From 78651886dc341aa31d75e5c9afefd3285c540bb4 Mon Sep 17 00:00:00 2001 From: Dmitry Ermakov Date: Mon, 14 Mar 2022 10:55:33 +0300 Subject: [PATCH] Add GK710X --- .github/workflows/gk7102_images.yml | 130 + br-ext-chip-goke/Config.in | 1 + .../board/gk710x/kernel/gk710x.generic.config | 1732 + .../gk710x/kernel/gk710xs.generic.config | 1733 + .../overlay/include/linux/compiler-gcc7.h | 65 + .../patches/0000-gk710x-kernel-3.4.43.patch | 298910 +++++++++++++++ .../patches/0003-overlayfs-v13-3.4-rc7.patch | 3363 + ...0011-fix-yylloc-for-modern-computers.patch | 11 + .../unknown_unknown_gk7102_openipc_defconfig | 96 + .../unknown_unknown_gk7102s_openipc_defconfig | 96 + br-ext-chip-goke/external.mk | 1 + br-ext-chip-goke/package/goke-osdrv-gk710x | 1 + building.sh | 26 +- general/package/goke-osdrv-gk710x/Config.in | 6 + .../goke-osdrv-gk710x/files/kmod/audio.ko | Bin 0 -> 15884 bytes .../goke-osdrv-gk710x/files/kmod/hal.ko | Bin 0 -> 38528 bytes .../goke-osdrv-gk710x/files/kmod/hw_crypto.ko | Bin 0 -> 4668 bytes .../goke-osdrv-gk710x/files/kmod/i2s.ko | Bin 0 -> 11832 bytes .../goke-osdrv-gk710x/files/kmod/media.ko | Bin 0 -> 251652 bytes .../goke-osdrv-gk710x/files/kmod/sensor.ko | Bin 0 -> 27224 bytes .../goke-osdrv-gk710x/files/lib/libadi.so | Bin 0 -> 153545 bytes .../goke-osdrv-gk710x/files/lib/libimage.so | Bin 0 -> 490991 bytes .../goke-osdrv-gk710x/files/script/S95goke | 72 + .../goke-osdrv-gk710x/files/script/ircut_demo | 87 + .../goke-osdrv-gk710x/files/script/load_goke | 54 + .../files/sensor/config/ar0130.bin | Bin 0 -> 174772 bytes .../files/sensor/config/ar0237.bin | Bin 0 -> 185124 bytes .../files/sensor/config/bg0701.bin | Bin 0 -> 126016 bytes .../files/sensor/config/gc1024.bin | Bin 0 -> 154212 bytes .../files/sensor/config/imx122.bin | Bin 0 -> 185172 bytes .../files/sensor/config/imx291.bin | Bin 0 -> 185196 bytes .../files/sensor/config/imx323.bin | Bin 0 -> 158292 bytes .../files/sensor/config/jxf22.bin | Bin 0 -> 174820 bytes .../files/sensor/config/jxh42.bin | Bin 0 -> 154140 bytes .../files/sensor/config/jxh61.bin | Bin 0 -> 159316 bytes .../files/sensor/config/jxh62.bin | Bin 0 -> 159316 bytes .../files/sensor/config/mis1002.bin | Bin 0 -> 159316 bytes .../files/sensor/config/ov2710.bin | Bin 0 -> 174820 bytes .../files/sensor/config/ov9732.bin | Bin 0 -> 154140 bytes .../files/sensor/config/ov9750.bin | Bin 0 -> 174820 bytes .../files/sensor/config/sc1035.bin | Bin 0 -> 174820 bytes .../files/sensor/config/sc1045.bin | Bin 0 -> 164540 bytes .../files/sensor/config/sc1135.bin | Bin 0 -> 174796 bytes .../files/sensor/config/sc1145.bin | Bin 0 -> 164444 bytes .../files/sensor/config/sc2035.bin | Bin 0 -> 185244 bytes .../files/sensor/config/sc2045.bin | Bin 0 -> 185244 bytes .../files/sensor/config/sc2135.bin | Bin 0 -> 185244 bytes .../files/sensor/fw/gk_fw_710x.bin | Bin 0 -> 1582496 bytes .../files/sensor/fw/gk_fw_710xs.bin | Bin 0 -> 1583176 bytes .../files/sensor/sc1135_ex.ko | Bin 0 -> 5832 bytes .../goke-osdrv-gk710x/goke-osdrv-gk710x.mk | 36 + 51 files changed, 306419 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/gk7102_images.yml create mode 100644 br-ext-chip-goke/board/gk710x/kernel/gk710x.generic.config create mode 100644 br-ext-chip-goke/board/gk710x/kernel/gk710xs.generic.config create mode 100644 br-ext-chip-goke/board/gk710x/kernel/overlay/include/linux/compiler-gcc7.h create mode 100644 br-ext-chip-goke/board/gk710x/kernel/patches/0000-gk710x-kernel-3.4.43.patch create mode 100644 br-ext-chip-goke/board/gk710x/kernel/patches/0003-overlayfs-v13-3.4-rc7.patch create mode 100644 br-ext-chip-goke/board/gk710x/kernel/patches/0011-fix-yylloc-for-modern-computers.patch create mode 100644 br-ext-chip-goke/configs/unknown_unknown_gk7102_openipc_defconfig create mode 100644 br-ext-chip-goke/configs/unknown_unknown_gk7102s_openipc_defconfig create mode 120000 br-ext-chip-goke/package/goke-osdrv-gk710x create mode 100644 general/package/goke-osdrv-gk710x/Config.in create mode 100755 general/package/goke-osdrv-gk710x/files/kmod/audio.ko create mode 100755 general/package/goke-osdrv-gk710x/files/kmod/hal.ko create mode 100755 general/package/goke-osdrv-gk710x/files/kmod/hw_crypto.ko create mode 100755 general/package/goke-osdrv-gk710x/files/kmod/i2s.ko create mode 100755 general/package/goke-osdrv-gk710x/files/kmod/media.ko create mode 100755 general/package/goke-osdrv-gk710x/files/kmod/sensor.ko create mode 100755 general/package/goke-osdrv-gk710x/files/lib/libadi.so create mode 100755 general/package/goke-osdrv-gk710x/files/lib/libimage.so create mode 100755 general/package/goke-osdrv-gk710x/files/script/S95goke create mode 100755 general/package/goke-osdrv-gk710x/files/script/ircut_demo create mode 100755 general/package/goke-osdrv-gk710x/files/script/load_goke create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/ar0130.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/ar0237.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/bg0701.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/gc1024.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/imx122.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/imx291.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/imx323.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/jxf22.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/jxh42.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/jxh61.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/jxh62.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/mis1002.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/ov2710.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/ov9732.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/ov9750.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/sc1035.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/sc1045.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/sc1135.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/sc1145.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/sc2035.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/sc2045.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/config/sc2135.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/fw/gk_fw_710x.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/fw/gk_fw_710xs.bin create mode 100755 general/package/goke-osdrv-gk710x/files/sensor/sc1135_ex.ko create mode 100644 general/package/goke-osdrv-gk710x/goke-osdrv-gk710x.mk diff --git a/.github/workflows/gk7102_images.yml b/.github/workflows/gk7102_images.yml new file mode 100644 index 00000000..b9339ee0 --- /dev/null +++ b/.github/workflows/gk7102_images.yml @@ -0,0 +1,130 @@ +name: "GK7102" + +on: + workflow_dispatch: + +jobs: + build_core: + name: OpenIPC firmware for GK7102 + runs-on: ubuntu-latest + + steps: + + - name: Checkout + id: checkout + uses: actions/checkout@v2 + + - name: Install build dependencies + id: install + run: | + make install-deps + mkdir -p tmp + + - name: Free disk space + id: freshing + run: | + sudo swapoff -a + sudo rm -f /swapfile + sudo apt clean + docker rmi $(docker image ls -aq) + df -h + + - name: Prepare buildroot + id: prepare + run: | + HEAD_TAG=$(git tag --points-at HEAD) + GIT_HASH=$(git rev-parse --short $GITHUB_SHA) + BRANCH_NAME=$(echo $GITHUB_REF | cut -d'/' -f 3) + if [ -z "$HEAD_TAG" ]; then + TAG_NAME="latest" + RELEASE_NAME="Development Build" + PRERELEASE=true + else + TAG_NAME=${{ github.ref }} + RELEASE_NAME="Release ${{ github.ref }}" + PRERELEASE=false + fi + echo "GIT_HASH=$GIT_HASH" >> $GITHUB_ENV + echo "TAG_NAME=$TAG_NAME" >> $GITHUB_ENV + echo "RELEASE_NAME=$RELEASE_NAME" >> $GITHUB_ENV + echo "PRERELEASE=$PRERELEASE" >> $GITHUB_ENV + echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV + cd $GITHUB_WORKSPACE + make prepare + + - name: Build GK7102 firmware + id: build-gk7102-firmware + continue-on-error: true + run: | + ARCHIVE_FW="${GITHUB_WORKSPACE}/output/images/openipc.gk7102-br.tgz" + echo "ARCHIVE_FW=$ARCHIVE_FW" >> $GITHUB_ENV + cd $GITHUB_WORKSPACE + make PLATFORM=goke BOARD=unknown_unknown_gk7102_openipc all + [[ $(stat --printf="%s" ${GITHUB_WORKSPACE}/output/images/uImage) -gt 2097152 ]] && echo "TG_NOTIFY=Warning, kernel size exceeded : $(stat --printf="%s" ${GITHUB_WORKSPACE}/output/images/uImage) vs 2097152... GK7102" >> $GITHUB_ENV && exit 1 + [[ $(stat --printf="%s" ${GITHUB_WORKSPACE}/output/images/rootfs.squashfs) -gt 5242880 ]] && echo "TG_NOTIFY=Warning, rootfs size exceeded - $(stat --printf="%s" ${GITHUB_WORKSPACE}/output/images/rootfs.squashfs) vs 5242880... GK7102" >> $GITHUB_ENV && exit 1 + cd ${GITHUB_WORKSPACE}/output/images + mv uImage uImage.gk7102 + mv rootfs.squashfs rootfs.squashfs.gk7102 + tar -C ${GITHUB_WORKSPACE}/output/images -cvzf $ARCHIVE_FW rootfs.squashfs.fh8856 uImage.gk7102 + + - name: Build GK7102 SDK + id: build-gk7102-sdk + continue-on-error: true + run: | + ARCHIVE_SDK="${GITHUB_WORKSPACE}/output/images/arm-openipc-linux-musleabi_sdk-buildroot.tar.gz" + echo "ARCHIVE_SDK=$ARCHIVE_SDK" >> $GITHUB_ENV + cd $GITHUB_WORKSPACE/output + make sdk + + - name: Send warning message to telegram channel + env: + TG_TOKEN: ${{ secrets.TELEGRAM_TOKEN_BOT_OPENIPC }} + TG_CHANNEL: ${{ secrets.TELEGRAM_CHANNEL_OPENIPC_DEV }} + if: steps.build-gk7102-firmware.outcome != 'success' || steps.build-gk7102-sdk.outcome != 'success' + run: | + TG_OPTIONS="-s --connect-timeout 30 --max-time 30" + TG_NOTIFY="${TG_NOTIFY:=Warning, Buildroot compiling error... GK7102}" + TG_HEADER=$(echo -e "\r\n$TG_NOTIFY \r\n\r\nCommit: $GIT_HASH \r\nBranch: $BRANCH_NAME \r\nTag: $TAG_NAME \r\n\r\n\xE2\x9A\xA0 GitHub Actions") + curl $TG_OPTIONS -H "Content-Type: multipart/form-data" -X POST https://api.telegram.org/bot$TG_TOKEN/sendMessage \ + -F chat_id=$TG_CHANNEL -F text="$TG_HEADER" + + - name: Create release + uses: actions/create-release@v1 + continue-on-error: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ env.TAG_NAME }} + release_name: ${{ env.RELEASE_NAME }} + draft: false + prerelease: ${{ env.PRERELEASE }} + + - name: Upload FW to release + uses: svenstaro/upload-release-action@v2 + continue-on-error: true + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: ${{ env.ARCHIVE_FW }} + asset_name: "openipc.gk7102-br.tgz" + tag: ${{ env.TAG_NAME }} + overwrite: true + + - name: Upload SDK to release + uses: svenstaro/upload-release-action@v2 + continue-on-error: true + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: ${{ env.ARCHIVE_SDK }} + asset_name: "arm-openipc-gk7102-linux-musleabi_sdk-buildroot.tar.gz" + tag: ${{ env.TAG_NAME }} + overwrite: true + + - name: Send binary file to telegram channel + env: + TG_TOKEN: ${{ secrets.TELEGRAM_TOKEN_BOT_OPENIPC }} + TG_CHANNEL: ${{ secrets.TELEGRAM_CHANNEL_OPENIPC_DEV }} + run: | + TG_OPTIONS="-s --connect-timeout 30 --max-time 30" + TG_HEADER=$(echo -e "\r\nCommit: $GIT_HASH \r\nBranch: $BRANCH_NAME \r\nTag: $TAG_NAME \r\n\r\n\xE2\x9C\x85 GitHub Actions") + curl $TG_OPTIONS -H "Content-Type: multipart/form-data" -X POST https://api.telegram.org/bot$TG_TOKEN/sendDocument \ + -F chat_id=$TG_CHANNEL -F document="@$ARCHIVE_FW" -F caption="$TG_HEADER" diff --git a/br-ext-chip-goke/Config.in b/br-ext-chip-goke/Config.in index dc0fb48f..32a92f2e 100644 --- a/br-ext-chip-goke/Config.in +++ b/br-ext-chip-goke/Config.in @@ -4,6 +4,7 @@ source "$BR2_EXTERNAL_GOKE_PATH/package/aura-httpd/Config.in" source "$BR2_EXTERNAL_GOKE_PATH/package/dropbear-openipc/Config.in" source "$BR2_EXTERNAL_GOKE_PATH/package/fdk-aac-openipc/Config.in" source "$BR2_EXTERNAL_GOKE_PATH/package/fwprintenv-openipc/Config.in" +source "$BR2_EXTERNAL_GOKE_PATH/package/goke-osdrv-gk710x/Config.in" source "$BR2_EXTERNAL_GOKE_PATH/package/goke-osdrv-gk7205v200/Config.in" source "$BR2_EXTERNAL_GOKE_PATH/package/ipctool/Config.in" source "$BR2_EXTERNAL_GOKE_PATH/package/json-c-openipc/Config.in" diff --git a/br-ext-chip-goke/board/gk710x/kernel/gk710x.generic.config b/br-ext-chip-goke/board/gk710x/kernel/gk710x.generic.config new file mode 100644 index 00000000..6e852168 --- /dev/null +++ b/br-ext-chip-goke/board/gk710x/kernel/gk710x.generic.config @@ -0,0 +1,1732 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.4.43 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_HAVE_PWM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +CONFIG_ARCH_USES_GETTIMEOFFSET=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_KTIME_SCALAR=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_NO_IOPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_PHYS_OFFSET=0xC0200000 +CONFIG_TEXT_OFFSET=0x00000000 +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_HAVE_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="arm-goke-linux-uclibcgnueabi-" +CONFIG_LOCALVERSION="-Goke" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZMA is not set +CONFIG_KERNEL_XZ=y +# CONFIG_KERNEL_LZO is not set +CONFIG_DEFAULT_HOSTNAME="openipc" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_FHANDLE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_IRQ_DOMAIN=y + +# +# RCU Subsystem +# +CONFIG_TINY_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_CGROUPS=y +# CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_FREEZER is not set +# CONFIG_CGROUP_DEVICE is not set +# CONFIG_CPUSETS is not set +# CONFIG_CGROUP_CPUACCT is not set +# CONFIG_RESOURCE_COUNTERS is not set +# CONFIG_CGROUP_SCHED is not set +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EXPERT=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_COUNTERS is not set +CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y + +# +# GCOV-based kernel profiling +# +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_BLOCK=y +# CONFIG_LBDAF is not set +CONFIG_BLK_DEV_BSG=y +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_UNINLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +# CONFIG_FREEZER is not set + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +CONFIG_ARCH_GK710X=y +# CONFIG_ARCH_GK710X_FPGA is not set +# CONFIG_ARCH_GK710XS is not set +# CONFIG_ARCH_GK710XS_FPGA is not set +# CONFIG_ARCH_GK720X is not set +# CONFIG_ARCH_GK720X_FPGA is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_GPIO_PCA953X is not set + +# +# System MMU +# +# CONFIG_ONLY_USE_NOR_8M is not set +CONFIG_ONLY_USE_NOR_16M=y +# CONFIG_ONLY_USE_NOR_32M is not set +# CONFIG_ONLY_USE_NAND is not set +# CONFIG_USE_NOR_AND_NAND is not set + +# +# Gk710X select peripheral +# +CONFIG_PHY_USE_AO_MCLK=y +# CONFIG_PHY_USE_SD_CLK is not set +# CONFIG_PHY_USE_EXTERN_CLK is not set +CONFIG_PMU_POWER_OFF_CPU=y +# CONFIG_PMU_ALWAYS_RUNNING is not set +# CONFIG_PMU_AUTOMOTIVE is not set +# CONFIG_SYSTEM_USE_EXTERN_I2S is not set +CONFIG_GK_CHIP_INCLUDE_FILE="mach/gk710x.h" + +# +# soc/fpga modules list +# +CONFIG_PLAT_GOKE=y +CONFIG_GK_CPU_ARM_1176_V1_00=y +CONFIG_GK_PLL_CHIP_V1_00=y +CONFIG_GK_EFUSE=y +CONFIG_GK_EFUSE_V1_00=y +CONFIG_GK_CRYPT=y +CONFIG_GK_CRYPT_V1_00=y +CONFIG_GK_TIMER=y +CONFIG_GK_TIMER_V1_00=y +CONFIG_GK_WDT=y +CONFIG_GK_WDT_V1_00=y +CONFIG_GK_DDR2_CON=y +CONFIG_GK_DDR2_CON_V1_00=y +CONFIG_GK_DDR2_PHY=y +CONFIG_GK_DDR2_PHY_V1_00=y +CONFIG_GK_GPIO=y +CONFIG_GK_GPIO_V1_00=y +CONFIG_GK_GPIO_MAX_INPUT_TYPE=64 +CONFIG_GK_GPIO_INSTANCES=1 +CONFIG_GK_UART=y +CONFIG_GK_UART_V1_00=y +CONFIG_GK_MUSB=y +CONFIG_GK_MUSB_CON_V1_00=y +CONFIG_GK_USB_DMA=y +CONFIG_GK_USB_DMA_V1_00=y +CONFIG_GK_USB_PHY=y +CONFIG_GK_USB_PHY_V1_00=y +CONFIG_GK_I2S=y +CONFIG_GK_I2S_V1_00=y +CONFIG_GK_AUD_CON=y +CONFIG_GK_AUD_CON_V1_00=y +CONFIG_GK_AUD_AD=y +CONFIG_GK_AUD_AD_V1_00=y +CONFIG_GK_AUD_DMA=y +CONFIG_GK_AUD_DMA_V1_00=y +CONFIG_GK_ETH=y +CONFIG_GK_ETH_EMAC=y +CONFIG_GK_ETH_EMAC_V1_00=y +CONFIG_GK_ETH_EDMA=y +CONFIG_GK_ETH_EDMA_V1_00=y +CONFIG_GK_ETH_EPHY=y +CONFIG_GK_ETH_EPHY_V1_00=y +CONFIG_GK_PWM=y +CONFIG_GK_PWM_V1_00=y +CONFIG_GK_SDIO=y +CONFIG_GK_SDIO2=y +CONFIG_GK_SDIO2_V1_00=y +CONFIG_GK_ADC=y +CONFIG_GK_ADC_V1_00=y +CONFIG_GK_I2C=y +CONFIG_GK_I2C_V1_00=y +CONFIG_GK_SFLASH=y +CONFIG_GK_SFLASH_V1_00=y +CONFIG_GK_SPI=y +CONFIG_GK_SPI_V1_00=y +CONFIG_GK_PMU=y +CONFIG_GK_PMU_V1_00=y +CONFIG_GK_MCU=y +CONFIG_GK_MCU_V1_00=y +CONFIG_GK_RTC=y +CONFIG_GK_RTC_V1_00=y +CONFIG_GK_IR=y +CONFIG_GK_IR_V1_00=y +CONFIG_GK_VOUT=y +CONFIG_GK_VOUT_V1_00=y +CONFIG_GK_HDMI=y +CONFIG_GK_HDMI_V1_00=y +CONFIG_GK_MIPI=y +CONFIG_GK_MIPI_V1_00=y +CONFIG_GK_VIN=y +CONFIG_GK_VIN_V1_00=y +CONFIG_GK_MDMA=y +CONFIG_GK_MDMA_V1_00=y +CONFIG_GK_SMEM=y +CONFIG_GK_SMEM_V1_00=y +CONFIG_GK_DSP1=y +CONFIG_GK_DSP1_V1_00=y +CONFIG_GK_DSP2=y +CONFIG_GK_DSP2_V1_00=y +CONFIG_GK_ISP=y +CONFIG_GK_ISP_V1_00=y +CONFIG_GK_FW=y +CONFIG_GK_FW_V1_00=y +CONFIG_GK_FB=y +CONFIG_GK_FB_V1_00=y + +# +# Processor Type +# +CONFIG_CPU_V6=y +CONFIG_CPU_32v6=y +CONFIG_CPU_ABRT_EV6=y +CONFIG_CPU_PABRT_V6=y +CONFIG_CPU_CACHE_V6=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V6=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_USE_DOMAINS=y + +# +# Processor Features +# +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +# CONFIG_CACHE_L2X0 is not set +CONFIG_ARM_L1_CACHE_SHIFT=4 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARM_NR_BANKS=8 +CONFIG_CPU_HAS_PMU=y +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_326103 is not set +# CONFIG_ARM_ERRATA_411920 is not set +# CONFIG_ARM_ERRATA_364296 is not set + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +# CONFIG_VMSPLIT_3G is not set +CONFIG_VMSPLIT_2G=y +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0x80000000 +CONFIG_ARCH_NR_GPIO=64 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ=100 +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +# CONFIG_HIGHMEM is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_COMPACTION is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_NEED_PER_CPU_KM=y +# CONFIG_CLEANCACHE is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +CONFIG_UACCESS_WITH_MEMCPY=y +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +CONFIG_DEPRECATED_PARAM_STRUCT=y + +# +# Boot options +# +# CONFIG_USE_OF is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set +CONFIG_KEXEC=y +CONFIG_ATAGS_PROC=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# +# CONFIG_CPU_IDLE is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_VFP=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +# CONFIG_SUSPEND is not set +# CONFIG_PM_RUNTIME is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +# CONFIG_ARM_CPU_SUSPEND is not set +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_UNIX_DIAG=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +CONFIG_NET_IPIP=y +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_IP_MROUTE is not set +CONFIG_ARPD=y +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_LRO=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +CONFIG_INET_UDP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET6_XFRM_MODE_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_BEET is not set +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +# CONFIG_IPV6_SIT is not set +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y +CONFIG_HAVE_BPF_JIT=y +# CONFIG_BPF_JIT is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WEXT_PRIV=y +CONFIG_CFG80211=m +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +CONFIG_WIRELESS_EXT_SYSFS=y +CONFIG_LIB80211=y +# CONFIG_LIB80211_DEBUG is not set +CONFIG_MAC80211=m +CONFIG_MAC80211_HAS_RC=y +# CONFIG_MAC80211_RC_PID is not set +CONFIG_MAC80211_RC_MINSTREL=y +CONFIG_MAC80211_RC_MINSTREL_HT=y +CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y +CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" +# CONFIG_MAC80211_MESH is not set +# CONFIG_MAC80211_DEBUG_MENU is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +# CONFIG_DMA_SHARED_BUFFER is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_AFS_PARTS=y +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_SWAP is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +CONFIG_MTD_SFLASH_GOKE=y +CONFIG_SFLASH_1X_R_1X_W_MODE=y +# CONFIG_SFLASH_4X_R_1X_W_MODE is not set +# CONFIG_SFLASH_4X_R_4X_W_MODE is not set +# CONFIG_MTD_SST25L is not set +CONFIG_MTD_SLRAM=y +CONFIG_MTD_PHRAM=y +# CONFIG_MTD_MTDRAM is not set +CONFIG_MTD_BLOCK2MTD=y + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOCG3 is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_SPINAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_GLUEBI is not set +# CONFIG_MTD_UBI_DEBUG is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +CONFIG_ADC_GOKE=y +# CONFIG_PWM_GOKE is not set +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_BMP085 is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=m +# CONFIG_VETH is not set + +# +# CAIF transport drivers +# +CONFIG_ETHERNET=y +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_DM9000 is not set +CONFIG_ETH_GOKE=y +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +CONFIG_INPUT_POLLDEV=y +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=y + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +CONFIG_INPUT_MISC=y +CONFIG_INPUT_GOKE_IR=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_CMA3000 is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_UNIX98_PTYS=y +CONFIG_DEVPTS_MULTIPLE_INSTANCES=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_GOKE=y +CONFIG_SERIAL_GOKE_CONSOLE=y +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_RAMOOPS is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +CONFIG_I2C_GOKE=y +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_TLE62X0 is not set +CONFIG_SPI_GOKE=y +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_WATCHDOG_GOKE=y +# CONFIG_DW_WATCHDOG is not set +# CONFIG_MAX63XX_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_REGULATOR is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB is not set +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set +# CONFIG_USB_ARCH_HAS_XHCI is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_DEBUG=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_GOKE=y +# CONFIG_CLOCK_32K is not set +CONFIG_CLOCK_24M=y +CONFIG_DMADEVICES=y +CONFIG_DMADEVICES_DEBUG=y +# CONFIG_DMADEVICES_VDEBUG is not set + +# +# DMA Devices +# +# CONFIG_DW_DMAC is not set +# CONFIG_TIMB_DMA is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +# CONFIG_STAGING is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y + +# +# Common Clock Framework +# +# CONFIG_COMMON_CLK_DISABLE_UNUSED is not set +# CONFIG_COMMON_CLK_DEBUG is not set + +# +# Hardware Spinlock drivers +# +# CONFIG_IOMMU_SUPPORT is not set + +# +# Remoteproc drivers (EXPERIMENTAL) +# + +# +# Rpmsg drivers (EXPERIMENTAL) +# +# CONFIG_VIRT_DRIVERS is not set +# CONFIG_PM_DEVFREQ is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +CONFIG_AUTOFS4_FS=y +# CONFIG_FUSE_FS is not set +CONFIG_OVERLAYFS_FS=y +CONFIG_GENERIC_ACL=y + +# +# Caches +# +CONFIG_FSCACHE=y +# CONFIG_FSCACHE_STATS is not set +# CONFIG_FSCACHE_HISTOGRAM is not set +# CONFIG_FSCACHE_DEBUG is not set +# CONFIG_FSCACHE_OBJECT_LIST is not set +CONFIG_CACHEFILES=y +# CONFIG_CACHEFILES_DEBUG is not set +# CONFIG_CACHEFILES_HISTOGRAM is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_YAFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +# CONFIG_JFFS2_SUMMARY is not set +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_FS_POSIX_ACL=y +CONFIG_JFFS2_FS_SECURITY=y +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_UBIFS_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +CONFIG_SQUASHFS=y +# CONFIG_SQUASHFS_XATTR is not set +# CONFIG_SQUASHFS_ZLIB is not set +# CONFIG_SQUASHFS_LZO is not set +CONFIG_SQUASHFS_XZ=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_EMBEDDED is not set +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +# CONFIG_NFS_V4_1 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFS_FSCACHE is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf-8" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=0 +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_DETECT_HUNG_TASK is not set +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_KMEMLEAK is not set +CONFIG_DEBUG_PREEMPT=y +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +# CONFIG_ARM_UNWIND is not set +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=y +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=y +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +# CONFIG_CRC_CCITT is not set +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_CRC8 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_XZ_DEC=y +CONFIG_XZ_DEC_X86=y +CONFIG_XZ_DEC_POWERPC=y +CONFIG_XZ_DEC_IA64=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_ARMTHUMB=y +CONFIG_XZ_DEC_SPARC=y +CONFIG_XZ_DEC_BCJ=y +# CONFIG_XZ_DEC_TEST is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_DMA=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_GENERIC_ATOMIC64=y +CONFIG_AVERAGE=y +# CONFIG_CORDIC is not set diff --git a/br-ext-chip-goke/board/gk710x/kernel/gk710xs.generic.config b/br-ext-chip-goke/board/gk710x/kernel/gk710xs.generic.config new file mode 100644 index 00000000..98b956f7 --- /dev/null +++ b/br-ext-chip-goke/board/gk710x/kernel/gk710xs.generic.config @@ -0,0 +1,1733 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.4.43 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_HAVE_PWM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +CONFIG_ARCH_USES_GETTIMEOFFSET=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_KTIME_SCALAR=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_NO_IOPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_PHYS_OFFSET=0xC0200000 +CONFIG_TEXT_OFFSET=0x00000000 +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_HAVE_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="arm-goke-linux-uclibcgnueabi-" +CONFIG_LOCALVERSION="-Goke" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZMA is not set +CONFIG_KERNEL_XZ=y +# CONFIG_KERNEL_LZO is not set +CONFIG_DEFAULT_HOSTNAME="openipc" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_FHANDLE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_IRQ_DOMAIN=y + +# +# RCU Subsystem +# +CONFIG_TINY_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_CGROUPS=y +# CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_FREEZER is not set +# CONFIG_CGROUP_DEVICE is not set +# CONFIG_CPUSETS is not set +# CONFIG_CGROUP_CPUACCT is not set +# CONFIG_RESOURCE_COUNTERS is not set +# CONFIG_CGROUP_SCHED is not set +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EXPERT=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_COUNTERS is not set +CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y + +# +# GCOV-based kernel profiling +# +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_BLOCK=y +# CONFIG_LBDAF is not set +CONFIG_BLK_DEV_BSG=y +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_UNINLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +# CONFIG_FREEZER is not set + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_GK710X is not set +# CONFIG_ARCH_GK710X_FPGA is not set +CONFIG_ARCH_GK710XS=y +# CONFIG_ARCH_GK710XS_FPGA is not set +# CONFIG_ARCH_GK720X is not set +# CONFIG_ARCH_GK720X_FPGA is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_GPIO_PCA953X is not set + +# +# System MMU +# +# CONFIG_GK710XS_SDIO2 is not set +# CONFIG_ONLY_USE_NOR_8M is not set +CONFIG_ONLY_USE_NOR_16M=y +# CONFIG_ONLY_USE_NOR_32M is not set +# CONFIG_ONLY_USE_NAND is not set +# CONFIG_USE_NOR_AND_NAND is not set + +# +# Gk710X select peripheral +# +CONFIG_PHY_USE_AO_MCLK=y +# CONFIG_PHY_USE_SD_CLK is not set +# CONFIG_PHY_USE_EXTERN_CLK is not set +CONFIG_PMU_POWER_OFF_CPU=y +# CONFIG_PMU_ALWAYS_RUNNING is not set +# CONFIG_PMU_AUTOMOTIVE is not set +# CONFIG_SYSTEM_USE_EXTERN_I2S is not set +CONFIG_GK_CHIP_INCLUDE_FILE="mach/gk710xs.h" + +# +# soc/fpga modules list +# +CONFIG_PLAT_GOKE=y +CONFIG_GK_CPU_ARM_1176_V1_00=y +CONFIG_GK_PLL_CHIP_V1_00=y +CONFIG_GK_EFUSE=y +CONFIG_GK_EFUSE_V1_00=y +CONFIG_GK_CRYPT=y +CONFIG_GK_CRYPT_V1_00=y +CONFIG_GK_TIMER=y +CONFIG_GK_TIMER_V1_00=y +CONFIG_GK_WDT=y +CONFIG_GK_WDT_V1_00=y +CONFIG_GK_DDR2_CON=y +CONFIG_GK_DDR2_CON_V1_00=y +CONFIG_GK_DDR2_PHY=y +CONFIG_GK_DDR2_PHY_V1_00=y +CONFIG_GK_GPIO=y +CONFIG_GK_GPIO_V1_20=y +CONFIG_GK_GPIO_MAX_INPUT_TYPE=128 +CONFIG_GK_GPIO_INSTANCES=1 +CONFIG_GK_UART=y +CONFIG_GK_UART_V1_00=y +CONFIG_GK_MUSB=y +CONFIG_GK_MUSB_CON_V1_10=y +CONFIG_GK_USB_DMA=y +CONFIG_GK_USB_DMA_V1_00=y +CONFIG_GK_USB_PHY=y +CONFIG_GK_USB_PHY_V1_00=y +CONFIG_GK_I2S=y +CONFIG_GK_I2S_V1_00=y +CONFIG_GK_AUD_CON=y +CONFIG_GK_AUD_CON_V1_00=y +CONFIG_GK_AUD_AD=y +CONFIG_GK_AUD_AD_V1_00=y +CONFIG_GK_AUD_DMA=y +CONFIG_GK_AUD_DMA_V1_00=y +CONFIG_GK_ETH=y +CONFIG_GK_ETH_EMAC=y +CONFIG_GK_ETH_EMAC_V1_00=y +CONFIG_GK_ETH_EDMA=y +CONFIG_GK_ETH_EDMA_V1_00=y +CONFIG_GK_ETH_EPHY=y +CONFIG_GK_ETH_EPHY_V1_00=y +CONFIG_GK_PWM=y +CONFIG_GK_PWM_V1_00=y +CONFIG_GK_SDIO=y +CONFIG_GK_SDIO2=y +CONFIG_GK_SDIO2_V1_00=y +CONFIG_GK_ADC=y +CONFIG_GK_ADC_V1_00=y +CONFIG_GK_I2C=y +CONFIG_GK_I2C_V1_00=y +CONFIG_GK_SFLASH=y +CONFIG_GK_SFLASH_V1_00=y +CONFIG_GK_SPI=y +CONFIG_GK_SPI_V1_00=y +CONFIG_GK_PMU=y +CONFIG_GK_PMU_V1_00=y +CONFIG_GK_MCU=y +CONFIG_GK_MCU_V1_00=y +CONFIG_GK_RTC=y +CONFIG_GK_RTC_V1_00=y +CONFIG_GK_IR=y +CONFIG_GK_IR_V1_00=y +CONFIG_GK_VOUT=y +CONFIG_GK_VOUT_V1_00=y +CONFIG_GK_HDMI=y +CONFIG_GK_HDMI_V1_00=y +CONFIG_GK_MIPI=y +CONFIG_GK_MIPI_V1_00=y +CONFIG_GK_VIN=y +CONFIG_GK_VIN_V1_00=y +CONFIG_GK_MDMA=y +CONFIG_GK_MDMA_V1_00=y +CONFIG_GK_SMEM=y +CONFIG_GK_SMEM_V1_00=y +CONFIG_GK_DSP1=y +CONFIG_GK_DSP1_V1_00=y +CONFIG_GK_DSP2=y +CONFIG_GK_DSP2_V1_00=y +CONFIG_GK_ISP=y +CONFIG_GK_ISP_V1_00=y +CONFIG_GK_FW=y +CONFIG_GK_FW_V1_00=y +CONFIG_GK_FB=y +CONFIG_GK_FB_V1_00=y + +# +# Processor Type +# +CONFIG_CPU_V6=y +CONFIG_CPU_32v6=y +CONFIG_CPU_ABRT_EV6=y +CONFIG_CPU_PABRT_V6=y +CONFIG_CPU_CACHE_V6=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V6=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_USE_DOMAINS=y + +# +# Processor Features +# +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +# CONFIG_CACHE_L2X0 is not set +CONFIG_ARM_L1_CACHE_SHIFT=4 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARM_NR_BANKS=8 +CONFIG_CPU_HAS_PMU=y +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_326103 is not set +# CONFIG_ARM_ERRATA_411920 is not set +# CONFIG_ARM_ERRATA_364296 is not set + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +# CONFIG_VMSPLIT_3G is not set +CONFIG_VMSPLIT_2G=y +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0x80000000 +CONFIG_ARCH_NR_GPIO=64 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ=100 +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +# CONFIG_HIGHMEM is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_COMPACTION is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_NEED_PER_CPU_KM=y +# CONFIG_CLEANCACHE is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +CONFIG_UACCESS_WITH_MEMCPY=y +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +CONFIG_DEPRECATED_PARAM_STRUCT=y + +# +# Boot options +# +# CONFIG_USE_OF is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set +CONFIG_KEXEC=y +CONFIG_ATAGS_PROC=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# +# CONFIG_CPU_IDLE is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_VFP=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +# CONFIG_SUSPEND is not set +# CONFIG_PM_RUNTIME is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +# CONFIG_ARM_CPU_SUSPEND is not set +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_UNIX_DIAG=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +CONFIG_NET_IPIP=y +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_IP_MROUTE is not set +CONFIG_ARPD=y +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_LRO=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +CONFIG_INET_UDP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET6_XFRM_MODE_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_BEET is not set +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +# CONFIG_IPV6_SIT is not set +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y +CONFIG_HAVE_BPF_JIT=y +# CONFIG_BPF_JIT is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WEXT_PRIV=y +CONFIG_CFG80211=m +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +CONFIG_WIRELESS_EXT_SYSFS=y +CONFIG_LIB80211=y +# CONFIG_LIB80211_DEBUG is not set +CONFIG_MAC80211=m +CONFIG_MAC80211_HAS_RC=y +# CONFIG_MAC80211_RC_PID is not set +CONFIG_MAC80211_RC_MINSTREL=y +CONFIG_MAC80211_RC_MINSTREL_HT=y +CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y +CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" +# CONFIG_MAC80211_MESH is not set +# CONFIG_MAC80211_DEBUG_MENU is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +# CONFIG_DMA_SHARED_BUFFER is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_AFS_PARTS=y +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_SWAP is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +CONFIG_MTD_SFLASH_GOKE=y +CONFIG_SFLASH_1X_R_1X_W_MODE=y +# CONFIG_SFLASH_4X_R_1X_W_MODE is not set +# CONFIG_SFLASH_4X_R_4X_W_MODE is not set +# CONFIG_MTD_SST25L is not set +CONFIG_MTD_SLRAM=y +CONFIG_MTD_PHRAM=y +# CONFIG_MTD_MTDRAM is not set +CONFIG_MTD_BLOCK2MTD=y + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOCG3 is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_SPINAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_GLUEBI is not set +# CONFIG_MTD_UBI_DEBUG is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +CONFIG_ADC_GOKE=y +# CONFIG_PWM_GOKE is not set +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_BMP085 is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=m +# CONFIG_VETH is not set + +# +# CAIF transport drivers +# +CONFIG_ETHERNET=y +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_DM9000 is not set +CONFIG_ETH_GOKE=y +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +CONFIG_INPUT_POLLDEV=y +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=y + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +CONFIG_INPUT_MISC=y +CONFIG_INPUT_GOKE_IR=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_CMA3000 is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_UNIX98_PTYS=y +CONFIG_DEVPTS_MULTIPLE_INSTANCES=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_GOKE=y +CONFIG_SERIAL_GOKE_CONSOLE=y +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_RAMOOPS is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +CONFIG_I2C_GOKE=y +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_TLE62X0 is not set +CONFIG_SPI_GOKE=y +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_WATCHDOG_GOKE=y +# CONFIG_DW_WATCHDOG is not set +# CONFIG_MAX63XX_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_REGULATOR is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB is not set +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set +# CONFIG_USB_ARCH_HAS_XHCI is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_DEBUG=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_GOKE=y +# CONFIG_CLOCK_32K is not set +CONFIG_CLOCK_24M=y +CONFIG_DMADEVICES=y +CONFIG_DMADEVICES_DEBUG=y +# CONFIG_DMADEVICES_VDEBUG is not set + +# +# DMA Devices +# +# CONFIG_DW_DMAC is not set +# CONFIG_TIMB_DMA is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +# CONFIG_STAGING is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y + +# +# Common Clock Framework +# +# CONFIG_COMMON_CLK_DISABLE_UNUSED is not set +# CONFIG_COMMON_CLK_DEBUG is not set + +# +# Hardware Spinlock drivers +# +# CONFIG_IOMMU_SUPPORT is not set + +# +# Remoteproc drivers (EXPERIMENTAL) +# + +# +# Rpmsg drivers (EXPERIMENTAL) +# +# CONFIG_VIRT_DRIVERS is not set +# CONFIG_PM_DEVFREQ is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +CONFIG_AUTOFS4_FS=y +# CONFIG_FUSE_FS is not set +CONFIG_OVERLAYFS_FS=y +CONFIG_GENERIC_ACL=y + +# +# Caches +# +CONFIG_FSCACHE=y +# CONFIG_FSCACHE_STATS is not set +# CONFIG_FSCACHE_HISTOGRAM is not set +# CONFIG_FSCACHE_DEBUG is not set +# CONFIG_FSCACHE_OBJECT_LIST is not set +CONFIG_CACHEFILES=y +# CONFIG_CACHEFILES_DEBUG is not set +# CONFIG_CACHEFILES_HISTOGRAM is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_YAFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +# CONFIG_JFFS2_SUMMARY is not set +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_FS_POSIX_ACL=y +CONFIG_JFFS2_FS_SECURITY=y +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_UBIFS_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +CONFIG_SQUASHFS=y +# CONFIG_SQUASHFS_XATTR is not set +# CONFIG_SQUASHFS_ZLIB is not set +# CONFIG_SQUASHFS_LZO is not set +CONFIG_SQUASHFS_XZ=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_EMBEDDED is not set +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +# CONFIG_NFS_V4_1 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFS_FSCACHE is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf-8" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=0 +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_DETECT_HUNG_TASK is not set +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_KMEMLEAK is not set +CONFIG_DEBUG_PREEMPT=y +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +# CONFIG_ARM_UNWIND is not set +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=y +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=y +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +# CONFIG_CRC_CCITT is not set +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_CRC8 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_XZ_DEC=y +CONFIG_XZ_DEC_X86=y +CONFIG_XZ_DEC_POWERPC=y +CONFIG_XZ_DEC_IA64=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_ARMTHUMB=y +CONFIG_XZ_DEC_SPARC=y +CONFIG_XZ_DEC_BCJ=y +# CONFIG_XZ_DEC_TEST is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_DMA=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_GENERIC_ATOMIC64=y +CONFIG_AVERAGE=y +# CONFIG_CORDIC is not set diff --git a/br-ext-chip-goke/board/gk710x/kernel/overlay/include/linux/compiler-gcc7.h b/br-ext-chip-goke/board/gk710x/kernel/overlay/include/linux/compiler-gcc7.h new file mode 100644 index 00000000..613f9936 --- /dev/null +++ b/br-ext-chip-goke/board/gk710x/kernel/overlay/include/linux/compiler-gcc7.h @@ -0,0 +1,65 @@ +#ifndef __LINUX_COMPILER_H +#error "Please don't include directly, include instead." +#endif + +#define __used __attribute__((__used__)) +#define __must_check __attribute__((warn_unused_result)) +#define __compiler_offsetof(a, b) __builtin_offsetof(a, b) + +/* Mark functions as cold. gcc will assume any path leading to a call + to them will be unlikely. This means a lot of manual unlikely()s + are unnecessary now for any paths leading to the usual suspects + like BUG(), printk(), panic() etc. [but let's keep them for now for + older compilers] + + Early snapshots of gcc 4.3 don't support this and we can't detect this + in the preprocessor, but we can live with this because they're unreleased. + Maketime probing would be overkill here. + + gcc also has a __attribute__((__hot__)) to move hot functions into + a special section, but I don't see any sense in this right now in + the kernel context */ +#define __cold __attribute__((__cold__)) + +#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) + +#ifndef __CHECKER__ +# define __compiletime_warning(message) __attribute__((warning(message))) +# define __compiletime_error(message) __attribute__((error(message))) +#endif /* __CHECKER__ */ + +/* + * Mark a position in code as unreachable. This can be used to + * suppress control flow warnings after asm blocks that transfer + * control elsewhere. + * + * Early snapshots of gcc 4.5 don't support this and we can't detect + * this in the preprocessor, but we can live with this because they're + * unreleased. Really, we need to have autoconf for the kernel. + */ +#define unreachable() __builtin_unreachable() + +/* Mark a function definition as prohibited from being cloned. */ +#define __noclone __attribute__((__noclone__)) + +/* + * Tell the optimizer that something else uses this function or variable. + */ +#define __visible __attribute__((externally_visible)) + +/* + * GCC 'asm goto' miscompiles certain code sequences: + * + * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670 + * + * Work it around via a compiler barrier quirk suggested by Jakub Jelinek. + * + * (asm goto is automatically volatile - the naming reflects this.) + */ +#define asm_volatile_goto(x...) do { asm goto(x); asm (""); } while (0) + +#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP +#define __HAVE_BUILTIN_BSWAP32__ +#define __HAVE_BUILTIN_BSWAP64__ +#define __HAVE_BUILTIN_BSWAP16__ +#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */ diff --git a/br-ext-chip-goke/board/gk710x/kernel/patches/0000-gk710x-kernel-3.4.43.patch b/br-ext-chip-goke/board/gk710x/kernel/patches/0000-gk710x-kernel-3.4.43.patch new file mode 100644 index 00000000..03c38e78 --- /dev/null +++ b/br-ext-chip-goke/board/gk710x/kernel/patches/0000-gk710x-kernel-3.4.43.patch @@ -0,0 +1,298910 @@ +diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig +index 7fe19a38..42b6b332 100644 +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -59,7 +59,7 @@ config GENERIC_GPIO + + config ARCH_USES_GETTIMEOFFSET + bool +- default n ++ default y + + config GENERIC_CLOCKEVENTS + bool +@@ -241,6 +241,13 @@ config PHYS_OFFSET + Please provide the physical address corresponding to the + location of main memory in your system. + ++config TEXT_OFFSET ++ hex "kernel start offset address base on physical address" ++ default 0x00000000 ++ help ++ Please provide the physical address corresponding to the ++ kernel start of main memory in your system. ++ + config GENERIC_BUG + def_bool y + depends on BUG +@@ -472,6 +479,832 @@ config ARCH_MXS + help + Support for Freescale MXS-based family of processors + ++config ARCH_GK710X ++ bool "Goke ipc GK710X family" ++ select CPU_V6 ++ select HAVE_PWM ++ select MULTI_IRQ_HANDLER ++ select IRQ_DOMAIN ++ select GENERIC_GPIO ++ select ARCH_REQUIRE_GPIOLIB ++ select GENERIC_CLOCKEVENTS ++ select CLKDEV_LOOKUP ++ select COMMON_CLK ++ select NO_IOPORT ++ select PLAT_GOKE ++ select GK_CPU_ARM_1176_V1_00 ++# select GK_CPU_ARM_1176_V1_10 ++# select GK_CPU_ARM_1176_V1_20 ++# select GK_CPU_CORTEX_A7_V1_00 ++ select GK_BUS_NIC_400_V1_00 ++# select GK_BUS_CCN_V1_00 ++# select GK_BUS_NOC_V1_00 ++# select GK_PLL_FPGA_V1_00 ++# select GK_PLL_FPGA_V1_10 ++# select GK_PLL_FPGA_V1_20 ++# select GK_PLL_FPGA_V1_30 ++ select GK_PLL_CHIP_V1_00 ++# select GK_PLL_CHIP_V1_10 ++# select GK_PLL_CHIP_V1_20 ++# select GK_PLL_CHIP_V1_30 ++ select GK_EFUSE ++ select GK_EFUSE_V1_00 ++# select GK_EFUSE_V1_10 ++# select GK_EFUSE_V1_20 ++# select GK_EFUSE_V1_30 ++ select GK_CRYPT ++ select GK_CRYPT_V1_00 ++# select GK_CRYPT_V1_10 ++ select GK_TIMER ++ select GK_TIMER_V1_00 ++# select GK_TIMER_V1_10 ++ select GK_WDT ++ select GK_WDT_V1_00 ++# select GK_WDT_V1_10 ++ select GK_DDR2_CON ++ select GK_DDR2_CON_V1_00 ++# select GK_DDR2_CON_V1_10 ++ select GK_DDR2_PHY ++ select GK_DDR2_PHY_V1_00 ++# select GK_DDR2_PHY_V1_10 ++ select GK_GPIO ++ select GK_GPIO_V1_00 ++# select GK_GPIO_V1_10 ++ select GK_UART ++ select GK_UART_V1_00 ++# select GK_UART_V1_10 ++# select GK_UART_V1_20 ++ select GK_MUSB ++ select GK_MUSB_CON_V1_00 ++# select GK_MUSB_CON_V1_10 ++ select GK_USB_DMA ++ select GK_USB_DMA_V1_00 ++# select GK_USB_DMA_V1_10 ++ select GK_USB_PHY ++ select GK_USB_PHY_V1_00 ++ select GK_I2S ++ select GK_I2S_V1_00 ++ select GK_AUD_CON ++ select GK_AUD_CON_V1_00 ++ select GK_AUD_AD ++ select GK_AUD_AD_V1_00 ++ select GK_AUD_DMA ++ select GK_AUD_DMA_V1_00 ++# select GK_AUD_DMA_V1_10 ++ select GK_ETH ++ select GK_ETH_EMAC ++ select GK_ETH_EMAC_V1_00 ++ select GK_ETH_EDMA ++ select GK_ETH_EDMA_V1_00 ++ select GK_ETH_EPHY ++ select GK_ETH_EPHY_V1_00 ++ select GK_PWM ++ select GK_PWM_V1_00 ++ select GK_SDIO ++ select GK_SDIO2 ++ select GK_SDIO2_V1_00 ++# select GK_SDIO3 ++# select GK_SDIO3_V1_00 ++ select GK_ADC ++ select GK_ADC_V1_00 ++# select GK_ADC_V1_10 ++ select GK_I2C ++ select GK_I2C_V1_00 ++ select GK_SFLASH ++ select GK_SFLASH_V1_00 ++ select GK_SPI ++ select GK_SPI_V1_00 ++ select GK_PMU ++ select GK_PMU_V1_00 ++# select GK_PMU_V1_10 ++ select GK_MCU ++ select GK_MCU_V1_00 ++ select GK_RTC ++ select GK_RTC_V1_00 ++ select GK_IR ++ select GK_IR_V1_00 ++ select GK_VOUT ++ select GK_VOUT_V1_00 ++# select GK_VOUT_V1_10 ++# select GK_VOUT_V1_20 ++ select GK_HDMI ++ select GK_HDMI_V1_00 ++ select GK_MIPI ++ select GK_MIPI_V1_00 ++ select GK_VIN ++ select GK_VIN_V1_00 ++# select GK_VIN_V1_10 ++# select GK_VIN_V1_20 ++ select GK_MDMA ++ select GK_MDMA_V1_00 ++ select GK_SMEM ++ select GK_SMEM_V1_00 ++# select GK_SMEM_V1_10 ++ select GK_DSP1 ++ select GK_DSP1_V1_00 ++ select GK_DSP2 ++ select GK_DSP2_V1_00 ++ select GK_ISP ++ select GK_ISP_V1_00 ++# select GK_ISP_V1_10 ++ select GK_FW ++ select GK_FW_V1_00 ++# select GK_FW_V1_10 ++# select GK_FW_V1_20 ++ select GK_FB ++ select GK_FB_V1_00 ++ help ++ Support for Goke GK710X(GK7101/GK7102/GK7103...) Soc ++ ++config ARCH_GK710X_FPGA ++ bool "Goke ipc GK710X FPGA" ++ select CPU_V6 ++ select HAVE_PWM ++ select MULTI_IRQ_HANDLER ++ select IRQ_DOMAIN ++ select GENERIC_GPIO ++ select ARCH_REQUIRE_GPIOLIB ++ select GENERIC_CLOCKEVENTS ++ select CLKDEV_LOOKUP ++ select COMMON_CLK ++ select NO_IOPORT ++ select PLAT_GOKE ++ select GK_CPU_ARM_1176_V1_00 ++# select GK_CPU_ARM_1176_V1_10 ++# select GK_CPU_ARM_1176_V1_20 ++# select GK_CPU_CORTEX_A7_V1_00 ++ select GK_BUS_NIC_400_V1_00 ++# select GK_BUS_CCN_V1_00 ++# select GK_BUS_NOC_V1_00 ++# select GK_PLL_FPGA_V1_00 ++# select GK_PLL_FPGA_V1_10 ++# select GK_PLL_FPGA_V1_20 ++# select GK_PLL_FPGA_V1_30 ++ select GK_PLL_CHIP_V1_00 ++# select GK_PLL_CHIP_V1_10 ++# select GK_PLL_CHIP_V1_20 ++# select GK_PLL_CHIP_V1_30 ++ select GK_EFUSE ++ select GK_EFUSE_V1_00 ++# select GK_EFUSE_V1_10 ++# select GK_EFUSE_V1_20 ++# select GK_EFUSE_V1_30 ++ select GK_CRYPT ++ select GK_CRYPT_V1_00 ++# select GK_CRYPT_V1_10 ++ select GK_TIMER ++ select GK_TIMER_V1_00 ++# select GK_TIMER_V1_10 ++ select GK_WDT ++ select GK_WDT_V1_00 ++# select GK_WDT_V1_10 ++ select GK_DDR2_CON ++ select GK_DDR2_CON_V1_00 ++# select GK_DDR2_CON_V1_10 ++ select GK_DDR2_PHY ++ select GK_DDR2_PHY_V1_00 ++# select GK_DDR2_PHY_V1_10 ++ select GK_GPIO ++ select GK_GPIO_V1_00 ++# select GK_GPIO_V1_10 ++ select GK_UART ++ select GK_UART_V1_00 ++# select GK_UART_V1_10 ++# select GK_UART_V1_20 ++ select GK_MUSB ++ select GK_MUSB_CON_V1_00 ++# select GK_MUSB_CON_V1_10 ++ select GK_USB_DMA ++ select GK_USB_DMA_V1_00 ++# select GK_USB_DMA_V1_10 ++ select GK_USB_PHY ++ select GK_USB_PHY_V1_00 ++ select GK_I2S ++ select GK_I2S_V1_00 ++ select GK_AUD_CON ++ select GK_AUD_CON_V1_00 ++ select GK_AUD_AD ++ select GK_AUD_AD_V1_00 ++ select GK_AUD_DMA ++ select GK_AUD_DMA_V1_00 ++# select GK_AUD_DMA_V1_10 ++ select GK_ETH ++ select GK_ETH_EMAC ++ select GK_ETH_EMAC_V1_00 ++ select GK_ETH_EDMA ++ select GK_ETH_EDMA_V1_00 ++ select GK_ETH_EPHY ++ select GK_ETH_EPHY_V1_00 ++ select GK_PWM ++ select GK_PWM_V1_00 ++ select GK_SDIO ++ select GK_SDIO2 ++ select GK_SDIO2_V1_00 ++# select GK_SDIO3 ++# select GK_SDIO3_V1_00 ++ select GK_ADC ++ select GK_ADC_V1_00 ++# select GK_ADC_V1_10 ++ select GK_I2C ++ select GK_I2C_V1_00 ++ select GK_SFLASH ++ select GK_SFLASH_V1_00 ++ select GK_SPI ++ select GK_SPI_V1_00 ++ select GK_PMU ++ select GK_PMU_V1_00 ++# select GK_PMU_V1_10 ++ select GK_MCU ++ select GK_MCU_V1_00 ++ select GK_RTC ++ select GK_RTC_V1_00 ++ select GK_IR ++ select GK_IR_V1_00 ++ select GK_VOUT ++ select GK_VOUT_V1_00 ++# select GK_VOUT_V1_10 ++# select GK_VOUT_V1_20 ++ select GK_HDMI ++ select GK_HDMI_V1_00 ++ select GK_MIPI ++ select GK_MIPI_V1_00 ++ select GK_VIN ++ select GK_VIN_V1_00 ++# select GK_VIN_V1_10 ++# select GK_VIN_V1_20 ++ select GK_MDMA ++ select GK_MDMA_V1_00 ++ select GK_SMEM ++ select GK_SMEM_V1_00 ++# select GK_SMEM_V1_10 ++ select GK_DSP1 ++ select GK_DSP1_V1_00 ++ select GK_DSP2 ++ select GK_DSP2_V1_00 ++ select GK_ISP ++ select GK_ISP_V1_00 ++# select GK_ISP_V1_10 ++ select GK_FW ++ select GK_FW_V1_00 ++# select GK_FW_V1_10 ++# select GK_FW_V1_20 ++ select GK_FB ++ select GK_FB_V1_00 ++ help ++ Support for Goke GK710X(GK7101/GK7102/GK7103...) FPGA ++ ++config ARCH_GK710XS ++ bool "Goke ipc GK710XS family" ++ select CPU_V6 ++ select HAVE_PWM ++ select MULTI_IRQ_HANDLER ++ select IRQ_DOMAIN ++ select GENERIC_GPIO ++ select ARCH_REQUIRE_GPIOLIB ++ select GENERIC_CLOCKEVENTS ++ select CLKDEV_LOOKUP ++ select COMMON_CLK ++ select NO_IOPORT ++ select PLAT_GOKE ++ select GK_CPU_ARM_1176_V1_00 ++# select GK_CPU_ARM_1176_V1_10 ++# select GK_CPU_ARM_1176_V1_20 ++# select GK_CPU_CORTEX_A7_V1_00 ++ select GK_BUS_NIC_400_V1_00 ++# select GK_BUS_CCN_V1_00 ++# select GK_BUS_NOC_V1_00 ++# select GK_PLL_FPGA_V1_00 ++# select GK_PLL_FPGA_V1_10 ++# select GK_PLL_FPGA_V1_20 ++# select GK_PLL_FPGA_V1_30 ++ select GK_PLL_CHIP_V1_00 ++# select GK_PLL_CHIP_V1_10 ++# select GK_PLL_CHIP_V1_20 ++# select GK_PLL_CHIP_V1_30 ++ select GK_EFUSE ++ select GK_EFUSE_V1_00 ++# select GK_EFUSE_V1_10 ++# select GK_EFUSE_V1_20 ++# select GK_EFUSE_V1_30 ++ select GK_CRYPT ++ select GK_CRYPT_V1_00 ++# select GK_CRYPT_V1_10 ++ select GK_TIMER ++ select GK_TIMER_V1_00 ++# select GK_TIMER_V1_10 ++ select GK_WDT ++ select GK_WDT_V1_00 ++# select GK_WDT_V1_10 ++ select GK_DDR2_CON ++ select GK_DDR2_CON_V1_00 ++# select GK_DDR2_CON_V1_10 ++ select GK_DDR2_PHY ++ select GK_DDR2_PHY_V1_00 ++# select GK_DDR2_PHY_V1_10 ++ select GK_GPIO ++# select GK_GPIO_V1_00 ++# select GK_GPIO_V1_10 ++ select GK_GPIO_V1_20 ++ select GK_UART ++ select GK_UART_V1_00 ++# select GK_UART_V1_10 ++# select GK_UART_V1_20 ++ select GK_MUSB ++# select GK_MUSB_CON_V1_00 ++ select GK_MUSB_CON_V1_10 ++ select GK_USB_DMA ++ select GK_USB_DMA_V1_00 ++# select GK_USB_DMA_V1_10 ++ select GK_USB_PHY ++ select GK_USB_PHY_V1_00 ++ select GK_I2S ++ select GK_I2S_V1_00 ++ select GK_AUD_CON ++ select GK_AUD_CON_V1_00 ++ select GK_AUD_AD ++ select GK_AUD_AD_V1_00 ++ select GK_AUD_DMA ++ select GK_AUD_DMA_V1_00 ++# select GK_AUD_DMA_V1_10 ++ select GK_ETH ++ select GK_ETH_EMAC ++ select GK_ETH_EMAC_V1_00 ++ select GK_ETH_EDMA ++ select GK_ETH_EDMA_V1_00 ++ select GK_ETH_EPHY ++ select GK_ETH_EPHY_V1_00 ++ select GK_PWM ++ select GK_PWM_V1_00 ++ select GK_SDIO ++ select GK_SDIO2 ++ select GK_SDIO2_V1_00 ++# select GK_SDIO3 ++# select GK_SDIO3_V1_00 ++ select GK_ADC ++ select GK_ADC_V1_00 ++# select GK_ADC_V1_10 ++ select GK_I2C ++ select GK_I2C_V1_00 ++ select GK_SFLASH ++ select GK_SFLASH_V1_00 ++ select GK_SPI ++ select GK_SPI_V1_00 ++ select GK_PMU ++ select GK_PMU_V1_00 ++# select GK_PMU_V1_10 ++ select GK_MCU ++ select GK_MCU_V1_00 ++ select GK_RTC ++ select GK_RTC_V1_00 ++ select GK_IR ++ select GK_IR_V1_00 ++ select GK_VOUT ++ select GK_VOUT_V1_00 ++# select GK_VOUT_V1_10 ++# select GK_VOUT_V1_20 ++ select GK_HDMI ++ select GK_HDMI_V1_00 ++ select GK_MIPI ++ select GK_MIPI_V1_00 ++ select GK_VIN ++ select GK_VIN_V1_00 ++# select GK_VIN_V1_10 ++# select GK_VIN_V1_20 ++ select GK_MDMA ++ select GK_MDMA_V1_00 ++ select GK_SMEM ++ select GK_SMEM_V1_00 ++# select GK_SMEM_V1_10 ++ select GK_DSP1 ++ select GK_DSP1_V1_00 ++ select GK_DSP2 ++ select GK_DSP2_V1_00 ++ select GK_ISP ++ select GK_ISP_V1_00 ++# select GK_ISP_V1_10 ++ select GK_FW ++ select GK_FW_V1_00 ++# select GK_FW_V1_10 ++# select GK_FW_V1_20 ++ select GK_FB ++ select GK_FB_V1_00 ++ help ++ Support for Goke GK710XS(GK7101S/GK7102S/GK7103S...) Soc ++ ++config ARCH_GK710XS_FPGA ++ bool "Goke ipc GK710XS FPGA" ++ select CPU_V6 ++ select HAVE_PWM ++ select MULTI_IRQ_HANDLER ++ select IRQ_DOMAIN ++ select GENERIC_GPIO ++ select ARCH_REQUIRE_GPIOLIB ++ select GENERIC_CLOCKEVENTS ++ select CLKDEV_LOOKUP ++ select COMMON_CLK ++ select NO_IOPORT ++ select PLAT_GOKE ++ select GK_CPU_ARM_1176_V1_00 ++# select GK_CPU_ARM_1176_V1_10 ++# select GK_CPU_ARM_1176_V1_20 ++# select GK_CPU_CORTEX_A7_V1_00 ++ select GK_BUS_NIC_400_V1_00 ++# select GK_BUS_CCN_V1_00 ++# select GK_BUS_NOC_V1_00 ++# select GK_PLL_FPGA_V1_00 ++# select GK_PLL_FPGA_V1_10 ++# select GK_PLL_FPGA_V1_20 ++# select GK_PLL_FPGA_V1_30 ++ select GK_PLL_CHIP_V1_00 ++# select GK_PLL_CHIP_V1_10 ++# select GK_PLL_CHIP_V1_20 ++# select GK_PLL_CHIP_V1_30 ++ select GK_EFUSE ++ select GK_EFUSE_V1_00 ++# select GK_EFUSE_V1_10 ++# select GK_EFUSE_V1_20 ++# select GK_EFUSE_V1_30 ++ select GK_CRYPT ++ select GK_CRYPT_V1_00 ++# select GK_CRYPT_V1_10 ++ select GK_TIMER ++ select GK_TIMER_V1_00 ++# select GK_TIMER_V1_10 ++ select GK_WDT ++ select GK_WDT_V1_00 ++# select GK_WDT_V1_10 ++ select GK_DDR2_CON ++ select GK_DDR2_CON_V1_00 ++# select GK_DDR2_CON_V1_10 ++ select GK_DDR2_PHY ++ select GK_DDR2_PHY_V1_00 ++# select GK_DDR2_PHY_V1_10 ++ select GK_GPIO ++# select GK_GPIO_V1_00 ++# select GK_GPIO_V1_10 ++ select GK_GPIO_V1_20 ++ select GK_UART ++ select GK_UART_V1_00 ++# select GK_UART_V1_10 ++# select GK_UART_V1_20 ++ select GK_MUSB ++# select GK_MUSB_CON_V1_00 ++ select GK_MUSB_CON_V1_10 ++ select GK_USB_DMA ++ select GK_USB_DMA_V1_00 ++# select GK_USB_DMA_V1_10 ++ select GK_USB_PHY ++ select GK_USB_PHY_V1_00 ++ select GK_I2S ++ select GK_I2S_V1_00 ++ select GK_AUD_CON ++ select GK_AUD_CON_V1_00 ++ select GK_AUD_AD ++ select GK_AUD_AD_V1_00 ++ select GK_AUD_DMA ++ select GK_AUD_DMA_V1_00 ++# select GK_AUD_DMA_V1_10 ++ select GK_ETH ++ select GK_ETH_EMAC ++ select GK_ETH_EMAC_V1_00 ++ select GK_ETH_EDMA ++ select GK_ETH_EDMA_V1_00 ++ select GK_ETH_EPHY ++ select GK_ETH_EPHY_V1_00 ++ select GK_PWM ++ select GK_PWM_V1_00 ++ select GK_SDIO ++ select GK_SDIO2 ++ select GK_SDIO2_V1_00 ++# select GK_SDIO3 ++# select GK_SDIO3_V1_00 ++ select GK_ADC ++ select GK_ADC_V1_00 ++# select GK_ADC_V1_10 ++ select GK_I2C ++ select GK_I2C_V1_00 ++ select GK_SFLASH ++ select GK_SFLASH_V1_00 ++ select GK_SPI ++ select GK_SPI_V1_00 ++ select GK_PMU ++ select GK_PMU_V1_00 ++# select GK_PMU_V1_10 ++ select GK_MCU ++ select GK_MCU_V1_00 ++ select GK_RTC ++ select GK_RTC_V1_00 ++ select GK_IR ++ select GK_IR_V1_00 ++ select GK_VOUT ++ select GK_VOUT_V1_00 ++# select GK_VOUT_V1_10 ++# select GK_VOUT_V1_20 ++ select GK_HDMI ++ select GK_HDMI_V1_00 ++ select GK_MIPI ++ select GK_MIPI_V1_00 ++ select GK_VIN ++ select GK_VIN_V1_00 ++# select GK_VIN_V1_10 ++# select GK_VIN_V1_20 ++ select GK_MDMA ++ select GK_MDMA_V1_00 ++ select GK_SMEM ++ select GK_SMEM_V1_00 ++# select GK_SMEM_V1_10 ++ select GK_DSP1 ++ select GK_DSP1_V1_00 ++ select GK_DSP2 ++ select GK_DSP2_V1_00 ++ select GK_ISP ++ select GK_ISP_V1_00 ++# select GK_ISP_V1_10 ++ select GK_FW ++ select GK_FW_V1_00 ++# select GK_FW_V1_10 ++# select GK_FW_V1_20 ++ select GK_FB ++ select GK_FB_V1_00 ++ help ++ Support for Goke GK710XS(GK7101S/GK7102S/GK7103S...) FPGA ++ ++config ARCH_GK720X ++ bool "Goke ipc GK720X_chip family" ++ select CPU_V6 ++ select HAVE_PWM ++ select MULTI_IRQ_HANDLER ++ select IRQ_DOMAIN ++ select GENERIC_GPIO ++ select ARCH_REQUIRE_GPIOLIB ++ select GENERIC_CLOCKEVENTS ++ select CLKDEV_LOOKUP ++ select COMMON_CLK ++ select NO_IOPORT ++# select PLAT_GOKE ++ select GK_CPU_ARM_1176_V1_00 ++# select GK_CPU_ARM_1176_V1_10 ++# select GK_CPU_ARM_1176_V1_20 ++# select GK_CPU_CORTEX_A7_V1_00 ++ select GK_BUS_NIC_400_V1_00 ++# select GK_BUS_CCN_V1_00 ++# select GK_BUS_NOC_V1_00 ++# select GK_PLL_FPGA_V1_00 ++# select GK_PLL_FPGA_V1_10 ++# select GK_PLL_FPGA_V1_20 ++# select GK_PLL_FPGA_V1_30 ++ select GK_PLL_CHIP_V1_00 ++# select GK_PLL_CHIP_V1_10 ++# select GK_PLL_CHIP_V1_20 ++# select GK_PLL_CHIP_V1_30 ++ select GK_EFUSE ++ select GK_EFUSE_V1_00 ++# select GK_EFUSE_V1_10 ++# select GK_EFUSE_V1_20 ++# select GK_EFUSE_V1_30 ++ select GK_CRYPT ++ select GK_CRYPT_V1_00 ++# select GK_CRYPT_V1_10 ++ select GK_TIMER ++ select GK_TIMER_V1_00 ++# select GK_TIMER_V1_10 ++ select GK_WDT ++ select GK_WDT_V1_00 ++# select GK_WDT_V1_10 ++ select GK_DDR2_CON ++ select GK_DDR2_CON_V1_00 ++# select GK_DDR2_CON_V1_10 ++ select GK_DDR2_PHY ++ select GK_DDR2_PHY_V1_00 ++# select GK_DDR2_PHY_V1_10 ++ select GK_GPIO ++# select GK_GPIO_V1_00 ++# select GK_GPIO_V1_10 ++ select GK_GPIO_V1_20 ++ select GK_UART ++ select GK_UART_V1_00 ++# select GK_UART_V1_10 ++# select GK_UART_V1_20 ++ select GK_MUSB ++# select GK_MUSB_CON_V1_00 ++ select GK_MUSB_CON_V1_10 ++ select GK_USB_DMA ++ select GK_USB_DMA_V1_00 ++# select GK_USB_DMA_V1_10 ++ select GK_USB_PHY ++ select GK_USB_PHY_V1_00 ++ select GK_I2S ++ select GK_I2S_V1_00 ++ select GK_AUD_CON ++ select GK_AUD_CON_V1_00 ++ select GK_AUD_AD ++ select GK_AUD_AD_V1_00 ++ select GK_AUD_DMA ++ select GK_AUD_DMA_V1_00 ++# select GK_AUD_DMA_V1_10 ++ select GK_ETH ++ select GK_ETH_EMAC ++ select GK_ETH_EMAC_V1_00 ++ select GK_ETH_EDMA ++ select GK_ETH_EDMA_V1_00 ++ select GK_ETH_EPHY ++ select GK_ETH_EPHY_V1_00 ++ select GK_PWM ++ select GK_PWM_V1_00 ++ select GK_SDIO ++ select GK_SDIO2 ++ select GK_SDIO2_V1_00 ++# select GK_SDIO3 ++# select GK_SDIO3_V1_00 ++ select GK_ADC ++ select GK_ADC_V1_00 ++# select GK_ADC_V1_10 ++ select GK_I2C ++ select GK_I2C_V1_00 ++ select GK_SFLASH ++ select GK_SFLASH_V1_00 ++ select GK_SPI ++ select GK_SPI_V1_00 ++ select GK_PMU ++ select GK_PMU_V1_00 ++# select GK_PMU_V1_10 ++ select GK_MCU ++ select GK_MCU_V1_00 ++ select GK_RTC ++ select GK_RTC_V1_00 ++ select GK_IR ++ select GK_IR_V1_00 ++ select GK_VOUT ++ select GK_VOUT_V1_00 ++# select GK_VOUT_V1_10 ++# select GK_VOUT_V1_20 ++ select GK_HDMI ++ select GK_HDMI_V1_00 ++ select GK_MIPI ++ select GK_MIPI_V1_00 ++ select GK_VIN ++ select GK_VIN_V1_00 ++# select GK_VIN_V1_10 ++# select GK_VIN_V1_20 ++ select GK_MDMA ++ select GK_MDMA_V1_00 ++ select GK_SMEM ++ select GK_SMEM_V1_00 ++# select GK_SMEM_V1_10 ++ select GK_DSP1 ++ select GK_DSP1_V1_00 ++ select GK_DSP2 ++ select GK_DSP2_V1_00 ++ select GK_ISP ++ select GK_ISP_V1_00 ++# select GK_ISP_V1_10 ++ select GK_FW ++ select GK_FW_V1_00 ++# select GK_FW_V1_10 ++# select GK_FW_V1_20 ++ select GK_FB ++ select GK_FB_V1_00 ++ help ++ Support for Goke GK720X(GK7201/GK7202/GK7203...) chip ++ ++config ARCH_GK720X_FPGA ++ bool "Goke ipc GK720X_FPGA family" ++ select CPU_V6 ++ select HAVE_PWM ++ select MULTI_IRQ_HANDLER ++ select IRQ_DOMAIN ++ select GENERIC_GPIO ++ select ARCH_REQUIRE_GPIOLIB ++ select GENERIC_CLOCKEVENTS ++ select CLKDEV_LOOKUP ++ select COMMON_CLK ++ select NO_IOPORT ++# select PLAT_GOKE ++ select GK_CPU_ARM_1176_V1_00 ++# select GK_CPU_ARM_1176_V1_10 ++# select GK_CPU_ARM_1176_V1_20 ++# select GK_CPU_CORTEX_A7_V1_00 ++ select GK_BUS_NIC_400_V1_00 ++# select GK_BUS_CCN_V1_00 ++# select GK_BUS_NOC_V1_00 ++# select GK_PLL_FPGA_V1_00 ++# select GK_PLL_FPGA_V1_10 ++# select GK_PLL_FPGA_V1_20 ++# select GK_PLL_FPGA_V1_30 ++ select GK_PLL_CHIP_V1_00 ++# select GK_PLL_CHIP_V1_10 ++# select GK_PLL_CHIP_V1_20 ++# select GK_PLL_CHIP_V1_30 ++ select GK_EFUSE ++ select GK_EFUSE_V1_00 ++# select GK_EFUSE_V1_10 ++# select GK_EFUSE_V1_20 ++# select GK_EFUSE_V1_30 ++ select GK_CRYPT ++ select GK_CRYPT_V1_00 ++# select GK_CRYPT_V1_10 ++ select GK_TIMER ++ select GK_TIMER_V1_00 ++# select GK_TIMER_V1_10 ++ select GK_WDT ++ select GK_WDT_V1_00 ++# select GK_WDT_V1_10 ++ select GK_DDR2_CON ++ select GK_DDR2_CON_V1_00 ++# select GK_DDR2_CON_V1_10 ++ select GK_DDR2_PHY ++ select GK_DDR2_PHY_V1_00 ++# select GK_DDR2_PHY_V1_10 ++ select GK_GPIO ++# select GK_GPIO_V1_00 ++# select GK_GPIO_V1_10 ++ select GK_GPIO_V1_20 ++ select GK_UART ++ select GK_UART_V1_00 ++# select GK_UART_V1_10 ++# select GK_UART_V1_20 ++ select GK_MUSB ++# select GK_MUSB_CON_V1_00 ++ select GK_MUSB_CON_V1_10 ++ select GK_USB_DMA ++ select GK_USB_DMA_V1_00 ++# select GK_USB_DMA_V1_10 ++ select GK_USB_PHY ++ select GK_USB_PHY_V1_00 ++ select GK_I2S ++ select GK_I2S_V1_00 ++ select GK_AUD_CON ++ select GK_AUD_CON_V1_00 ++ select GK_AUD_AD ++ select GK_AUD_AD_V1_00 ++ select GK_AUD_DMA ++ select GK_AUD_DMA_V1_00 ++# select GK_AUD_DMA_V1_10 ++ select GK_ETH ++ select GK_ETH_EMAC ++ select GK_ETH_EMAC_V1_01 ++ select GK_ETH_EDMA ++ select GK_ETH_EDMA_V1_00 ++ select GK_ETH_EPHY ++ select GK_ETH_EPHY_V1_00 ++ select GK_PWM ++ select GK_PWM_V1_00 ++ select GK_SDIO ++ select GK_SDIO2 ++ select GK_SDIO2_V1_00 ++# select GK_SDIO3 ++# select GK_SDIO3_V1_00 ++ select GK_ADC ++ select GK_ADC_V1_00 ++# select GK_ADC_V1_10 ++ select GK_I2C ++ select GK_I2C_V1_00 ++ select GK_SFLASH ++ select GK_SFLASH_V1_00 ++ select GK_SPI ++ select GK_SPI_V1_00 ++ select GK_PMU ++ select GK_PMU_V1_00 ++# select GK_PMU_V1_10 ++ select GK_MCU ++ select GK_MCU_V1_00 ++ select GK_RTC ++ select GK_RTC_V1_00 ++ select GK_IR ++ select GK_IR_V1_00 ++ select GK_VOUT ++ select GK_VOUT_V1_00 ++# select GK_VOUT_V1_10 ++# select GK_VOUT_V1_20 ++ select GK_HDMI ++ select GK_HDMI_V1_00 ++ select GK_MIPI ++ select GK_MIPI_V1_00 ++ select GK_VIN ++ select GK_VIN_V1_00 ++# select GK_VIN_V1_10 ++# select GK_VIN_V1_20 ++ select GK_MDMA ++ select GK_MDMA_V1_00 ++ select GK_SMEM ++ select GK_SMEM_V1_00 ++# select GK_SMEM_V1_10 ++ select GK_DSP1 ++ select GK_DSP1_V1_00 ++ select GK_DSP2 ++ select GK_DSP2_V1_00 ++ select GK_ISP ++ select GK_ISP_V1_00 ++# select GK_ISP_V1_10 ++ select GK_FW ++ select GK_FW_V1_00 ++# select GK_FW_V1_10 ++# select GK_FW_V1_20 ++ select GK_FB ++ select GK_FB_V1_00 ++ help ++ Support for Goke GK720X(GK7201/GK7202/GK7203...) FPGA ++ + config ARCH_NETX + bool "Hilscher NetX based" + select CLKSRC_MMIO +@@ -1128,6 +1961,14 @@ source "arch/arm/mach-vt8500/Kconfig" + + source "arch/arm/mach-w90x900/Kconfig" + ++source "arch/arm/mach-gk710x/Kconfig" ++ ++source "arch/arm/mach-gk710xs/Kconfig" ++ ++ ++ ++source "arch/arm/plat-goke/Kconfig" ++ + # Definitions to make life easier + config ARCH_ACORN + bool +@@ -1618,10 +2459,16 @@ config LOCAL_TIMERS + "thundering herd" at every timer tick. + + config ARCH_NR_GPIO +- int ++ int "gpio numbers" + default 1024 if ARCH_SHMOBILE || ARCH_TEGRA + default 355 if ARCH_U8500 + default 264 if MACH_H4700 ++ default 55 if ARCH_GK710X ++ default 55 if ARCH_GK710X_FPGA ++ default 64 if ARCH_GK710XS ++ default 64 if ARCH_GK710XS_FPGA ++ default 64 if ARCH_GK720X_FPGA ++ default 64 if ARCH_GK720X + default 0 + help + Maximum number of GPIOs in the system. +@@ -1631,7 +2478,7 @@ config ARCH_NR_GPIO + source kernel/Kconfig.preempt + + config HZ +- int ++ int "TIME HZ" + default 200 if ARCH_EBSA110 || ARCH_S3C24XX || ARCH_S5P64X0 || \ + ARCH_S5PV210 || ARCH_EXYNOS4 + default OMAP_32K_TIMER_HZ if ARCH_OMAP && OMAP_32K_TIMER +diff --git a/arch/arm/Makefile b/arch/arm/Makefile +index 1d6402cb..66aee95c 100644 +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -131,6 +131,12 @@ endif + textofs-$(CONFIG_ARCH_MSM7X30) := 0x00208000 + textofs-$(CONFIG_ARCH_MSM8X60) := 0x00208000 + textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000 ++textofs-$(CONFIG_ARCH_GK710X) := $(shell printf "0x%08x" $$(($(CONFIG_TEXT_OFFSET) + 0x8000))) ++textofs-$(CONFIG_ARCH_GK710X_FPGA) := $(shell printf "0x%08x" $$(($(CONFIG_TEXT_OFFSET) + 0x8000))) ++textofs-$(CONFIG_ARCH_GK710XS) := $(shell printf "0x%08x" $$(($(CONFIG_TEXT_OFFSET) + 0x8000))) ++textofs-$(CONFIG_ARCH_GK710XS_FPGA) := $(shell printf "0x%08x" $$(($(CONFIG_TEXT_OFFSET) + 0x8000))) ++textofs-$(CONFIG_ARCH_GK720X) := $(shell printf "0x%08x" $$(($(CONFIG_TEXT_OFFSET) + 0x8000))) ++textofs-$(CONFIG_ARCH_GK720X_FPGA) := $(shell printf "0x%08x" $$(($(CONFIG_TEXT_OFFSET) + 0x8000))) + + # Machine directory name. This list is sorted alphanumerically + # by CONFIG_* macro name. +@@ -143,6 +149,12 @@ machine-$(CONFIG_ARCH_DOVE) := dove + machine-$(CONFIG_ARCH_EBSA110) := ebsa110 + machine-$(CONFIG_ARCH_EP93XX) := ep93xx + machine-$(CONFIG_ARCH_GEMINI) := gemini ++machine-$(CONFIG_ARCH_GK710X) := gk710x ++machine-$(CONFIG_ARCH_GK710X_FPGA) := gk710x_fpga ++machine-$(CONFIG_ARCH_GK710XS) := gk710xs ++machine-$(CONFIG_ARCH_GK710XS_FPGA) := gk710xs_fpga ++machine-$(CONFIG_ARCH_GK720X) := gk720x ++machine-$(CONFIG_ARCH_GK720X_FPGA) := gk720x_fpga + machine-$(CONFIG_ARCH_H720X) := h720x + machine-$(CONFIG_ARCH_HIGHBANK) := highbank + machine-$(CONFIG_ARCH_INTEGRATOR) := integrator +@@ -212,6 +224,7 @@ plat-$(CONFIG_PLAT_S3C24XX) := s3c24xx samsung + plat-$(CONFIG_PLAT_S5P) := s5p samsung + plat-$(CONFIG_PLAT_SPEAR) := spear + plat-$(CONFIG_PLAT_VERSATILE) := versatile ++plat-$(CONFIG_PLAT_GOKE) := goke + + ifeq ($(CONFIG_ARCH_EBSA110),y) + # This is what happens if you forget the IOCS16 line. +diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile +index c877087d..8fd609b1 100644 +--- a/arch/arm/boot/Makefile ++++ b/arch/arm/boot/Makefile +@@ -54,6 +54,9 @@ $(obj)/compressed/vmlinux: $(obj)/Image FORCE + $(obj)/zImage: $(obj)/compressed/vmlinux FORCE + $(call if_changed,objcopy) + @echo ' Kernel: $@ is ready' ++ @echo ' ZRELADDR = $(ZRELADDR)' ++ @echo ' PARAMS_PHYS = $(PARAMS_PHYS)' ++ @echo ' INITRD_PHYS = $(INITRD_PHYS)' + + endif + +diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c +index 8e2a8fca..85003fde 100644 +--- a/arch/arm/boot/compressed/misc.c ++++ b/arch/arm/boot/compressed/misc.c +@@ -1,7 +1,7 @@ + /* + * misc.c +- * +- * This is a collection of several routines from gzip-1.0.3 ++ * ++ * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 +@@ -10,7 +10,7 @@ + * + * Nicolas Pitre 1999/04/14 : + * For this code to run directly from Flash, all constant variables must +- * be marked with 'const' and all other variables initialized at run-time ++ * be marked with 'const' and all other variables initialized at run-time + * only. This way all non constant variables will end up in the bss segment, + * which should point to addresses in RAM and cleared to 0 on start. + * This allows for a much quicker boot time. +@@ -27,6 +27,24 @@ extern void error(char *x); + + #include + ++/* avoid EXPORT_SYMBOL warning. */ ++#define EXPORT_SYMBOL(x) ++ ++#if GPIO_HAL_MODE ++HAL_IO(gpio) ++#else ++DIR_IO(gpio) ++#endif ++#if RCT_HAL_MODE ++HAL_IO(rct) ++#else ++DIR_IO(rct) ++#endif ++#if UART_HAL_MODE ++HAL_IO(uart) ++#else ++DIR_IO(uart) ++#endif + #ifdef CONFIG_DEBUG_ICEDCC + + #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) || defined(CONFIG_CPU_V7) +@@ -129,6 +147,72 @@ asmlinkage void __div0(void) + + extern int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x)); + ++static inline void clk_setting(void) ++{ ++ u32 type; ++ u32 ARMFreq; ++ ++ type = *(volatile u32 *)CONFIG_U2K_PHY_TYPE; ++ ++ if(type != 0){ ++#ifdef CONFIG_PHY_USE_SD_CLK ++ gk_gpio_setbitsl(GK_PA_GPIO0 + 0x3c, 0x00000001); ++ gk_rct_clrbitsl(GK_PA_RCT + 0x108, 0x00000018); ++ gk_rct_writel(GK_PA_RCT + 0x014, 0x0011202D); ++ gk_rct_writel(GK_PA_RCT + 0x01c, 0x00D55555); ++ gk_rct_writel(GK_PA_RCT + 0x018, 0x00000016); ++#endif ++#ifdef CONFIG_PHY_USE_AO_MCLK ++ gk_rct_writel(GK_PA_RCT + 0x024, 0x00124021); ++ gk_rct_writel(GK_PA_RCT + 0x078, 0x00555555); ++ if(type == 2)//50MHz ++ gk_rct_writel(GK_PA_RCT + 0x084, 0x00000002); ++ else//25MHz ++ gk_rct_writel(GK_PA_RCT + 0x084, 0x00000004); ++ gk_rct_writel(GK_PA_RCT + 0x080, 0x00000001); ++#endif ++ } ++ else ++ { ++ gk_gpio_clrbitsl(GK_PA_GPIO0 + 0x3c, 0x00000001); ++#ifdef CONFIG_PHY_USE_SD_CLK ++ gk_rct_setbitsl(GK_PA_RCT + 0x108, 0x00000018); ++ gk_rct_writel(GK_PA_RCT + 0x014, 0x0011202E); ++ gk_rct_writel(GK_PA_RCT + 0x01c, 0x00000000); ++ gk_rct_writel(GK_PA_RCT + 0x018, 0x00000017); ++#endif ++ ++#ifdef CONFIG_PHY_USE_AO_MCLK ++ gk_rct_writel(GK_PA_RCT + 0x024, 0x00124020); ++ gk_rct_writel(GK_PA_RCT + 0x078, 0x00000000); ++ gk_rct_writel(GK_PA_RCT + 0x084, 0x00000004); ++ gk_rct_writel(GK_PA_RCT + 0x080, 0x00000001); ++#endif ++ } ++ ++//misc clock configure ++ // SFLASH ioctrl ++ gk_rct_writel(GK_PA_RCT + 0x0198, 0x00000011); ++ ++ // Sensor ioctrl ++ gk_rct_writel(GK_PA_RCT + 0x019C, 0x00000012); ++ // modify idsp arm freq ++ //[25:20]REFDIV ++ //[18:16]PSTDIV2 ++ //[14:12]PSTDIV1 ++ //[11:0]FBDIV ++ // Fout=(Fin / REFDIV)*FBDIV/ POSTDIV1/ POSTDIV2 ++ // 0x53 = 1G ++ // 0x4B = 900M ++ // 0x43 = 800M ++ // 0x32 = 600M ++ // 0x21 = 400M ++ // 0x29 = 500M ++ //putstr("modify idsp arm freq\n"); ++ ARMFreq = *(volatile u32 *)CONFIG_U2K_ARM_FREQ; ++ gk_rct_writel(GK_PA_RCT + 0x8c, ARMFreq); ++} ++ + + void + decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p, +@@ -144,6 +228,8 @@ decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p, + + arch_decomp_setup(); + ++ clk_setting(); ++ + putstr("Uncompressing Linux..."); + ret = do_decompress(input_data, input_data_end - input_data, + output_data, error); +diff --git a/arch/arm/configs/gk710x_evb_mini_defconfig b/arch/arm/configs/gk710x_evb_mini_defconfig +new file mode 100644 +index 00000000..7b18b6b8 +--- /dev/null ++++ b/arch/arm/configs/gk710x_evb_mini_defconfig +@@ -0,0 +1,160 @@ ++# CONFIG_ARM_PATCH_PHYS_VIRT is not set ++CONFIG_PHYS_OFFSET=0xC0200000 ++CONFIG_EXPERIMENTAL=y ++CONFIG_CROSS_COMPILE="arm-goke-linux-uclibcgnueabi-" ++CONFIG_LOCALVERSION="-gk" ++# CONFIG_LOCALVERSION_AUTO is not set ++CONFIG_KERNEL_XZ=y ++CONFIG_DEFAULT_HOSTNAME="GK710X" ++CONFIG_SYSVIPC=y ++CONFIG_POSIX_MQUEUE=y ++CONFIG_IKCONFIG=y ++CONFIG_CGROUPS=y ++CONFIG_NAMESPACES=y ++CONFIG_RELAY=y ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_EMBEDDED=y ++# CONFIG_COMPAT_BRK is not set ++CONFIG_SLAB=y ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_ARCH_GK710X=y ++CONFIG_ONLY_USE_NOR_16M=y ++# CONFIG_ARM_THUMB is not set ++CONFIG_HIGH_RES_TIMERS=y ++CONFIG_VMSPLIT_2G=y ++CONFIG_PREEMPT=y ++CONFIG_AEABI=y ++CONFIG_KSM=y ++CONFIG_UACCESS_WITH_MEMCPY=y ++CONFIG_DEPRECATED_PARAM_STRUCT=y ++CONFIG_KEXEC=y ++CONFIG_VFP=y ++# CONFIG_SUSPEND is not set ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_UNIX_DIAG=y ++CONFIG_XFRM_USER=y ++CONFIG_NET_KEY=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++CONFIG_IP_ADVANCED_ROUTER=y ++CONFIG_IP_FIB_TRIE_STATS=y ++CONFIG_IP_MULTIPLE_TABLES=y ++CONFIG_IP_ROUTE_MULTIPATH=y ++CONFIG_IP_ROUTE_VERBOSE=y ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++CONFIG_IP_PNP_BOOTP=y ++CONFIG_IP_PNP_RARP=y ++CONFIG_NET_IPIP=y ++CONFIG_NET_IPGRE_DEMUX=y ++CONFIG_NET_IPGRE=y ++CONFIG_NET_IPGRE_BROADCAST=y ++CONFIG_IP_MROUTE=y ++CONFIG_IP_MROUTE_MULTIPLE_TABLES=y ++CONFIG_IP_PIMSM_V1=y ++CONFIG_IP_PIMSM_V2=y ++CONFIG_ARPD=y ++CONFIG_SYN_COOKIES=y ++CONFIG_INET_AH=y ++CONFIG_INET_ESP=y ++CONFIG_INET_IPCOMP=y ++CONFIG_INET_UDP_DIAG=y ++CONFIG_IPV6=y ++# CONFIG_WIRELESS is not set ++# CONFIG_FIRMWARE_IN_KERNEL is not set ++CONFIG_MTD=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_AFS_PARTS=y ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_SFLASH_GOKE=y ++CONFIG_MTD_SLRAM=y ++CONFIG_MTD_PHRAM=y ++CONFIG_MTD_BLOCK2MTD=y ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_ADC_GOKE=y ++CONFIG_NETDEVICES=y ++# CONFIG_NET_VENDOR_BROADCOM is not set ++# CONFIG_NET_VENDOR_CHELSIO is not set ++# CONFIG_NET_VENDOR_CIRRUS is not set ++CONFIG_ETH_GOKE=y ++# CONFIG_NET_VENDOR_FARADAY is not set ++# CONFIG_NET_VENDOR_INTEL is not set ++# CONFIG_NET_VENDOR_MARVELL is not set ++# CONFIG_NET_VENDOR_MICREL is not set ++# CONFIG_NET_VENDOR_MICROCHIP is not set ++# CONFIG_NET_VENDOR_NATSEMI is not set ++# CONFIG_NET_VENDOR_SEEQ is not set ++# CONFIG_NET_VENDOR_SMSC is not set ++# CONFIG_NET_VENDOR_STMICRO is not set ++CONFIG_INPUT_POLLDEV=y ++CONFIG_INPUT_EVDEV=y ++CONFIG_INPUT_EVBUG=y ++# CONFIG_INPUT_KEYBOARD is not set ++# CONFIG_INPUT_MOUSE is not set ++CONFIG_INPUT_MISC=y ++CONFIG_INPUT_GOKE_IR=y ++# CONFIG_SERIO is not set ++CONFIG_VT_HW_CONSOLE_BINDING=y ++CONFIG_DEVPTS_MULTIPLE_INSTANCES=y ++# CONFIG_LEGACY_PTYS is not set ++CONFIG_SERIAL_GOKE=y ++CONFIG_SERIAL_GOKE_CONSOLE=y ++# CONFIG_HW_RANDOM is not set ++CONFIG_I2C=y ++CONFIG_I2C_CHARDEV=y ++CONFIG_I2C_GOKE=y ++CONFIG_SPI=y ++CONFIG_SPI_SPIDEV=y ++CONFIG_SPI_GOKE=y ++CONFIG_GPIO_SYSFS=y ++# CONFIG_HWMON is not set ++CONFIG_WATCHDOG=y ++CONFIG_WATCHDOG_CORE=y ++CONFIG_WATCHDOG_GOKE=y ++# CONFIG_HID_SUPPORT is not set ++# CONFIG_USB_SUPPORT is not set ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_DEBUG=y ++CONFIG_RTC_DRV_GOKE=y ++CONFIG_DMADEVICES=y ++CONFIG_DMADEVICES_DEBUG=y ++# CONFIG_IOMMU_SUPPORT is not set ++CONFIG_AUTOFS4_FS=y ++CONFIG_FSCACHE=y ++CONFIG_CACHEFILES=y ++CONFIG_TMPFS=y ++CONFIG_TMPFS_POSIX_ACL=y ++CONFIG_CONFIGFS_FS=y ++CONFIG_JFFS2_FS=y ++CONFIG_SQUASHFS=y ++# CONFIG_SQUASHFS_ZLIB is not set ++CONFIG_SQUASHFS_XZ=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_NFS_V4=y ++CONFIG_ROOT_NFS=y ++CONFIG_NLS=y ++CONFIG_NLS_DEFAULT="cp437" ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_PRINTK_TIME=y ++# CONFIG_ENABLE_WARN_DEPRECATED is not set ++# CONFIG_ENABLE_MUST_CHECK is not set ++CONFIG_FRAME_WARN=0 ++# CONFIG_FTRACE is not set ++# CONFIG_ARM_UNWIND is not set ++CONFIG_CRYPTO_ECB=y ++CONFIG_CRYPTO_CRC32C=y ++CONFIG_CRYPTO_MICHAEL_MIC=y ++CONFIG_CRYPTO_ARC4=y ++CONFIG_CRYPTO_LZO=y ++CONFIG_CRYPTO_ANSI_CPRNG=y ++CONFIG_CRC16=y ++CONFIG_CRC_T10DIF=y ++CONFIG_CRC_ITU_T=y ++CONFIG_AVERAGE=y +diff --git a/arch/arm/configs/gk710xs_evb_mini_defconfig b/arch/arm/configs/gk710xs_evb_mini_defconfig +new file mode 100644 +index 00000000..358862f8 +--- /dev/null ++++ b/arch/arm/configs/gk710xs_evb_mini_defconfig +@@ -0,0 +1,160 @@ ++# CONFIG_ARM_PATCH_PHYS_VIRT is not set ++CONFIG_PHYS_OFFSET=0xC0200000 ++CONFIG_EXPERIMENTAL=y ++CONFIG_CROSS_COMPILE="arm-goke-linux-uclibcgnueabi-" ++CONFIG_LOCALVERSION="-gk" ++# CONFIG_LOCALVERSION_AUTO is not set ++CONFIG_KERNEL_XZ=y ++CONFIG_DEFAULT_HOSTNAME="GK710XS" ++CONFIG_SYSVIPC=y ++CONFIG_POSIX_MQUEUE=y ++CONFIG_IKCONFIG=y ++CONFIG_CGROUPS=y ++CONFIG_NAMESPACES=y ++CONFIG_RELAY=y ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_EMBEDDED=y ++# CONFIG_COMPAT_BRK is not set ++CONFIG_SLAB=y ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_ARCH_GK710XS=y ++CONFIG_ONLY_USE_NOR_16M=y ++# CONFIG_ARM_THUMB is not set ++CONFIG_MULTI_IRQ_HANDLER=y ++CONFIG_VMSPLIT_2G=y ++CONFIG_PREEMPT=y ++CONFIG_AEABI=y ++CONFIG_KSM=y ++CONFIG_UACCESS_WITH_MEMCPY=y ++CONFIG_DEPRECATED_PARAM_STRUCT=y ++CONFIG_KEXEC=y ++CONFIG_VFP=y ++# CONFIG_SUSPEND is not set ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_UNIX_DIAG=y ++CONFIG_XFRM_USER=y ++CONFIG_NET_KEY=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++CONFIG_IP_ADVANCED_ROUTER=y ++CONFIG_IP_FIB_TRIE_STATS=y ++CONFIG_IP_MULTIPLE_TABLES=y ++CONFIG_IP_ROUTE_MULTIPATH=y ++CONFIG_IP_ROUTE_VERBOSE=y ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++CONFIG_IP_PNP_BOOTP=y ++CONFIG_IP_PNP_RARP=y ++CONFIG_NET_IPIP=y ++CONFIG_NET_IPGRE_DEMUX=y ++CONFIG_NET_IPGRE=y ++CONFIG_NET_IPGRE_BROADCAST=y ++CONFIG_IP_MROUTE=y ++CONFIG_IP_MROUTE_MULTIPLE_TABLES=y ++CONFIG_IP_PIMSM_V1=y ++CONFIG_IP_PIMSM_V2=y ++CONFIG_ARPD=y ++CONFIG_SYN_COOKIES=y ++CONFIG_INET_AH=y ++CONFIG_INET_ESP=y ++CONFIG_INET_IPCOMP=y ++CONFIG_INET_UDP_DIAG=y ++CONFIG_IPV6=y ++# CONFIG_WIRELESS is not set ++# CONFIG_FIRMWARE_IN_KERNEL is not set ++CONFIG_MTD=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_AFS_PARTS=y ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_SFLASH_GOKE=y ++CONFIG_MTD_SLRAM=y ++CONFIG_MTD_PHRAM=y ++CONFIG_MTD_BLOCK2MTD=y ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_ADC_GOKE=y ++CONFIG_NETDEVICES=y ++# CONFIG_NET_VENDOR_BROADCOM is not set ++# CONFIG_NET_VENDOR_CHELSIO is not set ++# CONFIG_NET_VENDOR_CIRRUS is not set ++CONFIG_ETH_GOKE=y ++# CONFIG_NET_VENDOR_FARADAY is not set ++# CONFIG_NET_VENDOR_INTEL is not set ++# CONFIG_NET_VENDOR_MARVELL is not set ++# CONFIG_NET_VENDOR_MICREL is not set ++# CONFIG_NET_VENDOR_MICROCHIP is not set ++# CONFIG_NET_VENDOR_NATSEMI is not set ++# CONFIG_NET_VENDOR_SEEQ is not set ++# CONFIG_NET_VENDOR_SMSC is not set ++# CONFIG_NET_VENDOR_STMICRO is not set ++CONFIG_INPUT_POLLDEV=y ++CONFIG_INPUT_EVDEV=y ++CONFIG_INPUT_EVBUG=y ++# CONFIG_INPUT_KEYBOARD is not set ++# CONFIG_INPUT_MOUSE is not set ++CONFIG_INPUT_MISC=y ++CONFIG_INPUT_GOKE_IR=y ++# CONFIG_SERIO is not set ++CONFIG_VT_HW_CONSOLE_BINDING=y ++CONFIG_DEVPTS_MULTIPLE_INSTANCES=y ++# CONFIG_LEGACY_PTYS is not set ++CONFIG_SERIAL_GOKE=y ++CONFIG_SERIAL_GOKE_CONSOLE=y ++# CONFIG_HW_RANDOM is not set ++CONFIG_I2C=y ++CONFIG_I2C_CHARDEV=y ++CONFIG_I2C_GOKE=y ++CONFIG_SPI=y ++CONFIG_SPI_SPIDEV=y ++CONFIG_SPI_GOKE=y ++CONFIG_GPIO_SYSFS=y ++# CONFIG_HWMON is not set ++CONFIG_WATCHDOG=y ++CONFIG_WATCHDOG_CORE=y ++CONFIG_WATCHDOG_GOKE=y ++# CONFIG_HID_SUPPORT is not set ++# CONFIG_USB_SUPPORT is not set ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_DEBUG=y ++CONFIG_RTC_DRV_GOKE=y ++CONFIG_DMADEVICES=y ++CONFIG_DMADEVICES_DEBUG=y ++# CONFIG_IOMMU_SUPPORT is not set ++CONFIG_AUTOFS4_FS=y ++CONFIG_FSCACHE=y ++CONFIG_CACHEFILES=y ++CONFIG_TMPFS=y ++CONFIG_TMPFS_POSIX_ACL=y ++CONFIG_CONFIGFS_FS=y ++CONFIG_JFFS2_FS=y ++CONFIG_SQUASHFS=y ++# CONFIG_SQUASHFS_ZLIB is not set ++CONFIG_SQUASHFS_XZ=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_NFS_V4=y ++CONFIG_ROOT_NFS=y ++CONFIG_NLS=y ++CONFIG_NLS_DEFAULT="cp437" ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_PRINTK_TIME=y ++# CONFIG_ENABLE_WARN_DEPRECATED is not set ++# CONFIG_ENABLE_MUST_CHECK is not set ++CONFIG_FRAME_WARN=0 ++# CONFIG_FTRACE is not set ++# CONFIG_ARM_UNWIND is not set ++CONFIG_CRYPTO_ECB=y ++CONFIG_CRYPTO_CRC32C=y ++CONFIG_CRYPTO_MICHAEL_MIC=y ++CONFIG_CRYPTO_ARC4=y ++CONFIG_CRYPTO_LZO=y ++CONFIG_CRYPTO_ANSI_CPRNG=y ++CONFIG_CRC16=y ++CONFIG_CRC_T10DIF=y ++CONFIG_CRC_ITU_T=y ++CONFIG_AVERAGE=y +diff --git a/arch/arm/configs/gk720x_evb_mini_defconfig b/arch/arm/configs/gk720x_evb_mini_defconfig +new file mode 100644 +index 00000000..a4662527 +--- /dev/null ++++ b/arch/arm/configs/gk720x_evb_mini_defconfig +@@ -0,0 +1,169 @@ ++# CONFIG_ARM_PATCH_PHYS_VIRT is not set ++CONFIG_PHYS_OFFSET=0xC0300000 ++CONFIG_EXPERIMENTAL=y ++CONFIG_CROSS_COMPILE="arm-goke-linux-uclibcgnueabi-" ++CONFIG_LOCALVERSION="-gk" ++# CONFIG_LOCALVERSION_AUTO is not set ++CONFIG_KERNEL_XZ=y ++CONFIG_DEFAULT_HOSTNAME="GK720X" ++CONFIG_SYSVIPC=y ++CONFIG_POSIX_MQUEUE=y ++CONFIG_IKCONFIG=y ++CONFIG_CGROUPS=y ++CONFIG_NAMESPACES=y ++CONFIG_RELAY=y ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_EMBEDDED=y ++# CONFIG_COMPAT_BRK is not set ++CONFIG_SLAB=y ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_ARCH_GK720X=y ++CONFIG_ONLY_USE_NOR_16M=y ++# CONFIG_ARM_THUMB is not set ++CONFIG_MULTI_IRQ_HANDLER=y ++CONFIG_VMSPLIT_2G=y ++CONFIG_PREEMPT=y ++CONFIG_AEABI=y ++CONFIG_KSM=y ++CONFIG_UACCESS_WITH_MEMCPY=y ++CONFIG_DEPRECATED_PARAM_STRUCT=y ++CONFIG_KEXEC=y ++CONFIG_VFP=y ++# CONFIG_SUSPEND is not set ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_UNIX_DIAG=y ++CONFIG_XFRM_USER=y ++CONFIG_NET_KEY=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++CONFIG_IP_ADVANCED_ROUTER=y ++CONFIG_IP_FIB_TRIE_STATS=y ++CONFIG_IP_MULTIPLE_TABLES=y ++CONFIG_IP_ROUTE_MULTIPATH=y ++CONFIG_IP_ROUTE_VERBOSE=y ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++CONFIG_IP_PNP_BOOTP=y ++CONFIG_IP_PNP_RARP=y ++CONFIG_NET_IPIP=y ++CONFIG_NET_IPGRE_DEMUX=y ++CONFIG_NET_IPGRE=y ++CONFIG_NET_IPGRE_BROADCAST=y ++CONFIG_IP_MROUTE=y ++CONFIG_IP_MROUTE_MULTIPLE_TABLES=y ++CONFIG_IP_PIMSM_V1=y ++CONFIG_IP_PIMSM_V2=y ++CONFIG_ARPD=y ++CONFIG_SYN_COOKIES=y ++CONFIG_INET_AH=y ++CONFIG_INET_ESP=y ++CONFIG_INET_IPCOMP=y ++CONFIG_INET_UDP_DIAG=y ++CONFIG_IPV6=y ++CONFIG_INITRAMFS_SOURCE="/opt/goke/rootfs_uClibc" ++CONFIG_INITRAMFS_ROOT_UID=0 ++CONFIG_INITRAMFS_ROOT_GID=0 ++CONFIG_RD_GZIP=y ++# CONFIG_RD_BZIP2 is not set ++# CONFIG_RD_LZMA is not set ++# CONFIG_RD_XZ is not set ++# CONFIG_RD_LZO is not set ++CONFIG_INITRAMFS_COMPRESSION_NONE=y ++# CONFIG_WIRELESS is not set ++# CONFIG_FIRMWARE_IN_KERNEL is not set ++CONFIG_MTD=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_AFS_PARTS=y ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_SFLASH_GOKE=y ++CONFIG_MTD_SLRAM=y ++CONFIG_MTD_PHRAM=y ++CONFIG_MTD_BLOCK2MTD=y ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_ADC_GOKE=y ++CONFIG_NETDEVICES=y ++# CONFIG_NET_VENDOR_BROADCOM is not set ++# CONFIG_NET_VENDOR_CHELSIO is not set ++# CONFIG_NET_VENDOR_CIRRUS is not set ++CONFIG_ETH_GOKE=y ++# CONFIG_NET_VENDOR_FARADAY is not set ++# CONFIG_NET_VENDOR_INTEL is not set ++# CONFIG_NET_VENDOR_MARVELL is not set ++# CONFIG_NET_VENDOR_MICREL is not set ++# CONFIG_NET_VENDOR_MICROCHIP is not set ++# CONFIG_NET_VENDOR_NATSEMI is not set ++# CONFIG_NET_VENDOR_SEEQ is not set ++# CONFIG_NET_VENDOR_SMSC is not set ++# CONFIG_NET_VENDOR_STMICRO is not set ++CONFIG_INPUT_POLLDEV=y ++CONFIG_INPUT_EVDEV=y ++CONFIG_INPUT_EVBUG=y ++# CONFIG_INPUT_KEYBOARD is not set ++# CONFIG_INPUT_MOUSE is not set ++CONFIG_INPUT_MISC=y ++CONFIG_INPUT_GOKE_IR=y ++# CONFIG_SERIO is not set ++CONFIG_VT_HW_CONSOLE_BINDING=y ++CONFIG_DEVPTS_MULTIPLE_INSTANCES=y ++# CONFIG_LEGACY_PTYS is not set ++CONFIG_SERIAL_GOKE=y ++CONFIG_SERIAL_GOKE_CONSOLE=y ++# CONFIG_HW_RANDOM is not set ++CONFIG_I2C=y ++CONFIG_I2C_CHARDEV=y ++CONFIG_I2C_GOKE=y ++CONFIG_SPI=y ++CONFIG_SPI_SPIDEV=y ++CONFIG_SPI_GOKE=y ++CONFIG_GPIO_SYSFS=y ++# CONFIG_HWMON is not set ++CONFIG_WATCHDOG=y ++CONFIG_WATCHDOG_CORE=y ++CONFIG_WATCHDOG_GOKE=y ++# CONFIG_HID_SUPPORT is not set ++# CONFIG_USB_SUPPORT is not set ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_DEBUG=y ++CONFIG_RTC_DRV_GOKE=y ++CONFIG_DMADEVICES=y ++CONFIG_DMADEVICES_DEBUG=y ++# CONFIG_IOMMU_SUPPORT is not set ++CONFIG_AUTOFS4_FS=y ++CONFIG_FSCACHE=y ++CONFIG_CACHEFILES=y ++CONFIG_TMPFS=y ++CONFIG_TMPFS_POSIX_ACL=y ++CONFIG_CONFIGFS_FS=y ++CONFIG_JFFS2_FS=y ++CONFIG_SQUASHFS=y ++# CONFIG_SQUASHFS_ZLIB is not set ++CONFIG_SQUASHFS_XZ=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_NFS_V4=y ++CONFIG_ROOT_NFS=y ++CONFIG_NLS=y ++CONFIG_NLS_DEFAULT="cp437" ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_PRINTK_TIME=y ++# CONFIG_ENABLE_WARN_DEPRECATED is not set ++# CONFIG_ENABLE_MUST_CHECK is not set ++CONFIG_FRAME_WARN=0 ++# CONFIG_FTRACE is not set ++# CONFIG_ARM_UNWIND is not set ++CONFIG_CRYPTO_ECB=y ++CONFIG_CRYPTO_CRC32C=y ++CONFIG_CRYPTO_MICHAEL_MIC=y ++CONFIG_CRYPTO_ARC4=y ++CONFIG_CRYPTO_LZO=y ++CONFIG_CRYPTO_ANSI_CPRNG=y ++CONFIG_CRC16=y ++CONFIG_CRC_T10DIF=y ++CONFIG_CRC_ITU_T=y ++CONFIG_AVERAGE=y +diff --git a/arch/arm/configs/gk720x_fpga_mini_defconfig b/arch/arm/configs/gk720x_fpga_mini_defconfig +new file mode 100644 +index 00000000..e224feba +--- /dev/null ++++ b/arch/arm/configs/gk720x_fpga_mini_defconfig +@@ -0,0 +1,169 @@ ++# CONFIG_ARM_PATCH_PHYS_VIRT is not set ++CONFIG_PHYS_OFFSET=0xC0300000 ++CONFIG_EXPERIMENTAL=y ++CONFIG_CROSS_COMPILE="arm-goke-linux-uclibcgnueabi-" ++CONFIG_LOCALVERSION="-gk" ++# CONFIG_LOCALVERSION_AUTO is not set ++CONFIG_KERNEL_XZ=y ++CONFIG_DEFAULT_HOSTNAME="GK720X_FPGA" ++CONFIG_SYSVIPC=y ++CONFIG_POSIX_MQUEUE=y ++CONFIG_IKCONFIG=y ++CONFIG_CGROUPS=y ++CONFIG_NAMESPACES=y ++CONFIG_RELAY=y ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_EMBEDDED=y ++# CONFIG_COMPAT_BRK is not set ++CONFIG_SLAB=y ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_ARCH_GK720X_FPGA=y ++CONFIG_ONLY_USE_NOR_16M=y ++# CONFIG_ARM_THUMB is not set ++CONFIG_MULTI_IRQ_HANDLER=y ++CONFIG_VMSPLIT_2G=y ++CONFIG_PREEMPT=y ++CONFIG_AEABI=y ++CONFIG_KSM=y ++CONFIG_UACCESS_WITH_MEMCPY=y ++CONFIG_DEPRECATED_PARAM_STRUCT=y ++CONFIG_KEXEC=y ++CONFIG_VFP=y ++# CONFIG_SUSPEND is not set ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_UNIX_DIAG=y ++CONFIG_XFRM_USER=y ++CONFIG_NET_KEY=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++CONFIG_IP_ADVANCED_ROUTER=y ++CONFIG_IP_FIB_TRIE_STATS=y ++CONFIG_IP_MULTIPLE_TABLES=y ++CONFIG_IP_ROUTE_MULTIPATH=y ++CONFIG_IP_ROUTE_VERBOSE=y ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++CONFIG_IP_PNP_BOOTP=y ++CONFIG_IP_PNP_RARP=y ++CONFIG_NET_IPIP=y ++CONFIG_NET_IPGRE_DEMUX=y ++CONFIG_NET_IPGRE=y ++CONFIG_NET_IPGRE_BROADCAST=y ++CONFIG_IP_MROUTE=y ++CONFIG_IP_MROUTE_MULTIPLE_TABLES=y ++CONFIG_IP_PIMSM_V1=y ++CONFIG_IP_PIMSM_V2=y ++CONFIG_ARPD=y ++CONFIG_SYN_COOKIES=y ++CONFIG_INET_AH=y ++CONFIG_INET_ESP=y ++CONFIG_INET_IPCOMP=y ++CONFIG_INET_UDP_DIAG=y ++CONFIG_IPV6=y ++CONFIG_INITRAMFS_SOURCE="/opt/goke/rootfs_uClibc" ++CONFIG_INITRAMFS_ROOT_UID=0 ++CONFIG_INITRAMFS_ROOT_GID=0 ++CONFIG_RD_GZIP=y ++# CONFIG_RD_BZIP2 is not set ++# CONFIG_RD_LZMA is not set ++# CONFIG_RD_XZ is not set ++# CONFIG_RD_LZO is not set ++CONFIG_INITRAMFS_COMPRESSION_NONE=y ++# CONFIG_WIRELESS is not set ++# CONFIG_FIRMWARE_IN_KERNEL is not set ++CONFIG_MTD=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_AFS_PARTS=y ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_SFLASH_GOKE=y ++CONFIG_MTD_SLRAM=y ++CONFIG_MTD_PHRAM=y ++CONFIG_MTD_BLOCK2MTD=y ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_ADC_GOKE=y ++CONFIG_NETDEVICES=y ++# CONFIG_NET_VENDOR_BROADCOM is not set ++# CONFIG_NET_VENDOR_CHELSIO is not set ++# CONFIG_NET_VENDOR_CIRRUS is not set ++CONFIG_ETH_GOKE=y ++# CONFIG_NET_VENDOR_FARADAY is not set ++# CONFIG_NET_VENDOR_INTEL is not set ++# CONFIG_NET_VENDOR_MARVELL is not set ++# CONFIG_NET_VENDOR_MICREL is not set ++# CONFIG_NET_VENDOR_MICROCHIP is not set ++# CONFIG_NET_VENDOR_NATSEMI is not set ++# CONFIG_NET_VENDOR_SEEQ is not set ++# CONFIG_NET_VENDOR_SMSC is not set ++# CONFIG_NET_VENDOR_STMICRO is not set ++CONFIG_INPUT_POLLDEV=y ++CONFIG_INPUT_EVDEV=y ++CONFIG_INPUT_EVBUG=y ++# CONFIG_INPUT_KEYBOARD is not set ++# CONFIG_INPUT_MOUSE is not set ++CONFIG_INPUT_MISC=y ++CONFIG_INPUT_GOKE_IR=y ++# CONFIG_SERIO is not set ++CONFIG_VT_HW_CONSOLE_BINDING=y ++CONFIG_DEVPTS_MULTIPLE_INSTANCES=y ++# CONFIG_LEGACY_PTYS is not set ++CONFIG_SERIAL_GOKE=y ++CONFIG_SERIAL_GOKE_CONSOLE=y ++# CONFIG_HW_RANDOM is not set ++CONFIG_I2C=y ++CONFIG_I2C_CHARDEV=y ++CONFIG_I2C_GOKE=y ++CONFIG_SPI=y ++CONFIG_SPI_SPIDEV=y ++CONFIG_SPI_GOKE=y ++CONFIG_GPIO_SYSFS=y ++# CONFIG_HWMON is not set ++CONFIG_WATCHDOG=y ++CONFIG_WATCHDOG_CORE=y ++CONFIG_WATCHDOG_GOKE=y ++# CONFIG_HID_SUPPORT is not set ++# CONFIG_USB_SUPPORT is not set ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_DEBUG=y ++CONFIG_RTC_DRV_GOKE=y ++CONFIG_DMADEVICES=y ++CONFIG_DMADEVICES_DEBUG=y ++# CONFIG_IOMMU_SUPPORT is not set ++CONFIG_AUTOFS4_FS=y ++CONFIG_FSCACHE=y ++CONFIG_CACHEFILES=y ++CONFIG_TMPFS=y ++CONFIG_TMPFS_POSIX_ACL=y ++CONFIG_CONFIGFS_FS=y ++CONFIG_JFFS2_FS=y ++CONFIG_SQUASHFS=y ++# CONFIG_SQUASHFS_ZLIB is not set ++CONFIG_SQUASHFS_XZ=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_NFS_V4=y ++CONFIG_ROOT_NFS=y ++CONFIG_NLS=y ++CONFIG_NLS_DEFAULT="cp437" ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_PRINTK_TIME=y ++# CONFIG_ENABLE_WARN_DEPRECATED is not set ++# CONFIG_ENABLE_MUST_CHECK is not set ++CONFIG_FRAME_WARN=0 ++# CONFIG_FTRACE is not set ++# CONFIG_ARM_UNWIND is not set ++CONFIG_CRYPTO_ECB=y ++CONFIG_CRYPTO_CRC32C=y ++CONFIG_CRYPTO_MICHAEL_MIC=y ++CONFIG_CRYPTO_ARC4=y ++CONFIG_CRYPTO_LZO=y ++CONFIG_CRYPTO_ANSI_CPRNG=y ++CONFIG_CRC16=y ++CONFIG_CRC_T10DIF=y ++CONFIG_CRC_ITU_T=y ++CONFIG_AVERAGE=y +diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h +index 9af5563d..619c4132 100644 +--- a/arch/arm/include/asm/io.h ++++ b/arch/arm/include/asm/io.h +@@ -28,6 +28,10 @@ + #include + #include + ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++#include ++#include ++ + /* + * ISA I/O bus memory addresses are 1:1 with the physical address. + */ +@@ -47,13 +51,15 @@ extern void __raw_readsb(const void __iomem *addr, void *data, int bytelen); + extern void __raw_readsw(const void __iomem *addr, void *data, int wordlen); + extern void __raw_readsl(const void __iomem *addr, void *data, int longlen); + +-#define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v)) +-#define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v)) +-#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v)) + +-#define __raw_readb(a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a)) +-#define __raw_readw(a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a)) +-#define __raw_readl(a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a)) ++#define __raw_writeb(v,a) (__chk_io_ptr(a), gk_hw_writeb((u32)a,v)) ++#define __raw_writew(v,a) (__chk_io_ptr(a), gk_hw_writew((u32)a,v)) ++#define __raw_writel(v,a) (__chk_io_ptr(a), gk_hw_writel((u32)a,v)) ++ ++#define __raw_readb(a) (__chk_io_ptr(a), gk_hw_readb((u32)a)) ++#define __raw_readw(a) (__chk_io_ptr(a), gk_hw_readw((u32)a)) ++#define __raw_readl(a) (__chk_io_ptr(a), gk_hw_readl((u32)a)) ++ + + /* + * Architecture ioremap implementation. +diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h +index fcb57574..32d1f18a 100644 +--- a/arch/arm/include/asm/memory.h ++++ b/arch/arm/include/asm/memory.h +@@ -81,6 +81,7 @@ + #define IOREMAP_MAX_ORDER 24 + + #define CONSISTENT_END (0xffe00000UL) ++#define CONSISTENT_BASE (CONSISTENT_END - CONSISTENT_DMA_SIZE) + + #else /* CONFIG_MMU */ + +diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h +index 41dc31f8..83a83ea0 100644 +--- a/arch/arm/include/asm/pgtable.h ++++ b/arch/arm/include/asm/pgtable.h +@@ -105,7 +105,8 @@ extern pgprot_t pgprot_kernel; + + #ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE + #define pgprot_dmacoherent(prot) \ +- __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE | L_PTE_XN) ++ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED) ++// __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE | L_PTE_XN) + #define __HAVE_PHYS_MEM_ACCESS_PROT + struct file; + extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, +diff --git a/arch/arm/lib/memcpy.S b/arch/arm/lib/memcpy.S +index a9b9e228..25d403ef 100644 +--- a/arch/arm/lib/memcpy.S ++++ b/arch/arm/lib/memcpy.S +@@ -47,6 +47,10 @@ + .macro enter reg1 reg2 + stmdb sp!, {r0, \reg1, \reg2} + .endm ++ ++ .macro usave reg1 reg2 ++ UNWIND( .save {r0, \reg1, \reg2} ) ++ .endm + + .macro exit reg1 reg2 + ldmfd sp!, {r0, \reg1, \reg2} +diff --git a/arch/arm/mach-gk710x/Kconfig b/arch/arm/mach-gk710x/Kconfig +new file mode 100644 +index 00000000..9db429ca +--- /dev/null ++++ b/arch/arm/mach-gk710x/Kconfig +@@ -0,0 +1,27 @@ ++# ++# arch/arm/mach-gk710x/Kconfig ++# ++# History: ++# 2014/06/18 - [Kewell Liu] created file ++# ++# Copyright (C) 2002-2016, Goke Microelectronics China. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++# ++ ++if ARCH_GK710X ++ ++endif ++ +diff --git a/arch/arm/mach-gk710x/Makefile b/arch/arm/mach-gk710x/Makefile +new file mode 100644 +index 00000000..e5835428 +--- /dev/null ++++ b/arch/arm/mach-gk710x/Makefile +@@ -0,0 +1,13 @@ ++ ++obj-$(CONFIG_ARCH_GK710X) += gk710x.o ++obj-$(CONFIG_ARCH_GK710X) += irq.o ++obj-$(CONFIG_ARCH_GK710X) += rct.o ++obj-$(CONFIG_ARCH_GK710X) += mdma.o dma.o ++obj-$(CONFIG_ARCH_GK710X) += vi.o ++ ++obj-$(CONFIG_ARCH_GK710X) += mach-gk710x.o ++ ++ccflags-$(CONFIG_ARCH_GK710X) += -D__LINUX__ ++ ++ccflags-$(CONFIG_ARCH_GK710X) += -Iarch/arm/mach-gk710x/include ++ +diff --git a/arch/arm/mach-gk710x/Makefile.boot b/arch/arm/mach-gk710x/Makefile.boot +new file mode 100644 +index 00000000..f835b343 +--- /dev/null ++++ b/arch/arm/mach-gk710x/Makefile.boot +@@ -0,0 +1,6 @@ ++ ++zreladdr-y := $(shell printf "0x%08x" $$(($(CONFIG_PHYS_OFFSET) + $(TEXT_OFFSET)))) ++params_phys-y := $(shell printf "0x%08x" $$(($(CONFIG_PHYS_OFFSET) + 0x100))) ++ ++dtb-y += gk7101-evb.dtb ++ +diff --git a/arch/arm/mach-gk710x/dma.c b/arch/arm/mach-gk710x/dma.c +new file mode 100644 +index 00000000..9304ee04 +--- /dev/null ++++ b/arch/arm/mach-gk710x/dma.c +@@ -0,0 +1,507 @@ ++/* ++ * arch/arm/mach-gk/dma.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static struct dma_s G_dma; ++static spinlock_t dma_lock; ++static gk_dma_req_t *dummy_descriptor = NULL; ++static dma_addr_t dummy_descriptor_phys; ++ ++#ifdef CONFIG_GK_DMA_PROC ++static const char dma_proc_name[] = "dma"; ++static struct proc_dir_entry *dma_file; ++ ++static int gk_dma_proc_read(char *buf, char **start, off_t off, ++ int len, int *eof, void *data) ++{ ++ char *p = buf; ++ ++ p += sprintf(p, "You can add something here to debug DMA \n"); ++ ++ return p - buf; ++} ++#endif ++ ++extern void gk_usb_dma_irq(void); ++static irqreturn_t gk_dma_int_handler(int irq, void *dev_id) ++{ ++ struct dma_s *dma; ++ int i; ++ int j; ++ u32 ireg; ++ ++ dma = (struct dma_s *)dev_id; ++ ++ ireg = gk_dma_readl(DMA_INT_REG); ++ for (i = 0; i < NUM_DMA_CHANNELS; i++) { ++ if (ireg & (0x1 << i)) { ++ dma->chan[i].status = gk_dma_readl(DMA_CHAN_STA_REG(i)); ++ gk_dma_writel(DMA_CHAN_STA_REG(i), 0); ++ ++ for (j = 0; j < dma->chan[i].irq_count; j++) { ++ if (dma->chan[i].irq[j].enabled == 1) { ++ dma->chan[i].irq[j].handler( ++ dma->chan[i].irq[j].harg, ++ dma->chan[i].status); ++ } ++ } ++ } ++ } ++#if 0 ++ if (ireg & 0x8) { ++ //printk("@:%x\n", ireg); ++ //printk("$\n"); ++ gk_usb_dma_irq(); ++ } ++#endif ++ return IRQ_HANDLED; ++} ++ ++#if (DMA_SUPPORT_DMA_FIOS == 1) ++static irqreturn_t gk_dma_fios_int_handler(int irq, void *dev_id) ++{ ++ struct dma_s *dma; ++ int i; ++ u32 ireg; ++ ++ dma = (struct dma_s *)dev_id; ++ ++ ireg = gk_dma_readl(DMA_FIOS_INT_REG); ++ if (ireg & DMA_INT_CHAN0) { ++ dma->chan[FIO_DMA_CHAN].status = ++ gk_dma_readl(DMA_FIOS_CHAN_STA_REG(FIO_DMA_CHAN)); ++ gk_dma_writel(DMA_FIOS_CHAN_STA_REG(FIO_DMA_CHAN), 0); ++ ++ for (i = 0; i < dma->chan[FIO_DMA_CHAN].irq_count; i++) { ++ if (dma->chan[FIO_DMA_CHAN].irq[i].enabled == 1) { ++ dma->chan[FIO_DMA_CHAN].irq[i].handler( ++ dma->chan[FIO_DMA_CHAN].irq[i].harg, ++ dma->chan[FIO_DMA_CHAN].status); ++ } ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++#endif ++ ++int gk_dma_request_irq(int chan, ++ gk_dma_handler handler, void *harg) ++{ ++ int retval = 0; ++ int i; ++ unsigned long flags; ++ if (unlikely(chan < 0 || chan >= NUM_DMA_CHANNELS)) { ++ pr_err("%s: chan[%d] < NUM_DMA_CHANNELS[%d]!\n", ++ __func__, chan, NUM_DMA_CHANNELS); ++ retval = -EINVAL; ++ goto gk_dma_request_irq_exit_na; ++ } ++ ++ if (unlikely(handler == NULL)) { ++ pr_err("%s: handler is NULL!\n", __func__); ++ retval = -EINVAL; ++ goto gk_dma_request_irq_exit_na; ++ } ++ ++ spin_lock_irqsave(&dma_lock, flags); ++ if (unlikely(G_dma.chan[chan].irq_count > ++ MAX_DMA_CHANNEL_IRQ_HANDLERS)) { ++ pr_err("%s: chan[%d]'s irq_count[%d] > " ++ "MAX_DMA_CHANNEL_IRQ_HANDLERS[%d]!\n", ++ __func__, chan, G_dma.chan[chan].irq_count, ++ MAX_DMA_CHANNEL_IRQ_HANDLERS); ++ retval = -EINVAL; ++ goto gk_dma_request_irq_exit; ++ } ++ ++ for (i = 0; i < MAX_DMA_CHANNEL_IRQ_HANDLERS; i++) { ++ if (G_dma.chan[chan].irq[i].handler == NULL) { ++ G_dma.chan[chan].irq[i].enabled = 0; ++ G_dma.chan[chan].irq[i].handler = handler; ++ G_dma.chan[chan].irq[i].harg = harg; ++ G_dma.chan[chan].irq_count++; ++ break; ++ } ++ } ++ ++gk_dma_request_irq_exit: ++ spin_unlock_irqrestore(&dma_lock, flags); ++ ++gk_dma_request_irq_exit_na: ++ return retval; ++} ++EXPORT_SYMBOL(gk_dma_request_irq); ++ ++void gk_dma_free_irq(int chan, gk_dma_handler handler) ++{ ++ int i; ++ unsigned long flags; ++ ++ if (unlikely(chan < 0 || chan >= NUM_DMA_CHANNELS)) { ++ pr_err("%s: chan[%d] < NUM_DMA_CHANNELS[%d]!\n", ++ __func__, chan, NUM_DMA_CHANNELS); ++ return; ++ } ++ ++ if (unlikely(handler == NULL)) { ++ pr_err("%s: handler is NULL!\n", __func__); ++ return; ++ } ++ ++ spin_lock_irqsave(&dma_lock, flags); ++ if (unlikely(G_dma.chan[chan].irq_count > ++ MAX_DMA_CHANNEL_IRQ_HANDLERS)) { ++ pr_err("%s: chan[%d]'s irq_count[%d] > " ++ "MAX_DMA_CHANNEL_IRQ_HANDLERS[%d]!\n", ++ __func__, chan, G_dma.chan[chan].irq_count, ++ MAX_DMA_CHANNEL_IRQ_HANDLERS); ++ goto gk_dma_free_irq_exit; ++ } ++ ++ for (i = 0; i < MAX_DMA_CHANNEL_IRQ_HANDLERS; i++) { ++ if (G_dma.chan[chan].irq[i].handler == handler) { ++ G_dma.chan[chan].irq[i].enabled = 0; ++ G_dma.chan[chan].irq[i].handler = NULL; ++ G_dma.chan[chan].irq[i].harg = NULL; ++ G_dma.chan[chan].irq_count--; ++ break; ++ } ++ } ++ ++ for (i = i + 1; i < MAX_DMA_CHANNEL_IRQ_HANDLERS; i++) { ++ if (G_dma.chan[chan].irq[i].handler != NULL) { ++ G_dma.chan[chan].irq[i - 1].enabled = ++ G_dma.chan[chan].irq[i].enabled; ++ G_dma.chan[chan].irq[i - 1].handler = ++ G_dma.chan[chan].irq[i].handler; ++ G_dma.chan[chan].irq[i - 1].harg = ++ G_dma.chan[chan].irq[i].harg; ++ G_dma.chan[chan].irq[i].handler = NULL; ++ G_dma.chan[chan].irq[i].harg = NULL; ++ G_dma.chan[chan].irq[i].enabled = 0; ++ } ++ } ++ ++gk_dma_free_irq_exit: ++ spin_unlock_irqrestore(&dma_lock, flags); ++} ++EXPORT_SYMBOL(gk_dma_free_irq); ++ ++int gk_dma_enable_irq(int chan, gk_dma_handler handler) ++{ ++ int retval = 0; ++ int i; ++ unsigned long flags; ++ ++ if (unlikely(chan < 0 || chan >= NUM_DMA_CHANNELS)) { ++ pr_err("%s: chan[%d] < NUM_DMA_CHANNELS[%d]!\n", ++ __func__, chan, NUM_DMA_CHANNELS); ++ retval = -EINVAL; ++ goto gk_dma_enable_irq_na; ++ } ++ ++ if (unlikely(handler == NULL)) { ++ pr_err("%s: handler is NULL!\n", __func__); ++ retval = -EINVAL; ++ goto gk_dma_enable_irq_na; ++ } ++ ++ spin_lock_irqsave(&dma_lock, flags); ++ for (i = 0; i < MAX_DMA_CHANNEL_IRQ_HANDLERS; i++) { ++ if (G_dma.chan[chan].irq[i].handler == NULL) { ++ retval = -EINVAL; ++ pr_err("%s: can't find 0x%x!\n", ++ __func__, (u32)handler); ++ break; ++ } ++ ++ if (G_dma.chan[chan].irq[i].handler == handler) { ++ G_dma.chan[chan].irq[i].enabled = 1; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&dma_lock, flags); ++ ++gk_dma_enable_irq_na: ++ return retval; ++} ++EXPORT_SYMBOL(gk_dma_enable_irq); ++ ++int gk_dma_disable_irq(int chan, gk_dma_handler handler) ++{ ++ int retval = 0; ++ int i; ++ unsigned long flags; ++ ++ if (unlikely(chan < 0 || chan >= NUM_DMA_CHANNELS)) { ++ pr_err("%s: chan[%d] < NUM_DMA_CHANNELS[%d]!\n", ++ __func__, chan, NUM_DMA_CHANNELS); ++ retval = -EINVAL; ++ goto gk_dma_disable_irq_na; ++ } ++ ++ if (unlikely(handler == NULL)) { ++ pr_err("%s: handler is NULL!\n", __func__); ++ retval = -EINVAL; ++ goto gk_dma_disable_irq_na; ++ } ++ ++ spin_lock_irqsave(&dma_lock, flags); ++ for (i = 0; i < MAX_DMA_CHANNEL_IRQ_HANDLERS; i++) { ++ if (G_dma.chan[chan].irq[i].handler == NULL) { ++ retval = -EINVAL; ++ pr_err("%s: can't find 0x%x!\n", ++ __func__, (u32)handler); ++ break; ++ } ++ ++ if (G_dma.chan[chan].irq[i].handler == handler) { ++ G_dma.chan[chan].irq[i].enabled = 0; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&dma_lock, flags); ++ ++gk_dma_disable_irq_na: ++ return retval; ++} ++EXPORT_SYMBOL(gk_dma_disable_irq); ++ ++static inline int gk_req_dma(gk_dma_req_t * req, int chan) ++{ ++ int retval = 0; ++ u32 ctr = 0; ++ ++ if (unlikely(req->xfr_count > 0x003fffff)) { ++ pr_err("%s: xfr_count[0x%x] out of range!\n", ++ __func__, req->xfr_count); ++ retval = -EINVAL; ++ goto gk_req_dma_exit; ++ } ++ ++ gk_dma_writel(DMA_CHAN_STA_REG(chan), 0); ++ ++ if (req->next == NULL) { ++ gk_dma_writel(DMA_CHAN_SRC_REG(chan), req->src); ++ ++ gk_dma_writel(DMA_CHAN_DST_REG(chan), req->dst); ++ ++ ctr |= (req->attr | req->xfr_count); ++ ctr &= ~DMA_CHANX_CTR_D; ++ ctr |= DMA_CHANX_CTR_EN; ++ ++ } else {/* Descriptor mode */ ++ gk_dma_writel((u32) req, DMA_CHAN_DA_REG(chan)); ++ ++ ctr |= DMA_CHANX_CTR_D; ++ ctr |= DMA_CHANX_CTR_EN; ++ } ++ gk_dma_writel(DMA_CHAN_CTR_REG(chan), ctr); ++ ++gk_req_dma_exit: ++ return retval; ++} ++ ++int gk_dma_xfr(gk_dma_req_t *req, int chan) ++{ ++ int retval = 0; ++ ++ ++#ifdef CHECK_DMA_CHAN_USE_FLAG ++ unsigned long flags; ++#endif ++ ++ if (unlikely(chan < 0 || chan >= NUM_DMA_CHANNELS)) { ++ pr_err("%s: chan[%d] < NUM_DMA_CHANNELS[%d]!\n", ++ __func__, chan, NUM_DMA_CHANNELS); ++ retval = -EINVAL; ++ goto gk_dma_xfr_exit; ++ } ++ ++ if (unlikely(req == NULL)) { ++ pr_err("%s: req is NULL!\n", __func__); ++ retval = -EINVAL; ++ goto gk_dma_xfr_exit; ++ } ++ ++#ifdef CHECK_DMA_CHAN_USE_FLAG ++ spin_lock_irqsave(&dma_lock, flags); ++ G_dma.chan[chan].use_flag = 1; ++ spin_unlock_irqrestore(&dma_lock, flags); ++#endif ++ ++ retval = gk_req_dma(req, chan); ++ ++gk_dma_xfr_exit: ++ return retval; ++} ++EXPORT_SYMBOL(gk_dma_xfr); ++ ++int gk_dma_desc_xfr(dma_addr_t desc_addr, int chan) ++{ ++ ++ ++ if (unlikely(desc_addr == 0)) { ++ pr_err("%s: desc_addr is NULL!\n", __func__); ++ return -EINVAL; ++ } ++ ++ if (unlikely((desc_addr & 0x7) != 0)) { ++ pr_err("%s: desc_addr isn't aligned!\n", __func__); ++ return -EINVAL; ++ } ++ ++ if (unlikely(chan < 0 || chan >= NUM_DMA_CHANNELS)) { ++ pr_err("%s: chan[%d] < NUM_DMA_CHANNELS[%d]!\n", ++ __func__, chan, NUM_DMA_CHANNELS); ++ return -EINVAL; ++ } ++ ++ if (gk_dma_readl(DMA_CHAN_CTR_REG(chan)) & DMA_CHANX_CTR_EN) ++ pr_err("%s: dma (channel = %d) is still enabled!\n", __func__, chan); ++ ++ gk_dma_writel(DMA_CHAN_DA_REG(chan), desc_addr); ++ ++ gk_dma_writel(DMA_CHAN_CTR_REG(chan), DMA_CHANX_CTR_EN | DMA_CHANX_CTR_D); ++ ++ return 0; ++} ++EXPORT_SYMBOL(gk_dma_desc_xfr); ++ ++int gk_dma_desc_stop(int chan) ++{ ++ ++ ++ if (unlikely(chan < 0 || chan >= NUM_DMA_CHANNELS)) { ++ pr_err("%s: chan[%d] < NUM_DMA_CHANNELS[%d]!\n", ++ __func__, chan, NUM_DMA_CHANNELS); ++ return -EINVAL; ++ } ++ ++ /* Disable DMA: following sequence is not mentioned at APM.*/ ++ if (gk_dma_readl(DMA_CHAN_CTR_REG(chan)) & DMA_CHANX_CTR_EN) { ++ gk_dma_writel(DMA_CHAN_STA_REG(chan), DMA_CHANX_STA_DD); ++ ++ ++ gk_dma_writel(DMA_CHAN_DA_REG(chan), dummy_descriptor_phys); ++ ++ gk_dma_writel(DMA_CHAN_CTR_REG(chan), 0x28000000); ++ ++ ++ udelay(1); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(gk_dma_desc_stop); ++ ++int gk_dma_read_ctrl_reg(int chan) ++{ ++ return gk_dma_readl(DMA_CHAN_CTR_REG(chan));//add by DONALD, for audio drv use, mask different register addr macro value. ++} ++EXPORT_SYMBOL(gk_dma_read_ctrl_reg); ++ ++ ++int __init gk_init_dma(void) ++{ ++ int retval = 0; ++ int i; ++ struct dma_s *dma = &G_dma; ++ gk_dma_req_t *dma_desc_array; ++ ++ spin_lock_init(&dma_lock); ++ memset(&G_dma, 0x0, sizeof(G_dma)); ++ ++ dummy_descriptor = dma_alloc_coherent(NULL, ++ sizeof(gk_dma_req_t) * 4, ++ &dummy_descriptor_phys, GFP_KERNEL); ++ if (!dummy_descriptor) { ++ retval = -ENOMEM; ++ goto gk_init_dma_exit; ++ } ++ ++ dma_desc_array = (gk_dma_req_t *)dummy_descriptor; ++ dma_desc_array->attr = DMA_DESC_EOC | DMA_DESC_WM | DMA_DESC_NI | ++ DMA_DESC_IE | DMA_DESC_ST | DMA_DESC_ID; ++ dma_desc_array->src = 0; ++ dma_desc_array->next = (gk_dma_req_t *)dummy_descriptor_phys; ++ dma_desc_array->rpt = dummy_descriptor_phys + sizeof(gk_dma_req_t); ++ dma_desc_array->dst = dummy_descriptor_phys + sizeof(gk_dma_req_t) * 2; ++ dma_desc_array->xfr_count = 0; ++ ++ retval = request_irq(DMA_IRQ, gk_dma_int_handler, ++ IRQ_TYPE_LEVEL_HIGH, "gk-dma", dma); ++ if (retval) { ++ pr_err("%s: request_irq %d fail %d!\n", ++ __func__, DMA_IRQ, retval); ++ goto gk_init_dma_exit; ++ } ++ ++ for (i = 0; i < NUM_DMA_CHANNELS; i++) { ++ gk_dma_writel(DMA_CHAN_STA_REG(i), 0); ++ ++ gk_dma_writel(DMA_CHAN_CTR_REG(i), 0x38000000); ++ ++ } ++ ++#if (DMA_SUPPORT_DMA_FIOS == 1) ++ retval = request_irq(DMA_FIOS_IRQ, gk_dma_fios_int_handler, ++ IRQ_TYPE_LEVEL_HIGH, "gk-fios-dma", dma); ++ if (retval){ ++ pr_err("%s: request_irq %d fail %d!\n", ++ __func__, DMA_FIOS_IRQ, retval); ++ goto gk_init_dma_exit; ++ } ++ gk_dma_writel(DMA_FIOS_CHAN_STA_REG(0), 0); ++ ++ ++ gk_dma_writel(DMA_FIOS_CHAN_CTR_REG(0), 0x38000000); ++ ++#endif ++ ++#ifdef CONFIG_GK_DMA_PROC ++ dma_file = create_proc_entry(dma_proc_name, S_IRUGO | S_IWUSR, ++ get_gk_proc_dir()); ++ if (dma_file == NULL) { ++ retval = -ENOMEM; ++ pr_err("%s: for %s fail!\n", __func__, dma_proc_name); ++ } else { ++ dma_file->read_proc = gk_dma_proc_read; ++ dma_file->write_proc = NULL; ++ } ++#endif ++ ++gk_init_dma_exit: ++ return retval; ++} ++ +diff --git a/arch/arm/mach-gk710x/gk710x.c b/arch/arm/mach-gk710x/gk710x.c +new file mode 100644 +index 00000000..41de4f51 +--- /dev/null ++++ b/arch/arm/mach-gk710x/gk710x.c +@@ -0,0 +1,774 @@ ++/* ++ * linux/arch/arm/mach-gk/gk.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * 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. ++ * ++ */ ++ ++//#define KE_DEBUG ++ ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++extern u8* load_data_init(void); ++ ++ ++struct gk_mem_map_desc ++{ ++ char name[32]; ++ struct map_desc io_desc; ++}; ++ ++/* the module name MUST match hardware.h */ ++#define IOMAP_DESC_ENTRY(module, len) { \ ++ .virtual = GK_VA_##module, \ ++ .pfn = __phys_to_pfn(GK_PA_##module), \ ++ .length = (len), \ ++ .type = MT_DEVICE \ ++} ++ ++#define GK_IOMAP(module_name, module, len) { \ ++ .name = module_name, \ ++ IOMAP_DESC_ENTRY(module, len), \ ++} ++ ++ ++#define GK_IO_DESC_AHB_ID 0 ++#define GK_IO_DESC_APB_ID 1 ++#define GK_IO_DESC_PPM_ID 2 ++#define GK_IO_DESC_BSB_ID 3 ++#define GK_IO_DESC_DSP_ID 4 ++#define GK_IO_DESC_USR_ID 5 ++ ++static struct gk_mem_map_desc gk_mem_desc[] = ++{ ++ // reserved 0xF0000000 to hal1, and 0xF1000000 to hal2 ++ // used in get_hal1_virt & get_hal2_virt; ++ [GK_IO_DESC_AHB_ID] = ++ {/*0*/ ++ .name = "AHB", ++ .io_desc = ++ { ++ .virtual= GK_VA_AHB_BASE, ++ .pfn = __phys_to_pfn(GK_PA_AHB_BASE), ++ .length = 0x01000000, ++ .type = MT_DEVICE, ++ }, ++ }, ++ [GK_IO_DESC_APB_ID] = ++ {/*1*/ ++ .name = "APB", ++ .io_desc = ++ { ++ .virtual= GK_VA_APB_BASE, ++ .pfn = __phys_to_pfn(GK_PA_APB_BASE), ++ .length = 0x01000000, ++ .type = MT_DEVICE, ++ }, ++ }, ++ [GK_IO_DESC_PPM_ID] = ++ {/*2*/ ++ .name = "PPM", /*Private Physical Memory*/ ++ .io_desc = ++ { ++ .virtual= 0xc0000000, ++ .pfn = __phys_to_pfn(0xc0000000/*DEFAULT_MEM_START*/), ++ .length = CONFIG_PHYS_OFFSET-0xc0000000, ++ .type = MT_MEMORY, ++ }, ++ }, ++ [GK_IO_DESC_BSB_ID] = ++ {/*3*/ ++ .name = "BSB", ++ .io_desc = ++ { ++ .virtual= 0xf5000000, ++ .pfn = __phys_to_pfn(0xc2800000), ++ .length = 0x00200000, ++ .type = MT_MEMORY, ++ }, ++ }, ++ [GK_IO_DESC_DSP_ID] = ++ {/*4*/ ++ .name = "DSP", ++ .io_desc = ++ { ++ .virtual= 0xf6000000, ++ .pfn = __phys_to_pfn(0xC2a00000), ++ .length = 0x01500000, ++ .type = MT_MEMORY, ++ }, ++ }, ++ [GK_IO_DESC_USR_ID] = ++ {/*5*/ ++ .name = "USR", ++ .io_desc = ++ { ++ .virtual= 0xfe000000, // dsp_size <= 0xfe000000-0xf6000000 ++ .pfn = __phys_to_pfn(0xC3FF0000), ++ .length = 0x00010000, ++ .type = MT_MEMORY, ++ }, ++ }, ++}; ++ ++ ++ ++#if 1 ++//-----------HAL1------------- ++u32 get_hal1_virt(void) ++{ ++ return 0xF0000000; ++} ++EXPORT_SYMBOL(get_hal1_virt); ++ ++//-----------HAL2------------- ++u32 get_hal2_virt(void) ++{ ++ return 0xF1000000; ++} ++EXPORT_SYMBOL(get_hal2_virt); ++ ++//-----------AHB------------- ++u32 get_ahb_phys(void) ++{ ++ return __pfn_to_phys(gk_mem_desc[GK_IO_DESC_AHB_ID].io_desc.pfn); ++} ++EXPORT_SYMBOL(get_ahb_phys); ++ ++u32 get_ahb_virt(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_AHB_ID].io_desc.virtual; ++} ++EXPORT_SYMBOL(get_ahb_virt); ++ ++u32 get_ahb_size(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_AHB_ID].io_desc.length; ++} ++EXPORT_SYMBOL(get_ahb_size); ++ ++//-----------APB------------- ++u32 get_apb_phys(void) ++{ ++ return __pfn_to_phys(gk_mem_desc[GK_IO_DESC_APB_ID].io_desc.pfn); ++} ++EXPORT_SYMBOL(get_apb_phys); ++ ++u32 get_apb_virt(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_APB_ID].io_desc.virtual; ++} ++EXPORT_SYMBOL(get_apb_virt); ++ ++u32 get_apb_size(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_APB_ID].io_desc.length; ++} ++EXPORT_SYMBOL(get_apb_size); ++ ++//-----------PPM------------- ++u32 get_ppm_phys(void) ++{ ++ return __pfn_to_phys(gk_mem_desc[GK_IO_DESC_PPM_ID].io_desc.pfn); ++} ++EXPORT_SYMBOL(get_ppm_phys); ++ ++u32 get_ppm_virt(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_PPM_ID].io_desc.virtual; ++} ++EXPORT_SYMBOL(get_ppm_virt); ++ ++u32 get_ppm_size(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_PPM_ID].io_desc.length; ++} ++EXPORT_SYMBOL(get_ppm_size); ++ ++//-----------DSP------------- ++u32 get_dspmem_virt(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_DSP_ID].io_desc.virtual; ++} ++EXPORT_SYMBOL(get_dspmem_virt); ++ ++u32 get_dspmem_size(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_DSP_ID].io_desc.length; ++} ++EXPORT_SYMBOL(get_dspmem_size); ++ ++u32 get_dspmem_phys(void) ++{ ++ return __pfn_to_phys(gk_mem_desc[GK_IO_DESC_DSP_ID].io_desc.pfn); ++} ++EXPORT_SYMBOL(get_dspmem_phys); ++ ++//-----------BSB------------- ++u32 get_bsbmem_phys(void) ++{ ++ return __pfn_to_phys(gk_mem_desc[GK_IO_DESC_BSB_ID].io_desc.pfn); ++} ++EXPORT_SYMBOL(get_bsbmem_phys); ++ ++u32 get_bsbmem_virt(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_BSB_ID].io_desc.virtual; ++} ++EXPORT_SYMBOL(get_bsbmem_virt); ++ ++u32 get_bsbmem_size(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_BSB_ID].io_desc.length; ++} ++EXPORT_SYMBOL(get_bsbmem_size); ++u32 get_usrmem_phys(void) ++{ ++ return __pfn_to_phys(gk_mem_desc[GK_IO_DESC_USR_ID].io_desc.pfn); ++} ++EXPORT_SYMBOL(get_usrmem_phys); ++u32 get_usrmem_virt(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_USR_ID].io_desc.virtual; ++} ++EXPORT_SYMBOL(get_usrmem_virt); ++u32 get_usrmem_size(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_USR_ID].io_desc.length; ++} ++EXPORT_SYMBOL(get_usrmem_size); ++ ++ ++ ++u32 gk_phys_to_virt(u32 paddr) ++{ ++ int i; ++ u32 phystart; ++ u32 phylength; ++ u32 phyoffset; ++ u32 vstart; ++ ++ for (i = 0; i < ARRAY_SIZE(gk_mem_desc); i++) ++ { ++ phystart = __pfn_to_phys(gk_mem_desc[i].io_desc.pfn); ++ phylength = gk_mem_desc[i].io_desc.length; ++ vstart = gk_mem_desc[i].io_desc.virtual; ++ if ((paddr >= phystart) && (paddr < (phystart + phylength))) ++ { ++ phyoffset = paddr - phystart; ++ return (vstart + phyoffset); ++ } ++ } ++ ++ return __phys_to_virt(paddr); ++} ++EXPORT_SYMBOL(gk_phys_to_virt); ++ ++u32 gk_virt_to_phys(u32 vaddr) ++{ ++ int i; ++ u32 phystart; ++ u32 vlength; ++ u32 voffset; ++ u32 vstart; ++ ++ for (i = 0; i < ARRAY_SIZE(gk_mem_desc); i++) ++ { ++ phystart = __pfn_to_phys(gk_mem_desc[i].io_desc.pfn); ++ vlength = gk_mem_desc[i].io_desc.length; ++ vstart = gk_mem_desc[i].io_desc.virtual; ++ if ((vaddr >= vstart) && (vaddr < (vstart + vlength))) ++ { ++ voffset = vaddr - vstart; ++ return (phystart + voffset); ++ } ++ } ++ ++ return __virt_to_phys(vaddr); ++} ++EXPORT_SYMBOL(gk_virt_to_phys); ++#endif ++ ++void get_stepping_info(int *chip, int *major, int *minor) ++{ ++ *chip = 0x5; ++ *major = 0x1; ++ *minor = 0x0; ++} ++EXPORT_SYMBOL(get_stepping_info); ++ ++/* ==========================================================================*/ ++u64 gk_dmamask = DMA_BIT_MASK(32); ++EXPORT_SYMBOL(gk_dmamask); ++ ++ ++/* ==========================================================================*/ ++static struct proc_dir_entry *gk_proc_dir = NULL; ++ ++int __init gk_create_proc_dir(void) ++{ ++ int retval = 0; ++ ++ printk("create proc dir\n"); ++ ++ gk_proc_dir = proc_mkdir("goke", NULL); ++ if (!gk_proc_dir) ++ retval = -ENOMEM; ++ ++ return retval; ++} ++ ++struct proc_dir_entry *get_gk_proc_dir(void) ++{ ++ return gk_proc_dir; ++} ++EXPORT_SYMBOL(get_gk_proc_dir); ++ ++/* ==========================================================================*/ ++typedef void* (*hal_function_t) (unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) ; ++ ++struct hw_ops *g_hw; ++EXPORT_SYMBOL(g_hw); ++ ++ ++#if HW_HAL_MODE ++HAL_IO(hw) ++#else ++DIR_IO(hw) ++#endif ++ ++#if ADC_HAL_MODE ++HAL_IO(adc) ++#else ++DIR_IO(adc) ++#endif ++#if AUD_HAL_MODE ++HAL_IO(aud) ++#else ++DIR_IO(aud) ++#endif ++#if CRY_HAL_MODE ++HAL_IO(cry) ++#else ++DIR_IO(cry) ++#endif ++#if DDR_HAL_MODE ++HAL_IO(ddr) ++#else ++DIR_IO(ddr) ++#endif ++#if DSP_HAL_MODE ++HAL_IO(dsp) ++#else ++DIR_IO(dsp) ++#endif ++#if ETH_HAL_MODE ++HAL_IO(eth) ++#else ++DIR_IO(eth) ++#endif ++#if GREG_HAL_MODE ++HAL_IO(greg) ++#else ++DIR_IO(greg) ++#endif ++#if GPIO_HAL_MODE ++HAL_IO(gpio) ++#else ++DIR_IO(gpio) ++#endif ++#if I2C_HAL_MODE ++HAL_IO(i2c) ++#else ++DIR_IO(i2c) ++#endif ++#if I2S_HAL_MODE ++HAL_IO(i2s) ++#else ++DIR_IO(i2s) ++#endif ++#if IR_HAL_MODE ++HAL_IO(ir) ++#else ++DIR_IO(ir) ++#endif ++#if IRQ_HAL_MODE ++HAL_IO(irq) ++#else ++DIR_IO(irq) ++#endif ++#if MCU_HAL_MODE ++HAL_IO(mcu) ++#else ++DIR_IO(mcu) ++#endif ++#if PWM_HAL_MODE ++HAL_IO(pwm) ++#else ++DIR_IO(pwm) ++#endif ++#if RCT_HAL_MODE ++HAL_IO(rct) ++#else ++DIR_IO(rct) ++#endif ++#if SD_HAL_MODE ++HAL_IO(sd) ++#else ++DIR_IO(sd) ++#endif ++#if SF_HAL_MODE ++HAL_IO(sf) ++#else ++DIR_IO(sf) ++#endif ++#if SSI_HAL_MODE ++HAL_IO(ssi) ++#else ++DIR_IO(ssi) ++#endif ++#if TIMER_HAL_MODE ++HAL_IO(timer) ++#else ++DIR_IO(timer) ++#endif ++#if UART_HAL_MODE ++HAL_IO(uart) ++#else ++DIR_IO(uart) ++#endif ++#if USB_HAL_MODE ++HAL_IO(usb) ++#else ++DIR_IO(usb) ++#endif ++#if VOUT_HAL_MODE ++HAL_IO(vout) ++#else ++DIR_IO(vout) ++#endif ++#if WDT_HAL_MODE ++HAL_IO(wdt) ++#else ++DIR_IO(wdt) ++#endif ++#if EFUSE_HAL_MODE ++HAL_IO(efuse) ++#else ++DIR_IO(efuse) ++#endif ++#if USB_DMA_ADD_MODE ++unsigned int gk_dma_readl(unsigned int ptr) ++{ ++ return g_hw->dma_readl(ptr); ++} ++EXPORT_SYMBOL(gk_dma_readl); ++void gk_dma_writel(unsigned int ptr, unsigned int value) ++{ ++ g_hw->dma_writel(ptr,value); ++} ++EXPORT_SYMBOL(gk_dma_writel); ++#else ++DIR_IO(dma) ++#endif ++#if USB_DMA_ADD_MODE ++unsigned char (*gk_usb_readb)(unsigned int ptr, unsigned int offset); ++unsigned short (*gk_usb_readw)(unsigned int ptr, unsigned int offset); ++unsigned int (*gk_usb_readl)(unsigned int ptr, unsigned int offset); ++void (*gk_usb_writeb)(unsigned int ptr, unsigned int offset, unsigned char value); ++void (*gk_usb_writew)(unsigned int ptr, unsigned int offset, unsigned short value); ++void (*gk_usb_writel)(unsigned int ptr, unsigned int offset, unsigned int value); ++ ++#endif ++#if SPI_API_MODE ++unsigned char (*gk_spi_readb)(unsigned int ptr); ++unsigned short (*gk_spi_readw)(unsigned int ptr); ++unsigned int (*gk_spi_readl)(unsigned int ptr); ++void (*gk_spi_writeb)(unsigned int ptr, unsigned char value); ++void (*gk_spi_writew)(unsigned int ptr, unsigned short value); ++void (*gk_spi_writel)(unsigned int ptr, unsigned int value); ++#endif ++ ++static inline unsigned int gk_hal_init (void *hal_base_address, unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4) ++{ ++ unsigned int rval=0; ++ hal_function_t hal_init = (hal_function_t) (hal_base_address) ; ++ ++ g_hw = (struct hw_ops *)hal_init (arg0, arg1, arg2, arg3, arg4) ; ++ printk("hal version = %x \n", (u32)g_hw->get_version()); ++ ++#if USB_DMA_ADD_MODE ++ if((u32)g_hw->get_version() < 0x20151223) ++ { ++ printk("Error: hal version must up to 0x20151223!!!\n"); ++ } ++ gk_usb_readb = g_hw->usb_readb; ++ gk_usb_readw = g_hw->usb_readw; ++ gk_usb_readl = g_hw->usb_readl; ++ gk_usb_writeb = g_hw->usb_writeb; ++ gk_usb_writew = g_hw->usb_writew; ++ gk_usb_writel = g_hw->usb_writel; ++ ++#endif ++#if SPI_API_MODE ++ if((u32)g_hw->get_version() < 0x20160324) ++ { ++ printk("Error: hal version must up to 0x20160324!!!\n"); ++ } ++ gk_spi_readb = g_hw->spi_readb; ++ gk_spi_readw = g_hw->spi_readw; ++ gk_spi_readl = g_hw->spi_readl; ++ gk_spi_writeb = g_hw->spi_writeb; ++ gk_spi_writew = g_hw->spi_writew; ++ gk_spi_writel = g_hw->spi_writel; ++#endif ++ return rval ; ++} ++ ++ ++static int __init early_boot_splash_logo(char *p) ++{ ++ printk("set boot splash logo = 1 \n"); ++ gk_boot_splash_logo = 1; ++ return 0; ++} ++early_param("boot_splash_logo_on", early_boot_splash_logo); ++ ++void __init gk_map_io(void) ++{ ++ int i; ++ u32 iop, ios, iov, hal_add; ++ u32 usr_phy_addr; ++ u32 bsb_phy_addr; ++ u32 bsb_size; ++ u32 dsp_phy_addr; ++ u32 dsp_size; ++ u32 soc_type; //0:, 1:7102 ++ u32 mem_size; ++ u32 mem_total; ++ u32 usr_size; //user used, cmem module ++ struct memblock_region *reg; ++ unsigned long kernelMemoryGet=0; ++ ++ /*************************/ ++ /* AHB */ ++ /*-----------------------*/ ++ /* APB */ ++ /*-----------------------*/ ++ /* PPM <3M> */ ++ /*-----------------------*/ ++ /* KER */ ++ /*-----------------------*/ ++ /* BSB <2M/4M> */ ++ /*-----------------------*/ ++ /* DSP */ ++ /*-----------------------*/ ++ /* USR <64K> */ ++ /*************************/ ++ ++ for (i = 0; i < GK_IO_DESC_BSB_ID; i++) ++ { ++ iop = __pfn_to_phys(gk_mem_desc[i].io_desc.pfn); ++ ios = gk_mem_desc[i].io_desc.length; ++ iov = gk_mem_desc[i].io_desc.virtual; ++ printk("%s: 0x%x 0x%x -- 0x%x\n", gk_mem_desc[i].name, iop, iov, ios); ++ if (ios > 0) ++ { ++ iotable_init(&(gk_mem_desc[i].io_desc), 1); ++ } ++ } ++ ++ /* calc mem_size by uboot params parsing*/ ++ for_each_memblock(memory, reg) ++ { ++ unsigned long pages = memblock_region_memory_end_pfn(reg) - ++ memblock_region_memory_base_pfn(reg); ++ kernelMemoryGet = pages >> (20 - PAGE_SHIFT); ++ } ++ mem_size = kernelMemoryGet*1024*1024; ++ ++#if 0 ++ soc_type = *(volatile u32 *)CONFIG_U2K_SOC_ADDR; ++ ++ /* if can't get correct value from uboot env, use GK7102 for default*/ ++ if(soc_type>1) ++ soc_type = 1; ++ ++ ++ ++ mem_total = *(volatile u32 *)CONFIG_U2K_TOTAL_MEM; ++ if(mem_total != 64 && mem_total != 128) ++ { ++ /* set mem_total and bsb size by chip ID*/ ++ switch(soc_type) ++ { ++ case CONFIG_SOC_GK7102: /*GK7102*/ ++ mem_total = 64*1024*1024; ++ //bsb_size = 0x200000; /*use 2M for GK7102*/ ++ break; ++ case CONFIG_SOC_GK7101: /*GK*/ ++ default: ++ mem_total = 128*1024*1024; ++ //bsb_size = 0x400000; /*use 4M for GK*/ ++ break; ++ } ++ } ++ else mem_total = mem_total*1024*1024; ++#else ++ mem_total = (*(volatile u32 *)CONFIG_U2K_TOTAL_MEM)*1024*1024; ++#endif ++ ++ bsb_size = *(volatile u32 *)CONFIG_U2K_BSB_ADDR; ++ usr_size = 0x10000; ++ usr_phy_addr = 0xC0000000 + mem_total - usr_size; ++ bsb_phy_addr = 0xC0000000 + get_ppm_size() + mem_size; ++ dsp_phy_addr = bsb_phy_addr + bsb_size; ++ dsp_size = mem_total - get_ppm_size() - mem_size - bsb_size - usr_size; ++ ++ gk_mem_desc[GK_IO_DESC_BSB_ID].io_desc.pfn = __phys_to_pfn(bsb_phy_addr); ++ gk_mem_desc[GK_IO_DESC_BSB_ID].io_desc.length = bsb_size; ++ ++ gk_mem_desc[GK_IO_DESC_DSP_ID].io_desc.pfn = __phys_to_pfn(dsp_phy_addr); ++ gk_mem_desc[GK_IO_DESC_DSP_ID].io_desc.length = dsp_size; ++ ++ gk_mem_desc[GK_IO_DESC_USR_ID].io_desc.pfn = __phys_to_pfn(usr_phy_addr); ++ gk_mem_desc[GK_IO_DESC_USR_ID].io_desc.length = usr_size; ++ ++ for (i = GK_IO_DESC_BSB_ID; i < ARRAY_SIZE(gk_mem_desc); i++) ++ { ++ iop = __pfn_to_phys(gk_mem_desc[i].io_desc.pfn); ++ ios = gk_mem_desc[i].io_desc.length; ++ iov = gk_mem_desc[i].io_desc.virtual; ++ printk("%s: 0x%x 0x%x -- 0x%x\n", gk_mem_desc[i].name, iop, iov, ios); ++ if (ios > 0) ++ { ++ iotable_init(&(gk_mem_desc[i].io_desc), 1); ++ } ++ } ++ ++ hal_add = *(volatile u32 *)CONFIG_U2K_HAL_ADDR; ++ gk_hal_init((void*)(gk_phys_to_virt(hal_add)), get_hal1_virt(), get_hal2_virt(), get_ahb_virt(), get_apb_virt(), (u32)iotable_init); ++} ++ ++void gk_load_51mcu_code(u32 code) ++{ ++ int i; ++ u8 *pData = NULL; ++ ++ pData = load_data_init(); ++ ++ /* Software Reset */ ++ gk_mcu_setbitsl( MCU_SYS_BASE + 0x0000, 1 << 5); ++ ++ /* Enable the download command */ ++ gk_mcu_setbitsl( MCU_SYS_BASE + 0x002C, 1 << 4); ++ ++ /* Disable the MCU51 core clock */ ++ gk_mcu_clrbitsl( MCU_SYS_BASE + 0x002C, 1 << 1); ++ ++ /* Download MCU code to boot ram */ ++ for(i=0;i<4096;i++) ++ { ++ gk_mcu_writel((GK_VA_PMU_C51_CODE + (i*4)), pData[i]); ++ } ++ gk_mcu_writel(MCU_SYS_BASE + 0x005C, code); ++ gk_mcu_writel(MCU_SYS_BASE + 0x002C, 0xB2);// 1011 0010 ++ gk_mcu_writel(MCU_SYS_BASE + 0x002C, 0x63);// 0110 0011 ++} ++ ++void gk_power_off(void) ++{ ++ ++ u32 code = PMU_POWER_OFF_CPU; ++ /* Disable interrupts first */ ++ local_irq_disable(); ++ local_fiq_disable(); ++ printk("gk power off...\n"); ++ ++#ifdef CONFIG_PMU_AUTOMOTIVE ++ code = PMU_AUTOMOTIVE_KEY; ++#endif ++#ifdef CONFIG_PMU_POWER_OFF_CPU ++ code = PMU_POWER_OFF_CPU; ++#endif ++#ifdef CONFIG_PMU_ALWAYS_RUNNING ++ // get pmu controller ++ gk_gpio_config(gk_all_gpio_cfg.pmu_ctl, GPIO_TYPE_OUTPUT_1); ++ msleep(1); ++ gk_gpio_config(gk_all_gpio_cfg.pmu_ctl, GPIO_TYPE_OUTPUT_0); ++ msleep(1); ++ code = PMU_ALWAYS_RUNNING_POWEROFF; ++#endif ++ gk_load_51mcu_code(code); ++ ++ //printk("c51 start ... ...\n"); ++ while(1){;} ++} ++ ++ ++//reboot, user watch dog ++void gk_restart(char mode, const char *cmd) ++{ ++ printk("gk reboot...\n"); ++ ++ gk_wdt_writel( WDOG_RELOAD_REG, 0xff); ++ gk_wdt_writel( WDOG_RESTART_REG, 0x4755); ++ gk_wdt_writel( WDOG_CONTROL_REG, WDOG_CTR_RST_EN | WDOG_CTR_EN); ++ mdelay(1000); ++ printk("watchdog reset failed...\n"); ++} ++ ++ ++/* ==========================================================================*/ ++DEFINE_SPINLOCK(gk_reg_lock); ++unsigned long gk_reg_flags; ++u32 gk_reglock_count = 0; ++ ++/* ==========================================================================*/ ++EXPORT_SYMBOL(gk_reg_lock); ++EXPORT_SYMBOL(gk_reg_flags); ++EXPORT_SYMBOL(gk_reglock_count); ++module_param (gk_reglock_count, uint, S_IRUGO); ++ ++ +diff --git a/arch/arm/mach-gk710x/include/hal/hal.h b/arch/arm/mach-gk710x/include/hal/hal.h +new file mode 100644 +index 00000000..054e318c +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/hal/hal.h +@@ -0,0 +1,22 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/hal/hal.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __HAL_HAL_H ++#define __HAL_HAL_H ++ ++#endif ++ +diff --git a/arch/arm/mach-gk710x/include/hal/header.h b/arch/arm/mach-gk710x/include/hal/header.h +new file mode 100644 +index 00000000..259c551b +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/hal/header.h +@@ -0,0 +1,20 @@ ++#ifndef _HEADER_H_INCLUDED_ ++#define _HEADER_H_INCLUDED_ ++ ++typedef struct gk_hal_header_s { ++ char magic[16] ; ++ unsigned int major_version ; ++ unsigned int minor_version ; ++ unsigned char chip_name[8] ; ++ unsigned char chip_stepping[8] ; ++ unsigned char build_id[32] ; ++ unsigned char build_date[32] ; ++} gk_hal_header_t; ++ ++typedef struct gk_hal_function_info_s { ++ unsigned int (*function)(unsigned int, unsigned int, ++ unsigned int, unsigned int) ; ++ const char* name ; ++} gk_hal_function_info_t ; ++ ++#endif // ifndef _HEADER_H_INCLUDED_ +diff --git a/arch/arm/mach-gk710x/include/mach/audio_codec.h b/arch/arm/mach-gk710x/include/mach/audio_codec.h +new file mode 100644 +index 00000000..53e527ba +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/audio_codec.h +@@ -0,0 +1,115 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk/include/hal/audio_codec.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++#ifndef __HAL_AUDIO_CODEC_H__ ++#define __HAL_AUDIO_CODEC_H__ ++ ++#include ++ ++#define AUDIO_DMA_REG_OFFSET (0x30000000) ++ ++/*AHB genneral */ ++#define AHB_GREG_BASE (GK_VA_AHB_GREG) ++#define AHB_GREG_BASE_PHYS (GK_PA_AHB_GREG) ++#define AHB_GREG_REG(x) (AHB_GREG_BASE + (x)) ++#define AHB_GREG_REG_PHYS(x) (AHB_GREG_BASE_PHYS + (x)) ++ ++#define AHB_GREG_BASE_extern AHB_GREG_BASE ++ ++/*digital model*/ ++#define AUDIO_CODEC_DIGITAL_BASE (GK_VA_AUDIO_CODEC_DIGITAL) ++#define AUDIO_CODEC_DIGITAL_BASE_PHYS (GK_PA_AUDIO_CODEC_DIGITAL) ++#define AUDIO_CODEC_DIGITAL_REG(x) (AUDIO_CODEC_DIGITAL_BASE + (x)) ++#define AUDIO_CODEC_DIGITAL_REG_PHYS(x) (AUDIO_CODEC_DIGITAL_BASE_PHYS + (x)) ++ ++#define AUDIO_CODEC_DIGITAL_BASE_extern AUDIO_CODEC_DIGITAL_BASE ++ ++/*analog model*/ ++#define AUDIO_CODEC_ANALOG_BASE (GK_VA_AUDIO_CODEC_ANALOG) ++#define AUDIO_CODEC_ANALOG_BASE_PHYS (GK_PA_AUDIO_CODEC_ANALOG) ++#define AUDIO_CODEC_ANALOG_REG(x) (AUDIO_CODEC_ANALOG_BASE + (x)) ++#define AUDIO_CODEC_ANALOG_REG_PHYS(x) (AUDIO_CODEC_ANALOG_BASE_PHYS + (x)) ++ ++#define AUDIO_CODEC_ANALOG_BASE_extern AUDIO_CODEC_ANALOG_BASE ++ ++/*AHB genneral reg*/ ++#define AHB_GENNERNAL0_REG AHB_GREG_REG(0x00) ++#define AHB_GENNERNAL1_REG AHB_GREG_REG(0x04) ++ ++/*digital model reg */ ++#define AUDC_DIGITAL_SYS_RST_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x00) ++#define AUDC_DIGITAL_CKG_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x04) ++#define AUDC_DIGITAL_AUDIOBAND_CTRL2_REG AUDIO_CODEC_DIGITAL_REG(0x18) ++#define AUDC_DIGITAL_TIMING_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x08) ++#define AUDC_DIGITAL_AUDIOBAND_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x10) ++#define AUDC_DIGITAL_AUDIOBAND_STS_REG AUDIO_CODEC_DIGITAL_REG(0x1c) ++#define AUDC_DIGITAL_SDM_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x34) ++#define AUDC_DIGITAL_SDM_CTRL1_REG AUDIO_CODEC_DIGITAL_REG(0x38) ++#define AUDC_DIGITAL_NF_SYNTH_1_NF_H_REG AUDIO_CODEC_DIGITAL_REG(0x3c) ++#define AUDC_DIGITAL_NF_SYNTH_1_NF_L_REG AUDIO_CODEC_DIGITAL_REG(0x40) ++#define AUDC_DIGITAL_NF_SYNTH_2_NF_H_REG AUDIO_CODEC_DIGITAL_REG(0x44) ++#define AUDC_DIGITAL_NF_SYNTH_2_NF_L_REG AUDIO_CODEC_DIGITAL_REG(0x48) ++#define AUDC_DIGITAL_DIG_MIC_CTRL_REG AUDIO_CODEC_DIGITAL_REG(0x4c) ++#define AUDC_DIGITAL_AUDIOBAND_STS2_REG AUDIO_CODEC_DIGITAL_REG(0x20) ++#define AUDC_DIGITAL_SDM_DWA_DATAIN_L_REG AUDIO_CODEC_DIGITAL_REG(0x54) ++#define AUDC_DIGITAL_SDM_DWA_DATAIN_R_REG AUDIO_CODEC_DIGITAL_REG(0x58) ++#define AUDC_DIGITAL_VALID_SIGNALS_REG AUDIO_CODEC_DIGITAL_REG(0x5c) ++#define AUDC_DIGITAL_PGA1_DPGA_CFG1_REG AUDIO_CODEC_DIGITAL_REG(0x68) ++#define AUDC_DIGITAL_MMP1_DPGA_CFG1_REG AUDIO_CODEC_DIGITAL_REG(0x60) ++#define AUDC_DIGITAL_MMP1_DPGA_CFG2_REG AUDIO_CODEC_DIGITAL_REG(0x64) ++#define AUDC_DIGITAL_MIX_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x50) ++ ++#define AUDC_DIGITAL_MMP2_DPGA_CFG1_REG AUDIO_CODEC_DIGITAL_REG(0x6c) ++#define AUDC_DIGITAL_MMP2_DPGA_CFG2_REG AUDIO_CODEC_DIGITAL_REG(0x70) ++#define AUDC_DIGITAL_INT1_DOUT_REG AUDIO_CODEC_DIGITAL_REG(0x74) ++#define AUDC_DIGITAL_FIFO_TH_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x7c) ++#define AUDC_DIGITAL_INT2_DOUT_REG AUDIO_CODEC_DIGITAL_REG(0x78) ++ ++#define AUDC_DIGITAL_TIMING_CTRL1_REG AUDIO_CODEC_DIGITAL_REG(0x0c) ++#define AUDC_DIGITAL_AUDIOBAND_CTRL1_REG AUDIO_CODEC_DIGITAL_REG(0x14) ++#define AUDC_DIGITAL_FIFO_CTRL_REG AUDIO_CODEC_DIGITAL_REG(0x80) ++#define AUDC_DIGITAL_FIFO_STS_REG AUDIO_CODEC_DIGITAL_REG(0x84) ++#define AUDC_DIGITAL_NF_SYNTH_5_NF_H_REG AUDIO_CODEC_DIGITAL_REG(0x88) ++#define AUDC_DIGITAL_NF_SYNTH_5_NF_L_REG AUDIO_CODEC_DIGITAL_REG(0x8c) ++#define AUDC_DIGITAL_INT_CTRL_REG AUDIO_CODEC_DIGITAL_REG(0x90) ++ ++#define AUDC_DIGITAL_SINE_GEN_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x24) ++#define AUDC_DIGITAL_SINE_GEN_CTRL1_REG AUDIO_CODEC_DIGITAL_REG(0x28) ++#define AUDC_DIGITAL_TEST_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x30) ++ ++/*analog model reg */ ++#define AUDC_ANALOG_CTRL00_REG AUDIO_CODEC_ANALOG_REG(0x00) ++#define AUDC_ANALOG_CTRL01_REG AUDIO_CODEC_ANALOG_REG(0x04) ++#define AUDC_ANALOG_CTRL02_REG AUDIO_CODEC_ANALOG_REG(0x08) ++#define AUDC_ANALOG_CTRL03_REG AUDIO_CODEC_ANALOG_REG(0x0c) ++#define AUDC_ANALOG_CTRL04_REG AUDIO_CODEC_ANALOG_REG(0x10) ++#define AUDC_ANALOG_CTRL05_REG AUDIO_CODEC_ANALOG_REG(0x14) ++#define AUDC_ANALOG_CTRL06_REG AUDIO_CODEC_ANALOG_REG(0x18) ++#define AUDC_ANALOG_CTRL07_REG AUDIO_CODEC_ANALOG_REG(0x1c) ++#define AUDC_ANALOG_CTRL08_REG AUDIO_CODEC_ANALOG_REG(0x20) ++#define AUDC_ANALOG_CTRL09_REG AUDIO_CODEC_ANALOG_REG(0x24) ++#define AUDC_ANALOG_CTRL10_REG AUDIO_CODEC_ANALOG_REG(0x28) ++#define AUDC_ANALOG_CTRL11_REG AUDIO_CODEC_ANALOG_REG(0x2c) ++#define AUDC_ANALOG_CTRL12_REG AUDIO_CODEC_ANALOG_REG(0x30) ++#define AUDC_ANALOG_CTRL13_REG AUDIO_CODEC_ANALOG_REG(0x34) ++#define AUDC_ANALOG_CTRL14_REG AUDIO_CODEC_ANALOG_REG(0x38) ++#define AUDC_ANALOG_CTRL15_REG AUDIO_CODEC_ANALOG_REG(0x3c) ++#define AUDC_ANALOG_CTRL16_REG AUDIO_CODEC_ANALOG_REG(0x40) ++#define AUDC_ANALOG_CTRL17_REG AUDIO_CODEC_ANALOG_REG(0x44) ++#define AUDC_ANALOG_CTRL18_REG AUDIO_CODEC_ANALOG_REG(0x48) ++ ++extern unsigned int gk_aud_get_dma_offset(void); ++#endif /* __HAL_AUDIO_CODEC_H__ */ +diff --git a/arch/arm/mach-gk710x/include/mach/crypto.h b/arch/arm/mach-gk710x/include/mach/crypto.h +new file mode 100644 +index 00000000..1b58d898 +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/crypto.h +@@ -0,0 +1,48 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk/include/hal/i2s.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __HAL_CRYPTO_H__ ++#define __HAL_CRYPTO_H__ ++ ++#include ++ ++#define CRYPTO_VA_BASE GK_VA_CRYPT_UNIT ++#define CRYPTO_VA_REG(x) (CRYPTO_VA_BASE + (x)) ++#define REG_CRYPTO_DES_KEY CRYPTO_VA_REG(0x00c) /* read/write */ ++#define REG_CRYPTO_DES_INPUT CRYPTO_VA_REG(0x014) /* read/write */ ++#define REG_CRYPTO_DES_OPCODE CRYPTO_VA_REG(0x004) /* read/write */ ++#define REG_CRYPTO_DES_OUTPUT_RDY CRYPTO_VA_REG(0x018) /* read */ ++#define REG_CRYPTO_DES_OUTPUT CRYPTO_VA_REG(0x020) /* read */ ++#define REG_CRYPTO_DES_INTERRUPT CRYPTO_VA_REG(0x000) /* read/write */ ++ ++#define REG_CRYPTO_AES_128_KEY CRYPTO_VA_REG(0x074) /* read/write */ ++ ++#define REG_CRYPTO_AES_192_KEY CRYPTO_VA_REG(0x064) /* read/write */ ++ ++#define REG_CRYPTO_AES_256_KEY CRYPTO_VA_REG(0x04c) /* read/write */ ++ ++#define REG_CRYPTO_AES_INPUT CRYPTO_VA_REG(0x084) /* read/write */ ++#define REG_CRYPTO_AES_OPCODE CRYPTO_VA_REG(0x02C) /* read/write */ ++#define REG_CRYPTO_AES_OUTPUT_RDY CRYPTO_VA_REG(0x088) /* read */ ++ ++#define REG_CRYPTO_AES_OUTPUT CRYPTO_VA_REG(0x098) /* read */ ++#define REG_CRYPTO_AES_INTERRUPT CRYPTO_VA_REG(0x028) /* read/write */ ++#define REG_CRYPTO_EFUSE_BOOT_SW_DIS CRYPTO_VA_REG(0x024) /* read/write */ ++ ++ ++ ++#endif /* __HAL_CRYPTO_H__ */ +\ No newline at end of file +diff --git a/arch/arm/mach-gk710x/include/mach/debug-macro.S b/arch/arm/mach-gk710x/include/mach/debug-macro.S +new file mode 100644 +index 00000000..4f799674 +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/debug-macro.S +@@ -0,0 +1,65 @@ ++/* ++ * arch/arm/mach-gk710x/include/mach/debug-macro.S ++ * ++ * History: ++ * 2014/06/18 - [Kewell Liu] created file ++ * ++ * Copyright (C) 2002-2014, Goke Microelectronics China. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++ ++#ifdef CONFIG_MMU ++ ++ .macro addruart, rp, rv, tmp ++ ldr \rp, =GK_PA_APB_BASE @ Physical Base ++ ldr \rv, =GK_VA_APB_BASE @ Virtual Base ++ .endm ++ ++#else /* !CONFIG_MMU */ ++ ++ .macro addruart, rx, tmp ++ mrc p15, 0, \rx, c1, c0 ++ tst \rx, #1 @ MMU enabled ++ moveq \rx, #GK_PA_APB_BASE @ physical base address ++ movne \rx, #GK_VA_APB_BASE @ virtual address ++ orr \rx, \rx, #UART_OFFSET ++ .endm ++ ++#endif /* CONFIG_MMU */ ++ ++.macro senduart, rd, rx ++ str \rd, [\rx, #UART_TH_OFFSET] ++.endm ++ ++.macro waituart, rd, rx ++1001: ++ ldr \rd, [\rx, #UART_LS_OFFSET] ++ tst \rd, #UART_LS_TEMT ++ beq 1001b ++ ++.endm ++ ++.macro busyuart, rd, rx ++1002: ++ ldr \rd, [\rx, #UART_LS_OFFSET] ++ tst \rd, #UART_LS_TEMT ++ beq 1002b ++.endm ++ +diff --git a/arch/arm/mach-gk710x/include/mach/dma.h b/arch/arm/mach-gk710x/include/mach/dma.h +new file mode 100644 +index 00000000..6f9b4440 +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/dma.h +@@ -0,0 +1,170 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/hal/dma.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __HAL_DMA_H__ ++#define __HAL_DMA_H__ ++#include ++ ++ ++#define DMA_BASE (GK_VA_DMAC) ++#define DMA_REG(x) (DMA_BASE + (x)) ++ ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++ ++#define DMA_SUPPORT_DMA_FIOS 0 /* DMA_FIOS */ ++ ++/****************************/ ++/* DMA Channel Assignments */ ++/****************************/ ++ ++#if (DMA_SUPPORT_DMA_FIOS == 0) ++/* DMA instance channel */ ++#define FIO_DMA_CHAN 0 ++#define I2S_RX_DMA_CHAN 1 ++#define I2S_TX_DMA_CHAN 2 ++#define HOST_RX_DMA_CHAN 3 ++#define HOST_TX_DMA_CHAN 4 ++#endif ++ ++#define MS_DMA_CHAN 3 ++/* No AHB MS controller */ ++ ++/* Max number of channel */ ++#define NUM_DMA_FIOS_CHANNELS DMA_SUPPORT_DMA_FIOS ++ ++#define NUM_DMA_CHANNELS 4 ++ ++#if defined(CONFIG_GK_MUSB_CON_V1_00) ++#define DMA_CHAN_TX 3 ++#define DMA_CHAN_RX 3 ++#elif defined(CONFIG_GK_MUSB_CON_V1_10) ++#define DMA_CHAN_TX 0 ++#define DMA_CHAN_RX 3 ++#endif ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++#define DMA_CHAN_CTR_REG(x) DMA_REG((0x300 + ((x) << 4))) ++#define DMA_CHAN_SRC_REG(x) DMA_REG((0x304 + ((x) << 4))) ++#define DMA_CHAN_DST_REG(x) DMA_REG((0x308 + ((x) << 4))) ++#define DMA_CHAN_STA_REG(x) DMA_REG((0x30C + ((x) << 4))) ++#define DMA_CHAN_DA_REG(x) DMA_REG((0x380 + ((x) << 2))) ++#define DMA_INT_REG DMA_REG(0x3F0) ++ ++/* DMA_CHANX_CTR_REG */ ++#define DMA_CHANX_CTR_EN 0x80000000 ++#define DMA_CHANX_CTR_D 0x40000000 ++#define DMA_CHANX_CTR_WM 0x20000000 ++#define DMA_CHANX_CTR_RM 0x10000000 ++#define DMA_CHANX_CTR_NI 0x08000000 ++#define DMA_CHANX_CTR_BLK_1024B 0x07000000 ++#define DMA_CHANX_CTR_BLK_512B 0x06000000 ++#define DMA_CHANX_CTR_BLK_256B 0x05000000 ++#define DMA_CHANX_CTR_BLK_128B 0x04000000 ++#define DMA_CHANX_CTR_BLK_64B 0x03000000 ++#define DMA_CHANX_CTR_BLK_32B 0x02000000 ++#define DMA_CHANX_CTR_BLK_16B 0x01000000 ++#define DMA_CHANX_CTR_BLK_8B 0x00000000 ++#define DMA_CHANX_CTR_TS_8B 0x00C00000 ++#define DMA_CHANX_CTR_TS_4B 0x00800000 ++#define DMA_CHANX_CTR_TS_2B 0x00400000 ++#define DMA_CHANX_CTR_TS_1B 0x00000000 ++ ++/* DMA descriptor bit fields */ ++#define DMA_DESC_EOC 0x01000000 ++#define DMA_DESC_WM 0x00800000 ++#define DMA_DESC_RM 0x00400000 ++#define DMA_DESC_NI 0x00200000 ++#define DMA_DESC_TS_8B 0x00180000 ++#define DMA_DESC_TS_4B 0x00100000 ++#define DMA_DESC_TS_2B 0x00080000 ++#define DMA_DESC_TS_1B 0x00000000 ++#define DMA_DESC_BLK_1024B 0x00070000 ++#define DMA_DESC_BLK_512B 0x00060000 ++#define DMA_DESC_BLK_256B 0x00050000 ++#define DMA_DESC_BLK_128B 0x00040000 ++#define DMA_DESC_BLK_64B 0x00030000 ++#define DMA_DESC_BLK_32B 0x00020000 ++#define DMA_DESC_BLK_16B 0x00010000 ++#define DMA_DESC_BLK_8B 0x00000000 ++#define DMA_DESC_ID 0x00000004 ++#define DMA_DESC_IE 0x00000002 ++#define DMA_DESC_ST 0x00000001 ++ ++/* DMA_CHANX_STA_REG */ ++#define DMA_CHANX_STA_DM 0x80000000 ++#define DMA_CHANX_STA_OE 0x40000000 ++#define DMA_CHANX_STA_DA 0x20000000 ++#define DMA_CHANX_STA_DD 0x10000000 ++#define DMA_CHANX_STA_OD 0x08000000 ++#define DMA_CHANX_STA_ME 0x04000000 ++#define DMA_CHANX_STA_BE 0x02000000 ++#define DMA_CHANX_STA_RWE 0x01000000 ++#define DMA_CHANX_STA_AE 0x00800000 ++#define DMA_CHANX_STA_DN 0x00400000 ++ ++/* DMA_INT_REG */ ++#define DMA_INT_CHAN(x) (0x1 << (x)) ++ ++#if defined(__FPGA__) ++#define DMA_INT_CHAN7 0x00000080 ++#define DMA_INT_CHAN6 0x00000040 ++#define DMA_INT_CHAN5 0x00000020 ++#endif ++ ++#define DMA_INT_CHAN4 0x00000010 ++#define DMA_INT_CHAN3 0x00000008 ++#define DMA_INT_CHAN2 0x00000004 ++#define DMA_INT_CHAN1 0x00000002 ++#define DMA_INT_CHAN0 0x00000001 ++ ++ ++/*********************************/ ++/* FIO/DMA Burst Setup */ ++/* - descriptor, non-descriptor */ ++/* - main, spare */ ++/*********************************/ ++ ++#if defined(__FPGA__) ++ ++#define DMA_NODC_MN_BURST_SIZE (DMA_CHANX_CTR_BLK_32B | DMA_CHANX_CTR_TS_4B) ++#define DMA_NODC_SP_BURST_SIZE (DMA_CHANX_CTR_BLK_32B | DMA_CHANX_CTR_TS_4B) ++#define DMA_DESC_MN_BURST_SIZE (DMA_DESC_BLK_32B | DMA_DESC_TS_4B) ++#define DMA_DESC_SP_BURST_SIZE (DMA_DESC_BLK_32B | DMA_DESC_TS_4B) ++#define FIO_MN_BURST_SIZE (FIO_DMACTR_BLK_32B | FIO_DMACTR_TS4B) ++#define FIO_SP_BURST_SIZE (FIO_DMACTR_BLK_32B | FIO_DMACTR_TS4B) ++ ++#else ++ ++#if (DMA_SUPPORT_DMA_FIOS == 0) ++#define DMA_NODC_MN_BURST_SIZE (DMA_CHANX_CTR_BLK_512B | DMA_CHANX_CTR_TS_4B) ++#define DMA_NODC_SP_BURST_SIZE (DMA_CHANX_CTR_BLK_512B | DMA_CHANX_CTR_TS_4B) ++#define DMA_DESC_MN_BURST_SIZE (DMA_DESC_BLK_512B | DMA_DESC_TS_4B) ++#define DMA_DESC_SP_BURST_SIZE (DMA_DESC_BLK_512B | DMA_DESC_TS_4B) ++#define FIO_MN_BURST_SIZE (FIO_DMACTR_BLK_512B | FIO_DMACTR_TS4B) ++#define FIO_SP_BURST_SIZE (FIO_DMACTR_BLK_512B | FIO_DMACTR_TS4B) ++#else ++ ++#endif ++ ++#endif ++ ++#endif /* __HAL_DMA_H__ */ +diff --git a/arch/arm/mach-gk710x/include/mach/entry-macro.S b/arch/arm/mach-gk710x/include/mach/entry-macro.S +new file mode 100644 +index 00000000..009fdae1 +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/entry-macro.S +@@ -0,0 +1,59 @@ ++/* ++ * arch/arm/mach-gk710x/include/mach/entry-macro.S ++ * ++ * History: ++ * 2014/06/18 - [Kewell Liu] created file ++ * ++ * Copyright (C) 2002-2014, Goke Microelectronics China. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++ ++ .macro stat2nr, stat, nr, tmp ++ rsbs \tmp, \stat, #0 ++ and \nr, \tmp, \stat ++ clzcc \nr, \nr ++ rsc \nr, \nr, #32 ++ teq \nr, #32 ++ .endm ++ ++ .macro disable_fiq ++ .endm ++ ++ .macro get_irqnr_preamble, base, tmp ++ .endm ++ ++ .macro arch_ret_to_user, tmp1, tmp2 ++ .endm ++ ++ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp ++ ldr \base, =(VIC1_BASE) ++ ldr \irqstat, [\base, #VIC_IRQ_STA_OFFSET] ++ stat2nr \irqstat, \irqnr, \tmp ++#if (VIC_INSTANCES >= 2) ++ bne 1000f ++ ldr \base, =(VIC2_BASE) ++ ldr \irqstat, [\base, #VIC_IRQ_STA_OFFSET] ++ stat2nr \irqstat, \irqnr, \tmp ++ addne \irqnr, \irqnr, #VIC2_INT_VEC(0) ++#endif ++1000: ++ .endm ++ +diff --git a/arch/arm/mach-gk710x/include/mach/eth.h b/arch/arm/mach-gk710x/include/mach/eth.h +new file mode 100644 +index 00000000..b9115887 +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/eth.h +@@ -0,0 +1,466 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/mach/eth.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++#ifndef __MACH_ETH_H__ ++#define __MACH_ETH_H__ ++ ++#include ++ ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++ ++#define ETH_INSTANCES 1 ++ ++#define SUPPORT_GMII 0 // 10/100 bits phy ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++#define ETH_REG(x) (GK_VA_ETH_GMAC + (x)) ++ ++#define ETH_MAC_CFG_REG ETH_REG(0x0000) ++ ++#define ETH_MAC_GMII_ADDR_REG ETH_REG(0x0004) ++#define ETH_MAC_GMII_DATA_REG ETH_REG(0x0008) ++ ++#define ETH_MAC_FRAME_FILTER_REG ETH_REG(0x000c) ++#define ETH_MAC_HASH_HI_REG ETH_REG(0x0010) ++#define ETH_MAC_HASH_LO_REG ETH_REG(0x0014) ++#define ETH_MAC_FLOW_CTR_REG ETH_REG(0x0018) ++#define ETH_MAC_VLAN_TAG_REG ETH_REG(0x001c) ++#define ETH_MAC_VERSION_REG ETH_REG(0x0058) ++ ++#define ETH_MAC_MAC0_HI_REG ETH_REG(0x0040) ++#define ETH_MAC_MAC0_LO_REG ETH_REG(0x0044) ++#define ETH_MAC_MAC1_HI_REG ETH_REG(0x0048) ++#define ETH_MAC_MAC1_LO_REG ETH_REG(0x004c) ++#define ETH_MAC_MAC2_HI_REG ETH_REG(0x0050) ++#define ETH_MAC_MAC2_LO_REG ETH_REG(0x0054) ++ ++ ++#define ETH_DMA_TX_POLL_DMD_REG ETH_REG(0x1000) ++#define ETH_DMA_RX_POLL_DMD_REG ETH_REG(0x1004) ++#define ETH_DMA_BUS_MODE_REG ETH_REG(0x1008) ++#define ETH_DMA_RX_DESC_LIST_REG ETH_REG(0x100c) ++#define ETH_DMA_TX_DESC_LIST_REG ETH_REG(0x1010) ++#define ETH_DMA_STATUS_REG ETH_REG(0x1014) ++#define ETH_DMA_MISS_FRAME_BOCNT_REG ETH_REG(0x1018) ++ ++#define ETH_DMA_INTEN_REG ETH_REG(0x101c) ++#define ETH_DMA_OPMODE_REG ETH_REG(0x1020) ++ ++#define ETH_DMA_HOST_TX_DESC_REG ETH_REG(0x1048) ++#define ETH_DMA_HOST_RX_DESC_REG ETH_REG(0x104c) ++#define ETH_DMA_HOST_TX_BUF_REG ETH_REG(0x1040) ++#define ETH_DMA_HOST_RX_BUF_REG ETH_REG(0x1044) ++ ++ ++//------------------------------------------- ++#define ETH_MAC_CFG_OFFSET (0x0000) ++#define ETH_MAC_FRAME_FILTER_OFFSET (0x000c) ++#define ETH_MAC_HASH_HI_OFFSET (0x0010) ++#define ETH_MAC_HASH_LO_OFFSET (0x0014) ++#define ETH_MAC_GMII_ADDR_OFFSET (0x0004) ++#define ETH_MAC_GMII_DATA_OFFSET (0x0008) ++#define ETH_MAC_FLOW_CTR_OFFSET (0x0018) ++#define ETH_MAC_VLAN_TAG_OFFSET (0x001c) ++#define ETH_MAC_VERSION_OFFSET (0x0058) ++#define ETH_MAC_MAC0_HI_OFFSET (0x0040) ++#define ETH_MAC_MAC0_LO_OFFSET (0x0044) ++#define ETH_MAC_MAC1_HI_OFFSET (0x0048) ++#define ETH_MAC_MAC1_LO_OFFSET (0x004c) ++#define ETH_MAC_MAC2_HI_OFFSET (0x0050) ++#define ETH_MAC_MAC2_LO_OFFSET (0x0054) ++ ++#define ETH_DMA_BUS_MODE_OFFSET (0x1008) ++#define ETH_DMA_TX_POLL_DMD_OFFSET (0x1000) ++#define ETH_DMA_RX_POLL_DMD_OFFSET (0x1004) ++#define ETH_DMA_RX_DESC_LIST_OFFSET (0x100c) ++#define ETH_DMA_TX_DESC_LIST_OFFSET (0x1010) ++#define ETH_DMA_STATUS_OFFSET (0x1014) ++#define ETH_DMA_OPMODE_OFFSET (0x1020) ++#define ETH_DMA_INTEN_OFFSET (0x101c) ++#define ETH_DMA_MISS_FRAME_BOCNT_OFFSET (0x1018) ++#define ETH_DMA_HOST_TX_DESC_OFFSET (0x1048) ++#define ETH_DMA_HOST_RX_DESC_OFFSET (0x104c) ++#define ETH_DMA_HOST_TX_BUF_OFFSET (0x1040) ++#define ETH_DMA_HOST_RX_BUF_OFFSET (0x1044) ++ ++/* ETH_MAC_CFG_REG */ ++#define ETH_MAC_CFG_WD 0x00800000 ++#define ETH_MAC_CFG_JD 0x00400000 ++#define ETH_MAC_CFG_BE 0x00200000 ++#define ETH_MAC_CFG_JE 0x00100000 ++#define ETH_MAC_CFG_IFG_96 0x000e0000 ++#define ETH_MAC_CFG_IFG_88 0x000c0000 ++#define ETH_MAC_CFG_IFG_80 0x000a0000 ++#define ETH_MAC_CFG_IFG_72 0x00080000 ++#define ETH_MAC_CFG_IFG_64 0x00060000 ++#define ETH_MAC_CFG_IFG_56 0x00040000 ++#define ETH_MAC_CFG_IFG_48 0x00020000 ++#define ETH_MAC_CFG_IFG_40 0x00000000 ++#define ETH_MAC_CFG_DCRS 0x00010000 ++#define ETH_MAC_CFG_PS 0x00008000 ++#define ETH_MAC_CFG_FES 0x00004000 ++#define ETH_MAC_CFG_DO 0x00002000 ++#define ETH_MAC_CFG_LM 0x00001000 ++#define ETH_MAC_CFG_DM 0x00000800 ++#define ETH_MAC_CFG_IPC 0x00000400 ++#define ETH_MAC_CFG_DR 0x00000200 ++#define ETH_MAC_CFG_LUD 0x00000100 ++#define ETH_MAC_CFG_ACS 0x00000080 ++#define ETH_MAC_CFG_BL_1 0x00000060 ++#define ETH_MAC_CFG_BL_4 0x00000040 ++#define ETH_MAC_CFG_BL_8 0x00000020 ++#define ETH_MAC_CFG_BL_10 0x00000000 ++#define ETH_MAC_CFG_DC 0x00000010 ++#define ETH_MAC_CFG_TE 0x00000008 /* Transmitter Enable */ ++#define ETH_MAC_CFG_RE 0x00000004 /* Receiver Enable */ ++ ++/* ETH_MAC_FRAME_FILTER_REG */ ++#define ETH_MAC_FRAME_FILTER_RA 0x80000000 ++#define ETH_MAC_FRAME_FILTER_SAF 0x00000200 ++#define ETH_MAC_FRAME_FILTER_SAIF 0x00000100 ++#define ETH_MAC_FRAME_FILTER_PCF_PASS 0x000000c0 ++#define ETH_MAC_FRAME_FILTER_PCF_FAIL 0x00000040 ++#define ETH_MAC_FRAME_FILTER_PCF_ALL 0x00000000 ++#define ETH_MAC_FRAME_FILTER_DBF 0x00000020 ++#define ETH_MAC_FRAME_FILTER_PM 0x00000010 ++#define ETH_MAC_FRAME_FILTER_DAIF 0x00000008 ++#define ETH_MAC_FRAME_FILTER_HMC 0x00000004 ++#define ETH_MAC_FRAME_FILTER_HUC 0x00000002 ++#define ETH_MAC_FRAME_FILTER_PR 0x00000001 ++ ++/* ETH_MAC_GMII_ADDR_REG */ ++#define ETH_MAC_GMII_ADDR_PA(x) (((x) & 0x1f) << 11) ++#define ETH_MAC_GMII_ADDR_GR(x) (((x) & 0x1f) << 6) ++#define ETH_MAC_GMII_ADDR_CR_250_300MHZ 0x00000014 ++#define ETH_MAC_GMII_ADDR_CR_150_250MHZ 0x00000010 ++#define ETH_MAC_GMII_ADDR_CR_35_60MHZ 0x0000000c ++#define ETH_MAC_GMII_ADDR_CR_20_35MHZ 0x00000008 ++#define ETH_MAC_GMII_ADDR_CR_100_150MHZ 0x00000004 ++#define ETH_MAC_GMII_ADDR_CR_60_100MHZ 0x00000000 ++#define ETH_MAC_GMII_ADDR_GW 0x00000002 ++#define ETH_MAC_GMII_ADDR_GB 0x00000001 ++ ++/* ETH_MAC_FLOW_CTR_REG */ ++#define ETH_MAC_FLOW_CTR_PT(x) (((x) & 0xffff) << 16) ++#define ETH_MAC_FLOW_CTR_PLT_256 0x00000030 ++#define ETH_MAC_FLOW_CTR_PLT_144 0x00000020 ++#define ETH_MAC_FLOW_CTR_PLT_28 0x00000010 ++#define ETH_MAC_FLOW_CTR_PLT_4 0x00000000 ++#define ETH_MAC_FLOW_CTR_UP 0x00000008 ++#define ETH_MAC_FLOW_CTR_RFE 0x00000004 ++#define ETH_MAC_FLOW_CTR_TFE 0x00000002 ++#define ETH_MAC_FLOW_CTR_FCBBPA 0x00000001 ++ ++/* ETH_MAC_VERSION_REG */ ++#define ETH_MAC_VERSION_USER(v) (((x) & 0x0000ff00) >> 8) ++#define ETH_MAC_VERSION_SYN(v) ((x) & 0x000000ff) ++ ++/* ETH_DMA_BUS_MODE_REG */ ++#define ETH_DMA_BUS_MODE_FB 0x00010000 ++#define ETH_DMA_BUS_MODE_PR4 0x0000c000 ++#define ETH_DMA_BUS_MODE_PR3 0x00008000 ++#define ETH_DMA_BUS_MODE_PR2 0x00004000 ++#define ETH_DMA_BUS_MODE_PR1 0x00000000 ++#define ETH_DMA_BUS_MODE_PBL_32 0x00002000 ++#define ETH_DMA_BUS_MODE_PBL_16 0x00001000 ++#define ETH_DMA_BUS_MODE_PBL_8 0x00000800 ++#define ETH_DMA_BUS_MODE_PBL_4 0x00000400 ++#define ETH_DMA_BUS_MODE_PBL_2 0x00000200 ++#define ETH_DMA_BUS_MODE_PBL_1 0x00000100 ++#define ETH_DMA_BUS_MODE_DSL(len) ((len & 0x1f) << 2) ++#define ETH_DMA_BUS_MODE_DA_RX 0x00000002 ++#define ETH_DMA_BUS_MODE_DA_TX 0x00000000 ++#define ETH_DMA_BUS_MODE_SWR 0x00000001 ++ ++/* ETH_DMA_STATUS_REG */ ++#define ETH_DMA_STATUS_GPI 0x10000000 ++#define ETH_DMA_STATUS_GMI 0x08000000 ++#define ETH_DMA_STATUS_GLI 0x04000000 ++#define ETH_DMA_STATUS_EB_MASK 0x03800000 ++#define ETH_DMA_STATUS_EB_TXDMA 0x02000000 ++#define ETH_DMA_STATUS_EB_RXDMA 0x00000000 ++#define ETH_DMA_STATUS_EB_RXFER 0x01000000 ++#define ETH_DMA_STATUS_EB_TXFER 0x00000000 ++#define ETH_DMA_STATUS_EB_DESC 0x00800000 ++#define ETH_DMA_STATUS_EB_DBUF 0x00000000 ++#define ETH_DMA_STATUS_TS_MASK 0x00700000 ++#define ETH_DMA_STATUS_TS_CTD 0x00700000 ++#define ETH_DMA_STATUS_TS_SUSP 0x00600000 ++#define ETH_DMA_STATUS_TS_READ 0x00300000 ++#define ETH_DMA_STATUS_TS_WAIT 0x00200000 ++#define ETH_DMA_STATUS_TS_FETCH 0x00100000 ++#define ETH_DMA_STATUS_TS_STOP 0x00000000 ++#define ETH_DMA_STATUS_RS_MASK 0x000e0000 ++#define ETH_DMA_STATUS_RS_RCV 0x000e0000 ++#define ETH_DMA_STATUS_RS_CRD 0x000a0000 ++#define ETH_DMA_STATUS_RS_SUSP 0x00080000 ++#define ETH_DMA_STATUS_RS_WAIT 0x00060000 ++#define ETH_DMA_STATUS_RS_FETCH 0x00020000 ++#define ETH_DMA_STATUS_RS_STOP 0x00000000 ++#define ETH_DMA_STATUS_NIS 0x00010000 ++#define ETH_DMA_STATUS_AIS 0x00008000 ++#define ETH_DMA_STATUS_ERI 0x00004000 ++#define ETH_DMA_STATUS_FBI 0x00002000 ++#define ETH_DMA_STATUS_ETI 0x00000400 ++#define ETH_DMA_STATUS_RWT 0x00000200 ++#define ETH_DMA_STATUS_RPS 0x00000100 ++#define ETH_DMA_STATUS_RU 0x00000080 ++#define ETH_DMA_STATUS_RI 0x00000040 ++#define ETH_DMA_STATUS_UNF 0x00000020 ++#define ETH_DMA_STATUS_OVF 0x00000010 ++#define ETH_DMA_STATUS_TJT 0x00000008 ++#define ETH_DMA_STATUS_TU 0x00000004 ++#define ETH_DMA_STATUS_TPS 0x00000002 ++#define ETH_DMA_STATUS_TI 0x00000001 ++ ++/* ETH_DMA_OPMODE_REG */ ++#define ETH_DMA_OPMODE_DT 0x04000000 ++#define ETH_DMA_OPMODE_RSF 0x02000000 ++#define ETH_DMA_OPMODE_DFF 0x01000000 ++#define ETH_DMA_OPMODE_TSF 0x00200000 ++#define ETH_DMA_OPMODE_FTF 0x00100000 ++#define ETH_DMA_OPMODE_TTC_16 0x0001c000 ++#define ETH_DMA_OPMODE_TTC_24 0x00018000 ++#define ETH_DMA_OPMODE_TTC_32 0x00014000 ++#define ETH_DMA_OPMODE_TTC_40 0x00010000 ++#define ETH_DMA_OPMODE_TTC_256 0x0000c000 ++#define ETH_DMA_OPMODE_TTC_192 0x00008000 ++#define ETH_DMA_OPMODE_TTC_128 0x00004000 ++#define ETH_DMA_OPMODE_TTC_64 0x00000000 ++#define ETH_DMA_OPMODE_ST 0x00002000 ++#define ETH_DMA_OPMODE_RFD_4K 0x00001800 ++#define ETH_DMA_OPMODE_RFD_3K 0x00001000 ++#define ETH_DMA_OPMODE_RFD_2K 0x00000800 ++#define ETH_DMA_OPMODE_RFD_1K 0x00000000 ++#define ETH_DMA_OPMODE_RFA_4K 0x00000600 ++#define ETH_DMA_OPMODE_RFA_3K 0x00000400 ++#define ETH_DMA_OPMODE_RFA_2K 0x00000200 ++#define ETH_DMA_OPMODE_RFA_1K 0x00000000 ++#define ETH_DMA_OPMODE_EFC 0x00000100 ++#define ETH_DMA_OPMODE_FEF 0x00000080 ++#define ETH_DMA_OPMODE_FUF 0x00000040 ++#define ETH_DMA_OPMODE_RTC_128 0x00000018 ++#define ETH_DMA_OPMODE_RTC_96 0x00000010 ++#define ETH_DMA_OPMODE_RTC_32 0x00000008 ++#define ETH_DMA_OPMODE_RTC_64 0x00000000 ++#define ETH_DMA_OPMODE_OSF 0x00000004 ++#define ETH_DMA_OPMODE_SR 0x00000002 ++ ++/* ETH_DMA_INTEN_REG */ ++#define ETH_DMA_INTEN_NIE 0x00010000 ++#define ETH_DMA_INTEN_AIE 0x00008000 ++#define ETH_DMA_INTEN_ERE 0x00004000 ++#define ETH_DMA_INTEN_FBE 0x00002000 ++#define ETH_DMA_INTEN_ETE 0x00000400 ++#define ETH_DMA_INTEN_RWE 0x00000200 ++#define ETH_DMA_INTEN_RSE 0x00000100 ++#define ETH_DMA_INTEN_RUE 0x00000080 ++#define ETH_DMA_INTEN_RIE 0x00000040 ++#define ETH_DMA_INTEN_UNE 0x00000020 ++#define ETH_DMA_INTEN_OVE 0x00000010 ++#define ETH_DMA_INTEN_TJE 0x00000008 ++#define ETH_DMA_INTEN_TUE 0x00000004 ++#define ETH_DMA_INTEN_TSE 0x00000002 ++#define ETH_DMA_INTEN_TIE 0x00000001 ++ ++/* ETH_DMA_MISS_FRAME_BOCNT_REG */ ++#define ETH_DMA_MISS_FRAME_BOCNT_FIFO 0x10000000 ++#define ETH_DMA_MISS_FRAME_BOCNT_APP(v) (((v) & 0x0ffe0000) >> 17) ++#define ETH_DMA_MISS_FRAME_BOCNT_FRAME 0x00001000 ++#define ETH_DMA_MISS_FRAME_BOCNT_HOST(v) ((v) & 0x0000ffff) ++ ++/* Receive Descriptor 0 (RDES0) */ ++#define ETH_RDES0_OWN 0x80000000 ++#define ETH_RDES0_AFM 0x40000000 ++#define ETH_RDES0_FL(v) (((v) & 0x3fff0000) >> 16) ++#define ETH_RDES0_ES 0x00008000 ++#define ETH_RDES0_DE 0x00004000 ++#define ETH_RDES0_SAF 0x00002000 ++#define ETH_RDES0_LE 0x00001000 ++#define ETH_RDES0_OE 0x00000800 ++#define ETH_RDES0_VLAN 0x00000400 ++#define ETH_RDES0_FS 0x00000200 ++#define ETH_RDES0_LS 0x00000100 ++#define ETH_RDES0_IPC 0x00000080 ++#define ETH_RDES0_LC 0x00000040 ++#define ETH_RDES0_FT 0x00000020 ++#define ETH_RDES0_RWT 0x00000010 ++#define ETH_RDES0_RE 0x00000008 ++#define ETH_RDES0_DBE 0x00000004 ++#define ETH_RDES0_CE 0x00000002 ++#define ETH_RDES0_RX 0x00000001 ++ ++#define ETH_RDES0_COE_MASK 0x000000a1 ++#define ETH_RDES0_COE_LENLT600 0x00000000 /* Bit(5:7:0)=>0 IEEE 802.3 type frame Length field is Lessthan 0x0600 */ ++#define ETH_RDES0_COE_UNSUPPORTED 0x00000001 /* Bit(5:7:0)=>1 Payload & Ip header checksum bypassed (unsuppported payload) */ ++#define ETH_RDES0_COE_RESERVED 0x00000080 /* Bit(5:7:0)=>2 Reserved */ ++#define ETH_RDES0_COE_CHKBYPASS 0x00000081 /* Bit(5:7:0)=>3 Neither IPv4 nor IPV6. So checksum bypassed */ ++#define ETH_RDES0_COE_NOCHKERROR 0x00000020 /* Bit(5:7:0)=>4 No IPv4/IPv6 Checksum error detected */ ++#define ETH_RDES0_COE_PLCHKERROR 0x00000021 /* Bit(5:7:0)=>5 Payload checksum error detected for Ipv4/Ipv6 frames */ ++#define ETH_RDES0_COE_HDRCHKERROR 0x000000a0 /* Bit(5:7:0)=>6 Ip header checksum error detected for Ipv4 frames */ ++#define ETH_RDES0_COE_HDRPLCHKERROR 0x000000a1 /* Bit(5:7:0)=>7 Payload & Ip header checksum error detected for Ipv4/Ipv6 frames */ ++ ++/* Receive Descriptor 1 (RDES1) */ ++#define ETH_RDES1_DIC 0x80000000 ++#define ETH_RDES1_RER 0x02000000 ++#define ETH_RDES1_RCH 0x01000000 ++#define ETH_RDES1_RBS2(v) (((v) & 0x003ff800) >> 11) /* Receive Buffer 2 Size */ ++#define ETH_RDES1_RBS1(v) ((v) & 0x000007ff) /* Receive Buffer 1 Size */ ++#define ETH_RDES1_RBS2x(x) (((x) << 11) & 0x003ff800) /* Receive Buffer 2 Size */ ++#define ETH_RDES1_RBS1x(x) ((x) & 0x000007ff) /* Receive Buffer 1 Size */ ++ ++/* Transmit Descriptor 0 (TDES0) */ ++#define ETH_TDES0_OWN 0x80000000 ++#define ETH_TDES0_TTSS 0x00020000 ++#define ETH_TDES0_IHE 0x00010000 ++#define ETH_TDES0_ES 0x00008000 ++#define ETH_TDES0_JT 0x00004000 ++#define ETH_TDES0_FF 0x00002000 ++#define ETH_TDES0_PCE 0x00001000 ++#define ETH_TDES0_LCA 0x00000800 ++#define ETH_TDES0_NC 0x00000400 ++#define ETH_TDES0_LCO 0x00000200 ++#define ETH_TDES0_EC 0x00000100 ++#define ETH_TDES0_VF 0x00000080 ++#define ETH_TDES0_CC(v) (((v) & 0x00000078) >> 3) ++#define ETH_TDES0_ED 0x00000004 ++#define ETH_TDES0_UF 0x00000002 ++#define ETH_TDES0_DB 0x00000001 ++#define ETH_TDES0_ES_MASK (ETH_TDES0_UF | ETH_TDES0_ED | \ ++ ETH_TDES0_EC | ETH_TDES0_LCO | \ ++ ETH_TDES0_NC | ETH_TDES0_LCA | \ ++ ETH_TDES0_FF | ETH_TDES0_JT | \ ++ ETH_TDES0_ES) ++ ++/* Transmit Descriptor 1 (TDES1) */ ++#define ETH_TDES1_IC 0x80000000 ++#define ETH_TDES1_LS 0x40000000 ++#define ETH_TDES1_FS 0x20000000 ++#define ETH_TDES1_CIC_TUI 0x10000000 ++#define ETH_TDES1_CIC_HDR 0x08000000 ++#define ETH_TDES1_DC 0x04000000 ++#define ETH_TDES1_TER 0x02000000 ++#define ETH_TDES1_TCH 0x01000000 ++#define ETH_TDES1_DP 0x00800000 ++#define ETH_TDES1_TBS2(v) (((v) & 0x003ff800) >> 11) ++#define ETH_TDES1_TBS1(v) ((v) & 0x000007ff) ++#define ETH_TDES1_TBS2x(x) (((x) << 11) & 0x003ff800) ++#define ETH_TDES1_TBS1x(x) ((x) & 0x000007ff) ++ ++/* ==========================================================================*/ ++#define GKETH_MAC_SIZE (6) ++ ++ ++#define EPHY_BASE (GK_VA_ETH_PHY) ++#define EPHY_REG(x) (EPHY_BASE + (x)) ++ ++#define REG_EPHY_CONTROL EPHY_REG(0x000) /* read/write */ ++#define REG_EPHY_STATUS EPHY_REG(0x004) /* read */ ++#define REG_EPHY_ID1 EPHY_REG(0x008) /* read */ ++#define REG_EPHY_ID2 EPHY_REG(0x00C) /* read */ ++#define REG_EPHY_ANAR EPHY_REG(0x010) /* read/write */ ++#define REG_EPHY_ANLPAR EPHY_REG(0x014) /* read */ ++#define REG_EPHY_ANER EPHY_REG(0x018) /* read/write */ ++#define REG_EPHY_ANNPAR EPHY_REG(0x01C) /* read/write */ ++#define REG_EPHY_ANLPNP EPHY_REG(0x020) /* read */ ++#define REG_EPHY_MS_CONTROL EPHY_REG(0x024) /* read/write */ ++#define REG_EPHY_MS_STATUS EPHY_REG(0x028) /* read */ ++#define REG_EPHY_PSE_CONTROL EPHY_REG(0x02C) /* read/write */ ++#define REG_EPHY_PSE_STATUS EPHY_REG(0x030) /* read */ ++#define REG_EPHY_MMD_CONTROL EPHY_REG(0x034) /* read/write */ ++#define REG_EPHY_MMD_CONTROL_ADDR EPHY_REG(0x038) /* read/write */ ++#define REG_EPHY_AN_R_15 EPHY_REG(0x03C) /* read */ ++#define REG_EPHY_WAVE_SHAPING_34 EPHY_REG(0x040) /* read/write */ ++#define REG_EPHY_WAVE_SHAPING_56 EPHY_REG(0x044) /* read/write */ ++#define REG_EPHY_WAVE_SHAPING_78 EPHY_REG(0x048) /* read/write */ ++#define REG_EPHY_WAVE_SHAPING_9A EPHY_REG(0x04C) /* read/write */ ++#define REG_EPHY_WAVE_SHAPING_BC EPHY_REG(0x050) /* read/write */ ++#define REG_EPHY_WAVE_SHAPING_DE EPHY_REG(0x054) /* read/write */ ++#define REG_EPHY_SPEED EPHY_REG(0x058) /* read/write */ ++#define REG_EPHY_LTP EPHY_REG(0x05C) /* read/write */ ++#define REG_EPHY_MCU EPHY_REG(0x060) /* read/write */ ++#define REG_EPHY_CODE_RAM EPHY_REG(0x064) /* read/write */ ++#define REG_EPHY_CODE_RAM_W EPHY_REG(0x068) /* read/write */ ++#define REG_EPHY_100M_LINK EPHY_REG(0x088) /* read/write */ ++#define REG_EPHY_DEBUG EPHY_REG(0x0C8) /* read/write */ ++#define REG_EPHY_DEBUG_MODE EPHY_REG(0x0E0) /* read/write */ ++#define REG_EPHY_ADC_GAIN_PGA EPHY_REG(0x36C) /* read/write */ ++#define REG_EPHY_PLL_ADC_CTRL3 EPHY_REG(0x370) /* read/write */ ++#define REG_EPHY_RX_LPF EPHY_REG(0x374) /* read/write */ ++#define REG_EPHY_PLL_ADC_CTRL0 EPHY_REG(0x394) /* read/write */ ++#define REG_EPHY_PLL_ADC_CTRL1 EPHY_REG(0x398) /* read/write */ ++#define REG_EPHY_PLL_ADC_CTRL2 EPHY_REG(0x3A8) /* read/write */ ++#define REG_EPHY_ADC_DC EPHY_REG(0x3D4) /* read/write */ ++#define REG_EPHY_LDO EPHY_REG(0x3F8) /* read/write */ ++#define REG_EPHY_CLK_GATE EPHY_REG(0x450) /* read */ ++#define REG_EPHY_CLK1 EPHY_REG(0x460) /* read/write */ ++#define REG_EPHY_POWER EPHY_REG(0x474) /* read/write */ ++#define REG_EPHY_MDIIO EPHY_REG(0x540) /* read/write */ ++#define REG_EPHY_CLK0 EPHY_REG(0x588) /* read/write */ ++ ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++struct gk_eth_platform_info { ++ u8 mac_addr[GKETH_MAC_SIZE]; ++ u32 napi_weight; ++ u32 watchdog_timeo; ++ ++ u32 phy_id; ++ u32 phy_supported; ++ u32 mii_id; ++ struct gk_gpio_io_info phy_reset; ++ u32 mii_retry_limit; ++ u32 mii_retry_tmo; ++ ++ u32 default_tx_ring_size; ++ u32 default_rx_ring_size; ++ u32 default_dma_bus_mode; ++ u32 default_dma_opmode; ++ u32 default_supported; ++ ++ int (*is_enabled)(void); ++}; ++ ++#define GK_ETH_PARAM_CALL(id, arg, perm) \ ++ module_param_cb(eth##id##_napi_weight, ¶m_ops_uint, &(arg.napi_weight), perm); \ ++ module_param_cb(eth##id##_watchdog_timeo, ¶m_ops_uint, &(arg.watchdog_timeo), perm); \ ++ module_param_cb(eth##id##_phy_id, ¶m_ops_uint, &(arg.phy_id), perm); \ ++ module_param_cb(eth##id##_mii_id, ¶m_ops_uint, &(arg.mii_id), perm); \ ++ module_param_cb(eth##id##_mii_retry_limit, ¶m_ops_uint, &(arg.mii_retry_limit), perm); \ ++ module_param_cb(eth##id##_mii_retry_tmo, ¶m_ops_uint, &(arg.mii_retry_tmo), perm); ++ ++/* ==========================================================================*/ ++extern struct platform_device gk_eth0; ++ ++/* ==========================================================================*/ ++extern int gk_init_eth0(const u8 *mac_addr); ++extern void gk_set_phy_reset_pin(u32 gpio_pin); ++extern void gk_set_phy_speed_led(u32 gpio_type); ++ ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++ ++#endif /* __MACH_ETH_H__ */ ++ +diff --git a/arch/arm/mach-gk710x/include/mach/event.h b/arch/arm/mach-gk710x/include/mach/event.h +new file mode 100644 +index 00000000..f9fb34f3 +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/event.h +@@ -0,0 +1,121 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/plat/event.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++#ifndef __PLAT_EVENT_H ++#define __PLAT_EVENT_H ++ ++/* ==========================================================================*/ ++#define GK_EVENT_PRE (0x80000000) ++#define GK_EVENT_POST (0x40000000) ++#define GK_EVENT_CHECK (0x20000000) ++ ++#define GK_EVENT_ID_CPUFREQ (1) ++#define GK_EVENT_ID_PM (2) ++#define GK_EVENT_ID_TOSS (3) ++#define GK_EVENT_ID_GIVEUP_DSP (4) ++#define GK_EVENT_ID_TAKEOVER_DSP (5) ++#define GK_EVENT_ID_USBVBUS (6) ++#define GK_EVENT_ID_VI_LOSS (7) ++ ++#define GK_EVENT_PRE_CPUFREQ (GK_EVENT_ID_CPUFREQ | GK_EVENT_PRE) ++#define GK_EVENT_POST_CPUFREQ (GK_EVENT_ID_CPUFREQ | GK_EVENT_POST) ++#define GK_EVENT_CHECK_CPUFREQ (GK_EVENT_ID_CPUFREQ | GK_EVENT_CHECK) ++#define GK_EVENT_PRE_PM (GK_EVENT_ID_PM | GK_EVENT_PRE) ++#define GK_EVENT_POST_PM (GK_EVENT_ID_PM | GK_EVENT_POST) ++#define GK_EVENT_CHECK_PM (GK_EVENT_ID_PM | GK_EVENT_CHECK) ++#define GK_EVENT_PRE_TOSS (GK_EVENT_ID_TOSS | GK_EVENT_PRE) ++#define GK_EVENT_POST_TOSS (GK_EVENT_ID_TOSS | GK_EVENT_POST) ++#define GK_EVENT_CHECK_TOSS (GK_EVENT_ID_TOSS | GK_EVENT_CHECK) ++ ++#define GK_EVENT_PRE_GIVEUP_DSP (GK_EVENT_ID_GIVEUP_DSP | GK_EVENT_PRE) ++#define GK_EVENT_POST_GIVEUP_DSP (GK_EVENT_ID_GIVEUP_DSP | GK_EVENT_POST) ++#define GK_EVENT_GIVEUP_DSP (GK_EVENT_ID_GIVEUP_DSP | GK_EVENT_CHECK) ++#define GK_EVENT_PRE_TAKEOVER_DSP (GK_EVENT_ID_TAKEOVER_DSP | GK_EVENT_PRE) ++#define GK_EVENT_POST_TAKEOVER_DSP (GK_EVENT_ID_TAKEOVER_DSP | GK_EVENT_POST) ++#define GK_EVENT_TAKEOVER_DSP (GK_EVENT_ID_TAKEOVER_DSP | GK_EVENT_CHECK) ++ ++#define GK_EVENT_CHECK_USBVBUS (GK_EVENT_ID_USBVBUS | GK_EVENT_CHECK) ++ ++#define GK_EVENT_POST_VI_LOSS (GK_EVENT_ID_VI_LOSS | GK_EVENT_POST) ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++#include ++ ++/* ==========================================================================*/ ++enum gk_event_type { ++ /* No Event */ ++ GK_EV_NONE = 0x00000000, ++ ++ /* VI Event */ ++ GK_EV_VI_DECODER_SOURCE_PLUG = 0x00010000, ++ GK_EV_VI_DECODER_SOURCE_REMOVE, ++ ++ /* VO Event */ ++ GK_EV_VO_CVBS_PLUG = 0x00020000, ++ GK_EV_VO_CVBS_REMOVE, ++ GK_EV_VO_YPBPR_PLUG, ++ GK_EV_VO_YPBPR_REMOVE, ++ GK_EV_VO_HDMI_PLUG, ++ GK_EV_VO_HDMI_REMOVE, ++ ++ /* SENSOR Event*/ ++ GK_EV_ACCELEROMETER_REPORT = 0x00030000, ++ GK_EV_MAGNETIC_FIELD_REPORT, ++ GK_EV_LIGHT_REPORT, ++ GK_EV_PROXIMITY_REPORT, ++ GK_EV_GYROSCOPE_REPORT, ++ GK_EV_TEMPERATURE_REPORT, ++ ++ /* FB2 Event */ ++ GK_EV_FB2_PAN_DISPLAY = 0x00040000, ++}; ++ ++struct gk_event { ++ u32 sno; //sequential number ++ u64 time_code; ++ enum gk_event_type type; ++ u8 data[32]; ++}; ++ ++struct gk_event_pool { ++ struct mutex op_mutex; ++ struct gk_event events[256]; ++ unsigned int ev_sno; ++ unsigned char ev_index; ++}; ++ ++extern int gk_event_pool_init(struct gk_event_pool *pool); ++extern int gk_event_pool_affuse(struct gk_event_pool *pool, ++ struct gk_event event); ++extern int gk_event_pool_query_index(struct gk_event_pool *pool); ++extern int gk_event_pool_query_event(struct gk_event_pool *pool, ++ struct gk_event *event, unsigned char index); ++extern int gk_event_report_uevent(struct kobject *kobj, ++ enum kobject_action action, char *envp_ext[]); ++ ++/* ==========================================================================*/ ++extern int gk_unregister_event_notifier(void *nb); ++extern int gk_set_event(unsigned long val, void *v); ++extern int gk_register_raw_event_notifier(void *nb); ++extern int gk_unregister_raw_event_notifier(void *nb); ++extern int gk_set_raw_event(unsigned long val, void *v); ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif ++ +diff --git a/arch/arm/mach-gk710x/include/mach/flash.h b/arch/arm/mach-gk710x/include/mach/flash.h +new file mode 100644 +index 00000000..d0b4b3fd +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/flash.h +@@ -0,0 +1,59 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/mach/flash.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_FLASH_H ++#define __MACH_FLASH_H ++ ++#include ++ ++#define SFLASH_REG(x) (GK_VA_SFLASH + (x)) ++ ++#define REG_SFLASH_DATA SFLASH_REG(0x00) /* read/write */ ++#define REG_SFLASH_COMMAND SFLASH_REG(0x04) /* read/write */ ++#define REG_SFLASH_CE SFLASH_REG(0x08) /* read/write */ ++#define REG_SFLASH_SPEED SFLASH_REG(0x0C) /* read/write */ ++#define REG_SFLASH_PARA_XIP SFLASH_REG(0x10) /* read/write */ ++ ++// FPGA: SCLK = 40MHz ++// EVB: SCLK = 138MHz ++// 000: SCLK/2 ++// 001: SCLK/4 ++// 010: SCLK/6 ++// 011: SCLK/8 ++// 100: SCLK/10 ++typedef enum ++{ ++ GOKE_SFLASH_FREQ_DIV2 = 0, ++ GOKE_SFLASH_FREQ_DIV4, ++ GOKE_SFLASH_FREQ_DIV6, ++ GOKE_SFLASH_FREQ_DIV8, ++ GOKE_SFLASH_FREQ_DIV10 ++}GD_SFLASH_SPEED_MODE; ++ ++#define SYSTEM_SFLASH_FREQ GOKE_SFLASH_FREQ_DIV2 ++ ++struct sflash_platform_data /* flash device platform_data */ ++{ ++ uint32_t speed_mode; ++ uint32_t channel; ++ uint32_t nr_parts; ++ struct mtd_partition *parts; ++}; ++ ++#endif /* __MACH_FLASH_H */ ++ ++ +diff --git a/arch/arm/mach-gk710x/include/mach/gk710x.h b/arch/arm/mach-gk710x/include/mach/gk710x.h +new file mode 100644 +index 00000000..c308c13d +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/gk710x.h +@@ -0,0 +1,200 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk/include/mach/gk.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_GK710X_H ++#define __MACH_GK710X_H ++ ++ ++#include ++#include ++ ++#define CHIP_ID(x) ((x / 1000)) ++#define CHIP_MAJOR(x) ((x / 100) % 10) ++#define CHIP_MINOR(x) ((x / 10) % 10) ++ ++/* ==========================================================================*/ ++#define GK_DEBUG_NULL (0) ++#define GK_DEBUG_MEDIA (1 << 0) ++#define GK_DEBUG_VI (1 << 1) ++#define GK_DEBUG_VO (1 << 2) ++#define GK_DEBUG_AAA (1 << 3) ++#define GK_DEBUG_DSP (1 << 4) ++ ++/* definition SOC types */ ++#define CONFIG_SOC_GK7101 0 ++#define CONFIG_SOC_GK7102 1 ++ ++#define CONFIG_U2K_PHY_TYPE 0xC0000000 ++#define CONFIG_U2K_ARM_FREQ 0xC0000004 ++#define CONFIG_U2K_HAL_ADDR 0xC0000008 ++ ++#define CONFIG_U2K_SOC_ADDR 0xC0000010 //0:, 1:7102 ++#define CONFIG_U2K_MEM_ADDR 0xC0000014 ++#define CONFIG_U2K_BSB_ADDR 0xC0000018 ++#define CONFIG_U2K_DSP_ADDR 0xC000001C ++ ++#define CONFIG_U2K_ENABLE 0xC0000020 ++#define CONFIG_U2K_USR_ADDR 0xC0000024 //for user's cmem module ++ ++#define CONFIG_U2K_TOTAL_MEM 0xC0000028 ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++/* ==========================================================================*/ ++extern u32 gk_debug_level; ++extern u32 gk_debug_info; ++ ++#define HW_HAL_MODE 1 ++#define USB_DMA_ADD_MODE 0 // 1: need update hal to 20151223 ++#define SPI_API_MODE 1 // 1: need update hal to 20160324 ++#define ADC_HAL_MODE 1 ++#define AUD_HAL_MODE 1 ++#define CRY_HAL_MODE 1 ++#define DDR_HAL_MODE 1 ++#define DSP_HAL_MODE 1 ++#define ETH_HAL_MODE 1 ++#define GREG_HAL_MODE 1 ++#define GPIO_HAL_MODE 1 ++#define I2C_HAL_MODE 1 ++#define I2S_HAL_MODE 1 ++#define IR_HAL_MODE 1 ++#define IRQ_HAL_MODE 1 ++#define MCU_HAL_MODE 1 ++#define PWM_HAL_MODE 1 ++#define RCT_HAL_MODE 1 ++#define SD_HAL_MODE 1 ++#define SF_HAL_MODE 1 ++#define SSI_HAL_MODE 1 ++#define TIMER_HAL_MODE 1 ++#define UART_HAL_MODE 1 ++#define USB_HAL_MODE 1 ++#define VOUT_HAL_MODE 1 ++#define WDT_HAL_MODE 1 ++#define EFUSE_HAL_MODE 0 ++struct hw_ops ++{ ++ int (*get_version)(void); ++ unsigned int (*reserved)(unsigned int ); ++ ++ unsigned char (*hw_readb)(unsigned int ); ++ unsigned short (*hw_readw)(unsigned int ); ++ unsigned int (*hw_readl)(unsigned int ); ++ ++ void (*hw_writeb)(unsigned char , unsigned int ); ++ void (*hw_writew)(unsigned short , unsigned int ); ++ void (*hw_writel)(unsigned int , unsigned int ); ++ ++ unsigned int (*flash_read)(void); ++ void (*flash_write)(unsigned int); ++ ++ unsigned char (*usb_readb)(unsigned int ptr, unsigned int offset); ++ unsigned short (*usb_readw)(unsigned int ptr, unsigned int offset); ++ unsigned int (*usb_readl)(unsigned int ptr, unsigned int offset); ++ void (*usb_writeb)(unsigned int ptr, unsigned int offset, unsigned char value); ++ void (*usb_writew)(unsigned int ptr, unsigned int offset, unsigned short value); ++ void (*usb_writel)(unsigned int ptr, unsigned int offset, unsigned int value); ++ ++ unsigned int (*dma_readl)(unsigned int ptr); ++ void (*dma_writel)(unsigned int ptr, unsigned int value); ++ ++#if SPI_API_MODE ++ unsigned char (*spi_readb)(unsigned int ptr); ++ unsigned short (*spi_readw)(unsigned int ptr); ++ unsigned int (*spi_readl)(unsigned int ptr); ++ void (*spi_writeb)(unsigned int ptr, unsigned char value); ++ void (*spi_writew)(unsigned int ptr, unsigned short value); ++ void (*spi_writel)(unsigned int ptr, unsigned int value); ++#endif ++}; ++ ++extern struct hw_ops *g_hw; ++ ++extern unsigned long gk_debug_lookup_name(const char *name); ++void sensor_init(u8 active_level); ++void sensor_power(u8 power); ++u32 get_audio_clk_freq(void); ++ ++ ++#endif /* __ASSEMBLER__ */ ++ ++extern u32 get_ppm_phys(void); ++extern u32 get_ppm_virt(void); ++extern u32 get_ppm_size(void); ++ ++extern u32 get_bsbmem_phys(void); ++extern u32 get_bsbmem_virt(void); ++extern u32 get_bsbmem_size(void); ++ ++extern u32 get_dspmem_phys(void); ++extern u32 get_dspmem_virt(void); ++extern u32 get_dspmem_size(void); ++ ++extern u32 gk_phys_to_virt(u32 paddr); ++extern u32 gk_virt_to_phys(u32 vaddr); ++ ++extern u32 get_hal1_virt(void); ++extern u32 get_hal2_virt(void); ++ ++extern u32 get_ahb_phys(void); ++extern u32 get_ahb_virt(void); ++extern u32 get_ahb_size(void); ++ ++extern u32 get_apb_phys(void); ++extern u32 get_apb_virt(void); ++extern u32 get_apb_size(void); ++ ++extern u32 get_osd_phys(void); ++extern u32 get_osd_virt(void); ++extern u32 get_osd_size(void); ++ ++extern u32 get_pri_phys(void); ++extern u32 get_pri_virt(void); ++extern u32 get_pri_size(void); ++ ++extern u32 get_qpm_phys(void); ++extern u32 get_qpm_virt(void); ++extern u32 get_qpm_size(void); ++ ++extern u32 get_bsbmem_virt(void); ++extern u32 get_bsbmem_size(void); ++ ++extern u32 get_usrmem_phys(void); ++extern u32 get_usrmem_virt(void); ++extern u32 get_usrmem_size(void); ++ ++extern void get_stepping_info(int *chip, int *major, int *minor); ++extern int gk_register_event_notifier(void *nb); ++ ++extern u32 gk_boot_splash_logo; ++ ++extern u64 gk_dmamask; ++ ++extern int gk_create_proc_dir(void); ++extern struct proc_dir_entry *get_gk_proc_dir(void); ++ ++extern void get_stepping_info(int *chip, int *major, int *minor); ++ ++extern void gk_restart(char mode, const char *cmd); ++extern void gk_power_off(void); ++ ++extern void gk_map_io(void) __init; ++ ++extern void gk_load_51mcu_code(u32 code); ++ ++#endif /* __MACH_GK_H */ ++ +diff --git a/arch/arm/mach-gk710x/include/mach/gpio.h b/arch/arm/mach-gk710x/include/mach/gpio.h +new file mode 100644 +index 00000000..51741c05 +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/gpio.h +@@ -0,0 +1,114 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/mach/gpio.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_GPIO_H_ ++#define __MACH_GPIO_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Defines and Macros ++//***************************************************************************** ++//***************************************************************************** ++#define GPIO0_BASE (GK_VA_GPIO0) ++#define GPIO0_BANK0_BASE (GK_VA_GPIO0) ++#define GPIO0_BANK1_BASE (GK_VA_GPIO0) ++#define GPIO0_BANK0_PLL_IOCTRL_BASE (GK_VA_RCT + 0x0264) /* read/write */ ++#define GPIO0_BANK1_PLL_IOCTRL_BASE (GK_VA_RCT + 0x0264 - 0x100) /* read/write */ ++ ++// for bank ++#define REG_GPIO_IS_LOW_OFFSET (0x0000) /* read/write */ ++#define REG_GPIO_IS_HIGH_OFFSET (0x0004) /* read/write */ ++#define REG_GPIO_IBE_LOW_OFFSET (0x0008) /* read/write */ ++#define REG_GPIO_IBE_HIGH_OFFSET (0x000C) /* read/write */ ++#define REG_GPIO_IEV_LOW_OFFSET (0x0010) /* read/write */ ++#define REG_GPIO_IEV_HIGH_OFFSET (0x0014) /* read/write */ ++#define REG_GPIO_IE_LOW_OFFSET (0x0018) /* read/write */ ++#define REG_GPIO_IE_HIGH_OFFSET (0x001C) /* read/write */ ++#define REG_GPIO_IC_LOW_OFFSET (0x0020) /* write */ ++#define REG_GPIO_IC_HIGH_OFFSET (0x0024) /* write */ ++#define REG_GPIO_RIS_LOW_OFFSET (0x0028) /* read */ ++#define REG_GPIO_RIS_HIGH_OFFSET (0x002C) /* read */ ++#define REG_GPIO_MIS_LOW_OFFSET (0x0030) /* read */ ++#define REG_GPIO_MIS_HIGH_OFFSET (0x0034) /* read */ ++#define REG_GPIO_DIN_LOW_OFFSET (0x0040) /* read */ ++#define REG_GPIO_DIN_HIGH_OFFSET (0x0044) /* read */ ++#define REG_GPIO_OUTPUT_CFG_OFFSET (0x0100) /* write */ ++#define REG_GPIO_INPUT_CFG_OFFSET (0x0200) /* write */ ++ ++// for all bank ++#define REG_GPIO_INT_EN_OFFSET (0x0038) /* write */ ++#define REG_GPIO_PER_SEL_OFFSET (0x003C) /* read/write */ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Enumerated types ++//***************************************************************************** ++//***************************************************************************** ++ ++ ++ ++/*! ++******************************************************************************* ++** ++** \brief All available GPIO pins named by number. ++** ++** \sa GPIO_Open() ++** \sa GPIO_OpenFunctionMode() ++** \sa GPIO_SetType() ++** ++******************************************************************************* ++*/ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Data Structures ++//***************************************************************************** ++//***************************************************************************** ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Global Data ++//***************************************************************************** ++//***************************************************************************** ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** API Functions ++//***************************************************************************** ++//***************************************************************************** ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++extern int __init gk_init_gpio(void); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++ ++#endif /* __MACH_GPIO_H_ */ ++ +diff --git a/arch/arm/mach-gk710x/include/mach/gtypes.h b/arch/arm/mach-gk710x/include/mach/gtypes.h +new file mode 100644 +index 00000000..26932665 +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/gtypes.h +@@ -0,0 +1,132 @@ ++#ifndef _GTYPES_H_ ++#define _GTYPES_H_ ++ ++#ifdef __LINUX__ ++#include /* kmalloc */ ++#include /* printk */ ++#include /* wait queue */ ++#include /* copy user<->kernel */ ++#include /* paddr<->vaddr */ ++#include /* semaphore */ ++#include /* poll */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++/* necessary undefines */ ++#ifdef GFALSE ++ #undef GFALSE ++#endif ++#ifdef GTRUE ++ #undef GTRUE ++#endif ++ ++ ++/*! ++******************************************************************************* ++** ++** \name GOKESDK Error Codes ++** ++******************************************************************************* ++*/ ++/*@{*/ ++enum ++{ ++ GD_OK = 0, //!< No error. ++ GD_ERR_BAD_PARAMETER, //!< Bad parameter passed. ++ GD_ERR_OUT_OF_MEMORY, //!< Memory allocation failed. ++ GD_ERR_ALREADY_INITIALIZED, //!< Device already initialised. ++ GD_ERR_NOT_INITIALIZED, //!< Device not initialised. ++ GD_ERR_ALREADY_OPEN, //!< Device could not be opened again. ++ GD_ERR_FEATURE_NOT_SUPPORTED, //!< Feature or function is not available. ++ GD_ERR_TIMEOUT, //!< Timeout occured. ++ GD_ERR_DEVICE_BUSY, //!< The device is busy. ++ GD_ERR_INVALID_HANDLE, //!< The handle is invalid. ++}; ++/*@}*/ ++ ++ ++/*! ++******************************************************************************* ++** ++** \name GOKESDK Data Types ++** ++******************************************************************************* ++*/ ++/*@{*/ ++typedef unsigned char U8; //!< 8 bit unsigned integer. ++typedef unsigned short U16; //!< 16 bit unsigned integer. ++#ifdef __LINUX__ ++typedef unsigned int U32; //!< 32 bit unsigned integer. ++typedef signed int S32; //!< 32 bit signed integer. ++#else ++typedef unsigned long U32; //!< 32 bit unsigned integer. ++typedef signed long S32; //!< 32 bit signed integer. ++#endif ++typedef signed char S8; //!< 8 bit signed integer. ++typedef signed short S16; //!< 16 bit signed integer. ++typedef unsigned long long U64; //!< 64 bit unsigned integer. ++ ++#ifdef __LINUX__ ++typedef int GERR; ++#else ++typedef unsigned long GERR; //!< GOKESDK error/return code. ++#endif ++typedef unsigned long GD_HANDLE; //!< GOKESDK handle. ++ ++/*! \brief Defines a GOKESDK boolean. */ ++#ifndef GTYPES_NO_BOOL ++typedef enum ++{ ++ GFALSE = 0, //!< Logical false. ++ GTRUE = 1 //!< Logical true. ++} GBOOL; ++#endif ++/*@}*/ ++ ++ ++ ++ ++/*! ++******************************************************************************* ++** ++** \brief Defines a GOKESDK null. ++** ++******************************************************************************* ++*/ ++#ifndef NULL ++ #define NULL 0 ++#endif ++ ++ ++/* ++******************************************************************************* ++** ++** Defines the keyword for inlining a function. ++** ++******************************************************************************* ++*/ ++ ++#define GH_INLINE_LEVEL 2 ++ ++#if defined(__HIGHC__) ++#define GH_INLINE _Inline ++#endif ++#if defined(__GNUC__) ++#define GH_INLINE static __inline__ ++#endif ++ ++#ifdef GISR_IS_VOID ++ #define GISR1 void /* customize C-Interrupt handler */ ++ #define GISR2 void ++#else ++ #define GISR1 irqreturn_t ++ #define GISR2 irqreturn_t ++#endif ++ ++#endif +\ No newline at end of file +diff --git a/arch/arm/mach-gk710x/include/mach/hardware.h b/arch/arm/mach-gk710x/include/mach/hardware.h +new file mode 100644 +index 00000000..03f9e71c +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/hardware.h +@@ -0,0 +1,226 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk/include/mach/hardware.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++ ++#ifndef __ASM_ARCH_HARDWARE_H ++#define __ASM_ARCH_HARDWARE_H ++ ++#include ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++ ++/*-------------------------------------------------------------*/ ++ ++#define CONFIG_GK_PPM_SIZE 0x200000 ++ ++#define DEFAULT_MEM_START (0xc0000000) ++ ++ ++#define AHB_SIZE (0x01000000) ++#define APB_SIZE (0x01000000) ++ ++#define NOLINUX_MEM_V_START (0xe0000000) ++#define NOLINUX_MEM_V_SIZE (0x00100000) ++ ++ ++//-------------------dummy-----ahb----------- ++#define GK_PA_AHB_BASE (0x90000000) ++#define GK_VA_AHB_BASE (0xf2000000) ++ ++#define GK_ADDR_SDC_OFFSET 0x00000 //0x02000 //for dummy ++#define GK_ADDR_EFUSE_OFFSET 0x01000 ++#define GK_ADDR_DDRC_OFFSET 0x02000 ++#define GK_ADDR_DMAC_OFFSET 0x03000 ++#define GK_ADDR_VO_OFFSET 0x04000 ++#define GK_ADDR_CRYPT_OFFSET 0x05000 ++#define GK_ADDR_USB_OFFSET 0x06000 ++#define GK_ADDR_VIC1_OFFSET 0x08000 ++#define GK_ADDR_VIC2_OFFSET 0x09000 ++#define GK_ADDR_ETH_GMAC_OFFSET 0x0E000 ++#define GK_ADDR_ETH_DMA_OFFSET 0x0F000 ++#define GK_ADDR_I2S_OFFSET 0x0A000 ++#define GK_ADDR_SFLASH_OFFSET 0x16000 ++ ++#define GK_ADDR_ADC_OFFSET 0x20A00 ++#define GK_ADDR_AHB_GREG_OFFSET 0x20E00 ++#define GK_ADDR_USB_PHY_OFFSET 0x21000 ++#define GK_ADDR_ENET_PHY_OFFSET 0x22000 ++#define GK_ADDR_VEDIO_DAC_OFFSET 0x22600 ++ ++ ++#define GK_ADDR_PMU_OFFSET 0x80000 ++#define GK_ADDR_PMU_RTC_OFFSET 0x80000 ++#define GK_ADDR_PMU_C51_CODE_OFFSET 0xC0000 ++ ++ ++#define GK_ADDR_AUDIO_CODEC_ANALOG_OFFSET 0x21C00 ++#define GK_ADDR_AUDIO_CODEC_DIGITAL_OFFSET 0x20C00 ++ ++ ++#define GK_PA_SDC (GK_PA_AHB_BASE + GK_ADDR_SDC_OFFSET) ++#define GK_PA_I2S (GK_PA_AHB_BASE + GK_ADDR_I2S_OFFSET) ++#define GK_PA_AHB_GREG (GK_PA_AHB_BASE + GK_ADDR_AHB_GREG_OFFSET) ++#define GK_PA_EFUSE (GK_PA_AHB_BASE + GK_ADDR_EFUSE_OFFSET) ++#define GK_PA_SFLASH (GK_PA_AHB_BASE + GK_ADDR_SFLASH_OFFSET) ++#define GK_PA_ADC (GK_PA_AHB_BASE + GK_ADDR_ADC_OFFSET) ++#define GK_PA_VO (GK_PA_AHB_BASE + GK_ADDR_VO_OFFSET) ++#define GK_PA_AUDIO_CODEC_DIGITAL (GK_PA_AHB_BASE + GK_ADDR_AUDIO_CODEC_DIGITAL_OFFSET) ++#define GK_PA_AUDIO_CODEC_ANALOG (GK_PA_AHB_BASE + GK_ADDR_AUDIO_CODEC_ANALOG_OFFSET) ++#define GK_PA_DDRC (GK_PA_AHB_BASE + GK_ADDR_DDRC_OFFSET) ++#define GK_PA_VIC1 (GK_PA_AHB_BASE + GK_ADDR_VIC1_OFFSET) ++#define GK_PA_VIC2 (GK_PA_AHB_BASE + GK_ADDR_VIC2_OFFSET) ++#define GK_PA_ETH_GMAC (GK_PA_AHB_BASE + GK_ADDR_ETH_GMAC_OFFSET) ++#define GK_PA_ETH_DMA (GK_PA_AHB_BASE + GK_ADDR_ETH_DMA_OFFSET) ++#define GK_PA_USB_PHY (GK_PA_AHB_BASE + GK_ADDR_USB_PHY_OFFSET) ++#define GK_PA_ETH_PHY (GK_PA_AHB_BASE + GK_ADDR_ENET_PHY_OFFSET) ++#define GK_PA_PMU (GK_PA_AHB_BASE + GK_ADDR_PMU_OFFSET) ++#define GK_PA_PMU_RTC (GK_PA_AHB_BASE + GK_ADDR_PMU_RTC_OFFSET) ++#define GK_PA_PMU_C51_CODE (GK_PA_AHB_BASE + GK_ADDR_PMU_C51_CODE_OFFSET) ++#define GK_PA_VEDIO_DAC (GK_PA_AHB_BASE + GK_ADDR_VEDIO_DAC_OFFSET) ++#define GK_PA_CRYPT_UNIT (GK_PA_AHB_BASE + GK_ADDR_CRYPT_OFFSET) ++ ++#define GK_VA_SDC (GK_VA_AHB_BASE + GK_ADDR_SDC_OFFSET) ++#define GK_VA_I2S (GK_VA_AHB_BASE + GK_ADDR_I2S_OFFSET) ++#define GK_VA_AHB_GREG (GK_VA_AHB_BASE + GK_ADDR_AHB_GREG_OFFSET) ++#define GK_VA_EFUSE (GK_VA_AHB_BASE + GK_ADDR_EFUSE_OFFSET) ++#define GK_VA_ADC (GK_VA_AHB_BASE + GK_ADDR_ADC_OFFSET) ++#define GK_VA_DDRC (GK_VA_AHB_BASE + GK_ADDR_DDRC_OFFSET) ++#define GK_VA_VIC1 (GK_VA_AHB_BASE + GK_ADDR_VIC1_OFFSET) ++#define GK_VA_VIC2 (GK_VA_AHB_BASE + GK_ADDR_VIC2_OFFSET) ++#define GK_VA_ETH_GMAC (GK_VA_AHB_BASE + GK_ADDR_ETH_GMAC_OFFSET) ++#define GK_VA_ETH_DMA (GK_VA_AHB_BASE + GK_ADDR_ETH_DMA_OFFSET) ++#define GK_VA_USB_PHY (GK_VA_AHB_BASE + GK_ADDR_USB_PHY_OFFSET) ++#define GK_VA_ETH_PHY (GK_VA_AHB_BASE + GK_ADDR_ENET_PHY_OFFSET) ++#define GK_VA_PMU (GK_VA_AHB_BASE + GK_ADDR_PMU_OFFSET) ++#define GK_VA_PMU_RTC (GK_VA_AHB_BASE + GK_ADDR_PMU_RTC_OFFSET) ++#define GK_VA_SFLASH (GK_VA_AHB_BASE + GK_ADDR_SFLASH_OFFSET) ++#define GK_VA_VO (GK_VA_AHB_BASE + GK_ADDR_VO_OFFSET) ++#define GK_VA_AUDIO_CODEC_DIGITAL (GK_VA_AHB_BASE + GK_ADDR_AUDIO_CODEC_DIGITAL_OFFSET) ++#define GK_VA_AUDIO_CODEC_ANALOG (GK_VA_AHB_BASE + GK_ADDR_AUDIO_CODEC_ANALOG_OFFSET) ++#define GK_VA_PMU_C51_CODE (GK_VA_AHB_BASE + GK_ADDR_PMU_C51_CODE_OFFSET) ++#define GK_VA_VEDIO_DAC (GK_VA_AHB_BASE + GK_ADDR_VEDIO_DAC_OFFSET) /*cvbs*/ ++#define GK_VA_CRYPT_UNIT (GK_VA_AHB_BASE + GK_ADDR_CRYPT_OFFSET) ++#if USB_DMA_ADD_MODE ++#define GK_PA_DMAC (GK_PA_AHB_BASE + GK_ADDR_DMAC_OFFSET) ++#define GK_PA_USB (GK_PA_AHB_BASE + GK_ADDR_USB_OFFSET) ++#define GK_VA_DMAC (GK_VA_AHB_BASE + GK_ADDR_DMAC_OFFSET) ++#define GK_VA_USB (GK_VA_AHB_BASE + GK_ADDR_USB_OFFSET) ++#else ++#define GK_PA_DMAC (0x60005000) ++#define GK_PA_USB (0x60006000) ++#define GK_VA_DMAC (0xf0005000) ++#define GK_VA_USB (0xf0006000) ++#endif ++ ++ ++//-------------------dummy-----apb----------- ++#define GK_PA_APB_BASE (0xA0000000) ++#define GK_VA_APB_BASE (0xf3000000) ++ ++#define GK_ADDR_TIMER_OFFSET 0x00000 ++#define GK_ADDR_IDC_OFFSET 0x03000 ++#define GK_ADDR_IDC2_OFFSET 0x04000 ++#define GK_ADDR_UART0_OFFSET 0x05000 ++#define GK_ADDR_WDT_OFFSET 0x06000 ++#define GK_ADDR_GPIO0_OFFSET 0x09000 ++#define GK_ADDR_ADC2_OFFSET 0x07000 ++ ++#define GK_ADDR_PWM0_OFFSET 0x0a000 ++#define GK_ADDR_PWM1_OFFSET 0x0b000 ++#define GK_ADDR_PWM2_OFFSET 0x0c000 ++#define GK_ADDR_PWM3_OFFSET 0x0d000 ++ ++#define GK_ADDR_UART2_OFFSET 0x1E000 ++#define GK_ADDR_UART1_OFFSET 0x1F000 ++ ++#define GK_ADDR_SSI1_OFFSET 0x02000 ++#define GK_ADDR_SSI2_OFFSET 0x08000 ++#define GK_ADDR_TSSI_OFFSET 0x01000 ++ ++#define GK_ADDR_MEM_OFFSET 0x150000 ++#define GK_ADDR_RCT_OFFSET 0x170000 ++ ++ ++ ++#define GK_PA_TIMER (GK_PA_APB_BASE + GK_ADDR_TIMER_OFFSET) ++#define GK_PA_IDC (GK_PA_APB_BASE + GK_ADDR_IDC_OFFSET) ++#define GK_PA_IDC2 (GK_PA_APB_BASE + GK_ADDR_IDC2_OFFSET) ++#define GK_PA_UART0 (GK_PA_APB_BASE + GK_ADDR_UART0_OFFSET) ++#define GK_PA_WDT (GK_PA_APB_BASE + GK_ADDR_WDT_OFFSET) ++#define GK_PA_GPIO0 (GK_PA_APB_BASE + GK_ADDR_GPIO0_OFFSET) ++#define GK_PA_PWM0 (GK_PA_APB_BASE + GK_ADDR_PWM0_OFFSET) ++#define GK_PA_PWM1 (GK_PA_APB_BASE + GK_ADDR_PWM1_OFFSET) ++#define GK_PA_PWM2 (GK_PA_APB_BASE + GK_ADDR_PWM2_OFFSET) ++#define GK_PA_PWM3 (GK_PA_APB_BASE + GK_ADDR_PWM3_OFFSET) ++#define GK_PA_UART2 (GK_PA_APB_BASE + GK_ADDR_UART2_OFFSET) ++#define GK_PA_UART1 (GK_PA_APB_BASE + GK_ADDR_UART1_OFFSET) ++#define GK_PA_ADC2 (GK_PA_APB_BASE + GK_ADDR_ADC2_OFFSET) ++ ++#define GK_PA_SSI1 (GK_PA_APB_BASE + GK_ADDR_SSI1_OFFSET) ++#define GK_PA_SSI2 (GK_PA_APB_BASE + GK_ADDR_SSI2_OFFSET) ++#define GK_PA_TSSI (GK_PA_APB_BASE + GK_ADDR_TSSI_OFFSET) ++#define GK_PA_RCT (GK_PA_APB_BASE + GK_ADDR_RCT_OFFSET) ++#define GK_PA_MEM (GK_PA_APB_BASE + GK_ADDR_MEM_OFFSET) ++ ++ ++ ++#define GK_VA_TIMER (GK_VA_APB_BASE + GK_ADDR_TIMER_OFFSET) ++#define GK_VA_IDC (GK_VA_APB_BASE + GK_ADDR_IDC_OFFSET) ++#define GK_VA_IDC2 (GK_VA_APB_BASE + GK_ADDR_IDC2_OFFSET) ++#define GK_VA_UART0 (GK_VA_APB_BASE + GK_ADDR_UART0_OFFSET) ++#define GK_VA_WDT (GK_VA_APB_BASE + GK_ADDR_WDT_OFFSET) ++#define GK_VA_GPIO0 (GK_VA_APB_BASE + GK_ADDR_GPIO0_OFFSET) ++#define GK_VA_PWM0 (GK_VA_APB_BASE + GK_ADDR_PWM0_OFFSET) ++#define GK_VA_PWM1 (GK_VA_APB_BASE + GK_ADDR_PWM1_OFFSET) ++#define GK_VA_PWM2 (GK_VA_APB_BASE + GK_ADDR_PWM2_OFFSET) ++#define GK_VA_PWM3 (GK_VA_APB_BASE + GK_ADDR_PWM3_OFFSET) ++#define GK_VA_ADC2 (GK_VA_APB_BASE + GK_ADDR_ADC2_OFFSET) ++ ++#define GK_VA_UART2 (GK_VA_APB_BASE + GK_ADDR_UART2_OFFSET) ++#define GK_VA_UART1 (GK_VA_APB_BASE + GK_ADDR_UART1_OFFSET) ++ ++#define GK_VA_SSI1 (GK_VA_APB_BASE + GK_ADDR_SSI1_OFFSET) ++#define GK_VA_SSI2 (GK_VA_APB_BASE + GK_ADDR_SSI2_OFFSET) ++#define GK_VA_TSSI (GK_VA_APB_BASE + GK_ADDR_TSSI_OFFSET) ++#define GK_VA_RCT (GK_VA_APB_BASE + GK_ADDR_RCT_OFFSET) ++#define GK_VA_MEM (GK_VA_APB_BASE + GK_ADDR_MEM_OFFSET) ++ ++ ++#define GRAPHICS_DMA_OFFSET 0x15000 ++#define GRAPHICS_DMA_BASE (GK_VA_AHB_BASE + GRAPHICS_DMA_OFFSET) ++#define GRAPHICS_DMA_REG(x) (GRAPHICS_DMA_BASE + (x)) ++ ++ ++ ++#define VO_CLK_ONCHIP_PLL_27MHZ 0x0 /* Default setting */ ++#define VO_CLK_ONCHIP_PLL_SP_CLK 0x1 ++#define VO_CLK_ONCHIP_PLL_CLK_SI 0x2 ++#define VO_CLK_EXTERNAL 0x3 ++#define VO_CLK_ONCHIP_PLL_DSP_SCLK 0x4 ++ ++#define TIMER_OFFSET 0xb000 ++ ++ ++#define CONSISTENT_DMA_SIZE SZ_8M ++ ++/* ==========================================================================*/ ++ ++//end ++ ++#endif /* __ASM_ARCH_HARDWARE_H */ ++ ++ +diff --git a/arch/arm/mach-gk710x/include/mach/i2s.h b/arch/arm/mach-gk710x/include/mach/i2s.h +new file mode 100644 +index 00000000..5bdd528f +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/i2s.h +@@ -0,0 +1,158 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/hal/i2s.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __HAL_I2S_H__ ++#define __HAL_I2S_H__ ++ ++#include ++ ++#define I2S_BASE (GK_VA_I2S) ++#define I2S_BASE_PHYS (GK_PA_I2S) ++#define I2S_REG(x) (I2S_BASE + (x)) ++#define I2S_REG_PHYS(x) (I2S_BASE_PHYS + (x)) ++ ++#define I2S_BASE_extern I2S_BASE ++ ++#define I2S_DMA_REG_OFFSET (0x30000000) ++ ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++ ++#define I2S_SUPPORT_GATE_SHIFT 1 ++#define I2S_MAX_CHANNELS 6 ++#define I2S_GK_IP 1 ++#define I2S_24BITMUX_MODE_REG_BITS 4 ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++ ++#define I2S_MODE_OFFSET 0x08 ++#define I2S_RX_CTRL_OFFSET 0x2c ++#define I2S_TX_CTRL_OFFSET 0x0c ++#define I2S_WLEN_OFFSET 0x58 ++#define I2S_WPOS_OFFSET 0x44 ++#define I2S_SLOT_OFFSET 0x50 ++#define I2S_TX_FIFO_LTH_OFFSET 0x10 ++#define I2S_RX_FIFO_GTH_OFFSET 0x3c ++#define I2S_CLOCK_OFFSET 0x00 ++#define I2S_INIT_OFFSET 0x4c ++#define I2S_TX_STATUS_OFFSET 0x14 ++#define I2S_TX_LEFT_DATA_OFFSET 0x1c ++#define I2S_TX_RIGHT_DATA_OFFSET 0x20 ++#define I2S_RX_STATUS_OFFSET 0x54 ++#define I2S_RX_DATA_OFFSET 0x30 ++#define I2S_TX_FIFO_CNTR_OFFSET 0x18 ++#define I2S_RX_FIFO_CNTR_OFFSET 0x34 ++#define I2S_TX_INT_ENABLE_OFFSET 0x24 ++#define I2S_RX_INT_ENABLE_OFFSET 0x38 ++#define I2S_RX_ECHO_OFFSET 0x40 ++#define I2S_24BITMUX_MODE_OFFSET 0x28 ++#define I2S_RX_DATA_DMA_OFFSET 0x80 ++#define I2S_TX_LEFT_DATA_DMA_OFFSET 0xc0 ++ ++#define I2S_MODE_REG I2S_REG(0x08) ++#define I2S_RX_CTRL_REG I2S_REG(0x2c) ++#define I2S_TX_CTRL_REG I2S_REG(0x0c) ++#define I2S_WLEN_REG I2S_REG(0x58) ++#define I2S_WPOS_REG I2S_REG(0x44) ++#define I2S_SLOT_REG I2S_REG(0x50) ++#define I2S_TX_FIFO_LTH_REG I2S_REG(0x10) ++#define I2S_RX_FIFO_GTH_REG I2S_REG(0x3c) ++#define I2S_CLOCK_REG I2S_REG(0x00) ++#define I2S_INIT_REG I2S_REG(0x4c) ++#define I2S_TX_STATUS_REG I2S_REG(0x14) ++#define I2S_TX_LEFT_DATA_REG I2S_REG(0x1c) ++#define I2S_TX_RIGHT_DATA_REG I2S_REG(0x20) ++#define I2S_RX_STATUS_REG I2S_REG(0x54) ++#define I2S_RX_DATA_REG I2S_REG(0x30) ++#define I2S_TX_FIFO_CNTR_REG I2S_REG(0x18) ++#define I2S_RX_FIFO_CNTR_REG I2S_REG(0x34) ++#define I2S_TX_INT_ENABLE_REG I2S_REG(0x24) ++#define I2S_RX_INT_ENABLE_REG I2S_REG(0x38) ++#define I2S_RX_ECHO_REG I2S_REG(0x40) ++#define I2S_24BITMUX_MODE_REG I2S_REG(0x28) ++#define I2S_GATEOFF_REG I2S_REG(0x48) ++#define I2S_CHANNEL_SELECT_REG I2S_REG(0x04) ++#define I2S_RX_DATA_DMA_REG I2S_REG(0x80) ++#define I2S_TX_LEFT_DATA_DMA_REG I2S_REG(0xc0) ++ ++ ++#if (I2S_GK_IP == 1) ++#define I2S_TX_FIFO_RESET_BIT (1 << 0) ++#define I2S_RX_FIFO_RESET_BIT (1 << 3) ++#endif ++#define I2S_TX_ENABLE_BIT (1 << 2) ++#define I2S_RX_ENABLE_BIT (1 << 1) ++#define I2S_FIFO_RESET_BIT (1 << 4) ++ ++#define I2S_RX_LOOPBACK_BIT (1 << 2) ++#define I2S_RX_ORDER_BIT (1 << 0) ++#define I2S_RX_WS_MST_BIT (1 << 3) ++#define I2S_RX_WS_INV_BIT (1 << 1) ++ ++#define I2S_TX_LOOPBACK_BIT (1 << 5) ++#define I2S_TX_ORDER_BIT (1 << 3) ++#define I2S_TX_WS_MST_BIT (1 << 6) ++#define I2S_TX_WS_INV_BIT (1 << 2) ++#define I2S_TX_UNISON_BIT (1 << 4) ++#define I2S_TX_MUTE_BIT (1 << 7) ++#define I2S_TX_MONO_MASK 0xfffffffc ++#define I2S_TX_MONO_STEREO (0) ++#define I2S_TX_MONO_RIGHT (2) ++#define I2S_TX_MONO_LEFT (3) ++ ++#define I2S_CLK_WS_OUT_EN (1 << 7) ++#define I2S_CLK_BCLK_OUT_EN (1 << 5) ++#define I2S_CLK_BCLK_OUTPUT (1 << 8) ++#define I2S_CLK_TX_PO_FALL (1 << 9) ++#define I2S_CLK_RX_PO_FALL (1 << 6) ++#define I2S_CLK_DIV_MASK 0xffffffe0 ++#define I2S_CLK_MASTER_MODE (I2S_CLK_WS_OUT_EN | \ ++ I2S_CLK_BCLK_OUT_EN | \ ++ I2S_CLK_TX_PO_FALL | \ ++ I2S_CLK_RX_PO_FALL | \ ++ I2S_CLK_BCLK_OUTPUT) ++ ++ ++#if (I2S_GK_IP == 0) ++#define I2S_RX_SHIFT_ENB (1 << 2) ++#define I2S_TX_SHIFT_ENB (1 << 1) ++#else ++#define I2S_RX_SHIFT_ENB (1 << 1) ++#define I2S_TX_SHIFT_ENB (1 << 0) ++#endif ++ ++#define I2S_2CHANNELS_ENB 0x00 ++#define I2S_4CHANNELS_ENB 0x01 ++#define I2S_6CHANNELS_ENB 0x02 ++ ++#define I2S_FIFO_THRESHOLD_INTRPT 0x08 ++#define I2S_FIFO_FULL_INTRPT 0x02 ++#define I2S_FIFO_EMPTY_INTRPT 0x01 ++ ++/* I2S_24BITMUX_MODE_REG */ ++#define I2S_24BITMUX_MODE_BIT (1 << 3) ++#if (I2S_24BITMUX_MODE_REG_BITS == 4) ++#define I2S_24BITMUX_MODE_FDMA_BURST_DIS 0x2 ++#define I2S_24BITMUX_MODE_RST_CHAN0 0x4 ++#define I2S_24BITMUX_MODE_DMA_BOOTSEL 0x8 ++#endif ++ ++#endif /* __HAL_I2S_H__ */ +diff --git a/arch/arm/mach-gk710x/include/mach/idc.h b/arch/arm/mach-gk710x/include/mach/idc.h +new file mode 100644 +index 00000000..4d460e70 +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/idc.h +@@ -0,0 +1,165 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk/include/mach/idc.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++#ifndef __MACH_IDC_H__ ++#define __MACH_IDC_H__ ++ ++#include ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++ ++#define IDC_INSTANCES 2 ++#define IDCS_INSTANCES 0 ++ ++#define IDC_INTERNAL_DELAY_CLK 2 ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++#define IDC_PSLL_OFFSET 0x00 ++#define IDC_PSLH_OFFSET 0x04 ++#define IDC_FMCTRL_OFFSET 0x08 ++#define IDC_CTRL_OFFSET 0x0c ++#define IDC_STS_OFFSET 0x10 ++#define IDC_ENR_OFFSET 0x14 ++#define IDC_DATA_OFFSET 0x18 ++#define IDC_FMDATA_OFFSET 0x1c ++ ++#if (IDCS_INSTANCES >= 1) ++#define IDCS_ENR_OFFSET 0x00 ++#define IDCS_CTRL_OFFSET 0x04 ++#define IDCS_DATA_OFFSET 0x08 ++#define IDCS_STS_OFFSET 0x0c ++#define IDCS_FIFO_CNT_OFFSET 0x10 ++#define IDCS_RX_CNT_OFFSET 0x14 ++#define IDCS_TX_CNT_OFFSET 0x18 ++#define IDCS_HOLD_TIME_OFFSET 0x1c ++#define IDCS_SLAVE_ADDR_OFFSET 0x20 ++#define IDCS_SCL_TIMER_OFFSET 0x24 ++#define IDCS_TIMEOUT_STS_OFFSET 0x28 ++#endif ++ ++#define IDC_REG(x) (GK_PA_IDC + (x)) ++ ++#define IDC_ENR_REG IDC_REG(IDC_ENR_OFFSET) ++#define IDC_CTRL_REG IDC_REG(IDC_CTRL_OFFSET) ++#define IDC_DATA_REG IDC_REG(IDC_DATA_OFFSET) ++#define IDC_STS_REG IDC_REG(IDC_STS_OFFSET) ++#define IDC_PSLL_REG IDC_REG(IDC_PSLL_OFFSET) ++#define IDC_PSLH_REG IDC_REG(IDC_PSLH_OFFSET) ++#define IDC_FMCTRL_REG IDC_REG(IDC_FMCTRL_OFFSET) ++#define IDC_FMDATA_REG IDC_REG(IDC_FMDATA_OFFSET) ++ ++#if (IDC_INSTANCES >= 2) ++ ++#define IDC2_REG(x) (GK_PA_IDC2 + (x)) ++ ++#define IDC2_ENR_REG IDC2_REG(IDC_ENR_OFFSET) ++#define IDC2_CTRL_REG IDC2_REG(IDC_CTRL_OFFSET) ++#define IDC2_DATA_REG IDC2_REG(IDC_DATA_OFFSET) ++#define IDC2_STS_REG IDC2_REG(IDC_STS_OFFSET) ++#define IDC2_PSLL_REG IDC2_REG(IDC_PSLL_OFFSET) ++#define IDC2_PSLH_REG IDC2_REG(IDC_PSLH_OFFSET) ++#define IDC2_FMCTRL_REG IDC2_REG(IDC_FMCTRL_OFFSET) ++#define IDC2_FMDATA_REG IDC2_REG(IDC_FMDATA_OFFSET) ++#endif ++ ++#if (IDCS_INSTANCES >= 1) ++#define IDCS_ENR_REG IDCS_REG(IDCS_ENR_OFFSET) ++#define IDCS_CTRL_REG IDCS_REG(IDCS_CTRL_OFFSET) ++#define IDCS_DATA_REG IDCS_REG(IDCS_DATA_OFFSET) ++#define IDCS_STS_REG IDCS_REG(IDCS_STS_OFFSET) ++#define IDCS_FIFO_CNT_REG IDCS_REG(IDCS_FIFO_CNT_OFFSET) ++#define IDCS_RX_CNT_REG IDCS_REG(IDCS_RX_CNT_OFFSET) ++#define IDCS_TX_CNT_REG IDCS_REG(IDCS_TX_CNT_OFFSET) ++#define IDCS_HOLD_TIME_REG IDCS_REG(IDCS_HOLD_TIME_OFFSET) ++#define IDCS_SLAVE_ADDR_REG IDCS_REG(IDCS_SLAVE_ADDR_OFFSET) ++#define IDCS_SCL_TIMER_REG IDCS_REG(IDCS_SCL_TIMER_OFFSET) ++#define IDCS_TIMEOUT_STS_REG IDCS_REG(IDCS_TIMEOUT_STS_OFFSET) ++ ++ ++/* Bit/format definition */ ++ ++/* IDCS_CTRL_REG */ ++#define IDCS_IRQ_EN 0x02 ++#define IDCS_IRQ_P_SR_EN 0x04 ++#define IDCS_IRQ_FIFO_TH_EN 0x08 ++#define IDCS_IRQ_TIME_OUT_EN 0x10 ++ ++/* IDCS_STS_REG */ ++#define IDCS_TIMEOUT 0x100 ++#define IDCS_STOP 0x080 ++#define IDCS_REPEATED_START 0x040 ++#define IDCS_FIFO_TH_VLD 0x020 ++#define IDCS_SEL 0x010 ++#define IDCS_GENERAL_CALL 0x008 ++#define IDCS_FIFO_FULL 0x004 ++#define IDCS_FIFO_EMPTY 0x002 ++#define IDCS_RX_TX_STATE 0x001 ++ ++#define IDCS_TX_MODE 0x0 ++#define IDCS_RX_MODE 0x1 ++ ++#endif ++ ++/* ==========================================================================*/ ++/* IDC_ENABLE_REG */ ++#define IDC_ENR_ENABLE (0x01)//bit0 ++#define IDC_ENR_DISABLE (0x00) ++ ++/* IDC_CTRL_REG */ ++#define IDC_CTRL_IF (0x08)//bit3 ++#define IDC_CTRL_ACK (0x04)//bit2 ++#define IDC_CTRL_START (0x02)//bit1 ++#define IDC_CTRL_STOP (0x01)//bit0 ++#define IDC_CTRL_CLS (0x00) ++ ++#define IDC_FIFO_BUF_SIZE (63) ++ ++/* IDC_STS_REG */ ++#define IDC_STS_MODE (0x01)//1:master receiver; 0:master transmitter ++ ++/* IDC_FM_CTRL_REG */ ++ ++#define IDC_FMCTRL_IF (0x10)//bit4 ++#define IDC_FMCTRL_START (0x02)//bit1 ++#define IDC_FMCTRL_STOP (0x01)//bit0 ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++struct gk_platform_i2c { ++ int clk_limit; //Hz ++ int bulk_write_num; ++ unsigned int i2c_class; ++ u32 (*get_clock)(void); ++}; ++#define IDC_PARAM_CALL(id, arg, perm) \ ++ module_param_cb(idc##id##_clk_limit, ¶m_ops_int, &(arg.clk_limit), perm); \ ++ module_param_cb(idc##id##_bulk_write_num, ¶m_ops_int, &(arg.bulk_write_num), perm) ++ ++/* ==========================================================================*/ ++extern struct platform_device gk_idc; ++extern struct platform_device gk_idc_hdmi; ++//extern struct platform_device gk_i2cmux; ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif /* __MACH_IDC_H__ */ ++ +diff --git a/arch/arm/mach-gk710x/include/mach/io.h b/arch/arm/mach-gk710x/include/mach/io.h +new file mode 100644 +index 00000000..74fb7c4c +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/io.h +@@ -0,0 +1,506 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/mach/io.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_IO_H ++#define __MACH_IO_H ++ ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++ ++#ifndef __ASSEMBLER__ ++ ++#include ++ ++extern spinlock_t gk_reg_lock; ++extern unsigned long gk_reg_flags; ++extern u32 gk_reglock_count; ++ ++extern struct hw_ops *g_hw; ++#define gk_hal_readb(a) g_hw->hw_readb((u32)(a)) ++#define gk_hal_readw(a) g_hw->hw_readw((u32)(a)) ++#define gk_hal_writeb(a,v) g_hw->hw_writeb((v),(u32)(a)) ++#define gk_hal_writew(a,v) g_hw->hw_writew((v),(u32)(a)) ++#define gk_hal_readl(a) g_hw->hw_readl((u32)(a)) ++#define gk_hal_writel(a,v) g_hw->hw_writel((v),(u32)(a)) ++#define gk_flash_read() g_hw->flash_read() ++#define gk_flash_write(v) g_hw->flash_write((v)) ++#if 0 ++#define GK_REG_LOCK() spin_lock_irqsave(&gk_reg_lock, gk_reg_flags) ++#define GK_REG_UNLOCK() spin_unlock_irqrestore(&gk_reg_lock, gk_reg_flags) ++#define GK_INC_REGLOCK_COUNT() gk_reglock_count++ ++#else ++#define GK_REG_LOCK() ++#define GK_REG_UNLOCK() ++#define GK_INC_REGLOCK_COUNT() ++#endif ++ ++#define HAL_IO(mod) \ ++unsigned char gk_##mod##_readb(unsigned int addr) \ ++{\ ++ return g_hw->hw_readb((u32)(addr));\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_readb);\ ++unsigned short gk_##mod##_readw(unsigned int addr) \ ++{\ ++ return g_hw->hw_readw((u32)(addr));\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_readw);\ ++unsigned int gk_##mod##_readl(unsigned int addr) \ ++{\ ++ return g_hw->hw_readl((u32)(addr)); \ ++}\ ++EXPORT_SYMBOL(gk_##mod##_readl);\ ++void gk_##mod##_writeb(unsigned int addr,unsigned char val) \ ++{\ ++ g_hw->hw_writeb((val),(u32)(addr)); \ ++}\ ++EXPORT_SYMBOL(gk_##mod##_writeb); \ ++void gk_##mod##_writew(unsigned int addr,unsigned short val) \ ++{\ ++ g_hw->hw_writew((val),(u32)(addr)); \ ++}\ ++EXPORT_SYMBOL(gk_##mod##_writew); \ ++void gk_##mod##_writel(unsigned int addr,unsigned int val) \ ++{\ ++ g_hw->hw_writel((val),(u32)(addr));\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_writel); ++#define DIR_IO(mod) \ ++unsigned char gk_##mod##_readb(unsigned int addr) \ ++{\ ++ return *((volatile unsigned char*)(addr));\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_readb);\ ++unsigned short gk_##mod##_readw(unsigned int addr)\ ++{\ ++ return *((volatile unsigned short*)(addr));\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_readw);\ ++unsigned int gk_##mod##_readl(unsigned int addr)\ ++{\ ++ return *((volatile unsigned int*)(addr));\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_readl);\ ++void gk_##mod##_writeb(unsigned int addr,unsigned char val)\ ++{\ ++ *((volatile unsigned char*)(addr))= val;\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_writeb);\ ++void gk_##mod##_writew(unsigned int addr,unsigned short val)\ ++{\ ++ *((volatile unsigned short*)(addr))= val;\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_writew);\ ++void gk_##mod##_writel(unsigned int addr,unsigned int val)\ ++{\ ++ *((volatile unsigned int*)(addr))= val;\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_writel); ++ ++ ++#define IO_DEC(mod) \ ++extern unsigned char gk_##mod##_readb(unsigned int addr); \ ++extern unsigned short gk_##mod##_readw(unsigned int addr); \ ++extern unsigned int gk_##mod##_readl(unsigned int addr); \ ++extern void gk_##mod##_writeb(unsigned int addr,unsigned char val); \ ++extern void gk_##mod##_writew(unsigned int addr,unsigned short val); \ ++extern void gk_##mod##_writel(unsigned int addr,unsigned int val); ++ ++IO_DEC(hw) ++IO_DEC(adc) ++IO_DEC(aud) ++IO_DEC(cry) ++IO_DEC(ddr) ++IO_DEC(dma) ++IO_DEC(dsp) ++IO_DEC(eth) ++IO_DEC(greg) ++IO_DEC(gpio) ++IO_DEC(i2c) ++IO_DEC(i2s) ++IO_DEC(ir) ++IO_DEC(irq) ++IO_DEC(mcu) ++IO_DEC(pmu) ++IO_DEC(rct) ++IO_DEC(sd) ++IO_DEC(sf) ++IO_DEC(ssi) ++IO_DEC(timer) ++IO_DEC(uart) ++IO_DEC(usb) ++IO_DEC(vout) ++IO_DEC(wdt) ++IO_DEC(pwm) ++IO_DEC(efuse) ++ ++#define GK_HAL_OS_LOCK() \ ++ do { \ ++ GK_REG_LOCK(); \ ++ GK_INC_REGLOCK_COUNT(); \ ++ } while(0) ++ ++ ++#define GK_HAL_OS_UNLOCK() \ ++ do { \ ++ GK_REG_UNLOCK(); \ ++ } while(0) ++ ++//-------------------------------------- ++static inline u8 __gk_readb(const volatile void __iomem *address) ++{ ++ u8 tmpval; ++ ++ GK_REG_LOCK(); ++ GK_INC_REGLOCK_COUNT(); ++ tmpval = gk_hw_readb((u32)address); ++ GK_REG_UNLOCK(); ++ ++ return tmpval; ++} ++ ++static inline void __gk_writeb(const volatile void __iomem *address, u8 value) ++{ ++ GK_REG_LOCK(); ++ GK_INC_REGLOCK_COUNT(); ++ gk_hw_writeb((u32)address,value); ++ GK_REG_UNLOCK(); ++} ++ ++static inline u16 __gk_readw(const volatile void __iomem *address) ++{ ++ u16 tmpval; ++ ++ GK_REG_LOCK(); ++ GK_INC_REGLOCK_COUNT(); ++ tmpval = gk_hw_readw((u32)address); ++ GK_REG_UNLOCK(); ++ ++ return tmpval; ++} ++ ++static inline void __gk_writew(const volatile void __iomem *address, u16 value) ++{ ++ GK_REG_LOCK(); ++ GK_INC_REGLOCK_COUNT(); ++ gk_hw_writew((u32)address,value); ++ GK_REG_UNLOCK(); ++} ++ ++static inline u32 __gk_readl(const volatile void __iomem *address) ++{ ++ u32 tmpval; ++ ++ GK_REG_LOCK(); ++ GK_INC_REGLOCK_COUNT(); ++ tmpval = gk_hw_readl((u32)address); ++ GK_REG_UNLOCK(); ++ ++ return tmpval; ++} ++ ++static inline void __gk_writel(const volatile void __iomem *address, u32 value) ++{ ++ GK_REG_LOCK(); ++ GK_INC_REGLOCK_COUNT(); ++ gk_hw_writel((u32)address,value); ++ GK_REG_UNLOCK(); ++} ++ ++ ++ ++#if USB_DMA_ADD_MODE ++extern unsigned char (*gk_musb_readb)(unsigned int ptr, unsigned int offset); ++extern unsigned short (*gk_musb_readw)(unsigned int ptr, unsigned int offset); ++extern unsigned int (*gk_musb_readl)(unsigned int ptr, unsigned int offset); ++extern void (*gk_musb_writeb)(unsigned int ptr, unsigned int offset, unsigned char value); ++extern void (*gk_musb_writew)(unsigned int ptr, unsigned int offset, unsigned short value); ++extern void (*gk_musb_writel)(unsigned int ptr, unsigned int offset, unsigned int value); ++ ++#else ++#define gk_musb_readb(a, o) (*((volatile unsigned char*)(a+o))) ++#define gk_musb_readw(a, o) (*((volatile unsigned short*)(a+o))) ++#define gk_musb_readl(a, o) (*((volatile unsigned int*)(a+o))) ++#define gk_musb_writeb(a, o, v) ((*((volatile unsigned char*)(a+o))) = v) ++#define gk_musb_writew(a, o, v) ((*((volatile unsigned short*)(a+o))) = v) ++#define gk_musb_writel(a, o, v) ((*((volatile unsigned int*)(a+o))) = v) ++ ++#endif ++ ++#if SPI_API_MODE ++extern unsigned char (*gk_spi_readb)(unsigned int ptr); ++extern unsigned short (*gk_spi_readw)(unsigned int ptr); ++extern unsigned int (*gk_spi_readl)(unsigned int ptr); ++extern void (*gk_spi_writeb)(unsigned int ptr, unsigned char value); ++extern void (*gk_spi_writew)(unsigned int ptr, unsigned short value); ++extern void (*gk_spi_writel)(unsigned int ptr, unsigned int value); ++#else ++#define gk_spi_readb(a) gk_hal_readb(a) ++#define gk_spi_readw(a) gk_hal_readw(a) ++#define gk_spi_readl(a) gk_hal_readl(a) ++#define gk_spi_writeb(a, v) gk_hal_writeb((a), v) ++#define gk_spi_writew(a, v) gk_hal_writew((a), v) ++#define gk_spi_writel(a, v) gk_hal_writel((a), v) ++#endif ++ ++ ++#define gk_adc_setbitsb(v, mask) gk_adc_writeb((v),(gk_adc_readb((v)) | (mask))) ++#define gk_adc_setbitsw(v, mask) gk_adc_writew((v),(gk_adc_readw((v)) | (mask))) ++#define gk_adc_setbitsl(v, mask) gk_adc_writel((v),(gk_adc_readl((v)) | (mask))) ++#define gk_adc_clrbitsb(v, mask) gk_adc_writeb((v),(gk_adc_readb((v)) & ~(mask))) ++#define gk_adc_clrbitsw(v, mask) gk_adc_writew((v),(gk_adc_readw((v)) & ~(mask))) ++#define gk_adc_clrbitsl(v, mask) gk_adc_writel((v),(gk_adc_readl((v)) & ~(mask))) ++#define gk_adc_tstbitsb(v, mask) (gk_adc_readb((v)) & (mask)) ++#define gk_adc_tstbitsw(v, mask) (gk_adc_readw((v)) & (mask)) ++#define gk_adc_tstbitsl(v, mask) (gk_adc_readl((v)) & (mask)) ++ ++ ++ ++#define gk_aud_setbitsb(v, mask) gk_aud_writeb((v),(gk_aud_readb((v)) | (mask))) ++#define gk_aud_setbitsw(v, mask) gk_aud_writew((v),(gk_aud_readw((v)) | (mask))) ++#define gk_aud_setbitsl(v, mask) gk_aud_writel((v),(gk_aud_readl((v)) | (mask))) ++#define gk_aud_clrbitsb(v, mask) gk_aud_writeb((v),(gk_aud_readb((v)) & ~(mask))) ++#define gk_aud_clrbitsw(v, mask) gk_aud_writew((v),(gk_aud_readw((v)) & ~(mask))) ++#define gk_aud_clrbitsl(v, mask) gk_aud_writel((v),(gk_aud_readl((v)) & ~(mask))) ++#define gk_aud_tstbitsb(v, mask) (gk_aud_readb((v)) & (mask)) ++#define gk_aud_tstbitsw(v, mask) (gk_aud_readw((v)) & (mask)) ++#define gk_aud_tstbitsl(v, mask) (gk_aud_readl((v)) & (mask)) ++ ++ ++ ++ ++#define gk_cry_setbitsb(v, mask) gk_cry_writeb((v),(gk_cry_readb((v)) | (mask))) ++#define gk_cry_setbitsw(v, mask) gk_cry_writew((v),(gk_cry_readw((v)) | (mask))) ++#define gk_cry_setbitsl(v, mask) gk_cry_writel((v),(gk_cry_readl((v)) | (mask))) ++#define gk_cry_clrbitsb(v, mask) gk_cry_writeb((v),(gk_cry_readb((v)) & ~(mask))) ++#define gk_cry_clrbitsw(v, mask) gk_cry_writew((v),(gk_cry_readw((v)) & ~(mask))) ++#define gk_cry_clrbitsl(v, mask) gk_cry_writel((v),(gk_cry_readl((v)) & ~(mask))) ++#define gk_cry_tstbitsb(v, mask) (gk_cry_readb((v)) & (mask)) ++#define gk_cry_tstbitsw(v, mask) (gk_cry_readw((v)) & (mask)) ++#define gk_cry_tstbitsl(v, mask) (gk_cry_readl((v)) & (mask)) ++ ++ ++#define gk_ddr_setbitsb(v, mask) gk_ddr_writeb((v),(gk_ddr_readb((v)) | (mask))) ++#define gk_ddr_setbitsw(v, mask) gk_ddr_writew((v),(gk_ddr_readw((v)) | (mask))) ++#define gk_ddr_setbitsl(v, mask) gk_ddr_writel((v),(gk_ddr_readl((v)) | (mask))) ++#define gk_ddr_clrbitsb(v, mask) gk_ddr_writeb((v),(gk_ddr_readb((v)) & ~(mask))) ++#define gk_ddr_clrbitsw(v, mask) gk_ddr_writew((v),(gk_ddr_readw((v)) & ~(mask))) ++#define gk_ddr_clrbitsl(v, mask) gk_ddr_writel((v),(gk_ddr_readl((v)) & ~(mask))) ++#define gk_ddr_tstbitsb(v, mask) (gk_ddr_readb((v)) & (mask)) ++#define gk_ddr_tstbitsw(v, mask) (gk_ddr_readw((v)) & (mask)) ++#define gk_ddr_tstbitsl(v, mask) (gk_ddr_readl((v)) & (mask)) ++ ++ ++ ++#define gk_dsp_setbitsb(v, mask) gk_dsp_writeb((v),(gk_dsp_readb((v)) | (mask))) ++#define gk_dsp_setbitsw(v, mask) gk_dsp_writew((v),(gk_dsp_readw((v)) | (mask))) ++#define gk_dsp_setbitsl(v, mask) gk_dsp_writel((v),(gk_dsp_readl((v)) | (mask))) ++#define gk_dsp_clrbitsb(v, mask) gk_dsp_writeb((v),(gk_dsp_readb((v)) & ~(mask))) ++#define gk_dsp_clrbitsw(v, mask) gk_dsp_writew((v),(gk_dsp_readw((v)) & ~(mask))) ++#define gk_dsp_clrbitsl(v, mask) gk_dsp_writel((v),(gk_dsp_readl((v)) & ~(mask))) ++#define gk_dsp_tstbitsb(v, mask) (gk_dsp_readb((v)) & (mask)) ++#define gk_dsp_tstbitsw(v, mask) (gk_dsp_readw((v)) & (mask)) ++#define gk_dsp_tstbitsl(v, mask) (gk_dsp_readl((v)) & (mask)) ++ ++ ++#define gk_eth_setbitsb(v, mask) gk_eth_writeb((v),(gk_eth_readb((v)) | (mask))) ++#define gk_eth_setbitsw(v, mask) gk_eth_writew((v),(gk_eth_readw((v)) | (mask))) ++#define gk_eth_setbitsl(v, mask) gk_eth_writel((v),(gk_eth_readl((v)) | (mask))) ++#define gk_eth_clrbitsb(v, mask) gk_eth_writeb((v),(gk_eth_readb((v)) & ~(mask))) ++#define gk_eth_clrbitsw(v, mask) gk_eth_writew((v),(gk_eth_readw((v)) & ~(mask))) ++#define gk_eth_clrbitsl(v, mask) gk_eth_writel((v),(gk_eth_readl((v)) & ~(mask))) ++#define gk_eth_tstbitsb(v, mask) (gk_eth_readb((v)) & (mask)) ++#define gk_eth_tstbitsw(v, mask) (gk_eth_readw((v)) & (mask)) ++#define gk_eth_tstbitsl(v, mask) (gk_eth_readl((v)) & (mask)) ++ ++ ++#define gk_greg_setbitsb(v, mask) gk_greg_writeb((v),(gk_greg_readb((v)) | (mask))) ++#define gk_greg_setbitsw(v, mask) gk_greg_writew((v),(gk_greg_readw((v)) | (mask))) ++#define gk_greg_setbitsl(v, mask) gk_greg_writel((v),(gk_greg_readl((v)) | (mask))) ++#define gk_greg_clrbitsb(v, mask) gk_greg_writeb((v),(gk_greg_readb((v)) & ~(mask))) ++#define gk_greg_clrbitsw(v, mask) gk_greg_writew((v),(gk_greg_readw((v)) & ~(mask))) ++#define gk_greg_clrbitsl(v, mask) gk_greg_writel((v),(gk_greg_readl((v)) & ~(mask))) ++#define gk_greg_tstbitsb(v, mask) (gk_greg_readb((v)) & (mask)) ++#define gk_greg_tstbitsw(v, mask) (gk_greg_readw((v)) & (mask)) ++#define gk_greg_tstbitsl(v, mask) (gk_greg_readl((v)) & (mask)) ++ ++#define gk_gpio_setbitsb(v, mask) gk_gpio_writeb((v),(gk_gpio_readb((v)) | (mask))) ++#define gk_gpio_setbitsw(v, mask) gk_gpio_writew((v),(gk_gpio_readw((v)) | (mask))) ++#define gk_gpio_setbitsl(v, mask) gk_gpio_writel((v),(gk_gpio_readl((v)) | (mask))) ++#define gk_gpio_clrbitsb(v, mask) gk_gpio_writeb((v),(gk_gpio_readb((v)) & ~(mask))) ++#define gk_gpio_clrbitsw(v, mask) gk_gpio_writew((v),(gk_gpio_readw((v)) & ~(mask))) ++#define gk_gpio_clrbitsl(v, mask) gk_gpio_writel((v),(gk_gpio_readl((v)) & ~(mask))) ++#define gk_gpio_tstbitsb(v, mask) (gk_gpio_readb((v)) & (mask)) ++#define gk_gpio_tstbitsw(v, mask) (gk_gpio_readw((v)) & (mask)) ++#define gk_gpio_tstbitsl(v, mask) (gk_gpio_readl((v)) & (mask)) ++ ++#define gk_i2c_setbitsb(v, mask) gk_i2c_writeb((v),(gk_i2c_readb((v)) | (mask))) ++#define gk_i2c_setbitsw(v, mask) gk_i2c_writew((v),(gk_i2c_readw((v)) | (mask))) ++#define gk_i2c_setbitsl(v, mask) gk_i2c_writel((v),(gk_i2c_readl((v)) | (mask))) ++#define gk_i2c_clrbitsb(v, mask) gk_i2c_writeb((v),(gk_i2c_readb((v)) & ~(mask))) ++#define gk_i2c_clrbitsw(v, mask) gk_i2c_writew((v),(gk_i2c_readw((v)) & ~(mask))) ++#define gk_i2c_clrbitsl(v, mask) gk_i2c_writel((v),(gk_i2c_readl((v)) & ~(mask))) ++#define gk_i2c_tstbitsb(v, mask) (gk_i2c_readb((v)) & (mask)) ++#define gk_i2c_tstbitsw(v, mask) (gk_i2c_readw((v)) & (mask)) ++#define gk_i2c_tstbitsl(v, mask) (gk_i2c_readl((v)) & (mask)) ++ ++ ++#define gk_i2s_setbitsb(v, mask) gk_i2s_writeb((v),(gk_i2s_readb((v)) | (mask))) ++#define gk_i2s_setbitsw(v, mask) gk_i2s_writew((v),(gk_i2s_readw((v)) | (mask))) ++#define gk_i2s_setbitsl(v, mask) gk_i2s_writel((v),(gk_i2s_readl((v)) | (mask))) ++#define gk_i2s_clrbitsb(v, mask) gk_i2s_writeb((v),(gk_i2s_readb((v)) & ~(mask))) ++#define gk_i2s_clrbitsw(v, mask) gk_i2s_writew((v),(gk_i2s_readw((v)) & ~(mask))) ++#define gk_i2s_clrbitsl(v, mask) gk_i2s_writel((v),(gk_i2s_readl((v)) & ~(mask))) ++#define gk_i2s_tstbitsb(v, mask) (gk_i2s_readb((v)) & (mask)) ++#define gk_i2s_tstbitsw(v, mask) (gk_i2s_readw((v)) & (mask)) ++#define gk_i2s_tstbitsl(v, mask) (gk_i2s_readl((v)) & (mask)) ++ ++#define gk_ir_setbitsb(v, mask) gk_ir_writeb((v),(gk_ir_readb((v)) | (mask))) ++#define gk_ir_setbitsw(v, mask) gk_ir_writew((v),(gk_ir_readw((v)) | (mask))) ++#define gk_ir_setbitsl(v, mask) gk_ir_writel((v),(gk_ir_readl((v)) | (mask))) ++#define gk_ir_clrbitsb(v, mask) gk_ir_writeb((v),(gk_ir_readb((v)) & ~(mask))) ++#define gk_ir_clrbitsw(v, mask) gk_ir_writew((v),(gk_ir_readw((v)) & ~(mask))) ++#define gk_ir_clrbitsl(v, mask) gk_ir_writel((v),(gk_ir_readl((v)) & ~(mask))) ++#define gk_ir_tstbitsb(v, mask) (gk_ir_readb((v)) & (mask)) ++#define gk_ir_tstbitsw(v, mask) (gk_ir_readw((v)) & (mask)) ++#define gk_ir_tstbitsl(v, mask) (gk_ir_readl((v)) & (mask)) ++ ++#define gk_irq_setbitsb(v, mask) gk_irq_writeb((v),(gk_irq_readb((v)) | (mask))) ++#define gk_irq_setbitsw(v, mask) gk_irq_writew((v),(gk_irq_readw((v)) | (mask))) ++#define gk_irq_setbitsl(v, mask) gk_irq_writel((v),(gk_irq_readl((v)) | (mask))) ++#define gk_irq_clrbitsb(v, mask) gk_irq_writeb((v),(gk_irq_readb((v)) & ~(mask))) ++#define gk_irq_clrbitsw(v, mask) gk_irq_writew((v),(gk_irq_readw((v)) & ~(mask))) ++#define gk_irq_clrbitsl(v, mask) gk_irq_writel((v),(gk_irq_readl((v)) & ~(mask))) ++#define gk_irq_tstbitsb(v, mask) (gk_irq_readb((v)) & (mask)) ++#define gk_irq_tstbitsw(v, mask) (gk_irq_readw((v)) & (mask)) ++#define gk_irq_tstbitsl(v, mask) (gk_irq_readl((v)) & (mask)) ++ ++#define gk_mcu_setbitsb(v, mask) gk_mcu_writeb((v),(gk_mcu_readb((v)) | (mask))) ++#define gk_mcu_setbitsw(v, mask) gk_mcu_writew((v),(gk_mcu_readw((v)) | (mask))) ++#define gk_mcu_setbitsl(v, mask) gk_mcu_writel((v),(gk_mcu_readl((v)) | (mask))) ++#define gk_mcu_clrbitsb(v, mask) gk_mcu_writeb((v),(gk_mcu_readb((v)) & ~(mask))) ++#define gk_mcu_clrbitsw(v, mask) gk_mcu_writew((v),(gk_mcu_readw((v)) & ~(mask))) ++#define gk_mcu_clrbitsl(v, mask) gk_mcu_writel((v),(gk_mcu_readl((v)) & ~(mask))) ++#define gk_mcu_tstbitsb(v, mask) (gk_mcu_readb((v)) & (mask)) ++#define gk_mcu_tstbitsw(v, mask) (gk_mcu_readw((v)) & (mask)) ++#define gk_mcu_tstbitsl(v, mask) (gk_mcu_readl((v)) & (mask)) ++ ++#define gk_pwm_setbitsb(v, mask) gk_pwm_writeb((v),(gk_pwm_readb((v)) | (mask))) ++#define gk_pwm_setbitsw(v, mask) gk_pwm_writew((v),(gk_pwm_readw((v)) | (mask))) ++#define gk_pwm_setbitsl(v, mask) gk_pwm_writel((v),(gk_pwm_readl((v)) | (mask))) ++#define gk_pwm_clrbitsb(v, mask) gk_pwm_writeb((v),(gk_pwm_readb((v)) & ~(mask))) ++#define gk_pwm_clrbitsw(v, mask) gk_pwm_writew((v),(gk_pwm_readw((v)) & ~(mask))) ++#define gk_pwm_clrbitsl(v, mask) gk_pwm_writel((v),(gk_pwm_readl((v)) & ~(mask))) ++#define gk_pwm_tstbitsb(v, mask) (gk_pwm_readb((v)) & (mask)) ++#define gk_pwm_tstbitsw(v, mask) (gk_pwm_readw((v)) & (mask)) ++#define gk_pwm_tstbitsl(v, mask) (gk_pwm_readl((v)) & (mask)) ++ ++#define gk_rct_setbitsb(v, mask) gk_rct_writeb((v),(gk_rct_readb((v)) | (mask))) ++#define gk_rct_setbitsw(v, mask) gk_rct_writew((v),(gk_rct_readw((v)) | (mask))) ++#define gk_rct_setbitsl(v, mask) gk_rct_writel((v),(gk_rct_readl((v)) | (mask))) ++#define gk_rct_clrbitsb(v, mask) gk_rct_writeb((v),(gk_rct_readb((v)) & ~(mask))) ++#define gk_rct_clrbitsw(v, mask) gk_rct_writew((v),(gk_rct_readw((v)) & ~(mask))) ++#define gk_rct_clrbitsl(v, mask) gk_rct_writel((v),(gk_rct_readl((v)) & ~(mask))) ++#define gk_rct_tstbitsb(v, mask) (gk_rct_readb((v)) & (mask)) ++#define gk_rct_tstbitsw(v, mask) (gk_rct_readw((v)) & (mask)) ++#define gk_rct_tstbitsl(v, mask) (gk_rct_readl((v)) & (mask)) ++ ++#define gk_sd_setbitsb(v, mask) gk_sd_writeb((v),(gk_sd_readb((v)) | (mask))) ++#define gk_sd_setbitsw(v, mask) gk_sd_writew((v),(gk_sd_readw((v)) | (mask))) ++#define gk_sd_setbitsl(v, mask) gk_sd_writel((v),(gk_sd_readl((v)) | (mask))) ++#define gk_sd_clrbitsb(v, mask) gk_sd_writeb((v),(gk_sd_readb((v)) & ~(mask))) ++#define gk_sd_clrbitsw(v, mask) gk_sd_writew((v),(gk_sd_readw((v)) & ~(mask))) ++#define gk_sd_clrbitsl(v, mask) gk_sd_writel((v),(gk_sd_readl((v)) & ~(mask))) ++#define gk_sd_tstbitsb(v, mask) (gk_sd_readb((v)) & (mask)) ++#define gk_sd_tstbitsw(v, mask) (gk_sd_readw((v)) & (mask)) ++#define gk_sd_tstbitsl(v, mask) (gk_sd_readl((v)) & (mask)) ++ ++#define gk_sf_setbitsb(v, mask) gk_sf_writeb((v),(gk_sf_readb((v)) | (mask))) ++#define gk_sf_setbitsw(v, mask) gk_sf_writew((v),(gk_sf_readw((v)) | (mask))) ++#define gk_sf_setbitsl(v, mask) gk_sf_writel((v),(gk_sf_readl((v)) | (mask))) ++#define gk_sf_clrbitsb(v, mask) gk_sf_writeb((v),(gk_sf_readb((v)) & ~(mask))) ++#define gk_sf_clrbitsw(v, mask) gk_sf_writew((v),(gk_sf_readw((v)) & ~(mask))) ++#define gk_sf_clrbitsl(v, mask) gk_sf_writel((v),(gk_sf_readl((v)) & ~(mask))) ++#define gk_sf_tstbitsb(v, mask) (gk_sf_readb((v)) & (mask)) ++#define gk_sf_tstbitsw(v, mask) (gk_sf_readw((v)) & (mask)) ++#define gk_sf_tstbitsl(v, mask) (gk_sf_readl((v)) & (mask)) ++ ++#define gk_ssi_setbitsb(v, mask) gk_ssi_writeb((v),(gk_ssi_readb((v)) | (mask))) ++#define gk_ssi_setbitsw(v, mask) gk_ssi_writew((v),(gk_ssi_readw((v)) | (mask))) ++#define gk_ssi_setbitsl(v, mask) gk_ssi_writel((v),(gk_ssi_readl((v)) | (mask))) ++#define gk_ssi_clrbitsb(v, mask) gk_ssi_writeb((v),(gk_ssi_readb((v)) & ~(mask))) ++#define gk_ssi_clrbitsw(v, mask) gk_ssi_writew((v),(gk_ssi_readw((v)) & ~(mask))) ++#define gk_ssi_clrbitsl(v, mask) gk_ssi_writel((v),(gk_ssi_readl((v)) & ~(mask))) ++#define gk_ssi_tstbitsb(v, mask) (gk_ssi_readb((v)) & (mask)) ++#define gk_ssi_tstbitsw(v, mask) (gk_ssi_readw((v)) & (mask)) ++#define gk_ssi_tstbitsl(v, mask) (gk_ssi_readl((v)) & (mask)) ++ ++#define gk_timer_setbitsb(v, mask) gk_timer_writeb((v),(gk_timer_readb((v)) | (mask))) ++#define gk_timer_setbitsw(v, mask) gk_timer_writew((v),(gk_timer_readw((v)) | (mask))) ++#define gk_timer_setbitsl(v, mask) gk_timer_writel((v),(gk_timer_readl((v)) | (mask))) ++#define gk_timer_clrbitsb(v, mask) gk_timer_writeb((v),(gk_timer_readb((v)) & ~(mask))) ++#define gk_timer_clrbitsw(v, mask) gk_timer_writew((v),(gk_timer_readw((v)) & ~(mask))) ++#define gk_timer_clrbitsl(v, mask) gk_timer_writel((v),(gk_timer_readl((v)) & ~(mask))) ++#define gk_timer_tstbitsb(v, mask) (gk_timer_readb((v)) & (mask)) ++#define gk_timer_tstbitsw(v, mask) (gk_timer_readw((v)) & (mask)) ++#define gk_timer_tstbitsl(v, mask) (gk_timer_readl((v)) & (mask)) ++ ++#define gk_uart_setbitsb(v, mask) gk_uart_writeb((v),(gk_uart_readb((v)) | (mask))) ++#define gk_uart_setbitsw(v, mask) gk_uart_writew((v),(gk_uart_readw((v)) | (mask))) ++#define gk_uart_setbitsl(v, mask) gk_uart_writel((v),(gk_uart_readl((v)) | (mask))) ++#define gk_uart_clrbitsb(v, mask) gk_uart_writeb((v),(gk_uart_readb((v)) & ~(mask))) ++#define gk_uart_clrbitsw(v, mask) gk_uart_writew((v),(gk_uart_readw((v)) & ~(mask))) ++#define gk_uart_clrbitsl(v, mask) gk_uart_writel((v),(gk_uart_readl((v)) & ~(mask))) ++#define gk_uart_tstbitsb(v, mask) (gk_uart_readb((v)) & (mask)) ++#define gk_uart_tstbitsw(v, mask) (gk_uart_readw((v)) & (mask)) ++#define gk_uart_tstbitsl(v, mask) (gk_uart_readl((v)) & (mask)) ++ ++#define gk_usb_setbitsb(v, mask) gk_usb_writeb((v),(gk_usb_readb((v)) | (mask))) ++#define gk_usb_setbitsw(v, mask) gk_usb_writew((v),(gk_usb_readw((v)) | (mask))) ++#define gk_usb_setbitsl(v, mask) gk_usb_writel((v),(gk_usb_readl((v)) | (mask))) ++#define gk_usb_clrbitsb(v, mask) gk_usb_writeb((v),(gk_usb_readb((v)) & ~(mask))) ++#define gk_usb_clrbitsw(v, mask) gk_usb_writew((v),(gk_usb_readw((v)) & ~(mask))) ++#define gk_usb_clrbitsl(v, mask) gk_usb_writel((v),(gk_usb_readl((v)) & ~(mask))) ++#define gk_usb_tstbitsb(v, mask) (gk_usb_readb((v)) & (mask)) ++#define gk_usb_tstbitsw(v, mask) (gk_usb_readw((v)) & (mask)) ++#define gk_usb_tstbitsl(v, mask) (gk_usb_readl((v)) & (mask)) ++ ++#define gk_vout_setbitsb(v, mask) gk_vout_writeb((v),(gk_vout_readb((v)) | (mask))) ++#define gk_vout_setbitsw(v, mask) gk_vout_writew((v),(gk_vout_readw((v)) | (mask))) ++#define gk_vout_setbitsl(v, mask) gk_vout_writel((v),(gk_vout_readl((v)) | (mask))) ++#define gk_vout_clrbitsb(v, mask) gk_vout_writeb((v),(gk_vout_readb((v)) & ~(mask))) ++#define gk_vout_clrbitsw(v, mask) gk_vout_writew((v),(gk_vout_readw((v)) & ~(mask))) ++#define gk_vout_clrbitsl(v, mask) gk_vout_writel((v),(gk_vout_readl((v)) & ~(mask))) ++#define gk_vout_tstbitsb(v, mask) (gk_vout_readb((v)) & (mask)) ++#define gk_vout_tstbitsw(v, mask) (gk_vout_readw((v)) & (mask)) ++#define gk_vout_tstbitsl(v, mask) (gk_vout_readl((v)) & (mask)) ++ ++#define gk_wdt_setbitsb(v, mask) gk_wdt_writeb((v),(gk_wdt_readb((v)) | (mask))) ++#define gk_wdt_setbitsw(v, mask) gk_wdt_writew((v),(gk_wdt_readw((v)) | (mask))) ++#define gk_wdt_setbitsl(v, mask) gk_wdt_writel((v),(gk_wdt_readl((v)) | (mask))) ++#define gk_wdt_clrbitsb(v, mask) gk_wdt_writeb((v),(gk_wdt_readb((v)) & ~(mask))) ++#define gk_wdt_clrbitsw(v, mask) gk_wdt_writew((v),(gk_wdt_readw((v)) & ~(mask))) ++#define gk_wdt_clrbitsl(v, mask) gk_wdt_writel((v),(gk_wdt_readl((v)) & ~(mask))) ++#define gk_wdt_tstbitsb(v, mask) (gk_wdt_readb((v)) & (mask)) ++#define gk_wdt_tstbitsw(v, mask) (gk_wdt_readw((v)) & (mask)) ++#define gk_wdt_tstbitsl(v, mask) (gk_wdt_readl((v)) & (mask)) ++ ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif /* __MACH_IO_H */ +diff --git a/arch/arm/mach-gk710x/include/mach/ir.h b/arch/arm/mach-gk710x/include/mach/ir.h +new file mode 100644 +index 00000000..2bf5ca2e +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/ir.h +@@ -0,0 +1,50 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk/include/mach/ir.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_IR_H ++#define __MACH_IR_H ++ ++/* ==========================================================================*/ ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++enum gk_ir_protocol { ++ GK_IR_PROTOCOL_NEC = 0, ++ GK_IR_PROTOCOL_PANASONIC = 1, ++ GK_IR_PROTOCOL_SONY = 2, ++ GK_IR_PROTOCOL_PHILIPS = 3, ++ GK_IR_PROTOCOL_END ++}; ++ ++struct gk_ir_controller { ++ ++ int protocol; ++ int debug; ++}; ++#define GK_IR_PARAM_CALL(arg, perm) \ ++ module_param_cb(ir_protocol, ¶m_ops_int, &arg.protocol, perm); \ ++ module_param_cb(ir_debug, ¶m_ops_int, &arg.debug, perm) ++ ++/* ==========================================================================*/ ++extern struct platform_device gk_ir; ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif /* __MACH_IR_H */ ++ +diff --git a/arch/arm/mach-gk710x/include/mach/irqs.h b/arch/arm/mach-gk710x/include/mach/irqs.h +new file mode 100644 +index 00000000..6a01df2f +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/irqs.h +@@ -0,0 +1,198 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/mach/irqs.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_IRQS_H ++#define __MACH_IRQS_H ++ ++#include ++#define NR_IRQS 128 ++ ++#define NR_VIC_IRQ_SIZE (32) ++ ++#define VIC1_INT_VEC(x) ((x) + (NR_VIC_IRQ_SIZE * 0)) ++#define VIC2_INT_VEC(x) ((x) + (NR_VIC_IRQ_SIZE * 1)) ++//#define VIC3_INT_VEC(x) ((x) + (NR_VIC_IRQ_SIZE * 2)) ++//#define VIC4_INT_VEC(x) ((x) + (NR_VIC_IRQ_SIZE * 3)) ++ ++/* The following are ARCH specific IRQ numbers */ ++ ++#define VIC_INSTANCES 2 ++ ++#define NR_VIC_IRQS (VIC_INSTANCES * NR_VIC_IRQ_SIZE) ++#define GPIO_INT_VEC(x) (NR_VIC_IRQS + x) ++ ++// VIC Instance 1 ++#define SSI_SLAVE_IRQ 0 ++#define ETH_IRQ 1 ++#define ICORE_ERROR_IRQ 2 ++#define GPIO2_IRQ 4 ++#define CD2ND_BIT_CD_IRQ 5 ++#define USBVBUS_IRQ 6 ++#define VO_IRQ 7 ++#define DSP_VO1_IRQ 7 ++#define SD_IRQ 8 ++#define IDC_IRQ 9 ++#define SSI_IRQ 10 ++#define WDT_IRQ 11 ++#define IRIF_IRQ 12 ++#define CFCD1_IRQ 13 ++#define SDCD_IRQ 14 /* SD0 SD card card detection. */ ++#define UART1_IRQ 15 ++#define GPIO0_IRQ 16 ++#define GPIO1_IRQ 17 ++#define TIMER1_IRQ 18 ++#define TIMER2_IRQ 19 ++#define TIMER3_IRQ 20 ++#define DMA_IRQ 21 ++#define FIOCMD_IRQ 22 ++#define FIODMA_IRQ 23 ++#define VI_IRQ 24 ++#define DSP_VI_IRQ 24 ++#define VCORE_IRQ 25 ++#define DSP_VCORE_IRQ 25 ++#define USBC_IRQ 26 ++#define UART2_IRQ 27 ++#define HIF2_IRQ 28 ++#define I2STX_IRQ 29 ++#define I2SRX_IRQ 30 ++#define UART0_IRQ 31 ++ ++// VIC Instance 2 ++#define DMA_FIOS_IRQ (32 + 7) ++#define VO0_TV_SYNC_IRQ (32 + 16) ++#define VO1_LCD_SYNC_IRQ (32 + 17) ++#define DSP_VO0_IRQ (32 + 18) ++#define AES_IRQ (32 + 19) ++#define DES_IRQ (32 + 20) ++#define MDMA_IRQ (32 + 22) ++#define MOTOR_IRQ (32 + 23) ++#define ADC_LEVEL_IRQ (32 + 24) ++#define IDC_HDMI_IRQ (32 + 26) ++#define ICORE_LAST_PIXEL_IRQ (32 + 27) ++#define ICORE_VSYNC_IRQ (32 + 28) ++#define ICORE_SENSOR_VSYNC_IRQ (32 + 29) ++#define HDMI_IRQ (32 + 30) ++#define SSI2_IRQ (32 + 31) ++ ++#define MAX_IRQ_NUM (SSI2_IRQ + 1) ++#define IR_IRQ HDMI_IRQ ++ ++ ++//#define MAX_IRQ_NUM (MOTOR_IRQ + 1) ++ ++#define GPIO_IRQ(x) ((x) + NR_VIC_IRQS) ++ ++ ++#define VIC_IRQ(x) (x) ++ ++ ++/* ++ * VIC trigger types (SW definition). ++ */ ++#define VIRQ_RISING_EDGE 0 ++#define VIRQ_FALLING_EDGE 1 ++#define VIRQ_BOTH_EDGES 2 ++#define VIRQ_LEVEL_LOW 3 ++#define VIRQ_LEVEL_HIGH 4 ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++#define VIC_IRQ_STA_OFFSET 0x30 ++#define VIC_FIQ_STA_OFFSET 0x34 ++#define VIC_RAW_STA_OFFSET 0x18 ++#define VIC_INT_SEL_OFFSET 0x0c ++#define VIC_INTEN_OFFSET 0x10 ++#define VIC_INTEN_CLR_OFFSET 0x14 ++#define VIC_SOFTEN_OFFSET 0x1c ++#define VIC_SOFTEN_CLR_OFFSET 0x20 ++#define VIC_PROTEN_OFFSET 0x24 ++#define VIC_SENSE_OFFSET 0x00 ++#define VIC_BOTHEDGE_OFFSET 0x08 ++#define VIC_EVENT_OFFSET 0x04 ++#define VIC_EDGE_CLR_OFFSET 0x38 ++ ++#define VIC1_BASE (GK_VA_VIC1) ++#define VIC2_BASE (GK_VA_VIC2) ++ ++#define VIC1_REG(x) (VIC1_BASE + (x)) ++#define VIC2_REG(x) (VIC2_BASE + (x)) ++ ++#define VIC_IRQ_STA_REG VIC1_REG(VIC_IRQ_STA_OFFSET) ++#define VIC_FIQ_STA_REG VIC1_REG(VIC_FIQ_STA_OFFSET) ++#define VIC_RAW_STA_REG VIC1_REG(VIC_RAW_STA_OFFSET) ++#define VIC_INT_SEL_REG VIC1_REG(VIC_INT_SEL_OFFSET) ++#define VIC_INTEN_REG VIC1_REG(VIC_INTEN_OFFSET) ++#define VIC_INTEN_CLR_REG VIC1_REG(VIC_INTEN_CLR_OFFSET) ++#define VIC_SOFTEN_REG VIC1_REG(VIC_SOFTEN_OFFSET) ++#define VIC_SOFTEN_CLR_REG VIC1_REG(VIC_SOFTEN_CLR_OFFSET) ++#define VIC_PROTEN_REG VIC1_REG(VIC_PROTEN_OFFSET) ++#define VIC_SENSE_REG VIC1_REG(VIC_SENSE_OFFSET) ++#define VIC_BOTHEDGE_REG VIC1_REG(VIC_BOTHEDGE_OFFSET) ++#define VIC_EVENT_REG VIC1_REG(VIC_EVENT_OFFSET) ++#define VIC_EDGE_CLR_REG VIC1_REG(VIC_EDGE_CLR_OFFSET) ++ ++#if (VIC_INSTANCES >= 2) ++ ++#define VIC2_IRQ_STA_REG VIC2_REG(VIC_IRQ_STA_OFFSET) ++#define VIC2_FIQ_STA_REG VIC2_REG(VIC_FIQ_STA_OFFSET) ++#define VIC2_RAW_STA_REG VIC2_REG(VIC_RAW_STA_OFFSET) ++#define VIC2_INT_SEL_REG VIC2_REG(VIC_INT_SEL_OFFSET) ++#define VIC2_INTEN_REG VIC2_REG(VIC_INTEN_OFFSET) ++#define VIC2_INTEN_CLR_REG VIC2_REG(VIC_INTEN_CLR_OFFSET) ++#define VIC2_SOFTEN_REG VIC2_REG(VIC_SOFTEN_OFFSET) ++#define VIC2_SOFTEN_CLR_REG VIC2_REG(VIC_SOFTEN_CLR_OFFSET) ++#define VIC2_PROTEN_REG VIC2_REG(VIC_PROTEN_OFFSET) ++#define VIC2_SENSE_REG VIC2_REG(VIC_SENSE_OFFSET) ++#define VIC2_BOTHEDGE_REG VIC2_REG(VIC_BOTHEDGE_OFFSET) ++#define VIC2_EVENT_REG VIC2_REG(VIC_EVENT_OFFSET) ++#define VIC2_EDGE_CLR_REG VIC2_REG(VIC_EDGE_CLR_OFFSET) ++ ++#endif ++ ++struct gk_irq_info ++{ ++ int irq_gpio; ++ int irq_line; ++ int irq_type; ++ int irq_gpio_val; ++ int irq_gpio_mode; ++}; ++ ++//***************************************************************************** ++//***************************************************************************** ++//** API Functions ++//***************************************************************************** ++//***************************************************************************** ++#ifndef __ASSEMBLY__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct pt_regs; ++ ++extern void gk_init_irq(void) __init; ++extern void gk_vic_handle_irq(struct pt_regs *regs); ++ ++#ifdef __cplusplus ++} ++#endif ++#endif ++ ++#endif /* __MACH_IRQS_H */ ++ +diff --git a/arch/arm/mach-gk710x/include/mach/rct.h b/arch/arm/mach-gk710x/include/mach/rct.h +new file mode 100644 +index 00000000..bff86cad +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/rct.h +@@ -0,0 +1,36 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/mach/rct.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_RCT_H ++#define __MACH_RCT_H ++ ++/* ==============================================*/ ++#define GK_APB_FREQ 69000000 //20MHz ++#define GK_UART_FREQ 24000000 ++#define GK_SD_FREQ 48000000 ++ ++u32 get_apb_bus_freq_hz(void); ++u32 get_uart_freq_hz(void); ++u32 get_sd_freq_hz(void); ++u32 get_ssi0_freq_hz(void); ++u32 get_ssi1_freq_hz(void); ++ ++void set_sd_rct(u32 freq); ++ ++ ++#endif ++ +diff --git a/arch/arm/mach-gk710x/include/mach/sd.h b/arch/arm/mach-gk710x/include/mach/sd.h +new file mode 100644 +index 00000000..392a1ffa +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/sd.h +@@ -0,0 +1,423 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk/include/mach/sd.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_GK_SD_H ++#define __MACH_GK_SD_H ++ ++#include ++ ++/* ==========================================================================*/ ++#define GK_SD_MAX_SLOT_NUM (2) ++ ++#define GK_SD_PRIVATE_CAPS_VDD_18 (0x1 << 0) ++#define GK_SD_PRIVATE_CAPS_ADMA (0x1 << 1) ++#define GK_SD_PRIVATE_CAPS_DTO_BY_SDCLK (0x1 << 2) ++#define GK_SD_PRIVATE_CAPS_DDR (0x1 << 3) ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++struct gk_sd_slot { ++ struct mmc_host *pmmc_host; ++ ++ u32 default_caps; ++ u32 active_caps; ++ u32 default_caps2; ++ u32 active_caps2; ++ u32 private_caps; ++ ++ struct gk_gpio_io_info ext_power; ++ struct gk_gpio_io_info ext_reset; ++ int fixed_cd; ++ struct gk_irq_info gpio_cd; ++ u32 cd_delay; //jiffies ++ int fixed_wp; ++ struct gk_gpio_io_info gpio_wp; ++ ++ int (*check_owner)(void); ++ void (*request)(void); ++ void (*release)(void); ++ void (*set_int)(u32 mask, u32 on); ++ void (*set_vdd)(u32 vdd); ++ void (*set_bus_timing)(u32 timing); ++}; ++ ++struct gk_sd_controller { ++ u32 num_slots; ++ struct gk_sd_slot slot[GK_SD_MAX_SLOT_NUM]; ++ void (*set_pll)(u32); ++ u32 (*get_pll)(void); ++ ++ u32 max_blk_mask; ++ u32 max_clock; ++ u32 active_clock; ++ u32 wait_tmo; ++ u32 pwr_delay; //ms ++ ++ u32 dma_fix; ++ u32 support_pll_scaler; ++}; ++ ++/* ==========================================================================*/ ++extern struct platform_device gk_sd0; ++ ++extern int gk_init_sd(void); ++extern void gk_detect_sd_slot(int bus, int slot, int fixed_cd); ++extern void gk_set_sd_detect_pin(u32 gpio_pin); ++ ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#define SD_INSTANCES 1 ++#define SD_SUPPORT_PLL_SCALER 0 ++#define SD_HAS_INTERNAL_MUXER 1 ++#define SD_HAS_INTERNAL_2ND_CDWP 0 ++#define SD_HAS_DELAY_CTRL 0 ++#define SD_BUS_SWITCH_DLY 0 ++#define SD_HAS_IO_DRIVE_CTRL 1 ++ ++#define SD_HOST1_SUPPORT_XC 0 ++#define SD_HOST2_SUPPORT_XC 0 ++ ++#define SD_SUPPORT_ACMD23 1 ++ ++#define SD_HAS_SDXC_CLOCK 0 ++ ++#define SD_HOST1_HOST2_HAS_MUX 0 ++#define SD_SUPPORT_ADMA 0 ++ ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++ ++#define SD_REG(x) (GK_VA_SDC + (x)) //(0xf0002000 + (x)) ++ ++#define SD_DMA_ADDR_OFFSET 0x000 ++#define SD_BLK_SZ_OFFSET 0x00c /* Half word */ ++#define SD_BLK_CNT_OFFSET 0x00a /* Half word */ ++#define SD_ARG_OFFSET 0x034 ++#define SD_XFR_OFFSET 0x004 /* Half word */ ++#define SD_CMD_OFFSET 0x016 /* Half word */ ++#define SD_RSP0_OFFSET 0x01c ++#define SD_RSP1_OFFSET 0x020 ++#define SD_RSP2_OFFSET 0x024 ++#define SD_RSP3_OFFSET 0x028 ++#define SD_DATA_OFFSET 0x040 ++#define SD_STA_OFFSET 0x030 ++#define SD_HOST_OFFSET 0x02c /* Byte */ ++#define SD_PWR_OFFSET 0x02d /* Byte */ ++#define SD_GAP_OFFSET 0x02e /* Byte */ ++#define SD_WAK_OFFSET 0x02f /* Byte */ ++#define SD_CLK_OFFSET 0x01a /* Half word */ ++#define SD_TMO_OFFSET 0x018 /* Byte */ ++#define SD_RESET_OFFSET 0x019 /* Byte */ ++#define SD_NIS_OFFSET 0x012 /* Half word */ ++#define SD_EIS_OFFSET 0x014 /* Half word */ ++#define SD_NISEN_OFFSET 0x00e /* Half word */ ++#define SD_EISEN_OFFSET 0x010 /* Half word */ ++#define SD_NIXEN_OFFSET 0x006 /* Half word */ ++#define SD_EIXEN_OFFSET 0x008 /* Half word */ ++#define SD_AC12ES_OFFSET 0x03c /* Half word */ ++#define SD_CAP_OFFSET 0x038 ++#define SD_CUR_OFFSET 0x048 ++#define SD_ADMA_STA_OFFSET 0x054 ++#define SD_ADMA_ADDR_OFFSET 0x058 ++#define SD_XC_CTR_OFFSET 0x060 ++#define SD_BOOT_CTR_OFFSET 0x070 ++#define SD_BOOT_STA_OFFSET 0x074 ++#define SD_VOL_SW_OFFSET 0x07c ++#define SD_SIST_OFFSET 0x0fc /* Half word */ ++#define SD_VER_OFFSET 0x0fe /* Half word */ ++ ++#define SD_DMA_ADDR_REG SD_REG(SD_DMA_ADDR_OFFSET) ++#define SD_BLK_SZ_REG SD_REG(SD_BLK_SZ_OFFSET) /* Half word */ ++#define SD_BLK_CNT_REG SD_REG(SD_BLK_CNT_OFFSET) /* Half word */ ++#define SD_ARG_REG SD_REG(SD_ARG_OFFSET) ++#define SD_XFR_REG SD_REG(SD_XFR_OFFSET) /* Half word */ ++#define SD_CMD_REG SD_REG(SD_CMD_OFFSET) /* Half word */ ++#define SD_RSP0_REG SD_REG(SD_RSP0_OFFSET) ++#define SD_RSP1_REG SD_REG(SD_RSP1_OFFSET) ++#define SD_RSP2_REG SD_REG(SD_RSP2_OFFSET) ++#define SD_RSP3_REG SD_REG(SD_RSP3_OFFSET) ++#define SD_DATA_REG SD_REG(SD_DATA_OFFSET) ++#define SD_STA_REG SD_REG(SD_STA_OFFSET) ++#define SD_HOST_REG SD_REG(SD_HOST_OFFSET) /* Byte */ ++#define SD_PWR_REG SD_REG(SD_PWR_OFFSET) /* Byte */ ++#define SD_GAP_REG SD_REG(SD_GAP_OFFSET) /* Byte */ ++#define SD_WAK_REG SD_REG(SD_WAK_OFFSET) /* Byte */ ++#define SD_CLK_REG SD_REG(SD_CLK_OFFSET) /* Half word */ ++#define SD_TMO_REG SD_REG(SD_TMO_OFFSET) /* Byte */ ++#define SD_RESET_REG SD_REG(SD_RESET_OFFSET) /* Byte */ ++#define SD_NIS_REG SD_REG(SD_NIS_OFFSET) /* Half word */ ++#define SD_EIS_REG SD_REG(SD_EIS_OFFSET) /* Half word */ ++#define SD_NISEN_REG SD_REG(SD_NISEN_OFFSET) /* Half word */ ++#define SD_EISEN_REG SD_REG(SD_EISEN_OFFSET) /* Half word */ ++#define SD_NIXEN_REG SD_REG(SD_NIXEN_OFFSET) /* Half word */ ++#define SD_EIXEN_REG SD_REG(SD_EIXEN_OFFSET) /* Half word */ ++#define SD_AC12ES_REG SD_REG(SD_AC12ES_OFFSET) /* Half word */ ++#define SD_CAP_REG SD_REG(SD_CAP_OFFSET) ++#define SD_CUR_REG SD_REG(SD_CUR_OFFSET) ++#define SD_ADMA_STA_REG SD_REG(SD_ADMA_STA_OFFSET) ++#define SD_ADMA_ADDR_REG SD_REG(SD_ADMA_ADDR_OFFSET) ++#define SD_XC_CTR_REG SD_REG(SD_XC_CTR_OFFSET) ++#define SD_BOOT_CTR_REG SD_REG(SD_BOOT_CTR_OFFSET) ++#define SD_BOOT_STA_REG SD_REG(SD_BOOT_STA_OFFSET) ++#define SD_VOL_SW_REG SD_REG(SD_VOL_SW_OFFSET) ++#define SD_SIST_REG SD_REG(SD_SIST_OFFSET) /* Half word */ ++#define SD_VER_REG SD_REG(SD_VER_OFFSET) /* Half word */ ++ ++/* SD_BLK_SZ_REG */ ++#define SD_BLK_SZ_4KB 0x0000 ++#define SD_BLK_SZ_8KB 0x1000 ++#define SD_BLK_SZ_16KB 0x2000 ++#define SD_BLK_SZ_32KB 0x3000 ++#define SD_BLK_SZ_64KB 0x4000 ++#define SD_BLK_SZ_128KB 0x5000 ++#define SD_BLK_SZ_256KB 0x6000 ++#define SD_BLK_SZ_512KB 0x7000 ++ ++/* SD_XFR_REG */ ++#define SD_XFR_MUL_SEL 0x0020 ++#define SD_XFR_SGL_SEL 0x0000 ++#define SD_XFR_CTH_SEL 0x0010 ++#define SD_XFR_HTC_SEL 0x0000 ++#define SD_XFR_DMA_EN 0x0004 ++#define SD_XFR_AC12_EN 0x0002 ++#define SD_XFR_BLKCNT_EN 0x0001 ++ ++/* SD_CMD_REG */ ++#define SD_CMD_IDX(x) ((x) << 8) ++#define SD_CMD_NORMAL 0x00000000 ++#define SD_CMD_SUSPEND 0x00000040 ++#define SD_CMD_RESUME 0x00000080 ++#define SD_CMD_ABORT 0x000000C0 ++#define SD_CMD_CHKIDX 0x00000020 ++#define SD_CMD_DATA 0x00000010 ++#define SD_CMD_CHKCRC 0x00000008 ++ ++#define SD_CMD_RSP_NONE 0x00000000 ++#define SD_CMD_RSP_136 0x00000001 ++#define SD_CMD_RSP_48 0x00000002 ++#define SD_CMD_RSP_48BUSY 0x00000003 ++ ++/* SD_STA_REG */ ++#define SD_STA_DAT_LSL(x) ((((x) & 0x1e000000) >> 25) |(((x) & 0x00f00000) >> 20)) ++#define SD_STA_CMD_LSL(x) (((x) & 0x01000000) >> 24) ++#define SD_STA_WPS_PL 0x00080000 ++#define SD_STA_CSS 0x00040000 ++#define SD_STA_CDP_L 0x00020000 ++#define SD_STA_CARD_INSERTED 0x00010000 ++#define SD_STA_BUFFER_READ_EN 0x00000800 ++#define SD_STA_WRITE_XFR_ACTIVE 0x00000400 ++#define SD_STA_BUFFER_WRITE_EN 0x00000200 ++#define SD_STA_READ_XFR_ACTIVE 0x00000100 ++#define SD_STA_CMD_INHIBIT_DAT 0x00000004 ++#define SD_STA_DAT_ACTIVE 0x00000002 ++#define SD_STA_CMD_INHIBIT_CMD 0x00000001 ++ ++#define SD_STA_WRITABLE 0 ++#define SD_STA_READ_ONLY 1 ++ ++/* SD_HOST_REG */ ++#define SD_HOST_HIGH_SPEED 0x08 ++#define SD_HOST_8BIT 0x04 ++#define SD_HOST_4BIT 0x02 ++#define SD_HOST_LED_ON 0x01 ++ ++/* SD_PWR_REG */ ++#define SD_PWR_3_3V 0x0e ++#define SD_PWR_3_0V 0x0c ++#define SD_PWR_1_8V 0x0a ++#define SD_PWR_ON 0x01 ++#define SD_PWR_OFF 0x00 ++ ++/* SD_GAP_REG */ ++#define SD_GAP_INT_AT_GAP 0x08 ++#define SD_GAP_CONT_REQ 0x04 ++#define SD_GAP_READ_WAIT 0x02 ++#define SD_GAP_STOP_AT_GAP 0x01 ++ ++/* SD_WAK_REG */ ++#define SD_WAK_ON_CARD_RMV 0x04 ++#define SD_WAK_ON_CARD_INT 0x02 ++#define SD_WAK_ON_CARD_IST 0x01 ++ ++/* SD_CLK_REG */ ++#define SD_CLK_DIV_256 0x8000 ++#define SD_CLK_DIV_128 0x4000 ++#define SD_CLK_DIV_64 0x2000 ++#define SD_CLK_DIV_32 0x1000 ++#define SD_CLK_DIV_16 0x0800 ++#define SD_CLK_DIV_8 0x0400 ++#define SD_CLK_DIV_4 0x0200 ++#define SD_CLK_DIV_2 0x0100 ++#define SD_CLK_DIV_1 0x0000 ++#define SD_CLK_EN 0x0004 ++#define SD_CLK_ICLK_STABLE 0x0002 ++#define SD_CLK_ICLK_EN 0x0001 ++ ++/* SD_TMO_REG */ ++/* SD_RESET_REG */ ++#define SD_RESET_DAT 0x04 ++#define SD_RESET_ALL 0x02 ++#define SD_RESET_CMD 0x01 ++ ++/* SD_NIS_REG */ ++#define SD_NIS_ERROR 0x8000 ++#define SD_NIS_CARD 0x0100 ++#define SD_NIS_REMOVAL 0x0080 ++#define SD_NIS_READ_READY 0x0040 ++#define SD_NIS_INSERT 0x0020 ++#define SD_NIS_WRITE_READY 0x0010 ++#define SD_NIS_XFR_DONE 0x0008 ++#define SD_NIS_DMA 0x0004 ++#define SD_NIS_BLOCK_GAP 0x0002 ++#define SD_NIS_CMD_DONE 0x0001 ++ ++/* SD_EIS_REG */ ++#define SD_EIS_ACMD12_ERR 0x0100 ++#define SD_EIS_CURRENT_ERR 0x0080 ++#define SD_EIS_DATA_BIT_ERR 0x0040 ++#define SD_EIS_DATA_CRC_ERR 0x0020 ++#define SD_EIS_DATA_TMOUT_ERR 0x0010 ++#define SD_EIS_CMD_IDX_ERR 0x0008 ++#define SD_EIS_CMD_BIT_ERR 0x0004 ++#define SD_EIS_CMD_CRC_ERR 0x0002 ++#define SD_EIS_CMD_TMOUT_ERR 0x0001 ++ ++ ++/* SD_NISEN_REG */ ++#define SD_NISEN_CARD 0x0100 ++#define SD_NISEN_REMOVAL 0x0080 ++#define SD_NISEN_INSERT 0x0040 ++#define SD_NISEN_READ_READY 0x0020 ++#define SD_NISEN_WRITE_READY 0x0010 ++#define SD_NISEN_DMA 0x0008 ++#define SD_NISEN_BLOCK_GAP 0x0004 ++#define SD_NISEN_XFR_DONE 0x0002 ++#define SD_NISEN_CMD_DONE 0x0001 ++ ++/* SD_EISEN_REG */ ++#define SD_EISEN_ADMA_ERR 0x0200 ++#define SD_EISEN_ACMD12_ERR 0x0100 ++#define SD_EISEN_CURRENT_ERR 0x0080 ++#define SD_EISEN_DATA_BIT_ERR 0x0040 ++#define SD_EISEN_DATA_TMOUT_ERR 0x0020 ++#define SD_EISEN_DATA_CRC_ERR 0x0010 ++#define SD_EISEN_CMD_IDX_ERR 0x0008 ++#define SD_EISEN_CMD_CRC_ERR 0x0004 ++#define SD_EISEN_CMD_BIT_ERR 0x0002 ++#define SD_EISEN_CMD_TMOUT_ERR 0x0001 ++ ++/* SD_NIXEN_REG */ ++#define SD_NIXEN_CARD 0x0100 ++#define SD_NIXEN_REMOVAL 0x0080 ++#define SD_NIXEN_INSERT 0x0040 ++#define SD_NIXEN_READ_READY 0x0020 ++#define SD_NIXEN_WRITE_READY 0x0010 ++#define SD_NIXEN_DMA 0x0008 ++#define SD_NIXEN_BLOCK_GAP 0x0004 ++#define SD_NIXEN_XFR_DONE 0x0002 ++#define SD_NIXEN_CMD_DONE 0x0001 ++ ++/* SD_EIXEN_REG */ ++#define SD_EISEN_ADMA_ERR 0x0200 ++#define SD_EIXEN_ACMD12_ERR 0x0100 ++#define SD_EIXEN_CURRENT_ERR 0x0080 ++#define SD_EIXEN_DATA_BIT_ERR 0x0040 ++#define SD_EIXEN_DATA_CRC_ERR 0x0020 ++#define SD_EIXEN_CMD_CRC_ERR 0x0010 ++#define SD_EIXEN_DATA_TMOUT_ERR 0x0008 ++#define SD_EIXEN_CMD_IDX_ERR 0x0004 ++#define SD_EIXEN_CMD_BIT_ERR 0x0002 ++#define SD_EIXEN_CMD_TMOUT_ERR 0x0001 ++ ++/* SD_AC12ES_REG */ ++#define SD_AC12ES_NOT_ISSUED 0x0040 ++#define SD_AC12ES_INDEX 0x0020 ++#define SD_AC12ES_NOT_EXECED 0x0010 ++#define SD_AC12ES_END_BIT 0x0004 ++#define SD_AC12ES_CRC_ERROR 0x0002 ++#define SD_AC12ES_TMOUT_ERROR 0x0001 ++ ++/* SD_ADMA_STA_REG */ ++#define SD_ADMA_STA_ST_STOP 0x00000000 ++#define SD_ADMA_STA_ST_FDS 0x00000001 ++#define SD_ADMA_STA_ST_TFR 0x00000003 ++#define SD_ADMA_STA_LEN_ERR 0x00000004 ++ ++/* SD_CAP_REG */ ++#define SD_CAP_INTMODE 0x08000000 ++#define SD_CAP_VOL_1_8V 0x04000000 ++#define SD_CAP_VOL_3_0V 0x02000000 ++#define SD_CAP_VOL_3_3V 0x01000000 ++#define SD_CAP_DMA 0x00800000 ++#define SD_CAP_SUS_RES 0x00400000 ++#define SD_CAP_HIGH_SPEED 0x00200000 ++//#define SD_CAP_ADMA_SUPPORT 0x00080000 ++#define SD_CAP_MAX_512B_BLK 0x00000000 ++#define SD_CAP_MAX_1KB_BLK 0x00010000 ++#define SD_CAP_MAX_2KB_BLK 0x00020000 ++#define SD_CAP_BASE_FREQ(x) (((x) & 0x3f00) >> 8) ++#define SD_CAP_TOCLK_KHZ 0x00000000 ++#define SD_CAP_TOCLK_MHZ 0x00000080 ++#define SD_CAP_TOCLK_FREQ(x) (((x) & 0x3f)) ++ ++/* SD_XC_CTR_REG */ ++#define SD_XC_CTR_DDR_EN 0x00008000 ++#define SD_XC_CTR_VOL_1_8V 0x00000001 ++#define SD_XC_CTR_VOL_3_3V 0x00000000 ++ ++/* SD_BOOT_CTR_REG */ ++#define SD_BOOT_CTR_RST_EN 0x00010000 ++ ++/* SD_BOOT_STA_REG */ ++#define SD_BOOT_STA_END_ALT 0x01010000 ++#define SD_BOOT_STA_BOOT_RDY 0x00000001 ++ ++/* SD_VOL_SW_REG */ ++#define SD_VOL_SW_CMD_STAT_H 0x00010000 ++#define SD_VOL_SW_DAT_STAT_H 0x00000007 ++ ++/* SD_VER_REG */ ++#define SD_VER_VENDOR(x) ((x) >> 8) ++#define SD_VER_SPEC(x) ((x) & 0xf) ++ ++#define REG_SDIO_SYSADDRREG SD_REG(SD_DMA_ADDR_OFFSET) /* read/write */ ++#define REG_SDIO_BLKREG SD_REG(SD_BLK_SZ_OFFSET) /* read/write */ ++#define REG_SDIO_ARGREG SD_REG(SD_ARG_OFFSET) /* read/write */ ++#define REG_SDIO_TRANMODEREG SD_REG(SD_XFR_OFFSET) /* read/write */ ++#define REG_SDIO_RESP0REG SD_REG(SD_RSP0_OFFSET) /* read */ ++#define REG_SDIO_RESP1REG SD_REG(SD_RSP1_OFFSET) /* read */ ++#define REG_SDIO_RESP2REG SD_REG(SD_RSP2_OFFSET) /* read */ ++#define REG_SDIO_RESP3REG SD_REG(SD_RSP3_OFFSET) /* read */ ++#define REG_SDIO_BUFFERDATAPORTREG SD_REG(SD_DATA_OFFSET) /* read/write */ ++#define REG_SDIO_PRESENTSTATEREG SD_REG(SD_STA_OFFSET) /* read */ ++#define REG_SDIO_CONTROL00REG SD_REG(SD_HOST_OFFSET) /* read/write */ ++#define REG_SDIO_CONTROL01REG SD_REG(SD_CLK_OFFSET) /* read/write */ ++#define REG_SDIO_INTSTATUSREG SD_REG(SD_NIS_OFFSET) /* read/write */ ++#define REG_SDIO_INTSTATUSENREG SD_REG(SD_NISEN_OFFSET) /* read/write */ ++#define REG_SDIO_INTSIGENREG SD_REG(SD_NIXEN_OFFSET) /* read/write */ ++#define REG_SDIO_AUTOCMD12ERRSTATUSREG SD_REG(SD_AC12ES_OFFSET) /* read/write */ ++#define REG_SDIO_CAPREG SD_REG(SD_CAP_OFFSET) /* read */ ++#define REG_SDIO_MAXCURCAPREG SD_REG(SD_CUR_OFFSET) /* read/write */ ++#define REG_SDIO_SLOTINTSTATUSREG SD_REG(SD_SIST_OFFSET) /* read */ ++ ++#endif /* __MACH_GK_SD_H */ ++ +diff --git a/arch/arm/mach-gk710x/include/mach/spi.h b/arch/arm/mach-gk710x/include/mach/spi.h +new file mode 100644 +index 00000000..6e5eac05 +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/spi.h +@@ -0,0 +1,326 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/mach/spi.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_GK_SPI_H ++#define __MACH_GK_SPI_H ++ ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++#define SPI_MAX_SLAVE_ID 7 ++ ++#define SPI_SUPPORT_TISSP_NSM 1 ++ ++#define SPI_INSTANCES 2 ++#define SPI_AHB_INSTANCES 0 ++#define SPI_SUPPORT_TSSI_MODE 1 ++ ++ ++#define SPI_EN2_EN3_ENABLED_BY_HOST_ENA_REG 0 ++ ++#define SPI_EN2_ENABLED_BY_GPIO2_AFSEL_REG 0 ++ ++#define SPI_EN4_7_ENABLED_BY_GPIO1_AFSEL_REG 1 ++ ++#define SPI_SLAVE_INSTANCES 0 ++ ++#define SPI_SUPPORT_MASTER_CHANGE_ENA_POLARITY 0 ++#define SPI_SUPPORT_MASTER_DELAY_START_TIME 0 ++#define SPI_SUPPORT_NSM_SHAKE_START_BIT_CHSANGE 0 ++ ++#define SPI_EN2_EN3_ENABLED_BY_GPIO2_AFSEL_REG 0 ++ ++/* SPI_FIFO_SIZE */ ++#define SPI_DATA_FIFO_SIZE_16 0x10 ++#define SPI_DATA_FIFO_SIZE_32 0x20 ++#define SPI_DATA_FIFO_SIZE_64 0x40 ++#define SPI_DATA_FIFO_SIZE_128 0x80 ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++#if SPI_API_MODE ++#define SPI_CTRLR0_OFFSET 0x00 ++#define SPI_CTRLR1_OFFSET 0x04 ++#define SPI_SSIENR_OFFSET 0x08 ++#define SPI_MWCR_OFFSET 0x0C ++#define SPI_SER_OFFSET 0x10 ++#define SPI_BAUDR_OFFSET 0x14 ++#define SPI_TXFTLR_OFFSET 0x18 ++#define SPI_RXFTLR_OFFSET 0x1C ++#define SPI_TXFLR_OFFSET 0x20 ++#define SPI_RXFLR_OFFSET 0x24 ++#define SPI_SR_OFFSET 0x28 ++#define SPI_IMR_OFFSET 0x2C ++#define SPI_ISR_OFFSET 0x30 ++#define SPI_RISR_OFFSET 0x34 ++#define SPI_TXOICR_OFFSET 0x38 ++#define SPI_RXOICR_OFFSET 0x3C ++#define SPI_RXUICR_OFFSET 0x40 ++#define SPI_MSTICR_OFFSET 0x44 ++#define SPI_ICR_OFFSET 0x48 ++#if (SPI_AHB_INSTANCES >= 1) ++#define SPI_DMAC_OFFSET 0x4C ++#endif ++#define SPI_IDR_OFFSET 0x58 ++#define SPI_VERSION_ID_OFFSET 0x5C ++#define SPI_DR_OFFSET 0x60 ++ ++#if (SPI_SUPPORT_MASTER_CHANGE_ENA_POLARITY == 1) ++#define SPI_SSIENPOLR_OFFSET 0x260 ++#endif ++#if (SPI_SUPPORT_MASTER_DELAY_START_TIME == 1) ++#define SPI_SCLK_OUT_DLY_OFFSET 0x264 ++#endif ++#if (SPI_SUPPORT_NSM_SHAKE_START_BIT_CHSANGE == 1) ++#define SPI_START_BIT_OFFSET 0x268 ++#endif ++ ++#define TSSI_CTRL_OFFSET 0x00 ++#define TSSI_SSR_OFFSET 0x04 ++#define TSSI_INDEX_OFFSET 0x08 ++#define TSSI_DATA_OFFSET 0x0C ++#define TSSI_POLARITY_INVERT 0x10 ++#else ++#define SPI_CTRLR0_OFFSET 0x0c ++#define SPI_CTRLR1_OFFSET 0x10 ++#define SPI_SSIENR_OFFSET 0x08 ++#define SPI_MWCR_OFFSET 0x14 ++#define SPI_SER_OFFSET 0x60 ++#define SPI_BAUDR_OFFSET 0x18 ++#define SPI_TXFTLR_OFFSET 0x3c ++#define SPI_RXFTLR_OFFSET 0x48 ++#define SPI_TXFLR_OFFSET 0x40 ++#define SPI_RXFLR_OFFSET 0x4c ++#define SPI_SR_OFFSET 0x04 ++#define SPI_IMR_OFFSET 0x1c ++#define SPI_ISR_OFFSET 0x30 ++#define SPI_RISR_OFFSET 0x2c ++#define SPI_TXOICR_OFFSET 0x44 ++#define SPI_RXOICR_OFFSET 0x50 ++#define SPI_RXUICR_OFFSET 0x54 ++#define SPI_MSTICR_OFFSET 0x24 ++#define SPI_ICR_OFFSET 0x20 ++#if (SPI_AHB_INSTANCES >= 1) ++#define SPI_DMAC_OFFSET 0x28 ++#endif ++#define SPI_IDR_OFFSET 0x00 ++#define SPI_VERSION_ID_OFFSET 0x5c ++#define SPI_DR_OFFSET 0x38 ++ ++#if (SPI_SUPPORT_MASTER_CHANGE_ENA_POLARITY == 1) ++#define SPI_SSIENPOLR_OFFSET 0x260 ++#endif ++#if (SPI_SUPPORT_MASTER_DELAY_START_TIME == 1) ++#define SPI_SCLK_OUT_DLY_OFFSET 0x264 ++#endif ++#if (SPI_SUPPORT_NSM_SHAKE_START_BIT_CHSANGE == 1) ++#define SPI_START_BIT_OFFSET 0x268 ++#endif ++ ++#define TSSI_CTRL_OFFSET 0x04 ++#define TSSI_SSR_OFFSET 0x00 ++#define TSSI_INDEX_OFFSET 0x0c ++#define TSSI_DATA_OFFSET 0x08 ++#define TSSI_POLARITY_INVERT 0x10 ++#endif ++ ++#define SPI_REG(x) (GK_VA_SSI1 + (x)) ++#define SPI2_REG(x) (GK_VA_SSI2 + (x)) ++#define TSSI_REG(x) (GK_VA_TSSI + (x)) ++ ++#define SPI_CTRLR0_REG SPI_REG(SPI_CTRLR0_OFFSET) ++#define SPI_CTRLR1_REG SPI_REG(SPI_CTRLR1_OFFSET) ++#define SPI_SSIENR_REG SPI_REG(SPI_SSIENR_OFFSET) ++#define SPI_MWCR_REG SPI_REG(SPI_MWCR_OFFSET) ++#define SPI_SER_REG SPI_REG(SPI_SER_OFFSET) ++#define SPI_BAUDR_REG SPI_REG(SPI_BAUDR_OFFSET) ++#define SPI_TXFTLR_REG SPI_REG(SPI_TXFTLR_OFFSET) ++#define SPI_RXFTLR_REG SPI_REG(SPI_RXFTLR_OFFSET) ++#define SPI_TXFLR_REG SPI_REG(SPI_TXFLR_OFFSET) ++#define SPI_RXFLR_REG SPI_REG(SPI_RXFLR_OFFSET) ++#define SPI_SR_REG SPI_REG(SPI_SR_OFFSET) ++#define SPI_IMR_REG SPI_REG(SPI_IMR_OFFSET) ++#define SPI_ISR_REG SPI_REG(SPI_ISR_OFFSET) ++#define SPI_RISR_REG SPI_REG(SPI_RISR_OFFSET) ++#define SPI_TXOICR_REG SPI_REG(SPI_TXOICR_OFFSET) ++#define SPI_RXOICR_REG SPI_REG(SPI_RXOICR_OFFSET) ++#define SPI_RXUICR_REG SPI_REG(SPI_RXUICR_OFFSET) ++#define SPI_MSTICR_REG SPI_REG(SPI_MSTICR_OFFSET) ++#define SPI_ICR_REG SPI_REG(SPI_ICR_OFFSET) ++#define SPI_IDR_REG SPI_REG(SPI_IDR_OFFSET) ++#define SPI_VERSION_ID_REG SPI_REG(SPI_VERSION_ID_OFFSET) ++#define SPI_DR_REG SPI_REG(SPI_DR_OFFSET) ++ ++#if (SPI_INSTANCES >= 2) ++#define SPI2_CTRLR0_REG SPI2_REG(SPI_CTRLR0_OFFSET) ++#define SPI2_CTRLR1_REG SPI2_REG(SPI_CTRLR1_OFFSET) ++#define SPI2_SSIENR_REG SPI2_REG(SPI_SSIENR_OFFSET) ++#define SPI2_MWCR_REG SPI2_REG(SPI_MWCR_OFFSET) ++#define SPI2_SER_REG SPI2_REG(SPI_SER_OFFSET) ++#define SPI2_BAUDR_REG SPI2_REG(SPI_BAUDR_OFFSET) ++#define SPI2_TXFTLR_REG SPI2_REG(SPI_TXFTLR_OFFSET) ++#define SPI2_RXFTLR_REG SPI2_REG(SPI_RXFTLR_OFFSET) ++#define SPI2_TXFLR_REG SPI2_REG(SPI_TXFLR_OFFSET) ++#define SPI2_RXFLR_REG SPI2_REG(SPI_RXFLR_OFFSET) ++#define SPI2_SR_REG SPI2_REG(SPI_SR_OFFSET) ++#define SPI2_IMR_REG SPI2_REG(SPI_IMR_OFFSET) ++#define SPI2_ISR_REG SPI2_REG(SPI_ISR_OFFSET) ++#define SPI2_RISR_REG SPI2_REG(SPI_RISR_OFFSET) ++#define SPI2_TXOICR_REG SPI2_REG(SPI_TXOICR_OFFSET) ++#define SPI2_RXOICR_REG SPI2_REG(SPI_RXOICR_OFFSET) ++#define SPI2_RXUICR_REG SPI2_REG(SPI_RXUICR_OFFSET) ++#define SPI2_MSTICR_REG SPI2_REG(SPI_MSTICR_OFFSET) ++#define SPI2_ICR_REG SPI2_REG(SPI_ICR_OFFSET) ++#define SPI2_IDR_REG SPI2_REG(SPI_IDR_OFFSET) ++#define SPI2_VERSION_ID_REG SPI2_REG(SPI_VERSION_ID_OFFSET) ++#define SPI2_DR_REG SPI2_REG(SPI_DR_OFFSET) ++#endif ++ ++#define TSSI_CTRL_REG TSSI_REG(TSSI_CTRL_OFFSET) ++#define TSSI_SSR_REG TSSI_REG(TSSI_SSR_OFFSET) ++#define TSSI_INDEX_REG TSSI_REG(TSSI_INDEX_OFFSET) ++#define TSSI_DATA_REG TSSI_REG(TSSI_DATA_OFFSET) ++#define TSSI_POLARITY_INVERT_REG TSSI_REG(TSSI_POLARITY_INVERT) ++ ++ ++#define SPI_MASTER_INSTANCES (SPI_INSTANCES + SPI_AHB_INSTANCES) ++ ++/* ==========================================================================*/ ++/* SPI rw mode */ ++#define SPI_WRITE_READ 0 ++#define SPI_WRITE_ONLY 1 ++#define SPI_READ_ONLY 2 ++ ++/* Tx FIFO empty interrupt mask */ ++#define SPI_TXEIS_MASK 0x00000001 ++#define SPI_TXOIS_MASK 0x00000002 ++ ++/* SPI Parameters */ ++#define SPI_DUMMY_DATA 0xffff ++#define MAX_QUERY_TIMES 10 ++ ++/* Default SPI settings */ ++#define SPI_MODE SPI_MODE_0 ++#define SPI_SCPOL 0 ++#define SPI_SCPH 0 ++#define SPI_FRF 0 ++#define SPI_CFS 0x0 ++#define SPI_DFS 0xf ++#define SPI_BAUD_RATE 200000 ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++struct gk_spi_hw_info { ++ int bus_id; ++ int cs_id; ++}; ++typedef struct gk_spi_hw_info gk_spi_hw_t; ++ ++struct gk_spi_cfg_info { ++ u8 spi_mode; ++ u8 cfs_dfs; ++ u8 cs_change; ++ u32 baud_rate; ++}; ++typedef struct gk_spi_cfg_info gk_spi_cfg_t; ++ ++typedef struct { ++ u8 bus_id; ++ u8 cs_id; ++ u8 *buffer; ++ u16 n_size; ++} gk_spi_write_t; ++ ++typedef struct { ++ u8 bus_id; ++ u8 cs_id; ++ u8 *buffer; ++ u16 n_size; ++} gk_spi_read_t; ++ ++typedef struct { ++ u8 bus_id; ++ u8 cs_id; ++ u8 *w_buffer; ++ u8 *r_buffer; ++ u16 w_size; ++ u16 r_size; ++} gk_spi_write_then_read_t; ++ ++typedef struct { ++ u8 bus_id; ++ u8 cs_id; ++ u8 *w_buffer; ++ u8 *r_buffer; ++ u16 n_size; ++} gk_spi_write_and_read_t; ++ ++struct gk_spi_cs_config { ++ u8 bus_id; ++ u8 cs_id; ++ u8 cs_num; ++ int *cs_pins; ++}; ++ ++struct gk_spi_platform_info { ++ int support_dma; ++ int fifo_entries; ++ int cs_num; ++ int *cs_pins; ++ void (*cs_activate) (struct gk_spi_cs_config *); ++ void (*cs_deactivate)(struct gk_spi_cs_config *); ++ void (*rct_set_ssi_pll)(void); ++ u32 (*get_ssi_freq_hz)(void); ++}; ++#define GK_SPI_PARAM_CALL(id, arg, perm) \ ++ module_param_cb(spi##id##_cs0, ¶m_ops_int, &(arg[0]), perm); \ ++ module_param_cb(spi##id##_cs1, ¶m_ops_int, &(arg[1]), perm); \ ++ module_param_cb(spi##id##_cs2, ¶m_ops_int, &(arg[2]), perm); \ ++ module_param_cb(spi##id##_cs3, ¶m_ops_int, &(arg[3]), perm); \ ++ module_param_cb(spi##id##_cs4, ¶m_ops_int, &(arg[4]), perm); \ ++ module_param_cb(spi##id##_cs5, ¶m_ops_int, &(arg[5]), perm); \ ++ module_param_cb(spi##id##_cs6, ¶m_ops_int, &(arg[6]), perm); \ ++ module_param_cb(spi##id##_cs7, ¶m_ops_int, &(arg[7]), perm) ++ ++/* ==========================================================================*/ ++extern struct platform_device gk_spi0; ++extern struct platform_device gk_spi1; ++extern struct platform_device gk_spi2; ++extern struct platform_device gk_spi3; ++extern struct platform_device gk_spi4; ++extern struct platform_device gk_spi_slave; ++ ++/* ==========================================================================*/ ++extern int gk_spi_write(gk_spi_cfg_t *spi_cfg, ++ gk_spi_write_t *spi_write); ++extern int gk_spi_read(gk_spi_cfg_t *spi_cfg, ++ gk_spi_read_t *spi_read); ++extern int gk_spi_write_then_read(gk_spi_cfg_t *spi_cfg, ++ gk_spi_write_then_read_t *spi_write_then_read); ++extern int gk_spi_write_and_read(gk_spi_cfg_t *spi_cfg, ++ gk_spi_write_and_read_t *spi_write_and_read); ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif ++ +diff --git a/arch/arm/mach-gk710x/include/mach/timer.h b/arch/arm/mach-gk710x/include/mach/timer.h +new file mode 100644 +index 00000000..e7edc4de +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/timer.h +@@ -0,0 +1,100 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/mach/timer.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_TIMER_H__ ++#define __MACH_TIMER_H__ ++ ++#include ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++ ++#define INTERVAL_TIMER_INSTANCES 3 ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++#define TIMER_BASE GK_VA_TIMER ++#define TIMER_REG(x) (GK_VA_TIMER + (x)) ++ ++#define TIMER_CTR_OFFSET 0x0c ++ ++#define TIMER1_STATUS_OFFSET 0x00 ++#define TIMER1_MATCH1_OFFSET 0x04 ++#define TIMER1_MATCH2_OFFSET 0x08 ++ ++#define TIMER2_STATUS_OFFSET 0x14 ++#define TIMER2_MATCH1_OFFSET 0x18 ++#define TIMER2_MATCH2_OFFSET 0x1c ++ ++#define TIMER3_STATUS_OFFSET 0x20 ++#define TIMER3_MATCH1_OFFSET 0x24 ++#define TIMER3_MATCH2_OFFSET 0x28 ++ ++#define TIMER1_RELOAD_OFFSET 0x30 ++#define TIMER2_RELOAD_OFFSET 0x34 ++#define TIMER3_RELOAD_OFFSET 0x38 ++ ++#define TIMER1_STATUS_REG TIMER_REG(TIMER1_STATUS_OFFSET) ++#define TIMER1_RELOAD_REG TIMER_REG(TIMER1_RELOAD_OFFSET) ++#define TIMER1_MATCH1_REG TIMER_REG(TIMER1_MATCH1_OFFSET) ++#define TIMER1_MATCH2_REG TIMER_REG(TIMER1_MATCH2_OFFSET) ++#define TIMER2_STATUS_REG TIMER_REG(TIMER2_STATUS_OFFSET) ++#define TIMER2_RELOAD_REG TIMER_REG(TIMER2_RELOAD_OFFSET) ++#define TIMER2_MATCH1_REG TIMER_REG(TIMER2_MATCH1_OFFSET) ++#define TIMER2_MATCH2_REG TIMER_REG(TIMER2_MATCH2_OFFSET) ++#define TIMER3_STATUS_REG TIMER_REG(TIMER3_STATUS_OFFSET) ++#define TIMER3_RELOAD_REG TIMER_REG(TIMER3_RELOAD_OFFSET) ++#define TIMER3_MATCH1_REG TIMER_REG(TIMER3_MATCH1_OFFSET) ++#define TIMER3_MATCH2_REG TIMER_REG(TIMER3_MATCH2_OFFSET) ++ ++#define TIMER_CTR_REG TIMER_REG(TIMER_CTR_OFFSET) ++ ++ ++/* Bit field definition of timer control register */ ++#define TIMER_CTR_EN1 0x00000400 ++#define TIMER_CTR_EN2 0x00000200 ++#define TIMER_CTR_EN3 0x00000100 ++ ++#define TIMER_CTR_CSL1 0x00000040 ++#define TIMER_CTR_CSL2 0x00000020 ++#define TIMER_CTR_CSL3 0x00000010 ++ ++#define TIMER_CTR_OF1 0x00000004 ++#define TIMER_CTR_OF2 0x00000002 ++#define TIMER_CTR_OF3 0x00000001 ++ ++//***************************************************************************** ++//***************************************************************************** ++//** API Functions ++//***************************************************************************** ++//***************************************************************************** ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++extern struct sys_timer gk_sys_timer; ++extern int gk_init_timer(void) __init; ++ ++extern int get_hwtimer_output_ticks(u64 *out_tick); ++ ++#ifdef __cplusplus ++} ++#endif ++#endif +\ No newline at end of file +diff --git a/arch/arm/mach-gk710x/include/mach/timex.h b/arch/arm/mach-gk710x/include/mach/timex.h +new file mode 100644 +index 00000000..6ba355a1 +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/timex.h +@@ -0,0 +1,26 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/mach/timex.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_TIMEX_H ++#define __MACH_TIMEX_H ++ ++ ++#define CLOCK_TICK_RATE 15000000 //unit:100Hz 18MHz ++ ++ ++#endif /* __MACH_TIMEX_H */ ++ +diff --git a/arch/arm/mach-gk710x/include/mach/uart.h b/arch/arm/mach-gk710x/include/mach/uart.h +new file mode 100644 +index 00000000..d286b801 +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/uart.h +@@ -0,0 +1,316 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/mach/uart.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_UART_H_ ++#define __MACH_UART_H_ ++ ++#include ++#include ++ ++//#define KE_DEBUG ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Defines and Macros ++//***************************************************************************** ++//***************************************************************************** ++ ++#define UART_BASE_FREQ (get_uart_freq_hz()) ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++#define UART_INSTANCES 3 ++ ++#define UART0_VA_ADDR (GK_VA_UART0) ++#define UART0_PA_ADDR (GK_PA_UART0) ++ ++#if (UART_INSTANCES >= 2) ++#define UART1_VA_ADDR (GK_VA_UART1) ++#define UART1_PA_ADDR (GK_PA_UART1) ++#endif ++ ++#if (UART_INSTANCES >= 3) ++#define UART2_VA_ADDR (GK_VA_UART2) ++#define UART2_PA_ADDR (GK_PA_UART2) ++#endif ++ ++#if (UART_INSTANCES >= 4) ++#define UART3_VA_ADDR (GK_VA_UART3) ++#define UART3_PA_ADDR (GK_PA_UART3) ++#endif ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++ ++#define UART0_REG(x) (GK_VA_UART0 + (x)) ++ ++#if (UART_INSTANCES >= 2) ++#define UART1_REG(x) (GK_VA_UART1 + (x)) ++#endif ++ ++#if (UART_INSTANCES >= 3) ++#define UART2_REG(x) (GK_VA_UART2 + (x)) ++#endif ++ ++#if (UART_INSTANCES >= 4) ++#define UART3_REG(x) (GK_VA_UART3 + (x)) ++#endif ++ ++#define UART_RB_OFFSET 0x04 ++#define UART_TH_OFFSET 0x04 ++#define UART_DLL_OFFSET 0x04 ++#define UART_IE_OFFSET 0x00 ++#define UART_DLH_OFFSET 0x00 ++#define UART_II_OFFSET 0x08 ++#define UART_FC_OFFSET 0x08 ++#define UART_LC_OFFSET 0x18 ++#define UART_MC_OFFSET 0x0c ++#define UART_LS_OFFSET 0x14 ++#define UART_MS_OFFSET 0x10 ++#define UART_SC_OFFSET 0x1c /* Byte */ ++#define UART_SRR_OFFSET 0x88 ++ ++#define UART0_RB_REG UART0_REG(UART_RB_OFFSET) ++#define UART0_TH_REG UART0_REG(UART_TH_OFFSET) ++#define UART0_DLL_REG UART0_REG(UART_DLL_OFFSET) ++#define UART0_IE_REG UART0_REG(UART_IE_OFFSET) ++#define UART0_DLH_REG UART0_REG(UART_DLH_OFFSET) ++#define UART0_II_REG UART0_REG(UART_II_OFFSET) ++#define UART0_FC_REG UART0_REG(UART_FC_OFFSET) ++#define UART0_LC_REG UART0_REG(UART_LC_OFFSET) ++#define UART0_MC_REG UART0_REG(UART_MC_OFFSET) ++#define UART0_LS_REG UART0_REG(UART_LS_OFFSET) ++#define UART0_MS_REG UART0_REG(UART_MS_OFFSET) ++#define UART0_SC_REG UART0_REG(UART_SC_OFFSET) /* Byte */ ++ ++#if (UART_INSTANCES >= 2) ++ ++#define UART1_RB_REG UART1_REG(UART_RB_OFFSET) ++#define UART1_TH_REG UART1_REG(UART_TH_OFFSET) ++#define UART1_DLL_REG UART1_REG(UART_DLL_OFFSET) ++#define UART1_IE_REG UART1_REG(UART_IE_OFFSET) ++#define UART1_DLH_REG UART1_REG(UART_DLH_OFFSET) ++#define UART1_II_REG UART1_REG(UART_II_OFFSET) ++#define UART1_FC_REG UART1_REG(UART_FC_OFFSET) ++#define UART1_LC_REG UART1_REG(UART_LC_OFFSET) ++#define UART1_MC_REG UART1_REG(UART_MC_OFFSET) ++#define UART1_LS_REG UART1_REG(UART_LS_OFFSET) ++#define UART1_MS_REG UART1_REG(UART_MS_OFFSET) ++#define UART1_SC_REG UART1_REG(UART_SC_OFFSET) /* Byte */ ++ ++#endif /* UART_INSTANCES >= 2 */ ++ ++#if (UART_INSTANCES >= 3) ++ ++#define UART2_RB_REG UART2_REG(UART_RB_OFFSET) ++#define UART2_TH_REG UART2_REG(UART_TH_OFFSET) ++#define UART2_DLL_REG UART2_REG(UART_DLL_OFFSET) ++#define UART2_IE_REG UART2_REG(UART_IE_OFFSET) ++#define UART2_DLH_REG UART2_REG(UART_DLH_OFFSET) ++#define UART2_II_REG UART2_REG(UART_II_OFFSET) ++#define UART2_FC_REG UART2_REG(UART_FC_OFFSET) ++#define UART2_LC_REG UART2_REG(UART_LC_OFFSET) ++#define UART2_MC_REG UART2_REG(UART_MC_OFFSET) ++#define UART2_LS_REG UART2_REG(UART_LS_OFFSET) ++#define UART2_MS_REG UART2_REG(UART_MS_OFFSET) ++#define UART2_SC_REG UART2_REG(UART_SC_OFFSET) /* Byte */ ++ ++#endif /* UART_INSTANCES >= 3 */ ++ ++#if (UART_INSTANCES >= 4) ++ ++#define UART3_RB_REG UART3_REG(UART_RB_OFFSET) ++#define UART3_TH_REG UART3_REG(UART_TH_OFFSET) ++#define UART3_DLL_REG UART3_REG(UART_DLL_OFFSET) ++#define UART3_IE_REG UART3_REG(UART_IE_OFFSET) ++#define UART3_DLH_REG UART3_REG(UART_DLH_OFFSET) ++#define UART3_II_REG UART3_REG(UART_II_OFFSET) ++#define UART3_FC_REG UART3_REG(UART_FC_OFFSET) ++#define UART3_LC_REG UART3_REG(UART_LC_OFFSET) ++#define UART3_MC_REG UART3_REG(UART_MC_OFFSET) ++#define UART3_LS_REG UART3_REG(UART_LS_OFFSET) ++#define UART3_MS_REG UART3_REG(UART_MS_OFFSET) ++#define UART3_SC_REG UART3_REG(UART_SC_OFFSET) /* Byte */ ++ ++#endif /* UART_INSTANCES >= 4 */ ++ ++/* UART[x]_IE_REG */ ++#define UART_IE_PTIME 0x80 ++#define UART_IE_ETOI 0x20 ++#define UART_IE_EBDI 0x10 ++#define UART_IE_EDSSI 0x08 ++#define UART_IE_ELSI 0x04 ++#define UART_IE_ETBEI 0x02 ++#define UART_IE_ERBFI 0x01 ++ ++/* UART[x]_II_REG */ ++#define UART_II_MODEM_STATUS_CHANGED 0x00 ++#define UART_II_NO_INT_PENDING 0x01 ++#define UART_II_THR_EMPTY 0x02 ++#define UART_II_RCV_DATA_AVAIL 0x04 ++#define UART_II_RCV_STATUS 0x06 ++#define UART_II_CHAR_TIMEOUT 0x0c ++ ++/* UART[x]_FC_REG */ ++#define UART_FC_RX_ONECHAR 0x00 ++#define UART_FC_RX_QUARTER_FULL 0x40 ++#define UART_FC_RX_HALF_FULL 0x80 ++#define UART_FC_RX_2_TO_FULL 0xc0 ++#define UART_FC_TX_EMPTY 0x00 ++#define UART_FC_TX_2_IN_FIFO 0x10 ++#define UART_FC_TX_QUATER_IN_FIFO 0x20 ++#define UART_FC_TX_HALF_IN_FIFO 0x30 ++#define UART_FC_XMITR 0x04 ++#define UART_FC_RCVRR 0x02 ++#define UART_FC_FIFOE 0x01 ++ ++/* UART[x]_LC_REG */ ++#define UART_LC_BRK 0x80 ++ ++#define UART_LC_EVEN_PARITY 0x40 ++#define UART_LC_ODD_PARITY 0x00 ++ ++#define UART_LC_STICKY_PARITY 0x20 ++#define UART_LC_DLAB 0x10 ++ ++#define UART_LC_STOP_2BIT 0x08 ++#define UART_LC_STOP_1BIT 0x00 ++ ++#define UART_LC_PEN 0x04 ++#define UART_LC_CLS_8_BITS 0x03 ++#define UART_LC_CLS_7_BITS 0x02 ++#define UART_LC_CLS_6_BITS 0x01 ++#define UART_LC_CLS_5_BITS 0x00 ++ ++/* quick defs */ ++#define UART_LC_8N1 0x03 ++#define UART_LC_7E1 0x0a ++ ++/* UART[x]_MC_REG */ ++#define UART_MC_LB 0x40 ++#define UART_MC_AFCE 0x20 ++#define UART_MC_SIRE 0x10 ++#define UART_MC_RTS 0x08 ++#define UART_MC_DTR 0x04 ++#define UART_MC_OUT2 0x02 ++#define UART_MC_OUT1 0x01 ++ ++/* UART[x]_LS_REG */ ++#define UART_LS_FERR 0x80 ++ ++#define UART_LS_TEMT 0x40 ++#define UART_LS_BI 0x20 ++#define UART_LS_FE 0x10 ++#define UART_LS_THRE 0x08 ++ ++#define UART_LS_DR 0x04 ++#define UART_LS_PE 0x02 ++#define UART_LS_OE 0x01 ++ ++/* UART[x]_MS_REG */ ++#define UART_MS_DCD 0x80 ++#define UART_MS_DCTS 0x40 ++#define UART_MS_CTS 0x20 ++#define UART_MS_DDCD 0x10 ++#define UART_MS_DSR 0x08 ++#define UART_MS_DDSR 0x04 ++#define UART_MS_TERI 0x02 ++#define UART_MS_RI 0x01 ++ ++/* Other defs for UART */ ++#define RECV_BUF_SIZ 1500 ++#define SEND_BUF_SIZ 1500 ++ ++/* ==========================================================================*/ ++#define UART_FIFO_SIZE (16) ++ ++#define DEFAULT_UART_MCR (0) ++#define DEFAULT_UART_IER (UART_IE_ELSI | UART_IE_ERBFI) ++#define DEFAULT_UART_FCR (UART_FC_FIFOE | UART_FC_RX_2_TO_FULL | UART_FC_TX_EMPTY) ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Enumerated types ++//***************************************************************************** ++//***************************************************************************** ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Data Structures ++//***************************************************************************** ++//***************************************************************************** ++ ++#ifndef __ASSEMBLER__ ++ ++struct gk_uart_port_info ++{ ++ void *port; //struct uart_port * ++ u32 mcr; ++ u32 fcr; ++ u32 ier; ++ u32 tx_fifo_fix; ++ ++ void (*stop_tx)(unsigned char __iomem *membase); ++ void (*set_pll)(void); ++ u32 (*get_pll)(void); ++ u32 (*get_ms)(unsigned char __iomem *membase); ++}; ++ ++struct gk_uart_platform_info ++{ ++ int total_port_num; ++ int registed_port_num; ++ ++ struct gk_uart_port_info port[UART_INSTANCES]; ++}; ++ ++extern struct gk_uart_platform_info gk_uart_ports; ++ ++#ifdef KE_DEBUG ++extern void after_print(const char *str, ...); ++#endif ++ ++/* ==========================================================================*/ ++#endif /* __ASSEMBLER__ */ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Global Data ++//***************************************************************************** ++//***************************************************************************** ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** API Functions ++//***************************************************************************** ++//***************************************************************************** ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MACH_UART_H_ */ +diff --git a/arch/arm/mach-gk710x/include/mach/uncompress.h b/arch/arm/mach-gk710x/include/mach/uncompress.h +new file mode 100644 +index 00000000..87d274d1 +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/uncompress.h +@@ -0,0 +1,96 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/mach/uncompress.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_UNCOMPRESS_H ++#define __MACH_UNCOMPRESS_H ++ ++/* ==========================================================================*/ ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++#include ++#include ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++ ++typedef void* (*hal_function_t) (unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) ; ++ ++struct hw_ops *g_hw; ++ ++#define PA_UART0 GK_PA_UART0 ++#define UART_RB_OFFSET 0x04 ++#define UART_TH_OFFSET 0x04 ++#define UART_DLL_OFFSET 0x04 ++#define UART_IE_OFFSET 0x00 ++#define UART_DLH_OFFSET 0x00 ++#define UART_II_OFFSET 0x08 ++#define UART_FC_OFFSET 0x08 ++#define UART_LC_OFFSET 0x18 ++#define UART_MC_OFFSET 0x0c ++#define UART_LS_OFFSET 0x14 ++#define UART_MS_OFFSET 0x10 ++#define UART_SC_OFFSET 0x1c /* Byte */ ++#define UART_SRR_OFFSET 0x88 ++ ++ ++#define UART_LS_REG ((PA_UART0 + UART_LS_OFFSET)) ++#define UART_TH_REG ((PA_UART0 + UART_TH_OFFSET)) ++#define UART_RB_REG ((PA_UART0 + UART_RB_OFFSET)) ++#define UART_SRR_REG ((PA_UART0 + UART_SRR_OFFSET)) ++ ++#define UART_LC_REG ((PA_UART0 + UART_LC_OFFSET)) ++#define UART_DLL_REG ((PA_UART0 + UART_DLL_OFFSET)) ++#define UART_DLH_REG ((PA_UART0 + UART_DLH_OFFSET)) ++ ++/* ==========================================================================*/ ++ ++static inline void putc(int c) ++{ ++ while (!(gk_uart_readl(UART_LS_REG) & UART_LS_TEMT)); ++ gk_uart_writel(UART_TH_REG, c); ++} ++ ++static inline void flush(void) ++{ ++ unsigned int dump; ++ ++ while (gk_uart_readl(UART_LS_REG) & UART_LS_DR) ++ { ++ dump = gk_uart_readl(UART_RB_REG); ++ } ++} ++ ++ ++ ++ ++ ++static inline void arch_decomp_setup(void) ++{ ++ ++ hal_function_t hal_init = (hal_function_t) (*(volatile u32 *)CONFIG_U2K_HAL_ADDR); ++ ++ g_hw = (struct hw_ops *)hal_init (0, 0, 0x90000000, 0xa0000000, 0); ++ ++} ++ ++#define arch_decomp_wdog() ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif /* __MACH_UNCOMPRESS_H */ +diff --git a/arch/arm/mach-gk710x/include/mach/vmalloc.h b/arch/arm/mach-gk710x/include/mach/vmalloc.h +new file mode 100644 +index 00000000..ff65ed24 +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/vmalloc.h +@@ -0,0 +1,37 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/mach/vmalloc.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_VMALLOC_H ++#define __MACH_VMALLOC_H ++ ++/* ==========================================================================*/ ++#if defined(CONFIG_VMSPLIT_3G) ++#define VMALLOC_END UL(0xe0000000) ++#else ++#define VMALLOC_END UL(0xb0000000) ++#endif ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++/* ==========================================================================*/ ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif ++ +diff --git a/arch/arm/mach-gk710x/include/mach/vo_i80.h b/arch/arm/mach-gk710x/include/mach/vo_i80.h +new file mode 100644 +index 00000000..8c0acfef +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/vo_i80.h +@@ -0,0 +1,79 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/mach/vo_i80.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_VO_I80_H ++#define __MACH_V0_I80_H ++ ++#include ++ ++#define VO_I80_BASE (GK_VA_VO) ++#define VO_I80_REG(x) (VO_I80_BASE + (x)) ++ ++#define REG_VO_I80_DATA_FORMAT VO_I80_REG(0xC00) /* read/write */ ++#define REG_VO_I80_PIC_RESOLUTION VO_I80_REG(0xC04) /* read/write */ ++#define REG_VO_I80_PIXEL_RDWRCMD VO_I80_REG(0xC08) /* read/write */ ++#define REG_VO_I80_CMD_FORMAT VO_I80_REG(0xC0C) /* read/write */ ++#define REG_VO_I80_LCD_RST_PARA1 VO_I80_REG(0xC10) /* read/write */ ++#define REG_VO_I80_LCD_RST_PARA2 VO_I80_REG(0xC14) /* read/write */ ++#define REG_VO_I80_DELAY_PARA VO_I80_REG(0xC18) /* read/write */ ++#define REG_VO_I80_TWR_TIMING VO_I80_REG(0xC1C) /* read/write */ ++#define REG_VO_I80_TRD_TIMING VO_I80_REG(0xC20) /* read/write */ ++#define REG_VO_I80_TCS_TIMING VO_I80_REG(0xC24) /* read/write */ ++#define REG_VO_I80_POLAR_CTRL VO_I80_REG(0xC28) /* read/write */ ++#define REG_VO_I80_CTRL VO_I80_REG(0xC2C) /* read/write */ ++#define REG_VO_I80_FRAME_COUNTER VO_I80_REG(0xC30) /* read */ ++#define REG_VO_I80_I80_STATE VO_I80_REG(0xC34) /* read */ ++#define REG_VO_I80_CMD_SRAM_STATE VO_I80_REG(0xC38) /* read/write */ ++#define REG_VO_I80_TCSREF_WT_TIMING VO_I80_REG(0xC3C) /* read/write */ ++#define REG_VO_I80_TCSREF_RD_TIMING VO_I80_REG(0xC40) /* read/write */ ++#define REG_VO_I80_TODH_TIMING VO_I80_REG(0xC44) /* read/write */ ++#define REG_VO_I80_LCD_STATE VO_I80_REG(0xC48) /* read */ ++#define REG_VO_I80_LCD_STATE0 VO_I80_REG(0xC4C) /* read */ ++#define REG_VO_I80_LCD_STATE1 VO_I80_REG(0xC50) /* read */ ++#define REG_VO_I80_LCD_STATE2 VO_I80_REG(0xC54) /* read */ ++#define REG_VO_I80_LCD_STATE3 VO_I80_REG(0xC58) /* read */ ++#define REG_VO_I80_LCD_STATE4 VO_I80_REG(0xC5C) /* read */ ++#define REG_VO_I80_SRAM_CMDPARA VO_I80_REG(0xC80) /* read/write */ ++ ++ ++ ++#define I80_DESIGN_REF_CLK_FREQ 200//MHz GK7101S-->200MHz GK8601-->300MHz ++ ++#define I80_CLK_FREQ 100//MHz GK7101S: FPGA-->100MHz IC-->200MHz ++#define I80_CLK_PERIOD (1000/I80_CLK_FREQ)//FPGA-->10ns/Cycle IC-->5ns/cycle ++ ++#define MAX_RESET_1ST_H_L_MS ( ((1<<11)-1)*I80_DESIGN_REF_CLK_FREQ/(100*I80_CLK_FREQ) )//FPGA-->40ms IC-->20ms ++#define MAX_RESET_2ND_H_MS ( ((1<<11)-1)*I80_DESIGN_REF_CLK_FREQ/(10*I80_CLK_FREQ) ) //FPGA-->409ms IC-->204ms ++#define MAX_DELAY_MS ( ((1<<11)-1)*I80_DESIGN_REF_CLK_FREQ/(10*I80_CLK_FREQ) ) //FPGA-->409ms IC-->204ms ++//#define MAX_TRANS_NS ((1<<9)-1)*I80_CLK_PERIOD //FPGA-->5110ns IC-->2555ns ++//#define MAX_TAS_NS ((1<<6)-1)*I80_CLK_PERIOD //FPGA-->630ns IC-->315ns ++ ++#define TIMING_PARA_CEIL_NS(x) (((x)*I80_CLK_FREQ+999)/1000) ++ ++#define I80_1ST_H_L_COUNTER (10*I80_DESIGN_REF_CLK_FREQ) ++#define I80_2ND_H_COUNTER (100*I80_DESIGN_REF_CLK_FREQ) ++#define I80_HW_DELAY_COUNTER (100*I80_DESIGN_REF_CLK_FREQ) ++ ++#define TIMING_PARA_FIRST_H_CEIL_MS(x) ((1000*I80_CLK_FREQ*(x)+I80_1ST_H_L_COUNTER-1)/I80_1ST_H_L_COUNTER) ++#define TIMING_PARA_FIRST_L_CEIL_MS(x) ((1000*I80_CLK_FREQ*(x)+I80_1ST_H_L_COUNTER-1)/I80_1ST_H_L_COUNTER) ++#define TIMING_PARA_SECOND_H_CEIL_MS(x) ((1000*I80_CLK_FREQ*(x)+I80_2ND_H_COUNTER-1)/I80_2ND_H_COUNTER) ++#define TIMING_PARA_HW_DELAY_CEIL_MS(x) ((1000*I80_CLK_FREQ*(x)+I80_HW_DELAY_COUNTER-1)/I80_HW_DELAY_COUNTER) ++ ++ ++#endif /* __MACH_VO_I80_H */ ++ ++ +diff --git a/arch/arm/mach-gk710x/include/mach/wdt.h b/arch/arm/mach-gk710x/include/mach/wdt.h +new file mode 100644 +index 00000000..8956e6fc +--- /dev/null ++++ b/arch/arm/mach-gk710x/include/mach/wdt.h +@@ -0,0 +1,77 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/mach/wdt.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_WDT_H ++#define __MACH_WDT_H ++ ++/* ==============================================*/ ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++ ++/* On A5S WDT_RST_L_REG can not be cleared. */ ++/* When is more then 0xff. To work around we set */ ++/* WDT_RST_L_REG to 0x0 before WDT start because */ ++/* it is preserved during soft reset, if it's */ ++/* still 0x0 we could know the reset is from WDT */ ++ ++#define RCT_WDT_RESET_VAL 0 ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++ ++#define WDOG_REG(x) (GK_VA_WDT + (x)) ++ ++#define WDOG_STATUS_OFFSET 0x0c ++#define WDOG_RELOAD_OFFSET 0x10 ++#define WDOG_RESTART_OFFSET 0x14 ++#define WDOG_CONTROL_OFFSET 0x00 ++#define WDOG_TIMEOUT_OFFSET 0x04 ++#define WDOG_CLR_TMO_OFFSET 0x08 ++#define WDOG_RST_WD_OFFSET 0x18 ++ ++#define WDOG_STATUS_REG WDOG_REG(WDOG_STATUS_OFFSET) ++#define WDOG_RELOAD_REG WDOG_REG(WDOG_RELOAD_OFFSET) ++#define WDOG_RESTART_REG WDOG_REG(WDOG_RESTART_OFFSET) ++#define WDOG_CONTROL_REG WDOG_REG(WDOG_CONTROL_OFFSET) ++#define WDOG_TIMEOUT_REG WDOG_REG(WDOG_TIMEOUT_OFFSET) ++#define WDOG_CLR_TMO_REG WDOG_REG(WDOG_CLR_TMO_OFFSET) ++#define WDOG_RST_WD_REG WDOG_REG(WDOG_RST_WD_OFFSET) ++ ++/* Bit field definition of watch dog timer control register */ ++#define WDOG_CTR_RST_EN 0x00000004 ++#define WDOG_CTR_INT_EN 0x00000002 ++#define WDOG_CTR_EN 0x00000001 ++ ++/* WDOG_RESTART_REG only works with magic 0x4755. */ ++/* Set this value would transferred the value in */ ++/* WDOG_RELOAD_REG into WDOG_STATUS_REG and would */ ++/* not trigger the underflow event. */ ++#define WDT_RESTART_VAL 0X4755 ++ ++/* ==============================================*/ ++#ifndef __ASSEMBLER__ ++ ++extern struct platform_device gk_wdt; ++ ++#endif /* __ASSEMBLER__ */ ++/* ==============================================*/ ++ ++#endif /* __REGS_WDT_H */ ++ +diff --git a/arch/arm/mach-gk710x/irq.c b/arch/arm/mach-gk710x/irq.c +new file mode 100644 +index 00000000..d70f61dc +--- /dev/null ++++ b/arch/arm/mach-gk710x/irq.c +@@ -0,0 +1,410 @@ ++/* ++ * arch/arm/mach-gk/irq.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#ifdef CONFIG_ARM_VIC ++#include ++#endif ++ ++/** ++ * struct vic_device - VIC PM device ++ * @irq: The IRQ number for the base of the VIC. ++ * @base: The register base for the VIC. ++ * @resume_sources: A bitmask of interrupts for resume. ++ * @resume_irqs: The IRQs enabled for resume. ++ * @int_select: Save for VIC_INT_SELECT. ++ * @int_enable: Save for VIC_INT_ENABLE. ++ * @soft_int: Save for VIC_INT_SOFT. ++ * @protect: Save for VIC_PROTECT. ++ * @domain: The IRQ domain for the VIC. ++ */ ++struct gk_vic_device { ++ void __iomem *base; ++ int irq; ++ u32 resume_sources; ++ u32 resume_irqs; ++ u32 int_select; ++ u32 int_enable; ++ u32 soft_int; ++ u32 protect; ++ struct irq_domain *domain; ++}; ++ ++/* ==========================================================================*/ ++ ++/* we cannot allocate memory when VICs are initially registered */ ++static struct gk_vic_device gk_vic_decs[VIC_INSTANCES]; ++ ++static int gk_vic_id; ++/* ==========================================================================*/ ++ ++/* ==========================================================================*/ ++#define GK_GPIO_IRQ2GIRQ() do { \ ++ girq -= GPIO_IRQ(0); \ ++ } while (0) ++ ++ ++/* ==========================================================================*/ ++#if (VIC_INSTANCES == 1) ++#define GK_VIC_IRQ2BASE() do { \ ++ irq -= VIC1_INT_VEC(0); \ ++ } while (0) ++#elif (VIC_INSTANCES == 2) ++#define GK_VIC_IRQ2BASE() do { \ ++ irq -= VIC1_INT_VEC(0); \ ++ if (irq >= NR_VIC_IRQ_SIZE) { \ ++ irq -= NR_VIC_IRQ_SIZE; \ ++ vic_base = VIC2_BASE; \ ++ } \ ++ } while (0) ++#endif ++ ++static void gk_ack_irq(struct irq_data *d) ++{ ++ u32 vic_base = VIC1_BASE; ++ u32 irq = d->irq; ++ ++ GK_VIC_IRQ2BASE(); ++ ++ gk_irq_writel(vic_base + VIC_EDGE_CLR_OFFSET, 0x1 << irq); ++} ++ ++static void gk_disable_irq(struct irq_data *d) ++{ ++ u32 vic_base = VIC1_BASE; ++ u32 irq = d->irq; ++ ++ GK_VIC_IRQ2BASE(); ++ ++ gk_irq_writel(vic_base + VIC_INTEN_CLR_OFFSET, 0x1 << irq); ++} ++ ++static void gk_enable_irq(struct irq_data *d) ++{ ++ u32 vic_base = VIC1_BASE; ++ u32 irq = d->irq; ++ ++ GK_VIC_IRQ2BASE(); ++ ++ gk_irq_writel(vic_base + VIC_INTEN_OFFSET, 0x1 << irq); ++} ++ ++static void gk_mask_ack_irq(struct irq_data *d) ++{ ++ u32 vic_base = VIC1_BASE; ++ u32 irq = d->irq; ++ ++ GK_VIC_IRQ2BASE(); ++ ++ gk_irq_writel(vic_base + VIC_INTEN_CLR_OFFSET, 0x1 << irq); ++ gk_irq_writel(vic_base + VIC_EDGE_CLR_OFFSET, 0x1 << irq); ++} ++ ++static int gk_irq_set_type(struct irq_data *d, unsigned int type) ++{ ++ u32 vic_base = VIC1_BASE; ++ u32 mask; ++ u32 bit; ++ u32 sense; ++ u32 bothedges; ++ u32 event; ++ struct irq_desc *desc = irq_to_desc(d->irq); ++ u32 irq = d->irq; ++ ++ //printk("%s: irq[%d] type[%d] desc[%p]\n", __func__, irq, type, desc); ++ ++ GK_VIC_IRQ2BASE(); ++ ++ mask = ~(0x1 << irq); ++ bit = (0x1 << irq); ++ sense = gk_irq_readl(vic_base + VIC_SENSE_OFFSET); ++ bothedges = gk_irq_readl(vic_base + VIC_BOTHEDGE_OFFSET); ++ event = gk_irq_readl(vic_base + VIC_EVENT_OFFSET); ++ ++ switch (type) { ++ case IRQ_TYPE_EDGE_RISING: ++ sense &= mask; ++ bothedges &= mask; ++ event |= bit; ++ desc->handle_irq = handle_edge_irq; ++ break; ++ case IRQ_TYPE_EDGE_FALLING: ++ sense &= mask; ++ bothedges &= mask; ++ event &= mask; ++ desc->handle_irq = handle_edge_irq; ++ break; ++ case IRQ_TYPE_EDGE_BOTH: ++ sense &= mask; ++ bothedges |= bit; ++ event &= mask; ++ desc->handle_irq = handle_edge_irq; ++ break; ++ case IRQ_TYPE_LEVEL_HIGH: ++ sense |= bit; ++ bothedges &= mask; ++ event |= bit; ++ desc->handle_irq = handle_level_irq; ++ break; ++ case IRQ_TYPE_LEVEL_LOW: ++ sense |= bit; ++ bothedges &= mask; ++ event &= mask; ++ desc->handle_irq = handle_level_irq; ++ break; ++ default: ++ pr_err("%s: can't set irq type %d for irq 0x%08x@%d\n", ++ __func__, type, vic_base, irq); ++ return -EINVAL; ++ } ++ ++ gk_irq_writel(vic_base + VIC_SENSE_OFFSET, sense); ++ gk_irq_writel(vic_base + VIC_BOTHEDGE_OFFSET, bothedges); ++ gk_irq_writel(vic_base + VIC_EVENT_OFFSET, event); ++ ++ gk_ack_irq(d); ++ ++ return 0; ++} ++ ++static struct irq_chip gk_irq_chip = { ++ .name = "gk irq", ++ .irq_ack = gk_ack_irq, ++ .irq_mask = gk_disable_irq, ++ .irq_unmask = gk_enable_irq, ++ .irq_mask_ack = gk_mask_ack_irq, ++ .irq_set_type = gk_irq_set_type, ++}; ++ ++void gk_swvic_set(u32 irq) ++{ ++ u32 vic_base = VIC1_BASE; ++ ++ GK_VIC_IRQ2BASE(); ++ ++ gk_irq_writel(vic_base + VIC_SOFTEN_OFFSET, 0x1 << irq); ++} ++EXPORT_SYMBOL(gk_swvic_set); ++ ++void gk_swvic_clr(u32 irq) ++{ ++ u32 vic_base = VIC1_BASE; ++ ++ GK_VIC_IRQ2BASE(); ++ ++ gk_irq_writel(vic_base + VIC_SOFTEN_CLR_OFFSET, 0x1 << irq); ++} ++EXPORT_SYMBOL(gk_swvic_clr); ++ ++/* ==========================================================================*/ ++static inline u32 gk_irq_stat2nr(u32 stat) ++{ ++ u32 tmp; ++ u32 nr; ++ ++ __asm__ __volatile__ ++ ("rsbs %[tmp], %[stat], #0" : ++ [tmp] "=r" (tmp) : [stat] "r" (stat)); ++ __asm__ __volatile__ ++ ("and %[nr], %[tmp], %[stat]" : ++ [nr] "=r" (nr) : [tmp] "r" (tmp), [stat] "r" (stat)); ++ __asm__ __volatile__ ++ ("clzcc %[nr], %[nr]" : ++ [nr] "+r" (nr)); ++ __asm__ __volatile__ ++ ("rsc %[nr], %[nr], #32" : ++ [nr] "+r" (nr)); ++ ++ return nr; ++} ++ ++/* ==========================================================================*/ ++ ++u32 vic_base_addr[VIC_INSTANCES] = { ++ VIC1_BASE, ++#if (VIC_INSTANCES >= 2) ++ VIC2_BASE, ++#endif ++#if (VIC_INSTANCES >= 3) ++ VIC3_BASE, ++#endif ++#if (VIC_INSTANCES >= 4) ++ VIC4_BASE, ++#endif ++}; ++ ++#ifndef CONFIG_ARM_VIC ++ ++/** ++ * gk_vic_register() - Register a VIC. ++ * @base: The base address of the VIC. ++ * @irq: The base IRQ for the VIC. ++ * @resume_sources: bitmask of interrupts allowed for resume sources. ++ * @node: The device tree node associated with the VIC. ++ * ++ * Register the VIC with the system device tree so that it can be notified ++ * of suspend and resume requests and ensure that the correct actions are ++ * taken to re-instate the settings on resume. ++ * ++ * This also configures the IRQ domain for the VIC. ++ */ ++static void __init gk_vic_register(void __iomem *base, unsigned int irq, ++ u32 resume_sources, struct device_node *node) ++{ ++ struct gk_vic_device *pVic; ++ ++ if (gk_vic_id >= ARRAY_SIZE(gk_vic_decs)) ++ { ++ printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__); ++ return; ++ } ++ ++ pVic = &gk_vic_decs[gk_vic_id]; ++ pVic->base = base; ++ pVic->resume_sources = resume_sources; ++ pVic->irq = irq; ++ gk_vic_id++; ++ pVic->domain = irq_domain_add_legacy(node, NR_VIC_IRQ_SIZE, irq, 0, ++ &irq_domain_simple_ops, pVic); ++} ++ ++void __init gk_init_vic(u32 num_vic) ++{ ++ int irq, i; ++ ++ printk("gk init vic...\n"); ++ for (i = 0; i < NR_IRQS; i++) ++ { ++ //pr_err("registering irq %d \n", i); ++ irq_set_chip_and_handler(i, &gk_irq_chip, handle_level_irq); ++ set_irq_flags(i, IRQF_VALID); ++ } ++ ++ /* initialize the VICs */ ++ for (irq = 0; irq < num_vic; irq++) ++ { ++ gk_vic_register((void __iomem *)vic_base_addr[irq], (NR_VIC_IRQ_SIZE * irq), 0, NULL); ++ } ++} ++ ++/* ++ * Handle each interrupt in a single VIC. Returns non-zero if we've ++ * handled at least one interrupt. This reads the status register ++ * before handling each interrupt, which is necessary given that ++ * handle_IRQ may briefly re-enable interrupts for soft IRQ handling. ++ */ ++static int gk_handle_one_vic(struct gk_vic_device *vic, struct pt_regs *regs) ++{ ++ u32 stat, irq; ++ int handled = 0; ++ ++ while ((stat = readl_relaxed(vic->base + VIC_IRQ_STA_OFFSET))) { ++ irq = ffs(stat) - 1; ++ handle_IRQ(irq_find_mapping(vic->domain, irq), regs); ++ handled = 1; ++ } ++ ++ return handled; ++} ++ ++/* ++ * Keep iterating over all registered VIC's until there are no pending ++ * interrupts. ++ */ ++asmlinkage void __exception_irq_entry gk_vic_handle_irq(struct pt_regs *regs) ++{ ++ int i, handled; ++ do { ++ for (i = 0, handled = 0; i < gk_vic_id; ++i) ++ handled |= gk_handle_one_vic(&gk_vic_decs[i], regs); ++ } while (handled); ++} ++ ++#else ++ ++void __init gk_init_vic(u32 num_vic) ++{ ++ u32 vic[] = {~0, ~0, ~0}; ++ int irq; ++ ++printk("gk init vic...\n"); ++ /* initialize the VICs */ ++ for (irq = 0; irq < num_vic; irq++) ++ { ++ vic_init(vic_base_addr[irq], (NR_VIC_IRQ_SIZE * irq), vic[irq], 0); ++ } ++} ++ ++#endif ++ ++void __init gk_init_irq(void) ++{ ++ ++#ifndef CONFIG_ARM_VIC ++ printk(">> gk init irq vic1...\n"); ++ /* Set VIC sense and event type for each entry ++ * note: we initialize udc vbus irq type here */ ++ gk_irq_writel(VIC_SENSE_REG, 0x00000000); ++ gk_irq_writel(VIC_BOTHEDGE_REG, 0x00000000); ++ gk_irq_writel(VIC_EVENT_REG, 0x00000000); ++ ++#if (VIC_INSTANCES >= 2) ++ printk(">> gk init irq vic2...\n"); ++ gk_irq_writel(VIC2_SENSE_REG, 0x00000000); ++ gk_irq_writel(VIC2_BOTHEDGE_REG, 0x00000000); ++ gk_irq_writel(VIC2_EVENT_REG, 0x00000000); ++#endif ++ ++ /* Disable all IRQ */ ++ gk_irq_writel(VIC_INT_SEL_REG, 0x00000000); ++ gk_irq_writel(VIC_INTEN_REG, 0x00000000); ++ gk_irq_writel(VIC_INTEN_CLR_REG, 0xffffffff); ++ gk_irq_writel(VIC_EDGE_CLR_REG, 0xffffffff); ++ ++#if (VIC_INSTANCES >= 2) ++ gk_irq_writel(VIC2_INT_SEL_REG, 0x00000000); ++ gk_irq_writel(VIC2_INTEN_REG, 0x00000000); ++ gk_irq_writel(VIC2_INTEN_CLR_REG, 0xffffffff); ++ gk_irq_writel(VIC2_EDGE_CLR_REG, 0xffffffff); ++#endif ++#endif ++ ++ gk_init_vic(VIC_INSTANCES); ++ ++} ++ +diff --git a/arch/arm/mach-gk710x/mach-gk710x.c b/arch/arm/mach-gk710x/mach-gk710x.c +new file mode 100644 +index 00000000..1c3a4319 +--- /dev/null ++++ b/arch/arm/mach-gk710x/mach-gk710x.c +@@ -0,0 +1,1012 @@ ++/* ++ * linux/arch/arm/mach-gk/mach-gk.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * 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 CONFIG_GK_CHIP_INCLUDE_FILE ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++extern struct platform_device gk_fb0; ++extern struct platform_device gk_fb1; ++extern int gk_init_fb(void); ++ ++extern struct platform_device gk_sd0; ++ ++extern struct i2c_board_info gk_board_vi_infos[2]; ++extern struct i2c_board_info gk_board_hdmi_infos[2]; ++ ++//u64 gk_dmamask = DMA_BIT_MASK(32); ++//EXPORT_SYMBOL(gk_dmamask); ++ ++/* ==========================================================================*/ ++ ++#if defined(CONFIG_MTD_SFLASH_GOKE) || defined(CONFIG_MTD_SFLASH_GOKE_MODULE) ++ ++ ++#if defined(CONFIG_ONLY_USE_NOR_8M) ++#define GKAPP_MTDBLOCK0_UBOOT_BIN_OFFSET \ ++ (0) ++#define GKAPP_MTDBLOCK0_UBOOT_BIN_SIZE \ ++ (256 * 1024) ++ ++#define GKAPP_MTDBLOCK1_UBOOT_ENV_OFFSET \ ++ (GKAPP_MTDBLOCK0_UBOOT_BIN_OFFSET \ ++ + GKAPP_MTDBLOCK0_UBOOT_BIN_SIZE) ++#define GKAPP_MTDBLOCK1_UBOOT_ENV_SIZE \ ++ (64 * 1024) ++ ++#define GKAPP_MTDBLOCK2_USER_OFFSET \ ++ (GKAPP_MTDBLOCK1_UBOOT_ENV_OFFSET \ ++ + GKAPP_MTDBLOCK1_UBOOT_ENV_SIZE) ++#define GKAPP_MTDBLOCK2_USER_SIZE \ ++ (128 * 1024) ++ ++#define GKAPP_MTDBLOCK3_CUSTOM_OFFSET \ ++ (GKAPP_MTDBLOCK2_USER_OFFSET \ ++ + GKAPP_MTDBLOCK2_USER_SIZE) ++#define GKAPP_MTDBLOCK3_CUSTOM_SIZE \ ++ (512 * 1024) ++ ++#define GKAPP_MTDBLOCK4_KERNEL_OFFSET \ ++ (GKAPP_MTDBLOCK3_CUSTOM_OFFSET \ ++ + GKAPP_MTDBLOCK3_CUSTOM_SIZE) ++#define GKAPP_MTDBLOCK4_KERNEL_SIZE \ ++ ((1024 + 320) * 1024) ++ ++#define GKAPP_MTDBLOCK5_ROOTFS_OFFSET \ ++ (GKAPP_MTDBLOCK4_KERNEL_OFFSET \ ++ + GKAPP_MTDBLOCK4_KERNEL_SIZE) ++#define GKAPP_MTDBLOCK5_ROOTFS_SIZE \ ++ ((4096 + 0) * 1024) ++ ++#define GKAPP_MTDBLOCK6_RESOURCE_OFFSET \ ++ (GKAPP_MTDBLOCK5_ROOTFS_OFFSET \ ++ + GKAPP_MTDBLOCK5_ROOTFS_SIZE) ++#define GKAPP_MTDBLOCK6_RESOURCE_SIZE \ ++ ((1024 + 704 + 64) * 1024) ++ ++// for 8M nor flash ++static struct mtd_partition gk_flash_parts[]= ++{ ++#if 0 ++ [0] = { ++ .name = "uboot", ++ .offset = GKAPP_MTDBLOCK0_UBOOT_BIN_OFFSET, ++ .size = GKAPP_MTDBLOCK0_UBOOT_BIN_SIZE, ++ }, ++ [1] = { ++ .name = "uboot_env", ++ .offset = GKAPP_MTDBLOCK1_UBOOT_ENV_OFFSET, ++ .size = GKAPP_MTDBLOCK1_UBOOT_ENV_SIZE, ++ }, ++ [2] = {/* for usrm of Juan */ ++ .name = "user", ++ .offset = GKAPP_MTDBLOCK2_USER_OFFSET, ++ .size = GKAPP_MTDBLOCK2_USER_SIZE, ++ }, ++ [3] = {/* mount custom.jffs2 /media/conf */ ++ .name = "conf", ++ .offset = GKAPP_MTDBLOCK3_CUSTOM_OFFSET, ++ .size = GKAPP_MTDBLOCK3_CUSTOM_SIZE, ++ }, ++ [4] = { ++ .name = "kernel", ++ .offset = GKAPP_MTDBLOCK4_KERNEL_OFFSET, ++ .size = GKAPP_MTDBLOCK4_KERNEL_SIZE, ++ }, ++ [5] = {/* ro squashfs rootfs */ ++ .name = "rootfs", ++ .offset = GKAPP_MTDBLOCK5_ROOTFS_OFFSET, ++ .size = GKAPP_MTDBLOCK5_ROOTFS_SIZE, ++ }, ++ [6] = {/* mount font&web squashfs to /media/custom */ ++ .name = "resource", ++ .offset = GKAPP_MTDBLOCK6_RESOURCE_OFFSET, ++ .size = GKAPP_MTDBLOCK6_RESOURCE_SIZE, ++ }, ++#else ++#if 1//defined(CONFIG_MACH_GK7102_HZD_OJTV_v10_JXH42) || defined(CONFIG_MACH_GK_HZD_OJTV_v10_OV2710) ++ //256K ++ [0] = { ++ .name = "uboot", ++ .offset = 0x00000000, ++ .size = 0x00040000, ++ }, ++ //64K ++ [1] = { ++ .name = "ubootenv", ++ .offset = 0x00040000, ++ .size = 0x00010000, ++ }, ++ //128k ++ [2] = { ++ .name = "user", ++ .offset = 0x00050000, ++ .size = 0x00020000, ++ }, ++ //448k ++ [3] = { ++ .name = "config", ++ .offset = 0x00070000, ++ .size = 0x00070000, ++ }, ++ //1344k ++ [4] = { ++ .name = "kernel", ++ .offset = 0x000e0000, ++ .size = 0x001A0000, ++ }, ++ //4M ++ [5] = { ++ .name = "rootfs", ++ .offset = 0x00280000, ++ .size = 0x003b0000, ++ }, ++ //1856k ++ [6] = { ++ .name = "resource", ++ .offset = 0x00630000, ++ .size = 0x001d0000, ++ }, ++ //ALL 0--8M ++ [7] = { ++ .name = "all", ++ .offset = 0x00000000, ++ .size = 0x00800000, ++ }, ++#else ++ //256K ++ [0] = { ++ .name = "uboot", ++ .offset = 0x00000000, ++ .size = 0x00040000, ++ }, ++ //64K ++ [1] = { ++ .name = "ubootenv", ++ .offset = 0x00040000, ++ .size = 0x00010000, ++ }, ++ //128k ++ [2] = { ++ .name = "user", ++ .offset = 0x00050000, ++ .size = 0x00020000, ++ }, ++ //448k ++ [3] = { ++ .name = "config", ++ .offset = 0x00070000, ++ .size = 0x00070000, ++ }, ++ //1344k ++ [4] = { ++ .name = "kernel", ++ .offset = 0x000e0000, ++ .size = 0x00150000, ++ }, ++ //4M ++ [5] = { ++ .name = "rootfs", ++ .offset = 0x00230000, ++ .size = 0x00400000, ++ }, ++ //1856k ++ [6] = { ++ .name = "resource", ++ .offset = 0x00630000, ++ .size = 0x001d0000, ++ }, ++ //ALL 0--8M ++ [7] = { ++ .name = "all", ++ .offset = 0x00000000, ++ .size = 0x00800000, ++ }, ++ #endif ++#endif ++}; ++#elif defined(CONFIG_ONLY_USE_NOR_16M) ++// for 16M nor flash ++static struct mtd_partition gk_flash_parts[]= ++{ ++ //256K ++ [0] = { ++ .name = "uboot", ++ .offset = 0x00000000, ++ .size = 0x00040000, ++ }, ++ //64K ++ [1] = { ++ .name = "ubootenv", ++ .offset = 0x00040000, ++ .size = 0x00010000, ++ }, ++ // 2M ++ [2] = { ++ .name = "kernel", ++ .offset = 0x00050000, ++ .size = 0x00200000, ++ }, ++ //13M + 512K ++ [3] = { ++ .name = "rootfs", ++ .offset = 0x00250000, ++ .size = 0x00DB0000, ++ }, ++ ++}; ++#elif defined(CONFIG_ONLY_USE_NOR_32M) ++// for 32M nor flash ++static struct mtd_partition gk_flash_parts[]= ++{ ++ //256K ++ [0] = { ++ .name = "uboot", ++ .offset = 0x00000000, ++ .size = 0x00040000, ++ }, ++ //64K ++ [1] = { ++ .name = "ubootenv", ++ .offset = 0x00040000, ++ .size = 0x00010000, ++ }, ++ //768K ++ [2] = { ++ .name = "config", ++ .offset = 0x00050000, ++ .size = 0x000c0000, ++ }, ++ // 2.5M ++ [3] = { ++ .name = "kernel", ++ .offset = 0x00110000, ++ .size = 0x00280000, ++ }, ++ //27M ++ [4] = { ++ .name = "rootfs", ++ .offset = 0x00390000, ++ .size = 0x01b00000, ++ }, ++ // 1.5M ++ [5] = { ++ .name = "resource", ++ .offset = 0x01e90000, ++ .size = 0x00170000, ++ }, ++}; ++#elif defined(CONFIG_USE_NOR_AND_NAND) ++// for 8M nor flash ++static struct mtd_partition gk_flash_parts[]= ++{ ++ //192K ++ [0] = { ++ .name = "uboot", ++ .offset = 0x00000000, ++ .size = 0x00040000, ++ }, ++ //64K ++ [1] = { ++ .name = "ubootenv", ++ .offset = 0x00040000, ++ .size = 0x00010000, ++ }, ++ //512K ++ [2] = { ++ .name = "config", ++ .offset = 0x00050000, ++ .size = 0x00080000, ++ }, ++ // 1.25M ++ [3] = { ++ .name = "kernel", ++ .offset = 0x000D0000, ++ .size = 0x00140000, ++ }, ++ //5M ++ [4] = { ++ .name = "rootfs", ++ .offset = 0x00210000, ++ .size = 0x00500000, ++ }, ++ // 1M ++ [5] = { ++ .name = "resource", ++ .offset = 0x00710000, ++ .size = 0x000E0000, ++ }, ++}; ++#elif defined(CONFIG_ONLY_USE_NAND) ++// for 8M nor flash ++static struct mtd_partition gk_flash_parts[]= ++{ ++ //192K ++ [0] = { ++ .name = "uboot", ++ .offset = 0x00000000, ++ .size = 0x00040000, ++ }, ++ //64K ++ [1] = { ++ .name = "ubootenv", ++ .offset = 0x00040000, ++ .size = 0x00010000, ++ }, ++ //512K ++ [2] = { ++ .name = "config", ++ .offset = 0x00050000, ++ .size = 0x00080000, ++ }, ++ // 1.25M ++ [3] = { ++ .name = "kernel", ++ .offset = 0x000D0000, ++ .size = 0x00140000, ++ }, ++ //5M ++ [4] = { ++ .name = "rootfs", ++ .offset = 0x00210000, ++ .size = 0x00500000, ++ }, ++ // 1M ++ [5] = { ++ .name = "resource", ++ .offset = 0x00710000, ++ .size = 0x000E0000, ++ }, ++}; ++#else ++ ++#endif ++ ++static struct sflash_platform_data flash_platform_data = ++{ ++ .speed_mode = (uint32_t)SYSTEM_SFLASH_FREQ, ++ .channel = 0, ++ .nr_parts = ARRAY_SIZE(gk_flash_parts), ++ .parts = gk_flash_parts, ++}; ++ ++static struct platform_device gk_flash_device0 = ++{ ++ .name = "gk_flash", ++ .id = 0, ++ .dev = ++ { ++ .platform_data = &flash_platform_data, ++ }, ++}; ++#endif/*defined(CONFIG_MTD_GK_SFLASH) || defined(CONFIG_MTD_GK_SFLASH_MODULE)*/ ++ ++/* ================ Watch Dog Timer ======================*/ ++#ifdef CONFIG_WATCHDOG_GOKE ++static struct resource gk_wdt_resource[] = { ++ [0] = DEFINE_RES_MEM(GK_VA_WDT, SZ_4K), ++ [1] = DEFINE_RES_IRQ(WDT_IRQ), ++}; ++ ++struct platform_device gk_wdt = { ++ .name = "gk-wdt", ++ .id = -1, ++ .resource = gk_wdt_resource, ++ .num_resources = ARRAY_SIZE(gk_wdt_resource), ++ .dev = { ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++#endif /* CONFIG_WATCHDOG_GOKE */ ++/* ================= End ======================*/ ++ ++/* ================ Inter Integrated Circuit ===================*/ ++ ++#ifdef CONFIG_I2C_GOKE ++static struct resource gk_idc_resources[] = { ++ [0] = DEFINE_RES_MEM(GK_VA_IDC, SZ_4K), ++ [1] = DEFINE_RES_IRQ(IDC_IRQ), ++}; ++ ++struct gk_platform_i2c gk_idc_platform_info = { ++ .clk_limit = 400000, ++ .bulk_write_num = 60, ++ .get_clock = get_apb_bus_freq_hz, ++}; ++IDC_PARAM_CALL(0, gk_idc_platform_info, 0644); ++ ++struct platform_device gk_idc = { ++ .name = "i2c", ++ .id = 0, ++ .resource = gk_idc_resources, ++ .num_resources = ARRAY_SIZE(gk_idc_resources), ++ .dev = { ++ .platform_data = &gk_idc_platform_info, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++ ++#if (IDC_INSTANCES >= 2) ++static struct resource gk_idc_hdmi_resources[] = { ++ [0] = DEFINE_RES_MEM(GK_VA_IDC2, SZ_4K), ++ [1] = DEFINE_RES_IRQ(IDC_HDMI_IRQ), ++}; ++ ++struct gk_platform_i2c gk_idc_hdmi_platform_info = { ++ .clk_limit = 400000, ++ .bulk_write_num = 60, ++ .i2c_class = I2C_CLASS_DDC, ++ .get_clock = get_apb_bus_freq_hz, ++}; ++IDC_PARAM_CALL(1, gk_idc_hdmi_platform_info, 0644); ++ ++struct platform_device gk_idc_hdmi = { ++ .name = "i2c", ++ .id = 1, ++ .resource = gk_idc_hdmi_resources, ++ .num_resources = ARRAY_SIZE(gk_idc_hdmi_resources), ++ .dev = { ++ .platform_data = &gk_idc_hdmi_platform_info, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++#endif ++#endif ++ ++#ifdef CONFIG_SPI_GOKE ++/* ==========================================================================*/ ++void gk_spi_cs_activate(struct gk_spi_cs_config *cs_config) ++{ ++ u8 cs_pin; ++ ++ if (cs_config->bus_id >= SPI_MASTER_INSTANCES || ++ cs_config->cs_id >= cs_config->cs_num) ++ return; ++ cs_pin = cs_config->cs_pins[cs_config->cs_id]; ++ gk_gpio_set_out(cs_pin, 0); ++} ++ ++void gk_spi_cs_deactivate(struct gk_spi_cs_config *cs_config) ++{ ++ u8 cs_pin; ++ ++ if (cs_config->bus_id >= SPI_MASTER_INSTANCES || ++ cs_config->cs_id >= cs_config->cs_num) ++ return; ++ ++ cs_pin = cs_config->cs_pins[cs_config->cs_id]; ++ gk_gpio_set_out(cs_pin, 1); ++} ++ ++struct resource gk_spi0_resources[] = { ++ [0] = { ++ .start = GK_VA_SSI1, ++ .end = GK_VA_SSI1 + 0x0FFF, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = SSI_IRQ, ++ .end = SSI_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++int gk_spi0_cs_pins[] = {-1, -1, -1, -1, -1, -1, -1, -1}; ++GK_SPI_PARAM_CALL(0, gk_spi0_cs_pins, 0644); ++struct gk_spi_platform_info gk_spi0_platform_info = { ++ .support_dma = 0, ++#if (SPI_MASTER_INSTANCES == 5 ) ++ .fifo_entries = 64, ++#else ++ .fifo_entries = 16, ++#endif ++ .cs_num = ARRAY_SIZE(gk_spi0_cs_pins), ++ .cs_pins = gk_spi0_cs_pins, ++ .cs_activate = gk_spi_cs_activate, ++ .cs_deactivate = gk_spi_cs_deactivate, ++// .rct_set_ssi_pll = rct_set_ssi_pll, ++ .get_ssi_freq_hz = get_ssi0_freq_hz, ++}; ++ ++struct platform_device gk_spi0 = { ++ .name = "spi", ++ .id = 0, ++ .resource = gk_spi0_resources, ++ .num_resources = ARRAY_SIZE(gk_spi0_resources), ++ .dev = { ++ .platform_data = &gk_spi0_platform_info, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++ ++#if (SPI_MASTER_INSTANCES >= 2 ) ++struct resource gk_spi1_resources[] = { ++ [0] = { ++ .start = GK_VA_SSI2, ++ .end = GK_VA_SSI2 + 0x0FFF, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = SSI2_IRQ, ++ .end = SSI2_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++int gk_spi1_cs_pins[] = {-1, -1, -1, -1, -1, -1, -1, -1}; ++GK_SPI_PARAM_CALL(1, gk_spi1_cs_pins, 0644); ++struct gk_spi_platform_info gk_spi1_platform_info = { ++ .support_dma = 0, ++ .fifo_entries = 16, ++ .cs_num = ARRAY_SIZE(gk_spi1_cs_pins), ++ .cs_pins = gk_spi1_cs_pins, ++ .cs_activate = gk_spi_cs_activate, ++ .cs_deactivate = gk_spi_cs_deactivate, ++ .get_ssi_freq_hz = get_ssi1_freq_hz, ++}; ++ ++struct platform_device gk_spi1 = { ++ .name = "spi", ++ .id = 1, ++ .resource = gk_spi1_resources, ++ .num_resources = ARRAY_SIZE(gk_spi1_resources), ++ .dev = { ++ .platform_data = &gk_spi1_platform_info, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++#endif ++#endif ++static struct spi_board_info gk_spi_devices[] = { ++ { ++#ifdef CONFIG_MMC_SPI ++ .modalias = "mmc_spi", ++ .max_speed_hz = 69000000/4, /* max spi clock (SCK) speed in HZ */ ++ .bus_num = 0, ++ .mode = SPI_MODE_3, ++ //.platform_data = &bfin_mmc_spi_pdata, ++ //.controller_data = &mmc_spi_chip_info, ++#else ++ .modalias = "spidev", ++#endif ++ .bus_num = 0, ++ .chip_select = 0, ++ }, ++#if (SPI_INSTANCES >= 2) ++ { ++ .modalias = "spidev", ++ .bus_num = 1, ++ .chip_select = 0, ++ } ++#endif ++}; ++ ++/* ================= rtc ======================*/ ++struct platform_device gk_rtc = { ++ .name = "gk-rtc", ++ .id = -1, ++}; ++/* ================= End ======================*/ ++ ++/* ================= ir ======================*/ ++ ++struct gk_ir_controller gk_platform_ir_controller0 = { ++ ++ .protocol = GK_IR_PROTOCOL_NEC, ++ .debug = 0, ++}; ++GK_IR_PARAM_CALL(gk_platform_ir_controller0, 0644); ++ ++struct platform_device gk_ir = { ++ .name = "ir", ++ .id = 1, ++ .dev = { ++ .platform_data = &gk_platform_ir_controller0, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++ ++ ++/* ================= pcm/i2s ======================*/ ++ ++struct platform_device gk_pcm0 = { ++ .name = "gk-pcm-audio", ++ .id = -1, ++}; ++ ++static struct resource gk_i2s0_resources[] = { ++ [0] = { ++ .start = I2S_BASE, ++ .end = I2S_BASE + 0x0FFF, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = I2STX_IRQ, ++ .end = I2SRX_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct gk_i2s_controller gk_i2s_controller0 = { ++ .aucodec_digitalio_0 = NULL, ++ .aucodec_digitalio_1 = NULL, ++ .aucodec_digitalio_2 = NULL, ++ .channel_select = NULL, ++ .set_audio_pll = NULL, ++}; ++ ++ ++struct platform_device gk_i2s0 = { ++ .name = "gk-i2s", ++ .id = 0, ++ .resource = gk_i2s0_resources, ++ .num_resources = ARRAY_SIZE(gk_i2s0_resources), ++ .dev = { ++ .platform_data = &gk_i2s_controller0, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++/* ================= musb ====================*/ ++static struct musb_hdrc_config gk_musb_config = { ++ .multipoint = 1, ++ .dyn_fifo = 0, ++ .big_endian = 0, ++ .dma = 0, ++ .num_eps = 8, ++ .ram_bits = 12, ++}; ++ ++static struct musb_hdrc_platform_data gk_musb_data = { ++#if defined(CONFIG_GK_USB_HOST_MODE) ++ .mode = MUSB_HOST, ++#elif defined(CONFIG_GK_USB_SLAVE_MODE) ++ .mode = MUSB_PERIPHERAL, ++#elif defined(CONFIG_GK_USB_OTG_MODE) ++ .mode = MUSB_HOST, ++#endif ++ .min_power = 25, /* x2 = 50 mA drawn from VBUS as peripheral */ ++ .config = &gk_musb_config, ++}; ++ ++static struct resource gk_musb_resources[] = { ++ /* Order is significant! The start/end fields ++ * are updated during setup.. ++ */ ++ [0] = { ++ .start = GK_VA_USB, ++ .end = GK_VA_USB + 0x2000, ++ .flags = IORESOURCE_MEM, ++ }, ++/* ++ [1] = { ++ .start = GK_VA_USB_PHY, ++ .end = GK_VA_USB_PHY + 0xa00, ++ .flags = IORESOURCE_MEM, ++ }, ++*/ ++ [1] = { ++ .start = USBC_IRQ, ++ .end = USBC_IRQ, ++ .flags = IORESOURCE_IRQ, ++ .name = "mc", ++ }, ++}; ++ ++ ++static struct platform_device gk_musb = { ++ .name = "musb-gk", ++ .id = -1, ++ .dev = { ++ .platform_data = &gk_musb_data, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ }, ++ .num_resources = ARRAY_SIZE(gk_musb_resources), ++ .resource = gk_musb_resources, ++}; ++ ++ ++/* ================= End ======================*/ ++unsigned int gk_aud_get_dma_offset(void) ++{ ++ return AUDIO_DMA_REG_OFFSET; ++} ++EXPORT_SYMBOL(gk_aud_get_dma_offset); ++ ++ ++static struct platform_device *gk_devices[] __initdata = { ++ ++#ifdef CONFIG_MMC_GOKE ++#ifndef CONFIG_PHY_USE_SD_CLK ++ &gk_sd0, ++#endif ++#endif ++#ifdef CONFIG_WATCHDOG_GOKE ++ &gk_wdt, ++#endif ++#ifdef CONFIG_I2C_GOKE ++ &gk_idc, ++#if (IDC_INSTANCES >= 2) ++ &gk_idc_hdmi, ++#endif ++#endif ++ ++#ifdef CONFIG_FB_GOKE ++ &gk_fb0, ++ &gk_fb1, ++#endif ++#ifdef CONFIG_SPI_GOKE ++ &gk_spi0, ++#if (SPI_MASTER_INSTANCES >= 2 ) ++ &gk_spi1, ++#endif ++#endif ++#ifdef CONFIG_RTC_DRV_GOKE ++ &gk_rtc, ++#endif ++#ifdef CONFIG_INPUT_GOKE_IR ++ &gk_ir, ++#endif ++ ++#ifdef CONFIG_ETH_GOKE ++ &gk_eth0, ++#endif ++ //&gk_pcm0, ++ //&gk_i2s0, ++ &gk_musb, ++}; ++ ++//louis add ++/* ==========================================================================*/ ++ ++unsigned int gk_debug_level = GK_DEBUG_MEDIA | GK_DEBUG_DSP | GK_DEBUG_VI | GK_DEBUG_VO | GK_DEBUG_AAA; ++EXPORT_SYMBOL(gk_debug_level); ++ ++unsigned int gk_debug_info = 0; ++EXPORT_SYMBOL(gk_debug_info); ++ ++unsigned int gk_boot_splash_logo = 0; ++EXPORT_SYMBOL(gk_boot_splash_logo); ++ ++unsigned long gk_debug_lookup_name(const char *name) ++{ ++ return module_kallsyms_lookup_name(name); ++} ++EXPORT_SYMBOL(gk_debug_lookup_name); ++//end ++ ++void sensor_init(u8 active_level) ++{ ++ struct gk_gpio_io_info sensor_reset; ++ sensor_reset.gpio_id = gk_all_gpio_cfg.sensor_reset; ++ sensor_reset.active_level = active_level; ++ sensor_reset.active_delay = 1; ++ ++ printk("sensor board reset...\n"); ++ gk_set_gpio_output(&sensor_reset, 1); ++ mdelay(50);//100ms ++ gk_set_gpio_output(&sensor_reset, 0); ++ mdelay(200);//100ms ++} ++EXPORT_SYMBOL(sensor_init); ++ ++void sensor_power(u8 power) ++{ ++} ++EXPORT_SYMBOL(sensor_power); ++ ++/* ==========================================================================*/ ++static u8 cmdline_mac[6]; ++static int __init init_setup_mac(char *str) ++{ ++ int count, i, val; ++ ++ for (count = 0; count < 6 && *str; count++, str += 3) { ++ if (!isxdigit(str[0]) || !isxdigit(str[1])) ++ return 0; ++ if (str[2] != ((count < 5) ? ':' : '\0')) ++ return 0; ++ ++ for (i = 0, val = 0; i < 2; i++) { ++ val = val << 4; ++ val |= isdigit(str[i]) ? ++ str[i] - '0' : toupper(str[i]) - 'A' + 10; ++ } ++ cmdline_mac[count] = val; ++ } ++ return 1; ++ ++} ++__setup("mac=", init_setup_mac); ++ ++u8 cmdline_phytype; ++static int __init init_setup_phytype(char *str) ++{ ++ if (!isxdigit(str[0])) ++ return 0; ++ ++ cmdline_phytype = str[0] - '0'; ++ return 1; ++} ++__setup("phytype=", init_setup_phytype); ++EXPORT_SYMBOL(cmdline_phytype); ++ ++int __init gk_init_board(char *board_name) ++{ ++#ifdef CONFIG_ETH_GOKE ++ unsigned char mac_addr[6] = {00,0x11,0x22,0xa3,0xa0,00}; ++#endif ++ int retval = 0; ++ ++ //pr_info("Goke %s:\n", board_name); ++ //pr_info("\tboard revision:\t\t%d\n", 1); ++ ++ //retval = gk_init_pll(); ++ //BUG_ON(retval != 0); ++ // ++ printk("init timer...\n"); ++ retval = gk_init_timer(); ++ BUG_ON(retval != 0); ++ ++ printk("init gpio...\n"); ++ retval = gk_init_gpio(); ++ BUG_ON(retval != 0); ++ ++ gk_set_sd_detect_pin(gk_all_gpio_cfg.sd_detect); ++#ifdef CONFIG_SPI_GOKE ++ gk_spi0_cs_pins[0] = gk_all_gpio_cfg.spi0_en0; ++#if (SPI_MASTER_INSTANCES >= 2 ) ++ gk_spi1_cs_pins[0] = gk_all_gpio_cfg.spi1_en0; ++#endif ++#endif ++ ++ ++#ifdef CONFIG_ETH_GOKE ++ gk_set_phy_reset_pin(gk_all_gpio_cfg.phy_reset); ++ #if (ETH_INSTANCES >= 1) ++ if (cmdline_mac[0]) ++ memcpy(mac_addr, cmdline_mac, 6); ++ mac_addr[0] &= 0xfe; /* clear multicast bit */ ++ mac_addr[0] |= 0x02; /* set local assignment bit (IEEE802) */ ++ retval = gk_init_eth0(mac_addr); ++ BUG_ON(retval != 0); ++ #endif ++#endif ++ ++ retval = gk_init_dma(); ++ BUG_ON(retval != 0); ++ ++ //config video DAC for CVBS ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x00, 0x01); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x04, 0x01); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x08, 0x00); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x10, 0x01); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x14, 0x01); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x18, 0x3F); ++ ++ gk_init_sd(); ++ ++#ifdef CONFIG_PMU_ALWAYS_RUNNING ++ // get pmu controller ++ gk_gpio_func_config(gk_all_gpio_cfg.pmu_ctl, GPIO_TYPE_OUTPUT_1); ++ msleep(1); ++ gk_gpio_func_config(gk_all_gpio_cfg.pmu_ctl, GPIO_TYPE_OUTPUT_0); ++ msleep(1); ++ gk_load_51mcu_code(PMU_ALWAYS_RUNNING); ++#endif ++ return retval; ++ ++} ++ ++static void __init gk_init_machine(void) ++{ ++ int i; ++ ++ //clkdev_init(); ++ gk_init_board("GK_chip"); ++ ++#if defined(CONFIG_MTD_SFLASH_GOKE) || defined(CONFIG_MTD_SFLASH_GOKE_MODULE) ++ platform_device_register(&gk_flash_device0); ++#endif ++ ++ gk_create_proc_dir(); ++ ++#ifdef CONFIG_FB_GOKE ++ gk_init_fb(); ++#endif ++ ++ printk("gk register devices %d\n", ARRAY_SIZE(gk_devices)); ++ ++ /* Register devices */ ++ platform_add_devices(gk_devices, ARRAY_SIZE(gk_devices)); ++ for (i = 0; i < ARRAY_SIZE(gk_devices); i++) { ++ device_set_wakeup_capable(&gk_devices[i]->dev, 1); ++ device_set_wakeup_enable(&gk_devices[i]->dev, 0); ++ } ++ ++ printk("gk register I2C\n"); ++ //i2c_register_board_info(0, &gk_ak4642_board_info, 1); ++ i2c_register_board_info(0, gk_board_vi_infos, ARRAY_SIZE(gk_board_vi_infos)); ++ i2c_register_board_info(1, gk_board_hdmi_infos, ARRAY_SIZE(gk_board_hdmi_infos)); ++ ++ spi_register_board_info(gk_spi_devices, ++ ARRAY_SIZE(gk_spi_devices)); ++ ++ pm_power_off = gk_power_off; ++ ++} ++ ++MACHINE_START(GOKE_IPC, "Goke IPC Board") ++ .map_io = gk_map_io, ++ .init_irq = gk_init_irq, ++ .handle_irq = gk_vic_handle_irq, ++ .timer = &gk_sys_timer, ++ .init_machine = gk_init_machine, ++ .restart = gk_restart, ++MACHINE_END ++ ++ +diff --git a/arch/arm/mach-gk710x/mdma.c b/arch/arm/mach-gk710x/mdma.c +new file mode 100644 +index 00000000..877f9b54 +--- /dev/null ++++ b/arch/arm/mach-gk710x/mdma.c +@@ -0,0 +1,238 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/mdma.c ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#define TRANSFER_2D_WIDTH (1<<12) /* 4096*/ ++#define MAX_TRANSFER_2D_HEIGHT (1<<11) /* 2048*/ ++#define MAX_TRANSFER_SIZE_2D_UNIT (TRANSFER_2D_WIDTH * MAX_TRANSFER_2D_HEIGHT) /* 8MB*/ ++ ++#define TRANSFER_1D_WIDTH TRANSFER_2D_WIDTH ++#define MAX_TRANSFER_SIZE_1D_UNIT TRANSFER_1D_WIDTH ++ ++/* transfer 6 big blocks (although maximum is 8), because we may do another 1 small block and 1 line. total 8 Ops */ ++#define MAX_TRANSFER_SIZE_ONCE (MAX_TRANSFER_SIZE_2D_UNIT * 6) /* 48 MB*/ ++ ++#define MAX_OPS 8 ++ ++ ++static struct completion transfer_completion; ++ ++ ++/* handle 8MB at one time */ ++static inline int transfer_big_unit(u8 *dest_addr, u8 *src_addr, u32 size) ++{ ++ int row_count; ++ if (size > MAX_TRANSFER_SIZE_2D_UNIT) { ++ printk("transfer_unit size %d bigger than %d \n", ++ size, MAX_TRANSFER_SIZE_2D_UNIT); ++ return -1; ++ } ++ ++ row_count = size / TRANSFER_2D_WIDTH; ++ ++ /* copy rows by 2D copy */ ++ if (row_count > 0) { ++ gk_dsp_writel(MDMA_SRC_1_BASE_REG, (long)src_addr); ++ gk_dsp_writel(MDMA_SRC_1_PITCH_REG, TRANSFER_2D_WIDTH); ++ gk_dsp_writel(MDMA_DST_BASE_REG, (long)dest_addr); ++ gk_dsp_writel(MDMA_DST_PITCH_REG, TRANSFER_2D_WIDTH); ++ gk_dsp_writel(MDMA_WIDTH_REG, TRANSFER_2D_WIDTH - 1); ++ gk_dsp_writel(MDMA_HEIGHT_REG, row_count - 1); ++ ++ /* start 2D copy */ ++ gk_dsp_writel(MDMA_OPCODE_REG, 1); ++ } ++ return 0; ++ ++} ++ ++ ++/* use 1D copy to copy max 4KB each time */ ++static inline int transfer_small_unit(u8 *dest_addr, u8 *src_addr, u32 size) ++{ ++ ++ if (size > TRANSFER_1D_WIDTH) { ++ printk("transfer_unit size %d bigger than %d \n", ++ size, TRANSFER_1D_WIDTH); ++ return -1; ++ } ++ ++ /* linear copy */ ++ gk_dsp_writel(MDMA_SRC_1_BASE_REG, (long)src_addr); ++ gk_dsp_writel(MDMA_DST_BASE_REG, (long)dest_addr); ++ gk_dsp_writel(MDMA_WIDTH_REG, TRANSFER_1D_WIDTH - 1); ++ ++ /* start linear copy */ ++ gk_dsp_writel(MDMA_OPCODE_REG, 0); ++ ++ return 0; ++} ++ ++ ++ ++/* this is async function, just fill dma registers and let it run*/ ++static inline int transfer_once(u8 *dest_addr, u8 *src_addr, u32 size) ++{ ++ //total pending count must be no bigger than 8 ++ int big_count; ++ int rows_count; ++ int i; ++ u32 transferred_bytes = 0; ++ int remain_bytes ; ++ ++ if (size > MAX_TRANSFER_SIZE_ONCE) { ++ printk(" size too big %d for transfer once \n", size); ++ return -1; ++ } ++ ++ big_count = size/MAX_TRANSFER_SIZE_2D_UNIT; ++ //big pages (each is 8MB) ++ for (i = big_count ; i > 0; i--) { ++ transfer_big_unit(dest_addr + transferred_bytes, ++ src_addr + transferred_bytes, ++ MAX_TRANSFER_SIZE_2D_UNIT); ++ transferred_bytes += MAX_TRANSFER_SIZE_2D_UNIT; ++ } ++ remain_bytes = size - transferred_bytes; ++ ++ ++ //transfer rows (align to TRANSFER_2D_WIDTH) ++ rows_count = remain_bytes / TRANSFER_2D_WIDTH; ++ if (rows_count > 0) { ++ transfer_big_unit(dest_addr + transferred_bytes, ++ src_addr + transferred_bytes, ++ TRANSFER_2D_WIDTH * rows_count); ++ transferred_bytes += TRANSFER_2D_WIDTH * rows_count; ++ remain_bytes = size - transferred_bytes; ++ } ++ ++ if (remain_bytes > 0) { ++ transfer_small_unit(dest_addr + transferred_bytes, ++ src_addr + transferred_bytes, remain_bytes); ++ } ++ ++ return 0; ++} ++ ++/* this is synchronous function, will wait till transfer finishes */ ++int dma_memcpy(u8 *dest_addr, u8 *src_addr, u32 size) ++{ ++ int remain_size = size; ++ int transferred_size = 0; ++ int current_transfer_size; ++ ++ while (remain_size > 0) { ++ if (remain_size > MAX_TRANSFER_SIZE_ONCE) { ++ remain_size -= MAX_TRANSFER_SIZE_ONCE; ++ current_transfer_size = MAX_TRANSFER_SIZE_ONCE; ++ } else { ++ current_transfer_size = remain_size; ++ remain_size = 0; ++ } ++ ++ transfer_once(dest_addr + transferred_size, ++ src_addr + transferred_size, current_transfer_size); ++ wait_for_completion(&transfer_completion); ++ transferred_size += current_transfer_size; ++ } ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(dma_memcpy); ++ ++ ++static irqreturn_t mdma_interrupt(int irq, void *dev_id) ++{ ++ int pending_ops; ++ pending_ops = gk_dsp_readl(MDMA_PENDING_OPS_REG); ++ ++ if (pending_ops == 0) { ++ /* if no following transfer */ ++ complete(&transfer_completion); ++ } else { ++ ++ } ++ return IRQ_HANDLED; ++} ++ ++ ++static int hw_init(void) ++{ ++ int errorCode; ++ /* request irq, no device id, no irq sharing */ ++ errorCode = request_irq(MDMA_IRQ, mdma_interrupt, IRQF_TRIGGER_RISING, "mdma", 0); ++ ++ if (errorCode) { ++ printk("mdma irq request failed \n"); ++ return -1; ++ } ++ printk("mdma request irq: %d \n", MDMA_IRQ); ++ ++ return 0; ++} ++ ++ ++/* wait till transmit completes */ ++static void wait_transmit_complete(void) ++{ ++ int pending_ops; ++ pending_ops = gk_dsp_readl(MDMA_PENDING_OPS_REG); ++ ++ while(pending_ops!= 0) { ++ mdelay(10); ++ } ++} ++ ++static int __init mdma_init(void) ++{ ++ printk("mdma init...\n"); ++ ++ /* hardware and irq init */ ++ if (hw_init() != 0) ++ return -1; ++ /* init completion */ ++ init_completion(&transfer_completion); ++ ++ return 0; ++} ++ ++ ++static void __exit mdma_exit(void) ++{ ++ wait_transmit_complete(); ++} ++ ++MODULE_AUTHOR("Louis "); ++MODULE_DESCRIPTION("MDMA driver on gk"); ++MODULE_LICENSE("GPL v2"); ++MODULE_VERSION("1.0"); ++ ++module_init(mdma_init); ++module_exit(mdma_exit); ++ +diff --git a/arch/arm/mach-gk710x/rct.c b/arch/arm/mach-gk710x/rct.c +new file mode 100644 +index 00000000..457669ba +--- /dev/null ++++ b/arch/arm/mach-gk710x/rct.c +@@ -0,0 +1,194 @@ ++/* ++ * arch/arm/mach-gk/rct.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++u32 get_apb_bus_freq_hz(void) ++{ ++ typedef union { ++ u32 all; ++ struct { ++ u32 fbdiv : 12; ++ u32 pstdiv1 : 3; ++ u32 : 1; ++ u32 pstdiv2 : 3; ++ u32 : 1; ++ u32 refdiv : 6; ++ u32 : 6; ++ } bitc; ++ } GH_PLL_CORE_CTRL_S; ++ GH_PLL_CORE_CTRL_S arm_pll; ++ u32 div0118; ++ u32 apb_freq; ++ arm_pll.all = gk_rct_readl(GK_VA_RCT + 0x014); ++ div0118 = gk_rct_readl(GK_VA_RCT + 0x0118); ++ if(div0118 * arm_pll.bitc.fbdiv * arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2) ++ { ++ apb_freq = (24 * arm_pll.bitc.fbdiv * 1000000)/(div0118 * 4 * arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2); ++ } ++ else ++ { ++ apb_freq = GK_APB_FREQ; ++ } ++ ++ return apb_freq; ++} ++EXPORT_SYMBOL(get_apb_bus_freq_hz); ++ ++u32 get_uart_freq_hz(void) ++{ ++ return (u32)GK_UART_FREQ; ++} ++EXPORT_SYMBOL(get_uart_freq_hz); ++ ++u32 get_ssi0_freq_hz(void) ++{ ++ u32 div = gk_rct_readl(GK_VA_RCT + 0x0030) & 0xFF; ++ if(div == 0) ++ { ++ div = 8; ++ } ++ return (get_apb_bus_freq_hz()/div); ++} ++EXPORT_SYMBOL(get_ssi0_freq_hz); ++ ++u32 get_ssi1_freq_hz(void) ++{ ++ u32 div = gk_rct_readl(GK_VA_RCT + 0x00A0) & 0xFF; ++ if(div == 0) ++ { ++ div = 8; ++ } ++ return (get_apb_bus_freq_hz()/div); ++} ++EXPORT_SYMBOL(get_ssi1_freq_hz); ++ ++u32 get_sd_freq_hz(void) ++{ ++ typedef union { ++ u32 all; ++ struct { ++ u32 fbdiv : 12; ++ u32 pstdiv1 : 3; ++ u32 : 1; ++ u32 pstdiv2 : 3; ++ u32 : 1; ++ u32 refdiv : 6; ++ u32 : 6; ++ } bitc; ++ } GH_PLL_CORE_CTRL_S; ++ GH_PLL_CORE_CTRL_S arm_pll; ++ u32 div0018; ++ u32 sd_freq; ++ arm_pll.all = gk_rct_readl(GK_VA_RCT + 0x014); ++ div0018 = gk_rct_readl(GK_VA_RCT + 0x0018); ++ if(div0018 * arm_pll.bitc.fbdiv * arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2) ++ { ++ sd_freq = (24 * arm_pll.bitc.fbdiv * 1000000)/(div0018 * arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2); ++ } ++ else ++ { ++ sd_freq = GK_SD_FREQ; ++ } ++ return sd_freq; ++} ++EXPORT_SYMBOL(get_sd_freq_hz); ++ ++void set_sd_rct(u32 freq) ++{ ++ typedef union { ++ u32 all; ++ struct { ++ u32 fbdiv : 12; ++ u32 pstdiv1 : 3; ++ u32 : 1; ++ u32 pstdiv2 : 3; ++ u32 : 1; ++ u32 refdiv : 6; ++ u32 : 6; ++ } bitc; ++ } GH_PLL_CORE_CTRL_S; ++ GH_PLL_CORE_CTRL_S arm_pll; ++ u32 div0018; ++ arm_pll.all = gk_rct_readl(GK_VA_RCT + 0x014); ++ div0018 = gk_rct_readl(GK_VA_RCT + 0x0018); ++ if(div0018 * arm_pll.bitc.fbdiv * arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2) ++ { ++ div0018 = (24 * arm_pll.bitc.fbdiv * 1000000)/(arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2); ++ div0018 /= freq; ++ gk_rct_writel(GK_VA_RCT + 0x0018, div0018); ++ } ++} ++EXPORT_SYMBOL(set_sd_rct); ++ ++u32 get_audio_clk_freq(void) ++{ ++ typedef union { ++ u32 all; ++ struct { ++ u32 fbdiv : 12; ++ u32 pstdiv1 : 3; ++ u32 : 1; ++ u32 pstdiv2 : 3; ++ u32 : 1; ++ u32 refdiv : 6; ++ u32 : 6; ++ } bitc; ++ } GH_PLL_CORE_CTRL_S; ++ GH_PLL_CORE_CTRL_S arm_pll; ++ u32 PST_div; ++ u32 PRE_div; ++ u32 audio_freq; ++ u32 FRAC; ++ arm_pll.all = gk_rct_readl(GK_VA_RCT + 0x024); ++ FRAC = gk_rct_readl(GK_VA_RCT + 0x078); ++ PST_div = gk_rct_readl(GK_VA_RCT + 0x084); ++ PRE_div = gk_rct_readl(GK_VA_RCT + 0x080); ++ if(PST_div * PRE_div * arm_pll.bitc.fbdiv * arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2) ++ { ++ u64 FRAC_c; ++ u64 div_all; ++ FRAC_c = FRAC; ++ FRAC_c *= 15625; ++ FRAC_c *= 24; ++ div_all = 262144 * PST_div * PRE_div * arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2; ++ FRAC_c += (div_all>>1); ++ do_div((FRAC_c), (div_all)); \ ++ audio_freq = (24 * (arm_pll.bitc.fbdiv * 1000000))/(PST_div * PRE_div * arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2); ++ audio_freq += (u32)FRAC_c; ++ } ++ else ++ { ++ audio_freq = 12288000; ++ } ++ return audio_freq; ++} ++EXPORT_SYMBOL(get_audio_clk_freq); ++ +diff --git a/arch/arm/mach-gk710x/vi.c b/arch/arm/mach-gk710x/vi.c +new file mode 100644 +index 00000000..7e1b626a +--- /dev/null ++++ b/arch/arm/mach-gk710x/vi.c +@@ -0,0 +1,51 @@ ++/* ++ * arch/arm/mach-gk/vi.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++ ++#include ++#include ++ ++/* ==========================================================================*/ ++struct i2c_board_info gk_board_vi_infos[2] = { ++ [0] = { ++ .type = "gk_vi0", ++ .addr = 0x02, ++ }, ++ [1] = { ++ .type = "gk_vi1", ++ .addr = 0x03, ++ }, ++}; ++ ++struct i2c_board_info gk_board_hdmi_infos[2] = { ++ [0] = { ++ .type = "rtc8563", ++ .addr = 0x51, ++ }, ++ [1] = { ++ .type = "bma250", ++ .addr = 0x18, ++ }, ++}; ++ +diff --git a/arch/arm/mach-gk710xs/Kconfig b/arch/arm/mach-gk710xs/Kconfig +new file mode 100644 +index 00000000..a5a5247d +--- /dev/null ++++ b/arch/arm/mach-gk710xs/Kconfig +@@ -0,0 +1,38 @@ ++# ++# arch/arm/mach-gk710x/Kconfig ++# ++# History: ++# 2014/06/18 - [Kewell Liu] created file ++# ++# Copyright (C) 2002-2016, Goke Microelectronics China. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++# ++ ++if ARCH_GK710XS ++ ++config GK710XS_SDIO2 ++ bool "Gk710xs select SDIO2 enable" ++ default n ++ help ++ select SDIO2 enable. ++ ++#config MACH_GK7102S_ELEC_SC1135_V1_00 ++# depends on MACH_GK7102S ++# bool "GK7102S Elec Board" ++# help ++# select ELEC GK7102S + SC1135 Board ++endif ++ +diff --git a/arch/arm/mach-gk710xs/Makefile b/arch/arm/mach-gk710xs/Makefile +new file mode 100644 +index 00000000..1b837c23 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/Makefile +@@ -0,0 +1,12 @@ ++ ++obj-$(CONFIG_ARCH_GK710XS) += gk710xs.o ++obj-$(CONFIG_ARCH_GK710XS) += irq.o ++obj-$(CONFIG_ARCH_GK710XS) += rct.o ++obj-$(CONFIG_ARCH_GK710XS) += mdma.o dma.o ++obj-$(CONFIG_ARCH_GK710XS) += vi.o ++obj-$(CONFIG_ARCH_GK710XS) += mach-gk710xs.o ++ ++ccflags-$(CONFIG_ARCH_GK710XS) += -D__LINUX__ ++ ++ccflags-$(CONFIG_ARCH_GK710XS) += -Iarch/arm/mach-gk710xs/include ++ +diff --git a/arch/arm/mach-gk710xs/Makefile.boot b/arch/arm/mach-gk710xs/Makefile.boot +new file mode 100644 +index 00000000..2fa061fd +--- /dev/null ++++ b/arch/arm/mach-gk710xs/Makefile.boot +@@ -0,0 +1,6 @@ ++ ++zreladdr-y := $(shell printf "0x%08x" $$(($(CONFIG_PHYS_OFFSET) + $(TEXT_OFFSET)))) ++params_phys-y := $(shell printf "0x%08x" $$(($(CONFIG_PHYS_OFFSET) + 0x100))) ++ ++dtb-y += gk710xs-evb.dtb ++ +diff --git a/arch/arm/mach-gk710xs/dma.c b/arch/arm/mach-gk710xs/dma.c +new file mode 100644 +index 00000000..68e8eab7 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/dma.c +@@ -0,0 +1,508 @@ ++/* ++ * arch/arm/mach-gk/dma.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static struct dma_s G_dma; ++static spinlock_t dma_lock; ++static gk_dma_req_t *dummy_descriptor = NULL; ++static dma_addr_t dummy_descriptor_phys; ++ ++#ifdef CONFIG_GK_DMA_PROC ++static const char dma_proc_name[] = "dma"; ++static struct proc_dir_entry *dma_file; ++ ++static int gk_dma_proc_read(char *buf, char **start, off_t off, ++ int len, int *eof, void *data) ++{ ++ char *p = buf; ++ ++ p += sprintf(p, "You can add something here to debug DMA \n"); ++ ++ return p - buf; ++} ++#endif ++ ++extern void gk_usb_dma_irq(void); ++static irqreturn_t gk_dma_int_handler(int irq, void *dev_id) ++{ ++ struct dma_s *dma; ++ int i; ++ int j; ++ u32 ireg; ++ ++ dma = (struct dma_s *)dev_id; ++ ++ ireg = gk_dma_readl(DMA_INT_REG); ++ for (i = 0; i < NUM_DMA_CHANNELS; i++) { ++ if (ireg & (0x1 << i)) { ++ dma->chan[i].status = gk_dma_readl(DMA_CHAN_STA_REG(i)); ++ gk_dma_writel(DMA_CHAN_STA_REG(i), 0); ++ ++ for (j = 0; j < dma->chan[i].irq_count; j++) { ++ if (dma->chan[i].irq[j].enabled == 1) { ++ dma->chan[i].irq[j].handler( ++ dma->chan[i].irq[j].harg, ++ dma->chan[i].status); ++ } ++ } ++ } ++ } ++#if 0 ++ if ((ireg & 0x8) || (ireg & 0x1)) { ++ //if (ireg & 0x8) { ++ //printk("@:%x\n", ireg); ++ //printk("$\n"); ++ gk_usb_dma_irq(); ++ } ++#endif ++ return IRQ_HANDLED; ++} ++ ++#if (DMA_SUPPORT_DMA_FIOS == 1) ++static irqreturn_t gk_dma_fios_int_handler(int irq, void *dev_id) ++{ ++ struct dma_s *dma; ++ int i; ++ u32 ireg; ++ ++ dma = (struct dma_s *)dev_id; ++ ++ ireg = gk_dma_readl(DMA_FIOS_INT_REG); ++ if (ireg & DMA_INT_CHAN0) { ++ dma->chan[FIO_DMA_CHAN].status = ++ gk_dma_readl(DMA_FIOS_CHAN_STA_REG(FIO_DMA_CHAN)); ++ gk_dma_writel(DMA_FIOS_CHAN_STA_REG(FIO_DMA_CHAN), 0); ++ ++ for (i = 0; i < dma->chan[FIO_DMA_CHAN].irq_count; i++) { ++ if (dma->chan[FIO_DMA_CHAN].irq[i].enabled == 1) { ++ dma->chan[FIO_DMA_CHAN].irq[i].handler( ++ dma->chan[FIO_DMA_CHAN].irq[i].harg, ++ dma->chan[FIO_DMA_CHAN].status); ++ } ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++#endif ++ ++int gk_dma_request_irq(int chan, ++ gk_dma_handler handler, void *harg) ++{ ++ int retval = 0; ++ int i; ++ unsigned long flags; ++ if (unlikely(chan < 0 || chan >= NUM_DMA_CHANNELS)) { ++ pr_err("%s: chan[%d] < NUM_DMA_CHANNELS[%d]!\n", ++ __func__, chan, NUM_DMA_CHANNELS); ++ retval = -EINVAL; ++ goto gk_dma_request_irq_exit_na; ++ } ++ ++ if (unlikely(handler == NULL)) { ++ pr_err("%s: handler is NULL!\n", __func__); ++ retval = -EINVAL; ++ goto gk_dma_request_irq_exit_na; ++ } ++ ++ spin_lock_irqsave(&dma_lock, flags); ++ if (unlikely(G_dma.chan[chan].irq_count > ++ MAX_DMA_CHANNEL_IRQ_HANDLERS)) { ++ pr_err("%s: chan[%d]'s irq_count[%d] > " ++ "MAX_DMA_CHANNEL_IRQ_HANDLERS[%d]!\n", ++ __func__, chan, G_dma.chan[chan].irq_count, ++ MAX_DMA_CHANNEL_IRQ_HANDLERS); ++ retval = -EINVAL; ++ goto gk_dma_request_irq_exit; ++ } ++ ++ for (i = 0; i < MAX_DMA_CHANNEL_IRQ_HANDLERS; i++) { ++ if (G_dma.chan[chan].irq[i].handler == NULL) { ++ G_dma.chan[chan].irq[i].enabled = 0; ++ G_dma.chan[chan].irq[i].handler = handler; ++ G_dma.chan[chan].irq[i].harg = harg; ++ G_dma.chan[chan].irq_count++; ++ break; ++ } ++ } ++ ++gk_dma_request_irq_exit: ++ spin_unlock_irqrestore(&dma_lock, flags); ++ ++gk_dma_request_irq_exit_na: ++ return retval; ++} ++EXPORT_SYMBOL(gk_dma_request_irq); ++ ++void gk_dma_free_irq(int chan, gk_dma_handler handler) ++{ ++ int i; ++ unsigned long flags; ++ ++ if (unlikely(chan < 0 || chan >= NUM_DMA_CHANNELS)) { ++ pr_err("%s: chan[%d] < NUM_DMA_CHANNELS[%d]!\n", ++ __func__, chan, NUM_DMA_CHANNELS); ++ return; ++ } ++ ++ if (unlikely(handler == NULL)) { ++ pr_err("%s: handler is NULL!\n", __func__); ++ return; ++ } ++ ++ spin_lock_irqsave(&dma_lock, flags); ++ if (unlikely(G_dma.chan[chan].irq_count > ++ MAX_DMA_CHANNEL_IRQ_HANDLERS)) { ++ pr_err("%s: chan[%d]'s irq_count[%d] > " ++ "MAX_DMA_CHANNEL_IRQ_HANDLERS[%d]!\n", ++ __func__, chan, G_dma.chan[chan].irq_count, ++ MAX_DMA_CHANNEL_IRQ_HANDLERS); ++ goto gk_dma_free_irq_exit; ++ } ++ ++ for (i = 0; i < MAX_DMA_CHANNEL_IRQ_HANDLERS; i++) { ++ if (G_dma.chan[chan].irq[i].handler == handler) { ++ G_dma.chan[chan].irq[i].enabled = 0; ++ G_dma.chan[chan].irq[i].handler = NULL; ++ G_dma.chan[chan].irq[i].harg = NULL; ++ G_dma.chan[chan].irq_count--; ++ break; ++ } ++ } ++ ++ for (i = i + 1; i < MAX_DMA_CHANNEL_IRQ_HANDLERS; i++) { ++ if (G_dma.chan[chan].irq[i].handler != NULL) { ++ G_dma.chan[chan].irq[i - 1].enabled = ++ G_dma.chan[chan].irq[i].enabled; ++ G_dma.chan[chan].irq[i - 1].handler = ++ G_dma.chan[chan].irq[i].handler; ++ G_dma.chan[chan].irq[i - 1].harg = ++ G_dma.chan[chan].irq[i].harg; ++ G_dma.chan[chan].irq[i].handler = NULL; ++ G_dma.chan[chan].irq[i].harg = NULL; ++ G_dma.chan[chan].irq[i].enabled = 0; ++ } ++ } ++ ++gk_dma_free_irq_exit: ++ spin_unlock_irqrestore(&dma_lock, flags); ++} ++EXPORT_SYMBOL(gk_dma_free_irq); ++ ++int gk_dma_enable_irq(int chan, gk_dma_handler handler) ++{ ++ int retval = 0; ++ int i; ++ unsigned long flags; ++ ++ if (unlikely(chan < 0 || chan >= NUM_DMA_CHANNELS)) { ++ pr_err("%s: chan[%d] < NUM_DMA_CHANNELS[%d]!\n", ++ __func__, chan, NUM_DMA_CHANNELS); ++ retval = -EINVAL; ++ goto gk_dma_enable_irq_na; ++ } ++ ++ if (unlikely(handler == NULL)) { ++ pr_err("%s: handler is NULL!\n", __func__); ++ retval = -EINVAL; ++ goto gk_dma_enable_irq_na; ++ } ++ ++ spin_lock_irqsave(&dma_lock, flags); ++ for (i = 0; i < MAX_DMA_CHANNEL_IRQ_HANDLERS; i++) { ++ if (G_dma.chan[chan].irq[i].handler == NULL) { ++ retval = -EINVAL; ++ pr_err("%s: can't find 0x%x!\n", ++ __func__, (u32)handler); ++ break; ++ } ++ ++ if (G_dma.chan[chan].irq[i].handler == handler) { ++ G_dma.chan[chan].irq[i].enabled = 1; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&dma_lock, flags); ++ ++gk_dma_enable_irq_na: ++ return retval; ++} ++EXPORT_SYMBOL(gk_dma_enable_irq); ++ ++int gk_dma_disable_irq(int chan, gk_dma_handler handler) ++{ ++ int retval = 0; ++ int i; ++ unsigned long flags; ++ ++ if (unlikely(chan < 0 || chan >= NUM_DMA_CHANNELS)) { ++ pr_err("%s: chan[%d] < NUM_DMA_CHANNELS[%d]!\n", ++ __func__, chan, NUM_DMA_CHANNELS); ++ retval = -EINVAL; ++ goto gk_dma_disable_irq_na; ++ } ++ ++ if (unlikely(handler == NULL)) { ++ pr_err("%s: handler is NULL!\n", __func__); ++ retval = -EINVAL; ++ goto gk_dma_disable_irq_na; ++ } ++ ++ spin_lock_irqsave(&dma_lock, flags); ++ for (i = 0; i < MAX_DMA_CHANNEL_IRQ_HANDLERS; i++) { ++ if (G_dma.chan[chan].irq[i].handler == NULL) { ++ retval = -EINVAL; ++ pr_err("%s: can't find 0x%x!\n", ++ __func__, (u32)handler); ++ break; ++ } ++ ++ if (G_dma.chan[chan].irq[i].handler == handler) { ++ G_dma.chan[chan].irq[i].enabled = 0; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&dma_lock, flags); ++ ++gk_dma_disable_irq_na: ++ return retval; ++} ++EXPORT_SYMBOL(gk_dma_disable_irq); ++ ++static inline int gk_req_dma(gk_dma_req_t * req, int chan) ++{ ++ int retval = 0; ++ u32 ctr = 0; ++ ++ if (unlikely(req->xfr_count > 0x003fffff)) { ++ pr_err("%s: xfr_count[0x%x] out of range!\n", ++ __func__, req->xfr_count); ++ retval = -EINVAL; ++ goto gk_req_dma_exit; ++ } ++ ++ gk_dma_writel(DMA_CHAN_STA_REG(chan), 0); ++ ++ if (req->next == NULL) { ++ gk_dma_writel(DMA_CHAN_SRC_REG(chan), req->src); ++ ++ gk_dma_writel(DMA_CHAN_DST_REG(chan), req->dst); ++ ++ ctr |= (req->attr | req->xfr_count); ++ ctr &= ~DMA_CHANX_CTR_D; ++ ctr |= DMA_CHANX_CTR_EN; ++ ++ } else {/* Descriptor mode */ ++ gk_dma_writel((u32) req, DMA_CHAN_DA_REG(chan)); ++ ++ ctr |= DMA_CHANX_CTR_D; ++ ctr |= DMA_CHANX_CTR_EN; ++ } ++ gk_dma_writel(DMA_CHAN_CTR_REG(chan), ctr); ++ ++gk_req_dma_exit: ++ return retval; ++} ++ ++int gk_dma_xfr(gk_dma_req_t *req, int chan) ++{ ++ int retval = 0; ++ ++ ++#ifdef CHECK_DMA_CHAN_USE_FLAG ++ unsigned long flags; ++#endif ++ ++ if (unlikely(chan < 0 || chan >= NUM_DMA_CHANNELS)) { ++ pr_err("%s: chan[%d] < NUM_DMA_CHANNELS[%d]!\n", ++ __func__, chan, NUM_DMA_CHANNELS); ++ retval = -EINVAL; ++ goto gk_dma_xfr_exit; ++ } ++ ++ if (unlikely(req == NULL)) { ++ pr_err("%s: req is NULL!\n", __func__); ++ retval = -EINVAL; ++ goto gk_dma_xfr_exit; ++ } ++ ++#ifdef CHECK_DMA_CHAN_USE_FLAG ++ spin_lock_irqsave(&dma_lock, flags); ++ G_dma.chan[chan].use_flag = 1; ++ spin_unlock_irqrestore(&dma_lock, flags); ++#endif ++ ++ retval = gk_req_dma(req, chan); ++ ++gk_dma_xfr_exit: ++ return retval; ++} ++EXPORT_SYMBOL(gk_dma_xfr); ++ ++int gk_dma_desc_xfr(dma_addr_t desc_addr, int chan) ++{ ++ ++ ++ if (unlikely(desc_addr == 0)) { ++ pr_err("%s: desc_addr is NULL!\n", __func__); ++ return -EINVAL; ++ } ++ ++ if (unlikely((desc_addr & 0x7) != 0)) { ++ pr_err("%s: desc_addr isn't aligned!\n", __func__); ++ return -EINVAL; ++ } ++ ++ if (unlikely(chan < 0 || chan >= NUM_DMA_CHANNELS)) { ++ pr_err("%s: chan[%d] < NUM_DMA_CHANNELS[%d]!\n", ++ __func__, chan, NUM_DMA_CHANNELS); ++ return -EINVAL; ++ } ++ ++ if (gk_dma_readl(DMA_CHAN_CTR_REG(chan)) & DMA_CHANX_CTR_EN) ++ pr_err("%s: dma (channel = %d) is still enabled!\n", __func__, chan); ++ ++ gk_dma_writel(DMA_CHAN_DA_REG(chan), desc_addr); ++ ++ gk_dma_writel(DMA_CHAN_CTR_REG(chan), DMA_CHANX_CTR_EN | DMA_CHANX_CTR_D); ++ ++ return 0; ++} ++EXPORT_SYMBOL(gk_dma_desc_xfr); ++ ++int gk_dma_desc_stop(int chan) ++{ ++ ++ ++ if (unlikely(chan < 0 || chan >= NUM_DMA_CHANNELS)) { ++ pr_err("%s: chan[%d] < NUM_DMA_CHANNELS[%d]!\n", ++ __func__, chan, NUM_DMA_CHANNELS); ++ return -EINVAL; ++ } ++ ++ /* Disable DMA: following sequence is not mentioned at APM.*/ ++ if (gk_dma_readl(DMA_CHAN_CTR_REG(chan)) & DMA_CHANX_CTR_EN) { ++ gk_dma_writel(DMA_CHAN_STA_REG(chan), DMA_CHANX_STA_DD); ++ ++ ++ gk_dma_writel(DMA_CHAN_DA_REG(chan), dummy_descriptor_phys); ++ ++ gk_dma_writel(DMA_CHAN_CTR_REG(chan), 0x28000000); ++ ++ ++ udelay(1); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(gk_dma_desc_stop); ++ ++int gk_dma_read_ctrl_reg(int chan) ++{ ++ return gk_dma_readl(DMA_CHAN_CTR_REG(chan));//add by DONALD, for audio drv use, mask different register addr macro value. ++} ++EXPORT_SYMBOL(gk_dma_read_ctrl_reg); ++ ++ ++int __init gk_init_dma(void) ++{ ++ int retval = 0; ++ int i; ++ struct dma_s *dma = &G_dma; ++ gk_dma_req_t *dma_desc_array; ++ ++ spin_lock_init(&dma_lock); ++ memset(&G_dma, 0x0, sizeof(G_dma)); ++ ++ dummy_descriptor = dma_alloc_coherent(NULL, ++ sizeof(gk_dma_req_t) * 4, ++ &dummy_descriptor_phys, GFP_KERNEL); ++ if (!dummy_descriptor) { ++ retval = -ENOMEM; ++ goto gk_init_dma_exit; ++ } ++ ++ dma_desc_array = (gk_dma_req_t *)dummy_descriptor; ++ dma_desc_array->attr = DMA_DESC_EOC | DMA_DESC_WM | DMA_DESC_NI | ++ DMA_DESC_IE | DMA_DESC_ST | DMA_DESC_ID; ++ dma_desc_array->src = 0; ++ dma_desc_array->next = (gk_dma_req_t *)dummy_descriptor_phys; ++ dma_desc_array->rpt = dummy_descriptor_phys + sizeof(gk_dma_req_t); ++ dma_desc_array->dst = dummy_descriptor_phys + sizeof(gk_dma_req_t) * 2; ++ dma_desc_array->xfr_count = 0; ++ ++ retval = request_irq(DMA_IRQ, gk_dma_int_handler, ++ IRQ_TYPE_LEVEL_HIGH, "gk-dma", dma); ++ if (retval) { ++ pr_err("%s: request_irq %d fail %d!\n", ++ __func__, DMA_IRQ, retval); ++ goto gk_init_dma_exit; ++ } ++ ++ for (i = 0; i < NUM_DMA_CHANNELS; i++) { ++ gk_dma_writel(DMA_CHAN_STA_REG(i), 0); ++ ++ gk_dma_writel(DMA_CHAN_CTR_REG(i), 0x38000000); ++ ++ } ++ ++#if (DMA_SUPPORT_DMA_FIOS == 1) ++ retval = request_irq(DMA_FIOS_IRQ, gk_dma_fios_int_handler, ++ IRQ_TYPE_LEVEL_HIGH, "gk-fios-dma", dma); ++ if (retval){ ++ pr_err("%s: request_irq %d fail %d!\n", ++ __func__, DMA_FIOS_IRQ, retval); ++ goto gk_init_dma_exit; ++ } ++ gk_dma_writel(DMA_FIOS_CHAN_STA_REG(0), 0); ++ ++ ++ gk_dma_writel(DMA_FIOS_CHAN_CTR_REG(0), 0x38000000); ++ ++#endif ++ ++#ifdef CONFIG_GK_DMA_PROC ++ dma_file = create_proc_entry(dma_proc_name, S_IRUGO | S_IWUSR, ++ get_gk_proc_dir()); ++ if (dma_file == NULL) { ++ retval = -ENOMEM; ++ pr_err("%s: for %s fail!\n", __func__, dma_proc_name); ++ } else { ++ dma_file->read_proc = gk_dma_proc_read; ++ dma_file->write_proc = NULL; ++ } ++#endif ++ ++gk_init_dma_exit: ++ return retval; ++} ++ +diff --git a/arch/arm/mach-gk710xs/gk710xs.c b/arch/arm/mach-gk710xs/gk710xs.c +new file mode 100644 +index 00000000..a9d92dba +--- /dev/null ++++ b/arch/arm/mach-gk710xs/gk710xs.c +@@ -0,0 +1,736 @@ ++/* ++ * linux/arch/arm/mach-gk/gk.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * 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. ++ * ++ */ ++ ++//#define KE_DEBUG ++ ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++extern u8* load_data_init(void); ++ ++ ++struct gk_mem_map_desc ++{ ++ char name[32]; ++ struct map_desc io_desc; ++}; ++ ++/* the module name MUST match hardware.h */ ++#define IOMAP_DESC_ENTRY(module, len) { \ ++ .virtual = GK_VA_##module, \ ++ .pfn = __phys_to_pfn(GK_PA_##module), \ ++ .length = (len), \ ++ .type = MT_DEVICE \ ++} ++ ++#define GK_IOMAP(module_name, module, len) { \ ++ .name = module_name, \ ++ IOMAP_DESC_ENTRY(module, len), \ ++} ++ ++ ++#define GK_IO_DESC_AHB_ID 0 ++#define GK_IO_DESC_APB_ID 1 ++#define GK_IO_DESC_PPM_ID 2 ++#define GK_IO_DESC_BSB_ID 3 ++#define GK_IO_DESC_DSP_ID 4 ++#define GK_IO_DESC_USR_ID 5 ++ ++static struct gk_mem_map_desc gk_mem_desc[] = ++{ ++ // reserved 0xF0000000 to hal1, and 0xF1000000 to hal2 ++ // used in get_hal1_virt & get_hal2_virt; ++ [GK_IO_DESC_AHB_ID] = ++ {/*0*/ ++ .name = "AHB", ++ .io_desc = ++ { ++ .virtual= GK_VA_AHB_BASE, ++ .pfn = __phys_to_pfn(GK_PA_AHB_BASE), ++ .length = 0x01000000, ++ .type = MT_DEVICE, ++ }, ++ }, ++ [GK_IO_DESC_APB_ID] = ++ {/*1*/ ++ .name = "APB", ++ .io_desc = ++ { ++ .virtual= GK_VA_APB_BASE, ++ .pfn = __phys_to_pfn(GK_PA_APB_BASE), ++ .length = 0x01000000, ++ .type = MT_DEVICE, ++ }, ++ }, ++ [GK_IO_DESC_PPM_ID] = ++ {/*2*/ ++ .name = "PPM", /*Private Physical Memory*/ ++ .io_desc = ++ { ++ .virtual= 0xc0000000, ++ .pfn = __phys_to_pfn(0xc0000000/*DEFAULT_MEM_START*/), ++ .length = CONFIG_PHYS_OFFSET-0xc0000000, ++ .type = MT_MEMORY, ++ }, ++ }, ++ [GK_IO_DESC_BSB_ID] = ++ {/*3*/ ++ .name = "BSB", ++ .io_desc = ++ { ++ .virtual= 0xf5000000, ++ .pfn = __phys_to_pfn(0xc2800000), ++ .length = 0x00200000, ++ .type = MT_MEMORY, ++ }, ++ }, ++ [GK_IO_DESC_DSP_ID] = ++ {/*4*/ ++ .name = "DSP", ++ .io_desc = ++ { ++ .virtual= 0xf6000000, ++ .pfn = __phys_to_pfn(0xC2a00000), ++ .length = 0x01500000, ++ .type = MT_MEMORY, ++ }, ++ }, ++ [GK_IO_DESC_USR_ID] = ++ {/*5*/ ++ .name = "USR", ++ .io_desc = ++ { ++ .virtual= 0xfe000000, // dsp_size <= 0xfe000000-0xf6000000 ++ .pfn = __phys_to_pfn(0xC3FF0000), ++ .length = 0x00010000, ++ .type = MT_MEMORY, ++ }, ++ }, ++}; ++ ++ ++ ++#if 1 ++//-----------HAL1------------- ++u32 get_hal1_virt(void) ++{ ++ return 0xF2000000; ++} ++EXPORT_SYMBOL(get_hal1_virt); ++ ++//-----------HAL2------------- ++u32 get_hal2_virt(void) ++{ ++ return 0xF3000000; ++} ++EXPORT_SYMBOL(get_hal2_virt); ++ ++//-----------AHB------------- ++u32 get_ahb_phys(void) ++{ ++ return __pfn_to_phys(gk_mem_desc[GK_IO_DESC_AHB_ID].io_desc.pfn); ++} ++EXPORT_SYMBOL(get_ahb_phys); ++ ++u32 get_ahb_virt(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_AHB_ID].io_desc.virtual; ++} ++EXPORT_SYMBOL(get_ahb_virt); ++ ++u32 get_ahb_size(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_AHB_ID].io_desc.length; ++} ++EXPORT_SYMBOL(get_ahb_size); ++ ++//-----------APB------------- ++u32 get_apb_phys(void) ++{ ++ return __pfn_to_phys(gk_mem_desc[GK_IO_DESC_APB_ID].io_desc.pfn); ++} ++EXPORT_SYMBOL(get_apb_phys); ++ ++u32 get_apb_virt(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_APB_ID].io_desc.virtual; ++} ++EXPORT_SYMBOL(get_apb_virt); ++ ++u32 get_apb_size(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_APB_ID].io_desc.length; ++} ++EXPORT_SYMBOL(get_apb_size); ++ ++//-----------PPM------------- ++u32 get_ppm_phys(void) ++{ ++ return __pfn_to_phys(gk_mem_desc[GK_IO_DESC_PPM_ID].io_desc.pfn); ++} ++EXPORT_SYMBOL(get_ppm_phys); ++ ++u32 get_ppm_virt(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_PPM_ID].io_desc.virtual; ++} ++EXPORT_SYMBOL(get_ppm_virt); ++ ++u32 get_ppm_size(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_PPM_ID].io_desc.length; ++} ++EXPORT_SYMBOL(get_ppm_size); ++ ++//-----------DSP------------- ++u32 get_dspmem_virt(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_DSP_ID].io_desc.virtual; ++} ++EXPORT_SYMBOL(get_dspmem_virt); ++ ++u32 get_dspmem_size(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_DSP_ID].io_desc.length; ++} ++EXPORT_SYMBOL(get_dspmem_size); ++ ++u32 get_dspmem_phys(void) ++{ ++ return __pfn_to_phys(gk_mem_desc[GK_IO_DESC_DSP_ID].io_desc.pfn); ++} ++EXPORT_SYMBOL(get_dspmem_phys); ++ ++//-----------BSB------------- ++u32 get_bsbmem_phys(void) ++{ ++ return __pfn_to_phys(gk_mem_desc[GK_IO_DESC_BSB_ID].io_desc.pfn); ++} ++EXPORT_SYMBOL(get_bsbmem_phys); ++ ++u32 get_bsbmem_virt(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_BSB_ID].io_desc.virtual; ++} ++EXPORT_SYMBOL(get_bsbmem_virt); ++ ++u32 get_bsbmem_size(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_BSB_ID].io_desc.length; ++} ++EXPORT_SYMBOL(get_bsbmem_size); ++u32 get_usrmem_phys(void) ++{ ++ return __pfn_to_phys(gk_mem_desc[GK_IO_DESC_USR_ID].io_desc.pfn); ++} ++EXPORT_SYMBOL(get_usrmem_phys); ++u32 get_usrmem_virt(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_USR_ID].io_desc.virtual; ++} ++EXPORT_SYMBOL(get_usrmem_virt); ++u32 get_usrmem_size(void) ++{ ++ return gk_mem_desc[GK_IO_DESC_USR_ID].io_desc.length; ++} ++EXPORT_SYMBOL(get_usrmem_size); ++ ++ ++ ++u32 gk_phys_to_virt(u32 paddr) ++{ ++ int i; ++ u32 phystart; ++ u32 phylength; ++ u32 phyoffset; ++ u32 vstart; ++ ++ for (i = 0; i < ARRAY_SIZE(gk_mem_desc); i++) ++ { ++ phystart = __pfn_to_phys(gk_mem_desc[i].io_desc.pfn); ++ phylength = gk_mem_desc[i].io_desc.length; ++ vstart = gk_mem_desc[i].io_desc.virtual; ++ if ((paddr >= phystart) && (paddr < (phystart + phylength))) ++ { ++ phyoffset = paddr - phystart; ++ return (vstart + phyoffset); ++ } ++ } ++ ++ return __phys_to_virt(paddr); ++} ++EXPORT_SYMBOL(gk_phys_to_virt); ++ ++u32 gk_virt_to_phys(u32 vaddr) ++{ ++ int i; ++ u32 phystart; ++ u32 vlength; ++ u32 voffset; ++ u32 vstart; ++ ++ for (i = 0; i < ARRAY_SIZE(gk_mem_desc); i++) ++ { ++ phystart = __pfn_to_phys(gk_mem_desc[i].io_desc.pfn); ++ vlength = gk_mem_desc[i].io_desc.length; ++ vstart = gk_mem_desc[i].io_desc.virtual; ++ if ((vaddr >= vstart) && (vaddr < (vstart + vlength))) ++ { ++ voffset = vaddr - vstart; ++ return (phystart + voffset); ++ } ++ } ++ ++ return __virt_to_phys(vaddr); ++} ++EXPORT_SYMBOL(gk_virt_to_phys); ++#endif ++ ++void get_stepping_info(int *chip, int *major, int *minor) ++{ ++ *chip = 0x5; ++ *major = 0x1; ++ *minor = 0x0; ++} ++EXPORT_SYMBOL(get_stepping_info); ++ ++/* ==========================================================================*/ ++u64 gk_dmamask = DMA_BIT_MASK(32); ++EXPORT_SYMBOL(gk_dmamask); ++ ++ ++/* ==========================================================================*/ ++static struct proc_dir_entry *gk_proc_dir = NULL; ++ ++int __init gk_create_proc_dir(void) ++{ ++ int retval = 0; ++ ++ printk("create proc dir\n"); ++ ++ gk_proc_dir = proc_mkdir("goke", NULL); ++ if (!gk_proc_dir) ++ retval = -ENOMEM; ++ ++ return retval; ++} ++ ++struct proc_dir_entry *get_gk_proc_dir(void) ++{ ++ return gk_proc_dir; ++} ++EXPORT_SYMBOL(get_gk_proc_dir); ++ ++/* ==========================================================================*/ ++typedef void* (*hal_function_t) (unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) ; ++ ++struct hw_ops *g_hw; ++EXPORT_SYMBOL(g_hw); ++ ++#if HW_HAL_MODE ++HAL_IO(hw) ++#else ++DIR_IO(hw) ++#endif ++ ++#if ADC_HAL_MODE ++HAL_IO(adc) ++#else ++DIR_IO(adc) ++#endif ++#if AUD_HAL_MODE ++HAL_IO(aud) ++#else ++DIR_IO(aud) ++#endif ++#if CRY_HAL_MODE ++HAL_IO(cry) ++#else ++DIR_IO(cry) ++#endif ++#if DDR_HAL_MODE ++HAL_IO(ddr) ++#else ++DIR_IO(ddr) ++#endif ++#if DMA_HAL_MODE ++HAL_IO(dma) ++#else ++DIR_IO(dma) ++#endif ++#if DSP_HAL_MODE ++HAL_IO(dsp) ++#else ++DIR_IO(dsp) ++#endif ++#if ETH_HAL_MODE ++HAL_IO(eth) ++#else ++DIR_IO(eth) ++#endif ++#if GREG_HAL_MODE ++HAL_IO(greg) ++#else ++DIR_IO(greg) ++#endif ++#if GPIO_HAL_MODE ++HAL_IO(gpio) ++#else ++DIR_IO(gpio) ++#endif ++#if I2C_HAL_MODE ++HAL_IO(i2c) ++#else ++DIR_IO(i2c) ++#endif ++#if I2S_HAL_MODE ++HAL_IO(i2s) ++#else ++DIR_IO(i2s) ++#endif ++#if IR_HAL_MODE ++HAL_IO(ir) ++#else ++DIR_IO(ir) ++#endif ++#if IRQ_HAL_MODE ++HAL_IO(irq) ++#else ++DIR_IO(irq) ++#endif ++#if MCU_HAL_MODE ++HAL_IO(mcu) ++#else ++DIR_IO(mcu) ++#endif ++#if PWM_HAL_MODE ++HAL_IO(pwm) ++#else ++DIR_IO(pwm) ++#endif ++#if RCT_HAL_MODE ++HAL_IO(rct) ++#else ++DIR_IO(rct) ++#endif ++#if SD_HAL_MODE ++HAL_IO(sd) ++#else ++DIR_IO(sd) ++#endif ++#if SF_HAL_MODE ++HAL_IO(sf) ++#else ++DIR_IO(sf) ++#endif ++#if SSI_HAL_MODE ++HAL_IO(ssi) ++#else ++DIR_IO(ssi) ++#endif ++#if TIMER_HAL_MODE ++HAL_IO(timer) ++#else ++DIR_IO(timer) ++#endif ++#if UART_HAL_MODE ++HAL_IO(uart) ++#else ++DIR_IO(uart) ++#endif ++#if USB_HAL_MODE ++HAL_IO(usb) ++#else ++DIR_IO(usb) ++#endif ++#if VOUT_HAL_MODE ++HAL_IO(vout) ++#else ++DIR_IO(vout) ++#endif ++#if WDT_HAL_MODE ++HAL_IO(wdt) ++#else ++DIR_IO(wdt) ++#endif ++#if EFUSE_HAL_MODE ++HAL_IO(efuse) ++#else ++DIR_IO(efuse) ++#endif ++#if USB_DMA_ADD_MODE ++unsigned char (*gk_usb_readb)(unsigned int ptr, unsigned int offset); ++unsigned short (*gk_usb_readw)(unsigned int ptr, unsigned int offset); ++unsigned int (*gk_usb_readl)(unsigned int ptr, unsigned int offset); ++void (*gk_usb_writeb)(unsigned int ptr, unsigned int offset, unsigned char value); ++void (*gk_usb_writew)(unsigned int ptr, unsigned int offset, unsigned short value); ++void (*gk_usb_writel)(unsigned int ptr, unsigned int offset, unsigned int value); ++ ++unsigned int (*gk_dma_readl)(unsigned int ptr); ++void (*gk_dma_writel)(unsigned int ptr, unsigned int value); ++#endif ++static inline unsigned int gk_hal_init (void *hal_base_address, unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4) ++{ ++ unsigned int rval=0; ++#if 1 ++ hal_function_t hal_init = (hal_function_t) (hal_base_address) ; ++ ++ g_hw = (struct hw_ops *)hal_init (arg0, arg1, arg2, arg3, arg4) ; ++ printk("hal version = %x \n", (u32)g_hw->get_version()); ++#endif ++ ++ return rval ; ++} ++ ++ ++static int __init early_boot_splash_logo(char *p) ++{ ++ printk("set boot splash logo = 1 \n"); ++ gk_boot_splash_logo = 1; ++ return 0; ++} ++early_param("boot_splash_logo_on", early_boot_splash_logo); ++ ++void __init gk_map_io(void) ++{ ++ int i; ++ u32 iop, ios, iov, hal_add; ++ u32 usr_phy_addr; ++ u32 bsb_phy_addr; ++ u32 bsb_size; ++ u32 dsp_phy_addr; ++ u32 dsp_size; ++#if 0 ++ u32 soc_type; //0:, 1:7102 ++#endif ++ u32 mem_size; ++ u32 mem_total; ++ u32 usr_size; //user used, cmem module ++ struct memblock_region *reg; ++ unsigned long kernelMemoryGet=0; ++ ++ /*************************/ ++ /* AHB */ ++ /*-----------------------*/ ++ /* APB */ ++ /*-----------------------*/ ++ /* PPM <3M> */ ++ /*-----------------------*/ ++ /* KER */ ++ /*-----------------------*/ ++ /* BSB <2M/4M> */ ++ /*-----------------------*/ ++ /* DSP */ ++ /*-----------------------*/ ++ /* USR <64K> */ ++ /*************************/ ++ ++ for (i = 0; i < GK_IO_DESC_BSB_ID; i++) ++ { ++ iop = __pfn_to_phys(gk_mem_desc[i].io_desc.pfn); ++ ios = gk_mem_desc[i].io_desc.length; ++ iov = gk_mem_desc[i].io_desc.virtual; ++ printk("%s: 0x%x 0x%x -- 0x%x\n", gk_mem_desc[i].name, iop, iov, ios); ++ if (ios > 0) ++ { ++ iotable_init(&(gk_mem_desc[i].io_desc), 1); ++ } ++ } ++ ++ /* calc mem_size by uboot params parsing*/ ++ for_each_memblock(memory, reg) ++ { ++ unsigned long pages = memblock_region_memory_end_pfn(reg) - ++ memblock_region_memory_base_pfn(reg); ++ kernelMemoryGet = pages >> (20 - PAGE_SHIFT); ++ } ++ mem_size = kernelMemoryGet*1024*1024; ++ ++#if 0 ++ soc_type = *(volatile u32 *)CONFIG_U2K_SOC_ADDR; ++ ++ /* if can't get correct value from uboot env, use GK7102 for default*/ ++ if(soc_type>1) ++ soc_type = 1; ++ ++ ++ ++ mem_total = *(volatile u32 *)CONFIG_U2K_TOTAL_MEM; ++ if(mem_total != 64 && mem_total != 128) ++ { ++ /* set mem_total and bsb size by chip ID*/ ++ switch(soc_type) ++ { ++ case CONFIG_SOC_GK7102: /*GK7102*/ ++ mem_total = 64*1024*1024; ++ //bsb_size = 0x200000; /*use 2M for GK7102*/ ++ break; ++ case CONFIG_SOC_GK7101: /*GK*/ ++ default: ++ mem_total = 128*1024*1024; ++ //bsb_size = 0x400000; /*use 4M for GK*/ ++ break; ++ } ++ } ++ else mem_total = mem_total*1024*1024; ++#else ++ mem_total = (*(volatile u32 *)CONFIG_U2K_TOTAL_MEM)*1024*1024; ++#endif ++ ++ bsb_size = *(volatile u32 *)CONFIG_U2K_BSB_ADDR; ++ usr_size = 0x10000; ++ usr_phy_addr = 0xC0000000 + mem_total - usr_size; ++ bsb_phy_addr = 0xC0000000 + get_ppm_size() + mem_size; ++ dsp_phy_addr = bsb_phy_addr + bsb_size; ++ dsp_size = mem_total - get_ppm_size() - mem_size - bsb_size - usr_size; ++ ++ gk_mem_desc[GK_IO_DESC_BSB_ID].io_desc.pfn = __phys_to_pfn(bsb_phy_addr); ++ gk_mem_desc[GK_IO_DESC_BSB_ID].io_desc.length = bsb_size; ++ ++ gk_mem_desc[GK_IO_DESC_DSP_ID].io_desc.pfn = __phys_to_pfn(dsp_phy_addr); ++ gk_mem_desc[GK_IO_DESC_DSP_ID].io_desc.length = dsp_size; ++ ++ gk_mem_desc[GK_IO_DESC_USR_ID].io_desc.pfn = __phys_to_pfn(usr_phy_addr); ++ gk_mem_desc[GK_IO_DESC_USR_ID].io_desc.length = usr_size; ++ ++ for (i = GK_IO_DESC_BSB_ID; i < ARRAY_SIZE(gk_mem_desc); i++) ++ { ++ iop = __pfn_to_phys(gk_mem_desc[i].io_desc.pfn); ++ ios = gk_mem_desc[i].io_desc.length; ++ iov = gk_mem_desc[i].io_desc.virtual; ++ printk("%s: 0x%x 0x%x -- 0x%x\n", gk_mem_desc[i].name, iop, iov, ios); ++ if (ios > 0) ++ { ++ iotable_init(&(gk_mem_desc[i].io_desc), 1); ++ } ++ } ++ ++ hal_add = *(volatile u32 *)CONFIG_U2K_HAL_ADDR; ++ gk_hal_init((void*)(gk_phys_to_virt(hal_add)), get_hal1_virt(), get_hal2_virt(), get_ahb_virt(), get_apb_virt(), (u32)iotable_init); ++} ++ ++void gk_load_51mcu_code(u32 code) ++{ ++ int i; ++ u8 *pData = NULL; ++ ++ pData = load_data_init(); ++ ++ /* Software Reset */ ++ gk_mcu_setbitsl( MCU_SYS_BASE + 0x0000, 1 << 5); ++ ++ /* Enable the download command */ ++ gk_mcu_setbitsl( MCU_SYS_BASE + 0x002C, 1 << 4); ++ ++ /* Disable the MCU51 core clock */ ++ gk_mcu_clrbitsl( MCU_SYS_BASE + 0x002C, 1 << 1); ++ ++ /* Download MCU code to boot ram */ ++ for(i=0;i<4096;i++) ++ { ++ gk_mcu_writel((GK_VA_PMU_C51_CODE + (i*4)), pData[i]); ++ } ++ gk_mcu_writel(MCU_SYS_BASE + 0x005C, code); ++ gk_mcu_writel(MCU_SYS_BASE + 0x002C, 0xB2);// 1011 0010 ++ gk_mcu_writel(MCU_SYS_BASE + 0x002C, 0x63);// 0110 0011 ++} ++ ++void gk_power_off(void) ++{ ++ ++ u32 code = PMU_POWER_OFF_CPU; ++ /* Disable interrupts first */ ++ local_irq_disable(); ++ local_fiq_disable(); ++ printk("gk power off...\n"); ++ ++#ifdef CONFIG_PMU_AUTOMOTIVE ++ code = PMU_AUTOMOTIVE_KEY; ++#endif ++#ifdef CONFIG_PMU_POWER_OFF_CPU ++ code = PMU_POWER_OFF_CPU; ++#endif ++#ifdef CONFIG_PMU_ALWAYS_RUNNING ++ // get pmu controller ++ gk_gpio_config(gk_all_gpio_cfg.pmu_ctl, GPIO_TYPE_OUTPUT_1); ++ msleep(1); ++ gk_gpio_config(gk_all_gpio_cfg.pmu_ctl, GPIO_TYPE_OUTPUT_0); ++ msleep(1); ++ code = PMU_ALWAYS_RUNNING_POWEROFF; ++#endif ++ gk_load_51mcu_code(code); ++ ++ //printk("c51 start ... ...\n"); ++ while(1){;} ++} ++ ++ ++//reboot, user watch dog ++void gk_restart(char mode, const char *cmd) ++{ ++ printk("gk reboot...\n"); ++ ++ gk_wdt_writel( WDOG_RELOAD_REG, 0xff); ++ gk_wdt_writel( WDOG_RESTART_REG, 0x4755); ++ gk_wdt_writel( WDOG_CONTROL_REG, WDOG_CTR_RST_EN | WDOG_CTR_EN); ++ mdelay(1000); ++ printk("watchdog reset failed...\n"); ++} ++ ++ ++/* ==========================================================================*/ ++DEFINE_SPINLOCK(gk_reg_lock); ++unsigned long gk_reg_flags; ++u32 gk_reglock_count = 0; ++ ++/* ==========================================================================*/ ++EXPORT_SYMBOL(gk_reg_lock); ++EXPORT_SYMBOL(gk_reg_flags); ++EXPORT_SYMBOL(gk_reglock_count); ++module_param (gk_reglock_count, uint, S_IRUGO); ++ ++ +diff --git a/arch/arm/mach-gk710xs/include/hal/hal.h b/arch/arm/mach-gk710xs/include/hal/hal.h +new file mode 100644 +index 00000000..2ea55b76 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/hal/hal.h +@@ -0,0 +1,22 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/hal/hal.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __HAL_HAL_H ++#define __HAL_HAL_H ++ ++#endif ++ +diff --git a/arch/arm/mach-gk710xs/include/hal/header.h b/arch/arm/mach-gk710xs/include/hal/header.h +new file mode 100644 +index 00000000..259c551b +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/hal/header.h +@@ -0,0 +1,20 @@ ++#ifndef _HEADER_H_INCLUDED_ ++#define _HEADER_H_INCLUDED_ ++ ++typedef struct gk_hal_header_s { ++ char magic[16] ; ++ unsigned int major_version ; ++ unsigned int minor_version ; ++ unsigned char chip_name[8] ; ++ unsigned char chip_stepping[8] ; ++ unsigned char build_id[32] ; ++ unsigned char build_date[32] ; ++} gk_hal_header_t; ++ ++typedef struct gk_hal_function_info_s { ++ unsigned int (*function)(unsigned int, unsigned int, ++ unsigned int, unsigned int) ; ++ const char* name ; ++} gk_hal_function_info_t ; ++ ++#endif // ifndef _HEADER_H_INCLUDED_ +diff --git a/arch/arm/mach-gk710xs/include/mach/audio_codec.h b/arch/arm/mach-gk710xs/include/mach/audio_codec.h +new file mode 100644 +index 00000000..e9ae79fb +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/audio_codec.h +@@ -0,0 +1,116 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/hal/audio_codec.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++#ifndef __HAL_AUDIO_CODEC_H__ ++#define __HAL_AUDIO_CODEC_H__ ++ ++#include ++ ++#define AUDIO_DMA_REG_OFFSET (0x00000000) ++ ++ ++/*AHB genneral */ ++#define AHB_GREG_BASE (GK_VA_AHB_GREG) ++#define AHB_GREG_BASE_PHYS (GK_PA_AHB_GREG) ++#define AHB_GREG_REG(x) (AHB_GREG_BASE + (x)) ++#define AHB_GREG_REG_PHYS(x) (AHB_GREG_BASE_PHYS + (x)) ++ ++#define AHB_GREG_BASE_extern AHB_GREG_BASE ++ ++/*digital model*/ ++#define AUDIO_CODEC_DIGITAL_BASE (GK_VA_AUDIO_CODEC_DIGITAL) ++#define AUDIO_CODEC_DIGITAL_BASE_PHYS (GK_PA_AUDIO_CODEC_DIGITAL) ++#define AUDIO_CODEC_DIGITAL_REG(x) (AUDIO_CODEC_DIGITAL_BASE + (x)) ++#define AUDIO_CODEC_DIGITAL_REG_PHYS(x) (AUDIO_CODEC_DIGITAL_BASE_PHYS + (x)) ++ ++#define AUDIO_CODEC_DIGITAL_BASE_extern AUDIO_CODEC_DIGITAL_BASE ++ ++/*analog model*/ ++#define AUDIO_CODEC_ANALOG_BASE (GK_VA_AUDIO_CODEC_ANALOG) ++#define AUDIO_CODEC_ANALOG_BASE_PHYS (GK_PA_AUDIO_CODEC_ANALOG) ++#define AUDIO_CODEC_ANALOG_REG(x) (AUDIO_CODEC_ANALOG_BASE + (x)) ++#define AUDIO_CODEC_ANALOG_REG_PHYS(x) (AUDIO_CODEC_ANALOG_BASE_PHYS + (x)) ++ ++#define AUDIO_CODEC_ANALOG_BASE_extern AUDIO_CODEC_ANALOG_BASE ++ ++/*AHB genneral reg*/ ++#define AHB_GENNERNAL0_REG AHB_GREG_REG(0x00) ++#define AHB_GENNERNAL1_REG AHB_GREG_REG(0x04) ++ ++/*digital model reg */ ++#define AUDC_DIGITAL_SYS_RST_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x00) ++#define AUDC_DIGITAL_CKG_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x04) ++#define AUDC_DIGITAL_AUDIOBAND_CTRL2_REG AUDIO_CODEC_DIGITAL_REG(0x18) ++#define AUDC_DIGITAL_TIMING_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x08) ++#define AUDC_DIGITAL_AUDIOBAND_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x10) ++#define AUDC_DIGITAL_AUDIOBAND_STS_REG AUDIO_CODEC_DIGITAL_REG(0x1c) ++#define AUDC_DIGITAL_SDM_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x34) ++#define AUDC_DIGITAL_SDM_CTRL1_REG AUDIO_CODEC_DIGITAL_REG(0x38) ++#define AUDC_DIGITAL_NF_SYNTH_1_NF_H_REG AUDIO_CODEC_DIGITAL_REG(0x3c) ++#define AUDC_DIGITAL_NF_SYNTH_1_NF_L_REG AUDIO_CODEC_DIGITAL_REG(0x40) ++#define AUDC_DIGITAL_NF_SYNTH_2_NF_H_REG AUDIO_CODEC_DIGITAL_REG(0x44) ++#define AUDC_DIGITAL_NF_SYNTH_2_NF_L_REG AUDIO_CODEC_DIGITAL_REG(0x48) ++#define AUDC_DIGITAL_DIG_MIC_CTRL_REG AUDIO_CODEC_DIGITAL_REG(0x4c) ++#define AUDC_DIGITAL_AUDIOBAND_STS2_REG AUDIO_CODEC_DIGITAL_REG(0x20) ++#define AUDC_DIGITAL_SDM_DWA_DATAIN_L_REG AUDIO_CODEC_DIGITAL_REG(0x54) ++#define AUDC_DIGITAL_SDM_DWA_DATAIN_R_REG AUDIO_CODEC_DIGITAL_REG(0x58) ++#define AUDC_DIGITAL_VALID_SIGNALS_REG AUDIO_CODEC_DIGITAL_REG(0x5c) ++#define AUDC_DIGITAL_PGA1_DPGA_CFG1_REG AUDIO_CODEC_DIGITAL_REG(0x68) ++#define AUDC_DIGITAL_MMP1_DPGA_CFG1_REG AUDIO_CODEC_DIGITAL_REG(0x60) ++#define AUDC_DIGITAL_MMP1_DPGA_CFG2_REG AUDIO_CODEC_DIGITAL_REG(0x64) ++#define AUDC_DIGITAL_MIX_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x50) ++ ++#define AUDC_DIGITAL_MMP2_DPGA_CFG1_REG AUDIO_CODEC_DIGITAL_REG(0x6c) ++#define AUDC_DIGITAL_MMP2_DPGA_CFG2_REG AUDIO_CODEC_DIGITAL_REG(0x70) ++#define AUDC_DIGITAL_INT1_DOUT_REG AUDIO_CODEC_DIGITAL_REG(0x74) ++#define AUDC_DIGITAL_FIFO_TH_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x7c) ++#define AUDC_DIGITAL_INT2_DOUT_REG AUDIO_CODEC_DIGITAL_REG(0x78) ++ ++#define AUDC_DIGITAL_TIMING_CTRL1_REG AUDIO_CODEC_DIGITAL_REG(0x0c) ++#define AUDC_DIGITAL_AUDIOBAND_CTRL1_REG AUDIO_CODEC_DIGITAL_REG(0x14) ++#define AUDC_DIGITAL_FIFO_CTRL_REG AUDIO_CODEC_DIGITAL_REG(0x80) ++#define AUDC_DIGITAL_FIFO_STS_REG AUDIO_CODEC_DIGITAL_REG(0x84) ++#define AUDC_DIGITAL_NF_SYNTH_5_NF_H_REG AUDIO_CODEC_DIGITAL_REG(0x88) ++#define AUDC_DIGITAL_NF_SYNTH_5_NF_L_REG AUDIO_CODEC_DIGITAL_REG(0x8c) ++#define AUDC_DIGITAL_INT_CTRL_REG AUDIO_CODEC_DIGITAL_REG(0x90) ++ ++#define AUDC_DIGITAL_SINE_GEN_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x24) ++#define AUDC_DIGITAL_SINE_GEN_CTRL1_REG AUDIO_CODEC_DIGITAL_REG(0x28) ++#define AUDC_DIGITAL_TEST_CTRL0_REG AUDIO_CODEC_DIGITAL_REG(0x30) ++ ++/*analog model reg */ ++#define AUDC_ANALOG_CTRL00_REG AUDIO_CODEC_ANALOG_REG(0x00) ++#define AUDC_ANALOG_CTRL01_REG AUDIO_CODEC_ANALOG_REG(0x04) ++#define AUDC_ANALOG_CTRL02_REG AUDIO_CODEC_ANALOG_REG(0x08) ++#define AUDC_ANALOG_CTRL03_REG AUDIO_CODEC_ANALOG_REG(0x0c) ++#define AUDC_ANALOG_CTRL04_REG AUDIO_CODEC_ANALOG_REG(0x10) ++#define AUDC_ANALOG_CTRL05_REG AUDIO_CODEC_ANALOG_REG(0x14) ++#define AUDC_ANALOG_CTRL06_REG AUDIO_CODEC_ANALOG_REG(0x18) ++#define AUDC_ANALOG_CTRL07_REG AUDIO_CODEC_ANALOG_REG(0x1c) ++#define AUDC_ANALOG_CTRL08_REG AUDIO_CODEC_ANALOG_REG(0x20) ++#define AUDC_ANALOG_CTRL09_REG AUDIO_CODEC_ANALOG_REG(0x24) ++#define AUDC_ANALOG_CTRL10_REG AUDIO_CODEC_ANALOG_REG(0x28) ++#define AUDC_ANALOG_CTRL11_REG AUDIO_CODEC_ANALOG_REG(0x2c) ++#define AUDC_ANALOG_CTRL12_REG AUDIO_CODEC_ANALOG_REG(0x30) ++#define AUDC_ANALOG_CTRL13_REG AUDIO_CODEC_ANALOG_REG(0x34) ++#define AUDC_ANALOG_CTRL14_REG AUDIO_CODEC_ANALOG_REG(0x38) ++#define AUDC_ANALOG_CTRL15_REG AUDIO_CODEC_ANALOG_REG(0x3c) ++#define AUDC_ANALOG_CTRL16_REG AUDIO_CODEC_ANALOG_REG(0x40) ++#define AUDC_ANALOG_CTRL17_REG AUDIO_CODEC_ANALOG_REG(0x44) ++#define AUDC_ANALOG_CTRL18_REG AUDIO_CODEC_ANALOG_REG(0x48) ++ ++extern unsigned int gk_aud_get_dma_offset(void); ++#endif /* __HAL_AUDIO_CODEC_H__ */ +diff --git a/arch/arm/mach-gk710xs/include/mach/crypto.h b/arch/arm/mach-gk710xs/include/mach/crypto.h +new file mode 100644 +index 00000000..ef01bbe9 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/crypto.h +@@ -0,0 +1,48 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/hal/i2s.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __HAL_CRYPTO_H__ ++#define __HAL_CRYPTO_H__ ++ ++#include ++ ++#define CRYPTO_VA_BASE GK_VA_CRYPT_UNIT ++#define CRYPTO_VA_REG(x) (CRYPTO_VA_BASE + (x)) ++#define REG_CRYPTO_DES_KEY CRYPTO_VA_REG(0x00c) /* read/write */ ++#define REG_CRYPTO_DES_INPUT CRYPTO_VA_REG(0x014) /* read/write */ ++#define REG_CRYPTO_DES_OPCODE CRYPTO_VA_REG(0x004) /* read/write */ ++#define REG_CRYPTO_DES_OUTPUT_RDY CRYPTO_VA_REG(0x018) /* read */ ++#define REG_CRYPTO_DES_OUTPUT CRYPTO_VA_REG(0x020) /* read */ ++#define REG_CRYPTO_DES_INTERRUPT CRYPTO_VA_REG(0x000) /* read/write */ ++ ++#define REG_CRYPTO_AES_128_KEY CRYPTO_VA_REG(0x074) /* read/write */ ++ ++#define REG_CRYPTO_AES_192_KEY CRYPTO_VA_REG(0x064) /* read/write */ ++ ++#define REG_CRYPTO_AES_256_KEY CRYPTO_VA_REG(0x04c) /* read/write */ ++ ++#define REG_CRYPTO_AES_INPUT CRYPTO_VA_REG(0x084) /* read/write */ ++#define REG_CRYPTO_AES_OPCODE CRYPTO_VA_REG(0x02C) /* read/write */ ++#define REG_CRYPTO_AES_OUTPUT_RDY CRYPTO_VA_REG(0x088) /* read */ ++ ++#define REG_CRYPTO_AES_OUTPUT CRYPTO_VA_REG(0x098) /* read */ ++#define REG_CRYPTO_AES_INTERRUPT CRYPTO_VA_REG(0x028) /* read/write */ ++#define REG_CRYPTO_EFUSE_BOOT_SW_DIS CRYPTO_VA_REG(0x024) /* read/write */ ++ ++ ++ ++#endif /* __HAL_CRYPTO_H__ */ +diff --git a/arch/arm/mach-gk710xs/include/mach/debug-macro.S b/arch/arm/mach-gk710xs/include/mach/debug-macro.S +new file mode 100644 +index 00000000..f9b1a09d +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/debug-macro.S +@@ -0,0 +1,65 @@ ++/* ++ * arch/arm/mach-gk710xs/include/mach/debug-macro.S ++ * ++ * History: ++ * 2014/06/18 - [Kewell Liu] created file ++ * ++ * Copyright (C) 2002-2014, Goke Microelectronics China. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++ ++#ifdef CONFIG_MMU ++ ++ .macro addruart, rp, rv, tmp ++ ldr \rp, =GK_PA_APB_BASE @ Physical Base ++ ldr \rv, =GK_VA_APB_BASE @ Virtual Base ++ .endm ++ ++#else /* !CONFIG_MMU */ ++ ++ .macro addruart, rx, tmp ++ mrc p15, 0, \rx, c1, c0 ++ tst \rx, #1 @ MMU enabled ++ moveq \rx, #GK_PA_APB_BASE @ physical base address ++ movne \rx, #GK_VA_APB_BASE @ virtual address ++ orr \rx, \rx, #UART_OFFSET ++ .endm ++ ++#endif /* CONFIG_MMU */ ++ ++.macro senduart, rd, rx ++ str \rd, [\rx, #UART_TH_OFFSET] ++.endm ++ ++.macro waituart, rd, rx ++1001: ++ ldr \rd, [\rx, #UART_LS_OFFSET] ++ tst \rd, #UART_LS_TEMT ++ beq 1001b ++ ++.endm ++ ++.macro busyuart, rd, rx ++1002: ++ ldr \rd, [\rx, #UART_LS_OFFSET] ++ tst \rd, #UART_LS_TEMT ++ beq 1002b ++.endm ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/dma.h b/arch/arm/mach-gk710xs/include/mach/dma.h +new file mode 100644 +index 00000000..9a61e2f2 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/dma.h +@@ -0,0 +1,171 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/hal/dma.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __HAL_DMA_H__ ++#define __HAL_DMA_H__ ++#include ++ ++ ++#define DMA_BASE (GK_VA_DMAC) ++#define DMA_REG(x) (DMA_BASE + (x)) ++ ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++ ++#define DMA_SUPPORT_DMA_FIOS 0 /* DMA_FIOS */ ++ ++/****************************/ ++/* DMA Channel Assignments */ ++/****************************/ ++ ++#if (DMA_SUPPORT_DMA_FIOS == 0) ++/* DMA instance channel */ ++#define FIO_DMA_CHAN 0 ++#define I2S_RX_DMA_CHAN 1 ++#define I2S_TX_DMA_CHAN 2 ++#define HOST_RX_DMA_CHAN 3 ++#define HOST_TX_DMA_CHAN 4 ++#endif ++ ++#define MS_DMA_CHAN 3 ++/* No AHB MS controller */ ++ ++/* Max number of channel */ ++#define NUM_DMA_FIOS_CHANNELS DMA_SUPPORT_DMA_FIOS ++ ++ ++#define NUM_DMA_CHANNELS 4 ++#if defined(CONFIG_GK_MUSB_CON_V1_00) ++#define DMA_CHAN_TX 3 ++#define DMA_CHAN_RX 3 ++#elif defined(CONFIG_GK_MUSB_CON_V1_10) ++#define DMA_CHAN_TX 0 ++#define DMA_CHAN_RX 3 ++#endif ++ ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++#define DMA_CHAN_CTR_REG(x) DMA_REG((0x31C + ((x) << 4))) ++#define DMA_CHAN_SRC_REG(x) DMA_REG((0x320 + ((x) << 4))) ++#define DMA_CHAN_DST_REG(x) DMA_REG((0x324 + ((x) << 4))) ++#define DMA_CHAN_STA_REG(x) DMA_REG((0x328 + ((x) << 4))) ++#define DMA_CHAN_DA_REG(x) DMA_REG((0x308 + ((x) << 2))) ++#define DMA_INT_REG DMA_REG(0x304) ++ ++/* DMA_CHANX_CTR_REG */ ++#define DMA_CHANX_CTR_EN 0x80000000 ++#define DMA_CHANX_CTR_D 0x40000000 ++#define DMA_CHANX_CTR_WM 0x20000000 ++#define DMA_CHANX_CTR_RM 0x10000000 ++#define DMA_CHANX_CTR_NI 0x08000000 ++#define DMA_CHANX_CTR_BLK_1024B 0x07000000 ++#define DMA_CHANX_CTR_BLK_512B 0x06000000 ++#define DMA_CHANX_CTR_BLK_256B 0x05000000 ++#define DMA_CHANX_CTR_BLK_128B 0x04000000 ++#define DMA_CHANX_CTR_BLK_64B 0x03000000 ++#define DMA_CHANX_CTR_BLK_32B 0x02000000 ++#define DMA_CHANX_CTR_BLK_16B 0x01000000 ++#define DMA_CHANX_CTR_BLK_8B 0x00000000 ++#define DMA_CHANX_CTR_TS_8B 0x00C00000 ++#define DMA_CHANX_CTR_TS_4B 0x00800000 ++#define DMA_CHANX_CTR_TS_2B 0x00400000 ++#define DMA_CHANX_CTR_TS_1B 0x00000000 ++ ++/* DMA descriptor bit fields */ ++#define DMA_DESC_EOC 0x01000000 ++#define DMA_DESC_WM 0x00800000 ++#define DMA_DESC_RM 0x00400000 ++#define DMA_DESC_NI 0x00200000 ++#define DMA_DESC_TS_8B 0x00180000 ++#define DMA_DESC_TS_4B 0x00100000 ++#define DMA_DESC_TS_2B 0x00080000 ++#define DMA_DESC_TS_1B 0x00000000 ++#define DMA_DESC_BLK_1024B 0x00070000 ++#define DMA_DESC_BLK_512B 0x00060000 ++#define DMA_DESC_BLK_256B 0x00050000 ++#define DMA_DESC_BLK_128B 0x00040000 ++#define DMA_DESC_BLK_64B 0x00030000 ++#define DMA_DESC_BLK_32B 0x00020000 ++#define DMA_DESC_BLK_16B 0x00010000 ++#define DMA_DESC_BLK_8B 0x00000000 ++#define DMA_DESC_ID 0x00000004 ++#define DMA_DESC_IE 0x00000002 ++#define DMA_DESC_ST 0x00000001 ++ ++/* DMA_CHANX_STA_REG */ ++#define DMA_CHANX_STA_DM 0x80000000 ++#define DMA_CHANX_STA_OE 0x40000000 ++#define DMA_CHANX_STA_DA 0x20000000 ++#define DMA_CHANX_STA_DD 0x10000000 ++#define DMA_CHANX_STA_OD 0x08000000 ++#define DMA_CHANX_STA_ME 0x04000000 ++#define DMA_CHANX_STA_BE 0x02000000 ++#define DMA_CHANX_STA_RWE 0x01000000 ++#define DMA_CHANX_STA_AE 0x00800000 ++#define DMA_CHANX_STA_DN 0x00400000 ++ ++/* DMA_INT_REG */ ++#define DMA_INT_CHAN(x) (0x1 << (x)) ++ ++#if defined(__FPGA__) ++#define DMA_INT_CHAN7 0x00000080 ++#define DMA_INT_CHAN6 0x00000040 ++#define DMA_INT_CHAN5 0x00000020 ++#endif ++ ++#define DMA_INT_CHAN4 0x00000010 ++#define DMA_INT_CHAN3 0x00000008 ++#define DMA_INT_CHAN2 0x00000004 ++#define DMA_INT_CHAN1 0x00000002 ++#define DMA_INT_CHAN0 0x00000001 ++ ++ ++/*********************************/ ++/* FIO/DMA Burst Setup */ ++/* - descriptor, non-descriptor */ ++/* - main, spare */ ++/*********************************/ ++ ++#if defined(__FPGA__) ++ ++#define DMA_NODC_MN_BURST_SIZE (DMA_CHANX_CTR_BLK_32B | DMA_CHANX_CTR_TS_4B) ++#define DMA_NODC_SP_BURST_SIZE (DMA_CHANX_CTR_BLK_32B | DMA_CHANX_CTR_TS_4B) ++#define DMA_DESC_MN_BURST_SIZE (DMA_DESC_BLK_32B | DMA_DESC_TS_4B) ++#define DMA_DESC_SP_BURST_SIZE (DMA_DESC_BLK_32B | DMA_DESC_TS_4B) ++#define FIO_MN_BURST_SIZE (FIO_DMACTR_BLK_32B | FIO_DMACTR_TS4B) ++#define FIO_SP_BURST_SIZE (FIO_DMACTR_BLK_32B | FIO_DMACTR_TS4B) ++ ++#else ++ ++#if (DMA_SUPPORT_DMA_FIOS == 0) ++#define DMA_NODC_MN_BURST_SIZE (DMA_CHANX_CTR_BLK_512B | DMA_CHANX_CTR_TS_4B) ++#define DMA_NODC_SP_BURST_SIZE (DMA_CHANX_CTR_BLK_512B | DMA_CHANX_CTR_TS_4B) ++#define DMA_DESC_MN_BURST_SIZE (DMA_DESC_BLK_512B | DMA_DESC_TS_4B) ++#define DMA_DESC_SP_BURST_SIZE (DMA_DESC_BLK_512B | DMA_DESC_TS_4B) ++#define FIO_MN_BURST_SIZE (FIO_DMACTR_BLK_512B | FIO_DMACTR_TS4B) ++#define FIO_SP_BURST_SIZE (FIO_DMACTR_BLK_512B | FIO_DMACTR_TS4B) ++#else ++ ++#endif ++ ++#endif ++ ++#endif /* __HAL_DMA_H__ */ +diff --git a/arch/arm/mach-gk710xs/include/mach/entry-macro.S b/arch/arm/mach-gk710xs/include/mach/entry-macro.S +new file mode 100644 +index 00000000..46dd9c23 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/entry-macro.S +@@ -0,0 +1,59 @@ ++/* ++ * arch/arm/mach-gk710xs/include/mach/entry-macro.S ++ * ++ * History: ++ * 2014/06/18 - [Kewell Liu] created file ++ * ++ * Copyright (C) 2002-2014, Goke Microelectronics China. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++ ++ .macro stat2nr, stat, nr, tmp ++ rsbs \tmp, \stat, #0 ++ and \nr, \tmp, \stat ++ clzcc \nr, \nr ++ rsc \nr, \nr, #32 ++ teq \nr, #32 ++ .endm ++ ++ .macro disable_fiq ++ .endm ++ ++ .macro get_irqnr_preamble, base, tmp ++ .endm ++ ++ .macro arch_ret_to_user, tmp1, tmp2 ++ .endm ++ ++ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp ++ ldr \base, =(VIC1_BASE) ++ ldr \irqstat, [\base, #VIC_IRQ_STA_OFFSET] ++ stat2nr \irqstat, \irqnr, \tmp ++#if (VIC_INSTANCES >= 2) ++ bne 1000f ++ ldr \base, =(VIC2_BASE) ++ ldr \irqstat, [\base, #VIC_IRQ_STA_OFFSET] ++ stat2nr \irqstat, \irqnr, \tmp ++ addne \irqnr, \irqnr, #VIC2_INT_VEC(0) ++#endif ++1000: ++ .endm ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/eth.h b/arch/arm/mach-gk710xs/include/mach/eth.h +new file mode 100644 +index 00000000..346af333 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/eth.h +@@ -0,0 +1,466 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/eth.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++#ifndef __MACH_ETH_H__ ++#define __MACH_ETH_H__ ++ ++#include ++ ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++ ++#define ETH_INSTANCES 1 ++ ++#define SUPPORT_GMII 0 // 10/100 bits phy ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++#define ETH_REG(x) (GK_VA_ETH_GMAC + (x)) ++ ++#define ETH_MAC_CFG_REG ETH_REG(0x0000) ++ ++#define ETH_MAC_GMII_ADDR_REG ETH_REG(0x0004) ++#define ETH_MAC_GMII_DATA_REG ETH_REG(0x0008) ++ ++#define ETH_MAC_FRAME_FILTER_REG ETH_REG(0x000c) ++#define ETH_MAC_HASH_HI_REG ETH_REG(0x0010) ++#define ETH_MAC_HASH_LO_REG ETH_REG(0x0014) ++#define ETH_MAC_FLOW_CTR_REG ETH_REG(0x0018) ++#define ETH_MAC_VLAN_TAG_REG ETH_REG(0x001c) ++#define ETH_MAC_VERSION_REG ETH_REG(0x0058) ++ ++#define ETH_MAC_MAC0_HI_REG ETH_REG(0x0040) ++#define ETH_MAC_MAC0_LO_REG ETH_REG(0x0044) ++#define ETH_MAC_MAC1_HI_REG ETH_REG(0x0048) ++#define ETH_MAC_MAC1_LO_REG ETH_REG(0x004c) ++#define ETH_MAC_MAC2_HI_REG ETH_REG(0x0050) ++#define ETH_MAC_MAC2_LO_REG ETH_REG(0x0054) ++ ++ ++#define ETH_DMA_TX_POLL_DMD_REG ETH_REG(0x1000) ++#define ETH_DMA_RX_POLL_DMD_REG ETH_REG(0x1004) ++#define ETH_DMA_BUS_MODE_REG ETH_REG(0x1008) ++#define ETH_DMA_RX_DESC_LIST_REG ETH_REG(0x100c) ++#define ETH_DMA_TX_DESC_LIST_REG ETH_REG(0x1010) ++#define ETH_DMA_STATUS_REG ETH_REG(0x1014) ++#define ETH_DMA_MISS_FRAME_BOCNT_REG ETH_REG(0x1018) ++ ++#define ETH_DMA_INTEN_REG ETH_REG(0x101c) ++#define ETH_DMA_OPMODE_REG ETH_REG(0x1020) ++ ++#define ETH_DMA_HOST_TX_DESC_REG ETH_REG(0x1048) ++#define ETH_DMA_HOST_RX_DESC_REG ETH_REG(0x104c) ++#define ETH_DMA_HOST_TX_BUF_REG ETH_REG(0x1040) ++#define ETH_DMA_HOST_RX_BUF_REG ETH_REG(0x1044) ++ ++ ++//------------------------------------------- ++#define ETH_MAC_CFG_OFFSET (0x0000) ++#define ETH_MAC_FRAME_FILTER_OFFSET (0x000c) ++#define ETH_MAC_HASH_HI_OFFSET (0x0010) ++#define ETH_MAC_HASH_LO_OFFSET (0x0014) ++#define ETH_MAC_GMII_ADDR_OFFSET (0x0004) ++#define ETH_MAC_GMII_DATA_OFFSET (0x0008) ++#define ETH_MAC_FLOW_CTR_OFFSET (0x0018) ++#define ETH_MAC_VLAN_TAG_OFFSET (0x001c) ++#define ETH_MAC_VERSION_OFFSET (0x0058) ++#define ETH_MAC_MAC0_HI_OFFSET (0x0040) ++#define ETH_MAC_MAC0_LO_OFFSET (0x0044) ++#define ETH_MAC_MAC1_HI_OFFSET (0x0048) ++#define ETH_MAC_MAC1_LO_OFFSET (0x004c) ++#define ETH_MAC_MAC2_HI_OFFSET (0x0050) ++#define ETH_MAC_MAC2_LO_OFFSET (0x0054) ++ ++#define ETH_DMA_BUS_MODE_OFFSET (0x1008) ++#define ETH_DMA_TX_POLL_DMD_OFFSET (0x1000) ++#define ETH_DMA_RX_POLL_DMD_OFFSET (0x1004) ++#define ETH_DMA_RX_DESC_LIST_OFFSET (0x100c) ++#define ETH_DMA_TX_DESC_LIST_OFFSET (0x1010) ++#define ETH_DMA_STATUS_OFFSET (0x1014) ++#define ETH_DMA_OPMODE_OFFSET (0x1020) ++#define ETH_DMA_INTEN_OFFSET (0x101c) ++#define ETH_DMA_MISS_FRAME_BOCNT_OFFSET (0x1018) ++#define ETH_DMA_HOST_TX_DESC_OFFSET (0x1048) ++#define ETH_DMA_HOST_RX_DESC_OFFSET (0x104c) ++#define ETH_DMA_HOST_TX_BUF_OFFSET (0x1040) ++#define ETH_DMA_HOST_RX_BUF_OFFSET (0x1044) ++ ++/* ETH_MAC_CFG_REG */ ++#define ETH_MAC_CFG_WD 0x00800000 ++#define ETH_MAC_CFG_JD 0x00400000 ++#define ETH_MAC_CFG_BE 0x00200000 ++#define ETH_MAC_CFG_JE 0x00100000 ++#define ETH_MAC_CFG_IFG_96 0x000e0000 ++#define ETH_MAC_CFG_IFG_88 0x000c0000 ++#define ETH_MAC_CFG_IFG_80 0x000a0000 ++#define ETH_MAC_CFG_IFG_72 0x00080000 ++#define ETH_MAC_CFG_IFG_64 0x00060000 ++#define ETH_MAC_CFG_IFG_56 0x00040000 ++#define ETH_MAC_CFG_IFG_48 0x00020000 ++#define ETH_MAC_CFG_IFG_40 0x00000000 ++#define ETH_MAC_CFG_DCRS 0x00010000 ++#define ETH_MAC_CFG_PS 0x00008000 ++#define ETH_MAC_CFG_FES 0x00004000 ++#define ETH_MAC_CFG_DO 0x00002000 ++#define ETH_MAC_CFG_LM 0x00001000 ++#define ETH_MAC_CFG_DM 0x00000800 ++#define ETH_MAC_CFG_IPC 0x00000400 ++#define ETH_MAC_CFG_DR 0x00000200 ++#define ETH_MAC_CFG_LUD 0x00000100 ++#define ETH_MAC_CFG_ACS 0x00000080 ++#define ETH_MAC_CFG_BL_1 0x00000060 ++#define ETH_MAC_CFG_BL_4 0x00000040 ++#define ETH_MAC_CFG_BL_8 0x00000020 ++#define ETH_MAC_CFG_BL_10 0x00000000 ++#define ETH_MAC_CFG_DC 0x00000010 ++#define ETH_MAC_CFG_TE 0x00000008 /* Transmitter Enable */ ++#define ETH_MAC_CFG_RE 0x00000004 /* Receiver Enable */ ++ ++/* ETH_MAC_FRAME_FILTER_REG */ ++#define ETH_MAC_FRAME_FILTER_RA 0x80000000 ++#define ETH_MAC_FRAME_FILTER_SAF 0x00000200 ++#define ETH_MAC_FRAME_FILTER_SAIF 0x00000100 ++#define ETH_MAC_FRAME_FILTER_PCF_PASS 0x000000c0 ++#define ETH_MAC_FRAME_FILTER_PCF_FAIL 0x00000040 ++#define ETH_MAC_FRAME_FILTER_PCF_ALL 0x00000000 ++#define ETH_MAC_FRAME_FILTER_DBF 0x00000020 ++#define ETH_MAC_FRAME_FILTER_PM 0x00000010 ++#define ETH_MAC_FRAME_FILTER_DAIF 0x00000008 ++#define ETH_MAC_FRAME_FILTER_HMC 0x00000004 ++#define ETH_MAC_FRAME_FILTER_HUC 0x00000002 ++#define ETH_MAC_FRAME_FILTER_PR 0x00000001 ++ ++/* ETH_MAC_GMII_ADDR_REG */ ++#define ETH_MAC_GMII_ADDR_PA(x) (((x) & 0x1f) << 11) ++#define ETH_MAC_GMII_ADDR_GR(x) (((x) & 0x1f) << 6) ++#define ETH_MAC_GMII_ADDR_CR_250_300MHZ 0x00000014 ++#define ETH_MAC_GMII_ADDR_CR_150_250MHZ 0x00000010 ++#define ETH_MAC_GMII_ADDR_CR_35_60MHZ 0x0000000c ++#define ETH_MAC_GMII_ADDR_CR_20_35MHZ 0x00000008 ++#define ETH_MAC_GMII_ADDR_CR_100_150MHZ 0x00000004 ++#define ETH_MAC_GMII_ADDR_CR_60_100MHZ 0x00000000 ++#define ETH_MAC_GMII_ADDR_GW 0x00000002 ++#define ETH_MAC_GMII_ADDR_GB 0x00000001 ++ ++/* ETH_MAC_FLOW_CTR_REG */ ++#define ETH_MAC_FLOW_CTR_PT(x) (((x) & 0xffff) << 16) ++#define ETH_MAC_FLOW_CTR_PLT_256 0x00000030 ++#define ETH_MAC_FLOW_CTR_PLT_144 0x00000020 ++#define ETH_MAC_FLOW_CTR_PLT_28 0x00000010 ++#define ETH_MAC_FLOW_CTR_PLT_4 0x00000000 ++#define ETH_MAC_FLOW_CTR_UP 0x00000008 ++#define ETH_MAC_FLOW_CTR_RFE 0x00000004 ++#define ETH_MAC_FLOW_CTR_TFE 0x00000002 ++#define ETH_MAC_FLOW_CTR_FCBBPA 0x00000001 ++ ++/* ETH_MAC_VERSION_REG */ ++#define ETH_MAC_VERSION_USER(v) (((x) & 0x0000ff00) >> 8) ++#define ETH_MAC_VERSION_SYN(v) ((x) & 0x000000ff) ++ ++/* ETH_DMA_BUS_MODE_REG */ ++#define ETH_DMA_BUS_MODE_FB 0x00010000 ++#define ETH_DMA_BUS_MODE_PR4 0x0000c000 ++#define ETH_DMA_BUS_MODE_PR3 0x00008000 ++#define ETH_DMA_BUS_MODE_PR2 0x00004000 ++#define ETH_DMA_BUS_MODE_PR1 0x00000000 ++#define ETH_DMA_BUS_MODE_PBL_32 0x00002000 ++#define ETH_DMA_BUS_MODE_PBL_16 0x00001000 ++#define ETH_DMA_BUS_MODE_PBL_8 0x00000800 ++#define ETH_DMA_BUS_MODE_PBL_4 0x00000400 ++#define ETH_DMA_BUS_MODE_PBL_2 0x00000200 ++#define ETH_DMA_BUS_MODE_PBL_1 0x00000100 ++#define ETH_DMA_BUS_MODE_DSL(len) ((len & 0x1f) << 2) ++#define ETH_DMA_BUS_MODE_DA_RX 0x00000002 ++#define ETH_DMA_BUS_MODE_DA_TX 0x00000000 ++#define ETH_DMA_BUS_MODE_SWR 0x00000001 ++ ++/* ETH_DMA_STATUS_REG */ ++#define ETH_DMA_STATUS_GPI 0x10000000 ++#define ETH_DMA_STATUS_GMI 0x08000000 ++#define ETH_DMA_STATUS_GLI 0x04000000 ++#define ETH_DMA_STATUS_EB_MASK 0x03800000 ++#define ETH_DMA_STATUS_EB_TXDMA 0x02000000 ++#define ETH_DMA_STATUS_EB_RXDMA 0x00000000 ++#define ETH_DMA_STATUS_EB_RXFER 0x01000000 ++#define ETH_DMA_STATUS_EB_TXFER 0x00000000 ++#define ETH_DMA_STATUS_EB_DESC 0x00800000 ++#define ETH_DMA_STATUS_EB_DBUF 0x00000000 ++#define ETH_DMA_STATUS_TS_MASK 0x00700000 ++#define ETH_DMA_STATUS_TS_CTD 0x00700000 ++#define ETH_DMA_STATUS_TS_SUSP 0x00600000 ++#define ETH_DMA_STATUS_TS_READ 0x00300000 ++#define ETH_DMA_STATUS_TS_WAIT 0x00200000 ++#define ETH_DMA_STATUS_TS_FETCH 0x00100000 ++#define ETH_DMA_STATUS_TS_STOP 0x00000000 ++#define ETH_DMA_STATUS_RS_MASK 0x000e0000 ++#define ETH_DMA_STATUS_RS_RCV 0x000e0000 ++#define ETH_DMA_STATUS_RS_CRD 0x000a0000 ++#define ETH_DMA_STATUS_RS_SUSP 0x00080000 ++#define ETH_DMA_STATUS_RS_WAIT 0x00060000 ++#define ETH_DMA_STATUS_RS_FETCH 0x00020000 ++#define ETH_DMA_STATUS_RS_STOP 0x00000000 ++#define ETH_DMA_STATUS_NIS 0x00010000 ++#define ETH_DMA_STATUS_AIS 0x00008000 ++#define ETH_DMA_STATUS_ERI 0x00004000 ++#define ETH_DMA_STATUS_FBI 0x00002000 ++#define ETH_DMA_STATUS_ETI 0x00000400 ++#define ETH_DMA_STATUS_RWT 0x00000200 ++#define ETH_DMA_STATUS_RPS 0x00000100 ++#define ETH_DMA_STATUS_RU 0x00000080 ++#define ETH_DMA_STATUS_RI 0x00000040 ++#define ETH_DMA_STATUS_UNF 0x00000020 ++#define ETH_DMA_STATUS_OVF 0x00000010 ++#define ETH_DMA_STATUS_TJT 0x00000008 ++#define ETH_DMA_STATUS_TU 0x00000004 ++#define ETH_DMA_STATUS_TPS 0x00000002 ++#define ETH_DMA_STATUS_TI 0x00000001 ++ ++/* ETH_DMA_OPMODE_REG */ ++#define ETH_DMA_OPMODE_DT 0x04000000 ++#define ETH_DMA_OPMODE_RSF 0x02000000 ++#define ETH_DMA_OPMODE_DFF 0x01000000 ++#define ETH_DMA_OPMODE_TSF 0x00200000 ++#define ETH_DMA_OPMODE_FTF 0x00100000 ++#define ETH_DMA_OPMODE_TTC_16 0x0001c000 ++#define ETH_DMA_OPMODE_TTC_24 0x00018000 ++#define ETH_DMA_OPMODE_TTC_32 0x00014000 ++#define ETH_DMA_OPMODE_TTC_40 0x00010000 ++#define ETH_DMA_OPMODE_TTC_256 0x0000c000 ++#define ETH_DMA_OPMODE_TTC_192 0x00008000 ++#define ETH_DMA_OPMODE_TTC_128 0x00004000 ++#define ETH_DMA_OPMODE_TTC_64 0x00000000 ++#define ETH_DMA_OPMODE_ST 0x00002000 ++#define ETH_DMA_OPMODE_RFD_4K 0x00001800 ++#define ETH_DMA_OPMODE_RFD_3K 0x00001000 ++#define ETH_DMA_OPMODE_RFD_2K 0x00000800 ++#define ETH_DMA_OPMODE_RFD_1K 0x00000000 ++#define ETH_DMA_OPMODE_RFA_4K 0x00000600 ++#define ETH_DMA_OPMODE_RFA_3K 0x00000400 ++#define ETH_DMA_OPMODE_RFA_2K 0x00000200 ++#define ETH_DMA_OPMODE_RFA_1K 0x00000000 ++#define ETH_DMA_OPMODE_EFC 0x00000100 ++#define ETH_DMA_OPMODE_FEF 0x00000080 ++#define ETH_DMA_OPMODE_FUF 0x00000040 ++#define ETH_DMA_OPMODE_RTC_128 0x00000018 ++#define ETH_DMA_OPMODE_RTC_96 0x00000010 ++#define ETH_DMA_OPMODE_RTC_32 0x00000008 ++#define ETH_DMA_OPMODE_RTC_64 0x00000000 ++#define ETH_DMA_OPMODE_OSF 0x00000004 ++#define ETH_DMA_OPMODE_SR 0x00000002 ++ ++/* ETH_DMA_INTEN_REG */ ++#define ETH_DMA_INTEN_NIE 0x00010000 ++#define ETH_DMA_INTEN_AIE 0x00008000 ++#define ETH_DMA_INTEN_ERE 0x00004000 ++#define ETH_DMA_INTEN_FBE 0x00002000 ++#define ETH_DMA_INTEN_ETE 0x00000400 ++#define ETH_DMA_INTEN_RWE 0x00000200 ++#define ETH_DMA_INTEN_RSE 0x00000100 ++#define ETH_DMA_INTEN_RUE 0x00000080 ++#define ETH_DMA_INTEN_RIE 0x00000040 ++#define ETH_DMA_INTEN_UNE 0x00000020 ++#define ETH_DMA_INTEN_OVE 0x00000010 ++#define ETH_DMA_INTEN_TJE 0x00000008 ++#define ETH_DMA_INTEN_TUE 0x00000004 ++#define ETH_DMA_INTEN_TSE 0x00000002 ++#define ETH_DMA_INTEN_TIE 0x00000001 ++ ++/* ETH_DMA_MISS_FRAME_BOCNT_REG */ ++#define ETH_DMA_MISS_FRAME_BOCNT_FIFO 0x10000000 ++#define ETH_DMA_MISS_FRAME_BOCNT_APP(v) (((v) & 0x0ffe0000) >> 17) ++#define ETH_DMA_MISS_FRAME_BOCNT_FRAME 0x00001000 ++#define ETH_DMA_MISS_FRAME_BOCNT_HOST(v) ((v) & 0x0000ffff) ++ ++/* Receive Descriptor 0 (RDES0) */ ++#define ETH_RDES0_OWN 0x80000000 ++#define ETH_RDES0_AFM 0x40000000 ++#define ETH_RDES0_FL(v) (((v) & 0x3fff0000) >> 16) ++#define ETH_RDES0_ES 0x00008000 ++#define ETH_RDES0_DE 0x00004000 ++#define ETH_RDES0_SAF 0x00002000 ++#define ETH_RDES0_LE 0x00001000 ++#define ETH_RDES0_OE 0x00000800 ++#define ETH_RDES0_VLAN 0x00000400 ++#define ETH_RDES0_FS 0x00000200 ++#define ETH_RDES0_LS 0x00000100 ++#define ETH_RDES0_IPC 0x00000080 ++#define ETH_RDES0_LC 0x00000040 ++#define ETH_RDES0_FT 0x00000020 ++#define ETH_RDES0_RWT 0x00000010 ++#define ETH_RDES0_RE 0x00000008 ++#define ETH_RDES0_DBE 0x00000004 ++#define ETH_RDES0_CE 0x00000002 ++#define ETH_RDES0_RX 0x00000001 ++ ++#define ETH_RDES0_COE_MASK 0x000000a1 ++#define ETH_RDES0_COE_LENLT600 0x00000000 /* Bit(5:7:0)=>0 IEEE 802.3 type frame Length field is Lessthan 0x0600 */ ++#define ETH_RDES0_COE_UNSUPPORTED 0x00000001 /* Bit(5:7:0)=>1 Payload & Ip header checksum bypassed (unsuppported payload) */ ++#define ETH_RDES0_COE_RESERVED 0x00000080 /* Bit(5:7:0)=>2 Reserved */ ++#define ETH_RDES0_COE_CHKBYPASS 0x00000081 /* Bit(5:7:0)=>3 Neither IPv4 nor IPV6. So checksum bypassed */ ++#define ETH_RDES0_COE_NOCHKERROR 0x00000020 /* Bit(5:7:0)=>4 No IPv4/IPv6 Checksum error detected */ ++#define ETH_RDES0_COE_PLCHKERROR 0x00000021 /* Bit(5:7:0)=>5 Payload checksum error detected for Ipv4/Ipv6 frames */ ++#define ETH_RDES0_COE_HDRCHKERROR 0x000000a0 /* Bit(5:7:0)=>6 Ip header checksum error detected for Ipv4 frames */ ++#define ETH_RDES0_COE_HDRPLCHKERROR 0x000000a1 /* Bit(5:7:0)=>7 Payload & Ip header checksum error detected for Ipv4/Ipv6 frames */ ++ ++/* Receive Descriptor 1 (RDES1) */ ++#define ETH_RDES1_DIC 0x80000000 ++#define ETH_RDES1_RER 0x02000000 ++#define ETH_RDES1_RCH 0x01000000 ++#define ETH_RDES1_RBS2(v) (((v) & 0x003ff800) >> 11) /* Receive Buffer 2 Size */ ++#define ETH_RDES1_RBS1(v) ((v) & 0x000007ff) /* Receive Buffer 1 Size */ ++#define ETH_RDES1_RBS2x(x) (((x) << 11) & 0x003ff800) /* Receive Buffer 2 Size */ ++#define ETH_RDES1_RBS1x(x) ((x) & 0x000007ff) /* Receive Buffer 1 Size */ ++ ++/* Transmit Descriptor 0 (TDES0) */ ++#define ETH_TDES0_OWN 0x80000000 ++#define ETH_TDES0_TTSS 0x00020000 ++#define ETH_TDES0_IHE 0x00010000 ++#define ETH_TDES0_ES 0x00008000 ++#define ETH_TDES0_JT 0x00004000 ++#define ETH_TDES0_FF 0x00002000 ++#define ETH_TDES0_PCE 0x00001000 ++#define ETH_TDES0_LCA 0x00000800 ++#define ETH_TDES0_NC 0x00000400 ++#define ETH_TDES0_LCO 0x00000200 ++#define ETH_TDES0_EC 0x00000100 ++#define ETH_TDES0_VF 0x00000080 ++#define ETH_TDES0_CC(v) (((v) & 0x00000078) >> 3) ++#define ETH_TDES0_ED 0x00000004 ++#define ETH_TDES0_UF 0x00000002 ++#define ETH_TDES0_DB 0x00000001 ++#define ETH_TDES0_ES_MASK (ETH_TDES0_UF | ETH_TDES0_ED | \ ++ ETH_TDES0_EC | ETH_TDES0_LCO | \ ++ ETH_TDES0_NC | ETH_TDES0_LCA | \ ++ ETH_TDES0_FF | ETH_TDES0_JT | \ ++ ETH_TDES0_ES) ++ ++/* Transmit Descriptor 1 (TDES1) */ ++#define ETH_TDES1_IC 0x80000000 ++#define ETH_TDES1_LS 0x40000000 ++#define ETH_TDES1_FS 0x20000000 ++#define ETH_TDES1_CIC_TUI 0x10000000 ++#define ETH_TDES1_CIC_HDR 0x08000000 ++#define ETH_TDES1_DC 0x04000000 ++#define ETH_TDES1_TER 0x02000000 ++#define ETH_TDES1_TCH 0x01000000 ++#define ETH_TDES1_DP 0x00800000 ++#define ETH_TDES1_TBS2(v) (((v) & 0x003ff800) >> 11) ++#define ETH_TDES1_TBS1(v) ((v) & 0x000007ff) ++#define ETH_TDES1_TBS2x(x) (((x) << 11) & 0x003ff800) ++#define ETH_TDES1_TBS1x(x) ((x) & 0x000007ff) ++ ++/* ==========================================================================*/ ++#define GKETH_MAC_SIZE (6) ++ ++ ++#define EPHY_BASE (GK_VA_ETH_PHY) ++#define EPHY_REG(x) (EPHY_BASE + (x)) ++ ++#define REG_EPHY_CONTROL EPHY_REG(0x000) /* read/write */ ++#define REG_EPHY_STATUS EPHY_REG(0x004) /* read */ ++#define REG_EPHY_ID1 EPHY_REG(0x008) /* read */ ++#define REG_EPHY_ID2 EPHY_REG(0x00C) /* read */ ++#define REG_EPHY_ANAR EPHY_REG(0x010) /* read/write */ ++#define REG_EPHY_ANLPAR EPHY_REG(0x014) /* read */ ++#define REG_EPHY_ANER EPHY_REG(0x018) /* read/write */ ++#define REG_EPHY_ANNPAR EPHY_REG(0x01C) /* read/write */ ++#define REG_EPHY_ANLPNP EPHY_REG(0x020) /* read */ ++#define REG_EPHY_MS_CONTROL EPHY_REG(0x024) /* read/write */ ++#define REG_EPHY_MS_STATUS EPHY_REG(0x028) /* read */ ++#define REG_EPHY_PSE_CONTROL EPHY_REG(0x02C) /* read/write */ ++#define REG_EPHY_PSE_STATUS EPHY_REG(0x030) /* read */ ++#define REG_EPHY_MMD_CONTROL EPHY_REG(0x034) /* read/write */ ++#define REG_EPHY_MMD_CONTROL_ADDR EPHY_REG(0x038) /* read/write */ ++#define REG_EPHY_AN_R_15 EPHY_REG(0x03C) /* read */ ++#define REG_EPHY_WAVE_SHAPING_34 EPHY_REG(0x040) /* read/write */ ++#define REG_EPHY_WAVE_SHAPING_56 EPHY_REG(0x044) /* read/write */ ++#define REG_EPHY_WAVE_SHAPING_78 EPHY_REG(0x048) /* read/write */ ++#define REG_EPHY_WAVE_SHAPING_9A EPHY_REG(0x04C) /* read/write */ ++#define REG_EPHY_WAVE_SHAPING_BC EPHY_REG(0x050) /* read/write */ ++#define REG_EPHY_WAVE_SHAPING_DE EPHY_REG(0x054) /* read/write */ ++#define REG_EPHY_SPEED EPHY_REG(0x058) /* read/write */ ++#define REG_EPHY_LTP EPHY_REG(0x05C) /* read/write */ ++#define REG_EPHY_MCU EPHY_REG(0x060) /* read/write */ ++#define REG_EPHY_CODE_RAM EPHY_REG(0x064) /* read/write */ ++#define REG_EPHY_CODE_RAM_W EPHY_REG(0x068) /* read/write */ ++#define REG_EPHY_100M_LINK EPHY_REG(0x088) /* read/write */ ++#define REG_EPHY_DEBUG EPHY_REG(0x0C8) /* read/write */ ++#define REG_EPHY_DEBUG_MODE EPHY_REG(0x0E0) /* read/write */ ++#define REG_EPHY_ADC_GAIN_PGA EPHY_REG(0x36C) /* read/write */ ++#define REG_EPHY_PLL_ADC_CTRL3 EPHY_REG(0x370) /* read/write */ ++#define REG_EPHY_RX_LPF EPHY_REG(0x374) /* read/write */ ++#define REG_EPHY_PLL_ADC_CTRL0 EPHY_REG(0x394) /* read/write */ ++#define REG_EPHY_PLL_ADC_CTRL1 EPHY_REG(0x398) /* read/write */ ++#define REG_EPHY_PLL_ADC_CTRL2 EPHY_REG(0x3A8) /* read/write */ ++#define REG_EPHY_ADC_DC EPHY_REG(0x3D4) /* read/write */ ++#define REG_EPHY_LDO EPHY_REG(0x3F8) /* read/write */ ++#define REG_EPHY_CLK_GATE EPHY_REG(0x450) /* read */ ++#define REG_EPHY_CLK1 EPHY_REG(0x460) /* read/write */ ++#define REG_EPHY_POWER EPHY_REG(0x474) /* read/write */ ++#define REG_EPHY_MDIIO EPHY_REG(0x540) /* read/write */ ++#define REG_EPHY_CLK0 EPHY_REG(0x588) /* read/write */ ++ ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++struct gk_eth_platform_info { ++ u8 mac_addr[GKETH_MAC_SIZE]; ++ u32 napi_weight; ++ u32 watchdog_timeo; ++ ++ u32 phy_id; ++ u32 phy_supported; ++ u32 mii_id; ++ struct gk_gpio_io_info phy_reset; ++ u32 mii_retry_limit; ++ u32 mii_retry_tmo; ++ ++ u32 default_tx_ring_size; ++ u32 default_rx_ring_size; ++ u32 default_dma_bus_mode; ++ u32 default_dma_opmode; ++ u32 default_supported; ++ ++ int (*is_enabled)(void); ++}; ++ ++#define GK_ETH_PARAM_CALL(id, arg, perm) \ ++ module_param_cb(eth##id##_napi_weight, ¶m_ops_uint, &(arg.napi_weight), perm); \ ++ module_param_cb(eth##id##_watchdog_timeo, ¶m_ops_uint, &(arg.watchdog_timeo), perm); \ ++ module_param_cb(eth##id##_phy_id, ¶m_ops_uint, &(arg.phy_id), perm); \ ++ module_param_cb(eth##id##_mii_id, ¶m_ops_uint, &(arg.mii_id), perm); \ ++ module_param_cb(eth##id##_mii_retry_limit, ¶m_ops_uint, &(arg.mii_retry_limit), perm); \ ++ module_param_cb(eth##id##_mii_retry_tmo, ¶m_ops_uint, &(arg.mii_retry_tmo), perm); ++ ++/* ==========================================================================*/ ++extern struct platform_device gk_eth0; ++ ++/* ==========================================================================*/ ++extern int gk_init_eth0(const u8 *mac_addr); ++extern void gk_set_phy_reset_pin(u32 gpio_pin); ++extern void gk_set_phy_speed_led(u32 gpio_type); ++ ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++ ++#endif /* __MACH_ETH_H__ */ ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/event.h b/arch/arm/mach-gk710xs/include/mach/event.h +new file mode 100644 +index 00000000..55670825 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/event.h +@@ -0,0 +1,121 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/plat/event.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++#ifndef __PLAT_EVENT_H ++#define __PLAT_EVENT_H ++ ++/* ==========================================================================*/ ++#define GK_EVENT_PRE (0x80000000) ++#define GK_EVENT_POST (0x40000000) ++#define GK_EVENT_CHECK (0x20000000) ++ ++#define GK_EVENT_ID_CPUFREQ (1) ++#define GK_EVENT_ID_PM (2) ++#define GK_EVENT_ID_TOSS (3) ++#define GK_EVENT_ID_GIVEUP_DSP (4) ++#define GK_EVENT_ID_TAKEOVER_DSP (5) ++#define GK_EVENT_ID_USBVBUS (6) ++#define GK_EVENT_ID_VI_LOSS (7) ++ ++#define GK_EVENT_PRE_CPUFREQ (GK_EVENT_ID_CPUFREQ | GK_EVENT_PRE) ++#define GK_EVENT_POST_CPUFREQ (GK_EVENT_ID_CPUFREQ | GK_EVENT_POST) ++#define GK_EVENT_CHECK_CPUFREQ (GK_EVENT_ID_CPUFREQ | GK_EVENT_CHECK) ++#define GK_EVENT_PRE_PM (GK_EVENT_ID_PM | GK_EVENT_PRE) ++#define GK_EVENT_POST_PM (GK_EVENT_ID_PM | GK_EVENT_POST) ++#define GK_EVENT_CHECK_PM (GK_EVENT_ID_PM | GK_EVENT_CHECK) ++#define GK_EVENT_PRE_TOSS (GK_EVENT_ID_TOSS | GK_EVENT_PRE) ++#define GK_EVENT_POST_TOSS (GK_EVENT_ID_TOSS | GK_EVENT_POST) ++#define GK_EVENT_CHECK_TOSS (GK_EVENT_ID_TOSS | GK_EVENT_CHECK) ++ ++#define GK_EVENT_PRE_GIVEUP_DSP (GK_EVENT_ID_GIVEUP_DSP | GK_EVENT_PRE) ++#define GK_EVENT_POST_GIVEUP_DSP (GK_EVENT_ID_GIVEUP_DSP | GK_EVENT_POST) ++#define GK_EVENT_GIVEUP_DSP (GK_EVENT_ID_GIVEUP_DSP | GK_EVENT_CHECK) ++#define GK_EVENT_PRE_TAKEOVER_DSP (GK_EVENT_ID_TAKEOVER_DSP | GK_EVENT_PRE) ++#define GK_EVENT_POST_TAKEOVER_DSP (GK_EVENT_ID_TAKEOVER_DSP | GK_EVENT_POST) ++#define GK_EVENT_TAKEOVER_DSP (GK_EVENT_ID_TAKEOVER_DSP | GK_EVENT_CHECK) ++ ++#define GK_EVENT_CHECK_USBVBUS (GK_EVENT_ID_USBVBUS | GK_EVENT_CHECK) ++ ++#define GK_EVENT_POST_VI_LOSS (GK_EVENT_ID_VI_LOSS | GK_EVENT_POST) ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++#include ++ ++/* ==========================================================================*/ ++enum gk_event_type { ++ /* No Event */ ++ GK_EV_NONE = 0x00000000, ++ ++ /* VI Event */ ++ GK_EV_VI_DECODER_SOURCE_PLUG = 0x00010000, ++ GK_EV_VI_DECODER_SOURCE_REMOVE, ++ ++ /* VO Event */ ++ GK_EV_VO_CVBS_PLUG = 0x00020000, ++ GK_EV_VO_CVBS_REMOVE, ++ GK_EV_VO_YPBPR_PLUG, ++ GK_EV_VO_YPBPR_REMOVE, ++ GK_EV_VO_HDMI_PLUG, ++ GK_EV_VO_HDMI_REMOVE, ++ ++ /* SENSOR Event*/ ++ GK_EV_ACCELEROMETER_REPORT = 0x00030000, ++ GK_EV_MAGNETIC_FIELD_REPORT, ++ GK_EV_LIGHT_REPORT, ++ GK_EV_PROXIMITY_REPORT, ++ GK_EV_GYROSCOPE_REPORT, ++ GK_EV_TEMPERATURE_REPORT, ++ ++ /* FB2 Event */ ++ GK_EV_FB2_PAN_DISPLAY = 0x00040000, ++}; ++ ++struct gk_event { ++ u32 sno; //sequential number ++ u64 time_code; ++ enum gk_event_type type; ++ u8 data[32]; ++}; ++ ++struct gk_event_pool { ++ struct mutex op_mutex; ++ struct gk_event events[256]; ++ unsigned int ev_sno; ++ unsigned char ev_index; ++}; ++ ++extern int gk_event_pool_init(struct gk_event_pool *pool); ++extern int gk_event_pool_affuse(struct gk_event_pool *pool, ++ struct gk_event event); ++extern int gk_event_pool_query_index(struct gk_event_pool *pool); ++extern int gk_event_pool_query_event(struct gk_event_pool *pool, ++ struct gk_event *event, unsigned char index); ++extern int gk_event_report_uevent(struct kobject *kobj, ++ enum kobject_action action, char *envp_ext[]); ++ ++/* ==========================================================================*/ ++extern int gk_unregister_event_notifier(void *nb); ++extern int gk_set_event(unsigned long val, void *v); ++extern int gk_register_raw_event_notifier(void *nb); ++extern int gk_unregister_raw_event_notifier(void *nb); ++extern int gk_set_raw_event(unsigned long val, void *v); ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/flash.h b/arch/arm/mach-gk710xs/include/mach/flash.h +new file mode 100644 +index 00000000..c0a15479 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/flash.h +@@ -0,0 +1,59 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/flash.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_FLASH_H ++#define __MACH_FLASH_H ++ ++#include ++ ++#define SFLASH_REG(x) (GK_VA_SFLASH + (x)) ++ ++#define REG_SFLASH_DATA SFLASH_REG(0x00) /* read/write */ ++#define REG_SFLASH_COMMAND SFLASH_REG(0x04) /* read/write */ ++#define REG_SFLASH_CE SFLASH_REG(0x08) /* read/write */ ++#define REG_SFLASH_SPEED SFLASH_REG(0x0C) /* read/write */ ++#define REG_SFLASH_PARA_XIP SFLASH_REG(0x10) /* read/write */ ++ ++// FPGA: SCLK = 40MHz ++// EVB: SCLK = 138MHz ++// 000: SCLK/2 ++// 001: SCLK/4 ++// 010: SCLK/6 ++// 011: SCLK/8 ++// 100: SCLK/10 ++typedef enum ++{ ++ GOKE_SFLASH_FREQ_DIV2 = 0, ++ GOKE_SFLASH_FREQ_DIV4, ++ GOKE_SFLASH_FREQ_DIV6, ++ GOKE_SFLASH_FREQ_DIV8, ++ GOKE_SFLASH_FREQ_DIV10 ++}GD_SFLASH_SPEED_MODE; ++ ++#define SYSTEM_SFLASH_FREQ GOKE_SFLASH_FREQ_DIV2 ++ ++struct sflash_platform_data /* flash device platform_data */ ++{ ++ uint32_t speed_mode; ++ uint32_t channel; ++ uint32_t nr_parts; ++ struct mtd_partition *parts; ++}; ++ ++#endif /* __MACH_FLASH_H */ ++ ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/gk710xs.h b/arch/arm/mach-gk710xs/include/mach/gk710xs.h +new file mode 100644 +index 00000000..6ecbdd0d +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/gk710xs.h +@@ -0,0 +1,183 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/gk.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_GK710X_H ++#define __MACH_GK710X_H ++ ++ ++#include ++#include ++ ++#define CHIP_ID(x) ((x / 1000)) ++#define CHIP_MAJOR(x) ((x / 100) % 10) ++#define CHIP_MINOR(x) ((x / 10) % 10) ++ ++/* ==========================================================================*/ ++#define GK_DEBUG_NULL (0) ++#define GK_DEBUG_MEDIA (1 << 0) ++#define GK_DEBUG_VI (1 << 1) ++#define GK_DEBUG_VO (1 << 2) ++#define GK_DEBUG_AAA (1 << 3) ++#define GK_DEBUG_DSP (1 << 4) ++ ++/* definition SOC types */ ++#define CONFIG_SOC_GK7101 0 ++#define CONFIG_SOC_GK7102 1 ++ ++#define CONFIG_U2K_PHY_TYPE 0xC0000000 ++#define CONFIG_U2K_ARM_FREQ 0xC0000004 ++#define CONFIG_U2K_HAL_ADDR 0xC0000008 ++ ++#define CONFIG_U2K_SOC_ADDR 0xC0000010 //0:, 1:7102 ++#define CONFIG_U2K_MEM_ADDR 0xC0000014 ++#define CONFIG_U2K_BSB_ADDR 0xC0000018 ++#define CONFIG_U2K_DSP_ADDR 0xC000001C ++ ++#define CONFIG_U2K_ENABLE 0xC0000020 ++#define CONFIG_U2K_USR_ADDR 0xC0000024 //for user's cmem module ++ ++#define CONFIG_U2K_TOTAL_MEM 0xC0000028 ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++/* ==========================================================================*/ ++extern u32 gk_debug_level; ++extern u32 gk_debug_info; ++ ++#define HW_HAL_MODE 0 ++#define USB_DMA_ADD_MODE 0 ++#define FLASH_HAL_MODE 0 ++ ++#define ADC_HAL_MODE 0 ++#define AUD_HAL_MODE 0 ++#define CRY_HAL_MODE 0 ++#define DDR_HAL_MODE 0 ++#define DMA_HAL_MODE 0 ++#define DSP_HAL_MODE 0 ++#define ETH_HAL_MODE 0 ++#define GREG_HAL_MODE 0 ++#define GPIO_HAL_MODE 0 ++#define I2C_HAL_MODE 0 ++#define I2S_HAL_MODE 0 ++#define IR_HAL_MODE 0 ++#define IRQ_HAL_MODE 0 ++#define MCU_HAL_MODE 0 ++#define PWM_HAL_MODE 0 ++#define RCT_HAL_MODE 0 ++#define SD_HAL_MODE 0 ++#define SF_HAL_MODE 0 ++#define SSI_HAL_MODE 1 ++#define TIMER_HAL_MODE 0 ++#define UART_HAL_MODE 1 ++#define USB_HAL_MODE 0 ++#define VOUT_HAL_MODE 0 ++#define WDT_HAL_MODE 0 ++#define EFUSE_HAL_MODE 0 ++struct hw_ops ++{ ++ int (*get_version)(void); ++ unsigned int (*reserved)(unsigned int ); ++ ++ unsigned char (*hw_readb)(unsigned int ); ++ unsigned short (*hw_readw)(unsigned int ); ++ unsigned int (*hw_readl)(unsigned int ); ++ ++ void (*hw_writeb)(unsigned char , unsigned int ); ++ void (*hw_writew)(unsigned short , unsigned int ); ++ void (*hw_writel)(unsigned int , unsigned int ); ++ ++ unsigned int (*flash_read)(void); ++ void (*flash_write)(unsigned int); ++}; ++ ++extern struct hw_ops *g_hw; ++ ++extern unsigned long gk_debug_lookup_name(const char *name); ++void sensor_init(u8 active_level); ++void sensor_power(u8 power); ++u32 get_audio_clk_freq(void); ++ ++ ++#endif /* __ASSEMBLER__ */ ++ ++extern u32 get_ppm_phys(void); ++extern u32 get_ppm_virt(void); ++extern u32 get_ppm_size(void); ++ ++extern u32 get_bsbmem_phys(void); ++extern u32 get_bsbmem_virt(void); ++extern u32 get_bsbmem_size(void); ++ ++extern u32 get_dspmem_phys(void); ++extern u32 get_dspmem_virt(void); ++extern u32 get_dspmem_size(void); ++ ++extern u32 gk_phys_to_virt(u32 paddr); ++extern u32 gk_virt_to_phys(u32 vaddr); ++ ++extern u32 get_hal1_virt(void); ++extern u32 get_hal2_virt(void); ++ ++extern u32 get_ahb_phys(void); ++extern u32 get_ahb_virt(void); ++extern u32 get_ahb_size(void); ++ ++extern u32 get_apb_phys(void); ++extern u32 get_apb_virt(void); ++extern u32 get_apb_size(void); ++ ++extern u32 get_osd_phys(void); ++extern u32 get_osd_virt(void); ++extern u32 get_osd_size(void); ++ ++extern u32 get_pri_phys(void); ++extern u32 get_pri_virt(void); ++extern u32 get_pri_size(void); ++ ++extern u32 get_qpm_phys(void); ++extern u32 get_qpm_virt(void); ++extern u32 get_qpm_size(void); ++ ++extern u32 get_bsbmem_virt(void); ++extern u32 get_bsbmem_size(void); ++ ++extern u32 get_usrmem_phys(void); ++extern u32 get_usrmem_virt(void); ++extern u32 get_usrmem_size(void); ++ ++extern void get_stepping_info(int *chip, int *major, int *minor); ++extern int gk_register_event_notifier(void *nb); ++ ++extern u32 gk_boot_splash_logo; ++ ++extern u64 gk_dmamask; ++ ++extern int gk_create_proc_dir(void); ++extern struct proc_dir_entry *get_gk_proc_dir(void); ++ ++extern void get_stepping_info(int *chip, int *major, int *minor); ++ ++extern void gk_restart(char mode, const char *cmd); ++extern void gk_power_off(void); ++ ++extern void gk_map_io(void) __init; ++ ++extern void gk_load_51mcu_code(u32 code); ++ ++#endif /* __MACH_GK_H */ ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/gpio.h b/arch/arm/mach-gk710xs/include/mach/gpio.h +new file mode 100644 +index 00000000..4129060a +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/gpio.h +@@ -0,0 +1,116 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/gpio.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_GPIO_H_ ++#define __MACH_GPIO_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Defines and Macros ++//***************************************************************************** ++//***************************************************************************** ++#define GPIO0_BASE (GK_VA_GPIO0) ++#define GPIO0_BANK0_BASE (GK_VA_GPIO0) ++#define GPIO0_BANK1_BASE (GK_VA_GPIO0) ++#define GPIO0_BANK0_PLL_IOCTRL_BASE (GK_VA_RCT + 0x0230) /* read/write */ ++#define GPIO0_BANK1_PLL_IOCTRL_BASE (GK_VA_RCT + 0x0230 - 0x100) /* read/write */ ++ ++// for bank ++#define REG_GPIO_IS_LOW_OFFSET (0x0000) /* read/write */ ++#define REG_GPIO_IS_HIGH_OFFSET (0x0004) /* read/write */ ++#define REG_GPIO_IBE_LOW_OFFSET (0x0008) /* read/write */ ++#define REG_GPIO_IBE_HIGH_OFFSET (0x000C) /* read/write */ ++#define REG_GPIO_IEV_LOW_OFFSET (0x0010) /* read/write */ ++#define REG_GPIO_IEV_HIGH_OFFSET (0x0014) /* read/write */ ++#define REG_GPIO_IE_LOW_OFFSET (0x0018) /* read/write */ ++#define REG_GPIO_IE_HIGH_OFFSET (0x001C) /* read/write */ ++#define REG_GPIO_IC_LOW_OFFSET (0x0020) /* write */ ++#define REG_GPIO_IC_HIGH_OFFSET (0x0024) /* write */ ++#define REG_GPIO_RIS_LOW_OFFSET (0x0028) /* read */ ++#define REG_GPIO_RIS_HIGH_OFFSET (0x002C) /* read */ ++#define REG_GPIO_MIS_LOW_OFFSET (0x0030) /* read */ ++#define REG_GPIO_MIS_HIGH_OFFSET (0x0034) /* read */ ++#define REG_GPIO_DIN_LOW_OFFSET (0x0040) /* read */ ++#define REG_GPIO_DIN_HIGH_OFFSET (0x0044) /* read */ ++#define REG_GPIO_OUTPUT_CFG_OFFSET (0x0100) /* write */ ++#define REG_GPIO_INPUT_CFG_OFFSET (0x0200) /* write */ ++ ++// for all bank ++#define REG_GPIO_INT_EN_OFFSET (0x0038) /* write */ ++#define REG_GPIO_PER_SEL_OFFSET (0x003C) /* read/write */ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Enumerated types ++//***************************************************************************** ++//***************************************************************************** ++ ++/////add: ++//#if defined(CONFIG_MACH_GK7102S_ELEC_SC1135_V1_00) ++//#include "gpio_elec_sc1135_v1.h" ++//#endif ++/*! ++******************************************************************************* ++** ++** \brief All available GPIO pins named by number. ++** ++** \sa GPIO_Open() ++** \sa GPIO_OpenFunctionMode() ++** \sa GPIO_SetType() ++** ++******************************************************************************* ++*/ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Data Structures ++//***************************************************************************** ++//***************************************************************************** ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Global Data ++//***************************************************************************** ++//***************************************************************************** ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** API Functions ++//***************************************************************************** ++//***************************************************************************** ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++extern int __init gk_init_gpio(void); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++ ++#endif /* __MACH_GPIO_H_ */ ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/gpio_elec_sc1135_v1.h b/arch/arm/mach-gk710xs/include/mach/gpio_elec_sc1135_v1.h +new file mode 100644 +index 00000000..9c8d2ef0 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/gpio_elec_sc1135_v1.h +@@ -0,0 +1,118 @@ ++#ifndef _GPIO_ELEC_SC1135_V1_H_ ++#define _GPIO_ELEC_SC1135_V1_H_ ++ ++#ifdef CONFIG_PHY_USE_AO_MCLK ++ #define SYSTEM_GPIO_PHY_CLK GPIO_TYPE_OUTPUT_AOMCLK ++#endif ++#ifdef CONFIG_PHY_USE_SD_CLK ++ #define SYSTEM_GPIO_PHY_CLK GPIO_TYPE_OUTPUT_SDIO_CLK ++#endif ++#ifdef CONFIG_PHY_USE_EXTERN_CLK ++ #define SYSTEM_GPIO_PHY_CLK GPIO_TYPE_INPUT ++#endif ++ ++ ++#if defined(CONFIG_MACH_GK7101S_ELEC_SC1135_V1_00) || defined(CONFIG_MACH_GK7102S_ELEC_SC1135_V1_00) ++#define SYSTEM_GPIO_EXTPHY_TABLE \ ++ { GPIO_3 , GPIO_TYPE_INPUT_ENET_PHY_RXDV }, \ ++ { GPIO_30, GPIO_TYPE_OUTPUT_ENET_PHY_TXEN }, \ ++ { GPIO_31, GPIO_TYPE_OUTPUT_ENET_PHY_TXD_1 }, \ ++ { GPIO_32, GPIO_TYPE_OUTPUT_ENET_PHY_TXD_0 }, \ ++ { GPIO_33, GPIO_TYPE_INPUT_ENET_PHY_RXER }, \ ++ { GPIO_35, GPIO_TYPE_OUTPUT_ENET_GMII_MDC_O }, \ ++ { GPIO_36, GPIO_TYPE_INOUT_ETH_MDIO }, \ ++ { GPIO_48, GPIO_TYPE_INPUT }, \ ++ { GPIO_49, GPIO_TYPE_OUTPUT_1 /*ETH reset*/}, \ ++ { GPIO_50, SYSTEM_GPIO_PHY_CLK }, \ ++ { GPIO_51, GPIO_TYPE_INPUT_ENET_PHY_RXD_1 }, \ ++ { GPIO_52, GPIO_TYPE_INPUT_ENET_PHY_RXD_2 /*CLK*/}, \ ++ { GPIO_53, GPIO_TYPE_INPUT_ENET_PHY_RXD_0 }, \ ++ { GPIO_54, GPIO_TYPE_INPUT }, ++ ++#define SYSTEM_GPIO_INTPHY_TABLE \ ++ { GPIO_3 , GPIO_TYPE_INPUT }, \ ++ { GPIO_30, GPIO_TYPE_INPUT }, \ ++ { GPIO_31, GPIO_TYPE_INPUT }, \ ++ { GPIO_32, GPIO_TYPE_INPUT }, \ ++ { GPIO_33, GPIO_TYPE_INPUT }, \ ++ { GPIO_35, GPIO_TYPE_INPUT }, \ ++ { GPIO_36, GPIO_TYPE_INPUT }, \ ++ { GPIO_48, SYSTEM_GPIO_PHY_CLK }, \ ++ { GPIO_49, GPIO_TYPE_INPUT }, \ ++ { GPIO_50, GPIO_TYPE_INPUT }, \ ++ { GPIO_51, GPIO_TYPE_INPUT }, \ ++ { GPIO_52, GPIO_TYPE_INPUT }, \ ++ { GPIO_53, GPIO_TYPE_INPUT }, \ ++ { GPIO_54, GPIO_TYPE_OUTPUT_EPHY_LED_3 }, ++ ++#define SYSTEM_GPIO_XREF_TABLE \ ++ { GPIO_0 , GPIO_TYPE_OUTPUT_SF_CS0 }, \ ++ { GPIO_1 , GPIO_TYPE_OUTPUT_SF_CS1 }, \ ++ { GPIO_2 , GPIO_TYPE_INPUT }, \ ++ { GPIO_4 , GPIO_TYPE_INPUT }, \ ++ { GPIO_5 , GPIO_TYPE_INPUT }, \ ++ { GPIO_6 , GPIO_TYPE_INPUT }, \ ++ { GPIO_7 , GPIO_TYPE_INPUT }, \ ++ { GPIO_8 , GPIO_TYPE_INPUT }, \ ++ { GPIO_9 , GPIO_TYPE_INPUT }, \ ++ { GPIO_10, GPIO_TYPE_INPUT }, \ ++ { GPIO_11, GPIO_TYPE_INPUT }, \ ++ { GPIO_12, GPIO_TYPE_OUTPUT_0 /*IR_LED_CTRL*/}, \ ++ { GPIO_13, GPIO_TYPE_INPUT }, \ ++ { GPIO_14, GPIO_TYPE_INPUT }, \ ++ { GPIO_15, GPIO_TYPE_INPUT /*IR_DET_ADC*/}, \ ++ { GPIO_16, GPIO_TYPE_INPUT }, \ ++ { GPIO_17, GPIO_TYPE_INPUT }, \ ++ { GPIO_18, GPIO_TYPE_INPUT }, \ ++ { GPIO_19, GPIO_TYPE_INPUT }, \ ++ { GPIO_20, GPIO_TYPE_OUTPUT_0 /*IR_CUT+*/}, \ ++ { GPIO_21, GPIO_TYPE_INPUT }, \ ++ { GPIO_22, GPIO_TYPE_INPUT }, \ ++ { GPIO_23, GPIO_TYPE_OUTPUT_0 /*IR_CUT-*/}, \ ++ { GPIO_24, GPIO_TYPE_INPUT }, \ ++ { GPIO_25, GPIO_TYPE_INPUT_UART0_RX }, \ ++ { GPIO_26, GPIO_TYPE_OUTPUT_UART0_TX }, \ ++ { GPIO_27, GPIO_TYPE_OUTPUT_1 /*Sensor reset*/}, \ ++ { GPIO_28, GPIO_TYPE_INOUT_I2C_DATA /*S D*/}, \ ++ { GPIO_29, GPIO_TYPE_INOUT_I2C_CLK /*S C*/}, \ ++ { GPIO_34, GPIO_TYPE_INPUT }, \ ++ { GPIO_37, GPIO_TYPE_INPUT }, \ ++ { GPIO_38, GPIO_TYPE_INPUT }, \ ++ { GPIO_39, GPIO_TYPE_INPUT_SD_CD_N }, \ ++ { GPIO_40, GPIO_TYPE_INPUT }, \ ++ { GPIO_41, GPIO_TYPE_INOUT_SD_DATA_3 }, \ ++ { GPIO_42, GPIO_TYPE_INOUT_SD_DATA_2 }, \ ++ { GPIO_43, GPIO_TYPE_INOUT_SD_CMD }, \ ++ { GPIO_44, GPIO_TYPE_OUTPUT_SDIO_CLK }, \ ++ { GPIO_45, GPIO_TYPE_INOUT_SD_DATA_1 }, \ ++ { GPIO_46, GPIO_TYPE_OUTPUT_1/*SDIO_CARD_POWER_EN*/}, \ ++ { GPIO_47, GPIO_TYPE_INOUT_SD_DATA_0 }, \ ++ { GPIO_55, GPIO_TYPE_INPUT }, \ ++ { GPIO_56, GPIO_TYPE_INPUT }, \ ++ { GPIO_57, GPIO_TYPE_INPUT }, \ ++ { GPIO_58, GPIO_TYPE_INPUT }, \ ++ { GPIO_59, GPIO_TYPE_INPUT }, \ ++ { GPIO_60, GPIO_TYPE_INPUT }, \ ++ { GPIO_61, GPIO_TYPE_INPUT }, \ ++ { GPIO_62, GPIO_TYPE_INPUT } ++ ++#define SYSTEM_GPIO_IR_LED_CTRL GPIO_4 // not real pin ++#define SYSTEM_GPIO_IR_CUT1 GPIO_20 ++#define SYSTEM_GPIO_IR_CUT2 GPIO_23 ++#define SYSTEM_GPIO_SENSOR_RESET GPIO_27 ++#define SYSTEM_GPIO_PHY_RESET GPIO_49 ++#define SYSTEM_GPIO_PHY_SPEED_LED GPIO_54 ++ ++#define SYSTEM_GPIO_SPI0_EN0 GPIO_5 // not real pin ++#define SYSTEM_GPIO_SPI1_EN0 GPIO_6 // not real pin ++#define SYSTEM_GPIO_PWM0 GPIO_7 // not real pin ++#define SYSTEM_GPIO_PWM1 GPIO_8 // not real pin ++#define SYSTEM_GPIO_PWM2 GPIO_9 // not real pin ++#define SYSTEM_GPIO_PWM3 GPIO_10 // not real pin ++#define SYSTEM_GPIO_USB_HOST GPIO_11 // not real pin ++#define SYSTEM_GPIO_SD_DETECT GPIO_39 ++#define SYSTEM_GPIO_SD_POWER GPIO_46 ++#endif /* CONFIG_MACH_GK7102S_ELEC_SC1135_V1_00 */ ++ ++#endif /* _GPIO_RB_SC1035_H_ */ ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/gtypes.h b/arch/arm/mach-gk710xs/include/mach/gtypes.h +new file mode 100644 +index 00000000..26932665 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/gtypes.h +@@ -0,0 +1,132 @@ ++#ifndef _GTYPES_H_ ++#define _GTYPES_H_ ++ ++#ifdef __LINUX__ ++#include /* kmalloc */ ++#include /* printk */ ++#include /* wait queue */ ++#include /* copy user<->kernel */ ++#include /* paddr<->vaddr */ ++#include /* semaphore */ ++#include /* poll */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++/* necessary undefines */ ++#ifdef GFALSE ++ #undef GFALSE ++#endif ++#ifdef GTRUE ++ #undef GTRUE ++#endif ++ ++ ++/*! ++******************************************************************************* ++** ++** \name GOKESDK Error Codes ++** ++******************************************************************************* ++*/ ++/*@{*/ ++enum ++{ ++ GD_OK = 0, //!< No error. ++ GD_ERR_BAD_PARAMETER, //!< Bad parameter passed. ++ GD_ERR_OUT_OF_MEMORY, //!< Memory allocation failed. ++ GD_ERR_ALREADY_INITIALIZED, //!< Device already initialised. ++ GD_ERR_NOT_INITIALIZED, //!< Device not initialised. ++ GD_ERR_ALREADY_OPEN, //!< Device could not be opened again. ++ GD_ERR_FEATURE_NOT_SUPPORTED, //!< Feature or function is not available. ++ GD_ERR_TIMEOUT, //!< Timeout occured. ++ GD_ERR_DEVICE_BUSY, //!< The device is busy. ++ GD_ERR_INVALID_HANDLE, //!< The handle is invalid. ++}; ++/*@}*/ ++ ++ ++/*! ++******************************************************************************* ++** ++** \name GOKESDK Data Types ++** ++******************************************************************************* ++*/ ++/*@{*/ ++typedef unsigned char U8; //!< 8 bit unsigned integer. ++typedef unsigned short U16; //!< 16 bit unsigned integer. ++#ifdef __LINUX__ ++typedef unsigned int U32; //!< 32 bit unsigned integer. ++typedef signed int S32; //!< 32 bit signed integer. ++#else ++typedef unsigned long U32; //!< 32 bit unsigned integer. ++typedef signed long S32; //!< 32 bit signed integer. ++#endif ++typedef signed char S8; //!< 8 bit signed integer. ++typedef signed short S16; //!< 16 bit signed integer. ++typedef unsigned long long U64; //!< 64 bit unsigned integer. ++ ++#ifdef __LINUX__ ++typedef int GERR; ++#else ++typedef unsigned long GERR; //!< GOKESDK error/return code. ++#endif ++typedef unsigned long GD_HANDLE; //!< GOKESDK handle. ++ ++/*! \brief Defines a GOKESDK boolean. */ ++#ifndef GTYPES_NO_BOOL ++typedef enum ++{ ++ GFALSE = 0, //!< Logical false. ++ GTRUE = 1 //!< Logical true. ++} GBOOL; ++#endif ++/*@}*/ ++ ++ ++ ++ ++/*! ++******************************************************************************* ++** ++** \brief Defines a GOKESDK null. ++** ++******************************************************************************* ++*/ ++#ifndef NULL ++ #define NULL 0 ++#endif ++ ++ ++/* ++******************************************************************************* ++** ++** Defines the keyword for inlining a function. ++** ++******************************************************************************* ++*/ ++ ++#define GH_INLINE_LEVEL 2 ++ ++#if defined(__HIGHC__) ++#define GH_INLINE _Inline ++#endif ++#if defined(__GNUC__) ++#define GH_INLINE static __inline__ ++#endif ++ ++#ifdef GISR_IS_VOID ++ #define GISR1 void /* customize C-Interrupt handler */ ++ #define GISR2 void ++#else ++ #define GISR1 irqreturn_t ++ #define GISR2 irqreturn_t ++#endif ++ ++#endif +\ No newline at end of file +diff --git a/arch/arm/mach-gk710xs/include/mach/hardware.h b/arch/arm/mach-gk710xs/include/mach/hardware.h +new file mode 100644 +index 00000000..56dabda4 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/hardware.h +@@ -0,0 +1,223 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/hardware.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++ ++#ifndef __ASM_ARCH_HARDWARE_H ++#define __ASM_ARCH_HARDWARE_H ++ ++#include ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++ ++/*-------------------------------------------------------------*/ ++ ++#define CONFIG_GK_PPM_SIZE 0x200000 ++ ++#define DEFAULT_MEM_START (0xc0000000) ++ ++ ++#define AHB_SIZE (0x01000000) ++#define APB_SIZE (0x01000000) ++ ++#define NOLINUX_MEM_V_START (0xe0000000) ++#define NOLINUX_MEM_V_SIZE (0x00100000) ++ ++ ++//-------------------dummy-----ahb----------- ++#define GK_PA_AHB_BASE (0x90000000) ++#define GK_VA_AHB_BASE (0xf2000000) ++ ++#define GK_ADDR_SDC_OFFSET 0x00000 //0x02000 //for dummy ++#define GK_ADDR_SDC1_OFFSET 0x10000 //0x02000 //for dummy ++#define GK_ADDR_EFUSE_OFFSET 0x01000 ++#define GK_ADDR_DDRC_OFFSET 0x02000 ++#define GK_ADDR_DMAC_OFFSET 0x03000 ++#define GK_ADDR_VO_OFFSET 0x04000 ++#define GK_ADDR_CRYPT_OFFSET 0x05000 ++#define GK_ADDR_USB_OFFSET 0x06000 ++#define GK_ADDR_VIC1_OFFSET 0x08000 ++#define GK_ADDR_VIC2_OFFSET 0x09000 ++#define GK_ADDR_ETH_GMAC_OFFSET 0x0E000 ++#define GK_ADDR_ETH_DMA_OFFSET 0x0F000 ++#define GK_ADDR_I2S_OFFSET 0x0A000 ++#define GK_ADDR_SFLASH_OFFSET 0x16000 ++ ++#define GK_ADDR_ADC_OFFSET 0x20A00 ++#define GK_ADDR_AHB_GREG_OFFSET 0x20E00 ++#define GK_ADDR_USB_PHY_OFFSET 0x21000 ++#define GK_ADDR_ENET_PHY_OFFSET 0x22000 ++#define GK_ADDR_VEDIO_DAC_OFFSET 0x22600 ++ ++ ++#define GK_ADDR_PMU_OFFSET 0x80000 ++#define GK_ADDR_PMU_RTC_OFFSET 0x80000 ++#define GK_ADDR_PMU_C51_CODE_OFFSET 0xC0000 ++ ++ ++#define GK_ADDR_AUDIO_CODEC_ANALOG_OFFSET 0x21C00 ++#define GK_ADDR_AUDIO_CODEC_DIGITAL_OFFSET 0x20C00 ++ ++ ++#define GK_PA_SDC (GK_PA_AHB_BASE + GK_ADDR_SDC_OFFSET) ++#define GK_PA_SDC1 (GK_PA_AHB_BASE + GK_ADDR_SDC1_OFFSET) ++#define GK_PA_I2S (GK_PA_AHB_BASE + GK_ADDR_I2S_OFFSET) ++#define GK_PA_AHB_GREG (GK_PA_AHB_BASE + GK_ADDR_AHB_GREG_OFFSET) ++#define GK_PA_EFUSE (GK_PA_AHB_BASE + GK_ADDR_EFUSE_OFFSET) ++#define GK_PA_SFLASH (GK_PA_AHB_BASE + GK_ADDR_SFLASH_OFFSET) ++#define GK_PA_ADC (GK_PA_AHB_BASE + GK_ADDR_ADC_OFFSET) ++#define GK_PA_VO (GK_PA_AHB_BASE + GK_ADDR_VO_OFFSET) ++#define GK_PA_AUDIO_CODEC_DIGITAL (GK_PA_AHB_BASE + GK_ADDR_AUDIO_CODEC_DIGITAL_OFFSET) ++#define GK_PA_AUDIO_CODEC_ANALOG (GK_PA_AHB_BASE + GK_ADDR_AUDIO_CODEC_ANALOG_OFFSET) ++#define GK_PA_DDRC (GK_PA_AHB_BASE + GK_ADDR_DDRC_OFFSET) ++#define GK_PA_VIC1 (GK_PA_AHB_BASE + GK_ADDR_VIC1_OFFSET) ++#define GK_PA_VIC2 (GK_PA_AHB_BASE + GK_ADDR_VIC2_OFFSET) ++#define GK_PA_ETH_GMAC (GK_PA_AHB_BASE + GK_ADDR_ETH_GMAC_OFFSET) ++#define GK_PA_ETH_DMA (GK_PA_AHB_BASE + GK_ADDR_ETH_DMA_OFFSET) ++#define GK_PA_USB_PHY (GK_PA_AHB_BASE + GK_ADDR_USB_PHY_OFFSET) ++#define GK_PA_ETH_PHY (GK_PA_AHB_BASE + GK_ADDR_ENET_PHY_OFFSET) ++#define GK_PA_PMU (GK_PA_AHB_BASE + GK_ADDR_PMU_OFFSET) ++#define GK_PA_PMU_RTC (GK_PA_AHB_BASE + GK_ADDR_PMU_RTC_OFFSET) ++#define GK_PA_PMU_C51_CODE (GK_PA_AHB_BASE + GK_ADDR_PMU_C51_CODE_OFFSET) ++#define GK_PA_VEDIO_DAC (GK_PA_AHB_BASE + GK_ADDR_VEDIO_DAC_OFFSET) ++#define GK_PA_CRYPT_UNIT (GK_PA_AHB_BASE + GK_ADDR_CRYPT_OFFSET) ++ ++#define GK_VA_SDC (GK_VA_AHB_BASE + GK_ADDR_SDC_OFFSET) ++#define GK_VA_SDC1 (GK_VA_AHB_BASE + GK_ADDR_SDC1_OFFSET) ++#define GK_VA_I2S (GK_VA_AHB_BASE + GK_ADDR_I2S_OFFSET) ++#define GK_VA_AHB_GREG (GK_VA_AHB_BASE + GK_ADDR_AHB_GREG_OFFSET) ++#define GK_VA_EFUSE (GK_VA_AHB_BASE + GK_ADDR_EFUSE_OFFSET) ++#define GK_VA_ADC (GK_VA_AHB_BASE + GK_ADDR_ADC_OFFSET) ++#define GK_VA_DDRC (GK_VA_AHB_BASE + GK_ADDR_DDRC_OFFSET) ++#define GK_VA_VIC1 (GK_VA_AHB_BASE + GK_ADDR_VIC1_OFFSET) ++#define GK_VA_VIC2 (GK_VA_AHB_BASE + GK_ADDR_VIC2_OFFSET) ++#define GK_VA_ETH_GMAC (GK_VA_AHB_BASE + GK_ADDR_ETH_GMAC_OFFSET) ++#define GK_VA_ETH_DMA (GK_VA_AHB_BASE + GK_ADDR_ETH_DMA_OFFSET) ++#define GK_VA_USB_PHY (GK_VA_AHB_BASE + GK_ADDR_USB_PHY_OFFSET) ++#define GK_VA_ETH_PHY (GK_VA_AHB_BASE + GK_ADDR_ENET_PHY_OFFSET) ++#define GK_VA_PMU (GK_VA_AHB_BASE + GK_ADDR_PMU_OFFSET) ++#define GK_VA_PMU_RTC (GK_VA_AHB_BASE + GK_ADDR_PMU_RTC_OFFSET) ++#define GK_VA_SFLASH (GK_VA_AHB_BASE + GK_ADDR_SFLASH_OFFSET) ++#define GK_VA_VO (GK_VA_AHB_BASE + GK_ADDR_VO_OFFSET) ++#define GK_VA_AUDIO_CODEC_DIGITAL (GK_VA_AHB_BASE + GK_ADDR_AUDIO_CODEC_DIGITAL_OFFSET) ++#define GK_VA_AUDIO_CODEC_ANALOG (GK_VA_AHB_BASE + GK_ADDR_AUDIO_CODEC_ANALOG_OFFSET) ++#define GK_VA_PMU_C51_CODE (GK_VA_AHB_BASE + GK_ADDR_PMU_C51_CODE_OFFSET) ++#define GK_VA_VEDIO_DAC (GK_VA_AHB_BASE + GK_ADDR_VEDIO_DAC_OFFSET) /*cvbs*/ ++#define GK_VA_CRYPT_UNIT (GK_VA_AHB_BASE + GK_ADDR_CRYPT_OFFSET) ++ ++#define GK_PA_DMAC (GK_PA_AHB_BASE + GK_ADDR_DMAC_OFFSET) ++#define GK_PA_USB (GK_PA_AHB_BASE + GK_ADDR_USB_OFFSET) ++#define GK_VA_DMAC (GK_VA_AHB_BASE + GK_ADDR_DMAC_OFFSET) ++#define GK_VA_USB (GK_VA_AHB_BASE + GK_ADDR_USB_OFFSET) ++ ++ ++//-------------------dummy-----apb----------- ++#define GK_PA_APB_BASE (0xA0000000) ++#define GK_VA_APB_BASE (0xf3000000) ++ ++#define GK_ADDR_TIMER_OFFSET 0x00000 ++#define GK_ADDR_IDC_OFFSET 0x03000 ++#define GK_ADDR_IDC2_OFFSET 0x04000 ++#define GK_ADDR_UART0_OFFSET 0x05000 ++#define GK_ADDR_WDT_OFFSET 0x06000 ++#define GK_ADDR_GPIO0_OFFSET 0x09000 ++#define GK_ADDR_ADC2_OFFSET 0x07000 ++ ++#define GK_ADDR_PWM0_OFFSET 0x0a000 ++#define GK_ADDR_PWM1_OFFSET 0x0b000 ++#define GK_ADDR_PWM2_OFFSET 0x0c000 ++#define GK_ADDR_PWM3_OFFSET 0x0d000 ++ ++#define GK_ADDR_UART2_OFFSET 0x1E000 ++#define GK_ADDR_UART1_OFFSET 0x1F000 ++ ++#define GK_ADDR_SSI1_OFFSET 0x08000 ++#define GK_ADDR_SSI2_OFFSET 0x02000 ++#define GK_ADDR_TSSI_OFFSET 0x01000 ++ ++#define GK_ADDR_MEM_OFFSET 0x150000 ++#define GK_ADDR_RCT_OFFSET 0x170000 ++ ++ ++ ++#define GK_PA_TIMER (GK_PA_APB_BASE + GK_ADDR_TIMER_OFFSET) ++#define GK_PA_IDC (GK_PA_APB_BASE + GK_ADDR_IDC_OFFSET) ++#define GK_PA_IDC2 (GK_PA_APB_BASE + GK_ADDR_IDC2_OFFSET) ++#define GK_PA_UART0 (GK_PA_APB_BASE + GK_ADDR_UART0_OFFSET) ++#define GK_PA_WDT (GK_PA_APB_BASE + GK_ADDR_WDT_OFFSET) ++#define GK_PA_GPIO0 (GK_PA_APB_BASE + GK_ADDR_GPIO0_OFFSET) ++#define GK_PA_PWM0 (GK_PA_APB_BASE + GK_ADDR_PWM0_OFFSET) ++#define GK_PA_PWM1 (GK_PA_APB_BASE + GK_ADDR_PWM1_OFFSET) ++#define GK_PA_PWM2 (GK_PA_APB_BASE + GK_ADDR_PWM2_OFFSET) ++#define GK_PA_PWM3 (GK_PA_APB_BASE + GK_ADDR_PWM3_OFFSET) ++#define GK_PA_UART2 (GK_PA_APB_BASE + GK_ADDR_UART2_OFFSET) ++#define GK_PA_UART1 (GK_PA_APB_BASE + GK_ADDR_UART1_OFFSET) ++#define GK_PA_ADC2 (GK_PA_APB_BASE + GK_ADDR_ADC2_OFFSET) ++ ++#define GK_PA_SSI1 (GK_PA_APB_BASE + GK_ADDR_SSI1_OFFSET) ++#define GK_PA_SSI2 (GK_PA_APB_BASE + GK_ADDR_SSI2_OFFSET) ++#define GK_PA_TSSI (GK_PA_APB_BASE + GK_ADDR_TSSI_OFFSET) ++#define GK_PA_RCT (GK_PA_APB_BASE + GK_ADDR_RCT_OFFSET) ++#define GK_PA_MEM (GK_PA_APB_BASE + GK_ADDR_MEM_OFFSET) ++ ++ ++ ++#define GK_VA_TIMER (GK_VA_APB_BASE + GK_ADDR_TIMER_OFFSET) ++#define GK_VA_IDC (GK_VA_APB_BASE + GK_ADDR_IDC_OFFSET) ++#define GK_VA_IDC2 (GK_VA_APB_BASE + GK_ADDR_IDC2_OFFSET) ++#define GK_VA_UART0 (GK_VA_APB_BASE + GK_ADDR_UART0_OFFSET) ++#define GK_VA_WDT (GK_VA_APB_BASE + GK_ADDR_WDT_OFFSET) ++#define GK_VA_GPIO0 (GK_VA_APB_BASE + GK_ADDR_GPIO0_OFFSET) ++#define GK_VA_PWM0 (GK_VA_APB_BASE + GK_ADDR_PWM0_OFFSET) ++#define GK_VA_PWM1 (GK_VA_APB_BASE + GK_ADDR_PWM1_OFFSET) ++#define GK_VA_PWM2 (GK_VA_APB_BASE + GK_ADDR_PWM2_OFFSET) ++#define GK_VA_PWM3 (GK_VA_APB_BASE + GK_ADDR_PWM3_OFFSET) ++#define GK_VA_ADC2 (GK_VA_APB_BASE + GK_ADDR_ADC2_OFFSET) ++ ++#define GK_VA_UART2 (GK_VA_APB_BASE + GK_ADDR_UART2_OFFSET) ++#define GK_VA_UART1 (GK_VA_APB_BASE + GK_ADDR_UART1_OFFSET) ++ ++#define GK_VA_SSI1 (GK_VA_APB_BASE + GK_ADDR_SSI1_OFFSET) ++#define GK_VA_SSI2 (GK_VA_APB_BASE + GK_ADDR_SSI2_OFFSET) ++#define GK_VA_TSSI (GK_VA_APB_BASE + GK_ADDR_TSSI_OFFSET) ++#define GK_VA_RCT (GK_VA_APB_BASE + GK_ADDR_RCT_OFFSET) ++#define GK_VA_MEM (GK_VA_APB_BASE + GK_ADDR_MEM_OFFSET) ++ ++ ++#define GRAPHICS_DMA_OFFSET 0x15000 ++#define GRAPHICS_DMA_BASE (GK_VA_AHB_BASE + GRAPHICS_DMA_OFFSET) ++#define GRAPHICS_DMA_REG(x) (GRAPHICS_DMA_BASE + (x)) ++ ++ ++ ++#define VO_CLK_ONCHIP_PLL_27MHZ 0x0 /* Default setting */ ++#define VO_CLK_ONCHIP_PLL_SP_CLK 0x1 ++#define VO_CLK_ONCHIP_PLL_CLK_SI 0x2 ++#define VO_CLK_EXTERNAL 0x3 ++#define VO_CLK_ONCHIP_PLL_DSP_SCLK 0x4 ++ ++#define TIMER_OFFSET 0xb000 ++ ++ ++#define CONSISTENT_DMA_SIZE SZ_8M ++ ++/* ==========================================================================*/ ++ ++//end ++ ++#endif /* __ASM_ARCH_HARDWARE_H */ ++ ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/i2s.h b/arch/arm/mach-gk710xs/include/mach/i2s.h +new file mode 100644 +index 00000000..b3a531a1 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/i2s.h +@@ -0,0 +1,158 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/hal/i2s.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __HAL_I2S_H__ ++#define __HAL_I2S_H__ ++ ++#include ++ ++#define I2S_BASE (GK_VA_I2S) ++#define I2S_BASE_PHYS (GK_PA_I2S) ++#define I2S_REG(x) (I2S_BASE + (x)) ++#define I2S_REG_PHYS(x) (I2S_BASE_PHYS + (x)) ++ ++#define I2S_BASE_extern I2S_BASE ++ ++#define I2S_DMA_REG_OFFSET (0x00000000) ++ ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++ ++#define I2S_SUPPORT_GATE_SHIFT 1 ++#define I2S_MAX_CHANNELS 6 ++#define I2S_GK_IP 1 ++#define I2S_24BITMUX_MODE_REG_BITS 4 ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++ ++#define I2S_MODE_OFFSET 0x08 ++#define I2S_RX_CTRL_OFFSET 0x2c ++#define I2S_TX_CTRL_OFFSET 0x0c ++#define I2S_WLEN_OFFSET 0x58 ++#define I2S_WPOS_OFFSET 0x44 ++#define I2S_SLOT_OFFSET 0x50 ++#define I2S_TX_FIFO_LTH_OFFSET 0x10 ++#define I2S_RX_FIFO_GTH_OFFSET 0x3c ++#define I2S_CLOCK_OFFSET 0x00 ++#define I2S_INIT_OFFSET 0x4c ++#define I2S_TX_STATUS_OFFSET 0x14 ++#define I2S_TX_LEFT_DATA_OFFSET 0x1c ++#define I2S_TX_RIGHT_DATA_OFFSET 0x20 ++#define I2S_RX_STATUS_OFFSET 0x54 ++#define I2S_RX_DATA_OFFSET 0x30 ++#define I2S_TX_FIFO_CNTR_OFFSET 0x18 ++#define I2S_RX_FIFO_CNTR_OFFSET 0x34 ++#define I2S_TX_INT_ENABLE_OFFSET 0x24 ++#define I2S_RX_INT_ENABLE_OFFSET 0x38 ++#define I2S_RX_ECHO_OFFSET 0x40 ++#define I2S_24BITMUX_MODE_OFFSET 0x28 ++#define I2S_RX_DATA_DMA_OFFSET 0x80 ++#define I2S_TX_LEFT_DATA_DMA_OFFSET 0xc0 ++ ++#define I2S_MODE_REG I2S_REG(0x08) ++#define I2S_RX_CTRL_REG I2S_REG(0x2c) ++#define I2S_TX_CTRL_REG I2S_REG(0x0c) ++#define I2S_WLEN_REG I2S_REG(0x58) ++#define I2S_WPOS_REG I2S_REG(0x44) ++#define I2S_SLOT_REG I2S_REG(0x50) ++#define I2S_TX_FIFO_LTH_REG I2S_REG(0x10) ++#define I2S_RX_FIFO_GTH_REG I2S_REG(0x3c) ++#define I2S_CLOCK_REG I2S_REG(0x00) ++#define I2S_INIT_REG I2S_REG(0x4c) ++#define I2S_TX_STATUS_REG I2S_REG(0x14) ++#define I2S_TX_LEFT_DATA_REG I2S_REG(0x1c) ++#define I2S_TX_RIGHT_DATA_REG I2S_REG(0x20) ++#define I2S_RX_STATUS_REG I2S_REG(0x54) ++#define I2S_RX_DATA_REG I2S_REG(0x30) ++#define I2S_TX_FIFO_CNTR_REG I2S_REG(0x18) ++#define I2S_RX_FIFO_CNTR_REG I2S_REG(0x34) ++#define I2S_TX_INT_ENABLE_REG I2S_REG(0x24) ++#define I2S_RX_INT_ENABLE_REG I2S_REG(0x38) ++#define I2S_RX_ECHO_REG I2S_REG(0x40) ++#define I2S_24BITMUX_MODE_REG I2S_REG(0x28) ++#define I2S_GATEOFF_REG I2S_REG(0x48) ++#define I2S_CHANNEL_SELECT_REG I2S_REG(0x04) ++#define I2S_RX_DATA_DMA_REG I2S_REG(0x80) ++#define I2S_TX_LEFT_DATA_DMA_REG I2S_REG(0xc0) ++ ++ ++#if (I2S_GK_IP == 1) ++#define I2S_TX_FIFO_RESET_BIT (1 << 0) ++#define I2S_RX_FIFO_RESET_BIT (1 << 3) ++#endif ++#define I2S_TX_ENABLE_BIT (1 << 2) ++#define I2S_RX_ENABLE_BIT (1 << 1) ++#define I2S_FIFO_RESET_BIT (1 << 4) ++ ++#define I2S_RX_LOOPBACK_BIT (1 << 2) ++#define I2S_RX_ORDER_BIT (1 << 0) ++#define I2S_RX_WS_MST_BIT (1 << 3) ++#define I2S_RX_WS_INV_BIT (1 << 1) ++ ++#define I2S_TX_LOOPBACK_BIT (1 << 5) ++#define I2S_TX_ORDER_BIT (1 << 3) ++#define I2S_TX_WS_MST_BIT (1 << 6) ++#define I2S_TX_WS_INV_BIT (1 << 2) ++#define I2S_TX_UNISON_BIT (1 << 4) ++#define I2S_TX_MUTE_BIT (1 << 7) ++#define I2S_TX_MONO_MASK 0xfffffffc ++#define I2S_TX_MONO_STEREO (0) ++#define I2S_TX_MONO_RIGHT (2) ++#define I2S_TX_MONO_LEFT (3) ++ ++#define I2S_CLK_WS_OUT_EN (1 << 7) ++#define I2S_CLK_BCLK_OUT_EN (1 << 5) ++#define I2S_CLK_BCLK_OUTPUT (1 << 8) ++#define I2S_CLK_TX_PO_FALL (1 << 9) ++#define I2S_CLK_RX_PO_FALL (1 << 6) ++#define I2S_CLK_DIV_MASK 0xffffffe0 ++#define I2S_CLK_MASTER_MODE (I2S_CLK_WS_OUT_EN | \ ++ I2S_CLK_BCLK_OUT_EN | \ ++ I2S_CLK_TX_PO_FALL | \ ++ I2S_CLK_RX_PO_FALL | \ ++ I2S_CLK_BCLK_OUTPUT) ++ ++ ++#if (I2S_GK_IP == 0) ++#define I2S_RX_SHIFT_ENB (1 << 2) ++#define I2S_TX_SHIFT_ENB (1 << 1) ++#else ++#define I2S_RX_SHIFT_ENB (1 << 1) ++#define I2S_TX_SHIFT_ENB (1 << 0) ++#endif ++ ++#define I2S_2CHANNELS_ENB 0x00 ++#define I2S_4CHANNELS_ENB 0x01 ++#define I2S_6CHANNELS_ENB 0x02 ++ ++#define I2S_FIFO_THRESHOLD_INTRPT 0x08 ++#define I2S_FIFO_FULL_INTRPT 0x02 ++#define I2S_FIFO_EMPTY_INTRPT 0x01 ++ ++/* I2S_24BITMUX_MODE_REG */ ++#define I2S_24BITMUX_MODE_BIT (1 << 3) ++#if (I2S_24BITMUX_MODE_REG_BITS == 4) ++#define I2S_24BITMUX_MODE_FDMA_BURST_DIS 0x2 ++#define I2S_24BITMUX_MODE_RST_CHAN0 0x4 ++#define I2S_24BITMUX_MODE_DMA_BOOTSEL 0x8 ++#endif ++ ++#endif /* __HAL_I2S_H__ */ +diff --git a/arch/arm/mach-gk710xs/include/mach/idc.h b/arch/arm/mach-gk710xs/include/mach/idc.h +new file mode 100644 +index 00000000..0b462563 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/idc.h +@@ -0,0 +1,165 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/idc.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++#ifndef __MACH_IDC_H__ ++#define __MACH_IDC_H__ ++ ++#include ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++ ++#define IDC_INSTANCES 2 ++#define IDCS_INSTANCES 0 ++ ++#define IDC_INTERNAL_DELAY_CLK 2 ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++#define IDC_PSLL_OFFSET 0x00 ++#define IDC_PSLH_OFFSET 0x04 ++#define IDC_FMCTRL_OFFSET 0x08 ++#define IDC_CTRL_OFFSET 0x0c ++#define IDC_STS_OFFSET 0x10 ++#define IDC_ENR_OFFSET 0x14 ++#define IDC_DATA_OFFSET 0x18 ++#define IDC_FMDATA_OFFSET 0x1c ++ ++#if (IDCS_INSTANCES >= 1) ++#define IDCS_ENR_OFFSET 0x00 ++#define IDCS_CTRL_OFFSET 0x04 ++#define IDCS_DATA_OFFSET 0x08 ++#define IDCS_STS_OFFSET 0x0c ++#define IDCS_FIFO_CNT_OFFSET 0x10 ++#define IDCS_RX_CNT_OFFSET 0x14 ++#define IDCS_TX_CNT_OFFSET 0x18 ++#define IDCS_HOLD_TIME_OFFSET 0x1c ++#define IDCS_SLAVE_ADDR_OFFSET 0x20 ++#define IDCS_SCL_TIMER_OFFSET 0x24 ++#define IDCS_TIMEOUT_STS_OFFSET 0x28 ++#endif ++ ++#define IDC_REG(x) (GK_PA_IDC + (x)) ++ ++#define IDC_ENR_REG IDC_REG(IDC_ENR_OFFSET) ++#define IDC_CTRL_REG IDC_REG(IDC_CTRL_OFFSET) ++#define IDC_DATA_REG IDC_REG(IDC_DATA_OFFSET) ++#define IDC_STS_REG IDC_REG(IDC_STS_OFFSET) ++#define IDC_PSLL_REG IDC_REG(IDC_PSLL_OFFSET) ++#define IDC_PSLH_REG IDC_REG(IDC_PSLH_OFFSET) ++#define IDC_FMCTRL_REG IDC_REG(IDC_FMCTRL_OFFSET) ++#define IDC_FMDATA_REG IDC_REG(IDC_FMDATA_OFFSET) ++ ++#if (IDC_INSTANCES >= 2) ++ ++#define IDC2_REG(x) (GK_PA_IDC2 + (x)) ++ ++#define IDC2_ENR_REG IDC2_REG(IDC_ENR_OFFSET) ++#define IDC2_CTRL_REG IDC2_REG(IDC_CTRL_OFFSET) ++#define IDC2_DATA_REG IDC2_REG(IDC_DATA_OFFSET) ++#define IDC2_STS_REG IDC2_REG(IDC_STS_OFFSET) ++#define IDC2_PSLL_REG IDC2_REG(IDC_PSLL_OFFSET) ++#define IDC2_PSLH_REG IDC2_REG(IDC_PSLH_OFFSET) ++#define IDC2_FMCTRL_REG IDC2_REG(IDC_FMCTRL_OFFSET) ++#define IDC2_FMDATA_REG IDC2_REG(IDC_FMDATA_OFFSET) ++#endif ++ ++#if (IDCS_INSTANCES >= 1) ++#define IDCS_ENR_REG IDCS_REG(IDCS_ENR_OFFSET) ++#define IDCS_CTRL_REG IDCS_REG(IDCS_CTRL_OFFSET) ++#define IDCS_DATA_REG IDCS_REG(IDCS_DATA_OFFSET) ++#define IDCS_STS_REG IDCS_REG(IDCS_STS_OFFSET) ++#define IDCS_FIFO_CNT_REG IDCS_REG(IDCS_FIFO_CNT_OFFSET) ++#define IDCS_RX_CNT_REG IDCS_REG(IDCS_RX_CNT_OFFSET) ++#define IDCS_TX_CNT_REG IDCS_REG(IDCS_TX_CNT_OFFSET) ++#define IDCS_HOLD_TIME_REG IDCS_REG(IDCS_HOLD_TIME_OFFSET) ++#define IDCS_SLAVE_ADDR_REG IDCS_REG(IDCS_SLAVE_ADDR_OFFSET) ++#define IDCS_SCL_TIMER_REG IDCS_REG(IDCS_SCL_TIMER_OFFSET) ++#define IDCS_TIMEOUT_STS_REG IDCS_REG(IDCS_TIMEOUT_STS_OFFSET) ++ ++ ++/* Bit/format definition */ ++ ++/* IDCS_CTRL_REG */ ++#define IDCS_IRQ_EN 0x02 ++#define IDCS_IRQ_P_SR_EN 0x04 ++#define IDCS_IRQ_FIFO_TH_EN 0x08 ++#define IDCS_IRQ_TIME_OUT_EN 0x10 ++ ++/* IDCS_STS_REG */ ++#define IDCS_TIMEOUT 0x100 ++#define IDCS_STOP 0x080 ++#define IDCS_REPEATED_START 0x040 ++#define IDCS_FIFO_TH_VLD 0x020 ++#define IDCS_SEL 0x010 ++#define IDCS_GENERAL_CALL 0x008 ++#define IDCS_FIFO_FULL 0x004 ++#define IDCS_FIFO_EMPTY 0x002 ++#define IDCS_RX_TX_STATE 0x001 ++ ++#define IDCS_TX_MODE 0x0 ++#define IDCS_RX_MODE 0x1 ++ ++#endif ++ ++/* ==========================================================================*/ ++/* IDC_ENABLE_REG */ ++#define IDC_ENR_ENABLE (0x01)//bit0 ++#define IDC_ENR_DISABLE (0x00) ++ ++/* IDC_CTRL_REG */ ++#define IDC_CTRL_IF (0x08)//bit3 ++#define IDC_CTRL_ACK (0x04)//bit2 ++#define IDC_CTRL_START (0x02)//bit1 ++#define IDC_CTRL_STOP (0x01)//bit0 ++#define IDC_CTRL_CLS (0x00) ++ ++#define IDC_FIFO_BUF_SIZE (63) ++ ++/* IDC_STS_REG */ ++#define IDC_STS_MODE (0x01)//1:master receiver; 0:master transmitter ++ ++/* IDC_FM_CTRL_REG */ ++ ++#define IDC_FMCTRL_IF (0x10)//bit4 ++#define IDC_FMCTRL_START (0x02)//bit1 ++#define IDC_FMCTRL_STOP (0x01)//bit0 ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++struct gk_platform_i2c { ++ int clk_limit; //Hz ++ int bulk_write_num; ++ unsigned int i2c_class; ++ u32 (*get_clock)(void); ++}; ++#define IDC_PARAM_CALL(id, arg, perm) \ ++ module_param_cb(idc##id##_clk_limit, ¶m_ops_int, &(arg.clk_limit), perm); \ ++ module_param_cb(idc##id##_bulk_write_num, ¶m_ops_int, &(arg.bulk_write_num), perm) ++ ++/* ==========================================================================*/ ++extern struct platform_device gk_idc; ++extern struct platform_device gk_idc_hdmi; ++//extern struct platform_device gk_i2cmux; ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif /* __MACH_IDC_H__ */ ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/io.h b/arch/arm/mach-gk710xs/include/mach/io.h +new file mode 100644 +index 00000000..866e4fca +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/io.h +@@ -0,0 +1,491 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/io.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_IO_H ++#define __MACH_IO_H ++ ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++ ++#ifndef __ASSEMBLER__ ++ ++#include ++ ++extern spinlock_t gk_reg_lock; ++extern unsigned long gk_reg_flags; ++extern u32 gk_reglock_count; ++ ++#define gk_hal_readb(a) g_hw->hw_readb((u32)(a)) ++#define gk_hal_readw(a) g_hw->hw_readw((u32)(a)) ++#define gk_hal_writeb(a,v) g_hw->hw_writeb((v),(u32)(a)) ++#define gk_hal_writew(a,v) g_hw->hw_writew((v),(u32)(a)) ++#define gk_hal_readl(a) g_hw->hw_readl((u32)(a)) ++#define gk_hal_writel(a,v) g_hw->hw_writel((v),(u32)(a)) ++#if FLASH_HAL_MODE ++#define gk_flash_read() g_hw->flash_read() ++#define gk_flash_write(v) g_hw->flash_write((v)) ++#else ++#define gk_flash_read() (*((volatile unsigned int *)(REG_SFLASH_DATA))) ++#define gk_flash_write(v) (*((volatile unsigned int *)(REG_SFLASH_DATA)) = (v)); ++#endif ++ ++#if 0 ++#define GK_REG_LOCK() spin_lock_irqsave(&gk_reg_lock, gk_reg_flags) ++#define GK_REG_UNLOCK() spin_unlock_irqrestore(&gk_reg_lock, gk_reg_flags) ++#define GK_INC_REGLOCK_COUNT() gk_reglock_count++ ++#else ++#define GK_REG_LOCK() ++#define GK_REG_UNLOCK() ++#define GK_INC_REGLOCK_COUNT() ++#endif ++ ++#define HAL_IO(mod) \ ++unsigned char gk_##mod##_readb(unsigned int addr) \ ++{\ ++ return g_hw->hw_readb((u32)(addr));\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_readb);\ ++unsigned short gk_##mod##_readw(unsigned int addr) \ ++{\ ++ return g_hw->hw_readw((u32)(addr));\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_readw);\ ++unsigned int gk_##mod##_readl(unsigned int addr) \ ++{\ ++ return g_hw->hw_readl((u32)(addr)); \ ++}\ ++EXPORT_SYMBOL(gk_##mod##_readl);\ ++void gk_##mod##_writeb(unsigned int addr,unsigned char val) \ ++{\ ++ g_hw->hw_writeb((val),(u32)(addr)); \ ++}\ ++EXPORT_SYMBOL(gk_##mod##_writeb); \ ++void gk_##mod##_writew(unsigned int addr,unsigned short val) \ ++{\ ++ g_hw->hw_writew((val),(u32)(addr)); \ ++}\ ++EXPORT_SYMBOL(gk_##mod##_writew); \ ++void gk_##mod##_writel(unsigned int addr,unsigned int val) \ ++{\ ++ g_hw->hw_writel((val),(u32)(addr));\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_writel); ++#define DIR_IO(mod) \ ++unsigned char gk_##mod##_readb(unsigned int addr) \ ++{\ ++ return *((volatile unsigned char*)(addr));\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_readb);\ ++unsigned short gk_##mod##_readw(unsigned int addr)\ ++{\ ++ return *((volatile unsigned short*)(addr));\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_readw);\ ++unsigned int gk_##mod##_readl(unsigned int addr)\ ++{\ ++ return *((volatile unsigned int*)(addr));\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_readl);\ ++void gk_##mod##_writeb(unsigned int addr,unsigned char val)\ ++{\ ++ *((volatile unsigned char*)(addr))= val;\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_writeb);\ ++void gk_##mod##_writew(unsigned int addr,unsigned short val)\ ++{\ ++ *((volatile unsigned short*)(addr))= val;\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_writew);\ ++void gk_##mod##_writel(unsigned int addr,unsigned int val)\ ++{\ ++ *((volatile unsigned int*)(addr))= val;\ ++}\ ++EXPORT_SYMBOL(gk_##mod##_writel); ++ ++ ++#define IO_DEC(mod) \ ++extern unsigned char gk_##mod##_readb(unsigned int addr); \ ++extern unsigned short gk_##mod##_readw(unsigned int addr); \ ++extern unsigned int gk_##mod##_readl(unsigned int addr); \ ++extern void gk_##mod##_writeb(unsigned int addr,unsigned char val); \ ++extern void gk_##mod##_writew(unsigned int addr,unsigned short val); \ ++extern void gk_##mod##_writel(unsigned int addr,unsigned int val); ++ ++IO_DEC(hw) ++IO_DEC(adc) ++IO_DEC(aud) ++IO_DEC(cry) ++IO_DEC(ddr) ++IO_DEC(dma) ++IO_DEC(dsp) ++IO_DEC(eth) ++IO_DEC(greg) ++IO_DEC(gpio) ++IO_DEC(i2c) ++IO_DEC(i2s) ++IO_DEC(ir) ++IO_DEC(irq) ++IO_DEC(mcu) ++IO_DEC(pmu) ++IO_DEC(rct) ++IO_DEC(sd) ++IO_DEC(sf) ++IO_DEC(ssi) ++IO_DEC(timer) ++IO_DEC(uart) ++IO_DEC(usb) ++IO_DEC(vout) ++IO_DEC(wdt) ++IO_DEC(pwm) ++IO_DEC(efuse) ++ ++#define GK_HAL_OS_LOCK() \ ++ do { \ ++ GK_REG_LOCK(); \ ++ GK_INC_REGLOCK_COUNT(); \ ++ } while(0) ++ ++ ++#define GK_HAL_OS_UNLOCK() \ ++ do { \ ++ GK_REG_UNLOCK(); \ ++ } while(0) ++ ++//-------------------------------------- ++static inline u8 __gk_readb(const volatile void __iomem *address) ++{ ++ u8 tmpval; ++ ++ GK_REG_LOCK(); ++ GK_INC_REGLOCK_COUNT(); ++ tmpval = gk_hw_readb((u32)address); ++ GK_REG_UNLOCK(); ++ ++ return tmpval; ++} ++ ++static inline void __gk_writeb(const volatile void __iomem *address, u8 value) ++{ ++ GK_REG_LOCK(); ++ GK_INC_REGLOCK_COUNT(); ++ gk_hw_writeb((u32)address,value); ++ GK_REG_UNLOCK(); ++} ++ ++static inline u16 __gk_readw(const volatile void __iomem *address) ++{ ++ u16 tmpval; ++ ++ GK_REG_LOCK(); ++ GK_INC_REGLOCK_COUNT(); ++ tmpval = gk_hw_readw((u32)address); ++ GK_REG_UNLOCK(); ++ ++ return tmpval; ++} ++ ++static inline void __gk_writew(const volatile void __iomem *address, u16 value) ++{ ++ GK_REG_LOCK(); ++ GK_INC_REGLOCK_COUNT(); ++ gk_hw_writew((u32)address,value); ++ GK_REG_UNLOCK(); ++} ++ ++static inline u32 __gk_readl(const volatile void __iomem *address) ++{ ++ u32 tmpval; ++ ++ GK_REG_LOCK(); ++ GK_INC_REGLOCK_COUNT(); ++ tmpval = gk_hw_readl((u32)address); ++ GK_REG_UNLOCK(); ++ ++ return tmpval; ++} ++ ++static inline void __gk_writel(const volatile void __iomem *address, u32 value) ++{ ++ GK_REG_LOCK(); ++ GK_INC_REGLOCK_COUNT(); ++ gk_hw_writel((u32)address,value); ++ GK_REG_UNLOCK(); ++} ++ ++#define gk_adc_setbitsb(v, mask) gk_adc_writeb((v),(gk_adc_readb((v)) | (mask))) ++#define gk_adc_setbitsw(v, mask) gk_adc_writew((v),(gk_adc_readw((v)) | (mask))) ++#define gk_adc_setbitsl(v, mask) gk_adc_writel((v),(gk_adc_readl((v)) | (mask))) ++#define gk_adc_clrbitsb(v, mask) gk_adc_writeb((v),(gk_adc_readb((v)) & ~(mask))) ++#define gk_adc_clrbitsw(v, mask) gk_adc_writew((v),(gk_adc_readw((v)) & ~(mask))) ++#define gk_adc_clrbitsl(v, mask) gk_adc_writel((v),(gk_adc_readl((v)) & ~(mask))) ++#define gk_adc_tstbitsb(v, mask) (gk_adc_readb((v)) & (mask)) ++#define gk_adc_tstbitsw(v, mask) (gk_adc_readw((v)) & (mask)) ++#define gk_adc_tstbitsl(v, mask) (gk_adc_readl((v)) & (mask)) ++ ++#define gk_aud_setbitsb(v, mask) gk_aud_writeb((v),(gk_aud_readb((v)) | (mask))) ++#define gk_aud_setbitsw(v, mask) gk_aud_writew((v),(gk_aud_readw((v)) | (mask))) ++#define gk_aud_setbitsl(v, mask) gk_aud_writel((v),(gk_aud_readl((v)) | (mask))) ++#define gk_aud_clrbitsb(v, mask) gk_aud_writeb((v),(gk_aud_readb((v)) & ~(mask))) ++#define gk_aud_clrbitsw(v, mask) gk_aud_writew((v),(gk_aud_readw((v)) & ~(mask))) ++#define gk_aud_clrbitsl(v, mask) gk_aud_writel((v),(gk_aud_readl((v)) & ~(mask))) ++#define gk_aud_tstbitsb(v, mask) (gk_aud_readb((v)) & (mask)) ++#define gk_aud_tstbitsw(v, mask) (gk_aud_readw((v)) & (mask)) ++#define gk_aud_tstbitsl(v, mask) (gk_aud_readl((v)) & (mask)) ++ ++#define gk_cry_setbitsb(v, mask) gk_cry_writeb((v),(gk_cry_readb((v)) | (mask))) ++#define gk_cry_setbitsw(v, mask) gk_cry_writew((v),(gk_cry_readw((v)) | (mask))) ++#define gk_cry_setbitsl(v, mask) gk_cry_writel((v),(gk_cry_readl((v)) | (mask))) ++#define gk_cry_clrbitsb(v, mask) gk_cry_writeb((v),(gk_cry_readb((v)) & ~(mask))) ++#define gk_cry_clrbitsw(v, mask) gk_cry_writew((v),(gk_cry_readw((v)) & ~(mask))) ++#define gk_cry_clrbitsl(v, mask) gk_cry_writel((v),(gk_cry_readl((v)) & ~(mask))) ++#define gk_cry_tstbitsb(v, mask) (gk_cry_readb((v)) & (mask)) ++#define gk_cry_tstbitsw(v, mask) (gk_cry_readw((v)) & (mask)) ++#define gk_cry_tstbitsl(v, mask) (gk_cry_readl((v)) & (mask)) ++ ++#define gk_ddr_setbitsb(v, mask) gk_ddr_writeb((v),(gk_ddr_readb((v)) | (mask))) ++#define gk_ddr_setbitsw(v, mask) gk_ddr_writew((v),(gk_ddr_readw((v)) | (mask))) ++#define gk_ddr_setbitsl(v, mask) gk_ddr_writel((v),(gk_ddr_readl((v)) | (mask))) ++#define gk_ddr_clrbitsb(v, mask) gk_ddr_writeb((v),(gk_ddr_readb((v)) & ~(mask))) ++#define gk_ddr_clrbitsw(v, mask) gk_ddr_writew((v),(gk_ddr_readw((v)) & ~(mask))) ++#define gk_ddr_clrbitsl(v, mask) gk_ddr_writel((v),(gk_ddr_readl((v)) & ~(mask))) ++#define gk_ddr_tstbitsb(v, mask) (gk_ddr_readb((v)) & (mask)) ++#define gk_ddr_tstbitsw(v, mask) (gk_ddr_readw((v)) & (mask)) ++#define gk_ddr_tstbitsl(v, mask) (gk_ddr_readl((v)) & (mask)) ++ ++#define gk_dma_setbitsb(v, mask) gk_dma_writeb((v),(gk_dma_readb((v)) | (mask))) ++#define gk_dma_setbitsw(v, mask) gk_dma_writew((v),(gk_dma_readw((v)) | (mask))) ++#define gk_dma_setbitsl(v, mask) gk_dma_writel((v),(gk_dma_readl((v)) | (mask))) ++#define gk_dma_clrbitsb(v, mask) gk_dma_writeb((v),(gk_dma_readb((v)) & ~(mask))) ++#define gk_dma_clrbitsw(v, mask) gk_dma_writew((v),(gk_dma_readw((v)) & ~(mask))) ++#define gk_dma_clrbitsl(v, mask) gk_dma_writel((v),(gk_dma_readl((v)) & ~(mask))) ++#define gk_dma_tstbitsb(v, mask) (gk_dma_readb((v)) & (mask)) ++#define gk_dma_tstbitsw(v, mask) (gk_dma_readw((v)) & (mask)) ++#define gk_dma_tstbitsl(v, mask) (gk_dma_readl((v)) & (mask)) ++ ++#define gk_dsp_setbitsb(v, mask) gk_dsp_writeb((v),(gk_dsp_readb((v)) | (mask))) ++#define gk_dsp_setbitsw(v, mask) gk_dsp_writew((v),(gk_dsp_readw((v)) | (mask))) ++#define gk_dsp_setbitsl(v, mask) gk_dsp_writel((v),(gk_dsp_readl((v)) | (mask))) ++#define gk_dsp_clrbitsb(v, mask) gk_dsp_writeb((v),(gk_dsp_readb((v)) & ~(mask))) ++#define gk_dsp_clrbitsw(v, mask) gk_dsp_writew((v),(gk_dsp_readw((v)) & ~(mask))) ++#define gk_dsp_clrbitsl(v, mask) gk_dsp_writel((v),(gk_dsp_readl((v)) & ~(mask))) ++#define gk_dsp_tstbitsb(v, mask) (gk_dsp_readb((v)) & (mask)) ++#define gk_dsp_tstbitsw(v, mask) (gk_dsp_readw((v)) & (mask)) ++#define gk_dsp_tstbitsl(v, mask) (gk_dsp_readl((v)) & (mask)) ++ ++#define gk_eth_setbitsb(v, mask) gk_eth_writeb((v),(gk_eth_readb((v)) | (mask))) ++#define gk_eth_setbitsw(v, mask) gk_eth_writew((v),(gk_eth_readw((v)) | (mask))) ++#define gk_eth_setbitsl(v, mask) gk_eth_writel((v),(gk_eth_readl((v)) | (mask))) ++#define gk_eth_clrbitsb(v, mask) gk_eth_writeb((v),(gk_eth_readb((v)) & ~(mask))) ++#define gk_eth_clrbitsw(v, mask) gk_eth_writew((v),(gk_eth_readw((v)) & ~(mask))) ++#define gk_eth_clrbitsl(v, mask) gk_eth_writel((v),(gk_eth_readl((v)) & ~(mask))) ++#define gk_eth_tstbitsb(v, mask) (gk_eth_readb((v)) & (mask)) ++#define gk_eth_tstbitsw(v, mask) (gk_eth_readw((v)) & (mask)) ++#define gk_eth_tstbitsl(v, mask) (gk_eth_readl((v)) & (mask)) ++ ++#define gk_greg_setbitsb(v, mask) gk_greg_writeb((v),(gk_greg_readb((v)) | (mask))) ++#define gk_greg_setbitsw(v, mask) gk_greg_writew((v),(gk_greg_readw((v)) | (mask))) ++#define gk_greg_setbitsl(v, mask) gk_greg_writel((v),(gk_greg_readl((v)) | (mask))) ++#define gk_greg_clrbitsb(v, mask) gk_greg_writeb((v),(gk_greg_readb((v)) & ~(mask))) ++#define gk_greg_clrbitsw(v, mask) gk_greg_writew((v),(gk_greg_readw((v)) & ~(mask))) ++#define gk_greg_clrbitsl(v, mask) gk_greg_writel((v),(gk_greg_readl((v)) & ~(mask))) ++#define gk_greg_tstbitsb(v, mask) (gk_greg_readb((v)) & (mask)) ++#define gk_greg_tstbitsw(v, mask) (gk_greg_readw((v)) & (mask)) ++#define gk_greg_tstbitsl(v, mask) (gk_greg_readl((v)) & (mask)) ++ ++#define gk_gpio_setbitsb(v, mask) gk_gpio_writeb((v),(gk_gpio_readb((v)) | (mask))) ++#define gk_gpio_setbitsw(v, mask) gk_gpio_writew((v),(gk_gpio_readw((v)) | (mask))) ++#define gk_gpio_setbitsl(v, mask) gk_gpio_writel((v),(gk_gpio_readl((v)) | (mask))) ++#define gk_gpio_clrbitsb(v, mask) gk_gpio_writeb((v),(gk_gpio_readb((v)) & ~(mask))) ++#define gk_gpio_clrbitsw(v, mask) gk_gpio_writew((v),(gk_gpio_readw((v)) & ~(mask))) ++#define gk_gpio_clrbitsl(v, mask) gk_gpio_writel((v),(gk_gpio_readl((v)) & ~(mask))) ++#define gk_gpio_tstbitsb(v, mask) (gk_gpio_readb((v)) & (mask)) ++#define gk_gpio_tstbitsw(v, mask) (gk_gpio_readw((v)) & (mask)) ++#define gk_gpio_tstbitsl(v, mask) (gk_gpio_readl((v)) & (mask)) ++ ++#define gk_i2c_setbitsb(v, mask) gk_i2c_writeb((v),(gk_i2c_readb((v)) | (mask))) ++#define gk_i2c_setbitsw(v, mask) gk_i2c_writew((v),(gk_i2c_readw((v)) | (mask))) ++#define gk_i2c_setbitsl(v, mask) gk_i2c_writel((v),(gk_i2c_readl((v)) | (mask))) ++#define gk_i2c_clrbitsb(v, mask) gk_i2c_writeb((v),(gk_i2c_readb((v)) & ~(mask))) ++#define gk_i2c_clrbitsw(v, mask) gk_i2c_writew((v),(gk_i2c_readw((v)) & ~(mask))) ++#define gk_i2c_clrbitsl(v, mask) gk_i2c_writel((v),(gk_i2c_readl((v)) & ~(mask))) ++#define gk_i2c_tstbitsb(v, mask) (gk_i2c_readb((v)) & (mask)) ++#define gk_i2c_tstbitsw(v, mask) (gk_i2c_readw((v)) & (mask)) ++#define gk_i2c_tstbitsl(v, mask) (gk_i2c_readl((v)) & (mask)) ++ ++#define gk_i2s_setbitsb(v, mask) gk_i2s_writeb((v),(gk_i2s_readb((v)) | (mask))) ++#define gk_i2s_setbitsw(v, mask) gk_i2s_writew((v),(gk_i2s_readw((v)) | (mask))) ++#define gk_i2s_setbitsl(v, mask) gk_i2s_writel((v),(gk_i2s_readl((v)) | (mask))) ++#define gk_i2s_clrbitsb(v, mask) gk_i2s_writeb((v),(gk_i2s_readb((v)) & ~(mask))) ++#define gk_i2s_clrbitsw(v, mask) gk_i2s_writew((v),(gk_i2s_readw((v)) & ~(mask))) ++#define gk_i2s_clrbitsl(v, mask) gk_i2s_writel((v),(gk_i2s_readl((v)) & ~(mask))) ++#define gk_i2s_tstbitsb(v, mask) (gk_i2s_readb((v)) & (mask)) ++#define gk_i2s_tstbitsw(v, mask) (gk_i2s_readw((v)) & (mask)) ++#define gk_i2s_tstbitsl(v, mask) (gk_i2s_readl((v)) & (mask)) ++ ++ ++#define gk_ir_setbitsb(v, mask) gk_ir_writeb((v),(gk_ir_readb((v)) | (mask))) ++#define gk_ir_setbitsw(v, mask) gk_ir_writew((v),(gk_ir_readw((v)) | (mask))) ++#define gk_ir_setbitsl(v, mask) gk_ir_writel((v),(gk_ir_readl((v)) | (mask))) ++#define gk_ir_clrbitsb(v, mask) gk_ir_writeb((v),(gk_ir_readb((v)) & ~(mask))) ++#define gk_ir_clrbitsw(v, mask) gk_ir_writew((v),(gk_ir_readw((v)) & ~(mask))) ++#define gk_ir_clrbitsl(v, mask) gk_ir_writel((v),(gk_ir_readl((v)) & ~(mask))) ++#define gk_ir_tstbitsb(v, mask) (gk_ir_readb((v)) & (mask)) ++#define gk_ir_tstbitsw(v, mask) (gk_ir_readw((v)) & (mask)) ++#define gk_ir_tstbitsl(v, mask) (gk_ir_readl((v)) & (mask)) ++ ++#define gk_irq_setbitsb(v, mask) gk_irq_writeb((v),(gk_irq_readb((v)) | (mask))) ++#define gk_irq_setbitsw(v, mask) gk_irq_writew((v),(gk_irq_readw((v)) | (mask))) ++#define gk_irq_setbitsl(v, mask) gk_irq_writel((v),(gk_irq_readl((v)) | (mask))) ++#define gk_irq_clrbitsb(v, mask) gk_irq_writeb((v),(gk_irq_readb((v)) & ~(mask))) ++#define gk_irq_clrbitsw(v, mask) gk_irq_writew((v),(gk_irq_readw((v)) & ~(mask))) ++#define gk_irq_clrbitsl(v, mask) gk_irq_writel((v),(gk_irq_readl((v)) & ~(mask))) ++#define gk_irq_tstbitsb(v, mask) (gk_irq_readb((v)) & (mask)) ++#define gk_irq_tstbitsw(v, mask) (gk_irq_readw((v)) & (mask)) ++#define gk_irq_tstbitsl(v, mask) (gk_irq_readl((v)) & (mask)) ++ ++#define gk_mcu_setbitsb(v, mask) gk_mcu_writeb((v),(gk_mcu_readb((v)) | (mask))) ++#define gk_mcu_setbitsw(v, mask) gk_mcu_writew((v),(gk_mcu_readw((v)) | (mask))) ++#define gk_mcu_setbitsl(v, mask) gk_mcu_writel((v),(gk_mcu_readl((v)) | (mask))) ++#define gk_mcu_clrbitsb(v, mask) gk_mcu_writeb((v),(gk_mcu_readb((v)) & ~(mask))) ++#define gk_mcu_clrbitsw(v, mask) gk_mcu_writew((v),(gk_mcu_readw((v)) & ~(mask))) ++#define gk_mcu_clrbitsl(v, mask) gk_mcu_writel((v),(gk_mcu_readl((v)) & ~(mask))) ++#define gk_mcu_tstbitsb(v, mask) (gk_mcu_readb((v)) & (mask)) ++#define gk_mcu_tstbitsw(v, mask) (gk_mcu_readw((v)) & (mask)) ++#define gk_mcu_tstbitsl(v, mask) (gk_mcu_readl((v)) & (mask)) ++ ++#define gk_pwm_setbitsb(v, mask) gk_pwm_writeb((v),(gk_pwm_readb((v)) | (mask))) ++#define gk_pwm_setbitsw(v, mask) gk_pwm_writew((v),(gk_pwm_readw((v)) | (mask))) ++#define gk_pwm_setbitsl(v, mask) gk_pwm_writel((v),(gk_pwm_readl((v)) | (mask))) ++#define gk_pwm_clrbitsb(v, mask) gk_pwm_writeb((v),(gk_pwm_readb((v)) & ~(mask))) ++#define gk_pwm_clrbitsw(v, mask) gk_pwm_writew((v),(gk_pwm_readw((v)) & ~(mask))) ++#define gk_pwm_clrbitsl(v, mask) gk_pwm_writel((v),(gk_pwm_readl((v)) & ~(mask))) ++#define gk_pwm_tstbitsb(v, mask) (gk_pwm_readb((v)) & (mask)) ++#define gk_pwm_tstbitsw(v, mask) (gk_pwm_readw((v)) & (mask)) ++#define gk_pwm_tstbitsl(v, mask) (gk_pwm_readl((v)) & (mask)) ++ ++#define gk_rct_setbitsb(v, mask) gk_rct_writeb((v),(gk_rct_readb((v)) | (mask))) ++#define gk_rct_setbitsw(v, mask) gk_rct_writew((v),(gk_rct_readw((v)) | (mask))) ++#define gk_rct_setbitsl(v, mask) gk_rct_writel((v),(gk_rct_readl((v)) | (mask))) ++#define gk_rct_clrbitsb(v, mask) gk_rct_writeb((v),(gk_rct_readb((v)) & ~(mask))) ++#define gk_rct_clrbitsw(v, mask) gk_rct_writew((v),(gk_rct_readw((v)) & ~(mask))) ++#define gk_rct_clrbitsl(v, mask) gk_rct_writel((v),(gk_rct_readl((v)) & ~(mask))) ++#define gk_rct_tstbitsb(v, mask) (gk_rct_readb((v)) & (mask)) ++#define gk_rct_tstbitsw(v, mask) (gk_rct_readw((v)) & (mask)) ++#define gk_rct_tstbitsl(v, mask) (gk_rct_readl((v)) & (mask)) ++ ++#define gk_sd_setbitsb(v, mask) gk_sd_writeb((v),(gk_sd_readb((v)) | (mask))) ++#define gk_sd_setbitsw(v, mask) gk_sd_writew((v),(gk_sd_readw((v)) | (mask))) ++#define gk_sd_setbitsl(v, mask) gk_sd_writel((v),(gk_sd_readl((v)) | (mask))) ++#define gk_sd_clrbitsb(v, mask) gk_sd_writeb((v),(gk_sd_readb((v)) & ~(mask))) ++#define gk_sd_clrbitsw(v, mask) gk_sd_writew((v),(gk_sd_readw((v)) & ~(mask))) ++#define gk_sd_clrbitsl(v, mask) gk_sd_writel((v),(gk_sd_readl((v)) & ~(mask))) ++#define gk_sd_tstbitsb(v, mask) (gk_sd_readb((v)) & (mask)) ++#define gk_sd_tstbitsw(v, mask) (gk_sd_readw((v)) & (mask)) ++#define gk_sd_tstbitsl(v, mask) (gk_sd_readl((v)) & (mask)) ++ ++#define gk_sf_setbitsb(v, mask) gk_sf_writeb((v),(gk_sf_readb((v)) | (mask))) ++#define gk_sf_setbitsw(v, mask) gk_sf_writew((v),(gk_sf_readw((v)) | (mask))) ++#define gk_sf_setbitsl(v, mask) gk_sf_writel((v),(gk_sf_readl((v)) | (mask))) ++#define gk_sf_clrbitsb(v, mask) gk_sf_writeb((v),(gk_sf_readb((v)) & ~(mask))) ++#define gk_sf_clrbitsw(v, mask) gk_sf_writew((v),(gk_sf_readw((v)) & ~(mask))) ++#define gk_sf_clrbitsl(v, mask) gk_sf_writel((v),(gk_sf_readl((v)) & ~(mask))) ++#define gk_sf_tstbitsb(v, mask) (gk_sf_readb((v)) & (mask)) ++#define gk_sf_tstbitsw(v, mask) (gk_sf_readw((v)) & (mask)) ++#define gk_sf_tstbitsl(v, mask) (gk_sf_readl((v)) & (mask)) ++ ++#define gk_ssi_setbitsb(v, mask) gk_ssi_writeb((v),(gk_ssi_readb((v)) | (mask))) ++#define gk_ssi_setbitsw(v, mask) gk_ssi_writew((v),(gk_ssi_readw((v)) | (mask))) ++#define gk_ssi_setbitsl(v, mask) gk_ssi_writel((v),(gk_ssi_readl((v)) | (mask))) ++#define gk_ssi_clrbitsb(v, mask) gk_ssi_writeb((v),(gk_ssi_readb((v)) & ~(mask))) ++#define gk_ssi_clrbitsw(v, mask) gk_ssi_writew((v),(gk_ssi_readw((v)) & ~(mask))) ++#define gk_ssi_clrbitsl(v, mask) gk_ssi_writel((v),(gk_ssi_readl((v)) & ~(mask))) ++#define gk_ssi_tstbitsb(v, mask) (gk_ssi_readb((v)) & (mask)) ++#define gk_ssi_tstbitsw(v, mask) (gk_ssi_readw((v)) & (mask)) ++#define gk_ssi_tstbitsl(v, mask) (gk_ssi_readl((v)) & (mask)) ++ ++#define gk_timer_setbitsb(v, mask) gk_timer_writeb((v),(gk_timer_readb((v)) | (mask))) ++#define gk_timer_setbitsw(v, mask) gk_timer_writew((v),(gk_timer_readw((v)) | (mask))) ++#define gk_timer_setbitsl(v, mask) gk_timer_writel((v),(gk_timer_readl((v)) | (mask))) ++#define gk_timer_clrbitsb(v, mask) gk_timer_writeb((v),(gk_timer_readb((v)) & ~(mask))) ++#define gk_timer_clrbitsw(v, mask) gk_timer_writew((v),(gk_timer_readw((v)) & ~(mask))) ++#define gk_timer_clrbitsl(v, mask) gk_timer_writel((v),(gk_timer_readl((v)) & ~(mask))) ++#define gk_timer_tstbitsb(v, mask) (gk_timer_readb((v)) & (mask)) ++#define gk_timer_tstbitsw(v, mask) (gk_timer_readw((v)) & (mask)) ++#define gk_timer_tstbitsl(v, mask) (gk_timer_readl((v)) & (mask)) ++ ++#define gk_uart_setbitsb(v, mask) gk_uart_writeb((v),(gk_uart_readb((v)) | (mask))) ++#define gk_uart_setbitsw(v, mask) gk_uart_writew((v),(gk_uart_readw((v)) | (mask))) ++#define gk_uart_setbitsl(v, mask) gk_uart_writel((v),(gk_uart_readl((v)) | (mask))) ++#define gk_uart_clrbitsb(v, mask) gk_uart_writeb((v),(gk_uart_readb((v)) & ~(mask))) ++#define gk_uart_clrbitsw(v, mask) gk_uart_writew((v),(gk_uart_readw((v)) & ~(mask))) ++#define gk_uart_clrbitsl(v, mask) gk_uart_writel((v),(gk_uart_readl((v)) & ~(mask))) ++#define gk_uart_tstbitsb(v, mask) (gk_uart_readb((v)) & (mask)) ++#define gk_uart_tstbitsw(v, mask) (gk_uart_readw((v)) & (mask)) ++#define gk_uart_tstbitsl(v, mask) (gk_uart_readl((v)) & (mask)) ++ ++#define gk_usb_setbitsb(v, mask) gk_usb_writeb((v),(gk_usb_readb((v)) | (mask))) ++#define gk_usb_setbitsw(v, mask) gk_usb_writew((v),(gk_usb_readw((v)) | (mask))) ++#define gk_usb_setbitsl(v, mask) gk_usb_writel((v),(gk_usb_readl((v)) | (mask))) ++#define gk_usb_clrbitsb(v, mask) gk_usb_writeb((v),(gk_usb_readb((v)) & ~(mask))) ++#define gk_usb_clrbitsw(v, mask) gk_usb_writew((v),(gk_usb_readw((v)) & ~(mask))) ++#define gk_usb_clrbitsl(v, mask) gk_usb_writel((v),(gk_usb_readl((v)) & ~(mask))) ++#define gk_usb_tstbitsb(v, mask) (gk_usb_readb((v)) & (mask)) ++#define gk_usb_tstbitsw(v, mask) (gk_usb_readw((v)) & (mask)) ++#define gk_usb_tstbitsl(v, mask) (gk_usb_readl((v)) & (mask)) ++ ++#define gk_vout_setbitsb(v, mask) gk_vout_writeb((v),(gk_vout_readb((v)) | (mask))) ++#define gk_vout_setbitsw(v, mask) gk_vout_writew((v),(gk_vout_readw((v)) | (mask))) ++#define gk_vout_setbitsl(v, mask) gk_vout_writel((v),(gk_vout_readl((v)) | (mask))) ++#define gk_vout_clrbitsb(v, mask) gk_vout_writeb((v),(gk_vout_readb((v)) & ~(mask))) ++#define gk_vout_clrbitsw(v, mask) gk_vout_writew((v),(gk_vout_readw((v)) & ~(mask))) ++#define gk_vout_clrbitsl(v, mask) gk_vout_writel((v),(gk_vout_readl((v)) & ~(mask))) ++#define gk_vout_tstbitsb(v, mask) (gk_vout_readb((v)) & (mask)) ++#define gk_vout_tstbitsw(v, mask) (gk_vout_readw((v)) & (mask)) ++#define gk_vout_tstbitsl(v, mask) (gk_vout_readl((v)) & (mask)) ++ ++#define gk_wdt_setbitsb(v, mask) gk_wdt_writeb((v),(gk_wdt_readb((v)) | (mask))) ++#define gk_wdt_setbitsw(v, mask) gk_wdt_writew((v),(gk_wdt_readw((v)) | (mask))) ++#define gk_wdt_setbitsl(v, mask) gk_wdt_writel((v),(gk_wdt_readl((v)) | (mask))) ++#define gk_wdt_clrbitsb(v, mask) gk_wdt_writeb((v),(gk_wdt_readb((v)) & ~(mask))) ++#define gk_wdt_clrbitsw(v, mask) gk_wdt_writew((v),(gk_wdt_readw((v)) & ~(mask))) ++#define gk_wdt_clrbitsl(v, mask) gk_wdt_writel((v),(gk_wdt_readl((v)) & ~(mask))) ++#define gk_wdt_tstbitsb(v, mask) (gk_wdt_readb((v)) & (mask)) ++#define gk_wdt_tstbitsw(v, mask) (gk_wdt_readw((v)) & (mask)) ++#define gk_wdt_tstbitsl(v, mask) (gk_wdt_readl((v)) & (mask)) ++ ++ ++#define gk_musb_readb(a, o) gk_usb_readb((a+o)) ++#define gk_musb_readw(a, o) gk_usb_readw((a+o)) ++#define gk_musb_readl(a, o) gk_usb_readl((a+o)) ++#define gk_musb_writeb(a, o, v) gk_usb_writeb((a+o),(v)) ++#define gk_musb_writew(a, o, v) gk_usb_writew((a+o),(v)) ++#define gk_musb_writel(a, o, v) gk_usb_writel((a+o),(v)) ++ ++#define gk_spi_readb(a) gk_ssi_readb((a)) ++#define gk_spi_readw(a) gk_ssi_readw((a)) ++#define gk_spi_readl(a) gk_ssi_readl((a)) ++#define gk_spi_writeb(a, v) gk_ssi_writeb((a),(v)) ++#define gk_spi_writew(a, v) gk_ssi_writew((a),(v)) ++#define gk_spi_writel(a, v) gk_ssi_writel((a),(v)) ++ ++ ++ ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif /* __MACH_IO_H */ +diff --git a/arch/arm/mach-gk710xs/include/mach/ir.h b/arch/arm/mach-gk710xs/include/mach/ir.h +new file mode 100644 +index 00000000..8c4cc40a +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/ir.h +@@ -0,0 +1,50 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/ir.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_IR_H ++#define __MACH_IR_H ++ ++/* ==========================================================================*/ ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++enum gk_ir_protocol { ++ GK_IR_PROTOCOL_NEC = 0, ++ GK_IR_PROTOCOL_PANASONIC = 1, ++ GK_IR_PROTOCOL_SONY = 2, ++ GK_IR_PROTOCOL_PHILIPS = 3, ++ GK_IR_PROTOCOL_END ++}; ++ ++struct gk_ir_controller { ++ ++ int protocol; ++ int debug; ++}; ++#define GK_IR_PARAM_CALL(arg, perm) \ ++ module_param_cb(ir_protocol, ¶m_ops_int, &arg.protocol, perm); \ ++ module_param_cb(ir_debug, ¶m_ops_int, &arg.debug, perm) ++ ++/* ==========================================================================*/ ++extern struct platform_device gk_ir; ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif /* __MACH_IR_H */ ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/irqs.h b/arch/arm/mach-gk710xs/include/mach/irqs.h +new file mode 100644 +index 00000000..62bfc193 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/irqs.h +@@ -0,0 +1,198 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/irqs.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_IRQS_H ++#define __MACH_IRQS_H ++ ++#include ++#define NR_IRQS 128 ++ ++#define NR_VIC_IRQ_SIZE (32) ++ ++#define VIC1_INT_VEC(x) ((x) + (NR_VIC_IRQ_SIZE * 0)) ++#define VIC2_INT_VEC(x) ((x) + (NR_VIC_IRQ_SIZE * 1)) ++//#define VIC3_INT_VEC(x) ((x) + (NR_VIC_IRQ_SIZE * 2)) ++//#define VIC4_INT_VEC(x) ((x) + (NR_VIC_IRQ_SIZE * 3)) ++ ++/* The following are ARCH specific IRQ numbers */ ++ ++#define VIC_INSTANCES 2 ++ ++#define NR_VIC_IRQS (VIC_INSTANCES * NR_VIC_IRQ_SIZE) ++#define GPIO_INT_VEC(x) (NR_VIC_IRQS + x) ++ ++// VIC Instance 1 ++#define SSI_SLAVE_IRQ 0 ++#define ETH_IRQ 1 ++#define ICORE_ERROR_IRQ 2 ++#define GPIO2_IRQ 4 ++#define CD2ND_BIT_CD_IRQ 5 ++#define USBVBUS_IRQ 6 ++#define VO_IRQ 7 ++#define DSP_VO1_IRQ 7 ++#define SD_IRQ 8 ++#define IDC_IRQ 9 ++#define SSI_IRQ 10 ++#define WDT_IRQ 11 ++#define IRIF_IRQ 12 ++#define SD1CD_IRQ 13 ++#define SDCD_IRQ 14 /* SD0 SD card card detection. */ ++#define UART1_IRQ 15 ++#define GPIO0_IRQ 16 ++#define GPIO1_IRQ 17 ++#define TIMER1_IRQ 18 ++#define TIMER2_IRQ 19 ++#define TIMER3_IRQ 20 ++#define DMA_IRQ 21 ++#define SD1_IRQ 22 ++#define FIODMA_IRQ 23 ++#define VI_IRQ 24 ++#define DSP_VI_IRQ 24 ++#define VCORE_IRQ 25 ++#define DSP_VCORE_IRQ 25 ++#define USBC_IRQ 26 ++#define UART2_IRQ 27 ++#define HIF2_IRQ 28 ++#define I2STX_IRQ 29 ++#define I2SRX_IRQ 30 ++#define UART0_IRQ 31 ++ ++// VIC Instance 2 ++#define DMA_FIOS_IRQ (32 + 7) ++#define VO0_TV_SYNC_IRQ (32 + 16) ++#define VO1_LCD_SYNC_IRQ (32 + 17) ++#define DSP_VO0_IRQ (32 + 18) ++#define AES_IRQ (32 + 19) ++#define DES_IRQ (32 + 20) ++#define MDMA_IRQ (32 + 22) ++#define MOTOR_IRQ (32 + 23) ++#define ADC_LEVEL_IRQ (32 + 24) ++#define IDC_HDMI_IRQ (32 + 26) ++#define ICORE_LAST_PIXEL_IRQ (32 + 27) ++#define ICORE_VSYNC_IRQ (32 + 28) ++#define ICORE_SENSOR_VSYNC_IRQ (32 + 29) ++#define HDMI_IRQ (32 + 30) ++#define SSI2_IRQ (32 + 31) ++ ++#define MAX_IRQ_NUM (SSI2_IRQ + 1) ++#define IR_IRQ HDMI_IRQ ++ ++ ++//#define MAX_IRQ_NUM (MOTOR_IRQ + 1) ++ ++#define GPIO_IRQ(x) ((x) + NR_VIC_IRQS) ++ ++ ++#define VIC_IRQ(x) (x) ++ ++ ++/* ++ * VIC trigger types (SW definition). ++ */ ++#define VIRQ_RISING_EDGE 0 ++#define VIRQ_FALLING_EDGE 1 ++#define VIRQ_BOTH_EDGES 2 ++#define VIRQ_LEVEL_LOW 3 ++#define VIRQ_LEVEL_HIGH 4 ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++#define VIC_IRQ_STA_OFFSET 0x30 ++#define VIC_FIQ_STA_OFFSET 0x34 ++#define VIC_RAW_STA_OFFSET 0x18 ++#define VIC_INT_SEL_OFFSET 0x0c ++#define VIC_INTEN_OFFSET 0x10 ++#define VIC_INTEN_CLR_OFFSET 0x14 ++#define VIC_SOFTEN_OFFSET 0x1c ++#define VIC_SOFTEN_CLR_OFFSET 0x20 ++#define VIC_PROTEN_OFFSET 0x24 ++#define VIC_SENSE_OFFSET 0x00 ++#define VIC_BOTHEDGE_OFFSET 0x08 ++#define VIC_EVENT_OFFSET 0x04 ++#define VIC_EDGE_CLR_OFFSET 0x38 ++ ++#define VIC1_BASE (GK_VA_VIC1) ++#define VIC2_BASE (GK_VA_VIC2) ++ ++#define VIC1_REG(x) (VIC1_BASE + (x)) ++#define VIC2_REG(x) (VIC2_BASE + (x)) ++ ++#define VIC_IRQ_STA_REG VIC1_REG(VIC_IRQ_STA_OFFSET) ++#define VIC_FIQ_STA_REG VIC1_REG(VIC_FIQ_STA_OFFSET) ++#define VIC_RAW_STA_REG VIC1_REG(VIC_RAW_STA_OFFSET) ++#define VIC_INT_SEL_REG VIC1_REG(VIC_INT_SEL_OFFSET) ++#define VIC_INTEN_REG VIC1_REG(VIC_INTEN_OFFSET) ++#define VIC_INTEN_CLR_REG VIC1_REG(VIC_INTEN_CLR_OFFSET) ++#define VIC_SOFTEN_REG VIC1_REG(VIC_SOFTEN_OFFSET) ++#define VIC_SOFTEN_CLR_REG VIC1_REG(VIC_SOFTEN_CLR_OFFSET) ++#define VIC_PROTEN_REG VIC1_REG(VIC_PROTEN_OFFSET) ++#define VIC_SENSE_REG VIC1_REG(VIC_SENSE_OFFSET) ++#define VIC_BOTHEDGE_REG VIC1_REG(VIC_BOTHEDGE_OFFSET) ++#define VIC_EVENT_REG VIC1_REG(VIC_EVENT_OFFSET) ++#define VIC_EDGE_CLR_REG VIC1_REG(VIC_EDGE_CLR_OFFSET) ++ ++#if (VIC_INSTANCES >= 2) ++ ++#define VIC2_IRQ_STA_REG VIC2_REG(VIC_IRQ_STA_OFFSET) ++#define VIC2_FIQ_STA_REG VIC2_REG(VIC_FIQ_STA_OFFSET) ++#define VIC2_RAW_STA_REG VIC2_REG(VIC_RAW_STA_OFFSET) ++#define VIC2_INT_SEL_REG VIC2_REG(VIC_INT_SEL_OFFSET) ++#define VIC2_INTEN_REG VIC2_REG(VIC_INTEN_OFFSET) ++#define VIC2_INTEN_CLR_REG VIC2_REG(VIC_INTEN_CLR_OFFSET) ++#define VIC2_SOFTEN_REG VIC2_REG(VIC_SOFTEN_OFFSET) ++#define VIC2_SOFTEN_CLR_REG VIC2_REG(VIC_SOFTEN_CLR_OFFSET) ++#define VIC2_PROTEN_REG VIC2_REG(VIC_PROTEN_OFFSET) ++#define VIC2_SENSE_REG VIC2_REG(VIC_SENSE_OFFSET) ++#define VIC2_BOTHEDGE_REG VIC2_REG(VIC_BOTHEDGE_OFFSET) ++#define VIC2_EVENT_REG VIC2_REG(VIC_EVENT_OFFSET) ++#define VIC2_EDGE_CLR_REG VIC2_REG(VIC_EDGE_CLR_OFFSET) ++ ++#endif ++ ++struct gk_irq_info ++{ ++ int irq_gpio; ++ int irq_line; ++ int irq_type; ++ int irq_gpio_val; ++ int irq_gpio_mode; ++}; ++ ++//***************************************************************************** ++//***************************************************************************** ++//** API Functions ++//***************************************************************************** ++//***************************************************************************** ++#ifndef __ASSEMBLY__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct pt_regs; ++ ++extern void gk_init_irq(void) __init; ++extern void gk_vic_handle_irq(struct pt_regs *regs); ++ ++#ifdef __cplusplus ++} ++#endif ++#endif ++ ++#endif /* __MACH_IRQS_H */ ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/rct.h b/arch/arm/mach-gk710xs/include/mach/rct.h +new file mode 100644 +index 00000000..d7d38cf3 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/rct.h +@@ -0,0 +1,36 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/rct.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_RCT_H ++#define __MACH_RCT_H ++ ++/* ==============================================*/ ++#define GK_APB_FREQ 69000000 //20MHz ++#define GK_UART_FREQ 24000000 ++#define GK_SD_FREQ 48000000 ++ ++u32 get_apb_bus_freq_hz(void); ++u32 get_uart_freq_hz(void); ++u32 get_sd_freq_hz(void); ++u32 get_ssi0_freq_hz(void); ++u32 get_ssi1_freq_hz(void); ++ ++void set_sd_rct(u32 freq); ++ ++ ++#endif ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/sd.h b/arch/arm/mach-gk710xs/include/mach/sd.h +new file mode 100644 +index 00000000..03b08c44 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/sd.h +@@ -0,0 +1,512 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/sd.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_GK_SD_H ++#define __MACH_GK_SD_H ++ ++#include ++ ++/* ==========================================================================*/ ++#define GK_SD_MAX_SLOT_NUM (2) ++ ++#define GK_SD_PRIVATE_CAPS_VDD_18 (0x1 << 0) ++#define GK_SD_PRIVATE_CAPS_ADMA (0x1 << 1) ++#define GK_SD_PRIVATE_CAPS_DTO_BY_SDCLK (0x1 << 2) ++#define GK_SD_PRIVATE_CAPS_DDR (0x1 << 3) ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++struct gk_sd_slot { ++ struct mmc_host *pmmc_host; ++ ++ u32 default_caps; ++ u32 active_caps; ++ u32 default_caps2; ++ u32 active_caps2; ++ u32 private_caps; ++ ++ struct gk_gpio_io_info ext_power; ++ struct gk_gpio_io_info ext_reset; ++ int fixed_cd; ++ struct gk_irq_info gpio_cd; ++ u32 cd_delay; //jiffies ++ int fixed_wp; ++ struct gk_gpio_io_info gpio_wp; ++ ++ int (*check_owner)(void); ++ void (*request)(void); ++ void (*release)(void); ++ void (*set_int)(u32 mask, u32 on); ++ void (*set_vdd)(u32 vdd); ++ void (*set_bus_timing)(u32 timing); ++}; ++ ++struct gk_sd_controller { ++ u32 num_slots; ++ struct gk_sd_slot slot[GK_SD_MAX_SLOT_NUM]; ++ void (*set_pll)(u32); ++ u32 (*get_pll)(void); ++ ++ u32 max_blk_mask; ++ u32 max_clock; ++ u32 active_clock; ++ u32 wait_tmo; ++ u32 pwr_delay; //ms ++ ++ u32 dma_fix; ++ u32 support_pll_scaler; ++}; ++ ++/* ==========================================================================*/ ++extern struct platform_device gk_sd0; ++ ++extern int gk_init_sd(void); ++extern void gk_detect_sd_slot(int bus, int slot, int fixed_cd); ++extern void gk_set_sd_detect_pin(u32 gpio_pin); ++#ifdef CONFIG_GK710XS_SDIO2 ++extern struct platform_device gk_sd1; ++extern void gk_detect_sd1_slot(int bus, int slot, int fixed_cd); ++extern void gk_set_sd1_detect_pin(u32 gpio_pin); ++#endif ++ ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#define SD_INSTANCES 1 ++#define SD_SUPPORT_PLL_SCALER 0 ++#define SD_HAS_INTERNAL_MUXER 1 ++#define SD_HAS_INTERNAL_2ND_CDWP 0 ++#define SD_HAS_DELAY_CTRL 0 ++#define SD_BUS_SWITCH_DLY 0 ++#define SD_HAS_IO_DRIVE_CTRL 1 ++ ++#define SD_HOST1_SUPPORT_XC 0 ++#define SD_HOST2_SUPPORT_XC 0 ++ ++#define SD_SUPPORT_ACMD23 1 ++ ++#define SD_HAS_SDXC_CLOCK 0 ++ ++#define SD_HOST1_HOST2_HAS_MUX 0 ++#define SD_SUPPORT_ADMA 0 ++ ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++ ++#define SD_REG(x) (GK_VA_SDC + (x)) //(0xf0002000 + (x)) ++#ifdef CONFIG_GK710XS_SDIO2 ++#define SD1_REG(x) (GK_VA_SDC1 + (x)) //(0xf0002000 + (x)) ++#endif ++ ++#define SD_DMA_ADDR_OFFSET 0x000 ++#define SD_BLK_SZ_OFFSET 0x00c /* Half word */ ++#define SD_BLK_CNT_OFFSET 0x00a /* Half word */ ++#define SD_ARG_OFFSET 0x034 ++#define SD_XFR_OFFSET 0x004 /* Half word */ ++#define SD_CMD_OFFSET 0x016 /* Half word */ ++#define SD_RSP0_OFFSET 0x01c ++#define SD_RSP1_OFFSET 0x020 ++#define SD_RSP2_OFFSET 0x024 ++#define SD_RSP3_OFFSET 0x028 ++#define SD_DATA_OFFSET 0x040 ++#define SD_STA_OFFSET 0x030 ++#define SD_HOST_OFFSET 0x02c /* Byte */ ++#define SD_PWR_OFFSET 0x02d /* Byte */ ++#define SD_GAP_OFFSET 0x02e /* Byte */ ++#define SD_WAK_OFFSET 0x02f /* Byte */ ++#define SD_CLK_OFFSET 0x01a /* Half word */ ++#define SD_TMO_OFFSET 0x018 /* Byte */ ++#define SD_RESET_OFFSET 0x019 /* Byte */ ++#define SD_NIS_OFFSET 0x012 /* Half word */ ++#define SD_EIS_OFFSET 0x014 /* Half word */ ++#define SD_NISEN_OFFSET 0x00e /* Half word */ ++#define SD_EISEN_OFFSET 0x010 /* Half word */ ++#define SD_NIXEN_OFFSET 0x006 /* Half word */ ++#define SD_EIXEN_OFFSET 0x008 /* Half word */ ++#define SD_AC12ES_OFFSET 0x03c /* Half word */ ++#define SD_CAP_OFFSET 0x038 ++#define SD_CUR_OFFSET 0x048 ++#define SD_ADMA_STA_OFFSET 0x054 ++#define SD_ADMA_ADDR_OFFSET 0x058 ++#define SD_XC_CTR_OFFSET 0x060 ++#define SD_BOOT_CTR_OFFSET 0x070 ++#define SD_BOOT_STA_OFFSET 0x074 ++#define SD_VOL_SW_OFFSET 0x07c ++#define SD_SIST_OFFSET 0x0fc /* Half word */ ++#define SD_VER_OFFSET 0x0fe /* Half word */ ++ ++#define SD_DMA_ADDR_REG SD_REG(SD_DMA_ADDR_OFFSET) ++#define SD_BLK_SZ_REG SD_REG(SD_BLK_SZ_OFFSET) /* Half word */ ++#define SD_BLK_CNT_REG SD_REG(SD_BLK_CNT_OFFSET) /* Half word */ ++#define SD_ARG_REG SD_REG(SD_ARG_OFFSET) ++#define SD_XFR_REG SD_REG(SD_XFR_OFFSET) /* Half word */ ++#define SD_CMD_REG SD_REG(SD_CMD_OFFSET) /* Half word */ ++#define SD_RSP0_REG SD_REG(SD_RSP0_OFFSET) ++#define SD_RSP1_REG SD_REG(SD_RSP1_OFFSET) ++#define SD_RSP2_REG SD_REG(SD_RSP2_OFFSET) ++#define SD_RSP3_REG SD_REG(SD_RSP3_OFFSET) ++#define SD_DATA_REG SD_REG(SD_DATA_OFFSET) ++#define SD_STA_REG SD_REG(SD_STA_OFFSET) ++#define SD_HOST_REG SD_REG(SD_HOST_OFFSET) /* Byte */ ++#define SD_PWR_REG SD_REG(SD_PWR_OFFSET) /* Byte */ ++#define SD_GAP_REG SD_REG(SD_GAP_OFFSET) /* Byte */ ++#define SD_WAK_REG SD_REG(SD_WAK_OFFSET) /* Byte */ ++#define SD_CLK_REG SD_REG(SD_CLK_OFFSET) /* Half word */ ++#define SD_TMO_REG SD_REG(SD_TMO_OFFSET) /* Byte */ ++#define SD_RESET_REG SD_REG(SD_RESET_OFFSET) /* Byte */ ++#define SD_NIS_REG SD_REG(SD_NIS_OFFSET) /* Half word */ ++#define SD_EIS_REG SD_REG(SD_EIS_OFFSET) /* Half word */ ++#define SD_NISEN_REG SD_REG(SD_NISEN_OFFSET) /* Half word */ ++#define SD_EISEN_REG SD_REG(SD_EISEN_OFFSET) /* Half word */ ++#define SD_NIXEN_REG SD_REG(SD_NIXEN_OFFSET) /* Half word */ ++#define SD_EIXEN_REG SD_REG(SD_EIXEN_OFFSET) /* Half word */ ++#define SD_AC12ES_REG SD_REG(SD_AC12ES_OFFSET) /* Half word */ ++#define SD_CAP_REG SD_REG(SD_CAP_OFFSET) ++#define SD_CUR_REG SD_REG(SD_CUR_OFFSET) ++#define SD_ADMA_STA_REG SD_REG(SD_ADMA_STA_OFFSET) ++#define SD_ADMA_ADDR_REG SD_REG(SD_ADMA_ADDR_OFFSET) ++#define SD_XC_CTR_REG SD_REG(SD_XC_CTR_OFFSET) ++#define SD_BOOT_CTR_REG SD_REG(SD_BOOT_CTR_OFFSET) ++#define SD_BOOT_STA_REG SD_REG(SD_BOOT_STA_OFFSET) ++#define SD_VOL_SW_REG SD_REG(SD_VOL_SW_OFFSET) ++#define SD_SIST_REG SD_REG(SD_SIST_OFFSET) /* Half word */ ++#define SD_VER_REG SD_REG(SD_VER_OFFSET) /* Half word */ ++ ++#ifdef CONFIG_GK710XS_SDIO2 ++#define SD1_DMA_ADDR_REG SD1_REG(SD_DMA_ADDR_OFFSET) ++#define SD1_BLK_SZ_REG SD1_REG(SD_BLK_SZ_OFFSET) /* Half word */ ++#define SD1_BLK_CNT_REG SD1_REG(SD_BLK_CNT_OFFSET) /* Half word */ ++#define SD1_ARG_REG SD1_REG(SD_ARG_OFFSET) ++#define SD1_XFR_REG SD1_REG(SD_XFR_OFFSET) /* Half word */ ++#define SD1_CMD_REG SD1_REG(SD_CMD_OFFSET) /* Half word */ ++#define SD1_RSP0_REG SD1_REG(SD_RSP0_OFFSET) ++#define SD1_RSP1_REG SD1_REG(SD_RSP1_OFFSET) ++#define SD1_RSP2_REG SD1_REG(SD_RSP2_OFFSET) ++#define SD1_RSP3_REG SD1_REG(SD_RSP3_OFFSET) ++#define SD1_DATA_REG SD1_REG(SD_DATA_OFFSET) ++#define SD1_STA_REG SD1_REG(SD_STA_OFFSET) ++#define SD1_HOST_REG SD1_REG(SD_HOST_OFFSET) /* Byte */ ++#define SD1_PWR_REG SD1_REG(SD_PWR_OFFSET) /* Byte */ ++#define SD1_GAP_REG SD1_REG(SD_GAP_OFFSET) /* Byte */ ++#define SD1_WAK_REG SD1_REG(SD_WAK_OFFSET) /* Byte */ ++#define SD1_CLK_REG SD1_REG(SD_CLK_OFFSET) /* Half word */ ++#define SD1_TMO_REG SD1_REG(SD_TMO_OFFSET) /* Byte */ ++#define SD1_RESET_REG SD1_REG(SD_RESET_OFFSET) /* Byte */ ++#define SD1_NIS_REG SD1_REG(SD_NIS_OFFSET) /* Half word */ ++#define SD1_EIS_REG SD1_REG(SD_EIS_OFFSET) /* Half word */ ++#define SD1_NISEN_REG SD1_REG(SD_NISEN_OFFSET) /* Half word */ ++#define SD1_EISEN_REG SD1_REG(SD_EISEN_OFFSET) /* Half word */ ++#define SD1_NIXEN_REG SD1_REG(SD_NIXEN_OFFSET) /* Half word */ ++#define SD1_EIXEN_REG SD1_REG(SD_EIXEN_OFFSET) /* Half word */ ++#define SD1_AC12ES_REG SD1_REG(SD_AC12ES_OFFSET) /* Half word */ ++#define SD1_CAP_REG SD1_REG(SD_CAP_OFFSET) ++#define SD1_CUR_REG SD1_REG(SD_CUR_OFFSET) ++#define SD1_ADMA_STA_REG SD1_REG(SD_ADMA_STA_OFFSET) ++#define SD1_ADMA_ADDR_REG SD1_REG(SD_ADMA_ADDR_OFFSET) ++#define SD1_XC_CTR_REG SD1_REG(SD_XC_CTR_OFFSET) ++#define SD1_BOOT_CTR_REG SD1_REG(SD_BOOT_CTR_OFFSET) ++#define SD1_BOOT_STA_REG SD1_REG(SD_BOOT_STA_OFFSET) ++#define SD1_VOL_SW_REG SD1_REG(SD_VOL_SW_OFFSET) ++#define SD1_SIST_REG SD1_REG(SD_SIST_OFFSET) /* Half word */ ++#define SD1_VER_REG SD1_REG(SD_VER_OFFSET) /* Half word */ ++#endif ++ ++/* SD_BLK_SZ_REG */ ++#define SD_BLK_SZ_4KB 0x0000 ++#define SD_BLK_SZ_8KB 0x1000 ++#define SD_BLK_SZ_16KB 0x2000 ++#define SD_BLK_SZ_32KB 0x3000 ++#define SD_BLK_SZ_64KB 0x4000 ++#define SD_BLK_SZ_128KB 0x5000 ++#define SD_BLK_SZ_256KB 0x6000 ++#define SD_BLK_SZ_512KB 0x7000 ++ ++/* SD_XFR_REG */ ++#if defined(CONFIG_ARCH_GK710XS) ++#define SD_XFR_MUL_SEL 0x0010 ++#define SD_XFR_SGL_SEL 0x0000 ++#define SD_XFR_CTH_SEL 0x0020 ++#else ++#define SD_XFR_MUL_SEL 0x0020 ++#define SD_XFR_SGL_SEL 0x0000 ++#define SD_XFR_CTH_SEL 0x0010 ++#endif ++#define SD_XFR_HTC_SEL 0x0000 ++#define SD_XFR_DMA_EN 0x0004 ++#define SD_XFR_AC12_EN 0x0002 ++#define SD_XFR_BLKCNT_EN 0x0001 ++ ++/* SD_CMD_REG */ ++#define SD_CMD_IDX(x) ((x) << 8) ++#define SD_CMD_NORMAL 0x00000000 ++#define SD_CMD_SUSPEND 0x00000040 ++#define SD_CMD_RESUME 0x00000080 ++#define SD_CMD_ABORT 0x000000C0 ++#define SD_CMD_CHKIDX 0x00000020 ++#define SD_CMD_DATA 0x00000010 ++#define SD_CMD_CHKCRC 0x00000008 ++ ++#define SD_CMD_RSP_NONE 0x00000000 ++#define SD_CMD_RSP_136 0x00000001 ++#define SD_CMD_RSP_48 0x00000002 ++#define SD_CMD_RSP_48BUSY 0x00000003 ++ ++/* SD_STA_REG */ ++#define SD_STA_DAT_LSL(x) ((((x) & 0x1e000000) >> 25) |(((x) & 0x00f00000) >> 20)) ++#define SD_STA_CMD_LSL(x) (((x) & 0x01000000) >> 24) ++#define SD_STA_WPS_PL 0x00080000 ++#define SD_STA_CSS 0x00040000 ++#define SD_STA_CDP_L 0x00020000 ++#define SD_STA_CARD_INSERTED 0x00010000 ++#define SD_STA_BUFFER_READ_EN 0x00000800 ++#define SD_STA_WRITE_XFR_ACTIVE 0x00000400 ++#define SD_STA_BUFFER_WRITE_EN 0x00000200 ++#define SD_STA_READ_XFR_ACTIVE 0x00000100 ++#define SD_STA_CMD_INHIBIT_DAT 0x00000004 ++#define SD_STA_DAT_ACTIVE 0x00000002 ++#define SD_STA_CMD_INHIBIT_CMD 0x00000001 ++ ++#define SD_STA_WRITABLE 0 ++#define SD_STA_READ_ONLY 1 ++ ++/* SD_HOST_REG */ ++#define SD_HOST_HIGH_SPEED 0x08 ++#define SD_HOST_8BIT 0x04 ++#define SD_HOST_4BIT 0x02 ++#define SD_HOST_LED_ON 0x01 ++ ++/* SD_PWR_REG */ ++#define SD_PWR_3_3V 0x0e ++#define SD_PWR_3_0V 0x0c ++#define SD_PWR_1_8V 0x0a ++#define SD_PWR_ON 0x01 ++#define SD_PWR_OFF 0x00 ++ ++/* SD_GAP_REG */ ++#define SD_GAP_INT_AT_GAP 0x08 ++#define SD_GAP_CONT_REQ 0x04 ++#define SD_GAP_READ_WAIT 0x02 ++#define SD_GAP_STOP_AT_GAP 0x01 ++ ++/* SD_WAK_REG */ ++#define SD_WAK_ON_CARD_RMV 0x04 ++#define SD_WAK_ON_CARD_INT 0x02 ++#define SD_WAK_ON_CARD_IST 0x01 ++ ++/* SD_CLK_REG */ ++#define SD_CLK_DIV_256 0x8000 ++#define SD_CLK_DIV_128 0x4000 ++#define SD_CLK_DIV_64 0x2000 ++#define SD_CLK_DIV_32 0x1000 ++#define SD_CLK_DIV_16 0x0800 ++#define SD_CLK_DIV_8 0x0400 ++#define SD_CLK_DIV_4 0x0200 ++#define SD_CLK_DIV_2 0x0100 ++#define SD_CLK_DIV_1 0x0000 ++#define SD_CLK_EN 0x0004 ++#define SD_CLK_ICLK_STABLE 0x0002 ++#define SD_CLK_ICLK_EN 0x0001 ++ ++/* SD_TMO_REG */ ++/* SD_RESET_REG */ ++#define SD_RESET_DAT 0x04 ++#define SD_RESET_ALL 0x02 ++#define SD_RESET_CMD 0x01 ++ ++/* SD_NIS_REG */ ++#define SD_NIS_ERROR 0x8000 ++#define SD_NIS_CARD 0x0100 ++#define SD_NIS_REMOVAL 0x0080 ++#define SD_NIS_READ_READY 0x0040 ++#define SD_NIS_INSERT 0x0020 ++#define SD_NIS_WRITE_READY 0x0010 ++#define SD_NIS_XFR_DONE 0x0008 ++#define SD_NIS_DMA 0x0004 ++#define SD_NIS_BLOCK_GAP 0x0002 ++#define SD_NIS_CMD_DONE 0x0001 ++ ++/* SD_EIS_REG */ ++#define SD_EIS_ACMD12_ERR 0x0100 ++#define SD_EIS_CURRENT_ERR 0x0080 ++#define SD_EIS_DATA_BIT_ERR 0x0040 ++#define SD_EIS_DATA_CRC_ERR 0x0020 ++#define SD_EIS_DATA_TMOUT_ERR 0x0010 ++#define SD_EIS_CMD_IDX_ERR 0x0008 ++#define SD_EIS_CMD_BIT_ERR 0x0004 ++#define SD_EIS_CMD_CRC_ERR 0x0002 ++#define SD_EIS_CMD_TMOUT_ERR 0x0001 ++ ++ ++/* SD_NISEN_REG */ ++#define SD_NISEN_CARD 0x0100 ++#define SD_NISEN_REMOVAL 0x0080 ++#define SD_NISEN_INSERT 0x0040 ++#define SD_NISEN_READ_READY 0x0020 ++#define SD_NISEN_WRITE_READY 0x0010 ++#define SD_NISEN_DMA 0x0008 ++#define SD_NISEN_BLOCK_GAP 0x0004 ++#define SD_NISEN_XFR_DONE 0x0002 ++#define SD_NISEN_CMD_DONE 0x0001 ++ ++/* SD_EISEN_REG */ ++#define SD_EISEN_ADMA_ERR 0x0200 ++#define SD_EISEN_ACMD12_ERR 0x0100 ++#define SD_EISEN_CURRENT_ERR 0x0080 ++#define SD_EISEN_DATA_BIT_ERR 0x0040 ++#define SD_EISEN_DATA_TMOUT_ERR 0x0020 ++#define SD_EISEN_DATA_CRC_ERR 0x0010 ++#define SD_EISEN_CMD_IDX_ERR 0x0008 ++#define SD_EISEN_CMD_CRC_ERR 0x0004 ++#define SD_EISEN_CMD_BIT_ERR 0x0002 ++#define SD_EISEN_CMD_TMOUT_ERR 0x0001 ++ ++/* SD_NIXEN_REG */ ++#define SD_NIXEN_CARD 0x0100 ++#define SD_NIXEN_REMOVAL 0x0080 ++#define SD_NIXEN_INSERT 0x0040 ++#define SD_NIXEN_READ_READY 0x0020 ++#define SD_NIXEN_WRITE_READY 0x0010 ++#define SD_NIXEN_DMA 0x0008 ++#define SD_NIXEN_BLOCK_GAP 0x0004 ++#define SD_NIXEN_XFR_DONE 0x0002 ++#define SD_NIXEN_CMD_DONE 0x0001 ++ ++/* SD_EIXEN_REG */ ++#define SD_EISEN_ADMA_ERR 0x0200 ++#define SD_EIXEN_ACMD12_ERR 0x0100 ++#define SD_EIXEN_CURRENT_ERR 0x0080 ++#define SD_EIXEN_DATA_BIT_ERR 0x0040 ++#define SD_EIXEN_DATA_CRC_ERR 0x0020 ++#define SD_EIXEN_CMD_CRC_ERR 0x0010 ++#define SD_EIXEN_DATA_TMOUT_ERR 0x0008 ++#define SD_EIXEN_CMD_IDX_ERR 0x0004 ++#define SD_EIXEN_CMD_BIT_ERR 0x0002 ++#define SD_EIXEN_CMD_TMOUT_ERR 0x0001 ++ ++/* SD_AC12ES_REG */ ++#define SD_AC12ES_NOT_ISSUED 0x0040 ++#define SD_AC12ES_INDEX 0x0020 ++#define SD_AC12ES_NOT_EXECED 0x0010 ++#define SD_AC12ES_END_BIT 0x0004 ++#define SD_AC12ES_CRC_ERROR 0x0002 ++#define SD_AC12ES_TMOUT_ERROR 0x0001 ++ ++/* SD_ADMA_STA_REG */ ++#define SD_ADMA_STA_ST_STOP 0x00000000 ++#define SD_ADMA_STA_ST_FDS 0x00000001 ++#define SD_ADMA_STA_ST_TFR 0x00000003 ++#define SD_ADMA_STA_LEN_ERR 0x00000004 ++ ++/* SD_CAP_REG */ ++#define SD_CAP_INTMODE 0x08000000 ++#define SD_CAP_VOL_1_8V 0x04000000 ++#define SD_CAP_VOL_3_0V 0x02000000 ++#define SD_CAP_VOL_3_3V 0x01000000 ++#define SD_CAP_DMA 0x00800000 ++#define SD_CAP_SUS_RES 0x00400000 ++#define SD_CAP_HIGH_SPEED 0x00200000 ++//#define SD_CAP_ADMA_SUPPORT 0x00080000 ++#define SD_CAP_MAX_512B_BLK 0x00000000 ++#define SD_CAP_MAX_1KB_BLK 0x00010000 ++#define SD_CAP_MAX_2KB_BLK 0x00020000 ++#define SD_CAP_BASE_FREQ(x) (((x) & 0x3f00) >> 8) ++#define SD_CAP_TOCLK_KHZ 0x00000000 ++#define SD_CAP_TOCLK_MHZ 0x00000080 ++#define SD_CAP_TOCLK_FREQ(x) (((x) & 0x3f)) ++ ++/* SD_XC_CTR_REG */ ++#define SD_XC_CTR_DDR_EN 0x00008000 ++#define SD_XC_CTR_VOL_1_8V 0x00000001 ++#define SD_XC_CTR_VOL_3_3V 0x00000000 ++ ++/* SD_BOOT_CTR_REG */ ++#define SD_BOOT_CTR_RST_EN 0x00010000 ++ ++/* SD_BOOT_STA_REG */ ++#define SD_BOOT_STA_END_ALT 0x01010000 ++#define SD_BOOT_STA_BOOT_RDY 0x00000001 ++ ++/* SD_VOL_SW_REG */ ++#define SD_VOL_SW_CMD_STAT_H 0x00010000 ++#define SD_VOL_SW_DAT_STAT_H 0x00000007 ++ ++/* SD_VER_REG */ ++#define SD_VER_VENDOR(x) ((x) >> 8) ++#define SD_VER_SPEC(x) ((x) & 0xf) ++ ++#if 0 ++#define REG_SDIO_SYSADDRREG SD_REG(SD_DMA_ADDR_OFFSET) /* read/write */ ++#define REG_SDIO_BLKCNTREG SD_REG(SD_BLK_CNT_OFFSET) /* read/write 16bit */ ++#define REG_SDIO_BLKSZREG SD_REG(SD_BLK_SZ_OFFSET) /* read/write */ ++#define REG_SDIO_ARGREG SD_REG(SD_ARG_OFFSET) /* read/write */ ++#define REG_SDIO_TRANMODEREG SD_REG(SD_XFR_OFFSET) /* read/write */ ++#define REG_SDIO_CMDREG SD_REG(SD_CMD_OFFSET) /* read/write 16bit */ ++#define REG_SDIO_RESP0REG SD_REG(SD_RSP0_OFFSET) /* read */ ++#define REG_SDIO_RESP1REG SD_REG(SD_RSP1_OFFSET) /* read */ ++#define REG_SDIO_RESP2REG SD_REG(SD_RSP2_OFFSET) /* read */ ++#define REG_SDIO_RESP3REG SD_REG(SD_RSP3_OFFSET) /* read */ ++#define REG_SDIO_BUFFERDATAPORTREG SD_REG(SD_DATA_OFFSET) /* read/write */ ++#define REG_SDIO_PRESENTSTATEREG SD_REG(SD_STA_OFFSET) /* read */ ++#define REG_SDIO_CONTROL00REG SD_REG(SD_HOST_OFFSET) /* read/write */ ++#define REG_SDIO_CONTROL010REG SD_REG(SD_TMO_OFFSET) /* read/write */ ++#define REG_SDIO_CONTROL011REG SD_REG(SD_CLK_OFFSET) /* read/write */ ++#define REG_SDIO_NORINTSTATUSREG SD_REG(SD_NIS_OFFSET) /* read/write 16bit */ ++#define REG_SDIO_ERRINTSTATUSREG SD_REG(SD_EIS_OFFSET) /* read/write 16bit */ ++#define REG_SDIO_NORINTSTATUSENREG SD_REG(SD_NISEN_OFFSET) /* read/write 16bit */ ++#define REG_SDIO_ERRINTSTATUSENREG SD_REG(SD_EISEN_OFFSET) /* read/write 16bit */ ++#define REG_SDIO_NORINTSIGENREG SD_REG(SD_NIXEN_OFFSET) /* read/write 16bit */ ++#define REG_SDIO_ERRINTSIGENREG SD_REG(SD_EIXEN_OFFSET) /* read/write 16bit */ ++#define REG_SDIO_AUTOCMD12ERRSTATUSREG SD_REG(SD_AC12ES_OFFSET) /* read/write */ ++#define REG_SDIO_CAPREG SD_REG(SD_CAP_OFFSET) /* read */ ++#define REG_SDIO_MAXCURCAPREG SD_REG(SD_CUR_OFFSET) /* read/write */ ++#define REG_SDIO_SLOTINTSTATUSREG SD_REG(SD_SIST_OFFSET) /* read */ ++ ++#ifdef CONFIG_GK710XS_SDIO2 ++#define REG_SDIO1_SYSADDRREG SD1_REG(SD_DMA_ADDR_OFFSET) /* read/write */ ++#define REG_SDIO1_BLKCNTREG SD1_REG(SD_BLK_CNT_OFFSET) /* read/write 16bit */ ++#define REG_SDIO1_BLKSZREG SD1_REG(SD_BLK_SZ_OFFSET) /* read/write 16bit */ ++#define REG_SDIO1_ARGREG SD1_REG(SD_ARG_OFFSET) /* read/write */ ++#define REG_SDIO1_TRANMODEREG SD1_REG(SD_XFR_OFFSET) /* read/write 16bit */ ++#define REG_SDIO1_CMDREG SD1_REG(SD_CMD_OFFSET) /* read/write 16bit */ ++#define REG_SDIO1_RESP0REG SD1_REG(SD_RSP0_OFFSET) /* read */ ++#define REG_SDIO1_RESP1REG SD1_REG(SD_RSP1_OFFSET) /* read */ ++#define REG_SDIO1_RESP2REG SD1_REG(SD_RSP2_OFFSET) /* read */ ++#define REG_SDIO1_RESP3REG SD1_REG(SD_RSP3_OFFSET) /* read */ ++#define REG_SDIO1_BUFFERDATAPORTREG SD1_REG(SD_DATA_OFFSET) /* read/write */ ++#define REG_SDIO1_PRESENTSTATEREG SD1_REG(SD_STA_OFFSET) /* read */ ++#define REG_SDIO1_CONTROL00REG SD1_REG(SD_HOST_OFFSET) /* read/write */ ++#define REG_SDIO1_CONTROL010REG SD1_REG(SD_TMO_OFFSET) /* read/write */ ++#define REG_SDIO1_CONTROL011REG SD1_REG(SD_CLK_OFFSET) /* read/write */ ++#define REG_SDIO1_NORINTSTATUSREG SD1_REG(SD_NIS_OFFSET) /* read/write 16bit */ ++#define REG_SDIO1_ERRINTSTATUSREG SD1_REG(SD_EIS_OFFSET) /* read/write 16bit */ ++#define REG_SDIO1_NORINTSTATUSENREG SD1_REG(SD_NISEN_OFFSET) /* read/write 16bit */ ++#define REG_SDIO1_ERRINTSTATUSENREG SD1_REG(SD_EISEN_OFFSET) /* read/write 16bit */ ++#define REG_SDIO1_NORINTSIGENREG SD1_REG(SD_NIXEN_OFFSET) /* read/write 16bit */ ++#define REG_SDIO1_ERRINTSIGENREG SD1_REG(SD_EIXEN_OFFSET) /* read/write 16bit */ ++#define REG_SDIO1_AUTOCMD12ERRSTATUSREG SD1_REG(SD_AC12ES_OFFSET) /* read/write */ ++#define REG_SDIO1_CAPREG SD1_REG(SD_CAP_OFFSET) /* read */ ++#define REG_SDIO1_MAXCURCAPREG SD1_REG(SD_CUR_OFFSET) /* read/write */ ++#define REG_SDIO1_SLOTINTSTATUSREG SD1_REG(SD_SIST_OFFSET) /* read */ ++#endif ++#endif ++ ++#endif /* __MACH_GK_SD_H */ ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/spi.h b/arch/arm/mach-gk710xs/include/mach/spi.h +new file mode 100644 +index 00000000..66706e39 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/spi.h +@@ -0,0 +1,327 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/spi.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_GK_SPI_H ++#define __MACH_GK_SPI_H ++ ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++#define SPI_MAX_SLAVE_ID 7 ++ ++#define SPI_SUPPORT_TISSP_NSM 1 ++ ++#define SPI_INSTANCES 2 ++#define SPI_AHB_INSTANCES 0 ++#define SPI_SUPPORT_TSSI_MODE 1 ++ ++ ++#define SPI_EN2_EN3_ENABLED_BY_HOST_ENA_REG 0 ++ ++#define SPI_EN2_ENABLED_BY_GPIO2_AFSEL_REG 0 ++ ++#define SPI_EN4_7_ENABLED_BY_GPIO1_AFSEL_REG 1 ++ ++#define SPI_SLAVE_INSTANCES 0 ++ ++#define SPI_SUPPORT_MASTER_CHANGE_ENA_POLARITY 0 ++#define SPI_SUPPORT_MASTER_DELAY_START_TIME 0 ++#define SPI_SUPPORT_NSM_SHAKE_START_BIT_CHSANGE 0 ++ ++#define SPI_EN2_EN3_ENABLED_BY_GPIO2_AFSEL_REG 0 ++ ++/* SPI_FIFO_SIZE */ ++#define SPI_DATA_FIFO_SIZE_16 0x10 ++#define SPI_DATA_FIFO_SIZE_32 0x20 ++#define SPI_DATA_FIFO_SIZE_64 0x40 ++#define SPI_DATA_FIFO_SIZE_128 0x80 ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++#if SSI_HAL_MODE ++#define SPI_CTRLR0_OFFSET 0x0c ++#define SPI_CTRLR1_OFFSET 0x10 ++#define SPI_SSIENR_OFFSET 0x08 ++#define SPI_MWCR_OFFSET 0x14 ++#define SPI_SER_OFFSET 0x60 ++#define SPI_BAUDR_OFFSET 0x18 ++#define SPI_TXFTLR_OFFSET 0x3c ++#define SPI_RXFTLR_OFFSET 0x48 ++#define SPI_TXFLR_OFFSET 0x40 ++#define SPI_RXFLR_OFFSET 0x4c ++#define SPI_SR_OFFSET 0x04 ++#define SPI_IMR_OFFSET 0x1c ++#define SPI_ISR_OFFSET 0x30 ++#define SPI_RISR_OFFSET 0x2c ++#define SPI_TXOICR_OFFSET 0x44 ++#define SPI_RXOICR_OFFSET 0x50 ++#define SPI_RXUICR_OFFSET 0x54 ++#define SPI_MSTICR_OFFSET 0x24 ++#define SPI_ICR_OFFSET 0x20 ++#if (SPI_AHB_INSTANCES >= 1) ++#define SPI_DMAC_OFFSET 0x28 ++#endif ++#define SPI_IDR_OFFSET 0x00 ++#define SPI_VERSION_ID_OFFSET 0x5c ++#define SPI_DR_OFFSET 0x38 ++ ++#if (SPI_SUPPORT_MASTER_CHANGE_ENA_POLARITY == 1) ++#define SPI_SSIENPOLR_OFFSET 0x260 ++#endif ++#if (SPI_SUPPORT_MASTER_DELAY_START_TIME == 1) ++#define SPI_SCLK_OUT_DLY_OFFSET 0x264 ++#endif ++#if (SPI_SUPPORT_NSM_SHAKE_START_BIT_CHSANGE == 1) ++#define SPI_START_BIT_OFFSET 0x268 ++#endif ++ ++#define TSSI_CTRL_OFFSET 0x04 ++#define TSSI_SSR_OFFSET 0x00 ++#define TSSI_INDEX_OFFSET 0x0c ++#define TSSI_DATA_OFFSET 0x08 ++#define TSSI_POLARITY_INVERT 0x10 ++ ++#else ++#define SPI_CTRLR0_OFFSET 0x00 ++#define SPI_CTRLR1_OFFSET 0x04 ++#define SPI_SSIENR_OFFSET 0x08 ++#define SPI_MWCR_OFFSET 0x0C ++#define SPI_SER_OFFSET 0x10 ++#define SPI_BAUDR_OFFSET 0x14 ++#define SPI_TXFTLR_OFFSET 0x18 ++#define SPI_RXFTLR_OFFSET 0x1C ++#define SPI_TXFLR_OFFSET 0x20 ++#define SPI_RXFLR_OFFSET 0x24 ++#define SPI_SR_OFFSET 0x28 ++#define SPI_IMR_OFFSET 0x2C ++#define SPI_ISR_OFFSET 0x30 ++#define SPI_RISR_OFFSET 0x34 ++#define SPI_TXOICR_OFFSET 0x38 ++#define SPI_RXOICR_OFFSET 0x3C ++#define SPI_RXUICR_OFFSET 0x40 ++#define SPI_MSTICR_OFFSET 0x44 ++#define SPI_ICR_OFFSET 0x48 ++#if (SPI_AHB_INSTANCES >= 1) ++#define SPI_DMAC_OFFSET 0x4C ++#endif ++#define SPI_IDR_OFFSET 0x58 ++#define SPI_VERSION_ID_OFFSET 0x5C ++#define SPI_DR_OFFSET 0x60 ++ ++#if (SPI_SUPPORT_MASTER_CHANGE_ENA_POLARITY == 1) ++#define SPI_SSIENPOLR_OFFSET 0x260 ++#endif ++#if (SPI_SUPPORT_MASTER_DELAY_START_TIME == 1) ++#define SPI_SCLK_OUT_DLY_OFFSET 0x264 ++#endif ++#if (SPI_SUPPORT_NSM_SHAKE_START_BIT_CHSANGE == 1) ++#define SPI_START_BIT_OFFSET 0x268 ++#endif ++ ++#define TSSI_CTRL_OFFSET 0x00 ++#define TSSI_SSR_OFFSET 0x04 ++#define TSSI_INDEX_OFFSET 0x08 ++#define TSSI_DATA_OFFSET 0x0C ++#define TSSI_POLARITY_INVERT 0x10 ++#endif ++ ++#define SPI_REG(x) (GK_VA_SSI1 + (x)) ++#define SPI2_REG(x) (GK_VA_SSI2 + (x)) ++#define TSSI_REG(x) (GK_VA_TSSI + (x)) ++ ++#define SPI_CTRLR0_REG SPI_REG(SPI_CTRLR0_OFFSET) ++#define SPI_CTRLR1_REG SPI_REG(SPI_CTRLR1_OFFSET) ++#define SPI_SSIENR_REG SPI_REG(SPI_SSIENR_OFFSET) ++#define SPI_MWCR_REG SPI_REG(SPI_MWCR_OFFSET) ++#define SPI_SER_REG SPI_REG(SPI_SER_OFFSET) ++#define SPI_BAUDR_REG SPI_REG(SPI_BAUDR_OFFSET) ++#define SPI_TXFTLR_REG SPI_REG(SPI_TXFTLR_OFFSET) ++#define SPI_RXFTLR_REG SPI_REG(SPI_RXFTLR_OFFSET) ++#define SPI_TXFLR_REG SPI_REG(SPI_TXFLR_OFFSET) ++#define SPI_RXFLR_REG SPI_REG(SPI_RXFLR_OFFSET) ++#define SPI_SR_REG SPI_REG(SPI_SR_OFFSET) ++#define SPI_IMR_REG SPI_REG(SPI_IMR_OFFSET) ++#define SPI_ISR_REG SPI_REG(SPI_ISR_OFFSET) ++#define SPI_RISR_REG SPI_REG(SPI_RISR_OFFSET) ++#define SPI_TXOICR_REG SPI_REG(SPI_TXOICR_OFFSET) ++#define SPI_RXOICR_REG SPI_REG(SPI_RXOICR_OFFSET) ++#define SPI_RXUICR_REG SPI_REG(SPI_RXUICR_OFFSET) ++#define SPI_MSTICR_REG SPI_REG(SPI_MSTICR_OFFSET) ++#define SPI_ICR_REG SPI_REG(SPI_ICR_OFFSET) ++#define SPI_IDR_REG SPI_REG(SPI_IDR_OFFSET) ++#define SPI_VERSION_ID_REG SPI_REG(SPI_VERSION_ID_OFFSET) ++#define SPI_DR_REG SPI_REG(SPI_DR_OFFSET) ++ ++#if (SPI_INSTANCES >= 2) ++#define SPI2_CTRLR0_REG SPI2_REG(SPI_CTRLR0_OFFSET) ++#define SPI2_CTRLR1_REG SPI2_REG(SPI_CTRLR1_OFFSET) ++#define SPI2_SSIENR_REG SPI2_REG(SPI_SSIENR_OFFSET) ++#define SPI2_MWCR_REG SPI2_REG(SPI_MWCR_OFFSET) ++#define SPI2_SER_REG SPI2_REG(SPI_SER_OFFSET) ++#define SPI2_BAUDR_REG SPI2_REG(SPI_BAUDR_OFFSET) ++#define SPI2_TXFTLR_REG SPI2_REG(SPI_TXFTLR_OFFSET) ++#define SPI2_RXFTLR_REG SPI2_REG(SPI_RXFTLR_OFFSET) ++#define SPI2_TXFLR_REG SPI2_REG(SPI_TXFLR_OFFSET) ++#define SPI2_RXFLR_REG SPI2_REG(SPI_RXFLR_OFFSET) ++#define SPI2_SR_REG SPI2_REG(SPI_SR_OFFSET) ++#define SPI2_IMR_REG SPI2_REG(SPI_IMR_OFFSET) ++#define SPI2_ISR_REG SPI2_REG(SPI_ISR_OFFSET) ++#define SPI2_RISR_REG SPI2_REG(SPI_RISR_OFFSET) ++#define SPI2_TXOICR_REG SPI2_REG(SPI_TXOICR_OFFSET) ++#define SPI2_RXOICR_REG SPI2_REG(SPI_RXOICR_OFFSET) ++#define SPI2_RXUICR_REG SPI2_REG(SPI_RXUICR_OFFSET) ++#define SPI2_MSTICR_REG SPI2_REG(SPI_MSTICR_OFFSET) ++#define SPI2_ICR_REG SPI2_REG(SPI_ICR_OFFSET) ++#define SPI2_IDR_REG SPI2_REG(SPI_IDR_OFFSET) ++#define SPI2_VERSION_ID_REG SPI2_REG(SPI_VERSION_ID_OFFSET) ++#define SPI2_DR_REG SPI2_REG(SPI_DR_OFFSET) ++#endif ++ ++#define TSSI_CTRL_REG TSSI_REG(TSSI_CTRL_OFFSET) ++#define TSSI_SSR_REG TSSI_REG(TSSI_SSR_OFFSET) ++#define TSSI_INDEX_REG TSSI_REG(TSSI_INDEX_OFFSET) ++#define TSSI_DATA_REG TSSI_REG(TSSI_DATA_OFFSET) ++#define TSSI_POLARITY_INVERT_REG TSSI_REG(TSSI_POLARITY_INVERT) ++ ++ ++#define SPI_MASTER_INSTANCES (SPI_INSTANCES + SPI_AHB_INSTANCES) ++ ++/* ==========================================================================*/ ++/* SPI rw mode */ ++#define SPI_WRITE_READ 0 ++#define SPI_WRITE_ONLY 1 ++#define SPI_READ_ONLY 2 ++ ++/* Tx FIFO empty interrupt mask */ ++#define SPI_TXEIS_MASK 0x00000001 ++#define SPI_TXOIS_MASK 0x00000002 ++ ++/* SPI Parameters */ ++#define SPI_DUMMY_DATA 0xffff ++#define MAX_QUERY_TIMES 10 ++ ++/* Default SPI settings */ ++#define SPI_MODE SPI_MODE_0 ++#define SPI_SCPOL 0 ++#define SPI_SCPH 0 ++#define SPI_FRF 0 ++#define SPI_CFS 0x0 ++#define SPI_DFS 0xf ++#define SPI_BAUD_RATE 200000 ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++struct gk_spi_hw_info { ++ int bus_id; ++ int cs_id; ++}; ++typedef struct gk_spi_hw_info gk_spi_hw_t; ++ ++struct gk_spi_cfg_info { ++ u8 spi_mode; ++ u8 cfs_dfs; ++ u8 cs_change; ++ u32 baud_rate; ++}; ++typedef struct gk_spi_cfg_info gk_spi_cfg_t; ++ ++typedef struct { ++ u8 bus_id; ++ u8 cs_id; ++ u8 *buffer; ++ u16 n_size; ++} gk_spi_write_t; ++ ++typedef struct { ++ u8 bus_id; ++ u8 cs_id; ++ u8 *buffer; ++ u16 n_size; ++} gk_spi_read_t; ++ ++typedef struct { ++ u8 bus_id; ++ u8 cs_id; ++ u8 *w_buffer; ++ u8 *r_buffer; ++ u16 w_size; ++ u16 r_size; ++} gk_spi_write_then_read_t; ++ ++typedef struct { ++ u8 bus_id; ++ u8 cs_id; ++ u8 *w_buffer; ++ u8 *r_buffer; ++ u16 n_size; ++} gk_spi_write_and_read_t; ++ ++struct gk_spi_cs_config { ++ u8 bus_id; ++ u8 cs_id; ++ u8 cs_num; ++ int *cs_pins; ++}; ++ ++struct gk_spi_platform_info { ++ int support_dma; ++ int fifo_entries; ++ int cs_num; ++ int *cs_pins; ++ void (*cs_activate) (struct gk_spi_cs_config *); ++ void (*cs_deactivate)(struct gk_spi_cs_config *); ++ void (*rct_set_ssi_pll)(void); ++ u32 (*get_ssi_freq_hz)(void); ++}; ++#define GK_SPI_PARAM_CALL(id, arg, perm) \ ++ module_param_cb(spi##id##_cs0, ¶m_ops_int, &(arg[0]), perm); \ ++ module_param_cb(spi##id##_cs1, ¶m_ops_int, &(arg[1]), perm); \ ++ module_param_cb(spi##id##_cs2, ¶m_ops_int, &(arg[2]), perm); \ ++ module_param_cb(spi##id##_cs3, ¶m_ops_int, &(arg[3]), perm); \ ++ module_param_cb(spi##id##_cs4, ¶m_ops_int, &(arg[4]), perm); \ ++ module_param_cb(spi##id##_cs5, ¶m_ops_int, &(arg[5]), perm); \ ++ module_param_cb(spi##id##_cs6, ¶m_ops_int, &(arg[6]), perm); \ ++ module_param_cb(spi##id##_cs7, ¶m_ops_int, &(arg[7]), perm) ++ ++/* ==========================================================================*/ ++extern struct platform_device gk_spi0; ++extern struct platform_device gk_spi1; ++extern struct platform_device gk_spi2; ++extern struct platform_device gk_spi3; ++extern struct platform_device gk_spi4; ++extern struct platform_device gk_spi_slave; ++ ++/* ==========================================================================*/ ++extern int gk_spi_write(gk_spi_cfg_t *spi_cfg, ++ gk_spi_write_t *spi_write); ++extern int gk_spi_read(gk_spi_cfg_t *spi_cfg, ++ gk_spi_read_t *spi_read); ++extern int gk_spi_write_then_read(gk_spi_cfg_t *spi_cfg, ++ gk_spi_write_then_read_t *spi_write_then_read); ++extern int gk_spi_write_and_read(gk_spi_cfg_t *spi_cfg, ++ gk_spi_write_and_read_t *spi_write_and_read); ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/timer.h b/arch/arm/mach-gk710xs/include/mach/timer.h +new file mode 100644 +index 00000000..fa099e1b +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/timer.h +@@ -0,0 +1,100 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/timer.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_TIMER_H__ ++#define __MACH_TIMER_H__ ++ ++#include ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++ ++#define INTERVAL_TIMER_INSTANCES 3 ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++#define TIMER_BASE GK_VA_TIMER ++#define TIMER_REG(x) (GK_VA_TIMER + (x)) ++ ++#define TIMER_CTR_OFFSET 0x0c ++ ++#define TIMER1_STATUS_OFFSET 0x00 ++#define TIMER1_MATCH1_OFFSET 0x04 ++#define TIMER1_MATCH2_OFFSET 0x08 ++ ++#define TIMER2_STATUS_OFFSET 0x14 ++#define TIMER2_MATCH1_OFFSET 0x18 ++#define TIMER2_MATCH2_OFFSET 0x1c ++ ++#define TIMER3_STATUS_OFFSET 0x20 ++#define TIMER3_MATCH1_OFFSET 0x24 ++#define TIMER3_MATCH2_OFFSET 0x28 ++ ++#define TIMER1_RELOAD_OFFSET 0x30 ++#define TIMER2_RELOAD_OFFSET 0x34 ++#define TIMER3_RELOAD_OFFSET 0x38 ++ ++#define TIMER1_STATUS_REG TIMER_REG(TIMER1_STATUS_OFFSET) ++#define TIMER1_RELOAD_REG TIMER_REG(TIMER1_RELOAD_OFFSET) ++#define TIMER1_MATCH1_REG TIMER_REG(TIMER1_MATCH1_OFFSET) ++#define TIMER1_MATCH2_REG TIMER_REG(TIMER1_MATCH2_OFFSET) ++#define TIMER2_STATUS_REG TIMER_REG(TIMER2_STATUS_OFFSET) ++#define TIMER2_RELOAD_REG TIMER_REG(TIMER2_RELOAD_OFFSET) ++#define TIMER2_MATCH1_REG TIMER_REG(TIMER2_MATCH1_OFFSET) ++#define TIMER2_MATCH2_REG TIMER_REG(TIMER2_MATCH2_OFFSET) ++#define TIMER3_STATUS_REG TIMER_REG(TIMER3_STATUS_OFFSET) ++#define TIMER3_RELOAD_REG TIMER_REG(TIMER3_RELOAD_OFFSET) ++#define TIMER3_MATCH1_REG TIMER_REG(TIMER3_MATCH1_OFFSET) ++#define TIMER3_MATCH2_REG TIMER_REG(TIMER3_MATCH2_OFFSET) ++ ++#define TIMER_CTR_REG TIMER_REG(TIMER_CTR_OFFSET) ++ ++ ++/* Bit field definition of timer control register */ ++#define TIMER_CTR_EN1 0x00000400 ++#define TIMER_CTR_EN2 0x00000200 ++#define TIMER_CTR_EN3 0x00000100 ++ ++#define TIMER_CTR_CSL1 0x00000004 ++#define TIMER_CTR_CSL2 0x00000002 ++#define TIMER_CTR_CSL3 0x00000001 ++ ++#define TIMER_CTR_OF1 0x00000040 ++#define TIMER_CTR_OF2 0x00000020 ++#define TIMER_CTR_OF3 0x00000010 ++ ++//***************************************************************************** ++//***************************************************************************** ++//** API Functions ++//***************************************************************************** ++//***************************************************************************** ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++extern struct sys_timer gk_sys_timer; ++extern int gk_init_timer(void) __init; ++ ++extern int get_hwtimer_output_ticks(u64 *out_tick); ++ ++#ifdef __cplusplus ++} ++#endif ++#endif +diff --git a/arch/arm/mach-gk710xs/include/mach/timex.h b/arch/arm/mach-gk710xs/include/mach/timex.h +new file mode 100644 +index 00000000..326a719c +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/timex.h +@@ -0,0 +1,26 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/timex.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_TIMEX_H ++#define __MACH_TIMEX_H ++ ++ ++#define CLOCK_TICK_RATE 15000000 //unit:100Hz 18MHz ++ ++ ++#endif /* __MACH_TIMEX_H */ ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/uart.h b/arch/arm/mach-gk710xs/include/mach/uart.h +new file mode 100644 +index 00000000..d286b801 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/uart.h +@@ -0,0 +1,316 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/mach/uart.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_UART_H_ ++#define __MACH_UART_H_ ++ ++#include ++#include ++ ++//#define KE_DEBUG ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Defines and Macros ++//***************************************************************************** ++//***************************************************************************** ++ ++#define UART_BASE_FREQ (get_uart_freq_hz()) ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++#define UART_INSTANCES 3 ++ ++#define UART0_VA_ADDR (GK_VA_UART0) ++#define UART0_PA_ADDR (GK_PA_UART0) ++ ++#if (UART_INSTANCES >= 2) ++#define UART1_VA_ADDR (GK_VA_UART1) ++#define UART1_PA_ADDR (GK_PA_UART1) ++#endif ++ ++#if (UART_INSTANCES >= 3) ++#define UART2_VA_ADDR (GK_VA_UART2) ++#define UART2_PA_ADDR (GK_PA_UART2) ++#endif ++ ++#if (UART_INSTANCES >= 4) ++#define UART3_VA_ADDR (GK_VA_UART3) ++#define UART3_PA_ADDR (GK_PA_UART3) ++#endif ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++ ++#define UART0_REG(x) (GK_VA_UART0 + (x)) ++ ++#if (UART_INSTANCES >= 2) ++#define UART1_REG(x) (GK_VA_UART1 + (x)) ++#endif ++ ++#if (UART_INSTANCES >= 3) ++#define UART2_REG(x) (GK_VA_UART2 + (x)) ++#endif ++ ++#if (UART_INSTANCES >= 4) ++#define UART3_REG(x) (GK_VA_UART3 + (x)) ++#endif ++ ++#define UART_RB_OFFSET 0x04 ++#define UART_TH_OFFSET 0x04 ++#define UART_DLL_OFFSET 0x04 ++#define UART_IE_OFFSET 0x00 ++#define UART_DLH_OFFSET 0x00 ++#define UART_II_OFFSET 0x08 ++#define UART_FC_OFFSET 0x08 ++#define UART_LC_OFFSET 0x18 ++#define UART_MC_OFFSET 0x0c ++#define UART_LS_OFFSET 0x14 ++#define UART_MS_OFFSET 0x10 ++#define UART_SC_OFFSET 0x1c /* Byte */ ++#define UART_SRR_OFFSET 0x88 ++ ++#define UART0_RB_REG UART0_REG(UART_RB_OFFSET) ++#define UART0_TH_REG UART0_REG(UART_TH_OFFSET) ++#define UART0_DLL_REG UART0_REG(UART_DLL_OFFSET) ++#define UART0_IE_REG UART0_REG(UART_IE_OFFSET) ++#define UART0_DLH_REG UART0_REG(UART_DLH_OFFSET) ++#define UART0_II_REG UART0_REG(UART_II_OFFSET) ++#define UART0_FC_REG UART0_REG(UART_FC_OFFSET) ++#define UART0_LC_REG UART0_REG(UART_LC_OFFSET) ++#define UART0_MC_REG UART0_REG(UART_MC_OFFSET) ++#define UART0_LS_REG UART0_REG(UART_LS_OFFSET) ++#define UART0_MS_REG UART0_REG(UART_MS_OFFSET) ++#define UART0_SC_REG UART0_REG(UART_SC_OFFSET) /* Byte */ ++ ++#if (UART_INSTANCES >= 2) ++ ++#define UART1_RB_REG UART1_REG(UART_RB_OFFSET) ++#define UART1_TH_REG UART1_REG(UART_TH_OFFSET) ++#define UART1_DLL_REG UART1_REG(UART_DLL_OFFSET) ++#define UART1_IE_REG UART1_REG(UART_IE_OFFSET) ++#define UART1_DLH_REG UART1_REG(UART_DLH_OFFSET) ++#define UART1_II_REG UART1_REG(UART_II_OFFSET) ++#define UART1_FC_REG UART1_REG(UART_FC_OFFSET) ++#define UART1_LC_REG UART1_REG(UART_LC_OFFSET) ++#define UART1_MC_REG UART1_REG(UART_MC_OFFSET) ++#define UART1_LS_REG UART1_REG(UART_LS_OFFSET) ++#define UART1_MS_REG UART1_REG(UART_MS_OFFSET) ++#define UART1_SC_REG UART1_REG(UART_SC_OFFSET) /* Byte */ ++ ++#endif /* UART_INSTANCES >= 2 */ ++ ++#if (UART_INSTANCES >= 3) ++ ++#define UART2_RB_REG UART2_REG(UART_RB_OFFSET) ++#define UART2_TH_REG UART2_REG(UART_TH_OFFSET) ++#define UART2_DLL_REG UART2_REG(UART_DLL_OFFSET) ++#define UART2_IE_REG UART2_REG(UART_IE_OFFSET) ++#define UART2_DLH_REG UART2_REG(UART_DLH_OFFSET) ++#define UART2_II_REG UART2_REG(UART_II_OFFSET) ++#define UART2_FC_REG UART2_REG(UART_FC_OFFSET) ++#define UART2_LC_REG UART2_REG(UART_LC_OFFSET) ++#define UART2_MC_REG UART2_REG(UART_MC_OFFSET) ++#define UART2_LS_REG UART2_REG(UART_LS_OFFSET) ++#define UART2_MS_REG UART2_REG(UART_MS_OFFSET) ++#define UART2_SC_REG UART2_REG(UART_SC_OFFSET) /* Byte */ ++ ++#endif /* UART_INSTANCES >= 3 */ ++ ++#if (UART_INSTANCES >= 4) ++ ++#define UART3_RB_REG UART3_REG(UART_RB_OFFSET) ++#define UART3_TH_REG UART3_REG(UART_TH_OFFSET) ++#define UART3_DLL_REG UART3_REG(UART_DLL_OFFSET) ++#define UART3_IE_REG UART3_REG(UART_IE_OFFSET) ++#define UART3_DLH_REG UART3_REG(UART_DLH_OFFSET) ++#define UART3_II_REG UART3_REG(UART_II_OFFSET) ++#define UART3_FC_REG UART3_REG(UART_FC_OFFSET) ++#define UART3_LC_REG UART3_REG(UART_LC_OFFSET) ++#define UART3_MC_REG UART3_REG(UART_MC_OFFSET) ++#define UART3_LS_REG UART3_REG(UART_LS_OFFSET) ++#define UART3_MS_REG UART3_REG(UART_MS_OFFSET) ++#define UART3_SC_REG UART3_REG(UART_SC_OFFSET) /* Byte */ ++ ++#endif /* UART_INSTANCES >= 4 */ ++ ++/* UART[x]_IE_REG */ ++#define UART_IE_PTIME 0x80 ++#define UART_IE_ETOI 0x20 ++#define UART_IE_EBDI 0x10 ++#define UART_IE_EDSSI 0x08 ++#define UART_IE_ELSI 0x04 ++#define UART_IE_ETBEI 0x02 ++#define UART_IE_ERBFI 0x01 ++ ++/* UART[x]_II_REG */ ++#define UART_II_MODEM_STATUS_CHANGED 0x00 ++#define UART_II_NO_INT_PENDING 0x01 ++#define UART_II_THR_EMPTY 0x02 ++#define UART_II_RCV_DATA_AVAIL 0x04 ++#define UART_II_RCV_STATUS 0x06 ++#define UART_II_CHAR_TIMEOUT 0x0c ++ ++/* UART[x]_FC_REG */ ++#define UART_FC_RX_ONECHAR 0x00 ++#define UART_FC_RX_QUARTER_FULL 0x40 ++#define UART_FC_RX_HALF_FULL 0x80 ++#define UART_FC_RX_2_TO_FULL 0xc0 ++#define UART_FC_TX_EMPTY 0x00 ++#define UART_FC_TX_2_IN_FIFO 0x10 ++#define UART_FC_TX_QUATER_IN_FIFO 0x20 ++#define UART_FC_TX_HALF_IN_FIFO 0x30 ++#define UART_FC_XMITR 0x04 ++#define UART_FC_RCVRR 0x02 ++#define UART_FC_FIFOE 0x01 ++ ++/* UART[x]_LC_REG */ ++#define UART_LC_BRK 0x80 ++ ++#define UART_LC_EVEN_PARITY 0x40 ++#define UART_LC_ODD_PARITY 0x00 ++ ++#define UART_LC_STICKY_PARITY 0x20 ++#define UART_LC_DLAB 0x10 ++ ++#define UART_LC_STOP_2BIT 0x08 ++#define UART_LC_STOP_1BIT 0x00 ++ ++#define UART_LC_PEN 0x04 ++#define UART_LC_CLS_8_BITS 0x03 ++#define UART_LC_CLS_7_BITS 0x02 ++#define UART_LC_CLS_6_BITS 0x01 ++#define UART_LC_CLS_5_BITS 0x00 ++ ++/* quick defs */ ++#define UART_LC_8N1 0x03 ++#define UART_LC_7E1 0x0a ++ ++/* UART[x]_MC_REG */ ++#define UART_MC_LB 0x40 ++#define UART_MC_AFCE 0x20 ++#define UART_MC_SIRE 0x10 ++#define UART_MC_RTS 0x08 ++#define UART_MC_DTR 0x04 ++#define UART_MC_OUT2 0x02 ++#define UART_MC_OUT1 0x01 ++ ++/* UART[x]_LS_REG */ ++#define UART_LS_FERR 0x80 ++ ++#define UART_LS_TEMT 0x40 ++#define UART_LS_BI 0x20 ++#define UART_LS_FE 0x10 ++#define UART_LS_THRE 0x08 ++ ++#define UART_LS_DR 0x04 ++#define UART_LS_PE 0x02 ++#define UART_LS_OE 0x01 ++ ++/* UART[x]_MS_REG */ ++#define UART_MS_DCD 0x80 ++#define UART_MS_DCTS 0x40 ++#define UART_MS_CTS 0x20 ++#define UART_MS_DDCD 0x10 ++#define UART_MS_DSR 0x08 ++#define UART_MS_DDSR 0x04 ++#define UART_MS_TERI 0x02 ++#define UART_MS_RI 0x01 ++ ++/* Other defs for UART */ ++#define RECV_BUF_SIZ 1500 ++#define SEND_BUF_SIZ 1500 ++ ++/* ==========================================================================*/ ++#define UART_FIFO_SIZE (16) ++ ++#define DEFAULT_UART_MCR (0) ++#define DEFAULT_UART_IER (UART_IE_ELSI | UART_IE_ERBFI) ++#define DEFAULT_UART_FCR (UART_FC_FIFOE | UART_FC_RX_2_TO_FULL | UART_FC_TX_EMPTY) ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Enumerated types ++//***************************************************************************** ++//***************************************************************************** ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Data Structures ++//***************************************************************************** ++//***************************************************************************** ++ ++#ifndef __ASSEMBLER__ ++ ++struct gk_uart_port_info ++{ ++ void *port; //struct uart_port * ++ u32 mcr; ++ u32 fcr; ++ u32 ier; ++ u32 tx_fifo_fix; ++ ++ void (*stop_tx)(unsigned char __iomem *membase); ++ void (*set_pll)(void); ++ u32 (*get_pll)(void); ++ u32 (*get_ms)(unsigned char __iomem *membase); ++}; ++ ++struct gk_uart_platform_info ++{ ++ int total_port_num; ++ int registed_port_num; ++ ++ struct gk_uart_port_info port[UART_INSTANCES]; ++}; ++ ++extern struct gk_uart_platform_info gk_uart_ports; ++ ++#ifdef KE_DEBUG ++extern void after_print(const char *str, ...); ++#endif ++ ++/* ==========================================================================*/ ++#endif /* __ASSEMBLER__ */ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Global Data ++//***************************************************************************** ++//***************************************************************************** ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** API Functions ++//***************************************************************************** ++//***************************************************************************** ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MACH_UART_H_ */ +diff --git a/arch/arm/mach-gk710xs/include/mach/uncompress.h b/arch/arm/mach-gk710xs/include/mach/uncompress.h +new file mode 100644 +index 00000000..cfa8cc09 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/uncompress.h +@@ -0,0 +1,76 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/uncompress.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_UNCOMPRESS_H ++#define __MACH_UNCOMPRESS_H ++ ++/* ==========================================================================*/ ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++#include ++#include ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++ ++typedef void* (*hal_function_t) (unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) ; ++ ++struct hw_ops *g_hw; ++ ++#define PA_UART0 GK_PA_UART0 ++ ++#define UART_LS_REG ((PA_UART0 + UART_LS_OFFSET)) ++#define UART_TH_REG ((PA_UART0 + UART_TH_OFFSET)) ++#define UART_RB_REG ((PA_UART0 + UART_RB_OFFSET)) ++#define UART_SRR_REG ((PA_UART0 + UART_SRR_OFFSET)) ++ ++#define UART_LC_REG ((PA_UART0 + UART_LC_OFFSET)) ++#define UART_DLL_REG ((PA_UART0 + UART_DLL_OFFSET)) ++#define UART_DLH_REG ((PA_UART0 + UART_DLH_OFFSET)) ++ ++/* ==========================================================================*/ ++ ++static inline void putc(int c) ++{ ++ while (!(gk_uart_readl(UART_LS_REG) & UART_LS_TEMT)); ++ gk_uart_writel(UART_TH_REG, c); ++} ++ ++static inline void flush(void) ++{ ++ unsigned int dump; ++ ++ while (gk_uart_readl(UART_LS_REG) & UART_LS_DR) ++ { ++ dump = gk_uart_readl(UART_RB_REG); ++ } ++} ++ ++static inline void arch_decomp_setup(void) ++{ ++ hal_function_t hal_init = (hal_function_t) (*(volatile u32 *)CONFIG_U2K_HAL_ADDR); ++ g_hw = (struct hw_ops *)hal_init (0, 0, 0x90000000, 0xa0000000, 0); ++} ++ ++ ++#define arch_decomp_wdog() ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif /* __MACH_UNCOMPRESS_H */ +diff --git a/arch/arm/mach-gk710xs/include/mach/vmalloc.h b/arch/arm/mach-gk710xs/include/mach/vmalloc.h +new file mode 100644 +index 00000000..5a0f541f +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/vmalloc.h +@@ -0,0 +1,37 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/vmalloc.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_VMALLOC_H ++#define __MACH_VMALLOC_H ++ ++/* ==========================================================================*/ ++#if defined(CONFIG_VMSPLIT_3G) ++#define VMALLOC_END UL(0xe0000000) ++#else ++#define VMALLOC_END UL(0xb0000000) ++#endif ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++/* ==========================================================================*/ ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/vo_i80.h b/arch/arm/mach-gk710xs/include/mach/vo_i80.h +new file mode 100644 +index 00000000..e4d07221 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/vo_i80.h +@@ -0,0 +1,79 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/vo_i80.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_VO_I80_H ++#define __MACH_V0_I80_H ++ ++#include ++ ++#define VO_I80_BASE (GK_VA_VO) ++#define VO_I80_REG(x) (VO_I80_BASE + (x)) ++ ++#define REG_VO_I80_DATA_FORMAT VO_I80_REG(0xC00) /* read/write */ ++#define REG_VO_I80_PIC_RESOLUTION VO_I80_REG(0xC04) /* read/write */ ++#define REG_VO_I80_PIXEL_RDWRCMD VO_I80_REG(0xC08) /* read/write */ ++#define REG_VO_I80_CMD_FORMAT VO_I80_REG(0xC0C) /* read/write */ ++#define REG_VO_I80_LCD_RST_PARA1 VO_I80_REG(0xC10) /* read/write */ ++#define REG_VO_I80_LCD_RST_PARA2 VO_I80_REG(0xC14) /* read/write */ ++#define REG_VO_I80_DELAY_PARA VO_I80_REG(0xC18) /* read/write */ ++#define REG_VO_I80_TWR_TIMING VO_I80_REG(0xC1C) /* read/write */ ++#define REG_VO_I80_TRD_TIMING VO_I80_REG(0xC20) /* read/write */ ++#define REG_VO_I80_TCS_TIMING VO_I80_REG(0xC24) /* read/write */ ++#define REG_VO_I80_POLAR_CTRL VO_I80_REG(0xC28) /* read/write */ ++#define REG_VO_I80_CTRL VO_I80_REG(0xC2C) /* read/write */ ++#define REG_VO_I80_FRAME_COUNTER VO_I80_REG(0xC30) /* read */ ++#define REG_VO_I80_I80_STATE VO_I80_REG(0xC34) /* read */ ++#define REG_VO_I80_CMD_SRAM_STATE VO_I80_REG(0xC38) /* read/write */ ++#define REG_VO_I80_TCSREF_WT_TIMING VO_I80_REG(0xC3C) /* read/write */ ++#define REG_VO_I80_TCSREF_RD_TIMING VO_I80_REG(0xC40) /* read/write */ ++#define REG_VO_I80_TODH_TIMING VO_I80_REG(0xC44) /* read/write */ ++#define REG_VO_I80_LCD_STATE VO_I80_REG(0xC48) /* read */ ++#define REG_VO_I80_LCD_STATE0 VO_I80_REG(0xC4C) /* read */ ++#define REG_VO_I80_LCD_STATE1 VO_I80_REG(0xC50) /* read */ ++#define REG_VO_I80_LCD_STATE2 VO_I80_REG(0xC54) /* read */ ++#define REG_VO_I80_LCD_STATE3 VO_I80_REG(0xC58) /* read */ ++#define REG_VO_I80_LCD_STATE4 VO_I80_REG(0xC5C) /* read */ ++#define REG_VO_I80_SRAM_CMDPARA VO_I80_REG(0xC80) /* read/write */ ++ ++ ++ ++#define I80_DESIGN_REF_CLK_FREQ 200//MHz GK7101S-->200MHz GK8601-->300MHz ++ ++#define I80_CLK_FREQ 200//MHz GK7101S: FPGA-->100MHz IC-->200MHz ++#define I80_CLK_PERIOD (1000/I80_CLK_FREQ)//FPGA-->10ns/Cycle IC-->5ns/cycle ++ ++#define MAX_RESET_1ST_H_L_MS ( ((1<<11)-1)*I80_DESIGN_REF_CLK_FREQ/(100*I80_CLK_FREQ) )//FPGA-->40ms IC-->20ms ++#define MAX_RESET_2ND_H_MS ( ((1<<11)-1)*I80_DESIGN_REF_CLK_FREQ/(10*I80_CLK_FREQ) ) //FPGA-->409ms IC-->204ms ++#define MAX_DELAY_MS ( ((1<<11)-1)*I80_DESIGN_REF_CLK_FREQ/(10*I80_CLK_FREQ) ) //FPGA-->409ms IC-->204ms ++//#define MAX_TRANS_NS ((1<<9)-1)*I80_CLK_PERIOD //FPGA-->5110ns IC-->2555ns ++//#define MAX_TAS_NS ((1<<6)-1)*I80_CLK_PERIOD //FPGA-->630ns IC-->315ns ++ ++#define TIMING_PARA_CEIL_NS(x) (((x)*I80_CLK_FREQ+999)/1000) ++ ++#define I80_1ST_H_L_COUNTER (10*I80_DESIGN_REF_CLK_FREQ) ++#define I80_2ND_H_COUNTER (100*I80_DESIGN_REF_CLK_FREQ) ++#define I80_HW_DELAY_COUNTER (100*I80_DESIGN_REF_CLK_FREQ) ++ ++#define TIMING_PARA_FIRST_H_CEIL_MS(x) ((1000*I80_CLK_FREQ*(x)+I80_1ST_H_L_COUNTER-1)/I80_1ST_H_L_COUNTER) ++#define TIMING_PARA_FIRST_L_CEIL_MS(x) ((1000*I80_CLK_FREQ*(x)+I80_1ST_H_L_COUNTER-1)/I80_1ST_H_L_COUNTER) ++#define TIMING_PARA_SECOND_H_CEIL_MS(x) ((1000*I80_CLK_FREQ*(x)+I80_2ND_H_COUNTER-1)/I80_2ND_H_COUNTER) ++#define TIMING_PARA_HW_DELAY_CEIL_MS(x) ((1000*I80_CLK_FREQ*(x)+I80_HW_DELAY_COUNTER-1)/I80_HW_DELAY_COUNTER) ++ ++ ++#endif /* __MACH_VO_I80_H */ ++ ++ +diff --git a/arch/arm/mach-gk710xs/include/mach/wdt.h b/arch/arm/mach-gk710xs/include/mach/wdt.h +new file mode 100644 +index 00000000..96be7d71 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/include/mach/wdt.h +@@ -0,0 +1,77 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/include/mach/wdt.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __MACH_WDT_H ++#define __MACH_WDT_H ++ ++/* ==============================================*/ ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++ ++/* On A5S WDT_RST_L_REG can not be cleared. */ ++/* When is more then 0xff. To work around we set */ ++/* WDT_RST_L_REG to 0x0 before WDT start because */ ++/* it is preserved during soft reset, if it's */ ++/* still 0x0 we could know the reset is from WDT */ ++ ++#define RCT_WDT_RESET_VAL 0 ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++ ++#define WDOG_REG(x) (GK_VA_WDT + (x)) ++ ++#define WDOG_STATUS_OFFSET 0x0c ++#define WDOG_RELOAD_OFFSET 0x10 ++#define WDOG_RESTART_OFFSET 0x14 ++#define WDOG_CONTROL_OFFSET 0x00 ++#define WDOG_TIMEOUT_OFFSET 0x04 ++#define WDOG_CLR_TMO_OFFSET 0x08 ++#define WDOG_RST_WD_OFFSET 0x18 ++ ++#define WDOG_STATUS_REG WDOG_REG(WDOG_STATUS_OFFSET) ++#define WDOG_RELOAD_REG WDOG_REG(WDOG_RELOAD_OFFSET) ++#define WDOG_RESTART_REG WDOG_REG(WDOG_RESTART_OFFSET) ++#define WDOG_CONTROL_REG WDOG_REG(WDOG_CONTROL_OFFSET) ++#define WDOG_TIMEOUT_REG WDOG_REG(WDOG_TIMEOUT_OFFSET) ++#define WDOG_CLR_TMO_REG WDOG_REG(WDOG_CLR_TMO_OFFSET) ++#define WDOG_RST_WD_REG WDOG_REG(WDOG_RST_WD_OFFSET) ++ ++/* Bit field definition of watch dog timer control register */ ++#define WDOG_CTR_RST_EN 0x00000004 ++#define WDOG_CTR_INT_EN 0x00000002 ++#define WDOG_CTR_EN 0x00000001 ++ ++/* WDOG_RESTART_REG only works with magic 0x4755. */ ++/* Set this value would transferred the value in */ ++/* WDOG_RELOAD_REG into WDOG_STATUS_REG and would */ ++/* not trigger the underflow event. */ ++#define WDT_RESTART_VAL 0X4755 ++ ++/* ==============================================*/ ++#ifndef __ASSEMBLER__ ++ ++extern struct platform_device gk_wdt; ++ ++#endif /* __ASSEMBLER__ */ ++/* ==============================================*/ ++ ++#endif /* __REGS_WDT_H */ ++ +diff --git a/arch/arm/mach-gk710xs/irq.c b/arch/arm/mach-gk710xs/irq.c +new file mode 100644 +index 00000000..d70f61dc +--- /dev/null ++++ b/arch/arm/mach-gk710xs/irq.c +@@ -0,0 +1,410 @@ ++/* ++ * arch/arm/mach-gk/irq.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#ifdef CONFIG_ARM_VIC ++#include ++#endif ++ ++/** ++ * struct vic_device - VIC PM device ++ * @irq: The IRQ number for the base of the VIC. ++ * @base: The register base for the VIC. ++ * @resume_sources: A bitmask of interrupts for resume. ++ * @resume_irqs: The IRQs enabled for resume. ++ * @int_select: Save for VIC_INT_SELECT. ++ * @int_enable: Save for VIC_INT_ENABLE. ++ * @soft_int: Save for VIC_INT_SOFT. ++ * @protect: Save for VIC_PROTECT. ++ * @domain: The IRQ domain for the VIC. ++ */ ++struct gk_vic_device { ++ void __iomem *base; ++ int irq; ++ u32 resume_sources; ++ u32 resume_irqs; ++ u32 int_select; ++ u32 int_enable; ++ u32 soft_int; ++ u32 protect; ++ struct irq_domain *domain; ++}; ++ ++/* ==========================================================================*/ ++ ++/* we cannot allocate memory when VICs are initially registered */ ++static struct gk_vic_device gk_vic_decs[VIC_INSTANCES]; ++ ++static int gk_vic_id; ++/* ==========================================================================*/ ++ ++/* ==========================================================================*/ ++#define GK_GPIO_IRQ2GIRQ() do { \ ++ girq -= GPIO_IRQ(0); \ ++ } while (0) ++ ++ ++/* ==========================================================================*/ ++#if (VIC_INSTANCES == 1) ++#define GK_VIC_IRQ2BASE() do { \ ++ irq -= VIC1_INT_VEC(0); \ ++ } while (0) ++#elif (VIC_INSTANCES == 2) ++#define GK_VIC_IRQ2BASE() do { \ ++ irq -= VIC1_INT_VEC(0); \ ++ if (irq >= NR_VIC_IRQ_SIZE) { \ ++ irq -= NR_VIC_IRQ_SIZE; \ ++ vic_base = VIC2_BASE; \ ++ } \ ++ } while (0) ++#endif ++ ++static void gk_ack_irq(struct irq_data *d) ++{ ++ u32 vic_base = VIC1_BASE; ++ u32 irq = d->irq; ++ ++ GK_VIC_IRQ2BASE(); ++ ++ gk_irq_writel(vic_base + VIC_EDGE_CLR_OFFSET, 0x1 << irq); ++} ++ ++static void gk_disable_irq(struct irq_data *d) ++{ ++ u32 vic_base = VIC1_BASE; ++ u32 irq = d->irq; ++ ++ GK_VIC_IRQ2BASE(); ++ ++ gk_irq_writel(vic_base + VIC_INTEN_CLR_OFFSET, 0x1 << irq); ++} ++ ++static void gk_enable_irq(struct irq_data *d) ++{ ++ u32 vic_base = VIC1_BASE; ++ u32 irq = d->irq; ++ ++ GK_VIC_IRQ2BASE(); ++ ++ gk_irq_writel(vic_base + VIC_INTEN_OFFSET, 0x1 << irq); ++} ++ ++static void gk_mask_ack_irq(struct irq_data *d) ++{ ++ u32 vic_base = VIC1_BASE; ++ u32 irq = d->irq; ++ ++ GK_VIC_IRQ2BASE(); ++ ++ gk_irq_writel(vic_base + VIC_INTEN_CLR_OFFSET, 0x1 << irq); ++ gk_irq_writel(vic_base + VIC_EDGE_CLR_OFFSET, 0x1 << irq); ++} ++ ++static int gk_irq_set_type(struct irq_data *d, unsigned int type) ++{ ++ u32 vic_base = VIC1_BASE; ++ u32 mask; ++ u32 bit; ++ u32 sense; ++ u32 bothedges; ++ u32 event; ++ struct irq_desc *desc = irq_to_desc(d->irq); ++ u32 irq = d->irq; ++ ++ //printk("%s: irq[%d] type[%d] desc[%p]\n", __func__, irq, type, desc); ++ ++ GK_VIC_IRQ2BASE(); ++ ++ mask = ~(0x1 << irq); ++ bit = (0x1 << irq); ++ sense = gk_irq_readl(vic_base + VIC_SENSE_OFFSET); ++ bothedges = gk_irq_readl(vic_base + VIC_BOTHEDGE_OFFSET); ++ event = gk_irq_readl(vic_base + VIC_EVENT_OFFSET); ++ ++ switch (type) { ++ case IRQ_TYPE_EDGE_RISING: ++ sense &= mask; ++ bothedges &= mask; ++ event |= bit; ++ desc->handle_irq = handle_edge_irq; ++ break; ++ case IRQ_TYPE_EDGE_FALLING: ++ sense &= mask; ++ bothedges &= mask; ++ event &= mask; ++ desc->handle_irq = handle_edge_irq; ++ break; ++ case IRQ_TYPE_EDGE_BOTH: ++ sense &= mask; ++ bothedges |= bit; ++ event &= mask; ++ desc->handle_irq = handle_edge_irq; ++ break; ++ case IRQ_TYPE_LEVEL_HIGH: ++ sense |= bit; ++ bothedges &= mask; ++ event |= bit; ++ desc->handle_irq = handle_level_irq; ++ break; ++ case IRQ_TYPE_LEVEL_LOW: ++ sense |= bit; ++ bothedges &= mask; ++ event &= mask; ++ desc->handle_irq = handle_level_irq; ++ break; ++ default: ++ pr_err("%s: can't set irq type %d for irq 0x%08x@%d\n", ++ __func__, type, vic_base, irq); ++ return -EINVAL; ++ } ++ ++ gk_irq_writel(vic_base + VIC_SENSE_OFFSET, sense); ++ gk_irq_writel(vic_base + VIC_BOTHEDGE_OFFSET, bothedges); ++ gk_irq_writel(vic_base + VIC_EVENT_OFFSET, event); ++ ++ gk_ack_irq(d); ++ ++ return 0; ++} ++ ++static struct irq_chip gk_irq_chip = { ++ .name = "gk irq", ++ .irq_ack = gk_ack_irq, ++ .irq_mask = gk_disable_irq, ++ .irq_unmask = gk_enable_irq, ++ .irq_mask_ack = gk_mask_ack_irq, ++ .irq_set_type = gk_irq_set_type, ++}; ++ ++void gk_swvic_set(u32 irq) ++{ ++ u32 vic_base = VIC1_BASE; ++ ++ GK_VIC_IRQ2BASE(); ++ ++ gk_irq_writel(vic_base + VIC_SOFTEN_OFFSET, 0x1 << irq); ++} ++EXPORT_SYMBOL(gk_swvic_set); ++ ++void gk_swvic_clr(u32 irq) ++{ ++ u32 vic_base = VIC1_BASE; ++ ++ GK_VIC_IRQ2BASE(); ++ ++ gk_irq_writel(vic_base + VIC_SOFTEN_CLR_OFFSET, 0x1 << irq); ++} ++EXPORT_SYMBOL(gk_swvic_clr); ++ ++/* ==========================================================================*/ ++static inline u32 gk_irq_stat2nr(u32 stat) ++{ ++ u32 tmp; ++ u32 nr; ++ ++ __asm__ __volatile__ ++ ("rsbs %[tmp], %[stat], #0" : ++ [tmp] "=r" (tmp) : [stat] "r" (stat)); ++ __asm__ __volatile__ ++ ("and %[nr], %[tmp], %[stat]" : ++ [nr] "=r" (nr) : [tmp] "r" (tmp), [stat] "r" (stat)); ++ __asm__ __volatile__ ++ ("clzcc %[nr], %[nr]" : ++ [nr] "+r" (nr)); ++ __asm__ __volatile__ ++ ("rsc %[nr], %[nr], #32" : ++ [nr] "+r" (nr)); ++ ++ return nr; ++} ++ ++/* ==========================================================================*/ ++ ++u32 vic_base_addr[VIC_INSTANCES] = { ++ VIC1_BASE, ++#if (VIC_INSTANCES >= 2) ++ VIC2_BASE, ++#endif ++#if (VIC_INSTANCES >= 3) ++ VIC3_BASE, ++#endif ++#if (VIC_INSTANCES >= 4) ++ VIC4_BASE, ++#endif ++}; ++ ++#ifndef CONFIG_ARM_VIC ++ ++/** ++ * gk_vic_register() - Register a VIC. ++ * @base: The base address of the VIC. ++ * @irq: The base IRQ for the VIC. ++ * @resume_sources: bitmask of interrupts allowed for resume sources. ++ * @node: The device tree node associated with the VIC. ++ * ++ * Register the VIC with the system device tree so that it can be notified ++ * of suspend and resume requests and ensure that the correct actions are ++ * taken to re-instate the settings on resume. ++ * ++ * This also configures the IRQ domain for the VIC. ++ */ ++static void __init gk_vic_register(void __iomem *base, unsigned int irq, ++ u32 resume_sources, struct device_node *node) ++{ ++ struct gk_vic_device *pVic; ++ ++ if (gk_vic_id >= ARRAY_SIZE(gk_vic_decs)) ++ { ++ printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__); ++ return; ++ } ++ ++ pVic = &gk_vic_decs[gk_vic_id]; ++ pVic->base = base; ++ pVic->resume_sources = resume_sources; ++ pVic->irq = irq; ++ gk_vic_id++; ++ pVic->domain = irq_domain_add_legacy(node, NR_VIC_IRQ_SIZE, irq, 0, ++ &irq_domain_simple_ops, pVic); ++} ++ ++void __init gk_init_vic(u32 num_vic) ++{ ++ int irq, i; ++ ++ printk("gk init vic...\n"); ++ for (i = 0; i < NR_IRQS; i++) ++ { ++ //pr_err("registering irq %d \n", i); ++ irq_set_chip_and_handler(i, &gk_irq_chip, handle_level_irq); ++ set_irq_flags(i, IRQF_VALID); ++ } ++ ++ /* initialize the VICs */ ++ for (irq = 0; irq < num_vic; irq++) ++ { ++ gk_vic_register((void __iomem *)vic_base_addr[irq], (NR_VIC_IRQ_SIZE * irq), 0, NULL); ++ } ++} ++ ++/* ++ * Handle each interrupt in a single VIC. Returns non-zero if we've ++ * handled at least one interrupt. This reads the status register ++ * before handling each interrupt, which is necessary given that ++ * handle_IRQ may briefly re-enable interrupts for soft IRQ handling. ++ */ ++static int gk_handle_one_vic(struct gk_vic_device *vic, struct pt_regs *regs) ++{ ++ u32 stat, irq; ++ int handled = 0; ++ ++ while ((stat = readl_relaxed(vic->base + VIC_IRQ_STA_OFFSET))) { ++ irq = ffs(stat) - 1; ++ handle_IRQ(irq_find_mapping(vic->domain, irq), regs); ++ handled = 1; ++ } ++ ++ return handled; ++} ++ ++/* ++ * Keep iterating over all registered VIC's until there are no pending ++ * interrupts. ++ */ ++asmlinkage void __exception_irq_entry gk_vic_handle_irq(struct pt_regs *regs) ++{ ++ int i, handled; ++ do { ++ for (i = 0, handled = 0; i < gk_vic_id; ++i) ++ handled |= gk_handle_one_vic(&gk_vic_decs[i], regs); ++ } while (handled); ++} ++ ++#else ++ ++void __init gk_init_vic(u32 num_vic) ++{ ++ u32 vic[] = {~0, ~0, ~0}; ++ int irq; ++ ++printk("gk init vic...\n"); ++ /* initialize the VICs */ ++ for (irq = 0; irq < num_vic; irq++) ++ { ++ vic_init(vic_base_addr[irq], (NR_VIC_IRQ_SIZE * irq), vic[irq], 0); ++ } ++} ++ ++#endif ++ ++void __init gk_init_irq(void) ++{ ++ ++#ifndef CONFIG_ARM_VIC ++ printk(">> gk init irq vic1...\n"); ++ /* Set VIC sense and event type for each entry ++ * note: we initialize udc vbus irq type here */ ++ gk_irq_writel(VIC_SENSE_REG, 0x00000000); ++ gk_irq_writel(VIC_BOTHEDGE_REG, 0x00000000); ++ gk_irq_writel(VIC_EVENT_REG, 0x00000000); ++ ++#if (VIC_INSTANCES >= 2) ++ printk(">> gk init irq vic2...\n"); ++ gk_irq_writel(VIC2_SENSE_REG, 0x00000000); ++ gk_irq_writel(VIC2_BOTHEDGE_REG, 0x00000000); ++ gk_irq_writel(VIC2_EVENT_REG, 0x00000000); ++#endif ++ ++ /* Disable all IRQ */ ++ gk_irq_writel(VIC_INT_SEL_REG, 0x00000000); ++ gk_irq_writel(VIC_INTEN_REG, 0x00000000); ++ gk_irq_writel(VIC_INTEN_CLR_REG, 0xffffffff); ++ gk_irq_writel(VIC_EDGE_CLR_REG, 0xffffffff); ++ ++#if (VIC_INSTANCES >= 2) ++ gk_irq_writel(VIC2_INT_SEL_REG, 0x00000000); ++ gk_irq_writel(VIC2_INTEN_REG, 0x00000000); ++ gk_irq_writel(VIC2_INTEN_CLR_REG, 0xffffffff); ++ gk_irq_writel(VIC2_EDGE_CLR_REG, 0xffffffff); ++#endif ++#endif ++ ++ gk_init_vic(VIC_INSTANCES); ++ ++} ++ +diff --git a/arch/arm/mach-gk710xs/mach-gk710xs.c b/arch/arm/mach-gk710xs/mach-gk710xs.c +new file mode 100644 +index 00000000..4e6e9779 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/mach-gk710xs.c +@@ -0,0 +1,1026 @@ ++/* ++ * linux/arch/arm/mach-gk/mach-gk.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * 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 CONFIG_GK_CHIP_INCLUDE_FILE ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++extern struct platform_device gk_fb0; ++extern struct platform_device gk_fb1; ++extern int gk_init_fb(void); ++ ++extern struct platform_device gk_sd0; ++ ++extern struct i2c_board_info gk_board_vi_infos[2]; ++extern struct i2c_board_info gk_board_hdmi_infos[2]; ++ ++//u64 gk_dmamask = DMA_BIT_MASK(32); ++//EXPORT_SYMBOL(gk_dmamask); ++ ++/* ==========================================================================*/ ++ ++#if defined(CONFIG_MTD_SFLASH_GOKE) || defined(CONFIG_MTD_SFLASH_GOKE_MODULE) ++//add: ++//#if defined(CONFIG_MACH_GK7102S_ELEC_SC1135_V1_00) ++//MACHINE_START(GK7102S_ELEC_SC1135_V1_00,"ELEC GK7102S V1 Board") ++//#endif ++ ++ ++#if defined(CONFIG_ONLY_USE_NOR_8M) ++#define GKAPP_MTDBLOCK0_UBOOT_BIN_OFFSET \ ++ (0) ++#define GKAPP_MTDBLOCK0_UBOOT_BIN_SIZE \ ++ (256 * 1024) ++ ++#define GKAPP_MTDBLOCK1_UBOOT_ENV_OFFSET \ ++ (GKAPP_MTDBLOCK0_UBOOT_BIN_OFFSET \ ++ + GKAPP_MTDBLOCK0_UBOOT_BIN_SIZE) ++#define GKAPP_MTDBLOCK1_UBOOT_ENV_SIZE \ ++ (64 * 1024) ++ ++#define GKAPP_MTDBLOCK2_USER_OFFSET \ ++ (GKAPP_MTDBLOCK1_UBOOT_ENV_OFFSET \ ++ + GKAPP_MTDBLOCK1_UBOOT_ENV_SIZE) ++#define GKAPP_MTDBLOCK2_USER_SIZE \ ++ (128 * 1024) ++ ++#define GKAPP_MTDBLOCK3_CUSTOM_OFFSET \ ++ (GKAPP_MTDBLOCK2_USER_OFFSET \ ++ + GKAPP_MTDBLOCK2_USER_SIZE) ++#define GKAPP_MTDBLOCK3_CUSTOM_SIZE \ ++ (512 * 1024) ++ ++#define GKAPP_MTDBLOCK4_KERNEL_OFFSET \ ++ (GKAPP_MTDBLOCK3_CUSTOM_OFFSET \ ++ + GKAPP_MTDBLOCK3_CUSTOM_SIZE) ++#define GKAPP_MTDBLOCK4_KERNEL_SIZE \ ++ ((1024 + 320) * 1024) ++ ++#define GKAPP_MTDBLOCK5_ROOTFS_OFFSET \ ++ (GKAPP_MTDBLOCK4_KERNEL_OFFSET \ ++ + GKAPP_MTDBLOCK4_KERNEL_SIZE) ++#define GKAPP_MTDBLOCK5_ROOTFS_SIZE \ ++ ((4096 + 0) * 1024) ++ ++#define GKAPP_MTDBLOCK6_RESOURCE_OFFSET \ ++ (GKAPP_MTDBLOCK5_ROOTFS_OFFSET \ ++ + GKAPP_MTDBLOCK5_ROOTFS_SIZE) ++#define GKAPP_MTDBLOCK6_RESOURCE_SIZE \ ++ ((1024 + 704 + 64) * 1024) ++ ++// for 8M nor flash ++static struct mtd_partition gk_flash_parts[]= ++{ ++#if 0 ++ [0] = { ++ .name = "uboot", ++ .offset = GKAPP_MTDBLOCK0_UBOOT_BIN_OFFSET, ++ .size = GKAPP_MTDBLOCK0_UBOOT_BIN_SIZE, ++ }, ++ [1] = { ++ .name = "uboot_env", ++ .offset = GKAPP_MTDBLOCK1_UBOOT_ENV_OFFSET, ++ .size = GKAPP_MTDBLOCK1_UBOOT_ENV_SIZE, ++ }, ++ [2] = {/* for usrm of Juan */ ++ .name = "user", ++ .offset = GKAPP_MTDBLOCK2_USER_OFFSET, ++ .size = GKAPP_MTDBLOCK2_USER_SIZE, ++ }, ++ [3] = {/* mount custom.jffs2 /media/conf */ ++ .name = "conf", ++ .offset = GKAPP_MTDBLOCK3_CUSTOM_OFFSET, ++ .size = GKAPP_MTDBLOCK3_CUSTOM_SIZE, ++ }, ++ [4] = { ++ .name = "kernel", ++ .offset = GKAPP_MTDBLOCK4_KERNEL_OFFSET, ++ .size = GKAPP_MTDBLOCK4_KERNEL_SIZE, ++ }, ++ [5] = {/* ro squashfs rootfs */ ++ .name = "rootfs", ++ .offset = GKAPP_MTDBLOCK5_ROOTFS_OFFSET, ++ .size = GKAPP_MTDBLOCK5_ROOTFS_SIZE, ++ }, ++ [6] = {/* mount font&web squashfs to /media/custom */ ++ .name = "resource", ++ .offset = GKAPP_MTDBLOCK6_RESOURCE_OFFSET, ++ .size = GKAPP_MTDBLOCK6_RESOURCE_SIZE, ++ }, ++#else ++#if 1//defined(CONFIG_MACH_GK7102_HZD_OJTV_v10_JXH42) || defined(CONFIG_MACH_GK_HZD_OJTV_v10_OV2710) ++ //256K ++ [0] = { ++ .name = "uboot", ++ .offset = 0x00000000, ++ .size = 0x00040000, ++ }, ++ //64K ++ [1] = { ++ .name = "ubootenv", ++ .offset = 0x00040000, ++ .size = 0x00010000, ++ }, ++ //128k ++ [2] = { ++ .name = "user", ++ .offset = 0x00050000, ++ .size = 0x00020000, ++ }, ++ //448k ++ [3] = { ++ .name = "config", ++ .offset = 0x00070000, ++ .size = 0x00070000, ++ }, ++ //1344k ++ [4] = { ++ .name = "kernel", ++ .offset = 0x000e0000, ++ .size = 0x001A0000, ++ }, ++ //4M ++ [5] = { ++ .name = "rootfs", ++ .offset = 0x00280000, ++ .size = 0x003b0000, ++ }, ++ //1856k ++ [6] = { ++ .name = "resource", ++ .offset = 0x00630000, ++ .size = 0x001d0000, ++ }, ++ //ALL 0--8M ++ [7] = { ++ .name = "all", ++ .offset = 0x00000000, ++ .size = 0x00800000, ++ }, ++#else ++ //256K ++ [0] = { ++ .name = "uboot", ++ .offset = 0x00000000, ++ .size = 0x00040000, ++ }, ++ //64K ++ [1] = { ++ .name = "ubootenv", ++ .offset = 0x00040000, ++ .size = 0x00010000, ++ }, ++ //128k ++ [2] = { ++ .name = "user", ++ .offset = 0x00050000, ++ .size = 0x00020000, ++ }, ++ //448k ++ [3] = { ++ .name = "config", ++ .offset = 0x00070000, ++ .size = 0x00070000, ++ }, ++ //1344k ++ [4] = { ++ .name = "kernel", ++ .offset = 0x000e0000, ++ .size = 0x00150000, ++ }, ++ //4M ++ [5] = { ++ .name = "rootfs", ++ .offset = 0x00230000, ++ .size = 0x00400000, ++ }, ++ //1856k ++ [6] = { ++ .name = "resource", ++ .offset = 0x00630000, ++ .size = 0x001d0000, ++ }, ++ //ALL 0--8M ++ [7] = { ++ .name = "all", ++ .offset = 0x00000000, ++ .size = 0x00800000, ++ }, ++ #endif ++#endif ++}; ++#elif defined(CONFIG_ONLY_USE_NOR_16M) ++// for 16M nor flash ++static struct mtd_partition gk_flash_parts[]= ++{ ++ //256K ++ [0] = { ++ .name = "uboot", ++ .offset = 0x00000000, ++ .size = 0x00040000, ++ }, ++ //64K ++ [1] = { ++ .name = "ubootenv", ++ .offset = 0x00040000, ++ .size = 0x00010000, ++ }, ++ // 2M ++ [2] = { ++ .name = "kernel", ++ .offset = 0x00050000, ++ .size = 0x00200000, ++ }, ++ //13M + 512K ++ [3] = { ++ .name = "rootfs", ++ .offset = 0x00250000, ++ .size = 0x00DB0000, ++ }, ++ ++}; ++#elif defined(CONFIG_ONLY_USE_NOR_32M) ++// for 32M nor flash ++static struct mtd_partition gk_flash_parts[]= ++{ ++ //256K ++ [0] = { ++ .name = "uboot", ++ .offset = 0x00000000, ++ .size = 0x00040000, ++ }, ++ //64K ++ [1] = { ++ .name = "ubootenv", ++ .offset = 0x00040000, ++ .size = 0x00010000, ++ }, ++ //768K ++ [2] = { ++ .name = "config", ++ .offset = 0x00050000, ++ .size = 0x000c0000, ++ }, ++ // 2.5M ++ [3] = { ++ .name = "kernel", ++ .offset = 0x00110000, ++ .size = 0x00280000, ++ }, ++ //27M ++ [4] = { ++ .name = "rootfs", ++ .offset = 0x00390000, ++ .size = 0x01b00000, ++ }, ++ // 1.5M ++ [5] = { ++ .name = "resource", ++ .offset = 0x01e90000, ++ .size = 0x00170000, ++ }, ++}; ++#elif defined(CONFIG_USE_NOR_AND_NAND) ++// for 8M nor flash ++static struct mtd_partition gk_flash_parts[]= ++{ ++ //192K ++ [0] = { ++ .name = "uboot", ++ .offset = 0x00000000, ++ .size = 0x00040000, ++ }, ++ //64K ++ [1] = { ++ .name = "ubootenv", ++ .offset = 0x00040000, ++ .size = 0x00010000, ++ }, ++ //512K ++ [2] = { ++ .name = "config", ++ .offset = 0x00050000, ++ .size = 0x00080000, ++ }, ++ // 1.25M ++ [3] = { ++ .name = "kernel", ++ .offset = 0x000D0000, ++ .size = 0x00140000, ++ }, ++ //5M ++ [4] = { ++ .name = "rootfs", ++ .offset = 0x00210000, ++ .size = 0x00500000, ++ }, ++ // 1M ++ [5] = { ++ .name = "resource", ++ .offset = 0x00710000, ++ .size = 0x000E0000, ++ }, ++}; ++#elif defined(CONFIG_ONLY_USE_NAND) ++// for 8M nor flash ++static struct mtd_partition gk_flash_parts[]= ++{ ++ //192K ++ [0] = { ++ .name = "uboot", ++ .offset = 0x00000000, ++ .size = 0x00040000, ++ }, ++ //64K ++ [1] = { ++ .name = "ubootenv", ++ .offset = 0x00040000, ++ .size = 0x00010000, ++ }, ++ //512K ++ [2] = { ++ .name = "config", ++ .offset = 0x00050000, ++ .size = 0x00080000, ++ }, ++ // 1.25M ++ [3] = { ++ .name = "kernel", ++ .offset = 0x000D0000, ++ .size = 0x00140000, ++ }, ++ //5M ++ [4] = { ++ .name = "rootfs", ++ .offset = 0x00210000, ++ .size = 0x00500000, ++ }, ++ // 1M ++ [5] = { ++ .name = "resource", ++ .offset = 0x00710000, ++ .size = 0x000E0000, ++ }, ++}; ++#else ++ ++#endif ++ ++static struct sflash_platform_data flash_platform_data = ++{ ++ .speed_mode = (uint32_t)SYSTEM_SFLASH_FREQ, ++ .channel = 0, ++ .nr_parts = ARRAY_SIZE(gk_flash_parts), ++ .parts = gk_flash_parts, ++}; ++ ++static struct platform_device gk_flash_device0 = ++{ ++ .name = "gk_flash", ++ .id = 0, ++ .dev = ++ { ++ .platform_data = &flash_platform_data, ++ }, ++}; ++#endif/*defined(CONFIG_MTD_GK_SFLASH) || defined(CONFIG_MTD_GK_SFLASH_MODULE)*/ ++ ++/* ================ Watch Dog Timer ======================*/ ++#ifdef CONFIG_WATCHDOG_GOKE ++static struct resource gk_wdt_resource[] = { ++ [0] = DEFINE_RES_MEM(GK_VA_WDT, SZ_4K), ++ [1] = DEFINE_RES_IRQ(WDT_IRQ), ++}; ++ ++struct platform_device gk_wdt = { ++ .name = "gk-wdt", ++ .id = -1, ++ .resource = gk_wdt_resource, ++ .num_resources = ARRAY_SIZE(gk_wdt_resource), ++ .dev = { ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++#endif /* CONFIG_WATCHDOG_GOKE */ ++/* ================= End ======================*/ ++ ++/* ================ Inter Integrated Circuit ===================*/ ++ ++#ifdef CONFIG_I2C_GOKE ++static struct resource gk_idc_resources[] = { ++ [0] = DEFINE_RES_MEM(GK_VA_IDC, SZ_4K), ++ [1] = DEFINE_RES_IRQ(IDC_IRQ), ++}; ++ ++struct gk_platform_i2c gk_idc_platform_info = { ++ .clk_limit = 400000, ++ .bulk_write_num = 60, ++ .get_clock = get_apb_bus_freq_hz, ++}; ++IDC_PARAM_CALL(0, gk_idc_platform_info, 0644); ++ ++struct platform_device gk_idc = { ++ .name = "i2c", ++ .id = 0, ++ .resource = gk_idc_resources, ++ .num_resources = ARRAY_SIZE(gk_idc_resources), ++ .dev = { ++ .platform_data = &gk_idc_platform_info, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++ ++#if (IDC_INSTANCES >= 2) ++static struct resource gk_idc_hdmi_resources[] = { ++ [0] = DEFINE_RES_MEM(GK_VA_IDC2, SZ_4K), ++ [1] = DEFINE_RES_IRQ(IDC_HDMI_IRQ), ++}; ++ ++struct gk_platform_i2c gk_idc_hdmi_platform_info = { ++ .clk_limit = 400000, ++ .bulk_write_num = 60, ++ .i2c_class = I2C_CLASS_DDC, ++ .get_clock = get_apb_bus_freq_hz, ++}; ++IDC_PARAM_CALL(1, gk_idc_hdmi_platform_info, 0644); ++ ++struct platform_device gk_idc_hdmi = { ++ .name = "i2c", ++ .id = 1, ++ .resource = gk_idc_hdmi_resources, ++ .num_resources = ARRAY_SIZE(gk_idc_hdmi_resources), ++ .dev = { ++ .platform_data = &gk_idc_hdmi_platform_info, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++#endif ++#endif ++ ++#ifdef CONFIG_SPI_GOKE ++/* ==========================================================================*/ ++void gk_spi_cs_activate(struct gk_spi_cs_config *cs_config) ++{ ++ u8 cs_pin; ++ ++ if (cs_config->bus_id >= SPI_MASTER_INSTANCES || ++ cs_config->cs_id >= cs_config->cs_num) ++ return; ++ cs_pin = cs_config->cs_pins[cs_config->cs_id]; ++ gk_gpio_set_out(cs_pin, 0); ++} ++ ++void gk_spi_cs_deactivate(struct gk_spi_cs_config *cs_config) ++{ ++ u8 cs_pin; ++ ++ if (cs_config->bus_id >= SPI_MASTER_INSTANCES || ++ cs_config->cs_id >= cs_config->cs_num) ++ return; ++ ++ cs_pin = cs_config->cs_pins[cs_config->cs_id]; ++ gk_gpio_set_out(cs_pin, 1); ++} ++ ++struct resource gk_spi0_resources[] = { ++ [0] = { ++ .start = GK_VA_SSI1, ++ .end = GK_VA_SSI1 + 0x0FFF, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = SSI_IRQ, ++ .end = SSI_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++int gk_spi0_cs_pins[] = {-1, -1, -1, -1, -1, -1, -1, -1}; ++GK_SPI_PARAM_CALL(0, gk_spi0_cs_pins, 0644); ++struct gk_spi_platform_info gk_spi0_platform_info = { ++ .support_dma = 0, ++#if (SPI_MASTER_INSTANCES == 5 ) ++ .fifo_entries = 64, ++#else ++ .fifo_entries = 16, ++#endif ++ .cs_num = ARRAY_SIZE(gk_spi0_cs_pins), ++ .cs_pins = gk_spi0_cs_pins, ++ .cs_activate = gk_spi_cs_activate, ++ .cs_deactivate = gk_spi_cs_deactivate, ++// .rct_set_ssi_pll = rct_set_ssi_pll, ++ .get_ssi_freq_hz = get_ssi0_freq_hz, ++}; ++ ++struct platform_device gk_spi0 = { ++ .name = "spi", ++ .id = 0, ++ .resource = gk_spi0_resources, ++ .num_resources = ARRAY_SIZE(gk_spi0_resources), ++ .dev = { ++ .platform_data = &gk_spi0_platform_info, ++ //.dma_mask = &gk_dmamask, ++ //.coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++ ++#if (SPI_MASTER_INSTANCES >= 2 ) ++struct resource gk_spi1_resources[] = { ++ [0] = { ++ .start = GK_VA_SSI2, ++ .end = GK_VA_SSI2 + 0x0FFF, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = SSI2_IRQ, ++ .end = SSI2_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++int gk_spi1_cs_pins[] = {-1, -1, -1, -1, -1, -1, -1, -1}; ++GK_SPI_PARAM_CALL(1, gk_spi1_cs_pins, 0644); ++struct gk_spi_platform_info gk_spi1_platform_info = { ++ .support_dma = 0, ++ .fifo_entries = 16, ++ .cs_num = ARRAY_SIZE(gk_spi1_cs_pins), ++ .cs_pins = gk_spi1_cs_pins, ++ .cs_activate = gk_spi_cs_activate, ++ .cs_deactivate = gk_spi_cs_deactivate, ++ .get_ssi_freq_hz = get_ssi1_freq_hz, ++}; ++ ++struct platform_device gk_spi1 = { ++ .name = "spi", ++ .id = 1, ++ .resource = gk_spi1_resources, ++ .num_resources = ARRAY_SIZE(gk_spi1_resources), ++ .dev = { ++ .platform_data = &gk_spi1_platform_info, ++ //.dma_mask = &gk_dmamask, ++ //.coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++#endif ++#endif ++static struct spi_board_info gk_spi_devices[] = { ++ { ++#ifdef CONFIG_MMC_SPI ++ .modalias = "mmc_spi", ++ .max_speed_hz = 69000000/4, /* max spi clock (SCK) speed in HZ */ ++ .bus_num = 0, ++ .mode = SPI_MODE_3, ++ //.platform_data = &bfin_mmc_spi_pdata, ++ //.controller_data = &mmc_spi_chip_info, ++#else ++ .modalias = "spidev", ++#endif ++ .bus_num = 0, ++ .chip_select = 0, ++ }, ++#if (SPI_INSTANCES >= 2) ++ { ++ .modalias = "spidev", ++ .bus_num = 1, ++ .chip_select = 0, ++ } ++#endif ++}; ++ ++/* ================= rtc ======================*/ ++struct platform_device gk_rtc = { ++ .name = "gk-rtc", ++ .id = -1, ++}; ++/* ================= End ======================*/ ++ ++/* ================= ir ======================*/ ++ ++struct gk_ir_controller gk_platform_ir_controller0 = { ++ ++ .protocol = GK_IR_PROTOCOL_NEC, ++ .debug = 0, ++}; ++GK_IR_PARAM_CALL(gk_platform_ir_controller0, 0644); ++ ++struct platform_device gk_ir = { ++ .name = "ir", ++ .id = 1, ++ .dev = { ++ .platform_data = &gk_platform_ir_controller0, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++ ++ ++/* ================= pcm/i2s ======================*/ ++ ++struct platform_device gk_pcm0 = { ++ .name = "gk-pcm-audio", ++ .id = -1, ++}; ++ ++static struct resource gk_i2s0_resources[] = { ++ [0] = { ++ .start = I2S_BASE, ++ .end = I2S_BASE + 0x0FFF, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = I2STX_IRQ, ++ .end = I2SRX_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct gk_i2s_controller gk_i2s_controller0 = { ++ .aucodec_digitalio_0 = NULL, ++ .aucodec_digitalio_1 = NULL, ++ .aucodec_digitalio_2 = NULL, ++ .channel_select = NULL, ++ .set_audio_pll = NULL, ++}; ++ ++ ++struct platform_device gk_i2s0 = { ++ .name = "gk-i2s", ++ .id = 0, ++ .resource = gk_i2s0_resources, ++ .num_resources = ARRAY_SIZE(gk_i2s0_resources), ++ .dev = { ++ .platform_data = &gk_i2s_controller0, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++/* ================= musb ====================*/ ++static struct musb_hdrc_config gk_musb_config = { ++ .multipoint = 1, ++ .dyn_fifo = 0, ++ .big_endian = 0, ++ .dma = 0, ++ .num_eps = 8, ++ .ram_bits = 12, ++}; ++ ++static struct musb_hdrc_platform_data gk_musb_data = { ++#if defined(CONFIG_GK_USB_HOST_MODE) ++ .mode = MUSB_HOST, ++#elif defined(CONFIG_GK_USB_SLAVE_MODE) ++ .mode = MUSB_PERIPHERAL, ++#elif defined(CONFIG_GK_USB_OTG_MODE) ++ .mode = MUSB_HOST, ++#endif ++ .min_power = 25, /* x2 = 50 mA drawn from VBUS as peripheral */ ++ .config = &gk_musb_config, ++}; ++ ++static struct resource gk_musb_resources[] = { ++ /* Order is significant! The start/end fields ++ * are updated during setup.. ++ */ ++ [0] = { ++ .start = GK_VA_USB, ++ .end = GK_VA_USB + 0x2000, ++ .flags = IORESOURCE_MEM, ++ }, ++/* ++ [1] = { ++ .start = GK_VA_USB_PHY, ++ .end = GK_VA_USB_PHY + 0xa00, ++ .flags = IORESOURCE_MEM, ++ }, ++*/ ++ [1] = { ++ .start = USBC_IRQ, ++ .end = USBC_IRQ, ++ .flags = IORESOURCE_IRQ, ++ .name = "mc", ++ }, ++}; ++ ++ ++static struct platform_device gk_musb = { ++ .name = "musb-gk", ++ .id = -1, ++ .dev = { ++ .platform_data = &gk_musb_data, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ }, ++ .num_resources = ARRAY_SIZE(gk_musb_resources), ++ .resource = gk_musb_resources, ++}; ++ ++ ++/* ================= End ======================*/ ++unsigned int gk_aud_get_dma_offset(void) ++{ ++ return AUDIO_DMA_REG_OFFSET; ++} ++EXPORT_SYMBOL(gk_aud_get_dma_offset); ++ ++ ++static struct platform_device *gk_devices[] __initdata = { ++ ++#ifdef CONFIG_MMC_GOKE ++#ifndef CONFIG_PHY_USE_SD_CLK ++ &gk_sd0, ++#ifdef CONFIG_GK710XS_SDIO2 ++ &gk_sd1, ++#endif ++#endif ++#endif ++#ifdef CONFIG_WATCHDOG_GOKE ++ &gk_wdt, ++#endif ++#ifdef CONFIG_I2C_GOKE ++ &gk_idc, ++#if (IDC_INSTANCES >= 2) ++ &gk_idc_hdmi, ++#endif ++#endif ++ ++#ifdef CONFIG_FB_GOKE ++ &gk_fb0, ++ &gk_fb1, ++#endif ++#ifdef CONFIG_SPI_GOKE ++ &gk_spi0, ++#if (SPI_MASTER_INSTANCES >= 2 ) ++ &gk_spi1, ++#endif ++#endif ++#ifdef CONFIG_RTC_DRV_GOKE ++ &gk_rtc, ++#endif ++#ifdef CONFIG_INPUT_GOKE_IR ++ &gk_ir, ++#endif ++ ++#ifdef CONFIG_ETH_GOKE ++ &gk_eth0, ++#endif ++ //&gk_pcm0, ++ //&gk_i2s0, ++ &gk_musb, ++}; ++ ++//louis add ++/* ==========================================================================*/ ++ ++unsigned int gk_debug_level = GK_DEBUG_MEDIA | GK_DEBUG_DSP | GK_DEBUG_VI | GK_DEBUG_VO | GK_DEBUG_AAA; ++EXPORT_SYMBOL(gk_debug_level); ++ ++unsigned int gk_debug_info = 0; ++EXPORT_SYMBOL(gk_debug_info); ++ ++unsigned int gk_boot_splash_logo = 0; ++EXPORT_SYMBOL(gk_boot_splash_logo); ++ ++unsigned long gk_debug_lookup_name(const char *name) ++{ ++ return module_kallsyms_lookup_name(name); ++} ++EXPORT_SYMBOL(gk_debug_lookup_name); ++//end ++ ++void sensor_init(u8 active_level) ++{ ++ struct gk_gpio_io_info sensor_reset; ++ sensor_reset.gpio_id = gk_all_gpio_cfg.sensor_reset; ++ sensor_reset.active_level = active_level; ++ sensor_reset.active_delay = 1; ++ ++ printk("sensor board reset...\n"); ++ gk_set_gpio_output(&sensor_reset, 1); ++ mdelay(50);//100ms ++ gk_set_gpio_output(&sensor_reset, 0); ++ mdelay(200);//100ms ++} ++EXPORT_SYMBOL(sensor_init); ++ ++void sensor_power(u8 power) ++{ ++} ++EXPORT_SYMBOL(sensor_power); ++ ++/* ==========================================================================*/ ++static u8 cmdline_mac[6]; ++static int __init init_setup_mac(char *str) ++{ ++ int count, i, val; ++ ++ for (count = 0; count < 6 && *str; count++, str += 3) { ++ if (!isxdigit(str[0]) || !isxdigit(str[1])) ++ return 0; ++ if (str[2] != ((count < 5) ? ':' : '\0')) ++ return 0; ++ ++ for (i = 0, val = 0; i < 2; i++) { ++ val = val << 4; ++ val |= isdigit(str[i]) ? ++ str[i] - '0' : toupper(str[i]) - 'A' + 10; ++ } ++ cmdline_mac[count] = val; ++ } ++ return 1; ++ ++} ++__setup("mac=", init_setup_mac); ++ ++u8 cmdline_phytype; ++static int __init init_setup_phytype(char *str) ++{ ++ if (!isxdigit(str[0])) ++ return 0; ++ ++ cmdline_phytype = str[0] - '0'; ++ return 1; ++} ++__setup("phytype=", init_setup_phytype); ++EXPORT_SYMBOL(cmdline_phytype); ++ ++int __init gk_init_board(char *board_name) ++{ ++#ifdef CONFIG_ETH_GOKE ++ unsigned char mac_addr[6] = {00,0x11,0x22,0xa3,0xa0,00}; ++#endif ++ int retval = 0; ++ ++ //pr_info("Goke %s:\n", board_name); ++ //pr_info("\tboard revision:\t\t%d\n", 1); ++ ++ //retval = gk_init_pll(); ++ //BUG_ON(retval != 0); ++ // ++#if 1 //wangbin add for gk7101s ++// gk_writel(0xf3170208,0x24);//RGB i80 CVBS ++// gk_writel(0xf3170208,0x20);//BT1120 ++#endif ++ printk("init timer...\n"); ++ retval = gk_init_timer(); ++ BUG_ON(retval != 0); ++ ++ printk("init gpio...\n"); ++ retval = gk_init_gpio(); ++ BUG_ON(retval != 0); ++ ++ gk_set_sd_detect_pin(gk_all_gpio_cfg.sd_detect); ++#ifdef CONFIG_GK710XS_SDIO2 ++ gk_set_sd1_detect_pin(gk_all_gpio_cfg.sd1_detect); ++#endif ++#ifdef CONFIG_SPI_GOKE ++ gk_spi0_cs_pins[0] = gk_all_gpio_cfg.spi0_en0; ++#if (SPI_MASTER_INSTANCES >= 2 ) ++ gk_spi1_cs_pins[0] = gk_all_gpio_cfg.spi1_en0; ++#endif ++#endif ++ ++ ++#ifdef CONFIG_ETH_GOKE ++ gk_set_phy_reset_pin(gk_all_gpio_cfg.phy_reset); ++ #if (ETH_INSTANCES >= 1) ++ if (cmdline_mac[0]) ++ memcpy(mac_addr, cmdline_mac, 6); ++ mac_addr[0] &= 0xfe; /* clear multicast bit */ ++ mac_addr[0] |= 0x02; /* set local assignment bit (IEEE802) */ ++ retval = gk_init_eth0(mac_addr); ++ BUG_ON(retval != 0); ++ #endif ++#endif ++ ++ retval = gk_init_dma(); ++ BUG_ON(retval != 0); ++ ++ //config video DAC for CVBS ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x00, 0x01); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x04, 0x01); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x08, 0x00); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x10, 0x01); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x14, 0x01); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x18, 0x3F); ++ ++ gk_init_sd(); ++ ++#ifdef CONFIG_PMU_ALWAYS_RUNNING ++ // get pmu controller ++ gk_gpio_func_config(gk_all_gpio_cfg.pmu_ctl, GPIO_TYPE_OUTPUT_1); ++ msleep(1); ++ gk_gpio_func_config(gk_all_gpio_cfg.pmu_ctl, GPIO_TYPE_OUTPUT_0); ++ msleep(1); ++ gk_load_51mcu_code(PMU_ALWAYS_RUNNING); ++#endif ++ return retval; ++ ++} ++ ++static void __init gk_init_machine(void) ++{ ++ int i; ++ ++ //clkdev_init(); ++ gk_init_board("GK_chip"); ++ ++#if defined(CONFIG_MTD_SFLASH_GOKE) || defined(CONFIG_MTD_SFLASH_GOKE_MODULE) ++ platform_device_register(&gk_flash_device0); ++#endif ++ ++ gk_create_proc_dir(); ++ ++#ifdef CONFIG_FB_GOKE ++ gk_init_fb(); ++#endif ++ ++ printk("gk register devices %d\n", ARRAY_SIZE(gk_devices)); ++ ++ /* Register devices */ ++ platform_add_devices(gk_devices, ARRAY_SIZE(gk_devices)); ++ for (i = 0; i < ARRAY_SIZE(gk_devices); i++) { ++ device_set_wakeup_capable(&gk_devices[i]->dev, 1); ++ device_set_wakeup_enable(&gk_devices[i]->dev, 0); ++ } ++ ++ printk("gk register I2C\n"); ++ //i2c_register_board_info(0, &gk_ak4642_board_info, 1); ++ i2c_register_board_info(0, gk_board_vi_infos, ARRAY_SIZE(gk_board_vi_infos)); ++ i2c_register_board_info(1, gk_board_hdmi_infos, ARRAY_SIZE(gk_board_hdmi_infos)); ++ ++ spi_register_board_info(gk_spi_devices, ++ ARRAY_SIZE(gk_spi_devices)); ++ ++ pm_power_off = gk_power_off; ++ ++} ++ ++MACHINE_START(GOKE_IPC, "Goke IPC Board") ++ .map_io = gk_map_io, ++ .init_irq = gk_init_irq, ++ .handle_irq = gk_vic_handle_irq, ++ .timer = &gk_sys_timer, ++ .init_machine = gk_init_machine, ++ .restart = gk_restart, ++MACHINE_END ++ ++ +diff --git a/arch/arm/mach-gk710xs/mdma.c b/arch/arm/mach-gk710xs/mdma.c +new file mode 100644 +index 00000000..62964dd4 +--- /dev/null ++++ b/arch/arm/mach-gk710xs/mdma.c +@@ -0,0 +1,238 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk710xs/mdma.c ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#define TRANSFER_2D_WIDTH (1<<12) /* 4096*/ ++#define MAX_TRANSFER_2D_HEIGHT (1<<11) /* 2048*/ ++#define MAX_TRANSFER_SIZE_2D_UNIT (TRANSFER_2D_WIDTH * MAX_TRANSFER_2D_HEIGHT) /* 8MB*/ ++ ++#define TRANSFER_1D_WIDTH TRANSFER_2D_WIDTH ++#define MAX_TRANSFER_SIZE_1D_UNIT TRANSFER_1D_WIDTH ++ ++/* transfer 6 big blocks (although maximum is 8), because we may do another 1 small block and 1 line. total 8 Ops */ ++#define MAX_TRANSFER_SIZE_ONCE (MAX_TRANSFER_SIZE_2D_UNIT * 6) /* 48 MB*/ ++ ++#define MAX_OPS 8 ++ ++ ++static struct completion transfer_completion; ++ ++ ++/* handle 8MB at one time */ ++static inline int transfer_big_unit(u8 *dest_addr, u8 *src_addr, u32 size) ++{ ++ int row_count; ++ if (size > MAX_TRANSFER_SIZE_2D_UNIT) { ++ printk("transfer_unit size %d bigger than %d \n", ++ size, MAX_TRANSFER_SIZE_2D_UNIT); ++ return -1; ++ } ++ ++ row_count = size / TRANSFER_2D_WIDTH; ++ ++ /* copy rows by 2D copy */ ++ if (row_count > 0) { ++ gk_dsp_writel(MDMA_SRC_1_BASE_REG, (long)src_addr); ++ gk_dsp_writel(MDMA_SRC_1_PITCH_REG, TRANSFER_2D_WIDTH); ++ gk_dsp_writel(MDMA_DST_BASE_REG, (long)dest_addr); ++ gk_dsp_writel(MDMA_DST_PITCH_REG, TRANSFER_2D_WIDTH); ++ gk_dsp_writel(MDMA_WIDTH_REG, TRANSFER_2D_WIDTH - 1); ++ gk_dsp_writel(MDMA_HEIGHT_REG, row_count - 1); ++ ++ /* start 2D copy */ ++ gk_dsp_writel(MDMA_OPCODE_REG, 1); ++ } ++ return 0; ++ ++} ++ ++ ++/* use 1D copy to copy max 4KB each time */ ++static inline int transfer_small_unit(u8 *dest_addr, u8 *src_addr, u32 size) ++{ ++ ++ if (size > TRANSFER_1D_WIDTH) { ++ printk("transfer_unit size %d bigger than %d \n", ++ size, TRANSFER_1D_WIDTH); ++ return -1; ++ } ++ ++ /* linear copy */ ++ gk_dsp_writel(MDMA_SRC_1_BASE_REG, (long)src_addr); ++ gk_dsp_writel(MDMA_DST_BASE_REG, (long)dest_addr); ++ gk_dsp_writel(MDMA_WIDTH_REG, TRANSFER_1D_WIDTH - 1); ++ ++ /* start linear copy */ ++ gk_dsp_writel(MDMA_OPCODE_REG, 0); ++ ++ return 0; ++} ++ ++ ++ ++/* this is async function, just fill dma registers and let it run*/ ++static inline int transfer_once(u8 *dest_addr, u8 *src_addr, u32 size) ++{ ++ //total pending count must be no bigger than 8 ++ int big_count; ++ int rows_count; ++ int i; ++ u32 transferred_bytes = 0; ++ int remain_bytes ; ++ ++ if (size > MAX_TRANSFER_SIZE_ONCE) { ++ printk(" size too big %d for transfer once \n", size); ++ return -1; ++ } ++ ++ big_count = size/MAX_TRANSFER_SIZE_2D_UNIT; ++ //big pages (each is 8MB) ++ for (i = big_count ; i > 0; i--) { ++ transfer_big_unit(dest_addr + transferred_bytes, ++ src_addr + transferred_bytes, ++ MAX_TRANSFER_SIZE_2D_UNIT); ++ transferred_bytes += MAX_TRANSFER_SIZE_2D_UNIT; ++ } ++ remain_bytes = size - transferred_bytes; ++ ++ ++ //transfer rows (align to TRANSFER_2D_WIDTH) ++ rows_count = remain_bytes / TRANSFER_2D_WIDTH; ++ if (rows_count > 0) { ++ transfer_big_unit(dest_addr + transferred_bytes, ++ src_addr + transferred_bytes, ++ TRANSFER_2D_WIDTH * rows_count); ++ transferred_bytes += TRANSFER_2D_WIDTH * rows_count; ++ remain_bytes = size - transferred_bytes; ++ } ++ ++ if (remain_bytes > 0) { ++ transfer_small_unit(dest_addr + transferred_bytes, ++ src_addr + transferred_bytes, remain_bytes); ++ } ++ ++ return 0; ++} ++ ++/* this is synchronous function, will wait till transfer finishes */ ++int dma_memcpy(u8 *dest_addr, u8 *src_addr, u32 size) ++{ ++ int remain_size = size; ++ int transferred_size = 0; ++ int current_transfer_size; ++ ++ while (remain_size > 0) { ++ if (remain_size > MAX_TRANSFER_SIZE_ONCE) { ++ remain_size -= MAX_TRANSFER_SIZE_ONCE; ++ current_transfer_size = MAX_TRANSFER_SIZE_ONCE; ++ } else { ++ current_transfer_size = remain_size; ++ remain_size = 0; ++ } ++ ++ transfer_once(dest_addr + transferred_size, ++ src_addr + transferred_size, current_transfer_size); ++ wait_for_completion(&transfer_completion); ++ transferred_size += current_transfer_size; ++ } ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(dma_memcpy); ++ ++ ++static irqreturn_t mdma_interrupt(int irq, void *dev_id) ++{ ++ int pending_ops; ++ pending_ops = gk_dsp_readl(MDMA_PENDING_OPS_REG); ++ ++ if (pending_ops == 0) { ++ /* if no following transfer */ ++ complete(&transfer_completion); ++ } else { ++ ++ } ++ return IRQ_HANDLED; ++} ++ ++ ++static int hw_init(void) ++{ ++ int errorCode; ++ /* request irq, no device id, no irq sharing */ ++ errorCode = request_irq(MDMA_IRQ, mdma_interrupt, IRQF_TRIGGER_RISING, "mdma", 0); ++ ++ if (errorCode) { ++ printk("mdma irq request failed \n"); ++ return -1; ++ } ++ printk("mdma request irq: %d \n", MDMA_IRQ); ++ ++ return 0; ++} ++ ++ ++/* wait till transmit completes */ ++static void wait_transmit_complete(void) ++{ ++ int pending_ops; ++ pending_ops = gk_dsp_readl(MDMA_PENDING_OPS_REG); ++ ++ while(pending_ops!= 0) { ++ mdelay(10); ++ } ++} ++ ++static int __init mdma_init(void) ++{ ++ printk("mdma init...\n"); ++ ++ /* hardware and irq init */ ++ if (hw_init() != 0) ++ return -1; ++ /* init completion */ ++ init_completion(&transfer_completion); ++ ++ return 0; ++} ++ ++ ++static void __exit mdma_exit(void) ++{ ++ wait_transmit_complete(); ++} ++ ++MODULE_AUTHOR("Louis "); ++MODULE_DESCRIPTION("MDMA driver on gk"); ++MODULE_LICENSE("GPL v2"); ++MODULE_VERSION("1.0"); ++ ++module_init(mdma_init); ++module_exit(mdma_exit); ++ +diff --git a/arch/arm/mach-gk710xs/rct.c b/arch/arm/mach-gk710xs/rct.c +new file mode 100644 +index 00000000..457669ba +--- /dev/null ++++ b/arch/arm/mach-gk710xs/rct.c +@@ -0,0 +1,194 @@ ++/* ++ * arch/arm/mach-gk/rct.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++u32 get_apb_bus_freq_hz(void) ++{ ++ typedef union { ++ u32 all; ++ struct { ++ u32 fbdiv : 12; ++ u32 pstdiv1 : 3; ++ u32 : 1; ++ u32 pstdiv2 : 3; ++ u32 : 1; ++ u32 refdiv : 6; ++ u32 : 6; ++ } bitc; ++ } GH_PLL_CORE_CTRL_S; ++ GH_PLL_CORE_CTRL_S arm_pll; ++ u32 div0118; ++ u32 apb_freq; ++ arm_pll.all = gk_rct_readl(GK_VA_RCT + 0x014); ++ div0118 = gk_rct_readl(GK_VA_RCT + 0x0118); ++ if(div0118 * arm_pll.bitc.fbdiv * arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2) ++ { ++ apb_freq = (24 * arm_pll.bitc.fbdiv * 1000000)/(div0118 * 4 * arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2); ++ } ++ else ++ { ++ apb_freq = GK_APB_FREQ; ++ } ++ ++ return apb_freq; ++} ++EXPORT_SYMBOL(get_apb_bus_freq_hz); ++ ++u32 get_uart_freq_hz(void) ++{ ++ return (u32)GK_UART_FREQ; ++} ++EXPORT_SYMBOL(get_uart_freq_hz); ++ ++u32 get_ssi0_freq_hz(void) ++{ ++ u32 div = gk_rct_readl(GK_VA_RCT + 0x0030) & 0xFF; ++ if(div == 0) ++ { ++ div = 8; ++ } ++ return (get_apb_bus_freq_hz()/div); ++} ++EXPORT_SYMBOL(get_ssi0_freq_hz); ++ ++u32 get_ssi1_freq_hz(void) ++{ ++ u32 div = gk_rct_readl(GK_VA_RCT + 0x00A0) & 0xFF; ++ if(div == 0) ++ { ++ div = 8; ++ } ++ return (get_apb_bus_freq_hz()/div); ++} ++EXPORT_SYMBOL(get_ssi1_freq_hz); ++ ++u32 get_sd_freq_hz(void) ++{ ++ typedef union { ++ u32 all; ++ struct { ++ u32 fbdiv : 12; ++ u32 pstdiv1 : 3; ++ u32 : 1; ++ u32 pstdiv2 : 3; ++ u32 : 1; ++ u32 refdiv : 6; ++ u32 : 6; ++ } bitc; ++ } GH_PLL_CORE_CTRL_S; ++ GH_PLL_CORE_CTRL_S arm_pll; ++ u32 div0018; ++ u32 sd_freq; ++ arm_pll.all = gk_rct_readl(GK_VA_RCT + 0x014); ++ div0018 = gk_rct_readl(GK_VA_RCT + 0x0018); ++ if(div0018 * arm_pll.bitc.fbdiv * arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2) ++ { ++ sd_freq = (24 * arm_pll.bitc.fbdiv * 1000000)/(div0018 * arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2); ++ } ++ else ++ { ++ sd_freq = GK_SD_FREQ; ++ } ++ return sd_freq; ++} ++EXPORT_SYMBOL(get_sd_freq_hz); ++ ++void set_sd_rct(u32 freq) ++{ ++ typedef union { ++ u32 all; ++ struct { ++ u32 fbdiv : 12; ++ u32 pstdiv1 : 3; ++ u32 : 1; ++ u32 pstdiv2 : 3; ++ u32 : 1; ++ u32 refdiv : 6; ++ u32 : 6; ++ } bitc; ++ } GH_PLL_CORE_CTRL_S; ++ GH_PLL_CORE_CTRL_S arm_pll; ++ u32 div0018; ++ arm_pll.all = gk_rct_readl(GK_VA_RCT + 0x014); ++ div0018 = gk_rct_readl(GK_VA_RCT + 0x0018); ++ if(div0018 * arm_pll.bitc.fbdiv * arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2) ++ { ++ div0018 = (24 * arm_pll.bitc.fbdiv * 1000000)/(arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2); ++ div0018 /= freq; ++ gk_rct_writel(GK_VA_RCT + 0x0018, div0018); ++ } ++} ++EXPORT_SYMBOL(set_sd_rct); ++ ++u32 get_audio_clk_freq(void) ++{ ++ typedef union { ++ u32 all; ++ struct { ++ u32 fbdiv : 12; ++ u32 pstdiv1 : 3; ++ u32 : 1; ++ u32 pstdiv2 : 3; ++ u32 : 1; ++ u32 refdiv : 6; ++ u32 : 6; ++ } bitc; ++ } GH_PLL_CORE_CTRL_S; ++ GH_PLL_CORE_CTRL_S arm_pll; ++ u32 PST_div; ++ u32 PRE_div; ++ u32 audio_freq; ++ u32 FRAC; ++ arm_pll.all = gk_rct_readl(GK_VA_RCT + 0x024); ++ FRAC = gk_rct_readl(GK_VA_RCT + 0x078); ++ PST_div = gk_rct_readl(GK_VA_RCT + 0x084); ++ PRE_div = gk_rct_readl(GK_VA_RCT + 0x080); ++ if(PST_div * PRE_div * arm_pll.bitc.fbdiv * arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2) ++ { ++ u64 FRAC_c; ++ u64 div_all; ++ FRAC_c = FRAC; ++ FRAC_c *= 15625; ++ FRAC_c *= 24; ++ div_all = 262144 * PST_div * PRE_div * arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2; ++ FRAC_c += (div_all>>1); ++ do_div((FRAC_c), (div_all)); \ ++ audio_freq = (24 * (arm_pll.bitc.fbdiv * 1000000))/(PST_div * PRE_div * arm_pll.bitc.refdiv * arm_pll.bitc.pstdiv1 * arm_pll.bitc.pstdiv2); ++ audio_freq += (u32)FRAC_c; ++ } ++ else ++ { ++ audio_freq = 12288000; ++ } ++ return audio_freq; ++} ++EXPORT_SYMBOL(get_audio_clk_freq); ++ +diff --git a/arch/arm/mach-gk710xs/vi.c b/arch/arm/mach-gk710xs/vi.c +new file mode 100644 +index 00000000..42a3081c +--- /dev/null ++++ b/arch/arm/mach-gk710xs/vi.c +@@ -0,0 +1,55 @@ ++/* ++ * arch/arm/mach-gk/vi.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++ ++#include ++#include ++ ++/* ==========================================================================*/ ++struct i2c_board_info gk_board_vi_infos[2] = { ++ [0] = { ++ .type = "gk_vi0", ++ .addr = 0x02, ++ }, ++ [1] = { ++ .type = "gk_vi1", ++ .addr = 0x03, ++ }, ++}; ++ ++struct i2c_board_info gk_board_hdmi_infos[3] = { ++ [0] = { ++ .type = "ep952", ++ .addr = (0x52>>1), ++ }, ++ [1] = { ++ .type = "rtc8563", ++ .addr = 0x51, ++ }, ++ [2] = { ++ .type = "bma250", ++ .addr = 0x18, ++ }, ++}; ++ +diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig +index 7c8a7d84..f6f381f2 100644 +--- a/arch/arm/mm/Kconfig ++++ b/arch/arm/mm/Kconfig +@@ -747,7 +747,11 @@ config CPU_DCACHE_SIZE + hex + depends on CPU_ARM740T || CPU_ARM946E + default 0x00001000 if CPU_ARM740T +- default 0x00002000 # default size for ARM946E-S ++ default 0x00002000 if !(PLAT_GOKE) # default size for ARM946E-S ++ default 0x00004000 if ARCH_GK710X ++ default 0x00004000 if ARCH_GK710X_FPGA ++ default 0x00004000 if ARCH_GK710XS ++ default 0x00004000 if ARCH_GK710XS_FPGA + help + Some cores are synthesizable to have various sized cache. For + ARM946E-S case, it can vary from 0KB to 1MB. +@@ -890,7 +894,11 @@ config ARM_L1_CACHE_SHIFT_6 + config ARM_L1_CACHE_SHIFT + int + default 6 if ARM_L1_CACHE_SHIFT_6 +- default 5 ++ default 5 if !(PLAT_GOKE) ++ default 4 if ARCH_GK710X ++ default 4 if ARCH_GK710X_FPGA ++ default 4 if ARCH_GK710XS ++ default 4 if ARCH_GK710XS_FPGA + + config ARM_DMA_MEM_BUFFERABLE + bool "Use non-cacheable memory for DMA" if (CPU_V6 || CPU_V6K) && !CPU_V7 +diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c +index a3e4adf2..ad77d659 100644 +--- a/arch/arm/mm/dma-mapping.c ++++ b/arch/arm/mm/dma-mapping.c +@@ -128,7 +128,7 @@ static void __dma_free_buffer(struct page *page, size_t size) + */ + static pte_t **consistent_pte; + +-#define DEFAULT_CONSISTENT_DMA_SIZE SZ_2M ++#define DEFAULT_CONSISTENT_DMA_SIZE SZ_8M + + unsigned long consistent_base = CONSISTENT_END - DEFAULT_CONSISTENT_DMA_SIZE; + +diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c +index 8f5813bb..1742ae3d 100644 +--- a/arch/arm/mm/init.c ++++ b/arch/arm/mm/init.c +@@ -653,6 +653,9 @@ void __init mem_init(void) + " ITCM : 0x%08lx - 0x%08lx (%4ld kB)\n" + #endif + " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n" ++#ifdef CONFIG_MMU ++ " DMA : 0x%08lx - 0x%08lx (%4ld MB)\n" ++#endif + " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n" + " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n" + #ifdef CONFIG_HIGHMEM +@@ -673,6 +676,9 @@ void __init mem_init(void) + MLK(ITCM_OFFSET, (unsigned long) itcm_end), + #endif + MLK(FIXADDR_START, FIXADDR_TOP), ++#ifdef CONFIG_MMU ++ MLM(CONSISTENT_BASE, CONSISTENT_END), ++#endif + MLM(VMALLOC_START, VMALLOC_END), + MLM(PAGE_OFFSET, (unsigned long)high_memory), + #ifdef CONFIG_HIGHMEM +diff --git a/arch/arm/plat-goke/Kconfig b/arch/arm/plat-goke/Kconfig +new file mode 100644 +index 00000000..c14cdce3 +--- /dev/null ++++ b/arch/arm/plat-goke/Kconfig +@@ -0,0 +1,734 @@ ++# ++# arch/arm/plat-goke/Kconfig ++# ++# History: ++# 2016/04/18 - [Steven Yu] created file ++# ++# Copyright (C) 2002-2016, Goke Microelectronics China. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++# ++ ++if ARCH_GK710X || ARCH_GK710XS || ARCH_GK710X_FPGA || ARCH_GK710XS_FPGA || ARCH_GK720X || ARCH_GK720X_FPGA ++ ++choice ++ prompt "Gk710X system flash select" ++ default ONLY_USE_NOR_8M ++ ++config ONLY_USE_NOR_8M ++ bool "system only 8Mbytes nor flash" ++ help ++ select Goke GK710X only use 8M nor flash ++ ++config ONLY_USE_NOR_16M ++ bool "system only 16Mbytes nor flash" ++ help ++ select Goke GK710X only use 16M nor flash ++ ++config ONLY_USE_NOR_32M ++ bool "system only 32Mbytes nor flash" ++ help ++ select Goke GK710X only use 32M nor flash ++ ++config ONLY_USE_NAND ++ bool "system only use nand flash" ++ help ++ select Goke GK710X only use nand flash ++ ++config USE_NOR_AND_NAND ++ bool "system use nor and nand flash" ++ help ++ select Goke GK710X only use nor and nand flash ++ ++endchoice ++ ++ ++menu "Gk710X select peripheral" ++ ++choice ++ prompt "phy clk mode select" ++ default PHY_USE_AO_MCLK ++ ++config PHY_USE_AO_MCLK ++ bool "the phy use the audio mclk" ++ help ++ select Goke GK710X phy the phy use audio mclk ++ ++config PHY_USE_SD_CLK ++ bool "the phy use the SDIO clk" ++ help ++ select Goke GK710X phy the phy use SDIO mclk ++ ++config PHY_USE_EXTERN_CLK ++ bool "the phy use the extern clk" ++ help ++ select Goke GK710X phy the phy use the extern mclk ++ ++endchoice ++ ++choice ++ prompt "pmu work mode" ++ default PMU_POWER_OFF_CPU ++ ++config PMU_POWER_OFF_CPU ++ bool "load mcu code then power off the arm cpu" ++ help ++ select the 51cpu work mode ++ ++config PMU_ALWAYS_RUNNING ++ bool "load mcu code do not power off the arm cpu" ++ help ++ select the 51cpu work mode, must use a gpio connect to pmu gpio 3 to get the pmu controller ++ ++config PMU_AUTOMOTIVE ++ bool "work mode for automotive" ++ help ++ select the 51cpu work mode ++ ++endchoice ++ ++ ++config SYSTEM_USE_EXTERN_I2S ++ bool "The soc select extern I2S" ++ help ++ select extern I2S or not. ++ ++endmenu ++ ++config GK_CHIP_INCLUDE_FILE ++ string ++ default "mach/gk710x.h" if ARCH_GK710X ++ default "mach/gk710xs.h" if ARCH_GK710XS ++ default "mach/gk720x.h" if ARCH_GK720X ++ default "mach/gk720x.h" if ARCH_GK720X_FPGA ++endif ++ ++comment "soc/fpga modules list" ++ ++config PLAT_GOKE ++ bool ++ help ++ Support for . ++ ++config GK_CPU_ARM_1176_V1_00 ++ bool ++ help ++ Support for ARM 1176 v1.00. ++ ++config GK_CPU_ARM_1176_V1_10 ++ bool ++ help ++ Support for ARM 1176 v1.10. ++ ++config GK_CPU_ARM_1176_V1_20 ++ bool ++ help ++ Support for ARM 1176 v1.20. ++ ++config GK_CPU_CORTEX_A7_V1_00 ++ bool ++ help ++ Support for CORTEX A7 v1.00. ++ ++config GK_PLL_CHIP_V1_00 ++ bool ++ help ++ Support for pll v1.00 soc. ++ ++config GK_PLL_CHIP_V1_10 ++ bool ++ help ++ Support for pll v1.10 soc. ++ ++config GK_PLL_CHIP_V1_20 ++ bool ++ help ++ Support for pll v1.20 soc. ++ ++config GK_PLL_FPGA_V1_00 ++ bool ++ help ++ Support for pll v1.00 fpga. ++ ++config GK_PLL_FPGA_V1_10 ++ bool ++ help ++ Support for pll v1.10 fpga. ++ ++config GK_PLL_FPGA_V1_20 ++ bool ++ help ++ Support for pll v1.20 fpga. ++ ++config GK_EFUSE ++ bool ++ help ++ Support for efuse v1.00. ++ ++config GK_EFUSE_V1_00 ++ bool ++ help ++ Support for efuse v1.00. ++ ++config GK_EFUSE_V1_10 ++ bool ++ help ++ Support for efuse v1.10. ++ ++config GK_EFUSE_V1_20 ++ bool ++ help ++ Support for efuse v1.20. ++ ++config GK_EFUSE_V1_30 ++ bool ++ help ++ Support for efuse v1.30. ++ ++config GK_CRYPT ++ bool ++ help ++ Support for . ++ ++config GK_CRYPT_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_CRYPT_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_TIMER ++ bool ++ help ++ Support for . ++ ++config GK_TIMER_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_TIMER_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_WDT ++ bool ++ help ++ Support for . ++ ++config GK_WDT_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_WDT_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_DDR2_CON ++ bool ++ help ++ Support for . ++ ++config GK_DDR2_CON_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_DDR2_CON_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_DDR2_PHY ++ bool ++ help ++ Support for . ++ ++config GK_DDR2_PHY_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_DDR2_PHY_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_GPIO ++ bool ++ help ++ Support for . ++ ++config GK_GPIO_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_GPIO_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_GPIO_V1_20 ++ bool ++ help ++ Support for . ++ ++config GK_GPIO_MAX_INPUT_TYPE ++ int ++ default 64 if ARCH_GK710X ++ default 64 if ARCH_GK710X_FPGA ++ default 128 if ARCH_GK710XS ++ default 128 if ARCH_GK710XS_FPGA ++ default 128 if ARCH_GK720X ++ default 128 if ARCH_GK720X_FPGA ++ help ++ Support for . ++ ++config GK_GPIO_INSTANCES ++ int ++ default 1 if ARCH_GK710X ++ default 1 if ARCH_GK710X_FPGA ++ default 1 if ARCH_GK710XS ++ default 1 if ARCH_GK710XS_FPGA ++ default 1 if ARCH_GK720X ++ default 1 if ARCH_GK720X_FPGA ++ help ++ Support for . ++ ++config GK_UART ++ bool ++ help ++ Support for . ++ ++config GK_UART_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_UART_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_UART_V1_20 ++ bool ++ help ++ Support for . ++ ++config GK_MUSB ++ bool ++ help ++ Support for . ++ ++config GK_MUSB_CON_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_MUSB_CON_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_USB_DMA ++ bool ++ help ++ Support for . ++ ++config GK_USB_DMA_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_USB_DMA_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_USB_PHY ++ bool ++ help ++ Support for . ++ ++config GK_USB_PHY_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_I2S ++ bool ++ help ++ Support for . ++ ++config GK_I2S_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_AUD_CON ++ bool ++ help ++ Support for . ++ ++config GK_AUD_CON_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_AUD_AD ++ bool ++ help ++ Support for . ++ ++config GK_AUD_AD_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_AUD_DMA ++ bool ++ help ++ Support for . ++ ++config GK_AUD_DMA_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_AUD_DMA_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_ETH ++ bool ++ help ++ Support for . ++ ++config GK_ETH_EMAC ++ bool ++ help ++ Support for . ++ ++config GK_ETH_EMAC_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_ETH_EMAC_V1_01 ++ bool ++ help ++ Support for . ++config GK_ETH_EDMA ++ bool ++ help ++ Support for . ++ ++config GK_ETH_EDMA_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_ETH_EPHY ++ bool ++ help ++ Support for . ++ ++config GK_ETH_EPHY_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_PWM ++ bool ++ help ++ Support for . ++ ++config GK_PWM_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_SDIO ++ bool ++ help ++ Support for . ++ ++config GK_SDIO2 ++ bool ++ help ++ Support for . ++ ++config GK_SDIO2_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_SDIO3 ++ bool ++ help ++ Support for . ++ ++config GK_SDIO3_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_ADC ++ bool ++ help ++ Support for . ++ ++config GK_ADC_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_ADC_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_I2C ++ bool ++ help ++ Support for . ++ ++config GK_I2C_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_SFLASH ++ bool ++ help ++ Support for . ++ ++config GK_SFLASH_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_SPI ++ bool ++ help ++ Support for . ++ ++config GK_SPI_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_PMU ++ bool ++ help ++ Support for . ++ ++config GK_PMU_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_PMU_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_MCU ++ bool ++ help ++ Support for . ++ ++config GK_MCU_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_RTC ++ bool ++ help ++ Support for . ++ ++config GK_RTC_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_IR ++ bool ++ help ++ Support for . ++ ++config GK_IR_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_VOUT ++ bool ++ help ++ Support for . ++ ++config GK_VOUT_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_VOUT_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_VOUT_V1_20 ++ bool ++ help ++ Support for . ++ ++config GK_HDMI ++ bool ++ help ++ Support for . ++ ++config GK_HDMI_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_MIPI ++ bool ++ help ++ Support for . ++ ++config GK_MIPI_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_VIN ++ bool ++ help ++ Support for . ++ ++config GK_VIN_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_VIN_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_VIN_V1_20 ++ bool ++ help ++ Support for . ++ ++config GK_MDMA ++ bool ++ help ++ Support for . ++ ++config GK_MDMA_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_SMEM ++ bool ++ help ++ Support for . ++ ++config GK_SMEM_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_SMEM_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_DSP1 ++ bool ++ help ++ Support for . ++ ++config GK_DSP1_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_DSP2 ++ bool ++ help ++ Support for . ++ ++config GK_DSP2_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_ISP ++ bool ++ help ++ Support for . ++ ++config GK_ISP_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_ISP_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_FW ++ bool ++ help ++ Support for . ++ ++config GK_FW_V1_00 ++ bool ++ help ++ Support for . ++ ++config GK_FW_V1_10 ++ bool ++ help ++ Support for . ++ ++config GK_FW_V1_20 ++ bool ++ help ++ Support for . ++ ++config GK_FB ++ bool ++ help ++ Support for . ++ ++config GK_FB_V1_00 ++ bool ++ help ++ Support for . +diff --git a/arch/arm/plat-goke/Makefile b/arch/arm/plat-goke/Makefile +new file mode 100644 +index 00000000..cf261b01 +--- /dev/null ++++ b/arch/arm/plat-goke/Makefile +@@ -0,0 +1,16 @@ ++obj-y += gk_gpio.o ++obj-y += timer.o ++obj-$(CONFIG_SERIAL_GOKE) += uart.o ++obj-$(CONFIG_ETH_GOKE) += eth.o ++obj-y += cache.o event.o highres_timer.o sync_proc.o ++obj-y += fb.o ++obj-y += pmu.o ++obj-y += sd.o ++obj-y += hw_timer.o ++obj-y += switch.o ++ ++obj-$(CONFIG_GK_GPIO_V1_00) += gk_gpio_v1_00.o ++obj-$(CONFIG_GK_GPIO_V1_10) += gk_gpio_v1_10.o ++obj-$(CONFIG_GK_GPIO_V1_20) += gk_gpio_v1_20.o ++ ++ccflags-y += -Iarch/arm/plat-goke/include/ +diff --git a/arch/arm/plat-goke/cache.c b/arch/arm/plat-goke/cache.c +new file mode 100644 +index 00000000..285625d8 +--- /dev/null ++++ b/arch/arm/plat-goke/cache.c +@@ -0,0 +1,354 @@ ++/* ++ * arch/arm/mach-gk7101/cache.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#ifdef CONFIG_CACHE_PL310 ++#include ++#endif ++#include ++ ++#include ++#include ++ ++/* ==========================================================================*/ ++#ifdef MODULE_PARAM_PREFIX ++#undef MODULE_PARAM_PREFIX ++#endif ++#define MODULE_PARAM_PREFIX "gk_config." ++ ++ ++/* ==========================================================================*/ ++#ifdef CONFIG_OUTER_CACHE ++static u32 cache_l2_status = 0; ++#ifdef CONFIG_CACHE_PL310 ++static void __iomem *gk_cache_l2_base = __io(GK_VA_L2CC_BASE); ++#endif ++#endif ++ ++static int cache_check_start = 1; ++module_param(cache_check_start, int, 0644); ++static int cache_check_end = 0; ++module_param(cache_check_end, int, 0644); ++static int cache_check_fail_halt = 0; ++module_param(cache_check_fail_halt, int, 0644); ++ ++/* ==========================================================================*/ ++void gk_cache_clean_range(void *addr, unsigned int size) ++{ ++#ifdef CONFIG_CPU_DCACHE_DISABLE ++ return ; ++#else ++ ++ u32 vstart; ++ u32 vend; ++#ifdef CONFIG_OUTER_CACHE ++ u32 pstart; ++#endif ++ u32 addr_tmp; ++ ++ vstart = (u32)addr & CACHE_LINE_MASK; ++ vend = ((u32)addr + size + CACHE_LINE_SIZE - 1) & CACHE_LINE_MASK; ++ if (cache_check_start && (vstart != (u32)addr)) { ++ pr_warn("%s start:0x%08x vs 0x%08x\n", ++ __func__, vstart, (u32)addr); ++ if (cache_check_fail_halt) ++ BUG(); ++ } ++ if (cache_check_end && (vend != ((u32)addr + size))) { ++ pr_warn("%s start:0x%08x vs 0x%08x\n", ++ __func__, vend, ((u32)addr + size)); ++ if (cache_check_fail_halt) ++ BUG(); ++ } ++#ifdef CONFIG_OUTER_CACHE ++ pstart = gk_virt_to_phys(vstart); ++#endif ++ ++ for (addr_tmp = vstart; addr_tmp < vend; addr_tmp += CACHE_LINE_SIZE) { ++ __asm__ __volatile__ ( ++ "mcr p15, 0, %0, c7, c10, 1" : : "r" (addr_tmp)); ++ } ++ dsb(); ++ ++#ifdef CONFIG_OUTER_CACHE ++ outer_clean_range(pstart, (pstart + size)); ++#endif ++ ++#endif //CONFIG_CPU_DCACHE_DISABLE ++} ++EXPORT_SYMBOL(gk_cache_clean_range); ++ ++void gk_cache_inv_range(void *addr, unsigned int size) ++{ ++#ifdef CONFIG_CPU_DCACHE_DISABLE ++ return ; ++#else ++ ++ u32 vstart; ++ u32 vend; ++#ifdef CONFIG_OUTER_CACHE ++ u32 pstart; ++#endif ++ u32 addr_tmp; ++ ++ vstart = (u32)addr & CACHE_LINE_MASK; ++ vend = ((u32)addr + size + CACHE_LINE_SIZE - 1) & CACHE_LINE_MASK; ++ if (cache_check_start && (vstart != (u32)addr)) { ++ pr_warn("%s start:0x%08x vs 0x%08x\n", ++ __func__, vstart, (u32)addr); ++ if (cache_check_fail_halt) ++ BUG(); ++ } ++ if (cache_check_end && (vend != ((u32)addr + size))) { ++ pr_warn("%s start:0x%08x vs 0x%08x\n", ++ __func__, vend, ((u32)addr + size)); ++ if (cache_check_fail_halt) ++ BUG(); ++ } ++#ifdef CONFIG_OUTER_CACHE ++ pstart = gk_virt_to_phys(vstart); ++ outer_inv_range(pstart, (pstart + size)); ++#endif ++ ++ for (addr_tmp = vstart; addr_tmp < vend; addr_tmp += CACHE_LINE_SIZE) { ++ __asm__ __volatile__ ( ++ "mcr p15, 0, %0, c7, c6, 1" : : "r" (addr_tmp)); ++ } ++ dsb(); ++ ++#ifdef CONFIG_OUTER_CACHE ++ outer_inv_range(pstart, (pstart + size)); ++ ++ for (addr_tmp = vstart; addr_tmp < vend; addr_tmp += CACHE_LINE_SIZE) { ++ __asm__ __volatile__ ( ++ "mcr p15, 0, %0, c7, c6, 1" : : "r" (addr_tmp)); ++ } ++ dsb(); ++#endif ++ ++#endif //CONFIG_CPU_DCACHE_DISABLE ++} ++EXPORT_SYMBOL(gk_cache_inv_range); ++ ++void gk_cache_flush_range(void *addr, unsigned int size) ++{ ++#ifdef CONFIG_CPU_DCACHE_DISABLE ++ return ; ++#else ++ ++ u32 vstart; ++ u32 vend; ++#ifdef CONFIG_OUTER_CACHE ++ u32 pstart; ++#endif ++ u32 addr_tmp; ++ ++ vstart = (u32)addr & CACHE_LINE_MASK; ++ vend = ((u32)addr + size + CACHE_LINE_SIZE - 1) & CACHE_LINE_MASK; ++ if (cache_check_start && (vstart != (u32)addr)) { ++ pr_warn("%s start:0x%08x vs 0x%08x\n", ++ __func__, vstart, (u32)addr); ++ if (cache_check_fail_halt) ++ BUG(); ++ } ++ if (cache_check_end && (vend != ((u32)addr + size))) { ++ pr_warn("%s start:0x%08x vs 0x%08x\n", ++ __func__, vend, ((u32)addr + size)); ++ if (cache_check_fail_halt) ++ BUG(); ++ } ++#ifdef CONFIG_OUTER_CACHE ++ pstart = gk_virt_to_phys(vstart); ++ ++ for (addr_tmp = vstart; addr_tmp < vend; addr_tmp += CACHE_LINE_SIZE) { ++ __asm__ __volatile__ ( ++ "mcr p15, 0, %0, c7, c10, 1" : : "r" (addr_tmp)); ++ } ++ dsb(); ++ ++ outer_flush_range(pstart, (pstart + size)); ++ ++ for (addr_tmp = vstart; addr_tmp < vend; addr_tmp += CACHE_LINE_SIZE) { ++ __asm__ __volatile__ ( ++ "mcr p15, 0, %0, c7, c6, 1" : : "r" (addr_tmp)); ++ } ++ dsb(); ++#else ++ for (addr_tmp = vstart; addr_tmp < vend; addr_tmp += CACHE_LINE_SIZE) { ++ __asm__ __volatile__ ( ++ "mcr p15, 0, %0, c7, c14, 1" : : "r" (addr_tmp)); ++ } ++ dsb(); ++#endif ++ ++#endif //CONFIG_CPU_DCACHE_DISABLE ++} ++EXPORT_SYMBOL(gk_cache_flush_range); ++ ++void gk_cache_pli_range(void *addr, unsigned int size) ++{ ++#ifdef CONFIG_CPU_DCACHE_DISABLE ++ return ; ++#else ++ ++ u32 vstart; ++ u32 vend; ++ u32 addr_tmp; ++ ++ vstart = (u32)addr & CACHE_LINE_MASK; ++ vend = ((u32)addr + size + CACHE_LINE_SIZE - 1) & CACHE_LINE_MASK; ++ ++ for (addr_tmp = vstart; addr_tmp < vend; addr_tmp += CACHE_LINE_SIZE) { ++#if __LINUX_ARM_ARCH__ >= 7 ++ __asm__ __volatile__ ( ++ "pli [%0]" : : "r" (addr_tmp)); ++#elif __LINUX_ARM_ARCH__ >= 5 ++ __asm__ __volatile__ ( ++ "mcr p15, 0, %0, c7, c13, 1" : : "r" (addr_tmp)); ++#else ++#error "PLI not supported" ++#endif ++ } ++ ++#endif //CONFIG_CPU_DCACHE_DISABLE ++} ++EXPORT_SYMBOL(gk_cache_pli_range); ++ ++#ifdef CONFIG_OUTER_CACHE ++/* ==========================================================================*/ ++void gk_cache_l2_enable_raw() ++{ ++#ifdef CONFIG_CPU_DCACHE_DISABLE ++ return ; ++#else ++ ++ if (!outer_is_enabled()) { ++ ++#ifdef CONFIG_CACHE_PL310 ++ if (readl(gk_cache_l2_base + L2X0_DATA_LATENCY_CTRL) != ++ 0x00000120) { ++ writel(0x00000120, (gk_cache_l2_base + ++ L2X0_DATA_LATENCY_CTRL)); ++ l2x0_init(gk_cache_l2_base, ++ ((1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT) | ++ (0x1 << L2X0_AUX_CTRL_CR_POLICY_SHIFT) | ++ (0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | ++ (1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) | ++ (1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT)), ++ L2X0_AUX_CTRL_MASK); ++ } else ++#endif ++ outer_enable(); ++ } ++ ++#endif //CONFIG_CPU_DCACHE_DISABLE ++} ++EXPORT_SYMBOL(gk_cache_l2_enable_raw); ++ ++void gk_cache_l2_disable_raw() ++{ ++#ifdef CONFIG_CPU_DCACHE_DISABLE ++ return ; ++#else ++ ++ flush_cache_all(); ++ outer_flush_all(); ++ outer_disable(); ++ outer_inv_all(); ++ flush_cache_all(); ++ ++#endif //CONFIG_CPU_DCACHE_DISABLE ++} ++EXPORT_SYMBOL(gk_cache_l2_disable_raw); ++ ++int gk_cache_l2_enable() ++{ ++#ifdef CONFIG_CPU_DCACHE_DISABLE ++ return 0; ++#else ++ ++ gk_cache_l2_enable_raw(); ++ return outer_is_enabled() ? 0 : -1; ++ ++#endif //CONFIG_CPU_DCACHE_DISABLE ++} ++EXPORT_SYMBOL(gk_cache_l2_enable); ++ ++int gk_cache_l2_disable() ++{ ++#ifdef CONFIG_CPU_DCACHE_DISABLE ++ return 0; ++#else ++ ++ unsigned long flags; ++ ++ if (outer_is_enabled()) { ++ disable_nonboot_cpus(); ++ local_irq_save(flags); ++ gk_cache_l2_disable_raw(); ++ local_irq_restore(flags); ++ enable_nonboot_cpus(); ++ } ++ ++ ++ return outer_is_enabled() ? -1 : 0; ++ ++#endif //CONFIG_CPU_DCACHE_DISABLE ++} ++EXPORT_SYMBOL(gk_cache_l2_disable); ++ ++/* =========================Debug Only========================================*/ ++int cache_l2_set_status(const char *val, const struct kernel_param *kp) ++{ ++ int ret; ++ ++ ret = param_set_uint(val, kp); ++ if (!ret) { ++ if (cache_l2_status) { ++ ret = gk_cache_l2_enable(); ++ } else { ++ ret = gk_cache_l2_disable(); ++ } ++ } ++ ++ return ret; ++} ++ ++static int cache_l2_get_status(char *buffer, const struct kernel_param *kp) ++{ ++ cache_l2_status = outer_is_enabled(); ++ ++ return param_get_uint(buffer, kp); ++} ++ ++static struct kernel_param_ops param_ops_cache_l2 = { ++ .set = cache_l2_set_status, ++ .get = cache_l2_get_status, ++}; ++module_param_cb(cache_l2, ¶m_ops_cache_l2, &cache_l2_status, 0644); ++#endif ++ +diff --git a/arch/arm/plat-goke/eth.c b/arch/arm/plat-goke/eth.c +new file mode 100644 +index 00000000..0f80af70 +--- /dev/null ++++ b/arch/arm/plat-goke/eth.c +@@ -0,0 +1,127 @@ ++/* ++ * arch/arm/mach-gk7101/eth.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++extern u64 gk_dmamask; ++ ++int rct_is_eth_enabled(void) ++{ ++ return 1; ++} ++ ++/* ==========================================================================*/ ++#ifdef MODULE_PARAM_PREFIX ++#undef MODULE_PARAM_PREFIX ++#endif ++#define MODULE_PARAM_PREFIX "gk_config." ++ ++/* ==========================================================================*/ ++static struct resource gk_eth0_resources[] = { ++ [0] = DEFINE_RES_MEM(GK_VA_ETH_GMAC, SZ_8K), ++ [1] = DEFINE_RES_IRQ(ETH_IRQ), ++}; ++ ++struct gk_eth_platform_info gk_eth0_platform_info = { ++ .mac_addr = {0, 0, 0, 0, 0, 0}, ++ .napi_weight = 32, ++ .watchdog_timeo = (2 * HZ), ++ .mii_id = -1, ++ .phy_supported = SUPPORTED_10baseT_Half | ++ SUPPORTED_10baseT_Full | ++ SUPPORTED_100baseT_Half | ++ SUPPORTED_100baseT_Full | ++#if (SUPPORT_GMII == 1) ++ SUPPORTED_1000baseT_Half | ++ SUPPORTED_1000baseT_Full | ++#endif ++ SUPPORTED_Autoneg | ++ SUPPORTED_MII, ++ .phy_reset = { ++ .gpio_id = -1, ++ .active_level = GPIO_HIGH, ++ .active_delay = 1, ++ }, ++ .mii_retry_limit = 200, ++ .mii_retry_tmo = 10, ++ .default_tx_ring_size = 32, ++ .default_rx_ring_size = 64, ++ .default_dma_bus_mode = (ETH_DMA_BUS_MODE_FB | ++ ETH_DMA_BUS_MODE_PBL_32 | ++ ETH_DMA_BUS_MODE_DA_RX), ++ .default_dma_opmode = (ETH_DMA_OPMODE_TTC_256 | ++ ETH_DMA_OPMODE_RTC_64 | ++ ETH_DMA_OPMODE_FUF), ++ .default_supported = 0, ++ .is_enabled = rct_is_eth_enabled, ++}; ++GK_ETH_PARAM_CALL(0, gk_eth0_platform_info, 0644); ++ ++int __init gk_init_eth0(const u8 *mac_addr) ++{ ++ int errCode = 0; ++ ++ gk_eth0_platform_info.mac_addr[0] = mac_addr[0]; ++ gk_eth0_platform_info.mac_addr[1] = mac_addr[1]; ++ gk_eth0_platform_info.mac_addr[2] = mac_addr[2]; ++ gk_eth0_platform_info.mac_addr[3] = mac_addr[3]; ++ gk_eth0_platform_info.mac_addr[4] = mac_addr[4]; ++ gk_eth0_platform_info.mac_addr[5] = mac_addr[5]; ++ ++ ++ return errCode; ++} ++ ++void gk_set_phy_reset_pin(u32 gpio_pin) ++{ ++ /*set phy reset pin*/ ++ gk_eth0_platform_info.phy_reset.gpio_id = gpio_pin; ++} ++ ++ ++void gk_set_phy_speed_led(u32 gpio_type) ++{ ++ gk_gpio_func_config(gk_all_gpio_cfg.phy_speed_led, gpio_type); ++} ++ ++struct platform_device gk_eth0 = { ++ .name = "gk-eth", ++ .id = 0, ++ .resource = gk_eth0_resources, ++ .num_resources = ARRAY_SIZE(gk_eth0_resources), ++ .dev = { ++ .platform_data = &gk_eth0_platform_info, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++ +diff --git a/arch/arm/plat-goke/event.c b/arch/arm/plat-goke/event.c +new file mode 100644 +index 00000000..13d0d705 +--- /dev/null ++++ b/arch/arm/plat-goke/event.c +@@ -0,0 +1,160 @@ ++/* ++ * arch/arm/mach-gk/event.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++ ++/* ==========================================================================*/ ++static BLOCKING_NOTIFIER_HEAD(blocking_event_list); ++static RAW_NOTIFIER_HEAD(raw_event_list); ++ ++/* ==========================================================================*/ ++int gk_register_event_notifier(void *nb) ++{ ++ return blocking_notifier_chain_register(&blocking_event_list, nb); ++} ++EXPORT_SYMBOL(gk_register_event_notifier); ++ ++int gk_unregister_event_notifier(void *nb) ++{ ++ return blocking_notifier_chain_unregister(&blocking_event_list, nb); ++} ++EXPORT_SYMBOL(gk_unregister_event_notifier); ++ ++int gk_set_event(unsigned long val, void *v) ++{ ++ return blocking_notifier_call_chain(&blocking_event_list, val, v); ++} ++EXPORT_SYMBOL(gk_set_event); ++ ++int gk_register_raw_event_notifier(void *nb) ++{ ++ return raw_notifier_chain_register(&raw_event_list, nb); ++} ++EXPORT_SYMBOL(gk_register_raw_event_notifier); ++ ++int gk_unregister_raw_event_notifier(void *nb) ++{ ++ return raw_notifier_chain_unregister(&raw_event_list, nb); ++} ++EXPORT_SYMBOL(gk_unregister_raw_event_notifier); ++ ++int gk_set_raw_event(unsigned long val, void *v) ++{ ++ return raw_notifier_call_chain(&raw_event_list, val, v); ++} ++EXPORT_SYMBOL(gk_set_raw_event); ++ ++int gk_event_pool_init(struct gk_event_pool *pool) ++{ ++ if (!pool) ++ return -EINVAL; ++ ++ memset(pool, 0, sizeof(struct gk_event_pool)); ++ mutex_init(&pool->op_mutex); ++ return 0; ++} ++EXPORT_SYMBOL(gk_event_pool_init); ++ ++int gk_event_pool_affuse(struct gk_event_pool *pool, ++ struct gk_event event) ++{ ++ if (!pool) ++ return -EINVAL; ++ ++ if (event.type == GK_EV_NONE) ++ return 0; ++ ++ mutex_lock(&pool->op_mutex); ++ pool->ev_sno++; ++ pool->events[pool->ev_index].sno = pool->ev_sno; ++ pool->events[pool->ev_index].time_code = 0; //FIX ME ++ pool->events[pool->ev_index].type = event.type; ++ memcpy(pool->events[pool->ev_index].data, event.data, sizeof(event.data)); ++ pool->ev_index++; ++ mutex_unlock(&pool->op_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL(gk_event_pool_affuse); ++ ++int gk_event_pool_query_index(struct gk_event_pool *pool) ++{ ++ unsigned char index; ++ ++ if (!pool) ++ return -EINVAL; ++ ++ mutex_lock(&pool->op_mutex); ++ index = pool->ev_index - 1; ++ mutex_unlock(&pool->op_mutex); ++ ++ return (int)index; ++} ++EXPORT_SYMBOL(gk_event_pool_query_index); ++ ++int gk_event_pool_query_event(struct gk_event_pool *pool, ++ struct gk_event *event, unsigned char index) ++{ ++ int retval = 0; ++ ++ if (!pool || !event) ++ return -EINVAL; ++ ++ mutex_lock(&pool->op_mutex); ++ ++ if (pool->events[index].type == GK_EV_NONE) { ++ retval = -EAGAIN; ++ goto gk_event_pool_query_event_exit; ++ } ++ ++ if (index == pool->ev_index) { ++ retval = -EAGAIN; ++ goto gk_event_pool_query_event_exit; ++ } ++ ++ *event = pool->events[index]; ++ ++gk_event_pool_query_event_exit: ++ mutex_unlock(&pool->op_mutex); ++ return retval; ++} ++EXPORT_SYMBOL(gk_event_pool_query_event); ++ ++int gk_event_report_uevent(struct kobject *kobj, enum kobject_action action, ++ char *envp_ext[]) ++{ ++ return kobject_uevent_env(kobj, action, envp_ext); ++} ++EXPORT_SYMBOL(gk_event_report_uevent); ++ ++ +diff --git a/arch/arm/plat-goke/fb.c b/arch/arm/plat-goke/fb.c +new file mode 100644 +index 00000000..1100605a +--- /dev/null ++++ b/arch/arm/plat-goke/fb.c +@@ -0,0 +1,893 @@ ++/* ++ * arch/arm/mach-gk/fb.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#include ++#include ++ ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++ ++/* ==========================================================================*/ ++static struct gk_platform_fb gk_platform_fb0 = { ++ .screen_var = { ++ .xres = 720, ++ .yres = 480, ++ .xres_virtual = 720, ++ .yres_virtual = 480, ++ .xoffset = 0, ++ .yoffset = 0, ++ .bits_per_pixel = 8, ++ .red = {.offset = 0, .length = 8, .msb_right = 0}, ++ .green = {.offset = 0, .length = 8, .msb_right = 0}, ++ .blue = {.offset = 0, .length = 8, .msb_right = 0}, ++ .activate = FB_ACTIVATE_NOW, ++ .height = -1, ++ .width = -1, ++ .pixclock = 36101, ++ .left_margin = 24, ++ .right_margin = 96, ++ .upper_margin = 10, ++ .lower_margin = 32, ++ .hsync_len = 40, ++ .vsync_len = 3, ++ .vmode = FB_VMODE_NONINTERLACED, ++ }, ++ .screen_fix = { ++ .id = "GK FB", ++ .type = FB_TYPE_PACKED_PIXELS, ++ .visual = FB_VISUAL_PSEUDOCOLOR, ++ .xpanstep = 1, ++ .ypanstep = 1, ++ .ywrapstep = 1, ++ .accel = FB_ACCEL_NONE, ++ .line_length = 0, ++ .smem_start = 0, ++ .smem_len = 0, ++ }, ++ .dsp_status = GK_DSP_UNKNOWN_MODE, ++ .fb_status = GK_FB_UNKNOWN_MODE, ++ .clut_table = { ++ 0, 128, 128, ++ 1, 128, 128, ++ 2, 128, 128, ++ 3, 128, 128, ++ 4, 128, 128, ++ 5, 128, 128, ++ 6, 128, 128, ++ 7, 128, 128, ++ 8, 128, 128, ++ 9, 128, 128, ++ 10, 128, 128, ++ 11, 128, 128, ++ 12, 128, 128, ++ 13, 128, 128, ++ 14, 128, 128, ++ 15, 128, 128, ++ 16, 128, 128, ++ 17, 128, 128, ++ 18, 128, 128, ++ 19, 128, 128, ++ 20, 128, 128, ++ 21, 128, 128, ++ 22, 128, 128, ++ 23, 128, 128, ++ 24, 128, 128, ++ 25, 128, 128, ++ 26, 128, 128, ++ 27, 128, 128, ++ 28, 128, 128, ++ 29, 128, 128, ++ 30, 128, 128, ++ 31, 128, 128, ++ 32, 128, 128, ++ 33, 128, 128, ++ 34, 128, 128, ++ 35, 128, 128, ++ 36, 128, 128, ++ 37, 128, 128, ++ 38, 128, 128, ++ 39, 128, 128, ++ 40, 128, 128, ++ 41, 128, 128, ++ 42, 128, 128, ++ 43, 128, 128, ++ 44, 128, 128, ++ 45, 128, 128, ++ 46, 128, 128, ++ 47, 128, 128, ++ 48, 128, 128, ++ 49, 128, 128, ++ 50, 128, 128, ++ 51, 128, 128, ++ 52, 128, 128, ++ 53, 128, 128, ++ 54, 128, 128, ++ 55, 128, 128, ++ 56, 128, 128, ++ 57, 128, 128, ++ 58, 128, 128, ++ 59, 128, 128, ++ 60, 128, 128, ++ 61, 128, 128, ++ 62, 128, 128, ++ 63, 128, 128, ++ 64, 128, 128, ++ 65, 128, 128, ++ 66, 128, 128, ++ 67, 128, 128, ++ 68, 128, 128, ++ 69, 128, 128, ++ 70, 128, 128, ++ 71, 128, 128, ++ 72, 128, 128, ++ 73, 128, 128, ++ 74, 128, 128, ++ 75, 128, 128, ++ 76, 128, 128, ++ 77, 128, 128, ++ 78, 128, 128, ++ 79, 128, 128, ++ 80, 128, 128, ++ 81, 128, 128, ++ 82, 128, 128, ++ 83, 128, 128, ++ 84, 128, 128, ++ 85, 128, 128, ++ 86, 128, 128, ++ 87, 128, 128, ++ 88, 128, 128, ++ 89, 128, 128, ++ 90, 128, 128, ++ 91, 128, 128, ++ 92, 128, 128, ++ 93, 128, 128, ++ 94, 128, 128, ++ 95, 128, 128, ++ 96, 128, 128, ++ 97, 128, 128, ++ 98, 128, 128, ++ 99, 128, 128, ++ 100, 128, 128, ++ 101, 128, 128, ++ 102, 128, 128, ++ 103, 128, 128, ++ 104, 128, 128, ++ 105, 128, 128, ++ 106, 128, 128, ++ 107, 128, 128, ++ 108, 128, 128, ++ 109, 128, 128, ++ 110, 128, 128, ++ 111, 128, 128, ++ 112, 128, 128, ++ 113, 128, 128, ++ 114, 128, 128, ++ 115, 128, 128, ++ 116, 128, 128, ++ 117, 128, 128, ++ 118, 128, 128, ++ 119, 128, 128, ++ 120, 128, 128, ++ 121, 128, 128, ++ 122, 128, 128, ++ 123, 128, 128, ++ 124, 128, 128, ++ 125, 128, 128, ++ 126, 128, 128, ++ 127, 128, 128, ++ 128, 128, 128, ++ 129, 128, 128, ++ 130, 128, 128, ++ 131, 128, 128, ++ 132, 128, 128, ++ 133, 128, 128, ++ 134, 128, 128, ++ 135, 128, 128, ++ 136, 128, 128, ++ 137, 128, 128, ++ 138, 128, 128, ++ 139, 128, 128, ++ 140, 128, 128, ++ 141, 128, 128, ++ 142, 128, 128, ++ 143, 128, 128, ++ 144, 128, 128, ++ 145, 128, 128, ++ 146, 128, 128, ++ 147, 128, 128, ++ 148, 128, 128, ++ 149, 128, 128, ++ 150, 128, 128, ++ 151, 128, 128, ++ 152, 128, 128, ++ 153, 128, 128, ++ 154, 128, 128, ++ 155, 128, 128, ++ 156, 128, 128, ++ 157, 128, 128, ++ 158, 128, 128, ++ 159, 128, 128, ++ 160, 128, 128, ++ 161, 128, 128, ++ 162, 128, 128, ++ 163, 128, 128, ++ 164, 128, 128, ++ 165, 128, 128, ++ 166, 128, 128, ++ 167, 128, 128, ++ 168, 128, 128, ++ 169, 128, 128, ++ 170, 128, 128, ++ 171, 128, 128, ++ 172, 128, 128, ++ 173, 128, 128, ++ 174, 128, 128, ++ 175, 128, 128, ++ 176, 128, 128, ++ 177, 128, 128, ++ 178, 128, 128, ++ 179, 128, 128, ++ 180, 128, 128, ++ 181, 128, 128, ++ 182, 128, 128, ++ 183, 128, 128, ++ 184, 128, 128, ++ 185, 128, 128, ++ 186, 128, 128, ++ 187, 128, 128, ++ 188, 128, 128, ++ 189, 128, 128, ++ 190, 128, 128, ++ 191, 128, 128, ++ 192, 128, 128, ++ 193, 128, 128, ++ 194, 128, 128, ++ 195, 128, 128, ++ 196, 128, 128, ++ 197, 128, 128, ++ 198, 128, 128, ++ 199, 128, 128, ++ 200, 128, 128, ++ 201, 128, 128, ++ 202, 128, 128, ++ 203, 128, 128, ++ 204, 128, 128, ++ 205, 128, 128, ++ 206, 128, 128, ++ 207, 128, 128, ++ 208, 128, 128, ++ 209, 128, 128, ++ 210, 128, 128, ++ 211, 128, 128, ++ 212, 128, 128, ++ 213, 128, 128, ++ 214, 128, 128, ++ 215, 128, 128, ++ 216, 128, 128, ++ 217, 128, 128, ++ 218, 128, 128, ++ 219, 128, 128, ++ 220, 128, 128, ++ 221, 128, 128, ++ 222, 128, 128, ++ 223, 128, 128, ++ 224, 128, 128, ++ 225, 128, 128, ++ 226, 128, 128, ++ 227, 128, 128, ++ 228, 128, 128, ++ 229, 128, 128, ++ 230, 128, 128, ++ 231, 128, 128, ++ 232, 128, 128, ++ 233, 128, 128, ++ 234, 128, 128, ++ 235, 128, 128, ++ 236, 128, 128, ++ 237, 128, 128, ++ 238, 128, 128, ++ 239, 128, 128, ++ 240, 128, 128, ++ 241, 128, 128, ++ 242, 128, 128, ++ 243, 128, 128, ++ 244, 128, 128, ++ 245, 128, 128, ++ 246, 128, 128, ++ 247, 128, 128, ++ 248, 128, 128, ++ 249, 128, 128, ++ 250, 128, 128, ++ 251, 128, 128, ++ 252, 128, 128, ++ 253, 128, 128, ++ 254, 128, 128, ++ 255, 128, 128, ++ }, ++ .blend_table = { ++ 0, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ }, ++ .color_format = GK_FB_COLOR_CLUT_8BPP, ++ .conversion_buf = { ++ .available = 0, ++ .ping_buf = NULL, ++ .ping_buf_size = 0, ++ .pong_buf = NULL, ++ .pong_buf_size = 0, ++ }, ++ .use_prealloc = 0, ++ .prealloc_line_length = 0, ++ ++ .pan_display = NULL, ++ .setcmap = NULL, ++ .check_var = NULL, ++ .set_par = NULL, ++ .set_blank = NULL, ++ ++ .proc_fb_info = NULL, ++ .proc_file = NULL, ++}; ++ ++struct platform_device gk_fb0 = { ++ .name = "gk-fb", ++ .id = 0, ++ .resource = NULL, ++ .num_resources = 0, ++ .dev = { ++ .platform_data = &gk_platform_fb0, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++ ++static struct gk_platform_fb gk_platform_fb1 = { ++ .screen_var = { ++ .xres = 720, ++ .yres = 480, ++ .xres_virtual = 720, ++ .yres_virtual = 480, ++ .xoffset = 0, ++ .yoffset = 0, ++ .bits_per_pixel = 8, ++ .red = {.offset = 0, .length = 8, .msb_right = 0}, ++ .green = {.offset = 0, .length = 8, .msb_right = 0}, ++ .blue = {.offset = 0, .length = 8, .msb_right = 0}, ++ .activate = FB_ACTIVATE_NOW, ++ .height = -1, ++ .width = -1, ++ .pixclock = 36101, ++ .left_margin = 24, ++ .right_margin = 96, ++ .upper_margin = 10, ++ .lower_margin = 32, ++ .hsync_len = 40, ++ .vsync_len = 3, ++ .vmode = FB_VMODE_NONINTERLACED, ++ }, ++ .screen_fix = { ++ .id = "GK FB", ++ .type = FB_TYPE_PACKED_PIXELS, ++ .visual = FB_VISUAL_PSEUDOCOLOR, ++ .xpanstep = 1, ++ .ypanstep = 1, ++ .ywrapstep = 1, ++ .accel = FB_ACCEL_NONE, ++ .line_length = 0, ++ .smem_start = 0, ++ .smem_len = 0, ++ }, ++ .dsp_status = GK_DSP_UNKNOWN_MODE, ++ .fb_status = GK_FB_UNKNOWN_MODE, ++ .clut_table = { ++ 0, 128, 128, ++ 1, 128, 128, ++ 2, 128, 128, ++ 3, 128, 128, ++ 4, 128, 128, ++ 5, 128, 128, ++ 6, 128, 128, ++ 7, 128, 128, ++ 8, 128, 128, ++ 9, 128, 128, ++ 10, 128, 128, ++ 11, 128, 128, ++ 12, 128, 128, ++ 13, 128, 128, ++ 14, 128, 128, ++ 15, 128, 128, ++ 16, 128, 128, ++ 17, 128, 128, ++ 18, 128, 128, ++ 19, 128, 128, ++ 20, 128, 128, ++ 21, 128, 128, ++ 22, 128, 128, ++ 23, 128, 128, ++ 24, 128, 128, ++ 25, 128, 128, ++ 26, 128, 128, ++ 27, 128, 128, ++ 28, 128, 128, ++ 29, 128, 128, ++ 30, 128, 128, ++ 31, 128, 128, ++ 32, 128, 128, ++ 33, 128, 128, ++ 34, 128, 128, ++ 35, 128, 128, ++ 36, 128, 128, ++ 37, 128, 128, ++ 38, 128, 128, ++ 39, 128, 128, ++ 40, 128, 128, ++ 41, 128, 128, ++ 42, 128, 128, ++ 43, 128, 128, ++ 44, 128, 128, ++ 45, 128, 128, ++ 46, 128, 128, ++ 47, 128, 128, ++ 48, 128, 128, ++ 49, 128, 128, ++ 50, 128, 128, ++ 51, 128, 128, ++ 52, 128, 128, ++ 53, 128, 128, ++ 54, 128, 128, ++ 55, 128, 128, ++ 56, 128, 128, ++ 57, 128, 128, ++ 58, 128, 128, ++ 59, 128, 128, ++ 60, 128, 128, ++ 61, 128, 128, ++ 62, 128, 128, ++ 63, 128, 128, ++ 64, 128, 128, ++ 65, 128, 128, ++ 66, 128, 128, ++ 67, 128, 128, ++ 68, 128, 128, ++ 69, 128, 128, ++ 70, 128, 128, ++ 71, 128, 128, ++ 72, 128, 128, ++ 73, 128, 128, ++ 74, 128, 128, ++ 75, 128, 128, ++ 76, 128, 128, ++ 77, 128, 128, ++ 78, 128, 128, ++ 79, 128, 128, ++ 80, 128, 128, ++ 81, 128, 128, ++ 82, 128, 128, ++ 83, 128, 128, ++ 84, 128, 128, ++ 85, 128, 128, ++ 86, 128, 128, ++ 87, 128, 128, ++ 88, 128, 128, ++ 89, 128, 128, ++ 90, 128, 128, ++ 91, 128, 128, ++ 92, 128, 128, ++ 93, 128, 128, ++ 94, 128, 128, ++ 95, 128, 128, ++ 96, 128, 128, ++ 97, 128, 128, ++ 98, 128, 128, ++ 99, 128, 128, ++ 100, 128, 128, ++ 101, 128, 128, ++ 102, 128, 128, ++ 103, 128, 128, ++ 104, 128, 128, ++ 105, 128, 128, ++ 106, 128, 128, ++ 107, 128, 128, ++ 108, 128, 128, ++ 109, 128, 128, ++ 110, 128, 128, ++ 111, 128, 128, ++ 112, 128, 128, ++ 113, 128, 128, ++ 114, 128, 128, ++ 115, 128, 128, ++ 116, 128, 128, ++ 117, 128, 128, ++ 118, 128, 128, ++ 119, 128, 128, ++ 120, 128, 128, ++ 121, 128, 128, ++ 122, 128, 128, ++ 123, 128, 128, ++ 124, 128, 128, ++ 125, 128, 128, ++ 126, 128, 128, ++ 127, 128, 128, ++ 128, 128, 128, ++ 129, 128, 128, ++ 130, 128, 128, ++ 131, 128, 128, ++ 132, 128, 128, ++ 133, 128, 128, ++ 134, 128, 128, ++ 135, 128, 128, ++ 136, 128, 128, ++ 137, 128, 128, ++ 138, 128, 128, ++ 139, 128, 128, ++ 140, 128, 128, ++ 141, 128, 128, ++ 142, 128, 128, ++ 143, 128, 128, ++ 144, 128, 128, ++ 145, 128, 128, ++ 146, 128, 128, ++ 147, 128, 128, ++ 148, 128, 128, ++ 149, 128, 128, ++ 150, 128, 128, ++ 151, 128, 128, ++ 152, 128, 128, ++ 153, 128, 128, ++ 154, 128, 128, ++ 155, 128, 128, ++ 156, 128, 128, ++ 157, 128, 128, ++ 158, 128, 128, ++ 159, 128, 128, ++ 160, 128, 128, ++ 161, 128, 128, ++ 162, 128, 128, ++ 163, 128, 128, ++ 164, 128, 128, ++ 165, 128, 128, ++ 166, 128, 128, ++ 167, 128, 128, ++ 168, 128, 128, ++ 169, 128, 128, ++ 170, 128, 128, ++ 171, 128, 128, ++ 172, 128, 128, ++ 173, 128, 128, ++ 174, 128, 128, ++ 175, 128, 128, ++ 176, 128, 128, ++ 177, 128, 128, ++ 178, 128, 128, ++ 179, 128, 128, ++ 180, 128, 128, ++ 181, 128, 128, ++ 182, 128, 128, ++ 183, 128, 128, ++ 184, 128, 128, ++ 185, 128, 128, ++ 186, 128, 128, ++ 187, 128, 128, ++ 188, 128, 128, ++ 189, 128, 128, ++ 190, 128, 128, ++ 191, 128, 128, ++ 192, 128, 128, ++ 193, 128, 128, ++ 194, 128, 128, ++ 195, 128, 128, ++ 196, 128, 128, ++ 197, 128, 128, ++ 198, 128, 128, ++ 199, 128, 128, ++ 200, 128, 128, ++ 201, 128, 128, ++ 202, 128, 128, ++ 203, 128, 128, ++ 204, 128, 128, ++ 205, 128, 128, ++ 206, 128, 128, ++ 207, 128, 128, ++ 208, 128, 128, ++ 209, 128, 128, ++ 210, 128, 128, ++ 211, 128, 128, ++ 212, 128, 128, ++ 213, 128, 128, ++ 214, 128, 128, ++ 215, 128, 128, ++ 216, 128, 128, ++ 217, 128, 128, ++ 218, 128, 128, ++ 219, 128, 128, ++ 220, 128, 128, ++ 221, 128, 128, ++ 222, 128, 128, ++ 223, 128, 128, ++ 224, 128, 128, ++ 225, 128, 128, ++ 226, 128, 128, ++ 227, 128, 128, ++ 228, 128, 128, ++ 229, 128, 128, ++ 230, 128, 128, ++ 231, 128, 128, ++ 232, 128, 128, ++ 233, 128, 128, ++ 234, 128, 128, ++ 235, 128, 128, ++ 236, 128, 128, ++ 237, 128, 128, ++ 238, 128, 128, ++ 239, 128, 128, ++ 240, 128, 128, ++ 241, 128, 128, ++ 242, 128, 128, ++ 243, 128, 128, ++ 244, 128, 128, ++ 245, 128, 128, ++ 246, 128, 128, ++ 247, 128, 128, ++ 248, 128, 128, ++ 249, 128, 128, ++ 250, 128, 128, ++ 251, 128, 128, ++ 252, 128, 128, ++ 253, 128, 128, ++ 254, 128, 128, ++ 255, 128, 128, ++ }, ++ .blend_table = { ++ 0, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ }, ++ .color_format = GK_FB_COLOR_CLUT_8BPP, ++ .conversion_buf = { ++ .available = 0, ++ .ping_buf = NULL, ++ .ping_buf_size = 0, ++ .pong_buf = NULL, ++ .pong_buf_size = 0, ++ }, ++ .use_prealloc = 0, ++ .prealloc_line_length = 0, ++ ++ .pan_display = NULL, ++ .setcmap = NULL, ++ .check_var = NULL, ++ .set_par = NULL, ++ .set_blank = NULL, ++ ++ .proc_fb_info = NULL, ++ .proc_file = NULL, ++}; ++ ++struct platform_device gk_fb1 = { ++ .name = "gk-fb", ++ .id = 1, ++ .resource = NULL, ++ .num_resources = 0, ++ .dev = { ++ .platform_data = &gk_platform_fb1, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++ ++int gk_fb_get_platform_info(u32 fb_id, ++ struct gk_platform_fb *platform_info) ++{ ++ u32 status = -EPERM; ++ ++ if (fb_id == 0) { ++ mutex_lock(&gk_platform_fb0.lock); ++ memcpy(platform_info, &gk_platform_fb0, ++ sizeof(struct gk_platform_fb)); ++ mutex_unlock(&gk_platform_fb0.lock); ++ ++ status = 0; ++ } else ++ if (fb_id == 1) { ++ mutex_lock(&gk_platform_fb1.lock); ++ memcpy(platform_info, &gk_platform_fb1, ++ sizeof(struct gk_platform_fb)); ++ mutex_unlock(&gk_platform_fb1.lock); ++ ++ status = 0; ++ } ++ ++ ++ return status; ++} ++EXPORT_SYMBOL(gk_fb_get_platform_info); ++ ++int gk_fb_set_media_info(u32 fb_id, struct gk_fb_media_info *media) ++{ ++ u32 status = -EPERM; ++ ++ if (fb_id == 0) { ++ mutex_lock(&gk_platform_fb0.lock); ++ gk_platform_fb0.screen_var = media->screen_var; ++ gk_platform_fb0.screen_fix = media->screen_fix; ++ gk_platform_fb0.pan_display = media->pan_display; ++ gk_platform_fb0.setcmap = media->setcmap; ++ gk_platform_fb0.check_var = media->check_var; ++ gk_platform_fb0.set_par = media->set_par; ++ gk_platform_fb0.set_blank = media->set_blank; ++ gk_platform_fb0.dsp_status = media->dsp_status; ++ mutex_unlock(&gk_platform_fb0.lock); ++ ++ status = 0; ++ } else ++ if (fb_id == 1) { ++ mutex_lock(&gk_platform_fb1.lock); ++ gk_platform_fb1.screen_var = media->screen_var; ++ gk_platform_fb1.screen_fix = media->screen_fix; ++ gk_platform_fb1.pan_display = media->pan_display; ++ gk_platform_fb1.setcmap = media->setcmap; ++ gk_platform_fb1.check_var = media->check_var; ++ gk_platform_fb1.set_par = media->set_par; ++ gk_platform_fb1.set_blank = media->set_blank; ++ gk_platform_fb1.dsp_status = media->dsp_status; ++ mutex_unlock(&gk_platform_fb1.lock); ++ ++ status = 0; ++ } ++ ++ return status; ++} ++EXPORT_SYMBOL(gk_fb_set_media_info); ++ ++int gk_fb_update_info(u32 fb_id, int xres, int yres, ++ int xvirtual, int yvirtual, int format, u32 bits_per_pixel, ++ u32 smem_start, u32 smem_len) ++{ ++ u32 status = -EPERM; ++ ++ if (fb_id == 0) { ++ mutex_lock(&gk_platform_fb0.lock); ++ gk_platform_fb0.screen_var.xres = xres; ++ gk_platform_fb0.screen_var.yres = yres; ++ gk_platform_fb0.screen_var.xres_virtual = xvirtual; ++ gk_platform_fb0.screen_var.yres_virtual = yvirtual; ++ gk_platform_fb0.screen_var.bits_per_pixel = ++ bits_per_pixel; ++ gk_platform_fb0.color_format = format; ++ gk_platform_fb0.use_prealloc = 1; ++ gk_platform_fb0.screen_fix.smem_start = smem_start; ++ gk_platform_fb0.screen_fix.smem_len = smem_len; ++ mutex_unlock(&gk_platform_fb0.lock); ++ ++ status = 0; ++ } else ++ if (fb_id == 1) { ++ mutex_lock(&gk_platform_fb1.lock); ++ gk_platform_fb1.screen_var.xres = xres; ++ gk_platform_fb1.screen_var.yres = yres; ++ gk_platform_fb1.screen_var.xres_virtual = xvirtual; ++ gk_platform_fb1.screen_var.yres_virtual = yvirtual; ++ gk_platform_fb1.screen_var.bits_per_pixel = ++ bits_per_pixel; ++ gk_platform_fb1.color_format = format; ++ gk_platform_fb1.use_prealloc = 1; ++ gk_platform_fb1.screen_fix.smem_start = smem_start; ++ gk_platform_fb1.screen_fix.smem_len = smem_len; ++ mutex_unlock(&gk_platform_fb1.lock); ++ ++ status = 0; ++ } ++ ++ pr_debug("%s %d: %dx%d %dx%d %d %d 0x%08x:0x%08x\n", __func__, fb_id, ++ xres, yres, xvirtual, yvirtual, ++ format, bits_per_pixel, smem_start, smem_len); ++ ++ return status; ++} ++#if 1 ++int __init gk_init_fb(void) ++{ ++ printk("init fb...\n"); ++ ++ mutex_init(&gk_platform_fb0.lock); ++ init_waitqueue_head(&gk_platform_fb0.proc_wait); ++ ++ mutex_init(&gk_platform_fb1.lock); ++ init_waitqueue_head(&gk_platform_fb1.proc_wait); ++ ++ return 0; ++} ++#endif ++ +diff --git a/arch/arm/plat-goke/gk_gpio.c b/arch/arm/plat-goke/gk_gpio.c +new file mode 100644 +index 00000000..68e7a446 +--- /dev/null ++++ b/arch/arm/plat-goke/gk_gpio.c +@@ -0,0 +1,1123 @@ ++/* ++ * arch/arm/mach-gk7101/gpio.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* ++ m instances per chip ++ n banks per instance ++ max 64 pins per bank ++ pin: used as pin number at chip ++ offset: used as offset at it's instance ++ pin = it's instance base number + offset ++*/ ++ ++static DEFINE_MUTEX(gk_gpio_mtx); ++extern struct gk_gpio_inst gk_gpio_insts[CONFIG_GK_GPIO_INSTANCES]; ++ ++void GH_GPIO_set_INPUT_CFG_in_sel(u8 index, u8 data) ++{ ++ GH_GPIO_INPUT_CFG_S in_data; ++ in_data.all = gk_gpio_insts[0].input_cfg[index]; ++ in_data.bitc.in_sel = data; ++ gk_gpio_insts[0].input_cfg[index] = in_data.all; ++ gk_gpio_writel(gk_gpio_insts[0].gpio_bank[0].base_reg + REG_GPIO_INPUT_CFG_OFFSET + (index * 0x4), in_data.all); ++} ++ ++/* ==========================================================================*/ ++#define to_gk_gpio_chip(c) \ ++ container_of(c, struct gk_gpio_bank, chip) ++ ++static struct gk_gpio_inst* gk_gpio_id_to_inst(u32 pin) ++{ ++ u32 i; ++ u32 j; ++ if (pin < 0) ++ { ++ return NULL; ++ } ++ else ++ { ++ for(i=0; i= gk_gpio_insts[i].gpio_bank[j].chip.base) && ++ (pin < (gk_gpio_insts[i].gpio_bank[j].chip.base + ++ gk_gpio_insts[i].gpio_bank[j].chip.ngpio))) ++ { ++ return &gk_gpio_insts[i]; ++ } ++ } ++ } ++ } ++ return NULL; ++} ++ ++static struct gk_gpio_bank* gk_gpio_id_to_bank(u32 pin) ++{ ++ u32 i; ++ u32 j; ++ if (pin< 0) ++ { ++ return NULL; ++ } ++ else ++ { ++ for(i=0; i= gk_gpio_insts[i].gpio_bank[j].chip.base) && ++ (pin < (gk_gpio_insts[i].gpio_bank[j].chip.base + ++ gk_gpio_insts[i].gpio_bank[j].chip.ngpio))) ++ { ++ return &gk_gpio_insts[i].gpio_bank[j]; ++ } ++ } ++ } ++ } ++ return NULL; ++} ++ ++ ++ ++int gk_gpio_request(struct gpio_chip *chip, u32 offset) ++{ ++ int ret = 0; ++ struct gk_gpio_bank *bank; ++ u32 pin; ++ ++ bank = to_gk_gpio_chip(chip); ++ mutex_lock(&gk_gpio_mtx); ++ ++ pin = offset + chip->base; ++ if (test_bit(pin, (const volatile unsigned long *) ++ gk_gpio_insts[bank->index].gpio_valid)) ++ { ++ if (test_bit(pin, (const volatile unsigned long *) ++ gk_gpio_insts[bank->index].gpio_freeflag)) ++ { ++ __clear_bit(pin, (volatile unsigned long *) ++ gk_gpio_insts[bank->index].gpio_freeflag); ++ } ++ else ++ { ++ ret = -EACCES; ++ } ++ } ++ else ++ { ++ ret = -EPERM; ++ } ++ ++ mutex_unlock(&gk_gpio_mtx); ++ ++ return ret; ++} ++ ++void gk_gpio_free(struct gpio_chip *chip, u32 offset) ++{ ++ u32 pin; ++ struct gk_gpio_bank *bank; ++ ++ mutex_lock(&gk_gpio_mtx); ++ ++ pin = offset + chip->base; ++ bank = to_gk_gpio_chip(chip); ++ ++ __set_bit(pin, (volatile unsigned long *) ++ gk_gpio_insts[bank->index].gpio_freeflag); ++ ++ mutex_unlock(&gk_gpio_mtx); ++} ++ ++int gk_gpio_func_config(u32 pin, u32 func) ++{ ++ int ret = 0; ++ unsigned long flags; ++ struct gk_gpio_bank *bank; ++ ++ bank = gk_gpio_id_to_bank(pin); ++ if (bank == NULL) ++ { ++ pr_err("%s: invalid GPIO %d for func %d.\n", __func__, pin, func); ++ return -EINVAL; ++ } ++ spin_lock_irqsave(&bank->lock, flags); ++ ++ if(GPIO_GET_FUNC(func) > GPIO_FUNC_INOUT) ++ { ++ pr_err("%s: invalid GPIO func %d for GPIO:%d.\n", __func__, func, pin); ++ spin_unlock_irqrestore(&bank->lock, flags); ++ return -EINVAL; ++ } ++ ++ //printk("gpio==============[%s %d]\n", __func__, __LINE__); ++ ret = gk_gpio_set_type(bank, pin, func); ++ spin_unlock_irqrestore(&bank->lock, flags); ++ ++ return ret; ++ ++} ++ ++int gk_gpio_direction_input(struct gpio_chip *chip, u32 offset, int val) ++{ ++ int ret = 0; ++ u32 pin; ++ ++ pin = offset + chip->base; ++ if (val == 0) ++ ret = gk_gpio_func_config(pin, GPIO_TYPE_INPUT_0); ++ else ++ ret = gk_gpio_func_config(pin, GPIO_TYPE_INPUT_1); ++ return ret; ++} ++ ++static inline int gk_gpio_inline_get(struct gk_gpio_bank *bank, u32 pin) ++{ ++ unsigned long flags; ++ u32 val = 0; ++ ++ spin_lock_irqsave(&bank->lock, flags); ++ ++ if((pin - bank->chip.base) < 32) ++ { ++ val = gk_gpio_readl(bank->base_reg + REG_GPIO_DIN_LOW_OFFSET); ++ } ++ else ++ { ++ val = gk_gpio_readl(bank->base_reg + REG_GPIO_DIN_HIGH_OFFSET); ++ } ++ ++ spin_unlock_irqrestore(&bank->lock, flags); ++ ++ val = (val >> (pin % 32)) & 0x1; ++ return (val ? GPIO_HIGH : GPIO_LOW); ++ ++} ++ ++int gk_gpio_get(u32 pin) ++{ ++ struct gk_gpio_bank *bank; ++ ++ bank = gk_gpio_id_to_bank(pin); ++ if (bank == NULL) ++ { ++ pr_err("%s: invalid GPIO %d.\n", __func__, pin); ++ return 0; ++ } ++ ++ return gk_gpio_inline_get(bank, (u32)pin); ++} ++EXPORT_SYMBOL(gk_gpio_get); ++ ++int gk_gpio_get_ex(struct gpio_chip *chip, unsigned offset) ++{ ++ u32 pin; ++ ++ pin = offset + chip->base; ++ return gk_gpio_get(pin); ++} ++EXPORT_SYMBOL(gk_gpio_get_ex); ++ ++void gk_gpio_set_out(u32 pin, u32 value) ++{ ++ struct gk_gpio_bank* bank; ++ GH_GPIO_OUTPUT_CFG_S data; ++ bank = gk_gpio_id_to_bank(pin); ++ data.all = gk_gpio_insts[bank->index].output_cfg[pin]; ++ data.bitc.out_sel = 1; ++ if (value == GPIO_LOW) ++ { ++ data.bitc.out_sel &= ~0x01; ++ } ++ else ++ { ++ data.bitc.out_sel |= 0x01; ++ } ++ gk_gpio_writel(bank->base_reg + REG_GPIO_OUTPUT_CFG_OFFSET + ((pin - bank->chip.base) * 0x4), ++ data.all); ++ gk_gpio_insts[bank->index].output_cfg[pin] = data.all; ++} ++EXPORT_SYMBOL(gk_gpio_set_out); ++ ++static inline void gk_gpio_inline_set(struct gk_gpio_bank *bank, u32 pin, int value) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&bank->lock, flags); ++ gk_gpio_set_out(pin, value); ++ spin_unlock_irqrestore(&bank->lock, flags); ++} ++ ++int gk_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int val) ++{ ++ int ret = 0; ++ u32 pin; ++ struct gk_gpio_bank *bank; ++ ++ pin = offset + chip->base; ++ ++ bank = gk_gpio_id_to_bank(pin); ++ ret = gk_gpio_func_config(pin, val ? GPIO_TYPE_OUTPUT_1 : GPIO_TYPE_OUTPUT_0); ++ gk_gpio_inline_set(bank, pin, val); ++ ++ return ret; ++} ++ ++void gk_gpio_set(struct gpio_chip *chip, unsigned offset, int val) ++{ ++ struct gk_gpio_bank *bank; ++ u32 pin; ++ ++ pin = offset + chip->base; ++ ++ bank = gk_gpio_id_to_bank(pin); ++ if (bank == NULL) ++ { ++ pr_err("%s: invalid GPIO %d.\n", __func__, pin); ++ return; ++ } ++ gk_gpio_inline_set(bank, pin, val); ++} ++EXPORT_SYMBOL(gk_gpio_set); ++ ++int gk_gpio_to_irq(struct gpio_chip *chip, unsigned offset) ++{ ++ struct gk_gpio_bank *bank; ++ u32 pin; ++ pin = offset + chip->base; ++ ++ bank = to_gk_gpio_chip(chip); ++ return gk_gpio_insts[bank->index].irq_no; ++} ++ ++void gk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) ++{ ++ int i; ++ struct gk_gpio_bank *bank; ++ u32 afsel; ++ u32 lmask; ++ u32 data; ++ u32 hmask; ++ unsigned long flags; ++ ++ bank = to_gk_gpio_chip(chip); ++ ++ spin_lock_irqsave(&bank->lock, flags); ++ afsel = gk_gpio_readl(gk_gpio_insts[bank->index].base_bus + REG_GPIO_PER_SEL_OFFSET); ++ lmask = gk_gpio_readl(bank->base_reg + REG_GPIO_IE_LOW_OFFSET); ++ hmask = gk_gpio_readl(bank->base_reg + REG_GPIO_IE_HIGH_OFFSET); ++ data = gk_gpio_readl(gk_gpio_insts[bank->index].base_bus + REG_GPIO_INT_EN_OFFSET); ++ spin_unlock_irqrestore(&bank->lock, flags); ++ ++ seq_printf(s, "GPIO_BASE:\t0x%08X\n", bank->base_reg); ++ seq_printf(s, "GPIO_PSEL:\t0x%08X\n", afsel); ++ seq_printf(s, "GPIO_MASK:\t0x%08X:0x%08X\n", hmask, lmask); ++ seq_printf(s, "GPIO_GPEN:\t0x%08X\n", data); ++ ++ for (i = 0; i < chip->ngpio; i++) ++ { ++ seq_printf(s, "GPIO %d: HW\n", (chip->base + i)); ++ } ++} ++ ++int gk_gpio_set_type(struct gk_gpio_bank* bank, u32 pin, u32 type) ++{ ++ GH_GPIO_OUTPUT_CFG_S out_data; ++ GH_GPIO_INPUT_CFG_S in_data; ++ GH_PLL_IOCTRL_GPIO_S io_data; ++ out_data.all = gk_gpio_insts[bank->index].output_cfg[pin]; ++ switch(GPIO_GET_FUNC(type)) ++ { ++ case GPIO_FUNC_OUT: // out ++ out_data.bitc.out_sel = GPIO_GET_OUT_SEL(type); ++ out_data.bitc.oen_sel = GPIO_GET_OEN_SEL(type); ++ break; ++ case GPIO_FUNC_IN: // in ++ if(GPIO_GET_IN_SEL(type) >= 2) ++ { ++ out_data.bitc.out_sel = GPIO_GET_OUT_SEL(type); ++ out_data.bitc.oen_sel = GPIO_GET_OEN_SEL(type); ++ in_data.all = gk_gpio_insts[bank->index].input_cfg[GPIO_GET_IN_SEL(type) - 2]; ++ in_data.bitc.in_sel = pin; ++ gk_gpio_writel(bank->base_reg + REG_GPIO_INPUT_CFG_OFFSET + ((GPIO_GET_IN_SEL(type) - 2) * 0x4), ++ in_data.all); ++ gk_gpio_insts[bank->index].input_cfg[GPIO_GET_IN_SEL(type) - 2] = in_data.all; ++ } ++ else ++ { ++ out_data.bitc.out_sel = GPIO_GET_OUT_SEL(type); ++ out_data.bitc.oen_sel = GPIO_GET_OEN_SEL(type); ++ } ++ break; ++ case GPIO_FUNC_INOUT: // in+out ++ // don't change, otherwise if out_sel at first might output a 0, then change to 1 ++ in_data.all = gk_gpio_insts[bank->index].input_cfg[GPIO_GET_IN_SEL(type) - 2]; ++ in_data.bitc.in_sel = pin; ++ gk_gpio_writel(bank->base_reg + REG_GPIO_INPUT_CFG_OFFSET + ((GPIO_GET_IN_SEL(type) - 2) * 0x4), ++ in_data.all); ++ gk_gpio_insts[bank->index].input_cfg[GPIO_GET_IN_SEL(type) - 2] = in_data.all; ++ out_data.bitc.oen_sel = GPIO_GET_OEN_SEL(type); ++ out_data.bitc.out_sel = GPIO_GET_OUT_SEL(type); ++ break; ++ default: ++ return -EINVAL; ++ } ++ out_data.bitc.oen_invert = GPIO_GET_OEN_INVERT(type); ++ out_data.bitc.out_invert = GPIO_GET_OUT_INVERT(type); ++ gk_gpio_writel(bank->base_reg + REG_GPIO_OUTPUT_CFG_OFFSET + ((pin - bank->chip.base) * 0x4), ++ out_data.all); ++ gk_gpio_insts[bank->index].output_cfg[pin] = out_data.all; ++ // Pull up/down & 2mA...... ++#if defined(CONFIG_ARCH_GK710XS) ++ if(pin<4)//gpio0-3 ++ { ++ io_data.all = gk_gpio_readl((bank->io_reg + ((((55-pin)-bank->chip.base)/0x04) * 0x04))); ++ switch(pin%4) ++ { ++ case 0: ++ io_data.bitc.io2 = GPIO_GET_IOCTRL(type); ++ break; ++ case 1: ++ io_data.bitc.io0 = GPIO_GET_IOCTRL(type); ++ break; ++ case 2: ++ io_data.bitc.io1 = GPIO_GET_IOCTRL(type); ++ break; ++ case 3: ++ io_data.bitc.io3 = GPIO_GET_IOCTRL(type); ++ break; ++ } ++ gk_gpio_writel((bank->io_reg + ((((55-pin)-bank->chip.base)/0x04) * 0x04)), io_data.all); ++ } ++ else if(pin<52)//gpio4-51 ++ { ++ io_data.all = gk_gpio_readl((bank->io_reg + ((((55-pin)-bank->chip.base)/0x04) * 0x04))); ++ switch(pin%4) ++ { ++ case 0: ++ io_data.bitc.io1 = GPIO_GET_IOCTRL(type); ++ break; ++ case 1: ++ io_data.bitc.io2 = GPIO_GET_IOCTRL(type); ++ break; ++ case 2: ++ io_data.bitc.io0 = GPIO_GET_IOCTRL(type); ++ break; ++ case 3: ++ io_data.bitc.io3 = GPIO_GET_IOCTRL(type); ++ break; ++ } ++ gk_gpio_writel((bank->io_reg + ((((55-pin)-bank->chip.base)/0x04) * 0x04)), io_data.all); ++ ++ } ++ else if(pin<56)//gpio52-55 ++ { ++ io_data.all = gk_gpio_readl((bank->io_reg + ((((55-pin)-bank->chip.base)/0x04) * 0x04))); ++ switch(pin%4) ++ { ++ case 0: ++ io_data.bitc.io1 = GPIO_GET_IOCTRL(type); ++ break; ++ case 1: ++ io_data.bitc.io0 = GPIO_GET_IOCTRL(type); ++ break; ++ case 2: ++ io_data.bitc.io2 = GPIO_GET_IOCTRL(type); ++ break; ++ case 3: ++ io_data.bitc.io3 = GPIO_GET_IOCTRL(type); ++ break; ++ } ++ gk_gpio_writel((bank->io_reg + ((((55-pin)-bank->chip.base)/0x04) * 0x04)), io_data.all); ++ } ++ else//gpio56-62 ++ { ++ io_data.all = gk_gpio_readl((bank->io_reg + (((pin-bank->chip.base)/0x04) * 0x04))); ++ switch(pin%4) ++ { ++ case 0: ++ io_data.bitc.io0 = GPIO_GET_IOCTRL(type); ++ break; ++ case 1: ++ io_data.bitc.io1 = GPIO_GET_IOCTRL(type); ++ break; ++ case 2: ++ io_data.bitc.io2 = GPIO_GET_IOCTRL(type); ++ break; ++ case 3: ++ io_data.bitc.io3 = GPIO_GET_IOCTRL(type); ++ break; ++ } ++ gk_gpio_writel((bank->io_reg + (((pin-bank->chip.base)/0x04) * 0x04)), io_data.all); ++ } ++#else ++ io_data.all = gk_gpio_readl((bank->io_reg - (((pin-bank->chip.base)/0x04) * 0x04))); ++ switch(pin%4) ++ { ++ case 0: ++ io_data.bitc.io0 = GPIO_GET_IOCTRL(type); ++ break; ++ case 1: ++ io_data.bitc.io1 = GPIO_GET_IOCTRL(type); ++ break; ++ case 2: ++ io_data.bitc.io2 = GPIO_GET_IOCTRL(type); ++ break; ++ case 3: ++ io_data.bitc.io3 = GPIO_GET_IOCTRL(type); ++ break; ++ } ++ gk_gpio_writel((bank->io_reg - (((pin-bank->chip.base)/0x04) * 0x04)), io_data.all); ++#endif ++ ++ return(0); ++} ++ ++void gk_gpio_config(u32 pin, u32 func) ++{ ++ if(gk_gpio_func_config((u32)pin, func)) ++ { ++ pr_err("%s: failed to configure GPIO %d for func %d.\n", __func__, pin, func); ++ } ++} ++EXPORT_SYMBOL(gk_gpio_config); ++ ++void gk_gpio_raw_lock(u32 pin, unsigned long *pflags) ++{ ++ struct gk_gpio_bank *bank; ++ bank = gk_gpio_id_to_bank(pin); ++ if (bank == NULL) ++ { ++ pr_err("%s: invalid GPIO %d.\n", __func__, pin); ++ return; ++ } ++ spin_lock_irqsave(&bank->lock, *pflags); ++} ++ ++void gk_gpio_raw_unlock(u32 pin, unsigned long *pflags) ++{ ++ struct gk_gpio_bank *bank; ++ bank = gk_gpio_id_to_bank(pin); ++ if (bank == NULL) ++ { ++ pr_err("%s: invalid GPIO %d.\n", __func__, pin); ++ return; ++ } ++ spin_unlock_irqrestore(&bank->lock, *pflags); ++} ++ ++u32 gk_gpio_suspend(u32 level) ++{ ++ u32 i; ++ u32 j; ++ unsigned long flags; ++ ++ for (i = 0; i < CONFIG_GK_GPIO_INSTANCES; i++) ++ { ++ for (j = 0; j < gk_gpio_insts[i].bank_num; j++) ++ { ++ spin_lock_irqsave(&gk_gpio_insts[i].gpio_bank[j].lock, flags); ++ gk_gpio_insts[i].gpio_bank[j].pm_info.isl_reg = ++ gk_gpio_readl(gk_gpio_insts[i].gpio_bank[j].base_reg + REG_GPIO_IS_LOW_OFFSET); ++ gk_gpio_insts[i].gpio_bank[j].pm_info.ish_reg = ++ gk_gpio_readl(gk_gpio_insts[i].gpio_bank[j].base_reg + REG_GPIO_IS_HIGH_OFFSET); ++ gk_gpio_insts[i].gpio_bank[j].pm_info.ibel_reg = ++ gk_gpio_readl(gk_gpio_insts[i].gpio_bank[j].base_reg + REG_GPIO_IBE_LOW_OFFSET); ++ gk_gpio_insts[i].gpio_bank[j].pm_info.ibeh_reg = ++ gk_gpio_readl(gk_gpio_insts[i].gpio_bank[j].base_reg + REG_GPIO_IBE_HIGH_OFFSET); ++ gk_gpio_insts[i].gpio_bank[j].pm_info.ievl_reg = ++ gk_gpio_readl(gk_gpio_insts[i].gpio_bank[j].base_reg + REG_GPIO_IEV_LOW_OFFSET); ++ gk_gpio_insts[i].gpio_bank[j].pm_info.ievh_reg = ++ gk_gpio_readl(gk_gpio_insts[i].gpio_bank[j].base_reg + REG_GPIO_IEV_HIGH_OFFSET); ++ gk_gpio_insts[i].gpio_bank[j].pm_info.iel_reg = ++ gk_gpio_readl(gk_gpio_insts[i].gpio_bank[j].base_reg + REG_GPIO_IE_LOW_OFFSET); ++ gk_gpio_insts[i].gpio_bank[j].pm_info.ieh_reg = ++ gk_gpio_readl(gk_gpio_insts[i].gpio_bank[j].base_reg + REG_GPIO_IE_HIGH_OFFSET); ++ spin_unlock_irqrestore(&gk_gpio_insts[i].gpio_bank[j].lock, flags); ++ } ++ gk_gpio_insts[i].per_sel_reg = ++ gk_gpio_readl(gk_gpio_insts[i].base_bus + REG_GPIO_PER_SEL_OFFSET); ++ gk_gpio_writel(gk_gpio_insts[i].base_bus + REG_GPIO_INT_EN_OFFSET, 0x00000000); ++ } ++ ++ return 0; ++} ++ ++u32 gk_gpio_resume(u32 level) ++{ ++ u32 i; ++ u32 j; ++ unsigned long flags; ++ ++ for (i = 0; i < CONFIG_GK_GPIO_INSTANCES; i++) ++ { ++ for (j = 0; j < gk_gpio_insts[i].bank_num; j++) ++ { ++ spin_lock_irqsave(&gk_gpio_insts[i].gpio_bank[j].lock, flags); ++ gk_gpio_writel(gk_gpio_insts[i].gpio_bank[j].base_reg + REG_GPIO_IS_LOW_OFFSET, ++ gk_gpio_insts[i].gpio_bank[j].pm_info.isl_reg); ++ gk_gpio_writel(gk_gpio_insts[i].gpio_bank[j].base_reg + REG_GPIO_IS_HIGH_OFFSET, ++ gk_gpio_insts[i].gpio_bank[j].pm_info.ish_reg); ++ gk_gpio_writel(gk_gpio_insts[i].gpio_bank[j].base_reg + REG_GPIO_IBE_LOW_OFFSET, ++ gk_gpio_insts[i].gpio_bank[j].pm_info.ibel_reg); ++ gk_gpio_writel(gk_gpio_insts[i].gpio_bank[j].base_reg + REG_GPIO_IBE_HIGH_OFFSET, ++ gk_gpio_insts[i].gpio_bank[j].pm_info.ibeh_reg); ++ gk_gpio_writel(gk_gpio_insts[i].gpio_bank[j].base_reg + REG_GPIO_IEV_LOW_OFFSET, ++ gk_gpio_insts[i].gpio_bank[j].pm_info.ievl_reg); ++ gk_gpio_writel(gk_gpio_insts[i].gpio_bank[j].base_reg + REG_GPIO_IEV_HIGH_OFFSET, ++ gk_gpio_insts[i].gpio_bank[j].pm_info.ievh_reg); ++ gk_gpio_writel(gk_gpio_insts[i].gpio_bank[j].base_reg + REG_GPIO_IE_LOW_OFFSET, ++ gk_gpio_insts[i].gpio_bank[j].pm_info.iel_reg); ++ gk_gpio_writel(gk_gpio_insts[i].gpio_bank[j].base_reg + REG_GPIO_IE_HIGH_OFFSET, ++ gk_gpio_insts[i].gpio_bank[j].pm_info.ieh_reg); ++ spin_unlock_irqrestore(&gk_gpio_insts[i].gpio_bank[j].lock, flags); ++ } ++ gk_gpio_writel(gk_gpio_insts[i].base_bus + REG_GPIO_PER_SEL_OFFSET, ++ gk_gpio_insts[i].per_sel_reg); ++ gk_gpio_writel(gk_gpio_insts[i].base_bus + REG_GPIO_INT_EN_OFFSET, 0x00000001); ++ } ++ return 0; ++} ++ ++int gk_set_gpio_output_can_sleep(struct gk_gpio_io_info *pinfo, u32 on, int can_sleep) ++{ ++ if (pinfo == NULL) ++ { ++ pr_err("%s: pinfo is NULL.\n", __func__); ++ return -1; ++ } ++ if (pinfo->gpio_id < 0 ) ++ { ++ pr_debug("%s: wrong gpio id %d.\n", __func__, pinfo->gpio_id); ++ return -1; ++ } ++ ++ pr_debug("%s: Gpio[%d] %s, level[%s], delay[%dms].\n", __func__, ++ pinfo->gpio_id, on ? "ON" : "OFF", ++ pinfo->active_level ? "HIGH" : "LOW", ++ pinfo->active_delay); ++ if (pinfo->gpio_id >= CONFIG_ARCH_NR_GPIO) ++ { ++ pr_debug("%s: try expander gpio id %d.\n", ++ __func__, pinfo->gpio_id); ++ return -1; ++ } ++ else ++ { ++ if (on) ++ { ++ gk_gpio_config(pinfo->gpio_id, pinfo->active_level ? GPIO_TYPE_OUTPUT_1 : GPIO_TYPE_OUTPUT_0); ++ gk_gpio_set_out(pinfo->gpio_id, pinfo->active_level); ++ } ++ else ++ { ++ gk_gpio_config(pinfo->gpio_id, pinfo->active_level ? GPIO_TYPE_OUTPUT_0 : GPIO_TYPE_OUTPUT_1); ++ gk_gpio_set_out(pinfo->gpio_id, !pinfo->active_level); ++ } ++ } ++ if (can_sleep) ++ { ++ msleep(pinfo->active_delay); ++ } ++ else ++ { ++ mdelay(pinfo->active_delay); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(gk_set_gpio_output_can_sleep); ++ ++u32 gk_get_gpio_input_can_sleep(struct gk_gpio_io_info *pinfo, int can_sleep) ++{ ++ u32 gpio_value = 0; ++ ++ if (pinfo == NULL) ++ { ++ pr_err("%s: pinfo is NULL.\n", __func__); ++ goto gk_get_gpio_input_can_sleep_exit; ++ } ++ if (pinfo->gpio_id < 0 ) ++ { ++ pr_debug("%s: wrong gpio id %d.\n", __func__, pinfo->gpio_id); ++ goto gk_get_gpio_input_can_sleep_exit; ++ } ++ ++ if (pinfo->gpio_id >= CONFIG_ARCH_NR_GPIO) ++ { ++ pr_debug("%s: try expander gpio id %d.\n", ++ __func__, pinfo->gpio_id); ++ goto gk_get_gpio_input_can_sleep_exit; ++ } ++ else ++ { ++ gk_gpio_config(pinfo->gpio_id, pinfo->active_level ? GPIO_TYPE_OUTPUT_1 : GPIO_TYPE_OUTPUT_0); ++ if (can_sleep) ++ { ++ msleep(pinfo->active_delay); ++ } ++ else ++ { ++ mdelay(pinfo->active_delay); ++ } ++ gpio_value = gk_gpio_get(pinfo->gpio_id); ++ } ++ ++ pr_debug("%s: {gpio[%d], level[%s], delay[%dms]} get[%d].\n", ++ __func__, pinfo->gpio_id, ++ pinfo->active_level ? "HIGH" : "LOW", ++ pinfo->active_delay, gpio_value); ++ ++gk_get_gpio_input_can_sleep_exit: ++ return (gpio_value == pinfo->active_level) ? 1 : 0; ++} ++EXPORT_SYMBOL(gk_get_gpio_input_can_sleep); ++ ++int gk_set_gpio_reset_can_sleep(struct gk_gpio_io_info *pinfo, int can_sleep) ++{ ++ int ret = 0; ++ ++ if (pinfo == NULL) ++ { ++ pr_err("%s: pinfo is NULL.\n", __func__); ++ ret = -1; ++ goto gk_set_gpio_reset_can_sleep_exit; ++ } ++ if (pinfo->gpio_id < 0 ) ++ { ++ pr_debug("%s: wrong gpio id %d.\n", __func__, pinfo->gpio_id); ++ ret = -1; ++ goto gk_set_gpio_reset_can_sleep_exit; ++ } ++ ++ pr_debug("%s: Reset gpio[%d], level[%s], delay[%dms].\n", ++ __func__, pinfo->gpio_id, ++ pinfo->active_level ? "HIGH" : "LOW", ++ pinfo->active_delay); ++ if (pinfo->gpio_id >= CONFIG_ARCH_NR_GPIO) ++ { ++ pr_debug("%s: try expander gpio id %d.\n", ++ __func__, pinfo->gpio_id); ++ ret = -1; ++ goto gk_set_gpio_reset_can_sleep_exit; ++ } ++ else ++ { ++ gk_gpio_config(pinfo->gpio_id, GPIO_TYPE_OUTPUT_0); ++ gk_gpio_set_out(pinfo->gpio_id, pinfo->active_level); ++ if (can_sleep) ++ { ++ msleep(pinfo->active_delay); ++ } ++ else ++ { ++ mdelay(pinfo->active_delay); ++ } ++ gk_gpio_set_out(pinfo->gpio_id, !pinfo->active_level); ++ if (can_sleep) ++ { ++ msleep(pinfo->active_delay); ++ } ++ else ++ { ++ mdelay(pinfo->active_delay); ++ } ++ } ++ ++gk_set_gpio_reset_can_sleep_exit: ++ return ret; ++} ++EXPORT_SYMBOL(gk_set_gpio_reset_can_sleep); ++ ++int gk_set_gpio_output(struct gk_gpio_io_info *pinfo, u32 on) ++{ ++ return gk_set_gpio_output_can_sleep(pinfo, on, 0); ++} ++EXPORT_SYMBOL(gk_set_gpio_output); ++ ++u32 gk_get_gpio_input(struct gk_gpio_io_info *pinfo) ++{ ++ return gk_get_gpio_input_can_sleep(pinfo, 0); ++} ++EXPORT_SYMBOL(gk_get_gpio_input); ++ ++int gk_set_gpio_reset(struct gk_gpio_io_info *pinfo) ++{ ++ return gk_set_gpio_reset_can_sleep(pinfo, 0); ++} ++EXPORT_SYMBOL(gk_set_gpio_reset); ++ ++int gk_is_valid_gpio_irq(struct gk_gpio_irq_info *pinfo) ++{ ++ struct gk_gpio_inst *gpio_inst; ++ struct gk_gpio_bank *gpio_bank; ++ if (pinfo == NULL) ++ { ++ printk("%s: pinfo is NULL.\n", __func__); ++ return 0; ++ } ++ ++ gpio_inst = gk_gpio_id_to_inst(pinfo->pin); ++ gpio_bank = gk_gpio_id_to_bank(pinfo->pin); ++ if ((gpio_bank == NULL) || (gpio_inst == NULL)) ++ { ++ pr_err("%s: invalid GPIO %d.\n", __func__, pinfo->pin); ++ return 0; ++ } ++ ++ if ((pinfo->type != IRQ_TYPE_EDGE_RISING) && ++ (pinfo->type != IRQ_TYPE_EDGE_FALLING) && ++ (pinfo->type != IRQ_TYPE_EDGE_BOTH) && ++ (pinfo->type != IRQ_TYPE_LEVEL_HIGH) && ++ (pinfo->type != IRQ_TYPE_LEVEL_LOW)) ++ return 0; ++ ++ return 1; ++} ++EXPORT_SYMBOL(gk_is_valid_gpio_irq); ++ ++static irqreturn_t gk_gpio_irq(int irq, void *dev) ++{ ++ struct gk_gpio_inst *gpio_inst; ++ struct gk_gpio_bank *gpio_bank; ++ struct gk_gpio_irq_info *pinfo = (struct gk_gpio_irq_info*)dev; ++ unsigned long flags; ++ u32 misl_reg; ++ u32 mish_reg; ++ u32 index; ++ u32 mask = 1; ++ u32 i = 1; ++ mdelay(20); ++ ++ if (pinfo == NULL) ++ { ++ pr_err("%s: pinfo is NULL.\n", __func__); ++ return IRQ_NONE; ++ } ++ gpio_inst = gk_gpio_id_to_inst(pinfo->pin); ++ if (gpio_inst == NULL) ++ { ++ pr_err("%s: invalid GPIO %d.\n", __func__, pinfo->pin); ++ return IRQ_NONE; ++ } ++ for(i=0;ibank_num;i++) ++ { ++ gpio_bank = &gpio_inst->gpio_bank[i]; ++ spin_lock_irqsave(&gpio_bank->lock, flags); ++ misl_reg = gk_gpio_readl(gpio_bank->base_reg + REG_GPIO_MIS_LOW_OFFSET); ++ mish_reg = gk_gpio_readl(gpio_bank->base_reg + REG_GPIO_MIS_HIGH_OFFSET); ++ gk_gpio_writel(gpio_bank->base_reg + REG_GPIO_IC_LOW_OFFSET, misl_reg); ++ gk_gpio_writel(gpio_bank->base_reg + REG_GPIO_IC_HIGH_OFFSET, mish_reg); ++ spin_unlock_irqrestore(&gpio_bank->lock, flags); ++ ++ for(index=0; index < 32; index++) ++ { ++ if(misl_reg & mask) ++ { ++ pinfo[index+gpio_bank->chip.base].val = gk_gpio_inline_get(gpio_bank, index+gpio_bank->chip.base); ++ if (pinfo[index+gpio_bank->chip.base].handler) ++ { ++ pinfo[index+gpio_bank->chip.base].handler(irq, &pinfo[index+gpio_bank->chip.base]); ++ } ++ } ++ if(mish_reg & mask) ++ { ++ pinfo[index + gpio_bank->chip.base + 32].val = gk_gpio_inline_get(gpio_bank, index+gpio_bank->chip.base + 32); ++ if (pinfo[index + gpio_bank->chip.base + 32].handler) ++ { ++ pinfo[index + gpio_bank->chip.base + 32].handler(irq, &pinfo[index + gpio_bank->chip.base + 32]); ++ } ++ } ++ mask <<= 1; ++ } ++ } ++ return IRQ_HANDLED; ++} ++ ++int gk_gpio_request_irq(struct gk_gpio_irq_info *pinfo) ++{ ++ struct gk_gpio_inst *gpio_inst; ++ struct gk_gpio_bank *gpio_bank; ++ u32 mask; ++ u32 offset; ++ unsigned long flags; ++ if (pinfo == NULL) ++ { ++ pr_err("%s: pinfo is NULL.\n", __func__); ++ return -1; ++ } ++ ++ gpio_inst = gk_gpio_id_to_inst(pinfo->pin); ++ gpio_bank = gk_gpio_id_to_bank(pinfo->pin); ++ if ((gpio_bank == NULL) || (gpio_inst == NULL)) ++ { ++ pr_err("%s: invalid GPIO %d.\n", __func__, pinfo->pin); ++ return -1; ++ } ++ spin_lock_irqsave(&gpio_bank->lock, flags); ++ memcpy(&gpio_inst->irq_info[pinfo->pin], pinfo, sizeof(struct gk_gpio_irq_info)); ++ gk_gpio_writel(gpio_inst->base_bus + REG_GPIO_INT_EN_OFFSET, 0x00); ++ mask = 0x01<<(pinfo->pin % 0x20); ++ offset = pinfo->pin - gpio_bank->chip.base; ++ if(offset / 0x20) ++ { ++ gpio_bank->pm_info.ish_reg = gk_gpio_readl(gpio_bank->base_reg + REG_GPIO_IS_HIGH_OFFSET); ++ gpio_bank->pm_info.ibeh_reg = gk_gpio_readl(gpio_bank->base_reg + REG_GPIO_IBE_HIGH_OFFSET); ++ gpio_bank->pm_info.ievh_reg = gk_gpio_readl(gpio_bank->base_reg + REG_GPIO_IEV_HIGH_OFFSET); ++ gpio_bank->pm_info.ieh_reg = gk_gpio_readl(gpio_bank->base_reg + REG_GPIO_IE_HIGH_OFFSET); ++ ++ gpio_bank->pm_info.ieh_reg |= mask; ++ switch(pinfo->type) ++ { ++ case IRQ_TYPE_LEVEL_LOW: ++ gpio_bank->pm_info.ish_reg |= mask; ++ gpio_bank->pm_info.ibeh_reg &= ~mask; ++ gpio_bank->pm_info.ievh_reg &= ~mask; ++ gk_gpio_set_type(gpio_bank, pinfo->pin, GPIO_TYPE_INPUT_1); ++ break; ++ case IRQ_TYPE_LEVEL_HIGH: ++ gpio_bank->pm_info.ish_reg |= mask; ++ gpio_bank->pm_info.ibeh_reg &= ~mask; ++ gpio_bank->pm_info.ievh_reg |= mask; ++ gk_gpio_set_type(gpio_bank, pinfo->pin, GPIO_TYPE_INPUT_0); ++ break; ++ case IRQ_TYPE_EDGE_FALLING: ++ gpio_bank->pm_info.ish_reg &= ~mask; ++ gpio_bank->pm_info.ibeh_reg &= ~mask; ++ gpio_bank->pm_info.ievh_reg &= ~mask; ++ gk_gpio_set_type(gpio_bank, pinfo->pin, GPIO_TYPE_INPUT_1); ++ break; ++ case IRQ_TYPE_EDGE_RISING: ++ gpio_bank->pm_info.ish_reg &= ~mask; ++ gpio_bank->pm_info.ibeh_reg &= ~mask; ++ gpio_bank->pm_info.ievh_reg |= mask; ++ gk_gpio_set_type(gpio_bank, pinfo->pin, GPIO_TYPE_INPUT_0); ++ break; ++ case IRQ_TYPE_EDGE_BOTH: ++ gpio_bank->pm_info.ish_reg &= ~mask; ++ gpio_bank->pm_info.ibeh_reg |= mask; ++ gk_gpio_set_type(gpio_bank, pinfo->pin, GPIO_TYPE_INPUT_1); ++ break; ++ } ++ gk_gpio_writel(gpio_bank->base_reg + REG_GPIO_IS_HIGH_OFFSET, gpio_bank->pm_info.ish_reg); ++ gk_gpio_writel(gpio_bank->base_reg + REG_GPIO_IBE_HIGH_OFFSET, gpio_bank->pm_info.ibeh_reg); ++ gk_gpio_writel(gpio_bank->base_reg + REG_GPIO_IEV_HIGH_OFFSET, gpio_bank->pm_info.ievh_reg); ++ gk_gpio_writel(gpio_bank->base_reg + REG_GPIO_IE_HIGH_OFFSET, gpio_bank->pm_info.ieh_reg); ++ } ++ else ++ { ++ gpio_bank->pm_info.isl_reg = gk_gpio_readl(gpio_bank->base_reg + REG_GPIO_IS_LOW_OFFSET); ++ gpio_bank->pm_info.ibel_reg = gk_gpio_readl(gpio_bank->base_reg + REG_GPIO_IBE_LOW_OFFSET); ++ gpio_bank->pm_info.ievl_reg = gk_gpio_readl(gpio_bank->base_reg + REG_GPIO_IEV_LOW_OFFSET); ++ gpio_bank->pm_info.iel_reg = gk_gpio_readl(gpio_bank->base_reg + REG_GPIO_IE_LOW_OFFSET); ++ ++ gpio_bank->pm_info.iel_reg |= mask; ++ switch(pinfo->type) ++ { ++ case IRQ_TYPE_LEVEL_LOW: ++ gpio_bank->pm_info.isl_reg |= mask; ++ gpio_bank->pm_info.ibel_reg &= ~mask; ++ gpio_bank->pm_info.ievl_reg &= ~mask; ++ gk_gpio_set_type(gpio_bank, pinfo->pin, GPIO_TYPE_INPUT_1); ++ break; ++ case IRQ_TYPE_LEVEL_HIGH: ++ gpio_bank->pm_info.isl_reg |= mask; ++ gpio_bank->pm_info.ibel_reg &= ~mask; ++ gpio_bank->pm_info.ievl_reg |= mask; ++ gk_gpio_set_type(gpio_bank, pinfo->pin, GPIO_TYPE_INPUT_0); ++ break; ++ case IRQ_TYPE_EDGE_FALLING: ++ gpio_bank->pm_info.isl_reg &= ~mask; ++ gpio_bank->pm_info.ibel_reg &= ~mask; ++ gpio_bank->pm_info.ievl_reg &= ~mask; ++ gk_gpio_set_type(gpio_bank, pinfo->pin, GPIO_TYPE_INPUT_1); ++ break; ++ case IRQ_TYPE_EDGE_RISING: ++ gpio_bank->pm_info.isl_reg &= ~mask; ++ gpio_bank->pm_info.ibel_reg &= ~mask; ++ gpio_bank->pm_info.ievl_reg |= mask; ++ gk_gpio_set_type(gpio_bank, pinfo->pin, GPIO_TYPE_INPUT_0); ++ break; ++ case IRQ_TYPE_EDGE_BOTH: ++ gpio_bank->pm_info.isl_reg &= ~mask; ++ gpio_bank->pm_info.ibel_reg |= mask; ++ gk_gpio_set_type(gpio_bank, pinfo->pin, GPIO_TYPE_INPUT_1); ++ break; ++ } ++ gk_gpio_writel(gpio_bank->base_reg + REG_GPIO_IS_LOW_OFFSET, gpio_bank->pm_info.isl_reg); ++ gk_gpio_writel(gpio_bank->base_reg + REG_GPIO_IBE_LOW_OFFSET, gpio_bank->pm_info.ibel_reg); ++ gk_gpio_writel(gpio_bank->base_reg + REG_GPIO_IEV_LOW_OFFSET, gpio_bank->pm_info.ievl_reg); ++ gk_gpio_writel(gpio_bank->base_reg + REG_GPIO_IE_LOW_OFFSET, gpio_bank->pm_info.iel_reg); ++ } ++ __set_bit(offset, (volatile unsigned long *)gpio_inst->irq_flag); ++ if(gpio_inst->irq_now == 0x00) ++ { ++ request_irq(gpio_inst->irq_no, gk_gpio_irq, IRQF_TRIGGER_HIGH, "gpio_irq", (void*)(&gpio_inst->irq_info[0])); ++ gpio_inst->irq_now = 0x01; ++ gk_gpio_writel(gpio_inst->base_bus + REG_GPIO_INT_EN_OFFSET, 0x01); ++ } ++ spin_unlock_irqrestore(&gpio_bank->lock, flags); ++ return 0; ++} ++EXPORT_SYMBOL(gk_gpio_request_irq); ++ ++int gk_gpio_release_irq(u32 pin) ++{ ++ struct gk_gpio_inst *gpio_inst; ++ struct gk_gpio_bank *gpio_bank; ++ u32 mask, i; ++ u32 offset; ++ unsigned long flags; ++ ++ gpio_inst = gk_gpio_id_to_inst(pin); ++ gpio_bank = gk_gpio_id_to_bank(pin); ++ if ((gpio_bank == NULL) || (gpio_inst == NULL)) ++ { ++ pr_err("%s: invalid GPIO %d.\n", __func__, pin); ++ return -1; ++ } ++ spin_lock_irqsave(&gpio_bank->lock, flags); ++ memset(&gpio_inst->irq_info[pin], 0x00, sizeof(struct gk_gpio_irq_info)); ++ ++ offset = pin - gpio_bank->chip.base; ++ mask = 0x01<<(offset % 0x20); ++ if(offset / 0x20) ++ { ++ gpio_bank->pm_info.ieh_reg = gk_gpio_readl(gpio_bank->base_reg + REG_GPIO_IE_HIGH_OFFSET); ++ gpio_bank->pm_info.ieh_reg &= ~mask; ++ gk_gpio_writel(gpio_bank->base_reg + REG_GPIO_IE_HIGH_OFFSET, gpio_bank->pm_info.ieh_reg); ++ } ++ else ++ { ++ gpio_bank->pm_info.iel_reg = gk_gpio_readl(gpio_bank->base_reg + REG_GPIO_IE_LOW_OFFSET); ++ gpio_bank->pm_info.iel_reg &= ~mask; ++ gk_gpio_writel(gpio_bank->base_reg + REG_GPIO_IE_LOW_OFFSET, gpio_bank->pm_info.iel_reg); ++ } ++ __clear_bit(offset, (volatile unsigned long *)gpio_inst->irq_flag); ++ offset = 0; ++ for (i = 0; i < (sizeof(gpio_inst->irq_flag) /sizeof(gpio_inst->irq_flag[0])); i++) ++ { ++ if(gpio_inst->irq_flag[i] != 0) ++ { ++ offset = 1; ++ break; ++ } ++ } ++ if(!offset) ++ { ++ gk_gpio_writel(gpio_bank->base_reg + REG_GPIO_INT_EN_OFFSET, 0x00); ++ } ++ spin_unlock_irqrestore(&gpio_bank->lock, flags); ++ return 0; ++} ++EXPORT_SYMBOL(gk_gpio_release_irq); ++ ++int __init goke_init_gpio(void) ++{ ++ u32 i,j,ret=0; ++ for(i=0;i ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++gpio_cfg_t gk_all_gpio_cfg; ++ ++struct gk_gpio_bank gk_gpio0_banks[] = ++{ ++ GK_GPIO_BANK("gk-gpio0", GPIO0_BANK0_BASE, GPIO0_BANK0_PLL_IOCTRL_BASE, ++ GK_GPIO(0 * GPIO_BANK_SIZE), CONFIG_ARCH_NR_GPIO, 0), ++}; ++// last one max = CONFIG_ARCH_NR_GPIO - base ++ ++struct gk_gpio_inst gk_gpio_insts[CONFIG_GK_GPIO_INSTANCES] = ++{ ++ [0] = ++ { ++ .bank_num = ARRAY_SIZE(gk_gpio0_banks), ++ .gpio_bank = gk_gpio0_banks, ++ .output_cfg = {0}, ++ .input_cfg = {0}, ++ .irq_no = GPIO0_IRQ, ++ .irq_info = {{0}}, ++ .irq_now = 0, ++ .gpio_valid = {0}, ++ .gpio_freeflag = {0}, ++ .irq_flag = {0}, ++ .base_bus = GPIO0_BASE, ++ .per_sel_reg = 0, ++ }, ++}; ++ ++int __init gk_init_gpio(void) ++{ ++ int retval = 0; ++ int i, index; ++ int gpio_count; ++ ++ const char chip_type[][8] = ++ { ++ {"GK7101"}, ++ {"GK7102"}, ++ {"GK7101S"}, ++ {"GK7102S"} ++ }; ++ ++ /* use usr memory's GPIO setting by uboot pass*/ ++ u32 usrmemphyaddr=0; ++ int intphy_gpio_count; ++ int extphy_gpio_count; ++ ++ usrmemphyaddr=get_usrmem_virt(); ++ memcpy((u8*)&gk_all_gpio_cfg,(u8*)usrmemphyaddr,sizeof(gk_all_gpio_cfg)); ++ gk_all_gpio_cfg.board_type[31] = '\0'; ++ /*get gpio configure infor*/ ++ gpio_count = gk_all_gpio_cfg.gpio_count; ++ intphy_gpio_count = gk_all_gpio_cfg.intphy_gpio_count; ++ extphy_gpio_count = gk_all_gpio_cfg.extphy_gpio_count; ++ ++#if 1 ++ printk("###################################\n"); ++ if(gk_all_gpio_cfg.soc_type >= sizeof(chip_type)/ sizeof(chip_type[0])) ++ { ++ printk("[BOOT VERSION] %s %s v%d.%d \n", "Unknown",gk_all_gpio_cfg.board_type, ++ gk_all_gpio_cfg.board_version>> 16, gk_all_gpio_cfg.board_version & 0xffff); ++ } ++ else ++ { ++ printk("[BOOT VERSION] %s %s v%d.%d \n", chip_type[gk_all_gpio_cfg.soc_type],gk_all_gpio_cfg.board_type, ++ gk_all_gpio_cfg.board_version >> 16, gk_all_gpio_cfg.board_version & 0xffff); ++ } ++ if (gk_all_gpio_cfg.ext_phy_clk == 0) ++ printk("[NET INT_CLK] Internal PHY clock \n"); ++ else ++ printk("[NET EXT_CLK] External PHY clock %dMHz \n", gk_all_gpio_cfg.ext_phy_clk); ++ printk("[GPIO]#############################\n"); ++ printk("[GPIO] gpio map get from uboot\n"); ++ printk("[GPIO CFG] gpio count = %d\n",gk_all_gpio_cfg.gpio_count); ++ printk("[GPIO CFG] intphy count = %d\n",gk_all_gpio_cfg.intphy_gpio_count); ++ printk("[GPIO CFG] extphy count = %d\n",gk_all_gpio_cfg.extphy_gpio_count); ++ printk("[GPIO CFG] IR LED CTL (%d)\n",gk_all_gpio_cfg.ir_led_ctl); ++ printk("[GPIO CFG] IR CUT1 (%d)\n",gk_all_gpio_cfg.ir_cut1); ++ printk("[GPIO CFG] IR CUT2 (%d)\n",gk_all_gpio_cfg.ir_cut2); ++ printk("[GPIO CFG] SENSOR Reset (%d)\n",gk_all_gpio_cfg.sensor_reset); ++ printk("[GPIO CFG] PHY Reset (%d)\n",gk_all_gpio_cfg.phy_reset); ++ printk("[GPIO CFG] PHY Speed Led (%d)\n",gk_all_gpio_cfg.phy_speed_led); ++ printk("[GPIO CFG] SPI0 EN (%d)\n",gk_all_gpio_cfg.spi0_en0); ++ printk("[GPIO CFG] SPI1 EN (%d)\n",gk_all_gpio_cfg.spi1_en0); ++ printk("[GPIO CFG] USB HOST (%d)\n",gk_all_gpio_cfg.usb_host); ++ printk("[GPIO CFG] SD Detect (%d)\n",gk_all_gpio_cfg.sd_detect); ++ printk("[GPIO CFG] SD Power (%d)\n",gk_all_gpio_cfg.sd_power); ++ printk("[GPIO]#############################\n"); ++#endif ++ ++ goke_init_gpio(); ++ ++ for(index=0; index < gpio_count; index++) ++ { ++ if(gk_all_gpio_cfg.gpio_chip[index].type != GPIO_TYPE_UNDEFINED) ++ { ++ gk_gpio_func_config(gk_all_gpio_cfg.gpio_chip[index].pin, gk_all_gpio_cfg.gpio_chip[index].type); ++ } ++ } ++ ++ if(cmdline_phytype == 0) ++ { ++ gpio_count = intphy_gpio_count; ++ for(index=0; index < gpio_count; index++) ++ { ++ if(gk_all_gpio_cfg.int_phy_gpio[index].type != GPIO_TYPE_UNDEFINED) ++ { ++ gk_gpio_func_config(gk_all_gpio_cfg.int_phy_gpio[index].pin, gk_all_gpio_cfg.int_phy_gpio[index].type); ++ } ++ } ++ } ++ else ++ { ++ gpio_count = extphy_gpio_count; ++ for(index=0; index < gpio_count; index++) ++ { ++ if(gk_all_gpio_cfg.ext_phy_gpio[index].type != GPIO_TYPE_UNDEFINED) ++ { ++ gk_gpio_func_config(gk_all_gpio_cfg.ext_phy_gpio[index].pin, gk_all_gpio_cfg.ext_phy_gpio[index].type); ++ } ++ } ++ } ++ ++ for(i=0;i ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++gpio_cfg_t gk_all_gpio_cfg; ++ ++struct gk_gpio_bank gk_gpio0_banks[] = ++{ ++ GK_GPIO_BANK("gk-gpio0", GPIO0_BANK0_BASE, GPIO0_BANK0_PLL_IOCTRL_BASE, ++ GK_GPIO(0 * GPIO_BANK_SIZE), GPIO_BANK_SIZE, 0), ++ GK_GPIO_BANK("gk-gpio1", GPIO0_BANK1_BASE, GPIO0_BANK1_PLL_IOCTRL_BASE, ++ GK_GPIO(1 * GPIO_BANK_SIZE), CONFIG_ARCH_NR_GPIO - GK_GPIO(1 * GPIO_BANK_SIZE), 0), ++}; ++// last one max = CONFIG_ARCH_NR_GPIO - base ++ ++struct gk_gpio_inst gk_gpio_insts[CONFIG_GK_GPIO_INSTANCES] = ++{ ++ [0] = ++ { ++ .bank_num = ARRAY_SIZE(gk_gpio0_banks), ++ .gpio_bank = gk_gpio0_banks, ++ .output_cfg = {0}, ++ .input_cfg = {0}, ++ .irq_no = GPIO0_IRQ, ++ .irq_info = {0}, ++ .irq_now = 0, ++ .gpio_valid = {0}, ++ .gpio_freeflag = {0}, ++ .irq_flag = {0}, ++ .base_bus = GPIO0_BASE, ++ .per_sel_reg = 0, ++ }, ++}; ++ ++int __init gk_init_gpio(void) ++{ ++ int retval = 0; ++ int i, index; ++ int gpio_count; ++ ++ const char chip_type[][8] = ++ { ++ {"GK7101"}, ++ {"GK7102"}, ++ {"GK7101S"}, ++ {"GK7102S"} ++ }; ++ ++ /* use usr memory's GPIO setting by uboot pass*/ ++ u32 usrmemphyaddr=0; ++ int intphy_gpio_count; ++ int extphy_gpio_count; ++ ++ usrmemphyaddr=get_usrmem_virt(); ++ memcpy((u8*)&gk_all_gpio_cfg,(u8*)usrmemphyaddr,sizeof(gk_all_gpio_cfg)); ++ gk_all_gpio_cfg.board_type[31] = '\0'; ++ /*get gpio configure infor*/ ++ gpio_count = gk_all_gpio_cfg.gpio_count; ++ intphy_gpio_count = gk_all_gpio_cfg.intphy_gpio_count; ++ extphy_gpio_count = gk_all_gpio_cfg.extphy_gpio_count; ++ ++#if 1 ++ printk("###################################\n"); ++ if(gk_all_gpio_cfg.soc_type >= sizeof(chip_type)/ sizeof(chip_type[0])) ++ { ++ printk("[BOOT VERSION] %s %s v%d.%d \n", "Unknown",gk_all_gpio_cfg.board_type, ++ gk_all_gpio_cfg.board_version>> 16, gk_all_gpio_cfg.board_version & 0xffff); ++ } ++ else ++ { ++ printk("[BOOT VERSION] %s %s v%d.%d \n", chip_type[gk_all_gpio_cfg.soc_type],gk_all_gpio_cfg.board_type, ++ gk_all_gpio_cfg.board_version >> 16, gk_all_gpio_cfg.board_version & 0xffff); ++ } ++ if (gk_all_gpio_cfg.ext_phy_clk == 0) ++ printk("[NET INT_CLK] Internal PHY clock \n"); ++ else ++ printk("[NET EXT_CLK] External PHY clock %dMHz \n", gk_all_gpio_cfg.ext_phy_clk); ++ printk("[GPIO]#############################\n"); ++ printk("[GPIO] gpio map get from uboot\n"); ++ printk("[GPIO CFG] gpio count = %d\n",gk_all_gpio_cfg.gpio_count); ++ printk("[GPIO CFG] intphy count = %d\n",gk_all_gpio_cfg.intphy_gpio_count); ++ printk("[GPIO CFG] extphy count = %d\n",gk_all_gpio_cfg.extphy_gpio_count); ++ printk("[GPIO CFG] IR LED CTL (%d)\n",gk_all_gpio_cfg.ir_led_ctl); ++ printk("[GPIO CFG] IR CUT1 (%d)\n",gk_all_gpio_cfg.ir_cut1); ++ printk("[GPIO CFG] IR CUT2 (%d)\n",gk_all_gpio_cfg.ir_cut2); ++ printk("[GPIO CFG] SENSOR Reset (%d)\n",gk_all_gpio_cfg.sensor_reset); ++ printk("[GPIO CFG] PHY Reset (%d)\n",gk_all_gpio_cfg.phy_reset); ++ printk("[GPIO CFG] PHY Speed Led (%d)\n",gk_all_gpio_cfg.phy_speed_led); ++ printk("[GPIO CFG] SPI0 EN (%d)\n",gk_all_gpio_cfg.spi0_en0); ++ printk("[GPIO CFG] SPI1 EN (%d)\n",gk_all_gpio_cfg.spi1_en0); ++ printk("[GPIO CFG] USB HOST (%d)\n",gk_all_gpio_cfg.usb_host); ++ printk("[GPIO CFG] SD Detect (%d)\n",gk_all_gpio_cfg.sd_detect); ++ printk("[GPIO CFG] SD Power (%d)\n",gk_all_gpio_cfg.sd_power); ++ printk("[GPIO]#############################\n"); ++#endif ++ ++ goke_init_gpio(); ++ ++ for(index=0; index < gpio_count; index++) ++ { ++ if(gk_all_gpio_cfg.gpio_chip[index].type != GPIO_TYPE_UNDEFINED) ++ { ++ gk_gpio_func_config(gk_all_gpio_cfg.gpio_chip[index].pin, gk_all_gpio_cfg.gpio_chip[index].type); ++ } ++ } ++ if(cmdline_phytype == 0) ++ { ++ gpio_count = intphy_gpio_count; ++ for(index=0; index < gpio_count; index++) ++ { ++ if(gk_all_gpio_cfg.int_phy_gpio[index].type != GPIO_TYPE_UNDEFINED) ++ { ++ gk_gpio_func_config(gk_all_gpio_cfg.int_phy_gpio[index].pin, gk_all_gpio_cfg.int_phy_gpio[index].type); ++ } ++ } ++ } ++ else ++ { ++ gpio_count = extphy_gpio_count; ++ for(index=0; index < gpio_count; index++) ++ { ++ if(gk_all_gpio_cfg.ext_phy_gpio[index].type != GPIO_TYPE_UNDEFINED) ++ { ++ gk_gpio_func_config(gk_all_gpio_cfg.ext_phy_gpio[index].pin, gk_all_gpio_cfg.ext_phy_gpio[index].type); ++ } ++ } ++ } ++ for(i=0;i ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++gpio_cfg_t gk_all_gpio_cfg; ++ ++struct gk_gpio_bank gk_gpio0_banks[] = ++{ ++ GK_GPIO_BANK("gk-gpio0", GPIO0_BANK0_BASE, GPIO0_BANK0_PLL_IOCTRL_BASE, ++ GK_GPIO(0 * GPIO_BANK_SIZE), CONFIG_ARCH_NR_GPIO, 0), ++}; ++// last one max = CONFIG_ARCH_NR_GPIO - base ++ ++struct gk_gpio_inst gk_gpio_insts[CONFIG_GK_GPIO_INSTANCES] = ++{ ++ [0] = ++ { ++ .bank_num = ARRAY_SIZE(gk_gpio0_banks), ++ .gpio_bank = gk_gpio0_banks, ++ .output_cfg = {0}, ++ .input_cfg = {0}, ++ .irq_no = GPIO0_IRQ, ++ .irq_info = {{0},}, ++ .irq_now = 0, ++ .gpio_valid = {0}, ++ .gpio_freeflag = {0}, ++ .irq_flag = {0}, ++ .base_bus = GPIO0_BASE, ++ .per_sel_reg = 0, ++ }, ++}; ++ ++int __init gk_init_gpio(void) ++{ ++ int retval = 0; ++ int i, index; ++ int gpio_count; ++ ++ const char chip_type[][8] = ++ { ++ {"GK7101"}, ++ {"GK7102"}, ++ {"GK7101S"}, ++ {"GK7102S"} ++ }; ++ ++ /* use usr memory's GPIO setting by uboot pass*/ ++ u32 usrmemphyaddr=0; ++ int intphy_gpio_count; ++ int extphy_gpio_count; ++ ++ usrmemphyaddr=get_usrmem_virt(); ++ memcpy((u8*)&gk_all_gpio_cfg,(u8*)usrmemphyaddr,sizeof(gk_all_gpio_cfg)); ++ gk_all_gpio_cfg.board_type[31] = '\0'; ++ /*get gpio configure infor*/ ++ gpio_count = gk_all_gpio_cfg.gpio_count; ++ intphy_gpio_count = gk_all_gpio_cfg.intphy_gpio_count; ++ extphy_gpio_count = gk_all_gpio_cfg.extphy_gpio_count; ++ ++#if 1 ++ printk("###################################\n"); ++ if(gk_all_gpio_cfg.soc_type >= sizeof(chip_type)/ sizeof(chip_type[0])) ++ { ++ printk("[BOOT VERSION] %s %s v%d.%d \n", "Unknown",gk_all_gpio_cfg.board_type, ++ gk_all_gpio_cfg.board_version>> 16, gk_all_gpio_cfg.board_version & 0xffff); ++ } ++ else ++ { ++ printk("[BOOT VERSION] %s %s v%d.%d \n", chip_type[gk_all_gpio_cfg.soc_type],gk_all_gpio_cfg.board_type, ++ gk_all_gpio_cfg.board_version >> 16, gk_all_gpio_cfg.board_version & 0xffff); ++ } ++ if (gk_all_gpio_cfg.ext_phy_clk == 0) ++ printk("[NET INT_CLK] Internal PHY clock \n"); ++ else ++ printk("[NET EXT_CLK] External PHY clock %dMHz \n", gk_all_gpio_cfg.ext_phy_clk); ++ printk("[GPIO]#############################\n"); ++ printk("[GPIO] gpio map get from uboot\n"); ++ printk("[GPIO CFG] gpio count = %d\n",gk_all_gpio_cfg.gpio_count); ++ printk("[GPIO CFG] intphy count = %d\n",gk_all_gpio_cfg.intphy_gpio_count); ++ printk("[GPIO CFG] extphy count = %d\n",gk_all_gpio_cfg.extphy_gpio_count); ++ printk("[GPIO CFG] IR LED CTL (%d)\n",gk_all_gpio_cfg.ir_led_ctl); ++ printk("[GPIO CFG] IR CUT1 (%d)\n",gk_all_gpio_cfg.ir_cut1); ++ printk("[GPIO CFG] IR CUT2 (%d)\n",gk_all_gpio_cfg.ir_cut2); ++ printk("[GPIO CFG] SENSOR Reset (%d)\n",gk_all_gpio_cfg.sensor_reset); ++ printk("[GPIO CFG] PHY Reset (%d)\n",gk_all_gpio_cfg.phy_reset); ++ printk("[GPIO CFG] PHY Speed Led (%d)\n",gk_all_gpio_cfg.phy_speed_led); ++ printk("[GPIO CFG] SPI0 EN (%d)\n",gk_all_gpio_cfg.spi0_en0); ++ printk("[GPIO CFG] SPI1 EN (%d)\n",gk_all_gpio_cfg.spi1_en0); ++ printk("[GPIO CFG] USB HOST (%d)\n",gk_all_gpio_cfg.usb_host); ++ printk("[GPIO CFG] SD Detect (%d)\n",gk_all_gpio_cfg.sd_detect); ++ printk("[GPIO CFG] SD Power (%d)\n",gk_all_gpio_cfg.sd_power); ++ printk("[GPIO CFG] SD1 Detect (%d)\n",gk_all_gpio_cfg.sd1_detect); ++ printk("[GPIO CFG] SD1 Power (%d)\n",gk_all_gpio_cfg.sd1_power); ++ printk("[GPIO]#############################\n"); ++#endif ++ ++ goke_init_gpio(); ++ ++ for(index=0; index < gpio_count; index++) ++ { ++ if(gk_all_gpio_cfg.gpio_chip[index].type != GPIO_TYPE_UNDEFINED) ++ { ++ gk_gpio_func_config(gk_all_gpio_cfg.gpio_chip[index].pin, gk_all_gpio_cfg.gpio_chip[index].type); ++ } ++ } ++ if(cmdline_phytype == 0) ++ { ++ gpio_count = intphy_gpio_count; ++ for(index=0; index < gpio_count; index++) ++ { ++ if(gk_all_gpio_cfg.int_phy_gpio[index].type != GPIO_TYPE_UNDEFINED) ++ { ++ gk_gpio_func_config(gk_all_gpio_cfg.int_phy_gpio[index].pin, gk_all_gpio_cfg.int_phy_gpio[index].type); ++ } ++ } ++ } ++ else ++ { ++ gpio_count = extphy_gpio_count; ++ for(index=0; index < gpio_count; index++) ++ { ++ if(gk_all_gpio_cfg.ext_phy_gpio[index].type != GPIO_TYPE_UNDEFINED) ++ { ++ gk_gpio_func_config(gk_all_gpio_cfg.ext_phy_gpio[index].pin, gk_all_gpio_cfg.ext_phy_gpio[index].type); ++ } ++ } ++ } ++ for(i=0;i ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++int highres_timer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode) ++{ ++ return hrtimer_start(timer, tim, mode); ++} ++EXPORT_SYMBOL(highres_timer_start); ++ ++void highres_timer_init(struct hrtimer *timer, clockid_t clock_id, enum hrtimer_mode mode) ++{ ++ hrtimer_init(timer, clock_id, mode); ++} ++EXPORT_SYMBOL(highres_timer_init); ++ ++int highres_timer_cancel(struct hrtimer *timer) ++{ ++ return hrtimer_cancel(timer); ++} ++EXPORT_SYMBOL(highres_timer_cancel); ++ ++MODULE_AUTHOR("Louis"); ++MODULE_DESCRIPTION("high resolution timer wrapper"); ++MODULE_LICENSE("GPL v2"); ++MODULE_VERSION("1.0"); ++ +diff --git a/arch/arm/plat-goke/hw_timer.c b/arch/arm/plat-goke/hw_timer.c +new file mode 100644 +index 00000000..34737b28 +--- /dev/null ++++ b/arch/arm/plat-goke/hw_timer.c +@@ -0,0 +1,594 @@ ++/* ++ * arch/arm/mach-gk/hw_timer.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++ ++ ++#define GK_HWTIMER_NAME "hwtimer" ++ ++#define GK_HWTIMER_STATUS_REG TIMER1_STATUS_REG ++#define GK_HWTIMER_RELOAD_REG TIMER1_RELOAD_REG ++#define GK_HWTIMER_MATCH1_REG TIMER1_MATCH1_REG ++#define GK_HWTIMER_MATCH2_REG TIMER1_MATCH2_REG ++#define GK_HWTIMER_CTR_EN TIMER_CTR_EN1 ++#define GK_HWTIMER_CTR_OF TIMER_CTR_OF1 ++#define GK_HWTIMER_CTR_CSL TIMER_CTR_CSL1 ++#define GK_HWTIMER_CTR_MASK 0x0000000F ++ ++#define GK_HWTIMER_IRQ TIMER1_IRQ ++ ++#define HWTIMER_INPUT_FREQ (get_apb_bus_freq_hz()) ++#define HWTIMER_OUTPUT_FREQ 90000 ++ ++typedef struct hw_timer_state_s ++{ ++ u32 enable_flag; ++ u32 reg_value; ++ u64 overflow_count; ++ u64 overflow_value; ++ u64 output_ticks; ++}hw_timer_state_t; ++ ++static u64 hwtimer_overflow_count = 0; ++static u64 hwtimer_init_output_value = 0; ++static u32 hwtimer_init_overflow_value = 0; ++static u32 hwtimer_input_freq_unchanged = 1; ++ ++static hw_timer_state_t timer_state; ++ ++static spinlock_t timer_isr_lock; ++ ++static int hwtimer_reset(void); ++ ++static inline void gk_hwtimer_disable(void) ++{ ++ gk_timer_clrbitsl(TIMER_CTR_REG, GK_HWTIMER_CTR_EN); ++} ++ ++static inline void gk_hwtimer_enable(void) ++{ ++ gk_timer_setbitsl(TIMER_CTR_REG, GK_HWTIMER_CTR_EN); ++} ++ ++static inline void gk_hwtimer_misc(void) ++{ ++ gk_timer_setbitsl(TIMER_CTR_REG, GK_HWTIMER_CTR_OF); ++ gk_timer_clrbitsl(TIMER_CTR_REG, GK_HWTIMER_CTR_CSL); ++} ++ ++static inline void gk_hwtimer_config(void) ++{ ++ if (hwtimer_init_overflow_value) { ++ gk_timer_writel(GK_HWTIMER_STATUS_REG, hwtimer_init_overflow_value); ++ gk_timer_writel(GK_HWTIMER_RELOAD_REG, hwtimer_init_overflow_value); ++ } else { ++ hwtimer_init_overflow_value = HWTIMER_INPUT_FREQ; ++ gk_timer_writel(GK_HWTIMER_STATUS_REG, hwtimer_init_overflow_value); ++ gk_timer_writel(GK_HWTIMER_RELOAD_REG, hwtimer_init_overflow_value); ++ } ++ ++ gk_timer_writel(GK_HWTIMER_MATCH1_REG, 0x0); ++ gk_timer_writel(GK_HWTIMER_MATCH2_REG, 0x0); ++ gk_hwtimer_misc(); ++} ++ ++static inline void gk_hwtimer_init(void) ++{ ++ gk_hwtimer_disable(); ++ gk_hwtimer_config(); ++ gk_hwtimer_enable(); ++ timer_state.enable_flag = 1; ++} ++ ++static u32 gk_hwtimer_read(void) ++{ ++ return (u32)gk_timer_readl(GK_HWTIMER_STATUS_REG); ++} ++ ++static inline int get_gcd(int a, int b) ++{ ++ if ((a == 0) || (b == 0)) { ++ printk("wrong input for gcd \n"); ++ return 1; ++ } ++ while ((a != 0) && (b != 0)) { ++ if (a > b) { ++ a = a % b; ++ } else { ++ b = b % a; ++ } ++ } ++ return (a == 0) ? b : a; ++} ++ ++static int calc_output_ticks(void) ++{ ++ u64 total_ticks; ++ u64 overflow_ticks; ++ u64 hwtimer_ticks; ++ u32 curr_reg_value; ++ int output_freq = HWTIMER_OUTPUT_FREQ; ++ ++ int gcd; ++ ++ if (hwtimer_input_freq_unchanged) { ++ curr_reg_value = gk_hwtimer_read(); ++ ++ overflow_ticks = hwtimer_overflow_count * hwtimer_init_overflow_value; ++ hwtimer_ticks = hwtimer_init_overflow_value - curr_reg_value; ++ total_ticks = overflow_ticks + hwtimer_ticks; ++ ++ // change frequency from apb clock to 90K ++ gcd = get_gcd(output_freq, (int)hwtimer_init_overflow_value); ++ total_ticks = total_ticks * (output_freq / gcd) + ++ hwtimer_init_overflow_value / (gcd * 2); ++ if (hwtimer_init_overflow_value) ++ do_div(total_ticks, hwtimer_init_overflow_value / gcd); ++ else { ++ printk("HWTimer: calculate output ticks failed! Can not divide zero!\n"); ++ return -EINVAL; ++ } ++ ++ //update timer state ++ timer_state.output_ticks = total_ticks; ++ timer_state.overflow_count = hwtimer_overflow_count; ++ timer_state.reg_value = curr_reg_value; ++ } else { ++ curr_reg_value = gk_hwtimer_read(); ++ if (curr_reg_value > timer_state.reg_value) { ++ overflow_ticks = (hwtimer_overflow_count - timer_state.overflow_count) ++ * hwtimer_init_overflow_value; ++ hwtimer_ticks = curr_reg_value - timer_state.reg_value; ++ total_ticks = overflow_ticks + hwtimer_ticks; ++ } else { ++ overflow_ticks = (hwtimer_overflow_count - timer_state.overflow_count) ++ * hwtimer_init_overflow_value; ++ hwtimer_ticks = timer_state.reg_value - curr_reg_value; ++ total_ticks = overflow_ticks - hwtimer_ticks; ++ } ++ ++ // change frequency from apb clock to 90K ++ total_ticks = total_ticks * HWTIMER_OUTPUT_FREQ; ++ if (timer_state.overflow_value) ++ do_div(total_ticks, timer_state.overflow_value); ++ else { ++ printk("HWTimer: calculate output ticks failed! Can not divide zero!\n"); ++ return -EINVAL; ++ } ++ total_ticks += timer_state.output_ticks; ++ ++ //update timer state structure ++ timer_state.output_ticks = total_ticks; ++ timer_state.overflow_count = hwtimer_overflow_count; ++ timer_state.reg_value = curr_reg_value; ++ } ++ ++ return 0; ++} ++ ++/*static void hw_timer_check_input_freq(int isr_flag) ++{ ++ u32 curr_input_freq = HWTIMER_INPUT_FREQ; ++ ++ if (timer_state.overflow_value != curr_input_freq) { ++ //printk("HWTimer: input frequency is changed from %lld to %u!\n", ++ // timer_state.overflow_value, curr_input_freq); ++ if (hwtimer_input_freq_unchanged) { ++ hwtimer_input_freq_unchanged = 0; ++ } ++ if (isr_flag) ++ calc_output_ticks(); ++ timer_state.overflow_value = curr_input_freq; ++ } ++}*/ ++ ++static int hwtimer_write_proc(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ int retval = 0; ++ char buf[50]; ++ ++ if (count > 50) { ++ printk("HWTimer: %s: count %d out of size!\n", __func__, (u32)count); ++ retval = -ENOSPC; ++ goto hwtimer_write_proc_exit; ++ } ++ if (count > 1) { ++ if (copy_from_user(buf, buffer, count - 1)) { ++ printk("HWTimer: %s: copy_from_user fail!\n", __func__); ++ retval = -EFAULT; ++ goto hwtimer_write_proc_exit; ++ } ++ buf[count] = '\0'; ++ hwtimer_init_output_value = simple_strtoull(buf, NULL, 10); ++ } ++ ++ hwtimer_reset(); ++ ++ retval = count; ++ ++hwtimer_write_proc_exit: ++ return retval; ++} ++ ++int get_hwtimer_output_ticks(u64 *out_tick) ++{ ++ int ret = 0; ++ if (timer_state.enable_flag) { ++ ret = calc_output_ticks(); ++ if (!ret) { ++ //hw_timer_check_input_freq(0); ++ *out_tick = timer_state.output_ticks + hwtimer_init_output_value; ++ } else { ++ *out_tick = 0; ++ } ++ } else { ++ *out_tick = 0; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(get_hwtimer_output_ticks); ++ ++static int hwtimer_read_proc(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int ret = 0; ++ u64 final_ticks = 0; ++ ++ if (off) ++ return ret; ++ ++ *start = page + off; ++ *eof = 1; ++ ++ if (timer_state.enable_flag) { ++ ret = calc_output_ticks(); ++ if (!ret) { ++ //hw_timer_check_input_freq(0); ++ final_ticks = timer_state.output_ticks + hwtimer_init_output_value; ++ ret = sprintf(*start, "%lld\n", final_ticks); ++ } else { ++ ret = sprintf(*start, "%d\n", 0); ++ } ++ } else { ++ ret = sprintf(*start, "%d\n", 0); ++ } ++ ++ return ret; ++} ++ ++/* buffer size is one page but our output routines use some slack for overruns */ ++#define PROC_BLOCK_SIZE (PAGE_SIZE - 1024) ++static ssize_t hwtimer_proc_file_read_func(struct file *file, ++ char __user *buf, size_t nbytes, loff_t *ppos) ++{ ++ struct inode * inode = file->f_path.dentry->d_inode; ++ char *page; ++ ssize_t retval=0; ++ int eof=0; ++ ssize_t n, count; ++ char *start; ++ struct proc_dir_entry * dp; ++ unsigned long long pos; ++ ++ pos = *ppos; ++ if (pos > MAX_NON_LFS) ++ return 0; ++ if (nbytes > MAX_NON_LFS - pos) ++ nbytes = MAX_NON_LFS - pos; ++ ++ dp = PDE(inode); ++ if (!(page = (char*) __get_free_page(GFP_TEMPORARY))) ++ return -ENOMEM; ++ ++ while ((nbytes > 0) && !eof) { ++ count = min_t(size_t, PROC_BLOCK_SIZE, nbytes); ++ ++ start = NULL; ++ if (dp->read_proc) { ++ n = dp->read_proc(page, &start, *ppos, ++ count, &eof, dp->data); ++ } else ++ break; ++ ++ if (n == 0) /* end of file */ ++ break; ++ if (n < 0) { /* error */ ++ if (retval == 0) ++ retval = n; ++ break; ++ } ++ ++ if (start == NULL) { ++ if (n > PAGE_SIZE) { ++ printk(KERN_ERR ++ "proc_file_read: Apparent buffer overflow!\n"); ++ n = PAGE_SIZE; ++ } ++ n -= *ppos; ++ if (n <= 0) ++ break; ++ if (n > count) ++ n = count; ++ start = page + *ppos; ++ } else if (start < page) { ++ if (n > PAGE_SIZE) { ++ printk(KERN_ERR ++ "proc_file_read: Apparent buffer overflow!\n"); ++ n = PAGE_SIZE; ++ } ++ if (n > count) { ++ /* ++ * Don't reduce n because doing so might ++ * cut off part of a data block. ++ */ ++ printk(KERN_WARNING ++ "proc_file_read: Read count exceeded\n"); ++ } ++ } else /* start >= page */ { ++ unsigned long startoff = (unsigned long)(start - page); ++ if (n > (PAGE_SIZE - startoff)) { ++ printk(KERN_ERR ++ "proc_file_read: Apparent buffer overflow!\n"); ++ n = PAGE_SIZE - startoff; ++ } ++ if (n > count) ++ n = count; ++ } ++ ++ n -= copy_to_user(buf, start < page ? page : start, n); ++ if (n == 0) { ++ if (retval == 0) ++ retval = -EFAULT; ++ break; ++ } ++ ++ // disable proc file offset update to support read without sync ++ //*ppos += start < page ? (unsigned long)start : n; ++ nbytes -= n; ++ buf += n; ++ retval += n; ++ } ++ free_page((unsigned long) page); ++ return retval; ++} ++ ++static void __hwtimer_pde_users_dec(struct proc_dir_entry *pde) ++{ ++ pde->pde_users--; ++ if (pde->pde_unload_completion && pde->pde_users == 0) ++ complete(pde->pde_unload_completion); ++} ++ ++static void hw_timer_pde_users_dec(struct proc_dir_entry *pde) ++{ ++ spin_lock(&pde->pde_unload_lock); ++ __hwtimer_pde_users_dec(pde); ++ spin_unlock(&pde->pde_unload_lock); ++} ++ ++static ssize_t hwtimer_proc_file_read(struct file *file, ++ char __user *buf, size_t nbytes, loff_t *ppos) ++{ ++ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); ++ ssize_t rv = -EIO; ++ ++ spin_lock(&pde->pde_unload_lock); ++ if (!pde->proc_fops) { ++ spin_unlock(&pde->pde_unload_lock); ++ return rv; ++ } ++ pde->pde_users++; ++ spin_unlock(&pde->pde_unload_lock); ++ ++ rv = hwtimer_proc_file_read_func(file, buf, nbytes, ppos); ++ ++ hw_timer_pde_users_dec(pde); ++ return rv; ++} ++ ++static ssize_t hwtimer_proc_file_write(struct file *file, ++ const char __user *buffer, size_t count, loff_t *ppos) ++{ ++ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); ++ ssize_t rv = -EIO; ++ ++ if (pde->write_proc) { ++ spin_lock(&pde->pde_unload_lock); ++ if (!pde->proc_fops) { ++ spin_unlock(&pde->pde_unload_lock); ++ return rv; ++ } ++ pde->pde_users++; ++ spin_unlock(&pde->pde_unload_lock); ++ ++ /* FIXME: does this routine need ppos? probably... */ ++ rv = pde->write_proc(file, buffer, count, pde->data); ++ hw_timer_pde_users_dec(pde); ++ } ++ return rv; ++} ++ ++static const struct file_operations hwtimer_fops = { ++ .owner = THIS_MODULE, ++ .read = hwtimer_proc_file_read, ++ .write = hwtimer_proc_file_write, ++}; ++ ++static int hwtimer_create_proc(void) ++{ ++ int err_code = 0; ++ struct proc_dir_entry *hwtimer_entry; ++ ++ hwtimer_entry = proc_create_data(GK_HWTIMER_NAME, ++ S_IRUGO | S_IWUGO, get_gk_proc_dir(), &hwtimer_fops, NULL); ++ //hwtimer_entry = create_proc_entry(GK_HWTIMER_NAME, ++ // S_IRUGO, get_gk_proc_dir()); ++ ++ if (!hwtimer_entry) { ++ err_code = -EINVAL; ++ } else { ++ hwtimer_entry->read_proc = hwtimer_read_proc; ++ hwtimer_entry->write_proc = hwtimer_write_proc; ++ } ++ ++ return err_code; ++} ++ ++static irqreturn_t hwtimer_isr(int irq, void *dev_id) ++{ ++ spin_lock(&timer_isr_lock); ++ hwtimer_overflow_count++; ++ spin_unlock(&timer_isr_lock); ++ ++ return IRQ_HANDLED; ++} ++ ++static void init_timer_state(void) ++{ ++ timer_state.enable_flag = 0; ++ timer_state.output_ticks = 0; ++ timer_state.overflow_count = 0; ++ timer_state.reg_value = hwtimer_init_overflow_value; ++ timer_state.overflow_value = hwtimer_init_overflow_value; ++} ++ ++static void hwtimer_remove_proc(void) ++{ ++ remove_proc_entry(GK_HWTIMER_NAME, get_gk_proc_dir()); ++} ++ ++int hwtimer_reset() ++{ ++ hwtimer_overflow_count = 0; ++ hwtimer_init_overflow_value = HWTIMER_INPUT_FREQ; ++ init_timer_state(); ++ gk_hwtimer_init(); ++ ++ return 0; ++} ++ ++static int __init hwtimer_init(void) ++{ ++ int err_code = 0; ++ err_code = hwtimer_create_proc(); ++ if (err_code) { ++ printk("HWTimer: create proc file for hw timer failed!\n"); ++ goto hwtimer_init_err_create_proc; ++ } ++ ++ hwtimer_overflow_count = 0; ++ err_code = request_irq(GK_HWTIMER_IRQ, hwtimer_isr, ++ IRQF_TRIGGER_RISING, GK_HWTIMER_NAME, NULL); ++ if (err_code) { ++ printk("HWTimer: request irq for hw timer failed!\n"); ++ goto hwtimer_init_err_request_irq; ++ } ++ ++ hwtimer_init_overflow_value = HWTIMER_INPUT_FREQ; ++ init_timer_state(); ++ gk_hwtimer_init(); ++ ++ goto hwtimer_init_err_na; ++ ++hwtimer_init_err_request_irq: ++ free_irq(GK_HWTIMER_IRQ, NULL); ++ ++hwtimer_init_err_create_proc: ++ hwtimer_remove_proc(); ++ ++hwtimer_init_err_na: ++ return err_code; ++} ++ ++static void __exit hwtimer_exit(void) ++{ ++ if (timer_state.enable_flag) { ++ gk_hwtimer_disable(); ++ timer_state.enable_flag = 0; ++ } ++ free_irq(GK_HWTIMER_IRQ, NULL); ++ hwtimer_remove_proc(); ++} ++ ++module_init(hwtimer_init); ++module_exit(hwtimer_exit); ++ ++MODULE_DESCRIPTION("gk hardware timer driver"); ++MODULE_LICENSE("Proprietary"); ++ +diff --git a/arch/arm/plat-goke/include/plat/audio.h b/arch/arm/plat-goke/include/plat/audio.h +new file mode 100644 +index 00000000..68d66997 +--- /dev/null ++++ b/arch/arm/plat-goke/include/plat/audio.h +@@ -0,0 +1,181 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk/include/plat/audio.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++#ifndef __PLAT_AUDIO_H ++#define __PLAT_AUDIO_H ++ ++#include ++ ++/* ==========================================================================*/ ++#define DAI_CLOCK_MASK 0x0000001f ++ ++#define MAX_MCLK_IDX_NUM 15 ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++struct notifier_block; ++ ++struct gk_i2s_interface { ++ u8 state; ++ u8 mode; ++ u8 sfreq; ++ u8 clksrc; ++ u8 ms_mode; ++ u8 mclk; ++ u8 ch; ++ u8 oversample; ++ u8 word_order; ++ u8 word_len; ++ u8 word_pos; ++ u8 slots; ++}; ++ ++#define MAX_OVERSAMPLE_IDX_NUM 9 ++enum AudioCodec_OverSample { ++ AudioCodec_128xfs = 0, ++ AudioCodec_256xfs = 1, ++ AudioCodec_384xfs = 2, ++ AudioCodec_512xfs = 3, ++ AudioCodec_768xfs = 4, ++ AudioCodec_1024xfs = 5, ++ AudioCodec_1152xfs = 6, ++ AudioCodec_1536xfs = 7, ++ AudioCodec_2304xfs = 8 ++}; ++ ++enum AudioCodec_MCLK { ++ AudioCodec_18_432M = 0, ++ AudioCodec_16_9344M = 1, ++ AudioCodec_12_288M = 2, ++ AudioCodec_11_2896M = 3, ++ AudioCodec_9_216M = 4, ++ AudioCodec_8_4672M = 5, ++ AudioCodec_8_192M = 6, ++ AudioCodec_6_144 = 7, ++ AudioCodec_5_6448M = 8, ++ AudioCodec_4_608M = 9, ++ AudioCodec_4_2336M = 10, ++ AudioCodec_4_096M = 11, ++ AudioCodec_3_072M = 12, ++ AudioCodec_2_8224M = 13, ++ AudioCodec_2_048M = 14 ++}; ++ ++enum audio_in_freq_e ++{ ++ AUDIO_SF_reserved = 0, ++ AUDIO_SF_96000, ++ AUDIO_SF_48000, ++ AUDIO_SF_44100, ++ AUDIO_SF_32000, ++ AUDIO_SF_24000, ++ AUDIO_SF_22050, ++ AUDIO_SF_16000, ++ AUDIO_SF_12000, ++ AUDIO_SF_11025, ++ AUDIO_SF_8000, ++}; ++ ++enum Audio_Notify_Type ++{ ++ AUDIO_NOTIFY_UNKNOWN, ++ AUDIO_NOTIFY_INIT, ++ AUDIO_NOTIFY_SETHWPARAMS, ++ AUDIO_NOTIFY_REMOVE ++}; ++ ++enum DAI_Mode ++{ ++ DAI_leftJustified_Mode = 0, ++ DAI_rightJustified_Mode = 1, ++ DAI_MSBExtend_Mode = 2, ++ DAI_I2S_Mode = 4, ++ DAI_DSP_Mode = 6 ++}; ++ ++enum DAI_MS_MODE ++{ ++ DAI_SLAVE = 0, ++ DAI_MASTER = 1 ++}; ++ ++enum DAI_resolution ++{ ++ DAI_16bits = 0, ++ DAI_18bits = 1, ++ DAI_20bits = 2, ++ DAI_24bits = 3, ++ DAI_32bits = 4 ++ ++}; ++ ++enum DAI_ifunion ++{ ++ DAI_union = 0, ++ DAI_nonunion = 1 ++}; ++ ++enum DAI_WordOrder ++{ ++ DAI_MSB_FIRST = 0, ++ DAI_LSB_FIRST = 1 ++}; ++ ++enum DAI_INIT_CTL ++{ ++ DAI_FIFO_RST = 1, ++ DAI_RX_EN = 2, ++ DAI_TX_EN = 4 ++}; ++ ++#define DAI_32slots 32 ++#define DAI_64slots 64 ++#define DAI_48slots 48 ++ ++#define GK_CLKSRC_ONCHIP AUC_CLK_ONCHIP_PLL_27MHZ ++#define GK_CLKSRC_EXTERNAL AUC_CLK_EXTERNAL ++#define GK_CLKDIV_LRCLK 0 ++ ++struct gk_i2s_controller { ++ void (*aucodec_digitalio_0)(void); ++ void (*aucodec_digitalio_1)(void); ++ void (*aucodec_digitalio_2)(void); ++ void (*channel_select)(u32); ++ void (*set_audio_pll)(u8, u8); ++}; ++ ++/* ==========================================================================*/ ++extern struct platform_device gk_i2s0; ++extern struct platform_device gk_pcm0; ++extern struct platform_device gk_dummy_codec0; ++ ++extern u32 alsa_tx_enable_flag; ++ ++/* ==========================================================================*/ ++extern int gk_init_audio(void); ++ ++extern void gk_audio_notify_transition(struct gk_i2s_interface *data, unsigned int type); ++extern int gk_audio_register_notifier(struct notifier_block *nb); ++extern int gk_audio_unregister_notifier(struct notifier_block *nb); ++ ++extern struct gk_i2s_interface get_audio_i2s_interface(void); ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif ++ +diff --git a/arch/arm/plat-goke/include/plat/cache.h b/arch/arm/plat-goke/include/plat/cache.h +new file mode 100644 +index 00000000..dc650b35 +--- /dev/null ++++ b/arch/arm/plat-goke/include/plat/cache.h +@@ -0,0 +1,41 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/plat/cache.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __PLAT_CACHE_H ++#define __PLAT_CACHE_H ++ ++/* ==========================================================================*/ ++#define CACHE_LINE_SIZE 32 ++#define CACHE_LINE_MASK ~(CACHE_LINE_SIZE - 1) ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++extern void gk_cache_clean_range(void *addr, unsigned int size); ++extern void gk_cache_inv_range(void *addr, unsigned int size); ++extern void gk_cache_flush_range(void *addr, unsigned int size); ++extern void gk_cache_pli_range(void *addr, unsigned int size); ++extern int gk_cache_l2_enable(void); ++extern int gk_cache_l2_disable(void); ++extern void gk_cache_l2_enable_raw(void); ++extern void gk_cache_l2_disable_raw(void); ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif ++ +diff --git a/arch/arm/plat-goke/include/plat/dma.h b/arch/arm/plat-goke/include/plat/dma.h +new file mode 100644 +index 00000000..81687552 +--- /dev/null ++++ b/arch/arm/plat-goke/include/plat/dma.h +@@ -0,0 +1,86 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk/include/plat/dma.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __PLAT_DMA_H ++#define __PLAT_DMA_H ++ ++#include ++ ++/* ==========================================================================*/ ++#define MAX_DMA_CHANNEL_IRQ_HANDLERS 4 ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++typedef struct gk_dma_req_s { ++ u32 src; /* Source address */ ++ u32 dst; /* Destination address */ ++ struct gk_dma_req_s *next; /* Pointing to next descriptor */ ++ u32 rpt; /* The physical address to store DMA hardware ++ reporting status */ ++ u32 xfr_count; /* Transfer byte count , max value = 2^22 */ ++ u32 attr; /* Descriptor 's attribute */ ++} gk_dma_req_t; ++ ++typedef struct gk_dmadesc_s { ++ u32 src_addr; /**< Source address */ ++ u32 dst_addr; /**< Destination address */ ++ u32 next; /**< Next descriptor */ ++ u32 rpt_addr; /**< Report address */ ++ u32 xfrcnt; /**< Transfer count */ ++ u32 ctrl; /**< Control */ ++ u32 rsv0; /**< Reserved */ ++ u32 rsv1; /**< Reserved */ ++ u32 rpt; /**< Report */ ++ u32 rsv2; /**< Reserved */ ++ u32 rsv3; /**< Reserved */ ++ u32 rsv4; /**< Reserved */ ++} gk_dmadesc_t; ++ ++typedef void (*gk_dma_handler)(void *dev_id, u32 status); ++ ++struct dma_s { ++ struct dma_chan_s { ++ u32 status; /**< The status of the current transaction */ ++ int use_flag; ++ int irq_count; ++ struct { ++ int enabled; ++ gk_dma_handler handler; ++ void *harg; ++ } irq[MAX_DMA_CHANNEL_IRQ_HANDLERS]; ++ } chan[NUM_DMA_CHANNELS]; ++}; ++ ++/* ==========================================================================*/ ++ ++/* ==========================================================================*/ ++extern int gk_dma_request_irq(int chan, gk_dma_handler handler, void *harg); ++extern void gk_dma_free_irq(int chan, gk_dma_handler handler); ++extern int gk_dma_enable_irq(int chan, gk_dma_handler handler); ++extern int gk_dma_disable_irq(int chan, gk_dma_handler handler); ++extern int gk_dma_xfr(gk_dma_req_t *req, int chan); ++extern int gk_dma_desc_xfr(dma_addr_t desc_addr, int chan); ++extern int gk_dma_desc_stop(int chan); ++extern int gk_dma_read_ctrl_reg(int chan); ++extern int gk_init_dma(void); ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif ++ +diff --git a/arch/arm/plat-goke/include/plat/fb.h b/arch/arm/plat-goke/include/plat/fb.h +new file mode 100644 +index 00000000..a40df190 +--- /dev/null ++++ b/arch/arm/plat-goke/include/plat/fb.h +@@ -0,0 +1,143 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk/include/plat/fb.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __PLAT_FB_H ++#define __PLAT_FB_H ++ ++/* ==========================================================================*/ ++#define GK_CLUT_BYTES (3) ++#define GK_CLUT_TABLE_SIZE (256 * GK_CLUT_BYTES) ++#define GK_BLEND_TABLE_SIZE (256) ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++#include "linux/fb.h" ++enum gk_fb_color_format { ++ GK_FB_COLOR_AUTO = 0, ++ ++ GK_FB_COLOR_CLUT_8BPP, ++ GK_FB_COLOR_RGB565, ++ ++ GK_FB_COLOR_BGR565, ++ GK_FB_COLOR_AGBR4444, //AYUV 4:4:4:4 ++ GK_FB_COLOR_RGBA4444, ++ GK_FB_COLOR_BGRA4444, ++ GK_FB_COLOR_ABGR4444, ++ GK_FB_COLOR_ARGB4444, ++ GK_FB_COLOR_AGBR1555, //AYUV 1:5:5:5 ++ GK_FB_COLOR_GBR1555, //YUV 1(ignored):5:5:5 ++ GK_FB_COLOR_RGBA5551, ++ GK_FB_COLOR_BGRA5551, ++ GK_FB_COLOR_ABGR1555, ++ GK_FB_COLOR_ARGB1555, ++ GK_FB_COLOR_AGBR8888, //AYUV 8:8:8:8 ++ GK_FB_COLOR_RGBA8888, ++ GK_FB_COLOR_BGRA8888, ++ GK_FB_COLOR_ABGR8888, ++ GK_FB_COLOR_ARGB8888, ++ ++ GK_FB_COLOR_YUV565, ++ GK_FB_COLOR_AYUV4444, ++ GK_FB_COLOR_AYUV1555, ++ GK_FB_COLOR_YUV555, ++ ++ GK_FB_COLOR_UNSUPPORTED, //Reserved only, not supported ++}; ++ ++typedef enum ++{ ++ GK_DSP_ENCODE_MODE = 0x00, ++ GK_DSP_DECODE_MODE = 0x01, ++ GK_DSP_RESET_MODE = 0x02, ++ GK_DSP_UNKNOWN_MODE = 0x03, ++ GK_DSP_QUICKLOGO_MODE = 0x04, ++}gk_dsp_op_mode_e; ++ ++enum gk_fb_status { ++ GK_FB_UNKNOWN_MODE = 0x00, ++ GK_FB_ACTIVE_MODE, ++ GK_FB_STOP_MODE, ++}; ++ ++typedef int (*gk_fb_pan_display_fn)(struct fb_var_screeninfo *var, ++ struct fb_info *info); ++typedef int (*gk_fb_setcmap_fn)(struct fb_cmap *cmap, ++ struct fb_info *info); ++typedef int (*gk_fb_check_var_fn)(struct fb_var_screeninfo *var, ++ struct fb_info *info); ++typedef int (*gk_fb_set_par_fn)(struct fb_info *info); ++typedef int (*gk_fb_blank_fn)(int blank_mode, struct fb_info *info); ++ ++struct gk_fb_cvs_buf { //Conversion Buffer ++ int available; ++ u8 *ping_buf; ++ u32 ping_buf_size; ++ u8 *pong_buf; ++ u32 pong_buf_size; ++}; ++ ++struct gk_fb_media_info { ++ struct fb_var_screeninfo screen_var; ++ struct fb_fix_screeninfo screen_fix; ++ gk_dsp_op_mode_e dsp_status; ++ ++ gk_fb_pan_display_fn pan_display; ++ gk_fb_setcmap_fn setcmap; ++ gk_fb_check_var_fn check_var; ++ gk_fb_set_par_fn set_par; ++ gk_fb_blank_fn set_blank; ++}; ++ ++struct gk_platform_fb { ++ struct mutex lock; ++ struct fb_var_screeninfo screen_var; ++ struct fb_fix_screeninfo screen_fix; ++ gk_dsp_op_mode_e dsp_status; ++ enum gk_fb_status fb_status; ++ u8 clut_table[GK_CLUT_TABLE_SIZE]; ++ u8 blend_table[GK_BLEND_TABLE_SIZE]; ++ enum gk_fb_color_format color_format; ++ struct gk_fb_cvs_buf conversion_buf; ++ u32 use_prealloc; ++ u32 prealloc_line_length; ++ ++ gk_fb_pan_display_fn pan_display; ++ gk_fb_setcmap_fn setcmap; ++ gk_fb_check_var_fn check_var; ++ gk_fb_set_par_fn set_par; ++ gk_fb_blank_fn set_blank; ++ ++ struct fb_info *proc_fb_info; ++ struct proc_dir_entry *proc_file; ++ wait_queue_head_t proc_wait; ++ u32 proc_wait_flag; ++}; ++ ++/* ==========================================================================*/ ++ ++/* ==========================================================================*/ ++extern int gk_fb_get_platform_info(u32, struct gk_platform_fb *); ++extern int gk_fb_set_media_info(u32, struct gk_fb_media_info *); ++extern int gk_fb_update_info(u32 fb_id, int xres, int yres, ++ int xvirtual, int yvirtual, int format, u32 bits_per_pixel, ++ u32 smem_start, u32 smem_len); ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif ++ +diff --git a/arch/arm/plat-goke/include/plat/gk_gpio.h b/arch/arm/plat-goke/include/plat/gk_gpio.h +new file mode 100644 +index 00000000..6ccbf5dc +--- /dev/null ++++ b/arch/arm/plat-goke/include/plat/gk_gpio.h +@@ -0,0 +1,228 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/plat-goke/include/plat/gk_gpio.h ++** ++** \version $Id: gk_gpio.h 9588 2016-08-16 01:55:35Z dengbiao $ ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2016 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++#ifndef _GK_GPIO_H_ ++#define _GK_GPIO_H_ ++#include ++#include ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Defines and Macros ++//***************************************************************************** ++//***************************************************************************** ++#define GK_GPIO(n) (n) ++#define GPIO_BANK_SIZE 64 ++ ++/* SW definitions */ ++#define GPIO_HIGH 1 ++#define GPIO_LOW 0 ++ ++#define GK_GPIO_IO_MODULE_PARAM_CALL(name_prefix, arg, perm) \ ++ module_param_cb(name_prefix##gpio_id, ¶m_ops_int, &(arg.gpio_id), perm); \ ++ module_param_cb(name_prefix##active_level, ¶m_ops_int, &(arg.active_level), perm); \ ++ module_param_cb(name_prefix##active_delay, ¶m_ops_int, &(arg.active_delay), perm) ++#define GK_GPIO_RESET_MODULE_PARAM_CALL(name_prefix, arg, perm) \ ++ module_param_cb(name_prefix##gpio_id, ¶m_ops_int, &(arg.gpio_id), perm); \ ++ module_param_cb(name_prefix##active_level, ¶m_ops_int, &(arg.active_level), perm); \ ++ module_param_cb(name_prefix##active_delay, ¶m_ops_int, &(arg.active_delay), perm) ++ ++/* GPIO function selection */ ++/* Select SW or HW control and input/output direction of S/W function */ ++#define GPIO_FUNC_SW_INPUT 0 ++#define GPIO_FUNC_SW_OUTPUT 1 ++#define GPIO_FUNC_HW 2 ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Enumerated types ++//***************************************************************************** ++//***************************************************************************** ++/* GPIO function selection */ ++typedef enum ++{ ++ GPIO_FUNC_IN = 1, ++ GPIO_FUNC_OUT = 2, ++ GPIO_FUNC_INOUT = 3, ++}GPIO_FUNC_TYPE_E; ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Data Structures ++//***************************************************************************** ++//***************************************************************************** ++struct gk_gpio_irq_info ++{ ++ int pin; ++ int type; ++ int val; // when is input, the value will be transfered to handler ++ irq_handler_t handler; ++}; ++struct gk_gpio_io_info ++{ ++ int gpio_id; ++ int active_level; ++ int active_delay; //ms ++}; ++ ++typedef struct ++{ ++ u32 pin; ++ u32 type; ++}GPIO_XREF_S; ++ ++struct gk_gpio_bank ++{ ++ struct gpio_chip chip; ++ spinlock_t lock; ++ u32 base_reg; // for is/ibe/iev/ie/ic/ris/mis/din/ ++ u32 io_reg; // PLL_IOCTRL ++ u32 index; // instance no ++ struct ++ { ++ u32 isl_reg; ++ u32 ish_reg; ++ u32 ibel_reg; ++ u32 ibeh_reg; ++ u32 ievl_reg; ++ u32 ievh_reg; ++ u32 iel_reg; ++ u32 ieh_reg; ++ }pm_info; ++}; ++ ++struct gk_gpio_inst ++{ ++ u32 bank_num; ++ struct gk_gpio_bank* gpio_bank; ++ u32 output_cfg[CONFIG_ARCH_NR_GPIO]; // CONFIG_GK_GPIO_MAX_OUTPUT_TYPE != CONFIG_ARCH_NR_GPIO ++ u32 input_cfg[CONFIG_GK_GPIO_MAX_INPUT_TYPE]; // CONFIG_GK_GPIO_MAX_INPUT_TYPE != CONFIG_ARCH_NR_GPIO ++ u32 irq_no; ++ struct gk_gpio_irq_info irq_info[CONFIG_ARCH_NR_GPIO]; ++ u32 irq_now; ++ u32 gpio_valid[BITS_TO_LONGS(CONFIG_ARCH_NR_GPIO)]; ++ u32 gpio_freeflag[BITS_TO_LONGS(CONFIG_ARCH_NR_GPIO)]; ++ u32 irq_flag[BITS_TO_LONGS(CONFIG_ARCH_NR_GPIO)]; ++ u32 base_bus; // for sel/in ++ u32 per_sel_reg; ++}; ++ ++#define GK_GPIO_BANK(name, reg_base, io_base, base_gpio, gpio_num, bank) \ ++{ \ ++ .chip = \ ++ { \ ++ .label = name, \ ++ .owner = THIS_MODULE, \ ++ .request = gk_gpio_request, \ ++ .free = gk_gpio_free, \ ++ .direction_input = gk_gpio_direction_input, \ ++ .get = gk_gpio_get_ex, \ ++ .direction_output = gk_gpio_direction_output, \ ++ .set = gk_gpio_set, \ ++ .to_irq = gk_gpio_to_irq, \ ++ .dbg_show = gk_gpio_dbg_show, \ ++ .base = base_gpio, \ ++ .ngpio = gpio_num, \ ++ .can_sleep = 0, \ ++ .exported = 0, \ ++ }, \ ++ .base_reg = reg_base, \ ++ .io_reg = io_base, \ ++ .index = bank, \ ++ .pm_info = {0}, \ ++} ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Global Data ++//***************************************************************************** ++//***************************************************************************** ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** API Functions ++//***************************************************************************** ++//***************************************************************************** ++#ifdef CONFIG_GK_GPIO_V1_00 ++#include ++#endif ++#ifdef CONFIG_GK_GPIO_V1_10 ++#include ++#endif ++#ifdef CONFIG_GK_GPIO_V1_20 ++#include ++#endif ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++extern int __init gk_init_gpio(void); ++extern int gk_gpio_set_type(struct gk_gpio_bank* bank, u32 pin, u32 type); // GPIO_TYPE_E ++int gk_gpio_request(struct gpio_chip *chip, u32 pin); ++void gk_gpio_free(struct gpio_chip *chip, u32 pin); ++int gk_gpio_direction_input(struct gpio_chip *chip, u32 pin, int val); ++int gk_gpio_get(unsigned offset); ++int gk_gpio_get_ex(struct gpio_chip *chip, unsigned offset); ++int gk_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int val); ++void gk_gpio_set(struct gpio_chip *chip, unsigned offset, int val); ++int gk_gpio_to_irq(struct gpio_chip *chip, unsigned offset); ++void gk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip); ++int gk_is_valid_gpio_irq(struct gk_gpio_irq_info *pinfo); ++extern void gk_gpio_set_out(u32 id, u32 value); ++ ++int gk_gpio_func_config(u32 pin, u32 func); ++ ++extern int gk_set_gpio_output(struct gk_gpio_io_info *pinfo, u32 on); ++extern u32 gk_get_gpio_input(struct gk_gpio_io_info *pinfo); ++extern int gk_set_gpio_reset(struct gk_gpio_io_info *pinfo); ++extern int gk_set_gpio_output_can_sleep(struct gk_gpio_io_info *pinfo, u32 on, int can_sleep); ++extern u32 gk_get_gpio_input_can_sleep(struct gk_gpio_io_info *pinfo, int can_sleep); ++extern int gk_set_gpio_reset_can_sleep(struct gk_gpio_io_info *pinfo, int can_sleep); ++extern void gk_gpio_config(u32 pin, u32 func); ++ ++ ++#define GK_GPIO_IRQ_MODULE_PARAM_CALL(name_prefix, arg, perm) \ ++ module_param_cb(name_prefix##pin, ¶m_ops_int, &(arg.pin), perm); \ ++ module_param_cb(name_prefix##type, ¶m_ops_int, &(arg.type), perm); \ ++ module_param_cb(name_prefix##val, ¶m_ops_int, &(arg.val), perm); ++ ++#define GK_IRQ_MODULE_PARAM_CALL(name_prefix, arg, perm) \ ++ module_param_cb(name_prefix##irq_gpio, ¶m_ops_int, &(arg.irq_gpio), perm); \ ++ module_param_cb(name_prefix##irq_line, ¶m_ops_int, &(arg.irq_line), perm); \ ++ module_param_cb(name_prefix##irq_type, ¶m_ops_int, &(arg.irq_type), perm); \ ++ module_param_cb(name_prefix##irq_gpio_val, ¶m_ops_int, &(arg.irq_gpio_val), perm); \ ++ module_param_cb(name_prefix##irq_gpio_mode, ¶m_ops_int, &(arg.irq_gpio_mode), perm) ++extern int gk_is_valid_gpio_irq(struct gk_gpio_irq_info *pgpio_irq); ++extern int gk_gpio_request_irq(struct gk_gpio_irq_info *pinfo); ++extern int gk_gpio_release_irq(u32 pin); ++int __init goke_init_gpio(void); ++void GH_GPIO_set_INPUT_CFG_in_sel(u8 index, u8 data); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++ ++ ++#endif /* _GK_GPIO_H_ */ ++ +diff --git a/arch/arm/plat-goke/include/plat/gk_gpio_v1_00.h b/arch/arm/plat-goke/include/plat/gk_gpio_v1_00.h +new file mode 100644 +index 00000000..f1ac8d9b +--- /dev/null ++++ b/arch/arm/plat-goke/include/plat/gk_gpio_v1_00.h +@@ -0,0 +1,320 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/plat-goke/include/plat/gk_gpio_v1_00.h ++** ++** \version $Id: gk_gpio_v1_00.h 10728 2016-10-21 02:05:33Z yulindeng $ ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2016 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++#ifndef _GK_GPIO_V1_00_H_ ++#define _GK_GPIO_V1_00_H_ ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Defines and Macros ++//***************************************************************************** ++//***************************************************************************** ++/************************/ ++/* GPIO pins definition */ ++/************************/ ++#define GPIO_SET_OUT_SEL(n) ((n)&0x3F) ++#define GPIO_SET_IN_SEL(n) (((n)&0x3F)<<8) ++#define GPIO_SET_OEN_SEL(n) (((n)&0x3F)<<16) ++#define GPIO_SET_OUT_INVERT(n) (((n)&0x1)<<22) ++#define GPIO_SET_OEN_INVERT(n) (((n)&0x1)<<23) ++#define GPIO_SET_IOCTRL(n) (((n)&0x3F)<<24) ++#define GPIO_SET_FUNC(n) (((n)&0x3)<<30) ++ ++#define GPIO_GET_OUT_SEL(n) (((n)&0x0000003F)) ++#define GPIO_GET_IN_SEL(n) (((n)&0x00003F00)>>8) ++#define GPIO_GET_OEN_SEL(n) (((n)&0x003F0000)>>16) ++#define GPIO_GET_OUT_INVERT(n) (((n)&0x00400000)>>22) ++#define GPIO_GET_OEN_INVERT(n) (((n)&0x00800000)>>23) ++#define GPIO_GET_IOCTRL(n) (((n)&0x3F000000)>>24) ++#define GPIO_GET_FUNC(n) (((n)&0xC0000000)>>30) ++ ++#define IOCTRL_NORMAL 0x00 //!< Hi-z ++#define IOCTRL_PULL_UP 0x10 //!< PULL_UP ++#define IOCTRL_PULL_DOWN 0x20 //!< PULL_DOWN ++#define IOCTRL_REPEAT 0x30 //!< REPEAT ++ ++#define IOCTRL_2MA 0x00 //!< 2mA ++#define IOCTRL_4MA 0x01 //!< 4mA ++#define IOCTRL_8MA 0x02 //!< 8mA ++#define IOCTRL_12MA 0x03 //!< 12mA ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Enumerated types ++//***************************************************************************** ++//***************************************************************************** ++typedef enum ++{ ++ /* ----------------------------------- GPIO output function define ----------------------------------- */ ++ GPIO_TYPE_OUTPUT_0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 0), //!< Output type: value = 0 ++ GPIO_TYPE_OUTPUT_1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 1), //!< Output type: value = 1 ++ GPIO_TYPE_OUTPUT_SPI1_SO = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 2) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 2), //!< Output type: tssi_txd ++ GPIO_TYPE_OUTPUT_SPI1_CS0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 3), //!< Output type: tssi_cs0_n ++ GPIO_TYPE_OUTPUT_SPI1_SCLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 4), //!< Output type: tssi_sclk_out ++ GPIO_TYPE_OUTPUT_UART2_RTS_N = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 5), //!< Output type: uart2_rts_n ++ GPIO_TYPE_OUTPUT_UART2_DTR_N = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 6), //!< Output type: uart2_dtr_n ++ GPIO_TYPE_OUTPUT_UART2_TX = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 7), //!< Output type: uart2_tx ++ GPIO_TYPE_OUTPUT_UART1_TX = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 8), //!< Output type: uart1_tx ++ GPIO_TYPE_OUTPUT_UART0_TX = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 9), //!< Output type: uart0_tx ++ GPIO_TYPE_OUTPUT_PWM3_OUT = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(10), //!< Output type: pwm3_out ++ GPIO_TYPE_OUTPUT_PWM2_OUT = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(11), //!< Output type: pwm2_out ++ GPIO_TYPE_OUTPUT_PWM1_OUT = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(12), //!< Output type: pwm1_out ++ GPIO_TYPE_OUTPUT_PWM0_OUT = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(13), //!< Output type: pwm0_out ++ GPIO_TYPE_OUTPUT_SPI0_SO = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 7) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(14), //!< Output type: ssi_txd ++ GPIO_TYPE_OUTPUT_SPI0_CS7 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(15), //!< Output type: ssi_cs7_n ++ GPIO_TYPE_OUTPUT_SPI0_CS6 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(16), //!< Output type: ssi_cs6_n ++ GPIO_TYPE_OUTPUT_SPI0_CS5 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(17), //!< Output type: ssi_cs5_n ++ GPIO_TYPE_OUTPUT_SPI0_CS4 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(18), //!< Output type: ssi_cs4_n ++ GPIO_TYPE_OUTPUT_SPI0_CS1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(19), //!< Output type: ssi_cs1_n ++ GPIO_TYPE_OUTPUT_SPI0_CS0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(20), //!< Output type: ssi_cs0_n ++ GPIO_TYPE_OUTPUT_SPI0_SCLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(21), //!< Output type: ssi_sclk_out ++ //GPIO_TYPE_INOUT_SD_DATA_0 GPIO_SET_OEN_SEL( 8) GPIO_SET_OUT_SEL(22) ++ //GPIO_TYPE_INOUT_SD_DATA_1 GPIO_SET_OEN_SEL( 9) GPIO_SET_OUT_SEL(23) ++ //GPIO_TYPE_INOUT_SD_DATA_2 GPIO_SET_OEN_SEL(10) GPIO_SET_OUT_SEL(24) ++ //GPIO_TYPE_INOUT_SD_DATA_3 GPIO_SET_OEN_SEL(11) GPIO_SET_OUT_SEL(25) ++ //GPIO_TYPE_INOUT_SD_DATA_4 GPIO_SET_OEN_SEL(12) GPIO_SET_OUT_SEL(26) ++ //GPIO_TYPE_INOUT_SD_DATA_5 GPIO_SET_OEN_SEL(13) GPIO_SET_OUT_SEL(27) ++ //GPIO_TYPE_INOUT_SD_DATA_6 GPIO_SET_OEN_SEL(14) GPIO_SET_OUT_SEL(28) ++ //GPIO_TYPE_INOUT_SD_DATA_7 GPIO_SET_OEN_SEL(15) GPIO_SET_OUT_SEL(29) ++ //GPIO_TYPE_INOUT_SDIO_CMD GPIO_SET_OEN_SEL(16) GPIO_SET_OUT_SEL(30) ++ GPIO_TYPE_OUTPUT_SDIO_CLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(31), //!< Output type: sd_clk_sdcard ++ GPIO_TYPE_OUTPUT_AOMCLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(32), //!< Output type: i2s_au_clk ++ GPIO_TYPE_OUTPUT_AOBCLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(17) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(33), //!< Output type: i2s_clk_o ++ GPIO_TYPE_OUTPUT_AOLRCLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(18) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(34), //!< Output type: i2s_ws_o ++ GPIO_TYPE_OUTPUT_AO_DATA0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(35), //!< Output type: i2s_so ++ GPIO_TYPE_OUTPUT_SF_CS0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(36), //!< Output type: sf_cs0_n ++ GPIO_TYPE_OUTPUT_SF_CS1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(37), //!< Output type: sf_cs1_n ++ GPIO_TYPE_OUTPUT_EPHY_LED_0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(38), //!< Output type: ephy_led[0] hcd ok ++ GPIO_TYPE_OUTPUT_EPHY_LED_1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(39), //!< Output type: ephy_led[1] duplex ++ GPIO_TYPE_OUTPUT_EPHY_LED_2 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(40), //!< Output type: ephy_led[2] 10M CRS out ++ GPIO_TYPE_OUTPUT_EPHY_LED_3 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(41), //!< Output type: ephy_led[3] 100M CRS out ++ GPIO_TYPE_OUTPUT_EPHY_LED_4 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(42), //!< Output type: ephy_led[4] clo gs ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXD_0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(43), //!< Output type: enet_phy_txd[0] ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXD_1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(44), //!< Output type: enet_phy_txd[1] ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXD_2 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(45), //!< Output type: enet_phy_txd[2] ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXD_3 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(46), //!< Output type: enet_phy_txd[3] ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXER = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(47), //!< Output type: enet_phy_txer ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXEN = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(48), //!< Output type: enet_phy_txen ++ // GPIO_TYPE_INOUT_ETH_MDIO GPIO_SET_OUT_SEL(49) ++ GPIO_TYPE_OUTPUT_ENET_GMII_MDC_O = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(50), //!< Output type: enet_gmii_mdc_o ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(51), //!< Output type: ahb_dac_dr[0] ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(52), //!< Output type: ahb_dac_dr[1] ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_2 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(53), //!< Output type: ahb_dac_dr[2] ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_3 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(54), //!< Output type: ahb_dac_dr[3] ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_4 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(55), //!< Output type: ahb_dac_dr[4] ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_5 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(56), //!< Output type: ahb_dac_dr[5] ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_6 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(57), //!< Output type: ahb_dac_dr[6] ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_7 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(58), //!< Output type: ahb_dac_dr[7] ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_8 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(59), //!< Output type: ahb_dac_dr[8] ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_9 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(60), //!< Output type: ahb_dac_dr[9] ++ ++ /* ----------------------------------- GPIO input function define ----------------------------------- */ ++ GPIO_TYPE_INPUT = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_NORMAL|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 0), //!< Input type: normal input ++ GPIO_TYPE_INPUT_0 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 0), //!< Input type: normal input ++ GPIO_TYPE_INPUT_1 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL( 1) | GPIO_SET_OUT_SEL( 0), //!< Input type: normal input ++ GPIO_TYPE_INPUT_SPI1_SI = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+ 0) | GPIO_SET_OUT_SEL( 0), //!< Input type: tssi_rxd ++ //GPIO_TYPE_INOUT_I2C_DATA GPIO_SET_IN_SEL(2+ 1) ++ //GPIO_TYPE_INOUT_I2C_CLK GPIO_SET_IN_SEL(2+ 2) ++ //GPIO_TYPE_INOUT_I2C_DATA2 GPIO_SET_IN_SEL(2+ 3) ++ //GPIO_TYPE_INOUT_I2C_CLK2 GPIO_SET_IN_SEL(2+ 4) ++ GPIO_TYPE_INPUT_UART2_RX = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+ 5) | GPIO_SET_OUT_SEL( 0), //!< Input type: uart2_rx ++ GPIO_TYPE_INPUT_UART1_RX = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+ 6) | GPIO_SET_OUT_SEL( 0), //!< Input type: uart1_rx ++ GPIO_TYPE_INPUT_UART0_RX = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+ 7) | GPIO_SET_OUT_SEL( 0), //!< Input type: uart0_rx ++ GPIO_TYPE_INPUT_TIMER1_CLK = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+ 8) | GPIO_SET_OUT_SEL( 0), //!< Input type: timer1_clk ++ GPIO_TYPE_INPUT_TIMER2_CLK = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+ 9) | GPIO_SET_OUT_SEL( 0), //!< Input type: timer2_clk ++ GPIO_TYPE_INPUT_TIMER3_CLK = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+10) | GPIO_SET_OUT_SEL( 0), //!< Input type: timer3_clk ++ GPIO_TYPE_INPUT_SPI0_SI = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+11) | GPIO_SET_OUT_SEL( 0), //!< Input type: ssi_rxd ++ GPIO_TYPE_INPUT_SD_WP_N = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+12) | GPIO_SET_OUT_SEL( 0), //!< Input type: sd_wp_n ++ GPIO_TYPE_INPUT_SD_CD_N = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+13) | GPIO_SET_OUT_SEL( 0), //!< Input type: sd_cd_n ++ //GPIO_TYPE_INOUT_SD_DATA_0 GPIO_SET_IN_SEL(2+14) ++ //GPIO_TYPE_INOUT_SD_DATA_1 GPIO_SET_IN_SEL(2+15) ++ //GPIO_TYPE_INOUT_SD_DATA_2 GPIO_SET_IN_SEL(2+16) ++ //GPIO_TYPE_INOUT_SD_DATA_3 GPIO_SET_IN_SEL(2+17) ++ //GPIO_TYPE_INOUT_SD_DATA_4 GPIO_SET_IN_SEL(2+18) ++ //GPIO_TYPE_INOUT_SD_DATA_5 GPIO_SET_IN_SEL(2+19) ++ //GPIO_TYPE_INOUT_SD_DATA_6 GPIO_SET_IN_SEL(2+20) ++ //GPIO_TYPE_INOUT_SD_DATA_7 GPIO_SET_IN_SEL(2+21) ++ //GPIO_TYPE_INOUT_SDIO_CMD GPIO_SET_IN_SEL(2+22) ++ GPIO_TYPE_INPUT_I2S_CLK = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+23) | GPIO_SET_OUT_SEL( 0), //!< Input type: i2s_clk ++ GPIO_TYPE_INPUT_I2S_WS = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+24) | GPIO_SET_OUT_SEL( 0), //!< Input type: i2s_ws ++ GPIO_TYPE_INPUT_I2S_SI = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+25) | GPIO_SET_OUT_SEL( 0), //!< Input type: i2s_si ++ GPIO_TYPE_INPUT_CLK_AU = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+26) | GPIO_SET_OUT_SEL( 0), //!< Input type: clk_au ++ GPIO_TYPE_INPUT_ENET_PHY_RXD_0 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+27) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_phy_rxd[0] ++ GPIO_TYPE_INPUT_ENET_PHY_RXD_1 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+28) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_phy_rxd[1] ++ GPIO_TYPE_INPUT_ENET_PHY_RXD_2 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+29) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_phy_rxd[2] ++ GPIO_TYPE_INPUT_ENET_PHY_RXD_3 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+30) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_phy_rxd[3] ++ GPIO_TYPE_INPUT_ENET_PHY_COL = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+31) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_phy_col ++ GPIO_TYPE_INPUT_ENET_PHY_CRS = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+32) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_phy_crs ++ GPIO_TYPE_INPUT_ENET_PHY_RXER = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+33) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_phy_rxer ++ GPIO_TYPE_INPUT_ENET_PHY_RXDV = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+34) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_phy_rxdv ++ // GPIO_TYPE_INOUT_ETH_MDIO GPIO_SET_IN_SEL(2+35) ++ GPIO_TYPE_INPUT_ENET_CLK_RX = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+36) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_clk_rx ++ GPIO_TYPE_INPUT_ENET_CLK_TX = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+37) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_clk_tx ++ ++ /* ----------------------------------- GPIO input&&output function define ----------------------------------- */ ++ GPIO_TYPE_INOUT_I2C_DATA = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 3) | GPIO_SET_IN_SEL(2+ 1) | GPIO_SET_OUT_SEL( 0), //!< Input/Output type: i2c_sda ++ GPIO_TYPE_INOUT_I2C_CLK = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 4) | GPIO_SET_IN_SEL(2+ 2) | GPIO_SET_OUT_SEL( 0), //!< Input/Output type: i2c_scl ++ GPIO_TYPE_INOUT_I2C_DATA2 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 5) | GPIO_SET_IN_SEL(2+ 3) | GPIO_SET_OUT_SEL( 0), //!< Input/Output type: i2c_sda2 ++ GPIO_TYPE_INOUT_I2C_CLK2 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 6) | GPIO_SET_IN_SEL(2+ 4) | GPIO_SET_OUT_SEL( 0), //!< Input/Output type: i2c_scl2 ++ ++ GPIO_TYPE_INOUT_ETH_MDIO = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(19) | GPIO_SET_IN_SEL(2+35) | GPIO_SET_OUT_SEL(49), //!< Input/Output type: enet_gmii_mdi/enet_gmii_mod_o ++ ++ GPIO_TYPE_INOUT_SD_DATA_0 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 8) | GPIO_SET_IN_SEL(2+14) | GPIO_SET_OUT_SEL(22), //!< Input/Output type: sd_data_out[0] ++ GPIO_TYPE_INOUT_SD_DATA_1 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 9) | GPIO_SET_IN_SEL(2+15) | GPIO_SET_OUT_SEL(23), //!< Input/Output type: sd_data_out[1] ++ GPIO_TYPE_INOUT_SD_DATA_2 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(10) | GPIO_SET_IN_SEL(2+16) | GPIO_SET_OUT_SEL(24), //!< Input/Output type: sd_data_out[2] ++ GPIO_TYPE_INOUT_SD_DATA_3 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(11) | GPIO_SET_IN_SEL(2+17) | GPIO_SET_OUT_SEL(25), //!< Input/Output type: sd_data_out[3] ++ GPIO_TYPE_INOUT_SD_DATA_4 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(12) | GPIO_SET_IN_SEL(2+18) | GPIO_SET_OUT_SEL(26), //!< Input/Output type: sd_data_out[4] ++ GPIO_TYPE_INOUT_SD_DATA_5 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(13) | GPIO_SET_IN_SEL(2+19) | GPIO_SET_OUT_SEL(27), //!< Input/Output type: sd_data_out[5] ++ GPIO_TYPE_INOUT_SD_DATA_6 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(14) | GPIO_SET_IN_SEL(2+20) | GPIO_SET_OUT_SEL(28), //!< Input/Output type: sd_data_out[6] ++ GPIO_TYPE_INOUT_SD_DATA_7 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(15) | GPIO_SET_IN_SEL(2+21) | GPIO_SET_OUT_SEL(29), //!< Input/Output type: sd_data_out[7] ++ GPIO_TYPE_INOUT_SD_CMD = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(16) | GPIO_SET_IN_SEL(2+22) | GPIO_SET_OUT_SEL(30), //!< Input/Output : sd_cmd ++ ++ GPIO_TYPE_UNDEFINED = 0, ++} GPIO_TYPE_E; ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Data Structures ++//***************************************************************************** ++//***************************************************************************** ++typedef union { /* PLL_IOCTRL_GPIO */ ++ u32 all; ++ struct { ++ u32 io1 : 6; ++ u32 : 2; ++ u32 io2 : 6; ++ u32 : 2; ++ u32 io0 : 6; ++ u32 : 2; ++ u32 io3 : 6; ++ u32 : 2; ++ } bitc; ++} GH_PLL_IOCTRL_GPIO_S; ++ ++typedef union { /* GPIO_OUTPUT_CFG */ ++ u32 all; ++ struct { ++ u32 out_sel : 6; ++ u32 : 2; ++ u32 oen_sel : 6; ++ u32 out_invert : 1; ++ u32 oen_invert : 1; ++ u32 : 16; ++ } bitc; ++} GH_GPIO_OUTPUT_CFG_S; ++ ++typedef union { /* GPIO_INPUT_CFG */ ++ u32 all; ++ struct { ++ u32 in_sel : 6; ++ u32 : 26; ++ } bitc; ++} GH_GPIO_INPUT_CFG_S; ++ ++typedef union { /* GPIO_INT_EN */ ++ u32 all; ++ struct { ++ u32 int_en : 1; ++ u32 : 31; ++ } bitc; ++} GH_GPIO_INT_EN_S; ++ ++typedef struct gpio_cfg ++{ ++ u32 gpio_count; ++ GPIO_XREF_S gpio_chip[64]; ++ u32 extphy_gpio_count; ++ GPIO_XREF_S ext_phy_gpio[16]; ++ u32 intphy_gpio_count; ++ GPIO_XREF_S int_phy_gpio[16]; ++ ++ u32 ir_led_ctl; ++ u32 ir_cut1; ++ u32 ir_cut2; ++ ++ u32 sensor_reset; ++ ++ u32 phy_reset; ++ u32 phy_speed_led; ++ ++ u32 spi0_en0; ++ u32 spi1_en0; ++ ++ u32 pwm0; ++ u32 pwm1; ++ u32 pwm2; ++ u32 pwm3; ++ ++ u32 usb_host; ++ ++ u32 sd_detect; ++ u32 sd_power; ++ ++ //board info ++ u32 soc_type; ++ s8 board_type[32]; ++ u32 board_version; ++ u32 reserve1; ++ ++ //extra device info ++ u32 ext_phy_clk; ++ u32 reserve2; ++ ++ // Add by Steven Yu:for pmu ++ u32 pmu_ctl; ++ ++}gpio_cfg_t; ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Global Data ++//***************************************************************************** ++//***************************************************************************** ++extern gpio_cfg_t gk_all_gpio_cfg; ++extern u8 cmdline_phytype; ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** API Functions ++//***************************************************************************** ++//***************************************************************************** ++ ++ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++ ++ ++#endif /* _GK_GPIO_V1_00_H_ */ ++ +diff --git a/arch/arm/plat-goke/include/plat/gk_gpio_v1_10.h b/arch/arm/plat-goke/include/plat/gk_gpio_v1_10.h +new file mode 100644 +index 00000000..e83395c5 +--- /dev/null ++++ b/arch/arm/plat-goke/include/plat/gk_gpio_v1_10.h +@@ -0,0 +1,506 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/plat-goke/include/plat/gk_gpio_v1_10.h ++** ++** \version $Id: gk_gpio_v1_10.h 10728 2016-10-21 02:05:33Z yulindeng $ ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2016 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++#ifndef _GK_GPIO_V1_10_H_ ++#define _GK_GPIO_V1_10_H_ ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Defines and Macros ++//***************************************************************************** ++//***************************************************************************** ++/************************/ ++/* GPIO pins definition */ ++/************************/ ++#define GPIO_SET_OUT_SEL(n) ((n)&0x7F) ++#define GPIO_SET_IN_SEL(n) (((n)&0x7F)<<7) ++#define GPIO_SET_OEN_SEL(n) (((n)&0x7F)<<14) ++#define GPIO_SET_OUT_INVERT(n) (((n)&0x1)<<22) ++#define GPIO_SET_OEN_INVERT(n) (((n)&0x1)<<23) ++#define GPIO_SET_IOCTRL(n) (((n)&0x3F)<<24) ++#define GPIO_SET_FUNC(n) (((n)&0x3)<<30) ++ ++#define GPIO_GET_OUT_SEL(n) (((n)&0x0000007F)) ++#define GPIO_GET_IN_SEL(n) (((n)&0x00003F80)>>7) ++#define GPIO_GET_OEN_SEL(n) (((n)&0x001FC000)>>14) ++#define GPIO_GET_OUT_INVERT(n) (((n)&0x00400000)>>22) ++#define GPIO_GET_OEN_INVERT(n) (((n)&0x00800000)>>23) ++#define GPIO_GET_IOCTRL(n) (((n)&0x3F000000)>>24) ++#define GPIO_GET_FUNC(n) (((n)&0xC0000000)>>30) ++ ++#define IOCTRL_NORMAL 0x00 //!< Hi-z ++#define IOCTRL_PULL_UP 0x10 //!< PULL_UP ++#define IOCTRL_PULL_DOWN 0x20 //!< PULL_DOWN ++#define IOCTRL_REPEAT 0x30 //!< REPEAT ++ ++#define IOCTRL_2MA 0x00 //!< 2mA ++#define IOCTRL_4MA 0x01 //!< 4mA ++#define IOCTRL_8MA 0x02 //!< 8mA ++#define IOCTRL_12MA 0x03 //!< 12mA ++#define IOCTRL_10MA 0x03 //!< 10mA ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Enumerated types ++//***************************************************************************** ++//***************************************************************************** ++typedef enum ++{ ++ /* ----------------------------------- GPIO output function define ----------------------------------- */ ++ //GPIO_SET_OUT_SEL( 0) ++ //GPIO_SET_OUT_SEL( 1) ++ //GPIO_SET_OUT_SEL( 2) ++ GPIO_TYPE_OUTPUT_JTAG_TDO = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 3) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 3), //!< 3.Output type: pad_jtag_tdo ++ //GPIO_TYPE_INOUT_I2C_CLK GPIO_SET_OEN_SEL( 4) | GPIO_SET_IN_SEL( 4) | GPIO_SET_OUT_SEL( 4), //!< 4.Input/Output type : pad_sensor_scl ++ //GPIO_TYPE_INOUT_I2C_DATA GPIO_SET_OEN_SEL( 5) | GPIO_SET_IN_SEL( 5) | GPIO_SET_OUT_SEL( 5), //!< 5.Input/Output type : pad_sensor_sda ++ GPIO_TYPE_OUTPUT_SENSOR_RESET = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 6), //!< 6.Output type: pad_sensor_reset ++ GPIO_TYPE_OUTPUT_SENSOR_POWEREN = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 7), //!< 7.Output type: pad_sensor_poweren ++ GPIO_TYPE_OUTPUT_LCD_DATA0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 8), //!< 8.Output type: pad_lcd_data0 ++ GPIO_TYPE_OUTPUT_LCD_DATA1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 9), //!< 9.Output type: pad_lcd_data1 ++ GPIO_TYPE_OUTPUT_LCD_DATA2 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 10), //!< 10.Output type: pad_lcd_data2 ++ GPIO_TYPE_OUTPUT_LCD_DATA3 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 11), //!< 11.Output type: pad_lcd_data3 ++ GPIO_TYPE_OUTPUT_LCD_DATA4 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 12), //!< 12.Output type: pad_lcd_data4 ++ GPIO_TYPE_OUTPUT_LCD_DATA5 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 13), //!< 13.Output type: pad_lcd_data5 ++ GPIO_TYPE_OUTPUT_LCD_DATA6 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 14), //!< 14.Output type: pad_lcd_data6 ++ GPIO_TYPE_OUTPUT_LCD_DATA7 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 15), //!< 15.Output type: pad_lcd_data7 ++ GPIO_TYPE_OUTPUT_LCD_DATA8 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 16), //!< 16.Output type: pad_lcd_data8 ++ GPIO_TYPE_OUTPUT_LCD_DATA9 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 17), //!< 17.Output type: pad_lcd_data9 ++ GPIO_TYPE_OUTPUT_LCD_DATA10 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 18), //!< 18.Output type: pad_lcd_data10 ++ GPIO_TYPE_OUTPUT_LCD_DATA11 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 19), //!< 19.Output type: pad_lcd_data11 ++ GPIO_TYPE_OUTPUT_LCD_DATA12 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 20), //!< 20.Output type: pad_lcd_data12 ++ GPIO_TYPE_OUTPUT_LCD_DATA13 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 21), //!< 21.Output type: pad_lcd_data13 ++ GPIO_TYPE_OUTPUT_LCD_DATA14 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 22), //!< 22.Output type: pad_lcd_data14 ++ GPIO_TYPE_OUTPUT_LCD_DATA15 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 23), //!< 23.Output type: pad_lcd_data15 ++ GPIO_TYPE_OUTPUT_LCD_DATA16 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 24), //!< 24.Output type: pad_lcd_data16 ++ GPIO_TYPE_OUTPUT_LCD_DATA17 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 25), //!< 25.Output type: pad_lcd_data17 ++ GPIO_TYPE_OUTPUT_LCD_DATA18 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 26), //!< 26.Output type: pad_lcd_data18 ++ GPIO_TYPE_OUTPUT_LCD_DATA19 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 27), //!< 27.Output type: pad_lcd_data19 ++ GPIO_TYPE_OUTPUT_LCD_DATA20 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 28), //!< 28.Output type: pad_lcd_data20 ++ GPIO_TYPE_OUTPUT_LCD_DATA21 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 29), //!< 29.Output type: pad_lcd_data21 ++ GPIO_TYPE_OUTPUT_LCD_DATA22 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 30), //!< 30.Output type: pad_lcd_data22 ++ GPIO_TYPE_OUTPUT_LCD_DATA23 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 31), //!< 31.Output type: pad_lcd_data23 ++ GPIO_TYPE_OUTPUT_LCD_DEN = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 32), //!< 32.Output type: pad_lcd_den ++ GPIO_TYPE_OUTPUT_LCD_VSYNC = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 33), //!< 33.Output type: pad_lcd_vsync ++ GPIO_TYPE_OUTPUT_LCD_HSYNC = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 34), //!< 34.Output type: pad_lcd_hsync ++ GPIO_TYPE_OUTPUT_LCD_CLOCK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_10MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 35), //!< 35.Output type: pad_lcd_clock ++ //GPIO_TYPE_INOUT_I2C_CLK2 GPIO_SET_OEN_SEL( 36) | GPIO_SET_IN_SEL( 36) | GPIO_SET_OUT_SEL( 36), //!< 36.Input/Output type : pad_lcd_scl ++ //GPIO_TYPE_INOUT_I2C_DATA2 GPIO_SET_OEN_SEL( 37) | GPIO_SET_IN_SEL( 37) | GPIO_SET_OUT_SEL( 37), //!< 37.Input/Output type : pad_lcd_sda ++ GPIO_TYPE_OUTPUT_LCD_CS = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 38), //!< 38.Output type: pad_lcd_cs ++ GPIO_TYPE_OUTPUT_LCD_RESET = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 39), //!< 39.Output type: pad_lcd_reset ++ GPIO_TYPE_OUTPUT_LCD_BL_EN = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 40), //!< 40.Output type: pad_lcd_bl_en ++ //GPIO_TYPE_INPUT_USB_OTG_ID GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 41) | GPIO_SET_OUT_SEL( 41), //!< 41.Input type: pad_usb_otg_id ++ //GPIO_TYPE_INOUT_SD_DATA_0 GPIO_SET_OEN_SEL( 42) | GPIO_SET_IN_SEL( 42) | GPIO_SET_OUT_SEL( 42), //!< 42.Input/Output type : pad_sd0_d0 ++ //GPIO_TYPE_INOUT_SD_DATA_1 GPIO_SET_OEN_SEL( 43) | GPIO_SET_IN_SEL( 43) | GPIO_SET_OUT_SEL( 43), //!< 43.Input/Output type : pad_sd0_d1 ++ //GPIO_TYPE_INOUT_SD_DATA_2 GPIO_SET_OEN_SEL( 44) | GPIO_SET_IN_SEL( 44) | GPIO_SET_OUT_SEL( 44), //!< 44.Input/Output type : pad_sd0_d2 ++ //GPIO_TYPE_INOUT_SD_DATA_3 GPIO_SET_OEN_SEL( 45) | GPIO_SET_IN_SEL( 45) | GPIO_SET_OUT_SEL( 45), //!< 45.Input/Output type : pad_sd0_d3 ++ GPIO_TYPE_OUTPUT_SDIO_CLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_REPEAT |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 46) | GPIO_SET_IN_SEL( 46) | GPIO_SET_OUT_SEL( 46), //!< 46.Output type: pad_sd0_clk ++ //GPIO_TYPE_INOUT_SD_CMD GPIO_SET_OEN_SEL( 47) | GPIO_SET_IN_SEL( 47) | GPIO_SET_OUT_SEL( 47), //!< 47.Input/Output type : pad_sd0_cmd ++ GPIO_TYPE_INPUT_SD_CD_N = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 48) | GPIO_SET_IN_SEL( 48) | GPIO_SET_OUT_SEL( 48), //!< 48.Output type: pad_sd0_cd ++ //GPIO_TYPE_INPUT_SPI0_SI GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 49) | GPIO_SET_OUT_SEL( 49), //!< 49.Input type: pad_spi_si ++ GPIO_TYPE_OUTPUT_SPI0_SO = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 50) | GPIO_SET_IN_SEL( 50) | GPIO_SET_OUT_SEL( 50), //!< 50.Output type: pad_spi_so ++ GPIO_TYPE_OUTPUT_SPI0_CS0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 51) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 51), //!< 51.Output type: pad_spi_cs ++ GPIO_TYPE_OUTPUT_SPI0_SCLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 52) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 52), //!< 52.Output type: pad_spi_sclk ++ //GPIO_TYPE_INPUT_UART0_RX GPIO_SET_OEN_SEL( 53) | GPIO_SET_IN_SEL( 53) | GPIO_SET_OUT_SEL( 53), //!< 53.Input type: pad_uart_rx ++ GPIO_TYPE_OUTPUT_UART0_TX = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 54) | GPIO_SET_IN_SEL( 54) | GPIO_SET_OUT_SEL( 54), //!< 54.Output type: pad_uart_tx ++ GPIO_TYPE_OUTPUT_GPS_POWER_EN = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 55), //!< 55.Output type: pad_gps_power_en ++ GPIO_TYPE_OUTPUT_GPS_TXD = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 56) | GPIO_SET_IN_SEL( 56) | GPIO_SET_OUT_SEL( 56), //!< 56.Output type: pad_gps_tx ++ //GPIO_TYPE_INPUT_GPS_RXD GPIO_SET_OEN_SEL( 57) | GPIO_SET_IN_SEL( 57) | GPIO_SET_OUT_SEL( 57), //!< 57.Input type: pad_gps_rx ++ GPIO_TYPE_OUTPUT_RD_POWER_EN = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL( 58) | GPIO_SET_OUT_SEL( 58), //!< 58.Output type: pad_rd_power_en ++ //GPIO_TYPE_INPUT_RD_RXD GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 59) | GPIO_SET_OUT_SEL( 59), //!< 59.Input type: pad_rd_rx ++ //GPIO_TYPE_INOUT_I2C_CLK3 GPIO_SET_OEN_SEL( 60) | GPIO_SET_IN_SEL( 60) | GPIO_SET_OUT_SEL( 60), //!< 60.Input/Output type : pad_g_sen_sck ++ //GPIO_TYPE_INOUT_I2C_DATA3 GPIO_SET_OEN_SEL( 61) | GPIO_SET_IN_SEL( 61) | GPIO_SET_OUT_SEL( 61), //!< 61.Input/Output type : pad_g_sen_sda ++ GPIO_TYPE_OUTPUT_SF_CS0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 62) | GPIO_SET_IN_SEL( 62) | GPIO_SET_OUT_SEL( 62), //!< 62.Output type: pad_sf_cs ++ GPIO_TYPE_OUTPUT_PWM = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL( 63) | GPIO_SET_OUT_SEL( 63), //!< 63.Output type: pad_pwm ++ GPIO_TYPE_OUTPUT_I2S_MCLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 64) | GPIO_SET_IN_SEL( 64) | GPIO_SET_OUT_SEL( 64), //!< 64.Output type: pad_i2s_mclk ++ //GPIO_TYPE_INOUT_I2S_SCLK GPIO_SET_OEN_SEL( 65) | GPIO_SET_IN_SEL( 65) | GPIO_SET_OUT_SEL( 65), //!< 65.Input/Output type : pad_i2s_sclk ++ //GPIO_TYPE_INOUT_I2S_WS GPIO_SET_OEN_SEL( 66) | GPIO_SET_IN_SEL( 66) | GPIO_SET_OUT_SEL( 66), //!< 66.Input/Output type : pad_i2s_ws ++ //GPIO_TYPE_INPUT_I2S_SDATA0 GPIO_SET_OEN_SEL( 67) | GPIO_SET_IN_SEL( 67) | GPIO_SET_OUT_SEL( 67), //!< 67.Input type: pad_i2s_sdata0 ++ GPIO_TYPE_OUTPUT_I2S_SDATA1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 68) | GPIO_SET_IN_SEL( 68) | GPIO_SET_OUT_SEL( 68), //!< 68.Output type: pad_i2s_data1 ++ GPIO_TYPE_OUTPUT_SPI0_CS1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 74) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 69), //!< 69.Output type: ss_1_n ++ GPIO_TYPE_OUTPUT_SPI0_CS4 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 74) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 70), //!< 70.Output type: ss_4_n ++ GPIO_TYPE_OUTPUT_SPI0_CS5 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 74) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 71), //!< 71.Output type: ss_5_n ++ GPIO_TYPE_OUTPUT_SPI0_CS6 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 74) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 72), //!< 72.Output type: ss_6_n ++ GPIO_TYPE_OUTPUT_SPI0_CS7 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 74) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 73), //!< 73.Output type: ss_7_n ++ GPIO_TYPE_OUTPUT_SS_TXD2 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 74), //!< 74.Output type: txd2 ++ GPIO_TYPE_OUTPUT_SCLK2 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 75), //!< 75.Output type: sclk2_out ++ GPIO_TYPE_OUTPUT_RTS2 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 76), //!< 76.Output type: rts_2_n ++ GPIO_TYPE_OUTPUT_DTR2 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 77), //!< 77.Output type: dtr_2_n ++ GPIO_TYPE_OUTPUT_UART1_TX = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 78), //!< 78.Output type: UART_TX_2 ++ GPIO_TYPE_OUTPUT_UART2_TX = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 79), //!< 79.Output type: UART_TX_3 ++ //GPIO_SET_OUT_SEL( 80) ++ //GPIO_SET_OUT_SEL( 81) ++ GPIO_TYPE_OUTPUT_EPHY_LED_0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 82), //!< 82.Output type: enet_phy_led0 ++ GPIO_TYPE_OUTPUT_EPHY_LED_1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 83), //!< 83.Output type: enet_phy_led1 ++ GPIO_TYPE_OUTPUT_EPHY_LED_2 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 84), //!< 84.Output type: enet_phy_led2 ++ GPIO_TYPE_OUTPUT_EPHY_LED_3 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 85), //!< 85.Output type: enet_phy_led3 ++ GPIO_TYPE_OUTPUT_EPHY_LED_4 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 86), //!< 86.Output type: enet_phy_led4 ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXD_0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 87), //!< 87.Output type: enet_phy_txd0 ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXD_1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 88), //!< 88.Output type: enet_phy_txd1 ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXD_2 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 89), //!< 89.Output type: enet_phy_txd2 ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXD_3 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 90), //!< 90.Output type: enet_phy_txd3 ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXER = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 91), //!< 91.Output type: enet_phy_txer ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXEN = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 92), //!< 92.Output type: enet_phy_txen ++ //GPIO_TYPE_INOUT_ETH_MDIO GPIO_SET_OEN_SEL( 69) | GPIO_SET_IN_SEL( 87) | GPIO_SET_OUT_SEL( 93), //!< 93.Output type: enet_gmii_mdo_o ++ GPIO_TYPE_OUTPUT_ENET_GMII_MDC_O = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 94), //!< 94.Output type: enet_gmii_mdc_o ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 95), //!< 95.Output type: ahd_dac_dr0 ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 96), //!< 96.Output type: ahd_dac_dr1 ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_2 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 97), //!< 97.Output type: ahd_dac_dr2 ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_3 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 98), //!< 98.Output type: ahd_dac_dr3 ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_4 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL( 99), //!< 99.Output type: ahd_dac_dr4 ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_5 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL(100), //!<100.Output type: ahd_dac_dr5 ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_6 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL(101), //!<101.Output type: ahd_dac_dr6 ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_7 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL(102), //!<102.Output type: ahd_dac_dr7 ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_8 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL(103), //!<103.Output type: ahd_dac_dr8 ++ GPIO_TYPE_OUTPUT_AHB_DAC_DR_9 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL(104), //!<104.Output type: ahd_dac_dr9 ++ GPIO_TYPE_OUTPUT_I80_RESET = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL(105), //!<105.Output type: i80_reset ++ GPIO_TYPE_OUTPUT_I80_CS = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL(106), //!<106.Output type: i80_cs ++ GPIO_TYPE_OUTPUT_I80_RD = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL(107), //!<107.Output type: i80_rd ++ GPIO_TYPE_OUTPUT_I80_WR = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL(108), //!<108.Output type: i80_wr ++ GPIO_TYPE_OUTPUT_I80_RS = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL(109), //!<109.Output type: i80_rs ++ //GPIO_TYPE_INOUT_I80_D8 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 16) | GPIO_SET_OUT_SEL(110), //!<110.Output type: i80_d8 ++ //GPIO_TYPE_INOUT_I80_D7 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 15) | GPIO_SET_OUT_SEL(111), //!<111.Output type: i80_d7 ++ //GPIO_TYPE_INOUT_I80_D6 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 14) | GPIO_SET_OUT_SEL(112), //!<112.Output type: i80_d6 ++ //GPIO_TYPE_INOUT_I80_D5 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 13) | GPIO_SET_OUT_SEL(113), //!<113.Output type: i80_d5 ++ //GPIO_TYPE_INOUT_I80_D4 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 12) | GPIO_SET_OUT_SEL(114), //!<114.Output type: i80_d4 ++ //GPIO_TYPE_INOUT_I80_D3 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 11) | GPIO_SET_OUT_SEL(115), //!<115.Output type: i80_d3 ++ //GPIO_TYPE_INOUT_I80_D2 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 10) | GPIO_SET_OUT_SEL(116), //!<116.Output type: i80_d2 ++ //GPIO_TYPE_INOUT_I80_D1 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 9) | GPIO_SET_OUT_SEL(117), //!<117.Output type: i80_d1 ++ //GPIO_TYPE_INOUT_I80_D0 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 8) | GPIO_SET_OUT_SEL(118), //!<118.Output type: i80_d0 ++ GPIO_TYPE_INPUT_UART3_TX = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL(119), //!<119.Output type: UART_ORC_TX ++ //GPIO_SET_OUT_SEL(120) ++ //GPIO_SET_OUT_SEL(121) ++ //GPIO_SET_OUT_SEL(122) ++ //GPIO_SET_OUT_SEL(123) ++ //GPIO_SET_OUT_SEL(124) ++ //GPIO_SET_OUT_SEL(125) ++ GPIO_TYPE_OUTPUT_0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL(126), //!< Output type: value = 0 ++ GPIO_TYPE_OUTPUT_1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL(127), //!< Output type: value = 1 ++ ++ /* ----------------------------------- GPIO input function define ----------------------------------- */ ++ GPIO_TYPE_INPUT_JTAG_TRSTN = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 0), //!< 0. Input type: pad_jtag_trstn ++ GPIO_TYPE_INPUT_JTAG_TMS = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL( 1) | GPIO_SET_OUT_SEL( 0), //!< 1. Input type: pad_jtag_tms ++ GPIO_TYPE_INPUT_JTAG_TDI = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 2) | GPIO_SET_IN_SEL( 2) | GPIO_SET_OUT_SEL( 0), //!< 2. Input type: pad_jtag_tdi ++ //GPIO_SET_IN_SEL( 3) ++ //GPIO_TYPE_INOUT_I2C_CLK GPIO_SET_OEN_SEL( 4) | GPIO_SET_IN_SEL( 4) | GPIO_SET_OUT_SEL( 4), //!< 4. Input/Output type : pad_sensor_scl ++ //GPIO_TYPE_INOUT_I2C_DATA GPIO_SET_OEN_SEL( 5) | GPIO_SET_IN_SEL( 5) | GPIO_SET_OUT_SEL( 5), //!< 5. Input/Output type : pad_sensor_sda ++ //GPIO_SET_IN_SEL( 6) ++ //GPIO_SET_IN_SEL( 7) ++ //GPIO_TYPE_INOUT_I80_D0 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 8) | GPIO_SET_OUT_SEL(118), //!<118.Output type: i80_d0 ++ //GPIO_TYPE_INOUT_I80_D1 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 9) | GPIO_SET_OUT_SEL(117), //!<117.Output type: i80_d1 ++ //GPIO_TYPE_INOUT_I80_D2 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 10) | GPIO_SET_OUT_SEL(116), //!<116.Output type: i80_d2 ++ //GPIO_TYPE_INOUT_I80_D3 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 11) | GPIO_SET_OUT_SEL(115), //!<115.Output type: i80_d3 ++ //GPIO_TYPE_INOUT_I80_D4 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 12) | GPIO_SET_OUT_SEL(114), //!<114.Output type: i80_d4 ++ //GPIO_TYPE_INOUT_I80_D5 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 13) | GPIO_SET_OUT_SEL(113), //!<113.Output type: i80_d5 ++ //GPIO_TYPE_INOUT_I80_D6 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 14) | GPIO_SET_OUT_SEL(112), //!<112.Output type: i80_d6 ++ //GPIO_TYPE_INOUT_I80_D7 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 15) | GPIO_SET_OUT_SEL(111), //!<111.Output type: i80_d7 ++ //GPIO_TYPE_INOUT_I80_D8 GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 16) | GPIO_SET_OUT_SEL(110), //!<110.Output type: i80_d8 ++ //GPIO_SET_IN_SEL( 17) ++ //GPIO_SET_IN_SEL( 18) ++ //GPIO_SET_IN_SEL( 19) ++ //GPIO_SET_IN_SEL( 20) ++ //GPIO_SET_IN_SEL( 21) ++ //GPIO_SET_IN_SEL( 22) ++ //GPIO_SET_IN_SEL( 23) ++ //GPIO_SET_IN_SEL( 24) ++ //GPIO_SET_IN_SEL( 25) ++ //GPIO_SET_IN_SEL( 26) ++ //GPIO_SET_IN_SEL( 27) ++ //GPIO_SET_IN_SEL( 28) ++ //GPIO_SET_IN_SEL( 29) ++ //GPIO_SET_IN_SEL( 30) ++ //GPIO_SET_IN_SEL( 31) ++ //GPIO_SET_IN_SEL( 32) ++ //GPIO_SET_IN_SEL( 33) ++ //GPIO_SET_IN_SEL( 34) ++ //GPIO_SET_IN_SEL( 35) ++ //GPIO_TYPE_INOUT_I2C_CLK2 GPIO_SET_OEN_SEL( 36) | GPIO_SET_IN_SEL( 36) | GPIO_SET_OUT_SEL( 36), //!< 36.Input/Output type : pad_lcd_scl ++ //GPIO_TYPE_INOUT_I2C_DATA2 GPIO_SET_OEN_SEL( 37) | GPIO_SET_IN_SEL( 37) | GPIO_SET_OUT_SEL( 37), //!< 37.Input/Output type : pad_lcd_sda ++ //GPIO_SET_IN_SEL( 38) ++ //GPIO_SET_IN_SEL( 39) ++ //GPIO_SET_IN_SEL( 40) ++ GPIO_TYPE_INPUT_USB_OTG_ID = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_REPEAT |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 41) | GPIO_SET_OUT_SEL( 41), //!< 41.Input type: pad_usb_otg_id ++ //GPIO_TYPE_INOUT_SD_DATA_0 GPIO_SET_OEN_SEL( 42) | GPIO_SET_IN_SEL( 42) | GPIO_SET_OUT_SEL( 42), //!< 42.Input/Output type : pad_sd0_d0 ++ //GPIO_TYPE_INOUT_SD_DATA_1 GPIO_SET_OEN_SEL( 43) | GPIO_SET_IN_SEL( 43) | GPIO_SET_OUT_SEL( 43), //!< 43.Input/Output type : pad_sd0_d1 ++ //GPIO_TYPE_INOUT_SD_DATA_2 GPIO_SET_OEN_SEL( 44) | GPIO_SET_IN_SEL( 44) | GPIO_SET_OUT_SEL( 44), //!< 44.Input/Output type : pad_sd0_d2 ++ //GPIO_TYPE_INOUT_SD_DATA_3 GPIO_SET_OEN_SEL( 45) | GPIO_SET_IN_SEL( 45) | GPIO_SET_OUT_SEL( 45), //!< 45.Input/Output type : pad_sd0_d3 ++ //GPIO_TYPE_OUTPUT_SDIO_CLK GPIO_SET_OEN_SEL( 46) | GPIO_SET_IN_SEL( 46) | GPIO_SET_OUT_SEL( 46), //!< 46.Output type: pad_sd0_clk ++ //GPIO_TYPE_INOUT_SD_CMD GPIO_SET_OEN_SEL( 47) | GPIO_SET_IN_SEL( 47) | GPIO_SET_OUT_SEL( 47), //!< 47.Input/Output type : pad_sd0_cmd ++ //GPIO_TYPE_INPUT_SD_CD_N GPIO_SET_OEN_SEL( 48) | GPIO_SET_IN_SEL( 48) | GPIO_SET_OUT_SEL( 48), //!< 48.Output type: pad_sd0_cd ++ GPIO_TYPE_INPUT_SPI0_SI = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 49) | GPIO_SET_OUT_SEL( 49), //!< 49.Input type: pad_spi_si ++ //PIO_TYPE_OUTPUT_SPI_SO GPIO_SET_OEN_SEL( 50) | GPIO_SET_IN_SEL( 50) | GPIO_SET_OUT_SEL( 50), //!< 50.Output type: pad_spi_so ++ //GPIO_SET_IN_SEL( 51) ++ //GPIO_SET_IN_SEL( 52) ++ GPIO_TYPE_INPUT_UART0_RX = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 53) | GPIO_SET_IN_SEL( 53) | GPIO_SET_OUT_SEL( 53), //!< 53.Input type: pad_uart_rx ++ //GPIO_TYPE_OUTPUT_UART0_TX GPIO_SET_OEN_SEL( 54) | GPIO_SET_IN_SEL( 54) | GPIO_SET_OUT_SEL( 54), //!< 54.Output type: pad_uart_tx ++ //GPIO_SET_IN_SEL( 55) ++ //GPIO_TYPE_OUTPUT_GPS_TXD GPIO_SET_OEN_SEL( 56) | GPIO_SET_IN_SEL( 56) | GPIO_SET_OUT_SEL( 56), //!< 56.Output type: pad_gps_tx ++ GPIO_TYPE_INPUT_GPS_RXD = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 57) | GPIO_SET_IN_SEL( 57) | GPIO_SET_OUT_SEL( 57), //!< 57.Input type: pad_gps_rx ++ //GPIO_TYPE_OUTPUT_RD_POWER_EN GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL( 58) | GPIO_SET_OUT_SEL( 58), //!< 58.Output type: pad_rd_power_en ++ GPIO_TYPE_INPUT_RD_RXD = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 59) | GPIO_SET_OUT_SEL( 59), //!< 59.Input type: pad_rd_rx ++ //GPIO_TYPE_INOUT_I2C_CLK3 GPIO_SET_OEN_SEL( 60) | GPIO_SET_IN_SEL( 60) | GPIO_SET_OUT_SEL( 60), //!< 60.Input/Output type : pad_g_sen_sck ++ //GPIO_TYPE_INOUT_I2C_DATA3 GPIO_SET_OEN_SEL( 61) | GPIO_SET_IN_SEL( 61) | GPIO_SET_OUT_SEL( 61), //!< 61.Input/Output type : pad_g_sen_sda ++ //GPIO_TYPE_OUTPUT_SF_CS0 GPIO_SET_OEN_SEL( 62) | GPIO_SET_IN_SEL( 62) | GPIO_SET_OUT_SEL( 62), //!< 62.Output type: pad_sf_cs ++ //GPIO_TYPE_OUTPUT_PWM GPIO_SET_OEN_SEL(126) | GPIO_SET_IN_SEL( 63) | GPIO_SET_OUT_SEL( 63), //!< 63.Output type: pad_pwm ++ //GPIO_TYPE_OUTPUT_I2S_MCLK GPIO_SET_OEN_SEL( 64) | GPIO_SET_IN_SEL( 64) | GPIO_SET_OUT_SEL( 64), //!< 64.Output type: pad_i2s_mclk ++ //GPIO_TYPE_INOUT_I2S_SCLK GPIO_SET_OEN_SEL( 65) | GPIO_SET_IN_SEL( 65) | GPIO_SET_OUT_SEL( 65), //!< 65.Input/Output type : pad_i2s_sclk ++ //GPIO_TYPE_INOUT_I2S_WS GPIO_SET_OEN_SEL( 66) | GPIO_SET_IN_SEL( 66) | GPIO_SET_OUT_SEL( 66), //!< 66.Input/Output type : pad_i2s_ws ++ //GPIO_TYPE_INPUT_I2S_SDATA0 GPIO_SET_OEN_SEL( 67) | GPIO_SET_IN_SEL( 67) | GPIO_SET_OUT_SEL( 67), //!< 67.Input type: pad_i2s_sdata0 ++ //GPIO_TYPE_OUTPUT_I2S_SDATA1 GPIO_SET_OEN_SEL( 68) | GPIO_SET_IN_SEL( 68) | GPIO_SET_OUT_SEL( 68), //!< 68.Output type: pad_i2s_data1 ++ GPIO_TYPE_INPUT_TIMER1_CLK = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 69) | GPIO_SET_OUT_SEL(126), //!< 69.Input type: tm11_clk ++ GPIO_TYPE_INPUT_TIMER2_CLK = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 70) | GPIO_SET_OUT_SEL(126), //!< 70.Input type: tm12_clk ++ GPIO_TYPE_INPUT_TIMER3_CLK = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 71) | GPIO_SET_OUT_SEL(126), //!< 71.Input type: tm13_clk ++ GPIO_TYPE_INPUT_SD_DATA4 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 70) | GPIO_SET_IN_SEL( 72) | GPIO_SET_OUT_SEL(126), //!< Input type: sd_data4_in ++ GPIO_TYPE_INPUT_SD_DATA5 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 71) | GPIO_SET_IN_SEL( 73) | GPIO_SET_OUT_SEL(126), //!< Input type: sd_data5_in ++ GPIO_TYPE_INPUT_SD_DATA6 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 72) | GPIO_SET_IN_SEL( 74) | GPIO_SET_OUT_SEL(126), //!< Input type: sd_data6_in ++ GPIO_TYPE_INPUT_SD_DATA7 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 73) | GPIO_SET_IN_SEL( 75) | GPIO_SET_OUT_SEL(126), //!< Input type: sd_data7_in ++ GPIO_TYPE_INPUT_ENET_CLK_RX = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 76) | GPIO_SET_OUT_SEL(126), //!< 76.Input type: gpio_clk_rx_i ++ GPIO_TYPE_INPUT_ENET_CLK_TX = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 77) | GPIO_SET_OUT_SEL(126), //!< 77.Input type: gpio_clk_tx_i ++ GPIO_TYPE_INPUT_GPIO_RCT_CLK = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 78) | GPIO_SET_OUT_SEL(126), //!< 78.Input type: gpio_rct_clk_au ++ GPIO_TYPE_INPUT_ENET_PHY_RXD_0 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 79) | GPIO_SET_OUT_SEL(126), //!< 79.Input type: gpio_phy_rxd0 ++ GPIO_TYPE_INPUT_ENET_PHY_RXD_1 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 80) | GPIO_SET_OUT_SEL(126), //!< 80.Input type: gpio_phy_rxd1 ++ GPIO_TYPE_INPUT_ENET_PHY_RXD_2 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_REPEAT |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 81) | GPIO_SET_OUT_SEL(126), //!< 81.Input type: gpio_phy_rxd2 ++ GPIO_TYPE_INPUT_ENET_PHY_RXD_3 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 82) | GPIO_SET_OUT_SEL(126), //!< 82.Input type: gpio_phy_rxd3 ++ GPIO_TYPE_INPUT_ENET_PHY_COL = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 83) | GPIO_SET_OUT_SEL(126), //!< 83.Input type: gpio_phy_cil_i ++ GPIO_TYPE_INPUT_ENET_PHY_CRS = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 84) | GPIO_SET_OUT_SEL(126), //!< 84.Input type: gpio_phy_crs_i ++ GPIO_TYPE_INPUT_ENET_PHY_RXER = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 85) | GPIO_SET_OUT_SEL(126), //!< 85.Input type: gpio_phy_rxer ++ GPIO_TYPE_INPUT_ENET_PHY_RXDV = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 86) | GPIO_SET_OUT_SEL(126), //!< 86.Input type: gpio_phy_rxdv ++ //GPIO_TYPE_INOUT_ETH_MDIO GPIO_SET_OEN_SEL( 69) | GPIO_SET_IN_SEL( 87) | GPIO_SET_OUT_SEL( 93), //!< 93.Output type: enet_gmii_mdo_o ++ GPIO_TYPE_INPUT_UART1_RX = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 88) | GPIO_SET_OUT_SEL(126), //!< 88.Input type: UART_RX_2 ++ GPIO_TYPE_INPUT_UART2_RX = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 89) | GPIO_SET_OUT_SEL(126), //!< 89.Input type: UART_RX_3 ++ GPIO_TYPE_INPUT_SS_RXD2 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 90) | GPIO_SET_OUT_SEL(126), //!< 90.Input type: usrt3rx ++ GPIO_TYPE_INPUT_SD_WP_N = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 91) | GPIO_SET_OUT_SEL(126), //!< 91.Input type: sdwp_n ++ GPIO_TYPE_INPUT_SD_WP3 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 92) | GPIO_SET_OUT_SEL(126), //!< 92.Input type: sdwp_n3 ++ GPIO_TYPE_INPUT_UART3_RX = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL( 93) | GPIO_SET_OUT_SEL(126), //!< 93.Input type: UART_ORC_RX ++ //GPIO_SET_IN_SEL( 94) ++ //GPIO_SET_IN_SEL( 95) ++ //GPIO_SET_IN_SEL( 96) ++ //GPIO_SET_IN_SEL( 97) ++ //GPIO_SET_IN_SEL( 98) ++ //GPIO_SET_IN_SEL( 99) ++ //GPIO_SET_IN_SEL(100) ++ //GPIO_SET_IN_SEL(101) ++ //GPIO_SET_IN_SEL(102) ++ //GPIO_SET_IN_SEL(103) ++ //GPIO_SET_IN_SEL(104) ++ //GPIO_SET_IN_SEL(105) ++ //GPIO_SET_IN_SEL(106) ++ //GPIO_SET_IN_SEL(107) ++ //GPIO_SET_IN_SEL(108) ++ //GPIO_SET_IN_SEL(109) ++ //GPIO_SET_IN_SEL(110) ++ //GPIO_SET_IN_SEL(111) ++ //GPIO_SET_IN_SEL(112) ++ //GPIO_SET_IN_SEL(113) ++ //GPIO_SET_IN_SEL(114) ++ //GPIO_SET_IN_SEL(115) ++ //GPIO_SET_IN_SEL(116) ++ //GPIO_SET_IN_SEL(117) ++ //GPIO_SET_IN_SEL(118) ++ //GPIO_SET_IN_SEL(119) ++ //GPIO_SET_IN_SEL(120) ++ //GPIO_SET_IN_SEL(121) ++ //GPIO_SET_IN_SEL(122) ++ //GPIO_SET_IN_SEL(123) ++ //GPIO_SET_IN_SEL(124) ++ //GPIO_SET_IN_SEL(125) ++ GPIO_TYPE_INPUT = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL(127), //!< Input type: normal input ++ GPIO_TYPE_INPUT_0 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL(126) | GPIO_SET_OUT_SEL(127), //!< Input type: normal input ++ GPIO_TYPE_INPUT_1 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(127) | GPIO_SET_IN_SEL(127) | GPIO_SET_OUT_SEL(127), //!< Input type: normal input ++ ++ /* ----------------------------------- GPIO input&&output function define ----------------------------------- */ ++ GPIO_TYPE_INOUT_I2C_CLK = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 4) | GPIO_SET_IN_SEL( 4) | GPIO_SET_OUT_SEL( 4), //!< 4.Input/Output type : pad_sensor_scl ++ GPIO_TYPE_INOUT_I2C_DATA = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 5) | GPIO_SET_IN_SEL( 5) | GPIO_SET_OUT_SEL( 5), //!< 5.Input/Output type : pad_sensor_sda ++ GPIO_TYPE_INOUT_I80_D0 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 8) | GPIO_SET_OUT_SEL(118), //!<118.Output type: i80_d0 ++ GPIO_TYPE_INOUT_I80_D1 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 9) | GPIO_SET_OUT_SEL(117), //!<117.Output type: i80_d1 ++ GPIO_TYPE_INOUT_I80_D2 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 10) | GPIO_SET_OUT_SEL(116), //!<116.Output type: i80_d2 ++ GPIO_TYPE_INOUT_I80_D3 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 11) | GPIO_SET_OUT_SEL(115), //!<115.Output type: i80_d3 ++ GPIO_TYPE_INOUT_I80_D4 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 12) | GPIO_SET_OUT_SEL(114), //!<114.Output type: i80_d4 ++ GPIO_TYPE_INOUT_I80_D5 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 13) | GPIO_SET_OUT_SEL(113), //!<113.Output type: i80_d5 ++ GPIO_TYPE_INOUT_I80_D6 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 14) | GPIO_SET_OUT_SEL(112), //!<112.Output type: i80_d6 ++ GPIO_TYPE_INOUT_I80_D7 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 15) | GPIO_SET_OUT_SEL(111), //!<111.Output type: i80_d7 ++ GPIO_TYPE_INOUT_I80_D8 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 75) | GPIO_SET_IN_SEL( 16) | GPIO_SET_OUT_SEL(110), //!<110.Output type: i80_d8 ++ GPIO_TYPE_INOUT_I2C_CLK2 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 36) | GPIO_SET_IN_SEL( 36) | GPIO_SET_OUT_SEL( 36), //!< 36.Input/Output type : pad_lcd_scl ++ GPIO_TYPE_INOUT_I2C_DATA2 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 37) | GPIO_SET_IN_SEL( 37) | GPIO_SET_OUT_SEL( 37), //!< 37.Input/Output type : pad_lcd_sda ++ GPIO_TYPE_INOUT_SD_DATA_0 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 42) | GPIO_SET_IN_SEL( 42) | GPIO_SET_OUT_SEL( 42), //!< 42.Input/Output type : pad_sd0_d0 ++ GPIO_TYPE_INOUT_SD_DATA_1 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 43) | GPIO_SET_IN_SEL( 43) | GPIO_SET_OUT_SEL( 43), //!< 43.Input/Output type : pad_sd0_d1 ++ GPIO_TYPE_INOUT_SD_DATA_2 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 44) | GPIO_SET_IN_SEL( 44) | GPIO_SET_OUT_SEL( 44), //!< 44.Input/Output type : pad_sd0_d2 ++ GPIO_TYPE_INOUT_SD_DATA_3 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_8MA ) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 45) | GPIO_SET_IN_SEL( 45) | GPIO_SET_OUT_SEL( 45), //!< 45.Input/Output type : pad_sd0_d3 ++ GPIO_TYPE_INOUT_SD_CMD = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 47) | GPIO_SET_IN_SEL( 47) | GPIO_SET_OUT_SEL( 47), //!< 47.Input/Output type : pad_sd0_cmd ++ GPIO_TYPE_INOUT_I2C_CLK3 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 60) | GPIO_SET_IN_SEL( 60) | GPIO_SET_OUT_SEL( 60), //!< 60.Input/Output type : pad_g_sen_sck ++ GPIO_TYPE_INOUT_I2C_DATA3 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 61) | GPIO_SET_IN_SEL( 61) | GPIO_SET_OUT_SEL( 61), //!< 61.Input/Output type : pad_g_sen_sda ++ GPIO_TYPE_INOUT_I2S_SCLK = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 65) | GPIO_SET_IN_SEL( 65) | GPIO_SET_OUT_SEL( 65), //!< 65.Input/Output type : pad_i2s_sclk ++ GPIO_TYPE_INOUT_I2S_WS = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 66) | GPIO_SET_IN_SEL( 66) | GPIO_SET_OUT_SEL( 66), //!< 66.Input/Output type : pad_i2s_ws ++ GPIO_TYPE_INPUT_I2S_SDATA0 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA ) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 67) | GPIO_SET_IN_SEL( 67) | GPIO_SET_OUT_SEL( 67), //!< 67.Input type: pad_i2s_sdata0 ++ GPIO_TYPE_INOUT_ETH_MDIO = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_NORMAL |IOCTRL_4MA ) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 69) | GPIO_SET_IN_SEL( 87) | GPIO_SET_OUT_SEL( 93), //!< 93.Output type: enet_gmii_mdo_o ++ ++ GPIO_TYPE_UNDEFINED = 0, ++} GPIO_TYPE_E; ++/* ++GPIO_TYPE_OUTPUT_SPI1_SO = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 2) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 2), //!< Output type: tssi_txd ++GPIO_TYPE_OUTPUT_SPI1_CS0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 3), //!< Output type: tssi_cs0_n ++GPIO_TYPE_OUTPUT_SPI1_SCLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 4), //!< Output type: tssi_sclk_out ++GPIO_TYPE_OUTPUT_UART2_RTS_N = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 5), //!< Output type: uart2_rts_n ++GPIO_TYPE_OUTPUT_UART2_DTR_N = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 6), //!< Output type: uart2_dtr_n ++GPIO_TYPE_OUTPUT_PWM3_OUT = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(10), //!< Output type: pwm3_out ++GPIO_TYPE_OUTPUT_PWM2_OUT = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(11), //!< Output type: pwm2_out ++GPIO_TYPE_OUTPUT_PWM1_OUT = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(12), //!< Output type: pwm1_out ++GPIO_TYPE_OUTPUT_PWM0_OUT = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(13), //!< Output type: pwm0_out ++GPIO_TYPE_OUTPUT_AOMCLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(32), //!< Output type: i2s_au_clk ++GPIO_TYPE_OUTPUT_AOBCLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(17) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(33), //!< Output type: i2s_clk_o ++GPIO_TYPE_OUTPUT_AOLRCLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(18) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(34), //!< Output type: i2s_ws_o ++GPIO_TYPE_OUTPUT_AO_DATA0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(35), //!< Output type: i2s_so ++GPIO_TYPE_OUTPUT_SF_CS1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(37), //!< Output type: sf_cs1_n ++GPIO_TYPE_INPUT_SPI1_SI = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+ 0) | GPIO_SET_OUT_SEL( 0), //!< Input type: tssi_rxd ++GPIO_TYPE_INPUT_I2S_CLK = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+23) | GPIO_SET_OUT_SEL( 0), //!< Input type: i2s_clk ++GPIO_TYPE_INPUT_I2S_WS = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+24) | GPIO_SET_OUT_SEL( 0), //!< Input type: i2s_ws ++GPIO_TYPE_INPUT_I2S_SI = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+25) | GPIO_SET_OUT_SEL( 0), //!< Input type: i2s_si ++GPIO_TYPE_INPUT_CLK_AU = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+26) | GPIO_SET_OUT_SEL( 0), //!< Input type: clk_au ++GPIO_TYPE_INOUT_SD_DATA_4 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(12) | GPIO_SET_IN_SEL(2+18) | GPIO_SET_OUT_SEL(26), //!< Input/Output type: sd_data_out[4] ++GPIO_TYPE_INOUT_SD_DATA_5 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(13) | GPIO_SET_IN_SEL(2+19) | GPIO_SET_OUT_SEL(27), //!< Input/Output type: sd_data_out[5] ++GPIO_TYPE_INOUT_SD_DATA_6 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(14) | GPIO_SET_IN_SEL(2+20) | GPIO_SET_OUT_SEL(28), //!< Input/Output type: sd_data_out[6] ++GPIO_TYPE_INOUT_SD_DATA_7 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(15) | GPIO_SET_IN_SEL(2+21) | GPIO_SET_OUT_SEL(29), //!< Input/Output type: sd_data_out[7] ++*/ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Data Structures ++//***************************************************************************** ++//***************************************************************************** ++typedef union { /* PLL_IOCTRL_GPIO */ ++ u32 all; ++ struct { ++ u32 io1 : 6; ++ u32 : 2; ++ u32 io2 : 6; ++ u32 : 2; ++ u32 io0 : 6; ++ u32 : 2; ++ u32 io3 : 6; ++ u32 : 2; ++ } bitc; ++} GH_PLL_IOCTRL_GPIO_S; ++ ++typedef union { /* GPIO_OUTPUT_CFG */ ++ u32 all; ++ struct { ++ u32 out_sel : 7; ++ u32 oen_sel : 7; ++ u32 out_invert : 1; ++ u32 oen_invert : 1; ++ u32 : 16; ++ } bitc; ++} GH_GPIO_OUTPUT_CFG_S; ++ ++typedef union { /* GPIO_INPUT_CFG */ ++ u32 all; ++ struct { ++ u32 in_sel : 7; ++ u32 : 25; ++ } bitc; ++} GH_GPIO_INPUT_CFG_S; ++ ++typedef union { /* GPIO_INT_EN */ ++ u32 all; ++ struct { ++ u32 int_en : 1; ++ u32 : 31; ++ } bitc; ++} GH_GPIO_INT_EN_S; ++ ++typedef struct gpio_cfg ++{ ++ u32 gpio_count; ++ GPIO_XREF_S gpio_chip[128]; ++ u32 extphy_gpio_count; ++ GPIO_XREF_S ext_phy_gpio[16]; ++ u32 intphy_gpio_count; ++ GPIO_XREF_S int_phy_gpio[16]; ++ ++ u32 ir_led_ctl; ++ u32 ir_cut1; ++ u32 ir_cut2; ++ ++ u32 sensor_reset; ++ ++ u32 phy_reset; ++ u32 phy_speed_led; ++ ++ u32 spi0_en0; ++ u32 spi1_en0; ++ ++ u32 pwm0; ++ u32 pwm1; ++ u32 pwm2; ++ u32 pwm3; ++ ++ u32 usb_host; ++ ++ u32 sd_detect; ++ u32 sd_power; ++ ++ //board info ++ u32 soc_type; ++ s8 board_type[32]; ++ u32 board_version; ++ u32 reserve1; ++ ++ //extra device info ++ u32 ext_phy_clk; ++ u32 reserve2; ++ ++ // Add by Steven Yu:for pmu ++ u32 pmu_ctl; ++ ++}gpio_cfg_t; ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Global Data ++//***************************************************************************** ++//***************************************************************************** ++extern gpio_cfg_t gk_all_gpio_cfg; ++extern u8 cmdline_phytype; ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** API Functions ++//***************************************************************************** ++//***************************************************************************** ++ ++ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++ ++ ++#endif /* _GK_GPIO_V1_10_H_ */ ++ +diff --git a/arch/arm/plat-goke/include/plat/gk_gpio_v1_20.h b/arch/arm/plat-goke/include/plat/gk_gpio_v1_20.h +new file mode 100644 +index 00000000..ed8ab340 +--- /dev/null ++++ b/arch/arm/plat-goke/include/plat/gk_gpio_v1_20.h +@@ -0,0 +1,404 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/plat-goke/include/plat/gk_gpio_v1_00.h ++** ++** \version $Id: gk_gpio_v1_00.h 9208 2016-07-21 12:51:42Z yulindeng $ ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2016 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++#ifndef _GK_GPIO_V1_20_H_ ++#define _GK_GPIO_V1_20_H_ ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Defines and Macros ++//***************************************************************************** ++//***************************************************************************** ++/************************/ ++/* GPIO pins definition */ ++/************************/ ++#define GPIO_SET_OUT_SEL(n) ((n)&0x7F) ++#define GPIO_SET_IN_SEL(n) (((n)&0x3F)<<8) ++#define GPIO_SET_OEN_SEL(n) (((n)&0x3F)<<16) ++#define GPIO_SET_OUT_INVERT(n) (((n)&0x1)<<22) ++#define GPIO_SET_OEN_INVERT(n) (((n)&0x1)<<23) ++#define GPIO_SET_IOCTRL(n) (((n)&0x3F)<<24) ++#define GPIO_SET_FUNC(n) (((n)&0x3)<<30) ++ ++#define GPIO_GET_OUT_SEL(n) (((n)&0x0000007F)) ++#define GPIO_GET_IN_SEL(n) (((n)&0x00003F00)>>8) ++#define GPIO_GET_OEN_SEL(n) (((n)&0x003F0000)>>16) ++#define GPIO_GET_OUT_INVERT(n) (((n)&0x00400000)>>22) ++#define GPIO_GET_OEN_INVERT(n) (((n)&0x00800000)>>23) ++#define GPIO_GET_IOCTRL(n) (((n)&0x3F000000)>>24) ++#define GPIO_GET_FUNC(n) (((n)&0xC0000000)>>30) ++ ++#define IOCTRL_NORMAL 0x00 //!< Hi-z ++#define IOCTRL_PULL_UP 0x10 //!< PULL_UP ++#define IOCTRL_PULL_DOWN 0x20 //!< PULL_DOWN ++#define IOCTRL_REPEAT 0x30 //!< REPEAT ++ ++#define IOCTRL_2MA 0x00 //!< 2mA ++#define IOCTRL_4MA 0x01 //!< 4mA ++#define IOCTRL_8MA 0x02 //!< 8mA ++#define IOCTRL_12MA 0x03 //!< 12mA ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Enumerated types ++//***************************************************************************** ++//***************************************************************************** ++typedef enum ++{ ++ /* ----------------------------------- GPIO output function define ----------------------------------- */ ++ GPIO_TYPE_OUTPUT_0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 0), //!< Output type: value = 0 ++ GPIO_TYPE_OUTPUT_1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 1), //!< Output type: value = 1 ++ GPIO_TYPE_OUTPUT_SPI1_SO = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 2) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 2), //!< Output type: tssi_txd ++ GPIO_TYPE_OUTPUT_SPI1_CS0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 3), //!< Output type: tssi_cs0_n ++ GPIO_TYPE_OUTPUT_SPI1_SCLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 4), //!< Output type: tssi_sclk_out ++ GPIO_TYPE_OUTPUT_UART2_RTS_N = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 5), //!< Output type: uart2_rts_n ++ GPIO_TYPE_OUTPUT_UART2_DTR_N = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 6), //!< Output type: uart2_dtr_n ++ GPIO_TYPE_OUTPUT_UART2_TX = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 7), //!< Output type: uart2_tx ++ GPIO_TYPE_OUTPUT_UART1_TX = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 8), //!< Output type: uart1_tx ++ GPIO_TYPE_OUTPUT_UART0_TX = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 9), //!< Output type: uart0_tx ++ GPIO_TYPE_OUTPUT_PWM3_OUT = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(10), //!< Output type: pwm3_out ++ GPIO_TYPE_OUTPUT_PWM2_OUT = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(11), //!< Output type: pwm2_out ++ GPIO_TYPE_OUTPUT_PWM1_OUT = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(12), //!< Output type: pwm1_out ++ GPIO_TYPE_OUTPUT_PWM0_OUT = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(13), //!< Output type: pwm0_out ++ GPIO_TYPE_OUTPUT_SPI0_SO = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 7) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(14), //!< Output type: ssi_txd ++ GPIO_TYPE_OUTPUT_SPI0_CS7 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(15), //!< Output type: ssi_cs7_n ++ GPIO_TYPE_OUTPUT_SPI0_CS6 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(16), //!< Output type: ssi_cs6_n ++ GPIO_TYPE_OUTPUT_SPI0_CS5 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(17), //!< Output type: ssi_cs5_n ++ GPIO_TYPE_OUTPUT_SPI0_CS4 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(18), //!< Output type: ssi_cs4_n ++ GPIO_TYPE_OUTPUT_SPI0_CS1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(19), //!< Output type: ssi_cs1_n ++ GPIO_TYPE_OUTPUT_SPI0_CS0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(20), //!< Output type: ssi_cs0_n ++ GPIO_TYPE_OUTPUT_SPI0_SCLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(21), //!< Output type: ssi_sclk_out ++ //GPIO_TYPE_INOUT_SD_DATA_0 GPIO_SET_OEN_SEL( 8) GPIO_SET_OUT_SEL(22) ++ //GPIO_TYPE_INOUT_SD_DATA_0 GPIO_SET_OEN_SEL( 9) GPIO_SET_OUT_SEL(23) ++ //GPIO_TYPE_INOUT_SD_DATA_0 GPIO_SET_OEN_SEL(10) GPIO_SET_OUT_SEL(24) ++ //GPIO_TYPE_INOUT_SD_DATA_0 GPIO_SET_OEN_SEL(11) GPIO_SET_OUT_SEL(25) ++ //GPIO_TYPE_INOUT_SD_DATA_0 GPIO_SET_OEN_SEL(12) GPIO_SET_OUT_SEL(26) ++ //GPIO_TYPE_INOUT_SD_DATA_0 GPIO_SET_OEN_SEL(13) GPIO_SET_OUT_SEL(27) ++ //GPIO_TYPE_INOUT_SD_DATA_0 GPIO_SET_OEN_SEL(14) GPIO_SET_OUT_SEL(28) ++ //GPIO_TYPE_INOUT_SD_DATA_0 GPIO_SET_OEN_SEL(15) GPIO_SET_OUT_SEL(29) ++ //GPIO_TYPE_INOUT_SDIO_CMD GPIO_SET_OEN_SEL(16) GPIO_SET_OUT_SEL(30) ++ GPIO_TYPE_OUTPUT_SDIO_CLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(31), //!< Output type: sd_clk_sdcard ++ GPIO_TYPE_OUTPUT_AOMCLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(32), //!< Output type: i2s_au_clk ++ GPIO_TYPE_OUTPUT_AOBCLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(17) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(33), //!< Output type: i2s_clk_o ++ GPIO_TYPE_OUTPUT_AOLRCLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(18) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(34), //!< Output type: i2s_ws_o ++ GPIO_TYPE_OUTPUT_AO_DATA0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(35), //!< Output type: i2s_so ++ GPIO_TYPE_OUTPUT_SF_CS0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(36), //!< Output type: sf_cs0_n ++ GPIO_TYPE_OUTPUT_SF_CS1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(37), //!< Output type: sf_cs1_n ++ GPIO_TYPE_OUTPUT_EPHY_LED_0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(38), //!< Output type: ephy_led[0] hcd ok ++ GPIO_TYPE_OUTPUT_EPHY_LED_1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(39), //!< Output type: ephy_led[1] duplex ++ GPIO_TYPE_OUTPUT_EPHY_LED_2 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(40), //!< Output type: ephy_led[2] 10M CRS out ++ GPIO_TYPE_OUTPUT_EPHY_LED_3 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(41), //!< Output type: ephy_led[3] 100M CRS out ++ GPIO_TYPE_OUTPUT_EPHY_LED_4 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(42), //!< Output type: ephy_led[4] clo gs ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXD_0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(43), //!< Output type: enet_phy_txd[0] ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXD_1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(44), //!< Output type: enet_phy_txd[1] ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXD_2 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(45), //!< Output type: enet_phy_txd[2] ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXD_3 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(46), //!< Output type: enet_phy_txd[3] ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXER = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(47), //!< Output type: enet_phy_txer ++ GPIO_TYPE_OUTPUT_ENET_PHY_TXEN = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(48), //!< Output type: enet_phy_txen ++ // GPIO_TYPE_INOUT_ETH_MDIO GPIO_SET_OUT_SEL(49) ++ GPIO_TYPE_OUTPUT_ENET_GMII_MDC_O = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(50), //!< Output type: enet_gmii_mdc_o ++ //GPIO_TYPE_INOUT_SD2_DATA_0 GPIO_SET_OEN_SEL(20) GPIO_SET_OUT_SEL(51) ++ //GPIO_TYPE_INOUT_SD2_DATA_1 GPIO_SET_OEN_SEL(21) GPIO_SET_OUT_SEL(52) ++ //GPIO_TYPE_INOUT_SD2_DATA_2 GPIO_SET_OEN_SEL(22) GPIO_SET_OUT_SEL(53) ++ //GPIO_TYPE_INOUT_SD2_DATA_3 GPIO_SET_OEN_SEL(23) GPIO_SET_OUT_SEL(54) ++ //GPIO_TYPE_INOUT_SDIO_CMD GPIO_SET_OEN_SEL(24) GPIO_SET_OUT_SEL(55) ++ GPIO_TYPE_OUTPUT_SDIO2_CLK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(56), //!< Output type: sd2_clk_sdcard ++ GPIO_TYPE_OUTPUT_JTAGE_TDO = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(57), //!< Output type: jtag_tdout ++ GPIO_TYPE_OUTPUT_VD_VSYNC = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(58), //!< Output type: lcd_vsync ++ GPIO_TYPE_OUTPUT_VD_HSYNC = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(59), //!< Output type: lcd_hsync ++ GPIO_TYPE_OUTPUT_VD_CLOCK = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(60), //!< Output type: lcd_dclk ++ GPIO_TYPE_OUTPUT_VD_HVLD = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(61), //!< Output type: lcd_hvld ++ GPIO_TYPE_OUTPUT_VD_DATA0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(62), //!< Output type: lcd_data0 ++ GPIO_TYPE_OUTPUT_VD_DATA1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(63), //!< Output type: lcd_data1 ++ GPIO_TYPE_OUTPUT_VD_DATA2 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(64), //!< Output type: lcd_data2 ++ GPIO_TYPE_OUTPUT_VD_DATA3 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(65), //!< Output type: lcd_data3 ++ GPIO_TYPE_OUTPUT_VD_DATA4 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(66), //!< Output type: lcd_data4 ++ GPIO_TYPE_OUTPUT_VD_DATA5 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(67), //!< Output type: lcd_data5 ++ GPIO_TYPE_OUTPUT_VD_DATA6 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(68), //!< Output type: lcd_data6 ++ GPIO_TYPE_OUTPUT_VD_DATA7 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(69), //!< Output type: lcd_data7 ++ GPIO_TYPE_OUTPUT_VD_DATA8 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(70), //!< Output type: lcd_data8 ++ GPIO_TYPE_OUTPUT_VD_DATA9 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(71), //!< Output type: lcd_data9 ++ GPIO_TYPE_OUTPUT_VD_DATA10 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(72), //!< Output type: lcd_data10 ++ GPIO_TYPE_OUTPUT_VD_DATA11 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(73), //!< Output type: lcd_data11 ++ GPIO_TYPE_OUTPUT_VD_DATA12 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(74), //!< Output type: lcd_data12 ++ GPIO_TYPE_OUTPUT_VD_DATA13 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(75), //!< Output type: lcd_data13 ++ GPIO_TYPE_OUTPUT_VD_DATA14 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(76), //!< Output type: lcd_data14 ++ GPIO_TYPE_OUTPUT_VD_DATA15 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(77), //!< Output type: lcd_data15 ++ GPIO_TYPE_OUTPUT_VD_DATA16 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(78), //!< Output type: lcd_data16 ++ GPIO_TYPE_OUTPUT_VD_DATA17 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(79), //!< Output type: lcd_data17 ++ GPIO_TYPE_OUTPUT_VD_DATA18 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(80), //!< Output type: lcd_data18 ++ GPIO_TYPE_OUTPUT_VD_DATA19 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(81), //!< Output type: lcd_data19 ++ GPIO_TYPE_OUTPUT_VD_DATA20 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(82), //!< Output type: lcd_data20 ++ GPIO_TYPE_OUTPUT_VD_DATA21 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(83), //!< Output type: lcd_data21 ++ GPIO_TYPE_OUTPUT_VD_DATA22 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(84), //!< Output type: lcd_data22 ++ GPIO_TYPE_OUTPUT_VD_DATA23 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(85), //!< Output type: lcd_data23 ++ GPIO_TYPE_OUTPUT_RCT_CLK_OUT2 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(86), //!< Output type: rct_clk_out2 ++ GPIO_TYPE_OUTPUT_RCT_CLK_OUT1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(87), //!< Output type: rct_clk_out1 ++ GPIO_TYPE_OUTPUT_I80_LCD_RST = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(88), //!< Output type: i80_lcd_rst ++ GPIO_TYPE_OUTPUT_I80_RDN = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(89), //!< Output type: i80_rdn ++ GPIO_TYPE_OUTPUT_I80_WRN = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(90), //!< Output type: i80_wrn ++ GPIO_TYPE_OUTPUT_I80_DCX = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(91), //!< Output type: i80_dcx ++ GPIO_TYPE_OUTPUT_I80_CSN = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(92), //!< Output type: i80_csn ++ GPIO_TYPE_OUTPUT_I80_DATA0 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(93), //!< Output type: i80_data_tx0 ++ GPIO_TYPE_OUTPUT_I80_DATA1 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(94), //!< Output type: i80_data_tx1 ++ GPIO_TYPE_OUTPUT_I80_DATA2 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(95), //!< Output type: i80_data_tx2 ++ GPIO_TYPE_OUTPUT_I80_DATA3 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(96), //!< Output type: i80_data_tx3 ++ GPIO_TYPE_OUTPUT_I80_DATA4 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(97), //!< Output type: i80_data_tx4 ++ GPIO_TYPE_OUTPUT_I80_DATA5 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(98), //!< Output type: i80_data_tx5 ++ GPIO_TYPE_OUTPUT_I80_DATA6 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(99), //!< Output type: i80_data_tx6 ++ GPIO_TYPE_OUTPUT_I80_DATA7 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(100), //!< Output type: i80_data_tx7 ++ GPIO_TYPE_OUTPUT_I80_DATA8 = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(101), //!< Output type: i80_data_tx8 ++ GPIO_TYPE_OUTPUT_PWM7_OUT = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(102), //!< Output type: pwm7_out ++ GPIO_TYPE_OUTPUT_PWM6_OUT = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(103), //!< Output type: pwm6_out ++ GPIO_TYPE_OUTPUT_PWM5_OUT = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(104), //!< Output type: pwm5_out ++ GPIO_TYPE_OUTPUT_PWM4_OUT = GPIO_SET_FUNC(GPIO_FUNC_OUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 0) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL(105), //!< Output type: pwm4_out ++ ++ /* ----------------------------------- GPIO input function define ----------------------------------- */ ++ ++ GPIO_TYPE_INPUT = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_NORMAL|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 0), //!< Input type: normal input ++ GPIO_TYPE_INPUT_0 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL( 0) | GPIO_SET_OUT_SEL( 0), //!< Input type: normal input ++ GPIO_TYPE_INPUT_1 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL( 1) | GPIO_SET_OUT_SEL( 0), //!< Input type: normal input ++ GPIO_TYPE_INPUT_SPI1_SI = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+ 0) | GPIO_SET_OUT_SEL( 0), //!< Input type: tssi_rxd ++ //GPIO_TYPE_INOUT_I2C_DATA GPIO_SET_IN_SEL(2+ 1) ++ //GPIO_TYPE_INOUT_I2C_CLK GPIO_SET_IN_SEL(2+ 2) ++ //GPIO_TYPE_INOUT_I2C_DATA2 GPIO_SET_IN_SEL(2+ 3) ++ //GPIO_TYPE_INOUT_I2C_CLK2 GPIO_SET_IN_SEL(2+ 4) ++ GPIO_TYPE_INPUT_UART2_RX = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+ 5) | GPIO_SET_OUT_SEL( 0), //!< Input type: uart2_rx ++ GPIO_TYPE_INPUT_UART1_RX = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+ 6) | GPIO_SET_OUT_SEL( 0), //!< Input type: uart1_rx ++ GPIO_TYPE_INPUT_UART0_RX = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+ 7) | GPIO_SET_OUT_SEL( 0), //!< Input type: uart0_rx ++ GPIO_TYPE_INPUT_TIMER1_CLK = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+ 8) | GPIO_SET_OUT_SEL( 0), //!< Input type: timer1_clk ++ GPIO_TYPE_INPUT_TIMER2_CLK = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+ 9) | GPIO_SET_OUT_SEL( 0), //!< Input type: timer2_clk ++ GPIO_TYPE_INPUT_TIMER3_CLK = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+10) | GPIO_SET_OUT_SEL( 0), //!< Input type: timer3_clk ++ GPIO_TYPE_INPUT_SPI0_SI = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+11) | GPIO_SET_OUT_SEL( 0), //!< Input type: ssi_rxd ++ GPIO_TYPE_INPUT_SD_WP_N = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+12) | GPIO_SET_OUT_SEL( 0), //!< Input type: sd_wp_n ++ GPIO_TYPE_INPUT_SD_CD_N = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+13) | GPIO_SET_OUT_SEL( 0), //!< Input type: sd_cd_n ++ //GPIO_TYPE_INOUT_SD_DATA_0 GPIO_SET_IN_SEL(2+14) ++ //GPIO_TYPE_INOUT_SD_DATA_1 GPIO_SET_IN_SEL(2+15) ++ //GPIO_TYPE_INOUT_SD_DATA_2 GPIO_SET_IN_SEL(2+16) ++ //GPIO_TYPE_INOUT_SD_DATA_3 GPIO_SET_IN_SEL(2+17) ++ //GPIO_TYPE_INOUT_SD_DATA_4 GPIO_SET_IN_SEL(2+18) ++ //GPIO_TYPE_INOUT_SD_DATA_5 GPIO_SET_IN_SEL(2+19) ++ //GPIO_TYPE_INOUT_SD_DATA_6 GPIO_SET_IN_SEL(2+20) ++ //GPIO_TYPE_INOUT_SD_DATA_7 GPIO_SET_IN_SEL(2+21) ++ //GPIO_TYPE_INOUT_SDIO_CMD GPIO_SET_IN_SEL(2+22) ++ GPIO_TYPE_INPUT_I2S_CLK = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+23) | GPIO_SET_OUT_SEL( 0), //!< Input type: i2s_clk ++ GPIO_TYPE_INPUT_I2S_WS = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+24) | GPIO_SET_OUT_SEL( 0), //!< Input type: i2s_ws ++ GPIO_TYPE_INPUT_I2S_SI = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+25) | GPIO_SET_OUT_SEL( 0), //!< Input type: i2s_si ++ GPIO_TYPE_INPUT_CLK_AU = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+26) | GPIO_SET_OUT_SEL( 0), //!< Input type: clk_au ++ GPIO_TYPE_INPUT_ENET_PHY_RXD_0 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+27) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_phy_rxd[0] ++ GPIO_TYPE_INPUT_ENET_PHY_RXD_1 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+28) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_phy_rxd[1] ++ GPIO_TYPE_INPUT_ENET_PHY_RXD_2 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+29) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_phy_rxd[2] ++ GPIO_TYPE_INPUT_ENET_PHY_RXD_3 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+30) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_phy_rxd[3] ++ GPIO_TYPE_INPUT_ENET_PHY_COL = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+31) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_phy_col ++ GPIO_TYPE_INPUT_ENET_PHY_CRS = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+32) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_phy_crs ++ GPIO_TYPE_INPUT_ENET_PHY_RXER = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+33) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_phy_rxer ++ GPIO_TYPE_INPUT_ENET_PHY_RXDV = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+34) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_phy_rxdv ++ // GPIO_TYPE_INOUT_ETH_MDIO GPIO_SET_IN_SEL(2+35) ++ GPIO_TYPE_INPUT_ENET_CLK_RX = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+36) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_clk_rx ++ GPIO_TYPE_INPUT_ENET_CLK_TX = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+37) | GPIO_SET_OUT_SEL( 0), //!< Input type: enet_clk_tx ++ GPIO_TYPE_INPUT_SD2_WP_N = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+38) | GPIO_SET_OUT_SEL( 0), //!< Input type: sd2_wp_n ++ GPIO_TYPE_INPUT_SD2_CD_N = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+39) | GPIO_SET_OUT_SEL( 0), //!< Input type: sd2_cd_n ++ //GPIO_TYPE_INOUT_SD_DATA_0 GPIO_SET_IN_SEL(2+40) ++ //GPIO_TYPE_INOUT_SD_DATA_1 GPIO_SET_IN_SEL(2+41) ++ //GPIO_TYPE_INOUT_SD_DATA_2 GPIO_SET_IN_SEL(2+42) ++ //GPIO_TYPE_INOUT_SD_DATA_3 GPIO_SET_IN_SEL(2+43) ++ //GPIO_TYPE_INOUT_SDIO_CMD GPIO_SET_IN_SEL(2+44) ++ GPIO_TYPE_INPUT_I80_DATA0 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+45) | GPIO_SET_OUT_SEL( 0), //!< Input type: i80_data_rx0 ++ GPIO_TYPE_INPUT_I80_DATA1 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+46) | GPIO_SET_OUT_SEL( 0), //!< Input type: i80_data_rx1 ++ GPIO_TYPE_INPUT_I80_DATA2 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+47) | GPIO_SET_OUT_SEL( 0), //!< Input type: i80_data_rx2 ++ GPIO_TYPE_INPUT_I80_DATA3 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+48) | GPIO_SET_OUT_SEL( 0), //!< Input type: i80_data_rx3 ++ GPIO_TYPE_INPUT_I80_DATA4 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+49) | GPIO_SET_OUT_SEL( 0), //!< Input type: i80_data_rx4 ++ GPIO_TYPE_INPUT_I80_DATA5 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+50) | GPIO_SET_OUT_SEL( 0), //!< Input type: i80_data_rx5 ++ GPIO_TYPE_INPUT_I80_DATA6 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+51) | GPIO_SET_OUT_SEL( 0), //!< Input type: i80_data_rx6 ++ GPIO_TYPE_INPUT_I80_DATA7 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+52) | GPIO_SET_OUT_SEL( 0), //!< Input type: i80_data_rx7 ++ GPIO_TYPE_INPUT_I80_DATA8 = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+53) | GPIO_SET_OUT_SEL( 0), //!< Input type: i80_data_rx8 ++ GPIO_TYPE_INPUT_JTAG_TRSTN = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+56) | GPIO_SET_OUT_SEL( 0), //!< Input type: jtag_trstn ++ GPIO_TYPE_INPUT_JTAG_TCK = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+57) | GPIO_SET_OUT_SEL( 0), //!< Input type: jtag_tck ++ GPIO_TYPE_INPUT_JTAG_TMS = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+58) | GPIO_SET_OUT_SEL( 0), //!< Input type: jtag_tms ++ GPIO_TYPE_INPUT_JTAG_TDI = GPIO_SET_FUNC(GPIO_FUNC_IN) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 1) | GPIO_SET_IN_SEL(2+59) | GPIO_SET_OUT_SEL( 0), //!< Input type: jtag_tdi ++ ++ /* ----------------------------------- GPIO input&&output function define ----------------------------------- */ ++ GPIO_TYPE_INOUT_I2C_DATA = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 3) | GPIO_SET_IN_SEL(2+ 1) | GPIO_SET_OUT_SEL( 0), //!< Input/Output type: i2c_sda ++ GPIO_TYPE_INOUT_I2C_CLK = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 4) | GPIO_SET_IN_SEL(2+ 2) | GPIO_SET_OUT_SEL( 0), //!< Input/Output type: i2c_scl ++ GPIO_TYPE_INOUT_I2C_DATA2 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 5) | GPIO_SET_IN_SEL(2+ 3) | GPIO_SET_OUT_SEL( 0), //!< Input/Output type: i2c_sda2 ++ GPIO_TYPE_INOUT_I2C_CLK2 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(0) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 6) | GPIO_SET_IN_SEL(2+ 4) | GPIO_SET_OUT_SEL( 0), //!< Input/Output type: i2c_scl2 ++ ++ GPIO_TYPE_INOUT_ETH_MDIO = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(19) | GPIO_SET_IN_SEL(2+35) | GPIO_SET_OUT_SEL(49), //!< Input/Output type: enet_gmii_mdi/enet_gmii_mod_o ++ ++ GPIO_TYPE_INOUT_SD_DATA_0 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 8) | GPIO_SET_IN_SEL(2+14) | GPIO_SET_OUT_SEL(22), //!< Input/Output type: sd_data_out[0] ++ GPIO_TYPE_INOUT_SD_DATA_1 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL( 9) | GPIO_SET_IN_SEL(2+15) | GPIO_SET_OUT_SEL(23), //!< Input/Output type: sd_data_out[1] ++ GPIO_TYPE_INOUT_SD_DATA_2 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(10) | GPIO_SET_IN_SEL(2+16) | GPIO_SET_OUT_SEL(24), //!< Input/Output type: sd_data_out[2] ++ GPIO_TYPE_INOUT_SD_DATA_3 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(11) | GPIO_SET_IN_SEL(2+17) | GPIO_SET_OUT_SEL(25), //!< Input/Output type: sd_data_out[3] ++ GPIO_TYPE_INOUT_SD_DATA_4 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(12) | GPIO_SET_IN_SEL(2+18) | GPIO_SET_OUT_SEL(26), //!< Input/Output type: sd_data_out[4] ++ GPIO_TYPE_INOUT_SD_DATA_5 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(13) | GPIO_SET_IN_SEL(2+19) | GPIO_SET_OUT_SEL(27), //!< Input/Output type: sd_data_out[5] ++ GPIO_TYPE_INOUT_SD_DATA_6 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(14) | GPIO_SET_IN_SEL(2+20) | GPIO_SET_OUT_SEL(28), //!< Input/Output type: sd_data_out[6] ++ GPIO_TYPE_INOUT_SD_DATA_7 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(15) | GPIO_SET_IN_SEL(2+21) | GPIO_SET_OUT_SEL(29), //!< Input/Output type: sd_data_out[7] ++ GPIO_TYPE_INOUT_SD_CMD = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(16) | GPIO_SET_IN_SEL(2+22) | GPIO_SET_OUT_SEL(30), //!< Input/Output : sd_cmd ++ ++ GPIO_TYPE_INOUT_SD2_DATA_0 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(20) | GPIO_SET_IN_SEL(2+40) | GPIO_SET_OUT_SEL(51), //!< Input/Output type: sd2_data_out[0] ++ GPIO_TYPE_INOUT_SD2_DATA_1 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(21) | GPIO_SET_IN_SEL(2+41) | GPIO_SET_OUT_SEL(52), //!< Input/Output type: sd2_data_out[1] ++ GPIO_TYPE_INOUT_SD2_DATA_2 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(22) | GPIO_SET_IN_SEL(2+42) | GPIO_SET_OUT_SEL(53), //!< Input/Output type: sd2_data_out[2] ++ GPIO_TYPE_INOUT_SD2_DATA_3 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(23) | GPIO_SET_IN_SEL(2+43) | GPIO_SET_OUT_SEL(54), //!< Input/Output type: sd2_data_out[3] ++ GPIO_TYPE_INOUT_SD2_CMD = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_UP|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(24) | GPIO_SET_IN_SEL(2+44) | GPIO_SET_OUT_SEL(55), //!< Input/Output : sd2_cmd ++ ++ GPIO_TYPE_INOUT_I80_DATA0 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(25) | GPIO_SET_IN_SEL(2+45) | GPIO_SET_OUT_SEL(93), //!< Input/Output type: i80_data_rx0 ++ GPIO_TYPE_INOUT_I80_DATA1 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(25) | GPIO_SET_IN_SEL(2+46) | GPIO_SET_OUT_SEL(94), //!< Input/Output type: i80_data_rx1 ++ GPIO_TYPE_INOUT_I80_DATA2 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(25) | GPIO_SET_IN_SEL(2+47) | GPIO_SET_OUT_SEL(95), //!< Input/Output type: i80_data_rx2 ++ GPIO_TYPE_INOUT_I80_DATA3 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(25) | GPIO_SET_IN_SEL(2+48) | GPIO_SET_OUT_SEL(96), //!< Input/Output type: i80_data_rx3 ++ GPIO_TYPE_INOUT_I80_DATA4 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(25) | GPIO_SET_IN_SEL(2+49) | GPIO_SET_OUT_SEL(97), //!< Input/Output type: i80_data_rx4 ++ GPIO_TYPE_INOUT_I80_DATA5 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(25) | GPIO_SET_IN_SEL(2+50) | GPIO_SET_OUT_SEL(98), //!< Input/Output type: i80_data_rx5 ++ GPIO_TYPE_INOUT_I80_DATA6 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(25) | GPIO_SET_IN_SEL(2+51) | GPIO_SET_OUT_SEL(99), //!< Input/Output type: i80_data_rx6 ++ GPIO_TYPE_INOUT_I80_DATA7 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(25) | GPIO_SET_IN_SEL(2+52) | GPIO_SET_OUT_SEL(100), //!< Input/Output type: i80_data_rx7 ++ GPIO_TYPE_INOUT_I80_DATA8 = GPIO_SET_FUNC(GPIO_FUNC_INOUT) | GPIO_SET_IOCTRL(IOCTRL_PULL_DOWN|IOCTRL_2MA) | GPIO_SET_OEN_INVERT(1) | GPIO_SET_OUT_INVERT(0) | GPIO_SET_OEN_SEL(25) | GPIO_SET_IN_SEL(2+53) | GPIO_SET_OUT_SEL(101), //!< Input/Output type: i80_data_rx8 ++ ++ GPIO_TYPE_UNDEFINED = 0, ++} GPIO_TYPE_E; ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Data Structures ++//***************************************************************************** ++//***************************************************************************** ++typedef union { /* PLL_IOCTRL_GPIO */ ++ u32 all; ++ struct { ++ u32 io0 : 6; ++ u32 : 2; ++ u32 io1 : 6; ++ u32 : 2; ++ u32 io2 : 6; ++ u32 : 2; ++ u32 io3 : 6; ++ u32 : 2; ++ } bitc; ++} GH_PLL_IOCTRL_GPIO_S; ++ ++typedef union { /* GPIO_OUTPUT_CFG */ ++ u32 all; ++ struct { ++ u32 out_sel : 7; ++ u32 : 1; ++ u32 oen_sel : 6; ++ u32 out_invert : 1; ++ u32 oen_invert : 1; ++ u32 : 16; ++ } bitc; ++} GH_GPIO_OUTPUT_CFG_S; ++ ++typedef union { /* GPIO_INPUT_CFG */ ++ u32 all; ++ struct { ++ u32 in_sel : 6; ++ u32 : 26; ++ } bitc; ++} GH_GPIO_INPUT_CFG_S; ++ ++typedef union { /* GPIO_INT_EN */ ++ u32 all; ++ struct { ++ u32 int_en : 1; ++ u32 : 31; ++ } bitc; ++} GH_GPIO_INT_EN_S; ++ ++typedef struct gpio_cfg ++{ ++ u32 gpio_count; ++ GPIO_XREF_S gpio_chip[64]; ++ u32 extphy_gpio_count; ++ GPIO_XREF_S ext_phy_gpio[16]; ++ u32 intphy_gpio_count; ++ GPIO_XREF_S int_phy_gpio[16]; ++ ++ u32 ir_led_ctl; ++ u32 ir_cut1; ++ u32 ir_cut2; ++ ++ u32 sensor_reset; ++ ++ u32 phy_reset; ++ u32 phy_speed_led; ++ ++ u32 spi0_en0; ++ u32 spi1_en0; ++ ++ u32 pwm0; ++ u32 pwm1; ++ u32 pwm2; ++ u32 pwm3; ++ ++ u32 usb_host; ++ ++ u32 sd_detect; ++ u32 sd_power; ++ u32 sd1_detect; ++ u32 sd1_power; ++ ++ //board info ++ u32 soc_type; ++ s8 board_type[32]; ++ u32 board_version; ++ u32 reserve1; ++ ++ //extra device info ++ u32 ext_phy_clk; ++ u32 reserve2; ++ ++ // Add by Steven Yu:for pmu ++ u32 pmu_ctl; ++ ++}gpio_cfg_t; ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** Global Data ++//***************************************************************************** ++//***************************************************************************** ++extern gpio_cfg_t gk_all_gpio_cfg; ++extern u8 cmdline_phytype; ++ ++ ++ ++//***************************************************************************** ++//***************************************************************************** ++//** API Functions ++//***************************************************************************** ++//***************************************************************************** ++ ++ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++ ++ ++#endif /* _GK_GPIO_V1_20_H_ */ ++ +diff --git a/arch/arm/plat-goke/include/plat/highres_timer.h b/arch/arm/plat-goke/include/plat/highres_timer.h +new file mode 100644 +index 00000000..aecf5e7d +--- /dev/null ++++ b/arch/arm/plat-goke/include/plat/highres_timer.h +@@ -0,0 +1,25 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/plat/highres_timer.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++#ifndef __PLAT_HIGHRES_TIMER_H ++#define __PLAT_HIGHRES_TIMER_H ++ ++extern void highres_timer_init(struct hrtimer *timer, clockid_t clock_id, enum hrtimer_mode mode); ++extern int highres_timer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode); ++extern int highres_timer_cancel(struct hrtimer *timer); ++ ++#endif ++ +diff --git a/arch/arm/plat-goke/include/plat/input.h b/arch/arm/plat-goke/include/plat/input.h +new file mode 100644 +index 00000000..02b8be2e +--- /dev/null ++++ b/arch/arm/plat-goke/include/plat/input.h +@@ -0,0 +1,265 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk/include/plat/input.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __PLAT_INPUT_H__ ++#define __PLAT_INPUT_H__ ++ ++#define MCU_RTC_BASE (GK_VA_PMU_RTC + 0x0000) //0xf2080000 ++#define MCU_IRR_BASE (GK_VA_PMU_RTC + 0x2000) ++#define MCU_FPC_BASE (GK_VA_PMU_RTC + 0x4000) ++#define MCU_GPIO_BASE (GK_VA_PMU_RTC + 0x6000) ++#define MCU_SYS_BASE (GK_VA_PMU_RTC + 0xA000) ++#define MCU_IRQ_BASE (GK_VA_PMU_RTC + 0xDC00) ++ ++/********************************/ ++/* PGPIO Register List */ ++/********************************/ ++#define PMU_GPIO_0_PWRUP 5 ++#define PMU_GPIO_1_IR 7 ++#define PMU_GPIO_2 2 ++#define PMU_GPIO_3 3 ++#define PMU_GPIO_4 4 ++ ++#define PMU_GPIO_0_DATA (MCU_GPIO_BASE + (0x0004 << PMU_GPIO_0_PWRUP)) ++#define PMU_GPIO_1_DATA (MCU_GPIO_BASE + (0x0004 << PMU_GPIO_1_IR)) ++#define PMU_GPIO_2_DATA (MCU_GPIO_BASE + (0x0004 << PMU_GPIO_2)) ++#define PMU_GPIO_3_DATA (MCU_GPIO_BASE + (0x0004 << PMU_GPIO_3)) ++#define PMU_GPIO_4_DATA (MCU_GPIO_BASE + (0x0004 << PMU_GPIO_4)) ++#define PMU_GPIO_DIR (MCU_GPIO_BASE + 0x0400) ++#define PMU_GPIO_IS (MCU_GPIO_BASE + 0x0404) ++#define PMU_GPIO_IBE (MCU_GPIO_BASE + 0x0408) ++#define PMU_GPIO_IEV (MCU_GPIO_BASE + 0x040C) ++#define PMU_GPIO_IE (MCU_GPIO_BASE + 0x0410) ++#define PMU_GPIO_RIS (MCU_GPIO_BASE + 0x0414) ++#define PMU_GPIO_MIS (MCU_GPIO_BASE + 0x0418) ++#define PMU_GPIO_IC (MCU_GPIO_BASE + 0x041C) ++#define PMU_GPIO_AFSEL (MCU_GPIO_BASE + 0x0420) ++ ++#define PMU_AUTOMOTIVE_KEY 0x10 // power on/off by key ++#define PMU_AUTOMOTIVE_ACC 0x11 // power on/off by acc ++#define PMU_AUTOMOTIVE_KEY_ACC 0x12 // power on/off by key & check the acc status ++#define PMU_POWER_OFF_CPU 0x20 // load 51 code then power off, power on by IR ++#define PMU_ALWAYS_RUNNING_POWEROFF 0x30 // load 51 code then power off, power on by IR ++#define PMU_ALWAYS_RUNNING 0x31 // load 51 code but do not power off, rtc always work ++typedef enum ++{ ++ NEG_EDGE = 0, ++ POS_EDGE, ++ ALL_EDGE, ++}GPIO_INT_EDGE_MODE_E; ++ ++typedef enum ++{ ++ EDGE_TRIGGER = 0, ++ LEVEL_TRIGGER, ++}GPIO_INT_TRIGGER_MODE_E; ++ ++typedef enum ++{ ++ LOW_LEVEL = 0, ++ HIGH_LEVEL, ++}GPIO_INT_LEVEL_MODE_E; ++ ++/********************************/ ++/* IR Register List */ ++/********************************/ ++#define REG_IRR_PROG (MCU_IRR_BASE + 0x00) /* write */ //0xf0082000 ++#define IRR_RESTART_IRR (1<<3) ++#define IRR_FALLING_DETECT (1<<2) ++#define IRR_RISING_DETECT (1<<1) ++#define IRR_TRANS_0XFF (1<<0) ++#define REG_IRR_PRESCALER_L (MCU_IRR_BASE + 0x04) /* write */ ++#define REG_IRR_PRESCALER_H (MCU_IRR_BASE + 0x08) /* write */ ++#define REG_IRR_IRR_READ (MCU_IRR_BASE + 0x0C) /* read/clear */ ++#define IRR_READ_VALID (1<<7) ++#define REG_IRR_IRT_READ (MCU_IRR_BASE + 0x10) /* read/clear */ ++#define REG_IRR_IRQMASK_L (MCU_IRR_BASE + 0x14) /* write */ ++#define IRR_RX_DATA_L_MSK (0x3<<0) ++#define REG_IRR_IRQMASK_H (MCU_IRR_BASE + 0x18) /* write */ ++#define IRR_RX_DATA_H_MSK (0x3f<<0) ++#define IRR_RX_DATA_H_SHIFT (2) ++ ++/********************************/ ++/* SYS/IRQ Register List */ ++/********************************/ ++#define REG_PMU_SYS_REG_CFG1 (MCU_SYS_BASE + 0x0004) /* read/write */ ++#define REG_PMU_IRQ_EN (MCU_IRQ_BASE + 0x0000) ++#define IRQ_EN_RTC (1<<0) ++#define IRQ_EN_IRR (1<<1) ++#define IRQ_EN_FPC (1<<2) ++#define IRQ_EN_GPIO (1<<3) ++#define IRQ_EN_CEC (1<<4) ++#define IRQ_EN_ADC (1<<5) ++#define IRQ_EN_IRT (1<<6) ++#define REG_PMU_IRQ_CLR_RTC (MCU_IRQ_BASE + 0x0020) /* read/write */ ++#define REG_PMU_IRQ_CLR_IRR (MCU_IRQ_BASE + 0x0024) /* read/write */ ++#define REG_PMU_IRQ_CLR_FPC (MCU_IRQ_BASE + 0x0028) /* read/write */ ++#define REG_PMU_IRQ_CLR_GPIO (MCU_IRQ_BASE + 0x002C) /* read/write */ ++#define REG_PMU_IRQ_CLR_CEC (MCU_IRQ_BASE + 0x0030) /* read/write */ ++#define REG_PMU_IRQ_CLR_ADC (MCU_IRQ_BASE + 0x0034) /* read/write */ ++#define REG_PMU_IRQ_CLR_IRT (MCU_IRQ_BASE + 0x0038) /* read/write */ ++#define REG_PMU_IRQ_STATUS (MCU_IRQ_BASE + 0x0040) /* read/write */ ++ ++/* ==========================================================================*/ ++#define GKINPUT_TABLE_SIZE (256) ++ ++#define GKINPUT_SOURCE_MASK (0x0F) ++#define GKINPUT_SOURCE_IR (0x01) ++#define GKINPUT_SOURCE_ADC (0x02) ++#define GKINPUT_SOURCE_GPIO (0x04) ++#define GKINPUT_SOURCE_VI (0x08) ++ ++#define GKINPUT_TYPE_MASK (0xF0) ++#define GKINPUT_TYPE_KEY (0x10) ++#define GKINPUT_TYPE_REL (0x20) ++#define GKINPUT_TYPE_ABS (0x40) ++#define GKINPUT_TYPE_SW (0x80) ++ ++#define GKINPUT_IR_KEY (GKINPUT_SOURCE_IR | GKINPUT_TYPE_KEY) ++#define GKINPUT_IR_REL (GKINPUT_SOURCE_IR | GKINPUT_TYPE_REL) ++#define GKINPUT_IR_ABS (GKINPUT_SOURCE_IR | GKINPUT_TYPE_ABS) ++#define GKINPUT_IR_SW (GKINPUT_SOURCE_IR | GKINPUT_TYPE_SW) ++#define GKINPUT_ADC_KEY (GKINPUT_SOURCE_ADC | GKINPUT_TYPE_KEY) ++#define GKINPUT_ADC_REL (GKINPUT_SOURCE_ADC | GKINPUT_TYPE_REL) ++#define GKINPUT_ADC_ABS (GKINPUT_SOURCE_ADC | GKINPUT_TYPE_ABS) ++#define GKINPUT_GPIO_KEY (GKINPUT_SOURCE_GPIO | GKINPUT_TYPE_KEY) ++#define GKINPUT_GPIO_REL (GKINPUT_SOURCE_GPIO | GKINPUT_TYPE_REL) ++#define GKINPUT_GPIO_ABS (GKINPUT_SOURCE_GPIO | GKINPUT_TYPE_ABS) ++#define GKINPUT_GPIO_SW (GKINPUT_SOURCE_GPIO | GKINPUT_TYPE_SW) ++#define GKINPUT_VI_KEY (GKINPUT_SOURCE_VI | GKINPUT_TYPE_KEY) ++#define GKINPUT_VI_REL (GKINPUT_SOURCE_VI | GKINPUT_TYPE_REL) ++#define GKINPUT_VI_ABS (GKINPUT_SOURCE_VI | GKINPUT_TYPE_ABS) ++#define GKINPUT_VI_SW (GKINPUT_SOURCE_VI | GKINPUT_TYPE_SW) ++ ++#define GKINPUT_END (0xFFFFFFFF) ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++struct gk_key_table { ++ u32 type; ++ union { ++ struct { ++ u32 key_code; ++ u32 key_flag; ++ u32 raw_id; ++ } ir_key; ++ struct { ++ u32 key_code; ++ s32 rel_step; ++ u32 raw_id; ++ } ir_rel; ++ struct { ++ s32 abs_x; ++ s32 abs_y; ++ u32 raw_id; ++ } ir_abs; ++ struct { ++ u32 key_code; ++ u32 key_value; ++ u32 raw_id; ++ } ir_sw; ++ struct { ++ u32 key_code; ++ u16 irq_trig;// 0 low trigger, 1 high trigger ++ u16 chan; ++ u16 low_level; ++ u16 high_level; ++ } adc_key; ++ struct { ++ u16 key_code; ++ s16 rel_step; ++ u16 irq_trig;// 0 low trigger, 1 high trigger ++ u16 chan; ++ u16 low_level; ++ u16 high_level; ++ } adc_rel; ++ struct { ++ s16 abs_x; ++ s16 abs_y; ++ u16 irq_trig;// 0 low trigger, 1 high trigger ++ u16 chan; ++ u16 low_level; ++ u16 high_level; ++ } adc_abs; ++ struct { ++ u32 key_code; ++ u32 active_val; ++ u16 can_wakeup; ++ u8 id; ++ u8 irq_mode; ++ } gpio_key; ++ struct { ++ u32 key_code; ++ s32 rel_step; ++ u16 can_wakeup; ++ u8 id; ++ u8 irq_mode; ++ } gpio_rel; ++ struct { ++ s32 abs_x; ++ s32 abs_y; ++ u16 can_wakeup; ++ u8 id; ++ u8 irq_mode; ++ } gpio_abs; ++ struct { ++ u32 key_code; ++ u32 active_val; ++ u16 can_wakeup; ++ u8 id; ++ u8 irq_mode; ++ } gpio_sw; ++ struct { ++ u32 reserve; ++ u32 reserve0; ++ u32 reserve1; ++ } vi_key; ++ struct { ++ u32 reserve; ++ u32 reserve0; ++ u32 reserve1; ++ } vi_rel; ++ struct { ++ u32 reserve; ++ u32 reserve0; ++ u32 reserve1; ++ } vi_abs; ++ struct { ++ u32 reserve; ++ u32 reserve0; ++ u32 reserve1; ++ } vi_sw; ++ }; ++}; ++ ++/* ==========================================================================*/ ++struct gk_input_board_info { ++ struct gk_key_table *pkeymap; ++ struct input_dev *pinput_dev; ++ struct platform_device *pdev; ++ ++ int abx_max_x; ++ int abx_max_y; ++ int abx_max_pressure; ++ int abx_max_width; ++}; ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif ++ +diff --git a/arch/arm/plat-goke/include/plat/mdma.h b/arch/arm/plat-goke/include/plat/mdma.h +new file mode 100644 +index 00000000..62b720d1 +--- /dev/null ++++ b/arch/arm/plat-goke/include/plat/mdma.h +@@ -0,0 +1,82 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk7101/include/plat/mdma.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __PLAT_MDMA_H__ ++#define __PLAT_MDMA_H__ ++ ++ ++/****************************************************/ ++/* Capabilities based on chip revision */ ++/****************************************************/ ++ ++ ++#define NUMBERS_MDMA_INSTANCES 4 ++ ++ ++#define MDMA_ON_AHB 1 ++ ++ ++#define MDMA_SUPPORT_ALPHA_BLEND 0 ++ ++/****************************************************/ ++/* Controller registers definitions */ ++/****************************************************/ ++ ++#if (MDMA_ON_AHB == 1) ++#define MDMA_SRC_1_BASE_OFFSET 0x00 ++#define MDMA_SRC_1_PITCH_OFFSET 0x04 ++#define MDMA_SRC_2_BASE_OFFSET 0x08 ++#define MDMA_SRC_2_PITCH_OFFSET 0x0c ++#define MDMA_DST_BASE_OFFSET 0x10 ++#define MDMA_DST_PITCH_OFFSET 0x14 ++#define MDMA_WIDTH_OFFSET 0x18 ++#define MDMA_HIGHT_OFFSET 0x1c ++#define MDMA_TRANSPARENT_OFFSET 0x20 ++#define MDMA_OPCODE_OFFSET 0x24 ++#define MDMA_PENDING_OPS_OFFSET 0x28 ++ ++#if (MDMA_SUPPORT_ALPHA_BLEND == 1) ++#define MDMA_PIXELFORMAT_OFFSET 0x2c ++#define MDMA_ALPHA_OFFSET 0x30 ++#define MDMA_CLUT_BASE_OFFSET 0x400 ++#endif ++ ++#define MDMA_SRC_1_BASE_REG GRAPHICS_DMA_REG(MDMA_SRC_1_BASE_OFFSET) ++#define MDMA_SRC_1_PITCH_REG GRAPHICS_DMA_REG(MDMA_SRC_1_PITCH_OFFSET) ++#define MDMA_SRC_2_BASE_REG GRAPHICS_DMA_REG(MDMA_SRC_2_BASE_OFFSET) ++#define MDMA_SRC_2_PITCH_REG GRAPHICS_DMA_REG(MDMA_SRC_2_PITCH_OFFSET) ++#define MDMA_DST_BASE_REG GRAPHICS_DMA_REG(MDMA_DST_BASE_OFFSET) ++#define MDMA_DST_PITCH_REG GRAPHICS_DMA_REG(MDMA_DST_PITCH_OFFSET) ++#define MDMA_WIDTH_REG GRAPHICS_DMA_REG(MDMA_WIDTH_OFFSET) ++#define MDMA_HEIGHT_REG GRAPHICS_DMA_REG(MDMA_HIGHT_OFFSET) ++#define MDMA_TRANSPARENT_REG GRAPHICS_DMA_REG(MDMA_TRANSPARENT_OFFSET) ++#define MDMA_OPCODE_REG GRAPHICS_DMA_REG(MDMA_OPCODE_OFFSET) ++#define MDMA_PENDING_OPS_REG GRAPHICS_DMA_REG(MDMA_PENDING_OPS_OFFSET) ++ ++#if (MDMA_SUPPORT_ALPHA_BLEND == 1) ++#define MDMA_PIXELFORMAT_REG GRAPHICS_DMA_REG(MDMA_PIXELFORMAT_OFFSET) ++#define MDMA_ALPHA_REG GRAPHICS_DMA_REG(MDMA_ALPHA_OFFSET) ++#define MDMA_CLUT_BASE_REG GRAPHICS_DMA_REG(MDMA_CLUT_BASE_OFFSET) ++ ++/* MDMA_PIXELFORMAT_REG */ ++#define MDMA_PIXELFORMAT_THROTTLE_DRAM (1L << 11) ++ ++#endif /* (MDMA_SUPPORT_ALPHA_BLEND == 1)*/ ++#endif /* MDMA_ON_AHB == 1 */ ++ ++#endif ++ +diff --git a/arch/arm/plat-goke/include/plat/reglock.h b/arch/arm/plat-goke/include/plat/reglock.h +new file mode 100644 +index 00000000..7b657ab8 +--- /dev/null ++++ b/arch/arm/plat-goke/include/plat/reglock.h +@@ -0,0 +1,44 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk/include/plat/reglock.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __PLAT_REGISTER_LOCK_H ++#define __PLAT_REGISTER_LOCK_H ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++ ++#ifdef CONFIG_GK_ADD_REGISTER_LOCK ++#include ++extern spinlock_t gk_register_lock; ++extern unsigned long gk_register_flags; ++extern u32 gk_reglock_count; ++ ++#define GK_REG_LOCK() spin_lock_irqsave(&gk_register_lock, gk_register_flags) ++#define GK_REG_UNLOCK() spin_unlock_irqrestore(&gk_register_lock, gk_register_flags) ++#define GK_INC_REGLOCK_COUNT() gk_reglock_count++ ++#else ++#define GK_REG_LOCK() ++#define GK_REG_UNLOCK() ++#define GK_INC_REGLOCK_COUNT() ++ ++#endif /* CONFIG_GK_ADD_REGISTER_LOCK */ ++ ++#endif /* __ASSEMBLER__ */ ++/* ==========================================================================*/ ++ ++#endif ++ +diff --git a/arch/arm/plat-goke/include/plat/syncproc.h b/arch/arm/plat-goke/include/plat/syncproc.h +new file mode 100644 +index 00000000..c15eb2d8 +--- /dev/null ++++ b/arch/arm/plat-goke/include/plat/syncproc.h +@@ -0,0 +1,73 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk/include/plat/syncproc.h ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#ifndef __PLAT_SYNC_PROC_H ++#define __PLAT_SYNC_PROC_H ++ ++/* ==========================================================================*/ ++#define GK_SYNC_PROC_MAX_ID (31) ++#define GK_SYNC_PROC_PAGE_SIZE (PAGE_SIZE - 16) ++ ++/* ==========================================================================*/ ++#ifndef __ASSEMBLER__ ++#include ++#include ++#include ++typedef int(sync_read_proc_t)(char *start, void *data); ++ ++struct gk_sync_proc_pinfo { ++ u32 id; ++ u32 mask; ++ char *page; ++}; ++ ++struct gk_sync_proc_hinfo { ++ u32 maxid; ++ wait_queue_head_t sync_proc_head; ++ atomic_t sync_proc_flag; ++ struct idr sync_proc_idr; ++ struct mutex sync_proc_lock; ++ sync_read_proc_t *sync_read_proc; ++ void *sync_read_data; ++}; ++ ++/* ==========================================================================*/ ++ ++/* ==========================================================================*/ ++extern int gk_sync_proc_hinit(struct gk_sync_proc_hinfo *hinfo); ++extern int gk_sync_proc_open(struct inode *inode, struct file *file); ++extern int gk_sync_proc_release(struct inode *inode, struct file *file); ++extern ssize_t gk_sync_proc_read(struct file *file, char __user *buf, size_t size, loff_t *ppos); ++extern ssize_t gk_sync_proc_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos); ++ ++struct gk_async_proc_info { ++ char proc_name[256]; ++ struct file_operations fops; ++ void *private_data; ++ struct fasync_struct *fasync_queue; ++ struct mutex op_mutex; ++ int use_count; ++}; ++ ++extern int gk_async_proc_create(struct gk_async_proc_info *pinfo); ++extern int gk_async_proc_remove(struct gk_async_proc_info *pinfo); ++ ++ ++#endif /* __ASSEMBLER__ */ ++ ++#endif ++ +diff --git a/arch/arm/plat-goke/pmu.c b/arch/arm/plat-goke/pmu.c +new file mode 100644 +index 00000000..771737f9 +--- /dev/null ++++ b/arch/arm/plat-goke/pmu.c +@@ -0,0 +1,3869 @@ ++/* ++ * arch/arm/mach-gk7101/pmu.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++u8 BOOTRAM[SZ_4K] = {0}; // 4K MCU boot ram ++ ++u8* load_data_init(void) ++{ ++ BOOTRAM[0] = 0x02; ++ BOOTRAM[1] = 0x08; ++ BOOTRAM[2] = 0x40; ++ BOOTRAM[3] = 0x02; ++ BOOTRAM[4] = 0x09; ++ BOOTRAM[5] = 0xCE; ++ BOOTRAM[6] = 0x90; ++ BOOTRAM[7] = 0x81; ++ BOOTRAM[8] = 0x80; ++ BOOTRAM[9] = 0xEB; ++ BOOTRAM[10] = 0xF0; ++ BOOTRAM[11] = 0xA3; ++ BOOTRAM[12] = 0xEA; ++ BOOTRAM[13] = 0xF0; ++ BOOTRAM[14] = 0xA3; ++ BOOTRAM[15] = 0xE9; ++ BOOTRAM[16] = 0xF0; ++ BOOTRAM[17] = 0xE4; ++ BOOTRAM[18] = 0x90; ++ BOOTRAM[19] = 0x81; ++ BOOTRAM[20] = 0x89; ++ BOOTRAM[21] = 0xF0; ++ BOOTRAM[22] = 0xFD; ++ BOOTRAM[23] = 0xFC; ++ BOOTRAM[24] = 0xD3; ++ BOOTRAM[25] = 0x90; ++ BOOTRAM[26] = 0x81; ++ BOOTRAM[27] = 0x4F; ++ BOOTRAM[28] = 0xE0; ++ BOOTRAM[29] = 0x9D; ++ BOOTRAM[30] = 0x90; ++ BOOTRAM[31] = 0x81; ++ BOOTRAM[32] = 0x4E; ++ BOOTRAM[33] = 0xE0; ++ BOOTRAM[34] = 0x9C; ++ BOOTRAM[35] = 0x50; ++ BOOTRAM[36] = 0x03; ++ BOOTRAM[37] = 0x02; ++ BOOTRAM[38] = 0x03; ++ BOOTRAM[39] = 0x0E; ++ BOOTRAM[40] = 0xED; ++ BOOTRAM[41] = 0x25; ++ BOOTRAM[42] = 0xE0; ++ BOOTRAM[43] = 0xFF; ++ BOOTRAM[44] = 0xEC; ++ BOOTRAM[45] = 0x33; ++ BOOTRAM[46] = 0xFE; ++ BOOTRAM[47] = 0x74; ++ BOOTRAM[48] = 0x00; ++ BOOTRAM[49] = 0x2F; ++ BOOTRAM[50] = 0xF5; ++ BOOTRAM[51] = 0x82; ++ BOOTRAM[52] = 0x74; ++ BOOTRAM[53] = 0x81; ++ BOOTRAM[54] = 0x3E; ++ BOOTRAM[55] = 0xF5; ++ BOOTRAM[56] = 0x83; ++ BOOTRAM[57] = 0xE0; ++ BOOTRAM[58] = 0xFE; ++ BOOTRAM[59] = 0xA3; ++ BOOTRAM[60] = 0xE0; ++ BOOTRAM[61] = 0xFF; ++ BOOTRAM[62] = 0x90; ++ BOOTRAM[63] = 0x81; ++ BOOTRAM[64] = 0x89; ++ BOOTRAM[65] = 0xE0; ++ BOOTRAM[66] = 0xF9; ++ BOOTRAM[67] = 0x70; ++ BOOTRAM[68] = 0x3E; ++ BOOTRAM[69] = 0xC3; ++ BOOTRAM[70] = 0xEF; ++ BOOTRAM[71] = 0x94; ++ BOOTRAM[72] = 0x7C; ++ BOOTRAM[73] = 0xEE; ++ BOOTRAM[74] = 0x94; ++ BOOTRAM[75] = 0x15; ++ BOOTRAM[76] = 0x50; ++ BOOTRAM[77] = 0x0C; ++ BOOTRAM[78] = 0xEF; ++ BOOTRAM[79] = 0x94; ++ BOOTRAM[80] = 0x94; ++ BOOTRAM[81] = 0xEE; ++ BOOTRAM[82] = 0x94; ++ BOOTRAM[83] = 0x11; ++ BOOTRAM[84] = 0x40; ++ BOOTRAM[85] = 0x04; ++ BOOTRAM[86] = 0x74; ++ BOOTRAM[87] = 0x01; ++ BOOTRAM[88] = 0x80; ++ BOOTRAM[89] = 0x16; ++ BOOTRAM[90] = 0xC3; ++ BOOTRAM[91] = 0xEF; ++ BOOTRAM[92] = 0x94; ++ BOOTRAM[93] = 0xB8; ++ BOOTRAM[94] = 0xEE; ++ BOOTRAM[95] = 0x94; ++ BOOTRAM[96] = 0x0B; ++ BOOTRAM[97] = 0x50; ++ BOOTRAM[98] = 0x1D; ++ BOOTRAM[99] = 0xEF; ++ BOOTRAM[100] = 0x94; ++ BOOTRAM[101] = 0xC4; ++ BOOTRAM[102] = 0xEE; ++ BOOTRAM[103] = 0x94; ++ BOOTRAM[104] = 0x09; ++ BOOTRAM[105] = 0x40; ++ BOOTRAM[106] = 0x15; ++ BOOTRAM[107] = 0x90; ++ BOOTRAM[108] = 0x81; ++ BOOTRAM[109] = 0x89; ++ BOOTRAM[110] = 0x74; ++ BOOTRAM[111] = 0x14; ++ BOOTRAM[112] = 0xF0; ++ BOOTRAM[113] = 0xE4; ++ BOOTRAM[114] = 0x90; ++ BOOTRAM[115] = 0x81; ++ BOOTRAM[116] = 0x83; ++ BOOTRAM[117] = 0xF0; ++ BOOTRAM[118] = 0xA3; ++ BOOTRAM[119] = 0xF0; ++ BOOTRAM[120] = 0xA3; ++ BOOTRAM[121] = 0xF0; ++ BOOTRAM[122] = 0xA3; ++ BOOTRAM[123] = 0xF0; ++ BOOTRAM[124] = 0xA3; ++ BOOTRAM[125] = 0x02; ++ BOOTRAM[126] = 0x02; ++ BOOTRAM[127] = 0xF9; ++ BOOTRAM[128] = 0x02; ++ BOOTRAM[129] = 0x03; ++ BOOTRAM[130] = 0x00; ++ BOOTRAM[131] = 0xE9; ++ BOOTRAM[132] = 0x64; ++ BOOTRAM[133] = 0x01; ++ BOOTRAM[134] = 0x60; ++ BOOTRAM[135] = 0x03; ++ BOOTRAM[136] = 0x02; ++ BOOTRAM[137] = 0x01; ++ BOOTRAM[138] = 0x21; ++ BOOTRAM[139] = 0xC3; ++ BOOTRAM[140] = 0xEF; ++ BOOTRAM[141] = 0x94; ++ BOOTRAM[142] = 0xB0; ++ BOOTRAM[143] = 0xEE; ++ BOOTRAM[144] = 0x94; ++ BOOTRAM[145] = 0x04; ++ BOOTRAM[146] = 0x50; ++ BOOTRAM[147] = 0x37; ++ BOOTRAM[148] = 0xEF; ++ BOOTRAM[149] = 0x94; ++ BOOTRAM[150] = 0xE8; ++ BOOTRAM[151] = 0xEE; ++ BOOTRAM[152] = 0x94; ++ BOOTRAM[153] = 0x03; ++ BOOTRAM[154] = 0x40; ++ BOOTRAM[155] = 0x2F; ++ BOOTRAM[156] = 0x90; ++ BOOTRAM[157] = 0x81; ++ BOOTRAM[158] = 0x83; ++ BOOTRAM[159] = 0xE0; ++ BOOTRAM[160] = 0xF0; ++ BOOTRAM[161] = 0x90; ++ BOOTRAM[162] = 0x81; ++ BOOTRAM[163] = 0x88; ++ BOOTRAM[164] = 0xE0; ++ BOOTRAM[165] = 0x04; ++ BOOTRAM[166] = 0xF0; ++ BOOTRAM[167] = 0x70; ++ BOOTRAM[168] = 0x06; ++ BOOTRAM[169] = 0x90; ++ BOOTRAM[170] = 0x81; ++ BOOTRAM[171] = 0x87; ++ BOOTRAM[172] = 0xE0; ++ BOOTRAM[173] = 0x04; ++ BOOTRAM[174] = 0xF0; ++ BOOTRAM[175] = 0x90; ++ BOOTRAM[176] = 0x81; ++ BOOTRAM[177] = 0x87; ++ BOOTRAM[178] = 0xE0; ++ BOOTRAM[179] = 0x70; ++ BOOTRAM[180] = 0x04; ++ BOOTRAM[181] = 0xA3; ++ BOOTRAM[182] = 0xE0; ++ BOOTRAM[183] = 0x64; ++ BOOTRAM[184] = 0x08; ++ BOOTRAM[185] = 0x60; ++ BOOTRAM[186] = 0x03; ++ BOOTRAM[187] = 0x02; ++ BOOTRAM[188] = 0x03; ++ BOOTRAM[189] = 0x06; ++ BOOTRAM[190] = 0x90; ++ BOOTRAM[191] = 0x81; ++ BOOTRAM[192] = 0x89; ++ BOOTRAM[193] = 0x74; ++ BOOTRAM[194] = 0x02; ++ BOOTRAM[195] = 0xF0; ++ BOOTRAM[196] = 0xE4; ++ BOOTRAM[197] = 0x90; ++ BOOTRAM[198] = 0x81; ++ BOOTRAM[199] = 0x87; ++ BOOTRAM[200] = 0x02; ++ BOOTRAM[201] = 0x02; ++ BOOTRAM[202] = 0xF9; ++ BOOTRAM[203] = 0xC3; ++ BOOTRAM[204] = 0xEF; ++ BOOTRAM[205] = 0x94; ++ BOOTRAM[206] = 0xFC; ++ BOOTRAM[207] = 0xEE; ++ BOOTRAM[208] = 0x94; ++ BOOTRAM[209] = 0x08; ++ BOOTRAM[210] = 0x50; ++ BOOTRAM[211] = 0x4A; ++ BOOTRAM[212] = 0xEF; ++ BOOTRAM[213] = 0x94; ++ BOOTRAM[214] = 0xD0; ++ BOOTRAM[215] = 0xEE; ++ BOOTRAM[216] = 0x94; ++ BOOTRAM[217] = 0x07; ++ BOOTRAM[218] = 0x40; ++ BOOTRAM[219] = 0x42; ++ BOOTRAM[220] = 0x90; ++ BOOTRAM[221] = 0x81; ++ BOOTRAM[222] = 0x87; ++ BOOTRAM[223] = 0xA3; ++ BOOTRAM[224] = 0xE0; ++ BOOTRAM[225] = 0xFB; ++ BOOTRAM[226] = 0x74; ++ BOOTRAM[227] = 0x01; ++ BOOTRAM[228] = 0xA8; ++ BOOTRAM[229] = 0x03; ++ BOOTRAM[230] = 0x08; ++ BOOTRAM[231] = 0x80; ++ BOOTRAM[232] = 0x02; ++ BOOTRAM[233] = 0xC3; ++ BOOTRAM[234] = 0x33; ++ BOOTRAM[235] = 0xD8; ++ BOOTRAM[236] = 0xFC; ++ BOOTRAM[237] = 0xFB; ++ BOOTRAM[238] = 0x90; ++ BOOTRAM[239] = 0x81; ++ BOOTRAM[240] = 0x83; ++ BOOTRAM[241] = 0xE0; ++ BOOTRAM[242] = 0x2B; ++ BOOTRAM[243] = 0xF0; ++ BOOTRAM[244] = 0x90; ++ BOOTRAM[245] = 0x81; ++ BOOTRAM[246] = 0x88; ++ BOOTRAM[247] = 0xE0; ++ BOOTRAM[248] = 0x04; ++ BOOTRAM[249] = 0xF0; ++ BOOTRAM[250] = 0x70; ++ BOOTRAM[251] = 0x06; ++ BOOTRAM[252] = 0x90; ++ BOOTRAM[253] = 0x81; ++ BOOTRAM[254] = 0x87; ++ BOOTRAM[255] = 0xE0; ++ BOOTRAM[256] = 0x04; ++ BOOTRAM[257] = 0xF0; ++ BOOTRAM[258] = 0x90; ++ BOOTRAM[259] = 0x81; ++ BOOTRAM[260] = 0x87; ++ BOOTRAM[261] = 0xE0; ++ BOOTRAM[262] = 0x70; ++ BOOTRAM[263] = 0x04; ++ BOOTRAM[264] = 0xA3; ++ BOOTRAM[265] = 0xE0; ++ BOOTRAM[266] = 0x64; ++ BOOTRAM[267] = 0x08; ++ BOOTRAM[268] = 0x60; ++ BOOTRAM[269] = 0x03; ++ BOOTRAM[270] = 0x02; ++ BOOTRAM[271] = 0x03; ++ BOOTRAM[272] = 0x06; ++ BOOTRAM[273] = 0x90; ++ BOOTRAM[274] = 0x81; ++ BOOTRAM[275] = 0x89; ++ BOOTRAM[276] = 0x74; ++ BOOTRAM[277] = 0x02; ++ BOOTRAM[278] = 0xF0; ++ BOOTRAM[279] = 0xE4; ++ BOOTRAM[280] = 0x90; ++ BOOTRAM[281] = 0x81; ++ BOOTRAM[282] = 0x87; ++ BOOTRAM[283] = 0x02; ++ BOOTRAM[284] = 0x02; ++ BOOTRAM[285] = 0xF9; ++ BOOTRAM[286] = 0x02; ++ BOOTRAM[287] = 0x03; ++ BOOTRAM[288] = 0x00; ++ BOOTRAM[289] = 0xE9; ++ BOOTRAM[290] = 0x64; ++ BOOTRAM[291] = 0x02; ++ BOOTRAM[292] = 0x60; ++ BOOTRAM[293] = 0x03; ++ BOOTRAM[294] = 0x02; ++ BOOTRAM[295] = 0x01; ++ BOOTRAM[296] = 0xBF; ++ BOOTRAM[297] = 0xC3; ++ BOOTRAM[298] = 0xEF; ++ BOOTRAM[299] = 0x94; ++ BOOTRAM[300] = 0xB0; ++ BOOTRAM[301] = 0xEE; ++ BOOTRAM[302] = 0x94; ++ BOOTRAM[303] = 0x04; ++ BOOTRAM[304] = 0x50; ++ BOOTRAM[305] = 0x37; ++ BOOTRAM[306] = 0xEF; ++ BOOTRAM[307] = 0x94; ++ BOOTRAM[308] = 0xE8; ++ BOOTRAM[309] = 0xEE; ++ BOOTRAM[310] = 0x94; ++ BOOTRAM[311] = 0x03; ++ BOOTRAM[312] = 0x40; ++ BOOTRAM[313] = 0x2F; ++ BOOTRAM[314] = 0x90; ++ BOOTRAM[315] = 0x81; ++ BOOTRAM[316] = 0x84; ++ BOOTRAM[317] = 0xE0; ++ BOOTRAM[318] = 0xF0; ++ BOOTRAM[319] = 0x90; ++ BOOTRAM[320] = 0x81; ++ BOOTRAM[321] = 0x88; ++ BOOTRAM[322] = 0xE0; ++ BOOTRAM[323] = 0x04; ++ BOOTRAM[324] = 0xF0; ++ BOOTRAM[325] = 0x70; ++ BOOTRAM[326] = 0x06; ++ BOOTRAM[327] = 0x90; ++ BOOTRAM[328] = 0x81; ++ BOOTRAM[329] = 0x87; ++ BOOTRAM[330] = 0xE0; ++ BOOTRAM[331] = 0x04; ++ BOOTRAM[332] = 0xF0; ++ BOOTRAM[333] = 0x90; ++ BOOTRAM[334] = 0x81; ++ BOOTRAM[335] = 0x87; ++ BOOTRAM[336] = 0xE0; ++ BOOTRAM[337] = 0x70; ++ BOOTRAM[338] = 0x04; ++ BOOTRAM[339] = 0xA3; ++ BOOTRAM[340] = 0xE0; ++ BOOTRAM[341] = 0x64; ++ BOOTRAM[342] = 0x08; ++ BOOTRAM[343] = 0x60; ++ BOOTRAM[344] = 0x03; ++ BOOTRAM[345] = 0x02; ++ BOOTRAM[346] = 0x03; ++ BOOTRAM[347] = 0x06; ++ BOOTRAM[348] = 0x90; ++ BOOTRAM[349] = 0x81; ++ BOOTRAM[350] = 0x89; ++ BOOTRAM[351] = 0x74; ++ BOOTRAM[352] = 0x03; ++ BOOTRAM[353] = 0xF0; ++ BOOTRAM[354] = 0xE4; ++ BOOTRAM[355] = 0x90; ++ BOOTRAM[356] = 0x81; ++ BOOTRAM[357] = 0x87; ++ BOOTRAM[358] = 0x02; ++ BOOTRAM[359] = 0x02; ++ BOOTRAM[360] = 0xF9; ++ BOOTRAM[361] = 0xC3; ++ BOOTRAM[362] = 0xEF; ++ BOOTRAM[363] = 0x94; ++ BOOTRAM[364] = 0xFC; ++ BOOTRAM[365] = 0xEE; ++ BOOTRAM[366] = 0x94; ++ BOOTRAM[367] = 0x08; ++ BOOTRAM[368] = 0x50; ++ BOOTRAM[369] = 0x4A; ++ BOOTRAM[370] = 0xEF; ++ BOOTRAM[371] = 0x94; ++ BOOTRAM[372] = 0xD0; ++ BOOTRAM[373] = 0xEE; ++ BOOTRAM[374] = 0x94; ++ BOOTRAM[375] = 0x07; ++ BOOTRAM[376] = 0x40; ++ BOOTRAM[377] = 0x42; ++ BOOTRAM[378] = 0x90; ++ BOOTRAM[379] = 0x81; ++ BOOTRAM[380] = 0x87; ++ BOOTRAM[381] = 0xA3; ++ BOOTRAM[382] = 0xE0; ++ BOOTRAM[383] = 0xFB; ++ BOOTRAM[384] = 0x74; ++ BOOTRAM[385] = 0x01; ++ BOOTRAM[386] = 0xA8; ++ BOOTRAM[387] = 0x03; ++ BOOTRAM[388] = 0x08; ++ BOOTRAM[389] = 0x80; ++ BOOTRAM[390] = 0x02; ++ BOOTRAM[391] = 0xC3; ++ BOOTRAM[392] = 0x33; ++ BOOTRAM[393] = 0xD8; ++ BOOTRAM[394] = 0xFC; ++ BOOTRAM[395] = 0xFB; ++ BOOTRAM[396] = 0x90; ++ BOOTRAM[397] = 0x81; ++ BOOTRAM[398] = 0x84; ++ BOOTRAM[399] = 0xE0; ++ BOOTRAM[400] = 0x2B; ++ BOOTRAM[401] = 0xF0; ++ BOOTRAM[402] = 0x90; ++ BOOTRAM[403] = 0x81; ++ BOOTRAM[404] = 0x88; ++ BOOTRAM[405] = 0xE0; ++ BOOTRAM[406] = 0x04; ++ BOOTRAM[407] = 0xF0; ++ BOOTRAM[408] = 0x70; ++ BOOTRAM[409] = 0x06; ++ BOOTRAM[410] = 0x90; ++ BOOTRAM[411] = 0x81; ++ BOOTRAM[412] = 0x87; ++ BOOTRAM[413] = 0xE0; ++ BOOTRAM[414] = 0x04; ++ BOOTRAM[415] = 0xF0; ++ BOOTRAM[416] = 0x90; ++ BOOTRAM[417] = 0x81; ++ BOOTRAM[418] = 0x87; ++ BOOTRAM[419] = 0xE0; ++ BOOTRAM[420] = 0x70; ++ BOOTRAM[421] = 0x04; ++ BOOTRAM[422] = 0xA3; ++ BOOTRAM[423] = 0xE0; ++ BOOTRAM[424] = 0x64; ++ BOOTRAM[425] = 0x08; ++ BOOTRAM[426] = 0x60; ++ BOOTRAM[427] = 0x03; ++ BOOTRAM[428] = 0x02; ++ BOOTRAM[429] = 0x03; ++ BOOTRAM[430] = 0x06; ++ BOOTRAM[431] = 0x90; ++ BOOTRAM[432] = 0x81; ++ BOOTRAM[433] = 0x89; ++ BOOTRAM[434] = 0x74; ++ BOOTRAM[435] = 0x03; ++ BOOTRAM[436] = 0xF0; ++ BOOTRAM[437] = 0xE4; ++ BOOTRAM[438] = 0x90; ++ BOOTRAM[439] = 0x81; ++ BOOTRAM[440] = 0x87; ++ BOOTRAM[441] = 0x02; ++ BOOTRAM[442] = 0x02; ++ BOOTRAM[443] = 0xF9; ++ BOOTRAM[444] = 0x02; ++ BOOTRAM[445] = 0x03; ++ BOOTRAM[446] = 0x00; ++ BOOTRAM[447] = 0xE9; ++ BOOTRAM[448] = 0x64; ++ BOOTRAM[449] = 0x03; ++ BOOTRAM[450] = 0x60; ++ BOOTRAM[451] = 0x03; ++ BOOTRAM[452] = 0x02; ++ BOOTRAM[453] = 0x02; ++ BOOTRAM[454] = 0x5D; ++ BOOTRAM[455] = 0xC3; ++ BOOTRAM[456] = 0xEF; ++ BOOTRAM[457] = 0x94; ++ BOOTRAM[458] = 0xB0; ++ BOOTRAM[459] = 0xEE; ++ BOOTRAM[460] = 0x94; ++ BOOTRAM[461] = 0x04; ++ BOOTRAM[462] = 0x50; ++ BOOTRAM[463] = 0x37; ++ BOOTRAM[464] = 0xEF; ++ BOOTRAM[465] = 0x94; ++ BOOTRAM[466] = 0xE8; ++ BOOTRAM[467] = 0xEE; ++ BOOTRAM[468] = 0x94; ++ BOOTRAM[469] = 0x03; ++ BOOTRAM[470] = 0x40; ++ BOOTRAM[471] = 0x2F; ++ BOOTRAM[472] = 0x90; ++ BOOTRAM[473] = 0x81; ++ BOOTRAM[474] = 0x85; ++ BOOTRAM[475] = 0xE0; ++ BOOTRAM[476] = 0xF0; ++ BOOTRAM[477] = 0x90; ++ BOOTRAM[478] = 0x81; ++ BOOTRAM[479] = 0x88; ++ BOOTRAM[480] = 0xE0; ++ BOOTRAM[481] = 0x04; ++ BOOTRAM[482] = 0xF0; ++ BOOTRAM[483] = 0x70; ++ BOOTRAM[484] = 0x06; ++ BOOTRAM[485] = 0x90; ++ BOOTRAM[486] = 0x81; ++ BOOTRAM[487] = 0x87; ++ BOOTRAM[488] = 0xE0; ++ BOOTRAM[489] = 0x04; ++ BOOTRAM[490] = 0xF0; ++ BOOTRAM[491] = 0x90; ++ BOOTRAM[492] = 0x81; ++ BOOTRAM[493] = 0x87; ++ BOOTRAM[494] = 0xE0; ++ BOOTRAM[495] = 0x70; ++ BOOTRAM[496] = 0x04; ++ BOOTRAM[497] = 0xA3; ++ BOOTRAM[498] = 0xE0; ++ BOOTRAM[499] = 0x64; ++ BOOTRAM[500] = 0x08; ++ BOOTRAM[501] = 0x60; ++ BOOTRAM[502] = 0x03; ++ BOOTRAM[503] = 0x02; ++ BOOTRAM[504] = 0x03; ++ BOOTRAM[505] = 0x06; ++ BOOTRAM[506] = 0x90; ++ BOOTRAM[507] = 0x81; ++ BOOTRAM[508] = 0x89; ++ BOOTRAM[509] = 0x74; ++ BOOTRAM[510] = 0x04; ++ BOOTRAM[511] = 0xF0; ++ BOOTRAM[512] = 0xE4; ++ BOOTRAM[513] = 0x90; ++ BOOTRAM[514] = 0x81; ++ BOOTRAM[515] = 0x87; ++ BOOTRAM[516] = 0x02; ++ BOOTRAM[517] = 0x02; ++ BOOTRAM[518] = 0xF9; ++ BOOTRAM[519] = 0xC3; ++ BOOTRAM[520] = 0xEF; ++ BOOTRAM[521] = 0x94; ++ BOOTRAM[522] = 0xFC; ++ BOOTRAM[523] = 0xEE; ++ BOOTRAM[524] = 0x94; ++ BOOTRAM[525] = 0x08; ++ BOOTRAM[526] = 0x50; ++ BOOTRAM[527] = 0x4A; ++ BOOTRAM[528] = 0xEF; ++ BOOTRAM[529] = 0x94; ++ BOOTRAM[530] = 0xD0; ++ BOOTRAM[531] = 0xEE; ++ BOOTRAM[532] = 0x94; ++ BOOTRAM[533] = 0x07; ++ BOOTRAM[534] = 0x40; ++ BOOTRAM[535] = 0x42; ++ BOOTRAM[536] = 0x90; ++ BOOTRAM[537] = 0x81; ++ BOOTRAM[538] = 0x87; ++ BOOTRAM[539] = 0xA3; ++ BOOTRAM[540] = 0xE0; ++ BOOTRAM[541] = 0xFB; ++ BOOTRAM[542] = 0x74; ++ BOOTRAM[543] = 0x01; ++ BOOTRAM[544] = 0xA8; ++ BOOTRAM[545] = 0x03; ++ BOOTRAM[546] = 0x08; ++ BOOTRAM[547] = 0x80; ++ BOOTRAM[548] = 0x02; ++ BOOTRAM[549] = 0xC3; ++ BOOTRAM[550] = 0x33; ++ BOOTRAM[551] = 0xD8; ++ BOOTRAM[552] = 0xFC; ++ BOOTRAM[553] = 0xFB; ++ BOOTRAM[554] = 0x90; ++ BOOTRAM[555] = 0x81; ++ BOOTRAM[556] = 0x85; ++ BOOTRAM[557] = 0xE0; ++ BOOTRAM[558] = 0x2B; ++ BOOTRAM[559] = 0xF0; ++ BOOTRAM[560] = 0x90; ++ BOOTRAM[561] = 0x81; ++ BOOTRAM[562] = 0x88; ++ BOOTRAM[563] = 0xE0; ++ BOOTRAM[564] = 0x04; ++ BOOTRAM[565] = 0xF0; ++ BOOTRAM[566] = 0x70; ++ BOOTRAM[567] = 0x06; ++ BOOTRAM[568] = 0x90; ++ BOOTRAM[569] = 0x81; ++ BOOTRAM[570] = 0x87; ++ BOOTRAM[571] = 0xE0; ++ BOOTRAM[572] = 0x04; ++ BOOTRAM[573] = 0xF0; ++ BOOTRAM[574] = 0x90; ++ BOOTRAM[575] = 0x81; ++ BOOTRAM[576] = 0x87; ++ BOOTRAM[577] = 0xE0; ++ BOOTRAM[578] = 0x70; ++ BOOTRAM[579] = 0x04; ++ BOOTRAM[580] = 0xA3; ++ BOOTRAM[581] = 0xE0; ++ BOOTRAM[582] = 0x64; ++ BOOTRAM[583] = 0x08; ++ BOOTRAM[584] = 0x60; ++ BOOTRAM[585] = 0x03; ++ BOOTRAM[586] = 0x02; ++ BOOTRAM[587] = 0x03; ++ BOOTRAM[588] = 0x06; ++ BOOTRAM[589] = 0x90; ++ BOOTRAM[590] = 0x81; ++ BOOTRAM[591] = 0x89; ++ BOOTRAM[592] = 0x74; ++ BOOTRAM[593] = 0x04; ++ BOOTRAM[594] = 0xF0; ++ BOOTRAM[595] = 0xE4; ++ BOOTRAM[596] = 0x90; ++ BOOTRAM[597] = 0x81; ++ BOOTRAM[598] = 0x87; ++ BOOTRAM[599] = 0x02; ++ BOOTRAM[600] = 0x02; ++ BOOTRAM[601] = 0xF9; ++ BOOTRAM[602] = 0x02; ++ BOOTRAM[603] = 0x03; ++ BOOTRAM[604] = 0x00; ++ BOOTRAM[605] = 0xE9; ++ BOOTRAM[606] = 0x64; ++ BOOTRAM[607] = 0x04; ++ BOOTRAM[608] = 0x60; ++ BOOTRAM[609] = 0x03; ++ BOOTRAM[610] = 0x02; ++ BOOTRAM[611] = 0x03; ++ BOOTRAM[612] = 0x06; ++ BOOTRAM[613] = 0xC3; ++ BOOTRAM[614] = 0xEF; ++ BOOTRAM[615] = 0x94; ++ BOOTRAM[616] = 0xB0; ++ BOOTRAM[617] = 0xEE; ++ BOOTRAM[618] = 0x94; ++ BOOTRAM[619] = 0x04; ++ BOOTRAM[620] = 0x50; ++ BOOTRAM[621] = 0x33; ++ BOOTRAM[622] = 0xEF; ++ BOOTRAM[623] = 0x94; ++ BOOTRAM[624] = 0xE8; ++ BOOTRAM[625] = 0xEE; ++ BOOTRAM[626] = 0x94; ++ BOOTRAM[627] = 0x03; ++ BOOTRAM[628] = 0x40; ++ BOOTRAM[629] = 0x2B; ++ BOOTRAM[630] = 0x90; ++ BOOTRAM[631] = 0x81; ++ BOOTRAM[632] = 0x86; ++ BOOTRAM[633] = 0xE0; ++ BOOTRAM[634] = 0xF0; ++ BOOTRAM[635] = 0x90; ++ BOOTRAM[636] = 0x81; ++ BOOTRAM[637] = 0x88; ++ BOOTRAM[638] = 0xE0; ++ BOOTRAM[639] = 0x04; ++ BOOTRAM[640] = 0xF0; ++ BOOTRAM[641] = 0x70; ++ BOOTRAM[642] = 0x06; ++ BOOTRAM[643] = 0x90; ++ BOOTRAM[644] = 0x81; ++ BOOTRAM[645] = 0x87; ++ BOOTRAM[646] = 0xE0; ++ BOOTRAM[647] = 0x04; ++ BOOTRAM[648] = 0xF0; ++ BOOTRAM[649] = 0x90; ++ BOOTRAM[650] = 0x81; ++ BOOTRAM[651] = 0x87; ++ BOOTRAM[652] = 0xE0; ++ BOOTRAM[653] = 0x70; ++ BOOTRAM[654] = 0x04; ++ BOOTRAM[655] = 0xA3; ++ BOOTRAM[656] = 0xE0; ++ BOOTRAM[657] = 0x64; ++ BOOTRAM[658] = 0x08; ++ BOOTRAM[659] = 0x70; ++ BOOTRAM[660] = 0x71; ++ BOOTRAM[661] = 0x90; ++ BOOTRAM[662] = 0x81; ++ BOOTRAM[663] = 0x89; ++ BOOTRAM[664] = 0x74; ++ BOOTRAM[665] = 0x05; ++ BOOTRAM[666] = 0xF0; ++ BOOTRAM[667] = 0xE4; ++ BOOTRAM[668] = 0x90; ++ BOOTRAM[669] = 0x81; ++ BOOTRAM[670] = 0x87; ++ BOOTRAM[671] = 0x80; ++ BOOTRAM[672] = 0x58; ++ BOOTRAM[673] = 0xC3; ++ BOOTRAM[674] = 0xEF; ++ BOOTRAM[675] = 0x94; ++ BOOTRAM[676] = 0xFC; ++ BOOTRAM[677] = 0xEE; ++ BOOTRAM[678] = 0x94; ++ BOOTRAM[679] = 0x08; ++ BOOTRAM[680] = 0x50; ++ BOOTRAM[681] = 0x56; ++ BOOTRAM[682] = 0xEF; ++ BOOTRAM[683] = 0x94; ++ BOOTRAM[684] = 0xD0; ++ BOOTRAM[685] = 0xEE; ++ BOOTRAM[686] = 0x94; ++ BOOTRAM[687] = 0x07; ++ BOOTRAM[688] = 0x40; ++ BOOTRAM[689] = 0x4E; ++ BOOTRAM[690] = 0x90; ++ BOOTRAM[691] = 0x81; ++ BOOTRAM[692] = 0x87; ++ BOOTRAM[693] = 0xA3; ++ BOOTRAM[694] = 0xE0; ++ BOOTRAM[695] = 0xFF; ++ BOOTRAM[696] = 0x74; ++ BOOTRAM[697] = 0x01; ++ BOOTRAM[698] = 0xA8; ++ BOOTRAM[699] = 0x07; ++ BOOTRAM[700] = 0x08; ++ BOOTRAM[701] = 0x80; ++ BOOTRAM[702] = 0x02; ++ BOOTRAM[703] = 0xC3; ++ BOOTRAM[704] = 0x33; ++ BOOTRAM[705] = 0xD8; ++ BOOTRAM[706] = 0xFC; ++ BOOTRAM[707] = 0xFF; ++ BOOTRAM[708] = 0x90; ++ BOOTRAM[709] = 0x81; ++ BOOTRAM[710] = 0x86; ++ BOOTRAM[711] = 0xE0; ++ BOOTRAM[712] = 0x2F; ++ BOOTRAM[713] = 0xF0; ++ BOOTRAM[714] = 0x90; ++ BOOTRAM[715] = 0x81; ++ BOOTRAM[716] = 0x88; ++ BOOTRAM[717] = 0xE0; ++ BOOTRAM[718] = 0x04; ++ BOOTRAM[719] = 0xF0; ++ BOOTRAM[720] = 0x70; ++ BOOTRAM[721] = 0x06; ++ BOOTRAM[722] = 0x90; ++ BOOTRAM[723] = 0x81; ++ BOOTRAM[724] = 0x87; ++ BOOTRAM[725] = 0xE0; ++ BOOTRAM[726] = 0x04; ++ BOOTRAM[727] = 0xF0; ++ BOOTRAM[728] = 0x90; ++ BOOTRAM[729] = 0x81; ++ BOOTRAM[730] = 0x87; ++ BOOTRAM[731] = 0xE0; ++ BOOTRAM[732] = 0x70; ++ BOOTRAM[733] = 0x04; ++ BOOTRAM[734] = 0xA3; ++ BOOTRAM[735] = 0xE0; ++ BOOTRAM[736] = 0x64; ++ BOOTRAM[737] = 0x08; ++ BOOTRAM[738] = 0x70; ++ BOOTRAM[739] = 0x22; ++ BOOTRAM[740] = 0x90; ++ BOOTRAM[741] = 0x81; ++ BOOTRAM[742] = 0x85; ++ BOOTRAM[743] = 0xE0; ++ BOOTRAM[744] = 0xF4; ++ BOOTRAM[745] = 0xFF; ++ BOOTRAM[746] = 0xA3; ++ BOOTRAM[747] = 0xE0; ++ BOOTRAM[748] = 0x90; ++ BOOTRAM[749] = 0x81; ++ BOOTRAM[750] = 0x89; ++ BOOTRAM[751] = 0xB5; ++ BOOTRAM[752] = 0x07; ++ BOOTRAM[753] = 0x0C; ++ BOOTRAM[754] = 0x74; ++ BOOTRAM[755] = 0x05; ++ BOOTRAM[756] = 0xF0; ++ BOOTRAM[757] = 0xE4; ++ BOOTRAM[758] = 0x90; ++ BOOTRAM[759] = 0x81; ++ BOOTRAM[760] = 0x87; ++ BOOTRAM[761] = 0xF0; ++ BOOTRAM[762] = 0xA3; ++ BOOTRAM[763] = 0xF0; ++ BOOTRAM[764] = 0x80; ++ BOOTRAM[765] = 0x08; ++ BOOTRAM[766] = 0x80; ++ BOOTRAM[767] = 0x03; ++ BOOTRAM[768] = 0x90; ++ BOOTRAM[769] = 0x81; ++ BOOTRAM[770] = 0x89; ++ BOOTRAM[771] = 0x74; ++ BOOTRAM[772] = 0x14; ++ BOOTRAM[773] = 0xF0; ++ BOOTRAM[774] = 0x0D; ++ BOOTRAM[775] = 0xBD; ++ BOOTRAM[776] = 0x00; ++ BOOTRAM[777] = 0x01; ++ BOOTRAM[778] = 0x0C; ++ BOOTRAM[779] = 0x02; ++ BOOTRAM[780] = 0x00; ++ BOOTRAM[781] = 0x18; ++ BOOTRAM[782] = 0x90; ++ BOOTRAM[783] = 0x81; ++ BOOTRAM[784] = 0x83; ++ BOOTRAM[785] = 0xE0; ++ BOOTRAM[786] = 0xFE; ++ BOOTRAM[787] = 0xA3; ++ BOOTRAM[788] = 0xE0; ++ BOOTRAM[789] = 0x7C; ++ BOOTRAM[790] = 0x00; ++ BOOTRAM[791] = 0x24; ++ BOOTRAM[792] = 0x00; ++ BOOTRAM[793] = 0xFF; ++ BOOTRAM[794] = 0xEC; ++ BOOTRAM[795] = 0x3E; ++ BOOTRAM[796] = 0xF9; ++ BOOTRAM[797] = 0x90; ++ BOOTRAM[798] = 0x81; ++ BOOTRAM[799] = 0x80; ++ BOOTRAM[800] = 0xE0; ++ BOOTRAM[801] = 0xFB; ++ BOOTRAM[802] = 0xA3; ++ BOOTRAM[803] = 0xE0; ++ BOOTRAM[804] = 0xFA; ++ BOOTRAM[805] = 0xA3; ++ BOOTRAM[806] = 0xE0; ++ BOOTRAM[807] = 0xC9; ++ BOOTRAM[808] = 0x8F; ++ BOOTRAM[809] = 0xF0; ++ BOOTRAM[810] = 0x12; ++ BOOTRAM[811] = 0x04; ++ BOOTRAM[812] = 0x57; ++ BOOTRAM[813] = 0x90; ++ BOOTRAM[814] = 0x81; ++ BOOTRAM[815] = 0x89; ++ BOOTRAM[816] = 0xE0; ++ BOOTRAM[817] = 0xB4; ++ BOOTRAM[818] = 0x05; ++ BOOTRAM[819] = 0x06; ++ BOOTRAM[820] = 0x90; ++ BOOTRAM[821] = 0x81; ++ BOOTRAM[822] = 0x85; ++ BOOTRAM[823] = 0xE0; ++ BOOTRAM[824] = 0xFF; ++ BOOTRAM[825] = 0x22; ++ BOOTRAM[826] = 0x7F; ++ BOOTRAM[827] = 0x00; ++ BOOTRAM[828] = 0x22; ++ BOOTRAM[829] = 0xE7; ++ BOOTRAM[830] = 0x09; ++ BOOTRAM[831] = 0xF6; ++ BOOTRAM[832] = 0x08; ++ BOOTRAM[833] = 0xDF; ++ BOOTRAM[834] = 0xFA; ++ BOOTRAM[835] = 0x80; ++ BOOTRAM[836] = 0x46; ++ BOOTRAM[837] = 0xE7; ++ BOOTRAM[838] = 0x09; ++ BOOTRAM[839] = 0xF2; ++ BOOTRAM[840] = 0x08; ++ BOOTRAM[841] = 0xDF; ++ BOOTRAM[842] = 0xFA; ++ BOOTRAM[843] = 0x80; ++ BOOTRAM[844] = 0x3E; ++ BOOTRAM[845] = 0x88; ++ BOOTRAM[846] = 0x82; ++ BOOTRAM[847] = 0x8C; ++ BOOTRAM[848] = 0x83; ++ BOOTRAM[849] = 0xE7; ++ BOOTRAM[850] = 0x09; ++ BOOTRAM[851] = 0xF0; ++ BOOTRAM[852] = 0xA3; ++ BOOTRAM[853] = 0xDF; ++ BOOTRAM[854] = 0xFA; ++ BOOTRAM[855] = 0x80; ++ BOOTRAM[856] = 0x32; ++ BOOTRAM[857] = 0xE3; ++ BOOTRAM[858] = 0x09; ++ BOOTRAM[859] = 0xF6; ++ BOOTRAM[860] = 0x08; ++ BOOTRAM[861] = 0xDF; ++ BOOTRAM[862] = 0xFA; ++ BOOTRAM[863] = 0x80; ++ BOOTRAM[864] = 0x78; ++ BOOTRAM[865] = 0xE3; ++ BOOTRAM[866] = 0x09; ++ BOOTRAM[867] = 0xF2; ++ BOOTRAM[868] = 0x08; ++ BOOTRAM[869] = 0xDF; ++ BOOTRAM[870] = 0xFA; ++ BOOTRAM[871] = 0x80; ++ BOOTRAM[872] = 0x70; ++ BOOTRAM[873] = 0x88; ++ BOOTRAM[874] = 0x82; ++ BOOTRAM[875] = 0x8C; ++ BOOTRAM[876] = 0x83; ++ BOOTRAM[877] = 0xE3; ++ BOOTRAM[878] = 0x09; ++ BOOTRAM[879] = 0xF0; ++ BOOTRAM[880] = 0xA3; ++ BOOTRAM[881] = 0xDF; ++ BOOTRAM[882] = 0xFA; ++ BOOTRAM[883] = 0x80; ++ BOOTRAM[884] = 0x64; ++ BOOTRAM[885] = 0x89; ++ BOOTRAM[886] = 0x82; ++ BOOTRAM[887] = 0x8A; ++ BOOTRAM[888] = 0x83; ++ BOOTRAM[889] = 0xE0; ++ BOOTRAM[890] = 0xA3; ++ BOOTRAM[891] = 0xF6; ++ BOOTRAM[892] = 0x08; ++ BOOTRAM[893] = 0xDF; ++ BOOTRAM[894] = 0xFA; ++ BOOTRAM[895] = 0x80; ++ BOOTRAM[896] = 0x58; ++ BOOTRAM[897] = 0x89; ++ BOOTRAM[898] = 0x82; ++ BOOTRAM[899] = 0x8A; ++ BOOTRAM[900] = 0x83; ++ BOOTRAM[901] = 0xE0; ++ BOOTRAM[902] = 0xA3; ++ BOOTRAM[903] = 0xF2; ++ BOOTRAM[904] = 0x08; ++ BOOTRAM[905] = 0xDF; ++ BOOTRAM[906] = 0xFA; ++ BOOTRAM[907] = 0x80; ++ BOOTRAM[908] = 0x4C; ++ BOOTRAM[909] = 0x80; ++ BOOTRAM[910] = 0xD2; ++ BOOTRAM[911] = 0x80; ++ BOOTRAM[912] = 0xFA; ++ BOOTRAM[913] = 0x80; ++ BOOTRAM[914] = 0xC6; ++ BOOTRAM[915] = 0x80; ++ BOOTRAM[916] = 0xD4; ++ BOOTRAM[917] = 0x80; ++ BOOTRAM[918] = 0x69; ++ BOOTRAM[919] = 0x80; ++ BOOTRAM[920] = 0xF2; ++ BOOTRAM[921] = 0x80; ++ BOOTRAM[922] = 0x33; ++ BOOTRAM[923] = 0x80; ++ BOOTRAM[924] = 0x10; ++ BOOTRAM[925] = 0x80; ++ BOOTRAM[926] = 0xA6; ++ BOOTRAM[927] = 0x80; ++ BOOTRAM[928] = 0xEA; ++ BOOTRAM[929] = 0x80; ++ BOOTRAM[930] = 0x9A; ++ BOOTRAM[931] = 0x80; ++ BOOTRAM[932] = 0xA8; ++ BOOTRAM[933] = 0x80; ++ BOOTRAM[934] = 0xDA; ++ BOOTRAM[935] = 0x80; ++ BOOTRAM[936] = 0xE2; ++ BOOTRAM[937] = 0x80; ++ BOOTRAM[938] = 0xCA; ++ BOOTRAM[939] = 0x80; ++ BOOTRAM[940] = 0x33; ++ BOOTRAM[941] = 0x89; ++ BOOTRAM[942] = 0x82; ++ BOOTRAM[943] = 0x8A; ++ BOOTRAM[944] = 0x83; ++ BOOTRAM[945] = 0xEC; ++ BOOTRAM[946] = 0xFA; ++ BOOTRAM[947] = 0xE4; ++ BOOTRAM[948] = 0x93; ++ BOOTRAM[949] = 0xA3; ++ BOOTRAM[950] = 0xC8; ++ BOOTRAM[951] = 0xC5; ++ BOOTRAM[952] = 0x82; ++ BOOTRAM[953] = 0xC8; ++ BOOTRAM[954] = 0xCC; ++ BOOTRAM[955] = 0xC5; ++ BOOTRAM[956] = 0x83; ++ BOOTRAM[957] = 0xCC; ++ BOOTRAM[958] = 0xF0; ++ BOOTRAM[959] = 0xA3; ++ BOOTRAM[960] = 0xC8; ++ BOOTRAM[961] = 0xC5; ++ BOOTRAM[962] = 0x82; ++ BOOTRAM[963] = 0xC8; ++ BOOTRAM[964] = 0xCC; ++ BOOTRAM[965] = 0xC5; ++ BOOTRAM[966] = 0x83; ++ BOOTRAM[967] = 0xCC; ++ BOOTRAM[968] = 0xDF; ++ BOOTRAM[969] = 0xE9; ++ BOOTRAM[970] = 0xDE; ++ BOOTRAM[971] = 0xE7; ++ BOOTRAM[972] = 0x80; ++ BOOTRAM[973] = 0x0D; ++ BOOTRAM[974] = 0x89; ++ BOOTRAM[975] = 0x82; ++ BOOTRAM[976] = 0x8A; ++ BOOTRAM[977] = 0x83; ++ BOOTRAM[978] = 0xE4; ++ BOOTRAM[979] = 0x93; ++ BOOTRAM[980] = 0xA3; ++ BOOTRAM[981] = 0xF6; ++ BOOTRAM[982] = 0x08; ++ BOOTRAM[983] = 0xDF; ++ BOOTRAM[984] = 0xF9; ++ BOOTRAM[985] = 0xEC; ++ BOOTRAM[986] = 0xFA; ++ BOOTRAM[987] = 0xA9; ++ BOOTRAM[988] = 0xF0; ++ BOOTRAM[989] = 0xED; ++ BOOTRAM[990] = 0xFB; ++ BOOTRAM[991] = 0x22; ++ BOOTRAM[992] = 0x89; ++ BOOTRAM[993] = 0x82; ++ BOOTRAM[994] = 0x8A; ++ BOOTRAM[995] = 0x83; ++ BOOTRAM[996] = 0xEC; ++ BOOTRAM[997] = 0xFA; ++ BOOTRAM[998] = 0xE0; ++ BOOTRAM[999] = 0xA3; ++ BOOTRAM[1000] = 0xC8; ++ BOOTRAM[1001] = 0xC5; ++ BOOTRAM[1002] = 0x82; ++ BOOTRAM[1003] = 0xC8; ++ BOOTRAM[1004] = 0xCC; ++ BOOTRAM[1005] = 0xC5; ++ BOOTRAM[1006] = 0x83; ++ BOOTRAM[1007] = 0xCC; ++ BOOTRAM[1008] = 0xF0; ++ BOOTRAM[1009] = 0xA3; ++ BOOTRAM[1010] = 0xC8; ++ BOOTRAM[1011] = 0xC5; ++ BOOTRAM[1012] = 0x82; ++ BOOTRAM[1013] = 0xC8; ++ BOOTRAM[1014] = 0xCC; ++ BOOTRAM[1015] = 0xC5; ++ BOOTRAM[1016] = 0x83; ++ BOOTRAM[1017] = 0xCC; ++ BOOTRAM[1018] = 0xDF; ++ BOOTRAM[1019] = 0xEA; ++ BOOTRAM[1020] = 0xDE; ++ BOOTRAM[1021] = 0xE8; ++ BOOTRAM[1022] = 0x80; ++ BOOTRAM[1023] = 0xDB; ++ BOOTRAM[1024] = 0x89; ++ BOOTRAM[1025] = 0x82; ++ BOOTRAM[1026] = 0x8A; ++ BOOTRAM[1027] = 0x83; ++ BOOTRAM[1028] = 0xE4; ++ BOOTRAM[1029] = 0x93; ++ BOOTRAM[1030] = 0xA3; ++ BOOTRAM[1031] = 0xF2; ++ BOOTRAM[1032] = 0x08; ++ BOOTRAM[1033] = 0xDF; ++ BOOTRAM[1034] = 0xF9; ++ BOOTRAM[1035] = 0x80; ++ BOOTRAM[1036] = 0xCC; ++ BOOTRAM[1037] = 0x88; ++ BOOTRAM[1038] = 0xF0; ++ BOOTRAM[1039] = 0xEF; ++ BOOTRAM[1040] = 0x60; ++ BOOTRAM[1041] = 0x01; ++ BOOTRAM[1042] = 0x0E; ++ BOOTRAM[1043] = 0x4E; ++ BOOTRAM[1044] = 0x60; ++ BOOTRAM[1045] = 0xC3; ++ BOOTRAM[1046] = 0x88; ++ BOOTRAM[1047] = 0xF0; ++ BOOTRAM[1048] = 0xED; ++ BOOTRAM[1049] = 0x24; ++ BOOTRAM[1050] = 0x02; ++ BOOTRAM[1051] = 0xB4; ++ BOOTRAM[1052] = 0x04; ++ BOOTRAM[1053] = 0x00; ++ BOOTRAM[1054] = 0x50; ++ BOOTRAM[1055] = 0xB9; ++ BOOTRAM[1056] = 0xF5; ++ BOOTRAM[1057] = 0x82; ++ BOOTRAM[1058] = 0xEB; ++ BOOTRAM[1059] = 0x24; ++ BOOTRAM[1060] = 0x02; ++ BOOTRAM[1061] = 0xB4; ++ BOOTRAM[1062] = 0x04; ++ BOOTRAM[1063] = 0x00; ++ BOOTRAM[1064] = 0x50; ++ BOOTRAM[1065] = 0xAF; ++ BOOTRAM[1066] = 0x23; ++ BOOTRAM[1067] = 0x23; ++ BOOTRAM[1068] = 0x45; ++ BOOTRAM[1069] = 0x82; ++ BOOTRAM[1070] = 0x23; ++ BOOTRAM[1071] = 0x90; ++ BOOTRAM[1072] = 0x03; ++ BOOTRAM[1073] = 0x8D; ++ BOOTRAM[1074] = 0x73; ++ BOOTRAM[1075] = 0xBB; ++ BOOTRAM[1076] = 0x01; ++ BOOTRAM[1077] = 0x06; ++ BOOTRAM[1078] = 0x89; ++ BOOTRAM[1079] = 0x82; ++ BOOTRAM[1080] = 0x8A; ++ BOOTRAM[1081] = 0x83; ++ BOOTRAM[1082] = 0xF0; ++ BOOTRAM[1083] = 0x22; ++ BOOTRAM[1084] = 0x50; ++ BOOTRAM[1085] = 0x02; ++ BOOTRAM[1086] = 0xF7; ++ BOOTRAM[1087] = 0x22; ++ BOOTRAM[1088] = 0xBB; ++ BOOTRAM[1089] = 0xFE; ++ BOOTRAM[1090] = 0x01; ++ BOOTRAM[1091] = 0xF3; ++ BOOTRAM[1092] = 0x22; ++ BOOTRAM[1093] = 0xEF; ++ BOOTRAM[1094] = 0x8D; ++ BOOTRAM[1095] = 0xF0; ++ BOOTRAM[1096] = 0xA4; ++ BOOTRAM[1097] = 0xA8; ++ BOOTRAM[1098] = 0xF0; ++ BOOTRAM[1099] = 0xCF; ++ BOOTRAM[1100] = 0x8C; ++ BOOTRAM[1101] = 0xF0; ++ BOOTRAM[1102] = 0xA4; ++ BOOTRAM[1103] = 0x28; ++ BOOTRAM[1104] = 0xCE; ++ BOOTRAM[1105] = 0x8D; ++ BOOTRAM[1106] = 0xF0; ++ BOOTRAM[1107] = 0xA4; ++ BOOTRAM[1108] = 0x2E; ++ BOOTRAM[1109] = 0xFE; ++ BOOTRAM[1110] = 0x22; ++ BOOTRAM[1111] = 0xBB; ++ BOOTRAM[1112] = 0x01; ++ BOOTRAM[1113] = 0x0A; ++ BOOTRAM[1114] = 0x89; ++ BOOTRAM[1115] = 0x82; ++ BOOTRAM[1116] = 0x8A; ++ BOOTRAM[1117] = 0x83; ++ BOOTRAM[1118] = 0xF0; ++ BOOTRAM[1119] = 0xE5; ++ BOOTRAM[1120] = 0xF0; ++ BOOTRAM[1121] = 0xA3; ++ BOOTRAM[1122] = 0xF0; ++ BOOTRAM[1123] = 0x22; ++ BOOTRAM[1124] = 0x50; ++ BOOTRAM[1125] = 0x06; ++ BOOTRAM[1126] = 0xF7; ++ BOOTRAM[1127] = 0x09; ++ BOOTRAM[1128] = 0xA7; ++ BOOTRAM[1129] = 0xF0; ++ BOOTRAM[1130] = 0x19; ++ BOOTRAM[1131] = 0x22; ++ BOOTRAM[1132] = 0xBB; ++ BOOTRAM[1133] = 0xFE; ++ BOOTRAM[1134] = 0x06; ++ BOOTRAM[1135] = 0xF3; ++ BOOTRAM[1136] = 0xE5; ++ BOOTRAM[1137] = 0xF0; ++ BOOTRAM[1138] = 0x09; ++ BOOTRAM[1139] = 0xF3; ++ BOOTRAM[1140] = 0x19; ++ BOOTRAM[1141] = 0x22; ++ BOOTRAM[1142] = 0x90; ++ BOOTRAM[1143] = 0x19; ++ BOOTRAM[1144] = 0x06; ++ BOOTRAM[1145] = 0xE0; ++ BOOTRAM[1146] = 0xA3; ++ BOOTRAM[1147] = 0xF0; ++ BOOTRAM[1148] = 0x7D; ++ BOOTRAM[1149] = 0x01; ++ BOOTRAM[1150] = 0x7F; ++ BOOTRAM[1151] = 0x02; ++ BOOTRAM[1152] = 0x12; ++ BOOTRAM[1153] = 0x0C; ++ BOOTRAM[1154] = 0x76; ++ BOOTRAM[1155] = 0x7F; ++ BOOTRAM[1156] = 0x03; ++ BOOTRAM[1157] = 0x12; ++ BOOTRAM[1158] = 0x0C; ++ BOOTRAM[1159] = 0x76; ++ BOOTRAM[1160] = 0x7F; ++ BOOTRAM[1161] = 0x04; ++ BOOTRAM[1162] = 0x12; ++ BOOTRAM[1163] = 0x0C; ++ BOOTRAM[1164] = 0x76; ++ BOOTRAM[1165] = 0x7F; ++ BOOTRAM[1166] = 0x05; ++ BOOTRAM[1167] = 0x12; ++ BOOTRAM[1168] = 0x0C; ++ BOOTRAM[1169] = 0x76; ++ BOOTRAM[1170] = 0x1D; ++ BOOTRAM[1171] = 0x7F; ++ BOOTRAM[1172] = 0x07; ++ BOOTRAM[1173] = 0x12; ++ BOOTRAM[1174] = 0x0C; ++ BOOTRAM[1175] = 0x76; ++ BOOTRAM[1176] = 0x0D; ++ BOOTRAM[1177] = 0x7F; ++ BOOTRAM[1178] = 0x02; ++ BOOTRAM[1179] = 0x12; ++ BOOTRAM[1180] = 0x0C; ++ BOOTRAM[1181] = 0xA2; ++ BOOTRAM[1182] = 0x90; ++ BOOTRAM[1183] = 0x81; ++ BOOTRAM[1184] = 0x97; ++ BOOTRAM[1185] = 0xE0; ++ BOOTRAM[1186] = 0xFF; ++ BOOTRAM[1187] = 0x64; ++ BOOTRAM[1188] = 0x10; ++ BOOTRAM[1189] = 0x60; ++ BOOTRAM[1190] = 0x05; ++ BOOTRAM[1191] = 0xEF; ++ BOOTRAM[1192] = 0x64; ++ BOOTRAM[1193] = 0x12; ++ BOOTRAM[1194] = 0x70; ++ BOOTRAM[1195] = 0x29; ++ BOOTRAM[1196] = 0xE4; ++ BOOTRAM[1197] = 0x12; ++ BOOTRAM[1198] = 0x0A; ++ BOOTRAM[1199] = 0x99; ++ BOOTRAM[1200] = 0x90; ++ BOOTRAM[1201] = 0x81; ++ BOOTRAM[1202] = 0x96; ++ BOOTRAM[1203] = 0xE0; ++ BOOTRAM[1204] = 0xFD; ++ BOOTRAM[1205] = 0x7F; ++ BOOTRAM[1206] = 0x02; ++ BOOTRAM[1207] = 0x12; ++ BOOTRAM[1208] = 0x0A; ++ BOOTRAM[1209] = 0x44; ++ BOOTRAM[1210] = 0x7D; ++ BOOTRAM[1211] = 0x01; ++ BOOTRAM[1212] = 0x12; ++ BOOTRAM[1213] = 0x0A; ++ BOOTRAM[1214] = 0x3B; ++ BOOTRAM[1215] = 0x90; ++ BOOTRAM[1216] = 0x19; ++ BOOTRAM[1217] = 0x07; ++ BOOTRAM[1218] = 0x74; ++ BOOTRAM[1219] = 0xFF; ++ BOOTRAM[1220] = 0xF0; ++ BOOTRAM[1221] = 0x7D; ++ BOOTRAM[1222] = 0x01; ++ BOOTRAM[1223] = 0x7F; ++ BOOTRAM[1224] = 0x02; ++ BOOTRAM[1225] = 0x12; ++ BOOTRAM[1226] = 0x0C; ++ BOOTRAM[1227] = 0xFA; ++ BOOTRAM[1228] = 0x1D; ++ BOOTRAM[1229] = 0x7F; ++ BOOTRAM[1230] = 0x04; ++ BOOTRAM[1231] = 0x12; ++ BOOTRAM[1232] = 0x0C; ++ BOOTRAM[1233] = 0xFA; ++ BOOTRAM[1234] = 0x0D; ++ BOOTRAM[1235] = 0x80; ++ BOOTRAM[1236] = 0x2C; ++ BOOTRAM[1237] = 0x90; ++ BOOTRAM[1238] = 0x81; ++ BOOTRAM[1239] = 0x97; ++ BOOTRAM[1240] = 0xE0; ++ BOOTRAM[1241] = 0x64; ++ BOOTRAM[1242] = 0x11; ++ BOOTRAM[1243] = 0x70; ++ BOOTRAM[1244] = 0x2B; ++ BOOTRAM[1245] = 0x12; ++ BOOTRAM[1246] = 0x0A; ++ BOOTRAM[1247] = 0x99; ++ BOOTRAM[1248] = 0x0D; ++ BOOTRAM[1249] = 0x7F; ++ BOOTRAM[1250] = 0x02; ++ BOOTRAM[1251] = 0x12; ++ BOOTRAM[1252] = 0x0A; ++ BOOTRAM[1253] = 0x44; ++ BOOTRAM[1254] = 0x90; ++ BOOTRAM[1255] = 0x81; ++ BOOTRAM[1256] = 0x96; ++ BOOTRAM[1257] = 0xE0; ++ BOOTRAM[1258] = 0xFD; ++ BOOTRAM[1259] = 0x12; ++ BOOTRAM[1260] = 0x0A; ++ BOOTRAM[1261] = 0x3B; ++ BOOTRAM[1262] = 0x90; ++ BOOTRAM[1263] = 0x19; ++ BOOTRAM[1264] = 0x07; ++ BOOTRAM[1265] = 0x74; ++ BOOTRAM[1266] = 0xFF; ++ BOOTRAM[1267] = 0xF0; ++ BOOTRAM[1268] = 0xE4; ++ BOOTRAM[1269] = 0xFD; ++ BOOTRAM[1270] = 0x7F; ++ BOOTRAM[1271] = 0x02; ++ BOOTRAM[1272] = 0x12; ++ BOOTRAM[1273] = 0x0C; ++ BOOTRAM[1274] = 0xFA; ++ BOOTRAM[1275] = 0x0D; ++ BOOTRAM[1276] = 0x7F; ++ BOOTRAM[1277] = 0x04; ++ BOOTRAM[1278] = 0x12; ++ BOOTRAM[1279] = 0x0C; ++ BOOTRAM[1280] = 0xFA; ++ BOOTRAM[1281] = 0x7F; ++ BOOTRAM[1282] = 0x05; ++ BOOTRAM[1283] = 0x12; ++ BOOTRAM[1284] = 0x0C; ++ BOOTRAM[1285] = 0xFA; ++ BOOTRAM[1286] = 0x80; ++ BOOTRAM[1287] = 0x19; ++ BOOTRAM[1288] = 0x7D; ++ BOOTRAM[1289] = 0x01; ++ BOOTRAM[1290] = 0x7F; ++ BOOTRAM[1291] = 0x03; ++ BOOTRAM[1292] = 0x12; ++ BOOTRAM[1293] = 0x0C; ++ BOOTRAM[1294] = 0xA2; ++ BOOTRAM[1295] = 0x1D; ++ BOOTRAM[1296] = 0x7F; ++ BOOTRAM[1297] = 0x04; ++ BOOTRAM[1298] = 0x12; ++ BOOTRAM[1299] = 0x0C; ++ BOOTRAM[1300] = 0xA2; ++ BOOTRAM[1301] = 0x0D; ++ BOOTRAM[1302] = 0x7F; ++ BOOTRAM[1303] = 0x05; ++ BOOTRAM[1304] = 0x12; ++ BOOTRAM[1305] = 0x0C; ++ BOOTRAM[1306] = 0xA2; ++ BOOTRAM[1307] = 0x1D; ++ BOOTRAM[1308] = 0x7F; ++ BOOTRAM[1309] = 0x04; ++ BOOTRAM[1310] = 0x12; ++ BOOTRAM[1311] = 0x0D; ++ BOOTRAM[1312] = 0x52; ++ BOOTRAM[1313] = 0x90; ++ BOOTRAM[1314] = 0x81; ++ BOOTRAM[1315] = 0x97; ++ BOOTRAM[1316] = 0xE0; ++ BOOTRAM[1317] = 0xFF; ++ BOOTRAM[1318] = 0x64; ++ BOOTRAM[1319] = 0x31; ++ BOOTRAM[1320] = 0x60; ++ BOOTRAM[1321] = 0x05; ++ BOOTRAM[1322] = 0xEF; ++ BOOTRAM[1323] = 0x64; ++ BOOTRAM[1324] = 0x30; ++ BOOTRAM[1325] = 0x70; ++ BOOTRAM[1326] = 0x39; ++ BOOTRAM[1327] = 0xE4; ++ BOOTRAM[1328] = 0xFD; ++ BOOTRAM[1329] = 0x7F; ++ BOOTRAM[1330] = 0x02; ++ BOOTRAM[1331] = 0x12; ++ BOOTRAM[1332] = 0x0A; ++ BOOTRAM[1333] = 0xC0; ++ BOOTRAM[1334] = 0x7D; ++ BOOTRAM[1335] = 0x02; ++ BOOTRAM[1336] = 0x7F; ++ BOOTRAM[1337] = 0x02; ++ BOOTRAM[1338] = 0x12; ++ BOOTRAM[1339] = 0x0A; ++ BOOTRAM[1340] = 0x44; ++ BOOTRAM[1341] = 0x7D; ++ BOOTRAM[1342] = 0x20; ++ BOOTRAM[1343] = 0x7F; ++ BOOTRAM[1344] = 0x02; ++ BOOTRAM[1345] = 0x12; ++ BOOTRAM[1346] = 0x0D; ++ BOOTRAM[1347] = 0xA6; ++ BOOTRAM[1348] = 0xE4; ++ BOOTRAM[1349] = 0xFD; ++ BOOTRAM[1350] = 0x0F; ++ BOOTRAM[1351] = 0x12; ++ BOOTRAM[1352] = 0x0A; ++ BOOTRAM[1353] = 0xC0; ++ BOOTRAM[1354] = 0x0D; ++ BOOTRAM[1355] = 0x7F; ++ BOOTRAM[1356] = 0x03; ++ BOOTRAM[1357] = 0x12; ++ BOOTRAM[1358] = 0x0A; ++ BOOTRAM[1359] = 0x44; ++ BOOTRAM[1360] = 0x7D; ++ BOOTRAM[1361] = 0x20; ++ BOOTRAM[1362] = 0x7F; ++ BOOTRAM[1363] = 0x03; ++ BOOTRAM[1364] = 0x12; ++ BOOTRAM[1365] = 0x0D; ++ BOOTRAM[1366] = 0xA6; ++ BOOTRAM[1367] = 0x90; ++ BOOTRAM[1368] = 0x19; ++ BOOTRAM[1369] = 0x07; ++ BOOTRAM[1370] = 0x74; ++ BOOTRAM[1371] = 0xFF; ++ BOOTRAM[1372] = 0xF0; ++ BOOTRAM[1373] = 0x7D; ++ BOOTRAM[1374] = 0x01; ++ BOOTRAM[1375] = 0x1F; ++ BOOTRAM[1376] = 0x12; ++ BOOTRAM[1377] = 0x0C; ++ BOOTRAM[1378] = 0xFA; ++ BOOTRAM[1379] = 0x7F; ++ BOOTRAM[1380] = 0x03; ++ BOOTRAM[1381] = 0x12; ++ BOOTRAM[1382] = 0x0C; ++ BOOTRAM[1383] = 0xFA; ++ BOOTRAM[1384] = 0x22; ++ BOOTRAM[1385] = 0xE4; ++ BOOTRAM[1386] = 0xFF; ++ BOOTRAM[1387] = 0xFE; ++ BOOTRAM[1388] = 0xF9; ++ BOOTRAM[1389] = 0x90; ++ BOOTRAM[1390] = 0x08; ++ BOOTRAM[1391] = 0x04; ++ BOOTRAM[1392] = 0xE0; ++ BOOTRAM[1393] = 0xFD; ++ BOOTRAM[1394] = 0x7C; ++ BOOTRAM[1395] = 0x00; ++ BOOTRAM[1396] = 0x90; ++ BOOTRAM[1397] = 0x08; ++ BOOTRAM[1398] = 0x03; ++ BOOTRAM[1399] = 0xE0; ++ BOOTRAM[1400] = 0xFB; ++ BOOTRAM[1401] = 0x7A; ++ BOOTRAM[1402] = 0x00; ++ BOOTRAM[1403] = 0x20; ++ BOOTRAM[1404] = 0xE7; ++ BOOTRAM[1405] = 0x03; ++ BOOTRAM[1406] = 0x02; ++ BOOTRAM[1407] = 0x06; ++ BOOTRAM[1408] = 0x2D; ++ BOOTRAM[1409] = 0x54; ++ BOOTRAM[1410] = 0x3F; ++ BOOTRAM[1411] = 0x78; ++ BOOTRAM[1412] = 0x02; ++ BOOTRAM[1413] = 0xC3; ++ BOOTRAM[1414] = 0x33; ++ BOOTRAM[1415] = 0xCE; ++ BOOTRAM[1416] = 0x33; ++ BOOTRAM[1417] = 0xCE; ++ BOOTRAM[1418] = 0xD8; ++ BOOTRAM[1419] = 0xF9; ++ BOOTRAM[1420] = 0xFF; ++ BOOTRAM[1421] = 0xED; ++ BOOTRAM[1422] = 0x54; ++ BOOTRAM[1423] = 0x03; ++ BOOTRAM[1424] = 0xFD; ++ BOOTRAM[1425] = 0xEF; ++ BOOTRAM[1426] = 0x4D; ++ BOOTRAM[1427] = 0xFF; ++ BOOTRAM[1428] = 0xC3; ++ BOOTRAM[1429] = 0x94; ++ BOOTRAM[1430] = 0xFC; ++ BOOTRAM[1431] = 0xEE; ++ BOOTRAM[1432] = 0x94; ++ BOOTRAM[1433] = 0x00; ++ BOOTRAM[1434] = 0x50; ++ BOOTRAM[1435] = 0x39; ++ BOOTRAM[1436] = 0x90; ++ BOOTRAM[1437] = 0x08; ++ BOOTRAM[1438] = 0x00; ++ BOOTRAM[1439] = 0x74; ++ BOOTRAM[1440] = 0x03; ++ BOOTRAM[1441] = 0xF0; ++ BOOTRAM[1442] = 0x12; ++ BOOTRAM[1443] = 0x0E; ++ BOOTRAM[1444] = 0xDA; ++ BOOTRAM[1445] = 0xAC; ++ BOOTRAM[1446] = 0x06; ++ BOOTRAM[1447] = 0xAD; ++ BOOTRAM[1448] = 0x07; ++ BOOTRAM[1449] = 0x90; ++ BOOTRAM[1450] = 0x81; ++ BOOTRAM[1451] = 0x4F; ++ BOOTRAM[1452] = 0xE0; ++ BOOTRAM[1453] = 0x25; ++ BOOTRAM[1454] = 0xE0; ++ BOOTRAM[1455] = 0xFF; ++ BOOTRAM[1456] = 0x90; ++ BOOTRAM[1457] = 0x81; ++ BOOTRAM[1458] = 0x4E; ++ BOOTRAM[1459] = 0xE0; ++ BOOTRAM[1460] = 0x33; ++ BOOTRAM[1461] = 0xFE; ++ BOOTRAM[1462] = 0x74; ++ BOOTRAM[1463] = 0x00; ++ BOOTRAM[1464] = 0x2F; ++ BOOTRAM[1465] = 0xF5; ++ BOOTRAM[1466] = 0x82; ++ BOOTRAM[1467] = 0x74; ++ BOOTRAM[1468] = 0x81; ++ BOOTRAM[1469] = 0x3E; ++ BOOTRAM[1470] = 0xF5; ++ BOOTRAM[1471] = 0x83; ++ BOOTRAM[1472] = 0xEC; ++ BOOTRAM[1473] = 0xF0; ++ BOOTRAM[1474] = 0xA3; ++ BOOTRAM[1475] = 0xED; ++ BOOTRAM[1476] = 0xF0; ++ BOOTRAM[1477] = 0x90; ++ BOOTRAM[1478] = 0x81; ++ BOOTRAM[1479] = 0x4F; ++ BOOTRAM[1480] = 0xE0; ++ BOOTRAM[1481] = 0x04; ++ BOOTRAM[1482] = 0xF0; ++ BOOTRAM[1483] = 0x70; ++ BOOTRAM[1484] = 0x06; ++ BOOTRAM[1485] = 0x90; ++ BOOTRAM[1486] = 0x81; ++ BOOTRAM[1487] = 0x4E; ++ BOOTRAM[1488] = 0xE0; ++ BOOTRAM[1489] = 0x04; ++ BOOTRAM[1490] = 0xF0; ++ BOOTRAM[1491] = 0x80; ++ BOOTRAM[1492] = 0x45; ++ BOOTRAM[1493] = 0xC3; ++ BOOTRAM[1494] = 0xEF; ++ BOOTRAM[1495] = 0x94; ++ BOOTRAM[1496] = 0xFC; ++ BOOTRAM[1497] = 0xEE; ++ BOOTRAM[1498] = 0x94; ++ BOOTRAM[1499] = 0x00; ++ BOOTRAM[1500] = 0x40; ++ BOOTRAM[1501] = 0x3C; ++ BOOTRAM[1502] = 0xD3; ++ BOOTRAM[1503] = 0x90; ++ BOOTRAM[1504] = 0x81; ++ BOOTRAM[1505] = 0x4F; ++ BOOTRAM[1506] = 0xE0; ++ BOOTRAM[1507] = 0x94; ++ BOOTRAM[1508] = 0x00; ++ BOOTRAM[1509] = 0x90; ++ BOOTRAM[1510] = 0x81; ++ BOOTRAM[1511] = 0x4E; ++ BOOTRAM[1512] = 0xE0; ++ BOOTRAM[1513] = 0x94; ++ BOOTRAM[1514] = 0x00; ++ BOOTRAM[1515] = 0x40; ++ BOOTRAM[1516] = 0x2D; ++ BOOTRAM[1517] = 0x90; ++ BOOTRAM[1518] = 0x08; ++ BOOTRAM[1519] = 0x00; ++ BOOTRAM[1520] = 0x74; ++ BOOTRAM[1521] = 0x02; ++ BOOTRAM[1522] = 0xF0; ++ BOOTRAM[1523] = 0x7B; ++ BOOTRAM[1524] = 0x01; ++ BOOTRAM[1525] = 0x7A; ++ BOOTRAM[1526] = 0x81; ++ BOOTRAM[1527] = 0x79; ++ BOOTRAM[1528] = 0x7E; ++ BOOTRAM[1529] = 0x12; ++ BOOTRAM[1530] = 0x00; ++ BOOTRAM[1531] = 0x06; ++ BOOTRAM[1532] = 0xA9; ++ BOOTRAM[1533] = 0x07; ++ BOOTRAM[1534] = 0xE9; ++ BOOTRAM[1535] = 0x60; ++ BOOTRAM[1536] = 0x12; ++ BOOTRAM[1537] = 0x90; ++ BOOTRAM[1538] = 0x81; ++ BOOTRAM[1539] = 0x7E; ++ BOOTRAM[1540] = 0xE0; ++ BOOTRAM[1541] = 0xFE; ++ BOOTRAM[1542] = 0xA3; ++ BOOTRAM[1543] = 0xE0; ++ BOOTRAM[1544] = 0xFF; ++ BOOTRAM[1545] = 0xAD; ++ BOOTRAM[1546] = 0x01; ++ BOOTRAM[1547] = 0x12; ++ BOOTRAM[1548] = 0x0C; ++ BOOTRAM[1549] = 0x16; ++ BOOTRAM[1550] = 0x7E; ++ BOOTRAM[1551] = 0x00; ++ BOOTRAM[1552] = 0x12; ++ BOOTRAM[1553] = 0x0A; ++ BOOTRAM[1554] = 0xEC; ++ BOOTRAM[1555] = 0xE4; ++ BOOTRAM[1556] = 0x90; ++ BOOTRAM[1557] = 0x81; ++ BOOTRAM[1558] = 0x4E; ++ BOOTRAM[1559] = 0xF0; ++ BOOTRAM[1560] = 0xA3; ++ BOOTRAM[1561] = 0xF0; ++ BOOTRAM[1562] = 0xC3; ++ BOOTRAM[1563] = 0x90; ++ BOOTRAM[1564] = 0x81; ++ BOOTRAM[1565] = 0x4F; ++ BOOTRAM[1566] = 0xE0; ++ BOOTRAM[1567] = 0x94; ++ BOOTRAM[1568] = 0x27; ++ BOOTRAM[1569] = 0x90; ++ BOOTRAM[1570] = 0x81; ++ BOOTRAM[1571] = 0x4E; ++ BOOTRAM[1572] = 0xE0; ++ BOOTRAM[1573] = 0x94; ++ BOOTRAM[1574] = 0x00; ++ BOOTRAM[1575] = 0x40; ++ BOOTRAM[1576] = 0x04; ++ BOOTRAM[1577] = 0xE4; ++ BOOTRAM[1578] = 0xF0; ++ BOOTRAM[1579] = 0xA3; ++ BOOTRAM[1580] = 0xF0; ++ BOOTRAM[1581] = 0x22; ++ BOOTRAM[1582] = 0x90; ++ BOOTRAM[1583] = 0x81; ++ BOOTRAM[1584] = 0x82; ++ BOOTRAM[1585] = 0xEE; ++ BOOTRAM[1586] = 0xF0; ++ BOOTRAM[1587] = 0xA3; ++ BOOTRAM[1588] = 0xEF; ++ BOOTRAM[1589] = 0xF0; ++ BOOTRAM[1590] = 0xA3; ++ BOOTRAM[1591] = 0xEC; ++ BOOTRAM[1592] = 0xF0; ++ BOOTRAM[1593] = 0xA3; ++ BOOTRAM[1594] = 0xED; ++ BOOTRAM[1595] = 0xF0; ++ BOOTRAM[1596] = 0x90; ++ BOOTRAM[1597] = 0x81; ++ BOOTRAM[1598] = 0x91; ++ BOOTRAM[1599] = 0x74; ++ BOOTRAM[1600] = 0x01; ++ BOOTRAM[1601] = 0xF0; ++ BOOTRAM[1602] = 0xA3; ++ BOOTRAM[1603] = 0x74; ++ BOOTRAM[1604] = 0x81; ++ BOOTRAM[1605] = 0xF0; ++ BOOTRAM[1606] = 0xA3; ++ BOOTRAM[1607] = 0x74; ++ BOOTRAM[1608] = 0x88; ++ BOOTRAM[1609] = 0xF0; ++ BOOTRAM[1610] = 0x7B; ++ BOOTRAM[1611] = 0x01; ++ BOOTRAM[1612] = 0x7A; ++ BOOTRAM[1613] = 0x81; ++ BOOTRAM[1614] = 0x79; ++ BOOTRAM[1615] = 0x86; ++ BOOTRAM[1616] = 0x12; ++ BOOTRAM[1617] = 0x0D; ++ BOOTRAM[1618] = 0x7D; ++ BOOTRAM[1619] = 0x90; ++ BOOTRAM[1620] = 0x81; ++ BOOTRAM[1621] = 0x91; ++ BOOTRAM[1622] = 0x74; ++ BOOTRAM[1623] = 0x01; ++ BOOTRAM[1624] = 0xF0; ++ BOOTRAM[1625] = 0xA3; ++ BOOTRAM[1626] = 0x74; ++ BOOTRAM[1627] = 0x81; ++ BOOTRAM[1628] = 0xF0; ++ BOOTRAM[1629] = 0xA3; ++ BOOTRAM[1630] = 0x74; ++ BOOTRAM[1631] = 0x8C; ++ BOOTRAM[1632] = 0xF0; ++ BOOTRAM[1633] = 0x7B; ++ BOOTRAM[1634] = 0x01; ++ BOOTRAM[1635] = 0x7A; ++ BOOTRAM[1636] = 0x81; ++ BOOTRAM[1637] = 0x79; ++ BOOTRAM[1638] = 0x8A; ++ BOOTRAM[1639] = 0x12; ++ BOOTRAM[1640] = 0x0D; ++ BOOTRAM[1641] = 0x7D; ++ BOOTRAM[1642] = 0x90; ++ BOOTRAM[1643] = 0x81; ++ BOOTRAM[1644] = 0x88; ++ BOOTRAM[1645] = 0xE0; ++ BOOTRAM[1646] = 0xFE; ++ BOOTRAM[1647] = 0xA3; ++ BOOTRAM[1648] = 0xE0; ++ BOOTRAM[1649] = 0xFF; ++ BOOTRAM[1650] = 0xC3; ++ BOOTRAM[1651] = 0x90; ++ BOOTRAM[1652] = 0x81; ++ BOOTRAM[1653] = 0x8D; ++ BOOTRAM[1654] = 0xE0; ++ BOOTRAM[1655] = 0x9F; ++ BOOTRAM[1656] = 0xFF; ++ BOOTRAM[1657] = 0x90; ++ BOOTRAM[1658] = 0x81; ++ BOOTRAM[1659] = 0x8C; ++ BOOTRAM[1660] = 0xE0; ++ BOOTRAM[1661] = 0x9E; ++ BOOTRAM[1662] = 0xFE; ++ BOOTRAM[1663] = 0xD3; ++ BOOTRAM[1664] = 0x90; ++ BOOTRAM[1665] = 0x81; ++ BOOTRAM[1666] = 0x85; ++ BOOTRAM[1667] = 0xE0; ++ BOOTRAM[1668] = 0x9F; ++ BOOTRAM[1669] = 0x90; ++ BOOTRAM[1670] = 0x81; ++ BOOTRAM[1671] = 0x84; ++ BOOTRAM[1672] = 0xE0; ++ BOOTRAM[1673] = 0x9E; ++ BOOTRAM[1674] = 0x50; ++ BOOTRAM[1675] = 0xC7; ++ BOOTRAM[1676] = 0x90; ++ BOOTRAM[1677] = 0x81; ++ BOOTRAM[1678] = 0x86; ++ BOOTRAM[1679] = 0xE0; ++ BOOTRAM[1680] = 0xFE; ++ BOOTRAM[1681] = 0xA3; ++ BOOTRAM[1682] = 0xE0; ++ BOOTRAM[1683] = 0xFF; ++ BOOTRAM[1684] = 0x90; ++ BOOTRAM[1685] = 0x81; ++ BOOTRAM[1686] = 0x8A; ++ BOOTRAM[1687] = 0xE0; ++ BOOTRAM[1688] = 0xFC; ++ BOOTRAM[1689] = 0xA3; ++ BOOTRAM[1690] = 0xE0; ++ BOOTRAM[1691] = 0xFD; ++ BOOTRAM[1692] = 0xC3; ++ BOOTRAM[1693] = 0x9F; ++ BOOTRAM[1694] = 0xFF; ++ BOOTRAM[1695] = 0xEC; ++ BOOTRAM[1696] = 0x9E; ++ BOOTRAM[1697] = 0xFE; ++ BOOTRAM[1698] = 0xD3; ++ BOOTRAM[1699] = 0x90; ++ BOOTRAM[1700] = 0x81; ++ BOOTRAM[1701] = 0x83; ++ BOOTRAM[1702] = 0xE0; ++ BOOTRAM[1703] = 0x9F; ++ BOOTRAM[1704] = 0x90; ++ BOOTRAM[1705] = 0x81; ++ BOOTRAM[1706] = 0x82; ++ BOOTRAM[1707] = 0xE0; ++ BOOTRAM[1708] = 0x9E; ++ BOOTRAM[1709] = 0x40; ++ BOOTRAM[1710] = 0x3F; ++ BOOTRAM[1711] = 0x90; ++ BOOTRAM[1712] = 0x81; ++ BOOTRAM[1713] = 0x86; ++ BOOTRAM[1714] = 0xE0; ++ BOOTRAM[1715] = 0xFE; ++ BOOTRAM[1716] = 0xA3; ++ BOOTRAM[1717] = 0xE0; ++ BOOTRAM[1718] = 0xFF; ++ BOOTRAM[1719] = 0xC3; ++ BOOTRAM[1720] = 0xED; ++ BOOTRAM[1721] = 0x9F; ++ BOOTRAM[1722] = 0xEC; ++ BOOTRAM[1723] = 0x9E; ++ BOOTRAM[1724] = 0x50; ++ BOOTRAM[1725] = 0x95; ++ BOOTRAM[1726] = 0x90; ++ BOOTRAM[1727] = 0x81; ++ BOOTRAM[1728] = 0x8A; ++ BOOTRAM[1729] = 0xE0; ++ BOOTRAM[1730] = 0xFE; ++ BOOTRAM[1731] = 0xA3; ++ BOOTRAM[1732] = 0xE0; ++ BOOTRAM[1733] = 0xFF; ++ BOOTRAM[1734] = 0xC3; ++ BOOTRAM[1735] = 0x90; ++ BOOTRAM[1736] = 0x81; ++ BOOTRAM[1737] = 0x87; ++ BOOTRAM[1738] = 0xE0; ++ BOOTRAM[1739] = 0x9F; ++ BOOTRAM[1740] = 0xFF; ++ BOOTRAM[1741] = 0x90; ++ BOOTRAM[1742] = 0x81; ++ BOOTRAM[1743] = 0x86; ++ BOOTRAM[1744] = 0xE0; ++ BOOTRAM[1745] = 0x9E; ++ BOOTRAM[1746] = 0xFE; ++ BOOTRAM[1747] = 0x90; ++ BOOTRAM[1748] = 0x81; ++ BOOTRAM[1749] = 0x82; ++ BOOTRAM[1750] = 0xE0; ++ BOOTRAM[1751] = 0xFC; ++ BOOTRAM[1752] = 0xA3; ++ BOOTRAM[1753] = 0xE0; ++ BOOTRAM[1754] = 0xFD; ++ BOOTRAM[1755] = 0xC3; ++ BOOTRAM[1756] = 0x74; ++ BOOTRAM[1757] = 0xFF; ++ BOOTRAM[1758] = 0x9D; ++ BOOTRAM[1759] = 0xFD; ++ BOOTRAM[1760] = 0x74; ++ BOOTRAM[1761] = 0xFF; ++ BOOTRAM[1762] = 0x9C; ++ BOOTRAM[1763] = 0xFC; ++ BOOTRAM[1764] = 0xC3; ++ BOOTRAM[1765] = 0xED; ++ BOOTRAM[1766] = 0x9F; ++ BOOTRAM[1767] = 0xEC; ++ BOOTRAM[1768] = 0x9E; ++ BOOTRAM[1769] = 0x50; ++ BOOTRAM[1770] = 0x03; ++ BOOTRAM[1771] = 0x02; ++ BOOTRAM[1772] = 0x06; ++ BOOTRAM[1773] = 0x53; ++ BOOTRAM[1774] = 0x22; ++ BOOTRAM[1775] = 0x90; ++ BOOTRAM[1776] = 0x19; ++ BOOTRAM[1777] = 0x06; ++ BOOTRAM[1778] = 0xE0; ++ BOOTRAM[1779] = 0x90; ++ BOOTRAM[1780] = 0x81; ++ BOOTRAM[1781] = 0x7E; ++ BOOTRAM[1782] = 0xF0; ++ BOOTRAM[1783] = 0xE0; ++ BOOTRAM[1784] = 0xFF; ++ BOOTRAM[1785] = 0x90; ++ BOOTRAM[1786] = 0x19; ++ BOOTRAM[1787] = 0x07; ++ BOOTRAM[1788] = 0xF0; ++ BOOTRAM[1789] = 0xEF; ++ BOOTRAM[1790] = 0x30; ++ BOOTRAM[1791] = 0xE2; ++ BOOTRAM[1792] = 0x41; ++ BOOTRAM[1793] = 0x90; ++ BOOTRAM[1794] = 0x81; ++ BOOTRAM[1795] = 0x97; ++ BOOTRAM[1796] = 0xE0; ++ BOOTRAM[1797] = 0xFF; ++ BOOTRAM[1798] = 0x64; ++ BOOTRAM[1799] = 0x10; ++ BOOTRAM[1800] = 0x60; ++ BOOTRAM[1801] = 0x0A; ++ BOOTRAM[1802] = 0xEF; ++ BOOTRAM[1803] = 0x64; ++ BOOTRAM[1804] = 0x11; ++ BOOTRAM[1805] = 0x60; ++ BOOTRAM[1806] = 0x05; ++ BOOTRAM[1807] = 0xEF; ++ BOOTRAM[1808] = 0x64; ++ BOOTRAM[1809] = 0x12; ++ BOOTRAM[1810] = 0x70; ++ BOOTRAM[1811] = 0x19; ++ BOOTRAM[1812] = 0xEF; ++ BOOTRAM[1813] = 0xB4; ++ BOOTRAM[1814] = 0x12; ++ BOOTRAM[1815] = 0x11; ++ BOOTRAM[1816] = 0x7F; ++ BOOTRAM[1817] = 0x04; ++ BOOTRAM[1818] = 0x12; ++ BOOTRAM[1819] = 0x0D; ++ BOOTRAM[1820] = 0x26; ++ BOOTRAM[1821] = 0x90; ++ BOOTRAM[1822] = 0x81; ++ BOOTRAM[1823] = 0x94; ++ BOOTRAM[1824] = 0xE0; ++ BOOTRAM[1825] = 0x6F; ++ BOOTRAM[1826] = 0x70; ++ BOOTRAM[1827] = 0x01; ++ BOOTRAM[1828] = 0xEE; ++ BOOTRAM[1829] = 0x70; ++ BOOTRAM[1830] = 0x1B; ++ BOOTRAM[1831] = 0x80; ++ BOOTRAM[1832] = 0x00; ++ BOOTRAM[1833] = 0x7F; ++ BOOTRAM[1834] = 0x02; ++ BOOTRAM[1835] = 0x80; ++ BOOTRAM[1836] = 0x12; ++ BOOTRAM[1837] = 0x90; ++ BOOTRAM[1838] = 0x81; ++ BOOTRAM[1839] = 0x97; ++ BOOTRAM[1840] = 0xE0; ++ BOOTRAM[1841] = 0xFF; ++ BOOTRAM[1842] = 0x64; ++ BOOTRAM[1843] = 0x31; ++ BOOTRAM[1844] = 0x60; ++ BOOTRAM[1845] = 0x04; ++ BOOTRAM[1846] = 0xEF; ++ BOOTRAM[1847] = 0xB4; ++ BOOTRAM[1848] = 0x30; ++ BOOTRAM[1849] = 0x08; ++ BOOTRAM[1850] = 0x7F; ++ BOOTRAM[1851] = 0x02; ++ BOOTRAM[1852] = 0x12; ++ BOOTRAM[1853] = 0x0D; ++ BOOTRAM[1854] = 0x26; ++ BOOTRAM[1855] = 0x12; ++ BOOTRAM[1856] = 0x0E; ++ BOOTRAM[1857] = 0x8B; ++ BOOTRAM[1858] = 0x90; ++ BOOTRAM[1859] = 0x81; ++ BOOTRAM[1860] = 0x7E; ++ BOOTRAM[1861] = 0xE0; ++ BOOTRAM[1862] = 0x30; ++ BOOTRAM[1863] = 0xE3; ++ BOOTRAM[1864] = 0x13; ++ BOOTRAM[1865] = 0x90; ++ BOOTRAM[1866] = 0x81; ++ BOOTRAM[1867] = 0x97; ++ BOOTRAM[1868] = 0xE0; ++ BOOTRAM[1869] = 0xFF; ++ BOOTRAM[1870] = 0x64; ++ BOOTRAM[1871] = 0x31; ++ BOOTRAM[1872] = 0x60; ++ BOOTRAM[1873] = 0x04; ++ BOOTRAM[1874] = 0xEF; ++ BOOTRAM[1875] = 0xB4; ++ BOOTRAM[1876] = 0x30; ++ BOOTRAM[1877] = 0x06; ++ BOOTRAM[1878] = 0x12; ++ BOOTRAM[1879] = 0x0E; ++ BOOTRAM[1880] = 0xCA; ++ BOOTRAM[1881] = 0x12; ++ BOOTRAM[1882] = 0x0E; ++ BOOTRAM[1883] = 0xD2; ++ BOOTRAM[1884] = 0x90; ++ BOOTRAM[1885] = 0x81; ++ BOOTRAM[1886] = 0x7E; ++ BOOTRAM[1887] = 0xE0; ++ BOOTRAM[1888] = 0x30; ++ BOOTRAM[1889] = 0xE4; ++ BOOTRAM[1890] = 0x17; ++ BOOTRAM[1891] = 0x90; ++ BOOTRAM[1892] = 0x81; ++ BOOTRAM[1893] = 0x97; ++ BOOTRAM[1894] = 0xE0; ++ BOOTRAM[1895] = 0xFF; ++ BOOTRAM[1896] = 0x64; ++ BOOTRAM[1897] = 0x10; ++ BOOTRAM[1898] = 0x60; ++ BOOTRAM[1899] = 0x09; ++ BOOTRAM[1900] = 0xEF; ++ BOOTRAM[1901] = 0x64; ++ BOOTRAM[1902] = 0x11; ++ BOOTRAM[1903] = 0x60; ++ BOOTRAM[1904] = 0x04; ++ BOOTRAM[1905] = 0xEF; ++ BOOTRAM[1906] = 0xB4; ++ BOOTRAM[1907] = 0x12; ++ BOOTRAM[1908] = 0x05; ++ BOOTRAM[1909] = 0x7F; ++ BOOTRAM[1910] = 0x04; ++ BOOTRAM[1911] = 0x12; ++ BOOTRAM[1912] = 0x0E; ++ BOOTRAM[1913] = 0x8B; ++ BOOTRAM[1914] = 0x90; ++ BOOTRAM[1915] = 0x81; ++ BOOTRAM[1916] = 0x7E; ++ BOOTRAM[1917] = 0xE0; ++ BOOTRAM[1918] = 0x30; ++ BOOTRAM[1919] = 0xE5; ++ BOOTRAM[1920] = 0x17; ++ BOOTRAM[1921] = 0x90; ++ BOOTRAM[1922] = 0x81; ++ BOOTRAM[1923] = 0x97; ++ BOOTRAM[1924] = 0xE0; ++ BOOTRAM[1925] = 0xFF; ++ BOOTRAM[1926] = 0x64; ++ BOOTRAM[1927] = 0x10; ++ BOOTRAM[1928] = 0x60; ++ BOOTRAM[1929] = 0x09; ++ BOOTRAM[1930] = 0xEF; ++ BOOTRAM[1931] = 0x64; ++ BOOTRAM[1932] = 0x11; ++ BOOTRAM[1933] = 0x60; ++ BOOTRAM[1934] = 0x04; ++ BOOTRAM[1935] = 0xEF; ++ BOOTRAM[1936] = 0xB4; ++ BOOTRAM[1937] = 0x12; ++ BOOTRAM[1938] = 0x05; ++ BOOTRAM[1939] = 0x7F; ++ BOOTRAM[1940] = 0x05; ++ BOOTRAM[1941] = 0x12; ++ BOOTRAM[1942] = 0x0E; ++ BOOTRAM[1943] = 0x8B; ++ BOOTRAM[1944] = 0x22; ++ BOOTRAM[1945] = 0x90; ++ BOOTRAM[1946] = 0x81; ++ BOOTRAM[1947] = 0x68; ++ BOOTRAM[1948] = 0x74; ++ BOOTRAM[1949] = 0x01; ++ BOOTRAM[1950] = 0xF0; ++ BOOTRAM[1951] = 0xE4; ++ BOOTRAM[1952] = 0xA3; ++ BOOTRAM[1953] = 0xF0; ++ BOOTRAM[1954] = 0xA3; ++ BOOTRAM[1955] = 0xF0; ++ BOOTRAM[1956] = 0x90; ++ BOOTRAM[1957] = 0x37; ++ BOOTRAM[1958] = 0x00; ++ BOOTRAM[1959] = 0xF0; ++ BOOTRAM[1960] = 0x12; ++ BOOTRAM[1961] = 0x0E; ++ BOOTRAM[1962] = 0xC2; ++ BOOTRAM[1963] = 0x90; ++ BOOTRAM[1964] = 0x28; ++ BOOTRAM[1965] = 0x17; ++ BOOTRAM[1966] = 0xE0; ++ BOOTRAM[1967] = 0x90; ++ BOOTRAM[1968] = 0x81; ++ BOOTRAM[1969] = 0x97; ++ BOOTRAM[1970] = 0xF0; ++ BOOTRAM[1971] = 0xE0; ++ BOOTRAM[1972] = 0xFF; ++ BOOTRAM[1973] = 0x64; ++ BOOTRAM[1974] = 0x10; ++ BOOTRAM[1975] = 0x60; ++ BOOTRAM[1976] = 0x1C; ++ BOOTRAM[1977] = 0xEF; ++ BOOTRAM[1978] = 0x64; ++ BOOTRAM[1979] = 0x11; ++ BOOTRAM[1980] = 0x60; ++ BOOTRAM[1981] = 0x17; ++ BOOTRAM[1982] = 0xEF; ++ BOOTRAM[1983] = 0x64; ++ BOOTRAM[1984] = 0x12; ++ BOOTRAM[1985] = 0x60; ++ BOOTRAM[1986] = 0x12; ++ BOOTRAM[1987] = 0xEF; ++ BOOTRAM[1988] = 0x64; ++ BOOTRAM[1989] = 0x20; ++ BOOTRAM[1990] = 0x60; ++ BOOTRAM[1991] = 0x0D; ++ BOOTRAM[1992] = 0xEF; ++ BOOTRAM[1993] = 0x64; ++ BOOTRAM[1994] = 0x31; ++ BOOTRAM[1995] = 0x60; ++ BOOTRAM[1996] = 0x08; ++ BOOTRAM[1997] = 0xEF; ++ BOOTRAM[1998] = 0x64; ++ BOOTRAM[1999] = 0x30; ++ BOOTRAM[2000] = 0x60; ++ BOOTRAM[2001] = 0x03; ++ BOOTRAM[2002] = 0x74; ++ BOOTRAM[2003] = 0x20; ++ BOOTRAM[2004] = 0xF0; ++ BOOTRAM[2005] = 0x90; ++ BOOTRAM[2006] = 0x81; ++ BOOTRAM[2007] = 0x97; ++ BOOTRAM[2008] = 0xE0; ++ BOOTRAM[2009] = 0xFF; ++ BOOTRAM[2010] = 0x64; ++ BOOTRAM[2011] = 0x10; ++ BOOTRAM[2012] = 0x60; ++ BOOTRAM[2013] = 0x0A; ++ BOOTRAM[2014] = 0xEF; ++ BOOTRAM[2015] = 0x64; ++ BOOTRAM[2016] = 0x11; ++ BOOTRAM[2017] = 0x60; ++ BOOTRAM[2018] = 0x05; ++ BOOTRAM[2019] = 0xEF; ++ BOOTRAM[2020] = 0x64; ++ BOOTRAM[2021] = 0x12; ++ BOOTRAM[2022] = 0x70; ++ BOOTRAM[2023] = 0x2B; ++ BOOTRAM[2024] = 0x90; ++ BOOTRAM[2025] = 0x28; ++ BOOTRAM[2026] = 0x18; ++ BOOTRAM[2027] = 0xE0; ++ BOOTRAM[2028] = 0x90; ++ BOOTRAM[2029] = 0x81; ++ BOOTRAM[2030] = 0x96; ++ BOOTRAM[2031] = 0xF0; ++ BOOTRAM[2032] = 0xE0; ++ BOOTRAM[2033] = 0xFF; ++ BOOTRAM[2034] = 0x64; ++ BOOTRAM[2035] = 0x01; ++ BOOTRAM[2036] = 0x60; ++ BOOTRAM[2037] = 0x0A; ++ BOOTRAM[2038] = 0xEF; ++ BOOTRAM[2039] = 0x60; ++ BOOTRAM[2040] = 0x07; ++ BOOTRAM[2041] = 0x64; ++ BOOTRAM[2042] = 0x02; ++ BOOTRAM[2043] = 0x60; ++ BOOTRAM[2044] = 0x03; ++ BOOTRAM[2045] = 0x74; ++ BOOTRAM[2046] = 0x01; ++ BOOTRAM[2047] = 0xF0; ++ BOOTRAM[2048] = 0x90; ++ BOOTRAM[2049] = 0x28; ++ BOOTRAM[2050] = 0x19; ++ BOOTRAM[2051] = 0xE0; ++ BOOTRAM[2052] = 0x90; ++ BOOTRAM[2053] = 0x81; ++ BOOTRAM[2054] = 0x94; ++ BOOTRAM[2055] = 0xF0; ++ BOOTRAM[2056] = 0xE0; ++ BOOTRAM[2057] = 0xFF; ++ BOOTRAM[2058] = 0x60; ++ BOOTRAM[2059] = 0x07; ++ BOOTRAM[2060] = 0x64; ++ BOOTRAM[2061] = 0x01; ++ BOOTRAM[2062] = 0x60; ++ BOOTRAM[2063] = 0x03; ++ BOOTRAM[2064] = 0x74; ++ BOOTRAM[2065] = 0x01; ++ BOOTRAM[2066] = 0xF0; ++ BOOTRAM[2067] = 0xD2; ++ BOOTRAM[2068] = 0xAF; ++ BOOTRAM[2069] = 0xD2; ++ BOOTRAM[2070] = 0xA8; ++ BOOTRAM[2071] = 0xC2; ++ BOOTRAM[2072] = 0x88; ++ BOOTRAM[2073] = 0x12; ++ BOOTRAM[2074] = 0x0E; ++ BOOTRAM[2075] = 0x29; ++ BOOTRAM[2076] = 0x12; ++ BOOTRAM[2077] = 0x0E; ++ BOOTRAM[2078] = 0x5A; ++ BOOTRAM[2079] = 0x12; ++ BOOTRAM[2080] = 0x0E; ++ BOOTRAM[2081] = 0x3A; ++ BOOTRAM[2082] = 0x90; ++ BOOTRAM[2083] = 0x81; ++ BOOTRAM[2084] = 0x97; ++ BOOTRAM[2085] = 0xE0; ++ BOOTRAM[2086] = 0x64; ++ BOOTRAM[2087] = 0x31; ++ BOOTRAM[2088] = 0x60; ++ BOOTRAM[2089] = 0x03; ++ BOOTRAM[2090] = 0x12; ++ BOOTRAM[2091] = 0x0B; ++ BOOTRAM[2092] = 0x8C; ++ BOOTRAM[2093] = 0x90; ++ BOOTRAM[2094] = 0x37; ++ BOOTRAM[2095] = 0x00; ++ BOOTRAM[2096] = 0x74; ++ BOOTRAM[2097] = 0x0B; ++ BOOTRAM[2098] = 0xF0; ++ BOOTRAM[2099] = 0x7D; ++ BOOTRAM[2100] = 0x07; ++ BOOTRAM[2101] = 0x7C; ++ BOOTRAM[2102] = 0x00; ++ BOOTRAM[2103] = 0x7F; ++ BOOTRAM[2104] = 0x20; ++ BOOTRAM[2105] = 0x7E; ++ BOOTRAM[2106] = 0xA1; ++ BOOTRAM[2107] = 0x12; ++ BOOTRAM[2108] = 0x06; ++ BOOTRAM[2109] = 0x2E; ++ BOOTRAM[2110] = 0x80; ++ BOOTRAM[2111] = 0xF3; ++ BOOTRAM[2112] = 0x78; ++ BOOTRAM[2113] = 0x7F; ++ BOOTRAM[2114] = 0xE4; ++ BOOTRAM[2115] = 0xF6; ++ BOOTRAM[2116] = 0xD8; ++ BOOTRAM[2117] = 0xFD; ++ BOOTRAM[2118] = 0x75; ++ BOOTRAM[2119] = 0x81; ++ BOOTRAM[2120] = 0x07; ++ BOOTRAM[2121] = 0x02; ++ BOOTRAM[2122] = 0x08; ++ BOOTRAM[2123] = 0x87; ++ BOOTRAM[2124] = 0x02; ++ BOOTRAM[2125] = 0x07; ++ BOOTRAM[2126] = 0x99; ++ BOOTRAM[2127] = 0xE4; ++ BOOTRAM[2128] = 0x93; ++ BOOTRAM[2129] = 0xA3; ++ BOOTRAM[2130] = 0xF8; ++ BOOTRAM[2131] = 0xE4; ++ BOOTRAM[2132] = 0x93; ++ BOOTRAM[2133] = 0xA3; ++ BOOTRAM[2134] = 0x40; ++ BOOTRAM[2135] = 0x03; ++ BOOTRAM[2136] = 0xF6; ++ BOOTRAM[2137] = 0x80; ++ BOOTRAM[2138] = 0x01; ++ BOOTRAM[2139] = 0xF2; ++ BOOTRAM[2140] = 0x08; ++ BOOTRAM[2141] = 0xDF; ++ BOOTRAM[2142] = 0xF4; ++ BOOTRAM[2143] = 0x80; ++ BOOTRAM[2144] = 0x29; ++ BOOTRAM[2145] = 0xE4; ++ BOOTRAM[2146] = 0x93; ++ BOOTRAM[2147] = 0xA3; ++ BOOTRAM[2148] = 0xF8; ++ BOOTRAM[2149] = 0x54; ++ BOOTRAM[2150] = 0x07; ++ BOOTRAM[2151] = 0x24; ++ BOOTRAM[2152] = 0x0C; ++ BOOTRAM[2153] = 0xC8; ++ BOOTRAM[2154] = 0xC3; ++ BOOTRAM[2155] = 0x33; ++ BOOTRAM[2156] = 0xC4; ++ BOOTRAM[2157] = 0x54; ++ BOOTRAM[2158] = 0x0F; ++ BOOTRAM[2159] = 0x44; ++ BOOTRAM[2160] = 0x20; ++ BOOTRAM[2161] = 0xC8; ++ BOOTRAM[2162] = 0x83; ++ BOOTRAM[2163] = 0x40; ++ BOOTRAM[2164] = 0x04; ++ BOOTRAM[2165] = 0xF4; ++ BOOTRAM[2166] = 0x56; ++ BOOTRAM[2167] = 0x80; ++ BOOTRAM[2168] = 0x01; ++ BOOTRAM[2169] = 0x46; ++ BOOTRAM[2170] = 0xF6; ++ BOOTRAM[2171] = 0xDF; ++ BOOTRAM[2172] = 0xE4; ++ BOOTRAM[2173] = 0x80; ++ BOOTRAM[2174] = 0x0B; ++ BOOTRAM[2175] = 0x01; ++ BOOTRAM[2176] = 0x02; ++ BOOTRAM[2177] = 0x04; ++ BOOTRAM[2178] = 0x08; ++ BOOTRAM[2179] = 0x10; ++ BOOTRAM[2180] = 0x20; ++ BOOTRAM[2181] = 0x40; ++ BOOTRAM[2182] = 0x80; ++ BOOTRAM[2183] = 0x90; ++ BOOTRAM[2184] = 0x08; ++ BOOTRAM[2185] = 0xCC; ++ BOOTRAM[2186] = 0xE4; ++ BOOTRAM[2187] = 0x7E; ++ BOOTRAM[2188] = 0x01; ++ BOOTRAM[2189] = 0x93; ++ BOOTRAM[2190] = 0x60; ++ BOOTRAM[2191] = 0xBC; ++ BOOTRAM[2192] = 0xA3; ++ BOOTRAM[2193] = 0xFF; ++ BOOTRAM[2194] = 0x54; ++ BOOTRAM[2195] = 0x3F; ++ BOOTRAM[2196] = 0x30; ++ BOOTRAM[2197] = 0xE5; ++ BOOTRAM[2198] = 0x09; ++ BOOTRAM[2199] = 0x54; ++ BOOTRAM[2200] = 0x1F; ++ BOOTRAM[2201] = 0xFE; ++ BOOTRAM[2202] = 0xE4; ++ BOOTRAM[2203] = 0x93; ++ BOOTRAM[2204] = 0xA3; ++ BOOTRAM[2205] = 0x60; ++ BOOTRAM[2206] = 0x01; ++ BOOTRAM[2207] = 0x0E; ++ BOOTRAM[2208] = 0xCF; ++ BOOTRAM[2209] = 0x54; ++ BOOTRAM[2210] = 0xC0; ++ BOOTRAM[2211] = 0x25; ++ BOOTRAM[2212] = 0xE0; ++ BOOTRAM[2213] = 0x60; ++ BOOTRAM[2214] = 0xA8; ++ BOOTRAM[2215] = 0x40; ++ BOOTRAM[2216] = 0xB8; ++ BOOTRAM[2217] = 0xE4; ++ BOOTRAM[2218] = 0x93; ++ BOOTRAM[2219] = 0xA3; ++ BOOTRAM[2220] = 0xFA; ++ BOOTRAM[2221] = 0xE4; ++ BOOTRAM[2222] = 0x93; ++ BOOTRAM[2223] = 0xA3; ++ BOOTRAM[2224] = 0xF8; ++ BOOTRAM[2225] = 0xE4; ++ BOOTRAM[2226] = 0x93; ++ BOOTRAM[2227] = 0xA3; ++ BOOTRAM[2228] = 0xC8; ++ BOOTRAM[2229] = 0xC5; ++ BOOTRAM[2230] = 0x82; ++ BOOTRAM[2231] = 0xC8; ++ BOOTRAM[2232] = 0xCA; ++ BOOTRAM[2233] = 0xC5; ++ BOOTRAM[2234] = 0x83; ++ BOOTRAM[2235] = 0xCA; ++ BOOTRAM[2236] = 0xF0; ++ BOOTRAM[2237] = 0xA3; ++ BOOTRAM[2238] = 0xC8; ++ BOOTRAM[2239] = 0xC5; ++ BOOTRAM[2240] = 0x82; ++ BOOTRAM[2241] = 0xC8; ++ BOOTRAM[2242] = 0xCA; ++ BOOTRAM[2243] = 0xC5; ++ BOOTRAM[2244] = 0x83; ++ BOOTRAM[2245] = 0xCA; ++ BOOTRAM[2246] = 0xDF; ++ BOOTRAM[2247] = 0xE9; ++ BOOTRAM[2248] = 0xDE; ++ BOOTRAM[2249] = 0xE7; ++ BOOTRAM[2250] = 0x80; ++ BOOTRAM[2251] = 0xBE; ++ BOOTRAM[2252] = 0x41; ++ BOOTRAM[2253] = 0x81; ++ BOOTRAM[2254] = 0x97; ++ BOOTRAM[2255] = 0x00; ++ BOOTRAM[2256] = 0x41; ++ BOOTRAM[2257] = 0x81; ++ BOOTRAM[2258] = 0x96; ++ BOOTRAM[2259] = 0x00; ++ BOOTRAM[2260] = 0x41; ++ BOOTRAM[2261] = 0x81; ++ BOOTRAM[2262] = 0x94; ++ BOOTRAM[2263] = 0x00; ++ BOOTRAM[2264] = 0x41; ++ BOOTRAM[2265] = 0x81; ++ BOOTRAM[2266] = 0x95; ++ BOOTRAM[2267] = 0x01; ++ BOOTRAM[2268] = 0x42; ++ BOOTRAM[2269] = 0x81; ++ BOOTRAM[2270] = 0x98; ++ BOOTRAM[2271] = 0x00; ++ BOOTRAM[2272] = 0x00; ++ BOOTRAM[2273] = 0x60; ++ BOOTRAM[2274] = 0x4E; ++ BOOTRAM[2275] = 0x81; ++ BOOTRAM[2276] = 0x00; ++ BOOTRAM[2277] = 0x00; ++ BOOTRAM[2278] = 0x00; ++ BOOTRAM[2279] = 0x00; ++ BOOTRAM[2280] = 0x00; ++ BOOTRAM[2281] = 0x00; ++ BOOTRAM[2282] = 0x00; ++ BOOTRAM[2283] = 0x00; ++ BOOTRAM[2284] = 0x00; ++ BOOTRAM[2285] = 0x00; ++ BOOTRAM[2286] = 0x00; ++ BOOTRAM[2287] = 0x00; ++ BOOTRAM[2288] = 0x00; ++ BOOTRAM[2289] = 0x00; ++ BOOTRAM[2290] = 0x00; ++ BOOTRAM[2291] = 0x00; ++ BOOTRAM[2292] = 0x00; ++ BOOTRAM[2293] = 0x00; ++ BOOTRAM[2294] = 0x00; ++ BOOTRAM[2295] = 0x00; ++ BOOTRAM[2296] = 0x00; ++ BOOTRAM[2297] = 0x00; ++ BOOTRAM[2298] = 0x00; ++ BOOTRAM[2299] = 0x00; ++ BOOTRAM[2300] = 0x00; ++ BOOTRAM[2301] = 0x00; ++ BOOTRAM[2302] = 0x00; ++ BOOTRAM[2303] = 0x00; ++ BOOTRAM[2304] = 0x00; ++ BOOTRAM[2305] = 0x00; ++ BOOTRAM[2306] = 0x00; ++ BOOTRAM[2307] = 0x00; ++ BOOTRAM[2308] = 0x00; ++ BOOTRAM[2309] = 0x00; ++ BOOTRAM[2310] = 0x00; ++ BOOTRAM[2311] = 0x00; ++ BOOTRAM[2312] = 0x00; ++ BOOTRAM[2313] = 0x00; ++ BOOTRAM[2314] = 0x00; ++ BOOTRAM[2315] = 0x00; ++ BOOTRAM[2316] = 0x00; ++ BOOTRAM[2317] = 0x00; ++ BOOTRAM[2318] = 0x00; ++ BOOTRAM[2319] = 0x00; ++ BOOTRAM[2320] = 0x00; ++ BOOTRAM[2321] = 0x00; ++ BOOTRAM[2322] = 0x00; ++ BOOTRAM[2323] = 0x00; ++ BOOTRAM[2324] = 0x00; ++ BOOTRAM[2325] = 0x00; ++ BOOTRAM[2326] = 0x00; ++ BOOTRAM[2327] = 0x00; ++ BOOTRAM[2328] = 0x00; ++ BOOTRAM[2329] = 0x00; ++ BOOTRAM[2330] = 0x00; ++ BOOTRAM[2331] = 0x00; ++ BOOTRAM[2332] = 0x00; ++ BOOTRAM[2333] = 0x00; ++ BOOTRAM[2334] = 0x00; ++ BOOTRAM[2335] = 0x00; ++ BOOTRAM[2336] = 0x00; ++ BOOTRAM[2337] = 0x00; ++ BOOTRAM[2338] = 0x00; ++ BOOTRAM[2339] = 0x00; ++ BOOTRAM[2340] = 0x00; ++ BOOTRAM[2341] = 0x00; ++ BOOTRAM[2342] = 0x00; ++ BOOTRAM[2343] = 0x00; ++ BOOTRAM[2344] = 0x00; ++ BOOTRAM[2345] = 0x00; ++ BOOTRAM[2346] = 0x00; ++ BOOTRAM[2347] = 0x00; ++ BOOTRAM[2348] = 0x00; ++ BOOTRAM[2349] = 0x00; ++ BOOTRAM[2350] = 0x00; ++ BOOTRAM[2351] = 0x00; ++ BOOTRAM[2352] = 0x00; ++ BOOTRAM[2353] = 0x00; ++ BOOTRAM[2354] = 0x00; ++ BOOTRAM[2355] = 0x42; ++ BOOTRAM[2356] = 0x81; ++ BOOTRAM[2357] = 0x4E; ++ BOOTRAM[2358] = 0x00; ++ BOOTRAM[2359] = 0x00; ++ BOOTRAM[2360] = 0x58; ++ BOOTRAM[2361] = 0x81; ++ BOOTRAM[2362] = 0x50; ++ BOOTRAM[2363] = 0x0B; ++ BOOTRAM[2364] = 0x0B; ++ BOOTRAM[2365] = 0x0C; ++ BOOTRAM[2366] = 0x00; ++ BOOTRAM[2367] = 0x1B; ++ BOOTRAM[2368] = 0x01; ++ BOOTRAM[2369] = 0x0F; ++ BOOTRAM[2370] = 0x02; ++ BOOTRAM[2371] = 0x03; ++ BOOTRAM[2372] = 0x03; ++ BOOTRAM[2373] = 0x19; ++ BOOTRAM[2374] = 0x04; ++ BOOTRAM[2375] = 0x11; ++ BOOTRAM[2376] = 0x05; ++ BOOTRAM[2377] = 0x01; ++ BOOTRAM[2378] = 0x06; ++ BOOTRAM[2379] = 0x09; ++ BOOTRAM[2380] = 0x07; ++ BOOTRAM[2381] = 0x1D; ++ BOOTRAM[2382] = 0x08; ++ BOOTRAM[2383] = 0x0D; ++ BOOTRAM[2384] = 0x09; ++ BOOTRAM[2385] = 0x1C; ++ BOOTRAM[2386] = 0x0A; ++ BOOTRAM[2387] = 0x41; ++ BOOTRAM[2388] = 0x81; ++ BOOTRAM[2389] = 0x9E; ++ BOOTRAM[2390] = 0x00; ++ BOOTRAM[2391] = 0x00; ++ BOOTRAM[2392] = 0x90; ++ BOOTRAM[2393] = 0x81; ++ BOOTRAM[2394] = 0x95; ++ BOOTRAM[2395] = 0x74; ++ BOOTRAM[2396] = 0x01; ++ BOOTRAM[2397] = 0xF0; ++ BOOTRAM[2398] = 0x90; ++ BOOTRAM[2399] = 0x81; ++ BOOTRAM[2400] = 0x97; ++ BOOTRAM[2401] = 0xE0; ++ BOOTRAM[2402] = 0xFF; ++ BOOTRAM[2403] = 0x64; ++ BOOTRAM[2404] = 0x10; ++ BOOTRAM[2405] = 0x60; ++ BOOTRAM[2406] = 0x09; ++ BOOTRAM[2407] = 0xEF; ++ BOOTRAM[2408] = 0x64; ++ BOOTRAM[2409] = 0x11; ++ BOOTRAM[2410] = 0x60; ++ BOOTRAM[2411] = 0x04; ++ BOOTRAM[2412] = 0xEF; ++ BOOTRAM[2413] = 0xB4; ++ BOOTRAM[2414] = 0x12; ++ BOOTRAM[2415] = 0x11; ++ BOOTRAM[2416] = 0x7D; ++ BOOTRAM[2417] = 0x07; ++ BOOTRAM[2418] = 0x7C; ++ BOOTRAM[2419] = 0x00; ++ BOOTRAM[2420] = 0x7F; ++ BOOTRAM[2421] = 0x20; ++ BOOTRAM[2422] = 0x7E; ++ BOOTRAM[2423] = 0xA1; ++ BOOTRAM[2424] = 0x12; ++ BOOTRAM[2425] = 0x06; ++ BOOTRAM[2426] = 0x2E; ++ BOOTRAM[2427] = 0xE4; ++ BOOTRAM[2428] = 0xFD; ++ BOOTRAM[2429] = 0x7F; ++ BOOTRAM[2430] = 0x03; ++ BOOTRAM[2431] = 0x80; ++ BOOTRAM[2432] = 0x04; ++ BOOTRAM[2433] = 0xE4; ++ BOOTRAM[2434] = 0xFD; ++ BOOTRAM[2435] = 0x7F; ++ BOOTRAM[2436] = 0x04; ++ BOOTRAM[2437] = 0x12; ++ BOOTRAM[2438] = 0x0D; ++ BOOTRAM[2439] = 0x52; ++ BOOTRAM[2440] = 0xE4; ++ BOOTRAM[2441] = 0xFD; ++ BOOTRAM[2442] = 0xFC; ++ BOOTRAM[2443] = 0x7F; ++ BOOTRAM[2444] = 0xE8; ++ BOOTRAM[2445] = 0x7E; ++ BOOTRAM[2446] = 0x03; ++ BOOTRAM[2447] = 0x12; ++ BOOTRAM[2448] = 0x06; ++ BOOTRAM[2449] = 0x2E; ++ BOOTRAM[2450] = 0x12; ++ BOOTRAM[2451] = 0x0E; ++ BOOTRAM[2452] = 0xCA; ++ BOOTRAM[2453] = 0x90; ++ BOOTRAM[2454] = 0x28; ++ BOOTRAM[2455] = 0x00; ++ BOOTRAM[2456] = 0xE0; ++ BOOTRAM[2457] = 0x44; ++ BOOTRAM[2458] = 0x10; ++ BOOTRAM[2459] = 0xF0; ++ BOOTRAM[2460] = 0xE4; ++ BOOTRAM[2461] = 0xFD; ++ BOOTRAM[2462] = 0xFC; ++ BOOTRAM[2463] = 0x7F; ++ BOOTRAM[2464] = 0xE8; ++ BOOTRAM[2465] = 0x7E; ++ BOOTRAM[2466] = 0x03; ++ BOOTRAM[2467] = 0x12; ++ BOOTRAM[2468] = 0x06; ++ BOOTRAM[2469] = 0x2E; ++ BOOTRAM[2470] = 0x90; ++ BOOTRAM[2471] = 0x81; ++ BOOTRAM[2472] = 0x97; ++ BOOTRAM[2473] = 0xE0; ++ BOOTRAM[2474] = 0xFF; ++ BOOTRAM[2475] = 0x64; ++ BOOTRAM[2476] = 0x31; ++ BOOTRAM[2477] = 0x60; ++ BOOTRAM[2478] = 0x1E; ++ BOOTRAM[2479] = 0xEF; ++ BOOTRAM[2480] = 0x64; ++ BOOTRAM[2481] = 0x30; ++ BOOTRAM[2482] = 0x60; ++ BOOTRAM[2483] = 0x19; ++ BOOTRAM[2484] = 0x12; ++ BOOTRAM[2485] = 0x0E; ++ BOOTRAM[2486] = 0xD2; ++ BOOTRAM[2487] = 0xE4; ++ BOOTRAM[2488] = 0xFD; ++ BOOTRAM[2489] = 0xFC; ++ BOOTRAM[2490] = 0x7F; ++ BOOTRAM[2491] = 0xE8; ++ BOOTRAM[2492] = 0x7E; ++ BOOTRAM[2493] = 0x03; ++ BOOTRAM[2494] = 0x12; ++ BOOTRAM[2495] = 0x06; ++ BOOTRAM[2496] = 0x2E; ++ BOOTRAM[2497] = 0xE4; ++ BOOTRAM[2498] = 0xFD; ++ BOOTRAM[2499] = 0xFC; ++ BOOTRAM[2500] = 0x7F; ++ BOOTRAM[2501] = 0xE8; ++ BOOTRAM[2502] = 0x7E; ++ BOOTRAM[2503] = 0x03; ++ BOOTRAM[2504] = 0x12; ++ BOOTRAM[2505] = 0x06; ++ BOOTRAM[2506] = 0x2E; ++ BOOTRAM[2507] = 0x80; ++ BOOTRAM[2508] = 0xEA; ++ BOOTRAM[2509] = 0x22; ++ BOOTRAM[2510] = 0xC0; ++ BOOTRAM[2511] = 0xE0; ++ BOOTRAM[2512] = 0xC0; ++ BOOTRAM[2513] = 0xF0; ++ BOOTRAM[2514] = 0xC0; ++ BOOTRAM[2515] = 0x83; ++ BOOTRAM[2516] = 0xC0; ++ BOOTRAM[2517] = 0x82; ++ BOOTRAM[2518] = 0xC0; ++ BOOTRAM[2519] = 0xD0; ++ BOOTRAM[2520] = 0x75; ++ BOOTRAM[2521] = 0xD0; ++ BOOTRAM[2522] = 0x00; ++ BOOTRAM[2523] = 0xC0; ++ BOOTRAM[2524] = 0x00; ++ BOOTRAM[2525] = 0xC0; ++ BOOTRAM[2526] = 0x01; ++ BOOTRAM[2527] = 0xC0; ++ BOOTRAM[2528] = 0x02; ++ BOOTRAM[2529] = 0xC0; ++ BOOTRAM[2530] = 0x03; ++ BOOTRAM[2531] = 0xC0; ++ BOOTRAM[2532] = 0x04; ++ BOOTRAM[2533] = 0xC0; ++ BOOTRAM[2534] = 0x05; ++ BOOTRAM[2535] = 0xC0; ++ BOOTRAM[2536] = 0x06; ++ BOOTRAM[2537] = 0xC0; ++ BOOTRAM[2538] = 0x07; ++ BOOTRAM[2539] = 0x90; ++ BOOTRAM[2540] = 0x37; ++ BOOTRAM[2541] = 0x10; ++ BOOTRAM[2542] = 0xE0; ++ BOOTRAM[2543] = 0x90; ++ BOOTRAM[2544] = 0x81; ++ BOOTRAM[2545] = 0x7D; ++ BOOTRAM[2546] = 0xF0; ++ BOOTRAM[2547] = 0xE0; ++ BOOTRAM[2548] = 0x30; ++ BOOTRAM[2549] = 0xE0; ++ BOOTRAM[2550] = 0x09; ++ BOOTRAM[2551] = 0x12; ++ BOOTRAM[2552] = 0x0B; ++ BOOTRAM[2553] = 0xD9; ++ BOOTRAM[2554] = 0x90; ++ BOOTRAM[2555] = 0x37; ++ BOOTRAM[2556] = 0x08; ++ BOOTRAM[2557] = 0x74; ++ BOOTRAM[2558] = 0x01; ++ BOOTRAM[2559] = 0xF0; ++ BOOTRAM[2560] = 0x90; ++ BOOTRAM[2561] = 0x81; ++ BOOTRAM[2562] = 0x7D; ++ BOOTRAM[2563] = 0xE0; ++ BOOTRAM[2564] = 0x30; ++ BOOTRAM[2565] = 0xE1; ++ BOOTRAM[2566] = 0x09; ++ BOOTRAM[2567] = 0x12; ++ BOOTRAM[2568] = 0x05; ++ BOOTRAM[2569] = 0x69; ++ BOOTRAM[2570] = 0x90; ++ BOOTRAM[2571] = 0x37; ++ BOOTRAM[2572] = 0x09; ++ BOOTRAM[2573] = 0x74; ++ BOOTRAM[2574] = 0x02; ++ BOOTRAM[2575] = 0xF0; ++ BOOTRAM[2576] = 0x90; ++ BOOTRAM[2577] = 0x81; ++ BOOTRAM[2578] = 0x7D; ++ BOOTRAM[2579] = 0xE0; ++ BOOTRAM[2580] = 0x30; ++ BOOTRAM[2581] = 0xE3; ++ BOOTRAM[2582] = 0x09; ++ BOOTRAM[2583] = 0x90; ++ BOOTRAM[2584] = 0x37; ++ BOOTRAM[2585] = 0x0B; ++ BOOTRAM[2586] = 0x74; ++ BOOTRAM[2587] = 0x08; ++ BOOTRAM[2588] = 0xF0; ++ BOOTRAM[2589] = 0x12; ++ BOOTRAM[2590] = 0x06; ++ BOOTRAM[2591] = 0xEF; ++ BOOTRAM[2592] = 0xD0; ++ BOOTRAM[2593] = 0x07; ++ BOOTRAM[2594] = 0xD0; ++ BOOTRAM[2595] = 0x06; ++ BOOTRAM[2596] = 0xD0; ++ BOOTRAM[2597] = 0x05; ++ BOOTRAM[2598] = 0xD0; ++ BOOTRAM[2599] = 0x04; ++ BOOTRAM[2600] = 0xD0; ++ BOOTRAM[2601] = 0x03; ++ BOOTRAM[2602] = 0xD0; ++ BOOTRAM[2603] = 0x02; ++ BOOTRAM[2604] = 0xD0; ++ BOOTRAM[2605] = 0x01; ++ BOOTRAM[2606] = 0xD0; ++ BOOTRAM[2607] = 0x00; ++ BOOTRAM[2608] = 0xD0; ++ BOOTRAM[2609] = 0xD0; ++ BOOTRAM[2610] = 0xD0; ++ BOOTRAM[2611] = 0x82; ++ BOOTRAM[2612] = 0xD0; ++ BOOTRAM[2613] = 0x83; ++ BOOTRAM[2614] = 0xD0; ++ BOOTRAM[2615] = 0xF0; ++ BOOTRAM[2616] = 0xD0; ++ BOOTRAM[2617] = 0xE0; ++ BOOTRAM[2618] = 0x32; ++ BOOTRAM[2619] = 0x7F; ++ BOOTRAM[2620] = 0x04; ++ BOOTRAM[2621] = 0x12; ++ BOOTRAM[2622] = 0x0A; ++ BOOTRAM[2623] = 0x44; ++ BOOTRAM[2624] = 0x7D; ++ BOOTRAM[2625] = 0x01; ++ BOOTRAM[2626] = 0x7F; ++ BOOTRAM[2627] = 0x05; ++ BOOTRAM[2628] = 0x90; ++ BOOTRAM[2629] = 0x19; ++ BOOTRAM[2630] = 0x03; ++ BOOTRAM[2631] = 0xE0; ++ BOOTRAM[2632] = 0xFE; ++ BOOTRAM[2633] = 0x90; ++ BOOTRAM[2634] = 0x19; ++ BOOTRAM[2635] = 0x02; ++ BOOTRAM[2636] = 0xE0; ++ BOOTRAM[2637] = 0xFC; ++ BOOTRAM[2638] = 0xED; ++ BOOTRAM[2639] = 0x14; ++ BOOTRAM[2640] = 0x60; ++ BOOTRAM[2641] = 0x17; ++ BOOTRAM[2642] = 0x04; ++ BOOTRAM[2643] = 0x70; ++ BOOTRAM[2644] = 0x28; ++ BOOTRAM[2645] = 0x74; ++ BOOTRAM[2646] = 0x01; ++ BOOTRAM[2647] = 0xA8; ++ BOOTRAM[2648] = 0x07; ++ BOOTRAM[2649] = 0x08; ++ BOOTRAM[2650] = 0x80; ++ BOOTRAM[2651] = 0x02; ++ BOOTRAM[2652] = 0xC3; ++ BOOTRAM[2653] = 0x33; ++ BOOTRAM[2654] = 0xD8; ++ BOOTRAM[2655] = 0xFC; ++ BOOTRAM[2656] = 0xF4; ++ BOOTRAM[2657] = 0xFD; ++ BOOTRAM[2658] = 0x5E; ++ BOOTRAM[2659] = 0xFE; ++ BOOTRAM[2660] = 0xEC; ++ BOOTRAM[2661] = 0x5D; ++ BOOTRAM[2662] = 0xFC; ++ BOOTRAM[2663] = 0x80; ++ BOOTRAM[2664] = 0x21; ++ BOOTRAM[2665] = 0x74; ++ BOOTRAM[2666] = 0x01; ++ BOOTRAM[2667] = 0xA8; ++ BOOTRAM[2668] = 0x07; ++ BOOTRAM[2669] = 0x08; ++ BOOTRAM[2670] = 0x80; ++ BOOTRAM[2671] = 0x02; ++ BOOTRAM[2672] = 0xC3; ++ BOOTRAM[2673] = 0x33; ++ BOOTRAM[2674] = 0xD8; ++ BOOTRAM[2675] = 0xFC; ++ BOOTRAM[2676] = 0xFD; ++ BOOTRAM[2677] = 0x4E; ++ BOOTRAM[2678] = 0xFE; ++ BOOTRAM[2679] = 0xED; ++ BOOTRAM[2680] = 0xF4; ++ BOOTRAM[2681] = 0x5C; ++ BOOTRAM[2682] = 0xFC; ++ BOOTRAM[2683] = 0x80; ++ BOOTRAM[2684] = 0x0D; ++ BOOTRAM[2685] = 0x74; ++ BOOTRAM[2686] = 0x01; ++ BOOTRAM[2687] = 0xA8; ++ BOOTRAM[2688] = 0x07; ++ BOOTRAM[2689] = 0x08; ++ BOOTRAM[2690] = 0x80; ++ BOOTRAM[2691] = 0x02; ++ BOOTRAM[2692] = 0xC3; ++ BOOTRAM[2693] = 0x33; ++ BOOTRAM[2694] = 0xD8; ++ BOOTRAM[2695] = 0xFC; ++ BOOTRAM[2696] = 0x4C; ++ BOOTRAM[2697] = 0xFC; ++ BOOTRAM[2698] = 0xAF; ++ BOOTRAM[2699] = 0x06; ++ BOOTRAM[2700] = 0x90; ++ BOOTRAM[2701] = 0x19; ++ BOOTRAM[2702] = 0x03; ++ BOOTRAM[2703] = 0xEE; ++ BOOTRAM[2704] = 0xF0; ++ BOOTRAM[2705] = 0xAF; ++ BOOTRAM[2706] = 0x04; ++ BOOTRAM[2707] = 0x90; ++ BOOTRAM[2708] = 0x19; ++ BOOTRAM[2709] = 0x02; ++ BOOTRAM[2710] = 0xEC; ++ BOOTRAM[2711] = 0xF0; ++ BOOTRAM[2712] = 0x22; ++ BOOTRAM[2713] = 0xFD; ++ BOOTRAM[2714] = 0x7F; ++ BOOTRAM[2715] = 0x03; ++ BOOTRAM[2716] = 0x12; ++ BOOTRAM[2717] = 0x0C; ++ BOOTRAM[2718] = 0xA2; ++ BOOTRAM[2719] = 0x0D; ++ BOOTRAM[2720] = 0x7F; ++ BOOTRAM[2721] = 0x04; ++ BOOTRAM[2722] = 0x12; ++ BOOTRAM[2723] = 0x0C; ++ BOOTRAM[2724] = 0xA2; ++ BOOTRAM[2725] = 0x7F; ++ BOOTRAM[2726] = 0x05; ++ BOOTRAM[2727] = 0x12; ++ BOOTRAM[2728] = 0x0C; ++ BOOTRAM[2729] = 0xA2; ++ BOOTRAM[2730] = 0x1D; ++ BOOTRAM[2731] = 0x7F; ++ BOOTRAM[2732] = 0x03; ++ BOOTRAM[2733] = 0x12; ++ BOOTRAM[2734] = 0x0D; ++ BOOTRAM[2735] = 0x52; ++ BOOTRAM[2736] = 0xE4; ++ BOOTRAM[2737] = 0xFD; ++ BOOTRAM[2738] = 0x7F; ++ BOOTRAM[2739] = 0x02; ++ BOOTRAM[2740] = 0x12; ++ BOOTRAM[2741] = 0x0A; ++ BOOTRAM[2742] = 0xC0; ++ BOOTRAM[2743] = 0x0D; ++ BOOTRAM[2744] = 0x7F; ++ BOOTRAM[2745] = 0x04; ++ BOOTRAM[2746] = 0x12; ++ BOOTRAM[2747] = 0x0A; ++ BOOTRAM[2748] = 0xC0; ++ BOOTRAM[2749] = 0x1D; ++ BOOTRAM[2750] = 0x7F; ++ BOOTRAM[2751] = 0x05; ++ BOOTRAM[2752] = 0x90; ++ BOOTRAM[2753] = 0x19; ++ BOOTRAM[2754] = 0x01; ++ BOOTRAM[2755] = 0xE0; ++ BOOTRAM[2756] = 0xFE; ++ BOOTRAM[2757] = 0xED; ++ BOOTRAM[2758] = 0x70; ++ BOOTRAM[2759] = 0x0F; ++ BOOTRAM[2760] = 0x04; ++ BOOTRAM[2761] = 0xA8; ++ BOOTRAM[2762] = 0x07; ++ BOOTRAM[2763] = 0x08; ++ BOOTRAM[2764] = 0x80; ++ BOOTRAM[2765] = 0x02; ++ BOOTRAM[2766] = 0xC3; ++ BOOTRAM[2767] = 0x33; ++ BOOTRAM[2768] = 0xD8; ++ BOOTRAM[2769] = 0xFC; ++ BOOTRAM[2770] = 0xF4; ++ BOOTRAM[2771] = 0x5E; ++ BOOTRAM[2772] = 0xFE; ++ BOOTRAM[2773] = 0x80; ++ BOOTRAM[2774] = 0x0D; ++ BOOTRAM[2775] = 0x74; ++ BOOTRAM[2776] = 0x01; ++ BOOTRAM[2777] = 0xA8; ++ BOOTRAM[2778] = 0x07; ++ BOOTRAM[2779] = 0x08; ++ BOOTRAM[2780] = 0x80; ++ BOOTRAM[2781] = 0x02; ++ BOOTRAM[2782] = 0xC3; ++ BOOTRAM[2783] = 0x33; ++ BOOTRAM[2784] = 0xD8; ++ BOOTRAM[2785] = 0xFC; ++ BOOTRAM[2786] = 0x4E; ++ BOOTRAM[2787] = 0xFE; ++ BOOTRAM[2788] = 0xAF; ++ BOOTRAM[2789] = 0x06; ++ BOOTRAM[2790] = 0x90; ++ BOOTRAM[2791] = 0x19; ++ BOOTRAM[2792] = 0x01; ++ BOOTRAM[2793] = 0xEE; ++ BOOTRAM[2794] = 0xF0; ++ BOOTRAM[2795] = 0x22; ++ BOOTRAM[2796] = 0x90; ++ BOOTRAM[2797] = 0x81; ++ BOOTRAM[2798] = 0x80; ++ BOOTRAM[2799] = 0xEE; ++ BOOTRAM[2800] = 0xF0; ++ BOOTRAM[2801] = 0xA3; ++ BOOTRAM[2802] = 0xEF; ++ BOOTRAM[2803] = 0xF0; ++ BOOTRAM[2804] = 0x64; ++ BOOTRAM[2805] = 0x0B; ++ BOOTRAM[2806] = 0x4E; ++ BOOTRAM[2807] = 0x70; ++ BOOTRAM[2808] = 0x0C; ++ BOOTRAM[2809] = 0x90; ++ BOOTRAM[2810] = 0x81; ++ BOOTRAM[2811] = 0x95; ++ BOOTRAM[2812] = 0xE0; ++ BOOTRAM[2813] = 0x60; ++ BOOTRAM[2814] = 0x03; ++ BOOTRAM[2815] = 0x02; ++ BOOTRAM[2816] = 0x0B; ++ BOOTRAM[2817] = 0x8C; ++ BOOTRAM[2818] = 0x02; ++ BOOTRAM[2819] = 0x09; ++ BOOTRAM[2820] = 0x58; ++ BOOTRAM[2821] = 0x90; ++ BOOTRAM[2822] = 0x81; ++ BOOTRAM[2823] = 0x80; ++ BOOTRAM[2824] = 0xE0; ++ BOOTRAM[2825] = 0xFE; ++ BOOTRAM[2826] = 0xA3; ++ BOOTRAM[2827] = 0xE0; ++ BOOTRAM[2828] = 0xFF; ++ BOOTRAM[2829] = 0x64; ++ BOOTRAM[2830] = 0x01; ++ BOOTRAM[2831] = 0x4E; ++ BOOTRAM[2832] = 0x70; ++ BOOTRAM[2833] = 0x09; ++ BOOTRAM[2834] = 0x12; ++ BOOTRAM[2835] = 0x0E; ++ BOOTRAM[2836] = 0x80; ++ BOOTRAM[2837] = 0x90; ++ BOOTRAM[2838] = 0x81; ++ BOOTRAM[2839] = 0x98; ++ BOOTRAM[2840] = 0xE4; ++ BOOTRAM[2841] = 0x80; ++ BOOTRAM[2842] = 0x09; ++ BOOTRAM[2843] = 0xEF; ++ BOOTRAM[2844] = 0x64; ++ BOOTRAM[2845] = 0x04; ++ BOOTRAM[2846] = 0x4E; ++ BOOTRAM[2847] = 0x70; ++ BOOTRAM[2848] = 0x08; ++ BOOTRAM[2849] = 0x90; ++ BOOTRAM[2850] = 0x81; ++ BOOTRAM[2851] = 0x98; ++ BOOTRAM[2852] = 0xF0; ++ BOOTRAM[2853] = 0xA3; ++ BOOTRAM[2854] = 0x04; ++ BOOTRAM[2855] = 0xF0; ++ BOOTRAM[2856] = 0x22; ++ BOOTRAM[2857] = 0xEF; ++ BOOTRAM[2858] = 0x64; ++ BOOTRAM[2859] = 0x03; ++ BOOTRAM[2860] = 0x4E; ++ BOOTRAM[2861] = 0x70; ++ BOOTRAM[2862] = 0x0D; ++ BOOTRAM[2863] = 0x7F; ++ BOOTRAM[2864] = 0x02; ++ BOOTRAM[2865] = 0xFE; ++ BOOTRAM[2866] = 0x12; ++ BOOTRAM[2867] = 0x0E; ++ BOOTRAM[2868] = 0x95; ++ BOOTRAM[2869] = 0xE4; ++ BOOTRAM[2870] = 0x90; ++ BOOTRAM[2871] = 0x81; ++ BOOTRAM[2872] = 0x98; ++ BOOTRAM[2873] = 0xF0; ++ BOOTRAM[2874] = 0xA3; ++ BOOTRAM[2875] = 0xF0; ++ BOOTRAM[2876] = 0x22; ++ BOOTRAM[2877] = 0x78; ++ BOOTRAM[2878] = 0x9A; ++ BOOTRAM[2879] = 0x7C; ++ BOOTRAM[2880] = 0x81; ++ BOOTRAM[2881] = 0x7D; ++ BOOTRAM[2882] = 0x01; ++ BOOTRAM[2883] = 0x7B; ++ BOOTRAM[2884] = 0xFF; ++ BOOTRAM[2885] = 0x7A; ++ BOOTRAM[2886] = 0x0E; ++ BOOTRAM[2887] = 0x79; ++ BOOTRAM[2888] = 0xF0; ++ BOOTRAM[2889] = 0x7E; ++ BOOTRAM[2890] = 0x00; ++ BOOTRAM[2891] = 0x7F; ++ BOOTRAM[2892] = 0x04; ++ BOOTRAM[2893] = 0x12; ++ BOOTRAM[2894] = 0x04; ++ BOOTRAM[2895] = 0x0D; ++ BOOTRAM[2896] = 0x90; ++ BOOTRAM[2897] = 0x28; ++ BOOTRAM[2898] = 0x11; ++ BOOTRAM[2899] = 0xE4; ++ BOOTRAM[2900] = 0xF0; ++ BOOTRAM[2901] = 0x90; ++ BOOTRAM[2902] = 0x81; ++ BOOTRAM[2903] = 0x9D; ++ BOOTRAM[2904] = 0xE0; ++ BOOTRAM[2905] = 0x90; ++ BOOTRAM[2906] = 0x00; ++ BOOTRAM[2907] = 0x04; ++ BOOTRAM[2908] = 0xF0; ++ BOOTRAM[2909] = 0x90; ++ BOOTRAM[2910] = 0x81; ++ BOOTRAM[2911] = 0x9C; ++ BOOTRAM[2912] = 0xE0; ++ BOOTRAM[2913] = 0x90; ++ BOOTRAM[2914] = 0x00; ++ BOOTRAM[2915] = 0x03; ++ BOOTRAM[2916] = 0xF0; ++ BOOTRAM[2917] = 0x90; ++ BOOTRAM[2918] = 0x81; ++ BOOTRAM[2919] = 0x9B; ++ BOOTRAM[2920] = 0xE0; ++ BOOTRAM[2921] = 0x90; ++ BOOTRAM[2922] = 0x00; ++ BOOTRAM[2923] = 0x02; ++ BOOTRAM[2924] = 0xF0; ++ BOOTRAM[2925] = 0x90; ++ BOOTRAM[2926] = 0x81; ++ BOOTRAM[2927] = 0x9A; ++ BOOTRAM[2928] = 0xE0; ++ BOOTRAM[2929] = 0x90; ++ BOOTRAM[2930] = 0x00; ++ BOOTRAM[2931] = 0x01; ++ BOOTRAM[2932] = 0xF0; ++ BOOTRAM[2933] = 0xE4; ++ BOOTRAM[2934] = 0xFB; ++ BOOTRAM[2935] = 0xFD; ++ BOOTRAM[2936] = 0xFF; ++ BOOTRAM[2937] = 0x12; ++ BOOTRAM[2938] = 0x0E; ++ BOOTRAM[2939] = 0x74; ++ BOOTRAM[2940] = 0xE4; ++ BOOTRAM[2941] = 0xFE; ++ BOOTRAM[2942] = 0x12; ++ BOOTRAM[2943] = 0x0D; ++ BOOTRAM[2944] = 0xE0; ++ BOOTRAM[2945] = 0x12; ++ BOOTRAM[2946] = 0x0E; ++ BOOTRAM[2947] = 0xB9; ++ BOOTRAM[2948] = 0x90; ++ BOOTRAM[2949] = 0x28; ++ BOOTRAM[2950] = 0x11; ++ BOOTRAM[2951] = 0xE0; ++ BOOTRAM[2952] = 0x44; ++ BOOTRAM[2953] = 0x02; ++ BOOTRAM[2954] = 0xF0; ++ BOOTRAM[2955] = 0x22; ++ BOOTRAM[2956] = 0x7D; ++ BOOTRAM[2957] = 0x07; ++ BOOTRAM[2958] = 0x7C; ++ BOOTRAM[2959] = 0x00; ++ BOOTRAM[2960] = 0x7F; ++ BOOTRAM[2961] = 0x20; ++ BOOTRAM[2962] = 0x7E; ++ BOOTRAM[2963] = 0xA1; ++ BOOTRAM[2964] = 0x12; ++ BOOTRAM[2965] = 0x06; ++ BOOTRAM[2966] = 0x2E; ++ BOOTRAM[2967] = 0xE4; ++ BOOTRAM[2968] = 0x90; ++ BOOTRAM[2969] = 0x81; ++ BOOTRAM[2970] = 0x95; ++ BOOTRAM[2971] = 0xF0; ++ BOOTRAM[2972] = 0x12; ++ BOOTRAM[2973] = 0x0E; ++ BOOTRAM[2974] = 0xC2; ++ BOOTRAM[2975] = 0x90; ++ BOOTRAM[2976] = 0x28; ++ BOOTRAM[2977] = 0x00; ++ BOOTRAM[2978] = 0xE0; ++ BOOTRAM[2979] = 0x54; ++ BOOTRAM[2980] = 0xEF; ++ BOOTRAM[2981] = 0xF0; ++ BOOTRAM[2982] = 0xE4; ++ BOOTRAM[2983] = 0xFD; ++ BOOTRAM[2984] = 0xFC; ++ BOOTRAM[2985] = 0x7F; ++ BOOTRAM[2986] = 0xE8; ++ BOOTRAM[2987] = 0x7E; ++ BOOTRAM[2988] = 0x03; ++ BOOTRAM[2989] = 0x12; ++ BOOTRAM[2990] = 0x06; ++ BOOTRAM[2991] = 0x2E; ++ BOOTRAM[2992] = 0x90; ++ BOOTRAM[2993] = 0x81; ++ BOOTRAM[2994] = 0x97; ++ BOOTRAM[2995] = 0xE0; ++ BOOTRAM[2996] = 0xFF; ++ BOOTRAM[2997] = 0x64; ++ BOOTRAM[2998] = 0x10; ++ BOOTRAM[2999] = 0x60; ++ BOOTRAM[3000] = 0x09; ++ BOOTRAM[3001] = 0xEF; ++ BOOTRAM[3002] = 0x64; ++ BOOTRAM[3003] = 0x11; ++ BOOTRAM[3004] = 0x60; ++ BOOTRAM[3005] = 0x04; ++ BOOTRAM[3006] = 0xEF; ++ BOOTRAM[3007] = 0xB4; ++ BOOTRAM[3008] = 0x12; ++ BOOTRAM[3009] = 0x06; ++ BOOTRAM[3010] = 0x7D; ++ BOOTRAM[3011] = 0x01; ++ BOOTRAM[3012] = 0x7F; ++ BOOTRAM[3013] = 0x03; ++ BOOTRAM[3014] = 0x80; ++ BOOTRAM[3015] = 0x04; ++ BOOTRAM[3016] = 0x7D; ++ BOOTRAM[3017] = 0x01; ++ BOOTRAM[3018] = 0x7F; ++ BOOTRAM[3019] = 0x04; ++ BOOTRAM[3020] = 0x12; ++ BOOTRAM[3021] = 0x0D; ++ BOOTRAM[3022] = 0x52; ++ BOOTRAM[3023] = 0xE4; ++ BOOTRAM[3024] = 0xFD; ++ BOOTRAM[3025] = 0xFC; ++ BOOTRAM[3026] = 0x7F; ++ BOOTRAM[3027] = 0xE8; ++ BOOTRAM[3028] = 0x7E; ++ BOOTRAM[3029] = 0x03; ++ BOOTRAM[3030] = 0x02; ++ BOOTRAM[3031] = 0x06; ++ BOOTRAM[3032] = 0x2E; ++ BOOTRAM[3033] = 0x90; ++ BOOTRAM[3034] = 0x00; ++ BOOTRAM[3035] = 0x08; ++ BOOTRAM[3036] = 0x74; ++ BOOTRAM[3037] = 0x01; ++ BOOTRAM[3038] = 0xF0; ++ BOOTRAM[3039] = 0xE4; ++ BOOTRAM[3040] = 0xF0; ++ BOOTRAM[3041] = 0x7B; ++ BOOTRAM[3042] = 0x01; ++ BOOTRAM[3043] = 0x90; ++ BOOTRAM[3044] = 0x81; ++ BOOTRAM[3045] = 0x86; ++ BOOTRAM[3046] = 0x04; ++ BOOTRAM[3047] = 0xF0; ++ BOOTRAM[3048] = 0xA3; ++ BOOTRAM[3049] = 0x74; ++ BOOTRAM[3050] = 0x81; ++ BOOTRAM[3051] = 0xF0; ++ BOOTRAM[3052] = 0xA3; ++ BOOTRAM[3053] = 0x74; ++ BOOTRAM[3054] = 0x81; ++ BOOTRAM[3055] = 0xF0; ++ BOOTRAM[3056] = 0xA3; ++ BOOTRAM[3057] = 0xEB; ++ BOOTRAM[3058] = 0xF0; ++ BOOTRAM[3059] = 0xA3; ++ BOOTRAM[3060] = 0x74; ++ BOOTRAM[3061] = 0x81; ++ BOOTRAM[3062] = 0xF0; ++ BOOTRAM[3063] = 0xA3; ++ BOOTRAM[3064] = 0x74; ++ BOOTRAM[3065] = 0x82; ++ BOOTRAM[3066] = 0xF0; ++ BOOTRAM[3067] = 0x7A; ++ BOOTRAM[3068] = 0x81; ++ BOOTRAM[3069] = 0x79; ++ BOOTRAM[3070] = 0x80; ++ BOOTRAM[3071] = 0x12; ++ BOOTRAM[3072] = 0x0C; ++ BOOTRAM[3073] = 0x47; ++ BOOTRAM[3074] = 0x7B; ++ BOOTRAM[3075] = 0x01; ++ BOOTRAM[3076] = 0x7A; ++ BOOTRAM[3077] = 0x81; ++ BOOTRAM[3078] = 0x79; ++ BOOTRAM[3079] = 0x7E; ++ BOOTRAM[3080] = 0x12; ++ BOOTRAM[3081] = 0x0D; ++ BOOTRAM[3082] = 0xF3; ++ BOOTRAM[3083] = 0x90; ++ BOOTRAM[3084] = 0x81; ++ BOOTRAM[3085] = 0x7E; ++ BOOTRAM[3086] = 0xE0; ++ BOOTRAM[3087] = 0xFE; ++ BOOTRAM[3088] = 0xA3; ++ BOOTRAM[3089] = 0xE0; ++ BOOTRAM[3090] = 0xFF; ++ BOOTRAM[3091] = 0x02; ++ BOOTRAM[3092] = 0x0E; ++ BOOTRAM[3093] = 0x9E; ++ BOOTRAM[3094] = 0x90; ++ BOOTRAM[3095] = 0x81; ++ BOOTRAM[3096] = 0x80; ++ BOOTRAM[3097] = 0xEE; ++ BOOTRAM[3098] = 0xF0; ++ BOOTRAM[3099] = 0xA3; ++ BOOTRAM[3100] = 0xEF; ++ BOOTRAM[3101] = 0xF0; ++ BOOTRAM[3102] = 0xE4; ++ BOOTRAM[3103] = 0xFF; ++ BOOTRAM[3104] = 0xEF; ++ BOOTRAM[3105] = 0x25; ++ BOOTRAM[3106] = 0xE0; ++ BOOTRAM[3107] = 0x24; ++ BOOTRAM[3108] = 0x50; ++ BOOTRAM[3109] = 0xF5; ++ BOOTRAM[3110] = 0x82; ++ BOOTRAM[3111] = 0xE4; ++ BOOTRAM[3112] = 0x34; ++ BOOTRAM[3113] = 0x81; ++ BOOTRAM[3114] = 0xF5; ++ BOOTRAM[3115] = 0x83; ++ BOOTRAM[3116] = 0xE0; ++ BOOTRAM[3117] = 0xB5; ++ BOOTRAM[3118] = 0x05; ++ BOOTRAM[3119] = 0x0F; ++ BOOTRAM[3120] = 0xEF; ++ BOOTRAM[3121] = 0x25; ++ BOOTRAM[3122] = 0xE0; ++ BOOTRAM[3123] = 0x24; ++ BOOTRAM[3124] = 0x51; ++ BOOTRAM[3125] = 0xF5; ++ BOOTRAM[3126] = 0x82; ++ BOOTRAM[3127] = 0xE4; ++ BOOTRAM[3128] = 0x34; ++ BOOTRAM[3129] = 0x81; ++ BOOTRAM[3130] = 0xF5; ++ BOOTRAM[3131] = 0x83; ++ BOOTRAM[3132] = 0xE0; ++ BOOTRAM[3133] = 0xFF; ++ BOOTRAM[3134] = 0x22; ++ BOOTRAM[3135] = 0x0F; ++ BOOTRAM[3136] = 0xEF; ++ BOOTRAM[3137] = 0xB4; ++ BOOTRAM[3138] = 0x0C; ++ BOOTRAM[3139] = 0xDC; ++ BOOTRAM[3140] = 0x7F; ++ BOOTRAM[3141] = 0xFF; ++ BOOTRAM[3142] = 0x22; ++ BOOTRAM[3143] = 0x90; ++ BOOTRAM[3144] = 0x00; ++ BOOTRAM[3145] = 0x1D; ++ BOOTRAM[3146] = 0xE0; ++ BOOTRAM[3147] = 0x12; ++ BOOTRAM[3148] = 0x04; ++ BOOTRAM[3149] = 0x33; ++ BOOTRAM[3150] = 0x90; ++ BOOTRAM[3151] = 0x00; ++ BOOTRAM[3152] = 0x1C; ++ BOOTRAM[3153] = 0xE0; ++ BOOTRAM[3154] = 0xFF; ++ BOOTRAM[3155] = 0x90; ++ BOOTRAM[3156] = 0x81; ++ BOOTRAM[3157] = 0x86; ++ BOOTRAM[3158] = 0xE0; ++ BOOTRAM[3159] = 0xFB; ++ BOOTRAM[3160] = 0xA3; ++ BOOTRAM[3161] = 0xE0; ++ BOOTRAM[3162] = 0xFA; ++ BOOTRAM[3163] = 0xA3; ++ BOOTRAM[3164] = 0xE0; ++ BOOTRAM[3165] = 0xF9; ++ BOOTRAM[3166] = 0xEF; ++ BOOTRAM[3167] = 0x12; ++ BOOTRAM[3168] = 0x04; ++ BOOTRAM[3169] = 0x33; ++ BOOTRAM[3170] = 0x90; ++ BOOTRAM[3171] = 0x00; ++ BOOTRAM[3172] = 0x1B; ++ BOOTRAM[3173] = 0xE0; ++ BOOTRAM[3174] = 0xFF; ++ BOOTRAM[3175] = 0x90; ++ BOOTRAM[3176] = 0x81; ++ BOOTRAM[3177] = 0x89; ++ BOOTRAM[3178] = 0xE0; ++ BOOTRAM[3179] = 0xFB; ++ BOOTRAM[3180] = 0xA3; ++ BOOTRAM[3181] = 0xE0; ++ BOOTRAM[3182] = 0xFA; ++ BOOTRAM[3183] = 0xA3; ++ BOOTRAM[3184] = 0xE0; ++ BOOTRAM[3185] = 0xF9; ++ BOOTRAM[3186] = 0xEF; ++ BOOTRAM[3187] = 0x02; ++ BOOTRAM[3188] = 0x04; ++ BOOTRAM[3189] = 0x33; ++ BOOTRAM[3190] = 0x90; ++ BOOTRAM[3191] = 0x19; ++ BOOTRAM[3192] = 0x08; ++ BOOTRAM[3193] = 0xE0; ++ BOOTRAM[3194] = 0xFE; ++ BOOTRAM[3195] = 0xED; ++ BOOTRAM[3196] = 0x70; ++ BOOTRAM[3197] = 0x0F; ++ BOOTRAM[3198] = 0x04; ++ BOOTRAM[3199] = 0xA8; ++ BOOTRAM[3200] = 0x07; ++ BOOTRAM[3201] = 0x08; ++ BOOTRAM[3202] = 0x80; ++ BOOTRAM[3203] = 0x02; ++ BOOTRAM[3204] = 0xC3; ++ BOOTRAM[3205] = 0x33; ++ BOOTRAM[3206] = 0xD8; ++ BOOTRAM[3207] = 0xFC; ++ BOOTRAM[3208] = 0xF4; ++ BOOTRAM[3209] = 0x5E; ++ BOOTRAM[3210] = 0xFE; ++ BOOTRAM[3211] = 0x80; ++ BOOTRAM[3212] = 0x0D; ++ BOOTRAM[3213] = 0x74; ++ BOOTRAM[3214] = 0x01; ++ BOOTRAM[3215] = 0xA8; ++ BOOTRAM[3216] = 0x07; ++ BOOTRAM[3217] = 0x08; ++ BOOTRAM[3218] = 0x80; ++ BOOTRAM[3219] = 0x02; ++ BOOTRAM[3220] = 0xC3; ++ BOOTRAM[3221] = 0x33; ++ BOOTRAM[3222] = 0xD8; ++ BOOTRAM[3223] = 0xFC; ++ BOOTRAM[3224] = 0x4E; ++ BOOTRAM[3225] = 0xFE; ++ BOOTRAM[3226] = 0xAF; ++ BOOTRAM[3227] = 0x06; ++ BOOTRAM[3228] = 0x90; ++ BOOTRAM[3229] = 0x19; ++ BOOTRAM[3230] = 0x08; ++ BOOTRAM[3231] = 0xEE; ++ BOOTRAM[3232] = 0xF0; ++ BOOTRAM[3233] = 0x22; ++ BOOTRAM[3234] = 0x90; ++ BOOTRAM[3235] = 0x19; ++ BOOTRAM[3236] = 0x00; ++ BOOTRAM[3237] = 0xE0; ++ BOOTRAM[3238] = 0xFE; ++ BOOTRAM[3239] = 0xED; ++ BOOTRAM[3240] = 0x70; ++ BOOTRAM[3241] = 0x0F; ++ BOOTRAM[3242] = 0x04; ++ BOOTRAM[3243] = 0xA8; ++ BOOTRAM[3244] = 0x07; ++ BOOTRAM[3245] = 0x08; ++ BOOTRAM[3246] = 0x80; ++ BOOTRAM[3247] = 0x02; ++ BOOTRAM[3248] = 0xC3; ++ BOOTRAM[3249] = 0x33; ++ BOOTRAM[3250] = 0xD8; ++ BOOTRAM[3251] = 0xFC; ++ BOOTRAM[3252] = 0xF4; ++ BOOTRAM[3253] = 0x5E; ++ BOOTRAM[3254] = 0xFE; ++ BOOTRAM[3255] = 0x80; ++ BOOTRAM[3256] = 0x0D; ++ BOOTRAM[3257] = 0x74; ++ BOOTRAM[3258] = 0x01; ++ BOOTRAM[3259] = 0xA8; ++ BOOTRAM[3260] = 0x07; ++ BOOTRAM[3261] = 0x08; ++ BOOTRAM[3262] = 0x80; ++ BOOTRAM[3263] = 0x02; ++ BOOTRAM[3264] = 0xC3; ++ BOOTRAM[3265] = 0x33; ++ BOOTRAM[3266] = 0xD8; ++ BOOTRAM[3267] = 0xFC; ++ BOOTRAM[3268] = 0x4E; ++ BOOTRAM[3269] = 0xFE; ++ BOOTRAM[3270] = 0xAF; ++ BOOTRAM[3271] = 0x06; ++ BOOTRAM[3272] = 0x90; ++ BOOTRAM[3273] = 0x19; ++ BOOTRAM[3274] = 0x00; ++ BOOTRAM[3275] = 0xEE; ++ BOOTRAM[3276] = 0xF0; ++ BOOTRAM[3277] = 0x22; ++ BOOTRAM[3278] = 0x90; ++ BOOTRAM[3279] = 0x19; ++ BOOTRAM[3280] = 0x03; ++ BOOTRAM[3281] = 0xE0; ++ BOOTRAM[3282] = 0xFE; ++ BOOTRAM[3283] = 0xED; ++ BOOTRAM[3284] = 0x70; ++ BOOTRAM[3285] = 0x0F; ++ BOOTRAM[3286] = 0x04; ++ BOOTRAM[3287] = 0xA8; ++ BOOTRAM[3288] = 0x07; ++ BOOTRAM[3289] = 0x08; ++ BOOTRAM[3290] = 0x80; ++ BOOTRAM[3291] = 0x02; ++ BOOTRAM[3292] = 0xC3; ++ BOOTRAM[3293] = 0x33; ++ BOOTRAM[3294] = 0xD8; ++ BOOTRAM[3295] = 0xFC; ++ BOOTRAM[3296] = 0xF4; ++ BOOTRAM[3297] = 0x5E; ++ BOOTRAM[3298] = 0xFE; ++ BOOTRAM[3299] = 0x80; ++ BOOTRAM[3300] = 0x0D; ++ BOOTRAM[3301] = 0x74; ++ BOOTRAM[3302] = 0x01; ++ BOOTRAM[3303] = 0xA8; ++ BOOTRAM[3304] = 0x07; ++ BOOTRAM[3305] = 0x08; ++ BOOTRAM[3306] = 0x80; ++ BOOTRAM[3307] = 0x02; ++ BOOTRAM[3308] = 0xC3; ++ BOOTRAM[3309] = 0x33; ++ BOOTRAM[3310] = 0xD8; ++ BOOTRAM[3311] = 0xFC; ++ BOOTRAM[3312] = 0x4E; ++ BOOTRAM[3313] = 0xFE; ++ BOOTRAM[3314] = 0xAF; ++ BOOTRAM[3315] = 0x06; ++ BOOTRAM[3316] = 0x90; ++ BOOTRAM[3317] = 0x19; ++ BOOTRAM[3318] = 0x03; ++ BOOTRAM[3319] = 0xEE; ++ BOOTRAM[3320] = 0xF0; ++ BOOTRAM[3321] = 0x22; ++ BOOTRAM[3322] = 0x90; ++ BOOTRAM[3323] = 0x19; ++ BOOTRAM[3324] = 0x04; ++ BOOTRAM[3325] = 0xE0; ++ BOOTRAM[3326] = 0xFE; ++ BOOTRAM[3327] = 0xED; ++ BOOTRAM[3328] = 0x70; ++ BOOTRAM[3329] = 0x0F; ++ BOOTRAM[3330] = 0x04; ++ BOOTRAM[3331] = 0xA8; ++ BOOTRAM[3332] = 0x07; ++ BOOTRAM[3333] = 0x08; ++ BOOTRAM[3334] = 0x80; ++ BOOTRAM[3335] = 0x02; ++ BOOTRAM[3336] = 0xC3; ++ BOOTRAM[3337] = 0x33; ++ BOOTRAM[3338] = 0xD8; ++ BOOTRAM[3339] = 0xFC; ++ BOOTRAM[3340] = 0xF4; ++ BOOTRAM[3341] = 0x5E; ++ BOOTRAM[3342] = 0xFE; ++ BOOTRAM[3343] = 0x80; ++ BOOTRAM[3344] = 0x0D; ++ BOOTRAM[3345] = 0x74; ++ BOOTRAM[3346] = 0x01; ++ BOOTRAM[3347] = 0xA8; ++ BOOTRAM[3348] = 0x07; ++ BOOTRAM[3349] = 0x08; ++ BOOTRAM[3350] = 0x80; ++ BOOTRAM[3351] = 0x02; ++ BOOTRAM[3352] = 0xC3; ++ BOOTRAM[3353] = 0x33; ++ BOOTRAM[3354] = 0xD8; ++ BOOTRAM[3355] = 0xFC; ++ BOOTRAM[3356] = 0x4E; ++ BOOTRAM[3357] = 0xFE; ++ BOOTRAM[3358] = 0xAF; ++ BOOTRAM[3359] = 0x06; ++ BOOTRAM[3360] = 0x90; ++ BOOTRAM[3361] = 0x19; ++ BOOTRAM[3362] = 0x04; ++ BOOTRAM[3363] = 0xEE; ++ BOOTRAM[3364] = 0xF0; ++ BOOTRAM[3365] = 0x22; ++ BOOTRAM[3366] = 0xAD; ++ BOOTRAM[3367] = 0x07; ++ BOOTRAM[3368] = 0x74; ++ BOOTRAM[3369] = 0x01; ++ BOOTRAM[3370] = 0x7E; ++ BOOTRAM[3371] = 0x00; ++ BOOTRAM[3372] = 0xA8; ++ BOOTRAM[3373] = 0x05; ++ BOOTRAM[3374] = 0x08; ++ BOOTRAM[3375] = 0x80; ++ BOOTRAM[3376] = 0x05; ++ BOOTRAM[3377] = 0xC3; ++ BOOTRAM[3378] = 0x33; ++ BOOTRAM[3379] = 0xCE; ++ BOOTRAM[3380] = 0x33; ++ BOOTRAM[3381] = 0xCE; ++ BOOTRAM[3382] = 0xD8; ++ BOOTRAM[3383] = 0xF9; ++ BOOTRAM[3384] = 0xFF; ++ BOOTRAM[3385] = 0x24; ++ BOOTRAM[3386] = 0x00; ++ BOOTRAM[3387] = 0xFB; ++ BOOTRAM[3388] = 0xEE; ++ BOOTRAM[3389] = 0x34; ++ BOOTRAM[3390] = 0x18; ++ BOOTRAM[3391] = 0x8B; ++ BOOTRAM[3392] = 0x82; ++ BOOTRAM[3393] = 0xF5; ++ BOOTRAM[3394] = 0x83; ++ BOOTRAM[3395] = 0xE0; ++ BOOTRAM[3396] = 0xFD; ++ BOOTRAM[3397] = 0xEF; ++ BOOTRAM[3398] = 0x5D; ++ BOOTRAM[3399] = 0x60; ++ BOOTRAM[3400] = 0x05; ++ BOOTRAM[3401] = 0x7E; ++ BOOTRAM[3402] = 0x00; ++ BOOTRAM[3403] = 0x7F; ++ BOOTRAM[3404] = 0x01; ++ BOOTRAM[3405] = 0x22; ++ BOOTRAM[3406] = 0xE4; ++ BOOTRAM[3407] = 0xFE; ++ BOOTRAM[3408] = 0xFF; ++ BOOTRAM[3409] = 0x22; ++ BOOTRAM[3410] = 0xED; ++ BOOTRAM[3411] = 0x54; ++ BOOTRAM[3412] = 0x01; ++ BOOTRAM[3413] = 0xFE; ++ BOOTRAM[3414] = 0xA8; ++ BOOTRAM[3415] = 0x07; ++ BOOTRAM[3416] = 0x08; ++ BOOTRAM[3417] = 0x80; ++ BOOTRAM[3418] = 0x02; ++ BOOTRAM[3419] = 0xC3; ++ BOOTRAM[3420] = 0x33; ++ BOOTRAM[3421] = 0xD8; ++ BOOTRAM[3422] = 0xFC; ++ BOOTRAM[3423] = 0xFD; ++ BOOTRAM[3424] = 0x74; ++ BOOTRAM[3425] = 0x01; ++ BOOTRAM[3426] = 0x7E; ++ BOOTRAM[3427] = 0x00; ++ BOOTRAM[3428] = 0xA8; ++ BOOTRAM[3429] = 0x07; ++ BOOTRAM[3430] = 0x08; ++ BOOTRAM[3431] = 0x80; ++ BOOTRAM[3432] = 0x05; ++ BOOTRAM[3433] = 0xC3; ++ BOOTRAM[3434] = 0x33; ++ BOOTRAM[3435] = 0xCE; ++ BOOTRAM[3436] = 0x33; ++ BOOTRAM[3437] = 0xCE; ++ BOOTRAM[3438] = 0xD8; ++ BOOTRAM[3439] = 0xF9; ++ BOOTRAM[3440] = 0x24; ++ BOOTRAM[3441] = 0x00; ++ BOOTRAM[3442] = 0xFF; ++ BOOTRAM[3443] = 0xEE; ++ BOOTRAM[3444] = 0x34; ++ BOOTRAM[3445] = 0x18; ++ BOOTRAM[3446] = 0x8F; ++ BOOTRAM[3447] = 0x82; ++ BOOTRAM[3448] = 0xF5; ++ BOOTRAM[3449] = 0x83; ++ BOOTRAM[3450] = 0xED; ++ BOOTRAM[3451] = 0xF0; ++ BOOTRAM[3452] = 0x22; ++ BOOTRAM[3453] = 0x90; ++ BOOTRAM[3454] = 0x10; ++ BOOTRAM[3455] = 0x2C; ++ BOOTRAM[3456] = 0xE0; ++ BOOTRAM[3457] = 0xFD; ++ BOOTRAM[3458] = 0xA3; ++ BOOTRAM[3459] = 0xE0; ++ BOOTRAM[3460] = 0xFF; ++ BOOTRAM[3461] = 0xED; ++ BOOTRAM[3462] = 0xCF; ++ BOOTRAM[3463] = 0x8F; ++ BOOTRAM[3464] = 0xF0; ++ BOOTRAM[3465] = 0x12; ++ BOOTRAM[3466] = 0x04; ++ BOOTRAM[3467] = 0x57; ++ BOOTRAM[3468] = 0x90; ++ BOOTRAM[3469] = 0x10; ++ BOOTRAM[3470] = 0x2E; ++ BOOTRAM[3471] = 0xE0; ++ BOOTRAM[3472] = 0xFD; ++ BOOTRAM[3473] = 0xA3; ++ BOOTRAM[3474] = 0xE0; ++ BOOTRAM[3475] = 0xF9; ++ BOOTRAM[3476] = 0xED; ++ BOOTRAM[3477] = 0xFF; ++ BOOTRAM[3478] = 0x90; ++ BOOTRAM[3479] = 0x81; ++ BOOTRAM[3480] = 0x91; ++ BOOTRAM[3481] = 0xE0; ++ BOOTRAM[3482] = 0xFB; ++ BOOTRAM[3483] = 0xA3; ++ BOOTRAM[3484] = 0xE0; ++ BOOTRAM[3485] = 0xFA; ++ BOOTRAM[3486] = 0xA3; ++ BOOTRAM[3487] = 0xE0; ++ BOOTRAM[3488] = 0xC9; ++ BOOTRAM[3489] = 0x8F; ++ BOOTRAM[3490] = 0xF0; ++ BOOTRAM[3491] = 0x02; ++ BOOTRAM[3492] = 0x04; ++ BOOTRAM[3493] = 0x57; ++ BOOTRAM[3494] = 0xEF; ++ BOOTRAM[3495] = 0x24; ++ BOOTRAM[3496] = 0x10; ++ BOOTRAM[3497] = 0xFB; ++ BOOTRAM[3498] = 0xE4; ++ BOOTRAM[3499] = 0x34; ++ BOOTRAM[3500] = 0x28; ++ BOOTRAM[3501] = 0x8B; ++ BOOTRAM[3502] = 0x82; ++ BOOTRAM[3503] = 0xF5; ++ BOOTRAM[3504] = 0x83; ++ BOOTRAM[3505] = 0xE0; ++ BOOTRAM[3506] = 0x54; ++ BOOTRAM[3507] = 0xCF; ++ BOOTRAM[3508] = 0x4D; ++ BOOTRAM[3509] = 0xFE; ++ BOOTRAM[3510] = 0xEF; ++ BOOTRAM[3511] = 0x24; ++ BOOTRAM[3512] = 0x10; ++ BOOTRAM[3513] = 0xFD; ++ BOOTRAM[3514] = 0xE4; ++ BOOTRAM[3515] = 0x34; ++ BOOTRAM[3516] = 0x28; ++ BOOTRAM[3517] = 0x8D; ++ BOOTRAM[3518] = 0x82; ++ BOOTRAM[3519] = 0xF5; ++ BOOTRAM[3520] = 0x83; ++ BOOTRAM[3521] = 0xEE; ++ BOOTRAM[3522] = 0xF0; ++ BOOTRAM[3523] = 0x22; ++ BOOTRAM[3524] = 0x7E; ++ BOOTRAM[3525] = 0x02; ++ BOOTRAM[3526] = 0x90; ++ BOOTRAM[3527] = 0x08; ++ BOOTRAM[3528] = 0x00; ++ BOOTRAM[3529] = 0x74; ++ BOOTRAM[3530] = 0x08; ++ BOOTRAM[3531] = 0xF0; ++ BOOTRAM[3532] = 0x74; ++ BOOTRAM[3533] = 0x76; ++ BOOTRAM[3534] = 0xA3; ++ BOOTRAM[3535] = 0xF0; ++ BOOTRAM[3536] = 0xEE; ++ BOOTRAM[3537] = 0xA3; ++ BOOTRAM[3538] = 0xF0; ++ BOOTRAM[3539] = 0x90; ++ BOOTRAM[3540] = 0x08; ++ BOOTRAM[3541] = 0x00; ++ BOOTRAM[3542] = 0xF0; ++ BOOTRAM[3543] = 0x90; ++ BOOTRAM[3544] = 0x08; ++ BOOTRAM[3545] = 0x05; ++ BOOTRAM[3546] = 0x74; ++ BOOTRAM[3547] = 0xFF; ++ BOOTRAM[3548] = 0xF0; ++ BOOTRAM[3549] = 0xA3; ++ BOOTRAM[3550] = 0xF0; ++ BOOTRAM[3551] = 0x22; ++ BOOTRAM[3552] = 0xAD; ++ BOOTRAM[3553] = 0x07; ++ BOOTRAM[3554] = 0xAC; ++ BOOTRAM[3555] = 0x06; ++ BOOTRAM[3556] = 0xEC; ++ BOOTRAM[3557] = 0xFF; ++ BOOTRAM[3558] = 0xAE; ++ BOOTRAM[3559] = 0x05; ++ BOOTRAM[3560] = 0x90; ++ BOOTRAM[3561] = 0x00; ++ BOOTRAM[3562] = 0x0A; ++ BOOTRAM[3563] = 0xEF; ++ BOOTRAM[3564] = 0xF0; ++ BOOTRAM[3565] = 0x90; ++ BOOTRAM[3566] = 0x00; ++ BOOTRAM[3567] = 0x09; ++ BOOTRAM[3568] = 0xEE; ++ BOOTRAM[3569] = 0xF0; ++ BOOTRAM[3570] = 0x22; ++ BOOTRAM[3571] = 0x90; ++ BOOTRAM[3572] = 0x00; ++ BOOTRAM[3573] = 0x1F; ++ BOOTRAM[3574] = 0xE0; ++ BOOTRAM[3575] = 0xFF; ++ BOOTRAM[3576] = 0x90; ++ BOOTRAM[3577] = 0x00; ++ BOOTRAM[3578] = 0x1E; ++ BOOTRAM[3579] = 0xE0; ++ BOOTRAM[3580] = 0xFD; ++ BOOTRAM[3581] = 0xEF; ++ BOOTRAM[3582] = 0xFF; ++ BOOTRAM[3583] = 0xED; ++ BOOTRAM[3584] = 0xCF; ++ BOOTRAM[3585] = 0x8F; ++ BOOTRAM[3586] = 0xF0; ++ BOOTRAM[3587] = 0x02; ++ BOOTRAM[3588] = 0x04; ++ BOOTRAM[3589] = 0x57; ++ BOOTRAM[3590] = 0x90; ++ BOOTRAM[3591] = 0x00; ++ BOOTRAM[3592] = 0x00; ++ BOOTRAM[3593] = 0xE4; ++ BOOTRAM[3594] = 0xF0; ++ BOOTRAM[3595] = 0x90; ++ BOOTRAM[3596] = 0x00; ++ BOOTRAM[3597] = 0x08; ++ BOOTRAM[3598] = 0x04; ++ BOOTRAM[3599] = 0xF0; ++ BOOTRAM[3600] = 0xE4; ++ BOOTRAM[3601] = 0xF0; ++ BOOTRAM[3602] = 0x90; ++ BOOTRAM[3603] = 0x37; ++ BOOTRAM[3604] = 0x08; ++ BOOTRAM[3605] = 0x04; ++ BOOTRAM[3606] = 0xF0; ++ BOOTRAM[3607] = 0x22; ++ BOOTRAM[3608] = 0x12; ++ BOOTRAM[3609] = 0x0E; ++ BOOTRAM[3610] = 0x80; ++ BOOTRAM[3611] = 0x12; ++ BOOTRAM[3612] = 0x0E; ++ BOOTRAM[3613] = 0x67; ++ BOOTRAM[3614] = 0x12; ++ BOOTRAM[3615] = 0x0E; ++ BOOTRAM[3616] = 0xE9; ++ BOOTRAM[3617] = 0x90; ++ BOOTRAM[3618] = 0x37; ++ BOOTRAM[3619] = 0x00; ++ BOOTRAM[3620] = 0xE4; ++ BOOTRAM[3621] = 0xF0; ++ BOOTRAM[3622] = 0x02; ++ BOOTRAM[3623] = 0x0E; ++ BOOTRAM[3624] = 0x3A; ++ BOOTRAM[3625] = 0x7E; ++ BOOTRAM[3626] = 0x00; ++ BOOTRAM[3627] = 0x74; ++ BOOTRAM[3628] = 0x17; ++ BOOTRAM[3629] = 0x90; ++ BOOTRAM[3630] = 0x10; ++ BOOTRAM[3631] = 0x2A; ++ BOOTRAM[3632] = 0xF0; ++ BOOTRAM[3633] = 0xEE; ++ BOOTRAM[3634] = 0xA3; ++ BOOTRAM[3635] = 0xF0; ++ BOOTRAM[3636] = 0x90; ++ BOOTRAM[3637] = 0x10; ++ BOOTRAM[3638] = 0x29; ++ BOOTRAM[3639] = 0x04; ++ BOOTRAM[3640] = 0xF0; ++ BOOTRAM[3641] = 0x22; ++ BOOTRAM[3642] = 0x90; ++ BOOTRAM[3643] = 0x37; ++ BOOTRAM[3644] = 0x08; ++ BOOTRAM[3645] = 0x74; ++ BOOTRAM[3646] = 0x01; ++ BOOTRAM[3647] = 0xF0; ++ BOOTRAM[3648] = 0xA3; ++ BOOTRAM[3649] = 0x04; ++ BOOTRAM[3650] = 0xF0; ++ BOOTRAM[3651] = 0x90; ++ BOOTRAM[3652] = 0x37; ++ BOOTRAM[3653] = 0x0B; ++ BOOTRAM[3654] = 0x74; ++ BOOTRAM[3655] = 0x08; ++ BOOTRAM[3656] = 0xF0; ++ BOOTRAM[3657] = 0x22; ++ BOOTRAM[3658] = 0x90; ++ BOOTRAM[3659] = 0x00; ++ BOOTRAM[3660] = 0x08; ++ BOOTRAM[3661] = 0x74; ++ BOOTRAM[3662] = 0x01; ++ BOOTRAM[3663] = 0xF0; ++ BOOTRAM[3664] = 0xE4; ++ BOOTRAM[3665] = 0xF0; ++ BOOTRAM[3666] = 0x90; ++ BOOTRAM[3667] = 0x00; ++ BOOTRAM[3668] = 0x00; ++ BOOTRAM[3669] = 0xF0; ++ BOOTRAM[3670] = 0x74; ++ BOOTRAM[3671] = 0x21; ++ BOOTRAM[3672] = 0xF0; ++ BOOTRAM[3673] = 0x22; ++ BOOTRAM[3674] = 0x12; ++ BOOTRAM[3675] = 0x0D; ++ BOOTRAM[3676] = 0xC4; ++ BOOTRAM[3677] = 0x12; ++ BOOTRAM[3678] = 0x04; ++ BOOTRAM[3679] = 0x76; ++ BOOTRAM[3680] = 0x7F; ++ BOOTRAM[3681] = 0x01; ++ BOOTRAM[3682] = 0x7E; ++ BOOTRAM[3683] = 0x00; ++ BOOTRAM[3684] = 0x02; ++ BOOTRAM[3685] = 0x0E; ++ BOOTRAM[3686] = 0x95; ++ BOOTRAM[3687] = 0x90; ++ BOOTRAM[3688] = 0x08; ++ BOOTRAM[3689] = 0x00; ++ BOOTRAM[3690] = 0x74; ++ BOOTRAM[3691] = 0x08; ++ BOOTRAM[3692] = 0xF0; ++ BOOTRAM[3693] = 0x90; ++ BOOTRAM[3694] = 0x37; ++ BOOTRAM[3695] = 0x09; ++ BOOTRAM[3696] = 0x74; ++ BOOTRAM[3697] = 0x02; ++ BOOTRAM[3698] = 0xF0; ++ BOOTRAM[3699] = 0x22; ++ BOOTRAM[3700] = 0x90; ++ BOOTRAM[3701] = 0x00; ++ BOOTRAM[3702] = 0x05; ++ BOOTRAM[3703] = 0xEF; ++ BOOTRAM[3704] = 0xF0; ++ BOOTRAM[3705] = 0xA3; ++ BOOTRAM[3706] = 0xED; ++ BOOTRAM[3707] = 0xF0; ++ BOOTRAM[3708] = 0xA3; ++ BOOTRAM[3709] = 0xEB; ++ BOOTRAM[3710] = 0xF0; ++ BOOTRAM[3711] = 0x22; ++ BOOTRAM[3712] = 0x90; ++ BOOTRAM[3713] = 0x28; ++ BOOTRAM[3714] = 0x08; ++ BOOTRAM[3715] = 0xE4; ++ BOOTRAM[3716] = 0xF0; ++ BOOTRAM[3717] = 0xA3; ++ BOOTRAM[3718] = 0xF0; ++ BOOTRAM[3719] = 0xA3; ++ BOOTRAM[3720] = 0x04; ++ BOOTRAM[3721] = 0xF0; ++ BOOTRAM[3722] = 0x22; ++ BOOTRAM[3723] = 0xEF; ++ BOOTRAM[3724] = 0x60; ++ BOOTRAM[3725] = 0x03; ++ BOOTRAM[3726] = 0x02; ++ BOOTRAM[3727] = 0x09; ++ BOOTRAM[3728] = 0x58; ++ BOOTRAM[3729] = 0x12; ++ BOOTRAM[3730] = 0x0B; ++ BOOTRAM[3731] = 0x8C; ++ BOOTRAM[3732] = 0x22; ++ BOOTRAM[3733] = 0xEF; ++ BOOTRAM[3734] = 0x90; ++ BOOTRAM[3735] = 0x28; ++ BOOTRAM[3736] = 0x08; ++ BOOTRAM[3737] = 0xF0; ++ BOOTRAM[3738] = 0xEE; ++ BOOTRAM[3739] = 0xA3; ++ BOOTRAM[3740] = 0xF0; ++ BOOTRAM[3741] = 0x22; ++ BOOTRAM[3742] = 0x90; ++ BOOTRAM[3743] = 0x81; ++ BOOTRAM[3744] = 0x83; ++ BOOTRAM[3745] = 0xEE; ++ BOOTRAM[3746] = 0xF0; ++ BOOTRAM[3747] = 0xA3; ++ BOOTRAM[3748] = 0xEF; ++ BOOTRAM[3749] = 0xF0; ++ BOOTRAM[3750] = 0x22; ++ BOOTRAM[3751] = 0x90; ++ BOOTRAM[3752] = 0x00; ++ BOOTRAM[3753] = 0x00; ++ BOOTRAM[3754] = 0xE4; ++ BOOTRAM[3755] = 0xF0; ++ BOOTRAM[3756] = 0x74; ++ BOOTRAM[3757] = 0x11; ++ BOOTRAM[3758] = 0xF0; ++ BOOTRAM[3759] = 0x22; ++ BOOTRAM[3760] = 0x90; ++ BOOTRAM[3761] = 0x00; ++ BOOTRAM[3762] = 0x00; ++ BOOTRAM[3763] = 0xE4; ++ BOOTRAM[3764] = 0xF0; ++ BOOTRAM[3765] = 0x74; ++ BOOTRAM[3766] = 0x09; ++ BOOTRAM[3767] = 0xF0; ++ BOOTRAM[3768] = 0x22; ++ BOOTRAM[3769] = 0x90; ++ BOOTRAM[3770] = 0x00; ++ BOOTRAM[3771] = 0x00; ++ BOOTRAM[3772] = 0xE4; ++ BOOTRAM[3773] = 0xF0; ++ BOOTRAM[3774] = 0x74; ++ BOOTRAM[3775] = 0x21; ++ BOOTRAM[3776] = 0xF0; ++ BOOTRAM[3777] = 0x22; ++ BOOTRAM[3778] = 0x90; ++ BOOTRAM[3779] = 0x28; ++ BOOTRAM[3780] = 0x00; ++ BOOTRAM[3781] = 0xE0; ++ BOOTRAM[3782] = 0x44; ++ BOOTRAM[3783] = 0x01; ++ BOOTRAM[3784] = 0xF0; ++ BOOTRAM[3785] = 0x22; ++ BOOTRAM[3786] = 0x90; ++ BOOTRAM[3787] = 0x28; ++ BOOTRAM[3788] = 0x00; ++ BOOTRAM[3789] = 0xE0; ++ BOOTRAM[3790] = 0x54; ++ BOOTRAM[3791] = 0xFE; ++ BOOTRAM[3792] = 0xF0; ++ BOOTRAM[3793] = 0x22; ++ BOOTRAM[3794] = 0x90; ++ BOOTRAM[3795] = 0x28; ++ BOOTRAM[3796] = 0x0B; ++ BOOTRAM[3797] = 0xE0; ++ BOOTRAM[3798] = 0x44; ++ BOOTRAM[3799] = 0xA1; ++ BOOTRAM[3800] = 0xF0; ++ BOOTRAM[3801] = 0x22; ++ BOOTRAM[3802] = 0x7C; ++ BOOTRAM[3803] = 0x00; ++ BOOTRAM[3804] = 0x7D; ++ BOOTRAM[3805] = 0x1A; ++ BOOTRAM[3806] = 0x12; ++ BOOTRAM[3807] = 0x04; ++ BOOTRAM[3808] = 0x45; ++ BOOTRAM[3809] = 0x22; ++ BOOTRAM[3810] = 0x90; ++ BOOTRAM[3811] = 0x28; ++ BOOTRAM[3812] = 0x0A; ++ BOOTRAM[3813] = 0x74; ++ BOOTRAM[3814] = 0x01; ++ BOOTRAM[3815] = 0xF0; ++ BOOTRAM[3816] = 0x22; ++ BOOTRAM[3817] = 0x90; ++ BOOTRAM[3818] = 0x10; ++ BOOTRAM[3819] = 0x29; ++ BOOTRAM[3820] = 0x74; ++ BOOTRAM[3821] = 0x04; ++ BOOTRAM[3822] = 0xF0; ++ BOOTRAM[3823] = 0x22; ++ BOOTRAM[3824] = 0x3F; ++ BOOTRAM[3825] = 0x78; ++ BOOTRAM[3826] = 0x7D; ++ BOOTRAM[3827] = 0x01; ++ return BOOTRAM; ++} ++ ++EXPORT_SYMBOL(load_data_init); ++ +diff --git a/arch/arm/plat-goke/sd.c b/arch/arm/plat-goke/sd.c +new file mode 100644 +index 00000000..5c06c7e3 +--- /dev/null ++++ b/arch/arm/plat-goke/sd.c +@@ -0,0 +1,1196 @@ ++/* ++ * arch/arm/mach-gk/generic/sd.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* ==========================================================================*/ ++#ifdef MODULE_PARAM_PREFIX ++#undef MODULE_PARAM_PREFIX ++#endif ++#define MODULE_PARAM_PREFIX "gk_config." ++ ++extern u64 gk_dmamask; ++ ++/* ==========================================================================*/ ++typedef void (*mmc_dc_fn)(struct mmc_host *host, unsigned long delay); ++ ++static DEFINE_SPINLOCK(gk_sd0_int_lock); ++static u32 gk_sd0_int = 0; ++static u32 gk_sdio0_int = 0; ++#ifdef CONFIG_GK710XS_SDIO2 ++static DEFINE_SPINLOCK(gk_sd1_int_lock); ++static u32 gk_sd1_int = 0; ++static u32 gk_sdio1_int = 0; ++#endif ++ ++/*----------------------------------------------------------------------------*/ ++/* registers */ ++/*----------------------------------------------------------------------------*/ ++ ++/* ==========================================================================*/ ++struct resource gk_sd0_resources[] = { ++ [0] = { ++ .start = GK_VA_SDC, ++ .end = GK_VA_SDC + 0x0FFF, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = SD_IRQ, ++ .end = SD_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++void gk_sd0_slot1_request(void) ++{ ++ return; ++} ++ ++void gk_sd0_slot1_release(void) ++{ ++ //fio_unlock(SELECT_FIO_SD); ++ return; ++} ++ ++#if (SD_HAS_INTERNAL_MUXER == 1) ++void gk_sd_slot2_request(void) ++{ ++ //fio_select_lock(SELECT_FIO_SDIO); ++ return; ++} ++ ++void gk_sd_slot2_release(void) ++{ ++ //fio_unlock(SELECT_FIO_SDIO); ++ return; ++} ++#endif ++ ++int gk_sd0_is_enable(void) ++{ ++ return 1; ++} ++ ++void gk_sd0_set_int(u32 mask, u32 on) ++{ ++ unsigned long flags; ++ u32 int_flag; ++ ++ spin_lock_irqsave(&gk_sd0_int_lock, flags); ++ int_flag = gk_sd_readw(SD_NISEN_REG); ++ int_flag |= (gk_sd_readw(SD_EISEN_REG) << 16); ++ if (on) ++ int_flag |= mask; ++ else ++ int_flag &= ~mask; ++ gk_sd0_int = int_flag; ++ if (gk_sd0_is_enable()) { ++ gk_sd_writew(SD_NISEN_REG, int_flag); ++ gk_sd_writew(SD_EISEN_REG, int_flag >> 16); ++ gk_sd_writew(SD_NIXEN_REG, int_flag); ++ gk_sd_writew(SD_EIXEN_REG, int_flag >> 16); ++ } ++ spin_unlock_irqrestore(&gk_sd0_int_lock, flags); ++ return; ++} ++ ++int gk_sdio_is_enable(void) ++{ ++ return 1; ++} ++ ++void gk_sdio_set_int(u32 mask, u32 on) ++{ ++ unsigned long flags; ++ u32 int_flag; ++ ++ spin_lock_irqsave(&gk_sd0_int_lock, flags); ++ int_flag = gk_sd_readw(SD_NISEN_REG); ++ int_flag |= (gk_sd_readw(SD_EISEN_REG) << 16); ++ if (on) ++ int_flag |= mask; ++ else ++ int_flag &= ~mask; ++ gk_sdio0_int = int_flag; ++ if (gk_sdio_is_enable()) { ++ gk_sd_writew(SD_NISEN_REG, int_flag); ++ gk_sd_writew(SD_EISEN_REG, int_flag >> 16); ++ gk_sd_writew(SD_NIXEN_REG, int_flag); ++ gk_sd_writew(SD_EIXEN_REG, int_flag >> 16); ++ } ++ spin_unlock_irqrestore(&gk_sd0_int_lock, flags); ++} ++ ++struct gk_sd_controller gk_sd_controller0 = { ++#if (SD_HAS_INTERNAL_MUXER == 1) ++ .num_slots = 1, ++#else ++ .num_slots = 1, ++#endif ++ .slot[0] = { ++ .pmmc_host = NULL, ++ ++ .default_caps = MMC_CAP_4_BIT_DATA | ++ MMC_CAP_SDIO_IRQ | ++ MMC_CAP_ERASE | ++ MMC_CAP_BUS_WIDTH_TEST, ++ .active_caps = 0, ++ .default_caps2 = 0, ++ .active_caps2 = 0, ++ .private_caps = GK_SD_PRIVATE_CAPS_DTO_BY_SDCLK, ++ ++ .ext_power = { ++ .gpio_id = -1, ++ .active_level = GPIO_LOW, ++ .active_delay = 1, ++ }, ++ .ext_reset = { ++ .gpio_id = -1, ++ .active_level = GPIO_LOW, ++ .active_delay = 1, ++ }, ++ .fixed_cd = -1, ++#if (SD_HAS_INTERNAL_MUXER == 1) ++ .gpio_cd = { ++ .irq_gpio = -1, ++ .irq_line = SDCD_IRQ, ++ .irq_type = IRQ_TYPE_EDGE_BOTH, ++ .irq_gpio_val = GPIO_LOW, ++ .irq_gpio_mode = GPIO_TYPE_INPUT_SD_CD_N, ++ }, ++#else ++ .gpio_cd = { ++ .irq_gpio = -1, ++ .irq_line = -1, ++ .irq_type = -1, ++ .irq_gpio_val = GPIO_LOW, ++ .irq_gpio_mode = GPIO_FUNC_SW_INPUT, ++ }, ++#endif ++ .cd_delay = 100, ++ .fixed_wp = -1, ++ .gpio_wp = { ++ .gpio_id = -1, ++ .active_level = GPIO_HIGH, ++ .active_delay = 1, ++ }, ++ ++ .check_owner = gk_sd0_is_enable, ++ .request = gk_sd0_slot1_request, ++ .release = gk_sd0_slot1_release, ++ .set_int = gk_sd0_set_int, ++ .set_vdd = NULL, ++ .set_bus_timing = NULL, ++ }, ++#if (SD_HAS_INTERNAL_MUXER == 1) ++ .slot[1] = { ++ .pmmc_host = NULL, ++ ++ .default_caps = MMC_CAP_4_BIT_DATA | ++ MMC_CAP_SDIO_IRQ | ++ MMC_CAP_ERASE | ++ MMC_CAP_BUS_WIDTH_TEST, ++ .active_caps = 0, ++ .default_caps2 = 0, ++ .active_caps2 = 0, ++ .private_caps = GK_SD_PRIVATE_CAPS_DTO_BY_SDCLK, ++ ++ .ext_power = { ++ .gpio_id = -1, ++ .active_level = GPIO_LOW, ++ .active_delay = 1, ++ }, ++ .ext_reset = { ++ .gpio_id = -1, ++ .active_level = GPIO_LOW, ++ .active_delay = 1, ++ }, ++ .fixed_cd = -1, ++ .gpio_cd = { ++ .irq_gpio = -1, ++ .irq_line = -1, ++ .irq_type = -1, ++ .irq_gpio_val = GPIO_LOW, ++ .irq_gpio_mode = GPIO_FUNC_SW_INPUT, ++ }, ++ .cd_delay = 100, ++ .fixed_wp = -1, ++ .gpio_wp = { ++ .gpio_id = -1, ++ .active_level = GPIO_HIGH, ++ .active_delay = 1, ++ }, ++ ++ .check_owner = gk_sdio_is_enable, ++ .request = gk_sd_slot2_request, ++ .release = gk_sd_slot2_release, ++ .set_int = gk_sdio_set_int, ++ .set_vdd = NULL, ++ .set_bus_timing = NULL, ++ }, ++#endif ++ .set_pll = set_sd_rct, ++ .get_pll = get_sd_freq_hz, ++ ++ .max_blk_mask = SD_BLK_SZ_64KB, /*SD_BLK_SZ_128KB*/ ++ .max_clock = 48000000, ++ .active_clock = 0, ++ .wait_tmo = ((5 * HZ) / 2), ++ .pwr_delay = 1, ++ ++ .dma_fix = 0, ++#if (SD_SUPPORT_PLL_SCALER == 1) ++ .support_pll_scaler = 1, ++#else ++ .support_pll_scaler = 0, ++#endif ++}; ++ ++ ++struct platform_device gk_sd0 = { ++ .name = "gk-sd", ++ .id = 0, ++ .resource = gk_sd0_resources, ++ .num_resources = ARRAY_SIZE(gk_sd0_resources), ++ .dev = { ++ .platform_data = &gk_sd_controller0, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++ ++#ifdef CONFIG_GK710XS_SDIO2 ++struct resource gk_sd1_resources[] = { ++ [0] = { ++ .start = GK_VA_SDC1, ++ .end = GK_VA_SDC1 + 0x0FFF, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = SD1_IRQ, ++ .end = SD1_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++void gk_sd1_slot1_request(void) ++{ ++ return; ++} ++ ++void gk_sd1_slot1_release(void) ++{ ++ //fio_unlock(SELECT_FIO_SD); ++ return; ++} ++ ++#if (SD_HAS_INTERNAL_MUXER == 1) ++void gk_sd1_slot2_request(void) ++{ ++ //fio_select_lock(SELECT_FIO_SDIO); ++ return; ++} ++ ++void gk_sd1_slot2_release(void) ++{ ++ //fio_unlock(SELECT_FIO_SDIO); ++ return; ++} ++#endif ++ ++int gk_sd1_is_enable(void) ++{ ++ return 1; ++} ++ ++void gk_sd1_set_int(u32 mask, u32 on) ++{ ++ unsigned long flags; ++ u32 int_flag; ++ ++ spin_lock_irqsave(&gk_sd1_int_lock, flags); ++ int_flag = gk_sd_readw(SD1_NISEN_REG); ++ int_flag |= (gk_sd_readw(SD1_EISEN_REG) << 16); ++ if (on) ++ int_flag |= mask; ++ else ++ int_flag &= ~mask; ++ gk_sd1_int = int_flag; ++ if (gk_sd1_is_enable()) { ++ gk_sd_writew(SD1_NISEN_REG, int_flag); ++ gk_sd_writew(SD1_EISEN_REG, int_flag >> 16); ++ gk_sd_writew(SD1_NIXEN_REG, int_flag); ++ gk_sd_writew(SD1_EIXEN_REG, int_flag >> 16); ++ } ++ spin_unlock_irqrestore(&gk_sd1_int_lock, flags); ++ return; ++} ++ ++int gk_sdio2_is_enable(void) ++{ ++ return 1; ++} ++ ++void gk_sdio2_set_int(u32 mask, u32 on) ++{ ++ unsigned long flags; ++ u32 int_flag; ++ ++ spin_lock_irqsave(&gk_sd1_int_lock, flags); ++ int_flag = gk_sd_readw(SD1_NISEN_REG); ++ int_flag |= (gk_sd_readw(SD1_EISEN_REG) << 16); ++ if (on) ++ int_flag |= mask; ++ else ++ int_flag &= ~mask; ++ gk_sdio1_int = int_flag; ++ if (gk_sdio2_is_enable()) { ++ gk_sd_writew(SD1_NISEN_REG, int_flag); ++ gk_sd_writew(SD1_EISEN_REG, int_flag >> 16); ++ gk_sd_writew(SD1_NIXEN_REG, int_flag); ++ gk_sd_writew(SD1_EIXEN_REG, int_flag >> 16); ++ } ++ spin_unlock_irqrestore(&gk_sd1_int_lock, flags); ++} ++ ++struct gk_sd_controller gk_sd1_controller0 = { ++#if (SD_HAS_INTERNAL_MUXER == 1) ++ .num_slots = 1, ++#else ++ .num_slots = 1, ++#endif ++ .slot[0] = { ++ .pmmc_host = NULL, ++ ++ .default_caps = MMC_CAP_4_BIT_DATA | ++ MMC_CAP_SDIO_IRQ | ++ MMC_CAP_ERASE | ++ MMC_CAP_BUS_WIDTH_TEST, ++ .active_caps = 0, ++ .default_caps2 = 0, ++ .active_caps2 = 0, ++ .private_caps = GK_SD_PRIVATE_CAPS_DTO_BY_SDCLK, ++ ++ .ext_power = { ++ .gpio_id = -1, ++ .active_level = GPIO_LOW, ++ .active_delay = 1, ++ }, ++ .ext_reset = { ++ .gpio_id = -1, ++ .active_level = GPIO_LOW, ++ .active_delay = 1, ++ }, ++ .fixed_cd = -1, ++#if (SD_HAS_INTERNAL_MUXER == 1) ++ .gpio_cd = { ++ .irq_gpio = -1, ++ .irq_line = SD1CD_IRQ, ++ .irq_type = IRQ_TYPE_EDGE_BOTH, ++ .irq_gpio_val = GPIO_LOW, ++ .irq_gpio_mode = GPIO_FUNC_HW, ++ }, ++#else ++ .gpio_cd = { ++ .irq_gpio = -1, ++ .irq_line = -1, ++ .irq_type = -1, ++ .irq_gpio_val = GPIO_LOW, ++ .irq_gpio_mode = GPIO_TYPE_INPUT_SD_CD_N, ++ }, ++#endif ++ .cd_delay = 100, ++ .fixed_wp = -1, ++ .gpio_wp = { ++ .gpio_id = -1, ++ .active_level = GPIO_HIGH, ++ .active_delay = 1, ++ }, ++ ++ .check_owner = gk_sd1_is_enable, ++ .request = gk_sd1_slot1_request, ++ .release = gk_sd1_slot1_release, ++ .set_int = gk_sd1_set_int, ++ .set_vdd = NULL, ++ .set_bus_timing = NULL, ++ }, ++#if (SD_HAS_INTERNAL_MUXER == 1) ++ .slot[1] = { ++ .pmmc_host = NULL, ++ ++ .default_caps = MMC_CAP_4_BIT_DATA | ++ MMC_CAP_SDIO_IRQ | ++ MMC_CAP_ERASE | ++ MMC_CAP_BUS_WIDTH_TEST, ++ .active_caps = 0, ++ .default_caps2 = 0, ++ .active_caps2 = 0, ++ .private_caps = GK_SD_PRIVATE_CAPS_DTO_BY_SDCLK, ++ ++ .ext_power = { ++ .gpio_id = -1, ++ .active_level = GPIO_LOW, ++ .active_delay = 1, ++ }, ++ .ext_reset = { ++ .gpio_id = -1, ++ .active_level = GPIO_LOW, ++ .active_delay = 1, ++ }, ++ .fixed_cd = -1, ++ .gpio_cd = { ++ .irq_gpio = -1, ++ .irq_line = -1, ++ .irq_type = -1, ++ .irq_gpio_val = GPIO_LOW, ++ .irq_gpio_mode = GPIO_FUNC_SW_INPUT, ++ }, ++ .cd_delay = 100, ++ .fixed_wp = -1, ++ .gpio_wp = { ++ .gpio_id = -1, ++ .active_level = GPIO_HIGH, ++ .active_delay = 1, ++ }, ++ ++ .check_owner = gk_sdio2_is_enable, ++ .request = gk_sd1_slot2_request, ++ .release = gk_sd1_slot2_release, ++ .set_int = gk_sdio2_set_int, ++ .set_vdd = NULL, ++ .set_bus_timing = NULL, ++ }, ++#endif ++ .set_pll = set_sd_rct, ++ .get_pll = get_sd_freq_hz, ++ ++ .max_blk_mask = SD_BLK_SZ_64KB, /*SD_BLK_SZ_128KB*/ ++ .max_clock = 24000000, ++ .active_clock = 0, ++ .wait_tmo = ((5 * HZ) / 2), ++ .pwr_delay = 1, ++ ++ .dma_fix = 0, ++#if (SD_SUPPORT_PLL_SCALER == 1) ++ .support_pll_scaler = 1, ++#else ++ .support_pll_scaler = 0, ++#endif ++}; ++ ++ ++struct platform_device gk_sd1 = { ++ .name = "gk-sd", ++ .id = 1, ++ .resource = gk_sd1_resources, ++ .num_resources = ARRAY_SIZE(gk_sd1_resources), ++ .dev = { ++ .platform_data = &gk_sd1_controller0, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++#endif ++typedef union { /* SDIO_Control01Reg */ ++ u8 all; ++ struct { ++ u8 datatimeoutcountervalue : 4; ++ u8 : 4; ++ } bitc; ++} GH_SDIO_TMO_S; ++ ++typedef union { /* SDIO_Control01Reg */ ++ u8 all; ++ struct { ++ u8 softwareresetcmdline : 1; ++ u8 softwareresetall : 1; ++ u8 softwareresetdatline : 1; ++ u8 : 5; ++ } bitc; ++} GH_SDIO_RST_S; ++ ++typedef union { /* SDIO_Control01Reg */ ++ u16 all; ++ struct { ++ u16 internalclken : 1; ++ u16 internalclkstable : 1; ++ u16 sdclken : 1; ++ u16 : 5; ++ u16 sdclkfreselect : 8; ++ } bitc; ++} GH_SDIO_CLK_S; ++ ++typedef union { /* SDIO_Control00Reg */ ++ u8 all; ++ struct { ++ u8 ledcontrol : 1; ++ u8 datatrawidth : 1; ++ u8 sd8bitmode : 1; ++ u8 hostspeeden : 1; ++ u8 : 2; ++ u8 carddetecttestlevel : 1; ++ u8 carddetectsigdet : 1; ++ } bitc; ++} GH_SDIO_HOST_S; ++ ++typedef union { /* SDIO_Control00Reg */ ++ u8 all; ++ struct { ++ u8 sdbuspower : 1; ++ u8 sdbusvoltageselect : 3; ++ u8 : 4; ++ } bitc; ++} GH_SDIO_PWR_S; ++ ++void GH_SDIO_set_Control01Reg_SoftwareResetAll(u8 data) ++{ ++ GH_SDIO_RST_S d; ++ d.all = gk_sd_readb(SD_RESET_REG); ++ d.bitc.softwareresetall = data; ++ gk_sd_writeb(SD_RESET_REG, d.all); ++} ++ ++void GH_SDIO_set_Control01Reg_SoftwareResetCmdLine(u8 data) ++{ ++ GH_SDIO_RST_S d; ++ d.all = gk_sd_readb(SD_RESET_REG); ++ d.bitc.softwareresetcmdline = data; ++ gk_sd_writeb(SD_RESET_REG, d.all); ++} ++ ++void GH_SDIO_set_Control01Reg_SoftwareResetDatLine(u8 data) ++{ ++ GH_SDIO_RST_S d; ++ d.all = gk_sd_readb(SD_RESET_REG); ++ d.bitc.softwareresetdatline = data; ++ gk_sd_writeb(SD_RESET_REG, d.all); ++} ++ ++void GH_SDIO_set_Control01Reg_SdClkEn(u8 data) ++{ ++ GH_SDIO_CLK_S d; ++ d.all = gk_sd_readw(SD_CLK_REG); ++ d.bitc.sdclken = data; ++ gk_sd_writew(SD_CLK_REG, d.all); ++} ++ ++void GH_SDIO_set_Control01Reg_SdclkFreSelect(u8 data) ++{ ++ GH_SDIO_CLK_S d; ++ d.all = gk_sd_readw(SD_CLK_REG); ++ d.bitc.sdclkfreselect = data; ++ gk_sd_writew(SD_CLK_REG, d.all); ++} ++ ++void GH_SDIO_set_Control01Reg_InternalClkEn(u8 data) ++{ ++ GH_SDIO_CLK_S d; ++ d.all = gk_sd_readw(SD_CLK_REG); ++ d.bitc.internalclken = data; ++ gk_sd_writew(SD_CLK_REG, d.all); ++} ++ ++u16 GH_SDIO_get_Control01Reg(void) ++{ ++ u16 value = gk_sd_readw(SD_CLK_REG); ++ ++ return value; ++} ++ ++void GH_SDIO_set_Control00Reg_SdBusVoltageSelect(u8 data) ++{ ++ GH_SDIO_PWR_S d; ++ d.all = gk_sd_readb(SD_PWR_REG); ++ d.bitc.sdbusvoltageselect = data; ++ gk_sd_writeb(SD_PWR_REG, d.all); ++} ++ ++u32 GH_SDIO_get_CapReg(void) ++{ ++ u32 value = gk_sd_readl(SD_CAP_REG); ++ return value; ++} ++ ++void GH_SDIO_set_Control00Reg_SdBusPower(u8 data) ++{ ++ GH_SDIO_PWR_S d; ++ d.all = gk_sd_readb(SD_PWR_REG); ++ d.bitc.sdbuspower = data; ++ gk_sd_writeb(SD_PWR_REG, d.all); ++} ++ ++void GH_SDIO_set_Control01Reg_DataTimeoutCounterValue(u8 data) ++{ ++ GH_SDIO_TMO_S d; ++ d.all = gk_sd_readb(SD_TMO_REG); ++ d.bitc.datatimeoutcountervalue = data; ++ gk_sd_writeb(SD_TMO_REG, d.all); ++} ++ ++void GH_SDIO_set_Control00Reg_HostSpeedEn(u8 data) ++{ ++ GH_SDIO_HOST_S d; ++ d.all = gk_sd_readb(SD_HOST_REG); ++ d.bitc.hostspeeden = data; ++ gk_sd_writeb(SD_HOST_REG, d.all); ++} ++ ++void GH_SDIO_set_Control00Reg_DataTraWidth(u8 data) ++{ ++ GH_SDIO_HOST_S d; ++ d.all = gk_sd_readb(SD_HOST_REG); ++ d.bitc.datatrawidth = data; ++ gk_sd_writeb(SD_HOST_REG, d.all); ++} ++ ++void GH_SDIO_set_NorIntStatusReg(u16 data) ++{ ++ gk_sd_writew(SD_NIS_REG, data); ++} ++ ++u16 GH_SDIO_get_NorIntStatusReg(void) ++{ ++ u16 value = gk_sd_readw(SD_NIS_REG); ++ return value; ++} ++ ++void GH_SDIO_set_ErrIntStatusReg(u16 data) ++{ ++ gk_sd_writew(SD_EIS_REG, data); ++} ++ ++u16 GH_SDIO_get_ErrIntStatusReg(void) ++{ ++ u16 value = gk_sd_readw(SD_EIS_REG); ++ return value; ++} ++ ++void GH_SDIO_set_NorIntStatusEnReg(u16 data) ++{ ++ gk_sd_writew(SD_NISEN_REG, data); ++} ++ ++void GH_SDIO_set_ErrIntStatusEnReg(u16 data) ++{ ++ gk_sd_writew(SD_EISEN_REG, data); ++} ++ ++void GH_SDIO_set_NorIntSigEnReg(u16 data) ++{ ++ gk_sd_writew(SD_NIXEN_REG, data); ++} ++ ++void GH_SDIO_set_ErrIntSigEnReg(u16 data) ++{ ++ gk_sd_writew(SD_EIXEN_REG, data); ++} ++ ++#ifdef CONFIG_GK710XS_SDIO2 ++void GH_SDIO1_set_Control01Reg_SoftwareResetAll(u8 data) ++{ ++ GH_SDIO_RST_S d; ++ d.all = gk_sd_readb(SD1_RESET_REG); ++ d.bitc.softwareresetall = data; ++ gk_sd_writeb(SD1_RESET_REG, d.all); ++} ++ ++void GH_SDIO1_set_Control01Reg_SoftwareResetCmdLine(u8 data) ++{ ++ GH_SDIO_RST_S d; ++ d.all = gk_sd_readb(SD1_RESET_REG); ++ d.bitc.softwareresetcmdline = data; ++ gk_sd_writeb(SD1_RESET_REG, d.all); ++} ++ ++void GH_SDIO1_set_Control01Reg_SoftwareResetDatLine(u8 data) ++{ ++ GH_SDIO_RST_S d; ++ d.all = gk_sd_readb(SD1_RESET_REG); ++ d.bitc.softwareresetdatline = data; ++ gk_sd_writeb(SD1_RESET_REG, d.all); ++} ++ ++void GH_SDIO1_set_Control01Reg_SdClkEn(u8 data) ++{ ++ GH_SDIO_CLK_S d; ++ d.all = gk_sd_readw(SD1_CLK_REG); ++ d.bitc.sdclken = data; ++ gk_sd_writew(SD1_CLK_REG, d.all); ++} ++ ++void GH_SDIO1_set_Control01Reg_SdclkFreSelect(u8 data) ++{ ++ GH_SDIO_CLK_S d; ++ d.all = gk_sd_readw(SD1_CLK_REG); ++ d.bitc.sdclkfreselect = data; ++ gk_sd_writew(SD1_CLK_REG, d.all); ++} ++ ++void GH_SDIO1_set_Control01Reg_InternalClkEn(u8 data) ++{ ++ GH_SDIO_CLK_S d; ++ d.all = gk_sd_readw(SD1_CLK_REG); ++ d.bitc.internalclken = data; ++ gk_sd_writew(SD1_CLK_REG, d.all); ++} ++ ++u16 GH_SDIO1_get_Control01Reg(void) ++{ ++ u16 value = gk_sd_readw(SD1_CLK_REG); ++ ++ return value; ++} ++ ++void GH_SDIO1_set_Control00Reg_SdBusVoltageSelect(u8 data) ++{ ++ GH_SDIO_PWR_S d; ++ d.all = gk_sd_readb(SD1_PWR_REG); ++ d.bitc.sdbusvoltageselect = data; ++ gk_sd_writeb(SD1_PWR_REG, d.all); ++} ++ ++u32 GH_SDIO1_get_CapReg(void) ++{ ++ u32 value = gk_sd_readl(SD1_CAP_REG); ++ return value; ++} ++ ++void GH_SDIO1_set_Control00Reg_SdBusPower(u8 data) ++{ ++ GH_SDIO_PWR_S d; ++ d.all = gk_sd_readb(SD1_PWR_REG); ++ d.bitc.sdbuspower = data; ++ gk_sd_writeb(SD1_PWR_REG, d.all); ++} ++ ++void GH_SDIO1_set_Control01Reg_DataTimeoutCounterValue(u8 data) ++{ ++ GH_SDIO_TMO_S d; ++ d.all = gk_sd_readb(SD1_TMO_REG); ++ d.bitc.datatimeoutcountervalue = data; ++ gk_sd_writeb(SD1_TMO_REG, d.all); ++} ++ ++void GH_SDIO1_set_Control00Reg_HostSpeedEn(u8 data) ++{ ++ GH_SDIO_HOST_S d; ++ d.all = gk_sd_readb(SD1_HOST_REG); ++ d.bitc.hostspeeden = data; ++ gk_sd_writeb(SD1_HOST_REG, d.all); ++} ++ ++void GH_SDIO1_set_Control00Reg_DataTraWidth(u8 data) ++{ ++ GH_SDIO_HOST_S d; ++ d.all = gk_sd_readb(SD1_HOST_REG); ++ d.bitc.datatrawidth = data; ++ gk_sd_writeb(SD1_HOST_REG, d.all); ++} ++ ++void GH_SDIO1_set_NorIntStatusReg(u16 data) ++{ ++ gk_sd_writew(SD1_NIS_REG, data); ++} ++ ++u16 GH_SDIO1_get_NorIntStatusReg(void) ++{ ++ u16 value = gk_sd_readw(SD1_NIS_REG); ++ return value; ++} ++ ++void GH_SDIO1_set_ErrIntStatusReg(u16 data) ++{ ++ gk_sd_writew(SD1_EIS_REG, data); ++} ++ ++u16 GH_SDIO1_get_ErrIntStatusReg(void) ++{ ++ u16 value = gk_sd_readw(SD1_EIS_REG); ++ return value; ++} ++ ++void GH_SDIO1_set_NorIntStatusEnReg(u16 data) ++{ ++ gk_sd_writew(SD1_NISEN_REG, data); ++} ++ ++void GH_SDIO1_set_ErrIntStatusEnReg(u16 data) ++{ ++ gk_sd_writew(SD1_EISEN_REG, data); ++} ++ ++void GH_SDIO1_set_NorIntSigEnReg(u16 data) ++{ ++ gk_sd_writew(SD1_NIXEN_REG, data); ++} ++ ++void GH_SDIO1_set_ErrIntSigEnReg(u16 data) ++{ ++ gk_sd_writew(SD1_EIXEN_REG, data); ++} ++ ++void gk_set_sd1_detect_pin(u32 gpio_pin) ++{ ++ gk_sd1_controller0.slot[0].gpio_cd.irq_gpio = gpio_pin; ++} ++ ++#endif ++ ++static void sdioSoftReset(u8 index) ++{ ++ if(index == 0) ++ { ++ GH_SDIO_set_Control01Reg_SoftwareResetAll(1); ++ GH_SDIO_set_Control01Reg_SoftwareResetCmdLine(1); ++ GH_SDIO_set_Control01Reg_SoftwareResetDatLine(1); ++ } ++#ifdef CONFIG_GK710XS_SDIO2 ++ else if(index ==1) ++ { ++ GH_SDIO1_set_Control01Reg_SoftwareResetAll(1); ++ GH_SDIO1_set_Control01Reg_SoftwareResetCmdLine(1); ++ GH_SDIO1_set_Control01Reg_SoftwareResetDatLine(1); ++ } ++#endif ++} ++ ++static void sdioClockOnOff(u8 index, u32 on) ++{ ++ if(index == 0) ++ { ++ if (on == 0) ++ { ++ GH_SDIO_set_Control01Reg_SdClkEn(0); ++ } ++ else ++ { ++ GH_SDIO_set_Control01Reg_SdClkEn(1); ++ } ++ } ++#ifdef CONFIG_GK710XS_SDIO2 ++ else if(index == 1) ++ { ++ if (on == 0) ++ { ++ GH_SDIO1_set_Control01Reg_SdClkEn(0); ++ } ++ else ++ { ++ GH_SDIO1_set_Control01Reg_SdClkEn(1); ++ } ++ } ++#endif ++} ++ ++static void sdioSelectVoltage(u8 index) ++{ ++ u32 caps; ++ if(index == 0) ++ { ++ caps=GH_SDIO_get_CapReg(); ++ ++ if(caps & 0x1<<24) ++ { ++ GH_SDIO_set_Control00Reg_SdBusVoltageSelect(0x7); ++ GH_SDIO_set_Control00Reg_SdBusPower(1); ++ ++ } ++ else if(caps & 0x1<<25) ++ { ++ GH_SDIO_set_Control00Reg_SdBusVoltageSelect(0x6); ++ GH_SDIO_set_Control00Reg_SdBusPower(1); ++ } ++ else if(caps & 0x1<<26) ++ { ++ GH_SDIO_set_Control00Reg_SdBusVoltageSelect(0x5); ++ GH_SDIO_set_Control00Reg_SdBusPower(1); ++ } ++ } ++#ifdef CONFIG_GK710XS_SDIO2 ++ else if(index == 1) ++ { ++ caps=GH_SDIO1_get_CapReg(); ++ ++ if(caps & 0x1<<24) ++ { ++ GH_SDIO1_set_Control00Reg_SdBusVoltageSelect(0x7); ++ GH_SDIO1_set_Control00Reg_SdBusPower(1); ++ ++ } ++ else if(caps & 0x1<<25) ++ { ++ GH_SDIO1_set_Control00Reg_SdBusVoltageSelect(0x6); ++ GH_SDIO1_set_Control00Reg_SdBusPower(1); ++ } ++ else if(caps & 0x1<<26) ++ { ++ GH_SDIO1_set_Control00Reg_SdBusVoltageSelect(0x5); ++ GH_SDIO1_set_Control00Reg_SdBusPower(1); ++ } ++ } ++#endif ++} ++ ++static void sdioSetClockDiv(u8 index, u8 div) ++{ ++ if(index == 0) ++ { ++ GH_SDIO_set_Control01Reg_SdclkFreSelect(div); ++ GH_SDIO_set_Control01Reg_InternalClkEn(1); ++ ++ while(1) ++ { ++ if((GH_SDIO_get_Control01Reg() & (0x1<<1))) ++ break; ++ } ++ sdioClockOnOff(index, 1); ++ } ++#ifdef CONFIG_GK710XS_SDIO2 ++ else if(index == 1) ++ { ++ GH_SDIO1_set_Control01Reg_SdclkFreSelect(div); ++ GH_SDIO1_set_Control01Reg_InternalClkEn(1); ++ ++ while(1) ++ { ++ if((GH_SDIO1_get_Control01Reg() & (0x1<<1))) ++ break; ++ } ++ sdioClockOnOff(index, 1); ++ } ++#endif ++} ++ ++static void sdioSetTimeoutControl(u8 index, u8 timeout) ++{ ++ if(index == 0) ++ { ++ GH_SDIO_set_Control01Reg_DataTimeoutCounterValue(timeout); ++ } ++#ifdef CONFIG_GK710XS_SDIO2 ++ else if(index == 1) ++ { ++ GH_SDIO1_set_Control01Reg_DataTimeoutCounterValue(timeout); ++ } ++#endif ++} ++ ++static void sdioSetHostctlSpeed(u8 index, u8 mode) ++{ ++ if(index == 0) ++ { ++ GH_SDIO_set_Control00Reg_HostSpeedEn(mode); ++ } ++#ifdef CONFIG_GK710XS_SDIO2 ++ else if(index == 1) ++ { ++ GH_SDIO1_set_Control00Reg_HostSpeedEn(mode); ++ } ++#endif ++} ++ ++static void sdioSetHostctlWidth(u8 index, u8 mode) ++{ ++ if(index == 0) ++ { ++ GH_SDIO_set_Control00Reg_DataTraWidth(mode); ++ } ++#ifdef CONFIG_GK710XS_SDIO2 ++ else if(index == 1) ++ { ++ GH_SDIO1_set_Control00Reg_DataTraWidth(mode); ++ } ++#endif ++} ++ ++#define SDIO_INT_STATUS_EN (1 | 1<<1 | 1<<3 | 1<<4 |1<<5 | 1<<6 | 1<<7) ++#define SDIO_INT_SIG_EN (1 | 1<<1 | 1<<3 | 1<<4 |1<<5 | 1<<6 | 1<<7) ++static void sdioEnableIntStatus(u8 index) ++{ ++ /*clear int*/ ++ if(index == 0) ++ { ++ if(GH_SDIO_get_NorIntStatusReg() & (0x1 << 15)) ++ { ++ GH_SDIO_set_ErrIntStatusReg(GH_SDIO_get_ErrIntStatusReg()); ++ } ++ ++ GH_SDIO_set_NorIntStatusEnReg(0x0); ++ GH_SDIO_set_NorIntStatusEnReg(SDIO_INT_STATUS_EN); ++ GH_SDIO_set_ErrIntStatusEnReg(0xffff); ++ } ++#ifdef CONFIG_GK710XS_SDIO2 ++ else if(index == 1) ++ { ++ if(GH_SDIO1_get_NorIntStatusReg() & (0x1 << 15)) ++ { ++ GH_SDIO1_set_ErrIntStatusReg(GH_SDIO1_get_ErrIntStatusReg()); ++ } ++ ++ GH_SDIO1_set_NorIntStatusEnReg(0x0); ++ GH_SDIO1_set_NorIntStatusEnReg(SDIO_INT_STATUS_EN); ++ GH_SDIO1_set_ErrIntStatusEnReg(0xffff); ++ } ++#endif ++} ++ ++static void sdioEnableIntSig(u8 index) ++{ ++ if(index == 0) ++ { ++ GH_SDIO_set_NorIntSigEnReg(0); ++ GH_SDIO_set_NorIntSigEnReg(SDIO_INT_SIG_EN); ++ GH_SDIO_set_ErrIntSigEnReg(0xffff); ++ } ++#ifdef CONFIG_GK710XS_SDIO2 ++ else if(index == 1) ++ { ++ GH_SDIO1_set_NorIntSigEnReg(0); ++ GH_SDIO1_set_NorIntSigEnReg(SDIO_INT_SIG_EN); ++ GH_SDIO1_set_ErrIntSigEnReg(0xffff); ++ } ++#endif ++} ++ ++static void GD_SDIO_Rest(u8 index) ++{ ++ sdioSoftReset(index); ++ sdioClockOnOff(index, 0); ++ sdioSetClockDiv(index, 0x00); ++ sdioSelectVoltage(index); ++ sdioSetTimeoutControl(index, 0xe); ++ sdioSetHostctlSpeed(index, 0); ++ sdioSetHostctlWidth(index, 1); ++ /*clear interrupt status*/ ++ if(index == 0) ++ { ++ GH_SDIO_set_NorIntStatusReg(GH_SDIO_get_NorIntStatusReg()); ++ GH_SDIO_set_ErrIntStatusReg(GH_SDIO_get_ErrIntStatusReg()); ++ } ++#ifdef CONFIG_GK710XS_SDIO2 ++ else if(index == 1) ++ { ++ GH_SDIO1_set_NorIntStatusReg(GH_SDIO1_get_NorIntStatusReg()); ++ GH_SDIO1_set_ErrIntStatusReg(GH_SDIO1_get_ErrIntStatusReg()); ++ } ++#endif ++ sdioEnableIntStatus(index); ++ sdioEnableIntSig(index); ++} ++ ++int __init gk_init_sd(void) ++{ ++ int retval = 0; ++ ++ GD_SDIO_Rest(0); ++#ifdef CONFIG_GK710XS_SDIO2 ++ GD_SDIO_Rest(1); ++#endif ++ return retval; ++} ++ ++void gk_set_sd_detect_pin(u32 gpio_pin) ++{ ++ gk_sd_controller0.slot[0].gpio_cd.irq_gpio = gpio_pin; ++} ++ ++void gk_detect_sd_slot(int bus, int slot, int fixed_cd) ++{ ++ struct gk_sd_slot *pslotinfo = NULL; ++ mmc_dc_fn mmc_dc = NULL; ++ ++ printk("%s:%d[%d:%d:%d]\n", __func__, __LINE__, bus, slot, fixed_cd); ++ if ((bus == 0) && (slot == 0)) { ++ pslotinfo = &gk_sd_controller0.slot[0]; ++ } ++#if (SD_HAS_INTERNAL_MUXER == 1) ++ if ((bus == 0) && (slot == 1)) { ++ pslotinfo = &gk_sd_controller0.slot[1]; ++ } ++#endif ++ ++ ++#if defined(CONFIG_MMC) ++ mmc_dc = mmc_detect_change; ++#else ++#if defined(CONFIG_KALLSYMS) ++ mmc_dc = (mmc_dc_fn)module_kallsyms_lookup_name("mmc_detect_change"); ++#endif ++#endif ++ if (pslotinfo && mmc_dc && pslotinfo->pmmc_host) { ++ pslotinfo->fixed_cd = fixed_cd; ++ mmc_dc(pslotinfo->pmmc_host, pslotinfo->cd_delay); ++ printk("%s:%d[%p:%p:%p:%d]\n", __func__, __LINE__, pslotinfo, ++ mmc_dc, pslotinfo->pmmc_host, pslotinfo->cd_delay); ++ } ++} ++EXPORT_SYMBOL(gk_detect_sd_slot); ++ ++#ifdef CONFIG_GK710XS_SDIO2 ++void gk_detect_sd1_slot(int bus, int slot, int fixed_cd) ++{ ++ struct gk_sd_slot *pslotinfo = NULL; ++ mmc_dc_fn mmc_dc = NULL; ++ ++ printk("%s:%d[%d:%d:%d]\n", __func__, __LINE__, bus, slot, fixed_cd); ++ if ((bus == 0) && (slot == 0)) { ++ pslotinfo = &gk_sd1_controller0.slot[0]; ++ } ++#if (SD_HAS_INTERNAL_MUXER == 1) ++ if ((bus == 0) && (slot == 1)) { ++ pslotinfo = &gk_sd1_controller0.slot[1]; ++ } ++#endif ++ ++ ++#if defined(CONFIG_MMC) ++ mmc_dc = mmc_detect_change; ++#else ++#if defined(CONFIG_KALLSYMS) ++ mmc_dc = (mmc_dc_fn)module_kallsyms_lookup_name("mmc_detect_change"); ++#endif ++#endif ++ if (pslotinfo && mmc_dc && pslotinfo->pmmc_host) { ++ pslotinfo->fixed_cd = fixed_cd; ++ mmc_dc(pslotinfo->pmmc_host, pslotinfo->cd_delay); ++ printk("%s:%d[%p:%p:%p:%d]\n", __func__, __LINE__, pslotinfo, ++ mmc_dc, pslotinfo->pmmc_host, pslotinfo->cd_delay); ++ } ++} ++EXPORT_SYMBOL(gk_detect_sd1_slot); ++#endif ++ ++ +diff --git a/arch/arm/plat-goke/switch.c b/arch/arm/plat-goke/switch.c +new file mode 100644 +index 00000000..9523784a +--- /dev/null ++++ b/arch/arm/plat-goke/switch.c +@@ -0,0 +1,495 @@ ++/*! ++***************************************************************************** ++** \file arch/arm/mach-gk/switch.c ++** ++** \version ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++#include ++ ++ ++#define GK_USB_SWITCH_NAME "usb_switch" ++#define GK_AUDIO_SWITCH_NAME "audio_switch" ++#define GK_CVBS_SWITCH_NAME "cvbs_switch" ++#define GK_PHY_SWITCH_NAME "phy_switch" ++#define GK_ADC_SWITCH_NAME "adc_switch" ++#define BUFER_COUNT 50 ++#define CHECK_COUNT {if(count>=(BUFER_COUNT-1))count=(BUFER_COUNT-1);} ++ ++static u8 usb_status = 1; ++static int usb_read_proc(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int ret = 0; ++ int len = 0; ++ ++ if (off) ++ { ++ *eof = 1; ++ return ret; ++ } ++ ++ len = sprintf(page, "%s\n", usb_status==0?"off":"on"); ++ ++ return len; ++} ++ ++static int usb_write_proc(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ int retval = 0; ++ char buf[BUFER_COUNT]; ++ ++ CHECK_COUNT; ++ if (copy_from_user(buf, buffer, count)) { ++ retval = -EFAULT; ++ } ++ ++ switch(buf[0]) ++ { ++ case '0': ++ usb_status = 0; ++ gk_usb_setbitsl(GK_VA_USB_PHY, 0x0000FFC4); ++ break; ++ case '1': ++ usb_status = 1; ++ gk_usb_clrbitsl(GK_VA_USB_PHY, 0x0000FFC4); ++ break; ++ } ++ return count; ++} ++ ++static int create_usb_proc_node(void) ++{ ++ int err_code = 0; ++ struct proc_dir_entry *usb_entry; ++ ++ usb_entry = create_proc_entry(GK_USB_SWITCH_NAME, S_IRUGO | S_IWUGO, get_gk_proc_dir()); ++ ++ if (!usb_entry) ++ { ++ err_code = -EINVAL; ++ } ++ else ++ { ++ usb_entry->read_proc = usb_read_proc; ++ usb_entry->write_proc = usb_write_proc; ++ } ++ ++ return err_code; ++} ++ ++static u8 audio_status = 1; ++static int audio_read_proc(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int ret = 0; ++ int len = 0; ++ ++ if (off) ++ { ++ *eof = 1; ++ return ret; ++ } ++ ++ audio_status = gk_aud_readl(AUDC_ANALOG_CTRL00_REG); ++ len = sprintf(page, "%s\n", audio_status==0?"off":"on"); ++ ++ return len; ++} ++ ++static int audio_write_proc(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ int retval = 0; ++ char buf[BUFER_COUNT]; ++ u32 addr = 0; ++ ++ CHECK_COUNT; ++ if (copy_from_user(buf, buffer, count)) { ++ retval = -EFAULT; ++ } ++ ++ switch(buf[0]) ++ { ++ case '0': ++ // 0x90022474 set to 0x000003FF ++ // Audio ++ //0x90021C00~0x90021C34 address space clear (0) ++ //0x90020C00~0x90020D6C address space clear (0) ++ for(addr = GK_VA_AUDIO_CODEC_ANALOG; addr <= (GK_VA_AUDIO_CODEC_ANALOG + 0x34); addr+=4) ++ { ++ //printk("[%s] 0x%08x=0x%08x\n", __func__, addr, gk_readl(addr)); ++ gk_aud_writel( addr, 0x00000000); ++ } ++ for(addr = GK_VA_AUDIO_CODEC_DIGITAL; addr <= (GK_VA_AUDIO_CODEC_DIGITAL + 0x16C); addr+=4) ++ { ++ //printk("[%s] 0x%08x=0x%08x\n", __func__, addr, gk_readl(addr)); ++ gk_aud_writel( addr, 0x00000000); ++ } ++ audio_status = 0; ++ break; ++ case '1': ++ // 0x90022474 set to 0x000003FF ++ gk_aud_writel(AUDC_ANALOG_CTRL00_REG, 0x8040); ++ gk_aud_writel(AUDC_ANALOG_CTRL03_REG, 0x4004); ++ gk_aud_writel(AUDC_ANALOG_CTRL04_REG, 0x2000); ++ gk_aud_writel(AUDC_ANALOG_CTRL06_REG, 0x4); ++ gk_aud_writel(AUDC_ANALOG_CTRL11_REG, 0x0); ++ gk_aud_writel(AUDC_ANALOG_CTRL13_REG, 0x6000); ++ gk_aud_writel(AUDC_ANALOG_CTRL00_REG, 0x8040); ++ gk_aud_writel(AUDC_ANALOG_CTRL03_REG, 0x401c); ++ gk_aud_writel(AUDC_ANALOG_CTRL04_REG, 0x233a); ++ gk_aud_writel(AUDC_ANALOG_CTRL05_REG, 0x280c); ++ gk_aud_writel(AUDC_ANALOG_CTRL06_REG, 0x8407); ++ gk_aud_writel(AUDC_ANALOG_CTRL07_REG, 0x3802); ++ gk_aud_writel(AUDC_ANALOG_CTRL08_REG, 0xf8); ++ gk_aud_writel(AUDC_ANALOG_CTRL09_REG, 0x0); ++ gk_aud_writel(AUDC_ANALOG_CTRL10_REG, 0xc0c0); ++ gk_aud_writel(AUDC_ANALOG_CTRL11_REG, 0x9080); ++ gk_aud_writel(AUDC_ANALOG_CTRL12_REG, 0x0); ++ gk_aud_writel(AUDC_ANALOG_CTRL13_REG, 0x6000); ++ gk_aud_writel(AUDC_DIGITAL_MMP1_DPGA_CFG1_REG, 0x5); ++ gk_aud_writel(AUDC_DIGITAL_MMP2_DPGA_CFG1_REG, 0x5); ++ gk_aud_writel(AUDC_DIGITAL_SYS_RST_CTRL0_REG, 0xe000); ++ gk_aud_writel(AUDC_DIGITAL_SYS_RST_CTRL0_REG, 0x0); ++ gk_aud_writel(AUDC_DIGITAL_AUDIOBAND_CTRL0_REG, 0x2); ++ gk_aud_writel(AUDC_DIGITAL_CKG_CTRL0_REG, 0x3); ++ gk_aud_writel(AUDC_DIGITAL_TIMING_CTRL0_REG, 0x33f); ++ gk_aud_writel(AUDC_DIGITAL_TIMING_CTRL1_REG, 0xf3e); ++ gk_aud_writel(AUDC_DIGITAL_AUDIOBAND_CTRL2_REG, 0xfaaf); ++ gk_aud_writel(AUDC_DIGITAL_SDM_CTRL0_REG, 0x15); ++ gk_aud_writel(AUDC_DIGITAL_MMP1_DPGA_CFG1_REG, 0x0); ++ gk_aud_writel(AUDC_DIGITAL_MMP2_DPGA_CFG1_REG, 0x0); ++ gk_aud_writel(AUDC_DIGITAL_TIMING_CTRL0_REG, 0x23f); ++ gk_aud_writel(AUDC_DIGITAL_MIX_CTRL0_REG, 0x2500); ++ gk_aud_writel(AUDC_DIGITAL_TIMING_CTRL1_REG, 0x23e); ++ gk_aud_writel(AUDC_DIGITAL_AUDIOBAND_CTRL1_REG, 0xea82); ++ gk_aud_writel(AUDC_DIGITAL_AUDIOBAND_CTRL2_REG, 0xaaaf); ++ gk_aud_writel(AUDC_ANALOG_CTRL02_REG, 0x8); ++ gk_aud_writel(AUDC_DIGITAL_NF_SYNTH_1_NF_H_REG, 0x000000BB); ++ gk_aud_writel(AUDC_DIGITAL_NF_SYNTH_1_NF_L_REG, 0x00008000); ++ mdelay(1); ++ gk_aud_writel(AUDC_DIGITAL_NF_SYNTH_1_NF_H_REG, 0x0000C0BB); ++ mdelay(1); ++ gk_aud_writel(AUDC_DIGITAL_NF_SYNTH_1_NF_H_REG, 0x000000BB); ++ gk_aud_writel(AUDC_DIGITAL_NF_SYNTH_2_NF_H_REG, 0x000000c0); ++ gk_aud_writel(AUDC_DIGITAL_NF_SYNTH_2_NF_L_REG, 0x00000000); ++ mdelay(1); ++ gk_aud_writel(AUDC_DIGITAL_NF_SYNTH_2_NF_H_REG, 0x0000c0c0); ++ mdelay(1); ++ gk_aud_writel(AUDC_DIGITAL_NF_SYNTH_2_NF_H_REG, 0x0000c0); ++ gk_aud_writel(AUDC_DIGITAL_FIFO_TH_CTRL0_REG, 0x402); ++ gk_aud_writel(AUDC_DIGITAL_FIFO_CTRL_REG, 0x8808); ++ gk_aud_writel(AUDC_DIGITAL_FIFO_CTRL_REG, 0x8888); ++ gk_greg_writel(AHB_GENNERNAL1_REG, 0x00000001); ++ audio_status = 1; ++ break; ++ } ++ return count; ++} ++ ++static int create_audio_proc_node(void) ++{ ++ int err_code = 0; ++ struct proc_dir_entry *audio_entry; ++ ++ audio_entry = create_proc_entry(GK_AUDIO_SWITCH_NAME, S_IRUGO | S_IWUGO, get_gk_proc_dir()); ++ ++ if (!audio_entry) ++ { ++ err_code = -EINVAL; ++ } ++ else ++ { ++ audio_entry->read_proc = audio_read_proc; ++ audio_entry->write_proc = audio_write_proc; ++ } ++ ++ return err_code; ++} ++ ++static int cvbs_read_proc(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int ret = 0; ++ int len = 0; ++ u32 cvbs_status; ++ ++ if (off) ++ { ++ *eof = 1; ++ return ret; ++ } ++ cvbs_status = gk_vout_readl(GK_VA_VEDIO_DAC); ++ cvbs_status &= 0x00000001; ++ len = sprintf(page, "%s\n", cvbs_status==0?"off":"on"); ++ ++ return len; ++} ++ ++static int cvbs_write_proc(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ int retval = 0; ++ char buf[BUFER_COUNT]; ++ CHECK_COUNT; ++ ++ if (copy_from_user(buf, buffer, count)) { ++ retval = -EFAULT; ++ } ++ ++ switch(buf[0]) ++ { ++ case '0': ++ gk_vout_clrbitsl(GK_VA_VEDIO_DAC, 0x00000001); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x04, 0x00); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x08, 0x00); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x10, 0x00); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x14, 0x00); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x18, 0x00); ++ break; ++ case '1': ++ gk_vout_setbitsl(GK_VA_VEDIO_DAC, 0x00000001); ++ //config video DAC for CVBS ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x00, 0x01); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x04, 0x01); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x08, 0x00); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x10, 0x01); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x14, 0x01); ++ gk_vout_writel( GK_VA_VEDIO_DAC + 0x18, 0x3F); ++ break; ++ } ++ return count; ++} ++ ++static int create_cvbs_proc_node(void) ++{ ++ int err_code = 0; ++ struct proc_dir_entry *cvbs_entry; ++ ++ cvbs_entry = create_proc_entry(GK_CVBS_SWITCH_NAME, S_IRUGO | S_IWUGO, get_gk_proc_dir()); ++ ++ if (!cvbs_entry) ++ { ++ err_code = -EINVAL; ++ } ++ else ++ { ++ cvbs_entry->read_proc = cvbs_read_proc; ++ cvbs_entry->write_proc = cvbs_write_proc; ++ } ++ ++ return err_code; ++} ++ ++static int phy_read_proc(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int ret = 0; ++ int len = 0; ++ u32 phy_status; ++ if (off) ++ { ++ *eof = 1; ++ return ret; ++ } ++ phy_status = gk_eth_readl(GK_VA_ETH_PHY + 0x474); ++ len = sprintf(page, "%s\n", phy_status==0x000003FF?"off":"on"); ++ ++ return len; ++} ++ ++static int phy_write_proc(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ int retval = 0; ++ char buf[BUFER_COUNT]; ++ CHECK_COUNT; ++ ++ if (copy_from_user(buf, buffer, count)) { ++ retval = -EFAULT; ++ } ++ ++ switch(buf[0]) ++ { ++ case '0': ++ // 0x90022474 set to 0x000003FF ++ gk_eth_writel(GK_VA_ETH_PHY + 0x474, 0x000003FF); ++ break; ++ case '1': ++ // 0x90022474 set to 0x000003FF ++ gk_eth_writel(GK_VA_ETH_PHY + 0x474, 0x00000000); ++ break; ++ } ++ return count; ++} ++ ++static int create_phy_proc_node(void) ++{ ++ int err_code = 0; ++ struct proc_dir_entry *phy_entry; ++ ++ phy_entry = create_proc_entry(GK_PHY_SWITCH_NAME, S_IRUGO | S_IWUGO, get_gk_proc_dir()); ++ ++ if (!phy_entry) ++ { ++ err_code = -EINVAL; ++ } ++ else ++ { ++ phy_entry->read_proc = phy_read_proc; ++ phy_entry->write_proc = phy_write_proc; ++ } ++ ++ return err_code; ++} ++ ++static int adc_read_proc(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int ret = 0; ++ int len = 0; ++ u32 adc_status; ++ if (off) ++ { ++ *eof = 1; ++ return ret; ++ } ++ adc_status = gk_adc_readl(GK_VA_ADC + 0x00); ++ len = sprintf(page, "%s\n", adc_status&0x00000001?"off":"on"); ++ ++ return len; ++} ++ ++static int adc_write_proc(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ int retval = 0; ++ char buf[BUFER_COUNT]; ++ CHECK_COUNT; ++ ++ if (copy_from_user(buf, buffer, count)) { ++ retval = -EFAULT; ++ } ++ ++ switch(buf[0]) ++ { ++ case '0': ++ gk_vout_setbitsl(GK_VA_ADC + 0x00, 0x00000001); ++ gk_vout_clrbitsl(GK_VA_ADC2 + 0x18, 0x00000001); ++ break; ++ case '1': ++ gk_vout_clrbitsl(GK_VA_ADC + 0x00, 0x00000001); ++ gk_vout_setbitsl(GK_VA_ADC2 + 0x18, 0x00000001); ++ break; ++ } ++ return count; ++} ++ ++static int create_adc_proc_node(void) ++{ ++ int err_code = 0; ++ struct proc_dir_entry *adc_entry; ++ ++ adc_entry = create_proc_entry(GK_ADC_SWITCH_NAME, S_IRUGO | S_IWUGO, get_gk_proc_dir()); ++ ++ if (!adc_entry) ++ { ++ err_code = -EINVAL; ++ } ++ else ++ { ++ adc_entry->read_proc = adc_read_proc; ++ adc_entry->write_proc = adc_write_proc; ++ } ++ ++ return err_code; ++} ++ ++static int __init switch_init(void) ++{ ++ create_usb_proc_node(); ++ create_audio_proc_node(); ++ create_cvbs_proc_node(); ++ create_phy_proc_node(); ++ create_adc_proc_node(); ++ return 0; ++} ++ ++static void __exit switch_exit(void) ++{ ++} ++ ++module_init(switch_init); ++module_exit(switch_exit); ++MODULE_DESCRIPTION("gk swith driver"); ++MODULE_LICENSE("Proprietary"); ++ +diff --git a/arch/arm/plat-goke/sync_proc.c b/arch/arm/plat-goke/sync_proc.c +new file mode 100644 +index 00000000..39400917 +--- /dev/null ++++ b/arch/arm/plat-goke/sync_proc.c +@@ -0,0 +1,338 @@ ++/* ++ * arch/arm/mach-gk/sync_proc.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++ ++ ++int gk_sync_proc_hinit(struct gk_sync_proc_hinfo *hinfo) ++{ ++ hinfo->maxid = GK_SYNC_PROC_MAX_ID; ++ init_waitqueue_head(&hinfo->sync_proc_head); ++ atomic_set(&hinfo->sync_proc_flag, 0); ++ idr_init(&hinfo->sync_proc_idr); ++ mutex_init(&hinfo->sync_proc_lock); ++ hinfo->sync_read_proc = NULL; ++ ++ return 0; ++} ++EXPORT_SYMBOL(gk_sync_proc_hinit); ++ ++int gk_sync_proc_open(struct inode *inode, struct file *file) ++{ ++ int retval = 0; ++ struct gk_sync_proc_pinfo *pinfo = file->private_data; ++ struct proc_dir_entry *dp; ++ struct gk_sync_proc_hinfo *hinfo; ++ int id; ++ dp = PDE(inode); ++ hinfo = (struct gk_sync_proc_hinfo *)dp->data; ++ if (!hinfo) { ++ retval = -EPERM; ++ goto gk_sync_proc_open_exit; ++ } ++ if (hinfo->maxid > GK_SYNC_PROC_MAX_ID) { ++ retval = -EPERM; ++ goto gk_sync_proc_open_exit; ++ } ++ ++ if (pinfo) { ++ retval = -EPERM; ++ goto gk_sync_proc_open_exit; ++ } ++ pinfo = kmalloc(sizeof(*pinfo), GFP_KERNEL); ++ if (!pinfo) { ++ retval = -ENOMEM; ++ goto gk_sync_proc_open_exit; ++ } ++ memset(pinfo, 0, sizeof(*pinfo)); ++ ++ if (idr_pre_get(&hinfo->sync_proc_idr, GFP_KERNEL) == 0) { ++ retval = -ENOMEM; ++ goto gk_sync_proc_open_kfree_p; ++ } ++ mutex_lock(&hinfo->sync_proc_lock); ++ retval = idr_get_new_above(&hinfo->sync_proc_idr, pinfo, 0, &id); ++ mutex_unlock(&hinfo->sync_proc_lock); ++ if (retval != 0) ++ goto gk_sync_proc_open_kfree_p; ++ if (id > 31) { ++ retval = -ENOMEM; ++ goto gk_sync_proc_open_remove_id; ++ } ++ ++ if (!(pinfo->page = (char*) __get_free_page(GFP_KERNEL))) { ++ retval = -ENOMEM; ++ goto gk_sync_proc_open_remove_id; ++ } ++ pinfo->id = id; ++ pinfo->mask = (0x01 << id); ++ ++ file->private_data = pinfo; ++ file->f_version = 0; ++ file->f_mode &= ~FMODE_PWRITE; ++ ++ goto gk_sync_proc_open_exit; ++ ++gk_sync_proc_open_remove_id: ++ mutex_lock(&hinfo->sync_proc_lock); ++ idr_remove(&hinfo->sync_proc_idr, id); ++ mutex_unlock(&hinfo->sync_proc_lock); ++ ++gk_sync_proc_open_kfree_p: ++ kfree(pinfo); ++ ++gk_sync_proc_open_exit: ++ return retval; ++} ++EXPORT_SYMBOL(gk_sync_proc_open); ++ ++int gk_sync_proc_release(struct inode *inode, struct file *file) ++{ ++ int retval = 0; ++ struct gk_sync_proc_pinfo *pinfo = file->private_data; ++ struct proc_dir_entry *dp; ++ struct gk_sync_proc_hinfo *hinfo; ++ dp = PDE(inode); ++ ++ hinfo = (struct gk_sync_proc_hinfo *)dp->data; ++ if (!hinfo) { ++ retval = -EPERM; ++ goto gk_sync_proc_release_exit; ++ } ++ ++ if (!pinfo) { ++ retval = -ENOMEM; ++ goto gk_sync_proc_release_exit; ++ } ++ ++ mutex_lock(&hinfo->sync_proc_lock); ++ idr_remove(&hinfo->sync_proc_idr, pinfo->id); ++ mutex_unlock(&hinfo->sync_proc_lock); ++ ++ free_page((unsigned long)pinfo->page); ++ kfree(pinfo); ++ file->private_data = NULL; ++ ++gk_sync_proc_release_exit: ++ return retval; ++} ++EXPORT_SYMBOL(gk_sync_proc_release); ++ ++/* Note: ignore ppos*/ ++ssize_t gk_sync_proc_read(struct file *file, char __user *buf, ++ size_t size, loff_t *ppos) ++{ ++ int retval = 0; ++ struct gk_sync_proc_pinfo *pinfo = file->private_data; ++ struct proc_dir_entry *dp; ++ struct gk_sync_proc_hinfo *hinfo; ++ struct inode *inode = file->f_path.dentry->d_inode; ++ char *start; ++ int len; ++ size_t count; ++ dp = PDE(inode); ++ hinfo = (struct gk_sync_proc_hinfo *)dp->data; ++ if (!hinfo) { ++ retval = -EPERM; ++ goto gk_sync_proc_read_exit; ++ } ++ if (!hinfo->sync_read_proc) { ++ retval = -EPERM; ++ goto gk_sync_proc_read_exit; ++ } ++ ++ if (!pinfo) { ++ retval = -ENOMEM; ++ goto gk_sync_proc_read_exit; ++ } ++ ++ count = min_t(size_t, GK_SYNC_PROC_PAGE_SIZE, size); ++ start = pinfo->page; ++ len = 0; ++ while (1) { ++ wait_event_interruptible(hinfo->sync_proc_head, ++ (atomic_read(&hinfo->sync_proc_flag) & pinfo->mask)); ++ atomic_clear_mask(pinfo->mask, ++ (unsigned long *)&hinfo->sync_proc_flag); ++ ++ len = hinfo->sync_read_proc(start, hinfo->sync_read_data); ++ if (len < count) { ++ start += len; ++ count -= len; ++ } else if (len == count) { ++ start += len; ++ count -= len; ++ break; ++ } else { ++ break; ++ } ++ } ++ len = start - pinfo->page; ++ if (len == 0) { ++ retval = -EFAULT; ++ } else { ++ if (copy_to_user(buf, pinfo->page, len)) { ++ retval = -EFAULT; ++ } else { ++ retval = len; ++ } ++ } ++ ++gk_sync_proc_read_exit: ++ return retval; ++} ++EXPORT_SYMBOL(gk_sync_proc_read); ++ ++ssize_t gk_sync_proc_write(struct file *file, const char __user *buf, ++ size_t size, loff_t *ppos) ++{ ++ int retval = 0; ++ struct proc_dir_entry *dp; ++ struct gk_sync_proc_hinfo *hinfo; ++ struct inode *inode = file->f_path.dentry->d_inode; ++ ++ dp = PDE(inode); ++ hinfo = (struct gk_sync_proc_hinfo *)dp->data; ++ ++ if (!hinfo) { ++ retval = -EPERM; ++ goto gk_sync_proc_write_exit; ++ } ++ ++ atomic_set(&hinfo->sync_proc_flag, 0xFFFFFFFF); ++ wake_up_all(&hinfo->sync_proc_head); ++ ++ retval = size; ++ ++gk_sync_proc_write_exit: ++ return retval; ++} ++EXPORT_SYMBOL(gk_sync_proc_write); ++ ++#define GET_PROC_DATA_FROM_FILEP(filp) (struct gk_async_proc_info *)(PDE(filp->f_path.dentry->d_inode)->data) ++ ++static int gk_async_proc_open(struct inode *inode, struct file *filp) ++{ ++ struct gk_async_proc_info *pinfo; ++ ++ pinfo = GET_PROC_DATA_FROM_FILEP(filp); ++ ++ mutex_lock(&pinfo->op_mutex); ++ pinfo->use_count++; ++ filp->f_op = &pinfo->fops; ++ filp->private_data = pinfo->private_data; ++ mutex_unlock(&pinfo->op_mutex); ++ ++ return 0; ++} ++ ++static int gk_async_proc_fasync(int fd, struct file * filp, int on) ++{ ++ int retval; ++ struct gk_async_proc_info *pinfo; ++ ++ pinfo = GET_PROC_DATA_FROM_FILEP(filp); ++ ++ mutex_lock(&pinfo->op_mutex); ++ retval = fasync_helper(fd, filp, on, &pinfo->fasync_queue); ++ mutex_unlock(&pinfo->op_mutex); ++ ++ return retval; ++} ++ ++static int gk_async_proc_release(struct inode *inode, struct file *filp) ++{ ++ int retval; ++ struct gk_async_proc_info *pinfo; ++ ++ pinfo = GET_PROC_DATA_FROM_FILEP(filp); ++ ++ mutex_lock(&pinfo->op_mutex); ++ retval = fasync_helper(-1, filp, 0, &pinfo->fasync_queue); ++ pinfo->use_count--; ++ mutex_unlock(&pinfo->op_mutex); ++ ++ return retval; ++} ++ ++int gk_async_proc_create(struct gk_async_proc_info *pinfo) ++{ ++ int retval = 0; ++ struct proc_dir_entry *entry; ++ ++ if (!pinfo) { ++ retval = -EINVAL; ++ goto gk_async_proc_create_exit; ++ } ++ ++ pinfo->fops.open = gk_async_proc_open; ++ pinfo->fops.fasync = gk_async_proc_fasync; ++ pinfo->fops.release = gk_async_proc_release; ++ mutex_init(&pinfo->op_mutex); ++ pinfo->use_count = 0; ++ pinfo->fasync_queue = NULL; ++ ++ entry = proc_create_data(pinfo->proc_name, S_IRUGO, ++ get_gk_proc_dir(), &pinfo->fops, pinfo); ++ if (!entry) { ++ retval = -EINVAL; ++ } ++ ++gk_async_proc_create_exit: ++ return retval; ++} ++EXPORT_SYMBOL(gk_async_proc_create); ++ ++int gk_async_proc_remove(struct gk_async_proc_info *pinfo) ++{ ++ int retval = 0; ++ ++ if (!pinfo) { ++ retval = -EINVAL; ++ } else { ++ remove_proc_entry(pinfo->proc_name, get_gk_proc_dir()); ++ } ++ ++ return retval; ++} ++EXPORT_SYMBOL(gk_async_proc_remove); ++ +diff --git a/arch/arm/plat-goke/timer.c b/arch/arm/plat-goke/timer.c +new file mode 100644 +index 00000000..6b699d3a +--- /dev/null ++++ b/arch/arm/plat-goke/timer.c +@@ -0,0 +1,350 @@ ++/* ++ * arch/arm/mach-gk/timer.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * Default clock is from APB. ++ * Timer 3 is used as clock_event_device. ++ * Timer 2 is used as free-running clocksource ++ * if CONFIG_GK_SUPPORT_CLOCKSOURCE is defined ++ * Timer 1 is not used. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++/* ==========================================================================*/ ++#define GK_TIMER_FREQ (get_apb_bus_freq_hz()) ++#define GK_TIMER_RATING (300) ++ ++static struct clock_event_device gk_clkevt; ++static struct irqaction gk_ce_timer_irq; ++static u32 timer_reload = 0; ++static u32 timer_Mhz = 69; ++ ++/* ==========================================================================*/ ++#define GK_CE_TIMER_STATUS_REG TIMER3_STATUS_REG ++#define GK_CE_TIMER_RELOAD_REG TIMER3_RELOAD_REG ++#define GK_CE_TIMER_MATCH1_REG TIMER3_MATCH1_REG ++#define GK_CE_TIMER_MATCH2_REG TIMER3_MATCH2_REG ++#define GK_CE_TIMER_IRQ TIMER3_IRQ ++#define GK_CE_TIMER_CTR_EN TIMER_CTR_EN3 ++#define GK_CE_TIMER_CTR_OF TIMER_CTR_OF3 ++#define GK_CE_TIMER_CTR_CSL TIMER_CTR_CSL3 ++#define GK_CE_TIMER_CTR_MASK 0x00000F00 ++ ++int gk_start_highres_timer(u32 ms_to_timeout); ++ ++int gk_init_highres_timer(void *pcallback); ++ ++ ++ ++static inline void gk_ce_timer_disable(void) ++{ ++ gk_timer_clrbitsl(TIMER_CTR_REG, GK_CE_TIMER_CTR_EN); ++} ++ ++static inline void gk_ce_timer_enable(void) ++{ ++ gk_timer_setbitsl(TIMER_CTR_REG, GK_CE_TIMER_CTR_EN); ++} ++ ++static inline void gk_ce_timer_misc(void) ++{ ++ gk_timer_setbitsl(TIMER_CTR_REG, (GK_CE_TIMER_CTR_OF | GK_CE_TIMER_CTR_CSL)); ++ gk_timer_clrbitsl(TIMER_CTR_REG, GK_CE_TIMER_CTR_CSL); ++} ++ ++static inline void gk_ce_timer_set_periodic(void) ++{ ++ u32 cnt; ++ ++ cnt = GK_TIMER_FREQ / HZ; ++ gk_timer_writel(GK_CE_TIMER_STATUS_REG, cnt); ++ gk_timer_writel(GK_CE_TIMER_RELOAD_REG, cnt); ++ timer_reload = cnt; ++ timer_Mhz = GK_TIMER_FREQ/1000000; ++ gk_timer_writel(GK_CE_TIMER_MATCH1_REG, 0x0); ++ gk_timer_writel(GK_CE_TIMER_MATCH2_REG, 0x0); ++ gk_ce_timer_misc(); ++} ++ ++static inline void gk_ce_timer_set_oneshot(void) ++{ ++ gk_timer_writel(GK_CE_TIMER_STATUS_REG, 0x0); ++ gk_timer_writel(GK_CE_TIMER_RELOAD_REG, 0xffffffff); ++ gk_timer_writel(GK_CE_TIMER_MATCH1_REG, 0x0); ++ gk_timer_writel(GK_CE_TIMER_MATCH2_REG, 0x0); ++ gk_ce_timer_misc(); ++} ++ ++static void gk_ce_timer_set_mode(enum clock_event_mode mode, ++ struct clock_event_device *evt) ++{ ++ switch (mode) { ++ case CLOCK_EVT_MODE_PERIODIC: ++ gk_ce_timer_disable(); ++ gk_ce_timer_set_periodic(); ++ gk_ce_timer_enable(); ++ break; ++ case CLOCK_EVT_MODE_ONESHOT: ++ gk_ce_timer_disable(); ++ gk_ce_timer_set_oneshot(); ++ gk_ce_timer_enable(); ++ break; ++ case CLOCK_EVT_MODE_UNUSED: ++ remove_irq(gk_clkevt.irq, &gk_ce_timer_irq); ++ case CLOCK_EVT_MODE_SHUTDOWN: ++ gk_ce_timer_disable(); ++ break; ++ case CLOCK_EVT_MODE_RESUME: ++ break; ++ } ++ pr_debug("%s:%d\n", __func__, mode); ++} ++ ++static int gk_ce_timer_set_next_event(unsigned long delta, ++ struct clock_event_device *dev) ++{ ++ gk_timer_writel(GK_CE_TIMER_STATUS_REG, delta); ++ ++ return 0; ++} ++ ++static void gk_timer_irq_clr(u32 timer_irq) ++{ ++ if((timer_irq > TIMER3_IRQ)&&(timer_irq < TIMER1_IRQ)) ++ { ++ printk("Error Timer Irq = %d!\n", timer_irq); ++ } ++ ++ gk_irq_writel(VIC_EDGE_CLR_REG, (1 << timer_irq)); ++} ++ ++static struct clock_event_device gk_clkevt = { ++ .name = "gk-clkevt", ++ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, ++ .rating = GK_TIMER_RATING, ++ .set_next_event = gk_ce_timer_set_next_event, ++ .set_mode = gk_ce_timer_set_mode, ++ .mode = CLOCK_EVT_MODE_UNUSED, ++ .irq = GK_CE_TIMER_IRQ, ++}; ++ ++static irqreturn_t gk_ce_timer_interrupt(int irq, void *dev_id) ++{ ++ gk_timer_irq_clr(irq); ++ gk_clkevt.event_handler(&gk_clkevt); ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction gk_ce_timer_irq = { ++ .name = "tick-timer", ++ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING, ++ .handler = gk_ce_timer_interrupt, ++}; ++ ++/* ==========================================================================*/ ++#if defined(CONFIG_SUPPORT_CLOCKSOURCE) ++#define GK_CS_TIMER_STATUS_REG TIMER2_STATUS_REG ++#define GK_CS_TIMER_RELOAD_REG TIMER2_RELOAD_REG ++#define GK_CS_TIMER_MATCH1_REG TIMER2_MATCH1_REG ++#define GK_CS_TIMER_MATCH2_REG TIMER2_MATCH2_REG ++#define GK_CS_TIMER_CTR_EN TIMER_CTR_EN2 ++#define GK_CS_TIMER_CTR_OF TIMER_CTR_OF2 ++#define GK_CS_TIMER_CTR_CSL TIMER_CTR_CSL2 ++#define GK_CS_TIMER_CTR_MASK 0x000000F0 ++ ++static inline void gk_cs_timer_init(void) ++{ ++ gk_timer_clrbitsl(TIMER_CTR_REG, GK_CS_TIMER_CTR_EN); ++ gk_timer_clrbitsl(TIMER_CTR_REG, GK_CS_TIMER_CTR_OF); ++ gk_timer_clrbitsl(TIMER_CTR_REG, GK_CS_TIMER_CTR_CSL); ++ gk_timer_writel(GK_CS_TIMER_STATUS_REG, 0xffffffff); ++ gk_timer_writel(GK_CS_TIMER_RELOAD_REG, 0xffffffff); ++ gk_timer_writel(GK_CS_TIMER_MATCH1_REG, 0x0); ++ gk_timer_writel(GK_CS_TIMER_MATCH2_REG, 0x0); ++ gk_timer_setbitsl(TIMER_CTR_REG, GK_CS_TIMER_CTR_EN); ++} ++ ++static cycle_t gk_cs_timer_read(struct clocksource *cs) ++{ ++ return ((cycle_t)gk_timer_readl(GK_CS_TIMER_STATUS_REG)); ++} ++ ++static struct clocksource gk_cs_timer_clksrc = ++{ ++ .name = "gk-cs-timer", ++ .rating = GK_TIMER_RATING, ++ .read = gk_cs_timer_read, ++ .mask = CLOCKSOURCE_MASK(32), ++ .mult = 2236962133u, ++ .shift = 27, ++ .flags = CLOCK_SOURCE_IS_CONTINUOUS, ++}; ++ ++#endif ++ ++/* ==========================================================================*/ ++static void __init gk_timer_init(void) ++{ ++ printk("mach gk init timer...\n"); ++#if defined(CONFIG_SUPPORT_CLOCKSOURCE) ++ gk_cs_timer_init(); ++ clocks_calc_mult_shift(&gk_cs_timer_clksrc.mult, ++ &gk_cs_timer_clksrc.shift, ++ GK_TIMER_FREQ, NSEC_PER_SEC, 60); ++ pr_debug("%s: mult = %u, shift = %u\n", ++ gk_cs_timer_clksrc.name, ++ gk_cs_timer_clksrc.mult, ++ gk_cs_timer_clksrc.shift); ++ clocksource_register(&gk_cs_timer_clksrc); ++#endif ++ ++ gk_clkevt.cpumask = cpumask_of(0); ++ setup_irq(gk_clkevt.irq, &gk_ce_timer_irq); ++ clockevents_config_and_register(&gk_clkevt, GK_TIMER_FREQ, 0x01, 0xffffffff); ++ ++ ++ return; ++ ++} ++ ++unsigned long gk_timer_offset(void) ++{ ++ u32 val = (timer_reload - gk_timer_readl(GK_CE_TIMER_STATUS_REG))/timer_Mhz; ++ ++ return val; ++} ++ ++ ++struct sys_timer gk_sys_timer = { ++ .init = gk_timer_init, ++ .offset = gk_timer_offset, ++}; ++ ++int __init gk_init_timer(void) ++{ ++ int errCode = 0; ++ ++ /* Reset all timers */ ++ //gk_timer_writel(TIMER_CTR_REG, 0x0); ++ timer_reload = gk_timer_readl(GK_CE_TIMER_RELOAD_REG); ++ gk_init_highres_timer(NULL); ++ gk_start_highres_timer(100); ++ ++ return errCode; ++} ++ ++//---------------------------------------- ++typedef void (* HIGH_RES_TIMER_CALLBACK) (void); ++ ++static HIGH_RES_TIMER_CALLBACK s_pCallback_high_res = NULL; ++ ++static u32 dev_id = 0; ++static u32 timer_ms_delay = 12; ++static u32 timer_intr_cnt = 0; ++static void init_hw_timer(void) ++{ ++ u32 interrupt_interval_in_ms = 1; ++ u32 apb_clk = get_apb_bus_freq_hz(); ++ u32 timer_clk = apb_clk * interrupt_interval_in_ms /100; ++ gk_timer_clrbitsl(TIMER_CTR_REG, TIMER_CTR_EN2); ++ gk_timer_clrbitsl(TIMER_CTR_REG, TIMER_CTR_OF2); ++ gk_timer_clrbitsl(TIMER_CTR_REG, TIMER_CTR_CSL2); ++ gk_timer_writel(TIMER2_STATUS_REG, timer_clk); ++ gk_timer_writel(TIMER2_RELOAD_REG, timer_clk); ++ gk_timer_writel(TIMER2_MATCH1_REG, 0x0); ++ gk_timer_writel(TIMER2_MATCH2_REG, 0x0); ++ ++ gk_timer_setbitsl(TIMER_CTR_REG, (TIMER_CTR_OF2 | TIMER_CTR_CSL2)); ++ gk_timer_clrbitsl(TIMER_CTR_REG, TIMER_CTR_CSL2); ++ //gk_setbitsl(TIMER_CTR_REG, TIMER_CTR_EN2); ++} ++ ++static void deinit_hw_timer(void) ++{ ++ gk_timer_clrbitsl(TIMER_CTR_REG, TIMER_CTR_EN2); ++} ++ ++static irqreturn_t hw_timer_irq_handler(int irqno, void *dev_id) ++{ ++ gk_timer_irq_clr(irqno); ++ ++ //printk("timer2 irq...%d\n", timer_intr_cnt); ++ ++ if (timer_intr_cnt++ != timer_ms_delay) ++ return IRQ_HANDLED; ++ ++ timer_intr_cnt = 0; ++ //run callback, the callback must be fast enough to be put into interrupt context ++ if(s_pCallback_high_res) ++ s_pCallback_high_res(); ++ return IRQ_HANDLED; ++} ++ ++ ++ ++int gk_init_highres_timer(void *pcallback) ++{ ++ int rval; ++ HIGH_RES_TIMER_CALLBACK ptimercb = (HIGH_RES_TIMER_CALLBACK)pcallback; ++ ++ printk("Init HW timer for DSP communication\n"); ++ ++ s_pCallback_high_res = ptimercb; ++ rval = request_irq(TIMER2_IRQ, hw_timer_irq_handler, IRQF_SHARED | IRQF_TIMER | IRQF_TRIGGER_RISING, "HW Timer2", &dev_id); ++ ++ if (rval < 0) ++ printk("%s, %d, Can NOT request_irq %d\n",__func__,__LINE__,rval); ++ init_hw_timer(); ++ return 0; ++} ++ ++int gk_start_highres_timer(u32 ms_to_timeout) ++{ ++ unsigned long flags; ++ local_irq_save(flags); ++ timer_ms_delay = ms_to_timeout; ++ timer_intr_cnt = 0; ++ local_irq_restore(flags); ++ gk_timer_setbitsl(TIMER_CTR_REG, TIMER_CTR_EN2); ++ return 0; ++} ++ ++int gk_deinit_highres_timer(void) ++{ ++ s_pCallback_high_res = NULL; ++ deinit_hw_timer(); ++ return 0; ++} ++ +diff --git a/arch/arm/plat-goke/uart.c b/arch/arm/plat-goke/uart.c +new file mode 100644 +index 00000000..14cc6752 +--- /dev/null ++++ b/arch/arm/plat-goke/uart.c +@@ -0,0 +1,302 @@ ++/* ++ * arch/arm/mach-gk/uart.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++ ++extern u64 gk_dmamask; ++ ++/* ==========================================================================*/ ++ ++static void gk_uart_stop_tx(unsigned char __iomem *membase); ++#if (UART_INSTANCES >= 2) ++static u32 gk_uart_read_ms(unsigned char __iomem *membase); ++#endif ++ ++/* ==========================================================================*/ ++/* Serial port registrations */ ++ ++static struct uart_port gk_uart_port_resource[] = ++{ ++ [0] = { ++ .type = PORT_UART00, ++ .iotype = UPIO_MEM, ++ .membase = (void *)UART0_VA_ADDR, ++ .mapbase = (unsigned long)UART0_PA_ADDR, ++ .irq = UART0_IRQ, ++ .uartclk = GK_UART_FREQ/*12500000*/, ++ .fifosize = UART_FIFO_SIZE, ++ .line = 0, ++ }, ++#if (UART_INSTANCES >= 2) ++ [1] = { ++ .type = PORT_UART00, ++ .iotype = UPIO_MEM, ++ .membase = (void *)UART1_VA_ADDR, ++ .mapbase = (unsigned long)UART1_PA_ADDR, ++ .irq = UART1_IRQ, ++ .uartclk = GK_UART_FREQ/*12500000*/, ++ .fifosize = UART_FIFO_SIZE, ++ .line = 0, ++ }, ++#endif ++#if (UART_INSTANCES >= 3) ++ [2] = { ++ .type = PORT_UART00, ++ .iotype = UPIO_MEM, ++ .membase = (void *)UART2_VA_ADDR, ++ .mapbase = (unsigned long)UART2_PA_ADDR, ++ .irq = UART2_IRQ, ++ .uartclk = GK_UART_FREQ/*12500000*/, ++ .fifosize = UART_FIFO_SIZE, ++ .line = 0, ++ }, ++#endif ++}; ++ ++struct gk_uart_platform_info gk_uart_ports = ++{ ++ .total_port_num = ARRAY_SIZE(gk_uart_port_resource), ++ .registed_port_num = 0, ++ .port[0] = { ++ .port = &gk_uart_port_resource[0], ++ .mcr = DEFAULT_UART_MCR, ++ .fcr = DEFAULT_UART_FCR, ++ .ier = DEFAULT_UART_IER, ++ .stop_tx = gk_uart_stop_tx, ++ .set_pll = NULL, ++ .get_pll = get_uart_freq_hz, ++ .get_ms = gk_uart_read_ms, ++ }, ++#if (UART_INSTANCES >= 2) ++ .port[1] = { ++ .port = &gk_uart_port_resource[1], ++ .mcr = DEFAULT_UART_MCR, ++ .fcr = DEFAULT_UART_FCR, ++ .ier = DEFAULT_UART_IER, ++ .stop_tx = gk_uart_stop_tx, ++ .set_pll = NULL, ++ .get_pll = get_uart_freq_hz, ++ .get_ms = gk_uart_read_ms, ++ }, ++#endif ++#if (UART_INSTANCES >= 3) ++ .port[2] = { ++ .port = &gk_uart_port_resource[2], ++ .mcr = DEFAULT_UART_MCR, ++ .fcr = DEFAULT_UART_FCR, ++ .ier = DEFAULT_UART_IER, ++ .stop_tx = gk_uart_stop_tx, ++ .set_pll = NULL, ++ .get_pll = get_uart_freq_hz, ++ .get_ms = gk_uart_read_ms, ++ }, ++#endif ++ ++}; ++ ++struct platform_device gk_uart0 = ++{ ++ .name = "uart", ++ .id = 0, ++ .resource = NULL, ++ .num_resources = 0, ++ .dev = { ++ .platform_data = &gk_uart_ports, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++#if (UART_INSTANCES >= 2) ++struct platform_device gk_uart1 = ++{ ++ .name = "uart", ++ .id = 1, ++ .resource = NULL, ++ .num_resources = 0, ++ .dev = { ++ .platform_data = &gk_uart_ports, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++#endif ++#if (UART_INSTANCES >= 3) ++struct platform_device gk_uart2 = ++{ ++ .name = "uart", ++ .id = 2, ++ .resource = NULL, ++ .num_resources = 0, ++ .dev = { ++ .platform_data = &gk_uart_ports, ++ .dma_mask = &gk_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ } ++}; ++#endif ++ ++/* uart devices */ ++struct platform_device *gk_uart_devs[UART_INSTANCES] = { ++ &gk_uart0, ++#if (UART_INSTANCES >= 2) ++ &gk_uart1, ++#endif ++#if (UART_INSTANCES >= 3) ++ &gk_uart2, ++#endif ++}; ++ ++/* ==========================================================================*/ ++ ++static void gk_uart_stop_tx(unsigned char __iomem *membase) ++{ ++ gk_uart_clrbitsl((unsigned int)(membase + UART_IE_OFFSET), UART_IE_ETBEI); ++} ++ ++#if (UART_INSTANCES >= 2) ++static u32 gk_uart_read_ms(unsigned char __iomem *membase) ++{ ++ return gk_uart_readl((unsigned int)(membase + UART_MS_OFFSET)); ++} ++#endif ++ ++ ++ ++/* uart registration process */ ++static int __init gk_arch_init(void) ++{ ++ int ret; ++ ++ ret = platform_add_devices(gk_uart_devs, ARRAY_SIZE(gk_uart_devs)); ++ if(ret < 0) ++ { ++ printk(KERN_ERR "%s: failed to add uart device err=%d\n", __FUNCTION__, ret); ++ } ++ return ret; ++} ++ ++arch_initcall(gk_arch_init); ++ ++ ++#ifdef KE_DEBUG ++ ++#define vtop(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) ++#define ptov(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) ++ ++static inline void ke_putc(int c) ++{ ++ while (!(gk_uart_readl(gk_uart_devs[0]->dev.platform_data->port[0].port->membase+UART_LS_OFFSET) & UART_LS_TEMT)); ++ gk_uart_writel(gk_uart_devs[0]->dev.platform_data->port[0].port->membase+UART_TH_OFFSET, c); ++} ++ ++static inline void ke_flush(void) ++{ ++ unsigned int dump; ++ ++ while (gk_uart_readl(gk_uart_devs[0]->dev.platform_data->port[0].port->membase+UART_LS_OFFSET) & UART_LS_DR) ++ { ++ dump = gk_uart_readl(gk_uart_devs[0]->dev.platform_data->port[0].port->membase+UART_RB_OFFSET); ++ } ++} ++ ++static void ke_putstr(const char *ptr) ++{ ++ char c; ++ ++ while ((c = *ptr++) != '\0') { ++ if (c == '\n') ++ ke_putc('\r'); ++ ke_putc(c); ++ } ++ ++ ke_flush(); ++} ++ ++void __init ke_print(const char *str, ...) ++{ ++ char buf[256]; ++ va_list ap; ++ ++ va_start(ap, str); ++ vsnprintf(buf, sizeof(buf), str, ap); ++ va_end(ap); ++ ++ ke_putstr(buf); ++} ++ ++/** ++ * Put a character out to the UART controller. ++ */ ++static void after_putc(int c) ++{ ++ while (!(gk_uart_readl(gk_uart_devs[0]->dev.platform_data->port[0].port->membase+UART_LS_OFFSET) & UART_LS_TEMT)); ++ gk_uart_writel(gk_uart_devs[0]->dev.platform_data->port[0].port->membase+UART_TH_OFFSET, c); ++} ++ ++static void after_flush(void) ++{ ++ unsigned int dump; ++ ++ while (gk_uart_readl(gk_uart_devs[0]->dev.platform_data->port[0].port->membase+UART_LS_OFFSET) & UART_LS_DR) ++ { ++ dump = gk_uart_readl(gk_uart_devs[0]->dev.platform_data->port[0].port->membase+UART_RB_OFFSET); ++ } ++} ++ ++static void after_putstr(const char *ptr) ++{ ++ char c; ++ ++ while ((c = *ptr++) != '\0') { ++ if (c == '\n') ++ after_putc('\r'); ++ after_putc(c); ++ } ++ ++ after_flush(); ++} ++ ++ ++void after_print(const char *str, ...) ++{ ++ char buf[256]; ++ va_list ap; ++ ++ va_start(ap, str); ++ vsnprintf(buf, sizeof(buf), str, ap); ++ va_end(ap); ++ ++ after_putstr(buf); ++} ++ ++#endif ++ +diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types +index f9c9f33f..f30b5082 100644 +--- a/arch/arm/tools/mach-types ++++ b/arch/arm/tools/mach-types +@@ -1169,3 +1169,7 @@ elite_ulk MACH_ELITE_ULK ELITE_ULK 3888 + pov2 MACH_POV2 POV2 3889 + ipod_touch_2g MACH_IPOD_TOUCH_2G IPOD_TOUCH_2G 3890 + da850_pqab MACH_DA850_PQAB DA850_PQAB 3891 ++goke_ipc MACH_GOKE_IPC GOKE_IPC 3988 ++#gk7102s_elec_sc1135_v1 MACH_GK7102S_ELEC_SC1135_V1_00 GK7102S_ELEC_SC1135_V1_00 3988 ++ ++# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number +diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S +index 323ce1a6..50a724a8 100644 +--- a/arch/arm/vfp/entry.S ++++ b/arch/arm/vfp/entry.S +@@ -28,6 +28,7 @@ ENTRY(do_vfp) + str r11, [r10, #TI_PREEMPT] + #endif + enable_irq ++ str r2, [sp, #S_PC] @ update regs->ARM_pc for Thumb 2 case + ldr r4, .LCvfp + ldr r11, [r10, #TI_CPU] @ CPU number + add r10, r10, #TI_VFPSTATE @ r10 = workspace +diff --git a/drivers/base/Makefile b/drivers/base/Makefile +index b6d1b9c4..220ae825 100644 +--- a/drivers/base/Makefile ++++ b/drivers/base/Makefile +@@ -1,7 +1,7 @@ + # Makefile for the Linux device tree + + obj-y := core.o bus.o dd.o syscore.o \ +- driver.o class.o platform.o \ ++ driver.o class.o platform.o ipcbus.o \ + cpu.o firmware.o init.o map.o devres.o \ + attribute_container.o transport_class.o \ + topology.o +diff --git a/drivers/base/ipcbus.c b/drivers/base/ipcbus.c +new file mode 100644 +index 00000000..38e610ee +--- /dev/null ++++ b/drivers/base/ipcbus.c +@@ -0,0 +1,193 @@ ++/*! ++***************************************************************************** ++** \file drivers/base/ipcbus.c ++** ++** \version $Id$ ++** ++** \brief ++** ++** \attention THIS SAMPLE CODE IS PROVIDED AS IS. GOKE MICROELECTRONICS ++** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ++** OMMISSIONS ++** ++** (C) Copyright 2012-2015 by GOKE MICROELECTRONICS CO.,LTD ++** ++***************************************************************************** ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static struct device gk_bus = { ++ .init_name = "ipc_bus" ++}; ++ ++struct ipc_dev { ++ struct device dev; ++ struct device *next; ++}; ++ ++#define to_gk_dev(x) container_of((x), struct ipc_dev, dev) ++ ++static int gk_bus_match(struct device *dev, struct device_driver *driver) ++{ ++ struct ipc_driver *ipc_driver = to_ipc_driver(driver); ++ ++ if (dev->platform_data == ipc_driver) { ++ if (!ipc_driver->match || ipc_driver->match(dev)) ++ return 1; ++ dev->platform_data = NULL; ++ } ++ return 0; ++} ++ ++static int gk_bus_probe(struct device *dev) ++{ ++ struct ipc_driver *ipc_driver = dev->platform_data; ++ ++ if (ipc_driver->probe) ++ return ipc_driver->probe(dev); ++ ++ return 0; ++} ++ ++static int gk_bus_remove(struct device *dev) ++{ ++ struct ipc_driver *ipc_driver = dev->platform_data; ++ ++ if (ipc_driver->remove) ++ return ipc_driver->remove(dev); ++ ++ return 0; ++} ++ ++static void gk_bus_shutdown(struct device *dev) ++{ ++ struct ipc_driver *ipc_driver = dev->platform_data; ++ ++ if (ipc_driver->shutdown) ++ ipc_driver->shutdown(dev); ++} ++ ++static int gk_bus_suspend(struct device *dev, pm_message_t state) ++{ ++ struct ipc_driver *ipc_driver = dev->platform_data; ++ ++ if (ipc_driver->suspend) ++ return ipc_driver->suspend(dev, state); ++ ++ return 0; ++} ++ ++static int gk_bus_resume(struct device *dev) ++{ ++ struct ipc_driver *ipc_driver = dev->platform_data; ++ ++ if (ipc_driver->resume) ++ return ipc_driver->resume(dev); ++ ++ return 0; ++} ++ ++static struct bus_type gk_bus_type = { ++ .name = "ipc_bus", ++ .match = gk_bus_match, ++ .probe = gk_bus_probe, ++ .remove = gk_bus_remove, ++ .shutdown = gk_bus_shutdown, ++ .suspend = gk_bus_suspend, ++ .resume = gk_bus_resume ++}; ++ ++static void gk_dev_release(struct device *dev) ++{ ++ kfree(to_gk_dev(dev)); ++} ++ ++void ipc_unregister_driver(struct ipc_driver *ipc_driver) ++{ ++ struct device *dev = ipc_driver->devices; ++ ++ while (dev) { ++ struct device *tmp = to_gk_dev(dev)->next; ++ device_unregister(dev); ++ dev = tmp; ++ } ++ driver_unregister(&ipc_driver->driver); ++} ++EXPORT_SYMBOL(ipc_unregister_driver); ++ ++int ipc_register_driver(struct ipc_driver *ipc_driver) ++{ ++ int error; ++ unsigned int id; ++ ++ ipc_driver->driver.bus = &gk_bus_type; ++ ipc_driver->devices = NULL; ++ ++ error = driver_register(&ipc_driver->driver); ++ if (error) ++ return error; ++ ++ for (id = 0; id < 1; id++) { ++ struct ipc_dev *ipc_dev; ++ ++ ipc_dev = kzalloc(sizeof *ipc_dev, GFP_KERNEL); ++ if (!ipc_dev) { ++ error = -ENOMEM; ++ break; ++ } ++ ++ ipc_dev->dev.parent = &gk_bus; ++ ipc_dev->dev.bus = &gk_bus_type; ++ ++ dev_set_name(&ipc_dev->dev, "%s", ++ ipc_driver->driver.name); ++ ipc_dev->dev.platform_data = ipc_driver; ++ ipc_dev->dev.release = gk_dev_release; ++ ++ ipc_dev->dev.coherent_dma_mask = DMA_BIT_MASK(24); ++ ipc_dev->dev.dma_mask = &ipc_dev->dev.coherent_dma_mask; ++ ++ error = device_register(&ipc_dev->dev); ++ if (error) { ++ put_device(&ipc_dev->dev); ++ break; ++ } ++ ++ if (ipc_dev->dev.platform_data) { ++ ipc_dev->next = ipc_driver->devices; ++ ipc_driver->devices = &ipc_dev->dev; ++ } else ++ device_unregister(&ipc_dev->dev); ++ } ++ ++ if (!error && !ipc_driver->devices) ++ error = -ENODEV; ++ ++ if (error) ++ ipc_unregister_driver(ipc_driver); ++ ++ return error; ++} ++EXPORT_SYMBOL(ipc_register_driver); ++ ++static int __init gk_bus_init(void) ++{ ++ int error; ++ ++ error = bus_register(&gk_bus_type); ++ if (!error) { ++ error = device_register(&gk_bus); ++ if (error) ++ bus_unregister(&gk_bus_type); ++ } ++ return error; ++} ++ ++device_initcall(gk_bus_init); +diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c +index 112c16e0..c487ab68 100644 +--- a/drivers/gpio/gpiolib.c ++++ b/drivers/gpio/gpiolib.c +@@ -253,8 +253,10 @@ static ssize_t gpio_direction_store(struct device *dev, + status = gpio_direction_output(gpio, 1); + else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low")) + status = gpio_direction_output(gpio, 0); +- else if (sysfs_streq(buf, "in")) +- status = gpio_direction_input(gpio); ++ else if (sysfs_streq(buf, "in") || sysfs_streq(buf, "in0")) ++ status = gpio_direction_input(gpio, 0); ++ else if (sysfs_streq(buf, "in1")) ++ status = gpio_direction_input(gpio, 1); + else + status = -EINVAL; + +@@ -1300,7 +1302,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) + set_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags); + + if (flags & GPIOF_DIR_IN) +- err = gpio_direction_input(gpio); ++ err = gpio_direction_input(gpio, 0); + else + err = gpio_direction_output(gpio, + (flags & GPIOF_INIT_HIGH) ? 1 : 0); +@@ -1386,7 +1388,7 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); + * rely on gpio_request() having been called beforehand. + */ + +-int gpio_direction_input(unsigned gpio) ++int gpio_direction_input(unsigned gpio, int val) + { + unsigned long flags; + struct gpio_chip *chip; +@@ -1425,7 +1427,7 @@ int gpio_direction_input(unsigned gpio) + } + } + +- status = chip->direction_input(chip, gpio); ++ status = chip->direction_input(chip, gpio, val); + if (status == 0) + clear_bit(FLAG_IS_OUT, &desc->flags); + +@@ -1450,11 +1452,11 @@ int gpio_direction_output(unsigned gpio, int value) + + /* Open drain pin should not be driven to 1 */ + if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags)) +- return gpio_direction_input(gpio); ++ return gpio_direction_input(gpio, 0); + + /* Open source pin should not be driven to 0 */ + if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags)) +- return gpio_direction_input(gpio); ++ return gpio_direction_input(gpio, 0); + + spin_lock_irqsave(&gpio_lock, flags); + +@@ -1604,7 +1606,7 @@ static void _gpio_set_open_drain_value(unsigned gpio, + { + int err = 0; + if (value) { +- err = chip->direction_input(chip, gpio - chip->base); ++ err = chip->direction_input(chip, gpio - chip->base, 0); + if (!err) + clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); + } else { +@@ -1633,7 +1635,7 @@ static void _gpio_set_open_source_value(unsigned gpio, + if (!err) + set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); + } else { +- err = chip->direction_input(chip, gpio - chip->base); ++ err = chip->direction_input(chip, gpio - chip->base, 0); + if (!err) + clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); + } +diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +index ea8736bc..2ba35466 100644 +--- a/drivers/i2c/busses/Kconfig ++++ b/drivers/i2c/busses/Kconfig +@@ -285,6 +285,18 @@ config I2C_POWERMAC + + comment "I2C system bus drivers (mostly embedded / system-on-chip)" + ++config I2C_GOKE ++ tristate "goke ipc I2C bus support" ++ depends on GK_I2C ++ select I2C_MUX if MACH_GK7101_EVB_SUPPORT_I2C_MUX ++ select I2C_MUX_GK7101 if MACH_GK7101_EVB_SUPPORT_I2C_MUX ++ help ++ This driver supports the goke ipc ++ I2C Bus master controller ++ ++ This driver can also be built as a module. If so, the module ++ will be called goke_i2c_vxx. ++ + config I2C_AT91 + tristate "Atmel AT91 I2C Two-Wire interface (TWI)" + depends on ARCH_AT91 && EXPERIMENTAL && BROKEN +diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile +index 2f05d7b6..4395f856 100644 +--- a/drivers/i2c/busses/Makefile ++++ b/drivers/i2c/busses/Makefile +@@ -28,6 +28,9 @@ obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o + obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o + + # Embedded system I2C/SMBus host controller drivers ++ifdef CONFIG_I2C_GOKE ++obj-$(CONFIG_GK_I2C_V1_00) += i2c-goke_v1_00.o ++endif + obj-$(CONFIG_I2C_AT91) += i2c-at91.o + obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o + obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o +diff --git a/drivers/i2c/busses/i2c-goke_v1_00.c b/drivers/i2c/busses/i2c-goke_v1_00.c +new file mode 100644 +index 00000000..419e3cb7 +--- /dev/null ++++ b/drivers/i2c/busses/i2c-goke_v1_00.c +@@ -0,0 +1,863 @@ ++/* linux/drivers/i2c/busses/i2c-gk.c ++ * ++ * History: ++ * 2014/07/30 - [Kewell Liu] created file ++ * ++ * Copyright (C) 2002-2014, Goke Microelectronics China. ++ * ++ * GK I2C Controller ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++*/ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++#ifndef CONFIG_I2C_GK_RETRIES ++#define CONFIG_I2C_GK_RETRIES (3) ++#endif ++ ++#ifndef CONFIG_I2C_GK_ACK_TIMEOUT ++#define CONFIG_I2C_GK_ACK_TIMEOUT (1 * HZ) ++#endif ++ ++#define CONFIG_I2C_GK_BULK_RETRY_NUM (4) ++ ++/* i2c controller state */ ++enum gk_i2c_state { ++ I2C_STATE_IDLE, ++ I2C_STATE_START, ++ I2C_STATE_START_TEN, ++ I2C_STATE_START_NEW, ++ I2C_STATE_READ, ++ I2C_STATE_READ_STOP, ++ I2C_STATE_WRITE, ++ I2C_STATE_WRITE_WAIT_ACK, ++ I2C_STATE_BULK_WRITE, ++ I2C_STATE_NO_ACK, ++ I2C_STATE_ERROR ++}; ++ ++struct gk_i2c { ++ spinlock_t lock; ++ unsigned int suspended; ++ ++ struct i2c_msg *msg; ++ unsigned int msg_num; ++ unsigned int msg_idx; ++ unsigned int msg_ptr; ++ unsigned int msg_addr; ++ wait_queue_head_t msg_wait; ++ ++ unsigned int irq; ++ ++ enum gk_i2c_state state; ++ ++ void __iomem *regbase; ++ struct device *dev; ++ struct resource *ioarea; ++ struct i2c_adapter adap; ++ ++ struct gk_platform_i2c *pdata; ++ ++}; ++ ++static inline void gk_i2c_start_single_msg(struct gk_i2c *i2c) ++{ ++ if (i2c->msg->flags & I2C_M_TEN) ++ { ++ i2c->state = I2C_STATE_START_TEN; ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_DATA_OFFSET), ++ (0xf0 | ((i2c->msg_addr >> 8) & 0x07))); ++ } ++ else ++ { ++ i2c->state = I2C_STATE_START; ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_DATA_OFFSET), ++ (i2c->msg_addr & 0xff)); ++ } ++ ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_CTRL_OFFSET), ++ IDC_CTRL_START); ++} ++ ++static inline void gk_i2c_bulk_write(struct gk_i2c *i2c, u32 fifosize) ++{ ++ do ++ { ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_FMDATA_OFFSET), ++ i2c->msg->buf[i2c->msg_idx]); ++ i2c->msg_idx++; ++ fifosize--; ++ ++ if (i2c->msg_idx >= i2c->msg->len) ++ { ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_FMCTRL_OFFSET), ++ (IDC_FMCTRL_IF | IDC_FMCTRL_STOP)); ++ return; ++ } ++ } while (fifosize > 1); ++ ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_FMCTRL_OFFSET), ++ IDC_FMCTRL_IF); ++} ++ ++static inline void gk_i2c_start_bulk_msg_write(struct gk_i2c *i2c) ++{ ++ u32 fifosize = IDC_FIFO_BUF_SIZE; ++ ++ i2c->state = I2C_STATE_BULK_WRITE; ++ ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_FMCTRL_OFFSET), ++ IDC_FMCTRL_START); ++ ++ if (i2c->msg->flags & I2C_M_TEN) { ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_FMDATA_OFFSET), ++ (0xf0 | ((i2c->msg_addr >> 8) & 0x07))); ++ fifosize--; ++ } ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_FMDATA_OFFSET), ++ (i2c->msg_addr & 0xff)); ++ fifosize -= 2; ++ ++ gk_i2c_bulk_write(i2c, fifosize); ++} ++ ++/* gk_i2c_message_start ++ * ++ * put the start of a message onto the bus ++ */ ++static void gk_i2c_message_start(struct gk_i2c *i2c) ++{ ++ struct i2c_msg *msg = i2c->msg; ++ i2c->msg_idx = 0; ++ ++ i2c->msg_addr = ((msg->addr & 0x7f) << 1); ++ ++ if (msg->flags & I2C_M_RD) ++ i2c->msg_addr |= 1; ++ ++ if (msg->flags & I2C_M_REV_DIR_ADDR) ++ i2c->msg_addr ^= 1; ++ ++ if (msg->flags & I2C_M_RD) { ++ gk_i2c_start_single_msg(i2c); ++ } else if (msg->len > i2c->pdata->bulk_write_num) { ++ gk_i2c_start_bulk_msg_write(i2c); ++ } else { ++ gk_i2c_start_single_msg(i2c); ++ } ++ ++ dev_dbg(i2c->dev, "msg_addr[0x%x], len[0x%x]", i2c->msg_addr, i2c->msg->len); ++ ++} ++ ++static inline void gk_i2c_stop(struct gk_i2c *i2c, enum gk_i2c_state state, u32 *pack) ++{ ++ if(state != I2C_STATE_IDLE) { ++ //dev_warn(i2c->dev, "gk_i2c_stop[%d] from %d to %d\n", i2c->msg_num, i2c->state, state); ++ *pack |= IDC_CTRL_ACK; ++ } ++ ++ i2c->state = state; ++ i2c->msg = NULL; ++ i2c->msg_num = 0; ++ ++ *pack |= IDC_CTRL_STOP; ++ // StevenYu:Do not check state. ++ //if(i2c->state == I2C_STATE_IDLE) ++ wake_up(&i2c->msg_wait); ++} ++ ++static inline u32 gk_i2c_check_ack(struct gk_i2c *i2c, u32 *pack, u32 retry) ++{ ++ u32 retVal = IDC_CTRL_ACK; ++ //printk("gk_i2c_check_ack...\n"); ++ ++gk_i2c_check_ack_enter: ++ if (((*pack) & IDC_CTRL_ACK)==0) ++ //if (unlikely((*pack) & IDC_CTRL_ACK)) ++ { ++ //printk("pack: 0x%x\n", *pack); ++ if (i2c->msg->flags & I2C_M_IGNORE_NAK) ++ goto gk_i2c_check_ack_exit; ++ ++ if ((i2c->msg->flags & I2C_M_RD) && ++ (i2c->msg->flags & I2C_M_NO_RD_ACK)) ++ goto gk_i2c_check_ack_exit; ++ ++ if (retry--) { ++ udelay(100); ++ *pack = gk_i2c_readl((unsigned int)(i2c->regbase + IDC_CTRL_OFFSET)); ++ //printk("pack = 0x%x \n", *pack); ++ goto gk_i2c_check_ack_enter; ++ } ++ retVal = 0; ++ gk_i2c_stop(i2c, I2C_STATE_NO_ACK, pack); ++ } ++ ++gk_i2c_check_ack_exit: ++ return retVal; ++ ++} ++ ++/* gk_i2c_set_clk ++ * ++ * work out a divisor for the user requested frequency setting, ++ * either by the requested frequency, or scanning the acceptable ++ * range of frequencies until something is found ++*/ ++static void gk_i2c_set_clk(struct gk_i2c *i2c) ++{ ++ unsigned int apb_clk; ++ unsigned int idc_prescale; ++ ++ apb_clk = i2c->pdata->get_clock(); ++ //apb_clk = 30000000; ++ ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_ENR_OFFSET), ++ IDC_ENR_DISABLE); ++ ++ if ((i2c->pdata->clk_limit < 1000) || ++ (i2c->pdata->clk_limit > 400000)) ++ { ++ i2c->pdata->clk_limit = 100000; ++ } ++ ++// prescale = ((GD_GET_APB_ClkHz()/(U32)openParamsP->speed - 2) >> 2) - 1; ++ ++ idc_prescale = ((apb_clk / i2c->pdata->clk_limit -2) >> 2) - 1; ++ ++ //dev_dbg(i2c->dev, "apb_clk[%dHz]\n", apb_clk); ++ //dev_dbg(i2c->dev, "idc_prescale[%d]\n", idc_prescale); ++ //dev_dbg(i2c->dev, "clk[%dHz]\n", i2c->pdata->clk_limit); ++ ++ //dev_dbg(i2c->dev, "regbase 0x%08x\n", i2c->regbase); ++ ++ //gk_writel(i2c->regbase + IDC_PSLL_OFFSET, (idc_prescale & 0xff)); ++ //gk_writel(i2c->regbase + IDC_PSLH_OFFSET, ((idc_prescale & 0xff00) >> 8)); ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_PSLL_OFFSET), ++ (idc_prescale & 0xffff)); ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_ENR_OFFSET), ++ (IDC_ENR_ENABLE)); ++ ++ //dev_info(i2c->dev, "IDC_PSLL_OFFSET 0x%08x\n", gk_readb(i2c->regbase + IDC_PSLL_OFFSET)); ++ //dev_info(i2c->dev, "IDC_PSLH_OFFSET 0x%08x\n", gk_readb(i2c->regbase + IDC_PSLH_OFFSET)); ++ //dev_info(i2c->dev, "IDC_ENR_OFFSET 0x%08x\n", gk_readb(i2c->regbase + IDC_ENR_OFFSET)); ++ ++} ++ ++static inline void gk_i2c_hw_off(struct gk_i2c *i2c) ++{ ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_ENR_OFFSET), ++ IDC_ENR_DISABLE); ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_PSLL_OFFSET), 0); ++ //gk_writeb(i2c->regbase + IDC_PSLH_OFFSET, 0); ++} ++ ++/* gk_i2c_init ++ * ++ * initialise the controller, set the IO lines and frequency ++*/ ++static int gk_i2c_init(struct gk_i2c *i2c) ++{ ++ gk_i2c_set_clk(i2c); ++ ++ i2c->msg = NULL; ++ i2c->msg_num = 0; ++ i2c->state = I2C_STATE_IDLE; ++ ++ return 0; ++} ++ ++static irqreturn_t gk_i2c_irq(int irqno, void *dev_id) ++{ ++ struct platform_device *pdev; ++ struct gk_i2c *i2c; ++ ++ u32 status_reg; ++ u32 control_reg; ++ u32 ack_control = IDC_CTRL_CLS; ++ ++ i2c = (struct gk_i2c *)dev_id; ++ pdev = (struct platform_device *)i2c->dev->platform_data; ++ ++ status_reg = gk_i2c_readl((unsigned int)(i2c->regbase + IDC_STS_OFFSET)); ++ control_reg = gk_i2c_readl((unsigned int)(i2c->regbase + IDC_CTRL_OFFSET)); ++ ++ //dev_dbg(i2c->dev, "i2c[%d]:state[0x%x]\n", pdev->id, i2c->state); ++ //dev_dbg(i2c->dev, "i2c[%d]:status_reg[0x%x]\n", pdev->id, status_reg); ++ //dev_dbg(i2c->dev, "i2c[%d]:control_reg[0x%x]\n", pdev->id, control_reg); ++ ++ switch (i2c->state) ++ { ++ case I2C_STATE_START: ++ if (gk_i2c_check_ack(i2c, &control_reg, 0) == IDC_CTRL_ACK) ++ { ++ if (i2c->msg->flags & I2C_M_RD) ++ { ++ if (i2c->msg->len == 1) ++ ack_control |= IDC_CTRL_ACK; ++ i2c->state = I2C_STATE_READ; ++ } ++ else ++ { ++ i2c->state = I2C_STATE_WRITE; ++ goto i2c_irq_write; ++ } ++ } ++ break; ++ case I2C_STATE_START_TEN: ++ i2c->state = I2C_STATE_START; ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_DATA_OFFSET), ++ (i2c->msg_addr & 0xff)); ++ break; ++ case I2C_STATE_START_NEW: ++i2c_irq_start_new: ++ gk_i2c_message_start(i2c); ++ goto i2c_irq_exit; ++ break; ++ case I2C_STATE_READ_STOP: ++ i2c->msg->buf[i2c->msg_idx] = ++ gk_i2c_readl((unsigned int)(i2c->regbase + IDC_DATA_OFFSET)); ++ i2c->msg_idx++; ++i2c_irq_read_stop: ++ gk_i2c_stop(i2c, I2C_STATE_IDLE, &ack_control); ++ break; ++ case I2C_STATE_READ: ++ i2c->msg->buf[i2c->msg_idx] = ++ gk_i2c_readl((unsigned int)(i2c->regbase + IDC_DATA_OFFSET)); ++ i2c->msg_idx++; ++ ++ if (i2c->msg_idx >= i2c->msg->len - 1) ++ { ++ if (i2c->msg_num > 1) ++ { ++ i2c->msg++; ++ i2c->state = I2C_STATE_START_NEW; ++ i2c->msg_num--; ++ } ++ else ++ { ++ if (i2c->msg_idx > i2c->msg->len - 1) ++ { ++ goto i2c_irq_read_stop; ++ } ++ else ++ { ++ i2c->state = I2C_STATE_READ_STOP; ++ ack_control |= IDC_CTRL_ACK; ++ } ++ } ++ } ++ //ack_control |= IDC_CTRL_ACK; ++ break; ++ case I2C_STATE_WRITE: ++i2c_irq_write: ++ i2c->state = I2C_STATE_WRITE_WAIT_ACK; ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_DATA_OFFSET), ++ i2c->msg->buf[i2c->msg_idx]); ++ break; ++ case I2C_STATE_WRITE_WAIT_ACK: ++ if (gk_i2c_check_ack(i2c, &control_reg, 0) == IDC_CTRL_ACK) ++ { ++ i2c->state = I2C_STATE_WRITE; ++ i2c->msg_idx++; ++ ++ if (i2c->msg_idx >= i2c->msg->len) ++ { ++ if (i2c->msg_num > 1) ++ { ++ i2c->msg++; ++ i2c->state = I2C_STATE_START_NEW; ++ i2c->msg_num--; ++ goto i2c_irq_start_new; ++ } ++ gk_i2c_stop(i2c, I2C_STATE_IDLE, &ack_control); ++ } ++ else ++ { ++ goto i2c_irq_write; ++ } ++ } ++ break; ++ case I2C_STATE_BULK_WRITE: ++ if (gk_i2c_check_ack(i2c, &control_reg, CONFIG_I2C_GK_BULK_RETRY_NUM) == IDC_CTRL_ACK) ++ { ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_CTRL_OFFSET), ++ IDC_CTRL_ACK); ++ if (i2c->msg_idx >= i2c->msg->len) ++ { ++ if (i2c->msg_num > 1) ++ { ++ i2c->msg++; ++ i2c->state = I2C_STATE_START_NEW; ++ i2c->msg_num--; ++ goto i2c_irq_start_new; ++ } ++ gk_i2c_stop(i2c, I2C_STATE_IDLE, &ack_control); ++ } ++ else ++ { ++ gk_i2c_bulk_write(i2c, IDC_FIFO_BUF_SIZE); ++ } ++ goto i2c_irq_exit; ++ } ++ else ++ { ++ ack_control = IDC_CTRL_ACK; ++ } ++ break; ++ default: ++ dev_err(i2c->dev, "i2c[%d]:gk_i2c_irq in wrong state[0x%x]\n", pdev->id, i2c->state); ++ //dev_err(i2c->dev, "i2c[%d]:status_reg[0x%x]\n", pdev->id, status_reg); ++ //dev_err(i2c->dev, "i2c[%d]:control_reg[0x%x]\n", pdev->id, control_reg); ++ ack_control = IDC_CTRL_STOP | IDC_CTRL_ACK; ++ i2c->state = I2C_STATE_ERROR; ++ break; ++ } ++ ++ gk_i2c_writel((unsigned int)(i2c->regbase + IDC_CTRL_OFFSET), ack_control); ++ ++i2c_irq_exit: ++ return IRQ_HANDLED; ++ ++} ++ ++/* gk_i2c_doxfer ++ * ++ * this starts an i2c transfer ++ */ ++static int gk_i2c_doxfer(struct gk_i2c *i2c, struct i2c_msg *msgs, int num) ++{ ++ unsigned long timeout; ++ int ret; ++ ++ if (i2c->suspended) return -EIO; ++ ++ spin_lock_irq(&i2c->lock); ++ ++ i2c->msg = msgs; ++ i2c->msg_num = num; ++ i2c->msg_ptr = 0; ++ i2c->msg_idx = 0; ++ i2c->state = I2C_STATE_START; ++ ++ gk_i2c_message_start(i2c); ++ spin_unlock_irq(&i2c->lock); ++ ++ // StevenYu:delete the delay. ++ //mdelay(1); ++ timeout = wait_event_timeout(i2c->msg_wait, i2c->msg_num == 0, CONFIG_I2C_GK_ACK_TIMEOUT); ++ ++ ret = i2c->msg_idx; ++ ++ /* having these next two as dev_err() makes life very ++ * noisy when doing an i2cdetect */ ++ ++ if (timeout == 0) ++ dev_dbg(i2c->dev, "timeout\n"); ++ else if (ret != num) ++ dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); ++ ++ /* ensure the stop has been through the bus */ ++ dev_dbg(i2c->dev, "%ld jiffies left.\n", timeout); ++ ++ if (i2c->state != I2C_STATE_IDLE) ++ { ++ dev_err(i2c->dev,"I2C state 0x%d, please check address 0x%x!\n", i2c->state, i2c->msg_addr); ++ ret = -EAGAIN; ++ } ++ ++ return ret; ++ ++} ++ ++static int gk_i2c_doxfer_noevent(struct gk_i2c *i2c, struct i2c_msg *msgs, int num) ++{ ++ unsigned long timeout; ++ int ret; ++ unsigned long flags; ++ ++ if (i2c->suspended) return -EIO; ++ ++ spin_lock_irq(&i2c->lock); ++ i2c->msg = msgs; ++ i2c->msg_num = num; ++ i2c->msg_ptr = 0; ++ i2c->msg_idx = 0; ++ i2c->state = I2C_STATE_START; ++ gk_i2c_message_start(i2c); ++ spin_unlock_irq(&i2c->lock); ++ ++ while(i2c->state != I2C_STATE_IDLE) ++ { ++ udelay(10); ++ } ++ ++ ret = i2c->msg_idx; ++ ++ /* having these next two as dev_err() makes life very ++ * noisy when doing an i2cdetect */ ++ ++ if (timeout == 0) ++ dev_dbg(i2c->dev, "timeout\n"); ++ else if (ret != num) ++ dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); ++ ++ /* ensure the stop has been through the bus */ ++ dev_dbg(i2c->dev, "%ld jiffies left.\n", timeout); ++ ++ if (i2c->state != I2C_STATE_IDLE) ++ { ++ dev_err(i2c->dev,"I2C state 0x%d, please check address 0x%x!\n", i2c->state, i2c->msg_addr); ++ ret = -EAGAIN; ++ } ++ ++ return ret; ++} ++ ++/* gk_i2c_xfer ++ * ++ * first port of call from the i2c bus code when an message needs ++ * transferring across the i2c bus. ++ */ ++ ++static int gk_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ++{ ++ struct gk_i2c *i2c = (struct gk_i2c *)adap->algo_data; ++ int retry; ++ int ret; ++ ++ //pm_runtime_get_sync(&adap->dev); ++ ++ for (retry = 0; retry < adap->retries; retry++) ++ { ++ if (i2c->state != I2C_STATE_IDLE) ++ { ++ gk_i2c_init(i2c); ++ } ++ ++ ret = gk_i2c_doxfer(i2c, msgs, num); ++ //printk("do xfer ret: %d \n", ret); ++ if (ret != -EAGAIN) ++ { ++ //pm_runtime_put_sync(&adap->dev); ++ return num;//ret; ++ } ++ ++ dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry); ++ ++ udelay(100); ++ } ++ ++ //pm_runtime_put_sync(&adap->dev); ++ return -EREMOTEIO; ++ ++} ++ ++ ++static int gk_i2c_xfer_noevent(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ++{ ++ struct gk_i2c *i2c = (struct gk_i2c *)adap->algo_data; ++ int retry; ++ int ret; ++ ++ //pm_runtime_get_sync(&adap->dev); ++ ++ for (retry = 0; retry < adap->retries; retry++) ++ { ++ if (i2c->state != I2C_STATE_IDLE) ++ { ++ gk_i2c_init(i2c); ++ } ++ ++ ret = gk_i2c_doxfer_noevent(i2c, msgs, num); ++ //printk("do xfer ret: %d \n", ret); ++ if (ret != -EAGAIN) ++ { ++ //pm_runtime_put_sync(&adap->dev); ++ return num;//ret; ++ } ++ ++ dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry); ++ ++ udelay(100); ++ } ++ ++ //pm_runtime_put_sync(&adap->dev); ++ return -EREMOTEIO; ++ ++} ++/* declare our i2c functionality */ ++static u32 gk_i2c_func(struct i2c_adapter *adap) ++{ ++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; ++} ++ ++/* i2c bus registration info */ ++ ++static const struct i2c_algorithm gk_i2c_algorithm = { ++ .master_xfer = gk_i2c_xfer, ++ .master_xfer_noevent = gk_i2c_xfer_noevent, ++ .functionality = gk_i2c_func, ++}; ++ ++/* gk_i2c_probe ++ * ++ * called by the bus driver when a suitable device is found ++ */ ++ ++static int gk_i2c_probe(struct platform_device *pdev) ++{ ++ struct gk_i2c *i2c; ++ struct gk_platform_i2c *pdata = NULL; ++ struct resource *res; ++ ++ int ret; ++ ++ pdata = (struct gk_platform_i2c *)pdev->dev.platform_data; ++ if (!pdata) { ++ dev_err(&pdev->dev, "i2c[%d]: Can't get platform_data!\n", pdev->id); ++ return -EINVAL; ++ } ++ ++ i2c = devm_kzalloc(&pdev->dev, sizeof(struct gk_i2c), GFP_KERNEL); ++ if (!i2c) { ++ dev_err(&pdev->dev, "no memory for i2c[%d]\n", pdev->id); ++ return -ENOMEM; ++ } ++ ++ /* setup info block for the i2c core */ ++ strlcpy(i2c->adap.name, pdev->name, sizeof(i2c->adap.name)); ++ i2c->adap.owner = THIS_MODULE; ++ i2c->adap.algo = &gk_i2c_algorithm; ++ i2c->adap.retries = CONFIG_I2C_GK_RETRIES; ++ i2c->adap.class = (I2C_CLASS_HWMON | I2C_CLASS_SPD); ++ i2c->adap.nr = pdev->id; ++ i2c->adap.algo_data = i2c; ++ i2c->adap.dev.parent = &pdev->dev; ++ ++ i2c->pdata = pdata; ++ ++ spin_lock_init(&i2c->lock); ++ init_waitqueue_head(&i2c->msg_wait); ++ ++ /* find the clock and enable it */ ++ i2c->dev = &pdev->dev; ++ ++ /* map the registers */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (res == NULL) { ++ dev_err(&pdev->dev, "Get I2C[%d] mem resource failed!\n", pdev->id); ++ ret = -ENOENT; ++ goto err_noclk; ++ } ++#if 0 ++ ++ i2c->ioarea = request_mem_region(res->start, resource_size(res), pdev->name); ++ if (i2c->ioarea == NULL) { ++ dev_err(&pdev->dev, "Request I2C[%d] ioarea failed!\n", pdev->id); ++ ret = -ENXIO; ++ goto err_noclk; ++ } ++ ++ ++ i2c->regbase = ioremap(res->start, resource_size(res)); ++ if (i2c->regbase == NULL) { ++ dev_err(&pdev->dev, "i2c[%d] cannot map IO\n", pdev->id); ++ ret = -ENXIO; ++ goto err_ioarea; ++ } ++ dev_err(&pdev->dev, "i2c[%d]:registers %p (%p, %p)\n", pdev->id, i2c->regbase, i2c->ioarea, res); ++#else ++ i2c->regbase = (void __iomem*)res->start; ++ printk("i2c regbase: 0x%x \n", (u32)i2c->regbase); ++#endif ++ ++ /* initialise the i2c controller */ ++ ret = gk_i2c_init(i2c); ++ if (ret != 0) ++ goto err_iomap; ++ ++ /* find the IRQ for this unit (note, this relies on the init call to ++ * ensure no current IRQs pending ++ */ ++ i2c->irq = ret = platform_get_irq(pdev, 0); ++ if (ret <= 0) { ++ dev_err(&pdev->dev, "Get I2C[%d] irq resource failed!\n", pdev->id); ++ goto err_iomap; ++ } ++ ++ dev_info(&pdev->dev, "i2c irq:registers %d\n", i2c->irq); ++ ret = request_irq(i2c->irq, gk_i2c_irq, IRQF_TRIGGER_HIGH, dev_name(&pdev->dev), i2c); ++ if (ret != 0) { ++ dev_err(&pdev->dev, "Request i2c[%d] IRQ=%d failed!\n", pdev->id, i2c->irq); ++ goto err_iomap; ++ } ++ ++ i2c_set_adapdata(&i2c->adap, i2c); ++ /* Note, previous versions of the driver used i2c_add_adapter() ++ * to add the bus at any number. We now pass the bus number via ++ * the platform data, so if unset it will now default to always ++ * being bus 0. ++ */ ++ ret = i2c_add_numbered_adapter(&i2c->adap); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "i2c[%d] Failed to add bus to i2c core\n", pdev->id); ++ goto err_irq; ++ } ++ ++ platform_set_drvdata(pdev, i2c); ++ ++ //pm_runtime_enable(&pdev->dev); ++ //pm_runtime_enable(&i2c->adap.dev); ++ ++ dev_info(&pdev->dev, "GK I2C[%d] adapter[%s] probed!\n", pdev->id, dev_name(&i2c->adap.dev)); ++ return 0; ++ ++ err_irq: ++ free_irq(i2c->irq, i2c); ++ ++ err_iomap: ++// iounmap(i2c->regbase); ++ ++ //err_ioarea: ++ //release_mem_region(i2c->ioarea->start, (i2c->ioarea->end - i2c->ioarea->start) + 1); ++ kfree(i2c); ++ ++ err_noclk: ++ return ret; ++ ++} ++ ++/* gk_i2c_remove ++ * ++ * called when device is removed from the bus ++*/ ++ ++static int gk_i2c_remove(struct platform_device *pdev) ++{ ++ struct gk_i2c *i2c = platform_get_drvdata(pdev); ++ ++ if(i2c) ++ { ++ gk_i2c_hw_off(i2c); ++ ++ //pm_runtime_disable(&i2c->adap.dev); ++ //pm_runtime_disable(&pdev->dev); ++ ++ i2c_del_adapter(&i2c->adap); ++ free_irq(i2c->irq, i2c); ++#if 0 ++ iounmap(i2c->regbase); ++ ++ release_mem_region(i2c->ioarea->start, (i2c->ioarea->end - i2c->ioarea->start) + 1); ++#endif ++ kfree(i2c); ++ } ++ ++ return 0; ++ ++} ++ ++#ifdef CONFIG_PM ++static int gk_i2c_suspend_noirq(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct gk_i2c *i2c = platform_get_drvdata(pdev); ++ ++ if(i2c){ ++ i2c->suspended = 1; ++ disable_irq(i2c->irq); ++ } ++ ++ dev_dbg(&pdev->dev, "%s\n", __func__); ++ ++ return 0; ++} ++ ++static int gk_i2c_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct gk_i2c *i2c = platform_get_drvdata(pdev); ++ ++ if(i2c){ ++ i2c->suspended = 0; ++ gk_i2c_init(i2c); ++ } ++ ++ dev_dbg(&pdev->dev, "%s\n", __func__); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops gk_i2c_dev_pm_ops = { ++ .suspend_noirq = gk_i2c_suspend_noirq, ++ .resume = gk_i2c_resume, ++}; ++ ++#define GK_I2C_DEV_PM_OPS (&gk_i2c_dev_pm_ops) ++#else ++#define GK_I2C_DEV_PM_OPS NULL ++#endif ++ ++/* device driver for platform bus bits */ ++static struct platform_driver gk_i2c_driver = { ++ .probe = gk_i2c_probe, ++ .remove = gk_i2c_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "i2c", ++ .pm = GK_I2C_DEV_PM_OPS, ++ }, ++}; ++ ++static int __init gk_i2c_adap_init(void) ++{ ++ return platform_driver_register(&gk_i2c_driver); ++} ++subsys_initcall(gk_i2c_adap_init); ++ ++static void __exit gk_i2c_adap_exit(void) ++{ ++ platform_driver_unregister(&gk_i2c_driver); ++} ++module_exit(gk_i2c_adap_exit); ++ ++MODULE_DESCRIPTION("GK I2C Bus driver"); ++MODULE_AUTHOR("Kewell Liu, "); ++MODULE_LICENSE("GPL"); ++ +diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c +index feb7dc35..c1485fc6 100644 +--- a/drivers/i2c/i2c-core.c ++++ b/drivers/i2c/i2c-core.c +@@ -1366,6 +1366,40 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) + } + EXPORT_SYMBOL(i2c_transfer); + ++int i2c_transfer_noevent(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ++{ ++ unsigned long orig_jiffies; ++ int ret, try; ++ ++ /* REVISIT the fault reporting model here is weak: ++ * ++ * - When we get an error after receiving N bytes from a slave, ++ * there is no way to report "N". ++ * ++ * - When we get a NAK after transmitting N bytes to a slave, ++ * there is no way to report "N" ... or to let the master ++ * continue executing the rest of this combined message, if ++ * that's the appropriate response. ++ * ++ * - When for example "num" is two and we successfully complete ++ * the first message but get an error part way through the ++ * second, it's unclear whether that should be reported as ++ * one (discarding status on the second message) or errno ++ * (discarding status on the first one). ++ */ ++ /* Retry automatically on arbitration loss */ ++ orig_jiffies = jiffies; ++ for (ret = 0, try = 0; try <= adap->retries; try++) { ++ ret = adap->algo->master_xfer_noevent(adap, msgs, num); ++ if (ret != -EAGAIN) ++ break; ++ if (time_after(jiffies, orig_jiffies + adap->timeout)) ++ break; ++ } ++ return ret; ++} ++EXPORT_SYMBOL(i2c_transfer_noevent); ++ + /** + * i2c_master_send - issue a single I2C message in master transmit mode + * @client: Handle to slave device +diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig +index 90b7a016..c2e955ce 100644 +--- a/drivers/i2c/muxes/Kconfig ++++ b/drivers/i2c/muxes/Kconfig +@@ -17,6 +17,17 @@ config I2C_MUX_GPIO + This driver can also be built as a module. If so, the module + will be called gpio-i2cmux. + ++config I2C_MUX_GOKE ++ tristate "goke ipc I2C multiplexer" ++ depends on I2C_GOKE ++ help ++ If you say yes to this option, support will be included for a ++ goke ipc I2C multiplexer. This driver provides access to ++ I2C busses with an internal MUX, which is controlled ++ through GPIO pin functions. ++ This driver can also be built as a module. If so, the module ++ will be called goke-i2cmux_v1_00. ++ + config I2C_MUX_PCA9541 + tristate "NXP PCA9541 I2C Master Selector" + depends on EXPERIMENTAL +diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile +index 4640436e..d9996612 100644 +--- a/drivers/i2c/muxes/Makefile ++++ b/drivers/i2c/muxes/Makefile +@@ -5,4 +5,8 @@ obj-$(CONFIG_I2C_MUX_GPIO) += gpio-i2cmux.o + obj-$(CONFIG_I2C_MUX_PCA9541) += pca9541.o + obj-$(CONFIG_I2C_MUX_PCA954x) += pca954x.o + ++ifdef CONFIG_I2C_MUX_GOKE ++obj-$(CONFIG_GK_I2C_V1_00) += goke-i2cmux_v1_00.o ++endif ++ + ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG +diff --git a/drivers/i2c/muxes/goke-i2cmux_v1_00.c b/drivers/i2c/muxes/goke-i2cmux_v1_00.c +new file mode 100644 +index 00000000..98ae11da +--- /dev/null ++++ b/drivers/i2c/muxes/goke-i2cmux_v1_00.c +@@ -0,0 +1,134 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct gk_mux { ++ struct i2c_adapter *parent; ++ struct i2c_adapter *adap; /* child busses */ ++ struct gk_i2cmux_platform_data data; ++}; ++ ++static int gk_mux_select(struct i2c_adapter *adap, void *data, u32 chan) ++{ ++ struct gk_mux *mux = data; ++ ++ gk_gpio_config(mux->data.gpio, mux->data.select_function); ++ ++ return 0; ++} ++ ++static int gk_mux_deselect(struct i2c_adapter *adap, void *data, u32 chan) ++{ ++ struct gk_mux *mux = data; ++ ++ gk_gpio_config(mux->data.gpio, mux->data.deselect_function); ++ ++ return 0; ++} ++ ++static int __devinit gk_mux_probe(struct platform_device *pdev) ++{ ++ struct gk_mux *mux; ++ struct gk_i2cmux_platform_data *pdata; ++ struct i2c_adapter *parent; ++ int ret = 0; ++ ++ pdata = pdev->dev.platform_data; ++ if (!pdata) { ++ dev_err(&pdev->dev, "Missing platform data\n"); ++ return -ENODEV; ++ } ++ ++ parent = i2c_get_adapter(pdata->parent); ++ if (!parent) { ++ dev_err(&pdev->dev, "Parent adapter (%d) not found\n", ++ pdata->parent); ++ return -ENODEV; ++ } ++ ++ mux = kzalloc(sizeof(*mux), GFP_KERNEL); ++ if (!mux) { ++ ret = -ENOMEM; ++ goto alloc_failed; ++ } ++ ++ mux->parent = parent; ++ mux->data = *pdata; ++ mux->adap = i2c_add_mux_adapter(parent, mux, pdata->number, 0, ++ gk_mux_select, gk_mux_deselect); ++ if (!mux->adap) { ++ ret = -ENODEV; ++ dev_err(&pdev->dev, "Failed to add mux adapter\n"); ++ goto add_adapter_failed; ++ } ++ ++ gk_mux_deselect(mux->adap, mux, 0); ++ dev_info(&pdev->dev, "mux on %s adapter\n", parent->name); ++ ++ platform_set_drvdata(pdev, mux); ++ ++ goto gk_mux_probe_exit; ++ ++add_adapter_failed: ++ i2c_del_mux_adapter(mux->adap); ++ kfree(mux); ++ ++alloc_failed: ++ i2c_put_adapter(parent); ++ ++gk_mux_probe_exit: ++ return ret; ++} ++ ++static int __devexit gk_mux_remove(struct platform_device *pdev) ++{ ++ struct gk_mux *mux; ++ ++ mux = platform_get_drvdata(pdev); ++ if (mux) { ++ i2c_del_mux_adapter(mux->adap); ++ platform_set_drvdata(pdev, NULL); ++ i2c_put_adapter(mux->parent); ++ kfree(mux); ++ } ++ ++ return 0; ++} ++ ++static struct platform_driver gk_mux_driver = { ++ .probe = gk_mux_probe, ++ .remove = __devexit_p(gk_mux_remove), ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "gk-i2cmux", ++ }, ++}; ++ ++static int __init gk_mux_init(void) ++{ ++ return platform_driver_register(&gk_mux_driver); ++} ++ ++static void __exit gk_mux_exit(void) ++{ ++ platform_driver_unregister(&gk_mux_driver); ++} ++ ++subsys_initcall(gk_mux_init); ++module_exit(gk_mux_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("GOKE MICROELECTRONICS Inc."); ++MODULE_DESCRIPTION("GOKE I2C Driver"); ++ +diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig +index 7faf4a7f..957397f6 100644 +--- a/drivers/input/misc/Kconfig ++++ b/drivers/input/misc/Kconfig +@@ -12,6 +12,12 @@ menuconfig INPUT_MISC + + if INPUT_MISC + ++config INPUT_GOKE_IR ++ tristate "Support goke ipc IR" ++ depends on GK_IR ++ help ++ gk7101 general input. It can support Virtual input from proc, IR and GPIO. ++ + config INPUT_88PM860X_ONKEY + tristate "88PM860x ONKEY support" + depends on MFD_88PM860X +diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile +index f55cdf49..b43b7aa5 100644 +--- a/drivers/input/misc/Makefile ++++ b/drivers/input/misc/Makefile +@@ -4,6 +4,10 @@ + + # Each configuration option enables a list of files. + ++ifdef CONFIG_INPUT_GOKE_IR ++obj-$(CONFIG_GK_IR_V1_00) += gk_ir_v1_00.o ++endif ++ + obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o + obj-$(CONFIG_INPUT_AB8500_PONKEY) += ab8500-ponkey.o + obj-$(CONFIG_INPUT_AD714X) += ad714x.o +diff --git a/drivers/input/misc/gk_ir_nec.c b/drivers/input/misc/gk_ir_nec.c +new file mode 100644 +index 00000000..2d298375 +--- /dev/null ++++ b/drivers/input/misc/gk_ir_nec.c +@@ -0,0 +1,320 @@ ++/* ++ * drivers/input/misc/gk_ir_nec.c ++ * ++ */ ++ ++#include ++#include ++ ++#include ++ ++/** ++ * Pulse-Width-Coded Signals vary the length of pulses to code the information. ++ * In this case if the pulse width is short (approximately 550us) it ++ * corresponds to a logical zero or a low. If the pulse width is long ++ * (approximately 2200us) it corresponds to a logical one or a high. ++ * ++ * +--+ +--+ +----+ +----+ ++ * | | | | | | | | ++ * ---+ +--+ +--+ +--+ +--- ++ * 0 0 1 1 ++ */ ++ ++/* NEC - APEX - HITACHI - PIONEER */ ++#define NEC_DEFAULT_FREQUENCY 36000 /* 36KHz */ ++#define NEC_DEFAULT_SMALLER_TIME 560 /* T, 560 microseconds. */ ++ ++/** bit 0 [1120us] ++ * ---+ +----+ ++ * | | | ++ * +----+ +--- ++ * -T +T ++ */ ++ ++/** bit 1 [2240us] ++ * ---+ +------------+ ++ * | | | ++ * +----+ +--- ++ * -T +3T ++ */ ++ ++/** start [13.3ms] ++ * ---+ +---------------+ ++ * | | | ++ * +--------------------------------+ +--- ++ * -16T(9ms) +7.5T(4.2ms) ++ */ ++ ++/** Subsequent Frame [11.3ms] ++ * ---+ +--------+ +--- ++ * | | | | ++ * +--------------------------------+ +--+ ++ * -16T(9ms) +4T(2.2ms) ++ */ ++ ++#define NEC_LEADER_LOW_UPBOUND 123 /* default 9ms */ ++#define NEC_LEADER_LOW_LOWBOUND 113 ++#define NEC_LEADER_HIGH_UPBOUND 63 /* default 4.2ms */ ++#define NEC_LEADER_HIGH_LOWBOUND 52 ++ ++#define SAM_LEADER_LOW_UPBOUND 64 /* default 4.5ms */ ++#define SAM_LEADER_LOW_LOWBOUND 50 ++#define SAM_LEADER_HIGH_UPBOUND 64 /* default 4.5ms */ ++#define SAM_LEADER_HIGH_LOWBOUND 50 ++ ++#define NEC_REPEAT_LOW_UPBOUND 123 /* default 9ms */ ++#define NEC_REPEAT_LOW_LOWBOUND 113 ++#define NEC_REPEAT_HIGH_UPBOUND 33 /* default 2.2ms */ ++#define NEC_REPEAT_HIGH_LOWBOUND 23 ++ ++#define NEC_DATA_LOW_UPBOUND 12 /* default 560us */ ++#define NEC_DATA_LOW_LOWBOUND 1 ++#define NEC_DATA_0_HIGH_UPBOUND 12 /* default 560us */ ++#define NEC_DATA_0_HIGH_LOWBOUND 1 ++#define NEC_DATA_1_HIGH_UPBOUND 26 /* default 1680us */ ++#define NEC_DATA_1_HIGH_LOWBOUND 15 ++ ++/** ++ * Check the waveform data is leader code or not. ++ */ ++static int gk_ir_nec_pulse_leader_code(struct gk_ir_info *pinfo) ++{ ++ int check_sam = 0; ++ ++ u16 val = gk_ir_read_data(pinfo, pinfo->ir_pread); ++ ++ if ((val < NEC_LEADER_LOW_UPBOUND) && ++ (val > NEC_LEADER_LOW_LOWBOUND)) { ++ } else { ++ if ((val < SAM_LEADER_LOW_UPBOUND) && ++ (val > SAM_LEADER_LOW_LOWBOUND)) { ++ check_sam = 1; ++ } else { ++ return 0; ++ } ++ } ++ ++ if ((pinfo->ir_pread + 1) >= MAX_IR_BUFFER) { ++ val = gk_ir_read_data(pinfo, 0); ++ } else { ++ val = gk_ir_read_data(pinfo, pinfo->ir_pread + 1); ++ } ++ ++ if (check_sam) { ++ if ((val < SAM_LEADER_HIGH_UPBOUND) && ++ (val > SAM_LEADER_HIGH_LOWBOUND) ) ++ return 1; ++ else ++ return 0; ++ } else { ++ if ((val < NEC_LEADER_HIGH_UPBOUND) && ++ (val > NEC_LEADER_HIGH_LOWBOUND) ) ++ return 1; ++ else ++ return 0; ++ } ++} ++ ++static int gk_ir_nec_find_head(struct gk_ir_info *pinfo) ++{ ++ int i, val = 0; ++ ++ i = gk_ir_get_tick_size(pinfo) - pinfo->frame_info.frame_head_size + 1; ++ ++ while(i--) { ++ if(gk_ir_nec_pulse_leader_code(pinfo)) { ++ dev_dbg(&pinfo->pinput_dev->dev, "find leader code, i [%d]\n", i); ++ val = 1; ++ break; ++ } else { ++ dev_dbg(&pinfo->pinput_dev->dev, "didn't find leader code, i [%d]\n", i); ++ gk_ir_move_read_ptr(pinfo, 1); ++ } ++ } ++ ++ return val ; ++} ++/** ++ * Check the waveform data is subsequent code or not. ++ */ ++static int gk_ir_nec_pulse_subsequent_code(struct gk_ir_info *pinfo) ++{ ++ u16 val = gk_ir_read_data(pinfo, pinfo->ir_pread); ++ ++ if ((val < NEC_REPEAT_LOW_UPBOUND) && ++ (val > NEC_REPEAT_LOW_LOWBOUND)) { ++ } else { ++ return 0; ++ } ++ ++ if ((pinfo->ir_pread + 1) >= MAX_IR_BUFFER) { ++ val = gk_ir_read_data(pinfo, 0); ++ } else { ++ val = gk_ir_read_data(pinfo, pinfo->ir_pread + 1); ++ } ++ ++ if ((val < NEC_REPEAT_HIGH_UPBOUND) && ++ (val > NEC_REPEAT_HIGH_LOWBOUND) ) ++ return 1; ++ else ++ return 0; ++} ++ ++static int gk_ir_nec_find_subsequent(struct gk_ir_info *pinfo) ++{ ++ int i, val = 0; ++ ++ i = gk_ir_get_tick_size(pinfo) - pinfo->frame_info.frame_head_size + 1; ++ ++ while(i--) { ++ if(gk_ir_nec_pulse_subsequent_code(pinfo)) { ++ dev_dbg(&pinfo->pinput_dev->dev, "find leader code, i [%d]\n", i); ++ val = 1; ++ break; ++ } else { ++ dev_dbg(&pinfo->pinput_dev->dev, "didn't find leader code, i [%d]\n", i); ++ gk_ir_move_read_ptr(pinfo, 1); ++ } ++ } ++ ++ return val ; ++} ++ ++/** ++ * Check the waveform data is 0 bit or not. ++ */ ++static int gk_ir_nec_pulse_code_0(struct gk_ir_info *pinfo) ++{ ++ u16 val = gk_ir_read_data(pinfo, pinfo->ir_pread); ++ if ((val < NEC_DATA_LOW_UPBOUND) && ++ (val > NEC_DATA_LOW_LOWBOUND)) { ++ } else { ++ return 0; ++ } ++ ++ if ((pinfo->ir_pread + 1) >= MAX_IR_BUFFER) { ++ val = gk_ir_read_data(pinfo, 0); ++ } else { ++ val = gk_ir_read_data(pinfo, pinfo->ir_pread + 1); ++ } ++ ++ if ((val < NEC_DATA_0_HIGH_UPBOUND) && ++ (val > NEC_DATA_0_HIGH_LOWBOUND) ) ++ return 1; ++ else ++ return 0; ++} ++ ++/** ++ * Check the waveform data is 1 bit or not. ++ */ ++static int gk_ir_nec_pulse_code_1(struct gk_ir_info *pinfo) ++{ ++ u16 val = gk_ir_read_data(pinfo, pinfo->ir_pread); ++ ++ if ((val < NEC_DATA_LOW_UPBOUND) && ++ (val > NEC_DATA_LOW_LOWBOUND)) { ++ } else { ++ return 0; ++ } ++ ++ if ((pinfo->ir_pread + 1) >= MAX_IR_BUFFER) { ++ val = gk_ir_read_data(pinfo, 0); ++ } else { ++ val = gk_ir_read_data(pinfo, pinfo->ir_pread + 1); ++ } ++ ++ if ((val < NEC_DATA_1_HIGH_UPBOUND) && ++ (val > NEC_DATA_1_HIGH_LOWBOUND) ) ++ return 1; ++ else ++ return 0; ++} ++ ++static int gk_ir_nec_pulse_data_translate(struct gk_ir_info *pinfo, u8 * data) ++{ ++ int i; ++ *data = 0; ++ ++ for (i = 7; i >= 0; i--) { ++ if (gk_ir_nec_pulse_code_0(pinfo)) { ++ ++ } else if (gk_ir_nec_pulse_code_1(pinfo)) { ++ *data |= 1 << i; ++ } else { ++ dev_dbg(&pinfo->pinput_dev->dev, "%d ERROR, the waveform can't match\n", i); ++ return -1; ++ } ++ gk_ir_move_read_ptr(pinfo, 2); ++ } ++ ++ return 0; ++} ++ ++static int gk_ir_nec_pulse_decode(struct gk_ir_info *pinfo, u32 *uid) ++{ ++ u8 addr = 0, inv_addr = 0, data = 0, inv_data = 0; ++ int rval; ++ ++ /* Then follows 32 bits of data, broken down in 4 bytes of 8 bits. */ ++ ++ /* The first 8 bits is the Address. */ ++ rval = gk_ir_nec_pulse_data_translate(pinfo, &addr); ++ if (rval < 0) ++ return rval; ++ ++ /* The second 8 bits is the Address Complement. */ ++ rval = gk_ir_nec_pulse_data_translate(pinfo, &inv_addr); ++ if (rval < 0) ++ return rval; ++ ++ /* The third 8 bits is the data. */ ++ rval = gk_ir_nec_pulse_data_translate(pinfo, &data); ++ if (rval < 0) ++ return rval; ++ ++ /* The fourth 8 bits is the data Complement. */ ++ rval = gk_ir_nec_pulse_data_translate(pinfo, &inv_data); ++ if (rval < 0) ++ return rval; ++ ++ dev_dbg(&pinfo->pinput_dev->dev, "addr\tinv_addr\tdata\tinv_data\n"); ++ dev_dbg(&pinfo->pinput_dev->dev, "0x%x\t0x%x\t\t0x%x\t0x%x\n", addr, inv_addr, data, inv_data); ++ ++ *uid = (addr << 24) | (inv_addr << 16) | (data << 8) | inv_data; ++ ++ return 0; ++} ++ ++int gk_ir_nec_parse(struct gk_ir_info *pinfo, u32 *uid) ++{ ++ int rval; ++ int cur_ptr = pinfo->ir_pread; ++ ++ if ((gk_ir_nec_find_head(pinfo) || (gk_ir_nec_find_subsequent(pinfo))) ++ && gk_ir_get_tick_size(pinfo) >= pinfo->frame_info.frame_data_size ++ + pinfo->frame_info.frame_head_size) ++ { ++ dev_dbg(&pinfo->pinput_dev->dev, "go to decode statge\n"); ++ gk_ir_move_read_ptr(pinfo, pinfo->frame_info.frame_head_size);//move ptr to data ++ rval = gk_ir_nec_pulse_decode(pinfo, uid); ++ } else { ++ return -1; ++ } ++ ++ if (rval >= 0) { ++ dev_dbg(&pinfo->pinput_dev->dev, "buffer[%d]-->mornal key\n", cur_ptr); ++ return 0; ++ } ++ ++ return (-1); ++} ++ ++void gk_ir_get_nec_info(struct gk_ir_frame_info *pframe_info) ++{ ++ pframe_info->frame_head_size = 2; ++ pframe_info->frame_data_size = 64; ++ pframe_info->frame_end_size = 1; ++ pframe_info->frame_repeat_head_size = 4; ++} ++ +diff --git a/drivers/input/misc/gk_ir_v1_00.c b/drivers/input/misc/gk_ir_v1_00.c +new file mode 100644 +index 00000000..01221545 +--- /dev/null ++++ b/drivers/input/misc/gk_ir_v1_00.c +@@ -0,0 +1,1134 @@ ++/* ++ * drivers/input/misc/gk_ir_v1_00.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++ ++#define BOARD_FPGA 1 ++#ifdef BOARD_FPGA ++#define IR_INPUT_CLK 24000000 // for 27MHZ Crystal ++#else ++#define IR_INPUT_CLK 24000000 // for 24MHZ Crystal ++#endif ++ ++#define IR_FREQ 38 // for NEC unit:MHz ++ ++#define IRR_MAX_DATA 0x0100 ++static u16 IrBuffer[IRR_MAX_DATA] = {0}; ++static u16 IrWritePointer = 0; ++static u16 IrDataNumber = 0; //number of the received data. ++static u16 IrSeqNumber = 0; //number of the sequence command ++static u16 IrReadPointer = 0; ++static u8 IrBufferOver = 0; ++static u8 IrBufferOverApi = 0; ++static u8 IRDataAvailable = 0; ++ ++static uint32_t lastKey = 0; ++static uint32_t lastDeviceId = 0; ++static uint32_t lastRepeatFlag = 0; ++ ++ ++/* ========================================================================= */ ++#define MAX_IR_BUFFER (512) ++#define HW_FIFO_BUFFER (48) ++#define MSC_GKIRKEYINFO 0x5 ++#define GK_IR_KEYPRESS_TIMEOUT 300 ++ ++static struct gk_key_table keymap[] = ++{ ++ {GKINPUT_IR_KEY, {.ir_key = {KEY_POWER, 3, 0x0b}}}, //POWER ++ {GKINPUT_IR_KEY, {.ir_key = {KEY_0, 3, 0x0c}}}, //KEY 0 ++ {GKINPUT_IR_KEY, {.ir_key = {KEY_1, 3, 0x1b}}}, //KEY 1 ++ {GKINPUT_IR_KEY, {.ir_key = {KEY_2, 3, 0x0f}}}, //KEY 2 ++ {GKINPUT_IR_KEY, {.ir_key = {KEY_3, 3, 0x03}}}, //KEY 3 ++ {GKINPUT_IR_KEY, {.ir_key = {KEY_4, 3, 0x19}}}, //KEY 4 ++ {GKINPUT_IR_KEY, {.ir_key = {KEY_5, 3, 0x11}}}, //KEY 5 ++ {GKINPUT_IR_KEY, {.ir_key = {KEY_6, 3, 0x01}}}, //KEY 6 ++ {GKINPUT_IR_KEY, {.ir_key = {KEY_7, 3, 0x09}}}, //KEY 7 ++ {GKINPUT_IR_KEY, {.ir_key = {KEY_8, 3, 0x1d}}}, //KEY 8 ++ {GKINPUT_IR_KEY, {.ir_key = {KEY_9, 3, 0x0d}}}, //KEY 9 ++ ++ {GKINPUT_END}, ++}; ++ ++/* ========================================================================= */ ++struct gk_ir_frame_info ++{ ++ u32 frame_head_size; ++ u32 frame_data_size; ++ u32 frame_end_size; ++ u32 frame_repeat_head_size; ++}; ++ ++struct gk_ir_info ++{ ++ struct input_dev *pinput_dev; ++ unsigned char __iomem *regbase; ++ ++ u32 id; ++ ++ unsigned int irq; ++ ++ int (*ir_parse)(struct gk_ir_info *pirinfo, u32 *uid); ++ int ir_pread; ++ int ir_pwrite; ++ u16 tick_buf[MAX_IR_BUFFER]; ++ ++ struct gk_ir_frame_info frame_info; ++ u32 frame_data_to_received; ++ ++ u32 last_ir_uid; ++ u32 last_ir_flag; ++ spinlock_t keylock; ++ ++ struct gk_key_table *pkeymap; ++ struct gk_ir_controller *pcontroller_info; ++}; ++ ++typedef enum ++{ ++ GD_IR_RECEIVER = 1, //!< Receiver function. ++ GD_IR_TRANSMITTER, //!< Transmitter function. ++} GD_IR_TYPE_E; ++ ++/* ========================================================================= */ ++static void gk_ir_disable(struct gk_ir_info *pirinfo) ++{ ++ disable_irq(pirinfo->irq); ++} ++ ++static void gk_ir_enable(struct gk_ir_info *pirinfo) ++{ ++ u32 edges; ++ ++ pirinfo->frame_data_to_received = pirinfo->frame_info.frame_head_size ++ + pirinfo->frame_info.frame_data_size; ++ ++ BUG_ON(pirinfo->frame_data_to_received > MAX_IR_BUFFER); ++ ++ if (pirinfo->frame_data_to_received > HW_FIFO_BUFFER) ++ { ++ edges = HW_FIFO_BUFFER; ++ pirinfo->frame_data_to_received -= HW_FIFO_BUFFER; ++ } ++ else ++ { ++ edges = pirinfo->frame_data_to_received; ++ pirinfo->frame_data_to_received = 0; ++ } ++ ++ enable_irq(pirinfo->irq); ++} ++ ++static int gk_ir_get_tick_size(struct gk_ir_info *pirinfo) ++{ ++ int size = 0; ++ ++ if (pirinfo->ir_pread > pirinfo->ir_pwrite) ++ size = MAX_IR_BUFFER - pirinfo->ir_pread + pirinfo->ir_pwrite; ++ else ++ size = pirinfo->ir_pwrite - pirinfo->ir_pread; ++ ++ return size; ++} ++ ++void gk_ir_inc_read_ptr(struct gk_ir_info *pirinfo) ++{ ++ BUG_ON(pirinfo->ir_pread == pirinfo->ir_pwrite); ++ ++ pirinfo->ir_pread++; ++ if (pirinfo->ir_pread >= MAX_IR_BUFFER) ++ pirinfo->ir_pread = 0; ++} ++ ++void gk_ir_move_read_ptr(struct gk_ir_info *pirinfo, int offset) ++{ ++ for (; offset > 0; offset--) ++ { ++ gk_ir_inc_read_ptr(pirinfo); ++ } ++} ++ ++static u16 gk_ir_read_data( struct gk_ir_info *pirinfo, int pointer) ++{ ++ BUG_ON(pointer < 0); ++ BUG_ON(pointer >= MAX_IR_BUFFER); ++ BUG_ON(pointer == pirinfo->ir_pwrite); ++ ++ return pirinfo->tick_buf[pointer]; ++} ++ ++static inline void gk_ir_write_data(struct gk_ir_info *pirinfo, u16 val) ++{ ++ BUG_ON(pirinfo->ir_pwrite < 0); ++ BUG_ON(pirinfo->ir_pwrite >= MAX_IR_BUFFER); ++ ++ pirinfo->tick_buf[pirinfo->ir_pwrite] = val; ++ ++ pirinfo->ir_pwrite++; ++ ++ if (pirinfo->ir_pwrite >= MAX_IR_BUFFER) ++ pirinfo->ir_pwrite = 0; ++} ++ ++#if 0 ++static int gk_input_report_ir(struct gk_ir_info *pirinfo, u32 uid) ++{ ++ ++ if (!pirinfo->pkeymap) ++ return -1; ++ ++ if ((pirinfo->last_ir_uid == uid) && (pirinfo->last_ir_flag)) ++ { ++ pirinfo->last_ir_flag--; ++ return 0; ++ } ++ pirinfo->last_ir_uid = uid; ++ ++ //input_report_key(pirinfo->pinput_dev, pirinfo->pkeymap[i].ir_key.key_code, 1); ++ //input_report_key(pirinfo->pinput_dev, pirinfo->pkeymap[i].ir_key.key_code, 0); ++ //printk( "IR_KEY [%d]\n", pirinfo->pkeymap[i].ir_key.key_code); ++ ++ return 0; ++} ++#endif ++ ++ ++#include "gk_ir_nec.c" ++ ++void gk_ir_set_protocol(struct gk_ir_info *pirinfo, ++ enum gk_ir_protocol protocol_id) ++{ ++ memset(pirinfo->tick_buf, 0x0, sizeof(pirinfo->tick_buf)); ++ pirinfo->ir_pread = 0; ++ pirinfo->ir_pwrite = 0; ++ ++ switch (protocol_id) ++ { ++ case GK_IR_PROTOCOL_NEC: ++ default: ++ printk("Protocol NEC[%d]\n", protocol_id); ++ pirinfo->ir_parse = gk_ir_nec_parse; ++ gk_ir_get_nec_info(&pirinfo->frame_info); ++ break; ++ } ++} ++ ++static void gk_ir_init(struct gk_ir_info *pirinfo) ++{ ++ u16 prescaler; ++ int i; ++ ++ prescaler = (u16)((IR_INPUT_CLK/(IR_FREQ * 1000)) - 1); ++ ++ gk_ir_writel( REG_PMU_IRQ_EN, 0x0); ++ gk_ir_writel( REG_PMU_IRQ_CLR_RTC, IRQ_EN_RTC); ++ gk_ir_writel( REG_PMU_IRQ_CLR_IRR, IRQ_EN_IRR); ++ gk_ir_writel( REG_PMU_IRQ_CLR_FPC, IRQ_EN_FPC); ++ gk_ir_writel( REG_PMU_IRQ_CLR_GPIO, IRQ_EN_GPIO); ++ gk_ir_writel( REG_PMU_IRQ_CLR_CEC, IRQ_EN_CEC); ++ gk_ir_writel( REG_PMU_IRQ_CLR_ADC, IRQ_EN_ADC); ++ gk_ir_writel( REG_PMU_IRQ_CLR_IRT, IRQ_EN_IRT); ++ ++ gk_ir_writel( REG_PMU_IRQ_EN, IRQ_EN_IRT | IRQ_EN_RTC | IRQ_EN_IRR); ++ ++ gk_ir_disable(pirinfo); ++ ++ gk_ir_writel( REG_IRR_PROG, 0x08); ++ gk_ir_writel( REG_IRR_PRESCALER_H, (u8)(((prescaler) >> 8) & 0xff)); ++ gk_ir_writel( REG_IRR_PRESCALER_L, (u8)(prescaler & 0xff)); ++ ++ gk_ir_writel( REG_IRR_PROG, 0x02); ++ gk_ir_writel( REG_IRR_IRQMASK_H, 0xFF); ++ gk_ir_writel( REG_IRR_IRQMASK_L, 0xFF); ++ ++ IrDataNumber = 0; ++ IrSeqNumber = 0; ++ IrReadPointer = 0; ++ IrWritePointer = 0; ++ IrBufferOver = 0; ++ IRDataAvailable = 0; ++ memset(&IrBuffer, 0, sizeof(IrBuffer)); ++ ++ if (pirinfo->pcontroller_info->protocol >= GK_IR_PROTOCOL_END) ++ pirinfo->pcontroller_info->protocol = GK_IR_PROTOCOL_NEC; ++ gk_ir_set_protocol(pirinfo, pirinfo->pcontroller_info->protocol); ++ ++ gk_ir_enable(pirinfo); ++ ++ for(i=0; ipinput_dev->evbit); ++ set_bit(pirinfo->pkeymap[i].ir_key.raw_id, ++ pirinfo->pinput_dev->keybit); ++ } ++} ++ ++typedef union /* IRR_IRR_Read */ ++{ ++ u32 all; ++ struct ++ { ++ u32 irr_pulse27 : 6; ++ u32 edge : 1; ++ u32 valid : 1; ++ u32 : 24; ++ } bitc; ++} GH_IRR_IRR_READ_S; ++ ++static u16 ir_count2time(u32 count) ++{ ++ return (u16)((10000 * count) /(IR_FREQ * 10)); ++} ++ ++ ++/*! ++******************************************************************************* ++** ++** \brief Checks the status of an instance. ++** ++** This function returns the status the of the receiver or transmitter. ++** If receiving is complete, it returns the number of received data. ++** If transmitting is complete, it returns the number of transmitted ++** data. ++** ++** \param handle Handle of receiver or transmitter to check. ++** \param pNum Number of time data stored in the IR buffer. ++** ++** \return Possible return codes: ++** - #GD_OK ++** - #GD_ERR_IR_NO_SEQUENCE Receiving is not completed yet. ++** - #GD_ERR_OUT_OF_MEMORY Receiver buffer overflow ++** - #GD_ERR_IR_TRANSMIT_INPROCESS Transmitting is not yet complete. ++** - #GD_ERR_INVALID_HANDLE ++** ++******************************************************************************/ ++ ++int GD_IR_Status(GD_IR_TYPE_E handle, u16* pNum) ++{ ++ u32 ReturnValue; ++ ++ if(handle == GD_IR_RECEIVER ) ++ { ++ ReturnValue = -1; ++ if (IrDataNumber) ++ ReturnValue = 0; ++ if (IrBufferOverApi) ++ { ++ IrBufferOverApi = 0; ++ ReturnValue = -1; ++ } ++ *pNum = IrSeqNumber; ++ return ReturnValue; ++ } ++ else ++ return -1; ++} ++ ++ ++/*! ++******************************************************************************* ++** ++** \brief Reads data from the IR receice buffer. ++** ++** \param handle Handle of IR receiver. ++** \param pData Pointer to data array. ++** \param num Number of data to be read. ++** ++** \return Possible return codes: ++** - #GD_OK ++** - #GD_ERR_INVALID_HANDLE ++** ++******************************************************************************/ ++int GD_IR_Receive(GD_IR_TYPE_E handle, u16 *pData, u16 num) ++{ ++ u16 TimeData; ++ u16 ix; ++ ++ if (handle != GD_IR_RECEIVER) return -1; ++ ++ for (ix=0; ix= IRR_MAX_DATA) ++ IrReadPointer = 0; ++ } ++ ++ return 0; ++} ++ ++ ++/*! ++******************************************************************************* ++ ++This function decodes the Infrared data of NEC mode. ++ ++\note The device ID is a 16-bit custom code (Custom Code, Custom Code?. ++ Where the upper 8 bits refer to the Custom Code and the lower 8 bits ++ refer to the Custom Code'. ++ ++\param handle Handle of the receiver device in the IR driver. ++\param pKeyValue Pointer to IR key value. ++\param pRepeatFlag Pointer to repeat flag of remote controller. ++\param pDeviceID Pointer to device ID of the remote controller. ++ ++\return Return values from GD_IR_Status, most important are: ++ \c GD_OK ++ \c GD_ERR_IR_NO_SEQUENCE = no signal received ++ own return values: ++ \c GM_ERR_IR_INVAL_SEQ = no valid sequence detected ++ ++******************************************************************************/ ++int GM_IRR_NEC_Mode(u16 *pDeviceID, u8 *pKeyValue, u8 *pRepeatFlag) ++{ ++ u16 Data = 0,nData = 0,TmpData = 0; ++ u8 CtlData=0; ++ u8 NCtlData=0; ++ u8 IRData=0; ++ u8 NIRData=0; ++ u16 ix, iy=0; ++ u8 RepeatFlg=0 ; ++ u8 IR_State=0; /* must init this value as 0 !*/ ++ int err; ++ static u8 firstRepeat = 1; ++ ++ /* preset return values to 0 */ ++ *pKeyValue = 0; ++ *pRepeatFlag = 0; ++ *pDeviceID = 0; ++ ++ err = GD_IR_Status(GD_IR_RECEIVER, &nData); ++ if(err) ++ return(err); ++ else ++ { ++ for (ix=0; ix<=nData; ix++) ++ { ++ GD_IR_Receive(GD_IR_RECEIVER,&Data,1); ++ //if ( Data & GD_IR_EDGE_FLAG) ++ { ++ TmpData = Data; ++ if ( IR_State == 0 ) ++ { ++ if ( ( TmpData < 5500 ) && ( TmpData > 4500 ) ) ++ { ++ RepeatFlg=0; ++ IR_State= 1; ++ CtlData=0; ++ NCtlData=0; ++ IRData=0; ++ NIRData=0; ++ iy = 0; ++ } ++ else if ( ( TmpData < 3000 ) && ( TmpData > 2500 ) ) ++ { ++ RepeatFlg=1; ++ IR_State= 20; ++ CtlData=0; ++ NCtlData=0; ++ IRData=0; ++ NIRData=0; ++ iy = 0; ++ } ++ else ++ { ++ IR_State = 20; ++ } ++ } ++ else if ( IR_State == 1 ) ++ { ++ if ( ( TmpData < 1200 ) && ( TmpData > 850 ) ) ++ { ++ CtlData = CtlData; ++ iy ++; ++ if ( iy == 8 ) ++ { ++ IR_State = 2; ++ iy = 0; ++ } ++ } ++ else if ( ( TmpData < 2300 ) && ( TmpData > 2000 ) ) ++ { ++ CtlData = CtlData + (1< 850 ) ) ++ { ++ NCtlData = NCtlData ; ++ iy ++; ++ if ( iy == 8 ) ++ { ++ IR_State = 3; ++ iy = 0; ++ } ++ } ++ else if ( ( TmpData < 2300 ) && ( TmpData > 2000 ) ) ++ { ++ NCtlData = NCtlData + (1< 850 ) ) ++ { ++ IRData = IRData ; ++ iy ++; ++ if ( iy == 8 ) ++ { ++ IR_State = 4; ++ iy = 0; ++ } ++ } ++ else if ( ( TmpData < 2300 ) && ( TmpData > 2000 ) ) ++ { ++ IRData = IRData + (1< 850 ) ) ++ { ++ NIRData = NIRData ; ++ iy ++; ++ if ( iy == 8 ) ++ { ++ IR_State = 5; ++ iy = 0; ++ } ++ } ++ else if ( ( TmpData < 2300 ) && ( TmpData > 2000 ) ) ++ { ++ NIRData = NIRData + (1<MAX_HI_TIME)) ++ return 1; // if 'illegal' timing values ++ if (OneBitsSeq) ++ { ++ // if 'receiveing '1'-bit sequence ++ RC5_Dataword = RC5_Dataword << 1; // shift up previous data bits ++ RC5_Dataword |= 0x0001; // add '1'-bit ++ BitCount++; ++ } ++ if (IrTimeVal>=LNG_HI_TIME) ++ OneBitsSeq = 0; // if transition into 'receiving '0'-bits sequence ++ } ++ else ++ { ++ // else expecting a 'NegativeSignalEdge' ++ ExpectPosEdge = 1; ++ if (!nData) ++ { ++ // if expecting final 'stop' time-duration ++ if (IrTimeValMAX_LO_TIME)) ++ return 3; // if 'illegal' timing values ++ if (!OneBitsSeq) ++ { ++ // if 'receiveing '0'-bit sequence ++ // shift up previous data bits, insert '0'-bit ++ RC5_Dataword = RC5_Dataword << 1; ++ BitCount++; ++ } ++ if (IrTimeVal>=LNG_LO_TIME) ++ OneBitsSeq = 1; // if transition into 'receiving '1'-bits sequence ++ } ++ } ++// GM_PrStr("\nResultBits:"); GM_PrHex(BitCount,2); ++ if (BitCount!=14) return 4; ++ *pIrData = RC5_Dataword; ++ return 0; ++} ++ ++ ++/*! ++******************************************************************************* ++ ++This function decodes the Infrared data of RC-5 mode. ++ ++\note The device ID is a 16-bit custom code (Custom Code, Custom Code). ++ Where the upper 8 bits refer to the Custom Code and the lower 8 bits ++ refer to the Custom Code'. ++ ++\param handle Handle of the receiver device in the IR driver. ++\param pKeyValue Pointer to IR key value. ++\param pRepeatFlag Pointer to repeat flag of remote controller. ++\param pDeviceID Pointer to device ID of the remote controller. ++ ++\return Return values from GD_IR_Status, most important are: ++ \c GD_OK ++ \c GD_ERR_IR_NO_SEQUENCE = no signal received ++ own return values: ++ \c GM_ERR_IR_INVAL_SEQ = no valid sequence detected ++ ++******************************************************************************/ ++int GM_IRR_RC5_Mode(u16 *pDeviceID, u8 *pKeyValue, u8 *pRepeatFlag) ++{ ++ static u8 LastTogInfo=0; ++ u16 nNewIrcTimingData; ++ u16 DecodedData; ++ int err, ix, Count, KVal, KRep, KDev; ++ ++ //-- preset return values -- ++ KVal = 0; ++ KRep = 0; ++ KDev = 0; ++ ++ err = GD_IR_Status(GD_IR_RECEIVER, &nNewIrcTimingData); ++ if(err) ++ { ++ return(err); ++ } ++ ++ nNewIrcTimingData += 1; // plus 'Stop' Timing value ++ Count = nNewIrcTimingData; ++ do ++ { ++ // transfer IR-Timing data (to local RxBuffer) ++ ix = Count; // (multiple chuncs 'invalid data' if necessary) ++ if (ix>MAX_IR_DATA) ++ ix = MAX_IR_DATA; ++ Count -= ix; ++ GD_IR_Receive(GD_IR_RECEIVER, IRC_ActIrData, ix); // 'empty' IR-Data ++ } while (Count); ++ err = -1; // def. return code ++ ++ if (nNewIrcTimingData"); GM_PrHex(DecodedData,4); ++ KVal = DecodedData & 0x3F; ++ if (!(DecodedData&0x1000)) KVal |= 0x40; ++ KDev = (DecodedData>>6) & 0x1F; ++ ix = (DecodedData>>11) & 1; // get Toggle Info ++ if (ix==(int)LastTogInfo) KRep = 1; // if not 'Toggling' => Set Repeat-Flag ++ LastTogInfo = ix; // save for next time ++ err = 0; ++ } ++ } ++// else GM_PrStr("\n{CanNotBeRc5Data}"); ++ *pKeyValue = KVal ; ++ *pRepeatFlag = KRep; ++ *pDeviceID = KDev; ++ return err; ++} ++ ++ ++/* ---------------------------------------------------------------------- */ ++static void gk_ir_event_Notifier(struct gk_ir_info *pirinfo) ++{ ++ uint32_t deviceId = 0; ++ uint32_t scancode = 0; ++ uint32_t repeatFlag = 0; ++ uint32_t keyInfo = 0; ++ unsigned long flags; ++ ++ ++ spin_lock_irqsave(&pirinfo->keylock, flags); ++ /* Get IR key */ ++ if(GM_IRR_NEC_Mode((uint16_t*)&deviceId, (uint8_t*)&scancode, (uint8_t*)&repeatFlag) == 0) ++ { ++ ++ if(!deviceId) ++ { ++ deviceId = lastDeviceId; ++ } ++ /*report if deviceId or keytype changed*/ ++ if(deviceId != lastDeviceId || repeatFlag != lastRepeatFlag) ++ { ++ lastDeviceId = deviceId; ++ lastRepeatFlag = repeatFlag; ++ ++ keyInfo = (lastDeviceId<<16) | lastRepeatFlag; ++ //printk("keyInfo: %x\n", keyInfo); ++ ++ //input_event(pirinfo->pinput_dev, EV_MSC, MSC_GKIRKEYINFO, keyInfo); ++ //input_sync(pirinfo->pinput_dev); ++ } ++ ++ //currentKeydownJiffies = jiffies; ++ ++ if(repeatFlag == 0) ++ { ++ lastKey = scancode; ++ } ++ /* key repeat message must be in a certain time interval */ ++ //else if (currentKeydownJiffies - lastKeyJiffies > msecs_to_jiffies(GK_IR_KEYPRESS_TIMEOUT)) { ++ // lastKeyJiffies = currentKeydownJiffies; ++ // printk("No sequence is received\n"); ++ // goto out; ++ //} ++ else ++ { ++ scancode = lastKey; ++ } ++ //lastKeyJiffies = currentKeydownJiffies; ++ ++ //printk("report key: 0x%02x\n", scancode); ++ /*key event is triggered by key pressed*/ ++ input_report_key(pirinfo->pinput_dev, scancode, 1); ++ input_report_key(pirinfo->pinput_dev, scancode, 0); ++ input_sync(pirinfo->pinput_dev); ++#if 0 ++ /*can't get status of key released, just to released key without report */ ++ if(!!test_bit(scancode, pirinfo->pinput_dev->key) == 1) ++ { ++ clear_bit(scancode, pirinfo->pinput_dev->key); ++ } ++#endif ++ } ++ else ++ { ++ //printk("GM_IRR_NEC_Mode: error\n"); ++ } ++ ++ spin_unlock_irqrestore(&pirinfo->keylock, flags); ++ return; ++} ++ ++ ++static irqreturn_t gk_ir_irq(int irq, void *devid) ++{ ++ struct gk_ir_info *pirinfo; ++ //int key_val; ++ //u32 uid; ++ //u32 edges; ++ ++ u32 irdata = 0,irtdata = 0,irq_flag = 0; ++ u16 tmp_value = 0; ++ GH_IRR_IRR_READ_S m_irr_read; ++ ++ pirinfo = (struct gk_ir_info *)devid; ++ ++ BUG_ON(pirinfo->ir_pread < 0); ++ BUG_ON(pirinfo->ir_pread >= MAX_IR_BUFFER); ++ ++ irq_flag = gk_ir_readl(REG_PMU_IRQ_STATUS); ++ //printk("irq status = 0x%x \n", irq_flag); ++ ++ if(irq_flag & IRQ_EN_IRR) // irr irq ++ { ++ irdata = gk_ir_readl(REG_IRR_IRR_READ); ++ irtdata = gk_ir_readl(REG_IRR_IRT_READ); ++ ++ m_irr_read.all = irdata; ++ if (m_irr_read.bitc.valid == 1) ++ { ++ tmp_value = ((irtdata & 0x00000003) | ((irdata << 2) & 0x000000fc)); ++ ++ ++ if (tmp_value < 0xfC) ++ { ++ gk_ir_writel( REG_IRR_PROG, 0x03); ++ tmp_value = ir_count2time(tmp_value); ++ ++ //printk("ir value = 0x%x\n", tmp_value); ++ ++ IrBuffer[IrWritePointer++] = tmp_value; ++ IrDataNumber++; ++ IrSeqNumber++; ++ IRDataAvailable = 1; ++ } ++ else if (tmp_value >= 0xfC) ++ { ++ gk_ir_writel( REG_IRR_PROG,0x02); ++ //printk("ir value = 0x%x\n", tmp_value); ++ gk_ir_event_Notifier(pirinfo); ++ IrDataNumber = 0; ++ IrSeqNumber = 0; ++ IrReadPointer = 0; ++ IrWritePointer = 0; ++ memset(&IrBuffer, 0, sizeof(IrBuffer)); ++ } ++ if (IrDataNumber>=IRR_MAX_DATA) ++ { ++ IrBufferOverApi = 1; ++ } ++ if (IrWritePointer >= IRR_MAX_DATA) ++ { ++ IrWritePointer = 0; ++ } ++ } ++ gk_ir_writel( REG_PMU_IRQ_CLR_IRR, IRQ_EN_IRR); // clear irr irq ++ ++ } ++ ++ if(irq_flag & IRQ_EN_IRT) // irt irq ++ { ++ gk_ir_writel( REG_PMU_SYS_REG_CFG1, 1); ++ gk_ir_writel( REG_PMU_IRQ_CLR_IRT, IRQ_EN_IRT); // clear irt irq ++ } ++ ++ if(irq_flag & IRQ_EN_RTC) // rtc irq ++ { ++ *(volatile u32 *)(0xf0080000 + (0x8*4)) = 0x01; // clear ir irq ++ *(volatile u32 *)(0xf0080000 + (0x8*4)) = 0x00; // clear ir irq ++ gk_ir_writel( REG_PMU_IRQ_CLR_RTC, IRQ_EN_RTC); // clear rtc irq ++ } ++ if(irq_flag & IRQ_EN_FPC) // fpc irq ++ { ++ gk_ir_writel( REG_PMU_IRQ_CLR_FPC, IRQ_EN_FPC); // clear fpc irq ++ } ++ if(irq_flag & IRQ_EN_GPIO) // gpio irq ++ { ++ u32 regval = 0; ++ regval = gk_ir_readl(PMU_GPIO_RIS); ++ gk_ir_writel( PMU_GPIO_IC, regval); ++ gk_ir_writel( REG_PMU_IRQ_CLR_GPIO, IRQ_EN_GPIO); // clear gpio irq ++ } ++ if(irq_flag & IRQ_EN_CEC) // cec irq ++ { ++ gk_ir_writel( REG_PMU_IRQ_CLR_CEC, IRQ_EN_CEC); // clear cec irq ++ } ++ if(irq_flag & IRQ_EN_ADC) // adc irq ++ { ++ gk_ir_writel( REG_PMU_IRQ_CLR_ADC, IRQ_EN_ADC); // clear adc irq ++ } ++ return IRQ_HANDLED; ++} ++ ++static int __devinit gk_ir_probe(struct platform_device *pdev) ++{ ++ int retval; ++ ++ struct gk_ir_info *pirinfo; ++ ++ //struct proc_dir_entry *input_file; ++ struct input_dev *pinput_dev; ++ ++ pinput_dev = input_allocate_device(); ++ if (!pinput_dev) ++ { ++ dev_err(&pdev->dev, "input_allocate_device fail!\n"); ++ retval = -ENOMEM; ++ goto ir_errorCode_na; ++ } ++ pinput_dev->name = "GKInput"; ++ pinput_dev->phys = "gk/input0"; ++ pinput_dev->id.bustype = BUS_HOST; ++ ++ retval = input_register_device(pinput_dev); ++ if (retval) ++ { ++ dev_err(&pdev->dev, "Register input_dev failed!\n"); ++ goto gk_input_probe_free_input_dev; ++ } ++ //pbinfo->pdev = pdev; ++ //pbinfo->pinput_dev = pinput_dev; ++ ++ pirinfo = kzalloc(sizeof(struct gk_ir_info), GFP_KERNEL); ++ if (!pirinfo) ++ { ++ dev_err(&pdev->dev, "Failed to allocate pirinfo!\n"); ++ retval = -ENOMEM; ++ goto gk_input_probe_unregister_input_dev; ++ } ++ ++ pirinfo->pcontroller_info = (struct gk_ir_controller *)pdev->dev.platform_data; ++ if ((pirinfo->pcontroller_info == NULL) ) ++ { ++ dev_err(&pdev->dev, "Platform data is NULL!\n"); ++ retval = -ENXIO; ++ goto ir_errorCode_pinfo; ++ } ++ ++ pirinfo->regbase = (unsigned char __iomem *)MCU_IRR_BASE; ++ pirinfo->id = pdev->id; ++ pirinfo->irq = IR_IRQ; ++ ++ pirinfo->last_ir_uid = 0; ++ pirinfo->last_ir_flag = 0; ++ pirinfo->pinput_dev = pinput_dev; ++ //pirinfo->pinput_dev = pboard_info->pinput_dev; ++ pirinfo->pkeymap = keymap; ++ ++ platform_set_drvdata(pdev, pirinfo); ++ ++ gk_ir_init(pirinfo); ++ ++ retval = request_irq(pirinfo->irq, gk_ir_irq, IRQF_TRIGGER_LOW, ++ dev_name(&pdev->dev), pirinfo); ++ if (retval) ++ { ++ dev_err(&pdev->dev, "Request IRQ failed!\n"); ++ goto ir_errorCode_free_platform; ++ } ++ printk("ir request irq: %d \n", pirinfo->irq); ++ ++ printk("IR Host Controller probed!\n"); ++ ++ goto ir_errorCode_na; ++ ++ir_errorCode_free_platform: ++ platform_set_drvdata(pdev, NULL); ++ ++ir_errorCode_pinfo: ++ kfree(pirinfo); ++ ++gk_input_probe_unregister_input_dev: ++ input_unregister_device(pinput_dev); ++ ++ return retval; ++ ++gk_input_probe_free_input_dev: ++ input_free_device(pinput_dev); ++ //pbinfo->pdev = NULL; ++ //pbinfo->pinput_dev = NULL; ++ ++ir_errorCode_na: ++ return retval; ++} ++ ++static int __devexit gk_ir_remove(struct platform_device *pdev) ++{ ++ struct gk_ir_info *pirinfo; ++ int retval = 0; ++ ++ pirinfo = platform_get_drvdata(pdev); ++ ++ if (pirinfo) ++ { ++ free_irq(pirinfo->irq, pirinfo); ++ input_unregister_device(pirinfo->pinput_dev); ++ platform_set_drvdata(pdev, NULL); ++ kfree(pirinfo); ++ } ++ ++ dev_notice(&pdev->dev, ++ "Remove GK IR Controller.\n"); ++ ++ return retval; ++} ++ ++static struct platform_driver gk_ir_driver = ++{ ++ .probe = gk_ir_probe, ++ .remove = __devexit_p(gk_ir_remove), ++ .driver = ++ { ++ .name = "ir", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init gk_input_init(void) ++{ ++ int retval = 0; ++ ++ retval = platform_driver_register(&gk_ir_driver); ++ if (retval) ++ printk(KERN_ERR "Register gk_input_driver failed %d!\n", ++ retval); ++ ++ return retval; ++} ++ ++static void __exit gk_input_exit(void) ++{ ++ platform_driver_unregister(&gk_ir_driver); ++} ++ ++module_init(gk_input_init); ++module_exit(gk_input_exit); ++ ++MODULE_DESCRIPTION("GOKE Input Driver"); ++MODULE_AUTHOR("Goke Microelectronics Inc."); ++MODULE_LICENSE("GPL"); ++ +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index c7795096..81e4a315 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -4,6 +4,21 @@ + + menu "Misc devices" + ++config ADC_GOKE ++ tristate "goke ipc ADC support" ++ depends on GK_ADC ++ help ++ This driver exports functions to choose ADC channel and read ADC ++ data. ++ ++config PWM_GOKE ++ tristate "goke ipc PWM support" ++ depends on GK_PWM ++ help ++ This driver exports functions to enable/disble/config/free Pulse ++ Width Modulation in the GOKE IPC Chip. ++ It is used by led and backlight driver to control the intensity. ++ + config SENSORS_LIS3LV02D + tristate + depends on INPUT +diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile +index 3e1d8010..6208f079 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -49,3 +49,9 @@ obj-y += carma/ + obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o + obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ + obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o ++ifdef CONFIG_ADC_GOKE ++obj-$(CONFIG_GK_ADC_V1_00) += gk_adc_v1_00.o ++endif ++ifdef CONFIG_PWM_GOKE ++obj-$(CONFIG_GK_PWM_V1_00) += gk_pwm_v1_00.o ++endif +diff --git a/drivers/misc/gk_adc_v1_00.c b/drivers/misc/gk_adc_v1_00.c +new file mode 100644 +index 00000000..12295ae6 +--- /dev/null ++++ b/drivers/misc/gk_adc_v1_00.c +@@ -0,0 +1,354 @@ ++/* ++ * drivers/misc/gk_adc_v1_00.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define DEVICE_NAME "adc" ++ ++/*----------------------------------------------------------------------------*/ ++/* registers */ ++/*----------------------------------------------------------------------------*/ ++#define ADC_VA_BASE (GK_VA_ADC2) ++#define ADC_REG(x) (ADC_VA_BASE + (x)) ++ ++#define ADC_ANALOG_VA_BASE (GK_VA_ADC) ++#define ADC_ANALOG_REG(x) (ADC_ANALOG_VA_BASE + (x)) ++ ++#define REG_ADC_AUX_ATOP ADC_ANALOG_REG(0x00) /* read/write */ ++#define REG_ADC_GPIO ADC_ANALOG_REG(0x04) /* read/write */ ++#define REG_ADC_CONTROL ADC_REG(0x000) /* read/write */ ++#define REG_ADC_READDATA ADC_REG(0x004) /* read */ ++#define REG_ADC_ENABLE ADC_REG(0x018) /* read/write */ ++#define REG_ADC_INTCONTROL ADC_REG(0x044) /* read/write */ ++ ++#define GK_ADC_IOC_MAGIC 'A' ++#define IOC_ADC_SET_CHANNEL _IOW(GK_ADC_IOC_MAGIC, 0, unsigned int) ++#define IOC_ADC_GET_CHANNEL _IOR(GK_ADC_IOC_MAGIC, 1, unsigned int) ++#define IOC_ADC_GET_DATA _IOR(GK_ADC_IOC_MAGIC, 2, unsigned int) ++/*---------------------------------------------------------------------------*/ ++/* types, enums and structures */ ++/*---------------------------------------------------------------------------*/ ++/*! ++******************************************************************************* ++** ++** \brief ADC channel number. ++** ++** \sa ADC_OPEN_PARAMS_S ++** ++******************************************************************************/ ++typedef enum ++{ ++ ADC_CHANNEL_ONE = 0, //!< ADC channel 1. ++ ADC_CHANNEL_TWO, //!< ADC channel 2. ++ ADC_CHANNEL_COUNT, //!< ADC channel count ++ ADC_CHANNEL_NONE = -1, ++}ADC_CHANNEL_E; ++ ++/*----------------------------------------------------------------------------*/ ++/* bit group structures */ ++/*----------------------------------------------------------------------------*/ ++typedef union { /* ADC_AUX_ATOP */ ++ uint32_t all; ++ struct { ++ uint32_t sar_maxsel : 4; ++ uint32_t sar_maxnsel : 3; ++ uint32_t sar_pd : 1; ++ uint32_t sar_oneshot : 1; ++ uint32_t sar_freerun : 1; ++ uint32_t sar_refnsel : 2; ++ uint32_t sar_refsel : 3; ++ uint32_t sar_pd_tsi : 1; ++ uint32_t : 16; ++ } bitc; ++} ADC_AUX_ATOP_S; ++ ++typedef union { /* ADC_GPIO */ ++ uint32_t all; ++ struct { ++ uint32_t sar_test : 4; ++ uint32_t sar_key_pge : 4; ++ uint32_t sar_key_aie : 4; ++ uint32_t oen_sar_key : 4; ++ uint32_t : 16; ++ } bitc; ++} ADC_GPIO_S; ++ ++typedef union { /* ADC_Control */ ++ uint32_t all; ++ struct { ++ uint32_t status : 1; ++ uint32_t start : 1; ++ uint32_t : 1; ++ uint32_t channel : 3; ++ uint32_t : 26; ++ } bitc; ++} ADC_CONTROL_S; ++ ++ ++/*---------------------------------------------------------------------------*/ ++/* ADC state structure */ ++/*---------------------------------------------------------------------------*/ ++typedef struct ++{ ++ ADC_CHANNEL_E channel; ++ uint32_t data; ++} ADC_STATE_MACHINE_S; ++ ++static struct mutex adc_mutex; ++static uint32_t in_use; ++static ADC_CHANNEL_E cur_ch; ++ ++void ADC_set_Control(uint32_t data) ++{ ++ gk_adc_writel(REG_ADC_CONTROL, data); ++} ++ ++uint32_t ADC_get_Control_status(void) ++{ ++ ADC_CONTROL_S d; ++ d.all = gk_adc_readl(REG_ADC_CONTROL); ++ return d.bitc.status; ++} ++ ++void ADC_set_Control_status(uint8_t data) ++{ ++ ADC_CONTROL_S d; ++ d.all = gk_adc_readl(REG_ADC_CONTROL); ++ d.bitc.status = data; ++ gk_adc_writel(REG_ADC_CONTROL, d.all); ++} ++ ++void ADC_set_Control_start(uint8_t data) ++{ ++ ADC_CONTROL_S d; ++ d.all = gk_adc_readl(REG_ADC_CONTROL); ++ d.bitc.start = data; ++ gk_adc_writel(REG_ADC_CONTROL, d.all); ++} ++ ++void ADC_set_Control_channel(uint8_t data) ++{ ++ ADC_CONTROL_S d; ++ d.all = gk_adc_readl(REG_ADC_CONTROL); ++ d.bitc.channel = data; ++ gk_adc_writel(REG_ADC_CONTROL, d.all); ++} ++ ++static uint32_t ADC_get_ReadData(uint8_t index) ++{ ++ uint32_t value; ++ value = gk_adc_readl(REG_ADC_READDATA + (index * 0x4)); ++ return value; ++} ++ ++static void ADC_set_Enable(uint32_t data) ++{ ++ gk_adc_writel(REG_ADC_ENABLE, data); ++} ++ ++static void ADC_set_AUX_ATOP(uint32_t data) ++{ ++ gk_adc_writel(REG_ADC_AUX_ATOP, data); ++} ++ ++static void ADC_set_AUX_ATOP_sar_maxsel(uint8_t data) ++{ ++ ADC_AUX_ATOP_S d; ++ d.all = gk_adc_readl(REG_ADC_AUX_ATOP); ++ d.bitc.sar_maxsel = data; ++ gk_adc_writel(REG_ADC_AUX_ATOP, d.all); ++} ++ ++static void ADC_select_channel(ADC_CHANNEL_E channel) ++{ ++ if(channel == ADC_CHANNEL_ONE){ ++ ADC_set_AUX_ATOP_sar_maxsel(0x05); ++ ADC_set_Control_channel(0x01); ++ }else if(channel == ADC_CHANNEL_TWO){ ++ ADC_set_AUX_ATOP_sar_maxsel(0x06); ++ ADC_set_Control_channel(0x02); ++ }else{ ++ printk(KERN_ERR "Invalid channel number.\n"); ++ } ++} ++ ++static int gk_adc_open(struct inode *inode, struct file *filp) ++{ ++ mutex_lock(&adc_mutex); ++ if(1 == in_use){ ++ return -EBUSY; ++ } else { ++ in_use = 1; ++ } ++ cur_ch = ADC_CHANNEL_NONE; ++ mutex_unlock(&adc_mutex); ++ ++ return 0; ++} ++ ++static int gk_adc_close(struct inode *inode, struct file *filp) ++{ ++ mutex_lock(&adc_mutex); ++ in_use = 0; ++ mutex_unlock(&adc_mutex); ++ return 0; ++} ++ ++static long gk_adc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ uint32_t cnt = 0; ++ ADC_STATE_MACHINE_S adc_state; ++ ++ switch (cmd) ++ { ++ case IOC_ADC_SET_CHANNEL: //set ADC channel ++ { ++ if (arg == 0) ++ return -EINVAL; ++ ++ if (copy_from_user(&adc_state, (void __user *)arg, sizeof(ADC_STATE_MACHINE_S))) ++ return -EFAULT; ++ ++ if((adc_state.channel == ADC_CHANNEL_ONE) ++ || (adc_state.channel == ADC_CHANNEL_TWO)){ ++ mutex_lock(&adc_mutex); ++ cur_ch = adc_state.channel; ++ mutex_unlock(&adc_mutex); ++ ADC_select_channel(cur_ch); ++ }else { ++ printk(KERN_ERR "Invalid param, ADC only has two channel.\n"); ++ return -EINVAL; ++ } ++ break; ++ } ++ case IOC_ADC_GET_CHANNEL: ++ { ++ if(copy_to_user((void __user *)arg, &adc_state, sizeof(ADC_STATE_MACHINE_S))) ++ return -EFAULT; ++ break; ++ } ++ case IOC_ADC_GET_DATA: ++ { ++ if (copy_from_user(&adc_state, (void __user *)arg, sizeof(ADC_STATE_MACHINE_S))) ++ return -EFAULT; ++ if((adc_state.channel == ADC_CHANNEL_ONE) ++ || (adc_state.channel == ADC_CHANNEL_TWO)){ ++ mutex_lock(&adc_mutex); ++ if(adc_state.channel != cur_ch){ ++ cur_ch = adc_state.channel; ++ ADC_select_channel(cur_ch); ++ ADC_set_Control_status(0); ++ while(0 == ADC_get_Control_status()){ ++ cnt++; ++ if (cnt > 10){ ++ break; ++ } ++ mdelay(1); ++ } ++ adc_state.data = ADC_get_ReadData((u32)cur_ch); ++ } ++ else { ++ adc_state.data = ADC_get_ReadData((u32)cur_ch); ++ } ++ mutex_unlock(&adc_mutex); ++ }else { ++ printk(KERN_ERR "Invalid param, ADC only has two channel.\n"); ++ return -EINVAL; ++ } ++ if(copy_to_user((void __user *)arg, &adc_state, sizeof(ADC_STATE_MACHINE_S))) ++ return -EFAULT; ++ break; ++ } ++ default: ++ return -EINVAL; ++ } ++ return 0; //³É¹¦·µ»Ø ++} ++ ++ ++/*initalize structure file operations for adc*/ ++static struct file_operations dev_fops = { ++ .owner = THIS_MODULE, ++ .open = gk_adc_open, ++ .release = gk_adc_close, ++// .read = gk_adc_read, ++ .unlocked_ioctl = gk_adc_ioctl, ++}; ++ ++static struct miscdevice misc = { ++ .minor = 11, /*MISC_DYNAMIC_MINOR,*/ ++ .name = DEVICE_NAME, ++ .fops = &dev_fops, ++}; ++ ++static int __init dev_init(void) ++{ ++ int ret; ++ ADC_AUX_ATOP_S data; ++ mutex_init(&adc_mutex); ++ in_use = 0; ++ ADC_set_Enable(1); ++ data.all = 0; ++ data.bitc.sar_maxnsel = 0x05; ++ data.bitc.sar_maxsel = 0x05; ++ data.bitc.sar_freerun = 0x01; ++ ADC_set_AUX_ATOP(data.all); ++ // 001 0 1 0 ++ ADC_set_Control(0x000A); ++ ret = misc_register(&misc); //register a misc device ++ printk (DEVICE_NAME" initialized (10:11)\n"); ++ return ret; ++} ++ ++static void __exit dev_exit(void) ++{ ++ misc_deregister(&misc); //unregister a misc device ++ mutex_destroy(&adc_mutex); ++} ++ ++module_init(dev_init); ++module_exit(dev_exit); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Goke Microelectronics Inc."); ++MODULE_DESCRIPTION("GK ADC Driver"); +diff --git a/drivers/misc/gk_pwm_v1_00.c b/drivers/misc/gk_pwm_v1_00.c +new file mode 100644 +index 00000000..c4df48ac +--- /dev/null ++++ b/drivers/misc/gk_pwm_v1_00.c +@@ -0,0 +1,546 @@ ++/* ++ * drivers/drivers/misc/gk_pwm_v1_00.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++ ++#define DEVICE_NAME "pwm" //É豸Ãû, major 10 ++#define NODE_NAME "gk_pwm" ++#define MAX_CHANNEL 4 ++ ++//¶¨Òåºê±äÁ¿,ÓÃÓÚºóÃæµÄ ioctl ÖеĿØÖÆÃüÁî ++#define GK_PWM_IOCTL_MAGIC 'k' ++ ++#define _PWM_IO(IOCTL) _IO(GK_PWM_IOCTL_MAGIC, IOCTL) ++#define _PWM_IOR(IOCTL, param) _IOR(GK_PWM_IOCTL_MAGIC, IOCTL, param) ++#define _PWM_IOW(IOCTL, param) _IOW(GK_PWM_IOCTL_MAGIC, IOCTL, param) ++#define _PWM_IOWR(IOCTL, param) _IOWR(GK_PWM_IOCTL_MAGIC, IOCTL, param) ++ ++extern u32 get_apb_bus_freq_hz(void); ++ ++typedef struct pwm_status_s ++{ ++ u8 channel; ++ u8 enable; ++}pwm_status_t; ++ ++typedef struct pwm_mode_s ++{ ++ u8 channel; /* 0 ~ 3*/ ++ u8 mode; /* 0: normal speed 1: sync speed */ ++}pwm_mode_t; ++ ++typedef struct pwm_speed_s ++{ ++ u8 channel; /* 0 ~ 3 */ ++ u32 speed; /* 0x01 ~ 0x3ff*/ ++}pwm_speed_t; ++ ++typedef struct ++{ ++ u8 channel; /* 0 ~ 3 */ ++ u16 xon; /* 0x00 ~ 0xffff */ ++ u16 xoff; /* 0x00 ~ 0xffff */ ++}pwm_duty_t; ++ ++ ++enum { ++ IOCTL_ENABLE = 0x10, ++ IOCTL_DISABLE, ++ IOCTL_SET_DUTY, ++ IOCTL_GET_DUTY, ++ IOCTL_SET_MODE, ++ IOCTL_GET_MODE, ++ IOCTL_SET_SPEED, ++ IOCTL_GET_SPEED, ++ IOCTL_GET_STATUS, ++}; ++ ++#define GK_PWM_IOCTL_ENABLE _PWM_IO(IOCTL_ENABLE) ++#define GK_PWM_IOCTL_DISABLE _PWM_IO(IOCTL_DISABLE) ++#define GK_PWM_IOCTL_SET_DUTY _PWM_IOW(IOCTL_SET_DUTY, pwm_duty_t*) ++#define GK_PWM_IOCTL_GET_DUTY _PWM_IOR(IOCTL_GET_DUTY, pwm_duty_t*) ++#define GK_PWM_IOCTL_SET_MODE _PWM_IOW(IOCTL_SET_MODE, pwm_mode_t*) ++#define GK_PWM_IOCTL_GET_MODE _PWM_IOR(IOCTL_GET_MODE, pwm_mode_t*) ++#define GK_PWM_IOCTL_SET_SPEED _PWM_IOW(IOCTL_SET_SPEED, pwm_speed_t*) ++#define GK_PWM_IOCTL_GET_SPEED _PWM_IOR(IOCTL_GET_SPEED, pwm_speed_t*) ++#define GK_PWM_IOCTL_GET_STATUS _PWM_IOR(IOCTL_GET_STATUS, pwm_status_t*) ++ ++/*----------------------------------------------------------------------------*/ ++/* registers */ ++/*----------------------------------------------------------------------------*/ ++#define PWM_VA_BASE GK_VA_PWM0 ++#define REG_PWM_ENABLE (PWM_VA_BASE + 0x0000) /* read/write */ ++#define REG_PWM_CONTROL (PWM_VA_BASE + 0x0004) /* read/write */ ++#define REG_PWM_CONTROL1 (PWM_VA_BASE + 0x0008) /* read/write */ ++#define REG_PWM_MODE (PWM_VA_BASE + 0x000C) /* read/write */ ++ ++typedef enum ++{ ++ GD_NORMAL_SPEED, ++ GD_SYNC_SPEED, ++}GD_PWM_MODE_E; ++ ++static struct semaphore lock; ++ ++typedef union { /* PWM_Mode */ ++ u32 all; ++ struct { ++ u32 divider : 10; ++ u32 mode : 1; ++ u32 : 21; ++ } bitc; ++} GH_PWM_MODE_S; ++ ++static u32 speed_ctl[5][2] = ++{ ++// speed div clk div max:xon+1+xoff=1 ++ {20000, 1}, // 69000000 / 1 = 69000000 / 2000 = 34500 ++ { 2000, 10}, // 69000000 / 10 = 6900000 / 200 = 34500 ++ { 200, 100}, // 69000000 / 100 = 690000 / 20 = 34500 ++ { 20, 1000}, // 69000000 / 1000 = 69000 / 2 = 34500 ++ { 1, 10000}, // 69000000 / 10000 = 6900 / 1 = 6900 ++}; ++static u32 g_duty[MAX_CHANNEL] = {1000, 1000, 1000, 1000}; ++static u32 g_dutyset[MAX_CHANNEL] = { 499, 499, 499, 499}; ++static void gk_pwm_set_duty(pwm_duty_t *pwm_duty); ++static void gk_pwm_get_duty(pwm_duty_t *pwm_duty); ++ ++/* pwm enable */ ++static inline void GH_PWM_set_Enable(u8 index, u32 data) ++{ ++ gk_pwm_writel(REG_PWM_ENABLE + index * (0x00001000), data); ++} ++ ++/* get pwm enable status */ ++static inline u32 GH_PWM_get_Enable(u8 index) ++{ ++ return gk_pwm_readl(REG_PWM_ENABLE + index * (0x00001000)); ++} ++ ++/* get pwm speed mode */ ++static inline u32 GH_PWM_get_Mode(u8 index) ++{ ++ GH_PWM_MODE_S d; ++ d.all = gk_pwm_readl(REG_PWM_MODE + index * (0x00001000)); ++ return d.bitc.mode; ++ ++} ++ ++/* set pwm speed mode */ ++static inline void GH_PWM_set_Mode(u8 index, u32 data) ++{ ++ GH_PWM_MODE_S d; ++ ++ d.all = gk_pwm_readl(REG_PWM_MODE + index * (0x00001000)); ++ if(data) ++ d.bitc.mode = 1; ++ else ++ d.bitc.mode = 0; ++ gk_pwm_writel(REG_PWM_MODE + index * (0x00001000), d.all); ++} ++ ++/* set pwm divider params */ ++static inline void GH_PWM_set_Mode_divider(u8 index, u16 data) ++{ ++ GH_PWM_MODE_S d; ++ d.all = gk_pwm_readl(REG_PWM_MODE + index * (0x00001000)); ++ d.bitc.divider = data; ++ gk_pwm_writel(REG_PWM_MODE + index * (0x00001000), d.all); ++} ++ ++/* get pwm divider params */ ++static inline u16 GH_PWM_get_Mode_divider(u8 index) ++{ ++ GH_PWM_MODE_S d; ++ d.all = gk_pwm_readl(REG_PWM_MODE + index * (0x00001000)); ++ return d.bitc.divider; ++} ++ ++/* set value of control0 */ ++static inline void GH_PWM_set_Control(u8 index, u32 data) ++{ ++ gk_pwm_writel(REG_PWM_CONTROL + index * (0x00001000), data); ++} ++ ++/* get value of control0 */ ++static inline u32 GH_PWM_get_Control(u8 index) ++{ ++ return gk_pwm_readl(REG_PWM_CONTROL + index * (0x00001000)); ++} ++ ++/* set value of control1 */ ++static inline void GH_PWM_set_Control1(u8 index, u32 data) ++{ ++ gk_pwm_writel(REG_PWM_CONTROL1 + index * (0x00001000), data); ++} ++ ++/* get value of control1 */ ++static inline u32 GH_PWM_get_Control1(u8 index) ++{ ++ return gk_pwm_readl(REG_PWM_CONTROL1 + index * (0x00001000)); ++} ++ ++static inline s32 GH_PWM_get_freq(u8 channel) ++{ ++ u32 frq; ++ if(GH_PWM_get_Mode(channel)) ++ { ++ return -EINVAL;// because we can not get the vi pclk ++ } ++ else ++ { ++ frq = get_apb_bus_freq_hz(); ++ //printk("frq=%d\n", frq); ++ } ++ ++ return frq; ++ ++} ++ ++/* set pwm speed */ ++static int gk_pwm_set_speed(u8 channel, u32 speed) ++{ ++ s32 frq = 0; ++ u16 fdiv = 0; ++ u16 i = 0; ++ pwm_duty_t pwm_duty; ++ pwm_duty.channel = channel; ++ ++ frq = GH_PWM_get_freq(channel); ++ if(frq <= 0) return -EINVAL; ++ ++ fdiv = 1000; ++ for(i=0;i<5;i++) ++ { ++ if(speed >= speed_ctl[i][0]) ++ { ++ fdiv = speed_ctl[i][1]; ++ g_duty[channel] = frq / fdiv / speed; ++ if(g_duty[channel] == 0) ++ { ++ g_duty[channel] = 1; ++ } ++ break; ++ } ++ } ++ if(fdiv == 0) return -EINVAL; ++ ++ //printk(KERN_INFO "\npwm: freq:%d.%03dKHz, pwm freq:%dHz\n", frq/1000, frq%1000, frq/fdiv); ++ if(GH_PWM_get_Mode(channel)) ++ { ++ return -EINVAL;// because we can not get the vi pclk ++ } ++ else ++ { ++ gk_pwm_writel( GK_VA_RCT + 0x060, fdiv); ++ } ++ pwm_duty.xoff = g_dutyset[pwm_duty.channel]; ++ pwm_duty.xon = 998 - g_dutyset[pwm_duty.channel]; ++ // reset duty ++ gk_pwm_set_duty(&pwm_duty); ++ ++ return 0; ++} ++ ++/* get pwm speed */ ++static long gk_pwm_get_speed(u8 channel, u32 *speed) ++{ ++ s32 frq = 0; ++ u32 fdiv = 0; ++ ++ if(GH_PWM_get_Mode(channel)) ++ { ++ //fdiv = GH_PWM_get_Mode_divider(channel); ++ //fdiv += 1; ++ return -EINVAL;// because we can not get the vi pclk ++ } ++ else ++ { ++ fdiv = gk_pwm_readl( GK_VA_RCT + 0x060); ++ } ++ ++ frq = GH_PWM_get_freq(channel); ++ if(frq <= 0) return -EINVAL; ++ ++ *speed = frq / fdiv / g_duty[channel]; ++ ++ return 0; ++} ++ ++/* set pwm duty rate */ ++static void gk_pwm_set_duty(pwm_duty_t *pwm_duty) ++{ ++ u32 mode; ++ ++ g_dutyset[pwm_duty->channel] = pwm_duty->xoff; ++ pwm_duty->xoff = (pwm_duty->xoff + 1) * g_duty[pwm_duty->channel] / 1000; ++ pwm_duty->xon = (pwm_duty->xon + 1) * g_duty[pwm_duty->channel] / 1000; ++ if(pwm_duty->xoff) ++ pwm_duty->xoff --; ++ if(pwm_duty->xon) ++ pwm_duty->xon --; ++ ++ mode = GH_PWM_get_Mode(pwm_duty->channel); ++ if(mode == GD_NORMAL_SPEED){ ++ GH_PWM_set_Control(pwm_duty->channel,(pwm_duty->xoff << 16| pwm_duty->xon)); ++ } ++ else if(mode == GD_SYNC_SPEED){ ++ GH_PWM_set_Control1(pwm_duty->channel,(pwm_duty->xoff << 16| pwm_duty->xon)); ++ } ++} ++ ++/* get pwm duty rate */ ++static void gk_pwm_get_duty(pwm_duty_t *pwm_duty) ++{ ++ u32 mode = 0; ++ u32 duty_data = 0; ++ ++ mode = GH_PWM_get_Mode(pwm_duty->channel); ++ if(mode == GD_NORMAL_SPEED){ ++ duty_data = GH_PWM_get_Control(pwm_duty->channel); ++ } ++ else if(mode == GD_SYNC_SPEED){ ++ duty_data = GH_PWM_get_Control1(pwm_duty->channel); ++ } ++ pwm_duty->xoff = (duty_data >> 16) & 0xffff; ++ pwm_duty->xon = duty_data & 0xffff; ++ // fix to pwm_duty->xoff + 1 + pwm_duty->xon + 1 = 1000 (adi) ++ pwm_duty->xoff = (pwm_duty->xoff + 1) * 1000 / g_duty[pwm_duty->channel]; ++ pwm_duty->xon = (pwm_duty->xon + 1) * 1000 / g_duty[pwm_duty->channel]; ++ if(pwm_duty->xoff) ++ pwm_duty->xoff --; ++ if(pwm_duty->xon) ++ pwm_duty->xon --; ++} ++ ++/* open file description of pwm */ ++static int gk_pwm_open(struct inode *inode, struct file *file) ++{ ++ if (!down_trylock(&lock)) //ÊÇ·ñ»ñµÃÐźÅÁ¿,ÊÇ down_trylock(&lock)=0,·ñÔò·Ç 0 ++ { ++ //configure PWM function. ++ gk_gpio_config(gk_all_gpio_cfg.pwm0, GPIO_TYPE_OUTPUT_PWM0_OUT); ++ gk_gpio_config(gk_all_gpio_cfg.pwm1, GPIO_TYPE_OUTPUT_PWM1_OUT); ++ gk_gpio_config(gk_all_gpio_cfg.pwm2, GPIO_TYPE_OUTPUT_PWM2_OUT); ++ gk_gpio_config(gk_all_gpio_cfg.pwm3, GPIO_TYPE_OUTPUT_PWM3_OUT); ++ return 0; ++ } ++ else ++ return -EBUSY; //·µ»Ø´íÎóÐÅÏ¢:ÇëÇóµÄ×ÊÔ´²»¿ÉÓà ++} ++/* close pwm */ ++static int gk_pwm_close(struct inode *inode, struct file *file) ++{ ++ GH_PWM_set_Enable(0,0); ++ GH_PWM_set_Enable(1,0); ++ GH_PWM_set_Enable(2,0); ++ GH_PWM_set_Enable(3,0); ++ // logout PWM function. ++ gk_gpio_config(gk_all_gpio_cfg.pwm0, GPIO_TYPE_UNDEFINED); ++ gk_gpio_config(gk_all_gpio_cfg.pwm1, GPIO_TYPE_UNDEFINED); ++ gk_gpio_config(gk_all_gpio_cfg.pwm2, GPIO_TYPE_UNDEFINED); ++ gk_gpio_config(gk_all_gpio_cfg.pwm3, GPIO_TYPE_UNDEFINED); ++ up(&lock); //ÊÍ·ÅÐźÅÁ¿ lock ++ ++ return 0; ++} ++ ++/* pwm ioctl */ ++static long gk_pwm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++// pwm_ctrl_t pwm_ctrl; ++ long error = 0; ++ pwm_mode_t pwm_mode; ++ pwm_duty_t pwm_duty; ++ pwm_speed_t pwm_speed; ++ pwm_status_t pwm_status; ++ switch (cmd) ++ { ++ case GK_PWM_IOCTL_DISABLE: //disabel channel ++ if(arg >= MAX_CHANNEL) return -EINVAL; ++ ++ GH_PWM_set_Enable(arg, 0); ++ break; ++ ++ case GK_PWM_IOCTL_ENABLE: //enabel channel ++ if(arg >= MAX_CHANNEL) return -EINVAL; ++ ++ GH_PWM_set_Enable(arg, 1); ++ break; ++ ++ ++ case GK_PWM_IOCTL_SET_MODE: //config pwm mode. ++ if (arg == 0) ++ return -EINVAL; ++ ++ if (copy_from_user(&pwm_mode, (void __user *)arg, sizeof(pwm_mode_t))) ++ return -EFAULT; ++ ++ //printk("set mode channel:%d mode:%d\n", pwm_mode.channel, pwm_mode.mode); ++ GH_PWM_set_Mode(pwm_mode.channel, pwm_mode.mode); ++ ++ break; ++ ++ case GK_PWM_IOCTL_GET_MODE: //get pwm mode. ++ if (arg == 0) ++ return -EINVAL; ++ ++ if (copy_from_user(&pwm_mode, (void __user *)arg, sizeof(pwm_mode_t))) ++ return -EFAULT; ++ ++ pwm_mode.mode = GH_PWM_get_Mode(pwm_mode.channel); ++ ++ if (copy_to_user((void __user *)arg, &pwm_mode, sizeof(pwm_mode_t))) ++ return -EFAULT; ++ ++ break; ++ ++ case GK_PWM_IOCTL_SET_SPEED://set pwm speed. ++ if (arg == 0) ++ return -EINVAL; ++ ++ if (copy_from_user(&pwm_speed, (void __user *)arg, sizeof(pwm_speed_t))) ++ return -EFAULT; ++ ++ //printk("set speed channel:%d speed:%d\n", pwm_speed.channel, pwm_speed.speed); ++ return gk_pwm_set_speed(pwm_speed.channel, pwm_speed.speed); ++ ++ break; ++ ++ case GK_PWM_IOCTL_GET_SPEED://get pwm speed. ++ if (arg == 0) ++ return -EINVAL; ++ ++ if (copy_from_user(&pwm_speed, (void __user *)arg, sizeof(pwm_speed_t))) ++ return -EFAULT; ++ ++ error = gk_pwm_get_speed(pwm_speed.channel, &pwm_speed.speed); ++ if(error != 0) ++ return error; ++ ++ if (copy_to_user((void __user *)arg, &pwm_speed, sizeof(pwm_speed_t))) ++ return -EFAULT; ++ ++ break; ++ ++ case GK_PWM_IOCTL_SET_DUTY://set pwm duty. ++ if (arg == 0) ++ return -EINVAL; //·µ»Ø´íÎóÐÅÏ¢,±íʾÏò²ÎÊý´«µÝÁËÎÞЧµÄ²ÎÊý ++ ++ if (copy_from_user(&pwm_duty, (void __user *)arg, sizeof(pwm_duty_t))) ++ return -EFAULT; ++ gk_pwm_set_duty(&pwm_duty); ++ ++ break; ++ ++ case GK_PWM_IOCTL_GET_DUTY://get pwm duty. ++ if (arg == 0) ++ return -EINVAL; //·µ»Ø´íÎóÐÅÏ¢,±íʾÏò²ÎÊý´«µÝÁËÎÞЧµÄ²ÎÊý ++ ++ if (copy_from_user(&pwm_duty, (void __user *)arg, sizeof(pwm_duty_t))) ++ return -EFAULT; ++ ++ gk_pwm_get_duty(&pwm_duty); ++ ++ if (copy_to_user((void __user *)arg, &pwm_duty, sizeof(pwm_duty_t))) ++ return -EFAULT; ++ ++ break; ++ ++ case GK_PWM_IOCTL_GET_STATUS: ++ if (arg == 0) ++ return -EINVAL; ++ ++ if (copy_from_user(&pwm_status, (void __user *)arg, sizeof(pwm_status_t))) ++ return -EFAULT; ++ ++ pwm_status.enable = (GH_PWM_get_Enable(pwm_status.channel) > 0) ? 1 : 0; ++ ++ if (copy_to_user((void __user *)arg, &pwm_status, sizeof(pwm_status_t))) ++ return -EFAULT; ++ ++ break; ++ ++ default: ++ printk(KERN_ERR "\npwm:bad params\n"); ++ return -EINVAL; ++ break; ++ } ++ return 0; //normal return ++} ++ ++ ++/*³õʼ»¯É豸µÄÎļþ²Ù×÷µÄ½á¹¹Ìå*/ ++static struct file_operations dev_fops = { ++ .owner = THIS_MODULE, ++ .open = gk_pwm_open, ++ .release = gk_pwm_close, ++ .unlocked_ioctl = gk_pwm_ioctl, ++}; ++ ++static struct miscdevice misc = { ++ .minor = 10, /*MISC_DYNAMIC_MINOR,*/ ++ .name = DEVICE_NAME, ++ .nodename = NODE_NAME, ++ .fops = &dev_fops, ++}; ++ ++ ++ ++static int __init dev_init(void) ++{ ++ int ret; ++ sema_init(&lock, 1); //³õʼ»¯Ò»¸ö»¥³âËø ++ ret = misc_register(&misc); //×¢²áÒ»¸ö misc É豸 ++ printk (DEVICE_NAME" initialized (10:10)\n"); ++ return ret; ++} ++ ++static void __exit dev_exit(void) ++{ ++ misc_deregister(&misc); //×¢ÏúÉ豸 ++} ++ ++module_init(dev_init); ++module_exit(dev_exit); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Goke Microelectronics Inc."); ++MODULE_DESCRIPTION("GK PWM Driver"); +diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig +index 2bc06e73..1ac19e69 100644 +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -4,6 +4,14 @@ + + comment "MMC/SD/SDIO Host Controller Drivers" + ++config MMC_GOKE ++ tristate "goke ipc SD/MMC Host Controller driver" ++ depends on GK_SDIO ++ help ++ This selects the goke ipc Media Processor Multimedia Card ++ Interface support. If you have an goke Media Processor ++ platform with a Multimedia Card slot, say Y here. ++ + config MMC_ARMMMCI + tristate "ARM AMBA Multimedia Card Interface support" + depends on ARM_AMBA +diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile +index 3e7e26d0..7477add4 100644 +--- a/drivers/mmc/host/Makefile ++++ b/drivers/mmc/host/Makefile +@@ -2,6 +2,9 @@ + # Makefile for MMC/SD host controller drivers + # + ++ifdef CONFIG_MMC_GOKE ++obj-$(CONFIG_GK_SDIO2_V1_00) += gk_sdio2_v1_00.o ++endif + obj-$(CONFIG_MMC_ARMMMCI) += mmci.o + obj-$(CONFIG_MMC_PXA) += pxamci.o + obj-$(CONFIG_MMC_IMX) += imxmmc.o +diff --git a/drivers/mmc/host/gk_sdio2_v1_00.c b/drivers/mmc/host/gk_sdio2_v1_00.c +new file mode 100644 +index 00000000..d3d4295b +--- /dev/null ++++ b/drivers/mmc/host/gk_sdio2_v1_00.c +@@ -0,0 +1,2077 @@ ++/* ++ * drivers/mmc/host/gk_sdio2_v1_00.c ++ * ++ * Author: louis liang ++ * Copyright (C) 2014-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++#include ++ ++/*----------------------------------------------------------------------------*/ ++/* registers base: GK_VA_SDC */ ++/*----------------------------------------------------------------------------*/ ++ ++ ++/* ==========================================================================*/ ++ ++/* ==========================================================================*/ ++ ++/* ==========================================================================*/ ++/* ==========================================================================*/ ++#define CONFIG_SD_GK_TIMEOUT_VAL (0xe) ++#define CONFIG_SD_GK_WAIT_TIMEOUT (HZ / 100) ++#define CONFIG_SD_GK_WAIT_COUNTER_LIMIT (100000) ++#define CONFIG_SD_GK_DEFAULT_CLOCK (48000000) ++#define CONFIG_SD_GK_MAX_TIMEOUT (10 * HZ) ++ ++//#define CONFIG_SD_GK_DEBUG ++#undef CONFIG_SD_GK_DEBUG_VERBOSE ++ ++#define gk_sd_printk(level, phcinfo, format, arg...) \ ++ printk("-- %s.%u: " format, \ ++ dev_name(((struct gk_sd_controller_info *)phcinfo->pinfo)->dev),\ ++ phcinfo->slot_id, ## arg) ++ ++#define gk_sd_err(phcinfo, format, arg...) \ ++ gk_sd_printk(KERN_ERR, phcinfo, format, ## arg) ++#define gk_sd_warn(phcinfo, format, arg...) \ ++ gk_sd_printk(KERN_WARNING, phcinfo, format, ## arg) ++#define gk_sd_info(phcinfo, format, arg...) \ ++ gk_sd_printk(KERN_INFO, phcinfo, format, ## arg) ++#define gk_sd_rtdbg(phcinfo, format, arg...) \ ++ gk_sd_printk(KERN_DEBUG, phcinfo, format, ## arg) ++ ++#ifdef CONFIG_SD_GK_DEBUG ++#define gk_sd_dbg(phcinfo, format, arg...) \ ++ gk_sd_printk(KERN_DEBUG, phcinfo, format, ## arg) ++#else ++#define gk_sd_dbg(phcinfo, format, arg...) \ ++ ({ if (0) gk_sd_printk(KERN_DEBUG, phcinfo, format, ##arg); 0; }) ++#endif ++ ++/* ==========================================================================*/ ++enum gk_sd_state { ++ GK_SD_STATE_IDLE, ++ GK_SD_STATE_CMD, ++ GK_SD_STATE_DATA, ++ GK_SD_STATE_RESET, ++ GK_SD_STATE_ERR ++}; ++ ++#define REG_WR(reg,value) (*((volatile u32 *)(reg))=(value)) ++ ++struct gk_sd_mmc_info { ++ struct mmc_host *mmc; ++ struct mmc_request *mrq; ++ ++ wait_queue_head_t wait; ++ ++ enum gk_sd_state state; ++ ++ struct scatterlist *sg; ++ u32 sg_len; ++ u32 wait_tmo; ++ u16 blk_sz; ++ u16 blk_cnt; ++ u32 arg_reg; ++ u16 xfr_reg; ++ u16 cmd_reg; ++ u16 sta_reg; ++ u8 tmo; ++ u8 use_adma; ++ u32 sta_counter; ++ ++ char *buf_vaddress; ++ dma_addr_t buf_paddress; ++ u32 dma_address; ++ u32 dma_size; ++ ++ void (*pre_dma)(void *data); ++ void (*post_dma)(void *data); ++ ++ struct gk_sd_slot *plat_info; ++ u32 slot_id; ++ void *pinfo; ++ u32 valid; ++ ++ struct notifier_block system_event; ++ struct semaphore system_event_sem; ++}; ++ ++struct gk_sd_controller_info { ++ unsigned char __iomem *regbase; ++ struct device *dev; ++ unsigned int irq; ++ u32 dma_fix; ++ u32 clk_limit; ++ u32 reset_error; ++ ++ u32 max_blk_sz; ++ struct kmem_cache *buf_cache; ++ ++ struct gk_sd_controller *pcontroller; ++ struct gk_sd_mmc_info *pslotinfo[GK_SD_MAX_SLOT_NUM]; ++ struct mmc_ios controller_ios; ++}; ++ ++/* ==========================================================================*/ ++#ifdef CONFIG_SD_GK_DEBUG_VERBOSE ++static void gk_sd_show_info(struct gk_sd_mmc_info *pslotinfo) ++{ ++ gk_sd_dbg(pslotinfo, "Enter %s\n", __func__); ++ gk_sd_dbg(pslotinfo, "sg = 0x%x.\n", (u32)pslotinfo->sg); ++ gk_sd_dbg(pslotinfo, "sg_len = 0x%x.\n", pslotinfo->sg_len); ++ gk_sd_dbg(pslotinfo, "tmo = 0x%x.\n", pslotinfo->tmo); ++ gk_sd_dbg(pslotinfo, "blk_sz = 0x%x.\n", pslotinfo->blk_sz); ++ gk_sd_dbg(pslotinfo, "blk_cnt = 0x%x.\n", pslotinfo->blk_cnt); ++ gk_sd_dbg(pslotinfo, "arg_reg = 0x%x.\n", pslotinfo->arg_reg); ++ gk_sd_dbg(pslotinfo, "xfr_reg = 0x%x.\n", pslotinfo->xfr_reg); ++ gk_sd_dbg(pslotinfo, "cmd_reg = 0x%x.\n", pslotinfo->cmd_reg); ++ gk_sd_dbg(pslotinfo, "buf_vaddress = 0x%x.\n", (u32)pslotinfo->buf_vaddress); ++ gk_sd_dbg(pslotinfo, "buf_paddress = 0x%x.\n", pslotinfo->buf_paddress); ++ gk_sd_dbg(pslotinfo, "dma_address = 0x%x.\n", pslotinfo->dma_address); ++ gk_sd_dbg(pslotinfo, "dma_size = 0x%x.\n", pslotinfo->dma_size); ++ gk_sd_dbg(pslotinfo, "pre_dma = 0x%x.\n", (u32)pslotinfo->pre_dma); ++ gk_sd_dbg(pslotinfo, "post_dma = 0x%x.\n", (u32)pslotinfo->post_dma); ++ gk_sd_dbg(pslotinfo, "SD: state = 0x%x.\n", pslotinfo->state); ++ gk_sd_dbg(pslotinfo, "Exit %s\n", __func__); ++} ++#endif ++ ++ ++static u32 gk_sd_check_dma_boundary( ++ struct gk_sd_mmc_info *pslotinfo, ++ u32 address, u32 size, u32 max_size) ++{ ++ u32 start_512kb; ++ u32 end_512kb; ++ ++ start_512kb = (address) & (~(max_size - 1)); ++ end_512kb = (address + size - 1) & (~(max_size - 1)); ++ ++ if (start_512kb != end_512kb) { ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static u32 gk_sd_dma_mask_to_size(u32 mask) ++{ ++ u32 size; ++ ++ switch (mask) { ++ case SD_BLK_SZ_512KB: ++ size = 0x80000; ++ break; ++ case SD_BLK_SZ_256KB: ++ size = 0x40000; ++ break; ++ case SD_BLK_SZ_128KB: ++ size = 0x20000; ++ break; ++ case SD_BLK_SZ_64KB: ++ size = 0x10000; ++ break; ++ case SD_BLK_SZ_32KB: ++ size = 0x8000; ++ break; ++ case SD_BLK_SZ_16KB: ++ size = 0x4000; ++ break; ++ case SD_BLK_SZ_8KB: ++ size = 0x2000; ++ break; ++ case SD_BLK_SZ_4KB: ++ size = 0x1000; ++ break; ++ default: ++ size = 0; ++ BUG_ON(1); ++ break; ++ } ++ ++ return size; ++} ++ ++static void gk_sd_pre_sg_to_dma(void *data) ++{ ++ struct gk_sd_mmc_info *pslotinfo; ++ struct gk_sd_controller_info *pinfo; ++ int i; ++ //int j; ++ u32 offset; ++ //u32 *res; ++ ++ pslotinfo = (struct gk_sd_mmc_info *)data; ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ ++ for (i = 0, offset = 0; i < pslotinfo->sg_len; i++) { ++ //printk("copy: 0x%0x - 0x%0x len=%d\n", pslotinfo->buf_vaddress + offset, ++ // sg_virt(&pslotinfo->sg[i]), pslotinfo->sg[i].length); ++#if 0 ++ res = (u32*)(pslotinfo->buf_vaddress + offset); ++ for(j=0;jsg[i].length/4;j++) ++ printk("0x%0x \n", res[j]); ++ printk("\n"); ++#endif ++ ++ memcpy(pslotinfo->buf_vaddress + offset, ++ sg_virt(&pslotinfo->sg[i]), ++ pslotinfo->sg[i].length); ++ offset += pslotinfo->sg[i].length; ++ } ++ ++ BUG_ON(offset != pslotinfo->dma_size); ++ dma_sync_single_for_device(pinfo->dev, pslotinfo->buf_paddress, ++ pslotinfo->dma_size, DMA_TO_DEVICE); ++ pslotinfo->dma_address = pslotinfo->buf_paddress; ++ pslotinfo->blk_sz |= SD_BLK_SZ_512KB; ++} ++ ++static void gk_sd_post_sg_to_dma(void *data) ++{ ++ struct gk_sd_mmc_info *pslotinfo; ++ struct gk_sd_controller_info *pinfo; ++ ++ ++ pslotinfo = (struct gk_sd_mmc_info *)data; ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ dma_sync_single_for_cpu(pinfo->dev, pslotinfo->buf_paddress, ++ pslotinfo->dma_size, DMA_TO_DEVICE); ++} ++ ++static void gk_sd_pre_dma_to_sg(void *data) ++{ ++ struct gk_sd_mmc_info *pslotinfo; ++ struct gk_sd_controller_info *pinfo; ++ ++ pslotinfo = (struct gk_sd_mmc_info *)data; ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ dma_sync_single_for_device(pinfo->dev, pslotinfo->buf_paddress, pslotinfo->dma_size, DMA_FROM_DEVICE); ++ //printk("dma_sync_single_for_device: buf=0x%x size=%d\n", pslotinfo->buf_paddress, pslotinfo->dma_size); ++ pslotinfo->dma_address = pslotinfo->buf_paddress; ++ pslotinfo->blk_sz |= SD_BLK_SZ_512KB; ++} ++ ++static void gk_sd_post_dma_to_sg(void *data) ++{ ++ struct gk_sd_mmc_info *pslotinfo; ++ struct gk_sd_controller_info *pinfo; ++ int i; ++ //int j; ++ //u8 *res; ++ u32 offset; ++ ++ pslotinfo = (struct gk_sd_mmc_info *)data; ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ dma_sync_single_for_cpu(pinfo->dev, pslotinfo->buf_paddress, ++ pslotinfo->dma_size, DMA_FROM_DEVICE); ++ for (i = 0, offset = 0; i < pslotinfo->sg_len; i++) { ++ ++ //printk("copy: 0x%0x - 0x%0x len=%d\n", sg_virt(&pslotinfo->sg[i]), ++ // pslotinfo->buf_vaddress + offset, pslotinfo->sg[i].length); ++#if 0 ++ res = (u8*)(pslotinfo->buf_vaddress + offset); ++ for(j=0;jsg[i].length;j=j+8) ++ printk("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x \n", ++ res[j], res[j+1], res[j+2], res[j+3], ++ res[j+4], res[j+5], res[j+6], res[j+7]); ++ printk("\n"); ++#endif ++ memcpy(sg_virt(&pslotinfo->sg[i]), ++ pslotinfo->buf_vaddress + offset, ++ pslotinfo->sg[i].length); ++ offset += pslotinfo->sg[i].length; ++ } ++ BUG_ON(offset != pslotinfo->dma_size); ++} ++ ++static void gk_sd_request_bus(struct mmc_host *mmc) ++{ ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ ++ down(&pslotinfo->system_event_sem); ++ ++ if (pslotinfo->plat_info->request) ++ pslotinfo->plat_info->request(); ++} ++ ++static void gk_sd_release_bus(struct mmc_host *mmc) ++{ ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ ++ if (pslotinfo->plat_info->release) ++ pslotinfo->plat_info->release(); ++ ++ up(&pslotinfo->system_event_sem); ++} ++ ++static void gk_sd_enable_int(struct mmc_host *mmc, u32 mask) ++{ ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ ++ pslotinfo->plat_info->set_int(mask, 1); ++} ++ ++static void gk_sd_disable_int(struct mmc_host *mmc, u32 mask) ++{ ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ ++ pslotinfo->plat_info->set_int(mask, 0); ++} ++ ++static void gk_sd_set_iclk(struct mmc_host *mmc, u16 clk_div) ++{ ++ u16 clkreg; ++ u32 counter = 0; ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ struct gk_sd_controller_info *pinfo; ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++// printk("set clock div\n"); ++ ++ ++#if 1 ++ clk_div <<= 8; ++ clk_div |= SD_CLK_ICLK_EN; ++ gk_sd_writew((unsigned int)pinfo->regbase + SD_CLK_OFFSET, clk_div); ++ //printk("## 1set clock div = %d \n", clk_div); ++ while (1) { ++ clkreg = gk_sd_readw((unsigned int)pinfo->regbase + SD_CLK_OFFSET); ++ if (clkreg & SD_CLK_ICLK_STABLE) ++ break; ++ if ((clkreg & ~SD_CLK_ICLK_STABLE) != clk_div) { ++ gk_sd_writew((unsigned int)pinfo->regbase + SD_CLK_OFFSET, clk_div); ++ //printk("## 2set clock div = %d \n", clk_div); ++ udelay(1); ++ } ++ counter++; ++ if (counter > CONFIG_SD_GK_WAIT_COUNTER_LIMIT) { ++ gk_sd_warn(pslotinfo, ++ "Wait SD_CLK_ICLK_STABLE = %d @ 0x%x\n", ++ counter, clkreg); ++ break; ++ } ++ } ++#endif ++} ++ ++static void gk_sd_clear_clken(struct mmc_host *mmc) ++{ ++ u16 clkreg; ++ u32 counter = 0; ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ struct gk_sd_controller_info *pinfo; ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ while (1) { ++ clkreg = gk_sd_readw((unsigned int)pinfo->regbase + SD_CLK_OFFSET); ++ if (clkreg & SD_CLK_EN) { ++ gk_sd_writew((unsigned int)pinfo->regbase + SD_CLK_OFFSET, ++ (clkreg & ~SD_CLK_EN)); ++ udelay(1); ++ } else { ++ break; ++ } ++ counter++; ++ if (counter > CONFIG_SD_GK_WAIT_COUNTER_LIMIT) { ++ gk_sd_warn(pslotinfo, "%s(%d @ 0x%x)\n", ++ __func__, counter, clkreg); ++ break; ++ } ++ } ++} ++ ++static void gk_sd_set_clken(struct mmc_host *mmc) ++{ ++ u16 clkreg; ++ u32 counter = 0; ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ struct gk_sd_controller_info *pinfo; ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ while (1) { ++ clkreg = gk_sd_readw((unsigned int)pinfo->regbase + SD_CLK_OFFSET); ++ if (clkreg & SD_CLK_EN) { ++ break; ++ } else { ++ gk_sd_writew((unsigned int)pinfo->regbase + SD_CLK_OFFSET, (clkreg | SD_CLK_EN)); ++ //printk("## 3set clock div = %d \n", (clkreg | SD_CLK_EN)); ++ udelay(1); ++ } ++ counter++; ++ if (counter > CONFIG_SD_GK_WAIT_COUNTER_LIMIT) { ++ gk_sd_warn(pslotinfo, "%s(%d @ 0x%x)\n", ++ __func__, counter, clkreg); ++ break; ++ } ++ } ++} ++ ++static void gk_sd_reset_all(struct mmc_host *mmc) ++{ ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ struct gk_sd_controller_info *pinfo; ++ u32 nis_flag = 0; ++ u32 eis_flag = 0; ++ u32 counter = 0; ++ u8 reset_reg; ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ //printk(pslotinfo, "Enter %s with state %u\n", __func__, pslotinfo->state); ++ ++ gk_sd_disable_int(mmc, 0xFFFFFFFF); ++ gk_sd_writew((unsigned int)pinfo->regbase + SD_NIS_OFFSET, 0xFFFF); ++ gk_sd_writew((unsigned int)pinfo->regbase + SD_EIS_OFFSET, 0xFFFF); ++ gk_sd_writeb((unsigned int)pinfo->regbase + SD_RESET_OFFSET, SD_RESET_ALL); ++ while (1) { ++ reset_reg = gk_sd_readb((unsigned int)pinfo->regbase + SD_RESET_OFFSET); ++ if (!(reset_reg & SD_RESET_ALL)) ++ break; ++ counter++; ++ if (counter > CONFIG_SD_GK_WAIT_COUNTER_LIMIT) { ++ gk_sd_warn(pslotinfo, "Wait SD_RESET_ALL....\n"); ++ break; ++ } ++ } ++ ++ gk_sd_set_iclk(mmc, 0x0000); ++ gk_sd_writeb((unsigned int)pinfo->regbase + SD_TMO_OFFSET, ++ CONFIG_SD_GK_TIMEOUT_VAL); ++ ++ nis_flag = SD_NISEN_REMOVAL | ++ SD_NISEN_INSERT | ++ SD_NISEN_DMA | ++ SD_NISEN_BLOCK_GAP | ++ SD_NISEN_XFR_DONE | ++ SD_NISEN_CMD_DONE; ++ eis_flag = SD_EISEN_ACMD12_ERR | ++ SD_EISEN_CURRENT_ERR | ++ SD_EISEN_DATA_BIT_ERR | ++ SD_EISEN_DATA_CRC_ERR | ++ SD_EISEN_DATA_TMOUT_ERR | ++ SD_EISEN_CMD_IDX_ERR | ++ SD_EISEN_CMD_BIT_ERR | ++ SD_EISEN_CMD_CRC_ERR | ++ SD_EISEN_CMD_TMOUT_ERR; ++ ++ gk_sd_enable_int(mmc, (eis_flag << 16) | nis_flag); ++ ++ //GD_SDIO_Rest(); ++ ++ pslotinfo->state = GK_SD_STATE_RESET; ++ pinfo->reset_error = 0; ++ ++ gk_sd_dbg(pslotinfo, "Exit %s with counter %u\n", __func__, counter); ++} ++ ++static void gk_sd_reset_cmd_line(struct mmc_host *mmc) ++{ ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ struct gk_sd_controller_info *pinfo; ++ u32 counter = 0; ++ u8 reset_reg; ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ gk_sd_writeb((unsigned int)pinfo->regbase + SD_RESET_OFFSET, SD_RESET_CMD); ++ while (1) { ++ reset_reg = gk_sd_readb((unsigned int)pinfo->regbase + SD_RESET_OFFSET); ++ if (!(reset_reg & SD_RESET_CMD)) ++ break; ++ counter++; ++ if (counter > CONFIG_SD_GK_WAIT_COUNTER_LIMIT) { ++ //printk("Wait SD_RESET_CMD...\n"); ++ pinfo->reset_error = 1; ++ break; ++ } ++ } ++} ++ ++static void gk_sd_reset_data_line(struct mmc_host *mmc) ++{ ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ struct gk_sd_controller_info *pinfo; ++ u32 counter = 0; ++ u8 reset_reg; ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ gk_sd_dbg(pslotinfo, "Enter %s with state %u\n", ++ __func__, pslotinfo->state); ++ ++ gk_sd_writeb((unsigned int)pinfo->regbase + SD_RESET_OFFSET, SD_RESET_DAT); ++ while (1) { ++ reset_reg = gk_sd_readb((unsigned int)pinfo->regbase + SD_RESET_OFFSET); ++ if (!(reset_reg & SD_RESET_DAT)) ++ break; ++ counter++; ++ if (counter > CONFIG_SD_GK_WAIT_COUNTER_LIMIT) { ++ gk_sd_warn(pslotinfo, "Wait SD_RESET_DAT...\n"); ++ pinfo->reset_error = 1; ++ break; ++ } ++ } ++ gk_sd_dbg(pslotinfo, "Exit %s with counter %u\n", __func__, counter); ++} ++ ++static inline void gk_sd_data_done( ++ struct gk_sd_mmc_info *pslotinfo, u16 nis, u16 eis) ++{ ++ struct mmc_data *data; ++ ++ if ((pslotinfo->state == GK_SD_STATE_CMD) && ++ ((pslotinfo->cmd_reg & 0x3) == SD_CMD_RSP_48BUSY)) { ++ if (eis) { ++ pslotinfo->state = GK_SD_STATE_ERR; ++ } else { ++ pslotinfo->state = GK_SD_STATE_IDLE; ++ } ++ wake_up(&pslotinfo->wait); ++ return; ++ } ++ if (pslotinfo->mrq == NULL) { ++ gk_sd_dbg(pslotinfo, "%s: mrq is NULL, nis[0x%x] eis[0x%x]\n", ++ __func__, nis, eis); ++ return; ++ } ++ if (pslotinfo->mrq->data == NULL) { ++ gk_sd_dbg(pslotinfo, "%s: data is NULL, nis[0x%x] eis[0x%x]\n", ++ __func__, nis, eis); ++ return; ++ } ++ ++ data = pslotinfo->mrq->data; ++ ++ //printk("### CMD[%u] get eis[0x%x]\n", pslotinfo->mrq->cmd->opcode, eis); ++ ++ if (eis) { ++ if (eis & SD_EIS_DATA_BIT_ERR) { ++ data->error = -EILSEQ; ++ } else if (eis & SD_EIS_DATA_CRC_ERR) { ++ data->error = -EILSEQ; ++ } else if (eis & SD_EIS_DATA_TMOUT_ERR) { ++ data->error = -ETIMEDOUT; ++ } else { ++ data->error = -EIO; ++ } ++//#ifdef CONFIG_SD_GK_DEBUG_VERBOSE ++ //printk("error -- %s: CMD[%u] get eis[0x%x]\n", __func__, ++ // pslotinfo->mrq->cmd->opcode, eis); ++//#endif ++ pslotinfo->state = GK_SD_STATE_ERR; ++ wake_up(&pslotinfo->wait); ++ return; ++ } else { ++ data->bytes_xfered = pslotinfo->dma_size; ++ } ++ ++ pslotinfo->state = GK_SD_STATE_IDLE; ++ wake_up(&pslotinfo->wait); ++} ++ ++static inline void gk_sd_cmd_done( ++ struct gk_sd_mmc_info *pslotinfo, u16 nis, u16 eis) ++{ ++ struct mmc_command *cmd; ++ u32 rsp0, rsp1, rsp2, rsp3; ++ struct gk_sd_controller_info *pinfo; ++ u16 ac12es; ++ ++ if (pslotinfo->mrq == NULL) { ++ printk("%s: mrq is NULL, nis[0x%x] eis[0x%x]\n", ++ __func__, nis, eis); ++ return; ++ } ++ if (pslotinfo->mrq->cmd == NULL) { ++ printk( "%s: cmd is NULL, nis[0x%x] eis[0x%x]\n", ++ __func__, nis, eis); ++ return; ++ } ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ cmd = pslotinfo->mrq->cmd; ++ ++ //printk("#### CMD[%u] get eis[0x%x]\n", pslotinfo->mrq->cmd->opcode, eis); ++ ++ if (eis) { ++ if (eis & SD_EIS_CMD_BIT_ERR) { ++ cmd->error = -EILSEQ; ++ } else if (eis & SD_EIS_CMD_CRC_ERR) { ++ cmd->error = -EILSEQ; ++ } else if (eis & SD_EIS_CMD_TMOUT_ERR) { ++ cmd->error = -ETIMEDOUT; ++ } else if (eis & SD_EIS_ACMD12_ERR) { ++ ac12es = gk_sd_readl((unsigned int)pinfo->regbase + SD_AC12ES_OFFSET); ++ if (ac12es & SD_AC12ES_TMOUT_ERROR) { ++ cmd->error = -ETIMEDOUT; ++ } else if (eis & SD_AC12ES_CRC_ERROR) { ++ cmd->error = -EILSEQ; ++ } else { ++ cmd->error = -EIO; ++ } ++ ++ if (pslotinfo->mrq->stop) { ++ pslotinfo->mrq->stop->error = cmd->error; ++ } else { ++ gk_sd_err(pslotinfo, "%s NULL stop 0x%x %u\n", ++ __func__, ac12es, cmd->error); ++ } ++ } else { ++ cmd->error = -EIO; ++ } ++//#ifdef CONFIG_SD_GK_DEBUG_VERBOSE ++ ++//#endif ++ pslotinfo->state = GK_SD_STATE_ERR; ++ ++ //printk("error - %s: CMD[%u] get eis[0x%x] state= [%s]\n", __func__, ++ // pslotinfo->mrq->cmd->opcode, eis, sd_state(pslotinfo->state)); ++ ++ wake_up(&pslotinfo->wait); ++ return; ++ } ++//printk("cmd handle ok...get reponse\n"); ++ if (cmd->flags & MMC_RSP_136) { ++ rsp0 = gk_sd_readl((unsigned int)pinfo->regbase + SD_RSP0_OFFSET); ++ rsp1 = gk_sd_readl((unsigned int)pinfo->regbase + SD_RSP1_OFFSET); ++ rsp2 = gk_sd_readl((unsigned int)pinfo->regbase + SD_RSP2_OFFSET); ++ rsp3 = gk_sd_readl((unsigned int)pinfo->regbase + SD_RSP3_OFFSET); ++ cmd->resp[0] = ((rsp3 << 8) | (rsp2 >> 24)); ++ cmd->resp[1] = ((rsp2 << 8) | (rsp1 >> 24)); ++ cmd->resp[2] = ((rsp1 << 8) | (rsp0 >> 24)); ++ cmd->resp[3] = (rsp0 << 8); ++ ++ //printk("response1: [0x%x] [0x%x] [0x%x] [0x%x] \n", cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); ++ } else { ++ cmd->resp[0] = gk_sd_readl((unsigned int)pinfo->regbase + SD_RSP0_OFFSET); ++ //printk("response2: [0x%x] \n", cmd->resp[0]); ++ } ++ ++ if ((pslotinfo->state == GK_SD_STATE_CMD) && ++ ((pslotinfo->cmd_reg & 0x3) != SD_CMD_RSP_48BUSY)) { ++ pslotinfo->state = GK_SD_STATE_IDLE; ++ wake_up(&pslotinfo->wait); ++ } ++} ++ ++static irqreturn_t gk_sd_irq(int irq, void *devid) ++{ ++ struct gk_sd_controller_info *pinfo; ++ struct gk_sd_mmc_info *pslotinfo = NULL; ++ u16 nis=0; ++ u16 eis=0; ++ u32 enabled = 0; ++ u32 i; ++ ++ pinfo = (struct gk_sd_controller_info *)devid; ++ ++ /* Read the interrupt registers */ ++ nis = gk_sd_readw((unsigned int)pinfo->regbase + SD_NIS_OFFSET); ++ eis = gk_sd_readw((unsigned int)pinfo->regbase + SD_EIS_OFFSET); ++ //printk("-- nis = 0x%x eis = 0x%x\n", nis, eis); ++#if 0 ++ switch(nis) ++ { ++ case SD_NIS_ERROR: ++ printk("-- SD_NIS_ERROR\n"); ++ break; ++ case SD_NIS_CARD: ++ printk("-- SD_NIS_CARD\n"); ++ break; ++ case SD_NIS_REMOVAL: ++ printk("-- SD_NIS_REMOVAL\n"); ++ break; ++ case SD_NIS_INSERT: ++ printk("-- SD_NIS_INSERT\n"); ++ break; ++ case SD_NIS_READ_READY: ++ printk("-- SD_NIS_READ_READY\n"); ++ break; ++ case SD_NIS_WRITE_READY: ++ printk("-- SD_NIS_WRITE_READY\n"); ++ break; ++ case SD_NIS_DMA: ++ printk("-- SD_NIS_DMA\n"); ++ break; ++ case SD_NIS_BLOCK_GAP: ++ printk("-- SD_NIS_BLOCK_GAP\n"); ++ break; ++ case SD_NIS_XFR_DONE: ++ printk("-- SD_NIS_XFR_DONE\n"); ++ break; ++ case SD_NIS_CMD_DONE: ++ printk("-- SD_NIS_CMD_DONE\n"); ++ break; ++ default: ++ printk("-- unknow nis -- 0x%x\n", nis); ++ break; ++ } ++#endif ++ switch(eis) ++ { ++ case SD_EIS_ACMD12_ERR: ++ printk("-- SD_EIS_ACMD12_ERR\n"); ++ break; ++ case SD_EIS_CURRENT_ERR: ++ printk("-- SD_EIS_CURRENT_ERR\n"); ++ break; ++ case SD_EIS_DATA_BIT_ERR: ++ printk("-- SD_EIS_DATA_BIT_ERR\n"); ++ break; ++ case SD_EIS_DATA_CRC_ERR: ++ printk("-- SD_EIS_DATA_CRC_ERR\n"); ++ break; ++ case SD_EIS_DATA_TMOUT_ERR: ++ printk("-- SD_EIS_DATA_TMOUT_ERR\n"); ++ break; ++ case SD_EIS_CMD_IDX_ERR: ++ printk("-- SD_EIS_CMD_IDX_ERR\n"); ++ break; ++ case SD_EIS_CMD_BIT_ERR: ++ printk("-- SD_EIS_CMD_BIT_ERR\n"); ++ break; ++ case SD_EIS_CMD_CRC_ERR: ++ printk("-- SD_EIS_CMD_CRC_ERR\n"); ++ break; ++ case SD_EIS_CMD_TMOUT_ERR: ++ //printk("-- SD_EIS_CMD_TMOUT_ERR\n"); ++ break; ++ default: ++ break; ++ } ++ ++ ++ for (i = 0; i < pinfo->pcontroller->num_slots; i++) { ++ pslotinfo = pinfo->pslotinfo[i]; ++ enabled = pslotinfo->plat_info->check_owner(); ++ if (enabled) ++ break; ++ } ++ ++ /* Clear interrupt */ ++ gk_sd_writew((unsigned int)pinfo->regbase + SD_NIS_OFFSET, nis); ++ gk_sd_writew((unsigned int)pinfo->regbase + SD_EIS_OFFSET, eis); ++ if (enabled) { ++ //printk("-- %s nis = 0x%x, eis = 0x%x & [%s]\n", ++ //__func__, nis, eis, sd_state(pslotinfo->state)); ++ } else { ++ gk_sd_dbg(pslotinfo, "%s[false] nis = 0x%x, eis = 0x%x\n", ++ __func__, nis, eis); ++ if (eis) { ++ gk_sd_reset_all(pslotinfo->mmc); ++ } ++ goto gk_sd_irq_exit; ++ } ++ ++ if (nis & SD_NIS_CARD) { ++ //printk("SD_NIS_CARD -- mmc_signal_sdio_irq\n"); ++ mmc_signal_sdio_irq(pslotinfo->mmc); ++ } ++ ++ //if (!gk_is_valid_gpio_irq(&pslotinfo->plat_info->gpio_cd) && ++ // (pslotinfo->plat_info->fixed_cd == -1)) ++ { ++ if (nis & SD_NIS_REMOVAL) { ++ //printk("SD_NIS_REMOVAL -- mmc_detect_change\n"); ++ mmc_detect_change(pslotinfo->mmc, pslotinfo->plat_info->cd_delay); ++ } else if (nis & SD_NIS_INSERT) { ++ //printk("SD_NIS_INSERT -- mmc_detect_change\n"); ++ mmc_detect_change(pslotinfo->mmc, pslotinfo->plat_info->cd_delay); ++ } ++ } ++ ++ if (eis) { ++ if (eis & (SD_EIS_CMD_TMOUT_ERR | SD_EIS_CMD_CRC_ERR | ++ SD_EIS_CMD_BIT_ERR | SD_EIS_CMD_IDX_ERR | ++ SD_EIS_ACMD12_ERR)) { ++ gk_sd_reset_cmd_line(pslotinfo->mmc); ++ } ++ if (eis & (SD_EIS_DATA_TMOUT_ERR | SD_EIS_DATA_CRC_ERR)) { ++ gk_sd_reset_data_line(pslotinfo->mmc); ++ } ++ if (eis & (SD_EIS_DATA_BIT_ERR | SD_EIS_CURRENT_ERR)) { ++ gk_sd_reset_all(pslotinfo->mmc); ++ } ++ if (pslotinfo->state == GK_SD_STATE_CMD) { ++ gk_sd_cmd_done(pslotinfo, nis, eis); ++ } else if (pslotinfo->state == GK_SD_STATE_DATA) { ++ gk_sd_data_done(pslotinfo, nis, eis); ++ } ++ } else { ++ if (nis & SD_NIS_CMD_DONE) { ++ gk_sd_cmd_done(pslotinfo, nis, eis); ++ } ++ if (nis & SD_NIS_XFR_DONE) { ++ gk_sd_data_done(pslotinfo, nis, eis); ++ } ++#if 0 ++ if (nis & SD_NIS_DMA) { ++ gk_sd_writel((unsigned int)pinfo->regbase + SD_DMA_ADDR_OFFSET, ++ gk_sd_readl((unsigned int)pinfo->regbase + SD_DMA_ADDR_OFFSET)); ++ } ++#endif ++ } ++ ++gk_sd_irq_exit: ++ //printk("-----------handle irq end-------------\n"); ++ return IRQ_HANDLED; ++} ++ ++static int gk_sd_gpio_cd_check_val(struct gk_sd_mmc_info *pslotinfo) ++{ ++ u32 val = -1; ++ ++ gk_gpio_config(pslotinfo->plat_info->gpio_cd.irq_gpio, GPIO_TYPE_INPUT_0); ++ val = gk_gpio_get(pslotinfo->plat_info->gpio_cd.irq_gpio); ++ ++ gk_gpio_config(pslotinfo->plat_info->gpio_cd.irq_gpio, pslotinfo->plat_info->gpio_cd.irq_gpio_mode); ++ val = (val == pslotinfo->plat_info->gpio_cd.irq_gpio_val) ? 1 : 0; ++ ++ gk_sd_dbg(pslotinfo, "%s:%u\n", (val == 1) ? ++ "card insert" : "card eject", ++ pslotinfo->plat_info->cd_delay); ++ ++ pslotinfo->plat_info->fixed_cd = val; ++ ++ return val; ++} ++ ++static irqreturn_t gk_sd_gpio_cd_irq(int irq, void *devid) ++{ ++ struct gk_sd_mmc_info *pslotinfo; ++ ++ pslotinfo = (struct gk_sd_mmc_info *)devid; ++ if (pslotinfo->valid && ++ (gk_sd_gpio_cd_check_val(pslotinfo) != -1)) { ++ mmc_detect_change(pslotinfo->mmc, ++ pslotinfo->plat_info->cd_delay); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static void gk_sd_set_clk(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ struct gk_sd_controller_info *pinfo; ++ u16 clk_div = 0x0000; ++ u32 sd_clk; ++ u32 desired_clk; ++ u32 actual_clk; ++ u32 bneed_div = 1; ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ gk_sd_clear_clken(mmc); ++ if (ios->clock == 0) { ++ pinfo->pcontroller->active_clock = 0; ++ } else { ++ desired_clk = ios->clock; ++ if (desired_clk > pinfo->clk_limit) ++ desired_clk = pinfo->clk_limit; ++ ++ if (pinfo->pcontroller->support_pll_scaler) { ++ if (desired_clk < 10000000) { ++ /* Below 10Mhz, divide by sd controller */ ++ pinfo->pcontroller->set_pll(pinfo->clk_limit); ++ } else { ++ pinfo->pcontroller->set_pll(desired_clk); ++ actual_clk = pinfo->pcontroller->get_pll(); ++ bneed_div = 0; ++ } ++ } ++ ++ if (bneed_div) { ++ sd_clk = pinfo->pcontroller->get_pll(); ++ for (clk_div = 0x0; clk_div <= 0x80;) { ++ if (clk_div == 0) ++ actual_clk = sd_clk; ++ else ++ actual_clk = sd_clk / (clk_div << 1); ++ ++ if (actual_clk <= desired_clk) ++ break; ++ ++ if (clk_div >= 0x80) ++ break; ++ ++ if (clk_div == 0x0) ++ clk_div = 0x1; ++ else ++ clk_div <<= 1; ++ } ++ } ++ //printk("sd_pll = %u.\n",pinfo->pcontroller->get_pll()); ++ //printk("desired_clk = %u.\n", desired_clk); ++ //printk("actual_clk = %u.\n", actual_clk); ++ //printk("clk_div = %u.\n", clk_div); ++ pinfo->pcontroller->active_clock = actual_clk; ++ gk_sd_set_iclk(mmc, clk_div); ++ gk_sd_set_clken(mmc); ++ } ++} ++ ++static void gk_sd_set_pwr(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ //printk("gk_sd_set_pwr ....\n"); ++ ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ struct gk_sd_controller_info *pinfo; ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ if (ios->power_mode == MMC_POWER_OFF) { ++ //printk("power off\n"); ++ gk_sd_reset_all(pslotinfo->mmc); ++ gk_sd_writeb((unsigned int)pinfo->regbase + SD_PWR_OFFSET, SD_PWR_OFF); ++ //gk_set_gpio_output_can_sleep( ++ // &pslotinfo->plat_info->ext_reset, 1, 1); ++ //gk_set_gpio_output_can_sleep( ++ // &pslotinfo->plat_info->ext_power, 0, 1); ++ if (pslotinfo->plat_info->set_vdd) { ++ pslotinfo->plat_info->set_vdd(0); ++ } ++ } else if (ios->power_mode == MMC_POWER_UP) { ++ if (pslotinfo->plat_info->set_vdd) { ++ pslotinfo->plat_info->set_vdd(3300); ++ } ++ //printk("power up...\n"); ++ //gk_set_gpio_output_can_sleep( ++ // &pslotinfo->plat_info->ext_power, 1, 1); ++ //gk_set_gpio_output_can_sleep( ++ // &pslotinfo->plat_info->ext_reset, 0, 1); ++ gk_sd_writeb((unsigned int)pinfo->regbase + SD_PWR_OFFSET, ++ (SD_PWR_ON | SD_PWR_3_3V)); ++ } else if (ios->power_mode == MMC_POWER_ON) { ++ //printk("power on...\n"); ++ switch (1 << ios->vdd) { ++ case MMC_VDD_32_33: ++ case MMC_VDD_33_34: ++ break; ++ default: ++ gk_sd_err(pslotinfo, "%s Wrong voltage[%u]!\n", ++ __func__, ios->vdd); ++ break; ++ } ++ } ++ msleep(pinfo->pcontroller->pwr_delay); ++ gk_sd_dbg(pslotinfo, "pwr = 0x%x.\n", ++ gk_sd_readb((unsigned int)pinfo->regbase + SD_PWR_OFFSET)); ++ ++} ++ ++static void gk_sd_set_bus(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ struct gk_sd_controller_info *pinfo; ++ u8 hostr = 0; ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ hostr = gk_sd_readb((unsigned int)pinfo->regbase + SD_HOST_OFFSET); ++ if (ios->bus_width == MMC_BUS_WIDTH_8) { ++ hostr |= SD_HOST_8BIT; ++ hostr &= ~(SD_HOST_4BIT); ++ } else if (ios->bus_width == MMC_BUS_WIDTH_4) { ++ hostr &= ~(SD_HOST_8BIT); ++ hostr |= SD_HOST_4BIT; ++ } else if (ios->bus_width == MMC_BUS_WIDTH_1) { ++ hostr &= ~(SD_HOST_8BIT); ++ hostr &= ~(SD_HOST_4BIT); ++ } else { ++ gk_sd_err(pslotinfo, "Unknown bus_width[%u], assume 1bit.\n", ++ ios->bus_width); ++ hostr &= ~(SD_HOST_8BIT); ++ hostr &= ~(SD_HOST_4BIT); ++ } ++ // Steven Yu: ++ // do not set this bit, would cause xc card rw failed. ++ hostr &= ~SD_HOST_HIGH_SPEED; ++ //hostr |= SD_HOST_HIGH_SPEED; ++ gk_sd_writeb((unsigned int)pinfo->regbase + SD_HOST_OFFSET, hostr); ++ ++ gk_sd_dbg(pslotinfo, "hostr = 0x%x.\n", hostr); ++} ++ ++static void gk_sd_check_ios(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ struct gk_sd_controller_info *pinfo; ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ if ((pinfo->controller_ios.power_mode != ios->power_mode) || ++ (pinfo->controller_ios.vdd != ios->vdd) || ++ (pslotinfo->state == GK_SD_STATE_RESET)) { ++ gk_sd_set_pwr(mmc, ios); ++ pinfo->controller_ios.power_mode = ios->power_mode; ++ pinfo->controller_ios.vdd = ios->vdd; ++ } ++ ++ if ((pinfo->controller_ios.clock != ios->clock) || ++ (pslotinfo->state == GK_SD_STATE_RESET)) { ++ gk_sd_set_clk(mmc, ios); ++ pinfo->controller_ios.clock = ios->clock; ++ } ++ ++ if ((pinfo->controller_ios.bus_width != ios->bus_width) || ++ (pinfo->controller_ios.timing != ios->timing) || ++ //(pinfo->controller_ios.ddr != ios->ddr) || ++ (pslotinfo->state == GK_SD_STATE_RESET)) { ++ gk_sd_set_bus(mmc, ios); ++ pinfo->controller_ios.bus_width = ios->bus_width; ++ pinfo->controller_ios.timing = ios->timing; ++ //pinfo->controller_ios.ddr = ios->ddr; ++ } ++ ++ if (pslotinfo->state == GK_SD_STATE_RESET) { ++ pslotinfo->state = GK_SD_STATE_IDLE; ++ } ++} ++ ++static u32 gk_sd_check_cd(struct mmc_host *mmc) ++{ ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ struct gk_sd_controller_info *pinfo; ++ int cdpin; ++ u32 valid_cd = 0; ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ if (pslotinfo->plat_info->fixed_cd == 1) { ++ valid_cd = 1; ++ } else if (pslotinfo->plat_info->fixed_cd == 0) { ++ valid_cd = 0; ++ } else { ++ ++ printk("gk_sd_check_cd\n"); ++ cdpin = gk_sd_gpio_cd_check_val(pslotinfo); ++ if (cdpin == 1) { ++ valid_cd = 1; ++ } else if (cdpin == -1) { ++ if (gk_sd_tstbitsl((unsigned int)pinfo->regbase + SD_STA_OFFSET, ++ SD_STA_CARD_INSERTED)) { ++ valid_cd = 1; ++ } ++ } ++ } ++ ++ return valid_cd; ++} ++ ++static inline void gk_sd_prepare_tmo( ++ struct gk_sd_mmc_info *pslotinfo, ++ struct mmc_data *pmmcdata) ++{ ++ struct gk_sd_controller_info *pinfo; ++#if defined(CONFIG_SD_GK_CALIB_TMO) ++ u32 actual_cycle_ns; ++ u32 desired_tmo; ++ u32 actual_tmo; ++ u32 actual_hz; ++#endif ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++#if defined(CONFIG_SD_GK_CALIB_TMO) ++ if (pinfo->pcontroller->active_clock >= HZ) { ++ actual_hz = pinfo->pcontroller->active_clock / HZ; ++ actual_cycle_ns = ((1000000000 / HZ) / actual_hz); ++ desired_tmo = pmmcdata->timeout_ns / actual_cycle_ns; ++ desired_tmo += pmmcdata->timeout_clks; ++ for (pslotinfo->tmo = 0; pslotinfo->tmo < 0xe; ++ pslotinfo->tmo++) { ++ actual_tmo = (0x1 << (13 + pslotinfo->tmo)); ++ if (actual_tmo >= desired_tmo) ++ break; ++ } ++ pslotinfo->wait_tmo = (actual_tmo + actual_hz - 1); ++ pslotinfo->wait_tmo /= actual_hz; ++ } else { ++ pslotinfo->tmo = CONFIG_SD_GK_TIMEOUT_VAL; ++ pslotinfo->wait_tmo = pinfo->pcontroller->wait_tmo; ++ } ++ if ((pslotinfo->wait_tmo > 0) && (pslotinfo->wait_tmo < ++ CONFIG_SD_GK_MAX_TIMEOUT)) { ++ pslotinfo->sta_counter = CONFIG_SD_GK_MAX_TIMEOUT; ++ pslotinfo->sta_counter /= pslotinfo->wait_tmo; ++ } else { ++ pslotinfo->sta_counter = 1; ++ pslotinfo->wait_tmo = (1 * HZ); ++ } ++#else ++ pslotinfo->tmo = CONFIG_SD_GK_TIMEOUT_VAL; ++ pslotinfo->wait_tmo = pinfo->pcontroller->wait_tmo; ++ if ((pslotinfo->wait_tmo > 0) && (pslotinfo->wait_tmo < ++ CONFIG_SD_GK_MAX_TIMEOUT)) { ++ pslotinfo->sta_counter = CONFIG_SD_GK_MAX_TIMEOUT; ++ pslotinfo->sta_counter /= pslotinfo->wait_tmo; ++ } else { ++ pslotinfo->sta_counter = 1; ++ pslotinfo->wait_tmo = (1 * HZ); ++ } ++#endif ++ gk_sd_dbg(pslotinfo, "timeout_ns = %u, timeout_clks = %u @ %uHz, " ++ "wait_tmo = %u, tmo = %u, sta_counter = %u.\n", ++ pmmcdata->timeout_ns, pmmcdata->timeout_clks, ++ pinfo->pcontroller->active_clock, pslotinfo->wait_tmo, ++ pslotinfo->tmo, pslotinfo->sta_counter); ++} ++ ++static inline void gk_sd_pre_cmd( ++ struct gk_sd_mmc_info *pslotinfo) ++{ ++ struct gk_sd_controller_info *pinfo; ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ pslotinfo->state = GK_SD_STATE_CMD; ++ pslotinfo->sg_len = 0; ++ pslotinfo->sg = NULL; ++ pslotinfo->blk_sz = 0; ++ pslotinfo->blk_cnt = 0; ++ pslotinfo->arg_reg = 0; ++ pslotinfo->cmd_reg = 0; ++ pslotinfo->sta_reg = 0; ++ pslotinfo->tmo = CONFIG_SD_GK_TIMEOUT_VAL; ++ pslotinfo->wait_tmo = (1 * HZ); ++ pslotinfo->xfr_reg = 0; ++ pslotinfo->dma_address = 0; ++ pslotinfo->dma_size = 0; ++ ++ if (pslotinfo->mrq->stop) { ++ //if (likely(pslotinfo->mrq->stop->opcode == MMC_STOP_TRANSMISSION)) { ++ if ((pslotinfo->mrq->stop->opcode == MMC_STOP_TRANSMISSION)) { ++ pslotinfo->xfr_reg = SD_XFR_AC12_EN; ++ } else { ++ gk_sd_err(pslotinfo, "%s strange stop cmd%u\n", ++ __func__, pslotinfo->mrq->stop->opcode); ++ } ++ } ++ ++ if (!(pslotinfo->mrq->cmd->flags & MMC_RSP_PRESENT)) ++ pslotinfo->cmd_reg = SD_CMD_RSP_NONE; ++ else if (pslotinfo->mrq->cmd->flags & MMC_RSP_136) ++ pslotinfo->cmd_reg = SD_CMD_RSP_136; ++ else if (pslotinfo->mrq->cmd->flags & MMC_RSP_BUSY) ++ pslotinfo->cmd_reg = SD_CMD_RSP_48BUSY; ++ else ++ pslotinfo->cmd_reg = SD_CMD_RSP_48; ++ if (pslotinfo->mrq->cmd->flags & MMC_RSP_CRC) ++ { ++ //printk("add crc check...\n"); ++ pslotinfo->cmd_reg |= SD_CMD_CHKCRC; ++ } ++ ++ if (pslotinfo->mrq->cmd->flags & MMC_RSP_OPCODE) ++ pslotinfo->cmd_reg |= SD_CMD_CHKIDX; ++ ++ //printk("## cmd = %d ##\n", pslotinfo->mrq->cmd->opcode); ++ pslotinfo->cmd_reg |= SD_CMD_IDX(pslotinfo->mrq->cmd->opcode); ++ pslotinfo->arg_reg = pslotinfo->mrq->cmd->arg; ++ ++//printk(" cmd_reg = 0x%x arg_reg = 0x%x \n", pslotinfo->cmd_reg, pslotinfo->arg_reg); ++ ++ if (pslotinfo->mrq->data) { ++ pslotinfo->state = GK_SD_STATE_DATA; ++ gk_sd_prepare_tmo(pslotinfo, pslotinfo->mrq->data); ++ pslotinfo->blk_sz = (pslotinfo->mrq->data->blksz & 0xFFF); ++ pslotinfo->dma_size = pslotinfo->mrq->data->blksz * pslotinfo->mrq->data->blocks; ++ //printk("blk size = %d dma_size = %d \n", pslotinfo->blk_sz, pslotinfo->dma_size); ++ ++ pslotinfo->sg_len = pslotinfo->mrq->data->sg_len; ++ pslotinfo->sg = pslotinfo->mrq->data->sg; ++ pslotinfo->xfr_reg |= SD_XFR_DMA_EN; ++ pslotinfo->cmd_reg |= SD_CMD_DATA; ++ pslotinfo->blk_cnt = pslotinfo->mrq->data->blocks; ++ if (pslotinfo->blk_cnt > 1) { ++ pslotinfo->xfr_reg |= SD_XFR_MUL_SEL; ++ pslotinfo->xfr_reg |= SD_XFR_BLKCNT_EN; ++ } ++ if (pslotinfo->mrq->data->flags & MMC_DATA_STREAM) { ++ pslotinfo->xfr_reg |= SD_XFR_MUL_SEL; ++ pslotinfo->xfr_reg &= ~SD_XFR_BLKCNT_EN; ++ } ++ if (pslotinfo->mrq->data->flags & MMC_DATA_WRITE) { ++ pslotinfo->xfr_reg &= ~SD_XFR_CTH_SEL; ++ pslotinfo->sta_reg = (SD_STA_WRITE_XFR_ACTIVE | ++ SD_STA_DAT_ACTIVE); ++ pslotinfo->pre_dma = &gk_sd_pre_sg_to_dma; ++ pslotinfo->post_dma = &gk_sd_post_sg_to_dma; ++ } else { ++ pslotinfo->xfr_reg |= SD_XFR_CTH_SEL; ++ pslotinfo->sta_reg = (SD_STA_READ_XFR_ACTIVE | ++ SD_STA_DAT_ACTIVE); ++ pslotinfo->pre_dma = &gk_sd_pre_dma_to_sg; ++ pslotinfo->post_dma = &gk_sd_post_dma_to_sg; ++ } ++ //printk("-----pre dma handle----\n"); ++ pslotinfo->pre_dma(pslotinfo); ++ if (pinfo->dma_fix) { ++ pslotinfo->dma_address |= pinfo->dma_fix; ++ } ++ } ++} ++ ++static inline void gk_sd_send_cmd( ++ struct gk_sd_mmc_info *pslotinfo) ++{ ++ struct gk_sd_controller_info *pinfo; ++ u32 valid_request = 0; ++ u32 counter = 0; ++ u32 sta_reg; ++ u32 tmpreg; ++ long timeout; ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ gk_sd_request_bus(pslotinfo->mmc); ++ ++ valid_request = gk_sd_check_cd(pslotinfo->mmc); ++ //printk("send cmd = %u valid_request = %u.\n", pslotinfo->mrq->cmd->opcode, valid_request); ++ ++ if (!valid_request) { ++ pslotinfo->mrq->cmd->error = -ENOMEDIUM; ++ pslotinfo->state = GK_SD_STATE_ERR; ++ //printk("send cmd error...\n"); ++ goto gk_sd_send_cmd_exit; ++ } ++ ++ gk_sd_check_ios(pslotinfo->mmc, &pslotinfo->mmc->ios); ++ if (pslotinfo->mrq->data) { ++ while (1) { ++ sta_reg = gk_sd_readl((unsigned int)pinfo->regbase + SD_STA_OFFSET); ++ if ((sta_reg & SD_STA_CMD_INHIBIT_DAT) == 0) { ++ break; ++ } ++ counter++; ++ if (counter > CONFIG_SD_GK_WAIT_COUNTER_LIMIT) { ++ printk( ++ "Wait SD_STA_CMD_INHIBIT_DAT...\n"); ++ pslotinfo->state = GK_SD_STATE_ERR; ++ pinfo->reset_error = 1; ++ goto gk_sd_send_cmd_exit; ++ } ++ } ++ //printk("@@ write cmd arg...\n"); ++ gk_sd_writeb((unsigned int)pinfo->regbase + SD_TMO_OFFSET, pslotinfo->tmo); ++ gk_sd_writel((unsigned int)pinfo->regbase + SD_DMA_ADDR_OFFSET, ++ pslotinfo->dma_address); ++ gk_sd_writew((unsigned int)pinfo->regbase + SD_BLK_SZ_OFFSET, ++ pslotinfo->blk_sz); ++ gk_sd_writew((unsigned int)pinfo->regbase + SD_BLK_CNT_OFFSET, ++ pslotinfo->blk_cnt); ++ gk_sd_writel((unsigned int)pinfo->regbase + SD_ARG_OFFSET, pslotinfo->arg_reg); ++ gk_sd_writew((unsigned int)pinfo->regbase + SD_XFR_OFFSET, ++ pslotinfo->xfr_reg); ++ gk_sd_writew((unsigned int)pinfo->regbase + SD_CMD_OFFSET, ++ pslotinfo->cmd_reg); ++ } else { ++ while (1) { ++ sta_reg = gk_sd_readl((unsigned int)pinfo->regbase + SD_STA_OFFSET); ++ if ((sta_reg & SD_STA_CMD_INHIBIT_CMD) == 0) { ++ break; ++ } ++ counter++; ++ if (counter > CONFIG_SD_GK_WAIT_COUNTER_LIMIT) { ++ gk_sd_warn(pslotinfo, ++ "Wait SD_STA_CMD_INHIBIT_CMD...\n"); ++ pslotinfo->state = GK_SD_STATE_ERR; ++ pinfo->reset_error = 1; ++ goto gk_sd_send_cmd_exit; ++ } ++ } ++ ++ gk_sd_writel((unsigned int)pinfo->regbase + SD_ARG_OFFSET, pslotinfo->arg_reg); ++ gk_sd_writew((unsigned int)pinfo->regbase + SD_XFR_OFFSET, ++ 0x00); ++ gk_sd_writew((unsigned int)pinfo->regbase + SD_CMD_OFFSET, ++ pslotinfo->cmd_reg); ++ } ++ ++gk_sd_send_cmd_exit: ++ if (pslotinfo->state == GK_SD_STATE_CMD) { ++ timeout = wait_event_timeout(pslotinfo->wait, ++ (pslotinfo->state != GK_SD_STATE_CMD), ++ pslotinfo->wait_tmo); ++ if (pslotinfo->state == GK_SD_STATE_CMD) { ++ printk("@cmd%u %u@[%ld:%u], sta=0x%04x\n", ++ pslotinfo->mrq->cmd->opcode, ++ pslotinfo->state, timeout, pslotinfo->wait_tmo, ++ gk_sd_readl((unsigned int)pinfo->regbase + SD_STA_OFFSET)); ++ pslotinfo->mrq->cmd->error = -ETIMEDOUT; ++ } ++ } else if (pslotinfo->state == GK_SD_STATE_DATA) { ++ do { ++ timeout = wait_event_timeout(pslotinfo->wait, ++ (pslotinfo->state != GK_SD_STATE_DATA), ++ pslotinfo->wait_tmo); ++ sta_reg = gk_sd_readl((unsigned int)pinfo->regbase + SD_STA_OFFSET); ++ if ((pslotinfo->state == GK_SD_STATE_DATA) && ++ (sta_reg & pslotinfo->sta_reg)) { ++ printk("#data%u %u@[%ld:%u:%u:%u], sta=0x%04x:0x%04x\n", ++ pslotinfo->mrq->cmd->opcode, ++ pslotinfo->state, timeout, ++ pslotinfo->wait_tmo, ++ pslotinfo->mrq->data->timeout_ns, ++ pslotinfo->mrq->data->timeout_clks, ++ sta_reg, pslotinfo->sta_reg); ++ printk("#DMA %u in %u sg [0x%08x:0x%08x]\n", ++ pslotinfo->dma_size, ++ pslotinfo->sg_len, ++ pslotinfo->dma_address, ++ pslotinfo->dma_size); ++ tmpreg = gk_sd_readw((unsigned int)pinfo->regbase + ++ SD_BLK_CNT_OFFSET); ++ if (tmpreg) { ++ gk_sd_rtdbg(pslotinfo, ++ "SD_DMA_ADDR_OFFSET[0x%08X]\n", ++ gk_sd_readl((unsigned int)pinfo->regbase + ++ SD_DMA_ADDR_OFFSET)); ++ gk_sd_writel(((unsigned int)pinfo->regbase + ++ SD_DMA_ADDR_OFFSET), ++ gk_sd_readl((unsigned int)pinfo->regbase + ++ SD_DMA_ADDR_OFFSET)); ++ } else { ++ gk_sd_rtdbg(pslotinfo, ++ "SD_DATA_OFFSET[0x%08X]\n", ++ gk_sd_readl((unsigned int)pinfo->regbase + ++ SD_DATA_OFFSET)); ++ gk_sd_rtdbg(pslotinfo, ++ "SD_STA_OFFSET[0x%08X]\n", ++ gk_sd_readl((unsigned int)pinfo->regbase + ++ SD_STA_OFFSET)); ++ } ++ } else { ++ break; ++ } ++ } while (pslotinfo->sta_counter--); ++ if (pslotinfo->state == GK_SD_STATE_DATA) { ++ printk( ++ "#data%u %u@%u, sta=0x%04x:0x%04x\n", ++ pslotinfo->mrq->cmd->opcode, ++ pslotinfo->state, ++ pslotinfo->wait_tmo, ++ sta_reg, pslotinfo->sta_reg); ++ pslotinfo->mrq->data->error = -ETIMEDOUT; ++ } ++ } ++} ++ ++static inline void gk_sd_post_cmd( ++ struct gk_sd_mmc_info *pslotinfo) ++{ ++ struct gk_sd_controller_info *pinfo; ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ if (pslotinfo->state == GK_SD_STATE_IDLE) { ++ gk_sd_release_bus(pslotinfo->mmc); ++ if (pslotinfo->mrq->data) { ++ pslotinfo->post_dma(pslotinfo); ++ } ++ } else { ++#ifdef CONFIG_SD_GK_DEBUG_VERBOSE ++ u32 counter = 0; ++ ++ gk_sd_err(pslotinfo, "CMD%u retries[%u] state[%u].\n", ++ pslotinfo->mrq->cmd->opcode, ++ pslotinfo->mrq->cmd->retries, ++ pslotinfo->state); ++ for (counter = 0; counter < 0x100; counter += 4) { ++ gk_sd_err(pslotinfo, "0x%04x: 0x%08x\n", ++ counter, gk_sd_readl((unsigned int)pinfo->regbase + counter)); ++ } ++ gk_sd_show_info(pslotinfo); ++#endif ++ if (pinfo->reset_error) { ++ gk_sd_reset_all(pslotinfo->mmc); ++ } ++ gk_sd_release_bus(pslotinfo->mmc); ++ } ++} ++ ++static void gk_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) ++{ ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ ++ //if(pslotinfo->mrq && pslotinfo->mrq->cmd) ++ // printk("- %s: CMD[%u] \n", __func__, pslotinfo->mrq->cmd->opcode); ++ //printk("\n"); ++ pslotinfo->mrq = mrq; ++ //if(mrq && mrq->cmd) printk("######### mmc cmd request: CMD[%u] \n", mrq->cmd->opcode); ++ //if(mrq && mrq->data) printk("######### mmc data request: blksz=%d blocks=%d\n", mrq->data->blksz, mrq->data->blocks); ++ //if(mrq && mrq->stop) printk("######### mmc stop request: CMD[%u] \n", mrq->stop->opcode); ++ ++ gk_sd_pre_cmd(pslotinfo); ++ gk_sd_send_cmd(pslotinfo); ++ gk_sd_post_cmd(pslotinfo); ++ ++ pslotinfo->mrq = NULL; ++ mmc_request_done(mmc, mrq); ++ //printk("######### mmc request done-\n"); ++} ++ ++static void gk_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ gk_sd_request_bus(mmc); ++ gk_sd_check_ios(mmc, ios); ++ gk_sd_release_bus(mmc); ++} ++ ++static int gk_sd_get_ro(struct mmc_host *mmc) ++{ ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ struct gk_sd_controller_info *pinfo; ++ u32 wpspl; ++ ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ gk_sd_request_bus(mmc); ++ ++ if (pslotinfo->plat_info->fixed_wp < 0) { ++ if (pslotinfo->plat_info->gpio_wp.gpio_id != -1) { ++ wpspl = gk_get_gpio_input(&pslotinfo->plat_info->gpio_wp); ++ } else { ++ wpspl = gk_sd_readl((unsigned int)pinfo->regbase + SD_STA_OFFSET); ++ wpspl &= SD_STA_WPS_PL; //1 read only, 0 write ++ } ++ } else { ++ wpspl = pslotinfo->plat_info->fixed_wp; ++ } ++ ++ gk_sd_release_bus(mmc); ++ ++ gk_sd_dbg(pslotinfo, "RO[0x%x].\n", wpspl); ++ ++ return wpspl ? SD_STA_READ_ONLY : SD_STA_WRITABLE; ++} ++ ++static int gk_sd_get_cd(struct mmc_host *mmc) ++{ ++ struct gk_sd_mmc_info *pslotinfo = mmc_priv(mmc); ++ u32 cdpin; ++ ++ gk_sd_request_bus(mmc); ++ cdpin = gk_sd_check_cd(mmc); ++ gk_sd_release_bus(mmc); ++ ++ gk_sd_dbg(pslotinfo, "CD[%u].\n", cdpin); ++ return cdpin ? 1 : 0; ++} ++ ++static void gk_sd_enable_sdio_irq(struct mmc_host *mmc, int enable) ++{ ++ if (enable) ++ gk_sd_enable_int(mmc, SD_NISEN_CARD); ++ else ++ gk_sd_disable_int(mmc, SD_NISEN_CARD); ++} ++ ++static const struct mmc_host_ops gk_sd_host_ops = { ++ .request = gk_sd_request, ++ .set_ios = gk_sd_ios, ++ .get_ro = gk_sd_get_ro, ++ .get_cd = gk_sd_get_cd, ++ .enable_sdio_irq = gk_sd_enable_sdio_irq, ++}; ++ ++static int gk_sd_system_event(struct notifier_block *nb, ++ unsigned long val, void *data) ++{ ++ int retval = NOTIFY_OK; ++ struct gk_sd_mmc_info *pslotinfo; ++ struct gk_sd_controller_info *pinfo; ++ ++ pslotinfo = container_of(nb, struct gk_sd_mmc_info, ++ system_event); ++ pinfo = (struct gk_sd_controller_info *)pslotinfo->pinfo; ++ ++ switch (val) { ++ case GK_EVENT_PRE_CPUFREQ: ++ pr_debug("%s[%u]: Pre Change\n", __func__, pslotinfo->slot_id); ++ down(&pslotinfo->system_event_sem); ++ break; ++ ++ case GK_EVENT_POST_CPUFREQ: ++ pr_debug("%s[%u]: Post Change\n", __func__, pslotinfo->slot_id); ++ gk_sd_set_clk(pslotinfo->mmc, &pinfo->controller_ios); ++ up(&pslotinfo->system_event_sem); ++ break; ++ ++ default: ++ break; ++ } ++ ++ return retval; ++} ++ ++/* ==========================================================================*/ ++static int __devinit gk_sd_probe(struct platform_device *pdev) ++{ ++ int retval = 0; ++ struct gk_sd_controller_info *pinfo; ++ struct gk_sd_mmc_info *pslotinfo = NULL; ++ struct resource *irq; ++ struct resource *mem; ++ struct mmc_host *mmc; ++ u32 hc_cap = 0; ++ u32 i; ++ u32 clock_min; ++ u32 hc_timeout_clk = 0; ++ ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (mem == NULL) { ++ dev_err(&pdev->dev, "Get SD/MMC mem resource failed!\n"); ++ retval = -ENXIO; ++ goto gk_sd_probe_na; ++ } ++ ++ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ if (irq == NULL) { ++ dev_err(&pdev->dev, "Get SD/MMC irq resource failed!\n"); ++ retval = -ENXIO; ++ goto gk_sd_probe_na; ++ } ++ dev_dbg(&pdev->dev, "sdio get irq: %d \n", irq->start); ++ ++ pinfo = kzalloc(sizeof(struct gk_sd_controller_info), ++ GFP_KERNEL); ++ if (pinfo == NULL) { ++ dev_err(&pdev->dev, "Out of memory!\n"); ++ retval = -ENOMEM; ++ goto gk_sd_probe_na; ++ } ++ pinfo->regbase = (unsigned char __iomem *)mem->start; ++ //printk("regbase = 0x%x \n", pinfo->regbase); ++ pinfo->dev = &pdev->dev; ++ pinfo->irq = irq->start; ++ pinfo->pcontroller = (struct gk_sd_controller *)pdev->dev.platform_data; ++ if ((pinfo->pcontroller == NULL) || ++ (pinfo->pcontroller->get_pll == NULL) || ++ (pinfo->pcontroller->set_pll == NULL)) { ++ dev_err(&pdev->dev, "Need SD/MMC controller info!\n"); ++ retval = -EPERM; ++ goto gk_sd_probe_free_pinfo; ++ } ++ ++ pinfo->dma_fix = pinfo->pcontroller->dma_fix; ++ if (pinfo->pcontroller->wait_tmo < CONFIG_SD_GK_WAIT_TIMEOUT) { ++ dev_notice(&pdev->dev, "Change wait timeout from %u to %u.\n", ++ pinfo->pcontroller->wait_tmo, ++ CONFIG_SD_GK_WAIT_TIMEOUT); ++ pinfo->pcontroller->wait_tmo = ++ CONFIG_SD_GK_WAIT_TIMEOUT; ++ } ++ ++ pinfo->pcontroller->set_pll(pinfo->pcontroller->max_clock ? ++ pinfo->pcontroller->max_clock : ++ CONFIG_SD_GK_DEFAULT_CLOCK); ++ ++ pinfo->clk_limit = pinfo->pcontroller->get_pll(); ++ clock_min = pinfo->clk_limit >> 8; ++ if (pinfo->clk_limit < clock_min) { ++ pinfo->clk_limit = clock_min; ++ dev_err(&pdev->dev, "Wrong clk_limit %uHz vs %uHz!\n", ++ pinfo->clk_limit, clock_min); ++ retval = -EPERM; ++ goto gk_sd_probe_free_pinfo; ++ } ++ if (pinfo->pcontroller->max_clock != pinfo->clk_limit) { ++ pinfo->pcontroller->max_clock = pinfo->clk_limit; ++ } ++ pinfo->max_blk_sz = gk_sd_dma_mask_to_size( ++ pinfo->pcontroller->max_blk_mask); ++ pinfo->buf_cache = kmem_cache_create(dev_name(&pdev->dev), ++ pinfo->max_blk_sz, pinfo->max_blk_sz, 0, NULL); ++ if (!pinfo->buf_cache) { ++ dev_err(&pdev->dev, "Can't alloc DMA Cache"); ++ retval = -ENOMEM; ++ goto gk_sd_probe_free_pinfo; ++ } ++ ++ dev_dbg(&pdev->dev, "## max blk sz = %d \n", pinfo->max_blk_sz); ++ ++ for (i = 0; i < pinfo->pcontroller->num_slots; i++) { ++ mmc = mmc_alloc_host(sizeof(struct gk_sd_mmc_info), &pdev->dev); ++ if (!mmc) { ++ dev_err(&pdev->dev, "Failed to allocate mmc host" ++ " for slot%u!\n", i); ++ retval = -ENOMEM; ++ goto gk_sd_probe_free_host; ++ } ++ dev_dbg(&pdev->dev, "mmc_alloc_host ok...\n"); ++ mmc->ops = &gk_sd_host_ops; ++ ++ pinfo->pslotinfo[i] = pslotinfo = mmc_priv(mmc); ++ pslotinfo->mmc = mmc; ++ init_waitqueue_head(&pslotinfo->wait); ++ pslotinfo->state = GK_SD_STATE_ERR; ++ pslotinfo->plat_info = &(pinfo->pcontroller->slot[i]); ++ if ((pslotinfo->plat_info == NULL) || ++ (pslotinfo->plat_info->check_owner == NULL) || ++ (pslotinfo->plat_info->set_int == NULL)) { ++ dev_err(&pdev->dev, "Need SD/MMC slot info!\n"); ++ retval = -EPERM; ++ goto gk_sd_probe_free_host; ++ } ++ pslotinfo->slot_id = i; ++ pslotinfo->pinfo = pinfo; ++ sema_init(&pslotinfo->system_event_sem, 1); ++ ++ gk_sd_request_bus(mmc); ++ ++ gk_sd_reset_all(mmc); ++ //GD_SDIO_Rest(); ++ ++ hc_cap = gk_sd_readl((unsigned int)pinfo->regbase + SD_CAP_OFFSET); ++ hc_timeout_clk = SD_CAP_TOCLK_FREQ(hc_cap); ++ if (hc_cap & SD_CAP_TOCLK_MHZ) { ++ hc_timeout_clk *= 1000; ++ } ++ dev_dbg(&pdev->dev, "## Timeout Clock Frequency: %uKHz.\n", hc_timeout_clk); ++ ++ mmc->f_min = clock_min; ++ mmc->f_max = pinfo->clk_limit; ++ dev_dbg(&pdev->dev, "## SD Clock: base[%uMHz], min[%uHz], max[%uHz].\n", ++ SD_CAP_BASE_FREQ(hc_cap), ++ mmc->f_min, ++ mmc->f_max); ++ ++ if (hc_cap & SD_CAP_MAX_2KB_BLK) ++ mmc->max_blk_size = 2048; ++ else if (hc_cap & SD_CAP_MAX_1KB_BLK) ++ mmc->max_blk_size = 1024; ++ else if (hc_cap & SD_CAP_MAX_512B_BLK) ++ mmc->max_blk_size = 512; ++ ++ //mmc->max_blk_size = 512; ++ dev_dbg(&pdev->dev, "## SD max_blk_size: %u.\n", mmc->max_blk_size); ++ ++ mmc->caps = pslotinfo->plat_info->default_caps; ++ if (pinfo->clk_limit > 25000000) { ++ mmc->caps |= MMC_CAP_SD_HIGHSPEED; ++ mmc->caps |= MMC_CAP_MMC_HIGHSPEED; ++ } ++ if (hc_cap & SD_CAP_DMA) { ++ dev_dbg(&pdev->dev, "HW support DMA!\n"); ++ } else { ++ dev_dbg(&pdev->dev, "HW do not support DMA!\n"); ++ retval = -ENODEV; ++ goto gk_sd_probe_free_host; ++ } ++ if (hc_cap & SD_CAP_SUS_RES) { ++ dev_dbg(&pdev->dev, "HW support Suspend/Resume!\n"); ++ } else { ++ dev_dbg(&pdev->dev, "HW do not support Suspend/Resume!\n"); ++ } ++ ++ mmc->ocr_avail = 0; ++ if (hc_cap & SD_CAP_VOL_3_3V) { ++ mmc->ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34; ++ } ++ if (mmc->ocr_avail == 0) { ++ dev_dbg(&pdev->dev, "Hardware report wrong voltages[0x%x].!\n", ++ hc_cap); ++ retval = -ENODEV; ++ goto gk_sd_probe_free_host; ++ } ++ ++ if (hc_cap & SD_CAP_INTMODE) { ++ dev_dbg(&pdev->dev, "HW support Interrupt mode!\n"); ++ } else { ++ dev_dbg(&pdev->dev, "HW do not support Interrupt mode!\n"); ++ retval = -ENODEV; ++ goto gk_sd_probe_free_host; ++ } ++ ++ mmc->max_blk_count = 0xFFFF; ++ mmc->max_seg_size = pinfo->max_blk_sz; ++ mmc->max_segs = mmc->max_seg_size / PAGE_SIZE; ++ mmc->max_req_size = min(mmc->max_seg_size, mmc->max_blk_size * mmc->max_blk_count); ++ dev_dbg(&pdev->dev, "## max req size = %d \n", mmc->max_req_size); ++ pslotinfo->buf_vaddress = kmem_cache_alloc(pinfo->buf_cache, GFP_KERNEL); ++ if (!pslotinfo->buf_vaddress) { ++ gk_sd_err(pslotinfo, "Can't alloc DMA memory"); ++ retval = -ENOMEM; ++ goto gk_sd_probe_free_host; ++ } ++ pslotinfo->buf_paddress = dma_map_single( ++ pinfo->dev, pslotinfo->buf_vaddress, ++ mmc->max_req_size, DMA_BIDIRECTIONAL); ++ if (gk_sd_check_dma_boundary(pslotinfo, ++ pslotinfo->buf_paddress, mmc->max_req_size, ++ pinfo->max_blk_sz) == 0) { ++ dev_dbg(&pdev->dev, "DMA boundary err!\n"); ++ retval = -ENOMEM; ++ goto gk_sd_probe_free_host; ++ } ++ dev_dbg(&pdev->dev, "Slot%u use bounce buffer[" ++ "0x%p<->0x%08x]\n", pslotinfo->slot_id, ++ pslotinfo->buf_vaddress, ++ pslotinfo->buf_paddress); ++ ++ pslotinfo->plat_info->active_caps = mmc->caps; ++ dev_dbg(&pdev->dev, "SD caps: 0x%lx.\n", mmc->caps); ++ dev_dbg(&pdev->dev, "SD ocr: 0x%x.\n", mmc->ocr_avail); ++ dev_notice(&pdev->dev, "Slot%u req_size=0x%08X, " ++ "segs=%u, seg_size=0x%08X\n", ++ pslotinfo->slot_id, mmc->max_req_size, ++ mmc->max_segs, mmc->max_seg_size); ++/* ++ if (pslotinfo->plat_info->ext_power.gpio_id != -1) { ++ retval = gpio_request( ++ pslotinfo->plat_info->ext_power.gpio_id, ++ pdev->name); ++ if (retval < 0) { ++ gk_sd_err(pslotinfo, "Can't get Power GPIO%d\n", ++ pslotinfo->plat_info->ext_power.gpio_id); ++ pslotinfo->plat_info->ext_power.gpio_id = -1; ++ } ++ } ++ ++ if (pslotinfo->plat_info->ext_reset.gpio_id != -1) { ++ retval = gpio_request( ++ pslotinfo->plat_info->ext_reset.gpio_id, ++ pdev->name); ++ if (retval < 0) { ++ gk_sd_err(pslotinfo, "Can't get Reset GPIO%d\n", ++ pslotinfo->plat_info->ext_reset.gpio_id); ++ pslotinfo->plat_info->ext_reset.gpio_id = -1; ++ } ++ } ++ ++ if (pslotinfo->plat_info->gpio_wp.gpio_id != -1) { ++ retval = gpio_request( ++ pslotinfo->plat_info->gpio_wp.gpio_id, ++ pdev->name); ++ if (retval < 0) { ++ gk_sd_err(pslotinfo, "Can't get WP GPIO%d\n", ++ pslotinfo->plat_info->gpio_wp.gpio_id); ++ pslotinfo->plat_info->gpio_wp.gpio_id = -1; ++ } ++ } ++*/ ++ gk_sd_release_bus(mmc); ++ } ++ ++ retval = request_irq(pinfo->irq, gk_sd_irq, ++ IRQF_SHARED | IRQF_TRIGGER_HIGH, ++ "sd_control", pinfo); ++ if (retval) { ++ dev_err(&pdev->dev, "Can't Request IRQ%u!\n", pinfo->irq); ++ goto gk_sd_probe_free_host; ++ } ++ //printk("-- request %d irq ok\n", pinfo->irq); ++ ++ for (i = 0; i < pinfo->pcontroller->num_slots; i++) { ++ pslotinfo = pinfo->pslotinfo[i]; ++ pslotinfo->system_event.notifier_call = gk_sd_system_event; ++ gk_register_event_notifier(&pslotinfo->system_event); ++ ++ //if (gk_is_valid_gpio_irq( &pslotinfo->plat_info->gpio_cd)) ++ { ++ /* louis add ++ retval = gpio_request( ++ pslotinfo->plat_info->gpio_cd.irq_gpio, ++ pdev->name); ++ if (retval < 0) { ++ gk_sd_err(pslotinfo, "Can't get CD GPIO%d\n", ++ pslotinfo->plat_info->gpio_cd.irq_gpio); ++ pslotinfo->plat_info->gpio_cd.irq_gpio = -1; ++ continue; ++ } ++ */ ++ gk_sd_gpio_cd_check_val(pslotinfo); ++ retval = request_irq( ++ pslotinfo->plat_info->gpio_cd.irq_line, ++ gk_sd_gpio_cd_irq, ++ pslotinfo->plat_info->gpio_cd.irq_type, ++ "sd_card_detect", pslotinfo); ++ if (retval) { ++ printk( ++ "Can't Request GPIO(%d) CD IRQ(%d)!\n", ++ pslotinfo->plat_info->gpio_cd.irq_gpio, ++ pslotinfo->plat_info->gpio_cd.irq_line); ++ } ++ //else printk("-- request detect irq %d ok\n", pslotinfo->plat_info->gpio_cd.irq_line); ++ } ++ } ++ ++ platform_set_drvdata(pdev, pinfo); ++ ++ for (i = 0; i < pinfo->pcontroller->num_slots; i++) { ++ pslotinfo = pinfo->pslotinfo[i]; ++ pslotinfo->plat_info->pmmc_host = pslotinfo->mmc; ++ pslotinfo->valid = 1; ++ retval = mmc_add_host(pslotinfo->mmc); ++ if (retval) { ++ gk_sd_err(pslotinfo, "Can't add mmc host!\n"); ++ } ++ } ++ ++ dev_notice(&pdev->dev, ++ "GK SD/MMC[%d] has %u slots @ %uHz, [0x%08x:0x%08x]\n", ++ pdev->id, pinfo->pcontroller->num_slots, ++ pinfo->clk_limit, hc_cap, pinfo->dma_fix); ++ retval = 0; ++ goto gk_sd_probe_na; ++ ++gk_sd_probe_free_host: ++ for (i = 0; i < pinfo->pcontroller->num_slots; i++) { ++ pslotinfo = pinfo->pslotinfo[i]; ++ if (pslotinfo->plat_info->gpio_wp.gpio_id != -1) ++ gpio_free(pslotinfo->plat_info->gpio_wp.gpio_id); ++ if (pslotinfo->plat_info->ext_power.gpio_id != -1) ++ gpio_free(pslotinfo->plat_info->ext_power.gpio_id); ++ if (pslotinfo->plat_info->ext_reset.gpio_id != -1) ++ gpio_free(pslotinfo->plat_info->ext_reset.gpio_id); ++ if (pslotinfo->buf_paddress) { ++ dma_unmap_single(pinfo->dev, pslotinfo->buf_paddress, ++ pslotinfo->mmc->max_req_size, ++ DMA_BIDIRECTIONAL); ++ pslotinfo->buf_paddress = (dma_addr_t)NULL; ++ } ++ if (pslotinfo->buf_vaddress) { ++ kmem_cache_free(pinfo->buf_cache, ++ pslotinfo->buf_vaddress); ++ pslotinfo->buf_vaddress = NULL; ++ } ++ if (pslotinfo->mmc) { ++ mmc_free_host(pslotinfo->mmc); ++ } ++ } ++ if (pinfo->buf_cache) { ++ kmem_cache_destroy(pinfo->buf_cache); ++ pinfo->buf_cache = NULL; ++ } ++ ++gk_sd_probe_free_pinfo: ++ kfree(pinfo); ++ ++gk_sd_probe_na: ++ return retval; ++} ++ ++static int __devexit gk_sd_remove(struct platform_device *pdev) ++{ ++ int retval = 0; ++ struct gk_sd_controller_info *pinfo; ++ struct gk_sd_mmc_info *pslotinfo; ++ u32 i; ++ ++ pinfo = platform_get_drvdata(pdev); ++ ++ if (pinfo) { ++ platform_set_drvdata(pdev, NULL); ++ ++ free_irq(pinfo->irq, pinfo); ++ ++ for (i = 0; i < pinfo->pcontroller->num_slots; i++) { ++ pslotinfo = pinfo->pslotinfo[i]; ++ pslotinfo->plat_info->pmmc_host = NULL; ++ gk_unregister_event_notifier( ++ &pslotinfo->system_event); ++ ++ free_irq(pslotinfo->plat_info->gpio_cd.irq_line, pslotinfo); ++ gpio_free(pslotinfo->plat_info->gpio_cd.irq_gpio); ++ ++ if (pslotinfo->mmc) { ++ mmc_remove_host(pslotinfo->mmc); ++ } ++ } ++ ++ for (i = 0; i < pinfo->pcontroller->num_slots; i++) { ++ pslotinfo = pinfo->pslotinfo[i]; ++ if (pslotinfo->plat_info->ext_power.gpio_id != -1) { ++ gpio_free( ++ pslotinfo->plat_info->ext_power.gpio_id); ++ } ++ if (pslotinfo->plat_info->ext_reset.gpio_id != -1) { ++ gpio_free( ++ pslotinfo->plat_info->ext_reset.gpio_id); ++ } ++ if (pslotinfo->plat_info->gpio_wp.gpio_id != -1) { ++ gpio_free( ++ pslotinfo->plat_info->gpio_wp.gpio_id); ++ } ++ if (pslotinfo->buf_paddress) { ++ dma_unmap_single(pinfo->dev, ++ pslotinfo->buf_paddress, ++ pslotinfo->mmc->max_req_size, ++ DMA_BIDIRECTIONAL); ++ pslotinfo->buf_paddress = (dma_addr_t)NULL; ++ } ++ if (pslotinfo->buf_vaddress) { ++ kmem_cache_free(pinfo->buf_cache, ++ pslotinfo->buf_vaddress); ++ pslotinfo->buf_vaddress = NULL; ++ } ++ if (pslotinfo->mmc) { ++ mmc_free_host(pslotinfo->mmc); ++ } ++ } ++ if (pinfo->buf_cache) { ++ kmem_cache_destroy(pinfo->buf_cache); ++ pinfo->buf_cache = NULL; ++ } ++ kfree(pinfo); ++ } ++ ++ dev_notice(&pdev->dev, ++ "Remove GK Media Processor SD/MMC Host Controller.\n"); ++ ++ return retval; ++} ++ ++#ifdef CONFIG_PM ++static int gk_sd_suspend(struct platform_device *pdev, ++ pm_message_t state) ++{ ++ int retval = 0; ++ struct gk_sd_controller_info *pinfo; ++ struct gk_sd_mmc_info *pslotinfo; ++ u32 i; ++ ++ pinfo = platform_get_drvdata(pdev); ++ ++ for (i = 0; i < pinfo->pcontroller->num_slots; i++) { ++ pslotinfo = pinfo->pslotinfo[i]; ++ if (pslotinfo->mmc) { ++ retval = mmc_suspend_host(pslotinfo->mmc); ++ if (retval) { ++ gk_sd_err(pslotinfo, ++ "mmc_suspend_host[%d] failed[%d]!\n", ++ i, retval); ++ } ++ } ++ } ++ ++ disable_irq(pinfo->irq); ++ for (i = 0; i < pinfo->pcontroller->num_slots; i++) { ++ pslotinfo = pinfo->pslotinfo[i]; ++ disable_irq(pslotinfo->plat_info->gpio_cd.irq_line); ++ } ++ ++ dev_dbg(&pdev->dev, "%s exit with %d @ %d\n", ++ __func__, retval, state.event); ++ return retval; ++} ++ ++static int gk_sd_resume(struct platform_device *pdev) ++{ ++ int retval = 0; ++ struct gk_sd_controller_info *pinfo; ++ struct gk_sd_mmc_info *pslotinfo; ++ u32 i; ++ ++ pinfo = platform_get_drvdata(pdev); ++ pinfo->pcontroller->set_pll(pinfo->clk_limit); ++ for (i = 0; i < pinfo->pcontroller->num_slots; i++) { ++ pslotinfo = pinfo->pslotinfo[i]; ++ gk_sd_reset_all(pslotinfo->mmc); ++ enable_irq(pslotinfo->plat_info->gpio_cd.irq_line); ++ } ++ enable_irq(pinfo->irq); ++ ++ for (i = 0; i < pinfo->pcontroller->num_slots; i++) { ++ pslotinfo = pinfo->pslotinfo[i]; ++ if (pslotinfo->mmc) { ++ retval = mmc_resume_host(pslotinfo->mmc); ++ if (retval) { ++ gk_sd_err(pslotinfo, ++ "mmc_resume_host[%d] failed[%d]!\n", ++ i, retval); ++ } ++ } ++ } ++ ++ dev_dbg(&pdev->dev, "%s exit with %d\n", __func__, retval); ++ ++ return retval; ++} ++#endif ++ ++static struct platform_driver gk_sd_driver = { ++ .probe = gk_sd_probe, ++ .remove = __devexit_p(gk_sd_remove), ++#ifdef CONFIG_PM ++ .suspend = gk_sd_suspend, ++ .resume = gk_sd_resume, ++#endif ++ .driver = { ++ .name = "gk-sd", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init gk_sd_init(void) ++{ ++ int retval = 0; ++ ++ retval = platform_driver_register(&gk_sd_driver); ++ if (retval) { ++ printk(KERN_ERR "%s: Register failed %d!\n", ++ __func__, retval); ++ } ++ ++ return retval; ++} ++ ++static void __exit gk_sd_exit(void) ++{ ++ platform_driver_unregister(&gk_sd_driver); ++} ++ ++fs_initcall(gk_sd_init); ++module_exit(gk_sd_exit); ++ ++MODULE_DESCRIPTION("GOKE Media Processor SD/MMC Host Controller"); ++MODULE_AUTHOR("Goke Microelectronics Inc."); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c +index 273306c6..7dc3a267 100644 +--- a/drivers/mmc/host/mmc_spi.c ++++ b/drivers/mmc/host/mmc_spi.c +@@ -190,6 +190,8 @@ mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len) + host->data_dma, sizeof(*host->data), + DMA_FROM_DEVICE); + ++ spi_message_add_tail(&host->status, &host->readback); ++ + return status; + } + +@@ -955,12 +957,22 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, + t->len); + + if (direction == DMA_TO_DEVICE) ++ { + status = mmc_spi_writeblock(host, t, timeout); ++ if(length) ++ spi_message_add_tail(&host->token, &host->m); ++ } + else + status = mmc_spi_readblock(host, t, timeout); + if (status < 0) + break; +- ++ if(length) ++ { ++ spi_message_add_tail(t, &host->m); ++ spi_message_add_tail(&host->crc, &host->m); ++ if (direction == DMA_TO_DEVICE) ++ spi_message_add_tail(&host->early_status, &host->m); ++ } + data->bytes_xfered += t->len; + length -= t->len; + +diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig +index 27143e04..a5d975c2 100644 +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -322,6 +322,8 @@ source "drivers/mtd/devices/Kconfig" + + source "drivers/mtd/nand/Kconfig" + ++source "drivers/mtd/spinand/Kconfig" ++ + source "drivers/mtd/onenand/Kconfig" + + source "drivers/mtd/lpddr/Kconfig" +diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile +index f9013542..e5ebd5b9 100644 +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -30,6 +30,6 @@ obj-$(CONFIG_MTD_SWAP) += mtdswap.o + nftl-objs := nftlcore.o nftlmount.o + inftl-objs := inftlcore.o inftlmount.o + +-obj-y += chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/ ++obj-y += chips/ lpddr/ maps/ devices/ nand/ spinand/ onenand/ tests/ + + obj-$(CONFIG_MTD_UBI) += ubi/ +diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig +index 4cdb2af7..d82a37df 100644 +--- a/drivers/mtd/devices/Kconfig ++++ b/drivers/mtd/devices/Kconfig +@@ -96,6 +96,37 @@ config MTD_M25P80 + if you want to specify device partitioning or to use a device which + doesn't support the JEDEC ID instruction. + ++config MTD_SFLASH_GOKE ++ tristate "Support most Serial Flash on goke ipc (S25FL128P,MX25L12845E...)" ++ depends on EXPERIMENTAL ++ depends on GK_SFLASH ++ ++if MTD_SFLASH_GOKE ++choice SFLASH_WR_MODE ++ default SFLASH_W_1X_R_1X_MODE ++ prompt 'SFLASH read write mode' ++ help ++ SFLASH read write mode. ++config SFLASH_1X_R_1X_W_MODE ++ bool 'USE 1X mode read and 1X mode write' ++ depends on MTD_SFLASH_GOKE ++ help ++ Enable USE 1X mode read write. ++ ++config SFLASH_4X_R_1X_W_MODE ++ bool 'USE 4X mode read and 1X mode write' ++ depends on MTD_SFLASH_GOKE ++ help ++ Enable USE 4X mode read and 1X mode write. ++ ++config SFLASH_4X_R_4X_W_MODE ++ bool 'USE 4X mode read and 4X mode write' ++ depends on MTD_SFLASH_GOKE ++ help ++ Enable USE 4X mode read and 4X mode write. ++endchoice ++endif # if INET ++ + config M25PXX_USE_FAST_READ + bool "Use FAST_READ OPCode allowing SPI CLK <= 50MHz" + depends on MTD_M25P80 +diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile +index a4dd1d82..6d6ce50f 100644 +--- a/drivers/mtd/devices/Makefile ++++ b/drivers/mtd/devices/Makefile +@@ -1,6 +1,9 @@ + # + # linux/drivers/mtd/devices/Makefile + # ++ifdef CONFIG_MTD_SFLASH_GOKE ++obj-$(CONFIG_GK_SFLASH_V1_00) += gk_sflash_v1_00.o ++endif + + obj-$(CONFIG_MTD_DOC2000) += doc2000.o + obj-$(CONFIG_MTD_DOC2001) += doc2001.o +@@ -20,4 +23,4 @@ obj-$(CONFIG_MTD_M25P80) += m25p80.o + obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o + obj-$(CONFIG_MTD_SST25L) += sst25l.o + +-CFLAGS_docg3.o += -I$(src) +\ No newline at end of file ++CFLAGS_docg3.o += -I$(src) +diff --git a/drivers/mtd/devices/gk_sflash_v1_00.c b/drivers/mtd/devices/gk_sflash_v1_00.c +new file mode 100644 +index 00000000..109d030b +--- /dev/null ++++ b/drivers/mtd/devices/gk_sflash_v1_00.c +@@ -0,0 +1,2879 @@ ++/* ++ * drivers/mtd/devices/gk_sflash_v1_00.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/*get register address*/ ++#include ++/*include write and read function*/ ++#include ++#include ++ ++#include "gk_sflash_v1_00.h" ++ ++/****************************************************************************/ ++/* ++******************************************************************************* ++** ++** gd_sflash_devices_supported is an array containing serial flash ++** geometry and information data of all supported devices, it will ++** be used during GD_SFLASH_Init() to find the connected serial ++** flash decive ++** ++******************************************************************************* ++*/ ++#define GD_SFLASH_USE_BUFFER 0 ++/* ++******************************************************************************* ++** ++** serial flash specific commands for Spansion flash devices ++** ++******************************************************************************* ++*/ ++static const goke_sflash_cmd_s sflash_commands_mx = ++{ ++ /* read_ID */ 0x9F, ++ /* write_enable */ 0x06, ++ /* write_disable */ 0x04, ++ /* read_status */ 0x05, ++ /* write_status */ 0x01, ++ /* read_data */ 0x03, ++ /* read_data_fast */ 0x0B, ++ /* erase_sector */ 0xD8, ++ /* erase_chip */ 0xC7, ++ /* program_page */ 0x02, ++ /* status_mask_wip */ 0x01, ++ /* status_mask_wel */ 0x02, ++ /* read_io2 */ 0xbb, ++ /* read_io4 */ 0xeb, ++ /* program_page2 */ 0x00, ++ /* program_page4 */ 0x38, ++ /* read_ext_addr */ 0xFF, ++ /* write_ext_addr */ 0xFF, ++ /* read_status2 */ 0xFF, ++}; ++static const goke_sflash_cmd_s sflash_commands_spansion = ++{ ++ /* read_ID */ 0x9F, ++ /* write_enable */ 0x06, ++ /* write_disable */ 0x04, ++ /* read_status */ 0x05, ++ /* write_status */ 0x01, ++ /* read_data */ 0x03, ++ /* read_data_fast */ 0x0B, ++ /* erase_sector */ 0xD8, ++ /* erase_chip */ 0xC7, ++ /* program_page */ 0x02, ++ /* status_mask_wip */ 0x01, ++ /* status_mask_wel */ 0x02, ++ /* read_io2 */ 0xbb, ++ /* read_io4 */ 0xeb, ++ /* program_page2 */ 0x00, ++ /* program_page4 */ 0x32, ++ /* read_ext_addr */ 0xFF, ++ /* write_ext_addr */ 0xFF, ++ /* read_status2 */ 0x35, ++}; ++ ++/*-------------------------------------------------------------------------------*/ ++/* serial flash specific commands for STmicro flash devices */ ++/*-------------------------------------------------------------------------------*/ ++static const goke_sflash_cmd_s sflash_commands_stmicro = ++{ ++ /* read_ID */ 0x9F, ++ /* write_enable */ 0x06, ++ /* write_disable */ 0x04, ++ /* read_status */ 0x05, ++ /* write_status */ 0x01, ++ /* read_data */ 0x03, ++ /* read_data_fast */ 0x0B, ++ /* erase_sector */ 0xD8, ++ /* erase_chip */ 0xC7, ++ /* program_page */ 0x02, ++ /* status_mask_wip */ 0x01, ++ /* status_mask_wel */ 0x02, ++ /* read_io2 */ 0x00, ++ /* read_io4 */ 0x00, ++ /* program_page2 */ 0x00, ++ /* program_page4 */ 0x00, ++ /* read_ext_addr */ 0xFF, ++ /* write_ext_addr */ 0xFF, ++ /* read_status2 */ 0xFF, ++}; ++ ++/*-------------------------------------------------------------------------------*/ ++/* serial flash specific commands for Atmel flash devices */ ++/*-------------------------------------------------------------------------------*/ ++static const goke_sflash_cmd_s sflash_commands_atmel = ++{ ++ /* read_ID */ 0x9F, ++ /* write_enable */ 0x06, ++ /* write_disable */ 0x04, ++ /* read_status */ 0x05, ++ /* write_status */ 0x01, ++ /* read_data */ 0x03, ++ /* read_data_fast */ 0x0B, ++ /* erase_sector */ 0xD8, ++ /* erase_chip */ 0xC7, ++ /* program_page */ 0x02, ++ /* status_mask_wip */ 0x01, ++ /* status_mask_wel */ 0x02, ++ /* read_io2 */ 0x00, ++ /* read_io4 */ 0x00, ++ /* program_page2 */ 0x00, ++ /* program_page4 */ 0x00, ++ /* read_ext_addr */ 0xFF, ++ /* write_ext_addr */ 0xFF, ++ /* read_status2 */ 0xFF, ++}; ++ ++/*-------------------------------------------------------------------------------*/ ++/* serial flash specific commands for NUMONYX flash devices */ ++/*-------------------------------------------------------------------------------*/ ++static const goke_sflash_cmd_s sflash_commands_numonyx = ++{ ++ /* read_ID */ 0x9F, ++ /* write_enable */ 0x06, ++ /* write_disable */ 0x04, ++ /* read_status */ 0x05, ++ /* write_status */ 0x01, ++ /* read_data */ 0x03, ++ /* read_data_fast */ 0x0B, ++ /* erase_sector */ 0xD8, ++ /* erase_chip */ 0xC7, ++ /* program_page */ 0x02, ++ /* status_mask_wip */ 0x01, ++ /* status_mask_wel */ 0x02, ++ /* read_io2 */ 0xbb, ++ /* read_io4 */ 0xeb, ++ /* program_page2 */ 0xd2, ++ /* program_page4 */ 0x12, ++ /* read_ext_addr */ 0xFF, ++ /* write_ext_addr */ 0xFF, ++ /* read_status2 */ 0xFF, ++}; ++ ++static const goke_sflash_cmd_s sflash_commands_wb = ++{ ++ /* read_ID */ 0x9F, ++ /* write_enable */ 0x06, ++ /* write_disable */ 0x04, ++ /* read_status */ 0x05, ++ /* write_status */ 0x01, ++ /* read_data */ 0x03, ++ /* read_data_fast */ 0x0B, ++ /* erase_sector */ 0xD8, ++ /* erase_chip */ 0xC7, ++ /* program_page */ 0x02, ++ /* status_mask_wip */ 0x01, ++ /* status_mask_wel */ 0x02, ++ /* read_io2 */ 0xbb, ++ /* read_io4 */ 0xeb, ++ /* program_page2 */ 0x00, ++ /* program_page4 */ 0x32, ++ /* read_ext_addr */ 0xC8, ++ /* write_ext_addr */ 0xC5, ++ /* read_status2 */ 0x35, ++}; ++ ++static const goke_sflash_cmd_s sflash_command_sst = ++{ ++ /* read_ID */ 0x9F, ++ /* write_enable */ 0x06, ++ /* write_disable */ 0x04, ++ /* read_status */ 0x05, ++ /* write_status */ 0x01, ++ /* read_data */ 0x03, ++ /* read_data_fast */ 0x0B, ++ /* erase_sector */ 0x20, ++ /* erase_chip */ 0xC7, ++ /* program_page */ 0x02, ++ /* status_mask_wip */ 0x80, ++ /* status_mask_wel */ 0x02, ++ /* read_io2 */ 0x00, ++ /* read_io4 */ 0x0B, ++ /* program_page2 */ 0x00, ++ /* program_page4 */ 0x32, ++ /* read_ext_addr */ 0xFF, ++ /* write_ext_addr */ 0xFF, ++ /* read_status2 */ 0xFF, ++}; ++static const goke_sflash_cmd_s sflash_commands_gd = ++{ ++ /* read_ID */ 0x9F, ++ /* write_enable */ 0x06, ++ /* write_disable */ 0x04, ++ /* read_status */ 0x05, ++ /* write_status */ 0x01, ++ /* read_data */ 0x03, ++ /* read_data_fast */ 0x0B, ++ /* erase_sector */ 0xD8, ++ /* erase_chip */ 0xC7, ++ /* program_page */ 0x02, ++ /* status_mask_wip */ 0x01, ++ /* status_mask_wel */ 0x02, ++ /* read_io2 */ 0xbb, ++ /* read_io4 */ 0xeb, ++ /* program_page2 */ 0x00, ++ /* program_page4 */ 0x32, ++ /* read_ext_addr */ 0xFF, ++ /* write_ext_addr */ 0xFF, ++ /* read_status2 */ 0x35, ++}; ++static const goke_sflash_cmd_s sflash_commands_eon = ++{ ++ /* read_ID */ 0x9F, ++ /* write_enable */ 0x06, ++ /* write_disable */ 0x04, ++ /* read_status */ 0x05, ++ /* write_status */ 0x01, ++ /* read_data */ 0x03, ++ /* read_data_fast */ 0x0B, ++ /* erase_sector */ 0xD8, ++ /* erase_chip */ 0xC7, ++ /* program_page */ 0x02, ++ /* status_mask_wip */ 0x01, ++ /* status_mask_wel */ 0x02, ++ /* read_io2 */ 0x00, ++ /* read_io4 */ 0x0b, ++ /* program_page2 */ 0x00, ++ /* program_page4 */ 0x02, ++ /* read_ext_addr */ 0xFF, ++ /* write_ext_addr */ 0xFF, ++ /* read_status2 */ 0xFF, ++}; ++ ++static const goke_sflash_cmd_s sflash_commands_issi = ++{ ++ /* read_ID */ 0x9F, ++ /* write_enable */ 0x06, ++ /* write_disable */ 0x04, ++ /* read_status */ 0x05, ++ /* write_status */ 0x01, ++ /* read_data */ 0x03, ++ /* read_data_fast */ 0x0B, ++ /* erase_sector */ 0xD8, ++ /* erase_chip */ 0xC7, ++ /* program_page */ 0x02, ++ /* status_mask_wip */ 0x01, ++ /* status_mask_wel */ 0x02, ++ /* read_io2 */ 0xbb, ++ /* read_io4 */ 0xeb, ++ /* program_page2 */ 0x00, ++ /* program_page4 */ 0x38, ++ /* read_ext_addr */ 0xFF, ++ /* write_ext_addr */ 0xFF, ++ /* read_status2 */ 0xFF, ++}; ++/*-------------------------------------------------------------------------------*/ ++/* serial flash geometry and information data of all supported devices */ ++/*-------------------------------------------------------------------------------*/ ++static goke_sflash_dev_s sflash_devices_supported[] = ++{ ++ ++ /* ++ ** Spansion seem to use unique sectors ++ ** with 64kBytes each, they increment the ++ ** number of sectors for bigger chips ++ */ ++ { ++ /* manufacture_ID */ 0x01, ++ /* device_ID */ 0x0212, ++ /* manufacture_name */ "Spansion", ++ /* device_name */ "S25FL004A", ++ /* device_bytes */ 524288, ++ /* sector_count */ 8, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_spansion, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x9CF5, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0x01, ++ /* device_ID */ 0x0213, ++ /* manufacture_name */ "Spansion", ++ /* device_name */ "S25FL008A", ++ /* device_bytes */ 1048576, ++ /* sector_count */ 16, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_spansion, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x9CF5, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0x01, ++ /* device_ID */ 0x0214, ++ /* manufacture_name */ "Spansion", ++ /* device_name */ "S25FL016A", ++ /* device_bytes */ 2097152, ++ /* sector_count */ 32, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_spansion, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x9CF5, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0x01, ++ /* device_ID */ 0x0215, ++ /* manufacture_name */ "Spansion", ++ /* device_name */ "S25FL032P", ++ /* device_bytes */ 4194304, ++ /* sector_count */ 64, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_spansion, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x9CF5, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0x01, ++ /* device_ID */ 0x0216, ++ /* manufacture_name */ "Spansion", ++ /* device_name */ "S25FL064A", ++ /* device_bytes */ 8388608, ++ /* sector_count */ 128, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_spansion, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x9CF5, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0x01, ++ /* device_ID */ 0x2018, ++ /* manufacture_name */ "Spansion", ++ /* device_name */ "FL128PIFL", ++ /* device_bytes */ 16777216, ++ /* sector_count */ 256, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_spansion, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x9CF5, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ ++ /* ++ ** MX seem to use unique sectors ++ ** with 64kBytes each, they increment the ++ ** number of sectors for bigger chips ++ */ ++ /* gk6105 8M SFlash */ ++ { ++ /* manufacture_ID */ 0xc2, ++ /* device_ID */ 0x2617, ++ /* manufacture_name */ "MX", ++ /* device_name */ "MX25L6455E", ++ /* device_bytes */ 8388608, ++ /* sector_count */ 128, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_mx, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x00BC, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufactureID */ 0xc2, ++ /* deviceID */ 0x2017, ++ /* manufactureName */ "MX", ++ /* deviceName */ "MX25L6465E", ++ /* deviceBytes */ 8388608, ++ /* sectorCount */ 128, ++ /* sectorBytes */ 65536, ++ /* sectorPages */ 256, ++ /* pageBytes */ 256, ++ /* commands */ &sflash_commands_mx, ++ /* ioMode */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x00BC, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0xc2, ++ /* device_ID */ 0x2018, ++ /* manufacture_name */ "MX", ++ /* device_name */ "MX25L12845", ++ /* device_bytes */ 16777216, ++ /* sector_count */ 256, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_mx, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x00BC, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0xc2, ++ /* device_ID */ 0x5e16, ++ /* manufacture_name */ "MX", ++ /* device_name */ "MX253235D", ++ /* device_bytes */ 4194304, ++ /* sector_count */ 64, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_mx, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x00BC, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0xc2, ++ /* device_ID */ 0x2415, ++ /* manufacture_name */ "MX", ++ /* device_name */ "MX25L1605D", ++ /* device_bytes */ 2097152, ++ /* sector_count */ 32, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_mx, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x00BC, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0xc2, ++ /* device_ID */ 0x2415, ++ /* manufacture_name */ "MX", ++ /* device_name */ "MX25L1635D", ++ /* device_bytes */ 2097152, ++ /* sector_count */ 32, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_mx, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x00BC, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0xc2, ++ /* device_ID */ 0x9e16, ++ /* manufacture_name */ "MX", ++ /* device_name */ "MX25L3255D", ++ /* device_bytes */ 4194304, ++ /* sector_count */ 64, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_mx, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x00BC, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0xef, ++ /* device_ID */ 0x4015, ++ /* manufacture_name */ "Winbond", ++ /* device_name */ "W25Q16BV", ++ /* device_bytes */ 2097152, ++ /* sector_count */ 32, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_wb, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x1C00, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0xef, ++ /* device_ID */ 0x4017, ++ /* manufacture_name */ "Winbond", ++ /* device_name */ "W25Q64FV", ++ /* device_bytes */ 8388608, ++ /* sector_count */ 128, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_wb, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x1C00, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufactureID */ 0xef, ++ /* deviceID */ 0x4018, ++ /* manufactureName */ "Winbond", ++ /* deviceName */ "W25Q128FV", ++ /* deviceBytes */ 16777216, ++ /* sectorCount */ 256, ++ /* sectorBytes */ 65536, ++ /* sectorPages */ 256, ++ /* pageBytes */ 256, ++ /* commands */ &sflash_commands_wb, ++ /* ioMode */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x1C00, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufactureID */ 0xef, ++ /* deviceID */ 0x4019, ++ /* manufactureName */ "Winbond", ++ /* deviceName */ "W25Q256FV", ++ /* deviceBytes */ (1024*1024*32), ++ /* sectorCount */ 512, ++ /* sectorBytes */ 65536, ++ /* sectorPages */ 256, ++ /* pageBytes */ 256, ++ /* commands */ &sflash_commands_wb, ++ /* ioMode */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x3C00, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0xbf, ++ /* device_ID */ 0x2601, ++ /* manufacture_name */ "SST", ++ /* device_name */ "SST26VF016", ++ /* device_bytes */ 2097152, ++ /* sector_count */ 512, ++ /* sector_bytes */ 4096, ++ /* sector_pages */ 16, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_command_sst, ++ /* iomode */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0xFFFF, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0x20, ++ /* device_ID */ 0xba18, ++ /* manufacture_name */ "numonyx", ++ /* device_name */ "N25Q128", ++ /* device_bytes */ 8388608*2, ++ /* sector_count */ 256, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_numonyx, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0xFFFF, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0xC8, ++ /* device_ID */ 0x4017, ++ /* manufacture_name */ "giga", ++ /* device_name */ "GD25Q64C", ++ /* device_bytes */ 8388608, ++ /* sector_count */ 128, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_gd, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0xFC79, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0xC8, ++ /* device_ID */ 0x4018, ++ /* manufacture_name */ "giga", ++ /* device_name */ "GD25Q128C", ++ /* device_bytes */ 8388608*2, ++ /* sector_count */ 256, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_gd, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0xFC79, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0x1c, ++ /* device_ID */ 0x3017, ++ /* manufacture_name */ "EON", ++ /* device_name */ "EN25Q64", ++ /* device_bytes */ 8388608, ++ /* sector_count */ 128, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_eon, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x003C, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0x1c, ++ /* device_ID */ 0x7017, ++ /* manufacture_name */ "EON", ++ /* device_name */ "ENQH64A", ++ /* device_bytes */ 8388608, ++ /* sector_count */ 128, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_eon, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x003C, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0x1c, ++ /* device_ID */ 0x7018, ++ /* manufacture_name */ "EON", ++ /* device_name */ "EN25Q128", ++ /* device_bytes */ 8388608*2, ++ /* sector_count */ 256, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_eon, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0x003C, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0x9D, ++ /* device_ID */ 0x6017, ++ /* manufacture_name */ "ISSI", ++ /* device_name */ "IC25LP064", ++ /* device_bytes */ 8388608, ++ /* sector_count */ 128, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_issi, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0xFFFF, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ }, ++ { ++ /* manufacture_ID */ 0x9D, ++ /* device_ID */ 0x6018, ++ /* manufacture_name */ "ISSI", ++ /* device_name */ "IC25LP128", ++ /* device_bytes */ 8388608*2, ++ /* sector_count */ 256, ++ /* sector_bytes */ 65536, ++ /* sector_pages */ 256, ++ /* page_bytes */ 256, ++ /* commands */ &sflash_commands_issi, ++ /* feature */ GD_SFLASH_1X_WRITE | GD_SFLASH_1X_READ, ++ /* lock_mask */ 0xFFFF, ++ /* io4_mask */ 0xFFFF, ++ /* channel */ 0x0, ++ } ++ ++}; ++static goke_sflash_feature_e old_feature = GOKE_SFLASH_FEATURE_IO1; ++static u32 sflash_write_enable(goke_sflash_dev_s *device); ++ ++struct gk_sflash ++{ ++ struct mutex lock; ++ struct mtd_info mtd; ++ goke_sflash_dev_s *device; ++}; ++static u32 sflash_cmd_bit_set(goke_sflash_command_s *sflashCmd, u32 *cmdBitSet); ++ ++static inline struct gk_sflash* mtd_to_gk_flash(struct mtd_info *mtd) ++{ ++ return container_of(mtd, struct gk_sflash, mtd); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/* register SFLASH_CE (read/write) */ ++/*----------------------------------------------------------------------------*/ ++ ++__inline static void sflash_set_ce(u32 data) ++{ ++ gk_sf_writel(REG_SFLASH_CE, data); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/* register SFLASH_Command (read/write) */ ++/*----------------------------------------------------------------------------*/ ++ ++__inline static void sflash_set_speed(u32 data) ++{ ++ gk_sf_writel(REG_SFLASH_SPEED, data); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/* register SFLASH_Command (read/write) */ ++/*----------------------------------------------------------------------------*/ ++ ++__inline static void sflash_set_command(u32 data) ++{ ++ gk_sf_writel(REG_SFLASH_COMMAND, data); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/* register SFLASH_Data (read/write) */ ++/*----------------------------------------------------------------------------*/ ++ ++__inline static void sflash_set_data(u32 data) ++{ ++ gk_flash_write(data); ++} ++ ++__inline static u32 sflash_get_data(void) ++{ ++ return gk_flash_read(); ++} ++ ++static u32 sflash_wip_done_wait(goke_sflash_dev_s *device) ++{ ++ u8 wip_mask; ++ goke_sflash_command_s sflash_cmd; ++ u32 cmd_bit_set = 0; ++ ++ cmd_bit_set |= (device->commands->read_status| ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /*dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ (1<manufacture_ID == 0xbf) ++ { ++ cmd_bit_set |= (SFLASH_CMD_MODE_4X|SFLASH_DATA_CYCLE_NUM_2); ++ } ++ else ++ { ++ cmd_bit_set |= (SFLASH_CMD_MODE_1X|SFLASH_DATA_CYCLE_NUM_0); ++ } ++ ++ sflash_cmd_bit_set(&sflash_cmd,&cmd_bit_set); ++ ++ wip_mask = device->commands->status_mask_wip; ++ while(1) ++ { ++ sflash_set_command(sflash_cmd.all); ++ ++ if((sflash_get_data() & wip_mask) != wip_mask) /*flash device ready*/ ++ { ++ return(0); ++ } ++ } ++ return 1; ++} ++ ++static u32 sflash_wel_done_wait(goke_sflash_dev_s *device) ++{ ++ u8 wel_mask; ++ goke_sflash_command_s sflash_cmd; ++ u32 cmd_bit_set = 0; ++ ++ cmd_bit_set |= (device->commands->read_status| ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /*dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ (1<manufacture_ID == 0xbf) ++ { ++ cmd_bit_set |= (SFLASH_CMD_MODE_4X|SFLASH_DATA_CYCLE_NUM_2); ++ } ++ else ++ { ++ cmd_bit_set |= (SFLASH_CMD_MODE_1X|SFLASH_DATA_CYCLE_NUM_0); ++ } ++ ++ sflash_cmd_bit_set(&sflash_cmd,&cmd_bit_set); ++ ++ wel_mask = device->commands->status_mask_wel; ++ while(1) ++ { ++ sflash_set_command(sflash_cmd.all); ++ ++ if((sflash_get_data() & wel_mask) == wel_mask) /*flash enable ready*/ ++ { ++ return(0); ++ } ++ } ++ return 1; ++} ++ ++/*! ++******************************************************************************** ++** ++** \brief unlock the serial flash ++** ++** This function unlock the serial flash. ++** ++** \return ++** - GD_ERR_INVALID_HANDLE if the given handle parameter points to 0 ++** - GD_OK if unlock operation successfully ++** ++******************************************************************************** ++*/ ++static u32 sflash_Unlock(goke_sflash_dev_s *device) ++{ ++ goke_sflash_command_s sflash_cmd; ++ u32 cmd_bit_set = 0; ++ u8 status; ++ u16 sflashData; ++ ulong CESetting = 0x38; ++ ++ CESetting = CESetting | ((ulong)device->channel << 6); ++ sflash_set_ce(CESetting); ++ ++ /* write enable the device */ ++ sflash_write_enable(device); ++ ++ cmd_bit_set = (device->commands->read_status | // command ++ SFLASH_SEND_CMD | // transfer the command ++ SFLASH_SEND_ADDR_BYTE_NUM_0 | // address num ++ SFLASH_SEND_DUMMY_BYTE_NUM_0 | // dummy cycle ++ SFLASH_RWN_READ | // read data ++ SFLASH_CMD_MODE_1X | // set the sflash cmd mode ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0 | // set the sflash adr mode ++ SFLASH_DATA_CYCLE_NUM_0 | // set the sflash data mode ++ (1<commands->read_status2 != 0xFF) ++ { ++ cmd_bit_set = (device->commands->read_status2| // command ++ SFLASH_SEND_CMD | // transfer the command ++ SFLASH_SEND_ADDR_BYTE_NUM_0 | // address num ++ SFLASH_SEND_DUMMY_BYTE_NUM_0 | // dummy cycle ++ SFLASH_RWN_READ | // read data ++ SFLASH_CMD_MODE_1X | // set the sflash cmd mode ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0 | // set the sflash adr mode ++ SFLASH_DATA_CYCLE_NUM_0 | // set the sflash data mode ++ (1<commands->write_status| // command ++ SFLASH_SEND_CMD | // transfer the command ++ SFLASH_SEND_ADDR_BYTE_NUM_0 | // address num ++ SFLASH_SEND_DUMMY_BYTE_NUM_0 | // dummy cycle ++ SFLASH_RWN_WRITE | // write data ++ SFLASH_CMD_MODE_1X | // set the sflash cmd mode ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0 | // set the sflash adr mode ++ SFLASH_DATA_CYCLE_NUM_0 | // set the sflash data mode ++ (1<commands->read_status2 != 0xFF) ++ { ++ sflash_cmd.bitc.data_num = 0x2; // transfer data ++ } ++ sflashData &= ~(device->lock_mask); ++ if(device->manufacture_ID == 0x01) ++ { ++ sflashData |= 0x0024; ++ } ++ ++ sflash_set_command(sflash_cmd.all); ++ sflash_set_data(sflashData); ++ ++ sflash_wip_done_wait(device); ++ CESetting = CESetting & (~((ulong)device->channel << 6)); ++ sflash_set_ce(CESetting); ++ return(0); ++} ++ ++static goke_sflash_dev_s* jedec_probe(struct platform_device *dev) ++{ ++ u32 sflash_data; ++ u8 manufacture_ID; ++ u16 device_ID; ++ u32 index; ++ u32 count; ++ u32 cmd_bit_set = 0; ++ u8 command,status; ++ u32 prot1; ++ u32 prot2; ++ goke_sflash_dev_s *device; ++ goke_sflash_command_s sflash_cmd; ++ u32 ce_setting = 0x0E; ++ GD_SFLASH_SPEED_MODE speed_mode = GOKE_SFLASH_FREQ_DIV2; ++ goke_sflash_channel_e channel = GOKE_SFLASH_CHANNEL_0; ++#ifdef CONFIG_OF ++ if (of_property_read_u32(dev->dev.of_node, "gofortune-semi,channel", &channel) || ++ of_property_read_u32(dev->dev.of_node, "gofortune-semi,speed", &speed_mode)) { ++ return NULL; ++ } ++#else /* CONFIG_OF */ ++ struct sflash_platform_data *platform_data = dev->dev.platform_data; ++ ++ channel = platform_data->channel; ++ speed_mode = platform_data->speed_mode; ++#endif /* !CONFIG_OF */ ++ printk(KERN_ERR "speed_mod is %d\n", speed_mode); ++ if(channel >= GOKE_SFLASH_CHANNEL_NUM) ++ { ++ return NULL; ++ } ++ ++ ce_setting = ce_setting | ((u32)channel << 6); ++ ++ sflash_set_ce(ce_setting); ++ sflash_set_speed(speed_mode); /*0 -- 1/2freq 1--1/4freq 2....4*/ ++ ++ count = sizeof(sflash_devices_supported)/sizeof(goke_sflash_dev_s); ++ ++ for(index=0; index < count; index++) ++ { ++ device = &(sflash_devices_supported[index]); ++ ++ command = device->commands->read_ID; ++ ++ sflash_set_ce(ce_setting); ++ cmd_bit_set |= (SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ (3<> 16); ++ device_ID = (u16)(sflash_data & 0x0000FFFF); ++ if((manufacture_ID == device->manufacture_ID) ++ && (device_ID == device->device_ID)) ++ { ++ if(manufacture_ID == 0xbf) /*SST sflash which support most quad IO cmd*/ ++ { ++ cmd_bit_set |= (0x38| /*enable quad command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_NOTHING| /*no read/write*/ ++ SFLASH_CMD_MODE_1X| /*set command mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ (0<> 16); ++ device_ID = (u16)(sflash_data & 0x0000FFFF); ++ ++ if(manufacture_ID != 0xbf || device_ID!= 0x2601) ++ { ++ return(NULL); ++ } ++ ++ /*ok read the protection bit for each block*/ ++ sflash_cmd.bitc.code = 0x72; /*read block protection register*/ ++ sflash_cmd.bitc.data_num = 0x6; /*transfer data number*/ ++ ++ sflash_set_command(sflash_cmd.all); ++ prot1 = sflash_get_data(); ++ prot2 = sflash_get_data(); ++ ++ /*ok write enable the device*/ ++ sflash_cmd.bitc.code = 0x06; /*enable quad command*/ ++ sflash_cmd.bitc.rwn = SFLASH_RWN_NOTHING>>15; /*3; no read/write*/ ++ sflash_cmd.bitc.data_num = 0; ++ sflash_set_command(sflash_cmd.all); ++ sflash_get_data(); ++ ++ /*program the prot bit*/ ++ sflash_cmd.bitc.code = 0x42; /*enable quad command*/ ++ sflash_cmd.bitc.rwn = SFLASH_RWN_WRITE>>15; /*write*/ ++ sflash_cmd.bitc.data_num = 6; ++ prot1 = 0x0; ++ prot2=0x0; ++ sflash_set_command(sflash_cmd.all); ++ sflash_set_data(prot1); ++ sflash_set_data(prot2); ++ ++ /*wait the program*/ ++ sflash_cmd.bitc.code = 0x05; /*read status*/ ++ sflash_cmd.bitc.rwn = SFLASH_RWN_READ>>15; /*read*/ ++ sflash_cmd.bitc.data_num = 1; ++ do ++ { ++ sflash_set_command(sflash_cmd.all); ++ status = sflash_get_data()&0xff; ++ }while((status&0x80) == 0x80); ++ ++ /*ok read the protection bit for each block*/ ++ sflash_cmd.bitc.code = 0x72; /*enable quad command*/ ++ sflash_cmd.bitc.data_num = 0x6; /*transfer data number*/ ++ sflash_set_command(sflash_cmd.all); ++ prot1 = sflash_get_data(); ++ prot2 = sflash_get_data(); ++ ++#ifdef CONFIG_SFLASH_1X_R_1X_W_MODE ++ device->feature = GD_SFLASH_1X_READ | GD_SFLASH_1X_WRITE; ++ printk("USE 1X mode read and 1X mode write\n"); ++#else ++#ifdef CONFIG_SFLASH_4X_R_1X_W_MODE ++ device->feature = GD_SFLASH_4X_READ | GD_SFLASH_1X_WRITE; ++ printk("USE 4X mode read and 1X mode write\n"); ++#endif ++#ifdef CONFIG_SFLASH_4X_R_4X_W_MODE ++ device->feature = GD_SFLASH_4X_READ | GD_SFLASH_4X_WRITE; ++ printk("USE 4X mode read and 4X mode write\n"); ++#endif ++#endif ++ } ++ else if(device->manufacture_ID == 0x0c2) ++ { ++ cmd_bit_set |= (0x2b| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ (1<commands->write_enable; /*command*/ ++ sflash_cmd.bitc.rwn = SFLASH_RWN_NOTHING>>15; /* not read & write*/ ++ sflash_cmd.bitc.data_num = 0x0; /*not transfer data*/ ++ sflash_set_command( sflash_cmd.all ); ++ sflash_get_data(); ++ sflash_cmd.bitc.code = 0x05; /*read status*/ ++ sflash_cmd.bitc.rwn = SFLASH_RWN_READ>>15; /*read*/ ++ sflash_cmd.bitc.data_num = 1; ++ do ++ { ++ sflash_set_command(sflash_cmd.all); ++ status = sflash_get_data()&0xff; ++ }while((status&0x01) == 0x01); ++ ++ sflash_cmd.bitc.code = 0x98; /*command*/ ++ sflash_cmd.bitc.rwn = SFLASH_RWN_NOTHING>>15; /* not read & write*/ ++ sflash_cmd.bitc.data_num = 0x0; /*not transfer data*/ ++ sflash_set_command( sflash_cmd.all ); ++ sflash_get_data(); ++ sflash_cmd.bitc.code = 0x05; /*read status*/ ++ sflash_cmd.bitc.rwn = SFLASH_RWN_READ>>15; /*read*/ ++ sflash_cmd.bitc.data_num = 1; ++ do ++ { ++ sflash_set_command( sflash_cmd.all ); ++ status = sflash_get_data()&0xff; ++ }while((status&0x01) == 0x01); ++ } ++ // check if the chip support 4X read mode? ++ cmd_bit_set |= (0x5A| /*command RDSFDP*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_3| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_1| /*dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ SFLASH_TRANSFER_BYTE_NUM_4| /*transfer data number*/ ++ SFLASH_HOLD_TIME_100ns ++ ); ++ ++ sflash_cmd_bit_set(&sflash_cmd,&cmd_bit_set); ++ sflash_set_command(sflash_cmd.all); ++ sflash_set_data(0x30); ++ sflash_data = sflash_get_data(); ++ ++#ifdef CONFIG_SFLASH_1X_R_1X_W_MODE ++ device->feature = GD_SFLASH_1X_READ | GD_SFLASH_1X_WRITE; ++ printk("USE 1X mode read and 1X mode write\n"); ++#else ++#ifdef CONFIG_SFLASH_4X_R_1X_W_MODE ++ device->feature = GD_SFLASH_4X_READ | GD_SFLASH_1X_WRITE; ++ printk("USE 4X mode read and 1X mode write\n"); ++#endif ++#ifdef CONFIG_SFLASH_4X_R_4X_W_MODE ++ device->feature = GD_SFLASH_4X_READ | GD_SFLASH_4X_WRITE; ++ printk("USE 4X mode read and 4X mode write\n"); ++#endif ++#endif ++ // command-address-data ++ // 0x32[bit12]=1:1-2-2 ++ // 0x32[bit13]=1:1-2-4 ++ // 0x32[bit14]=1:1-4-4 ++ // sflash_data=0x30 31 32 33 ++ if((sflash_data != 0x00000000) || (sflash_data != 0xFFFFFFFF)) ++ { ++ device->feature &= 0xFFFFFFF8; ++ if(sflash_data & 0x00006000) ++ { ++ //device->feature |= GD_SFLASH_4X_READ; ++ printk("support 4X mode read:0x%08x\n", sflash_data); ++ } ++ else ++ { ++ device->feature |= GD_SFLASH_1X_READ; ++ printk("not support 4X mode read:0x%08x\n", sflash_data); ++ } ++ } ++ } ++ else ++ { ++#ifdef CONFIG_SFLASH_1X_R_1X_W_MODE ++ device->feature = GD_SFLASH_1X_READ | GD_SFLASH_1X_WRITE; ++ printk("USE 1X mode read and 1X mode write\n"); ++#else ++#ifdef CONFIG_SFLASH_4X_R_1X_W_MODE ++ device->feature = GD_SFLASH_4X_READ | GD_SFLASH_1X_WRITE; ++ printk("USE 4X mode read and 1X mode write\n"); ++#endif ++#ifdef CONFIG_SFLASH_4X_R_4X_W_MODE ++ device->feature = GD_SFLASH_4X_READ | GD_SFLASH_4X_WRITE; ++ printk("USE 4X mode read and 4X mode write\n"); ++#endif ++#endif ++ } ++ device->channel = channel; ++ sflash_Unlock(device); ++#if GD_SFLASH_USE_BUFFER ++ device->buffer_size = device->sector_bytes; ++ device->buffer = kmalloc(device->buffer_size, GFP_KERNEL); ++ device->offset = 0xFFFFFFFF; ++ if(device->buffer) ++ { ++ return device; ++ } ++ else ++ { ++ return NULL; ++ } ++#else ++ return device; ++#endif ++ } ++ } ++ return NULL; ++} ++ ++static u32 sflash_enable_io4(goke_sflash_dev_s* device ) ++{ ++ u8 status1 = 0; ++ u8 status2 = 0; ++ u32 data = 0; ++ u32 cmd_bit_set = 0; ++ goke_sflash_command_s sflash_cmd; ++ u32 ce_setting = 0x38; ++ ++ if( !device ) ++ return(EINVAL); ++ ++ /*for IO4 mode only*/ ++ ce_setting = ce_setting | ((u32)device->channel << 6); ++ sflash_set_ce(ce_setting); ++ ++ /*after Init, the SST enter IO4 mode*/ ++ if(device->manufacture_ID == 0xbf) ++ { ++ return 0; ++ } ++ if(device->manufacture_ID == 0x1c) ++ { ++ cmd_bit_set |= (0x38| /*enable quad command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /*dummy cycle*/ ++ SFLASH_RWN_NOTHING| /*no read/write*/ ++ SFLASH_CMD_MODE_1X| /*set command mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ (0<commands->read_status| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ (1<manufacture_ID == 0xef) /*winbond read status2*/ ++ ||(device->manufacture_ID == 0x01) /*for FL064P;Tom.wang;2010-10-21*/ ++ ||(device->manufacture_ID == 0xc8)) /*for GD liujinyng2011-10-12*/ ++ { ++ sflash_cmd.bitc.code = 0x35; /*command*/ ++ sflash_set_command( sflash_cmd.all ); ++ status2 = sflash_get_data()&0xff; ++ } ++ ++ /* write enable the device */ ++ sflash_cmd.bitc.code = device->commands->write_enable; /*command*/ ++ sflash_cmd.bitc.rwn = SFLASH_RWN_NOTHING>>15; /* not read & write*/ ++ sflash_cmd.bitc.data_num = 0x0; /*not transfer data*/ ++ sflash_set_command(sflash_cmd.all); ++ sflash_get_data(); ++ ++ ++ if(device->manufacture_ID == 0xc2) ++ { ++ data = status1|0x40; ++ } ++ else if(device->manufacture_ID == 0xef) ++ { ++ data = (status1<<8)+(status2|0x2); ++ } ++ else if(device->manufacture_ID == 0x01) /*for FL064P;Tom.wang;2010-10-21*/ ++ { ++ data = (status1<<8)+(status2|0x2); ++ } ++ else if(device->manufacture_ID == 0xc8) ++ { ++ data = status2|0x2; ++ } ++ ++ /* write the status register */ ++ sflash_cmd.bitc.code = device->commands->write_status; /*command*/ ++ sflash_cmd.bitc.rwn = SFLASH_RWN_WRITE>>15; /*write*/ ++ if(device->manufacture_ID == 0xc2) ++ { ++ sflash_cmd.bitc.data_num = 0x1; /*transfer 1 byte data*/ ++ } ++ else if(device->manufacture_ID == 0xef) ++ { ++ sflash_cmd.bitc.data_num = 0x2; /*transfer 2 byte data*/ ++ } ++ else if(device->manufacture_ID == 0x01) /*for FL064P;Tom.wang;2010-10-21*/ ++ { ++ sflash_cmd.bitc.data_num = 0x2; /*transfer data*/ ++ } ++ else if(device->manufacture_ID == 0xc8) ++ { ++ sflash_cmd.bitc.code = 0x31; ++ sflash_cmd.bitc.data_num = 0x1; /*transfer data*/ ++ } ++ sflash_set_command(sflash_cmd.all); ++ sflash_set_data(data); ++ sflash_wip_done_wait(device); ++ ++ return 0; ++} ++ ++static u32 sflash_disenable_io4( goke_sflash_dev_s* device ) ++{ ++ u8 status1 = 0; ++ u8 status2 = 0; ++ u32 data = 0; ++ u32 cmd_bit_set = 0; ++ goke_sflash_command_s sflash_cmd; ++ u32 ce_setting = 0x0E; ++ ++ if( !device ) ++ return(EINVAL); ++ ++ /*fix configuration for no pull-high W/P pin*/ ++ ce_setting = ce_setting | ((u32)device->channel << 6); ++ sflash_set_ce(ce_setting); ++ ++ /*SST sflash support IO4 mode. don't exit this mode*/ ++ if(device->manufacture_ID == 0xbf) ++ { ++ return 0; ++ } ++ if(device->manufacture_ID == 0x1c) ++ { ++ cmd_bit_set |= (0xff| /*enable quad command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_NOTHING| /*no read/write*/ ++ SFLASH_CMD_MODE_4X| /*set command mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ (0<commands->read_status| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ (1<manufacture_ID == 0xef) /*winbond read status2*/ ++ ||(device->manufacture_ID == 0x01) /*for FL064P;Tom.wang;2010-10-21*/ ++ ||(device->manufacture_ID == 0xc8)) /*for GD liujinyng2011-10-12*/ ++ { ++ sflash_cmd.bitc.code = 0x35; /*command*/ ++ sflash_set_command(sflash_cmd.all); ++ status2 = sflash_get_data()&0xff; ++ } ++ ++ /* write enable the device */ ++ sflash_cmd.bitc.code = device->commands->write_enable; /*command*/ ++ sflash_cmd.bitc.rwn = SFLASH_RWN_NOTHING>>15; /* not read & write*/ ++ sflash_cmd.bitc.data_num = 0x0; /*not transfer data*/ ++ sflash_set_command( sflash_cmd.all ); ++ sflash_get_data(); ++ ++ if(device->manufacture_ID == 0xc2) ++ { ++ //Steven Yu: // clear quad ++ //for GK workaround do not enable reset mode otherwise code can not bootup ++ //data = status1&(~0x40); /*clear quad*/ ++ //write back status1 ++ data = status1; ++ } ++ else if(device->manufacture_ID == 0xef) ++ { ++ data = (status1<<8)+ (status2 & (~0x2)); /*clear the quad*/ ++ } ++ else if(device->manufacture_ID == 0x01) /*for FL064P;Tom.wang;2010-10-21*/ ++ { ++ data = (status1<<8)+ (status2 & (~0x2)); /*clear the quad*/ ++ } ++ else if(device->manufacture_ID == 0xc8) ++ { ++ data = status2 & (~0x2); ++ } ++ ++ /* write the status register */ ++ sflash_cmd.bitc.code = device->commands->write_status; /*command*/ ++ sflash_cmd.bitc.rwn = SFLASH_RWN_WRITE>>15; /*write*/ ++ if(device->manufacture_ID == 0xc2) ++ { ++ sflash_cmd.bitc.data_num = 0x1; /*transfer data*/ ++ } ++ else if(device->manufacture_ID == 0xef) ++ { ++ sflash_cmd.bitc.data_num = 0x2; /*transfer data*/ ++ } ++ else if(device->manufacture_ID == 0x01) /*for FL064P;Tom.wang;2010-10-21*/ ++ { ++ sflash_cmd.bitc.data_num = 0x2; /*transfer data*/ ++ } ++ else if(device->manufacture_ID == 0xc8) ++ { ++ sflash_cmd.bitc.code = 0x31; ++ sflash_cmd.bitc.data_num = 0x1; /*transfer data*/ ++ } ++ ++ sflash_set_command(sflash_cmd.all); ++ sflash_set_data(data); ++ sflash_wip_done_wait(device); ++ ++ return 0; ++} ++ ++static u32 sflash_write_enable(goke_sflash_dev_s *device) ++{ ++ goke_sflash_command_s sflash_cmd; ++ u32 cmd_bit_set = 0; ++ ++ cmd_bit_set = (device->commands->write_enable| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_NOTHING| /*no read/write data*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ (0<manufacture_ID == 0xbf) ++ { ++ cmd_bit_set |= SFLASH_CMD_MODE_4X; /*set the sflash cmd mode*/ ++ } ++ else ++ { ++ cmd_bit_set |= SFLASH_CMD_MODE_1X; /*set the sflash cmd mode*/ ++ } ++ ++ sflash_cmd_bit_set(&sflash_cmd,&cmd_bit_set); ++ sflash_set_command(sflash_cmd.all); ++ sflash_get_data(); ++ ++ return sflash_wel_done_wait(device); ++} ++ ++static u32 sflash_set_ext_addr(goke_sflash_dev_s* device, u8 offset) ++{ ++ u32 cmd_bit_set = 0; ++ goke_sflash_command_s sflash_cmd; ++ u8 extadd = 0; ++ ++ sflash_write_enable(device); ++ ++ cmd_bit_set = (device->commands->read_ext_addr|/*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ (2<commands->write_ext_addr|/*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_WRITE| /*write data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ (1<commands->read_data| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_3| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ SFLASH_TRANSFER_BYTE_NUM_4| /*transfer data number*/ ++ SFLASH_HOLD_TIME_100ns ++ ); ++ ++ sflash_cmd_bit_set(&sflash_cmd,&cmd_bit_set); ++ if(offset >= GD_SFLASH_16M_SIZE) ++ { ++ sflash_set_ext_addr(device, offset/GD_SFLASH_16M_SIZE); ++ } ++ sflash_set_command(sflash_cmd.all); ++ sflash_set_data(offset); ++ ++ while(data_len--) ++ { ++ *buffer++ = sflash_get_data(); ++ } ++ if(offset >= GD_SFLASH_16M_SIZE) ++ { ++ //restore to 0x00 ++ sflash_set_ext_addr(device, 0x00); ++ } ++ ++ return 0; ++} ++ ++static int sflash_read_io2( goke_sflash_dev_s* device, u32 offset, u32* buffer, u32 data_len ) ++{ ++ u32 cmd_bit_set = 0; ++ goke_sflash_command_s sflash_cmd; ++ ++ if( !device ) ++ return(EINVAL); ++ ++ if(device->manufacture_ID == 0x20) ++ { ++ cmd_bit_set |= (device->commands->read_io2| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_3| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_2| /* dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_1| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_1| /*set the sflash data mode*/ ++ SFLASH_TRANSFER_BYTE_NUM_4 /*transfer data number*/ ++ ); ++ } ++ else ++ { ++ cmd_bit_set |= (device->commands->read_io2| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_3| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_1| /* dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_1| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_1| /*set the sflash data mode*/ ++ SFLASH_TRANSFER_BYTE_NUM_4 /*transfer data number*/ ++ ); ++ } ++ ++ sflash_cmd_bit_set(&sflash_cmd,&cmd_bit_set); ++ if(offset >= GD_SFLASH_16M_SIZE) ++ { ++ sflash_set_ext_addr(device, offset/GD_SFLASH_16M_SIZE); ++ } ++ sflash_set_command(sflash_cmd.all); ++ sflash_set_data(offset); ++ ++ while(data_len--) ++ { ++ *buffer++ = sflash_get_data(); ++ } ++ if(offset >= GD_SFLASH_16M_SIZE) ++ { ++ //restore to 0x00 ++ sflash_set_ext_addr(device, 0x00); ++ } ++ ++ return 0; ++} ++ ++static int sflash_read_io4( goke_sflash_dev_s* device, u32 offset, u32* buffer, u32 data_len ) ++{ ++ u32 cmd_bit_set = 0; ++ u32 err = 0; ++ goke_sflash_command_s sflash_cmd; ++ ++ if( !device ) ++ return(EINVAL); ++ if(device->manufacture_ID == 0x20) ++ { ++ err = 0; ++ } ++ else ++ { ++ err = sflash_enable_io4(device); /*enable the IO4 mode*/ ++ } ++ if(err != 0) ++ { ++ return err; ++ } ++ ++ if(device->manufacture_ID == 0xbf) ++ { ++ cmd_bit_set |= (device->commands->read_io4| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_3| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_1| /*dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_CMD_MODE_4X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_2| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_2| /*set the sflash data mode*/ ++ SFLASH_TRANSFER_BYTE_NUM_4 /*transfer data number*/ ++ ); ++ } ++ else if(device->manufacture_ID == 0x1c) ++ { ++ cmd_bit_set |= (device->commands->read_io4| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_3| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_3| /*dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_CMD_MODE_4X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_2| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_2| /*set the sflash data mode*/ ++ SFLASH_TRANSFER_BYTE_NUM_4 /*transfer data number*/ ++ ); ++ } ++ else if(device->manufacture_ID == 0x20) ++ { ++ cmd_bit_set |= (device->commands->read_io4| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_3| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_5| /*dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_2| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_2| /*set the sflash data mode*/ ++ SFLASH_TRANSFER_BYTE_NUM_4 /*transfer data number*/ ++ ); ++ } ++ else ++ { ++ cmd_bit_set |= (device->commands->read_io4| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_3| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_3| /*dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_2| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_2| /*set the sflash data mode*/ ++ SFLASH_TRANSFER_BYTE_NUM_4 /*transfer data number*/ ++ ); ++ } ++ ++ sflash_cmd_bit_set(&sflash_cmd,&cmd_bit_set); ++ if(offset >= GD_SFLASH_16M_SIZE) ++ { ++ sflash_set_ext_addr(device, offset/GD_SFLASH_16M_SIZE); ++ } ++ sflash_set_command(sflash_cmd.all); ++ sflash_set_data(offset); ++ ++ while(data_len--) ++ { ++ *buffer++ = sflash_get_data(); ++ } ++ if(offset >= GD_SFLASH_16M_SIZE) ++ { ++ //restore to 0x00 ++ sflash_set_ext_addr(device, 0x00); ++ } ++ ++ //if(device->manufacture_ID == 0x20) ++ //{ ++ // err = sflash_wip_done_wait(device); ++ //} ++ //else ++ //{ ++ // err = sflash_disenable_io4(device); /*disable the IO4 mode*/ ++ //} ++ ++ return err; ++} ++ ++ ++static int sflash_write_io1( goke_sflash_dev_s* device, u32 offset, u32* buffer, u32 data_len ) ++{ ++ u32 count = 0; ++ u32 page_words; ++ u32 write_words = data_len; ++ u32 cmd_bit_set = 0; ++ goke_sflash_command_s sflash_cmd; ++ u32 result = 0; ++ u32 extadd = 0; ++ ++ if( !device ) ++ return(EINVAL); ++ ++ page_words = device->page_bytes / sizeof(u32); ++ ++ while(write_words--) ++ { ++ if(count == 0) ++ { ++ // >16MB ++ if((extadd == 0) && (offset >= GD_SFLASH_16M_SIZE)) ++ { ++ extadd = 1; ++ sflash_set_ext_addr(device, offset/GD_SFLASH_16M_SIZE); ++ } ++ ++ /*issue a write command sequence to prepare the device for data to be written*/ ++ cmd_bit_set |= (device->commands->write_enable| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_NOTHING| /*no read/write data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ (0<commands->program_page| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_3| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_WRITE| /*write data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ SFLASH_TRANSFER_BYTE_NUM_4| /*transfer data number*/ ++ SFLASH_HOLD_TIME_100ns ++ ); ++ ++ sflash_cmd_bit_set(&sflash_cmd,&cmd_bit_set); ++ sflash_set_command(sflash_cmd.all); ++ sflash_set_data(offset); ++ } ++ ++ sflash_set_data(*buffer++); ++ count++; ++ offset += 4; ++ ++ if((offset % device->page_bytes) == 0) ++ { ++ /* we are at a page boundary so we have to ++ wait until the WIP status to be cleared by the device*/ ++ result = sflash_wip_done_wait(device); ++ if( result != 0 ) ++ { ++ break; ++ } ++ count = 0; ++ } ++ } ++ ++ /*new added for the case that words < page_words*/ ++ //if(data_len < page_words) ++ { ++ result = sflash_wip_done_wait(device); ++ if(result != 0) ++ { ++ return(result); ++ } ++ } ++ ++ if(extadd) ++ { ++ //restore to 0x00 ++ sflash_set_ext_addr(device, 0x00); ++ } ++ cmd_bit_set |= (device->commands->read_status| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ (1<page_bytes / sizeof(u32); ++ ++ while(write_words--) ++ { ++ if(count == 0) ++ { ++ // >16MB ++ if((extadd == 0) && (offset >= GD_SFLASH_16M_SIZE)) ++ { ++ extadd = 1; ++ sflash_set_ext_addr(device, offset/GD_SFLASH_16M_SIZE); ++ } ++ /* issue a write command sequence to prepare the device for data to be written*/ ++ cmd_bit_set |= (device->commands->write_enable| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /*dummy cycle*/ ++ SFLASH_RWN_NOTHING| /*no read/write data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ (0<commands->program_page2| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_3| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /*dummy cycle*/ ++ SFLASH_RWN_WRITE| /*write data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_1| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_1| /*set the sflash data mode*/ ++ (0x1f<16MB ++ if(offset >= GD_SFLASH_16M_SIZE) ++ { ++ sflash_set_ext_addr(device, offset/GD_SFLASH_16M_SIZE); ++ } ++ sflash_cmd_bit_set(&sflash_cmd,&cmd_bit_set); ++ sflash_set_command(sflash_cmd.all); ++ sflash_set_data(offset); ++ } ++ ++ sflash_set_data(*buffer++); ++ count++; ++ offset += 4; ++ ++ if((offset % device->page_bytes ) == 0) ++ { ++ /*we are at a page boundary so we have to ++ wait until the WIP status to be cleared by the device*/ ++ result = sflash_wip_done_wait(device); ++ if(result != 0) ++ { ++ break; ++ } ++ count = 0; ++ } ++ } ++ ++ /*new added for the case that words < page_words*/ ++ //if(data_len < page_words) ++ { ++ result = sflash_wip_done_wait(device); ++ if(result != 0) ++ { ++ return(result); ++ } ++ } ++ ++ if(extadd) ++ { ++ //restore to 0x00 ++ sflash_set_ext_addr(device, 0x00); ++ } ++ cmd_bit_set |= (device->commands->read_status| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_CMD_MODE_1X| /*set the sflash cmd mode*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_1| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_1| /*set the sflash data mode*/ ++ (1<page_bytes / sizeof(u32); ++ ++ while(write_words--) ++ { ++ if(count == 0) ++ { ++ // >16MB ++ if((extadd == 0) && (offset >= GD_SFLASH_16M_SIZE)) ++ { ++ extadd = 1; ++ sflash_set_ext_addr(device, offset/GD_SFLASH_16M_SIZE); ++ } ++ //if(device->manufacture_ID != 0x20) ++ // sflash_enable_io4(device); ++ /*issue a write command sequence to prepare the device for data to be written*/ ++ cmd_bit_set |= (device->commands->write_enable| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_NOTHING| /*no read/write data*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ (0<manufacture_ID == 0xbf) ++ { ++ cmd_bit_set |= SFLASH_CMD_MODE_4X; /*set the sflash cmd mode*/ ++ } ++ else if(device->manufacture_ID == 0x1c) ++ { ++ cmd_bit_set |= SFLASH_CMD_MODE_4X; /*set the sflash cmd mode*/ ++ } ++ else ++ { ++ cmd_bit_set |= SFLASH_CMD_MODE_1X; /*set the sflash cmd mode*/ ++ } ++ sflash_cmd_bit_set(&sflash_cmd,&cmd_bit_set); ++ sflash_set_command(sflash_cmd.all); ++ sflash_get_data(); ++ ++ cmd_bit_set |= (device->commands->program_page4| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_3| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_WRITE| /*write data*/ ++ SFLASH_DATA_CYCLE_NUM_2| /*set the sflash data mode*/ ++ (0x1f<manufacture_ID == 0xbf) ++ { ++ cmd_bit_set |= SFLASH_CMD_MODE_4X; /*set the sflash cmd mode*/ ++ } ++ else if (device->manufacture_ID == 0x1c) ++ { ++ cmd_bit_set |= SFLASH_CMD_MODE_4X; ++ } ++ else ++ { ++ cmd_bit_set |= SFLASH_CMD_MODE_1X; /*set the sflash cmd mode*/ ++ } ++ ++ ++ if(device->manufacture_ID == 0xc2) ++ { ++ cmd_bit_set |= SFLASH_ADDR_DUMMY_CYCLE_NUM_2; /*set the sflash adr mode*/ ++ } ++ else if(device->manufacture_ID == 0xbf) ++ { ++ cmd_bit_set |= SFLASH_ADDR_DUMMY_CYCLE_NUM_2; /*set the sflash adr mode*/ ++ } ++ else if(device->manufacture_ID == 0xef) ++ { ++ cmd_bit_set |= SFLASH_ADDR_DUMMY_CYCLE_NUM_0; /*set the sflash adr mode*/ ++ } ++ else if(device->manufacture_ID == 0x01) /*for FL064P;Tom.wang;2010-10-21*/ ++ { ++ cmd_bit_set |= SFLASH_ADDR_DUMMY_CYCLE_NUM_0; /*set the sflash adr mode*/ ++ } ++ else if(device->manufacture_ID == 0x20) ++ { ++ cmd_bit_set |= SFLASH_ADDR_DUMMY_CYCLE_NUM_2; ++ } ++ else if(device->manufacture_ID == 0xc8) ++ { ++ cmd_bit_set |= SFLASH_ADDR_DUMMY_CYCLE_NUM_0; ++ } ++ else if(device->manufacture_ID == 0x1c) ++ { ++ cmd_bit_set |= SFLASH_ADDR_DUMMY_CYCLE_NUM_2; ++ } ++ sflash_cmd_bit_set(&sflash_cmd,&cmd_bit_set); ++ sflash_set_command(sflash_cmd.all); ++ sflash_set_data(offset); ++ } ++ ++ sflash_set_data(*buffer++); ++ count++; ++ offset += 4; ++ ++ if((offset % device->page_bytes) == 0) ++ { ++ //if(device->manufacture_ID != 0x20) ++ //sflash_disenable_io4(device); ++ /* we are at a page boundary so we have to ++ wait until the WIP status to be cleared by the device*/ ++ result = sflash_wip_done_wait(device); ++ if(result != 0) ++ { ++ break; ++ } ++ count = 0; ++ } ++ } ++ ++ //if(device->manufacture_ID != 0x20) ++ //{ ++ // sflash_disenable_io4(device); ++ //} ++ ++ /*new added for the case that words < page_words*/ ++ //if(data_len < page_words) ++ { ++ result = sflash_wip_done_wait(device); ++ if(result != 0) ++ { ++ return(result); ++ } ++ } ++ if(extadd) ++ { ++ //restore to 0x00 ++ sflash_set_ext_addr(device, 0x00); ++ } ++ cmd_bit_set |= (device->commands->read_status| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_0| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_READ| /*read data*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ (1<manufacture_ID == 0xbf) ++ { ++ /*set the sflash cmd mode, set the sflash data mode*/ ++ cmd_bit_set |= (SFLASH_CMD_MODE_4X|SFLASH_DATA_CYCLE_NUM_2); ++ } ++ else ++ { ++ /*set the sflash cmd mode, set the sflash data mode*/ ++ cmd_bit_set |= (SFLASH_CMD_MODE_1X|SFLASH_DATA_CYCLE_NUM_0); ++ } ++ ++ sflash_cmd_bit_set(&sflash_cmd,&cmd_bit_set); ++ sflash_set_command(sflash_cmd.all); ++ sflash_get_data(); ++ ++ return(result); ++} ++ ++static int sflash_erase_chip(goke_sflash_dev_s* device) ++{ ++ goke_sflash_command_s sflash_cmd; ++ ulong CESetting = 0x38; ++ CESetting = CESetting | ((ulong)device->channel << 6); ++ sflash_set_ce(CESetting); ++ ++ if(old_feature == GOKE_SFLASH_FEATURE_IO4) ++ { ++ old_feature = GOKE_SFLASH_FEATURE_IO1; ++ if(device->manufacture_ID != 0x20) ++ { ++ sflash_disenable_io4(device); /*disable the IO4 mode*/ ++ } ++ } ++ if( !device ) ++ return(EINVAL); ++ ++ ++ sflash_wip_done_wait(device); ++ ++ sflash_write_enable(device); ++ ++ sflash_cmd.bitc.code = device->commands->erase_chip; //command ++ sflash_cmd.bitc.data_num = 0x1f; ++ sflash_set_command( sflash_cmd.all ); ++ ++ sflash_wip_done_wait( device ); ++ ++ //sflash_write_disable(device); ++ ++ return 0; ++} ++ ++static int sflash_erase_sector(goke_sflash_dev_s* device, uint32_t offset) ++{ ++ u32 cmd_bit_set = 0; ++ goke_sflash_command_s sflash_cmd; ++ u32 result; ++ ulong CESetting = 0x38; ++ ++ if( !device ) ++ return(EINVAL); ++ ++ CESetting = CESetting | ((ulong)device->channel << 6); ++ sflash_set_ce(CESetting); ++ if( (offset + device->sector_bytes) > device->device_bytes ) ++ return(EINVAL); ++ ++ // >16MB ++ if(offset >= GD_SFLASH_16M_SIZE) ++ { ++ sflash_set_ext_addr(device, offset/GD_SFLASH_16M_SIZE); ++ } ++ if(old_feature == GOKE_SFLASH_FEATURE_IO4) ++ { ++ old_feature = GOKE_SFLASH_FEATURE_IO1; ++ if(device->manufacture_ID != 0x20) ++ { ++ sflash_disenable_io4(device); /*disable the IO4 mode*/ ++ } ++ } ++ ++ sflash_write_enable(device); ++ ++ cmd_bit_set |= (device->commands->erase_sector| /*command*/ ++ SFLASH_SEND_CMD| /*transfer the command*/ ++ SFLASH_SEND_ADDR_BYTE_NUM_3| /*address num*/ ++ SFLASH_SEND_DUMMY_BYTE_NUM_0| /* dummy cycle*/ ++ SFLASH_RWN_NOTHING| /*no read/write data*/ ++ SFLASH_ADDR_DUMMY_CYCLE_NUM_0| /*set the sflash adr mode*/ ++ SFLASH_DATA_CYCLE_NUM_0| /*set the sflash data mode*/ ++ (0<= GD_SFLASH_16M_SIZE) ++ { ++ //restore to 0x00 ++ sflash_set_ext_addr(device, 0x00); ++ } ++ ++ sflash_cmd.bitc.code = device->commands->write_disable; /*command*/ ++ if(device->manufacture_ID == 0xbf) ++ { ++ sflash_cmd.bitc.cmd_mode = 2; /*set the sflash cmd mode*/ ++ } ++ else if(device->manufacture_ID == 0x1c) ++ { ++ sflash_cmd.bitc.cmd_mode = 0; ++ } ++ else ++ { ++ sflash_cmd.bitc.cmd_mode = 0; /*set the sflash cmd mode*/ ++ } ++ sflash_cmd.bitc.adr_num = 0; /*address num*/ ++ ++ sflash_set_command(sflash_cmd.all); ++ sflash_get_data(); ++ CESetting = CESetting & (~((ulong)device->channel << 6)); ++ sflash_set_ce(CESetting); ++ return(result); ++} ++ ++static goke_sflash_feature_e sflash_get_feature(goke_sflash_dev_s* device, goke_sflash_type_e type) ++{ ++ goke_sflash_feature_e feature = GOKE_SFLASH_FEATURE_IO1; ++ u8 temp = 0; ++ ++ if( !device ) ++ { ++ return feature; ++ } ++ if(type == GOKE_SFLASH_TYPE_READ) ++ { ++ temp = device->feature & 0x0F; ++ } ++ else ++ { ++ temp = (device->feature & 0xF0) >> 4; ++ } ++ switch(temp) ++ { ++ case 0x01: ++ feature = GOKE_SFLASH_FEATURE_IO1; ++ break; ++ case 0x02: ++ feature = GOKE_SFLASH_FEATURE_IO2; ++ break; ++ case 0x04: ++ feature = GOKE_SFLASH_FEATURE_IO4; ++ break; ++ default: ++ break; ++ } ++ return feature; ++} ++ ++static u32 sflash_cmd_bit_set(goke_sflash_command_s *sflashCmd, u32 *cmd_bit_set) ++{ ++ if(!sflashCmd) ++ { ++ return -1; ++ } ++ ++ sflashCmd->all = (*cmd_bit_set); ++ (*cmd_bit_set) = 0; ++ ++ return 0; ++} ++ ++static int sflash_write_iox( goke_sflash_dev_s* device, uint32_t address, ++ uint32_t* buffer, uint32_t words ) ++{ ++ goke_sflash_feature_e feature = GOKE_SFLASH_FEATURE_IO1; ++ uint32_t CESetting = 0x38; ++ uint32_t err = 0; ++ ++ feature = sflash_get_feature(device, GOKE_SFLASH_TYPE_WRITE); ++ ++ CESetting = CESetting | ((ulong)device->channel << 6); ++ sflash_set_ce(CESetting); ++ if(feature == GOKE_SFLASH_FEATURE_IO4) //support IO4 mode ++ { ++ sflash_set_ce(0x38 | ((u32)device->channel << 6)); ++ if(old_feature != feature) ++ { ++ old_feature = feature; ++ if(device->manufacture_ID != 0x20) ++ { ++ err = sflash_enable_io4(device); /*enable the IO4 mode*/ ++ } ++ if(err != 0) ++ { ++ return err; ++ } ++ } ++ sflash_write_io4( device, address, buffer, words ); ++ } ++ else if( feature == GOKE_SFLASH_FEATURE_IO2) //support IO2 mode ++ { ++ sflash_set_ce(0x0E | ((u32)device->channel << 6)); ++ if(old_feature != feature) ++ { ++ old_feature = feature; ++ if(device->manufacture_ID != 0x20) ++ { ++ err = sflash_disenable_io4(device); /*disable the IO4 mode*/ ++ } ++ } ++ sflash_write_io2( device, address, buffer, words ); ++ } ++ else ++ { ++ sflash_set_ce(0x0E | ((u32)device->channel << 6)); ++ if(old_feature != feature) ++ { ++ old_feature = feature; ++ if(device->manufacture_ID != 0x20) ++ { ++ err = sflash_disenable_io4(device); /*disable the IO4 mode*/ ++ } ++ } ++ sflash_write_io1( device, address, buffer, words ); ++ } ++ ++ CESetting = CESetting & (~((ulong)device->channel << 6)); ++ sflash_set_ce(CESetting); ++ ++ return 0; ++} ++ ++static int sflash_read_iox( goke_sflash_dev_s* device, uint32_t address, ++ uint32_t* buffer, uint32_t words ) ++{ ++ goke_sflash_feature_e feature = GOKE_SFLASH_FEATURE_IO1; ++ uint32_t CESetting = 0x38; ++ uint32_t err = 0; ++ ++ feature = sflash_get_feature(device, GOKE_SFLASH_TYPE_READ); ++ CESetting = CESetting | ((ulong)device->channel << 6); ++ sflash_set_ce(CESetting); ++ ++ if(feature == GOKE_SFLASH_FEATURE_IO4) //support IO4 mode ++ { ++ sflash_set_ce(0x38 | ((u32)device->channel << 6)); ++ if(old_feature != feature) ++ { ++ old_feature = feature; ++ if(device->manufacture_ID != 0x20) ++ { ++ err = sflash_enable_io4(device); /*enable the IO4 mode*/ ++ } ++ if(err != 0) ++ { ++ return err; ++ } ++ } ++ sflash_read_io4( device, address, buffer, words ); ++ } ++ else if( feature == GOKE_SFLASH_FEATURE_IO2) //support IO2 mode ++ { ++ sflash_set_ce(0x0E | ((u32)device->channel << 6)); ++ if(old_feature != feature) ++ { ++ old_feature = feature; ++ if(device->manufacture_ID != 0x20) ++ { ++ err = sflash_disenable_io4(device); /*disable the IO4 mode*/ ++ } ++ } ++ sflash_read_io2( device, address, buffer, words ); ++ } ++ else ++ { ++ sflash_set_ce(0x0E | ((u32)device->channel << 6)); ++ if(old_feature != feature) ++ { ++ old_feature = feature; ++ if(device->manufacture_ID != 0x20) ++ { ++ err = sflash_disenable_io4(device); /*disable the IO4 mode*/ ++ } ++ } ++ sflash_read_io1( device, address, buffer, words ); ++ } ++ ++ CESetting = CESetting & (~((ulong)device->channel << 6)); ++ sflash_set_ce(CESetting); ++ return err; ++} ++ ++/* ++ * Write an address range to the flash chip. Data must be written in ++ * FLASH_PAGESIZE chunks. The address range may be any size provided ++ * it is within the physical boundaries. ++ */ ++static int mtd_flash_write(struct mtd_info *mtd, loff_t to, size_t len, ++ size_t *retlen, const u_char *buf) ++{ ++ struct gk_sflash *flash = mtd_to_gk_flash(mtd); ++ ++ uint32_t addr,left,align_data; ++ uint32_t *wptr = NULL; ++ ++ if (!flash) ++ return -EINVAL; ++ ++ if( !(flash->device) ) ++ return -EINVAL; ++ ++ if (retlen) ++ *retlen = 0; ++ ++ /* sanity checks */ ++ if (!len) ++ return(0); ++ ++ if (to + len > flash->mtd.size) ++ return -EINVAL; ++ ++ mutex_lock(&flash->lock); ++ ++ addr = to; ++ wptr = (uint32_t*)buf; ++ left = len % (sizeof(uint32_t)); ++#if GD_SFLASH_USE_BUFFER ++ if(((addr>=flash->device->offset) && (addr<(flash->device->offset+flash->device->buffer_size))) || ++ (((addr+len)>=flash->device->offset) && ((addr+len)<(flash->device->offset+flash->device->buffer_size)))) ++ { ++ flash->device->offset = 0xFFFFFFFF; ++ //printk("[%s %d] 0x%08x 0x%08x 0x%08x\n", __func__, __LINE__, flash->device->offset, addr, len); ++ } ++#endif ++ ++ sflash_write_iox( flash->device, addr, wptr, len / (sizeof(uint32_t)) ); ++ ++ if(left > 0) ++ { ++ sflash_read_iox( flash->device, addr + (len - left), &align_data, 1 ); ++ memcpy( (u_char*)&align_data, buf + (len - left), left ); ++ sflash_write_iox( flash->device, addr + (len - left), &align_data, 1); ++ } ++ ++ *retlen = len; ++ ++ mutex_unlock(&flash->lock); ++ ++ return 0; ++} ++ ++/* ++ * Read an address range from the flash chip. The address range ++ * may be any size provided it is within the physical boundaries. ++ */ ++static int mtd_flash_read(struct mtd_info *mtd, loff_t from, size_t len, ++ size_t *retlen, u_char *buf) ++{ ++ struct gk_sflash *flash = mtd_to_gk_flash(mtd); ++ ++ unsigned int addr; ++ unsigned int end; ++ unsigned int off_set = 0; ++#if GD_SFLASH_USE_BUFFER ++ unsigned int left_bytes; ++#else ++ unsigned char buffer[256 + 10]; ++ unsigned int rd_pages = 0; ++ unsigned int cnt; ++ unsigned int start_addr; ++ unsigned int p_start, p_end; ++#endif ++ ++ if (!flash) ++ return -EINVAL; ++ ++ if( !(flash->device) ) ++ return -EINVAL; ++ ++ /* sanity checks */ ++ if (!len) ++ return 0; ++ ++ if (from + len > flash->mtd.size) ++ return -EINVAL; ++ ++ /* Byte count starts at zero. */ ++ if (retlen) ++ *retlen = 0; ++ ++ mutex_lock(&flash->lock); ++ addr = from; ++ off_set = 0; ++ end = addr + len; ++#if GD_SFLASH_USE_BUFFER ++ if((len >= flash->device->buffer_size) && ((addr%4) == 0x00) && ((len%4) == 0x00) && (((u32)buf%4) == 0x00)) ++ { ++ sflash_read_iox(flash->device, addr, (uint32_t*)buf, len / 4); ++ *retlen = len; ++ mutex_unlock(&flash->lock); ++ return 0; ++ } ++ ++ if((addr>=flash->device->offset) && (addr<(flash->device->offset+flash->device->buffer_size))) ++ { ++ } ++ else ++ { ++ flash->device->offset = addr - (addr % flash->device->buffer_size); ++ sflash_read_iox(flash->device, flash->device->offset, (uint32_t*)flash->device->buffer, flash->device->buffer_size / 4); ++ } ++ do ++ { ++ if((addr>=flash->device->offset) && (addr<(flash->device->offset+flash->device->buffer_size))) ++ { ++ left_bytes = flash->device->buffer_size - (addr - flash->device->offset); ++ if(left_bytes >= len) ++ { ++ memcpy(buf + off_set, flash->device->buffer + (addr - flash->device->offset), len); ++ *retlen = len; ++ mutex_unlock(&flash->lock); ++ return 0; ++ } ++ memcpy(buf + off_set, flash->device->buffer + (addr - flash->device->offset), left_bytes); ++ off_set += left_bytes; ++ len -= left_bytes; ++ addr += left_bytes; ++ sflash_read_iox(flash->device, flash->device->offset+flash->device->buffer_size, (uint32_t*)flash->device->buffer, flash->device->buffer_size / 4); ++ flash->device->offset += flash->device->buffer_size; ++ } ++ }while(1); ++#else ++ ++ if(((addr%4) == 0x00) && ((len%4) == 0x00) && (((u32)buf%4) == 0x00)) ++ { ++ sflash_read_iox( flash->device, addr, (uint32_t*)buf, len / 4); ++ mutex_unlock(&flash->lock); ++ *retlen = len; ++ return 0; ++ } ++ if (addr%256 == 0) { ++ start_addr = addr; ++ } else { ++ start_addr = addr - (addr % 256); ++ } ++ ++ if (addr%256 != 0) { ++ if ((addr + len) > (start_addr + 256)) { ++ p_start = start_addr + 256; ++ rd_pages += 1; ++ } else { ++ p_start = start_addr; ++ } ++ ++ } else { ++ p_start = start_addr; ++ } ++ ++ if (end%256 != 0) { ++ rd_pages += 1; ++ p_end = end - (end%256); ++ } else { ++ p_end = end; ++ } ++ ++ rd_pages += (p_end - p_start) / 256; ++ ++ //printk("\n\nread addr : 0x%08x, start : 0x%08x, len : %d, rd_pages : %d, p_start : 0x%x, p_end : 0x%x\n", addr, start_addr, len, rd_pages, p_start, p_end); ++ ++ for (cnt = 0; cnt < rd_pages;) { ++ sflash_read_iox( flash->device, start_addr + cnt*256, (uint32_t*)buffer, 64); ++ if (cnt == 0) { ++ if (addr + len < start_addr + 256) { ++ memcpy(buf + off_set, buffer + (addr % 256), len); ++ off_set += len; ++ } else { ++ memcpy(buf + off_set, buffer + (addr % 256), 256 - addr%256); ++ off_set += (256 - addr%256); ++ } ++ ++ //printk("cnt : %d, offset : %d\n", cnt, off_set); ++ } else if (cnt == (rd_pages - 1)) { ++ if (end % 256 == 0) { ++ memcpy(buf + off_set, buffer, 256); ++ off_set += 256; ++ } else { ++ memcpy(buf + off_set, buffer, end % 256); ++ off_set += (end % 256); ++ } ++ //printk("cnt : %d, offset : %d\n", cnt, off_set); ++ } else { ++ memcpy(buf + off_set, buffer, 256); ++ off_set += 256; ++ //printk("cnt : %d, offset : %d, read num : %d\n", cnt, off_set, 256); ++ } ++ ++ cnt++; ++ } ++ ++#endif ++ ++ *retlen = len; ++ mutex_unlock(&flash->lock); ++ ++ return 0; ++ ++} ++ ++/* ++ * Erase an address range on the flash chip. The address range may extend ++ * one or more erase sectors. Return an error is there is a problem erasing. ++ */ ++static int mtd_flash_erase(struct mtd_info *mtd, struct erase_info *instr) ++{ ++ struct gk_sflash *flash = mtd_to_gk_flash(mtd); ++ uint32_t addr,len; ++ uint32_t rem; ++ ++ if( !flash) ++ return -EINVAL; ++ ++ if( !(flash->device) ) ++ return -EINVAL; ++ ++ /* sanity checks */ ++ if (instr->addr + instr->len > flash->mtd.size) ++ return -EINVAL; ++ ++ div_u64_rem(instr->len, mtd->erasesize, &rem); ++ if (rem) ++ return -EINVAL; ++ ++ addr = instr->addr; ++ len = instr->len; ++ ++ //printk("erase, addr : 0x%08x, len : %d\n", addr, len); ++ ++ mutex_lock(&flash->lock); ++#if GD_SFLASH_USE_BUFFER ++ if(((addr>=flash->device->offset) && (addr<(flash->device->offset+flash->device->buffer_size))) || ++ (((addr+len)>=flash->device->offset) && ((addr+len)<(flash->device->offset+flash->device->buffer_size)))) ++ { ++ flash->device->offset = 0xFFFFFFFF; ++ //printk("[%s %d] 0x%08x 0x%08x 0x%08x\n", __func__, __LINE__, flash->device->offset, addr, len); ++ } ++#endif ++ ++ /* whole-chip erase? */ ++ if (len == flash->mtd.size) ++ { ++ if (sflash_erase_chip(flash->device)) ++ { ++ instr->state = MTD_ERASE_FAILED; ++ mutex_unlock(&flash->lock); ++ return -EIO; ++ } ++ ++ /* REVISIT in some cases we could speed up erasing large regions ++ * by using OPCODE_SE instead of OPCODE_BE_4K. We may have set up ++ * to use "small sector erase", but that's not always optimal. ++ */ ++ ++ /* "sector"-at-a-time erase */ ++ } ++ else ++ { ++ while (len) ++ { ++ if (sflash_erase_sector(flash->device, addr)) ++ { ++ instr->state = MTD_ERASE_FAILED; ++ mutex_unlock(&flash->lock); ++ return -EIO; ++ } ++ ++ addr += mtd->erasesize; ++ len -= mtd->erasesize; ++ } ++ } ++ ++ mutex_unlock(&flash->lock); ++ ++ instr->state = MTD_ERASE_DONE; ++ mtd_erase_callback(instr); ++ ++ return 0; ++ ++} ++ ++ ++static int gk_flash_probe(struct platform_device *dev) ++{ ++ struct gk_sflash *flash; ++ goke_sflash_dev_s *chip_info; ++ struct mtd_part_parser_data ppdata; ++ struct sflash_platform_data *data = dev->dev.platform_data; ++ unsigned i; ++ int ret; ++ ++ chip_info = jedec_probe(dev); ++ ++ if (!chip_info){ ++ printk(KERN_ERR "detect sflash fail\n"); ++ return -ENODEV; ++ } ++ ++ flash = kzalloc(sizeof *flash, GFP_KERNEL); ++ if (!flash) ++ return -ENOMEM; ++ ++ flash->device = chip_info; ++ mutex_init(&flash->lock); ++ platform_set_drvdata(dev, flash); ++ ++ flash->mtd.name = dev->name; ++ ++ flash->mtd.type = MTD_NORFLASH; ++ flash->mtd.writesize = 1; ++ flash->mtd.flags = MTD_CAP_NORFLASH; ++ flash->mtd.size = chip_info->device_bytes; ++ flash->mtd._erase = mtd_flash_erase; ++ flash->mtd._read = mtd_flash_read; ++ flash->mtd._write = mtd_flash_write; ++ ++ flash->mtd.erasesize = chip_info->sector_bytes; ++ ++ ppdata.of_node = dev->dev.of_node; ++ flash->mtd.dev.parent = &dev->dev; ++ flash->mtd.writebufsize = chip_info->page_bytes; ++ ++ dev_info(&dev->dev, "%s (%lld Kbytes)\n", chip_info->device_name, ++ (long long)flash->mtd.size >> 10); ++ ++ if (flash->mtd.numeraseregions) ++ for (i = 0; i < flash->mtd.numeraseregions; i++) ++ printk("mtd.eraseregions[%d] = { .offset = 0x%llx, " ++ ".erasesize = 0x%.8x (%uKiB), " ++ ".numblocks = %d }\n", ++ i, (long long)flash->mtd.eraseregions[i].offset, ++ flash->mtd.eraseregions[i].erasesize, ++ flash->mtd.eraseregions[i].erasesize / 1024, ++ flash->mtd.eraseregions[i].numblocks); ++ ++ /* partitions should match sector boundaries; and it may be good to ++ * use readonly partitions for writeprotected sectors (BP2..BP0). ++ */ ++ ret = mtd_device_parse_register(&flash->mtd, NULL, &ppdata, ++ data ? data->parts : NULL, ++ data ? data->nr_parts : 0); ++ // printk(KERN_ERR "sflash dev_t = 0x%x\n", flash->mtd.dev.devt); ++ ++ return ret; ++} ++ ++ ++static int gk_flash_remove(struct platform_device *dev) ++{ ++ struct gk_sflash *flash = platform_get_drvdata(dev); ++ int status; ++ ++ /* Clean up MTD stuff. */ ++ status = mtd_device_unregister(&flash->mtd); ++ if (status == 0) { ++ kfree(flash); ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_OF ++static struct of_device_id match_table[] = { ++ { .compatible = "mxic,mx25l12845e" }, ++ { .compatible = "spansion,s25fl128p" }, ++ { } /* end */ ++}; ++#else /* CONFIG_OF */ ++#define match_table NULL ++ ++#endif /* !CONFIG_OF */ ++ ++static struct platform_driver gk_flash_driver = ++{ ++ .driver = ++ { ++ .name = "gk_flash", ++ .owner = THIS_MODULE, ++ .of_match_table = match_table, ++ }, ++ .probe = gk_flash_probe, ++ .remove = gk_flash_remove, ++}; ++ ++ ++#ifdef CONFIG_OF ++module_platform_driver(gk_flash_driver); ++#else /* CONFIG_OF */ ++static int gk_flash_init(void) ++{ ++ int retval = 0; ++ ++// printk(KERN_ERR "sflash pa = 0x%x, va = 0x%x\n",(unsigned int)GK_PA_SFLASH ,(unsigned int)GK_VA_SFLASH); ++ ++ retval = platform_driver_register(&gk_flash_driver); ++// printk(KERN_ERR "sflash init ret = %d\n", retval); ++ ++ return retval; ++} ++ ++static void gk_flash_exit(void) ++{ ++ platform_driver_unregister(&gk_flash_driver); ++} ++ ++ ++module_init(gk_flash_init); ++module_exit(gk_flash_exit); ++#endif /* !CONFIG_OF */ ++ ++MODULE_DESCRIPTION("GOKE MTD serial flash driver for MTD"); ++MODULE_AUTHOR("Goke Microelectronics Inc."); ++MODULE_LICENSE("GPL"); ++ +diff --git a/drivers/mtd/devices/gk_sflash_v1_00.h b/drivers/mtd/devices/gk_sflash_v1_00.h +new file mode 100644 +index 00000000..cc6bb20a +--- /dev/null ++++ b/drivers/mtd/devices/gk_sflash_v1_00.h +@@ -0,0 +1,237 @@ ++/* ++ * drivers/mtd/devices/gk_sflash_v1_v00.h ++ * ++ * gk soc ++ * ++ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++ ++ ++#include ++#include ++#include ++ ++/* send cmd or not [ 8]*/ ++#define SFLASH_SEND_CMD 0x00000100 ++#define SFLASH_NO_SEND_CMD 0x00000000 ++ ++/* byte number of address to send [11:9]*/ ++#define SFLASH_SEND_ADDR_BYTE_NUM_0 0x00000000 ++#define SFLASH_SEND_ADDR_BYTE_NUM_1 0x00000200 ++#define SFLASH_SEND_ADDR_BYTE_NUM_2 0x00000400 ++#define SFLASH_SEND_ADDR_BYTE_NUM_3 0x00000600 ++#define SFLASH_SEND_ADDR_BYTE_NUM_4 0x00000800 ++#define SFLASH_SEND_ADDR_BYTE_NUM_5 0x00000a00 ++#define SFLASH_SEND_ADDR_BYTE_NUM_6 0x00000c00 ++#define SFLASH_SEND_ADDR_BYTE_NUM_7 0x00000e00 ++ ++/*Byte number of dummy cycle to send [14:12]*/ ++ ++#define SFLASH_SEND_DUMMY_BYTE_NUM_0 0x000000000 ++#define SFLASH_SEND_DUMMY_BYTE_NUM_1 0x000001000 ++#define SFLASH_SEND_DUMMY_BYTE_NUM_2 0x000002000 ++#define SFLASH_SEND_DUMMY_BYTE_NUM_3 0x000003000 ++#define SFLASH_SEND_DUMMY_BYTE_NUM_4 0x000004000 ++#define SFLASH_SEND_DUMMY_BYTE_NUM_5 0x000005000 ++#define SFLASH_SEND_DUMMY_BYTE_NUM_6 0x000006000 ++#define SFLASH_SEND_DUMMY_BYTE_NUM_7 0x000007000 ++ ++/* Command operation[16:15]: 00 for read data from SF; 01 for write data to SF; 11 for nothing to do */ ++ ++#define SFLASH_RWN_READ 0x00000000 ++#define SFLASH_RWN_WRITE 0x00008000 ++#define SFLASH_RWN_NOTHING 0x00018000 ++ ++/*I/O mode of command cycle to SF[18:17]: 00 for x1; 01 for x2; 10 for x4*/ ++#define SFLASH_CMD_MODE_1X 0x00000000 ++#define SFLASH_CMD_MODE_2X 0x00020000 ++#define SFLASH_CMD_MODE_4X 0x00040000 ++ ++/* I/O mode of address and dummy cycle to SF[20:19]*/ ++#define SFLASH_ADDR_DUMMY_CYCLE_NUM_0 0x00000000 ++#define SFLASH_ADDR_DUMMY_CYCLE_NUM_1 0x00080000 ++#define SFLASH_ADDR_DUMMY_CYCLE_NUM_2 0x00100000 ++#define SFLASH_ADDR_DUMMY_CYCLE_NUM_3 0x00180000 ++ ++/*I/O mode of data cycle to or from SF [22:21] */ ++ ++#define SFLASH_DATA_CYCLE_NUM_0 0x00000000 ++#define SFLASH_DATA_CYCLE_NUM_1 0x00200000 ++#define SFLASH_DATA_CYCLE_NUM_2 0x00400000 ++#define SFLASH_DATA_CYCLE_NUM_3 0x00600000 ++ ++/*Transfer data byte number to or from SF[27:23]. For 11111 case, transfer 4bytes per request. For other case, transfer number bytes.*/ ++ ++#define SFLASH_TRANSFER_BYTE_NUM_4 0x0f800000 ++#define SFLASH_TRANSFER_BYTE_LOC 23 ++ ++#define SFLASH_HOLD_TIME_100ns 0x00000000 ++#define SFLASH_HOLD_TIME_3us 0x10000000 ++#define SFLASH_HOLD_TIME_100us 0x20000000 ++ ++#define GD_SFLASH_1X_READ 0x01 ++#define GD_SFLASH_2X_READ 0x02 ++#define GD_SFLASH_4X_READ 0x04 ++#define GD_SFLASH_1X_WRITE 0x10 ++#define GD_SFLASH_2X_WRITE 0x20 ++#define GD_SFLASH_4X_WRITE 0x40 ++ ++#define GD_SFLASH_16M_SIZE 0x1000000 ++ ++/*----------------------------------------------------------------------------*/ ++/* bit group structures */ ++/*----------------------------------------------------------------------------*/ ++typedef union { /* SFLASH_Command */ ++ u32 all; ++ struct { ++ u32 code : 8; ++ u32 send_cmd : 1; ++ u32 adr_num : 3; ++ u32 dummy_num : 3; ++ u32 rwn : 2; ++ u32 cmd_mode : 2; ++ u32 adr_mode : 2; ++ u32 data_mode : 2; ++ u32 data_num : 5; ++ u32 hold_time : 2; ++ u32 : 2; ++ } bitc; ++} goke_sflash_command_s; ++ ++typedef union { /* SFLASH_CE */ ++ u32 all; ++ struct { ++ u32 ce : 1; ++ u32 wp : 1; ++ u32 hold : 1; ++ u32 ce_mode : 1; ++ u32 wp_mode : 1; ++ u32 hold_mode : 1; ++ u32 ch_select : 1; ++ u32 : 25; ++ } bitc; ++} goke_sflash_ce_s; ++ ++typedef union { /* SFLASH_Speed */ ++ u32 all; ++ struct { ++ u32 sf_sclk_sel : 3; ++ u32 : 29; ++ } bitc; ++} goke_sflash_speed_s; ++ ++typedef union { /* SFLASH_PARA_XIP */ ++ u32 all; ++ struct { ++ u32 sflash_command : 8; ++ u32 : 1; ++ u32 adr_num : 3; ++ u32 dummy_num : 3; ++ u32 : 2; ++ u32 cmd_mod : 2; ++ u32 adr_mod : 2; ++ u32 data_mod : 2; ++ u32 : 1; ++ u32 dumy_data : 8; ++ } bitc; ++} goke_sflash_para_xip_s; ++ ++/*-------------------------------------------------------------------------------*/ ++/* \brief Flash channel number. */ ++/*-------------------------------------------------------------------------------*/ ++ ++typedef enum ++{ ++ GOKE_SFLASH_CHANNEL_0 = 0, ++ GOKE_SFLASH_CHANNEL_1, ++ GOKE_SFLASH_CHANNEL_NUM ++}goke_sflash_channel_e; ++ ++/*-------------------------------------------------------------------------------*/ ++/* \brief Flash I/O feature. */ ++/*-------------------------------------------------------------------------------*/ ++ ++typedef enum ++{ ++ GOKE_SFLASH_FEATURE_IO1 = 0, ++ GOKE_SFLASH_FEATURE_IO2, ++ GOKE_SFLASH_FEATURE_IO4 ++}goke_sflash_feature_e; ++ ++/*-------------------------------------------------------------------------------*/ ++/* \brief Flash feature type. */ ++/*-------------------------------------------------------------------------------*/ ++ ++typedef enum ++{ ++ GOKE_SFLASH_TYPE_READ = 0, ++ GOKE_SFLASH_TYPE_WRITE ++}goke_sflash_type_e; ++ ++/*-------------------------------------------------------------------------------*/ ++/* serial flash specific commands and statis register bit definitions */ ++/*-------------------------------------------------------------------------------*/ ++ ++typedef struct ++{ ++ u8 read_ID; /*!< command to read the chip identification*/ ++ u8 write_enable; /*!< command to enable a write/erase sequence*/ ++ u8 write_disable; /*!< command to disable a write/erase sequence*/ ++ u8 read_status; /*!< command to read from status register*/ ++ u8 write_status; /*!< command to write to status register*/ ++ u8 read_data; /*!< command to read data*/ ++ u8 read_data_fast; /*!< command to read data in fast mode*/ ++ u8 erase_sector; /*!< command to erase a single sector*/ ++ u8 erase_chip; /*!< command to erase the entire chip*/ ++ u8 program_page; /*!< command to program a sector page*/ ++ u32 status_mask_wip; /*!< status register mask for bit write-in-progress*/ ++ u32 status_mask_wel; /*!< status register mask for bit write-enable-latch*/ ++ u8 read_io2; /*!< command to read data by IO2*/ ++ u8 read_io4; /*!< command to read data by IO4*/ ++ u8 program_page2; /*!< command to program a sector page by IO2*/ ++ u8 program_page4; /*!< command to program a sector page by IO4*/ ++ u8 read_ext_addr; /*!< command to read the extenden address*/ ++ u8 write_ext_addr; /*!< command to write the extenden address*/ ++ u8 read_status2; /*!< command to read from status2 register*/ ++}goke_sflash_cmd_s; ++ ++/*-------------------------------------------------------------------------------*/ ++/* serial flash specific geometry and information data structure */ ++/*-------------------------------------------------------------------------------*/ ++ ++typedef struct ++{ ++ u8 manufacture_ID; /*!< Manufacture identification*/ ++ u16 device_ID; /*!< Device identification (memory type/capacity)*/ ++ char* manufacture_name; /*!< Pointer to manufacture name*/ ++ char* device_name; /*!< Pointer to device name*/ ++ u32 device_bytes; /*!< Size of flash device in bytes*/ ++ u32 sector_count; /*!< Number of sectors*/ ++ u32 sector_bytes; /*!< Size of a single flash sector in bytes*/ ++ u32 sector_pages; /*!< Number of pages per sector*/ ++ u32 page_bytes; /*!< Size of a programmable page in bytes*/ ++ const goke_sflash_cmd_s* commands; /*!< Device specific access commands*/ ++ u32 feature; /*! ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "gk_spinand_v1_00.h" ++#include "spinand.h" ++ ++#if 1 ++#define uswap_32(x) x ++#else ++#define uswap_32(x) \ ++ ((((x) & 0xff000000) >> 24) | \ ++ (((x) & 0x00ff0000) >> 8) | \ ++ (((x) & 0x0000ff00) << 8) | \ ++ (((x) & 0x000000ff) << 24)) ++#endif ++ ++#define gk_spi_nand_driver_version "GK-MTD_01.00_Linux3.4.43_20150115" ++ ++ ++#define BAD_BLOCK 0 ++#define BAD_BLOCK_OFF 0x00 ++ ++struct gk_spinand_host { ++ struct spinand_chip chip; ++ struct mtd_info mtd; ++ ++ /* page size of attached chip */ ++ unsigned int page_size; ++ int use_ecc; ++ int cs; ++ ++ void __iomem *io_base; ++ struct device *dev; ++ struct completion comp; ++ struct mutex lock; ++}; ++ ++/******************************************************/ ++/* SPI Nand Part ( Hardware Dependent ) */ ++/******************************************************/ ++ ++/** ++ OOB area specification layout: Total available free bytes. ++*/ ++static struct nand_ecclayout spinand_ecc_64_layout_gd = { ++ .eccbytes = 16, ++ .eccpos = { 0x0c, 0x0d, 0x0e, 0x0f, ++ 0x1c, 0x1d, 0x1e, 0x1f, ++ 0x2c, 0x2d, 0x2e, 0x2f, ++ 0x3c, 0x3d, 0x3e, 0x3f,}, ++ .oobavail = 32, ++ .oobfree = { ++ {.offset = 0x04, .length = 8}, ++ {.offset = 0x14, .length = 8}, ++ {.offset = 0x24, .length = 8}, ++ {.offset = 0x34, .length = 8}, ++ } ++}; ++ ++static struct nand_ecclayout spinand_ecc_64_layout_esmt = { ++ .eccbytes = 28, ++ .eccpos = { 0x01, 0x02, 0x03, ++ 0x04, 0x05, 0x06, 0x07, ++ 0x11, 0x12, 0x13, ++ 0x14, 0x15, 0x16, 0x17, ++ 0x21, 0x22, 0x23, ++ 0x24, 0x25, 0x26, 0x27, ++ 0x31, 0x32, 0x33, ++ 0x34, 0x35, 0x36, 0x37,}, ++ .oobavail = 32, ++ .oobfree = { ++ {.offset = 0x08, .length = 8}, ++ {.offset = 0x18, .length = 8}, ++ {.offset = 0x28, .length = 8}, ++ {.offset = 0x38, .length = 8}, ++ } ++}; ++ ++static struct nand_ecclayout spinand_ecc_64_layout_ato = { ++ .eccbytes = 20, ++ .eccpos = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, ++ 0x18, 0x19, 0x1a, 0x1b, 0x1c, ++ 0x28, 0x29, 0x2a, 0x2b, 0x2c, ++ 0x38, 0x39, 0x3a, 0x3b, 0x3c,}, ++ .oobavail = 0, ++ .oobfree = { ++ {.offset = 0x04, .length = 8}, ++ {.offset = 0x14, .length = 8}, ++ {.offset = 0x24, .length = 8}, ++ {.offset = 0x34, .length = 8}, ++ } ++}; ++ ++static struct nand_ecclayout spinand_ecc_64_layout_wb = { ++ .eccbytes = 24, ++ .eccpos = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, ++ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, ++ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, ++ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,}, ++ .oobavail = 8, ++ .oobfree = { ++ {.offset = 0x02, .length = 2}, ++ {.offset = 0x12, .length = 2}, ++ {.offset = 0x22, .length = 2}, ++ {.offset = 0x32, .length = 2}, ++ } ++}; ++ ++/** ++ SPI Nand command set. ++*/ ++spinand_cmd_t spinand_commands_gd = ++{ ++ /* writeEnable */ 0x06, ++ /* writeDisable */ 0x04, ++ /* getFeatures */ 0x0f, ++ /* setFeatures */ 0x1f, ++ /* pageRead */ 0x13, ++ /* readCache */ 0x0b, //0x03 ++ /* readCacheX2 */ 0x3b, ++ /* readCacheX4 */ 0x6b, ++ /* readCacheIO2 */ 0xbb, ++ /* readCacheIO4 */ 0xeb, ++ /* readID */ 0x9f, ++ /* programLoad */ 0x02, ++ /* programLoadX4 */ 0x32, ++ /* progExecute */ 0x10, ++ /* progLoadRand */ 0x84, ++ /* progLoadRandX4 */ 0xc4, ++ /* progLoadRandIO2 */ 0x72, ++ /* blockErase */ 0xd8, ++ /* reset */ 0xff ++}; ++ ++spinand_cmd_t spinand_commands_esmt = ++{ ++ /* writeEnable */ 0x06, ++ /* writeDisable */ 0x04, ++ /* getFeatures */ 0x0f, ++ /* setFeatures */ 0x1f, ++ /* pageRead */ 0x13, ++ /* readCache */ 0x0b, //0x03 ++ /* readCacheX2 */ 0x3b, ++ /* readCacheX4 */ 0x6b, ++ /* readCacheIO2 */ 0xbb, ++ /* readCacheIO4 */ 0xeb, ++ /* readID */ 0x9f, ++ /* programLoad */ 0x02, ++ /* programLoadX4 */ 0x32, ++ /* progExecute */ 0x10, ++ /* progLoadRand */ 0x84, ++ /* progLoadRandX4 */ 0x34, ++ /* progLoadRandIO2 */ 0x72, ++ /* blockErase */ 0xd8, ++ /* reset */ 0xff ++}; ++ ++spinand_cmd_t spinand_commands_ato = ++{ ++ /* writeEnable */ 0x06, ++ /* writeDisable */ 0x04, ++ /* getFeatures */ 0x0f, ++ /* setFeatures */ 0x1f, ++ /* pageRead */ 0x13, ++ /* readCache */ 0x0b, //0x03 ++ /* readCacheX2 */ 0x3b, //not supported ++ /* readCacheX4 */ 0x6b, ++ /* readCacheIO2 */ 0xbb, //not supported ++ /* readCacheIO4 */ 0xeb, //not supported ++ /* readID */ 0x9f, ++ /* programLoad */ 0x02, ++ /* programLoadX4 */ 0x32, ++ /* progExecute */ 0x10, ++ /* progLoadRand */ 0x84, ++ /* progLoadRandX4 */ 0x34, ++ /* progLoadRandIO2 */ 0x72, //not supported ++ /* blockErase */ 0xd8, ++ /* reset */ 0xff ++}; ++ ++spinand_cmd_t spinand_commands_wb = ++{ ++ /* writeEnable */ 0x06, ++ /* writeDisable */ 0x04, ++ /* getFeatures */ 0x0f, ++ /* setFeatures */ 0x1f, ++ /* pageRead */ 0x13, ++ /* readCache */ 0x0b, //0x03 ++ /* readCacheX2 */ 0x3b, ++ /* readCacheX4 */ 0x6b, ++ /* readCacheIO2 */ 0xbb, ++ /* readCacheIO4 */ 0xeb, ++ /* readID */ 0x9f, ++ /* programLoad */ 0x02, ++ /* programLoadX4 */ 0x32, ++ /* progExecute */ 0x10, ++ /* progLoadRand */ 0x84, ++ /* progLoadRandX4 */ 0x34, ++ /* progLoadRandIO2 */ 0x72, ++ /* blockErase */ 0xd8, ++ /* reset */ 0xff ++}; ++ ++static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; ++ ++static struct nand_bbt_descr badblock_ptn_gd = { ++ .options = 0, ++ .offs = 0, ++ .len = 1, ++ .pattern = scan_ff_pattern, ++}; ++ ++static struct nand_bbt_descr badblock_ptn_esmt = { ++ .options = NAND_BBT_SCAN2NDPAGE, ++ .offs = 0, ++ .len = 1, ++ .pattern = scan_ff_pattern, ++}; ++ ++static struct nand_bbt_descr badblock_ptn_ato = { ++ .options = 0, ++ .offs = 0, ++ .len = 1, ++ .pattern = scan_ff_pattern, ++}; ++ ++static struct nand_bbt_descr badblock_ptn_wb = { ++ .options = 0, ++ .offs = 0, ++ .len = 1, ++ .pattern = scan_ff_pattern, ++}; ++ ++/* ++******************************************************************************* ++** ++** gd_sflash_devices_supported is an array containing serial flash ++** geometry and information data of all supported devices, it will ++** be used during GD_SFLASH_Init() to find the connected serial ++** flash decive ++** ++******************************************************************************* ++*/ ++struct spinand_info spinand_devices_supported[] = ++{ ++ { ++ /* manufactureID */ 0xC8, ++ /* deviceID */ 0xF1, ++ /* manufactureName */ "GigaDevice", ++ /* deviceName */ "GD5F1GQ4UAYIG", ++ /* nand_size */ (1024 * (2048 + 64) * 64), ++ /* usable_size */ (1024 * 2048 * 64), ++ /* block_size */ ((2048 + 64) * 64), ++ /* block_main_size */ (2048 * 64), ++ /* block_per_chip */ 1024, ++ /* page_size */ (2048 + 64), ++ /* page_main_size */ 2048, ++ /* page_spare_size */ 64, ++ /* page_per_block */ 64, ++ /* block_shift */ 17, ++ /* block_mask */ 0x1ffff, ++ /* page_shift */ 11, ++ /* page_mask */ 0x7ff, ++ /* commands */ &spinand_commands_gd, ++ /* feature */ SPINAND_1X_WRITE | SPINAND_4X_READ, ++ /* channel */ 1, ++ /* nand_ecclayout */ &spinand_ecc_64_layout_gd, ++ /* badblockbits */ 8, ++ /* badblock_pattern */ &badblock_ptn_gd ++ }, ++ { ++ /* manufactureID */ 0xC8, ++ /* deviceID */ 0xF2, ++ /* manufactureName */ "GigaDevice", ++ /* deviceName */ "GD5F2GQ4UAYIG", ++ /* nand_size */ (2048 * (2048 + 64) * 64), ++ /* usable_size */ (2048 * 2048 * 64), ++ /* block_size */ ((2048 + 64) * 64), ++ /* block_main_size */ (2048 * 64), ++ /* block_per_chip */ 2048, ++ /* page_size */ (2048 + 64), ++ /* page_main_size */ 2048, ++ /* page_spare_size */ 64, ++ /* page_per_block */ 64, ++ /* block_shift */ 17, ++ /* block_mask */ 0x1ffff, ++ /* page_shift */ 11, ++ /* page_mask */ 0x7ff, ++ /* commands */ &spinand_commands_gd, ++ /* feature */ SPINAND_1X_WRITE | SPINAND_4X_READ, ++ /* channel */ 1, ++ /* nand_ecclayout */ &spinand_ecc_64_layout_gd, ++ /* badblockbits */ 8, ++ /* badblock_pattern */ &badblock_ptn_gd ++ }, ++ { ++ /* manufactureID */ 0xC8, ++ /* deviceID */ 0xF4, ++ /* manufactureName */ "GigaDevice", ++ /* deviceName */ "GD5F4GQ4UAYIG", ++ /* nand_size */ (4096 * (2048 + 64) * 64), ++ /* usable_size */ (4096 * 2048 * 64), ++ /* block_size */ ((2048 + 64) * 64), ++ /* block_main_size */ (2048 * 64), ++ /* block_per_chip */ 4096, ++ /* page_size */ (2048 + 64), ++ /* page_main_size */ 2048, ++ /* page_spare_size */ 64, ++ /* page_per_block */ 64, ++ /* block_shift */ 17, ++ /* block_mask */ 0x1ffff, ++ /* page_shift */ 11, ++ /* page_mask */ 0x7ff, ++ /* commands */ &spinand_commands_gd, ++ /* feature */ SPINAND_1X_WRITE | SPINAND_4X_READ, ++ /* channel */ 1, ++ /* nand_ecclayout */ &spinand_ecc_64_layout_gd, ++ /* badblockbits */ 8, ++ /* badblock_pattern */ &badblock_ptn_gd ++ }, ++ { ++ /* manufactureID */ 0xC8, ++ /* deviceID */ 0x20, ++ /* manufactureName */ "ESMT", ++ /* deviceName */ "F50L512M41A", ++ /* nand_size */ (512 * (2048 + 64) * 64), ++ /* usable_size */ (512 * 2048 * 64), ++ /* block_size */ ((2048 + 64) * 64), ++ /* block_main_size */ (2048 * 64), ++ /* block_per_chip */ 512, ++ /* page_size */ (2048 + 64), ++ /* page_main_size */ 2048, ++ /* page_spare_size */ 64, ++ /* page_per_block */ 64, ++ /* block_shift */ 17, ++ /* block_mask */ 0x1ffff, ++ /* page_shift */ 11, ++ /* page_mask */ 0x7ff, ++ /* commands */ &spinand_commands_esmt, ++ /* feature */ SPINAND_1X_WRITE | SPINAND_4X_READ, ++ /* channel */ 1, ++ /* nand_ecclayout */ &spinand_ecc_64_layout_esmt, ++ /* badblockbits */ 8, ++ /* badblock_pattern */ &badblock_ptn_esmt ++ }, ++ { ++ /* manufactureID */ 0x9b, ++ /* deviceID */ 0x12, ++ /* manufactureName */ "ATO", ++ /* deviceName */ "ATO25D1GA", ++ /* nand_size */ (1024 * (2048 + 64) * 64), ++ /* usable_size */ (1024 * 2048 * 64), ++ /* block_size */ ((2048 + 64) * 64), ++ /* block_main_size */ (2048 * 64), ++ /* block_per_chip */ 1024, ++ /* page_size */ (2048 + 64), ++ /* page_main_size */ 2048, ++ /* page_spare_size */ 64, ++ /* page_per_block */ 64, ++ /* block_shift */ 17, ++ /* block_mask */ 0x1ffff, ++ /* page_shift */ 11, ++ /* page_mask */ 0x7ff, ++ /* commands */ &spinand_commands_ato, ++ /* feature */ SPINAND_1X_WRITE | SPINAND_4X_READ, ++ /* channel */ 1, ++ /* nand_ecclayout */ &spinand_ecc_64_layout_ato, ++ /* badblockbits */ 8, ++ /* badblock_pattern */ &badblock_ptn_ato ++ }, ++ { ++ /* manufactureID */ 0xEF, ++ /* deviceID */ 0xAA21, ++ /* manufactureName */ "Winbond", ++ /* deviceName */ "W25N01GV", ++ /* nand_size */ (1024 * (2048 + 64) * 64), ++ /* usable_size */ (1024 * 2048 * 64), ++ /* block_size */ ((2048 + 64) * 64), ++ /* block_main_size */ (2048 * 64), ++ /* block_per_chip */ 1024, ++ /* page_size */ (2048 + 64), ++ /* page_main_size */ 2048, ++ /* page_spare_size */ 64, ++ /* page_per_block */ 64, ++ /* block_shift */ 17, ++ /* block_mask */ 0x1ffff, ++ /* page_shift */ 11, ++ /* page_mask */ 0x7ff, ++ /* commands */ &spinand_commands_wb, ++ /* feature */ SPINAND_1X_WRITE | SPINAND_4X_READ, ++ /* channel */ 1, ++ /* nand_ecclayout */ &spinand_ecc_64_layout_wb, ++ /* badblockbits */ 8, ++ /* badblock_pattern */ &badblock_ptn_wb ++ }, ++}; ++ ++struct gk_spinand_platform_data ++{ ++ uint32_t speed_mode; ++ uint32_t channel; ++ struct mtd_partition *parts; ++ unsigned int nr_parts; ++}; ++ ++static struct mtd_partition gk_spinand_partitions[ ] = { ++ [0] = { ++ .name = "uboot", ++ .offset = 0, ++ .size = SZ_1M, ++ }, ++ [1] = { ++ .name = "uboot-env", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = SZ_1M, ++ }, ++ [2] = { ++ .name = "user", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = SZ_4M, ++ }, ++ [3] = { ++ .name = "config", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = SZ_1M, ++ }, ++ [4] = { ++ .name = "kernel", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = SZ_4M, ++ }, ++ [5] = { ++ .name = "rootfs", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = SZ_4M * 28, // 1g bit nand sflash ++ }, ++ [6] = { ++ .name = "resource", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = SZ_4M, ++ }, ++}; ++ ++#define NUM_PARTITIONS (ARRAY_SIZE(gk_spinand_partitions)) ++ ++static int gk_spinand_set_channel(struct spinand_info *info) ++{ ++ uint32_t ce_setting = 0; ++ uint32_t new_ce_setting = 0; ++ ++ if( info && info->mid) ++ { ++ ce_setting = spinand_get_ce(); ++ new_ce_setting = (ce_setting & ~(1 << 6)) | ((uint32_t)info->channel << 6); ++ if(ce_setting != new_ce_setting) ++ { ++ spinand_set_ce_chselect((uint8_t)info->channel); ++ } ++ return 0; ++ } ++ return -EINVAL; ++} ++ ++static int gk_spinand_release_channel(struct spinand_info *info) ++{ ++ uint32_t ce_setting = 0; ++ uint32_t new_ce_setting = 0; ++ ++ if( info && info->mid) ++ { ++ ce_setting = spinand_get_ce(); ++ new_ce_setting = ce_setting & (~((uint32_t)info->channel << 6)); ++ if(ce_setting != new_ce_setting) ++ { ++ spinand_set_ce_chselect(!((uint8_t)info->channel)); ++ } ++ return 0; ++ } ++ return -EINVAL; ++} ++/** ++ * gk_spinand_write_enable - send command 0x06 to enable write or erase the Nand cells ++ * ++ * Description: ++ * Before write and erase the Nand cells, the write enable has to be set. ++ * After the write or erase, the write enable bit is automatically cleared( status register bit 2 ) ++ * Set the bit 2 of the status register has the same effect ++ */ ++static uint32_t gk_spinand_write_enable(struct spinand_chip *chip, bool enable) ++{ ++ struct spinand_info *info = chip->info; ++ ++ flash_command_s SflashCmd = {0}; ++ ++ uint32_t sflashData; ++ uint32_t cmdBitSet = 0; ++ ++ // ++ // issue a write command sequence to prepare ++ // the device for data to be written ++ // ++ cmdBitSet |= (FLASH_SEND_CMD | // transfer the command ++ FLASH_SEND_ADDR_BYTE_NUM_0 | // address num ++ FLASH_SEND_DUMMY_BYTE_NUM_0 | // dummy cycle ++ FLASH_RWN_NOTHING | // no read/write data ++ FLASH_CMD_MODE_1X | // set the sflash cmd mode ++ FLASH_ADDR_DUMMY_CYCLE_NUM_0 | // set the sflash adr mode ++ FLASH_DATA_CYCLE_NUM_0 | // set the sflash data mode ++ (0 << FLASH_TRANSFER_BYTE_LOC) | // transfer data number ++ FLASH_HOLD_TIME_100ns ++ ); ++ ++ if(enable == WR_ENABLE) ++ { ++ cmdBitSet |= (uint32_t)info->commands->writeEnable; // command ++ } ++ else ++ { ++ cmdBitSet |= (uint32_t)info->commands->writeDisable; // command ++ } ++ ++ SflashCmd.all = cmdBitSet; ++ spinand_set_command(SflashCmd.all); ++ sflashData = spinand_get_data(); ++ ++ return sflashData; ++ ++} ++ ++/** ++ * gk_spinand_set_feature - send command 0x1f to the SPI Nand status register ++ * ++ * Description: ++ * After read, write, or erase, the Nand device is expected to set the busy status. ++ * This function is to allow reading the status of the command: read, write, and erase. ++ * Once the status turns to be ready, the other status bits also are valid status bits. ++ */ ++static int gk_spinand_set_feature(struct spinand_chip *chip, uint32_t off, uint8_t input) ++{ ++ struct spinand_info *info = chip->info; ++ ++ uint32_t cmdBitSet = 0; ++ ++ flash_command_s SflashCmd = {0}; ++ ++ cmdBitSet |= (info->commands->setFeatures | // command ++ FLASH_SEND_CMD | // transfer the command ++ FLASH_SEND_ADDR_BYTE_NUM_1 | // address num ++ FLASH_SEND_DUMMY_BYTE_NUM_0 | // dummy cycle ++ FLASH_RWN_WRITE | // write data ++ FLASH_CMD_MODE_1X | // set the sflash cmd mode ++ FLASH_ADDR_DUMMY_CYCLE_NUM_0 | // set the sflash adr mode ++ FLASH_DATA_CYCLE_NUM_0 | // set the sflash data mode ++ (1 << FLASH_TRANSFER_BYTE_LOC) | // transfer data number ++ FLASH_HOLD_TIME_100ns ++ ); ++ ++ SflashCmd.all = cmdBitSet; ++ spinand_set_command(SflashCmd.all); ++ spinand_set_data(off); ++ spinand_set_data(input); ++ ++ return 0; ++ ++} ++ ++/** ++ * gk_spinand_get_feature - send command 0xf to the SPI Nand status register ++ * ++ * Description: ++ * After read, write, or erase, the Nand device is expected to set the busy status. ++ * This function is to allow reading the status of the command: read, write, and erase. ++ * Once the status turns to be ready, the other status bits also are valid status bits. ++ */ ++static int gk_spinand_get_feature(struct spinand_chip *chip, uint32_t off, uint32_t *output) ++{ ++ struct spinand_info *info = chip->info; ++ ++ uint32_t sflashData; ++ uint32_t cmdBitSet = 0; ++ ++ flash_command_s SflashCmd = {0}; ++ ++ cmdBitSet |= (info->commands->getFeatures | // command ++ FLASH_SEND_CMD | // transfer the command ++ FLASH_SEND_ADDR_BYTE_NUM_1 | // address num ++ FLASH_SEND_DUMMY_BYTE_NUM_0 | // dummy cycle ++ FLASH_RWN_READ | // read data ++ FLASH_CMD_MODE_1X | // set the sflash cmd mode ++ FLASH_ADDR_DUMMY_CYCLE_NUM_0 | // set the sflash adr mode ++ FLASH_DATA_CYCLE_NUM_0 | // set the sflash data mode ++ (1 << FLASH_TRANSFER_BYTE_LOC) | // transfer data number ++ FLASH_HOLD_TIME_100ns ++ ); ++ ++ SflashCmd.all = cmdBitSet; ++ spinand_set_command(SflashCmd.all); ++ spinand_set_data(off); ++ ++ sflashData = spinand_get_data(); ++ *output = sflashData; ++ ++ return 0; ++ ++} ++ ++/** ++ * spinand_reset- send reset command "0xff" to the Nand device ++ * ++ * Description: ++ * Reset the SPI Nand with the reset command 0xff ++ */ ++static int gk_spinand_reset(struct spinand_chip *chip) ++{ ++ struct spinand_info *info = chip->info; ++ ++ uint32_t cmdBitSet = 0; ++ ++ flash_command_s SflashCmd = {0}; ++ ++ gk_spinand_set_channel(info); ++ ++ cmdBitSet |= (info->commands->reset | // command ++ FLASH_SEND_CMD | // transfer the command ++ FLASH_SEND_ADDR_BYTE_NUM_0 | // address num ++ FLASH_SEND_DUMMY_BYTE_NUM_0 | // dummy cycle ++ FLASH_RWN_NOTHING | // read data ++ FLASH_CMD_MODE_1X | // set the sflash cmd mode ++ FLASH_ADDR_DUMMY_CYCLE_NUM_0 | // set the sflash adr mode ++ FLASH_DATA_CYCLE_NUM_0 | // set the sflash data mode ++ (1 << FLASH_TRANSFER_BYTE_LOC) | // transfer data number ++ FLASH_HOLD_TIME_100ns ++ ); ++ ++ SflashCmd.all = cmdBitSet; ++ spinand_set_command(SflashCmd.all); ++ gk_spinand_release_channel(info); ++ return 0; ++ ++} ++/** ++ * spinand_read_id- Read SPI Nand ID ++ * ++ * Description: ++ * Read ID: read two ID bytes from the SPI Nand device ++ */ ++static int gk_spinand_read_id(struct spinand_chip *chip, uint32_t* id) ++{ ++ struct spinand_info *info = chip->info; ++ ++ uint32_t sflashData; ++ uint32_t cmdBitSet = 0; ++ ++ flash_command_s SflashCmd; ++ ++ gk_spinand_set_channel(info); ++ ++ // spi nand flash: send readID cmd ++ cmdBitSet |= (FLASH_SEND_CMD| // transfer the command ++ FLASH_SEND_ADDR_BYTE_NUM_1| // address num ++ FLASH_SEND_DUMMY_BYTE_NUM_0| // dummy cycle ++ FLASH_RWN_READ| // read data ++ FLASH_CMD_MODE_1X| // set the sflash cmd mode ++ FLASH_ADDR_DUMMY_CYCLE_NUM_0| // set the sflash adr mode ++ FLASH_DATA_CYCLE_NUM_0| // set the sflash data mode ++ (3 << FLASH_TRANSFER_BYTE_LOC) // transfer data number ++ ); ++ ++ cmdBitSet |= (uint32_t)info->commands->readID; // readID command ++ SflashCmd.all = cmdBitSet; ++ spinand_set_command(SflashCmd.all); ++ spinand_set_data(0x00); ++ sflashData = spinand_get_data(); ++ ++ *id = sflashData; ++ ++ gk_spinand_release_channel(info); ++ ++ return 0; ++ ++} ++ ++/** ++ * gk_spinand_unlock_allblock- send write register 0x1f command to the Nand device ++ * ++ * Description: ++ * After power up, all the Nand blocks are locked. This function allows ++ * one to unlock the blocks, and so it can be wriiten or erased. ++ */ ++static int gk_spinand_unlock_allblock(struct spinand_chip *chip) ++{ ++ struct spinand_info *info = chip->info; ++ ++ gk_spinand_set_channel(info); ++ gk_spinand_set_feature(chip , REG_PROTECTION, BL_ALL_UNLOCKED); ++ gk_spinand_release_channel(info); ++ return 0; ++} ++ ++#if 0 ++ ++/** ++ * gk_spinand_enable_bbi - send command 0x1f to write the SPI Nand OTP register ++ * ++ * Description: ++ * There is one bit( bit 0x10 ) to set or to clear the internal ECC. ++ * Enable chip internal BBI, set the bit to 1 ++ * Disable chip internal BBI, clear the bit to 0 ++ */ ++static int gk_spinand_enable_bbi(struct spinand_chip *chip) ++{ ++ struct spinand_info *info = chip->info; ++ uint32_t ufeature = 0; ++ ++ gk_spinand_set_channel(info); ++ ++ gk_spinand_get_feature(chip, REG_FEATURE, &ufeature); ++ ++ if ((ufeature & OTP_BBI_MASK) == OTP_BBI_MASK) ++ { ++ return 0; ++ } ++ else ++ { ++ ufeature |= OTP_BBI_MASK; ++ gk_spinand_set_feature(chip, REG_FEATURE, (uint8_t)(ufeature & 0xff)); ++ gk_spinand_get_feature(chip, REG_FEATURE, &ufeature); ++ return ufeature; ++ } ++} ++ ++static int gk_spinand_disable_bbi(struct spinand_chip *chip) ++{ ++ struct spinand_info *info = chip->info; ++ uint32_t ufeature = 0; ++ ++ gk_spinand_set_channel(info); ++ ++ gk_spinand_get_feature(chip, REG_FEATURE, &ufeature); ++ ++ if ((ufeature & OTP_BBI_MASK) == OTP_BBI_MASK) ++ { ++ ufeature &= ~OTP_BBI_MASK; ++ gk_spinand_set_feature(chip, REG_FEATURE, (uint8_t)(ufeature & 0xff)); ++ gk_spinand_get_feature(chip, REG_FEATURE, &ufeature); ++ return ufeature; ++ } ++ else ++ { ++ return 0; ++ } ++} ++ ++#endif ++ ++/** ++ * gk_spinand_enable_ecc - send command 0x1f to write the SPI Nand OTP register ++ * ++ * Description: ++ * There is one bit( bit 0x10 ) to set or to clear the internal ECC. ++ * Enable chip internal ECC, set the bit to 1 ++ * Disable chip internal ECC, clear the bit to 0 ++ */ ++#ifdef CONFIG_MTD_SPINAND_INTERECC ++static int gk_spinand_enable_ecc(struct spinand_chip *chip) ++{ ++ struct spinand_info *info = chip->info; ++ uint32_t ufeature = 0; ++ ++ gk_spinand_set_channel(info); ++ ++ gk_spinand_get_feature(chip, REG_FEATURE, &ufeature); ++ ++ if ((ufeature & OTP_ECC_MASK) == OTP_ECC_MASK) ++ { ++ gk_spinand_release_channel(info); ++ return 0; ++ } ++ else ++ { ++ ufeature |= OTP_ECC_MASK; ++ gk_spinand_set_feature(chip, REG_FEATURE, (uint8_t)(ufeature & 0xff)); ++ gk_spinand_get_feature(chip, REG_FEATURE, &ufeature); ++ gk_spinand_release_channel(info); ++ return ufeature; ++ } ++} ++#endif ++ ++static int gk_spinand_disable_ecc(struct spinand_chip *chip) ++{ ++ struct spinand_info *info = chip->info; ++ uint32_t ufeature = 0; ++ ++ gk_spinand_set_channel(info); ++ ++ gk_spinand_get_feature(chip, REG_FEATURE, &ufeature); ++ ++ if ((ufeature & OTP_ECC_MASK) == OTP_ECC_MASK) ++ { ++ ufeature &= ~OTP_ECC_MASK; ++ gk_spinand_set_feature(chip, REG_FEATURE, (uint8_t)(ufeature & 0xff)); ++ gk_spinand_get_feature(chip, REG_FEATURE, &ufeature); ++ gk_spinand_release_channel(info); ++ return ufeature; ++ } ++ else ++ { ++ gk_spinand_release_channel(info); ++ return 0; ++ } ++} ++ ++static int gk_spinand_read_page_to_cache(struct spinand_chip *chip, uint32_t page_id) ++{ ++ struct spinand_info *info = chip->info; ++ ++ flash_command_s SflashCmd = {0}; ++ ++ uint32_t cmdBitSet = 0; ++ ++ // 1. page read to cache ++ cmdBitSet |= (info->commands->pageRead | // command ++ FLASH_SEND_CMD | // transfer the command ++ FLASH_SEND_ADDR_BYTE_NUM_3 | // address num ++ FLASH_SEND_DUMMY_BYTE_NUM_0 | // dummy cycle ++ FLASH_RWN_READ | // read data ++ FLASH_CMD_MODE_1X | // set the sflash cmd mode ++ FLASH_ADDR_DUMMY_CYCLE_NUM_0 | // set the sflash adr mode ++ FLASH_DATA_CYCLE_NUM_0 | // set the sflash data mode ++ FLASH_TRANSFER_BYTE_NUM_4 // transfer data number ++ ); ++ ++ SflashCmd.all = cmdBitSet; ++ spinand_set_command(SflashCmd.all); ++ spinand_set_data(page_id); // here address should be page/block address, ++ ++ return 0; ++ ++} ++ ++/** ++ * spinand_read_from_cache- send command 0x03 to read out the data from the cache register( 2112 bytes max ) ++ * ++ * Description: ++ * The read can specify 1 to 2112 bytes of data read at the coresponded locations. ++ * No tRd delay. ++ */ ++static int gk_spinand_read_from_cache( ++ struct spinand_chip *chip, ++ uint32_t byte_id, uint32_t len, ++ uint8_t* rbuf) ++{ ++ struct spinand_info *info = chip->info; ++ ++ flash_command_s SflashCmd = {0}; ++ ++ uint32_t i, ilen, tmpData; ++ uint32_t cmdBitSet = 0; ++ uint32_t feature = FLASH_FEATURE_IO1; ++ uint32_t *pData = (uint32_t*)chip->tmpbuf; ++ ++ switch((info->feature & 0x0f)) ++ { ++ default: ++ case 0x01: ++ feature = FLASH_FEATURE_IO1; ++ break; ++ case 0x02: ++ feature = FLASH_FEATURE_IO2; ++ break; ++ case 0x04: ++ feature = FLASH_FEATURE_IO4; ++ break; ++ } ++ ++ // 3. read from cache ++ if(feature == FLASH_FEATURE_IO4) ++ { ++ cmdBitSet |= (info->commands->readCacheX4 | // command ++ FLASH_SEND_CMD | // transfer the command ++ FLASH_SEND_ADDR_BYTE_NUM_2 | // address num ++ FLASH_SEND_DUMMY_BYTE_NUM_1 | // dummy cycle ++ FLASH_RWN_READ | // read data ++ FLASH_CMD_MODE_1X | // set the sflash cmd mode ++ FLASH_ADDR_DUMMY_CYCLE_NUM_0 | // set the sflash adr mode ++ FLASH_DATA_CYCLE_NUM_2 | // set the sflash data mode ++ FLASH_TRANSFER_BYTE_NUM_4 // transfer data number ++ ); ++ } ++ else if(feature == FLASH_FEATURE_IO2) ++ { ++ cmdBitSet |= (info->commands->readCacheX2 | // command ++ FLASH_SEND_CMD | // transfer the command ++ FLASH_SEND_ADDR_BYTE_NUM_2 | // address num ++ FLASH_SEND_DUMMY_BYTE_NUM_1 | // dummy cycle ++ FLASH_RWN_READ | // read data ++ FLASH_CMD_MODE_1X | // set the sflash cmd mode ++ FLASH_ADDR_DUMMY_CYCLE_NUM_0 | // set the sflash adr mode ++ FLASH_DATA_CYCLE_NUM_1 | // set the sflash data mode ++ FLASH_TRANSFER_BYTE_NUM_4 // transfer data number ++ ); ++ } ++ else ++ { ++ cmdBitSet |= (info->commands->readCache | // command ++ FLASH_SEND_CMD | // transfer the command ++ FLASH_SEND_ADDR_BYTE_NUM_2 | // address num ++ FLASH_SEND_DUMMY_BYTE_NUM_1 | // dummy cycle ++ FLASH_RWN_READ | // read data ++ FLASH_CMD_MODE_1X | // set the sflash cmd mode ++ FLASH_ADDR_DUMMY_CYCLE_NUM_0 | // set the sflash adr mode ++ FLASH_DATA_CYCLE_NUM_0 | // set the sflash data mode ++ FLASH_TRANSFER_BYTE_NUM_4 // transfer data number ++ ); ++ } ++ ++ SflashCmd.all = cmdBitSet; ++ spinand_set_command(SflashCmd.all); ++ spinand_set_data(byte_id); // Set the start address what you want to read ++ ++ ilen = ((len - 1) >> 2) + 1; ++ ++ for(i = 0; i < ilen; i++) ++ { ++ tmpData = spinand_get_data(); ++ *pData++ = uswap_32(tmpData); ++ } ++ ++ memcpy(rbuf, (uint8_t*)chip->tmpbuf, len); ++ ++ return 0; ++ ++} ++ ++/** ++ * spinand_read_page_raw-to read a page with: ++ * @page_id: the physical page number ++ * @offset: the location from 0 to 2111 ++ * @len: number of bytes to read ++ * @rbuf: read buffer to hold @len bytes ++ * ++ * Description: ++ * The read icludes two commands to the Nand: 0x13 and 0x03 commands ++ * Poll to read status to wait for tRD time. ++ */ ++static int gk_spinand_read_page_raw( ++ struct spinand_chip *chip, ++ uint32_t page_id, uint32_t offset, ++ uint32_t len, uint8_t* rbuf) ++{ ++ ssize_t retval; ++ uint32_t status = 0; ++ struct spinand_info *info = chip->info; ++ ++ #ifdef CONFIG_DEBUG_R ++ pr_info("[%s]: PageID = 0x%08x, Offset = 0x%08x, len = %d, rbufadd = 0x%x\n", ++ __FUNCTION__, page_id, offset, len, rbuf); ++ #endif ++ ++#ifdef CONFIG_MTD_SPINAND_INTERECC ++ gk_spinand_disable_ecc(chip); ++#endif ++ ++ gk_spinand_set_channel(info); ++ ++ retval = gk_spinand_read_page_to_cache(chip, page_id); ++ ++ while (1) ++ { ++ gk_spinand_get_feature(chip, REG_STATUS, &status); ++ ++ #ifdef CONFIG_DEBUG_R ++ pr_info("[%s_%d]: status = 0x%08x\n", ++ __FUNCTION__, __LINE__,status); ++ #endif ++ ++ if ((status & STATUS_OIP_MASK) == STATUS_READY) ++ { ++ break; ++ } ++ } ++ ++ retval = gk_spinand_read_from_cache(chip, offset, len, rbuf); ++ ++ gk_spinand_release_channel(info); ++ ++#ifdef CONFIG_MTD_SPINAND_INTERECC ++ gk_spinand_enable_ecc(chip); ++#endif ++ ++ return retval; ++ ++} ++ ++ ++/** ++ * spinand_read_page-to read a page with: ++ * @page_id: the physical page number ++ * @offset: the location from 0 to 2111 ++ * @len: number of bytes to read ++ * @rbuf: read buffer to hold @len bytes ++ * ++ * Description: ++ * The read icludes two commands to the Nand: 0x13 and 0x03 commands ++ * Poll to read status to wait for tRD time. ++ */ ++static int gk_spinand_read_page( ++ struct spinand_chip *chip, ++ uint32_t page_id, uint32_t offset, ++ uint32_t len, uint8_t* rbuf) ++{ ++ struct spinand_info *info = chip->info; ++ ssize_t retval; ++ uint32_t status = 0; ++ ++ #ifdef CONFIG_DEBUG_R ++ pr_info("[%s]: PageID = 0x%08x, Offset = 0x%08x, len = %d, rbufadd = 0x%x\n", ++ __FUNCTION__, page_id, offset, len, rbuf); ++ #endif ++ ++ gk_spinand_set_channel(info); ++ ++ retval = gk_spinand_read_page_to_cache(chip, page_id); ++ ++ while (1) ++ { ++ gk_spinand_get_feature(chip, REG_STATUS, &status); ++ ++ #ifdef CONFIG_DEBUG_R ++ pr_info("[%s_%d]: status = 0x%08x\n", ++ __FUNCTION__, __LINE__,status); ++ #endif ++ ++ if ((status & STATUS_OIP_MASK) == STATUS_READY) ++ { ++ if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) ++ { ++ pr_err("[%s]ecc error, page = 0x%08x\n", __FUNCTION__, page_id); ++ return -1; ++ } ++ break; ++ } ++ } ++ ++ retval = gk_spinand_read_from_cache(chip, offset, len, rbuf); ++ ++ gk_spinand_release_channel(info); ++ ++ return 0; ++ ++} ++ ++#define RET_OK 0 ++ ++#define WRITE_BYTE 0x1 ++#define WRITE_WORD 0x2 ++#define WRITE_LWORD 0x4 ++#define WRITE_CLWORD 0x1f ++ ++ ++static int gk_spinand_write_to_cache( ++ struct spinand_chip *chip, uint32_t offset, uint32_t dflag) ++{ ++ struct spinand_info *info = chip->info; ++ ++ flash_command_s SflashCmd = {0}; ++ ++ uint32_t cmdBitSet = 0; ++ uint32_t feature = FLASH_FEATURE_IO1; ++ ++#ifdef CONFIG_DEBUG_W ++ printk("[DEBUG_W]: %s\n", __FUNCTION__); ++ { ++ int i = 0, j = 0; ++ uint8_t* buf = (uint8_t*)chip->tmpbuf; ++ ++ for(i = 0,j = 0; i < 128; i++,j++) ++ { ++ if(j % 16 == 0) ++ { ++ printk("\n"); ++ } ++ printk("%02x ", buf[i]); ++ } ++ ++ printk("\n"); ++ } ++#endif ++ ++ ++ switch(((info->feature >> 4) & 0x0f)) ++ { ++ default: ++ case 0x01: ++ feature = FLASH_FEATURE_IO1; ++ break; ++ case 0x02: ++ feature = FLASH_FEATURE_IO2; ++ break; ++ case 0x04: ++ feature = FLASH_FEATURE_IO4; ++ break; ++ } ++ ++ if(feature == FLASH_FEATURE_IO4) ++ { ++ cmdBitSet |= (info->commands->programLoadX4 | // command ++ FLASH_SEND_CMD | // transfer the command ++ FLASH_SEND_ADDR_BYTE_NUM_2 | // address num ++ FLASH_SEND_DUMMY_BYTE_NUM_0 | // dummy cycle ++ FLASH_RWN_WRITE | // write data ++ FLASH_CMD_MODE_1X | // set the sflash cmd mode ++ FLASH_ADDR_DUMMY_CYCLE_NUM_0 | // set the sflash adr mode ++ FLASH_DATA_CYCLE_NUM_2 | // set the sflash data mode ++ dflag << FLASH_TRANSFER_BYTE_LOC | // transfer data number ++ FLASH_HOLD_TIME_100ns ++ ); ++ } ++ else if(feature == FLASH_FEATURE_IO2) ++ { ++ /* no supported */ ++ cmdBitSet |= (info->commands->programLoad | // command ++ FLASH_SEND_CMD | // transfer the command ++ FLASH_SEND_ADDR_BYTE_NUM_2 | // address num ++ FLASH_SEND_DUMMY_BYTE_NUM_0 | // dummy cycle ++ FLASH_RWN_WRITE | // write data ++ FLASH_CMD_MODE_1X | // set the sflash cmd mode ++ FLASH_ADDR_DUMMY_CYCLE_NUM_0 | // set the sflash adr mode ++ FLASH_DATA_CYCLE_NUM_1 | // set the sflash data mode ++ dflag << FLASH_TRANSFER_BYTE_LOC | // transfer data number ++ FLASH_HOLD_TIME_100ns ++ ); ++ } ++ else ++ { ++ cmdBitSet |= (info->commands->programLoad | // command ++ FLASH_SEND_CMD | // transfer the command ++ FLASH_SEND_ADDR_BYTE_NUM_2 | // address num ++ FLASH_SEND_DUMMY_BYTE_NUM_0 | // dummy cycle ++ FLASH_RWN_WRITE | // write data ++ FLASH_CMD_MODE_1X | // set the sflash cmd mode ++ FLASH_ADDR_DUMMY_CYCLE_NUM_0 | // set the sflash adr mode ++ FLASH_DATA_CYCLE_NUM_0 | // set the sflash data mode ++ dflag << FLASH_TRANSFER_BYTE_LOC | // transfer data number ++ FLASH_HOLD_TIME_100ns ++ ); ++ } ++ ++ SflashCmd.all = cmdBitSet; ++ spinand_set_command(SflashCmd.all); ++ spinand_set_data(offset); // Set the start address what you want to write ++ ++ return RET_OK; ++ ++} ++ ++/** ++ * gk_spinand_program_data_to_cache -- to write a page to cache with: ++ * @byte_id: the location to write to the cache ++ * @len: number of bytes to write ++ * @rbuf: read buffer to hold @len bytes ++ * ++ * Description: ++ * The write command used here is 0x84--indicating that the cache is not cleared first. ++ * Since it is writing the data to cache, there is no tPROG time. ++ */ ++static int gk_spinand_program_data_to_cache( ++ struct spinand_chip *chip, uint32_t offset, ++ uint32_t len, uint8_t* wbuf) ++{ ++ ++ ++ uint32_t i, u4Len, uleftLen, dflag = WRITE_CLWORD, wdata, doff; ++ uint32_t uTmpData; ++ ++#ifndef CONFIG_NAND_SPL ++ uint32_t *pData = (uint32_t*)chip->tmpbuf; ++#else ++ uint32_t *pData = (uint32_t*)wbuf; ++#endif ++ ++ /* calc the length of data(unit:long word) */ ++ u4Len = len >> 2; ++ uleftLen = len % 4; ++ doff = 0; ++ ++#ifndef CONFIG_NAND_SPL ++ /* copy data to temporary 4 bytes align buffer */ ++ memcpy((uint8_t*)pData, (wbuf + offset), (u4Len << 2)); ++#endif ++ ++ /* write the data which length is a multiple of 4 bytes to cache firstly */ ++ if(u4Len > 0) ++ { ++ dflag = WRITE_CLWORD; ++ gk_spinand_write_to_cache(chip, offset, dflag); ++ for(i = 0; i < u4Len; i++) ++ { ++ uTmpData = *pData++; ++ uTmpData = uswap_32(uTmpData); ++ spinand_set_data(uTmpData); ++ } ++ ++ doff += (u4Len << 2); ++ } ++ ++ i = 0; ++ ++ /* write the left data to cache */ ++ while(uleftLen) ++ { ++ dflag = WRITE_BYTE; ++ doff += i; ++ wdata = (uint32_t)wbuf[doff]; ++ gk_spinand_write_to_cache(chip, (offset + doff), dflag); ++ spinand_set_data(wdata); ++ uleftLen--; ++ } ++ ++ return RET_OK; ++ ++} ++ ++/** ++ * gk_spinand_program_execute -- to write a page from cache to the Nand array with: ++ * @page_id: the physical page location to write the page. ++ * ++ * Description: ++ * The write command used here is 0x10--indicating the cache is writing to the Nand array. ++ * Need to wait for tPROG time to finish the transaction. ++ */ ++static int gk_spinand_program_execute(struct spinand_chip *chip, uint32_t page_id) ++{ ++ struct spinand_info *info = chip->info; ++ ++ flash_command_s SflashCmd = {0}; ++ ++ uint32_t cmdBitSet = 0; ++ ++ cmdBitSet |= (info->commands->progExecute | // command ++ FLASH_SEND_CMD | // transfer the command ++ FLASH_SEND_ADDR_BYTE_NUM_3 | // address num ++ FLASH_SEND_DUMMY_BYTE_NUM_0 | // dummy cycle ++ FLASH_RWN_WRITE | // write data ++ FLASH_CMD_MODE_1X | // set the sflash cmd mode ++ FLASH_ADDR_DUMMY_CYCLE_NUM_0 | // set the sflash adr mode ++ FLASH_DATA_CYCLE_NUM_0 | // set the sflash data mode ++ FLASH_TRANSFER_BYTE_NUM_4 | // transfer data number ++ FLASH_HOLD_TIME_100ns ++ ); ++ ++ SflashCmd.all = cmdBitSet; ++ spinand_set_command(SflashCmd.all); ++ spinand_set_data(page_id); // here address should be page/block address, ++ ++ return 0; ++ ++} ++ ++/** ++ * gk_spinand_program_page_raw--to write a page with: ++ * @page_id: the physical page location to write the page. ++ * @offset: the location from the cache starting from 0 to 2111 ++ * @len: the number of bytes to write ++ * @wbuf: the buffer to hold the number of bytes ++ * ++ * Description: ++ * The commands used here are 0x06, 0x84, and 0x10--indicating that the write enable is first ++ * sent, the write cache command, and the write execute command ++ * Poll to wait for the tPROG time to finish the transaction. ++ */ ++static int gk_spinand_program_page_raw( ++ struct spinand_chip *chip, ++ uint32_t page_id, uint32_t offset, ++ uint32_t len, uint8_t* wbuf) ++{ ++ ssize_t retval; ++ uint32_t status = 0; ++ struct spinand_info *info = chip->info; ++ ++ #ifdef CONFIG_DEBUG_W ++ pr_info("[%s]: PageID = 0x%08x, rbufadd = 0x%x\n", ++ __FUNCTION__, page_id, wbuf); ++ #endif ++ ++#ifdef CONFIG_MTD_SPINAND_INTERECC ++ gk_spinand_disable_ecc(chip); ++#endif ++ ++ gk_spinand_set_channel(info); ++ ++ retval = gk_spinand_write_enable(chip, WR_ENABLE); ++ ++ retval = gk_spinand_program_data_to_cache(chip, offset, len, wbuf); ++ ++ retval = gk_spinand_program_execute(chip, page_id); ++ ++ while (1) ++ { ++ gk_spinand_get_feature(chip, REG_STATUS, &status); ++ ++ if ((status & STATUS_OIP_MASK) == STATUS_READY) ++ { ++ break; ++ } ++ } ++ ++ gk_spinand_release_channel(info); ++ ++#ifdef CONFIG_MTD_SPINAND_INTERECC ++ gk_spinand_enable_ecc(chip); ++#endif ++ ++ ++ return 0; ++ ++} ++ ++/** ++ * spinand_program_page--to write a page with: ++ * @page_id: the physical page location to write the page. ++ * @offset: the location from the cache starting from 0 to 2111 ++ * @len: the number of bytes to write ++ * @wbuf: the buffer to hold the number of bytes ++ * ++ * Description: ++ * The commands used here are 0x06, 0x84, and 0x10--indicating that the write enable is first ++ * sent, the write cache command, and the write execute command ++ * Poll to wait for the tPROG time to finish the transaction. ++ */ ++static int gk_spinand_program_page( ++ struct spinand_chip *chip, ++ uint32_t page_id, uint32_t offset, ++ uint32_t len, uint8_t* wbuf) ++{ ++ struct spinand_info *info = chip->info; ++ ssize_t retval; ++ uint32_t status = 0; ++ ++#ifdef CONFIG_DEBUG_W ++ pr_info("[%s]: blockId = %d, PageID = 0x%08x\n", ++ __FUNCTION__, page_id/info->page_per_block, page_id); ++#endif ++ ++ gk_spinand_set_channel(info); ++ ++ retval = gk_spinand_write_enable(chip, WR_ENABLE); ++ ++ retval = gk_spinand_program_data_to_cache(chip, offset, len, wbuf); ++ ++ retval = gk_spinand_program_execute(chip, page_id); ++ ++ while (1) ++ { ++ gk_spinand_get_feature(chip, REG_STATUS, &status); ++ ++ if ((status & STATUS_OIP_MASK) == STATUS_READY) ++ { ++ if ((status & STATUS_P_FAIL_MASK) == STATUS_P_FAIL) ++ { ++ pr_err("[%s]: program error, page = 0x%08x\n", __FUNCTION__, page_id); ++ gk_spinand_release_channel(info); ++ return -1; ++ } ++ else ++ { ++ break; ++ } ++ } ++ } ++ gk_spinand_release_channel(info); ++ ++ return 0; ++ ++} ++ ++/** ++ * spinand_erase_block_do -- to erase a block with: ++ * @block_id: the physical block location to erase. ++ * ++ * Description: ++ * The command used here is 0xd8--indicating an erase command to erase one block--64 pages ++ * Need to wait for tERS. ++ */ ++static int gk_spinand_erase_block_do(struct spinand_chip *chip, uint32_t block_id) ++{ ++ struct spinand_info *info = chip->info; ++ ++ uint32_t cmdBitSet = 0; ++ ++ flash_command_s SflashCmd = {0}; ++ ++ cmdBitSet |= (info->commands->blockErase | // command ++ FLASH_SEND_CMD | // transfer the command ++ FLASH_SEND_ADDR_BYTE_NUM_3 | // address num ++ FLASH_SEND_DUMMY_BYTE_NUM_0 | // dummy cycle ++ FLASH_RWN_WRITE | // write data ++ FLASH_CMD_MODE_1X | // set the sflash cmd mode ++ FLASH_ADDR_DUMMY_CYCLE_NUM_0 | // set the sflash adr mode ++ FLASH_DATA_CYCLE_NUM_0 | // set the sflash data mode ++ FLASH_TRANSFER_BYTE_NUM_4 | // transfer data number ++ FLASH_HOLD_TIME_100ns ++ ); ++ ++ SflashCmd.all = cmdBitSet; ++ spinand_set_command(SflashCmd.all); ++ spinand_set_data(block_id); ++ ++ return 0; ++ ++} ++ ++/** ++ * spinand_erase_block--to erase a page with: ++ * @block_id: the physical block location to erase. ++ * ++ * Description: ++ * The commands used here are 0x06 and 0xd8--indicating an erase command to erase one block--64 pages ++ * It will first to enable the write enable bit ( 0x06 command ), and then send the 0xd8 erase command ++ * Poll to wait for the tERS time to complete the tranaction. ++ */ ++static int gk_spinand_erase_block(struct spinand_chip *chip, uint32_t block_id) ++{ ++ struct spinand_info *info = chip->info; ++ ssize_t retval; ++ uint32_t status = 0; ++ ++ gk_spinand_set_channel(info); ++ ++ retval = gk_spinand_write_enable(chip, WR_ENABLE); ++ ++ retval = gk_spinand_erase_block_do(chip, block_id); ++ ++ while(1) ++ { ++ gk_spinand_get_feature(chip, REG_STATUS, &status); ++ ++ if ((status & STATUS_OIP_MASK) == STATUS_READY) ++ { ++ if ((status & STATUS_E_FAIL_MASK) == STATUS_E_FAIL) ++ { ++ pr_err("%s: erase error, block = %d\n", __FUNCTION__, block_id/info->page_per_block); ++ gk_spinand_release_channel(info); ++ return -1; ++ } ++ else ++ break; ++ } ++ } ++ gk_spinand_release_channel(info); ++ ++ return 0; ++ ++} ++ ++/**************************************************************/ ++/* */ ++/**************************************************************/ ++static struct spinand_info* gk_get_spinand_info(struct platform_device *dev) ++{ ++ uint32_t sflashData; ++ uint8_t mID; ++ uint16_t dID; ++ uint32_t index; ++ uint32_t count; ++ uint32_t CESetting = 0x0E; ++ uint32_t cmdBitSet = 0; ++ ++ struct spinand_info* sninfo; ++ struct gk_spinand_platform_data *platform_data = dev->dev.platform_data; ++ flash_command_s SflashCmd; ++ ++ uint32_t channel = platform_data->channel; ++ uint32_t speed_mode = platform_data->speed_mode; ++ ++ pr_info("%s: SPINAND Channel = %d, SpeedMode = %d !\n", __FUNCTION__, channel, speed_mode); ++ ++ if(channel >= FLASH_CHANNEL_NUM) ++ { ++ return NULL; ++ } ++ ++ CESetting = CESetting | ((uint32_t)channel << 6); ++ ++ spinand_set_ce (CESetting); ++ spinand_set_speed (speed_mode); //0 -- 1/2freq 1--1/4freq 2....4 ++ ++ CESetting = spinand_get_ce(); ++ speed_mode = spinand_get_speed(); ++// pr_info("%s: CE = 0x%08x, SpeedMode = 0x%08x !\n", __FUNCTION__, CESetting, speed_mode); ++ ++ // spi nand flash: send readID cmd ++ cmdBitSet |= (FLASH_SEND_CMD| // transfer the command ++ FLASH_SEND_ADDR_BYTE_NUM_1| // address num ++ FLASH_SEND_DUMMY_BYTE_NUM_0| // dummy cycle ++ FLASH_RWN_READ| // read data ++ FLASH_CMD_MODE_1X| // set the sflash cmd mode ++ FLASH_ADDR_DUMMY_CYCLE_NUM_0| // set the sflash adr mode ++ FLASH_DATA_CYCLE_NUM_0| // set the sflash data mode ++ (3 << FLASH_TRANSFER_BYTE_LOC) // transfer data number ++ ); ++ ++ cmdBitSet |= CMD_READ_ID; // readID command ++ SflashCmd.all = cmdBitSet; ++ spinand_set_command(SflashCmd.all); ++ spinand_set_data(0x00); ++ sflashData = spinand_get_data(); ++ ++ mID = (uint8_t)((sflashData & 0x00FF0000) >> 16); ++ dID = (uint16_t)(sflashData & 0x0000FFFF); ++ ++ pr_info("%s: SPINAND MID = 0x%x, DID = 0x%x, Data = 0x%x !\n", ++ __FUNCTION__, mID, dID, sflashData); ++ ++ count = sizeof(spinand_devices_supported)/sizeof(struct spinand_info); ++ ++ for(index = 0; index < count; index++) ++ { ++ sninfo = &(spinand_devices_supported[index]); ++ if((mID == sninfo->mid) && ++ (dID == sninfo->did)) ++ { ++ spinand_set_ce_chselect(!channel); ++ return( sninfo ); ++ } ++ } ++ spinand_set_ce_chselect(!channel); ++ ++ return NULL; ++ ++} ++ ++/** ++ * spinand_probe - [spinand Interface] ++* @spi_nand: registered device driver. ++ * ++ * Description: ++ * To set up the device driver parameters to make the device available. ++ */ ++static int __devinit gk_spinand_probe(struct platform_device *pdev) ++{ ++ struct gk_spinand_host *host; ++ struct spinand_chip *chip; ++ struct spinand_info *info; ++ ++ int res = 0; ++ ++ info = gk_get_spinand_info(pdev); ++ if (!info) ++ { ++ dev_err(&pdev->dev, "No support this SPI nand!\n"); ++ return -ENOMEM; ++ } ++ ++ pr_err("%s: %s (%lld Kbytes)\n", __FUNCTION__, info->deviceName, ++ (long long)info->nand_size >> 10); ++ ++ host = kzalloc(sizeof(struct gk_spinand_host), GFP_KERNEL); ++ if (!host) ++ { ++ dev_err(&pdev->dev, "no memory for NAND host context\n"); ++ return -ENOMEM; ++ } ++ host->io_base = (void*)REG_SFLASH_DATA; ++ ++ platform_set_drvdata(pdev, host); ++ ++ /* Initialize the SPI nand chip information */ ++ chip = &(host->chip); ++ chip->mtd = &host->mtd; ++ chip->priv = host; ++ chip->info = info; ++ ++ chip->reset = gk_spinand_reset; ++ chip->read_id = gk_spinand_read_id; ++ chip->read_page = gk_spinand_read_page; ++ chip->read_page_raw = gk_spinand_read_page_raw; ++ chip->program_page = gk_spinand_program_page; ++ chip->program_page_raw = gk_spinand_program_page_raw; ++ chip->erase_block = gk_spinand_erase_block; ++ chip->scan_bbt = NULL; ++ chip->block_markbad = NULL; ++ chip->block_bad = NULL; ++ chip->chip_delay = 50; ++ chip->chip_id = info->channel; ++ chip->chipsize = info->usable_size; ++ chip->options = NAND_NO_READRDY; ++ ++ chip->badblockpos = info->badblock_pattern->offs; ++ chip->badblockbits = info->badblockbits; ++// chip->bbt_options = NAND_BBT_NO_OOB | NAND_BBT_USE_FLASH ++// | NAND_BBT_CREATE | NAND_BBT_WRITE; ++ chip->bbt_options = NAND_BBT_NO_OOB | NAND_BBT_CREATE | NAND_BBT_WRITE; ++ chip->bbt_erase_shift = chip->phys_erase_shift = ffs(info->block_main_size) - 1; ++ chip->page_shift = info->page_shift; ++ chip->bbt = NULL; ++ chip->bbt_td = NULL; ++ chip->bbt_md = NULL; ++ chip->badblock_pattern = info->badblock_pattern; ++ ++ /* Convert chipsize to number of pages per chip -1. */ ++ chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; ++ ++ mutex_init(&chip->lock); ++ ++ chip->buffers = kzalloc(sizeof(struct nand_buffers), GFP_KERNEL); ++ if (!chip->buffers) ++ { ++ dev_err(&pdev->dev, "[%s]no memory for NAND data buffer\n", __FUNCTION__); ++ res = -ENOMEM; ++ goto fail_err0; ++ } ++ chip->pagebuf = chip->buffers->databuf; ++ ++ /* Set the internal oob buffer location, just after the page data */ ++ chip->oob_poi = (chip->pagebuf + info->page_main_size); ++ ++ chip->oobbuf = kzalloc((info->page_size + 7), GFP_KERNEL); ++ if (!chip->oobbuf) ++ { ++ dev_err(&pdev->dev, "[%s]no memory for NAND tmp data buffer\n", __FUNCTION__); ++ res = -ENOMEM; ++ goto fail_err1; ++ } ++ ++ chip->tmpbuf = (uint32_t*)(((uint32_t)(chip->oobbuf + 3)) & 0xfffffffc);/* 4bytes alige */ ++ ++ res = gk_spinand_unlock_allblock(chip); ++#ifdef CONFIG_MTD_SPINAND_INTERECC ++ res = gk_spinand_enable_ecc(chip); ++#else ++ res = gk_spinand_disable_ecc(chip); ++#endif ++ ++ /* Initialize the SPI nand MTD information */ ++ host->mtd.priv = chip; ++ host->mtd.dev.parent = &pdev->dev; ++ res = spinand_scan(&(host->mtd)); ++ if (res) ++ { ++ dev_err(&pdev->dev, "[%s_%d]NAND scan failed with %d\n", __FUNCTION__, __LINE__, res); ++ res = -ENOMEM; ++ goto fail_err2; ++ } ++ ++ res = mtd_device_register(&(host->mtd), gk_spinand_partitions, NUM_PARTITIONS); ++ if (res) ++ { ++ dev_err(&pdev->dev, "[%s_%d]MTD device register error!\n", __FUNCTION__, __LINE__); ++ res = -ENOMEM; ++ goto fail_err2; ++ } ++ ++ return 0; ++ ++fail_err2: ++ kfree(chip->oobbuf); ++fail_err1: ++ kfree(chip->buffers); ++fail_err0: ++ kfree(host); ++ ++ return res; ++ ++} ++ ++/** ++ * __devexit spinand_remove--Remove the device driver ++ * @spi: the spi device. ++ * ++ * Description: ++ * To remove the device driver parameters and free up allocated memories. ++ */ ++static int __devexit gk_spinand_remove(struct platform_device *pdev) ++{ ++ struct mtd_info *mtd; ++ struct spinand_chip *chip; ++ struct gk_spinand_host *host; ++ ++ pr_info("%s: remove\n", dev_name(&pdev->dev)); ++ ++ host = dev_get_drvdata(&pdev->dev); ++ ++ mtd = &host->mtd; ++ mtd_device_unregister(mtd); ++ ++ chip = &host->chip; ++ ++ kfree(chip->oobbuf); ++ kfree(chip->buffers); ++ kfree(host); ++ ++ return 0; ++ ++} ++ ++#ifdef CONFIG_PM ++static int gk_spinand_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ return 0; ++} ++ ++static int gk_spinand_resume(struct platform_device *pdev) ++{ ++ return 0; ++} ++#else ++#define gk_spinand_suspend NULL ++#define gk_spinand_resume NULL ++#endif ++ ++static struct gk_spinand_platform_data gk_spinand_data = ++{ ++ .speed_mode = SYSTEM_SFLASH_FREQ, // LindengYu: use the 138 div 2 = 69MHz ++ .channel = 1, ++ .parts = gk_spinand_partitions, ++ .nr_parts = NUM_PARTITIONS, ++}; ++ ++/** ++ * Device name structure description ++*/ ++static struct platform_device gk_spinand_device = { ++ ++ .name = "gk_spi_nand", ++ .id = 1, ++ .dev = ++ { ++ .platform_data = &gk_spinand_data, ++ }, ++}; ++ ++ ++/** ++ * Device name structure description ++*/ ++static struct platform_driver gk_spinand_driver = { ++ .driver = { ++ .name = "gk_spi_nand", ++ .bus = &platform_bus_type, ++ .owner = THIS_MODULE, ++ }, ++ ++ .probe = gk_spinand_probe, ++ .remove = __devexit_p(gk_spinand_remove), ++ .suspend = gk_spinand_suspend, ++ .resume = gk_spinand_resume, ++}; ++ ++/** ++ * Device driver registration ++*/ ++static int __init gk_spinand_init(void) ++{ ++ int ret = 0; ++ ++ ret = platform_driver_register(&gk_spinand_driver); ++ ++ if(!ret) ++ { ++ ret = platform_device_register(&gk_spinand_device); ++ if(ret) ++ { ++ platform_driver_unregister(&gk_spinand_driver); ++ } ++ } ++ return ret; ++} ++ ++/** ++ * unregister Device driver. ++*/ ++static void __exit gk_spinand_exit(void) ++{ ++ platform_device_unregister(&gk_spinand_device); ++ platform_driver_unregister(&gk_spinand_driver); ++} ++ ++module_init(gk_spinand_init); ++module_exit(gk_spinand_exit); ++ ++MODULE_DESCRIPTION("GOKE SPI NAND driver"); ++MODULE_AUTHOR("Goke Microelectronics Inc."); ++MODULE_LICENSE("GPL"); ++ ++ +diff --git a/drivers/mtd/spinand/gk_spinand_v1_00.h b/drivers/mtd/spinand/gk_spinand_v1_00.h +new file mode 100644 +index 00000000..dce7791a +--- /dev/null ++++ b/drivers/mtd/spinand/gk_spinand_v1_00.h +@@ -0,0 +1,669 @@ ++/* ++ * drivers/mtd/spinand/gk_spinand_v1_00.h ++ * ++ * gk soc ++ * ++ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++#include ++#include ++ ++/* send cmd or not [ 8]*/ ++#define FLASH_SEND_CMD 0x00000100 ++#define FLASH_NO_SEND_CMD 0x00000000 ++ ++ /* byte number of address to send [11:9]*/ ++#define FLASH_SEND_ADDR_BYTE_NUM_0 0x00000000 ++#define FLASH_SEND_ADDR_BYTE_NUM_1 0x00000200 ++#define FLASH_SEND_ADDR_BYTE_NUM_2 0x00000400 ++#define FLASH_SEND_ADDR_BYTE_NUM_3 0x00000600 ++#define FLASH_SEND_ADDR_BYTE_NUM_4 0x00000800 ++#define FLASH_SEND_ADDR_BYTE_NUM_5 0x00000a00 ++#define FLASH_SEND_ADDR_BYTE_NUM_6 0x00000c00 ++#define FLASH_SEND_ADDR_BYTE_NUM_7 0x00000e00 ++ ++ /*Byte number of dummy cycle to send [14:12]*/ ++ ++#define FLASH_SEND_DUMMY_BYTE_NUM_0 0x000000000 ++#define FLASH_SEND_DUMMY_BYTE_NUM_1 0x000001000 ++#define FLASH_SEND_DUMMY_BYTE_NUM_2 0x000002000 ++#define FLASH_SEND_DUMMY_BYTE_NUM_3 0x000003000 ++#define FLASH_SEND_DUMMY_BYTE_NUM_4 0x000004000 ++#define FLASH_SEND_DUMMY_BYTE_NUM_5 0x000005000 ++#define FLASH_SEND_DUMMY_BYTE_NUM_6 0x000006000 ++#define FLASH_SEND_DUMMY_BYTE_NUM_7 0x000007000 ++ ++ /* Command operation[16:15]: 00 for read data from SF; 01 for write data to SF; 11 for nothing to do */ ++ ++#define FLASH_RWN_READ 0x00000000 ++#define FLASH_RWN_WRITE 0x00008000 ++#define FLASH_RWN_NOTHING 0x00018000 ++ ++ /*I/O mode of command cycle to SF[18:17]: 00 for x1; 01 for x2; 10 for x4*/ ++#define FLASH_CMD_MODE_1X 0x00000000 ++#define FLASH_CMD_MODE_2X 0x00020000 ++#define FLASH_CMD_MODE_4X 0x00040000 ++ ++ /* I/O mode of address and dummy cycle to SF[20:19]*/ ++#define FLASH_ADDR_DUMMY_CYCLE_NUM_0 0x00000000 ++#define FLASH_ADDR_DUMMY_CYCLE_NUM_1 0x00080000 ++#define FLASH_ADDR_DUMMY_CYCLE_NUM_2 0x00100000 ++#define FLASH_ADDR_DUMMY_CYCLE_NUM_3 0x00180000 ++ ++ /*I/O mode of data cycle to or from SF [22:21] */ ++ ++#define FLASH_DATA_CYCLE_NUM_0 0x00000000 ++#define FLASH_DATA_CYCLE_NUM_1 0x00200000 ++#define FLASH_DATA_CYCLE_NUM_2 0x00400000 ++#define FLASH_DATA_CYCLE_NUM_3 0x00600000 ++ ++ /*Transfer data byte number to or from SF[27:23]. For 11111 case, transfer 4bytes per request. For other case, transfer number bytes.*/ ++ ++#define FLASH_TRANSFER_BYTE_NUM_4 0x0f800000 ++#define FLASH_TRANSFER_BYTE_LOC 23 ++ ++#define FLASH_HOLD_TIME_100ns 0x00000000 ++#define FLASH_HOLD_TIME_3us 0x10000000 ++#define FLASH_HOLD_TIME_100us 0x20000000 ++ ++ /*! ++ ******************************************************************************* ++ ** ++ ** \brief Flash channel number. ++ ** ++ ******************************************************************************* ++ */ ++ typedef enum ++ { ++ FLASH_CHANNEL_0 = 0, ++ FLASH_CHANNEL_1, ++ FLASH_CHANNEL_NUM ++ }flash_channel_e; ++ ++ /*! ++ ******************************************************************************* ++ ** ++ ** \brief Flash I/O feature. ++ ** ++ ******************************************************************************* ++ */ ++ typedef enum ++ { ++ FLASH_FEATURE_IO1 = 0, ++ FLASH_FEATURE_IO2, ++ FLASH_FEATURE_IO4 ++ }flash_feature_e; ++ ++ ++/*----------------------------------------------------------------------------*/ ++/* bit group structures */ ++/*----------------------------------------------------------------------------*/ ++typedef union { /* SFLASH_Command */ ++ uint32_t all; ++ struct { ++ uint32_t code : 8; ++ uint32_t sendcmd : 1; ++ uint32_t adrnum : 3; ++ uint32_t dummynum : 3; ++ uint32_t rwn : 2; ++ uint32_t cmdmode : 2; ++ uint32_t adrmode : 2; ++ uint32_t datamode : 2; ++ uint32_t datanum : 5; ++ uint32_t holdtime : 2; ++ uint32_t : 2; ++ } bitc; ++}flash_command_s; ++ ++ typedef union { /* SFLASH_CE */ ++ uint32_t all; ++ struct { ++ uint32_t ce : 1; ++ uint32_t wp : 1; ++ uint32_t hold : 1; ++ uint32_t cemode : 1; ++ uint32_t wpmode : 1; ++ uint32_t holdmode : 1; ++ uint32_t chselect : 1; ++ uint32_t : 25; ++ } bitc; ++}flash_ce_s; ++ ++typedef union { /* SFLASH_Speed */ ++ uint32_t all; ++ struct { ++ uint32_t sf_sclk_sel : 3; ++ uint32_t : 29; ++ } bitc; ++} flash_speed_s; ++ ++typedef union { /* SFLASH_PARA_XIP */ ++ uint32_t all; ++ struct { ++ uint32_t sflash_command : 8; ++ uint32_t : 1; ++ uint32_t adr_num : 3; ++ uint32_t dummy_num : 3; ++ uint32_t : 2; ++ uint32_t cmd_mod : 2; ++ uint32_t adr_mod : 2; ++ uint32_t data_mod : 2; ++ uint32_t : 1; ++ uint32_t dumy_data : 8; ++ } bitc; ++} flash_para_xip_s; ++ ++ /*----------------------------------------------------------------------------*/ ++/* register SFLASH_Data (read/write) */ ++/*----------------------------------------------------------------------------*/ ++void spinand_set_data (uint32_t data) ++{ ++ gk_ssi_writel(REG_SFLASH_DATA, data); ++ //*(volatile uint32_t *)REG_SFLASH_DATA = data; ++} ++uint32_t spinand_get_data (void) ++{ ++ return gk_ssi_readl(REG_SFLASH_DATA); ++ //return (*(volatile uint32_t *)REG_SFLASH_DATA); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/* register SFLASH_Command (read/write) */ ++/*----------------------------------------------------------------------------*/ ++void spinand_set_command(uint32_t data) ++{ ++ gk_ssi_writel(REG_SFLASH_COMMAND, data); ++ //*(volatile uint32_t *)REG_SFLASH_COMMAND = data; ++} ++uint32_t spinand_get_command (void) ++{ ++ return gk_ssi_readl(REG_SFLASH_COMMAND); ++ //return (*(volatile uint32_t *)REG_SFLASH_COMMAND); ++} ++void spinand_set_command_code(uint8_t data) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_COMMAND; ++ d.bitc.code = data; ++ gk_ssi_writel(REG_SFLASH_COMMAND, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_COMMAND = d.all; ++} ++uint8_t spinand_get_command_code(void) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ return d.bitc.code; ++ ++ //return (*(volatile flash_command_s *)REG_SFLASH_COMMAND).bitc.code; ++} ++void spinand_set_command_sendcmd(uint8_t data) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_COMMAND; ++ d.bitc.sendcmd = data; ++ gk_ssi_writel(REG_SFLASH_COMMAND, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_COMMAND = d.all; ++} ++uint8_t spinand_get_command_sendcmd(void) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ return d.bitc.sendcmd; ++ ++ //return (*(volatile flash_command_s *)REG_SFLASH_COMMAND).bitc.sendcmd; ++} ++void spinand_set_command_adrnum (uint8_t data) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_COMMAND; ++ d.bitc.adrnum = data; ++ gk_ssi_writel(REG_SFLASH_COMMAND, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_COMMAND = d.all; ++} ++uint8_t spinand_get_command_adrnum (void) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ return d.bitc.adrnum; ++ ++ //return (*(volatile flash_command_s *)REG_SFLASH_COMMAND).bitc.adrnum; ++} ++void spinand_set_command_dummynum (uint8_t data) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_COMMAND; ++ d.bitc.dummynum = data; ++ gk_ssi_writel(REG_SFLASH_COMMAND, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_COMMAND = d.all; ++} ++uint8_t spinand_get_command_dummynum (void) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ return d.bitc.dummynum; ++ ++ //return (*(volatile flash_command_s *)REG_SFLASH_COMMAND).bitc.dummynum; ++} ++void spinand_set_command_rwn(uint8_t data) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_COMMAND; ++ d.bitc.rwn = data; ++ gk_ssi_writel(REG_SFLASH_COMMAND, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_COMMAND = d.all; ++} ++uint8_t spinand_get_command_rwn (void) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ return d.bitc.rwn; ++ ++ //return (*(volatile flash_command_s *)REG_SFLASH_COMMAND).bitc.rwn; ++} ++void spinand_set_command_cmdmode (uint8_t data) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_COMMAND; ++ d.bitc.cmdmode = data; ++ gk_ssi_writel(REG_SFLASH_COMMAND, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_COMMAND = d.all; ++} ++uint8_t spinand_get_command_cmdmode (void) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ return d.bitc.cmdmode; ++ ++ //return (*(volatile flash_command_s *)REG_SFLASH_COMMAND).bitc.cmdmode; ++} ++void spinand_set_command_adrmode (uint8_t data) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_COMMAND; ++ d.bitc.adrmode = data; ++ gk_ssi_writel(REG_SFLASH_COMMAND, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_COMMAND = d.all; ++} ++uint8_t spinand_get_command_adrmode (void) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ return d.bitc.adrmode; ++ ++ //return (*(volatile flash_command_s *)REG_SFLASH_COMMAND).bitc.adrmode; ++} ++void spinand_set_command_datamode(uint8_t data) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_COMMAND; ++ d.bitc.datamode = data; ++ gk_ssi_writel(REG_SFLASH_COMMAND, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_COMMAND = d.all; ++} ++uint8_t spinand_get_command_datamode(void) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ return d.bitc.datamode; ++ ++ ++ //return (*(volatile flash_command_s *)REG_SFLASH_COMMAND).bitc.datamode; ++} ++void spinand_set_command_datanum (uint8_t data) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_COMMAND; ++ d.bitc.datanum = data; ++ gk_ssi_writel(REG_SFLASH_COMMAND, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_COMMAND = d.all; ++} ++uint8_t spinand_get_command_datanum (void) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ return d.bitc.datanum; ++ ++ //return (*(volatile flash_command_s *)REG_SFLASH_COMMAND).bitc.datanum; ++} ++void spinand_set_command_holdtime (uint8_t data) ++{ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_COMMAND; ++ d.bitc.holdtime = data; ++ gk_ssi_writel(REG_SFLASH_COMMAND, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_COMMAND = d.all; ++} ++uint8_t spinand_get_command_holdtime (void) ++{ ++ ++ flash_command_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_COMMAND); ++ return d.bitc.holdtime; ++ ++ //return (*(volatile flash_command_s *)REG_SFLASH_COMMAND).bitc.holdtime; ++} ++ ++ ++/*----------------------------------------------------------------------------*/ ++/* register SFLASH_CE (read/write) */ ++/*----------------------------------------------------------------------------*/ ++void spinand_set_ce (uint32_t data) ++{ ++ gk_ssi_writel(REG_SFLASH_CE, data); ++ //*(volatile uint32_t *)REG_SFLASH_CE = data; ++} ++uint32_t spinand_get_ce(void) ++{ ++ return gk_ssi_readl(REG_SFLASH_CE); ++ //return (*(volatile uint32_t *)REG_SFLASH_CE); ++} ++void spinand_set_ce_ce(uint8_t data) ++{ ++ flash_ce_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_CE); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_CE; ++ d.bitc.ce = data; ++ gk_ssi_writel(REG_SFLASH_CE, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_CE = d.all; ++} ++uint8_t spinand_get_ce_ce(void) ++{ ++ ++ flash_ce_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_CE); ++ return d.bitc.ce; ++ ++ //return (*(volatile flash_ce_s *)REG_SFLASH_CE).bitc.ce; ++} ++void spinand_set_ce_wp(uint8_t data) ++{ ++ flash_ce_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_CE); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_CE; ++ d.bitc.wp = data; ++ gk_ssi_writel(REG_SFLASH_CE, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_CE = d.all; ++} ++uint8_t spinand_get_ce_wp(void) ++{ ++ flash_ce_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_CE); ++ return d.bitc.wp; ++ ++ //return (*(volatile flash_ce_s *)REG_SFLASH_CE).bitc.wp; ++} ++void spinand_set_ce_hold (uint8_t data) ++{ ++ flash_ce_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_CE); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_CE; ++ d.bitc.hold = data; ++ gk_ssi_writel(REG_SFLASH_CE, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_CE = d.all; ++} ++uint8_t spinand_get_ce_hold(void) ++{ ++ flash_ce_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_CE); ++ return d.bitc.hold; ++ ++ //return (*(volatile flash_ce_s *)REG_SFLASH_CE).bitc.hold; ++} ++void spinand_set_ce_cemode (uint8_t data) ++{ ++ flash_ce_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_CE); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_CE; ++ d.bitc.cemode = data; ++ gk_ssi_writel(REG_SFLASH_CE, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_CE = d.all; ++} ++uint8_t spinand_get_ce_cemode(void) ++{ ++ flash_ce_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_CE); ++ return d.bitc.cemode; ++ ++ //return (*(volatile flash_ce_s *)REG_SFLASH_CE).bitc.cemode; ++} ++void spinand_set_ce_wpmode (uint8_t data) ++{ ++ flash_ce_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_CE); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_CE; ++ d.bitc.wpmode = data; ++ gk_ssi_writel(REG_SFLASH_CE, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_CE = d.all; ++} ++uint8_t spinand_get_ce_wpmode(void) ++{ ++ flash_ce_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_CE); ++ return d.bitc.wpmode; ++ ++ //return (*(volatile flash_ce_s *)REG_SFLASH_CE).bitc.wpmode; ++} ++void spinand_set_ce_holdmode (uint8_t data) ++{ ++ flash_ce_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_CE); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_CE; ++ d.bitc.holdmode = data; ++ gk_ssi_writel(REG_SFLASH_CE, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_CE = d.all; ++} ++uint8_t spinand_get_ce_holdmode(void) ++{ ++ flash_ce_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_CE); ++ return d.bitc.holdmode; ++ ++ //return (*(volatile flash_ce_s *)REG_SFLASH_CE).bitc.holdmode; ++} ++void spinand_set_ce_chselect (uint8_t data) ++{ ++ flash_ce_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_CE); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_CE; ++ d.bitc.chselect = data; ++ gk_ssi_writel(REG_SFLASH_CE, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_CE = d.all; ++} ++uint8_t spinand_get_ce_chselect(void) ++{ ++ flash_ce_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_CE); ++ return d.bitc.chselect; ++ ++ //return (*(volatile flash_ce_s *)REG_SFLASH_CE).bitc.chselect; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/* register SFLASH_Speed (read/write) */ ++/*----------------------------------------------------------------------------*/ ++void spinand_set_speed (uint32_t data) ++{ ++ gk_ssi_writel(REG_SFLASH_SPEED, data); ++ //*(volatile uint32_t *)REG_SFLASH_SPEED = data; ++} ++uint32_t spinand_get_speed(void) ++{ ++ return gk_ssi_readl(REG_SFLASH_SPEED); ++ //return (*(volatile uint32_t *)REG_SFLASH_SPEED); ++} ++void spinand_set_speed_sf_sclk_sel (uint8_t data) ++{ ++ flash_speed_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_SPEED); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_SPEED; ++ d.bitc.sf_sclk_sel = data; ++ gk_ssi_writel(REG_SFLASH_SPEED, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_SPEED = d.all; ++} ++uint8_t spinand_get_speed_sf_sclk_sel(void) ++{ ++ flash_speed_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_SPEED); ++ return d.bitc.sf_sclk_sel; ++ ++ //return (*(volatile flash_speed_s *)REG_SFLASH_SPEED).bitc.sf_sclk_sel; ++} ++ ++/*----------------------------------------------------------------------------*/ ++/* register SFLASH_PARA_XIP (read/write) */ ++/*----------------------------------------------------------------------------*/ ++void spinand_set_para_xip (uint32_t data) ++{ ++ gk_ssi_writel(REG_SFLASH_PARA_XIP, data); ++ //*(volatile uint32_t *)REG_SFLASH_PARA_XIP = data; ++} ++uint32_t spinand_get_para_xip(void) ++{ ++ return gk_ssi_readl(REG_SFLASH_PARA_XIP); ++ //return (*(volatile uint32_t *)REG_SFLASH_PARA_XIP); ++} ++void spinand_set_para_xip_sflash_command (uint8_t data) ++{ ++ flash_para_xip_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_PARA_XIP); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_PARA_XIP; ++ d.bitc.sflash_command = data; ++ gk_ssi_writel(REG_SFLASH_PARA_XIP, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_PARA_XIP = d.all; ++} ++uint8_t spinand_get_para_xip_sflash_command(void) ++{ ++ flash_para_xip_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_PARA_XIP); ++ return d.bitc.sflash_command; ++ ++ //return (*(volatile flash_para_xip_s *)REG_SFLASH_PARA_XIP).bitc.sflash_command; ++} ++void spinand_set_para_xip_adr_num (uint8_t data) ++{ ++ flash_para_xip_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_PARA_XIP); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_PARA_XIP; ++ d.bitc.adr_num = data; ++ gk_ssi_writel(REG_SFLASH_PARA_XIP, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_PARA_XIP = d.all; ++} ++uint8_t spinand_get_para_xip_adr_num(void) ++{ ++ flash_para_xip_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_PARA_XIP); ++ return d.bitc.adr_num; ++ ++ //return (*(volatile flash_para_xip_s *)REG_SFLASH_PARA_XIP).bitc.adr_num; ++} ++void spinand_set_para_xip_nummy_num (uint8_t data) ++{ ++ flash_para_xip_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_PARA_XIP); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_PARA_XIP; ++ d.bitc.dummy_num = data; ++ gk_ssi_writel(REG_SFLASH_PARA_XIP, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_PARA_XIP = d.all; ++} ++uint8_t spinand_get_para_xip_nummy_num(void) ++{ ++ flash_para_xip_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_PARA_XIP); ++ return d.bitc.dummy_num; ++ ++ // return (*(volatile flash_para_xip_s *)REG_SFLASH_PARA_XIP).bitc.dummy_num; ++} ++void spinand_set_para_xip_cmd_mod (uint8_t data) ++{ ++ flash_para_xip_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_PARA_XIP); ++ // d.all = *(volatile uint32_t *)REG_SFLASH_PARA_XIP; ++ d.bitc.cmd_mod = data; ++ gk_ssi_writel(REG_SFLASH_PARA_XIP, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_PARA_XIP = d.all; ++} ++uint8_t spinand_get_para_xip_cmd_mod(void) ++{ ++ flash_para_xip_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_PARA_XIP); ++ return d.bitc.cmd_mod; ++ ++ //return (*(volatile flash_para_xip_s *)REG_SFLASH_PARA_XIP).bitc.cmd_mod; ++} ++void spinand_set_para_xip_adr_mod (uint8_t data) ++{ ++ flash_para_xip_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_PARA_XIP); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_PARA_XIP; ++ d.bitc.adr_mod = data; ++ gk_ssi_writel(REG_SFLASH_PARA_XIP, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_PARA_XIP = d.all; ++} ++uint8_t spinand_get_para_xip_adr_mod(void) ++{ ++ flash_para_xip_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_PARA_XIP); ++ return d.bitc.adr_mod; ++ ++ //return (*(volatile flash_para_xip_s *)REG_SFLASH_PARA_XIP).bitc.adr_mod; ++} ++void spinand_set_para_xip_data_mod (uint8_t data) ++{ ++ flash_para_xip_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_PARA_XIP); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_PARA_XIP; ++ d.bitc.data_mod = data; ++ gk_ssi_writel(REG_SFLASH_PARA_XIP, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_PARA_XIP = d.all; ++} ++uint8_t spinand_get_para_xip_data_mod(void) ++{ ++ flash_para_xip_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_PARA_XIP); ++ return d.bitc.data_mod; ++ ++ //return (*(volatile flash_para_xip_s *)REG_SFLASH_PARA_XIP).bitc.data_mod; ++} ++void spinand_set_para_xip_nummy_data (uint8_t data) ++{ ++ flash_para_xip_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_PARA_XIP); ++ //d.all = *(volatile uint32_t *)REG_SFLASH_PARA_XIP; ++ d.bitc.dumy_data = data; ++ gk_ssi_writel(REG_SFLASH_PARA_XIP, d.all); ++ //*(volatile uint32_t *)REG_SFLASH_PARA_XIP = d.all; ++} ++uint8_t spinand_get_para_xip_nummy_data(void) ++{ ++ flash_para_xip_s d; ++ d.all = gk_ssi_readl(REG_SFLASH_PARA_XIP); ++ return d.bitc.dumy_data; ++ ++ //return (*(volatile flash_para_xip_s *)REG_SFLASH_PARA_XIP).bitc.dumy_data; ++} ++ +diff --git a/drivers/mtd/spinand/spinand.h b/drivers/mtd/spinand/spinand.h +new file mode 100644 +index 00000000..50559bd2 +--- /dev/null ++++ b/drivers/mtd/spinand/spinand.h +@@ -0,0 +1,244 @@ ++/* ++ linux/drivers/mtd/spinand/spinand.h ++ ++ Copyright (c) 2013 Gofortune Semiconductor Corporation. ++ Kewell Liu ++ ++ 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. ++ ++ based on nand.h ++*/ ++ ++#ifndef __LINUX_MTD_SPINAND_H ++#define __LINUX_MTD_SPINAND_H ++ ++#include ++#include ++#include ++ ++#define SPINAND_OOBSIZE 128 ++#define SPINAND_PAGESIZE 2048 ++#define SPINAND_PAGENUMB 2048 ++#define SPINAND_BLOCKNUM 2048 ++ ++#define WR_ENABLE 1 ++#define WR_DISABLE 0 ++ ++/* i/o mode */ ++#define SPINAND_1X_READ 0x01 ++#define SPINAND_2X_READ 0x02 ++#define SPINAND_4X_READ 0x04 ++#define SPINAND_1X_WRITE 0x10 ++#define SPINAND_2X_WRITE 0x20 ++#define SPINAND_4X_WRITE 0x40 ++ ++ ++/* The max num of chip select current support */ ++#define NUM_CHIP_SELECT (2) ++ ++/* cmd */ ++#define CMD_READ 0x13 ++#define CMD_READ_RDM 0x03 ++#define CMD_PROG_PAGE_CLRCACHE 0x02 ++#define CMD_PROG_PAGE 0x84 ++#define CMD_PROG_PAGE_EXC 0x10 ++#define CMD_ERASE_BLK 0xd8 ++#define CMD_WR_ENABLE 0x06 ++#define CMD_WR_DISABLE 0x04 ++#define CMD_READ_ID 0x9f ++#define CMD_RESET 0xff ++#define CMD_READ_REG 0x0f ++#define CMD_WRITE_REG 0x1f ++ ++/* feature/ status reg */ ++#define REG_PROTECTION 0xa0 ++#define REG_FEATURE 0xb0 ++#define REG_STATUS 0xc0 /* timing */ ++#define REG_OUTPUT_DRIVER 0xd0 ++ ++/* status */ ++#define STATUS_OIP_MASK 0x01 ++#define STATUS_READY 0 << 0 ++#define STATUS_BUSY 1 << 0 ++ ++#define STATUS_E_FAIL_MASK 0x04 ++#define STATUS_E_FAIL 1 << 2 ++ ++#define STATUS_P_FAIL_MASK 0x08 ++#define STATUS_P_FAIL 1 << 3 ++ ++#define STATUS_ECC_MASK 0x30 ++#define STATUS_ECC_1BIT_CORRECTED 1 << 4 ++#define STATUS_ECC_ERROR 2 << 4 ++#define STATUS_ECC_RESERVED 3 << 4 ++ ++/* Output Driver */ ++#define OPD_DRV_MASK 0x60 ++#define OPD_DRV_S1_MASK 0x40 ++#define OPD_DRV_S0_MASK 0x20 ++ ++/* ECC enable defines */ ++#define OTP_ECC_MASK 0x10 ++//#define OTP_ECC_OFF 0 ++//#define OTP_ECC_ON 1 ++ ++//#define ECC_DISABLED ++//#define ECC_IN_NAND ++//#define ECC_SOFT ++ ++/* block lock */ ++#define BL_ALL_LOCKED 0x38 ++#define BL_1_2_LOCKED 0x30 ++#define BL_1_4_LOCKED 0x28 ++#define BL_1_8_LOCKED 0x20 ++#define BL_1_16_LOCKED 0x18 ++#define BL_1_32_LOCKED 0x10 ++#define BL_1_64_LOCKED 0x08 ++#define BL_ALL_UNLOCKED 0 ++ ++/****************************************************************************/ ++/* ++******************************************************************************* ++** ++** serial flash specific commands and statis register bit definitions ++** ++******************************************************************************* ++*/ ++typedef struct ++{ ++ uint32_t writeEnable; // command to enable a write/erase sequence ++ uint32_t writeDisable; // command to disable a write/erase sequence ++ uint32_t getFeatures; // command to read from status register ++ uint32_t setFeatures; // command to write to status register ++ uint32_t pageRead; // command to read data to cache ++ uint32_t readCache; // command to read data from cache ++ uint32_t readCacheX2; // command to read data from cache X 2 ++ uint32_t readCacheX4; // command to read data from cache X 4 ++ uint32_t readCacheIO2; // command to read data from cache by IO2 ++ uint32_t readCacheIO4; // command to read data from cache by IO4 ++ uint32_t readID; // command to read the chip identification ++ uint32_t programLoad; // command to program a page ++ uint32_t programLoadX4; // command to program a page X 4 ++ uint32_t progExecute; // command to program execute ++ uint32_t progLoadRand; // command to program a page ++ uint32_t progLoadRandX4; // command to program a page X 4 ++ uint32_t progLoadRandIO2; // command to program a page by IO2 ++ uint32_t blockErase; // command to erase a block ++ uint32_t reset; // status register mask for bit write-in-progress ++ ++}spinand_cmd_t; ++ ++/* ++******************************************************************************* ++** ++** serial flash specific geometry and information data structure ++** ++******************************************************************************* ++*/ ++struct spinand_info { ++ uint8_t mid; ++ uint16_t did; ++ char* manuname; ++ char* deviceName; // Pointer to device name ++ uint32_t nand_size; ++ uint32_t usable_size; ++ ++ uint32_t block_size; ++ uint32_t block_main_size; ++ uint32_t block_per_chip; ++ ++ uint32_t page_size; ++ uint32_t page_main_size; ++ uint32_t page_spare_size; ++ uint32_t page_per_block; ++ ++ uint32_t block_shift; ++ uint32_t block_mask; ++ ++ uint32_t page_shift; ++ uint32_t page_mask; /* use to calc the offset address of byte in page */ ++ ++ spinand_cmd_t* commands; /* Device specific access commands */ ++ uint32_t feature; /* bit0(IO1 read) bit1(IO2 read) bit2(IO4 read) ++ bit4(IO1 write) bit5(IO2 write) bit6(IO4 write) */ ++ uint32_t channel; ++ ++ struct nand_ecclayout *ecclayout; ++ ++ int badblockbits; ++ struct nand_bbt_descr *badblock_pattern; ++ ++}; ++ ++struct spinand_chip { /* used for multi chip */ ++ ++ struct mutex lock; ++ struct spinand_info *info; ++ struct mtd_info *mtd; ++ ++ int (*reset) (struct spinand_chip *chip); ++ int (*read_id) (struct spinand_chip *chip, uint32_t* id); ++ int (*read_page) (struct spinand_chip *chip, uint32_t page_id, ++ uint32_t offset, uint32_t len, uint8_t* rbuf); ++ int (*read_page_raw) (struct spinand_chip *chip, uint32_t page_id, ++ uint32_t offset, uint32_t len, uint8_t* rbuf); ++ int (*program_page) (struct spinand_chip *chip, uint32_t page_id, ++ uint32_t offset, uint32_t len, uint8_t* wbuf); ++ int (*program_page_raw) (struct spinand_chip *chip, uint32_t page_id, ++ uint32_t offset, uint32_t len, uint8_t* wbuf); ++ int (*erase_block) (struct spinand_chip *chip, uint32_t block_id); ++ int (*scan_bbt)(struct mtd_info *mtd); ++ int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); ++ int (*block_bad)(struct mtd_info *mtd, loff_t ofs); ++ ++ u8 *pagebuf; ++ u8 *oobbuf; /* temp buffer */ ++ ++ unsigned int *tmpbuf; /* temp buffer */ ++ ++ int page_id; ++ int phys_erase_shift; ++ int bbt_erase_shift; ++ int page_shift; ++ int pagemask; ++ int chip_id; ++ uint64_t chipsize; ++ int badblockpos; ++ int badblockbits; ++ ++ int chip_delay; ++ unsigned int options; ++ unsigned int bbt_options; ++ ++ uint8_t *oob_poi; ++ struct nand_ecclayout *ecclayout; ++ struct nand_buffers *buffers; ++ ++ uint8_t *bbt; ++ struct nand_bbt_descr *bbt_td; ++ struct nand_bbt_descr *bbt_md; ++ ++ struct nand_bbt_descr *badblock_pattern; ++ ++ void *priv; ++ ++}; ++ ++extern int spinand_scan(struct mtd_info * mtd); ++extern int spinand_update_bbt(struct mtd_info *mtd, loff_t offs); ++extern int spinand_default_bbt(struct mtd_info *mtd); ++extern int spinand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt); ++extern int spinand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt); ++ ++ ++#endif /* __LINUX_MTD_SPINAND_H */ ++ ++ ++ +diff --git a/drivers/mtd/spinand/spinand_base.c b/drivers/mtd/spinand/spinand_base.c +new file mode 100644 +index 00000000..74c452e0 +--- /dev/null ++++ b/drivers/mtd/spinand/spinand_base.c +@@ -0,0 +1,1496 @@ ++/* ++ * drivers/mtd/spinand/spinand_base.c ++ * ++ * Overview: ++ * This is the generic MTD driver for SPI NAND flash devices. It should be ++ * capable of working with almost all SPI NAND chips currently available. ++ * ++ * Copyright (c) 2013 Gofortune Semiconductor Corporation. ++ * Kewell Liu ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "spinand.h" ++ ++ ++/******************************************************/ ++/* MTD Part ( Hardware Independent ) */ ++/******************************************************/ ++ ++static int spinand_check_offs_len(struct mtd_info *mtd, ++ loff_t ofs, uint64_t len) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ int ret = 0; ++ ++ /* Start address must align on block boundary */ ++ if (ofs & ((1 << chip->phys_erase_shift) - 1)) { ++ pr_err("%s: unaligned address\n", __func__); ++ ret = -EINVAL; ++ } ++ ++ /* Length must align on block boundary */ ++ if (len & ((1 << chip->phys_erase_shift) - 1)) { ++ pr_err("%s: length not block aligned\n", __func__); ++ ret = -EINVAL; ++ } ++ ++ return ret; ++ ++} ++ ++/** ++ * nand_transfer_oob - [INTERN] Transfer oob to client buffer ++ * @chip: nand chip structure ++ * @oob: oob destination address ++ * @ops: oob ops structure ++ * @len: size of oob to transfer ++ */ ++static int spinand_transfer_oob(struct spinand_chip *chip, uint8_t *oob, ++ struct mtd_oob_ops *ops, size_t len) ++{ ++ struct spinand_info *info = chip->info; ++ ++ switch (ops->mode) { ++ ++ case MTD_OPS_PLACE_OOB: ++ case MTD_OPS_RAW: ++ memcpy(oob, (chip->oob_poi + ops->ooboffs), len); ++ ops->ooboffs = 0; //for second read ++ return 0; ++ ++ case MTD_OPS_AUTO_OOB: { ++ struct nand_oobfree *free = info->ecclayout->oobfree; ++ uint32_t boffs = 0, roffs = ops->ooboffs; ++ size_t bytes = 0; ++ ++ for (; free->length && len; free++, len -= bytes) { ++ /* Read request not from offset 0? */ ++ if (unlikely(roffs)) { ++ if (roffs >= free->length) { ++ roffs -= free->length; ++ continue; ++ } ++ boffs = free->offset + roffs; ++ bytes = min_t(size_t, len, ++ (free->length - roffs)); ++ roffs = 0; ++ } else { ++ bytes = min_t(size_t, len, free->length); ++ boffs = free->offset; ++ } ++ memcpy(oob, (chip->oob_poi + boffs), bytes); ++ oob += bytes; ++ } ++ return 0; ++ } ++ default: ++ BUG(); ++ } ++ ++ return -EINVAL; ++ ++} ++ ++/** ++ * spinand_fill_oob - [INTERN] Transfer client buffer to oob ++ * @mtd: MTD device structure ++ * @oob: oob data buffer ++ * @len: oob data write length ++ * @ops: oob ops structure ++ */ ++static int spinand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, ++ struct mtd_oob_ops *ops) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ struct spinand_info *info = chip->info; ++ ++ /* ++ * Initialise to all 0xFF, to avoid the possibility of left over OOB ++ * data from a previous OOB read. ++ */ ++ memset(chip->oob_poi, 0xff, mtd->oobsize); ++ ++ switch (ops->mode) { ++ ++ case MTD_OPS_PLACE_OOB: ++ case MTD_OPS_RAW: ++ memcpy(chip->oob_poi + ops->ooboffs, oob, len); ++ ops->ooboffs = 0; //for second write ++ return 0; ++ ++ case MTD_OPS_AUTO_OOB: { ++ struct nand_oobfree *free = info->ecclayout->oobfree; ++ uint32_t boffs = 0, woffs = ops->ooboffs; ++ size_t bytes = 0; ++ ++ for (; free->length && len; free++, len -= bytes) { ++ /* Write request not from offset 0? */ ++ if (unlikely(woffs)) { ++ if (woffs >= free->length) { ++ woffs -= free->length; ++ continue; ++ } ++ boffs = free->offset + woffs; ++ bytes = min_t(size_t, len, ++ (free->length - woffs)); ++ woffs = 0; ++ } else { ++ bytes = min_t(size_t, len, free->length); ++ boffs = free->offset; ++ } ++ memcpy(chip->oob_poi + boffs, oob, bytes); ++ oob += bytes; ++ } ++ return 0; ++ } ++ default: ++ BUG(); ++ } ++ ++ return -EINVAL; ++ ++} ++ ++/** ++ * spinand_check_wp - [GENERIC] check if the chip is write protected ++ * @mtd: MTD device structure ++ * ++ * Check, if the device is write protected. The function expects, that the ++ * device is already selected. ++ */ ++static int spinand_check_wp(struct mtd_info *mtd) ++{ ++ //struct spinand_chip *chip = mtd->priv; ++ ++ /* Broken xD cards report WP despite being writable */ ++ ++ /* Check the WP bit */ ++ //chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); ++ //return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; ++ return 0; ++} ++ ++/** ++ * spinand_block_checkbad - [GENERIC] Check if a block is marked bad ++ * @mtd: MTD device structure ++ * @ofs: offset from device start ++ * @allowbbt: 1, if its allowed to access the bbt area ++ * ++ * Check, if the block is bad. Either by reading the bad block table or ++ * calling of the scan function. ++ */ ++static int spinand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ ++ if (!chip->bbt) ++ return chip->block_bad(mtd, ofs); ++ ++ /* Return info from the table */ ++ return spinand_isbad_bbt(mtd, ofs, allowbbt); ++} ++ ++/** ++ * spinand_do_read_oob - [INTERN] NAND read out-of-band ++ * @mtd: MTD device structure ++ * @from: offset to read from ++ * @ops: oob operations description structure ++ * ++ * NAND read out-of-band data from the spare area. ++ */ ++static int spinand_do_read_oob(struct mtd_info *mtd, loff_t from, ++ struct mtd_oob_ops *ops) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ struct spinand_info *info = chip->info; ++ uint32_t page_id, oob_num; ++ ++ uint32_t count; ++ uint32_t oob_ok, oob_left; ++ ++ int readlen = ops->ooblen; ++ int ooblen; ++ ++ signed int retval; ++ ++ #ifdef CONFIG_DEBUG_R ++ pr_info("%s: from = 0x%08Lx, len = %i\n", ++ __func__, (unsigned long long)from, readlen); ++ #endif ++ ++ if (ops->mode == MTD_OPS_AUTO_OOB) ++ { ++ ooblen = mtd->oobavail; ++ } ++ else ++ { ++ ooblen = mtd->oobsize; ++ } ++ ++ if (unlikely(ops->ooboffs >= ooblen)) { ++ dev_err(&mtd->dev, "%s: attempt to start read outside oob\n", __func__); ++ return -EINVAL; ++ } ++ ++ /* Do not allow reads past end of device */ ++ if (unlikely(from >= mtd->size || ++ ops->ooboffs + readlen > ((mtd->size >> info->page_shift) - ++ (from >> info->page_shift)) * ooblen)) { ++ dev_err(&mtd->dev, "%s: attempt to read beyond end of device\n", __func__); ++ return -EINVAL; ++ } ++ ++ /* Shift to get page */ ++ page_id = (uint32_t)(from >> info->page_shift); ++ ++ /* for oob */ ++ oob_num = (ops->ooblen + ooblen -1) / ooblen; ++ ++ count = 0; ++ ++ oob_left = ops->ooblen; ++ oob_ok = 0; ++ ++#ifdef CONFIG_DEBUG_R ++ pr_info("page_id 0x%08x\n" ++ "oob_num 0x%08x\n" ++ "ooblen 0x%08x\n" ++ "oob_left 0x%08x\n", ++ page_id, ++ oob_num, ++ ooblen, ++ oob_left); ++#endif ++ ++ while (1) ++ { ++ if (count < oob_num) ++ { ++ memset(chip->oob_poi, 0, info->page_spare_size); ++ if(ops->mode == MTD_OPS_RAW) ++ { ++ retval = chip->read_page_raw(chip, (page_id + count), info->page_main_size, ++ info->page_spare_size, chip->oob_poi); ++ } ++ else ++ { ++ retval = chip->read_page(chip, (page_id + count), info->page_main_size, ++ info->page_spare_size, chip->oob_poi); ++ } ++ if (retval != 0) ++ { ++ dev_err(&mtd->dev, "%s: fail, block = %d, PageId = 0x%08x\n", __FUNCTION__, ++ ((page_id + count)/info->page_per_block), (page_id + count)); ++ return -EBADMSG; ++ } ++ ++ #ifdef CONFIG_DEBUG_R ++ { ++ int i = 0; ++ ++ for(i = 0; i < mtd->oobsize; i++) ++ { ++ if(i % 16 == 0) ++ { ++ printk("\n"); ++ } ++ printk("%02x ", chip->oob_poi[i]); ++ } ++ ++ printk("\n"); ++ } ++ #endif ++ } ++ else ++ { ++ break; ++ } ++ ++ if (count < oob_num && ops->oobbuf && chip->oob_poi) ++ { ++ int size; ++ ++ /* copy oobbuf to ops oobbuf */ ++ if (oob_left < ooblen) ++ { ++ size = oob_left; ++ } ++ else ++ { ++ size = ooblen; ++ } ++ ++ retval = spinand_transfer_oob(chip, (ops->oobbuf + oob_ok), ops, size); ++ if (retval != 0) ++ { ++ dev_err(&mtd->dev, "[%s]: fail oob mode = %d!\n", __FUNCTION__, ops->mode); ++ return -EUCLEAN; ++ } ++ ++ oob_ok += size; ++ oob_left -= size; ++ ++ ops->oobretlen = oob_ok; ++ ++ } ++ ++ count++; ++ ++ } ++ ++ return 0; ++ ++} ++ ++ ++static int spinand_do_read_ops(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ struct spinand_info *info = chip->info; ++ uint32_t page_id, page_offset, page_num, oob_num = 0; ++ ++ uint32_t count; ++ uint32_t main_ok, main_left, main_offset; ++ uint32_t oob_ok, oob_left; ++ ++ signed int retval; ++ int ooblen; ++ ++ if (!chip->buffers) ++ return -ENOMEM; ++ ++ if (ops->mode == MTD_OPS_AUTO_OOB) ++ { ++ ooblen = mtd->oobavail; ++ } ++ else ++ { ++ ooblen = mtd->oobsize; ++ } ++ ++ page_id = (uint32_t)(from >> info->page_shift); ++ ++ /* for main data */ ++ page_offset = (uint32_t)(from & info->page_mask); ++ page_num = (page_offset + ops->len + info->page_main_size -1 ) / info->page_main_size; ++ ++ /* for oob */ ++ if(ooblen) ++ oob_num = (ops->ooblen + ooblen - 1) / ooblen; ++ ++ count = 0; ++ ++ main_left = ops->len; ++ main_ok = 0; ++ main_offset = page_offset; ++ ++ oob_left = ops->ooblen; ++ oob_ok = 0; ++ ++ #ifdef CONFIG_DEBUG_R ++ pr_info("[DEBUG_R]:%s\n",__FUNCTION__); ++ pr_info("page_id 0x%08x\n" ++ "page_offset 0x%08x\n" ++ "page_num 0x%08x\n" ++ "oob_num 0x%08x\n" ++ "main_left 0x%08x\n" ++ "main_offset 0x%08x\n" ++ "oob_left 0x%08x\n", ++ page_id, ++ page_offset, ++ page_num, ++ oob_num, ++ main_left, ++ main_offset, ++ oob_left); ++ #endif ++ ++ while (1) ++ { ++ if (count < page_num || count < oob_num) ++ { ++ memset(chip->pagebuf, 0, info->page_size); ++ retval = chip->read_page(chip, (page_id + count), 0, info->page_size, chip->pagebuf); ++ if (retval != 0) ++ { ++ dev_err(&mtd->dev, "%s: fail, block = %d, PageId = 0x%08x\n", __FUNCTION__, ++ ((page_id + count)/info->page_per_block), (page_id + count)); ++ return -EBADMSG; ++ } ++ } ++ else ++ { ++ break; ++ } ++ ++ if (count < page_num && ops->datbuf) ++ { ++ int size; ++ ++ if ((main_offset + main_left) < info->page_main_size) ++ { ++ size = main_left; ++ } ++ else ++ { ++ size = info->page_main_size - main_offset; ++ } ++ ++ memcpy((ops->datbuf + main_ok), (chip->pagebuf + main_offset), size); ++ ++ main_ok += size; ++ main_left -= size; ++ main_offset = 0; ++ ++ ops->retlen = main_ok; ++ } ++ ++ if (count < oob_num && ops->oobbuf && chip->oob_poi) ++ { ++ int size; ++ ++ /* copy oobbuf to ops oobbuf */ ++ if (oob_left < ooblen) ++ { ++ size = oob_left; ++ } ++ else ++ { ++ size = ooblen; ++ } ++ ++ retval = spinand_transfer_oob(chip, (ops->oobbuf + oob_ok), ops, size); ++ if (retval != 0) ++ { ++ dev_err(&mtd->dev, "[%s]: fail oob mode = %d!\n", __FUNCTION__, ops->mode); ++ return -EUCLEAN; ++ } ++ ++ oob_ok += size; ++ oob_left -= size; ++ ++ ops->oobretlen = oob_ok; ++ ++ } ++ ++ count++; ++ ++ } ++ ++ return 0; ++ ++} ++ ++/** ++ * spinand_do_write_oob - [MTD Interface] NAND write out-of-band ++ * @mtd: MTD device structure ++ * @to: offset to write to ++ * @ops: oob operation description structure ++ * ++ * NAND write out-of-band. ++ */ ++static int spinand_do_write_oob(struct mtd_info *mtd, loff_t to, ++ struct mtd_oob_ops *ops) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ struct spinand_info *info = chip->info; ++ uint32_t page_id, oob_num; ++ ++ uint32_t count; ++ uint32_t oob_ok, oob_left; ++ ++ uint32_t ooblen; ++ ++ signed int retval; ++ ++ #ifdef CONFIG_DEBUG_W ++ pr_info("%s: to = 0x%08x, len = %i\n", ++ __func__, (unsigned int)to, (int)ops->ooblen); ++ #endif ++ ++ if (ops->mode == MTD_OPS_AUTO_OOB) ++ ooblen = mtd->oobavail; ++ else ++ ooblen = mtd->oobsize; ++ ++ /* Do not allow write past end of page */ ++ if ((ops->ooboffs + ops->ooblen) > ooblen) { ++ dev_err(&mtd->dev, "%s: attempt to write past end of page\n", __func__); ++ return -EINVAL; ++ } ++ ++ if (unlikely(ops->ooboffs >= ooblen)) { ++ dev_err(&mtd->dev, "%s: attempt to start write outside oob\n", __func__); ++ return -EINVAL; ++ } ++ ++ /* Do not allow write past end of device */ ++ if (unlikely(to >= mtd->size || ++ ops->ooboffs + ops->ooblen > ++ ((mtd->size >> info->page_shift) - ++ (to >> info->page_shift)) * ooblen)) { ++ dev_err(&mtd->dev, "%s: attempt to write beyond end of device\n", __func__); ++ return -EINVAL; ++ } ++ ++ /* Shift to get page */ ++ page_id = (uint32_t)(to >> info->page_shift); ++ ++ /* Check, if it is write protected */ ++ if (spinand_check_wp(mtd)) ++ return -EROFS; ++ ++ /* Invalidate the page cache, if we write to the cached page */ ++ if (page_id == chip->page_id) ++ chip->page_id = -1; ++ ++ /* for oob */ ++ oob_num = (ops->ooblen + ooblen - 1) / ooblen; ++ ++ count = 0; ++ ++ oob_left = ops->ooblen; ++ oob_ok = 0; ++ ++ memset(chip->pagebuf, 0xff, mtd->writesize); ++ ++#ifdef CONFIG_DEBUG_W ++ pr_info("page_id 0x%08x\n" ++ "oob_num 0x%08x\n" ++ "ooblen 0x%08x\n" ++ "oob_left 0x%08x\n", ++ page_id, ++ oob_num, ++ ooblen, ++ oob_left); ++#endif ++ while (1) ++ { ++ uint32_t size; ++ ++ if(count >= oob_num) ++ { ++ break; ++ } ++ ++ if (oob_left < ooblen) ++ { ++ size = oob_left; ++ } ++ else ++ { ++ size = ooblen; ++ } ++ ++ if (ops->oobbuf && chip->oob_poi) ++ { ++ retval = spinand_fill_oob(mtd, (ops->oobbuf + oob_ok), size, ops); ++ if (retval != 0) ++ { ++ dev_err(&mtd->dev, "[%s]: fail oob mode = %d!\n", __FUNCTION__, ops->mode); ++ return -EPERM; ++ } ++ oob_ok += size; ++ ops->oobretlen = oob_ok; ++ ++ #ifdef CONFIG_DEBUG_W ++ { ++ int i = 0, j = 0; ++ ++ for(i = 0,j = 0; i < mtd->oobsize; i++,j++) ++ { ++ if(j % 16 == 0) ++ { ++ printk("\n"); ++ } ++ printk("%02x ", chip->oob_poi[i]); ++ } ++ ++ printk("\n"); ++ } ++ #endif ++ } ++ ++ if (ops->mode == MTD_OPS_RAW) ++ { ++ retval = chip->program_page_raw(chip, (page_id + count), ++ info->page_main_size, info->page_spare_size, chip->pagebuf); ++ } ++ else ++ { ++ retval = chip->program_page(chip, (page_id + count), ++ info->page_main_size, info->page_spare_size, chip->pagebuf); ++ } ++ ++ if (retval != 0) ++ { ++ dev_err(&mtd->dev, "[%s]: fail, block = %d, PageId = 0x%08x\n", __FUNCTION__, ++ ((page_id + count)/info->page_per_block), (page_id + count)); ++ return -EPERM; ++ } ++ ++ count++; ++ ++ } ++ ++ return 0; ++ ++} ++ ++static int spinand_do_write_ops(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ struct spinand_info *info = chip->info; ++ ++ uint32_t page_id, page_offset, page_num, oob_num = 0; ++ ++ int count; ++ ++ int main_ok, main_left, main_offset; ++ int oob_ok, oob_left; ++ ++ uint32_t ooblen; ++ ++ signed int retval; ++ ++#ifdef CONFIG_DEBUG_W ++ pr_info("%s: \n" ++ "to = 0x%08x,\n" ++ "len = %i,\n" ++ "ooblen = %i\n", __func__, (unsigned int)to, (int)ops->len,(int)ops->ooblen); ++#endif ++ ++ if (!chip->buffers) ++ return -ENOMEM; ++ ++ if (ops->mode == MTD_OPS_AUTO_OOB) ++ ooblen = mtd->oobavail; ++ else ++ ooblen = mtd->oobsize; ++ ++ page_id = (uint32_t)(to >> info->page_shift); ++ ++ /* Check, if it is write protected */ ++ if (spinand_check_wp(mtd)) ++ return -EROFS; ++ ++ /* for main data */ ++ page_offset = to & info->page_mask; ++ page_num = (page_offset + ops->len + info->page_main_size - 1 ) / info->page_main_size; ++ ++ /* for oob */ ++ if(ooblen) ++ oob_num = (ops->ooblen + ooblen - 1) / ooblen; ++ ++ count = 0; ++ ++ main_left = ops->len; ++ main_ok = 0; ++ main_offset = page_offset; ++ ++ oob_left = ops->ooblen; ++ oob_ok = 0; ++ ++#ifdef CONFIG_DEBUG_W ++ ++ pr_info("page_id 0x%08x\n" ++ "page_offset 0x%08x\n" ++ "page_num 0x%08x\n" ++ "oob_num 0x%08x\n" ++ "main_left 0x%08x\n" ++ "main_offset 0x%08x\n" ++ "oob_left 0x%08x\n", ++ page_id, ++ page_offset, ++ page_num, ++ oob_num, ++ main_left, ++ main_offset, ++ oob_left); ++#endif ++ ++ while (1) ++ { ++ if (count < page_num || count < oob_num) ++ { ++ memset(chip->pagebuf, 0xFF, info->page_size); ++ } ++ else ++ { ++ break; ++ } ++ ++ if (count < page_num && ops->datbuf) ++ { ++ int size; ++ ++ if ((main_offset + main_left) < info->page_main_size) ++ { ++ size = main_left; ++ } ++ else ++ { ++ size = info->page_main_size - main_offset; ++ } ++ ++ memcpy ((chip->pagebuf + main_offset), (ops->datbuf + main_ok), size); ++ ++ main_ok += size; ++ main_left -= size; ++ } ++ ++ if (count < oob_num && ops->oobbuf && chip->oob_poi) ++ { ++ int size; ++ ++ if (oob_left < ooblen) ++ { ++ size = oob_left; ++ } ++ else ++ { ++ size = ooblen; ++ } ++ ++ retval = spinand_fill_oob(mtd, (ops->oobbuf + oob_ok), size, ops); ++ if (retval != 0) ++ { ++ dev_err(&mtd->dev, "[%s]: fail oob mode = %d!\n", __FUNCTION__, ops->mode); ++ return -EPERM; ++ } ++ ++ oob_ok += size; ++ oob_left -= size; ++ ++ } ++ ++ if (count < page_num || count < oob_num) ++ { ++ #ifdef CONFIG_DEBUG_W ++ { ++ int i = 0; ++ ++ for(i = 0; i < 64; i++) ++ { ++ if(i % 16 == 0) ++ { ++ printk("\n"); ++ } ++ printk("%02x ", chip->pagebuf[i]); ++ } ++ ++ printk("\n"); ++ } ++ #endif ++ ++ if(oob_num > 0) ++ { ++ retval = chip->program_page(chip, (page_id + count), main_offset, ++ info->page_size, chip->pagebuf); ++ } ++ else ++ { ++ retval = chip->program_page(chip, (page_id + count), main_offset, ++ info->page_main_size, chip->pagebuf); ++ } ++ ++ if (retval != 0) ++ { ++ dev_err(&mtd->dev, "[%s]: fail, block = %d, PageId = 0x%08x\n", __FUNCTION__, ++ ((page_id + count)/info->page_per_block), (page_id + count)); ++ return -EPERM; ++ } ++ ++ main_offset = 0; ++ ++ } ++ ++ if (count < page_num && ops->datbuf) ++ { ++ ops->retlen = main_ok; ++ } ++ ++ if (count < oob_num && ops->oobbuf && chip->oob_poi) ++ { ++ ops->oobretlen = oob_ok; ++ } ++ ++ count++; ++ ++ } ++ ++ return 0; ++ ++} ++ ++static int spinand_read(struct mtd_info *mtd, loff_t from, size_t len, ++ size_t *retlen, u_char *buf) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ struct mtd_oob_ops ops = {0}; ++ int ret; ++ ++ /* Do not allow reads past end of device */ ++ if ((from + len) > mtd->size) ++ return -EINVAL; ++ ++ if (!len) ++ return 0; ++ ++ mutex_lock(&chip->lock); ++ ++ ops.mode = 0; ++ ops.len = len; ++ ops.datbuf = buf; ++ ops.ooblen = 0; ++ ops.oobbuf = NULL; ++ ++ #ifdef CONFIG_DEBUG_R ++ pr_info("[DEBUG_R]:%s\n",__FUNCTION__); ++ pr_info("from 0x%llx\n" ++ "len 0x%x\n", ++ from, ++ len); ++ #endif ++ ++ ret = spinand_do_read_ops(mtd, from, &ops); ++ ++ *retlen = ops.retlen; ++ ++ mutex_unlock(&chip->lock); ++ ++ return ret; ++ ++} ++ ++static int spinand_write(struct mtd_info *mtd, loff_t to, size_t len, ++ size_t *retlen, const u_char *buf) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ struct mtd_oob_ops ops = {0}; ++ int ret; ++ ++ /* Do not allow reads past end of device */ ++ if ((to + len) > mtd->size) ++ return -EINVAL; ++ if (!len) ++ return 0; ++ ++ mutex_lock(&chip->lock); ++ ++ ops.len = len; ++ ops.datbuf = (uint8_t *)buf; ++ ops.ooblen = 0; ++ ops.oobbuf = NULL; ++ ops.mode = 0; ++ ++#ifdef CONFIG_DEBUG_W ++ pr_info("[DEBUG_W]:%s\n",__FUNCTION__); ++ pr_info("to 0x%llx\n" ++ "len 0x%x\n", ++ to, ++ len); ++#endif ++ ++ ret = spinand_do_write_ops(mtd, to, &ops); ++ ++ *retlen = ops.retlen; ++ ++ mutex_unlock(&chip->lock); ++ ++ return ret; ++ ++} ++ ++static int spinand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ int ret = -ENOTSUPP; ++ ++ ops->retlen = 0; ++ ++ /* Do not allow reads past end of device */ ++ if (ops->datbuf && (from + ops->len) > mtd->size) { ++ dev_err(&mtd->dev, "%s: attempt to read beyond end of device\n", __func__); ++ return -EINVAL; ++ } ++ ++ switch (ops->mode) { ++ case MTD_OPS_PLACE_OOB: ++ case MTD_OPS_AUTO_OOB: ++ case MTD_OPS_RAW: ++ break; ++ ++ default: ++ dev_err(&mtd->dev, "%s: The mode = %d no supported\n", __func__, ops->mode); ++ goto out; ++ } ++ ++ mutex_lock(&chip->lock); ++ ++ if (!ops->datbuf) ++ ret = spinand_do_read_oob(mtd, from, ops); ++ else ++ ret = spinand_do_read_ops(mtd, from, ops); ++ ++ mutex_unlock(&chip->lock); ++out: ++ ++ return ret; ++ ++} ++ ++/** ++ * spinand_write_oob - [MTD Interface] NAND write data and/or out-of-band ++ * @mtd: MTD device structure ++ * @to: offset to write to ++ * @ops: oob operation description structure ++ */ ++static int spinand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ int ret = -ENOTSUPP; ++ ++ ops->retlen = 0; ++ ++ /* Do not allow writes past end of device */ ++ if (ops->datbuf && (to + ops->len) > mtd->size) { ++ pr_debug("%s: attempt to write beyond end of device\n", __func__); ++ return -EINVAL; ++ } ++ ++#ifdef CONFIG_DEBUG_W ++ pr_info("[DEBUG_W]:%s\n",__FUNCTION__); ++ pr_info("to 0x%llx\n" ++ "len 0x%x\n" ++ "ooblen 0x%x\n", ++ to, ++ ops->len, ops->ooblen); ++#endif ++ ++ ++ switch (ops->mode) { ++ case MTD_OPS_PLACE_OOB: ++ case MTD_OPS_AUTO_OOB: ++ case MTD_OPS_RAW: ++ break; ++ ++ default: ++ dev_err(&mtd->dev, "%s: The mode = %d no supported\n", __func__, ops->mode); ++ goto out; ++ } ++ ++ mutex_lock(&chip->lock); ++ ++ if (!ops->datbuf) ++ ret = spinand_do_write_oob(mtd, to, ops); ++ else ++ ret = spinand_do_write_ops(mtd, to, ops); ++ ++ mutex_unlock(&chip->lock); ++ ++out: ++ ++ return ret; ++ ++} ++ ++#define BBT_PAGE_MASK 0xffffff3f ++/** ++ * spinand_erase_nand - [INTERN] erase block(s) ++ * @mtd: MTD device structure ++ * @instr: erase instruction ++ * @allowbbt: allow erasing the bbt area ++ * ++ * Erase one ore more blocks. ++ */ ++int spinand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt) ++{ ++ int page, pages_per_block, ret; ++ struct spinand_chip *chip = mtd->priv; ++ struct spinand_info *info = chip->info; ++ ++ loff_t rewrite_bbt[NAND_MAX_CHIPS] = {0}; ++ unsigned int bbt_masked_page = 0xffffffff; ++ loff_t len; ++ ++ pr_debug("%s: start = 0x%012llx, len = %llu\n", ++ __func__, (unsigned long long)instr->addr, ++ (unsigned long long)instr->len); ++ ++ if (spinand_check_offs_len(mtd, instr->addr, instr->len)) ++ return -EINVAL; ++ ++ /* Do not allow erase past end of device */ ++ if ((instr->len + instr->addr) > info->usable_size) { ++ pr_err("%s: Erase past end of device\n",__FUNCTION__); ++ return -EINVAL; ++ } ++ ++ mutex_lock(&chip->lock); ++ ++ /* Grab the lock and see if the device is available */ ++ //nand_get_device(chip, mtd, FL_ERASING); ++ ++ /* Shift to get first page */ ++ page = (int)(instr->addr >> chip->page_shift); ++ page &= chip->pagemask; ++ ++ /* Calculate pages in each block */ ++ pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); ++ ++ /* Check, if it is write protected */ ++ if (spinand_check_wp(mtd)) { ++ pr_debug("%s: device is write protected!\n", __func__); ++ instr->state = MTD_ERASE_FAILED; ++ goto erase_exit; ++ } ++ ++ /* ++ * If BBT requires refresh, set the BBT page mask to see if the BBT ++ * should be rewritten. Otherwise the mask is set to 0xffffffff which ++ * can not be matched. This is also done when the bbt is actually ++ * erased to avoid recursive updates. ++ */ ++ if (chip->options & BBT_AUTO_REFRESH && !allowbbt) ++ bbt_masked_page = chip->bbt_td->pages[0] & BBT_PAGE_MASK; ++ ++ /* Loop through the pages */ ++ len = instr->len; ++ ++ instr->state = MTD_ERASING; ++ ++ while (len) ++ { ++ /* Check if we have a bad block, we do not erase bad blocks! */ ++ if (spinand_block_checkbad(mtd, ((loff_t) page) << chip->page_shift, allowbbt)) ++ { ++ pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", __func__, page); ++ instr->state = MTD_ERASE_FAILED; ++ goto erase_exit; ++ } ++ ++ ret = chip->erase_block(chip, (uint32_t)page); ++ ++ /* See if block erase succeeded */ ++ if (ret != 0) ++ { ++ ret = chip->erase_block(chip, (uint32_t)page); ++ if (ret != 0) ++ { ++ pr_err("%s: failed erase, block = %d!\n", __FUNCTION__, ++ (uint32_t)(page/pages_per_block)); ++ instr->state = MTD_ERASE_FAILED; ++ instr->fail_addr = ((loff_t)page << chip->page_shift); ++ goto erase_exit; ++ } ++ } ++ ++ /* ++ * If BBT requires refresh, set the BBT rewrite flag to the ++ * page being erased. ++ */ ++ if (bbt_masked_page != 0xffffffff && (page & BBT_PAGE_MASK) == bbt_masked_page) ++ rewrite_bbt[0] = ((loff_t)page << chip->page_shift); ++ ++ /* Increment page address and decrement length */ ++ len -= (1 << chip->phys_erase_shift); ++ page += pages_per_block; ++ ++ } ++ instr->state = MTD_ERASE_DONE; ++ ++erase_exit: ++ ++ mutex_unlock(&chip->lock); ++ ++ ret = (instr->state == MTD_ERASE_DONE ? 0 : -EIO); ++ ++ /* Do call back function */ ++ if (!ret) ++ mtd_erase_callback(instr); ++ ++ /* ++ * If BBT requires refresh and erase was successful, rewrite any ++ * selected bad block tables. ++ */ ++ if (bbt_masked_page == 0xffffffff || ret) ++ return ret; ++ ++ if (rewrite_bbt[0]) ++ { ++ /* Update the BBT for chip */ ++ pr_debug("%s: update_bbt (0x%0llx 0x%08x)\n", ++ __func__, rewrite_bbt[0], chip->bbt_td->pages[0]); ++ spinand_update_bbt(mtd, rewrite_bbt[0]); ++ } ++ ++ /* Return more or less happy */ ++ return ret; ++ ++} ++ ++/** ++ * spinand_erase - [MTD Interface] erase block(s) ++ * @mtd: MTD device structure ++ * @instr: erase instruction ++ * ++ * Erase one ore more blocks. ++ */ ++static int spinand_erase(struct mtd_info *mtd, struct erase_info *instr) ++{ ++ return spinand_erase_nand(mtd, instr, 0); ++} ++ ++ ++/** ++ * spinand_sync - [MTD Interface] sync ++ * @param mtd MTD device structure ++ * ++ * Sync is actually a wait for chip ready function ++ */ ++static void spinand_sync(struct mtd_info *mtd) ++{ ++ dev_err(&mtd->dev, "spinand_sync: called\n"); ++} ++ ++/** ++ * spinand_block_isbad - [MTD Interface] Check if block at offset is bad ++ * @mtd: MTD device structure ++ * @offs: offset relative to mtd start ++ */ ++static int spinand_block_isbad(struct mtd_info *mtd, loff_t offs) ++{ ++ return spinand_block_checkbad(mtd, offs, 0); ++} ++ ++/** ++ * spinand_block_bad - [DEFAULT] Read bad block marker from the chip ++ * @mtd: MTD device structure ++ * @ofs: offset from device start ++ * ++ * Check, if the block is bad. ++ */ ++static int spinand_block_bad(struct mtd_info *mtd, loff_t ofs) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ struct spinand_info *info = chip->info; ++ struct nand_bbt_descr *badblock_ptn = info->badblock_pattern; ++ uint32_t page_id; ++ uint16_t is_bad = 0; ++ int i = 0, res = 0; ++ ++ if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) ++ ofs += mtd->erasesize - mtd->writesize; ++ ++ page_id = (uint32_t)(ofs >> chip->page_shift) & chip->pagemask; ++ ++ #ifdef KE_DEBUG_R ++ pr_debug("[%s]: page_id = 0x%08x, Ofs = 0x%08x\n", ++ __FUNCTION__, page_id, ofs); ++ #endif ++ ++ do ++ { ++ if (chip->options & NAND_BUSWIDTH_16) ++ { ++ chip->read_page(chip, page_id, ++ (info->page_main_size + chip->badblockpos), badblock_ptn->len, (uint8_t*)&is_bad); ++ is_bad = cpu_to_le16(is_bad); ++ if (chip->badblockpos & 0x1) ++ is_bad >>= 8; ++ else ++ is_bad &= 0xFF; ++ } ++ else ++ { ++ chip->read_page(chip, page_id, ++ (info->page_main_size + chip->badblockpos), badblock_ptn->len, (uint8_t*)&is_bad); ++ } ++ ++ if (likely(chip->badblockbits == 8)) ++ { ++ res = is_bad != 0xFF; ++ } ++ else ++ { ++ res = hweight8(is_bad) < chip->badblockbits; ++ } ++ ofs += mtd->writesize; ++ page_id = (uint32_t)(ofs >> chip->page_shift) & chip->pagemask; ++ i++; ++ } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE)); ++ ++ #ifdef KE_DEBUG_R ++ pr_debug("[%s]: Block = 0x%04x, is %s\n", ++ __FUNCTION__, (uint32_t)(ofs >> chip->bbt_erase_shift), (res > 0)? "bad":"good"); ++ #endif ++ ++ return res; ++ ++} ++ ++#if 0 ++ ++/** ++ * spinand_default_block_bad - [DEFAULT] Read bad block marker from the chip ++ * @mtd: MTD device structure ++ * @ofs: offset from device start ++ * ++ * Check, if the block is bad. ++ */ ++static int spinand_default_block_bad(struct mtd_info *mtd, loff_t ofs) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ struct spinand_info *info = chip->info; ++ uint32_t page_id; ++ uint8_t is_bad = 0; ++ int ret = 0; ++ ++ if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) ++ ofs += mtd->erasesize - mtd->writesize; ++ ++ page_id = (uint32_t)(ofs >> chip->page_shift); ++ ++ mutex_lock(&chip->lock); ++ ++ chip->read_page(chip, page_id, ++ (info->page_main_size + chip->badblockpos), 1, &is_bad); ++ ++ mutex_unlock(&chip->lock); ++ ++ if (is_bad != 0xff) ++ { ++ ret = 1; ++ } ++ ++ return ret; ++ ++} ++ ++#endif ++ ++/** ++ * spinand_default_block_markbad - [DEFAULT] mark a block bad ++ * @mtd: MTD device structure ++ * @ofs: offset from device start ++ * ++ * This is the default implementation, which can be overridden by a hardware ++ * specific driver. We try operations in the following order, according to our ++ * bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH): ++ * (1) erase the affected block, to allow OOB marker to be written cleanly ++ * (2) update in-memory BBT ++ * (3) write bad block marker to OOB area of affected block ++ * (4) update flash-based BBT ++ * Note that we retain the first error encountered in (3) or (4), finish the ++ * procedures, and dump the error in the end. ++*/ ++static int spinand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ uint8_t buf[2] = { 0, 0 }; ++ int block, res, ret = 0, i = 0; ++ int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM); ++ ++ if (write_oob) { ++ struct erase_info einfo; ++ ++ /* Attempt erase before marking OOB */ ++ memset(&einfo, 0, sizeof(einfo)); ++ einfo.mtd = mtd; ++ einfo.addr = ofs; ++ einfo.len = 1 << chip->phys_erase_shift; ++ spinand_erase_nand(mtd, &einfo, 0); ++ } ++ ++ /* Get block number */ ++ block = (int)(ofs >> chip->bbt_erase_shift); ++ /* Mark block bad in memory-based BBT */ ++ if (chip->bbt) ++ chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); ++ ++ /* Write bad block marker to OOB */ ++ if (write_oob) ++ { ++ struct mtd_oob_ops ops; ++ loff_t wr_ofs = ofs; ++ ++ //nand_get_device(chip, mtd, FL_WRITING); ++ ++ ops.datbuf = NULL; ++ ops.oobbuf = buf; ++ ops.ooboffs = chip->badblockpos; ++ if (chip->options & NAND_BUSWIDTH_16) { ++ ops.ooboffs &= ~0x01; ++ ops.len = ops.ooblen = 2; ++ } else { ++ ops.len = ops.ooblen = 1; ++ } ++ ops.mode = MTD_OPS_PLACE_OOB; ++ ++ /* Write to first/last page(s) if necessary */ ++ if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) ++ wr_ofs += mtd->erasesize - mtd->writesize; ++ do { ++ res = spinand_do_write_oob(mtd, wr_ofs, &ops); ++ if (!ret) ++ ret = res; ++ ++ i++; ++ wr_ofs += mtd->writesize; ++ } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); ++ ++ //nand_release_device(mtd); ++ } ++ ++ /* Update flash-based bad block table */ ++ if (chip->bbt_options & NAND_BBT_USE_FLASH) { ++ res = spinand_update_bbt(mtd, ofs); ++ if (!ret) ++ ret = res; ++ } ++ ++ if (!ret) ++ mtd->ecc_stats.badblocks++; ++ ++ return ret; ++ ++} ++ ++/** ++ * spinand_block_markbad - [MTD Interface] Mark bad block ++ * @param mtd MTD device structure ++ * @param ofs Bad block number ++ */ ++static int spinand_block_markbad(struct mtd_info *mtd, loff_t ofs) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ uint32_t ret = 0; ++ ++ ret = spinand_block_isbad(mtd, ofs); ++ if (ret) ++ { ++ /* If it was bad already, return success and do nothing */ ++ if (ret > 0) ++ return 0; ++ return ret; ++ } ++ ++ return chip->block_markbad(mtd, ofs); ++} ++ ++ ++/** ++ * spinand_suspend - [MTD Interface] Suspend the spinand flash ++ * @param mtd MTD device structure ++ */ ++static int spinand_suspend(struct mtd_info *mtd) ++{ ++ return 0; ++} ++ ++/** ++ * spinand_resume - [MTD Interface] Resume the spinand flash ++ * @param mtd MTD device structure ++ */ ++static void spinand_resume(struct mtd_info *mtd) ++{ ++ return; ++} ++ ++/* Set default functions */ ++static void spinand_set_defaults(struct spinand_chip *chip) ++{ ++ /* check for proper chip_delay setup, set 20us if not */ ++ if (!chip->chip_delay) ++ chip->chip_delay = 20; ++ ++ if (!chip->scan_bbt) ++ chip->scan_bbt = spinand_default_bbt; ++ ++ if (!chip->block_markbad) ++ chip->block_markbad = spinand_default_block_markbad; ++ ++ if (!chip->block_bad) ++ chip->block_bad = spinand_block_bad; ++} ++ ++ ++/** ++ * spinand_scan - [SpiNAND Interface] Scan for the SpiNAND device ++ * @param mtd MTD device structure ++ * ++ * This fills out all the not initialized function pointers ++ * with the defaults. ++ * The flash ID is read and the mtd/chip structures are ++ * filled with the appropriate values. ++ */ ++int spinand_scan(struct mtd_info *mtd) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ struct spinand_info *info = chip->info; ++ ++ //chip->state = FL_READY; ++ //init_waitqueue_head(&chip->wq); ++ //spin_lock_init(&chip->chip_lock); ++ spinand_set_defaults(chip); ++ ++ mtd->name = info->deviceName; ++ mtd->size = info->usable_size; ++ mtd->erasesize = info->block_main_size; ++ mtd->writesize = info->page_main_size; ++ mtd->writebufsize = info->page_main_size; ++ mtd->oobsize = info->page_spare_size; ++ mtd->oobavail = info->ecclayout->oobavail; ++ mtd->owner = THIS_MODULE; ++ mtd->type = MTD_NANDFLASH; ++ mtd->flags = MTD_CAP_NANDFLASH; ++ mtd->ecclayout = info->ecclayout; ++ ++ mtd->_erase = spinand_erase; ++ mtd->_point = NULL; ++ mtd->_unpoint = NULL; ++ mtd->_read = spinand_read; ++ mtd->_write = spinand_write; ++ mtd->_read_oob = spinand_read_oob; ++ mtd->_write_oob = spinand_write_oob; ++ mtd->_sync = spinand_sync; ++ mtd->_lock = NULL; ++ mtd->_unlock = NULL; ++ mtd->_suspend = spinand_suspend; ++ mtd->_resume = spinand_resume; ++ mtd->_block_isbad = spinand_block_isbad; ++ mtd->_block_markbad = spinand_block_markbad; ++ ++ /* Check, if we should skip the bad block table scan */ ++ if (chip->options & NAND_SKIP_BBTSCAN) ++ return 0; ++ ++ /* Build bad block table */ ++ return chip->scan_bbt(mtd); ++ ++} ++ ++EXPORT_SYMBOL_GPL(spinand_scan); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Kewell Liu, "); ++MODULE_DESCRIPTION("SPI NAND driver code"); +diff --git a/drivers/mtd/spinand/spinand_bbt.c b/drivers/mtd/spinand/spinand_bbt.c +new file mode 100644 +index 00000000..9e2da341 +--- /dev/null ++++ b/drivers/mtd/spinand/spinand_bbt.c +@@ -0,0 +1,1602 @@ ++/* ++ * drivers/mtd/spinand/spinand_bbt.c ++ * ++ * Overview: ++ * Bad block table support for the SPI NAND driver ++ * ++ * Copyright (c) 2013 Gofortune Semiconductor Corporation. ++ * Kewell Liu ++ * ++ * 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. ++ * ++ * Description: ++ * ++ * When nand_scan_bbt is called, then it tries to find the bad block table ++ * depending on the options in the BBT descriptor(s). If no flash based BBT ++ * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory ++ * marked good / bad blocks. This information is used to create a memory BBT. ++ * Once a new bad block is discovered then the "factory" information is updated ++ * on the device. ++ * If a flash based BBT is specified then the function first tries to find the ++ * BBT on flash. If a BBT is found then the contents are read and the memory ++ * based BBT is created. If a mirrored BBT is selected then the mirror is ++ * searched too and the versions are compared. If the mirror has a greater ++ * version number than the mirror BBT is used to build the memory based BBT. ++ * If the tables are not versioned, then we "or" the bad block information. ++ * If one of the BBTs is out of date or does not exist it is (re)created. ++ * If no BBT exists at all then the device is scanned for factory marked ++ * good / bad blocks and the bad block tables are created. ++ * ++ * For manufacturer created BBTs like the one found on M-SYS DOC devices ++ * the BBT is searched and read but never created ++ * ++ * The auto generated bad block table is located in the last good blocks ++ * of the device. The table is mirrored, so it can be updated eventually. ++ * The table is marked in the OOB area with an ident pattern and a version ++ * number which indicates which of both tables is more up to date. If the NAND ++ * controller needs the complete OOB area for the ECC information then the ++ * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of ++ * course): it moves the ident pattern and the version byte into the data area ++ * and the OOB area will remain untouched. ++ * ++ * The table uses 2 bits per block ++ * 11b: block is good ++ * 00b: block is factory marked bad ++ * 01b, 10b: block is marked bad due to wear ++ * ++ * The memory bad block table uses the following scheme: ++ * 00b: block is good ++ * 01b: block is marked bad due to wear ++ * 10b: block is reserved (to protect the bbt area) ++ * 11b: block is factory marked bad ++ * ++ * Multichip devices like DOC store the bad block info per floor. ++ * ++ * Following assumptions are made: ++ * - bbts start at a page boundary, if autolocated on a block boundary ++ * - the space necessary for a bbt in FLASH does not exceed a block boundary ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "spinand.h" ++ ++#ifdef CONFIG_SELF_START_BLOCK ++#define START_BLOCK 18 ++#else ++#define START_BLOCK 0 ++#endif ++ ++ ++static int spinand_check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) ++{ ++ int ret; ++ ++ ret = memcmp(buf, td->pattern, td->len); ++ if (!ret) ++ return ret; ++ return -1; ++} ++ ++/** ++ * spinand_check_pattern - [GENERIC] check if a pattern is in the buffer ++ * @buf: the buffer to search ++ * @len: the length of buffer to search ++ * @paglen: the pagelength ++ * @td: search pattern descriptor ++ * ++ * Check for a pattern at the given place. Used to search bad block tables and ++ * good / bad block identifiers. If the SCAN_EMPTY option is set then check, if ++ * all bytes except the pattern area contain 0xff. ++ */ ++static int spinand_check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) ++{ ++ int i, end = 0; ++ uint8_t *p = buf; ++ ++ if (td->options & NAND_BBT_NO_OOB) ++ return spinand_check_pattern_no_oob(buf, td); ++ ++ end = paglen + td->offs; ++ if (td->options & NAND_BBT_SCANEMPTY) ++ { ++ for (i = 0; i < end; i++) ++ { ++ if (p[i] != 0xff) ++ return -1; ++ } ++ } ++ p += end; ++ ++ /* Compare the pattern */ ++ if (memcmp(p, td->pattern, td->len)) ++ return -1; ++ ++ if (td->options & NAND_BBT_SCANEMPTY) ++ { ++ p += td->len; ++ end += td->len; ++ for (i = end; i < len; i++) ++ { ++ if (*p++ != 0xff) ++ return -1; ++ } ++ } ++ ++ return 0; ++ ++} ++ ++/** ++ * spinand_check_short_pattern - [GENERIC] check if a pattern is in the buffer ++ * @buf: the buffer to search ++ * @td: search pattern descriptor ++ * ++ * Check for a pattern at the given place. Used to search bad block tables and ++ * good / bad block identifiers. Same as check_pattern, but no optional empty ++ * check. ++ */ ++static int spinand_check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) ++{ ++ int i; ++ uint8_t *p = buf; ++ ++ /* Compare the pattern */ ++ for (i = 0; i < td->len; i++) { ++ if (p[td->offs + i] != td->pattern[i]) ++ return -1; ++ } ++ return 0; ++} ++ ++/** ++ * spinand_add_marker_len - compute the length of the marker in data area ++ * @td: BBT descriptor used for computation ++ * ++ * The length will be 0 if the marker is located in OOB area. ++ */ ++static u32 spinand_add_marker_len(struct nand_bbt_descr *td) ++{ ++ u32 len; ++ ++ if (!(td->options & NAND_BBT_NO_OOB)) ++ return 0; ++ ++ len = td->len; ++ if (td->options & NAND_BBT_VERSION) ++ len++; ++ return len; ++} ++ ++/** ++ * spinand_read_bbt - [GENERIC] Read the bad block table starting from page ++ * @mtd: MTD device structure ++ * @buf: temporary buffer ++ * @page: the starting page ++ * @num: the number of bbt descriptors to read ++ * @td: the bbt describtion table ++ * @offs: offset in the memory table ++ * ++ * Read the bad block table starting from page. ++ */ ++static int spinand_read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, ++ struct nand_bbt_descr *td, int offs) ++{ ++ int res, ret = 0, i, j, act = 0; ++ struct spinand_chip *this = mtd->priv; ++ size_t retlen, len, totlen; ++ loff_t from; ++ int bits = td->options & NAND_BBT_NRBITS_MSK; ++ uint8_t msk = (uint8_t)((1 << bits) - 1); ++ u32 marker_len; ++ int reserved_block_code = td->reserved_block_code; ++ ++ totlen = (num * bits) >> 3; ++ marker_len = spinand_add_marker_len(td); ++ from = ((loff_t)page) << this->page_shift; ++ ++#ifdef CONFIG_DEBUG_R ++ ++ pr_info("[%s]: read bbt >>>\n", __FUNCTION__); ++ pr_info("BlockNum %d\n" ++ "totlen %d\n" ++ "marker_len %d\n" ++ "from 0x%llx\n", ++ totlen, ++ marker_len, ++ from); ++ ++#endif ++ ++ ++ while (totlen) ++ { ++ len = min(totlen, (size_t)(1 << this->bbt_erase_shift)); ++ if (marker_len) { ++ /* ++ * In case the BBT marker is not in the OOB area it ++ * will be just in the first page. ++ */ ++ len -= marker_len; ++ from += marker_len; ++ marker_len = 0; ++ } ++ ++ res = mtd_read(mtd, from, len, &retlen, buf); ++ if (res < 0) ++ { ++ if (mtd_is_eccerr(res)) { ++ pr_info("%s: ECC error in BBT at 0x%012llx\n", __FUNCTION__,from & ~mtd->writesize); ++ return res; ++ } else if (mtd_is_bitflip(res)) { ++ pr_info("%s: corrected error in BBT at 0x%012llx\n", __FUNCTION__,from & ~mtd->writesize); ++ ret = res; ++ } else { ++ pr_info("%s: error reading BBT\n",__FUNCTION__); ++ return res; ++ } ++ } ++ ++ /* Analyse data */ ++ for (i = 0; i < len; i++) ++ { ++ uint8_t dat = buf[i]; ++ for (j = 0; j < 8; j += bits, act += 2) ++ { ++ uint8_t tmp = (dat >> j) & msk; ++ if (tmp == msk) ++ continue; ++ if (reserved_block_code && (tmp == reserved_block_code)) ++ { ++ pr_info("%s: reserved block at 0x%012llx\n",__FUNCTION__, ++ (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); ++ this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); ++ mtd->ecc_stats.bbtblocks++; ++ continue; ++ } ++ ++ /* ++ * Leave it for now, if it's matured we can ++ * move this message to pr_debug. ++ */ ++ pr_info("%s: bad block at 0x%012llx\n",__FUNCTION__, ++ (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); ++ ++ /* Factory marked bad or worn out? */ ++ if (tmp == 0) ++ this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); ++ else ++ this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06); ++ mtd->ecc_stats.badblocks++; ++ ++ } ++ } ++ ++ totlen -= len; ++ from += len; ++ ++ } ++ ++ return ret; ++ ++} ++ ++/** ++ * spinand_read_abs_bbt - [GENERIC] Read the bad block table starting at a given page ++ * @mtd: MTD device structure ++ * @buf: temporary buffer ++ * @td: descriptor for the bad block table ++ * ++ * Read the bad block table for all chips starting at a given page. We assume ++ * that the bbt bits are in consecutive order. ++ */ ++static int spinand_read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) ++{ ++ struct spinand_chip *this = mtd->priv; ++ int res = 0; ++ ++ res = spinand_read_bbt(mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, td, 0); ++ if (res) ++ return res; ++ ++ return 0; ++} ++ ++/** ++ * spinand_scan_read_raw_data - [GENERIC] Scan read raw data from flash ++ * @mtd: MTD device structure ++ * @buf: temporary buffer ++ * @offs: offset in the memory table ++ * @readlen: the length of the data to read ++ * ++ * Scan read raw data from flash, BBT marker is in the first page, no OOB ++ */ ++static int spinand_scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, ++ struct nand_bbt_descr *td) ++{ ++ size_t retlen; ++ size_t len; ++ ++ len = td->len; ++ if (td->options & NAND_BBT_VERSION) ++ len++; ++ ++ return mtd_read(mtd, offs, len, &retlen, buf); ++} ++ ++/** ++ * spinand_scan_read_raw_oob - [GENERIC] Scan read oob raw data from flash ++ * @mtd: MTD device structure ++ * @buf: temporary buffer ++ * @offs: offset in the memory table ++ * @readlen: the length of the data to read ++ * ++ * Scan read oob raw data from flash ++ */ ++static int spinand_scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, ++ size_t readlen) ++{ ++ struct mtd_oob_ops ops; ++ int res; ++ ++ ops.mode = MTD_OPS_RAW; ++ ops.ooboffs = 0; ++ ops.ooblen = mtd->oobsize; ++ ++ while (readlen > 0) ++ { ++ ops.datbuf = buf; ++ ops.len = min(readlen, (size_t)mtd->writesize); ++ ops.oobbuf = buf + ops.len; ++ ++ res = mtd_read_oob(mtd, offs, &ops); ++ ++ if (res) ++ { ++ return res; ++ } ++ ++ buf += mtd->oobsize + mtd->writesize; ++ readlen -= mtd->writesize; ++ offs += mtd->writesize; ++ } ++ ++ return 0; ++ ++} ++ ++static int spinand_scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, ++ size_t len, struct nand_bbt_descr *td) ++{ ++ if (td->options & NAND_BBT_NO_OOB) ++ return spinand_scan_read_raw_data(mtd, buf, offs, td); ++ else ++ return spinand_scan_read_raw_oob(mtd, buf, offs, len); ++} ++ ++/** ++ * spinand_scan_write_bbt - [GENERIC] Scan write data with oob to flash ++ * @mtd: MTD device structure ++ * @offs: offset to write ++ * @len: the length of the data to write ++ * @buf: temporary buffer for main data ++ * @oob: temporary buffer for oob data ++ * ++ * Scan write data with oob to flash ++ */ ++static int spinand_scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, ++ uint8_t *buf, uint8_t *oob) ++{ ++ struct mtd_oob_ops ops; ++ ++ ops.mode = MTD_OPS_PLACE_OOB; ++ ops.ooboffs = 0; ++ ops.ooblen = mtd->oobsize; ++ ops.datbuf = buf; ++ ops.oobbuf = oob; ++ ops.len = len; ++ ++#ifdef CONFIG_DEBUG_W ++ pr_info("[%s]: scan write bbt >>>\n", __FUNCTION__); ++ pr_info("offs 0x%llx\n" ++ "len 0x%x\n" ++ "oobbuf 0x%x\n", ++ offs, ++ len, oob); ++ ++#endif ++ ++ return mtd_write_oob(mtd, offs, &ops); ++} ++ ++static u32 spinand_bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) ++{ ++ u32 ver_offs = td->veroffs; ++ ++ if (!(td->options & NAND_BBT_NO_OOB)) ++ ver_offs += mtd->writesize; ++ return ver_offs; ++} ++ ++/** ++ * spinand_read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page ++ * @mtd: MTD device structure ++ * @buf: temporary buffer ++ * @td: descriptor for the bad block table ++ * @md: descriptor for the bad block table mirror ++ * ++ * Read the bad block table(s) for all chips starting at a given page. We ++ * assume that the bbt bits are in consecutive order. ++ */ ++static int spinand_read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, ++ struct nand_bbt_descr *td, struct nand_bbt_descr *md) ++{ ++ struct spinand_chip *this = mtd->priv; ++ ++ /* Read the primary version, if available */ ++ if (td->options & NAND_BBT_VERSION) ++ { ++ spinand_scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, mtd->writesize, td); ++ td->version[0] = buf[spinand_bbt_get_ver_offs(mtd, td)]; ++ pr_info("line%d: TD BBT at page %d, version 0x%02X\n", __LINE__,td->pages[0], td->version[0]); ++ } ++ ++ /* Read the mirror version, if available */ ++ if (md && (md->options & NAND_BBT_VERSION)) ++ { ++ spinand_scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, mtd->writesize, md); ++ md->version[0] = buf[spinand_bbt_get_ver_offs(mtd, md)]; ++ pr_info("Line%d: MD BBT at page %d, version 0x%02X\n", __LINE__,md->pages[0], md->version[0]); ++ } ++ ++ return 1; ++ ++} ++ ++/** ++ * spinand_scan_block_full - [GENERIC] Scan a given block full ++ * @mtd: MTD device structure ++ * @bd: descriptor for the good/bad block search pattern ++ * @offs: address offset of spi nand(from) ++ * @buf: temporary buffer ++ * @readlen: the length of the data to read ++ * @scanlen: the length of the data to scan ++ * @rpagenum: the number of the pages to read ++ * ++ * Scan the full pages in a given block ++ */ ++static int spinand_scan_block_full( ++ struct mtd_info *mtd, struct nand_bbt_descr *bd, ++ loff_t offs, uint8_t *buf, size_t readlen, ++ int scanlen, int rpagenum) ++{ ++ int ret, j; ++ ++ /* read oob raw */ ++ ret = spinand_scan_read_raw_oob(mtd, buf, offs, readlen); ++ ++ /* Ignore ECC errors when checking for BBM */ ++ if (ret && !mtd_is_bitflip_or_eccerr(ret)) ++ return ret; ++ ++ /* check pattern per page */ ++ for (j = 0; j < rpagenum; j++, buf += scanlen) { ++ if (spinand_check_pattern(buf, scanlen, mtd->writesize, bd)) ++ return 1; ++ } ++ return 0; ++} ++ ++/** ++ * spinand_scan_block_fast - [GENERIC] Scan a given block partially ++ * @mtd: MTD device structure ++ * @bd: descriptor for the good/bad block search pattern ++ * @offs: address offset of spi nand(from) ++ * @buf: temporary buffer ++ * @rpagenum: the number of the pages to read ++ * ++ * Scan the partially pages in a given block ++ */ ++static int spinand_scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, ++ loff_t offs, uint8_t *buf, int rpagenum) ++{ ++ struct mtd_oob_ops ops; ++ int j, ret; ++ ++ ops.ooblen = mtd->oobsize; ++ ops.oobbuf = buf; ++ ops.ooboffs = 0; ++ ops.datbuf = NULL; ++ ops.mode = MTD_OPS_RAW; ++ ops.len = 0; ++ ++ for (j = 0; j < rpagenum; j++) ++ { ++ /* ++ * Read the full oob until read_oob is fixed to handle single ++ * byte reads for 16 bit buswidth. ++ */ ++ ret = mtd_read_oob(mtd, offs, &ops); ++// printk("read oob return val is 0x%x\n", ret); ++ /* Ignore ECC errors when checking for BBM */ ++ if (ret && !mtd_is_bitflip_or_eccerr(ret)) ++ return ret; ++ ++ if (spinand_check_short_pattern(buf, bd)) ++ return 1; ++ ++ offs += mtd->writesize; ++ } ++ return 0; ++} ++ ++/** ++ * spinand_create_bbt - [GENERIC] Create a bad block table by scanning the device ++ * @mtd: MTD device structure ++ * @buf: temporary buffer ++ * @bd: descriptor for the good/bad block search pattern ++ * @chip: create the table for a specific chip, -1 read all chips; applies only ++ * if NAND_BBT_PERCHIP option is set ++ * ++ * Create a bad block table by scanning the device for the given good/bad block ++ * identify pattern. ++ */ ++static int spinand_create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) ++{ ++ struct spinand_chip *this = mtd->priv; ++ int i, numblocks, rpagenum, scanlen; ++ int startblock; ++ loff_t from; ++ size_t readlen; ++ ++ pr_info("%s: Scanning device for bad blocks\n", __FUNCTION__); ++ ++ /* get the page numbers what we want to scan */ ++ if (bd->options & NAND_BBT_SCANALLPAGES) ++ rpagenum = 1 << (this->bbt_erase_shift - this->page_shift); ++ else if (bd->options & NAND_BBT_SCAN2NDPAGE) ++ rpagenum = 2; ++ else ++ rpagenum = 1; ++ ++ if (!(bd->options & NAND_BBT_SCANEMPTY)) { ++ /* We need only read few bytes from the OOB area */ ++ scanlen = 0; ++ readlen = bd->len; ++ } else { ++ /* Full page content should be read */ ++ scanlen = mtd->writesize + mtd->oobsize; ++ readlen = rpagenum * mtd->writesize; ++ } ++ ++ /* ++ * Note that numblocks is 2 * (real numblocks) here, see i+=2 ++ * below as it makes shifting and masking less painful ++ */ ++ numblocks = mtd->size >> (this->bbt_erase_shift - 1); ++ startblock = 0; ++ from = 0; ++ ++ /* only scan the last page */ ++ if (this->bbt_options & NAND_BBT_SCANLASTPAGE) ++ from += mtd->erasesize - (mtd->writesize * rpagenum); ++ ++ for (i = startblock; i < numblocks;) ++ { ++ int ret; ++ ++ BUG_ON(bd->options & NAND_BBT_NO_OOB); ++ ++ if (bd->options & NAND_BBT_SCANALLPAGES) ++ ret = spinand_scan_block_full(mtd, bd, from, buf, readlen, scanlen, rpagenum); ++ else ++ ret = spinand_scan_block_fast(mtd, bd, from, buf, rpagenum); ++ ++ if (ret < 0) ++ { ++ pr_err("[%s]Never go here!\n", __FUNCTION__); ++ return ret; ++ } ++ ++ if (ret) { ++ this->bbt[i >> 3] |= 0x03 << (i & 0x6); ++ pr_info("Bad eraseblock %d at 0x%012llx\n", ++ i >> 1, (unsigned long long)from); ++ mtd->ecc_stats.badblocks++; ++ } ++ ++ i += 2; ++ from += (1 << this->bbt_erase_shift); ++ ++ } ++ ++#ifdef CONFIG_DEBUG_R ++{ ++ pr_info("%s: BBT content:\n", __FUNCTION__); ++ ++ int i = 0, j = 0; ++ ++ for(i = 0,j = 0; i < 512; i++,j++) ++ { ++ if(j % 16 == 0) ++ { ++ printk("\n"); ++ } ++ printk("%02x ", this->bbt[i]); ++ } ++ ++ printk("\n"); ++} ++#endif ++ ++ return 0; ++ ++} ++ ++/** ++ * spinand_search_bbt - [GENERIC] scan the device for a specific bad block table ++ * @mtd: MTD device structure ++ * @buf: temporary buffer ++ * @td: descriptor for the bad block table ++ * ++ * Read the bad block table by searching for a given ident pattern. Search is ++ * preformed either from the beginning up or from the end of the device ++ * downwards. The search starts always at the start of a block. If the option ++ * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains ++ * the bad block information of this chip. This is necessary to provide support ++ * for certain DOC devices. ++ * ++ * The bbt ident pattern resides in the oob area of the first page in a block. ++ */ ++static int spinand_search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) ++{ ++ struct spinand_chip *this = mtd->priv; ++ ++ int startblock, block, dir; ++ int scanlen = mtd->writesize + mtd->oobsize; ++ int bbtblocks; ++ int blocktopage = this->bbt_erase_shift - this->page_shift; ++ ++#ifdef CONFIG_DEBUG_R ++ ++ pr_info("[%s]: search bbt >>>\n", __FUNCTION__); ++ ++#endif ++ ++ ++ /* Search direction top -> down? */ ++ if (td->options & NAND_BBT_LASTBLOCK) ++ { ++ startblock = (mtd->size >> this->bbt_erase_shift) - 1; ++ dir = -1; ++ } ++ else ++ { ++ startblock = START_BLOCK; ++ dir = 1; ++ } ++ ++ /* calc block number on device */ ++ bbtblocks = mtd->size >> this->bbt_erase_shift; ++ ++ /* Reset version information */ ++ td->version[0] = 0; ++ td->pages[0] = -1; ++ ++ /* Scan the maximum number of blocks */ ++ for (block = 0; block < td->maxblocks; block++) ++ { ++ int actblock = startblock + dir * block; ++ loff_t offs = (loff_t)actblock << this->bbt_erase_shift; ++ ++#ifdef CONFIG_DEBUG_R ++ ++ pr_info("actblock 0x%08x\n" ++ "offs 0x%llx\n", ++ actblock, ++ offs); ++ ++#endif ++ ++ /* Read first page */ ++ spinand_scan_read_raw(mtd, buf, offs, mtd->writesize, td); ++ ++#ifdef CONFIG_DEBUG_R ++ printk("Pattern: %c,%c,%c,%c\n",td->pattern[0],td->pattern[1],td->pattern[2],td->pattern[3]); ++ printk("Pattern: %x,%x,%x,%x",td->pattern[0],td->pattern[1],td->pattern[2],td->pattern[3]); ++ ++ { ++ int i = 0, j = 0; ++ ++ for(i = 0,j = 0; i < 128; i++,j++) ++ { ++ if(j % 16 == 0) ++ { ++ printk("\n"); ++ } ++ printk("%02x ", buf[i]); ++ } ++ ++ printk("\n"); ++ } ++#endif ++ ++ if (!spinand_check_pattern(buf, scanlen, mtd->writesize, td)) ++ { ++ td->pages[0] = actblock << blocktopage; ++ if (td->options & NAND_BBT_VERSION) ++ { ++ offs = spinand_bbt_get_ver_offs(mtd, td); ++ td->version[0] = buf[offs]; ++ } ++ break; ++ } ++ } ++ ++ /* Check, if we found a bbt */ ++ if (td->pages[0] == -1) ++ pr_warn("Bad block table not found\n"); ++ else ++ pr_info("Bad block table found at page %d, version 0x%02X\n", td->pages[0], td->version[0]); ++ ++ return 0; ++ ++} ++ ++/** ++ * spinand_search_read_bbts - [GENERIC] scan the device for bad block table(s) ++ * @mtd: MTD device structure ++ * @buf: temporary buffer ++ * @td: descriptor for the bad block table ++ * @md: descriptor for the bad block table mirror ++ * ++ * Search and read the bad block table(s). ++ */ ++static int spinand_search_read_bbts( ++ struct mtd_info *mtd, uint8_t * buf, ++ struct nand_bbt_descr *td, struct nand_bbt_descr *md) ++{ ++ /* Search the primary table */ ++ spinand_search_bbt(mtd, buf, td); ++ ++ /* Search the mirror table */ ++ if (md) ++ spinand_search_bbt(mtd, buf, md); ++ ++ /* Force result check */ ++ return 1; ++} ++ ++/** ++ * spinand_write_bbt - [GENERIC] (Re)write the bad block table ++ * @mtd: MTD device structure ++ * @buf: temporary buffer ++ * @td: descriptor for the bad block table ++ * @md: descriptor for the bad block table mirror ++ * ++ * (Re)write the bad block table. ++ */ ++static int spinand_write_bbt(struct mtd_info *mtd, uint8_t *buf, ++ struct nand_bbt_descr *td, struct nand_bbt_descr *md) ++{ ++ struct spinand_chip *this = mtd->priv; ++ struct erase_info einfo; ++ int i, j, res; ++ int bits, startblock, dir, page, offs, numblocks, sft, sftmsk; ++ int bbtoffs, pageoffs, ooboffs; ++ uint8_t msk[4]; ++ uint8_t rcode = td->reserved_block_code; ++ size_t retlen, len = 0; ++ loff_t to; ++ struct mtd_oob_ops ops; ++ ++ ops.ooblen = mtd->oobsize; ++ ops.ooboffs = 0; ++ ops.datbuf = NULL; ++ ops.mode = MTD_OPS_PLACE_OOB; ++ ops.len = 0; ++ ++#ifdef CONFIG_DEBUG_W ++ pr_info("[%s]: write bbt start >>>\n", __FUNCTION__); ++#endif ++ ++ if (!rcode) ++ rcode = 0xff; ++ ++ /* Write bad block table per chip rather than per device? */ ++ numblocks = (int)(mtd->size >> this->bbt_erase_shift); ++ ++ /* ++ * There was already a version of the table, reuse the page ++ * This applies for absolute placement too, as we have the ++ * page nr. in td->pages. ++ */ ++ if (td->pages[0] != -1) { ++ page = td->pages[0]; ++ goto write; ++ } ++ ++ /* ++ * Automatic placement of the bad block table. Search direction ++ * top -> down? ++ */ ++ if (td->options & NAND_BBT_LASTBLOCK) { ++ startblock = numblocks - 1; ++ dir = -1; ++ } else { ++ startblock = START_BLOCK; ++ dir = 1; ++ } ++ ++ for (i = 0; i < td->maxblocks; i++) ++ { ++ int block = startblock + dir * i; ++ ++ /* Check, if the block is bad */ ++ switch ((this->bbt[block >> 2] >> (2 * (block & 0x03))) & 0x03) ++ { ++ case 0x01: ++ case 0x03: ++ continue; ++ } ++ page = block << (this->bbt_erase_shift - this->page_shift); ++ ++ /* Check, if the block is used by the mirror table */ ++ if (!md || md->pages[0] != page) ++ goto write; ++ } ++ ++ pr_err("No space left to write bad block table\n"); ++ return -ENOSPC; ++ ++write: ++ ++ /* Set up shift count and masks for the flash table */ ++ bits = td->options & NAND_BBT_NRBITS_MSK; ++ msk[2] = ~rcode; ++ switch (bits) { ++ case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; ++ msk[3] = 0x01; ++ break; ++ case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; ++ msk[3] = 0x03; ++ break; ++ case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; ++ msk[3] = 0x0f; ++ break; ++ case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; ++ msk[3] = 0xff; ++ break; ++ default: return -EINVAL; ++ } ++ ++ bbtoffs = 0; ++ ++ to = ((loff_t)page) << this->page_shift; ++ ++ /* Must we save the block contents? */ ++ if (td->options & NAND_BBT_SAVECONTENT) ++ { ++ /* Make it block aligned */ ++ to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1)); ++ len = 1 << this->bbt_erase_shift; ++ res = mtd_read(mtd, to, len, &retlen, buf); ++ if (res < 0) ++ { ++ if (retlen != len) { ++ pr_info("nand_bbt: error reading block for writing the bad block table\n"); ++ return res; ++ } ++ pr_warn("nand_bbt: ECC error while reading block for writing bad block table\n"); ++ } ++ ++ /* Read oob data */ ++ ops.ooblen = (len >> this->page_shift) * mtd->oobsize; ++ ops.oobbuf = &buf[len]; ++ res = mtd_read_oob(mtd, to + mtd->writesize, &ops); ++ if (res < 0 || ops.oobretlen != ops.ooblen) ++ goto outerr; ++ ++ /* Calc the byte offset in the buffer */ ++ pageoffs = page - (int)(to >> this->page_shift); ++ offs = pageoffs << this->page_shift; ++ /* Preset the bbt area with 0xff */ ++ memset(&buf[offs], 0xff, (size_t)(numblocks >> sft)); ++ ooboffs = len + (pageoffs * mtd->oobsize); ++ ++ } ++ else if (td->options & NAND_BBT_NO_OOB) ++ { ++ ooboffs = 0; ++ offs = td->len; ++ ++ /* The version byte */ ++ if (td->options & NAND_BBT_VERSION) ++ offs++; ++ /* Calc length */ ++ len = (size_t)(numblocks >> sft); ++ len += offs; ++ /* Make it page aligned! */ ++ len = ALIGN(len, mtd->writesize); ++ ++#ifdef CONFIG_DEBUG_W ++ ++ pr_info("[%s]: must go here >>>\n", __FUNCTION__); ++ pr_info(" len = %d\n", len); ++ ++#endif ++ ++ ++ /* Preset the buffer with 0xff */ ++ memset(buf, 0xff, len); ++ /* Pattern is located at the begin of first page */ ++ memcpy(buf, td->pattern, td->len); ++ } ++ else ++ { ++ /* Calc length */ ++ len = (size_t)(numblocks >> sft); ++ /* Make it page aligned! */ ++ len = ALIGN(len, mtd->writesize); ++ /* Preset the buffer with 0xff */ ++ memset(buf, 0xff, len + ++ (len >> this->page_shift)* mtd->oobsize); ++ offs = 0; ++ ooboffs = len; ++ /* Pattern is located in oob area of first page */ ++ memcpy(&buf[ooboffs + td->offs], td->pattern, td->len); ++ } ++ ++ if (td->options & NAND_BBT_VERSION) ++ buf[ooboffs + td->veroffs] = td->version[0]; ++ ++ /* Walk through the memory table */ ++ for (i = 0; i < numblocks;) ++ { ++ uint8_t dat; ++ dat = this->bbt[bbtoffs + (i >> 2)]; ++ for (j = 0; j < 4; j++, i++) ++ { ++ int sftcnt = (i << (3 - sft)) & sftmsk; ++ /* Do not store the reserved bbt blocks! */ ++ buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt); ++ dat >>= 2; ++ } ++ } ++ ++ memset(&einfo, 0, sizeof(einfo)); ++ einfo.mtd = mtd; ++ einfo.addr = to; ++ einfo.len = 1 << this->bbt_erase_shift; ++ res = spinand_erase_nand(mtd, &einfo, 1); ++ if (res < 0) ++ goto outerr; ++ ++#ifdef CONFIG_DEBUG_W ++ pr_info("[%s]: erase OK! len = %d >>>\n", __FUNCTION__, len); ++#endif ++ ++ ++ res = spinand_scan_write_bbt(mtd, to, len, buf, ++ td->options & NAND_BBT_NO_OOB ? NULL : &buf[len]); ++ if (res < 0) ++ goto outerr; ++ ++ pr_info("Bad block table written to 0x%012llx, version 0x%02X\n", ++ (unsigned long long)to, td->version[0]); ++ ++ /* Mark it as used */ ++ td->pages[0] = page; ++ ++ return 0; ++ ++ outerr: ++ pr_warn("write_bbt: error while writing bbt block = 0x%llx, %d\n",to,res); ++ return res; ++ ++} ++ ++/** ++ * spinand_memory_bbt - [GENERIC] create a memory based bad block table ++ * @mtd: MTD device structure ++ * @bd: descriptor for the good/bad block search pattern ++ * ++ * The function creates a memory based bbt by scanning the device for ++ * manufacturer / software marked good / bad blocks. ++ */ ++static inline int spinand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) ++{ ++ struct spinand_chip *chip = mtd->priv; ++ ++ bd->options &= ~NAND_BBT_SCANEMPTY; ++ return spinand_create_bbt(mtd, chip->buffers->databuf, bd); ++} ++ ++/** ++ * spinand_check_create - [GENERIC] create and write bbt(s) if necessary ++ * @mtd: MTD device structure ++ * @buf: temporary buffer ++ * @bd: descriptor for the good/bad block search pattern ++ * ++ * The function checks the results of the previous call to read_bbt and creates ++ * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found ++ * for the chip/device. Update is necessary if one of the tables is missing or ++ * the version nr. of one table is less than the other. ++ */ ++static int spinand_check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) ++{ ++ int writeops, create, res, res2, tpageno, mpageno; ++ struct spinand_chip *this = mtd->priv; ++ struct nand_bbt_descr *td = this->bbt_td; ++ struct nand_bbt_descr *md = this->bbt_md; ++ struct nand_bbt_descr *rd, *rd2; ++ uint8_t tversion, mversion; ++ ++ writeops = 0; ++ create = 0; ++ rd = NULL; ++ rd2 = NULL; ++ res = res2 = 0; ++ tpageno = td->pages[0]; ++ mpageno = md->pages[0]; ++ tversion = td->version[0]; ++ mversion = md->version[0]; ++ ++#ifdef CONFIG_DEBUG_R ++ ++ pr_info("[%s]: check & create >>>\n", __FUNCTION__); ++ pr_info("tpageno 0x%08x\n" ++ "mpageno 0x%08x\n" ++ "tversion 0x%08x\n" ++ "mversion 0x%08x\n", ++ tpageno, ++ mpageno, ++ tversion, ++ mversion); ++ ++#endif ++ ++ ++ /* Mirrored table available? */ ++ if (md) ++ { ++ if (tpageno == -1 && mpageno == -1) { ++ create = 1; ++ writeops = 0x03; ++ } else if (tpageno == -1) { ++ rd = md; ++ writeops = 0x01; ++ } else if (mpageno == -1) { ++ rd = td; ++ writeops = 0x02; ++ } else if (tversion == mversion) { ++ rd = td; ++ if (!(td->options & NAND_BBT_VERSION)) ++ rd2 = md; ++ } else if (((int8_t)(tversion - mversion)) > 0) { ++ rd = td; ++ writeops = 0x02; ++ } else { ++ rd = md; ++ writeops = 0x01; ++ } ++ } ++ else { ++ if (tpageno == -1) { ++ create = 1; ++ writeops = 0x01; ++ } else { ++ rd = td; ++ } ++ } ++ ++ if (create) ++ { ++ /* Create the bad block table by scanning the device? */ ++ if (!(td->options & NAND_BBT_CREATE)) ++ goto out; ++ ++ /* Create the table in memory by scanning the chip(s) */ ++ if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) ++ spinand_create_bbt(mtd, buf, bd); ++ ++ td->version[0] = 1; ++ if (md) ++ md->version[0] = 1; ++ } ++ ++ /* Read back first? */ ++ if (rd) ++ { ++ res = spinand_read_abs_bbt(mtd, buf, rd); ++ if (mtd_is_eccerr(res)) { ++ /* Mark table as invalid */ ++ rd->pages[0] = -1; ++ rd->version[0] = 0; ++ goto out;; ++ } ++ } ++ ++ /* If they weren't versioned, read both */ ++ if (rd2) ++ { ++ res2 = spinand_read_abs_bbt(mtd, buf, rd2); ++ if (mtd_is_eccerr(res2)) { ++ /* Mark table as invalid */ ++ rd2->pages[0] = -1; ++ rd2->version[0] = 0; ++ goto out;; ++ } ++ } ++ ++ /* Scrub the flash table(s)? */ ++ if (mtd_is_bitflip(res) || mtd_is_bitflip(res2)) ++ writeops = 0x03; ++ ++ /* Update version numbers before writing */ ++ if (md) { ++ td->version[0] = max(td->version[0], md->version[0]); ++ md->version[0] = td->version[0]; ++ } ++ ++ /* Write the bad block table to the device? */ ++ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { ++ res = spinand_write_bbt(mtd, buf, td, md); ++ if (res < 0) ++ return res; ++ } ++ ++ /* Write the mirror bad block table to the device? */ ++ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { ++ res = spinand_write_bbt(mtd, buf, md, td); ++ if (res < 0) ++ return res; ++ } ++ ++out: ++ ++ return 0; ++ ++} ++ ++/** ++ * spinand_update_bbt - [NAND Interface] update bad block table(s) ++ * @mtd: MTD device structure ++ * @offs: the offset of the newly marked block ++ * ++ * The function updates the bad block table(s). ++ */ ++int spinand_update_bbt(struct mtd_info *mtd, loff_t offs) ++{ ++ struct spinand_chip *this = mtd->priv; ++ int len, res = 0; ++ uint8_t *buf; ++ struct nand_bbt_descr *td = this->bbt_td; ++ struct nand_bbt_descr *md = this->bbt_md; ++ ++#ifdef CONFIG_DEBUG_W ++ pr_info("[%s]: update bbt >>>\n", __FUNCTION__); ++#endif ++ ++ if (!this->bbt || !td) ++ return -EINVAL; ++ ++ /* Allocate a temporary buffer for one eraseblock incl. oob */ ++ len = (1 << this->bbt_erase_shift); ++ len += (len >> this->page_shift) * mtd->oobsize; ++ buf = kmalloc(len, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ td->version[0]++; ++ if (md) ++ md->version[0]++; ++ ++ /* Write the bad block table to the device? */ ++ if (td->options & NAND_BBT_WRITE) ++ { ++ res = spinand_write_bbt(mtd, buf, td, md); ++ if (res < 0) ++ goto out; ++ } ++ ++ /* Write the mirror bad block table to the device? */ ++ if (md && (md->options & NAND_BBT_WRITE)) ++ { ++ res = spinand_write_bbt(mtd, buf, md, td); ++ } ++ ++ out: ++ ++#ifdef CONFIG_DEBUG_W ++ pr_info("[%s]: update bbt ret = %d <<<\n", __FUNCTION__, res); ++#endif ++ ++ kfree(buf); ++ return res; ++ ++} ++ ++/** ++ * spinand_mark_bbt_regions - [GENERIC] mark the bad block table regions ++ * @mtd: MTD device structure ++ * @td: bad block table descriptor ++ * ++ * The bad block table regions are marked as "bad" to prevent accidental ++ * erasures / writes. The regions are identified by the mark 0x02. ++ */ ++static void spinand_mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) ++{ ++ struct spinand_chip *this = mtd->priv; ++ int j, block, nrblocks, update; ++ uint8_t oldval, newval; ++ ++#ifdef CONFIG_DEBUG_W ++ pr_info("[%s]: mark start >>>\n", __FUNCTION__); ++#endif ++ ++ ++ /* calc the block number */ ++ nrblocks = (int)(mtd->size >> this->bbt_erase_shift); ++ ++ if ((td->options & NAND_BBT_ABSPAGE) || !(td->options & NAND_BBT_WRITE)) ++ { ++ if (td->pages[0] == -1) ++ return; ++ block = td->pages[0] >> (this->bbt_erase_shift - this->page_shift); ++ block <<= 1; ++ oldval = this->bbt[(block >> 3)]; ++ newval = oldval | (0x2 << (block & 0x06)); ++ this->bbt[(block >> 3)] = newval; ++ if ((oldval != newval) && td->reserved_block_code) ++ spinand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1)); ++ return; ++ } ++ ++ update = 0; ++ /* get the first block */ ++ if (td->options & NAND_BBT_LASTBLOCK) ++ block = nrblocks - td->maxblocks; ++ else ++ block = START_BLOCK; ++ ++ block <<= 1; ++ ++#ifdef CONFIG_DEBUG_W ++ pr_info(" block : %d\n" ++ " maxblock : %d\n", block, td->maxblocks); ++#endif ++ ++ for (j = 0; j < td->maxblocks; j++) ++ { ++ oldval = this->bbt[(block >> 3)]; ++ newval = oldval | (0x2 << (block & 0x06)); ++ this->bbt[(block >> 3)] = newval; ++ if (oldval != newval) ++ update = 1; ++ block += 2; ++ ++#ifdef CONFIG_DEBUG_W ++ pr_info("Reserve block:\n"); ++ pr_info(" oldval : %d\n" ++ " newval : %d\n" ++ " block : %d\n", oldval, newval, (block - 2)); ++#endif ++ } ++ ++ /* ++ * If we want reserved blocks to be recorded to flash, and some ++ * new ones have been marked, then we need to update the stored ++ * bbts. This should only happen once. ++ */ ++ if (update && td->reserved_block_code) ++ spinand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1)); ++ ++#ifdef CONFIG_DEBUG_W ++ pr_info("[%s]: mark end <<<\n", __FUNCTION__); ++#endif ++ ++} ++ ++/** ++ * spinand_verify_bbt_descr - verify the bad block description ++ * @mtd: MTD device structure ++ * @bd: the table to verify ++ * ++ * This functions performs a few sanity checks on the bad block description ++ * table. ++ */ ++static void spinand_verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) ++{ ++ struct spinand_chip *this = mtd->priv; ++ u32 pattern_len; ++ u32 bits; ++ u32 table_size; ++ ++ if (!bd) ++ { ++ return; ++ } ++ ++ pattern_len = bd->len; ++ bits = bd->options & NAND_BBT_NRBITS_MSK; ++ ++ BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) && ++ !(this->bbt_options & NAND_BBT_USE_FLASH)); ++ BUG_ON(!bits); ++ ++ if (bd->options & NAND_BBT_VERSION) ++ { ++ pattern_len++; ++ } ++ ++ if (bd->options & NAND_BBT_NO_OOB) ++ { ++ BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH)); ++ BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB)); ++ BUG_ON(bd->offs); ++ if (bd->options & NAND_BBT_VERSION) ++ { ++ BUG_ON(bd->veroffs != bd->len); ++ } ++ BUG_ON(bd->options & NAND_BBT_SAVECONTENT); ++ } ++ ++ table_size = mtd->size >> this->bbt_erase_shift; ++ ++ table_size >>= 3; ++ table_size *= bits; ++ if (bd->options & NAND_BBT_NO_OOB) ++ { ++ table_size += pattern_len; ++ } ++ ++ BUG_ON(table_size > (1 << this->bbt_erase_shift)); ++ ++} ++ ++/** ++ * spinand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) ++ * @mtd: MTD device structure ++ * @bd: descriptor for the good/bad block search pattern ++ * ++ * The function checks, if a bad block table(s) is/are already available. If ++ * not it scans the device for manufacturer marked good / bad blocks and writes ++ * the bad block table(s) to the selected place. ++ * ++ * The bad block table memory is allocated here. It must be freed by calling ++ * the nand_free_bbt function. ++ */ ++int spinand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) ++{ ++ struct spinand_chip *this = mtd->priv; ++ int len, res = 0; ++ uint8_t *buf; ++ struct nand_bbt_descr *td = this->bbt_td; ++ struct nand_bbt_descr *md = this->bbt_md; ++ ++ len = mtd->size >> (this->bbt_erase_shift + 2); ++ /* ++ * Allocate memory (2bit per block) and clear the memory bad block ++ * table. ++ */ ++ this->bbt = kzalloc(len, GFP_KERNEL); ++ if (!this->bbt) ++ { ++ pr_err("scan_bbt: no memory for bad block\n"); ++ return -ENOMEM; ++ } ++ ++ /* ++ * If no primary table decriptor is given, scan the device to build a ++ * memory based bad block table. ++ */ ++ if (!td) { ++ if ((res = spinand_memory_bbt(mtd, bd))) { ++ pr_err("scan_bbt: can't scan flash and build the RAM-based BBT\n"); ++ kfree(this->bbt); ++ this->bbt = NULL; ++ } ++ return res; ++ } ++ spinand_verify_bbt_descr(mtd, td); ++ spinand_verify_bbt_descr(mtd, md); ++ ++ /* Allocate a temporary buffer for one eraseblock incl. oob */ ++ len = (1 << this->bbt_erase_shift); ++ len += (len >> this->page_shift) * mtd->oobsize; ++ buf = vmalloc(len); ++ if (!buf) { ++ kfree(this->bbt); ++ this->bbt = NULL; ++ return -ENOMEM; ++ } ++ ++ /* Is the bbt at a given page? */ ++ if (td->options & NAND_BBT_ABSPAGE) { ++ res = spinand_read_abs_bbts(mtd, buf, td, md); ++ } else { ++ /* Search the bad block table using a pattern in oob */ ++ res = spinand_search_read_bbts(mtd, buf, td, md); ++ } ++ ++ /* create a new BBT */ ++ if (res) ++ { ++ res = spinand_check_create(mtd, buf, bd); ++ } ++ ++ /* Prevent the bbt regions from erasing / writing */ ++ spinand_mark_bbt_region(mtd, td); ++ if (md) ++ { ++ spinand_mark_bbt_region(mtd, md); ++ } ++ ++ /* free the above temporary buffer */ ++ vfree(buf); ++ return res; ++ ++} ++ ++/* ++ * Define some generic bad / good block scan pattern which are used ++ * while scanning a device for factory marked good / bad blocks. ++ */ ++static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; ++ ++/* Generic flash bbt descriptors */ ++static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; ++static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; ++ ++static struct nand_bbt_descr spinand_bbt_main = { ++ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE ++ | NAND_BBT_2BIT | NAND_BBT_VERSION , ++ .offs = 8, ++ .len = 4, ++ .veroffs = 12, ++ .maxblocks = 4, ++ .pattern = bbt_pattern ++}; ++ ++static struct nand_bbt_descr spinand_bbt_mirror = { ++ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE ++ | NAND_BBT_2BIT | NAND_BBT_VERSION , ++ .offs = 8, ++ .len = 4, ++ .veroffs = 12, ++ .maxblocks = 4, ++ .pattern = mirror_pattern ++}; ++ ++static struct nand_bbt_descr spinand_bbt_main_no_bbt = { ++ .options = NAND_BBT_CREATE | NAND_BBT_WRITE ++ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_NO_OOB, ++ .len = 4, ++ .veroffs = 4, ++ .maxblocks = 4, ++ //.reserved_block_code = 2, ++ .pattern = bbt_pattern ++}; ++ ++static struct nand_bbt_descr spinand_bbt_mirror_no_bbt = { ++ .options = NAND_BBT_CREATE | NAND_BBT_WRITE ++ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_NO_OOB, ++ .len = 4, ++ .veroffs = 4, ++ .maxblocks = 4, ++ //.reserved_block_code = 2, ++ .pattern = mirror_pattern ++}; ++ ++#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB) ++/** ++ * spinand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure ++ * @this: NAND chip to create descriptor for ++ * ++ * This function allocates and initializes a nand_bbt_descr for BBM detection ++ * based on the properties of @this. The new descriptor is stored in ++ * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when ++ * passed to this function. ++ */ ++static int spinand_create_badblock_pattern(struct spinand_chip *this) ++{ ++ struct nand_bbt_descr *bd; ++ if (this->badblock_pattern) { ++ pr_warn("Bad block pattern already allocated; not replacing\n"); ++ return -EINVAL; ++ } ++ bd = kzalloc(sizeof(*bd), GFP_KERNEL); ++ if (!bd) ++ return -ENOMEM; ++ bd->options = this->bbt_options & BADBLOCK_SCAN_MASK; ++ bd->offs = this->badblockpos; ++ bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1; ++ bd->pattern = scan_ff_pattern; ++ bd->options |= NAND_BBT_DYNAMICSTRUCT; ++ this->badblock_pattern = bd; ++ return 0; ++} ++ ++/** ++ * spinand_default_bbt - [NAND Interface] Select a default bad block table for the device ++ * @mtd: MTD device structure ++ * ++ * This function selects the default bad block table support for the device and ++ * calls the nand_scan_bbt function. ++ */ ++int spinand_default_bbt(struct mtd_info *mtd) ++{ ++ struct spinand_chip *this = mtd->priv; ++ ++ ++ /* Is a flash based bad block table requested? */ ++ if (this->bbt_options & NAND_BBT_USE_FLASH) { ++ /* Use the default pattern descriptors */ ++ if (!this->bbt_td) { ++ if (this->bbt_options & NAND_BBT_NO_OOB) { ++ this->bbt_td = &spinand_bbt_main_no_bbt; ++ this->bbt_md = &spinand_bbt_mirror_no_bbt; ++ } else { ++ this->bbt_td = &spinand_bbt_main; ++ this->bbt_md = &spinand_bbt_mirror; ++ } ++ } ++ } else { ++ this->bbt_td = NULL; ++ this->bbt_md = NULL; ++ } ++ ++ if (!this->badblock_pattern) ++ spinand_create_badblock_pattern(this); ++ ++ return spinand_scan_bbt(mtd, this->badblock_pattern); ++ ++} ++ ++/** ++ * spinand_isbad_bbt - [NAND Interface] Check if a block is bad ++ * @mtd: MTD device structure ++ * @offs: offset in the device ++ * @allowbbt: allow access to bad block table region ++ */ ++int spinand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) ++{ ++ struct spinand_chip *this = mtd->priv; ++ int block; ++ uint8_t res; ++ ++ /* Get block number * 2 */ ++ block = (int)(offs >> (this->bbt_erase_shift - 1)); ++ res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; ++ ++ pr_debug("spinand_isbad_bbt(): bbt info for offs 0x%08x: " ++ "(block %d) 0x%02x\n",(unsigned int)offs, block >> 1, res); ++ ++ switch ((int)res) { ++ case 0x00: ++ return 0; ++ case 0x01: ++ return 1; ++ case 0x02: ++ return allowbbt ? 0 : 1; ++ } ++ return 1; ++ ++} ++ ++EXPORT_SYMBOL(spinand_isbad_bbt); ++EXPORT_SYMBOL(spinand_scan_bbt); ++EXPORT_SYMBOL(spinand_default_bbt); ++ +diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig +index c63a64cb..c45318b0 100644 +--- a/drivers/net/ethernet/Kconfig ++++ b/drivers/net/ethernet/Kconfig +@@ -33,6 +33,7 @@ source "drivers/net/ethernet/chelsio/Kconfig" + source "drivers/net/ethernet/cirrus/Kconfig" + source "drivers/net/ethernet/cisco/Kconfig" + source "drivers/net/ethernet/davicom/Kconfig" ++source "drivers/net/ethernet/goke/Kconfig" + + config DNET + tristate "Dave ethernet support (DNET)" +diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile +index 9676a510..7b90703a 100644 +--- a/drivers/net/ethernet/Makefile ++++ b/drivers/net/ethernet/Makefile +@@ -2,6 +2,7 @@ + # Makefile for the Linux network Ethernet device drivers. + # + ++obj-$(CONFIG_GK_ETH) += goke/ + obj-$(CONFIG_NET_VENDOR_3COM) += 3com/ + obj-$(CONFIG_NET_VENDOR_8390) += 8390/ + obj-$(CONFIG_NET_VENDOR_ADAPTEC) += adaptec/ +diff --git a/drivers/net/ethernet/goke/Kconfig b/drivers/net/ethernet/goke/Kconfig +new file mode 100644 +index 00000000..7a02ba0c +--- /dev/null ++++ b/drivers/net/ethernet/goke/Kconfig +@@ -0,0 +1,14 @@ ++# ++# Acorn Network device configuration ++# These are for Acorn's Expansion card network interfaces ++# ++ ++config ETH_GOKE ++ tristate "Goke 10/100/1000 GMAC Ethernet support" ++ depends on GK_ETH ++ select CRC32 ++ select PHYLIB ++ select MII ++ help ++ This driver supports Goke 10/100/1000 GMAC Ethernet. ++ +diff --git a/drivers/net/ethernet/goke/Makefile b/drivers/net/ethernet/goke/Makefile +new file mode 100644 +index 00000000..17758d82 +--- /dev/null ++++ b/drivers/net/ethernet/goke/Makefile +@@ -0,0 +1,9 @@ ++# File: drivers/net/arm/Makefile ++# ++# Makefile for the ARM network device drivers ++# ++ ++ifdef CONFIG_ETH_GOKE ++obj-$(CONFIG_GK_ETH_EMAC_V1_00) += gk_eth_v1_00.o ++obj-$(CONFIG_GK_ETH_EMAC_V1_01) += gk_eth_v1_01.o ++endif +diff --git a/drivers/net/ethernet/goke/gk_eth_v1_00.c b/drivers/net/ethernet/goke/gk_eth_v1_00.c +new file mode 100644 +index 00000000..cc05fc6f +--- /dev/null ++++ b/drivers/net/ethernet/goke/gk_eth_v1_00.c +@@ -0,0 +1,2478 @@ ++/* ++ * drivers/net/arm/gk_eth.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* ==========================================================================*/ ++#define GKETH_PACKET_MAXFRAME (1536) ++#define GKETH_RX_COPYBREAK (1518) ++#define GKETH_RX_RNG_MIN (8) ++#define GKETH_TX_RNG_MIN (4) ++ ++#define GKETH_RXDMA_STATUS (ETH_DMA_STATUS_OVF | ETH_DMA_STATUS_RI | \ ++ ETH_DMA_STATUS_RU | ETH_DMA_STATUS_RPS | \ ++ ETH_DMA_STATUS_RWT) ++#define GKETH_RXDMA_INTEN (ETH_DMA_INTEN_OVE | ETH_DMA_INTEN_RIE | \ ++ ETH_DMA_INTEN_RUE | ETH_DMA_INTEN_RSE | \ ++ ETH_DMA_INTEN_RWE) ++#define GKETH_TXDMA_STATUS (ETH_DMA_STATUS_TI | ETH_DMA_STATUS_TPS | \ ++ ETH_DMA_STATUS_TU | ETH_DMA_STATUS_TJT | \ ++ ETH_DMA_STATUS_UNF) ++#define GKETH_TXDMA_INTEN (ETH_DMA_INTEN_TIE | ETH_DMA_INTEN_TSE | \ ++ ETH_DMA_INTEN_TUE | ETH_DMA_INTEN_TJE | \ ++ ETH_DMA_INTEN_UNE) ++#define GKETH_DMA_INTEN (ETH_DMA_INTEN_NIE | ETH_DMA_INTEN_AIE | \ ++ ETH_DMA_INTEN_FBE | GKETH_RXDMA_INTEN | \ ++ GKETH_TXDMA_INTEN) ++ ++#define GKETH_TDES0_ATOMIC_CHECK ++#undef GKETH_TDES0_ATOMIC_CHECK_ALL ++#define GKETH_RDES0_ATOMIC_CHECK ++#undef GKETH_RDES0_ATOMIC_CHECK_ALL ++ ++/* ==========================================================================*/ ++struct GKETH_desc { ++ u32 status; ++ u32 length; ++ u32 buffer1; ++ u32 buffer2; ++} __attribute((packed)); ++ ++struct GKETH_rng_info { ++ struct sk_buff *skb; ++ dma_addr_t mapping; ++ unsigned long buf_size; ++}; ++ ++struct GKETH_tx_rngmng { ++ unsigned int cur_tx; ++ unsigned int dirty_tx; ++ struct GKETH_rng_info *rng_tx; ++ struct GKETH_desc *desc_tx; ++}; ++ ++struct GKETH_rx_rngmng { ++ unsigned int cur_rx; ++ unsigned int dirty_rx; ++ struct GKETH_rng_info *rng_rx; ++ struct GKETH_desc *desc_rx; ++}; ++ ++struct GKETH_info { ++ unsigned int rx_count; ++ struct GKETH_rx_rngmng rx; ++ unsigned int tx_count; ++ unsigned int tx_irq_count; ++ struct GKETH_tx_rngmng tx; ++ dma_addr_t rx_dma_desc; ++ dma_addr_t tx_dma_desc; ++ spinlock_t lock; ++ int oldspeed; ++ int oldduplex; ++ int oldlink; ++ ++ struct net_device_stats stats; ++ struct napi_struct napi; ++ struct net_device *ndev; ++ struct mii_bus new_bus; ++ struct phy_device *phydev; ++ uint32_t msg_enable; ++ ++ unsigned char __iomem *regbase; ++ struct gk_eth_platform_info *platform_info; ++}; ++ ++/* ==========================================================================*/ ++extern uint8_t cmdline_phytype; ++static int msg_level = -1; ++module_param (msg_level, int, 0); ++MODULE_PARM_DESC (msg_level, "Override default message level"); ++ ++typedef union { /* EPHY_SPEED */ ++ u16 all; ++ struct { ++ u16 ltp_f : 8; ++ u16 isolate : 1; ++ u16 rptr : 1; ++ u16 duplex : 1; ++ u16 speed : 1; ++ u16 ane : 1; ++ u16 ldps : 1; ++ u16 disable_eee_force : 1; ++ u16 : 1; ++ } bitc; ++} GH_EPHY_SPEED_S; ++ ++static void GK_EPHY_POWER_OFF(void) ++{ ++ u16 dat; ++ ++ dat = gk_eth_readl(REG_EPHY_POWER); ++ //printk("power reg : 0x%04x\n", dat); ++ ++ gk_eth_writel(REG_EPHY_POWER, 0x03ff); ++} ++ ++static void GK_EPHY_POWER_ON(void) ++{ ++ u16 dat; ++ ++ dat = gk_eth_readl(REG_EPHY_POWER); ++ //printk("power reg : 0x%04x\n", dat); ++ ++ gk_eth_writel(REG_EPHY_POWER, 0); ++} ++ ++static void GH_EPHY_set_SPEED_ane(u8 data) ++{ ++ GH_EPHY_SPEED_S d; ++ d.all = gk_eth_readl(REG_EPHY_SPEED); ++ //d.all = *(volatile u16 *)REG_EPHY_SPEED; ++ d.bitc.ane = data; ++ gk_eth_writel(REG_EPHY_SPEED, d.all); ++ //*(volatile u16 *)REG_EPHY_SPEED = d.all; ++} ++ ++static void MHal_EMAC_WritReg8( u32 bank, u32 reg, u8 val ) ++{ ++ u32 address = REG_EPHY_CONTROL + (bank-0x32)*0x100*2; ++ address = address + (reg << 1) - (reg & 1); ++ gk_eth_writeb(address, val); ++ //*( ( volatile u8* ) address ) = val; ++} ++ ++static u8 MHal_EMAC_ReadReg8( u32 bank, u32 reg ) ++{ ++ u8 val; ++ u32 address = REG_EPHY_CONTROL + (bank-0x32)*0x100*2; ++ address = address + (reg << 1) - (reg & 1); ++ val = gk_eth_readb(address); ++ //val = *( ( volatile u8* ) address ); ++ return val; ++} ++ ++/* ==========================================================================*/ ++static inline int gkhw_dma_reset(struct GKETH_info *lp) ++{ ++ int errorCode = 0; ++ u32 counter = 0; ++ ++ gk_eth_setbitsl((unsigned int)(lp->regbase + ETH_DMA_BUS_MODE_OFFSET), ++ ETH_DMA_BUS_MODE_SWR); ++ do { ++ if (counter++ > 1000) { ++ errorCode = -EIO; ++ break; ++ } ++ mdelay(1); ++ } while (gk_eth_tstbitsl((unsigned int)(lp->regbase + ETH_DMA_BUS_MODE_OFFSET), ++ ETH_DMA_BUS_MODE_SWR)); ++ ++ if (errorCode && netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "DMA Error: Check PHY.\n"); ++ //else printk("dma reset ok\n"); ++ ++ return errorCode; ++} ++ ++static inline void gkhw_dma_int_enable(struct GKETH_info *lp) ++{ ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_INTEN_OFFSET), ++ GKETH_DMA_INTEN); ++} ++ ++static inline void gkhw_dma_int_disable(struct GKETH_info *lp) ++{ ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_INTEN_OFFSET), 0); ++} ++ ++static inline void gkhw_dma_rx_start(struct GKETH_info *lp) ++{ ++ gk_eth_setbitsl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET), ++ ETH_DMA_OPMODE_SR); ++} ++ ++static inline void gkhw_dma_rx_stop(struct GKETH_info *lp) ++{ ++ unsigned int irq_status; ++ int i = 1300; ++ ++ gk_eth_clrbitsl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET), ++ ETH_DMA_OPMODE_SR); ++ do { ++ udelay(1); ++ irq_status = ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET)); ++ } while ((irq_status & ETH_DMA_STATUS_RS_MASK) && --i); ++ if ((i <= 0) && netif_msg_drv(lp)) { ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Stop RX status=0x%x, opmode=0x%x.\n", ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET)), ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET))); ++ } ++} ++ ++static inline void gkhw_dma_tx_start(struct GKETH_info *lp) ++{ ++ gk_eth_setbitsl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET), ++ ETH_DMA_OPMODE_ST); ++} ++ ++static inline void gkhw_dma_tx_stop(struct GKETH_info *lp) ++{ ++ unsigned int irq_status; ++ int i = 1300; ++ ++ gk_eth_clrbitsl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET), ++ ETH_DMA_OPMODE_ST); ++ do { ++ udelay(1); ++ irq_status = ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET)); ++ } while ((irq_status & ETH_DMA_STATUS_TS_MASK) && --i); ++ if ((i <= 0) && netif_msg_drv(lp)) { ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Stop TX status=0x%x, opmode=0x%x.\n", ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET)), ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET))); ++ } ++ gk_eth_setbitsl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET), ++ ETH_DMA_OPMODE_FTF); ++} ++ ++static inline void gkhw_dma_tx_restart(struct GKETH_info *lp, u32 entry) ++{ ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_TX_DESC_LIST_OFFSET), ++ (u32)lp->tx_dma_desc + (entry * sizeof(struct GKETH_desc))); ++ gkhw_dma_tx_start(lp); ++} ++ ++static inline void gkhw_dma_tx_poll(struct GKETH_info *lp, u32 entry) ++{ ++ lp->tx.desc_tx[entry].status = ETH_TDES0_OWN; ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_TX_POLL_DMD_OFFSET), 0x01); ++} ++ ++static inline void gkhw_stop_tx_rx(struct GKETH_info *lp) ++{ ++ unsigned int irq_status; ++ int i = 1300; ++ ++ gk_eth_clrbitsl((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET), ++ ETH_MAC_CFG_RE); ++ gk_eth_clrbitsl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET), ++ (ETH_DMA_OPMODE_SR | ETH_DMA_OPMODE_ST)); ++ do { ++ udelay(1); ++ irq_status = ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET)); ++ } while ((irq_status & (ETH_DMA_STATUS_TS_MASK | ++ ETH_DMA_STATUS_RS_MASK)) && --i); ++ if ((i <= 0) && netif_msg_drv(lp)) { ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Stop TX/RX status=0x%x, opmode=0x%x.\n", ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET)), ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET))); ++ } ++ gk_eth_clrbitsl((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET), ++ ETH_MAC_CFG_TE); ++} ++ ++static inline void gkhw_set_dma_desc(struct GKETH_info *lp) ++{ ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_RX_DESC_LIST_OFFSET), ++ lp->rx_dma_desc); ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_TX_DESC_LIST_OFFSET), ++ lp->tx_dma_desc); ++} ++ ++static inline phy_interface_t gkhw_get_interface(struct GKETH_info *lp) ++{ ++ return gk_eth_tstbitsl((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET), ++ ETH_MAC_CFG_PS) ? PHY_INTERFACE_MODE_RMII : ++ PHY_INTERFACE_MODE_RMII; ++ ++} ++ ++static inline void gkhw_set_hwaddr(struct GKETH_info *lp, u8 *hwaddr) ++{ ++ u32 val; ++ ++ val = (hwaddr[5] << 8) | hwaddr[4]; ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_MAC0_HI_OFFSET), val); ++ udelay(4); ++ val = (hwaddr[3] << 24) | (hwaddr[2] << 16) | ++ (hwaddr[1] << 8) | hwaddr[0]; ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_MAC0_LO_OFFSET), val); ++} ++ ++static inline void gkhw_get_hwaddr(struct GKETH_info *lp, u8 *hwaddr) ++{ ++ u32 hval; ++ u32 lval; ++ ++ hval = gk_eth_readl((unsigned int)(lp->regbase + ETH_MAC_MAC0_HI_OFFSET)); ++ lval = gk_eth_readl((unsigned int)(lp->regbase + ETH_MAC_MAC0_LO_OFFSET)); ++ hwaddr[5] = ((hval >> 8) & 0xff); ++ hwaddr[4] = ((hval >> 0) & 0xff); ++ hwaddr[3] = ((lval >> 24) & 0xff); ++ hwaddr[2] = ((lval >> 16) & 0xff); ++ hwaddr[1] = ((lval >> 8) & 0xff); ++ hwaddr[0] = ((lval >> 0) & 0xff); ++} ++ ++static inline void gkhw_set_link_mode_speed(struct GKETH_info *lp) ++{ ++ u32 val; ++ ++ val = gk_eth_readl((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET)); ++ switch (lp->oldspeed) { ++ case SPEED_1000: ++ val &= ~(ETH_MAC_CFG_PS); ++ break; ++ case SPEED_100: ++ case SPEED_10: ++ default: ++ val |= ETH_MAC_CFG_PS; ++ break; ++ } ++ if (lp->oldduplex) { ++ val &= ~(ETH_MAC_CFG_DO); ++ val |= ETH_MAC_CFG_DM; ++ } else { ++ // Steven Yu: if DO==1, would disable the receive. ++ //val &= ~(ETH_MAC_CFG_DO); ++ val &= ~(ETH_MAC_CFG_DO); ++ // Steven Yu: if DM==0, phytype==0, TX Error: No Carrier. ++ //val &= ~(ETH_MAC_CFG_DM); ++ val |= ETH_MAC_CFG_DM; ++ } ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET), val); ++} ++ ++static inline int gkhw_enable(struct GKETH_info *lp) ++{ ++ int errorCode = 0; ++ ++ //gk_set_gpio_output(&lp->platform_info->mii_power, 1); ++ //gk_set_gpio_reset(&lp->platform_info->mii_reset); ++ ++ errorCode = gkhw_dma_reset(lp); ++ if (errorCode) ++ goto gkhw_init_exit; ++ ++ gkhw_set_hwaddr(lp, lp->ndev->dev_addr); ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_BUS_MODE_OFFSET), ++ lp->platform_info->default_dma_bus_mode); ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_FRAME_FILTER_OFFSET), 0); ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET), ++ lp->platform_info->default_dma_opmode); ++#if defined(CONFIG_GK_ETH_SUPPORT_IPC) ++ gk_eth_setbitsl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET), ++ ETH_DMA_OPMODE_TSF); ++#endif ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET), ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET))); ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET), ++ (ETH_MAC_CFG_TE | ETH_MAC_CFG_RE | (1<<4)| (1<<7)| (1<<8))); ++#if defined(CONFIG_GK_ETH_SUPPORT_IPC) ++ gk_eth_setbitsl((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET), ++ ETH_MAC_CFG_IPC); ++#endif ++ ++gkhw_init_exit: ++ return errorCode; ++} ++ ++static inline void gkhw_disable(struct GKETH_info *lp) ++{ ++ gkhw_stop_tx_rx(lp); ++ gkhw_dma_int_disable(lp); ++ //gk_set_gpio_output(&lp->platform_info->mii_power, 0); ++ //gk_set_gpio_output(&lp->platform_info->mii_reset, 1); ++} ++ ++static inline void gkhw_dump(struct GKETH_info *lp) ++{ ++ u32 i; ++ ++ dev_info(&lp->ndev->dev, "RX Info: cur_rx %d, dirty_rx %d.\n", ++ lp->rx.cur_rx, lp->rx.dirty_rx); ++ dev_info(&lp->ndev->dev, "RX Info: RX descriptor " ++ "0x%08x 0x%08x 0x%08x 0x%08x.\n", ++ lp->rx.desc_rx[lp->rx.dirty_rx % lp->rx_count].status, ++ lp->rx.desc_rx[lp->rx.dirty_rx % lp->rx_count].length, ++ lp->rx.desc_rx[lp->rx.dirty_rx % lp->rx_count].buffer1, ++ lp->rx.desc_rx[lp->rx.dirty_rx % lp->rx_count].buffer2); ++ dev_info(&lp->ndev->dev, "TX Info: cur_tx %d, dirty_tx %d.\n", ++ lp->tx.cur_tx, lp->tx.dirty_tx); ++ for (i = lp->tx.dirty_tx; i < lp->tx.cur_tx; i++) { ++ dev_info(&lp->ndev->dev, "TX Info: TX descriptor[%d] " ++ "0x%08x 0x%08x 0x%08x 0x%08x.\n", i, ++ lp->tx.desc_tx[i % lp->tx_count].status, ++ lp->tx.desc_tx[i % lp->tx_count].length, ++ lp->tx.desc_tx[i % lp->tx_count].buffer1, ++ lp->tx.desc_tx[i % lp->tx_count].buffer2); ++ } ++ for (i = 0; i <= 21; i++) { ++ dev_info(&lp->ndev->dev, "GMAC[%d]: 0x%08x.\n", i, ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET + (i << 2)))); ++ } ++ for (i = 0; i <= 54; i++) { ++ dev_info(&lp->ndev->dev, "GDMA[%d]: 0x%08x.\n", i, ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_BUS_MODE_OFFSET + (i << 2)))); ++ } ++} ++ ++/* ==========================================================================*/ ++static int gkhw_mdio_read(struct mii_bus *bus, ++ int mii_id, int regnum) ++{ ++//#ifdef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++ struct GKETH_info *lp; ++ int val; ++ int limit; ++ int addr; ++ ++ if(cmdline_phytype != 0){ ++ lp = (struct GKETH_info *)bus->priv; ++ ++ for (limit = lp->platform_info->mii_retry_limit; limit > 0; limit--) { ++ if (!gk_eth_tstbitsl((unsigned int)(lp->regbase + ETH_MAC_GMII_ADDR_OFFSET), ++ ETH_MAC_GMII_ADDR_GB)) ++ break; ++ udelay(lp->platform_info->mii_retry_tmo); ++ } ++ if ((limit <= 0) && netif_msg_hw(lp)) { ++ dev_err(&lp->ndev->dev, "MII Error: Preread tmo!\n"); ++ val = 0xFFFFFFFF; ++ goto gkhw_mdio_read_exit; ++ } ++ ++ val = ETH_MAC_GMII_ADDR_PA(mii_id) | ETH_MAC_GMII_ADDR_GR(regnum); ++ val |= ETH_MAC_GMII_ADDR_CR_100_150MHZ | ETH_MAC_GMII_ADDR_GB; ++ //val |= ETH_MAC_GMII_ADDR_CR_60_100MHZ | ETH_MAC_GMII_ADDR_GB; ++ //val |= ETH_MAC_GMII_ADDR_CR_250_300MHZ | ETH_MAC_GMII_ADDR_GB; ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_GMII_ADDR_OFFSET), val); ++ ++ for (limit = lp->platform_info->mii_retry_limit; limit > 0; limit--) { ++ if (!gk_eth_tstbitsl((unsigned int)(lp->regbase + ETH_MAC_GMII_ADDR_OFFSET), ++ ETH_MAC_GMII_ADDR_GB)) ++ break; ++ udelay(lp->platform_info->mii_retry_tmo); ++ } ++ if ((limit <= 0) && netif_msg_hw(lp)) { ++ dev_err(&lp->ndev->dev, "MII Error: Postread tmo!\n"); ++ val = 0xFFFFFFFF; ++ goto gkhw_mdio_read_exit; ++ } ++ ++ val = gk_eth_readl((unsigned int)(lp->regbase + ETH_MAC_GMII_DATA_OFFSET)); ++ ++ gkhw_mdio_read_exit: ++ if (netif_msg_hw(lp)) ++ { ++ printk("mdio read error\n"); ++ dev_info(&lp->ndev->dev, ++ "MII Read: id[0x%02x], add[0x%02x], val[0x%04x].\n", ++ mii_id, regnum, val); ++ } ++ ++ return val; ++ } else { ++//#else ++ ++ lp = (struct GKETH_info *)bus->priv; ++ addr = REG_EPHY_CONTROL + regnum * 4; ++ val = gk_eth_readl((unsigned int)(REG_EPHY_CONTROL + regnum * 4)); ++ if(regnum == 1){ ++ if((gk_eth_readl((unsigned int)(REG_EPHY_CONTROL + 4)) & (0x1 << 5)) != 0) ++ val |= 0x1 << 2; ++ } ++ return val; ++ } ++//#endif ++} ++ ++static int gkhw_mdio_write(struct mii_bus *bus, ++ int mii_id, int regnum, u16 value) ++{ ++//#ifdef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++#define INTER_PHY_BASE 0xF0022000 ++ int errorCode = 0; ++ struct GKETH_info *lp; ++ int val; ++ int limit = 0; ++ ++ if(cmdline_phytype != 0){ ++ ++ lp = (struct GKETH_info *)bus->priv; ++ ++ if (netif_msg_hw(lp)) ++ dev_info(&lp->ndev->dev, ++ "MII Write: id[0x%02x], add[0x%02x], val[0x%04x].\n", ++ mii_id, regnum, value); ++ ++ for (limit = lp->platform_info->mii_retry_limit; limit > 0; limit--) { ++ if (!gk_eth_tstbitsl((unsigned int)(lp->regbase + ETH_MAC_GMII_ADDR_OFFSET), ++ ETH_MAC_GMII_ADDR_GB)) ++ break; ++ udelay(lp->platform_info->mii_retry_tmo); ++ } ++ if ((limit <= 0) && netif_msg_hw(lp)) { ++ dev_err(&lp->ndev->dev, "MII Error: Prewrite tmo!\n"); ++ errorCode = -EIO; ++ goto gkhw_mdio_write_exit; ++ } ++ ++ val = value; ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_GMII_DATA_OFFSET), val); ++ val = ETH_MAC_GMII_ADDR_PA(mii_id) | ETH_MAC_GMII_ADDR_GR(regnum); ++ val |= ETH_MAC_GMII_ADDR_CR_100_150MHZ | ETH_MAC_GMII_ADDR_GW | ++ //val |= ETH_MAC_GMII_ADDR_CR_60_100MHZ | ETH_MAC_GMII_ADDR_GW | ++ //val |= ETH_MAC_GMII_ADDR_CR_250_300MHZ | ETH_MAC_GMII_ADDR_GW | ++ ETH_MAC_GMII_ADDR_GB; ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_GMII_ADDR_OFFSET), val); ++ ++ for (limit = lp->platform_info->mii_retry_limit; limit > 0; limit--) { ++ if (!gk_eth_tstbitsl((unsigned int)(lp->regbase + ETH_MAC_GMII_ADDR_OFFSET), ++ ETH_MAC_GMII_ADDR_GB)) ++ break; ++ udelay(lp->platform_info->mii_retry_tmo); ++ } ++ if ((limit <= 0) && netif_msg_hw(lp)) { ++ dev_err(&lp->ndev->dev, "MII Error: Postwrite tmo!\n"); ++ errorCode = -EIO; ++ goto gkhw_mdio_write_exit; ++ } ++ ++gkhw_mdio_write_exit: ++ return errorCode; ++ } else { ++//#else ++ ++ lp = (struct GKETH_info *)bus->priv; ++ gk_eth_writel((unsigned int)(INTER_PHY_BASE + regnum * 4), value); ++ return 0; ++ } ++//#endif ++} ++ ++static int gkhw_mdio_reset(struct mii_bus *bus) ++{ ++ int errorCode = 0; ++ struct GKETH_info *lp; ++ ++ lp = (struct GKETH_info *)bus->priv; ++ ++ // LindengYu: Add reset to here ++ printk("###### PHY Reset.1.0.2\n"); ++ gk_set_gpio_output(&lp->platform_info->phy_reset, 0); ++ mdelay(10);//100ms ++ gk_set_gpio_output(&lp->platform_info->phy_reset, 1); ++ // RTL8201 need 200ms ++ mdelay(100);//100ms ++ return errorCode; ++} ++ ++#if 0 ++static int gkhw_phy_reset(struct GKETH_info *lp) ++{ ++//#ifdef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++ printk("cmdline_phytype = %d\n", cmdline_phytype); ++ if(cmdline_phytype != 0){ ++ struct gk_eth_platform_info *pf; ++ ++ pf = lp->platform_info; ++ ++ if(pf != NULL) ++ { ++ //dev_err(&lp->ndev->dev,"###### PHY Reset.1.0.1\n"); ++ printk("###### PHY Reset.1.0.1\n"); ++ gk_set_gpio_output(&pf->phy_reset, 0); ++ mdelay(50);//100ms ++ gk_set_gpio_output(&pf->phy_reset, 1); ++ mdelay(200);//100ms ++ } ++ ++ //gk_set_gpio_output(&lp->platform_info->mii_power, 0); ++ //gk_set_gpio_output(&lp->platform_info->mii_reset, 1); ++ //gk_set_gpio_output(&lp->platform_info->mii_power, 1); ++ //gk_set_gpio_output(&lp->platform_info->mii_reset, 0); ++ } ++//#endif ++ return 0; ++ ++} ++#endif ++ ++/* ==========================================================================*/ ++static void GKETH_adjust_link(struct net_device *ndev) ++{ ++ struct GKETH_info *lp; ++ unsigned long flags; ++ struct phy_device *phydev; ++ int need_update = 0; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ phydev = lp->phydev; ++ if (phydev->link) ++ { ++ if (phydev->duplex != lp->oldduplex) ++ { ++ need_update = 1; ++ lp->oldduplex = phydev->duplex; ++ } ++ if (phydev->speed != lp->oldspeed) ++ { ++ switch (phydev->speed) ++ { ++ case SPEED_1000: ++ case SPEED_100: ++ case SPEED_10: ++ need_update = 1; ++ lp->oldspeed = phydev->speed; ++ break; ++ default: ++ if (netif_msg_link(lp)) ++ dev_warn(&lp->ndev->dev, ++ "Unknown Speed(%d).\n", ++ phydev->speed); ++ break; ++ } ++ } ++ if (lp->oldlink != phydev->link) ++ { ++ need_update = 1; ++ lp->oldlink = phydev->link; ++ } ++ } ++ else if (lp->oldlink) ++ { ++ need_update = 1; ++ lp->oldlink = PHY_DOWN; ++ lp->oldspeed = 0; ++ lp->oldduplex = -1; ++ } ++ ++ if (need_update) ++ { ++ u16 rmii; ++ gkhw_set_link_mode_speed(lp); ++ rmii = gkhw_mdio_read(&lp->new_bus, lp->new_bus.phy_used->addr , 0x01); ++ //printk("#############-------------reg1 %04x--------\n", rmii); ++ if (phydev->link) ++ { ++ switch (phydev->speed) ++ { ++ case SPEED_100: ++ if(cmdline_phytype == 0) ++ { ++ gk_set_phy_speed_led(GPIO_TYPE_OUTPUT_EPHY_LED_3); ++ } ++ GH_GPIO_set_INPUT_CFG_in_sel(GPIO_GET_IN_SEL(GPIO_TYPE_INPUT_ENET_PHY_RXD_3) - 2, 0x01); ++ break; ++ case SPEED_10: ++ if(cmdline_phytype == 0) ++ { ++ gk_set_phy_speed_led(GPIO_TYPE_OUTPUT_EPHY_LED_2); ++ } ++ GH_GPIO_set_INPUT_CFG_in_sel(GPIO_GET_IN_SEL(GPIO_TYPE_INPUT_ENET_PHY_RXD_3) - 2, 0x00); ++ break; ++ default: ++ break; ++ } ++ } ++ else ++ { ++ if(cmdline_phytype == 0) ++ { ++ gk_set_phy_speed_led(GPIO_TYPE_INPUT_0); ++ } ++ } ++ if (netif_msg_link(lp)) ++ phy_print_status(phydev); ++ } ++ spin_unlock_irqrestore(&lp->lock, flags); ++} ++ ++typedef union { /* EPHY_MII_RMII */ ++ u32 all; ++ struct { ++ u32 usb_tm1 : 1; ++ u32 rmii : 1; ++ u32 : 30; ++ } bitc; ++} GH_EPHY_MII_RMII_S; ++ ++#define REG_EPHY_MII_RMII GK_VA_AHB_GREG //(0xF0020E00) /* read/write */ ++ ++void GH_EPHY_set_MII_RMII_rmii(u8 data) ++{ ++ GH_EPHY_MII_RMII_S d; ++ d.all = gk_eth_readl(REG_EPHY_MII_RMII); ++ //d.all = *(volatile u32 *)REG_EPHY_MII_RMII; ++ d.bitc.rmii = data; ++ gk_eth_writel(REG_EPHY_MII_RMII, d.all); ++ //*(volatile u32 *)REG_EPHY_MII_RMII = d.all; ++} ++ ++static int GKETH_phy_start(struct GKETH_info *lp) ++{ ++//#ifdef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++ int errorCode = 0; ++ struct phy_device *phydev; ++ phy_interface_t interface; ++ struct net_device *ndev; ++ int phy_addr; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ phydev = lp->phydev; ++ spin_unlock_irqrestore(&lp->lock, flags); ++ if (phydev) ++ goto GKETH_init_phy_exit; ++ ++ ndev = lp->ndev; ++ lp->oldlink = PHY_DOWN; ++ lp->oldspeed = 0; ++ lp->oldduplex = -1; ++ ++ if(cmdline_phytype != 0) ++ { ++ phy_addr = lp->platform_info->mii_id; ++ if ((phy_addr >= 0) && (phy_addr < PHY_MAX_ADDR)) ++ { ++ if (lp->new_bus.phy_map[phy_addr]) ++ { ++ phydev = lp->new_bus.phy_map[phy_addr]; ++ if (phydev->phy_id == lp->platform_info->phy_id) ++ { ++ goto GKETH_init_phy_default; ++ } ++ } ++ dev_notice(&lp->ndev->dev, ++ "Could not find default PHY in %d.\n", phy_addr); ++ } ++ goto GKETH_init_phy_scan; ++ ++ GKETH_init_phy_default: ++ printk("GKETH_init_phy_default ...\n"); ++ if (netif_msg_hw(lp)) ++ dev_info(&lp->ndev->dev, "Find default PHY in %d!\n", phy_addr); ++ goto GKETH_init_phy_connect; ++ ++ GKETH_init_phy_scan: ++ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { ++ if (lp->new_bus.phy_map[phy_addr]) { ++ phydev = lp->new_bus.phy_map[phy_addr]; ++ if (phydev->phy_id == lp->platform_info->phy_id) ++ goto GKETH_init_phy_connect; ++ } ++ } ++ if (!phydev) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "No PHY device.\n"); ++ errorCode = -ENODEV; ++ goto GKETH_init_phy_exit; ++ } else { ++ if (netif_msg_drv(lp)) ++ dev_notice(&lp->ndev->dev, ++ "Try PHY[%d] whose id is 0x%08x!\n", ++ phydev->addr, phydev->phy_id); ++ } ++ ++ GKETH_init_phy_connect: ++ interface = gkhw_get_interface(lp); ++ ++ phydev = phy_connect(ndev, dev_name(&phydev->dev), ++ &GKETH_adjust_link, 0, interface); ++ if (IS_ERR(phydev)) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "Could not attach to PHY!\n"); ++ errorCode = PTR_ERR(phydev); ++ goto GKETH_init_phy_exit; ++ } ++ ++ //phydev->supported &= lp->platform_info->phy_supported; ++ phydev->supported = lp->platform_info->phy_supported; ++ phydev->advertising = phydev->supported; ++ ++ //GH_EPHY_set_MII_RMII_rmii(0x0); ++ ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ lp->phydev = phydev; ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ dev_err(&lp->ndev->dev,"###### GKETH_phy_start_aneg...\n"); ++ ++ errorCode = phy_start_aneg(phydev); ++ ++ GKETH_init_phy_exit: ++ return errorCode; ++ } else { ++ ++//#else ++ interface = gkhw_get_interface(lp); ++ phydev = lp->new_bus.phy_map[0]; ++ phydev = phy_connect(ndev, dev_name(&phydev->dev), ++ &GKETH_adjust_link, 0, interface); ++ if (IS_ERR(phydev)) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "Could not attach to PHY!\n"); ++ errorCode = PTR_ERR(phydev); ++ return errorCode; ++ } ++ ++ phydev->supported = lp->platform_info->phy_supported; ++ phydev->advertising = phydev->supported; ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ lp->phydev = phydev; ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ dev_err(&lp->ndev->dev,"###### GKETH_phy_start_aneg...\n"); ++ ++ errorCode = phy_start_aneg(phydev); ++ return 0; ++ } ++} ++ ++static void GKETH_phy_stop(struct GKETH_info *lp) ++{ ++ struct phy_device *phydev; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ phydev = lp->phydev; ++ dev_err(&lp->ndev->dev,"###### GKETH_phy_stop\n"); ++ lp->phydev = NULL; ++ spin_unlock_irqrestore(&lp->lock, flags); ++ if (phydev) ++ phy_disconnect(phydev); ++} ++ ++static inline int GKETH_rx_rngmng_check_skb(struct GKETH_info *lp, u32 entry) ++{ ++ int errorCode = 0; ++ dma_addr_t mapping; ++ struct sk_buff *skb; ++ ++ if (lp->rx.rng_rx[entry].skb == NULL) { ++ skb = dev_alloc_skb(GKETH_PACKET_MAXFRAME); ++ if (skb == NULL) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "RX Error: dev_alloc_skb.\n"); ++ errorCode = -ENOMEM; ++ goto GKETH_rx_rngmng_skb_exit; ++ } ++ ++ skb->dev = lp->ndev; ++ lp->rx.rng_rx[entry].buf_size = GKETH_PACKET_MAXFRAME; ++ mapping = dma_map_single(&lp->ndev->dev, ++ skb->data, ++ lp->rx.rng_rx[entry].buf_size, ++ DMA_FROM_DEVICE); ++ ++ lp->rx.rng_rx[entry].skb = skb; ++ lp->rx.rng_rx[entry].mapping = mapping; ++ lp->rx.desc_rx[entry].buffer1 = mapping; ++ } ++ ++GKETH_rx_rngmng_skb_exit: ++ return errorCode; ++} ++ ++static inline void GKETH_rx_rngmng_init(struct GKETH_info *lp) ++{ ++ int i; ++ ++ lp->rx.cur_rx = 0; ++ lp->rx.dirty_rx = 0; ++ for (i = 0; i < lp->rx_count; i++) { ++ if (GKETH_rx_rngmng_check_skb(lp, i)) ++ break; ++ lp->rx.desc_rx[i].status = ETH_RDES0_OWN; ++ lp->rx.desc_rx[i].length = ++ ETH_RDES1_RCH | GKETH_PACKET_MAXFRAME; ++ lp->rx.desc_rx[i].buffer2 = (u32)lp->rx_dma_desc + ++ ((i + 1) * sizeof(struct GKETH_desc)); ++ } ++ lp->rx.desc_rx[lp->rx_count - 1].buffer2 = (u32)lp->rx_dma_desc; ++} ++ ++static inline void GKETH_rx_rngmng_refill(struct GKETH_info *lp) ++{ ++ u32 entry; ++ ++ while (lp->rx.cur_rx > lp->rx.dirty_rx) { ++ entry = lp->rx.dirty_rx % lp->rx_count; ++ if (GKETH_rx_rngmng_check_skb(lp, entry)) ++ break; ++ lp->rx.desc_rx[entry].status = ETH_RDES0_OWN; ++ lp->rx.dirty_rx++; ++ } ++} ++ ++static inline void GKETH_rx_rngmng_del(struct GKETH_info *lp) ++{ ++ int i; ++ dma_addr_t mapping; ++ struct sk_buff *skb; ++ ++ for (i = 0; i < lp->rx_count; i++) { ++ if (lp->rx.rng_rx) { ++ skb = lp->rx.rng_rx[i].skb; ++ mapping = lp->rx.rng_rx[i].mapping; ++ lp->rx.rng_rx[i].skb = NULL; ++ lp->rx.rng_rx[i].mapping = 0; ++ if (skb) { ++ dma_unmap_single(&lp->ndev->dev, mapping, ++ lp->rx.rng_rx[i].buf_size, DMA_FROM_DEVICE); ++ dev_kfree_skb(skb); ++ } ++ lp->rx.rng_rx[i].buf_size = 0; ++ } ++ if (lp->rx.desc_rx) { ++ lp->rx.desc_rx[i].status = 0; ++ lp->rx.desc_rx[i].length = 0; ++ lp->rx.desc_rx[i].buffer1 = 0xBADF00D0; ++ lp->rx.desc_rx[i].buffer2 = 0xBADF00D0; ++ } ++ } ++} ++ ++static inline void GKETH_tx_rngmng_init(struct GKETH_info *lp) ++{ ++ int i; ++ ++ lp->tx.cur_tx = 0; ++ lp->tx.dirty_tx = 0; ++ for (i = 0; i < lp->tx_count; i++) { ++ lp->tx.rng_tx[i].mapping = 0 ; ++ lp->tx.desc_tx[i].length = (ETH_TDES1_LS | ETH_TDES1_FS | ++ ETH_TDES1_TCH); ++ lp->tx.desc_tx[i].buffer1 = 0; ++ lp->tx.desc_tx[i].buffer2 = (u32)lp->tx_dma_desc + ++ ((i + 1) * sizeof(struct GKETH_desc)); ++ } ++ lp->tx.desc_tx[lp->tx_count - 1].buffer2 = (u32)lp->tx_dma_desc; ++} ++ ++static inline void GKETH_tx_rngmng_del(struct GKETH_info *lp) ++{ ++ int i; ++ dma_addr_t mapping; ++ struct sk_buff *skb; ++ unsigned int dirty_tx; ++ u32 entry; ++ u32 status; ++ ++ for (dirty_tx = lp->tx.dirty_tx; lp->tx.cur_tx > dirty_tx; dirty_tx++) { ++ entry = dirty_tx % lp->tx_count; ++ if (lp->tx.desc_tx) { ++ status = lp->tx.desc_tx[entry].status; ++ if (status & ETH_TDES0_OWN) ++ lp->stats.tx_dropped++; ++ } ++ } ++ for (i = 0; i < lp->tx_count; i++) { ++ if (lp->tx.rng_tx) { ++ skb = lp->tx.rng_tx[i].skb; ++ mapping = lp->tx.rng_tx[i].mapping; ++ lp->tx.rng_tx[i].skb = NULL; ++ lp->tx.rng_tx[i].mapping = 0; ++ if (skb) { ++ dma_unmap_single(&lp->ndev->dev, mapping, ++ skb->len, DMA_TO_DEVICE); ++ dev_kfree_skb(skb); ++ } ++ } ++ if (lp->tx.desc_tx) { ++ lp->tx.desc_tx[i].status = 0; ++ lp->tx.desc_tx[i].length = 0; ++ lp->tx.desc_tx[i].buffer1 = 0xBADF00D0; ++ lp->tx.desc_tx[i].buffer2 = 0xBADF00D0; ++ } ++ } ++} ++ ++static inline void GKETH_check_dma_error(struct GKETH_info *lp, ++ u32 irq_status) ++{ ++ u32 miss_ov = 0; ++ ++ if (unlikely(irq_status & ETH_DMA_STATUS_AIS)) { ++ if (irq_status & (ETH_DMA_STATUS_RU | ETH_DMA_STATUS_OVF)) ++ miss_ov = gk_eth_readl((unsigned int)(lp->regbase + ++ ETH_DMA_MISS_FRAME_BOCNT_OFFSET)); ++ ++ if (irq_status & ETH_DMA_STATUS_FBI) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Fatal Bus Error 0x%x.\n", ++ (irq_status & ETH_DMA_STATUS_EB_MASK)); ++ } ++ if (irq_status & ETH_DMA_STATUS_ETI) { ++ if (netif_msg_tx_err(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Early Transmit.\n"); ++ } ++ if (irq_status & ETH_DMA_STATUS_RWT) { ++ if (netif_msg_rx_err(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Receive Watchdog Timeout.\n"); ++ } ++ if (irq_status & ETH_DMA_STATUS_RPS) { ++ if (netif_msg_rx_err(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Receive Process Stopped.\n"); ++ } ++ if (irq_status & ETH_DMA_STATUS_RU) { ++ if (miss_ov & ETH_DMA_MISS_FRAME_BOCNT_FRAME) { ++ lp->stats.rx_dropped += ++ ETH_DMA_MISS_FRAME_BOCNT_HOST(miss_ov); ++ } ++ gkhw_dma_rx_stop(lp); ++ if (netif_msg_rx_err(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Receive Buffer Unavailable, %d.\n", ++ ETH_DMA_MISS_FRAME_BOCNT_HOST(miss_ov)); ++ } ++ if (irq_status & ETH_DMA_STATUS_UNF) { ++ if (netif_msg_tx_err(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Transmit Underflow.\n"); ++ } ++ if (irq_status & ETH_DMA_STATUS_OVF) { ++ if (miss_ov & ETH_DMA_MISS_FRAME_BOCNT_FIFO) { ++ lp->stats.rx_fifo_errors += ++ ETH_DMA_MISS_FRAME_BOCNT_APP(miss_ov); ++ } ++ if (netif_msg_rx_err(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Receive FIFO Overflow, %d.\n", ++ ETH_DMA_MISS_FRAME_BOCNT_APP(miss_ov)); ++ } ++ if (irq_status & ETH_DMA_STATUS_TJT) { ++ lp->stats.tx_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Transmit Jabber Timeout.\n"); ++ } ++ if (irq_status & ETH_DMA_STATUS_TPS) { ++ if (netif_msg_tx_err(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Transmit Process Stopped.\n"); ++ } ++ if (netif_msg_tx_err(lp) || netif_msg_rx_err(lp)) { ++ dev_err(&lp->ndev->dev, "DMA Error: Abnormal: 0x%x.\n", ++ irq_status); ++ gkhw_dump(lp); ++ } ++ } ++} ++ ++static inline void GKETH_interrupt_rx(struct GKETH_info *lp, u32 irq_status) ++{ ++ if (irq_status & GKETH_RXDMA_STATUS) { ++ dev_vdbg(&lp->ndev->dev, "RX IRQ[0x%x]!\n", irq_status); ++ gk_eth_clrbitsl((unsigned int)(lp->regbase + ETH_DMA_INTEN_OFFSET), ++ GKETH_RXDMA_INTEN); ++ napi_schedule(&lp->napi); ++ } ++} ++ ++static inline u32 GKETH_check_tdes0_status(struct GKETH_info *lp, ++ unsigned int status) ++{ ++ u32 tx_retry = 0; ++ ++ if (status & ETH_TDES0_JT) { ++ lp->stats.tx_heartbeat_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "TX Error: Jabber Timeout.\n"); ++ } ++ if (status & ETH_TDES0_FF) { ++ lp->stats.tx_dropped++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "TX Error: Frame Flushed.\n"); ++ } ++ if (status & ETH_TDES0_PCE) { ++ lp->stats.tx_fifo_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "TX Error: Payload Checksum Error.\n"); ++ } ++ if (status & ETH_TDES0_LCA) { ++ lp->stats.tx_carrier_errors++; ++ dev_err(&lp->ndev->dev, "TX Error: Loss of Carrier.\n"); ++ } ++ if (status & ETH_TDES0_NC) { ++ lp->stats.tx_carrier_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "TX Error: No Carrier.\n"); ++ } ++ if (status & ETH_TDES0_LCO) { ++ lp->stats.tx_aborted_errors++; ++ lp->stats.collisions++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "TX Error: Late Collision.\n"); ++ } ++ if (status & ETH_TDES0_EC) { ++ lp->stats.tx_aborted_errors++; ++ lp->stats.collisions += ETH_TDES0_CC(status); ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "TX Error: Excessive Collision %d.\n", ++ ETH_TDES0_CC(status)); ++ } ++ if (status & ETH_TDES0_VF) { ++ if (netif_msg_drv(lp)) ++ dev_info(&lp->ndev->dev, "TX Info: VLAN Frame.\n"); ++ } ++ if (status & ETH_TDES0_ED) { ++ lp->stats.tx_fifo_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "TX Error: Excessive Deferral.\n"); ++ } ++ if (status & ETH_TDES0_UF) { ++ tx_retry = 1; ++ if (netif_msg_tx_err(lp)) { ++ dev_err(&lp->ndev->dev, "TX Error: Underflow Error.\n"); ++ gkhw_dump(lp); ++ } ++ } ++ if (status & ETH_TDES0_DB) { ++ lp->stats.tx_fifo_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "TX Error: Deferred Bit.\n"); ++ } ++ ++ return tx_retry; ++} ++ ++static inline void GKETH_interrupt_tx(struct GKETH_info *lp, u32 irq_status) ++{ ++ unsigned int dirty_tx; ++ unsigned int dirty_to_tx; ++ u32 entry; ++ u32 status; ++ ++ if (irq_status & GKETH_TXDMA_STATUS) ++ { ++ dev_vdbg(&lp->ndev->dev, "cur_tx[%d], dirty_tx[%d], 0x%x.\n", ++ lp->tx.cur_tx, lp->tx.dirty_tx, irq_status); ++ for (dirty_tx = lp->tx.dirty_tx; dirty_tx < lp->tx.cur_tx; dirty_tx++) ++ { ++ entry = dirty_tx % lp->tx_count; ++ status = lp->tx.desc_tx[entry].status; ++ ++ if (status & ETH_TDES0_OWN) ++ break; ++ ++ if (unlikely(status & ETH_TDES0_ES)) ++ { ++#if defined(GKETH_TDES0_ATOMIC_CHECK) ++ if ((status & ETH_TDES0_ES_MASK) == ++ ETH_TDES0_ES) { ++ if (netif_msg_probe(lp)) { ++ dev_err(&lp->ndev->dev, ++ "TX Error: Wrong ES" ++ " 0x%08x vs 0x%08x.\n", ++ status, ++ lp->tx.desc_tx[entry].status); ++ gkhw_dump(lp); ++ } ++ break; ++ } ++#endif ++ if (GKETH_check_tdes0_status(lp, status)) { ++ gkhw_dma_tx_stop(lp); ++ gkhw_dma_tx_restart(lp, entry); ++ gkhw_dma_tx_poll(lp, entry); ++ break; ++ } else { ++ lp->stats.tx_errors++; ++ } ++ } ++ else ++ { ++#if defined(GKETH_TDES0_ATOMIC_CHECK_ALL) ++ udelay(1); ++ if (unlikely(status != ++ lp->tx.desc_tx[entry].status)) { ++ if (netif_msg_probe(lp)) { ++ dev_err(&lp->ndev->dev, ++ "TX Error: Wrong status" ++ " 0x%08x vs 0x%08x.\n", ++ status, ++ lp->tx.desc_tx[entry].status); ++ gkhw_dump(lp); ++ } ++ } ++#endif ++#if defined(CONFIG_GK_ETH_SUPPORT_IPC) ++ if (unlikely(status & ETH_TDES0_IHE)) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "TX Error: IP Header Error.\n"); ++ } ++#endif ++ lp->stats.tx_bytes += ++ lp->tx.rng_tx[entry].skb->len; ++ lp->stats.tx_packets++; ++ } ++ ++ dma_unmap_single(&lp->ndev->dev, ++ lp->tx.rng_tx[entry].mapping, ++ lp->tx.rng_tx[entry].skb->len, ++ DMA_TO_DEVICE); ++ dev_kfree_skb_irq(lp->tx.rng_tx[entry].skb); ++ lp->tx.rng_tx[entry].skb = NULL; ++ lp->tx.rng_tx[entry].mapping = 0; ++ } ++ ++ dirty_to_tx = lp->tx.cur_tx - dirty_tx; ++ if (unlikely(dirty_to_tx > lp->tx_count)) { ++ netif_stop_queue(lp->ndev); ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "TX Error: TX OV.\n"); ++ gkhw_dump(lp); ++ gkhw_dma_tx_stop(lp); ++ GKETH_tx_rngmng_del(lp); ++ GKETH_tx_rngmng_init(lp); ++ dirty_tx = dirty_to_tx = 0; ++ } ++ if (likely(dirty_to_tx < (lp->tx_count / 2))) { ++ dev_vdbg(&lp->ndev->dev, "TX Info: Now gap %d.\n", ++ dirty_to_tx); ++ netif_wake_queue(lp->ndev); ++ } ++ lp->tx.dirty_tx = dirty_tx; ++ } ++} ++ ++static irqreturn_t GKETH_interrupt(int irq, void *dev_id) ++{ ++ struct net_device *ndev; ++ struct GKETH_info *lp; ++ u32 irq_status; ++ unsigned long flags; ++ ++ ndev = (struct net_device *)dev_id; ++ lp = netdev_priv(ndev); ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ irq_status = gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET)); ++ GKETH_check_dma_error(lp, irq_status); ++ GKETH_interrupt_rx(lp, irq_status); ++ GKETH_interrupt_tx(lp, irq_status); ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET), irq_status); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ return IRQ_HANDLED; ++} ++ ++static int GKETH_start_hw(struct net_device *ndev) ++{ ++ int errorCode = 0; ++ struct GKETH_info *lp; ++ unsigned long flags; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ dev_err(&lp->ndev->dev,"###### GKETH_start_hw\n"); ++ ++ #if 1 ++ //kewell add ++ //LindengYu: if reset, might change the phy address. So, reset the phy before at the get phy id. ++ //gkhw_phy_reset(lp); ++ //GKETH_phy_start(lp); ++ #else ++ gkhw_phy_set_high(lp); ++ gkhw_phy_reset(lp); ++ GH_EPHY_set_MII_RMII_rmii(0x1); ++ #endif ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ errorCode = gkhw_enable(lp); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ if (errorCode) ++ goto GKETH_start_hw_exit; ++ ++ lp->rx.rng_rx = kmalloc((sizeof(struct GKETH_rng_info) * ++ lp->rx_count), GFP_KERNEL); ++ if (lp->rx.rng_rx == NULL) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "alloc rng_rx fail.\n"); ++ errorCode = -ENOMEM; ++ goto GKETH_start_hw_exit; ++ } ++ lp->rx.desc_rx = dma_alloc_coherent(&lp->ndev->dev, ++ (sizeof(struct GKETH_desc) * lp->rx_count), ++ &lp->rx_dma_desc, GFP_KERNEL); ++ if (lp->rx.desc_rx == NULL) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "dma_alloc_coherent desc_rx fail.\n"); ++ errorCode = -ENOMEM; ++ goto GKETH_start_hw_exit; ++ } ++ memset(lp->rx.rng_rx, 0, ++ (sizeof(struct GKETH_rng_info) * lp->rx_count)); ++ memset(lp->rx.desc_rx, 0, ++ (sizeof(struct GKETH_desc) * lp->rx_count)); ++ GKETH_rx_rngmng_init(lp); ++ ++ lp->tx.rng_tx = kmalloc((sizeof(struct GKETH_rng_info) * ++ lp->tx_count), GFP_KERNEL); ++ if (lp->tx.rng_tx == NULL) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "alloc rng_tx fail.\n"); ++ errorCode = -ENOMEM; ++ goto GKETH_start_hw_exit; ++ } ++ lp->tx.desc_tx = dma_alloc_coherent(&lp->ndev->dev, ++ (sizeof(struct GKETH_desc) * lp->tx_count), ++ &lp->tx_dma_desc, GFP_KERNEL); ++ if (lp->tx.desc_tx == NULL) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "dma_alloc_coherent desc_tx fail.\n"); ++ errorCode = -ENOMEM; ++ goto GKETH_start_hw_exit; ++ } ++ memset(lp->tx.rng_tx, 0, ++ (sizeof(struct GKETH_rng_info) * lp->tx_count)); ++ memset(lp->tx.desc_tx, 0, ++ (sizeof(struct GKETH_desc) * lp->tx_count)); ++ GKETH_tx_rngmng_init(lp); ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ gkhw_set_dma_desc(lp); ++ gkhw_dma_rx_start(lp); ++ gkhw_dma_tx_start(lp); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++GKETH_start_hw_exit: ++ return errorCode; ++} ++ ++static void GKETH_stop_hw(struct net_device *ndev) ++{ ++ struct GKETH_info *lp; ++ unsigned long flags; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ gkhw_disable(lp); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ GKETH_tx_rngmng_del(lp); ++ if (lp->tx.desc_tx) { ++ dma_free_coherent(&lp->ndev->dev, ++ (sizeof(struct GKETH_desc) * lp->tx_count), ++ lp->tx.desc_tx, lp->tx_dma_desc); ++ lp->tx.desc_tx = NULL; ++ } ++ if (lp->tx.rng_tx) { ++ kfree(lp->tx.rng_tx); ++ lp->tx.rng_tx = NULL; ++ } ++ ++ GKETH_rx_rngmng_del(lp); ++ if (lp->rx.desc_rx) { ++ dma_free_coherent(&lp->ndev->dev, ++ (sizeof(struct GKETH_desc) * lp->rx_count), ++ lp->rx.desc_rx, lp->rx_dma_desc); ++ lp->rx.desc_rx = NULL; ++ } ++ if (lp->rx.rng_rx) { ++ kfree(lp->rx.rng_rx); ++ lp->rx.rng_rx = NULL; ++ } ++} ++ ++static int GKETH_open(struct net_device *ndev) ++{ ++ int errorCode = 0; ++ struct GKETH_info *lp; ++//#ifdef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++ u32 rmii; ++//#endif ++ ++ if(!(cmdline_phytype != 0)) { ++ GK_EPHY_POWER_ON(); ++ udelay(1000); ++ } ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ ++ errorCode = GKETH_start_hw(ndev); ++ if (errorCode) ++ goto GKETH_open_exit; ++ ++ errorCode = request_irq(ndev->irq, GKETH_interrupt, ++ IRQF_SHARED | IRQF_TRIGGER_HIGH, ndev->name, ndev); ++ if (errorCode) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "Request_irq[%d] fail.\n", ndev->irq); ++ goto GKETH_open_exit; ++ } ++ ++ napi_enable(&lp->napi); ++ netif_start_queue(ndev); ++ ++ ++ netif_carrier_off(ndev); ++ ++ ++ gkhw_dma_int_enable(lp); ++ ++ errorCode = GKETH_phy_start(lp); ++ ++#if 0 ++{ ++ u32 ii; ++ u32 phy_register_value = 0; ++ ++ for(ii = 0; ii < 32; ii++) ++ { ++ phy_register_value = gkhw_mdio_read(&lp->new_bus, 3 , ii); ++ //printk(" [%02d]: 0x%08x\n", ii, phy_register_value); ++ printk( "MII Read: id[0x03], add[0x%02x], val[0x%04x].\n", ++ ii, phy_register_value); ++ } ++} ++#endif ++//#ifdef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++ if(cmdline_phytype != 0) ++ { ++ if(lp->new_bus.phy_used->phy_id == 0x02430c54) // IP101g ++ { ++ // LindengYu: I don't known why do not go into effect. ++ // change to page 3 ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 20, 0x03); ++ rmii = gkhw_mdio_read(&lp->new_bus, lp->new_bus.phy_used->addr, 0x10); ++ rmii &= 0x3FFF; ++ rmii |= 0x4000; ++ // change to LED0 mode1, Link/Act mode ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 0x10, rmii); ++ // restore to page 16 ++ rmii = gkhw_mdio_read(&lp->new_bus, lp->new_bus.phy_used->addr, 0x10); ++ } ++ else// if(lp->new_bus.phy_used->phy_id == 0x001CC815) // rtl820x ++ { ++ // change to rmii mode ++ rmii = gkhw_mdio_read(&lp->new_bus, lp->new_bus.phy_used->addr, 25); ++ rmii |= (1<<10); ++ rmii &= ~(1<<11); ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 25, rmii); ++ } ++ } ++ ++//#endif ++ ++GKETH_open_exit: ++ if (errorCode) { ++ printk("eth open error\n"); ++ GKETH_phy_stop(lp); ++ GKETH_stop_hw(ndev); ++ } ++ ++ return errorCode; ++} ++ ++static int GKETH_stop(struct net_device *ndev) ++{ ++ int errorCode = 0; ++ struct GKETH_info *lp; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ ++ netif_stop_queue(ndev); ++ napi_disable(&lp->napi); ++ flush_scheduled_work(); ++ free_irq(ndev->irq, ndev); ++ GKETH_phy_stop(lp); ++ GKETH_stop_hw(ndev); ++ ++ //printk("GKETH_stop\n"); ++ GK_EPHY_POWER_OFF(); ++ ++ return errorCode; ++} ++ ++static int GKETH_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) ++{ ++ int errorCode = 0; ++ struct GKETH_info *lp; ++ dma_addr_t mapping; ++ u32 entry; ++ unsigned int dirty_to_tx; ++ u32 tx_flag; ++ unsigned long flags; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ entry = lp->tx.cur_tx % lp->tx_count; ++ dirty_to_tx = lp->tx.cur_tx - lp->tx.dirty_tx; ++ if (dirty_to_tx >= lp->tx_count) { ++ netif_stop_queue(ndev); ++ errorCode = -ENOMEM; ++ spin_unlock_irqrestore(&lp->lock, flags); ++ goto GKETH_hard_start_xmit_exit; ++ } ++ ++ mapping = dma_map_single(&lp->ndev->dev, ++ skb->data, skb->len, DMA_TO_DEVICE); ++ tx_flag = ETH_TDES1_LS | ETH_TDES1_FS | ETH_TDES1_TCH; ++ if (dirty_to_tx >= lp->tx_irq_count) { ++ netif_stop_queue(ndev); ++ tx_flag |= ETH_TDES1_IC; ++ } ++#if defined(CONFIG_GK_ETH_SUPPORT_IPC) ++ if (skb->ip_summed == CHECKSUM_PARTIAL) { ++ tx_flag |= ETH_TDES1_CIC_TUI | ETH_TDES1_CIC_HDR; ++ } ++#endif ++ lp->tx.rng_tx[entry].skb = skb; ++ lp->tx.rng_tx[entry].mapping = mapping; ++ lp->tx.desc_tx[entry].buffer1 = mapping; ++ lp->tx.desc_tx[entry].length = ETH_TDES1_TBS1x(skb->len) | tx_flag; ++ lp->tx.cur_tx++; ++ gkhw_dma_tx_poll(lp, entry); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ ndev->trans_start = jiffies; ++ dev_vdbg(&lp->ndev->dev, "TX Info: cur_tx[%d], dirty_tx[%d], " ++ "entry[%d], len[%d], data_len[%d], ip_summed[%d], " ++ "csum_start[%d], csum_offset[%d].\n", ++ lp->tx.cur_tx, lp->tx.dirty_tx, entry, skb->len, skb->data_len, ++ skb->ip_summed, skb->csum_start, skb->csum_offset); ++ ++GKETH_hard_start_xmit_exit: ++ return errorCode; ++} ++ ++static void GKETH_timeout(struct net_device *ndev) ++{ ++ struct GKETH_info *lp; ++ unsigned long flags; ++ u32 irq_status; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ ++ dev_info(&lp->ndev->dev, "OOM Info:...\n"); ++ spin_lock_irqsave(&lp->lock, flags); ++ irq_status = gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET)); ++ GKETH_interrupt_tx(lp, irq_status | GKETH_TXDMA_STATUS); ++ gkhw_dump(lp); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ netif_wake_queue(ndev); ++} ++ ++static struct net_device_stats *GKETH_get_stats(struct net_device *ndev) ++{ ++ struct GKETH_info *lp = netdev_priv(ndev); ++ ++ return &lp->stats; ++} ++ ++static inline void GKETH_check_rdes0_status(struct GKETH_info *lp, ++ unsigned int status) ++{ ++ if (status & ETH_RDES0_DE) { ++ lp->stats.rx_frame_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "RX Error: Descriptor Error.\n"); ++ } ++ if (status & ETH_RDES0_SAF) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "RX Error: Source Address Filter Fail.\n"); ++ } ++ if (status & ETH_RDES0_LE) { ++ lp->stats.rx_length_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "RX Error: Length Error.\n"); ++ } ++ if (status & ETH_RDES0_OE) { ++ lp->stats.rx_over_errors++; ++ if (netif_msg_rx_err(lp)) ++ dev_err(&lp->ndev->dev, "RX Error: Overflow Error.\n"); ++ } ++ if (status & ETH_RDES0_VLAN) { ++ if (netif_msg_drv(lp)) ++ dev_info(&lp->ndev->dev, "RX Info: VLAN.\n"); ++ } ++ if (status & ETH_RDES0_IPC) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "RX Error: IPC Checksum/Giant Frame.\n"); ++ } ++ if (status & ETH_RDES0_LC) { ++ lp->stats.collisions++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "RX Error: Late Collision.\n"); ++ } ++ if (status & ETH_RDES0_FT) { ++ if (netif_msg_rx_err(lp)) ++ dev_info(&lp->ndev->dev, ++ "RX Info: Ethernet-type frame.\n"); ++ } ++ if (status & ETH_RDES0_RWT) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "RX Error: Watchdog Timeout.\n"); ++ } ++ if (status & ETH_RDES0_RE) { ++ lp->stats.rx_errors++; ++ if (netif_msg_rx_err(lp)) ++ dev_err(&lp->ndev->dev, "RX Error: Receive.\n"); ++ } ++ if (status & ETH_RDES0_DBE) { ++ if (gk_eth_tstbitsl((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET), ++ ETH_MAC_CFG_PS)) { ++ lp->stats.rx_length_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "RX Error: Dribble Bit.\n"); ++ } ++ } ++ if (status & ETH_RDES0_CE) { ++ lp->stats.rx_crc_errors++; ++ if (netif_msg_rx_err(lp)) ++ dev_err(&lp->ndev->dev, "RX Error: CRC.\n"); ++ } ++ if (status & ETH_RDES0_RX) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "RX Error: Rx MAC Address/Payload Checksum.\n"); ++ } ++} ++ ++static inline void GKETH_napi_rx(struct GKETH_info *lp, u32 status, u32 entry) ++{ ++ short pkt_len; ++ struct sk_buff *skb; ++ dma_addr_t mapping; ++ ++ pkt_len = ETH_RDES0_FL(status) - 4; ++ ++ if (unlikely(pkt_len > GKETH_RX_COPYBREAK)) { ++ dev_warn(&lp->ndev->dev, "Bogus packet size %d.\n", pkt_len); ++ pkt_len = GKETH_RX_COPYBREAK; ++ lp->stats.rx_length_errors++; ++ } ++ ++ skb = lp->rx.rng_rx[entry].skb; ++ mapping = lp->rx.rng_rx[entry].mapping; ++ if (likely(skb && mapping)) { ++ dma_unmap_single(&lp->ndev->dev, mapping, ++ lp->rx.rng_rx[entry].buf_size, DMA_FROM_DEVICE); ++ skb->len = 0; ++ skb_put(skb, pkt_len); ++ skb->protocol = eth_type_trans(skb, lp->ndev); ++#if defined(CONFIG_GK_ETH_SUPPORT_IPC) ++ if ((status & ETH_RDES0_COE_MASK) == ETH_RDES0_COE_NOCHKERROR) { ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ } else { ++ skb->ip_summed = CHECKSUM_NONE; ++ if (netif_msg_rx_err(lp)) { ++ dev_err(&lp->ndev->dev, ++ "RX Error: RDES0_COE[0x%x].\n", status); ++ gkhw_dump(lp); ++ } ++ } ++#endif ++ netif_receive_skb(skb); ++ lp->rx.rng_rx[entry].skb = NULL; ++ lp->rx.rng_rx[entry].mapping = 0; ++ lp->ndev->last_rx = jiffies; ++ lp->stats.rx_packets++; ++ lp->stats.rx_bytes += pkt_len; ++ } else { ++ if (netif_msg_drv(lp)) { ++ dev_err(&lp->ndev->dev, ++ "RX Error: %d skb[%p], map[0x%08X].\n", ++ entry, skb, mapping); ++ gkhw_dump(lp); ++ } ++ } ++} ++ ++int GKETH_napi(struct napi_struct *napi, int budget) ++{ ++ int rx_budget = budget; ++ struct GKETH_info *lp; ++ u32 entry; ++ u32 status; ++ unsigned long flags; ++ ++ lp = container_of(napi, struct GKETH_info, napi); ++ ++ if (unlikely(!netif_carrier_ok(lp->ndev))) ++ goto GKETH_poll_complete; ++ ++ while (rx_budget > 0) { ++ entry = lp->rx.cur_rx % lp->rx_count; ++ status = lp->rx.desc_rx[entry].status; ++ if (status & ETH_RDES0_OWN) ++ break; ++#if defined(GKETH_RDES0_ATOMIC_CHECK) ++ if (unlikely((status & (ETH_RDES0_FS | ETH_RDES0_LS)) != ++ (ETH_RDES0_FS | ETH_RDES0_LS))) { ++ if (netif_msg_probe(lp)) { ++ dev_err(&lp->ndev->dev, "RX Error: Wrong FS/LS" ++ " cur_rx[%d] status 0x%08x.\n", ++ lp->rx.cur_rx, status); ++ gkhw_dump(lp); ++ } ++ break; ++ } ++#endif ++#if defined(GKETH_TDES0_ATOMIC_CHECK_ALL) ++ udelay(1); ++ if (unlikely(status != lp->rx.desc_rx[entry].status)) { ++ if (netif_msg_probe(lp)) { ++ dev_err(&lp->ndev->dev, "RX Error: Wrong status" ++ " 0x%08x vs 0x%08x.\n", ++ status, lp->rx.desc_rx[entry].status); ++ gkhw_dump(lp); ++ } ++ } ++#endif ++ if (likely((status & ETH_RDES0_ES) != ETH_RDES0_ES)) { ++ GKETH_napi_rx(lp, status, entry); ++ } else { ++ GKETH_check_rdes0_status(lp, status); ++ } ++ rx_budget--; ++ lp->rx.cur_rx++; ++ ++ if ((lp->rx.cur_rx - lp->rx.dirty_rx) > (lp->rx_count / 4)) ++ GKETH_rx_rngmng_refill(lp); ++ } ++ ++GKETH_poll_complete: ++ if (rx_budget > 0) { ++ GKETH_rx_rngmng_refill(lp); ++ spin_lock_irqsave(&lp->lock, flags); ++ napi_complete(&lp->napi); ++ gk_eth_setbitsl((unsigned int)(lp->regbase + ETH_DMA_INTEN_OFFSET), ++ GKETH_RXDMA_INTEN); ++ gkhw_dma_rx_start(lp); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ } ++ ++ return (budget - rx_budget); ++} ++ ++static inline u32 gkhw_hashtable_crc(unsigned char *mac) ++{ ++ unsigned char tmpbuf[ETH_ALEN]; ++ int i; ++ u32 crc; ++ ++ for (i = 0; i < ETH_ALEN; i++) ++ tmpbuf[i] = bitrev8(mac[i]); ++ crc = crc32_be(~0, tmpbuf, ETH_ALEN); ++ ++ return (crc ^ ~0); ++} ++ ++static inline void gkhw_hashtable_get(struct net_device *ndev, u32 *hat) ++{ ++ struct netdev_hw_addr *ha; ++ unsigned int bitnr; ++#if 0 ++ unsigned char test1[] = {0x1F,0x52,0x41,0x9C,0xB6,0xAF}; ++ unsigned char test2[] = {0xA0,0x0A,0x98,0x00,0x00,0x45}; ++ dev_info(&ndev->dev, ++ "Test1: 0x%08X.\n", gkhw_hashtable_crc(test1)); ++ dev_info(&ndev->dev, ++ "Test2: 0x%08X.\n", gkhw_hashtable_crc(test2)); ++#endif ++ ++ hat[0] = hat[1] = 0; ++ netdev_for_each_mc_addr(ha, ndev) { ++ if (!(ha->addr[0] & 1)) ++ continue; ++ bitnr = gkhw_hashtable_crc(ha->addr); ++ bitnr >>= 26; ++ bitnr &= 0x3F; ++ hat[bitnr >> 5] |= 1 << (bitnr & 31); ++ } ++} ++ ++static int GKETH_set_mac_address(struct net_device *ndev, void *addr) ++{ ++ struct GKETH_info *lp; ++ unsigned long flags; ++ struct sockaddr *saddr; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ spin_lock_irqsave(&lp->lock, flags); ++ saddr = (struct sockaddr *)(addr); ++ ++ //if (netif_running(ndev)) ++ // goto fail1; ++ ++ if (!is_valid_ether_addr(saddr->sa_data)) ++ goto fail2; ++ ++ dev_dbg(&lp->ndev->dev, "MAC address[%pM].\n", saddr->sa_data); ++ ++ memcpy(ndev->dev_addr, saddr->sa_data, ndev->addr_len); ++ gkhw_set_hwaddr(lp, ndev->dev_addr); ++ gkhw_get_hwaddr(lp, ndev->dev_addr); ++ memcpy(lp->platform_info->mac_addr, ndev->dev_addr, GKETH_MAC_SIZE); ++ ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ return 0; ++ ++fail2: ++ spin_unlock_irqrestore(&lp->lock, flags); ++ return -EADDRNOTAVAIL; ++} ++ ++static void GKETH_set_multicast_list(struct net_device *ndev) ++{ ++ struct GKETH_info *lp; ++ unsigned int mac_filter; ++ u32 hat[2]; ++ unsigned long flags; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ spin_lock_irqsave(&lp->lock, flags); ++ ++ mac_filter = gk_eth_readl((unsigned int)(lp->regbase + ++ ETH_MAC_FRAME_FILTER_OFFSET)); ++ hat[0] = 0; ++ hat[1] = 0; ++ ++ if (ndev->flags & IFF_PROMISC) { ++ mac_filter |= ETH_MAC_FRAME_FILTER_PR; ++ } else if (ndev->flags & (~IFF_PROMISC)) { ++ mac_filter &= ~ETH_MAC_FRAME_FILTER_PR; ++ } ++ ++ if (ndev->flags & IFF_ALLMULTI) { ++ hat[0] = 0xFFFFFFFF; ++ hat[1] = 0xFFFFFFFF; ++ mac_filter |= ETH_MAC_FRAME_FILTER_PM; ++ } else if (!netdev_mc_empty(ndev)) { ++ gkhw_hashtable_get(ndev, hat); ++ mac_filter &= ~ETH_MAC_FRAME_FILTER_PM; ++ mac_filter |= ETH_MAC_FRAME_FILTER_HMC; ++ } else if (ndev->flags & (~IFF_ALLMULTI)) { ++ mac_filter &= ~ETH_MAC_FRAME_FILTER_PM; ++ mac_filter |= ETH_MAC_FRAME_FILTER_HMC; ++ } ++ ++ if (netif_msg_hw(lp)) { ++ dev_info(&lp->ndev->dev, "MC Info: flags 0x%x.\n", ndev->flags); ++ dev_info(&lp->ndev->dev, "MC Info: mc_count 0x%x.\n", ++ netdev_mc_count(ndev)); ++ dev_info(&lp->ndev->dev, "MC Info: mac_filter 0x%x.\n", ++ mac_filter); ++ dev_info(&lp->ndev->dev, "MC Info: hat[0x%x:0x%x].\n", ++ hat[1], hat[0]); ++ } ++ ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_HASH_HI_OFFSET), hat[1]); ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_HASH_LO_OFFSET), hat[0]); ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_FRAME_FILTER_OFFSET), mac_filter); ++ ++ spin_unlock_irqrestore(&lp->lock, flags); ++} ++ ++ ++#ifdef CONFIG_NET_POLL_CONTROLLER ++static void GKETH_poll_controller(struct net_device *ndev) ++{ ++ GKETH_interrupt(ndev->irq, ndev); ++} ++#endif ++ ++static int GKETH_get_settings(struct net_device *ndev, ++ struct ethtool_cmd *ecmd) ++{ ++ int errorCode = 0; ++ struct GKETH_info *lp; ++ unsigned long flags; ++ ++ if (!netif_running(ndev)) { ++ errorCode = -EINVAL; ++ goto GKETH_get_settings_exit; ++ } ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ spin_lock_irqsave(&lp->lock, flags); ++ if (lp->phydev) { ++ errorCode = phy_ethtool_gset(lp->phydev, ecmd); ++ } else { ++ errorCode = -EINVAL; ++ } ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++GKETH_get_settings_exit: ++ return errorCode; ++} ++ ++static int GKETH_set_settings(struct net_device *ndev, ++ struct ethtool_cmd *ecmd) ++{ ++ int errorCode = 0; ++ struct GKETH_info *lp; ++ unsigned long flags; ++ ++ if (!netif_running(ndev)) { ++ errorCode = -EINVAL; ++ goto GKETH_get_settings_exit; ++ } ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ spin_lock_irqsave(&lp->lock, flags); ++ if (lp->phydev) { ++ errorCode = phy_ethtool_sset(lp->phydev, ecmd); ++ } else { ++ errorCode = -EINVAL; ++ } ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++GKETH_get_settings_exit: ++ return errorCode; ++} ++ ++static int GKETH_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) ++{ ++ int errorCode = 0; ++ struct GKETH_info *lp; ++ unsigned long flags; ++ ++ if (!netif_running(ndev)) { ++ errorCode = -EINVAL; ++ goto GKETH_get_settings_exit; ++ } ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ spin_lock_irqsave(&lp->lock, flags); ++ if (lp->phydev) { ++ errorCode = phy_mii_ioctl(lp->phydev, ifr, cmd); ++ } else { ++ errorCode = -EINVAL; ++ } ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++GKETH_get_settings_exit: ++ return errorCode; ++} ++ ++/* ==========================================================================*/ ++static const struct net_device_ops GKETH_netdev_ops = { ++ .ndo_open = GKETH_open, ++ .ndo_stop = GKETH_stop, ++ .ndo_start_xmit = GKETH_hard_start_xmit, ++ .ndo_set_mac_address = GKETH_set_mac_address, ++ .ndo_validate_addr = eth_validate_addr, ++ .ndo_do_ioctl = GKETH_ioctl, ++ .ndo_change_mtu = eth_change_mtu, ++ .ndo_tx_timeout = GKETH_timeout, ++ .ndo_get_stats = GKETH_get_stats, ++ .ndo_set_rx_mode = GKETH_set_multicast_list, ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ .ndo_poll_controller = GKETH_poll_controller, ++#endif ++}; ++ ++static const struct ethtool_ops GKETH_ethtool_ops = { ++ .get_settings = GKETH_get_settings, ++ .set_settings = GKETH_set_settings, ++ .get_link = ethtool_op_get_link, ++}; ++ ++static int __devinit GKETH_drv_probe(struct platform_device *pdev) ++{ ++ int errorCode = 0; ++ struct net_device *ndev; ++ struct GKETH_info *lp; ++ struct gk_eth_platform_info *platform_info; ++ struct resource *reg_res; ++ struct resource *irq_res; ++ ++ void __iomem *eth_base; ++ int i; ++//#ifndef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++ u8 uRegVal; ++//#else ++ u32 rmii; ++//#endif ++ ++ ++ platform_info = (struct gk_eth_platform_info *)pdev->dev.platform_data; ++ if (platform_info == NULL) { ++ dev_err(&pdev->dev, "Can't get platform_data!\n"); ++ errorCode = - EPERM; ++ goto GKETH_drv_probe_exit; ++ } ++ ++ if (platform_info->is_enabled) { ++ if (!platform_info->is_enabled()) { ++ dev_err(&pdev->dev, "Not enabled, check HW config!\n"); ++ errorCode = -EPERM; ++ goto GKETH_drv_probe_exit; ++ } ++ } ++ ++ reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (reg_res == NULL) { ++ dev_err(&pdev->dev, "Get reg_res failed!\n"); ++ errorCode = -ENXIO; ++ goto GKETH_drv_probe_exit; ++ } ++ ++ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ if (irq_res == NULL) { ++ dev_err(&pdev->dev, "Get irq_res failed!\n"); ++ errorCode = -ENXIO; ++ goto GKETH_drv_probe_exit; ++ } ++ ++ ndev = alloc_etherdev(sizeof(struct GKETH_info)); ++ if (ndev == NULL) { ++ dev_err(&pdev->dev, "alloc_etherdev fail.\n"); ++ errorCode = -ENOMEM; ++ goto GKETH_drv_probe_exit; ++ } ++#if 0 ++ /* get the memory region for the watchdog timer */ ++ size = resource_size(reg_res); ++ if (!request_mem_region(reg_res->start, size, pdev->name)) { ++ dev_err(&pdev->dev, "Failed to get eth's memory region\n"); ++ errorCode = -EBUSY; ++ goto GKETH_drv_probe_free_netdev; ++ } ++ ++ eth_base = ioremap(reg_res->start, size); ++ if (eth_base == NULL) { ++ dev_err(&pdev->dev, "failed to ioremap() region\n"); ++ errorCode = -EINVAL; ++ goto GKTH_drv_probe_free_res; ++ } ++#else ++ eth_base = (void __iomem *)reg_res->start; ++#endif ++ ++#define KE_DEBUG ++#ifdef KE_DEBUG ++ printk("[%s] eth_base = 0x%08x\n", __FUNCTION__, (u32)eth_base); ++#endif ++ ++ SET_NETDEV_DEV(ndev, &pdev->dev); ++ ndev->dev.dma_mask = pdev->dev.dma_mask; ++ ndev->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; ++ ndev->irq = irq_res->start; ++#if defined(CONFIG_GK_ETH_SUPPORT_IPC) ++ ndev->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; ++#endif ++ lp = netdev_priv(ndev); ++ spin_lock_init(&lp->lock); ++ lp->ndev = ndev; ++ lp->regbase = (unsigned char __iomem *)eth_base; ++ lp->platform_info = platform_info; ++ lp->rx_count = lp->platform_info->default_rx_ring_size; ++ if (lp->rx_count < GKETH_RX_RNG_MIN) ++ lp->rx_count = GKETH_RX_RNG_MIN; ++ lp->tx_count = lp->platform_info->default_tx_ring_size; ++ if (lp->tx_count < GKETH_TX_RNG_MIN) ++ lp->tx_count = GKETH_TX_RNG_MIN; ++ lp->tx_irq_count = (lp->tx_count * 2) / 3; ++ lp->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV | NETIF_MSG_LINK); ++ ++ lp->new_bus.name = "goke MII Bus", ++ lp->new_bus.read = &gkhw_mdio_read; ++ lp->new_bus.write = &gkhw_mdio_write; ++ lp->new_bus.reset = &gkhw_mdio_reset; ++ //pdev->id = 0x3; ++ //lp->platform_info->mii_id = pdev->id; ++ printk("mii id = %d \n", pdev->id); ++ snprintf(lp->new_bus.id, MII_BUS_ID_SIZE, "%x", pdev->id); ++ lp->new_bus.priv = lp; ++ lp->new_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); ++ if (lp->new_bus.irq == NULL) { ++ dev_err(&pdev->dev, "alloc new_bus.irq fail.\n"); ++ errorCode = -ENOMEM; ++ goto GKETH_drv_probe_free_mii_gpio_irq; ++ } ++ for(i = 0; i < PHY_MAX_ADDR; ++i) ++ lp->new_bus.irq[i] = PHY_POLL; ++ lp->new_bus.parent = &pdev->dev; ++ lp->new_bus.state = MDIOBUS_ALLOCATED; ++//#ifndef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++ if(cmdline_phytype == 0){ ++ lp->new_bus.phy_mask = 0xFFFFFFFE; ++ } ++//#endif ++ ++ //printk("mdiobus register ...\n"); ++ errorCode = mdiobus_register(&lp->new_bus); ++ if (errorCode) { ++ dev_err(&pdev->dev, "mdiobus_register fail%d.\n", errorCode); ++ goto GKETH_drv_probe_kfree_mdiobus; ++ } ++ //printk("ok\n"); ++//#ifdef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++ if(cmdline_phytype != 0) ++ { ++ GH_EPHY_set_MII_RMII_rmii(0x1); ++ // RMII mode GPIO_TYPE_OUTPUT_ENET_PHY_TXD_3 used as 10/100M indicator ++ gk_set_phy_speed_led(GPIO_TYPE_INPUT_0); ++ ++ if(lp->new_bus.phy_used->phy_id == 0x02430c54) // IP101g ++ { ++ // LindengYu: I don't known why do not go into effect. ++ // change to page 3 ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 20, 0x03); ++ rmii = gkhw_mdio_read(&lp->new_bus, lp->new_bus.phy_used->addr, 0x10); ++ rmii &= 0x3FFF; ++ rmii |= 0x4000; ++ // change to LED0 mode1, Link/Act mode ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 0x10, rmii); ++ // restore to page 16 ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 20, 0x10); ++ } ++ else// if(lp->new_bus.phy_used->phy_id == 0x001CC815) // rtl820x ++ { ++ // change to rmii mode ++ rmii = gkhw_mdio_read(&lp->new_bus, lp->new_bus.phy_used->addr, 25); ++ rmii |= (1<<10); ++ rmii &= ~(1<<11); ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 25, rmii); ++ } ++#if 0 ++ { ++ u16 reglist[24][2]= ++ { ++ {0x10, 0x00},{0x10, 0x01},{0x10, 0x02},{0x10, 0x03}, ++ {0x10, 0x04},{0x10, 0x05},{0x10, 0x06},{0x10, 0x07}, ++ {0x10, 0x08},{0x10, 0x10},{0x10, 0x11},{0x10, 0x12}, ++ {0x10, 0x14},{0x01, 0x11},{0x01, 0x12},{0x01, 0x17}, ++ {0x02, 0x12},{0x08, 0x11},{0x0B, 0x12},{0x12, 0x11}, ++ {0x03, 0x10},{0x04, 0x10},{0x05, 0x10},{0x11, 0x11}, ++ }; ++ // page 16 ++ u16 regdata; ++ u16 regpage=0x00; ++ u32 i; ++ printk("Page Addr Data\n"); ++ for(i=0;i<24;i++) ++ { ++ if(regpage != reglist[i][0]) ++ { ++ regpage = reglist[i][0]; ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 0x14, regpage); ++ } ++ regdata = gkhw_mdio_read(&lp->new_bus, lp->new_bus.phy_used->addr, reglist[i][1]); ++ printk("%02d %02d 0x%04x\n",reglist[i][0] ,reglist[i][1] ,regdata); ++ } ++ } ++#endif ++ //EPHY POWER OFF ++ //printk("net probe ephy power off\n"); ++ GK_EPHY_POWER_OFF(); ++ } ++ else ++ { ++//#else ++ GH_EPHY_set_MII_RMII_rmii(0x0); ++ #if 0 ++ gk_eth_writel(0xF0022540, 0x00000000); ++ gk_eth_writel(0xF00220C8, 0x0000C400); // reg_test_out(debug_bus_out) ++ gk_eth_writel(0xF00220E0, 0x0000810A); // debug mode ++ gk_eth_writel(0xF0022588, 0x00000007); // DAC 100M clk gate for 10M TX ++ #else ++ gk_eth_writel(GK_VA_ETH_PHY + 0x0540, 0x00000000); ++ gk_eth_writel(GK_VA_ETH_PHY + 0x00C8, 0x0000C400); // reg_test_out(debug_bus_out) ++ gk_eth_writel(GK_VA_ETH_PHY + 0x00E0, 0x0000810A); // debug mode ++ gk_eth_writel(GK_VA_ETH_PHY + 0x0588, 0x00000007); // DAC 100M clk gate for 10M TX ++ #endif ++ MHal_EMAC_WritReg8(0x0033, 0xde, 0x59); ++ MHal_EMAC_WritReg8(0x0033, 0xf4, 0x21); ++ MHal_EMAC_WritReg8(0x0032, 0x72, 0x80); ++ MHal_EMAC_WritReg8(0x0033, 0xfc, 0x00); ++ MHal_EMAC_WritReg8(0x0033, 0xfd, 0x00); ++ MHal_EMAC_WritReg8(0x0033, 0xb7, 0x07); ++ MHal_EMAC_WritReg8(0x0033, 0xcb, 0x11); ++ MHal_EMAC_WritReg8(0x0033, 0xcc, 0x80); ++ MHal_EMAC_WritReg8(0x0033, 0xcd, 0xd1); ++ MHal_EMAC_WritReg8(0x0033, 0xd4, 0x00); ++ MHal_EMAC_WritReg8(0x0033, 0xb9, 0x40); ++ MHal_EMAC_WritReg8(0x0033, 0xbb, 0x05); ++ MHal_EMAC_WritReg8(0x0033, 0xea, 0x46); ++ MHal_EMAC_WritReg8(0x0033, 0xa1, 0x00); ++ MHal_EMAC_WritReg8(0x0034, 0x3a, 0x03); ++ MHal_EMAC_WritReg8(0x0034, 0x3b, 0x00); ++ ++ //gain shift ++ MHal_EMAC_WritReg8(0x0033, 0xb4, 0x56); ++ ++ //det max ++ MHal_EMAC_WritReg8(0x0033, 0x4f, 0x02); ++ ++ //det min ++ MHal_EMAC_WritReg8(0x0033, 0x51, 0x01); ++ ++ //snr len (emc noise) ++ MHal_EMAC_WritReg8(0x0033, 0x77, 0x18); ++ ++ //snr k value ++ MHal_EMAC_WritReg8(0x0033, 0x43, 0x15); ++ ++ //100 gat ++ MHal_EMAC_WritReg8(0x0034, 0xc5, 0x00); ++ ++ //200 gat ++ MHal_EMAC_WritReg8(0x0034, 0x30, 0x43); ++ ++ //en_100t_phase ++ MHal_EMAC_WritReg8(0x0034, 0x39, 0x41); ++ ++ //10T waveform ++ uRegVal = MHal_EMAC_ReadReg8(0x0034, 0xe8); ++ uRegVal &= 0xf8; ++ uRegVal |= 0x06; ++ MHal_EMAC_WritReg8(0x0034, 0xe8, uRegVal); ++ MHal_EMAC_WritReg8(0x0032, 0x2b, 0x00); ++ ++ //analog ++ MHal_EMAC_WritReg8(0x0033, 0xd8, 0xb0); ++ MHal_EMAC_WritReg8(0x0033, 0xd9, 0x30); ++ ++ //disable EEE ++ uRegVal = MHal_EMAC_ReadReg8(0x0032, 0x2d); ++ uRegVal |= 0x40; ++ MHal_EMAC_WritReg8(0x0032, 0x2d, uRegVal); ++ ++ GH_EPHY_set_SPEED_ane(0x01); ++ } ++//#endif ++ ++ ether_setup(ndev); ++ ndev->netdev_ops = &GKETH_netdev_ops; ++ ndev->watchdog_timeo = lp->platform_info->watchdog_timeo; ++ netif_napi_add(ndev, &lp->napi, GKETH_napi, ++ lp->platform_info->napi_weight); ++ if (!is_valid_ether_addr(lp->platform_info->mac_addr)) ++ random_ether_addr(lp->platform_info->mac_addr); ++ memcpy(ndev->dev_addr, lp->platform_info->mac_addr, GKETH_MAC_SIZE); ++ ++ SET_ETHTOOL_OPS(ndev, &GKETH_ethtool_ops); ++ errorCode = register_netdev(ndev); ++ if (errorCode) { ++ dev_err(&pdev->dev, " register_netdev fail%d.\n", errorCode); ++ goto GKETH_drv_probe_netif_napi_del; ++ } ++ ++ platform_set_drvdata(pdev, ndev); ++ dev_notice(&pdev->dev, "MAC Address[%pM].\n", ndev->dev_addr); ++ ++ goto GKETH_drv_probe_exit; ++ ++GKETH_drv_probe_netif_napi_del: ++ netif_napi_del(&lp->napi); ++ mdiobus_unregister(&lp->new_bus); ++ ++GKETH_drv_probe_kfree_mdiobus: ++ kfree(lp->new_bus.irq); ++ ++GKETH_drv_probe_free_mii_gpio_irq: ++ //iounmap(eth_base); ++ ++//GKTH_drv_probe_free_res: ++ //release_mem_region(reg_res->start, size); ++ ++ ++//GKETH_drv_probe_free_netdev: ++ free_netdev(ndev); ++ ++GKETH_drv_probe_exit: ++ return errorCode; ++} ++ ++static int __devexit GKETH_drv_remove(struct platform_device *pdev) ++{ ++ struct net_device *ndev; ++ struct GKETH_info *lp; ++ ++ ndev = platform_get_drvdata(pdev); ++ if (ndev) { ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ unregister_netdev(ndev); ++ netif_napi_del(&lp->napi); ++ mdiobus_unregister(&lp->new_bus); ++ kfree(lp->new_bus.irq); ++ platform_set_drvdata(pdev, NULL); ++ free_netdev(ndev); ++ dev_notice(&pdev->dev, "Removed.\n"); ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int GKETH_drv_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ int errorCode = 0; ++ struct net_device *ndev; ++ struct GKETH_info *lp; ++ unsigned long flags; ++ ++ ndev = platform_get_drvdata(pdev); ++ if (ndev) { ++ if (!netif_running(ndev)) ++ goto GKETH_drv_suspend_exit; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ ++ napi_disable(&lp->napi); ++ netif_device_detach(ndev); ++ disable_irq(ndev->irq); ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ gkhw_disable(lp); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ } ++ ++GKETH_drv_suspend_exit: ++ dev_dbg(&pdev->dev, "%s exit with %d @ %d\n", ++ __func__, errorCode, state.event); ++ return errorCode; ++} ++ ++static int GKETH_drv_resume(struct platform_device *pdev) ++{ ++ int errorCode = 0; ++ struct net_device *ndev; ++ struct GKETH_info *lp; ++ unsigned long flags; ++ ++ ndev = platform_get_drvdata(pdev); ++ if (ndev) { ++ if (!netif_running(ndev)) ++ goto GKETH_drv_resume_exit; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ errorCode = gkhw_enable(lp); ++ gkhw_set_link_mode_speed(lp); ++ GKETH_rx_rngmng_init(lp); ++ GKETH_tx_rngmng_init(lp); ++ gkhw_set_dma_desc(lp); ++ gkhw_dma_rx_start(lp); ++ gkhw_dma_tx_start(lp); ++ gkhw_dma_int_enable(lp); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ if (errorCode) { ++ dev_err(&pdev->dev, "gkhw_enable.\n"); ++ } else { ++ enable_irq(ndev->irq); ++ netif_device_attach(ndev); ++ napi_enable(&lp->napi); ++ } ++ } ++ ++GKETH_drv_resume_exit: ++ dev_dbg(&pdev->dev, "%s exit with %d\n", __func__, errorCode); ++ return errorCode; ++} ++#endif ++ ++static struct platform_driver GKETH_driver = { ++ .probe = GKETH_drv_probe, ++ .remove = __devexit_p(GKETH_drv_remove), ++#ifdef CONFIG_PM ++ .suspend = GKETH_drv_suspend, ++ .resume = GKETH_drv_resume, ++#endif ++ .driver = { ++ .name = "gk-eth", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init GKETH_init(void) ++{ ++ printk("%s\n", __FUNCTION__); ++ return platform_driver_register(&GKETH_driver); ++} ++ ++static void __exit GKETH_exit(void) ++{ ++ platform_driver_unregister(&GKETH_driver); ++} ++ ++module_init(GKETH_init); ++module_exit(GKETH_exit); ++ ++MODULE_DESCRIPTION("Goke GK Ethernet Driver"); ++MODULE_AUTHOR("Goke Microelectronics Inc."); ++MODULE_LICENSE("GPL"); ++ +diff --git a/drivers/net/ethernet/goke/gk_eth_v1_01.c b/drivers/net/ethernet/goke/gk_eth_v1_01.c +new file mode 100644 +index 00000000..4bf06c03 +--- /dev/null ++++ b/drivers/net/ethernet/goke/gk_eth_v1_01.c +@@ -0,0 +1,2524 @@ ++/* ++ * drivers/net/arm/gk_eth.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* ==========================================================================*/ ++#define GKETH_PACKET_MAXFRAME (1536) ++#define GKETH_RX_COPYBREAK (1518) ++#define GKETH_RX_RNG_MIN (8) ++#define GKETH_TX_RNG_MIN (4) ++ ++#define GKETH_RXDMA_STATUS (ETH_DMA_STATUS_OVF | ETH_DMA_STATUS_RI | \ ++ ETH_DMA_STATUS_RU | ETH_DMA_STATUS_RPS | \ ++ ETH_DMA_STATUS_RWT) ++#define GKETH_RXDMA_INTEN (ETH_DMA_INTEN_OVE | ETH_DMA_INTEN_RIE | \ ++ ETH_DMA_INTEN_RUE | ETH_DMA_INTEN_RSE | \ ++ ETH_DMA_INTEN_RWE) ++#define GKETH_TXDMA_STATUS (ETH_DMA_STATUS_TI | ETH_DMA_STATUS_TPS | \ ++ ETH_DMA_STATUS_TU | ETH_DMA_STATUS_TJT | \ ++ ETH_DMA_STATUS_UNF) ++#define GKETH_TXDMA_INTEN (ETH_DMA_INTEN_TIE | ETH_DMA_INTEN_TSE | \ ++ ETH_DMA_INTEN_TUE | ETH_DMA_INTEN_TJE | \ ++ ETH_DMA_INTEN_UNE) ++#define GKETH_DMA_INTEN (ETH_DMA_INTEN_NIE | ETH_DMA_INTEN_AIE | \ ++ ETH_DMA_INTEN_FBE | GKETH_RXDMA_INTEN | \ ++ GKETH_TXDMA_INTEN) ++ ++#define GKETH_TDES0_ATOMIC_CHECK ++#undef GKETH_TDES0_ATOMIC_CHECK_ALL ++#define GKETH_RDES0_ATOMIC_CHECK ++#undef GKETH_RDES0_ATOMIC_CHECK_ALL ++ ++/* ==========================================================================*/ ++struct GKETH_desc { ++ u32 status; ++ u32 length; ++ u32 buffer1; ++ u32 buffer2; ++} __attribute((packed)); ++ ++struct GKETH_rng_info { ++ struct sk_buff *skb; ++ dma_addr_t mapping; ++ unsigned long buf_size; ++}; ++ ++struct GKETH_tx_rngmng { ++ unsigned int cur_tx; ++ unsigned int dirty_tx; ++ struct GKETH_rng_info *rng_tx; ++ struct GKETH_desc *desc_tx; ++}; ++ ++struct GKETH_rx_rngmng { ++ unsigned int cur_rx; ++ unsigned int dirty_rx; ++ struct GKETH_rng_info *rng_rx; ++ struct GKETH_desc *desc_rx; ++}; ++ ++struct GKETH_info { ++ unsigned int rx_count; ++ struct GKETH_rx_rngmng rx; ++ unsigned int tx_count; ++ unsigned int tx_irq_count; ++ struct GKETH_tx_rngmng tx; ++ dma_addr_t rx_dma_desc; ++ dma_addr_t tx_dma_desc; ++ spinlock_t lock; ++ int oldspeed; ++ int oldduplex; ++ int oldlink; ++ ++ struct net_device_stats stats; ++ struct napi_struct napi; ++ struct net_device *ndev; ++ struct mii_bus new_bus; ++ struct phy_device *phydev; ++ uint32_t msg_enable; ++ ++ unsigned char __iomem *regbase; ++ struct gk_eth_platform_info *platform_info; ++}; ++ ++/* ==========================================================================*/ ++extern uint8_t cmdline_phytype; ++static int msg_level = -1; ++module_param (msg_level, int, 0); ++MODULE_PARM_DESC (msg_level, "Override default message level"); ++ ++typedef union { /* EPHY_SPEED */ ++ u16 all; ++ struct { ++ u16 ltp_f : 8; ++ u16 isolate : 1; ++ u16 rptr : 1; ++ u16 duplex : 1; ++ u16 speed : 1; ++ u16 ane : 1; ++ u16 ldps : 1; ++ u16 disable_eee_force : 1; ++ u16 : 1; ++ } bitc; ++} GH_EPHY_SPEED_S; ++ ++static void GK_EPHY_POWER_OFF(void) ++{ ++ u16 dat; ++ ++ dat = gk_eth_readl(REG_EPHY_POWER); ++ //printk("power reg : 0x%04x\n", dat); ++ ++ gk_eth_writel(REG_EPHY_POWER, 0x03ff); ++} ++ ++static void GK_EPHY_POWER_ON(void) ++{ ++ u16 dat; ++ ++ dat = gk_eth_readl(REG_EPHY_POWER); ++ //printk("power reg : 0x%04x\n", dat); ++ ++ gk_eth_writel(REG_EPHY_POWER, 0); ++} ++ ++static void GH_EPHY_set_SPEED_ane(u8 data) ++{ ++ GH_EPHY_SPEED_S d; ++ d.all = gk_eth_readl(REG_EPHY_SPEED); ++ //d.all = *(volatile u16 *)REG_EPHY_SPEED; ++ d.bitc.ane = data; ++ gk_eth_writel(REG_EPHY_SPEED, d.all); ++ //*(volatile u16 *)REG_EPHY_SPEED = d.all; ++} ++ ++static void MHal_EMAC_WritReg8( u32 bank, u32 reg, u8 val ) ++{ ++ u32 address = REG_EPHY_CONTROL + (bank-0x32)*0x100*2; ++ address = address + (reg << 1) - (reg & 1); ++ gk_eth_writeb(address, val); ++ //*( ( volatile u8* ) address ) = val; ++} ++ ++static u8 MHal_EMAC_ReadReg8( u32 bank, u32 reg ) ++{ ++ u8 val; ++ u32 address = REG_EPHY_CONTROL + (bank-0x32)*0x100*2; ++ address = address + (reg << 1) - (reg & 1); ++ val = gk_eth_readb(address); ++ //val = *( ( volatile u8* ) address ); ++ return val; ++} ++ ++/* ==========================================================================*/ ++static inline int gkhw_dma_reset(struct GKETH_info *lp) ++{ ++ int errorCode = 0; ++ u32 counter = 0; ++ ++ gk_eth_setbitsl((unsigned int)(lp->regbase + ETH_DMA_BUS_MODE_OFFSET), ++ ETH_DMA_BUS_MODE_SWR); ++ do { ++ if (counter++ > 1000) { ++ errorCode = -EIO; ++ break; ++ } ++ mdelay(1); ++ } while (gk_eth_tstbitsl((unsigned int)(lp->regbase + ETH_DMA_BUS_MODE_OFFSET), ++ ETH_DMA_BUS_MODE_SWR)); ++ ++ if (errorCode && netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "DMA Error: Check PHY.\n"); ++ //else printk("dma reset ok\n"); ++ ++ return errorCode; ++} ++ ++static inline void gkhw_dma_int_enable(struct GKETH_info *lp) ++{ ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_INTEN_OFFSET), ++ GKETH_DMA_INTEN); ++} ++ ++static inline void gkhw_dma_int_disable(struct GKETH_info *lp) ++{ ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_INTEN_OFFSET), 0); ++} ++ ++static inline void gkhw_dma_rx_start(struct GKETH_info *lp) ++{ ++ gk_eth_setbitsl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET), ++ ETH_DMA_OPMODE_SR); ++} ++ ++static inline void gkhw_dma_rx_stop(struct GKETH_info *lp) ++{ ++ unsigned int irq_status; ++ int i = 1300; ++ ++ gk_eth_clrbitsl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET), ++ ETH_DMA_OPMODE_SR); ++ do { ++ udelay(1); ++ irq_status = ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET)); ++ } while ((irq_status & ETH_DMA_STATUS_RS_MASK) && --i); ++ if ((i <= 0) && netif_msg_drv(lp)) { ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Stop RX status=0x%x, opmode=0x%x.\n", ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET)), ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET))); ++ } ++} ++ ++static inline void gkhw_dma_tx_start(struct GKETH_info *lp) ++{ ++ gk_eth_setbitsl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET), ++ ETH_DMA_OPMODE_ST); ++} ++ ++static inline void gkhw_dma_tx_stop(struct GKETH_info *lp) ++{ ++ unsigned int irq_status; ++ int i = 1300; ++ ++ gk_eth_clrbitsl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET), ++ ETH_DMA_OPMODE_ST); ++ do { ++ udelay(1); ++ irq_status = ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET)); ++ } while ((irq_status & ETH_DMA_STATUS_TS_MASK) && --i); ++ if ((i <= 0) && netif_msg_drv(lp)) { ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Stop TX status=0x%x, opmode=0x%x.\n", ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET)), ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET))); ++ } ++ gk_eth_setbitsl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET), ++ ETH_DMA_OPMODE_FTF); ++} ++ ++static inline void gkhw_dma_tx_restart(struct GKETH_info *lp, u32 entry) ++{ ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_TX_DESC_LIST_OFFSET), ++ (u32)lp->tx_dma_desc + (entry * sizeof(struct GKETH_desc))); ++ gkhw_dma_tx_start(lp); ++} ++ ++static inline void gkhw_dma_tx_poll(struct GKETH_info *lp, u32 entry) ++{ ++ lp->tx.desc_tx[entry].status = ETH_TDES0_OWN; ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_TX_POLL_DMD_OFFSET), 0x01); ++} ++ ++static inline void gkhw_stop_tx_rx(struct GKETH_info *lp) ++{ ++ unsigned int irq_status; ++ int i = 1300; ++ ++ gk_eth_clrbitsl((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET), ++ ETH_MAC_CFG_RE); ++ gk_eth_clrbitsl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET), ++ (ETH_DMA_OPMODE_SR | ETH_DMA_OPMODE_ST)); ++ do { ++ udelay(1); ++ irq_status = ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET)); ++ } while ((irq_status & (ETH_DMA_STATUS_TS_MASK | ++ ETH_DMA_STATUS_RS_MASK)) && --i); ++ if ((i <= 0) && netif_msg_drv(lp)) { ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Stop TX/RX status=0x%x, opmode=0x%x.\n", ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET)), ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET))); ++ } ++ gk_eth_clrbitsl((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET), ++ ETH_MAC_CFG_TE); ++} ++ ++static inline void gkhw_set_dma_desc(struct GKETH_info *lp) ++{ ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_RX_DESC_LIST_OFFSET), ++ lp->rx_dma_desc); ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_TX_DESC_LIST_OFFSET), ++ lp->tx_dma_desc); ++} ++ ++static inline phy_interface_t gkhw_get_interface(struct GKETH_info *lp) ++{ ++ return gk_eth_tstbitsl((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET), ++ ETH_MAC_CFG_PS) ? PHY_INTERFACE_MODE_RMII : ++ PHY_INTERFACE_MODE_RMII; ++ ++} ++ ++static inline void gkhw_set_hwaddr(struct GKETH_info *lp, u8 *hwaddr) ++{ ++ u32 val; ++ ++ val = (hwaddr[5] << 8) | hwaddr[4]; ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_MAC0_HI_OFFSET), val); ++ udelay(4); ++ val = (hwaddr[3] << 24) | (hwaddr[2] << 16) | ++ (hwaddr[1] << 8) | hwaddr[0]; ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_MAC0_LO_OFFSET), val); ++} ++ ++static inline void gkhw_get_hwaddr(struct GKETH_info *lp, u8 *hwaddr) ++{ ++ u32 hval; ++ u32 lval; ++ ++ hval = gk_eth_readl((unsigned int)(lp->regbase + ETH_MAC_MAC0_HI_OFFSET)); ++ lval = gk_eth_readl((unsigned int)(lp->regbase + ETH_MAC_MAC0_LO_OFFSET)); ++ hwaddr[5] = ((hval >> 8) & 0xff); ++ hwaddr[4] = ((hval >> 0) & 0xff); ++ hwaddr[3] = ((lval >> 24) & 0xff); ++ hwaddr[2] = ((lval >> 16) & 0xff); ++ hwaddr[1] = ((lval >> 8) & 0xff); ++ hwaddr[0] = ((lval >> 0) & 0xff); ++} ++ ++static inline void gkhw_set_link_mode_speed(struct GKETH_info *lp) ++{ ++ u32 val; ++ ++ val = gk_eth_readl((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET)); ++ switch (lp->oldspeed) { ++ case SPEED_1000: ++ val &= ~(ETH_MAC_CFG_PS); ++ break; ++ case SPEED_100: ++ case SPEED_10: ++ default: ++ val |= ETH_MAC_CFG_PS; ++ break; ++ } ++ if (lp->oldduplex) { ++ val &= ~(ETH_MAC_CFG_DO); ++ val |= ETH_MAC_CFG_DM; ++ } else { ++ // Steven Yu: if DO==1, would disable the receive. ++ val |= (ETH_MAC_CFG_DO); ++ //val &= ~(ETH_MAC_CFG_DO); ++ // Steven Yu: if DM==0, phytype==0, TX Error: No Carrier. ++ val &= ~(ETH_MAC_CFG_DM); ++ //val |= ETH_MAC_CFG_DM; ++ } ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET), val); ++} ++ ++static inline int gkhw_enable(struct GKETH_info *lp) ++{ ++ int errorCode = 0; ++ ++ //gk_set_gpio_output(&lp->platform_info->mii_power, 1); ++ //gk_set_gpio_reset(&lp->platform_info->mii_reset); ++ ++ errorCode = gkhw_dma_reset(lp); ++ if (errorCode) ++ goto gkhw_init_exit; ++ ++ gkhw_set_hwaddr(lp, lp->ndev->dev_addr); ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_BUS_MODE_OFFSET), ++ lp->platform_info->default_dma_bus_mode); ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_FRAME_FILTER_OFFSET), 0); ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET), ++ lp->platform_info->default_dma_opmode); ++#if defined(CONFIG_GK_ETH_SUPPORT_IPC) ++ gk_eth_setbitsl((unsigned int)(lp->regbase + ETH_DMA_OPMODE_OFFSET), ++ ETH_DMA_OPMODE_TSF); ++#endif ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET), ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET))); ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET), ++ (ETH_MAC_CFG_TE | ETH_MAC_CFG_RE | (1<<4)| (1<<7)| (1<<8))); ++#if defined(CONFIG_GK_ETH_SUPPORT_IPC) ++ gk_eth_setbitsl((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET), ++ ETH_MAC_CFG_IPC); ++#endif ++ ++gkhw_init_exit: ++ return errorCode; ++} ++ ++static inline void gkhw_disable(struct GKETH_info *lp) ++{ ++ gkhw_stop_tx_rx(lp); ++ gkhw_dma_int_disable(lp); ++ //gk_set_gpio_output(&lp->platform_info->mii_power, 0); ++ //gk_set_gpio_output(&lp->platform_info->mii_reset, 1); ++} ++ ++static inline void gkhw_dump(struct GKETH_info *lp) ++{ ++ u32 i; ++ ++ dev_info(&lp->ndev->dev, "RX Info: cur_rx %d, dirty_rx %d.\n", ++ lp->rx.cur_rx, lp->rx.dirty_rx); ++ dev_info(&lp->ndev->dev, "RX Info: RX descriptor " ++ "0x%08x 0x%08x 0x%08x 0x%08x.\n", ++ lp->rx.desc_rx[lp->rx.dirty_rx % lp->rx_count].status, ++ lp->rx.desc_rx[lp->rx.dirty_rx % lp->rx_count].length, ++ lp->rx.desc_rx[lp->rx.dirty_rx % lp->rx_count].buffer1, ++ lp->rx.desc_rx[lp->rx.dirty_rx % lp->rx_count].buffer2); ++ dev_info(&lp->ndev->dev, "TX Info: cur_tx %d, dirty_tx %d.\n", ++ lp->tx.cur_tx, lp->tx.dirty_tx); ++ for (i = lp->tx.dirty_tx; i < lp->tx.cur_tx; i++) { ++ dev_info(&lp->ndev->dev, "TX Info: TX descriptor[%d] " ++ "0x%08x 0x%08x 0x%08x 0x%08x.\n", i, ++ lp->tx.desc_tx[i % lp->tx_count].status, ++ lp->tx.desc_tx[i % lp->tx_count].length, ++ lp->tx.desc_tx[i % lp->tx_count].buffer1, ++ lp->tx.desc_tx[i % lp->tx_count].buffer2); ++ } ++ for (i = 0; i <= 21; i++) { ++ dev_info(&lp->ndev->dev, "GMAC[%d]: 0x%08x.\n", i, ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET + (i << 2)))); ++ } ++ for (i = 0; i <= 54; i++) { ++ dev_info(&lp->ndev->dev, "GDMA[%d]: 0x%08x.\n", i, ++ gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_BUS_MODE_OFFSET + (i << 2)))); ++ } ++} ++ ++/* ==========================================================================*/ ++static int gkhw_mdio_read(struct mii_bus *bus, ++ int mii_id, int regnum) ++{ ++//#ifdef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++ struct GKETH_info *lp; ++ int val; ++ int limit; ++ int addr; ++ ++// printk("%s miid %d regnum:%d ",__FUNCTION__,mii_id,regnum); ++ if(cmdline_phytype != 0){ ++ lp = (struct GKETH_info *)bus->priv; ++ ++ for (limit = lp->platform_info->mii_retry_limit; limit > 0; limit--) { ++ if (!gk_eth_tstbitsl((unsigned int)(lp->regbase + ETH_MAC_GMII_ADDR_OFFSET), ++ ETH_MAC_GMII_ADDR_GB)) ++ break; ++ udelay(lp->platform_info->mii_retry_tmo); ++ } ++ if ((limit <= 0) && netif_msg_hw(lp)) { ++ dev_err(&lp->ndev->dev, "MII Error: Preread tmo!\n"); ++ val = 0xFFFFFFFF; ++ goto gkhw_mdio_read_exit; ++ } ++ ++ val = ETH_MAC_GMII_ADDR_PA(mii_id) | ETH_MAC_GMII_ADDR_GR(regnum); ++ //val |= ETH_MAC_GMII_ADDR_CR_100_150MHZ | ETH_MAC_GMII_ADDR_GB; ++ val |= ETH_MAC_GMII_ADDR_CR_60_100MHZ | ETH_MAC_GMII_ADDR_GB; ++ //val |= ETH_MAC_GMII_ADDR_CR_250_300MHZ | ETH_MAC_GMII_ADDR_GB; ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_GMII_ADDR_OFFSET), val); ++ ++ for (limit = lp->platform_info->mii_retry_limit; limit > 0; limit--) { ++ if (!gk_eth_tstbitsl((unsigned int)(lp->regbase + ETH_MAC_GMII_ADDR_OFFSET), ++ ETH_MAC_GMII_ADDR_GB)) ++ break; ++ udelay(lp->platform_info->mii_retry_tmo); ++ } ++ if ((limit <= 0) && netif_msg_hw(lp)) { ++ dev_err(&lp->ndev->dev, "MII Error: Postread tmo!\n"); ++ val = 0xFFFFFFFF; ++ goto gkhw_mdio_read_exit; ++ } ++ ++ val = gk_eth_readl((unsigned int)(lp->regbase + ETH_MAC_GMII_DATA_OFFSET)); ++ ++ gkhw_mdio_read_exit: ++ if (netif_msg_hw(lp)) ++ { ++ printk("mdio read error\n"); ++ dev_info(&lp->ndev->dev, ++ "MII Read: id[0x%02x], add[0x%02x], val[0x%04x].\n", ++ mii_id, regnum, val); ++ } ++ ++ if(val==0) ++ val=0xffff; ++//printk("value:%x\n",val); ++ return val; ++ } else { ++//#else ++ ++ lp = (struct GKETH_info *)bus->priv; ++ addr = REG_EPHY_CONTROL + regnum * 4; ++ val = gk_eth_readl((unsigned int)(REG_EPHY_CONTROL + regnum * 4)); ++ if(regnum == 1){ ++ if((gk_eth_readl((unsigned int)(REG_EPHY_CONTROL + 4)) & (0x1 << 5)) != 0) ++ val |= 0x1 << 2; ++ } ++ return val; ++ } ++//#endif ++} ++ ++static int gkhw_mdio_write(struct mii_bus *bus, ++ int mii_id, int regnum, u16 value) ++{ ++//#ifdef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++#define INTER_PHY_BASE 0xF0022000 ++ int errorCode = 0; ++ struct GKETH_info *lp; ++ int val; ++ int limit = 0; ++ ++ if(cmdline_phytype != 0){ ++ ++ lp = (struct GKETH_info *)bus->priv; ++ ++ if (netif_msg_hw(lp)) ++ dev_info(&lp->ndev->dev, ++ "MII Write: id[0x%02x], add[0x%02x], val[0x%04x].\n", ++ mii_id, regnum, value); ++ ++ for (limit = lp->platform_info->mii_retry_limit; limit > 0; limit--) { ++ if (!gk_eth_tstbitsl((unsigned int)(lp->regbase + ETH_MAC_GMII_ADDR_OFFSET), ++ ETH_MAC_GMII_ADDR_GB)) ++ break; ++ udelay(lp->platform_info->mii_retry_tmo); ++ } ++ if ((limit <= 0) && netif_msg_hw(lp)) { ++ dev_err(&lp->ndev->dev, "MII Error: Prewrite tmo!\n"); ++ errorCode = -EIO; ++ goto gkhw_mdio_write_exit; ++ } ++ ++ val = value; ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_GMII_DATA_OFFSET), val); ++ val = ETH_MAC_GMII_ADDR_PA(mii_id) | ETH_MAC_GMII_ADDR_GR(regnum); ++ //val |= ETH_MAC_GMII_ADDR_CR_100_150MHZ | ETH_MAC_GMII_ADDR_GW | ++ val |= ETH_MAC_GMII_ADDR_CR_60_100MHZ | ETH_MAC_GMII_ADDR_GW | ++ //val |= ETH_MAC_GMII_ADDR_CR_250_300MHZ | ETH_MAC_GMII_ADDR_GW | ++ ETH_MAC_GMII_ADDR_GB; ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_GMII_ADDR_OFFSET), val); ++ ++ for (limit = lp->platform_info->mii_retry_limit; limit > 0; limit--) { ++ if (!gk_eth_tstbitsl((unsigned int)(lp->regbase + ETH_MAC_GMII_ADDR_OFFSET), ++ ETH_MAC_GMII_ADDR_GB)) ++ break; ++ udelay(lp->platform_info->mii_retry_tmo); ++ } ++ if ((limit <= 0) && netif_msg_hw(lp)) { ++ dev_err(&lp->ndev->dev, "MII Error: Postwrite tmo!\n"); ++ errorCode = -EIO; ++ goto gkhw_mdio_write_exit; ++ } ++ ++gkhw_mdio_write_exit: ++ return errorCode; ++ } else { ++//#else ++ ++ lp = (struct GKETH_info *)bus->priv; ++ gk_eth_writel((unsigned int)(INTER_PHY_BASE + regnum * 4), value); ++ return 0; ++ } ++//#endif ++} ++ ++static int gkhw_mdio_reset(struct mii_bus *bus) ++{ ++ int errorCode = 0; ++ struct GKETH_info *lp; ++ ++ lp = (struct GKETH_info *)bus->priv; ++ ++ // LindengYu: Add reset to here ++ printk("###### PHY Reset.1.0.2\n"); ++ //gk_set_gpio_output(&lp->platform_info->phy_reset, 0); ++ gk_gpio_set_out(lp->platform_info->phy_reset.gpio_id, 0); ++ //*(u32 *)(GK_VA_GPIO0 + REG_GPIO_OUTPUT_CFG_OFFSET + 6*4) = 0X0; ++ mdelay(10);//100ms ++ //gk_set_gpio_output(&lp->platform_info->phy_reset, 1); ++ gk_gpio_set_out(lp->platform_info->phy_reset.gpio_id, 1); ++ //*(u32 *)(GK_VA_GPIO0 + REG_GPIO_OUTPUT_CFG_OFFSET + 6*4) = 0X1; ++ // RTL8201 need 200ms ++ mdelay(100);//100ms ++ //gk_set_gpio_reset_can_sleep(&lp->platform_info->phy_reset, 50); ++ return errorCode; ++} ++ ++#if 0 ++static int gkhw_phy_reset(struct GKETH_info *lp) ++{ ++//#ifdef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++ printk("cmdline_phytype = %d\n", cmdline_phytype); ++ if(cmdline_phytype != 0){ ++ struct gk_eth_platform_info *pf; ++ ++ pf = lp->platform_info; ++ ++ if(pf != NULL) ++ { ++ //dev_err(&lp->ndev->dev,"###### PHY Reset.1.0.1\n"); ++ printk("###### PHY Reset.1.0.1\n"); ++ gk_set_gpio_output(&pf->phy_reset, 0); ++ mdelay(50);//100ms ++ gk_set_gpio_output(&pf->phy_reset, 1); ++ mdelay(200);//100ms ++ } ++ ++ //gk_set_gpio_output(&lp->platform_info->mii_power, 0); ++ //gk_set_gpio_output(&lp->platform_info->mii_reset, 1); ++ //gk_set_gpio_output(&lp->platform_info->mii_power, 1); ++ //gk_set_gpio_output(&lp->platform_info->mii_reset, 0); ++ } ++//#endif ++ return 0; ++ ++} ++#endif ++ ++/* ==========================================================================*/ ++static void GKETH_adjust_link(struct net_device *ndev) ++{ ++ struct GKETH_info *lp; ++ unsigned long flags; ++ struct phy_device *phydev; ++ int need_update = 0; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ phydev = lp->phydev; ++ if (phydev->link) ++ { ++ if (phydev->duplex != lp->oldduplex) ++ { ++ need_update = 1; ++ lp->oldduplex = phydev->duplex; ++ } ++ if (phydev->speed != lp->oldspeed) ++ { ++ switch (phydev->speed) ++ { ++ case SPEED_1000: ++ case SPEED_100: ++ case SPEED_10: ++ need_update = 1; ++ lp->oldspeed = phydev->speed; ++ break; ++ default: ++ if (netif_msg_link(lp)) ++ dev_warn(&lp->ndev->dev, ++ "Unknown Speed(%d).\n", ++ phydev->speed); ++ break; ++ } ++ } ++ if (lp->oldlink != phydev->link) ++ { ++ need_update = 1; ++ lp->oldlink = phydev->link; ++ } ++ } ++ else if (lp->oldlink) ++ { ++ need_update = 1; ++ lp->oldlink = PHY_DOWN; ++ lp->oldspeed = 0; ++ lp->oldduplex = -1; ++ } ++ ++ if (need_update) ++ { ++ u16 rmii; ++ gkhw_set_link_mode_speed(lp); ++ rmii = gkhw_mdio_read(&lp->new_bus, lp->new_bus.phy_used->addr , 0x01); ++// printk("#############-------------reg1 %04x--------\n", rmii); ++ if(cmdline_phytype == 0) ++ { ++ if (phydev->link) ++ { ++ switch (phydev->speed) ++ { ++ case SPEED_100: ++ if(cmdline_phytype == 0) ++ { ++ gk_set_phy_speed_led(GPIO_TYPE_OUTPUT_EPHY_LED_3); ++ } ++ GH_GPIO_set_INPUT_CFG_in_sel(GPIO_GET_IN_SEL(GPIO_TYPE_INPUT_ENET_PHY_RXD_3) - 2, 0x01); ++ break; ++ case SPEED_10: ++ if(cmdline_phytype == 0) ++ { ++ gk_set_phy_speed_led(GPIO_TYPE_OUTPUT_EPHY_LED_2); ++ } ++ GH_GPIO_set_INPUT_CFG_in_sel(GPIO_GET_IN_SEL(GPIO_TYPE_INPUT_ENET_PHY_RXD_3) - 2, 0x00); ++ break; ++ default: ++ break; ++ } ++ } ++ else ++ { ++ if(cmdline_phytype == 0) ++ { ++ gk_set_phy_speed_led(GPIO_TYPE_INPUT_0); ++ } ++ } ++ } ++ if (netif_msg_link(lp)) ++ phy_print_status(phydev); ++ } ++ spin_unlock_irqrestore(&lp->lock, flags); ++} ++ ++typedef union { /* EPHY_MII_RMII */ ++ u32 all; ++ struct { ++ u32 usb_tm1 : 1; ++ u32 rmii : 1; ++ u32 : 30; ++ } bitc; ++} GH_EPHY_MII_RMII_S; ++ ++#define REG_EPHY_MII_RMII GK_VA_AHB_GREG //(0xF0020E00) /* read/write */ ++ ++void GH_EPHY_set_MII_RMII_rmii(u8 data) ++{ ++ GH_EPHY_MII_RMII_S d; ++ d.all = gk_eth_readl(REG_EPHY_MII_RMII); ++ //d.all = *(volatile u32 *)REG_EPHY_MII_RMII; ++ d.bitc.rmii = data; ++ gk_eth_writel(REG_EPHY_MII_RMII, d.all); ++ //*(volatile u32 *)REG_EPHY_MII_RMII = d.all; ++} ++ ++static int GKETH_phy_start(struct GKETH_info *lp) ++{ ++//#ifdef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++ int errorCode = 0; ++ struct phy_device *phydev; ++ phy_interface_t interface; ++ struct net_device *ndev; ++ int phy_addr; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ phydev = lp->phydev; ++ spin_unlock_irqrestore(&lp->lock, flags); ++ if (phydev) ++ goto GKETH_init_phy_exit; ++ ++ ndev = lp->ndev; ++ lp->oldlink = PHY_DOWN; ++ lp->oldspeed = 0; ++ lp->oldduplex = -1; ++ ++ if(cmdline_phytype != 0) ++ { ++ phy_addr = lp->platform_info->mii_id; ++ if ((phy_addr >= 0) && (phy_addr < PHY_MAX_ADDR)) ++ { ++ if (lp->new_bus.phy_map[phy_addr]) ++ { ++ phydev = lp->new_bus.phy_map[phy_addr]; ++ if (phydev->phy_id == lp->platform_info->phy_id) ++ { ++ goto GKETH_init_phy_default; ++ } ++ } ++ dev_notice(&lp->ndev->dev, ++ "Could not find default PHY in %d.\n", phy_addr); ++ } ++ goto GKETH_init_phy_scan; ++ ++ GKETH_init_phy_default: ++ printk("GKETH_init_phy_default ...\n"); ++ if (netif_msg_hw(lp)) ++ dev_info(&lp->ndev->dev, "Find default PHY in %d!\n", phy_addr); ++ goto GKETH_init_phy_connect; ++ ++ GKETH_init_phy_scan: ++ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { ++ if (lp->new_bus.phy_map[phy_addr]) { ++ phydev = lp->new_bus.phy_map[phy_addr]; ++ if (phydev->phy_id == lp->platform_info->phy_id) ++ goto GKETH_init_phy_connect; ++ } ++ } ++ if (!phydev) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "No PHY device.\n"); ++ errorCode = -ENODEV; ++ goto GKETH_init_phy_exit; ++ } else { ++ if (netif_msg_drv(lp)) ++ dev_notice(&lp->ndev->dev, ++ "Try PHY[%d] whose id is 0x%08x!\n", ++ phydev->addr, phydev->phy_id); ++ } ++ ++ GKETH_init_phy_connect: ++ interface = gkhw_get_interface(lp); ++ ++ phydev = phy_connect(ndev, dev_name(&phydev->dev), ++ &GKETH_adjust_link, 0, interface); ++ if (IS_ERR(phydev)) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "Could not attach to PHY!\n"); ++ errorCode = PTR_ERR(phydev); ++ goto GKETH_init_phy_exit; ++ } ++ ++ //phydev->supported &= lp->platform_info->phy_supported; ++ phydev->supported = lp->platform_info->phy_supported; ++ phydev->advertising = phydev->supported; ++ ++ //GH_EPHY_set_MII_RMII_rmii(0x0); ++ ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ lp->phydev = phydev; ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ dev_err(&lp->ndev->dev,"###### GKETH_phy_start_aneg...\n"); ++ ++ errorCode = phy_start_aneg(phydev); ++ ++ GKETH_init_phy_exit: ++ return errorCode; ++ } else { ++ ++//#else ++ interface = gkhw_get_interface(lp); ++ phydev = lp->new_bus.phy_map[0]; ++ phydev = phy_connect(ndev, dev_name(&phydev->dev), ++ &GKETH_adjust_link, 0, interface); ++ if (IS_ERR(phydev)) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "Could not attach to PHY!\n"); ++ errorCode = PTR_ERR(phydev); ++ return errorCode; ++ } ++ ++ phydev->supported = lp->platform_info->phy_supported; ++ phydev->advertising = phydev->supported; ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ lp->phydev = phydev; ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ dev_err(&lp->ndev->dev,"###### GKETH_phy_start_aneg...\n"); ++ ++ errorCode = phy_start_aneg(phydev); ++ return 0; ++ } ++} ++ ++static void GKETH_phy_stop(struct GKETH_info *lp) ++{ ++ struct phy_device *phydev; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ phydev = lp->phydev; ++ dev_err(&lp->ndev->dev,"###### GKETH_phy_stop\n"); ++ lp->phydev = NULL; ++ spin_unlock_irqrestore(&lp->lock, flags); ++ if (phydev) ++ phy_disconnect(phydev); ++} ++ ++static inline int GKETH_rx_rngmng_check_skb(struct GKETH_info *lp, u32 entry) ++{ ++ int errorCode = 0; ++ dma_addr_t mapping; ++ struct sk_buff *skb; ++ ++ if (lp->rx.rng_rx[entry].skb == NULL) { ++ skb = dev_alloc_skb(GKETH_PACKET_MAXFRAME); ++ if (skb == NULL) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "RX Error: dev_alloc_skb.\n"); ++ errorCode = -ENOMEM; ++ goto GKETH_rx_rngmng_skb_exit; ++ } ++ ++ skb->dev = lp->ndev; ++ lp->rx.rng_rx[entry].buf_size = GKETH_PACKET_MAXFRAME; ++ mapping = dma_map_single(&lp->ndev->dev, ++ skb->data, ++ lp->rx.rng_rx[entry].buf_size, ++ DMA_FROM_DEVICE); ++ ++ lp->rx.rng_rx[entry].skb = skb; ++ lp->rx.rng_rx[entry].mapping = mapping; ++ lp->rx.desc_rx[entry].buffer1 = mapping; ++ } ++ ++GKETH_rx_rngmng_skb_exit: ++ return errorCode; ++} ++ ++static inline void GKETH_rx_rngmng_init(struct GKETH_info *lp) ++{ ++ int i; ++ ++ lp->rx.cur_rx = 0; ++ lp->rx.dirty_rx = 0; ++ for (i = 0; i < lp->rx_count; i++) { ++ if (GKETH_rx_rngmng_check_skb(lp, i)) ++ break; ++ lp->rx.desc_rx[i].status = ETH_RDES0_OWN; ++ lp->rx.desc_rx[i].length = ++ ETH_RDES1_RCH | GKETH_PACKET_MAXFRAME; ++ lp->rx.desc_rx[i].buffer2 = (u32)lp->rx_dma_desc + ++ ((i + 1) * sizeof(struct GKETH_desc)); ++ } ++ lp->rx.desc_rx[lp->rx_count - 1].buffer2 = (u32)lp->rx_dma_desc; ++} ++ ++static inline void GKETH_rx_rngmng_refill(struct GKETH_info *lp) ++{ ++ u32 entry; ++ ++ while (lp->rx.cur_rx > lp->rx.dirty_rx) { ++ entry = lp->rx.dirty_rx % lp->rx_count; ++ if (GKETH_rx_rngmng_check_skb(lp, entry)) ++ break; ++ lp->rx.desc_rx[entry].status = ETH_RDES0_OWN; ++ lp->rx.dirty_rx++; ++ } ++} ++ ++static inline void GKETH_rx_rngmng_del(struct GKETH_info *lp) ++{ ++ int i; ++ dma_addr_t mapping; ++ struct sk_buff *skb; ++ ++ for (i = 0; i < lp->rx_count; i++) { ++ if (lp->rx.rng_rx) { ++ skb = lp->rx.rng_rx[i].skb; ++ mapping = lp->rx.rng_rx[i].mapping; ++ lp->rx.rng_rx[i].skb = NULL; ++ lp->rx.rng_rx[i].mapping = 0; ++ if (skb) { ++ dma_unmap_single(&lp->ndev->dev, mapping, ++ lp->rx.rng_rx[i].buf_size, DMA_FROM_DEVICE); ++ dev_kfree_skb(skb); ++ } ++ lp->rx.rng_rx[i].buf_size = 0; ++ } ++ if (lp->rx.desc_rx) { ++ lp->rx.desc_rx[i].status = 0; ++ lp->rx.desc_rx[i].length = 0; ++ lp->rx.desc_rx[i].buffer1 = 0xBADF00D0; ++ lp->rx.desc_rx[i].buffer2 = 0xBADF00D0; ++ } ++ } ++} ++ ++static inline void GKETH_tx_rngmng_init(struct GKETH_info *lp) ++{ ++ int i; ++ ++ lp->tx.cur_tx = 0; ++ lp->tx.dirty_tx = 0; ++ for (i = 0; i < lp->tx_count; i++) { ++ lp->tx.rng_tx[i].mapping = 0 ; ++ lp->tx.desc_tx[i].length = (ETH_TDES1_LS | ETH_TDES1_FS | ++ ETH_TDES1_TCH); ++ lp->tx.desc_tx[i].buffer1 = 0; ++ lp->tx.desc_tx[i].buffer2 = (u32)lp->tx_dma_desc + ++ ((i + 1) * sizeof(struct GKETH_desc)); ++ } ++ lp->tx.desc_tx[lp->tx_count - 1].buffer2 = (u32)lp->tx_dma_desc; ++} ++ ++static inline void GKETH_tx_rngmng_del(struct GKETH_info *lp) ++{ ++ int i; ++ dma_addr_t mapping; ++ struct sk_buff *skb; ++ unsigned int dirty_tx; ++ u32 entry; ++ u32 status; ++ ++ for (dirty_tx = lp->tx.dirty_tx; lp->tx.cur_tx > dirty_tx; dirty_tx++) { ++ entry = dirty_tx % lp->tx_count; ++ if (lp->tx.desc_tx) { ++ status = lp->tx.desc_tx[entry].status; ++ if (status & ETH_TDES0_OWN) ++ lp->stats.tx_dropped++; ++ } ++ } ++ for (i = 0; i < lp->tx_count; i++) { ++ if (lp->tx.rng_tx) { ++ skb = lp->tx.rng_tx[i].skb; ++ mapping = lp->tx.rng_tx[i].mapping; ++ lp->tx.rng_tx[i].skb = NULL; ++ lp->tx.rng_tx[i].mapping = 0; ++ if (skb) { ++ dma_unmap_single(&lp->ndev->dev, mapping, ++ skb->len, DMA_TO_DEVICE); ++ dev_kfree_skb(skb); ++ } ++ } ++ if (lp->tx.desc_tx) { ++ lp->tx.desc_tx[i].status = 0; ++ lp->tx.desc_tx[i].length = 0; ++ lp->tx.desc_tx[i].buffer1 = 0xBADF00D0; ++ lp->tx.desc_tx[i].buffer2 = 0xBADF00D0; ++ } ++ } ++} ++ ++static inline void GKETH_check_dma_error(struct GKETH_info *lp, ++ u32 irq_status) ++{ ++ u32 miss_ov = 0; ++ ++ if (unlikely(irq_status & ETH_DMA_STATUS_AIS)) { ++ if (irq_status & (ETH_DMA_STATUS_RU | ETH_DMA_STATUS_OVF)) ++ miss_ov = gk_eth_readl((unsigned int)(lp->regbase + ++ ETH_DMA_MISS_FRAME_BOCNT_OFFSET)); ++ ++ if (irq_status & ETH_DMA_STATUS_FBI) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Fatal Bus Error 0x%x.\n", ++ (irq_status & ETH_DMA_STATUS_EB_MASK)); ++ } ++ if (irq_status & ETH_DMA_STATUS_ETI) { ++ if (netif_msg_tx_err(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Early Transmit.\n"); ++ } ++ if (irq_status & ETH_DMA_STATUS_RWT) { ++ if (netif_msg_rx_err(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Receive Watchdog Timeout.\n"); ++ } ++ if (irq_status & ETH_DMA_STATUS_RPS) { ++ if (netif_msg_rx_err(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Receive Process Stopped.\n"); ++ } ++ if (irq_status & ETH_DMA_STATUS_RU) { ++ if (miss_ov & ETH_DMA_MISS_FRAME_BOCNT_FRAME) { ++ lp->stats.rx_dropped += ++ ETH_DMA_MISS_FRAME_BOCNT_HOST(miss_ov); ++ } ++ gkhw_dma_rx_stop(lp); ++ if (netif_msg_rx_err(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Receive Buffer Unavailable, %d.\n", ++ ETH_DMA_MISS_FRAME_BOCNT_HOST(miss_ov)); ++ } ++ if (irq_status & ETH_DMA_STATUS_UNF) { ++ if (netif_msg_tx_err(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Transmit Underflow.\n"); ++ } ++ if (irq_status & ETH_DMA_STATUS_OVF) { ++ if (miss_ov & ETH_DMA_MISS_FRAME_BOCNT_FIFO) { ++ lp->stats.rx_fifo_errors += ++ ETH_DMA_MISS_FRAME_BOCNT_APP(miss_ov); ++ } ++ if (netif_msg_rx_err(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Receive FIFO Overflow, %d.\n", ++ ETH_DMA_MISS_FRAME_BOCNT_APP(miss_ov)); ++ } ++ if (irq_status & ETH_DMA_STATUS_TJT) { ++ lp->stats.tx_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Transmit Jabber Timeout.\n"); ++ } ++ if (irq_status & ETH_DMA_STATUS_TPS) { ++ if (netif_msg_tx_err(lp)) ++ dev_err(&lp->ndev->dev, ++ "DMA Error: Transmit Process Stopped.\n"); ++ } ++ if (netif_msg_tx_err(lp) || netif_msg_rx_err(lp)) { ++ dev_err(&lp->ndev->dev, "DMA Error: Abnormal: 0x%x.\n", ++ irq_status); ++ gkhw_dump(lp); ++ } ++ } ++} ++ ++static inline void GKETH_interrupt_rx(struct GKETH_info *lp, u32 irq_status) ++{ ++ if (irq_status & GKETH_RXDMA_STATUS) { ++ dev_vdbg(&lp->ndev->dev, "RX IRQ[0x%x]!\n", irq_status); ++ gk_eth_clrbitsl((unsigned int)(lp->regbase + ETH_DMA_INTEN_OFFSET), ++ GKETH_RXDMA_INTEN); ++ napi_schedule(&lp->napi); ++ } ++} ++ ++static inline u32 GKETH_check_tdes0_status(struct GKETH_info *lp, ++ unsigned int status) ++{ ++ u32 tx_retry = 0; ++ ++ if (status & ETH_TDES0_JT) { ++ lp->stats.tx_heartbeat_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "TX Error: Jabber Timeout.\n"); ++ } ++ if (status & ETH_TDES0_FF) { ++ lp->stats.tx_dropped++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "TX Error: Frame Flushed.\n"); ++ } ++ if (status & ETH_TDES0_PCE) { ++ lp->stats.tx_fifo_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "TX Error: Payload Checksum Error.\n"); ++ } ++ if (status & ETH_TDES0_LCA) { ++ lp->stats.tx_carrier_errors++; ++ dev_err(&lp->ndev->dev, "TX Error: Loss of Carrier.\n"); ++ } ++ if (status & ETH_TDES0_NC) { ++ lp->stats.tx_carrier_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "TX Error: No Carrier.\n"); ++ } ++ if (status & ETH_TDES0_LCO) { ++ lp->stats.tx_aborted_errors++; ++ lp->stats.collisions++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "TX Error: Late Collision.\n"); ++ } ++ if (status & ETH_TDES0_EC) { ++ lp->stats.tx_aborted_errors++; ++ lp->stats.collisions += ETH_TDES0_CC(status); ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "TX Error: Excessive Collision %d.\n", ++ ETH_TDES0_CC(status)); ++ } ++ if (status & ETH_TDES0_VF) { ++ if (netif_msg_drv(lp)) ++ dev_info(&lp->ndev->dev, "TX Info: VLAN Frame.\n"); ++ } ++ if (status & ETH_TDES0_ED) { ++ lp->stats.tx_fifo_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "TX Error: Excessive Deferral.\n"); ++ } ++ if (status & ETH_TDES0_UF) { ++ tx_retry = 1; ++ if (netif_msg_tx_err(lp)) { ++ dev_err(&lp->ndev->dev, "TX Error: Underflow Error.\n"); ++ gkhw_dump(lp); ++ } ++ } ++ if (status & ETH_TDES0_DB) { ++ lp->stats.tx_fifo_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "TX Error: Deferred Bit.\n"); ++ } ++ ++ return tx_retry; ++} ++ ++static inline void GKETH_interrupt_tx(struct GKETH_info *lp, u32 irq_status) ++{ ++ unsigned int dirty_tx; ++ unsigned int dirty_to_tx; ++ u32 entry; ++ u32 status; ++ ++ if (irq_status & GKETH_TXDMA_STATUS) ++ { ++ dev_vdbg(&lp->ndev->dev, "cur_tx[%d], dirty_tx[%d], 0x%x.\n", ++ lp->tx.cur_tx, lp->tx.dirty_tx, irq_status); ++ for (dirty_tx = lp->tx.dirty_tx; dirty_tx < lp->tx.cur_tx; dirty_tx++) ++ { ++ entry = dirty_tx % lp->tx_count; ++ status = lp->tx.desc_tx[entry].status; ++ ++ if (status & ETH_TDES0_OWN) ++ break; ++ ++ if (unlikely(status & ETH_TDES0_ES)) ++ { ++#if defined(GKETH_TDES0_ATOMIC_CHECK) ++ if ((status & ETH_TDES0_ES_MASK) == ++ ETH_TDES0_ES) { ++ if (netif_msg_probe(lp)) { ++ dev_err(&lp->ndev->dev, ++ "TX Error: Wrong ES" ++ " 0x%08x vs 0x%08x.\n", ++ status, ++ lp->tx.desc_tx[entry].status); ++ gkhw_dump(lp); ++ } ++ break; ++ } ++#endif ++ if (GKETH_check_tdes0_status(lp, status)) { ++ gkhw_dma_tx_stop(lp); ++ gkhw_dma_tx_restart(lp, entry); ++ gkhw_dma_tx_poll(lp, entry); ++ break; ++ } else { ++ lp->stats.tx_errors++; ++ } ++ } ++ else ++ { ++#if defined(GKETH_TDES0_ATOMIC_CHECK_ALL) ++ udelay(1); ++ if (unlikely(status != ++ lp->tx.desc_tx[entry].status)) { ++ if (netif_msg_probe(lp)) { ++ dev_err(&lp->ndev->dev, ++ "TX Error: Wrong status" ++ " 0x%08x vs 0x%08x.\n", ++ status, ++ lp->tx.desc_tx[entry].status); ++ gkhw_dump(lp); ++ } ++ } ++#endif ++#if defined(CONFIG_GK_ETH_SUPPORT_IPC) ++ if (unlikely(status & ETH_TDES0_IHE)) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "TX Error: IP Header Error.\n"); ++ } ++#endif ++ lp->stats.tx_bytes += ++ lp->tx.rng_tx[entry].skb->len; ++ lp->stats.tx_packets++; ++ } ++ ++ dma_unmap_single(&lp->ndev->dev, ++ lp->tx.rng_tx[entry].mapping, ++ lp->tx.rng_tx[entry].skb->len, ++ DMA_TO_DEVICE); ++ dev_kfree_skb_irq(lp->tx.rng_tx[entry].skb); ++ lp->tx.rng_tx[entry].skb = NULL; ++ lp->tx.rng_tx[entry].mapping = 0; ++ } ++ ++ dirty_to_tx = lp->tx.cur_tx - dirty_tx; ++ if (unlikely(dirty_to_tx > lp->tx_count)) { ++ netif_stop_queue(lp->ndev); ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "TX Error: TX OV.\n"); ++ gkhw_dump(lp); ++ gkhw_dma_tx_stop(lp); ++ GKETH_tx_rngmng_del(lp); ++ GKETH_tx_rngmng_init(lp); ++ dirty_tx = dirty_to_tx = 0; ++ } ++ if (likely(dirty_to_tx < (lp->tx_count / 2))) { ++ dev_vdbg(&lp->ndev->dev, "TX Info: Now gap %d.\n", ++ dirty_to_tx); ++ netif_wake_queue(lp->ndev); ++ } ++ lp->tx.dirty_tx = dirty_tx; ++ } ++} ++ ++static irqreturn_t GKETH_interrupt(int irq, void *dev_id) ++{ ++ struct net_device *ndev; ++ struct GKETH_info *lp; ++ u32 irq_status; ++ unsigned long flags; ++ ++ ndev = (struct net_device *)dev_id; ++ lp = netdev_priv(ndev); ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ irq_status = gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET)); ++ GKETH_check_dma_error(lp, irq_status); ++ GKETH_interrupt_rx(lp, irq_status); ++ GKETH_interrupt_tx(lp, irq_status); ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET), irq_status); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ return IRQ_HANDLED; ++} ++ ++static int GKETH_start_hw(struct net_device *ndev) ++{ ++ int errorCode = 0; ++ struct GKETH_info *lp; ++ unsigned long flags; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ dev_err(&lp->ndev->dev,"###### GKETH_start_hw\n"); ++ ++ #if 1 ++ //kewell add ++ //LindengYu: if reset, might change the phy address. So, reset the phy before at the get phy id. ++ //gkhw_phy_reset(lp); ++ //GKETH_phy_start(lp); ++ #else ++ gkhw_phy_set_high(lp); ++ gkhw_phy_reset(lp); ++ GH_EPHY_set_MII_RMII_rmii(0x1); ++ #endif ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ errorCode = gkhw_enable(lp); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ if (errorCode) ++ goto GKETH_start_hw_exit; ++ ++ lp->rx.rng_rx = kmalloc((sizeof(struct GKETH_rng_info) * ++ lp->rx_count), GFP_KERNEL); ++ if (lp->rx.rng_rx == NULL) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "alloc rng_rx fail.\n"); ++ errorCode = -ENOMEM; ++ goto GKETH_start_hw_exit; ++ } ++ lp->rx.desc_rx = dma_alloc_coherent(&lp->ndev->dev, ++ (sizeof(struct GKETH_desc) * lp->rx_count), ++ &lp->rx_dma_desc, GFP_KERNEL); ++ if (lp->rx.desc_rx == NULL) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "dma_alloc_coherent desc_rx fail.\n"); ++ errorCode = -ENOMEM; ++ goto GKETH_start_hw_exit; ++ } ++ memset(lp->rx.rng_rx, 0, ++ (sizeof(struct GKETH_rng_info) * lp->rx_count)); ++ memset(lp->rx.desc_rx, 0, ++ (sizeof(struct GKETH_desc) * lp->rx_count)); ++ GKETH_rx_rngmng_init(lp); ++ ++ lp->tx.rng_tx = kmalloc((sizeof(struct GKETH_rng_info) * ++ lp->tx_count), GFP_KERNEL); ++ if (lp->tx.rng_tx == NULL) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "alloc rng_tx fail.\n"); ++ errorCode = -ENOMEM; ++ goto GKETH_start_hw_exit; ++ } ++ lp->tx.desc_tx = dma_alloc_coherent(&lp->ndev->dev, ++ (sizeof(struct GKETH_desc) * lp->tx_count), ++ &lp->tx_dma_desc, GFP_KERNEL); ++ if (lp->tx.desc_tx == NULL) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "dma_alloc_coherent desc_tx fail.\n"); ++ errorCode = -ENOMEM; ++ goto GKETH_start_hw_exit; ++ } ++ memset(lp->tx.rng_tx, 0, ++ (sizeof(struct GKETH_rng_info) * lp->tx_count)); ++ memset(lp->tx.desc_tx, 0, ++ (sizeof(struct GKETH_desc) * lp->tx_count)); ++ GKETH_tx_rngmng_init(lp); ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ gkhw_set_dma_desc(lp); ++ gkhw_dma_rx_start(lp); ++ gkhw_dma_tx_start(lp); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++GKETH_start_hw_exit: ++ return errorCode; ++} ++ ++static void GKETH_stop_hw(struct net_device *ndev) ++{ ++ struct GKETH_info *lp; ++ unsigned long flags; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ gkhw_disable(lp); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ GKETH_tx_rngmng_del(lp); ++ if (lp->tx.desc_tx) { ++ dma_free_coherent(&lp->ndev->dev, ++ (sizeof(struct GKETH_desc) * lp->tx_count), ++ lp->tx.desc_tx, lp->tx_dma_desc); ++ lp->tx.desc_tx = NULL; ++ } ++ if (lp->tx.rng_tx) { ++ kfree(lp->tx.rng_tx); ++ lp->tx.rng_tx = NULL; ++ } ++ ++ GKETH_rx_rngmng_del(lp); ++ if (lp->rx.desc_rx) { ++ dma_free_coherent(&lp->ndev->dev, ++ (sizeof(struct GKETH_desc) * lp->rx_count), ++ lp->rx.desc_rx, lp->rx_dma_desc); ++ lp->rx.desc_rx = NULL; ++ } ++ if (lp->rx.rng_rx) { ++ kfree(lp->rx.rng_rx); ++ lp->rx.rng_rx = NULL; ++ } ++} ++ ++static int GKETH_open(struct net_device *ndev) ++{ ++ int errorCode = 0; ++ struct GKETH_info *lp; ++//#ifdef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++ u32 rmii; ++//#endif ++ ++ if(!(cmdline_phytype != 0)) { ++ GK_EPHY_POWER_ON(); ++ udelay(1000); ++ } ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ ++ errorCode = GKETH_start_hw(ndev); ++ if (errorCode) ++ goto GKETH_open_exit; ++ ++ errorCode = request_irq(ndev->irq, GKETH_interrupt, ++ IRQF_SHARED | IRQF_TRIGGER_HIGH, ndev->name, ndev); ++ if (errorCode) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "Request_irq[%d] fail.\n", ndev->irq); ++ goto GKETH_open_exit; ++ } ++ ++ napi_enable(&lp->napi); ++ netif_start_queue(ndev); ++ ++ ++ netif_carrier_off(ndev); ++ ++ ++ gkhw_dma_int_enable(lp); ++ ++ errorCode = GKETH_phy_start(lp); ++ ++#if 0 ++{ ++ u32 ii; ++ u32 phy_register_value = 0; ++ ++ for(ii = 0; ii < 32; ii++) ++ { ++ phy_register_value = gkhw_mdio_read(&lp->new_bus, 3 , ii); ++ //printk(" [%02d]: 0x%08x\n", ii, phy_register_value); ++ printk( "MII Read: id[0x03], add[0x%02x], val[0x%04x].\n", ++ ii, phy_register_value); ++ } ++} ++#endif ++//#ifdef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++ if(cmdline_phytype != 0) ++ { ++ if(lp->new_bus.phy_used->phy_id == 0x02430c54) // IP101g ++ { ++ // LindengYu: I don't known why do not go into effect. ++ // change to page 3 ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 20, 0x03); ++ rmii = gkhw_mdio_read(&lp->new_bus, lp->new_bus.phy_used->addr, 0x10); ++ rmii &= 0x3FFF; ++ rmii |= 0x4000; ++ // change to LED0 mode1, Link/Act mode ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 0x10, rmii); ++ // restore to page 16 ++ rmii = gkhw_mdio_read(&lp->new_bus, lp->new_bus.phy_used->addr, 0x10); ++ } ++ else// if(lp->new_bus.phy_used->phy_id == 0x001CC815) // rtl820x ++ { ++ // change to rmii mode ++ rmii = gkhw_mdio_read(&lp->new_bus, lp->new_bus.phy_used->addr, 25); ++ //rmii |= (1<<10); ++ rmii &= ~(1<<10); ++ rmii &= ~(1<<11); ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 25, rmii); ++ } ++ } ++ ++//#endif ++ ++GKETH_open_exit: ++ if (errorCode) { ++ printk("eth open error\n"); ++ GKETH_phy_stop(lp); ++ GKETH_stop_hw(ndev); ++ } ++ ++ return errorCode; ++} ++ ++static int GKETH_stop(struct net_device *ndev) ++{ ++ int errorCode = 0; ++ struct GKETH_info *lp; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ ++ netif_stop_queue(ndev); ++ napi_disable(&lp->napi); ++ flush_scheduled_work(); ++ free_irq(ndev->irq, ndev); ++ GKETH_phy_stop(lp); ++ GKETH_stop_hw(ndev); ++ ++ //printk("GKETH_stop\n"); ++ GK_EPHY_POWER_OFF(); ++ ++ return errorCode; ++} ++ ++static int GKETH_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) ++{ ++ int errorCode = 0; ++ struct GKETH_info *lp; ++ dma_addr_t mapping; ++ u32 entry; ++ unsigned int dirty_to_tx; ++ u32 tx_flag; ++ unsigned long flags; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ entry = lp->tx.cur_tx % lp->tx_count; ++ dirty_to_tx = lp->tx.cur_tx - lp->tx.dirty_tx; ++ if (dirty_to_tx >= lp->tx_count) { ++ netif_stop_queue(ndev); ++ errorCode = -ENOMEM; ++ spin_unlock_irqrestore(&lp->lock, flags); ++ goto GKETH_hard_start_xmit_exit; ++ } ++ ++ mapping = dma_map_single(&lp->ndev->dev, ++ skb->data, skb->len, DMA_TO_DEVICE); ++ tx_flag = ETH_TDES1_LS | ETH_TDES1_FS | ETH_TDES1_TCH; ++ if (dirty_to_tx >= lp->tx_irq_count) { ++ netif_stop_queue(ndev); ++ tx_flag |= ETH_TDES1_IC; ++ } ++#if defined(CONFIG_GK_ETH_SUPPORT_IPC) ++ if (skb->ip_summed == CHECKSUM_PARTIAL) { ++ tx_flag |= ETH_TDES1_CIC_TUI | ETH_TDES1_CIC_HDR; ++ } ++#endif ++ lp->tx.rng_tx[entry].skb = skb; ++ lp->tx.rng_tx[entry].mapping = mapping; ++ lp->tx.desc_tx[entry].buffer1 = mapping; ++ lp->tx.desc_tx[entry].length = ETH_TDES1_TBS1x(skb->len) | tx_flag; ++ lp->tx.cur_tx++; ++ gkhw_dma_tx_poll(lp, entry); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ ndev->trans_start = jiffies; ++ dev_vdbg(&lp->ndev->dev, "TX Info: cur_tx[%d], dirty_tx[%d], " ++ "entry[%d], len[%d], data_len[%d], ip_summed[%d], " ++ "csum_start[%d], csum_offset[%d].\n", ++ lp->tx.cur_tx, lp->tx.dirty_tx, entry, skb->len, skb->data_len, ++ skb->ip_summed, skb->csum_start, skb->csum_offset); ++ ++GKETH_hard_start_xmit_exit: ++ return errorCode; ++} ++ ++static void GKETH_timeout(struct net_device *ndev) ++{ ++ struct GKETH_info *lp; ++ unsigned long flags; ++ u32 irq_status; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ ++ dev_info(&lp->ndev->dev, "OOM Info:...\n"); ++ spin_lock_irqsave(&lp->lock, flags); ++ irq_status = gk_eth_readl((unsigned int)(lp->regbase + ETH_DMA_STATUS_OFFSET)); ++ GKETH_interrupt_tx(lp, irq_status | GKETH_TXDMA_STATUS); ++ gkhw_dump(lp); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ netif_wake_queue(ndev); ++} ++ ++static struct net_device_stats *GKETH_get_stats(struct net_device *ndev) ++{ ++ struct GKETH_info *lp = netdev_priv(ndev); ++ ++ return &lp->stats; ++} ++ ++static inline void GKETH_check_rdes0_status(struct GKETH_info *lp, ++ unsigned int status) ++{ ++ if (status & ETH_RDES0_DE) { ++ lp->stats.rx_frame_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "RX Error: Descriptor Error.\n"); ++ } ++ if (status & ETH_RDES0_SAF) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "RX Error: Source Address Filter Fail.\n"); ++ } ++ if (status & ETH_RDES0_LE) { ++ lp->stats.rx_length_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "RX Error: Length Error.\n"); ++ } ++ if (status & ETH_RDES0_OE) { ++ lp->stats.rx_over_errors++; ++ if (netif_msg_rx_err(lp)) ++ dev_err(&lp->ndev->dev, "RX Error: Overflow Error.\n"); ++ } ++ if (status & ETH_RDES0_VLAN) { ++ if (netif_msg_drv(lp)) ++ dev_info(&lp->ndev->dev, "RX Info: VLAN.\n"); ++ } ++ if (status & ETH_RDES0_IPC) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "RX Error: IPC Checksum/Giant Frame.\n"); ++ } ++ if (status & ETH_RDES0_LC) { ++ lp->stats.collisions++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, "RX Error: Late Collision.\n"); ++ } ++ if (status & ETH_RDES0_FT) { ++ if (netif_msg_rx_err(lp)) ++ dev_info(&lp->ndev->dev, ++ "RX Info: Ethernet-type frame.\n"); ++ } ++ if (status & ETH_RDES0_RWT) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "RX Error: Watchdog Timeout.\n"); ++ } ++ if (status & ETH_RDES0_RE) { ++ lp->stats.rx_errors++; ++ if (netif_msg_rx_err(lp)) ++ dev_err(&lp->ndev->dev, "RX Error: Receive.\n"); ++ } ++ if (status & ETH_RDES0_DBE) { ++ if (gk_eth_tstbitsl((unsigned int)(lp->regbase + ETH_MAC_CFG_OFFSET), ++ ETH_MAC_CFG_PS)) { ++ lp->stats.rx_length_errors++; ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "RX Error: Dribble Bit.\n"); ++ } ++ } ++ if (status & ETH_RDES0_CE) { ++ lp->stats.rx_crc_errors++; ++ if (netif_msg_rx_err(lp)) ++ dev_err(&lp->ndev->dev, "RX Error: CRC.\n"); ++ } ++ if (status & ETH_RDES0_RX) { ++ if (netif_msg_drv(lp)) ++ dev_err(&lp->ndev->dev, ++ "RX Error: Rx MAC Address/Payload Checksum.\n"); ++ } ++} ++ ++static inline void GKETH_napi_rx(struct GKETH_info *lp, u32 status, u32 entry) ++{ ++ short pkt_len; ++ struct sk_buff *skb; ++ dma_addr_t mapping; ++ ++ pkt_len = ETH_RDES0_FL(status) - 4; ++ ++ if (unlikely(pkt_len > GKETH_RX_COPYBREAK)) { ++ dev_warn(&lp->ndev->dev, "Bogus packet size %d.\n", pkt_len); ++ pkt_len = GKETH_RX_COPYBREAK; ++ lp->stats.rx_length_errors++; ++ } ++ ++ skb = lp->rx.rng_rx[entry].skb; ++ mapping = lp->rx.rng_rx[entry].mapping; ++ if (likely(skb && mapping)) { ++ dma_unmap_single(&lp->ndev->dev, mapping, ++ lp->rx.rng_rx[entry].buf_size, DMA_FROM_DEVICE); ++ skb->len = 0; ++ skb_put(skb, pkt_len); ++ skb->protocol = eth_type_trans(skb, lp->ndev); ++#if defined(CONFIG_GK_ETH_SUPPORT_IPC) ++ if ((status & ETH_RDES0_COE_MASK) == ETH_RDES0_COE_NOCHKERROR) { ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ } else { ++ skb->ip_summed = CHECKSUM_NONE; ++ if (netif_msg_rx_err(lp)) { ++ dev_err(&lp->ndev->dev, ++ "RX Error: RDES0_COE[0x%x].\n", status); ++ gkhw_dump(lp); ++ } ++ } ++#endif ++ netif_receive_skb(skb); ++ lp->rx.rng_rx[entry].skb = NULL; ++ lp->rx.rng_rx[entry].mapping = 0; ++ lp->ndev->last_rx = jiffies; ++ lp->stats.rx_packets++; ++ lp->stats.rx_bytes += pkt_len; ++ } else { ++ if (netif_msg_drv(lp)) { ++ dev_err(&lp->ndev->dev, ++ "RX Error: %d skb[%p], map[0x%08X].\n", ++ entry, skb, mapping); ++ gkhw_dump(lp); ++ } ++ } ++} ++ ++int GKETH_napi(struct napi_struct *napi, int budget) ++{ ++ int rx_budget = budget; ++ struct GKETH_info *lp; ++ u32 entry; ++ u32 status; ++ unsigned long flags; ++ ++ lp = container_of(napi, struct GKETH_info, napi); ++ ++ if (unlikely(!netif_carrier_ok(lp->ndev))) ++ goto GKETH_poll_complete; ++ ++ while (rx_budget > 0) { ++ entry = lp->rx.cur_rx % lp->rx_count; ++ status = lp->rx.desc_rx[entry].status; ++ if (status & ETH_RDES0_OWN) ++ break; ++#if defined(GKETH_RDES0_ATOMIC_CHECK) ++ if (unlikely((status & (ETH_RDES0_FS | ETH_RDES0_LS)) != ++ (ETH_RDES0_FS | ETH_RDES0_LS))) { ++ if (netif_msg_probe(lp)) { ++ dev_err(&lp->ndev->dev, "RX Error: Wrong FS/LS" ++ " cur_rx[%d] status 0x%08x.\n", ++ lp->rx.cur_rx, status); ++ gkhw_dump(lp); ++ } ++ break; ++ } ++#endif ++#if defined(GKETH_TDES0_ATOMIC_CHECK_ALL) ++ udelay(1); ++ if (unlikely(status != lp->rx.desc_rx[entry].status)) { ++ if (netif_msg_probe(lp)) { ++ dev_err(&lp->ndev->dev, "RX Error: Wrong status" ++ " 0x%08x vs 0x%08x.\n", ++ status, lp->rx.desc_rx[entry].status); ++ gkhw_dump(lp); ++ } ++ } ++#endif ++ if (likely((status & ETH_RDES0_ES) != ETH_RDES0_ES)) { ++ GKETH_napi_rx(lp, status, entry); ++ } else { ++ GKETH_check_rdes0_status(lp, status); ++ } ++ rx_budget--; ++ lp->rx.cur_rx++; ++ ++ if ((lp->rx.cur_rx - lp->rx.dirty_rx) > (lp->rx_count / 4)) ++ GKETH_rx_rngmng_refill(lp); ++ } ++ ++GKETH_poll_complete: ++ if (rx_budget > 0) { ++ GKETH_rx_rngmng_refill(lp); ++ spin_lock_irqsave(&lp->lock, flags); ++ napi_complete(&lp->napi); ++ gk_eth_setbitsl((unsigned int)(lp->regbase + ETH_DMA_INTEN_OFFSET), ++ GKETH_RXDMA_INTEN); ++ gkhw_dma_rx_start(lp); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ } ++ ++ return (budget - rx_budget); ++} ++ ++static inline u32 gkhw_hashtable_crc(unsigned char *mac) ++{ ++ unsigned char tmpbuf[ETH_ALEN]; ++ int i; ++ u32 crc; ++ ++ for (i = 0; i < ETH_ALEN; i++) ++ tmpbuf[i] = bitrev8(mac[i]); ++ crc = crc32_be(~0, tmpbuf, ETH_ALEN); ++ ++ return (crc ^ ~0); ++} ++ ++static inline void gkhw_hashtable_get(struct net_device *ndev, u32 *hat) ++{ ++ struct netdev_hw_addr *ha; ++ unsigned int bitnr; ++#if 0 ++ unsigned char test1[] = {0x1F,0x52,0x41,0x9C,0xB6,0xAF}; ++ unsigned char test2[] = {0xA0,0x0A,0x98,0x00,0x00,0x45}; ++ dev_info(&ndev->dev, ++ "Test1: 0x%08X.\n", gkhw_hashtable_crc(test1)); ++ dev_info(&ndev->dev, ++ "Test2: 0x%08X.\n", gkhw_hashtable_crc(test2)); ++#endif ++ ++ hat[0] = hat[1] = 0; ++ netdev_for_each_mc_addr(ha, ndev) { ++ if (!(ha->addr[0] & 1)) ++ continue; ++ bitnr = gkhw_hashtable_crc(ha->addr); ++ bitnr >>= 26; ++ bitnr &= 0x3F; ++ hat[bitnr >> 5] |= 1 << (bitnr & 31); ++ } ++} ++ ++static int GKETH_set_mac_address(struct net_device *ndev, void *addr) ++{ ++ struct GKETH_info *lp; ++ unsigned long flags; ++ struct sockaddr *saddr; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ spin_lock_irqsave(&lp->lock, flags); ++ saddr = (struct sockaddr *)(addr); ++ ++ //if (netif_running(ndev)) ++ // goto fail1; ++ ++ if (!is_valid_ether_addr(saddr->sa_data)) ++ goto fail2; ++ ++ dev_dbg(&lp->ndev->dev, "MAC address[%pM].\n", saddr->sa_data); ++ ++ memcpy(ndev->dev_addr, saddr->sa_data, ndev->addr_len); ++ gkhw_set_hwaddr(lp, ndev->dev_addr); ++ gkhw_get_hwaddr(lp, ndev->dev_addr); ++ memcpy(lp->platform_info->mac_addr, ndev->dev_addr, GKETH_MAC_SIZE); ++ ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ return 0; ++ ++fail2: ++ spin_unlock_irqrestore(&lp->lock, flags); ++ return -EADDRNOTAVAIL; ++} ++ ++static void GKETH_set_multicast_list(struct net_device *ndev) ++{ ++ struct GKETH_info *lp; ++ unsigned int mac_filter; ++ u32 hat[2]; ++ unsigned long flags; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ spin_lock_irqsave(&lp->lock, flags); ++ ++ mac_filter = gk_eth_readl((unsigned int)(lp->regbase + ++ ETH_MAC_FRAME_FILTER_OFFSET)); ++ hat[0] = 0; ++ hat[1] = 0; ++ ++ if (ndev->flags & IFF_PROMISC) { ++ mac_filter |= ETH_MAC_FRAME_FILTER_PR; ++ } else if (ndev->flags & (~IFF_PROMISC)) { ++ mac_filter &= ~ETH_MAC_FRAME_FILTER_PR; ++ } ++ ++ if (ndev->flags & IFF_ALLMULTI) { ++ hat[0] = 0xFFFFFFFF; ++ hat[1] = 0xFFFFFFFF; ++ mac_filter |= ETH_MAC_FRAME_FILTER_PM; ++ } else if (!netdev_mc_empty(ndev)) { ++ gkhw_hashtable_get(ndev, hat); ++ mac_filter &= ~ETH_MAC_FRAME_FILTER_PM; ++ mac_filter |= ETH_MAC_FRAME_FILTER_HMC; ++ } else if (ndev->flags & (~IFF_ALLMULTI)) { ++ mac_filter &= ~ETH_MAC_FRAME_FILTER_PM; ++ mac_filter |= ETH_MAC_FRAME_FILTER_HMC; ++ } ++ ++ if (netif_msg_hw(lp)) { ++ dev_info(&lp->ndev->dev, "MC Info: flags 0x%x.\n", ndev->flags); ++ dev_info(&lp->ndev->dev, "MC Info: mc_count 0x%x.\n", ++ netdev_mc_count(ndev)); ++ dev_info(&lp->ndev->dev, "MC Info: mac_filter 0x%x.\n", ++ mac_filter); ++ dev_info(&lp->ndev->dev, "MC Info: hat[0x%x:0x%x].\n", ++ hat[1], hat[0]); ++ } ++ ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_HASH_HI_OFFSET), hat[1]); ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_HASH_LO_OFFSET), hat[0]); ++ gk_eth_writel((unsigned int)(lp->regbase + ETH_MAC_FRAME_FILTER_OFFSET), mac_filter); ++ ++ spin_unlock_irqrestore(&lp->lock, flags); ++} ++ ++ ++#ifdef CONFIG_NET_POLL_CONTROLLER ++static void GKETH_poll_controller(struct net_device *ndev) ++{ ++ GKETH_interrupt(ndev->irq, ndev); ++} ++#endif ++ ++static int GKETH_get_settings(struct net_device *ndev, ++ struct ethtool_cmd *ecmd) ++{ ++ int errorCode = 0; ++ struct GKETH_info *lp; ++ unsigned long flags; ++ ++ if (!netif_running(ndev)) { ++ errorCode = -EINVAL; ++ goto GKETH_get_settings_exit; ++ } ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ spin_lock_irqsave(&lp->lock, flags); ++ if (lp->phydev) { ++ errorCode = phy_ethtool_gset(lp->phydev, ecmd); ++ } else { ++ errorCode = -EINVAL; ++ } ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++GKETH_get_settings_exit: ++ return errorCode; ++} ++ ++static int GKETH_set_settings(struct net_device *ndev, ++ struct ethtool_cmd *ecmd) ++{ ++ int errorCode = 0; ++ struct GKETH_info *lp; ++ unsigned long flags; ++ ++ if (!netif_running(ndev)) { ++ errorCode = -EINVAL; ++ goto GKETH_get_settings_exit; ++ } ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ spin_lock_irqsave(&lp->lock, flags); ++ if (lp->phydev) { ++ errorCode = phy_ethtool_sset(lp->phydev, ecmd); ++ } else { ++ errorCode = -EINVAL; ++ } ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++GKETH_get_settings_exit: ++ return errorCode; ++} ++ ++static int GKETH_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) ++{ ++ int errorCode = 0; ++ struct GKETH_info *lp; ++ unsigned long flags; ++ ++ if (!netif_running(ndev)) { ++ errorCode = -EINVAL; ++ goto GKETH_get_settings_exit; ++ } ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ spin_lock_irqsave(&lp->lock, flags); ++ if (lp->phydev) { ++ errorCode = phy_mii_ioctl(lp->phydev, ifr, cmd); ++ } else { ++ errorCode = -EINVAL; ++ } ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++GKETH_get_settings_exit: ++ return errorCode; ++} ++ ++/* ==========================================================================*/ ++static const struct net_device_ops GKETH_netdev_ops = { ++ .ndo_open = GKETH_open, ++ .ndo_stop = GKETH_stop, ++ .ndo_start_xmit = GKETH_hard_start_xmit, ++ .ndo_set_mac_address = GKETH_set_mac_address, ++ .ndo_validate_addr = eth_validate_addr, ++ .ndo_do_ioctl = GKETH_ioctl, ++ .ndo_change_mtu = eth_change_mtu, ++ .ndo_tx_timeout = GKETH_timeout, ++ .ndo_get_stats = GKETH_get_stats, ++ .ndo_set_rx_mode = GKETH_set_multicast_list, ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ .ndo_poll_controller = GKETH_poll_controller, ++#endif ++}; ++ ++static const struct ethtool_ops GKETH_ethtool_ops = { ++ .get_settings = GKETH_get_settings, ++ .set_settings = GKETH_set_settings, ++ .get_link = ethtool_op_get_link, ++}; ++ ++static int __devinit GKETH_drv_probe(struct platform_device *pdev) ++{ ++ int errorCode = 0; ++ struct net_device *ndev; ++ struct GKETH_info *lp; ++ struct gk_eth_platform_info *platform_info; ++ struct resource *reg_res; ++ struct resource *irq_res; ++ ++ void __iomem *eth_base; ++ int i; ++//#ifndef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++ u8 uRegVal; ++//#else ++ u32 rmii; ++//#endif ++ ++ ++ platform_info = (struct gk_eth_platform_info *)pdev->dev.platform_data; ++ if (platform_info == NULL) { ++ dev_err(&pdev->dev, "Can't get platform_data!\n"); ++ errorCode = - EPERM; ++ goto GKETH_drv_probe_exit; ++ } ++ ++ if (platform_info->is_enabled) { ++ if (!platform_info->is_enabled()) { ++ dev_err(&pdev->dev, "Not enabled, check HW config!\n"); ++ errorCode = -EPERM; ++ goto GKETH_drv_probe_exit; ++ } ++ } ++ ++ reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (reg_res == NULL) { ++ dev_err(&pdev->dev, "Get reg_res failed!\n"); ++ errorCode = -ENXIO; ++ goto GKETH_drv_probe_exit; ++ } ++ ++ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ if (irq_res == NULL) { ++ dev_err(&pdev->dev, "Get irq_res failed!\n"); ++ errorCode = -ENXIO; ++ goto GKETH_drv_probe_exit; ++ } ++ ++ ndev = alloc_etherdev(sizeof(struct GKETH_info)); ++ if (ndev == NULL) { ++ dev_err(&pdev->dev, "alloc_etherdev fail.\n"); ++ errorCode = -ENOMEM; ++ goto GKETH_drv_probe_exit; ++ } ++#if 0 ++ /* get the memory region for the watchdog timer */ ++ size = resource_size(reg_res); ++ if (!request_mem_region(reg_res->start, size, pdev->name)) { ++ dev_err(&pdev->dev, "Failed to get eth's memory region\n"); ++ errorCode = -EBUSY; ++ goto GKETH_drv_probe_free_netdev; ++ } ++ ++ eth_base = ioremap(reg_res->start, size); ++ if (eth_base == NULL) { ++ dev_err(&pdev->dev, "failed to ioremap() region\n"); ++ errorCode = -EINVAL; ++ goto GKTH_drv_probe_free_res; ++ } ++#else ++ eth_base = (void __iomem *)reg_res->start; ++#endif ++ ++#define KE_DEBUG ++#ifdef KE_DEBUG ++ printk("[%s] eth_base = 0x%08x\n", __FUNCTION__, (u32)eth_base); ++#endif ++ ++ SET_NETDEV_DEV(ndev, &pdev->dev); ++ ndev->dev.dma_mask = pdev->dev.dma_mask; ++ ndev->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; ++ ndev->irq = irq_res->start; ++#if defined(CONFIG_GK_ETH_SUPPORT_IPC) ++ ndev->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; ++#endif ++ lp = netdev_priv(ndev); ++ spin_lock_init(&lp->lock); ++ lp->ndev = ndev; ++ lp->regbase = (unsigned char __iomem *)eth_base; ++ lp->platform_info = platform_info; ++ lp->rx_count = lp->platform_info->default_rx_ring_size; ++ if (lp->rx_count < GKETH_RX_RNG_MIN) ++ lp->rx_count = GKETH_RX_RNG_MIN; ++ lp->tx_count = lp->platform_info->default_tx_ring_size; ++ if (lp->tx_count < GKETH_TX_RNG_MIN) ++ lp->tx_count = GKETH_TX_RNG_MIN; ++ lp->tx_irq_count = (lp->tx_count * 2) / 3; ++ lp->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV | NETIF_MSG_LINK); ++ ++ lp->new_bus.name = "goke MII Bus", ++ lp->new_bus.read = &gkhw_mdio_read; ++ lp->new_bus.write = &gkhw_mdio_write; ++ lp->new_bus.reset = &gkhw_mdio_reset; ++ //pdev->id = 0x3; ++ //lp->platform_info->mii_id = pdev->id; ++ printk("mii id = %d \n", pdev->id); ++ snprintf(lp->new_bus.id, MII_BUS_ID_SIZE, "%x", pdev->id); ++ lp->new_bus.priv = lp; ++ lp->new_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); ++ if (lp->new_bus.irq == NULL) { ++ dev_err(&pdev->dev, "alloc new_bus.irq fail.\n"); ++ errorCode = -ENOMEM; ++ goto GKETH_drv_probe_free_mii_gpio_irq; ++ } ++ for(i = 0; i < PHY_MAX_ADDR; ++i) ++ lp->new_bus.irq[i] = PHY_POLL; ++ lp->new_bus.parent = &pdev->dev; ++ lp->new_bus.state = MDIOBUS_ALLOCATED; ++//#ifndef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++ if(cmdline_phytype == 0){ ++ lp->new_bus.phy_mask = 0xFFFFFFFE; ++ } ++//#endif ++ ++ //printk("mdiobus register ...\n"); ++ errorCode = mdiobus_register(&lp->new_bus); ++ if (errorCode) { ++ dev_err(&pdev->dev, "mdiobus_register fail%d.\n", errorCode); ++ goto GKETH_drv_probe_kfree_mdiobus; ++ } ++ //printk("ok\n"); ++//#ifdef CONFIG_SYSTEM_USE_EXTERN_ETHPHY ++ if(cmdline_phytype != 0) ++ { ++#if 0//ephy rmii mode ++ GH_EPHY_set_MII_RMII_rmii(0x1); ++ // RMII mode GPIO_TYPE_OUTPUT_ENET_PHY_TXD_3 used as 10/100M indicator ++ gk_set_phy_speed_led(GPIO_TYPE_INPUT_0); ++ ++ if(lp->new_bus.phy_used->phy_id == 0x02430c54) // IP101g ++ { ++ // LindengYu: I don't known why do not go into effect. ++ // change to page 3 ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 20, 0x03); ++ rmii = gkhw_mdio_read(&lp->new_bus, lp->new_bus.phy_used->addr, 0x10); ++ rmii &= 0x3FFF; ++ rmii |= 0x4000; ++ // change to LED0 mode1, Link/Act mode ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 0x10, rmii); ++ // restore to page 16 ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 20, 0x10); ++ } ++ else// if(lp->new_bus.phy_used->phy_id == 0x001CC815) // rtl820x ++ { ++ // change to rmii mode ++ rmii = gkhw_mdio_read(&lp->new_bus, lp->new_bus.phy_used->addr, 25); ++ rmii |= (1<<10); ++ rmii &= ~(1<<11); ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 25, rmii); ++ } ++#else //ephy mii mode ++ GH_EPHY_set_MII_RMII_rmii(0x0); ++ // RMII mode GPIO_TYPE_OUTPUT_ENET_PHY_TXD_3 used as 10/100M indicator ++#if 0 ++ gk_set_phy_speed_led(GPIO_TYPE_INPUT_0); ++#endif ++// printk("cmdline_phytype0:%d \n",cmdline_phytype); ++ if(lp->new_bus.phy_used->phy_id == 0x02430c54) // IP101g ++ { ++ // LindengYu: I don't known why do not go into effect. ++ // change to page 3 ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 20, 0x03); ++ rmii = gkhw_mdio_read(&lp->new_bus, lp->new_bus.phy_used->addr, 0x10); ++ rmii &= 0x3FFF; ++ rmii |= 0x4000; ++ // change to LED0 mode1, Link/Act mode ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 0x10, rmii); ++ // restore to page 16 ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 20, 0x10); ++ } ++ else// if(lp->new_bus.phy_used->phy_id == 0x001CC815) // rtl820x ++ { ++ // change to rmii mode ++// printk("read 25 reg nuw bus 0x%x\n",&(lp->new_bus)); ++ rmii = gkhw_mdio_read(&(lp->new_bus), lp->new_bus.phy_used->addr, 25); ++// printk("cmdline_phytype1:%d\n",cmdline_phytype); ++ rmii &= ~(1<<10); ++ rmii &= ~(1<<11); ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 25, rmii); ++ } ++ ++#endif ++#if 0 ++ { ++ u16 reglist[24][2]= ++ { ++ {0x10, 0x00},{0x10, 0x01},{0x10, 0x02},{0x10, 0x03}, ++ {0x10, 0x04},{0x10, 0x05},{0x10, 0x06},{0x10, 0x07}, ++ {0x10, 0x08},{0x10, 0x10},{0x10, 0x11},{0x10, 0x12}, ++ {0x10, 0x14},{0x01, 0x11},{0x01, 0x12},{0x01, 0x17}, ++ {0x02, 0x12},{0x08, 0x11},{0x0B, 0x12},{0x12, 0x11}, ++ {0x03, 0x10},{0x04, 0x10},{0x05, 0x10},{0x11, 0x11}, ++ }; ++ // page 16 ++ u16 regdata; ++ u16 regpage=0x00; ++ u32 i; ++ printk("Page Addr Data\n"); ++ for(i=0;i<24;i++) ++ { ++ if(regpage != reglist[i][0]) ++ { ++ regpage = reglist[i][0]; ++ gkhw_mdio_write(&lp->new_bus, lp->new_bus.phy_used->addr, 0x14, regpage); ++ } ++ regdata = gkhw_mdio_read(&lp->new_bus, lp->new_bus.phy_used->addr, reglist[i][1]); ++ printk("%02d %02d 0x%04x\n",reglist[i][0] ,reglist[i][1] ,regdata); ++ } ++ } ++#endif ++ //EPHY POWER OFF ++ //printk("net probe ephy power off\n"); ++ GK_EPHY_POWER_OFF(); ++ } ++ else ++ { ++//#else ++ GH_EPHY_set_MII_RMII_rmii(0x0); ++ #if 0 ++ gk_eth_writel(0xF0022540, 0x00000000); ++ gk_eth_writel(0xF00220C8, 0x0000C400); // reg_test_out(debug_bus_out) ++ gk_eth_writel(0xF00220E0, 0x0000810A); // debug mode ++ gk_eth_writel(0xF0022588, 0x00000007); // DAC 100M clk gate for 10M TX ++ #else ++ gk_eth_writel(GK_VA_ETH_PHY + 0x0540, 0x00000000); ++ gk_eth_writel(GK_VA_ETH_PHY + 0x00C8, 0x0000C400); // reg_test_out(debug_bus_out) ++ gk_eth_writel(GK_VA_ETH_PHY + 0x00E0, 0x0000810A); // debug mode ++ gk_eth_writel(GK_VA_ETH_PHY + 0x0588, 0x00000007); // DAC 100M clk gate for 10M TX ++ #endif ++ MHal_EMAC_WritReg8(0x0033, 0xde, 0x59); ++ MHal_EMAC_WritReg8(0x0033, 0xf4, 0x21); ++ MHal_EMAC_WritReg8(0x0032, 0x72, 0x80); ++ MHal_EMAC_WritReg8(0x0033, 0xfc, 0x00); ++ MHal_EMAC_WritReg8(0x0033, 0xfd, 0x00); ++ MHal_EMAC_WritReg8(0x0033, 0xb7, 0x07); ++ MHal_EMAC_WritReg8(0x0033, 0xcb, 0x11); ++ MHal_EMAC_WritReg8(0x0033, 0xcc, 0x80); ++ MHal_EMAC_WritReg8(0x0033, 0xcd, 0xd1); ++ MHal_EMAC_WritReg8(0x0033, 0xd4, 0x00); ++ MHal_EMAC_WritReg8(0x0033, 0xb9, 0x40); ++ MHal_EMAC_WritReg8(0x0033, 0xbb, 0x05); ++ MHal_EMAC_WritReg8(0x0033, 0xea, 0x46); ++ MHal_EMAC_WritReg8(0x0033, 0xa1, 0x00); ++ MHal_EMAC_WritReg8(0x0034, 0x3a, 0x03); ++ MHal_EMAC_WritReg8(0x0034, 0x3b, 0x00); ++ ++ //gain shift ++ MHal_EMAC_WritReg8(0x0033, 0xb4, 0x56); ++ ++ //det max ++ MHal_EMAC_WritReg8(0x0033, 0x4f, 0x02); ++ ++ //det min ++ MHal_EMAC_WritReg8(0x0033, 0x51, 0x01); ++ ++ //snr len (emc noise) ++ MHal_EMAC_WritReg8(0x0033, 0x77, 0x18); ++ ++ //snr k value ++ MHal_EMAC_WritReg8(0x0033, 0x43, 0x15); ++ ++ //100 gat ++ MHal_EMAC_WritReg8(0x0034, 0xc5, 0x00); ++ ++ //200 gat ++ MHal_EMAC_WritReg8(0x0034, 0x30, 0x43); ++ ++ //en_100t_phase ++ MHal_EMAC_WritReg8(0x0034, 0x39, 0x41); ++ ++ //10T waveform ++ uRegVal = MHal_EMAC_ReadReg8(0x0034, 0xe8); ++ uRegVal &= 0xf8; ++ uRegVal |= 0x06; ++ MHal_EMAC_WritReg8(0x0034, 0xe8, uRegVal); ++ MHal_EMAC_WritReg8(0x0032, 0x2b, 0x00); ++ ++ //analog ++ MHal_EMAC_WritReg8(0x0033, 0xd8, 0xb0); ++ MHal_EMAC_WritReg8(0x0033, 0xd9, 0x30); ++ ++ //disable EEE ++ uRegVal = MHal_EMAC_ReadReg8(0x0032, 0x2d); ++ uRegVal |= 0x40; ++ MHal_EMAC_WritReg8(0x0032, 0x2d, uRegVal); ++ ++ GH_EPHY_set_SPEED_ane(0x01); ++ } ++//#endif ++ ++ ether_setup(ndev); ++ ndev->netdev_ops = &GKETH_netdev_ops; ++ ndev->watchdog_timeo = lp->platform_info->watchdog_timeo; ++ netif_napi_add(ndev, &lp->napi, GKETH_napi, ++ lp->platform_info->napi_weight); ++ if (!is_valid_ether_addr(lp->platform_info->mac_addr)) ++ random_ether_addr(lp->platform_info->mac_addr); ++ memcpy(ndev->dev_addr, lp->platform_info->mac_addr, GKETH_MAC_SIZE); ++ ++ SET_ETHTOOL_OPS(ndev, &GKETH_ethtool_ops); ++ errorCode = register_netdev(ndev); ++ if (errorCode) { ++ dev_err(&pdev->dev, " register_netdev fail%d.\n", errorCode); ++ goto GKETH_drv_probe_netif_napi_del; ++ } ++ ++ platform_set_drvdata(pdev, ndev); ++ dev_notice(&pdev->dev, "MAC Address[%pM].\n", ndev->dev_addr); ++ ++ goto GKETH_drv_probe_exit; ++ ++GKETH_drv_probe_netif_napi_del: ++ netif_napi_del(&lp->napi); ++ mdiobus_unregister(&lp->new_bus); ++ ++GKETH_drv_probe_kfree_mdiobus: ++ kfree(lp->new_bus.irq); ++ ++GKETH_drv_probe_free_mii_gpio_irq: ++ //iounmap(eth_base); ++ ++//GKTH_drv_probe_free_res: ++ //release_mem_region(reg_res->start, size); ++ ++ ++//GKETH_drv_probe_free_netdev: ++ free_netdev(ndev); ++ ++GKETH_drv_probe_exit: ++ return errorCode; ++} ++ ++static int __devexit GKETH_drv_remove(struct platform_device *pdev) ++{ ++ struct net_device *ndev; ++ struct GKETH_info *lp; ++ ++ ndev = platform_get_drvdata(pdev); ++ if (ndev) { ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ unregister_netdev(ndev); ++ netif_napi_del(&lp->napi); ++ mdiobus_unregister(&lp->new_bus); ++ kfree(lp->new_bus.irq); ++ platform_set_drvdata(pdev, NULL); ++ free_netdev(ndev); ++ dev_notice(&pdev->dev, "Removed.\n"); ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int GKETH_drv_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ int errorCode = 0; ++ struct net_device *ndev; ++ struct GKETH_info *lp; ++ unsigned long flags; ++ ++ ndev = platform_get_drvdata(pdev); ++ if (ndev) { ++ if (!netif_running(ndev)) ++ goto GKETH_drv_suspend_exit; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ ++ napi_disable(&lp->napi); ++ netif_device_detach(ndev); ++ disable_irq(ndev->irq); ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ gkhw_disable(lp); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ } ++ ++GKETH_drv_suspend_exit: ++ dev_dbg(&pdev->dev, "%s exit with %d @ %d\n", ++ __func__, errorCode, state.event); ++ return errorCode; ++} ++ ++static int GKETH_drv_resume(struct platform_device *pdev) ++{ ++ int errorCode = 0; ++ struct net_device *ndev; ++ struct GKETH_info *lp; ++ unsigned long flags; ++ ++ ndev = platform_get_drvdata(pdev); ++ if (ndev) { ++ if (!netif_running(ndev)) ++ goto GKETH_drv_resume_exit; ++ ++ lp = (struct GKETH_info *)netdev_priv(ndev); ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ errorCode = gkhw_enable(lp); ++ gkhw_set_link_mode_speed(lp); ++ GKETH_rx_rngmng_init(lp); ++ GKETH_tx_rngmng_init(lp); ++ gkhw_set_dma_desc(lp); ++ gkhw_dma_rx_start(lp); ++ gkhw_dma_tx_start(lp); ++ gkhw_dma_int_enable(lp); ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ if (errorCode) { ++ dev_err(&pdev->dev, "gkhw_enable.\n"); ++ } else { ++ enable_irq(ndev->irq); ++ netif_device_attach(ndev); ++ napi_enable(&lp->napi); ++ } ++ } ++ ++GKETH_drv_resume_exit: ++ dev_dbg(&pdev->dev, "%s exit with %d\n", __func__, errorCode); ++ return errorCode; ++} ++#endif ++ ++static struct platform_driver GKETH_driver = { ++ .probe = GKETH_drv_probe, ++ .remove = __devexit_p(GKETH_drv_remove), ++#ifdef CONFIG_PM ++ .suspend = GKETH_drv_suspend, ++ .resume = GKETH_drv_resume, ++#endif ++ .driver = { ++ .name = "gk-eth", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init GKETH_init(void) ++{ ++ printk("%s\n", __FUNCTION__); ++ return platform_driver_register(&GKETH_driver); ++} ++ ++static void __exit GKETH_exit(void) ++{ ++ platform_driver_unregister(&GKETH_driver); ++} ++ ++module_init(GKETH_init); ++module_exit(GKETH_exit); ++ ++MODULE_DESCRIPTION("Goke GK Ethernet Driver"); ++MODULE_AUTHOR("Goke Microelectronics Inc."); ++MODULE_LICENSE("GPL"); ++ +diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c +index 8985cc62..1ebd058b 100644 +--- a/drivers/net/phy/mdio_bus.c ++++ b/drivers/net/phy/mdio_bus.c +@@ -99,7 +99,7 @@ static struct class mdio_bus_class = { + */ + int mdiobus_register(struct mii_bus *bus) + { +- int i, err; ++ int i, j, err; + + if (NULL == bus || NULL == bus->name || + NULL == bus->read || +@@ -124,18 +124,32 @@ int mdiobus_register(struct mii_bus *bus) + + if (bus->reset) + bus->reset(bus); +- +- for (i = 0; i < PHY_MAX_ADDR; i++) { +- if ((bus->phy_mask & (1 << i)) == 0) { +- struct phy_device *phydev; +- +- phydev = mdiobus_scan(bus, i); +- if (IS_ERR(phydev)) { +- err = PTR_ERR(phydev); +- goto error; +- } +- } +- } ++ for(j=0;j<5;j++) ++ { ++ for (i = 0; i < PHY_MAX_ADDR; i++) { ++ if ((bus->phy_mask & (1 << i)) == 0) { ++ struct phy_device *phydev; ++ ++ phydev = mdiobus_scan(bus, i); ++ if (IS_ERR(phydev)) { ++ err = PTR_ERR(phydev); ++ goto error; ++ } ++ } ++ ++ } ++ for (i = 0; i < PHY_MAX_ADDR; i++) ++ { ++ if(bus->phy_used) ++ { ++ printk("%s: PHY[%d] whose id 0x%08x \n", __func__, j, bus->phy_used->phy_id); ++ goto find_phy; ++ } ++ ++ } ++ mdelay(100); ++ } ++find_phy: + + bus->state = MDIOBUS_REGISTERED; + pr_info("%s: probed\n", bus->name); +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index e8c42d6a..896ca045 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -181,6 +181,7 @@ static struct phy_device* phy_device_create(struct mii_bus *bus, + + dev->state = PHY_DOWN; + ++ bus->phy_used = dev; + mutex_init(&dev->lock); + INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine); + +diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile +index 98db7619..e7649432 100644 +--- a/drivers/net/wireless/Makefile ++++ b/drivers/net/wireless/Makefile +@@ -24,6 +24,8 @@ obj-$(CONFIG_B43LEGACY) += b43legacy/ + obj-$(CONFIG_ZD1211RW) += zd1211rw/ + obj-$(CONFIG_RTL8180) += rtl818x/ + obj-$(CONFIG_RTL8187) += rtl818x/ ++obj-$(CONFIG_RTL8189ES) += rtl818x/ ++obj-$(CONFIG_RTL8189EU) += rtl818x/ + obj-$(CONFIG_RTLWIFI) += rtlwifi/ + + # 16-bit wireless PCMCIA client drivers +@@ -61,3 +63,5 @@ obj-$(CONFIG_MWIFIEX) += mwifiex/ + + obj-$(CONFIG_BRCMFMAC) += brcm80211/ + obj-$(CONFIG_BRCMSMAC) += brcm80211/ ++#obj-$(CONFIG_RTL8189ES) += rtl8189es/ ++#obj-$(CONFIG_RTL8188EU) += rtl8189eu/ +diff --git a/drivers/net/wireless/rtl818x/Kconfig b/drivers/net/wireless/rtl818x/Kconfig +index 17d80fe5..7d6c6419 100644 +--- a/drivers/net/wireless/rtl818x/Kconfig ++++ b/drivers/net/wireless/rtl818x/Kconfig +@@ -85,4 +85,17 @@ config RTL8187_LEDS + bool + depends on RTL8187 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = RTL8187) + default y ++ ++config RTL8189ES ++ tristate "Realtek 8189E SDIO WiFi" ++ #depends on USB ++ ---help--- ++ Help message of RTL8189ES ++ ++config RTL8189EU ++ tristate "Realtek 8189E USB WiFi" ++ depends on USB ++ ---help--- ++ Help message of RTL8189EU ++ + +diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile +index 99756907..2c93804d 100644 +--- a/drivers/net/wireless/rtl818x/Makefile ++++ b/drivers/net/wireless/rtl818x/Makefile +@@ -1,2 +1,4 @@ + obj-$(CONFIG_RTL8180) += rtl8180/ + obj-$(CONFIG_RTL8187) += rtl8187/ ++obj-$(CONFIG_RTL8189ES) += rtl8189/ ++obj-$(CONFIG_RTL8189EU) += rtl8189/ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/Makefile b/drivers/net/wireless/rtl818x/rtl8189/Makefile +new file mode 100644 +index 00000000..a5aa51f5 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/Makefile +@@ -0,0 +1,872 @@ ++EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS) ++EXTRA_CFLAGS += -O1 ++#EXTRA_CFLAGS += -O3 ++#EXTRA_CFLAGS += -Wall ++#EXTRA_CFLAGS += -Wextra ++#EXTRA_CFLAGS += -Werror ++#EXTRA_CFLAGS += -pedantic ++#EXTRA_CFLAGS += -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes ++ ++EXTRA_CFLAGS += -Wno-unused-variable ++EXTRA_CFLAGS += -Wno-unused-value ++EXTRA_CFLAGS += -Wno-unused-label ++EXTRA_CFLAGS += -Wno-unused-parameter ++EXTRA_CFLAGS += -Wno-unused-function ++EXTRA_CFLAGS += -Wno-unused ++ ++EXTRA_CFLAGS += -Wno-uninitialized ++ ++EXTRA_CFLAGS += -I$(src)/include ++ ++CONFIG_AUTOCFG_CP = n ++ ++ifeq ($(CONFIG_RTL8189ES), y) ++CONFIG_USB_HCI = n ++CONFIG_SDIO_HCI = y ++else ++CONFIG_USB_HCI = y ++CONFIG_SDIO_HCI = n ++endif ++ ++CONFIG_RTL8192C = n ++CONFIG_RTL8192D = n ++CONFIG_RTL8723A = n ++CONFIG_RTL8188E = y ++ ++#CONFIG_USB_HCI = n ++CONFIG_PCI_HCI = n ++#CONFIG_SDIO_HCI = y ++CONFIG_GSPI_HCI = n ++ ++CONFIG_MP_INCLUDED = y ++CONFIG_POWER_SAVING = y ++CONFIG_USB_AUTOSUSPEND = n ++CONFIG_HW_PWRP_DETECTION = n ++CONFIG_WIFI_TEST = n ++CONFIG_BT_COEXIST = n ++CONFIG_RTL8192CU_REDEFINE_1X1 = n ++CONFIG_INTEL_WIDI = n ++CONFIG_WAPI_SUPPORT = n ++CONFIG_EFUSE_CONFIG_FILE = n ++CONFIG_EXT_CLK = n ++CONFIG_FTP_PROTECT = n ++CONFIG_WOWLAN = n ++CONFIG_GPIO_WAKEUP = n ++CONFIG_ODM_ADAPTIVITY = n ++CONFIG_MMC_PM_KEEP_POWER = n ++ ++CONFIG_PLATFORM_I386_PC = n ++CONFIG_PLATFORM_ANDROID_X86 = n ++CONFIG_PLATFORM_JB_X86 = n ++CONFIG_PLATFORM_ARM_S3C2K4 = n ++CONFIG_PLATFORM_ARM_PXA2XX = n ++CONFIG_PLATFORM_ARM_S3C6K4 = n ++CONFIG_PLATFORM_MIPS_RMI = n ++CONFIG_PLATFORM_RTD2880B = n ++CONFIG_PLATFORM_MIPS_AR9132 = n ++CONFIG_PLATFORM_RTK_DMP = n ++CONFIG_PLATFORM_MIPS_PLM = n ++CONFIG_PLATFORM_MSTAR389 = n ++CONFIG_PLATFORM_MT53XX = n ++CONFIG_PLATFORM_ARM_MX51_241H = n ++CONFIG_PLATFORM_ACTIONS_ATJ227X = n ++CONFIG_PLATFORM_TEGRA3_CARDHU = n ++CONFIG_PLATFORM_TEGRA4_DALMORE = n ++CONFIG_PLATFORM_ARM_TCC8900 = n ++CONFIG_PLATFORM_ARM_TCC8920 = n ++CONFIG_PLATFORM_ARM_TCC8920_JB42 = n ++CONFIG_PLATFORM_ARM_RK2818 = n ++CONFIG_PLATFORM_ARM_URBETTER = n ++CONFIG_PLATFORM_ARM_TI_PANDA = n ++CONFIG_PLATFORM_MIPS_JZ4760 = n ++CONFIG_PLATFORM_DMP_PHILIPS = n ++CONFIG_PLATFORM_TI_DM365 = n ++CONFIG_PLATFORM_MSTAR_TITANIA12 = n ++CONFIG_PLATFORM_MSTAR = n ++CONFIG_PLATFORM_SZEBOOK = n ++CONFIG_PLATFORM_ARM_SUNxI = n ++CONFIG_PLATFORM_ARM_SUN6I = n ++CONFIG_PLATFORM_ARM_SUN7I = n ++CONFIG_PLATFORM_ACTIONS_ATM702X = n ++CONFIG_PLATFORM_MN10300 = n ++CONFIG_PLATFORM_ACTIONS_ATV5201 = n ++CONFIG_PLATFORM_GOKE_IPC = y ++ ++CONFIG_DRVEXT_MODULE = n ++ ++export TopDIR ?= $(shell pwd) ++ ++ ++OUTSRC_FILES := hal/OUTSRC/odm_debug.o \ ++ hal/OUTSRC/odm_interface.o\ ++ hal/OUTSRC/odm_HWConfig.o\ ++ hal/OUTSRC/odm.o\ ++ hal/OUTSRC/HalPhyRf.o ++ ++ifeq ($(CONFIG_RTL8192C), y) ++RTL871X = rtl8192c ++ ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME = 8192cu ++OUTSRC_FILES += hal/OUTSRC/$(RTL871X)/Hal8192CUFWImg_CE.o \ ++ hal/OUTSRC/$(RTL871X)/Hal8192CUPHYImg_CE.o \ ++ hal/OUTSRC/$(RTL871X)/Hal8192CUMACImg_CE.o ++endif ++ ++ifeq ($(CONFIG_PCI_HCI), y) ++MODULE_NAME = 8192ce ++OUTSRC_FILES += hal/OUTSRC/$(RTL871X)/Hal8192CEFWImg_CE.o \ ++ hal/OUTSRC/$(RTL871X)/Hal8192CEPHYImg_CE.o \ ++ hal/OUTSRC/$(RTL871X)/Hal8192CEMACImg_CE.o ++endif ++ ++OUTSRC_FILES += hal/OUTSRC/$(RTL871X)/odm_RTL8192C.o\ ++ hal/OUTSRC/$(RTL871X)/HalDMOutSrc8192C_CE.o ++ ++CHIP_FILES := \ ++ hal/$(RTL871X)/$(RTL871X)_sreset.o \ ++ hal/$(RTL871X)/$(RTL871X)_xmit.o ++CHIP_FILES += $(OUTSRC_FILES) ++ ++endif ++ ++ifeq ($(CONFIG_RTL8192D), y) ++RTL871X = rtl8192d ++ ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME = 8192du ++OUTSRC_FILES += hal/OUTSRC/$(RTL871X)/Hal8192DUFWImg_CE.o \ ++ hal/OUTSRC/$(RTL871X)/Hal8192DUPHYImg_CE.o \ ++ hal/OUTSRC/$(RTL871X)/Hal8192DUMACImg_CE.o ++endif ++ ++ifeq ($(CONFIG_PCI_HCI), y) ++MODULE_NAME = 8192de ++OUTSRC_FILES += hal/OUTSRC/$(RTL871X)/Hal8192DEFWImg_CE.o \ ++ hal/OUTSRC/$(RTL871X)/Hal8192DEPHYImg_CE.o \ ++ hal/OUTSRC/$(RTL871X)/Hal8192DEMACImg_CE.o ++endif ++ ++OUTSRC_FILES += hal/OUTSRC/$(RTL871X)/odm_RTL8192D.o\ ++ hal/OUTSRC/$(RTL871X)/HalDMOutSrc8192D_CE.o ++CHIP_FILES := \ ++ hal/$(RTL871X)/$(RTL871X)_xmit.o ++CHIP_FILES += $(OUTSRC_FILES) ++endif ++ ++ifeq ($(CONFIG_RTL8723A), y) ++ ++RTL871X = rtl8723a ++ ++HAL_COMM_FILES := hal/$(RTL871X)/$(RTL871X)_xmit.o \ ++ hal/$(RTL871X)/$(RTL871X)_sreset.o ++ ++ifeq ($(CONFIG_GSPI_HCI), y) ++MODULE_NAME = 8723as ++OUTSRC_FILES += hal/OUTSRC/$(RTL871X)/Hal8723SHWImg_CE.o ++endif ++ ++ifeq ($(CONFIG_SDIO_HCI), y) ++MODULE_NAME = 8723as ++OUTSRC_FILES += hal/OUTSRC/$(RTL871X)/Hal8723SHWImg_CE.o ++endif ++ ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME = 8723au ++OUTSRC_FILES += hal/OUTSRC/$(RTL871X)/Hal8723UHWImg_CE.o ++endif ++ ++ifeq ($(CONFIG_PCI_HCI), y) ++MODULE_NAME = 8723ae ++OUTSRC_FILES += hal/OUTSRC/$(RTL871X)/Hal8723EHWImg_CE.o ++endif ++ ++#hal/OUTSRC/$(RTL871X)/HalHWImg8723A_FW.o ++OUTSRC_FILES += hal/OUTSRC/$(RTL871X)/HalHWImg8723A_BB.o\ ++ hal/OUTSRC/$(RTL871X)/HalHWImg8723A_MAC.o\ ++ hal/OUTSRC/$(RTL871X)/HalHWImg8723A_RF.o\ ++ hal/OUTSRC/$(RTL871X)/odm_RegConfig8723A.o ++ ++OUTSRC_FILES += hal/OUTSRC/rtl8192c/HalDMOutSrc8192C_CE.o ++clean_more ?= ++clean_more += clean_odm-8192c ++ ++PWRSEQ_FILES := hal/HalPwrSeqCmd.o \ ++ hal/$(RTL871X)/Hal8723PwrSeq.o ++ ++CHIP_FILES += $(HAL_COMM_FILES) $(OUTSRC_FILES) $(PWRSEQ_FILES) ++ ++ifeq ($(CONFIG_BT_COEXIST), y) ++CHIP_FILES += hal/$(RTL871X)/rtl8723a_bt-coexist.o ++endif ++ ++endif ++ ++ifeq ($(CONFIG_RTL8188E), y) ++ ++RTL871X = rtl8188e ++HAL_COMM_FILES := hal/$(RTL871X)/$(RTL871X)_xmit.o\ ++ hal/$(RTL871X)/$(RTL871X)_sreset.o ++ ++ifeq ($(CONFIG_SDIO_HCI), y) ++MODULE_NAME = 8189es ++endif ++ ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME = 8188eu ++endif ++ ++ifeq ($(CONFIG_PCI_HCI), y) ++MODULE_NAME = 8188ee ++endif ++ ++OUTSRC_FILES += hal/OUTSRC/$(RTL871X)/HalHWImg8188E_MAC.o\ ++ hal/OUTSRC/$(RTL871X)/HalHWImg8188E_BB.o\ ++ hal/OUTSRC/$(RTL871X)/HalHWImg8188E_RF.o\ ++ hal/OUTSRC/$(RTL871X)/Hal8188EFWImg_CE.o\ ++ hal/OUTSRC/$(RTL871X)/HalPhyRf_8188e.o\ ++ hal/OUTSRC/$(RTL871X)/odm_RegConfig8188E.o\ ++ hal/OUTSRC/$(RTL871X)/Hal8188ERateAdaptive.o\ ++ hal/OUTSRC/$(RTL871X)/odm_RTL8188E.o ++ ++ifeq ($(CONFIG_RTL8188E), y) ++ifeq ($(CONFIG_WOWLAN), y) ++OUTSRC_FILES += hal/OUTSRC/$(RTL871X)/HalHWImg8188E_FW.o ++endif ++endif ++ ++PWRSEQ_FILES := hal/HalPwrSeqCmd.o \ ++ hal/$(RTL871X)/Hal8188EPwrSeq.o ++ ++CHIP_FILES += $(HAL_COMM_FILES) $(OUTSRC_FILES) $(PWRSEQ_FILES) ++ ++endif ++ ++ ++ifeq ($(CONFIG_GSPI_HCI), y) ++HCI_NAME = gspi ++endif ++ ++ifeq ($(CONFIG_SDIO_HCI), y) ++HCI_NAME = sdio ++endif ++ ++ifeq ($(CONFIG_USB_HCI), y) ++HCI_NAME = usb ++endif ++ ++ifeq ($(CONFIG_PCI_HCI), y) ++HCI_NAME = pci ++endif ++ ++ ++_OS_INTFS_FILES := os_dep/osdep_service.o \ ++ os_dep/linux/os_intfs.o \ ++ os_dep/linux/$(HCI_NAME)_intf.o \ ++ os_dep/linux/$(HCI_NAME)_ops_linux.o \ ++ os_dep/linux/ioctl_linux.o \ ++ os_dep/linux/xmit_linux.o \ ++ os_dep/linux/mlme_linux.o \ ++ os_dep/linux/recv_linux.o \ ++ os_dep/linux/ioctl_cfg80211.o \ ++ os_dep/linux/rtw_android.o ++ ++ifeq ($(CONFIG_SDIO_HCI), y) ++_OS_INTFS_FILES += os_dep/linux/custom_gpio_linux.o ++_OS_INTFS_FILES += os_dep/linux/$(HCI_NAME)_ops_linux.o ++endif ++ ++ifeq ($(CONFIG_GSPI_HCI), y) ++_OS_INTFS_FILES += os_dep/linux/custom_gpio_linux.o ++_OS_INTFS_FILES += os_dep/linux/$(HCI_NAME)_ops_linux.o ++endif ++ ++_HAL_INTFS_FILES := hal/hal_intf.o \ ++ hal/hal_com.o \ ++ hal/$(RTL871X)/$(RTL871X)_hal_init.o \ ++ hal/$(RTL871X)/$(RTL871X)_phycfg.o \ ++ hal/$(RTL871X)/$(RTL871X)_rf6052.o \ ++ hal/$(RTL871X)/$(RTL871X)_dm.o \ ++ hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ ++ hal/$(RTL871X)/$(RTL871X)_cmd.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ ++ hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o ++ ++ifeq ($(CONFIG_SDIO_HCI), y) ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o ++else ++ifeq ($(CONFIG_GSPI_HCI), y) ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o ++else ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o ++endif ++endif ++ ++ifeq ($(CONFIG_MP_INCLUDED), y) ++_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_mp.o ++endif ++ ++_HAL_INTFS_FILES += $(CHIP_FILES) ++ ++ ++ifeq ($(CONFIG_AUTOCFG_CP), y) ++CURR_DIR = $(shell pwd)/drivers/net/wireless/rtl818x/rtl8189 ++$(shell cp $(CURR_DIR)/autoconf_rtl8189e_$(HCI_NAME)_linux.h $(CURR_DIR)/include/autoconf.h) ++#ifeq ($(CONFIG_RTL8188E)$(CONFIG_SDIO_HCI),yy) ++#$(shell cp $(CURR_DIR)/autoconf_rtl8189e_$(HCI_NAME)_linux.h $(CURR_DIR)/include/autoconf.h) ++#else ++#$(shell cp $(CURR_DIR)/autoconf_$(RTL871X)_$(HCI_NAME)_linux.h $(CURR_DIR)/include/autoconf.h) ++#endif ++endif ++ ++ ++ifeq ($(CONFIG_USB_HCI), y) ++ifeq ($(CONFIG_USB_AUTOSUSPEND), y) ++EXTRA_CFLAGS += -DCONFIG_USB_AUTOSUSPEND ++endif ++endif ++ ++ifeq ($(CONFIG_MP_INCLUDED), y) ++EXTRA_CFLAGS += -DCONFIG_MP_INCLUDED ++endif ++ ++ifeq ($(CONFIG_POWER_SAVING), y) ++EXTRA_CFLAGS += -DCONFIG_POWER_SAVING ++endif ++ ++ifeq ($(CONFIG_HW_PWRP_DETECTION), y) ++EXTRA_CFLAGS += -DCONFIG_HW_PWRP_DETECTION ++endif ++ ++ifeq ($(CONFIG_WIFI_TEST), y) ++EXTRA_CFLAGS += -DCONFIG_WIFI_TEST ++endif ++ ++ifeq ($(CONFIG_BT_COEXIST), y) ++EXTRA_CFLAGS += -DCONFIG_BT_COEXIST ++endif ++ ++ifeq ($(CONFIG_RTL8192CU_REDEFINE_1X1), y) ++EXTRA_CFLAGS += -DRTL8192C_RECONFIG_TO_1T1R ++endif ++ ++ifeq ($(CONFIG_INTEL_WIDI), y) ++EXTRA_CFLAGS += -DCONFIG_INTEL_WIDI ++endif ++ ++ifeq ($(CONFIG_WAPI_SUPPORT), y) ++EXTRA_CFLAGS += -DCONFIG_WAPI_SUPPORT ++endif ++ ++ifeq ($(CONFIG_EFUSE_CONFIG_FILE), y) ++EXTRA_CFLAGS += -DCONFIG_EFUSE_CONFIG_FILE ++endif ++ ++ifeq ($(CONFIG_EXT_CLK), y) ++EXTRA_CFLAGS += -DCONFIG_EXT_CLK ++endif ++ ++ifeq ($(CONFIG_FTP_PROTECT), y) ++EXTRA_CFLAGS += -DCONFIG_FTP_PROTECT ++endif ++ ++ifeq ($(CONFIG_ODM_ADAPTIVITY), y) ++EXTRA_CFLAGS += -DCONFIG_ODM_ADAPTIVITY ++endif ++ ++ifeq ($(CONFIG_MMC_PM_KEEP_POWER), y) ++EXTRA_CFLAGS += -DCONFIG_MMC_PM_KEEP_POWER ++endif ++ ++ifeq ($(CONFIG_RTL8188E), y) ++ifeq ($(CONFIG_WOWLAN), y) ++EXTRA_CFLAGS += -DCONFIG_WOWLAN ++EXTRA_CFLAGS += -DCONFIG_MMC_PM_KEEP_POWER ++endif ++ifeq ($(CONFIG_GPIO_WAKEUP), y) ++EXTRA_CFLAGS += -DCONFIG_GPIO_WAKEUP ++endif ++endif ++ ++ifeq ($(CONFIG_RTL8188E), y) ++ifeq ($(CONFIG_EFUSE_CONFIG_FILE), y) ++EXTRA_CFLAGS += -DCONFIG_RF_GAIN_OFFSET ++endif ++endif ++ ++ifeq ($(CONFIG_PLATFORM_I386_PC), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++SUBARCH := $(shell uname -m | sed -e s/i.86/i386/) ++ARCH ?= $(SUBARCH) ++CROSS_COMPILE ?= ++KVER := $(shell uname -r) ++KSRC := /lib/modules/$(KVER)/build ++MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ ++INSTALL_PREFIX := ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ACTIONS_ATM702X), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ACTIONS_ATM702X ++#ARCH := arm ++ARCH := $(R_ARCH) ++#CROSS_COMPILE := arm-none-linux-gnueabi- ++CROSS_COMPILE := $(R_CROSS_COMPILE) ++KVER:= 3.4.0 ++#KSRC := ../../../../build/out/kernel ++KSRC := $(KERNEL_BUILD_PATH) ++MODULE_NAME :=wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_TI_AM3517), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_SHUTTLE ++CROSS_COMPILE := arm-eabi- ++KSRC := $(shell pwd)/../../../Android/kernel ++ARCH := arm ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MSTAR_TITANIA12), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR -DCONFIG_PLATFORM_MSTAR_TITANIA12 ++ARCH:=mips ++CROSS_COMPILE:= /usr/src/Mstar_kernel/mips-4.3/bin/mips-linux-gnu- ++KVER:= 2.6.28.9 ++KSRC:= /usr/src/Mstar_kernel/2.6.28.9/ ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MSTAR), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR ++ARCH:=arm ++CROSS_COMPILE:= /usr/src/bin/arm-none-linux-gnueabi- ++KVER:= 3.1.10 ++KSRC:= /usr/src/Mstar_kernel/3.1.10/ ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ANDROID_X86), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++SUBARCH := $(shell uname -m | sed -e s/i.86/i386/) ++ARCH := $(SUBARCH) ++CROSS_COMPILE := /media/DATA-2/android-x86/ics-x86_20120130/prebuilt/linux-x86/toolchain/i686-unknown-linux-gnu-4.2.1/bin/i686-unknown-linux-gnu- ++KSRC := /media/DATA-2/android-x86/ics-x86_20120130/out/target/product/generic_x86/obj/kernel ++MODULE_NAME :=wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_JB_X86), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_P2P_IPS ++SUBARCH := $(shell uname -m | sed -e s/i.86/i386/) ++ARCH := $(SUBARCH) ++CROSS_COMPILE := /home/android_sdk/android-x86_JB/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7/bin/i686-linux-android- ++KSRC := /home/android_sdk/android-x86_JB/out/target/product/x86/obj/kernel/ ++MODULE_NAME :=wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_PXA2XX), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++ARCH := arm ++CROSS_COMPILE := arm-none-linux-gnueabi- ++KVER := 2.6.34.1 ++KSRC ?= /usr/src/linux-2.6.34.1 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_S3C2K4), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++ARCH := arm ++CROSS_COMPILE := arm-linux- ++KVER := 2.6.24.7_$(ARCH) ++KSRC := /usr/src/kernels/linux-$(KVER) ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_S3C6K4), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++ARCH := arm ++CROSS_COMPILE := arm-none-linux-gnueabi- ++KVER := 2.6.34.1 ++KSRC ?= /usr/src/linux-2.6.34.1 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_RTD2880B), y) ++EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN -DCONFIG_PLATFORM_RTD2880B ++ARCH:= ++CROSS_COMPILE:= ++KVER:= ++KSRC:= ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MIPS_RMI), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++ARCH:=mips ++CROSS_COMPILE:=mipsisa32r2-uclibc- ++KVER:= ++KSRC:= /root/work/kernel_realtek ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MIPS_PLM), y) ++EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN ++ARCH:=mips ++CROSS_COMPILE:=mipsisa32r2-uclibc- ++KVER:= ++KSRC:= /root/work/kernel_realtek ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MSTAR389), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR389 ++ARCH:=mips ++CROSS_COMPILE:= mips-linux-gnu- ++KVER:= 2.6.28.10 ++KSRC:= /home/mstar/mstar_linux/2.6.28.9/ ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MIPS_AR9132), y) ++EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN ++ARCH := mips ++CROSS_COMPILE := mips-openwrt-linux- ++KSRC := /home/alex/test_openwrt/tmp/linux-2.6.30.9 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_DMP_PHILIPS), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DRTK_DMP_PLATFORM ++ARCH := mips ++#CROSS_COMPILE:=/usr/local/msdk-4.3.6-mips-EL-2.6.12.6-0.9.30.3/bin/mipsel-linux- ++CROSS_COMPILE:=/usr/local/toolchain_mipsel/bin/mipsel-linux- ++KSRC ?=/usr/local/Jupiter/linux-2.6.12 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_RTK_DMP), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DRTK_DMP_PLATFORM ++ARCH:=mips ++CROSS_COMPILE:=mipsel-linux- ++KVER:= ++KSRC ?= /usr/src/DMP_Kernel/jupiter/linux-2.6.12 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MT53XX), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MT53XX ++ARCH:= arm ++CROSS_COMPILE:= arm11_mtk_le- ++KVER:= 2.6.27 ++KSRC?= /proj/mtk00802/BD_Compare/BDP/Dev/BDP_V301/BDP_Linux/linux-2.6.27 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_MX51_241H), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_WISTRON_PLATFORM ++ARCH := arm ++CROSS_COMPILE := /opt/freescale/usr/local/gcc-4.1.2-glibc-2.5-nptl-3/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi- ++KVER := 2.6.31 ++KSRC ?= /lib/modules/2.6.31-770-g0e46b52/source ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ACTIONS_ATJ227X), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ACTIONS_ATJ227X ++ARCH := mips ++CROSS_COMPILE := /home/cnsd4/project/actions/tools-2.6.27/bin/mipsel-linux-gnu- ++KVER := 2.6.27 ++KSRC := /home/cnsd4/project/actions/linux-2.6.27.28 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_TI_DM365), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_TI_DM365 ++ARCH := arm ++CROSS_COMPILE := /home/cnsd4/Appro/mv_pro_5.0/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le- ++KVER := 2.6.18 ++KSRC := /home/cnsd4/Appro/mv_pro_5.0/montavista/pro/devkit/lsp/ti-davinci/linux-dm365 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_TEGRA3_CARDHU), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_P2P_IPS ++ARCH := arm ++CROSS_COMPILE := /home/android_sdk/nvidia/tegra-16r3-partner-android-4.1_20120723/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- ++KSRC := /home/android_sdk/nvidia/tegra-16r3-partner-android-4.1_20120723/out/target/product/cardhu/obj/KERNEL ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_TEGRA4_DALMORE), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_P2P_IPS ++ARCH := arm ++CROSS_COMPILE := /home/android_sdk/nvidia/tegra-17r9-partner-android-4.2-dalmore_20130131/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- ++KSRC := /home/android_sdk/nvidia/tegra-17r9-partner-android-4.2-dalmore_20130131/out/target/product/dalmore/obj/KERNEL ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_TCC8900), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++ARCH := arm ++CROSS_COMPILE := /home/android_sdk/Telechips/SDK_2304_20110613/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- ++KSRC := /home/android_sdk/Telechips/SDK_2304_20110613/kernel ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_TCC8920), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++ARCH := arm ++CROSS_COMPILE := /home/android_sdk/Telechips/v12.06_r1-tcc-android-4.0.4/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- ++KSRC := /home/android_sdk/Telechips/v12.06_r1-tcc-android-4.0.4/kernel ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_TCC8920_JB42), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_P2P_IPS ++ARCH := arm ++CROSS_COMPILE := /home/android_sdk/Telechips/v13.03_r1-tcc-android-4.2.2_ds_patched/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- ++KSRC := /home/android_sdk/Telechips/v13.03_r1-tcc-android-4.2.2_ds_patched/kernel ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_RK2818), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ROCKCHIPS -DCONFIG_MINIMAL_MEMORY_USAGE ++ifeq ($(CONFIG_SDIO_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_DETECT_CPWM_BY_POLLING -DCONFIG_DETECT_C2H_BY_POLLING ++endif ++ARCH := arm ++CROSS_COMPILE := /usr/src/release_fae_version/toolchain/arm-eabi-4.4.0/bin/arm-eabi- ++KSRC := /usr/src/release_fae_version/kernel25_A7_281x ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_URBETTER), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN #-DCONFIG_MINIMAL_MEMORY_USAGE ++ARCH := arm ++CROSS_COMPILE := /media/DATA-1/urbetter/arm-2009q3/bin/arm-none-linux-gnueabi- ++KSRC := /media/DATA-1/urbetter/ics-urbetter/kernel ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_TI_PANDA), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN #-DCONFIG_MINIMAL_MEMORY_USAGE ++ARCH := arm ++#CROSS_COMPILE := /media/DATA-1/aosp/ics-aosp_20111227/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- ++#KSRC := /media/DATA-1/aosp/android-omap-panda-3.0_20120104 ++CROSS_COMPILE := /media/DATA-1/android-4.0/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- ++KSRC := /media/DATA-1/android-4.0/panda_kernel/omap ++MODULE_NAME := wlan ++endif ++ ++ifeq ($(CONFIG_PLATFORM_MIPS_JZ4760), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_MINIMAL_MEMORY_USAGE ++ARCH ?= mips ++CROSS_COMPILE ?= /mnt/sdb5/Ingenic/Umido/mips-4.3/bin/mips-linux-gnu- ++KSRC ?= /mnt/sdb5/Ingenic/Umido/kernel ++endif ++ ++ifeq ($(CONFIG_PLATFORM_SZEBOOK), y) ++EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN ++ARCH:=arm ++CROSS_COMPILE:=/opt/crosstool2/bin/armeb-unknown-linux-gnueabi- ++KVER:= 2.6.31.6 ++KSRC:= ../code/linux-2.6.31.6-2020/ ++endif ++ ++#Add setting for MN10300 ++ifeq ($(CONFIG_PLATFORM_MN10300), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MN10300 ++ARCH := mn10300 ++CROSS_COMPILE := mn10300-linux- ++KVER := 2.6.32.2 ++KSRC := /home/winuser/work/Plat_sLD2T_V3010/usr/src/linux-2.6.32.2 ++INSTALL_PREFIX := ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_SUNxI), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ARM_SUNxI ++ifeq ($(CONFIG_USB_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX ++endif ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DDCONFIG_P2P_IPS ++# default setting for A10-EVB mmc0 ++ifeq ($(CONFIG_SDIO_HCI), y) ++#EXTRA_CFLAGS += -DCONFIG_WITS_EVB_V13 ++endif ++ARCH := arm ++#CROSS_COMPILE := arm-none-linux-gnueabi- ++CROSS_COMPILE=/home/android_sdk/Allwinner/a10/android-jb42/lichee-jb42/buildroot/output/external-toolchain/bin/arm-none-linux-gnueabi- ++KVER := 3.0.8 ++#KSRC:= ../lichee/linux-3.0/ ++KSRC=/home/android_sdk/Allwinner/a10/android-jb42/lichee-jb42/linux-3.0 ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_SUN6I), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN6I ++ifeq ($(CONFIG_USB_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX ++endif ++# default setting for A31-EVB mmc0 ++ifeq ($(CONFIG_SDIO_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_A31_EVB ++endif ++ ++EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_P2P_IPS -DCONFIG_QOS_OPTIMIZATION ++ARCH := arm ++CROSS_COMPILE := /home/android_sdk/Allwinner/a31/android-jb42/lichee/buildroot/output/external-toolchain/bin/arm-linux-gnueabi- ++KVER := 3.3.0 ++#KSRC:= ../lichee/linux-3.3/ ++KSRC :=/home/android_sdk/Allwinner/a31/android-jb42/lichee/linux-3.3 ++ifeq ($(CONFIG_USB_HCI), y) ++MODULE_NAME := 8188eu_sw ++endif ++endif ++ ++ifeq ($(CONFIG_PLATFORM_ARM_SUN7I), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN7I ++ifeq ($(CONFIG_USB_HCI), y) ++EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX ++endif ++EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT ++# default setting for Android 4.1, 4.2 ++EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT ++EXTRA_CFLAGS += -DCONFIG_P2P_IPS -DCONFIG_QOS_OPTIMIZATION ++ARCH := arm ++# Cross compile setting for Android 4.2 SDK ++#CROSS_COMPILE := /home/android_sdk/Allwinner/a20/sugar/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- ++#KVER := 3.3.0 ++#KSRC :=/home/android_sdk/Allwinner/a20/sugar/lichee/linux-3.3 ++# Cross compile setting for Android 4.3 SDK ++CROSS_COMPILE := /home/android_sdk/Allwinner/a20/android-jb43/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- ++KVER := 3.4.39 ++KSRC :=/home/android_sdk/Allwinner/a20/android-jb43/lichee/linux-3.4 ++endif ++ ++ ++ifeq ($(CONFIG_PLATFORM_ACTIONS_ATV5201), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ACTIONS_ATV5201 ++ARCH := mips ++CROSS_COMPILE := mipsel-linux-gnu- ++KVER := $(KERNEL_VER) ++KSRC:= $(CFGDIR)/../../kernel/linux-$(KERNEL_VER) ++endif ++ ++ ++ifeq ($(CONFIG_PLATFORM_GOKE_IPC), y) ++EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_GOKE_IPC ++endif ++ ++ifneq ($(USER_MODULE_NAME),) ++MODULE_NAME := $(USER_MODULE_NAME) ++endif ++ ++ifneq ($(KERNELRELEASE),) ++ ++rtk_core := core/rtw_cmd.o \ ++ core/rtw_security.o \ ++ core/rtw_debug.o \ ++ core/rtw_io.o \ ++ core/rtw_ioctl_query.o \ ++ core/rtw_ioctl_set.o \ ++ core/rtw_ieee80211.o \ ++ core/rtw_mlme.o \ ++ core/rtw_mlme_ext.o \ ++ core/rtw_wlan_util.o \ ++ core/rtw_pwrctrl.o \ ++ core/rtw_rf.o \ ++ core/rtw_recv.o \ ++ core/rtw_sta_mgt.o \ ++ core/rtw_ap.o \ ++ core/rtw_xmit.o \ ++ core/rtw_p2p.o \ ++ core/rtw_tdls.o \ ++ core/rtw_br_ext.o \ ++ core/rtw_iol.o \ ++ core/rtw_led.o \ ++ core/rtw_sreset.o \ ++ core/rtw_odm.o ++ ++$(MODULE_NAME)-y += $(rtk_core) ++ ++$(MODULE_NAME)-$(CONFIG_INTEL_WIDI) += core/rtw_intel_widi.o ++ ++$(MODULE_NAME)-$(CONFIG_WAPI_SUPPORT) += core/rtw_wapi.o \ ++ core/rtw_wapi_sms4.o ++ ++$(MODULE_NAME)-y += core/efuse/rtw_efuse.o ++ ++$(MODULE_NAME)-y += $(_HAL_INTFS_FILES) ++ ++$(MODULE_NAME)-y += $(_OS_INTFS_FILES) ++ ++$(MODULE_NAME)-$(CONFIG_MP_INCLUDED) += core/rtw_mp.o \ ++ core/rtw_mp_ioctl.o ++ifeq ($(CONFIG_RTL8723A), y) ++ ++$(MODULE_NAME)-$(CONFIG_MP_INCLUDED)+= core/rtw_bt_mp.o ++endif ++ ++ifeq ($(CONFIG_RTL8189ES), y) ++obj-$(CONFIG_RTL8189ES) := $(MODULE_NAME).o ++else ++obj-$(CONFIG_RTL8189EU) := $(MODULE_NAME).o ++endif ++ ++else ++ ++ifeq ($(CONFIG_RTL8189EU), y) ++export CONFIG_RTL8189EU = m ++else ++export CONFIG_RTL8189ES = m ++endif ++ ++ ++all: modules ++ ++modules: ++ $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KSRC) M=$(shell pwd) modules ++ ++strip: ++ $(CROSS_COMPILE)strip $(MODULE_NAME).ko --strip-unneeded ++ ++install: ++ install -p -m 644 $(MODULE_NAME).ko $(MODDESTDIR) ++ /sbin/depmod -a ${KVER} ++ ++uninstall: ++ rm -f $(MODDESTDIR)/$(MODULE_NAME).ko ++ /sbin/depmod -a ${KVER} ++ ++config_r: ++ @echo "make config" ++ /bin/bash script/Configure script/config.in ++ ++.PHONY: modules clean clean_odm-8192c ++ ++clean_odm-8192c: ++ cd hal/OUTSRC/rtl8192c ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko ++ ++clean: $(clean_more) ++ rm -fr *.mod.c *.mod *.o .*.cmd *.ko *~ ++ rm -fr .tmp_versions ++ rm -fr Module.symvers ; rm -fr Module.markers ; rm -fr modules.order ++ cd core/efuse ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko ++ cd core ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko ++ cd hal/$(RTL871X)/$(HCI_NAME) ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko ++ cd hal/$(RTL871X) ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko ++ cd hal/OUTSRC/$(RTL871X) ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko ++ cd hal/OUTSRC/ ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko ++ cd hal ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko ++ cd os_dep/linux ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko ++ cd os_dep ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko ++endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/clean b/drivers/net/wireless/rtl818x/rtl8189/clean +new file mode 100644 +index 00000000..87664218 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/clean +@@ -0,0 +1,5 @@ ++#!/bin/bash ++rmmod 8192cu ++rmmod 8192ce ++rmmod 8192du ++rmmod 8192de +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/efuse/rtw_efuse.c b/drivers/net/wireless/rtl818x/rtl8189/core/efuse/rtw_efuse.c +new file mode 100644 +index 00000000..d7307b48 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/efuse/rtw_efuse.c +@@ -0,0 +1,1283 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_EFUSE_C_ ++ ++#include ++#include ++#include ++ ++#include ++ ++ ++ ++/*------------------------Define local variable------------------------------*/ ++u8 fakeEfuseBank=0; ++u32 fakeEfuseUsedBytes=0; ++u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE]={0}; ++u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN]={0}; ++u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN]={0}; ++ ++u32 BTEfuseUsedBytes=0; ++u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN]={0}; ++u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN]={0}; ++ ++u32 fakeBTEfuseUsedBytes=0; ++u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN]={0}; ++u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN]={0}; ++/*------------------------Define local variable------------------------------*/ ++ ++//------------------------------------------------------------------------------ ++#define REG_EFUSE_CTRL 0x0030 ++#define EFUSE_CTRL REG_EFUSE_CTRL // E-Fuse Control. ++//------------------------------------------------------------------------------ ++ ++BOOLEAN ++Efuse_Read1ByteFromFakeContent( ++ IN PADAPTER pAdapter, ++ IN u16 Offset, ++ IN OUT u8 *Value ); ++BOOLEAN ++Efuse_Read1ByteFromFakeContent( ++ IN PADAPTER pAdapter, ++ IN u16 Offset, ++ IN OUT u8 *Value ) ++{ ++ if(Offset >= EFUSE_MAX_HW_SIZE) ++ { ++ return _FALSE; ++ } ++ //DbgPrint("Read fake content, offset = %d\n", Offset); ++ if(fakeEfuseBank == 0) ++ *Value = fakeEfuseContent[Offset]; ++ else ++ *Value = fakeBTEfuseContent[fakeEfuseBank-1][Offset]; ++ return _TRUE; ++} ++ ++BOOLEAN ++Efuse_Write1ByteToFakeContent( ++ IN PADAPTER pAdapter, ++ IN u16 Offset, ++ IN u8 Value ); ++BOOLEAN ++Efuse_Write1ByteToFakeContent( ++ IN PADAPTER pAdapter, ++ IN u16 Offset, ++ IN u8 Value ) ++{ ++ if(Offset >= EFUSE_MAX_HW_SIZE) ++ { ++ return _FALSE; ++ } ++ if(fakeEfuseBank == 0) ++ fakeEfuseContent[Offset] = Value; ++ else ++ { ++ fakeBTEfuseContent[fakeEfuseBank-1][Offset] = Value; ++ } ++ return _TRUE; ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: Efuse_PowerSwitch ++ * ++ * Overview: When we want to enable write operation, we should change to ++ * pwr on state. When we stop write, we should switch to 500k mode ++ * and disable LDO 2.5V. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/17/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++VOID ++Efuse_PowerSwitch( ++ IN PADAPTER pAdapter, ++ IN u8 bWrite, ++ IN u8 PwrState) ++{ ++ pAdapter->HalFunc.EfusePowerSwitch(pAdapter, bWrite, PwrState); ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: efuse_GetCurrentSize ++ * ++ * Overview: Get current efuse size!!! ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/16/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++u16 ++Efuse_GetCurrentSize( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN BOOLEAN bPseudoTest) ++{ ++ u16 ret=0; ++ ++ ret = pAdapter->HalFunc.EfuseGetCurrentSize(pAdapter, efuseType, bPseudoTest); ++ ++ return ret; ++} ++ ++/* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */ ++u8 ++Efuse_CalculateWordCnts(IN u8 word_en) ++{ ++ u8 word_cnts = 0; ++ if(!(word_en & BIT(0))) word_cnts++; // 0 : write enable ++ if(!(word_en & BIT(1))) word_cnts++; ++ if(!(word_en & BIT(2))) word_cnts++; ++ if(!(word_en & BIT(3))) word_cnts++; ++ return word_cnts; ++} ++ ++// ++// Description: ++// Execute E-Fuse read byte operation. ++// Refered from SD1 Richard. ++// ++// Assumption: ++// 1. Boot from E-Fuse and successfully auto-load. ++// 2. PASSIVE_LEVEL (USB interface) ++// ++// Created by Roger, 2008.10.21. ++// ++VOID ++ReadEFuseByte( ++ PADAPTER Adapter, ++ u16 _offset, ++ u8 *pbuf, ++ IN BOOLEAN bPseudoTest) ++{ ++ u32 value32; ++ u8 readbyte; ++ u16 retry; ++ //u32 start=rtw_get_current_time(); ++ ++ if(bPseudoTest) ++ { ++ Efuse_Read1ByteFromFakeContent(Adapter, _offset, pbuf); ++ return; ++ } ++ ++ //Write Address ++ rtw_write8(Adapter, EFUSE_CTRL+1, (_offset & 0xff)); ++ readbyte = rtw_read8(Adapter, EFUSE_CTRL+2); ++ rtw_write8(Adapter, EFUSE_CTRL+2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); ++ ++ //Write bit 32 0 ++ readbyte = rtw_read8(Adapter, EFUSE_CTRL+3); ++ rtw_write8(Adapter, EFUSE_CTRL+3, (readbyte & 0x7f)); ++ ++ //Check bit 32 read-ready ++ retry = 0; ++ value32 = rtw_read32(Adapter, EFUSE_CTRL); ++ //while(!(((value32 >> 24) & 0xff) & 0x80) && (retry<10)) ++ while(!(((value32 >> 24) & 0xff) & 0x80) && (retry<10000)) ++ { ++ value32 = rtw_read32(Adapter, EFUSE_CTRL); ++ retry++; ++ } ++ ++ // 20100205 Joseph: Add delay suggested by SD1 Victor. ++ // This fix the problem that Efuse read error in high temperature condition. ++ // Designer says that there shall be some delay after ready bit is set, or the ++ // result will always stay on last data we read. ++ rtw_udelay_os(50); ++ value32 = rtw_read32(Adapter, EFUSE_CTRL); ++ ++ *pbuf = (u8)(value32 & 0xff); ++ //DBG_871X("ReadEFuseByte _offset:%08u, in %d ms\n",_offset ,rtw_get_passing_time_ms(start)); ++ ++} ++ ++ ++// ++// Description: ++// 1. Execute E-Fuse read byte operation according as map offset and ++// save to E-Fuse table. ++// 2. Refered from SD1 Richard. ++// ++// Assumption: ++// 1. Boot from E-Fuse and successfully auto-load. ++// 2. PASSIVE_LEVEL (USB interface) ++// ++// Created by Roger, 2008.10.21. ++// ++// 2008/12/12 MH 1. Reorganize code flow and reserve bytes. and add description. ++// 2. Add efuse utilization collect. ++// 2008/12/22 MH Read Efuse must check if we write section 1 data again!!! Sec1 ++// write addr must be after sec5. ++// ++ ++VOID ++efuse_ReadEFuse( ++ PADAPTER Adapter, ++ u8 efuseType, ++ u16 _offset, ++ u16 _size_byte, ++ u8 *pbuf, ++ IN BOOLEAN bPseudoTest ++ ); ++VOID ++efuse_ReadEFuse( ++ PADAPTER Adapter, ++ u8 efuseType, ++ u16 _offset, ++ u16 _size_byte, ++ u8 *pbuf, ++ IN BOOLEAN bPseudoTest ++ ) ++{ ++ Adapter->HalFunc.ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest); ++} ++ ++VOID ++EFUSE_GetEfuseDefinition( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN u8 type, ++ OUT void *pOut, ++ IN BOOLEAN bPseudoTest ++ ) ++{ ++ pAdapter->HalFunc.EFUSEGetEfuseDefinition(pAdapter, efuseType, type, pOut, bPseudoTest); ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: EFUSE_Read1Byte ++ * ++ * Overview: Copy from WMAC fot EFUSE read 1 byte. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 09/23/2008 MHC Copy from WMAC. ++ * ++ *---------------------------------------------------------------------------*/ ++u8 ++EFUSE_Read1Byte( ++ IN PADAPTER Adapter, ++ IN u16 Address) ++{ ++ u8 data; ++ u8 Bytetemp = {0x00}; ++ u8 temp = {0x00}; ++ u32 k=0; ++ u16 contentLen=0; ++ ++ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI , TYPE_EFUSE_REAL_CONTENT_LEN, (PVOID)&contentLen, _FALSE); ++ ++ if (Address < contentLen) //E-fuse 512Byte ++ { ++ //Write E-fuse Register address bit0~7 ++ temp = Address & 0xFF; ++ rtw_write8(Adapter, EFUSE_CTRL+1, temp); ++ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2); ++ //Write E-fuse Register address bit8~9 ++ temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC); ++ rtw_write8(Adapter, EFUSE_CTRL+2, temp); ++ ++ //Write 0x30[31]=0 ++ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); ++ temp = Bytetemp & 0x7F; ++ rtw_write8(Adapter, EFUSE_CTRL+3, temp); ++ ++ //Wait Write-ready (0x30[31]=1) ++ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); ++ while(!(Bytetemp & 0x80)) ++ { ++ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); ++ k++; ++ if(k==1000) ++ { ++ k=0; ++ break; ++ } ++ } ++ data=rtw_read8(Adapter, EFUSE_CTRL); ++ return data; ++ } ++ else ++ return 0xFF; ++ ++}/* EFUSE_Read1Byte */ ++ ++/*----------------------------------------------------------------------------- ++ * Function: EFUSE_Write1Byte ++ * ++ * Overview: Copy from WMAC fot EFUSE write 1 byte. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 09/23/2008 MHC Copy from WMAC. ++ * ++ *---------------------------------------------------------------------------*/ ++ ++void ++EFUSE_Write1Byte( ++ IN PADAPTER Adapter, ++ IN u16 Address, ++ IN u8 Value); ++void ++EFUSE_Write1Byte( ++ IN PADAPTER Adapter, ++ IN u16 Address, ++ IN u8 Value) ++{ ++ u8 Bytetemp = {0x00}; ++ u8 temp = {0x00}; ++ u32 k=0; ++ u16 contentLen=0; ++ ++ //RT_TRACE(COMP_EFUSE, DBG_LOUD, ("Addr=%x Data =%x\n", Address, Value)); ++ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI , TYPE_EFUSE_REAL_CONTENT_LEN, (PVOID)&contentLen, _FALSE); ++ ++ if( Address < contentLen) //E-fuse 512Byte ++ { ++ rtw_write8(Adapter, EFUSE_CTRL, Value); ++ ++ //Write E-fuse Register address bit0~7 ++ temp = Address & 0xFF; ++ rtw_write8(Adapter, EFUSE_CTRL+1, temp); ++ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2); ++ ++ //Write E-fuse Register address bit8~9 ++ temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC); ++ rtw_write8(Adapter, EFUSE_CTRL+2, temp); ++ ++ //Write 0x30[31]=1 ++ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); ++ temp = Bytetemp | 0x80; ++ rtw_write8(Adapter, EFUSE_CTRL+3, temp); ++ ++ //Wait Write-ready (0x30[31]=0) ++ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); ++ while(Bytetemp & 0x80) ++ { ++ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); ++ k++; ++ if(k==100) ++ { ++ k=0; ++ break; ++ } ++ } ++ } ++}/* EFUSE_Write1Byte */ ++ ++/* 11/16/2008 MH Read one byte from real Efuse. */ ++u8 ++efuse_OneByteRead( ++ IN PADAPTER pAdapter, ++ IN u16 addr, ++ IN u8 *data, ++ IN BOOLEAN bPseudoTest) ++{ ++ u8 tmpidx = 0; ++ u8 bResult; ++ ++ if(bPseudoTest) ++ { ++ bResult = Efuse_Read1ByteFromFakeContent(pAdapter, addr, data); ++ return bResult; ++ } ++ // -----------------e-fuse reg ctrl --------------------------------- ++ //address ++ rtw_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr&0xff)); ++ rtw_write8(pAdapter, EFUSE_CTRL+2, ((u8)((addr>>8) &0x03) ) | ++ (rtw_read8(pAdapter, EFUSE_CTRL+2)&0xFC )); ++ ++ rtw_write8(pAdapter, EFUSE_CTRL+3, 0x72);//read cmd ++ ++ while(!(0x80 &rtw_read8(pAdapter, EFUSE_CTRL+3))&&(tmpidx<100)) ++ { ++ tmpidx++; ++ } ++ if(tmpidx<100) ++ { ++ *data=rtw_read8(pAdapter, EFUSE_CTRL); ++ bResult = _TRUE; ++ } ++ else ++ { ++ *data = 0xff; ++ bResult = _FALSE; ++ } ++ return bResult; ++} ++ ++/* 11/16/2008 MH Write one byte to reald Efuse. */ ++u8 ++efuse_OneByteWrite( ++ IN PADAPTER pAdapter, ++ IN u16 addr, ++ IN u8 data, ++ IN BOOLEAN bPseudoTest) ++{ ++ u8 tmpidx = 0; ++ u8 bResult; ++ ++ if(bPseudoTest) ++ { ++ bResult = Efuse_Write1ByteToFakeContent(pAdapter, addr, data); ++ return bResult; ++ } ++ //RT_TRACE(COMP_EFUSE, DBG_LOUD, ("Addr = %x Data=%x\n", addr, data)); ++ ++ //return 0; ++ ++ // -----------------e-fuse reg ctrl --------------------------------- ++ //address ++ rtw_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr&0xff)); ++ rtw_write8(pAdapter, EFUSE_CTRL+2, ++ (rtw_read8(pAdapter, EFUSE_CTRL+2)&0xFC )|(u8)((addr>>8)&0x03) ); ++ rtw_write8(pAdapter, EFUSE_CTRL, data);//data ++ ++ rtw_write8(pAdapter, EFUSE_CTRL+3, 0xF2);//write cmd ++ ++ while((0x80 & rtw_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx<100) ){ ++ tmpidx++; ++ } ++ ++ if(tmpidx<100) ++ { ++ bResult = _TRUE; ++ } ++ else ++ { ++ bResult = _FALSE; ++ } ++ ++ return bResult; ++} ++ ++int ++Efuse_PgPacketRead( IN PADAPTER pAdapter, ++ IN u8 offset, ++ IN u8 *data, ++ IN BOOLEAN bPseudoTest) ++{ ++ int ret=0; ++ ++ ret = pAdapter->HalFunc.Efuse_PgPacketRead(pAdapter, offset, data, bPseudoTest); ++ ++ return ret; ++} ++ ++int ++Efuse_PgPacketWrite(IN PADAPTER pAdapter, ++ IN u8 offset, ++ IN u8 word_en, ++ IN u8 *data, ++ IN BOOLEAN bPseudoTest) ++{ ++ int ret; ++ ++ ret = pAdapter->HalFunc.Efuse_PgPacketWrite(pAdapter, offset, word_en, data, bPseudoTest); ++ ++ return ret; ++} ++ ++ ++int ++Efuse_PgPacketWrite_BT(IN PADAPTER pAdapter, ++ IN u8 offset, ++ IN u8 word_en, ++ IN u8 *data, ++ IN BOOLEAN bPseudoTest) ++{ ++ int ret; ++ ++ ret = pAdapter->HalFunc.Efuse_PgPacketWrite_BT(pAdapter, offset, word_en, data, bPseudoTest); ++ ++ return ret; ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: efuse_WordEnableDataRead ++ * ++ * Overview: Read allowed word in current efuse section data. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/16/2008 MHC Create Version 0. ++ * 11/21/2008 MHC Fix Write bug when we only enable late word. ++ * ++ *---------------------------------------------------------------------------*/ ++void ++efuse_WordEnableDataRead(IN u8 word_en, ++ IN u8 *sourdata, ++ IN u8 *targetdata) ++{ ++ if (!(word_en&BIT(0))) ++ { ++ targetdata[0] = sourdata[0]; ++ targetdata[1] = sourdata[1]; ++ } ++ if (!(word_en&BIT(1))) ++ { ++ targetdata[2] = sourdata[2]; ++ targetdata[3] = sourdata[3]; ++ } ++ if (!(word_en&BIT(2))) ++ { ++ targetdata[4] = sourdata[4]; ++ targetdata[5] = sourdata[5]; ++ } ++ if (!(word_en&BIT(3))) ++ { ++ targetdata[6] = sourdata[6]; ++ targetdata[7] = sourdata[7]; ++ } ++} ++ ++ ++u8 ++Efuse_WordEnableDataWrite( IN PADAPTER pAdapter, ++ IN u16 efuse_addr, ++ IN u8 word_en, ++ IN u8 *data, ++ IN BOOLEAN bPseudoTest) ++{ ++ u8 ret=0; ++ ++ ret = pAdapter->HalFunc.Efuse_WordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest); ++ ++ return ret; ++} ++ ++static u8 efuse_read8(PADAPTER padapter, u16 address, u8 *value) ++{ ++ return efuse_OneByteRead(padapter,address, value, _FALSE); ++} ++ ++static u8 efuse_write8(PADAPTER padapter, u16 address, u8 *value) ++{ ++ return efuse_OneByteWrite(padapter,address, *value, _FALSE); ++} ++ ++/* ++ * read/wirte raw efuse data ++ */ ++u8 rtw_efuse_access(PADAPTER padapter, u8 bWrite, u16 start_addr, u16 cnts, u8 *data) ++{ ++ int i = 0; ++ u16 real_content_len = 0, max_available_size = 0; ++ u8 res = _FAIL ; ++ u8 (*rw8)(PADAPTER, u16, u8*); ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (PVOID)&real_content_len, _FALSE); ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_available_size, _FALSE); ++ ++ if (start_addr > real_content_len) ++ return _FAIL; ++ ++ if (_TRUE == bWrite) { ++ if ((start_addr + cnts) > max_available_size) ++ return _FAIL; ++ rw8 = &efuse_write8; ++ } else ++ rw8 = &efuse_read8; ++ ++ Efuse_PowerSwitch(padapter, bWrite, _TRUE); ++ ++ // e-fuse one byte read / write ++ for (i = 0; i < cnts; i++) { ++ if (start_addr >= real_content_len) { ++ res = _FAIL; ++ break; ++ } ++ ++ res = rw8(padapter, start_addr++, data++); ++ if (_FAIL == res) break; ++ } ++ ++ Efuse_PowerSwitch(padapter, bWrite, _FALSE); ++ ++ return res; ++} ++//------------------------------------------------------------------------------ ++u16 efuse_GetMaxSize(PADAPTER padapter) ++{ ++ u16 max_size; ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI , TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_size, _FALSE); ++ return max_size; ++} ++//------------------------------------------------------------------------------ ++u8 efuse_GetCurrentSize(PADAPTER padapter, u16 *size) ++{ ++ Efuse_PowerSwitch(padapter, _FALSE, _TRUE); ++ *size = Efuse_GetCurrentSize(padapter, EFUSE_WIFI, _FALSE); ++ Efuse_PowerSwitch(padapter, _FALSE, _FALSE); ++ ++ return _SUCCESS; ++} ++//------------------------------------------------------------------------------ ++u8 rtw_efuse_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data) ++{ ++ u16 mapLen=0; ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE); ++ ++ if ((addr + cnts) > mapLen) ++ return _FAIL; ++ ++ Efuse_PowerSwitch(padapter, _FALSE, _TRUE); ++ ++ efuse_ReadEFuse(padapter, EFUSE_WIFI, addr, cnts, data, _FALSE); ++ ++ Efuse_PowerSwitch(padapter, _FALSE, _FALSE); ++ ++ return _SUCCESS; ++} ++ ++u8 rtw_BT_efuse_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data) ++{ ++ u16 mapLen=0; ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE); ++ ++ if ((addr + cnts) > mapLen) ++ return _FAIL; ++ ++ Efuse_PowerSwitch(padapter, _FALSE, _TRUE); ++ ++ efuse_ReadEFuse(padapter, EFUSE_BT, addr, cnts, data, _FALSE); ++ ++ Efuse_PowerSwitch(padapter, _FALSE, _FALSE); ++ ++ return _SUCCESS; ++} ++//------------------------------------------------------------------------------ ++u8 rtw_efuse_map_write(PADAPTER padapter, u16 addr, u16 cnts, u8 *data) ++{ ++ u8 offset, word_en; ++ u8 *map; ++ u8 newdata[PGPKT_DATA_SIZE]; ++ s32 i, j, idx; ++ u8 ret = _SUCCESS; ++ u16 mapLen=0; ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE); ++ ++ if ((addr + cnts) > mapLen) ++ return _FAIL; ++ ++ map = rtw_zmalloc(mapLen); ++ if(map == NULL){ ++ return _FAIL; ++ } ++ ++ ret = rtw_efuse_map_read(padapter, 0, mapLen, map); ++ if (ret == _FAIL) goto exit; ++ ++ Efuse_PowerSwitch(padapter, _TRUE, _TRUE); ++ ++ offset = (addr >> 3); ++ word_en = 0xF; ++ _rtw_memset(newdata, 0xFF, PGPKT_DATA_SIZE); ++ i = addr & 0x7; // index of one package ++ j = 0; // index of new package ++ idx = 0; // data index ++ ++ if (i & 0x1) { ++ // odd start ++ if (data[idx] != map[addr+idx]) { ++ word_en &= ~BIT(i >> 1); ++ newdata[i-1] = map[addr+idx-1]; ++ newdata[i] = data[idx]; ++ } ++ i++; ++ idx++; ++ } ++ do { ++ for (; i < PGPKT_DATA_SIZE; i += 2) ++ { ++ if (cnts == idx) break; ++ if ((cnts - idx) == 1) { ++ if (data[idx] != map[addr+idx]) { ++ word_en &= ~BIT(i >> 1); ++ newdata[i] = data[idx]; ++ newdata[i+1] = map[addr+idx+1]; ++ } ++ idx++; ++ break; ++ } else { ++ if ((data[idx] != map[addr+idx]) || ++ (data[idx+1] != map[addr+idx+1])) ++ { ++ word_en &= ~BIT(i >> 1); ++ newdata[i] = data[idx]; ++ newdata[i+1] = data[idx + 1]; ++ } ++ idx += 2; ++ } ++ if (idx == cnts) break; ++ } ++ ++ if (word_en != 0xF) { ++ ret = Efuse_PgPacketWrite(padapter, offset, word_en, newdata, _FALSE); ++ DBG_871X("offset=%x \n",offset); ++ DBG_871X("word_en=%x \n",word_en); ++ ++ for(i=0;i mapLen) ++ return _FAIL; ++ ++ map = rtw_zmalloc(mapLen); ++ if(map == NULL){ ++ return _FAIL; ++ } ++ ++ ret = rtw_BT_efuse_map_read(padapter, 0, mapLen, map); ++ if (ret == _FAIL) goto exit; ++ ++ Efuse_PowerSwitch(padapter, _TRUE, _TRUE); ++ ++ offset = (addr >> 3); ++ word_en = 0xF; ++ _rtw_memset(newdata, 0xFF, PGPKT_DATA_SIZE); ++ i = addr & 0x7; // index of one package ++ j = 0; // index of new package ++ idx = 0; // data index ++ ++ if (i & 0x1) { ++ // odd start ++ if (data[idx] != map[addr+idx]) { ++ word_en &= ~BIT(i >> 1); ++ newdata[i-1] = map[addr+idx-1]; ++ newdata[i] = data[idx]; ++ } ++ i++; ++ idx++; ++ } ++ do { ++ for (; i < PGPKT_DATA_SIZE; i += 2) ++ { ++ if (cnts == idx) break; ++ if ((cnts - idx) == 1) { ++ if (data[idx] != map[addr+idx]) { ++ word_en &= ~BIT(i >> 1); ++ newdata[i] = data[idx]; ++ newdata[i+1] = map[addr+idx+1]; ++ } ++ idx++; ++ break; ++ } else { ++ if ((data[idx] != map[addr+idx]) || ++ (data[idx+1] != map[addr+idx+1])) ++ { ++ word_en &= ~BIT(i >> 1); ++ newdata[i] = data[idx]; ++ newdata[i+1] = data[idx + 1]; ++ } ++ idx += 2; ++ } ++ if (idx == cnts) break; ++ } ++ ++ if (word_en != 0xF) ++ { ++ DBG_871X("%s: offset=%#X\n", __FUNCTION__, offset); ++ DBG_871X("%s: word_en=%#X\n", __FUNCTION__, word_en); ++ DBG_871X("%s: data=", __FUNCTION__); ++ for (i=0; iefuse_eeprom_data[Offset]; ++ ++} // EFUSE_ShadowRead1Byte ++ ++//---------------Read Two Bytes ++static VOID ++efuse_ShadowRead2Byte( ++ IN PADAPTER pAdapter, ++ IN u16 Offset, ++ IN OUT u16 *Value) ++{ ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); ++ ++ *Value = pEEPROM->efuse_eeprom_data[Offset]; ++ *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8; ++ ++} // EFUSE_ShadowRead2Byte ++ ++//---------------Read Four Bytes ++static VOID ++efuse_ShadowRead4Byte( ++ IN PADAPTER pAdapter, ++ IN u16 Offset, ++ IN OUT u32 *Value) ++{ ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); ++ ++ *Value = pEEPROM->efuse_eeprom_data[Offset]; ++ *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8; ++ *Value |= pEEPROM->efuse_eeprom_data[Offset+2]<<16; ++ *Value |= pEEPROM->efuse_eeprom_data[Offset+3]<<24; ++ ++} // efuse_ShadowRead4Byte ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: efuse_ShadowWrite1Byte ++ * efuse_ShadowWrite2Byte ++ * efuse_ShadowWrite4Byte ++ * ++ * Overview: Write efuse modify map by one/two/four byte. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/12/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++#ifdef PLATFORM ++static VOID ++efuse_ShadowWrite1Byte( ++ IN PADAPTER pAdapter, ++ IN u16 Offset, ++ IN u8 Value); ++#endif //PLATFORM ++static VOID ++efuse_ShadowWrite1Byte( ++ IN PADAPTER pAdapter, ++ IN u16 Offset, ++ IN u8 Value) ++{ ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); ++ ++ pEEPROM->efuse_eeprom_data[Offset] = Value; ++ ++} // efuse_ShadowWrite1Byte ++ ++//---------------Write Two Bytes ++static VOID ++efuse_ShadowWrite2Byte( ++ IN PADAPTER pAdapter, ++ IN u16 Offset, ++ IN u16 Value) ++{ ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); ++ ++ pEEPROM->efuse_eeprom_data[Offset] = Value&0x00FF; ++ pEEPROM->efuse_eeprom_data[Offset+1] = Value>>8; ++ ++} // efuse_ShadowWrite1Byte ++ ++//---------------Write Four Bytes ++static VOID ++efuse_ShadowWrite4Byte( ++ IN PADAPTER pAdapter, ++ IN u16 Offset, ++ IN u32 Value) ++{ ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); ++ ++ pEEPROM->efuse_eeprom_data[Offset] = (u8)(Value&0x000000FF); ++ pEEPROM->efuse_eeprom_data[Offset+1] = (u8)((Value>>8)&0x0000FF); ++ pEEPROM->efuse_eeprom_data[Offset+2] = (u8)((Value>>16)&0x00FF); ++ pEEPROM->efuse_eeprom_data[Offset+3] = (u8)((Value>>24)&0xFF); ++ ++} // efuse_ShadowWrite1Byte ++ ++/*----------------------------------------------------------------------------- ++ * Function: EFUSE_ShadowMapUpdate ++ * ++ * Overview: Transfer current EFUSE content to shadow init and modify map. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/13/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++void EFUSE_ShadowMapUpdate( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN BOOLEAN bPseudoTest) ++{ ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); ++ u16 mapLen=0; ++ ++ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, bPseudoTest); ++ ++ if (pEEPROM->bautoload_fail_flag == _TRUE) ++ { ++ _rtw_memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen); ++ } ++ else ++ { ++ #ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE ++ if(_SUCCESS != retriveAdaptorInfoFile(pAdapter->registrypriv.adaptor_info_caching_file_path, pEEPROM)) { ++ #endif ++ ++ Efuse_ReadAllMap(pAdapter, efuseType, pEEPROM->efuse_eeprom_data, bPseudoTest); ++ ++ #ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE ++ storeAdaptorInfoFile(pAdapter->registrypriv.adaptor_info_caching_file_path, pEEPROM); ++ } ++ #endif ++ } ++ ++ //PlatformMoveMemory((PVOID)&pHalData->EfuseMap[EFUSE_MODIFY_MAP][0], ++ //(PVOID)&pHalData->EfuseMap[EFUSE_INIT_MAP][0], mapLen); ++}// EFUSE_ShadowMapUpdate ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: EFUSE_ShadowRead ++ * ++ * Overview: Read from efuse init map !!!!! ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/12/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++void ++EFUSE_ShadowRead( ++ IN PADAPTER pAdapter, ++ IN u8 Type, ++ IN u16 Offset, ++ IN OUT u32 *Value ) ++{ ++ if (Type == 1) ++ efuse_ShadowRead1Byte(pAdapter, Offset, (u8 *)Value); ++ else if (Type == 2) ++ efuse_ShadowRead2Byte(pAdapter, Offset, (u16 *)Value); ++ else if (Type == 4) ++ efuse_ShadowRead4Byte(pAdapter, Offset, (u32 *)Value); ++ ++} // EFUSE_ShadowRead ++ ++/*----------------------------------------------------------------------------- ++ * Function: EFUSE_ShadowWrite ++ * ++ * Overview: Write efuse modify map for later update operation to use!!!!! ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/12/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++VOID ++EFUSE_ShadowWrite( ++ IN PADAPTER pAdapter, ++ IN u8 Type, ++ IN u16 Offset, ++ IN OUT u32 Value); ++VOID ++EFUSE_ShadowWrite( ++ IN PADAPTER pAdapter, ++ IN u8 Type, ++ IN u16 Offset, ++ IN OUT u32 Value) ++{ ++#if (MP_DRIVER == 0) ++ return; ++#endif ++ if ( pAdapter->registrypriv.mp_mode == 0) ++ return; ++ ++ ++ if (Type == 1) ++ efuse_ShadowWrite1Byte(pAdapter, Offset, (u8)Value); ++ else if (Type == 2) ++ efuse_ShadowWrite2Byte(pAdapter, Offset, (u16)Value); ++ else if (Type == 4) ++ efuse_ShadowWrite4Byte(pAdapter, Offset, (u32)Value); ++ ++} // EFUSE_ShadowWrite ++ ++VOID ++Efuse_InitSomeVar( ++ IN PADAPTER pAdapter ++ ); ++VOID ++Efuse_InitSomeVar( ++ IN PADAPTER pAdapter ++ ) ++{ ++ u8 i; ++ ++ _rtw_memset((PVOID)&fakeEfuseContent[0], 0xff, EFUSE_MAX_HW_SIZE); ++ _rtw_memset((PVOID)&fakeEfuseInitMap[0], 0xff, EFUSE_MAX_MAP_LEN); ++ _rtw_memset((PVOID)&fakeEfuseModifiedMap[0], 0xff, EFUSE_MAX_MAP_LEN); ++ ++ for(i=0; i ++ ++ int isAdaptorInfoFileValid(void) ++{ ++ return _TRUE; ++} ++ ++int storeAdaptorInfoFile(char *path, struct eeprom_priv * eeprom_priv) ++{ ++ int ret =_SUCCESS; ++ ++ if(path && eeprom_priv) { ++ ret = rtw_store_to_file(path, eeprom_priv->efuse_eeprom_data, EEPROM_MAX_SIZE_512); ++ if(ret == EEPROM_MAX_SIZE) ++ ret = _SUCCESS; ++ else ++ ret = _FAIL; ++ } else { ++ DBG_871X("%s NULL pointer\n",__FUNCTION__); ++ ret = _FAIL; ++ } ++ return ret; ++} ++ ++int retriveAdaptorInfoFile(char *path, struct eeprom_priv * eeprom_priv) ++{ ++ int ret = _SUCCESS; ++ mm_segment_t oldfs; ++ struct file *fp; ++ ++ if(path && eeprom_priv) { ++ ++ ret = rtw_retrive_from_file(path, eeprom_priv->efuse_eeprom_data, EEPROM_MAX_SIZE); ++ ++ if(ret == EEPROM_MAX_SIZE) ++ ret = _SUCCESS; ++ else ++ ret = _FAIL; ++ ++ #if 0 ++ if(isAdaptorInfoFileValid()) { ++ return 0; ++ } else { ++ return _FAIL; ++ } ++ #endif ++ ++ } else { ++ DBG_871X("%s NULL pointer\n",__FUNCTION__); ++ ret = _FAIL; ++ } ++ return ret; ++} ++#endif //CONFIG_ADAPTOR_INFO_CACHING_FILE ++#endif //PLATFORM_LINUX ++ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_ap.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_ap.c +new file mode 100644 +index 00000000..70df9b1a +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_ap.c +@@ -0,0 +1,2960 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_AP_C_ ++ ++#include ++#include ++#include ++#include ++ ++ ++#ifdef CONFIG_AP_MODE ++ ++extern unsigned char RTW_WPA_OUI[]; ++extern unsigned char WMM_OUI[]; ++extern unsigned char WPS_OUI[]; ++extern unsigned char P2P_OUI[]; ++extern unsigned char WFD_OUI[]; ++ ++void init_mlme_ap_info(_adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ ++ ++ _rtw_spinlock_init(&pmlmepriv->bcn_update_lock); ++ ++ //for ACL ++ _rtw_init_queue(&pacl_list->acl_node_q); ++ ++ //pmlmeext->bstart_bss = _FALSE; ++ ++ start_ap_mode(padapter); ++} ++ ++void free_mlme_ap_info(_adapter *padapter) ++{ ++ _irqL irqL; ++ struct sta_info *psta=NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ //stop_ap_mode(padapter); ++ ++ pmlmepriv->update_bcn = _FALSE; ++ pmlmeext->bstart_bss = _FALSE; ++ ++ rtw_sta_flush(padapter); ++ ++ pmlmeinfo->state = _HW_STATE_NOLINK_; ++ ++ //free_assoc_sta_resources ++ rtw_free_all_stainfo(padapter); ++ ++ //free bc/mc sta_info ++ psta = rtw_get_bcmc_stainfo(padapter); ++ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ rtw_free_stainfo(padapter, psta); ++ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ _rtw_spinlock_free(&pmlmepriv->bcn_update_lock); ++ ++} ++ ++static void update_BCNTIM(_adapter *padapter) ++{ ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *pnetwork_mlmeext = &(pmlmeinfo->network); ++ unsigned char *pie = pnetwork_mlmeext->IEs; ++ ++ //DBG_871X("%s\n", __FUNCTION__); ++ ++ //update TIM IE ++ //if(pstapriv->tim_bitmap) ++ if(_TRUE) ++ { ++ u8 *p, *dst_ie, *premainder_ie=NULL, *pbackup_remainder_ie=NULL; ++ u16 tim_bitmap_le; ++ uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen; ++ ++ tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap); ++ ++ p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, _TIM_IE_, &tim_ielen, pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_); ++ if (p != NULL && tim_ielen>0) ++ { ++ tim_ielen += 2; ++ ++ premainder_ie = p+tim_ielen; ++ ++ tim_ie_offset = (sint)(p -pie); ++ ++ remainder_ielen = pnetwork_mlmeext->IELength - tim_ie_offset - tim_ielen; ++ ++ //append TIM IE from dst_ie offset ++ dst_ie = p; ++ } ++ else ++ { ++ tim_ielen = 0; ++ ++ //calucate head_len ++ offset = _FIXED_IE_LENGTH_; ++ ++ /* get ssid_ie len */ ++ p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SSID_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)); ++ if (p != NULL) ++ offset += tmp_len+2; ++ ++ // get supported rates len ++ p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)); ++ if (p != NULL) ++ { ++ offset += tmp_len+2; ++ } ++ ++ //DS Parameter Set IE, len=3 ++ offset += 3; ++ ++ premainder_ie = pie + offset; ++ ++ remainder_ielen = pnetwork_mlmeext->IELength - offset - tim_ielen; ++ ++ //append TIM IE from offset ++ dst_ie = pie + offset; ++ ++ } ++ ++ ++ if(remainder_ielen>0) ++ { ++ pbackup_remainder_ie = rtw_malloc(remainder_ielen); ++ if(pbackup_remainder_ie && premainder_ie) ++ _rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); ++ } ++ ++ *dst_ie++=_TIM_IE_; ++ ++ if((pstapriv->tim_bitmap&0xff00) && (pstapriv->tim_bitmap&0x00fc)) ++ tim_ielen = 5; ++ else ++ tim_ielen = 4; ++ ++ *dst_ie++= tim_ielen; ++ ++ *dst_ie++=0;//DTIM count ++ *dst_ie++=1;//DTIM peroid ++ ++ if(pstapriv->tim_bitmap&BIT(0))//for bc/mc frames ++ *dst_ie++ = BIT(0);//bitmap ctrl ++ else ++ *dst_ie++ = 0; ++ ++ if(tim_ielen==4) ++ { ++ *dst_ie++ = *(u8*)&tim_bitmap_le; ++ } ++ else if(tim_ielen==5) ++ { ++ _rtw_memcpy(dst_ie, &tim_bitmap_le, 2); ++ dst_ie+=2; ++ } ++ ++ //copy remainder IE ++ if(pbackup_remainder_ie) ++ { ++ _rtw_memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen); ++ ++ rtw_mfree(pbackup_remainder_ie, remainder_ielen); ++ } ++ ++ offset = (uint)(dst_ie - pie); ++ pnetwork_mlmeext->IELength = offset + remainder_ielen; ++ ++ } ++ ++#ifndef CONFIG_INTERRUPT_BASED_TXBCN ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ set_tx_beacon_cmd(padapter); ++#endif ++#endif //!CONFIG_INTERRUPT_BASED_TXBCN ++ ++ ++} ++ ++void rtw_add_bcn_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 index, u8 *data, u8 len) ++{ ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ u8 bmatch = _FALSE; ++ u8 *pie = pnetwork->IEs; ++ u8 *p, *dst_ie, *premainder_ie=NULL, *pbackup_remainder_ie=NULL; ++ u32 i, offset, ielen, ie_offset, remainder_ielen = 0; ++ ++ for (i = sizeof(NDIS_802_11_FIXED_IEs); i < pnetwork->IELength;) ++ { ++ pIE = (PNDIS_802_11_VARIABLE_IEs)(pnetwork->IEs + i); ++ ++ if (pIE->ElementID > index) ++ { ++ break; ++ } ++ else if(pIE->ElementID == index) // already exist the same IE ++ { ++ p = (u8 *)pIE; ++ ielen = pIE->Length; ++ bmatch = _TRUE; ++ break; ++ } ++ ++ p = (u8 *)pIE; ++ ielen = pIE->Length; ++ i += (pIE->Length + 2); ++ } ++ ++ if (p != NULL && ielen>0) ++ { ++ ielen += 2; ++ ++ premainder_ie = p+ielen; ++ ++ ie_offset = (sint)(p -pie); ++ ++ remainder_ielen = pnetwork->IELength - ie_offset - ielen; ++ ++ if(bmatch) ++ dst_ie = p; ++ else ++ dst_ie = (p+ielen); ++ } ++ ++ if(remainder_ielen>0) ++ { ++ pbackup_remainder_ie = rtw_malloc(remainder_ielen); ++ if(pbackup_remainder_ie && premainder_ie) ++ _rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); ++ } ++ ++ *dst_ie++=index; ++ *dst_ie++=len; ++ ++ _rtw_memcpy(dst_ie, data, len); ++ dst_ie+=len; ++ ++ //copy remainder IE ++ if(pbackup_remainder_ie) ++ { ++ _rtw_memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen); ++ ++ rtw_mfree(pbackup_remainder_ie, remainder_ielen); ++ } ++ ++ offset = (uint)(dst_ie - pie); ++ pnetwork->IELength = offset + remainder_ielen; ++} ++ ++void rtw_remove_bcn_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 index) ++{ ++ u8 *p, *dst_ie, *premainder_ie=NULL, *pbackup_remainder_ie=NULL; ++ uint offset, ielen, ie_offset, remainder_ielen = 0; ++ u8 *pie = pnetwork->IEs; ++ ++ p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, index, &ielen, pnetwork->IELength - _FIXED_IE_LENGTH_); ++ if (p != NULL && ielen>0) ++ { ++ ielen += 2; ++ ++ premainder_ie = p+ielen; ++ ++ ie_offset = (sint)(p -pie); ++ ++ remainder_ielen = pnetwork->IELength - ie_offset - ielen; ++ ++ dst_ie = p; ++ } ++ else { ++ return; ++ } ++ ++ if(remainder_ielen>0) ++ { ++ pbackup_remainder_ie = rtw_malloc(remainder_ielen); ++ if(pbackup_remainder_ie && premainder_ie) ++ _rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); ++ } ++ ++ //copy remainder IE ++ if(pbackup_remainder_ie) ++ { ++ _rtw_memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen); ++ ++ rtw_mfree(pbackup_remainder_ie, remainder_ielen); ++ } ++ ++ offset = (uint)(dst_ie - pie); ++ pnetwork->IELength = offset + remainder_ielen; ++} ++ ++ ++u8 chk_sta_is_alive(struct sta_info *psta); ++u8 chk_sta_is_alive(struct sta_info *psta) ++{ ++ u8 ret = _FALSE; ++ #ifdef DBG_EXPIRATION_CHK ++ DBG_871X("sta:"MAC_FMT", rssi:%d, rx:"STA_PKTS_FMT", expire_to:%u, %s%ssq_len:%u\n" ++ , MAC_ARG(psta->hwaddr) ++ , psta->rssi_stat.UndecoratedSmoothedPWDB ++ //, STA_RX_PKTS_ARG(psta) ++ , STA_RX_PKTS_DIFF_ARG(psta) ++ , psta->expire_to ++ , psta->state&WIFI_SLEEP_STATE?"PS, ":"" ++ , psta->state&WIFI_STA_ALIVE_CHK_STATE?"SAC, ":"" ++ , psta->sleepq_len ++ ); ++ #endif ++ ++ //if(sta_last_rx_pkts(psta) == sta_rx_pkts(psta)) ++ if((psta->sta_stats.last_rx_data_pkts + psta->sta_stats.last_rx_ctrl_pkts) == (psta->sta_stats.rx_data_pkts + psta->sta_stats.rx_ctrl_pkts)) ++ { ++ #if 0 ++ if(psta->state&WIFI_SLEEP_STATE) ++ ret = _TRUE; ++ #endif ++ } ++ else ++ { ++ ret = _TRUE; ++ } ++ ++ sta_update_last_rx_pkts(psta); ++ ++ return ret; ++} ++ ++void expire_timeout_chk(_adapter *padapter) ++{ ++ _irqL irqL; ++ _list *phead, *plist; ++ u8 updated; ++ struct sta_info *psta=NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 chk_alive_num = 0; ++ char chk_alive_list[NUM_STA]; ++ int i; ++ ++ _enter_critical_bh(&pstapriv->auth_list_lock, &irqL); ++ ++ phead = &pstapriv->auth_list; ++ plist = get_next(phead); ++ ++ //check auth_queue ++ #ifdef DBG_EXPIRATION_CHK ++ if (rtw_end_of_queue_search(phead, plist) == _FALSE) { ++ DBG_871X(FUNC_NDEV_FMT" auth_list, cnt:%u\n" ++ , FUNC_NDEV_ARG(padapter->pnetdev), pstapriv->auth_list_cnt); ++ } ++ #endif ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, auth_list); ++ plist = get_next(plist); ++ ++ ++#ifdef CONFIG_ATMEL_RC_PATCH ++ if (_TRUE == _rtw_memcmp((void *)(pstapriv->atmel_rc_pattern), (void *)(psta->hwaddr), ETH_ALEN)) ++ continue; ++ if (psta->flag_atmel_rc) ++ continue; ++#endif ++ if(psta->expire_to>0) ++ { ++ psta->expire_to--; ++ if (psta->expire_to == 0) ++ { ++ rtw_list_delete(&psta->auth_list); ++ pstapriv->auth_list_cnt--; ++ ++ DBG_871X("auth expire %02X%02X%02X%02X%02X%02X\n", ++ psta->hwaddr[0],psta->hwaddr[1],psta->hwaddr[2],psta->hwaddr[3],psta->hwaddr[4],psta->hwaddr[5]); ++ ++ _exit_critical_bh(&pstapriv->auth_list_lock, &irqL); ++ ++ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ rtw_free_stainfo(padapter, psta); ++ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ ++ _enter_critical_bh(&pstapriv->auth_list_lock, &irqL); ++ } ++ } ++ ++ } ++ ++ _exit_critical_bh(&pstapriv->auth_list_lock, &irqL); ++ ++ psta = NULL; ++ ++ ++ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ ++ //check asoc_queue ++ #ifdef DBG_EXPIRATION_CHK ++ if (rtw_end_of_queue_search(phead, plist) == _FALSE) { ++ DBG_871X(FUNC_NDEV_FMT" asoc_list, cnt:%u\n" ++ , FUNC_NDEV_ARG(padapter->pnetdev), pstapriv->asoc_list_cnt); ++ } ++ #endif ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ plist = get_next(plist); ++#ifdef CONFIG_ATMEL_RC_PATCH ++ DBG_871X("%s:%d psta=%p, %02x,%02x||%02x,%02x \n\n", __func__, __LINE__, ++ psta,pstapriv->atmel_rc_pattern[0], pstapriv->atmel_rc_pattern[5], psta->hwaddr[0], psta->hwaddr[5]); ++ if (_TRUE == _rtw_memcmp((void *)pstapriv->atmel_rc_pattern, (void *)(psta->hwaddr), ETH_ALEN)) ++ continue; ++ if (psta->flag_atmel_rc) ++ continue; ++ DBG_871X("%s: debug line:%d \n", __func__, __LINE__); ++#endif ++ if (chk_sta_is_alive(psta) || !psta->expire_to) { ++ psta->expire_to = pstapriv->expire_to; ++ psta->keep_alive_trycnt = 0; ++ #ifdef CONFIG_TX_MCAST2UNI ++ psta->under_exist_checking = 0; ++ #endif // CONFIG_TX_MCAST2UNI ++ } else { ++ psta->expire_to--; ++ } ++ ++#ifndef CONFIG_ACTIVE_KEEP_ALIVE_CHECK ++#ifdef CONFIG_TX_MCAST2UNI ++#ifdef CONFIG_80211N_HT ++ if ( (psta->flags & WLAN_STA_HT) && (psta->htpriv.agg_enable_bitmap || psta->under_exist_checking) ) { ++ // check sta by delba(addba) for 11n STA ++ // ToDo: use CCX report to check for all STAs ++ //DBG_871X("asoc check by DELBA/ADDBA! (pstapriv->expire_to=%d s)(psta->expire_to=%d s), [%02x, %d]\n", pstapriv->expire_to*2, psta->expire_to*2, psta->htpriv.agg_enable_bitmap, psta->under_exist_checking); ++ ++ if ( psta->expire_to <= (pstapriv->expire_to - 50 ) ) { ++ DBG_871X("asoc expire by DELBA/ADDBA! (%d s)\n", (pstapriv->expire_to-psta->expire_to)*2); ++ psta->under_exist_checking = 0; ++ psta->expire_to = 0; ++ } else if ( psta->expire_to <= (pstapriv->expire_to - 3) && (psta->under_exist_checking==0)) { ++ DBG_871X("asoc check by DELBA/ADDBA! (%d s)\n", (pstapriv->expire_to-psta->expire_to)*2); ++ psta->under_exist_checking = 1; ++ //tear down TX AMPDU ++ send_delba(padapter, 1, psta->hwaddr);// // originator ++ psta->htpriv.agg_enable_bitmap = 0x0;//reset ++ psta->htpriv.candidate_tid_bitmap = 0x0;//reset ++ } ++ } ++#endif //CONFIG_80211N_HT ++#endif // CONFIG_TX_MCAST2UNI ++#endif //CONFIG_ACTIVE_KEEP_ALIVE_CHECK ++ ++ if (psta->expire_to <= 0) ++ { ++ #ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ if (padapter->registrypriv.wifi_spec == 1) ++ { ++ psta->expire_to = pstapriv->expire_to; ++ continue; ++ } ++ ++ if (psta->state & WIFI_SLEEP_STATE) { ++ if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) { ++ //to check if alive by another methods if staion is at ps mode. ++ psta->expire_to = pstapriv->expire_to; ++ psta->state |= WIFI_STA_ALIVE_CHK_STATE; ++ ++ //DBG_871X("alive chk, sta:" MAC_FMT " is at ps mode!\n", MAC_ARG(psta->hwaddr)); ++ ++ //to update bcn with tim_bitmap for this station ++ pstapriv->tim_bitmap |= BIT(psta->aid); ++ update_beacon(padapter, _TIM_IE_, NULL, _FALSE); ++ ++ if(!pmlmeext->active_keep_alive_check) ++ continue; ++ } ++ } ++ ++ if (pmlmeext->active_keep_alive_check) { ++ int stainfo_offset; ++ ++ stainfo_offset = rtw_stainfo_offset(pstapriv, psta); ++ if (stainfo_offset_valid(stainfo_offset)) { ++ chk_alive_list[chk_alive_num++] = stainfo_offset; ++ } ++ ++ continue; ++ } ++ #endif /* CONFIG_ACTIVE_KEEP_ALIVE_CHECK */ ++ ++ rtw_list_delete(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ ++ DBG_871X("asoc expire "MAC_FMT", state=0x%x\n", MAC_ARG(psta->hwaddr), psta->state); ++ updated = ap_free_sta(padapter, psta, _FALSE, WLAN_REASON_DEAUTH_LEAVING); ++ } ++ else ++ { ++ /* TODO: Aging mechanism to digest frames in sleep_q to avoid running out of xmitframe */ ++ if (psta->sleepq_len > (NR_XMITFRAME/pstapriv->asoc_list_cnt) ++ && padapter->xmitpriv.free_xmitframe_cnt < ((NR_XMITFRAME/pstapriv->asoc_list_cnt)/2) ++ ){ ++ DBG_871X("%s sta:"MAC_FMT", sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", __func__ ++ , MAC_ARG(psta->hwaddr) ++ , psta->sleepq_len, padapter->xmitpriv.free_xmitframe_cnt, pstapriv->asoc_list_cnt); ++ wakeup_sta_to_xmit(padapter, psta); ++ } ++ } ++ } ++ ++ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++#ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK ++if (chk_alive_num) { ++ ++ u8 backup_oper_channel=0; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ /* switch to correct channel of current network before issue keep-alive frames */ ++ if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) { ++ backup_oper_channel = rtw_get_oper_ch(padapter); ++ SelectChannel(padapter, pmlmeext->cur_channel); ++ } ++ ++ /* issue null data to check sta alive*/ ++ for (i = 0; i < chk_alive_num; i++) { ++ ++ int ret = _FAIL; ++ ++ psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); ++#ifdef CONFIG_ATMEL_RC_PATCH ++ if (_TRUE == _rtw_memcmp( pstapriv->atmel_rc_pattern, psta->hwaddr, ETH_ALEN)) ++ continue; ++ if (psta->flag_atmel_rc) ++ continue; ++#endif ++ if(!(psta->state &_FW_LINKED)) ++ continue; ++ ++ if (psta->state & WIFI_SLEEP_STATE) ++ ret = issue_nulldata(padapter, psta->hwaddr, 0, 1, 50); ++ else ++ ret = issue_nulldata(padapter, psta->hwaddr, 0, 3, 50); ++ ++ psta->keep_alive_trycnt++; ++ if (ret == _SUCCESS) ++ { ++ DBG_871X("asoc check, sta(" MAC_FMT ") is alive\n", MAC_ARG(psta->hwaddr)); ++ psta->expire_to = pstapriv->expire_to; ++ psta->keep_alive_trycnt = 0; ++ continue; ++ } ++ else if (psta->keep_alive_trycnt <= 3) ++ { ++ DBG_871X("ack check for asoc expire, keep_alive_trycnt=%d\n", psta->keep_alive_trycnt); ++ psta->expire_to = 1; ++ continue; ++ } ++ ++ psta->keep_alive_trycnt = 0; ++ ++ DBG_871X("asoc expire "MAC_FMT", state=0x%x\n", MAC_ARG(psta->hwaddr), psta->state); ++ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ if (rtw_is_list_empty(&psta->asoc_list)==_FALSE) { ++ rtw_list_delete(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ updated = ap_free_sta(padapter, psta, _FALSE, WLAN_REASON_DEAUTH_LEAVING); ++ } ++ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ } ++ ++ if (backup_oper_channel>0) /* back to the original operation channel */ ++ SelectChannel(padapter, backup_oper_channel); ++} ++#endif /* CONFIG_ACTIVE_KEEP_ALIVE_CHECK */ ++ ++ associated_clients_update(padapter, updated); ++} ++ ++void add_RATid(_adapter *padapter, struct sta_info *psta, u8 rssi_level) ++{ ++ int i; ++ u8 rf_type; ++ u32 init_rate=0; ++ unsigned char sta_band = 0, raid, shortGIrate = _FALSE; ++ unsigned char limit; ++ unsigned int tx_ra_bitmap=0; ++ struct ht_priv *psta_ht = NULL; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ WLAN_BSSID_EX *pcur_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; ++ ++#ifdef CONFIG_80211N_HT ++ if(psta) ++ psta_ht = &psta->htpriv; ++ else ++ return; ++#endif //CONFIG_80211N_HT ++ ++ if(!(psta->state & _FW_LINKED)) ++ return; ++ ++ //b/g mode ra_bitmap ++ for (i=0; ibssrateset); i++) ++ { ++ if (psta->bssrateset[i]) ++ tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i]&0x7f); ++ } ++#ifdef CONFIG_80211N_HT ++ //n mode ra_bitmap ++ if(psta_ht->ht_option) ++ { ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ if(rf_type == RF_2T2R) ++ limit=16;// 2R ++ else ++ limit=8;// 1R ++ ++ for (i=0; iht_cap.supp_mcs_set[i/8] & BIT(i%8)) ++ tx_ra_bitmap |= BIT(i+12); ++ } ++ ++ //max short GI rate ++ shortGIrate = psta_ht->sgi; ++ } ++#endif //CONFIG_80211N_HT ++ ++#if 0//gtest ++ if(get_rf_mimo_mode(padapter) == RTL8712_RF_2T2R) ++ { ++ //is this a 2r STA? ++ if((pstat->tx_ra_bitmap & 0x0ff00000) != 0 && !(priv->pshare->has_2r_sta & BIT(pstat->aid))) ++ { ++ priv->pshare->has_2r_sta |= BIT(pstat->aid); ++ if(rtw_read16(padapter, 0x102501f6) != 0xffff) ++ { ++ rtw_write16(padapter, 0x102501f6, 0xffff); ++ reset_1r_sta_RA(priv, 0xffff); ++ Switch_1SS_Antenna(priv, 3); ++ } ++ } ++ else// bg or 1R STA? ++ { ++ if((priv->pmib->dot11BssType.net_work_type & WIRELESS_11N) && pstat->ht_cap_len && priv->pshare->has_2r_sta == 0) ++ { ++ if(rtw_read16(padapter, 0x102501f6) != 0x7777) ++ { // MCS7 SGI ++ rtw_write16(padapter, 0x102501f6,0x7777); ++ reset_1r_sta_RA(priv, 0x7777); ++ Switch_1SS_Antenna(priv, 2); ++ } ++ } ++ } ++ ++ } ++ ++ if ((pstat->rssi_level < 1) || (pstat->rssi_level > 3)) ++ { ++ if (pstat->rssi >= priv->pshare->rf_ft_var.raGoDownUpper) ++ pstat->rssi_level = 1; ++ else if ((pstat->rssi >= priv->pshare->rf_ft_var.raGoDown20MLower) || ++ ((priv->pshare->is_40m_bw) && (pstat->ht_cap_len) && ++ (pstat->rssi >= priv->pshare->rf_ft_var.raGoDown40MLower) && ++ (pstat->ht_cap_buf.ht_cap_info & cpu_to_le16(_HTCAP_SUPPORT_CH_WDTH_)))) ++ pstat->rssi_level = 2; ++ else ++ pstat->rssi_level = 3; ++ } ++ ++ // rate adaptive by rssi ++ if ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11N) && pstat->ht_cap_len) ++ { ++ if ((get_rf_mimo_mode(priv) == MIMO_1T2R) || (get_rf_mimo_mode(priv) == MIMO_1T1R)) ++ { ++ switch (pstat->rssi_level) { ++ case 1: ++ pstat->tx_ra_bitmap &= 0x100f0000; ++ break; ++ case 2: ++ pstat->tx_ra_bitmap &= 0x100ff000; ++ break; ++ case 3: ++ if (priv->pshare->is_40m_bw) ++ pstat->tx_ra_bitmap &= 0x100ff005; ++ else ++ pstat->tx_ra_bitmap &= 0x100ff001; ++ ++ break; ++ } ++ } ++ else ++ { ++ switch (pstat->rssi_level) { ++ case 1: ++ pstat->tx_ra_bitmap &= 0x1f0f0000; ++ break; ++ case 2: ++ pstat->tx_ra_bitmap &= 0x1f0ff000; ++ break; ++ case 3: ++ if (priv->pshare->is_40m_bw) ++ pstat->tx_ra_bitmap &= 0x000ff005; ++ else ++ pstat->tx_ra_bitmap &= 0x000ff001; ++ ++ break; ++ } ++ ++ // Don't need to mask high rates due to new rate adaptive parameters ++ //if (pstat->is_broadcom_sta) // use MCS12 as the highest rate vs. Broadcom sta ++ // pstat->tx_ra_bitmap &= 0x81ffffff; ++ ++ // NIC driver will report not supporting MCS15 and MCS14 in asoc req ++ //if (pstat->is_rtl8190_sta && !pstat->is_2t_mimo_sta) ++ // pstat->tx_ra_bitmap &= 0x83ffffff; // if Realtek 1x2 sta, don't use MCS15 and MCS14 ++ } ++ } ++ else if ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11G) && isErpSta(pstat)) ++ { ++ switch (pstat->rssi_level) { ++ case 1: ++ pstat->tx_ra_bitmap &= 0x00000f00; ++ break; ++ case 2: ++ pstat->tx_ra_bitmap &= 0x00000ff0; ++ break; ++ case 3: ++ pstat->tx_ra_bitmap &= 0x00000ff5; ++ break; ++ } ++ } ++ else ++ { ++ pstat->tx_ra_bitmap &= 0x0000000d; ++ } ++ ++ // disable tx short GI when station cannot rx MCS15(AP is 2T2R) ++ // disable tx short GI when station cannot rx MCS7 (AP is 1T2R or 1T1R) ++ // if there is only 1r STA and we are 2T2R, DO NOT mask SGI rate ++ if ((!(pstat->tx_ra_bitmap & 0x8000000) && (priv->pshare->has_2r_sta > 0) && (get_rf_mimo_mode(padapter) == RTL8712_RF_2T2R)) || ++ (!(pstat->tx_ra_bitmap & 0x80000) && (get_rf_mimo_mode(padapter) != RTL8712_RF_2T2R))) ++ { ++ pstat->tx_ra_bitmap &= ~BIT(28); ++ } ++#endif ++ ++ if ( pcur_network->Configuration.DSConfig > 14 ) { ++ // 5G band ++ if (tx_ra_bitmap & 0xffff000) ++ sta_band |= WIRELESS_11_5N ; ++ ++ if (tx_ra_bitmap & 0xff0) ++ sta_band |= WIRELESS_11A; ++ ++ } else { ++ if (tx_ra_bitmap & 0xffff000) ++ sta_band |= WIRELESS_11_24N; ++ ++ if (tx_ra_bitmap & 0xff0) ++ sta_band |= WIRELESS_11G; ++ ++ if (tx_ra_bitmap & 0x0f) ++ sta_band |= WIRELESS_11B; ++ } ++ ++ psta->wireless_mode = sta_band; ++ ++ raid = networktype_to_raid(sta_band); ++ init_rate = get_highest_rate_idx(tx_ra_bitmap&0x0fffffff)&0x3f; ++ ++ if (psta->aid < NUM_STA) ++ { ++ u8 arg = 0; ++ ++ arg = psta->mac_id&0x1f; ++ ++ arg |= BIT(7);//support entry 2~31 ++ ++ if (shortGIrate==_TRUE) ++ arg |= BIT(5); ++ ++ tx_ra_bitmap |= ((raid<<28)&0xf0000000); ++ ++ DBG_871X("%s=> mac_id:%d , raid:%d , bitmap=0x%x, arg=0x%x\n", ++ __FUNCTION__ , psta->mac_id, raid ,tx_ra_bitmap, arg); ++ ++ //bitmap[0:27] = tx_rate_bitmap ++ //bitmap[28:31]= Rate Adaptive id ++ //arg[0:4] = macid ++ //arg[5] = Short GI ++ rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, rssi_level); ++ ++ ++ if (shortGIrate==_TRUE) ++ init_rate |= BIT(6); ++ ++ //set ra_id, init_rate ++ psta->raid = raid; ++ psta->init_rate = init_rate; ++ ++ } ++ else ++ { ++ DBG_871X("station aid %d exceed the max number\n", psta->aid); ++ } ++ ++} ++ ++void update_bmc_sta(_adapter *padapter) ++{ ++ _irqL irqL; ++ u32 init_rate=0; ++ unsigned char network_type, raid; ++ int i, supportRateNum = 0; ++ unsigned int tx_ra_bitmap=0; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ WLAN_BSSID_EX *pcur_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; ++ struct sta_info *psta = rtw_get_bcmc_stainfo(padapter); ++ ++ if(psta) ++ { ++ psta->aid = 0;//default set to 0 ++ //psta->mac_id = psta->aid+4; ++ psta->mac_id = psta->aid + 1; ++ ++ psta->qos_option = 0; ++#ifdef CONFIG_80211N_HT ++ psta->htpriv.ht_option = _FALSE; ++#endif //CONFIG_80211N_HT ++ ++ psta->ieee8021x_blocked = 0; ++ ++ _rtw_memset((void*)&psta->sta_stats, 0, sizeof(struct stainfo_stats)); ++ ++ //psta->dot118021XPrivacy = _NO_PRIVACY_;//!!! remove it, because it has been set before this. ++ ++ ++ ++ //prepare for add_RATid ++ supportRateNum = rtw_get_rateset_len((u8*)&pcur_network->SupportedRates); ++ network_type = rtw_check_network_type((u8*)&pcur_network->SupportedRates, supportRateNum, 1); ++ ++ _rtw_memcpy(psta->bssrateset, &pcur_network->SupportedRates, supportRateNum); ++ psta->bssratelen = supportRateNum; ++ ++ //b/g mode ra_bitmap ++ for (i=0; ibssrateset[i]) ++ tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i]&0x7f); ++ } ++ ++ if ( pcur_network->Configuration.DSConfig > 14 ) { ++ //force to A mode. 5G doesn't support CCK rates ++ network_type = WIRELESS_11A; ++ tx_ra_bitmap = 0x150; // 6, 12, 24 Mbps ++ } else { ++ //force to b mode ++ network_type = WIRELESS_11B; ++ tx_ra_bitmap = 0xf; ++ } ++ ++ //tx_ra_bitmap = update_basic_rate(pcur_network->SupportedRates, supportRateNum); ++ ++ raid = networktype_to_raid(network_type); ++ init_rate = get_highest_rate_idx(tx_ra_bitmap&0x0fffffff)&0x3f; ++ ++ //DBG_871X("Add id %d val %08x to ratr for bmc sta\n", psta->aid, tx_ra_bitmap); ++ //ap mode ++ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, _TRUE); ++ ++ //if(pHalData->fw_ractrl == _TRUE) ++ { ++ u8 arg = 0; ++ ++ arg = psta->mac_id&0x1f; ++ ++ arg |= BIT(7); ++ ++ //if (shortGIrate==_TRUE) ++ // arg |= BIT(5); ++ ++ tx_ra_bitmap |= ((raid<<28)&0xf0000000); ++ ++ DBG_871X("update_bmc_sta, mask=0x%x, arg=0x%x\n", tx_ra_bitmap, arg); ++ ++ //bitmap[0:27] = tx_rate_bitmap ++ //bitmap[28:31]= Rate Adaptive id ++ //arg[0:4] = macid ++ //arg[5] = Short GI ++ rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, 0); ++ ++ } ++ ++ //set ra_id, init_rate ++ psta->raid = raid; ++ psta->init_rate = init_rate; ++ ++ rtw_sta_media_status_rpt(padapter, psta, 1); ++ ++ _enter_critical_bh(&psta->lock, &irqL); ++ psta->state = _FW_LINKED; ++ _exit_critical_bh(&psta->lock, &irqL); ++ ++ } ++ else ++ { ++ DBG_871X("add_RATid_bmc_sta error!\n"); ++ } ++ ++} ++ ++//notes: ++//AID: 1~MAX for sta and 0 for bc/mc in ap/adhoc mode ++//MAC_ID = AID+1 for sta in ap/adhoc mode ++//MAC_ID = 1 for bc/mc for sta/ap/adhoc ++//MAC_ID = 0 for bssid for sta/ap/adhoc ++//CAM_ID = //0~3 for default key, cmd_id=macid + 3, macid=aid+1; ++ ++void update_sta_info_apmode(_adapter *padapter, struct sta_info *psta) ++{ ++ _irqL irqL; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++#ifdef CONFIG_80211N_HT ++ struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv; ++ struct ht_priv *phtpriv_sta = &psta->htpriv; ++#endif //CONFIG_80211N_HT ++ //set intf_tag to if1 ++ //psta->intf_tag = 0; ++ ++ //psta->mac_id = psta->aid+4; ++ psta->mac_id = psta->aid+1; ++ DBG_871X("%s\n",__FUNCTION__); ++ ++ //ap mode ++ rtw_hal_set_odm_var(padapter,HAL_ODM_STA_INFO,psta,_TRUE); ++ ++ if(psecuritypriv->dot11AuthAlgrthm==dot11AuthAlgrthm_8021X) ++ psta->ieee8021x_blocked = _TRUE; ++ else ++ psta->ieee8021x_blocked = _FALSE; ++ ++ ++ //update sta's cap ++ ++ //ERP ++ VCS_update(padapter, psta); ++#ifdef CONFIG_80211N_HT ++ //HT related cap ++ if(phtpriv_sta->ht_option) ++ { ++ //check if sta supports rx ampdu ++ phtpriv_sta->ampdu_enable = phtpriv_ap->ampdu_enable; ++ ++ //check if sta support s Short GI ++ if((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_20|IEEE80211_HT_CAP_SGI_40)) ++ { ++ phtpriv_sta->sgi = _TRUE; ++ } ++ ++ // bwmode ++ if((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH)) ++ { ++ //phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_40; ++ phtpriv_sta->bwmode = pmlmeext->cur_bwmode; ++ phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset; ++ ++ } ++ ++ psta->qos_option = _TRUE; ++ ++ } ++ else ++ { ++ phtpriv_sta->ampdu_enable = _FALSE; ++ ++ phtpriv_sta->sgi = _FALSE; ++ phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_20; ++ phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ } ++ ++ //Rx AMPDU ++ send_delba(padapter, 0, psta->hwaddr);// recipient ++ ++ //TX AMPDU ++ send_delba(padapter, 1, psta->hwaddr);// // originator ++ phtpriv_sta->agg_enable_bitmap = 0x0;//reset ++ phtpriv_sta->candidate_tid_bitmap = 0x0;//reset ++#endif //CONFIG_80211N_HT ++ ++ //todo: init other variables ++ ++ _rtw_memset((void*)&psta->sta_stats, 0, sizeof(struct stainfo_stats)); ++ ++ ++ //add ratid ++ //add_RATid(padapter, psta);//move to ap_sta_info_defer_update() ++ ++ ++ _enter_critical_bh(&psta->lock, &irqL); ++ psta->state |= _FW_LINKED; ++ _exit_critical_bh(&psta->lock, &irqL); ++ ++ ++} ++ ++static void update_hw_ht_param(_adapter *padapter) ++{ ++ unsigned char max_AMPDU_len; ++ unsigned char min_MPDU_spacing; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ ++ //handle A-MPDU parameter field ++ /* ++ AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k ++ AMPDU_para [4:2]:Min MPDU Start Spacing ++ */ ++ max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; ++ ++ min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); ++ ++ // ++ // Config SM Power Save setting ++ // ++ pmlmeinfo->SM_PS = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2; ++ if(pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) ++ { ++ /*u8 i; ++ //update the MCS rates ++ for (i = 0; i < 16; i++) ++ { ++ pmlmeinfo->HT_caps.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i]; ++ }*/ ++ DBG_871X("%s(): WLAN_HT_CAP_SM_PS_STATIC\n",__FUNCTION__); ++ } ++ ++ // ++ // Config current HT Protection mode. ++ // ++ //pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3; ++ ++} ++ ++static void start_bss_network(_adapter *padapter, u8 *pbuf) ++{ ++ u8 *p; ++ u8 val8, cur_channel, cur_bwmode, cur_ch_offset; ++ u16 bcn_interval; ++ u32 acparm; ++ int ie_len; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct security_priv* psecuritypriv=&(padapter->securitypriv); ++ WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *pnetwork_mlmeext = &(pmlmeinfo->network); ++ struct HT_info_element *pht_info=NULL; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); ++#endif //CONFIG_P2P ++ ++ //DBG_871X("%s\n", __FUNCTION__); ++ ++ bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod; ++ cur_channel = pnetwork->Configuration.DSConfig; ++ cur_bwmode = HT_CHANNEL_WIDTH_20;; ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ ++ //check if there is wps ie, ++ //if there is wpsie in beacon, the hostapd will update beacon twice when stating hostapd, ++ //and at first time the security ie ( RSN/WPA IE) will not include in beacon. ++ if(NULL == rtw_get_wps_ie(pnetwork->IEs+_FIXED_IE_LENGTH_, pnetwork->IELength-_FIXED_IE_LENGTH_, NULL, NULL)) ++ { ++ pmlmeext->bstart_bss = _TRUE; ++ } ++ ++ //todo: update wmm, ht cap ++ //pmlmeinfo->WMM_enable; ++ //pmlmeinfo->HT_enable; ++ if(pmlmepriv->qospriv.qos_option) ++ pmlmeinfo->WMM_enable = _TRUE; ++#ifdef CONFIG_80211N_HT ++ if(pmlmepriv->htpriv.ht_option) ++ { ++ pmlmeinfo->WMM_enable = _TRUE; ++ pmlmeinfo->HT_enable = _TRUE; ++ //pmlmeinfo->HT_info_enable = _TRUE; ++ //pmlmeinfo->HT_caps_enable = _TRUE; ++ ++ update_hw_ht_param(padapter); ++ } ++#endif //#CONFIG_80211N_HT ++ ++ ++ if(pmlmepriv->cur_network.join_res != _TRUE) //setting only at first time ++ { ++ //WEP Key will be set before this function, do not clear CAM. ++ if ((psecuritypriv->dot11PrivacyAlgrthm != _WEP40_) && (psecuritypriv->dot11PrivacyAlgrthm != _WEP104_)) ++ flush_all_cam_entry(padapter); //clear CAM ++ } ++ ++ //set MSR to AP_Mode ++ Set_MSR(padapter, _HW_STATE_AP_); ++ ++ //Set BSSID REG ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pnetwork->MacAddress); ++ ++ //Set EDCA param reg ++#ifdef CONFIG_CONCURRENT_MODE ++ acparm = 0x005ea42b; ++#else ++ acparm = 0x002F3217; // VO ++#endif ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm)); ++ acparm = 0x005E4317; // VI ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm)); ++ //acparm = 0x00105320; // BE ++ acparm = 0x005ea42b; ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm)); ++ acparm = 0x0000A444; // BK ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm)); ++ ++ //Set Security ++ val8 = (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)? 0xcc: 0xcf; ++ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); ++ ++ //Beacon Control related register ++ rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&bcn_interval)); ++ ++ ++ UpdateBrateTbl(padapter, pnetwork->SupportedRates); ++ rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates); ++ ++ if(pmlmepriv->cur_network.join_res != _TRUE) //setting only at first time ++ { ++ //u32 initialgain; ++ ++ //initialgain = 0x1e; ++ ++ ++ //disable dynamic functions, such as high power, DIG ++ //Save_DM_Func_Flag(padapter); ++ //Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, _FALSE); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(padapter->adapter_type > PRIMARY_ADAPTER) ++ { ++ if(rtw_buddy_adapter_up(padapter)) ++ { ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ ++ //turn on all dynamic functions on PRIMARY_ADAPTER, dynamic functions only runs at PRIMARY_ADAPTER ++ Switch_DM_Func(pbuddy_adapter, DYNAMIC_ALL_FUNC_ENABLE, _TRUE); ++ ++ //rtw_hal_set_hwreg(pbuddy_adapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); ++ } ++ } ++ else ++#endif ++ { ++ //turn on all dynamic functions ++ Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, _TRUE); ++ ++ //rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); ++ } ++ ++ } ++#ifdef CONFIG_80211N_HT ++ //set channel, bwmode ++ p = rtw_get_ie((pnetwork->IEs + sizeof(NDIS_802_11_FIXED_IEs)), _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - sizeof(NDIS_802_11_FIXED_IEs))); ++ if( p && ie_len) ++ { ++ pht_info = (struct HT_info_element *)(p+2); ++ ++ if ((pregpriv->cbw40_enable) && (pht_info->infos[0] & BIT(2))) ++ { ++ //switch to the 40M Hz mode ++ //pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; ++ cur_bwmode = HT_CHANNEL_WIDTH_40; ++ switch (pht_info->infos[0] & 0x3) ++ { ++ case 1: ++ //pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ break; ++ ++ case 3: ++ //pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ break; ++ ++ default: ++ //pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ break; ++ } ++ ++ } ++ ++ } ++#endif //CONFIG_80211N_HT ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ dc_set_ap_channel_bandwidth(padapter, cur_channel, cur_ch_offset, cur_bwmode); ++#else ++ //TODO: need to judge the phy parameters on concurrent mode for single phy ++ //set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++#ifdef CONFIG_CONCURRENT_MODE ++ if(!check_buddy_fwstate(padapter, _FW_LINKED|_FW_UNDER_LINKING|_FW_UNDER_SURVEY)) ++ { ++ set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode); ++ } ++ else if(check_buddy_fwstate(padapter, _FW_LINKED)==_TRUE)//only second adapter can enter AP Mode ++ { ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ ++ //To sync cur_channel/cur_bwmode/cur_ch_offset with primary adapter ++ DBG_871X("primary iface is at linked state, sync cur_channel/cur_bwmode/cur_ch_offset\n"); ++ DBG_871X("primary adapter, CH=%d, BW=%d, offset=%d\n", pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_bwmode, pbuddy_mlmeext->cur_ch_offset); ++ DBG_871X("second adapter, CH=%d, BW=%d, offset=%d\n", cur_channel, cur_bwmode, cur_ch_offset); ++ ++ cur_channel = pbuddy_mlmeext->cur_channel; ++ if(cur_bwmode == HT_CHANNEL_WIDTH_40) ++ { ++ if(pht_info) ++ pht_info->infos[0] &= ~(BIT(0)|BIT(1)); ++ ++ if(pbuddy_mlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40) ++ { ++ cur_ch_offset = pbuddy_mlmeext->cur_ch_offset; ++ ++ //to update cur_ch_offset value in beacon ++ if(pht_info) ++ { ++ switch(cur_ch_offset) ++ { ++ case HAL_PRIME_CHNL_OFFSET_LOWER: ++ pht_info->infos[0] |= 0x1; ++ break; ++ case HAL_PRIME_CHNL_OFFSET_UPPER: ++ pht_info->infos[0] |= 0x3; ++ break; ++ case HAL_PRIME_CHNL_OFFSET_DONT_CARE: ++ default: ++ break; ++ } ++ } ++ ++ } ++ else if(pbuddy_mlmeext->cur_bwmode == HT_CHANNEL_WIDTH_20) ++ { ++ cur_bwmode = HT_CHANNEL_WIDTH_20; ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ if(cur_channel>0 && cur_channel<5) ++ { ++ if(pht_info) ++ pht_info->infos[0] |= 0x1; ++ ++ cur_bwmode = HT_CHANNEL_WIDTH_40; ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ } ++ ++ if(cur_channel>7 && cur_channel<(14+1)) ++ { ++ if(pht_info) ++ pht_info->infos[0] |= 0x3; ++ ++ cur_bwmode = HT_CHANNEL_WIDTH_40; ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ } ++ ++ set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode); ++ } ++ ++ } ++ ++ // to update channel value in beacon ++ pnetwork->Configuration.DSConfig = cur_channel; ++ p = rtw_get_ie((pnetwork->IEs + sizeof(NDIS_802_11_FIXED_IEs)), _DSSET_IE_, &ie_len, (pnetwork->IELength - sizeof(NDIS_802_11_FIXED_IEs))); ++ if(p && ie_len>0) ++ *(p + 2) = cur_channel; ++ ++ if(pht_info) ++ pht_info->primary_channel = cur_channel; ++ } ++#else ++ set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode); ++#endif //CONFIG_CONCURRENT_MODE ++ ++ DBG_871X("CH=%d, BW=%d, offset=%d\n", cur_channel, cur_bwmode, cur_ch_offset); ++ ++ // ++ pmlmeext->cur_channel = cur_channel; ++ pmlmeext->cur_bwmode = cur_bwmode; ++ pmlmeext->cur_ch_offset = cur_ch_offset; ++#endif //CONFIG_DUALMAC_CONCURRENT ++ pmlmeext->cur_wireless_mode = pmlmepriv->cur_network.network_type; ++ ++ //let pnetwork_mlmeext == pnetwork_mlme. ++ _rtw_memcpy(pnetwork_mlmeext, pnetwork, pnetwork->Length); ++ ++ //update cur_wireless_mode ++ update_wireless_mode(padapter); ++ ++ //udpate capability after cur_wireless_mode updated ++ update_capinfo(padapter, rtw_get_capability((WLAN_BSSID_EX *)pnetwork)); ++ ++#ifdef CONFIG_P2P ++ _rtw_memcpy(pwdinfo->p2p_group_ssid, pnetwork->Ssid.Ssid, pnetwork->Ssid.SsidLength); ++ pwdinfo->p2p_group_ssid_len = pnetwork->Ssid.SsidLength; ++#endif //CONFIG_P2P ++ ++ if(_TRUE == pmlmeext->bstart_bss) ++ { ++ update_beacon(padapter, _TIM_IE_, NULL, _FALSE); ++ ++#ifndef CONFIG_INTERRUPT_BASED_TXBCN //other case will tx beacon when bcn interrupt coming in. ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ //issue beacon frame ++ if(send_beacon(padapter)==_FAIL) ++ { ++ DBG_871X("issue_beacon, fail!\n"); ++ } ++#endif ++#endif //!CONFIG_INTERRUPT_BASED_TXBCN ++ ++ } ++ ++ ++ //update bc/mc sta_info ++ update_bmc_sta(padapter); ++ ++ //pmlmeext->bstart_bss = _TRUE; ++ ++} ++ ++int rtw_check_beacon_data(_adapter *padapter, u8 *pbuf, int len) ++{ ++ int ret=_SUCCESS; ++ u8 *p; ++ u8 *pHT_caps_ie=NULL; ++ u8 *pHT_info_ie=NULL; ++ struct sta_info *psta = NULL; ++ u16 cap, ht_cap=_FALSE; ++ uint ie_len = 0; ++ int group_cipher, pairwise_cipher; ++ u8 channel, network_type, supportRate[NDIS_802_11_LENGTH_RATES_EX]; ++ int supportRateNum = 0; ++ u8 OUI1[] = {0x00, 0x50, 0xf2,0x01}; ++ u8 wps_oui[4]={0x0,0x50,0xf2,0x04}; ++ u8 WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ WLAN_BSSID_EX *pbss_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 *ie = pbss_network->IEs; ++ ++ ++ /* SSID */ ++ /* Supported rates */ ++ /* DS Params */ ++ /* WLAN_EID_COUNTRY */ ++ /* ERP Information element */ ++ /* Extended supported rates */ ++ /* WPA/WPA2 */ ++ /* Wi-Fi Wireless Multimedia Extensions */ ++ /* ht_capab, ht_oper */ ++ /* WPS IE */ ++ ++ DBG_871X("%s, len=%d\n", __FUNCTION__, len); ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE) ++ return _FAIL; ++ ++ ++ if(len>MAX_IE_SZ) ++ return _FAIL; ++ ++ pbss_network->IELength = len; ++ ++ _rtw_memset(ie, 0, MAX_IE_SZ); ++ ++ _rtw_memcpy(ie, pbuf, pbss_network->IELength); ++ ++ ++ if(pbss_network->InfrastructureMode!=Ndis802_11APMode) ++ return _FAIL; ++ ++ pbss_network->Rssi = 0; ++ ++ _rtw_memcpy(pbss_network->MacAddress, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ //beacon interval ++ p = rtw_get_beacon_interval_from_ie(ie);//ie + 8; // 8: TimeStamp, 2: Beacon Interval 2:Capability ++ //pbss_network->Configuration.BeaconPeriod = le16_to_cpu(*(unsigned short*)p); ++ pbss_network->Configuration.BeaconPeriod = RTW_GET_LE16(p); ++ ++ //capability ++ //cap = *(unsigned short *)rtw_get_capability_from_ie(ie); ++ //cap = le16_to_cpu(cap); ++ cap = RTW_GET_LE16(ie); ++ ++ //SSID ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SSID_IE_, &ie_len, (pbss_network->IELength -_BEACON_IE_OFFSET_)); ++ if(p && ie_len>0) ++ { ++ _rtw_memset(&pbss_network->Ssid, 0, sizeof(NDIS_802_11_SSID)); ++ _rtw_memcpy(pbss_network->Ssid.Ssid, (p + 2), ie_len); ++ pbss_network->Ssid.SsidLength = ie_len; ++ } ++ ++ //chnnel ++ channel = 0; ++ pbss_network->Configuration.Length = 0; ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _DSSET_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if(p && ie_len>0) ++ channel = *(p + 2); ++ ++ pbss_network->Configuration.DSConfig = channel; ++ ++ ++ _rtw_memset(supportRate, 0, NDIS_802_11_LENGTH_RATES_EX); ++ // get supported rates ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if (p != NULL) ++ { ++ _rtw_memcpy(supportRate, p+2, ie_len); ++ supportRateNum = ie_len; ++ } ++ ++ //get ext_supported rates ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ie_len, pbss_network->IELength - _BEACON_IE_OFFSET_); ++ if (p != NULL) ++ { ++ _rtw_memcpy(supportRate+supportRateNum, p+2, ie_len); ++ supportRateNum += ie_len; ++ ++ } ++ ++ network_type = rtw_check_network_type(supportRate, supportRateNum, channel); ++ ++ rtw_set_supported_rate(pbss_network->SupportedRates, network_type); ++ ++ ++ //parsing ERP_IE ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if(p && ie_len>0) ++ { ++ ERP_IE_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)p); ++ } ++ ++ //update privacy/security ++ if (cap & BIT(4)) ++ pbss_network->Privacy = 1; ++ else ++ pbss_network->Privacy = 0; ++ ++ psecuritypriv->wpa_psk = 0; ++ ++ //wpa2 ++ group_cipher = 0; pairwise_cipher = 0; ++ psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_; ++ psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_; ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if(p && ie_len>0) ++ { ++ if(rtw_parse_wpa2_ie(p, ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) ++ { ++ psecuritypriv->dot11AuthAlgrthm= dot11AuthAlgrthm_8021X; ++ ++ psecuritypriv->dot8021xalg = 1;//psk, todo:802.1x ++ psecuritypriv->wpa_psk |= BIT(1); ++ ++ psecuritypriv->wpa2_group_cipher = group_cipher; ++ psecuritypriv->wpa2_pairwise_cipher = pairwise_cipher; ++#if 0 ++ switch(group_cipher) ++ { ++ case WPA_CIPHER_NONE: ++ psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_; ++ break; ++ case WPA_CIPHER_WEP40: ++ psecuritypriv->wpa2_group_cipher = _WEP40_; ++ break; ++ case WPA_CIPHER_TKIP: ++ psecuritypriv->wpa2_group_cipher = _TKIP_; ++ break; ++ case WPA_CIPHER_CCMP: ++ psecuritypriv->wpa2_group_cipher = _AES_; ++ break; ++ case WPA_CIPHER_WEP104: ++ psecuritypriv->wpa2_group_cipher = _WEP104_; ++ break; ++ } ++ ++ switch(pairwise_cipher) ++ { ++ case WPA_CIPHER_NONE: ++ psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_; ++ break; ++ case WPA_CIPHER_WEP40: ++ psecuritypriv->wpa2_pairwise_cipher = _WEP40_; ++ break; ++ case WPA_CIPHER_TKIP: ++ psecuritypriv->wpa2_pairwise_cipher = _TKIP_; ++ break; ++ case WPA_CIPHER_CCMP: ++ psecuritypriv->wpa2_pairwise_cipher = _AES_; ++ break; ++ case WPA_CIPHER_WEP104: ++ psecuritypriv->wpa2_pairwise_cipher = _WEP104_; ++ break; ++ } ++#endif ++ } ++ ++ } ++ ++ //wpa ++ ie_len = 0; ++ group_cipher = 0; pairwise_cipher = 0; ++ psecuritypriv->wpa_group_cipher = _NO_PRIVACY_; ++ psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_; ++ for (p = ie + _BEACON_IE_OFFSET_; ;p += (ie_len + 2)) ++ { ++ p = rtw_get_ie(p, _SSN_IE_1_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); ++ if ((p) && (_rtw_memcmp(p+2, OUI1, 4))) ++ { ++ if(rtw_parse_wpa_ie(p, ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) ++ { ++ psecuritypriv->dot11AuthAlgrthm= dot11AuthAlgrthm_8021X; ++ ++ psecuritypriv->dot8021xalg = 1;//psk, todo:802.1x ++ ++ psecuritypriv->wpa_psk |= BIT(0); ++ ++ psecuritypriv->wpa_group_cipher = group_cipher; ++ psecuritypriv->wpa_pairwise_cipher = pairwise_cipher; ++ ++#if 0 ++ switch(group_cipher) ++ { ++ case WPA_CIPHER_NONE: ++ psecuritypriv->wpa_group_cipher = _NO_PRIVACY_; ++ break; ++ case WPA_CIPHER_WEP40: ++ psecuritypriv->wpa_group_cipher = _WEP40_; ++ break; ++ case WPA_CIPHER_TKIP: ++ psecuritypriv->wpa_group_cipher = _TKIP_; ++ break; ++ case WPA_CIPHER_CCMP: ++ psecuritypriv->wpa_group_cipher = _AES_; ++ break; ++ case WPA_CIPHER_WEP104: ++ psecuritypriv->wpa_group_cipher = _WEP104_; ++ break; ++ } ++ ++ switch(pairwise_cipher) ++ { ++ case WPA_CIPHER_NONE: ++ psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_; ++ break; ++ case WPA_CIPHER_WEP40: ++ psecuritypriv->wpa_pairwise_cipher = _WEP40_; ++ break; ++ case WPA_CIPHER_TKIP: ++ psecuritypriv->wpa_pairwise_cipher = _TKIP_; ++ break; ++ case WPA_CIPHER_CCMP: ++ psecuritypriv->wpa_pairwise_cipher = _AES_; ++ break; ++ case WPA_CIPHER_WEP104: ++ psecuritypriv->wpa_pairwise_cipher = _WEP104_; ++ break; ++ } ++#endif ++ } ++ ++ break; ++ ++ } ++ ++ if ((p == NULL) || (ie_len == 0)) ++ { ++ break; ++ } ++ ++ } ++ ++ //wmm ++ ie_len = 0; ++ pmlmepriv->qospriv.qos_option = 0; ++ if(pregistrypriv->wmm_enable) ++ { ++ for (p = ie + _BEACON_IE_OFFSET_; ;p += (ie_len + 2)) ++ { ++ p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); ++ if((p) && _rtw_memcmp(p+2, WMM_PARA_IE, 6)) ++ { ++ pmlmepriv->qospriv.qos_option = 1; ++ ++ *(p+8) |= BIT(7);//QoS Info, support U-APSD ++ ++ /* disable all ACM bits since the WMM admission control is not supported */ ++ *(p + 10) &= ~BIT(4); /* BE */ ++ *(p + 14) &= ~BIT(4); /* BK */ ++ *(p + 18) &= ~BIT(4); /* VI */ ++ *(p + 22) &= ~BIT(4); /* VO */ ++ ++ break; ++ } ++ ++ if ((p == NULL) || (ie_len == 0)) ++ { ++ break; ++ } ++ } ++ } ++#ifdef CONFIG_80211N_HT ++ //parsing HT_CAP_IE ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if(p && ie_len>0) ++ { ++ u8 rf_type; ++ ++ struct rtw_ieee80211_ht_cap *pht_cap = (struct rtw_ieee80211_ht_cap *)(p+2); ++ ++ pHT_caps_ie=p; ++ ++ ++ ht_cap = _TRUE; ++ network_type |= WIRELESS_11_24N; ++ ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ ++ if((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) || ++ (psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP)) ++ { ++ pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&(0x07<<2)); ++ } ++ else ++ { ++ pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&0x00); ++ } ++ ++ pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_FACTOR & 0x03); //set Max Rx AMPDU size to 64K ++ ++ if(rf_type == RF_1T1R) ++ { ++ pht_cap->supp_mcs_set[0] = 0xff; ++ pht_cap->supp_mcs_set[1] = 0x0; ++ } ++ ++ _rtw_memcpy(&pmlmepriv->htpriv.ht_cap, p+2, ie_len); ++ ++ } ++ ++ //parsing HT_INFO_IE ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if(p && ie_len>0) ++ { ++ pHT_info_ie=p; ++ } ++#endif //CONFIG_80211N_HT ++ switch(network_type) ++ { ++ case WIRELESS_11B: ++ pbss_network->NetworkTypeInUse = Ndis802_11DS; ++ break; ++ case WIRELESS_11G: ++ case WIRELESS_11BG: ++ case WIRELESS_11G_24N: ++ case WIRELESS_11BG_24N: ++ pbss_network->NetworkTypeInUse = Ndis802_11OFDM24; ++ break; ++ case WIRELESS_11A: ++ pbss_network->NetworkTypeInUse = Ndis802_11OFDM5; ++ break; ++ default : ++ pbss_network->NetworkTypeInUse = Ndis802_11OFDM24; ++ break; ++ } ++ ++ pmlmepriv->cur_network.network_type = network_type; ++ ++#ifdef CONFIG_80211N_HT ++ pmlmepriv->htpriv.ht_option = _FALSE; ++ ++ if( (psecuritypriv->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) || ++ (psecuritypriv->wpa_pairwise_cipher&WPA_CIPHER_TKIP)) ++ { ++ //todo: ++ //ht_cap = _FALSE; ++ } ++ ++ //ht_cap ++ if(pregistrypriv->ht_enable && ht_cap==_TRUE) ++ { ++ pmlmepriv->htpriv.ht_option = _TRUE; ++ pmlmepriv->qospriv.qos_option = 1; ++ ++ if(pregistrypriv->ampdu_enable==1) ++ { ++ pmlmepriv->htpriv.ampdu_enable = _TRUE; ++ } ++ ++ HT_caps_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)pHT_caps_ie); ++ ++ HT_info_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)pHT_info_ie); ++ } ++#endif ++ ++ ++ pbss_network->Length = get_WLAN_BSSID_EX_sz((WLAN_BSSID_EX *)pbss_network); ++ ++ //issue beacon to start bss network ++ start_bss_network(padapter, (u8*)pbss_network); ++ ++ ++ //alloc sta_info for ap itself ++ psta = rtw_get_stainfo(&padapter->stapriv, pbss_network->MacAddress); ++ if(!psta) ++ { ++ psta = rtw_alloc_stainfo(&padapter->stapriv, pbss_network->MacAddress); ++ if (psta == NULL) ++ { ++ return _FAIL; ++ } ++ } ++ psta->state |= WIFI_AP_STATE; //Aries, add,fix bug of flush_cam_entry at STOP AP mode , 0724 ++ rtw_indicate_connect( padapter); ++ ++ pmlmepriv->cur_network.join_res = _TRUE;//for check if already set beacon ++ ++ //update bc/mc sta_info ++ //update_bmc_sta(padapter); ++ ++ return ret; ++ ++} ++ ++void rtw_set_macaddr_acl(_adapter *padapter, int mode) ++{ ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ ++ DBG_871X("%s, mode=%d\n", __func__, mode); ++ ++ pacl_list->mode = mode; ++} ++ ++int rtw_acl_add_sta(_adapter *padapter, u8 *addr) ++{ ++ _irqL irqL; ++ _list *plist, *phead; ++ u8 added = _FALSE; ++ int i, ret=0; ++ struct rtw_wlan_acl_node *paclnode; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ _queue *pacl_node_q =&pacl_list->acl_node_q; ++ ++ DBG_871X("%s(acl_num=%d)=" MAC_FMT "\n", __func__, pacl_list->num, MAC_ARG(addr)); ++ ++ if((NUM_ACL-1) < pacl_list->num) ++ return (-1); ++ ++ ++ _enter_critical_bh(&(pacl_node_q->lock), &irqL); ++ ++ phead = get_list_head(pacl_node_q); ++ plist = get_next(phead); ++ ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list); ++ plist = get_next(plist); ++ ++ if(_rtw_memcmp(paclnode->addr, addr, ETH_ALEN)) ++ { ++ if(paclnode->valid == _TRUE) ++ { ++ added = _TRUE; ++ DBG_871X("%s, sta has been added\n", __func__); ++ break; ++ } ++ } ++ } ++ ++ _exit_critical_bh(&(pacl_node_q->lock), &irqL); ++ ++ ++ if(added == _TRUE) ++ return ret; ++ ++ ++ _enter_critical_bh(&(pacl_node_q->lock), &irqL); ++ ++ for(i=0; i< NUM_ACL; i++) ++ { ++ paclnode = &pacl_list->aclnode[i]; ++ ++ if(paclnode->valid == _FALSE) ++ { ++ _rtw_init_listhead(&paclnode->list); ++ ++ _rtw_memcpy(paclnode->addr, addr, ETH_ALEN); ++ ++ paclnode->valid = _TRUE; ++ ++ rtw_list_insert_tail(&paclnode->list, get_list_head(pacl_node_q)); ++ ++ pacl_list->num++; ++ ++ break; ++ } ++ } ++ ++ DBG_871X("%s, acl_num=%d\n", __func__, pacl_list->num); ++ ++ _exit_critical_bh(&(pacl_node_q->lock), &irqL); ++ ++ return ret; ++} ++ ++int rtw_acl_remove_sta(_adapter *padapter, u8 *addr) ++{ ++ _irqL irqL; ++ _list *plist, *phead; ++ int i, ret=0; ++ struct rtw_wlan_acl_node *paclnode; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ _queue *pacl_node_q =&pacl_list->acl_node_q; ++ ++ DBG_871X("%s(acl_num=%d)=" MAC_FMT "\n", __func__, pacl_list->num, MAC_ARG(addr)); ++ ++ _enter_critical_bh(&(pacl_node_q->lock), &irqL); ++ ++ phead = get_list_head(pacl_node_q); ++ plist = get_next(phead); ++ ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list); ++ plist = get_next(plist); ++ ++ if(_rtw_memcmp(paclnode->addr, addr, ETH_ALEN)) ++ { ++ if(paclnode->valid == _TRUE) ++ { ++ paclnode->valid = _FALSE; ++ ++ rtw_list_delete(&paclnode->list); ++ ++ pacl_list->num--; ++ } ++ } ++ } ++ ++ _exit_critical_bh(&(pacl_node_q->lock), &irqL); ++ ++ DBG_871X("%s, acl_num=%d\n", __func__, pacl_list->num); ++ ++ return ret; ++ ++} ++ ++#ifdef CONFIG_NATIVEAP_MLME ++ ++static void update_bcn_fixed_ie(_adapter *padapter) ++{ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++} ++ ++static void update_bcn_erpinfo_ie(_adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network); ++ unsigned char *p, *ie = pnetwork->IEs; ++ u32 len = 0; ++ ++ DBG_871X("%s, ERP_enable=%d\n", __FUNCTION__, pmlmeinfo->ERP_enable); ++ ++ if(!pmlmeinfo->ERP_enable) ++ return; ++ ++ //parsing ERP_IE ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); ++ if(p && len>0) ++ { ++ PNDIS_802_11_VARIABLE_IEs pIE = (PNDIS_802_11_VARIABLE_IEs)p; ++ ++ if (pmlmepriv->num_sta_non_erp == 1) ++ pIE->data[0] |= RTW_ERP_INFO_NON_ERP_PRESENT|RTW_ERP_INFO_USE_PROTECTION; ++ else ++ pIE->data[0] &= ~(RTW_ERP_INFO_NON_ERP_PRESENT|RTW_ERP_INFO_USE_PROTECTION); ++ ++ if(pmlmepriv->num_sta_no_short_preamble > 0) ++ pIE->data[0] |= RTW_ERP_INFO_BARKER_PREAMBLE_MODE; ++ else ++ pIE->data[0] &= ~(RTW_ERP_INFO_BARKER_PREAMBLE_MODE); ++ ++ ERP_IE_handler(padapter, pIE); ++ } ++ ++} ++ ++static void update_bcn_htcap_ie(_adapter *padapter) ++{ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++} ++ ++static void update_bcn_htinfo_ie(_adapter *padapter) ++{ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++} ++ ++static void update_bcn_rsn_ie(_adapter *padapter) ++{ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++} ++ ++static void update_bcn_wpa_ie(_adapter *padapter) ++{ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++} ++ ++static void update_bcn_wmm_ie(_adapter *padapter) ++{ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++} ++ ++static void update_bcn_wps_ie(_adapter *padapter) ++{ ++ u8 *pwps_ie=NULL, *pwps_ie_src, *premainder_ie, *pbackup_remainder_ie=NULL; ++ uint wps_ielen=0, wps_offset, remainder_ielen; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network); ++ unsigned char *ie = pnetwork->IEs; ++ u32 ielen = pnetwork->IELength; ++ ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ pwps_ie = rtw_get_wps_ie(ie+_FIXED_IE_LENGTH_, ielen-_FIXED_IE_LENGTH_, NULL, &wps_ielen); ++ ++ if(pwps_ie==NULL || wps_ielen==0) ++ return; ++ ++ wps_offset = (uint)(pwps_ie-ie); ++ ++ premainder_ie = pwps_ie + wps_ielen; ++ ++ remainder_ielen = ielen - wps_offset - wps_ielen; ++ ++ if(remainder_ielen>0) ++ { ++ pbackup_remainder_ie = rtw_malloc(remainder_ielen); ++ if(pbackup_remainder_ie) ++ _rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); ++ } ++ ++ ++ pwps_ie_src = pmlmepriv->wps_beacon_ie; ++ if(pwps_ie_src == NULL) ++ return; ++ ++ ++ wps_ielen = (uint)pwps_ie_src[1];//to get ie data len ++ if((wps_offset+wps_ielen+2+remainder_ielen)<=MAX_IE_SZ) ++ { ++ _rtw_memcpy(pwps_ie, pwps_ie_src, wps_ielen+2); ++ pwps_ie += (wps_ielen+2); ++ ++ if(pbackup_remainder_ie) ++ _rtw_memcpy(pwps_ie, pbackup_remainder_ie, remainder_ielen); ++ ++ //update IELength ++ pnetwork->IELength = wps_offset + (wps_ielen+2) + remainder_ielen; ++ } ++ ++ if(pbackup_remainder_ie) ++ rtw_mfree(pbackup_remainder_ie, remainder_ielen); ++ ++} ++ ++static void update_bcn_p2p_ie(_adapter *padapter) ++{ ++ ++} ++ ++static void update_bcn_vendor_spec_ie(_adapter *padapter, u8*oui) ++{ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ if(_rtw_memcmp(RTW_WPA_OUI, oui, 4)) ++ { ++ update_bcn_wpa_ie(padapter); ++ } ++ else if(_rtw_memcmp(WMM_OUI, oui, 4)) ++ { ++ update_bcn_wmm_ie(padapter); ++ } ++ else if(_rtw_memcmp(WPS_OUI, oui, 4)) ++ { ++ update_bcn_wps_ie(padapter); ++ } ++ else if(_rtw_memcmp(P2P_OUI, oui, 4)) ++ { ++ update_bcn_p2p_ie(padapter); ++ } ++ else ++ { ++ DBG_871X("unknown OUI type!\n"); ++ } ++ ++ ++} ++ ++void update_beacon(_adapter *padapter, u8 ie_id, u8 *oui, u8 tx) ++{ ++ _irqL irqL; ++ struct mlme_priv *pmlmepriv; ++ struct mlme_ext_priv *pmlmeext; ++ //struct mlme_ext_info *pmlmeinfo; ++ ++ //DBG_871X("%s\n", __FUNCTION__); ++ ++ if(!padapter) ++ return; ++ ++ pmlmepriv = &(padapter->mlmepriv); ++ pmlmeext = &(padapter->mlmeextpriv); ++ //pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if(_FALSE == pmlmeext->bstart_bss) ++ return; ++ ++ _enter_critical_bh(&pmlmepriv->bcn_update_lock, &irqL); ++ ++ switch(ie_id) ++ { ++ case 0xFF: ++ ++ update_bcn_fixed_ie(padapter);//8: TimeStamp, 2: Beacon Interval 2:Capability ++ ++ break; ++ ++ case _TIM_IE_: ++ ++ update_BCNTIM(padapter); ++ ++ break; ++ ++ case _ERPINFO_IE_: ++ ++ update_bcn_erpinfo_ie(padapter); ++ ++ break; ++ ++ case _HT_CAPABILITY_IE_: ++ ++ update_bcn_htcap_ie(padapter); ++ ++ break; ++ ++ case _RSN_IE_2_: ++ ++ update_bcn_rsn_ie(padapter); ++ ++ break; ++ ++ case _HT_ADD_INFO_IE_: ++ ++ update_bcn_htinfo_ie(padapter); ++ ++ break; ++ ++ case _VENDOR_SPECIFIC_IE_: ++ ++ update_bcn_vendor_spec_ie(padapter, oui); ++ ++ break; ++ ++ default: ++ break; ++ } ++ ++ pmlmepriv->update_bcn = _TRUE; ++ ++ _exit_critical_bh(&pmlmepriv->bcn_update_lock, &irqL); ++ ++#ifndef CONFIG_INTERRUPT_BASED_TXBCN ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ if(tx) ++ { ++ //send_beacon(padapter);//send_beacon must execute on TSR level ++ set_tx_beacon_cmd(padapter); ++ } ++#else ++ { ++ //PCI will issue beacon when BCN interrupt occurs. ++ } ++#endif ++#endif //!CONFIG_INTERRUPT_BASED_TXBCN ++ ++} ++ ++#ifdef CONFIG_80211N_HT ++ ++/* ++op_mode ++Set to 0 (HT pure) under the followign conditions ++ - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or ++ - all STAs in the BSS are 20 MHz HT in 20 MHz BSS ++Set to 1 (HT non-member protection) if there may be non-HT STAs ++ in both the primary and the secondary channel ++Set to 2 if only HT STAs are associated in BSS, ++ however and at least one 20 MHz HT STA is associated ++Set to 3 (HT mixed mode) when one or more non-HT STAs are associated ++ (currently non-GF HT station is considered as non-HT STA also) ++*/ ++static int rtw_ht_operation_update(_adapter *padapter) ++{ ++ u16 cur_op_mode, new_op_mode; ++ int op_mode_changes = 0; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv; ++ ++ if(pmlmepriv->htpriv.ht_option == _TRUE) ++ return 0; ++ ++ //if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed) ++ // return 0; ++ ++ DBG_871X("%s current operation mode=0x%X\n", ++ __FUNCTION__, pmlmepriv->ht_op_mode); ++ ++ if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) ++ && pmlmepriv->num_sta_ht_no_gf) { ++ pmlmepriv->ht_op_mode |= ++ HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT; ++ op_mode_changes++; ++ } else if ((pmlmepriv->ht_op_mode & ++ HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) && ++ pmlmepriv->num_sta_ht_no_gf == 0) { ++ pmlmepriv->ht_op_mode &= ++ ~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT; ++ op_mode_changes++; ++ } ++ ++ if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) && ++ (pmlmepriv->num_sta_no_ht || pmlmepriv->olbc_ht)) { ++ pmlmepriv->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT; ++ op_mode_changes++; ++ } else if ((pmlmepriv->ht_op_mode & ++ HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) && ++ (pmlmepriv->num_sta_no_ht == 0 && !pmlmepriv->olbc_ht)) { ++ pmlmepriv->ht_op_mode &= ++ ~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT; ++ op_mode_changes++; ++ } ++ ++ /* Note: currently we switch to the MIXED op mode if HT non-greenfield ++ * station is associated. Probably it's a theoretical case, since ++ * it looks like all known HT STAs support greenfield. ++ */ ++ new_op_mode = 0; ++ if (pmlmepriv->num_sta_no_ht || ++ (pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)) ++ new_op_mode = OP_MODE_MIXED; ++ else if ((phtpriv_ap->ht_cap.cap_info & IEEE80211_HT_CAP_SUP_WIDTH) ++ && pmlmepriv->num_sta_ht_20mhz) ++ new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED; ++ else if (pmlmepriv->olbc_ht) ++ new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS; ++ else ++ new_op_mode = OP_MODE_PURE; ++ ++ cur_op_mode = pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK; ++ if (cur_op_mode != new_op_mode) { ++ pmlmepriv->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK; ++ pmlmepriv->ht_op_mode |= new_op_mode; ++ op_mode_changes++; ++ } ++ ++ DBG_871X("%s new operation mode=0x%X changes=%d\n", ++ __FUNCTION__, pmlmepriv->ht_op_mode, op_mode_changes); ++ ++ return op_mode_changes; ++ ++} ++ ++#endif /* CONFIG_80211N_HT */ ++ ++void associated_clients_update(_adapter *padapter, u8 updated) ++{ ++ //update associcated stations cap. ++ if(updated == _TRUE) ++ { ++ _irqL irqL; ++ _list *phead, *plist; ++ struct sta_info *psta=NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ ++ //check asoc_queue ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ ++ plist = get_next(plist); ++ ++ VCS_update(padapter, psta); ++ } ++ ++ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ } ++ ++} ++ ++/* called > TSR LEVEL for USB or SDIO Interface*/ ++void bss_cap_update_on_sta_join(_adapter *padapter, struct sta_info *psta) ++{ ++ u8 beacon_updated = _FALSE; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ ++ ++#if 0 ++ if (!(psta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && ++ !psta->no_short_preamble_set) { ++ psta->no_short_preamble_set = 1; ++ pmlmepriv->num_sta_no_short_preamble++; ++ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && ++ (pmlmepriv->num_sta_no_short_preamble == 1)) ++ ieee802_11_set_beacons(hapd->iface); ++ } ++#endif ++ ++ ++ if(!(psta->flags & WLAN_STA_SHORT_PREAMBLE)) ++ { ++ if(!psta->no_short_preamble_set) ++ { ++ psta->no_short_preamble_set = 1; ++ ++ pmlmepriv->num_sta_no_short_preamble++; ++ ++ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && ++ (pmlmepriv->num_sta_no_short_preamble == 1)) ++ { ++ beacon_updated = _TRUE; ++ update_beacon(padapter, 0xFF, NULL, _TRUE); ++ } ++ ++ } ++ } ++ else ++ { ++ if(psta->no_short_preamble_set) ++ { ++ psta->no_short_preamble_set = 0; ++ ++ pmlmepriv->num_sta_no_short_preamble--; ++ ++ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && ++ (pmlmepriv->num_sta_no_short_preamble == 0)) ++ { ++ beacon_updated = _TRUE; ++ update_beacon(padapter, 0xFF, NULL, _TRUE); ++ } ++ ++ } ++ } ++ ++#if 0 ++ if (psta->flags & WLAN_STA_NONERP && !psta->nonerp_set) { ++ psta->nonerp_set = 1; ++ pmlmepriv->num_sta_non_erp++; ++ if (pmlmepriv->num_sta_non_erp == 1) ++ ieee802_11_set_beacons(hapd->iface); ++ } ++#endif ++ ++ if(psta->flags & WLAN_STA_NONERP) ++ { ++ if(!psta->nonerp_set) ++ { ++ psta->nonerp_set = 1; ++ ++ pmlmepriv->num_sta_non_erp++; ++ ++ if (pmlmepriv->num_sta_non_erp == 1) ++ { ++ beacon_updated = _TRUE; ++ update_beacon(padapter, _ERPINFO_IE_, NULL, _TRUE); ++ } ++ } ++ ++ } ++ else ++ { ++ if(psta->nonerp_set) ++ { ++ psta->nonerp_set = 0; ++ ++ pmlmepriv->num_sta_non_erp--; ++ ++ if (pmlmepriv->num_sta_non_erp == 0) ++ { ++ beacon_updated = _TRUE; ++ update_beacon(padapter, _ERPINFO_IE_, NULL, _TRUE); ++ } ++ } ++ ++ } ++ ++ ++#if 0 ++ if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT) && ++ !psta->no_short_slot_time_set) { ++ psta->no_short_slot_time_set = 1; ++ pmlmepriv->num_sta_no_short_slot_time++; ++ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && ++ (pmlmepriv->num_sta_no_short_slot_time == 1)) ++ ieee802_11_set_beacons(hapd->iface); ++ } ++#endif ++ ++ if(!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT)) ++ { ++ if(!psta->no_short_slot_time_set) ++ { ++ psta->no_short_slot_time_set = 1; ++ ++ pmlmepriv->num_sta_no_short_slot_time++; ++ ++ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && ++ (pmlmepriv->num_sta_no_short_slot_time == 1)) ++ { ++ beacon_updated = _TRUE; ++ update_beacon(padapter, 0xFF, NULL, _TRUE); ++ } ++ ++ } ++ } ++ else ++ { ++ if(psta->no_short_slot_time_set) ++ { ++ psta->no_short_slot_time_set = 0; ++ ++ pmlmepriv->num_sta_no_short_slot_time--; ++ ++ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && ++ (pmlmepriv->num_sta_no_short_slot_time == 0)) ++ { ++ beacon_updated = _TRUE; ++ update_beacon(padapter, 0xFF, NULL, _TRUE); ++ } ++ } ++ } ++ ++#ifdef CONFIG_80211N_HT ++ ++ if (psta->flags & WLAN_STA_HT) ++ { ++ u16 ht_capab = le16_to_cpu(psta->htpriv.ht_cap.cap_info); ++ ++ DBG_871X("HT: STA " MAC_FMT " HT Capabilities " ++ "Info: 0x%04x\n", MAC_ARG(psta->hwaddr), ht_capab); ++ ++ if (psta->no_ht_set) { ++ psta->no_ht_set = 0; ++ pmlmepriv->num_sta_no_ht--; ++ } ++ ++ if ((ht_capab & IEEE80211_HT_CAP_GRN_FLD) == 0) { ++ if (!psta->no_ht_gf_set) { ++ psta->no_ht_gf_set = 1; ++ pmlmepriv->num_sta_ht_no_gf++; ++ } ++ DBG_871X("%s STA " MAC_FMT " - no " ++ "greenfield, num of non-gf stations %d\n", ++ __FUNCTION__, MAC_ARG(psta->hwaddr), ++ pmlmepriv->num_sta_ht_no_gf); ++ } ++ ++ if ((ht_capab & IEEE80211_HT_CAP_SUP_WIDTH) == 0) { ++ if (!psta->ht_20mhz_set) { ++ psta->ht_20mhz_set = 1; ++ pmlmepriv->num_sta_ht_20mhz++; ++ } ++ DBG_871X("%s STA " MAC_FMT " - 20 MHz HT, " ++ "num of 20MHz HT STAs %d\n", ++ __FUNCTION__, MAC_ARG(psta->hwaddr), ++ pmlmepriv->num_sta_ht_20mhz); ++ } ++ ++ } ++ else ++ { ++ if (!psta->no_ht_set) { ++ psta->no_ht_set = 1; ++ pmlmepriv->num_sta_no_ht++; ++ } ++ if(pmlmepriv->htpriv.ht_option == _TRUE) { ++ DBG_871X("%s STA " MAC_FMT ++ " - no HT, num of non-HT stations %d\n", ++ __FUNCTION__, MAC_ARG(psta->hwaddr), ++ pmlmepriv->num_sta_no_ht); ++ } ++ } ++ ++ if (rtw_ht_operation_update(padapter) > 0) ++ { ++ update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, _FALSE); ++ update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _TRUE); ++ } ++ ++#endif /* CONFIG_80211N_HT */ ++ ++ //update associcated stations cap. ++ associated_clients_update(padapter, beacon_updated); ++ ++ DBG_871X("%s, updated=%d\n", __func__, beacon_updated); ++ ++} ++ ++u8 bss_cap_update_on_sta_leave(_adapter *padapter, struct sta_info *psta) ++{ ++ u8 beacon_updated = _FALSE; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ ++ if(!psta) ++ return beacon_updated; ++ ++ if (psta->no_short_preamble_set) { ++ psta->no_short_preamble_set = 0; ++ pmlmepriv->num_sta_no_short_preamble--; ++ if (pmlmeext->cur_wireless_mode > WIRELESS_11B ++ && pmlmepriv->num_sta_no_short_preamble == 0) ++ { ++ beacon_updated = _TRUE; ++ update_beacon(padapter, 0xFF, NULL, _TRUE); ++ } ++ } ++ ++ if (psta->nonerp_set) { ++ psta->nonerp_set = 0; ++ pmlmepriv->num_sta_non_erp--; ++ if (pmlmepriv->num_sta_non_erp == 0) ++ { ++ beacon_updated = _TRUE; ++ update_beacon(padapter, _ERPINFO_IE_, NULL, _TRUE); ++ } ++ } ++ ++ if (psta->no_short_slot_time_set) { ++ psta->no_short_slot_time_set = 0; ++ pmlmepriv->num_sta_no_short_slot_time--; ++ if (pmlmeext->cur_wireless_mode > WIRELESS_11B ++ && pmlmepriv->num_sta_no_short_slot_time == 0) ++ { ++ beacon_updated = _TRUE; ++ update_beacon(padapter, 0xFF, NULL, _TRUE); ++ } ++ } ++ ++#ifdef CONFIG_80211N_HT ++ ++ if (psta->no_ht_gf_set) { ++ psta->no_ht_gf_set = 0; ++ pmlmepriv->num_sta_ht_no_gf--; ++ } ++ ++ if (psta->no_ht_set) { ++ psta->no_ht_set = 0; ++ pmlmepriv->num_sta_no_ht--; ++ } ++ ++ if (psta->ht_20mhz_set) { ++ psta->ht_20mhz_set = 0; ++ pmlmepriv->num_sta_ht_20mhz--; ++ } ++ ++ if (rtw_ht_operation_update(padapter) > 0) ++ { ++ update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, _FALSE); ++ update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _TRUE); ++ } ++ ++#endif /* CONFIG_80211N_HT */ ++ ++ //update associcated stations cap. ++ //associated_clients_update(padapter, beacon_updated); //move it to avoid deadlock ++ ++ DBG_871X("%s, updated=%d\n", __func__, beacon_updated); ++ ++ return beacon_updated; ++ ++} ++ ++u8 ap_free_sta(_adapter *padapter, struct sta_info *psta, bool active, u16 reason) ++{ ++ _irqL irqL; ++ u8 beacon_updated = _FALSE; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ if(!psta) ++ return beacon_updated; ++ ++ if (active == _TRUE) ++ { ++#ifdef CONFIG_80211N_HT ++ //tear down Rx AMPDU ++ send_delba(padapter, 0, psta->hwaddr);// recipient ++ ++ //tear down TX AMPDU ++ send_delba(padapter, 1, psta->hwaddr);// // originator ++ ++#endif //CONFIG_80211N_HT ++ ++ issue_deauth(padapter, psta->hwaddr, reason); ++ } ++ ++ psta->htpriv.agg_enable_bitmap = 0x0;//reset ++ psta->htpriv.candidate_tid_bitmap = 0x0;//reset ++ ++ ++ //report_del_sta_event(padapter, psta->hwaddr, reason); ++ ++ //clear cam entry / key ++ //clear_cam_entry(padapter, (psta->mac_id + 3)); ++ rtw_clearstakey_cmd(padapter, (u8*)psta, (u8)(psta->mac_id + 3), _TRUE); ++ ++ ++ _enter_critical_bh(&psta->lock, &irqL); ++ psta->state &= ~_FW_LINKED; ++ _exit_critical_bh(&psta->lock, &irqL); ++ ++ #ifdef CONFIG_IOCTL_CFG80211 ++ if (1) { ++ #ifdef COMPAT_KERNEL_RELEASE ++ rtw_cfg80211_indicate_sta_disassoc(padapter, psta->hwaddr, reason); ++ #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) && !defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER) ++ rtw_cfg80211_indicate_sta_disassoc(padapter, psta->hwaddr, reason); ++ #else //(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) && !defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER) ++ /* will call rtw_cfg80211_indicate_sta_disassoc() in cmd_thread for old API context */ ++ #endif //(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) && !defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER) ++ } else ++ #endif //CONFIG_IOCTL_CFG80211 ++ { ++ rtw_indicate_sta_disassoc_event(padapter, psta); ++ } ++ ++ report_del_sta_event(padapter, psta->hwaddr, reason); ++ ++ beacon_updated = bss_cap_update_on_sta_leave(padapter, psta); ++ ++ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ rtw_free_stainfo(padapter, psta); ++ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ ++ ++ return beacon_updated; ++ ++} ++ ++int rtw_ap_inform_ch_switch(_adapter *padapter, u8 new_ch, u8 ch_offset) ++{ ++ _irqL irqL; ++ _list *phead, *plist; ++ int ret=0; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 bc_addr[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; ++ ++ if((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) ++ return ret; ++ ++ DBG_871X(FUNC_NDEV_FMT" with ch:%u, offset:%u\n", ++ FUNC_NDEV_ARG(padapter->pnetdev), new_ch, ch_offset); ++ ++ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ ++ /* for each sta in asoc_queue */ ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ plist = get_next(plist); ++ ++ issue_action_spct_ch_switch(padapter, psta->hwaddr, new_ch, ch_offset); ++ psta->expire_to = ((pstapriv->expire_to * 2) > 5) ? 5 : (pstapriv->expire_to * 2); ++ } ++ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ issue_action_spct_ch_switch(padapter, bc_addr, new_ch, ch_offset); ++ ++ return ret; ++} ++ ++int rtw_sta_flush(_adapter *padapter) ++{ ++ _irqL irqL; ++ _list *phead, *plist; ++ int ret=0; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 bc_addr[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; ++ u8 chk_alive_num = 0; ++ char chk_alive_list[NUM_STA]; ++ int i; ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev)); ++ ++ if((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) ++ return ret; ++ ++ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { ++ int stainfo_offset; ++ ++ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ plist = get_next(plist); ++ ++ /* Remove sta from asoc_list */ ++ rtw_list_delete(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ ++ /* Keep sta for ap_free_sta() beyond this asoc_list loop */ ++ stainfo_offset = rtw_stainfo_offset(pstapriv, psta); ++ if (stainfo_offset_valid(stainfo_offset)) { ++ chk_alive_list[chk_alive_num++] = stainfo_offset; ++ } ++ } ++ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ ++ /* For each sta in chk_alive_list, call ap_free_sta */ ++ for (i = 0; i < chk_alive_num; i++) { ++ psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); ++ ap_free_sta(padapter, psta, _TRUE, WLAN_REASON_DEAUTH_LEAVING); ++ } ++ ++ issue_deauth(padapter, bc_addr, WLAN_REASON_DEAUTH_LEAVING); ++ ++ associated_clients_update(padapter, _TRUE); ++ ++ return ret; ++ ++} ++ ++/* called > TSR LEVEL for USB or SDIO Interface*/ ++void sta_info_update(_adapter *padapter, struct sta_info *psta) ++{ ++ int flags = psta->flags; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ ++ //update wmm cap. ++ if(WLAN_STA_WME&flags) ++ psta->qos_option = 1; ++ else ++ psta->qos_option = 0; ++ ++ if(pmlmepriv->qospriv.qos_option == 0) ++ psta->qos_option = 0; ++ ++ ++#ifdef CONFIG_80211N_HT ++ //update 802.11n ht cap. ++ if(WLAN_STA_HT&flags) ++ { ++ psta->htpriv.ht_option = _TRUE; ++ psta->qos_option = 1; ++ } ++ else ++ { ++ psta->htpriv.ht_option = _FALSE; ++ } ++ ++ if(pmlmepriv->htpriv.ht_option == _FALSE) ++ psta->htpriv.ht_option = _FALSE; ++#endif ++ ++ ++ update_sta_info_apmode(padapter, psta); ++ ++ ++} ++ ++/* called >= TSR LEVEL for USB or SDIO Interface*/ ++void ap_sta_info_defer_update(_adapter *padapter, struct sta_info *psta) ++{ ++ if(psta->state & _FW_LINKED) ++ { ++ //add ratid ++ add_RATid(padapter, psta, 0);//DM_RATR_STA_INIT ++ } ++} ++/* restore hw setting from sw data structures */ ++void rtw_ap_restore_network(_adapter *padapter) ++{ ++ struct mlme_priv *mlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct sta_priv * pstapriv = &padapter->stapriv; ++ struct sta_info *psta; ++ struct security_priv* psecuritypriv=&(padapter->securitypriv); ++ _irqL irqL; ++ _list *phead, *plist; ++ u8 chk_alive_num = 0; ++ char chk_alive_list[NUM_STA]; ++ int i; ++ ++ rtw_setopmode_cmd(padapter, Ndis802_11APMode,_FALSE); ++ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ ++ start_bss_network(padapter, (u8*)&mlmepriv->cur_network.network); ++ ++ if((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) || ++ (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) ++ { ++ /* restore group key, WEP keys is restored in ips_leave() */ ++ rtw_set_key(padapter, psecuritypriv, psecuritypriv->dot118021XGrpKeyid, 0,_FALSE); ++ } ++ ++ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { ++ int stainfo_offset; ++ ++ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ plist = get_next(plist); ++ ++ stainfo_offset = rtw_stainfo_offset(pstapriv, psta); ++ if (stainfo_offset_valid(stainfo_offset)) { ++ chk_alive_list[chk_alive_num++] = stainfo_offset; ++ } ++ } ++ ++ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ for (i = 0; i < chk_alive_num; i++) { ++ psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); ++ ++ if (psta == NULL) { ++ DBG_871X(FUNC_ADPT_FMT" sta_info is null\n", FUNC_ADPT_ARG(padapter)); ++ } ++ else if(psta->state &_FW_LINKED) ++ { ++ Update_RA_Entry(padapter, psta); ++ //pairwise key ++ /* per sta pairwise key and settings */ ++ if( (padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) || ++ (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) ++ { ++ rtw_setstakey_cmd(padapter, (unsigned char *)psta, _TRUE,_FALSE); ++ } ++ } ++ } ++ ++} ++ ++void start_ap_mode(_adapter *padapter) ++{ ++ int i; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ ++ pmlmepriv->update_bcn = _FALSE; ++ ++ //init_mlme_ap_info(padapter); ++ pmlmeext->bstart_bss = _FALSE; ++ ++ pmlmepriv->num_sta_non_erp = 0; ++ ++ pmlmepriv->num_sta_no_short_slot_time = 0; ++ ++ pmlmepriv->num_sta_no_short_preamble = 0; ++ ++ pmlmepriv->num_sta_ht_no_gf = 0; ++#ifdef CONFIG_80211N_HT ++ pmlmepriv->num_sta_no_ht = 0; ++#endif //CONFIG_80211N_HT ++ pmlmepriv->num_sta_ht_20mhz = 0; ++ ++ pmlmepriv->olbc = _FALSE; ++ ++ pmlmepriv->olbc_ht = _FALSE; ++ ++#ifdef CONFIG_80211N_HT ++ pmlmepriv->ht_op_mode = 0; ++#endif ++ ++ for(i=0; ista_aid[i] = NULL; ++ ++ pmlmepriv->wps_beacon_ie = NULL; ++ pmlmepriv->wps_probe_resp_ie = NULL; ++ pmlmepriv->wps_assoc_resp_ie = NULL; ++ ++ pmlmepriv->p2p_beacon_ie = NULL; ++ pmlmepriv->p2p_probe_resp_ie = NULL; ++ ++ ++ //for ACL ++ _rtw_init_listhead(&(pacl_list->acl_node_q.queue)); ++ pacl_list->num = 0; ++ pacl_list->mode = 0; ++ for(i = 0; i < NUM_ACL; i++) ++ { ++ _rtw_init_listhead(&pacl_list->aclnode[i].list); ++ pacl_list->aclnode[i].valid = _FALSE; ++ } ++ ++} ++ ++void stop_ap_mode(_adapter *padapter) ++{ ++ _irqL irqL; ++ _list *phead, *plist; ++ struct rtw_wlan_acl_node *paclnode; ++ struct sta_info *psta=NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ _queue *pacl_node_q =&pacl_list->acl_node_q; ++ ++ pmlmepriv->update_bcn = _FALSE; ++ pmlmeext->bstart_bss = _FALSE; ++ //_rtw_spinlock_free(&pmlmepriv->bcn_update_lock); ++ ++ //reset and init security priv , this can refine with rtw_reset_securitypriv ++ _rtw_memset((unsigned char *)&padapter->securitypriv, 0, sizeof (struct security_priv)); ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled; ++ ++ //for ACL ++ _enter_critical_bh(&(pacl_node_q->lock), &irqL); ++ phead = get_list_head(pacl_node_q); ++ plist = get_next(phead); ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list); ++ plist = get_next(plist); ++ ++ if(paclnode->valid == _TRUE) ++ { ++ paclnode->valid = _FALSE; ++ ++ rtw_list_delete(&paclnode->list); ++ ++ pacl_list->num--; ++ } ++ } ++ _exit_critical_bh(&(pacl_node_q->lock), &irqL); ++ ++ DBG_871X("%s, free acl_node_queue, num=%d\n", __func__, pacl_list->num); ++ ++ rtw_sta_flush(padapter); ++ ++ //free_assoc_sta_resources ++ rtw_free_all_stainfo(padapter); ++ ++ psta = rtw_get_bcmc_stainfo(padapter); ++ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ rtw_free_stainfo(padapter, psta); ++ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ ++ rtw_init_bcmc_stainfo(padapter); ++ ++ rtw_free_mlme_priv_ie_data(pmlmepriv); ++ ++} ++ ++#endif //CONFIG_NATIVEAP_MLME ++#endif //CONFIG_AP_MODE ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_br_ext.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_br_ext.c +new file mode 100644 +index 00000000..44ff8275 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_br_ext.c +@@ -0,0 +1,1700 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_BR_EXT_C_ ++ ++#ifdef __KERNEL__ ++#include ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++#if 1 // rtw_wifi_driver ++#include ++#include ++#include "rtw_br_ext.h" ++#else // rtw_wifi_driver ++#include "./8192cd_cfg.h" ++ ++#ifndef __KERNEL__ ++#include "./sys-support.h" ++#endif ++ ++#include "./8192cd.h" ++#include "./8192cd_headers.h" ++#include "./8192cd_br_ext.h" ++#include "./8192cd_debug.h" ++#endif // rtw_wifi_driver ++ ++#ifdef CL_IPV6_PASS ++#ifdef __KERNEL__ ++#include ++#include ++#include ++#include ++#endif ++#endif ++ ++#ifdef CONFIG_BR_EXT ++ ++//#define BR_EXT_DEBUG ++ ++#define NAT25_IPV4 01 ++#define NAT25_IPV6 02 ++#define NAT25_IPX 03 ++#define NAT25_APPLE 04 ++#define NAT25_PPPOE 05 ++ ++#define RTL_RELAY_TAG_LEN (ETH_ALEN) ++#define TAG_HDR_LEN 4 ++ ++#define MAGIC_CODE 0x8186 ++#define MAGIC_CODE_LEN 2 ++#define WAIT_TIME_PPPOE 5 // waiting time for pppoe server in sec ++ ++/*----------------------------------------------------------------- ++ How database records network address: ++ 0 1 2 3 4 5 6 7 8 9 10 ++ |----|----|----|----|----|----|----|----|----|----|----| ++ IPv4 |type| | IP addr | ++ IPX |type| Net addr | Node addr | ++ IPX |type| Net addr |Sckt addr| ++ Apple |type| Network |node| ++ PPPoE |type| SID | AC MAC | ++-----------------------------------------------------------------*/ ++ ++ ++//Find a tag in pppoe frame and return the pointer ++static __inline__ unsigned char *__nat25_find_pppoe_tag(struct pppoe_hdr *ph, unsigned short type) ++{ ++ unsigned char *cur_ptr, *start_ptr; ++ unsigned short tagLen, tagType; ++ ++ start_ptr = cur_ptr = (unsigned char *)ph->tag; ++ while((cur_ptr - start_ptr) < ntohs(ph->length)) { ++ // prevent un-alignment access ++ tagType = (unsigned short)((cur_ptr[0] << 8) + cur_ptr[1]); ++ tagLen = (unsigned short)((cur_ptr[2] << 8) + cur_ptr[3]); ++ if(tagType == type) ++ return cur_ptr; ++ cur_ptr = cur_ptr + TAG_HDR_LEN + tagLen; ++ } ++ return 0; ++} ++ ++ ++static __inline__ int __nat25_add_pppoe_tag(struct sk_buff *skb, struct pppoe_tag *tag) ++{ ++ struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN); ++ int data_len; ++ ++ data_len = tag->tag_len + TAG_HDR_LEN; ++ if (skb_tailroom(skb) < data_len) { ++ _DEBUG_ERR("skb_tailroom() failed in add SID tag!\n"); ++ return -1; ++ } ++ ++ skb_put(skb, data_len); ++ // have a room for new tag ++ memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ntohs(ph->length)); ++ ph->length = htons(ntohs(ph->length) + data_len); ++ memcpy((unsigned char *)ph->tag, tag, data_len); ++ return data_len; ++} ++ ++static int skb_pull_and_merge(struct sk_buff *skb, unsigned char *src, int len) ++{ ++ int tail_len; ++ unsigned long end, tail; ++ ++ if ((src+len) > skb_tail_pointer(skb) || skb->len < len) ++ return -1; ++ ++ tail = (unsigned long)skb_tail_pointer(skb); ++ end = (unsigned long)src+len; ++ if (tail < end) ++ return -1; ++ ++ tail_len = (int)(tail-end); ++ if (tail_len > 0) ++ memmove(src, src+len, tail_len); ++ ++ skb_trim(skb, skb->len-len); ++ return 0; ++} ++ ++static __inline__ unsigned long __nat25_timeout(_adapter *priv) ++{ ++ unsigned long timeout; ++ ++ timeout = jiffies - NAT25_AGEING_TIME*HZ; ++ ++ return timeout; ++} ++ ++ ++static __inline__ int __nat25_has_expired(_adapter *priv, ++ struct nat25_network_db_entry *fdb) ++{ ++ if(time_before_eq(fdb->ageing_timer, __nat25_timeout(priv))) ++ return 1; ++ ++ return 0; ++} ++ ++ ++static __inline__ void __nat25_generate_ipv4_network_addr(unsigned char *networkAddr, ++ unsigned int *ipAddr) ++{ ++ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); ++ ++ networkAddr[0] = NAT25_IPV4; ++ memcpy(networkAddr+7, (unsigned char *)ipAddr, 4); ++} ++ ++ ++static __inline__ void __nat25_generate_ipx_network_addr_with_node(unsigned char *networkAddr, ++ unsigned int *ipxNetAddr, unsigned char *ipxNodeAddr) ++{ ++ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); ++ ++ networkAddr[0] = NAT25_IPX; ++ memcpy(networkAddr+1, (unsigned char *)ipxNetAddr, 4); ++ memcpy(networkAddr+5, ipxNodeAddr, 6); ++} ++ ++ ++static __inline__ void __nat25_generate_ipx_network_addr_with_socket(unsigned char *networkAddr, ++ unsigned int *ipxNetAddr, unsigned short *ipxSocketAddr) ++{ ++ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); ++ ++ networkAddr[0] = NAT25_IPX; ++ memcpy(networkAddr+1, (unsigned char *)ipxNetAddr, 4); ++ memcpy(networkAddr+5, (unsigned char *)ipxSocketAddr, 2); ++} ++ ++ ++static __inline__ void __nat25_generate_apple_network_addr(unsigned char *networkAddr, ++ unsigned short *network, unsigned char *node) ++{ ++ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); ++ ++ networkAddr[0] = NAT25_APPLE; ++ memcpy(networkAddr+1, (unsigned char *)network, 2); ++ networkAddr[3] = *node; ++} ++ ++ ++static __inline__ void __nat25_generate_pppoe_network_addr(unsigned char *networkAddr, ++ unsigned char *ac_mac, unsigned short *sid) ++{ ++ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); ++ ++ networkAddr[0] = NAT25_PPPOE; ++ memcpy(networkAddr+1, (unsigned char *)sid, 2); ++ memcpy(networkAddr+3, (unsigned char *)ac_mac, 6); ++} ++ ++ ++#ifdef CL_IPV6_PASS ++static void __nat25_generate_ipv6_network_addr(unsigned char *networkAddr, ++ unsigned int *ipAddr) ++{ ++ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); ++ ++ networkAddr[0] = NAT25_IPV6; ++ memcpy(networkAddr+1, (unsigned char *)ipAddr, 16); ++} ++ ++ ++static unsigned char *scan_tlv(unsigned char *data, int len, unsigned char tag, unsigned char len8b) ++{ ++ while (len > 0) { ++ if (*data == tag && *(data+1) == len8b && len >= len8b*8) ++ return data+2; ++ ++ len -= (*(data+1))*8; ++ data += (*(data+1))*8; ++ } ++ return NULL; ++} ++ ++ ++static int update_nd_link_layer_addr(unsigned char *data, int len, unsigned char *replace_mac) ++{ ++ struct icmp6hdr *icmphdr = (struct icmp6hdr *)data; ++ unsigned char *mac; ++ ++ if (icmphdr->icmp6_type == NDISC_ROUTER_SOLICITATION) { ++ if (len >= 8) { ++ mac = scan_tlv(&data[8], len-8, 1, 1); ++ if (mac) { ++ _DEBUG_INFO("Router Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ mac[0],mac[1],mac[2],mac[3],mac[4],mac[5], ++ replace_mac[0],replace_mac[1],replace_mac[2],replace_mac[3],replace_mac[4],replace_mac[5]); ++ memcpy(mac, replace_mac, 6); ++ return 1; ++ } ++ } ++ } ++ else if (icmphdr->icmp6_type == NDISC_ROUTER_ADVERTISEMENT) { ++ if (len >= 16) { ++ mac = scan_tlv(&data[16], len-16, 1, 1); ++ if (mac) { ++ _DEBUG_INFO("Router Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ mac[0],mac[1],mac[2],mac[3],mac[4],mac[5], ++ replace_mac[0],replace_mac[1],replace_mac[2],replace_mac[3],replace_mac[4],replace_mac[5]); ++ memcpy(mac, replace_mac, 6); ++ return 1; ++ } ++ } ++ } ++ else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) { ++ if (len >= 24) { ++ mac = scan_tlv(&data[24], len-24, 1, 1); ++ if (mac) { ++ _DEBUG_INFO("Neighbor Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ mac[0],mac[1],mac[2],mac[3],mac[4],mac[5], ++ replace_mac[0],replace_mac[1],replace_mac[2],replace_mac[3],replace_mac[4],replace_mac[5]); ++ memcpy(mac, replace_mac, 6); ++ return 1; ++ } ++ } ++ } ++ else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) { ++ if (len >= 24) { ++ mac = scan_tlv(&data[24], len-24, 2, 1); ++ if (mac) { ++ _DEBUG_INFO("Neighbor Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ mac[0],mac[1],mac[2],mac[3],mac[4],mac[5], ++ replace_mac[0],replace_mac[1],replace_mac[2],replace_mac[3],replace_mac[4],replace_mac[5]); ++ memcpy(mac, replace_mac, 6); ++ return 1; ++ } ++ } ++ } ++ else if (icmphdr->icmp6_type == NDISC_REDIRECT) { ++ if (len >= 40) { ++ mac = scan_tlv(&data[40], len-40, 2, 1); ++ if (mac) { ++ _DEBUG_INFO("Redirect, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ mac[0],mac[1],mac[2],mac[3],mac[4],mac[5], ++ replace_mac[0],replace_mac[1],replace_mac[2],replace_mac[3],replace_mac[4],replace_mac[5]); ++ memcpy(mac, replace_mac, 6); ++ return 1; ++ } ++ } ++ } ++ return 0; ++} ++ ++ ++static void convert_ipv6_mac_to_mc(struct sk_buff *skb) ++{ ++ struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN); ++ unsigned char *dst_mac = skb->data; ++ ++ //dst_mac[0] = 0xff; ++ //dst_mac[1] = 0xff; ++ /*modified by qinjunjie,ipv6 multicast address ix 0x33-33-xx-xx-xx-xx*/ ++ dst_mac[0] = 0x33; ++ dst_mac[1] = 0x33; ++ memcpy(&dst_mac[2], &iph->daddr.s6_addr32[3], 4); ++ #if defined(__LINUX_2_6__) ++ /*modified by qinjunjie,warning:should not remove next line*/ ++ skb->pkt_type = PACKET_MULTICAST; ++ #endif ++} ++#endif /* CL_IPV6_PASS */ ++ ++ ++static __inline__ int __nat25_network_hash(unsigned char *networkAddr) ++{ ++ if(networkAddr[0] == NAT25_IPV4) ++ { ++ unsigned long x; ++ ++ x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } ++ else if(networkAddr[0] == NAT25_IPX) ++ { ++ unsigned long x; ++ ++ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ ++ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } ++ else if(networkAddr[0] == NAT25_APPLE) ++ { ++ unsigned long x; ++ ++ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } ++ else if(networkAddr[0] == NAT25_PPPOE) ++ { ++ unsigned long x; ++ ++ x = networkAddr[0] ^ networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } ++#ifdef CL_IPV6_PASS ++ else if(networkAddr[0] == NAT25_IPV6) ++ { ++ unsigned long x; ++ ++ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ ++ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10] ^ ++ networkAddr[11] ^ networkAddr[12] ^ networkAddr[13] ^ networkAddr[14] ^ networkAddr[15] ^ ++ networkAddr[16]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } ++#endif ++ else ++ { ++ unsigned long x = 0; ++ int i; ++ ++ for (i=0; ibr_ext_lock, &irqL); ++ ++ ent->next_hash = priv->nethash[hash]; ++ if(ent->next_hash != NULL) ++ ent->next_hash->pprev_hash = &ent->next_hash; ++ priv->nethash[hash] = ent; ++ ent->pprev_hash = &priv->nethash[hash]; ++ ++ //_exit_critical_bh(&priv->br_ext_lock, &irqL); ++} ++ ++ ++static __inline__ void __network_hash_unlink(struct nat25_network_db_entry *ent) ++{ ++ // Caller must _enter_critical_bh already! ++ //_irqL irqL; ++ //_enter_critical_bh(&priv->br_ext_lock, &irqL); ++ ++ *(ent->pprev_hash) = ent->next_hash; ++ if(ent->next_hash != NULL) ++ ent->next_hash->pprev_hash = ent->pprev_hash; ++ ent->next_hash = NULL; ++ ent->pprev_hash = NULL; ++ ++ //_exit_critical_bh(&priv->br_ext_lock, &irqL); ++} ++ ++ ++static int __nat25_db_network_lookup_and_replace(_adapter *priv, ++ struct sk_buff *skb, unsigned char *networkAddr) ++{ ++ struct nat25_network_db_entry *db; ++ _irqL irqL; ++ _enter_critical_bh(&priv->br_ext_lock, &irqL); ++ ++ db = priv->nethash[__nat25_network_hash(networkAddr)]; ++ while (db != NULL) ++ { ++ if(!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) ++ { ++ if(!__nat25_has_expired(priv, db)) ++ { ++ // replace the destination mac address ++ memcpy(skb->data, db->macAddr, ETH_ALEN); ++ atomic_inc(&db->use_count); ++ ++#ifdef CL_IPV6_PASS ++ DEBUG_INFO("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" ++ "%02x%02x%02x%02x%02x%02x\n", ++ db->macAddr[0], ++ db->macAddr[1], ++ db->macAddr[2], ++ db->macAddr[3], ++ db->macAddr[4], ++ db->macAddr[5], ++ db->networkAddr[0], ++ db->networkAddr[1], ++ db->networkAddr[2], ++ db->networkAddr[3], ++ db->networkAddr[4], ++ db->networkAddr[5], ++ db->networkAddr[6], ++ db->networkAddr[7], ++ db->networkAddr[8], ++ db->networkAddr[9], ++ db->networkAddr[10], ++ db->networkAddr[11], ++ db->networkAddr[12], ++ db->networkAddr[13], ++ db->networkAddr[14], ++ db->networkAddr[15], ++ db->networkAddr[16]); ++#else ++ DEBUG_INFO("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", ++ db->macAddr[0], ++ db->macAddr[1], ++ db->macAddr[2], ++ db->macAddr[3], ++ db->macAddr[4], ++ db->macAddr[5], ++ db->networkAddr[0], ++ db->networkAddr[1], ++ db->networkAddr[2], ++ db->networkAddr[3], ++ db->networkAddr[4], ++ db->networkAddr[5], ++ db->networkAddr[6], ++ db->networkAddr[7], ++ db->networkAddr[8], ++ db->networkAddr[9], ++ db->networkAddr[10]); ++#endif ++ } ++ _exit_critical_bh(&priv->br_ext_lock, &irqL); ++ return 1; ++ } ++ ++ db = db->next_hash; ++ } ++ ++ _exit_critical_bh(&priv->br_ext_lock, &irqL); ++ return 0; ++} ++ ++ ++static void __nat25_db_network_insert(_adapter *priv, ++ unsigned char *macAddr, unsigned char *networkAddr) ++{ ++ struct nat25_network_db_entry *db; ++ int hash; ++ _irqL irqL; ++ _enter_critical_bh(&priv->br_ext_lock, &irqL); ++ ++ hash = __nat25_network_hash(networkAddr); ++ db = priv->nethash[hash]; ++ while (db != NULL) ++ { ++ if(!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) ++ { ++ memcpy(db->macAddr, macAddr, ETH_ALEN); ++ db->ageing_timer = jiffies; ++ _exit_critical_bh(&priv->br_ext_lock, &irqL); ++ return; ++ } ++ ++ db = db->next_hash; ++ } ++ ++ db = (struct nat25_network_db_entry *) rtw_malloc(sizeof(*db)); ++ if(db == NULL) { ++ _exit_critical_bh(&priv->br_ext_lock, &irqL); ++ return; ++ } ++ ++ memcpy(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN); ++ memcpy(db->macAddr, macAddr, ETH_ALEN); ++ atomic_set(&db->use_count, 1); ++ db->ageing_timer = jiffies; ++ ++ __network_hash_link(priv, db, hash); ++ ++ _exit_critical_bh(&priv->br_ext_lock, &irqL); ++} ++ ++ ++static void __nat25_db_print(_adapter *priv) ++{ ++ _irqL irqL; ++ _enter_critical_bh(&priv->br_ext_lock, &irqL); ++ ++#ifdef BR_EXT_DEBUG ++ static int counter = 0; ++ int i, j; ++ struct nat25_network_db_entry *db; ++ ++ counter++; ++ if((counter % 16) != 0) ++ return; ++ ++ for(i=0, j=0; inethash[i]; ++ ++ while (db != NULL) ++ { ++#ifdef CL_IPV6_PASS ++ panic_printk("NAT25: DB(%d) H(%02d) C(%d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" ++ "%02x%02x%02x%02x%02x%02x\n", ++ j, ++ i, ++ atomic_read(&db->use_count), ++ db->macAddr[0], ++ db->macAddr[1], ++ db->macAddr[2], ++ db->macAddr[3], ++ db->macAddr[4], ++ db->macAddr[5], ++ db->networkAddr[0], ++ db->networkAddr[1], ++ db->networkAddr[2], ++ db->networkAddr[3], ++ db->networkAddr[4], ++ db->networkAddr[5], ++ db->networkAddr[6], ++ db->networkAddr[7], ++ db->networkAddr[8], ++ db->networkAddr[9], ++ db->networkAddr[10], ++ db->networkAddr[11], ++ db->networkAddr[12], ++ db->networkAddr[13], ++ db->networkAddr[14], ++ db->networkAddr[15], ++ db->networkAddr[16]); ++#else ++ panic_printk("NAT25: DB(%d) H(%02d) C(%d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", ++ j, ++ i, ++ atomic_read(&db->use_count), ++ db->macAddr[0], ++ db->macAddr[1], ++ db->macAddr[2], ++ db->macAddr[3], ++ db->macAddr[4], ++ db->macAddr[5], ++ db->networkAddr[0], ++ db->networkAddr[1], ++ db->networkAddr[2], ++ db->networkAddr[3], ++ db->networkAddr[4], ++ db->networkAddr[5], ++ db->networkAddr[6], ++ db->networkAddr[7], ++ db->networkAddr[8], ++ db->networkAddr[9], ++ db->networkAddr[10]); ++#endif ++ j++; ++ ++ db = db->next_hash; ++ } ++ } ++#endif ++ ++ _exit_critical_bh(&priv->br_ext_lock, &irqL); ++} ++ ++ ++ ++ ++/* ++ * NAT2.5 interface ++ */ ++ ++void nat25_db_cleanup(_adapter *priv) ++{ ++ int i; ++ _irqL irqL; ++ _enter_critical_bh(&priv->br_ext_lock, &irqL); ++ ++ for(i=0; inethash[i]; ++ while (f != NULL) { ++ struct nat25_network_db_entry *g; ++ ++ g = f->next_hash; ++ if(priv->scdb_entry == f) ++ { ++ memset(priv->scdb_mac, 0, ETH_ALEN); ++ memset(priv->scdb_ip, 0, 4); ++ priv->scdb_entry = NULL; ++ } ++ __network_hash_unlink(f); ++ rtw_mfree((u8 *) f, sizeof(struct nat25_network_db_entry)); ++ ++ f = g; ++ } ++ } ++ ++ _exit_critical_bh(&priv->br_ext_lock, &irqL); ++} ++ ++ ++void nat25_db_expire(_adapter *priv) ++{ ++ int i; ++ _irqL irqL; ++ _enter_critical_bh(&priv->br_ext_lock, &irqL); ++ ++ //if(!priv->ethBrExtInfo.nat25_disable) ++ { ++ for (i=0; inethash[i]; ++ ++ while (f != NULL) ++ { ++ struct nat25_network_db_entry *g; ++ g = f->next_hash; ++ ++ if(__nat25_has_expired(priv, f)) ++ { ++ if(atomic_dec_and_test(&f->use_count)) ++ { ++#ifdef BR_EXT_DEBUG ++#ifdef CL_IPV6_PASS ++ panic_printk("NAT25 Expire H(%02d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" ++ "%02x%02x%02x%02x%02x%02x\n", ++ i, ++ f->macAddr[0], ++ f->macAddr[1], ++ f->macAddr[2], ++ f->macAddr[3], ++ f->macAddr[4], ++ f->macAddr[5], ++ f->networkAddr[0], ++ f->networkAddr[1], ++ f->networkAddr[2], ++ f->networkAddr[3], ++ f->networkAddr[4], ++ f->networkAddr[5], ++ f->networkAddr[6], ++ f->networkAddr[7], ++ f->networkAddr[8], ++ f->networkAddr[9], ++ f->networkAddr[10], ++ f->networkAddr[11], ++ f->networkAddr[12], ++ f->networkAddr[13], ++ f->networkAddr[14], ++ f->networkAddr[15], ++ f->networkAddr[16]); ++#else ++ ++ panic_printk("NAT25 Expire H(%02d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", ++ i, ++ f->macAddr[0], ++ f->macAddr[1], ++ f->macAddr[2], ++ f->macAddr[3], ++ f->macAddr[4], ++ f->macAddr[5], ++ f->networkAddr[0], ++ f->networkAddr[1], ++ f->networkAddr[2], ++ f->networkAddr[3], ++ f->networkAddr[4], ++ f->networkAddr[5], ++ f->networkAddr[6], ++ f->networkAddr[7], ++ f->networkAddr[8], ++ f->networkAddr[9], ++ f->networkAddr[10]); ++#endif ++#endif ++ if(priv->scdb_entry == f) ++ { ++ memset(priv->scdb_mac, 0, ETH_ALEN); ++ memset(priv->scdb_ip, 0, 4); ++ priv->scdb_entry = NULL; ++ } ++ __network_hash_unlink(f); ++ rtw_mfree((u8 *) f, sizeof(struct nat25_network_db_entry)); ++ } ++ } ++ ++ f = g; ++ } ++ } ++ } ++ ++ _exit_critical_bh(&priv->br_ext_lock, &irqL); ++} ++ ++ ++#ifdef SUPPORT_TX_MCAST2UNI ++static int checkIPMcAndReplace(_adapter *priv, struct sk_buff *skb, unsigned int *dst_ip) ++{ ++ struct stat_info *pstat; ++ struct list_head *phead, *plist; ++ int i; ++ ++ phead = &priv->asoc_list; ++ plist = phead->next; ++ ++ while (plist != phead) { ++ pstat = list_entry(plist, struct stat_info, asoc_list); ++ plist = plist->next; ++ ++ if (pstat->ipmc_num == 0) ++ continue; ++ ++ for (i=0; iipmc[i].used && !memcmp(&pstat->ipmc[i].mcmac[3], ((unsigned char *)dst_ip)+1, 3)) { ++ memcpy(skb->data, pstat->ipmc[i].mcmac, ETH_ALEN); ++ return 1; ++ } ++ } ++ } ++ return 0; ++} ++#endif ++ ++int nat25_db_handle(_adapter *priv, struct sk_buff *skb, int method) ++{ ++ unsigned short protocol; ++ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; ++ ++ if(skb == NULL) ++ return -1; ++ ++ if((method <= NAT25_MIN) || (method >= NAT25_MAX)) ++ return -1; ++ ++ protocol = *((unsigned short *)(skb->data + 2 * ETH_ALEN)); ++ ++ /*---------------------------------------------------*/ ++ /* Handle IP frame */ ++ /*---------------------------------------------------*/ ++ if(protocol == __constant_htons(ETH_P_IP)) ++ { ++ struct iphdr* iph = (struct iphdr *)(skb->data + ETH_HLEN); ++ ++ if(((unsigned char*)(iph) + (iph->ihl<<2)) >= (skb->data + ETH_HLEN + skb->len)) ++ { ++ DEBUG_WARN("NAT25: malformed IP packet !\n"); ++ return -1; ++ } ++ ++ switch(method) ++ { ++ case NAT25_CHECK: ++ return -1; ++ ++ case NAT25_INSERT: ++ { ++ //some muticast with source IP is all zero, maybe other case is illegal ++ //in class A, B, C, host address is all zero or all one is illegal ++ if (iph->saddr == 0) ++ return 0; ++ DEBUG_INFO("NAT25: Insert IP, SA=%08x, DA=%08x\n", iph->saddr, iph->daddr); ++ __nat25_generate_ipv4_network_addr(networkAddr, &iph->saddr); ++ //record source IP address and , source mac address into db ++ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); ++ ++ __nat25_db_print(priv); ++ } ++ return 0; ++ ++ case NAT25_LOOKUP: ++ { ++ DEBUG_INFO("NAT25: Lookup IP, SA=%08x, DA=%08x\n", iph->saddr, iph->daddr); ++#ifdef SUPPORT_TX_MCAST2UNI ++ if (priv->pshare->rf_ft_var.mc2u_disable || ++ ((((OPMODE & (WIFI_STATION_STATE|WIFI_ASOC_STATE)) ++ == (WIFI_STATION_STATE|WIFI_ASOC_STATE)) && ++ !checkIPMcAndReplace(priv, skb, &iph->daddr)) || ++ (OPMODE & WIFI_ADHOC_STATE))) ++#endif ++ { ++ __nat25_generate_ipv4_network_addr(networkAddr, &iph->daddr); ++ ++ if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) { ++ if (*((unsigned char *)&iph->daddr + 3) == 0xff) { ++ // L2 is unicast but L3 is broadcast, make L2 bacome broadcast ++ DEBUG_INFO("NAT25: Set DA as boardcast\n"); ++ memset(skb->data, 0xff, ETH_ALEN); ++ } ++ else { ++ // forward unknow IP packet to upper TCP/IP ++ DEBUG_INFO("NAT25: Replace DA with BR's MAC\n"); ++ if ( (*(u32 *)priv->br_mac) == 0 && (*(u16 *)(priv->br_mac+4)) == 0 ) { ++ void netdev_br_init(struct net_device *netdev); ++ printk("Re-init netdev_br_init() due to br_mac==0!\n"); ++ netdev_br_init(priv->pnetdev); ++ } ++ memcpy(skb->data, priv->br_mac, ETH_ALEN); ++ } ++ } ++ } ++ } ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++ ++ /*---------------------------------------------------*/ ++ /* Handle ARP frame */ ++ /*---------------------------------------------------*/ ++ else if(protocol == __constant_htons(ETH_P_ARP)) ++ { ++ struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN); ++ unsigned char *arp_ptr = (unsigned char *)(arp + 1); ++ unsigned int *sender, *target; ++ ++ if(arp->ar_pro != __constant_htons(ETH_P_IP)) ++ { ++ DEBUG_WARN("NAT25: arp protocol unknown (%4x)!\n", htons(arp->ar_pro)); ++ return -1; ++ } ++ ++ switch(method) ++ { ++ case NAT25_CHECK: ++ return 0; // skb_copy for all ARP frame ++ ++ case NAT25_INSERT: ++ { ++ DEBUG_INFO("NAT25: Insert ARP, MAC=%02x%02x%02x%02x%02x%02x\n", arp_ptr[0], ++ arp_ptr[1], arp_ptr[2], arp_ptr[3], arp_ptr[4], arp_ptr[5]); ++ ++ // change to ARP sender mac address to wlan STA address ++ memcpy(arp_ptr, GET_MY_HWADDR(priv), ETH_ALEN); ++ ++ arp_ptr += arp->ar_hln; ++ sender = (unsigned int *)arp_ptr; ++ ++ __nat25_generate_ipv4_network_addr(networkAddr, sender); ++ ++ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); ++ ++ __nat25_db_print(priv); ++ } ++ return 0; ++ ++ case NAT25_LOOKUP: ++ { ++ DEBUG_INFO("NAT25: Lookup ARP\n"); ++ ++ arp_ptr += arp->ar_hln; ++ sender = (unsigned int *)arp_ptr; ++ arp_ptr += (arp->ar_hln + arp->ar_pln); ++ target = (unsigned int *)arp_ptr; ++ ++ __nat25_generate_ipv4_network_addr(networkAddr, target); ++ ++ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); ++ ++ // change to ARP target mac address to Lookup result ++ arp_ptr = (unsigned char *)(arp + 1); ++ arp_ptr += (arp->ar_hln + arp->ar_pln); ++ memcpy(arp_ptr, skb->data, ETH_ALEN); ++ } ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++ ++ /*---------------------------------------------------*/ ++ /* Handle IPX and Apple Talk frame */ ++ /*---------------------------------------------------*/ ++ else if((protocol == __constant_htons(ETH_P_IPX)) || ++ (protocol <= __constant_htons(ETH_FRAME_LEN))) ++ { ++ unsigned char ipx_header[2] = {0xFF, 0xFF}; ++ struct ipxhdr *ipx = NULL; ++ struct elapaarp *ea = NULL; ++ struct ddpehdr *ddp = NULL; ++ unsigned char *framePtr = skb->data + ETH_HLEN; ++ ++ if(protocol == __constant_htons(ETH_P_IPX)) ++ { ++ DEBUG_INFO("NAT25: Protocol=IPX (Ethernet II)\n"); ++ ipx = (struct ipxhdr *)framePtr; ++ } ++ else if(protocol <= __constant_htons(ETH_FRAME_LEN)) ++ { ++ if(!memcmp(ipx_header, framePtr, 2)) ++ { ++ DEBUG_INFO("NAT25: Protocol=IPX (Ethernet 802.3)\n"); ++ ipx = (struct ipxhdr *)framePtr; ++ } ++ else ++ { ++ unsigned char ipx_8022_type = 0xE0; ++ unsigned char snap_8022_type = 0xAA; ++ ++ if(*framePtr == snap_8022_type) ++ { ++ unsigned char ipx_snap_id[5] = {0x0, 0x0, 0x0, 0x81, 0x37}; // IPX SNAP ID ++ unsigned char aarp_snap_id[5] = {0x00, 0x00, 0x00, 0x80, 0xF3}; // Apple Talk AARP SNAP ID ++ unsigned char ddp_snap_id[5] = {0x08, 0x00, 0x07, 0x80, 0x9B}; // Apple Talk DDP SNAP ID ++ ++ framePtr += 3; // eliminate the 802.2 header ++ ++ if(!memcmp(ipx_snap_id, framePtr, 5)) ++ { ++ framePtr += 5; // eliminate the SNAP header ++ ++ DEBUG_INFO("NAT25: Protocol=IPX (Ethernet SNAP)\n"); ++ ipx = (struct ipxhdr *)framePtr; ++ } ++ else if(!memcmp(aarp_snap_id, framePtr, 5)) ++ { ++ framePtr += 5; // eliminate the SNAP header ++ ++ ea = (struct elapaarp *)framePtr; ++ } ++ else if(!memcmp(ddp_snap_id, framePtr, 5)) ++ { ++ framePtr += 5; // eliminate the SNAP header ++ ++ ddp = (struct ddpehdr *)framePtr; ++ } ++ else ++ { ++ DEBUG_WARN("NAT25: Protocol=Ethernet SNAP %02x%02x%02x%02x%02x\n", framePtr[0], ++ framePtr[1], framePtr[2], framePtr[3], framePtr[4]); ++ return -1; ++ } ++ } ++ else if(*framePtr == ipx_8022_type) ++ { ++ framePtr += 3; // eliminate the 802.2 header ++ ++ if(!memcmp(ipx_header, framePtr, 2)) ++ { ++ DEBUG_INFO("NAT25: Protocol=IPX (Ethernet 802.2)\n"); ++ ipx = (struct ipxhdr *)framePtr; ++ } ++ else ++ return -1; ++ } ++ else ++ return -1; ++ } ++ } ++ else ++ return -1; ++ ++ /* IPX */ ++ if(ipx != NULL) ++ { ++ switch(method) ++ { ++ case NAT25_CHECK: ++ if(!memcmp(skb->data+ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) ++ { ++ DEBUG_INFO("NAT25: Check IPX skb_copy\n"); ++ return 0; ++ } ++ return -1; ++ ++ case NAT25_INSERT: ++ { ++ DEBUG_INFO("NAT25: Insert IPX, Dest=%08x,%02x%02x%02x%02x%02x%02x,%04x Source=%08x,%02x%02x%02x%02x%02x%02x,%04x\n", ++ ipx->ipx_dest.net, ++ ipx->ipx_dest.node[0], ++ ipx->ipx_dest.node[1], ++ ipx->ipx_dest.node[2], ++ ipx->ipx_dest.node[3], ++ ipx->ipx_dest.node[4], ++ ipx->ipx_dest.node[5], ++ ipx->ipx_dest.sock, ++ ipx->ipx_source.net, ++ ipx->ipx_source.node[0], ++ ipx->ipx_source.node[1], ++ ipx->ipx_source.node[2], ++ ipx->ipx_source.node[3], ++ ipx->ipx_source.node[4], ++ ipx->ipx_source.node[5], ++ ipx->ipx_source.sock); ++ ++ if(!memcmp(skb->data+ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) ++ { ++ DEBUG_INFO("NAT25: Use IPX Net, and Socket as network addr\n"); ++ ++ __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_source.net, &ipx->ipx_source.sock); ++ ++ // change IPX source node addr to wlan STA address ++ memcpy(ipx->ipx_source.node, GET_MY_HWADDR(priv), ETH_ALEN); ++ } ++ else ++ { ++ __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_source.net, ipx->ipx_source.node); ++ } ++ ++ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); ++ ++ __nat25_db_print(priv); ++ } ++ return 0; ++ ++ case NAT25_LOOKUP: ++ { ++ if(!memcmp(GET_MY_HWADDR(priv), ipx->ipx_dest.node, ETH_ALEN)) ++ { ++ DEBUG_INFO("NAT25: Lookup IPX, Modify Destination IPX Node addr\n"); ++ ++ __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_dest.net, &ipx->ipx_dest.sock); ++ ++ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); ++ ++ // replace IPX destination node addr with Lookup destination MAC addr ++ memcpy(ipx->ipx_dest.node, skb->data, ETH_ALEN); ++ } ++ else ++ { ++ __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_dest.net, ipx->ipx_dest.node); ++ ++ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); ++ } ++ } ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++ ++ /* AARP */ ++ else if(ea != NULL) ++ { ++ /* Sanity check fields. */ ++ if(ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN) ++ { ++ DEBUG_WARN("NAT25: Appletalk AARP Sanity check fail!\n"); ++ return -1; ++ } ++ ++ switch(method) ++ { ++ case NAT25_CHECK: ++ return 0; ++ ++ case NAT25_INSERT: ++ { ++ // change to AARP source mac address to wlan STA address ++ memcpy(ea->hw_src, GET_MY_HWADDR(priv), ETH_ALEN); ++ ++ DEBUG_INFO("NAT25: Insert AARP, Source=%d,%d Destination=%d,%d\n", ++ ea->pa_src_net, ++ ea->pa_src_node, ++ ea->pa_dst_net, ++ ea->pa_dst_node); ++ ++ __nat25_generate_apple_network_addr(networkAddr, &ea->pa_src_net, &ea->pa_src_node); ++ ++ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); ++ ++ __nat25_db_print(priv); ++ } ++ return 0; ++ ++ case NAT25_LOOKUP: ++ { ++ DEBUG_INFO("NAT25: Lookup AARP, Source=%d,%d Destination=%d,%d\n", ++ ea->pa_src_net, ++ ea->pa_src_node, ++ ea->pa_dst_net, ++ ea->pa_dst_node); ++ ++ __nat25_generate_apple_network_addr(networkAddr, &ea->pa_dst_net, &ea->pa_dst_node); ++ ++ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); ++ ++ // change to AARP destination mac address to Lookup result ++ memcpy(ea->hw_dst, skb->data, ETH_ALEN); ++ } ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++ ++ /* DDP */ ++ else if(ddp != NULL) ++ { ++ switch(method) ++ { ++ case NAT25_CHECK: ++ return -1; ++ ++ case NAT25_INSERT: ++ { ++ DEBUG_INFO("NAT25: Insert DDP, Source=%d,%d Destination=%d,%d\n", ++ ddp->deh_snet, ++ ddp->deh_snode, ++ ddp->deh_dnet, ++ ddp->deh_dnode); ++ ++ __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_snet, &ddp->deh_snode); ++ ++ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); ++ ++ __nat25_db_print(priv); ++ } ++ return 0; ++ ++ case NAT25_LOOKUP: ++ { ++ DEBUG_INFO("NAT25: Lookup DDP, Source=%d,%d Destination=%d,%d\n", ++ ddp->deh_snet, ++ ddp->deh_snode, ++ ddp->deh_dnet, ++ ddp->deh_dnode); ++ ++ __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_dnet, &ddp->deh_dnode); ++ ++ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); ++ } ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++ ++ return -1; ++ } ++ ++ /*---------------------------------------------------*/ ++ /* Handle PPPoE frame */ ++ /*---------------------------------------------------*/ ++ else if((protocol == __constant_htons(ETH_P_PPP_DISC)) || ++ (protocol == __constant_htons(ETH_P_PPP_SES))) ++ { ++ struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN); ++ unsigned short *pMagic; ++ ++ switch(method) ++ { ++ case NAT25_CHECK: ++ if (ph->sid == 0) ++ return 0; ++ return 1; ++ ++ case NAT25_INSERT: ++ if(ph->sid == 0) // Discovery phase according to tag ++ { ++ if(ph->code == PADI_CODE || ph->code == PADR_CODE) ++ { ++ if (priv->ethBrExtInfo.addPPPoETag) { ++ struct pppoe_tag *tag, *pOldTag; ++ unsigned char tag_buf[40]; ++ int old_tag_len=0; ++ ++ tag = (struct pppoe_tag *)tag_buf; ++ pOldTag = (struct pppoe_tag *)__nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID)); ++ if (pOldTag) { // if SID existed, copy old value and delete it ++ old_tag_len = ntohs(pOldTag->tag_len); ++ if (old_tag_len+TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN > sizeof(tag_buf)) { ++ DEBUG_ERR("SID tag length too long!\n"); ++ return -1; ++ } ++ ++ memcpy(tag->tag_data+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN, ++ pOldTag->tag_data, old_tag_len); ++ ++ if (skb_pull_and_merge(skb, (unsigned char *)pOldTag, TAG_HDR_LEN+old_tag_len) < 0) { ++ DEBUG_ERR("call skb_pull_and_merge() failed in PADI/R packet!\n"); ++ return -1; ++ } ++ ph->length = htons(ntohs(ph->length)-TAG_HDR_LEN-old_tag_len); ++ } ++ ++ tag->tag_type = PTT_RELAY_SID; ++ tag->tag_len = htons(MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN+old_tag_len); ++ ++ // insert the magic_code+client mac in relay tag ++ pMagic = (unsigned short *)tag->tag_data; ++ *pMagic = htons(MAGIC_CODE); ++ memcpy(tag->tag_data+MAGIC_CODE_LEN, skb->data+ETH_ALEN, ETH_ALEN); ++ ++ //Add relay tag ++ if(__nat25_add_pppoe_tag(skb, tag) < 0) ++ return -1; ++ ++ DEBUG_INFO("NAT25: Insert PPPoE, forward %s packet\n", ++ (ph->code == PADI_CODE ? "PADI" : "PADR")); ++ } ++ else { // not add relay tag ++ if (priv->pppoe_connection_in_progress && ++ memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN)) { ++ DEBUG_ERR("Discard PPPoE packet due to another PPPoE connection is in progress!\n"); ++ return -2; ++ } ++ ++ if (priv->pppoe_connection_in_progress == 0) ++ memcpy(priv->pppoe_addr, skb->data+ETH_ALEN, ETH_ALEN); ++ ++ priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE; ++ } ++ } ++ else ++ return -1; ++ } ++ else // session phase ++ { ++ DEBUG_INFO("NAT25: Insert PPPoE, insert session packet to %s\n", skb->dev->name); ++ ++ __nat25_generate_pppoe_network_addr(networkAddr, skb->data, &(ph->sid)); ++ ++ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); ++ ++ __nat25_db_print(priv); ++ ++ if (!priv->ethBrExtInfo.addPPPoETag && ++ priv->pppoe_connection_in_progress && ++ !memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN)) ++ priv->pppoe_connection_in_progress = 0; ++ } ++ return 0; ++ ++ case NAT25_LOOKUP: ++ if(ph->code == PADO_CODE || ph->code == PADS_CODE) ++ { ++ if (priv->ethBrExtInfo.addPPPoETag) { ++ struct pppoe_tag *tag; ++ unsigned char *ptr; ++ unsigned short tagType, tagLen; ++ int offset=0; ++ ++ if((ptr = __nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID))) == 0) { ++ DEBUG_ERR("Fail to find PTT_RELAY_SID in FADO!\n"); ++ return -1; ++ } ++ ++ tag = (struct pppoe_tag *)ptr; ++ tagType = (unsigned short)((ptr[0] << 8) + ptr[1]); ++ tagLen = (unsigned short)((ptr[2] << 8) + ptr[3]); ++ ++ if((tagType != ntohs(PTT_RELAY_SID)) || (tagLen < (MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN))) { ++ DEBUG_ERR("Invalid PTT_RELAY_SID tag length [%d]!\n", tagLen); ++ return -1; ++ } ++ ++ pMagic = (unsigned short *)tag->tag_data; ++ if (ntohs(*pMagic) != MAGIC_CODE) { ++ DEBUG_ERR("Can't find MAGIC_CODE in %s packet!\n", ++ (ph->code == PADO_CODE ? "PADO" : "PADS")); ++ return -1; ++ } ++ ++ memcpy(skb->data, tag->tag_data+MAGIC_CODE_LEN, ETH_ALEN); ++ ++ if (tagLen > MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN) ++ offset = TAG_HDR_LEN; ++ ++ if (skb_pull_and_merge(skb, ptr+offset, TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN-offset) < 0) { ++ DEBUG_ERR("call skb_pull_and_merge() failed in PADO packet!\n"); ++ return -1; ++ } ++ ph->length = htons(ntohs(ph->length)-(TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN-offset)); ++ if (offset > 0) ++ tag->tag_len = htons(tagLen-MAGIC_CODE_LEN-RTL_RELAY_TAG_LEN); ++ ++ DEBUG_INFO("NAT25: Lookup PPPoE, forward %s Packet from %s\n", ++ (ph->code == PADO_CODE ? "PADO" : "PADS"), skb->dev->name); ++ } ++ else { // not add relay tag ++ if (!priv->pppoe_connection_in_progress) { ++ DEBUG_ERR("Discard PPPoE packet due to no connection in progresss!\n"); ++ return -1; ++ } ++ memcpy(skb->data, priv->pppoe_addr, ETH_ALEN); ++ priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE; ++ } ++ } ++ else { ++ if(ph->sid != 0) ++ { ++ DEBUG_INFO("NAT25: Lookup PPPoE, lookup session packet from %s\n", skb->dev->name); ++ __nat25_generate_pppoe_network_addr(networkAddr, skb->data+ETH_ALEN, &(ph->sid)); ++ ++ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); ++ ++ __nat25_db_print(priv); ++ } ++ else ++ return -1; ++ ++ } ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++ ++ /*---------------------------------------------------*/ ++ /* Handle EAP frame */ ++ /*---------------------------------------------------*/ ++ else if(protocol == __constant_htons(0x888e)) ++ { ++ switch(method) ++ { ++ case NAT25_CHECK: ++ return -1; ++ ++ case NAT25_INSERT: ++ return 0; ++ ++ case NAT25_LOOKUP: ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++ ++ /*---------------------------------------------------*/ ++ /* Handle C-Media proprietary frame */ ++ /*---------------------------------------------------*/ ++ else if((protocol == __constant_htons(0xe2ae)) || ++ (protocol == __constant_htons(0xe2af))) ++ { ++ switch(method) ++ { ++ case NAT25_CHECK: ++ return -1; ++ ++ case NAT25_INSERT: ++ return 0; ++ ++ case NAT25_LOOKUP: ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++ ++ /*---------------------------------------------------*/ ++ /* Handle IPV6 frame */ ++ /*---------------------------------------------------*/ ++#ifdef CL_IPV6_PASS ++ else if(protocol == __constant_htons(ETH_P_IPV6)) ++ { ++ struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN); ++ ++ if (sizeof(*iph) >= (skb->len - ETH_HLEN)) ++ { ++ DEBUG_WARN("NAT25: malformed IPv6 packet !\n"); ++ return -1; ++ } ++ ++ switch(method) ++ { ++ case NAT25_CHECK: ++ if (skb->data[0] & 1) ++ return 0; ++ return -1; ++ ++ case NAT25_INSERT: ++ { ++ DEBUG_INFO("NAT25: Insert IP, SA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x," ++ " DA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n", ++ iph->saddr.s6_addr16[0],iph->saddr.s6_addr16[1],iph->saddr.s6_addr16[2],iph->saddr.s6_addr16[3], ++ iph->saddr.s6_addr16[4],iph->saddr.s6_addr16[5],iph->saddr.s6_addr16[6],iph->saddr.s6_addr16[7], ++ iph->daddr.s6_addr16[0],iph->daddr.s6_addr16[1],iph->daddr.s6_addr16[2],iph->daddr.s6_addr16[3], ++ iph->daddr.s6_addr16[4],iph->daddr.s6_addr16[5],iph->daddr.s6_addr16[6],iph->daddr.s6_addr16[7]); ++ ++ if (memcmp(&iph->saddr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16)) { ++ __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->saddr); ++ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); ++ __nat25_db_print(priv); ++ ++ if (iph->nexthdr == IPPROTO_ICMPV6 && ++ skb->len > (ETH_HLEN + sizeof(*iph) + 4)) { ++ if (update_nd_link_layer_addr(skb->data + ETH_HLEN + sizeof(*iph), ++ skb->len - ETH_HLEN - sizeof(*iph), GET_MY_HWADDR(priv))) { ++ struct icmp6hdr *hdr = (struct icmp6hdr *)(skb->data + ETH_HLEN + sizeof(*iph)); ++ hdr->icmp6_cksum = 0; ++ hdr->icmp6_cksum = csum_ipv6_magic(&iph->saddr, &iph->daddr, ++ iph->payload_len, ++ IPPROTO_ICMPV6, ++ csum_partial((__u8 *)hdr, iph->payload_len, 0)); ++ } ++ } ++ } ++ } ++ return 0; ++ ++ case NAT25_LOOKUP: ++ DEBUG_INFO("NAT25: Lookup IP, SA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x," ++ " DA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n", ++ iph->saddr.s6_addr16[0],iph->saddr.s6_addr16[1],iph->saddr.s6_addr16[2],iph->saddr.s6_addr16[3], ++ iph->saddr.s6_addr16[4],iph->saddr.s6_addr16[5],iph->saddr.s6_addr16[6],iph->saddr.s6_addr16[7], ++ iph->daddr.s6_addr16[0],iph->daddr.s6_addr16[1],iph->daddr.s6_addr16[2],iph->daddr.s6_addr16[3], ++ iph->daddr.s6_addr16[4],iph->daddr.s6_addr16[5],iph->daddr.s6_addr16[6],iph->daddr.s6_addr16[7]); ++ ++ ++ __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->daddr); ++ if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) { ++#ifdef SUPPORT_RX_UNI2MCAST ++ if (iph->daddr.s6_addr[0] == 0xff) ++ convert_ipv6_mac_to_mc(skb); ++#endif ++ } ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++#endif // CL_IPV6_PASS ++ ++ return -1; ++} ++ ++ ++int nat25_handle_frame(_adapter *priv, struct sk_buff *skb) ++{ ++#ifdef BR_EXT_DEBUG ++ if((!priv->ethBrExtInfo.nat25_disable) && (!(skb->data[0] & 1))) ++ { ++ panic_printk("NAT25: Input Frame: DA=%02x%02x%02x%02x%02x%02x SA=%02x%02x%02x%02x%02x%02x\n", ++ skb->data[0], ++ skb->data[1], ++ skb->data[2], ++ skb->data[3], ++ skb->data[4], ++ skb->data[5], ++ skb->data[6], ++ skb->data[7], ++ skb->data[8], ++ skb->data[9], ++ skb->data[10], ++ skb->data[11]); ++ } ++#endif ++ ++ if(!(skb->data[0] & 1)) ++ { ++ int is_vlan_tag=0, i, retval=0; ++ unsigned short vlan_hdr=0; ++ ++ if (*((unsigned short *)(skb->data+ETH_ALEN*2)) == __constant_htons(ETH_P_8021Q)) { ++ is_vlan_tag = 1; ++ vlan_hdr = *((unsigned short *)(skb->data+ETH_ALEN*2+2)); ++ for (i=0; i<6; i++) ++ *((unsigned short *)(skb->data+ETH_ALEN*2+2-i*2)) = *((unsigned short *)(skb->data+ETH_ALEN*2-2-i*2)); ++ skb_pull(skb, 4); ++ } ++ ++ if (!priv->ethBrExtInfo.nat25_disable) ++ { ++ _irqL irqL; ++ _enter_critical_bh(&priv->br_ext_lock, &irqL); ++ /* ++ * This function look up the destination network address from ++ * the NAT2.5 database. Return value = -1 means that the ++ * corresponding network protocol is NOT support. ++ */ ++ if (!priv->ethBrExtInfo.nat25sc_disable && ++ (*((unsigned short *)(skb->data+ETH_ALEN*2)) == __constant_htons(ETH_P_IP)) && ++ !memcmp(priv->scdb_ip, skb->data+ETH_HLEN+16, 4)) { ++ memcpy(skb->data, priv->scdb_mac, ETH_ALEN); ++ ++ _exit_critical_bh(&priv->br_ext_lock, &irqL); ++ } ++ else { ++ _exit_critical_bh(&priv->br_ext_lock, &irqL); ++ ++ retval = nat25_db_handle(priv, skb, NAT25_LOOKUP); ++ } ++ } ++ else { ++ if (((*((unsigned short *)(skb->data+ETH_ALEN*2)) == __constant_htons(ETH_P_IP)) && ++ !memcmp(priv->br_ip, skb->data+ETH_HLEN+16, 4)) || ++ ((*((unsigned short *)(skb->data+ETH_ALEN*2)) == __constant_htons(ETH_P_ARP)) && ++ !memcmp(priv->br_ip, skb->data+ETH_HLEN+24, 4))) { ++ // for traffic to upper TCP/IP ++ retval = nat25_db_handle(priv, skb, NAT25_LOOKUP); ++ } ++ } ++ ++ if (is_vlan_tag) { ++ skb_push(skb, 4); ++ for (i=0; i<6; i++) ++ *((unsigned short *)(skb->data+i*2)) = *((unsigned short *)(skb->data+4+i*2)); ++ *((unsigned short *)(skb->data+ETH_ALEN*2)) = __constant_htons(ETH_P_8021Q); ++ *((unsigned short *)(skb->data+ETH_ALEN*2+2)) = vlan_hdr; ++ } ++ ++ if(retval == -1) { ++ //DEBUG_ERR("NAT25: Lookup fail!\n"); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++#if 0 ++void mac_clone(_adapter *priv, unsigned char *addr) ++{ ++ struct sockaddr sa; ++ ++ memcpy(sa.sa_data, addr, ETH_ALEN); ++ DEBUG_INFO("MAC Clone: Addr=%02x%02x%02x%02x%02x%02x\n", ++ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); ++ rtl8192cd_set_hwaddr(priv->dev, &sa); ++} ++ ++ ++int mac_clone_handle_frame(_adapter *priv, struct sk_buff *skb) ++{ ++ if(priv->ethBrExtInfo.macclone_enable && !priv->macclone_completed) ++ { ++ if(!(skb->data[ETH_ALEN] & 1)) //// check any other particular MAC add ++ { ++ if(memcmp(skb->data+ETH_ALEN, GET_MY_HWADDR(priv), ETH_ALEN) && ++ ((priv->dev->br_port) && ++ memcmp(skb->data+ETH_ALEN, priv->br_mac, ETH_ALEN))) ++ { ++ mac_clone(priv, skb->data+ETH_ALEN); ++ priv->macclone_completed = 1; ++ } ++ } ++ } ++ ++ return 0; ++} ++#endif // 0 ++ ++#define SERVER_PORT 67 ++#define CLIENT_PORT 68 ++#define DHCP_MAGIC 0x63825363 ++#define BROADCAST_FLAG 0x8000 ++ ++struct dhcpMessage { ++ u_int8_t op; ++ u_int8_t htype; ++ u_int8_t hlen; ++ u_int8_t hops; ++ u_int32_t xid; ++ u_int16_t secs; ++ u_int16_t flags; ++ u_int32_t ciaddr; ++ u_int32_t yiaddr; ++ u_int32_t siaddr; ++ u_int32_t giaddr; ++ u_int8_t chaddr[16]; ++ u_int8_t sname[64]; ++ u_int8_t file[128]; ++ u_int32_t cookie; ++ u_int8_t options[308]; /* 312 - cookie */ ++}; ++ ++void dhcp_flag_bcast(_adapter *priv, struct sk_buff *skb) ++{ ++ if(skb == NULL) ++ return; ++ ++ if(!priv->ethBrExtInfo.dhcp_bcst_disable) ++ { ++ unsigned short protocol = *((unsigned short *)(skb->data + 2 * ETH_ALEN)); ++ ++ if(protocol == __constant_htons(ETH_P_IP)) // IP ++ { ++ struct iphdr* iph = (struct iphdr *)(skb->data + ETH_HLEN); ++ ++ if(iph->protocol == IPPROTO_UDP) // UDP ++ { ++ struct udphdr *udph = (struct udphdr *)((SIZE_PTR)iph + (iph->ihl << 2)); ++ ++ if((udph->source == __constant_htons(CLIENT_PORT)) ++ && (udph->dest == __constant_htons(SERVER_PORT))) // DHCP request ++ { ++ struct dhcpMessage *dhcph = ++ (struct dhcpMessage *)((SIZE_PTR)udph + sizeof(struct udphdr)); ++ ++ if(dhcph->cookie == __constant_htonl(DHCP_MAGIC)) // match magic word ++ { ++ if(!(dhcph->flags & htons(BROADCAST_FLAG))) // if not broadcast ++ { ++ register int sum = 0; ++ ++ DEBUG_INFO("DHCP: change flag of DHCP request to broadcast.\n"); ++ // or BROADCAST flag ++ dhcph->flags |= htons(BROADCAST_FLAG); ++ // recalculate checksum ++ sum = ~(udph->check) & 0xffff; ++ sum += dhcph->flags; ++ while(sum >> 16) ++ sum = (sum & 0xffff) + (sum >> 16); ++ udph->check = ~sum; ++ } ++ } ++ } ++ } ++ } ++ } ++} ++ ++ ++void *scdb_findEntry(_adapter *priv, unsigned char *macAddr, ++ unsigned char *ipAddr) ++{ ++ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; ++ struct nat25_network_db_entry *db; ++ int hash; ++ //_irqL irqL; ++ //_enter_critical_bh(&priv->br_ext_lock, &irqL); ++ ++ __nat25_generate_ipv4_network_addr(networkAddr, (unsigned int *)ipAddr); ++ hash = __nat25_network_hash(networkAddr); ++ db = priv->nethash[hash]; ++ while (db != NULL) ++ { ++ if(!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) { ++ //_exit_critical_bh(&priv->br_ext_lock, &irqL); ++ return (void *)db; ++ } ++ ++ db = db->next_hash; ++ } ++ ++ //_exit_critical_bh(&priv->br_ext_lock, &irqL); ++ return NULL; ++} ++ ++#endif // CONFIG_BR_EXT ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_bt_mp.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_bt_mp.c +new file mode 100644 +index 00000000..e3e0f3d9 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_bt_mp.c +@@ -0,0 +1,1735 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++ ++#include "rtw_bt_mp.h" ++#include ++#include ++ ++#ifdef CONFIG_RTL8723A ++ ++void MPh2c_timeout_handle(void *FunctionContext) ++{ ++ _adapter *pAdapter = (_adapter *)FunctionContext; ++ PMPT_CONTEXT pMptCtx=&pAdapter->mppriv.MptCtx; ++ ++ DBG_8192C("[MPT], MPh2c_timeout_handle \n"); ++ ++ pMptCtx->bMPh2c_timeout=_TRUE; ++ ++ _rtw_up_sema(&pMptCtx->MPh2c_Sema); ++ ++ //_cancel_timer_ex( &pMptCtx->MPh2c_timeout_timer); ++ ++ return; ++} ++u32 WaitC2Hevent( PADAPTER pAdapter,BOOLEAN *C2H_event ,u32 delay_time) ++{ ++ PMPT_CONTEXT pMptCtx=&(pAdapter->mppriv.MptCtx); ++ pMptCtx->bMPh2c_timeout=_FALSE; ++ DBG_8192C("WaitC2Hevent _set_timer \n"); ++ _set_timer( &pMptCtx->MPh2c_timeout_timer, delay_time ); ++ ++ _rtw_down_sema(&pMptCtx->MPh2c_Sema); ++ ++ if( pMptCtx->bMPh2c_timeout == _TRUE ) ++ { ++ C2H_event =_FALSE; ++ DBG_8192C("WaitC2Hevent bMPh2c_timeout _TRUE \n"); ++ return _FALSE; ++ } ++ ++ return _TRUE; ++ ++} ++ ++BT_CTRL_STATUS ++mptbt_CheckC2hFrame( ++ PADAPTER Adapter, ++ PBT_H2C pH2c, ++ PBT_EXT_C2H pExtC2h ++ ) ++{ ++ BT_CTRL_STATUS c2hStatus = BT_STATUS_C2H_SUCCESS; ++ ++ //DBG_8192C("[MPT], MPT rsp C2H hex: %x %x %x %x %x %x \n"), pExtC2h , pExtC2h+1 ,pExtC2h+2 ,pExtC2h+3 ,pExtC2h+4 ,pExtC2h+5); ++ ++ DBG_8192C("[MPT], statusCode = 0x%x\n", pExtC2h->statusCode); ++ DBG_8192C("[MPT], retLen = %d\n", pExtC2h->retLen); ++ DBG_8192C("[MPT], opCodeVer : req/rsp=%d/%d\n", pH2c->opCodeVer, pExtC2h->opCodeVer); ++ DBG_8192C("[MPT], reqNum : req/rsp=%d/%d\n", pH2c->reqNum, pExtC2h->reqNum); ++ if(pExtC2h->reqNum != pH2c->reqNum) ++ { ++ c2hStatus = BT_STATUS_C2H_REQNUM_MISMATCH; ++ DBG_8192C("[MPT], Error!! C2H reqNum Mismatch!!\n"); ++ } ++ else if(pExtC2h->opCodeVer != pH2c->opCodeVer) ++ { ++ c2hStatus = BT_STATUS_OPCODE_L_VERSION_MISMATCH; ++ DBG_8192C("[MPT], Error!! OPCode version L mismatch!!\n"); ++ } ++ ++ return c2hStatus; ++} ++ ++extern s32 FillH2CCmd(PADAPTER padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer); ++ ++BT_CTRL_STATUS ++mptbt_SendH2c( ++ PADAPTER Adapter, ++ PBT_H2C pH2c, ++ u2Byte h2cCmdLen ++ ) ++{ ++ //KIRQL OldIrql = KeGetCurrentIrql(); ++ BT_CTRL_STATUS h2cStatus=BT_STATUS_H2C_SUCCESS; ++ PMPT_CONTEXT pMptCtx=&(Adapter->mppriv.MptCtx); ++ u1Byte i; ++ ++ DBG_8192C("[MPT], mptbt_SendH2c()=========>\n"); ++ ++ //PlatformResetEvent(&pMptCtx->MptH2cRspEvent); ++ //PlatformResetEvent(&pMptCtx->MptBtC2hEvent); ++ ++// if(OldIrql == PASSIVE_LEVEL) ++// { ++ //RTPRINT_DATA(FMPBT, FMPBT_H2C_CONTENT, ("[MPT], MPT H2C hex: \n"), pH2c, h2cCmdLen); ++ ++ for(i=0; ih2cReqNum++; ++ pMptCtx->h2cReqNum %= 16; ++ ++ if(WaitC2Hevent(Adapter, &pMptCtx->MptH2cRspEvent, 200)) ++ { ++ DBG_8192C("[MPT], Received WiFi MptH2cRspEvent!!!\n"); ++ if(WaitC2Hevent(Adapter, &pMptCtx->MptBtC2hEvent, 800)) ++ { ++ DBG_8192C("[MPT], Received BT MptBtC2hEvent!!!\n"); ++ break; ++ } ++ else ++ { ++ DBG_8192C("[MPT], Error!!BT MptBtC2hEvent timeout!!\n"); ++ h2cStatus = BT_STATUS_H2C_BT_NO_RSP; ++ } ++ } ++ else ++ { ++ DBG_8192C("[MPT], Error!!WiFi MptH2cRspEvent timeout!!\n"); ++ h2cStatus = BT_STATUS_H2C_TIMTOUT; ++ } ++ } ++// } ++// else ++// { ++// RT_ASSERT(FALSE, ("[MPT], mptbt_SendH2c() can only run under PASSIVE_LEVEL!!\n")); ++// h2cStatus = BT_STATUS_WRONG_LEVEL; ++// } ++ ++ DBG_8192C("[MPT], mptbt_SendH2c()<=========\n"); ++ return h2cStatus; ++} ++ ++ ++ ++BT_CTRL_STATUS ++mptbt_CheckBtRspStatus( ++ PADAPTER Adapter, ++ PBT_EXT_C2H pExtC2h ++ ) ++{ ++ BT_CTRL_STATUS retStatus=BT_OP_STATUS_SUCCESS; ++ ++ switch(pExtC2h->statusCode) ++ { ++ case BT_OP_STATUS_SUCCESS: ++ retStatus = BT_STATUS_BT_OP_SUCCESS; ++ DBG_8192C("[MPT], BT status : BT_STATUS_SUCCESS\n"); ++ break; ++ case BT_OP_STATUS_VERSION_MISMATCH: ++ retStatus = BT_STATUS_OPCODE_L_VERSION_MISMATCH; ++ DBG_8192C("[MPT], BT status : BT_STATUS_OPCODE_L_VERSION_MISMATCH\n"); ++ break; ++ case BT_OP_STATUS_UNKNOWN_OPCODE: ++ retStatus = BT_STATUS_UNKNOWN_OPCODE_L; ++ DBG_8192C("[MPT], BT status : BT_STATUS_UNKNOWN_OPCODE_L\n"); ++ break; ++ case BT_OP_STATUS_ERROR_PARAMETER: ++ retStatus = BT_STATUS_PARAMETER_FORMAT_ERROR_L; ++ DBG_8192C("[MPT], BT status : BT_STATUS_PARAMETER_FORMAT_ERROR_L\n"); ++ break; ++ default: ++ retStatus = BT_STATUS_UNKNOWN_STATUS_L; ++ DBG_8192C("[MPT], BT status : BT_STATUS_UNKNOWN_STATUS_L\n"); ++ break; ++ } ++ ++ return retStatus; ++} ++ ++ ++ ++BT_CTRL_STATUS ++mptbt_BtFwOpCodeProcess( ++ PADAPTER Adapter, ++ u1Byte btFwOpCode, ++ u1Byte opCodeVer, ++ pu1Byte pH2cPar, ++ u1Byte h2cParaLen ++ ) ++{ ++ u1Byte H2C_Parameter[6] ={0}; ++ PBT_H2C pH2c=(PBT_H2C)&H2C_Parameter[0]; ++ PMPT_CONTEXT pMptCtx=&(Adapter->mppriv.MptCtx); ++ PBT_EXT_C2H pExtC2h=(PBT_EXT_C2H)&pMptCtx->c2hBuf[0]; ++ u2Byte paraLen=0,i; ++ BT_CTRL_STATUS h2cStatus=BT_STATUS_H2C_SUCCESS, c2hStatus=BT_STATUS_C2H_SUCCESS; ++ BT_CTRL_STATUS retStatus=BT_STATUS_H2C_BT_NO_RSP; ++ ++ pH2c->opCode = btFwOpCode; ++ pH2c->opCodeVer = opCodeVer; ++ pH2c->reqNum = pMptCtx->h2cReqNum; ++ //PlatformMoveMemory(&pH2c->buf[0], pH2cPar, h2cParaLen); ++ //_rtw_memcpy(&pH2c->buf[0], pH2cPar, h2cParaLen); ++ _rtw_memcpy(pH2c->buf, pH2cPar, h2cParaLen); ++ ++ DBG_8192C("[MPT], pH2c->opCode=%d\n", pH2c->opCode); ++ DBG_8192C("[MPT], pH2c->opCodeVer=%d\n", pH2c->opCodeVer); ++ DBG_8192C("[MPT], pH2c->reqNum=%d\n", pH2c->reqNum); ++ DBG_8192C("[MPT], h2c parameter length=%d\n", h2cParaLen); ++ if(h2cParaLen) ++ { ++ DBG_8192C("[MPT], parameters(hex): \n"); ++ for(i=0;ibuf[i]); ++ } ++ } ++ ++ h2cStatus = mptbt_SendH2c(Adapter, pH2c, h2cParaLen+2); ++ if(BT_STATUS_H2C_SUCCESS == h2cStatus) ++ { ++ // if reach here, it means H2C get the correct c2h response, ++ c2hStatus = mptbt_CheckC2hFrame(Adapter, pH2c, pExtC2h); ++ if(BT_STATUS_C2H_SUCCESS == c2hStatus) ++ { ++ retStatus = mptbt_CheckBtRspStatus(Adapter, pExtC2h); ++ } ++ else ++ { ++ DBG_8192C("[MPT], Error!! C2H failed for pH2c->opCode=%d\n", pH2c->opCode); ++ // check c2h status error, return error status code to upper layer. ++ retStatus = c2hStatus; ++ } ++ } ++ else ++ { ++ DBG_8192C("[MPT], Error!! H2C failed for pH2c->opCode=%d\n", pH2c->opCode); ++ // check h2c status error, return error status code to upper layer. ++ retStatus = h2cStatus; ++ } ++ ++ return retStatus; ++} ++ ++ ++ ++ ++u2Byte ++mptbt_BtReady( ++ PADAPTER Adapter, ++ PBT_REQ_CMD pBtReq, ++ PBT_RSP_CMD pBtRsp ++ ) ++{ ++ u1Byte h2cParaBuf[6] ={0}; ++ u1Byte h2cParaLen=0; ++ u2Byte paraLen=0; ++ u1Byte retStatus=BT_STATUS_BT_OP_SUCCESS; ++ u1Byte btOpcode; ++ u1Byte btOpcodeVer=0; ++ PMPT_CONTEXT pMptCtx=&(Adapter->mppriv.MptCtx); ++ PBT_EXT_C2H pExtC2h=(PBT_EXT_C2H)&pMptCtx->c2hBuf[0]; ++ u1Byte i; ++ u1Byte btFwVer=0, bdAddr[6]={0}; ++ u2Byte btRealFwVer=0; ++ pu2Byte pu2Tmp=NULL; ++ ++ // ++ // check upper layer parameters ++ // ++ ++ // 1. check upper layer opcode version ++ if(pBtReq->opCodeVer != 1) ++ { ++ DBG_8192C("[MPT], Error!! Upper OP code version not match!!!\n"); ++ pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; ++ return paraLen; ++ } ++ ++ pBtRsp->pParamStart[0] = MP_BT_NOT_READY; ++ paraLen = 10; ++ // ++ // execute lower layer opcodes ++ // ++ ++ // Get BT FW version ++ // fill h2c parameters ++ btOpcode = BT_LO_OP_GET_BT_VERSION; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ else ++ { ++ pu2Tmp = (pu2Byte)&pExtC2h->buf[0]; ++ btRealFwVer = *pu2Tmp; ++ btFwVer = pExtC2h->buf[1]; ++ DBG_8192C("[MPT], btRealFwVer=0x%x, btFwVer=0x%x\n", btRealFwVer, btFwVer); ++ } ++ ++ // Get BD Address ++ // fill h2c parameters ++ btOpcode = BT_LO_OP_GET_BD_ADDR_L; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ else ++ { ++ bdAddr[5] = pExtC2h->buf[0]; ++ bdAddr[4] = pExtC2h->buf[1]; ++ bdAddr[3] = pExtC2h->buf[2]; ++ } ++ ++ // fill h2c parameters ++ btOpcode = BT_LO_OP_GET_BD_ADDR_H; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ else ++ { ++ bdAddr[2] = pExtC2h->buf[0]; ++ bdAddr[1] = pExtC2h->buf[1]; ++ bdAddr[0] = pExtC2h->buf[2]; ++ } ++ DBG_8192C("[MPT], Local BDAddr:"); ++ for(i=0; i<6; i++) ++ { ++ DBG_8192C(" 0x%x ", bdAddr[i]); ++ } ++ pBtRsp->status = BT_STATUS_SUCCESS; ++ pBtRsp->pParamStart[0] = MP_BT_READY; ++ pu2Tmp = (pu2Byte)&pBtRsp->pParamStart[1]; ++ *pu2Tmp = btRealFwVer; ++ pBtRsp->pParamStart[3] = btFwVer; ++ for(i=0; i<6; i++) ++ { ++ pBtRsp->pParamStart[4+i] = bdAddr[5-i]; ++ } ++ ++ return paraLen; ++} ++ ++void mptbt_close_WiFiRF(PADAPTER Adapter) ++{ ++ PHY_SetBBReg(Adapter, 0x824, 0xF, 0x0); ++ PHY_SetBBReg(Adapter, 0x824, 0x700000, 0x0); ++ PHY_SetRFReg(Adapter, RF90_PATH_A, 0x0, 0xF0000, 0x0); ++} ++ ++void mptbt_open_WiFiRF(PADAPTER Adapter) ++{ ++ PHY_SetBBReg(Adapter, 0x824, 0x700000, 0x3); ++ PHY_SetBBReg(Adapter, 0x824, 0xF, 0x2); ++ PHY_SetRFReg(Adapter, RF90_PATH_A, 0x0, 0xF0000, 0x3); ++} ++ ++u4Byte mptbt_switch_RF(PADAPTER Adapter, u1Byte Enter) ++{ ++ u2Byte tmp_2byte = 0; ++ ++ //Enter test mode ++ if (Enter) { ++ ////1>. close WiFi RF ++ mptbt_close_WiFiRF(Adapter); ++ ++ ////2>. change ant switch to BT ++ tmp_2byte = rtw_read16(Adapter, 0x860); ++ tmp_2byte = tmp_2byte | BIT(9); ++ tmp_2byte = tmp_2byte & (~BIT(8)); ++ rtw_write16(Adapter, 0x860, tmp_2byte); ++ rtw_write16(Adapter, 0x870, 0x300); ++ } else { ++ ////1>. Open WiFi RF ++ mptbt_open_WiFiRF(Adapter); ++ ++ ////2>. change ant switch back ++ tmp_2byte = rtw_read16(Adapter, 0x860); ++ tmp_2byte = tmp_2byte | BIT(8); ++ tmp_2byte = tmp_2byte & (~BIT(9)); ++ rtw_write16(Adapter, 0x860, tmp_2byte); ++ rtw_write16(Adapter, 0x870, 0x300); ++ } ++ ++ return 0; ++} ++ ++u2Byte ++mptbt_BtSetMode( ++ PADAPTER Adapter, ++ PBT_REQ_CMD pBtReq, ++ PBT_RSP_CMD pBtRsp ++ ) ++{ ++ u1Byte h2cParaBuf[6] ={0}; ++ u1Byte h2cParaLen=0; ++ u2Byte paraLen=0; ++ u1Byte retStatus=BT_STATUS_BT_OP_SUCCESS; ++ u1Byte btOpcode; ++ u1Byte btOpcodeVer=0; ++ u1Byte btModeToSet=0; ++ ++ // ++ // check upper layer parameters ++ // ++ // 1. check upper layer opcode version ++ if(pBtReq->opCodeVer != 1) ++ { ++ DBG_8192C("[MPT], Error!! Upper OP code version not match!!!\n"); ++ pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; ++ return paraLen; ++ } ++ // 2. check upper layer parameter length ++ if(1 == pBtReq->paraLength) ++ { ++ btModeToSet = pBtReq->pParamStart[0]; ++ DBG_8192C("[MPT], BtTestMode=%d \n", btModeToSet); ++ } ++ else ++ { ++ DBG_8192C("[MPT], Error!! wrong parameter length=%d (should be 1)\n", pBtReq->paraLength); ++ pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; ++ return paraLen; ++ } ++ ++ // ++ // execute lower layer opcodes ++ // ++ ++ // 1. fill h2c parameters ++ // check bt mode ++ btOpcode = BT_LO_OP_SET_BT_MODE; ++ if(btModeToSet >= MP_BT_MODE_MAX) ++ { ++ pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ else ++ { ++ mptbt_switch_RF(Adapter, 1); ++ ++ h2cParaBuf[0] = btModeToSet; ++ h2cParaLen = 1; ++ // 2. execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ } ++ ++ // 3. construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS == retStatus) ++ { ++ pBtRsp->status = BT_STATUS_SUCCESS; ++ } ++ else ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ } ++ ++ return paraLen; ++} ++ ++ ++VOID ++MPTBT_FwC2hBtMpCtrl( ++ PADAPTER Adapter, ++ pu1Byte tmpBuf, ++ u1Byte length ++ ) ++{ ++ u32 i; ++ PMPT_CONTEXT pMptCtx=&(Adapter->mppriv.MptCtx); ++ PBT_EXT_C2H pExtC2h=(PBT_EXT_C2H)tmpBuf; ++ ++ if(Adapter->bBTFWReady == _FALSE || Adapter->registrypriv.mp_mode == 0 ) ++ { ++ DBG_8192C("[MPT], %s,bBTFWReady == _FALSE\n",__func__); ++ return; ++ } ++ //cancel_timeout for h2c handle ++ _cancel_timer_ex( &pMptCtx->MPh2c_timeout_timer); ++ ++ DBG_8192C("[MPT], MPTBT_FwC2hBtMpCtrl(), hex: \n"); ++ for(i=0;i<=length;i++) ++ { ++ //DBG_8192C("[MPT], MPTBT_FwC2hBtMpCtrl(), hex: \n",tmpBuf[i], length); ++ DBG_8192C(" 0x%x ",tmpBuf[i]); ++ } ++ DBG_8192C("\n [MPT], pExtC2h->extendId=0x%x\n", pExtC2h->extendId); ++ ++ switch(pExtC2h->extendId) ++ { ++ case EXT_C2H_WIFI_FW_ACTIVE_RSP: ++ DBG_8192C("[MPT], EXT_C2H_WIFI_FW_ACTIVE_RSP\n"); ++ DBG_8192C("[MPT], pExtC2h->buf hex: \n"); ++ if( length > 32 || length < 3 ) ++ break ; ++ for(i=0;i<=(length-3);i++) ++ DBG_8192C(" 0x%x ",pExtC2h->buf[i]); ++ //PlatformSetEvent(&pMptCtx->MptH2cRspEvent); ++ pMptCtx->MptH2cRspEvent=_TRUE; ++ _rtw_up_sema(&pMptCtx->MPh2c_Sema); ++ break; ++ case EXT_C2H_TRIG_BY_BT_FW: ++ DBG_8192C("[MPT], EXT_C2H_TRIG_BY_BT_FW\n"); ++ //PlatformMoveMemory(&pMptCtx->c2hBuf[0], tmpBuf, length); ++ _rtw_memcpy(&pMptCtx->c2hBuf[0], tmpBuf, length); ++ DBG_8192C("[MPT], pExtC2h->statusCode=0x%x\n", pExtC2h->statusCode); ++ DBG_8192C("[MPT], pExtC2h->retLen=0x%x\n", pExtC2h->retLen); ++ DBG_8192C("[MPT], pExtC2h->opCodeVer=0x%x\n", pExtC2h->opCodeVer); ++ DBG_8192C("[MPT], pExtC2h->reqNum=0x%x\n", pExtC2h->reqNum); ++ DBG_8192C("[MPT], pExtC2h->buf hex: \n"); ++ for(i=0;i<=(length-3);i++) ++ DBG_8192C(" 0x%x ",pExtC2h->buf[0]); ++ //PlatformSetEvent(&pMptCtx->MptBtC2hEvent); ++ pMptCtx->MptBtC2hEvent=_TRUE; ++ _rtw_up_sema(&pMptCtx->MPh2c_Sema); ++ break; ++ default: ++ DBG_8192C("[MPT], EXT_C2H Target not found,pExtC2h->extendId =%d ,pExtC2h->reqNum=%d\n",pExtC2h->extendId,pExtC2h->reqNum); ++ break; ++ } ++ ++ ++ ++} ++ ++ ++u2Byte ++mptbt_BtGetGeneral( ++ IN PADAPTER Adapter, ++ IN PBT_REQ_CMD pBtReq, ++ IN PBT_RSP_CMD pBtRsp ++ ) ++{ ++ PMPT_CONTEXT pMptCtx=&(Adapter->mppriv.MptCtx); ++ PBT_EXT_C2H pExtC2h=(PBT_EXT_C2H)&pMptCtx->c2hBuf[0]; ++ u1Byte h2cParaBuf[6] ={0}; ++ u1Byte h2cParaLen=0; ++ u2Byte paraLen=0; ++ u1Byte retStatus=BT_STATUS_BT_OP_SUCCESS; ++ u1Byte btOpcode, bdAddr[6]={0}; ++ u1Byte btOpcodeVer=0; ++ u1Byte getType=0, i; ++ u2Byte getParaLen=0, validParaLen=0; ++ u1Byte regType=0, reportType=0; ++ u4Byte regAddr=0, regValue=0; ++ pu4Byte pu4Tmp; ++ pu2Byte pu2Tmp; ++ pu1Byte pu1Tmp; ++ ++ // ++ // check upper layer parameters ++ // ++ ++ // check upper layer opcode version ++ if(pBtReq->opCodeVer != 1) ++ { ++ DBG_8192C("[MPT], Error!! Upper OP code version not match!!!\n"); ++ pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; ++ return paraLen; ++ } ++ // check upper layer parameter length ++ if(pBtReq->paraLength < 1) ++ { ++ DBG_8192C("[MPT], Error!! wrong parameter length=%d (should larger than 1)\n", pBtReq->paraLength); ++ pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; ++ return paraLen; ++ } ++ getParaLen = pBtReq->paraLength - 1; ++ getType = pBtReq->pParamStart[0]; ++ ++ DBG_8192C("[MPT], getType=%d, getParaLen=%d\n", getType, getParaLen); ++ ++ // check parameter first ++ switch(getType) ++ { ++ case BT_GGET_REG: ++ DBG_8192C("[MPT], [BT_GGET_REG]\n"); ++ validParaLen = 5; ++ if(getParaLen == validParaLen) ++ { ++ btOpcode = BT_LO_OP_READ_REG; ++ regType = pBtReq->pParamStart[1]; ++ pu4Tmp = (pu4Byte)&pBtReq->pParamStart[2]; ++ regAddr = *pu4Tmp; ++ DBG_8192C("[MPT], BT_GGET_REG regType=0x%x, regAddr=0x%x!!\n", ++ regType, regAddr); ++ if(regType >= BT_REG_MAX) ++ { ++ pBtRsp->status = (btOpcode<<8)| BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ else ++ { ++ if( ((BT_REG_RF==regType)&&(regAddr>0x7f)) || ++ ((BT_REG_MODEM==regType)&&(regAddr>0x1ff)) || ++ ((BT_REG_BLUEWIZE==regType)&&(regAddr>0xfff)) || ++ ((BT_REG_VENDOR==regType)&&(regAddr>0xfff)) || ++ ((BT_REG_LE==regType)&&(regAddr>0xfff)) ) ++ { ++ pBtRsp->status = (btOpcode<<8)| BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ } ++ } ++ break; ++ case BT_GGET_STATUS: ++ DBG_8192C("[MPT], [BT_GGET_STATUS]\n"); ++ validParaLen = 0; ++ break; ++ case BT_GGET_REPORT: ++ DBG_8192C("[MPT], [BT_GGET_REPORT]\n"); ++ validParaLen = 1; ++ if(getParaLen == validParaLen) ++ { ++ reportType = pBtReq->pParamStart[1]; ++ DBG_8192C("[MPT], BT_GGET_REPORT reportType=0x%x!!\n", reportType); ++ if(reportType >= BT_REPORT_MAX) ++ { ++ pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ } ++ break; ++ default: ++ { ++ DBG_8192C("[MPT], Error!! getType=%d, out of range\n", getType); ++ pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ break; ++ } ++ if(getParaLen != validParaLen) ++ { ++ DBG_8192C("[MPT], Error!! wrong parameter length=%d for BT_GET_GEN_CMD cmd id=0x%x, paraLen should=0x%x\n", ++ getParaLen, getType, validParaLen); ++ pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; ++ return paraLen; ++ } ++ ++ // ++ // execute lower layer opcodes ++ // ++ if(BT_GGET_REG == getType) ++ { ++ // fill h2c parameters ++ // here we should write reg value first then write the address, adviced by Austin ++ btOpcode = BT_LO_OP_READ_REG; ++ h2cParaBuf[0] = regType; ++ h2cParaBuf[1] = pBtReq->pParamStart[2]; ++ h2cParaBuf[2] = pBtReq->pParamStart[3]; ++ h2cParaLen = 3; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ ++ pu2Tmp = (pu2Byte)&pExtC2h->buf[0]; ++ regValue = *pu2Tmp; ++ DBG_8192C("[MPT], read reg regType=0x%x, regAddr=0x%x, regValue=0x%x\n", ++ regType, regAddr, regValue); ++ ++ pu4Tmp = (pu4Byte)&pBtRsp->pParamStart[0]; ++ *pu4Tmp = regValue; ++ paraLen = 4; ++ } ++ else if(BT_GGET_STATUS == getType) ++ { ++ btOpcode = BT_LO_OP_GET_BT_STATUS; ++ h2cParaLen = 0; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ ++ pBtRsp->pParamStart[0] = pExtC2h->buf[0]; ++ pBtRsp->pParamStart[1] = pExtC2h->buf[1]; ++ DBG_8192C("[MPT], read bt status, testMode=0x%x, testStatus=0x%x\n", ++ pBtRsp->pParamStart[0], pBtRsp->pParamStart[1]); ++ paraLen = 2; ++ } ++ else if(BT_GGET_REPORT == getType) ++ { ++ switch(reportType) ++ { ++ case BT_REPORT_RX_PACKET_CNT: ++ { ++ DBG_8192C("[MPT], [Rx Packet Counts]\n"); ++ btOpcode = BT_LO_OP_GET_RX_PKT_CNT_L; ++ h2cParaLen = 0; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ pBtRsp->pParamStart[0] = pExtC2h->buf[0]; ++ pBtRsp->pParamStart[1] = pExtC2h->buf[1]; ++ ++ btOpcode = BT_LO_OP_GET_RX_PKT_CNT_H; ++ h2cParaLen = 0; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ pBtRsp->pParamStart[2] = pExtC2h->buf[0]; ++ pBtRsp->pParamStart[3] = pExtC2h->buf[1]; ++ paraLen = 4; ++ } ++ break; ++ case BT_REPORT_RX_ERROR_BITS: ++ { ++ DBG_8192C("[MPT], [Rx Error Bits]\n"); ++ btOpcode = BT_LO_OP_GET_RX_ERROR_BITS_L; ++ h2cParaLen = 0; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ pBtRsp->pParamStart[0] = pExtC2h->buf[0]; ++ pBtRsp->pParamStart[1] = pExtC2h->buf[1]; ++ ++ btOpcode = BT_LO_OP_GET_RX_ERROR_BITS_H; ++ h2cParaLen = 0; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ pBtRsp->pParamStart[2] = pExtC2h->buf[0]; ++ pBtRsp->pParamStart[3] = pExtC2h->buf[1]; ++ paraLen = 4; ++ } ++ break; ++ case BT_REPORT_RSSI: ++ { ++ DBG_8192C("[MPT], [RSSI]\n"); ++ btOpcode = BT_LO_OP_GET_RSSI; ++ h2cParaLen = 0; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ pBtRsp->pParamStart[0] = pExtC2h->buf[0]; ++ pBtRsp->pParamStart[1] = pExtC2h->buf[1]; ++ paraLen = 2; ++ } ++ break; ++ case BT_REPORT_CFO_HDR_QUALITY: ++ { ++ DBG_8192C("[MPT], [CFO & Header Quality]\n"); ++ btOpcode = BT_LO_OP_GET_CFO_HDR_QUALITY_L; ++ h2cParaLen = 0; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ pBtRsp->pParamStart[0] = pExtC2h->buf[0]; ++ pBtRsp->pParamStart[1] = pExtC2h->buf[1]; ++ ++ btOpcode = BT_LO_OP_GET_CFO_HDR_QUALITY_H; ++ h2cParaLen = 0; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ pBtRsp->pParamStart[2] = pExtC2h->buf[0]; ++ pBtRsp->pParamStart[3] = pExtC2h->buf[1]; ++ paraLen = 4; ++ } ++ break; ++ case BT_REPORT_CONNECT_TARGET_BD_ADDR: ++ { ++ DBG_8192C("[MPT], [Connected Target BD ADDR]\n"); ++ btOpcode = BT_LO_OP_GET_TARGET_BD_ADDR_L; ++ h2cParaLen = 0; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ bdAddr[5] = pExtC2h->buf[0]; ++ bdAddr[4] = pExtC2h->buf[1]; ++ bdAddr[3] = pExtC2h->buf[2]; ++ ++ btOpcode = BT_LO_OP_GET_TARGET_BD_ADDR_H; ++ h2cParaLen = 0; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ bdAddr[2] = pExtC2h->buf[0]; ++ bdAddr[1] = pExtC2h->buf[1]; ++ bdAddr[0] = pExtC2h->buf[2]; ++ ++ DBG_8192C("[MPT], Connected Target BDAddr:%s", bdAddr); ++ for(i=0; i<6; i++) ++ { ++ pBtRsp->pParamStart[i] = bdAddr[5-i]; ++ } ++ paraLen = 6; ++ } ++ break; ++ default: ++ pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ break; ++ } ++ } ++ ++ pBtRsp->status = BT_STATUS_SUCCESS; ++ return paraLen; ++} ++ ++ ++ ++u2Byte ++mptbt_BtSetGeneral( ++ IN PADAPTER Adapter, ++ IN PBT_REQ_CMD pBtReq, ++ IN PBT_RSP_CMD pBtRsp ++ ) ++{ ++ u1Byte h2cParaBuf[6] ={0}; ++ u1Byte h2cParaLen=0; ++ u2Byte paraLen=0; ++ u1Byte retStatus=BT_STATUS_BT_OP_SUCCESS; ++ u1Byte btOpcode; ++ u1Byte btOpcodeVer=0; ++ u1Byte setType=0; ++ u2Byte setParaLen=0, validParaLen=0; ++ u1Byte regType=0, bdAddr[6]={0}, calVal=0; ++ u4Byte regAddr=0, regValue=0; ++ pu4Byte pu4Tmp; ++ pu2Byte pu2Tmp; ++ pu1Byte pu1Tmp; ++ ++ // ++ // check upper layer parameters ++ // ++ ++ // check upper layer opcode version ++ if(pBtReq->opCodeVer != 1) ++ { ++ DBG_8192C("[MPT], Error!! Upper OP code version not match!!!\n"); ++ pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; ++ return paraLen; ++ } ++ // check upper layer parameter length ++ if(pBtReq->paraLength < 1) ++ { ++ DBG_8192C("[MPT], Error!! wrong parameter length=%d (should larger than 1)\n", pBtReq->paraLength); ++ pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; ++ return paraLen; ++ } ++ setParaLen = pBtReq->paraLength - 1; ++ setType = pBtReq->pParamStart[0]; ++ ++ DBG_8192C("[MPT], setType=%d, setParaLen=%d\n", setType, setParaLen); ++ ++ // check parameter first ++ switch(setType) ++ { ++ case BT_GSET_REG: ++ DBG_8192C ("[MPT], [BT_GSET_REG]\n"); ++ validParaLen = 9; ++ if(setParaLen == validParaLen) ++ { ++ btOpcode = BT_LO_OP_WRITE_REG_VALUE; ++ regType = pBtReq->pParamStart[1]; ++ pu4Tmp = (pu4Byte)&pBtReq->pParamStart[2]; ++ regAddr = *pu4Tmp; ++ pu4Tmp = (pu4Byte)&pBtReq->pParamStart[6]; ++ regValue = *pu4Tmp; ++ DBG_8192C("[MPT], BT_GSET_REG regType=0x%x, regAddr=0x%x, regValue=0x%x!!\n", ++ regType, regAddr, regValue); ++ if(regType >= BT_REG_MAX) ++ { ++ pBtRsp->status = (btOpcode<<8)| BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ else ++ { ++ if( ((BT_REG_RF==regType)&&(regAddr>0x7f)) || ++ ((BT_REG_MODEM==regType)&&(regAddr>0x1ff)) || ++ ((BT_REG_BLUEWIZE==regType)&&(regAddr>0xfff)) || ++ ((BT_REG_VENDOR==regType)&&(regAddr>0xfff)) || ++ ((BT_REG_LE==regType)&&(regAddr>0xfff)) ) ++ { ++ pBtRsp->status = (btOpcode<<8)| BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ } ++ } ++ break; ++ case BT_GSET_RESET: ++ DBG_8192C("[MPT], [BT_GSET_RESET]\n"); ++ validParaLen = 0; ++ break; ++ case BT_GSET_TARGET_BD_ADDR: ++ DBG_8192C("[MPT], [BT_GSET_TARGET_BD_ADDR]\n"); ++ validParaLen = 6; ++ if(setParaLen == validParaLen) ++ { ++ btOpcode = BT_LO_OP_SET_TARGET_BD_ADDR_H; ++ if( (pBtReq->pParamStart[1]==0) && ++ (pBtReq->pParamStart[2]==0) && ++ (pBtReq->pParamStart[3]==0) && ++ (pBtReq->pParamStart[4]==0) && ++ (pBtReq->pParamStart[5]==0) && ++ (pBtReq->pParamStart[6]==0) ) ++ { ++ DBG_8192C("[MPT], Error!! targetBDAddr=all zero\n"); ++ pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ if( (pBtReq->pParamStart[1]==0xff) && ++ (pBtReq->pParamStart[2]==0xff) && ++ (pBtReq->pParamStart[3]==0xff) && ++ (pBtReq->pParamStart[4]==0xff) && ++ (pBtReq->pParamStart[5]==0xff) && ++ (pBtReq->pParamStart[6]==0xff) ) ++ { ++ DBG_8192C("[MPT], Error!! targetBDAddr=all 0xf\n"); ++ pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ bdAddr[0] = pBtReq->pParamStart[6]; ++ bdAddr[1] = pBtReq->pParamStart[5]; ++ bdAddr[2] = pBtReq->pParamStart[4]; ++ bdAddr[3] = pBtReq->pParamStart[3]; ++ bdAddr[4] = pBtReq->pParamStart[2]; ++ bdAddr[5] = pBtReq->pParamStart[1]; ++ DBG_8192C ("[MPT], target BDAddr:%x,%x,%x,%x,%x,%x\n", ++ bdAddr[0],bdAddr[1],bdAddr[2],bdAddr[3],bdAddr[4],bdAddr[5]); ++ } ++ break; ++ case BT_GSET_TX_PWR_FINETUNE: ++ DBG_8192C("[MPT], [BT_GSET_TX_PWR_FINETUNE]\n"); ++ validParaLen = 1; ++ if(setParaLen == validParaLen) ++ { ++ btOpcode = BT_LO_OP_SET_TX_POWER_CALIBRATION; ++ calVal = pBtReq->pParamStart[1]; ++ if( (calVal<1) || (calVal>9) ) ++ { ++ pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ DBG_8192C ("[MPT], calVal=%d\n", calVal); ++ } ++ break; ++ case BT_SET_TRACKING_INTERVAL: ++ DBG_871X("[MPT], [BT_SET_TRACKING_INTERVAL] setParaLen =%d \n",setParaLen); ++ ++ validParaLen = 1; ++ if(setParaLen == validParaLen) ++ calVal = pBtReq->pParamStart[1]; ++ break; ++ case BT_SET_THERMAL_METER: ++ DBG_871X("[MPT], [BT_SET_THERMAL_METER] setParaLen =%d \n",setParaLen); ++ validParaLen = 1; ++ if(setParaLen == validParaLen) ++ calVal = pBtReq->pParamStart[1]; ++ break; ++ case BT_ENABLE_CFO_TRACKING: ++ DBG_871X("[MPT], [BT_ENABLE_CFO_TRACKING] setParaLen =%d \n",setParaLen); ++ validParaLen = 1; ++ if(setParaLen == validParaLen) ++ calVal = pBtReq->pParamStart[1]; ++ break; ++ case BT_GSET_UPDATE_BT_PATCH: ++ if(IS_HARDWARE_TYPE_8723AE(Adapter) && Adapter->bFWReady) ++ { ++ u1Byte i; ++ DBG_8192C ("[MPT], write regs for load patch\n"); ++ //BTFwPatch8723A(Adapter); ++ PlatformEFIOWrite1Byte(Adapter, 0xCC, 0x2d); ++ rtw_msleep_os(50); ++ PlatformEFIOWrite4Byte(Adapter, 0x68, 0xa005000c); ++ rtw_msleep_os(50); ++ PlatformEFIOWrite4Byte(Adapter, 0x68, 0xb005000c); ++ rtw_msleep_os(50); ++ PlatformEFIOWrite1Byte(Adapter, 0xCC, 0x29); ++ for(i=0; i<12; i++) ++ rtw_msleep_os(100); ++//#if (DEV_BUS_TYPE == RT_PCI_INTERFACE) ++// BTFwPatch8723A(Adapter); ++//#endif ++ DBG_8192C("[MPT], load BT FW Patch finished!!!\n"); ++ } ++ break; ++ default: ++ { ++ DBG_8192C ("[MPT], Error!! setType=%d, out of range\n", setType); ++ pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ break; ++ } ++ if(setParaLen != validParaLen) ++ { ++ DBG_8192C("[MPT], Error!! wrong parameter length=%d for BT_SET_GEN_CMD cmd id=0x%x, paraLen should=0x%x\n", ++ setParaLen, setType, validParaLen); ++ pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; ++ return paraLen; ++ } ++ ++ // ++ // execute lower layer opcodes ++ // ++ if(BT_GSET_REG == setType) ++ { ++ // fill h2c parameters ++ // here we should write reg value first then write the address, adviced by Austin ++ btOpcode = BT_LO_OP_WRITE_REG_VALUE; ++ h2cParaBuf[0] = pBtReq->pParamStart[6]; ++ h2cParaBuf[1] = pBtReq->pParamStart[7]; ++ h2cParaBuf[2] = pBtReq->pParamStart[8]; ++ h2cParaLen = 3; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ ++ // write reg address ++ btOpcode = BT_LO_OP_WRITE_REG_ADDR; ++ h2cParaBuf[0] = regType; ++ h2cParaBuf[1] = pBtReq->pParamStart[2]; ++ h2cParaBuf[2] = pBtReq->pParamStart[3]; ++ h2cParaLen = 3; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ } ++ else if(BT_GSET_RESET == setType) ++ { ++ btOpcode = BT_LO_OP_RESET; ++ h2cParaLen = 0; ++ // execute h2c and check respond c2h from bt fw is correct or not ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ } ++ else if(BT_GSET_TARGET_BD_ADDR == setType) ++ { ++ // fill h2c parameters ++ btOpcode = BT_LO_OP_SET_TARGET_BD_ADDR_L; ++ h2cParaBuf[0] = pBtReq->pParamStart[1]; ++ h2cParaBuf[1] = pBtReq->pParamStart[2]; ++ h2cParaBuf[2] = pBtReq->pParamStart[3]; ++ h2cParaLen = 3; ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ ++ btOpcode = BT_LO_OP_SET_TARGET_BD_ADDR_H; ++ h2cParaBuf[0] = pBtReq->pParamStart[4]; ++ h2cParaBuf[1] = pBtReq->pParamStart[5]; ++ h2cParaBuf[2] = pBtReq->pParamStart[6]; ++ h2cParaLen = 3; ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ } ++ else if(BT_GSET_TX_PWR_FINETUNE == setType) ++ { ++ // fill h2c parameters ++ btOpcode = BT_LO_OP_SET_TX_POWER_CALIBRATION; ++ h2cParaBuf[0] = calVal; ++ h2cParaLen = 1; ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ } ++ else if(BT_SET_TRACKING_INTERVAL == setType) ++ { ++ // BT_LO_OP_SET_TRACKING_INTERVAL = 0x22, ++ // BT_LO_OP_SET_THERMAL_METER = 0x23, ++ // BT_LO_OP_ENABLE_CFO_TRACKING = 0x24, ++ btOpcode = BT_LO_OP_SET_TRACKING_INTERVAL; ++ h2cParaBuf[0] = calVal; ++ h2cParaLen = 1; ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ } ++ else if(BT_SET_THERMAL_METER == setType) ++ { ++ btOpcode = BT_LO_OP_SET_THERMAL_METER; ++ h2cParaBuf[0] = calVal; ++ h2cParaLen = 1; ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ } ++ else if(BT_ENABLE_CFO_TRACKING == setType) ++ { ++ btOpcode = BT_LO_OP_ENABLE_CFO_TRACKING; ++ h2cParaBuf[0] = calVal; ++ h2cParaLen = 1; ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ } ++ ++ pBtRsp->status = BT_STATUS_SUCCESS; ++ return paraLen; ++} ++ ++ ++ ++u2Byte ++mptbt_BtSetTxRxPars( ++ IN PADAPTER Adapter, ++ IN PBT_REQ_CMD pBtReq, ++ IN PBT_RSP_CMD pBtRsp ++ ) ++{ ++ u1Byte h2cParaBuf[6] ={0}; ++ u1Byte h2cParaLen=0; ++ u2Byte paraLen=0; ++ u1Byte retStatus=BT_STATUS_BT_OP_SUCCESS; ++ u1Byte btOpcode; ++ u1Byte btOpcodeVer=0; ++ PBT_TXRX_PARAMETERS pTxRxPars=(PBT_TXRX_PARAMETERS)&pBtReq->pParamStart[0]; ++ u2Byte lenTxRx=sizeof(BT_TXRX_PARAMETERS); ++ u1Byte i; ++ u1Byte bdAddr[6]={0}; ++ ++ // ++ // check upper layer parameters ++ // ++ ++ // 1. check upper layer opcode version ++ if(pBtReq->opCodeVer != 1) ++ { ++ DBG_8192C("[MPT], Error!! Upper OP code version not match!!!\n"); ++ pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; ++ return paraLen; ++ } ++ // 2. check upper layer parameter length ++ if(pBtReq->paraLength == sizeof(BT_TXRX_PARAMETERS)) ++ { ++ DBG_8192C ("[MPT], pTxRxPars->txrxChannel=0x%x \n", pTxRxPars->txrxChannel); ++ DBG_8192C ("[MPT], pTxRxPars->txrxTxPktCnt=0x%8x \n", pTxRxPars->txrxTxPktCnt); ++ DBG_8192C ("[MPT], pTxRxPars->txrxTxPktInterval=0x%x \n", pTxRxPars->txrxTxPktInterval); ++ DBG_8192C ("[MPT], pTxRxPars->txrxPayloadType=0x%x \n", pTxRxPars->txrxPayloadType); ++ DBG_8192C ("[MPT], pTxRxPars->txrxPktType=0x%x \n", pTxRxPars->txrxPktType); ++ DBG_8192C ("[MPT], pTxRxPars->txrxPayloadLen=0x%x \n", pTxRxPars->txrxPayloadLen); ++ DBG_8192C ("[MPT], pTxRxPars->txrxPktHeader=0x%x \n", pTxRxPars->txrxPktHeader); ++ DBG_8192C ("[MPT], pTxRxPars->txrxWhitenCoeff=0x%x \n", pTxRxPars->txrxWhitenCoeff); ++ bdAddr[0] = pTxRxPars->txrxBdaddr[5]; ++ bdAddr[1] = pTxRxPars->txrxBdaddr[4]; ++ bdAddr[2] = pTxRxPars->txrxBdaddr[3]; ++ bdAddr[3] = pTxRxPars->txrxBdaddr[2]; ++ bdAddr[4] = pTxRxPars->txrxBdaddr[1]; ++ bdAddr[5] = pTxRxPars->txrxBdaddr[0]; ++ DBG_8192C ("[MPT], pTxRxPars->txrxBdaddr: %s", &bdAddr[0]); ++ DBG_8192C ("[MPT], pTxRxPars->txrxTxGainIndex=0x%x \n", pTxRxPars->txrxTxGainIndex); ++ } ++ else ++ { ++ DBG_8192C ("[MPT], Error!! pBtReq->paraLength=%d, correct Len=%d\n", pBtReq->paraLength, lenTxRx); ++ pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; ++ return paraLen; ++ } ++ ++ // ++ // execute lower layer opcodes ++ // ++ ++ // fill h2c parameters ++ btOpcode = BT_LO_OP_SET_PKT_HEADER; ++ if(pTxRxPars->txrxPktHeader > 0x3ffff) ++ { ++ DBG_8192C ("[MPT], Error!! pTxRxPars->txrxPktHeader=0x%x is out of range, (should be between 0x0~0x3ffff)\n", pTxRxPars->txrxPktHeader); ++ pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ else ++ { ++ h2cParaBuf[0] = (u1Byte)(pTxRxPars->txrxPktHeader&0xff); ++ h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxPktHeader&0xff00)>>8); ++ h2cParaBuf[2] = (u1Byte)((pTxRxPars->txrxPktHeader&0xff0000)>>16); ++ h2cParaLen = 3; ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ } ++ ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ ++ // fill h2c parameters ++ btOpcode = BT_LO_OP_SET_PKT_TYPE_LEN; ++ { ++ u2Byte payloadLenLimit=0; ++ switch(pTxRxPars->txrxPktType) ++ { ++ case MP_BT_PKT_DH1: ++ payloadLenLimit = 27*8; ++ break; ++ case MP_BT_PKT_DH3: ++ payloadLenLimit = 183*8; ++ break; ++ case MP_BT_PKT_DH5: ++ payloadLenLimit = 339*8; ++ break; ++ case MP_BT_PKT_2DH1: ++ payloadLenLimit = 54*8; ++ break; ++ case MP_BT_PKT_2DH3: ++ payloadLenLimit = 367*8; ++ break; ++ case MP_BT_PKT_2DH5: ++ payloadLenLimit = 679*8; ++ break; ++ case MP_BT_PKT_3DH1: ++ payloadLenLimit = 83*8; ++ break; ++ case MP_BT_PKT_3DH3: ++ payloadLenLimit = 552*8; ++ break; ++ case MP_BT_PKT_3DH5: ++ payloadLenLimit = 1021*8; ++ break; ++ case MP_BT_PKT_LE: ++ payloadLenLimit = 39*8; ++ break; ++ default: ++ { ++ DBG_8192C ("[MPT], Error!! Unknown pTxRxPars->txrxPktType=0x%x\n", pTxRxPars->txrxPktType); ++ pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ break; ++ } ++ ++ if(pTxRxPars->txrxPayloadLen > payloadLenLimit) ++ { ++ DBG_8192C ("[MPT], Error!! pTxRxPars->txrxPayloadLen=0x%x, (should smaller than %d)\n", ++ pTxRxPars->txrxPayloadLen, payloadLenLimit); ++ pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ ++ h2cParaBuf[0] = pTxRxPars->txrxPktType; ++ h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxPayloadLen&0xff)); ++ h2cParaBuf[2] = (u1Byte)((pTxRxPars->txrxPayloadLen&0xff00)>>8); ++ h2cParaLen = 3; ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ } ++ ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ ++ // fill h2c parameters ++ btOpcode = BT_LO_OP_SET_PKT_CNT_L_PL_TYPE; ++ if(pTxRxPars->txrxPayloadType > MP_BT_PAYLOAD_MAX) ++ { ++ DBG_8192C ("[MPT], Error!! pTxRxPars->txrxPayloadType=0x%x, (should be between 0~4)\n", pTxRxPars->txrxPayloadType); ++ pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ else ++ { ++ h2cParaBuf[0] = (u1Byte)((pTxRxPars->txrxTxPktCnt&0xff)); ++ h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxTxPktCnt&0xff00)>>8); ++ h2cParaBuf[2] = pTxRxPars->txrxPayloadType; ++ h2cParaLen = 3; ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ } ++ ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ ++ // fill h2c parameters ++ btOpcode = BT_LO_OP_SET_PKT_CNT_H_PKT_INTV; ++ if(pTxRxPars->txrxTxPktInterval > 15) ++ { ++ DBG_8192C ("[MPT], Error!! pTxRxPars->txrxTxPktInterval=0x%x, (should be between 0~15)\n", pTxRxPars->txrxTxPktInterval); ++ pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ else ++ { ++ h2cParaBuf[0] = (u1Byte)((pTxRxPars->txrxTxPktCnt&0xff0000)>>16); ++ h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxTxPktCnt&0xff000000)>>24); ++ h2cParaBuf[2] = pTxRxPars->txrxTxPktInterval; ++ h2cParaLen = 3; ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ } ++ ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ ++ // fill h2c parameters ++ btOpcode = BT_LO_OP_SET_WHITENCOEFF; ++ { ++ h2cParaBuf[0] = pTxRxPars->txrxWhitenCoeff; ++ h2cParaLen = 1; ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ } ++ ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ ++ ++ // fill h2c parameters ++ btOpcode = BT_LO_OP_SET_CHNL_TX_GAIN; ++ if( (pTxRxPars->txrxChannel > 78) || ++ (pTxRxPars->txrxTxGainIndex > 7) ) ++ { ++ DBG_8192C ("[MPT], Error!! pTxRxPars->txrxChannel=0x%x, (should be between 0~78)\n", pTxRxPars->txrxChannel); ++ DBG_8192C ("[MPT], Error!! pTxRxPars->txrxTxGainIndex=0x%x, (should be between 0~7)\n", pTxRxPars->txrxTxGainIndex); ++ pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ else ++ { ++ h2cParaBuf[0] = pTxRxPars->txrxChannel; ++ h2cParaBuf[1] = pTxRxPars->txrxTxGainIndex; ++ h2cParaLen = 2; ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ } ++ ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ ++ // fill h2c parameters ++ btOpcode = BT_LO_OP_SET_BD_ADDR_L; ++ if( (pTxRxPars->txrxBdaddr[0]==0) && ++ (pTxRxPars->txrxBdaddr[1]==0) && ++ (pTxRxPars->txrxBdaddr[2]==0) && ++ (pTxRxPars->txrxBdaddr[3]==0) && ++ (pTxRxPars->txrxBdaddr[4]==0) && ++ (pTxRxPars->txrxBdaddr[5]==0) ) ++ { ++ DBG_8192C ("[MPT], Error!! pTxRxPars->txrxBdaddr=all zero\n"); ++ pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ if( (pTxRxPars->txrxBdaddr[0]==0xff) && ++ (pTxRxPars->txrxBdaddr[1]==0xff) && ++ (pTxRxPars->txrxBdaddr[2]==0xff) && ++ (pTxRxPars->txrxBdaddr[3]==0xff) && ++ (pTxRxPars->txrxBdaddr[4]==0xff) && ++ (pTxRxPars->txrxBdaddr[5]==0xff) ) ++ { ++ DBG_8192C ("[MPT], Error!! pTxRxPars->txrxBdaddr=all 0xf\n"); ++ pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ ++ { ++ h2cParaBuf[0] = pTxRxPars->txrxBdaddr[0]; ++ h2cParaBuf[1] = pTxRxPars->txrxBdaddr[1]; ++ h2cParaBuf[2] = pTxRxPars->txrxBdaddr[2]; ++ h2cParaLen = 3; ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ } ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ ++ btOpcode = BT_LO_OP_SET_BD_ADDR_H; ++ { ++ h2cParaBuf[0] = pTxRxPars->txrxBdaddr[3]; ++ h2cParaBuf[1] = pTxRxPars->txrxBdaddr[4]; ++ h2cParaBuf[2] = pTxRxPars->txrxBdaddr[5]; ++ h2cParaLen = 3; ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ } ++ // ckeck bt return status. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ ++ pBtRsp->status = BT_STATUS_SUCCESS; ++ return paraLen; ++} ++ ++ ++ ++u2Byte ++mptbt_BtTestCtrl( ++ IN PADAPTER Adapter, ++ IN PBT_REQ_CMD pBtReq, ++ IN PBT_RSP_CMD pBtRsp ++ ) ++{ ++ u1Byte h2cParaBuf[6] ={0}; ++ u1Byte h2cParaLen=0; ++ u2Byte paraLen=0; ++ u1Byte retStatus=BT_STATUS_BT_OP_SUCCESS; ++ u1Byte btOpcode; ++ u1Byte btOpcodeVer=0; ++ u1Byte testCtrl=0; ++ ++ // ++ // check upper layer parameters ++ // ++ ++ // 1. check upper layer opcode version ++ if(pBtReq->opCodeVer != 1) ++ { ++ DBG_8192C("[MPT], Error!! Upper OP code version not match!!!\n"); ++ pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; ++ return paraLen; ++ } ++ // 2. check upper layer parameter length ++ if(1 == pBtReq->paraLength) ++ { ++ testCtrl = pBtReq->pParamStart[0]; ++ DBG_8192C("[MPT], testCtrl=%d \n", testCtrl); ++ } ++ else ++ { ++ DBG_8192C("[MPT], Error!! wrong parameter length=%d (should be 1)\n", pBtReq->paraLength); ++ pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; ++ return paraLen; ++ } ++ ++ // ++ // execute lower layer opcodes ++ // ++ ++ // 1. fill h2c parameters ++ // check bt mode ++ btOpcode = BT_LO_OP_TEST_CTRL; ++ if(testCtrl >= MP_BT_TEST_MAX) ++ { ++ DBG_8192C("[MPT], Error!! testCtrl=0x%x, (should be between smaller or equal to 0x%x)\n", ++ testCtrl, MP_BT_TEST_MAX-1); ++ pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; ++ return paraLen; ++ } ++ else ++ { ++ h2cParaBuf[0] = testCtrl; ++ h2cParaLen = 1; ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ } ++ ++ // 3. construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ ++ pBtRsp->status = BT_STATUS_SUCCESS; ++ return paraLen; ++} ++ ++ ++u2Byte ++mptbt_TestBT( ++ IN PADAPTER Adapter, ++ IN PBT_REQ_CMD pBtReq, ++ IN PBT_RSP_CMD pBtRsp ++ ) ++{ ++ ++ u1Byte h2cParaBuf[6] ={0}; ++ u1Byte h2cParaLen=0; ++ u2Byte paraLen=0; ++ u1Byte retStatus=BT_STATUS_BT_OP_SUCCESS; ++ u1Byte btOpcode; ++ u1Byte btOpcodeVer=0; ++ u1Byte testCtrl=0; ++ ++ // 1. fill h2c parameters ++ btOpcode = 0x11; ++ h2cParaBuf[0] = 0x11; ++ h2cParaBuf[1] = 0x0; ++ h2cParaBuf[2] = 0x0; ++ h2cParaBuf[3] = 0x0; ++ h2cParaBuf[4] = 0x0; ++ h2cParaLen = 1; ++ // retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); ++ retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, h2cParaBuf, h2cParaLen); ++ ++ ++ // 3. construct respond status code and data. ++ if(BT_STATUS_BT_OP_SUCCESS != retStatus) ++ { ++ pBtRsp->status = ((btOpcode<<8)|retStatus); ++ DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status); ++ return paraLen; ++ } ++ ++ pBtRsp->status = BT_STATUS_SUCCESS; ++ return paraLen; ++} ++ ++VOID ++mptbt_BtControlProcess( ++ PADAPTER Adapter, ++ PVOID pInBuf ++ ) ++{ ++ u1Byte H2C_Parameter[6] ={0}; ++ PBT_H2C pH2c=(PBT_H2C)&H2C_Parameter[0]; ++ PMPT_CONTEXT pMptCtx=&(Adapter->mppriv.MptCtx); ++ PBT_REQ_CMD pBtReq=(PBT_REQ_CMD)pInBuf; ++ PBT_RSP_CMD pBtRsp=(PBT_RSP_CMD)&pMptCtx->mptOutBuf[0]; ++ u1Byte i; ++ ++ DBG_8192C("[MPT], mptbt_BtControlProcess()=========>\n"); ++ ++ DBG_8192C("[MPT], input opCodeVer=%d\n", pBtReq->opCodeVer); ++ DBG_8192C("[MPT], input OpCode=%d\n", pBtReq->OpCode); ++ DBG_8192C("[MPT], paraLength=%d \n", pBtReq->paraLength); ++ if(pBtReq->paraLength) ++ { ++ //DBG_8192C("[MPT], parameters(hex):0x%x %d \n",&pBtReq->pParamStart[0], pBtReq->paraLength); ++ } ++ ++ // The following we should maintain the User OP codes sent by upper layer ++ ++ pBtRsp->status = BT_STATUS_SUCCESS; ++ pMptCtx->mptOutLen = 4; //length of (BT_RSP_CMD.status+BT_RSP_CMD.paraLength) ++ pBtRsp->paraLength = 0x0; ++ ++ _rtw_memset((PVOID)&pMptCtx->mptOutBuf[0], '\0',100); ++ ++ switch(pBtReq->OpCode) ++ { ++ case BT_UP_OP_BT_READY: ++ DBG_8192C("[MPT], OPcode : [BT_READY]\n"); ++ pBtRsp->paraLength = mptbt_BtReady(Adapter, pBtReq, pBtRsp); ++ break; ++ case BT_UP_OP_BT_SET_MODE: ++ DBG_8192C("[MPT], OPcode : [BT_SET_MODE]\n"); ++ pBtRsp->paraLength = mptbt_BtSetMode(Adapter, pBtReq, pBtRsp); ++ break; ++ case BT_UP_OP_BT_SET_TX_RX_PARAMETER: ++ DBG_8192C("[MPT], OPcode : [BT_SET_TXRX_PARAMETER]\n"); ++ pBtRsp->paraLength = mptbt_BtSetTxRxPars(Adapter, pBtReq, pBtRsp); ++ break; ++ case BT_UP_OP_BT_SET_GENERAL: ++ DBG_8192C("[MPT], OPcode : [BT_SET_GENERAL]\n"); ++ pBtRsp->paraLength = mptbt_BtSetGeneral(Adapter, pBtReq, pBtRsp); ++ break; ++ case BT_UP_OP_BT_GET_GENERAL: ++ DBG_8192C("[MPT], OPcode : [BT_GET_GENERAL]\n"); ++ pBtRsp->paraLength = mptbt_BtGetGeneral(Adapter, pBtReq, pBtRsp); ++ break; ++ case BT_UP_OP_BT_TEST_CTRL: ++ DBG_8192C("[MPT], OPcode : [BT_TEST_CTRL]\n"); ++ pBtRsp->paraLength = mptbt_BtTestCtrl(Adapter, pBtReq, pBtRsp); ++ break; ++ case BT_UP_OP_TEST_BT: ++ DBG_8192C("[MPT], OPcode : [TEST_BT]\n"); ++ pBtRsp->paraLength = mptbt_TestBT(Adapter, pBtReq, pBtRsp); ++ break; ++ default: ++ DBG_8192C("[MPT], Error!! OPcode : UNDEFINED!!!!\n"); ++ pBtRsp->status = BT_STATUS_UNKNOWN_OPCODE_U; ++ pBtRsp->paraLength = 0x0; ++ break; ++ } ++ ++ DBG_8192C("pBtRsp->paraLength =%d \n",pBtRsp->paraLength); ++ ++ pMptCtx->mptOutLen += pBtRsp->paraLength; ++ ++ DBG_8192C("\n [MPT], OUT to DLL pMptCtx->mptOutLen=%d ,pBtRsp->paraLength =%d ",pMptCtx->mptOutLen,pBtRsp->paraLength); ++ ++ DBG_8192C("\n [MPT], mptbt_BtControlProcess()<=========\n"); ++} ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_cmd.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_cmd.c +new file mode 100644 +index 00000000..79bdc71a +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_cmd.c +@@ -0,0 +1,3281 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_CMD_C_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_BR_EXT ++#include ++#endif //CONFIG_BR_EXT ++ ++#ifdef CONFIG_BT_COEXIST ++#include ++#endif // CONFIG_BT_COEXIST ++ ++/* ++Caller and the rtw_cmd_thread can protect cmd_q by spin_lock. ++No irqsave is necessary. ++*/ ++ ++sint _rtw_init_cmd_priv (struct cmd_priv *pcmdpriv) ++{ ++ sint res=_SUCCESS; ++ ++_func_enter_; ++ ++ _rtw_init_sema(&(pcmdpriv->cmd_queue_sema), 0); ++ //_rtw_init_sema(&(pcmdpriv->cmd_done_sema), 0); ++ _rtw_init_sema(&(pcmdpriv->terminate_cmdthread_sema), 0); ++ ++ ++ _rtw_init_queue(&(pcmdpriv->cmd_queue)); ++ ++ //allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf ++ ++ pcmdpriv->cmd_seq = 1; ++ ++ pcmdpriv->cmd_allocated_buf = rtw_zmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ); ++ ++ if (pcmdpriv->cmd_allocated_buf == NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf + CMDBUFF_ALIGN_SZ - ( (SIZE_PTR)(pcmdpriv->cmd_allocated_buf) & (CMDBUFF_ALIGN_SZ-1)); ++ ++ pcmdpriv->rsp_allocated_buf = rtw_zmalloc(MAX_RSPSZ + 4); ++ ++ if (pcmdpriv->rsp_allocated_buf == NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf + 4 - ( (SIZE_PTR)(pcmdpriv->rsp_allocated_buf) & 3); ++ ++ pcmdpriv->cmd_issued_cnt = pcmdpriv->cmd_done_cnt = pcmdpriv->rsp_cnt = 0; ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++ ++} ++ ++#ifdef CONFIG_C2H_WK ++static void c2h_wk_callback(_workitem *work); ++#endif ++sint _rtw_init_evt_priv(struct evt_priv *pevtpriv) ++{ ++ sint res=_SUCCESS; ++ ++_func_enter_; ++ ++#ifdef CONFIG_H2CLBK ++ _rtw_init_sema(&(pevtpriv->lbkevt_done), 0); ++ pevtpriv->lbkevt_limit = 0; ++ pevtpriv->lbkevt_num = 0; ++ pevtpriv->cmdevt_parm = NULL; ++#endif ++ ++ //allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf ++ ATOMIC_SET(&pevtpriv->event_seq, 0); ++ pevtpriv->evt_done_cnt = 0; ++ ++#ifdef CONFIG_EVENT_THREAD_MODE ++ ++ _rtw_init_sema(&(pevtpriv->evt_notify), 0); ++ _rtw_init_sema(&(pevtpriv->terminate_evtthread_sema), 0); ++ ++ pevtpriv->evt_allocated_buf = rtw_zmalloc(MAX_EVTSZ + 4); ++ if (pevtpriv->evt_allocated_buf == NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ pevtpriv->evt_buf = pevtpriv->evt_allocated_buf + 4 - ((unsigned int)(pevtpriv->evt_allocated_buf) & 3); ++ ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ pevtpriv->allocated_c2h_mem = rtw_zmalloc(C2H_MEM_SZ +4); ++ ++ if (pevtpriv->allocated_c2h_mem == NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pevtpriv->c2h_mem = pevtpriv->allocated_c2h_mem + 4\ ++ - ( (u32)(pevtpriv->allocated_c2h_mem) & 3); ++#ifdef PLATFORM_OS_XP ++ pevtpriv->pc2h_mdl= IoAllocateMdl((u8 *)pevtpriv->c2h_mem, C2H_MEM_SZ , FALSE, FALSE, NULL); ++ ++ if(pevtpriv->pc2h_mdl == NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ MmBuildMdlForNonPagedPool(pevtpriv->pc2h_mdl); ++#endif ++#endif //end of CONFIG_SDIO_HCI ++ ++ _rtw_init_queue(&(pevtpriv->evt_queue)); ++ ++exit: ++ ++#endif //end of CONFIG_EVENT_THREAD_MODE ++ ++#ifdef CONFIG_C2H_WK ++ _init_workitem(&pevtpriv->c2h_wk, c2h_wk_callback, NULL); ++ pevtpriv->c2h_wk_alive = _FALSE; ++ pevtpriv->c2h_queue = rtw_cbuf_alloc(C2H_QUEUE_MAX_LEN+1); ++#endif ++ ++_func_exit_; ++ ++ return res; ++} ++ ++void _rtw_free_evt_priv (struct evt_priv *pevtpriv) ++{ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("+_rtw_free_evt_priv \n")); ++ ++#ifdef CONFIG_EVENT_THREAD_MODE ++ _rtw_free_sema(&(pevtpriv->evt_notify)); ++ _rtw_free_sema(&(pevtpriv->terminate_evtthread_sema)); ++ ++ ++ if (pevtpriv->evt_allocated_buf) ++ rtw_mfree(pevtpriv->evt_allocated_buf, MAX_EVTSZ + 4); ++#endif ++ ++#ifdef CONFIG_C2H_WK ++ _cancel_workitem_sync(&pevtpriv->c2h_wk); ++ while(pevtpriv->c2h_wk_alive) ++ rtw_msleep_os(10); ++ ++ while (!rtw_cbuf_empty(pevtpriv->c2h_queue)) { ++ void *c2h; ++ if ((c2h = rtw_cbuf_pop(pevtpriv->c2h_queue)) != NULL ++ && c2h != (void *)pevtpriv) { ++ rtw_mfree(c2h, 16); ++ } ++ } ++ rtw_cbuf_free(pevtpriv->c2h_queue); ++#endif ++ ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("-_rtw_free_evt_priv \n")); ++ ++_func_exit_; ++ ++} ++ ++void _rtw_free_cmd_priv (struct cmd_priv *pcmdpriv) ++{ ++_func_enter_; ++ ++ if(pcmdpriv){ ++ _rtw_spinlock_free(&(pcmdpriv->cmd_queue.lock)); ++ _rtw_free_sema(&(pcmdpriv->cmd_queue_sema)); ++ //_rtw_free_sema(&(pcmdpriv->cmd_done_sema)); ++ _rtw_free_sema(&(pcmdpriv->terminate_cmdthread_sema)); ++ ++ if (pcmdpriv->cmd_allocated_buf) ++ rtw_mfree(pcmdpriv->cmd_allocated_buf, MAX_CMDSZ + CMDBUFF_ALIGN_SZ); ++ ++ if (pcmdpriv->rsp_allocated_buf) ++ rtw_mfree(pcmdpriv->rsp_allocated_buf, MAX_RSPSZ + 4); ++ } ++_func_exit_; ++} ++ ++/* ++Calling Context: ++ ++rtw_enqueue_cmd can only be called between kernel thread, ++since only spin_lock is used. ++ ++ISR/Call-Back functions can't call this sub-function. ++ ++*/ ++ ++sint _rtw_enqueue_cmd(_queue *queue, struct cmd_obj *obj) ++{ ++ _irqL irqL; ++ ++_func_enter_; ++ ++ if (obj == NULL) ++ goto exit; ++ ++ //_enter_critical_bh(&queue->lock, &irqL); ++ _enter_critical(&queue->lock, &irqL); ++ ++ rtw_list_insert_tail(&obj->list, &queue->queue); ++ ++ //_exit_critical_bh(&queue->lock, &irqL); ++ _exit_critical(&queue->lock, &irqL); ++ ++exit: ++ ++_func_exit_; ++ ++ return _SUCCESS; ++} ++ ++struct cmd_obj *_rtw_dequeue_cmd(_queue *queue) ++{ ++ _irqL irqL; ++ struct cmd_obj *obj; ++ ++_func_enter_; ++ ++ //_enter_critical_bh(&(queue->lock), &irqL); ++ _enter_critical(&queue->lock, &irqL); ++ if (rtw_is_list_empty(&(queue->queue))) ++ obj = NULL; ++ else ++ { ++ obj = LIST_CONTAINOR(get_next(&(queue->queue)), struct cmd_obj, list); ++ rtw_list_delete(&obj->list); ++ } ++ ++ //_exit_critical_bh(&(queue->lock), &irqL); ++ _exit_critical(&queue->lock, &irqL); ++ ++_func_exit_; ++ ++ return obj; ++} ++ ++u32 rtw_init_cmd_priv(struct cmd_priv *pcmdpriv) ++{ ++ u32 res; ++_func_enter_; ++ res = _rtw_init_cmd_priv (pcmdpriv); ++_func_exit_; ++ return res; ++} ++ ++u32 rtw_init_evt_priv (struct evt_priv *pevtpriv) ++{ ++ int res; ++_func_enter_; ++ res = _rtw_init_evt_priv(pevtpriv); ++_func_exit_; ++ return res; ++} ++ ++void rtw_free_evt_priv (struct evt_priv *pevtpriv) ++{ ++_func_enter_; ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("rtw_free_evt_priv\n")); ++ _rtw_free_evt_priv(pevtpriv); ++_func_exit_; ++} ++ ++void rtw_free_cmd_priv (struct cmd_priv *pcmdpriv) ++{ ++_func_enter_; ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("rtw_free_cmd_priv\n")); ++ _rtw_free_cmd_priv(pcmdpriv); ++_func_exit_; ++} ++ ++int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj); ++int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) ++{ ++ u8 bAllow = _FALSE; //set to _TRUE to allow enqueuing cmd when hw_init_completed is _FALSE ++ ++ #ifdef SUPPORT_HW_RFOFF_DETECTED ++ //To decide allow or not ++ if( (adapter_to_pwrctl(pcmdpriv->padapter)->bHWPwrPindetect) ++ &&(!pcmdpriv->padapter->registrypriv.usbss_enable) ++ ) ++ { ++ if(cmd_obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra) ) ++ { ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)cmd_obj->parmbuf; ++ if(pdrvextra_cmd_parm->ec_id == POWER_SAVING_CTRL_WK_CID) ++ { ++ //DBG_871X("==>enqueue POWER_SAVING_CTRL_WK_CID\n"); ++ bAllow = _TRUE; ++ } ++ } ++ } ++ #endif ++ ++ if(cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan)) ++ bAllow = _TRUE; ++ ++ if( (pcmdpriv->padapter->hw_init_completed ==_FALSE && bAllow == _FALSE) ++ || pcmdpriv->cmdthd_running== _FALSE //com_thread not running ++ ) ++ { ++ //DBG_871X("%s:%s: drop cmdcode:%u, hw_init_completed:%u, cmdthd_running:%u\n", caller_func, __FUNCTION__, ++ // cmd_obj->cmdcode, ++ // pcmdpriv->padapter->hw_init_completed, ++ // pcmdpriv->cmdthd_running ++ //); ++ ++ return _FAIL; ++ } ++ return _SUCCESS; ++} ++ ++ ++ ++u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) ++{ ++ int res = _FAIL; ++ PADAPTER padapter = pcmdpriv->padapter; ++ ++_func_enter_; ++ ++ if (cmd_obj == NULL) { ++ goto exit; ++ } ++ ++ cmd_obj->padapter = padapter; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ //change pcmdpriv to primary's pcmdpriv ++ if (padapter->adapter_type != PRIMARY_ADAPTER && padapter->pbuddy_adapter) ++ pcmdpriv = &(padapter->pbuddy_adapter->cmdpriv); ++#endif ++ ++ if( _FAIL == (res=rtw_cmd_filter(pcmdpriv, cmd_obj)) ) { ++ rtw_free_cmd_obj(cmd_obj); ++ goto exit; ++ } ++ ++ res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj); ++ ++ if(res == _SUCCESS) ++ _rtw_up_sema(&pcmdpriv->cmd_queue_sema); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv) ++{ ++ struct cmd_obj *cmd_obj; ++ ++_func_enter_; ++ ++ cmd_obj = _rtw_dequeue_cmd(&pcmdpriv->cmd_queue); ++ ++_func_exit_; ++ return cmd_obj; ++} ++ ++void rtw_cmd_clr_isr(struct cmd_priv *pcmdpriv) ++{ ++_func_enter_; ++ pcmdpriv->cmd_done_cnt++; ++ //_rtw_up_sema(&(pcmdpriv->cmd_done_sema)); ++_func_exit_; ++} ++ ++void rtw_free_cmd_obj(struct cmd_obj *pcmd) ++{ ++_func_enter_; ++ ++ if((pcmd->cmdcode!=_JoinBss_CMD_) &&(pcmd->cmdcode!= _CreateBss_CMD_)) ++ { ++ //free parmbuf in cmd_obj ++ rtw_mfree((unsigned char*)pcmd->parmbuf, pcmd->cmdsz); ++ } ++ ++ if(pcmd->rsp!=NULL) ++ { ++ if(pcmd->rspsz!= 0) ++ { ++ //free rsp in cmd_obj ++ rtw_mfree((unsigned char*)pcmd->rsp, pcmd->rspsz); ++ } ++ } ++ ++ //free cmd_obj ++ rtw_mfree((unsigned char*)pcmd, sizeof(struct cmd_obj)); ++ ++_func_exit_; ++} ++ ++ ++void rtw_stop_cmd_thread(_adapter *adapter) ++{ ++ if(adapter->cmdThread && adapter->cmdpriv.cmdthd_running == _TRUE ++ && adapter->cmdpriv.stop_req == 0) ++ { ++ adapter->cmdpriv.stop_req = 1; ++ _rtw_up_sema(&adapter->cmdpriv.cmd_queue_sema); ++ _rtw_down_sema(&adapter->cmdpriv.terminate_cmdthread_sema); ++ } ++} ++ ++thread_return rtw_cmd_thread(thread_context context) ++{ ++ u8 ret; ++ struct cmd_obj *pcmd; ++ u8 *pcmdbuf, *prspbuf; ++ u8 (*cmd_hdl)(_adapter *padapter, u8* pbuf); ++ void (*pcmd_callback)(_adapter *dev, struct cmd_obj *pcmd); ++ PADAPTER padapter = (PADAPTER)context; ++ struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); ++ ++_func_enter_; ++ ++ thread_enter("RTW_CMD_THREAD"); ++ ++ pcmdbuf = pcmdpriv->cmd_buf; ++ prspbuf = pcmdpriv->rsp_buf; ++ ++ pcmdpriv->stop_req = 0; ++ pcmdpriv->cmdthd_running=_TRUE; ++ _rtw_up_sema(&pcmdpriv->terminate_cmdthread_sema); ++ ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("start r871x rtw_cmd_thread !!!!\n")); ++ ++ while(1) ++ { ++ if (_rtw_down_sema(&pcmdpriv->cmd_queue_sema) == _FAIL) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" _rtw_down_sema(&pcmdpriv->cmd_queue_sema) return _FAIL, break\n", FUNC_ADPT_ARG(padapter)); ++ break; ++ } ++ ++ if ((padapter->bDriverStopped == _TRUE)||(padapter->bSurpriseRemoved == _TRUE)) ++ { ++ DBG_871X_LEVEL(_drv_always_, "%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n", ++ __FUNCTION__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__); ++ break; ++ } ++ ++ if (pcmdpriv->stop_req) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" stop_req:%u, break\n", FUNC_ADPT_ARG(padapter), pcmdpriv->stop_req); ++ break; ++ } ++ ++ if(rtw_is_list_empty(&(pcmdpriv->cmd_queue.queue))) ++ { ++ //DBG_871X("%s: cmd queue is empty!\n", __func__); ++ continue; ++ } ++ ++#ifdef CONFIG_LPS_LCLK ++ if (rtw_register_cmd_alive(padapter) != _SUCCESS) ++ { ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ++ ("%s: wait to leave LPS_LCLK\n", __FUNCTION__)); ++ continue; ++ } ++#endif ++ ++_next: ++ if ((padapter->bDriverStopped == _TRUE)||(padapter->bSurpriseRemoved== _TRUE)) ++ { ++ DBG_871X_LEVEL(_drv_always_, "%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n", ++ __FUNCTION__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__); ++ break; ++ } ++ ++ if(!(pcmd = rtw_dequeue_cmd(pcmdpriv))) { ++#ifdef CONFIG_LPS_LCLK ++ rtw_unregister_cmd_alive(padapter); ++#endif ++ continue; ++ } ++ ++ if( _FAIL == rtw_cmd_filter(pcmdpriv, pcmd) ) ++ { ++ pcmd->res = H2C_DROPPED; ++ goto post_process; ++ } ++ ++ pcmdpriv->cmd_issued_cnt++; ++ ++ pcmd->cmdsz = _RND4((pcmd->cmdsz));//_RND4 ++ ++ _rtw_memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz); ++ ++ if(pcmd->cmdcode <= (sizeof(wlancmds) /sizeof(struct cmd_hdl))) ++ { ++ cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns; ++ ++ if (cmd_hdl) ++ { ++ ret = cmd_hdl(pcmd->padapter, pcmdbuf); ++ pcmd->res = ret; ++ } ++ ++ pcmdpriv->cmd_seq++; ++ } ++ else ++ { ++ pcmd->res = H2C_PARAMETERS_ERROR; ++ } ++ ++ cmd_hdl = NULL; ++ ++post_process: ++ ++ //call callback function for post-processed ++ if(pcmd->cmdcode <= (sizeof(rtw_cmd_callback) /sizeof(struct _cmd_callback))) ++ { ++ pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback; ++ if(pcmd_callback == NULL) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("mlme_cmd_hdl(): pcmd_callback=0x%p, cmdcode=0x%x\n", pcmd_callback, pcmd->cmdcode)); ++ rtw_free_cmd_obj(pcmd); ++ } ++ else ++ { ++ //todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!=NULL) ++ pcmd_callback(pcmd->padapter, pcmd);//need conider that free cmd_obj in rtw_cmd_callback ++ } ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("%s: cmdcode=0x%x callback not defined!\n", __FUNCTION__, pcmd->cmdcode)); ++ rtw_free_cmd_obj(pcmd); ++ } ++ ++ flush_signals_thread(); ++ ++ goto _next; ++ ++ } ++ pcmdpriv->cmdthd_running=_FALSE; ++ ++ ++ // free all cmd_obj resources ++ do{ ++ pcmd = rtw_dequeue_cmd(pcmdpriv); ++ if(pcmd==NULL) { ++#ifdef CONFIG_LPS_LCLK ++ rtw_unregister_cmd_alive(padapter); ++#endif ++ break; ++ } ++ ++ //DBG_871X("%s: leaving... drop cmdcode:%u\n", __FUNCTION__, pcmd->cmdcode); ++ ++ rtw_free_cmd_obj(pcmd); ++ }while(1); ++ ++ _rtw_up_sema(&pcmdpriv->terminate_cmdthread_sema); ++ ++_func_exit_; ++ ++ thread_exit(); ++ ++} ++ ++ ++#ifdef CONFIG_EVENT_THREAD_MODE ++u32 rtw_enqueue_evt(struct evt_priv *pevtpriv, struct evt_obj *obj) ++{ ++ _irqL irqL; ++ int res; ++ _queue *queue = &pevtpriv->evt_queue; ++ ++_func_enter_; ++ ++ res = _SUCCESS; ++ ++ if (obj == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ _enter_critical_bh(&queue->lock, &irqL); ++ ++ rtw_list_insert_tail(&obj->list, &queue->queue); ++ ++ _exit_critical_bh(&queue->lock, &irqL); ++ ++ //rtw_evt_notify_isr(pevtpriv); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++struct evt_obj *rtw_dequeue_evt(_queue *queue) ++{ ++ _irqL irqL; ++ struct evt_obj *pevtobj; ++ ++_func_enter_; ++ ++ _enter_critical_bh(&queue->lock, &irqL); ++ ++ if (rtw_is_list_empty(&(queue->queue))) ++ pevtobj = NULL; ++ else ++ { ++ pevtobj = LIST_CONTAINOR(get_next(&(queue->queue)), struct evt_obj, list); ++ rtw_list_delete(&pevtobj->list); ++ } ++ ++ _exit_critical_bh(&queue->lock, &irqL); ++ ++_func_exit_; ++ ++ return pevtobj; ++} ++ ++void rtw_free_evt_obj(struct evt_obj *pevtobj) ++{ ++_func_enter_; ++ ++ if(pevtobj->parmbuf) ++ rtw_mfree((unsigned char*)pevtobj->parmbuf, pevtobj->evtsz); ++ ++ rtw_mfree((unsigned char*)pevtobj, sizeof(struct evt_obj)); ++ ++_func_exit_; ++} ++ ++void rtw_evt_notify_isr(struct evt_priv *pevtpriv) ++{ ++_func_enter_; ++ pevtpriv->evt_done_cnt++; ++ _rtw_up_sema(&(pevtpriv->evt_notify)); ++_func_exit_; ++} ++#endif ++ ++ ++/* ++u8 rtw_setstandby_cmd(unsigned char *adapter) ++*/ ++u8 rtw_setstandby_cmd(_adapter *padapter, uint action) ++{ ++ struct cmd_obj* ph2c; ++ struct usb_suspend_parm* psetusbsuspend; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ ++ u8 ret = _SUCCESS; ++ ++_func_enter_; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ psetusbsuspend = (struct usb_suspend_parm*)rtw_zmalloc(sizeof(struct usb_suspend_parm)); ++ if (psetusbsuspend == NULL) { ++ rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ psetusbsuspend->action = action; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetusbsuspend, GEN_CMD_CODE(_SetUsbSuspend)); ++ ++ ret = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++_func_exit_; ++ ++ return ret; ++} ++ ++/* ++rtw_sitesurvey_cmd(~) ++ ### NOTE:#### (!!!!) ++ MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock ++*/ ++u8 rtw_sitesurvey_cmd(_adapter *padapter, NDIS_802_11_SSID *ssid, int ssid_num, ++ struct rtw_ieee80211_channel *ch, int ch_num) ++{ ++ u8 res = _FAIL; ++ struct cmd_obj *ph2c; ++ struct sitesurvey_parm *psurveyPara; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++#endif //CONFIG_P2P ++ ++_func_enter_; ++ ++#ifdef CONFIG_LPS ++ if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE){ ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1); ++ } ++#endif ++ ++#ifdef CONFIG_P2P_PS ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { ++ p2p_ps_wk_cmd(padapter, P2P_PS_SCAN, 1); ++ } ++#endif //CONFIG_P2P_PS ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) ++ return _FAIL; ++ ++ psurveyPara = (struct sitesurvey_parm*)rtw_zmalloc(sizeof(struct sitesurvey_parm)); ++ if (psurveyPara == NULL) { ++ rtw_mfree((unsigned char*) ph2c, sizeof(struct cmd_obj)); ++ return _FAIL; ++ } ++ ++ rtw_free_network_queue(padapter, _FALSE); ++ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("%s: flush network queue\n", __FUNCTION__)); ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey)); ++ ++ /* psurveyPara->bsslimit = 48; */ ++ psurveyPara->scan_mode = pmlmepriv->scan_mode; ++ ++ /* prepare ssid list */ ++ if (ssid) { ++ int i; ++ for (i=0; issid[i], &ssid[i], sizeof(NDIS_802_11_SSID)); ++ psurveyPara->ssid_num++; ++ if (0) ++ DBG_871X(FUNC_ADPT_FMT" ssid:(%s, %d)\n", FUNC_ADPT_ARG(padapter), ++ psurveyPara->ssid[i].Ssid, psurveyPara->ssid[i].SsidLength); ++ } ++ } ++ } ++ ++ /* prepare channel list */ ++ if (ch) { ++ int i; ++ for (i=0; ich[i], &ch[i], sizeof(struct rtw_ieee80211_channel)); ++ psurveyPara->ch_num++; ++ if (0) ++ DBG_871X(FUNC_ADPT_FMT" ch:%u\n", FUNC_ADPT_ARG(padapter), ++ psurveyPara->ch[i].hw_value); ++ } ++ } ++ } ++ ++ set_fwstate(pmlmepriv, _FW_UNDER_SURVEY); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++ if(res == _SUCCESS) { ++ ++ pmlmepriv->scan_start_time = rtw_get_current_time(); ++ ++#ifdef CONFIG_STA_MODE_SCAN_UNDER_AP_MODE ++ if((padapter->pbuddy_adapter->mlmeextpriv.mlmext_info.state&0x03) == WIFI_FW_AP_STATE) ++ _set_timer(&pmlmepriv->scan_to_timer, SURVEY_TO * ( padapter->mlmeextpriv.max_chan_nums + ( padapter->mlmeextpriv.max_chan_nums / RTW_SCAN_NUM_OF_CH ) * RTW_STAY_AP_CH_MILLISECOND ) + 1000 ); ++ else ++#endif //CONFIG_STA_MODE_SCAN_UNDER_AP_MODE ++ _set_timer(&pmlmepriv->scan_to_timer, SCANNING_TIMEOUT); ++ ++ rtw_led_control(padapter, LED_CTL_SITE_SURVEY); ++ ++ pmlmepriv->scan_interval = SCAN_INTERVAL;// 30*2 sec = 60sec ++ } else { ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); ++ } ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtw_setdatarate_cmd(_adapter *padapter, u8 *rateset) ++{ ++ struct cmd_obj* ph2c; ++ struct setdatarate_parm* pbsetdataratepara; ++ struct cmd_priv* pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++_func_enter_; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pbsetdataratepara = (struct setdatarate_parm*)rtw_zmalloc(sizeof(struct setdatarate_parm)); ++ if (pbsetdataratepara == NULL) { ++ rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara, GEN_CMD_CODE(_SetDataRate)); ++#ifdef MP_FIRMWARE_OFFLOAD ++ pbsetdataratepara->curr_rateidx = *(u32*)rateset; ++// _rtw_memcpy(pbsetdataratepara, rateset, sizeof(u32)); ++#else ++ pbsetdataratepara->mac_id = 5; ++ _rtw_memcpy(pbsetdataratepara->datarates, rateset, NumRates); ++#endif ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtw_setbasicrate_cmd(_adapter *padapter, u8 *rateset) ++{ ++ struct cmd_obj* ph2c; ++ struct setbasicrate_parm* pssetbasicratepara; ++ struct cmd_priv* pcmdpriv=&padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++_func_enter_; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res= _FAIL; ++ goto exit; ++ } ++ pssetbasicratepara = (struct setbasicrate_parm*)rtw_zmalloc(sizeof(struct setbasicrate_parm)); ++ ++ if (pssetbasicratepara == NULL) { ++ rtw_mfree((u8*) ph2c, sizeof(struct cmd_obj)); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pssetbasicratepara, _SetBasicRate_CMD_); ++ ++ _rtw_memcpy(pssetbasicratepara->basicrates, rateset, NumRates); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++ ++/* ++unsigned char rtw_setphy_cmd(unsigned char *adapter) ++ ++1. be called only after rtw_update_registrypriv_dev_network( ~) or mp testing program ++2. for AdHoc/Ap mode or mp mode? ++ ++*/ ++u8 rtw_setphy_cmd(_adapter *padapter, u8 modem, u8 ch) ++{ ++ struct cmd_obj* ph2c; ++ struct setphy_parm* psetphypara; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++// struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++// struct registry_priv* pregistry_priv = &padapter->registrypriv; ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ psetphypara = (struct setphy_parm*)rtw_zmalloc(sizeof(struct setphy_parm)); ++ ++ if(psetphypara==NULL){ ++ rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetphypara, _SetPhy_CMD_); ++ ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("CH=%d, modem=%d", ch, modem)); ++ ++ psetphypara->modem = modem; ++ psetphypara->rfchannel = ch; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++_func_exit_; ++ return res; ++} ++ ++u8 rtw_setbbreg_cmd(_adapter*padapter, u8 offset, u8 val) ++{ ++ struct cmd_obj* ph2c; ++ struct writeBB_parm* pwritebbparm; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ u8 res=_SUCCESS; ++_func_enter_; ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ pwritebbparm = (struct writeBB_parm*)rtw_zmalloc(sizeof(struct writeBB_parm)); ++ ++ if(pwritebbparm==NULL){ ++ rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pwritebbparm, GEN_CMD_CODE(_SetBBReg)); ++ ++ pwritebbparm->offset = offset; ++ pwritebbparm->value = val; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++_func_exit_; ++ return res; ++} ++ ++u8 rtw_getbbreg_cmd(_adapter *padapter, u8 offset, u8 *pval) ++{ ++ struct cmd_obj* ph2c; ++ struct readBB_parm* prdbbparm; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res=_FAIL; ++ goto exit; ++ } ++ prdbbparm = (struct readBB_parm*)rtw_zmalloc(sizeof(struct readBB_parm)); ++ ++ if(prdbbparm ==NULL){ ++ rtw_mfree((unsigned char *) ph2c, sizeof(struct cmd_obj)); ++ return _FAIL; ++ } ++ ++ _rtw_init_listhead(&ph2c->list); ++ ph2c->cmdcode =GEN_CMD_CODE(_GetBBReg); ++ ph2c->parmbuf = (unsigned char *)prdbbparm; ++ ph2c->cmdsz = sizeof(struct readBB_parm); ++ ph2c->rsp = pval; ++ ph2c->rspsz = sizeof(struct readBB_rsp); ++ ++ prdbbparm ->offset = offset; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++_func_exit_; ++ return res; ++} ++ ++u8 rtw_setrfreg_cmd(_adapter *padapter, u8 offset, u32 val) ++{ ++ struct cmd_obj* ph2c; ++ struct writeRF_parm* pwriterfparm; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ u8 res=_SUCCESS; ++_func_enter_; ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ pwriterfparm = (struct writeRF_parm*)rtw_zmalloc(sizeof(struct writeRF_parm)); ++ ++ if(pwriterfparm==NULL){ ++ rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg)); ++ ++ pwriterfparm->offset = offset; ++ pwriterfparm->value = val; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++_func_exit_; ++ return res; ++} ++ ++u8 rtw_getrfreg_cmd(_adapter *padapter, u8 offset, u8 *pval) ++{ ++ struct cmd_obj* ph2c; ++ struct readRF_parm* prdrfparm; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ prdrfparm = (struct readRF_parm*)rtw_zmalloc(sizeof(struct readRF_parm)); ++ if(prdrfparm ==NULL){ ++ rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ _rtw_init_listhead(&ph2c->list); ++ ph2c->cmdcode =GEN_CMD_CODE(_GetRFReg); ++ ph2c->parmbuf = (unsigned char *)prdrfparm; ++ ph2c->cmdsz = sizeof(struct readRF_parm); ++ ph2c->rsp = pval; ++ ph2c->rspsz = sizeof(struct readRF_rsp); ++ ++ prdrfparm ->offset = offset; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++void rtw_getbbrfreg_cmdrsp_callback(_adapter* padapter, struct cmd_obj *pcmd) ++{ ++ _func_enter_; ++ ++ //rtw_free_cmd_obj(pcmd); ++ rtw_mfree((unsigned char*) pcmd->parmbuf, pcmd->cmdsz); ++ rtw_mfree((unsigned char*) pcmd, sizeof(struct cmd_obj)); ++ ++#ifdef CONFIG_MP_INCLUDED ++ if (padapter->registrypriv.mp_mode == 1) ++ padapter->mppriv.workparam.bcompleted= _TRUE; ++#endif ++_func_exit_; ++} ++ ++void rtw_readtssi_cmdrsp_callback(_adapter* padapter, struct cmd_obj *pcmd) ++{ ++ _func_enter_; ++ ++ rtw_mfree((unsigned char*) pcmd->parmbuf, pcmd->cmdsz); ++ rtw_mfree((unsigned char*) pcmd, sizeof(struct cmd_obj)); ++ ++#ifdef CONFIG_MP_INCLUDED ++ if (padapter->registrypriv.mp_mode == 1) ++ padapter->mppriv.workparam.bcompleted= _TRUE; ++#endif ++ ++_func_exit_; ++} ++ ++u8 rtw_createbss_cmd(_adapter *padapter) ++{ ++ struct cmd_obj* pcmd; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ WLAN_BSSID_EX *pdev_network = &padapter->registrypriv.dev_network; ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++ rtw_led_control(padapter, LED_CTL_START_TO_LINK); ++ ++ if (pmlmepriv->assoc_ssid.SsidLength == 0){ ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,(" createbss for Any SSid:%s\n",pmlmepriv->assoc_ssid.Ssid)); ++ } else { ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,(" createbss for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid)); ++ } ++ ++ pcmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(pcmd==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ _rtw_init_listhead(&pcmd->list); ++ pcmd->cmdcode = _CreateBss_CMD_; ++ pcmd->parmbuf = (unsigned char *)pdev_network; ++ pcmd->cmdsz = get_WLAN_BSSID_EX_sz((WLAN_BSSID_EX*)pdev_network); ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ ++ pdev_network->Length = pcmd->cmdsz; ++ ++#ifdef CONFIG_RTL8712 ++ //notes: translate IELength & Length after assign the Length to cmdsz; ++ pdev_network->Length = cpu_to_le32(pcmd->cmdsz); ++ pdev_network->IELength = cpu_to_le32(pdev_network->IELength); ++ pdev_network->Ssid.SsidLength = cpu_to_le32(pdev_network->Ssid.SsidLength); ++#endif ++ ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtw_createbss_cmd_ex(_adapter *padapter, unsigned char *pbss, unsigned int sz) ++{ ++ struct cmd_obj* pcmd; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++ pcmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(pcmd==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ _rtw_init_listhead(&pcmd->list); ++ pcmd->cmdcode = GEN_CMD_CODE(_CreateBss); ++ pcmd->parmbuf = pbss; ++ pcmd->cmdsz = sz; ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtw_joinbss_cmd(_adapter *padapter, struct wlan_network* pnetwork) ++{ ++ u8 *auth, res = _SUCCESS; ++ uint t_len = 0; ++ WLAN_BSSID_EX *psecnetwork; ++ struct cmd_obj *pcmd; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct qos_priv *pqospriv= &pmlmepriv->qospriv; ++ struct security_priv *psecuritypriv=&padapter->securitypriv; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++#ifdef CONFIG_80211N_HT ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++#endif //CONFIG_80211N_HT ++ NDIS_802_11_NETWORK_INFRASTRUCTURE ndis_network_mode = pnetwork->network.InfrastructureMode; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++_func_enter_; ++ ++ rtw_led_control(padapter, LED_CTL_START_TO_LINK); ++ ++ if (pmlmepriv->assoc_ssid.SsidLength == 0){ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+Join cmd: Any SSid\n")); ++ } else { ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+Join cmd: SSid=[%s]\n", pmlmepriv->assoc_ssid.Ssid)); ++ } ++ ++ pcmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(pcmd==NULL){ ++ res=_FAIL; ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd: memory allocate for cmd_obj fail!!!\n")); ++ goto exit; ++ } ++ /* // for IEs is pointer ++ t_len = sizeof (ULONG) + sizeof (NDIS_802_11_MAC_ADDRESS) + 2 + ++ sizeof (NDIS_802_11_SSID) + sizeof (ULONG) + ++ sizeof (NDIS_802_11_RSSI) + sizeof (NDIS_802_11_NETWORK_TYPE) + ++ sizeof (NDIS_802_11_CONFIGURATION) + ++ sizeof (NDIS_802_11_NETWORK_INFRASTRUCTURE) + ++ sizeof (NDIS_802_11_RATES_EX)+ sizeof(WLAN_PHY_INFO)+ sizeof (ULONG) + MAX_IE_SZ; ++ */ ++ //for IEs is fix buf size ++ t_len = sizeof(WLAN_BSSID_EX); ++ ++ ++ //for hidden ap to set fw_state here ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) != _TRUE) ++ { ++ switch(ndis_network_mode) ++ { ++ case Ndis802_11IBSS: ++ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); ++ break; ++ ++ case Ndis802_11Infrastructure: ++ set_fwstate(pmlmepriv, WIFI_STATION_STATE); ++ break; ++ ++ case Ndis802_11APMode: ++ case Ndis802_11AutoUnknown: ++ case Ndis802_11InfrastructureMax: ++ break; ++ ++ } ++ } ++ ++ psecnetwork=(WLAN_BSSID_EX *)&psecuritypriv->sec_bss; ++ if(psecnetwork==NULL) ++ { ++ if(pcmd !=NULL) ++ rtw_mfree((unsigned char *)pcmd, sizeof(struct cmd_obj)); ++ ++ res=_FAIL; ++ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd :psecnetwork==NULL!!!\n")); ++ ++ goto exit; ++ } ++ ++ _rtw_memset(psecnetwork, 0, t_len); ++ ++ _rtw_memcpy(psecnetwork, &pnetwork->network, get_WLAN_BSSID_EX_sz(&pnetwork->network)); ++ ++ auth=&psecuritypriv->authenticator_ie[0]; ++ psecuritypriv->authenticator_ie[0]=(unsigned char)psecnetwork->IELength; ++ ++ if((psecnetwork->IELength-12) < (256-1)) { ++ _rtw_memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], psecnetwork->IELength-12); ++ } else { ++ _rtw_memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], (256-1)); ++ } ++ ++ psecnetwork->IELength = 0; ++ // Added by Albert 2009/02/18 ++ // If the the driver wants to use the bssid to create the connection. ++ // If not, we have to copy the connecting AP's MAC address to it so that ++ // the driver just has the bssid information for PMKIDList searching. ++ ++ if ( pmlmepriv->assoc_by_bssid == _FALSE ) ++ { ++ _rtw_memcpy( &pmlmepriv->assoc_bssid[ 0 ], &pnetwork->network.MacAddress[ 0 ], ETH_ALEN ); ++ } ++ ++ psecnetwork->IELength = rtw_restruct_sec_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength); ++ ++ ++ pqospriv->qos_option = 0; ++ ++ if(pregistrypriv->wmm_enable) ++ { ++ u32 tmp_len; ++ ++ tmp_len = rtw_restruct_wmm_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength, psecnetwork->IELength); ++ ++ if (psecnetwork->IELength != tmp_len) ++ { ++ psecnetwork->IELength = tmp_len; ++ pqospriv->qos_option = 1; //There is WMM IE in this corresp. beacon ++ } ++ else ++ { ++ pqospriv->qos_option = 0;//There is no WMM IE in this corresp. beacon ++ } ++ } ++ ++#ifdef CONFIG_80211N_HT ++ phtpriv->ht_option = _FALSE; ++ if(pregistrypriv->ht_enable) ++ { ++ // Added by Albert 2010/06/23 ++ // For the WEP mode, we will use the bg mode to do the connection to avoid some IOT issue. ++ // Especially for Realtek 8192u SoftAP. ++ if ( ( padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_ ) && ++ ( padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_ ) && ++ ( padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_ )) ++ { ++ //rtw_restructure_ht_ie ++ rtw_restructure_ht_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], ++ pnetwork->network.IELength, &psecnetwork->IELength); ++ } ++ } ++ ++#endif ++ ++ pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->network.IEs, pnetwork->network.IELength); ++ ++ if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_TENDA) ++ adapter_to_pwrctl(padapter)->smart_ps = 0; ++ else ++ adapter_to_pwrctl(padapter)->smart_ps = padapter->registrypriv.smart_ps; ++ ++ DBG_871X("%s: smart_ps=%d\n", __func__, adapter_to_pwrctl(padapter)->smart_ps); ++ ++ #if 0 ++ psecuritypriv->supplicant_ie[0]=(u8)psecnetwork->IELength; ++ ++ if(psecnetwork->IELength < (256-1)) ++ { ++ _rtw_memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0], psecnetwork->IELength); ++ } ++ else ++ { ++ _rtw_memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0], (256-1)); ++ } ++ #endif ++ ++ pcmd->cmdsz = get_WLAN_BSSID_EX_sz(psecnetwork);//get cmdsz before endian conversion ++ ++#ifdef CONFIG_RTL8712 ++ //wlan_network endian conversion ++ psecnetwork->Length = cpu_to_le32(psecnetwork->Length); ++ psecnetwork->Ssid.SsidLength= cpu_to_le32(psecnetwork->Ssid.SsidLength); ++ psecnetwork->Privacy = cpu_to_le32(psecnetwork->Privacy); ++ psecnetwork->Rssi = cpu_to_le32(psecnetwork->Rssi); ++ psecnetwork->NetworkTypeInUse = cpu_to_le32(psecnetwork->NetworkTypeInUse); ++ psecnetwork->Configuration.ATIMWindow = cpu_to_le32(psecnetwork->Configuration.ATIMWindow); ++ psecnetwork->Configuration.BeaconPeriod = cpu_to_le32(psecnetwork->Configuration.BeaconPeriod); ++ psecnetwork->Configuration.DSConfig = cpu_to_le32(psecnetwork->Configuration.DSConfig); ++ psecnetwork->Configuration.FHConfig.DwellTime=cpu_to_le32(psecnetwork->Configuration.FHConfig.DwellTime); ++ psecnetwork->Configuration.FHConfig.HopPattern=cpu_to_le32(psecnetwork->Configuration.FHConfig.HopPattern); ++ psecnetwork->Configuration.FHConfig.HopSet=cpu_to_le32(psecnetwork->Configuration.FHConfig.HopSet); ++ psecnetwork->Configuration.FHConfig.Length=cpu_to_le32(psecnetwork->Configuration.FHConfig.Length); ++ psecnetwork->Configuration.Length = cpu_to_le32(psecnetwork->Configuration.Length); ++ psecnetwork->InfrastructureMode = cpu_to_le32(psecnetwork->InfrastructureMode); ++ psecnetwork->IELength = cpu_to_le32(psecnetwork->IELength); ++#endif ++ ++ _rtw_init_listhead(&pcmd->list); ++ pcmd->cmdcode = _JoinBss_CMD_;//GEN_CMD_CODE(_JoinBss) ++ pcmd->parmbuf = (unsigned char *)psecnetwork; ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtw_disassoc_cmd(_adapter*padapter, u32 deauth_timeout_ms, bool enqueue) /* for sta_mode */ ++{ ++ struct cmd_obj *cmdobj = NULL; ++ struct disconnect_parm *param = NULL; ++ struct cmd_priv *cmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_disassoc_cmd\n")); ++ ++ /* prepare cmd parameter */ ++ param = (struct disconnect_parm *)rtw_zmalloc(sizeof(*param)); ++ if (param == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ param->deauth_timeout_ms = deauth_timeout_ms; ++ ++ if (enqueue) { ++ /* need enqueue, prepare cmd_obj and enqueue */ ++ cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj)); ++ if (cmdobj == NULL) { ++ res = _FAIL; ++ rtw_mfree((u8 *)param, sizeof(*param)); ++ goto exit; ++ } ++ init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_); ++ res = rtw_enqueue_cmd(cmdpriv, cmdobj); ++ } else { ++ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ ++ if (H2C_SUCCESS != disconnect_hdl(padapter, (u8 *)param)) ++ res = _FAIL; ++ rtw_mfree((u8 *)param, sizeof(*param)); ++ } ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtw_setopmode_cmd(_adapter *padapter, NDIS_802_11_NETWORK_INFRASTRUCTURE networktype, bool enqueue) ++{ ++ struct cmd_obj* ph2c; ++ struct setopmode_parm* psetop; ++ ++ struct cmd_priv *pcmdpriv= &padapter->cmdpriv; ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ psetop = (struct setopmode_parm*)rtw_zmalloc(sizeof(struct setopmode_parm)); ++ ++ if(psetop==NULL){ ++ res=_FAIL; ++ goto exit; ++ } ++ psetop->mode = (u8)networktype; ++ ++ if(enqueue){ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ rtw_mfree((u8 *)psetop, sizeof(*psetop)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_); ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ } ++ else{ ++ setopmode_hdl(padapter, (u8 *)psetop); ++ rtw_mfree((u8 *)psetop, sizeof(*psetop)); ++ } ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtw_setstakey_cmd(_adapter *padapter, u8 *psta, u8 unicast_key, bool enqueue) ++{ ++ struct cmd_obj* ph2c; ++ struct set_stakey_parm *psetstakey_para; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ struct set_stakey_rsp *psetstakey_rsp = NULL; ++ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct sta_info* sta = (struct sta_info* )psta; ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++ psetstakey_para = (struct set_stakey_parm*)rtw_zmalloc(sizeof(struct set_stakey_parm)); ++ if(psetstakey_para==NULL){ ++ res=_FAIL; ++ goto exit; ++ } ++ ++ _rtw_memcpy(psetstakey_para->addr, sta->hwaddr,ETH_ALEN); ++ ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE)){ ++#ifdef CONFIG_TDLS ++ if(sta->tdls_sta_state&TDLS_LINKED_STATE) ++ psetstakey_para->algorithm=(u8)sta->dot118021XPrivacy; ++ else ++#endif //CONFIG_TDLS ++ psetstakey_para->algorithm =(unsigned char) psecuritypriv->dot11PrivacyAlgrthm; ++ }else{ ++ GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, _FALSE); ++ } ++ ++ if (unicast_key == _TRUE) { ++#ifdef CONFIG_TDLS ++ if((sta->tdls_sta_state&TDLS_LINKED_STATE)==TDLS_LINKED_STATE) ++ _rtw_memcpy(&psetstakey_para->key, sta->tpk.tk, 16); ++ else ++#endif //CONFIG_TDLS ++ _rtw_memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16); ++ } ++ else { ++ _rtw_memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16); ++ } ++ ++ //jeff: set this becasue at least sw key is ready ++ padapter->securitypriv.busetkipkey=_TRUE; ++ ++ if(enqueue) ++ { ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if ( ph2c == NULL){ ++ rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ psetstakey_rsp = (struct set_stakey_rsp*)rtw_zmalloc(sizeof(struct set_stakey_rsp)); ++ if(psetstakey_rsp == NULL){ ++ rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); ++ rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm)); ++ res=_FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); ++ ph2c->rsp = (u8 *) psetstakey_rsp; ++ ph2c->rspsz = sizeof(struct set_stakey_rsp); ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ } ++ else{ ++ set_stakey_hdl(padapter, (u8 *)psetstakey_para); ++ rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm)); ++ } ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtw_clearstakey_cmd(_adapter *padapter, u8 *psta, u8 entry, u8 enqueue) ++{ ++ struct cmd_obj* ph2c; ++ struct set_stakey_parm *psetstakey_para; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ struct set_stakey_rsp *psetstakey_rsp = NULL; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct sta_info* sta = (struct sta_info* )psta; ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++ if(!enqueue) ++ { ++ clear_cam_entry(padapter, entry); ++ } ++ else ++ { ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if ( ph2c == NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ psetstakey_para = (struct set_stakey_parm*)rtw_zmalloc(sizeof(struct set_stakey_parm)); ++ if(psetstakey_para==NULL){ ++ rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); ++ res=_FAIL; ++ goto exit; ++ } ++ ++ psetstakey_rsp = (struct set_stakey_rsp*)rtw_zmalloc(sizeof(struct set_stakey_rsp)); ++ if(psetstakey_rsp == NULL){ ++ rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); ++ rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm)); ++ res=_FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); ++ ph2c->rsp = (u8 *) psetstakey_rsp; ++ ph2c->rspsz = sizeof(struct set_stakey_rsp); ++ ++ _rtw_memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN); ++ ++ psetstakey_para->algorithm = _NO_PRIVACY_; ++ ++ psetstakey_para->id = entry; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++ } ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtw_setrttbl_cmd(_adapter *padapter, struct setratable_parm *prate_table) ++{ ++ struct cmd_obj* ph2c; ++ struct setratable_parm * psetrttblparm; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ u8 res=_SUCCESS; ++_func_enter_; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ psetrttblparm = (struct setratable_parm*)rtw_zmalloc(sizeof(struct setratable_parm)); ++ ++ if(psetrttblparm==NULL){ ++ rtw_mfree((unsigned char *) ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable)); ++ ++ _rtw_memcpy(psetrttblparm,prate_table,sizeof(struct setratable_parm)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++_func_exit_; ++ return res; ++ ++} ++ ++u8 rtw_getrttbl_cmd(_adapter *padapter, struct getratable_rsp *pval) ++{ ++ struct cmd_obj* ph2c; ++ struct getratable_parm * pgetrttblparm; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ u8 res=_SUCCESS; ++_func_enter_; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ pgetrttblparm = (struct getratable_parm*)rtw_zmalloc(sizeof(struct getratable_parm)); ++ ++ if(pgetrttblparm==NULL){ ++ rtw_mfree((unsigned char *) ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++// init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable)); ++ ++ _rtw_init_listhead(&ph2c->list); ++ ph2c->cmdcode =GEN_CMD_CODE(_GetRaTable); ++ ph2c->parmbuf = (unsigned char *)pgetrttblparm; ++ ph2c->cmdsz = sizeof(struct getratable_parm); ++ ph2c->rsp = (u8*)pval; ++ ph2c->rspsz = sizeof(struct getratable_rsp); ++ ++ pgetrttblparm ->rsvd = 0x0; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++_func_exit_; ++ return res; ++ ++} ++ ++u8 rtw_setassocsta_cmd(_adapter *padapter, u8 *mac_addr) ++{ ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ struct cmd_obj* ph2c; ++ struct set_assocsta_parm *psetassocsta_para; ++ struct set_stakey_rsp *psetassocsta_rsp = NULL; ++ ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ psetassocsta_para = (struct set_assocsta_parm*)rtw_zmalloc(sizeof(struct set_assocsta_parm)); ++ if(psetassocsta_para==NULL){ ++ rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); ++ res=_FAIL; ++ goto exit; ++ } ++ ++ psetassocsta_rsp = (struct set_stakey_rsp*)rtw_zmalloc(sizeof(struct set_assocsta_rsp)); ++ if(psetassocsta_rsp==NULL){ ++ rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); ++ rtw_mfree((u8 *) psetassocsta_para, sizeof(struct set_assocsta_parm)); ++ return _FAIL; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetassocsta_para, _SetAssocSta_CMD_); ++ ph2c->rsp = (u8 *) psetassocsta_rsp; ++ ph2c->rspsz = sizeof(struct set_assocsta_rsp); ++ ++ _rtw_memcpy(psetassocsta_para->addr, mac_addr,ETH_ALEN); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++ } ++ ++u8 rtw_addbareq_cmd(_adapter*padapter, u8 tid, u8 *addr) ++{ ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ struct cmd_obj* ph2c; ++ struct addBaReq_parm *paddbareq_parm; ++ ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ paddbareq_parm = (struct addBaReq_parm*)rtw_zmalloc(sizeof(struct addBaReq_parm)); ++ if(paddbareq_parm==NULL){ ++ rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ paddbareq_parm->tid = tid; ++ _rtw_memcpy(paddbareq_parm->addr, addr, ETH_ALEN); ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq)); ++ ++ //DBG_871X("rtw_addbareq_cmd, tid=%d\n", tid); ++ ++ //rtw_enqueue_cmd(pcmdpriv, ph2c); ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++//add for CONFIG_IEEE80211W, none 11w can use it ++u8 rtw_reset_securitypriv_cmd(_adapter*padapter) ++{ ++ struct cmd_obj* ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if(pdrvextra_cmd_parm==NULL){ ++ rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = RESET_SECURITYPRIV; ++ pdrvextra_cmd_parm->type_size = 0; ++ pdrvextra_cmd_parm->pbuf = (u8 *)padapter; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ ++ //rtw_enqueue_cmd(pcmdpriv, ph2c); ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++ ++} ++ ++u8 rtw_free_assoc_resources_cmd(_adapter*padapter) ++{ ++ struct cmd_obj* ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if(pdrvextra_cmd_parm==NULL){ ++ rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = FREE_ASSOC_RESOURCES; ++ pdrvextra_cmd_parm->type_size = 0; ++ pdrvextra_cmd_parm->pbuf = (u8 *)padapter; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ ++ //rtw_enqueue_cmd(pcmdpriv, ph2c); ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++ ++} ++ ++u8 rtw_dynamic_chk_wk_cmd(_adapter*padapter) ++{ ++ struct cmd_obj* ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (padapter->adapter_type != PRIMARY_ADAPTER && padapter->pbuddy_adapter) ++ pcmdpriv = &(padapter->pbuddy_adapter->cmdpriv); ++#endif ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if(pdrvextra_cmd_parm==NULL){ ++ rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID; ++ pdrvextra_cmd_parm->type_size = 0; ++ pdrvextra_cmd_parm->pbuf = (u8 *)padapter; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ ++ //rtw_enqueue_cmd(pcmdpriv, ph2c); ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++ ++} ++ ++u8 rtw_set_ch_cmd(_adapter*padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue) ++{ ++ struct cmd_obj *pcmdobj; ++ struct set_ch_parm *set_ch_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++ DBG_871X(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n", ++ FUNC_NDEV_ARG(padapter->pnetdev), ch, bw, ch_offset); ++ ++ /* check input parameter */ ++ ++ /* prepare cmd parameter */ ++ set_ch_parm = (struct set_ch_parm *)rtw_zmalloc(sizeof(*set_ch_parm)); ++ if (set_ch_parm == NULL) { ++ res= _FAIL; ++ goto exit; ++ } ++ set_ch_parm->ch = ch; ++ set_ch_parm->bw = bw; ++ set_ch_parm->ch_offset = ch_offset; ++ ++ if (enqueue) { ++ /* need enqueue, prepare cmd_obj and enqueue */ ++ pcmdobj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(pcmdobj == NULL){ ++ rtw_mfree((u8 *)set_ch_parm, sizeof(*set_ch_parm)); ++ res=_FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(pcmdobj, set_ch_parm, GEN_CMD_CODE(_SetChannel)); ++ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); ++ } else { ++ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ ++ if( H2C_SUCCESS !=set_ch_hdl(padapter, (u8 *)set_ch_parm) ) ++ res = _FAIL; ++ ++ rtw_mfree((u8 *)set_ch_parm, sizeof(*set_ch_parm)); ++ } ++ ++ /* do something based on res... */ ++ ++exit: ++ ++ DBG_871X(FUNC_NDEV_FMT" res:%u\n", FUNC_NDEV_ARG(padapter->pnetdev), res); ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtw_set_chplan_cmd(_adapter*padapter, u8 chplan, u8 enqueue) ++{ ++ struct cmd_obj* pcmdobj; ++ struct SetChannelPlan_param *setChannelPlan_param; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_chplan_cmd\n")); ++ ++ //check input parameter ++ if(!rtw_is_channel_plan_valid(chplan)) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ //prepare cmd parameter ++ setChannelPlan_param = (struct SetChannelPlan_param *)rtw_zmalloc(sizeof(struct SetChannelPlan_param)); ++ if(setChannelPlan_param == NULL) { ++ res= _FAIL; ++ goto exit; ++ } ++ setChannelPlan_param->channel_plan=chplan; ++ ++ if(enqueue) ++ { ++ //need enqueue, prepare cmd_obj and enqueue ++ pcmdobj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(pcmdobj == NULL){ ++ rtw_mfree((u8 *)setChannelPlan_param, sizeof(struct SetChannelPlan_param)); ++ res=_FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelPlan_param, GEN_CMD_CODE(_SetChannelPlan)); ++ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); ++ } ++ else ++ { ++ //no need to enqueue, do the cmd hdl directly and free cmd parameter ++ if( H2C_SUCCESS !=set_chplan_hdl(padapter, (unsigned char *)setChannelPlan_param) ) ++ res = _FAIL; ++ ++ rtw_mfree((u8 *)setChannelPlan_param, sizeof(struct SetChannelPlan_param)); ++ } ++ ++ //do something based on res... ++ if(res == _SUCCESS) ++ padapter->mlmepriv.ChannelPlan = chplan; ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtw_led_blink_cmd(_adapter*padapter, PLED_871x pLed) ++{ ++ struct cmd_obj* pcmdobj; ++ struct LedBlink_param *ledBlink_param; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_led_blink_cmd\n")); ++ ++ pcmdobj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(pcmdobj == NULL){ ++ res=_FAIL; ++ goto exit; ++ } ++ ++ ledBlink_param = (struct LedBlink_param *)rtw_zmalloc(sizeof(struct LedBlink_param)); ++ if(ledBlink_param == NULL) { ++ rtw_mfree((u8 *)pcmdobj, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ ledBlink_param->pLed=pLed; ++ ++ init_h2fwcmd_w_parm_no_rsp(pcmdobj, ledBlink_param, GEN_CMD_CODE(_LedBlink)); ++ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtw_set_csa_cmd(_adapter*padapter, u8 new_ch_no) ++{ ++ struct cmd_obj* pcmdobj; ++ struct SetChannelSwitch_param*setChannelSwitch_param; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_csa_cmd\n")); ++ ++ pcmdobj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(pcmdobj == NULL){ ++ res=_FAIL; ++ goto exit; ++ } ++ ++ setChannelSwitch_param = (struct SetChannelSwitch_param *)rtw_zmalloc(sizeof(struct SetChannelSwitch_param)); ++ if(setChannelSwitch_param == NULL) { ++ rtw_mfree((u8 *)pcmdobj, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ setChannelSwitch_param->new_ch_no=new_ch_no; ++ ++ init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelSwitch_param, GEN_CMD_CODE(_SetChannelSwitch)); ++ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtw_tdls_cmd(_adapter *padapter, u8 *addr, u8 option) ++{ ++ struct cmd_obj* pcmdobj; ++ struct TDLSoption_param *TDLSoption; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++#ifdef CONFIG_TDLS ++ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_tdls_cmd\n")); ++ ++ pcmdobj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(pcmdobj == NULL){ ++ res=_FAIL; ++ goto exit; ++ } ++ ++ TDLSoption= (struct TDLSoption_param *)rtw_zmalloc(sizeof(struct TDLSoption_param)); ++ if(TDLSoption == NULL) { ++ rtw_mfree((u8 *)pcmdobj, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ _rtw_spinlock(&(padapter->tdlsinfo.cmd_lock)); ++ _rtw_memcpy(TDLSoption->addr, addr, 6); ++ TDLSoption->option = option; ++ _rtw_spinunlock(&(padapter->tdlsinfo.cmd_lock)); ++ init_h2fwcmd_w_parm_no_rsp(pcmdobj, TDLSoption, GEN_CMD_CODE(_TDLS)); ++ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); ++ ++#endif //CONFIG_TDLS ++ ++exit: ++ ++ ++_func_exit_; ++ ++ return res; ++} ++ ++#ifdef CONFIG_DETECT_C2H_BY_POLLING ++u8 rtw_event_polling_cmd(_adapter*padapter) ++{ ++ struct cmd_obj* ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++#if defined(CONFIG_CONCURRENT_MODE) ++ if (padapter->adapter_type != PRIMARY_ADAPTER) ++ { ++ return _FAIL; ++ } ++#endif ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if(pdrvextra_cmd_parm==NULL){ ++ rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = EVENT_POLLING_CID; ++ pdrvextra_cmd_parm->type_size = 0; ++ pdrvextra_cmd_parm->pbuf = (u8 *)padapter; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ ++ //rtw_enqueue_cmd(pcmdpriv, ph2c); ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ _func_exit_; ++ ++ return res; ++} ++#endif ++ ++static void traffic_status_watchdog(_adapter *padapter) ++{ ++#ifdef CONFIG_LPS ++ u8 bEnterPS; ++#endif ++ u16 BusyThreshold = 200;// 100; ++ u8 bBusyTraffic = _FALSE, bTxBusyTraffic = _FALSE, bRxBusyTraffic = _FALSE; ++ u8 bHigherBusyTraffic = _FALSE, bHigherBusyRxTraffic = _FALSE, bHigherBusyTxTraffic = _FALSE; ++#ifdef CONFIG_FTP_PROTECT ++ u16 bPktCount = 0; ++#endif ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++#ifdef CONFIG_TDLS ++ struct tdls_info *ptdlsinfo = &(padapter->tdlsinfo); ++#endif //CONFIG_TDLS ++ ++ RT_LINK_DETECT_T * link_detect = &pmlmepriv->LinkDetectInfo; ++ ++ // ++ // Determine if our traffic is busy now ++ // ++ if((check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE) ++ /*&& !MgntInitAdapterInProgress(pMgntInfo)*/) ++ { ++ // if we raise bBusyTraffic in last watchdog, using lower threshold. ++ if (pmlmepriv->LinkDetectInfo.bBusyTraffic) ++ BusyThreshold =180; // 75; ++ if( pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > BusyThreshold || ++ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > BusyThreshold ) ++ { ++ bBusyTraffic = _TRUE; ++ ++ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) ++ bRxBusyTraffic = _TRUE; ++ else ++ bTxBusyTraffic = _TRUE; ++ } ++ ++ // Higher Tx/Rx data. ++ if( pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 || ++ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000 ) ++ { ++ bHigherBusyTraffic = _TRUE; ++ ++ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) ++ bHigherBusyRxTraffic = _TRUE; ++ else ++ bHigherBusyTxTraffic = _TRUE; ++ } ++ ++#ifdef CONFIG_FTP_PROTECT ++ DBG_871X("RX in period:%d, TX in period:%d, ftp_lock_flag:%d\n", ++ pmlmepriv->LinkDetectInfo.NumRxOkInPeriod, ++ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod, ++ pmlmepriv->ftp_lock_flag); ++ ++ bPktCount = pmlmepriv->LinkDetectInfo.NumRxOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod; ++ if (bPktCount > 20 && !pmlmepriv->ftp_lock_flag) { ++ pmlmepriv->ftp_lock_flag = 1; ++ rtw_lock_suspend(); ++ } else if(bPktCount == 0 && pmlmepriv->ftp_lock_flag) { ++ pmlmepriv->ftp_lock_flag = 0; ++ rtw_unlock_suspend(); ++ } ++#endif //CONFIG_KEEP_FTP_TRANSMIT ++ ++#ifdef CONFIG_TRAFFIC_PROTECT ++#define TX_ACTIVE_TH 2 ++#define RX_ACTIVE_TH 1 ++#define TRAFFIC_PROTECT_PERIOD_MS 4500 ++ ++ if (link_detect->NumTxOkInPeriod > TX_ACTIVE_TH ++ || link_detect->NumRxUnicastOkInPeriod > RX_ACTIVE_TH) { ++ ++ DBG_871X_LEVEL(_drv_info_, FUNC_ADPT_FMT" acqiure wake_lock for %u ms(tx:%d,rx_unicast:%d)\n", ++ FUNC_ADPT_ARG(padapter), ++ TRAFFIC_PROTECT_PERIOD_MS, ++ link_detect->NumTxOkInPeriod, ++ link_detect->NumRxUnicastOkInPeriod); ++ ++ rtw_lock_suspend_timeout(TRAFFIC_PROTECT_PERIOD_MS); ++ } ++#endif ++ ++#ifdef CONFIG_TDLS ++#ifdef CONFIG_TDLS_AUTOSETUP ++ if( ( ptdlsinfo->watchdog_count % TDLS_WATCHDOG_PERIOD ) == 0 ) //10 * 2sec, periodically sending ++ issue_tdls_dis_req( padapter, NULL ); ++ ptdlsinfo->watchdog_count++; ++#endif //CONFIG_TDLS_AUTOSETUP ++#endif //CONFIG_TDLS ++ ++#ifdef CONFIG_LPS ++#ifdef CONFIG_BT_COEXIST ++ if (BT_1Ant(padapter) == _FALSE) ++#endif ++ { ++ // check traffic for powersaving. ++ if( ((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8 ) || ++ (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2) ) ++ { ++ //DBG_871X("Tx = %d, Rx = %d \n",pmlmepriv->LinkDetectInfo.NumTxOkInPeriod,pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod); ++ bEnterPS= _FALSE; ++ } ++ else ++ { ++ bEnterPS= _TRUE; ++ } ++ ++ // LeisurePS only work in infra mode. ++ if(bEnterPS) ++ { ++ LPS_Enter(padapter); ++ } ++ else ++ { ++ LPS_Leave(padapter); ++ } ++ } ++#endif // CONFIG_LPS ++ } ++ else ++ { ++#ifdef CONFIG_LPS ++ LPS_Leave(padapter); ++#endif ++ } ++ ++ pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0; ++ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0; ++ pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0; ++ pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic; ++ pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic; ++ pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic; ++ pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic; ++ pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic; ++ pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic; ++} ++ ++void dynamic_chk_wk_hdl(_adapter *padapter, u8 *pbuf, int sz); ++void dynamic_chk_wk_hdl(_adapter *padapter, u8 *pbuf, int sz) ++{ ++ struct mlme_priv *pmlmepriv; ++ ++ padapter = (_adapter *)pbuf; ++ pmlmepriv = &(padapter->mlmepriv); ++ ++#ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK ++#ifdef CONFIG_AP_MODE ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ { ++ expire_timeout_chk(padapter); ++ } ++#endif ++#endif //CONFIG_ACTIVE_KEEP_ALIVE_CHECK ++ ++ #ifdef DBG_CONFIG_ERROR_DETECT ++ rtw_hal_sreset_xmit_status_check(padapter); ++ #endif ++ ++ //if(check_fwstate(pmlmepriv, _FW_UNDER_LINKING|_FW_UNDER_SURVEY)==_FALSE) ++ { ++ linked_status_chk(padapter); ++ traffic_status_watchdog(padapter); ++ } ++ ++ rtw_hal_dm_watchdog(padapter); ++ ++ //check_hw_pbc(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size); ++ ++#ifdef CONFIG_BT_COEXIST ++ // ++ // BT-Coexist ++ // ++ BT_CoexistMechanism(padapter); ++#endif ++} ++ ++#ifdef CONFIG_LPS ++ ++void lps_ctrl_wk_hdl(_adapter *padapter, u8 lps_ctrl_type); ++void lps_ctrl_wk_hdl(_adapter *padapter, u8 lps_ctrl_type) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ u8 mstatus; ++ ++_func_enter_; ++ ++ if((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) ++ || (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE)) ++ { ++ return; ++ } ++ ++ switch(lps_ctrl_type) ++ { ++ case LPS_CTRL_SCAN: ++ //DBG_871X("LPS_CTRL_SCAN \n"); ++#ifdef CONFIG_BT_COEXIST ++ BT_WifiScanNotify(padapter, _TRUE); ++ if (BT_1Ant(padapter) == _FALSE) ++#endif ++ { ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ++ { //connect ++ LPS_Leave(padapter); ++ } ++ } ++ break; ++ case LPS_CTRL_JOINBSS: ++ //DBG_871X("LPS_CTRL_JOINBSS \n"); ++ LPS_Leave(padapter); ++ break; ++ case LPS_CTRL_CONNECT: ++ //DBG_871X("LPS_CTRL_CONNECT \n"); ++ mstatus = 1;//connect ++ // Reset LPS Setting ++ pwrpriv->LpsIdleCount = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus)); ++#ifdef CONFIG_BT_COEXIST ++ BT_WifiMediaStatusNotify(padapter, mstatus); ++#endif ++ break; ++ case LPS_CTRL_DISCONNECT: ++ //DBG_871X("LPS_CTRL_DISCONNECT \n"); ++ mstatus = 0;//disconnect ++#ifdef CONFIG_BT_COEXIST ++ BT_WifiMediaStatusNotify(padapter, mstatus); ++ if (BT_1Ant(padapter) == _FALSE) ++#endif ++ { ++ LPS_Leave(padapter); ++ } ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus)); ++ break; ++ case LPS_CTRL_SPECIAL_PACKET: ++ //DBG_871X("LPS_CTRL_SPECIAL_PACKET \n"); ++ pwrpriv->DelayLPSLastTimeStamp = rtw_get_current_time(); ++#ifdef CONFIG_BT_COEXIST ++ BT_SpecialPacketNotify(padapter); ++ if (BT_1Ant(padapter) == _FALSE) ++#endif ++ { ++ LPS_Leave(padapter); ++ } ++ break; ++ case LPS_CTRL_LEAVE: ++ //DBG_871X("LPS_CTRL_LEAVE \n"); ++#ifdef CONFIG_BT_COEXIST ++ BT_LpsLeave(padapter); ++ if (BT_1Ant(padapter) == _FALSE) ++#endif ++ { ++ LPS_Leave(padapter); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++_func_exit_; ++} ++ ++u8 rtw_lps_ctrl_wk_cmd(_adapter*padapter, u8 lps_ctrl_type, u8 enqueue) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ //struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); ++ u8 res = _SUCCESS; ++ ++_func_enter_; ++ ++ //if(!pwrctrlpriv->bLeisurePs) ++ // return res; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (padapter->iface_type != IFACE_PORT0) ++ return res; ++#endif ++ ++ if(enqueue) ++ { ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if(pdrvextra_cmd_parm==NULL){ ++ rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID; ++ pdrvextra_cmd_parm->type_size = lps_ctrl_type; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ } ++ else ++ { ++ lps_ctrl_wk_hdl(padapter, lps_ctrl_type); ++ } ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++ ++} ++ ++#endif ++ ++#if (RATE_ADAPTIVE_SUPPORT==1) ++void rpt_timer_setting_wk_hdl(_adapter *padapter, u16 minRptTime) ++{ ++ rtw_hal_set_hwreg(padapter, HW_VAR_RPT_TIMER_SETTING, (u8 *)(&minRptTime)); ++} ++ ++u8 rtw_rpt_timer_cfg_cmd(_adapter*padapter, u16 minRptTime) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ u8 res = _SUCCESS; ++ ++_func_enter_; ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if(pdrvextra_cmd_parm==NULL){ ++ rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = RTP_TIMER_CFG_WK_CID; ++ pdrvextra_cmd_parm->type_size = minRptTime; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++ ++_func_exit_; ++ ++ return res; ++ ++} ++ ++#endif ++ ++#ifdef CONFIG_ANTENNA_DIVERSITY ++void antenna_select_wk_hdl(_adapter *padapter, u8 antenna) ++{ ++ rtw_hal_set_hwreg(padapter, HW_VAR_ANTENNA_DIVERSITY_SELECT, (u8 *)(&antenna)); ++} ++ ++u8 rtw_antenna_select_cmd(_adapter*padapter, u8 antenna,u8 enqueue) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 bSupportAntDiv = _FALSE; ++ u8 res = _SUCCESS; ++ ++_func_enter_; ++ rtw_hal_get_def_var(padapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &(bSupportAntDiv)); ++ if(_FALSE == bSupportAntDiv ) return res; ++ ++ if(_TRUE == enqueue) ++ { ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if(pdrvextra_cmd_parm==NULL){ ++ rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = ANT_SELECT_WK_CID; ++ pdrvextra_cmd_parm->type_size = antenna; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ } ++ else{ ++ antenna_select_wk_hdl(padapter,antenna ); ++ } ++exit: ++ ++_func_exit_; ++ ++ return res; ++ ++} ++#endif ++ ++void power_saving_wk_hdl(_adapter *padapter, u8 *pbuf, int sz); ++void power_saving_wk_hdl(_adapter *padapter, u8 *pbuf, int sz) ++{ ++ rtw_ps_processor(padapter); ++} ++ ++//add for CONFIG_IEEE80211W, none 11w can use it ++void reset_securitypriv_hdl(_adapter *padapter) ++{ ++ rtw_reset_securitypriv(padapter); ++} ++ ++void free_assoc_resources_hdl(_adapter *padapter) ++{ ++ rtw_free_assoc_resources(padapter, 1); ++} ++ ++#ifdef CONFIG_P2P ++u8 p2p_protocol_wk_cmd(_adapter*padapter, int intCmdType ) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++_func_enter_; ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ return res; ++ } ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if(pdrvextra_cmd_parm==NULL){ ++ rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = P2P_PROTO_WK_CID; ++ pdrvextra_cmd_parm->type_size = intCmdType; // As the command tppe. ++ pdrvextra_cmd_parm->pbuf = NULL; // Must be NULL here ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++ ++} ++#endif //CONFIG_P2P ++ ++u8 rtw_ps_cmd(_adapter*padapter) ++{ ++ struct cmd_obj *ppscmd; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ u8 res = _SUCCESS; ++_func_enter_; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (padapter->adapter_type != PRIMARY_ADAPTER) ++ goto exit; ++#endif ++ ++ ppscmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ppscmd==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if(pdrvextra_cmd_parm==NULL){ ++ rtw_mfree((unsigned char *)ppscmd, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ppscmd); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++ ++} ++ ++#ifdef CONFIG_AP_MODE ++ ++static void rtw_chk_hi_queue_hdl(_adapter *padapter) ++{ ++ int cnt=0; ++ struct sta_info *psta_bmc; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ psta_bmc = rtw_get_bcmc_stainfo(padapter); ++ if(!psta_bmc) ++ return; ++ ++ if(psta_bmc->sleepq_len==0) ++ { ++ u8 val = 0; ++ ++ //while((rtw_read32(padapter, 0x414)&0x00ffff00)!=0) ++ //while((rtw_read32(padapter, 0x414)&0x0000ff00)!=0) ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val); ++ ++ while(_FALSE == val) ++ { ++ rtw_msleep_os(100); ++ ++ cnt++; ++ ++ if(cnt>10) ++ break; ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val); ++ } ++ ++ if(cnt<=10) ++ { ++ pstapriv->tim_bitmap &= ~BIT(0); ++ pstapriv->sta_dz_bitmap &= ~BIT(0); ++ ++ update_beacon(padapter, _TIM_IE_, NULL, _FALSE); ++ } ++ else //re check again ++ { ++ rtw_chk_hi_queue_cmd(padapter); ++ } ++ ++ } ++ ++} ++ ++u8 rtw_chk_hi_queue_cmd(_adapter*padapter) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if(pdrvextra_cmd_parm==NULL){ ++ rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID; ++ pdrvextra_cmd_parm->type_size = 0; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ return res; ++ ++} ++#endif ++ ++u8 rtw_c2h_wk_cmd(PADAPTER padapter, u8 *c2h_evt) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if (pdrvextra_cmd_parm == NULL) { ++ rtw_mfree((u8*)ph2c, sizeof(struct cmd_obj)); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = C2H_WK_CID; ++ pdrvextra_cmd_parm->type_size = c2h_evt?16:0; ++ pdrvextra_cmd_parm->pbuf = c2h_evt; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ return res; ++} ++ ++s32 c2h_evt_hdl(_adapter *adapter, struct c2h_evt_hdr *c2h_evt, c2h_id_filter filter) ++{ ++ s32 ret = _FAIL; ++ u8 buf[16]; ++ ++ if (!c2h_evt) { ++ /* No c2h event in cmd_obj, read c2h event before handling*/ ++ if (c2h_evt_read(adapter, buf) == _SUCCESS) { ++ c2h_evt = (struct c2h_evt_hdr *)buf; ++ ++ if (filter && filter(c2h_evt->id) == _FALSE) ++ goto exit; ++ ++ ret = rtw_hal_c2h_handler(adapter, c2h_evt); ++ } ++ } else { ++ ++ if (filter && filter(c2h_evt->id) == _FALSE) ++ goto exit; ++ ++ ret = rtw_hal_c2h_handler(adapter, c2h_evt); ++ } ++exit: ++ return ret; ++} ++ ++#ifdef CONFIG_C2H_WK ++static void c2h_wk_callback(_workitem *work) ++{ ++ struct evt_priv *evtpriv = container_of(work, struct evt_priv, c2h_wk); ++ _adapter *adapter = container_of(evtpriv, _adapter, evtpriv); ++ struct c2h_evt_hdr *c2h_evt; ++ c2h_id_filter ccx_id_filter = rtw_hal_c2h_id_filter_ccx(adapter); ++ ++ evtpriv->c2h_wk_alive = _TRUE; ++ ++ while (!rtw_cbuf_empty(evtpriv->c2h_queue)) { ++ if ((c2h_evt = (struct c2h_evt_hdr *)rtw_cbuf_pop(evtpriv->c2h_queue)) != NULL) { ++ /* This C2H event is read, clear it */ ++ c2h_evt_clear(adapter); ++ } else if ((c2h_evt = (struct c2h_evt_hdr *)rtw_malloc(16)) != NULL) { ++ /* This C2H event is not read, read & clear now */ ++ if (c2h_evt_read(adapter, (u8*)c2h_evt) != _SUCCESS) ++ continue; ++ } ++ ++ /* Special pointer to trigger c2h_evt_clear only */ ++ if ((void *)c2h_evt == (void *)evtpriv) ++ continue; ++ ++ if (!c2h_evt_exist(c2h_evt)) { ++ rtw_mfree((u8*)c2h_evt, 16); ++ continue; ++ } ++ ++ if (ccx_id_filter(c2h_evt->id) == _TRUE) { ++ /* Handle CCX report here */ ++ rtw_hal_c2h_handler(adapter, c2h_evt); ++ rtw_mfree((u8*)c2h_evt, 16); ++ } else { ++ /* Enqueue into cmd_thread for others */ ++ rtw_c2h_wk_cmd(adapter, (u8 *)c2h_evt); ++ } ++ } ++ ++ evtpriv->c2h_wk_alive = _FALSE; ++} ++#endif ++ ++#ifdef CONFIG_DETECT_C2H_BY_POLLING ++void event_polling_hdl(_adapter *padapter, u8 *pbuf, int sz) ++{ ++ c2h_id_filter ccx_id_filter = rtw_hal_c2h_id_filter_ccx(padapter); ++ u8 check_c2hcmd, check_ccx; ++ ++ //check_c2hcmd = rtw_read8(padapter, REG_C2HEVT_CLEAR); ++ //check_ccx= rtw_read8(padapter, REG_C2HEVT_MSG_NORMAL); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_C2HEVT_CLEAR, (u8 *)(&check_c2hcmd)); ++ rtw_hal_get_hwreg(padapter, HW_VAR_C2HEVT_MSG_NORMAL, (u8 *)(&check_ccx)); ++ ++ if (check_c2hcmd != 0) ++ { ++ struct c2h_evt_hdr *c2h_evt; ++ ++ if (check_c2hcmd != 0xFF) ++ { ++ c2h_evt_clear(padapter); ++ } ++ else if (ccx_id_filter(check_ccx & 0x0F) == _FALSE) ++ { ++ if ((c2h_evt = (struct c2h_evt_hdr *)rtw_zmalloc(16)) != NULL) { ++ if (c2h_evt_read(padapter, (u8 *)c2h_evt) == _SUCCESS) { ++ rtw_hal_c2h_handler(padapter, c2h_evt); ++ } ++ rtw_mfree((u8*)c2h_evt, 16); ++ } else { ++ /* Error handling for malloc fail */ ++ if (rtw_cbuf_push(padapter->evtpriv.c2h_queue, (void*)NULL) != _SUCCESS) ++ DBG_871X("%s rtw_cbuf_push fail\n", __func__); ++ _set_workitem(&padapter->evtpriv.c2h_wk); ++ } ++ } ++ else ++ { ++ if (padapter->xmitpriv.ack_tx == _FALSE) ++ { ++ c2h_evt_clear(padapter); ++ } ++ } ++ } ++} ++#endif ++ ++u8 rtw_drvextra_cmd_hdl(_adapter *padapter, unsigned char *pbuf) ++{ ++ struct drvextra_cmd_parm *pdrvextra_cmd; ++ ++ if(!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ pdrvextra_cmd = (struct drvextra_cmd_parm*)pbuf; ++ ++ switch(pdrvextra_cmd->ec_id) ++ { ++ case DYNAMIC_CHK_WK_CID: ++ dynamic_chk_wk_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size); ++ break; ++ case POWER_SAVING_CTRL_WK_CID: ++ power_saving_wk_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size); ++ break; ++#ifdef CONFIG_LPS ++ case LPS_CTRL_WK_CID: ++ lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type_size); ++ break; ++#endif ++#if (RATE_ADAPTIVE_SUPPORT==1) ++ case RTP_TIMER_CFG_WK_CID: ++ rpt_timer_setting_wk_hdl(padapter, pdrvextra_cmd->type_size); ++ break; ++#endif ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ case ANT_SELECT_WK_CID: ++ antenna_select_wk_hdl(padapter, pdrvextra_cmd->type_size); ++ break; ++#endif ++#ifdef CONFIG_P2P_PS ++ case P2P_PS_WK_CID: ++ p2p_ps_wk_hdl(padapter, pdrvextra_cmd->type_size); ++ break; ++#endif // CONFIG_P2P_PS ++#ifdef CONFIG_P2P ++ case P2P_PROTO_WK_CID: ++ // Commented by Albert 2011/07/01 ++ // I used the type_size as the type command ++ p2p_protocol_wk_hdl( padapter, pdrvextra_cmd->type_size ); ++ break; ++#endif ++#ifdef CONFIG_AP_MODE ++ case CHECK_HIQ_WK_CID: ++ rtw_chk_hi_queue_hdl(padapter); ++ break; ++#endif //CONFIG_AP_MODE ++#ifdef CONFIG_INTEL_WIDI ++ case INTEl_WIDI_WK_CID: ++ intel_widi_wk_hdl(padapter, pdrvextra_cmd->type_size, pdrvextra_cmd->pbuf); ++ break; ++#endif //CONFIG_INTEL_WIDI ++ //add for CONFIG_IEEE80211W, none 11w can use it ++ case RESET_SECURITYPRIV: ++ reset_securitypriv_hdl(padapter); ++ break; ++ case FREE_ASSOC_RESOURCES: ++ free_assoc_resources_hdl(padapter); ++ break; ++ case C2H_WK_CID: ++ c2h_evt_hdl(padapter, (struct c2h_evt_hdr *)pdrvextra_cmd->pbuf, NULL); ++ break; ++#ifdef CONFIG_DETECT_C2H_BY_POLLING ++ case EVENT_POLLING_CID: ++ event_polling_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size); ++ break; ++#endif ++ default: ++ break; ++ } ++ ++ if (pdrvextra_cmd->pbuf && pdrvextra_cmd->type_size>0) ++ { ++ rtw_mfree(pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size); ++ } ++ ++ return H2C_SUCCESS; ++} ++ ++void rtw_survey_cmd_callback(_adapter* padapter , struct cmd_obj *pcmd) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++_func_enter_; ++ ++ if(pcmd->res == H2C_DROPPED) ++ { ++ //TODO: cancel timer and do timeout handler directly... ++ //need to make timeout handlerOS independent ++ _set_timer(&pmlmepriv->scan_to_timer, 1); ++ } ++ else if (pcmd->res != H2C_SUCCESS) { ++ _set_timer(&pmlmepriv->scan_to_timer, 1); ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("\n ********Error: MgntActrtw_set_802_11_bssid_LIST_SCAN Fail ************\n\n.")); ++ } ++ ++ // free cmd ++ rtw_free_cmd_obj(pcmd); ++ ++_func_exit_; ++} ++void rtw_disassoc_cmd_callback(_adapter* padapter, struct cmd_obj *pcmd) ++{ ++ _irqL irqL; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++_func_enter_; ++ ++ if (pcmd->res != H2C_SUCCESS) ++ { ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ set_fwstate(pmlmepriv, _FW_LINKED); ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("\n ***Error: disconnect_cmd_callback Fail ***\n.")); ++ ++ goto exit; ++ } ++#ifdef CONFIG_BR_EXT ++ else //clear bridge database ++ nat25_db_cleanup(padapter); ++#endif //CONFIG_BR_EXT ++ ++ // free cmd ++ rtw_free_cmd_obj(pcmd); ++ ++exit: ++ ++_func_exit_; ++} ++ ++ ++void rtw_joinbss_cmd_callback(_adapter* padapter, struct cmd_obj *pcmd) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++_func_enter_; ++ ++ if(pcmd->res == H2C_DROPPED) ++ { ++ //TODO: cancel timer and do timeout handler directly... ++ //need to make timeout handlerOS independent ++ _set_timer(&pmlmepriv->assoc_timer, 1); ++ } ++ else if(pcmd->res != H2C_SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("********Error:rtw_select_and_join_from_scanned_queue Wait Sema Fail ************\n")); ++ _set_timer(&pmlmepriv->assoc_timer, 1); ++ } ++ ++ rtw_free_cmd_obj(pcmd); ++ ++_func_exit_; ++} ++ ++void rtw_createbss_cmd_callback(_adapter *padapter, struct cmd_obj *pcmd) ++{ ++ _irqL irqL; ++ u8 timer_cancelled; ++ struct sta_info *psta = NULL; ++ struct wlan_network *pwlan = NULL; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)pcmd->parmbuf; ++ struct wlan_network *tgt_network = &(pmlmepriv->cur_network); ++ ++_func_enter_; ++ ++ if((pcmd->res != H2C_SUCCESS)) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("\n ********Error: rtw_createbss_cmd_callback Fail ************\n\n.")); ++ _set_timer(&pmlmepriv->assoc_timer, 1 ); ++ } ++ ++ _cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled); ++ ++#ifdef CONFIG_FW_MLMLE ++ //endian_convert ++ pnetwork->Length = le32_to_cpu(pnetwork->Length); ++ pnetwork->Ssid.SsidLength = le32_to_cpu(pnetwork->Ssid.SsidLength); ++ pnetwork->Privacy =le32_to_cpu(pnetwork->Privacy); ++ pnetwork->Rssi = le32_to_cpu(pnetwork->Rssi); ++ pnetwork->NetworkTypeInUse =le32_to_cpu(pnetwork->NetworkTypeInUse); ++ pnetwork->Configuration.ATIMWindow = le32_to_cpu(pnetwork->Configuration.ATIMWindow); ++ //pnetwork->Configuration.BeaconPeriod = le32_to_cpu(pnetwork->Configuration.BeaconPeriod); ++ pnetwork->Configuration.DSConfig =le32_to_cpu(pnetwork->Configuration.DSConfig); ++ pnetwork->Configuration.FHConfig.DwellTime=le32_to_cpu(pnetwork->Configuration.FHConfig.DwellTime); ++ pnetwork->Configuration.FHConfig.HopPattern=le32_to_cpu(pnetwork->Configuration.FHConfig.HopPattern); ++ pnetwork->Configuration.FHConfig.HopSet=le32_to_cpu(pnetwork->Configuration.FHConfig.HopSet); ++ pnetwork->Configuration.FHConfig.Length=le32_to_cpu(pnetwork->Configuration.FHConfig.Length); ++ pnetwork->Configuration.Length = le32_to_cpu(pnetwork->Configuration.Length); ++ pnetwork->InfrastructureMode = le32_to_cpu(pnetwork->InfrastructureMode); ++ pnetwork->IELength = le32_to_cpu(pnetwork->IELength); ++#endif ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) ) ++ { ++ psta = rtw_get_stainfo(&padapter->stapriv, pnetwork->MacAddress); ++ if(!psta) ++ { ++ psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress); ++ if (psta == NULL) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("\nCan't alloc sta_info when createbss_cmd_callback\n")); ++ goto createbss_cmd_fail ; ++ } ++ } ++ ++ rtw_indicate_connect( padapter); ++ } ++ else ++ { ++ _irqL irqL; ++ ++ pwlan = _rtw_alloc_network(pmlmepriv); ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ if ( pwlan == NULL) ++ { ++ pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue); ++ if( pwlan == NULL) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("\n Error: can't get pwlan in rtw_joinbss_event_callback \n")); ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ goto createbss_cmd_fail; ++ } ++ pwlan->last_scanned = rtw_get_current_time(); ++ } ++ else ++ { ++ rtw_list_insert_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue); ++ } ++ ++ pnetwork->Length = get_WLAN_BSSID_EX_sz(pnetwork); ++ _rtw_memcpy(&(pwlan->network), pnetwork, pnetwork->Length); ++ //pwlan->fixed = _TRUE; ++ ++ //rtw_list_insert_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue); ++ ++ // copy pdev_network information to pmlmepriv->cur_network ++ _rtw_memcpy(&tgt_network->network, pnetwork, (get_WLAN_BSSID_EX_sz(pnetwork))); ++ ++ // reset DSConfig ++ //tgt_network->network.Configuration.DSConfig = (u32)rtw_ch2freq(pnetwork->Configuration.DSConfig); ++ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ ++#if 0 ++ if((pmlmepriv->fw_state) & WIFI_AP_STATE) ++ { ++ psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress); ++ ++ if (psta == NULL) { // for AP Mode & Adhoc Master Mode ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("\nCan't alloc sta_info when createbss_cmd_callback\n")); ++ goto createbss_cmd_fail ; ++ } ++ ++ rtw_indicate_connect( padapter); ++ } ++ else { ++ ++ //rtw_indicate_disconnect(dev); ++ } ++#endif ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ // we will set _FW_LINKED when there is one more sat to join us (rtw_stassoc_event_callback) ++ ++ } ++ ++createbss_cmd_fail: ++ ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ rtw_free_cmd_obj(pcmd); ++ ++_func_exit_; ++ ++} ++ ++ ++ ++void rtw_setstaKey_cmdrsp_callback(_adapter* padapter , struct cmd_obj *pcmd) ++{ ++ ++ struct sta_priv * pstapriv = &padapter->stapriv; ++ struct set_stakey_rsp* psetstakey_rsp = (struct set_stakey_rsp*) (pcmd->rsp); ++ struct sta_info* psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr); ++ ++_func_enter_; ++ ++ if(psta==NULL) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("\nERROR: rtw_setstaKey_cmdrsp_callback => can't get sta_info \n\n")); ++ goto exit; ++ } ++ ++ //psta->aid = psta->mac_id = psetstakey_rsp->keyid; //CAM_ID(CAM_ENTRY) ++ ++exit: ++ ++ rtw_free_cmd_obj(pcmd); ++ ++_func_exit_; ++ ++} ++void rtw_setassocsta_cmdrsp_callback(_adapter* padapter, struct cmd_obj *pcmd) ++{ ++ _irqL irqL; ++ struct sta_priv * pstapriv = &padapter->stapriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct set_assocsta_parm* passocsta_parm = (struct set_assocsta_parm*)(pcmd->parmbuf); ++ struct set_assocsta_rsp* passocsta_rsp = (struct set_assocsta_rsp*) (pcmd->rsp); ++ struct sta_info* psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr); ++ ++_func_enter_; ++ ++ if(psta==NULL) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("\nERROR: setassocsta_cmdrsp_callbac => can't get sta_info \n\n")); ++ goto exit; ++ } ++ ++ psta->aid = psta->mac_id = passocsta_rsp->cam_id; ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) && (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE)) ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ ++ set_fwstate(pmlmepriv, _FW_LINKED); ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++exit: ++ rtw_free_cmd_obj(pcmd); ++ ++_func_exit_; ++} ++ ++void rtw_getrttbl_cmd_cmdrsp_callback(_adapter* padapter, struct cmd_obj *pcmd); ++void rtw_getrttbl_cmd_cmdrsp_callback(_adapter* padapter, struct cmd_obj *pcmd) ++{ ++_func_enter_; ++ ++ rtw_free_cmd_obj(pcmd); ++#ifdef CONFIG_MP_INCLUDED ++ if (padapter->registrypriv.mp_mode == 1) ++ padapter->mppriv.workparam.bcompleted=_TRUE; ++#endif ++ ++_func_exit_; ++ ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_debug.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_debug.c +new file mode 100644 +index 00000000..d2fc13c0 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_debug.c +@@ -0,0 +1,1370 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_DEBUG_C_ ++ ++ ++#include ++ ++#ifdef CONFIG_DEBUG_RTL871X ++ ++ u32 GlobalDebugLevel = _drv_err_; ++ ++ u64 GlobalDebugComponents = \ ++ _module_rtl871x_xmit_c_ | ++ _module_xmit_osdep_c_ | ++ _module_rtl871x_recv_c_ | ++ _module_recv_osdep_c_ | ++ _module_rtl871x_mlme_c_ | ++ _module_mlme_osdep_c_ | ++ _module_rtl871x_sta_mgt_c_ | ++ _module_rtl871x_cmd_c_ | ++ _module_cmd_osdep_c_ | ++ _module_rtl871x_io_c_ | ++ _module_io_osdep_c_ | ++ _module_os_intfs_c_| ++ _module_rtl871x_security_c_| ++ _module_rtl871x_eeprom_c_| ++ _module_hal_init_c_| ++ _module_hci_hal_init_c_| ++ _module_rtl871x_ioctl_c_| ++ _module_rtl871x_ioctl_set_c_| ++ _module_rtl871x_ioctl_query_c_| ++ _module_rtl871x_pwrctrl_c_| ++ _module_hci_intfs_c_| ++ _module_hci_ops_c_| ++ _module_hci_ops_os_c_| ++ _module_rtl871x_ioctl_os_c| ++ _module_rtl8712_cmd_c_| ++ _module_hal_xmit_c_| ++ _module_rtl8712_recv_c_ | ++ _module_mp_ | ++ _module_efuse_; ++ ++#endif ++ ++#ifdef CONFIG_PROC_DEBUG ++#include ++ ++int proc_get_drv_version(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "%s\n", DRIVERVERSION); ++ ++ *eof = 1; ++ return len; ++} ++ ++#ifdef DBG_MEM_ALLOC ++int proc_get_mstat(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ int len = 0; ++ ++ len += _rtw_mstat_dump(page+len, count-len); ++ *eof = 1; ++ ++ return len; ++} ++#endif /* DBG_MEM_ALLOC */ ++ ++int proc_get_write_reg(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ *eof = 1; ++ return 0; ++} ++ ++int proc_set_write_reg(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ u32 addr, val, len; ++ ++ if (count < 3) ++ { ++ DBG_871X("argument size is less than 3\n"); ++ return -EFAULT; ++ } ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%x %x %x", &addr, &val, &len); ++ ++ if (num != 3) { ++ DBG_871X("invalid write_reg parameter!\n"); ++ return count; ++ } ++ ++ switch(len) ++ { ++ case 1: ++ rtw_write8(padapter, addr, (u8)val); ++ break; ++ case 2: ++ rtw_write16(padapter, addr, (u16)val); ++ break; ++ case 4: ++ rtw_write32(padapter, addr, val); ++ break; ++ default: ++ DBG_871X("error write length=%d", len); ++ break; ++ } ++ ++ } ++ ++ return count; ++ ++} ++ ++static u32 proc_get_read_addr=0xeeeeeeee; ++static u32 proc_get_read_len=0x4; ++ ++int proc_get_read_reg(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ int len = 0; ++ ++ if(proc_get_read_addr==0xeeeeeeee) ++ { ++ *eof = 1; ++ return len; ++ } ++ ++ switch(proc_get_read_len) ++ { ++ case 1: ++ len += snprintf(page + len, count - len, "rtw_read8(0x%x)=0x%x\n", proc_get_read_addr, rtw_read8(padapter, proc_get_read_addr)); ++ break; ++ case 2: ++ len += snprintf(page + len, count - len, "rtw_read16(0x%x)=0x%x\n", proc_get_read_addr, rtw_read16(padapter, proc_get_read_addr)); ++ break; ++ case 4: ++ len += snprintf(page + len, count - len, "rtw_read32(0x%x)=0x%x\n", proc_get_read_addr, rtw_read32(padapter, proc_get_read_addr)); ++ break; ++ default: ++ len += snprintf(page + len, count - len, "error read length=%d\n", proc_get_read_len); ++ break; ++ } ++ ++ *eof = 1; ++ return len; ++ ++} ++ ++int proc_set_read_reg(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char tmp[16]; ++ u32 addr, len; ++ ++ if (count < 2) ++ { ++ DBG_871X("argument size is less than 2\n"); ++ return -EFAULT; ++ } ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%x %x", &addr, &len); ++ ++ if (num != 2) { ++ DBG_871X("invalid read_reg parameter!\n"); ++ return count; ++ } ++ ++ proc_get_read_addr = addr; ++ ++ proc_get_read_len = len; ++ } ++ ++ return count; ++ ++} ++ ++int proc_get_fwstate(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "fwstate=0x%x\n", get_fwstate(pmlmepriv)); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_sec_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "auth_alg=0x%x, enc_alg=0x%x, auth_type=0x%x, enc_type=0x%x\n", ++ psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm, ++ psecuritypriv->ndisauthtype, psecuritypriv->ndisencryptstatus); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_mlmext_state(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "pmlmeinfo->state=0x%x\n", pmlmeinfo->state); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_qos_option(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "qos_option=%d\n", pmlmepriv->qospriv.qos_option); ++ ++ *eof = 1; ++ return len; ++ ++} ++ ++int proc_get_ht_option(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ int len = 0; ++#ifdef CONFIG_80211N_HT ++ len += snprintf(page + len, count - len, "ht_option=%d\n", pmlmepriv->htpriv.ht_option); ++#endif //CONFIG_80211N_HT ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_rf_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "cur_ch=%d, cur_bw=%d, cur_ch_offet=%d\n", ++ pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); ++ ++ ++ *eof = 1; ++ return len; ++ ++} ++ ++int proc_get_ap_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct sta_info *psta; ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct wlan_network *cur_network = &(pmlmepriv->cur_network); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ int len = 0; ++ ++ psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress); ++ if(psta) ++ { ++ int i; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ ++ len += snprintf(page + len, count - len, "SSID=%s\n", cur_network->network.Ssid.Ssid); ++ len += snprintf(page + len, count - len, "sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr)); ++ len += snprintf(page + len, count - len, "cur_channel=%d, cur_bwmode=%d, cur_ch_offset=%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); ++ len += snprintf(page + len, count - len, "rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self); ++ len += snprintf(page + len, count - len, "state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); ++#ifdef CONFIG_80211N_HT ++ len += snprintf(page + len, count - len, "qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); ++ len += snprintf(page + len, count - len, "bwmode=%d, ch_offset=%d, sgi=%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi); ++ len += snprintf(page + len, count - len, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable); ++ len += snprintf(page + len, count - len, "agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); ++#endif //CONFIG_80211N_HT ++ ++ for(i=0;i<16;i++) ++ { ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ if(preorder_ctrl->enable) ++ { ++ len += snprintf(page + len, count - len, "tid=%d, indicate_seq=%d\n", i, preorder_ctrl->indicate_seq); ++ } ++ } ++ ++ } ++ else ++ { ++ len += snprintf(page + len, count - len, "can't get sta's macaddr, cur_network's macaddr:" MAC_FMT "\n", MAC_ARG(cur_network->network.MacAddress)); ++ } ++ ++ *eof = 1; ++ return len; ++ ++} ++ ++int proc_get_adapter_state(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "bSurpriseRemoved=%d, bDriverStopped=%d\n", ++ padapter->bSurpriseRemoved, padapter->bDriverStopped); ++ ++ *eof = 1; ++ return len; ++ ++} ++ ++int proc_get_trx_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ int i; ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ struct hw_xmit *phwxmit; ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "free_xmitbuf_cnt=%d, free_xmitframe_cnt=%d" ++ ", free_ext_xmitbuf_cnt=%d, free_xframe_ext_cnt=%d" ++ ", free_recvframe_cnt=%d\n", ++ pxmitpriv->free_xmitbuf_cnt, pxmitpriv->free_xmitframe_cnt, ++ pxmitpriv->free_xmit_extbuf_cnt, pxmitpriv->free_xframe_ext_cnt, ++ precvpriv->free_recvframe_cnt); ++ ++ for(i = 0; i < 4; i++) ++ { ++ phwxmit = pxmitpriv->hwxmits + i; ++ len += snprintf(page + len, count - len, "%d, hwq.accnt=%d\n", i, phwxmit->accnt); ++ } ++ ++#ifdef CONFIG_USB_HCI ++ len += snprintf(page + len, count - len, "rx_urb_pending_cn=%d\n", precvpriv->rx_pending_cnt); ++#endif ++ ++ *eof = 1; ++ return len; ++ ++} ++ ++int proc_get_mac_reg_dump1(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i,j=1; ++ ++ len += snprintf(page + len, count - len, "\n======= MAC REG =======\n"); ++ ++ for(i=0x0;i<0x300;i+=4) ++ { ++ if(j%4==1) len += snprintf(page + len, count - len,"0x%02x",i); ++ len += snprintf(page + len, count - len," 0x%08x ",rtw_read32(padapter,i)); ++ if((j++)%4 == 0) len += snprintf(page + len, count - len,"\n"); ++ } ++ ++ *eof = 1; ++ return len; ++ ++} ++ ++int proc_get_mac_reg_dump2(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i,j=1; ++ ++ len += snprintf(page + len, count - len, "\n======= MAC REG =======\n"); ++ memset(page, 0, count); ++ for(i=0x300;i<0x600;i+=4) ++ { ++ if(j%4==1) len += snprintf(page + len, count - len,"0x%02x",i); ++ len += snprintf(page + len, count - len," 0x%08x ",rtw_read32(padapter,i)); ++ if((j++)%4 == 0) len += snprintf(page + len, count - len,"\n"); ++ } ++ ++ *eof = 1; ++ return len; ++ ++} ++ ++int proc_get_mac_reg_dump3(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i,j=1; ++ ++ len += snprintf(page + len, count - len, "\n======= MAC REG =======\n"); ++ ++ for(i=0x600;i<0x800;i+=4) ++ { ++ if(j%4==1) len += snprintf(page + len, count - len,"0x%02x",i); ++ len += snprintf(page + len, count - len," 0x%08x ",rtw_read32(padapter,i)); ++ if((j++)%4 == 0) len += snprintf(page + len, count - len,"\n"); ++ } ++ ++ *eof = 1; ++ return len; ++ ++} ++ ++int proc_get_bb_reg_dump1(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i,j=1; ++ ++ len += snprintf(page + len, count - len, "\n======= BB REG =======\n"); ++ for(i=0x800;i<0xB00;i+=4) ++ { ++ if(j%4==1) len += snprintf(page + len, count - len,"0x%02x",i); ++ len += snprintf(page + len, count - len," 0x%08x ",rtw_read32(padapter,i)); ++ if((j++)%4 == 0) len += snprintf(page + len, count - len,"\n"); ++ } ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_bb_reg_dump2(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i,j=1; ++ ++ len += snprintf(page + len, count - len, "\n======= BB REG =======\n"); ++ for(i=0xB00;i<0xE00;i+=4) ++ { ++ if(j%4==1) len += snprintf(page + len, count - len,"0x%02x",i); ++ len += snprintf(page + len, count - len," 0x%08x ",rtw_read32(padapter,i)); ++ if((j++)%4 == 0) len += snprintf(page + len, count - len,"\n"); ++ } ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_bb_reg_dump3(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i,j=1; ++ ++ len += snprintf(page + len, count - len, "\n======= BB REG =======\n"); ++ for(i=0xE00;i<0x1000;i+=4) ++ { ++ if(j%4==1) len += snprintf(page + len, count - len,"0x%02x",i); ++ len += snprintf(page + len, count - len," 0x%08x ",rtw_read32(padapter,i)); ++ if((j++)%4 == 0) len += snprintf(page + len, count - len,"\n"); ++ } ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_rf_reg_dump1(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i,j=1,path; ++ u32 value; ++ ++ len += snprintf(page + len, count - len, "\n======= RF REG =======\n"); ++ path = 1; ++ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n",path); ++ for(i=0;i<0xC0;i++) ++ { ++ //value = PHY_QueryRFReg(padapter, (RF90_RADIO_PATH_E)path,i, bMaskDWord); ++ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff); ++ if(j%4==1) len += snprintf(page + len, count - len, "0x%02x ",i); ++ len += snprintf(page + len, count - len, " 0x%08x ",value); ++ if((j++)%4==0) len += snprintf(page + len, count - len, "\n"); ++ } ++ ++ *eof = 1; ++ return len; ++} ++ ++ ++int proc_get_rf_reg_dump2(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i,j=1,path; ++ u32 value; ++ ++ len += snprintf(page + len, count - len, "\n======= RF REG =======\n"); ++ path = 1; ++ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n",path); ++ for(i=0xC0;i<0x100;i++) ++ { ++ //value = PHY_QueryRFReg(padapter, (RF90_RADIO_PATH_E)path,i, bMaskDWord); ++ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff); ++ if(j%4==1) len += snprintf(page + len, count - len, "0x%02x ",i); ++ len += snprintf(page + len, count - len, " 0x%08x ",value); ++ if((j++)%4==0) len += snprintf(page + len, count - len, "\n"); ++ } ++ *eof = 1; ++ return len; ++} ++ ++ ++int proc_get_rf_reg_dump3(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i,j=1,path; ++ u32 value; ++ ++ len += snprintf(page + len, count - len, "\n======= RF REG =======\n"); ++ path = 2; ++ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n",path); ++ for(i=0;i<0xC0;i++) ++ { ++ //value = PHY_QueryRFReg(padapter, (RF90_RADIO_PATH_E)path,i, bMaskDWord); ++ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff); ++ if(j%4==1) len += snprintf(page + len, count - len, "0x%02x ",i); ++ len += snprintf(page + len, count - len, " 0x%08x ",value); ++ if((j++)%4==0) len += snprintf(page + len, count - len, "\n"); ++ } ++ ++ *eof = 1; ++ return len; ++} ++ ++ ++int proc_get_rf_reg_dump4(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i,j=1,path; ++ u32 value; ++ ++ len += snprintf(page + len, count - len, "\n======= RF REG =======\n"); ++ path = 2; ++ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n",path); ++ for(i=0xC0;i<0x100;i++) ++ { ++ //value = PHY_QueryRFReg(padapter, (RF90_RADIO_PATH_E)path,i, bMaskDWord); ++ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff); ++ if(j%4==1) len += snprintf(page + len, count - len, "0x%02x ",i); ++ len += snprintf(page + len, count - len, " 0x%08x ",value); ++ if((j++)%4==0) len += snprintf(page + len, count - len, "\n"); ++ } ++ *eof = 1; ++ return len; ++} ++ ++ ++ ++int proc_get_rx_signal(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, ++ "rssi:%d\n" ++ "rxpwdb:%d\n" ++ "signal_strength:%u\n" ++ "signal_qual:%u\n" ++ "noise:%u\n", ++ padapter->recvpriv.rssi, ++ padapter->recvpriv.rxpwdb, ++ padapter->recvpriv.signal_strength, ++ padapter->recvpriv.signal_qual, ++ padapter->recvpriv.noise ++ ); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_set_rx_signal(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ u32 is_signal_dbg, signal_strength; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%u %u", &is_signal_dbg, &signal_strength); ++ ++ is_signal_dbg = is_signal_dbg==0?0:1; ++ ++ if(is_signal_dbg && num!=2) ++ return count; ++ ++ signal_strength = signal_strength>100?100:signal_strength; ++ signal_strength = signal_strength<0?0:signal_strength; ++ ++ padapter->recvpriv.is_signal_dbg = is_signal_dbg; ++ padapter->recvpriv.signal_strength_dbg=signal_strength; ++ ++ if(is_signal_dbg) ++ DBG_871X("set %s %u\n", "DBG_SIGNAL_STRENGTH", signal_strength); ++ else ++ DBG_871X("set %s\n", "HW_SIGNAL_STRENGTH"); ++ ++ } ++ ++ return count; ++ ++} ++#ifdef CONFIG_80211N_HT ++ ++int proc_get_ht_enable(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ int len = 0; ++ ++ if(pregpriv) ++ len += snprintf(page + len, count - len, ++ "%d\n", ++ pregpriv->ht_enable ++ ); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_set_ht_enable(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ char tmp[32]; ++ u32 mode; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%d ", &mode); ++ ++ if( pregpriv && mode >= 0 && mode < 2 ) ++ { ++ pregpriv->ht_enable= mode; ++ printk("ht_enable=%d\n", pregpriv->ht_enable); ++ } ++ } ++ ++ return count; ++ ++} ++ ++int proc_get_cbw40_enable(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ int len = 0; ++ ++ if(pregpriv) ++ len += snprintf(page + len, count - len, ++ "%d\n", ++ pregpriv->cbw40_enable ++ ); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_set_cbw40_enable(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ char tmp[32]; ++ u32 mode; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%d ", &mode); ++ ++ if( pregpriv && mode >= 0 && mode < 2 ) ++ { ++ ++ pregpriv->cbw40_enable= mode; ++ printk("cbw40_enable=%d\n", mode); ++ ++ } ++ } ++ ++ return count; ++ ++} ++ ++int proc_get_ampdu_enable(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ int len = 0; ++ ++ if(pregpriv) ++ len += snprintf(page + len, count - len, ++ "%d\n", ++ pregpriv->ampdu_enable ++ ); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_set_ampdu_enable(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ char tmp[32]; ++ u32 mode; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%d ", &mode); ++ ++ if( pregpriv && mode >= 0 && mode < 3 ) ++ { ++ pregpriv->ampdu_enable= mode; ++ printk("ampdu_enable=%d\n", mode); ++ } ++ ++ } ++ ++ return count; ++ ++} ++#endif //CONFIG_80211N_HT ++ ++int proc_get_two_path_rssi(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ int len = 0; ++ ++ if(padapter) ++ len += snprintf(page + len, count - len, ++ "%d %d\n", ++ padapter->recvpriv.RxRssi[0], ++ padapter->recvpriv.RxRssi[1] ++ ); ++ ++ *eof = 1; ++ return len; ++} ++#ifdef CONFIG_80211N_HT ++int proc_get_rx_stbc(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ int len = 0; ++ ++ if(pregpriv) ++ len += snprintf(page + len, count - len, ++ "%d\n", ++ pregpriv->rx_stbc ++ ); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_set_rx_stbc(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ char tmp[32]; ++ u32 mode; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%d ", &mode); ++ ++ if( pregpriv && (mode == 0 || mode == 1|| mode == 2|| mode == 3)) ++ { ++ pregpriv->rx_stbc= mode; ++ printk("rx_stbc=%d\n", mode); ++ } ++ } ++ ++ return count; ++ ++} ++#endif //CONFIG_80211N_HT ++ ++ ++int proc_get_rssi_disp(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ *eof = 1; ++ return 0; ++} ++ ++int proc_set_rssi_disp(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ u32 enable=0; ++ ++ if (count < 1) ++ { ++ DBG_8192C("argument size is less than 1\n"); ++ return -EFAULT; ++ } ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%x", &enable); ++ ++ if (num != 1) { ++ DBG_8192C("invalid set_rssi_disp parameter!\n"); ++ return count; ++ } ++ ++ if(enable) ++ { ++ DBG_8192C("Turn On Rx RSSI Display Function\n"); ++ padapter->bRxRSSIDisplay = enable ; ++ } ++ else ++ { ++ DBG_8192C("Turn Off Rx RSSI Display Function\n"); ++ padapter->bRxRSSIDisplay = 0 ; ++ } ++ ++ } ++ ++ return count; ++ ++} ++ ++ ++#ifdef CONFIG_AP_MODE ++ ++int proc_get_all_sta_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ _irqL irqL; ++ struct sta_info *psta; ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ int i, j; ++ _list *plist, *phead; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ int len = 0; ++ ++ ++ len += snprintf(page + len, count - len, "sta_dz_bitmap=0x%x, tim_bitmap=0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap); ++ ++ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ ++ for(i=0; i< NUM_STA; i++) ++ { ++ phead = &(pstapriv->sta_hash[i]); ++ plist = get_next(phead); ++ ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); ++ ++ plist = get_next(plist); ++ ++ //if(extra_arg == psta->aid) ++ { ++ len += snprintf(page + len, count - len, "sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr)); ++ len += snprintf(page + len, count - len, "rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self); ++ len += snprintf(page + len, count - len, "state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); ++#ifdef CONFIG_80211N_HT ++ len += snprintf(page + len, count - len, "qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); ++ len += snprintf(page + len, count - len, "bwmode=%d, ch_offset=%d, sgi=%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi); ++ len += snprintf(page + len, count - len, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable); ++ len += snprintf(page + len, count - len, "agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); ++#endif //CONFIG_80211N_HT ++ len += snprintf(page + len, count - len, "sleepq_len=%d\n", psta->sleepq_len); ++ len += snprintf(page + len, count - len, "capability=0x%x\n", psta->capability); ++ len += snprintf(page + len, count - len, "flags=0x%x\n", psta->flags); ++ len += snprintf(page + len, count - len, "wpa_psk=0x%x\n", psta->wpa_psk); ++ len += snprintf(page + len, count - len, "wpa2_group_cipher=0x%x\n", psta->wpa2_group_cipher); ++ len += snprintf(page + len, count - len, "wpa2_pairwise_cipher=0x%x\n", psta->wpa2_pairwise_cipher); ++ len += snprintf(page + len, count - len, "qos_info=0x%x\n", psta->qos_info); ++ len += snprintf(page + len, count - len, "dot118021XPrivacy=0x%x\n", psta->dot118021XPrivacy); ++ ++ for(j=0;j<16;j++) ++ { ++ preorder_ctrl = &psta->recvreorder_ctrl[j]; ++ if(preorder_ctrl->enable) ++ { ++ len += snprintf(page + len, count - len, "tid=%d, indicate_seq=%d\n", j, preorder_ctrl->indicate_seq); ++ } ++ } ++ ++ } ++ ++ } ++ ++ } ++ ++ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ ++ *eof = 1; ++ return len; ++ ++} ++ ++#endif ++ ++#ifdef DBG_MEMORY_LEAK ++#include ++extern atomic_t _malloc_cnt;; ++extern atomic_t _malloc_size;; ++ ++int proc_get_malloc_cnt(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "_malloc_cnt=%d\n", atomic_read(&_malloc_cnt)); ++ len += snprintf(page + len, count - len, "_malloc_size=%d\n", atomic_read(&_malloc_size)); ++ ++ *eof = 1; ++ return len; ++} ++#endif /* DBG_MEMORY_LEAK */ ++ ++#ifdef CONFIG_FIND_BEST_CHANNEL ++int proc_get_best_channel(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ int len = 0; ++ u32 i, best_channel_24G = 1, best_channel_5G = 36, index_24G = 0, index_5G = 0; ++ ++ for (i=0; pmlmeext->channel_set[i].ChannelNum !=0; i++) { ++ if ( pmlmeext->channel_set[i].ChannelNum == 1) ++ index_24G = i; ++ if ( pmlmeext->channel_set[i].ChannelNum == 36) ++ index_5G = i; ++ } ++ ++ for (i=0; pmlmeext->channel_set[i].ChannelNum !=0; i++) { ++ // 2.4G ++ if ( pmlmeext->channel_set[i].ChannelNum == 6 ) { ++ if ( pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_24G].rx_count ) { ++ index_24G = i; ++ best_channel_24G = pmlmeext->channel_set[i].ChannelNum; ++ } ++ } ++ ++ // 5G ++ if ( pmlmeext->channel_set[i].ChannelNum >= 36 ++ && pmlmeext->channel_set[i].ChannelNum < 140 ) { ++ // Find primary channel ++ if ( (( pmlmeext->channel_set[i].ChannelNum - 36) % 8 == 0) ++ && (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count) ) { ++ index_5G = i; ++ best_channel_5G = pmlmeext->channel_set[i].ChannelNum; ++ } ++ } ++ ++ if ( pmlmeext->channel_set[i].ChannelNum >= 149 ++ && pmlmeext->channel_set[i].ChannelNum < 165) { ++ // find primary channel ++ if ( (( pmlmeext->channel_set[i].ChannelNum - 149) % 8 == 0) ++ && (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count) ) { ++ index_5G = i; ++ best_channel_5G = pmlmeext->channel_set[i].ChannelNum; ++ } ++ } ++#if 1 // debug ++ len += snprintf(page + len, count - len, "The rx cnt of channel %3d = %d\n", ++ pmlmeext->channel_set[i].ChannelNum, pmlmeext->channel_set[i].rx_count); ++#endif ++ } ++ ++ len += snprintf(page + len, count - len, "best_channel_5G = %d\n", best_channel_5G); ++ len += snprintf(page + len, count - len, "best_channel_24G = %d\n", best_channel_24G); ++ ++ *eof = 1; ++ return len; ++ ++} ++ ++int proc_set_best_channel(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ char tmp[32]; ++ ++ if(count < 1) ++ return -EFAULT; ++ ++ if(buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) ++ { ++ int i; ++ for(i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) ++ { ++ pmlmeext->channel_set[i].rx_count = 0; ++ } ++ ++ DBG_871X("set %s\n", "Clean Best Channel Count"); ++ } ++ ++ return count; ++} ++#endif /* CONFIG_FIND_BEST_CHANNEL */ ++#ifdef CONFIG_BT_COEXIST ++#define _bt_dbg_off_ 0 ++#define _bt_dbg_on_ 1 ++ ++extern u32 BTCoexDbgLevel; ++int proc_get_btcoex_dbg(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ int len = 0; ++ ++ if(pregpriv) ++ len += snprintf(page + len, count - len, ++ "%d\n", ++ BTCoexDbgLevel ++ ); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_set_btcoex_dbg(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ char tmp[32]; ++ u32 mode; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%d ", &mode); ++ ++ if( pregpriv && (mode == 0 || mode == 1|| mode == 2|| mode == 3)) ++ { ++ BTCoexDbgLevel= mode; ++ printk("btcoex_dbg=%d\n", BTCoexDbgLevel); ++ } ++ } ++ ++ return count; ++ ++} ++#endif /* CONFIG_BT_COEXIST */ ++ ++#if defined(DBG_CONFIG_ERROR_DETECT) ++#include ++int proc_get_sreset(char *page, char **start, off_t offset, int count, int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ int len = 0; ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_set_sreset(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ s32 trigger_point; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%d", &trigger_point); ++ ++ if (trigger_point == SRESET_TGP_NULL) ++ rtw_hal_sreset_reset(padapter); ++ else ++ sreset_set_trigger_point(padapter, trigger_point); ++ } ++ ++ return count; ++ ++} ++#endif /* DBG_CONFIG_ERROR_DETECT */ ++ ++int proc_get_odm_dbg_comp(char *page, char **start, off_t offset, int count, int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ ++ len += _rtw_odm_dbg_comp_msg(adapter, page, count); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_set_odm_dbg_comp(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ ++ u64 dbg_comp; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%llx", &dbg_comp); ++ ++ if (num != 1) ++ return count; ++ ++ rtw_odm_dbg_comp_set(adapter, dbg_comp); ++ } ++ ++ return count; ++} ++ ++int proc_get_odm_dbg_level(char *page, char **start, off_t offset, int count, int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ ++ len += _rtw_odm_dbg_level_msg(adapter, page, count); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_set_odm_dbg_level(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ ++ u32 dbg_level; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%u", &dbg_level); ++ ++ if (num != 1) ++ return count; ++ ++ rtw_odm_dbg_level_set(adapter, dbg_level); ++ } ++ ++ return count; ++} ++ ++int proc_get_odm_adaptivity(char *page, char **start, off_t offset, int count, int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ ++ len += _rtw_odm_adaptivity_parm_msg(padapter, page, count); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_set_odm_adaptivity(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ u32 TH_L2H_ini; ++ s8 TH_EDCCA_HL_diff; ++ u32 IGI_Base; ++ int ForceEDCCA; ++ u8 AdapEn_RSSI; ++ u8 IGI_LowerBound; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%x %hhd %x %d %hhu %hhu", ++ &TH_L2H_ini, &TH_EDCCA_HL_diff, &IGI_Base, &ForceEDCCA, &AdapEn_RSSI, &IGI_LowerBound); ++ ++ if (num != 6) ++ return count; ++ ++ rtw_odm_adaptivity_parm_set(padapter, (s8)TH_L2H_ini, TH_EDCCA_HL_diff, (s8)IGI_Base, (bool)ForceEDCCA, AdapEn_RSSI, IGI_LowerBound); ++ } ++ ++ return count; ++} ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_eeprom.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_eeprom.c +new file mode 100644 +index 00000000..fd07d64d +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_eeprom.c +@@ -0,0 +1,423 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_EEPROM_C_ ++ ++#include ++#include ++#include ++ ++void up_clk(_adapter* padapter, u16 *x) ++{ ++_func_enter_; ++ *x = *x | _EESK; ++ rtw_write8(padapter, EE_9346CR, (u8)*x); ++ rtw_udelay_os(CLOCK_RATE); ++ ++_func_exit_; ++ ++} ++ ++void down_clk(_adapter * padapter, u16 *x ) ++{ ++_func_enter_; ++ *x = *x & ~_EESK; ++ rtw_write8(padapter, EE_9346CR, (u8)*x); ++ rtw_udelay_os(CLOCK_RATE); ++_func_exit_; ++} ++ ++void shift_out_bits(_adapter * padapter, u16 data, u16 count) ++{ ++ u16 x,mask; ++_func_enter_; ++ ++ if(padapter->bSurpriseRemoved==_TRUE){ ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==_TRUE")); ++ goto out; ++ } ++ mask = 0x01 << (count - 1); ++ x = rtw_read8(padapter, EE_9346CR); ++ ++ x &= ~(_EEDO | _EEDI); ++ ++ do ++ { ++ x &= ~_EEDI; ++ if(data & mask) ++ x |= _EEDI; ++ if(padapter->bSurpriseRemoved==_TRUE){ ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==_TRUE")); ++ goto out; ++ } ++ rtw_write8(padapter, EE_9346CR, (u8)x); ++ rtw_udelay_os(CLOCK_RATE); ++ up_clk(padapter, &x); ++ down_clk(padapter, &x); ++ mask = mask >> 1; ++ } while(mask); ++ if(padapter->bSurpriseRemoved==_TRUE){ ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==_TRUE")); ++ goto out; ++ } ++ x &= ~_EEDI; ++ rtw_write8(padapter, EE_9346CR, (u8)x); ++out: ++_func_exit_; ++} ++ ++u16 shift_in_bits (_adapter * padapter) ++{ ++ u16 x,d=0,i; ++_func_enter_; ++ if(padapter->bSurpriseRemoved==_TRUE){ ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==_TRUE")); ++ goto out; ++ } ++ x = rtw_read8(padapter, EE_9346CR); ++ ++ x &= ~( _EEDO | _EEDI); ++ d = 0; ++ ++ for(i=0; i<16; i++) ++ { ++ d = d << 1; ++ up_clk(padapter, &x); ++ if(padapter->bSurpriseRemoved==_TRUE){ ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==_TRUE")); ++ goto out; ++ } ++ x = rtw_read8(padapter, EE_9346CR); ++ ++ x &= ~(_EEDI); ++ if(x & _EEDO) ++ d |= 1; ++ ++ down_clk(padapter, &x); ++ } ++out: ++_func_exit_; ++ ++ return d; ++} ++ ++void standby(_adapter * padapter ) ++{ ++ u8 x; ++_func_enter_; ++ x = rtw_read8(padapter, EE_9346CR); ++ ++ x &= ~(_EECS | _EESK); ++ rtw_write8(padapter, EE_9346CR,x); ++ ++ rtw_udelay_os(CLOCK_RATE); ++ x |= _EECS; ++ rtw_write8(padapter, EE_9346CR, x); ++ rtw_udelay_os(CLOCK_RATE); ++_func_exit_; ++} ++ ++u16 wait_eeprom_cmd_done(_adapter* padapter) ++{ ++ u8 x; ++ u16 i,res=_FALSE; ++_func_enter_; ++ standby(padapter ); ++ for (i=0; i<200; i++) ++ { ++ x = rtw_read8(padapter, EE_9346CR); ++ if (x & _EEDO){ ++ res=_TRUE; ++ goto exit; ++ } ++ rtw_udelay_os(CLOCK_RATE); ++ } ++exit: ++_func_exit_; ++ return res; ++} ++ ++void eeprom_clean(_adapter * padapter) ++{ ++ u16 x; ++_func_enter_; ++ if(padapter->bSurpriseRemoved==_TRUE){ ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==_TRUE")); ++ goto out; ++ } ++ x = rtw_read8(padapter, EE_9346CR); ++ if(padapter->bSurpriseRemoved==_TRUE){ ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==_TRUE")); ++ goto out; ++ } ++ x &= ~(_EECS | _EEDI); ++ rtw_write8(padapter, EE_9346CR, (u8)x); ++ if(padapter->bSurpriseRemoved==_TRUE){ ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==_TRUE")); ++ goto out; ++ } ++ up_clk(padapter, &x); ++ if(padapter->bSurpriseRemoved==_TRUE){ ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==_TRUE")); ++ goto out; ++ } ++ down_clk(padapter, &x); ++out: ++_func_exit_; ++} ++ ++void eeprom_write16(_adapter * padapter, u16 reg, u16 data) ++{ ++ u8 x; ++#ifdef CONFIG_RTL8712 ++ u8 tmp8_ori,tmp8_new,tmp8_clk_ori,tmp8_clk_new; ++ tmp8_ori=rtw_read8(padapter, 0x102502f1); ++ tmp8_new=tmp8_ori & 0xf7; ++ if(tmp8_ori != tmp8_new){ ++ rtw_write8(padapter, 0x102502f1, tmp8_new); ++ RT_TRACE(_module_rtl871x_mp_ioctl_c_,_drv_err_,("====write 0x102502f1=====\n")); ++ } ++ tmp8_clk_ori=rtw_read8(padapter,0x10250003); ++ tmp8_clk_new=tmp8_clk_ori|0x20; ++ if(tmp8_clk_new!=tmp8_clk_ori){ ++ RT_TRACE(_module_rtl871x_mp_ioctl_c_,_drv_err_,("====write 0x10250003=====\n")); ++ rtw_write8(padapter, 0x10250003, tmp8_clk_new); ++ } ++#endif ++_func_enter_; ++ ++ x = rtw_read8(padapter, EE_9346CR); ++ ++ x &= ~(_EEDI | _EEDO | _EESK | _EEM0); ++ x |= _EEM1 | _EECS; ++ rtw_write8(padapter, EE_9346CR, x); ++ ++ shift_out_bits(padapter, EEPROM_EWEN_OPCODE, 5); ++ ++ if(padapter->EepromAddressSize==8) //CF+ and SDIO ++ shift_out_bits(padapter, 0, 6); ++ else //USB ++ shift_out_bits(padapter, 0, 4); ++ ++ standby( padapter); ++ ++// Commented out by rcnjko, 2004.0 ++// // Erase this particular word. Write the erase opcode and register ++// // number in that order. The opcode is 3bits in length; reg is 6 bits long. ++// shift_out_bits(Adapter, EEPROM_ERASE_OPCODE, 3); ++// shift_out_bits(Adapter, reg, Adapter->EepromAddressSize); ++// ++// if (wait_eeprom_cmd_done(Adapter ) == FALSE) ++// { ++// return; ++// } ++ ++ ++ standby(padapter ); ++ ++ // write the new word to the EEPROM ++ ++ // send the write opcode the EEPORM ++ shift_out_bits(padapter, EEPROM_WRITE_OPCODE, 3); ++ ++ // select which word in the EEPROM that we are writing to. ++ shift_out_bits(padapter, reg, padapter->EepromAddressSize); ++ ++ // write the data to the selected EEPROM word. ++ shift_out_bits(padapter, data, 16); ++ ++ if (wait_eeprom_cmd_done(padapter ) == _FALSE) ++ { ++ ++ goto exit; ++ } ++ ++ standby(padapter ); ++ ++ shift_out_bits(padapter, EEPROM_EWDS_OPCODE, 5); ++ shift_out_bits(padapter, reg, 4); ++ ++ eeprom_clean(padapter ); ++exit: ++#ifdef CONFIG_RTL8712 ++ if(tmp8_clk_new!=tmp8_clk_ori) ++ rtw_write8(padapter, 0x10250003, tmp8_clk_ori); ++ if(tmp8_new!=tmp8_ori) ++ rtw_write8(padapter, 0x102502f1, tmp8_ori); ++ ++#endif ++_func_exit_; ++ return; ++} ++ ++u16 eeprom_read16(_adapter * padapter, u16 reg) //ReadEEprom ++{ ++ ++ u16 x; ++ u16 data=0; ++#ifdef CONFIG_RTL8712 ++ u8 tmp8_ori,tmp8_new,tmp8_clk_ori,tmp8_clk_new; ++ tmp8_ori= rtw_read8(padapter, 0x102502f1); ++ tmp8_new = tmp8_ori & 0xf7; ++ if(tmp8_ori != tmp8_new){ ++ rtw_write8(padapter, 0x102502f1, tmp8_new); ++ RT_TRACE(_module_rtl871x_mp_ioctl_c_,_drv_err_,("====write 0x102502f1=====\n")); ++ } ++ tmp8_clk_ori=rtw_read8(padapter,0x10250003); ++ tmp8_clk_new=tmp8_clk_ori|0x20; ++ if(tmp8_clk_new!=tmp8_clk_ori){ ++ RT_TRACE(_module_rtl871x_mp_ioctl_c_,_drv_err_,("====write 0x10250003=====\n")); ++ rtw_write8(padapter, 0x10250003, tmp8_clk_new); ++ } ++#endif ++_func_enter_; ++ ++ if(padapter->bSurpriseRemoved==_TRUE){ ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==_TRUE")); ++ goto out; ++ } ++ // select EEPROM, reset bits, set _EECS ++ x = rtw_read8(padapter, EE_9346CR); ++ ++ if(padapter->bSurpriseRemoved==_TRUE){ ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==_TRUE")); ++ goto out; ++ } ++ ++ x &= ~(_EEDI | _EEDO | _EESK | _EEM0); ++ x |= _EEM1 | _EECS; ++ rtw_write8(padapter, EE_9346CR, (unsigned char)x); ++ ++ // write the read opcode and register number in that order ++ // The opcode is 3bits in length, reg is 6 bits long ++ shift_out_bits(padapter, EEPROM_READ_OPCODE, 3); ++ shift_out_bits(padapter, reg, padapter->EepromAddressSize); ++ ++ // Now read the data (16 bits) in from the selected EEPROM word ++ data = shift_in_bits(padapter); ++ ++ eeprom_clean(padapter); ++out: ++#ifdef CONFIG_RTL8712 ++ if(tmp8_clk_new!=tmp8_clk_ori) ++ rtw_write8(padapter, 0x10250003, tmp8_clk_ori); ++ if(tmp8_new!=tmp8_ori) ++ rtw_write8(padapter, 0x102502f1, tmp8_ori); ++ ++#endif ++_func_exit_; ++ return data; ++ ++ ++} ++ ++ ++ ++ ++//From even offset ++void eeprom_read_sz(_adapter * padapter, u16 reg, u8* data, u32 sz) ++{ ++ ++ u16 x, data16; ++ u32 i; ++_func_enter_; ++ if(padapter->bSurpriseRemoved==_TRUE){ ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==_TRUE")); ++ goto out; ++ } ++ // select EEPROM, reset bits, set _EECS ++ x = rtw_read8(padapter, EE_9346CR); ++ ++ if(padapter->bSurpriseRemoved==_TRUE){ ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==_TRUE")); ++ goto out; ++ } ++ ++ x &= ~(_EEDI | _EEDO | _EESK | _EEM0); ++ x |= _EEM1 | _EECS; ++ rtw_write8(padapter, EE_9346CR, (unsigned char)x); ++ ++ // write the read opcode and register number in that order ++ // The opcode is 3bits in length, reg is 6 bits long ++ shift_out_bits(padapter, EEPROM_READ_OPCODE, 3); ++ shift_out_bits(padapter, reg, padapter->EepromAddressSize); ++ ++ ++ for(i=0; i>8; ++ } ++ ++ eeprom_clean(padapter); ++out: ++_func_exit_; ++ ++ ++ ++} ++ ++ ++//addr_off : address offset of the entry in eeprom (not the tuple number of eeprom (reg); that is addr_off !=reg) ++u8 eeprom_read(_adapter * padapter, u32 addr_off, u8 sz, u8* rbuf) ++{ ++ u8 quotient, remainder, addr_2align_odd; ++ u16 reg, stmp , i=0, idx = 0; ++_func_enter_; ++ reg = (u16)(addr_off >> 1); ++ addr_2align_odd = (u8)(addr_off & 0x1); ++ ++ if(addr_2align_odd) //read that start at high part: e.g 1,3,5,7,9,... ++ { ++ stmp = eeprom_read16(padapter, reg); ++ rbuf[idx++] = (u8) ((stmp>>8)&0xff); //return hogh-part of the short ++ reg++; sz--; ++ } ++ ++ quotient = sz >> 1; ++ remainder = sz & 0x1; ++ ++ for( i=0 ; i < quotient; i++) ++ { ++ stmp = eeprom_read16(padapter, reg+i); ++ rbuf[idx++] = (u8) (stmp&0xff); ++ rbuf[idx++] = (u8) ((stmp>>8)&0xff); ++ } ++ ++ reg = reg+i; ++ if(remainder){ //end of read at lower part of short : 0,2,4,6,... ++ stmp = eeprom_read16(padapter, reg); ++ rbuf[idx] = (u8)(stmp & 0xff); ++ } ++_func_exit_; ++ return _TRUE; ++} ++ ++ ++ ++VOID read_eeprom_content(_adapter * padapter) ++{ ++ ++_func_enter_; ++ ++ ++_func_exit_; ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_ieee80211.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_ieee80211.c +new file mode 100644 +index 00000000..af32123c +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_ieee80211.c +@@ -0,0 +1,2187 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _IEEE80211_C ++ ++#include ++#include ++#include ++#include ++#include ++ ++u8 RTW_WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 }; ++u16 RTW_WPA_VERSION = 1; ++u8 WPA_AUTH_KEY_MGMT_NONE[] = { 0x00, 0x50, 0xf2, 0 }; ++u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 }; ++u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 }; ++u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 }; ++u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 }; ++u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 }; ++u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 }; ++u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 }; ++u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 }; ++ ++u16 RSN_VERSION_BSD = 1; ++u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 }; ++u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 }; ++u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 }; ++u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 }; ++u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 }; ++u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 }; ++u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 }; ++u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 }; ++//----------------------------------------------------------- ++// for adhoc-master to generate ie and provide supported-rate to fw ++//----------------------------------------------------------- ++ ++static u8 WIFI_CCKRATES[] = ++{(IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK), ++ (IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK), ++ (IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK), ++ (IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK)}; ++ ++static u8 WIFI_OFDMRATES[] = ++{(IEEE80211_OFDM_RATE_6MB), ++ (IEEE80211_OFDM_RATE_9MB), ++ (IEEE80211_OFDM_RATE_12MB), ++ (IEEE80211_OFDM_RATE_18MB), ++ (IEEE80211_OFDM_RATE_24MB), ++ IEEE80211_OFDM_RATE_36MB, ++ IEEE80211_OFDM_RATE_48MB, ++ IEEE80211_OFDM_RATE_54MB}; ++ ++ ++int rtw_get_bit_value_from_ieee_value(u8 val) ++{ ++ unsigned char dot11_rate_table[]={2,4,11,22,12,18,24,36,48,72,96,108,0}; // last element must be zero!! ++ ++ int i=0; ++ while(dot11_rate_table[i] != 0) { ++ if (dot11_rate_table[i] == val) ++ return BIT(i); ++ i++; ++ } ++ return 0; ++} ++ ++uint rtw_is_cckrates_included(u8 *rate) ++{ ++ u32 i = 0; ++ ++ while(rate[i]!=0) ++ { ++ if ( (((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || ++ (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22) ) ++ return _TRUE; ++ i++; ++ } ++ ++ return _FALSE; ++} ++ ++uint rtw_is_cckratesonly_included(u8 *rate) ++{ ++ u32 i = 0; ++ ++ ++ while(rate[i]!=0) ++ { ++ if ( (((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && ++ (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22) ) ++ ++ return _FALSE; ++ ++ i++; ++ } ++ ++ return _TRUE; ++ ++} ++ ++int rtw_check_network_type(unsigned char *rate, int ratelen, int channel) ++{ ++ if (channel > 14) ++ { ++ if ((rtw_is_cckrates_included(rate)) == _TRUE) ++ return WIRELESS_INVALID; ++ else ++ return WIRELESS_11A; ++ } ++ else // could be pure B, pure G, or B/G ++ { ++ if ((rtw_is_cckratesonly_included(rate)) == _TRUE) ++ return WIRELESS_11B; ++ else if((rtw_is_cckrates_included(rate)) == _TRUE) ++ return WIRELESS_11BG; ++ else ++ return WIRELESS_11G; ++ } ++ ++} ++ ++u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len, unsigned char *source, ++ unsigned int *frlen) ++{ ++ _rtw_memcpy((void *)pbuf, (void *)source, len); ++ *frlen = *frlen + len; ++ return (pbuf + len); ++} ++ ++// rtw_set_ie will update frame length ++u8 *rtw_set_ie ++( ++ u8 *pbuf, ++ sint index, ++ uint len, ++ u8 *source, ++ uint *frlen //frame length ++) ++{ ++_func_enter_; ++ *pbuf = (u8)index; ++ ++ *(pbuf + 1) = (u8)len; ++ ++ if (len > 0) ++ _rtw_memcpy((void *)(pbuf + 2), (void *)source, len); ++ ++ *frlen = *frlen + (len + 2); ++ ++ return (pbuf + len + 2); ++_func_exit_; ++} ++ ++inline u8 *rtw_set_ie_ch_switch(u8 *buf, u32 *buf_len, u8 ch_switch_mode, ++ u8 new_ch, u8 ch_switch_cnt) ++{ ++ u8 ie_data[3]; ++ ++ ie_data[0] = ch_switch_mode; ++ ie_data[1] = new_ch; ++ ie_data[2] = ch_switch_cnt; ++ return rtw_set_ie(buf, WLAN_EID_CHANNEL_SWITCH, 3, ie_data, buf_len); ++} ++ ++inline u8 secondary_ch_offset_to_hal_ch_offset(u8 ch_offset) ++{ ++ if (ch_offset == SCN) ++ return HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ else if(ch_offset == SCA) ++ return HAL_PRIME_CHNL_OFFSET_UPPER; ++ else if(ch_offset == SCB) ++ return HAL_PRIME_CHNL_OFFSET_LOWER; ++ ++ return HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++} ++ ++inline u8 hal_ch_offset_to_secondary_ch_offset(u8 ch_offset) ++{ ++ if (ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) ++ return SCN; ++ else if(ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) ++ return SCB; ++ else if(ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) ++ return SCA; ++ ++ return SCN; ++} ++ ++inline u8 *rtw_set_ie_secondary_ch_offset(u8 *buf, u32 *buf_len, u8 secondary_ch_offset) ++{ ++ return rtw_set_ie(buf, WLAN_EID_SECONDARY_CHANNEL_OFFSET, 1, &secondary_ch_offset, buf_len); ++} ++ ++inline u8 *rtw_set_ie_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl, ++ u8 flags, u16 reason, u16 precedence) ++{ ++ u8 ie_data[6]; ++ ++ ie_data[0] = ttl; ++ ie_data[1] = flags; ++ RTW_PUT_LE16((u8*)&ie_data[2], reason); ++ RTW_PUT_LE16((u8*)&ie_data[4], precedence); ++ ++ return rtw_set_ie(buf, 0x118, 6, ie_data, buf_len); ++} ++ ++/*---------------------------------------------------------------------------- ++index: the information element id index, limit is the limit for search ++-----------------------------------------------------------------------------*/ ++u8 *rtw_get_ie(u8 *pbuf, sint index, sint *len, sint limit) ++{ ++ sint tmp,i; ++ u8 *p; ++_func_enter_; ++ if (limit < 1){ ++ _func_exit_; ++ return NULL; ++ } ++ ++ p = pbuf; ++ i = 0; ++ *len = 0; ++ while(1) ++ { ++ if (*p == index) ++ { ++ *len = *(p + 1); ++ return (p); ++ } ++ else ++ { ++ tmp = *(p + 1); ++ p += (tmp + 2); ++ i += (tmp + 2); ++ } ++ if (i >= limit) ++ break; ++ } ++_func_exit_; ++ return NULL; ++} ++ ++/** ++ * rtw_get_ie_ex - Search specific IE from a series of IEs ++ * @in_ie: Address of IEs to search ++ * @in_len: Length limit from in_ie ++ * @eid: Element ID to match ++ * @oui: OUI to match ++ * @oui_len: OUI length ++ * @ie: If not NULL and the specific IE is found, the IE will be copied to the buf starting from the specific IE ++ * @ielen: If not NULL and the specific IE is found, will set to the length of the entire IE ++ * ++ * Returns: The address of the specific IE found, or NULL ++ */ ++u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen) ++{ ++ uint cnt; ++ u8 *target_ie = NULL; ++ ++ ++ if(ielen) ++ *ielen = 0; ++ ++ if(!in_ie || in_len<=0) ++ return target_ie; ++ ++ cnt = 0; ++ ++ while(cnt 12) ++ break; ++ ++ i++; ++ } ++_func_exit_; ++ return i; ++} ++ ++int rtw_generate_ie(struct registry_priv *pregistrypriv) ++{ ++ u8 wireless_mode; ++ int sz = 0, rateLen; ++ WLAN_BSSID_EX* pdev_network = &pregistrypriv->dev_network; ++ u8* ie = pdev_network->IEs; ++ ++_func_enter_; ++ ++ //timestamp will be inserted by hardware ++ sz += 8; ++ ie += sz; ++ ++ //beacon interval : 2bytes ++ *(u16*)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod);//BCN_INTERVAL; ++ sz += 2; ++ ie += 2; ++ ++ //capability info ++ *(u16*)ie = 0; ++ ++ *(u16*)ie |= cpu_to_le16(cap_IBSS); ++ ++ if(pregistrypriv->preamble == PREAMBLE_SHORT) ++ *(u16*)ie |= cpu_to_le16(cap_ShortPremble); ++ ++ if (pdev_network->Privacy) ++ *(u16*)ie |= cpu_to_le16(cap_Privacy); ++ ++ sz += 2; ++ ie += 2; ++ ++ //SSID ++ ie = rtw_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength, pdev_network->Ssid.Ssid, &sz); ++ ++ //supported rates ++ if(pregistrypriv->wireless_mode == WIRELESS_11ABGN) ++ { ++ if(pdev_network->Configuration.DSConfig > 14) ++ wireless_mode = WIRELESS_11A_5N; ++ else ++ wireless_mode = WIRELESS_11BG_24N; ++ } ++ else ++ { ++ wireless_mode = pregistrypriv->wireless_mode; ++ } ++ ++ rtw_set_supported_rate(pdev_network->SupportedRates, wireless_mode) ; ++ ++ rateLen = rtw_get_rateset_len(pdev_network->SupportedRates); ++ ++ if (rateLen > 8) ++ { ++ ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, 8, pdev_network->SupportedRates, &sz); ++ //ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); ++ } ++ else ++ { ++ ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, rateLen, pdev_network->SupportedRates, &sz); ++ } ++ ++ //DS parameter set ++ ie = rtw_set_ie(ie, _DSSET_IE_, 1, (u8 *)&(pdev_network->Configuration.DSConfig), &sz); ++ ++ ++ //IBSS Parameter Set ++ ++ ie = rtw_set_ie(ie, _IBSS_PARA_IE_, 2, (u8 *)&(pdev_network->Configuration.ATIMWindow), &sz); ++ ++ if (rateLen > 8) ++ { ++ ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); ++ } ++ ++#ifdef CONFIG_80211N_HT ++ //HT Cap. ++ if(((pregistrypriv->wireless_mode&WIRELESS_11_5N)||(pregistrypriv->wireless_mode&WIRELESS_11_24N)) ++ && (pregistrypriv->ht_enable==_TRUE)) ++ { ++ //todo: ++ } ++#endif //CONFIG_80211N_HT ++ ++ //pdev_network->IELength = sz; //update IELength ++ ++_func_exit_; ++ ++ //return _SUCCESS; ++ ++ return sz; ++ ++} ++ ++unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit) ++{ ++ int len; ++ u16 val16; ++ unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01}; ++ u8 *pbuf = pie; ++ int limit_new = limit; ++ ++ while(1) ++ { ++ pbuf = rtw_get_ie(pbuf, _WPA_IE_ID_, &len, limit_new); ++ ++ if (pbuf) { ++ ++ //check if oui matches... ++ if (_rtw_memcmp((pbuf + 2), wpa_oui_type, sizeof (wpa_oui_type)) == _FALSE) { ++ ++ goto check_next_ie; ++ } ++ ++ //check version... ++ _rtw_memcpy((u8 *)&val16, (pbuf + 6), sizeof(val16)); ++ ++ val16 = le16_to_cpu(val16); ++ if (val16 != 0x0001) ++ goto check_next_ie; ++ ++ *wpa_ie_len = *(pbuf + 1); ++ ++ return pbuf; ++ ++ } ++ else { ++ ++ *wpa_ie_len = 0; ++ return NULL; ++ } ++ ++check_next_ie: ++ ++ limit_new = limit - (pbuf - pie) - 2 - len; ++ ++ if (limit_new <= 0) ++ break; ++ ++ pbuf += (2 + len); ++ ++ } ++ ++ *wpa_ie_len = 0; ++ ++ return NULL; ++ ++} ++ ++unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit) ++{ ++ ++ return rtw_get_ie(pie, _WPA2_IE_ID_,rsn_ie_len, limit); ++ ++} ++ ++int rtw_get_wpa_cipher_suite(u8 *s) ++{ ++ if (_rtw_memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN) == _TRUE) ++ return WPA_CIPHER_NONE; ++ if (_rtw_memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN) == _TRUE) ++ return WPA_CIPHER_WEP40; ++ if (_rtw_memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN) == _TRUE) ++ return WPA_CIPHER_TKIP; ++ if (_rtw_memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN) == _TRUE) ++ return WPA_CIPHER_CCMP; ++ if (_rtw_memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN) == _TRUE) ++ return WPA_CIPHER_WEP104; ++ ++ return 0; ++} ++ ++int rtw_get_wpa2_cipher_suite(u8 *s) ++{ ++ if (_rtw_memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN) == _TRUE) ++ return WPA_CIPHER_NONE; ++ if (_rtw_memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN) == _TRUE) ++ return WPA_CIPHER_WEP40; ++ if (_rtw_memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN) == _TRUE) ++ return WPA_CIPHER_TKIP; ++ if (_rtw_memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN) == _TRUE) ++ return WPA_CIPHER_CCMP; ++ if (_rtw_memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN) == _TRUE) ++ return WPA_CIPHER_WEP104; ++ ++ return 0; ++} ++ ++ ++int rtw_parse_wpa_ie(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x) ++{ ++ int i, ret=_SUCCESS; ++ int left, count; ++ u8 *pos; ++ u8 SUITE_1X[4] = {0x00, 0x50, 0xf2, 1}; ++ ++ if (wpa_ie_len <= 0) { ++ /* No WPA IE - fail silently */ ++ return _FAIL; ++ } ++ ++ ++ if ((*wpa_ie != _WPA_IE_ID_) || (*(wpa_ie+1) != (u8)(wpa_ie_len - 2)) || ++ (_rtw_memcmp(wpa_ie+2, RTW_WPA_OUI_TYPE, WPA_SELECTOR_LEN) != _TRUE) ) ++ { ++ return _FAIL; ++ } ++ ++ pos = wpa_ie; ++ ++ pos += 8; ++ left = wpa_ie_len - 8; ++ ++ ++ //group_cipher ++ if (left >= WPA_SELECTOR_LEN) { ++ ++ *group_cipher = rtw_get_wpa_cipher_suite(pos); ++ ++ pos += WPA_SELECTOR_LEN; ++ left -= WPA_SELECTOR_LEN; ++ ++ } ++ else if (left > 0) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie length mismatch, %u too much", __FUNCTION__, left)); ++ ++ return _FAIL; ++ } ++ ++ ++ //pairwise_cipher ++ if (left >= 2) ++ { ++ //count = le16_to_cpu(*(u16*)pos); ++ count = RTW_GET_LE16(pos); ++ pos += 2; ++ left -= 2; ++ ++ if (count == 0 || left < count * WPA_SELECTOR_LEN) { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie count botch (pairwise), " ++ "count %u left %u", __FUNCTION__, count, left)); ++ return _FAIL; ++ } ++ ++ for (i = 0; i < count; i++) ++ { ++ *pairwise_cipher |= rtw_get_wpa_cipher_suite(pos); ++ ++ pos += WPA_SELECTOR_LEN; ++ left -= WPA_SELECTOR_LEN; ++ } ++ ++ } ++ else if (left == 1) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie too short (for key mgmt)", __FUNCTION__)); ++ return _FAIL; ++ } ++ ++ if (is_8021x) { ++ if (left >= 6) { ++ pos += 2; ++ if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("%s : there has 802.1x auth\n", __FUNCTION__)); ++ *is_8021x = 1; ++ } ++ } ++ } ++ ++ return ret; ++ ++} ++ ++int rtw_parse_wpa2_ie(u8* rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x) ++{ ++ int i, ret=_SUCCESS; ++ int left, count; ++ u8 *pos; ++ u8 SUITE_1X[4] = {0x00,0x0f, 0xac, 0x01}; ++ ++ if (rsn_ie_len <= 0) { ++ /* No RSN IE - fail silently */ ++ return _FAIL; ++ } ++ ++ ++ if ((*rsn_ie!= _WPA2_IE_ID_) || (*(rsn_ie+1) != (u8)(rsn_ie_len - 2))) ++ { ++ return _FAIL; ++ } ++ ++ pos = rsn_ie; ++ pos += 4; ++ left = rsn_ie_len - 4; ++ ++ //group_cipher ++ if (left >= RSN_SELECTOR_LEN) { ++ ++ *group_cipher = rtw_get_wpa2_cipher_suite(pos); ++ ++ pos += RSN_SELECTOR_LEN; ++ left -= RSN_SELECTOR_LEN; ++ ++ } else if (left > 0) { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie length mismatch, %u too much", __FUNCTION__, left)); ++ return _FAIL; ++ } ++ ++ //pairwise_cipher ++ if (left >= 2) ++ { ++ //count = le16_to_cpu(*(u16*)pos); ++ count = RTW_GET_LE16(pos); ++ pos += 2; ++ left -= 2; ++ ++ if (count == 0 || left < count * RSN_SELECTOR_LEN) { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie count botch (pairwise), " ++ "count %u left %u", __FUNCTION__, count, left)); ++ return _FAIL; ++ } ++ ++ for (i = 0; i < count; i++) ++ { ++ *pairwise_cipher |= rtw_get_wpa2_cipher_suite(pos); ++ ++ pos += RSN_SELECTOR_LEN; ++ left -= RSN_SELECTOR_LEN; ++ } ++ ++ } ++ else if (left == 1) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie too short (for key mgmt)", __FUNCTION__)); ++ ++ return _FAIL; ++ } ++ ++ if (is_8021x) { ++ if (left >= 6) { ++ pos += 2; ++ if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("%s (): there has 802.1x auth\n", __FUNCTION__)); ++ *is_8021x = 1; ++ } ++ } ++ } ++ ++ return ret; ++ ++} ++ ++#ifdef CONFIG_WAPI_SUPPORT ++int rtw_get_wapi_ie(u8 *in_ie,uint in_len,u8 *wapi_ie,u16 *wapi_len) ++{ ++ u8 authmode, i; ++ uint cnt; ++ u8 wapi_oui1[4]={0x0,0x14,0x72,0x01}; ++ u8 wapi_oui2[4]={0x0,0x14,0x72,0x02}; ++ ++_func_enter_; ++ cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_); ++ while(cnt found WPS_IE.....\n"); ++ *wps_ielen = ie_ptr[1]+2; ++ match=_TRUE; ++ } ++ return match; ++} ++ ++u8 *rtw_get_wps_ie_from_scan_queue(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen, u8 frame_type) ++{ ++ u8* wps = NULL; ++ ++ DBG_871X( "[%s] frame_type = %d\n", __FUNCTION__, frame_type ); ++ switch( frame_type ) ++ { ++ case 1: ++ case 3: ++ { // Beacon or Probe Response ++ wps = rtw_get_wps_ie(in_ie + _PROBERSP_IE_OFFSET_, in_len - _PROBERSP_IE_OFFSET_, wps_ie, wps_ielen); ++ break; ++ } ++ case 2: ++ { // Probe Request ++ wps = rtw_get_wps_ie(in_ie + _PROBEREQ_IE_OFFSET_ , in_len - _PROBEREQ_IE_OFFSET_ , wps_ie, wps_ielen); ++ break; ++ } ++ } ++ return wps; ++} ++ ++/** ++ * rtw_get_wps_ie - Search WPS IE from a series of IEs ++ * @in_ie: Address of IEs to search ++ * @in_len: Length limit from in_ie ++ * @wps_ie: If not NULL and WPS IE is found, WPS IE will be copied to the buf starting from wps_ie ++ * @wps_ielen: If not NULL and WPS IE is found, will set to the length of the entire WPS IE ++ * ++ * Returns: The address of the WPS IE found, or NULL ++ */ ++u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen) ++{ ++ uint cnt; ++ u8 *wpsie_ptr=NULL; ++ u8 eid, wps_oui[4]={0x0,0x50,0xf2,0x04}; ++ ++ if(wps_ielen) ++ *wps_ielen = 0; ++ ++ if(!in_ie || in_len<=0) ++ return wpsie_ptr; ++ ++ cnt = 0; ++ ++ while(cntwpa_ie = pos; ++ elems->wpa_ie_len = elen; ++ break; ++ case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */ ++ if (elen < 5) { ++ DBG_871X("short WME " ++ "information element ignored " ++ "(len=%lu)\n", ++ (unsigned long) elen); ++ return -1; ++ } ++ switch (pos[4]) { ++ case WME_OUI_SUBTYPE_INFORMATION_ELEMENT: ++ case WME_OUI_SUBTYPE_PARAMETER_ELEMENT: ++ elems->wme = pos; ++ elems->wme_len = elen; ++ break; ++ case WME_OUI_SUBTYPE_TSPEC_ELEMENT: ++ elems->wme_tspec = pos; ++ elems->wme_tspec_len = elen; ++ break; ++ default: ++ DBG_871X("unknown WME " ++ "information element ignored " ++ "(subtype=%d len=%lu)\n", ++ pos[4], (unsigned long) elen); ++ return -1; ++ } ++ break; ++ case 4: ++ /* Wi-Fi Protected Setup (WPS) IE */ ++ elems->wps_ie = pos; ++ elems->wps_ie_len = elen; ++ break; ++ default: ++ DBG_871X("Unknown Microsoft " ++ "information element ignored " ++ "(type=%d len=%lu)\n", ++ pos[3], (unsigned long) elen); ++ return -1; ++ } ++ break; ++ ++ case OUI_BROADCOM: ++ switch (pos[3]) { ++ case VENDOR_HT_CAPAB_OUI_TYPE: ++ elems->vendor_ht_cap = pos; ++ elems->vendor_ht_cap_len = elen; ++ break; ++ default: ++ DBG_871X("Unknown Broadcom " ++ "information element ignored " ++ "(type=%d len=%lu)\n", ++ pos[3], (unsigned long) elen); ++ return -1; ++ } ++ break; ++ ++ default: ++ DBG_871X("unknown vendor specific information " ++ "element ignored (vendor OUI %02x:%02x:%02x " ++ "len=%lu)\n", ++ pos[0], pos[1], pos[2], (unsigned long) elen); ++ return -1; ++ } ++ ++ return 0; ++ ++} ++ ++/** ++ * ieee802_11_parse_elems - Parse information elements in management frames ++ * @start: Pointer to the start of IEs ++ * @len: Length of IE buffer in octets ++ * @elems: Data structure for parsed elements ++ * @show_errors: Whether to show parsing errors in debug log ++ * Returns: Parsing result ++ */ ++ParseRes rtw_ieee802_11_parse_elems(u8 *start, uint len, ++ struct rtw_ieee802_11_elems *elems, ++ int show_errors) ++{ ++ uint left = len; ++ u8 *pos = start; ++ int unknown = 0; ++ ++ _rtw_memset(elems, 0, sizeof(*elems)); ++ ++ while (left >= 2) { ++ u8 id, elen; ++ ++ id = *pos++; ++ elen = *pos++; ++ left -= 2; ++ ++ if (elen > left) { ++ if (show_errors) { ++ DBG_871X("IEEE 802.11 element " ++ "parse failed (id=%d elen=%d " ++ "left=%lu)\n", ++ id, elen, (unsigned long) left); ++ } ++ return ParseFailed; ++ } ++ ++ switch (id) { ++ case WLAN_EID_SSID: ++ elems->ssid = pos; ++ elems->ssid_len = elen; ++ break; ++ case WLAN_EID_SUPP_RATES: ++ elems->supp_rates = pos; ++ elems->supp_rates_len = elen; ++ break; ++ case WLAN_EID_FH_PARAMS: ++ elems->fh_params = pos; ++ elems->fh_params_len = elen; ++ break; ++ case WLAN_EID_DS_PARAMS: ++ elems->ds_params = pos; ++ elems->ds_params_len = elen; ++ break; ++ case WLAN_EID_CF_PARAMS: ++ elems->cf_params = pos; ++ elems->cf_params_len = elen; ++ break; ++ case WLAN_EID_TIM: ++ elems->tim = pos; ++ elems->tim_len = elen; ++ break; ++ case WLAN_EID_IBSS_PARAMS: ++ elems->ibss_params = pos; ++ elems->ibss_params_len = elen; ++ break; ++ case WLAN_EID_CHALLENGE: ++ elems->challenge = pos; ++ elems->challenge_len = elen; ++ break; ++ case WLAN_EID_ERP_INFO: ++ elems->erp_info = pos; ++ elems->erp_info_len = elen; ++ break; ++ case WLAN_EID_EXT_SUPP_RATES: ++ elems->ext_supp_rates = pos; ++ elems->ext_supp_rates_len = elen; ++ break; ++ case WLAN_EID_VENDOR_SPECIFIC: ++ if (rtw_ieee802_11_parse_vendor_specific(pos, elen, ++ elems, ++ show_errors)) ++ unknown++; ++ break; ++ case WLAN_EID_RSN: ++ elems->rsn_ie = pos; ++ elems->rsn_ie_len = elen; ++ break; ++ case WLAN_EID_PWR_CAPABILITY: ++ elems->power_cap = pos; ++ elems->power_cap_len = elen; ++ break; ++ case WLAN_EID_SUPPORTED_CHANNELS: ++ elems->supp_channels = pos; ++ elems->supp_channels_len = elen; ++ break; ++ case WLAN_EID_MOBILITY_DOMAIN: ++ elems->mdie = pos; ++ elems->mdie_len = elen; ++ break; ++ case WLAN_EID_FAST_BSS_TRANSITION: ++ elems->ftie = pos; ++ elems->ftie_len = elen; ++ break; ++ case WLAN_EID_TIMEOUT_INTERVAL: ++ elems->timeout_int = pos; ++ elems->timeout_int_len = elen; ++ break; ++ case WLAN_EID_HT_CAP: ++ elems->ht_capabilities = pos; ++ elems->ht_capabilities_len = elen; ++ break; ++ case WLAN_EID_HT_OPERATION: ++ elems->ht_operation = pos; ++ elems->ht_operation_len = elen; ++ break; ++ default: ++ unknown++; ++ if (!show_errors) ++ break; ++ DBG_871X("IEEE 802.11 element parse " ++ "ignored unknown element (id=%d elen=%d)\n", ++ id, elen); ++ break; ++ } ++ ++ left -= elen; ++ pos += elen; ++ } ++ ++ if (left) ++ return ParseFailed; ++ ++ return unknown ? ParseUnknown : ParseOK; ++ ++} ++ ++static u8 key_char2num(u8 ch); ++static u8 key_char2num(u8 ch) ++{ ++ if((ch>='0')&&(ch<='9')) ++ return ch - '0'; ++ else if ((ch>='a')&&(ch<='f')) ++ return ch - 'a' + 10; ++ else if ((ch>='A')&&(ch<='F')) ++ return ch - 'A' + 10; ++ else ++ return 0xff; ++} ++ ++u8 str_2char2num(u8 hch, u8 lch); ++u8 str_2char2num(u8 hch, u8 lch) ++{ ++ return ((key_char2num(hch) * 10 ) + key_char2num(lch)); ++} ++ ++u8 key_2char2num(u8 hch, u8 lch); ++u8 key_2char2num(u8 hch, u8 lch) ++{ ++ return ((key_char2num(hch) << 4) | key_char2num(lch)); ++} ++ ++u8 convert_ip_addr(u8 hch, u8 mch, u8 lch) ++{ ++ return ((key_char2num(hch) * 100) + (key_char2num(mch) * 10 ) + key_char2num(lch)); ++} ++ ++extern char* rtw_initmac; ++void rtw_macaddr_cfg(u8 *mac_addr) ++{ ++ u8 mac[ETH_ALEN]; ++ if(mac_addr == NULL) return; ++ ++ if ( rtw_initmac ) ++ { // Users specify the mac address ++ int jj,kk; ++ ++ for( jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3 ) ++ { ++ mac[jj] = key_2char2num(rtw_initmac[kk], rtw_initmac[kk+ 1]); ++ } ++ _rtw_memcpy(mac_addr, mac, ETH_ALEN); ++ } ++ else ++ { // Use the mac address stored in the Efuse ++ _rtw_memcpy(mac, mac_addr, ETH_ALEN); ++ } ++ ++ if (((mac[0]==0xff) &&(mac[1]==0xff) && (mac[2]==0xff) && ++ (mac[3]==0xff) && (mac[4]==0xff) &&(mac[5]==0xff)) || ++ ((mac[0]==0x0) && (mac[1]==0x0) && (mac[2]==0x0) && ++ (mac[3]==0x0) && (mac[4]==0x0) &&(mac[5]==0x0))) ++ { ++ mac[0] = 0x00; ++ mac[1] = 0xe0; ++ mac[2] = 0x4c; ++ mac[3] = 0x87; ++ mac[4] = 0x00; ++ mac[5] = 0x00; ++ // use default mac addresss ++ _rtw_memcpy(mac_addr, mac, ETH_ALEN); ++ DBG_871X("MAC Address from efuse error, assign default one !!!\n"); ++ } ++ ++ DBG_871X("rtw_macaddr_cfg MAC Address = "MAC_FMT"\n", MAC_ARG(mac_addr)); ++} ++ ++void dump_ies(u8 *buf, u32 buf_len) ++{ ++ u8* pos = (u8*)buf; ++ u8 id, len; ++ ++ while(pos-buf<=buf_len){ ++ id = *pos; ++ len = *(pos+1); ++ ++ DBG_871X("%s ID:%u, LEN:%u\n", __FUNCTION__, id, len); ++ dump_wps_ie(pos, len); ++ #ifdef CONFIG_P2P ++ dump_p2p_ie(pos, len); ++ #ifdef CONFIG_WFD ++ dump_wfd_ie(pos, len); ++ #endif ++ #endif ++ ++ pos+=(2+len); ++ } ++} ++ ++void dump_wps_ie(u8 *ie, u32 ie_len) ++{ ++ u8* pos = (u8*)ie; ++ u16 id; ++ u16 len; ++ ++ u8 *wps_ie; ++ uint wps_ielen; ++ ++ wps_ie = rtw_get_wps_ie(ie, ie_len, NULL, &wps_ielen); ++ if(wps_ie != ie || wps_ielen == 0) ++ return; ++ ++ pos+=6; ++ while(pos-ie < ie_len){ ++ id = RTW_GET_BE16(pos); ++ len = RTW_GET_BE16(pos + 2); ++ ++ DBG_871X("%s ID:0x%04x, LEN:%u\n", __FUNCTION__, id, len); ++ ++ pos+=(4+len); ++ } ++} ++ ++#ifdef CONFIG_P2P ++/** ++ * rtw_get_p2p_merged_len - Get merged ie length from muitiple p2p ies. ++ * @in_ie: Pointer of the first p2p ie ++ * @in_len: Total len of muiltiple p2p ies ++ * Returns: Length of merged p2p ie length ++ */ ++u32 rtw_get_p2p_merged_ies_len(u8 *in_ie, u32 in_len) ++{ ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ u8 OUI[4] = { 0x50, 0x6f, 0x9a, 0x09 }; ++ int i=0; ++ int j=0, len=0; ++ ++ while( i < in_len) ++ { ++ pIE = (PNDIS_802_11_VARIABLE_IEs)(in_ie+ i); ++ ++ if( pIE->ElementID == _VENDOR_SPECIFIC_IE_ && _rtw_memcmp(pIE->data, OUI, 4) ) ++ { ++ len += pIE->Length-4; // 4 is P2P OUI length, don't count it in this loop ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ ++ return len + 4; // Append P2P OUI length at last. ++} ++ ++/** ++ * rtw_p2p_merge_ies - Merge muitiple p2p ies into one ++ * @in_ie: Pointer of the first p2p ie ++ * @in_len: Total len of muiltiple p2p ies ++ * @merge_ie: Pointer of merged ie ++ * Returns: Length of merged p2p ie ++ */ ++int rtw_p2p_merge_ies(u8 *in_ie, u32 in_len, u8 *merge_ie) ++{ ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ u8 len = 0; ++ u8 OUI[4] = { 0x50, 0x6f, 0x9a, 0x09 }; ++ u8 ELOUI[6] = { 0xDD, 0x00, 0x50, 0x6f, 0x9a, 0x09 }; //EID;Len;OUI, Len would copy at the end of function ++ int i=0; ++ ++ if( merge_ie != NULL) ++ { ++ //Set first P2P OUI ++ _rtw_memcpy(merge_ie, ELOUI, 6); ++ merge_ie += 6; ++ ++ while( i < in_len) ++ { ++ pIE = (PNDIS_802_11_VARIABLE_IEs)(in_ie+ i); ++ ++ // Take out the rest of P2P OUIs ++ if( pIE->ElementID == _VENDOR_SPECIFIC_IE_ && _rtw_memcmp(pIE->data, OUI, 4) ) ++ { ++ _rtw_memcpy( merge_ie, pIE->data +4, pIE->Length -4); ++ len += pIE->Length-4; ++ merge_ie += pIE->Length-4; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ ++ return len + 4; // 4 is for P2P OUI ++ ++ } ++ ++ return 0; ++} ++ ++void dump_p2p_ie(u8 *ie, u32 ie_len) { ++ u8* pos = (u8*)ie; ++ u8 id; ++ u16 len; ++ ++ u8 *p2p_ie; ++ uint p2p_ielen; ++ ++ p2p_ie = rtw_get_p2p_ie(ie, ie_len, NULL, &p2p_ielen); ++ if(p2p_ie != ie || p2p_ielen == 0) ++ return; ++ ++ pos+=6; ++ while(pos-ie < ie_len){ ++ id = *pos; ++ len = RTW_GET_LE16(pos+1); ++ ++ DBG_871X("%s ID:%u, LEN:%u\n", __FUNCTION__, id, len); ++ ++ pos+=(3+len); ++ } ++} ++ ++u8 *rtw_get_p2p_ie_from_scan_queue(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen, u8 frame_type) ++{ ++ u8* p2p = NULL; ++ ++ DBG_871X( "[%s] frame_type = %d\n", __FUNCTION__, frame_type ); ++ switch( frame_type ) ++ { ++ case 1: ++ case 3: ++ { // Beacon or Probe Response ++ p2p = rtw_get_p2p_ie(in_ie + _PROBERSP_IE_OFFSET_, in_len - _PROBERSP_IE_OFFSET_, p2p_ie, p2p_ielen); ++ break; ++ } ++ case 2: ++ { // Probe Request ++ p2p = rtw_get_p2p_ie(in_ie + _PROBEREQ_IE_OFFSET_ , in_len - _PROBEREQ_IE_OFFSET_ , p2p_ie, p2p_ielen); ++ break; ++ } ++ } ++ return p2p; ++} ++ ++/** ++ * rtw_get_p2p_ie - Search P2P IE from a series of IEs ++ * @in_ie: Address of IEs to search ++ * @in_len: Length limit from in_ie ++ * @p2p_ie: If not NULL and P2P IE is found, P2P IE will be copied to the buf starting from p2p_ie ++ * @p2p_ielen: If not NULL and P2P IE is found, will set to the length of the entire P2P IE ++ * ++ * Returns: The address of the P2P IE found, or NULL ++ */ ++u8 *rtw_get_p2p_ie(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen) ++{ ++ uint cnt = 0; ++ u8 *p2p_ie_ptr; ++ u8 eid, p2p_oui[4]={0x50,0x6F,0x9A,0x09}; ++ ++ if ( p2p_ielen != NULL ) ++ *p2p_ielen = 0; ++ ++ while(cnt MAX_IE_SZ)) { ++#ifdef PLATFORM_LINUX ++ dump_stack(); ++#endif ++ return NULL; ++ } ++ if( ( eid == _VENDOR_SPECIFIC_IE_ ) && ( _rtw_memcmp( &in_ie[cnt+2], p2p_oui, 4) == _TRUE ) ) ++ { ++ p2p_ie_ptr = in_ie + cnt; ++ ++ if ( p2p_ie != NULL ) ++ { ++ _rtw_memcpy( p2p_ie, &in_ie[ cnt ], in_ie[ cnt + 1 ] + 2 ); ++ } ++ ++ if ( p2p_ielen != NULL ) ++ { ++ *p2p_ielen = in_ie[ cnt + 1 ] + 2; ++ } ++ ++ return p2p_ie_ptr; ++ ++ break; ++ } ++ else ++ { ++ cnt += in_ie[ cnt + 1 ] +2; //goto next ++ } ++ ++ } ++ ++ return NULL; ++ ++} ++ ++/** ++ * rtw_get_p2p_attr - Search a specific P2P attribute from a given P2P IE ++ * @p2p_ie: Address of P2P IE to search ++ * @p2p_ielen: Length limit from p2p_ie ++ * @target_attr_id: The attribute ID of P2P attribute to search ++ * @buf_attr: If not NULL and the P2P attribute is found, P2P attribute will be copied to the buf starting from buf_attr ++ * @len_attr: If not NULL and the P2P attribute is found, will set to the length of the entire P2P attribute ++ * ++ * Returns: the address of the specific WPS attribute found, or NULL ++ */ ++u8 *rtw_get_p2p_attr(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id ,u8 *buf_attr, u32 *len_attr) ++{ ++ u8 *attr_ptr = NULL; ++ u8 *target_attr_ptr = NULL; ++ u8 p2p_oui[4]={0x50,0x6F,0x9A,0x09}; ++ ++ if(len_attr) ++ *len_attr = 0; ++ ++ if ( !p2p_ie || ( p2p_ie[0] != _VENDOR_SPECIFIC_IE_ ) || ++ ( _rtw_memcmp( p2p_ie + 2, p2p_oui , 4 ) != _TRUE ) ) ++ { ++ return attr_ptr; ++ } ++ ++ // 6 = 1(Element ID) + 1(Length) + 3 (OUI) + 1(OUI Type) ++ attr_ptr = p2p_ie + 6; //goto first attr ++ ++ while(attr_ptr - p2p_ie < p2p_ielen) ++ { ++ // 3 = 1(Attribute ID) + 2(Length) ++ u8 attr_id = *attr_ptr; ++ u16 attr_data_len = RTW_GET_LE16(attr_ptr + 1); ++ u16 attr_len = attr_data_len + 3; ++ ++ //DBG_871X("%s attr_ptr:%p, id:%u, length:%u\n", __FUNCTION__, attr_ptr, attr_id, attr_data_len); ++ if( attr_id == target_attr_id ) ++ { ++ target_attr_ptr = attr_ptr; ++ ++ if(buf_attr) ++ _rtw_memcpy(buf_attr, attr_ptr, attr_len); ++ ++ if(len_attr) ++ *len_attr = attr_len; ++ ++ break; ++ } ++ else ++ { ++ attr_ptr += attr_len; //goto next ++ } ++ ++ } ++ ++ return target_attr_ptr; ++} ++ ++/** ++ * rtw_get_p2p_attr_content - Search a specific P2P attribute content from a given P2P IE ++ * @p2p_ie: Address of P2P IE to search ++ * @p2p_ielen: Length limit from p2p_ie ++ * @target_attr_id: The attribute ID of P2P attribute to search ++ * @buf_content: If not NULL and the P2P attribute is found, P2P attribute content will be copied to the buf starting from buf_content ++ * @len_content: If not NULL and the P2P attribute is found, will set to the length of the P2P attribute content ++ * ++ * Returns: the address of the specific P2P attribute content found, or NULL ++ */ ++u8 *rtw_get_p2p_attr_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id ,u8 *buf_content, uint *len_content) ++{ ++ u8 *attr_ptr; ++ u32 attr_len; ++ ++ if(len_content) ++ *len_content = 0; ++ ++ attr_ptr = rtw_get_p2p_attr(p2p_ie, p2p_ielen, target_attr_id, NULL, &attr_len); ++ ++ if(attr_ptr && attr_len) ++ { ++ if(buf_content) ++ _rtw_memcpy(buf_content, attr_ptr+3, attr_len-3); ++ ++ if(len_content) ++ *len_content = attr_len-3; ++ ++ return attr_ptr+3; ++ } ++ ++ return NULL; ++} ++ ++u32 rtw_set_p2p_attr_content(u8 *pbuf, u8 attr_id, u16 attr_len, u8 *pdata_attr) ++{ ++ u32 a_len; ++ ++ *pbuf = attr_id; ++ ++ //*(u16*)(pbuf + 1) = cpu_to_le16(attr_len); ++ RTW_PUT_LE16(pbuf + 1, attr_len); ++ ++ if(pdata_attr) ++ _rtw_memcpy(pbuf + 3, pdata_attr, attr_len); ++ ++ a_len = attr_len + 3; ++ ++ return a_len; ++} ++ ++static uint rtw_p2p_attr_remove(u8 *ie, uint ielen_ori, u8 attr_id) ++{ ++ u8 *target_attr; ++ u32 target_attr_len; ++ uint ielen = ielen_ori; ++ int index=0; ++ ++ while(1) { ++ target_attr=rtw_get_p2p_attr(ie, ielen, attr_id, NULL, &target_attr_len); ++ if(target_attr && target_attr_len) ++ { ++ u8 *next_attr = target_attr+target_attr_len; ++ uint remain_len = ielen-(next_attr-ie); ++ //dump_ies(ie, ielen); ++ #if 0 ++ DBG_871X("[%d] ie:%p, ielen:%u\n" ++ "target_attr:%p, target_attr_len:%u\n" ++ "next_attr:%p, remain_len:%u\n" ++ , index++ ++ , ie, ielen ++ , target_attr, target_attr_len ++ , next_attr, remain_len ++ ); ++ #endif ++ ++ _rtw_memset(target_attr, 0, target_attr_len); ++ _rtw_memcpy(target_attr, next_attr, remain_len); ++ _rtw_memset(target_attr+remain_len, 0, target_attr_len); ++ *(ie+1) -= target_attr_len; ++ ielen-=target_attr_len; ++ } ++ else ++ { ++ //if(index>0) ++ // dump_ies(ie, ielen); ++ break; ++ } ++ } ++ ++ return ielen; ++} ++ ++void rtw_WLAN_BSSID_EX_remove_p2p_attr(WLAN_BSSID_EX *bss_ex, u8 attr_id) ++{ ++ u8 *p2p_ie; ++ uint p2p_ielen, p2p_ielen_ori; ++ int cnt; ++ ++ if( (p2p_ie=rtw_get_p2p_ie(bss_ex->IEs+_FIXED_IE_LENGTH_, bss_ex->IELength-_FIXED_IE_LENGTH_, NULL, &p2p_ielen_ori)) ) ++ { ++ #if 0 ++ if(rtw_get_p2p_attr(p2p_ie, p2p_ielen_ori, attr_id, NULL, NULL)) { ++ DBG_871X("rtw_get_p2p_attr: GOT P2P_ATTR:%u!!!!!!!!\n", attr_id); ++ dump_ies(bss_ex->IEs+_FIXED_IE_LENGTH_, bss_ex->IELength-_FIXED_IE_LENGTH_); ++ } ++ #endif ++ ++ p2p_ielen=rtw_p2p_attr_remove(p2p_ie, p2p_ielen_ori, attr_id); ++ if(p2p_ielen != p2p_ielen_ori) { ++ ++ u8 *next_ie_ori = p2p_ie+p2p_ielen_ori; ++ u8 *next_ie = p2p_ie+p2p_ielen; ++ uint remain_len = bss_ex->IELength-(next_ie_ori-bss_ex->IEs); ++ ++ _rtw_memcpy(next_ie, next_ie_ori, remain_len); ++ _rtw_memset(next_ie+remain_len, 0, p2p_ielen_ori-p2p_ielen); ++ bss_ex->IELength -= p2p_ielen_ori-p2p_ielen; ++ ++ #if 0 ++ DBG_871X("remove P2P_ATTR:%u!\n", attr_id); ++ dump_ies(bss_ex->IEs+_FIXED_IE_LENGTH_, bss_ex->IELength-_FIXED_IE_LENGTH_); ++ #endif ++ } ++ } ++} ++ ++#endif //CONFIG_P2P ++ ++#ifdef CONFIG_WFD ++void dump_wfd_ie(u8 *ie, u32 ie_len) ++{ ++ u8* pos = (u8*)ie; ++ u8 id; ++ u16 len; ++ ++ u8 *wfd_ie; ++ uint wfd_ielen; ++ ++ if(rtw_get_wfd_ie(ie, ie_len, NULL, &wfd_ielen) == _FALSE) ++ return; ++ ++ pos+=6; ++ while(pos-ie < ie_len){ ++ id = *pos; ++ len = RTW_GET_BE16(pos+1); ++ ++ DBG_871X("%s ID:%u, LEN:%u\n", __FUNCTION__, id, len); ++ ++ pos+=(3+len); ++ } ++} ++ ++int rtw_get_wfd_ie(u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen) ++{ ++ int match; ++ uint cnt = 0; ++ u8 eid, wfd_oui[4]={0x50,0x6F,0x9A,0x0A}; ++ ++ ++ match=_FALSE; ++ ++ if ( in_len < 0 ) ++ { ++ return match; ++ } ++ ++ while(cnt 1 byte for attribute ID field, 2 bytes for length field ++ if(attr_content) ++ _rtw_memcpy( attr_content, &wfd_ie[ cnt + 3 ], attrlen ); ++ ++ if(attr_contentlen) ++ *attr_contentlen = attrlen; ++ ++ cnt += attrlen + 3; ++ ++ match = _TRUE; ++ break; ++ } ++ else ++ { ++ cnt += attrlen + 3; //goto next ++ } ++ ++ } ++ ++ return match; ++ ++} ++#endif // CONFIG_WFD ++ ++//Baron adds to avoid FreeBSD warning ++int ieee80211_is_empty_essid(const char *essid, int essid_len) ++{ ++ /* Single white space is for Linksys APs */ ++ if (essid_len == 1 && essid[0] == ' ') ++ return 1; ++ ++ /* Otherwise, if the entire essid is 0, we assume it is hidden */ ++ while (essid_len) { ++ essid_len--; ++ if (essid[essid_len] != '\0') ++ return 0; ++ } ++ ++ return 1; ++} ++ ++int ieee80211_get_hdrlen(u16 fc) ++{ ++ int hdrlen = 24; ++ ++ switch (WLAN_FC_GET_TYPE(fc)) { ++ case RTW_IEEE80211_FTYPE_DATA: ++ if (fc & RTW_IEEE80211_STYPE_QOS_DATA) ++ hdrlen += 2; ++ if ((fc & RTW_IEEE80211_FCTL_FROMDS) && (fc & RTW_IEEE80211_FCTL_TODS)) ++ hdrlen += 6; /* Addr4 */ ++ break; ++ case RTW_IEEE80211_FTYPE_CTL: ++ switch (WLAN_FC_GET_STYPE(fc)) { ++ case RTW_IEEE80211_STYPE_CTS: ++ case RTW_IEEE80211_STYPE_ACK: ++ hdrlen = 10; ++ break; ++ default: ++ hdrlen = 16; ++ break; ++ } ++ break; ++ } ++ ++ return hdrlen; ++} ++ ++int rtw_get_cipher_info(struct wlan_network *pnetwork) ++{ ++ u32 wpa_ielen; ++ unsigned char *pbuf; ++ int group_cipher = 0, pairwise_cipher = 0, is8021x = 0; ++ int ret = _FAIL; ++ pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12); ++ ++ if(pbuf && (wpa_ielen>0)) { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_get_cipher_info: wpa_ielen: %d", wpa_ielen)); ++ if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is8021x)) { ++ ++ pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher; ++ pnetwork->BcnInfo.group_cipher = group_cipher; ++ pnetwork->BcnInfo.is_8021x = is8021x; ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("%s: pnetwork->pairwise_cipher: %d, is_8021x is %d", ++ __func__, pnetwork->BcnInfo.pairwise_cipher, pnetwork->BcnInfo.is_8021x)); ++ ret = _SUCCESS; ++ } ++ } else { ++ ++ pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12); ++ ++ if(pbuf && (wpa_ielen>0)) { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("get RSN IE\n")); ++ if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is8021x)) { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("get RSN IE OK!!!\n")); ++ pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher; ++ pnetwork->BcnInfo.group_cipher = group_cipher; ++ pnetwork->BcnInfo.is_8021x = is8021x; ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("%s: pnetwork->pairwise_cipher: %d," ++ "pnetwork->group_cipher is %d, is_8021x is %d", __func__, pnetwork->BcnInfo.pairwise_cipher, ++ pnetwork->BcnInfo.group_cipher,pnetwork->BcnInfo.is_8021x)); ++ ret = _SUCCESS; ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++void rtw_get_bcn_info(struct wlan_network *pnetwork) ++{ ++ unsigned short cap = 0; ++ u8 bencrypt = 0; ++ //u8 wpa_ie[255],rsn_ie[255]; ++ u16 wpa_len=0,rsn_len=0; ++ struct HT_info_element *pht_info = NULL; ++ struct rtw_ieee80211_ht_cap *pht_cap = NULL; ++ unsigned int len; ++ unsigned char *p; ++ ++ _rtw_memcpy((u8 *)&cap, rtw_get_capability_from_ie(pnetwork->network.IEs), 2); ++ cap = le16_to_cpu(cap); ++ if (cap & WLAN_CAPABILITY_PRIVACY) { ++ bencrypt = 1; ++ pnetwork->network.Privacy = 1; ++ } else { ++ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS; ++ } ++ rtw_get_sec_ie(pnetwork->network.IEs ,pnetwork->network.IELength,NULL,&rsn_len,NULL,&wpa_len); ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_get_bcn_info: ssid=%s\n",pnetwork->network.Ssid.Ssid)); ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_get_bcn_info: wpa_len=%d rsn_len=%d\n",wpa_len,rsn_len)); ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_get_bcn_info: ssid=%s\n",pnetwork->network.Ssid.Ssid)); ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_get_bcn_info: wpa_len=%d rsn_len=%d\n",wpa_len,rsn_len)); ++ ++ if (rsn_len > 0) { ++ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2; ++ } else if (wpa_len > 0) { ++ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA; ++ } else { ++ if (bencrypt) ++ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WEP; ++ } ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_get_bcn_info: pnetwork->encryp_protocol is %x\n", ++ pnetwork->BcnInfo.encryp_protocol)); ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_get_bcn_info: pnetwork->encryp_protocol is %x\n", ++ pnetwork->BcnInfo.encryp_protocol)); ++ rtw_get_cipher_info(pnetwork); ++ ++ /* get bwmode and ch_offset */ ++ /* parsing HT_CAP_IE */ ++ p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_); ++ if(p && len>0) { ++ pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2); ++ pnetwork->BcnInfo.ht_cap_info = pht_cap->cap_info; ++ } else { ++ pnetwork->BcnInfo.ht_cap_info = 0; ++ } ++ /* parsing HT_INFO_IE */ ++ p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_); ++ if(p && len>0) { ++ pht_info = (struct HT_info_element *)(p + 2); ++ pnetwork->BcnInfo.ht_info_infos_0 = pht_info->infos[0]; ++ } else { ++ pnetwork->BcnInfo.ht_info_infos_0 = 0; ++ } ++} ++ ++//show MCS rate, unit: 100Kbps ++u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI_20, u8 short_GI_40, unsigned char * MCS_rate) ++{ ++ u16 max_rate = 0; ++ ++ if(rf_type == RF_1T1R) ++ { ++ if(MCS_rate[0] & BIT(7)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?1500:1350):((short_GI_20)?722:650); ++ else if(MCS_rate[0] & BIT(6)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?1350:1215):((short_GI_20)?650:585); ++ else if(MCS_rate[0] & BIT(5)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?1200:1080):((short_GI_20)?578:520); ++ else if(MCS_rate[0] & BIT(4)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?900:810):((short_GI_20)?433:390); ++ else if(MCS_rate[0] & BIT(3)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?600:540):((short_GI_20)?289:260); ++ else if(MCS_rate[0] & BIT(2)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?450:405):((short_GI_20)?217:195); ++ else if(MCS_rate[0] & BIT(1)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?300:270):((short_GI_20)?144:130); ++ else if(MCS_rate[0] & BIT(0)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?150:135):((short_GI_20)?72:65); ++ } ++ else ++ { ++ if(MCS_rate[1]) ++ { ++ if(MCS_rate[1] & BIT(7)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?3000:2700):((short_GI_20)?1444:1300); ++ else if(MCS_rate[1] & BIT(6)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?2700:2430):((short_GI_20)?1300:1170); ++ else if(MCS_rate[1] & BIT(5)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?2400:2160):((short_GI_20)?1156:1040); ++ else if(MCS_rate[1] & BIT(4)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?1800:1620):((short_GI_20)?867:780); ++ else if(MCS_rate[1] & BIT(3)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?1200:1080):((short_GI_20)?578:520); ++ else if(MCS_rate[1] & BIT(2)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?900:810):((short_GI_20)?433:390); ++ else if(MCS_rate[1] & BIT(1)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?600:540):((short_GI_20)?289:260); ++ else if(MCS_rate[1] & BIT(0)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?300:270):((short_GI_20)?144:130); ++ } ++ else ++ { ++ if(MCS_rate[0] & BIT(7)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?1500:1350):((short_GI_20)?722:650); ++ else if(MCS_rate[0] & BIT(6)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?1350:1215):((short_GI_20)?650:585); ++ else if(MCS_rate[0] & BIT(5)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?1200:1080):((short_GI_20)?578:520); ++ else if(MCS_rate[0] & BIT(4)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?900:810):((short_GI_20)?433:390); ++ else if(MCS_rate[0] & BIT(3)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?600:540):((short_GI_20)?289:260); ++ else if(MCS_rate[0] & BIT(2)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?450:405):((short_GI_20)?217:195); ++ else if(MCS_rate[0] & BIT(1)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?300:270):((short_GI_20)?144:130); ++ else if(MCS_rate[0] & BIT(0)) ++ max_rate = (bw_40MHz) ? ((short_GI_40)?150:135):((short_GI_20)?72:65); ++ } ++ } ++ return max_rate; ++} ++ ++int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8* category, u8 *action) ++{ ++ const u8 *frame_body = frame + sizeof(struct rtw_ieee80211_hdr_3addr); ++ u16 fc; ++ u8 c, a; ++ ++ fc = le16_to_cpu(((struct rtw_ieee80211_hdr_3addr *)frame)->frame_ctl); ++ ++ if ((fc & (RTW_IEEE80211_FCTL_FTYPE|RTW_IEEE80211_FCTL_STYPE)) ++ != (RTW_IEEE80211_FTYPE_MGMT|RTW_IEEE80211_STYPE_ACTION) ++ ) ++ { ++ return _FALSE; ++ } ++ ++ c = frame_body[0]; ++ ++ switch(c) { ++ case RTW_WLAN_CATEGORY_P2P: /* vendor-specific */ ++ break; ++ default: ++ a = frame_body[1]; ++ } ++ ++ if (category) ++ *category = c; ++ if (action) ++ *action = a; ++ ++ return _TRUE; ++} ++ ++static const char *_action_public_str[] = { ++ "ACT_PUB_BSSCOEXIST", ++ "ACT_PUB_DSE_ENABLE", ++ "ACT_PUB_DSE_DEENABLE", ++ "ACT_PUB_DSE_REG_LOCATION", ++ "ACT_PUB_EXT_CHL_SWITCH", ++ "ACT_PUB_DSE_MSR_REQ", ++ "ACT_PUB_DSE_MSR_RPRT", ++ "ACT_PUB_MP", ++ "ACT_PUB_DSE_PWR_CONSTRAINT", ++ "ACT_PUB_VENDOR", ++ "ACT_PUB_GAS_INITIAL_REQ", ++ "ACT_PUB_GAS_INITIAL_RSP", ++ "ACT_PUB_GAS_COMEBACK_REQ", ++ "ACT_PUB_GAS_COMEBACK_RSP", ++ "ACT_PUB_TDLS_DISCOVERY_RSP", ++ "ACT_PUB_LOCATION_TRACK", ++ "ACT_PUB_RSVD", ++}; ++ ++const char *action_public_str(u8 action) ++{ ++ action = (action >= ACT_PUBLIC_MAX) ? ACT_PUBLIC_MAX : action; ++ return _action_public_str[action]; ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_io.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_io.c +new file mode 100644 +index 00000000..26797830 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_io.c +@@ -0,0 +1,509 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++/* ++ ++The purpose of rtw_io.c ++ ++a. provides the API ++ ++b. provides the protocol engine ++ ++c. provides the software interface between caller and the hardware interface ++ ++ ++Compiler Flag Option: ++ ++1. CONFIG_SDIO_HCI: ++ a. USE_SYNC_IRP: Only sync operations are provided. ++ b. USE_ASYNC_IRP:Both sync/async operations are provided. ++ ++2. CONFIG_USB_HCI: ++ a. USE_ASYNC_IRP: Both sync/async operations are provided. ++ ++3. CONFIG_CFIO_HCI: ++ b. USE_SYNC_IRP: Only sync operations are provided. ++ ++ ++Only sync read/rtw_write_mem operations are provided. ++ ++jackson@realtek.com.tw ++ ++*/ ++ ++#define _RTW_IO_C_ ++#include ++#include ++#include ++#include ++#include ++ ++#if defined (PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) ++#error "Shall be Linux or Windows, but not both!\n" ++#endif ++ ++#ifdef CONFIG_SDIO_HCI ++#include ++#endif ++ ++#ifdef CONFIG_GSPI_HCI ++#include ++#endif ++ ++#ifdef CONFIG_USB_HCI ++#include ++#endif ++ ++#ifdef CONFIG_PCI_HCI ++#include ++#endif ++ ++#ifdef CONFIG_SDIO_HCI ++#define rtw_le16_to_cpu(val) val ++#define rtw_le32_to_cpu(val) val ++#define rtw_cpu_to_le16(val) val ++#define rtw_cpu_to_le32(val) val ++#else ++#define rtw_le16_to_cpu(val) le16_to_cpu(val) ++#define rtw_le32_to_cpu(val) le32_to_cpu(val) ++#define rtw_cpu_to_le16(val) cpu_to_le16(val) ++#define rtw_cpu_to_le32(val) cpu_to_le32(val) ++#endif ++ ++ ++u8 _rtw_read8(_adapter *adapter, u32 addr) ++{ ++ u8 r_val; ++ //struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr); ++ _func_enter_; ++ _read8 = pintfhdl->io_ops._read8; ++ ++ r_val = _read8(pintfhdl, addr); ++ _func_exit_; ++ return r_val; ++} ++ ++u16 _rtw_read16(_adapter *adapter, u32 addr) ++{ ++ u16 r_val; ++ //struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr); ++ _func_enter_; ++ _read16 = pintfhdl->io_ops._read16; ++ ++ r_val = _read16(pintfhdl, addr); ++ _func_exit_; ++ return rtw_le16_to_cpu(r_val); ++} ++ ++u32 _rtw_read32(_adapter *adapter, u32 addr) ++{ ++ u32 r_val; ++ //struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr); ++ _func_enter_; ++ _read32 = pintfhdl->io_ops._read32; ++ ++ r_val = _read32(pintfhdl, addr); ++ _func_exit_; ++ return rtw_le32_to_cpu(r_val); ++ ++} ++ ++int _rtw_write8(_adapter *adapter, u32 addr, u8 val) ++{ ++ //struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ int (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val); ++ int ret; ++ _func_enter_; ++ _write8 = pintfhdl->io_ops._write8; ++ ++ ret = _write8(pintfhdl, addr, val); ++ _func_exit_; ++ ++ return RTW_STATUS_CODE(ret); ++} ++int _rtw_write16(_adapter *adapter, u32 addr, u16 val) ++{ ++ //struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ int (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val); ++ int ret; ++ _func_enter_; ++ _write16 = pintfhdl->io_ops._write16; ++ ++ val = rtw_cpu_to_le16(val); ++ ret = _write16(pintfhdl, addr, val); ++ _func_exit_; ++ ++ return RTW_STATUS_CODE(ret); ++} ++int _rtw_write32(_adapter *adapter, u32 addr, u32 val) ++{ ++ //struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ int (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val); ++ int ret; ++ _func_enter_; ++ _write32 = pintfhdl->io_ops._write32; ++ ++ val = rtw_cpu_to_le32(val); ++ ret = _write32(pintfhdl, addr, val); ++ _func_exit_; ++ ++ return RTW_STATUS_CODE(ret); ++} ++ ++int _rtw_writeN(_adapter *adapter, u32 addr ,u32 length , u8 *pdata) ++{ ++ //struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = (struct intf_hdl*)(&(pio_priv->intf)); ++ int (*_writeN)(struct intf_hdl *pintfhdl, u32 addr,u32 length, u8 *pdata); ++ int ret; ++ _func_enter_; ++ _writeN = pintfhdl->io_ops._writeN; ++ ++ ret = _writeN(pintfhdl, addr,length,pdata); ++ _func_exit_; ++ ++ return RTW_STATUS_CODE(ret); ++} ++int _rtw_write8_async(_adapter *adapter, u32 addr, u8 val) ++{ ++ //struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ int (*_write8_async)(struct intf_hdl *pintfhdl, u32 addr, u8 val); ++ int ret; ++ _func_enter_; ++ _write8_async = pintfhdl->io_ops._write8_async; ++ ++ ret = _write8_async(pintfhdl, addr, val); ++ _func_exit_; ++ ++ return RTW_STATUS_CODE(ret); ++} ++int _rtw_write16_async(_adapter *adapter, u32 addr, u16 val) ++{ ++ //struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ int (*_write16_async)(struct intf_hdl *pintfhdl, u32 addr, u16 val); ++ int ret; ++ _func_enter_; ++ _write16_async = pintfhdl->io_ops._write16_async; ++ val = rtw_cpu_to_le16(val); ++ ret = _write16_async(pintfhdl, addr, val); ++ _func_exit_; ++ ++ return RTW_STATUS_CODE(ret); ++} ++int _rtw_write32_async(_adapter *adapter, u32 addr, u32 val) ++{ ++ //struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ int (*_write32_async)(struct intf_hdl *pintfhdl, u32 addr, u32 val); ++ int ret; ++ _func_enter_; ++ _write32_async = pintfhdl->io_ops._write32_async; ++ val = rtw_cpu_to_le32(val); ++ ret = _write32_async(pintfhdl, addr, val); ++ _func_exit_; ++ ++ return RTW_STATUS_CODE(ret); ++} ++ ++void _rtw_read_mem(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem) ++{ ++ void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ //struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ ++ _func_enter_; ++ ++ if( (adapter->bDriverStopped ==_TRUE) || (adapter->bSurpriseRemoved == _TRUE)) ++ { ++ RT_TRACE(_module_rtl871x_io_c_, _drv_info_, ("rtw_read_mem:bDriverStopped(%d) OR bSurpriseRemoved(%d)", adapter->bDriverStopped, adapter->bSurpriseRemoved)); ++ return; ++ } ++ ++ _read_mem = pintfhdl->io_ops._read_mem; ++ ++ _read_mem(pintfhdl, addr, cnt, pmem); ++ ++ _func_exit_; ++ ++} ++ ++void _rtw_write_mem(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem) ++{ ++ void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ //struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ ++ _func_enter_; ++ ++ _write_mem = pintfhdl->io_ops._write_mem; ++ ++ _write_mem(pintfhdl, addr, cnt, pmem); ++ ++ _func_exit_; ++ ++} ++ ++void _rtw_read_port(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem) ++{ ++ u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ //struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ ++ _func_enter_; ++ ++ if( (adapter->bDriverStopped ==_TRUE) || (adapter->bSurpriseRemoved == _TRUE)) ++ { ++ RT_TRACE(_module_rtl871x_io_c_, _drv_info_, ("rtw_read_port:bDriverStopped(%d) OR bSurpriseRemoved(%d)", adapter->bDriverStopped, adapter->bSurpriseRemoved)); ++ return; ++ } ++ ++ _read_port = pintfhdl->io_ops._read_port; ++ ++ _read_port(pintfhdl, addr, cnt, pmem); ++ ++ _func_exit_; ++ ++} ++ ++void _rtw_read_port_cancel(_adapter *adapter) ++{ ++ void (*_read_port_cancel)(struct intf_hdl *pintfhdl); ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ ++ _read_port_cancel = pintfhdl->io_ops._read_port_cancel; ++ ++ if(_read_port_cancel) ++ _read_port_cancel(pintfhdl); ++ ++} ++ ++u32 _rtw_write_port(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem) ++{ ++ u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ //struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ u32 ret = _SUCCESS; ++ ++ _func_enter_; ++ ++ _write_port = pintfhdl->io_ops._write_port; ++ ++ ret = _write_port(pintfhdl, addr, cnt, pmem); ++ ++ _func_exit_; ++ ++ return ret; ++} ++ ++u32 _rtw_write_port_and_wait(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem, int timeout_ms) ++{ ++ int ret = _SUCCESS; ++ struct xmit_buf *pxmitbuf = (struct xmit_buf *)pmem; ++ struct submit_ctx sctx; ++ ++ rtw_sctx_init(&sctx, timeout_ms); ++ pxmitbuf->sctx = &sctx; ++ ++ ret = _rtw_write_port(adapter, addr, cnt, pmem); ++ ++ if (ret == _SUCCESS) ++ ret = rtw_sctx_wait(&sctx); ++ ++ return ret; ++} ++ ++void _rtw_write_port_cancel(_adapter *adapter) ++{ ++ void (*_write_port_cancel)(struct intf_hdl *pintfhdl); ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ ++ _write_port_cancel = pintfhdl->io_ops._write_port_cancel; ++ ++ if(_write_port_cancel) ++ _write_port_cancel(pintfhdl); ++ ++} ++ ++int rtw_init_io_priv(_adapter *padapter, void (*set_intf_ops)(struct _io_ops *pops)) ++{ ++ struct io_priv *piopriv = &padapter->iopriv; ++ struct intf_hdl *pintf = &piopriv->intf; ++ ++ if (set_intf_ops == NULL) ++ return _FAIL; ++ ++ piopriv->padapter = padapter; ++ pintf->padapter = padapter; ++ pintf->pintf_dev = adapter_to_dvobj(padapter); ++ ++ set_intf_ops(&pintf->io_ops); ++ ++ return _SUCCESS; ++} ++ ++/* ++* Increase and check if the continual_io_error of this @param dvobjprive is larger than MAX_CONTINUAL_IO_ERR ++* @return _TRUE: ++* @return _FALSE: ++*/ ++int rtw_inc_and_chk_continual_io_error(struct dvobj_priv *dvobj) ++{ ++ int ret = _FALSE; ++ int value; ++ if( (value=ATOMIC_INC_RETURN(&dvobj->continual_io_error)) > MAX_CONTINUAL_IO_ERR) { ++ DBG_871X("[dvobj:%p][ERROR] continual_io_error:%d > %d\n", dvobj, value, MAX_CONTINUAL_IO_ERR); ++ ret = _TRUE; ++ } else { ++ //DBG_871X("[dvobj:%p] continual_io_error:%d\n", dvobj, value); ++ } ++ return ret; ++} ++ ++/* ++* Set the continual_io_error of this @param dvobjprive to 0 ++*/ ++void rtw_reset_continual_io_error(struct dvobj_priv *dvobj) ++{ ++ ATOMIC_SET(&dvobj->continual_io_error, 0); ++} ++ ++#ifdef DBG_IO ++ ++u16 read_sniff_ranges[][2] = { ++ //{0x550, 0x551}, ++}; ++ ++u16 write_sniff_ranges[][2] = { ++ //{0x550, 0x551}, ++ //{0x4c, 0x4c}, ++}; ++ ++int read_sniff_num = sizeof(read_sniff_ranges)/sizeof(u16)/2; ++int write_sniff_num = sizeof(write_sniff_ranges)/sizeof(u16)/2; ++ ++bool match_read_sniff_ranges(u16 addr, u16 len) ++{ ++ int i; ++ for (i = 0; i read_sniff_ranges[i][0] && addr <= read_sniff_ranges[i][1]) ++ return _TRUE; ++ } ++ ++ return _FALSE; ++} ++ ++bool match_write_sniff_ranges(u16 addr, u16 len) ++{ ++ int i; ++ for (i = 0; i write_sniff_ranges[i][0] && addr <= write_sniff_ranges[i][1]) ++ return _TRUE; ++ } ++ ++ return _FALSE; ++} ++ ++u8 dbg_rtw_read8(_adapter *adapter, u32 addr, const char *caller, const int line) ++{ ++ u8 val = _rtw_read8(adapter, addr); ++ ++ if (match_read_sniff_ranges(addr, 1)) ++ DBG_871X("DBG_IO %s:%d rtw_read8(0x%04x) return 0x%02x\n", caller, line, addr, val); ++ ++ return val; ++} ++ ++u16 dbg_rtw_read16(_adapter *adapter, u32 addr, const char *caller, const int line) ++{ ++ u16 val = _rtw_read16(adapter, addr); ++ ++ if (match_read_sniff_ranges(addr, 2)) ++ DBG_871X("DBG_IO %s:%d rtw_read16(0x%04x) return 0x%04x\n", caller, line, addr, val); ++ ++ return val; ++} ++ ++u32 dbg_rtw_read32(_adapter *adapter, u32 addr, const char *caller, const int line) ++{ ++ u32 val = _rtw_read32(adapter, addr); ++ ++ if (match_read_sniff_ranges(addr, 4)) ++ DBG_871X("DBG_IO %s:%d rtw_read32(0x%04x) return 0x%08x\n", caller, line, addr, val); ++ ++ return val; ++} ++ ++int dbg_rtw_write8(_adapter *adapter, u32 addr, u8 val, const char *caller, const int line) ++{ ++ if (match_write_sniff_ranges(addr, 1)) ++ DBG_871X("DBG_IO %s:%d rtw_write8(0x%04x, 0x%02x)\n", caller, line, addr, val); ++ ++ return _rtw_write8(adapter, addr, val); ++} ++int dbg_rtw_write16(_adapter *adapter, u32 addr, u16 val, const char *caller, const int line) ++{ ++ if (match_write_sniff_ranges(addr, 2)) ++ DBG_871X("DBG_IO %s:%d rtw_write16(0x%04x, 0x%04x)\n", caller, line, addr, val); ++ ++ return _rtw_write16(adapter, addr, val); ++} ++int dbg_rtw_write32(_adapter *adapter, u32 addr, u32 val, const char *caller, const int line) ++{ ++ if (match_write_sniff_ranges(addr, 4)) ++ DBG_871X("DBG_IO %s:%d rtw_write32(0x%04x, 0x%08x)\n", caller, line, addr, val); ++ ++ return _rtw_write32(adapter, addr, val); ++} ++int dbg_rtw_writeN(_adapter *adapter, u32 addr ,u32 length , u8 *data, const char *caller, const int line) ++{ ++ if (match_write_sniff_ranges(addr, length)) ++ DBG_871X("DBG_IO %s:%d rtw_writeN(0x%04x, %u)\n", caller, line, addr, length); ++ ++ return _rtw_writeN(adapter, addr, length, data); ++} ++#endif ++ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_ioctl_query.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_ioctl_query.c +new file mode 100644 +index 00000000..06018867 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_ioctl_query.c +@@ -0,0 +1,196 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_IOCTL_QUERY_C_ ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++#ifdef PLATFORM_WINDOWS ++// ++// Added for WPA2-PSK, by Annie, 2005-09-20. ++// ++u8 ++query_802_11_capability( ++ _adapter* Adapter, ++ u8* pucBuf, ++ u32 * pulOutLen ++) ++{ ++ static NDIS_802_11_AUTHENTICATION_ENCRYPTION szAuthEnc[] = ++ { ++ {Ndis802_11AuthModeOpen, Ndis802_11EncryptionDisabled}, ++ {Ndis802_11AuthModeOpen, Ndis802_11Encryption1Enabled}, ++ {Ndis802_11AuthModeShared, Ndis802_11EncryptionDisabled}, ++ {Ndis802_11AuthModeShared, Ndis802_11Encryption1Enabled}, ++ {Ndis802_11AuthModeWPA, Ndis802_11Encryption2Enabled}, ++ {Ndis802_11AuthModeWPA, Ndis802_11Encryption3Enabled}, ++ {Ndis802_11AuthModeWPAPSK, Ndis802_11Encryption2Enabled}, ++ {Ndis802_11AuthModeWPAPSK, Ndis802_11Encryption3Enabled}, ++ {Ndis802_11AuthModeWPANone, Ndis802_11Encryption2Enabled}, ++ {Ndis802_11AuthModeWPANone, Ndis802_11Encryption3Enabled}, ++ {Ndis802_11AuthModeWPA2, Ndis802_11Encryption2Enabled}, ++ {Ndis802_11AuthModeWPA2, Ndis802_11Encryption3Enabled}, ++ {Ndis802_11AuthModeWPA2PSK, Ndis802_11Encryption2Enabled}, ++ {Ndis802_11AuthModeWPA2PSK, Ndis802_11Encryption3Enabled} ++ }; ++ static ULONG ulNumOfPairSupported = sizeof(szAuthEnc)/sizeof(NDIS_802_11_AUTHENTICATION_ENCRYPTION); ++ NDIS_802_11_CAPABILITY * pCap = (NDIS_802_11_CAPABILITY *)pucBuf; ++ u8* pucAuthEncryptionSupported = (u8*) pCap->AuthenticationEncryptionSupported; ++ ++ ++ pCap->Length = sizeof(NDIS_802_11_CAPABILITY); ++ if(ulNumOfPairSupported > 1 ) ++ pCap->Length += (ulNumOfPairSupported-1) * sizeof(NDIS_802_11_AUTHENTICATION_ENCRYPTION); ++ ++ pCap->Version = 2; ++ pCap->NoOfPMKIDs = NUM_PMKID_CACHE; ++ pCap->NoOfAuthEncryptPairsSupported = ulNumOfPairSupported; ++ ++ if( sizeof (szAuthEnc) <= 240 ) // 240 = 256 - 4*4 // SecurityInfo.szCapability: only 256 bytes in size. ++ { ++ _rtw_memcpy( pucAuthEncryptionSupported, (u8*)szAuthEnc, sizeof (szAuthEnc) ); ++ *pulOutLen = pCap->Length; ++ return _TRUE; ++ } ++ else ++ { ++ *pulOutLen = 0; ++ RT_TRACE(_module_rtl871x_ioctl_query_c_,_drv_info_,("_query_802_11_capability(): szAuthEnc size is too large.\n")); ++ return _FALSE; ++ } ++} ++ ++u8 query_802_11_association_information( _adapter *padapter,PNDIS_802_11_ASSOCIATION_INFORMATION pAssocInfo) ++{ ++ struct wlan_network *tgt_network; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct security_priv *psecuritypriv=&(padapter->securitypriv); ++ WLAN_BSSID_EX *psecnetwork=(WLAN_BSSID_EX*)&(psecuritypriv->sec_bss); ++ u8 * pDest = (u8 *)pAssocInfo + sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); ++ unsigned char i,*auth_ie,*supp_ie; ++ ++ //NdisZeroMemory(pAssocInfo, sizeof(NDIS_802_11_ASSOCIATION_INFORMATION)); ++ _rtw_memset(pAssocInfo, 0, sizeof(NDIS_802_11_ASSOCIATION_INFORMATION)); ++ //pAssocInfo->Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); ++ ++ //------------------------------------------------------ ++ // Association Request related information ++ //------------------------------------------------------ ++ // Req_1. AvailableRequestFixedIEs ++ if(psecnetwork!=NULL){ ++ ++ pAssocInfo->AvailableRequestFixedIEs |= NDIS_802_11_AI_REQFI_CAPABILITIES|NDIS_802_11_AI_REQFI_CURRENTAPADDRESS; ++ pAssocInfo->RequestFixedIEs.Capabilities = (unsigned short)* & psecnetwork->IEs[10]; ++ _rtw_memcpy(pAssocInfo->RequestFixedIEs.CurrentAPAddress, ++ & psecnetwork->MacAddress, 6); ++ ++ pAssocInfo->OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); ++ ++ if(check_fwstate( pmlmepriv, _FW_UNDER_LINKING|_FW_LINKED)==_TRUE) ++ { ++ ++ if(psecuritypriv->ndisauthtype>=Ndis802_11AuthModeWPA2) ++ pDest[0] =48; //RSN Information Element ++ else ++ pDest[0] =221; //WPA(SSN) Information Element ++ ++ RT_TRACE(_module_rtl871x_ioctl_query_c_,_drv_info_,("\n Adapter->ndisauthtype==Ndis802_11AuthModeWPA)?0xdd:0x30 [%d]",pDest[0])); ++ supp_ie=&psecuritypriv->supplicant_ie[0]; ++ for(i=0;inetwork.IELength=%d\n\n", i,(int)psecnetwork->IELength)); ++ while((iRequestIELength += (2 + supp_ie[1+i]);// (2 + psecnetwork->IEs[1+i]+4); ++ ++ } ++ ++ ++ RT_TRACE(_module_rtl871x_ioctl_query_c_,_drv_info_,("\n psecnetwork != NULL,fwstate==_FW_UNDER_LINKING \n")); ++ ++ } ++ ++ ++ //------------------------------------------------------ ++ // Association Response related information ++ //------------------------------------------------------ ++ ++ if(check_fwstate( pmlmepriv, _FW_LINKED)==_TRUE) ++ { ++ tgt_network =&(pmlmepriv->cur_network); ++ if(tgt_network!=NULL){ ++ pAssocInfo->AvailableResponseFixedIEs = ++ NDIS_802_11_AI_RESFI_CAPABILITIES ++ |NDIS_802_11_AI_RESFI_ASSOCIATIONID ++ ; ++ ++ pAssocInfo->ResponseFixedIEs.Capabilities =(unsigned short)* & tgt_network->network.IEs[10]; ++ pAssocInfo->ResponseFixedIEs.StatusCode = 0; ++ pAssocInfo->ResponseFixedIEs.AssociationId =(unsigned short) tgt_network->aid; ++ ++ pDest = (u8 *)pAssocInfo + sizeof(NDIS_802_11_ASSOCIATION_INFORMATION)+pAssocInfo->RequestIELength; ++ auth_ie=&psecuritypriv->authenticator_ie[0]; ++ ++ for(i=0;i0){ ++ _rtw_memcpy((u8 *)&pDest[0],&auth_ie[1],i); ++ pAssocInfo->ResponseIELength =i; ++ } ++ ++ ++ pAssocInfo->OffsetResponseIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAssocInfo->RequestIELength; ++ ++ ++ RT_TRACE(_module_rtl871x_ioctl_query_c_,_drv_info_,("\n tgt_network != NULL,fwstate==_FW_LINKED \n")); ++ } ++ } ++ RT_TRACE(_module_rtl871x_ioctl_query_c_,_drv_info_,("\n exit query_802_11_association_information \n")); ++_func_exit_; ++ ++ return _TRUE; ++} ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_ioctl_rtl.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_ioctl_rtl.c +new file mode 100644 +index 00000000..d0454a97 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_ioctl_rtl.c +@@ -0,0 +1,1032 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_IOCTL_RTL_C_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_MP_INCLUDED ++#include ++#include ++#endif ++ ++struct oid_obj_priv oid_rtl_seg_01_01[] = ++{ ++ {1, &oid_null_function}, //0x80 ++ {1, &oid_null_function}, //0x81 ++ {1, &oid_null_function}, //0x82 ++ {1, &oid_null_function}, //0x83//OID_RT_SET_SNIFFER_MODE ++ {1, &oid_rt_get_signal_quality_hdl}, //0x84 ++ {1, &oid_rt_get_small_packet_crc_hdl}, //0x85 ++ {1, &oid_rt_get_middle_packet_crc_hdl}, //0x86 ++ {1, &oid_rt_get_large_packet_crc_hdl}, //0x87 ++ {1, &oid_rt_get_tx_retry_hdl}, //0x88 ++ {1, &oid_rt_get_rx_retry_hdl}, //0x89 ++ {1, &oid_rt_pro_set_fw_dig_state_hdl}, //0x8A ++ {1, &oid_rt_pro_set_fw_ra_state_hdl} , //0x8B ++ {1, &oid_null_function}, //0x8C ++ {1, &oid_null_function}, //0x8D ++ {1, &oid_null_function}, //0x8E ++ {1, &oid_null_function}, //0x8F ++ {1, &oid_rt_get_rx_total_packet_hdl}, //0x90 ++ {1, &oid_rt_get_tx_beacon_ok_hdl}, //0x91 ++ {1, &oid_rt_get_tx_beacon_err_hdl}, //0x92 ++ {1, &oid_rt_get_rx_icv_err_hdl}, //0x93 ++ {1, &oid_rt_set_encryption_algorithm_hdl}, //0x94 ++ {1, &oid_null_function}, //0x95 ++ {1, &oid_rt_get_preamble_mode_hdl}, //0x96 ++ {1, &oid_null_function}, //0x97 ++ {1, &oid_rt_get_ap_ip_hdl}, //0x98 ++ {1, &oid_rt_get_channelplan_hdl}, //0x99 ++ {1, &oid_rt_set_preamble_mode_hdl}, //0x9A ++ {1, &oid_rt_set_bcn_intvl_hdl}, //0x9B ++ {1, &oid_null_function}, //0x9C ++ {1, &oid_rt_dedicate_probe_hdl}, //0x9D ++ {1, &oid_null_function}, //0x9E ++ {1, &oid_null_function}, //0x9F ++ {1, &oid_null_function}, //0xA0 ++ {1, &oid_null_function}, //0xA1 ++ {1, &oid_null_function}, //0xA2 ++ {1, &oid_null_function}, //0xA3 ++ {1, &oid_null_function}, //0xA4 ++ {1, &oid_null_function}, //0xA5 ++ {1, &oid_null_function}, //0xA6 ++ {1, &oid_rt_get_total_tx_bytes_hdl}, //0xA7 ++ {1, &oid_rt_get_total_rx_bytes_hdl}, //0xA8 ++ {1, &oid_rt_current_tx_power_level_hdl}, //0xA9 ++ {1, &oid_rt_get_enc_key_mismatch_count_hdl}, //0xAA ++ {1, &oid_rt_get_enc_key_match_count_hdl}, //0xAB ++ {1, &oid_rt_get_channel_hdl}, //0xAC ++ {1, &oid_rt_set_channelplan_hdl}, //0xAD ++ {1, &oid_rt_get_hardware_radio_off_hdl}, //0xAE ++ {1, &oid_null_function}, //0xAF ++ {1, &oid_null_function}, //0xB0 ++ {1, &oid_null_function}, //0xB1 ++ {1, &oid_null_function}, //0xB2 ++ {1, &oid_null_function}, //0xB3 ++ {1, &oid_rt_get_key_mismatch_hdl}, //0xB4 ++ {1, &oid_null_function}, //0xB5 ++ {1, &oid_null_function}, //0xB6 ++ {1, &oid_null_function}, //0xB7 ++ {1, &oid_null_function}, //0xB8 ++ {1, &oid_null_function}, //0xB9 ++ {1, &oid_null_function}, //0xBA ++ {1, &oid_rt_supported_wireless_mode_hdl}, //0xBB ++ {1, &oid_rt_get_channel_list_hdl}, //0xBC ++ {1, &oid_rt_get_scan_in_progress_hdl}, //0xBD ++ {1, &oid_null_function}, //0xBE ++ {1, &oid_null_function}, //0xBF ++ {1, &oid_null_function}, //0xC0 ++ {1, &oid_rt_forced_data_rate_hdl}, //0xC1 ++ {1, &oid_rt_wireless_mode_for_scan_list_hdl}, //0xC2 ++ {1, &oid_rt_get_bss_wireless_mode_hdl}, //0xC3 ++ {1, &oid_rt_scan_with_magic_packet_hdl}, //0xC4 ++ {1, &oid_null_function}, //0xC5 ++ {1, &oid_null_function}, //0xC6 ++ {1, &oid_null_function}, //0xC7 ++ {1, &oid_null_function}, //0xC8 ++ {1, &oid_null_function}, //0xC9 ++ {1, &oid_null_function}, //0xCA ++ {1, &oid_null_function}, //0xCB ++ {1, &oid_null_function}, //0xCC ++ {1, &oid_null_function}, //0xCD ++ {1, &oid_null_function}, //0xCE ++ {1, &oid_null_function}, //0xCF ++ ++}; ++ ++struct oid_obj_priv oid_rtl_seg_01_03[] = ++{ ++ {1, &oid_rt_ap_get_associated_station_list_hdl}, //0x00 ++ {1, &oid_null_function}, //0x01 ++ {1, &oid_rt_ap_switch_into_ap_mode_hdl}, //0x02 ++ {1, &oid_null_function}, //0x03 ++ {1, &oid_rt_ap_supported_hdl}, //0x04 ++ {1, &oid_rt_ap_set_passphrase_hdl}, //0x05 ++ ++}; ++ ++struct oid_obj_priv oid_rtl_seg_01_11[] = ++{ ++ {1, &oid_null_function}, //0xC0 OID_RT_PRO_RX_FILTER ++ {1, &oid_null_function}, //0xC1 OID_CE_USB_WRITE_REGISTRY ++ {1, &oid_null_function}, //0xC2 OID_CE_USB_READ_REGISTRY ++ {1, &oid_null_function}, //0xC3 OID_RT_PRO_SET_INITIAL_GAIN ++ {1, &oid_null_function}, //0xC4 OID_RT_PRO_SET_BB_RF_STANDBY_MODE ++ {1, &oid_null_function}, //0xC5 OID_RT_PRO_SET_BB_RF_SHUTDOWN_MODE ++ {1, &oid_null_function}, //0xC6 OID_RT_PRO_SET_TX_CHARGE_PUMP ++ {1, &oid_null_function}, //0xC7 OID_RT_PRO_SET_RX_CHARGE_PUMP ++ {1, &oid_rt_pro_rf_write_registry_hdl}, //0xC8 ++ {1, &oid_rt_pro_rf_read_registry_hdl}, //0xC9 ++ {1, &oid_null_function} //0xCA OID_RT_PRO_QUERY_RF_TYPE ++ ++}; ++ ++struct oid_obj_priv oid_rtl_seg_03_00[] = ++{ ++ {1, &oid_null_function}, //0x00 ++ {1, &oid_rt_get_connect_state_hdl}, //0x01 ++ {1, &oid_null_function}, //0x02 ++ {1, &oid_null_function}, //0x03 ++ {1, &oid_rt_set_default_key_id_hdl}, //0x04 ++ ++ ++}; ++ ++ ++//************** oid_rtl_seg_01_01 section start ************** ++ ++NDIS_STATUS oid_rt_pro_set_fw_dig_state_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ _irqL oldirql; ++ ++ _func_enter_; ++ ++ if(poid_par_priv->type_of_oid != SET_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ _irqlevel_changed_(&oldirql,LOWER); ++ if(poid_par_priv->information_buf_len >= sizeof(struct setdig_parm)) ++ { ++ //DEBUG_ERR(("===> oid_rt_pro_set_fw_dig_state_hdl. type:0x%02x.\n",*((unsigned char*)poid_par_priv->information_buf ))); ++ if(!rtw_setfwdig_cmd(Adapter,*((unsigned char*)poid_par_priv->information_buf ))) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ } ++ ++ } ++ else{ ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ } ++ _irqlevel_changed_(&oldirql,RAISE); ++ _func_exit_; ++#endif ++ return status; ++} ++//----------------------------------------------------------------------------- ++NDIS_STATUS oid_rt_pro_set_fw_ra_state_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ _irqL oldirql; ++ ++ _func_enter_; ++ if(poid_par_priv->type_of_oid != SET_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ ++ _irqlevel_changed_(&oldirql,LOWER); ++ ++ if(poid_par_priv->information_buf_len >= sizeof(struct setra_parm)) ++ { ++ //DEBUG_ERR(("===> oid_rt_pro_set_fw_ra_state_hdl. type:0x%02x.\n",*((unsigned char*)poid_par_priv->information_buf ))); ++ if(!rtw_setfwra_cmd(Adapter,*((unsigned char*)poid_par_priv->information_buf ))) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ } ++ ++ } ++ else{ ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ } ++ _irqlevel_changed_(&oldirql,RAISE); ++ _func_exit_; ++#endif ++ return status; ++} ++//----------------------------------------------------------------------------- ++NDIS_STATUS oid_rt_get_signal_quality_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ //DEBUG_ERR(("<**********************oid_rt_get_signal_quality_hdl \n")); ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++#if 0 ++ if(pMgntInfo->mAssoc || pMgntInfo->mIbss) ++ { ++ ulInfo = pAdapter->RxStats.SignalQuality; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } ++ else ++ { ++ ulInfo = 0xffffffff; // It stands for -1 in 4-byte integer. ++ } ++ break; ++#endif ++ ++ return status; ++} ++ ++//------------------------------------------------------------------------------ ++ ++NDIS_STATUS oid_rt_get_small_packet_crc_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ if(poid_par_priv->information_buf_len >= sizeof(ULONG) ) ++ { ++ *(ULONG *)poid_par_priv->information_buf = padapter->recvpriv.rx_smallpacket_crcerr; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } ++ else ++ { ++ status = NDIS_STATUS_INVALID_LENGTH; ++ } ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_get_middle_packet_crc_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ if(poid_par_priv->information_buf_len >= sizeof(ULONG) ) ++ { ++ *(ULONG *)poid_par_priv->information_buf = padapter->recvpriv.rx_middlepacket_crcerr; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } ++ else ++ { ++ status = NDIS_STATUS_INVALID_LENGTH; ++ } ++ ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_get_large_packet_crc_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ if(poid_par_priv->information_buf_len >= sizeof(ULONG) ) ++ { ++ *(ULONG *)poid_par_priv->information_buf = padapter->recvpriv.rx_largepacket_crcerr; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } ++ else ++ { ++ status = NDIS_STATUS_INVALID_LENGTH; ++ } ++ ++ ++ return status; ++} ++ ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_get_tx_retry_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ return status; ++} ++NDIS_STATUS oid_rt_get_rx_retry_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_get_rx_total_packet_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ if(poid_par_priv->information_buf_len >= sizeof(ULONG) ) ++ { ++ *(u64 *)poid_par_priv->information_buf = padapter->recvpriv.rx_pkts + padapter->recvpriv.rx_drop; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } ++ else ++ { ++ status = NDIS_STATUS_INVALID_LENGTH; ++ } ++ ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_get_tx_beacon_ok_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ return status; ++} ++NDIS_STATUS oid_rt_get_tx_beacon_err_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_get_rx_icv_err_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ if(poid_par_priv->information_buf_len>= sizeof(u32)) ++ { ++ //_rtw_memcpy(*(uint *)poid_par_priv->information_buf,padapter->recvpriv.rx_icv_err,sizeof(u32)); ++ *(uint *)poid_par_priv->information_buf = padapter->recvpriv.rx_icv_err; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } ++ else ++ { ++ status = NDIS_STATUS_INVALID_LENGTH ; ++ } ++ ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_set_encryption_algorithm_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != SET_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_get_preamble_mode_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ULONG preamblemode = 0 ; ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ if(poid_par_priv->information_buf_len>= sizeof(ULONG)) ++ { ++ if(padapter->registrypriv.preamble == PREAMBLE_LONG) ++ preamblemode = 0; ++ else if (padapter->registrypriv.preamble == PREAMBLE_AUTO) ++ preamblemode = 1; ++ else if (padapter->registrypriv.preamble == PREAMBLE_SHORT) ++ preamblemode = 2; ++ ++ ++ *(ULONG *)poid_par_priv->information_buf = preamblemode ; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } ++ else ++ { ++ status = NDIS_STATUS_INVALID_LENGTH ; ++ } ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_get_ap_ip_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ return status; ++} ++ ++NDIS_STATUS oid_rt_get_channelplan_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ struct eeprom_priv* peeprompriv = &padapter->eeprompriv; ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ *(u16 *)poid_par_priv->information_buf = peeprompriv->channel_plan ; ++ ++ return status; ++} ++NDIS_STATUS oid_rt_set_channelplan_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ struct eeprom_priv* peeprompriv = &padapter->eeprompriv; ++ ++ if(poid_par_priv->type_of_oid != SET_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ peeprompriv->channel_plan = *(u16 *)poid_par_priv->information_buf ; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_set_preamble_mode_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ULONG preamblemode = 0; ++ if(poid_par_priv->type_of_oid != SET_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ if(poid_par_priv->information_buf_len>= sizeof(ULONG)) ++ { ++ preamblemode = *(ULONG *)poid_par_priv->information_buf ; ++ if( preamblemode == 0) ++ padapter->registrypriv.preamble = PREAMBLE_LONG; ++ else if (preamblemode==1 ) ++ padapter->registrypriv.preamble = PREAMBLE_AUTO; ++ else if ( preamblemode==2 ) ++ padapter->registrypriv.preamble = PREAMBLE_SHORT; ++ ++ *(ULONG *)poid_par_priv->information_buf = preamblemode ; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } ++ else ++ { ++ status = NDIS_STATUS_INVALID_LENGTH ; ++ } ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_set_bcn_intvl_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != SET_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ return status; ++} ++NDIS_STATUS oid_rt_dedicate_probe_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_get_total_tx_bytes_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ if(poid_par_priv->information_buf_len>= sizeof(ULONG)) ++ { ++ *(u64 *)poid_par_priv->information_buf = padapter->xmitpriv.tx_bytes; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } ++ else ++ { ++ status = NDIS_STATUS_INVALID_LENGTH ; ++ } ++ ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_get_total_rx_bytes_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ if(poid_par_priv->information_buf_len>= sizeof(ULONG)) ++ { ++ //_rtw_memcpy(*(uint *)poid_par_priv->information_buf,padapter->recvpriv.rx_icv_err,sizeof(u32)); ++ *(u64 *)poid_par_priv->information_buf = padapter->recvpriv.rx_bytes; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } ++ else ++ { ++ status = NDIS_STATUS_INVALID_LENGTH ; ++ } ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_current_tx_power_level_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ return status; ++} ++NDIS_STATUS oid_rt_get_enc_key_mismatch_count_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ return status; ++} ++NDIS_STATUS oid_rt_get_enc_key_match_count_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ return status; ++} ++NDIS_STATUS oid_rt_get_channel_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ NDIS_802_11_CONFIGURATION *pnic_Config; ++ ++ ULONG channelnum; ++ ++ _func_enter_; ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ if ( (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE)) ++ pnic_Config = &pmlmepriv->cur_network.network.Configuration; ++ else ++ pnic_Config = &padapter->registrypriv.dev_network.Configuration; ++ ++ channelnum = pnic_Config->DSConfig; ++ *(ULONG *)poid_par_priv->information_buf = channelnum; ++ ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ _func_exit_; ++ ++ ++ ++ return status; ++} ++NDIS_STATUS oid_rt_get_hardware_radio_off_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ return status; ++} ++NDIS_STATUS oid_rt_get_key_mismatch_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ return status; ++} ++NDIS_STATUS oid_rt_supported_wireless_mode_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ULONG ulInfo = 0 ; ++ //DEBUG_ERR(("<**********************oid_rt_supported_wireless_mode_hdl \n")); ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ if(poid_par_priv->information_buf_len >= sizeof(ULONG)){ ++ ulInfo |= 0x0100; //WIRELESS_MODE_B ++ ulInfo |= 0x0200; //WIRELESS_MODE_G ++ ulInfo |= 0x0400; //WIRELESS_MODE_A ++ ++ *(ULONG *) poid_par_priv->information_buf = ulInfo; ++ //DEBUG_ERR(("<===oid_rt_supported_wireless_mode %x\n",ulInfo)); ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } ++ else{ ++ status = NDIS_STATUS_INVALID_LENGTH; ++ } ++ ++ return status; ++} ++NDIS_STATUS oid_rt_get_channel_list_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ return status; ++} ++NDIS_STATUS oid_rt_get_scan_in_progress_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ return status; ++} ++ ++ ++NDIS_STATUS oid_rt_forced_data_rate_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ return status; ++} ++NDIS_STATUS oid_rt_wireless_mode_for_scan_list_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ return status; ++} ++NDIS_STATUS oid_rt_get_bss_wireless_mode_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ return status; ++} ++ ++NDIS_STATUS oid_rt_scan_with_magic_packet_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ return status; ++} ++//************** oid_rtl_seg_01_01 section end ************** ++ ++//************** oid_rtl_seg_01_03 section start ************** ++NDIS_STATUS oid_rt_ap_get_associated_station_list_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ return status; ++} ++NDIS_STATUS oid_rt_ap_switch_into_ap_mode_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ return status; ++} ++NDIS_STATUS oid_rt_ap_supported_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ return status; ++} ++NDIS_STATUS oid_rt_ap_set_passphrase_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != SET_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ return status; ++} ++ ++//************** oid_rtl_seg_01_03 section end ************** ++ ++//**************** oid_rtl_seg_01_11 section start **************** ++NDIS_STATUS oid_rt_pro_rf_write_registry_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ _irqL oldirql; ++ _func_enter_; ++ //DEBUG_ERR(("<**********************oid_rt_pro_rf_write_registry_hdl \n")); ++ if(poid_par_priv->type_of_oid != SET_OID) //QUERY_OID ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ _irqlevel_changed_(&oldirql,LOWER); ++ if(poid_par_priv->information_buf_len== (sizeof(unsigned long)*3)) ++ { ++ //RegOffsetValue - The offset of RF register to write. ++ //RegDataWidth - The data width of RF register to write. ++ //RegDataValue - The value to write. ++ //RegOffsetValue = *((unsigned long*)InformationBuffer); ++ //RegDataWidth = *((unsigned long*)InformationBuffer+1); ++ //RegDataValue = *((unsigned long*)InformationBuffer+2); ++ if(!rtw_setrfreg_cmd(Adapter, ++ *(unsigned char*)poid_par_priv->information_buf, ++ (unsigned long)(*((unsigned long*)poid_par_priv->information_buf+2)))) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ } ++ ++ } ++ else{ ++ status = NDIS_STATUS_INVALID_LENGTH; ++ } ++ _irqlevel_changed_(&oldirql,RAISE); ++ _func_exit_; ++ ++ return status; ++} ++ ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_rf_read_registry_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ _irqL oldirql; ++ _func_enter_; ++ ++ //DEBUG_ERR(("<**********************oid_rt_pro_rf_read_registry_hdl \n")); ++ if(poid_par_priv->type_of_oid != SET_OID) //QUERY_OID ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ _irqlevel_changed_(&oldirql,LOWER); ++ if(poid_par_priv->information_buf_len== (sizeof(unsigned long)*3)) ++ { ++ if(Adapter->mppriv.act_in_progress == _TRUE) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ } ++ else ++ { ++ //init workparam ++ Adapter->mppriv.act_in_progress = _TRUE; ++ Adapter->mppriv.workparam.bcompleted= _FALSE; ++ Adapter->mppriv.workparam.act_type = MPT_READ_RF; ++ Adapter->mppriv.workparam.io_offset = *(unsigned long*)poid_par_priv->information_buf; ++ Adapter->mppriv.workparam.io_value = 0xcccccccc; ++ ++ //RegOffsetValue - The offset of RF register to read. ++ //RegDataWidth - The data width of RF register to read. ++ //RegDataValue - The value to read. ++ //RegOffsetValue = *((unsigned long*)InformationBuffer); ++ //RegDataWidth = *((unsigned long*)InformationBuffer+1); ++ //RegDataValue = *((unsigned long*)InformationBuffer+2); ++ if(!rtw_getrfreg_cmd(Adapter, ++ *(unsigned char*)poid_par_priv->information_buf, ++ (unsigned char*)&Adapter->mppriv.workparam.io_value)) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ } ++ } ++ ++ ++ } ++ else { ++ status = NDIS_STATUS_INVALID_LENGTH; ++ } ++ _irqlevel_changed_(&oldirql,RAISE); ++ _func_exit_; ++#endif ++ return status; ++} ++ ++//**************** oid_rtl_seg_01_11 section end**************** ++ ++ ++//************** oid_rtl_seg_03_00 section start ************** ++enum _CONNECT_STATE_{ ++ CHECKINGSTATUS, ++ ASSOCIATED, ++ ADHOCMODE, ++ NOTASSOCIATED ++}; ++ ++NDIS_STATUS oid_rt_get_connect_state_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ ULONG ulInfo; ++ ++ if(poid_par_priv->type_of_oid != QUERY_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ // nStatus==0 CheckingStatus ++ // nStatus==1 Associated ++ // nStatus==2 AdHocMode ++ // nStatus==3 NotAssociated ++ ++ if(check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE) ++ ulInfo = CHECKINGSTATUS; ++ else if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ++ ulInfo = ASSOCIATED; ++ else if(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)== _TRUE) ++ ulInfo = ADHOCMODE; ++ else ++ ulInfo = NOTASSOCIATED ; ++ ++ *(ULONG *)poid_par_priv->information_buf = ulInfo; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++#if 0 ++ // Rearrange the order to let the UI still shows connection when scan is in progress ++ RT_TRACE(COMP_OID_QUERY, DBG_LOUD, ("===> Query OID_RT_GET_CONNECT_STATE.\n")); ++ if(pMgntInfo->mAssoc) ++ ulInfo = 1; ++ else if(pMgntInfo->mIbss) ++ ulInfo = 2; ++ else if(pMgntInfo->bScanInProgress) ++ ulInfo = 0; ++ else ++ ulInfo = 3; ++ ulInfoLen = sizeof(ULONG); ++ RT_TRACE(COMP_OID_QUERY, DBG_LOUD, ("<=== Query OID_RT_GET_CONNECT_STATE: %d\n", ulInfo)); ++#endif ++ ++ return status; ++} ++ ++NDIS_STATUS oid_rt_set_default_key_id_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ if(poid_par_priv->type_of_oid != SET_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ return status; ++} ++//************** oid_rtl_seg_03_00 section end ************** ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_ioctl_set.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_ioctl_set.c +new file mode 100644 +index 00000000..d2d07d7e +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_ioctl_set.c +@@ -0,0 +1,1486 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_IOCTL_SET_C_ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_USB_HCI ++#include ++#include ++#endif ++#ifdef CONFIG_SDIO_HCI ++#include ++#endif ++ ++#ifdef CONFIG_GSPI_HCI ++#include ++#endif ++ ++extern void indicate_wx_scan_complete_event(_adapter *padapter); ++ ++#define IS_MAC_ADDRESS_BROADCAST(addr) \ ++( \ ++ ( (addr[0] == 0xff) && (addr[1] == 0xff) && \ ++ (addr[2] == 0xff) && (addr[3] == 0xff) && \ ++ (addr[4] == 0xff) && (addr[5] == 0xff) ) ? _TRUE : _FALSE \ ++) ++ ++u8 rtw_validate_bssid(u8 *bssid) ++{ ++ u8 ret = _TRUE; ++ ++ if (is_zero_mac_addr(bssid) ++ || is_broadcast_mac_addr(bssid) ++ || is_multicast_mac_addr(bssid) ++ ) { ++ ret = _FALSE; ++ } ++ ++ return ret; ++} ++ ++u8 rtw_validate_ssid(NDIS_802_11_SSID *ssid) ++{ ++ u8 i; ++ u8 ret=_TRUE; ++ ++_func_enter_; ++ ++ if (ssid->SsidLength > 32) { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("ssid length >32\n")); ++ ret= _FALSE; ++ goto exit; ++ } ++ ++#ifdef CONFIG_VALIDATE_SSID ++ for(i = 0; i < ssid->SsidLength; i++) ++ { ++ //wifi, printable ascii code must be supported ++ if(!( (ssid->Ssid[i] >= 0x20) && (ssid->Ssid[i] <= 0x7e) )){ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("ssid has nonprintabl ascii\n")); ++ ret= _FALSE; ++ break; ++ } ++ } ++#endif /* CONFIG_VALIDATE_SSID */ ++ ++exit: ++ ++_func_exit_; ++ ++ return ret; ++} ++ ++u8 rtw_do_join(_adapter * padapter); ++u8 rtw_do_join(_adapter * padapter) ++{ ++ _irqL irqL; ++ _list *plist, *phead; ++ u8* pibss = NULL; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ u8 ret=_SUCCESS; ++ ++_func_enter_; ++ ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("\n rtw_do_join: phead = %p; plist = %p \n\n\n", phead, plist)); ++ ++ pmlmepriv->cur_network.join_res = -2; ++ ++ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); ++ ++ pmlmepriv->pscanned = plist; ++ ++ pmlmepriv->to_join = _TRUE; ++ ++ if(_rtw_queue_empty(queue)== _TRUE) ++ { ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ ++ //when set_ssid/set_bssid for rtw_do_join(), but scanning queue is empty ++ //we try to issue sitesurvey firstly ++ ++ if (pmlmepriv->LinkDetectInfo.bBusyTraffic ==_FALSE ++ || rtw_to_roaming(padapter) > 0 ++ ) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("rtw_do_join(): site survey if scanned_queue is empty\n.")); ++ // submit site_survey_cmd ++ if(_SUCCESS!=(ret=rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0)) ) { ++ pmlmepriv->to_join = _FALSE; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("rtw_do_join(): site survey return error\n.")); ++ } ++ } ++ else ++ { ++ pmlmepriv->to_join = _FALSE; ++ ret = _FAIL; ++ } ++ ++ goto exit; ++ } ++ else ++ { ++ int select_ret; ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ if((select_ret=rtw_select_and_join_from_scanned_queue(pmlmepriv))==_SUCCESS) ++ { ++ pmlmepriv->to_join = _FALSE; ++ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); ++ } ++ else ++ { ++ if(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)==_TRUE) ++ { ++ // submit createbss_cmd to change to a ADHOC_MASTER ++ ++ //pmlmepriv->lock has been acquired by caller... ++ WLAN_BSSID_EX *pdev_network = &(padapter->registrypriv.dev_network); ++ ++ pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; ++ ++ pibss = padapter->registrypriv.dev_network.MacAddress; ++ ++ _rtw_memset(&pdev_network->Ssid, 0, sizeof(NDIS_802_11_SSID)); ++ _rtw_memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(NDIS_802_11_SSID)); ++ ++ rtw_update_registrypriv_dev_network(padapter); ++ ++ rtw_generate_random_ibss(pibss); ++ ++ if(rtw_createbss_cmd(padapter)!=_SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("***Error=>do_goin: rtw_createbss_cmd status FAIL*** \n ")); ++ ret = _FALSE; ++ goto exit; ++ } ++ ++ pmlmepriv->to_join = _FALSE; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("***Error=> rtw_select_and_join_from_scanned_queue FAIL under STA_Mode*** \n ")); ++ ++ } ++ else ++ { ++ // can't associate ; reset under-linking ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ ++#if 0 ++ if((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE)) ++ { ++ if(_rtw_memcmp(pmlmepriv->cur_network.network.Ssid.Ssid, pmlmepriv->assoc_ssid.Ssid, pmlmepriv->assoc_ssid.SsidLength)) ++ { ++ // for funk to do roaming ++ // funk will reconnect, but funk will not sitesurvey before reconnect ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("for funk to do roaming")); ++ if(pmlmepriv->sitesurveyctrl.traffic_busy==_FALSE) ++ rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0); ++ } ++ ++ } ++#endif ++ ++ //when set_ssid/set_bssid for rtw_do_join(), but there are no desired bss in scanning queue ++ //we try to issue sitesurvey firstly ++ if(pmlmepriv->LinkDetectInfo.bBusyTraffic==_FALSE ++ || rtw_to_roaming(padapter) > 0 ++ ) ++ { ++ //DBG_871X("rtw_do_join() when no desired bss in scanning queue \n"); ++ if( _SUCCESS!=(ret=rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0)) ){ ++ pmlmepriv->to_join = _FALSE; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("do_join(): site survey return error\n.")); ++ } ++ } ++ else ++ { ++ ret = _FAIL; ++ pmlmepriv->to_join = _FALSE; ++ } ++ } ++ ++ } ++ ++ } ++ ++exit: ++ ++_func_exit_; ++ ++ return ret; ++} ++ ++#ifdef PLATFORM_WINDOWS ++u8 rtw_pnp_set_power_wakeup(_adapter* padapter) ++{ ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("==>rtw_pnp_set_power_wakeup!!!\n")); ++ ++ res = rtw_setstandby_cmd(padapter, 0); ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("<==rtw_pnp_set_power_wakeup!!!\n")); ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtw_pnp_set_power_sleep(_adapter* padapter) ++{ ++ u8 res=_SUCCESS; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("==>rtw_pnp_set_power_sleep!!!\n")); ++ //DbgPrint("+rtw_pnp_set_power_sleep\n"); ++ ++ res = rtw_setstandby_cmd(padapter, 1); ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("<==rtw_pnp_set_power_sleep!!!\n")); ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtw_set_802_11_reload_defaults(_adapter * padapter, NDIS_802_11_RELOAD_DEFAULTS reloadDefaults) ++{ ++_func_enter_; ++ ++ switch( reloadDefaults) ++ { ++ case Ndis802_11ReloadWEPKeys: ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("SetInfo OID_802_11_RELOAD_DEFAULTS : Ndis802_11ReloadWEPKeys\n")); ++ break; ++ } ++ ++ // SecClearAllKeys(Adapter); ++ // 8711 CAM was not for En/Decrypt only ++ // so, we can't clear all keys. ++ // should we disable WPAcfg (ox0088) bit 1-2, instead of clear all CAM ++ ++ //TO DO... ++ ++_func_exit_; ++ ++ return _TRUE; ++} ++ ++u8 set_802_11_test(_adapter* padapter, NDIS_802_11_TEST *test) ++{ ++ u8 ret=_TRUE; ++ ++_func_enter_; ++ ++ switch(test->Type) ++ { ++ case 1: ++ NdisMIndicateStatus(padapter->hndis_adapter, NDIS_STATUS_MEDIA_SPECIFIC_INDICATION, (PVOID)&test->AuthenticationEvent, test->Length - 8); ++ NdisMIndicateStatusComplete(padapter->hndis_adapter); ++ break; ++ ++ case 2: ++ NdisMIndicateStatus(padapter->hndis_adapter, NDIS_STATUS_MEDIA_SPECIFIC_INDICATION, (PVOID)&test->RssiTrigger, sizeof(NDIS_802_11_RSSI)); ++ NdisMIndicateStatusComplete(padapter->hndis_adapter); ++ break; ++ ++ default: ++ ret=_FALSE; ++ break; ++ } ++ ++_func_exit_; ++ ++ return ret; ++} ++ ++u8 rtw_set_802_11_pmkid(_adapter* padapter, NDIS_802_11_PMKID *pmkid) ++{ ++ u8 ret=_SUCCESS; ++ ++ return ret; ++} ++ ++#endif ++ ++u8 rtw_set_802_11_bssid(_adapter* padapter, u8 *bssid) ++{ ++ _irqL irqL; ++ u8 status=_SUCCESS; ++ u32 cur_time = 0; ++ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++_func_enter_; ++ ++ DBG_871X_LEVEL(_drv_always_, "set bssid:%pM\n", bssid); ++ ++ if ((bssid[0]==0x00 && bssid[1]==0x00 && bssid[2]==0x00 && bssid[3]==0x00 && bssid[4]==0x00 &&bssid[5]==0x00) || ++ (bssid[0]==0xFF && bssid[1]==0xFF && bssid[2]==0xFF && bssid[3]==0xFF && bssid[4]==0xFF &&bssid[5]==0xFF)) ++ { ++ status = _FAIL; ++ goto exit; ++ } ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ ++ DBG_871X("Set BSSID under fw_state=0x%08x\n", get_fwstate(pmlmepriv)); ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) { ++ goto handle_tkip_countermeasure; ++ } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE) { ++ goto release_mlme_lock; ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == _TRUE) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_bssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n")); ++ ++ if (_rtw_memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, ETH_ALEN) == _TRUE) ++ { ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _FALSE) ++ goto release_mlme_lock;//it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. ++ } else { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("Set BSSID not the same bssid\n")); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("set_bssid="MAC_FMT"\n", MAC_ARG(bssid) )); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("cur_bssid="MAC_FMT"\n", MAC_ARG(pmlmepriv->cur_network.network.MacAddress) )); ++ ++ rtw_disassoc_cmd(padapter, 0, _TRUE); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ++ rtw_indicate_disconnect(padapter); ++ ++ rtw_free_assoc_resources(padapter, 1); ++ ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE)) { ++ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); ++ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); ++ } ++ } ++ } ++ ++handle_tkip_countermeasure: ++ if (rtw_handle_tkip_countermeasure(padapter, __func__) == _FAIL) { ++ status = _FAIL; ++ goto release_mlme_lock; ++ } ++ ++ _rtw_memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN); ++ pmlmepriv->assoc_by_bssid=_TRUE; ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) { ++ pmlmepriv->to_join = _TRUE; ++ } ++ else { ++ status = rtw_do_join(padapter); ++ } ++ ++release_mlme_lock: ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++exit: ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ++ ("rtw_set_802_11_bssid: status=%d\n", status)); ++ ++_func_exit_; ++ ++ return status; ++} ++ ++u8 rtw_set_802_11_ssid(_adapter* padapter, NDIS_802_11_SSID *ssid) ++{ ++ _irqL irqL; ++ u8 status = _SUCCESS; ++ u32 cur_time = 0; ++ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *pnetwork = &pmlmepriv->cur_network; ++ ++_func_enter_; ++ ++ DBG_871X_LEVEL(_drv_always_, "set ssid [%s] fw_state=0x%08x\n", ++ ssid->Ssid, get_fwstate(pmlmepriv)); ++ ++ if(padapter->hw_init_completed==_FALSE){ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ++ ("set_ssid: hw_init_completed==_FALSE=>exit!!!\n")); ++ status = _FAIL; ++ goto exit; ++ } ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ DBG_871X("Set SSID under fw_state=0x%08x\n", get_fwstate(pmlmepriv)); ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) { ++ goto handle_tkip_countermeasure; ++ } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE) { ++ goto release_mlme_lock; ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == _TRUE) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ++ ("set_ssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n")); ++ ++ if ((pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength) && ++ (_rtw_memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, ssid->SsidLength) == _TRUE)) ++ { ++ if((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _FALSE)) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ++ ("Set SSID is the same ssid, fw_state=0x%08x\n", ++ get_fwstate(pmlmepriv))); ++ ++ if(rtw_is_same_ibss(padapter, pnetwork) == _FALSE) ++ { ++ //if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again ++ rtw_disassoc_cmd(padapter, 0, _TRUE); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ++ rtw_indicate_disconnect(padapter); ++ ++ rtw_free_assoc_resources(padapter, 1); ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) { ++ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); ++ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); ++ } ++ } ++ else ++ { ++ goto release_mlme_lock;//it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. ++ } ++ } ++#ifdef CONFIG_LPS ++ else { ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_JOINBSS, 1); ++ } ++#endif ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("Set SSID not the same ssid\n")); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("set_ssid=[%s] len=0x%x\n", ssid->Ssid, (unsigned int)ssid->SsidLength)); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("assoc_ssid=[%s] len=0x%x\n", pmlmepriv->assoc_ssid.Ssid, (unsigned int)pmlmepriv->assoc_ssid.SsidLength)); ++ ++ rtw_disassoc_cmd(padapter, 0, _TRUE); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ++ rtw_indicate_disconnect(padapter); ++ ++ rtw_free_assoc_resources(padapter, 1); ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) { ++ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); ++ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); ++ } ++ } ++ } ++ ++handle_tkip_countermeasure: ++ if (rtw_handle_tkip_countermeasure(padapter, __func__) == _FAIL) { ++ status = _FAIL; ++ goto release_mlme_lock; ++ } ++ ++ if (rtw_validate_ssid(ssid) == _FALSE) { ++ status = _FAIL; ++ goto release_mlme_lock; ++ } ++ ++ _rtw_memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(NDIS_802_11_SSID)); ++ pmlmepriv->assoc_by_bssid=_FALSE; ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) { ++ pmlmepriv->to_join = _TRUE; ++ } ++ else { ++ status = rtw_do_join(padapter); ++ } ++ ++release_mlme_lock: ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++exit: ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ++ ("-rtw_set_802_11_ssid: status=%d\n", status)); ++ ++_func_exit_; ++ ++ return status; ++ ++} ++ ++u8 rtw_set_802_11_connect(_adapter* padapter, u8 *bssid, NDIS_802_11_SSID *ssid) ++{ ++ _irqL irqL; ++ u8 status = _SUCCESS; ++ u32 cur_time = 0; ++ bool bssid_valid = _TRUE; ++ bool ssid_valid = _TRUE; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++_func_enter_; ++ ++ if (!ssid || rtw_validate_ssid(ssid) == _FALSE) ++ ssid_valid = _FALSE; ++ ++ if (!bssid || rtw_validate_bssid(bssid) == _FALSE) ++ bssid_valid = _FALSE; ++ ++ if (ssid_valid == _FALSE && bssid_valid == _FALSE) { ++ DBG_871X(FUNC_ADPT_FMT" ssid:%p, ssid_valid:%d, bssid:%p, bssid_valid:%d\n", ++ FUNC_ADPT_ARG(padapter), ssid, ssid_valid, bssid, bssid_valid); ++ status = _FAIL; ++ goto exit; ++ } ++ ++ if(padapter->hw_init_completed==_FALSE){ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ++ ("set_ssid: hw_init_completed==_FALSE=>exit!!!\n")); ++ status = _FAIL; ++ goto exit; ++ } ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" fw_state=0x%08x\n", ++ FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv)); ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) { ++ goto handle_tkip_countermeasure; ++ } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE) { ++ goto release_mlme_lock; ++ } ++ ++handle_tkip_countermeasure: ++ if (rtw_handle_tkip_countermeasure(padapter, __func__) == _FAIL) { ++ status = _FAIL; ++ goto release_mlme_lock; ++ } ++ ++ if (ssid && ssid_valid) ++ _rtw_memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(NDIS_802_11_SSID)); ++ ++ if (bssid && bssid_valid) { ++ _rtw_memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN); ++ pmlmepriv->assoc_by_bssid = _TRUE; ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) { ++ pmlmepriv->to_join = _TRUE; ++ } ++ else { ++ status = rtw_do_join(padapter); ++ } ++ ++release_mlme_lock: ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++exit: ++ ++_func_exit_; ++ ++ return status; ++} ++ ++u8 rtw_set_802_11_infrastructure_mode(_adapter* padapter, ++ NDIS_802_11_NETWORK_INFRASTRUCTURE networktype) ++{ ++ _irqL irqL; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *cur_network = &pmlmepriv->cur_network; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE* pold_state = &(cur_network->network.InfrastructureMode); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_notice_, ++ ("+rtw_set_802_11_infrastructure_mode: old=%d new=%d fw_state=0x%08x\n", ++ *pold_state, networktype, get_fwstate(pmlmepriv))); ++ ++ if(*pold_state != networktype) ++ { ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,(" change mode!")); ++ //DBG_871X("change mode, old_mode=%d, new_mode=%d, fw_state=0x%x\n", *pold_state, networktype, get_fwstate(pmlmepriv)); ++ ++ if(*pold_state==Ndis802_11APMode) ++ { ++ //change to other mode from Ndis802_11APMode ++ cur_network->join_res = -1; ++ ++#ifdef CONFIG_NATIVEAP_MLME ++ stop_ap_mode(padapter); ++#endif ++ } ++ ++ if((check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE) ||(*pold_state==Ndis802_11IBSS)) ++ rtw_disassoc_cmd(padapter, 0, _TRUE); ++ ++ if((check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)== _TRUE) ) ++ rtw_free_assoc_resources(padapter, 1); ++ ++ if((*pold_state == Ndis802_11Infrastructure) ||(*pold_state == Ndis802_11IBSS)) ++ { ++ if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ++ { ++ rtw_indicate_disconnect(padapter); //will clr Linked_state; before this function, we must have chked whether issue dis-assoc_cmd or not ++ } ++ } ++ ++ *pold_state = networktype; ++ ++ _clr_fwstate_(pmlmepriv, ~WIFI_NULL_STATE); ++ ++ switch(networktype) ++ { ++ case Ndis802_11IBSS: ++ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); ++ break; ++ ++ case Ndis802_11Infrastructure: ++ set_fwstate(pmlmepriv, WIFI_STATION_STATE); ++ break; ++ ++ case Ndis802_11APMode: ++ set_fwstate(pmlmepriv, WIFI_AP_STATE); ++#ifdef CONFIG_NATIVEAP_MLME ++ start_ap_mode(padapter); ++ //rtw_indicate_connect(padapter); ++#endif ++ ++ break; ++ ++ case Ndis802_11AutoUnknown: ++ case Ndis802_11InfrastructureMax: ++ break; ++ } ++ ++ //SecClearAllKeys(adapter); ++ ++ //RT_TRACE(COMP_OID_SET, DBG_LOUD, ("set_infrastructure: fw_state:%x after changing mode\n", ++ // get_fwstate(pmlmepriv) )); ++ ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ } ++ ++_func_exit_; ++ ++ return _TRUE; ++} ++ ++ ++u8 rtw_set_802_11_disassociate(_adapter *padapter) ++{ ++ _irqL irqL; ++ struct mlme_priv * pmlmepriv = &padapter->mlmepriv; ++ ++_func_enter_; ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("MgntActrtw_set_802_11_disassociate: rtw_indicate_disconnect\n")); ++ ++ rtw_disassoc_cmd(padapter, 0, _TRUE); ++ rtw_indicate_disconnect(padapter); ++ //modify for CONFIG_IEEE80211W, none 11w can use it ++ rtw_free_assoc_resources_cmd(padapter); ++ rtw_pwr_wakeup(padapter); ++ } ++ ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++_func_exit_; ++ ++ return _TRUE; ++} ++ ++u8 rtw_set_802_11_bssid_list_scan(_adapter* padapter, NDIS_802_11_SSID *pssid, int ssid_max_num) ++{ ++ _irqL irqL; ++ struct mlme_priv *pmlmepriv= &padapter->mlmepriv; ++ u8 res=_TRUE; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("+rtw_set_802_11_bssid_list_scan(), fw_state=%x\n", get_fwstate(pmlmepriv))); ++ ++ if (padapter == NULL) { ++ res=_FALSE; ++ goto exit; ++ } ++ if (padapter->hw_init_completed==_FALSE){ ++ res = _FALSE; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("\n===rtw_set_802_11_bssid_list_scan:hw_init_completed==_FALSE===\n")); ++ goto exit; ++ } ++ ++ if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE) || ++ (pmlmepriv->LinkDetectInfo.bBusyTraffic == _TRUE)) ++ { ++ // Scan or linking is in progress, do nothing. ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("rtw_set_802_11_bssid_list_scan fail since fw_state = %x\n", get_fwstate(pmlmepriv))); ++ res = _TRUE; ++ ++ if(check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING))== _TRUE){ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("\n###_FW_UNDER_SURVEY|_FW_UNDER_LINKING\n\n")); ++ } else { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("\n###pmlmepriv->sitesurveyctrl.traffic_busy==_TRUE\n\n")); ++ } ++ } else { ++ if (rtw_is_scan_deny(padapter)) { ++ DBG_871X(FUNC_ADPT_FMT": scan deny\n", FUNC_ADPT_ARG(padapter)); ++ indicate_wx_scan_complete_event(padapter); ++ return _SUCCESS; ++ } ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ res = rtw_sitesurvey_cmd(padapter, pssid, ssid_max_num, NULL, 0); ++ ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ } ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtw_set_802_11_authentication_mode(_adapter* padapter, NDIS_802_11_AUTHENTICATION_MODE authmode) ++{ ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ int res; ++ u8 ret; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("set_802_11_auth.mode(): mode=%x\n", authmode)); ++ ++ psecuritypriv->ndisauthtype=authmode; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("rtw_set_802_11_authentication_mode:psecuritypriv->ndisauthtype=%d", psecuritypriv->ndisauthtype)); ++ ++ if(psecuritypriv->ndisauthtype>3) ++ psecuritypriv->dot11AuthAlgrthm=dot11AuthAlgrthm_8021X; ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ if(psecuritypriv->ndisauthtype == 6) ++ psecuritypriv->dot11AuthAlgrthm=dot11AuthAlgrthm_WAPI; ++#endif ++ ++ res=rtw_set_auth(padapter,psecuritypriv); ++ ++ if(res==_SUCCESS) ++ ret=_TRUE; ++ else ++ ret=_FALSE; ++ ++_func_exit_; ++ ++ return ret; ++} ++ ++u8 rtw_set_802_11_add_wep(_adapter* padapter, NDIS_802_11_WEP *wep){ ++ ++ u8 bdefaultkey; ++ u8 btransmitkey; ++ sint keyid,res; ++ struct security_priv* psecuritypriv=&(padapter->securitypriv); ++ u8 ret=_SUCCESS; ++ ++_func_enter_; ++ ++ bdefaultkey=(wep->KeyIndex & 0x40000000) > 0 ? _FALSE : _TRUE; //for ??? ++ btransmitkey= (wep->KeyIndex & 0x80000000) > 0 ? _TRUE : _FALSE; //for ??? ++ keyid=wep->KeyIndex & 0x3fffffff; ++ ++ if(keyid>4) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("MgntActrtw_set_802_11_add_wep:keyid>4=>fail\n")); ++ ret=_FALSE; ++ goto exit; ++ } ++ ++ switch(wep->KeyLength) ++ { ++ case 5: ++ psecuritypriv->dot11PrivacyAlgrthm=_WEP40_; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("MgntActrtw_set_802_11_add_wep:wep->KeyLength=5\n")); ++ break; ++ case 13: ++ psecuritypriv->dot11PrivacyAlgrthm=_WEP104_; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("MgntActrtw_set_802_11_add_wep:wep->KeyLength=13\n")); ++ break; ++ default: ++ psecuritypriv->dot11PrivacyAlgrthm=_NO_PRIVACY_; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("MgntActrtw_set_802_11_add_wep:wep->KeyLength!=5 or 13\n")); ++ break; ++ } ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("rtw_set_802_11_add_wep:befor memcpy, wep->KeyLength=0x%x wep->KeyIndex=0x%x keyid =%x\n",wep->KeyLength,wep->KeyIndex,keyid)); ++ ++ _rtw_memcpy(&(psecuritypriv->dot11DefKey[keyid].skey[0]),&(wep->KeyMaterial),wep->KeyLength); ++ ++ psecuritypriv->dot11DefKeylen[keyid]=wep->KeyLength; ++ ++ psecuritypriv->dot11PrivacyKeyIndex=keyid; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("rtw_set_802_11_add_wep:security key material : %x %x %x %x %x %x %x %x %x %x %x %x %x \n", ++ psecuritypriv->dot11DefKey[keyid].skey[0],psecuritypriv->dot11DefKey[keyid].skey[1],psecuritypriv->dot11DefKey[keyid].skey[2], ++ psecuritypriv->dot11DefKey[keyid].skey[3],psecuritypriv->dot11DefKey[keyid].skey[4],psecuritypriv->dot11DefKey[keyid].skey[5], ++ psecuritypriv->dot11DefKey[keyid].skey[6],psecuritypriv->dot11DefKey[keyid].skey[7],psecuritypriv->dot11DefKey[keyid].skey[8], ++ psecuritypriv->dot11DefKey[keyid].skey[9],psecuritypriv->dot11DefKey[keyid].skey[10],psecuritypriv->dot11DefKey[keyid].skey[11], ++ psecuritypriv->dot11DefKey[keyid].skey[12])); ++ ++ res=rtw_set_key(padapter,psecuritypriv, keyid, 1,_TRUE); ++ ++ if(res==_FAIL) ++ ret= _FALSE; ++exit: ++ ++_func_exit_; ++ ++ return ret; ++ ++} ++ ++u8 rtw_set_802_11_remove_wep(_adapter* padapter, u32 keyindex){ ++ ++ u8 ret=_SUCCESS; ++ ++_func_enter_; ++ ++ if (keyindex >= 0x80000000 || padapter == NULL){ ++ ++ ret=_FALSE; ++ goto exit; ++ ++ } ++ else ++ { ++ int res; ++ struct security_priv* psecuritypriv=&(padapter->securitypriv); ++ if( keyindex < 4 ){ ++ ++ _rtw_memset(&psecuritypriv->dot11DefKey[keyindex], 0, 16); ++ ++ res=rtw_set_key(padapter,psecuritypriv,keyindex, 0,_TRUE); ++ ++ psecuritypriv->dot11DefKeylen[keyindex]=0; ++ ++ if(res==_FAIL) ++ ret=_FAIL; ++ ++ } ++ else ++ { ++ ret=_FAIL; ++ } ++ ++ } ++ ++exit: ++ ++_func_exit_; ++ ++ return ret; ++ ++} ++ ++u8 rtw_set_802_11_add_key(_adapter* padapter, NDIS_802_11_KEY *key){ ++ ++ uint encryptionalgo; ++ u8 * pbssid; ++ struct sta_info *stainfo; ++ u8 bgroup = _FALSE; ++ u8 bgrouptkey = _FALSE;//can be remove later ++ u8 ret=_SUCCESS; ++ ++_func_enter_; ++ ++ if (((key->KeyIndex & 0x80000000) == 0) && ((key->KeyIndex & 0x40000000) > 0)){ ++ ++ // It is invalid to clear bit 31 and set bit 30. If the miniport driver encounters this combination, ++ // it must fail the request and return NDIS_STATUS_INVALID_DATA. ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("rtw_set_802_11_add_key: ((key->KeyIndex & 0x80000000) == 0)[=%d] ",(int)(key->KeyIndex & 0x80000000) == 0)); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("rtw_set_802_11_add_key:((key->KeyIndex & 0x40000000) > 0)[=%d]" , (int)(key->KeyIndex & 0x40000000) > 0)); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_info_,("rtw_set_802_11_add_key: key->KeyIndex=%d \n" ,(int)key->KeyIndex)); ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ if(key->KeyIndex & 0x40000000) ++ { ++ // Pairwise key ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("OID_802_11_ADD_KEY: +++++ Pairwise key +++++\n")); ++ ++ pbssid=get_bssid(&padapter->mlmepriv); ++ stainfo=rtw_get_stainfo(&padapter->stapriv, pbssid); ++ ++ if((stainfo!=NULL)&&(padapter->securitypriv.dot11AuthAlgrthm==dot11AuthAlgrthm_8021X)){ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("OID_802_11_ADD_KEY:( stainfo!=NULL)&&(Adapter->securitypriv.dot11AuthAlgrthm==dot11AuthAlgrthm_8021X)\n")); ++ encryptionalgo=stainfo->dot118021XPrivacy; ++ } ++ else{ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("OID_802_11_ADD_KEY: stainfo==NULL)||(Adapter->securitypriv.dot11AuthAlgrthm!=dot11AuthAlgrthm_8021X)\n")); ++ encryptionalgo=padapter->securitypriv.dot11PrivacyAlgrthm; ++ } ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("rtw_set_802_11_add_key: (encryptionalgo ==%d)!\n",encryptionalgo )); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("rtw_set_802_11_add_key: (Adapter->securitypriv.dot11PrivacyAlgrthm ==%d)!\n",padapter->securitypriv.dot11PrivacyAlgrthm)); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("rtw_set_802_11_add_key: (Adapter->securitypriv.dot11AuthAlgrthm ==%d)!\n",padapter->securitypriv.dot11AuthAlgrthm)); ++ ++ if((stainfo!=NULL)){ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("rtw_set_802_11_add_key: (stainfo->dot118021XPrivacy ==%d)!\n", stainfo->dot118021XPrivacy)); ++ } ++ ++ if(key->KeyIndex & 0x000000FF){ ++ // The key index is specified in the lower 8 bits by values of zero to 255. ++ // The key index should be set to zero for a Pairwise key, and the driver should fail with ++ // NDIS_STATUS_INVALID_DATA if the lower 8 bits is not zero ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,(" key->KeyIndex & 0x000000FF.\n")); ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ // check BSSID ++ if (IS_MAC_ADDRESS_BROADCAST(key->BSSID) == _TRUE){ ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("MacAddr_isBcst(key->BSSID)\n")); ++ ret= _FALSE; ++ goto exit; ++ } ++ ++ // Check key length for TKIP. ++ //if(encryptionAlgorithm == RT_ENC_TKIP_ENCRYPTION && key->KeyLength != 32) ++ if((encryptionalgo== _TKIP_)&& (key->KeyLength != 32)){ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("TKIP KeyLength:0x%x != 32\n", key->KeyLength)); ++ ret=_FAIL; ++ goto exit; ++ ++ } ++ ++ // Check key length for AES. ++ if((encryptionalgo== _AES_)&& (key->KeyLength != 16)) { ++ // For our supplicant, EAPPkt9x.vxd, cannot differentiate TKIP and AES case. ++ if(key->KeyLength == 32) { ++ key->KeyLength = 16; ++ } else { ++ ret= _FAIL; ++ goto exit; ++ } ++ } ++ ++ // Check key length for WEP. For NDTEST, 2005.01.27, by rcnjko. ++ if( (encryptionalgo== _WEP40_|| encryptionalgo== _WEP104_) && (key->KeyLength != 5 || key->KeyLength != 13)) { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("WEP KeyLength:0x%x != 5 or 13\n", key->KeyLength)); ++ ret=_FAIL; ++ goto exit; ++ } ++ ++ bgroup = _FALSE; ++ ++ // Check the pairwise key. Added by Annie, 2005-07-06. ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("------------------------------------------\n")); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("[Pairwise Key set]\n")); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("------------------------------------------\n")); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("key index: 0x%8x(0x%8x)\n", key->KeyIndex,(key->KeyIndex&0x3))); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("key Length: %d\n", key->KeyLength)); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("------------------------------------------\n")); ++ ++ } ++ else ++ { ++ // Group key - KeyIndex(BIT30==0) ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("OID_802_11_ADD_KEY: +++++ Group key +++++\n")); ++ ++ ++ // when add wep key through add key and didn't assigned encryption type before ++ if((padapter->securitypriv.ndisauthtype<=3)&&(padapter->securitypriv.dot118021XGrpPrivacy==0)) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("keylen=%d( Adapter->securitypriv.dot11PrivacyAlgrthm=%x )padapter->securitypriv.dot118021XGrpPrivacy(%x)\n", key->KeyLength,padapter->securitypriv.dot11PrivacyAlgrthm,padapter->securitypriv.dot118021XGrpPrivacy)); ++ ++ switch(key->KeyLength) ++ { ++ case 5: ++ padapter->securitypriv.dot11PrivacyAlgrthm=_WEP40_; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("Adapter->securitypriv.dot11PrivacyAlgrthm= %x key->KeyLength=%u\n", padapter->securitypriv.dot11PrivacyAlgrthm,key->KeyLength)); ++ break; ++ case 13: ++ padapter->securitypriv.dot11PrivacyAlgrthm=_WEP104_; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("Adapter->securitypriv.dot11PrivacyAlgrthm= %x key->KeyLength=%u\n", padapter->securitypriv.dot11PrivacyAlgrthm,key->KeyLength)); ++ break; ++ default: ++ padapter->securitypriv.dot11PrivacyAlgrthm=_NO_PRIVACY_; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("Adapter->securitypriv.dot11PrivacyAlgrthm= %x key->KeyLength=%u \n", padapter->securitypriv.dot11PrivacyAlgrthm,key->KeyLength)); ++ break; ++ } ++ ++ encryptionalgo=padapter->securitypriv.dot11PrivacyAlgrthm; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,(" Adapter->securitypriv.dot11PrivacyAlgrthm=%x\n", padapter->securitypriv.dot11PrivacyAlgrthm)); ++ ++ } ++ else ++ { ++ encryptionalgo=padapter->securitypriv.dot118021XGrpPrivacy; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("( Adapter->securitypriv.dot11PrivacyAlgrthm=%x )encryptionalgo(%x)=padapter->securitypriv.dot118021XGrpPrivacy(%x)keylen=%d\n", padapter->securitypriv.dot11PrivacyAlgrthm,encryptionalgo,padapter->securitypriv.dot118021XGrpPrivacy,key->KeyLength)); ++ ++ } ++ ++ if((check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE)==_TRUE) && (IS_MAC_ADDRESS_BROADCAST(key->BSSID) == _FALSE)) { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,(" IBSS but BSSID is not Broadcast Address.\n")); ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ // Check key length for TKIP ++ if((encryptionalgo== _TKIP_) && (key->KeyLength != 32)) { ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,(" TKIP GTK KeyLength:%u != 32\n", key->KeyLength)); ++ ret= _FAIL; ++ goto exit; ++ ++ } else if(encryptionalgo== _AES_ && (key->KeyLength != 16 && key->KeyLength != 32) ) { ++ ++ // Check key length for AES ++ // For NDTEST, we allow keylen=32 in this case. 2005.01.27, by rcnjko. ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("<=== SetInfo, OID_802_11_ADD_KEY: AES GTK KeyLength:%u != 16 or 32\n", key->KeyLength)); ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ // Change the key length for EAPPkt9x.vxd. Added by Annie, 2005-11-03. ++ if((encryptionalgo== _AES_) && (key->KeyLength == 32) ) { ++ key->KeyLength = 16; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("AES key length changed: %u\n", key->KeyLength) ); ++ } ++ ++ if(key->KeyIndex & 0x8000000) {//error ??? 0x8000_0000 ++ bgrouptkey = _TRUE; ++ } ++ ++ if((check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE)==_TRUE)&&(check_fwstate(&padapter->mlmepriv, _FW_LINKED)==_TRUE)) ++ { ++ bgrouptkey = _TRUE; ++ } ++ ++ bgroup = _TRUE; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("------------------------------------------\n") ); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("[Group Key set]\n") ); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("------------------------------------------\n")) ; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("key index: 0x%8x(0x%8x)\n", key->KeyIndex,(key->KeyIndex&0x3))); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("key Length: %d\n", key->KeyLength)) ; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("------------------------------------------\n")); ++ ++ } ++ ++ // If WEP encryption algorithm, just call rtw_set_802_11_add_wep(). ++ if((padapter->securitypriv.dot11AuthAlgrthm !=dot11AuthAlgrthm_8021X)&&(encryptionalgo== _WEP40_ || encryptionalgo== _WEP104_)) ++ { ++ u8 ret; ++ u32 keyindex; ++ u32 len = FIELD_OFFSET(NDIS_802_11_KEY, KeyMaterial) + key->KeyLength; ++ NDIS_802_11_WEP *wep = &padapter->securitypriv.ndiswep; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("OID_802_11_ADD_KEY: +++++ WEP key +++++\n")); ++ ++ wep->Length = len; ++ keyindex = key->KeyIndex&0x7fffffff; ++ wep->KeyIndex = keyindex ; ++ wep->KeyLength = key->KeyLength; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("OID_802_11_ADD_KEY:Before memcpy \n")); ++ ++ _rtw_memcpy(wep->KeyMaterial, key->KeyMaterial, key->KeyLength); ++ _rtw_memcpy(&(padapter->securitypriv.dot11DefKey[keyindex].skey[0]), key->KeyMaterial, key->KeyLength); ++ ++ padapter->securitypriv.dot11DefKeylen[keyindex]=key->KeyLength; ++ padapter->securitypriv.dot11PrivacyKeyIndex=keyindex; ++ ++ ret = rtw_set_802_11_add_wep(padapter, wep); ++ ++ goto exit; ++ ++ } ++ ++ if(key->KeyIndex & 0x20000000){ ++ // SetRSC ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("OID_802_11_ADD_KEY: +++++ SetRSC+++++\n")); ++ if(bgroup == _TRUE) ++ { ++ NDIS_802_11_KEY_RSC keysrc=key->KeyRSC & 0x00FFFFFFFFFFFFULL; ++ _rtw_memcpy(&padapter->securitypriv.dot11Grprxpn, &keysrc, 8); ++ } ++ else ++ { ++ NDIS_802_11_KEY_RSC keysrc=key->KeyRSC & 0x00FFFFFFFFFFFFULL; ++ _rtw_memcpy(&padapter->securitypriv.dot11Grptxpn, &keysrc, 8); ++ } ++ ++ } ++ ++ // Indicate this key idx is used for TX ++ // Save the key in KeyMaterial ++ if(bgroup == _TRUE) // Group transmit key ++ { ++ int res; ++ ++ if(bgrouptkey == _TRUE) ++ { ++ padapter->securitypriv.dot118021XGrpKeyid=(u8)key->KeyIndex; ++ } ++ ++ if((key->KeyIndex&0x3) == 0){ ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ _rtw_memset(&padapter->securitypriv.dot118021XGrpKey[(u8)((key->KeyIndex) & 0x03)], 0, 16); ++ _rtw_memset(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], 0, 16); ++ _rtw_memset(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], 0, 16); ++ ++ if((key->KeyIndex & 0x10000000)) ++ { ++ _rtw_memcpy(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 16, 8); ++ _rtw_memcpy(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 24, 8); ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("\n rtw_set_802_11_add_key:rx mic :0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", ++ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[0],padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[1], ++ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[2],padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[3], ++ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[4],padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[5], ++ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[6],padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[7])); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("\n rtw_set_802_11_add_key:set Group mic key!!!!!!!!\n")); ++ ++ } ++ else ++ { ++ _rtw_memcpy(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 24, 8); ++ _rtw_memcpy(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 16, 8); ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("\n rtw_set_802_11_add_key:rx mic :0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", ++ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[0],padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[1], ++ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[2],padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[3], ++ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[4],padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[5], ++ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[6],padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[7])); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("\n rtw_set_802_11_add_key:set Group mic key!!!!!!!!\n")); ++ ++ } ++ ++ //set group key by index ++ _rtw_memcpy(&padapter->securitypriv.dot118021XGrpKey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial, key->KeyLength); ++ ++ key->KeyIndex=key->KeyIndex & 0x03; ++ ++ padapter->securitypriv.binstallGrpkey=_TRUE; ++ ++ padapter->securitypriv.bcheck_grpkey=_FALSE; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("reset group key")); ++ ++ res=rtw_set_key(padapter,&padapter->securitypriv, key->KeyIndex, 1,_TRUE); ++ ++ if(res==_FAIL) ++ ret= _FAIL; ++ ++ goto exit; ++ ++ } ++ else // Pairwise Key ++ { ++ u8 res; ++ ++ pbssid=get_bssid(&padapter->mlmepriv); ++ stainfo=rtw_get_stainfo(&padapter->stapriv , pbssid ); ++ ++ if(stainfo!=NULL) ++ { ++ _rtw_memset( &stainfo->dot118021x_UncstKey, 0, 16);// clear keybuffer ++ ++ _rtw_memcpy(&stainfo->dot118021x_UncstKey, key->KeyMaterial, 16); ++ ++ if(encryptionalgo== _TKIP_) ++ { ++ padapter->securitypriv.busetkipkey=_FALSE; ++ ++ //_set_timer(&padapter->securitypriv.tkip_timer, 50); ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("\n ==========_set_timer\n")); ++ ++ // if TKIP, save the Receive/Transmit MIC key in KeyMaterial[128-255] ++ if((key->KeyIndex & 0x10000000)){ ++ _rtw_memcpy(&stainfo->dot11tkiptxmickey, key->KeyMaterial + 16, 8); ++ _rtw_memcpy(&stainfo->dot11tkiprxmickey, key->KeyMaterial + 24, 8); ++ ++ } else { ++ _rtw_memcpy(&stainfo->dot11tkiptxmickey, key->KeyMaterial + 24, 8); ++ _rtw_memcpy(&stainfo->dot11tkiprxmickey, key->KeyMaterial + 16, 8); ++ ++ } ++ ++ } ++ else if(encryptionalgo == _AES_) ++ { ++ ++ } ++ ++ ++ //Set key to CAM through H2C command ++ if(bgrouptkey)//never go to here ++ { ++ res=rtw_setstakey_cmd(padapter, (unsigned char *)stainfo, _FALSE, _TRUE); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("\n rtw_set_802_11_add_key:rtw_setstakey_cmd(group)\n")); ++ } ++ else{ ++ res=rtw_setstakey_cmd(padapter, (unsigned char *)stainfo, _TRUE, _TRUE); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("\n rtw_set_802_11_add_key:rtw_setstakey_cmd(unicast)\n")); ++ } ++ ++ if(res ==_FALSE) ++ ret= _FAIL; ++ ++ } ++ ++ } ++ ++exit: ++ ++_func_exit_; ++ ++ return ret; ++} ++ ++u8 rtw_set_802_11_remove_key(_adapter* padapter, NDIS_802_11_REMOVE_KEY *key){ ++ ++ uint encryptionalgo; ++ u8 * pbssid; ++ struct sta_info *stainfo; ++ u8 bgroup = (key->KeyIndex & 0x4000000) > 0 ? _FALSE: _TRUE; ++ u8 keyIndex = (u8)key->KeyIndex & 0x03; ++ u8 ret=_SUCCESS; ++ ++_func_enter_; ++ ++ if ((key->KeyIndex & 0xbffffffc) > 0) { ++ ret=_FAIL; ++ goto exit; ++ } ++ ++ if (bgroup == _TRUE) { ++ encryptionalgo= padapter->securitypriv.dot118021XGrpPrivacy; ++ // clear group key by index ++ //NdisZeroMemory(Adapter->MgntInfo.SecurityInfo.KeyBuf[keyIndex], MAX_WEP_KEY_LEN); ++ //Adapter->MgntInfo.SecurityInfo.KeyLen[keyIndex] = 0; ++ ++ _rtw_memset(&padapter->securitypriv.dot118021XGrpKey[keyIndex], 0, 16); ++ ++ //! \todo Send a H2C Command to Firmware for removing this Key in CAM Entry. ++ ++ } else { ++ ++ pbssid=get_bssid(&padapter->mlmepriv); ++ stainfo=rtw_get_stainfo(&padapter->stapriv , pbssid ); ++ if(stainfo !=NULL){ ++ encryptionalgo=stainfo->dot118021XPrivacy; ++ ++ // clear key by BSSID ++ _rtw_memset(&stainfo->dot118021x_UncstKey, 0, 16); ++ ++ //! \todo Send a H2C Command to Firmware for disable this Key in CAM Entry. ++ ++ } ++ else{ ++ ret= _FAIL; ++ goto exit; ++ } ++ } ++ ++exit: ++ ++_func_exit_; ++ ++ return _TRUE; ++ ++} ++ ++/* ++* rtw_get_cur_max_rate - ++* @adapter: pointer to _adapter structure ++* ++* Return 0 or 100Kbps ++*/ ++u16 rtw_get_cur_max_rate(_adapter *adapter) ++{ ++ int i = 0; ++ u8 *p; ++ u16 rate = 0, max_rate = 0; ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct registry_priv *pregistrypriv = &adapter->registrypriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ WLAN_BSSID_EX *pcur_bss = &pmlmepriv->cur_network.network; ++#ifdef CONFIG_80211N_HT ++ struct rtw_ieee80211_ht_cap *pht_capie; ++ u8 rf_type = 0; ++ u8 bw_40MHz=0, short_GI_20=0, short_GI_40=0; ++ u16 mcs_rate=0; ++ u32 ht_ielen = 0; ++#endif ++ ++#ifdef CONFIG_MP_INCLUDED ++ if (adapter->registrypriv.mp_mode == 1) ++ { ++ if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) ++ return 0; ++ } ++#endif ++ ++ if((check_fwstate(pmlmepriv, _FW_LINKED) != _TRUE) ++ && (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) != _TRUE)) ++ return 0; ++ ++#ifdef CONFIG_80211N_HT ++ if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N|WIRELESS_11_5N)) { ++ p = rtw_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pcur_bss->IELength-12); ++ if(p && ht_ielen>0) ++ { ++ pht_capie = (struct rtw_ieee80211_ht_cap *)(p+2); ++ ++ _rtw_memcpy(&mcs_rate , pht_capie->supp_mcs_set, 2); ++ ++ //bw_40MHz = (pht_capie->cap_info&IEEE80211_HT_CAP_SUP_WIDTH) ? 1:0; ++ //cur_bwmod is updated by beacon, pmlmeinfo is updated by association response ++ bw_40MHz = (pmlmeext->cur_bwmode && (HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH & pmlmeinfo->HT_info.infos[0])) ? 1:0; ++ ++ //short_GI = (pht_capie->cap_info&(IEEE80211_HT_CAP_SGI_20|IEEE80211_HT_CAP_SGI_40)) ? 1:0; ++ short_GI_20 = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info&IEEE80211_HT_CAP_SGI_20) ? 1:0; ++ short_GI_40 = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info&IEEE80211_HT_CAP_SGI_40) ? 1:0; ++ ++ rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ max_rate = rtw_mcs_rate( ++ rf_type, ++ bw_40MHz & (pregistrypriv->cbw40_enable), ++ short_GI_20, ++ short_GI_40, ++ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate ++ ); ++ } ++ } ++ else ++#endif //CONFIG_80211N_HT ++ { ++ while( (pcur_bss->SupportedRates[i]!=0) && (pcur_bss->SupportedRates[i]!=0xFF)) ++ { ++ rate = pcur_bss->SupportedRates[i]&0x7F; ++ if(rate>max_rate) ++ max_rate = rate; ++ i++; ++ } ++ ++ max_rate = max_rate*10/2; ++ } ++ ++ return max_rate; ++} ++ ++/* ++* rtw_set_scan_mode - ++* @adapter: pointer to _adapter structure ++* @scan_mode: ++* ++* Return _SUCCESS or _FAIL ++*/ ++int rtw_set_scan_mode(_adapter *adapter, RT_SCAN_TYPE scan_mode) ++{ ++ if(scan_mode != SCAN_ACTIVE && scan_mode != SCAN_PASSIVE) ++ return _FAIL; ++ ++ adapter->mlmepriv.scan_mode = scan_mode; ++ ++ return _SUCCESS; ++} ++ ++/* ++* rtw_set_channel_plan - ++* @adapter: pointer to _adapter structure ++* @channel_plan: ++* ++* Return _SUCCESS or _FAIL ++*/ ++int rtw_set_channel_plan(_adapter *adapter, u8 channel_plan) ++{ ++ struct registry_priv *pregistrypriv = &adapter->registrypriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ ++ //handle by cmd_thread to sync with scan operation ++ return rtw_set_chplan_cmd(adapter, channel_plan, 1); ++} ++ ++/* ++* rtw_set_country - ++* @adapter: pointer to _adapter structure ++* @country_code: string of country code ++* ++* Return _SUCCESS or _FAIL ++*/ ++int rtw_set_country(_adapter *adapter, const char *country_code) ++{ ++ int channel_plan = RT_CHANNEL_DOMAIN_WORLD_WIDE_5G; ++ ++ DBG_871X("%s country_code:%s\n", __func__, country_code); ++ ++ //TODO: should have a table to match country code and RT_CHANNEL_DOMAIN ++ //TODO: should consider 2-character and 3-character country code ++ if(0 == strcmp(country_code, "US")) ++ channel_plan = RT_CHANNEL_DOMAIN_FCC; ++ else if(0 == strcmp(country_code, "EU")) ++ channel_plan = RT_CHANNEL_DOMAIN_ETSI; ++ else if(0 == strcmp(country_code, "JP")) ++ channel_plan = RT_CHANNEL_DOMAIN_MKK; ++ else if(0 == strcmp(country_code, "CN")) ++ channel_plan = RT_CHANNEL_DOMAIN_CHINA; ++ else if(0 == strcmp(country_code, "IN")) ++ channel_plan = RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN; ++ else ++ DBG_871X("%s unknown country_code:%s\n", __FUNCTION__, country_code); ++ ++ return rtw_set_channel_plan(adapter, channel_plan); ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_iol.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_iol.c +new file mode 100644 +index 00000000..0e833be8 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_iol.c +@@ -0,0 +1,403 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#include ++ ++#ifdef CONFIG_IOL ++struct xmit_frame *rtw_IOL_accquire_xmit_frame(ADAPTER *adapter) ++{ ++ struct xmit_frame *xmit_frame; ++ struct xmit_buf *xmitbuf; ++ struct pkt_attrib *pattrib; ++ struct xmit_priv *pxmitpriv = &(adapter->xmitpriv); ++ ++#if 1 ++ if ((xmit_frame = rtw_alloc_xmitframe(pxmitpriv)) == NULL) ++ { ++ DBG_871X("%s rtw_alloc_xmitframe return null\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ if ((xmitbuf = rtw_alloc_xmitbuf(pxmitpriv)) == NULL) ++ { ++ DBG_871X("%s rtw_alloc_xmitbuf return null\n", __FUNCTION__); ++ rtw_free_xmitframe(pxmitpriv, xmit_frame); ++ xmit_frame=NULL; ++ goto exit; ++ } ++ ++ xmit_frame->frame_tag = MGNT_FRAMETAG; ++ xmit_frame->pxmitbuf = xmitbuf; ++ xmit_frame->buf_addr = xmitbuf->pbuf; ++ xmitbuf->priv_data = xmit_frame; ++ ++ pattrib = &xmit_frame->attrib; ++ update_mgntframe_attrib(adapter, pattrib); ++ pattrib->qsel = 0x10;//Beacon ++ pattrib->subtype = WIFI_BEACON; ++ pattrib->pktlen = pattrib->last_txcmdsz = 0; ++ ++#else ++ if ((xmit_frame = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ DBG_871X("%s alloc_mgtxmitframe return null\n", __FUNCTION__); ++ } ++ else { ++ pattrib = &xmit_frame->attrib; ++ update_mgntframe_attrib(adapter, pattrib); ++ pattrib->qsel = 0x10; ++ pattrib->pktlen = pattrib->last_txcmdsz = 0; ++ } ++#endif ++ ++exit: ++ return xmit_frame; ++} ++ ++ ++int rtw_IOL_append_cmds(struct xmit_frame *xmit_frame, u8 *IOL_cmds, u32 cmd_len) ++{ ++ struct pkt_attrib *pattrib = &xmit_frame->attrib; ++ u16 buf_offset; ++ u32 ori_len; ++ ++ buf_offset = TXDESC_OFFSET; ++ ori_len = buf_offset+pattrib->pktlen; ++ ++ //check if the io_buf can accommodate new cmds ++ if(ori_len + cmd_len + 8 > MAX_XMITBUF_SZ) { ++ DBG_871X("%s %u is large than MAX_XMITBUF_SZ:%u, can't accommodate new cmds\n", __FUNCTION__ ++ , ori_len + cmd_len + 8, MAX_XMITBUF_SZ); ++ return _FAIL; ++ } ++ ++ _rtw_memcpy(xmit_frame->buf_addr + buf_offset + pattrib->pktlen, IOL_cmds, cmd_len); ++ pattrib->pktlen += cmd_len; ++ pattrib->last_txcmdsz += cmd_len; ++ ++ //DBG_871X("%s ori:%u + cmd_len:%u = %u\n", __FUNCTION__, ori_len, cmd_len, buf_offset+pattrib->pktlen); ++ ++ return _SUCCESS; ++} ++bool rtw_IOL_applied(ADAPTER *adapter) ++{ ++ if(1 == adapter->registrypriv.fw_iol) ++ return _TRUE; ++ ++#ifdef CONFIG_USB_HCI ++ if((2 == adapter->registrypriv.fw_iol) && (!adapter_to_dvobj(adapter)->ishighspeed)) ++ return _TRUE; ++#endif ++ ++ return _FALSE; ++} ++/* ++bool rtw_IOL_applied(ADAPTER *adapter) ++{ ++ if(adapter->registrypriv.fw_iol) ++ return _TRUE; ++ ++#ifdef CONFIG_USB_HCI ++ if(!adapter_to_dvobj(adapter)->ishighspeed) ++ return _TRUE; ++#endif ++ ++ return _FALSE; ++} ++*/ ++ ++int rtw_IOL_exec_cmds_sync(ADAPTER *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt) ++{ ++ return rtw_hal_iol_cmd(adapter, xmit_frame, max_wating_ms,bndy_cnt); ++} ++ ++#ifdef CONFIG_IOL_NEW_GENERATION ++int rtw_IOL_append_LLT_cmd(struct xmit_frame *xmit_frame, u8 page_boundary) ++{ ++ return _SUCCESS; ++} ++int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, u8 mask) ++{ ++ struct ioreg_cfg cmd = {8,IOREG_CMD_WB_REG,0x0, 0x0,0x0}; ++ ++ //RTW_PUT_LE16((u8*)&cmd.address, addr); ++ //RTW_PUT_LE32((u8*)&cmd.value, (u32)value); ++ cmd.address = cpu_to_le16(addr); ++ cmd.data = cpu_to_le32(value); ++ ++ if(mask!=0xFF) ++ { ++ cmd.length = 12; ++ //RTW_PUT_LE32((u8*)&cmd.mask, (u32)mask); ++ cmd.mask = cpu_to_le32(mask); ++ } ++ ++ //DBG_871X("%s addr:0x%04x,value:0x%08x,mask:0x%08x\n", __FUNCTION__, addr,value,mask); ++ ++ return rtw_IOL_append_cmds(xmit_frame, (u8*)&cmd, cmd.length); ++ ++} ++int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, u16 mask) ++{ ++ struct ioreg_cfg cmd = {8,IOREG_CMD_WW_REG,0x0, 0x0,0x0}; ++ ++ //RTW_PUT_LE16((u8*)&cmd.address, addr); ++ //RTW_PUT_LE32((u8*)&cmd.value, (u32)value); ++ cmd.address = cpu_to_le16(addr); ++ cmd.data = cpu_to_le32(value); ++ ++ if(mask!=0xFFFF) ++ { ++ cmd.length = 12; ++ //RTW_PUT_LE32((u8*)&cmd.mask, (u32)mask); ++ cmd.mask = cpu_to_le32(mask); ++ } ++ ++ //DBG_871X("%s addr:0x%04x,value:0x%08x,mask:0x%08x\n", __FUNCTION__, addr,value,mask); ++ ++ return rtw_IOL_append_cmds(xmit_frame, (u8*)&cmd, cmd.length); ++ ++} ++int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, u32 mask) ++{ ++ struct ioreg_cfg cmd = {8,IOREG_CMD_WD_REG,0x0, 0x0,0x0}; ++ ++ //RTW_PUT_LE16((u8*)&cmd.address, addr); ++ //RTW_PUT_LE32((u8*)&cmd.value, (u32)value); ++ cmd.address = cpu_to_le16(addr); ++ cmd.data = cpu_to_le32(value); ++ ++ if(mask!=0xFFFFFFFF) ++ { ++ cmd.length = 12; ++ //RTW_PUT_LE32((u8*)&cmd.mask, (u32)mask); ++ cmd.mask = cpu_to_le32(mask); ++ } ++ ++ //DBG_871X("%s addr:0x%04x,value:0x%08x,mask:0x%08x\n", __FU2NCTION__, addr,value,mask); ++ ++ return rtw_IOL_append_cmds(xmit_frame, (u8*)&cmd, cmd.length); ++ ++} ++ ++int _rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path, u16 addr, u32 value, u32 mask) ++{ ++ struct ioreg_cfg cmd = {8,IOREG_CMD_W_RF,0x0, 0x0,0x0}; ++ ++ //RTW_PUT_LE16((u8*)&cmd.address, addr); ++ //RTW_PUT_LE32((u8*)&cmd.value, (u32)value); ++ cmd.address = (rf_path<<8) |((addr) &0xFF); ++ cmd.data = cpu_to_le32(value); ++ ++ if(mask!=0x000FFFFF) ++ { ++ cmd.length = 12; ++ //RTW_PUT_LE32((u8*)&cmd.mask, (u32)mask); ++ cmd.mask = cpu_to_le32(mask); ++ } ++ ++ //DBG_871X("%s rf_path:0x%02x addr:0x%04x,value:0x%08x,mask:0x%08x\n", __FU2NCTION__,rf_path, addr,value,mask); ++ ++ return rtw_IOL_append_cmds(xmit_frame, (u8*)&cmd, cmd.length); ++ ++} ++ ++ ++ ++int rtw_IOL_append_DELAY_US_cmd(struct xmit_frame *xmit_frame, u16 us) ++{ ++ struct ioreg_cfg cmd = {4,IOREG_CMD_DELAY_US,0x0, 0x0,0x0}; ++ //RTW_PUT_LE16((u8*)&cmd.address, us); ++ cmd.address = cpu_to_le16(us); ++ ++ //DBG_871X("%s %u\n", __FUNCTION__, us); ++ return rtw_IOL_append_cmds(xmit_frame, (u8*)&cmd, 4); ++} ++ ++int rtw_IOL_append_DELAY_MS_cmd(struct xmit_frame *xmit_frame, u16 ms) ++{ ++ struct ioreg_cfg cmd = {4,IOREG_CMD_DELAY_US,0x0, 0x0,0x0}; ++ ++ //RTW_PUT_LE16((u8*)&cmd.address, ms); ++ cmd.address = cpu_to_le16(ms); ++ ++ //DBG_871X("%s %u\n", __FUNCTION__, ms); ++ return rtw_IOL_append_cmds(xmit_frame, (u8*)&cmd, 4); ++} ++int rtw_IOL_append_END_cmd(struct xmit_frame *xmit_frame) ++{ ++ struct ioreg_cfg cmd = {4,IOREG_CMD_END,0xFFFF, 0xFF,0x0}; ++ return rtw_IOL_append_cmds(xmit_frame, (u8*)&cmd, 4); ++ ++} ++ ++u8 rtw_IOL_cmd_boundary_handle(struct xmit_frame *pxmit_frame) ++{ ++ u8 is_cmd_bndy = _FALSE; ++ if(((pxmit_frame->attrib.pktlen+32)%256) + 8 >= 256){ ++ rtw_IOL_append_END_cmd(pxmit_frame); ++ pxmit_frame->attrib.pktlen = ((((pxmit_frame->attrib.pktlen+32)/256)+1)*256 ); ++ ++ //printk("==> %s, pktlen(%d)\n",__FUNCTION__,pxmit_frame->attrib.pktlen); ++ pxmit_frame->attrib.last_txcmdsz = pxmit_frame->attrib.pktlen; ++ is_cmd_bndy = _TRUE; ++ } ++ return is_cmd_bndy; ++} ++ ++void rtw_IOL_cmd_buf_dump(ADAPTER *Adapter,int buf_len,u8 *pbuf) ++{ ++ int i; ++ int j=1; ++ ++ printk("###### %s ######\n",__FUNCTION__); ++ for(i=0;i< buf_len;i++){ ++ printk("%02x-",*(pbuf+i)); ++ ++ if(j%32 ==0) printk("\n");j++; ++ } ++ printk("\n"); ++ printk("============= ioreg_cmd len = %d =============== \n",buf_len); ++} ++ ++ ++#else //CONFIG_IOL_NEW_GENERATION ++int rtw_IOL_append_LLT_cmd(struct xmit_frame *xmit_frame, u8 page_boundary) ++{ ++ IOL_CMD cmd = {0x0, IOL_CMD_LLT, 0x0, 0x0}; ++ ++ RTW_PUT_BE32((u8*)&cmd.value, (u32)page_boundary); ++ ++ return rtw_IOL_append_cmds(xmit_frame, (u8*)&cmd, 8); ++} ++ ++int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value) ++{ ++ IOL_CMD cmd = {0x0, IOL_CMD_WB_REG, 0x0, 0x0}; ++ ++ RTW_PUT_BE16((u8*)&cmd.address, (u16)addr); ++ RTW_PUT_BE32((u8*)&cmd.value, (u32)value); ++ ++ return rtw_IOL_append_cmds(xmit_frame, (u8*)&cmd, 8); ++} ++ ++int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value) ++{ ++ IOL_CMD cmd = {0x0, IOL_CMD_WW_REG, 0x0, 0x0}; ++ ++ RTW_PUT_BE16((u8*)&cmd.address, (u16)addr); ++ RTW_PUT_BE32((u8*)&cmd.value, (u32)value); ++ ++ return rtw_IOL_append_cmds(xmit_frame, (u8*)&cmd, 8); ++} ++ ++int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value) ++{ ++ IOL_CMD cmd = {0x0, IOL_CMD_WD_REG, 0x0, 0x0}; ++ u8* pos = (u8 *)&cmd; ++ ++ RTW_PUT_BE16((u8*)&cmd.address, (u16)addr); ++ RTW_PUT_BE32((u8*)&cmd.value, (u32)value); ++ ++ return rtw_IOL_append_cmds(xmit_frame, (u8*)&cmd, 8); ++} ++ ++#ifdef DBG_IO ++int dbg_rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, const char *caller, const int line) ++{ ++ if (match_write_sniff_ranges(addr, 1)) ++ DBG_871X("DBG_IO %s:%d IOL_WB(0x%04x, 0x%02x)\n", caller, line, addr, value); ++ ++ return _rtw_IOL_append_WB_cmd(xmit_frame, addr, value); ++} ++ ++int dbg_rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, const char *caller, const int line) ++{ ++ if (match_write_sniff_ranges(addr, 2)) ++ DBG_871X("DBG_IO %s:%d IOL_WW(0x%04x, 0x%04x)\n", caller, line, addr, value); ++ ++ return _rtw_IOL_append_WW_cmd(xmit_frame, addr, value); ++} ++ ++int dbg_rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, const char *caller, const int line) ++{ ++ if (match_write_sniff_ranges(addr, 4)) ++ DBG_871X("DBG_IO %s:%d IOL_WD(0x%04x, 0x%08x)\n", caller, line, addr, value); ++ ++ return _rtw_IOL_append_WD_cmd(xmit_frame, addr, value); ++} ++#endif ++ ++int rtw_IOL_append_DELAY_US_cmd(struct xmit_frame *xmit_frame, u16 us) ++{ ++ IOL_CMD cmd = {0x0, IOL_CMD_DELAY_US, 0x0, 0x0}; ++ ++ RTW_PUT_BE32((u8*)&cmd.value, (u32)us); ++ ++ //DBG_871X("%s %u\n", __FUNCTION__, us); ++ ++ return rtw_IOL_append_cmds(xmit_frame, (u8*)&cmd, 8); ++} ++ ++int rtw_IOL_append_DELAY_MS_cmd(struct xmit_frame *xmit_frame, u16 ms) ++{ ++ IOL_CMD cmd = {0x0, IOL_CMD_DELAY_MS, 0x0, 0x0}; ++ ++ RTW_PUT_BE32((u8*)&cmd.value, (u32)ms); ++ ++ //DBG_871X("%s %u\n", __FUNCTION__, ms); ++ ++ return rtw_IOL_append_cmds(xmit_frame, (u8*)&cmd, 8); ++} ++ ++int rtw_IOL_append_END_cmd(struct xmit_frame *xmit_frame) ++{ ++ IOL_CMD end_cmd = {0x0, IOL_CMD_END, 0x0, 0x0}; ++ ++ ++ return rtw_IOL_append_cmds(xmit_frame, (u8*)&end_cmd, 8); ++ ++} ++ ++int rtw_IOL_exec_cmd_array_sync(PADAPTER adapter, u8 *IOL_cmds, u32 cmd_num, u32 max_wating_ms) ++{ ++ struct xmit_frame *xmit_frame; ++ ++ if((xmit_frame=rtw_IOL_accquire_xmit_frame(adapter)) == NULL) ++ return _FAIL; ++ ++ if(rtw_IOL_append_cmds(xmit_frame, IOL_cmds, cmd_num<<3) == _FAIL) ++ return _FAIL; ++ ++ return rtw_IOL_exec_cmds_sync(adapter, xmit_frame, max_wating_ms,0); ++} ++ ++int rtw_IOL_exec_empty_cmds_sync(ADAPTER *adapter, u32 max_wating_ms) ++{ ++ IOL_CMD end_cmd = {0x0, IOL_CMD_END, 0x0, 0x0}; ++ return rtw_IOL_exec_cmd_array_sync(adapter, (u8*)&end_cmd, 1, max_wating_ms); ++} ++#endif //CONFIG_IOL_NEW_GENERATION ++ ++ ++ ++ ++#endif //CONFIG_IOL ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_led.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_led.c +new file mode 100644 +index 00000000..7710f324 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_led.c +@@ -0,0 +1,2422 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#include ++ ++// ++// Description: ++// Callback function of LED BlinkTimer, ++// it just schedules to corresponding BlinkWorkItem/led_blink_hdl ++// ++void BlinkTimerCallback(void *data) ++{ ++ PLED_871x pLed = (PLED_871x)data; ++ _adapter *padapter = pLed->padapter; ++ ++ //DBG_871X("%s\n", __FUNCTION__); ++ ++ if( (padapter->bSurpriseRemoved == _TRUE) || ( padapter->bDriverStopped == _TRUE)) ++ { ++ //DBG_871X("%s bSurpriseRemoved:%d, bDriverStopped:%d\n", __FUNCTION__, padapter->bSurpriseRemoved, padapter->bDriverStopped); ++ return; ++ } ++ ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) ++ #ifdef CONFIG_LED_HANDLED_BY_CMD_THREAD ++ rtw_led_blink_cmd(padapter, pLed); ++ #else ++ _set_workitem(&(pLed->BlinkWorkItem)); ++ #endif ++#elif defined(CONFIG_PCI_HCI) ++ BlinkHandler(pLed); ++#endif ++ ++} ++ ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) ++// ++// Description: ++// Callback function of LED BlinkWorkItem. ++// We dispatch acture LED blink action according to LedStrategy. ++// ++void BlinkWorkItemCallback(struct work_struct *work) ++{ ++ PLED_871x pLed = container_of(work, LED_871x, BlinkWorkItem); ++ BlinkHandler(pLed); ++} ++#endif ++ ++// ++// Description: ++// Reset status of LED_871x object. ++// ++void ResetLedStatus(PLED_871x pLed) { ++ ++ pLed->CurrLedState = RTW_LED_OFF; // Current LED state. ++ pLed->bLedOn = _FALSE; // true if LED is ON, false if LED is OFF. ++ ++ pLed->bLedBlinkInProgress = _FALSE; // true if it is blinking, false o.w.. ++ pLed->bLedWPSBlinkInProgress = _FALSE; ++ ++ pLed->BlinkTimes = 0; // Number of times to toggle led state for blinking. ++ pLed->BlinkingLedState = LED_UNKNOWN; // Next state for blinking, either RTW_LED_ON or RTW_LED_OFF are. ++ ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) ++ pLed->bLedNoLinkBlinkInProgress = _FALSE; ++ pLed->bLedLinkBlinkInProgress = _FALSE; ++ pLed->bLedStartToLinkBlinkInProgress = _FALSE; ++ pLed->bLedScanBlinkInProgress = _FALSE; ++#endif ++} ++ ++ // ++// Description: ++// Initialize an LED_871x object. ++// ++void ++InitLed871x( ++ _adapter *padapter, ++ PLED_871x pLed, ++ LED_PIN_871x LedPin ++ ) ++{ ++ pLed->padapter = padapter; ++ pLed->LedPin = LedPin; ++ ++ ResetLedStatus(pLed); ++ ++ _init_timer(&(pLed->BlinkTimer), padapter->pnetdev, BlinkTimerCallback, pLed); ++ ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) ++ _init_workitem(&(pLed->BlinkWorkItem), BlinkWorkItemCallback, pLed); ++#endif ++} ++ ++ ++// ++// Description: ++// DeInitialize an LED_871x object. ++// ++void ++DeInitLed871x( ++ PLED_871x pLed ++ ) ++{ ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ _cancel_workitem_sync(&(pLed->BlinkWorkItem)); ++#endif ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ ResetLedStatus(pLed); ++} ++ ++ ++// ++// Description: ++// Implementation of LED blinking behavior. ++// It toggle off LED and schedule corresponding timer if necessary. ++// ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ ++void SwLedOn(_adapter *padapter, PLED_871x pLed); ++void SwLedOff(_adapter *padapter, PLED_871x pLed); ++ ++#define CONFIG_LED_REMOVE_HAL ++ ++void ++SwLedBlink( ++ PLED_871x pLed ++ ) ++{ ++ _adapter *padapter = pLed->padapter; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ u8 bStopBlinking = _FALSE; ++ ++ // Change LED according to BlinkingLedState specified. ++ if( pLed->BlinkingLedState == RTW_LED_ON ) ++ { ++ SwLedOn(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); ++ } ++ else ++ { ++ SwLedOff(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,( "Blinktimes (%d): turn off\n", pLed->BlinkTimes)); ++ } ++ ++ // Determine if we shall change LED state again. ++ pLed->BlinkTimes--; ++ switch(pLed->CurrLedState) ++ { ++ ++ case LED_BLINK_NORMAL: ++ if(pLed->BlinkTimes == 0) ++ { ++ bStopBlinking = _TRUE; ++ } ++ break; ++ ++ case LED_BLINK_StartToBlink: ++ if( check_fwstate(pmlmepriv, _FW_LINKED) && check_fwstate(pmlmepriv, WIFI_STATION_STATE) ) ++ { ++ bStopBlinking = _TRUE; ++ } ++ if( check_fwstate(pmlmepriv, _FW_LINKED) && ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ) ++ { ++ bStopBlinking = _TRUE; ++ } ++ else if(pLed->BlinkTimes == 0) ++ { ++ bStopBlinking = _TRUE; ++ } ++ break; ++ ++ case LED_BLINK_WPS: ++ if( pLed->BlinkTimes == 0 ) ++ { ++ bStopBlinking = _TRUE; ++ } ++ break; ++ ++ ++ default: ++ bStopBlinking = _TRUE; ++ break; ++ ++ } ++ ++ if(bStopBlinking) ++ { ++ //if(adapter_to_pwrctl(padapter)->cpwm >= PS_STATE_S2) ++ if(0) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else if( (check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE) && (pLed->bLedOn == _FALSE)) ++ { ++ SwLedOn(padapter, pLed); ++ } ++ else if( (check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE) && pLed->bLedOn == _TRUE) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ ++ pLed->BlinkTimes = 0; ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ else ++ { ++ // Assign LED state to toggle. ++ if( pLed->BlinkingLedState == RTW_LED_ON ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ ++ // Schedule a timer to toggle LED state. ++ switch( pLed->CurrLedState ) ++ { ++ case LED_BLINK_NORMAL: ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ break; ++ ++ case LED_BLINK_SLOWLY: ++ case LED_BLINK_StartToBlink: ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); ++ break; ++ ++ case LED_BLINK_WPS: ++ { ++ if( pLed->BlinkingLedState == RTW_LED_ON ) ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LONG_INTERVAL); ++ else ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LONG_INTERVAL); ++ } ++ break; ++ ++ default: ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); ++ break; ++ } ++ } ++} ++ ++void ++SwLedBlink1( ++ PLED_871x pLed ++ ) ++{ ++ _adapter *padapter = pLed->padapter; ++#ifndef CONFIG_LED_REMOVE_HAL ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++#endif ++ struct led_priv *ledpriv = &(padapter->ledpriv); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ PLED_871x pLed1 = &(ledpriv->SwLed1); ++ u8 bStopBlinking = _FALSE; ++ ++#ifndef CONFIG_LED_REMOVE_HAL ++ if(pHalData->EEPROMCustomerID == RT_CID_819x_CAMEO) ++ pLed = &(ledpriv->SwLed1); ++#endif ++ ++ // Change LED according to BlinkingLedState specified. ++ if( pLed->BlinkingLedState == RTW_LED_ON ) ++ { ++ SwLedOn(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,( "Blinktimes (%d): turn on\n", pLed->BlinkTimes)); ++ } ++ else ++ { ++ SwLedOff(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); ++ } ++ ++#ifndef CONFIG_LED_REMOVE_HAL ++ if(pHalData->EEPROMCustomerID == RT_CID_DEFAULT) ++ { ++ if(check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE) ++ { ++ if(!pLed1->bSWLedCtrl) ++ { ++ SwLedOn(padapter, pLed1); ++ pLed1->bSWLedCtrl = _TRUE; ++ } ++ else if(!pLed1->bLedOn) ++ SwLedOn(padapter, pLed1); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Blinktimes (): turn on pLed1\n")); ++ } ++ else ++ { ++ if(!pLed1->bSWLedCtrl) ++ { ++ SwLedOff(padapter, pLed1); ++ pLed1->bSWLedCtrl = _TRUE; ++ } ++ else if(pLed1->bLedOn) ++ SwLedOff(padapter, pLed1); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Blinktimes (): turn off pLed1\n")); ++ } ++ } ++ ++#endif ++ ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on ) ++ { ++ SwLedOff(padapter, pLed); ++ ResetLedStatus(pLed); ++ return; ++ } ++ ++ switch(pLed->CurrLedState) ++ { ++ case LED_BLINK_SLOWLY: ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ break; ++ ++ case LED_BLINK_NORMAL: ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); ++ break; ++ ++ case LED_BLINK_SCAN: ++ pLed->BlinkTimes--; ++ if( pLed->BlinkTimes == 0 ) ++ { ++ bStopBlinking = _TRUE; ++ } ++ ++ if(bStopBlinking) ++ { ++ if(check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE) ++ { ++ pLed->bLedLinkBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_NORMAL; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("CurrLedState %d\n", pLed->CurrLedState)); ++ ++ } ++ else if(check_fwstate(pmlmepriv, _FW_LINKED)== _FALSE) ++ { ++ pLed->bLedNoLinkBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("CurrLedState %d\n", pLed->CurrLedState)); ++ } ++ pLed->bLedScanBlinkInProgress = _FALSE; ++ } ++ else ++ { ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ break; ++ ++ case LED_BLINK_TXRX: ++ pLed->BlinkTimes--; ++ if( pLed->BlinkTimes == 0 ) ++ { ++ bStopBlinking = _TRUE; ++ } ++ if(bStopBlinking) ++ { ++ if(check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE) ++ { ++ pLed->bLedLinkBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_NORMAL; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("CurrLedState %d\n", pLed->CurrLedState)); ++ } ++ else if(check_fwstate(pmlmepriv, _FW_LINKED)== _FALSE) ++ { ++ pLed->bLedNoLinkBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("CurrLedState %d\n", pLed->CurrLedState)); ++ } ++ pLed->BlinkTimes = 0; ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ else ++ { ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ break; ++ ++ case LED_BLINK_WPS: ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); ++ break; ++ ++ case LED_BLINK_WPS_STOP: //WPS success ++ if(pLed->BlinkingLedState == RTW_LED_ON) ++ bStopBlinking = _FALSE; ++ else ++ bStopBlinking = _TRUE; ++ ++ if(bStopBlinking) ++ { ++ pLed->bLedLinkBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_NORMAL; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("CurrLedState %d\n", pLed->CurrLedState)); ++ ++ pLed->bLedWPSBlinkInProgress = _FALSE; ++ } ++ else ++ { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++} ++ ++void ++SwLedBlink2( ++ PLED_871x pLed ++ ) ++{ ++ _adapter *padapter = pLed->padapter; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ u8 bStopBlinking = _FALSE; ++ ++ // Change LED according to BlinkingLedState specified. ++ if( pLed->BlinkingLedState == RTW_LED_ON) ++ { ++ SwLedOn(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); ++ } ++ else ++ { ++ SwLedOff(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); ++ } ++ ++ switch(pLed->CurrLedState) ++ { ++ case LED_BLINK_SCAN: ++ pLed->BlinkTimes--; ++ if( pLed->BlinkTimes == 0 ) ++ { ++ bStopBlinking = _TRUE; ++ } ++ ++ if(bStopBlinking) ++ { ++ if( adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on ) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else if(check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE) ++ { ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ SwLedOn(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("stop scan blink CurrLedState %d\n", pLed->CurrLedState)); ++ ++ } ++ else if(check_fwstate(pmlmepriv, _FW_LINKED)== _FALSE) ++ { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ SwLedOff(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("stop scan blink CurrLedState %d\n", pLed->CurrLedState)); ++ } ++ pLed->bLedScanBlinkInProgress = _FALSE; ++ } ++ else ++ { ++ if( adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on ) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else ++ { ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ } ++ break; ++ ++ case LED_BLINK_TXRX: ++ pLed->BlinkTimes--; ++ if( pLed->BlinkTimes == 0 ) ++ { ++ bStopBlinking = _TRUE; ++ } ++ if(bStopBlinking) ++ { ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on ) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else if(check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE) ++ { ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ SwLedOn(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("stop CurrLedState %d\n", pLed->CurrLedState)); ++ ++ } ++ else if(check_fwstate(pmlmepriv, _FW_LINKED)== _FALSE) ++ { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ SwLedOff(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("stop CurrLedState %d\n", pLed->CurrLedState)); ++ } ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ else ++ { ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on ) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else ++ { ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++} ++ ++void ++SwLedBlink3( ++ PLED_871x pLed ++ ) ++{ ++ _adapter *padapter = pLed->padapter; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ u8 bStopBlinking = _FALSE; ++ ++ // Change LED according to BlinkingLedState specified. ++ if( pLed->BlinkingLedState == RTW_LED_ON ) ++ { ++ SwLedOn(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); ++ } ++ else ++ { ++ if(pLed->CurrLedState != LED_BLINK_WPS_STOP) ++ SwLedOff(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); ++ } ++ ++ switch(pLed->CurrLedState) ++ { ++ case LED_BLINK_SCAN: ++ pLed->BlinkTimes--; ++ if( pLed->BlinkTimes == 0 ) ++ { ++ bStopBlinking = _TRUE; ++ } ++ ++ if(bStopBlinking) ++ { ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on ) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else if(check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE) ++ { ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ if( !pLed->bLedOn ) ++ SwLedOn(padapter, pLed); ++ ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("CurrLedState %d\n", pLed->CurrLedState)); ++ } ++ else if(check_fwstate(pmlmepriv, _FW_LINKED)== _FALSE) ++ { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ if( pLed->bLedOn ) ++ SwLedOff(padapter, pLed); ++ ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("CurrLedState %d\n", pLed->CurrLedState)); ++ } ++ pLed->bLedScanBlinkInProgress = _FALSE; ++ } ++ else ++ { ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on ) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else ++ { ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ } ++ break; ++ ++ case LED_BLINK_TXRX: ++ pLed->BlinkTimes--; ++ if( pLed->BlinkTimes == 0 ) ++ { ++ bStopBlinking = _TRUE; ++ } ++ if(bStopBlinking) ++ { ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on ) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else if(check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE) ++ { ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ ++ if( !pLed->bLedOn ) ++ SwLedOn(padapter, pLed); ++ ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("CurrLedState %d\n", pLed->CurrLedState)); ++ } ++ else if(check_fwstate(pmlmepriv, _FW_LINKED)== _FALSE) ++ { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ ++ if( pLed->bLedOn ) ++ SwLedOff(padapter, pLed); ++ ++ ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("CurrLedState %d\n", pLed->CurrLedState)); ++ } ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ else ++ { ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on ) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else ++ { ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ } ++ break; ++ ++ case LED_BLINK_WPS: ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); ++ break; ++ ++ case LED_BLINK_WPS_STOP: //WPS success ++ if(pLed->BlinkingLedState == RTW_LED_ON) ++ { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); ++ bStopBlinking = _FALSE; ++ } ++ else ++ { ++ bStopBlinking = _TRUE; ++ } ++ ++ if(bStopBlinking) ++ { ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on ) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else ++ { ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ SwLedOn(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("CurrLedState %d\n", pLed->CurrLedState)); ++ } ++ pLed->bLedWPSBlinkInProgress = _FALSE; ++ } ++ break; ++ ++ ++ default: ++ break; ++ } ++ ++} ++ ++ ++void ++SwLedBlink4( ++ PLED_871x pLed ++ ) ++{ ++ _adapter *padapter = pLed->padapter; ++ struct led_priv *ledpriv = &(padapter->ledpriv); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ PLED_871x pLed1 = &(ledpriv->SwLed1); ++ u8 bStopBlinking = _FALSE; ++ ++ // Change LED according to BlinkingLedState specified. ++ if( pLed->BlinkingLedState == RTW_LED_ON ) ++ { ++ SwLedOn(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); ++ } ++ else ++ { ++ SwLedOff(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); ++ } ++ ++ if(!pLed1->bLedWPSBlinkInProgress && pLed1->BlinkingLedState == LED_UNKNOWN) ++ { ++ pLed1->BlinkingLedState = RTW_LED_OFF; ++ pLed1->CurrLedState = RTW_LED_OFF; ++ SwLedOff(padapter, pLed1); ++ } ++ ++ switch(pLed->CurrLedState) ++ { ++ case LED_BLINK_SLOWLY: ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ break; ++ ++ case LED_BLINK_StartToBlink: ++ if( pLed->bLedOn ) ++ { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); ++ } ++ else ++ { ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ } ++ break; ++ ++ case LED_BLINK_SCAN: ++ pLed->BlinkTimes--; ++ if( pLed->BlinkTimes == 0 ) ++ { ++ bStopBlinking = _FALSE; ++ } ++ ++ if(bStopBlinking) ++ { ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else ++ { ++ pLed->bLedNoLinkBlinkInProgress = _FALSE; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ } ++ pLed->bLedScanBlinkInProgress = _FALSE; ++ } ++ else ++ { ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else ++ { ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ } ++ break; ++ ++ case LED_BLINK_TXRX: ++ pLed->BlinkTimes--; ++ if( pLed->BlinkTimes == 0 ) ++ { ++ bStopBlinking = _TRUE; ++ } ++ if(bStopBlinking) ++ { ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else ++ { ++ pLed->bLedNoLinkBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ } ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ else ++ { ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else ++ { ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ } ++ break; ++ ++ case LED_BLINK_WPS: ++ if( pLed->bLedOn ) ++ { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); ++ } ++ else ++ { ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ } ++ break; ++ ++ case LED_BLINK_WPS_STOP: //WPS authentication fail ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ break; ++ ++ case LED_BLINK_WPS_STOP_OVERLAP: //WPS session overlap ++ pLed->BlinkTimes--; ++ if(pLed->BlinkTimes == 0) ++ { ++ if(pLed->bLedOn) ++ { ++ pLed->BlinkTimes = 1; ++ } ++ else ++ { ++ bStopBlinking = _TRUE; ++ } ++ } ++ ++ if(bStopBlinking) ++ { ++ pLed->BlinkTimes = 10; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); ++ } ++ else ++ { ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ } ++ break; ++ ++ ++ default: ++ break; ++ } ++ ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("SwLedBlink4 CurrLedState %d\n", pLed->CurrLedState)); ++ ++ ++} ++ ++void ++SwLedBlink5( ++ PLED_871x pLed ++ ) ++{ ++ _adapter *padapter = pLed->padapter; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ u8 bStopBlinking = _FALSE; ++ ++ // Change LED according to BlinkingLedState specified. ++ if( pLed->BlinkingLedState == RTW_LED_ON ) ++ { ++ SwLedOn(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); ++ } ++ else ++ { ++ SwLedOff(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); ++ } ++ ++ switch(pLed->CurrLedState) ++ { ++ case LED_BLINK_SCAN: ++ pLed->BlinkTimes--; ++ if( pLed->BlinkTimes == 0 ) ++ { ++ bStopBlinking = _TRUE; ++ } ++ ++ if(bStopBlinking) ++ { ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) ++ { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ if(pLed->bLedOn) ++ SwLedOff(padapter, pLed); ++ } ++ else ++ { pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ if(!pLed->bLedOn) ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ ++ pLed->bLedScanBlinkInProgress = _FALSE; ++ } ++ else ++ { ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else ++ { ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ } ++ break; ++ ++ ++ case LED_BLINK_TXRX: ++ pLed->BlinkTimes--; ++ if( pLed->BlinkTimes == 0 ) ++ { ++ bStopBlinking = _TRUE; ++ } ++ ++ if(bStopBlinking) ++ { ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) ++ { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ if(pLed->bLedOn) ++ SwLedOff(padapter, pLed); ++ } ++ else ++ { ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ if(!pLed->bLedOn) ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ else ++ { ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else ++ { ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("SwLedBlink5 CurrLedState %d\n", pLed->CurrLedState)); ++ ++ ++} ++ ++void ++SwLedBlink6( ++ PLED_871x pLed ++ ) ++{ ++ _adapter *padapter = pLed->padapter; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ u8 bStopBlinking = _FALSE; ++ ++ // Change LED according to BlinkingLedState specified. ++ if( pLed->BlinkingLedState == RTW_LED_ON ) ++ { ++ SwLedOn(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); ++ } ++ else ++ { ++ SwLedOff(padapter, pLed); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); ++ } ++ ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("<==== blink6\n")); ++} ++ ++static void ++SwLedControlMode0( ++ _adapter *padapter, ++ LED_CTL_MODE LedAction ++) ++{ ++ struct led_priv *ledpriv = &(padapter->ledpriv); ++ PLED_871x pLed = &(ledpriv->SwLed1); ++ ++ // Decide led state ++ switch(LedAction) ++ { ++ case LED_CTL_TX: ++ case LED_CTL_RX: ++ if( pLed->bLedBlinkInProgress == _FALSE ) ++ { ++ pLed->bLedBlinkInProgress = _TRUE; ++ ++ pLed->CurrLedState = LED_BLINK_NORMAL; ++ pLed->BlinkTimes = 2; ++ ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ } ++ break; ++ ++ case LED_CTL_START_TO_LINK: ++ if( pLed->bLedBlinkInProgress == _FALSE ) ++ { ++ pLed->bLedBlinkInProgress = _TRUE; ++ ++ pLed->CurrLedState = LED_BLINK_StartToBlink; ++ pLed->BlinkTimes = 24; ++ ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); ++ } ++ else ++ { ++ pLed->CurrLedState = LED_BLINK_StartToBlink; ++ } ++ break; ++ ++ case LED_CTL_LINK: ++ pLed->CurrLedState = RTW_LED_ON; ++ if( pLed->bLedBlinkInProgress == _FALSE ) ++ { ++ SwLedOn(padapter, pLed); ++ } ++ break; ++ ++ case LED_CTL_NO_LINK: ++ pLed->CurrLedState = RTW_LED_OFF; ++ if( pLed->bLedBlinkInProgress == _FALSE ) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ break; ++ ++ case LED_CTL_POWER_OFF: ++ pLed->CurrLedState = RTW_LED_OFF; ++ if(pLed->bLedBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ SwLedOff(padapter, pLed); ++ break; ++ ++ case LED_CTL_START_WPS: ++ if( pLed->bLedBlinkInProgress == _FALSE || pLed->CurrLedState == RTW_LED_ON) ++ { ++ pLed->bLedBlinkInProgress = _TRUE; ++ ++ pLed->CurrLedState = LED_BLINK_WPS; ++ pLed->BlinkTimes = 20; ++ ++ if( pLed->bLedOn ) ++ { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LONG_INTERVAL); ++ } ++ else ++ { ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LONG_INTERVAL); ++ } ++ } ++ break; ++ ++ case LED_CTL_STOP_WPS: ++ if(pLed->bLedBlinkInProgress) ++ { ++ pLed->CurrLedState = RTW_LED_OFF; ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ break; ++ ++ ++ default: ++ break; ++ } ++ ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Led %d\n", pLed->CurrLedState)); ++ ++} ++ ++ //ALPHA, added by chiyoko, 20090106 ++static void ++SwLedControlMode1( ++ _adapter *padapter, ++ LED_CTL_MODE LedAction ++) ++{ ++#ifndef CONFIG_LED_REMOVE_HAL ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++#endif ++ struct led_priv *ledpriv = &(padapter->ledpriv); ++ PLED_871x pLed = &(ledpriv->SwLed0); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++#ifndef CONFIG_LED_REMOVE_HAL ++ if(pHalData->EEPROMCustomerID == RT_CID_819x_CAMEO) ++ pLed = &(ledpriv->SwLed1); ++#endif ++ ++ switch(LedAction) ++ { ++ case LED_CTL_POWER_ON: ++ case LED_CTL_START_TO_LINK: ++ case LED_CTL_NO_LINK: ++ if( pLed->bLedNoLinkBlinkInProgress == _FALSE ) ++ { ++ if(pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) ++ { ++ return; ++ } ++ if( pLed->bLedLinkBlinkInProgress == _TRUE ) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedLinkBlinkInProgress = _FALSE; ++ } ++ if(pLed->bLedBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ ++ pLed->bLedNoLinkBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ } ++ break; ++ ++ case LED_CTL_LINK: ++ if( pLed->bLedLinkBlinkInProgress == _FALSE ) ++ { ++ if(pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) ++ { ++ return; ++ } ++ if(pLed->bLedNoLinkBlinkInProgress == _TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedNoLinkBlinkInProgress = _FALSE; ++ } ++ if(pLed->bLedBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ pLed->bLedLinkBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_NORMAL; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); ++ } ++ break; ++ ++ case LED_CTL_SITE_SURVEY: ++ if((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE)) ++ ; ++ else if(pLed->bLedScanBlinkInProgress ==_FALSE) ++ { ++ if(IS_LED_WPS_BLINKING(pLed)) ++ return; ++ ++ if(pLed->bLedNoLinkBlinkInProgress == _TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedNoLinkBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedLinkBlinkInProgress == _TRUE ) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedLinkBlinkInProgress = _FALSE; ++ } ++ if(pLed->bLedBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ pLed->bLedScanBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_SCAN; ++ pLed->BlinkTimes = 24; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ break; ++ ++ case LED_CTL_TX: ++ case LED_CTL_RX: ++ if(pLed->bLedBlinkInProgress ==_FALSE) ++ { ++ if(pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) ++ { ++ return; ++ } ++ if(pLed->bLedNoLinkBlinkInProgress == _TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedNoLinkBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedLinkBlinkInProgress == _TRUE ) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedLinkBlinkInProgress = _FALSE; ++ } ++ pLed->bLedBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_TXRX; ++ pLed->BlinkTimes = 2; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ break; ++ ++ case LED_CTL_START_WPS: //wait until xinpin finish ++ case LED_CTL_START_WPS_BOTTON: ++ if(pLed->bLedWPSBlinkInProgress ==_FALSE) ++ { ++ if(pLed->bLedNoLinkBlinkInProgress == _TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedNoLinkBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedLinkBlinkInProgress == _TRUE ) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedLinkBlinkInProgress = _FALSE; ++ } ++ if(pLed->bLedBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ if(pLed->bLedScanBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedScanBlinkInProgress = _FALSE; ++ } ++ pLed->bLedWPSBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_WPS; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ break; ++ ++ ++ case LED_CTL_STOP_WPS: ++ if(pLed->bLedNoLinkBlinkInProgress == _TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedNoLinkBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedLinkBlinkInProgress == _TRUE ) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedLinkBlinkInProgress = _FALSE; ++ } ++ if(pLed->bLedBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ if(pLed->bLedScanBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedScanBlinkInProgress = _FALSE; ++ } ++ if(pLed->bLedWPSBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ } ++ else ++ { ++ pLed->bLedWPSBlinkInProgress = _TRUE; ++ } ++ ++ pLed->CurrLedState = LED_BLINK_WPS_STOP; ++ if(pLed->bLedOn) ++ { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); ++ } ++ else ++ { ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), 0); ++ } ++ break; ++ ++ case LED_CTL_STOP_WPS_FAIL: ++ if(pLed->bLedWPSBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedWPSBlinkInProgress = _FALSE; ++ } ++ ++ pLed->bLedNoLinkBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ break; ++ ++ case LED_CTL_POWER_OFF: ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ if( pLed->bLedNoLinkBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedNoLinkBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedLinkBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedLinkBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedWPSBlinkInProgress ) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedWPSBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedScanBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedScanBlinkInProgress = _FALSE; ++ } ++ ++ SwLedOff(padapter, pLed); ++ break; ++ ++ default: ++ break; ++ ++ } ++ ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Led %d\n", pLed->CurrLedState)); ++} ++ ++ //Arcadyan/Sitecom , added by chiyoko, 20090216 ++static void ++SwLedControlMode2( ++ _adapter *padapter, ++ LED_CTL_MODE LedAction ++) ++{ ++ struct led_priv *ledpriv = &(padapter->ledpriv); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ PLED_871x pLed = &(ledpriv->SwLed0); ++ ++ switch(LedAction) ++ { ++ case LED_CTL_SITE_SURVEY: ++ if(pmlmepriv->LinkDetectInfo.bBusyTraffic) ++ ; ++ else if(pLed->bLedScanBlinkInProgress ==_FALSE) ++ { ++ if(IS_LED_WPS_BLINKING(pLed)) ++ return; ++ ++ if(pLed->bLedBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ pLed->bLedScanBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_SCAN; ++ pLed->BlinkTimes = 24; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ break; ++ ++ case LED_CTL_TX: ++ case LED_CTL_RX: ++ if((pLed->bLedBlinkInProgress ==_FALSE) && (check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE)) ++ { ++ if(pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) ++ { ++ return; ++ } ++ ++ pLed->bLedBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_TXRX; ++ pLed->BlinkTimes = 2; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ break; ++ ++ case LED_CTL_LINK: ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ if( pLed->bLedBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedScanBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedScanBlinkInProgress = _FALSE; ++ } ++ ++ _set_timer(&(pLed->BlinkTimer), 0); ++ break; ++ ++ case LED_CTL_START_WPS: //wait until xinpin finish ++ case LED_CTL_START_WPS_BOTTON: ++ if(pLed->bLedWPSBlinkInProgress ==_FALSE) ++ { ++ if(pLed->bLedBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ if(pLed->bLedScanBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedScanBlinkInProgress = _FALSE; ++ } ++ pLed->bLedWPSBlinkInProgress = _TRUE; ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), 0); ++ } ++ break; ++ ++ case LED_CTL_STOP_WPS: ++ pLed->bLedWPSBlinkInProgress = _FALSE; ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else ++ { ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), 0); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("CurrLedState %d\n", pLed->CurrLedState)); ++ } ++ break; ++ ++ case LED_CTL_STOP_WPS_FAIL: ++ pLed->bLedWPSBlinkInProgress = _FALSE; ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) ++ { ++ SwLedOff(padapter, pLed); ++ } ++ else ++ { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&(pLed->BlinkTimer), 0); ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("CurrLedState %d\n", pLed->CurrLedState)); ++ } ++ break; ++ ++ case LED_CTL_START_TO_LINK: ++ case LED_CTL_NO_LINK: ++ if(!IS_LED_BLINKING(pLed)) ++ { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&(pLed->BlinkTimer), 0); ++ } ++ break; ++ ++ case LED_CTL_POWER_OFF: ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ if( pLed->bLedBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedScanBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedScanBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedWPSBlinkInProgress ) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedWPSBlinkInProgress = _FALSE; ++ } ++ ++ _set_timer(&(pLed->BlinkTimer), 0); ++ break; ++ ++ default: ++ break; ++ ++ } ++ ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("CurrLedState %d\n", pLed->CurrLedState)); ++} ++ ++ //COREGA, added by chiyoko, 20090316 ++ static void ++ SwLedControlMode3( ++ _adapter *padapter, ++ LED_CTL_MODE LedAction ++) ++{ ++ struct led_priv *ledpriv = &(padapter->ledpriv); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ PLED_871x pLed = &(ledpriv->SwLed0); ++ ++ switch(LedAction) ++ { ++ case LED_CTL_SITE_SURVEY: ++ if(pmlmepriv->LinkDetectInfo.bBusyTraffic) ++ ; ++ else if(pLed->bLedScanBlinkInProgress ==_FALSE) ++ { ++ if(IS_LED_WPS_BLINKING(pLed)) ++ return; ++ ++ if(pLed->bLedBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ pLed->bLedScanBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_SCAN; ++ pLed->BlinkTimes = 24; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ break; ++ ++ case LED_CTL_TX: ++ case LED_CTL_RX: ++ if((pLed->bLedBlinkInProgress ==_FALSE) && (check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE)) ++ { ++ if(pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) ++ { ++ return; ++ } ++ ++ pLed->bLedBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_TXRX; ++ pLed->BlinkTimes = 2; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ break; ++ ++ case LED_CTL_LINK: ++ if(IS_LED_WPS_BLINKING(pLed)) ++ return; ++ ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ if( pLed->bLedBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedScanBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedScanBlinkInProgress = _FALSE; ++ } ++ ++ _set_timer(&(pLed->BlinkTimer), 0); ++ break; ++ ++ case LED_CTL_START_WPS: //wait until xinpin finish ++ case LED_CTL_START_WPS_BOTTON: ++ if(pLed->bLedWPSBlinkInProgress ==_FALSE) ++ { ++ if(pLed->bLedBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ if(pLed->bLedScanBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedScanBlinkInProgress = _FALSE; ++ } ++ pLed->bLedWPSBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_WPS; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ break; ++ ++ case LED_CTL_STOP_WPS: ++ if(pLed->bLedWPSBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedWPSBlinkInProgress = _FALSE; ++ } ++ else ++ { ++ pLed->bLedWPSBlinkInProgress = _TRUE; ++ } ++ ++ pLed->CurrLedState = LED_BLINK_WPS_STOP; ++ if(pLed->bLedOn) ++ { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); ++ } ++ else ++ { ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), 0); ++ } ++ ++ break; ++ ++ case LED_CTL_STOP_WPS_FAIL: ++ if(pLed->bLedWPSBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedWPSBlinkInProgress = _FALSE; ++ } ++ ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&(pLed->BlinkTimer), 0); ++ break; ++ ++ case LED_CTL_START_TO_LINK: ++ case LED_CTL_NO_LINK: ++ if(!IS_LED_BLINKING(pLed)) ++ { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&(pLed->BlinkTimer), 0); ++ } ++ break; ++ ++ case LED_CTL_POWER_OFF: ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ if( pLed->bLedBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedScanBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedScanBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedWPSBlinkInProgress ) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedWPSBlinkInProgress = _FALSE; ++ } ++ ++ _set_timer(&(pLed->BlinkTimer), 0); ++ break; ++ ++ default: ++ break; ++ ++ } ++ ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("CurrLedState %d\n", pLed->CurrLedState)); ++} ++ ++ ++ //Edimax-Belkin, added by chiyoko, 20090413 ++static void ++SwLedControlMode4( ++ _adapter *padapter, ++ LED_CTL_MODE LedAction ++) ++{ ++ struct led_priv *ledpriv = &(padapter->ledpriv); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ PLED_871x pLed = &(ledpriv->SwLed0); ++ PLED_871x pLed1 = &(ledpriv->SwLed1); ++ ++ switch(LedAction) ++ { ++ case LED_CTL_START_TO_LINK: ++ if(pLed1->bLedWPSBlinkInProgress) ++ { ++ pLed1->bLedWPSBlinkInProgress = _FALSE; ++ _cancel_timer_ex(&(pLed1->BlinkTimer)); ++ ++ pLed1->BlinkingLedState = RTW_LED_OFF; ++ pLed1->CurrLedState = RTW_LED_OFF; ++ ++ if(pLed1->bLedOn) ++ _set_timer(&(pLed->BlinkTimer), 0); ++ } ++ ++ if( pLed->bLedStartToLinkBlinkInProgress == _FALSE ) ++ { ++ if(pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) ++ { ++ return; ++ } ++ if(pLed->bLedBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ if(pLed->bLedNoLinkBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedNoLinkBlinkInProgress = _FALSE; ++ } ++ ++ pLed->bLedStartToLinkBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_StartToBlink; ++ if( pLed->bLedOn ) ++ { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); ++ } ++ else ++ { ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ } ++ } ++ break; ++ ++ case LED_CTL_LINK: ++ case LED_CTL_NO_LINK: ++ //LED1 settings ++ if(LedAction == LED_CTL_LINK) ++ { ++ if(pLed1->bLedWPSBlinkInProgress) ++ { ++ pLed1->bLedWPSBlinkInProgress = _FALSE; ++ _cancel_timer_ex(&(pLed1->BlinkTimer)); ++ ++ pLed1->BlinkingLedState = RTW_LED_OFF; ++ pLed1->CurrLedState = RTW_LED_OFF; ++ ++ if(pLed1->bLedOn) ++ _set_timer(&(pLed->BlinkTimer), 0); ++ } ++ } ++ ++ if( pLed->bLedNoLinkBlinkInProgress == _FALSE ) ++ { ++ if(pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) ++ { ++ return; ++ } ++ if(pLed->bLedBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ ++ pLed->bLedNoLinkBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ } ++ break; ++ ++ case LED_CTL_SITE_SURVEY: ++ if((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE)) ++ ; ++ else if(pLed->bLedScanBlinkInProgress ==_FALSE) ++ { ++ if(IS_LED_WPS_BLINKING(pLed)) ++ return; ++ ++ if(pLed->bLedNoLinkBlinkInProgress == _TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedNoLinkBlinkInProgress = _FALSE; ++ } ++ if(pLed->bLedBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ pLed->bLedScanBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_SCAN; ++ pLed->BlinkTimes = 24; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ break; ++ ++ case LED_CTL_TX: ++ case LED_CTL_RX: ++ if(pLed->bLedBlinkInProgress ==_FALSE) ++ { ++ if(pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) ++ { ++ return; ++ } ++ if(pLed->bLedNoLinkBlinkInProgress == _TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedNoLinkBlinkInProgress = _FALSE; ++ } ++ pLed->bLedBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_TXRX; ++ pLed->BlinkTimes = 2; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ break; ++ ++ case LED_CTL_START_WPS: //wait until xinpin finish ++ case LED_CTL_START_WPS_BOTTON: ++ if(pLed1->bLedWPSBlinkInProgress) ++ { ++ pLed1->bLedWPSBlinkInProgress = _FALSE; ++ _cancel_timer_ex(&(pLed1->BlinkTimer)); ++ ++ pLed1->BlinkingLedState = RTW_LED_OFF; ++ pLed1->CurrLedState = RTW_LED_OFF; ++ ++ if(pLed1->bLedOn) ++ _set_timer(&(pLed->BlinkTimer), 0); ++ } ++ ++ if(pLed->bLedWPSBlinkInProgress ==_FALSE) ++ { ++ if(pLed->bLedNoLinkBlinkInProgress == _TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedNoLinkBlinkInProgress = _FALSE; ++ } ++ if(pLed->bLedBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ if(pLed->bLedScanBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedScanBlinkInProgress = _FALSE; ++ } ++ pLed->bLedWPSBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_WPS; ++ if( pLed->bLedOn ) ++ { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); ++ } ++ else ++ { ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ } ++ } ++ break; ++ ++ case LED_CTL_STOP_WPS: //WPS connect success ++ if(pLed->bLedWPSBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedWPSBlinkInProgress = _FALSE; ++ } ++ ++ pLed->bLedNoLinkBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ ++ break; ++ ++ case LED_CTL_STOP_WPS_FAIL: //WPS authentication fail ++ if(pLed->bLedWPSBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedWPSBlinkInProgress = _FALSE; ++ } ++ ++ pLed->bLedNoLinkBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ ++ //LED1 settings ++ if(pLed1->bLedWPSBlinkInProgress) ++ _cancel_timer_ex(&(pLed1->BlinkTimer)); ++ else ++ pLed1->bLedWPSBlinkInProgress = _TRUE; ++ ++ pLed1->CurrLedState = LED_BLINK_WPS_STOP; ++ if( pLed1->bLedOn ) ++ pLed1->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed1->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ ++ break; ++ ++ case LED_CTL_STOP_WPS_FAIL_OVERLAP: //WPS session overlap ++ if(pLed->bLedWPSBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedWPSBlinkInProgress = _FALSE; ++ } ++ ++ pLed->bLedNoLinkBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ ++ //LED1 settings ++ if(pLed1->bLedWPSBlinkInProgress) ++ _cancel_timer_ex(&(pLed1->BlinkTimer)); ++ else ++ pLed1->bLedWPSBlinkInProgress = _TRUE; ++ ++ pLed1->CurrLedState = LED_BLINK_WPS_STOP_OVERLAP; ++ pLed1->BlinkTimes = 10; ++ if( pLed1->bLedOn ) ++ pLed1->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed1->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); ++ ++ break; ++ ++ case LED_CTL_POWER_OFF: ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ ++ if( pLed->bLedNoLinkBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedNoLinkBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedLinkBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedLinkBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedWPSBlinkInProgress ) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedWPSBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedScanBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedScanBlinkInProgress = _FALSE; ++ } ++ if( pLed->bLedStartToLinkBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedStartToLinkBlinkInProgress = _FALSE; ++ } ++ ++ if( pLed1->bLedWPSBlinkInProgress ) ++ { ++ _cancel_timer_ex(&(pLed1->BlinkTimer)); ++ pLed1->bLedWPSBlinkInProgress = _FALSE; ++ } ++ ++ pLed1->BlinkingLedState = LED_UNKNOWN; ++ SwLedOff(padapter, pLed); ++ SwLedOff(padapter, pLed1); ++ break; ++ ++ default: ++ break; ++ ++ } ++ ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Led %d\n", pLed->CurrLedState)); ++} ++ ++ ++ ++ //Sercomm-Belkin, added by chiyoko, 20090415 ++static void ++SwLedControlMode5( ++ _adapter *padapter, ++ LED_CTL_MODE LedAction ++) ++{ ++#ifndef CONFIG_LED_REMOVE_HAL ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++#endif ++ struct led_priv *ledpriv = &(padapter->ledpriv); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ PLED_871x pLed = &(ledpriv->SwLed0); ++ ++#ifndef CONFIG_LED_REMOVE_HAL ++ if(pHalData->EEPROMCustomerID == RT_CID_819x_CAMEO) ++ pLed = &(ledpriv->SwLed1); ++#endif ++ ++ switch(LedAction) ++ { ++ case LED_CTL_POWER_ON: ++ case LED_CTL_NO_LINK: ++ case LED_CTL_LINK: //solid blue ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ ++ _set_timer(&(pLed->BlinkTimer), 0); ++ break; ++ ++ case LED_CTL_SITE_SURVEY: ++ if((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE)) ++ ; ++ else if(pLed->bLedScanBlinkInProgress ==_FALSE) ++ { ++ if(pLed->bLedBlinkInProgress ==_TRUE) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ pLed->bLedScanBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_SCAN; ++ pLed->BlinkTimes = 24; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ break; ++ ++ case LED_CTL_TX: ++ case LED_CTL_RX: ++ if(pLed->bLedBlinkInProgress ==_FALSE) ++ { ++ if(pLed->CurrLedState == LED_BLINK_SCAN) ++ { ++ return; ++ } ++ pLed->bLedBlinkInProgress = _TRUE; ++ pLed->CurrLedState = LED_BLINK_TXRX; ++ pLed->BlinkTimes = 2; ++ if( pLed->bLedOn ) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ break; ++ ++ case LED_CTL_POWER_OFF: ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ ++ if( pLed->bLedBlinkInProgress) ++ { ++ _cancel_timer_ex(&(pLed->BlinkTimer)); ++ pLed->bLedBlinkInProgress = _FALSE; ++ } ++ ++ SwLedOff(padapter, pLed); ++ break; ++ ++ default: ++ break; ++ ++ } ++ ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("Led %d\n", pLed->CurrLedState)); ++} ++ ++ //WNC-Corega, added by chiyoko, 20090902 ++static void ++SwLedControlMode6( ++ _adapter *padapter, ++ LED_CTL_MODE LedAction ++) ++{ ++ struct led_priv *ledpriv = &(padapter->ledpriv); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ PLED_871x pLed0 = &(ledpriv->SwLed0); ++ ++ switch(LedAction) ++ { ++ case LED_CTL_POWER_ON: ++ case LED_CTL_LINK: ++ case LED_CTL_NO_LINK: ++ _cancel_timer_ex(&(pLed0->BlinkTimer)); ++ pLed0->CurrLedState = RTW_LED_ON; ++ pLed0->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&(pLed0->BlinkTimer), 0); ++ break; ++ ++ case LED_CTL_POWER_OFF: ++ SwLedOff(padapter, pLed0); ++ break; ++ ++ default: ++ break; ++ } ++ ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("ledcontrol 6 Led %d\n", pLed0->CurrLedState)); ++} ++ ++// ++// Description: ++// Handler function of LED Blinking. ++// We dispatch acture LED blink action according to LedStrategy. ++// ++void BlinkHandler(PLED_871x pLed) ++{ ++ _adapter *padapter = pLed->padapter; ++ struct led_priv *ledpriv = &(padapter->ledpriv); ++ ++ //DBG_871X("%s (%s:%d)\n",__FUNCTION__, current->comm, current->pid); ++ ++ if( (padapter->bSurpriseRemoved == _TRUE) || ( padapter->bDriverStopped == _TRUE)) ++ { ++ //DBG_871X("%s bSurpriseRemoved:%d, bDriverStopped:%d\n", __FUNCTION__, padapter->bSurpriseRemoved, padapter->bDriverStopped); ++ return; ++ } ++ ++ switch(ledpriv->LedStrategy) ++ { ++ case SW_LED_MODE0: ++ SwLedBlink(pLed); ++ break; ++ ++ case SW_LED_MODE1: ++ SwLedBlink1(pLed); ++ break; ++ ++ case SW_LED_MODE2: ++ SwLedBlink2(pLed); ++ break; ++ ++ case SW_LED_MODE3: ++ SwLedBlink3(pLed); ++ break; ++ ++ case SW_LED_MODE4: ++ SwLedBlink4(pLed); ++ break; ++ ++ case SW_LED_MODE5: ++ SwLedBlink5(pLed); ++ break; ++ ++ case SW_LED_MODE6: ++ SwLedBlink6(pLed); ++ break; ++ ++ default: ++ //RT_TRACE(COMP_LED, DBG_LOUD, ("BlinkWorkItemCallback 0x%x \n", pHalData->LedStrategy)); ++ //SwLedBlink(pLed); ++ break; ++ } ++} ++ ++void ++LedControl871x( ++ _adapter *padapter, ++ LED_CTL_MODE LedAction ++ ) ++{ ++ struct led_priv *ledpriv = &(padapter->ledpriv); ++ ++ if( (padapter->bSurpriseRemoved == _TRUE) || ( padapter->bDriverStopped == _TRUE) ++ ||(padapter->hw_init_completed == _FALSE) ) ++ { ++ return; ++ } ++ ++ ++ if( ledpriv->bRegUseLed == _FALSE) ++ return; ++ ++ //if (!priv->up) ++ // return; ++ ++ //if(priv->bInHctTest) ++ // return; ++ ++ if( (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && ++ adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) && ++ (LedAction == LED_CTL_TX || LedAction == LED_CTL_RX || ++ LedAction == LED_CTL_SITE_SURVEY || ++ LedAction == LED_CTL_LINK || ++ LedAction == LED_CTL_NO_LINK || ++ LedAction == LED_CTL_POWER_ON) ) ++ { ++ return; ++ } ++ ++ switch(ledpriv->LedStrategy) ++ { ++ case SW_LED_MODE0: ++ //SwLedControlMode0(padapter, LedAction); ++ break; ++ ++ case SW_LED_MODE1: ++ SwLedControlMode1(padapter, LedAction); ++ break; ++ case SW_LED_MODE2: ++ SwLedControlMode2(padapter, LedAction); ++ break; ++ ++ case SW_LED_MODE3: ++ SwLedControlMode3(padapter, LedAction); ++ break; ++ ++ case SW_LED_MODE4: ++ SwLedControlMode4(padapter, LedAction); ++ break; ++ ++ case SW_LED_MODE5: ++ SwLedControlMode5(padapter, LedAction); ++ break; ++ ++ case SW_LED_MODE6: ++ SwLedControlMode6(padapter, LedAction); ++ break; ++ ++ default: ++ break; ++ } ++ ++ RT_TRACE(_module_rtl8712_led_c_,_drv_info_,("LedStrategy:%d, LedAction %d\n", ledpriv->LedStrategy,LedAction)); ++} ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_mlme.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_mlme.c +new file mode 100644 +index 00000000..f6c7581a +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_mlme.c +@@ -0,0 +1,4154 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_MLME_C_ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++extern void indicate_wx_scan_complete_event(_adapter *padapter); ++extern u8 rtw_do_join(_adapter * padapter); ++ ++#ifdef CONFIG_DISABLE_MCS13TO15 ++extern unsigned char MCS_rate_2R_MCS13TO15_OFF[16]; ++extern unsigned char MCS_rate_2R[16]; ++#else //CONFIG_DISABLE_MCS13TO15 ++extern unsigned char MCS_rate_2R[16]; ++#endif //CONFIG_DISABLE_MCS13TO15 ++extern unsigned char MCS_rate_1R[16]; ++ ++sint _rtw_init_mlme_priv (_adapter* padapter) ++{ ++ sint i; ++ u8 *pbuf; ++ struct wlan_network *pnetwork; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ sint res = _SUCCESS; ++ ++_func_enter_; ++ ++ // We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). ++ //_rtw_memset((u8 *)pmlmepriv, 0, sizeof(struct mlme_priv)); ++ ++ pmlmepriv->nic_hdl = (u8 *)padapter; ++ ++ pmlmepriv->pscanned = NULL; ++ pmlmepriv->fw_state = 0; ++ pmlmepriv->cur_network.network.InfrastructureMode = Ndis802_11AutoUnknown; ++ pmlmepriv->scan_mode=SCAN_ACTIVE;// 1: active, 0: pasive. Maybe someday we should rename this varable to "active_mode" (Jeff) ++ ++ _rtw_spinlock_init(&(pmlmepriv->lock)); ++ _rtw_init_queue(&(pmlmepriv->free_bss_pool)); ++ _rtw_init_queue(&(pmlmepriv->scanned_queue)); ++ ++ set_scanned_network_val(pmlmepriv, 0); ++ ++ _rtw_memset(&pmlmepriv->assoc_ssid,0,sizeof(NDIS_802_11_SSID)); ++ ++ pbuf = rtw_zvmalloc(MAX_BSS_CNT * (sizeof(struct wlan_network))); ++ ++ if (pbuf == NULL){ ++ res=_FAIL; ++ goto exit; ++ } ++ pmlmepriv->free_bss_buf = pbuf; ++ ++ pnetwork = (struct wlan_network *)pbuf; ++ ++ for(i = 0; i < MAX_BSS_CNT; i++) ++ { ++ _rtw_init_listhead(&(pnetwork->list)); ++ ++ rtw_list_insert_tail(&(pnetwork->list), &(pmlmepriv->free_bss_pool.queue)); ++ ++ pnetwork++; ++ } ++ ++ //allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf ++ ++ rtw_clear_scan_deny(padapter); ++ ++ #ifdef CONFIG_FTP_PROTECT ++ pmlmepriv->ftp_lock_flag = 0; ++ #endif //CONFIG_FTP_PROTECT ++ ++ rtw_init_mlme_timer(padapter); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++void rtw_mfree_mlme_priv_lock (struct mlme_priv *pmlmepriv); ++void rtw_mfree_mlme_priv_lock (struct mlme_priv *pmlmepriv) ++{ ++ _rtw_spinlock_free(&pmlmepriv->lock); ++ _rtw_spinlock_free(&(pmlmepriv->free_bss_pool.lock)); ++ _rtw_spinlock_free(&(pmlmepriv->scanned_queue.lock)); ++} ++ ++static void rtw_free_mlme_ie_data(u8 **ppie, u32 *plen) ++{ ++ if(*ppie) ++ { ++ rtw_mfree(*ppie, *plen); ++ *plen = 0; ++ *ppie=NULL; ++ } ++} ++ ++void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv) ++{ ++#if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) ++ rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len); ++ rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->wps_beacon_ie, &pmlmepriv->wps_beacon_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_req_ie, &pmlmepriv->wps_probe_req_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_resp_ie, &pmlmepriv->wps_probe_resp_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->wps_assoc_resp_ie, &pmlmepriv->wps_assoc_resp_ie_len); ++ ++ rtw_free_mlme_ie_data(&pmlmepriv->p2p_beacon_ie, &pmlmepriv->p2p_beacon_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_req_ie, &pmlmepriv->p2p_probe_req_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_resp_ie, &pmlmepriv->p2p_probe_resp_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->p2p_go_probe_resp_ie, &pmlmepriv->p2p_go_probe_resp_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->p2p_assoc_req_ie, &pmlmepriv->p2p_assoc_req_ie_len); ++#endif ++ ++#if defined(CONFIG_WFD) && defined(CONFIG_IOCTL_CFG80211) ++ rtw_free_mlme_ie_data(&pmlmepriv->wfd_beacon_ie, &pmlmepriv->wfd_beacon_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->wfd_probe_req_ie, &pmlmepriv->wfd_probe_req_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->wfd_probe_resp_ie, &pmlmepriv->wfd_probe_resp_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->wfd_go_probe_resp_ie, &pmlmepriv->wfd_go_probe_resp_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->wfd_assoc_req_ie, &pmlmepriv->wfd_assoc_req_ie_len); ++#endif ++ ++} ++ ++void _rtw_free_mlme_priv (struct mlme_priv *pmlmepriv) ++{ ++_func_enter_; ++ ++ rtw_free_mlme_priv_ie_data(pmlmepriv); ++ ++ if(pmlmepriv){ ++ rtw_mfree_mlme_priv_lock (pmlmepriv); ++ ++ if (pmlmepriv->free_bss_buf) { ++ rtw_vmfree(pmlmepriv->free_bss_buf, MAX_BSS_CNT * sizeof(struct wlan_network)); ++ } ++ } ++_func_exit_; ++} ++ ++sint _rtw_enqueue_network(_queue *queue, struct wlan_network *pnetwork) ++{ ++ _irqL irqL; ++ ++_func_enter_; ++ ++ if (pnetwork == NULL) ++ goto exit; ++ ++ _enter_critical_bh(&queue->lock, &irqL); ++ ++ rtw_list_insert_tail(&pnetwork->list, &queue->queue); ++ ++ _exit_critical_bh(&queue->lock, &irqL); ++ ++exit: ++ ++_func_exit_; ++ ++ return _SUCCESS; ++} ++ ++struct wlan_network *_rtw_dequeue_network(_queue *queue) ++{ ++ _irqL irqL; ++ ++ struct wlan_network *pnetwork; ++ ++_func_enter_; ++ ++ _enter_critical_bh(&queue->lock, &irqL); ++ ++ if (_rtw_queue_empty(queue) == _TRUE) ++ ++ pnetwork = NULL; ++ ++ else ++ { ++ pnetwork = LIST_CONTAINOR(get_next(&queue->queue), struct wlan_network, list); ++ ++ rtw_list_delete(&(pnetwork->list)); ++ } ++ ++ _exit_critical_bh(&queue->lock, &irqL); ++ ++_func_exit_; ++ ++ return pnetwork; ++} ++ ++struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv )//(_queue *free_queue) ++{ ++ _irqL irqL; ++ struct wlan_network *pnetwork; ++ _queue *free_queue = &pmlmepriv->free_bss_pool; ++ _list* plist = NULL; ++ ++_func_enter_; ++ ++ _enter_critical_bh(&free_queue->lock, &irqL); ++ ++ if (_rtw_queue_empty(free_queue) == _TRUE) { ++ pnetwork=NULL; ++ goto exit; ++ } ++ plist = get_next(&(free_queue->queue)); ++ ++ pnetwork = LIST_CONTAINOR(plist , struct wlan_network, list); ++ ++ rtw_list_delete(&pnetwork->list); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("_rtw_alloc_network: ptr=%p\n", plist)); ++ pnetwork->network_type = 0; ++ pnetwork->fixed = _FALSE; ++ pnetwork->last_scanned = rtw_get_current_time(); ++ pnetwork->aid=0; ++ pnetwork->join_res=0; ++ ++ pmlmepriv->num_of_scanned ++; ++ ++exit: ++ _exit_critical_bh(&free_queue->lock, &irqL); ++ ++_func_exit_; ++ ++ return pnetwork; ++} ++ ++void _rtw_free_network(struct mlme_priv *pmlmepriv ,struct wlan_network *pnetwork, u8 isfreeall) ++{ ++ u32 curr_time, delta_time; ++ u32 lifetime = SCANQUEUE_LIFETIME; ++ _irqL irqL; ++ _queue *free_queue = &(pmlmepriv->free_bss_pool); ++ ++_func_enter_; ++ ++ if (pnetwork == NULL) ++ goto exit; ++ ++ if (pnetwork->fixed == _TRUE) ++ goto exit; ++ ++ curr_time = rtw_get_current_time(); ++ ++ if ( (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)==_TRUE ) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)==_TRUE ) ) ++ lifetime = 1; ++ ++ if(!isfreeall) ++ { ++#ifdef PLATFORM_WINDOWS ++ ++ delta_time = (curr_time -pnetwork->last_scanned)/10; ++ ++ if(delta_time < lifetime*1000000)// unit:usec ++ { ++ goto exit; ++ } ++ ++#endif ++ ++#ifdef PLATFORM_LINUX ++ ++ delta_time = (curr_time -pnetwork->last_scanned)/HZ; ++ ++ if(delta_time < lifetime)// unit:sec ++ { ++ goto exit; ++ } ++ ++#endif ++ ++#ifdef PLATFORM_FREEBSD ++ //i think needs to check again ++ delta_time = (curr_time -pnetwork->last_scanned)/hz; ++ ++ if(delta_time < lifetime)// unit:sec ++ { ++ goto exit; ++ } ++ ++#endif ++ } ++ ++ _enter_critical_bh(&free_queue->lock, &irqL); ++ ++ rtw_list_delete(&(pnetwork->list)); ++ ++ rtw_list_insert_tail(&(pnetwork->list),&(free_queue->queue)); ++ ++ pmlmepriv->num_of_scanned --; ++ ++ ++ //DBG_871X("_rtw_free_network:SSID=%s\n", pnetwork->network.Ssid.Ssid); ++ ++ _exit_critical_bh(&free_queue->lock, &irqL); ++ ++exit: ++ ++_func_exit_; ++ ++} ++ ++void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork) ++{ ++ ++ _queue *free_queue = &(pmlmepriv->free_bss_pool); ++ ++_func_enter_; ++ ++ if (pnetwork == NULL) ++ goto exit; ++ ++ if (pnetwork->fixed == _TRUE) ++ goto exit; ++ ++ //_enter_critical(&free_queue->lock, &irqL); ++ ++ rtw_list_delete(&(pnetwork->list)); ++ ++ rtw_list_insert_tail(&(pnetwork->list), get_list_head(free_queue)); ++ ++ pmlmepriv->num_of_scanned --; ++ ++ //_exit_critical(&free_queue->lock, &irqL); ++ ++exit: ++ ++_func_exit_; ++ ++} ++ ++ ++/* ++ return the wlan_network with the matching addr ++ ++ Shall be calle under atomic context... to avoid possible racing condition... ++*/ ++struct wlan_network *_rtw_find_network(_queue *scanned_queue, u8 *addr) ++{ ++ ++ //_irqL irqL; ++ _list *phead, *plist; ++ struct wlan_network *pnetwork = NULL; ++ u8 zero_addr[ETH_ALEN] = {0,0,0,0,0,0}; ++ ++_func_enter_; ++ ++ if(_rtw_memcmp(zero_addr, addr, ETH_ALEN)){ ++ pnetwork=NULL; ++ goto exit; ++ } ++ ++ //_enter_critical_bh(&scanned_queue->lock, &irqL); ++ ++ phead = get_list_head(scanned_queue); ++ plist = get_next(phead); ++ ++ while (plist != phead) ++ { ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network ,list); ++ ++ if (_rtw_memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN) == _TRUE) ++ break; ++ ++ plist = get_next(plist); ++ } ++ ++ if(plist == phead) ++ pnetwork = NULL; ++ ++ //_exit_critical_bh(&scanned_queue->lock, &irqL); ++ ++exit: ++ ++_func_exit_; ++ ++ return pnetwork; ++ ++} ++ ++ ++void _rtw_free_network_queue(_adapter *padapter, u8 isfreeall) ++{ ++ _irqL irqL; ++ _list *phead, *plist; ++ struct wlan_network *pnetwork; ++ struct mlme_priv* pmlmepriv = &padapter->mlmepriv; ++ _queue *scanned_queue = &pmlmepriv->scanned_queue; ++ ++_func_enter_; ++ ++ ++ _enter_critical_bh(&scanned_queue->lock, &irqL); ++ ++ phead = get_list_head(scanned_queue); ++ plist = get_next(phead); ++ ++ while (rtw_end_of_queue_search(phead, plist) == _FALSE) ++ { ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ plist = get_next(plist); ++ ++ _rtw_free_network(pmlmepriv,pnetwork, isfreeall); ++ ++ } ++ ++ _exit_critical_bh(&scanned_queue->lock, &irqL); ++ ++_func_exit_; ++ ++} ++ ++ ++ ++ ++sint rtw_if_up(_adapter *padapter) { ++ ++ sint res; ++_func_enter_; ++ ++ if( padapter->bDriverStopped || padapter->bSurpriseRemoved || ++ (check_fwstate(&padapter->mlmepriv, _FW_LINKED)== _FALSE)){ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_if_up:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); ++ res=_FALSE; ++ } ++ else ++ res= _TRUE; ++ ++_func_exit_; ++ return res; ++} ++ ++ ++void rtw_generate_random_ibss(u8* pibss) ++{ ++ u32 curtime = rtw_get_current_time(); ++ ++_func_enter_; ++ pibss[0] = 0x02; //in ad-hoc mode bit1 must set to 1 ++ pibss[1] = 0x11; ++ pibss[2] = 0x87; ++ pibss[3] = (u8)(curtime & 0xff) ;//p[0]; ++ pibss[4] = (u8)((curtime>>8) & 0xff) ;//p[1]; ++ pibss[5] = (u8)((curtime>>16) & 0xff) ;//p[2]; ++_func_exit_; ++ return; ++} ++ ++u8 *rtw_get_capability_from_ie(u8 *ie) ++{ ++ return (ie + 8 + 2); ++} ++ ++ ++u16 rtw_get_capability(WLAN_BSSID_EX *bss) ++{ ++ u16 val; ++_func_enter_; ++ ++ _rtw_memcpy((u8 *)&val, rtw_get_capability_from_ie(bss->IEs), 2); ++ ++_func_exit_; ++ return le16_to_cpu(val); ++} ++ ++u8 *rtw_get_timestampe_from_ie(u8 *ie) ++{ ++ return (ie + 0); ++} ++ ++u8 *rtw_get_beacon_interval_from_ie(u8 *ie) ++{ ++ return (ie + 8); ++} ++ ++ ++int rtw_init_mlme_priv (_adapter *padapter)//(struct mlme_priv *pmlmepriv) ++{ ++ int res; ++_func_enter_; ++ res = _rtw_init_mlme_priv(padapter);// (pmlmepriv); ++_func_exit_; ++ return res; ++} ++ ++void rtw_free_mlme_priv (struct mlme_priv *pmlmepriv) ++{ ++_func_enter_; ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("rtw_free_mlme_priv\n")); ++ _rtw_free_mlme_priv (pmlmepriv); ++_func_exit_; ++} ++ ++int rtw_enqueue_network(_queue *queue, struct wlan_network *pnetwork); ++int rtw_enqueue_network(_queue *queue, struct wlan_network *pnetwork) ++{ ++ int res; ++_func_enter_; ++ res = _rtw_enqueue_network(queue, pnetwork); ++_func_exit_; ++ return res; ++} ++ ++ ++#ifndef PLATFORM_FREEBSD //Baron ++static struct wlan_network *rtw_dequeue_network(_queue *queue) ++{ ++ struct wlan_network *pnetwork; ++_func_enter_; ++ pnetwork = _rtw_dequeue_network(queue); ++_func_exit_; ++ return pnetwork; ++} ++#endif //PLATFORM_FREEBSD ++ ++struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv ); ++struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv )//(_queue *free_queue) ++{ ++ struct wlan_network *pnetwork; ++_func_enter_; ++ pnetwork = _rtw_alloc_network(pmlmepriv); ++_func_exit_; ++ return pnetwork; ++} ++ ++void rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork, u8 is_freeall); ++void rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork, u8 is_freeall)//(struct wlan_network *pnetwork, _queue *free_queue) ++{ ++_func_enter_; ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("rtw_free_network==> ssid = %s \n\n" , pnetwork->network.Ssid.Ssid)); ++ _rtw_free_network(pmlmepriv, pnetwork, is_freeall); ++_func_exit_; ++} ++ ++void rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork ); ++void rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork ) ++{ ++_func_enter_; ++ //RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("rtw_free_network==> ssid = %s \n\n" , pnetwork->network.Ssid.Ssid)); ++ _rtw_free_network_nolock(pmlmepriv, pnetwork); ++_func_exit_; ++} ++ ++ ++void rtw_free_network_queue(_adapter* dev, u8 isfreeall) ++{ ++_func_enter_; ++ _rtw_free_network_queue(dev, isfreeall); ++_func_exit_; ++} ++ ++/* ++ return the wlan_network with the matching addr ++ ++ Shall be calle under atomic context... to avoid possible racing condition... ++*/ ++struct wlan_network *rtw_find_network(_queue *scanned_queue, u8 *addr) ++{ ++ struct wlan_network *pnetwork = _rtw_find_network(scanned_queue, addr); ++ ++ return pnetwork; ++} ++ ++int rtw_is_same_ibss(_adapter *adapter, struct wlan_network *pnetwork) ++{ ++ int ret=_TRUE; ++ struct security_priv *psecuritypriv = &adapter->securitypriv; ++ ++ if ( (psecuritypriv->dot11PrivacyAlgrthm != _NO_PRIVACY_ ) && ++ ( pnetwork->network.Privacy == 0 ) ) ++ { ++ ret=_FALSE; ++ } ++ else if((psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_ ) && ++ ( pnetwork->network.Privacy == 1 ) ) ++ { ++ ret=_FALSE; ++ } ++ else ++ { ++ ret=_TRUE; ++ } ++ ++ return ret; ++ ++} ++ ++inline int is_same_ess(WLAN_BSSID_EX *a, WLAN_BSSID_EX *b); ++inline int is_same_ess(WLAN_BSSID_EX *a, WLAN_BSSID_EX *b) ++{ ++ //RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("(%s,%d)(%s,%d)\n", ++ // a->Ssid.Ssid,a->Ssid.SsidLength,b->Ssid.Ssid,b->Ssid.SsidLength)); ++ return (a->Ssid.SsidLength == b->Ssid.SsidLength) ++ && _rtw_memcmp(a->Ssid.Ssid, b->Ssid.Ssid, a->Ssid.SsidLength)==_TRUE; ++} ++ ++int is_same_network(WLAN_BSSID_EX *src, WLAN_BSSID_EX *dst, u8 feature) ++{ ++ u16 s_cap, d_cap; ++ ++_func_enter_; ++ ++#ifdef PLATFORM_OS_XP ++ if ( ((uint)dst) <= 0x7fffffff || ++ ((uint)src) <= 0x7fffffff || ++ ((uint)&s_cap) <= 0x7fffffff || ++ ((uint)&d_cap) <= 0x7fffffff) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("\n@@@@ error address of dst\n")); ++ ++ KeBugCheckEx(0x87110000, (ULONG_PTR)dst, (ULONG_PTR)src,(ULONG_PTR)&s_cap, (ULONG_PTR)&d_cap); ++ ++ return _FALSE; ++ } ++#endif ++ ++ ++ _rtw_memcpy((u8 *)&s_cap, rtw_get_capability_from_ie(src->IEs), 2); ++ _rtw_memcpy((u8 *)&d_cap, rtw_get_capability_from_ie(dst->IEs), 2); ++ ++ ++ s_cap = le16_to_cpu(s_cap); ++ d_cap = le16_to_cpu(d_cap); ++ ++_func_exit_; ++ ++#ifdef CONFIG_P2P ++ if ((feature == 1) && // 1: P2P supported ++ (_rtw_memcmp(src->MacAddress, dst->MacAddress, ETH_ALEN) == _TRUE) ++ ) { ++ return _TRUE; ++ } ++#endif ++ ++ return ((src->Ssid.SsidLength == dst->Ssid.SsidLength) && ++ // (src->Configuration.DSConfig == dst->Configuration.DSConfig) && ++ ( (_rtw_memcmp(src->MacAddress, dst->MacAddress, ETH_ALEN)) == _TRUE) && ++ ( (_rtw_memcmp(src->Ssid.Ssid, dst->Ssid.Ssid, src->Ssid.SsidLength)) == _TRUE) && ++ ((s_cap & WLAN_CAPABILITY_IBSS) == ++ (d_cap & WLAN_CAPABILITY_IBSS)) && ++ ((s_cap & WLAN_CAPABILITY_BSS) == ++ (d_cap & WLAN_CAPABILITY_BSS))); ++ ++} ++ ++struct wlan_network * rtw_get_oldest_wlan_network(_queue *scanned_queue) ++{ ++ _list *plist, *phead; ++ ++ ++ struct wlan_network *pwlan = NULL; ++ struct wlan_network *oldest = NULL; ++_func_enter_; ++ phead = get_list_head(scanned_queue); ++ ++ plist = get_next(phead); ++ ++ while(1) ++ { ++ ++ if (rtw_end_of_queue_search(phead,plist)== _TRUE) ++ break; ++ ++ pwlan= LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ if(pwlan->fixed!=_TRUE) ++ { ++ if (oldest == NULL ||time_after(oldest->last_scanned, pwlan->last_scanned)) ++ oldest = pwlan; ++ } ++ ++ plist = get_next(plist); ++ } ++_func_exit_; ++ return oldest; ++ ++} ++ ++void update_network(WLAN_BSSID_EX *dst, WLAN_BSSID_EX *src, ++ _adapter * padapter, bool update_ie) ++{ ++ u8 ss_ori = dst->PhyInfo.SignalStrength; ++ u8 sq_ori = dst->PhyInfo.SignalQuality; ++ long rssi_ori = dst->Rssi; ++ ++ u8 ss_smp = src->PhyInfo.SignalStrength; ++ u8 sq_smp = src->PhyInfo.SignalQuality; ++ long rssi_smp = src->Rssi; ++ ++ u8 ss_final; ++ u8 sq_final; ++ long rssi_final; ++ ++_func_enter_; ++ ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ rtw_hal_antdiv_rssi_compared(padapter, dst, src); //this will update src.Rssi, need consider again ++#endif ++ ++ #if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) && 1 ++ if(strcmp(dst->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) { ++ DBG_871X(FUNC_ADPT_FMT" %s("MAC_FMT", ch%u) ss_ori:%3u, sq_ori:%3u, rssi_ori:%3ld, ss_smp:%3u, sq_smp:%3u, rssi_smp:%3ld\n" ++ , FUNC_ADPT_ARG(padapter) ++ , src->Ssid.Ssid, MAC_ARG(src->MacAddress), src->Configuration.DSConfig ++ ,ss_ori, sq_ori, rssi_ori ++ ,ss_smp, sq_smp, rssi_smp ++ ); ++ } ++ #endif ++ ++ /* The rule below is 1/5 for sample value, 4/5 for history value */ ++ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network(&(padapter->mlmepriv.cur_network.network), src, 0)) { ++ /* Take the recvpriv's value for the connected AP*/ ++ ss_final = padapter->recvpriv.signal_strength; ++ sq_final = padapter->recvpriv.signal_qual; ++ /* the rssi value here is undecorated, and will be used for antenna diversity */ ++ if(sq_smp != 101) /* from the right channel */ ++ rssi_final = (src->Rssi+dst->Rssi*4)/5; ++ else ++ rssi_final = rssi_ori; ++ } ++ else { ++ if(sq_smp != 101) { /* from the right channel */ ++ ss_final = ((u32)(src->PhyInfo.SignalStrength)+(u32)(dst->PhyInfo.SignalStrength)*4)/5; ++ sq_final = ((u32)(src->PhyInfo.SignalQuality)+(u32)(dst->PhyInfo.SignalQuality)*4)/5; ++ rssi_final = (src->Rssi+dst->Rssi*4)/5; ++ } else { ++ /* bss info not receving from the right channel, use the original RX signal infos */ ++ ss_final = dst->PhyInfo.SignalStrength; ++ sq_final = dst->PhyInfo.SignalQuality; ++ rssi_final = dst->Rssi; ++ } ++ ++ } ++ ++ if (update_ie) { ++ dst->Reserved[0] = src->Reserved[0]; ++ dst->Reserved[1] = src->Reserved[1]; ++ _rtw_memcpy((u8 *)dst, (u8 *)src, get_WLAN_BSSID_EX_sz(src)); ++ } ++ ++ dst->PhyInfo.SignalStrength = ss_final; ++ dst->PhyInfo.SignalQuality = sq_final; ++ dst->Rssi = rssi_final; ++ ++ #if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) && 1 ++ if(strcmp(dst->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) { ++ DBG_871X(FUNC_ADPT_FMT" %s("MAC_FMT"), SignalStrength:%u, SignalQuality:%u, RawRSSI:%ld\n" ++ , FUNC_ADPT_ARG(padapter) ++ , dst->Ssid.Ssid, MAC_ARG(dst->MacAddress), dst->PhyInfo.SignalStrength, dst->PhyInfo.SignalQuality, dst->Rssi); ++ } ++ #endif ++ ++#if 0 // old codes, may be useful one day... ++// DBG_871X("update_network: rssi=0x%lx dst->Rssi=%d ,dst->Rssi=0x%lx , src->Rssi=0x%lx",(dst->Rssi+src->Rssi)/2,dst->Rssi,dst->Rssi,src->Rssi); ++ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network(&(padapter->mlmepriv.cur_network.network), src, 0)) ++ { ++ ++ //DBG_871X("b:ssid=%s update_network: src->rssi=0x%d padapter->recvpriv.ui_rssi=%d\n",src->Ssid.Ssid,src->Rssi,padapter->recvpriv.signal); ++ if(padapter->recvpriv.signal_qual_data.total_num++ >= PHY_LINKQUALITY_SLID_WIN_MAX) ++ { ++ padapter->recvpriv.signal_qual_data.total_num = PHY_LINKQUALITY_SLID_WIN_MAX; ++ last_evm = padapter->recvpriv.signal_qual_data.elements[padapter->recvpriv.signal_qual_data.index]; ++ padapter->recvpriv.signal_qual_data.total_val -= last_evm; ++ } ++ padapter->recvpriv.signal_qual_data.total_val += query_rx_pwr_percentage(src->Rssi); ++ ++ padapter->recvpriv.signal_qual_data.elements[padapter->recvpriv.signal_qual_data.index++] = query_rx_pwr_percentage(src->Rssi); ++ if(padapter->recvpriv.signal_qual_data.index >= PHY_LINKQUALITY_SLID_WIN_MAX) ++ padapter->recvpriv.signal_qual_data.index = 0; ++ ++ //DBG_871X("Total SQ=%d pattrib->signal_qual= %d\n", padapter->recvpriv.signal_qual_data.total_val, src->Rssi); ++ ++ // <1> Showed on UI for user,in percentage. ++ tmpVal = padapter->recvpriv.signal_qual_data.total_val/padapter->recvpriv.signal_qual_data.total_num; ++ padapter->recvpriv.signal=(u8)tmpVal;//Link quality ++ ++ src->Rssi= translate_percentage_to_dbm(padapter->recvpriv.signal) ; ++ } ++ else{ ++// DBG_871X("ELSE:ssid=%s update_network: src->rssi=0x%d dst->rssi=%d\n",src->Ssid.Ssid,src->Rssi,dst->Rssi); ++ src->Rssi=(src->Rssi +dst->Rssi)/2;//dBM ++ } ++ ++// DBG_871X("a:update_network: src->rssi=0x%d padapter->recvpriv.ui_rssi=%d\n",src->Rssi,padapter->recvpriv.signal); ++ ++#endif ++ ++_func_exit_; ++} ++ ++static void update_current_network(_adapter *adapter, WLAN_BSSID_EX *pnetwork) ++{ ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ ++_func_enter_; ++ ++#ifdef PLATFORM_OS_XP ++ if ((unsigned long)(&(pmlmepriv->cur_network.network)) < 0x7ffffff) ++ { ++ KeBugCheckEx(0x87111c1c, (ULONG_PTR)(&(pmlmepriv->cur_network.network)), 0, 0,0); ++ } ++#endif ++ ++ if ( (check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE) && (is_same_network(&(pmlmepriv->cur_network.network), pnetwork, 0))) ++ { ++ //RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,"Same Network\n"); ++ ++ //if(pmlmepriv->cur_network.network.IELength<= pnetwork->IELength) ++ { ++ update_network(&(pmlmepriv->cur_network.network), pnetwork,adapter, _TRUE); ++ rtw_update_protection(adapter, (pmlmepriv->cur_network.network.IEs) + sizeof (NDIS_802_11_FIXED_IEs), ++ pmlmepriv->cur_network.network.IELength); ++ } ++ } ++ ++_func_exit_; ++ ++} ++ ++ ++/* ++ ++Caller must hold pmlmepriv->lock first. ++ ++ ++*/ ++void rtw_update_scanned_network(_adapter *adapter, WLAN_BSSID_EX *target) ++{ ++ _irqL irqL; ++ _list *plist, *phead; ++ ULONG bssid_ex_sz; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv); ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo= &(adapter->wdinfo); ++#endif ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ struct wlan_network *oldest = NULL; ++ int target_find = 0; ++ u8 feature = 0; ++ ++_func_enter_; ++ ++ _enter_critical_bh(&queue->lock, &irqL); ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++#ifdef CONFIG_P2P ++ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ feature = 1; // p2p enable ++#endif ++ ++ while(1) ++ { ++ if (rtw_end_of_queue_search(phead,plist)== _TRUE) ++ break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ if ((unsigned long)(pnetwork) < 0x7ffffff) ++ { ++#ifdef PLATFORM_OS_XP ++ KeBugCheckEx(0x87111c1c, (ULONG_PTR)pnetwork, 0, 0,0); ++#endif ++ } ++ ++ if (is_same_network(&(pnetwork->network), target, feature)) { ++ target_find = 1; ++ break; ++ } ++ ++ if ((oldest == ((struct wlan_network *)0)) || ++ time_after(oldest->last_scanned, pnetwork->last_scanned)) ++ oldest = pnetwork; ++ ++ plist = get_next(plist); ++ ++ } ++ ++ ++ /* If we didn't find a match, then get a new network slot to initialize ++ * with this beacon's information */ ++ //if (rtw_end_of_queue_search(phead,plist)== _TRUE) { ++ if (!target_find) { ++ ++ if (_rtw_queue_empty(&(pmlmepriv->free_bss_pool)) == _TRUE) { ++ /* If there are no more slots, expire the oldest */ ++ //list_del_init(&oldest->list); ++ pnetwork = oldest; ++ ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ //target->PhyInfo.Optimum_antenna = pHalData->CurAntenna;//optimum_antenna=>For antenna diversity ++ rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &(target->PhyInfo.Optimum_antenna)); ++#endif ++ _rtw_memcpy(&(pnetwork->network), target, get_WLAN_BSSID_EX_sz(target)); ++ //pnetwork->last_scanned = rtw_get_current_time(); ++ // variable initialize ++ pnetwork->fixed = _FALSE; ++ pnetwork->last_scanned = rtw_get_current_time(); ++ ++ pnetwork->network_type = 0; ++ pnetwork->aid=0; ++ pnetwork->join_res=0; ++ ++ /* bss info not receving from the right channel */ ++ if (pnetwork->network.PhyInfo.SignalQuality == 101) ++ pnetwork->network.PhyInfo.SignalQuality = 0; ++ } ++ else { ++ /* Otherwise just pull from the free list */ ++ ++ pnetwork = rtw_alloc_network(pmlmepriv); // will update scan_time ++ ++ if(pnetwork==NULL){ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("\n\n\nsomething wrong here\n\n\n")); ++ goto exit; ++ } ++ ++ bssid_ex_sz = get_WLAN_BSSID_EX_sz(target); ++ target->Length = bssid_ex_sz; ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ //target->PhyInfo.Optimum_antenna = pHalData->CurAntenna; ++ rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &(target->PhyInfo.Optimum_antenna)); ++#endif ++ _rtw_memcpy(&(pnetwork->network), target, bssid_ex_sz ); ++ ++ pnetwork->last_scanned = rtw_get_current_time(); ++ ++ /* bss info not receving from the right channel */ ++ if (pnetwork->network.PhyInfo.SignalQuality == 101) ++ pnetwork->network.PhyInfo.SignalQuality = 0; ++ ++ rtw_list_insert_tail(&(pnetwork->list),&(queue->queue)); ++ ++ } ++ } ++ else { ++ /* we have an entry and we are going to update it. But this entry may ++ * be already expired. In this case we do the same as we found a new ++ * net and call the new_net handler ++ */ ++ bool update_ie = _TRUE; ++ ++ pnetwork->last_scanned = rtw_get_current_time(); ++ ++ //target.Reserved[0]==1, means that scaned network is a bcn frame. ++ // probe resp(3) > beacon(1) > probe req(2) ++ if ((target->Reserved[0] != 2) && ++ (target->Reserved[0] >= pnetwork->network.Reserved[0]) ++ ) { ++ update_ie = _TRUE; ++ } ++ else { ++ update_ie = _FALSE; ++ } ++ ++ update_network(&(pnetwork->network), target,adapter, update_ie); ++ } ++ ++exit: ++ _exit_critical_bh(&queue->lock, &irqL); ++ ++_func_exit_; ++} ++ ++void rtw_add_network(_adapter *adapter, WLAN_BSSID_EX *pnetwork); ++void rtw_add_network(_adapter *adapter, WLAN_BSSID_EX *pnetwork) ++{ ++ _irqL irqL; ++ struct mlme_priv *pmlmepriv = &(((_adapter *)adapter)->mlmepriv); ++ //_queue *queue = &(pmlmepriv->scanned_queue); ++ ++_func_enter_; ++ ++ //_enter_critical_bh(&queue->lock, &irqL); ++ ++ #if defined(CONFIG_P2P) && defined(CONFIG_P2P_REMOVE_GROUP_INFO) ++ rtw_WLAN_BSSID_EX_remove_p2p_attr(pnetwork, P2P_ATTR_GROUP_INFO); ++ #endif ++ ++ update_current_network(adapter, pnetwork); ++ ++ rtw_update_scanned_network(adapter, pnetwork); ++ ++ //_exit_critical_bh(&queue->lock, &irqL); ++ ++_func_exit_; ++} ++ ++//select the desired network based on the capability of the (i)bss. ++// check items: (1) security ++// (2) network_type ++// (3) WMM ++// (4) HT ++// (5) others ++int rtw_is_desired_network(_adapter *adapter, struct wlan_network *pnetwork); ++int rtw_is_desired_network(_adapter *adapter, struct wlan_network *pnetwork) ++{ ++ struct security_priv *psecuritypriv = &adapter->securitypriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ u32 desired_encmode; ++ u32 privacy; ++ ++ //u8 wps_ie[512]; ++ uint wps_ielen; ++ ++ int bselected = _TRUE; ++ ++ desired_encmode = psecuritypriv->ndisencryptstatus; ++ privacy = pnetwork->network.Privacy; ++ ++ if(check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) ++ { ++ if(rtw_get_wps_ie(pnetwork->network.IEs+_FIXED_IE_LENGTH_, pnetwork->network.IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen)!=NULL) ++ { ++ return _TRUE; ++ } ++ else ++ { ++ return _FALSE; ++ } ++ } ++ if (adapter->registrypriv.wifi_spec == 1) //for correct flow of 8021X to do.... ++ { ++ u8 *p=NULL; ++ uint ie_len=0; ++ ++ if ((desired_encmode == Ndis802_11EncryptionDisabled) && (privacy != 0)) ++ bselected = _FALSE; ++ ++ if ( psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPA2PSK) { ++ p = rtw_get_ie(pnetwork->network.IEs + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pnetwork->network.IELength - _BEACON_IE_OFFSET_)); ++ if (p && ie_len>0) { ++ bselected = _TRUE; ++ } else { ++ bselected = _FALSE; ++ } ++ } ++ } ++ ++ ++ if ((desired_encmode != Ndis802_11EncryptionDisabled) && (privacy == 0)) { ++ DBG_871X("desired_encmode: %d, privacy: %d\n", desired_encmode, privacy); ++ bselected = _FALSE; ++ } ++ ++ if(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) ++ { ++ if(pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode) ++ bselected = _FALSE; ++ } ++ ++ ++ return bselected; ++} ++ ++/* TODO: Perry : For Power Management */ ++void rtw_atimdone_event_callback(_adapter *adapter , u8 *pbuf) ++{ ++ ++_func_enter_; ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("receive atimdone_evet\n")); ++_func_exit_; ++ return; ++} ++ ++ ++void rtw_survey_event_callback(_adapter *adapter, u8 *pbuf) ++{ ++ _irqL irqL; ++ u32 len; ++ WLAN_BSSID_EX *pnetwork; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ ++_func_enter_; ++ ++ pnetwork = (WLAN_BSSID_EX *)pbuf; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_survey_event_callback, ssid=%s\n", pnetwork->Ssid.Ssid)); ++ ++#ifdef CONFIG_RTL8712 ++ //endian_convert ++ pnetwork->Length = le32_to_cpu(pnetwork->Length); ++ pnetwork->Ssid.SsidLength = le32_to_cpu(pnetwork->Ssid.SsidLength); ++ pnetwork->Privacy =le32_to_cpu( pnetwork->Privacy); ++ pnetwork->Rssi = le32_to_cpu(pnetwork->Rssi); ++ pnetwork->NetworkTypeInUse =le32_to_cpu(pnetwork->NetworkTypeInUse); ++ pnetwork->Configuration.ATIMWindow = le32_to_cpu(pnetwork->Configuration.ATIMWindow); ++ pnetwork->Configuration.BeaconPeriod = le32_to_cpu(pnetwork->Configuration.BeaconPeriod); ++ pnetwork->Configuration.DSConfig =le32_to_cpu(pnetwork->Configuration.DSConfig); ++ pnetwork->Configuration.FHConfig.DwellTime=le32_to_cpu(pnetwork->Configuration.FHConfig.DwellTime); ++ pnetwork->Configuration.FHConfig.HopPattern=le32_to_cpu(pnetwork->Configuration.FHConfig.HopPattern); ++ pnetwork->Configuration.FHConfig.HopSet=le32_to_cpu(pnetwork->Configuration.FHConfig.HopSet); ++ pnetwork->Configuration.FHConfig.Length=le32_to_cpu(pnetwork->Configuration.FHConfig.Length); ++ pnetwork->Configuration.Length = le32_to_cpu(pnetwork->Configuration.Length); ++ pnetwork->InfrastructureMode = le32_to_cpu(pnetwork->InfrastructureMode); ++ pnetwork->IELength = le32_to_cpu(pnetwork->IELength); ++#endif ++ ++ len = get_WLAN_BSSID_EX_sz(pnetwork); ++ if(len > (sizeof(WLAN_BSSID_EX))) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("\n ****rtw_survey_event_callback: return a wrong bss ***\n")); ++ return; ++ } ++ ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ // update IBSS_network 's timestamp ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == _TRUE) ++ { ++ //RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,"rtw_survey_event_callback : WIFI_ADHOC_MASTER_STATE \n\n"); ++ if(_rtw_memcmp(&(pmlmepriv->cur_network.network.MacAddress), pnetwork->MacAddress, ETH_ALEN)) ++ { ++ struct wlan_network* ibss_wlan = NULL; ++ _irqL irqL; ++ ++ _rtw_memcpy(pmlmepriv->cur_network.network.IEs, pnetwork->IEs, 8); ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ibss_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->MacAddress); ++ if(ibss_wlan) ++ { ++ _rtw_memcpy(ibss_wlan->network.IEs , pnetwork->IEs, 8); ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ goto exit; ++ } ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ } ++ } ++ ++ // lock pmlmepriv->lock when you accessing network_q ++ if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == _FALSE) ++ { ++ if( pnetwork->Ssid.Ssid[0] == 0 ) ++ { ++ pnetwork->Ssid.SsidLength = 0; ++ } ++ rtw_add_network(adapter, pnetwork); ++ } ++ ++exit: ++ ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++_func_exit_; ++ ++ return; ++} ++ ++ ++ ++void rtw_surveydone_event_callback(_adapter *adapter, u8 *pbuf) ++{ ++ _irqL irqL; ++ u8 timer_cancelled = _FALSE; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ ++#ifdef CONFIG_MLME_EXT ++ ++ mlmeext_surveydone_event_callback(adapter); ++ ++#endif ++ ++_func_enter_; ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ if(pmlmepriv->wps_probe_req_ie) ++ { ++ u32 free_len = pmlmepriv->wps_probe_req_ie_len; ++ pmlmepriv->wps_probe_req_ie_len = 0; ++ rtw_mfree(pmlmepriv->wps_probe_req_ie, free_len); ++ pmlmepriv->wps_probe_req_ie = NULL; ++ } ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_surveydone_event_callback: fw_state:%x\n\n", get_fwstate(pmlmepriv))); ++ ++ if (check_fwstate(pmlmepriv,_FW_UNDER_SURVEY)) ++ { ++ //u8 timer_cancelled; ++ ++ timer_cancelled = _TRUE; ++ //_cancel_timer(&pmlmepriv->scan_to_timer, &timer_cancelled); ++ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); ++ } ++ else { ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("nic status =%x, survey done event comes too late!\n", get_fwstate(pmlmepriv))); ++ } ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ if(timer_cancelled) ++ _cancel_timer(&pmlmepriv->scan_to_timer, &timer_cancelled); ++ ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ #ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS ++ rtw_set_signal_stat_timer(&adapter->recvpriv); ++ #endif ++ ++ if(pmlmepriv->to_join == _TRUE) ++ { ++ if((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)==_TRUE) ) ++ { ++ if(check_fwstate(pmlmepriv, _FW_LINKED)==_FALSE) ++ { ++ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); ++ ++ if(rtw_select_and_join_from_scanned_queue(pmlmepriv)==_SUCCESS) ++ { ++ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT ); ++ } ++ else ++ { ++ WLAN_BSSID_EX *pdev_network = &(adapter->registrypriv.dev_network); ++ u8 *pibss = adapter->registrypriv.dev_network.MacAddress; ++ ++ //pmlmepriv->fw_state ^= _FW_UNDER_SURVEY;//because don't set assoc_timer ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("switching to adhoc master\n")); ++ ++ _rtw_memset(&pdev_network->Ssid, 0, sizeof(NDIS_802_11_SSID)); ++ _rtw_memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(NDIS_802_11_SSID)); ++ ++ rtw_update_registrypriv_dev_network(adapter); ++ rtw_generate_random_ibss(pibss); ++ ++ pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; ++ ++ if(rtw_createbss_cmd(adapter)!=_SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Error=>rtw_createbss_cmd status FAIL\n")); ++ } ++ ++ pmlmepriv->to_join = _FALSE; ++ } ++ } ++ } ++ else ++ { ++ int s_ret; ++ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); ++ pmlmepriv->to_join = _FALSE; ++ if(_SUCCESS == (s_ret=rtw_select_and_join_from_scanned_queue(pmlmepriv))) ++ { ++ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); ++ } ++ else if(s_ret == 2)//there is no need to wait for join ++ { ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ rtw_indicate_connect(adapter); ++ } ++ else ++ { ++ DBG_871X("try_to_join, but select scanning queue fail, to_roaming:%d\n", rtw_to_roaming(adapter)); ++ #ifdef CONFIG_LAYER2_ROAMING ++ if (rtw_to_roaming(adapter) != 0) { ++ if( --pmlmepriv->to_roaming == 0 ++ || _SUCCESS != rtw_sitesurvey_cmd(adapter, &pmlmepriv->assoc_ssid, 1, NULL, 0) ++ ) { ++ rtw_set_roaming(adapter, 0); ++#ifdef CONFIG_INTEL_WIDI ++ if(adapter->mlmepriv.widi_state == INTEL_WIDI_STATE_ROAMING) ++ { ++ _rtw_memset(pmlmepriv->sa_ext, 0x00, L2SDTA_SERVICE_VE_LEN); ++ intel_widi_wk_cmd(adapter, INTEL_WIDI_LISTEN_WK, NULL); ++ DBG_871X("change to widi listen\n"); ++ } ++#endif // CONFIG_INTEL_WIDI ++ rtw_free_assoc_resources(adapter, 1); ++ rtw_indicate_disconnect(adapter); ++ } else { ++ pmlmepriv->to_join = _TRUE; ++ } ++ } ++ else ++ #endif ++ { ++ rtw_indicate_disconnect(adapter); ++ } ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ } ++ } ++ } ++ ++ indicate_wx_scan_complete_event(adapter); ++ //DBG_871X("scan complete in %dms\n",rtw_get_passing_time_ms(pmlmepriv->scan_start_time)); ++ ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++#ifdef CONFIG_P2P_PS ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { ++ p2p_ps_wk_cmd(adapter, P2P_PS_SCAN_DONE, 0); ++ } ++#endif // CONFIG_P2P_PS ++ ++ rtw_os_xmit_schedule(adapter); ++#ifdef CONFIG_CONCURRENT_MODE ++ rtw_os_xmit_schedule(adapter->pbuddy_adapter); ++#endif ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ dc_resume_xmit(adapter); ++#endif ++ ++#ifdef CONFIG_DRVEXT_MODULE_WSC ++ drvext_surveydone_callback(&adapter->drvextpriv); ++#endif ++ ++#ifdef DBG_CONFIG_ERROR_DETECT ++ { ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ if(pmlmeext->sitesurvey_res.bss_cnt == 0){ ++ //rtw_hal_sreset_reset(adapter); ++ } ++ } ++#endif ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ rtw_cfg80211_surveydone_event_callback(adapter); ++#endif //CONFIG_IOCTL_CFG80211 ++ ++_func_exit_; ++ ++} ++ ++void rtw_dummy_event_callback(_adapter *adapter , u8 *pbuf) ++{ ++ ++} ++ ++void rtw_fwdbg_event_callback(_adapter *adapter , u8 *pbuf) ++{ ++ ++} ++ ++static void free_scanqueue(struct mlme_priv *pmlmepriv) ++{ ++ _irqL irqL, irqL0; ++ _queue *free_queue = &pmlmepriv->free_bss_pool; ++ _queue *scan_queue = &pmlmepriv->scanned_queue; ++ _list *plist, *phead, *ptemp; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+free_scanqueue\n")); ++ _enter_critical_bh(&scan_queue->lock, &irqL0); ++ _enter_critical_bh(&free_queue->lock, &irqL); ++ ++ phead = get_list_head(scan_queue); ++ plist = get_next(phead); ++ ++ while (plist != phead) ++ { ++ ptemp = get_next(plist); ++ rtw_list_delete(plist); ++ rtw_list_insert_tail(plist, &free_queue->queue); ++ plist =ptemp; ++ pmlmepriv->num_of_scanned --; ++ } ++ ++ _exit_critical_bh(&free_queue->lock, &irqL); ++ _exit_critical_bh(&scan_queue->lock, &irqL0); ++ ++_func_exit_; ++} ++ ++/* ++*rtw_free_assoc_resources: the caller has to lock pmlmepriv->lock ++*/ ++void rtw_free_assoc_resources(_adapter *adapter, int lock_scanned_queue) ++{ ++ _irqL irqL; ++ struct wlan_network* pwlan = NULL; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct wlan_network *tgt_network = &pmlmepriv->cur_network; ++ ++#ifdef CONFIG_TDLS ++ struct tdls_info *ptdlsinfo = &adapter->tdlsinfo; ++#endif //CONFIG_TDLS ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_free_assoc_resources\n")); ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("tgt_network->network.MacAddress="MAC_FMT" ssid=%s\n", ++ MAC_ARG(tgt_network->network.MacAddress), tgt_network->network.Ssid.Ssid)); ++ ++ if(check_fwstate( pmlmepriv, WIFI_STATION_STATE|WIFI_AP_STATE)) ++ { ++ struct sta_info* psta; ++ ++ psta = rtw_get_stainfo(&adapter->stapriv, tgt_network->network.MacAddress); ++ ++#ifdef CONFIG_TDLS ++ if(ptdlsinfo->setup_state != TDLS_STATE_NONE) ++ { ++ rtw_tdls_cmd(adapter, myid(&(adapter->eeprompriv)), TDLS_RS_RCR); ++ rtw_reset_tdls_info(adapter); ++ rtw_free_all_stainfo(adapter); ++ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ } ++ else ++#endif //CONFIG_TDLS ++ { ++ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ rtw_free_stainfo(adapter, psta); ++ } ++ ++ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ ++ } ++ ++ if(check_fwstate( pmlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE)) ++ { ++ struct sta_info* psta; ++ ++ rtw_free_all_stainfo(adapter); ++ ++ psta = rtw_get_bcmc_stainfo(adapter); ++ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ rtw_free_stainfo(adapter, psta); ++ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ ++ rtw_init_bcmc_stainfo(adapter); ++ } ++ ++ if(lock_scanned_queue) ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); ++ if(pwlan) ++ { ++ pwlan->fixed = _FALSE; ++#ifdef CONFIG_P2P ++ if(!rtw_p2p_chk_state(&adapter->wdinfo, P2P_STATE_NONE)) ++ { ++ u32 p2p_ielen=0; ++ u8 *p2p_ie; ++ //u16 capability; ++ u8 *pcap = NULL; ++ u32 capability_len=0; ++ ++ //DBG_871X("free disconnecting network\n"); ++ //rtw_free_network_nolock(pmlmepriv, pwlan); ++ ++ if((p2p_ie=rtw_get_p2p_ie(pwlan->network.IEs+_FIXED_IE_LENGTH_, pwlan->network.IELength-_FIXED_IE_LENGTH_, NULL, &p2p_ielen))) ++ { ++ pcap = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, NULL, &capability_len); ++ if(pcap && capability_len==2) ++ { ++ u16 cap = *(u16*)pcap ; ++ *(u16*)pcap = cap&0x00ff;//clear group capability when free this network ++ } ++ } ++ ++ rtw_set_scan_deny(adapter, 2000); ++ //rtw_clear_scan_deny(adapter); ++ } ++#endif //CONFIG_P2P ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("rtw_free_assoc_resources : pwlan== NULL \n\n")); ++ } ++ ++ ++ if((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && (adapter->stapriv.asoc_sta_count== 1)) ++ /*||check_fwstate(pmlmepriv, WIFI_STATION_STATE)*/) ++ { ++ rtw_free_network_nolock(pmlmepriv, pwlan); ++ } ++ ++ if(lock_scanned_queue) ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ adapter->securitypriv.key_mask = 0; ++ ++_func_exit_; ++ ++} ++ ++/* ++*rtw_indicate_connect: the caller has to lock pmlmepriv->lock ++*/ ++void rtw_indicate_connect(_adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_connect\n")); ++ ++ pmlmepriv->to_join = _FALSE; ++ ++ if(!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) ++ { ++ ++#ifdef CONFIG_SW_ANTENNA_DIVERSITY ++ rtw_hal_set_hwreg(padapter, HW_VAR_ANTENNA_DIVERSITY_LINK, 0); ++#endif ++ ++ set_fwstate(pmlmepriv, _FW_LINKED); ++ ++ rtw_led_control(padapter, LED_CTL_LINK); ++ ++ ++#ifdef CONFIG_DRVEXT_MODULE ++ if(padapter->drvextpriv.enable_wpa) ++ { ++ indicate_l2_connect(padapter); ++ } ++ else ++#endif ++ { ++ rtw_os_indicate_connect(padapter); ++ } ++ ++ } ++ ++ rtw_set_roaming(padapter, 0); ++#ifdef CONFIG_INTEL_WIDI ++ if(padapter->mlmepriv.widi_state == INTEL_WIDI_STATE_ROAMING) ++ { ++ _rtw_memset(pmlmepriv->sa_ext, 0x00, L2SDTA_SERVICE_VE_LEN); ++ intel_widi_wk_cmd(padapter, INTEL_WIDI_LISTEN_WK, NULL); ++ DBG_871X("change to widi listen\n"); ++ } ++#endif // CONFIG_INTEL_WIDI ++ ++ rtw_set_scan_deny(padapter, 3000); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("-rtw_indicate_connect: fw_state=0x%08x\n", get_fwstate(pmlmepriv))); ++ ++_func_exit_; ++ ++} ++ ++ ++/* ++*rtw_indicate_disconnect: the caller has to lock pmlmepriv->lock ++*/ ++void rtw_indicate_disconnect( _adapter *padapter ) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_disconnect\n")); ++ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING|WIFI_UNDER_WPS); ++ ++ //DBG_871X("clear wps when %s\n", __func__); ++ ++ if(rtw_to_roaming(padapter) > 0) ++ _clr_fwstate_(pmlmepriv, _FW_LINKED); ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ psta = rtw_get_stainfo(pstapriv,cur_network->MacAddress); ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) ++ { ++ rtw_wapi_return_one_sta_info(padapter, psta->hwaddr); ++ } ++ else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || ++ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ++ { ++ rtw_wapi_return_all_sta_info(padapter); ++ } ++#endif ++ ++ if(check_fwstate(&padapter->mlmepriv, _FW_LINKED) ++ || (rtw_to_roaming(padapter) <= 0) ++ ) ++ { ++ rtw_os_indicate_disconnect(padapter); ++ ++ //set ips_deny_time to avoid enter IPS before LPS leave ++ adapter_to_pwrctl(padapter)->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime(3000); ++ ++ _clr_fwstate_(pmlmepriv, _FW_LINKED); ++ ++ rtw_led_control(padapter, LED_CTL_NO_LINK); ++ ++ rtw_clear_scan_deny(padapter); ++ ++ } ++ ++#ifdef CONFIG_P2P_PS ++ p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1); ++#endif // CONFIG_P2P_PS ++ ++#ifdef CONFIG_LPS ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_DISCONNECT, 1); ++#endif ++ ++_func_exit_; ++} ++ ++inline void rtw_indicate_scan_done( _adapter *padapter, bool aborted) ++{ ++ rtw_os_indicate_scan_done(padapter, aborted); ++} ++ ++void rtw_scan_abort(_adapter *adapter) ++{ ++ u32 cnt=0; ++ u32 start; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv); ++ ++ start = rtw_get_current_time(); ++ pmlmeext->scan_abort = _TRUE; ++ while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) ++ && rtw_get_passing_time_ms(start) <= 200) { ++ ++ if (adapter->bDriverStopped || adapter->bSurpriseRemoved) ++ break; ++ ++ DBG_871X(FUNC_NDEV_FMT"fw_state=_FW_UNDER_SURVEY!\n", FUNC_NDEV_ARG(adapter->pnetdev)); ++ rtw_msleep_os(20); ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { ++ if (!adapter->bDriverStopped && !adapter->bSurpriseRemoved) ++ DBG_871X(FUNC_NDEV_FMT"waiting for scan_abort time out!\n", FUNC_NDEV_ARG(adapter->pnetdev)); ++ #ifdef CONFIG_PLATFORM_MSTAR ++ //_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); ++ set_survey_timer(pmlmeext, 0); ++ _set_timer(&pmlmepriv->scan_to_timer, 50); ++ #endif ++ rtw_indicate_scan_done(adapter, _TRUE); ++ } ++ pmlmeext->scan_abort = _FALSE; ++} ++ ++static struct sta_info *rtw_joinbss_update_stainfo(_adapter *padapter, struct wlan_network *pnetwork) ++{ ++ int i; ++ struct sta_info *bmc_sta, *psta=NULL; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ psta = rtw_get_stainfo(pstapriv, pnetwork->network.MacAddress); ++ if(psta==NULL) { ++ psta = rtw_alloc_stainfo(pstapriv, pnetwork->network.MacAddress); ++ } ++ ++ if(psta) //update ptarget_sta ++ { ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ psta->aid = pnetwork->join_res; ++#ifdef CONFIG_CONCURRENT_MODE ++ ++ if(PRIMARY_ADAPTER == padapter->adapter_type) ++ psta->mac_id=0; ++ else ++ psta->mac_id=2; ++#else ++ psta->mac_id=0; ++#endif ++ ++ //sta mode ++ rtw_hal_set_odm_var(padapter,HAL_ODM_STA_INFO,psta,_TRUE); ++ ++ //security related ++ if(padapter->securitypriv.dot11AuthAlgrthm== dot11AuthAlgrthm_8021X) ++ { ++ padapter->securitypriv.binstallGrpkey=_FALSE; ++ padapter->securitypriv.busetkipkey=_FALSE; ++ padapter->securitypriv.bgrpkey_handshake=_FALSE; ++ ++ psta->ieee8021x_blocked=_TRUE; ++ psta->dot118021XPrivacy=padapter->securitypriv.dot11PrivacyAlgrthm; ++ ++ _rtw_memset((u8 *)&psta->dot118021x_UncstKey, 0, sizeof (union Keytype)); ++ ++ _rtw_memset((u8 *)&psta->dot11tkiprxmickey, 0, sizeof (union Keytype)); ++ _rtw_memset((u8 *)&psta->dot11tkiptxmickey, 0, sizeof (union Keytype)); ++ ++ _rtw_memset((u8 *)&psta->dot11txpn, 0, sizeof (union pn48)); ++#ifdef CONFIG_IEEE80211W ++ _rtw_memset((u8 *)&psta->dot11wtxpn, 0, sizeof (union pn48)); ++#endif //CONFIG_IEEE80211W ++ _rtw_memset((u8 *)&psta->dot11rxpn, 0, sizeof (union pn48)); ++ } ++ ++ // Commented by Albert 2012/07/21 ++ // When doing the WPS, the wps_ie_len won't equal to 0 ++ // And the Wi-Fi driver shouldn't allow the data packet to be tramsmitted. ++ if ( padapter->securitypriv.wps_ie_len != 0 ) ++ { ++ psta->ieee8021x_blocked=_TRUE; ++ padapter->securitypriv.wps_ie_len = 0; ++ } ++ ++ ++ //for A-MPDU Rx reordering buffer control for bmc_sta & sta_info ++ //if A-MPDU Rx is enabled, reseting rx_ordering_ctrl wstart_b(indicate_seq) to default value=0xffff ++ //todo: check if AP can send A-MPDU packets ++ for(i=0; i < 16 ; i++) ++ { ++ //preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ preorder_ctrl->enable = _FALSE; ++ preorder_ctrl->indicate_seq = 0xffff; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d indicate_seq:%u \n", __FUNCTION__, __LINE__, ++ preorder_ctrl->indicate_seq); ++ #endif ++ preorder_ctrl->wend_b= 0xffff; ++ preorder_ctrl->wsize_b = 64;//max_ampdu_sz;//ex. 32(kbytes) -> wsize_b=32 ++ } ++ ++ ++ bmc_sta = rtw_get_bcmc_stainfo(padapter); ++ if(bmc_sta) ++ { ++ for(i=0; i < 16 ; i++) ++ { ++ //preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; ++ preorder_ctrl = &bmc_sta->recvreorder_ctrl[i]; ++ preorder_ctrl->enable = _FALSE; ++ preorder_ctrl->indicate_seq = 0xffff; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d indicate_seq:%u \n", __FUNCTION__, __LINE__, ++ preorder_ctrl->indicate_seq); ++ #endif ++ preorder_ctrl->wend_b= 0xffff; ++ preorder_ctrl->wsize_b = 64;//max_ampdu_sz;//ex. 32(kbytes) -> wsize_b=32 ++ } ++ } ++ ++ ++ //misc. ++ update_sta_info(padapter, psta); ++ ++ } ++ ++ return psta; ++ ++} ++ ++//pnetwork : returns from rtw_joinbss_event_callback ++//ptarget_wlan: found from scanned_queue ++static void rtw_joinbss_update_network(_adapter *padapter, struct wlan_network *ptarget_wlan, struct wlan_network *pnetwork) ++{ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct wlan_network *cur_network = &(pmlmepriv->cur_network); ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("\nfw_state:%x, BSSID:"MAC_FMT"\n" ++ ,get_fwstate(pmlmepriv), MAC_ARG(pnetwork->network.MacAddress))); ++ ++ ++ // why not use ptarget_wlan?? ++ _rtw_memcpy(&cur_network->network, &pnetwork->network, pnetwork->network.Length); ++ // some IEs in pnetwork is wrong, so we should use ptarget_wlan IEs ++ cur_network->network.IELength = ptarget_wlan->network.IELength; ++ _rtw_memcpy(&cur_network->network.IEs[0], &ptarget_wlan->network.IEs[0], MAX_IE_SZ); ++ ++ cur_network->aid = pnetwork->join_res; ++ ++ ++#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS ++ rtw_set_signal_stat_timer(&padapter->recvpriv); ++#endif ++ padapter->recvpriv.signal_strength = ptarget_wlan->network.PhyInfo.SignalStrength; ++ padapter->recvpriv.signal_qual = ptarget_wlan->network.PhyInfo.SignalQuality; ++ //the ptarget_wlan->network.Rssi is raw data, we use ptarget_wlan->network.PhyInfo.SignalStrength instead (has scaled) ++ padapter->recvpriv.rssi = translate_percentage_to_dbm(ptarget_wlan->network.PhyInfo.SignalStrength); ++ #if defined(DBG_RX_SIGNAL_DISPLAY_PROCESSING) && 1 ++ DBG_871X(FUNC_ADPT_FMT" signal_strength:%3u, rssi:%3d, signal_qual:%3u" ++ "\n" ++ , FUNC_ADPT_ARG(padapter) ++ , padapter->recvpriv.signal_strength ++ , padapter->recvpriv.rssi ++ , padapter->recvpriv.signal_qual ++ ); ++ #endif ++#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS ++ rtw_set_signal_stat_timer(&padapter->recvpriv); ++#endif ++ ++ //update fw_state //will clr _FW_UNDER_LINKING here indirectly ++ switch(pnetwork->network.InfrastructureMode) ++ { ++ case Ndis802_11Infrastructure: ++ ++ if(pmlmepriv->fw_state&WIFI_UNDER_WPS) ++ pmlmepriv->fw_state = WIFI_STATION_STATE|WIFI_UNDER_WPS; ++ else ++ pmlmepriv->fw_state = WIFI_STATION_STATE; ++ ++ break; ++ case Ndis802_11IBSS: ++ pmlmepriv->fw_state = WIFI_ADHOC_STATE; ++ break; ++ default: ++ pmlmepriv->fw_state = WIFI_NULL_STATE; ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Invalid network_mode\n")); ++ break; ++ } ++ ++ rtw_update_protection(padapter, (cur_network->network.IEs) + sizeof (NDIS_802_11_FIXED_IEs), ++ (cur_network->network.IELength)); ++ ++#ifdef CONFIG_80211N_HT ++ rtw_update_ht_cap(padapter, cur_network->network.IEs, cur_network->network.IELength); ++#endif ++ ++ ++} ++ ++//Notes: the fucntion could be > passive_level (the same context as Rx tasklet) ++//pnetwork : returns from rtw_joinbss_event_callback ++//ptarget_wlan: found from scanned_queue ++//if join_res > 0, for (fw_state==WIFI_STATION_STATE), we check if "ptarget_sta" & "ptarget_wlan" exist. ++//if join_res > 0, for (fw_state==WIFI_ADHOC_STATE), we only check if "ptarget_wlan" exist. ++//if join_res > 0, update "cur_network->network" from "pnetwork->network" if (ptarget_wlan !=NULL). ++// ++//#define REJOIN ++void rtw_joinbss_event_prehandle(_adapter *adapter, u8 *pbuf) ++{ ++ _irqL irqL,irqL2; ++ static u8 retry=0; ++ u8 timer_cancelled; ++ struct sta_info *ptarget_sta= NULL, *pcur_sta = NULL; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ struct wlan_network *pnetwork = (struct wlan_network *)pbuf; ++ struct wlan_network *cur_network = &(pmlmepriv->cur_network); ++ struct wlan_network *pcur_wlan = NULL, *ptarget_wlan = NULL; ++ unsigned int the_same_macaddr = _FALSE; ++ ++_func_enter_; ++ ++#ifdef CONFIG_RTL8712 ++ //endian_convert ++ pnetwork->join_res = le32_to_cpu(pnetwork->join_res); ++ pnetwork->network_type = le32_to_cpu(pnetwork->network_type); ++ pnetwork->network.Length = le32_to_cpu(pnetwork->network.Length); ++ pnetwork->network.Ssid.SsidLength = le32_to_cpu(pnetwork->network.Ssid.SsidLength); ++ pnetwork->network.Privacy =le32_to_cpu( pnetwork->network.Privacy); ++ pnetwork->network.Rssi = le32_to_cpu(pnetwork->network.Rssi); ++ pnetwork->network.NetworkTypeInUse =le32_to_cpu(pnetwork->network.NetworkTypeInUse) ; ++ pnetwork->network.Configuration.ATIMWindow = le32_to_cpu(pnetwork->network.Configuration.ATIMWindow); ++ pnetwork->network.Configuration.BeaconPeriod = le32_to_cpu(pnetwork->network.Configuration.BeaconPeriod); ++ pnetwork->network.Configuration.DSConfig = le32_to_cpu(pnetwork->network.Configuration.DSConfig); ++ pnetwork->network.Configuration.FHConfig.DwellTime=le32_to_cpu(pnetwork->network.Configuration.FHConfig.DwellTime); ++ pnetwork->network.Configuration.FHConfig.HopPattern=le32_to_cpu(pnetwork->network.Configuration.FHConfig.HopPattern); ++ pnetwork->network.Configuration.FHConfig.HopSet=le32_to_cpu(pnetwork->network.Configuration.FHConfig.HopSet); ++ pnetwork->network.Configuration.FHConfig.Length=le32_to_cpu(pnetwork->network.Configuration.FHConfig.Length); ++ pnetwork->network.Configuration.Length = le32_to_cpu(pnetwork->network.Configuration.Length); ++ pnetwork->network.InfrastructureMode = le32_to_cpu(pnetwork->network.InfrastructureMode); ++ pnetwork->network.IELength = le32_to_cpu(pnetwork->network.IELength ); ++#endif ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("joinbss event call back received with res=%d\n", pnetwork->join_res)); ++ ++ rtw_get_encrypt_decrypt_from_registrypriv(adapter); ++ ++ ++ if (pmlmepriv->assoc_ssid.SsidLength == 0) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("@@@@@ joinbss event call back for Any SSid\n")); ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("@@@@@ rtw_joinbss_event_callback for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid)); ++ } ++ ++ the_same_macaddr = _rtw_memcmp(pnetwork->network.MacAddress, cur_network->network.MacAddress, ETH_ALEN); ++ ++ pnetwork->network.Length = get_WLAN_BSSID_EX_sz(&pnetwork->network); ++ if(pnetwork->network.Length > sizeof(WLAN_BSSID_EX)) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("\n\n ***joinbss_evt_callback return a wrong bss ***\n\n")); ++ goto ignore_joinbss_callback; ++ } ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("\n rtw_joinbss_event_callback !! _enter_critical \n")); ++ ++ if(pnetwork->join_res > 0) ++ { ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ retry = 0; ++ if (check_fwstate(pmlmepriv,_FW_UNDER_LINKING) ) ++ { ++ //s1. find ptarget_wlan ++ if(check_fwstate(pmlmepriv, _FW_LINKED) ) ++ { ++ if(the_same_macaddr == _TRUE) ++ { ++ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); ++ } ++ else ++ { ++ pcur_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); ++ if(pcur_wlan) pcur_wlan->fixed = _FALSE; ++ ++ pcur_sta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress); ++ if(pcur_sta){ ++ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); ++ rtw_free_stainfo(adapter, pcur_sta); ++ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); ++ } ++ ++ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress); ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE){ ++ if(ptarget_wlan) ptarget_wlan->fixed = _TRUE; ++ } ++ } ++ ++ } ++ else ++ { ++ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress); ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE){ ++ if(ptarget_wlan) ptarget_wlan->fixed = _TRUE; ++ } ++ } ++ ++ //s2. update cur_network ++ if(ptarget_wlan) ++ { ++ rtw_joinbss_update_network(adapter, ptarget_wlan, pnetwork); ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Can't find ptarget_wlan when joinbss_event callback\n")); ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ goto ignore_joinbss_callback; ++ } ++ ++ ++ //s3. find ptarget_sta & update ptarget_sta after update cur_network only for station mode ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) ++ { ++ ptarget_sta = rtw_joinbss_update_stainfo(adapter, pnetwork); ++ if(ptarget_sta==NULL) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Can't update stainfo when joinbss_event callback\n")); ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ goto ignore_joinbss_callback; ++ } ++ } ++ ++ //s4. indicate connect ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) ++ { ++ pmlmepriv->cur_network_scanned = ptarget_wlan; ++ rtw_indicate_connect(adapter); ++ } ++ else ++ { ++ //adhoc mode will rtw_indicate_connect when rtw_stassoc_event_callback ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("adhoc mode, fw_state:%x", get_fwstate(pmlmepriv))); ++ } ++ ++ ++ //s5. Cancle assoc_timer ++ _cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("Cancle assoc_timer \n")); ++ ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("rtw_joinbss_event_callback err: fw_state:%x", get_fwstate(pmlmepriv))); ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ goto ignore_joinbss_callback; ++ } ++ ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ } ++ else if(pnetwork->join_res == -4) ++ { ++ rtw_reset_securitypriv(adapter); ++ _set_timer(&pmlmepriv->assoc_timer, 1); ++ ++ //rtw_free_assoc_resources(adapter, 1); ++ ++ if((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == _TRUE) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("fail! clear _FW_UNDER_LINKING ^^^fw_state=%x\n", get_fwstate(pmlmepriv))); ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ } ++ ++ } ++ else //if join_res < 0 (join fails), then try again ++ { ++ ++ #ifdef REJOIN ++ res = _FAIL; ++ if(retry < 2) { ++ res = rtw_select_and_join_from_scanned_queue(pmlmepriv); ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("rtw_select_and_join_from_scanned_queue again! res:%d\n",res)); ++ } ++ ++ if(res == _SUCCESS) ++ { ++ //extend time of assoc_timer ++ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); ++ retry++; ++ } ++ else if(res == 2)//there is no need to wait for join ++ { ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ rtw_indicate_connect(adapter); ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Set Assoc_Timer = 1; can't find match ssid in scanned_q \n")); ++ #endif ++ ++ _set_timer(&pmlmepriv->assoc_timer, 1); ++ //rtw_free_assoc_resources(adapter, 1); ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ ++ #ifdef REJOIN ++ retry = 0; ++ } ++ #endif ++ } ++ ++ignore_joinbss_callback: ++ ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ _func_exit_; ++} ++ ++void rtw_joinbss_event_callback(_adapter *adapter, u8 *pbuf) ++{ ++ struct wlan_network *pnetwork = (struct wlan_network *)pbuf; ++ ++_func_enter_; ++ ++ mlmeext_joinbss_event_callback(adapter, pnetwork->join_res); ++ ++ rtw_os_xmit_schedule(adapter); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ rtw_os_xmit_schedule(adapter->pbuddy_adapter); ++#endif ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ dc_resume_xmit(adapter); ++#endif ++ ++_func_exit_; ++} ++ ++u8 search_max_mac_id(_adapter *padapter) ++{ ++ u8 mac_id, aid; ++#if (RATE_ADAPTIVE_SUPPORT==1) //for 88E RA ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++#if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE)){ ++ ++ for (aid = (pstapriv->max_num_sta); aid > 0; aid--) ++ { ++ if (pstapriv->sta_aid[aid-1] != NULL) ++ break; ++ } ++/* ++ for (mac_id = (pstapriv->max_num_sta-1); mac_id >= 0; mac_id--) ++ { ++ if (pstapriv->sta_aid[mac_id] != NULL) ++ break; ++ } ++*/ ++ mac_id = aid + 1; ++ } ++ else ++#endif ++ {//adhoc id = 31~2 ++ for (mac_id = (NUM_STA-1); mac_id >= IBSS_START_MAC_ID ; mac_id--) ++ { ++ if (pmlmeinfo->FW_sta_info[mac_id].status == 1) ++ { ++ break; ++ } ++ } ++ } ++#endif ++ return mac_id; ++ ++} ++ ++//FOR STA, AP ,AD-HOC mode ++void rtw_sta_media_status_rpt(_adapter *adapter,struct sta_info *psta, u32 mstatus) ++{ ++ u16 media_status_rpt; ++ ++ if(psta==NULL) return; ++ ++ #if (RATE_ADAPTIVE_SUPPORT==1) //for 88E RA ++ { ++ u8 macid = search_max_mac_id(adapter); ++ rtw_hal_set_hwreg(adapter,HW_VAR_TX_RPT_MAX_MACID, (u8*)&macid); ++ } ++ #endif ++ media_status_rpt = (u16)((psta->mac_id<<8)|mstatus); // MACID|OPMODE:1 connect ++ rtw_hal_set_hwreg(adapter,HW_VAR_H2C_MEDIA_STATUS_RPT,(u8 *)&media_status_rpt); ++} ++ ++void rtw_stassoc_event_callback(_adapter *adapter, u8 *pbuf) ++{ ++ _irqL irqL; ++ struct sta_info *psta; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ struct stassoc_event *pstassoc = (struct stassoc_event*)pbuf; ++ struct wlan_network *cur_network = &(pmlmepriv->cur_network); ++ struct wlan_network *ptarget_wlan = NULL; ++ ++_func_enter_; ++ ++ if(rtw_access_ctrl(adapter, pstassoc->macaddr) == _FALSE) ++ return; ++ ++#if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ { ++ psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr); ++ if(psta) ++ { ++ u8 *passoc_req = NULL; ++ u32 assoc_req_len = 0; ++ ++ rtw_sta_media_status_rpt(adapter, psta, 1); ++ ++#ifndef CONFIG_AUTO_AP_MODE ++ ++ ap_sta_info_defer_update(adapter, psta); ++ ++ //report to upper layer ++ DBG_871X("indicate_sta_assoc_event to upper layer - hostapd\n"); ++#ifdef CONFIG_IOCTL_CFG80211 ++ _enter_critical_bh(&psta->lock, &irqL); ++ if(psta->passoc_req && psta->assoc_req_len>0) ++ { ++ passoc_req = rtw_zmalloc(psta->assoc_req_len); ++ if(passoc_req) ++ { ++ assoc_req_len = psta->assoc_req_len; ++ _rtw_memcpy(passoc_req, psta->passoc_req, assoc_req_len); ++ ++ rtw_mfree(psta->passoc_req , psta->assoc_req_len); ++ psta->passoc_req = NULL; ++ psta->assoc_req_len = 0; ++ } ++ } ++ _exit_critical_bh(&psta->lock, &irqL); ++ ++ if(passoc_req && assoc_req_len>0) ++ { ++ rtw_cfg80211_indicate_sta_assoc(adapter, passoc_req, assoc_req_len); ++ ++ rtw_mfree(passoc_req, assoc_req_len); ++ } ++#else //!CONFIG_IOCTL_CFG80211 ++ rtw_indicate_sta_assoc_event(adapter, psta); ++#endif //!CONFIG_IOCTL_CFG80211 ++#endif //!CONFIG_AUTO_AP_MODE ++ } ++ goto exit; ++ } ++#endif //defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) ++ ++ //for AD-HOC mode ++ psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr); ++ if( psta != NULL) ++ { ++ //the sta have been in sta_info_queue => do nothing ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Error: rtw_stassoc_event_callback: sta has been in sta_hash_queue \n")); ++ ++ goto exit; //(between drv has received this event before and fw have not yet to set key to CAM_ENTRY) ++ } ++ ++ psta = rtw_alloc_stainfo(&adapter->stapriv, pstassoc->macaddr); ++ if (psta == NULL) { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Can't alloc sta_info when rtw_stassoc_event_callback\n")); ++ goto exit; ++ } ++ ++ //to do : init sta_info variable ++ psta->qos_option = 0; ++ psta->mac_id = (uint)pstassoc->cam_id; ++ //psta->aid = (uint)pstassoc->cam_id; ++ DBG_871X("%s\n",__FUNCTION__); ++ //for ad-hoc mode ++ rtw_hal_set_odm_var(adapter,HAL_ODM_STA_INFO,psta,_TRUE); ++ ++ rtw_sta_media_status_rpt(adapter, psta, 1); ++ ++ if(adapter->securitypriv.dot11AuthAlgrthm==dot11AuthAlgrthm_8021X) ++ psta->dot118021XPrivacy = adapter->securitypriv.dot11PrivacyAlgrthm; ++ ++ ++ psta->ieee8021x_blocked = _FALSE; ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ if ( (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)==_TRUE ) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)==_TRUE ) ) ++ { ++ if(adapter->stapriv.asoc_sta_count== 2) ++ { ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); ++ pmlmepriv->cur_network_scanned = ptarget_wlan; ++ if(ptarget_wlan) ptarget_wlan->fixed = _TRUE; ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ // a sta + bc/mc_stainfo (not Ibss_stainfo) ++ rtw_indicate_connect(adapter); ++ } ++ } ++ ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ ++ mlmeext_sta_add_event_callback(adapter, psta); ++ ++#ifdef CONFIG_RTL8711 ++ //submit SetStaKey_cmd to tell fw, fw will allocate an CAM entry for this sta ++ rtw_setstakey_cmd(adapter, (unsigned char*)psta, _FALSE, _TRUE); ++#endif ++ ++exit: ++ ++_func_exit_; ++ ++} ++ ++void rtw_stadel_event_callback(_adapter *adapter, u8 *pbuf) ++{ ++ _irqL irqL,irqL2; ++ int mac_id=-1; ++ struct sta_info *psta; ++ struct wlan_network* pwlan = NULL; ++ WLAN_BSSID_EX *pdev_network=NULL; ++ u8* pibss = NULL; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ struct stadel_event *pstadel = (struct stadel_event*)pbuf; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct wlan_network *tgt_network = &(pmlmepriv->cur_network); ++ ++_func_enter_; ++ ++ psta = rtw_get_stainfo(&adapter->stapriv, pstadel->macaddr); ++ if(psta) ++ mac_id = psta->mac_id; ++ else ++ mac_id = pstadel->mac_id; ++ ++ DBG_871X("%s(mac_id=%d)=" MAC_FMT "\n", __func__, mac_id, MAC_ARG(pstadel->macaddr)); ++ ++ if(mac_id>=0){ ++ u16 media_status; ++ media_status = (mac_id<<8)|0; // MACID|OPMODE:0 means disconnect ++ //for STA,AP,ADHOC mode, report disconnect stauts to FW ++ rtw_hal_set_hwreg(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status); ++ } ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ { ++#ifdef CONFIG_IOCTL_CFG80211 ++ #ifdef COMPAT_KERNEL_RELEASE ++ ++ #elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)) || defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER) ++ rtw_cfg80211_indicate_sta_disassoc(adapter, pstadel->macaddr, *(u16*)pstadel->rsvd); ++ #endif //(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)) || defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER) ++#endif //CONFIG_IOCTL_CFG80211 ++ ++ return; ++ } ++ ++ ++ mlmeext_sta_del_event_callback(adapter); ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL2); ++ ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) ) ++ { ++ #ifdef CONFIG_LAYER2_ROAMING ++ if(adapter->registrypriv.wifi_spec==1) ++ rtw_set_roaming(adapter, 0); /* don't roam */ ++ else if (rtw_to_roaming(adapter) > 0) ++ pmlmepriv->to_roaming--; /* this stadel_event is caused by roaming, decrease to_roaming */ ++ else if (rtw_to_roaming(adapter) == 0) ++ rtw_set_roaming(adapter, adapter->registrypriv.max_roaming_times); ++#ifdef CONFIG_INTEL_WIDI ++ if(adapter->mlmepriv.widi_state != INTEL_WIDI_STATE_CONNECTED) ++#endif // CONFIG_INTEL_WIDI ++ if(*((unsigned short *)(pstadel->rsvd)) != WLAN_REASON_EXPIRATION_CHK) ++ rtw_set_roaming(adapter, 0); /* don't roam */ ++ #endif ++ ++ rtw_free_uc_swdec_pending_queue(adapter); ++ ++ rtw_free_assoc_resources(adapter, 1); ++ rtw_indicate_disconnect(adapter); ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ // remove the network entry in scanned_queue ++ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); ++ if (pwlan) { ++ pwlan->fixed = _FALSE; ++ rtw_free_network_nolock(pmlmepriv, pwlan); ++ } ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ #ifdef CONFIG_LAYER2_ROAMING ++ _rtw_roaming(adapter, tgt_network); ++ #else ++#ifdef CONFIG_INTEL_WIDI ++ process_intel_widi_disconnect(adapter, 1); ++#endif // CONFIG_INTEL_WIDI ++ #endif //CONFIG_LAYER2_ROAMING ++ ++ } ++ ++ if ( check_fwstate(pmlmepriv,WIFI_ADHOC_MASTER_STATE) || ++ check_fwstate(pmlmepriv,WIFI_ADHOC_STATE)) ++ { ++ ++ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ rtw_free_stainfo(adapter, psta); ++ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ ++ if(adapter->stapriv.asoc_sta_count== 1) //a sta + bc/mc_stainfo (not Ibss_stainfo) ++ { ++ //rtw_indicate_disconnect(adapter);//removed@20091105 ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ //free old ibss network ++ //pwlan = rtw_find_network(&pmlmepriv->scanned_queue, pstadel->macaddr); ++ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); ++ if(pwlan) ++ { ++ pwlan->fixed = _FALSE; ++ rtw_free_network_nolock(pmlmepriv, pwlan); ++ } ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ //re-create ibss ++ pdev_network = &(adapter->registrypriv.dev_network); ++ pibss = adapter->registrypriv.dev_network.MacAddress; ++ ++ _rtw_memcpy(pdev_network, &tgt_network->network, get_WLAN_BSSID_EX_sz(&tgt_network->network)); ++ ++ _rtw_memset(&pdev_network->Ssid, 0, sizeof(NDIS_802_11_SSID)); ++ _rtw_memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(NDIS_802_11_SSID)); ++ ++ rtw_update_registrypriv_dev_network(adapter); ++ ++ rtw_generate_random_ibss(pibss); ++ ++ if(check_fwstate(pmlmepriv,WIFI_ADHOC_STATE)) ++ { ++ set_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE); ++ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_STATE); ++ } ++ ++ if(rtw_createbss_cmd(adapter)!=_SUCCESS) ++ { ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_,_drv_err_,("***Error=>stadel_event_callback: rtw_createbss_cmd status FAIL*** \n ")); ++ ++ } ++ ++ ++ } ++ ++ } ++ ++ _exit_critical_bh(&pmlmepriv->lock, &irqL2); ++ ++_func_exit_; ++ ++} ++ ++ ++void rtw_cpwm_event_callback(PADAPTER padapter, u8 *pbuf) ++{ ++#ifdef CONFIG_LPS_LCLK ++ struct reportpwrstate_parm *preportpwrstate; ++#endif ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("+rtw_cpwm_event_callback !!!\n")); ++#ifdef CONFIG_LPS_LCLK ++ preportpwrstate = (struct reportpwrstate_parm*)pbuf; ++ preportpwrstate->state |= (u8)(adapter_to_pwrctl(padapter)->cpwm_tog + 0x80); ++ cpwm_int_hdl(padapter, preportpwrstate); ++#endif ++ ++_func_exit_; ++ ++} ++ ++/* ++* _rtw_join_timeout_handler - Timeout/faliure handler for CMD JoinBss ++* @adapter: pointer to _adapter structure ++*/ ++void _rtw_join_timeout_handler (_adapter *adapter) ++{ ++ _irqL irqL; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++#ifdef CONFIG_LAYER2_ROAMING ++ int do_join_r; ++#endif //CONFIG_LAYER2_ROAMING ++ ++#if 0 ++ if (adapter->bDriverStopped == _TRUE){ ++ _rtw_up_sema(&pmlmepriv->assoc_terminate); ++ return; ++ } ++#endif ++ ++_func_enter_; ++#ifdef PLATFORM_FREEBSD ++ rtw_mtx_lock(NULL); ++ if (callout_pending(&adapter->mlmepriv.assoc_timer.callout)) { ++ /* callout was reset */ ++ //mtx_unlock(&sc->sc_mtx); ++ rtw_mtx_unlock(NULL); ++ return; ++ } ++ if (!callout_active(&adapter->mlmepriv.assoc_timer.callout)) { ++ /* callout was stopped */ ++ //mtx_unlock(&sc->sc_mtx); ++ rtw_mtx_unlock(NULL); ++ return; ++ } ++ callout_deactivate(&adapter->mlmepriv.assoc_timer.callout); ++ ++ ++#endif ++ ++ DBG_871X("%s, fw_state=%x\n", __FUNCTION__, get_fwstate(pmlmepriv)); ++ ++ if(adapter->bDriverStopped ||adapter->bSurpriseRemoved) ++ return; ++ ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ #ifdef CONFIG_LAYER2_ROAMING ++ if (rtw_to_roaming(adapter) > 0) { /* join timeout caused by roaming */ ++ while(1) { ++ pmlmepriv->to_roaming--; ++ if (rtw_to_roaming(adapter) != 0) { /* try another */ ++ DBG_871X("%s try another roaming\n", __FUNCTION__); ++ if( _SUCCESS!=(do_join_r=rtw_do_join(adapter)) ) { ++ DBG_871X("%s roaming do_join return %d\n", __FUNCTION__ ,do_join_r); ++ continue; ++ } ++ break; ++ } else { ++#ifdef CONFIG_INTEL_WIDI ++ if(adapter->mlmepriv.widi_state == INTEL_WIDI_STATE_ROAMING) ++ { ++ _rtw_memset(pmlmepriv->sa_ext, 0x00, L2SDTA_SERVICE_VE_LEN); ++ intel_widi_wk_cmd(adapter, INTEL_WIDI_LISTEN_WK, NULL); ++ DBG_871X("change to widi listen\n"); ++ } ++#endif // CONFIG_INTEL_WIDI ++ DBG_871X("%s We've try roaming but fail\n", __FUNCTION__); ++ rtw_indicate_disconnect(adapter); ++ break; ++ } ++ } ++ ++ } else ++ #endif ++ { ++ rtw_indicate_disconnect(adapter); ++ free_scanqueue(pmlmepriv);//??? ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ //indicate disconnect for the case that join_timeout and check_fwstate != FW_LINKED ++ rtw_cfg80211_indicate_disconnect(adapter); ++#endif //CONFIG_IOCTL_CFG80211 ++ ++ } ++ ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ ++#ifdef CONFIG_DRVEXT_MODULE_WSC ++ drvext_assoc_fail_indicate(&adapter->drvextpriv); ++#endif ++#ifdef PLATFORM_FREEBSD ++ rtw_mtx_unlock(NULL); ++#endif ++ ++_func_exit_; ++ ++} ++ ++/* ++* rtw_scan_timeout_handler - Timeout/Faliure handler for CMD SiteSurvey ++* @adapter: pointer to _adapter structure ++*/ ++void rtw_scan_timeout_handler (_adapter *adapter) ++{ ++ _irqL irqL; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ ++ DBG_871X(FUNC_ADPT_FMT" fw_state=%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv)); ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); ++ ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ rtw_indicate_scan_done(adapter, _TRUE); ++ ++} ++ ++static void rtw_auto_scan_handler(_adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); ++ ++ //auto site survey per 60sec ++ if(pmlmepriv->scan_interval >0) ++ { ++ pmlmepriv->scan_interval--; ++ if(pmlmepriv->scan_interval==0) ++ { ++/* ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE) ++ { ++ DBG_871X("exit %s when _FW_UNDER_SURVEY|_FW_UNDER_LINKING -> \n", __FUNCTION__); ++ return; ++ } ++ ++ if(pmlmepriv->sitesurveyctrl.traffic_busy == _TRUE) ++ { ++ DBG_871X("%s exit cause traffic_busy(%x)\n",__FUNCTION__, pmlmepriv->sitesurveyctrl.traffic_busy); ++ return; ++ } ++*/ ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (rtw_buddy_adapter_up(padapter)) ++ { ++ if ((check_buddy_fwstate(padapter, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE) || ++ (padapter->pbuddy_adapter->mlmepriv.LinkDetectInfo.bBusyTraffic == _TRUE)) ++ { ++ DBG_871X("%s, but buddy_intf is under scanning or linking or BusyTraffic\n", __FUNCTION__); ++ return; ++ } ++ } ++#endif ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ rtw_set_802_11_bssid_list_scan(padapter, NULL, 0); ++ ++ pmlmepriv->scan_interval = SCAN_INTERVAL;// 30*2 sec = 60sec ++ ++ } ++ ++ } ++ ++} ++ ++void rtw_dynamic_check_timer_handlder(_adapter *adapter) ++{ ++#ifdef CONFIG_AP_MODE ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++#endif //CONFIG_AP_MODE ++ struct registry_priv *pregistrypriv = &adapter->registrypriv; ++#ifdef CONFIG_CONCURRENT_MODE ++ PADAPTER pbuddy_adapter = adapter->pbuddy_adapter; ++#endif ++ ++ if(!adapter) ++ return; ++#if defined(CONFIG_CHECK_BT_HANG) && defined(CONFIG_BT_COEXIST) ++ if(adapter->HalFunc.hal_checke_bt_hang) ++ { ++#ifdef CONFIG_CONCURRENT_MODE ++ if (adapter->adapter_type == PRIMARY_ADAPTER) ++#endif ++ adapter->HalFunc.hal_checke_bt_hang(adapter); ++ } ++#endif ++ if(adapter->hw_init_completed == _FALSE) ++ return; ++ ++ if ((adapter->bDriverStopped == _TRUE)||(adapter->bSurpriseRemoved== _TRUE)) ++ return; ++ ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(pbuddy_adapter) ++ { ++ if(adapter->net_closed == _TRUE && pbuddy_adapter->net_closed == _TRUE) ++ { ++ return; ++ } ++ } ++ else ++#endif //CONFIG_CONCURRENT_MODE ++ if(adapter->net_closed == _TRUE) ++ { ++ return; ++ } ++ ++ rtw_dynamic_chk_wk_cmd(adapter); ++ ++ if(pregistrypriv->wifi_spec==1) ++ { ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo = &adapter->wdinfo; ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++#endif ++ { ++ //auto site survey ++ rtw_auto_scan_handler(adapter); ++ } ++ } ++ ++#ifndef CONFIG_ACTIVE_KEEP_ALIVE_CHECK ++#ifdef CONFIG_AP_MODE ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ { ++ expire_timeout_chk(adapter); ++ } ++#endif ++#endif //!CONFIG_ACTIVE_KEEP_ALIVE_CHECK ++ ++#ifdef CONFIG_BR_EXT ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) ++ rcu_read_lock(); ++#endif // (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ if( adapter->pnetdev->br_port ++#else // (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ if( rcu_dereference(adapter->pnetdev->rx_handler_data) ++#endif // (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ && (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) == _TRUE) ) ++ { ++ // expire NAT2.5 entry ++ void nat25_db_expire(_adapter *priv); ++ nat25_db_expire(adapter); ++ ++ if (adapter->pppoe_connection_in_progress > 0) { ++ adapter->pppoe_connection_in_progress--; ++ } ++ ++ // due to rtw_dynamic_check_timer_handlder() is called every 2 seconds ++ if (adapter->pppoe_connection_in_progress > 0) { ++ adapter->pppoe_connection_in_progress--; ++ } ++ } ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) ++ rcu_read_unlock(); ++#endif // (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) ++ ++#endif // CONFIG_BR_EXT ++ ++} ++ ++ ++#ifdef CONFIG_SET_SCAN_DENY_TIMER ++inline bool rtw_is_scan_deny(_adapter *adapter) ++{ ++ struct mlme_priv *mlmepriv = &adapter->mlmepriv; ++ return (ATOMIC_READ(&mlmepriv->set_scan_deny) != 0) ? _TRUE : _FALSE; ++} ++ ++inline void rtw_clear_scan_deny(_adapter *adapter) ++{ ++ struct mlme_priv *mlmepriv = &adapter->mlmepriv; ++ ATOMIC_SET(&mlmepriv->set_scan_deny, 0); ++ if (0) ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter)); ++} ++ ++void rtw_set_scan_deny_timer_hdl(_adapter *adapter) ++{ ++ rtw_clear_scan_deny(adapter); ++} ++ ++void rtw_set_scan_deny(_adapter *adapter, u32 ms) ++{ ++ struct mlme_priv *mlmepriv = &adapter->mlmepriv; ++#ifdef CONFIG_CONCURRENT_MODE ++ struct mlme_priv *b_mlmepriv; ++#endif ++ ++ if (0) ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter)); ++ ATOMIC_SET(&mlmepriv->set_scan_deny, 1); ++ _set_timer(&mlmepriv->set_scan_deny_timer, ms); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (!adapter->pbuddy_adapter) ++ return; ++ ++ if (0) ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter->pbuddy_adapter)); ++ b_mlmepriv = &adapter->pbuddy_adapter->mlmepriv; ++ ATOMIC_SET(&b_mlmepriv->set_scan_deny, 1); ++ _set_timer(&b_mlmepriv->set_scan_deny_timer, ms); ++#endif ++ ++} ++#endif ++ ++#ifdef CONFIG_DETECT_C2H_BY_POLLING ++void rtw_event_polling_timer_hdl(_adapter *adapter) ++{ ++ rtw_event_polling_cmd(adapter); ++} ++#endif ++ ++#if defined(IEEE80211_SCAN_RESULT_EXPIRE) ++#define RTW_SCAN_RESULT_EXPIRE IEEE80211_SCAN_RESULT_EXPIRE/HZ*1000 -1000 //3000 -1000 ++#else ++#define RTW_SCAN_RESULT_EXPIRE 2000 ++#endif ++ ++#ifndef PLATFORM_FREEBSD ++/* ++* Select a new join candidate from the original @param candidate and @param competitor ++* @return _TRUE: candidate is updated ++* @return _FALSE: candidate is not updated ++*/ ++static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv ++ , struct wlan_network **candidate, struct wlan_network *competitor) ++{ ++ int updated = _FALSE; ++ _adapter *adapter = container_of(pmlmepriv, _adapter, mlmepriv); ++ ++ ++ //check bssid, if needed ++ if(pmlmepriv->assoc_by_bssid==_TRUE) { ++ if(_rtw_memcmp(competitor->network.MacAddress, pmlmepriv->assoc_bssid, ETH_ALEN) ==_FALSE) ++ goto exit; ++ } ++ ++ //check ssid, if needed ++ if(pmlmepriv->assoc_ssid.Ssid && pmlmepriv->assoc_ssid.SsidLength) { ++ if( competitor->network.Ssid.SsidLength != pmlmepriv->assoc_ssid.SsidLength ++ || _rtw_memcmp(competitor->network.Ssid.Ssid, pmlmepriv->assoc_ssid.Ssid, pmlmepriv->assoc_ssid.SsidLength) == _FALSE ++ ) ++ goto exit; ++ } ++ ++ if(rtw_is_desired_network(adapter, competitor) == _FALSE) ++ goto exit; ++ ++#ifdef CONFIG_LAYER2_ROAMING ++ if(rtw_to_roaming(adapter) > 0) { ++ if( rtw_get_passing_time_ms((u32)competitor->last_scanned) >= RTW_SCAN_RESULT_EXPIRE ++ || is_same_ess(&competitor->network, &pmlmepriv->cur_network.network) == _FALSE ++ ) ++ goto exit; ++ } ++#endif ++ ++ if(*candidate == NULL ||(*candidate)->network.Rssinetwork.Rssi ) ++ { ++ *candidate = competitor; ++ updated = _TRUE; ++ } ++ ++#if 0 ++ if(pmlmepriv->assoc_by_bssid==_TRUE) { // associate with bssid ++ if( (*candidate == NULL ||(*candidate)->network.Rssinetwork.Rssi ) ++ && _rtw_memcmp(competitor->network.MacAddress, pmlmepriv->assoc_bssid, ETH_ALEN)==_TRUE ++ ) { ++ *candidate = competitor; ++ updated = _TRUE; ++ } ++ } else if (pmlmepriv->assoc_ssid.SsidLength == 0 ) { // associate with ssid, but ssidlength is 0 ++ if( (*candidate == NULL ||(*candidate)->network.Rssinetwork.Rssi ) ) { ++ *candidate = competitor; ++ updated = _TRUE; ++ } ++ } else ++#ifdef CONFIG_LAYER2_ROAMING ++ if(rtw_to_roaming(adapter)) { // roaming ++ if( (*candidate == NULL ||(*candidate)->network.Rssinetwork.Rssi ) ++ && is_same_ess(&competitor->network, &pmlmepriv->cur_network.network) ++ //&&(!is_same_network(&competitor->network, &pmlmepriv->cur_network.network)) ++ && rtw_get_passing_time_ms((u32)competitor->last_scanned) < RTW_SCAN_RESULT_EXPIRE ++ && rtw_is_desired_network(adapter, competitor) ++ ) { ++ *candidate = competitor; ++ updated = _TRUE; ++ } ++ ++ } else ++#endif ++ { // associate with ssid ++ if( (*candidate == NULL ||(*candidate)->network.Rssinetwork.Rssi ) ++ && (competitor->network.Ssid.SsidLength==pmlmepriv->assoc_ssid.SsidLength) ++ &&((_rtw_memcmp(competitor->network.Ssid.Ssid, pmlmepriv->assoc_ssid.Ssid, pmlmepriv->assoc_ssid.SsidLength)) == _TRUE) ++ && rtw_is_desired_network(adapter, competitor) ++ ) { ++ *candidate = competitor; ++ updated = _TRUE; ++ } ++ } ++#endif ++ ++ if(updated){ ++ DBG_871X("[by_bssid:%u][assoc_ssid:%s]" ++ #ifdef CONFIG_LAYER2_ROAMING ++ "[to_roaming:%u] " ++ #endif ++ "new candidate: %s("MAC_FMT") rssi:%d\n", ++ pmlmepriv->assoc_by_bssid, ++ pmlmepriv->assoc_ssid.Ssid, ++ #ifdef CONFIG_LAYER2_ROAMING ++ rtw_to_roaming(adapter), ++ #endif ++ (*candidate)->network.Ssid.Ssid, ++ MAC_ARG((*candidate)->network.MacAddress), ++ (int)(*candidate)->network.Rssi ++ ); ++ } ++ ++exit: ++ return updated; ++} ++ ++/* ++Calling context: ++The caller of the sub-routine will be in critical section... ++ ++The caller must hold the following spinlock ++ ++pmlmepriv->lock ++ ++ ++*/ ++ ++int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv ) ++{ ++ _irqL irqL; ++ int ret; ++ _list *phead; ++ _adapter *adapter; ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ struct wlan_network *candidate = NULL; ++ u8 bSupportAntDiv = _FALSE; ++ ++_func_enter_; ++ ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ phead = get_list_head(queue); ++ adapter = (_adapter *)pmlmepriv->nic_hdl; ++ ++ pmlmepriv->pscanned = get_next( phead ); ++ ++ while (!rtw_end_of_queue_search(phead, pmlmepriv->pscanned)) { ++ ++ pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list); ++ if(pnetwork==NULL){ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s return _FAIL:(pnetwork==NULL)\n", __FUNCTION__)); ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ pmlmepriv->pscanned = get_next(pmlmepriv->pscanned); ++ ++ #if 0 ++ DBG_871X("MacAddress:"MAC_FMT" ssid:%s\n", MAC_ARG(pnetwork->network.MacAddress), pnetwork->network.Ssid.Ssid); ++ #endif ++ ++ rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork); ++ ++ } ++ ++ if(candidate == NULL) { ++ DBG_871X("%s: return _FAIL(candidate == NULL)\n", __FUNCTION__); ++#ifdef CONFIG_WOWLAN ++ _clr_fwstate_(pmlmepriv, _FW_LINKED|_FW_UNDER_LINKING); ++#endif ++ ret = _FAIL; ++ goto exit; ++ } else { ++ DBG_871X("%s: candidate: %s("MAC_FMT", ch:%u)\n", __FUNCTION__, ++ candidate->network.Ssid.Ssid, MAC_ARG(candidate->network.MacAddress), ++ candidate->network.Configuration.DSConfig); ++ } ++ ++ ++ // check for situation of _FW_LINKED ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ++ { ++ DBG_871X("%s: _FW_LINKED while ask_for_joinbss!!!\n", __FUNCTION__); ++ ++ #if 0 // for WPA/WPA2 authentication, wpa_supplicant will expect authentication from AP, it is needed to reconnect AP... ++ if(is_same_network(&pmlmepriv->cur_network.network, &candidate->network)) ++ { ++ DBG_871X("%s: _FW_LINKED and is same network, it needn't join again\n", __FUNCTION__); ++ ++ rtw_indicate_connect(adapter);//rtw_indicate_connect again ++ ++ ret = 2; ++ goto exit; ++ } ++ else ++ #endif ++ { ++ rtw_disassoc_cmd(adapter, 0, _TRUE); ++ rtw_indicate_disconnect(adapter); ++ rtw_free_assoc_resources(adapter, 0); ++ } ++ } ++ ++ #ifdef CONFIG_ANTENNA_DIVERSITY ++ rtw_hal_get_def_var(adapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &(bSupportAntDiv)); ++ if(_TRUE == bSupportAntDiv) ++ { ++ u8 CurrentAntenna; ++ rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &(CurrentAntenna)); ++ DBG_871X("#### Opt_Ant_(%s) , cur_Ant(%s)\n", ++ (2==candidate->network.PhyInfo.Optimum_antenna)?"A":"B", ++ (2==CurrentAntenna)?"A":"B" ++ ); ++ } ++ #endif ++ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); ++ ret = rtw_joinbss_cmd(adapter, candidate); ++ ++exit: ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++_func_exit_; ++ ++ return ret; ++} ++#else ++int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv ) ++{ ++ _irqL irqL; ++ _list *phead; ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ u8 CurrentAntenna; ++#endif ++ unsigned char *dst_ssid, *src_ssid; ++ _adapter *adapter; ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ struct wlan_network *pnetwork_max_rssi = NULL; ++ #ifdef CONFIG_LAYER2_ROAMING ++ struct wlan_network * roaming_candidate=NULL; ++ u32 cur_time=rtw_get_current_time(); ++ #endif ++ ++_func_enter_; ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ phead = get_list_head(queue); ++ adapter = (_adapter *)pmlmepriv->nic_hdl; ++ ++ pmlmepriv->pscanned = get_next( phead ); ++ ++ while (!rtw_end_of_queue_search(phead, pmlmepriv->pscanned)) { ++ ++ pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list); ++ if(pnetwork==NULL){ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("(2)rtw_select_and_join_from_scanned_queue return _FAIL:(pnetwork==NULL)\n")); ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ return _FAIL; ++ } ++ ++ dst_ssid = pnetwork->network.Ssid.Ssid; ++ src_ssid = pmlmepriv->assoc_ssid.Ssid; ++ ++ pmlmepriv->pscanned = get_next(pmlmepriv->pscanned); ++ ++ #if 0 ++ DBG_871X("MacAddress:"MAC_FMT" ssid:%s\n", MAC_ARG(pnetwork->network.MacAddress), pnetwork->network.Ssid.Ssid); ++ #endif ++ ++ if(pmlmepriv->assoc_by_bssid==_TRUE) ++ { ++ if(_rtw_memcmp(pnetwork->network.MacAddress, pmlmepriv->assoc_bssid, ETH_ALEN)==_TRUE) ++ { ++ //remove the condition @ 20081125 ++ //if((pmlmepriv->cur_network.network.InfrastructureMode==Ndis802_11AutoUnknown)|| ++ // pmlmepriv->cur_network.network.InfrastructureMode == pnetwork->network.InfrastructureMode) ++ // goto ask_for_joinbss; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ++ { ++ if(is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network), 0) ++ { ++ //DBG_871X("select_and_join(1): _FW_LINKED and is same network, it needn't join again\n"); ++ ++ rtw_indicate_connect(adapter);//rtw_indicate_connect again ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ return 2; ++ } ++ else ++ { ++ rtw_disassoc_cmd(adapter, 0, _TRUE); ++ rtw_indicate_disconnect(adapter); ++ rtw_free_assoc_resources(adapter, 0); ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ goto ask_for_joinbss; ++ ++ } ++ } ++ else ++ { ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ goto ask_for_joinbss; ++ } ++ ++ } ++ ++ } else if (pmlmepriv->assoc_ssid.SsidLength == 0) { ++ goto ask_for_joinbss;//anyway, join first selected(dequeued) pnetwork if ssid_len=0 ++ ++ #ifdef CONFIG_LAYER2_ROAMING ++ } else if (rtw_to_roaming(adapter) > 0) { ++ ++ if( (roaming_candidate == NULL ||roaming_candidate->network.Rssinetwork.Rssi ) ++ && is_same_ess(&pnetwork->network, &pmlmepriv->cur_network.network) ++ //&&(!is_same_network(&pnetwork->network, &pmlmepriv->cur_network.network, 0)) ++ && rtw_get_time_interval_ms((u32)pnetwork->last_scanned,cur_time) < 5000 ++ ) { ++ roaming_candidate = pnetwork; ++ //RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_, ++ DBG_871X ++ ("roaming_candidate???: %s("MAC_FMT")\n", ++ roaming_candidate->network.Ssid.Ssid, MAC_ARG(roaming_candidate->network.MacAddress) ) ++ //) ++ ; ++ } ++ continue; ++ #endif ++ ++ } else if ( (pnetwork->network.Ssid.SsidLength==pmlmepriv->assoc_ssid.SsidLength) ++ &&((_rtw_memcmp(dst_ssid, src_ssid, pmlmepriv->assoc_ssid.SsidLength)) == _TRUE) ++ ) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("dst_ssid=%s, src_ssid=%s \n", dst_ssid, src_ssid)); ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &(CurrentAntenna)); ++ DBG_871X("#### dst_ssid=(%s) Opt_Ant_(%s) , cur_Ant(%s)\n", dst_ssid, ++ (2==pnetwork->network.PhyInfo.Optimum_antenna)?"A":"B", ++ (2==CurrentAntenna)?"A":"B"); ++#endif ++ //remove the condition @ 20081125 ++ //if((pmlmepriv->cur_network.network.InfrastructureMode==Ndis802_11AutoUnknown)|| ++ // pmlmepriv->cur_network.network.InfrastructureMode == pnetwork->network.InfrastructureMode) ++ //{ ++ // _rtw_memcpy(pmlmepriv->assoc_bssid, pnetwork->network.MacAddress, ETH_ALEN); ++ // goto ask_for_joinbss; ++ //} ++ ++ if(pmlmepriv->assoc_by_rssi==_TRUE)//if the ssid is the same, select the bss which has the max rssi ++ { ++ if( NULL==pnetwork_max_rssi|| pnetwork->network.Rssi > pnetwork_max_rssi->network.Rssi) ++ pnetwork_max_rssi = pnetwork; ++ } ++ else if(rtw_is_desired_network(adapter, pnetwork) == _TRUE) ++ { ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ++ { ++#if 0 ++ if(is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network, 0)) ++ { ++ DBG_871X("select_and_join(2): _FW_LINKED and is same network, it needn't join again\n"); ++ ++ rtw_indicate_connect(adapter);//rtw_indicate_connect again ++ ++ return 2; ++ } ++ else ++#endif ++ { ++ rtw_disassoc_cmd(adapter, 0, _TRUE); ++ //rtw_indicate_disconnect(adapter);// ++ rtw_free_assoc_resources(adapter, 0); ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ goto ask_for_joinbss; ++ } ++ } ++ else ++ { ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ goto ask_for_joinbss; ++ } ++ ++ } ++ ++ ++ } ++ ++ } ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ #ifdef CONFIG_LAYER2_ROAMING ++ if(rtw_to_roaming(adapter) > 0 && roaming_candidate ){ ++ pnetwork=roaming_candidate; ++ DBG_871X("select_and_join_from_scanned_queue: roaming_candidate: %s("MAC_FMT")\n", ++ pnetwork->network.Ssid.Ssid, MAC_ARG(pnetwork->network.MacAddress)); ++ goto ask_for_joinbss; ++ } ++ #endif ++ ++ if((pmlmepriv->assoc_by_rssi==_TRUE) && (pnetwork_max_rssi!=NULL)) ++ { ++ pnetwork = pnetwork_max_rssi; ++ DBG_871X("select_and_join_from_scanned_queue: pnetwork_max_rssi: %s("MAC_FMT")\n", ++ pnetwork->network.Ssid.Ssid, MAC_ARG(pnetwork->network.MacAddress)); ++ goto ask_for_joinbss; ++ } ++ ++ DBG_871X("(1)rtw_select_and_join_from_scanned_queue return _FAIL\n"); ++ ++_func_exit_; ++ ++ return _FAIL; ++ ++ask_for_joinbss: ++ ++_func_exit_; ++ ++ return rtw_joinbss_cmd(adapter, pnetwork); ++ ++} ++#endif //PLATFORM_FREEBSD ++ ++ ++sint rtw_set_auth(_adapter * adapter,struct security_priv *psecuritypriv) ++{ ++ struct cmd_obj* pcmd; ++ struct setauth_parm *psetauthparm; ++ struct cmd_priv *pcmdpriv=&(adapter->cmdpriv); ++ sint res=_SUCCESS; ++ ++_func_enter_; ++ ++ pcmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(pcmd==NULL){ ++ res= _FAIL; //try again ++ goto exit; ++ } ++ ++ psetauthparm=(struct setauth_parm*)rtw_zmalloc(sizeof(struct setauth_parm)); ++ if(psetauthparm==NULL){ ++ rtw_mfree((unsigned char *)pcmd, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ _rtw_memset(psetauthparm, 0, sizeof(struct setauth_parm)); ++ psetauthparm->mode=(unsigned char)psecuritypriv->dot11AuthAlgrthm; ++ ++ pcmd->cmdcode = _SetAuth_CMD_; ++ pcmd->parmbuf = (unsigned char *)psetauthparm; ++ pcmd->cmdsz = (sizeof(struct setauth_parm)); ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ ++ ++ _rtw_init_listhead(&pcmd->list); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("after enqueue set_auth_cmd, auth_mode=%x\n", psecuritypriv->dot11AuthAlgrthm)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++ ++} ++ ++ ++sint rtw_set_key(_adapter * adapter,struct security_priv *psecuritypriv,sint keyid, u8 set_tx, bool enqueue) ++{ ++ u8 keylen; ++ struct cmd_obj *pcmd; ++ struct setkey_parm *psetkeyparm; ++ struct cmd_priv *pcmdpriv = &(adapter->cmdpriv); ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ sint res=_SUCCESS; ++ ++_func_enter_; ++ ++ psetkeyparm=(struct setkey_parm*)rtw_zmalloc(sizeof(struct setkey_parm)); ++ if(psetkeyparm==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ _rtw_memset(psetkeyparm, 0, sizeof(struct setkey_parm)); ++ ++ if(psecuritypriv->dot11AuthAlgrthm ==dot11AuthAlgrthm_8021X){ ++ psetkeyparm->algorithm=(unsigned char)psecuritypriv->dot118021XGrpPrivacy; ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("\n rtw_set_key: psetkeyparm->algorithm=(unsigned char)psecuritypriv->dot118021XGrpPrivacy=%d \n", psetkeyparm->algorithm)); ++ } ++ else{ ++ psetkeyparm->algorithm=(u8)psecuritypriv->dot11PrivacyAlgrthm; ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("\n rtw_set_key: psetkeyparm->algorithm=(u8)psecuritypriv->dot11PrivacyAlgrthm=%d \n", psetkeyparm->algorithm)); ++ ++ } ++ psetkeyparm->keyid = (u8)keyid;//0~3 ++ psetkeyparm->set_tx = set_tx; ++ if (is_wep_enc(psetkeyparm->algorithm)) ++ psecuritypriv->key_mask |= BIT(psetkeyparm->keyid); ++ ++ DBG_871X("==> rtw_set_key algorithm(%x),keyid(%x),key_mask(%x)\n",psetkeyparm->algorithm,psetkeyparm->keyid, psecuritypriv->key_mask); ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("\n rtw_set_key: psetkeyparm->algorithm=%d psetkeyparm->keyid=(u8)keyid=%d \n",psetkeyparm->algorithm, keyid)); ++ ++ switch(psetkeyparm->algorithm){ ++ ++ case _WEP40_: ++ keylen=5; ++ _rtw_memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen); ++ break; ++ case _WEP104_: ++ keylen=13; ++ _rtw_memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen); ++ break; ++ case _TKIP_: ++ keylen=16; ++ _rtw_memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen); ++ psetkeyparm->grpkey=1; ++ break; ++ case _AES_: ++ keylen=16; ++ _rtw_memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen); ++ psetkeyparm->grpkey=1; ++ break; ++ default: ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("\n rtw_set_key:psecuritypriv->dot11PrivacyAlgrthm = %x (must be 1 or 2 or 4 or 5)\n",psecuritypriv->dot11PrivacyAlgrthm)); ++ res= _FAIL; ++ rtw_mfree((unsigned char *)psetkeyparm, sizeof(struct setkey_parm)); ++ goto exit; ++ } ++ ++ ++ if(enqueue){ ++ pcmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(pcmd==NULL){ ++ rtw_mfree((unsigned char *)psetkeyparm, sizeof(struct setkey_parm)); ++ res= _FAIL; //try again ++ goto exit; ++ } ++ ++ pcmd->cmdcode = _SetKey_CMD_; ++ pcmd->parmbuf = (u8 *)psetkeyparm; ++ pcmd->cmdsz = (sizeof(struct setkey_parm)); ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ ++ _rtw_init_listhead(&pcmd->list); ++ ++ //_rtw_init_sema(&(pcmd->cmd_sem), 0); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++ } ++ else{ ++ setkey_hdl(adapter, (u8 *)psetkeyparm); ++ rtw_mfree((u8 *) psetkeyparm, sizeof(struct setkey_parm)); ++ } ++exit: ++_func_exit_; ++ return res; ++ ++} ++ ++ ++//adjust IEs for rtw_joinbss_cmd in WMM ++int rtw_restruct_wmm_ie(_adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len, uint initial_out_len) ++{ ++ unsigned int ielength=0; ++ unsigned int i, j; ++ ++ i = 12; //after the fixed IE ++ while(i=0 :if there is pre-auth key, and return the entry id ++// ++// ++ ++static int SecIsInPMKIDList(_adapter *Adapter, u8 *bssid) ++{ ++ struct security_priv *psecuritypriv=&Adapter->securitypriv; ++ int i=0; ++ ++ do ++ { ++ if( ( psecuritypriv->PMKIDList[i].bUsed ) && ++ ( _rtw_memcmp( psecuritypriv->PMKIDList[i].Bssid, bssid, ETH_ALEN ) == _TRUE ) ) ++ { ++ break; ++ } ++ else ++ { ++ i++; ++ //continue; ++ } ++ ++ }while(isecuritypriv; ++ ++ if(ie[13]<=20){ ++ // The RSN IE didn't include the PMK ID, append the PMK information ++ ie[ie_len]=1; ++ ie_len++; ++ ie[ie_len]=0; //PMKID count = 0x0100 ++ ie_len++; ++ _rtw_memcpy( &ie[ie_len], &psecuritypriv->PMKIDList[iEntry].PMKID, 16); ++ ++ ie_len+=16; ++ ie[13]+=18;//PMKID length = 2+16 ++ ++ } ++ return (ie_len); ++ ++} ++sint rtw_restruct_sec_ie(_adapter *adapter,u8 *in_ie, u8 *out_ie, uint in_len) ++{ ++ u8 authmode, securitytype, match; ++ u8 sec_ie[255], uncst_oui[4], bkup_ie[255]; ++ u8 wpa_oui[4]={0x0, 0x50, 0xf2, 0x01}; ++ uint ielength, cnt, remove_cnt; ++ int iEntry; ++ ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct security_priv *psecuritypriv=&adapter->securitypriv; ++ uint ndisauthmode=psecuritypriv->ndisauthtype; ++ uint ndissecuritytype = psecuritypriv->ndisencryptstatus; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ++ ("+rtw_restruct_sec_ie: ndisauthmode=%d ndissecuritytype=%d\n", ++ ndisauthmode, ndissecuritytype)); ++ ++ //copy fixed ie only ++ _rtw_memcpy(out_ie, in_ie,12); ++ ielength=12; ++ if((ndisauthmode==Ndis802_11AuthModeWPA)||(ndisauthmode==Ndis802_11AuthModeWPAPSK)) ++ authmode=_WPA_IE_ID_; ++ if((ndisauthmode==Ndis802_11AuthModeWPA2)||(ndisauthmode==Ndis802_11AuthModeWPA2PSK)) ++ authmode=_WPA2_IE_ID_; ++ ++ if(check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) ++ { ++ _rtw_memcpy(out_ie+ielength, psecuritypriv->wps_ie, psecuritypriv->wps_ie_len); ++ ++ ielength += psecuritypriv->wps_ie_len; ++ } ++ else if((authmode==_WPA_IE_ID_)||(authmode==_WPA2_IE_ID_)) ++ { ++ //copy RSN or SSN ++ _rtw_memcpy(&out_ie[ielength], &psecuritypriv->supplicant_ie[0], psecuritypriv->supplicant_ie[1]+2); ++ /* debug for CONFIG_IEEE80211W ++ { ++ int jj; ++ printk("supplicant_ie_length=%d &&&&&&&&&&&&&&&&&&&\n", psecuritypriv->supplicant_ie[1]+2); ++ for(jj=0; jj < psecuritypriv->supplicant_ie[1]+2; jj++) ++ printk(" %02x ", psecuritypriv->supplicant_ie[jj]); ++ printk("\n"); ++ }*/ ++ ielength+=psecuritypriv->supplicant_ie[1]+2; ++ rtw_report_sec_ie(adapter, authmode, psecuritypriv->supplicant_ie); ++ ++#ifdef CONFIG_DRVEXT_MODULE ++ drvext_report_sec_ie(&adapter->drvextpriv, authmode, sec_ie); ++#endif ++ } ++ ++ iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid); ++ if(iEntry<0) ++ { ++ return ielength; ++ } ++ else ++ { ++ if(authmode == _WPA2_IE_ID_) ++ { ++ ielength=rtw_append_pmkid(adapter, iEntry, out_ie, ielength); ++ } ++ } ++ ++_func_exit_; ++ ++ return ielength; ++} ++ ++void rtw_init_registrypriv_dev_network( _adapter* adapter) ++{ ++ struct registry_priv* pregistrypriv = &adapter->registrypriv; ++ struct eeprom_priv* peepriv = &adapter->eeprompriv; ++ WLAN_BSSID_EX *pdev_network = &pregistrypriv->dev_network; ++ u8 *myhwaddr = myid(peepriv); ++ ++_func_enter_; ++ ++ _rtw_memcpy(pdev_network->MacAddress, myhwaddr, ETH_ALEN); ++ ++ _rtw_memcpy(&pdev_network->Ssid, &pregistrypriv->ssid, sizeof(NDIS_802_11_SSID)); ++ ++ pdev_network->Configuration.Length=sizeof(NDIS_802_11_CONFIGURATION); ++ pdev_network->Configuration.BeaconPeriod = 100; ++ pdev_network->Configuration.FHConfig.Length = 0; ++ pdev_network->Configuration.FHConfig.HopPattern = 0; ++ pdev_network->Configuration.FHConfig.HopSet = 0; ++ pdev_network->Configuration.FHConfig.DwellTime = 0; ++ ++ ++_func_exit_; ++ ++} ++ ++void rtw_update_registrypriv_dev_network(_adapter* adapter) ++{ ++ int sz=0; ++ struct registry_priv* pregistrypriv = &adapter->registrypriv; ++ WLAN_BSSID_EX *pdev_network = &pregistrypriv->dev_network; ++ struct security_priv* psecuritypriv = &adapter->securitypriv; ++ struct wlan_network *cur_network = &adapter->mlmepriv.cur_network; ++ //struct xmit_priv *pxmitpriv = &adapter->xmitpriv; ++ ++_func_enter_; ++ ++#if 0 ++ pxmitpriv->vcs_setting = pregistrypriv->vrtl_carrier_sense; ++ pxmitpriv->vcs = pregistrypriv->vcs_type; ++ pxmitpriv->vcs_type = pregistrypriv->vcs_type; ++ //pxmitpriv->rts_thresh = pregistrypriv->rts_thresh; ++ pxmitpriv->frag_len = pregistrypriv->frag_thresh; ++ ++ adapter->qospriv.qos_option = pregistrypriv->wmm_enable; ++#endif ++ ++ pdev_network->Privacy = (psecuritypriv->dot11PrivacyAlgrthm > 0 ? 1 : 0) ; // adhoc no 802.1x ++ ++ pdev_network->Rssi = 0; ++ ++ switch(pregistrypriv->wireless_mode) ++ { ++ case WIRELESS_11B: ++ pdev_network->NetworkTypeInUse = (Ndis802_11DS); ++ break; ++ case WIRELESS_11G: ++ case WIRELESS_11BG: ++ case WIRELESS_11_24N: ++ case WIRELESS_11G_24N: ++ case WIRELESS_11BG_24N: ++ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24); ++ break; ++ case WIRELESS_11A: ++ case WIRELESS_11A_5N: ++ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM5); ++ break; ++ case WIRELESS_11ABGN: ++ if(pregistrypriv->channel > 14) ++ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM5); ++ else ++ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24); ++ break; ++ default : ++ // TODO ++ break; ++ } ++ ++ pdev_network->Configuration.DSConfig = (pregistrypriv->channel); ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("pregistrypriv->channel=%d, pdev_network->Configuration.DSConfig=0x%x\n", pregistrypriv->channel, pdev_network->Configuration.DSConfig)); ++ ++ if(cur_network->network.InfrastructureMode == Ndis802_11IBSS) ++ pdev_network->Configuration.ATIMWindow = (0); ++ ++ pdev_network->InfrastructureMode = (cur_network->network.InfrastructureMode); ++ ++ // 1. Supported rates ++ // 2. IE ++ ++ //rtw_set_supported_rate(pdev_network->SupportedRates, pregistrypriv->wireless_mode) ; // will be called in rtw_generate_ie ++ sz = rtw_generate_ie(pregistrypriv); ++ ++ pdev_network->IELength = sz; ++ ++ pdev_network->Length = get_WLAN_BSSID_EX_sz((WLAN_BSSID_EX *)pdev_network); ++ ++ //notes: translate IELength & Length after assign the Length to cmdsz in createbss_cmd(); ++ //pdev_network->IELength = cpu_to_le32(sz); ++ ++_func_exit_; ++ ++} ++ ++void rtw_get_encrypt_decrypt_from_registrypriv(_adapter* adapter) ++{ ++_func_enter_; ++ ++ ++_func_exit_; ++ ++} ++ ++//the fucntion is at passive_level ++void rtw_joinbss_reset(_adapter *padapter) ++{ ++ u8 threshold; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++#ifdef CONFIG_80211N_HT ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++#endif ++ ++ //todo: if you want to do something io/reg/hw setting before join_bss, please add code here ++ ++ ++ ++ ++#ifdef CONFIG_80211N_HT ++ ++ pmlmepriv->num_FortyMHzIntolerant = 0; ++ ++ pmlmepriv->num_sta_no_ht = 0; ++ ++ phtpriv->ampdu_enable = _FALSE;//reset to disabled ++ ++#ifdef CONFIG_USB_HCI ++ // TH=1 => means that invalidate usb rx aggregation ++ // TH=0 => means that validate usb rx aggregation, use init value. ++ if(phtpriv->ht_option) ++ { ++ if(padapter->registrypriv.wifi_spec==1) ++ threshold = 1; ++ else ++ threshold = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); ++ } ++ else ++ { ++ threshold = 1; ++ rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); ++ } ++#endif ++ ++#endif ++ ++} ++ ++ ++#ifdef CONFIG_80211N_HT ++ ++//the fucntion is >= passive_level ++unsigned int rtw_restructure_ht_ie(_adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len) ++{ ++ u32 ielen, out_len; ++ HT_CAP_AMPDU_FACTOR max_rx_ampdu_factor; ++ unsigned char *p, *pframe; ++ struct rtw_ieee80211_ht_cap ht_capie; ++ unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct qos_priv *pqospriv= &pmlmepriv->qospriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ ++ ++ phtpriv->ht_option = _FALSE; ++ ++ p = rtw_get_ie(in_ie+12, _HT_CAPABILITY_IE_, &ielen, in_len-12); ++ ++ if(p && ielen>0) ++ { ++ if(pqospriv->qos_option == 0) ++ { ++ out_len = *pout_len; ++ pframe = rtw_set_ie(out_ie+out_len, _VENDOR_SPECIFIC_IE_, ++ _WMM_IE_Length_, WMM_IE, pout_len); ++ ++ pqospriv->qos_option = 1; ++ } ++ ++ out_len = *pout_len; ++ ++ _rtw_memset(&ht_capie, 0, sizeof(struct rtw_ieee80211_ht_cap)); ++ ++ ht_capie.cap_info = IEEE80211_HT_CAP_SUP_WIDTH |IEEE80211_HT_CAP_SGI_20 | ++ IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_TX_STBC | ++ IEEE80211_HT_CAP_DSSSCCK40; ++ ++ ++ { ++ u32 rx_packet_offset, max_recvbuf_sz; ++ rtw_hal_get_def_var(padapter, HAL_DEF_RX_PACKET_OFFSET, &rx_packet_offset); ++ rtw_hal_get_def_var(padapter, HAL_DEF_MAX_RECVBUF_SZ, &max_recvbuf_sz); ++ //if(max_recvbuf_sz-rx_packet_offset>(8191-256)) { ++ // DBG_871X("%s IEEE80211_HT_CAP_MAX_AMSDU is set\n", __FUNCTION__); ++ // ht_capie.cap_info = ht_capie.cap_info |IEEE80211_HT_CAP_MAX_AMSDU; ++ //} ++ } ++ /* ++ AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k ++ AMPDU_para [4:2]:Min MPDU Start Spacing ++ */ ++ ++ /* ++ #if defined(CONFIG_RTL8188E )&& defined (CONFIG_SDIO_HCI) ++ ht_capie.ampdu_params_info = 2; ++ #else ++ ht_capie.ampdu_params_info = (IEEE80211_HT_CAP_AMPDU_FACTOR&0x03); ++ #endif ++ */ ++ ++ rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); ++ ht_capie.ampdu_params_info = (max_rx_ampdu_factor&0x03); ++ ++ if(padapter->securitypriv.dot11PrivacyAlgrthm == _AES_ ) ++ ht_capie.ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&(0x07<<2)); ++ else ++ ht_capie.ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&0x00); ++ ++ ++ pframe = rtw_set_ie(out_ie+out_len, _HT_CAPABILITY_IE_, ++ sizeof(struct rtw_ieee80211_ht_cap), (unsigned char*)&ht_capie, pout_len); ++ ++ ++ //_rtw_memcpy(out_ie+out_len, p, ielen+2);//gtest ++ //*pout_len = *pout_len + (ielen+2); ++ ++ ++ phtpriv->ht_option = _TRUE; ++ ++ p = rtw_get_ie(in_ie+12, _HT_ADD_INFO_IE_, &ielen, in_len-12); ++ if(p && (ielen==sizeof(struct ieee80211_ht_addt_info))) ++ { ++ out_len = *pout_len; ++ pframe = rtw_set_ie(out_ie+out_len, _HT_ADD_INFO_IE_, ielen, p+2 , pout_len); ++ } ++ ++ } ++ ++ return (phtpriv->ht_option); ++ ++} ++ ++//the fucntion is > passive_level (in critical_section) ++void rtw_update_ht_cap(_adapter *padapter, u8 *pie, uint ie_len) ++{ ++ u8 *p, max_ampdu_sz; ++ int len; ++ //struct sta_info *bmc_sta, *psta; ++ struct rtw_ieee80211_ht_cap *pht_capie; ++ struct ieee80211_ht_addt_info *pht_addtinfo; ++ //struct recv_reorder_ctrl *preorder_ctrl; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ //struct recv_priv *precvpriv = &padapter->recvpriv; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ //struct wlan_network *pcur_network = &(pmlmepriv->cur_network);; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ ++ if(!phtpriv->ht_option) ++ return; ++ ++ if ((!pmlmeinfo->HT_info_enable) || (!pmlmeinfo->HT_caps_enable)) ++ return; ++ ++ DBG_871X("+rtw_update_ht_cap()\n"); ++ ++ //maybe needs check if ap supports rx ampdu. ++ if((phtpriv->ampdu_enable==_FALSE) &&(pregistrypriv->ampdu_enable==1)) ++ { ++ if(pregistrypriv->wifi_spec==1) ++ { ++ phtpriv->ampdu_enable = _FALSE; ++ } ++ else ++ { ++ phtpriv->ampdu_enable = _TRUE; ++ } ++ } ++ else if(pregistrypriv->ampdu_enable==2) ++ { ++ phtpriv->ampdu_enable = _TRUE; ++ } ++ ++ ++ //check Max Rx A-MPDU Size ++ len = 0; ++ p = rtw_get_ie(pie+sizeof (NDIS_802_11_FIXED_IEs), _HT_CAPABILITY_IE_, &len, ie_len-sizeof (NDIS_802_11_FIXED_IEs)); ++ if(p && len>0) ++ { ++ pht_capie = (struct rtw_ieee80211_ht_cap *)(p+2); ++ max_ampdu_sz = (pht_capie->ampdu_params_info & IEEE80211_HT_CAP_AMPDU_FACTOR); ++ max_ampdu_sz = 1 << (max_ampdu_sz+3); // max_ampdu_sz (kbytes); ++ ++ //DBG_871X("rtw_update_ht_cap(): max_ampdu_sz=%d\n", max_ampdu_sz); ++ phtpriv->rx_ampdu_maxlen = max_ampdu_sz; ++ ++ } ++ ++ ++ len=0; ++ p = rtw_get_ie(pie+sizeof (NDIS_802_11_FIXED_IEs), _HT_ADD_INFO_IE_, &len, ie_len-sizeof (NDIS_802_11_FIXED_IEs)); ++ if(p && len>0) ++ { ++ pht_addtinfo = (struct ieee80211_ht_addt_info *)(p+2); ++ //todo: ++ } ++ ++ ++ //update cur_bwmode & cur_ch_offset ++ if ((pregistrypriv->cbw40_enable) && ++ (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & BIT(1)) && ++ (pmlmeinfo->HT_info.infos[0] & BIT(2))) ++ { ++ int i; ++ u8 rf_type; ++ ++ padapter->HalFunc.GetHwRegHandler(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ ++ //update the MCS rates ++ for (i = 0; i < 16; i++) ++ { ++ if((rf_type == RF_1T1R) || (rf_type == RF_1T2R)) ++ { ++ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i]; ++ } ++ else ++ { ++ #ifdef CONFIG_DISABLE_MCS13TO15 ++ if(pmlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40 && pregistrypriv->wifi_spec != 1 ) ++ { ++ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R_MCS13TO15_OFF[i]; ++ } ++ else ++ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R[i]; ++ #else ++ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R[i]; ++ #endif //CONFIG_DISABLE_MCS13TO15 ++ } ++ #ifdef RTL8192C_RECONFIG_TO_1T1R ++ { ++ pmlmeinfo->HT_caps.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i]; ++ } ++ #endif ++ } ++ //switch to the 40M Hz mode accoring to the AP ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; ++ switch ((pmlmeinfo->HT_info.infos[0] & 0x3)) ++ { ++ case HT_EXTCHNL_OFFSET_UPPER: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ break; ++ ++ case HT_EXTCHNL_OFFSET_LOWER: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ break; ++ ++ default: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ break; ++ } ++ } ++ ++ // ++ // Config SM Power Save setting ++ // ++ pmlmeinfo->SM_PS = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2; ++ if(pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) ++ { ++ /*u8 i; ++ //update the MCS rates ++ for (i = 0; i < 16; i++) ++ { ++ pmlmeinfo->HT_caps.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i]; ++ }*/ ++ DBG_871X("%s(): WLAN_HT_CAP_SM_PS_STATIC\n",__FUNCTION__); ++ } ++ ++ // ++ // Config current HT Protection mode. ++ // ++ pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3; ++ ++ ++ ++#if 0 //move to rtw_update_sta_info_client() ++ //for A-MPDU Rx reordering buffer control for bmc_sta & sta_info ++ //if A-MPDU Rx is enabled, reseting rx_ordering_ctrl wstart_b(indicate_seq) to default value=0xffff ++ //todo: check if AP can send A-MPDU packets ++ bmc_sta = rtw_get_bcmc_stainfo(padapter); ++ if(bmc_sta) ++ { ++ for(i=0; i < 16 ; i++) ++ { ++ //preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; ++ preorder_ctrl = &bmc_sta->recvreorder_ctrl[i]; ++ preorder_ctrl->enable = _FALSE; ++ preorder_ctrl->indicate_seq = 0xffff; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d indicate_seq:%u \n", __FUNCTION__, __LINE__, ++ preorder_ctrl->indicate_seq); ++ #endif ++ preorder_ctrl->wend_b= 0xffff; ++ preorder_ctrl->wsize_b = 64;//max_ampdu_sz;//ex. 32(kbytes) -> wsize_b=32 ++ } ++ } ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, pcur_network->network.MacAddress); ++ if(psta) ++ { ++ for(i=0; i < 16 ; i++) ++ { ++ //preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ preorder_ctrl->enable = _FALSE; ++ preorder_ctrl->indicate_seq = 0xffff; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d indicate_seq:%u \n", __FUNCTION__, __LINE__, ++ preorder_ctrl->indicate_seq); ++ #endif ++ preorder_ctrl->wend_b= 0xffff; ++ preorder_ctrl->wsize_b = 64;//max_ampdu_sz;//ex. 32(kbytes) -> wsize_b=32 ++ } ++ } ++#endif ++ ++} ++ ++void rtw_issue_addbareq_cmd(_adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ u8 issued; ++ int priority; ++ struct sta_info *psta=NULL; ++ struct ht_priv *phtpriv; ++ struct pkt_attrib *pattrib =&pxmitframe->attrib; ++ s32 bmcst = IS_MCAST(pattrib->ra); ++ ++ //if(bmcst || (padapter->mlmepriv.LinkDetectInfo.bTxBusyTraffic == _FALSE)) ++ if(bmcst || (padapter->mlmepriv.LinkDetectInfo.NumTxOkInPeriod<100)) ++ return; ++ ++ priority = pattrib->priority; ++ ++ if (pattrib->psta) ++ psta = pattrib->psta; ++ else ++ { ++ DBG_871X("%s, call rtw_get_stainfo()\n", __func__); ++ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); ++ } ++ ++ if(psta==NULL) ++ { ++ DBG_871X("%s, psta==NUL\n", __func__); ++ return; ++ } ++ ++ if(!(psta->state &_FW_LINKED)) ++ { ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); ++ return; ++ } ++ ++ ++ phtpriv = &psta->htpriv; ++ ++ if((phtpriv->ht_option==_TRUE) && (phtpriv->ampdu_enable==_TRUE)) ++ { ++ issued = (phtpriv->agg_enable_bitmap>>priority)&0x1; ++ issued |= (phtpriv->candidate_tid_bitmap>>priority)&0x1; ++ ++ if(0==issued) ++ { ++ DBG_871X("rtw_issue_addbareq_cmd, p=%d\n", priority); ++ psta->htpriv.candidate_tid_bitmap |= BIT((u8)priority); ++ rtw_addbareq_cmd(padapter,(u8) priority, pattrib->ra); ++ } ++ } ++ ++} ++ ++#endif ++ ++#ifdef CONFIG_LAYER2_ROAMING ++inline void rtw_set_roaming(_adapter *adapter, u8 to_roaming) ++{ ++ if (to_roaming == 0) ++ adapter->mlmepriv.to_join = _FALSE; ++ adapter->mlmepriv.to_roaming = to_roaming; ++} ++ ++inline u8 rtw_to_roaming(_adapter *adapter) ++{ ++ return adapter->mlmepriv.to_roaming; ++} ++ ++void rtw_roaming(_adapter *padapter, struct wlan_network *tgt_network) ++{ ++ _irqL irqL; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ _rtw_roaming(padapter, tgt_network); ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++} ++void _rtw_roaming(_adapter *padapter, struct wlan_network *tgt_network) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ int do_join_r; ++ ++ struct wlan_network *pnetwork; ++ ++ if(tgt_network != NULL) ++ pnetwork = tgt_network; ++ else ++ pnetwork = &pmlmepriv->cur_network; ++ ++ if(0 < rtw_to_roaming(padapter)) { ++ DBG_871X("roaming from %s("MAC_FMT"), length:%d\n", ++ pnetwork->network.Ssid.Ssid, MAC_ARG(pnetwork->network.MacAddress), ++ pnetwork->network.Ssid.SsidLength); ++ _rtw_memcpy(&pmlmepriv->assoc_ssid, &pnetwork->network.Ssid, sizeof(NDIS_802_11_SSID)); ++ ++ pmlmepriv->assoc_by_bssid = _FALSE; ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ rtw_wapi_return_all_sta_info(padapter); ++#endif ++ ++ while(1) { ++ if( _SUCCESS==(do_join_r=rtw_do_join(padapter)) ) { ++ break; ++ } else { ++ DBG_871X("roaming do_join return %d\n", do_join_r); ++ pmlmepriv->to_roaming--; ++ ++ if(0< rtw_to_roaming(padapter)) { ++ continue; ++ } else { ++ DBG_871X("%s(%d) -to roaming fail, indicate_disconnect\n", __FUNCTION__,__LINE__); ++ rtw_indicate_disconnect(padapter); ++ break; ++ } ++ } ++ } ++ } ++ ++} ++#endif ++ ++sint rtw_linked_check(_adapter *padapter) ++{ ++ if( (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE) || ++ (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) == _TRUE)) ++ { ++ if(padapter->stapriv.asoc_sta_count > 2) ++ return _TRUE; ++ } ++ else ++ { //Station mode ++ if(check_fwstate(&padapter->mlmepriv, _FW_LINKED)== _TRUE) ++ return _TRUE; ++ } ++ return _FALSE; ++} ++ ++#ifdef CONFIG_CONCURRENT_MODE ++sint rtw_buddy_adapter_up(_adapter *padapter) ++{ ++ sint res = _FALSE; ++ ++ if(padapter == NULL) ++ return res; ++ ++ ++ if(padapter->pbuddy_adapter == NULL) ++ { ++ res = _FALSE; ++ } ++ else if( (padapter->pbuddy_adapter->bDriverStopped) || (padapter->pbuddy_adapter->bSurpriseRemoved) || ++ (padapter->pbuddy_adapter->bup == _FALSE) || (padapter->pbuddy_adapter->hw_init_completed == _FALSE)) ++ { ++ res = _FALSE; ++ } ++ else ++ { ++ res = _TRUE; ++ } ++ ++ return res; ++ ++} ++ ++sint check_buddy_fwstate(_adapter *padapter, sint state) ++{ ++ if(padapter == NULL) ++ return _FALSE; ++ ++ if(padapter->pbuddy_adapter == NULL) ++ return _FALSE; ++ ++ if ((state == WIFI_FW_NULL_STATE) && ++ (padapter->pbuddy_adapter->mlmepriv.fw_state == WIFI_FW_NULL_STATE)) ++ return _TRUE; ++ ++ if (padapter->pbuddy_adapter->mlmepriv.fw_state & state) ++ return _TRUE; ++ ++ return _FALSE; ++} ++ ++u8 rtw_get_buddy_bBusyTraffic(_adapter *padapter) ++{ ++ if(padapter == NULL) ++ return _FALSE; ++ ++ if(padapter->pbuddy_adapter == NULL) ++ return _FALSE; ++ ++ return padapter->pbuddy_adapter->mlmepriv.LinkDetectInfo.bBusyTraffic; ++} ++ ++#endif //CONFIG_CONCURRENT_MODE ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_mlme_ext.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_mlme_ext.c +new file mode 100644 +index 00000000..b244cef0 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_mlme_ext.c +@@ -0,0 +1,13543 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_MLME_EXT_C_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_BT_COEXIST ++#include ++#endif ++ ++struct mlme_handler mlme_sta_tbl[]={ ++ {WIFI_ASSOCREQ, "OnAssocReq", &OnAssocReq}, ++ {WIFI_ASSOCRSP, "OnAssocRsp", &OnAssocRsp}, ++ {WIFI_REASSOCREQ, "OnReAssocReq", &OnAssocReq}, ++ {WIFI_REASSOCRSP, "OnReAssocRsp", &OnAssocRsp}, ++ {WIFI_PROBEREQ, "OnProbeReq", &OnProbeReq}, ++ {WIFI_PROBERSP, "OnProbeRsp", &OnProbeRsp}, ++ ++ /*---------------------------------------------------------- ++ below 2 are reserved ++ -----------------------------------------------------------*/ ++ {0, "DoReserved", &DoReserved}, ++ {0, "DoReserved", &DoReserved}, ++ {WIFI_BEACON, "OnBeacon", &OnBeacon}, ++ {WIFI_ATIM, "OnATIM", &OnAtim}, ++ {WIFI_DISASSOC, "OnDisassoc", &OnDisassoc}, ++ {WIFI_AUTH, "OnAuth", &OnAuthClient}, ++ {WIFI_DEAUTH, "OnDeAuth", &OnDeAuth}, ++ {WIFI_ACTION, "OnAction", &OnAction}, ++}; ++ ++#ifdef _CONFIG_NATIVEAP_MLME_ ++struct mlme_handler mlme_ap_tbl[]={ ++ {WIFI_ASSOCREQ, "OnAssocReq", &OnAssocReq}, ++ {WIFI_ASSOCRSP, "OnAssocRsp", &OnAssocRsp}, ++ {WIFI_REASSOCREQ, "OnReAssocReq", &OnAssocReq}, ++ {WIFI_REASSOCRSP, "OnReAssocRsp", &OnAssocRsp}, ++ {WIFI_PROBEREQ, "OnProbeReq", &OnProbeReq}, ++ {WIFI_PROBERSP, "OnProbeRsp", &OnProbeRsp}, ++ ++ /*---------------------------------------------------------- ++ below 2 are reserved ++ -----------------------------------------------------------*/ ++ {0, "DoReserved", &DoReserved}, ++ {0, "DoReserved", &DoReserved}, ++ {WIFI_BEACON, "OnBeacon", &OnBeacon}, ++ {WIFI_ATIM, "OnATIM", &OnAtim}, ++ {WIFI_DISASSOC, "OnDisassoc", &OnDisassoc}, ++ {WIFI_AUTH, "OnAuth", &OnAuth}, ++ {WIFI_DEAUTH, "OnDeAuth", &OnDeAuth}, ++ {WIFI_ACTION, "OnAction", &OnAction}, ++}; ++#endif ++ ++struct action_handler OnAction_tbl[]={ ++ {RTW_WLAN_CATEGORY_SPECTRUM_MGMT, "ACTION_SPECTRUM_MGMT", on_action_spct}, ++ {RTW_WLAN_CATEGORY_QOS, "ACTION_QOS", &OnAction_qos}, ++ {RTW_WLAN_CATEGORY_DLS, "ACTION_DLS", &OnAction_dls}, ++ {RTW_WLAN_CATEGORY_BACK, "ACTION_BACK", &OnAction_back}, ++ {RTW_WLAN_CATEGORY_PUBLIC, "ACTION_PUBLIC", on_action_public}, ++ {RTW_WLAN_CATEGORY_RADIO_MEASUREMENT, "ACTION_RADIO_MEASUREMENT", &DoReserved}, ++ {RTW_WLAN_CATEGORY_FT, "ACTION_FT", &DoReserved}, ++ {RTW_WLAN_CATEGORY_HT, "ACTION_HT", &OnAction_ht}, ++#ifdef CONFIG_IEEE80211W ++ {RTW_WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &OnAction_sa_query}, ++#else ++ {RTW_WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &DoReserved}, ++#endif //CONFIG_IEEE80211W ++ //add for CONFIG_IEEE80211W ++ {RTW_WLAN_CATEGORY_UNPROTECTED_WNM, "ACTION_UNPROTECTED_WNM", &DoReserved}, ++ {RTW_WLAN_CATEGORY_SELF_PROTECTED, "ACTION_SELF_PROTECTED", &DoReserved}, ++ {RTW_WLAN_CATEGORY_WMM, "ACTION_WMM", &OnAction_wmm}, ++ {RTW_WLAN_CATEGORY_P2P, "ACTION_P2P", &OnAction_p2p}, ++}; ++ ++ ++u8 null_addr[ETH_ALEN]= {0,0,0,0,0,0}; ++ ++/************************************************** ++OUI definitions for the vendor specific IE ++***************************************************/ ++unsigned char RTW_WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01}; ++unsigned char WMM_OUI[] = {0x00, 0x50, 0xf2, 0x02}; ++unsigned char WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04}; ++unsigned char P2P_OUI[] = {0x50,0x6F,0x9A,0x09}; ++unsigned char WFD_OUI[] = {0x50,0x6F,0x9A,0x0A}; ++ ++unsigned char WMM_INFO_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; ++unsigned char WMM_PARA_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; ++ ++unsigned char WPA_TKIP_CIPHER[4] = {0x00, 0x50, 0xf2, 0x02}; ++unsigned char RSN_TKIP_CIPHER[4] = {0x00, 0x0f, 0xac, 0x02}; ++ ++extern unsigned char REALTEK_96B_IE[]; ++ ++/******************************************************** ++MCS rate definitions ++*********************************************************/ ++#ifdef CONFIG_DISABLE_MCS13TO15 ++unsigned char MCS_rate_2R_MCS13TO15_OFF[16] = {0xff, 0x1f, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; ++unsigned char MCS_rate_2R[16] = {0xff, 0xff, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; ++#else //CONFIG_DISABLE_MCS13TO15 ++unsigned char MCS_rate_2R[16] = {0xff, 0xff, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; ++#endif //CONFIG_DISABLE_MCS13TO15 ++unsigned char MCS_rate_1R[16] = {0xff, 0x00, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; ++ ++/******************************************************** ++ChannelPlan definitions ++*********************************************************/ ++/*static RT_CHANNEL_PLAN DefaultChannelPlan[RT_CHANNEL_DOMAIN_MAX] = { ++ {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64,100,104,108,112,116,132,136,140,149,153,157,161,165},32}, // 0x00, RT_CHANNEL_DOMAIN_FCC ++ {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64,100,104,108,112,116,136,140,149,153,157,161,165},31}, // 0x01, RT_CHANNEL_DOMAIN_IC ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140},32}, // 0x02, RT_CHANNEL_DOMAIN_ETSI ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13}, // 0x03, RT_CHANNEL_DOMAIN_SPAIN ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13}, // 0x04, RT_CHANNEL_DOMAIN_FRANCE ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13}, // 0x05, RT_CHANNEL_DOMAIN_MKK ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13}, // 0x06, RT_CHANNEL_DOMAIN_MKK1 ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, // 0x07, RT_CHANNEL_DOMAIN_ISRAEL ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14,36,40,44,48,52,56,60,64},22}, // 0x08, RT_CHANNEL_DOMAIN_TELEC ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14}, // 0x09, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13}, // 0x0A, RT_CHANNEL_DOMAIN_WORLD_WIDE_13 ++ {{1,2,3,4,5,6,7,8,9,10,11,56,60,64,100,104,108,112,116,136,140,149,153,157,161,165},26}, // 0x0B, RT_CHANNEL_DOMAIN_TAIWAN ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,149,153,157,161,165},18}, // 0x0C, RT_CHANNEL_DOMAIN_CHINA ++ {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64,149,153,157,161,165},24}, // 0x0D, RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO ++ {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,149,153,157,161,165},31}, // 0x0E, RT_CHANNEL_DOMAIN_KOREA ++ {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64},19}, // 0x0F, RT_CHANNEL_DOMAIN_TURKEY ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140},32}, // 0x10, RT_CHANNEL_DOMAIN_JAPAN ++ {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,149,153,157,161,165},20}, // 0x11, RT_CHANNEL_DOMAIN_FCC_NO_DFS ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48},17}, // 0x12, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140,149,153,157,161,165},37}, // 0x13, RT_CHANNEL_DOMAIN_WORLD_WIDE_5G ++ {{1,2,3,4,5,6,7,8,9,10,11,56,60,64,149,153,157,161,165},19}, // 0x14, RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS ++};*/ ++ ++static RT_CHANNEL_PLAN_2G RTW_ChannelPlan2G[RT_CHANNEL_DOMAIN_2G_MAX] = { ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13}, // 0x00, RT_CHANNEL_DOMAIN_2G_WORLD , Passive scan CH 12, 13 ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13}, // 0x01, RT_CHANNEL_DOMAIN_2G_ETSI1 ++ {{1,2,3,4,5,6,7,8,9,10,11},11}, // 0x02, RT_CHANNEL_DOMAIN_2G_FCC1 ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14}, // 0x03, RT_CHANNEL_DOMAIN_2G_MIKK1 ++ {{10,11,12,13},4}, // 0x04, RT_CHANNEL_DOMAIN_2G_ETSI2 ++ {{},0}, // 0x05, RT_CHANNEL_DOMAIN_2G_NULL ++}; ++ ++static RT_CHANNEL_PLAN_5G RTW_ChannelPlan5G[RT_CHANNEL_DOMAIN_5G_MAX] = { ++ {{},0}, // 0x00, RT_CHANNEL_DOMAIN_5G_NULL ++ {{36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140},19}, // 0x01, RT_CHANNEL_DOMAIN_5G_ETSI1 ++ {{36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140,149,153,157,161,165},24}, // 0x02, RT_CHANNEL_DOMAIN_5G_ETSI2 ++ {{36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,149,153,157,161,165},22}, // 0x03, RT_CHANNEL_DOMAIN_5G_ETSI3 ++ {{36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140,149,153,157,161,165},24}, // 0x04, RT_CHANNEL_DOMAIN_5G_FCC1 ++ {{36,40,44,48,149,153,157,161,165},9}, // 0x05, RT_CHANNEL_DOMAIN_5G_FCC2 ++ {{36,40,44,48,52,56,60,64,149,153,157,161,165},13}, // 0x06, RT_CHANNEL_DOMAIN_5G_FCC3 ++ {{36,40,44,48,52,56,60,64,149,153,157,161},12}, // 0x07, RT_CHANNEL_DOMAIN_5G_FCC4 ++ {{149,153,157,161,165},5}, // 0x08, RT_CHANNEL_DOMAIN_5G_FCC5 ++ {{36,40,44,48,52,56,60,64},8}, // 0x09, RT_CHANNEL_DOMAIN_5G_FCC6 ++ {{36,40,44,48,52,56,60,64,100,104,108,112,116,136,140,149,153,157,161,165},20}, // 0x0A, RT_CHANNEL_DOMAIN_5G_FCC7_IC1 ++ {{36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,149,153,157,161,165},20}, // 0x0B, RT_CHANNEL_DOMAIN_5G_KCC1 ++ {{36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140},19}, // 0x0C, RT_CHANNEL_DOMAIN_5G_MKK1 ++ {{36,40,44,48,52,56,60,64},8}, // 0x0D, RT_CHANNEL_DOMAIN_5G_MKK2 ++ {{100,104,108,112,116,120,124,128,132,136,140},11}, // 0x0E, RT_CHANNEL_DOMAIN_5G_MKK3 ++ {{56,60,64,100,104,108,112,116,136,140,149,153,157,161,165},15}, // 0x0F, RT_CHANNEL_DOMAIN_5G_NCC1 ++ {{56,60,64,149,153,157,161,165},8}, // 0x10, RT_CHANNEL_DOMAIN_5G_NCC2 ++ ++ //===== Driver self defined for old channel plan Compatible ,Remember to modify if have new channel plan definition ===== ++ {{36,40,44,48,52,56,60,64,100,104,108,112,116,132,136,140,149,153,157,161,165},21}, // 0x11, RT_CHANNEL_DOMAIN_5G_FCC ++ {{36,40,44,48},4}, // 0x12, RT_CHANNEL_DOMAIN_5G_JAPAN_NO_DFS ++ {{36,40,44,48,149,153,157,161},8}, // 0x13, RT_CHANNEL_DOMAIN_5G_FCC4_NO_DFS ++}; ++ ++static RT_CHANNEL_PLAN_MAP RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = { ++ //===== 0x00 ~ 0x1F , Old Define ===== ++ {0x02,0x11}, //0x00, RT_CHANNEL_DOMAIN_FCC ++ {0x02,0x0A}, //0x01, RT_CHANNEL_DOMAIN_IC ++ {0x01,0x01}, //0x02, RT_CHANNEL_DOMAIN_ETSI ++ {0x01,0x00}, //0x03, RT_CHANNEL_DOMAIN_SPAIN ++ {0x01,0x00}, //0x04, RT_CHANNEL_DOMAIN_FRANCE ++ {0x03,0x00}, //0x05, RT_CHANNEL_DOMAIN_MKK ++ {0x03,0x00}, //0x06, RT_CHANNEL_DOMAIN_MKK1 ++ {0x01,0x09}, //0x07, RT_CHANNEL_DOMAIN_ISRAEL ++ {0x03,0x09}, //0x08, RT_CHANNEL_DOMAIN_TELEC ++ {0x03,0x00}, //0x09, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN ++ {0x00,0x00}, //0x0A, RT_CHANNEL_DOMAIN_WORLD_WIDE_13 ++ {0x02,0x0F}, //0x0B, RT_CHANNEL_DOMAIN_TAIWAN ++ {0x01,0x08}, //0x0C, RT_CHANNEL_DOMAIN_CHINA ++ {0x02,0x06}, //0x0D, RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO ++ {0x02,0x0B}, //0x0E, RT_CHANNEL_DOMAIN_KOREA ++ {0x02,0x09}, //0x0F, RT_CHANNEL_DOMAIN_TURKEY ++ {0x01,0x01}, //0x10, RT_CHANNEL_DOMAIN_JAPAN ++ {0x02,0x05}, //0x11, RT_CHANNEL_DOMAIN_FCC_NO_DFS ++ {0x01,0x12}, //0x12, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS ++ {0x00,0x04}, //0x13, RT_CHANNEL_DOMAIN_WORLD_WIDE_5G ++ {0x02,0x10}, //0x14, RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS ++ {0x00,0x12}, //0x15, RT_CHANNEL_DOMAIN_ETSI_NO_DFS ++ {0x00,0x13}, //0x16, RT_CHANNEL_DOMAIN_KOREA_NO_DFS ++ {0x03,0x12}, //0x17, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS ++ {0x05,0x08}, //0x18, RT_CHANNEL_DOMAIN_PAKISTAN_NO_DFS ++ {0x02,0x08}, //0x19, RT_CHANNEL_DOMAIN_TAIWAN2_NO_DFS ++ {0x00,0x00}, //0x1A, ++ {0x00,0x00}, //0x1B, ++ {0x00,0x00}, //0x1C, ++ {0x00,0x00}, //0x1D, ++ {0x00,0x00}, //0x1E, ++ {0x05,0x04}, //0x1F, RT_CHANNEL_DOMAIN_WORLD_WIDE_ONLY_5G ++ //===== 0x20 ~ 0x7F ,New Define ===== ++ {0x00,0x00}, //0x20, RT_CHANNEL_DOMAIN_WORLD_NULL ++ {0x01,0x00}, //0x21, RT_CHANNEL_DOMAIN_ETSI1_NULL ++ {0x02,0x00}, //0x22, RT_CHANNEL_DOMAIN_FCC1_NULL ++ {0x03,0x00}, //0x23, RT_CHANNEL_DOMAIN_MKK1_NULL ++ {0x04,0x00}, //0x24, RT_CHANNEL_DOMAIN_ETSI2_NULL ++ {0x02,0x04}, //0x25, RT_CHANNEL_DOMAIN_FCC1_FCC1 ++ {0x00,0x01}, //0x26, RT_CHANNEL_DOMAIN_WORLD_ETSI1 ++ {0x03,0x0C}, //0x27, RT_CHANNEL_DOMAIN_MKK1_MKK1 ++ {0x00,0x0B}, //0x28, RT_CHANNEL_DOMAIN_WORLD_KCC1 ++ {0x00,0x05}, //0x29, RT_CHANNEL_DOMAIN_WORLD_FCC2 ++ {0x00,0x00}, //0x2A, ++ {0x00,0x00}, //0x2B, ++ {0x00,0x00}, //0x2C, ++ {0x00,0x00}, //0x2D, ++ {0x00,0x00}, //0x2E, ++ {0x00,0x00}, //0x2F, ++ {0x00,0x06}, //0x30, RT_CHANNEL_DOMAIN_WORLD_FCC3 ++ {0x00,0x07}, //0x31, RT_CHANNEL_DOMAIN_WORLD_FCC4 ++ {0x00,0x08}, //0x32, RT_CHANNEL_DOMAIN_WORLD_FCC5 ++ {0x00,0x09}, //0x33, RT_CHANNEL_DOMAIN_WORLD_FCC6 ++ {0x02,0x0A}, //0x34, RT_CHANNEL_DOMAIN_FCC1_FCC7 ++ {0x00,0x02}, //0x35, RT_CHANNEL_DOMAIN_WORLD_ETSI2 ++ {0x00,0x03}, //0x36, RT_CHANNEL_DOMAIN_WORLD_ETSI3 ++ {0x03,0x0D}, //0x37, RT_CHANNEL_DOMAIN_MKK1_MKK2 ++ {0x03,0x0E}, //0x38, RT_CHANNEL_DOMAIN_MKK1_MKK3 ++ {0x02,0x0F}, //0x39, RT_CHANNEL_DOMAIN_FCC1_NCC1 ++ {0x00,0x00}, //0x3A, ++ {0x00,0x00}, //0x3B, ++ {0x00,0x00}, //0x3C, ++ {0x00,0x00}, //0x3D, ++ {0x00,0x00}, //0x3E, ++ {0x00,0x00}, //0x3F, ++ {0x02,0x10}, //0x40, RT_CHANNEL_DOMAIN_FCC1_NCC2 ++ {0x03,0x00}, //0x41, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G ++}; ++ ++static RT_CHANNEL_PLAN_MAP RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03,0x02}; //use the conbination for max channel numbers ++ ++/* ++ * Search the @param channel_num in given @param channel_set ++ * @ch_set: the given channel set ++ * @ch: the given channel number ++ * ++ * return the index of channel_num in channel_set, -1 if not found ++ */ ++int rtw_ch_set_search_ch(RT_CHANNEL_INFO *ch_set, const u32 ch) ++{ ++ int i; ++ for(i=0;ch_set[i].ChannelNum!=0;i++){ ++ if(ch == ch_set[i].ChannelNum) ++ break; ++ } ++ ++ if(i >= ch_set[i].ChannelNum) ++ return -1; ++ return i; ++} ++ ++/**************************************************************************** ++ ++Following are the initialization functions for WiFi MLME ++ ++*****************************************************************************/ ++ ++int init_hw_mlme_ext(_adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ //set_opmode_cmd(padapter, infra_client_with_mlme);//removed ++ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ ++ return _SUCCESS; ++} ++ ++static void init_mlme_ext_priv_value(_adapter* padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++#ifdef CONFIG_TDLS ++ u8 i; ++#endif ++ ++ //unsigned char default_channel_set[MAX_CHANNEL_NUM] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0}; ++ unsigned char mixed_datarate[NumRates] = {_1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_,_9M_RATE_, _12M_RATE_, _18M_RATE_, _24M_RATE_, _36M_RATE_, _48M_RATE_, _54M_RATE_, 0xff}; ++ unsigned char mixed_basicrate[NumRates] ={_1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, _12M_RATE_, _24M_RATE_, 0xff,}; ++ ++ ATOMIC_SET(&pmlmeext->event_seq, 0); ++ pmlmeext->mgnt_seq = 0;//reset to zero when disconnect at client mode ++#ifdef CONFIG_IEEE80211W ++ pmlmeext->sa_query_seq = 0; ++ pmlmeext->mgnt_80211w_IPN=0; ++ pmlmeext->mgnt_80211w_IPN_rx=0; ++#endif //CONFIG_IEEE80211W ++ pmlmeext->cur_channel = padapter->registrypriv.channel; ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ pmlmeext->retry = 0; ++ ++ pmlmeext->cur_wireless_mode = padapter->registrypriv.wireless_mode; ++ ++ //_rtw_memcpy(pmlmeext->channel_set, DefaultChannelPlan[padapter->mlmepriv.ChannelPlan].Channel, DefaultChannelPlan[padapter->mlmepriv.ChannelPlan].Len); ++ //_rtw_memcpy(pmlmeext->channel_set, default_channel_set, MAX_CHANNEL_NUM); ++ _rtw_memcpy(pmlmeext->datarate, mixed_datarate, NumRates); ++ _rtw_memcpy(pmlmeext->basicrate, mixed_basicrate, NumRates); ++ ++ if(pmlmeext->cur_channel > 14) ++ pmlmeext->tx_rate = IEEE80211_OFDM_RATE_6MB; ++ else ++ pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB; ++ ++ pmlmeext->sitesurvey_res.state = SCAN_DISABLE; ++ pmlmeext->sitesurvey_res.channel_idx = 0; ++ pmlmeext->sitesurvey_res.bss_cnt = 0; ++ pmlmeext->scan_abort = _FALSE; ++ ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ pmlmeinfo->reauth_count = 0; ++ pmlmeinfo->reassoc_count = 0; ++ pmlmeinfo->link_count = 0; ++ pmlmeinfo->auth_seq = 0; ++ pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; ++ pmlmeinfo->key_index = 0; ++ pmlmeinfo->iv = 0; ++ ++ pmlmeinfo->enc_algo = _NO_PRIVACY_; ++ pmlmeinfo->authModeToggle = 0; ++ ++ _rtw_memset(pmlmeinfo->chg_txt, 0, 128); ++ ++ pmlmeinfo->slotTime = SHORT_SLOT_TIME; ++ pmlmeinfo->preamble_mode = PREAMBLE_AUTO; ++ ++ pmlmeinfo->dialogToken = 0; ++ ++ pmlmeext->action_public_rxseq = 0xffff; ++ pmlmeext->action_public_dialog_token = 0xff; ++} ++ ++static int has_channel(RT_CHANNEL_INFO *channel_set, ++ u8 chanset_size, ++ u8 chan) { ++ int i; ++ ++ for (i = 0; i < chanset_size; i++) { ++ if (channel_set[i].ChannelNum == chan) { ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++static void init_channel_list(_adapter *padapter, RT_CHANNEL_INFO *channel_set, ++ u8 chanset_size, ++ struct p2p_channels *channel_list) { ++ ++ struct p2p_oper_class_map op_class[] = { ++ { IEEE80211G, 81, 1, 13, 1, BW20 }, ++ { IEEE80211G, 82, 14, 14, 1, BW20 }, ++#if 0 /* Do not enable HT40 on 2 GHz */ ++ { IEEE80211G, 83, 1, 9, 1, BW40PLUS }, ++ { IEEE80211G, 84, 5, 13, 1, BW40MINUS }, ++#endif ++ { IEEE80211A, 115, 36, 48, 4, BW20 }, ++ { IEEE80211A, 116, 36, 44, 8, BW40PLUS }, ++ { IEEE80211A, 117, 40, 48, 8, BW40MINUS }, ++ { IEEE80211A, 124, 149, 161, 4, BW20 }, ++ { IEEE80211A, 125, 149, 169, 4, BW20 }, ++ { IEEE80211A, 126, 149, 157, 8, BW40PLUS }, ++ { IEEE80211A, 127, 153, 161, 8, BW40MINUS }, ++ { -1, 0, 0, 0, 0, BW20 } ++ }; ++ ++ int cla, op; ++ ++ cla = 0; ++ ++ for (op = 0; op_class[op].op_class; op++) { ++ u8 ch; ++ struct p2p_oper_class_map *o = &op_class[op]; ++ struct p2p_reg_class *reg = NULL; ++ ++ for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { ++ if (!has_channel(channel_set, chanset_size, ch)) { ++ continue; ++ } ++ ++ if ((0 == padapter->registrypriv.ht_enable) && (8 == o->inc)) ++ continue; ++ ++ if ((0 == (padapter->registrypriv.cbw40_enable & BIT(1))) && ++ ((BW40MINUS == o->bw) || (BW40PLUS == o->bw))) ++ continue; ++ ++ if (reg == NULL) { ++ reg = &channel_list->reg_class[cla]; ++ cla++; ++ reg->reg_class = o->op_class; ++ reg->channels = 0; ++ } ++ reg->channel[reg->channels] = ch; ++ reg->channels++; ++ } ++ } ++ channel_list->reg_classes = cla; ++ ++} ++ ++static u8 init_channel_set(_adapter* padapter, u8 ChannelPlan, RT_CHANNEL_INFO *channel_set) ++{ ++ u8 index,chanset_size = 0; ++ u8 b5GBand = _FALSE, b2_4GBand = _FALSE; ++ u8 Index2G = 0, Index5G=0; ++ ++ _rtw_memset(channel_set, 0, sizeof(RT_CHANNEL_INFO)*MAX_CHANNEL_NUM); ++ ++ if(ChannelPlan >= RT_CHANNEL_DOMAIN_MAX && ChannelPlan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) ++ { ++ DBG_871X("ChannelPlan ID %x error !!!!!\n",ChannelPlan); ++ return chanset_size; ++ } ++ ++ if(padapter->registrypriv.wireless_mode & WIRELESS_11G) ++ { ++ b2_4GBand = _TRUE; ++ if(RT_CHANNEL_DOMAIN_REALTEK_DEFINE == ChannelPlan) ++ Index2G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index2G; ++ else ++ Index2G = RTW_ChannelPlanMap[ChannelPlan].Index2G; ++ } ++ ++ if(padapter->registrypriv.wireless_mode & WIRELESS_11A) ++ { ++ b5GBand = _TRUE; ++ if(RT_CHANNEL_DOMAIN_REALTEK_DEFINE == ChannelPlan) ++ Index5G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index5G; ++ else ++ Index5G = RTW_ChannelPlanMap[ChannelPlan].Index5G; ++ } ++ ++ if(b2_4GBand) ++ { ++ for(index=0;index= 1 && channel_set[chanset_size].ChannelNum <= 11) ++ channel_set[chanset_size].ScanType = SCAN_ACTIVE; ++ else if((channel_set[chanset_size].ChannelNum >= 12 && channel_set[chanset_size].ChannelNum <= 14)) ++ channel_set[chanset_size].ScanType = SCAN_PASSIVE; ++ } ++ else if(RT_CHANNEL_DOMAIN_WORLD_WIDE_13 == ChannelPlan || ++ RT_CHANNEL_DOMAIN_WORLD_WIDE_5G == ChannelPlan || ++ RT_CHANNEL_DOMAIN_2G_WORLD == Index2G)// channel 12~13, passive scan ++ { ++ if(channel_set[chanset_size].ChannelNum <= 11) ++ channel_set[chanset_size].ScanType = SCAN_ACTIVE; ++ else ++ channel_set[chanset_size].ScanType = SCAN_PASSIVE; ++ } ++ else ++ { ++ channel_set[chanset_size].ScanType = SCAN_ACTIVE; ++ } ++ ++ chanset_size++; ++ } ++ } ++ ++ if(b5GBand) ++ { ++ for(index=0;index= 149 ) ++ { ++ if(RT_CHANNEL_DOMAIN_WORLD_WIDE_5G == ChannelPlan)//passive scan for all 5G channels ++ channel_set[chanset_size].ScanType = SCAN_PASSIVE; ++ else ++ channel_set[chanset_size].ScanType = SCAN_ACTIVE; ++ } ++ else ++ { ++ channel_set[chanset_size].ScanType = SCAN_PASSIVE; ++ } ++ chanset_size++; ++#else /* CONFIG_DFS */ ++ if ( RTW_ChannelPlan5G[Index5G].Channel[index] <= 48 ++ || RTW_ChannelPlan5G[Index5G].Channel[index] >= 149 ) { ++ channel_set[chanset_size].ChannelNum = RTW_ChannelPlan5G[Index5G].Channel[index]; ++ if(RT_CHANNEL_DOMAIN_WORLD_WIDE_5G == ChannelPlan)//passive scan for all 5G channels ++ channel_set[chanset_size].ScanType = SCAN_PASSIVE; ++ else ++ channel_set[chanset_size].ScanType = SCAN_ACTIVE; ++ DBG_871X("%s(): channel_set[%d].ChannelNum = %d\n", __FUNCTION__, chanset_size, channel_set[chanset_size].ChannelNum); ++ chanset_size++; ++ } ++#endif /* CONFIG_DFS */ ++ } ++ } ++ ++ return chanset_size; ++} ++ ++int init_mlme_ext_priv(_adapter* padapter) ++{ ++ int res = _SUCCESS; ++ struct registry_priv* pregistrypriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ // We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). ++ //_rtw_memset((u8 *)pmlmeext, 0, sizeof(struct mlme_ext_priv)); ++ ++ pmlmeext->padapter = padapter; ++ ++ //fill_fwpriv(padapter, &(pmlmeext->fwpriv)); ++ ++ init_mlme_ext_priv_value(padapter); ++ pmlmeinfo->bAcceptAddbaReq = pregistrypriv->bAcceptAddbaReq; ++ ++ init_mlme_ext_timer(padapter); ++ ++#ifdef CONFIG_AP_MODE ++ init_mlme_ap_info(padapter); ++#endif ++ ++ pmlmeext->max_chan_nums = init_channel_set(padapter, pmlmepriv->ChannelPlan,pmlmeext->channel_set); ++ init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list); ++ ++ pmlmeext->chan_scan_time = SURVEY_TO; ++ pmlmeext->mlmeext_init = _TRUE; ++ ++ ++#ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK ++ pmlmeext->active_keep_alive_check = _TRUE; ++#endif ++ ++#ifdef DBG_FIXED_CHAN ++ pmlmeext->fixed_chan = 0xFF; ++#endif ++ ++ return res; ++ ++} ++ ++void free_mlme_ext_priv (struct mlme_ext_priv *pmlmeext) ++{ ++ _adapter *padapter = pmlmeext->padapter; ++ ++ if (!padapter) ++ return; ++ ++ if (padapter->bDriverStopped == _TRUE) ++ { ++ _cancel_timer_ex(&pmlmeext->survey_timer); ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ //_cancel_timer_ex(&pmlmeext->ADDBA_timer); ++ } ++} ++ ++static u8 cmp_pkt_chnl_diff(_adapter *padapter,u8* pframe,uint packet_len) ++{ // if the channel is same, return 0. else return channel differential ++ uint len; ++ u8 channel; ++ u8 *p; ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_, _DSSET_IE_, &len, packet_len - _BEACON_IE_OFFSET_); ++ if (p) ++ { ++ channel = *(p + 2); ++ if(padapter->mlmeextpriv.cur_channel >= channel) ++ { ++ return (padapter->mlmeextpriv.cur_channel - channel); ++ } ++ else ++ { ++ return (channel-padapter->mlmeextpriv.cur_channel); ++ } ++ } ++ else ++ { ++ return 0; ++ } ++} ++ ++static void _mgt_dispatcher(_adapter *padapter, struct mlme_handler *ptable, union recv_frame *precv_frame) ++{ ++ u8 bc_addr[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ ++ if(ptable->func) ++ { ++ //receive the frames that ra(a1) is my address or ra(a1) is bc address. ++ if (!_rtw_memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) && ++ !_rtw_memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN)) ++ { ++ return; ++ } ++ ++ ptable->func(padapter, precv_frame); ++ } ++ ++} ++ ++void mgt_dispatcher(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ int index; ++ struct mlme_handler *ptable; ++#ifdef CONFIG_AP_MODE ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++#endif //CONFIG_AP_MODE ++ u8 bc_addr[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(pframe)); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ++ ("+mgt_dispatcher: type(0x%x) subtype(0x%x)\n", ++ GetFrameType(pframe), GetFrameSubType(pframe))); ++ ++#if 0 ++ { ++ u8 *pbuf; ++ pbuf = GetAddr1Ptr(pframe); ++ DBG_871X("A1-%x:%x:%x:%x:%x:%x\n", *pbuf, *(pbuf+1), *(pbuf+2), *(pbuf+3), *(pbuf+4), *(pbuf+5)); ++ pbuf = GetAddr2Ptr(pframe); ++ DBG_871X("A2-%x:%x:%x:%x:%x:%x\n", *pbuf, *(pbuf+1), *(pbuf+2), *(pbuf+3), *(pbuf+4), *(pbuf+5)); ++ pbuf = GetAddr3Ptr(pframe); ++ DBG_871X("A3-%x:%x:%x:%x:%x:%x\n", *pbuf, *(pbuf+1), *(pbuf+2), *(pbuf+3), *(pbuf+4), *(pbuf+5)); ++ } ++#endif ++ ++ if (GetFrameType(pframe) != WIFI_MGT_TYPE) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("mgt_dispatcher: type(0x%x) error!\n", GetFrameType(pframe))); ++ return; ++ } ++ ++ //receive the frames that ra(a1) is my address or ra(a1) is bc address. ++ if (!_rtw_memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) && ++ !_rtw_memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN)) ++ { ++ return; ++ } ++ ++ ptable = mlme_sta_tbl; ++ ++ index = GetFrameSubType(pframe) >> 4; ++ ++#ifdef CONFIG_TDLS ++ if((index << 4)==WIFI_ACTION){ ++ //category==public (4), action==TDLS_DISCOVERY_RESPONSE ++ if(*(pframe+24)==0x04 && *(pframe+25)==TDLS_DISCOVERY_RESPONSE){ ++ DBG_871X("recv tdls discovery response frame\n"); ++ On_TDLS_Dis_Rsp(padapter, precv_frame); ++ } ++ } ++#endif //CONFIG_TDLS ++ ++ if (index > 13) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Currently we do not support reserved sub-fr-type=%d\n", index)); ++ return; ++ } ++ ptable += index; ++ ++#if 1 ++ if (psta != NULL) ++ { ++ if (GetRetry(pframe)) ++ { ++ if (precv_frame->u.hdr.attrib.seq_num == psta->RxMgmtFrameSeqNum) ++ { ++ /* drop the duplicate management frame */ ++ DBG_871X("Drop duplicate management frame with seq_num = %d.\n", precv_frame->u.hdr.attrib.seq_num); ++ return; ++ } ++ } ++ psta->RxMgmtFrameSeqNum = precv_frame->u.hdr.attrib.seq_num; ++ } ++#else ++ ++ if(GetRetry(pframe)) ++ { ++ //RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("drop due to decache!\n")); ++ //return; ++ } ++#endif ++ ++#ifdef CONFIG_AP_MODE ++ switch (GetFrameSubType(pframe)) ++ { ++ case WIFI_AUTH: ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ ptable->func = &OnAuth; ++ else ++ ptable->func = &OnAuthClient; ++ //pass through ++ case WIFI_ASSOCREQ: ++ case WIFI_REASSOCREQ: ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++#ifdef CONFIG_HOSTAPD_MLME ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ rtw_hostapd_mlme_rx(padapter, precv_frame); ++#endif ++ break; ++ case WIFI_PROBEREQ: ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ { ++#ifdef CONFIG_HOSTAPD_MLME ++ rtw_hostapd_mlme_rx(padapter, precv_frame); ++#else ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++#endif ++ } ++ else ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++ break; ++ case WIFI_BEACON: ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++ break; ++ case WIFI_ACTION: ++ //if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++ break; ++ default: ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ rtw_hostapd_mlme_rx(padapter, precv_frame); ++ break; ++ } ++#else ++ ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++ ++#endif ++ ++} ++ ++#ifdef CONFIG_P2P ++u32 p2p_listen_state_process(_adapter *padapter, unsigned char *da) ++{ ++ bool response = _TRUE; ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 ) ++ { ++ if(padapter->cfg80211_wdinfo.is_ro_ch == _FALSE ++ || rtw_get_oper_ch(padapter) != padapter->wdinfo.listen_channel ++ || wdev_to_priv(padapter->rtw_wdev)->p2p_enabled == _FALSE ++ || padapter->mlmepriv.wps_probe_resp_ie == NULL ++ || padapter->mlmepriv.p2p_probe_resp_ie == NULL ++ ) ++ { ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X("DON'T issue_probersp_p2p: p2p_enabled:%d, wps_probe_resp_ie:%p, p2p_probe_resp_ie:%p, ", ++ wdev_to_priv(padapter->rtw_wdev)->p2p_enabled, ++ padapter->mlmepriv.wps_probe_resp_ie, ++ padapter->mlmepriv.p2p_probe_resp_ie); ++ DBG_871X("is_ro_ch:%d, op_ch:%d, p2p_listen_channel:%d\n", ++ padapter->cfg80211_wdinfo.is_ro_ch, ++ rtw_get_oper_ch(padapter), ++ padapter->wdinfo.listen_channel); ++#endif ++ response = _FALSE; ++ } ++ } ++ else ++#endif //CONFIG_IOCTL_CFG80211 ++ if( padapter->wdinfo.driver_interface == DRIVER_WEXT ) ++ { ++ // do nothing if the device name is empty ++ if ( !padapter->wdinfo.device_name_len ) ++ { ++ response = _FALSE; ++ } ++ } ++ ++ if (response == _TRUE) ++ issue_probersp_p2p( padapter, da); ++ ++ return _SUCCESS; ++} ++#endif //CONFIG_P2P ++ ++ ++/**************************************************************************** ++ ++Following are the callback functions for each subtype of the management frames ++ ++*****************************************************************************/ ++ ++unsigned int OnProbeReq(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ unsigned int ielen; ++ unsigned char *p; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *cur = &(pmlmeinfo->network); ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint len = precv_frame->u.hdr.len; ++ u8 is_valid_p2p_probereq = _FALSE; ++ ++#ifdef CONFIG_ATMEL_RC_PATCH ++ u8 *target_ie=NULL, *wps_ie=NULL; ++ u8 *start; ++ uint search_len = 0, wps_ielen = 0, target_ielen = 0; ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++#endif ++ ++ ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); ++ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; ++ u8 wifi_test_chk_rate = 1; ++ ++ if ( !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && ++ !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE) && ++ !rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) && ++ !rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH) && ++ !rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) ++ ) ++ { ++ // Commented by Albert 2011/03/17 ++ // mcs_rate = 0 -> CCK 1M rate ++ // mcs_rate = 1 -> CCK 2M rate ++ // mcs_rate = 2 -> CCK 5.5M rate ++ // mcs_rate = 3 -> CCK 11M rate ++ // In the P2P mode, the driver should not support the CCK rate ++ ++ // Commented by Kurt 2012/10/16 ++ // IOT issue: Google Nexus7 use 1M rate to send p2p_probe_req after GO nego completed and Nexus7 is client ++#ifdef CONFIG_WIFI_TEST ++ if ( pattrib->mcs_rate <= 3 ) ++ { ++ wifi_test_chk_rate = 0; ++ } ++#endif //CONFIG_WIFI_TEST ++ ++ if( wifi_test_chk_rate == 1 ) ++ { ++ if((is_valid_p2p_probereq = process_probe_req_p2p_ie(pwdinfo, pframe, len)) == _TRUE) ++ { ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) ++ { ++#ifndef CONFIG_IOCTL_CFG80211 ++// FIXME ++ report_survey_event(padapter, precv_frame); ++#endif ++ p2p_listen_state_process( padapter, get_sa(pframe)); ++ ++ return _SUCCESS; ++ } ++ ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ { ++ goto _continue; ++ } ++ } ++ } ++ } ++ ++_continue: ++#endif //CONFIG_P2P ++ ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE)) ++ { ++ return _SUCCESS; ++ } ++ ++ if(check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE && ++ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE)==_FALSE) ++ { ++ return _SUCCESS; ++ } ++ ++ ++ //DBG_871X("+OnProbeReq\n"); ++ ++ ++#ifdef CONFIG_ATMEL_RC_PATCH ++ if ((wps_ie = rtw_get_wps_ie( ++ pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, ++ len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_, ++ NULL, &wps_ielen))) { ++ ++ target_ie = rtw_get_wps_attr_content( wps_ie, wps_ielen, WPS_ATTR_MANUFACTURER, NULL, &target_ielen); ++ } ++ if ((target_ie && (target_ielen == 4)) && (_TRUE ==_rtw_memcmp((void *)target_ie, "Ozmo",4 ))) { ++ //psta->flag_atmel_rc = 1; ++ unsigned char *sa_addr = get_sa(pframe); ++ DBG_871X("%s: Find Ozmo RC -- %02x:%02x:%02x:%02x:%02x:%02x \n\n", ++ __func__, *sa_addr, *(sa_addr+1), *(sa_addr+2), *(sa_addr+3), *(sa_addr+4), *(sa_addr+5)); ++ _rtw_memcpy( pstapriv->atmel_rc_pattern, get_sa(pframe), ETH_ALEN); ++ } ++#endif ++#ifdef CONFIG_CONCURRENT_MODE ++ if(((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) && ++ check_buddy_fwstate(padapter, _FW_UNDER_LINKING|_FW_UNDER_SURVEY)) ++ { ++ //don't process probe req ++ return _SUCCESS; ++ } ++#endif ++ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ielen, ++ len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); ++ ++ ++ //check (wildcard) SSID ++ if (p != NULL) ++ { ++ if(is_valid_p2p_probereq == _TRUE) ++ { ++ goto _issue_probersp; ++ } ++ ++ if ( (ielen != 0 && _FALSE ==_rtw_memcmp((void *)(p+2), (void *)cur->Ssid.Ssid, cur->Ssid.SsidLength)) ++ || (ielen == 0 && pmlmeinfo->hidden_ssid_mode) ++ ) ++ { ++ return _SUCCESS; ++ } ++ ++_issue_probersp: ++ ++ if(((check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE && ++ pmlmepriv->cur_network.join_res == _TRUE)) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ++ { ++ //DBG_871X("+issue_probersp during ap mode\n"); ++ issue_probersp(padapter, get_sa(pframe), is_valid_p2p_probereq); ++ } ++ ++ } ++ ++ return _SUCCESS; ++ ++} ++ ++unsigned int OnProbeRsp(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ struct sta_info *psta; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++#endif ++ ++ ++#ifdef CONFIG_P2P ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) ++ { ++ if ( _TRUE == pwdinfo->tx_prov_disc_info.benable ) ++ { ++ if( _rtw_memcmp( pwdinfo->tx_prov_disc_info.peerIFAddr, GetAddr2Ptr(pframe), ETH_ALEN ) ) ++ { ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) ++ { ++ pwdinfo->tx_prov_disc_info.benable = _FALSE; ++ issue_p2p_provision_request( padapter, ++ pwdinfo->tx_prov_disc_info.ssid.Ssid, ++ pwdinfo->tx_prov_disc_info.ssid.SsidLength, ++ pwdinfo->tx_prov_disc_info.peerDevAddr ); ++ } ++ else if ( rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) ) ++ { ++ pwdinfo->tx_prov_disc_info.benable = _FALSE; ++ issue_p2p_provision_request( padapter, ++ NULL, ++ 0, ++ pwdinfo->tx_prov_disc_info.peerDevAddr ); ++ } ++ } ++ } ++ return _SUCCESS; ++ } ++ else if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) ++ { ++ if ( _TRUE == pwdinfo->nego_req_info.benable ) ++ { ++ DBG_871X( "[%s] P2P State is GONEGO ING!\n", __FUNCTION__ ); ++ if( _rtw_memcmp( pwdinfo->nego_req_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN ) ) ++ { ++ pwdinfo->nego_req_info.benable = _FALSE; ++ issue_p2p_GO_request( padapter, pwdinfo->nego_req_info.peerDevAddr); ++ } ++ } ++ } ++ else if( rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ ) ) ++ { ++ if ( _TRUE == pwdinfo->invitereq_info.benable ) ++ { ++ DBG_871X( "[%s] P2P_STATE_TX_INVITE_REQ!\n", __FUNCTION__ ); ++ if( _rtw_memcmp( pwdinfo->invitereq_info.peer_macaddr, GetAddr2Ptr(pframe), ETH_ALEN ) ) ++ { ++ pwdinfo->invitereq_info.benable = _FALSE; ++ issue_p2p_invitation_request( padapter, pwdinfo->invitereq_info.peer_macaddr ); ++ } ++ } ++ } ++#endif //CONFIG_P2P ++ ++ ++ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) ++ { ++ report_survey_event(padapter, precv_frame); ++#ifdef CONFIG_CONCURRENT_MODE ++ report_survey_event(padapter->pbuddy_adapter, precv_frame); ++#endif //CONFIG_CONCURRENT_MODE ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ dc_report_survey_event(padapter, precv_frame); ++#endif //CONFIG_DUALMAC_CONCURRENT ++ return _SUCCESS; ++ } ++ ++ #if 0 //move to validate_recv_mgnt_frame ++ if (_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) ++ { ++ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) ++ { ++ if ((psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe))) != NULL) ++ { ++ psta->sta_stats.rx_mgnt_pkts++; ++ } ++ } ++ } ++ #endif ++ ++ return _SUCCESS; ++ ++} ++ ++unsigned int OnBeacon(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ int cam_idx; ++ struct sta_info *psta; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint len = precv_frame->u.hdr.len; ++ WLAN_BSSID_EX *pbss; ++ int ret = _SUCCESS; ++ u8 *p = NULL; ++ u32 ielen = 0; ++ ++#ifdef CONFIG_ATTEMPT_TO_FIX_AP_BEACON_ERROR ++ p = rtw_get_ie(pframe + sizeof(struct rtw_ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ielen, precv_frame->u.hdr.len -sizeof(struct rtw_ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_); ++ if ((p != NULL) && (ielen > 0)) ++ { ++ if ((*(p + 1 + ielen) == 0x2D) && (*(p + 2 + ielen) != 0x2D)) ++ { ++ /* Invalid value 0x2D is detected in Extended Supported Rates (ESR) IE. Try to fix the IE length to avoid failed Beacon parsing. */ ++ DBG_871X("[WIFIDBG] Error in ESR IE is detected in Beacon of BSSID:"MAC_FMT". Fix the length of ESR IE to avoid failed Beacon parsing.\n", MAC_ARG(GetAddr3Ptr(pframe))); ++ *(p + 1) = ielen - 1; ++ } ++ } ++#endif ++ ++ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) ++ { ++ report_survey_event(padapter, precv_frame); ++#ifdef CONFIG_CONCURRENT_MODE ++ report_survey_event(padapter->pbuddy_adapter, precv_frame); ++#endif ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ dc_report_survey_event(padapter, precv_frame); ++#endif ++ ++ return _SUCCESS; ++ } ++ ++ if (_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) ++ { ++ if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) ++ { ++ //we should update current network before auth, or some IE is wrong ++ pbss = (WLAN_BSSID_EX*)rtw_malloc(sizeof(WLAN_BSSID_EX)); ++ if (pbss) { ++ if (collect_bss_info(padapter, precv_frame, pbss) == _SUCCESS) { ++ update_network(&(pmlmepriv->cur_network.network), pbss, padapter, _TRUE); ++ rtw_get_bcn_info(&(pmlmepriv->cur_network)); ++ } ++ rtw_mfree((u8*)pbss, sizeof(WLAN_BSSID_EX)); ++ } ++ ++ //check the vendor of the assoc AP ++ pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pframe+sizeof(struct rtw_ieee80211_hdr_3addr), len-sizeof(struct rtw_ieee80211_hdr_3addr)); ++ ++ //update TSF Value ++ update_TSF(pmlmeext, pframe, len); ++ ++ //start auth ++ start_clnt_auth(padapter); ++ ++ return _SUCCESS; ++ } ++ ++ if(((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) && (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) ++ { ++ if ((psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe))) != NULL) ++ { ++ #ifdef CONFIG_PATCH_JOIN_WRONG_CHANNEL ++ //Merge from 8712 FW code ++ if (cmp_pkt_chnl_diff(padapter,pframe,len) != 0) ++ { // join wrong channel, deauth and reconnect ++ issue_deauth(padapter, (&(pmlmeinfo->network))->MacAddress, WLAN_REASON_DEAUTH_LEAVING); ++ ++ report_del_sta_event(padapter,(&(pmlmeinfo->network))->MacAddress, WLAN_REASON_JOIN_WRONG_CHANNEL); ++ pmlmeinfo->state &= (~WIFI_FW_ASSOC_SUCCESS); ++ return _SUCCESS; ++ } ++ #endif //CONFIG_PATCH_JOIN_WRONG_CHANNEL ++ ++ ret = rtw_check_bcn_info(padapter, pframe, len); ++ if (!ret) { ++ DBG_871X_LEVEL(_drv_always_, "ap has changed, disconnect now\n "); ++ receive_disconnect(padapter, pmlmeinfo->network.MacAddress , 0); ++ return _SUCCESS; ++ } ++ //update WMM, ERP in the beacon ++ //todo: the timer is used instead of the number of the beacon received ++ if ((sta_rx_pkts(psta) & 0xf) == 0) ++ { ++ //DBG_871X("update_bcn_info\n"); ++ update_beacon_info(padapter, pframe, len, psta); ++ } ++ ++#ifdef CONFIG_DFS ++ process_csa_ie(padapter, pframe, len); //channel switch announcement ++#endif //CONFIG_DFS ++ ++#ifdef CONFIG_P2P_PS ++ process_p2p_ps_ie(padapter, (pframe + WLAN_HDR_A3_LEN), (len - WLAN_HDR_A3_LEN)); ++#endif //CONFIG_P2P_PS ++ ++ #if 0 //move to validate_recv_mgnt_frame ++ psta->sta_stats.rx_mgnt_pkts++; ++ #endif ++ } ++ } ++ else if((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) ++ { ++ if ((psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe))) != NULL) ++ { ++ //update WMM, ERP in the beacon ++ //todo: the timer is used instead of the number of the beacon received ++ if ((sta_rx_pkts(psta) & 0xf) == 0) ++ { ++ //DBG_871X("update_bcn_info\n"); ++ update_beacon_info(padapter, pframe, len, psta); ++ } ++ ++ #if 0 //move to validate_recv_mgnt_frame ++ psta->sta_stats.rx_mgnt_pkts++; ++ #endif ++ } ++ else ++ { ++ //allocate a new CAM entry for IBSS station ++ if ((cam_idx = allocate_fw_sta_entry(padapter)) == NUM_STA) ++ { ++ goto _END_ONBEACON_; ++ } ++ ++ //get supported rate ++ if (update_sta_support_rate(padapter, (pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_), (len - WLAN_HDR_A3_LEN - _BEACON_IE_OFFSET_), cam_idx) == _FAIL) ++ { ++ pmlmeinfo->FW_sta_info[cam_idx].status = 0; ++ goto _END_ONBEACON_; ++ } ++ ++ //update TSF Value ++ update_TSF(pmlmeext, pframe, len); ++ ++ //report sta add event ++ report_add_sta_event(padapter, GetAddr2Ptr(pframe), cam_idx); ++ } ++ } ++ } ++ ++_END_ONBEACON_: ++ ++ return _SUCCESS; ++ ++} ++ ++unsigned int OnAuth(_adapter *padapter, union recv_frame *precv_frame) ++{ ++#ifdef CONFIG_AP_MODE ++ _irqL irqL; ++ unsigned int auth_mode, seq, ie_len; ++ unsigned char *sa, *p; ++ u16 algorithm; ++ int status; ++ static struct sta_info stat; ++ struct sta_info *pstat=NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint len = precv_frame->u.hdr.len; ++ ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) && ++ check_buddy_fwstate(padapter, _FW_UNDER_LINKING|_FW_UNDER_SURVEY)) ++ { ++ //don't process auth request; ++ return _SUCCESS; ++ } ++#endif //CONFIG_CONCURRENT_MODE ++ ++ if((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) ++ return _FAIL; ++ ++ DBG_871X("+OnAuth\n"); ++ ++ sa = GetAddr2Ptr(pframe); ++ ++ auth_mode = psecuritypriv->dot11AuthAlgrthm; ++ seq = cpu_to_le16(*(u16*)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + 2)); ++ algorithm = cpu_to_le16(*(u16*)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN)); ++ ++ if (GetPrivacy(pframe)) ++ { ++#if 0 //TODO: SW rtw_wep_decrypt ++ if (SWCRYPTO) ++ { ++ status = rtw_wep_decrypt(priv, pframe, pfrinfo->pktlen, ++ priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm); ++ if (status == FALSE) ++ { ++ SAVE_INT_AND_CLI(flags); ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,"wep-decrypt a Auth frame error!\n"); ++ status = _STATS_CHALLENGE_FAIL_; ++ goto auth_fail; ++ } ++ } ++ ++ seq = cpu_to_le16(*(unsigned short *)((unsigned int)pframe + WLAN_HDR_A3_LEN + 4 + 2)); ++ algorithm = cpu_to_le16(*(unsigned short *)((unsigned int)pframe + WLAN_HDR_A3_LEN + 4)); ++#endif ++ } ++ ++ ++ DBG_871X("auth alg=%x, seq=%X\n", algorithm, seq); ++ ++ if (auth_mode == 2 && ++ psecuritypriv->dot11PrivacyAlgrthm != _WEP40_ && ++ psecuritypriv->dot11PrivacyAlgrthm != _WEP104_) ++ auth_mode = 0; ++ ++ if ((algorithm > 0 && auth_mode == 0) || // rx a shared-key auth but shared not enabled ++ (algorithm == 0 && auth_mode == 1) ) // rx a open-system auth but shared-key is enabled ++ { ++ DBG_871X("auth rejected due to bad alg [alg=%d, auth_mib=%d] %02X%02X%02X%02X%02X%02X\n", ++ algorithm, auth_mode, sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]); ++ ++ status = _STATS_NO_SUPP_ALG_; ++ ++ goto auth_fail; ++ } ++ ++#if 0 //ACL control ++ phead = &priv->wlan_acl_list; ++ plist = phead->next; ++ //check sa ++ if (acl_mode == 1) // 1: positive check, only those on acl_list can be connected. ++ res = FAIL; ++ else ++ res = SUCCESS; ++ ++ while(plist != phead) ++ { ++ paclnode = list_entry(plist, struct rtw_wlan_acl_node, list); ++ plist = plist->next; ++ if (!memcmp((void *)sa, paclnode->addr, 6)) { ++ if (paclnode->mode & 2) { // deny ++ res = FAIL; ++ break; ++ } ++ else { ++ res = SUCCESS; ++ break; ++ } ++ } ++ } ++ ++ if (res != SUCCESS) { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,"auth abort because ACL!\n"); ++ return FAIL; ++ } ++#else ++ if(rtw_access_ctrl(padapter, sa) == _FALSE) ++ { ++ status = _STATS_UNABLE_HANDLE_STA_; ++ goto auth_fail; ++ } ++#endif ++ ++ pstat = rtw_get_stainfo(pstapriv, sa); ++ if (pstat == NULL) ++ { ++ // allocate a new one ++ DBG_871X("going to alloc stainfo for sa="MAC_FMT"\n", MAC_ARG(sa)); ++ pstat = rtw_alloc_stainfo(pstapriv, sa); ++ if (pstat == NULL) ++ { ++ DBG_871X(" Exceed the upper limit of supported clients...\n"); ++ status = _STATS_UNABLE_HANDLE_STA_; ++ goto auth_fail; ++ } ++ ++ pstat->state = WIFI_FW_AUTH_NULL; ++ pstat->auth_seq = 0; ++ ++ //pstat->flags = 0; ++ //pstat->capability = 0; ++ } ++ else ++ { ++ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ if(rtw_is_list_empty(&pstat->asoc_list)==_FALSE) ++ { ++ rtw_list_delete(&pstat->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ if (pstat->expire_to > 0) ++ { ++ //TODO: STA re_auth within expire_to ++ } ++ } ++ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ if (seq==1) { ++ //TODO: STA re_auth and auth timeout ++ } ++ } ++ ++ _enter_critical_bh(&pstapriv->auth_list_lock, &irqL); ++ if (rtw_is_list_empty(&pstat->auth_list)) ++ { ++ rtw_list_insert_tail(&pstat->auth_list, &pstapriv->auth_list); ++ pstapriv->auth_list_cnt++; ++ } ++ _exit_critical_bh(&pstapriv->auth_list_lock, &irqL); ++ ++ if (pstat->auth_seq == 0) ++ pstat->expire_to = pstapriv->auth_to; ++ ++ if ((pstat->auth_seq + 1) != seq) ++ { ++ DBG_871X("(1)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", ++ seq, pstat->auth_seq+1); ++ status = _STATS_OUT_OF_AUTH_SEQ_; ++ goto auth_fail; ++ } ++ ++ if (algorithm==0 && (auth_mode == 0 || auth_mode == 2)) ++ { ++ if (seq == 1) ++ { ++ pstat->state &= ~WIFI_FW_AUTH_NULL; ++ pstat->state |= WIFI_FW_AUTH_SUCCESS; ++ pstat->expire_to = pstapriv->assoc_to; ++ pstat->authalg = algorithm; ++ } ++ else ++ { ++ DBG_871X("(2)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", ++ seq, pstat->auth_seq+1); ++ status = _STATS_OUT_OF_AUTH_SEQ_; ++ goto auth_fail; ++ } ++ } ++ else // shared system or auto authentication ++ { ++ if (seq == 1) ++ { ++ //prepare for the challenging txt... ++ ++ //get_random_bytes((void *)pstat->chg_txt, 128);//TODO: ++ ++ pstat->state &= ~WIFI_FW_AUTH_NULL; ++ pstat->state |= WIFI_FW_AUTH_STATE; ++ pstat->authalg = algorithm; ++ pstat->auth_seq = 2; ++ } ++ else if (seq == 3) ++ { ++ //checking for challenging txt... ++ DBG_871X("checking for challenging txt...\n"); ++ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + 4 + _AUTH_IE_OFFSET_ , _CHLGETXT_IE_, (int *)&ie_len, ++ len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_ - 4); ++ ++ if((p==NULL) || (ie_len<=0)) ++ { ++ DBG_871X("auth rejected because challenge failure!(1)\n"); ++ status = _STATS_CHALLENGE_FAIL_; ++ goto auth_fail; ++ } ++ ++ if (_rtw_memcmp((void *)(p + 2), pstat->chg_txt, 128)) ++ { ++ pstat->state &= (~WIFI_FW_AUTH_STATE); ++ pstat->state |= WIFI_FW_AUTH_SUCCESS; ++ // challenging txt is correct... ++ pstat->expire_to = pstapriv->assoc_to; ++ } ++ else ++ { ++ DBG_871X("auth rejected because challenge failure!\n"); ++ status = _STATS_CHALLENGE_FAIL_; ++ goto auth_fail; ++ } ++ } ++ else ++ { ++ DBG_871X("(3)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", ++ seq, pstat->auth_seq+1); ++ status = _STATS_OUT_OF_AUTH_SEQ_; ++ goto auth_fail; ++ } ++ } ++ ++ ++ // Now, we are going to issue_auth... ++ pstat->auth_seq = seq + 1; ++ ++#ifdef CONFIG_NATIVEAP_MLME ++ issue_auth(padapter, pstat, (unsigned short)(_STATS_SUCCESSFUL_)); ++#endif ++ ++ if (pstat->state & WIFI_FW_AUTH_SUCCESS) ++ pstat->auth_seq = 0; ++ ++ ++ return _SUCCESS; ++ ++auth_fail: ++ ++ if(pstat) ++ rtw_free_stainfo(padapter , pstat); ++ ++ pstat = &stat; ++ _rtw_memset((char *)pstat, '\0', sizeof(stat)); ++ pstat->auth_seq = 2; ++ _rtw_memcpy(pstat->hwaddr, sa, 6); ++ ++#ifdef CONFIG_NATIVEAP_MLME ++ issue_auth(padapter, pstat, (unsigned short)status); ++#endif ++ ++#endif ++ return _FAIL; ++ ++} ++ ++unsigned int OnAuthClient(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ unsigned int seq, len, status, algthm, offset; ++ unsigned char *p; ++ unsigned int go2asoc = 0; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint pkt_len = precv_frame->u.hdr.len; ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ //check A1 matches or not ++ if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN)) ++ return _SUCCESS; ++ ++ if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE)) ++ return _SUCCESS; ++ ++ offset = (GetPrivacy(pframe))? 4: 0; ++ ++ algthm = le16_to_cpu(*(unsigned short *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset)); ++ seq = le16_to_cpu(*(unsigned short *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 2)); ++ status = le16_to_cpu(*(unsigned short *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 4)); ++ ++ if (status != 0) ++ { ++ DBG_871X("clnt auth fail, status: %d\n", status); ++ if(status == 13)//&& pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) ++ { ++ if(pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ++ pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; ++ else ++ pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; ++ //pmlmeinfo->reauth_count = 0; ++ } ++ ++ set_link_timer(pmlmeext, 1); ++ goto authclnt_fail; ++ } ++ ++ if (seq == 2) ++ { ++ if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ++ { ++ // legendary shared system ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _AUTH_IE_OFFSET_, _CHLGETXT_IE_, (int *)&len, ++ pkt_len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_); ++ ++ if (p == NULL) ++ { ++ //DBG_871X("marc: no challenge text?\n"); ++ goto authclnt_fail; ++ } ++ ++ _rtw_memcpy((void *)(pmlmeinfo->chg_txt), (void *)(p + 2), len); ++ pmlmeinfo->auth_seq = 3; ++ issue_auth(padapter, NULL, 0); ++ set_link_timer(pmlmeext, REAUTH_TO); ++ ++ return _SUCCESS; ++ } ++ else ++ { ++ // open system ++ go2asoc = 1; ++ } ++ } ++ else if (seq == 4) ++ { ++ if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ++ { ++ go2asoc = 1; ++ } ++ else ++ { ++ goto authclnt_fail; ++ } ++ } ++ else ++ { ++ // this is also illegal ++ //DBG_871X("marc: clnt auth failed due to illegal seq=%x\n", seq); ++ goto authclnt_fail; ++ } ++ ++ if (go2asoc) ++ { ++ DBG_871X_LEVEL(_drv_always_, "auth success, start assoc\n"); ++ start_clnt_assoc(padapter); ++ return _SUCCESS; ++ } ++ ++authclnt_fail: ++ ++ //pmlmeinfo->state &= ~(WIFI_FW_AUTH_STATE); ++ ++ return _FAIL; ++ ++} ++ ++unsigned int OnAssocReq(_adapter *padapter, union recv_frame *precv_frame) ++{ ++#ifdef CONFIG_AP_MODE ++ _irqL irqL; ++ u16 capab_info, listen_interval; ++ struct rtw_ieee802_11_elems elems; ++ struct sta_info *pstat; ++ unsigned char reassoc, *p, *pos, *wpa_ie; ++ unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; ++ int i, ie_len, wpa_ie_len, left; ++ unsigned char supportRate[16]; ++ int supportRateNum; ++ unsigned short status = _STATS_SUCCESSFUL_; ++ unsigned short frame_type, ie_offset=0; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *cur = &(pmlmeinfo->network); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint pkt_len = precv_frame->u.hdr.len; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); ++ u8 p2p_status_code = P2P_STATUS_SUCCESS; ++ u8 *p2pie; ++ u32 p2pielen = 0; ++#ifdef CONFIG_WFD ++ u8 wfd_ie[ 128 ] = { 0x00 }; ++ u32 wfd_ielen = 0; ++#endif // CONFIG_WFD ++#endif //CONFIG_P2P ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) && ++ check_buddy_fwstate(padapter, _FW_UNDER_LINKING|_FW_UNDER_SURVEY)) ++ { ++ //don't process assoc request; ++ return _SUCCESS; ++ } ++#endif //CONFIG_CONCURRENT_MODE ++ ++ if((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) ++ return _FAIL; ++ ++ frame_type = GetFrameSubType(pframe); ++ if (frame_type == WIFI_ASSOCREQ) ++ { ++ reassoc = 0; ++ ie_offset = _ASOCREQ_IE_OFFSET_; ++ } ++ else // WIFI_REASSOCREQ ++ { ++ reassoc = 1; ++ ie_offset = _REASOCREQ_IE_OFFSET_; ++ } ++ ++ ++ if (pkt_len < IEEE80211_3ADDR_LEN + ie_offset) { ++ DBG_871X("handle_assoc(reassoc=%d) - too short payload (len=%lu)" ++ "\n", reassoc, (unsigned long)pkt_len); ++ return _FAIL; ++ } ++ ++ pstat = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ if (pstat == (struct sta_info *)NULL) ++ { ++ status = _RSON_CLS2_; ++ goto asoc_class2_error; ++ } ++ ++ capab_info = RTW_GET_LE16(pframe + WLAN_HDR_A3_LEN); ++ //capab_info = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN)); ++ //listen_interval = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN+2)); ++ listen_interval = RTW_GET_LE16(pframe + WLAN_HDR_A3_LEN+2); ++ ++ left = pkt_len - (IEEE80211_3ADDR_LEN + ie_offset); ++ pos = pframe + (IEEE80211_3ADDR_LEN + ie_offset); ++ ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ // check if this stat has been successfully authenticated/assocated ++ if (!((pstat->state) & WIFI_FW_AUTH_SUCCESS)) ++ { ++ if (!((pstat->state) & WIFI_FW_ASSOC_SUCCESS)) ++ { ++ status = _RSON_CLS2_; ++ goto asoc_class2_error; ++ } ++ else ++ { ++ pstat->state &= (~WIFI_FW_ASSOC_SUCCESS); ++ pstat->state |= WIFI_FW_ASSOC_STATE; ++ } ++ } ++ else ++ { ++ pstat->state &= (~WIFI_FW_AUTH_SUCCESS); ++ pstat->state |= WIFI_FW_ASSOC_STATE; ++ } ++ ++ ++#if 0// todo:tkip_countermeasures ++ if (hapd->tkip_countermeasures) { ++ resp = WLAN_REASON_MICHAEL_MIC_FAILURE; ++ goto fail; ++ } ++#endif ++ ++ pstat->capability = capab_info; ++ ++#if 0//todo: ++ //check listen_interval ++ if (listen_interval > hapd->conf->max_listen_interval) { ++ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, ++ HOSTAPD_LEVEL_DEBUG, ++ "Too large Listen Interval (%d)", ++ listen_interval); ++ resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE; ++ goto fail; ++ } ++ ++ pstat->listen_interval = listen_interval; ++#endif ++ ++ //now parse all ieee802_11 ie to point to elems ++ if (rtw_ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed || ++ !elems.ssid) { ++ DBG_871X("STA " MAC_FMT " sent invalid association request\n", ++ MAC_ARG(pstat->hwaddr)); ++ status = _STATS_FAILURE_; ++ goto OnAssocReqFail; ++ } ++ ++ ++ // now we should check all the fields... ++ // checking SSID ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SSID_IE_, &ie_len, ++ pkt_len - WLAN_HDR_A3_LEN - ie_offset); ++ if (p == NULL) ++ { ++ status = _STATS_FAILURE_; ++ } ++ ++ if (ie_len == 0) // broadcast ssid, however it is not allowed in assocreq ++ status = _STATS_FAILURE_; ++ else ++ { ++ // check if ssid match ++ if (!_rtw_memcmp((void *)(p+2), cur->Ssid.Ssid, cur->Ssid.SsidLength)) ++ status = _STATS_FAILURE_; ++ ++ if (ie_len != cur->Ssid.SsidLength) ++ status = _STATS_FAILURE_; ++ } ++ ++ if(_STATS_SUCCESSFUL_ != status) ++ goto OnAssocReqFail; ++ ++ // check if the supported rate is ok ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SUPPORTEDRATES_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset); ++ if (p == NULL) { ++ DBG_871X("Rx a sta assoc-req which supported rate is empty!\n"); ++ // use our own rate set as statoin used ++ //_rtw_memcpy(supportRate, AP_BSSRATE, AP_BSSRATE_LEN); ++ //supportRateNum = AP_BSSRATE_LEN; ++ ++ status = _STATS_FAILURE_; ++ goto OnAssocReqFail; ++ } ++ else { ++ _rtw_memcpy(supportRate, p+2, ie_len); ++ supportRateNum = ie_len; ++ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _EXT_SUPPORTEDRATES_IE_ , &ie_len, ++ pkt_len - WLAN_HDR_A3_LEN - ie_offset); ++ if (p != NULL) { ++ ++ if(supportRateNum<=sizeof(supportRate)) ++ { ++ _rtw_memcpy(supportRate+supportRateNum, p+2, ie_len); ++ supportRateNum += ie_len; ++ } ++ } ++ } ++ ++ //todo: mask supportRate between AP & STA -> move to update raid ++ //get_matched_rate(pmlmeext, supportRate, &supportRateNum, 0); ++ ++ //update station supportRate ++ pstat->bssratelen = supportRateNum; ++ _rtw_memcpy(pstat->bssrateset, supportRate, supportRateNum); ++ UpdateBrateTblForSoftAP(pstat->bssrateset, pstat->bssratelen); ++ ++ //check RSN/WPA/WPS ++ pstat->dot8021xalg = 0; ++ pstat->wpa_psk = 0; ++ pstat->wpa_group_cipher = 0; ++ pstat->wpa2_group_cipher = 0; ++ pstat->wpa_pairwise_cipher = 0; ++ pstat->wpa2_pairwise_cipher = 0; ++ _rtw_memset(pstat->wpa_ie, 0, sizeof(pstat->wpa_ie)); ++ if((psecuritypriv->wpa_psk & BIT(1)) && elems.rsn_ie) { ++ ++ int group_cipher=0, pairwise_cipher=0; ++ ++ wpa_ie = elems.rsn_ie; ++ wpa_ie_len = elems.rsn_ie_len; ++ ++ if(rtw_parse_wpa2_ie(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) ++ { ++ pstat->dot8021xalg = 1;//psk, todo:802.1x ++ pstat->wpa_psk |= BIT(1); ++ ++ pstat->wpa2_group_cipher = group_cipher&psecuritypriv->wpa2_group_cipher; ++ pstat->wpa2_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa2_pairwise_cipher; ++ ++ if(!pstat->wpa2_group_cipher) ++ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; ++ ++ if(!pstat->wpa2_pairwise_cipher) ++ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; ++ } ++ else ++ { ++ status = WLAN_STATUS_INVALID_IE; ++ } ++ ++ } else if ((psecuritypriv->wpa_psk & BIT(0)) && elems.wpa_ie) { ++ ++ int group_cipher=0, pairwise_cipher=0; ++ ++ wpa_ie = elems.wpa_ie; ++ wpa_ie_len = elems.wpa_ie_len; ++ ++ if(rtw_parse_wpa_ie(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) ++ { ++ pstat->dot8021xalg = 1;//psk, todo:802.1x ++ pstat->wpa_psk |= BIT(0); ++ ++ pstat->wpa_group_cipher = group_cipher&psecuritypriv->wpa_group_cipher; ++ pstat->wpa_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa_pairwise_cipher; ++ ++ if(!pstat->wpa_group_cipher) ++ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; ++ ++ if(!pstat->wpa_pairwise_cipher) ++ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; ++ ++ } ++ else ++ { ++ status = WLAN_STATUS_INVALID_IE; ++ } ++ ++ } else { ++ wpa_ie = NULL; ++ wpa_ie_len = 0; ++ } ++ ++ if(_STATS_SUCCESSFUL_ != status) ++ goto OnAssocReqFail; ++ ++ pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); ++ //if (hapd->conf->wps_state && wpa_ie == NULL) { //todo: to check ap if supporting WPS ++ if(wpa_ie == NULL) { ++ if (elems.wps_ie) { ++ DBG_871X("STA included WPS IE in " ++ "(Re)Association Request - assume WPS is " ++ "used\n"); ++ pstat->flags |= WLAN_STA_WPS; ++ //wpabuf_free(sta->wps_ie); ++ //sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4, ++ // elems.wps_ie_len - 4); ++ } else { ++ DBG_871X("STA did not include WPA/RSN IE " ++ "in (Re)Association Request - possible WPS " ++ "use\n"); ++ pstat->flags |= WLAN_STA_MAYBE_WPS; ++ } ++ ++ ++ // AP support WPA/RSN, and sta is going to do WPS, but AP is not ready ++ // that the selected registrar of AP is _FLASE ++ if((psecuritypriv->wpa_psk >0) ++ && (pstat->flags & (WLAN_STA_WPS|WLAN_STA_MAYBE_WPS))) ++ { ++ if(pmlmepriv->wps_beacon_ie) ++ { ++ u8 selected_registrar = 0; ++ ++ rtw_get_wps_attr_content(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len, WPS_ATTR_SELECTED_REGISTRAR , &selected_registrar, NULL); ++ ++ if(!selected_registrar) ++ { ++ DBG_871X("selected_registrar is _FALSE , or AP is not ready to do WPS\n"); ++ ++ status = _STATS_UNABLE_HANDLE_STA_; ++ ++ goto OnAssocReqFail; ++ } ++ } ++ } ++ ++ } ++ else ++ { ++ int copy_len; ++ ++ if(psecuritypriv->wpa_psk == 0) ++ { ++ DBG_871X("STA " MAC_FMT ": WPA/RSN IE in association " ++ "request, but AP don't support WPA/RSN\n", MAC_ARG(pstat->hwaddr)); ++ ++ status = WLAN_STATUS_INVALID_IE; ++ ++ goto OnAssocReqFail; ++ ++ } ++ ++ if (elems.wps_ie) { ++ DBG_871X("STA included WPS IE in " ++ "(Re)Association Request - WPS is " ++ "used\n"); ++ pstat->flags |= WLAN_STA_WPS; ++ copy_len=0; ++ } ++ else ++ { ++ copy_len = ((wpa_ie_len+2) > sizeof(pstat->wpa_ie)) ? (sizeof(pstat->wpa_ie)):(wpa_ie_len+2); ++ } ++ ++ ++ if(copy_len>0) ++ _rtw_memcpy(pstat->wpa_ie, wpa_ie-2, copy_len); ++ ++ } ++ ++ ++ // check if there is WMM IE & support WWM-PS ++ pstat->flags &= ~WLAN_STA_WME; ++ pstat->qos_option = 0; ++ pstat->qos_info = 0; ++ pstat->has_legacy_ac = _TRUE; ++ pstat->uapsd_vo = 0; ++ pstat->uapsd_vi = 0; ++ pstat->uapsd_be = 0; ++ pstat->uapsd_bk = 0; ++ if (pmlmepriv->qospriv.qos_option) ++ { ++ p = pframe + WLAN_HDR_A3_LEN + ie_offset; ie_len = 0; ++ for (;;) ++ { ++ p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset); ++ if (p != NULL) { ++ if (_rtw_memcmp(p+2, WMM_IE, 6)) { ++ ++ pstat->flags |= WLAN_STA_WME; ++ ++ pstat->qos_option = 1; ++ pstat->qos_info = *(p+8); ++ ++ pstat->max_sp_len = (pstat->qos_info>>5)&0x3; ++ ++ if((pstat->qos_info&0xf) !=0xf) ++ pstat->has_legacy_ac = _TRUE; ++ else ++ pstat->has_legacy_ac = _FALSE; ++ ++ if(pstat->qos_info&0xf) ++ { ++ if(pstat->qos_info&BIT(0)) ++ pstat->uapsd_vo = BIT(0)|BIT(1); ++ else ++ pstat->uapsd_vo = 0; ++ ++ if(pstat->qos_info&BIT(1)) ++ pstat->uapsd_vi = BIT(0)|BIT(1); ++ else ++ pstat->uapsd_vi = 0; ++ ++ if(pstat->qos_info&BIT(2)) ++ pstat->uapsd_bk = BIT(0)|BIT(1); ++ else ++ pstat->uapsd_bk = 0; ++ ++ if(pstat->qos_info&BIT(3)) ++ pstat->uapsd_be = BIT(0)|BIT(1); ++ else ++ pstat->uapsd_be = 0; ++ ++ } ++ ++ break; ++ } ++ } ++ else { ++ break; ++ } ++ p = p + ie_len + 2; ++ } ++ } ++ ++ ++#ifdef CONFIG_80211N_HT ++ /* save HT capabilities in the sta object */ ++ _rtw_memset(&pstat->htpriv.ht_cap, 0, sizeof(struct rtw_ieee80211_ht_cap)); ++ if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct rtw_ieee80211_ht_cap)) ++ { ++ pstat->flags |= WLAN_STA_HT; ++ ++ pstat->flags |= WLAN_STA_WME; ++ ++ _rtw_memcpy(&pstat->htpriv.ht_cap, elems.ht_capabilities, sizeof(struct rtw_ieee80211_ht_cap)); ++ ++ } else ++ pstat->flags &= ~WLAN_STA_HT; ++ ++ ++ if((pmlmepriv->htpriv.ht_option == _FALSE) && (pstat->flags&WLAN_STA_HT)) ++ { ++ status = _STATS_FAILURE_; ++ goto OnAssocReqFail; ++ } ++ ++ ++ if ((pstat->flags & WLAN_STA_HT) && ++ ((pstat->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) || ++ (pstat->wpa_pairwise_cipher&WPA_CIPHER_TKIP))) ++ { ++ DBG_871X("HT: " MAC_FMT " tried to " ++ "use TKIP with HT association\n", MAC_ARG(pstat->hwaddr)); ++ ++ //status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; ++ //goto OnAssocReqFail; ++ } ++#endif /* CONFIG_80211N_HT */ ++ ++ // ++ //if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)//? ++ pstat->flags |= WLAN_STA_NONERP; ++ for (i = 0; i < pstat->bssratelen; i++) { ++ if ((pstat->bssrateset[i] & 0x7f) > 22) { ++ pstat->flags &= ~WLAN_STA_NONERP; ++ break; ++ } ++ } ++ ++ if (pstat->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) ++ pstat->flags |= WLAN_STA_SHORT_PREAMBLE; ++ else ++ pstat->flags &= ~WLAN_STA_SHORT_PREAMBLE; ++ ++ ++ ++ if (status != _STATS_SUCCESSFUL_) ++ goto OnAssocReqFail; ++ ++#ifdef CONFIG_P2P ++ pstat->is_p2p_device = _FALSE; ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ { ++ if( (p2pie=rtw_get_p2p_ie(pframe + WLAN_HDR_A3_LEN + ie_offset , pkt_len - WLAN_HDR_A3_LEN - ie_offset , NULL, &p2pielen))) ++ { ++ pstat->is_p2p_device = _TRUE; ++ if((p2p_status_code=(u8)process_assoc_req_p2p_ie(pwdinfo, pframe, pkt_len, pstat))>0) ++ { ++ pstat->p2p_status_code = p2p_status_code; ++ status = _STATS_CAP_FAIL_; ++ goto OnAssocReqFail; ++ } ++ } ++#ifdef CONFIG_WFD ++ if(rtw_get_wfd_ie(pframe + WLAN_HDR_A3_LEN + ie_offset , pkt_len - WLAN_HDR_A3_LEN - ie_offset , wfd_ie, &wfd_ielen )) ++ { ++ u8 attr_content[ 10 ] = { 0x00 }; ++ u32 attr_contentlen = 0; ++ ++ DBG_8192C( "[%s] WFD IE Found!!\n", __FUNCTION__ ); ++ rtw_get_wfd_attr_content( wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); ++ if ( attr_contentlen ) ++ { ++ pwdinfo->wfd_info->peer_rtsp_ctrlport = RTW_GET_BE16( attr_content + 2 ); ++ DBG_8192C( "[%s] Peer PORT NUM = %d\n", __FUNCTION__, pwdinfo->wfd_info->peer_rtsp_ctrlport ); ++ } ++ } ++#endif ++ } ++ pstat->p2p_status_code = p2p_status_code; ++#endif //CONFIG_P2P ++ ++ //TODO: identify_proprietary_vendor_ie(); ++ // Realtek proprietary IE ++ // identify if this is Broadcom sta ++ // identify if this is ralink sta ++ // Customer proprietary IE ++ ++ ++ ++ /* get a unique AID */ ++ if (pstat->aid > 0) { ++ DBG_871X(" old AID %d\n", pstat->aid); ++ } else { ++ for (pstat->aid = 1; pstat->aid <= NUM_STA; pstat->aid++) ++ if (pstapriv->sta_aid[pstat->aid - 1] == NULL) ++ break; ++ ++ //if (pstat->aid > NUM_STA) { ++ if (pstat->aid > pstapriv->max_num_sta) { ++ ++ pstat->aid = 0; ++ ++ DBG_871X(" no room for more AIDs\n"); ++ ++ status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; ++ ++ goto OnAssocReqFail; ++ ++ ++ } else { ++ pstapriv->sta_aid[pstat->aid - 1] = pstat; ++ DBG_871X("allocate new AID = (%d)\n", pstat->aid); ++ } ++ } ++ ++ ++ pstat->state &= (~WIFI_FW_ASSOC_STATE); ++ pstat->state |= WIFI_FW_ASSOC_SUCCESS; ++ ++ _enter_critical_bh(&pstapriv->auth_list_lock, &irqL); ++ if (!rtw_is_list_empty(&pstat->auth_list)) ++ { ++ rtw_list_delete(&pstat->auth_list); ++ pstapriv->auth_list_cnt--; ++ } ++ _exit_critical_bh(&pstapriv->auth_list_lock, &irqL); ++ ++ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ if (rtw_is_list_empty(&pstat->asoc_list)) ++ { ++ pstat->expire_to = pstapriv->expire_to; ++ rtw_list_insert_tail(&pstat->asoc_list, &pstapriv->asoc_list); ++ pstapriv->asoc_list_cnt++; ++ } ++ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ // now the station is qualified to join our BSS... ++ if(pstat && (pstat->state & WIFI_FW_ASSOC_SUCCESS) && (_STATS_SUCCESSFUL_==status)) ++ { ++#ifdef CONFIG_NATIVEAP_MLME ++ //.1 bss_cap_update & sta_info_update ++ bss_cap_update_on_sta_join(padapter, pstat); ++ sta_info_update(padapter, pstat); ++ ++ //.2 issue assoc rsp before notify station join event. ++ if (frame_type == WIFI_ASSOCREQ) ++ issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP); ++ else ++ issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP); ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ _enter_critical_bh(&pstat->lock, &irqL); ++ if(pstat->passoc_req) ++ { ++ rtw_mfree(pstat->passoc_req, pstat->assoc_req_len); ++ pstat->passoc_req = NULL; ++ pstat->assoc_req_len = 0; ++ } ++ ++ pstat->passoc_req = rtw_zmalloc(pkt_len); ++ if(pstat->passoc_req) ++ { ++ _rtw_memcpy(pstat->passoc_req, pframe, pkt_len); ++ pstat->assoc_req_len = pkt_len; ++ } ++ _exit_critical_bh(&pstat->lock, &irqL); ++#endif //CONFIG_IOCTL_CFG80211 ++ ++ //.3-(1) report sta add event ++ report_add_sta_event(padapter, pstat->hwaddr, pstat->aid); ++ ++#endif //CONFIG_NATIVEAP_MLME ++ } ++ ++ return _SUCCESS; ++ ++asoc_class2_error: ++ ++#ifdef CONFIG_NATIVEAP_MLME ++ issue_deauth(padapter, (void *)GetAddr2Ptr(pframe), status); ++#endif ++ ++ return _FAIL; ++ ++OnAssocReqFail: ++ ++ ++#ifdef CONFIG_NATIVEAP_MLME ++ pstat->aid = 0; ++ if (frame_type == WIFI_ASSOCREQ) ++ issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP); ++ else ++ issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP); ++#endif ++ ++ ++#endif /* CONFIG_AP_MODE */ ++ ++ return _FAIL; ++ ++} ++ ++unsigned int OnAssocRsp(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ uint i; ++ int res; ++ unsigned short status; ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ //WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint pkt_len = precv_frame->u.hdr.len; ++ PNDIS_802_11_VARIABLE_IEs pWapiIE = NULL; ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ //check A1 matches or not ++ if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN)) ++ return _SUCCESS; ++ ++ if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE))) ++ return _SUCCESS; ++ ++ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) ++ return _SUCCESS; ++ ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ ++ //status ++ if ((status = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN + 2))) > 0) ++ { ++ DBG_871X("assoc reject, status code: %d\n", status); ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ res = -4; ++ goto report_assoc_result; ++ } ++ ++ //get capabilities ++ pmlmeinfo->capability = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN)); ++ ++ //set slot time ++ pmlmeinfo->slotTime = (pmlmeinfo->capability & BIT(10))? 9: 20; ++ ++ //AID ++ res = pmlmeinfo->aid = (int)(le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN + 4))&0x3fff); ++ ++ //following are moved to join event callback function ++ //to handle HT, WMM, rate adaptive, update MAC reg ++ //for not to handle the synchronous IO in the tasklet ++ for (i = (6 + WLAN_HDR_A3_LEN); i < pkt_len;) ++ { ++ pIE = (PNDIS_802_11_VARIABLE_IEs)(pframe + i); ++ ++ switch (pIE->ElementID) ++ { ++ case _VENDOR_SPECIFIC_IE_: ++ if (_rtw_memcmp(pIE->data, WMM_PARA_OUI, 6)) //WMM ++ { ++ WMM_param_handler(padapter, pIE); ++ } ++#if defined(CONFIG_P2P) && defined(CONFIG_WFD) ++ else if ( _rtw_memcmp(pIE->data, WFD_OUI, 4)) //WFD ++ { ++ DBG_871X( "[%s] Found WFD IE\n", __FUNCTION__ ); ++ WFD_info_handler( padapter, pIE ); ++ } ++#endif ++ break; ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ case _WAPI_IE_: ++ pWapiIE = pIE; ++ break; ++#endif ++ ++ case _HT_CAPABILITY_IE_: //HT caps ++ HT_caps_handler(padapter, pIE); ++ break; ++ ++ case _HT_EXTRA_INFO_IE_: //HT info ++ HT_info_handler(padapter, pIE); ++ break; ++ ++ case _ERPINFO_IE_: ++ ERP_IE_handler(padapter, pIE); ++ ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ rtw_wapi_on_assoc_ok(padapter, pIE); ++#endif ++ ++ pmlmeinfo->state &= (~WIFI_FW_ASSOC_STATE); ++ pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; ++ ++ //Update Basic Rate Table for spec, 2010-12-28 , by thomas ++ UpdateBrateTbl(padapter, pmlmeinfo->network.SupportedRates); ++ ++report_assoc_result: ++ if (res > 0) { ++ rtw_buf_update(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len, pframe, pkt_len); ++ } else { ++ rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len); ++ } ++ ++ report_join_res(padapter, res); ++ ++ return _SUCCESS; ++} ++ ++unsigned int OnDeAuth(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ unsigned short reason; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++#endif //CONFIG_P2P ++ ++ //check A3 ++ if (!(_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN))) ++ return _SUCCESS; ++ ++#ifdef CONFIG_P2P ++ if ( pwdinfo->rx_invitereq_info.scan_op_ch_only ) ++ { ++ _cancel_timer_ex( &pwdinfo->reset_ch_sitesurvey ); ++ _set_timer( &pwdinfo->reset_ch_sitesurvey, 10 ); ++ } ++#endif //CONFIG_P2P ++ ++ reason = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN)); ++ ++ DBG_871X("%s Reason code(%d)\n", __FUNCTION__,reason); ++ ++#ifdef CONFIG_AP_MODE ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ { ++ _irqL irqL; ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ //_enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ //rtw_free_stainfo(padapter, psta); ++ //_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ ++ DBG_871X_LEVEL(_drv_always_, "ap recv deauth reason code(%d) sta:%pM\n", ++ reason, GetAddr2Ptr(pframe)); ++ ++ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ if(psta) ++ { ++ u8 updated; ++ ++ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ if(rtw_is_list_empty(&psta->asoc_list)==_FALSE) ++ { ++ rtw_list_delete(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ updated = ap_free_sta(padapter, psta, _FALSE, reason); ++ ++ } ++ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ associated_clients_update(padapter, updated); ++ } ++ ++ ++ return _SUCCESS; ++ } ++ else ++#endif ++ { ++ int ignore_received_deauth = 0; ++ ++ // Commented by Albert 20130604 ++ // Before sending the auth frame to start the STA/GC mode connection with AP/GO, ++ // we will send the deauth first. ++ // However, the Win8.1 with BRCM Wi-Fi will send the deauth with reason code 6 to us after receieving our deauth. ++ // Added the following code to avoid this case. ++ if ( ( pmlmeinfo->state & WIFI_FW_AUTH_STATE ) || ++ ( pmlmeinfo->state & WIFI_FW_ASSOC_STATE ) ) ++ { ++ if ( reason == WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA ) ++ { ++ ignore_received_deauth = 1; ++ } else if (WLAN_REASON_PREV_AUTH_NOT_VALID == reason) { ++ // TODO: 802.11r ++ ignore_received_deauth = 1; ++ } ++ } ++ ++ DBG_871X_LEVEL(_drv_always_, "sta recv deauth reason code(%d) sta:%pM, ignore = %d\n", ++ reason, GetAddr3Ptr(pframe), ignore_received_deauth); ++ ++ if ( 0 == ignore_received_deauth ) ++ { ++ receive_disconnect(padapter, GetAddr3Ptr(pframe) ,reason); ++ } ++ } ++ pmlmepriv->LinkDetectInfo.bBusyTraffic = _FALSE; ++ return _SUCCESS; ++ ++} ++ ++unsigned int OnDisassoc(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ unsigned short reason; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++#endif //CONFIG_P2P ++ ++ //check A3 ++ if (!(_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN))) ++ return _SUCCESS; ++ ++#ifdef CONFIG_P2P ++ if ( pwdinfo->rx_invitereq_info.scan_op_ch_only ) ++ { ++ _cancel_timer_ex( &pwdinfo->reset_ch_sitesurvey ); ++ _set_timer( &pwdinfo->reset_ch_sitesurvey, 10 ); ++ } ++#endif //CONFIG_P2P ++ ++ reason = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN)); ++ ++ DBG_871X("%s Reason code(%d)\n", __FUNCTION__,reason); ++ ++#ifdef CONFIG_AP_MODE ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ { ++ _irqL irqL; ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ //_enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ //rtw_free_stainfo(padapter, psta); ++ //_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ ++ DBG_871X_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n", ++ reason, GetAddr2Ptr(pframe)); ++ ++ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ if(psta) ++ { ++ u8 updated; ++ ++ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ if(rtw_is_list_empty(&psta->asoc_list)==_FALSE) ++ { ++ rtw_list_delete(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ updated = ap_free_sta(padapter, psta, _FALSE, reason); ++ ++ } ++ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ associated_clients_update(padapter, updated); ++ } ++ ++ return _SUCCESS; ++ } ++ else ++#endif ++ { ++ DBG_871X_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n", ++ reason, GetAddr3Ptr(pframe)); ++ ++ receive_disconnect(padapter, GetAddr3Ptr(pframe), reason); ++ } ++ pmlmepriv->LinkDetectInfo.bBusyTraffic = _FALSE; ++ return _SUCCESS; ++ ++} ++ ++unsigned int OnAtim(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ DBG_871X("%s\n", __FUNCTION__); ++ return _SUCCESS; ++} ++ ++unsigned int on_action_spct_ch_switch(_adapter *padapter, struct sta_info *psta, u8 *ies, uint ies_len) ++{ ++ unsigned int ret = _FAIL; ++ struct mlme_ext_priv *mlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(mlmeext->mlmext_info); ++ ++ if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) { ++ ret = _SUCCESS; ++ goto exit; ++ } ++ ++ if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) { ++ ++ int ch_switch_mode = -1, ch = -1, ch_switch_cnt = -1; ++ int ch_offset = -1; ++ u8 bwmode; ++ struct ieee80211_info_element *ie; ++ ++ DBG_871X(FUNC_NDEV_FMT" from "MAC_FMT"\n", ++ FUNC_NDEV_ARG(padapter->pnetdev), MAC_ARG(psta->hwaddr)); ++ ++ for_each_ie(ie, ies, ies_len) { ++ if (ie->id == WLAN_EID_CHANNEL_SWITCH) { ++ ch_switch_mode = ie->data[0]; ++ ch = ie->data[1]; ++ ch_switch_cnt = ie->data[2]; ++ DBG_871X("ch_switch_mode:%d, ch:%d, ch_switch_cnt:%d\n", ++ ch_switch_mode, ch, ch_switch_cnt); ++ } ++ else if (ie->id == WLAN_EID_SECONDARY_CHANNEL_OFFSET) { ++ ch_offset = secondary_ch_offset_to_hal_ch_offset(ie->data[0]); ++ DBG_871X("ch_offset:%d\n", ch_offset); ++ } ++ } ++ ++ if (ch == -1) ++ return _SUCCESS; ++ ++ if (ch_offset == -1) ++ bwmode = mlmeext->cur_bwmode; ++ else ++ bwmode = (ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) ? ++ HT_CHANNEL_WIDTH_20 : HT_CHANNEL_WIDTH_40; ++ ++ ch_offset = (ch_offset == -1) ? mlmeext->cur_ch_offset : ch_offset; ++ ++ /* todo: ++ * 1. the decision of channel switching ++ * 2. things after channel switching ++ */ ++ ++ ret = rtw_set_ch_cmd(padapter, ch, bwmode, ch_offset, _TRUE); ++ } ++ ++exit: ++ return ret; ++} ++ ++unsigned int on_action_spct(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ unsigned int ret = _FAIL; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint frame_len = precv_frame->u.hdr.len; ++ u8 *frame_body = (u8 *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ u8 category; ++ u8 action; ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev)); ++ ++ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ ++ if (!psta) ++ goto exit; ++ ++ category = frame_body[0]; ++ if(category != RTW_WLAN_CATEGORY_SPECTRUM_MGMT) ++ goto exit; ++ ++ action = frame_body[1]; ++ switch (action) { ++ case RTW_WLAN_ACTION_SPCT_MSR_REQ: ++ case RTW_WLAN_ACTION_SPCT_MSR_RPRT: ++ case RTW_WLAN_ACTION_SPCT_TPC_REQ: ++ case RTW_WLAN_ACTION_SPCT_TPC_RPRT: ++ break; ++ case RTW_WLAN_ACTION_SPCT_CHL_SWITCH: ++ #ifdef CONFIG_SPCT_CH_SWITCH ++ ret = on_action_spct_ch_switch(padapter, psta, &frame_body[2], ++ frame_len-(frame_body-pframe)-2); ++ #endif ++ break; ++ default: ++ break; ++ } ++ ++exit: ++ return ret; ++} ++ ++unsigned int OnAction_qos(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ return _SUCCESS; ++} ++ ++unsigned int OnAction_dls(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ return _SUCCESS; ++} ++ ++unsigned int OnAction_back(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ u8 *addr; ++ struct sta_info *psta=NULL; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ unsigned char *frame_body; ++ unsigned char category, action; ++ unsigned short tid, status, reason_code = 0; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++#ifdef CONFIG_80211N_HT ++ //check RA matches or not ++ if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))//for if1, sta/ap mode ++ return _SUCCESS; ++ ++/* ++ //check A1 matches or not ++ if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN)) ++ return _SUCCESS; ++*/ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ if((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) ++ if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) ++ return _SUCCESS; ++ ++ addr = GetAddr2Ptr(pframe); ++ psta = rtw_get_stainfo(pstapriv, addr); ++ ++ if(psta==NULL) ++ return _SUCCESS; ++ ++ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ ++ category = frame_body[0]; ++ if (category == RTW_WLAN_CATEGORY_BACK)// representing Block Ack ++ { ++#ifdef CONFIG_TDLS ++ if((psta->tdls_sta_state & TDLS_LINKED_STATE) && ++ (psta->htpriv.ht_option==_TRUE) && ++ (psta->htpriv.ampdu_enable==_TRUE) ) ++ { ++ //do nothing; just don't want to return _SUCCESS; ++ } ++ else ++#endif //CONFIG_TDLS ++ if (!pmlmeinfo->HT_enable) ++ { ++ return _SUCCESS; ++ } ++ ++ action = frame_body[1]; ++ DBG_871X("%s, action=%d\n", __FUNCTION__, action); ++ switch (action) ++ { ++ case RTW_WLAN_ACTION_ADDBA_REQ: //ADDBA request ++ ++ _rtw_memcpy(&(pmlmeinfo->ADDBA_req), &(frame_body[2]), sizeof(struct ADDBA_request)); ++ //process_addba_req(padapter, (u8*)&(pmlmeinfo->ADDBA_req), GetAddr3Ptr(pframe)); ++ process_addba_req(padapter, (u8*)&(pmlmeinfo->ADDBA_req), addr); ++ ++ if(pmlmeinfo->bAcceptAddbaReq == _TRUE) ++ { ++ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 0); ++ } ++ else ++ { ++ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 37);//reject ADDBA Req ++ } ++ ++ break; ++ ++ case RTW_WLAN_ACTION_ADDBA_RESP: //ADDBA response ++ ++ //status = frame_body[3] | (frame_body[4] << 8); //endian issue ++ status = RTW_GET_LE16(&frame_body[3]); ++ tid = ((frame_body[5] >> 2) & 0x7); ++ ++ if (status == 0) ++ { //successful ++ DBG_871X("agg_enable for TID=%d\n", tid); ++ psta->htpriv.agg_enable_bitmap |= 1 << tid; ++ psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); ++ } ++ else ++ { ++ psta->htpriv.agg_enable_bitmap &= ~BIT(tid); ++ } ++ ++ //DBG_871X("marc: ADDBA RSP: %x\n", pmlmeinfo->agg_enable_bitmap); ++ break; ++ ++ case RTW_WLAN_ACTION_DELBA: //DELBA ++ if ((frame_body[3] & BIT(3)) == 0) ++ { ++ psta->htpriv.agg_enable_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf)); ++ psta->htpriv.candidate_tid_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf)); ++ ++ //reason_code = frame_body[4] | (frame_body[5] << 8); ++ reason_code = RTW_GET_LE16(&frame_body[4]); ++ } ++ else if((frame_body[3] & BIT(3)) == BIT(3)) ++ { ++ tid = (frame_body[3] >> 4) & 0x0F; ++ ++ preorder_ctrl = &psta->recvreorder_ctrl[tid]; ++ preorder_ctrl->enable = _FALSE; ++ preorder_ctrl->indicate_seq = 0xffff; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d indicate_seq:%u \n", __FUNCTION__, __LINE__, ++ preorder_ctrl->indicate_seq); ++ #endif ++ } ++ ++ DBG_871X("%s(): DELBA: %x(%x)\n", __FUNCTION__,pmlmeinfo->agg_enable_bitmap, reason_code); ++ //todo: how to notify the host while receiving DELETE BA ++ break; ++ ++ default: ++ break; ++ } ++ } ++#endif //CONFIG_80211N_HT ++ return _SUCCESS; ++} ++ ++#ifdef CONFIG_P2P ++ ++static int get_reg_classes_full_count(struct p2p_channels channel_list) { ++ int cnt = 0; ++ int i; ++ ++ for (i = 0; i < channel_list.reg_classes; i++) { ++ cnt += channel_list.reg_class[i].channels; ++ } ++ ++ return cnt; ++} ++ ++static void get_channel_cnt_24g_5gl_5gh( struct mlme_ext_priv *pmlmeext, u8* p24g_cnt, u8* p5gl_cnt, u8* p5gh_cnt ) ++{ ++ int i = 0; ++ ++ *p24g_cnt = 0; ++ *p5gl_cnt = 0; ++ *p5gh_cnt = 0; ++ ++ for( i = 0; i < pmlmeext->max_chan_nums; i++ ) ++ { ++ if ( pmlmeext->channel_set[ i ].ChannelNum <= 14 ) ++ { ++ (*p24g_cnt)++; ++ } ++ else if ( ( pmlmeext->channel_set[ i ].ChannelNum > 14 ) && ( pmlmeext->channel_set[ i ].ChannelNum <= 48 ) ) ++ { ++ // Just include the channel 36, 40, 44, 48 channels for 5G low ++ (*p5gl_cnt)++; ++ } ++ else if ( ( pmlmeext->channel_set[ i ].ChannelNum >= 149 ) && ( pmlmeext->channel_set[ i ].ChannelNum <= 161 ) ) ++ { ++ // Just include the channel 149, 153, 157, 161 channels for 5G high ++ (*p5gh_cnt)++; ++ } ++ } ++} ++ ++void issue_p2p_GO_request(_adapter *padapter, u8* raddr) ++{ ++ ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ u32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_GO_NEGO_REQ; ++ u8 wpsie[ 255 ] = { 0x00 }, p2pie[ 255 ] = { 0x00 }; ++ u8 wpsielen = 0, p2pielen = 0, i; ++ u8 channel_cnt_24g = 0, channel_cnt_5gl = 0, channel_cnt_5gh = 0; ++ u16 len_channellist_attr = 0; ++#ifdef CONFIG_WFD ++ u32 wfdielen = 0; ++#endif //CONFIG_WFD ++ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo); ++ ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ DBG_871X( "[%s] In\n", __FUNCTION__ ); ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); ++ pwdinfo->negotiation_dialog_token = 1; // Initialize the dialog value ++ pframe = rtw_set_fixed_ie(pframe, 1, &pwdinfo->negotiation_dialog_token, &(pattrib->pktlen)); ++ ++ ++ ++ // WPS Section ++ wpsielen = 0; ++ // WPS OUI ++ *(u32*) ( wpsie ) = cpu_to_be32( WPSOUI ); ++ wpsielen += 4; ++ ++ // WPS version ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_VER1 ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0001 ); ++ wpsielen += 2; ++ ++ // Value: ++ wpsie[wpsielen++] = WPS_VERSION_1; // Version 1.0 ++ ++ // Device Password ID ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_DEVICE_PWID ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0002 ); ++ wpsielen += 2; ++ ++ // Value: ++ ++ if ( pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN ) ++ { ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_DPID_USER_SPEC ); ++ } ++ else if ( pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN ) ++ { ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_DPID_REGISTRAR_SPEC ); ++ } ++ else if ( pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC ) ++ { ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_DPID_PBC ); ++ } ++ ++ wpsielen += 2; ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen ); ++ ++ ++ // P2P IE Section. ++ ++ // P2P OUI ++ p2pielen = 0; ++ p2pie[ p2pielen++ ] = 0x50; ++ p2pie[ p2pielen++ ] = 0x6F; ++ p2pie[ p2pielen++ ] = 0x9A; ++ p2pie[ p2pielen++ ] = 0x09; // WFA P2P v1.0 ++ ++ // Commented by Albert 20110306 ++ // According to the P2P Specification, the group negoitation request frame should contain 9 P2P attributes ++ // 1. P2P Capability ++ // 2. Group Owner Intent ++ // 3. Configuration Timeout ++ // 4. Listen Channel ++ // 5. Extended Listen Timing ++ // 6. Intended P2P Interface Address ++ // 7. Channel List ++ // 8. P2P Device Info ++ // 9. Operating Channel ++ ++ ++ // P2P Capability ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_CAPABILITY; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Device Capability Bitmap, 1 byte ++ p2pie[ p2pielen++ ] = DMP_P2P_DEVCAP_SUPPORT; ++ ++ // Group Capability Bitmap, 1 byte ++ if ( pwdinfo->persistent_supported ) ++ { ++ p2pie[ p2pielen++ ] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP; ++ } ++ else ++ { ++ p2pie[ p2pielen++ ] = P2P_GRPCAP_CROSS_CONN; ++ } ++ ++ ++ // Group Owner Intent ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_GO_INTENT; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0001 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Todo the tie breaker bit. ++ p2pie[ p2pielen++ ] = ( ( pwdinfo->intent << 1 ) | BIT(0) ); ++ ++ // Configuration Timeout ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_CONF_TIMEOUT; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); ++ p2pielen += 2; ++ ++ // Value: ++ p2pie[ p2pielen++ ] = 200; // 2 seconds needed to be the P2P GO ++ p2pie[ p2pielen++ ] = 200; // 2 seconds needed to be the P2P Client ++ ++ ++ // Listen Channel ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_LISTEN_CH; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0005 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Country String ++ p2pie[ p2pielen++ ] = 'X'; ++ p2pie[ p2pielen++ ] = 'X'; ++ ++ // The third byte should be set to 0x04. ++ // Described in the "Operating Channel Attribute" section. ++ p2pie[ p2pielen++ ] = 0x04; ++ ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x51; // Copy from SD7 ++ ++ // Channel Number ++ p2pie[ p2pielen++ ] = pwdinfo->listen_channel; // listening channel number ++ ++ ++ // Extended Listen Timing ATTR ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_EX_LISTEN_TIMING; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0004 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Availability Period ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0xFFFF ); ++ p2pielen += 2; ++ ++ // Availability Interval ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0xFFFF ); ++ p2pielen += 2; ++ ++ ++ // Intended P2P Interface Address ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_INTENTED_IF_ADDR; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( ETH_ALEN ); ++ p2pielen += 2; ++ ++ // Value: ++ _rtw_memcpy( p2pie + p2pielen, myid( &padapter->eeprompriv ), ETH_ALEN ); ++ p2pielen += ETH_ALEN; ++ ++ ++ // Channel List ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_CH_LIST; ++ ++ // Length: ++ // Country String(3) ++ // + ( Operating Class (1) + Number of Channels(1) ) * Operation Classes (?) ++ // + number of channels in all classes ++ len_channellist_attr = 3 ++ + (1 + 1) * (u16)(pmlmeext->channel_list.reg_classes) ++ + get_reg_classes_full_count(pmlmeext->channel_list); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 5 + 1 ); ++ } ++ else ++ { ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( len_channellist_attr ); ++ } ++#else ++ ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( len_channellist_attr ); ++ ++#endif ++ p2pielen += 2; ++ ++ // Value: ++ // Country String ++ p2pie[ p2pielen++ ] = 'X'; ++ p2pie[ p2pielen++ ] = 'X'; ++ ++ // The third byte should be set to 0x04. ++ // Described in the "Operating Channel Attribute" section. ++ p2pie[ p2pielen++ ] = 0x04; ++ ++ // Channel Entry List ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ ++ // Operating Class ++ if ( pbuddy_mlmeext->cur_channel > 14 ) ++ { ++ if ( pbuddy_mlmeext->cur_channel >= 149 ) ++ { ++ p2pie[ p2pielen++ ] = 0x7c; ++ } ++ else ++ { ++ p2pie[ p2pielen++ ] = 0x73; ++ } ++ } ++ else ++ { ++ p2pie[ p2pielen++ ] = 0x51; ++ } ++ ++ // Number of Channels ++ // Just support 1 channel and this channel is AP's channel ++ p2pie[ p2pielen++ ] = 1; ++ ++ // Channel List ++ p2pie[ p2pielen++ ] = pbuddy_mlmeext->cur_channel; ++ } ++ else ++ { ++ int i,j; ++ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { ++ // Operating Class ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; ++ ++ // Number of Channels ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; ++ ++ // Channel List ++ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; ++ } ++ } ++ } ++#else // CONFIG_CONCURRENT_MODE ++ { ++ int i,j; ++ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { ++ // Operating Class ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; ++ ++ // Number of Channels ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; ++ ++ // Channel List ++ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; ++ } ++ } ++ } ++#endif // CONFIG_CONCURRENT_MODE ++ ++ // Device Info ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) ++ // + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 21 + pwdinfo->device_name_len ); ++ p2pielen += 2; ++ ++ // Value: ++ // P2P Device Address ++ _rtw_memcpy( p2pie + p2pielen, myid( &padapter->eeprompriv ), ETH_ALEN ); ++ p2pielen += ETH_ALEN; ++ ++ // Config Method ++ // This field should be big endian. Noted by P2P specification. ++ ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( pwdinfo->supported_wps_cm ); ++ ++ p2pielen += 2; ++ ++ // Primary Device Type ++ // Category ID ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_CID_MULIT_MEDIA ); ++ p2pielen += 2; ++ ++ // OUI ++ *(u32*) ( p2pie + p2pielen ) = cpu_to_be32( WPSOUI ); ++ p2pielen += 4; ++ ++ // Sub Category ID ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_SCID_MEDIA_SERVER ); ++ p2pielen += 2; ++ ++ // Number of Secondary Device Types ++ p2pie[ p2pielen++ ] = 0x00; // No Secondary Device Type List ++ ++ // Device Name ++ // Type: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_ATTR_DEVICE_NAME ); ++ p2pielen += 2; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( pwdinfo->device_name_len ); ++ p2pielen += 2; ++ ++ // Value: ++ _rtw_memcpy( p2pie + p2pielen, pwdinfo->device_name , pwdinfo->device_name_len ); ++ p2pielen += pwdinfo->device_name_len; ++ ++ ++ // Operating Channel ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_OPERATING_CH; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0005 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Country String ++ p2pie[ p2pielen++ ] = 'X'; ++ p2pie[ p2pielen++ ] = 'X'; ++ ++ // The third byte should be set to 0x04. ++ // Described in the "Operating Channel Attribute" section. ++ p2pie[ p2pielen++ ] = 0x04; ++ ++ // Operating Class ++ if ( pwdinfo->operating_channel <= 14 ) ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x51; ++ } ++ else if ( ( pwdinfo->operating_channel >= 36 ) && ( pwdinfo->operating_channel <= 48 ) ) ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x73; ++ } ++ else ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x7c; ++ } ++ ++ // Channel Number ++ p2pie[ p2pielen++ ] = pwdinfo->operating_channel; // operating channel number ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen ); ++ ++#ifdef CONFIG_WFD ++ wfdielen = build_nego_req_wfd_ie(pwdinfo, pframe); ++ pframe += wfdielen; ++ pattrib->pktlen += wfdielen; ++#endif //CONFIG_WFD ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++ return; ++ ++} ++ ++ ++void issue_p2p_GO_response(_adapter *padapter, u8* raddr, u8* frame_body,uint len, u8 result) ++{ ++ ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ u32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_GO_NEGO_RESP; ++ u8 wpsie[ 255 ] = { 0x00 }, p2pie[ 255 ] = { 0x00 }; ++ u8 p2pielen = 0, i; ++ uint wpsielen = 0; ++ u16 wps_devicepassword_id = 0x0000; ++ uint wps_devicepassword_id_len = 0; ++ u8 channel_cnt_24g = 0, channel_cnt_5gl = 0, channel_cnt_5gh; ++ u16 len_channellist_attr = 0; ++ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo); ++ ++#ifdef CONFIG_WFD ++ u32 wfdielen = 0; ++#endif //CONFIG_WFD ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ DBG_871X( "[%s] In, result = %d\n", __FUNCTION__, result ); ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); ++ pwdinfo->negotiation_dialog_token = frame_body[7]; // The Dialog Token of provisioning discovery request frame. ++ pframe = rtw_set_fixed_ie(pframe, 1, &(pwdinfo->negotiation_dialog_token), &(pattrib->pktlen)); ++ ++ // Commented by Albert 20110328 ++ // Try to get the device password ID from the WPS IE of group negotiation request frame ++ // WiFi Direct test plan 5.1.15 ++ rtw_get_wps_ie( frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, wpsie, &wpsielen); ++ rtw_get_wps_attr_content( wpsie, wpsielen, WPS_ATTR_DEVICE_PWID, (u8*) &wps_devicepassword_id, &wps_devicepassword_id_len); ++ wps_devicepassword_id = be16_to_cpu( wps_devicepassword_id ); ++ ++ _rtw_memset( wpsie, 0x00, 255 ); ++ wpsielen = 0; ++ ++ // WPS Section ++ wpsielen = 0; ++ // WPS OUI ++ *(u32*) ( wpsie ) = cpu_to_be32( WPSOUI ); ++ wpsielen += 4; ++ ++ // WPS version ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_VER1 ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0001 ); ++ wpsielen += 2; ++ ++ // Value: ++ wpsie[wpsielen++] = WPS_VERSION_1; // Version 1.0 ++ ++ // Device Password ID ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_DEVICE_PWID ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0002 ); ++ wpsielen += 2; ++ ++ // Value: ++ if ( wps_devicepassword_id == WPS_DPID_USER_SPEC ) ++ { ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_DPID_REGISTRAR_SPEC ); ++ } ++ else if ( wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC ) ++ { ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_DPID_USER_SPEC ); ++ } ++ else ++ { ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_DPID_PBC ); ++ } ++ wpsielen += 2; ++ ++ // Commented by Kurt 20120113 ++ // If some device wants to do p2p handshake without sending prov_disc_req ++ // We have to get peer_req_cm from here. ++ if(_rtw_memcmp( pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3) ) ++ { ++ if ( wps_devicepassword_id == WPS_DPID_USER_SPEC ) ++ { ++ _rtw_memcpy( pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3 ); ++ } ++ else if ( wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC ) ++ { ++ _rtw_memcpy( pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3 ); ++ } ++ else ++ { ++ _rtw_memcpy( pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3 ); ++ } ++ } ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen ); ++ ++ ++ // P2P IE Section. ++ ++ // P2P OUI ++ p2pielen = 0; ++ p2pie[ p2pielen++ ] = 0x50; ++ p2pie[ p2pielen++ ] = 0x6F; ++ p2pie[ p2pielen++ ] = 0x9A; ++ p2pie[ p2pielen++ ] = 0x09; // WFA P2P v1.0 ++ ++ // Commented by Albert 20100908 ++ // According to the P2P Specification, the group negoitation response frame should contain 9 P2P attributes ++ // 1. Status ++ // 2. P2P Capability ++ // 3. Group Owner Intent ++ // 4. Configuration Timeout ++ // 5. Operating Channel ++ // 6. Intended P2P Interface Address ++ // 7. Channel List ++ // 8. Device Info ++ // 9. Group ID ( Only GO ) ++ ++ ++ // ToDo: ++ ++ // P2P Status ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_STATUS; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0001 ); ++ p2pielen += 2; ++ ++ // Value: ++ p2pie[ p2pielen++ ] = result; ++ ++ // P2P Capability ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_CAPABILITY; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Device Capability Bitmap, 1 byte ++ ++ if ( rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) ) ++ { ++ // Commented by Albert 2011/03/08 ++ // According to the P2P specification ++ // if the sending device will be client, the P2P Capability should be reserved of group negotation response frame ++ p2pie[ p2pielen++ ] = 0; ++ } ++ else ++ { ++ // Be group owner or meet the error case ++ p2pie[ p2pielen++ ] = DMP_P2P_DEVCAP_SUPPORT; ++ } ++ ++ // Group Capability Bitmap, 1 byte ++ if ( pwdinfo->persistent_supported ) ++ { ++ p2pie[ p2pielen++ ] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP; ++ } ++ else ++ { ++ p2pie[ p2pielen++ ] = P2P_GRPCAP_CROSS_CONN; ++ } ++ ++ // Group Owner Intent ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_GO_INTENT; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0001 ); ++ p2pielen += 2; ++ ++ // Value: ++ if ( pwdinfo->peer_intent & 0x01 ) ++ { ++ // Peer's tie breaker bit is 1, our tie breaker bit should be 0 ++ p2pie[ p2pielen++ ] = ( pwdinfo->intent << 1 ); ++ } ++ else ++ { ++ // Peer's tie breaker bit is 0, our tie breaker bit should be 1 ++ p2pie[ p2pielen++ ] = ( ( pwdinfo->intent << 1 ) | BIT(0) ); ++ } ++ ++ ++ // Configuration Timeout ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_CONF_TIMEOUT; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); ++ p2pielen += 2; ++ ++ // Value: ++ p2pie[ p2pielen++ ] = 200; // 2 seconds needed to be the P2P GO ++ p2pie[ p2pielen++ ] = 200; // 2 seconds needed to be the P2P Client ++ ++ // Operating Channel ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_OPERATING_CH; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0005 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Country String ++ p2pie[ p2pielen++ ] = 'X'; ++ p2pie[ p2pielen++ ] = 'X'; ++ ++ // The third byte should be set to 0x04. ++ // Described in the "Operating Channel Attribute" section. ++ p2pie[ p2pielen++ ] = 0x04; ++ ++ // Operating Class ++ if ( pwdinfo->operating_channel <= 14 ) ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x51; ++ } ++ else if ( ( pwdinfo->operating_channel >= 36 ) && ( pwdinfo->operating_channel <= 48 ) ) ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x73; ++ } ++ else ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x7c; ++ } ++ ++ // Channel Number ++ p2pie[ p2pielen++ ] = pwdinfo->operating_channel; // operating channel number ++ ++ // Intended P2P Interface Address ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_INTENTED_IF_ADDR; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( ETH_ALEN ); ++ p2pielen += 2; ++ ++ // Value: ++ _rtw_memcpy( p2pie + p2pielen, myid( &padapter->eeprompriv ), ETH_ALEN ); ++ p2pielen += ETH_ALEN; ++ ++ // Channel List ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_CH_LIST; ++ ++ // Country String(3) ++ // + ( Operating Class (1) + Number of Channels(1) ) * Operation Classes (?) ++ // + number of channels in all classes ++ len_channellist_attr = 3 ++ + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes ++ + get_reg_classes_full_count(pmlmeext->channel_list); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 5 + 1 ); ++ } ++ else ++ { ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( len_channellist_attr ); ++ } ++#else ++ ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( len_channellist_attr ); ++ ++ #endif ++ p2pielen += 2; ++ ++ // Value: ++ // Country String ++ p2pie[ p2pielen++ ] = 'X'; ++ p2pie[ p2pielen++ ] = 'X'; ++ ++ // The third byte should be set to 0x04. ++ // Described in the "Operating Channel Attribute" section. ++ p2pie[ p2pielen++ ] = 0x04; ++ ++ // Channel Entry List ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ ++ // Operating Class ++ if ( pbuddy_mlmeext->cur_channel > 14 ) ++ { ++ if ( pbuddy_mlmeext->cur_channel >= 149 ) ++ { ++ p2pie[ p2pielen++ ] = 0x7c; ++ } ++ else ++ { ++ p2pie[ p2pielen++ ] = 0x73; ++ } ++ } ++ else ++ { ++ p2pie[ p2pielen++ ] = 0x51; ++ } ++ ++ // Number of Channels ++ // Just support 1 channel and this channel is AP's channel ++ p2pie[ p2pielen++ ] = 1; ++ ++ // Channel List ++ p2pie[ p2pielen++ ] = pbuddy_mlmeext->cur_channel; ++ } ++ else ++ { ++ int i, j; ++ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { ++ // Operating Class ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; ++ ++ // Number of Channels ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; ++ ++ // Channel List ++ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; ++ } ++ } ++ } ++#else // CONFIG_CONCURRENT_MODE ++ { ++ int i, j; ++ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { ++ // Operating Class ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; ++ ++ // Number of Channels ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; ++ ++ // Channel List ++ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; ++ } ++ } ++ } ++#endif // CONFIG_CONCURRENT_MODE ++ ++ ++ // Device Info ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) ++ // + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 21 + pwdinfo->device_name_len ); ++ p2pielen += 2; ++ ++ // Value: ++ // P2P Device Address ++ _rtw_memcpy( p2pie + p2pielen, myid( &padapter->eeprompriv ), ETH_ALEN ); ++ p2pielen += ETH_ALEN; ++ ++ // Config Method ++ // This field should be big endian. Noted by P2P specification. ++ ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( pwdinfo->supported_wps_cm ); ++ ++ p2pielen += 2; ++ ++ // Primary Device Type ++ // Category ID ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_CID_MULIT_MEDIA ); ++ p2pielen += 2; ++ ++ // OUI ++ *(u32*) ( p2pie + p2pielen ) = cpu_to_be32( WPSOUI ); ++ p2pielen += 4; ++ ++ // Sub Category ID ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_SCID_MEDIA_SERVER ); ++ p2pielen += 2; ++ ++ // Number of Secondary Device Types ++ p2pie[ p2pielen++ ] = 0x00; // No Secondary Device Type List ++ ++ // Device Name ++ // Type: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_ATTR_DEVICE_NAME ); ++ p2pielen += 2; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( pwdinfo->device_name_len ); ++ p2pielen += 2; ++ ++ // Value: ++ _rtw_memcpy( p2pie + p2pielen, pwdinfo->device_name , pwdinfo->device_name_len ); ++ p2pielen += pwdinfo->device_name_len; ++ ++ if ( rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) ) ++ { ++ // Group ID Attribute ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_GROUP_ID; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( ETH_ALEN + pwdinfo->nego_ssidlen ); ++ p2pielen += 2; ++ ++ // Value: ++ // p2P Device Address ++ _rtw_memcpy( p2pie + p2pielen , pwdinfo->device_addr, ETH_ALEN ); ++ p2pielen += ETH_ALEN; ++ ++ // SSID ++ _rtw_memcpy( p2pie + p2pielen, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen ); ++ p2pielen += pwdinfo->nego_ssidlen; ++ ++ } ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen ); ++ ++#ifdef CONFIG_WFD ++ wfdielen = build_nego_resp_wfd_ie(pwdinfo, pframe); ++ pframe += wfdielen; ++ pattrib->pktlen += wfdielen; ++#endif //CONFIG_WFD ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++ return; ++ ++} ++ ++void issue_p2p_GO_confirm(_adapter *padapter, u8* raddr, u8 result) ++{ ++ ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ u32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_GO_NEGO_CONF; ++ u8 wpsie[ 255 ] = { 0x00 }, p2pie[ 255 ] = { 0x00 }; ++ u8 wpsielen = 0, p2pielen = 0; ++ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo); ++#ifdef CONFIG_WFD ++ u32 wfdielen = 0; ++#endif //CONFIG_WFD ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ DBG_871X( "[%s] In\n", __FUNCTION__ ); ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(pwdinfo->negotiation_dialog_token), &(pattrib->pktlen)); ++ ++ ++ ++ // P2P IE Section. ++ ++ // P2P OUI ++ p2pielen = 0; ++ p2pie[ p2pielen++ ] = 0x50; ++ p2pie[ p2pielen++ ] = 0x6F; ++ p2pie[ p2pielen++ ] = 0x9A; ++ p2pie[ p2pielen++ ] = 0x09; // WFA P2P v1.0 ++ ++ // Commented by Albert 20110306 ++ // According to the P2P Specification, the group negoitation request frame should contain 5 P2P attributes ++ // 1. Status ++ // 2. P2P Capability ++ // 3. Operating Channel ++ // 4. Channel List ++ // 5. Group ID ( if this WiFi is GO ) ++ ++ // P2P Status ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_STATUS; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0001 ); ++ p2pielen += 2; ++ ++ // Value: ++ p2pie[ p2pielen++ ] = result; ++ ++ // P2P Capability ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_CAPABILITY; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Device Capability Bitmap, 1 byte ++ p2pie[ p2pielen++ ] = DMP_P2P_DEVCAP_SUPPORT; ++ ++ // Group Capability Bitmap, 1 byte ++ if ( pwdinfo->persistent_supported ) ++ { ++ p2pie[ p2pielen++ ] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP; ++ } ++ else ++ { ++ p2pie[ p2pielen++ ] = P2P_GRPCAP_CROSS_CONN; ++ } ++ ++ ++ // Operating Channel ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_OPERATING_CH; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0005 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Country String ++ p2pie[ p2pielen++ ] = 'X'; ++ p2pie[ p2pielen++ ] = 'X'; ++ ++ // The third byte should be set to 0x04. ++ // Described in the "Operating Channel Attribute" section. ++ p2pie[ p2pielen++ ] = 0x04; ++ ++ ++ if ( rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) ) ++ { ++ if ( pwdinfo->peer_operating_ch <= 14 ) ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x51; ++ } ++ else if ( ( pwdinfo->peer_operating_ch >= 36 ) && ( pwdinfo->peer_operating_ch <= 48 ) ) ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x73; ++ } ++ else ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x7c; ++ } ++ ++ p2pie[ p2pielen++ ] = pwdinfo->peer_operating_ch; ++ } ++ else ++ { ++ if ( pwdinfo->operating_channel <= 14 ) ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x51; ++ } ++ else if ( ( pwdinfo->operating_channel >= 36 ) && ( pwdinfo->operating_channel <= 48 ) ) ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x73; ++ } ++ else ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x7c; ++ } ++ ++ // Channel Number ++ p2pie[ p2pielen++ ] = pwdinfo->operating_channel; // Use the listen channel as the operating channel ++ } ++ ++ ++ // Channel List ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_CH_LIST; ++ ++ *(u16*) ( p2pie + p2pielen ) = 6; ++ p2pielen += 2; ++ ++ // Country String ++ p2pie[ p2pielen++ ] = 'X'; ++ p2pie[ p2pielen++ ] = 'X'; ++ ++ // The third byte should be set to 0x04. ++ // Described in the "Operating Channel Attribute" section. ++ p2pie[ p2pielen++ ] = 0x04; ++ ++ // Value: ++ if ( rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) ) ++ { ++ if ( pwdinfo->peer_operating_ch <= 14 ) ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x51; ++ } ++ else if ( ( pwdinfo->peer_operating_ch >= 36 ) && ( pwdinfo->peer_operating_ch <= 48 ) ) ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x73; ++ } ++ else ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x7c; ++ } ++ p2pie[ p2pielen++ ] = 1; ++ p2pie[ p2pielen++ ] = pwdinfo->peer_operating_ch; ++ } ++ else ++ { ++ if ( pwdinfo->operating_channel <= 14 ) ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x51; ++ } ++ else if ( ( pwdinfo->operating_channel >= 36 ) && ( pwdinfo->operating_channel <= 48 ) ) ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x73; ++ } ++ else ++ { ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x7c; ++ } ++ ++ // Channel Number ++ p2pie[ p2pielen++ ] = 1; ++ p2pie[ p2pielen++ ] = pwdinfo->operating_channel; // Use the listen channel as the operating channel ++ } ++ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) ) ++ { ++ // Group ID Attribute ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_GROUP_ID; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( ETH_ALEN + pwdinfo->nego_ssidlen ); ++ p2pielen += 2; ++ ++ // Value: ++ // p2P Device Address ++ _rtw_memcpy( p2pie + p2pielen , pwdinfo->device_addr, ETH_ALEN ); ++ p2pielen += ETH_ALEN; ++ ++ // SSID ++ _rtw_memcpy( p2pie + p2pielen, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen ); ++ p2pielen += pwdinfo->nego_ssidlen; ++ } ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen ); ++ ++#ifdef CONFIG_WFD ++ wfdielen = build_nego_confirm_wfd_ie(pwdinfo, pframe); ++ pframe += wfdielen; ++ pattrib->pktlen += wfdielen; ++#endif //CONFIG_WFD ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++ return; ++ ++} ++ ++void issue_p2p_invitation_request(_adapter *padapter, u8* raddr ) ++{ ++ ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ u32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_INVIT_REQ; ++ u8 p2pie[ 255 ] = { 0x00 }; ++ u8 p2pielen = 0, i; ++ u8 dialogToken = 3; ++ u8 channel_cnt_24g = 0, channel_cnt_5gl = 0, channel_cnt_5gh = 0; ++ u16 len_channellist_attr = 0; ++#ifdef CONFIG_WFD ++ u32 wfdielen = 0; ++#endif //CONFIG_WFD ++#ifdef CONFIG_CONCURRENT_MODE ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct wifidirect_info *pbuddy_wdinfo = &pbuddy_adapter->wdinfo; ++ struct mlme_priv *pbuddy_mlmepriv = &pbuddy_adapter->mlmepriv; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++#endif ++ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo); ++ ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, raddr, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); ++ ++ // P2P IE Section. ++ ++ // P2P OUI ++ p2pielen = 0; ++ p2pie[ p2pielen++ ] = 0x50; ++ p2pie[ p2pielen++ ] = 0x6F; ++ p2pie[ p2pielen++ ] = 0x9A; ++ p2pie[ p2pielen++ ] = 0x09; // WFA P2P v1.0 ++ ++ // Commented by Albert 20101011 ++ // According to the P2P Specification, the P2P Invitation request frame should contain 7 P2P attributes ++ // 1. Configuration Timeout ++ // 2. Invitation Flags ++ // 3. Operating Channel ( Only GO ) ++ // 4. P2P Group BSSID ( Should be included if I am the GO ) ++ // 5. Channel List ++ // 6. P2P Group ID ++ // 7. P2P Device Info ++ ++ // Configuration Timeout ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_CONF_TIMEOUT; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); ++ p2pielen += 2; ++ ++ // Value: ++ p2pie[ p2pielen++ ] = 200; // 2 seconds needed to be the P2P GO ++ p2pie[ p2pielen++ ] = 200; // 2 seconds needed to be the P2P Client ++ ++ // Invitation Flags ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_INVITATION_FLAGS; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0001 ); ++ p2pielen += 2; ++ ++ // Value: ++ p2pie[ p2pielen++ ] = P2P_INVITATION_FLAGS_PERSISTENT; ++ ++ ++ // Operating Channel ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_OPERATING_CH; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0005 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Country String ++ p2pie[ p2pielen++ ] = 'X'; ++ p2pie[ p2pielen++ ] = 'X'; ++ ++ // The third byte should be set to 0x04. ++ // Described in the "Operating Channel Attribute" section. ++ p2pie[ p2pielen++ ] = 0x04; ++ ++ // Operating Class ++ if ( pwdinfo->invitereq_info.operating_ch <= 14 ) ++ p2pie[ p2pielen++ ] = 0x51; ++ else if ( ( pwdinfo->invitereq_info.operating_ch >= 36 ) && ( pwdinfo->invitereq_info.operating_ch <= 48 ) ) ++ p2pie[ p2pielen++ ] = 0x73; ++ else ++ p2pie[ p2pielen++ ] = 0x7c; ++ ++ // Channel Number ++ p2pie[ p2pielen++ ] = pwdinfo->invitereq_info.operating_ch; // operating channel number ++ ++ if ( _rtw_memcmp( myid( &padapter->eeprompriv ), pwdinfo->invitereq_info.go_bssid, ETH_ALEN ) ) ++ { ++ // P2P Group BSSID ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_GROUP_BSSID; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( ETH_ALEN ); ++ p2pielen += 2; ++ ++ // Value: ++ // P2P Device Address for GO ++ _rtw_memcpy( p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN ); ++ p2pielen += ETH_ALEN; ++ } ++ ++ // Channel List ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_CH_LIST; ++ ++ ++ // Length: ++ // Country String(3) ++ // + ( Operating Class (1) + Number of Channels(1) ) * Operation Classes (?) ++ // + number of channels in all classes ++ len_channellist_attr = 3 ++ + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes ++ + get_reg_classes_full_count(pmlmeext->channel_list); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 5 + 1 ); ++ } ++ else ++ { ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( len_channellist_attr ); ++ } ++#else ++ ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( len_channellist_attr ); ++ ++ #endif ++ p2pielen += 2; ++ ++ // Value: ++ // Country String ++ p2pie[ p2pielen++ ] = 'X'; ++ p2pie[ p2pielen++ ] = 'X'; ++ ++ // The third byte should be set to 0x04. ++ // Described in the "Operating Channel Attribute" section. ++ p2pie[ p2pielen++ ] = 0x04; ++ ++ // Channel Entry List ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ ++ // Operating Class ++ if ( pbuddy_mlmeext->cur_channel > 14 ) ++ { ++ if ( pbuddy_mlmeext->cur_channel >= 149 ) ++ { ++ p2pie[ p2pielen++ ] = 0x7c; ++ } ++ else ++ { ++ p2pie[ p2pielen++ ] = 0x73; ++ } ++ } ++ else ++ { ++ p2pie[ p2pielen++ ] = 0x51; ++ } ++ ++ // Number of Channels ++ // Just support 1 channel and this channel is AP's channel ++ p2pie[ p2pielen++ ] = 1; ++ ++ // Channel List ++ p2pie[ p2pielen++ ] = pbuddy_mlmeext->cur_channel; ++ } ++ else ++ { ++ int i, j; ++ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { ++ // Operating Class ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; ++ ++ // Number of Channels ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; ++ ++ // Channel List ++ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; ++ } ++ } ++ } ++#else // CONFIG_CONCURRENT_MODE ++ { ++ int i, j; ++ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { ++ // Operating Class ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; ++ ++ // Number of Channels ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; ++ ++ // Channel List ++ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; ++ } ++ } ++ } ++#endif // CONFIG_CONCURRENT_MODE ++ ++ ++ // P2P Group ID ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_GROUP_ID; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 6 + pwdinfo->invitereq_info.ssidlen ); ++ p2pielen += 2; ++ ++ // Value: ++ // P2P Device Address for GO ++ _rtw_memcpy( p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN ); ++ p2pielen += ETH_ALEN; ++ ++ // SSID ++ _rtw_memcpy( p2pie + p2pielen, pwdinfo->invitereq_info.go_ssid, pwdinfo->invitereq_info.ssidlen ); ++ p2pielen += pwdinfo->invitereq_info.ssidlen; ++ ++ ++ // Device Info ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) ++ // + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 21 + pwdinfo->device_name_len ); ++ p2pielen += 2; ++ ++ // Value: ++ // P2P Device Address ++ _rtw_memcpy( p2pie + p2pielen, myid( &padapter->eeprompriv ), ETH_ALEN ); ++ p2pielen += ETH_ALEN; ++ ++ // Config Method ++ // This field should be big endian. Noted by P2P specification. ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_CONFIG_METHOD_DISPLAY ); ++ p2pielen += 2; ++ ++ // Primary Device Type ++ // Category ID ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_CID_MULIT_MEDIA ); ++ p2pielen += 2; ++ ++ // OUI ++ *(u32*) ( p2pie + p2pielen ) = cpu_to_be32( WPSOUI ); ++ p2pielen += 4; ++ ++ // Sub Category ID ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_SCID_MEDIA_SERVER ); ++ p2pielen += 2; ++ ++ // Number of Secondary Device Types ++ p2pie[ p2pielen++ ] = 0x00; // No Secondary Device Type List ++ ++ // Device Name ++ // Type: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_ATTR_DEVICE_NAME ); ++ p2pielen += 2; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( pwdinfo->device_name_len ); ++ p2pielen += 2; ++ ++ // Value: ++ _rtw_memcpy( p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len ); ++ p2pielen += pwdinfo->device_name_len; ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen ); ++ ++#ifdef CONFIG_WFD ++ wfdielen = build_invitation_req_wfd_ie(pwdinfo, pframe); ++ pframe += wfdielen; ++ pattrib->pktlen += wfdielen; ++#endif //CONFIG_WFD ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++ return; ++ ++} ++ ++void issue_p2p_invitation_response(_adapter *padapter, u8* raddr, u8 dialogToken, u8 status_code) ++{ ++ ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ u32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_INVIT_RESP; ++ u8 p2pie[ 255 ] = { 0x00 }; ++ u8 p2pielen = 0, i; ++ u8 channel_cnt_24g = 0, channel_cnt_5gl = 0, channel_cnt_5gh = 0; ++ u16 len_channellist_attr = 0; ++#ifdef CONFIG_CONCURRENT_MODE ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct wifidirect_info *pbuddy_wdinfo = &pbuddy_adapter->wdinfo; ++ struct mlme_priv *pbuddy_mlmepriv = &pbuddy_adapter->mlmepriv; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++#endif ++#ifdef CONFIG_WFD ++ u32 wfdielen = 0; ++#endif //CONFIG_WFD ++ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo); ++ ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, raddr, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); ++ ++ // P2P IE Section. ++ ++ // P2P OUI ++ p2pielen = 0; ++ p2pie[ p2pielen++ ] = 0x50; ++ p2pie[ p2pielen++ ] = 0x6F; ++ p2pie[ p2pielen++ ] = 0x9A; ++ p2pie[ p2pielen++ ] = 0x09; // WFA P2P v1.0 ++ ++ // Commented by Albert 20101005 ++ // According to the P2P Specification, the P2P Invitation response frame should contain 5 P2P attributes ++ // 1. Status ++ // 2. Configuration Timeout ++ // 3. Operating Channel ( Only GO ) ++ // 4. P2P Group BSSID ( Only GO ) ++ // 5. Channel List ++ ++ // P2P Status ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_STATUS; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0001 ); ++ p2pielen += 2; ++ ++ // Value: ++ // When status code is P2P_STATUS_FAIL_INFO_UNAVAILABLE. ++ // Sent the event receiving the P2P Invitation Req frame to DMP UI. ++ // DMP had to compare the MAC address to find out the profile. ++ // So, the WiFi driver will send the P2P_STATUS_FAIL_INFO_UNAVAILABLE to NB. ++ // If the UI found the corresponding profile, the WiFi driver sends the P2P Invitation Req ++ // to NB to rebuild the persistent group. ++ p2pie[ p2pielen++ ] = status_code; ++ ++ // Configuration Timeout ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_CONF_TIMEOUT; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); ++ p2pielen += 2; ++ ++ // Value: ++ p2pie[ p2pielen++ ] = 200; // 2 seconds needed to be the P2P GO ++ p2pie[ p2pielen++ ] = 200; // 2 seconds needed to be the P2P Client ++ ++ if( status_code == P2P_STATUS_SUCCESS ) ++ { ++ if( rtw_p2p_chk_role( pwdinfo, P2P_ROLE_GO ) ) ++ { ++ // The P2P Invitation request frame asks this Wi-Fi device to be the P2P GO ++ // In this case, the P2P Invitation response frame should carry the two more P2P attributes. ++ // First one is operating channel attribute. ++ // Second one is P2P Group BSSID attribute. ++ ++ // Operating Channel ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_OPERATING_CH; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0005 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Country String ++ p2pie[ p2pielen++ ] = 'X'; ++ p2pie[ p2pielen++ ] = 'X'; ++ ++ // The third byte should be set to 0x04. ++ // Described in the "Operating Channel Attribute" section. ++ p2pie[ p2pielen++ ] = 0x04; ++ ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x51; // Copy from SD7 ++ ++ // Channel Number ++ p2pie[ p2pielen++ ] = pwdinfo->operating_channel; // operating channel number ++ ++ ++ // P2P Group BSSID ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_GROUP_BSSID; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( ETH_ALEN ); ++ p2pielen += 2; ++ ++ // Value: ++ // P2P Device Address for GO ++ _rtw_memcpy( p2pie + p2pielen, myid( &padapter->eeprompriv ), ETH_ALEN ); ++ p2pielen += ETH_ALEN; ++ ++ } ++ ++ // Channel List ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_CH_LIST; ++ ++ // Length: ++ // Country String(3) ++ // + ( Operating Class (1) + Number of Channels(1) ) * Operation Classes (?) ++ // + number of channels in all classes ++ len_channellist_attr = 3 ++ + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes ++ + get_reg_classes_full_count(pmlmeext->channel_list); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 5 + 1 ); ++ } ++ else ++ { ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( len_channellist_attr ); ++ } ++#else ++ ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( len_channellist_attr ); ++ ++#endif ++ p2pielen += 2; ++ ++ // Value: ++ // Country String ++ p2pie[ p2pielen++ ] = 'X'; ++ p2pie[ p2pielen++ ] = 'X'; ++ ++ // The third byte should be set to 0x04. ++ // Described in the "Operating Channel Attribute" section. ++ p2pie[ p2pielen++ ] = 0x04; ++ ++ // Channel Entry List ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ ++ // Operating Class ++ if ( pbuddy_mlmeext->cur_channel > 14 ) ++ { ++ if ( pbuddy_mlmeext->cur_channel >= 149 ) ++ { ++ p2pie[ p2pielen++ ] = 0x7c; ++ } ++ else ++ { ++ p2pie[ p2pielen++ ] = 0x73; ++ } ++ } ++ else ++ { ++ p2pie[ p2pielen++ ] = 0x51; ++ } ++ ++ // Number of Channels ++ // Just support 1 channel and this channel is AP's channel ++ p2pie[ p2pielen++ ] = 1; ++ ++ // Channel List ++ p2pie[ p2pielen++ ] = pbuddy_mlmeext->cur_channel; ++ } ++ else ++ { ++ int i, j; ++ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { ++ // Operating Class ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; ++ ++ // Number of Channels ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; ++ ++ // Channel List ++ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; ++ } ++ } ++ } ++#else // CONFIG_CONCURRENT_MODE ++ { ++ int i, j; ++ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { ++ // Operating Class ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; ++ ++ // Number of Channels ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; ++ ++ // Channel List ++ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; ++ } ++ } ++ } ++#endif // CONFIG_CONCURRENT_MODE ++ } ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen ); ++ ++#ifdef CONFIG_WFD ++ wfdielen = build_invitation_resp_wfd_ie(pwdinfo, pframe); ++ pframe += wfdielen; ++ pattrib->pktlen += wfdielen; ++#endif //CONFIG_WFD ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++ return; ++ ++} ++ ++void issue_p2p_provision_request(_adapter *padapter, u8* pssid, u8 ussidlen, u8* pdev_raddr ) ++{ ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ u8 dialogToken = 1; ++ u32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_PROVISION_DISC_REQ; ++ u8 wpsie[ 100 ] = { 0x00 }; ++ u8 wpsielen = 0; ++ u32 p2pielen = 0; ++#ifdef CONFIG_WFD ++ u32 wfdielen = 0; ++#endif //CONFIG_WFD ++ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); ++ ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ DBG_871X( "[%s] In\n", __FUNCTION__ ); ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, pdev_raddr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, pdev_raddr, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); ++ ++ p2pielen = build_prov_disc_request_p2p_ie( pwdinfo, pframe, pssid, ussidlen, pdev_raddr ); ++ ++ pframe += p2pielen; ++ pattrib->pktlen += p2pielen; ++ ++ wpsielen = 0; ++ // WPS OUI ++ *(u32*) ( wpsie ) = cpu_to_be32( WPSOUI ); ++ wpsielen += 4; ++ ++ // WPS version ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_VER1 ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0001 ); ++ wpsielen += 2; ++ ++ // Value: ++ wpsie[wpsielen++] = WPS_VERSION_1; // Version 1.0 ++ ++ // Config Method ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_CONF_METHOD ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0002 ); ++ wpsielen += 2; ++ ++ // Value: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( pwdinfo->tx_prov_disc_info.wps_config_method_request ); ++ wpsielen += 2; ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen ); ++ ++ ++#ifdef CONFIG_WFD ++ wfdielen = build_provdisc_req_wfd_ie(pwdinfo, pframe); ++ pframe += wfdielen; ++ pattrib->pktlen += wfdielen; ++#endif //CONFIG_WFD ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++ return; ++ ++} ++ ++ ++u8 is_matched_in_profilelist( u8* peermacaddr, struct profile_info* profileinfo ) ++{ ++ u8 i, match_result = 0; ++ ++ DBG_871X( "[%s] peermac = %.2X %.2X %.2X %.2X %.2X %.2X\n", __FUNCTION__, ++ peermacaddr[0], peermacaddr[1],peermacaddr[2],peermacaddr[3],peermacaddr[4],peermacaddr[5]); ++ ++ for( i = 0; i < P2P_MAX_PERSISTENT_GROUP_NUM; i++, profileinfo++ ) ++ { ++ DBG_871X( "[%s] profileinfo_mac = %.2X %.2X %.2X %.2X %.2X %.2X\n", __FUNCTION__, ++ profileinfo->peermac[0], profileinfo->peermac[1],profileinfo->peermac[2],profileinfo->peermac[3],profileinfo->peermac[4],profileinfo->peermac[5]); ++ if ( _rtw_memcmp( peermacaddr, profileinfo->peermac, ETH_ALEN ) ) ++ { ++ match_result = 1; ++ DBG_871X( "[%s] Match!\n", __FUNCTION__ ); ++ break; ++ } ++ } ++ ++ return (match_result ); ++} ++ ++void issue_probersp_p2p(_adapter *padapter, unsigned char *da) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ unsigned char *mac; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ //WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); ++ u16 beacon_interval = 100; ++ u16 capInfo = 0; ++ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); ++ u8 wpsie[255] = { 0x00 }; ++ u32 wpsielen = 0, p2pielen = 0; ++#ifdef CONFIG_WFD ++ u32 wfdielen = 0; ++#endif //CONFIG_WFD ++#ifdef CONFIG_INTEL_WIDI ++ u8 zero_array_check[L2SDTA_SERVICE_VE_LEN] = { 0x00 }; ++#endif //CONFIG_INTEL_WIDI ++ ++ //DBG_871X("%s\n", __FUNCTION__); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ mac = myid(&(padapter->eeprompriv)); ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN); ++ ++ // Use the device address for BSSID field. ++ _rtw_memcpy(pwlanhdr->addr3, mac, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(fctrl, WIFI_PROBERSP); ++ ++ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = pattrib->hdrlen; ++ pframe += pattrib->hdrlen; ++ ++ //timestamp will be inserted by hardware ++ pframe += 8; ++ pattrib->pktlen += 8; ++ ++ // beacon interval: 2 bytes ++ _rtw_memcpy(pframe, (unsigned char *) &beacon_interval, 2); ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ // capability info: 2 bytes ++ // ESS and IBSS bits must be 0 (defined in the 3.1.2.1.1 of WiFi Direct Spec) ++ capInfo |= cap_ShortPremble; ++ capInfo |= cap_ShortSlot; ++ ++ _rtw_memcpy(pframe, (unsigned char *) &capInfo, 2); ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ ++ // SSID ++ pframe = rtw_set_ie(pframe, _SSID_IE_, 7, pwdinfo->p2p_wildcard_ssid, &pattrib->pktlen); ++ ++ // supported rates... ++ // Use the OFDM rate in the P2P probe response frame. ( 6(B), 9(B), 12, 18, 24, 36, 48, 54 ) ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pwdinfo->support_rate, &pattrib->pktlen); ++ ++ // DS parameter set ++ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&pwdinfo->listen_channel, &pattrib->pktlen); ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if(wdev_to_priv(padapter->rtw_wdev)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ { ++ if( pmlmepriv->wps_probe_resp_ie != NULL && pmlmepriv->p2p_probe_resp_ie != NULL ) ++ { ++ //WPS IE ++ _rtw_memcpy(pframe, pmlmepriv->wps_probe_resp_ie, pmlmepriv->wps_probe_resp_ie_len); ++ pattrib->pktlen += pmlmepriv->wps_probe_resp_ie_len; ++ pframe += pmlmepriv->wps_probe_resp_ie_len; ++ ++ //P2P IE ++ _rtw_memcpy(pframe, pmlmepriv->p2p_probe_resp_ie, pmlmepriv->p2p_probe_resp_ie_len); ++ pattrib->pktlen += pmlmepriv->p2p_probe_resp_ie_len; ++ pframe += pmlmepriv->p2p_probe_resp_ie_len; ++ } ++ } ++ else ++#endif //CONFIG_IOCTL_CFG80211 ++ { ++ ++ // Todo: WPS IE ++ // Noted by Albert 20100907 ++ // According to the WPS specification, all the WPS attribute is presented by Big Endian. ++ ++ wpsielen = 0; ++ // WPS OUI ++ *(u32*) ( wpsie ) = cpu_to_be32( WPSOUI ); ++ wpsielen += 4; ++ ++ // WPS version ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_VER1 ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0001 ); ++ wpsielen += 2; ++ ++ // Value: ++ wpsie[wpsielen++] = WPS_VERSION_1; // Version 1.0 ++ ++#ifdef CONFIG_INTEL_WIDI ++ // Commented by Kurt ++ // Appended WiDi info. only if we did issued_probereq_widi(), and then we saved ven. ext. in pmlmepriv->sa_ext. ++ if( _rtw_memcmp(pmlmepriv->sa_ext, zero_array_check, L2SDTA_SERVICE_VE_LEN) == _FALSE ++ || pmlmepriv->num_p2p_sdt != 0 ) ++ { ++ //Sec dev type ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_SEC_DEV_TYPE_LIST ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0008 ); ++ wpsielen += 2; ++ ++ // Value: ++ // Category ID ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_PDT_CID_DISPLAYS ); ++ wpsielen += 2; ++ ++ // OUI ++ *(u32*) ( wpsie + wpsielen ) = cpu_to_be32( INTEL_DEV_TYPE_OUI ); ++ wpsielen += 4; ++ ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_PDT_SCID_WIDI_CONSUMER_SINK ); ++ wpsielen += 2; ++ ++ if( _rtw_memcmp(pmlmepriv->sa_ext, zero_array_check, L2SDTA_SERVICE_VE_LEN) == _FALSE ) ++ { ++ // Vendor Extension ++ _rtw_memcpy( wpsie + wpsielen, pmlmepriv->sa_ext, L2SDTA_SERVICE_VE_LEN ); ++ wpsielen += L2SDTA_SERVICE_VE_LEN; ++ } ++ } ++#endif //CONFIG_INTEL_WIDI ++ ++ // WiFi Simple Config State ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_SIMPLE_CONF_STATE ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0001 ); ++ wpsielen += 2; ++ ++ // Value: ++ wpsie[wpsielen++] = WPS_WSC_STATE_NOT_CONFIG; // Not Configured. ++ ++ // Response Type ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_RESP_TYPE ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0001 ); ++ wpsielen += 2; ++ ++ // Value: ++ wpsie[wpsielen++] = WPS_RESPONSE_TYPE_8021X; ++ ++ // UUID-E ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_UUID_E ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0010 ); ++ wpsielen += 2; ++ ++ // Value: ++ if (pwdinfo->external_uuid == 0) { ++ _rtw_memset( wpsie + wpsielen, 0x0, 16 ); ++ _rtw_memcpy( wpsie + wpsielen, myid( &padapter->eeprompriv ), ETH_ALEN ); ++ } else { ++ _rtw_memcpy( wpsie + wpsielen, pwdinfo->uuid, 0x10 ); ++ } ++ wpsielen += 0x10; ++ ++ // Manufacturer ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_MANUFACTURER ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0007 ); ++ wpsielen += 2; ++ ++ // Value: ++ _rtw_memcpy( wpsie + wpsielen, "Realtek", 7 ); ++ wpsielen += 7; ++ ++ // Model Name ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_MODEL_NAME ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0006 ); ++ wpsielen += 2; ++ ++ // Value: ++ _rtw_memcpy( wpsie + wpsielen, "8192CU", 6 ); ++ wpsielen += 6; ++ ++ // Model Number ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_MODEL_NUMBER ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0001 ); ++ wpsielen += 2; ++ ++ // Value: ++ wpsie[ wpsielen++ ] = 0x31; // character 1 ++ ++ // Serial Number ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_SERIAL_NUMBER ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( ETH_ALEN ); ++ wpsielen += 2; ++ ++ // Value: ++ _rtw_memcpy( wpsie + wpsielen, "123456" , ETH_ALEN ); ++ wpsielen += ETH_ALEN; ++ ++ // Primary Device Type ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_PRIMARY_DEV_TYPE ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0008 ); ++ wpsielen += 2; ++ ++ // Value: ++ // Category ID ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_PDT_CID_MULIT_MEDIA ); ++ wpsielen += 2; ++ ++ // OUI ++ *(u32*) ( wpsie + wpsielen ) = cpu_to_be32( WPSOUI ); ++ wpsielen += 4; ++ ++ // Sub Category ID ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_PDT_SCID_MEDIA_SERVER ); ++ wpsielen += 2; ++ ++ // Device Name ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_DEVICE_NAME ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( pwdinfo->device_name_len ); ++ wpsielen += 2; ++ ++ // Value: ++ if (pwdinfo->device_name_len) ++ { ++ _rtw_memcpy( wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len ); ++ wpsielen += pwdinfo->device_name_len; ++ } ++ ++ // Config Method ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_CONF_METHOD ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0002 ); ++ wpsielen += 2; ++ ++ // Value: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( pwdinfo->supported_wps_cm ); ++ wpsielen += 2; ++ ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen ); ++ ++ ++ p2pielen = build_probe_resp_p2p_ie(pwdinfo, pframe); ++ pframe += p2pielen; ++ pattrib->pktlen += p2pielen; ++ } ++ ++#ifdef CONFIG_WFD ++#ifdef CONFIG_IOCTL_CFG80211 ++ if ( _TRUE == pwdinfo->wfd_info->wfd_enable ) ++#endif //CONFIG_IOCTL_CFG80211 ++ { ++ wfdielen = build_probe_resp_wfd_ie(pwdinfo, pframe, 0); ++ pframe += wfdielen; ++ pattrib->pktlen += wfdielen; ++ } ++#ifdef CONFIG_IOCTL_CFG80211 ++ else if (pmlmepriv->wfd_probe_resp_ie != NULL && pmlmepriv->wfd_probe_resp_ie_len>0) ++ { ++ //WFD IE ++ _rtw_memcpy(pframe, pmlmepriv->wfd_probe_resp_ie, pmlmepriv->wfd_probe_resp_ie_len); ++ pattrib->pktlen += pmlmepriv->wfd_probe_resp_ie_len; ++ pframe += pmlmepriv->wfd_probe_resp_ie_len; ++ } ++#endif //CONFIG_IOCTL_CFG80211 ++#endif //CONFIG_WFD ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++ return; ++ ++} ++ ++int _issue_probereq_p2p(_adapter *padapter, u8 *da, int wait_ack) ++{ ++ int ret = _FAIL; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ unsigned char *mac; ++ unsigned char bssrate[NumRates]; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ int bssrate_len = 0; ++ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); ++ u8 wpsie[255] = { 0x00 }, p2pie[ 255 ] = { 0x00 }; ++ u16 wpsielen = 0, p2pielen = 0; ++#ifdef CONFIG_WFD ++ u32 wfdielen = 0; ++#endif //CONFIG_WFD ++ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ goto exit; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ mac = myid(&(padapter->eeprompriv)); ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ if (da) { ++ _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, da, ETH_ALEN); ++ } else { ++ if ( ( pwdinfo->p2p_info.scan_op_ch_only ) || ( pwdinfo->rx_invitereq_info.scan_op_ch_only ) ) ++ { ++ // This two flags will be set when this is only the P2P client mode. ++ _rtw_memcpy(pwlanhdr->addr1, pwdinfo->p2p_peer_interface_addr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, pwdinfo->p2p_peer_interface_addr, ETH_ALEN); ++ } ++ else ++ { ++ // broadcast probe request frame ++ _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN); ++ } ++ } ++ _rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_PROBEREQ); ++ ++ pframe += sizeof (struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof (struct rtw_ieee80211_hdr_3addr); ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) ++ { ++ pframe = rtw_set_ie(pframe, _SSID_IE_, pwdinfo->tx_prov_disc_info.ssid.SsidLength, pwdinfo->tx_prov_disc_info.ssid.Ssid, &(pattrib->pktlen)); ++ } ++ else ++ { ++ pframe = rtw_set_ie(pframe, _SSID_IE_, P2P_WILDCARD_SSID_LEN, pwdinfo->p2p_wildcard_ssid, &(pattrib->pktlen)); ++ } ++ // Use the OFDM rate in the P2P probe request frame. ( 6(B), 9(B), 12(B), 24(B), 36, 48, 54 ) ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pwdinfo->support_rate, &pattrib->pktlen); ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if(wdev_to_priv(padapter->rtw_wdev)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ { ++ if( pmlmepriv->wps_probe_req_ie != NULL && pmlmepriv->p2p_probe_req_ie != NULL ) ++ { ++ //WPS IE ++ _rtw_memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len); ++ pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; ++ pframe += pmlmepriv->wps_probe_req_ie_len; ++ ++ //P2P IE ++ _rtw_memcpy(pframe, pmlmepriv->p2p_probe_req_ie, pmlmepriv->p2p_probe_req_ie_len); ++ pattrib->pktlen += pmlmepriv->p2p_probe_req_ie_len; ++ pframe += pmlmepriv->p2p_probe_req_ie_len; ++ } ++ } ++ else ++#endif //CONFIG_IOCTL_CFG80211 ++ { ++ ++ // WPS IE ++ // Noted by Albert 20110221 ++ // According to the WPS specification, all the WPS attribute is presented by Big Endian. ++ ++ wpsielen = 0; ++ // WPS OUI ++ *(u32*) ( wpsie ) = cpu_to_be32( WPSOUI ); ++ wpsielen += 4; ++ ++ // WPS version ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_VER1 ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0001 ); ++ wpsielen += 2; ++ ++ // Value: ++ wpsie[wpsielen++] = WPS_VERSION_1; // Version 1.0 ++ ++ if( pmlmepriv->wps_probe_req_ie == NULL ) ++ { ++ // UUID-E ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_UUID_E ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0010 ); ++ wpsielen += 2; ++ ++ // Value: ++ if (pwdinfo->external_uuid == 0) { ++ _rtw_memset( wpsie + wpsielen, 0x0, 16 ); ++ _rtw_memcpy( wpsie + wpsielen, myid( &padapter->eeprompriv ), ETH_ALEN ); ++ } else { ++ _rtw_memcpy( wpsie + wpsielen, pwdinfo->uuid, 0x10 ); ++ } ++ wpsielen += 0x10; ++ ++ // Config Method ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_CONF_METHOD ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0002 ); ++ wpsielen += 2; ++ ++ // Value: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( pwdinfo->supported_wps_cm ); ++ wpsielen += 2; ++ } ++ ++ // Device Name ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_DEVICE_NAME ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( pwdinfo->device_name_len ); ++ wpsielen += 2; ++ ++ // Value: ++ _rtw_memcpy( wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len ); ++ wpsielen += pwdinfo->device_name_len; ++ ++ // Primary Device Type ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_PRIMARY_DEV_TYPE ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0008 ); ++ wpsielen += 2; ++ ++ // Value: ++ // Category ID ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_PDT_CID_RTK_WIDI ); ++ wpsielen += 2; ++ ++ // OUI ++ *(u32*) ( wpsie + wpsielen ) = cpu_to_be32( WPSOUI ); ++ wpsielen += 4; ++ ++ // Sub Category ID ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_PDT_SCID_RTK_DMP ); ++ wpsielen += 2; ++ ++ // Device Password ID ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_DEVICE_PWID ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0002 ); ++ wpsielen += 2; ++ ++ // Value: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_DPID_REGISTRAR_SPEC ); // Registrar-specified ++ wpsielen += 2; ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen ); ++ ++ // P2P OUI ++ p2pielen = 0; ++ p2pie[ p2pielen++ ] = 0x50; ++ p2pie[ p2pielen++ ] = 0x6F; ++ p2pie[ p2pielen++ ] = 0x9A; ++ p2pie[ p2pielen++ ] = 0x09; // WFA P2P v1.0 ++ ++ // Commented by Albert 20110221 ++ // According to the P2P Specification, the probe request frame should contain 5 P2P attributes ++ // 1. P2P Capability ++ // 2. P2P Device ID if this probe request wants to find the specific P2P device ++ // 3. Listen Channel ++ // 4. Extended Listen Timing ++ // 5. Operating Channel if this WiFi is working as the group owner now ++ ++ // P2P Capability ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_CAPABILITY; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Device Capability Bitmap, 1 byte ++ p2pie[ p2pielen++ ] = DMP_P2P_DEVCAP_SUPPORT; ++ ++ // Group Capability Bitmap, 1 byte ++ if ( pwdinfo->persistent_supported ) ++ p2pie[ p2pielen++ ] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; ++ else ++ p2pie[ p2pielen++ ] = DMP_P2P_GRPCAP_SUPPORT; ++ ++ // Listen Channel ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_LISTEN_CH; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0005 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Country String ++ p2pie[ p2pielen++ ] = 'X'; ++ p2pie[ p2pielen++ ] = 'X'; ++ ++ // The third byte should be set to 0x04. ++ // Described in the "Operating Channel Attribute" section. ++ p2pie[ p2pielen++ ] = 0x04; ++ ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x51; // Copy from SD7 ++ ++ // Channel Number ++ p2pie[ p2pielen++ ] = pwdinfo->listen_channel; // listen channel ++ ++ ++ // Extended Listen Timing ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_EX_LISTEN_TIMING; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0004 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Availability Period ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0xFFFF ); ++ p2pielen += 2; ++ ++ // Availability Interval ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0xFFFF ); ++ p2pielen += 2; ++ ++ if ( rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) ) ++ { ++ // Operating Channel (if this WiFi is working as the group owner now) ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_OPERATING_CH; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0005 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Country String ++ p2pie[ p2pielen++ ] = 'X'; ++ p2pie[ p2pielen++ ] = 'X'; ++ ++ // The third byte should be set to 0x04. ++ // Described in the "Operating Channel Attribute" section. ++ p2pie[ p2pielen++ ] = 0x04; ++ ++ // Operating Class ++ p2pie[ p2pielen++ ] = 0x51; // Copy from SD7 ++ ++ // Channel Number ++ p2pie[ p2pielen++ ] = pwdinfo->operating_channel; // operating channel number ++ ++ } ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen ); ++ ++ if( pmlmepriv->wps_probe_req_ie != NULL ) ++ { ++ //WPS IE ++ _rtw_memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len); ++ pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; ++ pframe += pmlmepriv->wps_probe_req_ie_len; ++ } ++ } ++ ++#ifdef CONFIG_WFD ++#ifdef CONFIG_IOCTL_CFG80211 ++ if ( _TRUE == pwdinfo->wfd_info->wfd_enable ) ++#endif ++ { ++ wfdielen = build_probe_req_wfd_ie(pwdinfo, pframe); ++ pframe += wfdielen; ++ pattrib->pktlen += wfdielen; ++ } ++#ifdef CONFIG_IOCTL_CFG80211 ++ else if (pmlmepriv->wfd_probe_req_ie != NULL && pmlmepriv->wfd_probe_req_ie_len>0) ++ { ++ //WFD IE ++ _rtw_memcpy(pframe, pmlmepriv->wfd_probe_req_ie, pmlmepriv->wfd_probe_req_ie_len); ++ pattrib->pktlen += pmlmepriv->wfd_probe_req_ie_len; ++ pframe += pmlmepriv->wfd_probe_req_ie_len; ++ } ++#endif //CONFIG_IOCTL_CFG80211 ++#endif //CONFIG_WFD ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("issuing probe_req, tx_len=%d\n", pattrib->last_txcmdsz)); ++ ++ if (wait_ack) { ++ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); ++ } else { ++ dump_mgntframe(padapter, pmgntframe); ++ ret = _SUCCESS; ++ } ++ ++exit: ++ return ret; ++} ++ ++inline void issue_probereq_p2p(_adapter *adapter, u8 *da) ++{ ++ _issue_probereq_p2p(adapter, da, _FALSE); ++} ++ ++int issue_probereq_p2p_ex(_adapter *adapter, u8 *da, int try_cnt, int wait_ms) ++{ ++ int ret; ++ int i = 0; ++ u32 start = rtw_get_current_time(); ++ ++ do ++ { ++ ret = _issue_probereq_p2p(adapter, da, wait_ms>0?_TRUE:_FALSE); ++ ++ i++; ++ ++ if (adapter->bDriverStopped || adapter->bSurpriseRemoved) ++ break; ++ ++ if(i < try_cnt && wait_ms > 0 && ret==_FAIL) ++ rtw_msleep_os(wait_ms); ++ ++ }while((iu.hdr.adapter; ++ struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv); ++ u8 *frame = recv_frame->u.hdr.rx_data; ++ u16 seq_ctrl = ( (recv_frame->u.hdr.attrib.seq_num&0xffff) << 4) | ++ (recv_frame->u.hdr.attrib.frag_num & 0xf); ++ ++ if (GetRetry(frame)) { ++ if (token >= 0) { ++ if ((seq_ctrl == mlmeext->action_public_rxseq) ++ && (token == mlmeext->action_public_dialog_token)) ++ { ++ DBG_871X(FUNC_ADPT_FMT" seq_ctrl=0x%x, rxseq=0x%x, token:%d\n", ++ FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq, token); ++ return _FAIL; ++ } ++ } else { ++ if (seq_ctrl == mlmeext->action_public_rxseq) { ++ DBG_871X(FUNC_ADPT_FMT" seq_ctrl=0x%x, rxseq=0x%x\n", ++ FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq); ++ return _FAIL; ++ } ++ } ++ } ++ ++ mlmeext->action_public_rxseq = seq_ctrl; ++ ++ if (token >= 0) ++ mlmeext->action_public_dialog_token = token; ++ ++ return _SUCCESS; ++} ++ ++unsigned int on_action_public_p2p(union recv_frame *precv_frame) ++{ ++ _adapter *padapter = precv_frame->u.hdr.adapter; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint len = precv_frame->u.hdr.len; ++ u8 *frame_body; ++ u8 dialogToken=0; ++#ifdef CONFIG_P2P ++ u8 *p2p_ie; ++ u32 p2p_ielen, wps_ielen; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ u8 result = P2P_STATUS_SUCCESS; ++ u8 empty_addr[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ++ u8 *merged_p2pie = NULL; ++ u32 merged_p2p_ielen = 0; ++#endif //CONFIG_P2P ++ ++ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ ++ dialogToken = frame_body[7]; ++ ++ if (rtw_action_public_decache(precv_frame, dialogToken) == _FAIL) ++ return _FAIL; ++ ++#ifdef CONFIG_P2P ++ _cancel_timer_ex( &pwdinfo->reset_ch_sitesurvey ); ++#ifdef CONFIG_IOCTL_CFG80211 ++ if(wdev_to_priv(padapter->rtw_wdev)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211) ++ { ++ rtw_cfg80211_rx_p2p_action_public(padapter, pframe, len); ++ } ++ else ++#endif //CONFIG_IOCTL_CFG80211 ++ { ++ // Do nothing if the driver doesn't enable the P2P function. ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) ++ return _SUCCESS; ++ ++ len -= sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ switch( frame_body[ 6 ] )//OUI Subtype ++ { ++ case P2P_GO_NEGO_REQ: ++ { ++ DBG_871X( "[%s] Got GO Nego Req Frame\n", __FUNCTION__); ++ _rtw_memset( &pwdinfo->groupid_info, 0x00, sizeof( struct group_id_info ) ); ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ)) ++ { ++ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); ++ } ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) ++ { ++ // Commented by Albert 20110526 ++ // In this case, this means the previous nego fail doesn't be reset yet. ++ _cancel_timer_ex( &pwdinfo->restore_p2p_state_timer ); ++ // Restore the previous p2p state ++ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); ++ DBG_871X( "[%s] Restore the previous p2p state to %d\n", __FUNCTION__, rtw_p2p_state(pwdinfo) ); ++ } ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ _cancel_timer_ex( &pwdinfo->ap_p2p_switch_timer ); ++ } ++#endif // CONFIG_CONCURRENT_MODE ++ ++ // Commented by Kurt 20110902 ++ //Add if statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. ++ if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) ++ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); ++ ++ // Commented by Kurt 20120113 ++ // Get peer_dev_addr here if peer doesn't issue prov_disc frame. ++ if( _rtw_memcmp(pwdinfo->rx_prov_disc_info.peerDevAddr, empty_addr, ETH_ALEN) ); ++ _rtw_memcpy(pwdinfo->rx_prov_disc_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN); ++ ++ result = process_p2p_group_negotation_req( pwdinfo, frame_body, len ); ++ issue_p2p_GO_response( padapter, GetAddr2Ptr(pframe), frame_body, len, result ); ++#ifdef CONFIG_INTEL_WIDI ++ if( (padapter->mlmepriv.widi_state == INTEL_WIDI_STATE_LISTEN) && (padapter->mlmepriv.widi_state != INTEL_WIDI_STATE_WFD_CONNECTION) ) ++ { ++ padapter->mlmepriv.widi_state = INTEL_WIDI_STATE_WFD_CONNECTION; ++ _cancel_timer_ex(&(padapter->mlmepriv.listen_timer)); ++ intel_widi_wk_cmd(padapter, INTEL_WIDI_LISTEN_STOP_WK, NULL); ++ } ++#endif //CONFIG_INTEL_WIDI ++ ++ // Commented by Albert 20110718 ++ // No matter negotiating or negotiation failure, the driver should set up the restore P2P state timer. ++#ifdef CONFIG_CONCURRENT_MODE ++ // Commented by Albert 20120107 ++ _set_timer( &pwdinfo->restore_p2p_state_timer, 3000 ); ++#else // CONFIG_CONCURRENT_MODE ++ _set_timer( &pwdinfo->restore_p2p_state_timer, 5000 ); ++#endif // CONFIG_CONCURRENT_MODE ++ break; ++ } ++ case P2P_GO_NEGO_RESP: ++ { ++ DBG_871X( "[%s] Got GO Nego Resp Frame\n", __FUNCTION__); ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) ++ { ++ // Commented by Albert 20110425 ++ // The restore timer is enabled when issuing the nego request frame of rtw_p2p_connect function. ++ _cancel_timer_ex( &pwdinfo->restore_p2p_state_timer ); ++ pwdinfo->nego_req_info.benable = _FALSE; ++ result = process_p2p_group_negotation_resp( pwdinfo, frame_body, len); ++ issue_p2p_GO_confirm( pwdinfo->padapter, GetAddr2Ptr(pframe), result); ++ if ( P2P_STATUS_SUCCESS == result ) ++ { ++ if ( rtw_p2p_role(pwdinfo) == P2P_ROLE_CLIENT ) ++ { ++ pwdinfo->p2p_info.operation_ch[ 0 ] = pwdinfo->peer_operating_ch; ++ #ifdef P2P_OP_CHECK_SOCIAL_CH ++ pwdinfo->p2p_info.operation_ch[ 1 ] = 1; //Check whether GO is operating in channel 1; ++ pwdinfo->p2p_info.operation_ch[ 2 ] = 6; //Check whether GO is operating in channel 6; ++ pwdinfo->p2p_info.operation_ch[ 3 ] = 11; //Check whether GO is operating in channel 11; ++ #endif //P2P_OP_CHECK_SOCIAL_CH ++ pwdinfo->p2p_info.scan_op_ch_only = 1; ++ _set_timer( &pwdinfo->reset_ch_sitesurvey2, P2P_RESET_SCAN_CH ); ++ } ++ } ++ ++ // Reset the dialog token for group negotiation frames. ++ pwdinfo->negotiation_dialog_token = 1; ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) ++ { ++ _set_timer( &pwdinfo->restore_p2p_state_timer, 5000 ); ++ } ++ } ++ else ++ { ++ DBG_871X( "[%s] Skipped GO Nego Resp Frame (p2p_state != P2P_STATE_GONEGO_ING)\n", __FUNCTION__); ++ } ++ ++ break; ++ } ++ case P2P_GO_NEGO_CONF: ++ { ++ DBG_871X( "[%s] Got GO Nego Confirm Frame\n", __FUNCTION__); ++ result = process_p2p_group_negotation_confirm( pwdinfo, frame_body, len); ++ if ( P2P_STATUS_SUCCESS == result ) ++ { ++ if ( rtw_p2p_role(pwdinfo) == P2P_ROLE_CLIENT ) ++ { ++ pwdinfo->p2p_info.operation_ch[ 0 ] = pwdinfo->peer_operating_ch; ++ #ifdef P2P_OP_CHECK_SOCIAL_CH ++ pwdinfo->p2p_info.operation_ch[ 1 ] = 1; //Check whether GO is operating in channel 1; ++ pwdinfo->p2p_info.operation_ch[ 2 ] = 6; //Check whether GO is operating in channel 6; ++ pwdinfo->p2p_info.operation_ch[ 3 ] = 11; //Check whether GO is operating in channel 11; ++ #endif //P2P_OP_CHECK_SOCIAL_CH ++ pwdinfo->p2p_info.scan_op_ch_only = 1; ++ _set_timer( &pwdinfo->reset_ch_sitesurvey2, P2P_RESET_SCAN_CH ); ++ } ++ } ++ break; ++ } ++ case P2P_INVIT_REQ: ++ { ++ // Added by Albert 2010/10/05 ++ // Received the P2P Invite Request frame. ++ ++ DBG_871X( "[%s] Got invite request frame!\n", __FUNCTION__ ); ++ if ( (p2p_ie=rtw_get_p2p_ie( frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen)) ) ++ { ++ // Parse the necessary information from the P2P Invitation Request frame. ++ // For example: The MAC address of sending this P2P Invitation Request frame. ++ u32 attr_contentlen = 0; ++ u8 status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; ++ struct group_id_info group_id; ++ u8 invitation_flag = 0; ++ ++ ++ merged_p2p_ielen = rtw_get_p2p_merged_ies_len(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_); ++ ++ merged_p2pie = rtw_zmalloc(merged_p2p_ielen + 2); // 2 is for EID and Length ++ if (merged_p2pie == NULL) ++ { ++ DBG_871X( "[%s] Malloc p2p ie fail\n", __FUNCTION__); ++ goto exit; ++ } ++ _rtw_memset(merged_p2pie, 0x00, merged_p2p_ielen); ++ ++ merged_p2p_ielen = rtw_p2p_merge_ies(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, merged_p2pie); ++ ++ rtw_get_p2p_attr_content( merged_p2pie, merged_p2p_ielen, P2P_ATTR_INVITATION_FLAGS, &invitation_flag, &attr_contentlen); ++ if ( attr_contentlen ) ++ { ++ ++ rtw_get_p2p_attr_content( merged_p2pie, merged_p2p_ielen, P2P_ATTR_GROUP_BSSID, pwdinfo->p2p_peer_interface_addr, &attr_contentlen); ++ // Commented by Albert 20120510 ++ // Copy to the pwdinfo->p2p_peer_interface_addr. ++ // So that the WFD UI ( or Sigma ) can get the peer interface address by using the following command. ++ // #> iwpriv wlan0 p2p_get peer_ifa ++ // After having the peer interface address, the sigma can find the correct conf file for wpa_supplicant. ++ ++ if ( attr_contentlen ) ++ { ++ DBG_871X( "[%s] GO's BSSID = %.2X %.2X %.2X %.2X %.2X %.2X\n", __FUNCTION__, ++ pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], ++ pwdinfo->p2p_peer_interface_addr[2], pwdinfo->p2p_peer_interface_addr[3], ++ pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5] ); ++ } ++ ++ if ( invitation_flag & P2P_INVITATION_FLAGS_PERSISTENT ) ++ { ++ // Re-invoke the persistent group. ++ ++ _rtw_memset( &group_id, 0x00, sizeof( struct group_id_info ) ); ++ rtw_get_p2p_attr_content( merged_p2pie, merged_p2p_ielen, P2P_ATTR_GROUP_ID, ( u8* ) &group_id, &attr_contentlen); ++ if ( attr_contentlen ) ++ { ++ if ( _rtw_memcmp( group_id.go_device_addr, myid( &padapter->eeprompriv ), ETH_ALEN ) ) ++ { ++ // The p2p device sending this p2p invitation request wants this Wi-Fi device to be the persistent GO. ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_GO ); ++ rtw_p2p_set_role( pwdinfo, P2P_ROLE_GO ); ++ status_code = P2P_STATUS_SUCCESS; ++ } ++ else ++ { ++ // The p2p device sending this p2p invitation request wants to be the persistent GO. ++ if ( is_matched_in_profilelist( pwdinfo->p2p_peer_interface_addr, &pwdinfo->profileinfo[ 0 ] ) ) ++ { ++ u8 operatingch_info[5] = { 0x00 }; ++ ++ if ( rtw_get_p2p_attr_content(merged_p2pie, merged_p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen) ) ++ { ++ if( rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, (u32)operatingch_info[4] ) ) ++ { ++ // The operating channel is acceptable for this device. ++ pwdinfo->rx_invitereq_info.operation_ch[0]= operatingch_info[4]; ++ #ifdef P2P_OP_CHECK_SOCIAL_CH ++ pwdinfo->rx_invitereq_info.operation_ch[1]= 1; //Check whether GO is operating in channel 1; ++ pwdinfo->rx_invitereq_info.operation_ch[2]= 6; //Check whether GO is operating in channel 6; ++ pwdinfo->rx_invitereq_info.operation_ch[3]= 11; //Check whether GO is operating in channel 11; ++ #endif //P2P_OP_CHECK_SOCIAL_CH ++ pwdinfo->rx_invitereq_info.scan_op_ch_only = 1; ++ _set_timer( &pwdinfo->reset_ch_sitesurvey, P2P_RESET_SCAN_CH ); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH ); ++ rtw_p2p_set_role( pwdinfo, P2P_ROLE_CLIENT ); ++ status_code = P2P_STATUS_SUCCESS; ++ } ++ else ++ { ++ // The operating channel isn't supported by this device. ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH ); ++ rtw_p2p_set_role( pwdinfo, P2P_ROLE_DEVICE ); ++ status_code = P2P_STATUS_FAIL_NO_COMMON_CH; ++ _set_timer( &pwdinfo->restore_p2p_state_timer, 3000 ); ++ } ++ } ++ else ++ { ++ // Commented by Albert 20121130 ++ // Intel will use the different P2P IE to store the operating channel information ++ // Workaround for Intel WiDi 3.5 ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH ); ++ rtw_p2p_set_role( pwdinfo, P2P_ROLE_CLIENT ); ++ status_code = P2P_STATUS_SUCCESS; ++ } ++ } ++ else ++ { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH ); ++ #ifdef CONFIG_INTEL_WIDI ++ _rtw_memcpy( pwdinfo->p2p_peer_device_addr, group_id.go_device_addr , ETH_ALEN ); ++ rtw_p2p_set_role( pwdinfo, P2P_ROLE_CLIENT ); ++ #endif //CONFIG_INTEL_WIDI ++ ++ status_code = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP; ++ } ++ } ++ } ++ else ++ { ++ DBG_871X( "[%s] P2P Group ID Attribute NOT FOUND!\n", __FUNCTION__ ); ++ status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; ++ } ++ } ++ else ++ { ++ // Received the invitation to join a P2P group. ++ ++ _rtw_memset( &group_id, 0x00, sizeof( struct group_id_info ) ); ++ rtw_get_p2p_attr_content( merged_p2pie, merged_p2p_ielen, P2P_ATTR_GROUP_ID, ( u8* ) &group_id, &attr_contentlen); ++ if ( attr_contentlen ) ++ { ++ if ( _rtw_memcmp( group_id.go_device_addr, myid( &padapter->eeprompriv ), ETH_ALEN ) ) ++ { ++ // In this case, the GO can't be myself. ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH ); ++ status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; ++ } ++ else ++ { ++ // The p2p device sending this p2p invitation request wants to join an existing P2P group ++ // Commented by Albert 2012/06/28 ++ // In this case, this Wi-Fi device should use the iwpriv command to get the peer device address. ++ // The peer device address should be the destination address for the provisioning discovery request. ++ // Then, this Wi-Fi device should use the iwpriv command to get the peer interface address. ++ // The peer interface address should be the address for WPS mac address ++ _rtw_memcpy( pwdinfo->p2p_peer_device_addr, group_id.go_device_addr , ETH_ALEN ); ++ rtw_p2p_set_role( pwdinfo, P2P_ROLE_CLIENT ); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_JOIN ); ++ status_code = P2P_STATUS_SUCCESS; ++ } ++ } ++ else ++ { ++ DBG_871X( "[%s] P2P Group ID Attribute NOT FOUND!\n", __FUNCTION__ ); ++ status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; ++ } ++ } ++ } ++ else ++ { ++ DBG_871X( "[%s] P2P Invitation Flags Attribute NOT FOUND!\n", __FUNCTION__ ); ++ status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; ++ } ++ ++ DBG_871X( "[%s] status_code = %d\n", __FUNCTION__, status_code ); ++ ++ pwdinfo->inviteresp_info.token = frame_body[ 7 ]; ++ issue_p2p_invitation_response( padapter, GetAddr2Ptr(pframe), pwdinfo->inviteresp_info.token, status_code ); ++ _set_timer( &pwdinfo->restore_p2p_state_timer, 3000 ); ++ } ++#ifdef CONFIG_INTEL_WIDI ++ if( (padapter->mlmepriv.widi_state == INTEL_WIDI_STATE_LISTEN) && (padapter->mlmepriv.widi_state != INTEL_WIDI_STATE_WFD_CONNECTION) ) ++ { ++ padapter->mlmepriv.widi_state = INTEL_WIDI_STATE_WFD_CONNECTION; ++ _cancel_timer_ex(&(padapter->mlmepriv.listen_timer)); ++ intel_widi_wk_cmd(padapter, INTEL_WIDI_LISTEN_STOP_WK, NULL); ++ } ++#endif //CONFIG_INTEL_WIDI ++ break; ++ } ++ case P2P_INVIT_RESP: ++ { ++ u8 attr_content = 0x00; ++ u32 attr_contentlen = 0; ++ ++ DBG_871X( "[%s] Got invite response frame!\n", __FUNCTION__ ); ++ _cancel_timer_ex( &pwdinfo->restore_p2p_state_timer ); ++ if ( (p2p_ie=rtw_get_p2p_ie( frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen)) ) ++ { ++ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); ++ ++ if ( attr_contentlen == 1 ) ++ { ++ DBG_871X( "[%s] Status = %d\n", __FUNCTION__, attr_content ); ++ pwdinfo->invitereq_info.benable = _FALSE; ++ ++ if ( attr_content == P2P_STATUS_SUCCESS ) ++ { ++ if ( _rtw_memcmp( pwdinfo->invitereq_info.go_bssid, myid( &padapter->eeprompriv ), ETH_ALEN )) ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO ); ++ } ++ else ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ } ++ rtw_p2p_set_state( pwdinfo, P2P_STATE_RX_INVITE_RESP_OK ); ++ } ++ else ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ rtw_p2p_set_state( pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL ); ++ } ++ } ++ else ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ rtw_p2p_set_state( pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL ); ++ } ++ } ++ else ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ rtw_p2p_set_state( pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL ); ++ } ++ ++ if ( rtw_p2p_chk_state( pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL ) ) ++ { ++ _set_timer( &pwdinfo->restore_p2p_state_timer, 5000 ); ++ } ++ break; ++ } ++ case P2P_DEVDISC_REQ: ++ ++ process_p2p_devdisc_req(pwdinfo, pframe, len); ++ ++ break; ++ ++ case P2P_DEVDISC_RESP: ++ ++ process_p2p_devdisc_resp(pwdinfo, pframe, len); ++ ++ break; ++ ++ case P2P_PROVISION_DISC_REQ: ++ DBG_871X( "[%s] Got Provisioning Discovery Request Frame\n", __FUNCTION__ ); ++ process_p2p_provdisc_req(pwdinfo, pframe, len); ++ _rtw_memcpy(pwdinfo->rx_prov_disc_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN); ++ ++ //20110902 Kurt ++ //Add the following statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. ++ if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ)) ++ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); ++ ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ); ++ _set_timer( &pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT ); ++#ifdef CONFIG_INTEL_WIDI ++ if( (padapter->mlmepriv.widi_state == INTEL_WIDI_STATE_LISTEN) && (padapter->mlmepriv.widi_state != INTEL_WIDI_STATE_WFD_CONNECTION) ) ++ { ++ padapter->mlmepriv.widi_state = INTEL_WIDI_STATE_WFD_CONNECTION; ++ _cancel_timer_ex(&(padapter->mlmepriv.listen_timer)); ++ intel_widi_wk_cmd(padapter, INTEL_WIDI_LISTEN_STOP_WK, NULL); ++ } ++#endif //CONFIG_INTEL_WIDI ++ break; ++ ++ case P2P_PROVISION_DISC_RESP: ++ // Commented by Albert 20110707 ++ // Should we check the pwdinfo->tx_prov_disc_info.bsent flag here?? ++ DBG_871X( "[%s] Got Provisioning Discovery Response Frame\n", __FUNCTION__ ); ++ // Commented by Albert 20110426 ++ // The restore timer is enabled when issuing the provisioing request frame in rtw_p2p_prov_disc function. ++ _cancel_timer_ex( &pwdinfo->restore_p2p_state_timer ); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_RSP); ++ process_p2p_provdisc_resp(pwdinfo, pframe); ++ _set_timer( &pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT ); ++ break; ++ ++ } ++ } ++#endif //CONFIG_P2P ++ ++exit: ++ ++#ifdef CONFIG_P2P ++ if(merged_p2pie) ++ { ++ rtw_mfree(merged_p2pie, merged_p2p_ielen + 2); ++ } ++#endif ++ return _SUCCESS; ++} ++ ++unsigned int on_action_public_vendor(union recv_frame *precv_frame) ++{ ++ unsigned int ret = _FAIL; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint frame_len = precv_frame->u.hdr.len; ++ u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ if (_rtw_memcmp(frame_body + 2, P2P_OUI, 4) == _TRUE) { ++ ret = on_action_public_p2p(precv_frame); ++ } ++ ++ return ret; ++} ++ ++unsigned int on_action_public_default(union recv_frame *precv_frame, u8 action) ++{ ++ unsigned int ret = _FAIL; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint frame_len = precv_frame->u.hdr.len; ++ u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); ++ u8 token; ++ _adapter *adapter = precv_frame->u.hdr.adapter; ++ int cnt = 0; ++ char msg[64]; ++ ++ token = frame_body[2]; ++ ++ if (rtw_action_public_decache(precv_frame, token) == _FAIL) ++ goto exit; ++ ++ #ifdef CONFIG_IOCTL_CFG80211 ++ cnt += sprintf((msg+cnt), "%s(token:%u)", action_public_str(action), token); ++ rtw_cfg80211_rx_action(adapter, pframe, frame_len, msg); ++ #endif ++ ++ ret = _SUCCESS; ++ ++exit: ++ return ret; ++} ++ ++unsigned int on_action_public(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ unsigned int ret = _FAIL; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint frame_len = precv_frame->u.hdr.len; ++ u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); ++ u8 category, action; ++ ++ /* check RA matches or not */ ++ if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN)) ++ goto exit; ++ ++ category = frame_body[0]; ++ if(category != RTW_WLAN_CATEGORY_PUBLIC) ++ goto exit; ++ ++ action = frame_body[1]; ++ switch (action) { ++ case ACT_PUBLIC_VENDOR: ++ ret = on_action_public_vendor(precv_frame); ++ break; ++ default: ++ ret = on_action_public_default(precv_frame, action); ++ break; ++ } ++ ++exit: ++ return ret; ++} ++ ++unsigned int OnAction_ht(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ return _SUCCESS; ++} ++ ++#ifdef CONFIG_IEEE80211W ++unsigned int OnAction_sa_query(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ unsigned short tid; ++ //Baron ++ ++ DBG_871X("OnAction_sa_query\n"); ++ ++ switch (pframe[WLAN_HDR_A3_LEN+1]) ++ { ++ case 0: //SA Query req ++ _rtw_memcpy(&tid, &pframe[WLAN_HDR_A3_LEN+2], sizeof(unsigned short)); ++ DBG_871X("OnAction_sa_query request,action=%d, tid=%04x\n", pframe[WLAN_HDR_A3_LEN+1], tid); ++ issue_action_SA_Query(padapter, GetAddr2Ptr(pframe), 1, tid); ++ break; ++ ++ case 1: //SA Query rsp ++ _cancel_timer_ex(&pmlmeext->sa_query_timer); ++ DBG_871X("OnAction_sa_query response,action=%d, tid=%04x, cahcel timer\n", pframe[WLAN_HDR_A3_LEN+1], pframe[WLAN_HDR_A3_LEN+2]); ++ break; ++ default: ++ break; ++ } ++ if(0) ++ { ++ int pp; ++ printk("pattrib->pktlen = %d =>", pattrib->pkt_len); ++ for(pp=0;pp< pattrib->pkt_len; pp++) ++ printk(" %02x ", pframe[pp]); ++ printk("\n"); ++ } ++ ++ return _SUCCESS; ++} ++#endif //CONFIG_IEEE80211W ++ ++unsigned int OnAction_wmm(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ return _SUCCESS; ++} ++ ++unsigned int OnAction_p2p(_adapter *padapter, union recv_frame *precv_frame) ++{ ++#ifdef CONFIG_P2P ++ u8 *frame_body; ++ u8 category, OUI_Subtype, dialogToken=0; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint len = precv_frame->u.hdr.len; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ //check RA matches or not ++ if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))//for if1, sta/ap mode ++ return _SUCCESS; ++ ++ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ ++ category = frame_body[0]; ++ if(category != RTW_WLAN_CATEGORY_P2P) ++ return _SUCCESS; ++ ++ if ( cpu_to_be32( *( ( u32* ) ( frame_body + 1 ) ) ) != P2POUI ) ++ return _SUCCESS; ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if(wdev_to_priv(padapter->rtw_wdev)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ { ++ rtw_cfg80211_rx_action_p2p(padapter, pframe, len); ++ return _SUCCESS; ++ } ++ else ++#endif //CONFIG_IOCTL_CFG80211 ++ { ++ len -= sizeof(struct rtw_ieee80211_hdr_3addr); ++ OUI_Subtype = frame_body[5]; ++ dialogToken = frame_body[6]; ++ ++ switch(OUI_Subtype) ++ { ++ case P2P_NOTICE_OF_ABSENCE: ++ ++ break; ++ ++ case P2P_PRESENCE_REQUEST: ++ ++ process_p2p_presence_req(pwdinfo, pframe, len); ++ ++ break; ++ ++ case P2P_PRESENCE_RESPONSE: ++ ++ break; ++ ++ case P2P_GO_DISC_REQUEST: ++ ++ break; ++ ++ default: ++ break; ++ ++ } ++ } ++#endif //CONFIG_P2P ++ ++ return _SUCCESS; ++ ++} ++ ++unsigned int OnAction(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ int i; ++ unsigned char category; ++ struct action_handler *ptable; ++ unsigned char *frame_body; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ ++ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ ++ category = frame_body[0]; ++ ++ for(i = 0; i < sizeof(OnAction_tbl)/sizeof(struct action_handler); i++) ++ { ++ ptable = &OnAction_tbl[i]; ++ ++ if(category == ptable->num) ++ ptable->func(padapter, precv_frame); ++ ++ } ++ ++ return _SUCCESS; ++ ++} ++ ++unsigned int DoReserved(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ ++ //DBG_871X("rcvd mgt frame(%x, %x)\n", (GetFrameSubType(pframe) >> 4), *(unsigned int *)GetAddr1Ptr(pframe)); ++ return _SUCCESS; ++} ++ ++struct xmit_frame *_alloc_mgtxmitframe(struct xmit_priv *pxmitpriv, bool once) ++{ ++ struct xmit_frame *pmgntframe; ++ struct xmit_buf *pxmitbuf; ++ ++ if (once) ++ pmgntframe = rtw_alloc_xmitframe_once(pxmitpriv); ++ else ++ pmgntframe = rtw_alloc_xmitframe_ext(pxmitpriv); ++ ++ if (pmgntframe == NULL) { ++ DBG_871X(FUNC_ADPT_FMT" alloc xmitframe fail, once:%d\n", FUNC_ADPT_ARG(pxmitpriv->adapter), once); ++ goto exit; ++ } ++ ++ if ((pxmitbuf = rtw_alloc_xmitbuf_ext(pxmitpriv)) == NULL) { ++ DBG_871X(FUNC_ADPT_FMT" alloc xmitbuf fail\n", FUNC_ADPT_ARG(pxmitpriv->adapter)); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ pmgntframe = NULL; ++ goto exit; ++ } ++ ++ pmgntframe->frame_tag = MGNT_FRAMETAG; ++ pmgntframe->pxmitbuf = pxmitbuf; ++ pmgntframe->buf_addr = pxmitbuf->pbuf; ++ pxmitbuf->priv_data = pmgntframe; ++ ++exit: ++ return pmgntframe; ++ ++} ++ ++inline struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv) ++{ ++ return _alloc_mgtxmitframe(pxmitpriv, _FALSE); ++} ++ ++inline struct xmit_frame *alloc_mgtxmitframe_once(struct xmit_priv *pxmitpriv) ++{ ++ return _alloc_mgtxmitframe(pxmitpriv, _TRUE); ++} ++ ++ ++/**************************************************************************** ++ ++Following are some TX fuctions for WiFi MLME ++ ++*****************************************************************************/ ++ ++void update_mgnt_tx_rate(_adapter *padapter, u8 rate) ++{ ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ ++ pmlmeext->tx_rate = rate; ++ DBG_871X("%s(): rate = %x\n",__FUNCTION__, rate); ++} ++ ++void update_mgntframe_attrib(_adapter *padapter, struct pkt_attrib *pattrib) ++{ ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ ++ _rtw_memset((u8 *)(pattrib), 0, sizeof(struct pkt_attrib)); ++ ++ pattrib->hdrlen = 24; ++ pattrib->nr_frags = 1; ++ pattrib->priority = 7; ++ pattrib->mac_id = 0; ++ pattrib->qsel = 0x12; ++ ++ pattrib->pktlen = 0; ++ ++ if(pmlmeext->cur_wireless_mode & WIRELESS_11B) ++ pattrib->raid = 6;//b mode ++ else ++ pattrib->raid = 5;//a/g mode ++ ++ pattrib->encrypt = _NO_PRIVACY_; ++ pattrib->bswenc = _FALSE; ++ ++ pattrib->qos_en = _FALSE; ++ pattrib->ht_en = _FALSE; ++ pattrib->bwmode = HT_CHANNEL_WIDTH_20; ++ pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ pattrib->sgi = _FALSE; ++ ++ pattrib->seqnum = pmlmeext->mgnt_seq; ++ ++ pattrib->retry_ctrl = _TRUE; ++ ++} ++ ++void dump_mgntframe(_adapter *padapter, struct xmit_frame *pmgntframe) ++{ ++ if(padapter->bSurpriseRemoved == _TRUE || ++ padapter->bDriverStopped == _TRUE) ++ { ++ rtw_free_xmitbuf(&padapter->xmitpriv, pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(&padapter->xmitpriv, pmgntframe); ++ return; ++ } ++ ++ rtw_hal_mgnt_xmit(padapter, pmgntframe); ++} ++ ++s32 dump_mgntframe_and_wait(_adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms) ++{ ++ s32 ret = _FAIL; ++ _irqL irqL; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf; ++ struct submit_ctx sctx; ++ ++ if(padapter->bSurpriseRemoved == _TRUE || ++ padapter->bDriverStopped == _TRUE) ++ { ++ rtw_free_xmitbuf(&padapter->xmitpriv, pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(&padapter->xmitpriv, pmgntframe); ++ return ret; ++ } ++ ++ rtw_sctx_init(&sctx, timeout_ms); ++ pxmitbuf->sctx = &sctx; ++ ++ ret = rtw_hal_mgnt_xmit(padapter, pmgntframe); ++ ++ if (ret == _SUCCESS) ++ ret = rtw_sctx_wait(&sctx); ++ ++ _enter_critical(&pxmitpriv->lock_sctx, &irqL); ++ pxmitbuf->sctx = NULL; ++ _exit_critical(&pxmitpriv->lock_sctx, &irqL); ++ ++ return ret; ++} ++ ++s32 dump_mgntframe_and_wait_ack(_adapter *padapter, struct xmit_frame *pmgntframe) ++{ ++#ifdef CONFIG_XMIT_ACK ++ s32 ret = _FAIL; ++ u32 timeout_ms = 500;// 500ms ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ #ifdef CONFIG_CONCURRENT_MODE ++ if (padapter->pbuddy_adapter && !padapter->isprimary) ++ pxmitpriv = &(padapter->pbuddy_adapter->xmitpriv); ++ #endif ++ ++ if(padapter->bSurpriseRemoved == _TRUE || ++ padapter->bDriverStopped == _TRUE) ++ { ++ rtw_free_xmitbuf(&padapter->xmitpriv, pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(&padapter->xmitpriv, pmgntframe); ++ return -1; ++ } ++ ++ _enter_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL); ++ pxmitpriv->ack_tx = _TRUE; ++ ++ pmgntframe->ack_report = 1; ++ if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS) { ++ ret = rtw_ack_tx_wait(pxmitpriv, timeout_ms); ++ } ++ ++ pxmitpriv->ack_tx = _FALSE; ++ _exit_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL); ++ ++ return ret; ++#else //!CONFIG_XMIT_ACK ++ dump_mgntframe(padapter, pmgntframe); ++ rtw_msleep_os(50); ++ return _SUCCESS; ++#endif //!CONFIG_XMIT_ACK ++} ++ ++int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode) ++{ ++ u8 *ssid_ie; ++ sint ssid_len_ori; ++ int len_diff = 0; ++ ++ ssid_ie = rtw_get_ie(ies, WLAN_EID_SSID, &ssid_len_ori, ies_len); ++ ++ //DBG_871X("%s hidden_ssid_mode:%u, ssid_ie:%p, ssid_len_ori:%d\n", __FUNCTION__, hidden_ssid_mode, ssid_ie, ssid_len_ori); ++ ++ if(ssid_ie && ssid_len_ori>0) ++ { ++ switch(hidden_ssid_mode) ++ { ++ case 1: ++ { ++ u8 *next_ie = ssid_ie + 2 + ssid_len_ori; ++ u32 remain_len = 0; ++ ++ remain_len = ies_len -(next_ie-ies); ++ ++ ssid_ie[1] = 0; ++ _rtw_memcpy(ssid_ie+2, next_ie, remain_len); ++ len_diff -= ssid_len_ori; ++ ++ break; ++ } ++ case 2: ++ _rtw_memset(&ssid_ie[2], 0, ssid_len_ori); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return len_diff; ++} ++ ++void issue_beacon(_adapter *padapter, int timeout_ms) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ unsigned int rate_len; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++#if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) ++ _irqL irqL; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++#endif //#if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); ++ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); ++#endif //CONFIG_P2P ++ ++ ++ //DBG_871X("%s\n", __FUNCTION__); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ DBG_871X("%s, alloc mgnt frame fail\n", __FUNCTION__); ++ return; ++ } ++#if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) ++ _enter_critical_bh(&pmlmepriv->bcn_update_lock, &irqL); ++#endif //#if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->qsel = 0x10; ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); ++ //pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_BEACON); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof (struct rtw_ieee80211_hdr_3addr); ++ ++ if( (pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ { ++ //DBG_871X("ie len=%d\n", cur_network->IELength); ++#ifdef CONFIG_P2P ++ // for P2P : Primary Device Type & Device Name ++ u32 wpsielen=0, insert_len=0; ++ u8 *wpsie=NULL; ++ wpsie = rtw_get_wps_ie(cur_network->IEs+_FIXED_IE_LENGTH_, cur_network->IELength-_FIXED_IE_LENGTH_, NULL, &wpsielen); ++ ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && wpsie && wpsielen>0) ++ { ++ uint wps_offset, remainder_ielen; ++ u8 *premainder_ie, *pframe_wscie; ++ ++ wps_offset = (uint)(wpsie - cur_network->IEs); ++ ++ premainder_ie = wpsie + wpsielen; ++ ++ remainder_ielen = cur_network->IELength - wps_offset - wpsielen; ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if(wdev_to_priv(padapter->rtw_wdev)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ { ++ if(pmlmepriv->wps_beacon_ie && pmlmepriv->wps_beacon_ie_len>0) ++ { ++ _rtw_memcpy(pframe, cur_network->IEs, wps_offset); ++ pframe += wps_offset; ++ pattrib->pktlen += wps_offset; ++ ++ _rtw_memcpy(pframe, pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len); ++ pframe += pmlmepriv->wps_beacon_ie_len; ++ pattrib->pktlen += pmlmepriv->wps_beacon_ie_len; ++ ++ //copy remainder_ie to pframe ++ _rtw_memcpy(pframe, premainder_ie, remainder_ielen); ++ pframe += remainder_ielen; ++ pattrib->pktlen += remainder_ielen; ++ } ++ else ++ { ++ _rtw_memcpy(pframe, cur_network->IEs, cur_network->IELength); ++ pframe += cur_network->IELength; ++ pattrib->pktlen += cur_network->IELength; ++ } ++ } ++ else ++#endif //CONFIG_IOCTL_CFG80211 ++ { ++ pframe_wscie = pframe + wps_offset; ++ _rtw_memcpy(pframe, cur_network->IEs, wps_offset+wpsielen); ++ pframe += (wps_offset + wpsielen); ++ pattrib->pktlen += (wps_offset + wpsielen); ++ ++ //now pframe is end of wsc ie, insert Primary Device Type & Device Name ++ // Primary Device Type ++ // Type: ++ *(u16*) ( pframe + insert_len) = cpu_to_be16( WPS_ATTR_PRIMARY_DEV_TYPE ); ++ insert_len += 2; ++ ++ // Length: ++ *(u16*) ( pframe + insert_len ) = cpu_to_be16( 0x0008 ); ++ insert_len += 2; ++ ++ // Value: ++ // Category ID ++ *(u16*) ( pframe + insert_len ) = cpu_to_be16( WPS_PDT_CID_MULIT_MEDIA ); ++ insert_len += 2; ++ ++ // OUI ++ *(u32*) ( pframe + insert_len ) = cpu_to_be32( WPSOUI ); ++ insert_len += 4; ++ ++ // Sub Category ID ++ *(u16*) ( pframe + insert_len ) = cpu_to_be16( WPS_PDT_SCID_MEDIA_SERVER ); ++ insert_len += 2; ++ ++ ++ // Device Name ++ // Type: ++ *(u16*) ( pframe + insert_len ) = cpu_to_be16( WPS_ATTR_DEVICE_NAME ); ++ insert_len += 2; ++ ++ // Length: ++ *(u16*) ( pframe + insert_len ) = cpu_to_be16( pwdinfo->device_name_len ); ++ insert_len += 2; ++ ++ // Value: ++ _rtw_memcpy( pframe + insert_len, pwdinfo->device_name, pwdinfo->device_name_len ); ++ insert_len += pwdinfo->device_name_len; ++ ++ ++ //update wsc ie length ++ *(pframe_wscie+1) = (wpsielen -2) + insert_len; ++ ++ //pframe move to end ++ pframe+=insert_len; ++ pattrib->pktlen += insert_len; ++ ++ //copy remainder_ie to pframe ++ _rtw_memcpy(pframe, premainder_ie, remainder_ielen); ++ pframe += remainder_ielen; ++ pattrib->pktlen += remainder_ielen; ++ } ++ } ++ else ++#endif //CONFIG_P2P ++ { ++ int len_diff; ++ _rtw_memcpy(pframe, cur_network->IEs, cur_network->IELength); ++ len_diff = update_hidden_ssid( ++ pframe+_BEACON_IE_OFFSET_ ++ , cur_network->IELength-_BEACON_IE_OFFSET_ ++ , pmlmeinfo->hidden_ssid_mode ++ ); ++ pframe += (cur_network->IELength+len_diff); ++ pattrib->pktlen += (cur_network->IELength+len_diff); ++ } ++ ++ { ++ u8 *wps_ie; ++ uint wps_ielen; ++ u8 sr = 0; ++ wps_ie = rtw_get_wps_ie(pmgntframe->buf_addr+TXDESC_OFFSET+sizeof (struct rtw_ieee80211_hdr_3addr)+_BEACON_IE_OFFSET_, ++ pattrib->pktlen-sizeof (struct rtw_ieee80211_hdr_3addr)-_BEACON_IE_OFFSET_, NULL, &wps_ielen); ++ if (wps_ie && wps_ielen>0) { ++ rtw_get_wps_attr_content(wps_ie, wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8*)(&sr), NULL); ++ } ++ if (sr != 0) ++ set_fwstate(pmlmepriv, WIFI_UNDER_WPS); ++ else ++ _clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS); ++ } ++ ++#ifdef CONFIG_P2P ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ { ++ u32 len; ++#ifdef CONFIG_IOCTL_CFG80211 ++ if(wdev_to_priv(padapter->rtw_wdev)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ { ++ len = pmlmepriv->p2p_beacon_ie_len; ++ if(pmlmepriv->p2p_beacon_ie && len>0) ++ _rtw_memcpy(pframe, pmlmepriv->p2p_beacon_ie, len); ++ } ++ else ++#endif //CONFIG_IOCTL_CFG80211 ++ { ++ len = build_beacon_p2p_ie(pwdinfo, pframe); ++ } ++ ++ pframe += len; ++ pattrib->pktlen += len; ++#ifdef CONFIG_WFD ++#ifdef CONFIG_IOCTL_CFG80211 ++ if(_TRUE == pwdinfo->wfd_info->wfd_enable) ++#endif //CONFIG_IOCTL_CFG80211 ++ { ++ len = build_beacon_wfd_ie( pwdinfo, pframe ); ++ } ++#ifdef CONFIG_IOCTL_CFG80211 ++ else ++ { ++ len = 0; ++ if(pmlmepriv->wfd_beacon_ie && pmlmepriv->wfd_beacon_ie_len>0) ++ { ++ len = pmlmepriv->wfd_beacon_ie_len; ++ _rtw_memcpy(pframe, pmlmepriv->wfd_beacon_ie, len); ++ } ++ } ++#endif //CONFIG_IOCTL_CFG80211 ++ pframe += len; ++ pattrib->pktlen += len; ++#endif //CONFIG_WFD ++ } ++#endif //CONFIG_P2P ++ ++ goto _issue_bcn; ++ ++ } ++ ++ //below for ad-hoc mode ++ ++ //timestamp will be inserted by hardware ++ pframe += 8; ++ pattrib->pktlen += 8; ++ ++ // beacon interval: 2 bytes ++ ++ _rtw_memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ // capability info: 2 bytes ++ ++ _rtw_memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ // SSID ++ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen); ++ ++ // supported rates... ++ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8)? 8: rate_len), cur_network->SupportedRates, &pattrib->pktlen); ++ ++ // DS parameter set ++ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen); ++ ++ //if( (pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) ++ { ++ u8 erpinfo=0; ++ u32 ATIMWindow; ++ // IBSS Parameter Set... ++ //ATIMWindow = cur->Configuration.ATIMWindow; ++ ATIMWindow = 0; ++ pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen); ++ ++ //ERP IE ++ pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen); ++ } ++ ++ ++ // EXTERNDED SUPPORTED RATE ++ if (rate_len > 8) ++ { ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen); ++ } ++ ++ ++ //todo:HT for adhoc ++ ++_issue_bcn: ++ ++#if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) ++ pmlmepriv->update_bcn = _FALSE; ++ ++ _exit_critical_bh(&pmlmepriv->bcn_update_lock, &irqL); ++#endif //#if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) ++ ++ if ((pattrib->pktlen + TXDESC_SIZE) > 512) ++ { ++ DBG_871X("beacon frame too large\n"); ++ return; ++ } ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ //DBG_871X("issue bcn_sz=%d\n", pattrib->last_txcmdsz); ++ if(timeout_ms > 0) ++ dump_mgntframe_and_wait(padapter, pmgntframe, timeout_ms); ++ else ++ dump_mgntframe(padapter, pmgntframe); ++ ++} ++ ++void issue_probersp(_adapter *padapter, unsigned char *da, u8 is_valid_p2p_probereq) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ unsigned char *mac, *bssid; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++#if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) ++ u8 *pwps_ie; ++ uint wps_ielen; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++#endif //#if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); ++ unsigned int rate_len; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); ++#ifdef CONFIG_WFD ++ u32 wfdielen = 0; ++#endif //CONFIG_WFD ++#endif //CONFIG_P2P ++ ++ //DBG_871X("%s\n", __FUNCTION__); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ DBG_871X("%s, alloc mgnt frame fail\n", __FUNCTION__); ++ return; ++ } ++ ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ mac = myid(&(padapter->eeprompriv)); ++ bssid = cur_network->MacAddress; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(fctrl, WIFI_PROBERSP); ++ ++ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = pattrib->hdrlen; ++ pframe += pattrib->hdrlen; ++ ++ ++ if(cur_network->IELength>MAX_IE_SZ) ++ return; ++ ++#if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) ++ if( (pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ { ++ pwps_ie = rtw_get_wps_ie(cur_network->IEs+_FIXED_IE_LENGTH_, cur_network->IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen); ++ ++ //inerset & update wps_probe_resp_ie ++ if((pmlmepriv->wps_probe_resp_ie!=NULL) && pwps_ie && (wps_ielen>0)) ++ { ++ uint wps_offset, remainder_ielen; ++ u8 *premainder_ie; ++ ++ wps_offset = (uint)(pwps_ie - cur_network->IEs); ++ ++ premainder_ie = pwps_ie + wps_ielen; ++ ++ remainder_ielen = cur_network->IELength - wps_offset - wps_ielen; ++ ++ _rtw_memcpy(pframe, cur_network->IEs, wps_offset); ++ pframe += wps_offset; ++ pattrib->pktlen += wps_offset; ++ ++ wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1];//to get ie data len ++ if((wps_offset+wps_ielen+2)<=MAX_IE_SZ) ++ { ++ _rtw_memcpy(pframe, pmlmepriv->wps_probe_resp_ie, wps_ielen+2); ++ pframe += wps_ielen+2; ++ pattrib->pktlen += wps_ielen+2; ++ } ++ ++ if((wps_offset+wps_ielen+2+remainder_ielen)<=MAX_IE_SZ) ++ { ++ _rtw_memcpy(pframe, premainder_ie, remainder_ielen); ++ pframe += remainder_ielen; ++ pattrib->pktlen += remainder_ielen; ++ } ++ } ++ else ++ { ++ _rtw_memcpy(pframe, cur_network->IEs, cur_network->IELength); ++ pframe += cur_network->IELength; ++ pattrib->pktlen += cur_network->IELength; ++ } ++ ++ /* retrieve SSID IE from cur_network->Ssid */ ++ { ++ u8 *ssid_ie; ++ sint ssid_ielen; ++ sint ssid_ielen_diff; ++ u8 buf[MAX_IE_SZ]; ++ u8 *ies = pmgntframe->buf_addr+TXDESC_OFFSET+sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ ssid_ie = rtw_get_ie(ies+_FIXED_IE_LENGTH_, _SSID_IE_, &ssid_ielen, ++ (pframe-ies)-_FIXED_IE_LENGTH_); ++ ++ ssid_ielen_diff = cur_network->Ssid.SsidLength - ssid_ielen; ++ ++ if (ssid_ie && cur_network->Ssid.SsidLength) { ++ uint remainder_ielen; ++ u8 *remainder_ie; ++ remainder_ie = ssid_ie+2; ++ remainder_ielen = (pframe-remainder_ie); ++ ++ DBG_871X_LEVEL(_drv_warning_, FUNC_ADPT_FMT" remainder_ielen > MAX_IE_SZ\n", FUNC_ADPT_ARG(padapter)); ++ if (remainder_ielen > MAX_IE_SZ) { ++ remainder_ielen = MAX_IE_SZ; ++ } ++ ++ _rtw_memcpy(buf, remainder_ie, remainder_ielen); ++ _rtw_memcpy(remainder_ie+ssid_ielen_diff, buf, remainder_ielen); ++ *(ssid_ie+1) = cur_network->Ssid.SsidLength; ++ _rtw_memcpy(ssid_ie+2, cur_network->Ssid.Ssid, cur_network->Ssid.SsidLength); ++ ++ pframe += ssid_ielen_diff; ++ pattrib->pktlen += ssid_ielen_diff; ++ } ++ } ++ } ++ else ++#endif ++ { ++ ++ //timestamp will be inserted by hardware ++ pframe += 8; ++ pattrib->pktlen += 8; ++ ++ // beacon interval: 2 bytes ++ ++ _rtw_memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ // capability info: 2 bytes ++ ++ _rtw_memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ //below for ad-hoc mode ++ ++ // SSID ++ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen); ++ ++ // supported rates... ++ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8)? 8: rate_len), cur_network->SupportedRates, &pattrib->pktlen); ++ ++ // DS parameter set ++ pframe =rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen); ++ ++ if( (pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) ++ { ++ u8 erpinfo=0; ++ u32 ATIMWindow; ++ // IBSS Parameter Set... ++ //ATIMWindow = cur->Configuration.ATIMWindow; ++ ATIMWindow = 0; ++ pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen); ++ ++ //ERP IE ++ pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen); ++ } ++ ++ ++ // EXTERNDED SUPPORTED RATE ++ if (rate_len > 8) ++ { ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen); ++ } ++ ++ ++ //todo:HT for adhoc ++ ++ } ++ ++#ifdef CONFIG_P2P ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) /*&& is_valid_p2p_probereq*/) ++ { ++ u32 len; ++#ifdef CONFIG_IOCTL_CFG80211 ++ if(wdev_to_priv(padapter->rtw_wdev)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ { ++ //if pwdinfo->role == P2P_ROLE_DEVICE will call issue_probersp_p2p() ++ len = pmlmepriv->p2p_go_probe_resp_ie_len; ++ if(pmlmepriv->p2p_go_probe_resp_ie && len>0) ++ _rtw_memcpy(pframe, pmlmepriv->p2p_go_probe_resp_ie, len); ++ } ++ else ++#endif //CONFIG_IOCTL_CFG80211 ++ { ++ len = build_probe_resp_p2p_ie(pwdinfo, pframe); ++ } ++ ++ pframe += len; ++ pattrib->pktlen += len; ++ ++#ifdef CONFIG_WFD ++#ifdef CONFIG_IOCTL_CFG80211 ++ if(_TRUE == pwdinfo->wfd_info->wfd_enable) ++#endif //CONFIG_IOCTL_CFG80211 ++ { ++ len = build_probe_resp_wfd_ie(pwdinfo, pframe, 0); ++ } ++#ifdef CONFIG_IOCTL_CFG80211 ++ else ++ { ++ len = 0; ++ if(pmlmepriv->wfd_probe_resp_ie && pmlmepriv->wfd_probe_resp_ie_len>0) ++ { ++ len = pmlmepriv->wfd_probe_resp_ie_len; ++ _rtw_memcpy(pframe, pmlmepriv->wfd_probe_resp_ie, len); ++ } ++ } ++#endif //CONFIG_IOCTL_CFG80211 ++ pframe += len; ++ pattrib->pktlen += len; ++#endif //CONFIG_WFD ++ ++ } ++#endif //CONFIG_P2P ++ ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++ return; ++ ++} ++ ++int _issue_probereq(_adapter *padapter, NDIS_802_11_SSID *pssid, u8 *da, int wait_ack) ++{ ++ int ret = _FAIL; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ unsigned char *mac; ++ unsigned char bssrate[NumRates]; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ int bssrate_len = 0; ++ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_notice_,("+issue_probereq\n")); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ goto exit; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ mac = myid(&(padapter->eeprompriv)); ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ if (da) ++ { ++ // unicast probe request frame ++ _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, da, ETH_ALEN); ++ } ++ else ++ { ++ // broadcast probe request frame ++ _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN); ++ } ++ ++ _rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_PROBEREQ); ++ ++ pframe += sizeof (struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof (struct rtw_ieee80211_hdr_3addr); ++ ++ if(pssid) ++ pframe = rtw_set_ie(pframe, _SSID_IE_, pssid->SsidLength, pssid->Ssid, &(pattrib->pktlen)); ++ else ++ pframe = rtw_set_ie(pframe, _SSID_IE_, 0, NULL, &(pattrib->pktlen)); ++ ++ get_rate_set(padapter, bssrate, &bssrate_len); ++ ++ if (bssrate_len > 8) ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen)); ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen)); ++ } ++ else ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen)); ++ } ++ ++#if 0 ++ //add wps_ie for wps2.0 ++ if(pmlmepriv->probereq_wpsie_len>0 && pmlmepriv->probereq_wpsie_lenprobereq_wpsie, pmlmepriv->probereq_wpsie_len); ++ pframe += pmlmepriv->probereq_wpsie_len; ++ pattrib->pktlen += pmlmepriv->probereq_wpsie_len; ++ //pmlmepriv->probereq_wpsie_len = 0 ;//reset to zero ++ } ++#else ++ //add wps_ie for wps2.0 ++ if(pmlmepriv->wps_probe_req_ie_len>0 && pmlmepriv->wps_probe_req_ie) ++ { ++ _rtw_memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len); ++ pframe += pmlmepriv->wps_probe_req_ie_len; ++ pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; ++ //pmlmepriv->wps_probe_req_ie_len = 0 ;//reset to zero ++ } ++#endif ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_notice_,("issuing probe_req, tx_len=%d\n", pattrib->last_txcmdsz)); ++ ++ if (wait_ack) { ++ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); ++ } else { ++ dump_mgntframe(padapter, pmgntframe); ++ ret = _SUCCESS; ++ } ++ ++exit: ++ return ret; ++} ++ ++inline void issue_probereq(_adapter *padapter, NDIS_802_11_SSID *pssid, u8 *da) ++{ ++ _issue_probereq(padapter, pssid, da, _FALSE); ++} ++ ++int issue_probereq_ex(_adapter *padapter, NDIS_802_11_SSID *pssid, u8 *da, ++ int try_cnt, int wait_ms) ++{ ++ int ret; ++ int i = 0; ++ u32 start = rtw_get_current_time(); ++ ++ do ++ { ++ ret = _issue_probereq(padapter, pssid, da, wait_ms>0?_TRUE:_FALSE); ++ ++ i++; ++ ++ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) ++ break; ++ ++ if(i < try_cnt && wait_ms > 0 && ret==_FAIL) ++ rtw_msleep_os(wait_ms); ++ ++ }while((ixmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_AUTH); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ ++ if(psta)// for AP mode ++ { ++#ifdef CONFIG_NATIVEAP_MLME ++ ++ _rtw_memcpy(pwlanhdr->addr1, psta->hwaddr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ ++ // setting auth algo number ++ val16 = (u16)psta->authalg; ++ ++ if(status != _STATS_SUCCESSFUL_) ++ val16 = 0; ++ ++ if (val16) { ++ val16 = cpu_to_le16(val16); ++ use_shared_key = 1; ++ } ++ ++ pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&val16, &(pattrib->pktlen)); ++ ++ // setting auth seq number ++ val16 =(u16)psta->auth_seq; ++ val16 = cpu_to_le16(val16); ++ pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&val16, &(pattrib->pktlen)); ++ ++ // setting status code... ++ val16 = status; ++ val16 = cpu_to_le16(val16); ++ pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&val16, &(pattrib->pktlen)); ++ ++ // added challenging text... ++ if ((psta->auth_seq == 2) && (psta->state & WIFI_FW_AUTH_STATE) && (use_shared_key==1)) ++ { ++ pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, psta->chg_txt, &(pattrib->pktlen)); ++ } ++#endif ++ } ++ else ++ { ++ _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ ++ // setting auth algo number ++ val16 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared)? 1: 0;// 0:OPEN System, 1:Shared key ++ if (val16) { ++ val16 = cpu_to_le16(val16); ++ use_shared_key = 1; ++ } ++ //DBG_871X("%s auth_algo= %s auth_seq=%d\n",__FUNCTION__,(pmlmeinfo->auth_algo==0)?"OPEN":"SHARED",pmlmeinfo->auth_seq); ++ ++ //setting IV for auth seq #3 ++ if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key==1)) ++ { ++ //DBG_871X("==> iv(%d),key_index(%d)\n",pmlmeinfo->iv,pmlmeinfo->key_index); ++ val32 = ((pmlmeinfo->iv++) | (pmlmeinfo->key_index << 30)); ++ val32 = cpu_to_le32(val32); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&val32, &(pattrib->pktlen)); ++ ++ pattrib->iv_len = 4; ++ } ++ ++ pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&val16, &(pattrib->pktlen)); ++ ++ // setting auth seq number ++ val16 = pmlmeinfo->auth_seq; ++ val16 = cpu_to_le16(val16); ++ pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&val16, &(pattrib->pktlen)); ++ ++ ++ // setting status code... ++ val16 = status; ++ val16 = cpu_to_le16(val16); ++ pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&val16, &(pattrib->pktlen)); ++ ++ // then checking to see if sending challenging text... ++ if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key==1)) ++ { ++ pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, pmlmeinfo->chg_txt, &(pattrib->pktlen)); ++ ++ SetPrivacy(fctrl); ++ ++ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pattrib->encrypt = _WEP40_; ++ ++ pattrib->icv_len = 4; ++ ++ pattrib->pktlen += pattrib->icv_len; ++ ++ } ++ ++ } ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ rtw_wep_encrypt(padapter, (u8 *)pmgntframe); ++ DBG_871X("%s\n", __FUNCTION__); ++ dump_mgntframe(padapter, pmgntframe); ++ ++ return; ++} ++ ++ ++void issue_asocrsp(_adapter *padapter, unsigned short status, struct sta_info *pstat, int pkt_type) ++{ ++#ifdef CONFIG_AP_MODE ++ struct xmit_frame *pmgntframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ struct pkt_attrib *pattrib; ++ unsigned char *pbuf, *pframe; ++ unsigned short val; ++ unsigned short *fctrl; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network); ++ u8 *ie = pnetwork->IEs; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); ++#ifdef CONFIG_WFD ++ u32 wfdielen = 0; ++#endif //CONFIG_WFD ++ ++#endif //CONFIG_P2P ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy((void *)GetAddr1Ptr(pwlanhdr), pstat->hwaddr, ETH_ALEN); ++ _rtw_memcpy((void *)GetAddr2Ptr(pwlanhdr), myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy((void *)GetAddr3Ptr(pwlanhdr), get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP)) ++ SetFrameSubType(pwlanhdr, pkt_type); ++ else ++ return; ++ ++ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen += pattrib->hdrlen; ++ pframe += pattrib->hdrlen; ++ ++ //capability ++ val = *(unsigned short *)rtw_get_capability_from_ie(ie); ++ ++ pframe = rtw_set_fixed_ie(pframe, _CAPABILITY_ , (unsigned char *)&val, &(pattrib->pktlen)); ++ ++ status = cpu_to_le16(status); ++ pframe = rtw_set_fixed_ie(pframe , _STATUS_CODE_ , (unsigned char *)&status, &(pattrib->pktlen)); ++ ++ val = cpu_to_le16(pstat->aid | BIT(14) | BIT(15)); ++ pframe = rtw_set_fixed_ie(pframe, _ASOC_ID_ , (unsigned char *)&val, &(pattrib->pktlen)); ++ ++ if (pstat->bssratelen <= 8) ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, pstat->bssratelen, pstat->bssrateset, &(pattrib->pktlen)); ++ } ++ else ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pstat->bssrateset, &(pattrib->pktlen)); ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (pstat->bssratelen-8), pstat->bssrateset+8, &(pattrib->pktlen)); ++ } ++ ++#ifdef CONFIG_80211N_HT ++ if ((pstat->flags & WLAN_STA_HT) && (pmlmepriv->htpriv.ht_option)) ++ { ++ uint ie_len=0; ++ ++ //FILL HT CAP INFO IE ++ //p = hostapd_eid_ht_capabilities_info(hapd, p); ++ pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); ++ if(pbuf && ie_len>0) ++ { ++ _rtw_memcpy(pframe, pbuf, ie_len+2); ++ pframe += (ie_len+2); ++ pattrib->pktlen +=(ie_len+2); ++ } ++ ++ //FILL HT ADD INFO IE ++ //p = hostapd_eid_ht_operation(hapd, p); ++ pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); ++ if(pbuf && ie_len>0) ++ { ++ _rtw_memcpy(pframe, pbuf, ie_len+2); ++ pframe += (ie_len+2); ++ pattrib->pktlen +=(ie_len+2); ++ } ++ ++ } ++#endif ++ ++ //FILL WMM IE ++ if ((pstat->flags & WLAN_STA_WME) && (pmlmepriv->qospriv.qos_option)) ++ { ++ uint ie_len=0; ++ unsigned char WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; ++ ++ for (pbuf = ie + _BEACON_IE_OFFSET_; ;pbuf+= (ie_len + 2)) ++ { ++ pbuf = rtw_get_ie(pbuf, _VENDOR_SPECIFIC_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); ++ if(pbuf && _rtw_memcmp(pbuf+2, WMM_PARA_IE, 6)) ++ { ++ _rtw_memcpy(pframe, pbuf, ie_len+2); ++ pframe += (ie_len+2); ++ pattrib->pktlen +=(ie_len+2); ++ ++ break; ++ } ++ ++ if ((pbuf == NULL) || (ie_len == 0)) ++ { ++ break; ++ } ++ } ++ ++ } ++ ++ ++ if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) ++ { ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen)); ++ } ++ ++ //add WPS IE ie for wps 2.0 ++ if(pmlmepriv->wps_assoc_resp_ie && pmlmepriv->wps_assoc_resp_ie_len>0) ++ { ++ _rtw_memcpy(pframe, pmlmepriv->wps_assoc_resp_ie, pmlmepriv->wps_assoc_resp_ie_len); ++ ++ pframe += pmlmepriv->wps_assoc_resp_ie_len; ++ pattrib->pktlen += pmlmepriv->wps_assoc_resp_ie_len; ++ } ++ ++#ifdef CONFIG_P2P ++ if( padapter->wdinfo.driver_interface == DRIVER_WEXT ) ++ { ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && (pstat->is_p2p_device == _TRUE)) ++ { ++ u32 len; ++ ++ len = build_assoc_resp_p2p_ie(pwdinfo, pframe, pstat->p2p_status_code); ++ ++ pframe += len; ++ pattrib->pktlen += len; ++ } ++ } ++#ifdef CONFIG_WFD ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) ++#ifdef CONFIG_IOCTL_CFG80211 ++ && (_TRUE == pwdinfo->wfd_info->wfd_enable) ++#endif //CONFIG_IOCTL_CFG80211 ++ ) ++ { ++ wfdielen = build_assoc_resp_wfd_ie(pwdinfo, pframe); ++ pframe += wfdielen; ++ pattrib->pktlen += wfdielen; ++ } ++#endif //CONFIG_WFD ++#endif //CONFIG_P2P ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++#endif ++} ++ ++void issue_assocreq(_adapter *padapter) ++{ ++ int ret = _FAIL; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe, *p; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ unsigned short val16; ++ unsigned int i, j, ie_len, index=0; ++ unsigned char rf_type, bssrate[NumRates], sta_bssrate[NumRates]; ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ int bssrate_len = 0, sta_bssrate_len = 0; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); ++ u8 p2pie[ 255 ] = { 0x00 }; ++ u16 p2pielen = 0; ++#ifdef CONFIG_WFD ++ u32 wfdielen = 0; ++#endif //CONFIG_WFD ++#endif //CONFIG_P2P ++ ++#ifdef CONFIG_DFS ++ u16 cap; ++#endif //CONFIG_DFS ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ goto exit; ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ASSOCREQ); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ //caps ++ ++#ifdef CONFIG_DFS ++ _rtw_memcpy(&cap, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2); ++ cap |= BIT(8); ++ _rtw_memcpy(pframe, &cap, 2); ++#else ++ _rtw_memcpy(pframe, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2); ++#endif //CONFIG_DFS ++ ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ //listen interval ++ //todo: listen interval for power saving ++ val16 = cpu_to_le16(3); ++ _rtw_memcpy(pframe ,(unsigned char *)&val16, 2); ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ //SSID ++ pframe = rtw_set_ie(pframe, _SSID_IE_, pmlmeinfo->network.Ssid.SsidLength, pmlmeinfo->network.Ssid.Ssid, &(pattrib->pktlen)); ++ ++ //supported rate & extended supported rate ++ ++#if 1 // Check if the AP's supported rates are also supported by STA. ++ get_rate_set(padapter, sta_bssrate, &sta_bssrate_len); ++ //DBG_871X("sta_bssrate_len=%d\n", sta_bssrate_len); ++ ++ if(pmlmeext->cur_channel == 14)// for JAPAN, channel 14 can only uses B Mode(CCK) ++ { ++ sta_bssrate_len = 4; ++ } ++ ++ ++ //for (i = 0; i < sta_bssrate_len; i++) { ++ // DBG_871X("sta_bssrate[%d]=%02X\n", i, sta_bssrate[i]); ++ //} ++ ++ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { ++ if (pmlmeinfo->network.SupportedRates[i] == 0) break; ++ DBG_871X("network.SupportedRates[%d]=%02X\n", i, pmlmeinfo->network.SupportedRates[i]); ++ } ++ ++ ++ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { ++ if (pmlmeinfo->network.SupportedRates[i] == 0) break; ++ ++ ++ // Check if the AP's supported rates are also supported by STA. ++ for (j=0; j < sta_bssrate_len; j++) { ++ // Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP ++ if ( (pmlmeinfo->network.SupportedRates[i]|IEEE80211_BASIC_RATE_MASK) ++ == (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK)) { ++ //DBG_871X("match i = %d, j=%d\n", i, j); ++ break; ++ } else { ++ //DBG_871X("not match: %02X != %02X\n", (pmlmeinfo->network.SupportedRates[i]|IEEE80211_BASIC_RATE_MASK), (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK)); ++ } ++ } ++ ++ if (j == sta_bssrate_len) { ++ // the rate is not supported by STA ++ DBG_871X("%s(): the rate[%d]=%02X is not supported by STA!\n",__FUNCTION__, i, pmlmeinfo->network.SupportedRates[i]); ++ } else { ++ // the rate is supported by STA ++ bssrate[index++] = pmlmeinfo->network.SupportedRates[i]; ++ } ++ } ++ ++ bssrate_len = index; ++ DBG_871X("bssrate_len = %d\n", bssrate_len); ++ ++#else // Check if the AP's supported rates are also supported by STA. ++#if 0 ++ get_rate_set(padapter, bssrate, &bssrate_len); ++#else ++ for (bssrate_len = 0; bssrate_len < NumRates; bssrate_len++) { ++ if (pmlmeinfo->network.SupportedRates[bssrate_len] == 0) break; ++ ++ if (pmlmeinfo->network.SupportedRates[bssrate_len] == 0x2C) // Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP ++ break; ++ ++ bssrate[bssrate_len] = pmlmeinfo->network.SupportedRates[bssrate_len]; ++ } ++#endif ++#endif // Check if the AP's supported rates are also supported by STA. ++ ++ if (bssrate_len == 0) { ++ rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ goto exit; //don't connect to AP if no joint supported rate ++ } ++ ++ ++ if (bssrate_len > 8) ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen)); ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen)); ++ } ++ else ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen)); ++ } ++ ++ //RSN ++ p = rtw_get_ie((pmlmeinfo->network.IEs + sizeof(NDIS_802_11_FIXED_IEs)), _RSN_IE_2_, &ie_len, (pmlmeinfo->network.IELength - sizeof(NDIS_802_11_FIXED_IEs))); ++ if (p != NULL) ++ { ++ pframe = rtw_set_ie(pframe, _RSN_IE_2_, ie_len, (p + 2), &(pattrib->pktlen)); ++ } ++ ++#ifdef CONFIG_80211N_HT ++ //HT caps ++ if(padapter->mlmepriv.htpriv.ht_option==_TRUE) ++ { ++ p = rtw_get_ie((pmlmeinfo->network.IEs + sizeof(NDIS_802_11_FIXED_IEs)), _HT_CAPABILITY_IE_, &ie_len, (pmlmeinfo->network.IELength - sizeof(NDIS_802_11_FIXED_IEs))); ++ if ((p != NULL) && (!(is_ap_in_tkip(padapter)))) ++ { ++ _rtw_memcpy(&(pmlmeinfo->HT_caps), (p + 2), sizeof(struct HT_caps_element)); ++ ++ //to disable 40M Hz support while gd_bw_40MHz_en = 0 ++ if (pregpriv->cbw40_enable == 0) ++ { ++ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info &= (~(BIT(6) | BIT(1))); ++ } ++ else ++ { ++ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= BIT(1); ++ } ++ ++ //todo: disable SM power save mode ++ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= 0x000c; ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ //switch (pregpriv->rf_config) ++ switch(rf_type) ++ { ++ case RF_1T1R: ++ ++ if(pregpriv->rx_stbc) ++ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0100);//RX STBC One spatial stream ++ ++ _rtw_memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_1R, 16); ++ break; ++ ++ case RF_2T2R: ++ case RF_1T2R: ++ default: ++ ++ if((pregpriv->rx_stbc == 0x3) ||//enable for 2.4/5 GHz ++ ((pmlmeext->cur_wireless_mode & WIRELESS_11_24N) && (pregpriv->rx_stbc == 0x1)) || //enable for 2.4GHz ++ ((pmlmeext->cur_wireless_mode & WIRELESS_11_5N) && (pregpriv->rx_stbc == 0x2)) || //enable for 5GHz ++ (pregpriv->wifi_spec==1)) ++ { ++ DBG_871X("declare supporting RX STBC\n"); ++ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0200);//RX STBC two spatial stream ++ } ++ #ifdef CONFIG_DISABLE_MCS13TO15 ++ if(pmlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40 && (pregpriv->wifi_spec!=1)) ++ _rtw_memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_2R_MCS13TO15_OFF, 16); ++ else ++ _rtw_memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_2R, 16); ++ #else //CONFIG_DISABLE_MCS13TO15 ++ _rtw_memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_2R, 16); ++ #endif //CONFIG_DISABLE_MCS13TO15 ++ break; ++ } ++#ifdef RTL8192C_RECONFIG_TO_1T1R ++ { ++ if(pregpriv->rx_stbc) ++ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0100);//RX STBC One spatial stream ++ ++ _rtw_memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_1R, 16); ++ } ++#endif ++ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info = cpu_to_le16(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info); ++ ++#ifdef CONFIG_BT_COEXIST ++ if (BT_1Ant(padapter) == _TRUE) ++ { ++ // set to 8K ++ pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para &= (u8)~IEEE80211_HT_CAP_AMPDU_FACTOR; ++// pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para |= MAX_AMPDU_FACTOR_8K ++ } ++#endif ++ ++ pframe = rtw_set_ie(pframe, _HT_CAPABILITY_IE_, ie_len , (u8 *)(&(pmlmeinfo->HT_caps)), &(pattrib->pktlen)); ++ ++ } ++ } ++#endif ++ ++ //vendor specific IE, such as WPA, WMM, WPS ++ for (i = sizeof(NDIS_802_11_FIXED_IEs); i < pmlmeinfo->network.IELength;) ++ { ++ pIE = (PNDIS_802_11_VARIABLE_IEs)(pmlmeinfo->network.IEs + i); ++ ++ switch (pIE->ElementID) ++ { ++ case _VENDOR_SPECIFIC_IE_: ++ if ((_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4)) || ++ (_rtw_memcmp(pIE->data, WMM_OUI, 4)) || ++ (_rtw_memcmp(pIE->data, WPS_OUI, 4))) ++ { ++ if(!padapter->registrypriv.wifi_spec) ++ { ++ //Commented by Kurt 20110629 ++ //In some older APs, WPS handshake ++ //would be fail if we append vender extensions informations to AP ++ if(_rtw_memcmp(pIE->data, WPS_OUI, 4)){ ++ pIE->Length=14; ++ } ++ } ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, pIE->Length, pIE->data, &(pattrib->pktlen)); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ ++ if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) ++ { ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen)); ++ } ++ ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ rtw_build_assoc_req_wapi_ie(padapter, pframe, pattrib); ++#endif ++ ++ ++#ifdef CONFIG_P2P ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if(wdev_to_priv(padapter->rtw_wdev)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ { ++ if(pmlmepriv->p2p_assoc_req_ie && pmlmepriv->p2p_assoc_req_ie_len>0) ++ { ++ _rtw_memcpy(pframe, pmlmepriv->p2p_assoc_req_ie, pmlmepriv->p2p_assoc_req_ie_len); ++ pframe += pmlmepriv->p2p_assoc_req_ie_len; ++ pattrib->pktlen += pmlmepriv->p2p_assoc_req_ie_len; ++ } ++ } ++ else ++#endif //CONFIG_IOCTL_CFG80211 ++ { ++ if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) ++ { ++ // Should add the P2P IE in the association request frame. ++ // P2P OUI ++ ++ p2pielen = 0; ++ p2pie[ p2pielen++ ] = 0x50; ++ p2pie[ p2pielen++ ] = 0x6F; ++ p2pie[ p2pielen++ ] = 0x9A; ++ p2pie[ p2pielen++ ] = 0x09; // WFA P2P v1.0 ++ ++ // Commented by Albert 20101109 ++ // According to the P2P Specification, the association request frame should contain 3 P2P attributes ++ // 1. P2P Capability ++ // 2. Extended Listen Timing ++ // 3. Device Info ++ // Commented by Albert 20110516 ++ // 4. P2P Interface ++ ++ // P2P Capability ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_CAPABILITY; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Device Capability Bitmap, 1 byte ++ p2pie[ p2pielen++ ] = DMP_P2P_DEVCAP_SUPPORT; ++ ++ // Group Capability Bitmap, 1 byte ++ if ( pwdinfo->persistent_supported ) ++ p2pie[ p2pielen++ ] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; ++ else ++ p2pie[ p2pielen++ ] = DMP_P2P_GRPCAP_SUPPORT; ++ ++ // Extended Listen Timing ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_EX_LISTEN_TIMING; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0004 ); ++ p2pielen += 2; ++ ++ // Value: ++ // Availability Period ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0xFFFF ); ++ p2pielen += 2; ++ ++ // Availability Interval ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0xFFFF ); ++ p2pielen += 2; ++ ++ // Device Info ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) ++ // + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 21 + pwdinfo->device_name_len ); ++ p2pielen += 2; ++ ++ // Value: ++ // P2P Device Address ++ _rtw_memcpy( p2pie + p2pielen, myid( &padapter->eeprompriv ), ETH_ALEN ); ++ p2pielen += ETH_ALEN; ++ ++ // Config Method ++ // This field should be big endian. Noted by P2P specification. ++ if ( ( pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN ) || ++ ( pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN ) ) ++ { ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_CONFIG_METHOD_DISPLAY ); ++ } ++ else ++ { ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_CONFIG_METHOD_PBC ); ++ } ++ ++ p2pielen += 2; ++ ++ // Primary Device Type ++ // Category ID ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_CID_MULIT_MEDIA ); ++ p2pielen += 2; ++ ++ // OUI ++ *(u32*) ( p2pie + p2pielen ) = cpu_to_be32( WPSOUI ); ++ p2pielen += 4; ++ ++ // Sub Category ID ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_SCID_MEDIA_SERVER ); ++ p2pielen += 2; ++ ++ // Number of Secondary Device Types ++ p2pie[ p2pielen++ ] = 0x00; // No Secondary Device Type List ++ ++ // Device Name ++ // Type: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_ATTR_DEVICE_NAME ); ++ p2pielen += 2; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( pwdinfo->device_name_len ); ++ p2pielen += 2; ++ ++ // Value: ++ _rtw_memcpy( p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len ); ++ p2pielen += pwdinfo->device_name_len; ++ ++ // P2P Interface ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_INTERFACE; ++ ++ // Length: ++ *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x000D ); ++ p2pielen += 2; ++ ++ // Value: ++ _rtw_memcpy( p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN ); // P2P Device Address ++ p2pielen += ETH_ALEN; ++ ++ p2pie[ p2pielen++ ] = 1; // P2P Interface Address Count ++ ++ _rtw_memcpy( p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN ); // P2P Interface Address List ++ p2pielen += ETH_ALEN; ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen ); ++ ++#ifdef CONFIG_WFD ++ //wfdielen = build_assoc_req_wfd_ie(pwdinfo, pframe); ++ //pframe += wfdielen; ++ //pattrib->pktlen += wfdielen; ++#endif //CONFIG_WFD ++ } ++ } ++ ++#endif //CONFIG_P2P ++ ++#ifdef CONFIG_WFD ++#ifdef CONFIG_IOCTL_CFG80211 ++ if ( _TRUE == pwdinfo->wfd_info->wfd_enable ) ++#endif //CONFIG_IOCTL_CFG80211 ++ { ++ wfdielen = build_assoc_req_wfd_ie(pwdinfo, pframe); ++ pframe += wfdielen; ++ pattrib->pktlen += wfdielen; ++ } ++#ifdef CONFIG_IOCTL_CFG80211 ++ else if (pmlmepriv->wfd_assoc_req_ie != NULL && pmlmepriv->wfd_assoc_req_ie_len>0) ++ { ++ //WFD IE ++ _rtw_memcpy(pframe, pmlmepriv->wfd_assoc_req_ie, pmlmepriv->wfd_assoc_req_ie_len); ++ pattrib->pktlen += pmlmepriv->wfd_assoc_req_ie_len; ++ pframe += pmlmepriv->wfd_assoc_req_ie_len; ++ } ++#endif //CONFIG_IOCTL_CFG80211 ++#endif //CONFIG_WFD ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ dump_mgntframe(padapter, pmgntframe); ++ ++ ret = _SUCCESS; ++ ++exit: ++ if (ret == _SUCCESS) ++ rtw_buf_update(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len, (u8 *)pwlanhdr, pattrib->pktlen); ++ else ++ rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len); ++ ++ return; ++} ++ ++//when wait_ack is ture, this function shoule be called at process context ++static int _issue_nulldata(_adapter *padapter, unsigned char *da, unsigned int power_mode, int wait_ack) ++{ ++ int ret = _FAIL; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ struct xmit_priv *pxmitpriv; ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ ++ //DBG_871X("%s:%d\n", __FUNCTION__, power_mode); ++ ++ if(!padapter) ++ goto exit; ++ ++ pxmitpriv = &(padapter->xmitpriv); ++ pmlmeext = &(padapter->mlmeextpriv); ++ pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ goto exit; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->retry_ctrl = _FALSE; ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ if((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ { ++ SetFrDs(fctrl); ++ } ++ else if((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) ++ { ++ SetToDs(fctrl); ++ } ++ ++ if (power_mode) ++ { ++ SetPwrMgt(fctrl); ++ } ++ ++ _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_DATA_NULL); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ if(wait_ack) ++ { ++ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); ++ } ++ else ++ { ++ dump_mgntframe(padapter, pmgntframe); ++ ret = _SUCCESS; ++ } ++ ++exit: ++ return ret; ++} ++ ++ ++//when wait_ms >0 , this function shoule be called at process context ++//da == NULL for station mode ++int issue_nulldata(_adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms) ++{ ++ int ret; ++ int i = 0; ++ u32 start = rtw_get_current_time(); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ /* da == NULL, assum it's null data for sta to ap*/ ++ if (da == NULL) ++ da = get_my_bssid(&(pmlmeinfo->network)); ++ ++ do ++ { ++ ret = _issue_nulldata(padapter, da, power_mode, wait_ms>0?_TRUE:_FALSE); ++ ++ i++; ++ ++ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) ++ break; ++ ++ if(i < try_cnt && wait_ms > 0 && ret==_FAIL) ++ rtw_msleep_os(wait_ms); ++ ++ }while((ixmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ goto exit; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ pattrib->hdrlen +=2; ++ pattrib->qos_en = _TRUE; ++ pattrib->eosp = 1; ++ pattrib->ack_policy = 0; ++ pattrib->mdata = 0; ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ if((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ { ++ SetFrDs(fctrl); ++ } ++ else if((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) ++ { ++ SetToDs(fctrl); ++ } ++ ++ if(pattrib->mdata) ++ SetMData(fctrl); ++ ++ qc = (unsigned short *)(pframe + pattrib->hdrlen - 2); ++ ++ SetPriority(qc, tid); ++ ++ SetEOSP(qc, pattrib->eosp); ++ ++ SetAckpolicy(qc, pattrib->ack_policy); ++ ++ _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr_qos); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ if(wait_ack) ++ { ++ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); ++ } ++ else ++ { ++ dump_mgntframe(padapter, pmgntframe); ++ ret = _SUCCESS; ++ } ++ ++exit: ++ return ret; ++} ++ ++//when wait_ms >0 , this function shoule be called at process context ++//da == NULL for station mode ++int issue_qos_nulldata(_adapter *padapter, unsigned char *da, u16 tid, int try_cnt, int wait_ms) ++{ ++ int ret; ++ int i = 0; ++ u32 start = rtw_get_current_time(); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ /* da == NULL, assum it's null data for sta to ap*/ ++ if (da == NULL) ++ da = get_my_bssid(&(pmlmeinfo->network)); ++ ++ do ++ { ++ ret = _issue_qos_nulldata(padapter, da, tid, wait_ms>0?_TRUE:_FALSE); ++ ++ i++; ++ ++ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) ++ break; ++ ++ if(i < try_cnt && wait_ms > 0 && ret==_FAIL) ++ rtw_msleep_os(wait_ms); ++ ++ }while((ixmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ int ret = _FAIL; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++#endif //CONFIG_P2P ++ ++ //DBG_871X("%s to "MAC_FMT"\n", __func__, MAC_ARG(da)); ++ ++#ifdef CONFIG_P2P ++ if ( !( rtw_p2p_chk_state( pwdinfo, P2P_STATE_NONE ) ) && ( pwdinfo->rx_invitereq_info.scan_op_ch_only ) ) ++ { ++ _cancel_timer_ex( &pwdinfo->reset_ch_sitesurvey ); ++ _set_timer( &pwdinfo->reset_ch_sitesurvey, 10 ); ++ } ++#endif //CONFIG_P2P ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ goto exit; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->retry_ctrl = _FALSE; ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_DEAUTH); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ reason = cpu_to_le16(reason); ++ pframe = rtw_set_fixed_ie(pframe, _RSON_CODE_ , (unsigned char *)&reason, &(pattrib->pktlen)); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ ++ if(wait_ack) ++ { ++ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); ++ } ++ else ++ { ++ dump_mgntframe(padapter, pmgntframe); ++ ret = _SUCCESS; ++ } ++ ++exit: ++ return ret; ++} ++ ++int issue_deauth(_adapter *padapter, unsigned char *da, unsigned short reason) ++{ ++ DBG_871X("%s to "MAC_FMT"\n", __func__, MAC_ARG(da)); ++ return _issue_deauth(padapter, da, reason, _FALSE); ++} ++ ++int issue_deauth_ex(_adapter *padapter, u8 *da, unsigned short reason, int try_cnt, ++ int wait_ms) ++{ ++ int ret; ++ int i = 0; ++ u32 start = rtw_get_current_time(); ++ ++ do ++ { ++ ret = _issue_deauth(padapter, da, reason, wait_ms>0?_TRUE:_FALSE); ++ ++ i++; ++ ++ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) ++ break; ++ ++ if(i < try_cnt && wait_ms > 0 && ret==_FAIL) ++ rtw_msleep_os(wait_ms); ++ ++ }while((ixmitpriv); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ ++ DBG_871X(FUNC_NDEV_FMT" ra="MAC_FMT", ch:%u, offset:%u\n", ++ FUNC_NDEV_ARG(padapter->pnetdev), MAC_ARG(ra), new_ch, ch_offset); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ return; ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); /* RA */ ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); /* TA */ ++ _rtw_memcpy(pwlanhdr->addr3, ra, ETH_ALEN); /* DA = RA */ ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ /* category, action */ ++ { ++ u8 category, action; ++ category = RTW_WLAN_CATEGORY_SPECTRUM_MGMT; ++ action = RTW_WLAN_ACTION_SPCT_CHL_SWITCH; ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ } ++ ++ pframe = rtw_set_ie_ch_switch(pframe, &(pattrib->pktlen), 0, new_ch, 0); ++ pframe = rtw_set_ie_secondary_ch_offset(pframe, &(pattrib->pktlen), ++ hal_ch_offset_to_secondary_ch_offset(ch_offset)); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++} ++ ++#ifdef CONFIG_IEEE80211W ++void issue_action_SA_Query(_adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short tid) ++{ ++ u8 category = RTW_WLAN_CATEGORY_SA_QUERY; ++ u16 reason_code; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ u8 *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ u16 *fctrl; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ DBG_871X("%s: alloc_mgtxmitframe fail\n", __FUNCTION__); ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ if(raddr) ++ _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ else ++ _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &category, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &action, &pattrib->pktlen); ++ ++ switch (action) ++ { ++ case 0: //SA Query req ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&pmlmeext->sa_query_seq, &pattrib->pktlen); ++ pmlmeext->sa_query_seq++; ++ //send sa query request to AP, AP should reply sa query response in 1 second ++ set_sa_query_timer(pmlmeext, 1000); ++ break; ++ ++ case 1: //SA Query rsp ++ tid = cpu_to_le16(tid); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&tid, &pattrib->pktlen); ++ break; ++ default: ++ break; ++ } ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++#endif //CONFIG_IEEE80211W ++ ++void issue_action_BA(_adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short status) ++{ ++ u8 category = RTW_WLAN_CATEGORY_BACK; ++ u16 start_seq; ++ u16 BA_para_set; ++ u16 reason_code; ++ u16 BA_timeout_value; ++ u16 BA_starting_seqctrl; ++ HT_CAP_AMPDU_FACTOR max_rx_ampdu_factor; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ u8 *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ u16 *fctrl; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++#ifdef CONFIG_BT_COEXIST ++ u8 tendaAPMac[] = {0xC8, 0x3A, 0x35}; ++#endif ++ ++#ifdef CONFIG_80211N_HT ++ DBG_871X("%s, category=%d, action=%d, status=%d\n", __FUNCTION__, category, action, status); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ //_rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ ++ status = cpu_to_le16(status); ++ ++ ++ if (category == 3) ++ { ++ switch (action) ++ { ++ case 0: //ADDBA req ++ do { ++ pmlmeinfo->dialogToken++; ++ } while (pmlmeinfo->dialogToken == 0); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->dialogToken), &(pattrib->pktlen)); ++ ++#ifdef CONFIG_BT_COEXIST ++ if ((BT_1Ant(padapter) == _TRUE) && ++ ((pmlmeinfo->assoc_AP_vendor != broadcomAP) || ++ (_rtw_memcmp(raddr, tendaAPMac, 3) == _FALSE))) ++ { ++ // A-MSDU NOT Supported ++ BA_para_set = 0; ++ // immediate Block Ack ++ BA_para_set |= (1 << 1) & IEEE80211_ADDBA_PARAM_POLICY_MASK; ++ // TID ++ BA_para_set |= (status << 2) & IEEE80211_ADDBA_PARAM_TID_MASK; ++ // max buffer size is 8 MSDU ++ BA_para_set |= (8 << 6) & RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; ++ } ++ else ++#endif ++ { ++ #if defined(CONFIG_RTL8188E) && defined(CONFIG_SDIO_HCI) ++ BA_para_set = (0x0802 | ((status & 0xf) << 2)); //immediate ack & 16 buffer size ++ #else ++ BA_para_set = (0x1002 | ((status & 0xf) << 2)); //immediate ack & 64 buffer size ++ #endif ++ } ++ //sys_mib.BA_para_set = 0x0802; //immediate ack & 32 buffer size ++ BA_para_set = cpu_to_le16(BA_para_set); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_para_set)), &(pattrib->pktlen)); ++ ++ //BA_timeout_value = 0xffff;//max: 65535 TUs(~ 65 ms) ++ BA_timeout_value = 5000;//~ 5ms ++ BA_timeout_value = cpu_to_le16(BA_timeout_value); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_timeout_value)), &(pattrib->pktlen)); ++ ++ //if ((psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress)) != NULL) ++ if ((psta = rtw_get_stainfo(pstapriv, raddr)) != NULL) ++ { ++ start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07]&0xfff) + 1; ++ ++ DBG_871X("BA_starting_seqctrl = %d for TID=%d\n", start_seq, status & 0x07); ++ ++ psta->BA_starting_seqctrl[status & 0x07] = start_seq; ++ ++ BA_starting_seqctrl = start_seq << 4; ++ } ++ ++ BA_starting_seqctrl = cpu_to_le16(BA_starting_seqctrl); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_starting_seqctrl)), &(pattrib->pktlen)); ++ break; ++ ++ case 1: //ADDBA rsp ++ pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->ADDBA_req.dialog_token), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&status), &(pattrib->pktlen)); ++ /* ++ //BA_para_set = cpu_to_le16((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); //64 buffer size ++ #if defined(CONFIG_RTL8188E )&& defined (CONFIG_SDIO_HCI) ++ BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0800); //32buffer size ++ #else ++ BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); //64 buffer size ++ #endif ++ */ ++ rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); ++ if(MAX_AMPDU_FACTOR_64K == max_rx_ampdu_factor) ++ BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); //64 buffer size ++ else if(MAX_AMPDU_FACTOR_32K == max_rx_ampdu_factor) ++ BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0800); //32 buffer size ++ else if(MAX_AMPDU_FACTOR_16K == max_rx_ampdu_factor) ++ BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0400); //16 buffer size ++ else if(MAX_AMPDU_FACTOR_8K == max_rx_ampdu_factor) ++ BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0200); //8 buffer size ++ else ++ BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); //64 buffer size ++ ++#ifdef CONFIG_BT_COEXIST ++ if ((BT_1Ant(padapter) == _TRUE) && ++ ((pmlmeinfo->assoc_AP_vendor != broadcomAP) || ++ (_rtw_memcmp(raddr, tendaAPMac, 3) == _FALSE))) ++ { ++ // max buffer size is 8 MSDU ++ BA_para_set &= ~RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; ++ BA_para_set |= (8 << 6) & RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; ++ } ++#endif ++ ++ if(pregpriv->ampdu_amsdu==0)//disabled ++ BA_para_set = cpu_to_le16(BA_para_set & ~BIT(0)); ++ else if(pregpriv->ampdu_amsdu==1)//enabled ++ BA_para_set = cpu_to_le16(BA_para_set | BIT(0)); ++ else //auto ++ BA_para_set = cpu_to_le16(BA_para_set); ++ ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_para_set)), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(pmlmeinfo->ADDBA_req.BA_timeout_value)), &(pattrib->pktlen)); ++ break; ++ case 2://DELBA ++ BA_para_set = (status & 0x1F) << 3; ++ BA_para_set = cpu_to_le16(BA_para_set); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_para_set)), &(pattrib->pktlen)); ++ ++ reason_code = 37;//Requested from peer STA as it does not want to use the mechanism ++ reason_code = cpu_to_le16(reason_code); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(reason_code)), &(pattrib->pktlen)); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++#endif //CONFIG_80211N_HT ++} ++ ++static void issue_action_BSSCoexistPacket(_adapter *padapter) ++{ ++ _irqL irqL; ++ _list *plist, *phead; ++ unsigned char category, action; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ struct wlan_network *pnetwork = NULL; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ u8 InfoContent[16] = {0}; ++ u8 ICS[8][15]; ++#ifdef CONFIG_80211N_HT ++ if((pmlmepriv->num_FortyMHzIntolerant==0) || (pmlmepriv->num_sta_no_ht==0)) ++ return; ++ ++ if(_TRUE == pmlmeinfo->bwmode_updated) ++ return; ++ ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ ++ category = RTW_WLAN_CATEGORY_PUBLIC; ++ action = ACT_PUBLIC_BSSCOEXIST; ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ ++ ++ // ++ if(pmlmepriv->num_FortyMHzIntolerant>0) ++ { ++ u8 iedata=0; ++ ++ iedata |= BIT(2);//20 MHz BSS Width Request ++ ++ pframe = rtw_set_ie(pframe, EID_BSSCoexistence, 1, &iedata, &(pattrib->pktlen)); ++ ++ } ++ ++ ++ // ++ _rtw_memset(ICS, 0, sizeof(ICS)); ++ if(pmlmepriv->num_sta_no_ht>0) ++ { ++ int i; ++ ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while(1) ++ { ++ int len; ++ u8 *p; ++ WLAN_BSSID_EX *pbss_network; ++ ++ if (rtw_end_of_queue_search(phead,plist)== _TRUE) ++ break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ plist = get_next(plist); ++ ++ pbss_network = (WLAN_BSSID_EX *)&pnetwork->network; ++ ++ p = rtw_get_ie(pbss_network->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pbss_network->IELength - _FIXED_IE_LENGTH_); ++ if((p==NULL) || (len==0))//non-HT ++ { ++ if((pbss_network->Configuration.DSConfig<=0) || (pbss_network->Configuration.DSConfig>14)) ++ continue; ++ ++ ICS[0][pbss_network->Configuration.DSConfig]=1; ++ ++ if(ICS[0][0] == 0) ++ ICS[0][0] = 1; ++ } ++ ++ } ++ ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ ++ for(i= 0;i<8;i++) ++ { ++ if(ICS[i][0] == 1) ++ { ++ int j, k = 0; ++ ++ InfoContent[k] = i; ++ //SET_BSS_INTOLERANT_ELE_REG_CLASS(InfoContent,i); ++ k++; ++ ++ for(j=1;j<=14;j++) ++ { ++ if(ICS[i][j]==1) ++ { ++ if(k<16) ++ { ++ InfoContent[k] = j; //channel number ++ //SET_BSS_INTOLERANT_ELE_CHANNEL(InfoContent+k, j); ++ k++; ++ } ++ } ++ } ++ ++ pframe = rtw_set_ie(pframe, EID_BSSIntolerantChlReport, k, InfoContent, &(pattrib->pktlen)); ++ ++ } ++ ++ } ++ ++ ++ } ++ ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++#endif //CONFIG_80211N_HT ++} ++ ++unsigned int send_delba(_adapter *padapter, u8 initiator, u8 *addr) ++{ ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *psta = NULL; ++ //struct recv_reorder_ctrl *preorder_ctrl; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u16 tid; ++ ++ if((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) ++ if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) ++ return _SUCCESS; ++ ++ psta = rtw_get_stainfo(pstapriv, addr); ++ if(psta==NULL) ++ return _SUCCESS; ++ ++ //DBG_871X("%s:%s\n", __FUNCTION__, (initiator==0)?"RX_DIR":"TX_DIR"); ++ ++ if(initiator==0) // recipient ++ { ++ for(tid = 0;tidrecvreorder_ctrl[tid].enable == _TRUE) ++ { ++ DBG_871X("rx agg disable tid(%d)\n",tid); ++ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid <<1) |initiator)&0x1F)); ++ psta->recvreorder_ctrl[tid].enable = _FALSE; ++ psta->recvreorder_ctrl[tid].indicate_seq = 0xffff; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d indicate_seq:%u \n", __FUNCTION__, __LINE__, ++ psta->recvreorder_ctrl[tid].indicate_seq); ++ #endif ++ } ++ } ++ } ++ else if(initiator == 1)// originator ++ { ++#ifdef CONFIG_80211N_HT ++ //DBG_871X("tx agg_enable_bitmap(0x%08x)\n", psta->htpriv.agg_enable_bitmap); ++ for(tid = 0;tidhtpriv.agg_enable_bitmap & BIT(tid)) ++ { ++ DBG_871X("tx agg disable tid(%d)\n",tid); ++ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid <<1) |initiator)&0x1F) ); ++ psta->htpriv.agg_enable_bitmap &= ~BIT(tid); ++ psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); ++ ++ } ++ } ++#endif //CONFIG_80211N_HT ++ } ++ ++ return _SUCCESS; ++ ++} ++ ++unsigned int send_beacon(_adapter *padapter) ++{ ++ u8 bxmitok = _FALSE; ++ int issue=0; ++ int poll = 0; ++//#ifdef CONFIG_CONCURRENT_MODE ++ //struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ //struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ //_adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ //struct mlme_priv *pbuddy_mlmepriv = &(pbuddy_adapter->mlmepriv); ++//#endif ++ ++#ifdef CONFIG_PCI_HCI ++ ++ //DBG_871X("%s\n", __FUNCTION__); ++ ++ issue_beacon(padapter, 0); ++ ++ return _SUCCESS; ++ ++#endif ++ ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ u32 start = rtw_get_current_time(); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); ++ do{ ++ issue_beacon(padapter, 100); ++ issue++; ++ do { ++ rtw_yield_os(); ++ rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bxmitok)); ++ poll++; ++ }while((poll%10)!=0 && _FALSE == bxmitok && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); ++ ++ }while(_FALSE == bxmitok && issue<100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); ++ ++ if(padapter->bSurpriseRemoved || padapter->bDriverStopped) ++ { ++ return _FAIL; ++ } ++ ++ ++ if(_FALSE == bxmitok) ++ { ++ DBG_871X("%s fail! %u ms\n", __FUNCTION__, rtw_get_passing_time_ms(start)); ++ return _FAIL; ++ } ++ else ++ { ++ u32 passing_time = rtw_get_passing_time_ms(start); ++ ++ if(passing_time > 100 || issue > 3) ++ DBG_871X("%s success, issue:%d, poll:%d, %u ms\n", __FUNCTION__, issue, poll, rtw_get_passing_time_ms(start)); ++ //else ++ // DBG_871X("%s success, issue:%d, poll:%d, %u ms\n", __FUNCTION__, issue, poll, rtw_get_passing_time_ms(start)); ++ ++ return _SUCCESS; ++ } ++ ++#endif ++ ++} ++ ++/**************************************************************************** ++ ++Following are some utitity fuctions for WiFi MLME ++ ++*****************************************************************************/ ++ ++BOOLEAN IsLegal5GChannel( ++ IN PADAPTER Adapter, ++ IN u8 channel) ++{ ++ ++ int i=0; ++ u8 Channel_5G[45] = {36,38,40,42,44,46,48,50,52,54,56,58, ++ 60,62,64,100,102,104,106,108,110,112,114,116,118,120,122, ++ 124,126,128,130,132,134,136,138,140,149,151,153,155,157,159, ++ 161,163,165}; ++ for(i=0;imlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u32 initialgain = 0; ++ ++#ifdef CONFIG_P2P ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ ++#ifdef CONFIG_STA_MODE_SCAN_UNDER_AP_MODE ++ u8 stay_buddy_ch = 0; ++#endif //CONFIG_STA_MODE_SCAN_UNDER_AP_MODE ++ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ ++#endif //CONFIG_CONCURRENT_MODE ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ static unsigned char prev_survey_channel = 0; ++ static unsigned int p2p_scan_count = 0; ++ ++ if ( ( pwdinfo->rx_invitereq_info.scan_op_ch_only ) || ( pwdinfo->p2p_info.scan_op_ch_only ) ) ++ { ++ if ( pwdinfo->rx_invitereq_info.scan_op_ch_only ) ++ { ++ survey_channel = pwdinfo->rx_invitereq_info.operation_ch[pmlmeext->sitesurvey_res.channel_idx]; ++ } ++ else ++ { ++ survey_channel = pwdinfo->p2p_info.operation_ch[pmlmeext->sitesurvey_res.channel_idx]; ++ } ++ ScanType = SCAN_ACTIVE; ++ } ++ else if(rtw_p2p_findphase_ex_is_social(pwdinfo)) ++ { ++ // Commented by Albert 2011/06/03 ++ // The driver is in the find phase, it should go through the social channel. ++ int ch_set_idx; ++ survey_channel = pwdinfo->social_chan[pmlmeext->sitesurvey_res.channel_idx]; ++ ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, survey_channel); ++ if (ch_set_idx >= 0) ++ ScanType = pmlmeext->channel_set[ch_set_idx].ScanType; ++ else ++ ScanType = SCAN_ACTIVE; ++ } ++ else ++#endif //CONFIG_P2P ++ { ++ struct rtw_ieee80211_channel *ch; ++ if (pmlmeext->sitesurvey_res.channel_idx < pmlmeext->sitesurvey_res.ch_num) { ++ ch = &pmlmeext->sitesurvey_res.ch[pmlmeext->sitesurvey_res.channel_idx]; ++ survey_channel = ch->hw_value; ++ ScanType = (ch->flags & RTW_IEEE80211_CHAN_PASSIVE_SCAN) ? SCAN_PASSIVE : SCAN_ACTIVE; ++ } ++ } ++ ++ if (0){ ++#ifdef CONFIG_P2P ++ DBG_871X(FUNC_ADPT_FMT" ch:%u (cnt:%u,idx:%d) at %dms, %c%c%c\n" ++ , FUNC_ADPT_ARG(padapter) ++ , survey_channel ++ , pwdinfo->find_phase_state_exchange_cnt, pmlmeext->sitesurvey_res.channel_idx ++ , rtw_get_passing_time_ms(padapter->mlmepriv.scan_start_time) ++ , ScanType?'A':'P', pmlmeext->sitesurvey_res.scan_mode?'A':'P' ++ , pmlmeext->sitesurvey_res.ssid[0].SsidLength?'S':' ' ++ ); ++#endif ++ #ifdef DBG_FIXED_CHAN ++ DBG_871X(FUNC_ADPT_FMT" fixed_chan:%u\n", pmlmeext->fixed_chan); ++ #endif ++ } ++ ++ if(survey_channel != 0) ++ { ++ //PAUSE 4-AC Queue when site_survey ++ //rtw_hal_get_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); ++ //val8 |= 0x0f; ++ //rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); ++#ifdef CONFIG_CONCURRENT_MODE ++#ifdef CONFIG_STA_MODE_SCAN_UNDER_AP_MODE ++ if((padapter->pbuddy_adapter->mlmeextpriv.mlmext_info.state&0x03) == WIFI_FW_AP_STATE) ++ { ++ if( pmlmeinfo->scan_cnt == RTW_SCAN_NUM_OF_CH ) ++ { ++ pmlmeinfo->scan_cnt = 0; ++ survey_channel = pbuddy_mlmeext->cur_channel; ++ stay_buddy_ch = 1; ++ } ++ else ++ { ++ if( pmlmeinfo->scan_cnt == 0 ) ++ stay_buddy_ch = 2; ++ pmlmeinfo->scan_cnt++; ++ } ++ } ++#endif //CONFIG_STA_MODE_SCAN_UNDER_AP_MODE ++#endif //CONFIG_CONCURRENT_MODE ++ if(pmlmeext->sitesurvey_res.channel_idx == 0) ++ { ++#ifdef DBG_FIXED_CHAN ++ if(pmlmeext->fixed_chan !=0xff) ++ set_channel_bwmode(padapter, pmlmeext->fixed_chan, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ else ++#endif ++ set_channel_bwmode(padapter, survey_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ } ++ else ++ { ++#ifdef DBG_FIXED_CHAN ++ if(pmlmeext->fixed_chan!=0xff) ++ SelectChannel(padapter, pmlmeext->fixed_chan); ++ else ++#endif ++ SelectChannel(padapter, survey_channel); ++ } ++ ++#ifdef CONFIG_STA_MODE_SCAN_UNDER_AP_MODE ++ if( stay_buddy_ch == 1 ) ++ { ++ val8 = 0; //survey done ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ ++ if(check_buddy_mlmeinfo_state(padapter, WIFI_FW_AP_STATE) && ++ check_buddy_fwstate(padapter, _FW_LINKED)) ++ { ++ update_beacon(padapter->pbuddy_adapter, 0, NULL, _TRUE); ++ } ++ } ++ else if( stay_buddy_ch == 2 ) ++ { ++ val8 = 1; //under site survey ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ } ++#endif //CONFIG_STA_MODE_SCAN_UNDER_AP_MODE ++ ++ if(ScanType == SCAN_ACTIVE) //obey the channel plan setting... ++ { ++ #ifdef CONFIG_P2P ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || ++ rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH) ++ ) ++ { ++ issue_probereq_p2p(padapter, NULL); ++ issue_probereq_p2p(padapter, NULL); ++ issue_probereq_p2p(padapter, NULL); ++ } ++ else ++ #endif //CONFIG_P2P ++ { ++ int i; ++ for(i=0;isitesurvey_res.ssid[i].SsidLength) { ++ //todo: to issue two probe req??? ++ issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL); ++ //rtw_msleep_os(SURVEY_TO>>1); ++ issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL); ++ } ++ } ++ ++ if(pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) { ++ //todo: to issue two probe req??? ++ issue_probereq(padapter, NULL, NULL); ++ //rtw_msleep_os(SURVEY_TO>>1); ++ issue_probereq(padapter, NULL, NULL); ++ } ++ } ++ } ++#ifdef CONFIG_ATMEL_RC_PATCH ++ #ifdef CONFIG_P2P ++ if( !rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) && ++ !rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH) ++ ) ++ #endif//CONFIG_P2P ++ { ++ if(ScanType == SCAN_ACTIVE){ ++ if( check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE){ ++ if(survey_channel == pmlmeext->cur_channel ) ++ set_survey_timer(pmlmeext, 200); ++ else ++ set_survey_timer(pmlmeext, 20); ++ } ++ else{ ++ set_survey_timer(pmlmeext, 40); ++ } ++ } ++ else{//SCAN_PASSIVE ++ set_survey_timer(pmlmeext, pmlmeext->chan_scan_time); ++ } ++ } ++ else ++#endif //CONFIG_ATMEL_RC_PATCH ++ { ++#ifdef CONFIG_STA_MODE_SCAN_UNDER_AP_MODE ++ if( stay_buddy_ch == 1 ) ++ set_survey_timer(pmlmeext, pmlmeext->chan_scan_time * RTW_STAY_AP_CH_MILLISECOND ); ++ else ++#endif //CONFIG_STA_MODE_SCAN_UNDER_AP_MODE ++ set_survey_timer(pmlmeext, pmlmeext->chan_scan_time); ++ } ++ } ++ else ++ { ++ ++ // channel number is 0 or this channel is not valid. ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ u8 cur_channel; ++ u8 cur_bwmode; ++ u8 cur_ch_offset; ++ ++ if (rtw_get_ch_setting_union(padapter, &cur_channel, &cur_bwmode, &cur_ch_offset) != 0) ++ { ++ if (0) ++ DBG_871X(FUNC_ADPT_FMT" back to linked union - ch:%u, bw:%u, offset:%u\n", ++ FUNC_ADPT_ARG(padapter), cur_channel, cur_bwmode, cur_ch_offset); ++ } ++ #ifdef CONFIG_IOCTL_CFG80211 ++ else if(padapter->pbuddy_adapter ++ && pbuddy_adapter->wdinfo.driver_interface == DRIVER_CFG80211 ++ && wdev_to_priv(pbuddy_adapter->rtw_wdev)->p2p_enabled ++ && rtw_p2p_chk_state(&pbuddy_adapter->wdinfo, P2P_STATE_LISTEN) ++ ) ++ { ++ cur_channel = pbuddy_adapter->wdinfo.listen_channel; ++ cur_bwmode = pbuddy_mlmeext->cur_bwmode; ++ cur_ch_offset = pbuddy_mlmeext->cur_ch_offset; ++ } ++ #endif ++ else ++ { ++ cur_channel = pmlmeext->cur_channel; ++ cur_bwmode = pmlmeext->cur_bwmode; ++ cur_ch_offset = pmlmeext->cur_ch_offset; ++ } ++#endif ++ ++ ++#ifdef CONFIG_P2P ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) ++ { ++ if( ( pwdinfo->rx_invitereq_info.scan_op_ch_only ) || ( pwdinfo->p2p_info.scan_op_ch_only ) ) ++ { ++ // Set the find_phase_state_exchange_cnt to P2P_FINDPHASE_EX_CNT. ++ // This will let the following flow to run the scanning end. ++ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX); ++ } ++ #ifdef CONFIG_DBG_P2P ++ DBG_871X( "[%s] find phase exchange cnt = %d\n", __FUNCTION__, pwdinfo->find_phase_state_exchange_cnt ); ++ #endif ++ } ++ ++ if(rtw_p2p_findphase_ex_is_needed(pwdinfo)) ++ { ++ // Set the P2P State to the listen state of find phase and set the current channel to the listen channel ++ set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_LISTEN); ++ pmlmeext->sitesurvey_res.state = SCAN_DISABLE; ++ ++ initialgain = 0xff; //restore RX GAIN ++ rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); ++ //turn on dynamic functions ++ Restore_DM_Func_Flag(padapter); ++ //Switch_DM_Func(padapter, DYNAMIC_FUNC_DIG|DYNAMIC_FUNC_HP|DYNAMIC_FUNC_SS, _TRUE); ++ ++ _set_timer( &pwdinfo->find_phase_timer, ( u32 ) ( ( u32 ) ( pwdinfo->listen_dwell ) * 100 ) ); ++ } ++ else ++#endif //CONFIG_P2P ++ { ++ ++#ifdef CONFIG_STA_MODE_SCAN_UNDER_AP_MODE ++ pmlmeinfo->scan_cnt = 0; ++#endif //CONFIG_DMP_STA_NODE_SCAN_UNDER_AP_MODE ++ ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ // 20100721:Interrupt scan operation here. ++ // For SW antenna diversity before link, it needs to switch to another antenna and scan again. ++ // It compares the scan result and select beter one to do connection. ++ if(rtw_hal_antdiv_before_linked(padapter)) ++ { ++ pmlmeext->sitesurvey_res.bss_cnt = 0; ++ pmlmeext->sitesurvey_res.channel_idx = -1; ++ pmlmeext->chan_scan_time = SURVEY_TO /2; ++ set_survey_timer(pmlmeext, pmlmeext->chan_scan_time); ++ return; ++ } ++#endif ++ ++#ifdef CONFIG_P2P ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) ++ { ++ #ifdef CONFIG_CONCURRENT_MODE ++ if( pwdinfo->driver_interface == DRIVER_WEXT ) ++ { ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ _set_timer( &pwdinfo->ap_p2p_switch_timer, 500 ); ++ } ++ } ++ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); ++ #else ++ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); ++ #endif ++ } ++ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE); ++#endif //CONFIG_P2P ++ ++ pmlmeext->sitesurvey_res.state = SCAN_COMPLETE; ++ ++ //switch back to the original channel ++ //SelectChannel(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset); ++ ++ { ++#ifdef CONFIG_CONCURRENT_MODE ++ set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode); ++#else ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ dc_set_channel_bwmode_survey_done(padapter); ++#else ++ if( pwdinfo->driver_interface == DRIVER_WEXT ) ++ { ++ if( rtw_p2p_chk_state(pwdinfo, P2P_STATE_LISTEN) ) ++ { ++ set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ } ++ else ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ } ++ else if( pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ { ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ } ++#endif //CONFIG_DUALMAC_CONCURRENT ++#endif //CONFIG_CONCURRENT_MODE ++ } ++ ++ //flush 4-AC Queue after site_survey ++ //val8 = 0; ++ //rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); ++ ++ //config MSR ++ Set_MSR(padapter, (pmlmeinfo->state & 0x3)); ++ ++ initialgain = 0xff; //restore RX GAIN ++ rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); ++ //turn on dynamic functions ++ Restore_DM_Func_Flag(padapter); ++ //Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, _TRUE); ++ ++ if (is_client_associated_to_ap(padapter) == _TRUE) ++ { ++ issue_nulldata(padapter, NULL, 0, 3, 500); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(is_client_associated_to_ap(padapter->pbuddy_adapter) == _TRUE) ++ { ++ DBG_871X("adapter is surveydone(buddy_adapter is linked), issue nulldata(pwrbit=0)\n"); ++ ++ issue_nulldata(padapter->pbuddy_adapter, NULL, 0, 3, 500); ++ } ++#endif ++ } ++#ifdef CONFIG_CONCURRENT_MODE ++ else if(is_client_associated_to_ap(padapter->pbuddy_adapter) == _TRUE) ++ { ++ issue_nulldata(padapter->pbuddy_adapter, NULL, 0, 3, 500); ++ } ++#endif ++ ++ val8 = 0; //survey done ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ ++ report_surveydone_event(padapter); ++ ++#if defined(CONFIG_BT_COEXIST) && defined(CONFIG_RTL8723A) ++ if ((BT_1Ant(padapter) == _TRUE) && (BT_GetBtState(padapter) > BT_INFO_STATE_NO_CONNECTION)) ++ { ++ pmlmeext->chan_scan_time = SURVEY_TO * 2; ++ } ++ else ++ { ++ pmlmeext->chan_scan_time = SURVEY_TO; ++ } ++#else ++ pmlmeext->chan_scan_time = SURVEY_TO; ++#endif ++ ++ pmlmeext->sitesurvey_res.state = SCAN_DISABLE; ++ ++ issue_action_BSSCoexistPacket(padapter); ++ issue_action_BSSCoexistPacket(padapter); ++ issue_action_BSSCoexistPacket(padapter); ++ ++ } ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(check_buddy_mlmeinfo_state(padapter, WIFI_FW_AP_STATE) && ++ check_buddy_fwstate(padapter, _FW_LINKED)) ++ { ++ ++ DBG_871X("survey done, current CH=%d, BW=%d, offset=%d\n", cur_channel, cur_bwmode, cur_ch_offset); ++ ++ DBG_871X("restart pbuddy_adapter's beacon\n"); ++ ++ update_beacon(padapter->pbuddy_adapter, 0, NULL, _TRUE); ++ } ++#endif ++ ++ } ++ ++ return; ++ ++} ++ ++//collect bss info from Beacon and Probe request/response frames. ++u8 collect_bss_info(_adapter *padapter, union recv_frame *precv_frame, WLAN_BSSID_EX *bssid) ++{ ++ int i; ++ u32 len; ++ u8 *p; ++ u16 val16, subtype; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ u32 packet_len = precv_frame->u.hdr.len; ++ u8 ie_offset; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ len = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ if (len > MAX_IE_SZ) ++ { ++ //DBG_871X("IE too long for survey event\n"); ++ return _FAIL; ++ } ++ ++ _rtw_memset(bssid, 0, sizeof(WLAN_BSSID_EX)); ++ ++ subtype = GetFrameSubType(pframe); ++ ++ if(subtype==WIFI_BEACON) { ++ bssid->Reserved[0] = 1; ++ ie_offset = _BEACON_IE_OFFSET_; ++ } else { ++ // FIXME : more type ++ if (subtype == WIFI_PROBERSP) { ++ ie_offset = _PROBERSP_IE_OFFSET_; ++ bssid->Reserved[0] = 3; ++ } else if (subtype == WIFI_PROBEREQ) { ++ ie_offset = _PROBEREQ_IE_OFFSET_; ++ bssid->Reserved[0] = 2; ++ } else { ++ bssid->Reserved[0] = 0; ++ ie_offset = _FIXED_IE_LENGTH_; ++ } ++ } ++ ++ bssid->Length = sizeof(WLAN_BSSID_EX) - MAX_IE_SZ + len; ++ ++ //below is to copy the information element ++ bssid->IELength = len; ++ _rtw_memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength); ++ ++ //get the signal strength ++ //bssid->Rssi = precv_frame->u.hdr.attrib.SignalStrength; // 0-100 index. ++ bssid->Rssi = precv_frame->u.hdr.attrib.phy_info.RecvSignalPower; // in dBM.raw data ++ bssid->PhyInfo.SignalQuality = precv_frame->u.hdr.attrib.phy_info.SignalQuality;//in percentage ++ bssid->PhyInfo.SignalStrength = precv_frame->u.hdr.attrib.phy_info.SignalStrength;//in percentage ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ //rtw_hal_get_hwreg(padapter, HW_VAR_CURRENT_ANTENNA, (u8 *)(&bssid->PhyInfo.Optimum_antenna)); ++ rtw_hal_get_def_var(padapter, HAL_DEF_CURRENT_ANTENNA, &bssid->PhyInfo.Optimum_antenna); ++#endif ++ ++ // checking SSID ++ if ((p = rtw_get_ie(bssid->IEs + ie_offset, _SSID_IE_, &len, bssid->IELength - ie_offset)) == NULL) ++ { ++ DBG_871X("marc: cannot find SSID for survey event\n"); ++ return _FAIL; ++ } ++ ++ if (*(p + 1)) ++ { ++ if (len > NDIS_802_11_LENGTH_SSID) ++ { ++ DBG_871X("%s()-%d: IE too long (%d) for survey event\n", __FUNCTION__, __LINE__, len); ++ return _FAIL; ++ } ++ _rtw_memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1)); ++ bssid->Ssid.SsidLength = *(p + 1); ++ } ++ else ++ { ++ bssid->Ssid.SsidLength = 0; ++ } ++ ++ _rtw_memset(bssid->SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX); ++ ++ //checking rate info... ++ i = 0; ++ p = rtw_get_ie(bssid->IEs + ie_offset, _SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); ++ if (p != NULL) ++ { ++ if (len > NDIS_802_11_LENGTH_RATES_EX) ++ { ++ DBG_871X("%s()-%d: IE too long (%d) for survey event\n", __FUNCTION__, __LINE__, len); ++ return _FAIL; ++ } ++ _rtw_memcpy(bssid->SupportedRates, (p + 2), len); ++ i = len; ++ } ++ ++ p = rtw_get_ie(bssid->IEs + ie_offset, _EXT_SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); ++ if (p != NULL) ++ { ++ if (len > (NDIS_802_11_LENGTH_RATES_EX-i)) ++ { ++ DBG_871X("%s()-%d: IE too long (%d) for survey event\n", __FUNCTION__, __LINE__, len); ++ return _FAIL; ++ } ++ _rtw_memcpy(bssid->SupportedRates + i, (p + 2), len); ++ } ++ ++ //todo: ++#if 0 ++ if (judge_network_type(bssid->SupportedRates, (len + i)) == WIRELESS_11B) ++ { ++ bssid->NetworkTypeInUse = Ndis802_11DS; ++ } ++ else ++#endif ++ { ++ bssid->NetworkTypeInUse = Ndis802_11OFDM24; ++ } ++ ++ if (bssid->IELength < 12) ++ return _FAIL; ++ ++#ifdef CONFIG_P2P ++ if (subtype == WIFI_PROBEREQ) { ++ u8 *p2p_ie; ++ u32 p2p_ielen; ++ // Set Listion Channel ++ if ((p2p_ie = rtw_get_p2p_ie(bssid->IEs, bssid->IELength, NULL, &p2p_ielen))) { ++ u32 attr_contentlen = 0; ++ u8 listen_ch[5] = { 0x00 }; ++ ++ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_LISTEN_CH, listen_ch, &attr_contentlen); ++ bssid->Configuration.DSConfig = listen_ch[4]; ++ } ++ else { // use current channel ++ bssid->Configuration.DSConfig = rtw_get_oper_ch(padapter); ++ DBG_871X("%s()-%d: Cannot get p2p_ie. set DSconfig to op_ch(%d)\n", __FUNCTION__, __LINE__, bssid->Configuration.DSConfig); ++ } ++ ++ // FIXME ++ bssid->InfrastructureMode = Ndis802_11Infrastructure; ++ _rtw_memcpy(bssid->MacAddress, GetAddr2Ptr(pframe), ETH_ALEN); ++ bssid->Privacy = 1; ++ return _SUCCESS; ++ } ++#endif //CONFIG_P2P ++ ++ // Checking for DSConfig ++ p = rtw_get_ie(bssid->IEs + ie_offset, _DSSET_IE_, &len, bssid->IELength - ie_offset); ++ ++ bssid->Configuration.DSConfig = 0; ++ bssid->Configuration.Length = 0; ++ ++ if (p) ++ { ++ bssid->Configuration.DSConfig = *(p + 2); ++ } ++ else ++ {// In 5G, some ap do not have DSSET IE ++ // checking HT info for channel ++ p = rtw_get_ie(bssid->IEs + ie_offset, _HT_ADD_INFO_IE_, &len, bssid->IELength - ie_offset); ++ if(p) ++ { ++ struct HT_info_element *HT_info = (struct HT_info_element *)(p + 2); ++ bssid->Configuration.DSConfig = HT_info->primary_channel; ++ } ++ else ++ { // use current channel ++ bssid->Configuration.DSConfig = rtw_get_oper_ch(padapter); ++ } ++ } ++ ++ _rtw_memcpy(&bssid->Configuration.BeaconPeriod, rtw_get_beacon_interval_from_ie(bssid->IEs), 2); ++ bssid->Configuration.BeaconPeriod = le32_to_cpu(bssid->Configuration.BeaconPeriod); ++ ++ val16 = rtw_get_capability((WLAN_BSSID_EX *)bssid); ++ ++ if (val16 & BIT(0)) ++ { ++ bssid->InfrastructureMode = Ndis802_11Infrastructure; ++ _rtw_memcpy(bssid->MacAddress, GetAddr2Ptr(pframe), ETH_ALEN); ++ } ++ else ++ { ++ bssid->InfrastructureMode = Ndis802_11IBSS; ++ _rtw_memcpy(bssid->MacAddress, GetAddr3Ptr(pframe), ETH_ALEN); ++ } ++ ++ if (val16 & BIT(4)) ++ bssid->Privacy = 1; ++ else ++ bssid->Privacy = 0; ++ ++ bssid->Configuration.ATIMWindow = 0; ++ ++ //20/40 BSS Coexistence check ++ if((pregistrypriv->wifi_spec==1) && (_FALSE == pmlmeinfo->bwmode_updated)) ++ { ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++#ifdef CONFIG_80211N_HT ++ p = rtw_get_ie(bssid->IEs + ie_offset, _HT_CAPABILITY_IE_, &len, bssid->IELength - ie_offset); ++ if(p && len>0) ++ { ++ struct HT_caps_element *pHT_caps; ++ pHT_caps = (struct HT_caps_element *)(p + 2); ++ ++ if(pHT_caps->u.HT_cap_element.HT_caps_info&BIT(14)) ++ { ++ pmlmepriv->num_FortyMHzIntolerant++; ++ } ++ } ++ else ++ { ++ pmlmepriv->num_sta_no_ht++; ++ } ++#endif //CONFIG_80211N_HT ++ ++ } ++ ++#ifdef CONFIG_INTEL_WIDI ++ //process_intel_widi_query_or_tigger(padapter, bssid); ++ if(process_intel_widi_query_or_tigger(padapter, bssid)) ++ { ++ return _FAIL; ++ } ++#endif // CONFIG_INTEL_WIDI ++ ++ #if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) & 1 ++ if(strcmp(bssid->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) { ++ DBG_871X("Receiving %s("MAC_FMT", DSConfig:%u) from ch%u with ss:%3u, sq:%3u, RawRSSI:%3ld\n" ++ , bssid->Ssid.Ssid, MAC_ARG(bssid->MacAddress), bssid->Configuration.DSConfig ++ , rtw_get_oper_ch(padapter) ++ , bssid->PhyInfo.SignalStrength, bssid->PhyInfo.SignalQuality, bssid->Rssi ++ ); ++ } ++ #endif ++ ++ // mark bss info receving from nearby channel as SignalQuality 101 ++ if(bssid->Configuration.DSConfig != rtw_get_oper_ch(padapter)) ++ { ++ bssid->PhyInfo.SignalQuality= 101; ++ } ++ ++ return _SUCCESS; ++} ++ ++void start_create_ibss(_adapter* padapter) ++{ ++ unsigned short caps; ++ u8 val8; ++ u8 join_type; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX*)(&(pmlmeinfo->network)); ++ pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig; ++ pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork); ++ ++ //update wireless mode ++ update_wireless_mode(padapter); ++ ++ //udpate capability ++ caps = rtw_get_capability((WLAN_BSSID_EX *)pnetwork); ++ update_capinfo(padapter, caps); ++ if(caps&cap_IBSS)//adhoc master ++ { ++ //set_opmode_cmd(padapter, adhoc);//removed ++ ++ val8 = 0xcf; ++ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); ++ ++ //switch channel ++ //SelectChannel(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE); ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ ++ beacon_timing_control(padapter); ++ ++ //set msr to WIFI_FW_ADHOC_STATE ++ pmlmeinfo->state = WIFI_FW_ADHOC_STATE; ++ Set_MSR(padapter, (pmlmeinfo->state & 0x3)); ++ ++ //issue beacon ++ if(send_beacon(padapter)==_FAIL) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("issuing beacon frame fail....\n")); ++ ++ report_join_res(padapter, -1); ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ } ++ else ++ { ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, padapter->registrypriv.dev_network.MacAddress); ++ join_type = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); ++ ++ report_join_res(padapter, 1); ++ pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; ++ rtw_indicate_connect(padapter); ++ } ++ } ++ else ++ { ++ DBG_871X("start_create_ibss, invalid cap:%x\n", caps); ++ return; ++ } ++ //update bc/mc sta_info ++ update_bmc_sta(padapter); ++ ++} ++ ++void start_clnt_join(_adapter* padapter) ++{ ++ unsigned short caps; ++ u8 val8; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX*)(&(pmlmeinfo->network)); ++ int beacon_timeout; ++ ++ //update wireless mode ++ update_wireless_mode(padapter); ++ ++ //udpate capability ++ caps = rtw_get_capability((WLAN_BSSID_EX *)pnetwork); ++ update_capinfo(padapter, caps); ++ if (caps&cap_ESS) ++ { ++ Set_MSR(padapter, WIFI_FW_STATION_STATE); ++ ++ val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X)? 0xcc: 0xcf; ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ if (padapter->wapiInfo.bWapiEnable && pmlmeinfo->auth_algo == dot11AuthAlgrthm_WAPI) ++ { ++ //Disable TxUseDefaultKey, RxUseDefaultKey, RxBroadcastUseDefaultKey. ++ val8 = 0x4c; ++ } ++#endif ++ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); ++ ++ #ifdef CONFIG_DEAUTH_BEFORE_CONNECT ++ // Because of AP's not receiving deauth before ++ // AP may: 1)not response auth or 2)deauth us after link is complete ++ // issue deauth before issuing auth to deal with the situation ++ ++ // Commented by Albert 2012/07/21 ++ // For the Win8 P2P connection, it will be hard to have a successful connection if this Wi-Fi doesn't connect to it. ++ { ++ #ifdef CONFIG_P2P ++ _queue *queue = &(padapter->mlmepriv.scanned_queue); ++ _list *head = get_list_head(queue); ++ _list *pos = get_next(head); ++ struct wlan_network *scanned = NULL; ++ u8 ie_offset = 0; ++ _irqL irqL; ++ bool has_p2p_ie = _FALSE; ++ ++ _enter_critical_bh(&(padapter->mlmepriv.scanned_queue.lock), &irqL); ++ ++ for (pos = get_next(head);!rtw_end_of_queue_search(head, pos); pos = get_next(pos)) { ++ ++ scanned = LIST_CONTAINOR(pos, struct wlan_network, list); ++ if(scanned==NULL) ++ rtw_warn_on(1); ++ ++ if (_rtw_memcmp(&(scanned->network.Ssid), &(pnetwork->Ssid), sizeof(NDIS_802_11_SSID)) == _TRUE ++ && _rtw_memcmp(scanned->network.MacAddress, pnetwork->MacAddress, sizeof(NDIS_802_11_MAC_ADDRESS)) == _TRUE ++ ) { ++ ie_offset = (scanned->network.Reserved[0] == 2? 0:12); ++ if (rtw_get_p2p_ie(scanned->network.IEs+ie_offset, scanned->network.IELength-ie_offset, NULL, NULL)) ++ has_p2p_ie = _TRUE; ++ break; ++ } ++ } ++ ++ _exit_critical_bh(&(padapter->mlmepriv.scanned_queue.lock), &irqL); ++ ++ if (scanned == NULL || rtw_end_of_queue_search(head, pos) || has_p2p_ie == _FALSE) ++ #endif /* CONFIG_P2P */ ++ issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, 5, 100); ++ } ++ #endif /* CONFIG_DEAUTH_BEFORE_CONNECT */ ++ ++ //here wait for receiving the beacon to start auth ++ //and enable a timer ++ beacon_timeout = decide_wait_for_beacon_timeout(pmlmeinfo->bcn_interval); ++ set_link_timer(pmlmeext, beacon_timeout); ++ _set_timer( &padapter->mlmepriv.assoc_timer, ++ (REAUTH_TO * REAUTH_LIMIT) + (REASSOC_TO*REASSOC_LIMIT) +beacon_timeout); ++ ++ pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE; ++ ++ {//only for STA mode ++ u16 media_status; ++ u8 mac_id = 0; ++ ++ #ifdef CONFIG_CONCURRENT_MODE ++ if(PRIMARY_ADAPTER == padapter->adapter_type) ++ mac_id=0; ++ else ++ mac_id=2; ++ #endif ++ media_status = (mac_id<<8)|1; // MACID|OPMODE:1 connect ++ rtw_hal_set_hwreg(padapter,HW_VAR_H2C_MEDIA_STATUS_RPT,(u8 *)&media_status); ++ } ++ } ++ else if (caps&cap_IBSS) //adhoc client ++ { ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ if(dc_handle_join_request(padapter) == _FAIL) ++ { ++ DBG_871X("dc_handle_join_request for Ad-hoc fail !!!\n"); ++ return; ++ } ++#endif ++ ++ Set_MSR(padapter, WIFI_FW_ADHOC_STATE); ++ ++ val8 = 0xcf; ++ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); ++ ++ beacon_timing_control(padapter); ++ ++ pmlmeinfo->state = WIFI_FW_ADHOC_STATE; ++ ++ report_join_res(padapter, 1); ++ } ++ else ++ { ++ //DBG_871X("marc: invalid cap:%x\n", caps); ++ return; ++ } ++ ++} ++ ++void start_clnt_auth(_adapter* padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ ++ pmlmeinfo->state &= (~WIFI_FW_AUTH_NULL); ++ pmlmeinfo->state |= WIFI_FW_AUTH_STATE; ++ ++ pmlmeinfo->auth_seq = 1; ++ pmlmeinfo->reauth_count = 0; ++ pmlmeinfo->reassoc_count = 0; ++ pmlmeinfo->link_count = 0; ++ pmlmeext->retry = 0; ++ ++ ++ DBG_871X_LEVEL(_drv_always_, "start auth\n"); ++ issue_auth(padapter, NULL, 0); ++ ++ set_link_timer(pmlmeext, REAUTH_TO); ++ ++} ++ ++ ++void start_clnt_assoc(_adapter* padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ ++ pmlmeinfo->state &= (~(WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE)); ++ pmlmeinfo->state |= (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE); ++ ++ issue_assocreq(padapter); ++ ++ set_link_timer(pmlmeext, REASSOC_TO); ++} ++ ++unsigned int receive_disconnect(_adapter *padapter, unsigned char *MacAddr, unsigned short reason) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ //check A3 ++ if (!(_rtw_memcmp(MacAddr, get_my_bssid(&pmlmeinfo->network), ETH_ALEN))) ++ return _SUCCESS; ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ if((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) ++ { ++ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) ++ { ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ report_del_sta_event(padapter, MacAddr, reason); ++ ++ } ++ else if (pmlmeinfo->state & WIFI_FW_LINKING_STATE) ++ { ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ report_join_res(padapter, -2); ++ } ++ } ++ ++ return _SUCCESS; ++} ++ ++#ifdef CONFIG_80211D ++static void process_80211d(PADAPTER padapter, WLAN_BSSID_EX *bssid) ++{ ++ struct registry_priv *pregistrypriv; ++ struct mlme_ext_priv *pmlmeext; ++ RT_CHANNEL_INFO *chplan_new; ++ u8 channel; ++ u8 i; ++ ++ ++ pregistrypriv = &padapter->registrypriv; ++ pmlmeext = &padapter->mlmeextpriv; ++ ++ // Adjust channel plan by AP Country IE ++ if (pregistrypriv->enable80211d && ++ (!pmlmeext->update_channel_plan_by_ap_done)) ++ { ++ u8 *ie, *p; ++ u32 len; ++ RT_CHANNEL_PLAN chplan_ap; ++ RT_CHANNEL_INFO chplan_sta[MAX_CHANNEL_NUM]; ++ u8 country[4]; ++ u8 fcn; // first channel number ++ u8 noc; // number of channel ++ u8 j, k; ++ ++ ie = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _COUNTRY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); ++ if (!ie) return; ++ if (len < 6) return; ++ ++ ie += 2; ++ p = ie; ++ ie += len; ++ ++ _rtw_memset(country, 0, 4); ++ _rtw_memcpy(country, p, 3); ++ p += 3; ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ++ ("%s: 802.11d country=%s\n", __FUNCTION__, country)); ++ ++ i = 0; ++ while ((ie - p) >= 3) ++ { ++ fcn = *(p++); ++ noc = *(p++); ++ p++; ++ ++ for (j = 0; j < noc; j++) ++ { ++ if (fcn <= 14) channel = fcn + j; // 2.4 GHz ++ else channel = fcn + j*4; // 5 GHz ++ ++ chplan_ap.Channel[i++] = channel; ++ } ++ } ++ chplan_ap.Len = i; ++ ++#ifdef CONFIG_DEBUG_RTL871X ++#ifdef PLATFORM_LINUX ++ i = 0; ++ DBG_871X("%s: AP[%s] channel plan {", __func__, bssid->Ssid.Ssid); ++ while ((i < chplan_ap.Len) && (chplan_ap.Channel[i] != 0)) ++ { ++ DBG_8192C("%02d,", chplan_ap.Channel[i]); ++ i++; ++ } ++ DBG_871X("}\n"); ++#endif ++#endif ++ ++ _rtw_memcpy(chplan_sta, pmlmeext->channel_set, sizeof(chplan_sta)); ++#ifdef CONFIG_DEBUG_RTL871X ++#ifdef PLATFORM_LINUX ++ i = 0; ++ DBG_871X("%s: STA channel plan {", __func__); ++ while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) ++ { ++ DBG_871X("%02d(%c),", chplan_sta[i].ChannelNum, chplan_sta[i].ScanType==SCAN_PASSIVE?'p':'a'); ++ i++; ++ } ++ DBG_871X("}\n"); ++#endif ++#endif ++ ++ _rtw_memset(pmlmeext->channel_set, 0, sizeof(pmlmeext->channel_set)); ++ chplan_new = pmlmeext->channel_set; ++ ++ i = j = k = 0; ++ if (pregistrypriv->wireless_mode & WIRELESS_11G) ++ { ++ do { ++ if ((i == MAX_CHANNEL_NUM) || ++ (chplan_sta[i].ChannelNum == 0) || ++ (chplan_sta[i].ChannelNum > 14)) ++ break; ++ ++ if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] > 14)) ++ break; ++ ++ if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) ++ { ++ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; ++ chplan_new[k].ScanType = SCAN_ACTIVE; ++ i++; ++ j++; ++ k++; ++ } ++ else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) ++ { ++ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; ++// chplan_new[k].ScanType = chplan_sta[i].ScanType; ++ chplan_new[k].ScanType = SCAN_PASSIVE; ++ i++; ++ k++; ++ } ++ else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) ++ { ++ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; ++ chplan_new[k].ScanType = SCAN_ACTIVE; ++ j++; ++ k++; ++ } ++ } while (1); ++ ++ // change AP not support channel to Passive scan ++ while ((i < MAX_CHANNEL_NUM) && ++ (chplan_sta[i].ChannelNum != 0) && ++ (chplan_sta[i].ChannelNum <= 14)) ++ { ++ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; ++// chplan_new[k].ScanType = chplan_sta[i].ScanType; ++ chplan_new[k].ScanType = SCAN_PASSIVE; ++ i++; ++ k++; ++ } ++ ++ // add channel AP supported ++ while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) ++ { ++ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; ++ chplan_new[k].ScanType = SCAN_ACTIVE; ++ j++; ++ k++; ++ } ++ } ++ else ++ { ++ // keep original STA 2.4G channel plan ++ while ((i < MAX_CHANNEL_NUM) && ++ (chplan_sta[i].ChannelNum != 0) && ++ (chplan_sta[i].ChannelNum <= 14)) ++ { ++ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; ++ chplan_new[k].ScanType = chplan_sta[i].ScanType; ++ i++; ++ k++; ++ } ++ ++ // skip AP 2.4G channel plan ++ while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) ++ { ++ j++; ++ } ++ } ++ ++ if (pregistrypriv->wireless_mode & WIRELESS_11A) ++ { ++ do { ++ if ((i == MAX_CHANNEL_NUM) || ++ (chplan_sta[i].ChannelNum == 0)) ++ break; ++ ++ if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] == 0)) ++ break; ++ ++ if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) ++ { ++ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; ++ chplan_new[k].ScanType = SCAN_ACTIVE; ++ i++; ++ j++; ++ k++; ++ } ++ else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) ++ { ++ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; ++// chplan_new[k].ScanType = chplan_sta[i].ScanType; ++ chplan_new[k].ScanType = SCAN_PASSIVE; ++ i++; ++ k++; ++ } ++ else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) ++ { ++ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; ++ chplan_new[k].ScanType = SCAN_ACTIVE; ++ j++; ++ k++; ++ } ++ } while (1); ++ ++ // change AP not support channel to Passive scan ++ while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) ++ { ++ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; ++// chplan_new[k].ScanType = chplan_sta[i].ScanType; ++ chplan_new[k].ScanType = SCAN_PASSIVE; ++ i++; ++ k++; ++ } ++ ++ // add channel AP supported ++ while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] != 0)) ++ { ++ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; ++ chplan_new[k].ScanType = SCAN_ACTIVE; ++ j++; ++ k++; ++ } ++ } ++ else ++ { ++ // keep original STA 5G channel plan ++ while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) ++ { ++ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; ++ chplan_new[k].ScanType = chplan_sta[i].ScanType; ++ i++; ++ k++; ++ } ++ } ++ ++ pmlmeext->update_channel_plan_by_ap_done = 1; ++ ++#ifdef CONFIG_DEBUG_RTL871X ++#ifdef PLATFORM_LINUX ++ k = 0; ++ DBG_871X("%s: new STA channel plan {", __func__); ++ while ((k < MAX_CHANNEL_NUM) && (chplan_new[k].ChannelNum != 0)) ++ { ++ DBG_871X("%02d(%c),", chplan_new[k].ChannelNum, chplan_new[k].ScanType==SCAN_PASSIVE?'p':'c'); ++ k++; ++ } ++ DBG_871X("}\n"); ++#endif ++#endif ++ ++#if 0 ++ // recover the right channel index ++ channel = chplan_sta[pmlmeext->sitesurvey_res.channel_idx].ChannelNum; ++ k = 0; ++ while ((k < MAX_CHANNEL_NUM) && (chplan_new[k].ChannelNum != 0)) ++ { ++ if (chplan_new[k].ChannelNum == channel) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ++ ("%s: change mlme_ext sitesurvey channel index from %d to %d\n", ++ __FUNCTION__, pmlmeext->sitesurvey_res.channel_idx, k)); ++ pmlmeext->sitesurvey_res.channel_idx = k; ++ break; ++ } ++ k++; ++ } ++#endif ++ } ++ ++ // If channel is used by AP, set channel scan type to active ++ channel = bssid->Configuration.DSConfig; ++ chplan_new = pmlmeext->channel_set; ++ i = 0; ++ while ((i < MAX_CHANNEL_NUM) && (chplan_new[i].ChannelNum != 0)) ++ { ++ if (chplan_new[i].ChannelNum == channel) ++ { ++ if (chplan_new[i].ScanType == SCAN_PASSIVE) ++ { ++ //5G Bnad 2, 3 (DFS) doesn't change to active scan ++ if(channel >= 52 && channel <= 144) ++ break; ++ ++ chplan_new[i].ScanType = SCAN_ACTIVE; ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ++ ("%s: change channel %d scan type from passive to active\n", ++ __FUNCTION__, channel)); ++ } ++ break; ++ } ++ i++; ++ } ++} ++#endif ++ ++/**************************************************************************** ++ ++Following are the functions to report events ++ ++*****************************************************************************/ ++ ++void report_survey_event(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ struct cmd_obj *pcmd_obj; ++ u8 *pevtcmd; ++ u32 cmdsz; ++ struct survey_event *psurvey_evt; ++ struct C2HEvent_Header *pc2h_evt_hdr; ++ struct mlme_ext_priv *pmlmeext; ++ struct cmd_priv *pcmdpriv; ++ //u8 *pframe = precv_frame->u.hdr.rx_data; ++ //uint len = precv_frame->u.hdr.len; ++ ++ if(!padapter) ++ return; ++ ++ pmlmeext = &padapter->mlmeextpriv; ++ pcmdpriv = &padapter->cmdpriv; ++ ++ ++ if ((pcmd_obj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ return; ++ } ++ ++ cmdsz = (sizeof(struct survey_event) + sizeof(struct C2HEvent_Header)); ++ if ((pevtcmd = (u8*)rtw_zmalloc(cmdsz)) == NULL) ++ { ++ rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj)); ++ return; ++ } ++ ++ _rtw_init_listhead(&pcmd_obj->list); ++ ++ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); ++ pcmd_obj->cmdsz = cmdsz; ++ pcmd_obj->parmbuf = pevtcmd; ++ ++ pcmd_obj->rsp = NULL; ++ pcmd_obj->rspsz = 0; ++ ++ pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd); ++ pc2h_evt_hdr->len = sizeof(struct survey_event); ++ pc2h_evt_hdr->ID = GEN_EVT_CODE(_Survey); ++ pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); ++ ++ psurvey_evt = (struct survey_event*)(pevtcmd + sizeof(struct C2HEvent_Header)); ++ ++ if (collect_bss_info(padapter, precv_frame, (WLAN_BSSID_EX *)&psurvey_evt->bss) == _FAIL) ++ { ++ rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj)); ++ rtw_mfree((u8 *)pevtcmd, cmdsz); ++ return; ++ } ++ ++#ifdef CONFIG_80211D ++ process_80211d(padapter, &psurvey_evt->bss); ++#endif ++ ++ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); ++ ++ pmlmeext->sitesurvey_res.bss_cnt++; ++ ++ return; ++ ++} ++ ++void report_surveydone_event(_adapter *padapter) ++{ ++ struct cmd_obj *pcmd_obj; ++ u8 *pevtcmd; ++ u32 cmdsz; ++ struct surveydone_event *psurveydone_evt; ++ struct C2HEvent_Header *pc2h_evt_hdr; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ if ((pcmd_obj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ return; ++ } ++ ++ cmdsz = (sizeof(struct surveydone_event) + sizeof(struct C2HEvent_Header)); ++ if ((pevtcmd = (u8*)rtw_zmalloc(cmdsz)) == NULL) ++ { ++ rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj)); ++ return; ++ } ++ ++ _rtw_init_listhead(&pcmd_obj->list); ++ ++ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); ++ pcmd_obj->cmdsz = cmdsz; ++ pcmd_obj->parmbuf = pevtcmd; ++ ++ pcmd_obj->rsp = NULL; ++ pcmd_obj->rspsz = 0; ++ ++ pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd); ++ pc2h_evt_hdr->len = sizeof(struct surveydone_event); ++ pc2h_evt_hdr->ID = GEN_EVT_CODE(_SurveyDone); ++ pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); ++ ++ psurveydone_evt = (struct surveydone_event*)(pevtcmd + sizeof(struct C2HEvent_Header)); ++ psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt; ++ ++ DBG_871X("survey done event(%x)\n", psurveydone_evt->bss_cnt); ++ ++ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); ++ ++ return; ++ ++} ++ ++void report_join_res(_adapter *padapter, int res) ++{ ++ struct cmd_obj *pcmd_obj; ++ u8 *pevtcmd; ++ u32 cmdsz; ++ struct joinbss_event *pjoinbss_evt; ++ struct C2HEvent_Header *pc2h_evt_hdr; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ if ((pcmd_obj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ return; ++ } ++ ++ cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header)); ++ if ((pevtcmd = (u8*)rtw_zmalloc(cmdsz)) == NULL) ++ { ++ rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj)); ++ return; ++ } ++ ++ _rtw_init_listhead(&pcmd_obj->list); ++ ++ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); ++ pcmd_obj->cmdsz = cmdsz; ++ pcmd_obj->parmbuf = pevtcmd; ++ ++ pcmd_obj->rsp = NULL; ++ pcmd_obj->rspsz = 0; ++ ++ pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd); ++ pc2h_evt_hdr->len = sizeof(struct joinbss_event); ++ pc2h_evt_hdr->ID = GEN_EVT_CODE(_JoinBss); ++ pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); ++ ++ pjoinbss_evt = (struct joinbss_event*)(pevtcmd + sizeof(struct C2HEvent_Header)); ++ _rtw_memcpy((unsigned char *)(&(pjoinbss_evt->network.network)), &(pmlmeinfo->network), sizeof(WLAN_BSSID_EX)); ++ pjoinbss_evt->network.join_res = pjoinbss_evt->network.aid = res; ++ ++ DBG_871X("report_join_res(%d)\n", res); ++ ++ ++ rtw_joinbss_event_prehandle(padapter, (u8 *)&pjoinbss_evt->network); ++ ++ ++ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); ++ ++ return; ++ ++} ++ ++void report_del_sta_event(_adapter *padapter, unsigned char* MacAddr, unsigned short reason) ++{ ++ struct cmd_obj *pcmd_obj; ++ u8 *pevtcmd; ++ u32 cmdsz; ++ struct sta_info *psta; ++ int mac_id; ++ struct stadel_event *pdel_sta_evt; ++ struct C2HEvent_Header *pc2h_evt_hdr; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ if ((pcmd_obj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ return; ++ } ++ ++ cmdsz = (sizeof(struct stadel_event) + sizeof(struct C2HEvent_Header)); ++ if ((pevtcmd = (u8*)rtw_zmalloc(cmdsz)) == NULL) ++ { ++ rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj)); ++ return; ++ } ++ ++ _rtw_init_listhead(&pcmd_obj->list); ++ ++ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); ++ pcmd_obj->cmdsz = cmdsz; ++ pcmd_obj->parmbuf = pevtcmd; ++ ++ pcmd_obj->rsp = NULL; ++ pcmd_obj->rspsz = 0; ++ ++ pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd); ++ pc2h_evt_hdr->len = sizeof(struct stadel_event); ++ pc2h_evt_hdr->ID = GEN_EVT_CODE(_DelSTA); ++ pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); ++ ++ pdel_sta_evt = (struct stadel_event*)(pevtcmd + sizeof(struct C2HEvent_Header)); ++ _rtw_memcpy((unsigned char *)(&(pdel_sta_evt->macaddr)), MacAddr, ETH_ALEN); ++ _rtw_memcpy((unsigned char *)(pdel_sta_evt->rsvd),(unsigned char *)(&reason),2); ++ ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, MacAddr); ++ if(psta) ++ mac_id = (int)psta->mac_id; ++ else ++ mac_id = (-1); ++ ++ pdel_sta_evt->mac_id = mac_id; ++ ++ DBG_871X("report_del_sta_event: delete STA, mac_id=%d\n", mac_id); ++ ++ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); ++ ++ return; ++} ++ ++void report_add_sta_event(_adapter *padapter, unsigned char* MacAddr, int cam_idx) ++{ ++ struct cmd_obj *pcmd_obj; ++ u8 *pevtcmd; ++ u32 cmdsz; ++ struct stassoc_event *padd_sta_evt; ++ struct C2HEvent_Header *pc2h_evt_hdr; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ if ((pcmd_obj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ return; ++ } ++ ++ cmdsz = (sizeof(struct stassoc_event) + sizeof(struct C2HEvent_Header)); ++ if ((pevtcmd = (u8*)rtw_zmalloc(cmdsz)) == NULL) ++ { ++ rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj)); ++ return; ++ } ++ ++ _rtw_init_listhead(&pcmd_obj->list); ++ ++ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); ++ pcmd_obj->cmdsz = cmdsz; ++ pcmd_obj->parmbuf = pevtcmd; ++ ++ pcmd_obj->rsp = NULL; ++ pcmd_obj->rspsz = 0; ++ ++ pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd); ++ pc2h_evt_hdr->len = sizeof(struct stassoc_event); ++ pc2h_evt_hdr->ID = GEN_EVT_CODE(_AddSTA); ++ pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); ++ ++ padd_sta_evt = (struct stassoc_event*)(pevtcmd + sizeof(struct C2HEvent_Header)); ++ _rtw_memcpy((unsigned char *)(&(padd_sta_evt->macaddr)), MacAddr, ETH_ALEN); ++ padd_sta_evt->cam_id = cam_idx; ++ ++ DBG_871X("report_add_sta_event: add STA\n"); ++ ++ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); ++ ++ return; ++} ++ ++ ++/**************************************************************************** ++ ++Following are the event callback functions ++ ++*****************************************************************************/ ++ ++//for sta/adhoc mode ++void update_sta_info(_adapter *padapter, struct sta_info *psta) ++{ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ //ERP ++ VCS_update(padapter, psta); ++ ++#ifdef CONFIG_80211N_HT ++ //HT ++ if(pmlmepriv->htpriv.ht_option) ++ { ++ psta->htpriv.ht_option = _TRUE; ++ ++ psta->htpriv.ampdu_enable = pmlmepriv->htpriv.ampdu_enable; ++ ++ if (support_short_GI(padapter, &(pmlmeinfo->HT_caps))) ++ psta->htpriv.sgi = _TRUE; ++ ++ psta->qos_option = _TRUE; ++ ++ } ++ else ++#endif //CONFIG_80211N_HT ++ { ++#ifdef CONFIG_80211N_HT ++ psta->htpriv.ht_option = _FALSE; ++ ++ psta->htpriv.ampdu_enable = _FALSE; ++ ++ psta->htpriv.sgi = _FALSE; ++#endif //CONFIG_80211N_HT ++ psta->qos_option = _FALSE; ++ ++ } ++#ifdef CONFIG_80211N_HT ++ psta->htpriv.bwmode = pmlmeext->cur_bwmode; ++ psta->htpriv.ch_offset = pmlmeext->cur_ch_offset; ++ ++ psta->htpriv.agg_enable_bitmap = 0x0;//reset ++ psta->htpriv.candidate_tid_bitmap = 0x0;//reset ++#endif //CONFIG_80211N_HT ++ ++ //QoS ++ if(pmlmepriv->qospriv.qos_option) ++ psta->qos_option = _TRUE; ++ ++ ++ psta->state = _FW_LINKED; ++ ++} ++ ++void mlmeext_joinbss_event_callback(_adapter *padapter, int join_res) ++{ ++ struct sta_info *psta, *psta_bmc; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 join_type; ++ u16 media_status; ++ ++ psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress); ++ ++ if(join_res < 0) ++ { ++ join_type = 1; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr); ++ ++ //restore to initial setting. ++ update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode); ++ ++ if (psta){//only for STA mode ++ media_status = (psta->mac_id<<8)|0; // MACID|OPMODE:1 connect ++ rtw_hal_set_hwreg(padapter,HW_VAR_H2C_MEDIA_STATUS_RPT,(u8 *)&media_status); ++ } ++ ++ goto exit_mlmeext_joinbss_event_callback; ++ } ++ ++ if((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) ++ { ++ //for bc/mc ++ psta_bmc = rtw_get_bcmc_stainfo(padapter); ++ if(psta_bmc) ++ { ++ pmlmeinfo->FW_sta_info[psta_bmc->mac_id].psta = psta_bmc; ++ update_bmc_sta_support_rate(padapter, psta_bmc->mac_id); ++ Update_RA_Entry(padapter, psta_bmc); ++ } ++ //update bc/mc sta_info ++ update_bmc_sta(padapter); ++ } ++ ++ ++ //turn on dynamic functions ++ Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, _TRUE); ++ ++ // update IOT-releated issue ++ update_IOT_info(padapter); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, cur_network->SupportedRates); ++ ++ //BCN interval ++ rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pmlmeinfo->bcn_interval)); ++ ++ //udpate capability ++ update_capinfo(padapter, pmlmeinfo->capability); ++ ++ //WMM, Update EDCA param ++ WMMOnAssocRsp(padapter); ++ ++ //HT ++ HTOnAssocRsp(padapter); ++ ++#ifndef CONFIG_CONCURRENT_MODE ++ // Call set_channel_bwmode when the CONFIG_CONCURRENT_MODE doesn't be defined. ++ //Set cur_channel&cur_bwmode&cur_ch_offset ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++#endif ++ ++ ++ if (psta) //only for infra. mode ++ { ++ pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta; ++ ++ //DBG_871X("set_sta_rate\n"); ++ ++ psta->wireless_mode = pmlmeext->cur_wireless_mode; ++ ++ //set per sta rate after updating HT cap. ++ set_sta_rate(padapter, psta); ++ ++ rtw_sta_media_status_rpt(padapter, psta, 1); ++ } ++ ++ join_type = 2; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); ++ ++ if((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) ++ { ++ // correcting TSF ++ correct_TSF(padapter, pmlmeext); ++ ++ //set_link_timer(pmlmeext, DISCONNECT_TO); ++ } ++ ++#ifdef CONFIG_LPS ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_CONNECT, 0); ++#endif ++ ++exit_mlmeext_joinbss_event_callback: ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ dc_handle_join_done(padapter, join_res); ++#endif ++#ifdef CONFIG_CONCURRENT_MODE ++ concurrent_chk_joinbss_done(padapter, join_res); ++#endif ++ ++ DBG_871X("=>%s\n", __FUNCTION__); ++ ++} ++ ++void mlmeext_sta_add_event_callback(_adapter *padapter, struct sta_info *psta) ++{ ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 join_type; ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ if((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) ++ { ++ if(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)//adhoc master or sta_count>1 ++ { ++ //nothing to do ++ } ++ else//adhoc client ++ { ++ //update TSF Value ++ //update_TSF(pmlmeext, pframe, len); ++ ++ // correcting TSF ++ correct_TSF(padapter, pmlmeext); ++ ++ //start beacon ++ if(send_beacon(padapter)==_FAIL) ++ { ++ pmlmeinfo->FW_sta_info[psta->mac_id].status = 0; ++ ++ pmlmeinfo->state ^= WIFI_FW_ADHOC_STATE; ++ ++ return; ++ } ++ ++ pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; ++ ++ } ++ ++ join_type = 2; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); ++ } ++ ++ pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta; ++ ++ //rate radaptive ++ Update_RA_Entry(padapter, psta); ++ ++ //update adhoc sta_info ++ update_sta_info(padapter, psta); ++ ++} ++ ++void mlmeext_sta_del_event_callback(_adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if (is_client_associated_to_ap(padapter) || is_IBSS_empty(padapter)) ++ { ++ //set_opmode_cmd(padapter, infra_client_with_mlme); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, 0); ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr); ++ ++ //restore to initial setting. ++ update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode); ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ dc_set_channel_bwmode_disconnect(padapter); ++#else ++#ifdef CONFIG_CONCURRENT_MODE ++ if((check_buddy_fwstate(padapter, _FW_LINKED)) != _TRUE) ++ { ++#endif //CONFIG_CONCURRENT_MODE ++ ++ //switch to the 20M Hz mode after disconnect ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ //SelectChannel(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset); ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ } ++#endif //CONFIG_CONCURRENT_MODE ++#endif //CONFIG_DUALMAC_CONCURRENT ++ ++ flush_all_cam_entry(padapter); ++ ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ ++ //set MSR to no link state -> infra. mode ++ Set_MSR(padapter, _HW_STATE_STATION_); ++ ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ ++ } ++ ++} ++ ++/**************************************************************************** ++ ++Following are the functions for the timer handlers ++ ++*****************************************************************************/ ++void _linked_rx_signal_strehgth_display(_adapter *padapter); ++void _linked_rx_signal_strehgth_display(_adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 mac_id; ++ int UndecoratedSmoothedPWDB; ++ #if 0 ++ DBG_871X("============ linked status check ===================\n"); ++ DBG_871X("pathA Rx SNRdb:%d, pathB Rx SNRdb:%d\n",padapter->recvpriv.RxSNRdB[0], padapter->recvpriv.RxSNRdB[1]); ++ DBG_871X("pathA Rx PWDB:%d\n",padapter->recvpriv.rxpwdb); ++ rtw_hal_get_def_var(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &UndecoratedSmoothedPWDB); ++ DBG_871X("UndecoratedSmoothedPWDB:%d\n",UndecoratedSmoothedPWDB); ++ DBG_871X("Rx RSSI:%d\n",padapter->recvpriv.rssi); ++ DBG_871X("Rx Signal_strength:%d\n",padapter->recvpriv.signal_strength); ++ DBG_871X("Rx Signal_qual:%d \n",padapter->recvpriv.signal_qual); ++ if ( check_fwstate( &padapter->mlmepriv, _FW_LINKED ) ) ++ { ++ DBG_871X("bw mode: %d, channel: %d\n", padapter->mlmeextpriv.cur_bwmode, padapter->mlmeextpriv.cur_channel ); ++ DBG_871X("received bytes = %d\n", (u32) (padapter->recvpriv.rx_bytes - padapter->recvpriv.last_rx_bytes ) ); ++ } ++ DBG_871X("============ linked status check ===================\n"); ++ #endif ++ if((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) ++ { ++ mac_id=0; ++ } ++ else if((pmlmeinfo->state&0x03) == _HW_STATE_AP_) ++ { ++ mac_id=2; ++ } ++ ++ rtw_hal_get_def_var(padapter, HW_DEF_RA_INFO_DUMP,&mac_id); ++ #if 0 ++ DBG_871X("============ RX GAIN / FALSE ALARM ===================\n"); ++ DBG_871X(" DIG PATH-A(0x%02x), PATH-B(0x%02x)\n",rtw_read8(padapter,0xc50),rtw_read8(padapter,0xc58)); ++ DBG_871X(" OFDM -Alarm DA2(0x%04x),DA4(0x%04x),DA6(0x%04x),DA8(0x%04x)\n", ++ rtw_read16(padapter,0xDA2),rtw_read16(padapter,0xDA4),rtw_read16(padapter,0xDA6),rtw_read16(padapter,0xDA8)); ++ ++ DBG_871X(" CCK -Alarm A5B(0x%02x),A5C(0x%02x)\n",rtw_read8(padapter,0xA5B),rtw_read8(padapter,0xA5C)); ++ #endif ++ ++ ++ //rtw_hal_get_def_var(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &UndecoratedSmoothedPWDB); ++ //DBG_871X("UndecoratedSmoothedPWDB:%d\n",UndecoratedSmoothedPWDB); ++ ++} ++ ++u8 chk_ap_is_alive(_adapter *padapter, struct sta_info *psta) ++{ ++ u8 ret = _FALSE; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ #ifdef DBG_EXPIRATION_CHK ++ DBG_871X(FUNC_ADPT_FMT" rx:"STA_PKTS_FMT", beacon:%llu, probersp_to_self:%llu" ++ /*", probersp_bm:%llu, probersp_uo:%llu, probereq:%llu, BI:%u"*/ ++ ", retry:%u\n" ++ , FUNC_ADPT_ARG(padapter) ++ , STA_RX_PKTS_DIFF_ARG(psta) ++ , psta->sta_stats.rx_beacon_pkts - psta->sta_stats.last_rx_beacon_pkts ++ , psta->sta_stats.rx_probersp_pkts - psta->sta_stats.last_rx_probersp_pkts ++ /*, psta->sta_stats.rx_probersp_bm_pkts - psta->sta_stats.last_rx_probersp_bm_pkts ++ , psta->sta_stats.rx_probersp_uo_pkts - psta->sta_stats.last_rx_probersp_uo_pkts ++ , psta->sta_stats.rx_probereq_pkts - psta->sta_stats.last_rx_probereq_pkts ++ , pmlmeinfo->bcn_interval*/ ++ , pmlmeext->retry ++ ); ++ ++ DBG_871X(FUNC_ADPT_FMT" tx_pkts:%llu, link_count:%u\n", FUNC_ADPT_ARG(padapter) ++ , padapter->xmitpriv.tx_pkts ++ , pmlmeinfo->link_count ++ ); ++ #endif ++ ++ if((sta_rx_data_pkts(psta) == sta_last_rx_data_pkts(psta)) ++ && sta_rx_beacon_pkts(psta) == sta_last_rx_beacon_pkts(psta) ++ && sta_rx_probersp_pkts(psta) == sta_last_rx_probersp_pkts(psta) ++ ) ++ { ++ ret = _FALSE; ++ } ++ else ++ { ++ ret = _TRUE; ++ } ++ ++ sta_update_last_rx_pkts(psta); ++ ++ return ret; ++} ++ ++void linked_status_chk(_adapter *padapter) ++{ ++ u32 i; ++ struct sta_info *psta; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ if(padapter->bRxRSSIDisplay) ++ _linked_rx_signal_strehgth_display(padapter); ++ ++ #ifdef DBG_CONFIG_ERROR_DETECT ++ rtw_hal_sreset_linked_status_check(padapter); ++ #endif ++ ++ if (is_client_associated_to_ap(padapter)) ++ { ++ //linked infrastructure client mode ++ ++ int tx_chk = _SUCCESS, rx_chk = _SUCCESS; ++ int rx_chk_limit; ++ ++ #if defined(DBG_ROAMING_TEST) ++ rx_chk_limit = 1; ++ #elif defined(CONFIG_ACTIVE_KEEP_ALIVE_CHECK) ++ rx_chk_limit = 4; ++ #else ++ rx_chk_limit = 8; ++ #endif ++ ++ // Marked by Kurt 20130715 ++ // For WiDi 3.5 and latered on, they don't ask WiDi sink to do roaming, so we could not check rx limit that strictly. ++ // todo: To check why we under miracast session, rx_chk would be _FALSE ++ //#ifdef CONFIG_INTEL_WIDI ++ //if (padapter->mlmepriv.widi_state != INTEL_WIDI_STATE_NONE) ++ // rx_chk_limit = 1; ++ //#endif ++ ++ if ((psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress)) != NULL) ++ { ++ bool is_p2p_enable = _FALSE; ++ #ifdef CONFIG_P2P ++ is_p2p_enable = !rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE); ++ #endif ++ ++ if (chk_ap_is_alive(padapter, psta) == _FALSE) ++ rx_chk = _FAIL; ++ ++ if (pxmitpriv->last_tx_pkts == pxmitpriv->tx_pkts) ++ tx_chk = _FAIL; ++ ++ #ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK ++ if (pmlmeext->active_keep_alive_check && (rx_chk == _FAIL || tx_chk == _FAIL)) { ++ u8 backup_oper_channel=0; ++ ++ /* switch to correct channel of current network before issue keep-alive frames */ ++ if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) { ++ backup_oper_channel = rtw_get_oper_ch(padapter); ++ SelectChannel(padapter, pmlmeext->cur_channel); ++ } ++ ++ if (rx_chk != _SUCCESS) ++ issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, psta->hwaddr, 3, 1); ++ ++ if ((tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf) || rx_chk != _SUCCESS) { ++ tx_chk = issue_nulldata(padapter, psta->hwaddr, 0, 3, 1); ++ /* if tx acked and p2p disabled, set rx_chk _SUCCESS to reset retry count */ ++ if (tx_chk == _SUCCESS && !is_p2p_enable) ++ rx_chk = _SUCCESS; ++ } ++ ++ /* back to the original operation channel */ ++ if(backup_oper_channel>0) ++ SelectChannel(padapter, backup_oper_channel); ++ ++ } ++ else ++ #endif /* CONFIG_ACTIVE_KEEP_ALIVE_CHECK */ ++ { ++ if (rx_chk != _SUCCESS) { ++ if (pmlmeext->retry == 0) { ++ #ifdef DBG_EXPIRATION_CHK ++ DBG_871X("issue_probereq to trigger probersp, retry=%d\n", pmlmeext->retry); ++ #endif ++ issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress); ++ issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress); ++ issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress); ++ } ++ } ++ ++ if (tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf) { ++ #ifdef DBG_EXPIRATION_CHK ++ DBG_871X("%s issue_nulldata 0\n", __FUNCTION__); ++ #endif ++ tx_chk = issue_nulldata(padapter, NULL, 0, 1, 0); ++ } ++ } ++ ++ if (rx_chk == _FAIL) { ++ pmlmeext->retry++; ++ if (pmlmeext->retry > rx_chk_limit) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" disconnect or roaming\n", ++ FUNC_ADPT_ARG(padapter)); ++ receive_disconnect(padapter, pmlmeinfo->network.MacAddress ++ , WLAN_REASON_EXPIRATION_CHK); ++ return; ++ } ++ } else { ++ pmlmeext->retry = 0; ++ } ++ ++ if (tx_chk == _FAIL) { ++ pmlmeinfo->link_count &= 0xf; ++ } else { ++ pxmitpriv->last_tx_pkts = pxmitpriv->tx_pkts; ++ pmlmeinfo->link_count = 0; ++ } ++ ++ } //end of if ((psta = rtw_get_stainfo(pstapriv, passoc_res->network.MacAddress)) != NULL) ++ } ++ else if (is_client_associated_to_ibss(padapter)) ++ { ++ //linked IBSS mode ++ //for each assoc list entry to check the rx pkt counter ++ for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) ++ { ++ if (pmlmeinfo->FW_sta_info[i].status == 1) ++ { ++ psta = pmlmeinfo->FW_sta_info[i].psta; ++ ++ if(NULL==psta) continue; ++ ++ if (pmlmeinfo->FW_sta_info[i].rx_pkt == sta_rx_pkts(psta)) ++ { ++ ++ if(pmlmeinfo->FW_sta_info[i].retry<3) ++ { ++ pmlmeinfo->FW_sta_info[i].retry++; ++ } ++ else ++ { ++ pmlmeinfo->FW_sta_info[i].retry = 0; ++ pmlmeinfo->FW_sta_info[i].status = 0; ++ report_del_sta_event(padapter, psta->hwaddr ++ , 65535// indicate disconnect caused by no rx ++ ); ++ } ++ } ++ else ++ { ++ pmlmeinfo->FW_sta_info[i].retry = 0; ++ pmlmeinfo->FW_sta_info[i].rx_pkt = (u32)sta_rx_pkts(psta); ++ } ++ } ++ } ++ ++ //set_link_timer(pmlmeext, DISCONNECT_TO); ++ ++ } ++ ++} ++ ++void survey_timer_hdl(_adapter *padapter) ++{ ++ struct cmd_obj *ph2c; ++ struct sitesurvey_parm *psurveyPara; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++#endif ++ ++ //DBG_871X("marc: survey timer\n"); ++#ifdef PLATFORM_FREEBSD ++ rtw_mtx_lock(NULL); ++ if (callout_pending(&padapter->mlmeextpriv.survey_timer.callout)) { ++ /* callout was reset */ ++ //mtx_unlock(&sc->sc_mtx); ++ rtw_mtx_unlock(NULL); ++ return; ++ } ++ if (!callout_active(&padapter->mlmeextpriv.survey_timer.callout)) { ++ /* callout was stopped */ ++ //mtx_unlock(&sc->sc_mtx); ++ rtw_mtx_unlock(NULL); ++ return; ++ } ++ callout_deactivate(&padapter->mlmeextpriv.survey_timer.callout); ++ ++ ++#endif ++ ++ //issue rtw_sitesurvey_cmd ++ if (pmlmeext->sitesurvey_res.state > SCAN_START) ++ { ++ if(pmlmeext->sitesurvey_res.state == SCAN_PROCESS) ++ { ++#ifdef CONFIG_STA_MODE_SCAN_UNDER_AP_MODE ++ if( padapter->mlmeextpriv.mlmext_info.scan_cnt != RTW_SCAN_NUM_OF_CH ) ++#endif //CONFIG_STA_MODE_SCAN_UNDER_AP_MODE ++ pmlmeext->sitesurvey_res.channel_idx++; ++ } ++ ++ if(pmlmeext->scan_abort == _TRUE) ++ { ++ #ifdef CONFIG_P2P ++ if(!rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE)) ++ { ++ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX); ++ pmlmeext->sitesurvey_res.channel_idx = 3; ++ DBG_871X("%s idx:%d, cnt:%u\n", __FUNCTION__ ++ , pmlmeext->sitesurvey_res.channel_idx ++ , pwdinfo->find_phase_state_exchange_cnt ++ ); ++ } ++ else ++ #endif ++ { ++ pmlmeext->sitesurvey_res.channel_idx = pmlmeext->sitesurvey_res.ch_num; ++ DBG_871X("%s idx:%d\n", __FUNCTION__ ++ , pmlmeext->sitesurvey_res.channel_idx ++ ); ++ } ++ ++ pmlmeext->scan_abort = _FALSE;//reset ++ } ++ ++ if ((ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ goto exit_survey_timer_hdl; ++ } ++ ++ if ((psurveyPara = (struct sitesurvey_parm*)rtw_zmalloc(sizeof(struct sitesurvey_parm))) == NULL) ++ { ++ rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ goto exit_survey_timer_hdl; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey)); ++ rtw_enqueue_cmd(pcmdpriv, ph2c); ++ } ++ ++ ++exit_survey_timer_hdl: ++#ifdef PLATFORM_FREEBSD ++ rtw_mtx_unlock(NULL); ++#endif ++ ++ return; ++} ++ ++void link_timer_hdl(_adapter *padapter) ++{ ++ //static unsigned int rx_pkt = 0; ++ //static u64 tx_cnt = 0; ++ //struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ //struct sta_priv *pstapriv = &padapter->stapriv; ++ ++#ifdef PLATFORM_FREEBSD ++ rtw_mtx_lock(NULL); ++ if (callout_pending(&padapter->mlmeextpriv.survey_timer.callout)) { ++ /* callout was reset */ ++ //mtx_unlock(&sc->sc_mtx); ++ rtw_mtx_unlock(NULL); ++ return; ++ } ++ if (!callout_active(&padapter->mlmeextpriv.survey_timer.callout)) { ++ /* callout was stopped */ ++ //mtx_unlock(&sc->sc_mtx); ++ rtw_mtx_unlock(NULL); ++ return; ++ } ++ callout_deactivate(&padapter->mlmeextpriv.survey_timer.callout); ++ ++ ++#endif ++ ++ if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) ++ { ++ DBG_871X("link_timer_hdl:no beacon while connecting\n"); ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ report_join_res(padapter, -3); ++ } ++ else if (pmlmeinfo->state & WIFI_FW_AUTH_STATE) ++ { ++ //re-auth timer ++ if (++pmlmeinfo->reauth_count > REAUTH_LIMIT) ++ { ++ //if (pmlmeinfo->auth_algo != dot11AuthAlgrthm_Auto) ++ //{ ++ pmlmeinfo->state = 0; ++ report_join_res(padapter, -1); ++ return; ++ //} ++ //else ++ //{ ++ // pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; ++ // pmlmeinfo->reauth_count = 0; ++ //} ++ } ++ ++ DBG_871X("link_timer_hdl: auth timeout and try again\n"); ++ pmlmeinfo->auth_seq = 1; ++ issue_auth(padapter, NULL, 0); ++ set_link_timer(pmlmeext, REAUTH_TO); ++ } ++ else if (pmlmeinfo->state & WIFI_FW_ASSOC_STATE) ++ { ++ //re-assoc timer ++ if (++pmlmeinfo->reassoc_count > REASSOC_LIMIT) ++ { ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ report_join_res(padapter, -2); ++ return; ++ } ++ ++ DBG_871X("link_timer_hdl: assoc timeout and try again\n"); ++ issue_assocreq(padapter); ++ set_link_timer(pmlmeext, REASSOC_TO); ++ } ++#if 0 ++ else if (is_client_associated_to_ap(padapter)) ++ { ++ //linked infrastructure client mode ++ if ((psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress)) != NULL) ++ { ++ /*to monitor whether the AP is alive or not*/ ++ if (rx_pkt == psta->sta_stats.rx_pkts) ++ { ++ receive_disconnect(padapter, pmlmeinfo->network.MacAddress); ++ return; ++ } ++ else ++ { ++ rx_pkt = psta->sta_stats.rx_pkts; ++ set_link_timer(pmlmeext, DISCONNECT_TO); ++ } ++ ++ //update the EDCA paramter according to the Tx/RX mode ++ update_EDCA_param(padapter); ++ ++ /*to send the AP a nulldata if no frame is xmitted in order to keep alive*/ ++ if (pmlmeinfo->link_count++ == 0) ++ { ++ tx_cnt = pxmitpriv->tx_pkts; ++ } ++ else if ((pmlmeinfo->link_count & 0xf) == 0) ++ { ++ if (tx_cnt == pxmitpriv->tx_pkts) ++ { ++ issue_nulldata(padapter, NULL, 0, 0, 0); ++ } ++ ++ tx_cnt = pxmitpriv->tx_pkts; ++ } ++ } //end of if ((psta = rtw_get_stainfo(pstapriv, passoc_res->network.MacAddress)) != NULL) ++ } ++ else if (is_client_associated_to_ibss(padapter)) ++ { ++ //linked IBSS mode ++ //for each assoc list entry to check the rx pkt counter ++ for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) ++ { ++ if (pmlmeinfo->FW_sta_info[i].status == 1) ++ { ++ psta = pmlmeinfo->FW_sta_info[i].psta; ++ ++ if (pmlmeinfo->FW_sta_info[i].rx_pkt == psta->sta_stats.rx_pkts) ++ { ++ pmlmeinfo->FW_sta_info[i].status = 0; ++ report_del_sta_event(padapter, psta->hwaddr); ++ } ++ else ++ { ++ pmlmeinfo->FW_sta_info[i].rx_pkt = psta->sta_stats.rx_pkts; ++ } ++ } ++ } ++ ++ set_link_timer(pmlmeext, DISCONNECT_TO); ++ } ++#endif ++ ++#ifdef PLATFORM_FREEBSD ++ rtw_mtx_unlock(NULL); ++#endif ++ ++ return; ++} ++ ++void addba_timer_hdl(struct sta_info *psta) ++{ ++#ifdef CONFIG_80211N_HT ++ struct ht_priv *phtpriv; ++ ++ if(!psta) ++ return; ++ ++ phtpriv = &psta->htpriv; ++ ++ if((phtpriv->ht_option==_TRUE) && (phtpriv->ampdu_enable==_TRUE)) ++ { ++ if(phtpriv->candidate_tid_bitmap) ++ phtpriv->candidate_tid_bitmap=0x0; ++ ++ } ++#endif //CONFIG_80211N_HT ++} ++ ++#ifdef CONFIG_IEEE80211W ++void sa_query_timer_hdl(_adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_priv * pmlmepriv = &padapter->mlmepriv; ++ _irqL irqL; ++ //disconnect ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ++ { ++ rtw_disassoc_cmd(padapter, 0, _TRUE); ++ rtw_indicate_disconnect(padapter); ++ rtw_free_assoc_resources(padapter, 1); ++ } ++ ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ DBG_871X("SA query timeout disconnect\n"); ++} ++#endif //CONFIG_IEEE80211W ++ ++u8 NULL_hdl(_adapter *padapter, u8 *pbuf) ++{ ++ return H2C_SUCCESS; ++} ++ ++u8 setopmode_hdl(_adapter *padapter, u8 *pbuf) ++{ ++ u8 type; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct setopmode_parm *psetop = (struct setopmode_parm *)pbuf; ++ ++ if(psetop->mode == Ndis802_11APMode) ++ { ++ pmlmeinfo->state = WIFI_FW_AP_STATE; ++ type = _HW_STATE_AP_; ++#ifdef CONFIG_NATIVEAP_MLME ++ //start_ap_mode(padapter); ++#endif ++ } ++ else if(psetop->mode == Ndis802_11Infrastructure) ++ { ++ pmlmeinfo->state &= ~(BIT(0)|BIT(1));// clear state ++ pmlmeinfo->state |= WIFI_FW_STATION_STATE;//set to STATION_STATE ++ type = _HW_STATE_STATION_; ++ } ++ else if(psetop->mode == Ndis802_11IBSS) ++ { ++ type = _HW_STATE_ADHOC_; ++ } ++ else ++ { ++ type = _HW_STATE_NOLINK_; ++ } ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type)); ++ //Set_NETYPE0_MSR(padapter, type); ++ ++ return H2C_SUCCESS; ++ ++} ++ ++u8 createbss_hdl(_adapter *padapter, u8 *pbuf) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX*)(&(pmlmeinfo->network)); ++ struct joinbss_parm *pparm = (struct joinbss_parm *)pbuf; ++ //u32 initialgain; ++ ++ ++ if(pparm->network.InfrastructureMode == Ndis802_11APMode) ++ { ++#ifdef CONFIG_AP_MODE ++ ++ if(pmlmeinfo->state == WIFI_FW_AP_STATE) ++ { ++ //todo: ++ return H2C_SUCCESS; ++ } ++#endif ++ } ++ ++ //below is for ad-hoc master ++ if(pparm->network.InfrastructureMode == Ndis802_11IBSS) ++ { ++ rtw_joinbss_reset(padapter); ++ ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset= HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ pmlmeinfo->ERP_enable = 0; ++ pmlmeinfo->WMM_enable = 0; ++ pmlmeinfo->HT_enable = 0; ++ pmlmeinfo->HT_caps_enable = 0; ++ pmlmeinfo->HT_info_enable = 0; ++ pmlmeinfo->agg_enable_bitmap = 0; ++ pmlmeinfo->candidate_tid_bitmap = 0; ++ ++ //disable dynamic functions, such as high power, DIG ++ Save_DM_Func_Flag(padapter); ++ Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, _FALSE); ++ ++ //config the initial gain under linking, need to write the BB registers ++ //initialgain = 0x1E; ++ //rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); ++ ++ //cancel link timer ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ ++ //clear CAM ++ flush_all_cam_entry(padapter); ++ ++ _rtw_memcpy(pnetwork, pbuf, FIELD_OFFSET(WLAN_BSSID_EX, IELength)); ++ pnetwork->IELength = ((WLAN_BSSID_EX *)pbuf)->IELength; ++ ++ if(pnetwork->IELength>MAX_IE_SZ)//Check pbuf->IELength ++ return H2C_PARAMETERS_ERROR; ++ ++ _rtw_memcpy(pnetwork->IEs, ((WLAN_BSSID_EX *)pbuf)->IEs, pnetwork->IELength); ++ ++ start_create_ibss(padapter); ++ ++ } ++ ++ return H2C_SUCCESS; ++ ++} ++ ++u8 join_cmd_hdl(_adapter *padapter, u8 *pbuf) ++{ ++ u8 join_type; ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX*)(&(pmlmeinfo->network)); ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ struct joinbss_parm *pparm = (struct joinbss_parm *)pbuf; ++#endif //CONFIG_ANTENNA_DIVERSITY ++ u32 i; ++ //u32 initialgain; ++ //u32 acparm; ++ u8 ch, bw, offset; ++ ++ //check already connecting to AP or not ++ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) ++ { ++ if (pmlmeinfo->state & WIFI_FW_STATION_STATE) ++ { ++ issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, 5, 100); ++ } ++ ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ ++ //clear CAM ++ flush_all_cam_entry(padapter); ++ ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ ++ //set MSR to nolink -> infra. mode ++ //Set_MSR(padapter, _HW_STATE_NOLINK_); ++ Set_MSR(padapter, _HW_STATE_STATION_); ++ ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, 0); ++ } ++ ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ rtw_antenna_select_cmd(padapter, pparm->network.PhyInfo.Optimum_antenna, _FALSE); ++#endif ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ rtw_wapi_clear_all_cam_entry(padapter); ++#endif ++ ++ rtw_joinbss_reset(padapter); ++ ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset= HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ pmlmeinfo->ERP_enable = 0; ++ pmlmeinfo->WMM_enable = 0; ++ pmlmeinfo->HT_enable = 0; ++ pmlmeinfo->HT_caps_enable = 0; ++ pmlmeinfo->HT_info_enable = 0; ++ pmlmeinfo->agg_enable_bitmap = 0; ++ pmlmeinfo->candidate_tid_bitmap = 0; ++ pmlmeinfo->bwmode_updated = _FALSE; ++ //pmlmeinfo->assoc_AP_vendor = HT_IOT_PEER_MAX; ++ ++ _rtw_memcpy(pnetwork, pbuf, FIELD_OFFSET(WLAN_BSSID_EX, IELength)); ++ pnetwork->IELength = ((WLAN_BSSID_EX *)pbuf)->IELength; ++ ++ if(pnetwork->IELength>MAX_IE_SZ)//Check pbuf->IELength ++ return H2C_PARAMETERS_ERROR; ++ ++ _rtw_memcpy(pnetwork->IEs, ((WLAN_BSSID_EX *)pbuf)->IEs, pnetwork->IELength); ++ ++ pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig; ++ pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork); ++ ++ //Check AP vendor to move rtw_joinbss_cmd() ++ //pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->IEs, pnetwork->IELength); ++ ++ for (i = sizeof(NDIS_802_11_FIXED_IEs); i < pnetwork->IELength;) ++ { ++ pIE = (PNDIS_802_11_VARIABLE_IEs)(pnetwork->IEs + i); ++ ++ switch (pIE->ElementID) ++ { ++ case _VENDOR_SPECIFIC_IE_://Get WMM IE. ++ if ( _rtw_memcmp(pIE->data, WMM_OUI, 4) ) ++ { ++ pmlmeinfo->WMM_enable = 1; ++ } ++ break; ++ ++ case _HT_CAPABILITY_IE_: //Get HT Cap IE. ++ pmlmeinfo->HT_caps_enable = 1; ++ break; ++ ++ case _HT_EXTRA_INFO_IE_: //Get HT Info IE. ++#ifdef CONFIG_80211N_HT ++ pmlmeinfo->HT_info_enable = 1; ++ ++ //spec case only for cisco's ap because cisco's ap issue assoc rsp using mcs rate @40MHz or @20MHz ++//#if !defined(CONFIG_CONCURRENT_MODE) && !defined(CONFIG_DUALMAC_CONCURRENT) ++// if(pmlmeinfo->assoc_AP_vendor == ciscoAP) ++//#endif ++ { ++ struct HT_info_element *pht_info = (struct HT_info_element *)(pIE->data); ++ ++ if ((pregpriv->cbw40_enable) && (pht_info->infos[0] & BIT(2))) ++ { ++ //switch to the 40M Hz mode according to the AP ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; ++ switch (pht_info->infos[0] & 0x3) ++ { ++ case 1: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ break; ++ ++ case 3: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ break; ++ ++ default: ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ break; ++ } ++ ++ DBG_871X("set ch/bw before connected\n"); ++ } ++ } ++#endif //CONFIG_80211N_HT ++ break; ++ ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++#if 0 ++ if (padapter->registrypriv.wifi_spec) { ++ // for WiFi test, follow WMM test plan spec ++ acparm = 0x002F431C; // VO ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm)); ++ acparm = 0x005E541C; // VI ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm)); ++ acparm = 0x0000A525; // BE ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm)); ++ acparm = 0x0000A549; // BK ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm)); ++ ++ // for WiFi test, mixed mode with intel STA under bg mode throughput issue ++ if (padapter->mlmepriv.htpriv.ht_option == _FALSE){ ++ acparm = 0x00004320; ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm)); ++ } ++ } ++ else { ++ acparm = 0x002F3217; // VO ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm)); ++ acparm = 0x005E4317; // VI ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm)); ++ acparm = 0x00105320; // BE ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm)); ++ acparm = 0x0000A444; // BK ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm)); ++ } ++#endif ++ ++ /* check channel, bandwidth, offset and switch */ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ if(dc_handle_join_request(padapter, &ch, &bw, &offset) == _FAIL) { ++ DBG_871X("dc_handle_join_request fail !!!\n"); ++ return H2C_SUCCESS; ++ } ++#else //NON CONFIG_DUALMAC_CONCURRENT ++ if(rtw_chk_start_clnt_join(padapter, &ch, &bw, &offset) == _FAIL) { ++ report_join_res(padapter, (-4)); ++ return H2C_SUCCESS; ++ } ++#endif ++ ++ //disable dynamic functions, such as high power, DIG ++ //Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, _FALSE); ++ ++ //config the initial gain under linking, need to write the BB registers ++ //initialgain = 0x1E; ++ //rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pmlmeinfo->network.MacAddress); ++ join_type = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); ++ ++ set_channel_bwmode(padapter, ch, offset, bw); ++ ++ //cancel link timer ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ ++ start_clnt_join(padapter); ++ ++ return H2C_SUCCESS; ++ ++} ++ ++u8 disconnect_hdl(_adapter *padapter, unsigned char *pbuf) ++{ ++ struct disconnect_parm *param = (struct disconnect_parm *)pbuf; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX*)(&(pmlmeinfo->network)); ++ u8 val8; ++ ++ if (is_client_associated_to_ap(padapter)) ++ { ++ issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, param->deauth_timeout_ms/100, 100); ++ } ++ ++ //set_opmode_cmd(padapter, infra_client_with_mlme); ++ ++ //pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, 0); ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr); ++ ++ //restore to initial setting. ++ update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode); ++ ++ if(((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) ++ { ++ //Stop BCN ++ val8 = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_BCN_FUNC, (u8 *)(&val8)); ++ } ++ ++ ++ //set MSR to no link state -> infra. mode ++ Set_MSR(padapter, _HW_STATE_STATION_); ++ ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ dc_set_channel_bwmode_disconnect(padapter); ++#else ++#ifdef CONFIG_CONCURRENT_MODE ++ if((check_buddy_fwstate(padapter, _FW_LINKED)) != _TRUE) ++ { ++#endif //CONFIG_CONCURRENT_MODE ++ //switch to the 20M Hz mode after disconnect ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++#ifdef CONFIG_CONCURRENT_MODE ++ } ++#endif //CONFIG_CONCURRENT_MODE ++#endif //CONFIG_DUALMAC_CONCURRENT ++ ++ flush_all_cam_entry(padapter); ++ ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ ++ rtw_free_uc_swdec_pending_queue(padapter); ++ ++ return H2C_SUCCESS; ++} ++ ++int rtw_scan_ch_decision(_adapter *padapter, struct rtw_ieee80211_channel *out, ++ u32 out_num, struct rtw_ieee80211_channel *in, u32 in_num) ++{ ++ int i, j; ++ int scan_ch_num = 0; ++ int set_idx; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ /* clear out first */ ++ _rtw_memset(out, 0, sizeof(struct rtw_ieee80211_channel)*out_num); ++ ++ /* acquire channels from in */ ++ j = 0; ++ for (i=0;ichannel_set, in[i].hw_value)) >=0 ++ ) ++ { ++ _rtw_memcpy(&out[j], &in[i], sizeof(struct rtw_ieee80211_channel)); ++ ++ if(pmlmeext->channel_set[set_idx].ScanType == SCAN_PASSIVE) ++ out[j].flags |= RTW_IEEE80211_CHAN_PASSIVE_SCAN; ++ ++ j++; ++ } ++ if(j>=out_num) ++ break; ++ } ++ ++ /* if out is empty, use channel_set as default */ ++ if(j == 0) { ++ for (i=0;imax_chan_nums;i++) { ++ out[i].hw_value = pmlmeext->channel_set[i].ChannelNum; ++ ++ if(pmlmeext->channel_set[i].ScanType == SCAN_PASSIVE) ++ out[i].flags |= RTW_IEEE80211_CHAN_PASSIVE_SCAN; ++ ++ j++; ++ } ++ } ++ ++ if (padapter->setband == GHZ_24) { // 2.4G ++ for (i=0; i < j ; i++) { ++ if (out[i].hw_value > 35) ++ _rtw_memset(&out[i], 0 , sizeof(struct rtw_ieee80211_channel)); ++ else ++ scan_ch_num++; ++ } ++ j = scan_ch_num; ++ } else if (padapter->setband == GHZ_50) { // 5G ++ for (i=0; i < j ; i++) { ++ if (out[i].hw_value > 35) { ++ _rtw_memcpy(&out[scan_ch_num++], &out[i], sizeof(struct rtw_ieee80211_channel)); ++ } ++ } ++ j = scan_ch_num; ++ } else ++ {} ++ ++ return j; ++} ++ ++u8 sitesurvey_cmd_hdl(_adapter *padapter, u8 *pbuf) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct sitesurvey_parm *pparm = (struct sitesurvey_parm *)pbuf; ++ u8 bdelayscan = _FALSE; ++ u8 val8; ++ u32 initialgain; ++ u32 i; ++ ++#ifdef CONFIG_P2P ++ struct wifidirect_info* pwdinfo = &padapter->wdinfo; ++#endif ++ ++ if (pmlmeext->sitesurvey_res.state == SCAN_DISABLE) ++ { ++#ifdef CONFIG_CONCURRENT_MODE ++ //for first time sitesurvey_cmd ++ rtw_hal_set_hwreg(padapter, HW_VAR_CHECK_TXBUF, 0); ++#endif //CONFIG_CONCURRENT_MODE ++ ++ pmlmeext->sitesurvey_res.state = SCAN_START; ++ pmlmeext->sitesurvey_res.bss_cnt = 0; ++ pmlmeext->sitesurvey_res.channel_idx = 0; ++ ++ for(i=0;issid[i].SsidLength) { ++ _rtw_memcpy(pmlmeext->sitesurvey_res.ssid[i].Ssid, pparm->ssid[i].Ssid, IW_ESSID_MAX_SIZE); ++ pmlmeext->sitesurvey_res.ssid[i].SsidLength= pparm->ssid[i].SsidLength; ++ } else { ++ pmlmeext->sitesurvey_res.ssid[i].SsidLength= 0; ++ } ++ } ++ ++ pmlmeext->sitesurvey_res.ch_num = rtw_scan_ch_decision(padapter ++ , pmlmeext->sitesurvey_res.ch, RTW_CHANNEL_SCAN_AMOUNT ++ , pparm->ch, pparm->ch_num ++ ); ++ ++ pmlmeext->sitesurvey_res.scan_mode = pparm->scan_mode; ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ bdelayscan = dc_handle_site_survey(padapter); ++#endif ++ ++ //issue null data if associating to the AP ++ if (is_client_associated_to_ap(padapter) == _TRUE) ++ { ++ pmlmeext->sitesurvey_res.state = SCAN_TXNULL; ++ ++ /* switch to correct channel of current network before issue keep-alive frames */ ++ if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) { ++ SelectChannel(padapter, pmlmeext->cur_channel); ++ } ++ ++ issue_nulldata(padapter, NULL, 1, 3, 500); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(is_client_associated_to_ap(padapter->pbuddy_adapter) == _TRUE) ++ { ++ DBG_871X("adapter is scanning(buddy_adapter is linked), issue nulldata(pwrbit=1)\n"); ++ ++ issue_nulldata(padapter->pbuddy_adapter, NULL, 1, 3, 500); ++ } ++#endif ++ bdelayscan = _TRUE; ++ } ++#ifdef CONFIG_CONCURRENT_MODE ++ else if(is_client_associated_to_ap(padapter->pbuddy_adapter) == _TRUE) ++ { ++ #ifdef CONFIG_TDLS ++ if(padapter->pbuddy_adapter->wdinfo.wfd_tdls_enable == 1) ++ { ++ issue_tunneled_probe_req(padapter->pbuddy_adapter); ++ } ++ #endif //CONFIG_TDLS ++ ++ pmlmeext->sitesurvey_res.state = SCAN_TXNULL; ++ ++ issue_nulldata(padapter->pbuddy_adapter, NULL, 1, 3, 500); ++ ++ bdelayscan = _TRUE; ++ } ++#endif ++ if(bdelayscan) ++ { ++ //delay 50ms to protect nulldata(1). ++ set_survey_timer(pmlmeext, 50); ++ return H2C_SUCCESS; ++ } ++ } ++ ++ if ((pmlmeext->sitesurvey_res.state == SCAN_START) || (pmlmeext->sitesurvey_res.state == SCAN_TXNULL)) ++ { ++#ifdef CONFIG_FIND_BEST_CHANNEL ++#if 0 ++ for (i=0; pmlmeext->channel_set[i].ChannelNum !=0; i++) { ++ pmlmeext->channel_set[i].rx_count = 0; ++ } ++#endif ++#endif /* CONFIG_FIND_BEST_CHANNEL */ ++ ++ //disable dynamic functions, such as high power, DIG ++ Save_DM_Func_Flag(padapter); ++ Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, _FALSE); ++ ++ //config the initial gain under scaning, need to write the BB registers ++#ifdef CONFIG_P2P ++#ifdef CONFIG_IOCTL_CFG80211 ++ if((wdev_to_priv(padapter->rtw_wdev))->p2p_enabled == _TRUE && pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ initialgain = 0x30; ++ else ++#endif //CONFIG_IOCTL_CFG80211 ++ if ( !rtw_p2p_chk_state( pwdinfo, P2P_STATE_NONE ) ) ++ initialgain = 0x28; ++ else ++#endif //CONFIG_P2P ++ initialgain = 0x1e; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); ++ ++ //set MSR to no link state ++ Set_MSR(padapter, _HW_STATE_NOLINK_); ++ ++ val8 = 1; //under site survey ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ ++ pmlmeext->sitesurvey_res.state = SCAN_PROCESS; ++ } ++ ++ site_survey(padapter); ++ ++ return H2C_SUCCESS; ++ ++} ++ ++u8 setauth_hdl(_adapter *padapter, unsigned char *pbuf) ++{ ++ struct setauth_parm *pparm = (struct setauth_parm *)pbuf; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if (pparm->mode < 4) ++ { ++ pmlmeinfo->auth_algo = pparm->mode; ++ } ++ ++ return H2C_SUCCESS; ++} ++ ++u8 setkey_hdl(_adapter *padapter, u8 *pbuf) ++{ ++ unsigned short ctrl; ++ struct setkey_parm *pparm = (struct setkey_parm *)pbuf; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++ ++ //main tx key for wep. ++ if(pparm->set_tx) ++ pmlmeinfo->key_index = pparm->keyid; ++ ++ //write cam ++ ctrl = BIT(15) | ((pparm->algorithm) << 2) | pparm->keyid; ++ ++ DBG_871X_LEVEL(_drv_always_, "set group key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) " ++ "keyid:%d\n", pparm->algorithm, pparm->keyid); ++ write_cam(padapter, pparm->keyid, ctrl, null_sta, pparm->key); ++ ++ //allow multicast packets to driver ++ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_ON_RCR_AM, null_addr); ++ ++ return H2C_SUCCESS; ++} ++ ++u8 set_stakey_hdl(_adapter *padapter, u8 *pbuf) ++{ ++ u16 ctrl=0; ++ u8 cam_id;//cam_entry ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct set_stakey_parm *pparm = (struct set_stakey_parm *)pbuf; ++#ifdef CONFIG_TDLS ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *psta; ++#endif //CONFIG_TDLS ++ ++ //cam_entry: ++ //0~3 for default key ++ ++ //for concurrent mode (ap+sta): ++ //default key is disable, using sw encrypt/decrypt ++ //cam_entry = 4 //for sta mode (macid=0) ++ //cam_entry(macid+3) = 5 ~ N//for ap mode (aid=1~N, macid=2 ~N) ++ ++ //for concurrent mode (sta+sta): ++ //default key is disable, using sw encrypt/decrypt ++ //cam_entry = 4 //mapping to macid=0 ++ //cam_entry = 5 //mapping to macid=2 ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) ++ { ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *psta; ++ ++ psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress); ++ ++ if(psta && psta->mac_id==2) ++ { ++ cam_id = 5; ++ } ++ else ++ { ++ cam_id = 4; ++ } ++/* ++ if(padapter->iface_type > PRIMARY_IFACE) ++ { ++ cam_id = 5; ++ } ++ else ++ { ++ cam_id = 4; ++ } ++*/ ++ } ++#else ++ cam_id = 4; ++#endif ++ ++ DBG_871X_LEVEL(_drv_always_, "set pairwise key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) camid:%d\n", ++ pparm->algorithm, cam_id); ++ if((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ { ++ ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ if(pparm->algorithm == _NO_PRIVACY_) // clear cam entry ++ { ++ clear_cam_entry(padapter, pparm->id); ++ return H2C_SUCCESS_RSP; ++ } ++ ++ psta = rtw_get_stainfo(pstapriv, pparm->addr); ++ if(psta) ++ { ++ ctrl = (BIT(15) | ((pparm->algorithm) << 2)); ++ ++ DBG_871X("r871x_set_stakey_hdl(): enc_algorithm=%d\n", pparm->algorithm); ++ ++ if((psta->mac_id<1) || (psta->mac_id>(NUM_STA-4))) ++ { ++ DBG_871X("r871x_set_stakey_hdl():set_stakey failed, mac_id(aid)=%d\n", psta->mac_id); ++ return H2C_REJECTED; ++ } ++ ++ cam_id = (psta->mac_id + 3);//0~3 for default key, cmd_id=macid + 3, macid=aid+1; ++ ++ DBG_871X("Write CAM, mac_addr=%x:%x:%x:%x:%x:%x, cam_entry=%d\n", pparm->addr[0], ++ pparm->addr[1], pparm->addr[2], pparm->addr[3], pparm->addr[4], ++ pparm->addr[5], cam_id); ++ ++ write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key); ++ ++ return H2C_SUCCESS_RSP; ++ ++ } ++ else ++ { ++ DBG_871X("r871x_set_stakey_hdl(): sta has been free\n"); ++ return H2C_REJECTED; ++ } ++ ++ } ++ ++ //below for sta mode ++ ++ if(pparm->algorithm == _NO_PRIVACY_) // clear cam entry ++ { ++ clear_cam_entry(padapter, pparm->id); ++ return H2C_SUCCESS; ++ } ++ ++ ctrl = BIT(15) | ((pparm->algorithm) << 2); ++ ++#ifdef CONFIG_TDLS ++ if(ptdlsinfo->clear_cam!=0){ ++ clear_cam_entry(padapter, ptdlsinfo->clear_cam); ++ ptdlsinfo->clear_cam=0; ++ ++ return H2C_SUCCESS; ++ } ++ ++ psta = rtw_get_stainfo(pstapriv, pparm->addr);//Get TDLS Peer STA ++ if( psta->tdls_sta_state&TDLS_LINKED_STATE ){ ++ write_cam(padapter, psta->mac_id, ctrl, pparm->addr, pparm->key); ++ } ++ else ++#endif //CONFIG_TDLS ++ write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key); ++ ++ pmlmeinfo->enc_algo = pparm->algorithm; ++ ++ return H2C_SUCCESS; ++} ++ ++u8 add_ba_hdl(_adapter *padapter, unsigned char *pbuf) ++{ ++ struct addBaReq_parm *pparm = (struct addBaReq_parm *)pbuf; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, pparm->addr); ++ ++ if(!psta) ++ return H2C_SUCCESS; ++ ++#ifdef CONFIG_80211N_HT ++ if (((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && (pmlmeinfo->HT_enable)) || ++ ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) ++ { ++ //pmlmeinfo->ADDBA_retry_count = 0; ++ //pmlmeinfo->candidate_tid_bitmap |= (0x1 << pparm->tid); ++ //psta->htpriv.candidate_tid_bitmap |= BIT(pparm->tid); ++ issue_action_BA(padapter, pparm->addr, RTW_WLAN_ACTION_ADDBA_REQ, (u16)pparm->tid); ++ //_set_timer(&pmlmeext->ADDBA_timer, ADDBA_TO); ++ _set_timer(&psta->addba_retry_timer, ADDBA_TO); ++ } ++#ifdef CONFIG_TDLS ++ else if((psta->tdls_sta_state & TDLS_LINKED_STATE)&& ++ (psta->htpriv.ht_option==_TRUE) && ++ (psta->htpriv.ampdu_enable==_TRUE) ) ++ { ++ issue_action_BA(padapter, pparm->addr, RTW_WLAN_ACTION_ADDBA_REQ, (u16)pparm->tid); ++ //_set_timer(&pmlmeext->ADDBA_timer, ADDBA_TO); ++ _set_timer(&psta->addba_retry_timer, ADDBA_TO); ++ } ++#endif //CONFIG ++ else ++ { ++ psta->htpriv.candidate_tid_bitmap &= ~BIT(pparm->tid); ++ } ++#endif //CONFIG_80211N_HT ++ return H2C_SUCCESS; ++} ++ ++u8 set_tx_beacon_cmd(_adapter* padapter) ++{ ++ struct cmd_obj *ph2c; ++ struct Tx_Beacon_param *ptxBeacon_parm; ++ struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 res = _SUCCESS; ++ int len_diff = 0; ++ ++_func_enter_; ++ ++ if ((ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ res= _FAIL; ++ goto exit; ++ } ++ ++ if ((ptxBeacon_parm = (struct Tx_Beacon_param *)rtw_zmalloc(sizeof(struct Tx_Beacon_param))) == NULL) ++ { ++ rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ _rtw_memcpy(&(ptxBeacon_parm->network), &(pmlmeinfo->network), sizeof(WLAN_BSSID_EX)); ++ ++ len_diff = update_hidden_ssid( ++ ptxBeacon_parm->network.IEs+_BEACON_IE_OFFSET_ ++ , ptxBeacon_parm->network.IELength-_BEACON_IE_OFFSET_ ++ , pmlmeinfo->hidden_ssid_mode ++ ); ++ ptxBeacon_parm->network.IELength += len_diff; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, ptxBeacon_parm, GEN_CMD_CODE(_TX_Beacon)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++ ++u8 mlme_evt_hdl(_adapter *padapter, unsigned char *pbuf) ++{ ++ u8 evt_code, evt_seq; ++ u16 evt_sz; ++ uint *peventbuf; ++ void (*event_callback)(_adapter *dev, u8 *pbuf); ++ struct evt_priv *pevt_priv = &(padapter->evtpriv); ++ ++ peventbuf = (uint*)pbuf; ++ evt_sz = (u16)(*peventbuf&0xffff); ++ evt_seq = (u8)((*peventbuf>>24)&0x7f); ++ evt_code = (u8)((*peventbuf>>16)&0xff); ++ ++ ++ #ifdef CHECK_EVENT_SEQ ++ // checking event sequence... ++ if (evt_seq != (ATOMIC_READ(&pevt_priv->event_seq) & 0x7f) ) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("Evetn Seq Error! %d vs %d\n", (evt_seq & 0x7f), (ATOMIC_READ(&pevt_priv->event_seq) & 0x7f))); ++ ++ pevt_priv->event_seq = (evt_seq+1)&0x7f; ++ ++ goto _abort_event_; ++ } ++ #endif ++ ++ // checking if event code is valid ++ if (evt_code >= MAX_C2HEVT) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("\nEvent Code(%d) mismatch!\n", evt_code)); ++ goto _abort_event_; ++ } ++ ++ // checking if event size match the event parm size ++ if ((wlanevents[evt_code].parmsize != 0) && ++ (wlanevents[evt_code].parmsize != evt_sz)) ++ { ++ ++ RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("\nEvent(%d) Parm Size mismatch (%d vs %d)!\n", ++ evt_code, wlanevents[evt_code].parmsize, evt_sz)); ++ goto _abort_event_; ++ ++ } ++ ++ ATOMIC_INC(&pevt_priv->event_seq); ++ ++ peventbuf += 2; ++ ++ if(peventbuf) ++ { ++ event_callback = wlanevents[evt_code].event_callback; ++ event_callback(padapter, (u8*)peventbuf); ++ ++ pevt_priv->evt_done_cnt++; ++ } ++ ++ ++_abort_event_: ++ ++ ++ return H2C_SUCCESS; ++ ++} ++ ++u8 h2c_msg_hdl(_adapter *padapter, unsigned char *pbuf) ++{ ++ if(!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ return H2C_SUCCESS; ++} ++ ++u8 tx_beacon_hdl(_adapter *padapter, unsigned char *pbuf) ++{ ++ if(send_beacon(padapter)==_FAIL) ++ { ++ DBG_871X("issue_beacon, fail!\n"); ++ return H2C_PARAMETERS_ERROR; ++ } ++#ifdef CONFIG_AP_MODE ++ else //tx bc/mc frames after update TIM ++ { ++ _irqL irqL; ++ struct sta_info *psta_bmc; ++ _list *xmitframe_plist, *xmitframe_phead; ++ struct xmit_frame *pxmitframe=NULL; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ //for BC/MC Frames ++ psta_bmc = rtw_get_bcmc_stainfo(padapter); ++ if(!psta_bmc) ++ return H2C_SUCCESS; ++ ++ if((pstapriv->tim_bitmap&BIT(0)) && (psta_bmc->sleepq_len>0)) ++ { ++#ifndef CONFIG_PCI_HCI ++ rtw_msleep_os(10);// 10ms, ATIM(HIQ) Windows ++#endif ++ //_enter_critical_bh(&psta_bmc->sleep_q.lock, &irqL); ++ _enter_critical_bh(&pxmitpriv->lock, &irqL); ++ ++ xmitframe_phead = get_list_head(&psta_bmc->sleep_q); ++ xmitframe_plist = get_next(xmitframe_phead); ++ ++ while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) ++ { ++ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = get_next(xmitframe_plist); ++ ++ rtw_list_delete(&pxmitframe->list); ++ ++ psta_bmc->sleepq_len--; ++ if(psta_bmc->sleepq_len>0) ++ pxmitframe->attrib.mdata = 1; ++ else ++ pxmitframe->attrib.mdata = 0; ++ ++ pxmitframe->attrib.triggered=1; ++ ++ pxmitframe->attrib.qsel = 0x11;//HIQ ++ ++#if 0 ++ _exit_critical_bh(&psta_bmc->sleep_q.lock, &irqL); ++ if(rtw_hal_xmit(padapter, pxmitframe) == _TRUE) ++ { ++ rtw_os_xmit_complete(padapter, pxmitframe); ++ } ++ _enter_critical_bh(&psta_bmc->sleep_q.lock, &irqL); ++ ++#endif ++ rtw_hal_xmitframe_enqueue(padapter, pxmitframe); ++ ++ //pstapriv->tim_bitmap &= ~BIT(0); ++ ++ } ++ ++ //_exit_critical_bh(&psta_bmc->sleep_q.lock, &irqL); ++ _exit_critical_bh(&pxmitpriv->lock, &irqL); ++ ++//#if defined(CONFIG_PCI_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ rtw_chk_hi_queue_cmd(padapter); ++#endif ++ ++ } ++ ++ } ++#endif ++ ++ return H2C_SUCCESS; ++ ++} ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++void dc_SelectChannel(_adapter *padapter, unsigned char channel) ++{ ++ PADAPTER ptarget_adapter; ++ ++ if( (padapter->pbuddy_adapter != NULL) && ++ (padapter->DualMacConcurrent == _TRUE) && ++ (padapter->adapter_type == SECONDARY_ADAPTER)) ++ { ++ // only mac0 could control BB&RF ++ ptarget_adapter = padapter->pbuddy_adapter; ++ } ++ else ++ { ++ ptarget_adapter = padapter; ++ } ++ ++ _enter_critical_mutex(&(adapter_to_dvobj(ptarget_adapter)->setch_mutex), NULL); ++ ++ rtw_hal_set_chan(ptarget_adapter, channel); ++ ++ _exit_critical_mutex(&(adapter_to_dvobj(ptarget_adapter)->setch_mutex), NULL); ++} ++ ++void dc_SetBWMode(_adapter *padapter, unsigned short bwmode, unsigned char channel_offset) ++{ ++ PADAPTER ptarget_adapter; ++ ++ if( (padapter->pbuddy_adapter != NULL) && ++ (padapter->DualMacConcurrent == _TRUE) && ++ (padapter->adapter_type == SECONDARY_ADAPTER)) ++ { ++ // only mac0 could control BB&RF ++ ptarget_adapter = padapter->pbuddy_adapter; ++ } ++ else ++ { ++ ptarget_adapter = padapter; ++ } ++ ++ _enter_critical_mutex(&(adapter_to_dvobj(ptarget_adapter)->setbw_mutex), NULL); ++ ++ rtw_hal_set_bwmode(ptarget_adapter, (HT_CHANNEL_WIDTH)bwmode, channel_offset); ++ ++ _exit_critical_mutex(&(adapter_to_dvobj(ptarget_adapter)->setbw_mutex), NULL); ++} ++ ++static void dc_change_band(_adapter *padapter, WLAN_BSSID_EX *pnetwork) ++{ ++ u8 network_type,rate_len, total_rate_len,remainder_rate_len; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 erpinfo=0x4; ++ ++ //DBG_871X("%s\n", __FUNCTION__); ++ ++ if(pmlmeext->cur_channel >= 36) ++ { ++ network_type = WIRELESS_11A; ++ total_rate_len = IEEE80211_NUM_OFDM_RATESLEN; ++ DBG_871X("%s(): change to 5G Band\n",__FUNCTION__); ++ rtw_remove_bcn_ie(padapter, pnetwork, _ERPINFO_IE_); ++ } ++ else ++ { ++ network_type = WIRELESS_11BG; ++ total_rate_len = IEEE80211_CCK_RATE_LEN+IEEE80211_NUM_OFDM_RATESLEN; ++ DBG_871X("%s(): change to 2.4G Band\n",__FUNCTION__); ++ rtw_add_bcn_ie(padapter, pnetwork, _ERPINFO_IE_, &erpinfo, 1); ++ } ++ ++ rtw_set_supported_rate(pnetwork->SupportedRates, network_type); ++ ++ UpdateBrateTbl(padapter, pnetwork->SupportedRates); ++ rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates); ++ ++ if(total_rate_len > 8) ++ { ++ rate_len = 8; ++ remainder_rate_len = total_rate_len - 8; ++ } ++ else ++ { ++ rate_len = total_rate_len; ++ remainder_rate_len = 0; ++ } ++ ++ rtw_add_bcn_ie(padapter, pnetwork, _SUPPORTEDRATES_IE_, pnetwork->SupportedRates, rate_len); ++ ++ if(remainder_rate_len) ++ { ++ rtw_add_bcn_ie(padapter, pnetwork, _EXT_SUPPORTEDRATES_IE_, (pnetwork->SupportedRates+8), remainder_rate_len); ++ } ++ else ++ { ++ rtw_remove_bcn_ie(padapter, pnetwork, _EXT_SUPPORTEDRATES_IE_); ++ } ++} ++ ++void dc_set_channel_bwmode_disconnect(_adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_priv *pbuddy_mlmepriv = NULL; ++ ++ if(pbuddy_adapter != NULL && ++ padapter->DualMacConcurrent == _TRUE) ++ { ++ pbuddy_mlmepriv = &(pbuddy_adapter->mlmepriv); ++ if((check_fwstate(pbuddy_mlmepriv, _FW_LINKED)) != _TRUE) ++ { ++ //switch to the 20M Hz mode after disconnect ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ } ++ } ++ else ++ { ++ //switch to the 20M Hz mode after disconnect ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ } ++} ++ ++u8 dc_handle_join_request(_adapter *padapter, u8 *ch, u8 *bw, u8 *offset) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX*)(&(pmlmeinfo->network)); ++ PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = NULL; ++ struct mlme_priv *pbuddy_mlmepriv = NULL; ++ u8 ret = _SUCCESS; ++ ++ if(pbuddy_adapter != NULL && ++ padapter->DualMacConcurrent == _TRUE) ++ { ++ pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ pbuddy_mlmepriv = &(pbuddy_adapter->mlmepriv); ++ ++ if(pmlmeext->cur_channel != pbuddy_mlmeext->cur_channel || ++ pmlmeext->cur_bwmode != pbuddy_mlmeext->cur_bwmode || ++ pmlmeext->cur_ch_offset != pbuddy_mlmeext->cur_ch_offset) ++ { ++ if((check_fwstate(pbuddy_mlmepriv, WIFI_AP_STATE)) == _TRUE) ++ { ++ //issue deauth to all stas if if2 is at ap mode ++ rtw_sta_flush(pbuddy_adapter); ++ ++ //rtw_hal_set_hwreg(padapter, HW_VAR_CHECK_TXBUF, 0); ++ rtw_hal_set_hwreg(pbuddy_adapter, HW_VAR_CHECK_TXBUF, 0); ++ } ++ else if(check_fwstate(pbuddy_mlmepriv, _FW_LINKED) == _TRUE) ++ { ++ if(pmlmeext->cur_channel == pbuddy_mlmeext->cur_channel) ++ { ++ // HT_CHANNEL_WIDTH_40 or HT_CHANNEL_WIDTH_20 but channel offset is different ++ if((pmlmeext->cur_bwmode == pbuddy_mlmeext->cur_bwmode) && ++ (pmlmeext->cur_ch_offset != pbuddy_mlmeext->cur_ch_offset) ) ++ { ++ report_join_res(padapter, -4); ++ ret = _FAIL; ++ } ++ } ++ else ++ { ++ report_join_res(padapter, -4); ++ ret = _FAIL; ++ } ++ } ++ } ++ else if (is_client_associated_to_ap(pbuddy_adapter) == _TRUE) ++ { ++ issue_nulldata(pbuddy_adapter, NULL, 1, 0, 0); ++ } ++ } ++ ++ if (!ch || !bw || !offset) { ++ rtw_warn_on(1); ++ ret = _FAIL; ++ } ++ ++ if (ret == _SUCCESS) { ++ *ch = pmlmeext->cur_channel; ++ *bw = pmlmeext->cur_bwmode; ++ *offset = pmlmeext->cur_ch_offset; ++ } ++ ++exit: ++ return ret; ++} ++ ++void dc_handle_join_done(_adapter *padapter, u8 join_res) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_priv *pbuddy_mlmepriv = NULL; ++ struct mlme_ext_priv *pbuddy_mlmeext = NULL; ++ struct mlme_ext_info *pbuddy_mlmeinfo = NULL; ++ WLAN_BSSID_EX *pbuddy_network_mlmeext = NULL; ++ u8 change_band = _FALSE; ++ ++ ++ if(pbuddy_adapter != NULL && ++ padapter->DualMacConcurrent == _TRUE) ++ { ++ pbuddy_mlmepriv = &(pbuddy_adapter->mlmepriv); ++ pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ pbuddy_mlmeinfo = &(pbuddy_mlmeext->mlmext_info); ++ pbuddy_network_mlmeext = &(pbuddy_mlmeinfo->network); ++ ++ if(((pbuddy_mlmeinfo->state&0x03) == WIFI_FW_AP_STATE) && ++ check_fwstate(pbuddy_mlmepriv, _FW_LINKED)) ++ { ++ //restart and update beacon ++ DBG_871X("after join, current adapter, CH=%d, BW=%d, offset=%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); ++ ++ if(join_res >= 0) ++ { ++ u8 *p; ++ int ie_len; ++ struct HT_info_element *pht_info=NULL; ++ ++ if((pbuddy_mlmeext->cur_channel <= 14 && pmlmeext->cur_channel >= 36) || ++ (pbuddy_mlmeext->cur_channel >= 36 && pmlmeext->cur_channel <= 14)) ++ { ++ change_band = _TRUE; ++ } ++ ++ //sync channel/bwmode/ch_offset with another adapter ++ pbuddy_mlmeext->cur_channel = pmlmeext->cur_channel; ++ ++ if(pbuddy_mlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40) ++ { ++ p = rtw_get_ie((pbuddy_network_mlmeext->IEs + sizeof(NDIS_802_11_FIXED_IEs)), _HT_ADD_INFO_IE_, &ie_len, (pbuddy_network_mlmeext->IELength - sizeof(NDIS_802_11_FIXED_IEs))); ++ if( p && ie_len) ++ { ++ pht_info = (struct HT_info_element *)(p+2); ++ pht_info->infos[0] &= ~(BIT(0)|BIT(1)); //no secondary channel is present ++ } ++ ++ if(pmlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40) ++ { ++ pbuddy_mlmeext->cur_ch_offset = pmlmeext->cur_ch_offset; ++ ++ //to update cur_ch_offset value in beacon ++ if( pht_info ) ++ { ++ switch(pmlmeext->cur_ch_offset) ++ { ++ case HAL_PRIME_CHNL_OFFSET_LOWER: ++ pht_info->infos[0] |= 0x1; ++ break; ++ case HAL_PRIME_CHNL_OFFSET_UPPER: ++ pht_info->infos[0] |= 0x3; ++ break; ++ case HAL_PRIME_CHNL_OFFSET_DONT_CARE: ++ default: ++ break; ++ } ++ } ++ } ++ else if(pmlmeext->cur_bwmode == HT_CHANNEL_WIDTH_20) ++ { ++ pbuddy_mlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; ++ pbuddy_mlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ if(pmlmeext->cur_channel>0 && pmlmeext->cur_channel<5) ++ { ++ if(pht_info) ++ pht_info->infos[0] |= 0x1; ++ ++ pbuddy_mlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; ++ pbuddy_mlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ } ++ ++ if(pmlmeext->cur_channel>7 && pmlmeext->cur_channel<(14+1)) ++ { ++ if(pht_info) ++ pht_info->infos[0] |= 0x3; ++ ++ pbuddy_mlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; ++ pbuddy_mlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ } ++ ++ set_channel_bwmode(padapter, pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_ch_offset, pbuddy_mlmeext->cur_bwmode); ++ } ++ } ++ ++ // to update channel value in beacon ++ pbuddy_network_mlmeext->Configuration.DSConfig = pmlmeext->cur_channel; ++ p = rtw_get_ie((pbuddy_network_mlmeext->IEs + sizeof(NDIS_802_11_FIXED_IEs)), _DSSET_IE_, &ie_len, (pbuddy_network_mlmeext->IELength - sizeof(NDIS_802_11_FIXED_IEs))); ++ if(p && ie_len>0) ++ *(p + 2) = pmlmeext->cur_channel; ++ ++ p = rtw_get_ie((pbuddy_network_mlmeext->IEs + sizeof(NDIS_802_11_FIXED_IEs)), _HT_ADD_INFO_IE_, &ie_len, (pbuddy_network_mlmeext->IELength - sizeof(NDIS_802_11_FIXED_IEs))); ++ if( p && ie_len) ++ { ++ pht_info = (struct HT_info_element *)(p+2); ++ pht_info->primary_channel = pmlmeext->cur_channel; ++ } ++ ++ // update mlmepriv's cur_network ++ _rtw_memcpy(&pbuddy_mlmepriv->cur_network.network, pbuddy_network_mlmeext, pbuddy_network_mlmeext->Length); ++ } ++ else ++ { ++ // switch back to original channel/bwmode/ch_offset; ++ set_channel_bwmode(padapter, pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_ch_offset, pbuddy_mlmeext->cur_bwmode); ++ } ++ ++ DBG_871X("after join, another adapter, CH=%d, BW=%d, offset=%d\n", pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_bwmode, pbuddy_mlmeext->cur_ch_offset); ++ ++ if(change_band == _TRUE) ++ dc_change_band(pbuddy_adapter, pbuddy_network_mlmeext); ++ ++ DBG_871X("update pbuddy_adapter's beacon\n"); ++ ++ update_beacon(pbuddy_adapter, 0, NULL, _TRUE); ++ } ++ else if (is_client_associated_to_ap(pbuddy_adapter) == _TRUE) ++ { ++ if((pbuddy_mlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40) && ++ (pmlmeext->cur_bwmode == HT_CHANNEL_WIDTH_20)) ++ { ++ set_channel_bwmode(padapter, pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_ch_offset, pbuddy_mlmeext->cur_bwmode); ++ } ++ ++ issue_nulldata(pbuddy_adapter, NULL, 0, 0, 0); ++ } ++ } ++} ++ ++sint dc_check_fwstate(_adapter *padapter, sint fw_state) ++{ ++ PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_priv *pbuddy_mlmepriv = NULL; ++ ++ if(padapter->pbuddy_adapter != NULL && ++ padapter->DualMacConcurrent == _TRUE) ++ ++ { ++ pbuddy_mlmepriv = &(pbuddy_adapter->mlmepriv); ++ ++ return check_fwstate(pbuddy_mlmepriv, fw_state); ++ } ++ ++ return _FALSE; ++} ++ ++u8 dc_handle_site_survey(_adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ ++ // only mac0 can do scan request, help issue nulldata(1) for mac1 ++ if(pbuddy_adapter != NULL && ++ padapter->DualMacConcurrent == _TRUE) ++ { ++ if (is_client_associated_to_ap(pbuddy_adapter) == _TRUE) ++ { ++ pmlmeext->sitesurvey_res.state = SCAN_TXNULL; ++ ++ issue_nulldata(pbuddy_adapter, NULL, 1, 2, 0); ++ ++ return _TRUE; ++ } ++ } ++ ++ return _FALSE; ++} ++ ++void dc_report_survey_event(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ if(padapter->pbuddy_adapter != NULL && ++ padapter->DualMacConcurrent == _TRUE) ++ { ++ report_survey_event(padapter->pbuddy_adapter, precv_frame); ++ } ++} ++ ++void dc_set_channel_bwmode_survey_done(_adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_priv *pbuddy_mlmepriv = NULL; ++ struct mlme_ext_priv *pbuddy_mlmeext = NULL; ++ struct mlme_ext_info *pbuddy_mlmeinfo = NULL; ++ u8 cur_channel; ++ u8 cur_bwmode; ++ u8 cur_ch_offset; ++ ++ if(pbuddy_adapter != NULL && ++ padapter->DualMacConcurrent == _TRUE) ++ { ++ pbuddy_mlmepriv = &(pbuddy_adapter->mlmepriv); ++ pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ pbuddy_mlmeinfo = &(pbuddy_mlmeext->mlmext_info); ++ ++ if(check_fwstate(pbuddy_mlmepriv, _FW_LINKED)) ++ { ++ if(check_fwstate(pmlmepriv, _FW_LINKED) && ++ (pmlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40)) ++ { ++ cur_channel = pmlmeext->cur_channel; ++ cur_bwmode = pmlmeext->cur_bwmode; ++ cur_ch_offset = pmlmeext->cur_ch_offset; ++ } ++ else ++ { ++ cur_channel = pbuddy_mlmeext->cur_channel; ++ cur_bwmode = pbuddy_mlmeext->cur_bwmode; ++ cur_ch_offset = pbuddy_mlmeext->cur_ch_offset; ++ } ++ } ++ else ++ { ++ cur_channel = pmlmeext->cur_channel; ++ cur_bwmode = pmlmeext->cur_bwmode; ++ cur_ch_offset = pmlmeext->cur_ch_offset; ++ } ++ ++ set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode); ++ ++ if (is_client_associated_to_ap(pbuddy_adapter) == _TRUE) ++ { ++ //issue null data ++ issue_nulldata(pbuddy_adapter, NULL, 0, 0, 0); ++ } ++ ++ if(((pbuddy_mlmeinfo->state&0x03) == WIFI_FW_AP_STATE) && ++ check_fwstate(pbuddy_mlmepriv, _FW_LINKED)) ++ { ++ ++ DBG_871X("survey done, current CH=%d, BW=%d, offset=%d\n", cur_channel, cur_bwmode, cur_ch_offset); ++ ++ DBG_871X("restart pbuddy_adapter's beacon\n"); ++ ++ update_beacon(pbuddy_adapter, 0, NULL, _TRUE); ++ } ++ } ++ else ++ { ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ } ++} ++ ++void dc_set_ap_channel_bandwidth(_adapter *padapter, u8 channel, u8 channel_offset, u8 bwmode) ++{ ++ u8 *p; ++ u8 val8, cur_channel, cur_bwmode, cur_ch_offset, change_band; ++ int ie_len; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct HT_info_element *pht_info=NULL; ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_priv *pbuddy_mlmepriv = NULL; ++ struct mlme_ext_priv *pbuddy_mlmeext = NULL; ++ ++ DBG_871X("dualmac_concurrent_ap_set_channel_bwmode ==>\n"); ++ ++ cur_channel = channel; ++ cur_bwmode = bwmode; ++ cur_ch_offset = channel_offset; ++ change_band = _FALSE; ++ ++ p = rtw_get_ie((pnetwork->IEs + sizeof(NDIS_802_11_FIXED_IEs)), _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - sizeof(NDIS_802_11_FIXED_IEs))); ++ if( p && ie_len) ++ { ++ pht_info = (struct HT_info_element *)(p+2); ++ } ++ ++ if(pbuddy_adapter != NULL && ++ padapter->DualMacConcurrent == _TRUE) ++ { ++ pbuddy_mlmepriv = &(pbuddy_adapter->mlmepriv); ++ pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ ++ if(!check_fwstate(pbuddy_mlmepriv, _FW_LINKED|_FW_UNDER_LINKING|_FW_UNDER_SURVEY)) ++ { ++ set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode); ++ } ++ else if(check_fwstate(pbuddy_mlmepriv, _FW_LINKED)==_TRUE) ++ { ++ //To sync cur_channel/cur_bwmode/cur_ch_offset with another adapter ++ DBG_871X("Another iface is at linked state, sync cur_channel/cur_bwmode/cur_ch_offset\n"); ++ DBG_871X("Another adapter, CH=%d, BW=%d, offset=%d\n", pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_bwmode, pbuddy_mlmeext->cur_ch_offset); ++ DBG_871X("Current adapter, CH=%d, BW=%d, offset=%d\n", cur_channel, cur_bwmode, cur_ch_offset); ++ ++ cur_channel = pbuddy_mlmeext->cur_channel; ++ if(cur_bwmode == HT_CHANNEL_WIDTH_40) ++ { ++ if(pht_info) ++ pht_info->infos[0] &= ~(BIT(0)|BIT(1)); ++ ++ if(pbuddy_mlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40) ++ { ++ cur_ch_offset = pbuddy_mlmeext->cur_ch_offset; ++ ++ //to update cur_ch_offset value in beacon ++ if(pht_info) ++ { ++ switch(cur_ch_offset) ++ { ++ case HAL_PRIME_CHNL_OFFSET_LOWER: ++ pht_info->infos[0] |= 0x1; ++ break; ++ case HAL_PRIME_CHNL_OFFSET_UPPER: ++ pht_info->infos[0] |= 0x3; ++ break; ++ case HAL_PRIME_CHNL_OFFSET_DONT_CARE: ++ default: ++ break; ++ } ++ } ++ } ++ else if(pbuddy_mlmeext->cur_bwmode == HT_CHANNEL_WIDTH_20) ++ { ++ cur_bwmode = HT_CHANNEL_WIDTH_20; ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ if(cur_channel>0 && cur_channel<5) ++ { ++ if(pht_info) ++ pht_info->infos[0] |= 0x1; ++ ++ cur_bwmode = HT_CHANNEL_WIDTH_40; ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ } ++ ++ if(cur_channel>7 && cur_channel<(14+1)) ++ { ++ if(pht_info) ++ pht_info->infos[0] |= 0x3; ++ ++ cur_bwmode = HT_CHANNEL_WIDTH_40; ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ } ++ ++ set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode); ++ } ++ } ++ ++ // to update channel value in beacon ++ pnetwork->Configuration.DSConfig = cur_channel; ++ p = rtw_get_ie((pnetwork->IEs + sizeof(NDIS_802_11_FIXED_IEs)), _DSSET_IE_, &ie_len, (pnetwork->IELength - sizeof(NDIS_802_11_FIXED_IEs))); ++ if(p && ie_len>0) ++ *(p + 2) = cur_channel; ++ ++ if(pht_info) ++ pht_info->primary_channel = cur_channel; ++ } ++ } ++ else ++ { ++ set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode); ++ } ++ ++ DBG_871X("CH=%d, BW=%d, offset=%d\n", cur_channel, cur_bwmode, cur_ch_offset); ++ ++ if((channel <= 14 && cur_channel >= 36) || ++ (channel >= 36 && cur_channel <= 14)) ++ { ++ change_band = _TRUE; ++ } ++ ++ pmlmeext->cur_channel = cur_channel; ++ pmlmeext->cur_bwmode = cur_bwmode; ++ pmlmeext->cur_ch_offset = cur_ch_offset; ++ ++ if(change_band == _TRUE) ++ dc_change_band(padapter, pnetwork); ++ ++ DBG_871X("dualmac_concurrent_ap_set_channel_bwmode <==\n"); ++} ++ ++void dc_resume_xmit(_adapter *padapter) ++{ ++ PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ ++ if(pbuddy_adapter != NULL && ++ padapter->DualMacConcurrent == _TRUE) ++ { ++ DBG_871X("dc_resume_xmit, resume pbuddy_adapter Tx\n"); ++ rtw_os_xmit_schedule(pbuddy_adapter); ++ } ++} ++ ++u8 dc_check_xmit(_adapter *padapter) ++{ ++ PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_priv *pbuddy_mlmepriv = NULL; ++ ++ if(pbuddy_adapter != NULL && ++ padapter->DualMacConcurrent == _TRUE) ++ { ++ pbuddy_mlmepriv = &(pbuddy_adapter->mlmepriv); ++ if (check_fwstate(pbuddy_mlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE) ++ { ++ DBG_871X("dc_check_xmit pbuddy_adapter is under survey or under linking\n"); ++ return _FALSE; ++ } ++ } ++ ++ return _TRUE; ++} ++#endif ++ ++#ifdef CONFIG_CONCURRENT_MODE ++sint check_buddy_mlmeinfo_state(_adapter *padapter, u32 state) ++{ ++ PADAPTER pbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext; ++ struct mlme_ext_info *pbuddy_mlmeinfo; ++ ++ if(padapter == NULL) ++ return _FALSE; ++ ++ pbuddy_adapter = padapter->pbuddy_adapter; ++ ++ if(pbuddy_adapter == NULL) ++ return _FALSE; ++ ++ ++ pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ pbuddy_mlmeinfo = &(pbuddy_mlmeext->mlmext_info); ++ ++ if((pbuddy_mlmeinfo->state&0x03) == state) ++ return _TRUE; ++ ++ return _FALSE; ++ ++} ++ ++void concurrent_chk_joinbss_done(_adapter *padapter, int join_res) ++{ ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ PADAPTER pbuddy_adapter; ++ struct mlme_priv *pbuddy_mlmepriv; ++ struct mlme_ext_priv *pbuddy_mlmeext; ++ struct mlme_ext_info *pbuddy_mlmeinfo; ++ WLAN_BSSID_EX *pbuddy_network_mlmeext; ++ ++ pmlmeext = &padapter->mlmeextpriv; ++ pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ ++ if(!rtw_buddy_adapter_up(padapter)) ++ { ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ return; ++ } ++ ++ pbuddy_adapter = padapter->pbuddy_adapter; ++ pbuddy_mlmepriv = &(pbuddy_adapter->mlmepriv); ++ pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ pbuddy_mlmeinfo = &(pbuddy_mlmeext->mlmext_info); ++ pbuddy_network_mlmeext = &(pbuddy_mlmeinfo->network); ++ ++ if(((pbuddy_mlmeinfo->state&0x03) == WIFI_FW_AP_STATE) && ++ check_fwstate(pbuddy_mlmepriv, _FW_LINKED)) ++ { ++ //restart and update beacon ++ ++ DBG_871X("after join,primary adapter, CH=%d, BW=%d, offset=%d\n" ++ , pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); ++ ++ ++ if(join_res >= 0) ++ { ++ u8 *p; ++ int ie_len; ++ struct HT_info_element *pht_info=NULL; ++ ++ //sync channel/bwmode/ch_offset with primary adapter ++ pbuddy_mlmeext->cur_channel = pmlmeext->cur_channel; ++ if(pbuddy_mlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40) ++ { ++ p = rtw_get_ie((pbuddy_network_mlmeext->IEs + sizeof(NDIS_802_11_FIXED_IEs)), _HT_ADD_INFO_IE_, &ie_len, (pbuddy_network_mlmeext->IELength - sizeof(NDIS_802_11_FIXED_IEs))); ++ if( p && ie_len) ++ { ++ pht_info = (struct HT_info_element *)(p+2); ++ pht_info->infos[0] &= ~(BIT(0)|BIT(1)); //no secondary channel is present ++ } ++ ++ if(pmlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40) ++ { ++ pbuddy_mlmeext->cur_ch_offset = pmlmeext->cur_ch_offset; ++ ++ //to update cur_ch_offset value in beacon ++ if( pht_info ) ++ { ++ switch(pmlmeext->cur_ch_offset) ++ { ++ case HAL_PRIME_CHNL_OFFSET_LOWER: ++ pht_info->infos[0] |= 0x1; ++ break; ++ case HAL_PRIME_CHNL_OFFSET_UPPER: ++ pht_info->infos[0] |= 0x3; ++ break; ++ case HAL_PRIME_CHNL_OFFSET_DONT_CARE: ++ default: ++ break; ++ } ++ ++ } ++ ++ } ++ else if(pmlmeext->cur_bwmode == HT_CHANNEL_WIDTH_20) ++ { ++ if(pmlmeext->cur_channel>=1 && pmlmeext->cur_channel<=4) ++ { ++ if(pht_info) ++ pht_info->infos[0] |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE; ++ ++ pbuddy_mlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; ++ pbuddy_mlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ } ++ else if(pmlmeext->cur_channel>=5 && pmlmeext->cur_channel<=14) ++ { ++ if(pht_info) ++ pht_info->infos[0] |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW; ++ ++ pbuddy_mlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; ++ pbuddy_mlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ } ++ else ++ { ++ switch(pmlmeext->cur_channel) ++ { ++ case 36: ++ case 44: ++ case 52: ++ case 60: ++ case 100: ++ case 108: ++ case 116: ++ case 124: ++ case 132: ++ case 149: ++ case 157: ++ { ++ if(pht_info) ++ pht_info->infos[0] |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE; ++ pbuddy_mlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; ++ pbuddy_mlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ break; ++ } ++ case 40: ++ case 48: ++ case 56: ++ case 64: ++ case 104: ++ case 112: ++ case 120: ++ case 128: ++ case 136: ++ case 153: ++ case 161: ++ { ++ if(pht_info) ++ pht_info->infos[0] |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW; ++ ++ pbuddy_mlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; ++ pbuddy_mlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ break; ++ } ++ default: ++ if(pht_info) ++ pht_info->infos[0] &= ~HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW; ++ pbuddy_mlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; ++ pbuddy_mlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ break; ++ ++ } ++ ++ } ++ ++ } ++ ++ set_channel_bwmode(padapter, pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_ch_offset, pbuddy_mlmeext->cur_bwmode); ++ ++ } ++ else ++ { ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ } ++ ++ ++ // to update channel value in beacon ++ pbuddy_network_mlmeext->Configuration.DSConfig = pmlmeext->cur_channel; ++ p = rtw_get_ie((pbuddy_network_mlmeext->IEs + sizeof(NDIS_802_11_FIXED_IEs)), _DSSET_IE_, &ie_len, (pbuddy_network_mlmeext->IELength - sizeof(NDIS_802_11_FIXED_IEs))); ++ if(p && ie_len>0) ++ *(p + 2) = pmlmeext->cur_channel; ++ ++ p = rtw_get_ie((pbuddy_network_mlmeext->IEs + sizeof(NDIS_802_11_FIXED_IEs)), _HT_ADD_INFO_IE_, &ie_len, (pbuddy_network_mlmeext->IELength - sizeof(NDIS_802_11_FIXED_IEs))); ++ if( p && ie_len) ++ { ++ pht_info = (struct HT_info_element *)(p+2); ++ pht_info->primary_channel = pmlmeext->cur_channel; ++ } ++ ++ } ++ else ++ { ++ // switch back to original channel/bwmode/ch_offset; ++ set_channel_bwmode(padapter, pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_ch_offset, pbuddy_mlmeext->cur_bwmode); ++ } ++ ++ DBG_871X("after join, second adapter, CH=%d, BW=%d, offset=%d\n", pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_bwmode, pbuddy_mlmeext->cur_ch_offset); ++ ++ DBG_871X("update pbuddy_adapter's beacon\n"); ++ ++ update_beacon(pbuddy_adapter, 0, NULL, _TRUE); ++ ++ } ++ else if(((pbuddy_mlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) && ++ check_fwstate(pbuddy_mlmepriv, _FW_LINKED)) ++ { ++ if(join_res >= 0) ++ { ++ pbuddy_mlmeext->cur_channel = pmlmeext->cur_channel; ++ if(pbuddy_mlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40) ++ set_channel_bwmode(padapter, pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_ch_offset, pbuddy_mlmeext->cur_bwmode); ++ else if(pmlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40) ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ else ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ } ++ else ++ { ++ // switch back to original channel/bwmode/ch_offset; ++ set_channel_bwmode(padapter, pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_ch_offset, pbuddy_mlmeext->cur_bwmode); ++ } ++ } ++ else ++ { ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ } ++ ++} ++#endif //CONFIG_CONCURRENT_MODE ++ ++int rtw_chk_start_clnt_join(_adapter *padapter, u8 *ch, u8 *bw, u8 *offset) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ unsigned char cur_ch = pmlmeext->cur_channel; ++ unsigned char cur_bw = pmlmeext->cur_bwmode; ++ unsigned char cur_ch_offset = pmlmeext->cur_ch_offset; ++ bool chbw_allow = _TRUE; ++ bool connect_allow = _TRUE; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ PADAPTER pbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext; ++ struct mlme_ext_info *pbuddy_pmlmeinfo; ++ struct mlme_priv *pbuddy_mlmepriv; ++ ++ if (!rtw_buddy_adapter_up(padapter)) { ++ goto exit; ++ } ++ ++ pbuddy_adapter = padapter->pbuddy_adapter; ++ pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ pbuddy_pmlmeinfo = &(pbuddy_mlmeext->mlmext_info); ++ pbuddy_mlmepriv = &(pbuddy_adapter->mlmepriv); ++ ++ if((pbuddy_pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)//for AP MODE ++ { ++ DBG_871X("start_clnt_join: "ADPT_FMT"(ch=%d, bw=%d, ch_offset=%d)" ++ ", "ADPT_FMT" AP mode(ch=%d, bw=%d, ch_offset=%d)\n", ++ ADPT_ARG(padapter), pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset, ++ ADPT_ARG(pbuddy_adapter), pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_bwmode, pbuddy_mlmeext->cur_ch_offset); ++ ++ if(pmlmeext->cur_channel != pbuddy_mlmeext->cur_channel) ++ { ++ chbw_allow = _FALSE; ++ } ++ else if((pmlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40) && ++ (pbuddy_mlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40) && ++ (pmlmeext->cur_ch_offset != pbuddy_mlmeext->cur_ch_offset)) ++ { ++ chbw_allow = _FALSE; ++ } ++ else if((pmlmeext->cur_bwmode == HT_CHANNEL_WIDTH_20) && ++ (pbuddy_mlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40)) ++ { ++ cur_ch = pmlmeext->cur_channel; ++ cur_bw = pbuddy_mlmeext->cur_bwmode; ++ cur_ch_offset = pbuddy_mlmeext->cur_ch_offset; ++ } ++ ++ DBG_871X("start_clnt_join: connect_allow:%d, chbw_allow:%d\n", connect_allow, chbw_allow); ++ if (chbw_allow == _FALSE) { ++ #ifdef CONFIG_SPCT_CH_SWITCH ++ if (1) { ++ rtw_ap_inform_ch_switch(pbuddy_adapter, pmlmeext->cur_channel , pmlmeext->cur_ch_offset); ++ } else ++ #endif ++ { ++ //issue deauth to all stas if if2 is at ap mode ++ rtw_sta_flush(pbuddy_adapter); ++ } ++ rtw_hal_set_hwreg(padapter, HW_VAR_CHECK_TXBUF, 0); ++ } ++ } ++ else if(check_fwstate(pbuddy_mlmepriv, _FW_LINKED) == _TRUE && ++ check_fwstate(pbuddy_mlmepriv, WIFI_STATION_STATE) == _TRUE) //for Client Mode/p2p client ++ { ++ DBG_871X("start_clnt_join: "ADPT_FMT"(ch=%d, bw=%d, ch_offset=%d)" ++ ", "ADPT_FMT" STA mode(ch=%d, bw=%d, ch_offset=%d)\n", ++ ADPT_ARG(padapter), pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset, ++ ADPT_ARG(pbuddy_adapter), pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_bwmode, pbuddy_mlmeext->cur_ch_offset); ++ ++ if(pmlmeext->cur_channel != pbuddy_mlmeext->cur_channel) ++ { ++ chbw_allow = _FALSE; ++ } ++ else if((pmlmeext->cur_bwmode == HT_CHANNEL_WIDTH_20) && ++ (pbuddy_mlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40)) ++ { ++ cur_bw = HT_CHANNEL_WIDTH_40; ++ cur_ch_offset = pbuddy_mlmeext->cur_ch_offset; ++ } ++ else if((pmlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40) && ++ (pbuddy_mlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40) && ++ (pmlmeext->cur_ch_offset != pbuddy_mlmeext->cur_ch_offset)) ++ { ++ chbw_allow = _FALSE; ++ } ++ ++ connect_allow = chbw_allow; ++ ++ #if defined(CONFIG_P2P) && defined(CONFIG_IOCTL_CFG80211) ++ /* wlan0-sta mode has higher priority than p2p0-p2p client */ ++ if (!rtw_p2p_chk_state(&(pbuddy_adapter->wdinfo), P2P_STATE_NONE) ++ && pbuddy_adapter->wdinfo.driver_interface == DRIVER_CFG80211) ++ { ++ connect_allow = _TRUE; ++ } ++ #endif /* CONFIG_P2P && CONFIG_IOCTL_CFG80211 */ ++ ++ DBG_871X("start_clnt_join: connect_allow:%d, chbw_allow:%d\n", connect_allow, chbw_allow); ++ if (connect_allow == _TRUE && chbw_allow == _FALSE) { ++ /* disconnect buddy's connection */ ++ rtw_disassoc_cmd(pbuddy_adapter, 500, _FALSE); ++ rtw_indicate_disconnect(pbuddy_adapter); ++ rtw_free_assoc_resources(pbuddy_adapter, 1); ++ } ++ } ++ ++exit: ++#endif /* CONFIG_CONCURRENT_MODE */ ++ ++ if (!ch || !bw || !offset) { ++ rtw_warn_on(1); ++ connect_allow = _FALSE; ++ } ++ ++ if (connect_allow == _TRUE) { ++ DBG_871X("start_join_set_ch_bw: ch=%d, bwmode=%d, ch_offset=%d\n", cur_ch, cur_bw, cur_ch_offset); ++ *ch = cur_ch; ++ *bw = cur_bw; ++ *offset = cur_ch_offset; ++ } ++ ++ return connect_allow == _TRUE ? _SUCCESS : _FAIL; ++} ++ ++/* Find union about ch, bw, ch_offset of all linked interfaces */ ++int rtw_get_ch_setting_union(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset) ++{ ++ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); ++ _adapter *iface; ++ struct mlme_ext_priv *mlmeext; ++ int i; ++ u8 ch_ret = 0; ++ u8 bw_ret = HT_CHANNEL_WIDTH_20; ++ u8 offset_ret = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ int num = 0; ++ ++ if (ch) *ch = 0; ++ if (bw) *bw = HT_CHANNEL_WIDTH_20; ++ if (offset) *offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ for (i = 0; iiface_nums; i++) { ++ iface = dvobj->padapters[i]; ++ mlmeext = &iface->mlmeextpriv; ++ ++ if (!check_fwstate(&iface->mlmepriv, _FW_LINKED)) ++ continue; ++ ++ if (num == 0) { ++ ch_ret = mlmeext->cur_channel; ++ bw_ret = mlmeext->cur_bwmode; ++ offset_ret = mlmeext->cur_ch_offset; ++ num++; ++ continue; ++ } ++ ++ if (ch_ret != mlmeext->cur_channel) { ++ num = 0; ++ break; ++ } ++ ++ if (bw_ret < mlmeext->cur_bwmode) { ++ bw_ret = mlmeext->cur_bwmode; ++ offset_ret = mlmeext->cur_ch_offset; ++ } else if (bw_ret == mlmeext->cur_bwmode && offset_ret != mlmeext->cur_ch_offset) { ++ num = 0; ++ break; ++ } ++ ++ num++; ++ } ++ ++ if (num) { ++ if (ch) *ch = ch_ret; ++ if (bw) *bw = bw_ret; ++ if (offset) *offset = offset_ret; ++ } ++ ++ return num; ++} ++ ++u8 set_ch_hdl(_adapter *padapter, u8 *pbuf) ++{ ++ struct set_ch_parm *set_ch_parm; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ if(!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ set_ch_parm = (struct set_ch_parm *)pbuf; ++ ++ DBG_871X(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n", ++ FUNC_NDEV_ARG(padapter->pnetdev), ++ set_ch_parm->ch, set_ch_parm->bw, set_ch_parm->ch_offset); ++ ++ pmlmeext->cur_channel = set_ch_parm->ch; ++ pmlmeext->cur_ch_offset = set_ch_parm->ch_offset; ++ pmlmeext->cur_bwmode = set_ch_parm->bw; ++ ++ set_channel_bwmode(padapter, set_ch_parm->ch, set_ch_parm->ch_offset, set_ch_parm->bw); ++ ++ return H2C_SUCCESS; ++} ++ ++u8 set_chplan_hdl(_adapter *padapter, unsigned char *pbuf) ++{ ++ struct SetChannelPlan_param *setChannelPlan_param; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ if(!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ setChannelPlan_param = (struct SetChannelPlan_param *)pbuf; ++ ++ pmlmeext->max_chan_nums = init_channel_set(padapter, setChannelPlan_param->channel_plan, pmlmeext->channel_set); ++ init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list); ++ ++ return H2C_SUCCESS; ++} ++ ++u8 led_blink_hdl(_adapter *padapter, unsigned char *pbuf) ++{ ++ struct LedBlink_param *ledBlink_param; ++ ++ if(!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ ledBlink_param = (struct LedBlink_param *)pbuf; ++ ++ #ifdef CONFIG_LED_HANDLED_BY_CMD_THREAD ++ BlinkHandler(ledBlink_param->pLed); ++ #endif ++ ++ return H2C_SUCCESS; ++} ++ ++u8 set_csa_hdl(_adapter *padapter, unsigned char *pbuf) ++{ ++#ifdef CONFIG_DFS ++ struct SetChannelSwitch_param *setChannelSwitch_param; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u8 new_ch_no; ++ u8 gval8 = 0x00, sval8 = 0xff; ++ ++ if(!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ setChannelSwitch_param = (struct SetChannelSwitch_param *)pbuf; ++ new_ch_no = setChannelSwitch_param->new_ch_no; ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_TXPAUSE, &gval8); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, &sval8); ++ ++ DBG_871X("DFS detected! Swiching channel to %d!\n", new_ch_no); ++ SelectChannel(padapter, new_ch_no); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, &gval8); ++ ++ rtw_free_network_queue(padapter, _TRUE); ++ rtw_indicate_disconnect(padapter); ++ ++ if ( ((new_ch_no >= 52) && (new_ch_no <= 64)) ||((new_ch_no >= 100) && (new_ch_no <= 140)) ) { ++ DBG_871X("Switched to DFS band (ch %02x) again!!\n", new_ch_no); ++ } ++ ++ return H2C_SUCCESS; ++#else ++ return H2C_REJECTED; ++#endif //CONFIG_DFS ++ ++} ++ ++// TDLS_WRCR : write RCR DATA BIT ++// TDLS_SD_PTI : issue peer traffic indication ++// TDLS_CS_OFF : go back to the channel linked with AP, terminating channel switch procedure ++// TDLS_INIT_CH_SEN : init channel sensing, receive all data and mgnt frame ++// TDLS_DONE_CH_SEN: channel sensing and report candidate channel ++// TDLS_OFF_CH : first time set channel to off channel ++// TDLS_BASE_CH : go back tp the channel linked with AP when set base channel as target channel ++// TDLS_P_OFF_CH : periodically go to off channel ++// TDLS_P_BASE_CH : periodically go back to base channel ++// TDLS_RS_RCR : restore RCR ++// TDLS_CKALV_PH1 : check alive timer phase1 ++// TDLS_CKALV_PH2 : check alive timer phase2 ++// TDLS_FREE_STA : free tdls sta ++u8 tdls_hdl(_adapter *padapter, unsigned char *pbuf) ++{ ++#ifdef CONFIG_TDLS ++ _irqL irqL; ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ struct TDLSoption_param *TDLSoption; ++ struct sta_info *ptdls_sta; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u8 survey_channel, i, min, option; ++ ++ if(!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ TDLSoption = (struct TDLSoption_param *)pbuf; ++ ++ ptdls_sta = rtw_get_stainfo( &(padapter->stapriv), TDLSoption->addr ); ++ option = TDLSoption->option; ++ ++ if( ptdls_sta == NULL ) ++ { ++ if( option != TDLS_RS_RCR ) ++ return H2C_REJECTED; ++ } ++ ++ //_enter_critical_bh(&(ptdlsinfo->hdl_lock), &irqL); ++ DBG_871X("[%s] option:%d\n", __FUNCTION__, option); ++ ++ switch(option){ ++ case TDLS_WRCR: ++ //As long as TDLS handshake success, we should set RCR_CBSSID_DATA bit to 0 ++ //such we can receive all kinds of data frames. ++ rtw_hal_set_hwreg(padapter, HW_VAR_TDLS_WRCR, 0); ++ DBG_871X("TDLS with "MAC_FMT"\n", MAC_ARG(ptdls_sta->hwaddr)); ++ ++ pmlmeinfo->FW_sta_info[ptdls_sta->mac_id].psta = ptdls_sta; ++ //set TDLS sta rate. ++ set_sta_rate(padapter, ptdls_sta); ++ break; ++ case TDLS_SD_PTI: ++ issue_tdls_peer_traffic_indication(padapter, ptdls_sta); ++ break; ++ case TDLS_CS_OFF: ++ _cancel_timer_ex(&ptdls_sta->base_ch_timer); ++ _cancel_timer_ex(&ptdls_sta->off_ch_timer); ++ SelectChannel(padapter, pmlmeext->cur_channel); ++ ptdls_sta->tdls_sta_state &= ~(TDLS_CH_SWITCH_ON_STATE | ++ TDLS_PEER_AT_OFF_STATE | ++ TDLS_AT_OFF_CH_STATE); ++ DBG_871X("go back to base channel\n "); ++ issue_nulldata(padapter, NULL, 0, 0, 0); ++ break; ++ case TDLS_INIT_CH_SEN: ++ rtw_hal_set_hwreg(padapter, HW_VAR_TDLS_INIT_CH_SEN, 0); ++ pmlmeext->sitesurvey_res.channel_idx = 0; ++ ptdls_sta->option = TDLS_DONE_CH_SEN; ++ rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_DONE_CH_SEN); ++ break; ++ case TDLS_DONE_CH_SEN: ++ survey_channel = pmlmeext->channel_set[pmlmeext->sitesurvey_res.channel_idx].ChannelNum; ++ if(survey_channel){ ++ SelectChannel(padapter, survey_channel); ++ ptdlsinfo->cur_channel = survey_channel; ++ pmlmeext->sitesurvey_res.channel_idx++; ++ _set_timer(&ptdls_sta->option_timer, SURVEY_TO); ++ }else{ ++ SelectChannel(padapter, pmlmeext->cur_channel); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_TDLS_DONE_CH_SEN, 0); ++ ++ if(ptdlsinfo->ch_sensing==1){ ++ ptdlsinfo->ch_sensing=0; ++ ptdlsinfo->cur_channel=1; ++ min=ptdlsinfo->collect_pkt_num[0]; ++ for(i=1; i ptdlsinfo->collect_pkt_num[i]){ ++ ptdlsinfo->cur_channel=i+1; ++ min=ptdlsinfo->collect_pkt_num[i]; ++ } ++ ptdlsinfo->collect_pkt_num[i]=0; ++ } ++ ptdlsinfo->collect_pkt_num[0]=0; ++ ptdlsinfo->candidate_ch=ptdlsinfo->cur_channel; ++ DBG_871X("TDLS channel sensing done, candidate channel: %02x\n", ptdlsinfo->candidate_ch); ++ ptdlsinfo->cur_channel=0; ++ ++ } ++ ++ if(ptdls_sta->tdls_sta_state & TDLS_PEER_SLEEP_STATE){ ++ ptdls_sta->tdls_sta_state |= TDLS_APSD_CHSW_STATE; ++ }else{ ++ //send null data with pwrbit==1 before send ch_switching_req to peer STA. ++ issue_nulldata(padapter, NULL, 1, 0, 0); ++ ++ ptdls_sta->tdls_sta_state |= TDLS_CH_SW_INITIATOR_STATE; ++ ++ issue_tdls_ch_switch_req(padapter, ptdls_sta->hwaddr); ++ DBG_871X("issue tdls ch switch req\n"); ++ } ++ } ++ break; ++ case TDLS_OFF_CH: ++ issue_nulldata(padapter, NULL, 1, 0, 0); ++ SelectChannel(padapter, ptdls_sta->off_ch); ++ ++ DBG_871X("change channel to tar ch:%02x\n", ptdls_sta->off_ch); ++ ptdls_sta->tdls_sta_state |= TDLS_AT_OFF_CH_STATE; ++ ptdls_sta->tdls_sta_state &= ~(TDLS_PEER_AT_OFF_STATE); ++ _set_timer(&ptdls_sta->option_timer, (u32)ptdls_sta->ch_switch_time); ++ break; ++ case TDLS_BASE_CH: ++ _cancel_timer_ex(&ptdls_sta->base_ch_timer); ++ _cancel_timer_ex(&ptdls_sta->off_ch_timer); ++ SelectChannel(padapter, pmlmeext->cur_channel); ++ ptdls_sta->tdls_sta_state &= ~(TDLS_CH_SWITCH_ON_STATE | ++ TDLS_PEER_AT_OFF_STATE | ++ TDLS_AT_OFF_CH_STATE); ++ DBG_871X("go back to base channel\n "); ++ issue_nulldata(padapter, NULL, 0, 0, 0); ++ _set_timer(&ptdls_sta->option_timer, (u32)ptdls_sta->ch_switch_time); ++ break; ++ case TDLS_P_OFF_CH: ++ SelectChannel(padapter, pmlmeext->cur_channel); ++ issue_nulldata(padapter, NULL, 0, 0, 0); ++ DBG_871X("change channel to base ch:%02x\n", pmlmeext->cur_channel); ++ ptdls_sta->tdls_sta_state &= ~(TDLS_PEER_AT_OFF_STATE| TDLS_AT_OFF_CH_STATE); ++ _set_timer(&ptdls_sta->off_ch_timer, TDLS_STAY_TIME); ++ break; ++ case TDLS_P_BASE_CH: ++ issue_nulldata(ptdls_sta->padapter, NULL, 1, 0, 0); ++ SelectChannel(padapter, ptdls_sta->off_ch); ++ DBG_871X("change channel to off ch:%02x\n", ptdls_sta->off_ch); ++ ptdls_sta->tdls_sta_state |= TDLS_AT_OFF_CH_STATE; ++ if((ptdls_sta->tdls_sta_state & TDLS_PEER_AT_OFF_STATE) != TDLS_PEER_AT_OFF_STATE){ ++ issue_nulldata_to_TDLS_peer_STA(padapter, ptdls_sta, 0); ++ } ++ _set_timer(&ptdls_sta->base_ch_timer, TDLS_STAY_TIME); ++ break; ++ case TDLS_RS_RCR: ++ rtw_hal_set_hwreg(padapter, HW_VAR_TDLS_RS_RCR, 0); ++ DBG_871X("wirte REG_RCR, set bit6 on\n"); ++ break; ++ case TDLS_CKALV_PH1: ++ _set_timer(&ptdls_sta->alive_timer2, TDLS_ALIVE_TIMER_PH2); ++ break; ++ case TDLS_CKALV_PH2: ++ _set_timer(&ptdls_sta->alive_timer1, TDLS_ALIVE_TIMER_PH1); ++ break; ++ case TDLS_FREE_STA: ++ free_tdls_sta(padapter, ptdls_sta); ++ break; ++ ++ } ++ ++ //_exit_critical_bh(&(ptdlsinfo->hdl_lock), &irqL); ++ ++ return H2C_SUCCESS; ++#else ++ return H2C_REJECTED; ++#endif //CONFIG_TDLS ++ ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_mp.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_mp.c +new file mode 100644 +index 00000000..75f0da1a +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_mp.c +@@ -0,0 +1,1620 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_MP_C_ ++ ++#include ++ ++#ifdef PLATFORM_FREEBSD ++#include /* for RFHIGHPID */ ++#endif ++ ++#ifdef CONFIG_RTL8712 ++#include ++#endif ++#ifdef CONFIG_RTL8192C ++#include ++#endif ++#ifdef CONFIG_RTL8192D ++#include ++#endif ++#ifdef CONFIG_RTL8723A ++#include ++#include "rtw_bt_mp.h" ++#endif ++#ifdef CONFIG_RTL8188E ++#include "../hal/OUTSRC/odm_precomp.h" ++#include "rtl8188e_hal.h" ++#endif ++ ++ ++#ifdef CONFIG_MP_INCLUDED ++ ++u32 read_macreg(_adapter *padapter, u32 addr, u32 sz) ++{ ++ u32 val = 0; ++ ++ switch(sz) ++ { ++ case 1: ++ val = rtw_read8(padapter, addr); ++ break; ++ case 2: ++ val = rtw_read16(padapter, addr); ++ break; ++ case 4: ++ val = rtw_read32(padapter, addr); ++ break; ++ default: ++ val = 0xffffffff; ++ break; ++ } ++ ++ return val; ++ ++} ++ ++void write_macreg(_adapter *padapter, u32 addr, u32 val, u32 sz) ++{ ++ switch(sz) ++ { ++ case 1: ++ rtw_write8(padapter, addr, (u8)val); ++ break; ++ case 2: ++ rtw_write16(padapter, addr, (u16)val); ++ break; ++ case 4: ++ rtw_write32(padapter, addr, val); ++ break; ++ default: ++ break; ++ } ++ ++} ++ ++u32 read_bbreg(_adapter *padapter, u32 addr, u32 bitmask) ++{ ++ return rtw_hal_read_bbreg(padapter, addr, bitmask); ++} ++ ++void write_bbreg(_adapter *padapter, u32 addr, u32 bitmask, u32 val) ++{ ++ rtw_hal_write_bbreg(padapter, addr, bitmask, val); ++} ++ ++u32 _read_rfreg(PADAPTER padapter, u8 rfpath, u32 addr, u32 bitmask) ++{ ++ return rtw_hal_read_rfreg(padapter, (RF_RADIO_PATH_E)rfpath, addr, bitmask); ++} ++ ++void _write_rfreg(PADAPTER padapter, u8 rfpath, u32 addr, u32 bitmask, u32 val) ++{ ++ rtw_hal_write_rfreg(padapter, (RF_RADIO_PATH_E)rfpath, addr, bitmask, val); ++} ++ ++u32 read_rfreg(PADAPTER padapter, u8 rfpath, u32 addr) ++{ ++ return _read_rfreg(padapter, (RF_RADIO_PATH_E)rfpath, addr, bRFRegOffsetMask); ++} ++ ++void write_rfreg(PADAPTER padapter, u8 rfpath, u32 addr, u32 val) ++{ ++ _write_rfreg(padapter, (RF_RADIO_PATH_E)rfpath, addr, bRFRegOffsetMask, val); ++} ++ ++static void _init_mp_priv_(struct mp_priv *pmp_priv) ++{ ++ WLAN_BSSID_EX *pnetwork; ++ ++ _rtw_memset(pmp_priv, 0, sizeof(struct mp_priv)); ++ ++ pmp_priv->mode = MP_OFF; ++ ++ pmp_priv->channel = 1; ++ pmp_priv->bandwidth = HT_CHANNEL_WIDTH_20; ++ pmp_priv->prime_channel_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ pmp_priv->rateidx = MPT_RATE_1M; ++ pmp_priv->txpoweridx = 0x2A; ++ ++ pmp_priv->antenna_tx = ANTENNA_A; ++ pmp_priv->antenna_rx = ANTENNA_AB; ++ ++ pmp_priv->check_mp_pkt = 0; ++ ++ pmp_priv->tx_pktcount = 0; ++ ++ pmp_priv->rx_pktcount = 0; ++ pmp_priv->rx_crcerrpktcount = 0; ++ ++ pmp_priv->network_macaddr[0] = 0x00; ++ pmp_priv->network_macaddr[1] = 0xE0; ++ pmp_priv->network_macaddr[2] = 0x4C; ++ pmp_priv->network_macaddr[3] = 0x87; ++ pmp_priv->network_macaddr[4] = 0x66; ++ pmp_priv->network_macaddr[5] = 0x55; ++ ++ pnetwork = &pmp_priv->mp_network.network; ++ _rtw_memcpy(pnetwork->MacAddress, pmp_priv->network_macaddr, ETH_ALEN); ++ ++ pnetwork->Ssid.SsidLength = 8; ++ _rtw_memcpy(pnetwork->Ssid.Ssid, "mp_871x", pnetwork->Ssid.SsidLength); ++} ++ ++#ifdef PLATFORM_WINDOWS ++/* ++void mp_wi_callback( ++ IN NDIS_WORK_ITEM* pwk_item, ++ IN PVOID cntx ++ ) ++{ ++ _adapter* padapter =(_adapter *)cntx; ++ struct mp_priv *pmppriv=&padapter->mppriv; ++ struct mp_wi_cntx *pmp_wi_cntx=&pmppriv->wi_cntx; ++ ++ // Execute specified action. ++ if(pmp_wi_cntx->curractfunc != NULL) ++ { ++ LARGE_INTEGER cur_time; ++ ULONGLONG start_time, end_time; ++ NdisGetCurrentSystemTime(&cur_time); // driver version ++ start_time = cur_time.QuadPart/10; // The return value is in microsecond ++ ++ pmp_wi_cntx->curractfunc(padapter); ++ ++ NdisGetCurrentSystemTime(&cur_time); // driver version ++ end_time = cur_time.QuadPart/10; // The return value is in microsecond ++ ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("WorkItemActType: %d, time spent: %I64d us\n", ++ pmp_wi_cntx->param.act_type, (end_time-start_time))); ++ } ++ ++ NdisAcquireSpinLock(&(pmp_wi_cntx->mp_wi_lock)); ++ pmp_wi_cntx->bmp_wi_progress= _FALSE; ++ NdisReleaseSpinLock(&(pmp_wi_cntx->mp_wi_lock)); ++ ++ if (pmp_wi_cntx->bmpdrv_unload) ++ { ++ NdisSetEvent(&(pmp_wi_cntx->mp_wi_evt)); ++ } ++ ++} ++*/ ++ ++static int init_mp_priv_by_os(struct mp_priv *pmp_priv) ++{ ++ struct mp_wi_cntx *pmp_wi_cntx; ++ ++ if (pmp_priv == NULL) return _FAIL; ++ ++ pmp_priv->rx_testcnt = 0; ++ pmp_priv->rx_testcnt1 = 0; ++ pmp_priv->rx_testcnt2 = 0; ++ ++ pmp_priv->tx_testcnt = 0; ++ pmp_priv->tx_testcnt1 = 0; ++ ++ pmp_wi_cntx = &pmp_priv->wi_cntx ++ pmp_wi_cntx->bmpdrv_unload = _FALSE; ++ pmp_wi_cntx->bmp_wi_progress = _FALSE; ++ pmp_wi_cntx->curractfunc = NULL; ++ ++ return _SUCCESS; ++} ++#endif ++ ++#ifdef PLATFORM_LINUX ++static int init_mp_priv_by_os(struct mp_priv *pmp_priv) ++{ ++ int i, res; ++ struct mp_xmit_frame *pmp_xmitframe; ++ ++ if (pmp_priv == NULL) return _FAIL; ++ ++ _rtw_init_queue(&pmp_priv->free_mp_xmitqueue); ++ ++ pmp_priv->pallocated_mp_xmitframe_buf = NULL; ++ pmp_priv->pallocated_mp_xmitframe_buf = rtw_zmalloc(NR_MP_XMITFRAME * sizeof(struct mp_xmit_frame) + 4); ++ if (pmp_priv->pallocated_mp_xmitframe_buf == NULL) { ++ res = _FAIL; ++ goto _exit_init_mp_priv; ++ } ++ ++ pmp_priv->pmp_xmtframe_buf = pmp_priv->pallocated_mp_xmitframe_buf + 4 - ((SIZE_PTR) (pmp_priv->pallocated_mp_xmitframe_buf) & 3); ++ ++ pmp_xmitframe = (struct mp_xmit_frame*)pmp_priv->pmp_xmtframe_buf; ++ ++ for (i = 0; i < NR_MP_XMITFRAME; i++) ++ { ++ _rtw_init_listhead(&pmp_xmitframe->list); ++ rtw_list_insert_tail(&pmp_xmitframe->list, &pmp_priv->free_mp_xmitqueue.queue); ++ ++ pmp_xmitframe->pkt = NULL; ++ pmp_xmitframe->frame_tag = MP_FRAMETAG; ++ pmp_xmitframe->padapter = pmp_priv->papdater; ++ ++ pmp_xmitframe++; ++ } ++ ++ pmp_priv->free_mp_xmitframe_cnt = NR_MP_XMITFRAME; ++ ++ res = _SUCCESS; ++ ++_exit_init_mp_priv: ++ ++ return res; ++} ++#endif ++ ++static void mp_init_xmit_attrib(struct mp_tx *pmptx, PADAPTER padapter) ++{ ++ struct pkt_attrib *pattrib; ++ struct tx_desc *desc; ++ ++ // init xmitframe attribute ++ pattrib = &pmptx->attrib; ++ _rtw_memset(pattrib, 0, sizeof(struct pkt_attrib)); ++ desc = &pmptx->desc; ++ _rtw_memset(desc, 0, TXDESC_SIZE); ++ ++ pattrib->ether_type = 0x8712; ++ //_rtw_memcpy(pattrib->src, padapter->eeprompriv.mac_addr, ETH_ALEN); ++// _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ _rtw_memset(pattrib->dst, 0xFF, ETH_ALEN); ++// pattrib->pctrl = 0; ++// pattrib->dhcp_pkt = 0; ++// pattrib->pktlen = 0; ++ pattrib->ack_policy = 0; ++// pattrib->pkt_hdrlen = ETH_HLEN; ++ pattrib->hdrlen = WLAN_HDR_A3_LEN; ++ pattrib->subtype = WIFI_DATA; ++ pattrib->priority = 0; ++ pattrib->qsel = pattrib->priority; ++// do_queue_select(padapter, pattrib); ++ pattrib->nr_frags = 1; ++ pattrib->encrypt = 0; ++ pattrib->bswenc = _FALSE; ++ pattrib->qos_en = _FALSE; ++} ++ ++s32 init_mp_priv(PADAPTER padapter) ++{ ++ struct mp_priv *pmppriv = &padapter->mppriv; ++ ++ _init_mp_priv_(pmppriv); ++ pmppriv->papdater = padapter; ++ ++ pmppriv->tx.stop = 1; ++ mp_init_xmit_attrib(&pmppriv->tx, padapter); ++ ++ switch (padapter->registrypriv.rf_config) { ++ case RF_1T1R: ++ pmppriv->antenna_tx = ANTENNA_A; ++ pmppriv->antenna_rx = ANTENNA_A; ++ break; ++ case RF_1T2R: ++ default: ++ pmppriv->antenna_tx = ANTENNA_A; ++ pmppriv->antenna_rx = ANTENNA_AB; ++ break; ++ case RF_2T2R: ++ case RF_2T2R_GREEN: ++ pmppriv->antenna_tx = ANTENNA_AB; ++ pmppriv->antenna_rx = ANTENNA_AB; ++ break; ++ case RF_2T4R: ++ pmppriv->antenna_tx = ANTENNA_AB; ++ pmppriv->antenna_rx = ANTENNA_ABCD; ++ break; ++ } ++ ++ return _SUCCESS; ++} ++ ++void free_mp_priv(struct mp_priv *pmp_priv) ++{ ++ if (pmp_priv->pallocated_mp_xmitframe_buf) { ++ rtw_mfree(pmp_priv->pallocated_mp_xmitframe_buf, 0); ++ pmp_priv->pallocated_mp_xmitframe_buf = NULL; ++ } ++ pmp_priv->pmp_xmtframe_buf = NULL; ++} ++ ++#if defined (CONFIG_RTL8192C) || defined (CONFIG_RTL8723A) ++#define PHY_IQCalibrate(a,b) rtl8192c_PHY_IQCalibrate(a,b) ++#define PHY_LCCalibrate(a) rtl8192c_PHY_LCCalibrate(a) ++//#define dm_CheckTXPowerTracking(a) rtl8192c_odm_CheckTXPowerTracking(a) ++#define PHY_SetRFPathSwitch(a,b) rtl8192c_PHY_SetRFPathSwitch(a,b) ++#endif ++ ++#ifdef CONFIG_RTL8192D ++#define PHY_IQCalibrate(a,b) rtl8192d_PHY_IQCalibrate(a) ++#define PHY_LCCalibrate(a) rtl8192d_PHY_LCCalibrate(a) ++//#define dm_CheckTXPowerTracking(a) rtl8192d_odm_CheckTXPowerTracking(a) ++#define PHY_SetRFPathSwitch(a,b) rtl8192d_PHY_SetRFPathSwitch(a,b) ++#endif ++ ++#ifdef CONFIG_RTL8188E ++#define PHY_IQCalibrate(a,b) PHY_IQCalibrate_8188E(a,b) ++#define PHY_LCCalibrate(a) PHY_LCCalibrate_8188E(a) ++#define PHY_SetRFPathSwitch(a,b) PHY_SetRFPathSwitch_8188E(a,b) ++#endif ++ ++s32 ++MPT_InitializeAdapter( ++ IN PADAPTER pAdapter, ++ IN u8 Channel ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ s32 rtStatus = _SUCCESS; ++ PMPT_CONTEXT pMptCtx = &pAdapter->mppriv.MptCtx; ++ u32 ledsetting; ++ struct mlme_priv *pmlmepriv = &pAdapter->mlmepriv; ++ ++ //------------------------------------------------------------------------- ++ // HW Initialization for 8190 MPT. ++ //------------------------------------------------------------------------- ++ //------------------------------------------------------------------------- ++ // SW Initialization for 8190 MP. ++ //------------------------------------------------------------------------- ++ pMptCtx->bMptDrvUnload = _FALSE; ++ pMptCtx->bMassProdTest = _FALSE; ++ pMptCtx->bMptIndexEven = _TRUE; //default gain index is -6.0db ++ pMptCtx->h2cReqNum = 0x0; ++ /* Init mpt event. */ ++#if 0 // for Windows ++ NdisInitializeEvent( &(pMptCtx->MptWorkItemEvent) ); ++ NdisAllocateSpinLock( &(pMptCtx->MptWorkItemSpinLock) ); ++ ++ PlatformInitializeWorkItem( ++ Adapter, ++ &(pMptCtx->MptWorkItem), ++ (RT_WORKITEM_CALL_BACK)MPT_WorkItemCallback, ++ (PVOID)Adapter, ++ "MptWorkItem"); ++#endif ++ //init for BT MP ++#ifdef CONFIG_RTL8723A ++ pMptCtx->bMPh2c_timeout = _FALSE; ++ pMptCtx->MptH2cRspEvent = _FALSE; ++ pMptCtx->MptBtC2hEvent = _FALSE; ++ ++ _rtw_init_sema(&pMptCtx->MPh2c_Sema, 0); ++ _init_timer( &pMptCtx->MPh2c_timeout_timer, pAdapter->pnetdev, MPh2c_timeout_handle, pAdapter ); ++ ++ //before the reset bt patch command,set the wifi page 0's IO to BT mac reboot. ++#endif ++ ++ pMptCtx->bMptWorkItemInProgress = _FALSE; ++ pMptCtx->CurrMptAct = NULL; ++ //------------------------------------------------------------------------- ++ ++#if 1 ++ // Don't accept any packets ++ rtw_write32(pAdapter, REG_RCR, 0); ++#else ++ // Accept CRC error and destination address ++ //pHalData->ReceiveConfig |= (RCR_ACRC32|RCR_AAP); ++ //rtw_write32(pAdapter, REG_RCR, pHalData->ReceiveConfig); ++ rtw_write32(pAdapter, REG_RCR, 0x70000101); ++#endif ++ ++#if 0 ++ // If EEPROM or EFUSE is empty,we assign as RF 2T2R for MP. ++ if (pHalData->AutoloadFailFlag == TRUE) ++ { ++ pHalData->RF_Type = RF_2T2R; ++ } ++#endif ++ ++ //ledsetting = rtw_read32(pAdapter, REG_LEDCFG0); ++ //rtw_write32(pAdapter, REG_LEDCFG0, ledsetting & ~LED0DIS); ++ ++ if(IS_HARDWARE_TYPE_8192DU(pAdapter)) ++ { ++ rtw_write32(pAdapter, REG_LEDCFG0, 0x8888); ++ } ++ else ++ { ++ //rtw_write32(pAdapter, REG_LEDCFG0, 0x08080); ++ ledsetting = rtw_read32(pAdapter, REG_LEDCFG0); ++ ++ #if defined (CONFIG_RTL8192C) || defined( CONFIG_RTL8192D ) ++ rtw_write32(pAdapter, REG_LEDCFG0, ledsetting & ~LED0DIS); ++ #endif ++ } ++ ++ PHY_IQCalibrate(pAdapter, _FALSE); ++ dm_CheckTXPowerTracking(&pHalData->odmpriv); //trigger thermal meter ++ PHY_LCCalibrate(pAdapter); ++ ++#ifdef CONFIG_PCI_HCI ++ PHY_SetRFPathSwitch(pAdapter, 1/*pHalData->bDefaultAntenna*/); //Wifi default use Main ++#else ++ ++#ifdef CONFIG_RTL8192C ++ if (pHalData->BoardType == BOARD_MINICARD) ++ PHY_SetRFPathSwitch(pAdapter, 1/*pHalData->bDefaultAntenna*/); //default use Main ++#endif ++ ++#endif ++ ++ pMptCtx->backup0xc50 = (u1Byte)PHY_QueryBBReg(pAdapter, rOFDM0_XAAGCCore1, bMaskByte0); ++ pMptCtx->backup0xc58 = (u1Byte)PHY_QueryBBReg(pAdapter, rOFDM0_XBAGCCore1, bMaskByte0); ++ pMptCtx->backup0xc30 = (u1Byte)PHY_QueryBBReg(pAdapter, rOFDM0_RxDetector1, bMaskByte0); ++#ifdef CONFIG_RTL8188E ++ pMptCtx->backup0x52_RF_A = (u1Byte)PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0); ++ pMptCtx->backup0x52_RF_B = (u1Byte)PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0); ++#endif ++ //set ant to wifi side in mp mode ++#ifdef CONFIG_RTL8723A ++ rtl8723a_InitAntenna_Selection(pAdapter); ++#endif //CONFIG_RTL8723A ++ ++ //set ant to wifi side in mp mode ++ rtw_write16(pAdapter, 0x870, 0x300); ++ rtw_write16(pAdapter, 0x860, 0x110); ++ ++ if (pAdapter->registrypriv.mp_mode == 1) ++ pmlmepriv->fw_state = WIFI_MP_STATE; ++ ++ return rtStatus; ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: MPT_DeInitAdapter() ++ * ++ * Overview: Extra DeInitialization for Mass Production Test. ++ * ++ * Input: PADAPTER pAdapter ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/08/2007 MHC Create Version 0. ++ * 05/18/2007 MHC Add normal driver MPHalt code. ++ * ++ *---------------------------------------------------------------------------*/ ++VOID ++MPT_DeInitAdapter( ++ IN PADAPTER pAdapter ++ ) ++{ ++ PMPT_CONTEXT pMptCtx = &pAdapter->mppriv.MptCtx; ++ ++ pMptCtx->bMptDrvUnload = _TRUE; ++ #ifdef CONFIG_RTL8723A ++ _rtw_free_sema(&(pMptCtx->MPh2c_Sema)); ++ _cancel_timer_ex( &pMptCtx->MPh2c_timeout_timer); ++ ++ rtw_write32(pAdapter, 0xcc, (rtw_read32(pAdapter, 0xcc)& 0xFFFFFFFD)| 0x00000002); ++ rtw_write32(pAdapter, 0x6b, (rtw_read32(pAdapter, 0x6b)& 0xFFFFFFFB)); ++ rtw_msleep_os(500); ++ rtw_write32(pAdapter, 0x6b, (rtw_read32(pAdapter, 0x6b)& 0xFFFFFFFB)| 0x00000004); ++ rtw_write32(pAdapter, 0xcc, (rtw_read32(pAdapter, 0xcc)& 0xFFFFFFFD)); ++ rtw_msleep_os(1000); ++ ++ DBG_871X("_rtw_mp_xmit_priv reinit for normal mode\n"); ++ _rtw_mp_xmit_priv(&pAdapter->xmitpriv); ++ #endif ++#if 0 // for Windows ++ PlatformFreeWorkItem( &(pMptCtx->MptWorkItem) ); ++ ++ while(pMptCtx->bMptWorkItemInProgress) ++ { ++ if(NdisWaitEvent(&(pMptCtx->MptWorkItemEvent), 50)) ++ { ++ break; ++ } ++ } ++ NdisFreeSpinLock( &(pMptCtx->MptWorkItemSpinLock) ); ++#endif ++ ++} ++ ++static u8 mpt_ProStartTest(PADAPTER padapter) ++{ ++ PMPT_CONTEXT pMptCtx = &padapter->mppriv.MptCtx; ++ ++ pMptCtx->bMassProdTest = _TRUE; ++ pMptCtx->bStartContTx = _FALSE; ++ pMptCtx->bCckContTx = _FALSE; ++ pMptCtx->bOfdmContTx = _FALSE; ++ pMptCtx->bSingleCarrier = _FALSE; ++ pMptCtx->bCarrierSuppression = _FALSE; ++ pMptCtx->bSingleTone = _FALSE; ++ ++ return _SUCCESS; ++} ++ ++/* ++ * General use ++ */ ++s32 SetPowerTracking(PADAPTER padapter, u8 enable) ++{ ++ ++ Hal_SetPowerTracking( padapter, enable ); ++ return 0; ++} ++ ++void GetPowerTracking(PADAPTER padapter, u8 *enable) ++{ ++ Hal_GetPowerTracking( padapter, enable ); ++} ++ ++static void disable_dm(PADAPTER padapter) ++{ ++#ifndef CONFIG_RTL8723A ++ u8 v8; ++#endif ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ ++ //3 1. disable firmware dynamic mechanism ++ // disable Power Training, Rate Adaptive ++#ifdef CONFIG_RTL8723A ++ SetBcnCtrlReg(padapter, 0, EN_BCN_FUNCTION); ++#else ++ v8 = rtw_read8(padapter, REG_BCN_CTRL); ++ v8 &= ~EN_BCN_FUNCTION; ++ rtw_write8(padapter, REG_BCN_CTRL, v8); ++#endif ++ ++ //3 2. disable driver dynamic mechanism ++ // disable Dynamic Initial Gain ++ // disable High Power ++ // disable Power Tracking ++ Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, _FALSE); ++ ++ // enable APK, LCK and IQK but disable power tracking ++#ifndef CONFIG_RTL8188E ++ pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = _FALSE; ++#endif ++ Switch_DM_Func(padapter, DYNAMIC_RF_CALIBRATION, _TRUE); ++} ++ ++ ++void MPT_PwrCtlDM(PADAPTER padapter, u32 bstart) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ //Switch_DM_Func(padapter, DYNAMIC_RF_CALIBRATION, bstart); ++ if (bstart==1){ ++ DBG_871X("in MPT_PwrCtlDM start \n"); ++ Switch_DM_Func(padapter, DYNAMIC_RF_TX_PWR_TRACK, _TRUE); ++ pdmpriv->InitODMFlag |= ODM_RF_TX_PWR_TRACK ; ++ pdmpriv->InitODMFlag |= ODM_RF_CALIBRATION ; ++ pdmpriv->TxPowerTrackControl = _TRUE; ++#ifndef CONFIG_RTL8188E ++ pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = _TRUE; ++#endif ++ }else{ ++ DBG_871X("in MPT_PwrCtlDM stop \n"); ++ disable_dm(padapter); ++ pdmpriv->TxPowerTrackControl = _FALSE; ++ #ifndef CONFIG_RTL8188E ++ pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = _FALSE; ++ #endif ++ ++ } ++ ++} ++ ++ ++//This function initializes the DUT to the MP test mode ++s32 mp_start_test(PADAPTER padapter) ++{ ++ WLAN_BSSID_EX bssid; ++ struct sta_info *psta; ++ u32 length; ++ u8 val8; ++ ++ _irqL irqL; ++ s32 res = _SUCCESS; ++ ++ struct mp_priv *pmppriv = &padapter->mppriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *tgt_network = &pmlmepriv->cur_network; ++ ++ padapter->registrypriv.mp_mode = 1; ++ pmppriv->bSetTxPower=0; //for manually set tx power ++ ++ //3 disable dynamic mechanism ++ disable_dm(padapter); ++ //3 0. update mp_priv ++ ++ if (padapter->registrypriv.rf_config == RF_819X_MAX_TYPE) { ++// switch (phal->rf_type) { ++ switch (GET_RF_TYPE(padapter)) { ++ case RF_1T1R: ++ pmppriv->antenna_tx = ANTENNA_A; ++ pmppriv->antenna_rx = ANTENNA_A; ++ break; ++ case RF_1T2R: ++ default: ++ pmppriv->antenna_tx = ANTENNA_A; ++ pmppriv->antenna_rx = ANTENNA_AB; ++ break; ++ case RF_2T2R: ++ case RF_2T2R_GREEN: ++ pmppriv->antenna_tx = ANTENNA_AB; ++ pmppriv->antenna_rx = ANTENNA_AB; ++ break; ++ case RF_2T4R: ++ pmppriv->antenna_tx = ANTENNA_AB; ++ pmppriv->antenna_rx = ANTENNA_ABCD; ++ break; ++ } ++ } ++ ++ mpt_ProStartTest(padapter); ++ ++ //3 1. initialize a new WLAN_BSSID_EX ++// _rtw_memset(&bssid, 0, sizeof(WLAN_BSSID_EX)); ++ _rtw_memcpy(bssid.MacAddress, pmppriv->network_macaddr, ETH_ALEN); ++ bssid.Ssid.SsidLength = strlen("mp_pseudo_adhoc"); ++ _rtw_memcpy(bssid.Ssid.Ssid, (u8*)"mp_pseudo_adhoc", bssid.Ssid.SsidLength); ++ bssid.InfrastructureMode = Ndis802_11IBSS; ++ bssid.NetworkTypeInUse = Ndis802_11DS; ++ bssid.IELength = 0; ++ ++ length = get_WLAN_BSSID_EX_sz(&bssid); ++ if (length % 4) ++ bssid.Length = ((length >> 2) + 1) << 2; //round up to multiple of 4 bytes. ++ else ++ bssid.Length = length; ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) ++ goto end_of_mp_start_test; ++ ++ //init mp_start_test status ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { ++ rtw_disassoc_cmd(padapter, 500, _TRUE); ++ rtw_indicate_disconnect(padapter); ++ rtw_free_assoc_resources(padapter, 1); ++ } ++ pmppriv->prev_fw_state = get_fwstate(pmlmepriv); ++ if (padapter->registrypriv.mp_mode == 1) ++ pmlmepriv->fw_state = WIFI_MP_STATE; ++#if 0 ++ if (pmppriv->mode == _LOOPBOOK_MODE_) { ++ set_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE); //append txdesc ++ RT_TRACE(_module_mp_, _drv_notice_, ("+start mp in Lookback mode\n")); ++ } else { ++ RT_TRACE(_module_mp_, _drv_notice_, ("+start mp in normal mode\n")); ++ } ++#endif ++ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); ++ ++ //3 2. create a new psta for mp driver ++ //clear psta in the cur_network, if any ++ psta = rtw_get_stainfo(&padapter->stapriv, tgt_network->network.MacAddress); ++ if (psta) rtw_free_stainfo(padapter, psta); ++ ++ psta = rtw_alloc_stainfo(&padapter->stapriv, bssid.MacAddress); ++ if (psta == NULL) { ++ RT_TRACE(_module_mp_, _drv_err_, ("mp_start_test: Can't alloc sta_info!\n")); ++ pmlmepriv->fw_state = pmppriv->prev_fw_state; ++ res = _FAIL; ++ goto end_of_mp_start_test; ++ } ++ ++ //3 3. join psudo AdHoc ++ tgt_network->join_res = 1; ++ tgt_network->aid = psta->aid = 1; ++ _rtw_memcpy(&tgt_network->network, &bssid, length); ++ ++ rtw_indicate_connect(padapter); ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ ++end_of_mp_start_test: ++ ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ if (res == _SUCCESS) ++ { ++ // set MSR to WIFI_FW_ADHOC_STATE ++#if !defined (CONFIG_RTL8712) ++ val8 = rtw_read8(padapter, MSR) & 0xFC; // 0x0102 ++ val8 |= WIFI_FW_ADHOC_STATE; ++ rtw_write8(padapter, MSR, val8); // Link in ad hoc network ++#endif ++ ++#if defined (CONFIG_RTL8712) ++ rtw_write8(padapter, MSR, 1); // Link in ad hoc network ++ rtw_write8(padapter, RCR, 0); // RCR : disable all pkt, 0x10250048 ++ rtw_write8(padapter, RCR+2, 0x57); // RCR disable Check BSSID, 0x1025004a ++ ++ // disable RX filter map , mgt frames will put in RX FIFO 0 ++ rtw_write16(padapter, RXFLTMAP0, 0x0); // 0x10250116 ++ ++ val8 = rtw_read8(padapter, EE_9346CR); // 0x1025000A ++ if (!(val8 & _9356SEL))//boot from EFUSE ++ efuse_change_max_size(padapter); ++#endif ++ } ++ ++ return res; ++} ++//------------------------------------------------------------------------------ ++//This function change the DUT from the MP test mode into normal mode ++void mp_stop_test(PADAPTER padapter) ++{ ++ struct mp_priv *pmppriv = &padapter->mppriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *tgt_network = &pmlmepriv->cur_network; ++ struct sta_info *psta; ++ ++ _irqL irqL; ++ ++ if(pmppriv->mode==MP_ON) ++ { ++ pmppriv->bSetTxPower=0; ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _FALSE) ++ goto end_of_mp_stop_test; ++ ++ //3 1. disconnect psudo AdHoc ++ rtw_indicate_disconnect(padapter); ++ ++ //3 2. clear psta used in mp test mode. ++// rtw_free_assoc_resources(padapter, 1); ++ psta = rtw_get_stainfo(&padapter->stapriv, tgt_network->network.MacAddress); ++ if (psta) rtw_free_stainfo(padapter, psta); ++ ++ //3 3. return to normal state (default:station mode) ++ pmlmepriv->fw_state = pmppriv->prev_fw_state; // WIFI_STATION_STATE; ++ ++ //flush the cur_network ++ _rtw_memset(tgt_network, 0, sizeof(struct wlan_network)); ++ ++ _clr_fwstate_(pmlmepriv, WIFI_MP_STATE); ++ ++end_of_mp_stop_test: ++ ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ } ++} ++/*---------------------------hal\rtl8192c\MPT_Phy.c---------------------------*/ ++#if 0 ++//#ifdef CONFIG_USB_HCI ++static VOID mpt_AdjustRFRegByRateByChan92CU(PADAPTER pAdapter, u8 RateIdx, u8 Channel, u8 BandWidthID) ++{ ++ u8 eRFPath; ++ u32 rfReg0x26; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ ++ if (RateIdx < MPT_RATE_6M) { // CCK rate,for 88cu ++ rfReg0x26 = 0xf400; ++ } ++ else if ((RateIdx >= MPT_RATE_6M) && (RateIdx <= MPT_RATE_54M)) {// OFDM rate,for 88cu ++ if ((4 == Channel) || (8 == Channel) || (12 == Channel)) ++ rfReg0x26 = 0xf000; ++ else if ((5 == Channel) || (7 == Channel) || (13 == Channel) || (14 == Channel)) ++ rfReg0x26 = 0xf400; ++ else ++ rfReg0x26 = 0x4f200; ++ } ++ else if ((RateIdx >= MPT_RATE_MCS0) && (RateIdx <= MPT_RATE_MCS15)) {// MCS 20M ,for 88cu // MCS40M rate,for 88cu ++ ++ if (HT_CHANNEL_WIDTH_20 == BandWidthID) { ++ if ((4 == Channel) || (8 == Channel)) ++ rfReg0x26 = 0xf000; ++ else if ((5 == Channel) || (7 == Channel) || (13 == Channel) || (14 == Channel)) ++ rfReg0x26 = 0xf400; ++ else ++ rfReg0x26 = 0x4f200; ++ } ++ else{ ++ if ((4 == Channel) || (8 == Channel)) ++ rfReg0x26 = 0xf000; ++ else if ((5 == Channel) || (7 == Channel)) ++ rfReg0x26 = 0xf400; ++ else ++ rfReg0x26 = 0x4f200; ++ } ++ } ++ ++// RT_TRACE(COMP_CMD, DBG_LOUD, ("\n mpt_AdjustRFRegByRateByChan92CU():Chan:%d Rate=%d rfReg0x26:0x%08x\n",Channel, RateIdx,rfReg0x26)); ++ for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) { ++ write_rfreg(pAdapter, eRFPath, RF_SYN_G2, rfReg0x26); ++ } ++} ++#endif ++/*----------------------------------------------------------------------------- ++ * Function: mpt_SwitchRfSetting ++ * ++ * Overview: Change RF Setting when we siwthc channel/rate/BW for MP. ++ * ++ * Input: IN PADAPTER pAdapter ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 01/08/2009 MHC Suggestion from SD3 Willis for 92S series. ++ * 01/09/2009 MHC Add CCK modification for 40MHZ. Suggestion from SD3. ++ * ++ *---------------------------------------------------------------------------*/ ++static void mpt_SwitchRfSetting(PADAPTER pAdapter) ++{ ++ Hal_mpt_SwitchRfSetting(pAdapter); ++ } ++ ++/*---------------------------hal\rtl8192c\MPT_Phy.c---------------------------*/ ++/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/ ++static void MPT_CCKTxPowerAdjust(PADAPTER Adapter, BOOLEAN bInCH14) ++{ ++ Hal_MPT_CCKTxPowerAdjust(Adapter,bInCH14); ++} ++ ++static void MPT_CCKTxPowerAdjustbyIndex(PADAPTER pAdapter, BOOLEAN beven) ++{ ++ Hal_MPT_CCKTxPowerAdjustbyIndex(pAdapter,beven); ++ } ++ ++/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/ ++ ++/* ++ * SetChannel ++ * Description ++ * Use H2C command to change channel, ++ * not only modify rf register, but also other setting need to be done. ++ */ ++void SetChannel(PADAPTER pAdapter) ++{ ++ Hal_SetChannel(pAdapter); ++ ++} ++ ++/* ++ * Notice ++ * Switch bandwitdth may change center frequency(channel) ++ */ ++void SetBandwidth(PADAPTER pAdapter) ++{ ++ Hal_SetBandwidth(pAdapter); ++ ++} ++ ++static void SetCCKTxPower(PADAPTER pAdapter, u8 *TxPower) ++{ ++ Hal_SetCCKTxPower(pAdapter,TxPower); ++} ++ ++static void SetOFDMTxPower(PADAPTER pAdapter, u8 *TxPower) ++{ ++ Hal_SetOFDMTxPower(pAdapter,TxPower); ++ } ++ ++ ++void SetAntenna(PADAPTER pAdapter) ++ { ++ Hal_SetAntenna(pAdapter); ++} ++ ++void SetAntennaPathPower(PADAPTER pAdapter) ++{ ++ Hal_SetAntennaPathPower(pAdapter); ++} ++ ++void SetTxPower(PADAPTER pAdapter) ++{ ++ Hal_SetTxPower(pAdapter); ++ } ++ ++void SetTxAGCOffset(PADAPTER pAdapter, u32 ulTxAGCOffset) ++{ ++ u32 TxAGCOffset_B, TxAGCOffset_C, TxAGCOffset_D,tmpAGC; ++ ++ TxAGCOffset_B = (ulTxAGCOffset&0x000000ff); ++ TxAGCOffset_C = ((ulTxAGCOffset&0x0000ff00)>>8); ++ TxAGCOffset_D = ((ulTxAGCOffset&0x00ff0000)>>16); ++ ++ tmpAGC = (TxAGCOffset_D<<8 | TxAGCOffset_C<<4 | TxAGCOffset_B); ++ write_bbreg(pAdapter, rFPGA0_TxGainStage, ++ (bXBTxAGC|bXCTxAGC|bXDTxAGC), tmpAGC); ++} ++ ++void SetDataRate(PADAPTER pAdapter) ++{ ++ Hal_SetDataRate(pAdapter); ++} ++ ++void MP_PHY_SetRFPathSwitch(PADAPTER pAdapter ,BOOLEAN bMain) ++{ ++ ++ PHY_SetRFPathSwitch(pAdapter,bMain); ++ ++} ++ ++#if defined (CONFIG_RTL8712) ++/*------------------------------Define structure----------------------------*/ ++typedef struct _R_ANTENNA_SELECT_OFDM { ++ u32 r_tx_antenna:4; ++ u32 r_ant_l:4; ++ u32 r_ant_non_ht:4; ++ u32 r_ant_ht1:4; ++ u32 r_ant_ht2:4; ++ u32 r_ant_ht_s1:4; ++ u32 r_ant_non_ht_s1:4; ++ u32 OFDM_TXSC:2; ++ u32 Reserved:2; ++}R_ANTENNA_SELECT_OFDM; ++ ++typedef struct _R_ANTENNA_SELECT_CCK { ++ u8 r_cckrx_enable_2:2; ++ u8 r_cckrx_enable:2; ++ u8 r_ccktx_enable:4; ++}R_ANTENNA_SELECT_CCK; ++#endif ++ ++s32 SetThermalMeter(PADAPTER pAdapter, u8 target_ther) ++{ ++ return Hal_SetThermalMeter( pAdapter, target_ther); ++} ++ ++static void TriggerRFThermalMeter(PADAPTER pAdapter) ++{ ++ Hal_TriggerRFThermalMeter(pAdapter); ++} ++ ++static u8 ReadRFThermalMeter(PADAPTER pAdapter) ++{ ++ return Hal_ReadRFThermalMeter(pAdapter); ++} ++ ++void GetThermalMeter(PADAPTER pAdapter, u8 *value) ++{ ++ Hal_GetThermalMeter(pAdapter,value); ++} ++ ++void SetSingleCarrierTx(PADAPTER pAdapter, u8 bStart) ++{ ++ PhySetTxPowerLevel(pAdapter); ++ Hal_SetSingleCarrierTx(pAdapter,bStart); ++} ++ ++void SetSingleToneTx(PADAPTER pAdapter, u8 bStart) ++{ ++ PhySetTxPowerLevel(pAdapter); ++ Hal_SetSingleToneTx(pAdapter,bStart); ++} ++ ++void SetCarrierSuppressionTx(PADAPTER pAdapter, u8 bStart) ++{ ++ PhySetTxPowerLevel(pAdapter); ++ Hal_SetCarrierSuppressionTx(pAdapter, bStart); ++} ++ ++void SetCCKContinuousTx(PADAPTER pAdapter, u8 bStart) ++{ ++ PhySetTxPowerLevel(pAdapter); ++ Hal_SetCCKContinuousTx(pAdapter,bStart); ++} ++ ++void SetOFDMContinuousTx(PADAPTER pAdapter, u8 bStart) ++{ ++ PhySetTxPowerLevel(pAdapter); ++ Hal_SetOFDMContinuousTx( pAdapter, bStart); ++}/* mpt_StartOfdmContTx */ ++ ++void SetContinuousTx(PADAPTER pAdapter, u8 bStart) ++{ ++ PhySetTxPowerLevel(pAdapter); ++ Hal_SetContinuousTx(pAdapter,bStart); ++} ++ ++ ++void PhySetTxPowerLevel(PADAPTER pAdapter) ++{ ++ struct mp_priv *pmp_priv = &pAdapter->mppriv; ++ ++ if (pmp_priv->bSetTxPower==0) // for NO manually set power index ++ { ++#ifdef CONFIG_RTL8188E ++ PHY_SetTxPowerLevel8188E(pAdapter,pmp_priv->channel); ++#elif defined(CONFIG_RTL8192D) ++ PHY_SetTxPowerLevel8192D(pAdapter,pmp_priv->channel); ++#else ++ PHY_SetTxPowerLevel8192C(pAdapter,pmp_priv->channel); ++#endif ++ } ++} ++ ++//------------------------------------------------------------------------------ ++static void dump_mpframe(PADAPTER padapter, struct xmit_frame *pmpframe) ++{ ++ rtw_hal_mgnt_xmit(padapter, pmpframe); ++} ++ ++static struct xmit_frame *alloc_mp_xmitframe(struct xmit_priv *pxmitpriv) ++{ ++ struct xmit_frame *pmpframe; ++ struct xmit_buf *pxmitbuf; ++ ++ if ((pmpframe = rtw_alloc_xmitframe(pxmitpriv)) == NULL) ++ { ++ return NULL; ++ } ++ ++ if ((pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv)) == NULL) ++ { ++ rtw_free_xmitframe(pxmitpriv, pmpframe); ++ return NULL; ++ } ++ ++ pmpframe->frame_tag = MP_FRAMETAG; ++ ++ pmpframe->pxmitbuf = pxmitbuf; ++ ++ pmpframe->buf_addr = pxmitbuf->pbuf; ++ ++ pxmitbuf->priv_data = pmpframe; ++ ++ return pmpframe; ++ ++} ++ ++static thread_return mp_xmit_packet_thread(thread_context context) ++{ ++ struct xmit_frame *pxmitframe; ++ struct mp_tx *pmptx; ++ struct mp_priv *pmp_priv; ++ struct xmit_priv *pxmitpriv; ++ PADAPTER padapter; ++ ++ pmp_priv = (struct mp_priv *)context; ++ pmptx = &pmp_priv->tx; ++ padapter = pmp_priv->papdater; ++ pxmitpriv = &(padapter->xmitpriv); ++ ++ thread_enter("RTW_MP_THREAD"); ++ ++ //DBG_871X("%s:pkTx Start\n", __func__); ++ while (1) { ++ pxmitframe = alloc_mp_xmitframe(pxmitpriv); ++ if (pxmitframe == NULL) { ++ if (pmptx->stop || ++ padapter->bSurpriseRemoved || ++ padapter->bDriverStopped) { ++ goto exit; ++ } ++ else { ++ rtw_msleep_os(1); ++ continue; ++ } ++ } ++ ++ _rtw_memcpy((u8 *)(pxmitframe->buf_addr+TXDESC_OFFSET), pmptx->buf, pmptx->write_size); ++ _rtw_memcpy(&(pxmitframe->attrib), &(pmptx->attrib), sizeof(struct pkt_attrib)); ++ ++ dump_mpframe(padapter, pxmitframe); ++ ++ pmptx->sended++; ++ pmp_priv->tx_pktcount++; ++ ++ if (pmptx->stop || ++ padapter->bSurpriseRemoved || ++ padapter->bDriverStopped) ++ goto exit; ++ if ((pmptx->count != 0) && ++ (pmptx->count == pmptx->sended)) ++ goto exit; ++ ++ flush_signals_thread(); ++ } ++ ++exit: ++ //DBG_871X("%s:pkTx Exit\n", __func__); ++ rtw_mfree(pmptx->pallocated_buf, pmptx->buf_size); ++ pmptx->pallocated_buf = NULL; ++ pmptx->stop = 1; ++ ++ thread_exit(); ++} ++ ++void fill_txdesc_for_mp(PADAPTER padapter, struct tx_desc *ptxdesc) ++{ ++ struct mp_priv *pmp_priv = &padapter->mppriv; ++ _rtw_memcpy(ptxdesc, &(pmp_priv->tx.desc), TXDESC_SIZE); ++} ++ ++void SetPacketTx(PADAPTER padapter) ++{ ++ u8 *ptr, *pkt_start, *pkt_end; ++ u32 pkt_size,offset; ++ struct tx_desc *desc; ++ struct rtw_ieee80211_hdr *hdr; ++ u8 payload; ++ s32 bmcast; ++ struct pkt_attrib *pattrib; ++ struct mp_priv *pmp_priv; ++ ++ ++ pmp_priv = &padapter->mppriv; ++ if (pmp_priv->tx.stop) return; ++ pmp_priv->tx.sended = 0; ++ pmp_priv->tx.stop = 0; ++ pmp_priv->tx_pktcount = 0; ++ ++ //3 1. update_attrib() ++ pattrib = &pmp_priv->tx.attrib; ++ _rtw_memcpy(pattrib->src, padapter->eeprompriv.mac_addr, ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ _rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); ++ bmcast = IS_MCAST(pattrib->ra); ++ if (bmcast) { ++ pattrib->mac_id = 1; ++ pattrib->psta = rtw_get_bcmc_stainfo(padapter); ++ } else { ++ pattrib->mac_id = 0; ++ pattrib->psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv)); ++ } ++ ++ pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->pktlen; ++ ++ //3 2. allocate xmit buffer ++ pkt_size = pattrib->last_txcmdsz; ++ ++ if (pmp_priv->tx.pallocated_buf) ++ rtw_mfree(pmp_priv->tx.pallocated_buf, pmp_priv->tx.buf_size); ++ pmp_priv->tx.write_size = pkt_size; ++ pmp_priv->tx.buf_size = pkt_size + XMITBUF_ALIGN_SZ; ++ pmp_priv->tx.pallocated_buf = rtw_zmalloc(pmp_priv->tx.buf_size); ++ if (pmp_priv->tx.pallocated_buf == NULL) { ++ DBG_871X("%s: malloc(%d) fail!!\n", __func__, pmp_priv->tx.buf_size); ++ return; ++ } ++ pmp_priv->tx.buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pmp_priv->tx.pallocated_buf), XMITBUF_ALIGN_SZ); ++ ptr = pmp_priv->tx.buf; ++ ++ desc = &(pmp_priv->tx.desc); ++ _rtw_memset(desc, 0, TXDESC_SIZE); ++ pkt_start = ptr; ++ pkt_end = pkt_start + pkt_size; ++ ++ //3 3. init TX descriptor ++ // offset 0 ++#if defined(CONFIG_RTL8188E) && !defined(CONFIG_RTL8188E_SDIO) ++ desc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); ++ desc->txdw0 |= cpu_to_le32(pkt_size & 0x0000FFFF); // packet size ++ desc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) << OFFSET_SHT) & 0x00FF0000); //32 bytes for TX Desc ++ if (bmcast) desc->txdw0 |= cpu_to_le32(BMC); // broadcast packet ++ ++ desc->txdw1 |= cpu_to_le32((0x01 << 26) & 0xff000000); ++#endif ++ // offset 4 ++ #ifndef CONFIG_RTL8188E ++ desc->txdw1 |= cpu_to_le32(BK); // don't aggregate(AMPDU) ++ desc->txdw1 |= cpu_to_le32((pattrib->mac_id) & 0x1F); //CAM_ID(MAC_ID) ++ #else ++ desc->txdw1 |= cpu_to_le32((pattrib->mac_id) & 0x3F); //CAM_ID(MAC_ID) ++ #endif ++ desc->txdw1 |= cpu_to_le32((pattrib->qsel << QSEL_SHT) & 0x00001F00); // Queue Select, TID ++ ++ #ifdef CONFIG_RTL8188E ++ desc->txdw1 |= cpu_to_le32((pattrib->raid << RATE_ID_SHT) & 0x000F0000); // Rate Adaptive ID ++ #else ++ desc->txdw1 |= cpu_to_le32((pattrib->raid << Rate_ID_SHT) & 0x000F0000); // Rate Adaptive ID ++ ++ #endif ++ // offset 8 ++ // desc->txdw2 |= cpu_to_le32(AGG_BK);//AGG BK ++ // offset 12 ++ ++ desc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0x0fff0000); ++// desc->txdw3 |= cpu_to_le32((pattrib->seqnum & 0xFFF) << SEQ_SHT); ++ //desc->txdw3 |= cpu_to_le32((pattrib->seqnum << SEQ_SHT) & 0xffff0000); ++ ++ // offset 16 ++ //desc->txdw4 |= cpu_to_le32(QoS) ++ #ifdef CONFIG_RTL8188E ++ desc->txdw4 |= cpu_to_le32(HW_SSN); ++ #else ++ desc->txdw4 |= cpu_to_le32(HW_SEQ_EN); ++ #endif ++ desc->txdw4 |= cpu_to_le32(USERATE); ++ desc->txdw4 |= cpu_to_le32(DISDATAFB); ++ ++ if( pmp_priv->preamble ){ ++ if (pmp_priv->rateidx <= MPT_RATE_54M) ++ desc->txdw4 |= cpu_to_le32(DATA_SHORT); // CCK Short Preamble ++ } ++ if (pmp_priv->bandwidth == HT_CHANNEL_WIDTH_40) ++ desc->txdw4 |= cpu_to_le32(DATA_BW); ++ ++ // offset 20 ++ desc->txdw5 |= cpu_to_le32(pmp_priv->rateidx & 0x0000001F); ++ ++ if( pmp_priv->preamble ){ ++ if (pmp_priv->rateidx > MPT_RATE_54M) ++ desc->txdw5 |= cpu_to_le32(SGI); // MCS Short Guard Interval ++ } ++ #ifdef CONFIG_RTL8188E ++ desc->txdw5 |= cpu_to_le32(RTY_LMT_EN); // retry limit enable ++ desc->txdw5 |= cpu_to_le32(0x00180000); // DATA/RTS Rate Fallback Limit ++ #else ++ desc->txdw5 |= cpu_to_le32(0x0001FF00); // DATA/RTS Rate Fallback Limit ++ #endif ++ ++ //3 4. make wlan header, make_wlanhdr() ++ hdr = (struct rtw_ieee80211_hdr *)pkt_start; ++ SetFrameSubType(&hdr->frame_ctl, pattrib->subtype); ++ _rtw_memcpy(hdr->addr1, pattrib->dst, ETH_ALEN); // DA ++ _rtw_memcpy(hdr->addr2, pattrib->src, ETH_ALEN); // SA ++ _rtw_memcpy(hdr->addr3, get_bssid(&padapter->mlmepriv), ETH_ALEN); // RA, BSSID ++ ++ //3 5. make payload ++ ptr = pkt_start + pattrib->hdrlen; ++ ++ switch (pmp_priv->tx.payload) { ++ case 0: ++ payload = 0x00; ++ break; ++ case 1: ++ payload = 0x5a; ++ break; ++ case 2: ++ payload = 0xa5; ++ break; ++ case 3: ++ payload = 0xff; ++ break; ++ default: ++ payload = 0x00; ++ break; ++ } ++ ++ _rtw_memset(ptr, payload, pkt_end - ptr); ++ ++ //3 6. start thread ++#ifdef PLATFORM_LINUX ++ pmp_priv->tx.PktTxThread = kthread_run(mp_xmit_packet_thread, pmp_priv, "RTW_MP_THREAD"); ++ if (IS_ERR(pmp_priv->tx.PktTxThread)) ++ DBG_871X("Create PktTx Thread Fail !!!!!\n"); ++#endif ++#ifdef PLATFORM_FREEBSD ++{ ++ struct proc *p; ++ struct thread *td; ++ pmp_priv->tx.PktTxThread = kproc_kthread_add(mp_xmit_packet_thread, pmp_priv, ++ &p, &td, RFHIGHPID, 0, "MPXmitThread", "MPXmitThread"); ++ ++ if (pmp_priv->tx.PktTxThread < 0) ++ DBG_871X("Create PktTx Thread Fail !!!!!\n"); ++} ++#endif ++} ++ ++void SetPacketRx(PADAPTER pAdapter, u8 bStartRx) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ if(bStartRx) ++ { ++ // Accept CRC error and destination address ++#if 1 ++//ndef CONFIG_RTL8723A ++ //pHalData->ReceiveConfig = AAP | APM | AM | AB | APP_ICV | ADF | AMF | HTC_LOC_CTRL | APP_MIC | APP_PHYSTS; ++ ++ //pHalData->ReceiveConfig |= ACRC32; ++ ++ pHalData->ReceiveConfig = AAP | APM | AM | AB | APP_ICV | AMF | ADF | APP_FCS | HTC_LOC_CTRL | APP_MIC | APP_PHYSTS; ++ ++ pHalData->ReceiveConfig |= (RCR_ACRC32|RCR_AAP); ++ ++ rtw_write32(pAdapter, REG_RCR, pHalData->ReceiveConfig); ++ ++ // Accept all data frames ++ rtw_write16(pAdapter, REG_RXFLTMAP2, 0xFFFF); ++#else ++ rtw_write32(pAdapter, REG_RCR, 0x70000101); ++#endif ++ } ++ else ++ { ++ rtw_write32(pAdapter, REG_RCR, 0); ++ } ++} ++ ++void ResetPhyRxPktCount(PADAPTER pAdapter) ++{ ++ u32 i, phyrx_set = 0; ++ ++ for (i = 0; i <= 0xF; i++) { ++ phyrx_set = 0; ++ phyrx_set |= _RXERR_RPT_SEL(i); //select ++ phyrx_set |= RXERR_RPT_RST; // set counter to zero ++ rtw_write32(pAdapter, REG_RXERR_RPT, phyrx_set); ++ } ++} ++ ++static u32 GetPhyRxPktCounts(PADAPTER pAdapter, u32 selbit) ++{ ++ //selection ++ u32 phyrx_set = 0, count = 0; ++ ++ phyrx_set = _RXERR_RPT_SEL(selbit & 0xF); ++ rtw_write32(pAdapter, REG_RXERR_RPT, phyrx_set); ++ ++ //Read packet count ++ count = rtw_read32(pAdapter, REG_RXERR_RPT) & RXERR_COUNTER_MASK; ++ ++ return count; ++} ++ ++u32 GetPhyRxPktReceived(PADAPTER pAdapter) ++{ ++ u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0; ++ ++ OFDM_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_OFDM_MPDU_OK); ++ CCK_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_CCK_MPDU_OK); ++ HT_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_HT_MPDU_OK); ++ ++ return OFDM_cnt + CCK_cnt + HT_cnt; ++} ++ ++u32 GetPhyRxPktCRC32Error(PADAPTER pAdapter) ++{ ++ u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0; ++ ++ OFDM_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_OFDM_MPDU_FAIL); ++ CCK_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_CCK_MPDU_FAIL); ++ HT_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_HT_MPDU_FAIL); ++ ++ return OFDM_cnt + CCK_cnt + HT_cnt; ++} ++ ++//reg 0x808[9:0]: FFT data x ++//reg 0x808[22]: 0 --> 1 to get 1 FFT data y ++//reg 0x8B4[15:0]: FFT data y report ++static u32 rtw_GetPSDData(PADAPTER pAdapter, u32 point) ++{ ++ int psd_val; ++ ++ ++ psd_val = rtw_read32(pAdapter, 0x808); ++ psd_val &= 0xFFBFFC00; ++ psd_val |= point; ++ ++ rtw_write32(pAdapter, 0x808, psd_val); ++ rtw_mdelay_os(1); ++ psd_val |= 0x00400000; ++ ++ rtw_write32(pAdapter, 0x808, psd_val); ++ rtw_mdelay_os(1); ++ psd_val = rtw_read32(pAdapter, 0x8B4); ++ ++ psd_val &= 0x0000FFFF; ++ ++ return psd_val; ++} ++ ++/* ++ * pts start_point_min stop_point_max ++ * 128 64 64 + 128 = 192 ++ * 256 128 128 + 256 = 384 ++ * 512 256 256 + 512 = 768 ++ * 1024 512 512 + 1024 = 1536 ++ * ++ */ ++u32 mp_query_psd(PADAPTER pAdapter, u8 *data) ++{ ++ u32 i, psd_pts=0, psd_start=0, psd_stop=0; ++ u32 psd_data=0; ++ ++ ++#ifdef PLATFORM_LINUX ++ if (!netif_running(pAdapter->pnetdev)) { ++ RT_TRACE(_module_mp_, _drv_warning_, ("mp_query_psd: Fail! interface not opened!\n")); ++ return 0; ++ } ++#endif ++ ++ if (check_fwstate(&pAdapter->mlmepriv, WIFI_MP_STATE) == _FALSE) { ++ RT_TRACE(_module_mp_, _drv_warning_, ("mp_query_psd: Fail! not in MP mode!\n")); ++ return 0; ++ } ++ ++ if (strlen(data) == 0) { //default value ++ psd_pts = 128; ++ psd_start = 64; ++ psd_stop = 128; ++ } else { ++ sscanf(data, "pts=%d,start=%d,stop=%d", &psd_pts, &psd_start, &psd_stop); ++ } ++ ++ _rtw_memset(data, '\0', sizeof(data)); ++ ++ i = psd_start; ++ while (i < psd_stop) ++ { ++ if (i >= psd_pts) { ++ psd_data = rtw_GetPSDData(pAdapter, i-psd_pts); ++ } else { ++ psd_data = rtw_GetPSDData(pAdapter, i); ++ } ++ sprintf(data, "%s%x ", data, psd_data); ++ i++; ++ } ++ ++ #ifdef CONFIG_LONG_DELAY_ISSUE ++ rtw_msleep_os(100); ++ #else ++ rtw_mdelay_os(100); ++ #endif ++ ++ return strlen(data)+1; ++} ++ ++ ++ ++void _rtw_mp_xmit_priv (struct xmit_priv *pxmitpriv) ++{ ++ int i,res; ++ _adapter *padapter = pxmitpriv->adapter; ++ struct xmit_frame *pxmitframe = (struct xmit_frame*) pxmitpriv->pxmit_frame_buf; ++ struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; ++ ++ u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; ++ u32 num_xmit_extbuf = NR_XMIT_EXTBUFF; ++ if(padapter->registrypriv.mp_mode ==0) ++ { ++ max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; ++ num_xmit_extbuf = NR_XMIT_EXTBUFF; ++ } ++ else ++ { ++ #ifdef CONFIG_RTL8723A_SDIO ++ max_xmit_extbuf_size = 20000; ++ num_xmit_extbuf = 1; ++ #else ++ max_xmit_extbuf_size = 6000; ++ num_xmit_extbuf = 8; ++ #endif ++ } ++ ++ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; ++ for(i=0; ipallocated_xmit_extbuf) { ++ rtw_vmfree(pxmitpriv->pallocated_xmit_extbuf, num_xmit_extbuf * sizeof(struct xmit_buf) + 4); ++ } ++ ++ if(padapter->registrypriv.mp_mode ==0) ++ { ++ #ifdef CONFIG_RTL8723A_SDIO ++ max_xmit_extbuf_size = 20000; ++ num_xmit_extbuf = 1; ++ #else ++ max_xmit_extbuf_size = 6000; ++ num_xmit_extbuf = 8; ++ #endif ++ } ++ else ++ { ++ max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; ++ num_xmit_extbuf = NR_XMIT_EXTBUFF; ++ } ++ ++ // Init xmit extension buff ++ _rtw_init_queue(&pxmitpriv->free_xmit_extbuf_queue); ++ ++ pxmitpriv->pallocated_xmit_extbuf = rtw_zvmalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4); ++ ++ if (pxmitpriv->pallocated_xmit_extbuf == NULL){ ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("alloc xmit_extbuf fail!\n")); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pxmitpriv->pxmit_extbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->pallocated_xmit_extbuf), 4); ++ ++ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; ++ ++ for (i = 0; i < num_xmit_extbuf; i++) ++ { ++ _rtw_init_listhead(&pxmitbuf->list); ++ ++ pxmitbuf->priv_data = NULL; ++ pxmitbuf->padapter = padapter; ++ pxmitbuf->ext_tag = _TRUE; ++ ++/* ++ pxmitbuf->pallocated_buf = rtw_zmalloc(max_xmit_extbuf_size); ++ if (pxmitbuf->pallocated_buf == NULL) ++ { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), 4); ++*/ ++ ++ if((res=rtw_os_xmit_resource_alloc(padapter, pxmitbuf,max_xmit_extbuf_size + XMITBUF_ALIGN_SZ)) == _FAIL) { ++ res= _FAIL; ++ goto exit; ++ } ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ pxmitbuf->phead = pxmitbuf->pbuf; ++ pxmitbuf->pend = pxmitbuf->pbuf + max_xmit_extbuf_size; ++ pxmitbuf->len = 0; ++ pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; ++#endif ++ ++ rtw_list_insert_tail(&pxmitbuf->list, &(pxmitpriv->free_xmit_extbuf_queue.queue)); ++ #ifdef DBG_XMIT_BUF_EXT ++ pxmitbuf->no=i; ++ #endif ++ pxmitbuf++; ++ ++ } ++ ++ pxmitpriv->free_xmit_extbuf_cnt = num_xmit_extbuf; ++ ++exit: ++ ; ++} ++ ++ ++void Hal_ProSetCrystalCap (PADAPTER pAdapter , u32 CrystalCapVal) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ CrystalCapVal = CrystalCapVal & 0x3F; ++ ++ if(IS_HARDWARE_TYPE_8192D(pAdapter)) ++ { ++ PHY_SetBBReg(pAdapter, REG_AFE_XTAL_CTRL, 0xF0, CrystalCapVal & 0x0F); ++ PHY_SetBBReg(pAdapter, REG_AFE_PLL_CTRL, 0xF0000000, (CrystalCapVal & 0xF0) >> 4); ++ } ++ else if(IS_HARDWARE_TYPE_8188E(pAdapter)) ++ { ++ // write 0x24[16:11] = 0x24[22:17] = CrystalCap ++ PHY_SetBBReg(pAdapter, REG_AFE_XTAL_CTRL, 0x7FF800, (CrystalCapVal | (CrystalCapVal << 6))); ++ } ++ else ++ { ++ DBG_871X(" not as 88E and 92D Hal_ProSetCrystalCap 0x2c !!!!!\n"); ++ PHY_SetBBReg(pAdapter, 0x2c, 0xFFF000, (CrystalCapVal | (CrystalCapVal << 6))); ++ } ++} ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_mp_ioctl.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_mp_ioctl.c +new file mode 100644 +index 00000000..95570d1e +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_mp_ioctl.c +@@ -0,0 +1,2954 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_MP_IOCTL_C_ ++ ++#include ++#include ++#include ++#include ++ ++//#include ++#include ++ ++ ++//**************** oid_rtl_seg_81_85 section start **************** ++NDIS_STATUS oid_rt_wireless_mode_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ if (poid_par_priv->information_buf_len < sizeof(u8)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ if (poid_par_priv->type_of_oid == SET_OID) { ++ Adapter->registrypriv.wireless_mode = *(u8*)poid_par_priv->information_buf; ++ } else if (poid_par_priv->type_of_oid == QUERY_OID) { ++ *(u8*)poid_par_priv->information_buf = Adapter->registrypriv.wireless_mode; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ RT_TRACE(_module_mp_, _drv_info_, ("-query Wireless Mode=%d\n", Adapter->registrypriv.wireless_mode)); ++ } else { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ } ++ ++_func_exit_; ++ ++ return status; ++} ++//**************** oid_rtl_seg_81_87_80 section start **************** ++NDIS_STATUS oid_rt_pro_write_bb_reg_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ struct bb_reg_param *pbbreg; ++ u16 offset; ++ u32 value; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+oid_rt_pro_write_bb_reg_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(struct bb_reg_param)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ pbbreg = (struct bb_reg_param *)(poid_par_priv->information_buf); ++ ++ offset = (u16)(pbbreg->offset) & 0xFFF; //0ffset :0x800~0xfff ++ if (offset < BB_REG_BASE_ADDR) offset |= BB_REG_BASE_ADDR; ++ ++ value = pbbreg->value; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("oid_rt_pro_write_bb_reg_hdl: offset=0x%03X value=0x%08X\n", ++ offset, value)); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ write_bbreg(Adapter, offset, 0xFFFFFFFF, value); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_read_bb_reg_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ struct bb_reg_param *pbbreg; ++ u16 offset; ++ u32 value; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+oid_rt_pro_read_bb_reg_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(struct bb_reg_param)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ pbbreg = (struct bb_reg_param *)(poid_par_priv->information_buf); ++ ++ offset = (u16)(pbbreg->offset) & 0xFFF; //0ffset :0x800~0xfff ++ if (offset < BB_REG_BASE_ADDR) offset |= BB_REG_BASE_ADDR; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ value = read_bbreg(Adapter, offset, 0xFFFFFFFF); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ pbbreg->value = value; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("-oid_rt_pro_read_bb_reg_hdl: offset=0x%03X value:0x%08X\n", ++ offset, value)); ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ struct rf_reg_param *pbbreg; ++ u8 path; ++ u8 offset; ++ u32 value; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+oid_rt_pro_write_rf_reg_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(struct rf_reg_param)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ pbbreg = (struct rf_reg_param *)(poid_par_priv->information_buf); ++ ++ if (pbbreg->path >= MAX_RF_PATH_NUMS) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ if (pbbreg->offset > 0xFF) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ if (pbbreg->value > 0xFFFFF) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ path = (u8)pbbreg->path; ++ offset = (u8)pbbreg->offset; ++ value = pbbreg->value; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("oid_rt_pro_write_rf_reg_hdl: path=%d offset=0x%02X value=0x%05X\n", ++ path, offset, value)); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ write_rfreg(Adapter, path, offset, value); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ struct rf_reg_param *pbbreg; ++ u8 path; ++ u8 offset; ++ u32 value; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+oid_rt_pro_read_rf_reg_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(struct rf_reg_param)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ pbbreg = (struct rf_reg_param *)(poid_par_priv->information_buf); ++ ++ if (pbbreg->path >= MAX_RF_PATH_NUMS) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ if (pbbreg->offset > 0xFF) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ path = (u8)pbbreg->path; ++ offset = (u8)pbbreg->offset; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ value = read_rfreg(Adapter, path, offset); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ pbbreg->value = value; ++ ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("-oid_rt_pro_read_rf_reg_hdl: path=%d offset=0x%02X value=0x%05X\n", ++ path, offset, value)); ++ ++_func_exit_; ++ ++ return status; ++} ++//**************** oid_rtl_seg_81_87_00 section end**************** ++//------------------------------------------------------------------------------ ++ ++//**************** oid_rtl_seg_81_80_00 section start **************** ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_set_data_rate_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ u32 ratevalue;//4 ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("+oid_rt_pro_set_data_rate_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len != sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ ratevalue = *((u32*)poid_par_priv->information_buf);//4 ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("oid_rt_pro_set_data_rate_hdl: data rate idx=%d\n", ratevalue)); ++ if (ratevalue >= MPT_RATE_LAST) ++ return NDIS_STATUS_INVALID_DATA; ++ ++ Adapter->mppriv.rateidx = ratevalue; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetDataRate(Adapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ u32 mode; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+oid_rt_pro_start_test_hdl\n")); ++ ++ if (Adapter->registrypriv.mp_mode == 0) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ //IQCalibrateBcut(Adapter); ++ ++ mode = *((u32*)poid_par_priv->information_buf); ++ Adapter->mppriv.mode = mode;// 1 for loopback ++ ++ if (mp_start_test(Adapter) == _FAIL) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ goto exit; ++ } ++ ++exit: ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("-oid_rt_pro_start_test_hdl: mp_mode=%d\n", Adapter->mppriv.mode)); ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_stop_test_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+Set OID_RT_PRO_STOP_TEST\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ mp_stop_test(Adapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("-Set OID_RT_PRO_STOP_TEST\n")); ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_set_channel_direct_call_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ u32 Channel; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+oid_rt_pro_set_channel_direct_call_hdl\n")); ++ ++ if (poid_par_priv->information_buf_len != sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ if (poid_par_priv->type_of_oid == QUERY_OID) { ++ *((u32*)poid_par_priv->information_buf) = Adapter->mppriv.channel; ++ return NDIS_STATUS_SUCCESS; ++ } ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ Channel = *((u32*)poid_par_priv->information_buf); ++ RT_TRACE(_module_mp_, _drv_notice_, ("oid_rt_pro_set_channel_direct_call_hdl: Channel=%d\n", Channel)); ++ if (Channel > 14) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ Adapter->mppriv.channel = Channel; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetChannel(Adapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ u16 bandwidth; ++ u16 channel_offset; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("+oid_rt_set_bandwidth_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ bandwidth = *((u32*)poid_par_priv->information_buf);//4 ++ channel_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ if (bandwidth != HT_CHANNEL_WIDTH_40) ++ bandwidth = HT_CHANNEL_WIDTH_20; ++ padapter->mppriv.bandwidth = (u8)bandwidth; ++ padapter->mppriv.prime_channel_offset = (u8)channel_offset; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetBandwidth(padapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("-oid_rt_set_bandwidth_hdl: bandwidth=%d channel_offset=%d\n", ++ bandwidth, channel_offset)); ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_set_antenna_bb_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ u32 antenna; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+oid_rt_pro_set_antenna_bb_hdl\n")); ++ ++ if (poid_par_priv->information_buf_len != sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ if (poid_par_priv->type_of_oid == SET_OID) ++ { ++ antenna = *(u32*)poid_par_priv->information_buf; ++ ++ Adapter->mppriv.antenna_tx = (u16)((antenna & 0xFFFF0000) >> 16); ++ Adapter->mppriv.antenna_rx = (u16)(antenna & 0x0000FFFF); ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("oid_rt_pro_set_antenna_bb_hdl: tx_ant=0x%04x rx_ant=0x%04x\n", ++ Adapter->mppriv.antenna_tx, Adapter->mppriv.antenna_rx)); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetAntenna(Adapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ } else { ++ antenna = (Adapter->mppriv.antenna_tx << 16)|Adapter->mppriv.antenna_rx; ++ *(u32*)poid_par_priv->information_buf = antenna; ++ } ++ ++_func_exit_; ++ ++ return status; ++} ++ ++NDIS_STATUS oid_rt_pro_set_tx_power_control_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ u32 tx_pwr_idx; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_info_, ("+oid_rt_pro_set_tx_power_control_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len != sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ tx_pwr_idx = *((u32*)poid_par_priv->information_buf); ++ if (tx_pwr_idx > MAX_TX_PWR_INDEX_N_MODE) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ Adapter->mppriv.txpoweridx = (u8)tx_pwr_idx; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("oid_rt_pro_set_tx_power_control_hdl: idx=0x%2x\n", ++ Adapter->mppriv.txpoweridx)); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetTxPower(Adapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++} ++ ++//------------------------------------------------------------------------------ ++//**************** oid_rtl_seg_81_80_20 section start **************** ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_query_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid !=QUERY_OID) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ if (poid_par_priv->information_buf_len == sizeof(ULONG)) { ++ *(ULONG*)poid_par_priv->information_buf = Adapter->mppriv.tx_pktcount; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } else { ++ status = NDIS_STATUS_INVALID_LENGTH; ++ } ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_query_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ RT_TRACE(_module_mp_, _drv_alert_, ("===> oid_rt_pro_query_rx_packet_received_hdl.\n")); ++ if (poid_par_priv->information_buf_len == sizeof(ULONG)) { ++ *(ULONG*)poid_par_priv->information_buf = Adapter->mppriv.rx_pktcount; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ RT_TRACE(_module_mp_, _drv_alert_, ("recv_ok:%d \n",Adapter->mppriv.rx_pktcount)); ++ } else { ++ status = NDIS_STATUS_INVALID_LENGTH; ++ } ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_query_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ RT_TRACE(_module_mp_, _drv_alert_, ("===> oid_rt_pro_query_rx_packet_crc32_error_hdl.\n")); ++ if (poid_par_priv->information_buf_len == sizeof(ULONG)) { ++ *(ULONG*)poid_par_priv->information_buf = Adapter->mppriv.rx_crcerrpktcount; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ RT_TRACE(_module_mp_, _drv_alert_, ("recv_err:%d \n",Adapter->mppriv.rx_crcerrpktcount)); ++ } else { ++ status = NDIS_STATUS_INVALID_LENGTH; ++ } ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++ ++NDIS_STATUS oid_rt_pro_reset_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ RT_TRACE(_module_mp_, _drv_alert_, ("===> oid_rt_pro_reset_tx_packet_sent_hdl.\n")); ++ Adapter->mppriv.tx_pktcount = 0; ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_reset_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ if (poid_par_priv->information_buf_len == sizeof(ULONG)) { ++ Adapter->mppriv.rx_pktcount = 0; ++ Adapter->mppriv.rx_crcerrpktcount = 0; ++ } else { ++ status = NDIS_STATUS_INVALID_LENGTH; ++ } ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ResetPhyRxPktCount(Adapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_info_, ("+oid_rt_get_phy_rx_packet_received_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len != sizeof(ULONG)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ *(ULONG*)poid_par_priv->information_buf = GetPhyRxPktReceived(Adapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("-oid_rt_get_phy_rx_packet_received_hdl: recv_ok=%d\n", *(ULONG*)poid_par_priv->information_buf)); ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_info_, ("+oid_rt_get_phy_rx_packet_crc32_error_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ ++ if (poid_par_priv->information_buf_len != sizeof(ULONG)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ *(ULONG*)poid_par_priv->information_buf = GetPhyRxPktCRC32Error(Adapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ RT_TRACE(_module_mp_, _drv_info_, ("-oid_rt_get_phy_rx_packet_crc32_error_hdl: recv_err=%d\n", *(ULONG*)poid_par_priv->information_buf)); ++ ++_func_exit_; ++ ++ return status; ++} ++//**************** oid_rtl_seg_81_80_20 section end **************** ++NDIS_STATUS oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ u32 bStartTest; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+oid_rt_pro_set_continuous_tx_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ bStartTest = *((u32*)poid_par_priv->information_buf); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetContinuousTx(Adapter,(u8)bStartTest); ++ if (bStartTest) { ++ struct mp_priv *pmp_priv = &Adapter->mppriv; ++ if (pmp_priv->tx.stop == 0) { ++ pmp_priv->tx.stop = 1; ++ DBG_871X("%s: pkt tx is running...\n", __func__); ++ rtw_msleep_os(5); ++ } ++ pmp_priv->tx.stop = 0; ++ pmp_priv->tx.count = 1; ++ SetPacketTx(Adapter); ++ } ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++} ++ ++NDIS_STATUS oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ u32 bStartTest; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_alert_, ("+oid_rt_pro_set_single_carrier_tx_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ bStartTest = *((u32*)poid_par_priv->information_buf); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetSingleCarrierTx(Adapter, (u8)bStartTest); ++ if (bStartTest) { ++ struct mp_priv *pmp_priv = &Adapter->mppriv; ++ if (pmp_priv->tx.stop == 0) { ++ pmp_priv->tx.stop = 1; ++ DBG_871X("%s: pkt tx is running...\n", __func__); ++ rtw_msleep_os(5); ++ } ++ pmp_priv->tx.stop = 0; ++ pmp_priv->tx.count = 1; ++ SetPacketTx(Adapter); ++ } ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++} ++ ++NDIS_STATUS oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ u32 bStartTest; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+oid_rt_pro_set_carrier_suppression_tx_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ bStartTest = *((u32*)poid_par_priv->information_buf); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetCarrierSuppressionTx(Adapter, (u8)bStartTest); ++ if (bStartTest) { ++ struct mp_priv *pmp_priv = &Adapter->mppriv; ++ if (pmp_priv->tx.stop == 0) { ++ pmp_priv->tx.stop = 1; ++ DBG_871X("%s: pkt tx is running...\n", __func__); ++ rtw_msleep_os(5); ++ } ++ pmp_priv->tx.stop = 0; ++ pmp_priv->tx.count = 1; ++ SetPacketTx(Adapter); ++ } ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++} ++ ++NDIS_STATUS oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ u32 bStartTest; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_alert_, ("+oid_rt_pro_set_single_tone_tx_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ bStartTest = *((u32*)poid_par_priv->information_buf); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetSingleToneTx(Adapter,(u8)bStartTest); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++} ++ ++NDIS_STATUS oid_rt_pro_set_modulation_hdl(struct oid_par_priv* poid_par_priv) ++{ ++ return 0; ++} ++ ++NDIS_STATUS oid_rt_pro_trigger_gpio_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ rtw_hal_set_hwreg(Adapter, HW_VAR_TRIGGER_GPIO_0, 0); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++} ++//**************** oid_rtl_seg_81_80_00 section end **************** ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro8711_join_bss_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++ PNDIS_802_11_SSID pssid; ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ *poid_par_priv->bytes_needed = (u32)sizeof(NDIS_802_11_SSID); ++ *poid_par_priv->bytes_rw = 0; ++ if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ pssid = (PNDIS_802_11_SSID)poid_par_priv->information_buf; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ if (mp_start_joinbss(Adapter, pssid) == _FAIL) ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ *poid_par_priv->bytes_rw = sizeof(NDIS_802_11_SSID); ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ pRW_Reg RegRWStruct; ++ u32 offset, width; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("+oid_rt_pro_read_register_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ RegRWStruct = (pRW_Reg)poid_par_priv->information_buf; ++ offset = RegRWStruct->offset; ++ width = RegRWStruct->width; ++ ++ if (offset > 0xFFF) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ switch (width) { ++ case 1: ++ RegRWStruct->value = rtw_read8(Adapter, offset); ++ break; ++ case 2: ++ RegRWStruct->value = rtw_read16(Adapter, offset); ++ break; ++ default: ++ width = 4; ++ RegRWStruct->value = rtw_read32(Adapter, offset); ++ break; ++ } ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("oid_rt_pro_read_register_hdl: offset:0x%04X value:0x%X\n", ++ offset, RegRWStruct->value)); ++ ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ *poid_par_priv->bytes_rw = width; ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ pRW_Reg RegRWStruct; ++ u32 offset, width, value; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("+oid_rt_pro_write_register_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ RegRWStruct = (pRW_Reg)poid_par_priv->information_buf; ++ offset = RegRWStruct->offset; ++ width = RegRWStruct->width; ++ value = RegRWStruct->value; ++ ++ if (offset > 0xFFF) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ switch (RegRWStruct->width) ++ { ++ case 1: ++ if (value > 0xFF) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ break; ++ } ++ rtw_write8(padapter, offset, (u8)value); ++ break; ++ case 2: ++ if (value > 0xFFFF) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ break; ++ } ++ rtw_write16(padapter, offset, (u16)value); ++ break; ++ case 4: ++ rtw_write32(padapter, offset, value); ++ break; ++ default: ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ break; ++ } ++ ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("-oid_rt_pro_write_register_hdl: offset=0x%08X width=%d value=0x%X\n", ++ offset, width, value)); ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_burst_read_register_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ pBurst_RW_Reg pBstRwReg; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+oid_rt_pro_burst_read_register_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ pBstRwReg = (pBurst_RW_Reg)poid_par_priv->information_buf; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ rtw_read_mem(padapter, pBstRwReg->offset, (u32)pBstRwReg->len, pBstRwReg->Data); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ RT_TRACE(_module_mp_, _drv_info_, ("-oid_rt_pro_burst_read_register_hdl\n")); ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_burst_write_register_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ pBurst_RW_Reg pBstRwReg; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+oid_rt_pro_burst_write_register_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ pBstRwReg = (pBurst_RW_Reg)poid_par_priv->information_buf; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ rtw_write_mem(padapter, pBstRwReg->offset, (u32)pBstRwReg->len, pBstRwReg->Data); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ RT_TRACE(_module_mp_, _drv_info_, ("-oid_rt_pro_burst_write_register_hdl\n")); ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_write_txcmd_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++ PADAPTER Adapter = (PADAPTER)( poid_par_priv->adapter_context); ++ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ ++ TX_CMD_Desc *TxCmd_Info; ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ RT_TRACE(_module_mp_, _drv_info_, ("+Set OID_RT_PRO_WRITE_TXCMD\n")); ++ ++ TxCmd_Info=(TX_CMD_Desc*)poid_par_priv->information_buf; ++ ++ RT_TRACE(_module_mp_, _drv_info_, ("WRITE_TXCMD:Addr=%.8X\n", TxCmd_Info->offset)); ++ RT_TRACE(_module_mp_, _drv_info_, ("WRITE_TXCMD:1.)%.8X\n", (ULONG)TxCmd_Info->TxCMD.value[0])); ++ RT_TRACE(_module_mp_, _drv_info_, ("WRITE_TXCMD:2.)%.8X\n", (ULONG)TxCmd_Info->TxCMD.value[1])); ++ RT_TRACE(_module_mp_, _drv_info_, (("WRITE_TXCMD:3.)%.8X\n", (ULONG)TxCmd_Info->TxCMD.value[2])); ++ RT_TRACE(_module_mp_, _drv_info_, ("WRITE_TXCMD:4.)%.8X\n", (ULONG)TxCmd_Info->TxCMD.value[3])); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ rtw_write32(Adapter, TxCmd_Info->offset + 0, (unsigned int)TxCmd_Info->TxCMD.value[0]); ++ rtw_write32(Adapter, TxCmd_Info->offset + 4, (unsigned int)TxCmd_Info->TxCMD.value[1]); ++ ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("-Set OID_RT_PRO_WRITE_TXCMD: status=0x%08X\n", status)); ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++ ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_read16_eeprom_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ pEEPROM_RWParam pEEPROM; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_info_, ("+Query OID_RT_PRO_READ16_EEPROM\n")); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ pEEPROM = (pEEPROM_RWParam)poid_par_priv->information_buf; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ pEEPROM->value = eeprom_read16(padapter, (u16)(pEEPROM->offset >> 1)); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("-Query OID_RT_PRO_READ16_EEPROM: offset=0x%x value=0x%x\n", ++ pEEPROM->offset, pEEPROM->value)); ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++ ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_write16_eeprom_hdl (struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ pEEPROM_RWParam pEEPROM; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+Set OID_RT_PRO_WRITE16_EEPROM\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ pEEPROM = (pEEPROM_RWParam)poid_par_priv->information_buf; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ eeprom_write16(padapter, (u16)(pEEPROM->offset >> 1), pEEPROM->value); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro8711_wi_poll_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)( poid_par_priv->adapter_context); ++ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++ struct mp_wiparam *pwi_param; ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(struct mp_wiparam)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ if (Adapter->mppriv.workparam.bcompleted == _FALSE) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ pwi_param = (struct mp_wiparam *)poid_par_priv->information_buf; ++ ++ _rtw_memcpy(pwi_param, &Adapter->mppriv.workparam, sizeof(struct mp_wiparam)); ++ Adapter->mppriv.act_in_progress = _FALSE; ++// RT_TRACE(_module_mp_, _drv_info_, ("rf:%x\n", pwiparam->IoValue)); ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro8711_pkt_loss_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)( poid_par_priv->adapter_context); ++ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+oid_rt_pro8711_pkt_loss_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(uint)*2) { ++ RT_TRACE(_module_mp_, _drv_err_, ("-oid_rt_pro8711_pkt_loss_hdl: buf_len=%d\n", (int)poid_par_priv->information_buf_len)); ++ return NDIS_STATUS_INVALID_LENGTH; ++ } ++ ++ if (*(uint*)poid_par_priv->information_buf == 1)//init==1 ++ Adapter->mppriv.rx_pktloss = 0; ++ ++ *((uint*)poid_par_priv->information_buf+1) = Adapter->mppriv.rx_pktloss; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_rd_attrib_mem_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)( poid_par_priv->adapter_context); ++ struct io_queue *pio_queue = (struct io_queue *)Adapter->pio_queue; ++ struct intf_hdl *pintfhdl = &pio_queue->intf; ++ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++#ifdef CONFIG_SDIO_HCI ++ void (*_attrib_read)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++#endif ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+Query OID_RT_RD_ATTRIB_MEM\n")); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++#ifdef CONFIG_SDIO_HCI ++ _irqlevel_changed_(&oldirql, LOWER); ++{ ++ u32 *plmem = (u32*)poid_par_priv->information_buf+2; ++ _attrib_read = pintfhdl->io_ops._attrib_read; ++ _attrib_read(pintfhdl, *((u32*)poid_par_priv->information_buf), ++ *((u32*)poid_par_priv->information_buf+1), (u8*)plmem); ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++} ++ _irqlevel_changed_(&oldirql, RAISE); ++#endif ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_wr_attrib_mem_hdl (struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ struct io_queue *pio_queue = (struct io_queue *)Adapter->pio_queue; ++ struct intf_hdl *pintfhdl = &pio_queue->intf; ++ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++#ifdef CONFIG_SDIO_HCI ++ void (*_attrib_write)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++#endif ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++#ifdef CONFIG_SDIO_HCI ++ _irqlevel_changed_(&oldirql, LOWER); ++{ ++ u32 *plmem = (u32*)poid_par_priv->information_buf + 2; ++ _attrib_write = pintfhdl->io_ops._attrib_write; ++ _attrib_write(pintfhdl, *(u32*)poid_par_priv->information_buf, ++ *((u32*)poid_par_priv->information_buf+1), (u8*)plmem); ++} ++ _irqlevel_changed_(&oldirql, RAISE); ++#endif ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_set_rf_intfs_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+OID_RT_PRO_SET_RF_INTFS\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ if (rtw_setrfintfs_cmd(Adapter, *(unsigned char*)poid_par_priv->information_buf) == _FAIL) ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_poll_rx_status_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ _rtw_memcpy(poid_par_priv->information_buf, (unsigned char*)&Adapter->mppriv.rxstat, sizeof(struct recv_stat)); ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_cfg_debug_message_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++ PCFG_DBG_MSG_STRUCT pdbg_msg; ++ ++_func_enter_; ++ ++// RT_TRACE(0xffffffffff,_drv_alert_,("===> oid_rt_pro_cfg_debug_message_hdl.\n")); ++ ++#if 0//#ifdef CONFIG_DEBUG_RTL871X ++ ++ pdbg_msg = (PCFG_DBG_MSG_STRUCT)(poid_par_priv->information_buf); ++ ++ if (poid_par_priv->type_of_oid == SET_OID) { ++ RT_TRACE(0xffffffffff, _drv_alert_, ++ ("===>Set level :0x%08x, H32:0x%08x L32:0x%08x\n", ++ pdbg_msg->DebugLevel, pdbg_msg->DebugComponent_H32, pdbg_msg->DebugComponent_L32)); ++ ++ GlobalDebugLevel = pdbg_msg->DebugLevel; ++ GlobalDebugComponents = (pdbg_msg->DebugComponent_H32 << 32) | pdbg_msg->DebugComponent_L32; ++ RT_TRACE(0xffffffffff, _drv_alert_, ++ ("===> Set level :0x%08x, component:0x%016x\n", ++ GlobalDebugLevel, (u32)GlobalDebugComponents)); ++ } else { ++ pdbg_msg->DebugLevel = GlobalDebugLevel; ++ pdbg_msg->DebugComponent_H32 = (u32)(GlobalDebugComponents >> 32); ++ pdbg_msg->DebugComponent_L32 = (u32)GlobalDebugComponents; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ RT_TRACE(0xffffffffff, _drv_alert_, ++ ("===>Query level:0x%08x H32:0x%08x L32:0x%08x\n", ++ (u32)pdbg_msg->DebugLevel, (u32)pdbg_msg->DebugComponent_H32, (u32)pdbg_msg->DebugComponent_L32)); ++ } ++ ++#endif ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_set_data_rate_ex_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+OID_RT_PRO_SET_DATA_RATE_EX\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ if (rtw_setdatarate_cmd(Adapter, poid_par_priv->information_buf) !=_SUCCESS) ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++} ++//----------------------------------------------------------------------------- ++NDIS_STATUS oid_rt_get_thermal_meter_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ u8 thermal = 0; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+oid_rt_get_thermal_meter_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ GetThermalMeter(Adapter, &thermal); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ *(u32*)poid_par_priv->information_buf = (u32)thermal; ++ *poid_par_priv->bytes_rw = sizeof(u32); ++ ++_func_exit_; ++ ++ return status; ++} ++//----------------------------------------------------------------------------- ++NDIS_STATUS oid_rt_pro_read_tssi_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+oid_rt_pro_read_tssi_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (Adapter->mppriv.act_in_progress == _TRUE) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(u8)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ //init workparam ++ Adapter->mppriv.act_in_progress = _TRUE; ++ Adapter->mppriv.workparam.bcompleted = _FALSE; ++ Adapter->mppriv.workparam.act_type = MPT_READ_TSSI; ++ Adapter->mppriv.workparam.io_offset = 0; ++ Adapter->mppriv.workparam.io_value = 0xFFFFFFFF; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ if (!rtw_gettssi_cmd(Adapter,0, (u8*)&Adapter->mppriv.workparam.io_value)) ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_set_power_tracking_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ ++_func_enter_; ++ ++// if (poid_par_priv->type_of_oid != SET_OID) ++// return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(u8)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ if (poid_par_priv->type_of_oid == SET_OID) { ++ u8 enable; ++ ++ enable = *(u8*)poid_par_priv->information_buf; ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("+oid_rt_pro_set_power_tracking_hdl: enable=%d\n", enable)); ++ ++ SetPowerTracking(Adapter, enable); ++ } else { ++ GetPowerTracking(Adapter, (u8*)poid_par_priv->information_buf); ++ } ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++} ++//----------------------------------------------------------------------------- ++NDIS_STATUS oid_rt_pro_set_basic_rate_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ u32 ratevalue; ++ u8 datarates[NumRates]; ++ int i; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_info_, ("+OID_RT_PRO_SET_BASIC_RATE\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++#if 0 ++ ratevalue = *((u32*)poid_par_priv->information_buf); ++ ++ for (i = 0; i < NumRates; i++) { ++ if (ratevalue == mpdatarate[i]) ++ datarates[i] = mpdatarate[i]; ++ else ++ datarates[i] = 0xff; ++ RT_TRACE(_module_rtl871x_ioctl_c_, _drv_info_, ("basicrate_inx=%d\n", datarates[i])); ++ } ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ if (rtw_setbasicrate_cmd(padapter, datarates) != _SUCCESS) ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, RAISE); ++#endif ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("-OID_RT_PRO_SET_BASIC_RATE: status=0x%08X\n", status)); ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_qry_pwrstate_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < 8) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ *poid_par_priv->bytes_rw = 8; ++ _rtw_memcpy(poid_par_priv->information_buf, &(adapter_to_pwrctl(Adapter)->pwr_mode), 8); ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("-oid_rt_pro_qry_pwrstate_hdl: pwr_mode=%d smart_ps=%d\n", ++ adapter_to_pwrctl(Adapter)->pwr_mode, adapter_to_pwrctl(Adapter)->smart_ps)); ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_set_pwrstate_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++ uint pwr_mode, smart_ps; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+Set OID_RT_PRO_SET_PWRSTATE\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ *poid_par_priv->bytes_rw = 0; ++ *poid_par_priv->bytes_needed = 8; ++ ++ if (poid_par_priv->information_buf_len < 8) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ pwr_mode = *(uint *)(poid_par_priv->information_buf); ++ smart_ps = *(uint *)((int)poid_par_priv->information_buf + 4); ++ ++ *poid_par_priv->bytes_rw = 8; ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_h2c_set_rate_table_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++ struct setratable_parm *prate_table; ++ u8 res; ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ *poid_par_priv->bytes_needed = sizeof(struct setratable_parm); ++ if (poid_par_priv->information_buf_len < sizeof(struct setratable_parm)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ prate_table = (struct setratable_parm*)poid_par_priv->information_buf; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ res = rtw_setrttbl_cmd(Adapter, prate_table); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ if (res == _FAIL) ++ status = NDIS_STATUS_FAILURE; ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_h2c_get_rate_table_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ #if 0 ++ struct mp_wi_cntx *pmp_wi_cntx=&(Adapter->mppriv.wi_cntx); ++ u8 res=_SUCCESS; ++ DEBUG_INFO(("===> Set OID_RT_PRO_H2C_GET_RATE_TABLE.\n")); ++ ++ if(pmp_wi_cntx->bmp_wi_progress ==_TRUE){ ++ DEBUG_ERR(("\n mp workitem is progressing, not allow to set another workitem right now!!!\n")); ++ Status = NDIS_STATUS_NOT_ACCEPTED; ++ break; ++ } ++ else{ ++ pmp_wi_cntx->bmp_wi_progress=_TRUE; ++ pmp_wi_cntx->param.bcompleted=_FALSE; ++ pmp_wi_cntx->param.act_type=MPT_GET_RATE_TABLE; ++ pmp_wi_cntx->param.io_offset=0x0; ++ pmp_wi_cntx->param.bytes_cnt=sizeof(struct getratable_rsp); ++ pmp_wi_cntx->param.io_value=0xffffffff; ++ ++ res=rtw_getrttbl_cmd(Adapter,(struct getratable_rsp *)pmp_wi_cntx->param.data); ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ if(res != _SUCCESS) ++ { ++ Status = NDIS_STATUS_NOT_ACCEPTED; ++ } ++ } ++ DEBUG_INFO(("\n <=== Set OID_RT_PRO_H2C_GET_RATE_TABLE.\n")); ++ #endif ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++ ++//**************** oid_rtl_seg_87_12_00 section start **************** ++NDIS_STATUS oid_rt_pro_encryption_ctrl_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ struct security_priv *psecuritypriv = &Adapter->securitypriv; ++ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++ ENCRY_CTRL_STATE encry_mode; ++ ++ ++ *poid_par_priv->bytes_needed = sizeof(u8); ++ if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ if (poid_par_priv->type_of_oid == SET_OID) ++ { ++ encry_mode = *((u8*)poid_par_priv->information_buf); ++ switch (encry_mode) ++ { ++ case HW_CONTROL: ++ #if 0 ++ Adapter->registrypriv.software_decrypt=_FALSE; ++ Adapter->registrypriv.software_encrypt=_FALSE; ++ #else ++ psecuritypriv->sw_decrypt = _FALSE; ++ psecuritypriv->sw_encrypt = _FALSE; ++ #endif ++ break; ++ case SW_CONTROL: ++ #if 0 ++ Adapter->registrypriv.software_decrypt=_TRUE; ++ Adapter->registrypriv.software_encrypt=_TRUE; ++ #else ++ psecuritypriv->sw_decrypt = _TRUE; ++ psecuritypriv->sw_encrypt = _TRUE; ++ #endif ++ break; ++ case HW_ENCRY_SW_DECRY: ++ #if 0 ++ Adapter->registrypriv.software_decrypt=_TRUE; ++ Adapter->registrypriv.software_encrypt=_FALSE; ++ #else ++ psecuritypriv->sw_decrypt = _TRUE; ++ psecuritypriv->sw_encrypt = _FALSE; ++ #endif ++ break; ++ case SW_ENCRY_HW_DECRY: ++ #if 0 ++ Adapter->registrypriv.software_decrypt=_FALSE; ++ Adapter->registrypriv.software_encrypt=_TRUE; ++ #else ++ psecuritypriv->sw_decrypt = _FALSE; ++ psecuritypriv->sw_encrypt = _TRUE; ++ #endif ++ break; ++ } ++ ++ RT_TRACE(_module_rtl871x_ioctl_c_, _drv_notice_, ++ ("-oid_rt_pro_encryption_ctrl_hdl: SET encry_mode=0x%x sw_encrypt=0x%x sw_decrypt=0x%x\n", ++ encry_mode, psecuritypriv->sw_encrypt, psecuritypriv->sw_decrypt)); ++ } ++ else { ++ #if 0 ++ if (Adapter->registrypriv.software_encrypt == _FALSE) { ++ if (Adapter->registrypriv.software_decrypt == _FALSE) ++ encry_mode = HW_CONTROL; ++ else ++ encry_mode = HW_ENCRY_SW_DECRY; ++ } ++ else { ++ if (Adapter->registrypriv.software_decrypt == _FALSE) ++ encry_mode = SW_ENCRY_HW_DECRY; ++ else ++ encry_mode = SW_CONTROL; ++ } ++ #else ++ ++ if ((psecuritypriv->sw_encrypt == _FALSE) && (psecuritypriv->sw_decrypt == _FALSE)) ++ encry_mode = HW_CONTROL; ++ else if ((psecuritypriv->sw_encrypt == _FALSE) && (psecuritypriv->sw_decrypt == _TRUE)) ++ encry_mode = HW_ENCRY_SW_DECRY; ++ else if ((psecuritypriv->sw_encrypt == _TRUE) && (psecuritypriv->sw_decrypt == _FALSE)) ++ encry_mode = SW_ENCRY_HW_DECRY; ++ else if ((psecuritypriv->sw_encrypt == _TRUE) && (psecuritypriv->sw_decrypt == _TRUE)) ++ encry_mode = SW_CONTROL; ++ ++ #endif ++ ++ *(u8*)poid_par_priv->information_buf = encry_mode; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("-oid_rt_pro_encryption_ctrl_hdl: QUERY encry_mode=0x%x\n", ++ encry_mode)); ++ } ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_add_sta_info_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++ struct sta_info *psta = NULL; ++ UCHAR *macaddr; ++ ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ *poid_par_priv->bytes_needed = ETH_ALEN; ++ if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ macaddr = (UCHAR *) poid_par_priv->information_buf ; ++ ++ RT_TRACE(_module_rtl871x_ioctl_c_,_drv_notice_, ++ ("OID_RT_PRO_ADD_STA_INFO: addr="MAC_FMT"\n", MAC_ARG(macaddr) )); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ psta = rtw_get_stainfo(&Adapter->stapriv, macaddr); ++ ++ if (psta == NULL) { // the sta have been in sta_info_queue => do nothing ++ psta = rtw_alloc_stainfo(&Adapter->stapriv, macaddr); ++ ++ if (psta == NULL) { ++ RT_TRACE(_module_rtl871x_ioctl_c_,_drv_err_,("Can't alloc sta_info when OID_RT_PRO_ADD_STA_INFO\n")); ++ status = NDIS_STATUS_FAILURE; ++ } ++ } else { //(between drv has received this event before and fw have not yet to set key to CAM_ENTRY) ++ RT_TRACE(_module_rtl871x_ioctl_c_, _drv_err_, ++ ("Error: OID_RT_PRO_ADD_STA_INFO: sta has been in sta_hash_queue \n")); ++ } ++ ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_dele_sta_info_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++ struct sta_info *psta = NULL; ++ UCHAR *macaddr; ++ ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ *poid_par_priv->bytes_needed = ETH_ALEN; ++ if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ macaddr = (UCHAR *) poid_par_priv->information_buf ; ++ RT_TRACE(_module_rtl871x_ioctl_c_,_drv_notice_, ++ ("+OID_RT_PRO_ADD_STA_INFO: addr="MAC_FMT"\n", MAC_ARG(macaddr) )); ++ ++ psta = rtw_get_stainfo(&Adapter->stapriv, macaddr); ++ if (psta != NULL) { ++ _enter_critical(&(Adapter->stapriv.sta_hash_lock), &irqL); ++ rtw_free_stainfo(Adapter, psta); ++ _exit_critical(&(Adapter->stapriv.sta_hash_lock), &irqL); ++ } ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++#if 0 ++#include ++static u32 mp_query_drv_var(_adapter *padapter, u8 offset, u32 var) ++{ ++#ifdef CONFIG_SDIO_HCI ++ ++ if (offset == 1) { ++ u16 tmp_blk_num; ++ tmp_blk_num = rtw_read16(padapter, SDIO_RX0_RDYBLK_NUM); ++ RT_TRACE(_module_mp_, _drv_err_, ("Query Information, mp_query_drv_var SDIO_RX0_RDYBLK_NUM=0x%x dvobj.rxblknum=0x%x\n", tmp_blk_num, adapter_to_dvobj(padapter)->rxblknum)); ++ if (adapter_to_dvobj(padapter)->rxblknum != tmp_blk_num) { ++ RT_TRACE(_module_mp_,_drv_err_, ("Query Information, mp_query_drv_var call recv rx\n")); ++ // sd_recv_rxfifo(padapter); ++ } ++ } ++ ++#if 0 ++ if(offset <=100){ //For setting data rate and query data rate ++ if(offset==100){ //For query data rate ++ RT_TRACE(_module_mp_, _drv_emerg_, ("\n mp_query_drv_var: offset(%d): query rate=0x%.2x \n",offset,padapter->registrypriv.tx_rate)); ++ var=padapter->registrypriv.tx_rate; ++ ++ } ++ else if(offset<0x1d){ //For setting data rate ++ padapter->registrypriv.tx_rate=offset; ++ var=padapter->registrypriv.tx_rate; ++ padapter->registrypriv.use_rate=_TRUE; ++ RT_TRACE(_module_mp_, _drv_emerg_, ("\n mp_query_drv_var: offset(%d): set rate=0x%.2x \n",offset,padapter->registrypriv.tx_rate)); ++ } ++ else{ //not use the data rate ++ padapter->registrypriv.use_rate=_FALSE; ++ RT_TRACE(_module_mp_, _drv_emerg_, ("\n mp_query_drv_var: offset(%d) out of rate range\n",offset)); ++ } ++ } ++ else if (offset<=110){ //for setting debug level ++ RT_TRACE(_module_mp_, _drv_emerg_, (" mp_query_drv_var: offset(%d) for set debug level\n",offset)); ++ if(offset==110){ //For query data rate ++ RT_TRACE(_module_mp_, _drv_emerg_, (" mp_query_drv_var: offset(%d): query dbg level=0x%.2x \n",offset,padapter->registrypriv.dbg_level)); ++ padapter->registrypriv.dbg_level=GlobalDebugLevel; ++ var=padapter->registrypriv.dbg_level; ++ } ++ else if(offset<110 && offset>100){ ++ RT_TRACE(_module_mp_, _drv_emerg_, (" mp_query_drv_var: offset(%d): set dbg level=0x%.2x \n",offset,offset-100)); ++ padapter->registrypriv.dbg_level=GlobalDebugLevel=offset-100; ++ var=padapter->registrypriv.dbg_level; ++ RT_TRACE(_module_mp_, _drv_emerg_, (" mp_query_drv_var(_drv_emerg_): offset(%d): set dbg level=0x%.2x \n",offset,GlobalDebugLevel)); ++ RT_TRACE(_module_mp_, _drv_alert_, (" mp_query_drv_var(_drv_alert_): offset(%d): set dbg level=0x%.2x \n",offset,GlobalDebugLevel)); ++ RT_TRACE(_module_mp_, _drv_crit_, (" mp_query_drv_var(_drv_crit_): offset(%d): set dbg level=0x%.2x \n",offset,GlobalDebugLevel)); ++ RT_TRACE(_module_mp_, _drv_err_, (" mp_query_drv_var(_drv_err_): offset(%d): set dbg level=0x%.2x \n",offset,GlobalDebugLevel)); ++ RT_TRACE(_module_mp_, _drv_warning_, (" mp_query_drv_var(_drv_warning_): offset(%d): set dbg level=0x%.2x \n",offset,GlobalDebugLevel)); ++ RT_TRACE(_module_mp_, _drv_notice_, (" mp_query_drv_var(_drv_notice_): offset(%d): set dbg level=0x%.2x \n",offset,GlobalDebugLevel)); ++ RT_TRACE(_module_mp_, _drv_info_, (" mp_query_drv_var(_drv_info_): offset(%d): set dbg level=0x%.2x \n",offset,GlobalDebugLevel)); ++ RT_TRACE(_module_mp_, _drv_debug_, (" mp_query_drv_var(_drv_debug_): offset(%d): set dbg level=0x%.2x \n",offset,GlobalDebugLevel)); ++ ++ } ++ } ++ else if(offset >110 &&offset <116){ ++ if(115==offset){ ++ RT_TRACE(_module_mp_, _drv_emerg_, (" mp_query_drv_var(_drv_emerg_): offset(%d): query TRX access type: [tx_block_mode=%x,rx_block_mode=%x]\n",\ ++ offset, adapter_to_dvobj(padapter)->tx_block_mode, adapter_to_dvobj(padapter)->rx_block_mode)); ++ } ++ else { ++ switch(offset){ ++ case 111: ++ adapter_to_dvobj(padapter)->tx_block_mode=1; ++ adapter_to_dvobj(padapter)->rx_block_mode=1; ++ RT_TRACE(_module_mp_, _drv_emerg_, \ ++ (" mp_query_drv_var(_drv_emerg_): offset(%d): SET TRX access type:(TX block/RX block) [tx_block_mode=%x,rx_block_mode=%x]\n",\ ++ offset, adapter_to_dvobj(padapter)->tx_block_mode, adapter_to_dvobj(padapter)->rx_block_mode)); ++ break; ++ case 112: ++ adapter_to_dvobj(padapter)->tx_block_mode=1; ++ adapter_to_dvobj(padapter)->rx_block_mode=0; ++ RT_TRACE(_module_mp_, _drv_emerg_, \ ++ (" mp_query_drv_var(_drv_emerg_): offset(%d): SET TRX access type:(TX block/RX byte) [tx_block_mode=%x,rx_block_mode=%x]\n",\ ++ offset, adapter_to_dvobj(padapter)->tx_block_mode, adapter_to_dvobj(padapter)->rx_block_mode)); ++ break; ++ case 113: ++ adapter_to_dvobj(padapter)->tx_block_mode=0; ++ adapter_to_dvobj(padapter)->rx_block_mode=1; ++ RT_TRACE(_module_mp_, _drv_emerg_, \ ++ (" mp_query_drv_var(_drv_emerg_): offset(%d): SET TRX access type:(TX byte/RX block) [tx_block_mode=%x,rx_block_mode=%x]\n",\ ++ offset, adapter_to_dvobj(padapter)->tx_block_mode, adapter_to_dvobj(padapter)->rx_block_mode)); ++ break; ++ case 114: ++ adapter_to_dvobj(padapter)->tx_block_mode=0; ++ adapter_to_dvobj(padapter)->rx_block_mode=0; ++ RT_TRACE(_module_mp_, _drv_emerg_, \ ++ (" mp_query_drv_var(_drv_emerg_): offset(%d): SET TRX access type:(TX byte/RX byte) [tx_block_mode=%x,rx_block_mode=%x]\n",\ ++ offset, adapter_to_dvobj(padapter)->tx_block_mode, adapter_to_dvobj(padapter)->rx_block_mode)); ++ break; ++ default : ++ break; ++ ++ } ++ ++ } ++ ++ } ++ else if(offset>=127){ ++ u64 prnt_dbg_comp; ++ u8 chg_idx; ++ u64 tmp_dbg_comp; ++ chg_idx=offset-0x80; ++ tmp_dbg_comp=BIT(chg_idx); ++ prnt_dbg_comp=padapter->registrypriv.dbg_component= GlobalDebugComponents; ++ RT_TRACE(_module_mp_, _drv_emerg_, (" 1: mp_query_drv_var: offset(%d;0x%x):for dbg conpoment prnt_dbg_comp=0x%.16x GlobalDebugComponents=0x%.16x padapter->registrypriv.dbg_component=0x%.16x\n",offset,offset,prnt_dbg_comp,GlobalDebugComponents,padapter->registrypriv.dbg_component)); ++ if(offset==127){ ++ // prnt_dbg_comp=padapter->registrypriv.dbg_component= GlobalDebugComponents; ++ var=(u32)(padapter->registrypriv.dbg_component); ++ RT_TRACE(0xffffffff, _drv_emerg_, ("2: mp_query_drv_var: offset(%d;0x%x):for query dbg conpoment=0x%x(l) 0x%x(h) GlobalDebugComponents=0x%x(l) 0x%x(h) \n",offset,offset,padapter->registrypriv.dbg_component,prnt_dbg_comp)); ++ prnt_dbg_comp=GlobalDebugComponents; ++ RT_TRACE(0xffffffff, _drv_emerg_, ("2-1: mp_query_drv_var: offset(%d;0x%x):for query dbg conpoment=0x%x(l) 0x%x(h) GlobalDebugComponents=0x%x(l) 0x%x(h)\n",offset,offset,padapter->registrypriv.dbg_component,prnt_dbg_comp)); ++ prnt_dbg_comp=GlobalDebugComponents=padapter->registrypriv.dbg_component; ++ RT_TRACE(0xffffffff, _drv_emerg_, ("2-2: mp_query_drv_var: offset(%d;0x%x):for query dbg conpoment=0x%x(l) 0x%x(h) GlobalDebugComponents=0x%x(l) 0x%x(h)\n",offset,offset,padapter->registrypriv.dbg_component,prnt_dbg_comp)); ++ ++ } ++ else{ ++ RT_TRACE(0xffffffff, _drv_emerg_, ("3: mp_query_drv_var: offset(%d;0x%x):for query dbg conpoment=0x%x(l) 0x%x(h) GlobalDebugComponents=0x%x(l) 0x%x(h) chg_idx=%d\n",offset,offset,padapter->registrypriv.dbg_component,prnt_dbg_comp,chg_idx)); ++ prnt_dbg_comp=GlobalDebugComponents; ++ RT_TRACE(0xffffffff, _drv_emerg_,("3-1: mp_query_drv_var: offset(%d;0x%x):for query dbg conpoment=0x%x(l) 0x%x(h) GlobalDebugComponents=0x%x(l) 0x%x(h) chg_idx=%d\n",offset,offset,padapter->registrypriv.dbg_component,prnt_dbg_comp,chg_idx));// ("3-1: mp_query_drv_var: offset(%d;0x%x):before set dbg conpoment=0x%x chg_idx=%d or0x%x BIT(chg_idx[%d]=0x%x)\n",offset,offset,prnt_dbg_comp,chg_idx,chg_idx,(chg_idx),tmp_dbg_comp) ++ prnt_dbg_comp=GlobalDebugComponents=padapter->registrypriv.dbg_component; ++ RT_TRACE(0xffffffff, _drv_emerg_, ("3-2: mp_query_drv_var: offset(%d;0x%x):for query dbg conpoment=0x%x(l) 0x%x(h) GlobalDebugComponents=0x%x(l) 0x%x(h)\n",offset,offset,padapter->registrypriv.dbg_component,prnt_dbg_comp)); ++ ++ if(GlobalDebugComponents&tmp_dbg_comp){ ++ //this bit is already set, now clear it ++ GlobalDebugComponents=GlobalDebugComponents&(~tmp_dbg_comp); ++ } ++ else{ ++ //this bit is not set, now set it. ++ GlobalDebugComponents =GlobalDebugComponents|tmp_dbg_comp; ++ } ++ RT_TRACE(0xffffffff, _drv_emerg_, ("4: mp_query_drv_var: offset(%d;0x%x):before set dbg conpoment tmp_dbg_comp=0x%x GlobalDebugComponents=0x%x(l) 0x%x(h)",offset,offset,tmp_dbg_comp,prnt_dbg_comp)); ++ prnt_dbg_comp=GlobalDebugComponents; ++ RT_TRACE(0xffffffff, _drv_emerg_, ("4-1: mp_query_drv_var: offset(%d;0x%x):before set dbg conpoment tmp_dbg_comp=0x%x GlobalDebugComponents=0x%x(l) 0x%x(h)",offset,offset,tmp_dbg_comp,prnt_dbg_comp)); ++ ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_emerg_, ("0: mp_query_drv_var(_module_rtl871x_xmit_c_:0): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,prnt_dbg_comp)); ++ RT_TRACE(_module_xmit_osdep_c_, _drv_emerg_, ("1: mp_query_drv_var(_module_xmit_osdep_c_:1): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_emerg_, ("2: mp_query_drv_var(_module_rtl871x_recv_c_:2): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_recv_osdep_c_, _drv_emerg_, ("3: mp_query_drv_var(_module_recv_osdep_c_:3): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_emerg_, ("4: mp_query_drv_var(_module_rtl871x_mlme_c_:4): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_mlme_osdep_c_, _drv_emerg_, (" 5:mp_query_drv_var(_module_mlme_osdep_c_:5): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_emerg_, ("6: mp_query_drv_var(_module_rtl871x_sta_mgt_c_:6): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_emerg_, ("7: mp_query_drv_var(_module_rtl871x_cmd_c_:7): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_cmd_osdep_c_, _drv_emerg_, ("8: mp_query_drv_var(_module_cmd_osdep_c_:8): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_rtl871x_io_c_, _drv_emerg_, ("9: mp_query_drv_var(_module_rtl871x_io_c_:9): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_io_osdep_c_, _drv_emerg_, ("10: mp_query_drv_var(_module_io_osdep_c_:10): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_os_intfs_c_, _drv_emerg_, ("11: mp_query_drv_var(_module_os_intfs_c_:11): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_rtl871x_security_c_, _drv_emerg_, ("12: mp_query_drv_var(_module_rtl871x_security_c_:12): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_rtl871x_eeprom_c_, _drv_emerg_, ("13: mp_query_drv_var(_module_rtl871x_eeprom_c_:13): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_hal_init_c_, _drv_emerg_, ("14: mp_query_drv_var(_module_hal_init_c_:14): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_hci_hal_init_c_, _drv_emerg_, ("15: mp_query_drv_var(_module_hci_hal_init_c_:15): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_rtl871x_ioctl_c_, _drv_emerg_, ("16: mp_query_drv_var(_module_rtl871x_ioctl_c_:16): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_emerg_, ("17: mp_query_drv_var(_module_rtl871x_ioctl_set_c_:17): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_rtl871x_ioctl_query_c_, _drv_emerg_, ("18: mp_query_drv_var(_module_rtl871x_ioctl_query_c_:18): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_emerg_, ("19: mp_query_drv_var(_module_rtl871x_pwrctrl_c_:19): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_hci_intfs_c_, _drv_emerg_, ("20: mp_query_drv_var(_module_hci_intfs_c_:20): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_hci_ops_c_, _drv_emerg_, ("21: mp_query_drv_var(_module_hci_ops_c_:21): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_osdep_service_c_, _drv_emerg_, ("22: mp_query_drv_var(_module_osdep_service_c_:22): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_mp_, _drv_emerg_, ("23: mp_query_drv_var(_module_mp_:23): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ RT_TRACE(_module_hci_ops_os_c_, _drv_emerg_, ("24: mp_query_drv_var(_module_hci_ops_os_c_:24): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ var=(u32)(GlobalDebugComponents); ++ //GlobalDebugComponents=padapter->registrypriv.dbg_component; ++ RT_TRACE(0xffffffff, _drv_emerg_, (" ==mp_query_drv_var(_module_mp_): offset(%d;0x%x):before set dbg conpoment=0x%x(l) 0x%x(h)\n",offset,offset,GlobalDebugComponents)); ++ ++ } ++ } ++ else{ ++ RT_TRACE(_module_mp_, _drv_emerg_, ("\n mp_query_drv_var: offset(%d) >110\n",offset)); ++ } ++#endif ++#endif ++ ++ return var; ++} ++#endif ++ ++NDIS_STATUS oid_rt_pro_query_dr_variable_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++ DR_VARIABLE_STRUCT *pdrv_var; ++ ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ *poid_par_priv->bytes_needed = sizeof(DR_VARIABLE_STRUCT); ++ if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+Query Information, OID_RT_PRO_QUERY_DR_VARIABLE\n")); ++ ++ pdrv_var = (struct _DR_VARIABLE_STRUCT_ *)poid_par_priv->information_buf; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ pdrv_var->variable = mp_query_drv_var(Adapter, pdrv_var->offset, pdrv_var->variable); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("-oid_rt_pro_query_dr_variable_hdl: offset=0x%x valule=0x%x\n", ++ pdrv_var->offset, pdrv_var->variable)); ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++ RT_TRACE(_module_mp_, _drv_err_, ("oid_rt_pro_rx_packet_type_hdl...................\n")); ++ ++ if (poid_par_priv->information_buf_len < sizeof (UCHAR)) { ++ status = NDIS_STATUS_INVALID_LENGTH; ++ *poid_par_priv->bytes_needed = sizeof(UCHAR); ++ return status; ++ } ++ ++ if (poid_par_priv->type_of_oid == SET_OID) { ++ Adapter->mppriv.rx_with_status = *(UCHAR *) poid_par_priv->information_buf; ++ RT_TRACE(_module_rtl871x_ioctl_c_,_drv_err_, ("Query Information, OID_RT_PRO_RX_PACKET_TYPE:%d \n",\ ++ Adapter->mppriv.rx_with_status)); ++ ++ //*(u32 *)&Adapter->eeprompriv.mac_addr[0]=rtw_read32(Adapter, 0x10250050); ++ //*(u16 *)&Adapter->eeprompriv.mac_addr[4]=rtw_read16(Adapter, 0x10250054); ++ RT_TRACE(_module_rtl871x_ioctl_c_,_drv_err_,("MAC addr=0x%x:0x%x:0x%x:0x%x:0x%x:0x%x \n", ++ Adapter->eeprompriv.mac_addr[0],Adapter->eeprompriv.mac_addr[1],Adapter->eeprompriv.mac_addr[2],\ ++ Adapter->eeprompriv.mac_addr[3],Adapter->eeprompriv.mac_addr[4],Adapter->eeprompriv.mac_addr[5])); ++ ++ } ++ else { ++ *(UCHAR *) poid_par_priv->information_buf = Adapter->mppriv.rx_with_status; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ RT_TRACE(_module_rtl871x_ioctl_c_,_drv_err_, ("Query Information, OID_RT_PRO_RX_PACKET_TYPE:%d \n", \ ++ Adapter->mppriv.rx_with_status)); ++ ++ //*(u32 *)&Adapter->eeprompriv.mac_addr[0]=rtw_read32(Adapter, 0x10250050); ++ //*(u16 *)&Adapter->eeprompriv.mac_addr[4]=rtw_read16(Adapter, 0x10250054); ++ RT_TRACE(_module_rtl871x_ioctl_c_,_drv_err_,("MAC addr=0x%x:0x%x:0x%x:0x%x:0x%x:0x%x \n", ++ Adapter->eeprompriv.mac_addr[0],Adapter->eeprompriv.mac_addr[1],Adapter->eeprompriv.mac_addr[2],\ ++ Adapter->eeprompriv.mac_addr[3],Adapter->eeprompriv.mac_addr[4],Adapter->eeprompriv.mac_addr[5])); ++ } ++#endif ++ ++ return NDIS_STATUS_SUCCESS; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ PEFUSE_ACCESS_STRUCT pefuse; ++ u8 *data; ++ u16 addr = 0, cnts = 0, max_available_size = 0; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(EFUSE_ACCESS_STRUCT)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ pefuse = (PEFUSE_ACCESS_STRUCT)poid_par_priv->information_buf; ++ addr = pefuse->start_addr; ++ cnts = pefuse->cnts; ++ data = pefuse->data; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("+oid_rt_pro_read_efuse_hd: buf_len=%d addr=%d cnts=%d\n", ++ poid_par_priv->information_buf_len, addr, cnts)); ++ ++ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_available_size, _FALSE); ++ ++ if ((addr + cnts) > max_available_size) { ++ RT_TRACE(_module_mp_, _drv_err_, ("!oid_rt_pro_read_efuse_hdl: parameter error!\n")); ++ return NDIS_STATUS_NOT_ACCEPTED; ++ } ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ if (rtw_efuse_access(Adapter, _FALSE, addr, cnts, data) == _FAIL) { ++ RT_TRACE(_module_mp_, _drv_err_, ("!oid_rt_pro_read_efuse_hdl: rtw_efuse_access FAIL!\n")); ++ status = NDIS_STATUS_FAILURE; ++ } else ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ PEFUSE_ACCESS_STRUCT pefuse; ++ u8 *data; ++ u16 addr = 0, cnts = 0, max_available_size = 0; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ pefuse = (PEFUSE_ACCESS_STRUCT)poid_par_priv->information_buf; ++ addr = pefuse->start_addr; ++ cnts = pefuse->cnts; ++ data = pefuse->data; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("+oid_rt_pro_write_efuse_hdl: buf_len=%d addr=0x%04x cnts=%d\n", ++ poid_par_priv->information_buf_len, addr, cnts)); ++ ++ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_available_size, _FALSE); ++ ++ if ((addr + cnts) > max_available_size) { ++ RT_TRACE(_module_mp_, _drv_err_, ("!oid_rt_pro_write_efuse_hdl: parameter error")); ++ return NDIS_STATUS_NOT_ACCEPTED; ++ } ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ if (rtw_efuse_access(Adapter, _TRUE, addr, cnts, data) == _FAIL) ++ status = NDIS_STATUS_FAILURE; ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_rw_efuse_pgpkt_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ PPGPKT_STRUCT ppgpkt; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++// RT_TRACE(_module_mp_, _drv_info_, ("+oid_rt_pro_rw_efuse_pgpkt_hdl\n")); ++ ++ *poid_par_priv->bytes_rw = 0; ++ ++ if (poid_par_priv->information_buf_len < sizeof(PGPKT_STRUCT)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ ppgpkt = (PPGPKT_STRUCT)poid_par_priv->information_buf; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ if (poid_par_priv->type_of_oid == QUERY_OID) ++ { ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("oid_rt_pro_rw_efuse_pgpkt_hdl: Read offset=0x%x\n",\ ++ ppgpkt->offset)); ++ ++ Efuse_PowerSwitch(Adapter, _FALSE, _TRUE); ++ if (Efuse_PgPacketRead(Adapter, ppgpkt->offset, ppgpkt->data, _FALSE) == _TRUE) ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ else ++ status = NDIS_STATUS_FAILURE; ++ Efuse_PowerSwitch(Adapter, _FALSE, _FALSE); ++ } else { ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("oid_rt_pro_rw_efuse_pgpkt_hdl: Write offset=0x%x word_en=0x%x\n",\ ++ ppgpkt->offset, ppgpkt->word_en)); ++ ++ Efuse_PowerSwitch(Adapter, _TRUE, _TRUE); ++ if (Efuse_PgPacketWrite(Adapter, ppgpkt->offset, ppgpkt->word_en, ppgpkt->data, _FALSE) == _TRUE) ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ else ++ status = NDIS_STATUS_FAILURE; ++ Efuse_PowerSwitch(Adapter, _TRUE, _FALSE); ++ } ++ ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("-oid_rt_pro_rw_efuse_pgpkt_hdl: status=0x%08X\n", status)); ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_get_efuse_current_size_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ u16 size; ++ u8 ret; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len information_buf = size; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } else ++ status = NDIS_STATUS_FAILURE; ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_get_efuse_max_size_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ *(u32*)poid_par_priv->information_buf = efuse_GetMaxSize(Adapter); ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("-oid_rt_get_efuse_max_size_hdl: size=%d status=0x%08X\n", ++ *(int*)poid_par_priv->information_buf, status)); ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ NDIS_STATUS status; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_info_, ("+oid_rt_pro_efuse_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid == QUERY_OID) ++ status = oid_rt_pro_read_efuse_hdl(poid_par_priv); ++ else ++ status = oid_rt_pro_write_efuse_hdl(poid_par_priv); ++ ++ RT_TRACE(_module_mp_, _drv_info_, ("-oid_rt_pro_efuse_hdl: status=0x%08X\n", status)); ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ u8 *data; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ u16 mapLen=0; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+oid_rt_pro_efuse_map_hdl\n")); ++ ++ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE); ++ ++ *poid_par_priv->bytes_rw = 0; ++ ++ if (poid_par_priv->information_buf_len < mapLen) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ data = (u8*)poid_par_priv->information_buf; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ if (poid_par_priv->type_of_oid == QUERY_OID) ++ { ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("oid_rt_pro_efuse_map_hdl: READ\n")); ++ ++ if (rtw_efuse_map_read(Adapter, 0, mapLen, data) == _SUCCESS) ++ *poid_par_priv->bytes_rw = mapLen; ++ else { ++ RT_TRACE(_module_mp_, _drv_err_, ++ ("oid_rt_pro_efuse_map_hdl: READ fail\n")); ++ status = NDIS_STATUS_FAILURE; ++ } ++ } else { ++ // SET_OID ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("oid_rt_pro_efuse_map_hdl: WRITE\n")); ++ ++ if (rtw_efuse_map_write(Adapter, 0, mapLen, data) == _SUCCESS) ++ *poid_par_priv->bytes_rw = mapLen; ++ else { ++ RT_TRACE(_module_mp_, _drv_err_, ++ ("oid_rt_pro_efuse_map_hdl: WRITE fail\n")); ++ status = NDIS_STATUS_FAILURE; ++ } ++ } ++ ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("-oid_rt_pro_efuse_map_hdl: status=0x%08X\n", status)); ++ ++_func_exit_; ++ ++ return status; ++} ++ ++NDIS_STATUS oid_rt_set_crystal_cap_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ ++ u32 crystal_cap = 0; ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len information_buf);//4 ++ if (crystal_cap > 0xf) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ Adapter->mppriv.curr_crystalcap = crystal_cap; ++ ++ _irqlevel_changed_(&oldirql,LOWER); ++ SetCrystalCap(Adapter); ++ _irqlevel_changed_(&oldirql,RAISE); ++ ++_func_exit_; ++ ++#endif ++ return status; ++} ++ ++NDIS_STATUS oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ u8 rx_pkt_type; ++// u32 rcr_val32; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++// PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+oid_rt_set_rx_packet_type_hdl\n")); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(u8)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ rx_pkt_type = *((u8*)poid_par_priv->information_buf);//4 ++ ++ RT_TRACE(_module_mp_, _drv_info_, ("rx_pkt_type: %x\n",rx_pkt_type )); ++#if 0 ++ _irqlevel_changed_(&oldirql, LOWER); ++#if 0 ++ rcr_val8 = rtw_read8(Adapter, 0x10250048);//RCR ++ rcr_val8 &= ~(RCR_AB|RCR_AM|RCR_APM|RCR_AAP); ++ ++ if(rx_pkt_type == RX_PKT_BROADCAST){ ++ rcr_val8 |= (RCR_AB | RCR_ACRC32 ); ++ } ++ else if(rx_pkt_type == RX_PKT_DEST_ADDR){ ++ rcr_val8 |= (RCR_AAP| RCR_AM |RCR_ACRC32); ++ } ++ else if(rx_pkt_type == RX_PKT_PHY_MATCH){ ++ rcr_val8 |= (RCR_APM|RCR_ACRC32); ++ } ++ else{ ++ rcr_val8 &= ~(RCR_AAP|RCR_APM|RCR_AM|RCR_AB|RCR_ACRC32); ++ } ++ rtw_write8(padapter, 0x10250048,rcr_val8); ++#else ++ rcr_val32 = rtw_read32(padapter, RCR);//RCR = 0x10250048 ++ rcr_val32 &= ~(RCR_CBSSID|RCR_AB|RCR_AM|RCR_APM|RCR_AAP); ++#if 0 ++ if(rx_pkt_type == RX_PKT_BROADCAST){ ++ rcr_val32 |= (RCR_AB|RCR_AM|RCR_APM|RCR_AAP|RCR_ACRC32); ++ } ++ else if(rx_pkt_type == RX_PKT_DEST_ADDR){ ++ //rcr_val32 |= (RCR_CBSSID|RCR_AAP|RCR_AM|RCR_ACRC32); ++ rcr_val32 |= (RCR_CBSSID|RCR_APM|RCR_ACRC32); ++ } ++ else if(rx_pkt_type == RX_PKT_PHY_MATCH){ ++ rcr_val32 |= (RCR_APM|RCR_ACRC32); ++ //rcr_val32 |= (RCR_AAP|RCR_ACRC32); ++ } ++ else{ ++ rcr_val32 &= ~(RCR_AAP|RCR_APM|RCR_AM|RCR_AB|RCR_ACRC32); ++ } ++#else ++ switch (rx_pkt_type) ++ { ++ case RX_PKT_BROADCAST : ++ rcr_val32 |= (RCR_AB|RCR_AM|RCR_APM|RCR_AAP|RCR_ACRC32); ++ break; ++ case RX_PKT_DEST_ADDR : ++ rcr_val32 |= (RCR_AB|RCR_AM|RCR_APM|RCR_AAP|RCR_ACRC32); ++ break; ++ case RX_PKT_PHY_MATCH: ++ rcr_val32 |= (RCR_APM|RCR_ACRC32); ++ break; ++ default: ++ rcr_val32 &= ~(RCR_AAP|RCR_APM|RCR_AM|RCR_AB|RCR_ACRC32); ++ break; ++ } ++ ++ if (rx_pkt_type == RX_PKT_DEST_ADDR) { ++ padapter->mppriv.check_mp_pkt = 1; ++ } else { ++ padapter->mppriv.check_mp_pkt = 0; ++ } ++#endif ++ rtw_write32(padapter, RCR, rcr_val32); ++ ++#endif ++ _irqlevel_changed_(&oldirql, RAISE); ++#endif ++_func_exit_; ++ ++ return status; ++} ++ ++NDIS_STATUS oid_rt_pro_set_tx_agc_offset_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++ u32 txagc; ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ txagc = *(u32*)poid_par_priv->information_buf; ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("oid_rt_pro_set_tx_agc_offset_hdl: 0x%08x\n", txagc)); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetTxAGCOffset(Adapter, txagc); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++ ++NDIS_STATUS oid_rt_pro_set_pkt_test_mode_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++ ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ struct mp_priv *pmppriv = &Adapter->mppriv; ++ u32 type; ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len information_buf; ++ ++ if (_LOOPBOOK_MODE_ == type) { ++ pmppriv->mode = type; ++ set_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE); //append txdesc ++ RT_TRACE(_module_mp_, _drv_info_, ("test mode change to loopback mode:0x%08x.\n", get_fwstate(pmlmepriv))); ++ } else if (_2MAC_MODE_ == type){ ++ pmppriv->mode = type; ++ _clr_fwstate_(pmlmepriv, WIFI_MP_LPBK_STATE); ++ RT_TRACE(_module_mp_, _drv_info_, ("test mode change to 2mac mode:0x%08x.\n", get_fwstate(pmlmepriv))); ++ } else ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++ ++unsigned int mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ PMP_XMIT_PARM pparm; ++ PADAPTER padapter; ++ struct mp_priv *pmp_priv; ++ struct pkt_attrib *pattrib; ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("+%s\n", __func__)); ++ ++ pparm = (PMP_XMIT_PARM)poid_par_priv->information_buf; ++ padapter = (PADAPTER)poid_par_priv->adapter_context; ++ pmp_priv = &padapter->mppriv; ++ ++ if (poid_par_priv->type_of_oid == QUERY_OID) { ++ pparm->enable = !pmp_priv->tx.stop; ++ pparm->count = pmp_priv->tx.sended; ++ } else { ++ if (pparm->enable == 0) { ++ pmp_priv->tx.stop = 1; ++ } else if (pmp_priv->tx.stop == 1) { ++ pmp_priv->tx.stop = 0; ++ pmp_priv->tx.count = pparm->count; ++ pmp_priv->tx.payload = pparm->payload_type; ++ pattrib = &pmp_priv->tx.attrib; ++ pattrib->pktlen = pparm->length; ++ _rtw_memcpy(pattrib->dst, pparm->da, ETH_ALEN); ++ SetPacketTx(padapter); ++ } else ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ return NDIS_STATUS_SUCCESS; ++} ++ ++#if 0 ++unsigned int mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ unsigned char *pframe, *pmp_pkt; ++ struct ethhdr *pethhdr; ++ struct pkt_attrib *pattrib; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ int llc_sz, payload_len; ++ struct mp_xmit_frame *pxframe= NULL; ++ struct mp_xmit_packet *pmp_xmitpkt = (struct mp_xmit_packet*)param; ++ u8 addr3[] = {0x02, 0xE0, 0x4C, 0x87, 0x66, 0x55}; ++ ++// DBG_871X("+mp_ioctl_xmit_packet_hdl\n"); ++ ++ pxframe = alloc_mp_xmitframe(&padapter->mppriv); ++ if (pxframe == NULL) ++ { ++ DEBUG_ERR(("Can't alloc pmpframe %d:%s\n", __LINE__, __FILE__)); ++ return -1; ++ } ++ ++ //mp_xmit_pkt ++ payload_len = pmp_xmitpkt->len - 14; ++ pmp_pkt = (unsigned char*)pmp_xmitpkt->mem; ++ pethhdr = (struct ethhdr *)pmp_pkt; ++ ++ //DBG_871X("payload_len=%d, pkt_mem=0x%x\n", pmp_xmitpkt->len, (void*)pmp_xmitpkt->mem); ++ ++ //DBG_871X("pxframe=0x%x\n", (void*)pxframe); ++ //DBG_871X("pxframe->mem=0x%x\n", (void*)pxframe->mem); ++ ++ //update attribute ++ pattrib = &pxframe->attrib; ++ memset((u8 *)(pattrib), 0, sizeof (struct pkt_attrib)); ++ pattrib->pktlen = pmp_xmitpkt->len; ++ pattrib->ether_type = ntohs(pethhdr->h_proto); ++ pattrib->hdrlen = 24; ++ pattrib->nr_frags = 1; ++ pattrib->priority = 0; ++#ifndef CONFIG_MP_LINUX ++ if(IS_MCAST(pethhdr->h_dest)) ++ pattrib->mac_id = 4; ++ else ++ pattrib->mac_id = 5; ++#else ++ pattrib->mac_id = 5; ++#endif ++ ++ // ++ memset(pxframe->mem, 0 , WLANHDR_OFFSET); ++ pframe = (u8 *)(pxframe->mem) + WLANHDR_OFFSET; ++ ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ SetFrameSubType(pframe, WIFI_DATA); ++ ++ _rtw_memcpy(pwlanhdr->addr1, pethhdr->h_dest, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, pethhdr->h_source, ETH_ALEN); ++ ++ _rtw_memcpy(pwlanhdr->addr3, addr3, ETH_ALEN); ++ ++ pwlanhdr->seq_ctl = 0; ++ pframe += pattrib->hdrlen; ++ ++ llc_sz= rtw_put_snap(pframe, pattrib->ether_type); ++ pframe += llc_sz; ++ ++ _rtw_memcpy(pframe, (void*)(pmp_pkt+14), payload_len); ++ ++ pattrib->last_txcmdsz = pattrib->hdrlen + llc_sz + payload_len; ++ ++ DEBUG_INFO(("issuing mp_xmit_frame, tx_len=%d, ether_type=0x%x\n", pattrib->last_txcmdsz, pattrib->ether_type)); ++ xmit_mp_frame(padapter, pxframe); ++ ++ return _SUCCESS; ++} ++#endif ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_set_power_down_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#ifdef PLATFORM_OS_XP ++ _irqL oldirql; ++#endif ++ u8 bpwrup; ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++#ifdef PLATFORM_LINUX ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); ++#endif ++#endif ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("\n ===> Setoid_rt_set_power_down_hdl.\n")); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ bpwrup = *(u8 *)poid_par_priv->information_buf; ++ //CALL the power_down function ++#ifdef PLATFORM_LINUX ++#if defined(CONFIG_RTL8712) //Linux MP insmod unknown symbol ++ dev_power_down(padapter,bpwrup); ++#endif ++#endif ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ //DEBUG_ERR(("\n <=== Query OID_RT_PRO_READ_REGISTER. ++ // Add:0x%08x Width:%d Value:0x%08x\n",RegRWStruct->offset,RegRWStruct->width,RegRWStruct->value)); ++ ++_func_exit_; ++ ++ return status; ++} ++//------------------------------------------------------------------------------ ++NDIS_STATUS oid_rt_get_power_mode_hdl(struct oid_par_priv *poid_par_priv) ++{ ++#if 0 ++ NDIS_STATUS status = NDIS_STATUS_SUCCESS; ++ PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); ++//#ifdef PLATFORM_OS_XP ++// _irqL oldirql; ++//#endif ++ ++_func_enter_; ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ if (poid_par_priv->information_buf_len < sizeof(u32)) { ++ status = NDIS_STATUS_INVALID_LENGTH; ++ return status; ++ } ++ ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("\n ===> oid_rt_get_power_mode_hdl.\n")); ++ ++// _irqlevel_changed_(&oldirql, LOWER); ++ *(int*)poid_par_priv->information_buf = Adapter->registrypriv.low_power ? POWER_LOW : POWER_NORMAL; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++// _irqlevel_changed_(&oldirql, RAISE); ++ ++_func_exit_; ++ ++ return status; ++#else ++ return 0; ++#endif ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_odm.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_odm.c +new file mode 100644 +index 00000000..b7176266 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_odm.c +@@ -0,0 +1,217 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2013 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#include ++#ifdef CONFIG_RTL8192C ++#include ++#endif ++#ifdef CONFIG_RTL8192D ++#include ++#endif ++#ifdef CONFIG_RTL8723A ++#include ++#endif ++#ifdef CONFIG_RTL8188E ++#include ++#endif ++ ++const char *odm_comp_str[] = { ++ "ODM_COMP_DIG", ++ "ODM_COMP_RA_MASK", ++ "ODM_COMP_DYNAMIC_TXPWR", ++ "ODM_COMP_FA_CNT", ++ "ODM_COMP_RSSI_MONITOR", ++ "ODM_COMP_CCK_PD", ++ "ODM_COMP_ANT_DIV", ++ "ODM_COMP_PWR_SAVE", ++ "ODM_COMP_PWR_TRAIN", ++ "ODM_COMP_RATE_ADAPTIVE", ++ "ODM_COMP_PATH_DIV", ++ "ODM_COMP_PSD", ++ "ODM_COMP_DYNAMIC_PRICCA", ++ "ODM_COMP_RXHP", ++ NULL, ++ NULL, ++ "ODM_COMP_EDCA_TURBO", ++ "ODM_COMP_EARLY_MODE", ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ "ODM_COMP_TX_PWR_TRACK", ++ "ODM_COMP_RX_GAIN_TRACK", ++ "ODM_COMP_CALIBRATION", ++ NULL, ++ NULL, ++ NULL, ++ "ODM_COMP_COMMON", ++ "ODM_COMP_INIT", ++}; ++ ++#define RTW_ODM_COMP_MAX 32 ++ ++const char *odm_ability_str[] = { ++ "ODM_BB_DIG", ++ "ODM_BB_RA_MASK", ++ "ODM_BB_DYNAMIC_TXPWR", ++ "ODM_BB_FA_CNT", ++ "ODM_BB_RSSI_MONITOR", ++ "ODM_BB_CCK_PD ", ++ "ODM_BB_ANT_DIV", ++ "ODM_BB_PWR_SAVE", ++ "ODM_BB_PWR_TRAIN", ++ "ODM_BB_RATE_ADAPTIVE", ++ "ODM_BB_PATH_DIV", ++ "ODM_BB_PSD", ++ "ODM_BB_RXHP", ++ "ODM_BB_ADAPTIVITY", ++ "ODM_BB_DYNAMIC_ATC", ++ NULL, ++ "ODM_MAC_EDCA_TURBO", ++ "ODM_MAC_EARLY_MODE", ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ "ODM_RF_TX_PWR_TRACK", ++ "ODM_RF_RX_GAIN_TRACK", ++ "ODM_RF_CALIBRATION", ++}; ++ ++#define RTW_ODM_ABILITY_MAX 27 ++ ++const char *odm_dbg_level_str[] = { ++ NULL, ++ "ODM_DBG_OFF", ++ "ODM_DBG_SERIOUS", ++ "ODM_DBG_WARNING", ++ "ODM_DBG_LOUD", ++ "ODM_DBG_TRACE ", ++}; ++ ++#define RTW_ODM_DBG_LEVEL_NUM 6 ++ ++int _rtw_odm_dbg_comp_msg(_adapter *adapter, char *buf, int len) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); ++ DM_ODM_T *odm = &pHalData->odmpriv; ++ int cnt = 0; ++ u64 dbg_comp; ++ int i; ++ ++ rtw_hal_get_def_var(adapter, HW_DEF_ODM_DBG_FLAG, &dbg_comp); ++ cnt += snprintf(buf+cnt, len-cnt, "odm.DebugComponents = 0x%016llx \n", dbg_comp); ++ for (i=0;iodmpriv; ++ int cnt = 0; ++ u32 dbg_level; ++ int i; ++ ++ rtw_hal_get_def_var(adapter, HW_DEF_ODM_DBG_LEVEL, &dbg_level); ++ cnt += snprintf(buf+cnt, len-cnt, "odm.DebugDebugLevel = %u\n", dbg_level); ++ for (i=0;iodmpriv; ++ ++ return snprintf(buf, len, ++ "%10s %16s %8s %10s %11s %14s\n" ++ "0x%-8x %-16d 0x%-6x %-10d %-11u %-14u\n", ++ "TH_L2H_ini", "TH_EDCCA_HL_diff", "IGI_Base", "ForceEDCCA", "AdapEn_RSSI", "IGI_LowerBound", ++ (u8)odm->TH_L2H_ini, ++ odm->TH_EDCCA_HL_diff, ++ odm->IGI_Base, ++ odm->ForceEDCCA, ++ odm->AdapEn_RSSI, ++ odm->IGI_LowerBound ++ ); ++} ++ ++void rtw_odm_adaptivity_parm_msg(_adapter *adapter) ++{ ++ char buf[256] = {0}; ++ ++ _rtw_odm_dbg_comp_msg(adapter, buf, 256); ++ DBG_871X_LEVEL(_drv_always_, "\n%s", buf); ++} ++ ++void rtw_odm_adaptivity_parm_set(_adapter *adapter, s8 TH_L2H_ini, s8 TH_EDCCA_HL_diff, ++ s8 IGI_Base, bool ForceEDCCA, u8 AdapEn_RSSI, u8 IGI_LowerBound) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); ++ DM_ODM_T *odm = &pHalData->odmpriv; ++ ++ odm->TH_L2H_ini = TH_L2H_ini; ++ odm->TH_EDCCA_HL_diff = TH_EDCCA_HL_diff; ++ odm->IGI_Base = IGI_Base; ++ odm->ForceEDCCA = ForceEDCCA; ++ odm->AdapEn_RSSI = AdapEn_RSSI; ++ odm->IGI_LowerBound = IGI_LowerBound; ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_p2p.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_p2p.c +new file mode 100644 +index 00000000..b9b205ab +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_p2p.c +@@ -0,0 +1,5312 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_P2P_C_ ++ ++#include ++#include ++#include ++ ++#ifdef CONFIG_P2P ++ ++int rtw_p2p_is_channel_list_ok( u8 desired_ch, u8* ch_list, u8 ch_cnt ) ++{ ++ int found = 0, i = 0; ++ ++ for( i = 0; i < ch_cnt; i++ ) ++ { ++ if ( ch_list[ i ] == desired_ch ) ++ { ++ found = 1; ++ break; ++ } ++ } ++ return( found ); ++} ++ ++int is_any_client_associated(_adapter *padapter) ++{ ++ return padapter->stapriv.asoc_list_cnt ? _TRUE : _FALSE; ++} ++ ++static u32 go_add_group_info_attr(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ _irqL irqL; ++ _list *phead, *plist; ++ u32 len=0; ++ u16 attr_len = 0; ++ u8 tmplen, *pdata_attr, *pstart, *pcur; ++ struct sta_info *psta = NULL; ++ _adapter *padapter = pwdinfo->padapter; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ pdata_attr = rtw_zmalloc(MAX_P2P_IE_LEN); ++ ++ pstart = pdata_attr; ++ pcur = pdata_attr; ++ ++ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ ++ //look up sta asoc_queue ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ ++ plist = get_next(plist); ++ ++ ++ if(psta->is_p2p_device) ++ { ++ tmplen = 0; ++ ++ pcur++; ++ ++ //P2P device address ++ _rtw_memcpy(pcur, psta->dev_addr, ETH_ALEN); ++ pcur += ETH_ALEN; ++ ++ //P2P interface address ++ _rtw_memcpy(pcur, psta->hwaddr, ETH_ALEN); ++ pcur += ETH_ALEN; ++ ++ *pcur = psta->dev_cap; ++ pcur++; ++ ++ //*(u16*)(pcur) = cpu_to_be16(psta->config_methods); ++ RTW_PUT_BE16(pcur, psta->config_methods); ++ pcur += 2; ++ ++ _rtw_memcpy(pcur, psta->primary_dev_type, 8); ++ pcur += 8; ++ ++ *pcur = psta->num_of_secdev_type; ++ pcur++; ++ ++ _rtw_memcpy(pcur, psta->secdev_types_list, psta->num_of_secdev_type*8); ++ pcur += psta->num_of_secdev_type*8; ++ ++ if(psta->dev_name_len>0) ++ { ++ //*(u16*)(pcur) = cpu_to_be16( WPS_ATTR_DEVICE_NAME ); ++ RTW_PUT_BE16(pcur, WPS_ATTR_DEVICE_NAME); ++ pcur += 2; ++ ++ //*(u16*)(pcur) = cpu_to_be16( psta->dev_name_len ); ++ RTW_PUT_BE16(pcur, psta->dev_name_len); ++ pcur += 2; ++ ++ _rtw_memcpy(pcur, psta->dev_name, psta->dev_name_len); ++ pcur += psta->dev_name_len; ++ } ++ ++ ++ tmplen = (u8)(pcur-pstart); ++ ++ *pstart = (tmplen-1); ++ ++ attr_len += tmplen; ++ ++ //pstart += tmplen; ++ pstart = pcur; ++ ++ } ++ ++ ++ } ++ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ if(attr_len>0) ++ { ++ len = rtw_set_p2p_attr_content(pbuf, P2P_ATTR_GROUP_INFO, attr_len, pdata_attr); ++ } ++ ++ rtw_mfree(pdata_attr, MAX_P2P_IE_LEN); ++ ++ return len; ++ ++} ++ ++static void issue_group_disc_req(struct wifidirect_info *pwdinfo, u8 *da) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ _adapter *padapter = pwdinfo->padapter; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ unsigned char category = RTW_WLAN_CATEGORY_P2P;//P2P action frame ++ u32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_GO_DISC_REQUEST; ++ u8 dialogToken=0; ++ ++ DBG_871X("[%s]\n", __FUNCTION__); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ //Build P2P action frame header ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); ++ ++ //there is no IE in this P2P action frame ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++} ++ ++static void issue_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ _adapter *padapter = pwdinfo->padapter; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ u32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_DEVDISC_RESP; ++ u8 p2pie[8] = { 0x00 }; ++ u32 p2pielen = 0; ++ ++ DBG_871X("[%s]\n", __FUNCTION__); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, pwdinfo->device_addr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, pwdinfo->device_addr, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ //Build P2P public action frame header ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); ++ ++ ++ //Build P2P IE ++ // P2P OUI ++ p2pielen = 0; ++ p2pie[ p2pielen++ ] = 0x50; ++ p2pie[ p2pielen++ ] = 0x6F; ++ p2pie[ p2pielen++ ] = 0x9A; ++ p2pie[ p2pielen++ ] = 0x09; // WFA P2P v1.0 ++ ++ // P2P_ATTR_STATUS ++ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status); ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &pattrib->pktlen); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++} ++ ++static void issue_p2p_provision_resp(struct wifidirect_info *pwdinfo, u8* raddr, u8* frame_body, u16 config_method) ++{ ++ _adapter *padapter = pwdinfo->padapter; ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ u8 dialogToken = frame_body[7]; // The Dialog Token of provisioning discovery request frame. ++ u32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_PROVISION_DISC_RESP; ++ u8 wpsie[ 100 ] = { 0x00 }; ++ u8 wpsielen = 0; ++#ifdef CONFIG_WFD ++ u32 wfdielen = 0; ++#endif //CONFIG_WFD ++ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); ++ ++ wpsielen = 0; ++ // WPS OUI ++ //*(u32*) ( wpsie ) = cpu_to_be32( WPSOUI ); ++ RTW_PUT_BE32(wpsie, WPSOUI); ++ wpsielen += 4; ++ ++#if 0 ++ // WPS version ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_VER1 ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0001 ); ++ wpsielen += 2; ++ ++ // Value: ++ wpsie[wpsielen++] = WPS_VERSION_1; // Version 1.0 ++#endif ++ ++ // Config Method ++ // Type: ++ //*(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_CONF_METHOD ); ++ RTW_PUT_BE16(wpsie + wpsielen, WPS_ATTR_CONF_METHOD); ++ wpsielen += 2; ++ ++ // Length: ++ //*(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0002 ); ++ RTW_PUT_BE16(wpsie + wpsielen, 0x0002); ++ wpsielen += 2; ++ ++ // Value: ++ //*(u16*) ( wpsie + wpsielen ) = cpu_to_be16( config_method ); ++ RTW_PUT_BE16(wpsie + wpsielen, config_method); ++ wpsielen += 2; ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen ); ++ ++#ifdef CONFIG_WFD ++ wfdielen = build_provdisc_resp_wfd_ie(pwdinfo, pframe); ++ pframe += wfdielen; ++ pattrib->pktlen += wfdielen; ++#endif //CONFIG_WFD ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++ return; ++ ++} ++ ++static void issue_p2p_presence_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ _adapter *padapter = pwdinfo->padapter; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ unsigned char category = RTW_WLAN_CATEGORY_P2P;//P2P action frame ++ u32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_PRESENCE_RESPONSE; ++ u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 }; ++ u8 noa_attr_content[32] = { 0x00 }; ++ u32 p2pielen = 0; ++ ++ DBG_871X("[%s]\n", __FUNCTION__); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ //Build P2P action frame header ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); ++ ++ ++ //Add P2P IE header ++ // P2P OUI ++ p2pielen = 0; ++ p2pie[ p2pielen++ ] = 0x50; ++ p2pie[ p2pielen++ ] = 0x6F; ++ p2pie[ p2pielen++ ] = 0x9A; ++ p2pie[ p2pielen++ ] = 0x09; // WFA P2P v1.0 ++ ++ //Add Status attribute in P2P IE ++ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status); ++ ++ //Add NoA attribute in P2P IE ++ noa_attr_content[0] = 0x1;//index ++ noa_attr_content[1] = 0x0;//CTWindow and OppPS Parameters ++ ++ //todo: Notice of Absence Descriptor(s) ++ ++ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_NOA, 2, noa_attr_content); ++ ++ ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &(pattrib->pktlen)); ++ ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++} ++ ++u32 build_beacon_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 }; ++ u16 capability=0; ++ u32 len=0, p2pielen = 0; ++ ++ ++ // P2P OUI ++ p2pielen = 0; ++ p2pie[ p2pielen++ ] = 0x50; ++ p2pie[ p2pielen++ ] = 0x6F; ++ p2pie[ p2pielen++ ] = 0x9A; ++ p2pie[ p2pielen++ ] = 0x09; // WFA P2P v1.0 ++ ++ ++ // According to the P2P Specification, the beacon frame should contain 3 P2P attributes ++ // 1. P2P Capability ++ // 2. P2P Device ID ++ // 3. Notice of Absence ( NOA ) ++ ++ // P2P Capability ATTR ++ // Type: ++ // Length: ++ // Value: ++ // Device Capability Bitmap, 1 byte ++ // Be able to participate in additional P2P Groups and ++ // support the P2P Invitation Procedure ++ // Group Capability Bitmap, 1 byte ++ capability = P2P_DEVCAP_INVITATION_PROC|P2P_DEVCAP_CLIENT_DISCOVERABILITY; ++ capability |= ((P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS) << 8); ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING)) ++ capability |= (P2P_GRPCAP_GROUP_FORMATION<<8); ++ ++ capability = cpu_to_le16(capability); ++ ++ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_CAPABILITY, 2, (u8*)&capability); ++ ++ ++ // P2P Device ID ATTR ++ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_DEVICE_ID, ETH_ALEN, pwdinfo->device_addr); ++ ++ ++ // Notice of Absence ATTR ++ // Type: ++ // Length: ++ // Value: ++ ++ //go_add_noa_attr(pwdinfo); ++ ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len); ++ ++ ++ return len; ++ ++} ++ ++#ifdef CONFIG_WFD ++u32 build_beacon_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; ++ u32 len=0, wfdielen = 0; ++ _adapter *padapter = pwdinfo->padapter; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; ++ ++ // WFD OUI ++ wfdielen = 0; ++ wfdie[ wfdielen++ ] = 0x50; ++ wfdie[ wfdielen++ ] = 0x6F; ++ wfdie[ wfdielen++ ] = 0x9A; ++ wfdie[ wfdielen++ ] = 0x0A; // WFA WFD v1.0 ++ ++ // Commented by Albert 20110812 ++ // According to the WFD Specification, the beacon frame should contain 4 WFD attributes ++ // 1. WFD Device Information ++ // 2. Associated BSSID ++ // 3. Coupled Sink Information ++ ++ ++ // WFD Device Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value1: ++ // WFD device information ++ ++ if ( P2P_ROLE_GO == pwdinfo->role ) ++ { ++ if ( is_any_client_associated( pwdinfo->padapter ) ) ++ { ++ // WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD ); ++ } ++ else ++ { ++ // WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD ); ++ } ++ ++ } ++ else ++ { ++ // WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD ); ++ } ++ ++ wfdielen += 2; ++ ++ // Value2: ++ // Session Management Control Port ++ // Default TCP port for RTSP messages is 554 ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport ); ++ wfdielen += 2; ++ ++ // Value3: ++ // WFD Device Maximum Throughput ++ // 300Mbps is the maximum throughput ++ RTW_PUT_BE16(wfdie + wfdielen, 300); ++ wfdielen += 2; ++ ++ // Associated BSSID ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value: ++ // Associated BSSID ++ if ( check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE ) ++ { ++ _rtw_memcpy( wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN ); ++ } ++ else ++ { ++ _rtw_memset( wfdie + wfdielen, 0x00, ETH_ALEN ); ++ } ++ ++ wfdielen += ETH_ALEN; ++ ++ // Coupled Sink Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0007); ++ wfdielen += 2; ++ ++ // Value: ++ // Coupled Sink Status bitmap ++ // Not coupled/available for Coupling ++ wfdie[ wfdielen++ ] = 0; ++ // MAC Addr. ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); ++ ++ return len; ++ ++} ++ ++u32 build_probe_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; ++ u32 len=0, wfdielen = 0; ++ _adapter *padapter = pwdinfo->padapter; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; ++ ++ // WFD OUI ++ wfdielen = 0; ++ wfdie[ wfdielen++ ] = 0x50; ++ wfdie[ wfdielen++ ] = 0x6F; ++ wfdie[ wfdielen++ ] = 0x9A; ++ wfdie[ wfdielen++ ] = 0x0A; // WFA WFD v1.0 ++ ++ // Commented by Albert 20110812 ++ // According to the WFD Specification, the probe request frame should contain 4 WFD attributes ++ // 1. WFD Device Information ++ // 2. Associated BSSID ++ // 3. Coupled Sink Information ++ ++ ++ // WFD Device Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value1: ++ // WFD device information ++ ++ if ( 1 == pwdinfo->wfd_tdls_enable ) ++ { ++ // WFD primary sink + available for WFD session + WiFi TDLS mode + WSC ( WFD Service Discovery ) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | ++ WFD_DEVINFO_SESSION_AVAIL | ++ WFD_DEVINFO_WSD | ++ WFD_DEVINFO_PC_TDLS ); ++ } ++ else ++ { ++ // WFD primary sink + available for WFD session + WiFi Direct mode + WSC ( WFD Service Discovery ) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | ++ WFD_DEVINFO_SESSION_AVAIL | ++ WFD_DEVINFO_WSD ); ++ } ++ ++ wfdielen += 2; ++ ++ // Value2: ++ // Session Management Control Port ++ // Default TCP port for RTSP messages is 554 ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport ); ++ wfdielen += 2; ++ ++ // Value3: ++ // WFD Device Maximum Throughput ++ // 300Mbps is the maximum throughput ++ RTW_PUT_BE16(wfdie + wfdielen, 300); ++ wfdielen += 2; ++ ++ // Associated BSSID ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value: ++ // Associated BSSID ++ if ( check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE ) ++ { ++ _rtw_memcpy( wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN ); ++ } ++ else ++ { ++ _rtw_memset( wfdie + wfdielen, 0x00, ETH_ALEN ); ++ } ++ ++ wfdielen += ETH_ALEN; ++ ++ // Coupled Sink Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0007); ++ wfdielen += 2; ++ ++ // Value: ++ // Coupled Sink Status bitmap ++ // Not coupled/available for Coupling ++ wfdie[ wfdielen++ ] = 0; ++ // MAC Addr. ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); ++ ++ return len; ++ ++} ++ ++u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunneled) ++{ ++ u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; ++ u32 len=0, wfdielen = 0; ++ _adapter *padapter = pwdinfo->padapter; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; ++ ++ // WFD OUI ++ wfdielen = 0; ++ wfdie[ wfdielen++ ] = 0x50; ++ wfdie[ wfdielen++ ] = 0x6F; ++ wfdie[ wfdielen++ ] = 0x9A; ++ wfdie[ wfdielen++ ] = 0x0A; // WFA WFD v1.0 ++ ++ // Commented by Albert 20110812 ++ // According to the WFD Specification, the probe response frame should contain 4 WFD attributes ++ // 1. WFD Device Information ++ // 2. Associated BSSID ++ // 3. Coupled Sink Information ++ // 4. WFD Session Information ++ ++ ++ // WFD Device Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value1: ++ // WFD device information ++ // WFD primary sink + available for WFD session + WiFi Direct mode ++ ++ if ( _TRUE == pwdinfo->session_available ) ++ { ++ if ( P2P_ROLE_GO == pwdinfo->role ) ++ { ++ if ( is_any_client_associated( pwdinfo->padapter ) ) ++ { ++ if ( pwdinfo->wfd_tdls_enable ) ++ { ++ // TDLS mode + WSD ( WFD Service Discovery ) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT); ++ } ++ else ++ { ++ // WiFi Direct mode + WSD ( WFD Service Discovery ) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT); ++ } ++ } ++ else ++ { ++ if ( pwdinfo->wfd_tdls_enable ) ++ { ++ // available for WFD session + TDLS mode + WSD ( WFD Service Discovery ) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT); ++ } ++ else ++ { ++ // available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT); ++ } ++ } ++ } ++ else ++ { ++ if ( pwdinfo->wfd_tdls_enable ) ++ { ++ // available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT); ++ } ++ else ++ { ++ ++ // available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT); ++ } ++ } ++ } ++ else ++ { ++ if ( pwdinfo->wfd_tdls_enable ) ++ { ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD |WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT); ++ } ++ else ++ { ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT); ++ } ++ ++ } ++ ++ wfdielen += 2; ++ ++ // Value2: ++ // Session Management Control Port ++ // Default TCP port for RTSP messages is 554 ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport ); ++ wfdielen += 2; ++ ++ // Value3: ++ // WFD Device Maximum Throughput ++ // 300Mbps is the maximum throughput ++ RTW_PUT_BE16(wfdie + wfdielen, 300); ++ wfdielen += 2; ++ ++ // Associated BSSID ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value: ++ // Associated BSSID ++ if ( check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE ) ++ { ++ _rtw_memcpy( wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN ); ++ } ++ else ++ { ++ _rtw_memset( wfdie + wfdielen, 0x00, ETH_ALEN ); ++ } ++ ++ wfdielen += ETH_ALEN; ++ ++ // Coupled Sink Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0007); ++ wfdielen += 2; ++ ++ // Value: ++ // Coupled Sink Status bitmap ++ // Not coupled/available for Coupling ++ wfdie[ wfdielen++ ] = 0; ++ // MAC Addr. ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ { ++ // WFD Session Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_SESSION_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0000); ++ wfdielen += 2; ++ ++ // Todo: to add the list of WFD device info descriptor in WFD group. ++ ++ } ++#ifdef CONFIG_CONCURRENT_MODE ++#ifdef CONFIG_TDLS ++ if ( ( tunneled == 0 ) && ( padapter->pbuddy_adapter->wdinfo.wfd_tdls_enable == 1 ) ) ++ { ++ // Alternative MAC Address ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_ALTER_MAC; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, ETH_ALEN ); ++ wfdielen += 2; ++ ++ // Value: ++ // Alternative MAC Address ++ _rtw_memcpy( wfdie + wfdielen, &padapter->pbuddy_adapter->eeprompriv.mac_addr[ 0 ], ETH_ALEN ); ++ // This mac address is used to make the WFD session when TDLS is enable. ++ ++ wfdielen += ETH_ALEN; ++ } ++#endif // CONFIG_TDLS ++#endif // CONFIG_CONCURRENT_MODE ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); ++ ++ return len; ++ ++} ++ ++u32 build_assoc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; ++ u32 len=0, wfdielen = 0; ++ _adapter *padapter = NULL; ++ struct mlme_priv *pmlmepriv = NULL; ++ struct wifi_display_info *pwfd_info = NULL; ++ ++ // WFD OUI ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) ++ { ++ return 0; ++ } ++ ++ padapter = pwdinfo->padapter; ++ pmlmepriv = &padapter->mlmepriv; ++ pwfd_info = padapter->wdinfo.wfd_info; ++ ++ wfdielen = 0; ++ wfdie[ wfdielen++ ] = 0x50; ++ wfdie[ wfdielen++ ] = 0x6F; ++ wfdie[ wfdielen++ ] = 0x9A; ++ wfdie[ wfdielen++ ] = 0x0A; // WFA WFD v1.0 ++ ++ // Commented by Albert 20110812 ++ // According to the WFD Specification, the probe request frame should contain 4 WFD attributes ++ // 1. WFD Device Information ++ // 2. Associated BSSID ++ // 3. Coupled Sink Information ++ ++ ++ // WFD Device Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value1: ++ // WFD device information ++ // WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD ); ++ wfdielen += 2; ++ ++ // Value2: ++ // Session Management Control Port ++ // Default TCP port for RTSP messages is 554 ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport ); ++ wfdielen += 2; ++ ++ // Value3: ++ // WFD Device Maximum Throughput ++ // 300Mbps is the maximum throughput ++ RTW_PUT_BE16(wfdie + wfdielen, 300); ++ wfdielen += 2; ++ ++ // Associated BSSID ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value: ++ // Associated BSSID ++ if ( check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE ) ++ { ++ _rtw_memcpy( wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN ); ++ } ++ else ++ { ++ _rtw_memset( wfdie + wfdielen, 0x00, ETH_ALEN ); ++ } ++ ++ wfdielen += ETH_ALEN; ++ ++ // Coupled Sink Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0007); ++ wfdielen += 2; ++ ++ // Value: ++ // Coupled Sink Status bitmap ++ // Not coupled/available for Coupling ++ wfdie[ wfdielen++ ] = 0; ++ // MAC Addr. ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); ++ ++ return len; ++ ++} ++ ++u32 build_assoc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; ++ u32 len=0, wfdielen = 0; ++ _adapter *padapter = pwdinfo->padapter; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; ++ ++ // WFD OUI ++ wfdielen = 0; ++ wfdie[ wfdielen++ ] = 0x50; ++ wfdie[ wfdielen++ ] = 0x6F; ++ wfdie[ wfdielen++ ] = 0x9A; ++ wfdie[ wfdielen++ ] = 0x0A; // WFA WFD v1.0 ++ ++ // Commented by Albert 20110812 ++ // According to the WFD Specification, the probe request frame should contain 4 WFD attributes ++ // 1. WFD Device Information ++ // 2. Associated BSSID ++ // 3. Coupled Sink Information ++ ++ ++ // WFD Device Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value1: ++ // WFD device information ++ // WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD ); ++ wfdielen += 2; ++ ++ // Value2: ++ // Session Management Control Port ++ // Default TCP port for RTSP messages is 554 ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport ); ++ wfdielen += 2; ++ ++ // Value3: ++ // WFD Device Maximum Throughput ++ // 300Mbps is the maximum throughput ++ RTW_PUT_BE16(wfdie + wfdielen, 300); ++ wfdielen += 2; ++ ++ // Associated BSSID ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value: ++ // Associated BSSID ++ if ( check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE ) ++ { ++ _rtw_memcpy( wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN ); ++ } ++ else ++ { ++ _rtw_memset( wfdie + wfdielen, 0x00, ETH_ALEN ); ++ } ++ ++ wfdielen += ETH_ALEN; ++ ++ // Coupled Sink Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0007); ++ wfdielen += 2; ++ ++ // Value: ++ // Coupled Sink Status bitmap ++ // Not coupled/available for Coupling ++ wfdie[ wfdielen++ ] = 0; ++ // MAC Addr. ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); ++ ++ return len; ++ ++} ++ ++u32 build_nego_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; ++ u32 len=0, wfdielen = 0; ++ _adapter *padapter = pwdinfo->padapter; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; ++ ++ // WFD OUI ++ wfdielen = 0; ++ wfdie[ wfdielen++ ] = 0x50; ++ wfdie[ wfdielen++ ] = 0x6F; ++ wfdie[ wfdielen++ ] = 0x9A; ++ wfdie[ wfdielen++ ] = 0x0A; // WFA WFD v1.0 ++ ++ // Commented by Albert 20110825 ++ // According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes ++ // 1. WFD Device Information ++ // 2. Associated BSSID ( Optional ) ++ // 3. Local IP Adress ( Optional ) ++ ++ ++ // WFD Device Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value1: ++ // WFD device information ++ // WFD primary sink + WiFi Direct mode + WSD ( WFD Service Discovery ) + WFD Session Available ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL); ++ wfdielen += 2; ++ ++ // Value2: ++ // Session Management Control Port ++ // Default TCP port for RTSP messages is 554 ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport ); ++ wfdielen += 2; ++ ++ // Value3: ++ // WFD Device Maximum Throughput ++ // 300Mbps is the maximum throughput ++ RTW_PUT_BE16(wfdie + wfdielen, 300); ++ wfdielen += 2; ++ ++ // Associated BSSID ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value: ++ // Associated BSSID ++ if ( check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE ) ++ { ++ _rtw_memcpy( wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN ); ++ } ++ else ++ { ++ _rtw_memset( wfdie + wfdielen, 0x00, ETH_ALEN ); ++ } ++ ++ wfdielen += ETH_ALEN; ++ ++ // Coupled Sink Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0007); ++ wfdielen += 2; ++ ++ // Value: ++ // Coupled Sink Status bitmap ++ // Not coupled/available for Coupling ++ wfdie[ wfdielen++ ] = 0; ++ // MAC Addr. ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); ++ ++ return len; ++ ++} ++ ++u32 build_nego_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; ++ u32 len=0, wfdielen = 0; ++ _adapter *padapter = pwdinfo->padapter; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; ++ ++ // WFD OUI ++ wfdielen = 0; ++ wfdie[ wfdielen++ ] = 0x50; ++ wfdie[ wfdielen++ ] = 0x6F; ++ wfdie[ wfdielen++ ] = 0x9A; ++ wfdie[ wfdielen++ ] = 0x0A; // WFA WFD v1.0 ++ ++ // Commented by Albert 20110825 ++ // According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes ++ // 1. WFD Device Information ++ // 2. Associated BSSID ( Optional ) ++ // 3. Local IP Adress ( Optional ) ++ ++ ++ // WFD Device Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value1: ++ // WFD device information ++ // WFD primary sink + WiFi Direct mode + WSD ( WFD Service Discovery ) + WFD Session Available ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL); ++ wfdielen += 2; ++ ++ // Value2: ++ // Session Management Control Port ++ // Default TCP port for RTSP messages is 554 ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport ); ++ wfdielen += 2; ++ ++ // Value3: ++ // WFD Device Maximum Throughput ++ // 300Mbps is the maximum throughput ++ RTW_PUT_BE16(wfdie + wfdielen, 300); ++ wfdielen += 2; ++ ++ // Associated BSSID ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value: ++ // Associated BSSID ++ if ( check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE ) ++ { ++ _rtw_memcpy( wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN ); ++ } ++ else ++ { ++ _rtw_memset( wfdie + wfdielen, 0x00, ETH_ALEN ); ++ } ++ ++ wfdielen += ETH_ALEN; ++ ++ // Coupled Sink Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0007); ++ wfdielen += 2; ++ ++ // Value: ++ // Coupled Sink Status bitmap ++ // Not coupled/available for Coupling ++ wfdie[ wfdielen++ ] = 0; ++ // MAC Addr. ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); ++ ++ return len; ++ ++} ++ ++u32 build_nego_confirm_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; ++ u32 len=0, wfdielen = 0; ++ _adapter *padapter = pwdinfo->padapter; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; ++ ++ // WFD OUI ++ wfdielen = 0; ++ wfdie[ wfdielen++ ] = 0x50; ++ wfdie[ wfdielen++ ] = 0x6F; ++ wfdie[ wfdielen++ ] = 0x9A; ++ wfdie[ wfdielen++ ] = 0x0A; // WFA WFD v1.0 ++ ++ // Commented by Albert 20110825 ++ // According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes ++ // 1. WFD Device Information ++ // 2. Associated BSSID ( Optional ) ++ // 3. Local IP Adress ( Optional ) ++ ++ ++ // WFD Device Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value1: ++ // WFD device information ++ // WFD primary sink + WiFi Direct mode + WSD ( WFD Service Discovery ) + WFD Session Available ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL); ++ wfdielen += 2; ++ ++ // Value2: ++ // Session Management Control Port ++ // Default TCP port for RTSP messages is 554 ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport ); ++ wfdielen += 2; ++ ++ // Value3: ++ // WFD Device Maximum Throughput ++ // 300Mbps is the maximum throughput ++ RTW_PUT_BE16(wfdie + wfdielen, 300); ++ wfdielen += 2; ++ ++ // Associated BSSID ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value: ++ // Associated BSSID ++ if ( check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE ) ++ { ++ _rtw_memcpy( wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN ); ++ } ++ else ++ { ++ _rtw_memset( wfdie + wfdielen, 0x00, ETH_ALEN ); ++ } ++ ++ wfdielen += ETH_ALEN; ++ ++ // Coupled Sink Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0007); ++ wfdielen += 2; ++ ++ // Value: ++ // Coupled Sink Status bitmap ++ // Not coupled/available for Coupling ++ wfdie[ wfdielen++ ] = 0; ++ // MAC Addr. ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); ++ ++ return len; ++ ++} ++ ++u32 build_invitation_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; ++ u32 len=0, wfdielen = 0; ++ _adapter *padapter = pwdinfo->padapter; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; ++ ++ // WFD OUI ++ wfdielen = 0; ++ wfdie[ wfdielen++ ] = 0x50; ++ wfdie[ wfdielen++ ] = 0x6F; ++ wfdie[ wfdielen++ ] = 0x9A; ++ wfdie[ wfdielen++ ] = 0x0A; // WFA WFD v1.0 ++ ++ // Commented by Albert 20110825 ++ // According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes ++ // 1. WFD Device Information ++ // 2. Associated BSSID ( Optional ) ++ // 3. Local IP Adress ( Optional ) ++ ++ ++ // WFD Device Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value1: ++ // WFD device information ++ // WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD ); ++ wfdielen += 2; ++ ++ // Value2: ++ // Session Management Control Port ++ // Default TCP port for RTSP messages is 554 ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport ); ++ wfdielen += 2; ++ ++ // Value3: ++ // WFD Device Maximum Throughput ++ // 300Mbps is the maximum throughput ++ RTW_PUT_BE16(wfdie + wfdielen, 300); ++ wfdielen += 2; ++ ++ // Associated BSSID ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value: ++ // Associated BSSID ++ if ( check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE ) ++ { ++ _rtw_memcpy( wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN ); ++ } ++ else ++ { ++ _rtw_memset( wfdie + wfdielen, 0x00, ETH_ALEN ); ++ } ++ ++ wfdielen += ETH_ALEN; ++ ++ // Coupled Sink Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0007); ++ wfdielen += 2; ++ ++ // Value: ++ // Coupled Sink Status bitmap ++ // Not coupled/available for Coupling ++ wfdie[ wfdielen++ ] = 0; ++ // MAC Addr. ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ ++ if ( P2P_ROLE_GO == pwdinfo->role ) ++ { ++ // WFD Session Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_SESSION_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0000); ++ wfdielen += 2; ++ ++ // Todo: to add the list of WFD device info descriptor in WFD group. ++ ++ } ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); ++ ++ return len; ++ ++} ++ ++u32 build_invitation_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; ++ u32 len=0, wfdielen = 0; ++ _adapter *padapter = pwdinfo->padapter; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; ++ ++ // WFD OUI ++ wfdielen = 0; ++ wfdie[ wfdielen++ ] = 0x50; ++ wfdie[ wfdielen++ ] = 0x6F; ++ wfdie[ wfdielen++ ] = 0x9A; ++ wfdie[ wfdielen++ ] = 0x0A; // WFA WFD v1.0 ++ ++ // Commented by Albert 20110825 ++ // According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes ++ // 1. WFD Device Information ++ // 2. Associated BSSID ( Optional ) ++ // 3. Local IP Adress ( Optional ) ++ ++ ++ // WFD Device Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value1: ++ // WFD device information ++ // WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD ); ++ wfdielen += 2; ++ ++ // Value2: ++ // Session Management Control Port ++ // Default TCP port for RTSP messages is 554 ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport ); ++ wfdielen += 2; ++ ++ // Value3: ++ // WFD Device Maximum Throughput ++ // 300Mbps is the maximum throughput ++ RTW_PUT_BE16(wfdie + wfdielen, 300); ++ wfdielen += 2; ++ ++ // Associated BSSID ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value: ++ // Associated BSSID ++ if ( check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE ) ++ { ++ _rtw_memcpy( wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN ); ++ } ++ else ++ { ++ _rtw_memset( wfdie + wfdielen, 0x00, ETH_ALEN ); ++ } ++ ++ wfdielen += ETH_ALEN; ++ ++ // Coupled Sink Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0007); ++ wfdielen += 2; ++ ++ // Value: ++ // Coupled Sink Status bitmap ++ // Not coupled/available for Coupling ++ wfdie[ wfdielen++ ] = 0; ++ // MAC Addr. ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ ++ if ( P2P_ROLE_GO == pwdinfo->role ) ++ { ++ // WFD Session Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_SESSION_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0000); ++ wfdielen += 2; ++ ++ // Todo: to add the list of WFD device info descriptor in WFD group. ++ ++ } ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); ++ ++ return len; ++ ++} ++ ++u32 build_provdisc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; ++ u32 len=0, wfdielen = 0; ++ _adapter *padapter = pwdinfo->padapter; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; ++ ++ // WFD OUI ++ wfdielen = 0; ++ wfdie[ wfdielen++ ] = 0x50; ++ wfdie[ wfdielen++ ] = 0x6F; ++ wfdie[ wfdielen++ ] = 0x9A; ++ wfdie[ wfdielen++ ] = 0x0A; // WFA WFD v1.0 ++ ++ // Commented by Albert 20110825 ++ // According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes ++ // 1. WFD Device Information ++ // 2. Associated BSSID ( Optional ) ++ // 3. Local IP Adress ( Optional ) ++ ++ ++ // WFD Device Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value1: ++ // WFD device information ++ // WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD ); ++ wfdielen += 2; ++ ++ // Value2: ++ // Session Management Control Port ++ // Default TCP port for RTSP messages is 554 ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport ); ++ wfdielen += 2; ++ ++ // Value3: ++ // WFD Device Maximum Throughput ++ // 300Mbps is the maximum throughput ++ RTW_PUT_BE16(wfdie + wfdielen, 300); ++ wfdielen += 2; ++ ++ // Associated BSSID ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value: ++ // Associated BSSID ++ if ( check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE ) ++ { ++ _rtw_memcpy( wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN ); ++ } ++ else ++ { ++ _rtw_memset( wfdie + wfdielen, 0x00, ETH_ALEN ); ++ } ++ ++ wfdielen += ETH_ALEN; ++ ++ // Coupled Sink Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0007); ++ wfdielen += 2; ++ ++ // Value: ++ // Coupled Sink Status bitmap ++ // Not coupled/available for Coupling ++ wfdie[ wfdielen++ ] = 0; ++ // MAC Addr. ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); ++ ++ return len; ++ ++} ++ ++u32 build_provdisc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; ++ u32 len=0, wfdielen = 0; ++ _adapter *padapter = pwdinfo->padapter; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; ++ ++ // WFD OUI ++ wfdielen = 0; ++ wfdie[ wfdielen++ ] = 0x50; ++ wfdie[ wfdielen++ ] = 0x6F; ++ wfdie[ wfdielen++ ] = 0x9A; ++ wfdie[ wfdielen++ ] = 0x0A; // WFA WFD v1.0 ++ ++ // Commented by Albert 20110825 ++ // According to the WFD Specification, the provision discovery response frame should contain 3 WFD attributes ++ // 1. WFD Device Information ++ // 2. Associated BSSID ( Optional ) ++ // 3. Local IP Adress ( Optional ) ++ ++ ++ // WFD Device Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value1: ++ // WFD device information ++ // WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD ); ++ wfdielen += 2; ++ ++ // Value2: ++ // Session Management Control Port ++ // Default TCP port for RTSP messages is 554 ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport ); ++ wfdielen += 2; ++ ++ // Value3: ++ // WFD Device Maximum Throughput ++ // 300Mbps is the maximum throughput ++ RTW_PUT_BE16(wfdie + wfdielen, 300); ++ wfdielen += 2; ++ ++ // Associated BSSID ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value: ++ // Associated BSSID ++ if ( check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE ) ++ { ++ _rtw_memcpy( wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN ); ++ } ++ else ++ { ++ _rtw_memset( wfdie + wfdielen, 0x00, ETH_ALEN ); ++ } ++ ++ wfdielen += ETH_ALEN; ++ ++ // Coupled Sink Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0007); ++ wfdielen += 2; ++ ++ // Value: ++ // Coupled Sink Status bitmap ++ // Not coupled/available for Coupling ++ wfdie[ wfdielen++ ] = 0; ++ // MAC Addr. ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ wfdie[ wfdielen++ ] = 0; ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); ++ ++ return len; ++ ++} ++ ++ ++#endif //CONFIG_WFD ++ ++u32 build_probe_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 }; ++ u32 len=0, p2pielen = 0; ++#ifdef CONFIG_INTEL_WIDI ++ struct mlme_priv *pmlmepriv = &(pwdinfo->padapter->mlmepriv); ++ u8 zero_array_check[L2SDTA_SERVICE_VE_LEN] = { 0x00 }; ++ u8 widi_version = 0, i = 0; ++ ++ if( _rtw_memcmp( pmlmepriv->sa_ext, zero_array_check, L2SDTA_SERVICE_VE_LEN ) == _FALSE ) ++ { ++ widi_version = 35; ++ } ++ else if( pmlmepriv->num_p2p_sdt != 0 ) ++ { ++ widi_version = 40; ++ } ++#endif //CONFIG_INTEL_WIDI ++ ++ // P2P OUI ++ p2pielen = 0; ++ p2pie[ p2pielen++ ] = 0x50; ++ p2pie[ p2pielen++ ] = 0x6F; ++ p2pie[ p2pielen++ ] = 0x9A; ++ p2pie[ p2pielen++ ] = 0x09; // WFA P2P v1.0 ++ ++ // Commented by Albert 20100907 ++ // According to the P2P Specification, the probe response frame should contain 5 P2P attributes ++ // 1. P2P Capability ++ // 2. Extended Listen Timing ++ // 3. Notice of Absence ( NOA ) ( Only GO needs this ) ++ // 4. Device Info ++ // 5. Group Info ( Only GO need this ) ++ ++ // P2P Capability ATTR ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_CAPABILITY; ++ ++ // Length: ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); ++ RTW_PUT_LE16(p2pie + p2pielen, 0x0002); ++ p2pielen += 2; ++ ++ // Value: ++ // Device Capability Bitmap, 1 byte ++ p2pie[ p2pielen++ ] = DMP_P2P_DEVCAP_SUPPORT; ++ ++ // Group Capability Bitmap, 1 byte ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ { ++ p2pie[ p2pielen ] = (P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS); ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING)) ++ p2pie[ p2pielen ] |= P2P_GRPCAP_GROUP_FORMATION; ++ ++ p2pielen++; ++ } ++ else if ( rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) ) ++ { ++ // Group Capability Bitmap, 1 byte ++ if ( pwdinfo->persistent_supported ) ++ p2pie[ p2pielen++ ] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; ++ else ++ p2pie[ p2pielen++ ] = DMP_P2P_GRPCAP_SUPPORT; ++ } ++ ++ // Extended Listen Timing ATTR ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_EX_LISTEN_TIMING; ++ ++ // Length: ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0004 ); ++ RTW_PUT_LE16(p2pie + p2pielen, 0x0004); ++ p2pielen += 2; ++ ++ // Value: ++ // Availability Period ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0xFFFF ); ++ RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF); ++ p2pielen += 2; ++ ++ // Availability Interval ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0xFFFF ); ++ RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF); ++ p2pielen += 2; ++ ++ ++ // Notice of Absence ATTR ++ // Type: ++ // Length: ++ // Value: ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ { ++ //go_add_noa_attr(pwdinfo); ++ } ++ ++ // Device Info ATTR ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) ++ // + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 21 + pwdinfo->device_name_len ); ++#ifdef CONFIG_INTEL_WIDI ++ if( widi_version == 35 ) ++ { ++ RTW_PUT_LE16(p2pie + p2pielen, 21 + 8 + pwdinfo->device_name_len); ++ } ++ else if( widi_version == 40 ) ++ { ++ RTW_PUT_LE16(p2pie + p2pielen, 21 + 8 * pmlmepriv->num_p2p_sdt + pwdinfo->device_name_len); ++ } ++ else ++#endif //CONFIG_INTEL_WIDI ++ RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len); ++ p2pielen += 2; ++ ++ // Value: ++ // P2P Device Address ++ _rtw_memcpy( p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN ); ++ p2pielen += ETH_ALEN; ++ ++ // Config Method ++ // This field should be big endian. Noted by P2P specification. ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_be16( pwdinfo->supported_wps_cm ); ++ RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->supported_wps_cm); ++ p2pielen += 2; ++ ++#ifdef CONFIG_INTEL_WIDI ++ if( widi_version == 40 ) ++ { ++ // Primary Device Type ++ // Category ID ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_CID_MULIT_MEDIA ); ++ RTW_PUT_BE16(p2pie + p2pielen, pmlmepriv->p2p_pdt_cid ); ++ p2pielen += 2; ++ ++ // OUI ++ //*(u32*) ( p2pie + p2pielen ) = cpu_to_be32( WPSOUI ); ++ RTW_PUT_BE32(p2pie + p2pielen, WPSOUI); ++ p2pielen += 4; ++ ++ // Sub Category ID ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_SCID_MEDIA_SERVER ); ++ RTW_PUT_BE16(p2pie + p2pielen, pmlmepriv->p2p_pdt_scid); ++ p2pielen += 2; ++ } ++ else ++#endif //CONFIG_INTEL_WIDI ++ { ++ // Primary Device Type ++ // Category ID ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_CID_MULIT_MEDIA ); ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA); ++ p2pielen += 2; ++ ++ // OUI ++ //*(u32*) ( p2pie + p2pielen ) = cpu_to_be32( WPSOUI ); ++ RTW_PUT_BE32(p2pie + p2pielen, WPSOUI); ++ p2pielen += 4; ++ ++ // Sub Category ID ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_SCID_MEDIA_SERVER ); ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER); ++ p2pielen += 2; ++ } ++ ++ // Number of Secondary Device Types ++#ifdef CONFIG_INTEL_WIDI ++ if( widi_version == 35 ) ++ { ++ p2pie[ p2pielen++ ] = 0x01; ++ ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_DISPLAYS); ++ p2pielen += 2; ++ ++ RTW_PUT_BE32(p2pie + p2pielen, INTEL_DEV_TYPE_OUI); ++ p2pielen += 4; ++ ++ RTW_PUT_BE16(p2pie + p2pielen, P2P_SCID_WIDI_CONSUMER_SINK); ++ p2pielen += 2; ++ } ++ else if( widi_version == 40 ) ++ { ++ p2pie[ p2pielen++ ] = pmlmepriv->num_p2p_sdt; ++ for( ; i < pmlmepriv->num_p2p_sdt; i++ ) ++ { ++ RTW_PUT_BE16(p2pie + p2pielen, pmlmepriv->p2p_sdt_cid[i]); ++ p2pielen += 2; ++ ++ RTW_PUT_BE32(p2pie + p2pielen, INTEL_DEV_TYPE_OUI); ++ p2pielen += 4; ++ ++ RTW_PUT_BE16(p2pie + p2pielen, pmlmepriv->p2p_sdt_scid[i]); ++ p2pielen += 2; ++ } ++ } ++ else ++#endif //CONFIG_INTEL_WIDI ++ p2pie[ p2pielen++ ] = 0x00; // No Secondary Device Type List ++ ++ // Device Name ++ // Type: ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_ATTR_DEVICE_NAME ); ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME); ++ p2pielen += 2; ++ ++ // Length: ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_be16( pwdinfo->device_name_len ); ++ RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len); ++ p2pielen += 2; ++ ++ // Value: ++ _rtw_memcpy( p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len ); ++ p2pielen += pwdinfo->device_name_len; ++ ++ // Group Info ATTR ++ // Type: ++ // Length: ++ // Value: ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ { ++ p2pielen += go_add_group_info_attr(pwdinfo, p2pie + p2pielen); ++ } ++ ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len); ++ ++ ++ return len; ++ ++} ++ ++u32 build_prov_disc_request_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8* pssid, u8 ussidlen, u8* pdev_raddr ) ++{ ++ u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 }; ++ u32 len=0, p2pielen = 0; ++ ++ // P2P OUI ++ p2pielen = 0; ++ p2pie[ p2pielen++ ] = 0x50; ++ p2pie[ p2pielen++ ] = 0x6F; ++ p2pie[ p2pielen++ ] = 0x9A; ++ p2pie[ p2pielen++ ] = 0x09; // WFA P2P v1.0 ++ ++ // Commented by Albert 20110301 ++ // According to the P2P Specification, the provision discovery request frame should contain 3 P2P attributes ++ // 1. P2P Capability ++ // 2. Device Info ++ // 3. Group ID ( When joining an operating P2P Group ) ++ ++ // P2P Capability ATTR ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_CAPABILITY; ++ ++ // Length: ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); ++ RTW_PUT_LE16(p2pie + p2pielen, 0x0002); ++ p2pielen += 2; ++ ++ // Value: ++ // Device Capability Bitmap, 1 byte ++ p2pie[ p2pielen++ ] = DMP_P2P_DEVCAP_SUPPORT; ++ ++ // Group Capability Bitmap, 1 byte ++ if ( pwdinfo->persistent_supported ) ++ p2pie[ p2pielen++ ] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; ++ else ++ p2pie[ p2pielen++ ] = DMP_P2P_GRPCAP_SUPPORT; ++ ++ ++ // Device Info ATTR ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) ++ // + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 21 + pwdinfo->device_name_len ); ++ RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len); ++ p2pielen += 2; ++ ++ // Value: ++ // P2P Device Address ++ _rtw_memcpy( p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN ); ++ p2pielen += ETH_ALEN; ++ ++ // Config Method ++ // This field should be big endian. Noted by P2P specification. ++ if ( pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC ) ++ { ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_CONFIG_METHOD_PBC ); ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_PBC); ++ } ++ else ++ { ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_CONFIG_METHOD_DISPLAY ); ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_DISPLAY); ++ } ++ ++ p2pielen += 2; ++ ++ // Primary Device Type ++ // Category ID ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_CID_MULIT_MEDIA ); ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA); ++ p2pielen += 2; ++ ++ // OUI ++ //*(u32*) ( p2pie + p2pielen ) = cpu_to_be32( WPSOUI ); ++ RTW_PUT_BE32(p2pie + p2pielen, WPSOUI); ++ p2pielen += 4; ++ ++ // Sub Category ID ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_SCID_MEDIA_SERVER ); ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER); ++ p2pielen += 2; ++ ++ // Number of Secondary Device Types ++ p2pie[ p2pielen++ ] = 0x00; // No Secondary Device Type List ++ ++ // Device Name ++ // Type: ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_ATTR_DEVICE_NAME ); ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME); ++ p2pielen += 2; ++ ++ // Length: ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_be16( pwdinfo->device_name_len ); ++ RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len); ++ p2pielen += 2; ++ ++ // Value: ++ _rtw_memcpy( p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len ); ++ p2pielen += pwdinfo->device_name_len; ++ ++ if ( rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) ) ++ { ++ // Added by Albert 2011/05/19 ++ // In this case, the pdev_raddr is the device address of the group owner. ++ ++ // P2P Group ID ATTR ++ // Type: ++ p2pie[ p2pielen++ ] = P2P_ATTR_GROUP_ID; ++ ++ // Length: ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_le16( ETH_ALEN + ussidlen ); ++ RTW_PUT_LE16(p2pie + p2pielen, ETH_ALEN + ussidlen); ++ p2pielen += 2; ++ ++ // Value: ++ _rtw_memcpy( p2pie + p2pielen, pdev_raddr, ETH_ALEN ); ++ p2pielen += ETH_ALEN; ++ ++ _rtw_memcpy( p2pie + p2pielen, pssid, ussidlen ); ++ p2pielen += ussidlen; ++ ++ } ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len); ++ ++ ++ return len; ++ ++} ++ ++ ++u32 build_assoc_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 status_code) ++{ ++ u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 }; ++ u32 len=0, p2pielen = 0; ++ ++ // P2P OUI ++ p2pielen = 0; ++ p2pie[ p2pielen++ ] = 0x50; ++ p2pie[ p2pielen++ ] = 0x6F; ++ p2pie[ p2pielen++ ] = 0x9A; ++ p2pie[ p2pielen++ ] = 0x09; // WFA P2P v1.0 ++ ++ // According to the P2P Specification, the Association response frame should contain 2 P2P attributes ++ // 1. Status ++ // 2. Extended Listen Timing (optional) ++ ++ ++ // Status ATTR ++ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status_code); ++ ++ ++ // Extended Listen Timing ATTR ++ // Type: ++ // Length: ++ // Value: ++ ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len); ++ ++ return len; ++ ++} ++ ++u32 build_deauth_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u32 len=0; ++ ++ return len; ++} ++ ++u32 process_probe_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) ++{ ++ u8 *p; ++ u32 ret=_FALSE; ++ u8 *p2pie; ++ u32 p2pielen = 0; ++ int ssid_len=0, rate_cnt = 0; ++ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SUPPORTEDRATES_IE_, (int *)&rate_cnt, ++ len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); ++ ++ if ( rate_cnt <= 4 ) ++ { ++ int i, g_rate =0; ++ ++ for( i = 0; i < rate_cnt; i++ ) ++ { ++ if ( ( ( *( p + 2 + i ) & 0xff ) != 0x02 ) && ++ ( ( *( p + 2 + i ) & 0xff ) != 0x04 ) && ++ ( ( *( p + 2 + i ) & 0xff ) != 0x0B ) && ++ ( ( *( p + 2 + i ) & 0xff ) != 0x16 ) ) ++ { ++ g_rate = 1; ++ } ++ } ++ ++ if ( g_rate == 0 ) ++ { ++ // There is no OFDM rate included in SupportedRates IE of this probe request frame ++ // The driver should response this probe request. ++ return ret; ++ } ++ } ++ else ++ { ++ // rate_cnt > 4 means the SupportRates IE contains the OFDM rate because the count of CCK rates are 4. ++ // We should proceed the following check for this probe request. ++ } ++ ++ // Added comments by Albert 20100906 ++ // There are several items we should check here. ++ // 1. This probe request frame must contain the P2P IE. (Done) ++ // 2. This probe request frame must contain the wildcard SSID. (Done) ++ // 3. Wildcard BSSID. (Todo) ++ // 4. Destination Address. ( Done in mgt_dispatcher function ) ++ // 5. Requested Device Type in WSC IE. (Todo) ++ // 6. Device ID attribute in P2P IE. (Todo) ++ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ssid_len, ++ len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); ++ ++ ssid_len &= 0xff; // Just last 1 byte is valid for ssid len of the probe request ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ { ++ if((p2pie=rtw_get_p2p_ie( pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_ , len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_ , NULL, &p2pielen))) ++ { ++ if ( (p != NULL) && _rtw_memcmp( ( void * ) ( p+2 ), ( void * ) pwdinfo->p2p_wildcard_ssid , 7 )) ++ { ++ //todo: ++ //Check Requested Device Type attributes in WSC IE. ++ //Check Device ID attribute in P2P IE ++ ++ ret = _TRUE; ++ } ++ else if ( (p != NULL) && ( ssid_len == 0 ) ) ++ { ++ ret = _TRUE; ++ } ++ } ++ else ++ { ++ //non -p2p device ++ } ++ ++ } ++ ++ ++ return ret; ++ ++} ++ ++u32 process_assoc_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint len, struct sta_info *psta) ++{ ++ u8 status_code = P2P_STATUS_SUCCESS; ++ u8 *pbuf, *pattr_content=NULL; ++ u32 attr_contentlen = 0; ++ u16 cap_attr=0; ++ unsigned short frame_type, ie_offset=0; ++ u8 * ies; ++ u32 ies_len; ++ u8 * p2p_ie; ++ u32 p2p_ielen = 0; ++ ++ if(!rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ return P2P_STATUS_FAIL_REQUEST_UNABLE; ++ ++ frame_type = GetFrameSubType(pframe); ++ if (frame_type == WIFI_ASSOCREQ) ++ { ++ ie_offset = _ASOCREQ_IE_OFFSET_; ++ } ++ else // WIFI_REASSOCREQ ++ { ++ ie_offset = _REASOCREQ_IE_OFFSET_; ++ } ++ ++ ies = pframe + WLAN_HDR_A3_LEN + ie_offset; ++ ies_len = len - WLAN_HDR_A3_LEN - ie_offset; ++ ++ p2p_ie = rtw_get_p2p_ie(ies , ies_len , NULL, &p2p_ielen); ++ ++ if ( !p2p_ie ) ++ { ++ DBG_8192C( "[%s] P2P IE not Found!!\n", __FUNCTION__ ); ++ status_code = P2P_STATUS_FAIL_INVALID_PARAM; ++ } ++ else ++ { ++ DBG_8192C( "[%s] P2P IE Found!!\n", __FUNCTION__ ); ++ } ++ ++ while ( p2p_ie ) ++ { ++ //Check P2P Capability ATTR ++ if( rtw_get_p2p_attr_content( p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8*)&cap_attr, (uint*) &attr_contentlen) ) ++ { ++ DBG_8192C( "[%s] Got P2P Capability Attr!!\n", __FUNCTION__ ); ++ cap_attr = le16_to_cpu(cap_attr); ++ psta->dev_cap = cap_attr&0xff; ++ } ++ ++ //Check Extended Listen Timing ATTR ++ ++ ++ //Check P2P Device Info ATTR ++ if(rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO, NULL, (uint*)&attr_contentlen)) ++ { ++ DBG_8192C( "[%s] Got P2P DEVICE INFO Attr!!\n", __FUNCTION__ ); ++ pattr_content = pbuf = rtw_zmalloc(attr_contentlen); ++ if(pattr_content) ++ { ++ u8 num_of_secdev_type; ++ u16 dev_name_len; ++ ++ ++ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO , pattr_content, (uint*)&attr_contentlen); ++ ++ _rtw_memcpy(psta->dev_addr, pattr_content, ETH_ALEN);//P2P Device Address ++ ++ pattr_content += ETH_ALEN; ++ ++ _rtw_memcpy(&psta->config_methods, pattr_content, 2);//Config Methods ++ psta->config_methods = be16_to_cpu(psta->config_methods); ++ ++ pattr_content += 2; ++ ++ _rtw_memcpy(psta->primary_dev_type, pattr_content, 8); ++ ++ pattr_content += 8; ++ ++ num_of_secdev_type = *pattr_content; ++ pattr_content += 1; ++ ++ if(num_of_secdev_type==0) ++ { ++ psta->num_of_secdev_type = 0; ++ } ++ else ++ { ++ u32 len; ++ ++ psta->num_of_secdev_type = num_of_secdev_type; ++ ++ len = (sizeof(psta->secdev_types_list)<(num_of_secdev_type*8)) ? (sizeof(psta->secdev_types_list)) : (num_of_secdev_type*8); ++ ++ _rtw_memcpy(psta->secdev_types_list, pattr_content, len); ++ ++ pattr_content += (num_of_secdev_type*8); ++ } ++ ++ ++ //dev_name_len = attr_contentlen - ETH_ALEN - 2 - 8 - 1 - (num_of_secdev_type*8); ++ psta->dev_name_len=0; ++ if(WPS_ATTR_DEVICE_NAME == be16_to_cpu(*(u16*)pattr_content)) ++ { ++ dev_name_len = be16_to_cpu(*(u16*)(pattr_content+2)); ++ ++ psta->dev_name_len = (sizeof(psta->dev_name)dev_name):dev_name_len; ++ ++ _rtw_memcpy(psta->dev_name, pattr_content+4, psta->dev_name_len); ++ } ++ ++ rtw_mfree(pbuf, attr_contentlen); ++ ++ } ++ ++ } ++ ++ //Get the next P2P IE ++ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); ++ ++ } ++ ++ return status_code; ++ ++} ++ ++u32 process_p2p_devdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) ++{ ++ u8 *frame_body; ++ u8 status, dialogToken; ++ struct sta_info *psta = NULL; ++ _adapter *padapter = pwdinfo->padapter; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 *p2p_ie; ++ u32 p2p_ielen = 0; ++ ++ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ ++ dialogToken = frame_body[7]; ++ status = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP; ++ ++ if ( (p2p_ie=rtw_get_p2p_ie( frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen)) ) ++ { ++ u8 groupid[ 38 ] = { 0x00 }; ++ u8 dev_addr[ETH_ALEN] = { 0x00 }; ++ u32 attr_contentlen = 0; ++ ++ if(rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) ++ { ++ if(_rtw_memcmp(pwdinfo->device_addr, groupid, ETH_ALEN) && ++ _rtw_memcmp(pwdinfo->p2p_group_ssid, groupid+ETH_ALEN, pwdinfo->p2p_group_ssid_len)) ++ { ++ attr_contentlen=0; ++ if(rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_ID, dev_addr, &attr_contentlen)) ++ { ++ _irqL irqL; ++ _list *phead, *plist; ++ ++ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ ++ //look up sta asoc_queue ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ ++ plist = get_next(plist); ++ ++ if(psta->is_p2p_device && (psta->dev_cap&P2P_DEVCAP_CLIENT_DISCOVERABILITY) && ++ _rtw_memcmp(psta->dev_addr, dev_addr, ETH_ALEN)) ++ { ++ ++ //_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ //issue GO Discoverability Request ++ issue_group_disc_req(pwdinfo, psta->hwaddr); ++ //_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ status = P2P_STATUS_SUCCESS; ++ ++ break; ++ } ++ else ++ { ++ status = P2P_STATUS_FAIL_INFO_UNAVAILABLE; ++ } ++ ++ } ++ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ } ++ else ++ { ++ status = P2P_STATUS_FAIL_INVALID_PARAM; ++ } ++ ++ } ++ else ++ { ++ status = P2P_STATUS_FAIL_INVALID_PARAM; ++ } ++ ++ } ++ ++ } ++ ++ ++ //issue Device Discoverability Response ++ issue_p2p_devdisc_resp(pwdinfo, GetAddr2Ptr(pframe), status, dialogToken); ++ ++ ++ return (status==P2P_STATUS_SUCCESS) ? _TRUE:_FALSE; ++ ++} ++ ++u32 process_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) ++{ ++ return _TRUE; ++} ++ ++u8 process_p2p_provdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len ) ++{ ++ u8 *frame_body; ++ u8 *wpsie; ++ uint wps_ielen = 0, attr_contentlen = 0; ++ u16 uconfig_method = 0; ++ ++ ++ frame_body = (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ ++ if ( (wpsie=rtw_get_wps_ie( frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen)) ) ++ { ++ if ( rtw_get_wps_attr_content( wpsie, wps_ielen, WPS_ATTR_CONF_METHOD , ( u8* ) &uconfig_method, &attr_contentlen) ) ++ { ++ uconfig_method = be16_to_cpu( uconfig_method ); ++ switch( uconfig_method ) ++ { ++ case WPS_CM_DISPLYA: ++ { ++ _rtw_memcpy( pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3 ); ++ break; ++ } ++ case WPS_CM_LABEL: ++ { ++ _rtw_memcpy( pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "lab", 3 ); ++ break; ++ } ++ case WPS_CM_PUSH_BUTTON: ++ { ++ _rtw_memcpy( pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3 ); ++ break; ++ } ++ case WPS_CM_KEYPAD: ++ { ++ _rtw_memcpy( pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3 ); ++ break; ++ } ++ } ++ issue_p2p_provision_resp( pwdinfo, GetAddr2Ptr(pframe), frame_body, uconfig_method); ++ } ++ } ++ DBG_871X( "[%s] config method = %s\n", __FUNCTION__, pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req ); ++ return _TRUE; ++ ++} ++ ++u8 process_p2p_provdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe) ++{ ++ ++ return _TRUE; ++} ++ ++u8 rtw_p2p_get_peer_ch_list(struct wifidirect_info *pwdinfo, u8 *ch_content, u8 ch_cnt, u8 *peer_ch_list) ++{ ++ u8 i = 0, j = 0; ++ u8 temp = 0; ++ u8 ch_no = 0; ++ ch_content += 3; ++ ch_cnt -= 3; ++ ++ while( ch_cnt > 0) ++ { ++ ch_content += 1; ++ ch_cnt -= 1; ++ temp = *ch_content; ++ for( i = 0 ; i < temp ; i++, j++ ) ++ { ++ peer_ch_list[j] = *( ch_content + 1 + i ); ++ } ++ ch_content += (temp + 1); ++ ch_cnt -= (temp + 1); ++ ch_no += temp ; ++ } ++ ++ return ch_no; ++} ++ ++u8 rtw_p2p_check_peer_oper_ch(struct mlme_ext_priv *pmlmeext, u8 ch) ++{ ++ u8 i = 0; ++ ++ for( i = 0; i < pmlmeext->max_chan_nums; i++ ) ++ { ++ if ( pmlmeext->channel_set[ i ].ChannelNum == ch ) ++ { ++ return _SUCCESS; ++ } ++ } ++ ++ return _FAIL; ++} ++ ++u8 rtw_p2p_ch_inclusion(struct mlme_ext_priv *pmlmeext, u8 *peer_ch_list, u8 peer_ch_num, u8 *ch_list_inclusioned) ++{ ++ int i = 0, j = 0, temp = 0; ++ u8 ch_no = 0; ++ ++ for( i = 0; i < peer_ch_num; i++ ) ++ { ++ for( j = temp; j < pmlmeext->max_chan_nums; j++ ) ++ { ++ if( *( peer_ch_list + i ) == pmlmeext->channel_set[ j ].ChannelNum ) ++ { ++ ch_list_inclusioned[ ch_no++ ] = *( peer_ch_list + i ); ++ temp = j; ++ break; ++ } ++ } ++ } ++ ++ return ch_no; ++} ++ ++u8 process_p2p_group_negotation_req( struct wifidirect_info *pwdinfo, u8 *pframe, uint len ) ++{ ++ _adapter *padapter = pwdinfo->padapter; ++ u8 result = P2P_STATUS_SUCCESS; ++ u32 p2p_ielen = 0, wps_ielen = 0; ++ u8 * ies; ++ u32 ies_len; ++ u8 *p2p_ie; ++ u8 *wpsie; ++ u16 wps_devicepassword_id = 0x0000; ++ uint wps_devicepassword_id_len = 0; ++#ifdef CONFIG_WFD ++ u8 wfd_ie[ 128 ] = { 0x00 }; ++ u32 wfd_ielen = 0; ++#ifdef CONFIG_TDLS ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++#endif // CONFIG_TDLS ++#endif // CONFIG_WFD ++#ifdef CONFIG_CONCURRENT_MODE ++ _adapter *pbuddy_adapter = pwdinfo->padapter->pbuddy_adapter; ++ struct wifidirect_info *pbuddy_wdinfo = &pbuddy_adapter->wdinfo; ++ struct mlme_priv *pbuddy_mlmepriv = &pbuddy_adapter->mlmepriv; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++#endif ++ ++ if ( (wpsie=rtw_get_wps_ie( pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen)) ) ++ { ++ // Commented by Kurt 20120113 ++ // If some device wants to do p2p handshake without sending prov_disc_req ++ // We have to get peer_req_cm from here. ++ if(_rtw_memcmp( pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3) ) ++ { ++ rtw_get_wps_attr_content( wpsie, wps_ielen, WPS_ATTR_DEVICE_PWID, (u8*) &wps_devicepassword_id, &wps_devicepassword_id_len); ++ wps_devicepassword_id = be16_to_cpu( wps_devicepassword_id ); ++ ++ if ( wps_devicepassword_id == WPS_DPID_USER_SPEC ) ++ { ++ _rtw_memcpy( pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3 ); ++ } ++ else if ( wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC ) ++ { ++ _rtw_memcpy( pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3 ); ++ } ++ else ++ { ++ _rtw_memcpy( pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3 ); ++ } ++ } ++ } ++ else ++ { ++ DBG_871X( "[%s] WPS IE not Found!!\n", __FUNCTION__ ); ++ result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ return( result ); ++ } ++ ++ if ( pwdinfo->ui_got_wps_info == P2P_NO_WPSINFO ) ++ { ++ result = P2P_STATUS_FAIL_INFO_UNAVAILABLE; ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_INFOR_NOREADY); ++ return( result ); ++ } ++ ++ ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; ++ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; ++ ++ p2p_ie = rtw_get_p2p_ie( ies, ies_len, NULL, &p2p_ielen ); ++ ++ if ( !p2p_ie ) ++ { ++ DBG_871X( "[%s] P2P IE not Found!!\n", __FUNCTION__ ); ++ result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ } ++ ++ while ( p2p_ie ) ++ { ++ u8 attr_content = 0x00; ++ u32 attr_contentlen = 0; ++ u8 ch_content[100] = { 0x00 }; ++ uint ch_cnt = 0; ++ u8 peer_ch_list[100] = { 0x00 }; ++ u8 peer_ch_num = 0; ++ u8 ch_list_inclusioned[100] = { 0x00 }; ++ u8 ch_num_inclusioned = 0; ++ u16 cap_attr; ++ ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_ING); ++ ++ //Check P2P Capability ATTR ++ if(rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8*)&cap_attr, (uint*)&attr_contentlen) ) ++ { ++ cap_attr = le16_to_cpu(cap_attr); ++ ++#if defined(CONFIG_WFD) && defined(CONFIG_TDLS) ++ if(!(cap_attr & P2P_GRPCAP_INTRABSS) ) ++ ptdlsinfo->ap_prohibited = _TRUE; ++#endif //defined(CONFIG_WFD) && defined(CONFIG_TDLS) ++ } ++ ++ if ( rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT , &attr_content, &attr_contentlen) ) ++ { ++ DBG_871X( "[%s] GO Intent = %d, tie = %d\n", __FUNCTION__, attr_content >> 1, attr_content & 0x01 ); ++ pwdinfo->peer_intent = attr_content; // include both intent and tie breaker values. ++ ++ if ( pwdinfo->intent == ( pwdinfo->peer_intent >> 1 ) ) ++ { ++ // Try to match the tie breaker value ++ if ( pwdinfo->intent == P2P_MAX_INTENT ) ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ result = P2P_STATUS_FAIL_BOTH_GOINTENT_15; ++ } ++ else ++ { ++ if ( attr_content & 0x01 ) ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ } ++ else ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ } ++ } ++ } ++ else if ( pwdinfo->intent > ( pwdinfo->peer_intent >> 1 ) ) ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ } ++ else ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ } ++ ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ { ++ // Store the group id information. ++ _rtw_memcpy( pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN ); ++ _rtw_memcpy( pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen ); ++ } ++ } ++ ++ ++ attr_contentlen = 0; ++ if ( rtw_get_p2p_attr_content( p2p_ie, p2p_ielen, P2P_ATTR_INTENTED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen ) ) ++ { ++ if ( attr_contentlen != ETH_ALEN ) ++ { ++ _rtw_memset( pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN ); ++ } ++ } ++ ++ if ( rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, ch_content, &ch_cnt) ) ++ { ++ peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, ch_content, ch_cnt, peer_ch_list); ++ ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned); ++ ++ if( ch_num_inclusioned == 0) ++ { ++ DBG_871X( "[%s] No common channel in channel list!\n", __FUNCTION__ ); ++ result = P2P_STATUS_FAIL_NO_COMMON_CH; ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ break; ++ } ++ ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ { ++ if ( !rtw_p2p_is_channel_list_ok( pwdinfo->operating_channel, ++ ch_list_inclusioned, ch_num_inclusioned) ) ++ { ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ DBG_871X( "[%s] desired channel NOT Found!\n", __FUNCTION__ ); ++ result = P2P_STATUS_FAIL_NO_COMMON_CH; ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ break; ++ } ++ else ++#endif //CONFIG_CONCURRENT_MODE ++ { ++ u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0; ++ attr_contentlen = 0; ++ ++ if ( rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen) ) ++ { ++ peer_operating_ch = operatingch_info[4]; ++ } ++ ++ if ( rtw_p2p_is_channel_list_ok( peer_operating_ch, ++ ch_list_inclusioned, ch_num_inclusioned) ) ++ { ++ /** ++ * Change our operating channel as peer's for compatibility. ++ */ ++ pwdinfo->operating_channel = peer_operating_ch; ++ DBG_871X( "[%s] Change op ch to %02x as peer's\n", __FUNCTION__, pwdinfo->operating_channel); ++ } ++ else ++ { ++ // Take first channel of ch_list_inclusioned as operating channel ++ pwdinfo->operating_channel = ch_list_inclusioned[0]; ++ DBG_871X( "[%s] Change op ch to %02x\n", __FUNCTION__, pwdinfo->operating_channel); ++ } ++ } ++ ++ } ++ } ++ } ++ ++ //Get the next P2P IE ++ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); ++ } ++ ++#ifdef CONFIG_WFD ++ // Added by Albert 20110823 ++ // Try to get the TCP port information when receiving the negotiation request. ++ if ( rtw_get_wfd_ie( pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, wfd_ie, &wfd_ielen ) ) ++ { ++ u8 attr_content[ 10 ] = { 0x00 }; ++ u32 attr_contentlen = 0; ++ ++ DBG_871X( "[%s] WFD IE Found!!\n", __FUNCTION__ ); ++ rtw_get_wfd_attr_content( wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); ++ if ( attr_contentlen ) ++ { ++ pwdinfo->wfd_info->peer_rtsp_ctrlport = RTW_GET_BE16( attr_content + 2 ); ++ DBG_871X( "[%s] Peer PORT NUM = %d\n", __FUNCTION__, pwdinfo->wfd_info->peer_rtsp_ctrlport ); ++ } ++ } ++#endif // CONFIG_WFD ++ ++ return( result ); ++} ++ ++u8 process_p2p_group_negotation_resp( struct wifidirect_info *pwdinfo, u8 *pframe, uint len ) ++{ ++ _adapter *padapter = pwdinfo->padapter; ++ u8 result = P2P_STATUS_SUCCESS; ++ u32 p2p_ielen, wps_ielen; ++ u8 * ies; ++ u32 ies_len; ++ u8 * p2p_ie; ++#ifdef CONFIG_WFD ++ u8 wfd_ie[ 128 ] = { 0x00 }; ++ u32 wfd_ielen = 0; ++#ifdef CONFIG_TDLS ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++#endif // CONFIG_TDLS ++#endif // CONFIG_WFD ++ ++ ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; ++ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; ++ ++ // Be able to know which one is the P2P GO and which one is P2P client. ++ ++ if ( rtw_get_wps_ie( ies, ies_len, NULL, &wps_ielen) ) ++ { ++ ++ } ++ else ++ { ++ DBG_871X( "[%s] WPS IE not Found!!\n", __FUNCTION__ ); ++ result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ } ++ ++ p2p_ie = rtw_get_p2p_ie( ies, ies_len, NULL, &p2p_ielen ); ++ if ( !p2p_ie ) ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; ++ } ++ else ++ { ++ ++ u8 attr_content = 0x00; ++ u32 attr_contentlen = 0; ++ u8 operatingch_info[5] = { 0x00 }; ++ uint ch_cnt = 0; ++ u8 ch_content[100] = { 0x00 }; ++ u8 groupid[ 38 ]; ++ u16 cap_attr; ++ u8 peer_ch_list[100] = { 0x00 }; ++ u8 peer_ch_num = 0; ++ u8 ch_list_inclusioned[100] = { 0x00 }; ++ u8 ch_num_inclusioned = 0; ++ ++ while ( p2p_ie ) // Found the P2P IE. ++ { ++ ++ //Check P2P Capability ATTR ++ if(rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8*)&cap_attr, (uint*)&attr_contentlen) ) ++ { ++ cap_attr = le16_to_cpu(cap_attr); ++#ifdef CONFIG_TDLS ++ if(!(cap_attr & P2P_GRPCAP_INTRABSS) ) ++ ptdlsinfo->ap_prohibited = _TRUE; ++#endif // CONFIG_TDLS ++ } ++ ++ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); ++ if ( attr_contentlen == 1 ) ++ { ++ DBG_871X( "[%s] Status = %d\n", __FUNCTION__, attr_content ); ++ if ( attr_content == P2P_STATUS_SUCCESS ) ++ { ++ // Do nothing. ++ } ++ else ++ { ++ if ( P2P_STATUS_FAIL_INFO_UNAVAILABLE == attr_content ) { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INFOR_NOREADY); ++ } else { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ } ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ result = attr_content; ++ break; ++ } ++ } ++ ++ // Try to get the peer's interface address ++ attr_contentlen = 0; ++ if ( rtw_get_p2p_attr_content( p2p_ie, p2p_ielen, P2P_ATTR_INTENTED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen ) ) ++ { ++ if ( attr_contentlen != ETH_ALEN ) ++ { ++ _rtw_memset( pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN ); ++ } ++ } ++ ++ // Try to get the peer's intent and tie breaker value. ++ attr_content = 0x00; ++ attr_contentlen = 0; ++ if ( rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT , &attr_content, &attr_contentlen) ) ++ { ++ DBG_871X( "[%s] GO Intent = %d, tie = %d\n", __FUNCTION__, attr_content >> 1, attr_content & 0x01 ); ++ pwdinfo->peer_intent = attr_content; // include both intent and tie breaker values. ++ ++ if ( pwdinfo->intent == ( pwdinfo->peer_intent >> 1 ) ) ++ { ++ // Try to match the tie breaker value ++ if ( pwdinfo->intent == P2P_MAX_INTENT ) ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ result = P2P_STATUS_FAIL_BOTH_GOINTENT_15; ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ } ++ else ++ { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ if ( attr_content & 0x01 ) ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ } ++ else ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ } ++ } ++ } ++ else if ( pwdinfo->intent > ( pwdinfo->peer_intent >> 1 ) ) ++ { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ } ++ else ++ { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ } ++ ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ { ++ // Store the group id information. ++ _rtw_memcpy( pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN ); ++ _rtw_memcpy( pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen ); ++ ++ } ++ } ++ ++ // Try to get the operation channel information ++ ++ attr_contentlen = 0; ++ if ( rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) ++ { ++ DBG_871X( "[%s] Peer's operating channel = %d\n", __FUNCTION__, operatingch_info[4] ); ++ pwdinfo->peer_operating_ch = operatingch_info[4]; ++ } ++ ++ // Try to get the channel list information ++ if ( rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, pwdinfo->channel_list_attr, &pwdinfo->channel_list_attr_len ) ) ++ { ++ DBG_871X( "[%s] channel list attribute found, len = %d\n", __FUNCTION__, pwdinfo->channel_list_attr_len ); ++ ++ peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, pwdinfo->channel_list_attr, pwdinfo->channel_list_attr_len, peer_ch_list); ++ ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned); ++ ++ if( ch_num_inclusioned == 0) ++ { ++ DBG_871X( "[%s] No common channel in channel list!\n", __FUNCTION__ ); ++ result = P2P_STATUS_FAIL_NO_COMMON_CH; ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ break; ++ } ++ ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ { ++ if ( !rtw_p2p_is_channel_list_ok( pwdinfo->operating_channel, ++ ch_list_inclusioned, ch_num_inclusioned) ) ++ { ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ DBG_871X( "[%s] desired channel NOT Found!\n", __FUNCTION__ ); ++ result = P2P_STATUS_FAIL_NO_COMMON_CH; ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ break; ++ } ++ else ++#endif //CONFIG_CONCURRENT_MODE ++ { ++ u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0; ++ attr_contentlen = 0; ++ ++ if ( rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen) ) ++ { ++ peer_operating_ch = operatingch_info[4]; ++ } ++ ++ if ( rtw_p2p_is_channel_list_ok( peer_operating_ch, ++ ch_list_inclusioned, ch_num_inclusioned) ) ++ { ++ /** ++ * Change our operating channel as peer's for compatibility. ++ */ ++ pwdinfo->operating_channel = peer_operating_ch; ++ DBG_871X( "[%s] Change op ch to %02x as peer's\n", __FUNCTION__, pwdinfo->operating_channel); ++ } ++ else ++ { ++ // Take first channel of ch_list_inclusioned as operating channel ++ pwdinfo->operating_channel = ch_list_inclusioned[0]; ++ DBG_871X( "[%s] Change op ch to %02x\n", __FUNCTION__, pwdinfo->operating_channel); ++ } ++ } ++ ++ } ++ } ++ ++ } ++ else ++ { ++ DBG_871X( "[%s] channel list attribute not found!\n", __FUNCTION__); ++ } ++ ++ // Try to get the group id information if peer is GO ++ attr_contentlen = 0; ++ _rtw_memset( groupid, 0x00, 38 ); ++ if ( rtw_get_p2p_attr_content( p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen) ) ++ { ++ _rtw_memcpy( pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN ); ++ _rtw_memcpy( pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN ); ++ } ++ ++ //Get the next P2P IE ++ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); ++ } ++ ++ } ++ ++#ifdef CONFIG_WFD ++ // Added by Albert 20111122 ++ // Try to get the TCP port information when receiving the negotiation response. ++ if ( rtw_get_wfd_ie( pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, wfd_ie, &wfd_ielen ) ) ++ { ++ u8 attr_content[ 10 ] = { 0x00 }; ++ u32 attr_contentlen = 0; ++ ++ DBG_8192C( "[%s] WFD IE Found!!\n", __FUNCTION__ ); ++ rtw_get_wfd_attr_content( wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); ++ if ( attr_contentlen ) ++ { ++ pwdinfo->wfd_info->peer_rtsp_ctrlport = RTW_GET_BE16( attr_content + 2 ); ++ DBG_8192C( "[%s] Peer PORT NUM = %d\n", __FUNCTION__, pwdinfo->wfd_info->peer_rtsp_ctrlport ); ++ } ++ } ++#endif // CONFIG_WFD ++ ++ return( result ); ++ ++} ++ ++u8 process_p2p_group_negotation_confirm( struct wifidirect_info *pwdinfo, u8 *pframe, uint len ) ++{ ++ u8 * ies; ++ u32 ies_len; ++ u8 * p2p_ie; ++ u32 p2p_ielen = 0; ++ u8 result = P2P_STATUS_SUCCESS; ++ ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; ++ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; ++ ++ p2p_ie = rtw_get_p2p_ie( ies, ies_len, NULL, &p2p_ielen ); ++ while ( p2p_ie ) // Found the P2P IE. ++ { ++ u8 attr_content = 0x00, operatingch_info[5] = { 0x00 }; ++ u8 groupid[ 38 ] = { 0x00 }; ++ u32 attr_contentlen = 0; ++ ++ pwdinfo->negotiation_dialog_token = 1; ++ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); ++ if ( attr_contentlen == 1 ) ++ { ++ DBG_871X( "[%s] Status = %d\n", __FUNCTION__, attr_content ); ++ result = attr_content; ++ ++ if ( attr_content == P2P_STATUS_SUCCESS ) ++ { ++ u8 bcancelled = 0; ++ ++ _cancel_timer( &pwdinfo->restore_p2p_state_timer, &bcancelled ); ++ ++ // Commented by Albert 20100911 ++ // Todo: Need to handle the case which both Intents are the same. ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ if ( ( pwdinfo->intent ) > ( pwdinfo->peer_intent >> 1 ) ) ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ } ++ else if ( ( pwdinfo->intent ) < ( pwdinfo->peer_intent >> 1 ) ) ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ } ++ else ++ { ++ // Have to compare the Tie Breaker ++ if ( pwdinfo->peer_intent & 0x01 ) ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ } ++ else ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ } ++ } ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(pwdinfo->padapter , _FW_LINKED ) ) ++ { ++ // Switch back to the AP channel soon. ++ _set_timer( &pwdinfo->ap_p2p_switch_timer, 100 ); ++ } ++#endif ++ } ++ else ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ break; ++ } ++ } ++ ++ // Try to get the group id information ++ attr_contentlen = 0; ++ _rtw_memset( groupid, 0x00, 38 ); ++ if ( rtw_get_p2p_attr_content( p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen) ) ++ { ++ DBG_871X( "[%s] Ssid = %s, ssidlen = %zu\n", __FUNCTION__, &groupid[ETH_ALEN], strlen(&groupid[ETH_ALEN]) ); ++ _rtw_memcpy( pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN ); ++ _rtw_memcpy( pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN ); ++ } ++ ++ attr_contentlen = 0; ++ if ( rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen) ) ++ { ++ DBG_871X( "[%s] Peer's operating channel = %d\n", __FUNCTION__, operatingch_info[4] ); ++ pwdinfo->peer_operating_ch = operatingch_info[4]; ++ } ++ ++ //Get the next P2P IE ++ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); ++ ++ } ++ ++ return( result ); ++} ++ ++u8 process_p2p_presence_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) ++{ ++ u8 *frame_body; ++ u8 dialogToken=0; ++ u8 status = P2P_STATUS_SUCCESS; ++ ++ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ ++ dialogToken = frame_body[6]; ++ ++ //todo: check NoA attribute ++ ++ issue_p2p_presence_resp(pwdinfo, GetAddr2Ptr(pframe), status, dialogToken); ++ ++ return _TRUE; ++} ++ ++void find_phase_handler( _adapter* padapter ) ++{ ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ NDIS_802_11_SSID ssid; ++ _irqL irqL; ++ u8 _status = 0; ++ ++_func_enter_; ++ ++ _rtw_memset((unsigned char*)&ssid, 0, sizeof(NDIS_802_11_SSID)); ++ _rtw_memcpy(ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN ); ++ ssid.SsidLength = P2P_WILDCARD_SSID_LEN; ++ ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH); ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ _status = rtw_sitesurvey_cmd(padapter, &ssid, 1, NULL, 0); ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ ++_func_exit_; ++} ++ ++void p2p_concurrent_handler( _adapter* padapter ); ++ ++void restore_p2p_state_handler( _adapter* padapter ) ++{ ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++_func_enter_; ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ } ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_priv *pbuddy_mlmepriv = &pbuddy_adapter->mlmepriv; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_RSP)) ++ { ++ set_channel_bwmode(padapter, pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_ch_offset, pbuddy_mlmeext->cur_bwmode); ++ ++ issue_nulldata(pbuddy_adapter, NULL, 0, 3, 500); ++ } ++ } ++#endif ++ ++ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); ++ ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) ++ { ++#ifdef CONFIG_CONCURRENT_MODE ++ p2p_concurrent_handler( padapter ); ++#else ++ // In the P2P client mode, the driver should not switch back to its listen channel ++ // because this P2P client should stay at the operating channel of P2P GO. ++ set_channel_bwmode( padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++#endif ++ } ++_func_exit_; ++} ++ ++void pre_tx_invitereq_handler( _adapter* padapter ) ++{ ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 val8 = 1; ++_func_enter_; ++ ++ set_channel_bwmode(padapter, pwdinfo->invitereq_info.peer_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ issue_probereq_p2p(padapter, NULL); ++ _set_timer( &pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT ); ++ ++_func_exit_; ++} ++ ++void pre_tx_provdisc_handler( _adapter* padapter ) ++{ ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 val8 = 1; ++_func_enter_; ++ ++ set_channel_bwmode(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ issue_probereq_p2p(padapter, NULL); ++ _set_timer( &pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT ); ++ ++_func_exit_; ++} ++ ++void pre_tx_negoreq_handler( _adapter* padapter ) ++{ ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 val8 = 1; ++_func_enter_; ++ ++ set_channel_bwmode(padapter, pwdinfo->nego_req_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ issue_probereq_p2p(padapter, NULL); ++ _set_timer( &pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT ); ++ ++_func_exit_; ++} ++ ++#ifdef CONFIG_CONCURRENT_MODE ++void p2p_concurrent_handler( _adapter* padapter ) ++{ ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ //_adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ //struct wifidirect_info *pbuddy_wdinfo = &pbuddy_adapter->wdinfo; ++ //struct mlme_priv *pbuddy_mlmepriv = &pbuddy_adapter->mlmepriv; ++ //struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ u8 val8; ++_func_enter_; ++ ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ ++ pwdinfo->operating_channel = pbuddy_mlmeext->cur_channel; ++ ++ if( pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ { ++ DBG_871X("%s, switch ch back to buddy's cur_channel=%d\n", __func__, pbuddy_mlmeext->cur_channel); ++ ++ set_channel_bwmode(padapter, pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_ch_offset, pbuddy_mlmeext->cur_bwmode); ++ ++ issue_nulldata(pbuddy_adapter, NULL, 0, 3, 500); ++ } ++ else if( pwdinfo->driver_interface == DRIVER_WEXT ) ++ { ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) ++ { ++ // Now, the driver stays on the AP's channel. ++ // If the pwdinfo->ext_listen_period = 0, that means the P2P listen state is not available on listen channel. ++ if ( pwdinfo->ext_listen_period > 0 ) ++ { ++ DBG_8192C( "[%s] P2P_STATE_IDLE, ext_listen_period = %d\n", __FUNCTION__, pwdinfo->ext_listen_period ); ++ ++ if ( pbuddy_mlmeext->cur_channel != pwdinfo->listen_channel ) ++ { ++ // Will switch to listen channel so that need to send the NULL data with PW bit to AP. ++ issue_nulldata(pbuddy_adapter, NULL, 1, 3, 500); ++ set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ } ++ ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); ++ val8 = 1; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ ++ // Todo: To check the value of pwdinfo->ext_listen_period is equal to 0 or not. ++ _set_timer( &pwdinfo->ap_p2p_switch_timer, pwdinfo->ext_listen_period ); ++ } ++ } ++ else if ( rtw_p2p_chk_state(pwdinfo, P2P_STATE_LISTEN) || ++ rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL) || ++ ( rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) && pwdinfo->nego_req_info.benable == _FALSE ) || ++ rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ) ) ++ { ++ // Now, the driver is in the listen state of P2P mode. ++ DBG_8192C( "[%s] P2P_STATE_IDLE, ext_listen_interval = %d\n", __FUNCTION__, pwdinfo->ext_listen_interval ); ++ ++ // Commented by Albert 2012/11/01 ++ // If the AP's channel is the same as the listen channel, we should still be in the listen state ++ // Other P2P device is still able to find this device out even this device is in the AP's channel. ++ // So, configure this device to be able to receive the probe request frame and set it to listen state. ++ if ( pbuddy_mlmeext->cur_channel != pwdinfo->listen_channel ) ++ { ++ set_channel_bwmode(padapter, pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_ch_offset, pbuddy_mlmeext->cur_bwmode); ++ val8 = 0; ++ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_IDLE); ++ issue_nulldata(pbuddy_adapter, NULL, 0, 3, 500); ++ } ++ ++ // Todo: To check the value of pwdinfo->ext_listen_interval is equal to 0 or not. ++ _set_timer( &pwdinfo->ap_p2p_switch_timer, pwdinfo->ext_listen_interval ); ++ } ++ else if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_OK)) ++ { ++ // The driver had finished the P2P handshake successfully. ++ val8 = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ set_channel_bwmode(padapter, pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_ch_offset, pbuddy_mlmeext->cur_bwmode); ++ issue_nulldata(pbuddy_adapter, NULL, 0, 3, 500); ++ } ++ else if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) ++ { ++ val8 = 1; ++ set_channel_bwmode(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ issue_probereq_p2p(padapter, NULL); ++ _set_timer( &pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT ); ++ } ++ else if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) && pwdinfo->nego_req_info.benable == _TRUE) ++ { ++ val8 = 1; ++ set_channel_bwmode(padapter, pwdinfo->nego_req_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ issue_probereq_p2p(padapter, NULL); ++ _set_timer( &pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT ); ++ } ++ else if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ ) && pwdinfo->invitereq_info.benable == _TRUE) ++ { ++ /* ++ val8 = 1; ++ set_channel_bwmode(padapter, , HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ issue_probereq_p2p(padapter, NULL); ++ _set_timer( &pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT ); ++ */ ++ } ++ } ++ } ++ else ++ { ++ set_channel_bwmode( padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ } ++ ++_func_exit_; ++} ++#endif ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++static void ro_ch_handler(_adapter *padapter) ++{ ++ struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ u8 ch, bw, offset; ++_func_enter_; ++ ++ if (rtw_get_ch_setting_union(padapter, &ch, &bw, &offset) != 0) { ++ if (0) ++ DBG_871X(FUNC_ADPT_FMT" back to linked union - ch:%u, bw:%u, offset:%u\n", ++ FUNC_ADPT_ARG(padapter), ch, bw, offset); ++ } ++ else if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled && pwdinfo->listen_channel) { ++ ch = pwdinfo->listen_channel; ++ bw = HT_CHANNEL_WIDTH_20; ++ offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ if (0) ++ DBG_871X(FUNC_ADPT_FMT" back to listen ch - ch:%u, bw:%u, offset:%u\n", ++ FUNC_ADPT_ARG(padapter), ch, bw, offset); ++ } ++ else { ++ ch = pcfg80211_wdinfo->restore_channel; ++ bw = HT_CHANNEL_WIDTH_20; ++ offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ if (0) ++ DBG_871X(FUNC_ADPT_FMT" back to restore ch - ch:%u, bw:%u, offset:%u\n", ++ FUNC_ADPT_ARG(padapter), ch, bw, offset); ++ } ++ ++ set_channel_bwmode(padapter, ch, offset, bw); ++ ++ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X("%s, role=%d, p2p_state=%d\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo)); ++#endif ++ ++ pcfg80211_wdinfo->is_ro_ch = _FALSE; ++ ++ DBG_871X("cfg80211_remain_on_channel_expired\n"); ++ ++ rtw_cfg80211_remain_on_channel_expired(padapter, ++ pcfg80211_wdinfo->remain_on_ch_cookie, ++ &pcfg80211_wdinfo->remain_on_ch_channel, ++ pcfg80211_wdinfo->remain_on_ch_type, GFP_KERNEL); ++ ++_func_exit_; ++} ++ ++static void ro_ch_timer_process (void *FunctionContext) ++{ ++ _adapter *adapter = (_adapter *)FunctionContext; ++ struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(adapter->rtw_wdev); ++ ++ //printk("%s \n", __FUNCTION__); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ ATOMIC_SET(&pwdev_priv->ro_ch_to, 1); ++#endif ++ ++ p2p_protocol_wk_cmd( adapter, P2P_RO_CH_WK); ++} ++ ++static void rtw_change_p2pie_op_ch(_adapter *padapter, const u8 *frame_body, u32 len, u8 ch) ++{ ++ u8 *ies, *p2p_ie; ++ u32 ies_len, p2p_ielen; ++ PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ ++ ies = (u8*)(frame_body + _PUBLIC_ACTION_IE_OFFSET_); ++ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; ++ ++ p2p_ie = rtw_get_p2p_ie( ies, ies_len, NULL, &p2p_ielen ); ++ ++ while ( p2p_ie ) { ++ u32 attr_contentlen = 0; ++ u8 *pattr = NULL; ++ ++ //Check P2P_ATTR_OPERATING_CH ++ attr_contentlen = 0; ++ pattr = NULL; ++ if((pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, (uint*)&attr_contentlen))!=NULL) ++ { ++ *(pattr+4) = ch; ++ } ++ ++ //Get the next P2P IE ++ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); ++ } ++} ++ ++static void rtw_change_p2pie_ch_list(_adapter *padapter, const u8 *frame_body, u32 len, u8 ch) ++{ ++ u8 *ies, *p2p_ie; ++ u32 ies_len, p2p_ielen; ++ PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ ++ ies = (u8*)(frame_body + _PUBLIC_ACTION_IE_OFFSET_); ++ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; ++ ++ p2p_ie = rtw_get_p2p_ie( ies, ies_len, NULL, &p2p_ielen ); ++ ++ while (p2p_ie) { ++ u32 attr_contentlen = 0; ++ u8 *pattr = NULL; ++ ++ //Check P2P_ATTR_CH_LIST ++ if ((pattr=rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, NULL, (uint*)&attr_contentlen))!=NULL) { ++ int i; ++ u32 num_of_ch; ++ u8 *pattr_temp = pattr + 3 ; ++ ++ attr_contentlen -= 3; ++ ++ while (attr_contentlen>0) { ++ num_of_ch = *(pattr_temp+1); ++ ++ for(i=0; ipbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ u8 buddy_ch = pbuddy_mlmeext->cur_channel; ++ ++ ies = (u8*)(frame_body + _PUBLIC_ACTION_IE_OFFSET_); ++ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; ++ ++ p2p_ie = rtw_get_p2p_ie( ies, ies_len, NULL, &p2p_ielen ); ++ ++ while (p2p_ie) { ++ u32 attr_contentlen = 0; ++ u8 *pattr = NULL; ++ ++ //Check P2P_ATTR_CH_LIST ++ if ((pattr=rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, NULL, (uint*)&attr_contentlen))!=NULL) { ++ int i; ++ u32 num_of_ch; ++ u8 *pattr_temp = pattr + 3 ; ++ ++ attr_contentlen -= 3; ++ ++ while (attr_contentlen>0) { ++ num_of_ch = *(pattr_temp+1); ++ ++ for(i=0; ipbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ u8 buddy_ch = pbuddy_mlmeext->cur_channel; ++ ++ ies = (u8*)(frame_body + _PUBLIC_ACTION_IE_OFFSET_); ++ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; ++ ++ p2p_ie = rtw_get_p2p_ie( ies, ies_len, NULL, &p2p_ielen ); ++ ++ while (p2p_ie) { ++ u32 attr_contentlen = 0; ++ u8 *pattr = NULL; ++ ++ //Check P2P_ATTR_OPERATING_CH ++ attr_contentlen = 0; ++ pattr = NULL; ++ if((pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, (uint*)&attr_contentlen))!=NULL) { ++ if (*(pattr+4) == buddy_ch) { ++ DBG_871X(FUNC_ADPT_FMT" op_ch fit buddy_ch:%u\n", FUNC_ADPT_ARG(padapter), buddy_ch); ++ fit = _TRUE; ++ break; ++ } ++ } ++ ++ //Get the next P2P IE ++ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); ++ } ++#endif ++ return fit; ++} ++ ++static void rtw_cfg80211_adjust_p2pie_channel(_adapter *padapter, const u8 *frame_body, u32 len) ++{ ++#ifdef CONFIG_CONCURRENT_MODE ++ u8 *ies, *p2p_ie; ++ u32 ies_len, p2p_ielen; ++ PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ ++ ies = (u8*)(frame_body + _PUBLIC_ACTION_IE_OFFSET_); ++ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; ++ ++ p2p_ie = rtw_get_p2p_ie( ies, ies_len, NULL, &p2p_ielen ); ++ ++ while ( p2p_ie ) ++ { ++ u32 attr_contentlen = 0; ++ u8 *pattr = NULL; ++ ++ //Check P2P_ATTR_CH_LIST ++ if((pattr=rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, NULL, (uint*)&attr_contentlen))!=NULL) ++ { ++ int i; ++ u32 num_of_ch; ++ u8 *pattr_temp = pattr + 3 ; ++ ++ attr_contentlen -= 3; ++ ++ while(attr_contentlen>0) ++ { ++ num_of_ch = *(pattr_temp+1); ++ ++ for(i=0; icur_channel;//forcing to the same channel ++ ++ pattr_temp += (2+num_of_ch); ++ attr_contentlen -= (2+num_of_ch); ++ } ++ } ++ ++ //Check P2P_ATTR_OPERATING_CH ++ attr_contentlen = 0; ++ pattr = NULL; ++ if((pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, (uint*)&attr_contentlen))!=NULL) ++ { ++ *(pattr+4) = pbuddy_mlmeext->cur_channel;//forcing to the same channel ++ } ++ ++ //Get the next P2P IE ++ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); ++ ++ } ++ ++#endif ++} ++ ++#ifdef CONFIG_WFD ++void rtw_append_wfd_ie(_adapter *padapter, u8 *buf, u32* len) ++{ ++ unsigned char *frame_body; ++ u8 category, action, OUI_Subtype, dialogToken=0; ++ u32 wfdielen = 0; ++ struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); ++ ++ frame_body = (unsigned char *)(buf + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ category = frame_body[0]; ++ ++ if(category == RTW_WLAN_CATEGORY_PUBLIC) ++ { ++ action = frame_body[1]; ++ if (action == ACT_PUBLIC_VENDOR ++ && _rtw_memcmp(frame_body+2, P2P_OUI, 4) == _TRUE ++ ) ++ { ++ OUI_Subtype = frame_body[6]; ++ dialogToken = frame_body[7]; ++ switch( OUI_Subtype )//OUI Subtype ++ { ++ case P2P_GO_NEGO_REQ: ++ { ++ wfdielen = build_nego_req_wfd_ie( &padapter->wdinfo, buf + ( *len ) ); ++ (*len) += wfdielen; ++ break; ++ } ++ case P2P_GO_NEGO_RESP: ++ { ++ wfdielen = build_nego_resp_wfd_ie( &padapter->wdinfo, buf + ( *len ) ); ++ (*len) += wfdielen; ++ break; ++ } ++ case P2P_GO_NEGO_CONF: ++ { ++ wfdielen = build_nego_confirm_wfd_ie( &padapter->wdinfo, buf + ( *len ) ); ++ (*len) += wfdielen; ++ break; ++ } ++ case P2P_INVIT_REQ: ++ { ++ wfdielen = build_invitation_req_wfd_ie( &padapter->wdinfo, buf + ( *len ) ); ++ (*len) += wfdielen; ++ break; ++ } ++ case P2P_INVIT_RESP: ++ { ++ wfdielen = build_invitation_resp_wfd_ie( &padapter->wdinfo, buf + ( *len ) ); ++ (*len) += wfdielen; ++ break; ++ } ++ case P2P_DEVDISC_REQ: ++ break; ++ case P2P_DEVDISC_RESP: ++ ++ break; ++ case P2P_PROVISION_DISC_REQ: ++ { ++ wfdielen = build_provdisc_req_wfd_ie( &padapter->wdinfo, buf + ( *len ) ); ++ (*len) += wfdielen; ++ break; ++ } ++ case P2P_PROVISION_DISC_RESP: ++ { ++ wfdielen = build_provdisc_resp_wfd_ie( &padapter->wdinfo, buf + ( *len ) ); ++ (*len) += wfdielen; ++ break; ++ } ++ default: ++ ++ break; ++ } ++ ++ } ++ ++ } ++ else if(category == RTW_WLAN_CATEGORY_P2P) ++ { ++ OUI_Subtype = frame_body[5]; ++ dialogToken = frame_body[6]; ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X("ACTION_CATEGORY_P2P: OUI=0x%x, OUI_Subtype=%d, dialogToken=%d\n", ++ cpu_to_be32( *( ( u32* ) ( frame_body + 1 ) ) ), OUI_Subtype, dialogToken); ++#endif ++ ++ switch(OUI_Subtype) ++ { ++ case P2P_NOTICE_OF_ABSENCE: ++ ++ break; ++ case P2P_PRESENCE_REQUEST: ++ ++ break; ++ case P2P_PRESENCE_RESPONSE: ++ ++ break; ++ case P2P_GO_DISC_REQUEST: ++ ++ break; ++ default: ++ ++ break; ++ } ++ ++ } ++ else ++ { ++ DBG_871X("%s, action frame category=%d\n", __func__, category); ++ //is_p2p_frame = (-1); ++ } ++ ++ return; ++} ++#endif ++ ++u8 *dump_p2p_attr_ch_list(u8 *p2p_ie, uint p2p_ielen, u8 *buf, u32 buf_len) ++{ ++ uint attr_contentlen = 0; ++ u8 *pattr = NULL; ++ int w_sz = 0; ++ u8 ch_cnt = 0; ++ u8 ch_list[40]; ++ bool continuous = _FALSE; ++ ++ if ((pattr=rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, NULL, &attr_contentlen))!=NULL) { ++ int i, j; ++ u32 num_of_ch; ++ u8 *pattr_temp = pattr + 3 ; ++ ++ attr_contentlen -= 3; ++ ++ _rtw_memset(ch_list, 0, 40); ++ ++ while (attr_contentlen>0) { ++ num_of_ch = *(pattr_temp+1); ++ ++ for(i=0; i=ch_cnt) ++ ch_list[ch_cnt++] = *(pattr_temp+2+i); ++ ++ } ++ ++ pattr_temp += (2+num_of_ch); ++ attr_contentlen -= (2+num_of_ch); ++ } ++ ++ for (j=0;j>1 == resp >>1) ++ return req&0x01 ? _TRUE : _FALSE; ++ else if (req>>1 > resp>>1) ++ return _TRUE; ++ else ++ return _FALSE; ++} ++ ++int rtw_p2p_check_frames(_adapter *padapter, const u8 *buf, u32 len, u8 tx) ++{ ++ int is_p2p_frame = (-1); ++ unsigned char *frame_body; ++ u8 category, action, OUI_Subtype, dialogToken=0; ++ u8 *p2p_ie = NULL; ++ uint p2p_ielen = 0; ++ struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); ++ int status = -1; ++ u8 ch_list_buf[128] = {'\0'}; ++ int op_ch = -1; ++ int listen_ch = -1; ++ u8 intent = 0; ++ ++ frame_body = (unsigned char *)(buf + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ category = frame_body[0]; ++ //just for check ++ if(category == RTW_WLAN_CATEGORY_PUBLIC) ++ { ++ action = frame_body[1]; ++ if (action == ACT_PUBLIC_VENDOR ++ && _rtw_memcmp(frame_body+2, P2P_OUI, 4) == _TRUE ++ ) ++ { ++ OUI_Subtype = frame_body[6]; ++ dialogToken = frame_body[7]; ++ is_p2p_frame = OUI_Subtype; ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X("ACTION_CATEGORY_PUBLIC: ACT_PUBLIC_VENDOR, OUI=0x%x, OUI_Subtype=%d, dialogToken=%d\n", ++ cpu_to_be32( *( ( u32* ) ( frame_body + 2 ) ) ), OUI_Subtype, dialogToken); ++ #endif ++ ++ p2p_ie = rtw_get_p2p_ie( ++ (u8 *)buf+sizeof(struct rtw_ieee80211_hdr_3addr)+_PUBLIC_ACTION_IE_OFFSET_, ++ len-sizeof(struct rtw_ieee80211_hdr_3addr)-_PUBLIC_ACTION_IE_OFFSET_, ++ NULL, &p2p_ielen); ++ ++ switch( OUI_Subtype )//OUI Subtype ++ { ++ u8 *cont; ++ uint cont_len; ++ case P2P_GO_NEGO_REQ: ++ { ++ struct rtw_wdev_nego_info* nego_info = &pwdev_priv->nego_info; ++ ++ if (tx) { ++ #ifdef CONFIG_DRV_ISSUE_PROV_REQ // IOT FOR S2 ++ if(pwdev_priv->provdisc_req_issued == _FALSE) ++ rtw_cfg80211_issue_p2p_provision_request(padapter, buf, len); ++ #endif //CONFIG_DRV_ISSUE_PROV_REQ ++ ++ //pwdev_priv->provdisc_req_issued = _FALSE; ++ ++ #ifdef CONFIG_CONCURRENT_MODE ++ if(check_buddy_fwstate(padapter, _FW_LINKED) ++ || check_buddy_fwstate(padapter, WIFI_AP_STATE)) ++ rtw_cfg80211_adjust_p2pie_channel(padapter, frame_body, len-sizeof(struct rtw_ieee80211_hdr_3addr)); ++ #endif ++ } ++ ++ if ((cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len))) ++ op_ch = *(cont+4); ++ if ((cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_LISTEN_CH, NULL, &cont_len))) ++ listen_ch = *(cont+4); ++ if ((cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT, NULL, &cont_len))) ++ intent = *cont; ++ ++ if (nego_info->token != dialogToken) ++ rtw_wdev_nego_info_init(nego_info); ++ ++ _rtw_memcpy(nego_info->peer_mac, tx ? GetAddr1Ptr(buf) : GetAddr2Ptr(buf), ETH_ALEN); ++ nego_info->active = tx ? 1 : 0; ++ nego_info->token = dialogToken; ++ nego_info->req_op_ch = op_ch; ++ nego_info->req_listen_ch = listen_ch; ++ nego_info->req_intent = intent; ++ nego_info->state = 0; ++ ++ dump_p2p_attr_ch_list(p2p_ie, p2p_ielen, ch_list_buf, 128); ++ DBG_871X("RTW_%s:P2P_GO_NEGO_REQ, dialogToken=%d, intent:%u%s, listen_ch:%d, op_ch:%d, ch_list:%s\n", ++ (tx==_TRUE)?"Tx":"Rx", dialogToken, (intent>>1), intent&0x1 ? "+" : "-", listen_ch, op_ch, ch_list_buf); ++ ++ if (!tx) { ++ #ifdef CONFIG_CONCURRENT_MODE ++ if((check_buddy_fwstate(padapter, _FW_LINKED) ++ || check_buddy_fwstate(padapter, WIFI_AP_STATE)) ++ && rtw_chk_p2pie_ch_list_with_buddy(padapter, frame_body, len-sizeof(struct rtw_ieee80211_hdr_3addr)) == _FALSE) ++ { ++ DBG_871X(FUNC_ADPT_FMT" ch_list has no intersect with buddy\n", FUNC_ADPT_ARG(padapter)); ++ rtw_change_p2pie_ch_list(padapter, frame_body, len-sizeof(struct rtw_ieee80211_hdr_3addr), 0); ++ } ++ #endif ++ } ++ ++ break; ++ } ++ case P2P_GO_NEGO_RESP: ++ { ++ struct rtw_wdev_nego_info* nego_info = &pwdev_priv->nego_info; ++ ++ if (tx) { ++ #ifdef CONFIG_CONCURRENT_MODE ++ if(check_buddy_fwstate(padapter, _FW_LINKED) ++ || check_buddy_fwstate(padapter, WIFI_AP_STATE)) ++ rtw_cfg80211_adjust_p2pie_channel(padapter, frame_body, len-sizeof(struct rtw_ieee80211_hdr_3addr)); ++ #endif ++ } ++ ++ if ((cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len))) ++ op_ch = *(cont+4); ++ if ((cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT, NULL, &cont_len))) ++ intent = *cont; ++ if ((cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len))) ++ status = *cont; ++ ++ if (nego_info->token == dialogToken && nego_info->state == 0 ++ && _rtw_memcmp(nego_info->peer_mac, tx ? GetAddr1Ptr(buf) : GetAddr2Ptr(buf), ETH_ALEN) == _TRUE ++ ) { ++ nego_info->status = (status==-1) ? 0xff : status; ++ nego_info->rsp_op_ch= op_ch; ++ nego_info->rsp_intent = intent; ++ nego_info->state = 1; ++ if (status != 0) ++ nego_info->token = 0; /* init */ ++ } ++ ++ dump_p2p_attr_ch_list(p2p_ie, p2p_ielen, ch_list_buf, 128); ++ DBG_871X("RTW_%s:P2P_GO_NEGO_RESP, dialogToken=%d, intent:%u%s, status:%d, op_ch:%d, ch_list:%s\n", ++ (tx==_TRUE)?"Tx":"Rx", dialogToken, (intent>>1), intent&0x1 ? "+" : "-", status, op_ch, ch_list_buf); ++ ++ if (!tx) { ++ pwdev_priv->provdisc_req_issued = _FALSE; ++ #ifdef CONFIG_CONCURRENT_MODE ++ if((check_buddy_fwstate(padapter, _FW_LINKED) ++ || check_buddy_fwstate(padapter, WIFI_AP_STATE)) ++ && rtw_chk_p2pie_ch_list_with_buddy(padapter, frame_body, len-sizeof(struct rtw_ieee80211_hdr_3addr)) == _FALSE) ++ { ++ DBG_871X(FUNC_ADPT_FMT" ch_list has no intersect with buddy\n", FUNC_ADPT_ARG(padapter)); ++ rtw_change_p2pie_ch_list(padapter, frame_body, len-sizeof(struct rtw_ieee80211_hdr_3addr), 0); ++ } ++ #endif ++ } ++ ++ break; ++ } ++ case P2P_GO_NEGO_CONF: ++ { ++ struct rtw_wdev_nego_info* nego_info = &pwdev_priv->nego_info; ++ bool is_go = _FALSE; ++ ++ if (tx) { ++ #ifdef CONFIG_CONCURRENT_MODE ++ if(check_buddy_fwstate(padapter, _FW_LINKED) ++ || check_buddy_fwstate(padapter, WIFI_AP_STATE)) ++ rtw_cfg80211_adjust_p2pie_channel(padapter, frame_body, len-sizeof(struct rtw_ieee80211_hdr_3addr)); ++ #endif ++ } ++ ++ if ((cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len))) ++ op_ch = *(cont+4); ++ if ((cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len))) ++ status = *cont; ++ ++ if (nego_info->token == dialogToken && nego_info->state == 1 ++ && _rtw_memcmp(nego_info->peer_mac, tx ? GetAddr1Ptr(buf) : GetAddr2Ptr(buf), ETH_ALEN) == _TRUE ++ ) { ++ nego_info->status = (status==-1) ? 0xff : status; ++ nego_info->conf_op_ch = (op_ch==-1) ? 0 : op_ch; ++ nego_info->state = 2; ++ ++ if (status == 0) { ++ if (rtw_p2p_nego_intent_compare(nego_info->req_intent, nego_info->rsp_intent) && tx) ++ is_go = _TRUE; ++ } ++ ++ nego_info->token = 0; /* init */ ++ } ++ ++ dump_p2p_attr_ch_list(p2p_ie, p2p_ielen, ch_list_buf, 128); ++ DBG_871X("RTW_%s:P2P_GO_NEGO_CONF, dialogToken=%d, status:%d, op_ch:%d, ch_list:%s\n", ++ (tx==_TRUE)?"Tx":"Rx", dialogToken, status, op_ch, ch_list_buf); ++ ++ if (!tx) { ++ } ++ ++ break; ++ } ++ case P2P_INVIT_REQ: ++ { ++ struct rtw_wdev_invit_info* invit_info = &pwdev_priv->invit_info; ++ int flags = -1; ++ ++ if (tx) { ++ #ifdef CONFIG_CONCURRENT_MODE ++ if(check_buddy_fwstate(padapter, _FW_LINKED) ++ || check_buddy_fwstate(padapter, WIFI_AP_STATE)) ++ rtw_cfg80211_adjust_p2pie_channel(padapter, frame_body, len-sizeof(struct rtw_ieee80211_hdr_3addr)); ++ #endif ++ } ++ ++ if ((cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INVITATION_FLAGS, NULL, &cont_len))) ++ flags = *cont; ++ if ((cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len))) ++ op_ch = *(cont+4); ++ ++ if (invit_info->token != dialogToken) ++ rtw_wdev_invit_info_init(invit_info); ++ ++ _rtw_memcpy(invit_info->peer_mac, tx ? GetAddr1Ptr(buf) : GetAddr2Ptr(buf), ETH_ALEN); ++ invit_info->active = tx ? 1 : 0; ++ invit_info->token = dialogToken; ++ invit_info->flags = (flags==-1) ? 0x0 : flags; ++ invit_info->req_op_ch= op_ch; ++ invit_info->state = 0; ++ ++ dump_p2p_attr_ch_list(p2p_ie, p2p_ielen, ch_list_buf, 128); ++ DBG_871X("RTW_%s:P2P_INVIT_REQ, dialogToken=%d, flags:0x%02x, op_ch:%d, ch_list:%s\n", ++ (tx==_TRUE)?"Tx":"Rx", dialogToken, flags, op_ch, ch_list_buf); ++ ++ if (!tx) { ++ #ifdef CONFIG_CONCURRENT_MODE ++ if(check_buddy_fwstate(padapter, _FW_LINKED) ++ || check_buddy_fwstate(padapter, WIFI_AP_STATE)) { ++ if (op_ch != -1 && rtw_chk_p2pie_op_ch_with_buddy(padapter, frame_body, len-sizeof(struct rtw_ieee80211_hdr_3addr)) == _FALSE) { ++ DBG_871X(FUNC_ADPT_FMT" op_ch:%u has no intersect with buddy\n", FUNC_ADPT_ARG(padapter), op_ch); ++ rtw_change_p2pie_ch_list(padapter, frame_body, len-sizeof(struct rtw_ieee80211_hdr_3addr), 0); ++ } else if (rtw_chk_p2pie_ch_list_with_buddy(padapter, frame_body, len-sizeof(struct rtw_ieee80211_hdr_3addr)) == _FALSE) { ++ DBG_871X(FUNC_ADPT_FMT" ch_list has no intersect with buddy\n", FUNC_ADPT_ARG(padapter)); ++ rtw_change_p2pie_ch_list(padapter, frame_body, len-sizeof(struct rtw_ieee80211_hdr_3addr), 0); ++ } ++ } ++ #endif ++ } ++ ++ break; ++ } ++ case P2P_INVIT_RESP: ++ { ++ struct rtw_wdev_invit_info* invit_info = &pwdev_priv->invit_info; ++ ++ if (tx) { ++ #ifdef CONFIG_CONCURRENT_MODE ++ if(check_buddy_fwstate(padapter, _FW_LINKED) ++ || check_buddy_fwstate(padapter, WIFI_AP_STATE)) ++ rtw_cfg80211_adjust_p2pie_channel(padapter, frame_body, len-sizeof(struct rtw_ieee80211_hdr_3addr)); ++ #endif ++ } ++ ++ if ((cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len))) ++ { ++#ifdef CONFIG_P2P_INVITE_IOT ++ if(tx && *cont==7) ++ { ++ DBG_871X("TX_P2P_INVITE_RESP, status is no common channel, change to unknown group\n"); ++ *cont = 8; //unknow group status ++ } ++#endif //CONFIG_P2P_INVITE_IOT ++ status = *cont; ++ } ++ if ((cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len))) ++ op_ch = *(cont+4); ++ ++ if (invit_info->token == dialogToken && invit_info->state == 0 ++ && _rtw_memcmp(invit_info->peer_mac, tx ? GetAddr1Ptr(buf) : GetAddr2Ptr(buf), ETH_ALEN) == _TRUE ++ ) { ++ invit_info->status = (status==-1) ? 0xff : status; ++ invit_info->rsp_op_ch= op_ch; ++ invit_info->state = 1; ++ invit_info->token = 0; /* init */ ++ } ++ ++ dump_p2p_attr_ch_list(p2p_ie, p2p_ielen, ch_list_buf, 128); ++ DBG_871X("RTW_%s:P2P_INVIT_RESP, dialogToken=%d, status:%d, op_ch:%d, ch_list:%s\n", ++ (tx==_TRUE)?"Tx":"Rx", dialogToken, status, op_ch, ch_list_buf); ++ ++ if (!tx) { ++ } ++ ++ break; ++ } ++ case P2P_DEVDISC_REQ: ++ DBG_871X("RTW_%s:P2P_DEVDISC_REQ, dialogToken=%d\n", (tx==_TRUE)?"Tx":"Rx", dialogToken); ++ break; ++ case P2P_DEVDISC_RESP: ++ cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len); ++ DBG_871X("RTW_%s:P2P_DEVDISC_RESP, dialogToken=%d, status:%d\n", (tx==_TRUE)?"Tx":"Rx", dialogToken, cont?*cont:-1); ++ break; ++ case P2P_PROVISION_DISC_REQ: ++ { ++ size_t frame_body_len = len - sizeof(struct rtw_ieee80211_hdr_3addr); ++ u8 *p2p_ie; ++ uint p2p_ielen = 0; ++ uint contentlen = 0; ++ ++ DBG_871X("RTW_%s:P2P_PROVISION_DISC_REQ, dialogToken=%d\n", (tx==_TRUE)?"Tx":"Rx", dialogToken); ++ ++ //if(tx) ++ { ++ pwdev_priv->provdisc_req_issued = _FALSE; ++ ++ if( (p2p_ie=rtw_get_p2p_ie( frame_body + _PUBLIC_ACTION_IE_OFFSET_, frame_body_len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen))) ++ { ++ ++ if(rtw_get_p2p_attr_content( p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, NULL, &contentlen)) ++ { ++ pwdev_priv->provdisc_req_issued = _FALSE;//case: p2p_client join p2p GO ++ } ++ else ++ { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X("provdisc_req_issued is _TRUE\n"); ++ #endif //CONFIG_DEBUG_CFG80211 ++ pwdev_priv->provdisc_req_issued = _TRUE;//case: p2p_devices connection before Nego req. ++ } ++ ++ } ++ } ++ } ++ break; ++ case P2P_PROVISION_DISC_RESP: ++ DBG_871X("RTW_%s:P2P_PROVISION_DISC_RESP, dialogToken=%d\n", (tx==_TRUE)?"Tx":"Rx", dialogToken); ++ break; ++ default: ++ DBG_871X("RTW_%s:OUI_Subtype=%d, dialogToken=%d\n", (tx==_TRUE)?"Tx":"Rx", OUI_Subtype, dialogToken); ++ break; ++ } ++ ++ } ++ ++ } ++ else if(category == RTW_WLAN_CATEGORY_P2P) ++ { ++ OUI_Subtype = frame_body[5]; ++ dialogToken = frame_body[6]; ++ ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X("ACTION_CATEGORY_P2P: OUI=0x%x, OUI_Subtype=%d, dialogToken=%d\n", ++ cpu_to_be32( *( ( u32* ) ( frame_body + 1 ) ) ), OUI_Subtype, dialogToken); ++ #endif ++ ++ is_p2p_frame = OUI_Subtype; ++ ++ switch(OUI_Subtype) ++ { ++ case P2P_NOTICE_OF_ABSENCE: ++ DBG_871X("RTW_%s:P2P_NOTICE_OF_ABSENCE, dialogToken=%d\n", (tx==_TRUE)?"TX":"RX", dialogToken); ++ break; ++ case P2P_PRESENCE_REQUEST: ++ DBG_871X("RTW_%s:P2P_PRESENCE_REQUEST, dialogToken=%d\n", (tx==_TRUE)?"TX":"RX", dialogToken); ++ break; ++ case P2P_PRESENCE_RESPONSE: ++ DBG_871X("RTW_%s:P2P_PRESENCE_RESPONSE, dialogToken=%d\n", (tx==_TRUE)?"TX":"RX", dialogToken); ++ break; ++ case P2P_GO_DISC_REQUEST: ++ DBG_871X("RTW_%s:P2P_GO_DISC_REQUEST, dialogToken=%d\n", (tx==_TRUE)?"TX":"RX", dialogToken); ++ break; ++ default: ++ DBG_871X("RTW_%s:OUI_Subtype=%d, dialogToken=%d\n", (tx==_TRUE)?"TX":"RX", OUI_Subtype, dialogToken); ++ break; ++ } ++ ++ } ++ else ++ { ++ DBG_871X("RTW_%s:action frame category=%d\n", (tx==_TRUE)?"TX":"RX", category); ++ } ++ ++ return is_p2p_frame; ++} ++ ++void rtw_init_cfg80211_wifidirect_info( _adapter* padapter) ++{ ++ struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; ++ ++ _rtw_memset(pcfg80211_wdinfo, 0x00, sizeof(struct cfg80211_wifidirect_info) ); ++ ++ _init_timer( &pcfg80211_wdinfo->remain_on_ch_timer, padapter->pnetdev, ro_ch_timer_process, padapter ); ++} ++#endif //CONFIG_IOCTL_CFG80211 ++ ++void p2p_protocol_wk_hdl(_adapter *padapter, int intCmdType) ++{ ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ ++_func_enter_; ++ ++ switch(intCmdType) ++ { ++ case P2P_FIND_PHASE_WK: ++ { ++ find_phase_handler( padapter ); ++ break; ++ } ++ case P2P_RESTORE_STATE_WK: ++ { ++ restore_p2p_state_handler( padapter ); ++ break; ++ } ++ case P2P_PRE_TX_PROVDISC_PROCESS_WK: ++ { ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ p2p_concurrent_handler( padapter ); ++ } ++ else ++ { ++ pre_tx_provdisc_handler( padapter ); ++ } ++#else ++ pre_tx_provdisc_handler( padapter ); ++#endif ++ break; ++ } ++ case P2P_PRE_TX_INVITEREQ_PROCESS_WK: ++ { ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ p2p_concurrent_handler( padapter ); ++ } ++ else ++ { ++ pre_tx_invitereq_handler( padapter ); ++ } ++#else ++ pre_tx_invitereq_handler( padapter ); ++#endif ++ break; ++ } ++ case P2P_PRE_TX_NEGOREQ_PROCESS_WK: ++ { ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ p2p_concurrent_handler( padapter ); ++ } ++ else ++ { ++ pre_tx_negoreq_handler( padapter ); ++ } ++#else ++ pre_tx_negoreq_handler( padapter ); ++#endif ++ break; ++ } ++#ifdef CONFIG_P2P ++#ifdef CONFIG_CONCURRENT_MODE ++ case P2P_AP_P2P_CH_SWITCH_PROCESS_WK: ++ { ++ p2p_concurrent_handler( padapter ); ++ break; ++ } ++#endif ++#endif ++#ifdef CONFIG_IOCTL_CFG80211 ++ case P2P_RO_CH_WK: ++ { ++ ro_ch_handler( padapter ); ++ break; ++ } ++#endif //CONFIG_IOCTL_CFG80211 ++ ++ } ++ ++_func_exit_; ++} ++ ++#ifdef CONFIG_P2P_PS ++void process_p2p_ps_ie(PADAPTER padapter, u8 *IEs, u32 IELength) ++{ ++ u8 * ies; ++ u32 ies_len; ++ u8 * p2p_ie; ++ u32 p2p_ielen = 0; ++ u8 noa_attr[MAX_P2P_IE_LEN] = { 0x00 };// NoA length should be n*(13) + 2 ++ u32 attr_contentlen = 0; ++ ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ u8 find_p2p = _FALSE, find_p2p_ps = _FALSE; ++ u8 noa_offset, noa_num, noa_index; ++ ++_func_enter_; ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ return; ++ } ++#ifdef CONFIG_CONCURRENT_MODE ++ if(padapter->iface_type != IFACE_PORT0) ++ return; ++#endif ++ if(IELength <= _BEACON_IE_OFFSET_) ++ return; ++ ++ ies = IEs + _BEACON_IE_OFFSET_; ++ ies_len = IELength - _BEACON_IE_OFFSET_; ++ ++ p2p_ie = rtw_get_p2p_ie( ies, ies_len, NULL, &p2p_ielen); ++ ++ while(p2p_ie) ++ { ++ find_p2p = _TRUE; ++ // Get Notice of Absence IE. ++ if(rtw_get_p2p_attr_content( p2p_ie, p2p_ielen, P2P_ATTR_NOA, noa_attr, &attr_contentlen)) ++ { ++ find_p2p_ps = _TRUE; ++ noa_index = noa_attr[0]; ++ ++ if( (pwdinfo->p2p_ps_mode == P2P_PS_NONE) || ++ (noa_index != pwdinfo->noa_index) )// if index change, driver should reconfigure related setting. ++ { ++ pwdinfo->noa_index = noa_index; ++ pwdinfo->opp_ps = noa_attr[1] >> 7; ++ pwdinfo->ctwindow = noa_attr[1] & 0x7F; ++ ++ noa_offset = 2; ++ noa_num = 0; ++ // NoA length should be n*(13) + 2 ++ if(attr_contentlen > 2) ++ { ++ while(noa_offset < attr_contentlen) ++ { ++ //_rtw_memcpy(&wifidirect_info->noa_count[noa_num], &noa_attr[noa_offset], 1); ++ pwdinfo->noa_count[noa_num] = noa_attr[noa_offset]; ++ noa_offset += 1; ++ ++ _rtw_memcpy(&pwdinfo->noa_duration[noa_num], &noa_attr[noa_offset], 4); ++ noa_offset += 4; ++ ++ _rtw_memcpy(&pwdinfo->noa_interval[noa_num], &noa_attr[noa_offset], 4); ++ noa_offset += 4; ++ ++ _rtw_memcpy(&pwdinfo->noa_start_time[noa_num], &noa_attr[noa_offset], 4); ++ noa_offset += 4; ++ ++ noa_num++; ++ } ++ } ++ pwdinfo->noa_num = noa_num; ++ ++ if( pwdinfo->opp_ps == 1 ) ++ { ++ pwdinfo->p2p_ps_mode = P2P_PS_CTWINDOW; ++ // driver should wait LPS for entering CTWindow ++ if(adapter_to_pwrctl(padapter)->bFwCurrentInPSMode == _TRUE) ++ { ++ p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 1); ++ } ++ } ++ else if( pwdinfo->noa_num > 0 ) ++ { ++ pwdinfo->p2p_ps_mode = P2P_PS_NOA; ++ p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 1); ++ } ++ else if( pwdinfo->p2p_ps_mode > P2P_PS_NONE) ++ { ++ p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1); ++ } ++ } ++ ++ break; // find target, just break. ++ } ++ ++ //Get the next P2P IE ++ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); ++ ++ } ++ ++ if(find_p2p == _TRUE) ++ { ++ if( (pwdinfo->p2p_ps_mode > P2P_PS_NONE) && (find_p2p_ps == _FALSE) ) ++ { ++ p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1); ++ } ++ } ++ ++_func_exit_; ++} ++ ++void p2p_ps_wk_hdl(_adapter *padapter, u8 p2p_ps_state) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ ++_func_enter_; ++ ++ // Pre action for p2p state ++ switch(p2p_ps_state) ++ { ++ case P2P_PS_DISABLE: ++ pwdinfo->p2p_ps_state = p2p_ps_state; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); ++ ++ pwdinfo->noa_index = 0; ++ pwdinfo->ctwindow = 0; ++ pwdinfo->opp_ps = 0; ++ pwdinfo->noa_num = 0; ++ pwdinfo->p2p_ps_mode = P2P_PS_NONE; ++ if(pwrpriv->bFwCurrentInPSMode == _TRUE) ++ { ++ if(pwrpriv->smart_ps == 0) ++ { ++ pwrpriv->smart_ps = 2; ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&(pwrpriv->pwr_mode))); ++ } ++ } ++ break; ++ case P2P_PS_ENABLE: ++ if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) { ++ pwdinfo->p2p_ps_state = p2p_ps_state; ++ ++ if( pwdinfo->ctwindow > 0 ) ++ { ++ if(pwrpriv->smart_ps != 0) ++ { ++ pwrpriv->smart_ps = 0; ++ DBG_871X("%s(): Enter CTW, change SmartPS\n", __FUNCTION__); ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&(pwrpriv->pwr_mode))); ++ } ++ } ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); ++ } ++ break; ++ case P2P_PS_SCAN: ++ case P2P_PS_SCAN_DONE: ++ case P2P_PS_ALLSTASLEEP: ++ if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) { ++ pwdinfo->p2p_ps_state = p2p_ps_state; ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); ++ } ++ break; ++ default: ++ break; ++ } ++ ++_func_exit_; ++} ++ ++u8 p2p_ps_wk_cmd(_adapter*padapter, u8 p2p_ps_state, u8 enqueue) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++_func_enter_; ++ ++ if ( rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) ++#ifdef CONFIG_CONCURRENT_MODE ++ || (padapter->iface_type != IFACE_PORT0) ++#endif ++ ) ++ { ++ return res; ++ } ++ ++ if(enqueue) ++ { ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(ph2c==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if(pdrvextra_cmd_parm==NULL){ ++ rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = P2P_PS_WK_CID; ++ pdrvextra_cmd_parm->type_size = p2p_ps_state; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ } ++ else ++ { ++ p2p_ps_wk_hdl(padapter, p2p_ps_state); ++ } ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++ ++} ++#endif // CONFIG_P2P_PS ++ ++static void reset_ch_sitesurvey_timer_process (void *FunctionContext) ++{ ++ _adapter *adapter = (_adapter *)FunctionContext; ++ struct wifidirect_info *pwdinfo = &adapter->wdinfo; ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ return; ++ ++ DBG_871X( "[%s] In\n", __FUNCTION__ ); ++ // Reset the operation channel information ++ pwdinfo->rx_invitereq_info.operation_ch[0] = 0; ++#ifdef P2P_OP_CHECK_SOCIAL_CH ++ pwdinfo->rx_invitereq_info.operation_ch[1] = 0; ++ pwdinfo->rx_invitereq_info.operation_ch[2] = 0; ++ pwdinfo->rx_invitereq_info.operation_ch[3] = 0; ++#endif //P2P_OP_CHECK_SOCIAL_CH ++ pwdinfo->rx_invitereq_info.scan_op_ch_only = 0; ++} ++ ++static void reset_ch_sitesurvey_timer_process2 (void *FunctionContext) ++{ ++ _adapter *adapter = (_adapter *)FunctionContext; ++ struct wifidirect_info *pwdinfo = &adapter->wdinfo; ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ return; ++ ++ DBG_871X( "[%s] In\n", __FUNCTION__ ); ++ // Reset the operation channel information ++ pwdinfo->p2p_info.operation_ch[0] = 0; ++#ifdef P2P_OP_CHECK_SOCIAL_CH ++ pwdinfo->p2p_info.operation_ch[1] = 0; ++ pwdinfo->p2p_info.operation_ch[2] = 0; ++ pwdinfo->p2p_info.operation_ch[3] = 0; ++#endif //P2P_OP_CHECK_SOCIAL_CH ++ pwdinfo->p2p_info.scan_op_ch_only = 0; ++} ++ ++static void restore_p2p_state_timer_process (void *FunctionContext) ++{ ++ _adapter *adapter = (_adapter *)FunctionContext; ++ struct wifidirect_info *pwdinfo = &adapter->wdinfo; ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ return; ++ ++ p2p_protocol_wk_cmd( adapter, P2P_RESTORE_STATE_WK ); ++} ++ ++static void pre_tx_scan_timer_process (void *FunctionContext) ++{ ++ _adapter *adapter = (_adapter *) FunctionContext; ++ struct wifidirect_info *pwdinfo = &adapter->wdinfo; ++ _irqL irqL; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ u8 _status = 0; ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ return; ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) ++ { ++ if ( _TRUE == pwdinfo->tx_prov_disc_info.benable ) // the provision discovery request frame is trigger to send or not ++ { ++ p2p_protocol_wk_cmd( adapter, P2P_PRE_TX_PROVDISC_PROCESS_WK ); ++ //issue_probereq_p2p(adapter, NULL); ++ //_set_timer( &pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT ); ++ } ++ } ++ else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) ++ { ++ if ( _TRUE == pwdinfo->nego_req_info.benable ) ++ { ++ p2p_protocol_wk_cmd( adapter, P2P_PRE_TX_NEGOREQ_PROCESS_WK ); ++ } ++ } ++ else if ( rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ ) ) ++ { ++ if ( _TRUE == pwdinfo->invitereq_info.benable ) ++ { ++ p2p_protocol_wk_cmd( adapter, P2P_PRE_TX_INVITEREQ_PROCESS_WK ); ++ } ++ } ++ else ++ { ++ DBG_8192C( "[%s] p2p_state is %d, ignore!!\n", __FUNCTION__, rtw_p2p_state(pwdinfo) ); ++ } ++ ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++} ++ ++static void find_phase_timer_process (void *FunctionContext) ++{ ++ _adapter *adapter = (_adapter *)FunctionContext; ++ struct wifidirect_info *pwdinfo = &adapter->wdinfo; ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ return; ++ ++ adapter->wdinfo.find_phase_state_exchange_cnt++; ++ ++ p2p_protocol_wk_cmd( adapter, P2P_FIND_PHASE_WK ); ++} ++ ++#ifdef CONFIG_CONCURRENT_MODE ++void ap_p2p_switch_timer_process (void *FunctionContext) ++{ ++ _adapter *adapter = (_adapter *)FunctionContext; ++ struct wifidirect_info *pwdinfo = &adapter->wdinfo; ++#ifdef CONFIG_IOCTL_CFG80211 ++ struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(adapter->rtw_wdev); ++#endif ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ return; ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ ATOMIC_SET(&pwdev_priv->switch_ch_to, 1); ++#endif ++ ++ p2p_protocol_wk_cmd( adapter, P2P_AP_P2P_CH_SWITCH_PROCESS_WK ); ++} ++#endif ++ ++void reset_global_wifidirect_info( _adapter* padapter ) ++{ ++ struct wifidirect_info *pwdinfo; ++ ++ pwdinfo = &padapter->wdinfo; ++ pwdinfo->persistent_supported = 0; ++ pwdinfo->session_available = _TRUE; ++ pwdinfo->wfd_tdls_enable = 0; ++ pwdinfo->wfd_tdls_weaksec = 0; ++} ++ ++#ifdef CONFIG_WFD ++int rtw_init_wifi_display_info(_adapter* padapter) ++{ ++ int res = _SUCCESS; ++ struct wifi_display_info *pwfd_info = &padapter->wfd_info; ++ ++ // Used in P2P and TDLS ++ pwfd_info->rtsp_ctrlport = 554; ++ pwfd_info->peer_rtsp_ctrlport = 0; // Reset to 0 ++ pwfd_info->wfd_enable = _FALSE; ++ pwfd_info->wfd_device_type = WFD_DEVINFO_PSINK; ++ pwfd_info->scan_result_type = SCAN_RESULT_P2P_ONLY; ++ ++ // Used in P2P ++ pwfd_info->peer_session_avail = _TRUE; ++ pwfd_info->wfd_pc = _FALSE; ++ ++ // Used in TDLS ++ _rtw_memset( pwfd_info->ip_address, 0x00, 4 ); ++ _rtw_memset( pwfd_info->peer_ip_address, 0x00, 4 ); ++ return res; ++ ++} ++#endif //CONFIG_WFD ++ ++void rtw_init_wifidirect_timers(_adapter* padapter) ++{ ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ _init_timer( &pwdinfo->find_phase_timer, padapter->pnetdev, find_phase_timer_process, padapter ); ++ _init_timer( &pwdinfo->restore_p2p_state_timer, padapter->pnetdev, restore_p2p_state_timer_process, padapter ); ++ _init_timer( &pwdinfo->pre_tx_scan_timer, padapter->pnetdev, pre_tx_scan_timer_process, padapter ); ++ _init_timer( &pwdinfo->reset_ch_sitesurvey, padapter->pnetdev, reset_ch_sitesurvey_timer_process, padapter ); ++ _init_timer( &pwdinfo->reset_ch_sitesurvey2, padapter->pnetdev, reset_ch_sitesurvey_timer_process2, padapter ); ++#ifdef CONFIG_CONCURRENT_MODE ++ _init_timer( &pwdinfo->ap_p2p_switch_timer, padapter->pnetdev, ap_p2p_switch_timer_process, padapter ); ++#endif ++} ++ ++void rtw_init_wifidirect_addrs(_adapter* padapter, u8 *dev_addr, u8 *iface_addr) ++{ ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ /*init device&interface address */ ++ if (dev_addr) { ++ _rtw_memcpy(pwdinfo->device_addr, dev_addr, ETH_ALEN); ++ } ++ if (iface_addr) { ++ _rtw_memcpy(pwdinfo->interface_addr, iface_addr, ETH_ALEN); ++ } ++#endif ++} ++ ++void init_wifidirect_info( _adapter* padapter, enum P2P_ROLE role) ++{ ++ struct wifidirect_info *pwdinfo; ++#ifdef CONFIG_WFD ++ struct wifi_display_info *pwfd_info = &padapter->wfd_info; ++#endif ++#ifdef CONFIG_CONCURRENT_MODE ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct wifidirect_info *pbuddy_wdinfo; ++ struct mlme_priv *pbuddy_mlmepriv; ++ struct mlme_ext_priv *pbuddy_mlmeext; ++#endif ++ ++ pwdinfo = &padapter->wdinfo; ++ ++ pwdinfo->padapter = padapter; ++ ++ // 1, 6, 11 are the social channel defined in the WiFi Direct specification. ++ pwdinfo->social_chan[0] = 1; ++ pwdinfo->social_chan[1] = 6; ++ pwdinfo->social_chan[2] = 11; ++ pwdinfo->social_chan[3] = 0; // channel 0 for scanning ending in site survey function. ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (pbuddy_adapter) { ++ pbuddy_wdinfo = &pbuddy_adapter->wdinfo; ++ pbuddy_mlmepriv = &pbuddy_adapter->mlmepriv; ++ pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ } ++ ++ if ( ( check_buddy_fwstate(padapter, _FW_LINKED ) == _TRUE ) && ++ ( ( pbuddy_mlmeext->cur_channel == 1) || ( pbuddy_mlmeext->cur_channel == 6 ) || ( pbuddy_mlmeext->cur_channel == 11 ) ) ++ ) ++ { ++ // Use the AP's channel as the listen channel ++ // This will avoid the channel switch between AP's channel and listen channel. ++ pwdinfo->listen_channel = pbuddy_mlmeext->cur_channel; ++ } ++ else ++#endif //CONFIG_CONCURRENT_MODE ++ { ++ // Use the channel 11 as the listen channel ++ pwdinfo->listen_channel = 11; ++ } ++ ++ if (role == P2P_ROLE_DEVICE) ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ #ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) == _TRUE ) ++ { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_IDLE); ++ } ++ else ++ #endif ++ { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); ++ } ++ pwdinfo->intent = 1; ++ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_LISTEN); ++ } ++ else if (role == P2P_ROLE_CLIENT) ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ pwdinfo->intent = 1; ++ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ } ++ else if (role == P2P_ROLE_GO) ++ { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ pwdinfo->intent = 15; ++ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ } ++ ++// Use the OFDM rate in the P2P probe response frame. ( 6(B), 9(B), 12, 18, 24, 36, 48, 54 ) ++ pwdinfo->support_rate[0] = 0x8c; // 6(B) ++ pwdinfo->support_rate[1] = 0x92; // 9(B) ++ pwdinfo->support_rate[2] = 0x18; // 12 ++ pwdinfo->support_rate[3] = 0x24; // 18 ++ pwdinfo->support_rate[4] = 0x30; // 24 ++ pwdinfo->support_rate[5] = 0x48; // 36 ++ pwdinfo->support_rate[6] = 0x60; // 48 ++ pwdinfo->support_rate[7] = 0x6c; // 54 ++ ++ _rtw_memcpy( ( void* ) pwdinfo->p2p_wildcard_ssid, "DIRECT-", 7 ); ++ ++ _rtw_memset( pwdinfo->device_name, 0x00, WPS_MAX_DEVICE_NAME_LEN ); ++ pwdinfo->device_name_len = 0; ++ ++ _rtw_memset( &pwdinfo->invitereq_info, 0x00, sizeof( struct tx_invite_req_info ) ); ++ pwdinfo->invitereq_info.token = 3; // Token used for P2P invitation request frame. ++ ++ _rtw_memset( &pwdinfo->inviteresp_info, 0x00, sizeof( struct tx_invite_resp_info ) ); ++ pwdinfo->inviteresp_info.token = 0; ++ ++ pwdinfo->profileindex = 0; ++ _rtw_memset( &pwdinfo->profileinfo[ 0 ], 0x00, sizeof( struct profile_info ) * P2P_MAX_PERSISTENT_GROUP_NUM ); ++ ++ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE); ++ ++ pwdinfo->listen_dwell = ( u8 ) (( rtw_get_current_time() % 3 ) + 1); ++ //DBG_8192C( "[%s] listen_dwell time is %d00ms\n", __FUNCTION__, pwdinfo->listen_dwell ); ++ ++ _rtw_memset( &pwdinfo->tx_prov_disc_info, 0x00, sizeof( struct tx_provdisc_req_info ) ); ++ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_NONE; ++ ++ _rtw_memset( &pwdinfo->nego_req_info, 0x00, sizeof( struct tx_nego_req_info ) ); ++ ++ pwdinfo->device_password_id_for_nego = WPS_DPID_PBC; ++ pwdinfo->negotiation_dialog_token = 1; ++ ++ _rtw_memset( pwdinfo->nego_ssid, 0x00, WLAN_SSID_MAXLEN ); ++ pwdinfo->nego_ssidlen = 0; ++ ++ pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO; ++#ifdef CONFIG_WFD ++ pwdinfo->supported_wps_cm = WPS_CONFIG_METHOD_DISPLAY | WPS_CONFIG_METHOD_PBC; ++ pwdinfo->wfd_info = pwfd_info; ++#else ++ pwdinfo->supported_wps_cm = WPS_CONFIG_METHOD_DISPLAY | WPS_CONFIG_METHOD_PBC | WPS_CONFIG_METHOD_KEYPAD; ++#endif //CONFIG_WFD ++ pwdinfo->channel_list_attr_len = 0; ++ _rtw_memset( pwdinfo->channel_list_attr, 0x00, 100 ); ++ ++ _rtw_memset( pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, 0x00, 4 ); ++ _rtw_memset( pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, '0', 3 ); ++ _rtw_memset( &pwdinfo->groupid_info, 0x00, sizeof( struct group_id_info ) ); ++#ifdef CONFIG_CONCURRENT_MODE ++#ifdef CONFIG_IOCTL_CFG80211 ++ pwdinfo->ext_listen_interval = 1000; //The interval to be available with legacy AP during p2p0-find/scan ++ pwdinfo->ext_listen_period = 3000; //The time period to be available for P2P during nego ++#else //!CONFIG_IOCTL_CFG80211 ++ //pwdinfo->ext_listen_interval = 3000; ++ //pwdinfo->ext_listen_period = 400; ++ pwdinfo->ext_listen_interval = 1000; ++ pwdinfo->ext_listen_period = 1000; ++#endif //!CONFIG_IOCTL_CFG80211 ++#endif ++ ++// Commented by Kurt 20130319 ++// For WiDi purpose: Use CFG80211 interface but controled WFD/RDS frame by driver itself. ++#ifdef CONFIG_IOCTL_CFG80211 ++ pwdinfo->driver_interface = DRIVER_CFG80211; ++#else ++ pwdinfo->driver_interface = DRIVER_WEXT; ++#endif //CONFIG_IOCTL_CFG80211 ++ ++ pwdinfo->wfd_tdls_enable = 0; ++ _rtw_memset( pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN ); ++ _rtw_memset( pwdinfo->p2p_peer_device_addr, 0x00, ETH_ALEN ); ++ ++ pwdinfo->rx_invitereq_info.operation_ch[0] = 0; ++ pwdinfo->rx_invitereq_info.operation_ch[1] = 0; // Used to indicate the scan end in site survey function ++#ifdef P2P_OP_CHECK_SOCIAL_CH ++ pwdinfo->rx_invitereq_info.operation_ch[2] = 0; ++ pwdinfo->rx_invitereq_info.operation_ch[3] = 0; ++ pwdinfo->rx_invitereq_info.operation_ch[4] = 0; ++#endif //P2P_OP_CHECK_SOCIAL_CH ++ pwdinfo->rx_invitereq_info.scan_op_ch_only = 0; ++ pwdinfo->p2p_info.operation_ch[0] = 0; ++ pwdinfo->p2p_info.operation_ch[1] = 0; // Used to indicate the scan end in site survey function ++#ifdef P2P_OP_CHECK_SOCIAL_CH ++ pwdinfo->p2p_info.operation_ch[2] = 0; ++ pwdinfo->p2p_info.operation_ch[3] = 0; ++ pwdinfo->p2p_info.operation_ch[4] = 0; ++#endif //P2P_OP_CHECK_SOCIAL_CH ++ pwdinfo->p2p_info.scan_op_ch_only = 0; ++} ++ ++#ifdef CONFIG_DBG_P2P ++ ++/** ++ * rtw_p2p_role_txt - Get the p2p role name as a text string ++ * @role: P2P role ++ * Returns: The state name as a printable text string ++ */ ++const char * rtw_p2p_role_txt(enum P2P_ROLE role) ++{ ++ switch (role) { ++ case P2P_ROLE_DISABLE: ++ return "P2P_ROLE_DISABLE"; ++ case P2P_ROLE_DEVICE: ++ return "P2P_ROLE_DEVICE"; ++ case P2P_ROLE_CLIENT: ++ return "P2P_ROLE_CLIENT"; ++ case P2P_ROLE_GO: ++ return "P2P_ROLE_GO"; ++ default: ++ return "UNKNOWN"; ++ } ++} ++ ++/** ++ * rtw_p2p_state_txt - Get the p2p state name as a text string ++ * @state: P2P state ++ * Returns: The state name as a printable text string ++ */ ++const char * rtw_p2p_state_txt(enum P2P_STATE state) ++{ ++ switch (state) { ++ case P2P_STATE_NONE: ++ return "P2P_STATE_NONE"; ++ case P2P_STATE_IDLE: ++ return "P2P_STATE_IDLE"; ++ case P2P_STATE_LISTEN: ++ return "P2P_STATE_LISTEN"; ++ case P2P_STATE_SCAN: ++ return "P2P_STATE_SCAN"; ++ case P2P_STATE_FIND_PHASE_LISTEN: ++ return "P2P_STATE_FIND_PHASE_LISTEN"; ++ case P2P_STATE_FIND_PHASE_SEARCH: ++ return "P2P_STATE_FIND_PHASE_SEARCH"; ++ case P2P_STATE_TX_PROVISION_DIS_REQ: ++ return "P2P_STATE_TX_PROVISION_DIS_REQ"; ++ case P2P_STATE_RX_PROVISION_DIS_RSP: ++ return "P2P_STATE_RX_PROVISION_DIS_RSP"; ++ case P2P_STATE_RX_PROVISION_DIS_REQ: ++ return "P2P_STATE_RX_PROVISION_DIS_REQ"; ++ case P2P_STATE_GONEGO_ING: ++ return "P2P_STATE_GONEGO_ING"; ++ case P2P_STATE_GONEGO_OK: ++ return "P2P_STATE_GONEGO_OK"; ++ case P2P_STATE_GONEGO_FAIL: ++ return "P2P_STATE_GONEGO_FAIL"; ++ case P2P_STATE_RECV_INVITE_REQ_MATCH: ++ return "P2P_STATE_RECV_INVITE_REQ_MATCH"; ++ case P2P_STATE_PROVISIONING_ING: ++ return "P2P_STATE_PROVISIONING_ING"; ++ case P2P_STATE_PROVISIONING_DONE: ++ return "P2P_STATE_PROVISIONING_DONE"; ++ case P2P_STATE_TX_INVITE_REQ: ++ return "P2P_STATE_TX_INVITE_REQ"; ++ case P2P_STATE_RX_INVITE_RESP_OK: ++ return "P2P_STATE_RX_INVITE_RESP_OK"; ++ case P2P_STATE_RECV_INVITE_REQ_DISMATCH: ++ return "P2P_STATE_RECV_INVITE_REQ_DISMATCH"; ++ case P2P_STATE_RECV_INVITE_REQ_GO: ++ return "P2P_STATE_RECV_INVITE_REQ_GO"; ++ case P2P_STATE_RECV_INVITE_REQ_JOIN: ++ return "P2P_STATE_RECV_INVITE_REQ_JOIN"; ++ case P2P_STATE_RX_INVITE_RESP_FAIL: ++ return "P2P_STATE_RX_INVITE_RESP_FAIL"; ++ case P2P_STATE_RX_INFOR_NOREADY: ++ return "P2P_STATE_RX_INFOR_NOREADY"; ++ case P2P_STATE_TX_INFOR_NOREADY: ++ return "P2P_STATE_TX_INFOR_NOREADY"; ++ default: ++ return "UNKNOWN"; ++ } ++} ++ ++void dbg_rtw_p2p_set_state(struct wifidirect_info *wdinfo, enum P2P_STATE state, const char *caller, int line) ++{ ++ if(!_rtw_p2p_chk_state(wdinfo, state)) { ++ enum P2P_STATE old_state = _rtw_p2p_state(wdinfo); ++ _rtw_p2p_set_state(wdinfo, state); ++ DBG_871X("[CONFIG_DBG_P2P]%s:%d set_state from %s to %s\n", caller, line ++ , rtw_p2p_state_txt(old_state), rtw_p2p_state_txt(_rtw_p2p_state(wdinfo)) ++ ); ++ } else { ++ DBG_871X("[CONFIG_DBG_P2P]%s:%d set_state to same state %s\n", caller, line ++ , rtw_p2p_state_txt(_rtw_p2p_state(wdinfo)) ++ ); ++ } ++} ++void dbg_rtw_p2p_set_pre_state(struct wifidirect_info *wdinfo, enum P2P_STATE state, const char *caller, int line) ++{ ++ if(_rtw_p2p_pre_state(wdinfo) != state) { ++ enum P2P_STATE old_state = _rtw_p2p_pre_state(wdinfo); ++ _rtw_p2p_set_pre_state(wdinfo, state); ++ DBG_871X("[CONFIG_DBG_P2P]%s:%d set_pre_state from %s to %s\n", caller, line ++ , rtw_p2p_state_txt(old_state), rtw_p2p_state_txt(_rtw_p2p_pre_state(wdinfo)) ++ ); ++ } else { ++ DBG_871X("[CONFIG_DBG_P2P]%s:%d set_pre_state to same state %s\n", caller, line ++ , rtw_p2p_state_txt(_rtw_p2p_pre_state(wdinfo)) ++ ); ++ } ++} ++#if 0 ++void dbg_rtw_p2p_restore_state(struct wifidirect_info *wdinfo, const char *caller, int line) ++{ ++ if(wdinfo->pre_p2p_state != -1) { ++ DBG_871X("[CONFIG_DBG_P2P]%s:%d restore from %s to %s\n", caller, line ++ , p2p_state_str[wdinfo->p2p_state], p2p_state_str[wdinfo->pre_p2p_state] ++ ); ++ _rtw_p2p_restore_state(wdinfo); ++ } else { ++ DBG_871X("[CONFIG_DBG_P2P]%s:%d restore no pre state, cur state %s\n", caller, line ++ , p2p_state_str[wdinfo->p2p_state] ++ ); ++ } ++} ++#endif ++void dbg_rtw_p2p_set_role(struct wifidirect_info *wdinfo, enum P2P_ROLE role, const char *caller, int line) ++{ ++ if(wdinfo->role != role) { ++ enum P2P_ROLE old_role = wdinfo->role; ++ _rtw_p2p_set_role(wdinfo, role); ++ DBG_871X("[CONFIG_DBG_P2P]%s:%d set_role from %s to %s\n", caller, line ++ , rtw_p2p_role_txt(old_role), rtw_p2p_role_txt(wdinfo->role) ++ ); ++ } else { ++ DBG_871X("[CONFIG_DBG_P2P]%s:%d set_role to same role %s\n", caller, line ++ , rtw_p2p_role_txt(wdinfo->role) ++ ); ++ } ++} ++#endif //CONFIG_DBG_P2P ++ ++ ++int rtw_p2p_enable(_adapter *padapter, enum P2P_ROLE role) ++{ ++ int ret = _SUCCESS; ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ ++ if (role == P2P_ROLE_DEVICE || role == P2P_ROLE_CLIENT|| role == P2P_ROLE_GO) ++ { ++ u8 channel, ch_offset; ++ u16 bwmode; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct wifidirect_info *pbuddy_wdinfo = &pbuddy_adapter->wdinfo; ++ // Commented by Albert 2011/12/30 ++ // The driver just supports 1 P2P group operation. ++ // So, this function will do nothing if the buddy adapter had enabled the P2P function. ++ if(!rtw_p2p_chk_state(pbuddy_wdinfo, P2P_STATE_NONE)) ++ { ++ // The buddy adapter had enabled the P2P function. ++ return ret; ++ } ++#endif //CONFIG_CONCURRENT_MODE ++ ++ //leave IPS/Autosuspend ++ if (_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ // Added by Albert 2011/03/22 ++ // In the P2P mode, the driver should not support the b mode. ++ // So, the Tx packet shouldn't use the CCK rate ++ update_tx_basic_rate(padapter, WIRELESS_11AGN); ++ ++ //Enable P2P function ++ init_wifidirect_info(padapter, role); ++ ++ rtw_hal_set_odm_var(padapter,HAL_ODM_P2P_STATE,NULL,_TRUE); ++ #ifdef CONFIG_WFD ++ rtw_hal_set_odm_var(padapter,HAL_ODM_WIFI_DISPLAY_STATE,NULL,_TRUE); ++ #endif ++ ++ } ++ else if (role == P2P_ROLE_DISABLE) ++ { ++#ifdef CONFIG_INTEL_WIDI ++ if( padapter->mlmepriv.p2p_reject_disable == _TRUE ) ++ return ret; ++#endif //CONFIG_INTEL_WIDI ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 ) ++ wdev_to_priv(padapter->rtw_wdev)->p2p_enabled = _FALSE; ++#endif //CONFIG_IOCTL_CFG80211 ++ ++ if (_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ //Disable P2P function ++ if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ _cancel_timer_ex( &pwdinfo->find_phase_timer ); ++ _cancel_timer_ex( &pwdinfo->restore_p2p_state_timer ); ++ _cancel_timer_ex( &pwdinfo->pre_tx_scan_timer); ++ _cancel_timer_ex( &pwdinfo->reset_ch_sitesurvey); ++ _cancel_timer_ex( &pwdinfo->reset_ch_sitesurvey2); ++ reset_ch_sitesurvey_timer_process( padapter ); ++ reset_ch_sitesurvey_timer_process2( padapter ); ++ #ifdef CONFIG_CONCURRENT_MODE ++ _cancel_timer_ex( &pwdinfo->ap_p2p_switch_timer); ++ #endif ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE); ++ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_NONE); ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DISABLE); ++ _rtw_memset(&pwdinfo->rx_prov_disc_info, 0x00, sizeof(struct rx_provdisc_req_info)); ++ } ++ ++ rtw_hal_set_odm_var(padapter,HAL_ODM_P2P_STATE,NULL,_FALSE); ++ #ifdef CONFIG_WFD ++ rtw_hal_set_odm_var(padapter,HAL_ODM_WIFI_DISPLAY_STATE,NULL,_FALSE); ++ #endif ++ ++ //Restore to initial setting. ++ update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode); ++ ++#ifdef CONFIG_INTEL_WIDI ++ rtw_reset_widi_info(padapter); ++#endif //CONFIG_INTEL_WIDI ++ ++ //For WiDi purpose. ++#ifdef CONFIG_IOCTL_CFG80211 ++ pwdinfo->driver_interface = DRIVER_CFG80211; ++#else ++ pwdinfo->driver_interface = DRIVER_WEXT; ++#endif //CONFIG_IOCTL_CFG80211 ++ ++ } ++ ++exit: ++ return ret; ++} ++ ++#endif //CONFIG_P2P ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_pwrctrl.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_pwrctrl.c +new file mode 100644 +index 00000000..3ccfbfec +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_pwrctrl.c +@@ -0,0 +1,1926 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_PWRCTRL_C_ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_BT_COEXIST ++#include ++#endif ++ ++#ifdef CONFIG_IPS ++void _ips_enter(_adapter * padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ ++ if (padapter->hw_init_completed == _FALSE) { ++ DBG_871X("%s: hw_init_completed: %d\n", ++ __func__, padapter->hw_init_completed); ++ return; ++ } ++ ++ pwrpriv->bips_processing = _TRUE; ++ ++ // syn ips_mode with request ++ pwrpriv->ips_mode = pwrpriv->ips_mode_req; ++ ++ pwrpriv->ips_enter_cnts++; ++ DBG_871X("==>ips_enter cnts:%d\n",pwrpriv->ips_enter_cnts); ++#ifdef CONFIG_BT_COEXIST ++ BTDM_TurnOffBtCoexistBeforeEnterIPS(padapter); ++#endif ++ if(rf_off == pwrpriv->change_rfpwrstate ) ++ { ++ pwrpriv->bpower_saving = _TRUE; ++ DBG_871X_LEVEL(_drv_always_, "nolinked power save enter\n"); ++ ++ if(pwrpriv->ips_mode == IPS_LEVEL_2) ++ pwrpriv->bkeepfwalive = _TRUE; ++ ++ rtw_ips_pwr_down(padapter); ++ pwrpriv->rf_pwrstate = rf_off; ++ } ++ pwrpriv->bips_processing = _FALSE; ++ ++} ++ ++void ips_enter(_adapter * padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ ++ _enter_pwrlock(&pwrpriv->lock); ++ _ips_enter(padapter); ++ _exit_pwrlock(&pwrpriv->lock); ++} ++ ++int _ips_leave(_adapter * padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ int result = _SUCCESS; ++ ++ if((pwrpriv->rf_pwrstate == rf_off) &&(!pwrpriv->bips_processing)) ++ { ++ pwrpriv->bips_processing = _TRUE; ++ pwrpriv->change_rfpwrstate = rf_on; ++ pwrpriv->ips_leave_cnts++; ++ DBG_871X("==>ips_leave cnts:%d\n",pwrpriv->ips_leave_cnts); ++ ++ if ((result = rtw_ips_pwr_up(padapter)) == _SUCCESS) { ++ pwrpriv->rf_pwrstate = rf_on; ++ } ++ DBG_871X_LEVEL(_drv_always_, "nolinked power save leave\n"); ++ ++ DBG_871X("==> ips_leave.....LED(0x%08x)...\n",rtw_read32(padapter,0x4c)); ++ pwrpriv->bips_processing = _FALSE; ++ ++ pwrpriv->bkeepfwalive = _FALSE; ++ pwrpriv->bpower_saving = _FALSE; ++ } ++ ++ return result; ++} ++ ++int ips_leave(_adapter * padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ int ret; ++ ++ _enter_pwrlock(&pwrpriv->lock); ++ ret = _ips_leave(padapter); ++ _exit_pwrlock(&pwrpriv->lock); ++ ++ return ret; ++} ++#endif /* CONFIG_IPS */ ++ ++#ifdef CONFIG_AUTOSUSPEND ++extern void autosuspend_enter(_adapter* padapter); ++extern int autoresume_enter(_adapter* padapter); ++#endif ++ ++#ifdef SUPPORT_HW_RFOFF_DETECTED ++int rtw_hw_suspend(_adapter *padapter ); ++int rtw_hw_resume(_adapter *padapter); ++#endif ++ ++bool rtw_pwr_unassociated_idle(_adapter *adapter) ++{ ++ _adapter *buddy = adapter->pbuddy_adapter; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ struct xmit_priv *pxmit_priv = &adapter->xmitpriv; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo = &(adapter->wdinfo); ++#ifdef CONFIG_IOCTL_CFG80211 ++ struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &adapter->cfg80211_wdinfo; ++#endif ++#endif ++ ++ bool ret = _FALSE; ++ ++ if (adapter_to_pwrctl(adapter)->ips_deny_time >= rtw_get_current_time()) { ++ //DBG_871X("%s ips_deny_time\n", __func__); ++ goto exit; ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) ++ || check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) ++ || check_fwstate(pmlmepriv, WIFI_AP_STATE) ++ || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) ++ #if defined(CONFIG_P2P) && defined(CONFIG_IOCTL_CFG80211) && defined(CONFIG_P2P_IPS) ++ || pcfg80211_wdinfo->is_ro_ch ++ #elif defined(CONFIG_P2P) ++ || !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) ++ #endif ++ ) { ++ goto exit; ++ } ++ ++ /* consider buddy, if exist */ ++ if (buddy) { ++ struct mlme_priv *b_pmlmepriv = &(buddy->mlmepriv); ++ #ifdef CONFIG_P2P ++ struct wifidirect_info *b_pwdinfo = &(buddy->wdinfo); ++ #ifdef CONFIG_IOCTL_CFG80211 ++ struct cfg80211_wifidirect_info *b_pcfg80211_wdinfo = &buddy->cfg80211_wdinfo; ++ #endif ++ #endif ++ ++ if (check_fwstate(b_pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) ++ || check_fwstate(b_pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) ++ || check_fwstate(b_pmlmepriv, WIFI_AP_STATE) ++ || check_fwstate(b_pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) ++ #if defined(CONFIG_P2P) && defined(CONFIG_IOCTL_CFG80211) && defined(CONFIG_P2P_IPS) ++ || b_pcfg80211_wdinfo->is_ro_ch ++ #elif defined(CONFIG_P2P) ++ || !rtw_p2p_chk_state(b_pwdinfo, P2P_STATE_NONE) ++ #endif ++ ) { ++ goto exit; ++ } ++ } ++ ++#if (MP_DRIVER == 1) ++ if (adapter->registrypriv.mp_mode == 1) ++ goto exit; ++#endif ++ ++#ifdef CONFIG_INTEL_PROXIM ++ if(adapter->proximity.proxim_on==_TRUE){ ++ return; ++ } ++#endif ++ ++ if (pxmit_priv->free_xmitbuf_cnt != NR_XMITBUFF || ++ pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF) { ++ DBG_871X_LEVEL(_drv_always_, "There are some pkts to transmit\n"); ++ DBG_871X_LEVEL(_drv_info_, "free_xmitbuf_cnt: %d, free_xmit_extbuf_cnt: %d\n", ++ pxmit_priv->free_xmitbuf_cnt, pxmit_priv->free_xmit_extbuf_cnt); ++ goto exit; ++ } ++ ++ ret = _TRUE; ++ ++exit: ++ return ret; ++} ++ ++#if defined (PLATFORM_LINUX)||defined (PLATFORM_FREEBSD) ++void rtw_ps_processor(_adapter*padapter) ++{ ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++#endif //CONFIG_P2P ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++#ifdef SUPPORT_HW_RFOFF_DETECTED ++ rt_rf_power_state rfpwrstate; ++#endif //SUPPORT_HW_RFOFF_DETECTED ++ ++ pwrpriv->ps_processing = _TRUE; ++ ++#ifdef SUPPORT_HW_RFOFF_DETECTED ++ if(pwrpriv->bips_processing == _TRUE) ++ goto exit; ++ ++ //DBG_871X("==> fw report state(0x%x)\n",rtw_read8(padapter,0x1ca)); ++ if(pwrpriv->bHWPwrPindetect) ++ { ++ #ifdef CONFIG_AUTOSUSPEND ++ if(padapter->registrypriv.usbss_enable) ++ { ++ if(pwrpriv->rf_pwrstate == rf_on) ++ { ++ if(padapter->net_closed == _TRUE) ++ pwrpriv->ps_flag = _TRUE; ++ ++ rfpwrstate = RfOnOffDetect(padapter); ++ DBG_871X("@@@@- #1 %s==> rfstate:%s \n",__FUNCTION__,(rfpwrstate==rf_on)?"rf_on":"rf_off"); ++ if(rfpwrstate!= pwrpriv->rf_pwrstate) ++ { ++ if(rfpwrstate == rf_off) ++ { ++ pwrpriv->change_rfpwrstate = rf_off; ++ ++ pwrpriv->bkeepfwalive = _TRUE; ++ pwrpriv->brfoffbyhw = _TRUE; ++ ++ autosuspend_enter(padapter); ++ } ++ } ++ } ++ } ++ else ++ #endif //CONFIG_AUTOSUSPEND ++ { ++ rfpwrstate = RfOnOffDetect(padapter); ++ DBG_871X("@@@@- #2 %s==> rfstate:%s \n",__FUNCTION__,(rfpwrstate==rf_on)?"rf_on":"rf_off"); ++ ++ if(rfpwrstate!= pwrpriv->rf_pwrstate) ++ { ++ if(rfpwrstate == rf_off) ++ { ++ pwrpriv->change_rfpwrstate = rf_off; ++ pwrpriv->brfoffbyhw = _TRUE; ++ padapter->bCardDisableWOHSM = _TRUE; ++ rtw_hw_suspend(padapter ); ++ } ++ else ++ { ++ pwrpriv->change_rfpwrstate = rf_on; ++ rtw_hw_resume(padapter ); ++ } ++ DBG_871X("current rf_pwrstate(%s)\n",(pwrpriv->rf_pwrstate == rf_off)?"rf_off":"rf_on"); ++ } ++ } ++ pwrpriv->pwr_state_check_cnts ++; ++ } ++#endif //SUPPORT_HW_RFOFF_DETECTED ++ ++ if (pwrpriv->ips_mode_req == IPS_NONE) ++ goto exit; ++ ++ if (rtw_pwr_unassociated_idle(padapter) == _FALSE) ++ goto exit; ++ ++ if((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts%4)==0)) ++ { ++ DBG_871X("==>%s .fw_state(%x)\n",__FUNCTION__,get_fwstate(pmlmepriv)); ++ #if defined (CONFIG_BT_COEXIST)&& defined (CONFIG_AUTOSUSPEND) ++ #else ++ pwrpriv->change_rfpwrstate = rf_off; ++ #endif ++ #ifdef CONFIG_AUTOSUSPEND ++ if(padapter->registrypriv.usbss_enable) ++ { ++ if(pwrpriv->bHWPwrPindetect) ++ pwrpriv->bkeepfwalive = _TRUE; ++ ++ if(padapter->net_closed == _TRUE) ++ pwrpriv->ps_flag = _TRUE; ++ ++ #if defined (CONFIG_BT_COEXIST)&& defined (CONFIG_AUTOSUSPEND) ++ if (_TRUE==pwrpriv->bInternalAutoSuspend) { ++ DBG_871X("<==%s .pwrpriv->bInternalAutoSuspend)(%x)\n",__FUNCTION__,pwrpriv->bInternalAutoSuspend); ++ } else { ++ pwrpriv->change_rfpwrstate = rf_off; ++ padapter->bCardDisableWOHSM = _TRUE; ++ DBG_871X("<==%s .pwrpriv->bInternalAutoSuspend)(%x) call autosuspend_enter\n",__FUNCTION__,pwrpriv->bInternalAutoSuspend); ++ autosuspend_enter(padapter); ++ } ++ #else ++ padapter->bCardDisableWOHSM = _TRUE; ++ autosuspend_enter(padapter); ++ #endif //if defined (CONFIG_BT_COEXIST)&& defined (CONFIG_AUTOSUSPEND) ++ } ++ else if(pwrpriv->bHWPwrPindetect) ++ { ++ } ++ else ++ #endif //CONFIG_AUTOSUSPEND ++ { ++ #if defined (CONFIG_BT_COEXIST)&& defined (CONFIG_AUTOSUSPEND) ++ pwrpriv->change_rfpwrstate = rf_off; ++ #endif //defined (CONFIG_BT_COEXIST)&& defined (CONFIG_AUTOSUSPEND) ++ ++ #ifdef CONFIG_IPS ++ ips_enter(padapter); ++ #endif ++ } ++ } ++exit: ++ rtw_set_pwr_state_check_timer(pwrpriv); ++ pwrpriv->ps_processing = _FALSE; ++ return; ++} ++ ++void pwr_state_check_handler(void *FunctionContext); ++void pwr_state_check_handler(void *FunctionContext) ++{ ++ _adapter *padapter = (_adapter *)FunctionContext; ++ rtw_ps_cmd(padapter); ++} ++#endif ++ ++ ++ ++#ifdef CONFIG_LPS ++/* ++ * ++ * Parameters ++ * padapter ++ * pslv power state level, only could be PS_STATE_S0 ~ PS_STATE_S4 ++ * ++ */ ++void rtw_set_rpwm(PADAPTER padapter, u8 pslv) ++{ ++ u8 rpwm; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++#ifdef CONFIG_DETECT_CPWM_BY_POLLING ++ u8 cpwm_orig = 0; ++ u8 cpwm_now = 0; ++ u32 cpwm_polling_start_time = 0; ++ u8 pollingRes = _FAIL; ++#endif ++ ++_func_enter_; ++ ++ pslv = PS_STATE(pslv); ++ ++ ++ if (_TRUE == pwrpriv->btcoex_rfon) ++ { ++ if (pslv < PS_STATE_S4) ++ pslv = PS_STATE_S3; ++ } ++ ++#ifdef CONFIG_LPS_RPWM_TIMER ++ if (pwrpriv->brpwmtimeout == _TRUE) ++ { ++ DBG_871X("%s: RPWM timeout, force to set RPWM(0x%02X) again!\n", __FUNCTION__, pslv); ++ } ++ else ++#endif // CONFIG_LPS_RPWM_TIMER ++ { ++ if ( (pwrpriv->rpwm == pslv) ++#ifdef CONFIG_LPS_LCLK ++#ifndef CONFIG_RTL8723A ++ || ((pwrpriv->rpwm >= PS_STATE_S2)&&(pslv >= PS_STATE_S2)) ++#endif ++#endif ++ ) ++ { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_,_drv_err_, ++ ("%s: Already set rpwm[0x%02X], new=0x%02X!\n", __FUNCTION__, pwrpriv->rpwm, pslv)); ++ return; ++ } ++ } ++ ++ if ((padapter->bSurpriseRemoved == _TRUE) || ++ (padapter->hw_init_completed == _FALSE)) ++ { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ++ ("%s: SurpriseRemoved(%d) hw_init_completed(%d)\n", ++ __FUNCTION__, padapter->bSurpriseRemoved, padapter->hw_init_completed)); ++ ++ pwrpriv->cpwm = PS_STATE_S4; ++ ++ return; ++ } ++ ++ if (padapter->bDriverStopped == _TRUE) ++ { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ++ ("%s: change power state(0x%02X) when DriverStopped\n", __FUNCTION__, pslv)); ++ ++ if (pslv < PS_STATE_S2) { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ++ ("%s: Reject to enter PS_STATE(0x%02X) lower than S2 when DriverStopped!!\n", __FUNCTION__, pslv)); ++ return; ++ } ++ } ++ ++ rpwm = pslv | pwrpriv->tog; ++#ifdef CONFIG_LPS_LCLK ++ // only when from PS_STATE S0/S1 to S2 and higher needs ACK ++ if ((pwrpriv->cpwm < PS_STATE_S2) && (pslv >= PS_STATE_S2)) ++ rpwm |= PS_ACK; ++#endif ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ++ ("rtw_set_rpwm: rpwm=0x%02x cpwm=0x%02x\n", rpwm, pwrpriv->cpwm)); ++ ++ pwrpriv->rpwm = pslv; ++ ++#ifdef CONFIG_DETECT_CPWM_BY_POLLING ++ if (rpwm & PS_ACK) ++ { ++ //cpwm_orig = rtw_read8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HCPWM1); ++ rtw_hal_get_hwreg(padapter, HW_VAR_GET_CPWM, (u8 *)(&cpwm_orig)); ++ } ++#endif ++ ++#if defined(CONFIG_LPS_RPWM_TIMER) && !defined(CONFIG_DETECT_CPWM_BY_POLLING) ++ if (rpwm & PS_ACK) ++ _set_timer(&pwrpriv->pwr_rpwm_timer, LPS_RPWM_WAIT_MS); ++#endif // CONFIG_LPS_RPWM_TIMER && !CONFIG_DETECT_CPWM_BY_POLLING ++ rtw_hal_set_hwreg(padapter, HW_VAR_SET_RPWM, (u8 *)(&rpwm)); ++ ++ pwrpriv->tog += 0x80; ++ ++#ifdef CONFIG_LPS_LCLK ++ // No LPS 32K, No Ack ++ if (!(rpwm & PS_ACK)) ++#endif ++ { ++ pwrpriv->cpwm = pslv; ++ } ++ ++#ifdef CONFIG_DETECT_CPWM_BY_POLLING ++ if (rpwm & PS_ACK) ++ { ++ cpwm_polling_start_time = rtw_get_current_time(); ++ ++ //polling cpwm ++ do{ ++ rtw_mdelay_os(1); ++ ++ //cpwm_now = rtw_read8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HCPWM1); ++ rtw_hal_get_hwreg(padapter, HW_VAR_GET_CPWM, (u8 *)(&cpwm_now)); ++ if ((cpwm_orig ^ cpwm_now) & 0x80) ++ { ++#ifdef CONFIG_LPS_LCLK ++ #ifdef CONFIG_RTL8723A ++ pwrpriv->cpwm = PS_STATE(cpwm_now); ++ #else // !CONFIG_RTL8723A ++ pwrpriv->cpwm = PS_STATE_S4; ++ #endif // !CONFIG_RTL8723A ++ pwrpriv->cpwm_tog = cpwm_now & PS_TOGGLE; ++#endif ++ pollingRes = _SUCCESS; ++ break; ++ } ++ }while (rtw_get_passing_time_ms(cpwm_polling_start_time) < LPS_RPWM_WAIT_MS); ++ ++ if (pollingRes == _FAIL) ++ { ++#ifdef CONFIG_LPS_RPWM_TIMER ++ _set_timer(&pwrpriv->pwr_rpwm_timer, 1); ++#endif ++ DBG_871X("%s polling cpwm timeout!!!!!!!!!!\n", __FUNCTION__); ++ } ++ } ++#endif ++ ++_func_exit_; ++} ++ ++u8 PS_RDY_CHECK(_adapter * padapter); ++u8 PS_RDY_CHECK(_adapter * padapter) ++{ ++ u32 curr_time, delta_time; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++#ifdef CONFIG_WOWLAN ++ if(_TRUE == pwrpriv->bInSuspend && pwrpriv->wowlan_mode) ++ return _TRUE; ++ else if (_TRUE == pwrpriv->bInSuspend) ++ return _FALSE; ++#else ++ if(_TRUE == pwrpriv->bInSuspend ) ++ return _FALSE; ++#endif ++ ++ curr_time = rtw_get_current_time(); ++ delta_time = curr_time -pwrpriv->DelayLPSLastTimeStamp; ++ ++ if(delta_time < LPS_DELAY_TIME) ++ { ++ return _FALSE; ++ } ++ ++ if ((check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE) || ++ (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) || ++ (check_fwstate(pmlmepriv, WIFI_UNDER_WPS) == _TRUE) || ++ (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) ) ++ return _FALSE; ++ ++ if( (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && (padapter->securitypriv.binstallGrpkey == _FALSE) ) ++ { ++ DBG_871X("Group handshake still in progress !!!\n"); ++ return _FALSE; ++ } ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if (!rtw_cfg80211_pwr_mgmt(padapter)) ++ return _FALSE; ++#endif ++ ++ return _TRUE; ++} ++ ++void rtw_set_ps_mode(PADAPTER padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++#endif //CONFIG_P2P ++#ifdef CONFIG_TDLS ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ _irqL irqL; ++ int i, j; ++ _list *plist, *phead; ++ struct sta_info *ptdls_sta; ++#endif //CONFIG_TDLS ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ++ ("%s: PowerMode=%d Smart_PS=%d\n", ++ __FUNCTION__, ps_mode, smart_ps)); ++ ++ if(ps_mode > PM_Card_Disable) { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_,_drv_err_,("ps_mode:%d error\n", ps_mode)); ++ return; ++ } ++ ++ if (pwrpriv->pwr_mode == ps_mode) ++ { ++ if (PS_MODE_ACTIVE == ps_mode) return; ++ ++ if ((pwrpriv->smart_ps == smart_ps) && ++ (pwrpriv->bcn_ant_mode == bcn_ant_mode)) ++ { ++ return; ++ } ++ } ++ ++#ifdef CONFIG_LPS_LCLK ++ _enter_pwrlock(&pwrpriv->lock); ++#endif ++ ++ //if(pwrpriv->pwr_mode == PS_MODE_ACTIVE) ++ if(ps_mode == PS_MODE_ACTIVE) ++ { ++#ifdef CONFIG_P2P_PS ++ if(pwdinfo->opp_ps == 0) ++#endif //CONFIG_P2P_PS ++ { ++ DBG_871X("rtw_set_ps_mode: Leave 802.11 power save\n"); ++ ++#ifdef CONFIG_TDLS ++ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ ++ for(i=0; i< NUM_STA; i++) ++ { ++ phead = &(pstapriv->sta_hash[i]); ++ plist = get_next(phead); ++ ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ ptdls_sta = LIST_CONTAINOR(plist, struct sta_info, hash_list); ++ ++ if( ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE ) ++ issue_nulldata_to_TDLS_peer_STA(padapter, ptdls_sta, 0); ++ plist = get_next(plist); ++ } ++ } ++ ++ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++#endif //CONFIG_TDLS ++ ++ pwrpriv->pwr_mode = ps_mode; ++ rtw_set_rpwm(padapter, PS_STATE_S4); ++#ifdef CONFIG_WOWLAN ++ if (pwrpriv->wowlan_mode == _TRUE) ++ { ++ u32 start_time, delay_ms; ++ u8 val8; ++ delay_ms = 20; ++ start_time = rtw_get_current_time(); ++ do { ++ rtw_hal_get_hwreg(padapter, HW_VAR_SYS_CLKR, &val8); ++ if (!(val8 & BIT(4))){ //0x08 bit4 =1 --> in 32k, bit4 = 0 --> leave 32k ++ pwrpriv->cpwm = PS_STATE_S4; ++ break; ++ } ++ if (rtw_get_passing_time_ms(start_time) > delay_ms) ++ { ++ DBG_871X("%s: Wait for FW 32K leave more than %u ms!!!\n", __FUNCTION__, delay_ms); ++ break; ++ } ++ rtw_usleep_os(100); ++ } while (1); ++ } ++#endif ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); ++ pwrpriv->bFwCurrentInPSMode = _FALSE; ++ } ++ } ++ else ++ { ++ if (PS_RDY_CHECK(padapter) ++#ifdef CONFIG_BT_COEXIST ++ || (BT_1Ant(padapter) == _TRUE) ++#endif ++ ) ++ { ++ DBG_871X("%s: Enter 802.11 power save\n", __FUNCTION__); ++ ++#ifdef CONFIG_TDLS ++ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ ++ for(i=0; i< NUM_STA; i++) ++ { ++ phead = &(pstapriv->sta_hash[i]); ++ plist = get_next(phead); ++ ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ ptdls_sta = LIST_CONTAINOR(plist, struct sta_info, hash_list); ++ ++ if( ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE ) ++ issue_nulldata_to_TDLS_peer_STA(padapter, ptdls_sta, 1); ++ plist = get_next(plist); ++ } ++ } ++ ++ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++#endif //CONFIG_TDLS ++ ++ pwrpriv->bFwCurrentInPSMode = _TRUE; ++ pwrpriv->pwr_mode = ps_mode; ++ pwrpriv->smart_ps = smart_ps; ++ pwrpriv->bcn_ant_mode = bcn_ant_mode; ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); ++ ++#ifdef CONFIG_P2P_PS ++ // Set CTWindow after LPS ++ if(pwdinfo->opp_ps == 1) ++ p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 0); ++#endif //CONFIG_P2P_PS ++ ++#ifdef CONFIG_LPS_LCLK ++ DBG_871X("%s: alives: %d\n", __FUNCTION__, pwrpriv->alives); ++ if (pwrpriv->alives == 0) ++ rtw_set_rpwm(padapter, PS_STATE_S0); ++#else ++ rtw_set_rpwm(padapter, PS_STATE_S2); ++#endif ++ } ++ } ++ ++#ifdef CONFIG_LPS_LCLK ++ _exit_pwrlock(&pwrpriv->lock); ++#endif ++ ++_func_exit_; ++} ++ ++/* ++ * Return: ++ * 0: Leave OK ++ * -1: Timeout ++ * -2: Other error ++ */ ++s32 LPS_RF_ON_check(PADAPTER padapter, u32 delay_ms) ++{ ++ u32 start_time; ++ u8 bAwake = _FALSE; ++ s32 err = 0; ++ ++ ++ start_time = rtw_get_current_time(); ++ while (1) ++ { ++ rtw_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake); ++ if (_TRUE == bAwake) ++ break; ++ ++ if (_TRUE == padapter->bSurpriseRemoved) ++ { ++ err = -2; ++ DBG_871X("%s: device surprise removed!!\n", __FUNCTION__); ++ break; ++ } ++ ++ if (rtw_get_passing_time_ms(start_time) > delay_ms) ++ { ++ err = -1; ++ DBG_871X("%s: Wait for FW LPS leave more than %u ms!!!\n", __FUNCTION__, delay_ms); ++ break; ++ } ++ rtw_usleep_os(100); ++ } ++ ++ return err; ++} ++ ++// ++// Description: ++// Enter the leisure power save mode. ++// ++void LPS_Enter(PADAPTER padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ _adapter *buddy = padapter->pbuddy_adapter; ++ ++_func_enter_; ++ ++// DBG_871X("+LeisurePSEnter\n"); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (padapter->iface_type != IFACE_PORT0) ++ return; /* Skip power saving for concurrent mode port 1*/ ++ ++ /* consider buddy, if exist */ ++ if (buddy) { ++ struct mlme_priv *b_pmlmepriv = &(buddy->mlmepriv); ++ #ifdef CONFIG_P2P ++ struct wifidirect_info *b_pwdinfo = &(buddy->wdinfo); ++ #ifdef CONFIG_IOCTL_CFG80211 ++ struct cfg80211_wifidirect_info *b_pcfg80211_wdinfo = &buddy->cfg80211_wdinfo; ++ #endif ++ #endif ++ ++ if (check_fwstate(b_pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) ++ || check_fwstate(b_pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) ++ || check_fwstate(b_pmlmepriv, WIFI_AP_STATE) ++ || check_fwstate(b_pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) ++ #if defined(CONFIG_P2P) && defined(CONFIG_IOCTL_CFG80211) && defined(CONFIG_P2P_IPS) ++ || b_pcfg80211_wdinfo->is_ro_ch ++ #elif defined(CONFIG_P2P) ++ || !rtw_p2p_chk_state(b_pwdinfo, P2P_STATE_NONE) ++ #endif ++ || rtw_is_scan_deny(buddy) ++ ) { ++ return; ++ } ++ } ++#endif ++ ++ if (PS_RDY_CHECK(padapter) == _FALSE) ++ return; ++ ++ if (_TRUE == pwrpriv->bLeisurePs) ++ { ++ // Idle for a while if we connect to AP a while ago. ++ if(pwrpriv->LpsIdleCount >= 2) // 4 Sec ++ { ++ if(pwrpriv->pwr_mode == PS_MODE_ACTIVE) ++ { ++ pwrpriv->bpower_saving = _TRUE; ++ DBG_871X("%s smart_ps:%d\n", __func__, pwrpriv->smart_ps); ++ //For Tenda W311R IOT issue ++ rtw_set_ps_mode(padapter, pwrpriv->power_mgnt, pwrpriv->smart_ps, 0x40); ++ } ++ } ++ else ++ pwrpriv->LpsIdleCount++; ++ } ++ ++// DBG_871X("-LeisurePSEnter\n"); ++ ++_func_exit_; ++} ++ ++// ++// Description: ++// Leave the leisure power save mode. ++// ++void LPS_Leave(PADAPTER padapter) ++{ ++#define LPS_LEAVE_TIMEOUT_MS 100 ++ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ u32 start_time; ++ u8 bAwake = _FALSE; ++ ++_func_enter_; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (padapter->iface_type != IFACE_PORT0) ++ return; /* Skip power saving for concurrent mode port 1*/ ++#endif ++ ++// DBG_871X("+LeisurePSLeave\n"); ++ ++ if (pwrpriv->bLeisurePs) ++ { ++ if(pwrpriv->pwr_mode != PS_MODE_ACTIVE) ++ { ++ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0x40); ++ ++ if(pwrpriv->pwr_mode == PS_MODE_ACTIVE) ++ LPS_RF_ON_check(padapter, LPS_LEAVE_TIMEOUT_MS); ++ } ++ } ++ ++ pwrpriv->bpower_saving = _FALSE; ++ ++// DBG_871X("-LeisurePSLeave\n"); ++ ++_func_exit_; ++} ++#endif ++ ++// ++// Description: Leave all power save mode: LPS, FwLPS, IPS if needed. ++// Move code to function by tynli. 2010.03.26. ++// ++void LeaveAllPowerSaveMode(IN PADAPTER Adapter) ++{ ++ struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); ++ u8 enqueue = 0; ++ ++_func_enter_; ++ ++ //DBG_871X("%s.....\n",__FUNCTION__); ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ++ { //connect ++#ifdef CONFIG_LPS_LCLK ++ enqueue = 1; ++#endif ++ ++#ifdef CONFIG_P2P_PS ++ p2p_ps_wk_cmd(Adapter, P2P_PS_DISABLE, enqueue); ++#endif //CONFIG_P2P_PS ++ ++#ifdef CONFIG_LPS ++ rtw_lps_ctrl_wk_cmd(Adapter, LPS_CTRL_LEAVE, enqueue); ++#endif ++ ++#ifdef CONFIG_LPS_LCLK ++ LPS_Leave_check(Adapter); ++#endif ++ } ++ else ++ { ++ if(adapter_to_pwrctl(Adapter)->rf_pwrstate== rf_off) ++ { ++ #ifdef CONFIG_AUTOSUSPEND ++ if(Adapter->registrypriv.usbss_enable) ++ { ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)) ++ usb_disable_autosuspend(adapter_to_dvobj(Adapter)->pusbdev); ++ #elif (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,22) && LINUX_VERSION_CODE<=KERNEL_VERSION(2,6,34)) ++ adapter_to_dvobj(Adapter)->pusbdev->autosuspend_disabled = Adapter->bDisableAutosuspend;//autosuspend disabled by the user ++ #endif ++ } ++ else ++ #endif ++ { ++#if defined(CONFIG_PLATFORM_SPRD) && defined(CONFIG_RTL8188E) ++ #ifdef CONFIG_IPS ++ if(_FALSE == ips_leave(Adapter)) ++ { ++ DBG_871X("======> ips_leave fail.............\n"); ++ } ++ #endif ++#endif //CONFIG_PLATFORM_SPRD && CONFIG_RTL8188E ++ } ++ } ++ } ++ ++_func_exit_; ++} ++ ++#ifdef CONFIG_LPS_LCLK ++void LPS_Leave_check( ++ PADAPTER padapter) ++{ ++ struct pwrctrl_priv *pwrpriv; ++ u32 start_time; ++ u8 bReady; ++ ++_func_enter_; ++ ++ pwrpriv = adapter_to_pwrctl(padapter); ++ ++ bReady = _FALSE; ++ start_time = rtw_get_current_time(); ++ ++ rtw_yield_os(); ++ ++ while(1) ++ { ++ _enter_pwrlock(&pwrpriv->lock); ++ ++ if ((padapter->bSurpriseRemoved == _TRUE) ++ || (padapter->hw_init_completed == _FALSE) ++#ifdef CONFIG_USB_HCI ++ || (padapter->bDriverStopped== _TRUE) ++#endif ++ || (pwrpriv->pwr_mode == PS_MODE_ACTIVE) ++ ) ++ { ++ bReady = _TRUE; ++ } ++ ++ _exit_pwrlock(&pwrpriv->lock); ++ ++ if(_TRUE == bReady) ++ break; ++ ++ if(rtw_get_passing_time_ms(start_time)>100) ++ { ++ DBG_871X("Wait for cpwm event than 100 ms!!!\n"); ++ break; ++ } ++ rtw_msleep_os(1); ++ } ++ ++_func_exit_; ++} ++ ++/* ++ * Caller:ISR handler... ++ * ++ * This will be called when CPWM interrupt is up. ++ * ++ * using to update cpwn of drv; and drv willl make a decision to up or down pwr level ++ */ ++void cpwm_int_hdl( ++ PADAPTER padapter, ++ struct reportpwrstate_parm *preportpwrstate) ++{ ++ struct pwrctrl_priv *pwrpriv; ++ ++_func_enter_; ++ ++ pwrpriv = adapter_to_pwrctl(padapter); ++#if 0 ++ if (pwrpriv->cpwm_tog == (preportpwrstate->state & PS_TOGGLE)) { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ++ ("cpwm_int_hdl: tog(old)=0x%02x cpwm(new)=0x%02x toggle bit didn't change!?\n", ++ pwrpriv->cpwm_tog, preportpwrstate->state)); ++ goto exit; ++ } ++#endif ++ ++ _enter_pwrlock(&pwrpriv->lock); ++ ++#ifdef CONFIG_LPS_RPWM_TIMER ++ if (pwrpriv->rpwm < PS_STATE_S2) ++ { ++ DBG_871X("%s: Redundant CPWM Int. RPWM=0x%02X CPWM=0x%02x\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); ++ _exit_pwrlock(&pwrpriv->lock); ++ goto exit; ++ } ++#endif // CONFIG_LPS_RPWM_TIMER ++ ++ pwrpriv->cpwm = PS_STATE(preportpwrstate->state); ++ pwrpriv->cpwm_tog = preportpwrstate->state & PS_TOGGLE; ++ ++ if (pwrpriv->cpwm >= PS_STATE_S2) ++ { ++ if (pwrpriv->alives & CMD_ALIVE) ++ _rtw_up_sema(&padapter->cmdpriv.cmd_queue_sema); ++ ++ if (pwrpriv->alives & XMIT_ALIVE) ++ _rtw_up_sema(&padapter->xmitpriv.xmit_sema); ++ } ++ ++ _exit_pwrlock(&pwrpriv->lock); ++ ++exit: ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ++ ("cpwm_int_hdl: cpwm=0x%02x\n", pwrpriv->cpwm)); ++ ++_func_exit_; ++} ++ ++static void cpwm_event_callback(struct work_struct *work) ++{ ++ struct pwrctrl_priv *pwrpriv = container_of(work, struct pwrctrl_priv, cpwm_event); ++ struct dvobj_priv *dvobj = pwrctl_to_dvobj(pwrpriv); ++ _adapter *adapter = dvobj->if1; ++ struct reportpwrstate_parm report; ++ ++ //DBG_871X("%s\n",__FUNCTION__); ++ ++ report.state = PS_STATE_S2; ++ cpwm_int_hdl(adapter, &report); ++} ++ ++#ifdef CONFIG_LPS_RPWM_TIMER ++static void rpwmtimeout_workitem_callback(struct work_struct *work) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *dvobj; ++ struct pwrctrl_priv *pwrpriv; ++ ++ ++ pwrpriv = container_of(work, struct pwrctrl_priv, rpwmtimeoutwi); ++ dvobj = pwrctl_to_dvobj(pwrpriv); ++ padapter = dvobj->if1; ++// DBG_871X("+%s: rpwm=0x%02X cpwm=0x%02X\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); ++ ++ _enter_pwrlock(&pwrpriv->lock); ++ if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2)) ++ { ++ DBG_871X("%s: rpwm=0x%02X cpwm=0x%02X CPWM done!\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); ++ goto exit; ++ } ++ _exit_pwrlock(&pwrpriv->lock); ++ ++ if (rtw_read8(padapter, 0x100) != 0xEA) ++ { ++#if 1 ++ struct reportpwrstate_parm report; ++ ++ report.state = PS_STATE_S2; ++ DBG_871X("\n%s: FW already leave 32K!\n\n", __func__); ++ cpwm_int_hdl(padapter, &report); ++#else ++ DBG_871X("\n%s: FW already leave 32K!\n\n", __func__); ++ cpwm_event_callback(&pwrpriv->cpwm_event); ++#endif ++ return; ++ } ++ ++ _enter_pwrlock(&pwrpriv->lock); ++ ++ if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2)) ++ { ++ DBG_871X("%s: cpwm=%d, nothing to do!\n", __func__, pwrpriv->cpwm); ++ goto exit; ++ } ++ pwrpriv->brpwmtimeout = _TRUE; ++ rtw_set_rpwm(padapter, pwrpriv->rpwm); ++ pwrpriv->brpwmtimeout = _FALSE; ++ ++exit: ++ _exit_pwrlock(&pwrpriv->lock); ++} ++ ++/* ++ * This function is a timer handler, can't do any IO in it. ++ */ ++static void pwr_rpwm_timeout_handler(void *FunctionContext) ++{ ++ PADAPTER padapter; ++ struct pwrctrl_priv *pwrpriv; ++ ++ ++ padapter = (PADAPTER)FunctionContext; ++ pwrpriv = adapter_to_pwrctl(padapter); ++// DBG_871X("+%s: rpwm=0x%02X cpwm=0x%02X\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); ++ ++ if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2)) ++ { ++ DBG_871X("+%s: cpwm=%d, nothing to do!\n", __func__, pwrpriv->cpwm); ++ return; ++ } ++ ++ _set_workitem(&pwrpriv->rpwmtimeoutwi); ++} ++#endif // CONFIG_LPS_RPWM_TIMER ++ ++__inline static void register_task_alive(struct pwrctrl_priv *pwrctrl, u32 tag) ++{ ++ pwrctrl->alives |= tag; ++} ++ ++__inline static void unregister_task_alive(struct pwrctrl_priv *pwrctrl, u32 tag) ++{ ++ pwrctrl->alives &= ~tag; ++} ++ ++/* ++ * Caller: rtw_xmit_thread ++ * ++ * Check if the fw_pwrstate is okay for xmit. ++ * If not (cpwm is less than S3), then the sub-routine ++ * will raise the cpwm to be greater than or equal to S3. ++ * ++ * Calling Context: Passive ++ * ++ * Return Value: ++ * _SUCCESS rtw_xmit_thread can write fifo/txcmd afterwards. ++ * _FAIL rtw_xmit_thread can not do anything. ++ */ ++s32 rtw_register_tx_alive(PADAPTER padapter) ++{ ++ s32 res; ++ struct pwrctrl_priv *pwrctrl; ++ u8 pslv; ++ ++_func_enter_; ++ ++ res = _SUCCESS; ++ pwrctrl = adapter_to_pwrctl(padapter); ++#ifdef CONFIG_BT_COEXIST ++ if (_TRUE == adapter_to_pwrctl(padapter)->btcoex_rfon) ++ pslv = PS_STATE_S3; ++ else ++#endif ++ { ++ pslv = PS_STATE_S2; ++ } ++ ++ _enter_pwrlock(&pwrctrl->lock); ++ ++ register_task_alive(pwrctrl, XMIT_ALIVE); ++ ++ if (pwrctrl->bFwCurrentInPSMode == _TRUE) ++ { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ++ ("rtw_register_tx_alive: cpwm=0x%02x alives=0x%08x\n", ++ pwrctrl->cpwm, pwrctrl->alives)); ++ ++ if (pwrctrl->cpwm < pslv) ++ { ++ if (pwrctrl->cpwm < PS_STATE_S2) ++ res = _FAIL; ++ if (pwrctrl->rpwm < pslv) ++ rtw_set_rpwm(padapter, pslv); ++ } ++ } ++ ++ _exit_pwrlock(&pwrctrl->lock); ++ ++#ifdef CONFIG_DETECT_CPWM_BY_POLLING ++ if (_FAIL == res) ++ { ++ if (pwrctrl->cpwm >= PS_STATE_S2) ++ res = _SUCCESS; ++ } ++#endif // CONFIG_DETECT_CPWM_BY_POLLING ++ ++_func_exit_; ++ ++ return res; ++} ++ ++/* ++ * Caller: rtw_cmd_thread ++ * ++ * Check if the fw_pwrstate is okay for issuing cmd. ++ * If not (cpwm should be is less than S2), then the sub-routine ++ * will raise the cpwm to be greater than or equal to S2. ++ * ++ * Calling Context: Passive ++ * ++ * Return Value: ++ * _SUCCESS rtw_cmd_thread can issue cmds to firmware afterwards. ++ * _FAIL rtw_cmd_thread can not do anything. ++ */ ++s32 rtw_register_cmd_alive(PADAPTER padapter) ++{ ++ s32 res; ++ struct pwrctrl_priv *pwrctrl; ++ u8 pslv; ++ ++_func_enter_; ++ ++ res = _SUCCESS; ++ pwrctrl = adapter_to_pwrctl(padapter); ++#ifdef CONFIG_BT_COEXIST ++ if (_TRUE == adapter_to_pwrctl(padapter)->btcoex_rfon) ++ pslv = PS_STATE_S3; ++ else ++#endif ++ { ++ pslv = PS_STATE_S2; ++ } ++ ++ _enter_pwrlock(&pwrctrl->lock); ++ ++ register_task_alive(pwrctrl, CMD_ALIVE); ++ ++ if (pwrctrl->bFwCurrentInPSMode == _TRUE) ++ { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_info_, ++ ("rtw_register_cmd_alive: cpwm=0x%02x alives=0x%08x\n", ++ pwrctrl->cpwm, pwrctrl->alives)); ++ ++ if (pwrctrl->cpwm < pslv) ++ { ++ if (pwrctrl->cpwm < PS_STATE_S2) ++ res = _FAIL; ++ if (pwrctrl->rpwm < pslv) ++ rtw_set_rpwm(padapter, pslv); ++ } ++ } ++ ++ _exit_pwrlock(&pwrctrl->lock); ++ ++#ifdef CONFIG_DETECT_CPWM_BY_POLLING ++ if (_FAIL == res) ++ { ++ if (pwrctrl->cpwm >= PS_STATE_S2) ++ res = _SUCCESS; ++ } ++#endif // CONFIG_DETECT_CPWM_BY_POLLING ++ ++_func_exit_; ++ ++ return res; ++} ++ ++/* ++ * Caller: rx_isr ++ * ++ * Calling Context: Dispatch/ISR ++ * ++ * Return Value: ++ * _SUCCESS ++ * _FAIL ++ */ ++s32 rtw_register_rx_alive(PADAPTER padapter) ++{ ++ struct pwrctrl_priv *pwrctrl; ++ ++_func_enter_; ++ ++ pwrctrl = adapter_to_pwrctl(padapter); ++ ++ _enter_pwrlock(&pwrctrl->lock); ++ ++ register_task_alive(pwrctrl, RECV_ALIVE); ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ++ ("rtw_register_rx_alive: cpwm=0x%02x alives=0x%08x\n", ++ pwrctrl->cpwm, pwrctrl->alives)); ++ ++ _exit_pwrlock(&pwrctrl->lock); ++ ++_func_exit_; ++ ++ return _SUCCESS; ++} ++ ++/* ++ * Caller: evt_isr or evt_thread ++ * ++ * Calling Context: Dispatch/ISR or Passive ++ * ++ * Return Value: ++ * _SUCCESS ++ * _FAIL ++ */ ++s32 rtw_register_evt_alive(PADAPTER padapter) ++{ ++ struct pwrctrl_priv *pwrctrl; ++ ++_func_enter_; ++ ++ pwrctrl = adapter_to_pwrctl(padapter); ++ ++ _enter_pwrlock(&pwrctrl->lock); ++ ++ register_task_alive(pwrctrl, EVT_ALIVE); ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ++ ("rtw_register_evt_alive: cpwm=0x%02x alives=0x%08x\n", ++ pwrctrl->cpwm, pwrctrl->alives)); ++ ++ _exit_pwrlock(&pwrctrl->lock); ++ ++_func_exit_; ++ ++ return _SUCCESS; ++} ++ ++/* ++ * Caller: ISR ++ * ++ * If ISR's txdone, ++ * No more pkts for TX, ++ * Then driver shall call this fun. to power down firmware again. ++ */ ++void rtw_unregister_tx_alive(PADAPTER padapter) ++{ ++ struct pwrctrl_priv *pwrctrl; ++ ++_func_enter_; ++ ++ pwrctrl = adapter_to_pwrctl(padapter); ++ ++ _enter_pwrlock(&pwrctrl->lock); ++ ++ unregister_task_alive(pwrctrl, XMIT_ALIVE); ++ ++ if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) && ++ (pwrctrl->bFwCurrentInPSMode == _TRUE)) ++ { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ++ ("%s: cpwm=0x%02x alives=0x%08x\n", ++ __FUNCTION__, pwrctrl->cpwm, pwrctrl->alives)); ++ ++ if ((pwrctrl->alives == 0) && ++ (pwrctrl->cpwm > PS_STATE_S0)) ++ { ++ rtw_set_rpwm(padapter, PS_STATE_S0); ++ } ++ } ++ ++ _exit_pwrlock(&pwrctrl->lock); ++ ++_func_exit_; ++} ++ ++/* ++ * Caller: ISR ++ * ++ * If all commands have been done, ++ * and no more command to do, ++ * then driver shall call this fun. to power down firmware again. ++ */ ++void rtw_unregister_cmd_alive(PADAPTER padapter) ++{ ++ struct pwrctrl_priv *pwrctrl; ++ ++_func_enter_; ++ ++ pwrctrl = adapter_to_pwrctl(padapter); ++ ++ _enter_pwrlock(&pwrctrl->lock); ++ ++ unregister_task_alive(pwrctrl, CMD_ALIVE); ++ ++ if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) && ++ (pwrctrl->bFwCurrentInPSMode == _TRUE)) ++ { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_info_, ++ ("%s: cpwm=0x%02x alives=0x%08x\n", ++ __FUNCTION__, pwrctrl->cpwm, pwrctrl->alives)); ++ ++ if ((pwrctrl->alives == 0) && ++ (pwrctrl->cpwm > PS_STATE_S0)) ++ { ++ rtw_set_rpwm(padapter, PS_STATE_S0); ++ } ++ } ++ ++ _exit_pwrlock(&pwrctrl->lock); ++ ++_func_exit_; ++} ++ ++/* ++ * Caller: ISR ++ */ ++void rtw_unregister_rx_alive(PADAPTER padapter) ++{ ++ struct pwrctrl_priv *pwrctrl; ++ ++_func_enter_; ++ ++ pwrctrl = adapter_to_pwrctl(padapter); ++ ++ _enter_pwrlock(&pwrctrl->lock); ++ ++ unregister_task_alive(pwrctrl, RECV_ALIVE); ++ ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ++ ("rtw_unregister_rx_alive: cpwm=0x%02x alives=0x%08x\n", ++ pwrctrl->cpwm, pwrctrl->alives)); ++ ++ _exit_pwrlock(&pwrctrl->lock); ++ ++_func_exit_; ++} ++ ++void rtw_unregister_evt_alive(PADAPTER padapter) ++{ ++ struct pwrctrl_priv *pwrctrl; ++ ++_func_enter_; ++ ++ pwrctrl = adapter_to_pwrctl(padapter); ++ ++ unregister_task_alive(pwrctrl, EVT_ALIVE); ++ ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ++ ("rtw_unregister_evt_alive: cpwm=0x%02x alives=0x%08x\n", ++ pwrctrl->cpwm, pwrctrl->alives)); ++ ++ _exit_pwrlock(&pwrctrl->lock); ++ ++_func_exit_; ++} ++#endif /* CONFIG_LPS_LCLK */ ++ ++#ifdef CONFIG_RESUME_IN_WORKQUEUE ++static void resume_workitem_callback(struct work_struct *work); ++#endif //CONFIG_RESUME_IN_WORKQUEUE ++ ++void rtw_init_pwrctrl_priv(PADAPTER padapter) ++{ ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); ++ ++#if defined(CONFIG_CONCURRENT_MODE) ++ if (padapter->adapter_type != PRIMARY_ADAPTER) ++ return; ++#endif ++ ++_func_enter_; ++ ++#ifdef PLATFORM_WINDOWS ++ pwrctrlpriv->pnp_current_pwr_state=NdisDeviceStateD0; ++#endif ++ ++ _init_pwrlock(&pwrctrlpriv->lock); ++ pwrctrlpriv->rf_pwrstate = rf_on; ++ pwrctrlpriv->ips_enter_cnts=0; ++ pwrctrlpriv->ips_leave_cnts=0; ++ pwrctrlpriv->bips_processing = _FALSE; ++ ++ pwrctrlpriv->ips_mode = padapter->registrypriv.ips_mode; ++ pwrctrlpriv->ips_mode_req = padapter->registrypriv.ips_mode; ++ ++ pwrctrlpriv->pwr_state_check_interval = RTW_PWR_STATE_CHK_INTERVAL; ++ pwrctrlpriv->pwr_state_check_cnts = 0; ++ pwrctrlpriv->bInternalAutoSuspend = _FALSE; ++ pwrctrlpriv->bInSuspend = _FALSE; ++ pwrctrlpriv->bkeepfwalive = _FALSE; ++ ++#ifdef CONFIG_AUTOSUSPEND ++#ifdef SUPPORT_HW_RFOFF_DETECTED ++ pwrctrlpriv->pwr_state_check_interval = (pwrctrlpriv->bHWPwrPindetect) ?1000:2000; ++#endif ++#endif ++ ++ pwrctrlpriv->LpsIdleCount = 0; ++ //pwrctrlpriv->FWCtrlPSMode =padapter->registrypriv.power_mgnt;// PS_MODE_MIN; ++ if (padapter->registrypriv.mp_mode == 1) ++ pwrctrlpriv->power_mgnt =PS_MODE_ACTIVE ; ++ else ++ pwrctrlpriv->power_mgnt =padapter->registrypriv.power_mgnt;// PS_MODE_MIN; ++ pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt)?_TRUE:_FALSE; ++ ++ pwrctrlpriv->bFwCurrentInPSMode = _FALSE; ++ ++ pwrctrlpriv->rpwm = 0; ++ pwrctrlpriv->cpwm = PS_STATE_S4; ++ ++ pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE; ++ pwrctrlpriv->smart_ps = padapter->registrypriv.smart_ps; ++ pwrctrlpriv->bcn_ant_mode = 0; ++ ++ pwrctrlpriv->tog = 0x80; ++ ++ pwrctrlpriv->btcoex_rfon = _FALSE; ++ ++#ifdef CONFIG_LPS_LCLK ++ rtw_hal_set_hwreg(padapter, HW_VAR_SET_RPWM, (u8 *)(&pwrctrlpriv->rpwm)); ++ ++ _init_workitem(&pwrctrlpriv->cpwm_event, cpwm_event_callback, NULL); ++ ++#ifdef CONFIG_LPS_RPWM_TIMER ++ pwrctrlpriv->brpwmtimeout = _FALSE; ++ _init_workitem(&pwrctrlpriv->rpwmtimeoutwi, rpwmtimeout_workitem_callback, NULL); ++ _init_timer(&pwrctrlpriv->pwr_rpwm_timer, padapter->pnetdev, pwr_rpwm_timeout_handler, padapter); ++#endif // CONFIG_LPS_RPWM_TIMER ++#endif // CONFIG_LPS_LCLK ++ ++#ifdef PLATFORM_LINUX ++ _init_timer(&(pwrctrlpriv->pwr_state_check_timer), padapter->pnetdev, pwr_state_check_handler, (u8 *)padapter); ++#endif ++ ++ #ifdef CONFIG_RESUME_IN_WORKQUEUE ++ _init_workitem(&pwrctrlpriv->resume_work, resume_workitem_callback, NULL); ++ pwrctrlpriv->rtw_workqueue = create_singlethread_workqueue("rtw_workqueue"); ++ #endif //CONFIG_RESUME_IN_WORKQUEUE ++ ++ #if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_ANDROID_POWER) ++ pwrctrlpriv->early_suspend.suspend = NULL; ++ rtw_register_early_suspend(pwrctrlpriv); ++ #endif //CONFIG_HAS_EARLYSUSPEND || CONFIG_ANDROID_POWER ++ ++ ++_func_exit_; ++ ++} ++ ++ ++void rtw_free_pwrctrl_priv(PADAPTER adapter) ++{ ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(adapter); ++ ++#if defined(CONFIG_CONCURRENT_MODE) ++ if (adapter->adapter_type != PRIMARY_ADAPTER) ++ return; ++#endif ++ ++_func_enter_; ++ ++ //_rtw_memset((unsigned char *)pwrctrlpriv, 0, sizeof(struct pwrctrl_priv)); ++ ++ ++ #ifdef CONFIG_RESUME_IN_WORKQUEUE ++ if (pwrctrlpriv->rtw_workqueue) { ++ flush_workqueue(pwrctrlpriv->rtw_workqueue); ++ destroy_workqueue(pwrctrlpriv->rtw_workqueue); ++ } ++ #endif ++ ++ ++ #if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_ANDROID_POWER) ++ rtw_unregister_early_suspend(pwrctrlpriv); ++ #endif //CONFIG_HAS_EARLYSUSPEND || CONFIG_ANDROID_POWER ++ ++ _free_pwrlock(&pwrctrlpriv->lock); ++ ++_func_exit_; ++} ++ ++#ifdef CONFIG_RESUME_IN_WORKQUEUE ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++extern int rtw_resume_process(_adapter *padapter); ++#endif ++static void resume_workitem_callback(struct work_struct *work) ++{ ++ struct pwrctrl_priv *pwrpriv = container_of(work, struct pwrctrl_priv, resume_work); ++ struct dvobj_priv *dvobj = pwrctl_to_dvobj(pwrpriv); ++ _adapter *adapter = dvobj->if1; ++ ++ DBG_871X("%s\n",__FUNCTION__); ++ ++ #if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ rtw_resume_process(adapter); ++ #endif ++ ++} ++ ++void rtw_resume_in_workqueue(struct pwrctrl_priv *pwrpriv) ++{ ++ // accquire system's suspend lock preventing from falliing asleep while resume in workqueue ++ rtw_lock_suspend(); ++ ++ #if 1 ++ queue_work(pwrpriv->rtw_workqueue, &pwrpriv->resume_work); ++ #else ++ _set_workitem(&pwrpriv->resume_work); ++ #endif ++} ++#endif //CONFIG_RESUME_IN_WORKQUEUE ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_ANDROID_POWER) ++inline bool rtw_is_earlysuspend_registered(struct pwrctrl_priv *pwrpriv) ++{ ++ return (pwrpriv->early_suspend.suspend) ? _TRUE : _FALSE; ++} ++ ++inline bool rtw_is_do_late_resume(struct pwrctrl_priv *pwrpriv) ++{ ++ return (pwrpriv->do_late_resume) ? _TRUE : _FALSE; ++} ++ ++inline void rtw_set_do_late_resume(struct pwrctrl_priv *pwrpriv, bool enable) ++{ ++ pwrpriv->do_late_resume = enable; ++} ++#endif ++ ++#ifdef CONFIG_HAS_EARLYSUSPEND ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++extern int rtw_resume_process(_adapter *padapter); ++#endif ++static void rtw_early_suspend(struct early_suspend *h) ++{ ++ struct pwrctrl_priv *pwrpriv = container_of(h, struct pwrctrl_priv, early_suspend); ++ DBG_871X("%s\n",__FUNCTION__); ++ ++ rtw_set_do_late_resume(pwrpriv, _FALSE); ++} ++ ++static void rtw_late_resume(struct early_suspend *h) ++{ ++ struct pwrctrl_priv *pwrpriv = container_of(h, struct pwrctrl_priv, early_suspend); ++ struct dvobj_priv *dvobj = pwrctl_to_dvobj(pwrpriv); ++ _adapter *adapter = dvobj->if1; ++ ++ DBG_871X("%s\n",__FUNCTION__); ++ if(pwrpriv->do_late_resume) { ++ #if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ rtw_set_do_late_resume(pwrpriv, _FALSE); ++ rtw_resume_process(adapter); ++ #endif ++ } ++} ++ ++void rtw_register_early_suspend(struct pwrctrl_priv *pwrpriv) ++{ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ //jeff: set the early suspend level before blank screen, so we wll do late resume after scree is lit ++ pwrpriv->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 20; ++ pwrpriv->early_suspend.suspend = rtw_early_suspend; ++ pwrpriv->early_suspend.resume = rtw_late_resume; ++ register_early_suspend(&pwrpriv->early_suspend); ++} ++ ++void rtw_unregister_early_suspend(struct pwrctrl_priv *pwrpriv) ++{ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ rtw_set_do_late_resume(pwrpriv, _FALSE); ++ ++ if (pwrpriv->early_suspend.suspend) ++ unregister_early_suspend(&pwrpriv->early_suspend); ++ ++ pwrpriv->early_suspend.suspend = NULL; ++ pwrpriv->early_suspend.resume = NULL; ++} ++#endif //CONFIG_HAS_EARLYSUSPEND ++ ++#ifdef CONFIG_ANDROID_POWER ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++extern int rtw_resume_process(PADAPTER padapter); ++#endif ++static void rtw_early_suspend(android_early_suspend_t *h) ++{ ++ struct pwrctrl_priv *pwrpriv = container_of(h, struct pwrctrl_priv, early_suspend); ++ DBG_871X("%s\n",__FUNCTION__); ++ ++ rtw_set_do_late_resume(pwrpriv, _FALSE); ++} ++ ++static void rtw_late_resume(android_early_suspend_t *h) ++{ ++ struct pwrctrl_priv *pwrpriv = container_of(h, struct pwrctrl_priv, early_suspend); ++ struct dvobj_priv *dvobj = pwrctl_to_dvobj(pwrpriv); ++ _adapter *adapter = dvobj->if1; ++ ++ DBG_871X("%s\n",__FUNCTION__); ++ if(pwrpriv->do_late_resume) { ++ #if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ rtw_set_do_late_resume(pwrpriv, _FALSE); ++ rtw_resume_process(adapter); ++ #endif ++ } ++} ++ ++void rtw_register_early_suspend(struct pwrctrl_priv *pwrpriv) ++{ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ //jeff: set the early suspend level before blank screen, so we wll do late resume after scree is lit ++ pwrpriv->early_suspend.level = ANDROID_EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 20; ++ pwrpriv->early_suspend.suspend = rtw_early_suspend; ++ pwrpriv->early_suspend.resume = rtw_late_resume; ++ android_register_early_suspend(&pwrpriv->early_suspend); ++} ++ ++void rtw_unregister_early_suspend(struct pwrctrl_priv *pwrpriv) ++{ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ rtw_set_do_late_resume(pwrpriv, _FALSE); ++ ++ if (pwrpriv->early_suspend.suspend) ++ android_unregister_early_suspend(&pwrpriv->early_suspend); ++ ++ pwrpriv->early_suspend.suspend = NULL; ++ pwrpriv->early_suspend.resume = NULL; ++} ++#endif //CONFIG_ANDROID_POWER ++ ++u8 rtw_interface_ps_func(_adapter *padapter,HAL_INTF_PS_FUNC efunc_id,u8* val) ++{ ++ u8 bResult = _TRUE; ++ rtw_hal_intf_ps_func(padapter,efunc_id,val); ++ ++ return bResult; ++} ++ ++ ++inline void rtw_set_ips_deny(_adapter *padapter, u32 ms) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime(ms); ++} ++ ++/* ++* rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend ++* @adapter: pointer to _adapter structure ++* @ips_deffer_ms: the ms wiil prevent from falling into IPS after wakeup ++* Return _SUCCESS or _FAIL ++*/ ++ ++int _rtw_pwr_wakeup(_adapter *padapter, u32 ips_deffer_ms, const char *caller) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ int ret = _SUCCESS; ++ u32 start = rtw_get_current_time(); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (padapter->pbuddy_adapter) ++ LeaveAllPowerSaveMode(padapter->pbuddy_adapter); ++ ++ if ((padapter->isprimary == _FALSE) && padapter->pbuddy_adapter){ ++ padapter = padapter->pbuddy_adapter; ++ pmlmepriv = &padapter->mlmepriv; ++ } ++#endif ++ ++ if (pwrpriv->ips_deny_time < rtw_get_current_time() + rtw_ms_to_systime(ips_deffer_ms)) ++ pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime(ips_deffer_ms); ++ ++ ++ if (pwrpriv->ps_processing) { ++ DBG_871X("%s wait ps_processing...\n", __func__); ++ while (pwrpriv->ps_processing && rtw_get_passing_time_ms(start) <= 3000) ++ rtw_msleep_os(10); ++ if (pwrpriv->ps_processing) ++ DBG_871X("%s wait ps_processing timeout\n", __func__); ++ else ++ DBG_871X("%s wait ps_processing done\n", __func__); ++ } ++ ++#ifdef DBG_CONFIG_ERROR_DETECT ++ if (rtw_hal_sreset_inprogress(padapter)) { ++ DBG_871X("%s wait sreset_inprogress...\n", __func__); ++ while (rtw_hal_sreset_inprogress(padapter) && rtw_get_passing_time_ms(start) <= 4000) ++ rtw_msleep_os(10); ++ if (rtw_hal_sreset_inprogress(padapter)) ++ DBG_871X("%s wait sreset_inprogress timeout\n", __func__); ++ else ++ DBG_871X("%s wait sreset_inprogress done\n", __func__); ++ } ++#endif ++ ++ if (pwrpriv->bInternalAutoSuspend == _FALSE && pwrpriv->bInSuspend) { ++ DBG_871X("%s wait bInSuspend...\n", __func__); ++ while (pwrpriv->bInSuspend ++ && ((rtw_get_passing_time_ms(start) <= 3000 && !rtw_is_do_late_resume(pwrpriv)) ++ || (rtw_get_passing_time_ms(start) <= 500 && rtw_is_do_late_resume(pwrpriv))) ++ ) { ++ rtw_msleep_os(10); ++ } ++ if (pwrpriv->bInSuspend) ++ DBG_871X("%s wait bInSuspend timeout\n", __func__); ++ else ++ DBG_871X("%s wait bInSuspend done\n", __func__); ++ } ++ ++ //System suspend is not allowed to wakeup ++ if((pwrpriv->bInternalAutoSuspend == _FALSE) && (_TRUE == pwrpriv->bInSuspend )){ ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ //block??? ++ if((pwrpriv->bInternalAutoSuspend == _TRUE) && (padapter->net_closed == _TRUE)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ //I think this should be check in IPS, LPS, autosuspend functions... ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ++ { ++#if defined (CONFIG_BT_COEXIST)&& defined (CONFIG_AUTOSUSPEND) ++ if(_TRUE==pwrpriv->bInternalAutoSuspend){ ++ if(0==pwrpriv->autopm_cnt){ ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,33)) ++ if (usb_autopm_get_interface(adapter_to_dvobj(padapter)->pusbintf) < 0) ++ { ++ DBG_871X( "can't get autopm: \n"); ++ } ++ #elif (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,20)) ++ usb_autopm_disable(adapter_to_dvobj(padapter)->pusbintf); ++ #else ++ usb_autoresume_device(adapter_to_dvobj(padapter)->pusbdev, 1); ++ #endif ++ pwrpriv->autopm_cnt++; ++ } ++#endif //#if defined (CONFIG_BT_COEXIST)&& defined (CONFIG_AUTOSUSPEND) ++ ret = _SUCCESS; ++ goto exit; ++#if defined (CONFIG_BT_COEXIST)&& defined (CONFIG_AUTOSUSPEND) ++ } ++#endif //#if defined (CONFIG_BT_COEXIST)&& defined (CONFIG_AUTOSUSPEND) ++ } ++ ++ if(rf_off == pwrpriv->rf_pwrstate ) ++ { ++#ifdef CONFIG_USB_HCI ++#ifdef CONFIG_AUTOSUSPEND ++ if(pwrpriv->brfoffbyhw==_TRUE) ++ { ++ DBG_8192C("hw still in rf_off state ...........\n"); ++ ret = _FAIL; ++ goto exit; ++ } ++ else if(padapter->registrypriv.usbss_enable) ++ { ++ DBG_8192C("%s call autoresume_enter....\n",__FUNCTION__); ++ if(_FAIL == autoresume_enter(padapter)) ++ { ++ DBG_8192C("======> autoresume fail.............\n"); ++ ret = _FAIL; ++ goto exit; ++ } ++ } ++ else ++#endif ++#endif ++ { ++#ifdef CONFIG_IPS ++ DBG_8192C("%s call ips_leave....\n",__FUNCTION__); ++ if(_FAIL == ips_leave(padapter)) ++ { ++ DBG_8192C("======> ips_leave fail.............\n"); ++ ret = _FAIL; ++ goto exit; ++ } ++#endif ++ } ++ } ++ ++ //TODO: the following checking need to be merged... ++ if(padapter->bDriverStopped ++ || !padapter->bup ++ || !padapter->hw_init_completed ++ ){ ++ DBG_8192C("%s: bDriverStopped=%d, bup=%d, hw_init_completed=%u\n" ++ , caller ++ , padapter->bDriverStopped ++ , padapter->bup ++ , padapter->hw_init_completed); ++ ret= _FALSE; ++ goto exit; ++ } ++ ++exit: ++ if (pwrpriv->ips_deny_time < rtw_get_current_time() + rtw_ms_to_systime(ips_deffer_ms)) ++ pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime(ips_deffer_ms); ++ return ret; ++ ++} ++ ++int rtw_pm_set_lps(_adapter *padapter, u8 mode) ++{ ++ int ret = 0; ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); ++ ++ if ( mode < PS_MODE_NUM ) ++ { ++ if(pwrctrlpriv->power_mgnt !=mode) ++ { ++ if(PS_MODE_ACTIVE == mode) ++ { ++ LeaveAllPowerSaveMode(padapter); ++ } ++ else ++ { ++ pwrctrlpriv->LpsIdleCount = 2; ++ } ++ pwrctrlpriv->power_mgnt = mode; ++ pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt)?_TRUE:_FALSE; ++ } ++ } ++ else ++ { ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++int rtw_pm_set_ips(_adapter *padapter, u8 mode) ++{ ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); ++ ++ if( mode == IPS_NORMAL || mode == IPS_LEVEL_2 ) { ++ rtw_ips_mode_req(pwrctrlpriv, mode); ++ DBG_871X("%s %s\n", __FUNCTION__, mode == IPS_NORMAL?"IPS_NORMAL":"IPS_LEVEL_2"); ++ return 0; ++ } ++ else if(mode ==IPS_NONE){ ++ rtw_ips_mode_req(pwrctrlpriv, mode); ++ DBG_871X("%s %s\n", __FUNCTION__, "IPS_NONE"); ++ if((padapter->bSurpriseRemoved ==0)&&(_FAIL == rtw_pwr_wakeup(padapter)) ) ++ return -EFAULT; ++ } ++ else { ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_recv.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_recv.c +new file mode 100644 +index 00000000..322ee4ea +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_recv.c +@@ -0,0 +1,4403 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_RECV_C_ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_USB_HCI ++#include ++#endif ++ ++#ifdef CONFIG_BT_COEXIST ++#include ++#endif ++ ++#if defined (PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) ++ ++#error "Shall be Linux or Windows, but not both!\n" ++ ++#endif ++ ++#include ++#include ++ ++#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS ++void rtw_signal_stat_timer_hdl(RTW_TIMER_HDL_ARGS); ++#endif //CONFIG_NEW_SIGNAL_STAT_PROCESS ++ ++ ++void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv) ++{ ++ ++ ++_func_enter_; ++ ++ _rtw_memset((u8 *)psta_recvpriv, 0, sizeof (struct sta_recv_priv)); ++ ++ _rtw_spinlock_init(&psta_recvpriv->lock); ++ ++ //for(i=0; iblk_strms[i]); ++ ++ _rtw_init_queue(&psta_recvpriv->defrag_q); ++ ++_func_exit_; ++ ++} ++ ++sint _rtw_init_recv_priv(struct recv_priv *precvpriv, _adapter *padapter) ++{ ++ sint i; ++ ++ union recv_frame *precvframe; ++ ++ sint res=_SUCCESS; ++ ++_func_enter_; ++ ++ // We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). ++ //_rtw_memset((unsigned char *)precvpriv, 0, sizeof (struct recv_priv)); ++ ++ _rtw_spinlock_init(&precvpriv->lock); ++ ++ _rtw_init_queue(&precvpriv->free_recv_queue); ++ _rtw_init_queue(&precvpriv->recv_pending_queue); ++ _rtw_init_queue(&precvpriv->uc_swdec_pending_queue); ++ ++ precvpriv->adapter = padapter; ++ ++ precvpriv->free_recvframe_cnt = NR_RECVFRAME; ++ ++ rtw_os_recv_resource_init(precvpriv, padapter); ++ ++ precvpriv->pallocated_frame_buf = rtw_zvmalloc(NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ); ++ ++ if(precvpriv->pallocated_frame_buf==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ //_rtw_memset(precvpriv->pallocated_frame_buf, 0, NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ); ++ ++ precvpriv->precv_frame_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_frame_buf), RXFRAME_ALIGN_SZ); ++ //precvpriv->precv_frame_buf = precvpriv->pallocated_frame_buf + RXFRAME_ALIGN_SZ - ++ // ((SIZE_PTR) (precvpriv->pallocated_frame_buf) &(RXFRAME_ALIGN_SZ-1)); ++ ++ precvframe = (union recv_frame*) precvpriv->precv_frame_buf; ++ ++ ++ for(i=0; i < NR_RECVFRAME ; i++) ++ { ++ _rtw_init_listhead(&(precvframe->u.list)); ++ ++ rtw_list_insert_tail(&(precvframe->u.list), &(precvpriv->free_recv_queue.queue)); ++ ++ res = rtw_os_recv_resource_alloc(padapter, precvframe); ++ ++ precvframe->u.hdr.len = 0; ++ ++ precvframe->u.hdr.adapter =padapter; ++ precvframe++; ++ ++ } ++ ++#ifdef CONFIG_USB_HCI ++ ++ precvpriv->rx_pending_cnt=1; ++ ++ _rtw_init_sema(&precvpriv->allrxreturnevt, 0); ++ ++#endif ++ ++ res = rtw_hal_init_recv_priv(padapter); ++ ++#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS ++ #ifdef PLATFORM_LINUX ++ _init_timer(&precvpriv->signal_stat_timer, padapter->pnetdev, RTW_TIMER_HDL_NAME(signal_stat), padapter); ++ #elif defined(PLATFORM_OS_CE) || defined(PLATFORM_WINDOWS) ++ _init_timer(&precvpriv->signal_stat_timer, padapter->hndis_adapter, RTW_TIMER_HDL_NAME(signal_stat), padapter); ++ #endif ++ ++ precvpriv->signal_stat_sampling_interval = 1000; //ms ++ //precvpriv->signal_stat_converging_constant = 5000; //ms ++ ++ rtw_set_signal_stat_timer(precvpriv); ++#endif //CONFIG_NEW_SIGNAL_STAT_PROCESS ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++ ++} ++ ++void rtw_mfree_recv_priv_lock(struct recv_priv *precvpriv); ++void rtw_mfree_recv_priv_lock(struct recv_priv *precvpriv) ++{ ++ _rtw_spinlock_free(&precvpriv->lock); ++#ifdef CONFIG_RECV_THREAD_MODE ++ _rtw_free_sema(&precvpriv->recv_sema); ++ _rtw_free_sema(&precvpriv->terminate_recvthread_sema); ++#endif ++ ++ _rtw_spinlock_free(&precvpriv->free_recv_queue.lock); ++ _rtw_spinlock_free(&precvpriv->recv_pending_queue.lock); ++ ++ _rtw_spinlock_free(&precvpriv->free_recv_buf_queue.lock); ++ ++#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX ++ _rtw_spinlock_free(&precvpriv->recv_buf_pending_queue.lock); ++#endif // CONFIG_USE_USB_BUFFER_ALLOC_RX ++} ++ ++void _rtw_free_recv_priv (struct recv_priv *precvpriv) ++{ ++ _adapter *padapter = precvpriv->adapter; ++ ++_func_enter_; ++ ++ rtw_free_uc_swdec_pending_queue(padapter); ++ ++ rtw_mfree_recv_priv_lock(precvpriv); ++ ++ rtw_os_recv_resource_free(precvpriv); ++ ++ if(precvpriv->pallocated_frame_buf) { ++ rtw_vmfree(precvpriv->pallocated_frame_buf, NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ); ++ } ++ ++ rtw_hal_free_recv_priv(padapter); ++ ++_func_exit_; ++ ++} ++ ++union recv_frame *_rtw_alloc_recvframe (_queue *pfree_recv_queue) ++{ ++ ++ union recv_frame *precvframe; ++ _list *plist, *phead; ++ _adapter *padapter; ++ struct recv_priv *precvpriv; ++_func_enter_; ++ ++ if(_rtw_queue_empty(pfree_recv_queue) == _TRUE) ++ { ++ precvframe = NULL; ++ } ++ else ++ { ++ phead = get_list_head(pfree_recv_queue); ++ ++ plist = get_next(phead); ++ ++ precvframe = LIST_CONTAINOR(plist, union recv_frame, u); ++ ++ rtw_list_delete(&precvframe->u.hdr.list); ++ padapter=precvframe->u.hdr.adapter; ++ if(padapter !=NULL){ ++ precvpriv=&padapter->recvpriv; ++ if(pfree_recv_queue == &precvpriv->free_recv_queue) ++ precvpriv->free_recvframe_cnt--; ++ } ++ } ++ ++_func_exit_; ++ ++ return precvframe; ++ ++} ++ ++union recv_frame *rtw_alloc_recvframe (_queue *pfree_recv_queue) ++{ ++ _irqL irqL; ++ union recv_frame *precvframe; ++ ++ _enter_critical_bh(&pfree_recv_queue->lock, &irqL); ++ ++ precvframe = _rtw_alloc_recvframe(pfree_recv_queue); ++ ++ _exit_critical_bh(&pfree_recv_queue->lock, &irqL); ++ ++ return precvframe; ++} ++ ++void rtw_init_recvframe(union recv_frame *precvframe, struct recv_priv *precvpriv) ++{ ++ /* Perry: This can be removed */ ++ _rtw_init_listhead(&precvframe->u.hdr.list); ++ ++ precvframe->u.hdr.len=0; ++} ++ ++int rtw_free_recvframe(union recv_frame *precvframe, _queue *pfree_recv_queue) ++{ ++ _irqL irqL; ++ _adapter *padapter=precvframe->u.hdr.adapter; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++_func_enter_; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(padapter->adapter_type > PRIMARY_ADAPTER) ++ { ++ padapter = padapter->pbuddy_adapter;//get primary_padapter ++ precvpriv = &padapter->recvpriv; ++ pfree_recv_queue = &precvpriv->free_recv_queue; ++ precvframe->u.hdr.adapter = padapter; ++ } ++#endif ++ ++ ++#ifdef PLATFORM_WINDOWS ++ rtw_os_read_port(padapter, precvframe->u.hdr.precvbuf); ++#endif ++ ++#if defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD) ++ ++ if(precvframe->u.hdr.pkt) ++ { ++#ifdef CONFIG_BSD_RX_USE_MBUF ++ m_freem(precvframe->u.hdr.pkt); ++#else // CONFIG_BSD_RX_USE_MBUF ++ rtw_skb_free(precvframe->u.hdr.pkt);//free skb by driver ++#endif // CONFIG_BSD_RX_USE_MBUF ++ precvframe->u.hdr.pkt = NULL; ++ } ++ ++#endif //defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD) ++ ++ _enter_critical_bh(&pfree_recv_queue->lock, &irqL); ++ ++ rtw_list_delete(&(precvframe->u.hdr.list)); ++ ++ precvframe->u.hdr.len = 0; ++ ++ rtw_list_insert_tail(&(precvframe->u.hdr.list), get_list_head(pfree_recv_queue)); ++ ++ if(padapter !=NULL){ ++ if(pfree_recv_queue == &precvpriv->free_recv_queue) ++ precvpriv->free_recvframe_cnt++; ++ } ++ ++ _exit_critical_bh(&pfree_recv_queue->lock, &irqL); ++ ++_func_exit_; ++ ++ return _SUCCESS; ++ ++} ++ ++ ++ ++ ++sint _rtw_enqueue_recvframe(union recv_frame *precvframe, _queue *queue) ++{ ++ ++ _adapter *padapter=precvframe->u.hdr.adapter; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++_func_enter_; ++ ++ //_rtw_init_listhead(&(precvframe->u.hdr.list)); ++ rtw_list_delete(&(precvframe->u.hdr.list)); ++ ++ ++ rtw_list_insert_tail(&(precvframe->u.hdr.list), get_list_head(queue)); ++ ++ if (padapter != NULL) { ++ if (queue == &precvpriv->free_recv_queue) ++ precvpriv->free_recvframe_cnt++; ++ } ++ ++_func_exit_; ++ ++ return _SUCCESS; ++} ++ ++sint rtw_enqueue_recvframe(union recv_frame *precvframe, _queue *queue) ++{ ++ sint ret; ++ _irqL irqL; ++ ++ //_spinlock(&pfree_recv_queue->lock); ++ _enter_critical_bh(&queue->lock, &irqL); ++ ret = _rtw_enqueue_recvframe(precvframe, queue); ++ //_rtw_spinunlock(&pfree_recv_queue->lock); ++ _exit_critical_bh(&queue->lock, &irqL); ++ ++ return ret; ++} ++ ++/* ++sint rtw_enqueue_recvframe(union recv_frame *precvframe, _queue *queue) ++{ ++ return rtw_free_recvframe(precvframe, queue); ++} ++*/ ++ ++ ++ ++ ++/* ++caller : defrag ; recvframe_chk_defrag in recv_thread (passive) ++pframequeue: defrag_queue : will be accessed in recv_thread (passive) ++ ++using spinlock to protect ++ ++*/ ++ ++void rtw_free_recvframe_queue(_queue *pframequeue, _queue *pfree_recv_queue) ++{ ++ union recv_frame *precvframe; ++ _list *plist, *phead; ++ ++_func_enter_; ++ _rtw_spinlock(&pframequeue->lock); ++ ++ phead = get_list_head(pframequeue); ++ plist = get_next(phead); ++ ++ while(rtw_end_of_queue_search(phead, plist) == _FALSE) ++ { ++ precvframe = LIST_CONTAINOR(plist, union recv_frame, u); ++ ++ plist = get_next(plist); ++ ++ //rtw_list_delete(&precvframe->u.hdr.list); // will do this in rtw_free_recvframe() ++ ++ rtw_free_recvframe(precvframe, pfree_recv_queue); ++ } ++ ++ _rtw_spinunlock(&pframequeue->lock); ++ ++_func_exit_; ++ ++} ++ ++u32 rtw_free_uc_swdec_pending_queue(_adapter *adapter) ++{ ++ u32 cnt = 0; ++ union recv_frame *pending_frame; ++ while((pending_frame=rtw_alloc_recvframe(&adapter->recvpriv.uc_swdec_pending_queue))) { ++ rtw_free_recvframe(pending_frame, &adapter->recvpriv.free_recv_queue); ++ cnt++; ++ } ++ ++ if (cnt) ++ DBG_871X(FUNC_ADPT_FMT" dequeue %d\n", FUNC_ADPT_ARG(adapter), cnt); ++ ++ return cnt; ++} ++ ++ ++sint rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, _queue *queue) ++{ ++ _irqL irqL; ++ ++ _enter_critical_bh(&queue->lock, &irqL); ++ ++ rtw_list_delete(&precvbuf->list); ++ rtw_list_insert_head(&precvbuf->list, get_list_head(queue)); ++ ++ _exit_critical_bh(&queue->lock, &irqL); ++ ++ return _SUCCESS; ++} ++ ++sint rtw_enqueue_recvbuf(struct recv_buf *precvbuf, _queue *queue) ++{ ++ _irqL irqL; ++#ifdef CONFIG_SDIO_HCI ++ _enter_critical_bh(&queue->lock, &irqL); ++#else ++ _enter_critical_ex(&queue->lock, &irqL); ++#endif/*#ifdef CONFIG_SDIO_HCI*/ ++ ++ rtw_list_delete(&precvbuf->list); ++ ++ rtw_list_insert_tail(&precvbuf->list, get_list_head(queue)); ++#ifdef CONFIG_SDIO_HCI ++ _exit_critical_bh(&queue->lock, &irqL); ++#else ++ _exit_critical_ex(&queue->lock, &irqL); ++#endif/*#ifdef CONFIG_SDIO_HCI*/ ++ return _SUCCESS; ++ ++} ++ ++struct recv_buf *rtw_dequeue_recvbuf (_queue *queue) ++{ ++ _irqL irqL; ++ struct recv_buf *precvbuf; ++ _list *plist, *phead; ++ ++#ifdef CONFIG_SDIO_HCI ++ _enter_critical_bh(&queue->lock, &irqL); ++#else ++ _enter_critical_ex(&queue->lock, &irqL); ++#endif/*#ifdef CONFIG_SDIO_HCI*/ ++ ++ if(_rtw_queue_empty(queue) == _TRUE) ++ { ++ precvbuf = NULL; ++ } ++ else ++ { ++ phead = get_list_head(queue); ++ ++ plist = get_next(phead); ++ ++ precvbuf = LIST_CONTAINOR(plist, struct recv_buf, list); ++ ++ rtw_list_delete(&precvbuf->list); ++ ++ } ++ ++#ifdef CONFIG_SDIO_HCI ++ _exit_critical_bh(&queue->lock, &irqL); ++#else ++ _exit_critical_ex(&queue->lock, &irqL); ++#endif/*#ifdef CONFIG_SDIO_HCI*/ ++ ++ return precvbuf; ++ ++} ++ ++sint recvframe_chkmic(_adapter *adapter, union recv_frame *precvframe); ++sint recvframe_chkmic(_adapter *adapter, union recv_frame *precvframe){ ++ ++ sint i,res=_SUCCESS; ++ u32 datalen; ++ u8 miccode[8]; ++ u8 bmic_err=_FALSE,brpt_micerror = _TRUE; ++ u8 *pframe, *payload,*pframemic; ++ u8 *mickey; ++ //u8 *iv,rxdata_key_idx=0; ++ struct sta_info *stainfo; ++ struct rx_pkt_attrib *prxattrib=&precvframe->u.hdr.attrib; ++ struct security_priv *psecuritypriv=&adapter->securitypriv; ++ ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++_func_enter_; ++ ++ stainfo=rtw_get_stainfo(&adapter->stapriv ,&prxattrib->ta[0]); ++ ++ if(prxattrib->encrypt ==_TKIP_) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("\n recvframe_chkmic:prxattrib->encrypt ==_TKIP_\n")); ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("\n recvframe_chkmic:da=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", ++ prxattrib->ra[0],prxattrib->ra[1],prxattrib->ra[2],prxattrib->ra[3],prxattrib->ra[4],prxattrib->ra[5])); ++ ++ //calculate mic code ++ if(stainfo!= NULL) ++ { ++ if(IS_MCAST(prxattrib->ra)) ++ { ++ //mickey=&psecuritypriv->dot118021XGrprxmickey.skey[0]; ++ //iv = precvframe->u.hdr.rx_data+prxattrib->hdrlen; ++ //rxdata_key_idx =( ((iv[3])>>6)&0x3) ; ++ mickey=&psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0]; ++ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("\n recvframe_chkmic: bcmc key \n")); ++ //DBG_871X("\n recvframe_chkmic: bcmc key psecuritypriv->dot118021XGrpKeyid(%d),pmlmeinfo->key_index(%d) ,recv key_id(%d)\n", ++ // psecuritypriv->dot118021XGrpKeyid,pmlmeinfo->key_index,rxdata_key_idx); ++ ++ if(psecuritypriv->binstallGrpkey==_FALSE) ++ { ++ res=_FAIL; ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n")); ++ DBG_871X("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n"); ++ goto exit; ++ } ++ } ++ else{ ++ mickey=&stainfo->dot11tkiprxmickey.skey[0]; ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("\n recvframe_chkmic: unicast key \n")); ++ } ++ ++ datalen=precvframe->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len-prxattrib->icv_len-8;//icv_len included the mic code ++ pframe=precvframe->u.hdr.rx_data; ++ payload=pframe+prxattrib->hdrlen+prxattrib->iv_len; ++ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("\n prxattrib->iv_len=%d prxattrib->icv_len=%d\n",prxattrib->iv_len,prxattrib->icv_len)); ++ ++ //rtw_seccalctkipmic(&stainfo->dot11tkiprxmickey.skey[0],pframe,payload, datalen ,&miccode[0],(unsigned char)prxattrib->priority); //care the length of the data ++ ++ rtw_seccalctkipmic(mickey,pframe,payload, datalen ,&miccode[0],(unsigned char)prxattrib->priority); //care the length of the data ++ ++ pframemic=payload+datalen; ++ ++ bmic_err=_FALSE; ++ ++ for(i=0;i<8;i++){ ++ if(miccode[i] != *(pframemic+i)){ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("recvframe_chkmic:miccode[%d](%02x) != *(pframemic+%d)(%02x) ",i,miccode[i],i,*(pframemic+i))); ++ bmic_err=_TRUE; ++ } ++ } ++ ++ ++ if(bmic_err==_TRUE){ ++ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("\n *(pframemic-8)-*(pframemic-1)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", ++ *(pframemic-8),*(pframemic-7),*(pframemic-6),*(pframemic-5),*(pframemic-4),*(pframemic-3),*(pframemic-2),*(pframemic-1))); ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("\n *(pframemic-16)-*(pframemic-9)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", ++ *(pframemic-16),*(pframemic-15),*(pframemic-14),*(pframemic-13),*(pframemic-12),*(pframemic-11),*(pframemic-10),*(pframemic-9))); ++ ++ { ++ uint i; ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("\n ======demp packet (len=%d)======\n",precvframe->u.hdr.len)); ++ for(i=0;iu.hdr.len;i=i+8){ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x", ++ *(precvframe->u.hdr.rx_data+i),*(precvframe->u.hdr.rx_data+i+1), ++ *(precvframe->u.hdr.rx_data+i+2),*(precvframe->u.hdr.rx_data+i+3), ++ *(precvframe->u.hdr.rx_data+i+4),*(precvframe->u.hdr.rx_data+i+5), ++ *(precvframe->u.hdr.rx_data+i+6),*(precvframe->u.hdr.rx_data+i+7))); ++ } ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("\n ======demp packet end [len=%d]======\n",precvframe->u.hdr.len)); ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("\n hrdlen=%d, \n",prxattrib->hdrlen)); ++ } ++ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("ra=0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x psecuritypriv->binstallGrpkey=%d ", ++ prxattrib->ra[0],prxattrib->ra[1],prxattrib->ra[2], ++ prxattrib->ra[3],prxattrib->ra[4],prxattrib->ra[5],psecuritypriv->binstallGrpkey)); ++ ++ // double check key_index for some timing issue , ++ // cannot compare with psecuritypriv->dot118021XGrpKeyid also cause timing issue ++ if((IS_MCAST(prxattrib->ra)==_TRUE) && (prxattrib->key_index != pmlmeinfo->key_index )) ++ brpt_micerror = _FALSE; ++ ++ if((prxattrib->bdecrypted ==_TRUE)&& (brpt_micerror == _TRUE)) ++ { ++ rtw_handle_tkip_mic_err(adapter,(u8)IS_MCAST(prxattrib->ra)); ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,(" mic error :prxattrib->bdecrypted=%d ",prxattrib->bdecrypted)); ++ DBG_871X(" mic error :prxattrib->bdecrypted=%d\n",prxattrib->bdecrypted); ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,(" mic error :prxattrib->bdecrypted=%d ",prxattrib->bdecrypted)); ++ DBG_871X(" mic error :prxattrib->bdecrypted=%d\n",prxattrib->bdecrypted); ++ } ++ ++ res=_FAIL; ++ ++ } ++ else{ ++ //mic checked ok ++ if((psecuritypriv->bcheck_grpkey ==_FALSE)&&(IS_MCAST(prxattrib->ra)==_TRUE)){ ++ psecuritypriv->bcheck_grpkey =_TRUE; ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("psecuritypriv->bcheck_grpkey =_TRUE")); ++ } ++ } ++ ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("recvframe_chkmic: rtw_get_stainfo==NULL!!!\n")); ++ } ++ ++ recvframe_pull_tail(precvframe, 8); ++ ++ } ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++ ++} ++ ++//decrypt and set the ivlen,icvlen of the recv_frame ++union recv_frame * decryptor(_adapter *padapter,union recv_frame *precv_frame); ++union recv_frame * decryptor(_adapter *padapter,union recv_frame *precv_frame) ++{ ++ ++ struct rx_pkt_attrib *prxattrib = &precv_frame->u.hdr.attrib; ++ struct security_priv *psecuritypriv=&padapter->securitypriv; ++ union recv_frame *return_packet=precv_frame; ++ u32 res=_SUCCESS; ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("prxstat->decrypted=%x prxattrib->encrypt = 0x%03x\n",prxattrib->bdecrypted,prxattrib->encrypt)); ++ ++ if(prxattrib->encrypt>0) ++ { ++ u8 *iv = precv_frame->u.hdr.rx_data+prxattrib->hdrlen; ++ prxattrib->key_index = ( ((iv[3])>>6)&0x3) ; ++ ++ if(prxattrib->key_index > WEP_KEYS) ++ { ++ DBG_871X("prxattrib->key_index(%d) > WEP_KEYS \n", prxattrib->key_index); ++ ++ switch(prxattrib->encrypt){ ++ case _WEP40_: ++ case _WEP104_: ++ prxattrib->key_index = psecuritypriv->dot11PrivacyKeyIndex; ++ break; ++ case _TKIP_: ++ case _AES_: ++ default: ++ prxattrib->key_index = psecuritypriv->dot118021XGrpKeyid; ++ break; ++ } ++ } ++ } ++ ++ if((prxattrib->encrypt>0) && ((prxattrib->bdecrypted==0) ||(psecuritypriv->sw_decrypt==_TRUE))) ++ { ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(!IS_MCAST(prxattrib->ra))//bc/mc packets use sw decryption for concurrent mode ++#endif ++ psecuritypriv->hw_decrypted=_FALSE; ++ ++ #ifdef DBG_RX_DECRYPTOR ++ DBG_871X("prxstat->bdecrypted:%d, prxattrib->encrypt:%d, Setting psecuritypriv->hw_decrypted = %d\n" ++ , prxattrib->bdecrypted ,prxattrib->encrypt, psecuritypriv->hw_decrypted); ++ #endif ++ ++ switch(prxattrib->encrypt){ ++ case _WEP40_: ++ case _WEP104_: ++ rtw_wep_decrypt(padapter, (u8 *)precv_frame); ++ break; ++ case _TKIP_: ++ res = rtw_tkip_decrypt(padapter, (u8 *)precv_frame); ++ break; ++ case _AES_: ++ res = rtw_aes_decrypt(padapter, (u8 * )precv_frame); ++ break; ++#ifdef CONFIG_WAPI_SUPPORT ++ case _SMS4_: ++ rtw_sms4_decrypt(padapter, (u8 * )precv_frame); ++ break; ++#endif ++ default: ++ break; ++ } ++ } ++ else if(prxattrib->bdecrypted==1 ++ && prxattrib->encrypt >0 ++ && (psecuritypriv->busetkipkey==1 || prxattrib->encrypt !=_TKIP_ ) ++ ) ++ { ++#if 0 ++ if((prxstat->icv==1)&&(prxattrib->encrypt!=_AES_)) ++ { ++ psecuritypriv->hw_decrypted=_FALSE; ++ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("psecuritypriv->hw_decrypted=_FALSE")); ++ ++ rtw_free_recvframe(precv_frame, &padapter->recvpriv.free_recv_queue); ++ ++ return_packet=NULL; ++ ++ } ++ else ++#endif ++ { ++ psecuritypriv->hw_decrypted=_TRUE; ++ #ifdef DBG_RX_DECRYPTOR ++ DBG_871X("prxstat->bdecrypted:%d, prxattrib->encrypt:%d, Setting psecuritypriv->hw_decrypted = %d\n" ++ , prxattrib->bdecrypted ,prxattrib->encrypt, psecuritypriv->hw_decrypted); ++ #endif ++ ++ } ++ } ++ else { ++ #ifdef DBG_RX_DECRYPTOR ++ DBG_871X("prxstat->bdecrypted:%d, prxattrib->encrypt:%d, psecuritypriv->hw_decrypted:%d\n" ++ , prxattrib->bdecrypted ,prxattrib->encrypt, psecuritypriv->hw_decrypted); ++ #endif ++ } ++ ++ if(res == _FAIL) ++ { ++ rtw_free_recvframe(return_packet,&padapter->recvpriv.free_recv_queue); ++ return_packet = NULL; ++ ++ } ++ else{ ++ prxattrib->bdecrypted = _TRUE; ++ } ++ //recvframe_chkmic(adapter, precv_frame); //move to recvframme_defrag function ++ ++_func_exit_; ++ ++ return return_packet; ++ ++} ++//###set the security information in the recv_frame ++union recv_frame * portctrl(_adapter *adapter,union recv_frame * precv_frame); ++union recv_frame * portctrl(_adapter *adapter,union recv_frame * precv_frame) ++{ ++ u8 *psta_addr, *ptr; ++ uint auth_alg; ++ struct recv_frame_hdr *pfhdr; ++ struct sta_info *psta; ++ struct sta_priv *pstapriv ; ++ union recv_frame *prtnframe; ++ u16 ether_type=0; ++ u16 eapol_type = 0x888e;//for Funia BD's WPA issue ++ struct rx_pkt_attrib *pattrib; ++ ++_func_enter_; ++ ++ pstapriv = &adapter->stapriv; ++ ++ auth_alg = adapter->securitypriv.dot11AuthAlgrthm; ++ ++ ptr = get_recvframe_data(precv_frame); ++ pfhdr = &precv_frame->u.hdr; ++ pattrib = &pfhdr->attrib; ++ psta_addr = pattrib->ta; ++ ++ prtnframe = NULL; ++ ++ psta = rtw_get_stainfo(pstapriv, psta_addr); ++ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("########portctrl:adapter->securitypriv.dot11AuthAlgrthm=%d\n",adapter->securitypriv.dot11AuthAlgrthm)); ++ ++ if(auth_alg==2) ++ { ++ if ((psta!=NULL) && (psta->ieee8021x_blocked)) ++ { ++ //blocked ++ //only accept EAPOL frame ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("########portctrl:psta->ieee8021x_blocked==1\n")); ++ ++ prtnframe=precv_frame; ++ ++ //get ether_type ++ ptr=ptr+pfhdr->attrib.hdrlen+pfhdr->attrib.iv_len+LLC_HEADER_SIZE; ++ _rtw_memcpy(ðer_type,ptr, 2); ++ ether_type= ntohs((unsigned short )ether_type); ++ ++ if (ether_type == eapol_type) { ++ prtnframe=precv_frame; ++ } ++ else { ++ //free this frame ++ rtw_free_recvframe(precv_frame, &adapter->recvpriv.free_recv_queue); ++ prtnframe=NULL; ++ } ++ } ++ else ++ { ++ //allowed ++ //check decryption status, and decrypt the frame if needed ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("########portctrl:psta->ieee8021x_blocked==0\n")); ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("portctrl:precv_frame->hdr.attrib.privacy=%x\n",precv_frame->u.hdr.attrib.privacy)); ++ ++ if (pattrib->bdecrypted == 0) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("portctrl:prxstat->decrypted=%x\n", pattrib->bdecrypted)); ++ } ++ ++ prtnframe=precv_frame; ++ //check is the EAPOL frame or not (Rekey) ++ if(ether_type == eapol_type){ ++ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_notice_,("########portctrl:ether_type == 0x888e\n")); ++ //check Rekey ++ ++ prtnframe=precv_frame; ++ } ++ else{ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("########portctrl:ether_type=0x%04x\n", ether_type)); ++ } ++ } ++ } ++ else ++ { ++ prtnframe=precv_frame; ++ } ++ ++_func_exit_; ++ ++ return prtnframe; ++ ++} ++ ++sint recv_decache(union recv_frame *precv_frame, u8 bretry, struct stainfo_rxcache *prxcache); ++sint recv_decache(union recv_frame *precv_frame, u8 bretry, struct stainfo_rxcache *prxcache) ++{ ++ sint tid = precv_frame->u.hdr.attrib.priority; ++ ++ u16 seq_ctrl = ( (precv_frame->u.hdr.attrib.seq_num&0xffff) << 4) | ++ (precv_frame->u.hdr.attrib.frag_num & 0xf); ++ ++_func_enter_; ++ ++ if(tid>15) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, (tid>15)! seq_ctrl=0x%x, tid=0x%x\n", seq_ctrl, tid)); ++ ++ return _FAIL; ++ } ++ ++ if(1)//if(bretry) ++ { ++ if(seq_ctrl == prxcache->tid_rxseq[tid]) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, seq_ctrl=0x%x, tid=0x%x, tid_rxseq=0x%x\n", seq_ctrl, tid, prxcache->tid_rxseq[tid])); ++ ++ return _FAIL; ++ } ++ } ++ ++ prxcache->tid_rxseq[tid] = seq_ctrl; ++ ++_func_exit_; ++ ++ return _SUCCESS; ++ ++} ++ ++void process_pwrbit_data(_adapter *padapter, union recv_frame *precv_frame); ++void process_pwrbit_data(_adapter *padapter, union recv_frame *precv_frame) ++{ ++#ifdef CONFIG_AP_MODE ++ unsigned char pwrbit; ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *psta=NULL; ++ ++ psta = rtw_get_stainfo(pstapriv, pattrib->src); ++ ++ pwrbit = GetPwrMgt(ptr); ++ ++ if(psta) ++ { ++ if(pwrbit) ++ { ++ if(!(psta->state & WIFI_SLEEP_STATE)) ++ { ++ //psta->state |= WIFI_SLEEP_STATE; ++ //pstapriv->sta_dz_bitmap |= BIT(psta->aid); ++ ++ stop_sta_xmit(padapter, psta); ++ ++ //DBG_871X("to sleep, sta_dz_bitmap=%x\n", pstapriv->sta_dz_bitmap); ++ } ++ } ++ else ++ { ++ if(psta->state & WIFI_SLEEP_STATE) ++ { ++ //psta->state ^= WIFI_SLEEP_STATE; ++ //pstapriv->sta_dz_bitmap &= ~BIT(psta->aid); ++ ++ wakeup_sta_to_xmit(padapter, psta); ++ ++ //DBG_871X("to wakeup, sta_dz_bitmap=%x\n", pstapriv->sta_dz_bitmap); ++ } ++ } ++ ++ } ++ ++#endif ++} ++ ++void process_wmmps_data(_adapter *padapter, union recv_frame *precv_frame); ++void process_wmmps_data(_adapter *padapter, union recv_frame *precv_frame) ++{ ++#ifdef CONFIG_AP_MODE ++ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *psta=NULL; ++ ++ psta = rtw_get_stainfo(pstapriv, pattrib->src); ++ ++ if(!psta) return; ++ ++#ifdef CONFIG_TDLS ++ if( !(psta->tdls_sta_state & TDLS_LINKED_STATE ) ) ++ { ++#endif //CONFIG_TDLS ++ ++ if(!psta->qos_option) ++ return; ++ ++ if(!(psta->qos_info&0xf)) ++ return; ++ ++#ifdef CONFIG_TDLS ++ } ++#endif //CONFIG_TDLS ++ ++ if(psta->state&WIFI_SLEEP_STATE) ++ { ++ u8 wmmps_ac=0; ++ ++ switch(pattrib->priority) ++ { ++ case 1: ++ case 2: ++ wmmps_ac = psta->uapsd_bk&BIT(1); ++ break; ++ case 4: ++ case 5: ++ wmmps_ac = psta->uapsd_vi&BIT(1); ++ break; ++ case 6: ++ case 7: ++ wmmps_ac = psta->uapsd_vo&BIT(1); ++ break; ++ case 0: ++ case 3: ++ default: ++ wmmps_ac = psta->uapsd_be&BIT(1); ++ break; ++ } ++ ++ if(wmmps_ac) ++ { ++ if(psta->sleepq_ac_len>0) ++ { ++ //process received triggered frame ++ xmit_delivery_enabled_frames(padapter, psta); ++ } ++ else ++ { ++ //issue one qos null frame with More data bit = 0 and the EOSP bit set (=1) ++ issue_qos_nulldata(padapter, psta->hwaddr, (u16)pattrib->priority, 0, 0); ++ } ++ } ++ ++ } ++ ++ ++#endif ++ ++} ++ ++#ifdef CONFIG_TDLS ++sint OnTDLS(_adapter *adapter, union recv_frame *precv_frame) ++{ ++ struct rx_pkt_attrib *pattrib = & precv_frame->u.hdr.attrib; ++ sint ret = _SUCCESS; ++ u8 *paction = get_recvframe_data(precv_frame); ++ u8 category_field = 1; ++#ifdef CONFIG_WFD ++ u8 WFA_OUI[3] = { 0x50, 0x6f, 0x9a }; ++#endif //CONFIG_WFD ++ struct tdls_info *ptdlsinfo = &(adapter->tdlsinfo); ++ ++ //point to action field ++ paction+=pattrib->hdrlen ++ + pattrib->iv_len ++ + SNAP_SIZE ++ + ETH_TYPE_LEN ++ + PAYLOAD_TYPE_LEN ++ + category_field; ++ ++ if(ptdlsinfo->enable == 0) ++ { ++ DBG_871X("recv tdls frame, " ++ "but tdls haven't enabled\n"); ++ ret = _FAIL; ++ return ret; ++ } ++ ++ switch(*paction){ ++ case TDLS_SETUP_REQUEST: ++ DBG_871X("recv tdls setup request frame\n"); ++ ret=On_TDLS_Setup_Req(adapter, precv_frame); ++ break; ++ case TDLS_SETUP_RESPONSE: ++ DBG_871X("recv tdls setup response frame\n"); ++ ret=On_TDLS_Setup_Rsp(adapter, precv_frame); ++ break; ++ case TDLS_SETUP_CONFIRM: ++ DBG_871X("recv tdls setup confirm frame\n"); ++ ret=On_TDLS_Setup_Cfm(adapter, precv_frame); ++ break; ++ case TDLS_TEARDOWN: ++ DBG_871X("recv tdls teardown, free sta_info\n"); ++ ret=On_TDLS_Teardown(adapter, precv_frame); ++ break; ++ case TDLS_DISCOVERY_REQUEST: ++ DBG_871X("recv tdls discovery request frame\n"); ++ ret=On_TDLS_Dis_Req(adapter, precv_frame); ++ break; ++ case TDLS_PEER_TRAFFIC_RESPONSE: ++ DBG_871X("recv tdls peer traffic response frame\n"); ++ ret=On_TDLS_Peer_Traffic_Rsp(adapter, precv_frame); ++ break; ++ case TDLS_CHANNEL_SWITCH_REQUEST: ++ DBG_871X("recv tdls channel switch request frame\n"); ++ ret=On_TDLS_Ch_Switch_Req(adapter, precv_frame); ++ break; ++ case TDLS_CHANNEL_SWITCH_RESPONSE: ++ DBG_871X("recv tdls channel switch response frame\n"); ++ ret=On_TDLS_Ch_Switch_Rsp(adapter, precv_frame); ++ break; ++#ifdef CONFIG_WFD ++ case 0x50: //First byte of WFA OUI ++ if( _rtw_memcmp(WFA_OUI, (paction), 3) ) ++ { ++ if( *(paction + 3) == 0x04) //Probe request frame ++ { ++ //WFDTDLS: for sigma test, do not setup direct link automatically ++ ptdlsinfo->dev_discovered = 1; ++ DBG_871X("recv tunneled probe request frame\n"); ++ issue_tunneled_probe_rsp(adapter, precv_frame); ++ } ++ if( *(paction + 3) == 0x05) //Probe response frame ++ { ++ //WFDTDLS: for sigma test, do not setup direct link automatically ++ ptdlsinfo->dev_discovered = 1; ++ DBG_871X("recv tunneled probe response frame\n"); ++ } ++ } ++ break; ++#endif //CONFIG_WFD ++ default: ++ DBG_871X("receive TDLS frame but not supported\n"); ++ ret=_FAIL; ++ break; ++ } ++ ++exit: ++ return ret; ++ ++} ++#endif ++ ++void count_rx_stats(_adapter *padapter, union recv_frame *prframe, struct sta_info*sta); ++void count_rx_stats(_adapter *padapter, union recv_frame *prframe, struct sta_info*sta) ++{ ++ int sz; ++ struct sta_info *psta = NULL; ++ struct stainfo_stats *pstats = NULL; ++ struct rx_pkt_attrib *pattrib = & prframe->u.hdr.attrib; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++ sz = get_recvframe_len(prframe); ++ precvpriv->rx_bytes += sz; ++ ++ padapter->mlmepriv.LinkDetectInfo.NumRxOkInPeriod++; ++ ++ if( (!MacAddr_isBcst(pattrib->dst)) && (!IS_MCAST(pattrib->dst))){ ++ padapter->mlmepriv.LinkDetectInfo.NumRxUnicastOkInPeriod++; ++ } ++ ++ if(sta) ++ psta = sta; ++ else ++ psta = prframe->u.hdr.psta; ++ ++ if(psta) ++ { ++ pstats = &psta->sta_stats; ++ ++ pstats->rx_data_pkts++; ++ pstats->rx_bytes += sz; ++ } ++ ++} ++ ++sint sta2sta_data_frame( ++ _adapter *adapter, ++ union recv_frame *precv_frame, ++ struct sta_info**psta ++); ++sint sta2sta_data_frame( ++ _adapter *adapter, ++ union recv_frame *precv_frame, ++ struct sta_info**psta ++) ++{ ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ sint ret = _SUCCESS; ++ struct rx_pkt_attrib *pattrib = & precv_frame->u.hdr.attrib; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ u8 *mybssid = get_bssid(pmlmepriv); ++ u8 *myhwaddr = myid(&adapter->eeprompriv); ++ u8 * sta_addr = NULL; ++ sint bmcast = IS_MCAST(pattrib->dst); ++ ++#ifdef CONFIG_TDLS ++ struct tdls_info *ptdlsinfo = &adapter->tdlsinfo; ++ struct sta_info *ptdls_sta=NULL; ++ u8 *psnap_type=ptr+pattrib->hdrlen + pattrib->iv_len+SNAP_SIZE; ++ //frame body located after [+2]: ether-type, [+1]: payload type ++ u8 *pframe_body = psnap_type+2+1; ++#endif ++ ++_func_enter_; ++ ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE)) ++ { ++ ++ // filter packets that SA is myself or multicast or broadcast ++ if (_rtw_memcmp(myhwaddr, pattrib->src, ETH_ALEN)){ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,(" SA==myself \n")); ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ if( (!_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast) ){ ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ if( _rtw_memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || ++ _rtw_memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || ++ (!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN)) ) { ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ sta_addr = pattrib->src; ++ ++ } ++ else if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) ++ { ++#ifdef CONFIG_TDLS ++ ++ //direct link data transfer ++ if(ptdlsinfo->setup_state == TDLS_LINKED_STATE){ ++ ptdls_sta = rtw_get_stainfo(pstapriv, pattrib->src); ++ if(ptdls_sta==NULL) ++ { ++ ret=_FAIL; ++ goto exit; ++ } ++ else if(ptdls_sta->tdls_sta_state&TDLS_LINKED_STATE) ++ { ++ ++ //drop QoS-SubType Data, including QoS NULL, excluding QoS-Data ++ if( (GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE )== WIFI_QOS_DATA_TYPE) ++ { ++ if(GetFrameSubType(ptr)&(BIT(4)|BIT(5)|BIT(6))) ++ { ++ DBG_871X("drop QoS-Sybtype Data\n"); ++ ret= _FAIL; ++ goto exit; ++ } ++ } ++ // filter packets that SA is myself or multicast or broadcast ++ if (_rtw_memcmp(myhwaddr, pattrib->src, ETH_ALEN)){ ++ ret= _FAIL; ++ goto exit; ++ } ++ // da should be for me ++ if((!_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN))&& (!bmcast)) ++ { ++ ret= _FAIL; ++ goto exit; ++ } ++ // check BSSID ++ if( _rtw_memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || ++ _rtw_memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || ++ (!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN)) ) ++ { ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ //process UAPSD tdls sta ++ process_pwrbit_data(adapter, precv_frame); ++ ++ // if NULL-frame, check pwrbit ++ if ((GetFrameSubType(ptr)) == WIFI_DATA_NULL) ++ { ++ //NULL-frame with pwrbit=1, buffer_STA should buffer frames for sleep_STA ++ if(GetPwrMgt(ptr)) ++ { ++ DBG_871X("TDLS: recv peer null frame with pwr bit 1\n"); ++ ptdls_sta->tdls_sta_state|=TDLS_PEER_SLEEP_STATE; ++ // it would be triggered when we are off channel and receiving NULL DATA ++ // we can confirm that peer STA is at off channel ++ } ++ else if(ptdls_sta->tdls_sta_state&TDLS_CH_SWITCH_ON_STATE) ++ { ++ if((ptdls_sta->tdls_sta_state & TDLS_PEER_AT_OFF_STATE) != TDLS_PEER_AT_OFF_STATE) ++ { ++ issue_nulldata_to_TDLS_peer_STA(adapter, ptdls_sta, 0); ++ ptdls_sta->tdls_sta_state |= TDLS_PEER_AT_OFF_STATE; ++ On_TDLS_Peer_Traffic_Rsp(adapter, precv_frame); ++ } ++ } ++ ++ ret= _FAIL; ++ goto exit; ++ } ++ //receive some of all TDLS management frames, process it at ON_TDLS ++ if((_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_TDLS, 2))){ ++ ret= OnTDLS(adapter, precv_frame); ++ goto exit; ++ } ++ ++ } ++ ++ sta_addr = pattrib->src; ++ ++ } ++ else ++#endif //CONFIG_TDLS ++ { ++ // For Station mode, sa and bssid should always be BSSID, and DA is my mac-address ++ if(!_rtw_memcmp(pattrib->bssid, pattrib->src, ETH_ALEN) ) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("bssid != TA under STATION_MODE; drop pkt\n")); ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ sta_addr = pattrib->bssid; ++ } ++ ++ } ++ else if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ { ++ if (bmcast) ++ { ++ // For AP mode, if DA == MCAST, then BSSID should be also MCAST ++ if (!IS_MCAST(pattrib->bssid)){ ++ ret= _FAIL; ++ goto exit; ++ } ++ } ++ else // not mc-frame ++ { ++ // For AP mode, if DA is non-MCAST, then it must be BSSID, and bssid == BSSID ++ if(!_rtw_memcmp(pattrib->bssid, pattrib->dst, ETH_ALEN)) { ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ sta_addr = pattrib->src; ++ } ++ ++ } ++ else if(check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) ++ { ++ _rtw_memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); ++ _rtw_memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); ++ _rtw_memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); ++ _rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ ++ sta_addr = mybssid; ++ } ++ else ++ { ++ ret = _FAIL; ++ } ++ ++ ++ ++ if(bmcast) ++ *psta = rtw_get_bcmc_stainfo(adapter); ++ else ++ *psta = rtw_get_stainfo(pstapriv, sta_addr); // get ap_info ++ ++#ifdef CONFIG_TDLS ++ if(ptdls_sta != NULL) ++ *psta = ptdls_sta; ++#endif //CONFIG_TDLS ++ ++ if (*psta == NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("can't get psta under sta2sta_data_frame ; drop pkt\n")); ++#ifdef CONFIG_MP_INCLUDED ++ if (adapter->registrypriv.mp_mode == 1) ++ { ++ if(check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) ++ adapter->mppriv.rx_pktloss++; ++ } ++#endif ++ ret= _FAIL; ++ goto exit; ++ } ++ ++exit: ++_func_exit_; ++ return ret; ++ ++} ++ ++sint ap2sta_data_frame( ++ _adapter *adapter, ++ union recv_frame *precv_frame, ++ struct sta_info**psta ); ++sint ap2sta_data_frame( ++ _adapter *adapter, ++ union recv_frame *precv_frame, ++ struct sta_info**psta ) ++{ ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ struct rx_pkt_attrib *pattrib = & precv_frame->u.hdr.attrib; ++ sint ret = _SUCCESS; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ u8 *mybssid = get_bssid(pmlmepriv); ++ u8 *myhwaddr = myid(&adapter->eeprompriv); ++ sint bmcast = IS_MCAST(pattrib->dst); ++ ++_func_enter_; ++ ++ if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) ++ && (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE ++ || check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE ) ++ ) ++ { ++ ++ // filter packets that SA is myself or multicast or broadcast ++ if (_rtw_memcmp(myhwaddr, pattrib->src, ETH_ALEN)){ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,(" SA==myself \n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s SA="MAC_FMT", myhwaddr="MAC_FMT"\n", ++ __FUNCTION__, MAC_ARG(pattrib->src), MAC_ARG(myhwaddr)); ++ #endif ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ // da should be for me ++ if((!_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN))&& (!bmcast)) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_, ++ (" ap2sta_data_frame: compare DA fail; DA="MAC_FMT"\n", MAC_ARG(pattrib->dst))); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s DA="MAC_FMT"\n", __func__, MAC_ARG(pattrib->dst)); ++ #endif ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ ++ // check BSSID ++ if( _rtw_memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || ++ _rtw_memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || ++ (!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN)) ) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_, ++ (" ap2sta_data_frame: compare BSSID fail ; BSSID="MAC_FMT"\n", MAC_ARG(pattrib->bssid))); ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("mybssid="MAC_FMT"\n", MAC_ARG(mybssid))); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s BSSID="MAC_FMT", mybssid="MAC_FMT"\n", ++ __FUNCTION__, MAC_ARG(pattrib->bssid), MAC_ARG(mybssid)); ++ DBG_871X( "this adapter = %d, buddy adapter = %d\n", adapter->adapter_type, adapter->pbuddy_adapter->adapter_type ); ++ #endif ++ ++ if(!bmcast) ++ { ++ DBG_871X("issue_deauth to the nonassociated ap=" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->bssid)); ++ issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ++ } ++ ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ if(bmcast) ++ *psta = rtw_get_bcmc_stainfo(adapter); ++ else ++ *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); // get ap_info ++ ++ if (*psta == NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("ap2sta: can't get psta under STATION_MODE ; drop pkt\n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s can't get psta under STATION_MODE ; drop pkt\n", __FUNCTION__); ++ #endif ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ //if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) { ++ //} ++ ++ if (GetFrameSubType(ptr) & BIT(6)) { ++ /* No data, will not indicate to upper layer, temporily count it here */ ++ count_rx_stats(adapter, precv_frame, *psta); ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ ++ } ++ else if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) && ++ (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ) ++ { ++ _rtw_memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); ++ _rtw_memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); ++ _rtw_memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); ++ _rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ ++ // ++ _rtw_memcpy(pattrib->bssid, mybssid, ETH_ALEN); ++ ++ ++ *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); // get sta_info ++ if (*psta == NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("can't get psta under MP_MODE ; drop pkt\n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s can't get psta under WIFI_MP_STATE ; drop pkt\n", __FUNCTION__); ++ #endif ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ ++ } ++ else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ { ++ /* Special case */ ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ else ++ { ++ if(_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN)&& (!bmcast)) ++ { ++ *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); // get sta_info ++ if (*psta == NULL) ++ { ++ DBG_871X("issue_deauth to the ap=" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->bssid)); ++ ++ issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ++ } ++ } ++ ++ ret = _FAIL; ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s fw_state:0x%x\n", __FUNCTION__, get_fwstate(pmlmepriv)); ++ #endif ++ } ++ ++exit: ++ ++_func_exit_; ++ ++ return ret; ++ ++} ++ ++sint sta2ap_data_frame( ++ _adapter *adapter, ++ union recv_frame *precv_frame, ++ struct sta_info**psta ); ++sint sta2ap_data_frame( ++ _adapter *adapter, ++ union recv_frame *precv_frame, ++ struct sta_info**psta ) ++{ ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ struct rx_pkt_attrib *pattrib = & precv_frame->u.hdr.attrib; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ unsigned char *mybssid = get_bssid(pmlmepriv); ++ sint ret=_SUCCESS; ++ ++_func_enter_; ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ { ++ //For AP mode, RA=BSSID, TX=STA(SRC_ADDR), A3=DST_ADDR ++ if(!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN)) ++ { ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ *psta = rtw_get_stainfo(pstapriv, pattrib->src); ++ if (*psta == NULL) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("can't get psta under AP_MODE; drop pkt\n")); ++ DBG_871X("issue_deauth to sta=" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->src)); ++ ++ issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ++ ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ ++ process_pwrbit_data(adapter, precv_frame); ++ ++ if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) { ++ process_wmmps_data(adapter, precv_frame); ++ } ++ ++ if (GetFrameSubType(ptr) & BIT(6)) { ++ /* No data, will not indicate to upper layer, temporily count it here */ ++ count_rx_stats(adapter, precv_frame, *psta); ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ } ++ else { ++ u8 *myhwaddr = myid(&adapter->eeprompriv); ++ if (!_rtw_memcmp(pattrib->ra, myhwaddr, ETH_ALEN)) { ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ DBG_871X("issue_deauth to sta=" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->src)); ++ issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ ++exit: ++ ++_func_exit_; ++ ++ return ret; ++ ++} ++ ++sint validate_recv_ctrl_frame(_adapter *padapter, union recv_frame *precv_frame); ++sint validate_recv_ctrl_frame(_adapter *padapter, union recv_frame *precv_frame) ++{ ++#ifdef CONFIG_AP_MODE ++ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ //uint len = precv_frame->u.hdr.len; ++ ++ //DBG_871X("+validate_recv_ctrl_frame\n"); ++ ++ if (GetFrameType(pframe) != WIFI_CTRL_TYPE) ++ { ++ return _FAIL; ++ } ++ ++ //receive the frames that ra(a1) is my address ++ if (!_rtw_memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN)) ++ { ++ return _FAIL; ++ } ++ ++ //only handle ps-poll ++ if(GetFrameSubType(pframe) == WIFI_PSPOLL) ++ { ++ u16 aid; ++ u8 wmmps_ac=0; ++ struct sta_info *psta=NULL; ++ ++ aid = GetAid(pframe); ++ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ ++ if((psta==NULL) || (psta->aid!=aid)) ++ { ++ return _FAIL; ++ } ++ ++ //for rx pkt statistics ++ psta->sta_stats.rx_ctrl_pkts++; ++ ++ switch(pattrib->priority) ++ { ++ case 1: ++ case 2: ++ wmmps_ac = psta->uapsd_bk&BIT(0); ++ break; ++ case 4: ++ case 5: ++ wmmps_ac = psta->uapsd_vi&BIT(0); ++ break; ++ case 6: ++ case 7: ++ wmmps_ac = psta->uapsd_vo&BIT(0); ++ break; ++ case 0: ++ case 3: ++ default: ++ wmmps_ac = psta->uapsd_be&BIT(0); ++ break; ++ } ++ ++ if(wmmps_ac) ++ return _FAIL; ++ ++ if(psta->state & WIFI_STA_ALIVE_CHK_STATE) ++ { ++ DBG_871X("%s alive check-rx ps-poll\n", __func__); ++ psta->expire_to = pstapriv->expire_to; ++ psta->state ^= WIFI_STA_ALIVE_CHK_STATE; ++ } ++ ++ if((psta->state&WIFI_SLEEP_STATE) && (pstapriv->sta_dz_bitmap&BIT(psta->aid))) ++ { ++ _irqL irqL; ++ _list *xmitframe_plist, *xmitframe_phead; ++ struct xmit_frame *pxmitframe=NULL; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ //_enter_critical_bh(&psta->sleep_q.lock, &irqL); ++ _enter_critical_bh(&pxmitpriv->lock, &irqL); ++ ++ xmitframe_phead = get_list_head(&psta->sleep_q); ++ xmitframe_plist = get_next(xmitframe_phead); ++ ++ if ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) ++ { ++ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = get_next(xmitframe_plist); ++ ++ rtw_list_delete(&pxmitframe->list); ++ ++ psta->sleepq_len--; ++ ++ if(psta->sleepq_len>0) ++ pxmitframe->attrib.mdata = 1; ++ else ++ pxmitframe->attrib.mdata = 0; ++ ++ pxmitframe->attrib.triggered = 1; ++ ++ //DBG_871X("handling ps-poll, q_len=%d, tim=%x\n", psta->sleepq_len, pstapriv->tim_bitmap); ++ ++#if 0 ++ _exit_critical_bh(&psta->sleep_q.lock, &irqL); ++ if(rtw_hal_xmit(padapter, pxmitframe) == _TRUE) ++ { ++ rtw_os_xmit_complete(padapter, pxmitframe); ++ } ++ _enter_critical_bh(&psta->sleep_q.lock, &irqL); ++#endif ++ rtw_hal_xmitframe_enqueue(padapter, pxmitframe); ++ ++ if(psta->sleepq_len==0) ++ { ++ pstapriv->tim_bitmap &= ~BIT(psta->aid); ++ ++ //DBG_871X("after handling ps-poll, tim=%x\n", pstapriv->tim_bitmap); ++ ++ //upate BCN for TIM IE ++ //update_BCNTIM(padapter); ++ update_beacon(padapter, _TIM_IE_, NULL, _FALSE); ++ } ++ ++ //_exit_critical_bh(&psta->sleep_q.lock, &irqL); ++ _exit_critical_bh(&pxmitpriv->lock, &irqL); ++ ++ } ++ else ++ { ++ //_exit_critical_bh(&psta->sleep_q.lock, &irqL); ++ _exit_critical_bh(&pxmitpriv->lock, &irqL); ++ ++ //DBG_871X("no buffered packets to xmit\n"); ++ if(pstapriv->tim_bitmap&BIT(psta->aid)) ++ { ++ if(psta->sleepq_len==0) ++ { ++ DBG_871X("no buffered packets to xmit\n"); ++ ++ //issue nulldata with More data bit = 0 to indicate we have no buffered packets ++ issue_nulldata(padapter, psta->hwaddr, 0, 0, 0); ++ } ++ else ++ { ++ DBG_871X("error!psta->sleepq_len=%d\n", psta->sleepq_len); ++ psta->sleepq_len=0; ++ } ++ ++ pstapriv->tim_bitmap &= ~BIT(psta->aid); ++ ++ //upate BCN for TIM IE ++ //update_BCNTIM(padapter); ++ update_beacon(padapter, _TIM_IE_, NULL, _FALSE); ++ } ++ ++ } ++ ++ } ++ ++ } ++ ++#endif ++ ++ return _FAIL; ++ ++} ++ ++union recv_frame* recvframe_chk_defrag(PADAPTER padapter, union recv_frame *precv_frame); ++sint validate_recv_mgnt_frame(PADAPTER padapter, union recv_frame *precv_frame); ++sint validate_recv_mgnt_frame(PADAPTER padapter, union recv_frame *precv_frame) ++{ ++ //struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+validate_recv_mgnt_frame\n")); ++ ++#if 0 ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ { ++#ifdef CONFIG_NATIVEAP_MLME ++ mgt_dispatcher(padapter, precv_frame); ++#else ++ rtw_hostapd_mlme_rx(padapter, precv_frame); ++#endif ++ } ++ else ++ { ++ mgt_dispatcher(padapter, precv_frame); ++ } ++#endif ++ ++ precv_frame = recvframe_chk_defrag(padapter, precv_frame); ++ if (precv_frame == NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,("%s: fragment packet\n",__FUNCTION__)); ++ return _SUCCESS; ++ } ++ ++ { ++ //for rx pkt statistics ++ struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(precv_frame->u.hdr.rx_data)); ++ if (psta) { ++ psta->sta_stats.rx_mgnt_pkts++; ++ if (GetFrameSubType(precv_frame->u.hdr.rx_data) == WIFI_BEACON) ++ psta->sta_stats.rx_beacon_pkts++; ++ else if (GetFrameSubType(precv_frame->u.hdr.rx_data) == WIFI_PROBEREQ) ++ psta->sta_stats.rx_probereq_pkts++; ++ else if (GetFrameSubType(precv_frame->u.hdr.rx_data) == WIFI_PROBERSP) { ++ if (_rtw_memcmp(padapter->eeprompriv.mac_addr, GetAddr1Ptr(precv_frame->u.hdr.rx_data), ETH_ALEN) == _TRUE) ++ psta->sta_stats.rx_probersp_pkts++; ++ else if (is_broadcast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data)) ++ || is_multicast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data))) ++ psta->sta_stats.rx_probersp_bm_pkts++; ++ else ++ psta->sta_stats.rx_probersp_uo_pkts++; ++ } ++ } ++ } ++ ++#ifdef CONFIG_INTEL_PROXIM ++ if(padapter->proximity.proxim_on==_TRUE) ++ { ++ struct rx_pkt_attrib * pattrib=&precv_frame->u.hdr.attrib; ++ struct recv_stat* prxstat=( struct recv_stat * ) precv_frame->u.hdr.rx_head ; ++ u8 * pda,*psa,*pbssid,*ptr; ++ ptr=precv_frame->u.hdr.rx_data; ++ pda = get_da(ptr); ++ psa = get_sa(ptr); ++ pbssid = get_hdr_bssid(ptr); ++ ++ ++ _rtw_memcpy(pattrib->dst, pda, ETH_ALEN); ++ _rtw_memcpy(pattrib->src, psa, ETH_ALEN); ++ ++ _rtw_memcpy(pattrib->bssid, pbssid, ETH_ALEN); ++ ++ switch(pattrib->to_fr_ds) ++ { ++ case 0: ++ _rtw_memcpy(pattrib->ra, pda, ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, psa, ETH_ALEN); ++ break; ++ ++ case 1: ++ _rtw_memcpy(pattrib->ra, pda, ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pbssid, ETH_ALEN); ++ break; ++ ++ case 2: ++ _rtw_memcpy(pattrib->ra, pbssid, ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, psa, ETH_ALEN); ++ break; ++ ++ case 3: ++ _rtw_memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN); ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,(" case 3\n")); ++ break; ++ ++ default: ++ break; ++ ++ } ++ pattrib->priority=0; ++ pattrib->hdrlen = pattrib->to_fr_ds==3 ? 30 : 24; ++ ++ padapter->proximity.proxim_rx(padapter,precv_frame); ++ } ++#endif ++ mgt_dispatcher(padapter, precv_frame); ++ ++ return _SUCCESS; ++ ++} ++ ++sint validate_recv_data_frame(_adapter *adapter, union recv_frame *precv_frame); ++sint validate_recv_data_frame(_adapter *adapter, union recv_frame *precv_frame) ++{ ++ u8 bretry; ++ u8 *psa, *pda, *pbssid; ++ struct sta_info *psta = NULL; ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ struct rx_pkt_attrib *pattrib = & precv_frame->u.hdr.attrib; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct security_priv *psecuritypriv = &adapter->securitypriv; ++ sint ret = _SUCCESS; ++#ifdef CONFIG_TDLS ++ struct tdls_info *ptdlsinfo = &adapter->tdlsinfo; ++#endif //CONFIG_TDLS ++ ++_func_enter_; ++ ++ bretry = GetRetry(ptr); ++ pda = get_da(ptr); ++ psa = get_sa(ptr); ++ pbssid = get_hdr_bssid(ptr); ++ ++ if(pbssid == NULL){ ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s pbssid == NULL\n", __func__); ++ #endif ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ _rtw_memcpy(pattrib->dst, pda, ETH_ALEN); ++ _rtw_memcpy(pattrib->src, psa, ETH_ALEN); ++ ++ _rtw_memcpy(pattrib->bssid, pbssid, ETH_ALEN); ++ ++ switch(pattrib->to_fr_ds) ++ { ++ case 0: ++ _rtw_memcpy(pattrib->ra, pda, ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, psa, ETH_ALEN); ++ ret = sta2sta_data_frame(adapter, precv_frame, &psta); ++ break; ++ ++ case 1: ++ _rtw_memcpy(pattrib->ra, pda, ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pbssid, ETH_ALEN); ++ ret = ap2sta_data_frame(adapter, precv_frame, &psta); ++ break; ++ ++ case 2: ++ _rtw_memcpy(pattrib->ra, pbssid, ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, psa, ETH_ALEN); ++ ret = sta2ap_data_frame(adapter, precv_frame, &psta); ++ break; ++ ++ case 3: ++ _rtw_memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN); ++ ret =_FAIL; ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,(" case 3\n")); ++ break; ++ ++ default: ++ ret =_FAIL; ++ break; ++ ++ } ++ ++ if(ret ==_FAIL){ ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s case:%d, res:%d\n", __FUNCTION__, pattrib->to_fr_ds, ret); ++ #endif ++ goto exit; ++ } else if (ret == RTW_RX_HANDLED) { ++ goto exit; ++ } ++ ++ ++ if(psta==NULL){ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,(" after to_fr_ds_chk; psta==NULL \n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s psta == NULL\n", __func__); ++ #endif ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ //psta->rssi = prxcmd->rssi; ++ //psta->signal_quality= prxcmd->sq; ++ precv_frame->u.hdr.psta = psta; ++ ++ ++ pattrib->amsdu=0; ++ pattrib->ack_policy = 0; ++ //parsing QC field ++ if(pattrib->qos == 1) ++ { ++ pattrib->priority = GetPriority((ptr + 24)); ++ pattrib->ack_policy = GetAckpolicy((ptr + 24)); ++ pattrib->amsdu = GetAMsdu((ptr + 24)); ++ pattrib->hdrlen = pattrib->to_fr_ds==3 ? 32 : 26; ++ ++ if(pattrib->priority!=0 && pattrib->priority!=3) ++ { ++ adapter->recvpriv.bIsAnyNonBEPkts = _TRUE; ++ } ++ } ++ else ++ { ++ pattrib->priority=0; ++ pattrib->hdrlen = pattrib->to_fr_ds==3 ? 30 : 24; ++ } ++ ++ ++ if(pattrib->order)//HT-CTRL 11n ++ { ++ pattrib->hdrlen += 4; ++ } ++ ++ precv_frame->u.hdr.preorder_ctrl = &psta->recvreorder_ctrl[pattrib->priority]; ++ ++ // decache, drop duplicate recv packets ++ if(recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) == _FAIL) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("decache : drop pkt\n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s recv_decache return _FAIL\n", __func__); ++ #endif ++ ret= _FAIL; ++ goto exit; ++ } ++ ++#if 0 ++ if(psta->tdls_sta_state & TDLS_LINKED_STATE ) ++ { ++ if(psta->dot118021XPrivacy==_AES_) ++ pattrib->encrypt=psta->dot118021XPrivacy; ++ } ++#endif //CONFIG_TDLS ++ ++ if(pattrib->privacy){ ++ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("validate_recv_data_frame:pattrib->privacy=%x\n", pattrib->privacy)); ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("\n ^^^^^^^^^^^IS_MCAST(pattrib->ra(0x%02x))=%d^^^^^^^^^^^^^^^6\n", pattrib->ra[0],IS_MCAST(pattrib->ra))); ++ ++#ifdef CONFIG_TDLS ++ if((psta->tdls_sta_state & TDLS_LINKED_STATE) && (psta->dot118021XPrivacy==_AES_)) ++ { ++ pattrib->encrypt=psta->dot118021XPrivacy; ++ } ++ else ++#endif //CONFIG_TDLS ++ GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, IS_MCAST(pattrib->ra)); ++ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("\n pattrib->encrypt=%d\n",pattrib->encrypt)); ++ ++ SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, pattrib->encrypt); ++ } ++ else ++ { ++ pattrib->encrypt = 0; ++ pattrib->iv_len = pattrib->icv_len = 0; ++ } ++ ++exit: ++ ++_func_exit_; ++ ++ return ret; ++} ++ ++#ifdef CONFIG_IEEE80211W ++static sint validate_80211w_mgmt(_adapter *adapter, union recv_frame *precv_frame) ++{ ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct rx_pkt_attrib *pattrib = & precv_frame->u.hdr.attrib; ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ u8 type; ++ u8 subtype; ++ ++ type = GetFrameType(ptr); ++ subtype = GetFrameSubType(ptr); //bit(7)~bit(2) ++ ++ //only support station mode ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED) ++ && adapter->securitypriv.binstallBIPkey == _TRUE) ++ { ++ //unicast management frame decrypt ++ if(pattrib->privacy && !(IS_MCAST(GetAddr1Ptr(ptr))) && ++ (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC || subtype == WIFI_ACTION)) ++ { ++ u8 *ppp, *mgmt_DATA; ++ u32 data_len=0; ++ ppp = GetAddr2Ptr(ptr); ++ ++ pattrib->bdecrypted = 0; ++ pattrib->encrypt = _AES_; ++ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ //set iv and icv length ++ SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, pattrib->encrypt); ++ _rtw_memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN); ++ //actual management data frame body ++ data_len = pattrib->pkt_len - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len; ++ mgmt_DATA = rtw_zmalloc(data_len); ++ if(mgmt_DATA == NULL) ++ { ++ DBG_871X("%s mgmt allocate fail !!!!!!!!!\n", __FUNCTION__); ++ goto validate_80211w_fail; ++ } ++ /*//dump the packet content before decrypt ++ { ++ int pp; ++ printk("pattrib->pktlen = %d =>", pattrib->pkt_len); ++ for(pp=0;pp< pattrib->pkt_len; pp++) ++ printk(" %02x ", ptr[pp]); ++ printk("\n"); ++ }*/ ++ ++ precv_frame = decryptor(adapter, precv_frame); ++ //save actual management data frame body ++ _rtw_memcpy(mgmt_DATA, ptr+pattrib->hdrlen+pattrib->iv_len, data_len); ++ //overwrite the iv field ++ _rtw_memcpy(ptr+pattrib->hdrlen, mgmt_DATA, data_len); ++ //remove the iv and icv length ++ pattrib->pkt_len = pattrib->pkt_len - pattrib->iv_len - pattrib->icv_len; ++ rtw_mfree(mgmt_DATA, data_len); ++ /*//print packet content after decryption ++ { ++ int pp; ++ printk("after decryption pattrib->pktlen = %d @@=>", pattrib->pkt_len); ++ for(pp=0;pp< pattrib->pkt_len; pp++) ++ printk(" %02x ", ptr[pp]); ++ printk("\n"); ++ }*/ ++ if(!precv_frame) ++ { ++ DBG_871X("%s mgmt descrypt fail !!!!!!!!!\n", __FUNCTION__); ++ goto validate_80211w_fail; ++ } ++ } ++ else if(IS_MCAST(GetAddr1Ptr(ptr)) && ++ (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC)) ++ { ++ sint BIP_ret = _SUCCESS; ++ //verify BIP MME IE of broadcast/multicast de-auth/disassoc packet ++ BIP_ret = rtw_BIP_verify(adapter, (u8 * )precv_frame); ++ if(BIP_ret == _FAIL) ++ { ++ //DBG_871X("802.11w BIP verify fail\n"); ++ goto validate_80211w_fail; ++ } ++ else if(BIP_ret == RTW_RX_HANDLED) ++ { ++ //DBG_871X("802.11w recv none protected packet\n"); ++ //issue sa query request ++ issue_action_SA_Query(adapter, NULL, 0, 0); ++ goto validate_80211w_fail; ++ } ++ }//802.11w protect ++ else ++ { ++ if(subtype == WIFI_ACTION) ++ { ++ //according 802.11-2012 standard, these five types are not robust types ++ if( ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_PUBLIC && ++ ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_HT && ++ ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_UNPROTECTED_WNM && ++ ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_SELF_PROTECTED && ++ ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_P2P) ++ { ++ DBG_871X("action frame category=%d should robust\n", ptr[WLAN_HDR_A3_LEN]); ++ goto validate_80211w_fail; ++ } ++ } ++ else if(subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC) ++ { ++ DBG_871X("802.11w recv none protected packet\n"); ++ //issue sa query request ++ issue_action_SA_Query(adapter, NULL, 0, 0); ++ goto validate_80211w_fail; ++ } ++ } ++ } ++ return _SUCCESS; ++ ++validate_80211w_fail: ++ return _FAIL; ++ ++} ++#endif //CONFIG_IEEE80211W ++ ++sint validate_recv_frame(_adapter *adapter, union recv_frame *precv_frame); ++sint validate_recv_frame(_adapter *adapter, union recv_frame *precv_frame) ++{ ++ //shall check frame subtype, to / from ds, da, bssid ++ ++ //then call check if rx seq/frag. duplicated. ++ ++ u8 type; ++ u8 subtype; ++ sint retval = _SUCCESS; ++ struct rx_pkt_attrib *pattrib = & precv_frame->u.hdr.attrib; ++ ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ u8 ver =(unsigned char) (*ptr)&0x3 ; ++#ifdef CONFIG_FIND_BEST_CHANNEL ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++#endif ++ ++#ifdef CONFIG_TDLS ++ struct tdls_info *ptdlsinfo = &adapter->tdlsinfo; ++#endif //CONFIG_TDLS ++#ifdef CONFIG_WAPI_SUPPORT ++ PRT_WAPI_T pWapiInfo = &adapter->wapiInfo; ++ struct recv_frame_hdr *phdr = &precv_frame->u.hdr; ++ u8 wai_pkt = 0; ++ u16 sc; ++ u8 external_len = 0; ++#endif ++ ++_func_enter_; ++ ++ ++#ifdef CONFIG_FIND_BEST_CHANNEL ++ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { ++ int ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, rtw_get_oper_ch(adapter)); ++ if (ch_set_idx >= 0) ++ pmlmeext->channel_set[ch_set_idx].rx_count++; ++ } ++#endif ++ ++#ifdef CONFIG_TDLS ++ if(ptdlsinfo->ch_sensing==1 && ptdlsinfo->cur_channel !=0){ ++ ptdlsinfo->collect_pkt_num[ptdlsinfo->cur_channel-1]++; ++ } ++#endif //CONFIG_TDLS ++ ++#ifdef RTK_DMP_PLATFORM ++ if ( 0 ) ++ { ++ DBG_871X("++\n"); ++ { ++ int i; ++ for(i=0; i<64;i=i+8) ++ DBG_871X("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:", *(ptr+i), ++ *(ptr+i+1), *(ptr+i+2) ,*(ptr+i+3) ,*(ptr+i+4),*(ptr+i+5), *(ptr+i+6), *(ptr+i+7)); ++ ++ } ++ DBG_871X("--\n"); ++ } ++#endif //RTK_DMP_PLATFORM ++ ++ //add version chk ++ if(ver!=0){ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("validate_recv_data_frame fail! (ver!=0)\n")); ++ retval= _FAIL; ++ goto exit; ++ } ++ ++ type = GetFrameType(ptr); ++ subtype = GetFrameSubType(ptr); //bit(7)~bit(2) ++ ++ pattrib->to_fr_ds = get_tofr_ds(ptr); ++ ++ pattrib->frag_num = GetFragNum(ptr); ++ pattrib->seq_num = GetSequence(ptr); ++ ++ pattrib->pw_save = GetPwrMgt(ptr); ++ pattrib->mfrag = GetMFrag(ptr); ++ pattrib->mdata = GetMData(ptr); ++ pattrib->privacy = GetPrivacy(ptr); ++ pattrib->order = GetOrder(ptr); ++#ifdef CONFIG_WAPI_SUPPORT ++ sc = (pattrib->seq_num<<4) | pattrib->frag_num; ++#endif ++ ++#if 1 //Dump rx packets ++{ ++ u8 bDumpRxPkt; ++ rtw_hal_get_def_var(adapter, HAL_DEF_DBG_DUMP_RXPKT, &(bDumpRxPkt)); ++ if(bDumpRxPkt ==1){//dump all rx packets ++ int i; ++ DBG_871X("############################# \n"); ++ ++ for(i=0; i<64;i=i+8) ++ DBG_871X("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i), ++ *(ptr+i+1), *(ptr+i+2) ,*(ptr+i+3) ,*(ptr+i+4),*(ptr+i+5), *(ptr+i+6), *(ptr+i+7)); ++ DBG_871X("############################# \n"); ++ } ++ else if(bDumpRxPkt ==2){ ++ if(type== WIFI_MGT_TYPE){ ++ int i; ++ DBG_871X("############################# \n"); ++ ++ for(i=0; i<64;i=i+8) ++ DBG_871X("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i), ++ *(ptr+i+1), *(ptr+i+2) ,*(ptr+i+3) ,*(ptr+i+4),*(ptr+i+5), *(ptr+i+6), *(ptr+i+7)); ++ DBG_871X("############################# \n"); ++ } ++ } ++ else if(bDumpRxPkt ==3){ ++ if(type== WIFI_DATA_TYPE){ ++ int i; ++ DBG_871X("############################# \n"); ++ ++ for(i=0; i<64;i=i+8) ++ DBG_871X("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i), ++ *(ptr+i+1), *(ptr+i+2) ,*(ptr+i+3) ,*(ptr+i+4),*(ptr+i+5), *(ptr+i+6), *(ptr+i+7)); ++ DBG_871X("############################# \n"); ++ } ++ } ++} ++#endif ++ switch (type) ++ { ++ case WIFI_MGT_TYPE: //mgnt ++#ifdef CONFIG_IEEE80211W ++ if(validate_80211w_mgmt(adapter, precv_frame) == _FAIL) ++ { ++ retval = _FAIL; ++ break; ++ } ++#endif //CONFIG_IEEE80211W ++ ++ retval = validate_recv_mgnt_frame(adapter, precv_frame); ++ if (retval == _FAIL) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("validate_recv_mgnt_frame fail\n")); ++ } ++ retval = _FAIL; // only data frame return _SUCCESS ++ break; ++ case WIFI_CTRL_TYPE: //ctrl ++ retval = validate_recv_ctrl_frame(adapter, precv_frame); ++ if (retval == _FAIL) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("validate_recv_ctrl_frame fail\n")); ++ } ++ retval = _FAIL; // only data frame return _SUCCESS ++ break; ++ case WIFI_DATA_TYPE: //data ++#ifdef CONFIG_WAPI_SUPPORT ++ if(pattrib->qos) ++ external_len = 2; ++ else ++ external_len= 0; ++ ++ wai_pkt = rtw_wapi_is_wai_packet(adapter,ptr); ++ ++ phdr->bIsWaiPacket = wai_pkt; ++ ++ if(wai_pkt !=0){ ++ if(sc != adapter->wapiInfo.wapiSeqnumAndFragNum) ++ { ++ adapter->wapiInfo.wapiSeqnumAndFragNum = sc; ++ } ++ else ++ { ++ retval = _FAIL; ++ break; ++ } ++ } ++ else{ ++ ++ if(rtw_wapi_drop_for_key_absent(adapter,GetAddr2Ptr(ptr))){ ++ retval=_FAIL; ++ WAPI_TRACE(WAPI_RX,"drop for key absent for rx \n"); ++ break; ++ } ++ } ++ ++#endif ++ ++ rtw_led_control(adapter, LED_CTL_RX); ++ pattrib->qos = (subtype & BIT(7))? 1:0; ++ retval = validate_recv_data_frame(adapter, precv_frame); ++ if (retval == _FAIL) ++ { ++ struct recv_priv *precvpriv = &adapter->recvpriv; ++ //RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("validate_recv_data_frame fail\n")); ++ precvpriv->rx_drop++; ++ } ++ break; ++ default: ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("validate_recv_data_frame fail! type=0x%x\n", type)); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME validate_recv_data_frame fail! type=0x%x\n", type); ++ #endif ++ retval = _FAIL; ++ break; ++ } ++ ++exit: ++ ++_func_exit_; ++ ++ return retval; ++} ++ ++ ++//remove the wlanhdr and add the eth_hdr ++#if 1 ++ ++sint wlanhdr_to_ethhdr ( union recv_frame *precvframe); ++sint wlanhdr_to_ethhdr ( union recv_frame *precvframe) ++{ ++ sint rmv_len; ++ u16 eth_type, len; ++ u8 bsnaphdr; ++ u8 *psnap_type; ++ struct ieee80211_snap_hdr *psnap; ++ ++ sint ret=_SUCCESS; ++ _adapter *adapter =precvframe->u.hdr.adapter; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ ++ u8 *ptr = get_recvframe_data(precvframe) ; // point to frame_ctrl field ++ struct rx_pkt_attrib *pattrib = & precvframe->u.hdr.attrib; ++ ++_func_enter_; ++ ++ if(pattrib->encrypt){ ++ recvframe_pull_tail(precvframe, pattrib->icv_len); ++ } ++ ++ psnap=(struct ieee80211_snap_hdr *)(ptr+pattrib->hdrlen + pattrib->iv_len); ++ psnap_type=ptr+pattrib->hdrlen + pattrib->iv_len+SNAP_SIZE; ++ /* convert hdr + possible LLC headers into Ethernet header */ ++ //eth_type = (psnap_type[0] << 8) | psnap_type[1]; ++ if((_rtw_memcmp(psnap, rtw_rfc1042_header, SNAP_SIZE) && ++ (_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_IPX, 2) == _FALSE) && ++ (_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_AARP, 2)==_FALSE) )|| ++ //eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || ++ _rtw_memcmp(psnap, rtw_bridge_tunnel_header, SNAP_SIZE)){ ++ /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */ ++ bsnaphdr = _TRUE; ++ } ++ else { ++ /* Leave Ethernet header part of hdr and full payload */ ++ bsnaphdr = _FALSE; ++ } ++ ++ rmv_len = pattrib->hdrlen + pattrib->iv_len +(bsnaphdr?SNAP_SIZE:0); ++ len = precvframe->u.hdr.len - rmv_len; ++ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("\n===pattrib->hdrlen: %x, pattrib->iv_len:%x ===\n\n", pattrib->hdrlen, pattrib->iv_len)); ++ ++ _rtw_memcpy(ð_type, ptr+rmv_len, 2); ++ eth_type= ntohs((unsigned short )eth_type); //pattrib->ether_type ++ pattrib->eth_type = eth_type; ++ ++ if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE)) ++ { ++ ptr += rmv_len ; ++ *ptr = 0x87; ++ *(ptr+1) = 0x12; ++ ++ eth_type = 0x8712; ++ // append rx status for mp test packets ++ ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr)+2)-24); ++ _rtw_memcpy(ptr, get_rxmem(precvframe), 24); ++ ptr+=24; ++ } ++ else { ++ ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr)+ (bsnaphdr?2:0))); ++ } ++ ++ _rtw_memcpy(ptr, pattrib->dst, ETH_ALEN); ++ _rtw_memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN); ++ ++ if(!bsnaphdr) { ++ len = htons(len); ++ _rtw_memcpy(ptr+12, &len, 2); ++ } ++ ++_func_exit_; ++ return ret; ++ ++} ++ ++#else ++ ++sint wlanhdr_to_ethhdr ( union recv_frame *precvframe) ++{ ++ sint rmv_len; ++ u16 eth_type; ++ u8 bsnaphdr; ++ u8 *psnap_type; ++ struct ieee80211_snap_hdr *psnap; ++ ++ sint ret=_SUCCESS; ++ _adapter *adapter =precvframe->u.hdr.adapter; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ ++ u8* ptr = get_recvframe_data(precvframe) ; // point to frame_ctrl field ++ struct rx_pkt_attrib *pattrib = & precvframe->u.hdr.attrib; ++ struct _vlan *pvlan = NULL; ++ ++_func_enter_; ++ ++ psnap=(struct ieee80211_snap_hdr *)(ptr+pattrib->hdrlen + pattrib->iv_len); ++ psnap_type=ptr+pattrib->hdrlen + pattrib->iv_len+SNAP_SIZE; ++ if (psnap->dsap==0xaa && psnap->ssap==0xaa && psnap->ctrl==0x03) ++ { ++ if (_rtw_memcmp(psnap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN)) ++ bsnaphdr=_TRUE;//wlan_pkt_format = WLAN_PKT_FORMAT_SNAP_RFC1042; ++ else if (_rtw_memcmp(psnap->oui, SNAP_HDR_APPLETALK_DDP, WLAN_IEEE_OUI_LEN) && ++ _rtw_memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_DDP, 2) ) ++ bsnaphdr=_TRUE; //wlan_pkt_format = WLAN_PKT_FORMAT_APPLETALK; ++ else if (_rtw_memcmp( psnap->oui, oui_8021h, WLAN_IEEE_OUI_LEN)) ++ bsnaphdr=_TRUE; //wlan_pkt_format = WLAN_PKT_FORMAT_SNAP_TUNNEL; ++ else { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("drop pkt due to invalid frame format!\n")); ++ ret= _FAIL; ++ goto exit; ++ } ++ ++ } else ++ bsnaphdr=_FALSE;//wlan_pkt_format = WLAN_PKT_FORMAT_OTHERS; ++ ++ rmv_len = pattrib->hdrlen + pattrib->iv_len +(bsnaphdr?SNAP_SIZE:0); ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("===pattrib->hdrlen: %x, pattrib->iv_len:%x ===\n", pattrib->hdrlen, pattrib->iv_len)); ++ ++ if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) ++ { ++ ptr += rmv_len ; ++ *ptr = 0x87; ++ *(ptr+1) = 0x12; ++ ++ //back to original pointer ++ ptr -= rmv_len; ++ } ++ ++ ptr += rmv_len ; ++ ++ _rtw_memcpy(ð_type, ptr, 2); ++ eth_type= ntohs((unsigned short )eth_type); //pattrib->ether_type ++ ptr +=2; ++ ++ if(pattrib->encrypt){ ++ recvframe_pull_tail(precvframe, pattrib->icv_len); ++ } ++ ++ if(eth_type == 0x8100) //vlan ++ { ++ pvlan = (struct _vlan *) ptr; ++ ++ //eth_type = get_vlan_encap_proto(pvlan); ++ //eth_type = pvlan->h_vlan_encapsulated_proto;//? ++ rmv_len += 4; ++ ptr+=4; ++ } ++ ++ if(eth_type==0x0800)//ip ++ { ++ //struct iphdr* piphdr = (struct iphdr*) ptr; ++ //__u8 tos = (unsigned char)(pattrib->priority & 0xff); ++ ++ //piphdr->tos = tos; ++ ++ //if (piphdr->protocol == 0x06) ++ //{ ++ // RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("@@@===recv tcp len:%d @@@===\n", precvframe->u.hdr.len)); ++ //} ++ } ++ else if(eth_type==0x8712)// append rx status for mp test packets ++ { ++ //ptr -= 16; ++ //_rtw_memcpy(ptr, get_rxmem(precvframe), 16); ++ } ++ else ++ { ++#ifdef PLATFORM_OS_XP ++ NDIS_PACKET_8021Q_INFO VlanPriInfo; ++ UINT32 UserPriority = precvframe->u.hdr.attrib.priority; ++ UINT32 VlanID = (pvlan!=NULL ? get_vlan_id(pvlan) : 0 ); ++ ++ VlanPriInfo.Value = // Get current value. ++ NDIS_PER_PACKET_INFO_FROM_PACKET(precvframe->u.hdr.pkt, Ieee8021QInfo); ++ ++ VlanPriInfo.TagHeader.UserPriority = UserPriority; ++ VlanPriInfo.TagHeader.VlanId = VlanID ; ++ ++ VlanPriInfo.TagHeader.CanonicalFormatId = 0; // Should be zero. ++ VlanPriInfo.TagHeader.Reserved = 0; // Should be zero. ++ NDIS_PER_PACKET_INFO_FROM_PACKET(precvframe->u.hdr.pkt, Ieee8021QInfo) = VlanPriInfo.Value; ++#endif ++ } ++ ++ if(eth_type==0x8712)// append rx status for mp test packets ++ { ++ ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr)+2)-24); ++ _rtw_memcpy(ptr, get_rxmem(precvframe), 24); ++ ptr+=24; ++ } ++ else ++ ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr)+2)); ++ ++ _rtw_memcpy(ptr, pattrib->dst, ETH_ALEN); ++ _rtw_memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN); ++ ++ eth_type = htons((unsigned short)eth_type) ; ++ _rtw_memcpy(ptr+12, ð_type, 2); ++ ++exit: ++ ++_func_exit_; ++ ++ return ret; ++} ++#endif ++ ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++#ifdef PLATFORM_LINUX ++static void recvframe_expand_pkt( ++ PADAPTER padapter, ++ union recv_frame *prframe) ++{ ++ struct recv_frame_hdr *pfhdr; ++ _pkt *ppkt; ++ u8 shift_sz; ++ u32 alloc_sz; ++ ++ ++ pfhdr = &prframe->u.hdr; ++ ++ // 6 is for IP header 8 bytes alignment in QoS packet case. ++ if (pfhdr->attrib.qos) ++ shift_sz = 6; ++ else ++ shift_sz = 0; ++ ++ // for first fragment packet, need to allocate ++ // (1536 + RXDESC_SIZE + drvinfo_sz) to reassemble packet ++ // 8 is for skb->data 8 bytes alignment. ++// alloc_sz = _RND(1536 + RXDESC_SIZE + pfhdr->attrib.drvinfosize + shift_sz + 8, 128); ++ alloc_sz = 1664; // round (1536 + 24 + 32 + shift_sz + 8) to 128 bytes alignment ++ ++ //3 1. alloc new skb ++ // prepare extra space for 4 bytes alignment ++ ppkt = rtw_skb_alloc(alloc_sz); ++ ++ if (!ppkt) return; // no way to expand ++ ++ //3 2. Prepare new skb to replace & release old skb ++ // force ppkt->data at 8-byte alignment address ++ skb_reserve(ppkt, 8 - ((SIZE_PTR)ppkt->data & 7)); ++ // force ip_hdr at 8-byte alignment address according to shift_sz ++ skb_reserve(ppkt, shift_sz); ++ ++ // copy data to new pkt ++ _rtw_memcpy(skb_put(ppkt, pfhdr->len), pfhdr->rx_data, pfhdr->len); ++ ++ rtw_skb_free(pfhdr->pkt); ++ ++ // attach new pkt to recvframe ++ pfhdr->pkt = ppkt; ++ pfhdr->rx_head = ppkt->head; ++ pfhdr->rx_data = ppkt->data; ++ pfhdr->rx_tail = skb_tail_pointer(ppkt); ++ pfhdr->rx_end = skb_end_pointer(ppkt); ++} ++#else ++#warning "recvframe_expand_pkt not implement, defrag may crash system" ++#endif ++#endif ++ ++//perform defrag ++union recv_frame * recvframe_defrag(_adapter *adapter,_queue *defrag_q); ++union recv_frame * recvframe_defrag(_adapter *adapter,_queue *defrag_q) ++{ ++ _list *plist, *phead; ++ u8 *data,wlanhdr_offset; ++ u8 curfragnum; ++ struct recv_frame_hdr *pfhdr,*pnfhdr; ++ union recv_frame* prframe, *pnextrframe; ++ _queue *pfree_recv_queue; ++ ++_func_enter_; ++ ++ curfragnum=0; ++ pfree_recv_queue=&adapter->recvpriv.free_recv_queue; ++ ++ phead = get_list_head(defrag_q); ++ plist = get_next(phead); ++ prframe = LIST_CONTAINOR(plist, union recv_frame, u); ++ pfhdr=&prframe->u.hdr; ++ rtw_list_delete(&(prframe->u.list)); ++ ++ if(curfragnum!=pfhdr->attrib.frag_num) ++ { ++ //the first fragment number must be 0 ++ //free the whole queue ++ rtw_free_recvframe(prframe, pfree_recv_queue); ++ rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); ++ ++ return NULL; ++ } ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++#ifndef CONFIG_SDIO_RX_COPY ++ recvframe_expand_pkt(adapter, prframe); ++#endif ++#endif ++ ++ curfragnum++; ++ ++ plist= get_list_head(defrag_q); ++ ++ plist = get_next(plist); ++ ++ data=get_recvframe_data(prframe); ++ ++ while(rtw_end_of_queue_search(phead, plist) == _FALSE) ++ { ++ pnextrframe = LIST_CONTAINOR(plist, union recv_frame , u); ++ pnfhdr=&pnextrframe->u.hdr; ++ ++ ++ //check the fragment sequence (2nd ~n fragment frame) ++ ++ if(curfragnum!=pnfhdr->attrib.frag_num) ++ { ++ //the fragment number must be increasing (after decache) ++ //release the defrag_q & prframe ++ rtw_free_recvframe(prframe, pfree_recv_queue); ++ rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); ++ return NULL; ++ } ++ ++ curfragnum++; ++ ++ //copy the 2nd~n fragment frame's payload to the first fragment ++ //get the 2nd~last fragment frame's payload ++ ++ wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len; ++ ++ recvframe_pull(pnextrframe, wlanhdr_offset); ++ ++ //append to first fragment frame's tail (if privacy frame, pull the ICV) ++ recvframe_pull_tail(prframe, pfhdr->attrib.icv_len); ++ ++ //memcpy ++ _rtw_memcpy(pfhdr->rx_tail, pnfhdr->rx_data, pnfhdr->len); ++ ++ recvframe_put(prframe, pnfhdr->len); ++ ++ pfhdr->attrib.icv_len=pnfhdr->attrib.icv_len; ++ plist = get_next(plist); ++ ++ }; ++ ++ //free the defrag_q queue and return the prframe ++ rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); ++ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("Performance defrag!!!!!\n")); ++ ++_func_exit_; ++ ++ return prframe; ++} ++ ++//check if need to defrag, if needed queue the frame to defrag_q ++union recv_frame* recvframe_chk_defrag(PADAPTER padapter, union recv_frame *precv_frame) ++{ ++ u8 ismfrag; ++ u8 fragnum; ++ u8 *psta_addr; ++ struct recv_frame_hdr *pfhdr; ++ struct sta_info *psta; ++ struct sta_priv *pstapriv; ++ _list *phead; ++ union recv_frame *prtnframe = NULL; ++ _queue *pfree_recv_queue, *pdefrag_q; ++ ++_func_enter_; ++ ++ pstapriv = &padapter->stapriv; ++ ++ pfhdr = &precv_frame->u.hdr; ++ ++ pfree_recv_queue = &padapter->recvpriv.free_recv_queue; ++ ++ //need to define struct of wlan header frame ctrl ++ ismfrag = pfhdr->attrib.mfrag; ++ fragnum = pfhdr->attrib.frag_num; ++ ++ psta_addr = pfhdr->attrib.ta; ++ psta = rtw_get_stainfo(pstapriv, psta_addr); ++ if (psta == NULL) ++ { ++ u8 type = GetFrameType(pfhdr->rx_data); ++ if (type != WIFI_DATA_TYPE) { ++ psta = rtw_get_bcmc_stainfo(padapter); ++ pdefrag_q = &psta->sta_recvpriv.defrag_q; ++ } else ++ pdefrag_q = NULL; ++ } ++ else ++ pdefrag_q = &psta->sta_recvpriv.defrag_q; ++ ++ if ((ismfrag==0) && (fragnum==0)) ++ { ++ prtnframe = precv_frame;//isn't a fragment frame ++ } ++ ++ if (ismfrag==1) ++ { ++ //0~(n-1) fragment frame ++ //enqueue to defraf_g ++ if(pdefrag_q != NULL) ++ { ++ if(fragnum==0) ++ { ++ //the first fragment ++ if(_rtw_queue_empty(pdefrag_q) == _FALSE) ++ { ++ //free current defrag_q ++ rtw_free_recvframe_queue(pdefrag_q, pfree_recv_queue); ++ } ++ } ++ ++ ++ //Then enqueue the 0~(n-1) fragment into the defrag_q ++ ++ //_rtw_spinlock(&pdefrag_q->lock); ++ phead = get_list_head(pdefrag_q); ++ rtw_list_insert_tail(&pfhdr->list, phead); ++ //_rtw_spinunlock(&pdefrag_q->lock); ++ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("Enqueuq: ismfrag = %d, fragnum= %d\n", ismfrag,fragnum)); ++ ++ prtnframe=NULL; ++ ++ } ++ else ++ { ++ //can't find this ta's defrag_queue, so free this recv_frame ++ rtw_free_recvframe(precv_frame, pfree_recv_queue); ++ prtnframe=NULL; ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("Free because pdefrag_q ==NULL: ismfrag = %d, fragnum= %d\n", ismfrag, fragnum)); ++ } ++ ++ } ++ ++ if((ismfrag==0)&&(fragnum!=0)) ++ { ++ //the last fragment frame ++ //enqueue the last fragment ++ if(pdefrag_q != NULL) ++ { ++ //_rtw_spinlock(&pdefrag_q->lock); ++ phead = get_list_head(pdefrag_q); ++ rtw_list_insert_tail(&pfhdr->list,phead); ++ //_rtw_spinunlock(&pdefrag_q->lock); ++ ++ //call recvframe_defrag to defrag ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("defrag: ismfrag = %d, fragnum= %d\n", ismfrag, fragnum)); ++ precv_frame = recvframe_defrag(padapter, pdefrag_q); ++ prtnframe=precv_frame; ++ ++ } ++ else ++ { ++ //can't find this ta's defrag_queue, so free this recv_frame ++ rtw_free_recvframe(precv_frame, pfree_recv_queue); ++ prtnframe=NULL; ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("Free because pdefrag_q ==NULL: ismfrag = %d, fragnum= %d\n", ismfrag,fragnum)); ++ } ++ ++ } ++ ++ ++ if((prtnframe!=NULL)&&(prtnframe->u.hdr.attrib.privacy)) ++ { ++ //after defrag we must check tkip mic code ++ if(recvframe_chkmic(padapter, prtnframe)==_FAIL) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("recvframe_chkmic(padapter, prtnframe)==_FAIL\n")); ++ rtw_free_recvframe(prtnframe,pfree_recv_queue); ++ prtnframe=NULL; ++ } ++ } ++ ++_func_exit_; ++ ++ return prtnframe; ++ ++} ++ ++#define ENDIAN_FREE 1 ++ ++int amsdu_to_msdu(_adapter *padapter, union recv_frame *prframe); ++int amsdu_to_msdu(_adapter *padapter, union recv_frame *prframe) ++{ ++#if defined (PLATFORM_LINUX) || defined (PLATFORM_FREEBSD) //for amsdu TP improvement,Creator: Thomas ++ int a_len, padding_len; ++ u16 eth_type, nSubframe_Length; ++ u8 nr_subframes, i; ++ unsigned char *pdata; ++ struct rx_pkt_attrib *pattrib; ++#ifndef PLATFORM_FREEBSD ++ unsigned char *data_ptr; ++ _pkt *sub_skb,*subframes[MAX_SUBFRAME_COUNT]; ++#endif //PLATFORM_FREEBSD ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ _queue *pfree_recv_queue = &(precvpriv->free_recv_queue); ++ int ret = _SUCCESS; ++#ifdef PLATFORM_FREEBSD ++ struct mbuf *sub_m=NULL, *subframes[MAX_SUBFRAME_COUNT]; ++ u8 *ptr,offset; ++#endif //PLATFORM_FREEBSD ++ nr_subframes = 0; ++ ++ pattrib = &prframe->u.hdr.attrib; ++ ++ recvframe_pull(prframe, prframe->u.hdr.attrib.hdrlen); ++ ++ if(prframe->u.hdr.attrib.iv_len >0) ++ { ++ recvframe_pull(prframe, prframe->u.hdr.attrib.iv_len); ++ } ++ ++ a_len = prframe->u.hdr.len; ++ ++ pdata = prframe->u.hdr.rx_data; ++ ++ while(a_len > ETH_HLEN) { ++ ++ /* Offset 12 denote 2 mac address */ ++#ifdef ENDIAN_FREE ++ //nSubframe_Length = ntohs(*((u16*)(pdata + 12))); ++ nSubframe_Length = RTW_GET_BE16(pdata + 12); ++#else // ENDIAN_FREE ++ nSubframe_Length = *((u16*)(pdata + 12)); ++ //==m==>change the length order ++ nSubframe_Length = (nSubframe_Length>>8) + (nSubframe_Length<<8); ++ //ntohs(nSubframe_Length); ++#endif // ENDIAN_FREE ++ ++ if( a_len < (ETHERNET_HEADER_SIZE + nSubframe_Length) ) { ++ DBG_871X("nRemain_Length is %d and nSubframe_Length is : %d\n",a_len,nSubframe_Length); ++ goto exit; ++ } ++ ++#ifndef PLATFORM_FREEBSD ++ /* move the data point to data content */ ++ pdata += ETH_HLEN; ++ a_len -= ETH_HLEN; ++ ++ /* Allocate new skb for releasing to upper layer */ ++#ifdef CONFIG_SKB_COPY ++ sub_skb = rtw_skb_alloc(nSubframe_Length + 12); ++ if(sub_skb) ++ { ++ skb_reserve(sub_skb, 12); ++ data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length); ++ _rtw_memcpy(data_ptr, pdata, nSubframe_Length); ++ } ++ else ++#endif // CONFIG_SKB_COPY ++ { ++ sub_skb = rtw_skb_clone(prframe->u.hdr.pkt); ++ if(sub_skb) ++ { ++ sub_skb->data = pdata; ++ sub_skb->len = nSubframe_Length; ++ skb_set_tail_pointer(sub_skb, nSubframe_Length); ++ } ++ else ++ { ++ DBG_871X("rtw_skb_clone() Fail!!! , nr_subframes = %d\n",nr_subframes); ++ break; ++ } ++ } ++ ++#else // PLATFORM_FREEBSD ++ ++ //PLATFORM_FREEBSD ++ //Allocate a mbuff, ++ //sub_m =m_devget(pdata, nSubframe_Length+12, 12, padapter->pifp,NULL); ++ sub_m =m_devget(pdata, nSubframe_Length+ETH_HLEN, ETHER_ALIGN, padapter->pifp,NULL); ++ ++ pdata += ETH_HLEN; ++ a_len -= ETH_HLEN; ++#endif // PLATFORM_FREEBSD ++ ++#ifndef PLATFORM_FREEBSD ++ //sub_skb->dev = padapter->pnetdev; ++ subframes[nr_subframes++] = sub_skb; ++#else //PLATFORM_FREEBSD ++ //PLATFORM_FREEBSD ++ subframes[nr_subframes++] = sub_m; ++#endif //PLATFORM_FREEBSD ++ ++ if(nr_subframes >= MAX_SUBFRAME_COUNT) { ++ DBG_871X("ParseSubframe(): Too many Subframes! Packets dropped!\n"); ++ break; ++ } ++ ++ pdata += nSubframe_Length; ++ a_len -= nSubframe_Length; ++ if(a_len != 0) { ++ padding_len = 4 - ((nSubframe_Length + ETH_HLEN) & (4-1)); ++ if(padding_len == 4) { ++ padding_len = 0; ++ } ++ ++ if(a_len < padding_len) { ++ goto exit; ++ } ++ pdata += padding_len; ++ a_len -= padding_len; ++ } ++ } ++ ++ for(i=0; idata[6]); ++ eth_type = RTW_GET_BE16(&sub_skb->data[6]); ++#else // ENDIAN_FREE ++ eth_type = (sub_skb->data[6] << 8) | sub_skb->data[7]; ++#endif // ENDIAN_FREE ++ if (sub_skb->len >= 8 && ++ ((_rtw_memcmp(sub_skb->data, rtw_rfc1042_header, SNAP_SIZE) && ++ eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || ++ _rtw_memcmp(sub_skb->data, rtw_bridge_tunnel_header, SNAP_SIZE) )) { ++ /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */ ++ skb_pull(sub_skb, SNAP_SIZE); ++ _rtw_memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN); ++ _rtw_memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN); ++ } else { ++ u16 len; ++ /* Leave Ethernet header part of hdr and full payload */ ++ len = htons(sub_skb->len); ++ _rtw_memcpy(skb_push(sub_skb, 2), &len, 2); ++ _rtw_memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN); ++ _rtw_memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN); ++ } ++ ++ /* Indicat the packets to upper layer */ ++ if (sub_skb) { ++ //memset(sub_skb->cb, 0, sizeof(sub_skb->cb)); ++ ++#ifdef CONFIG_BR_EXT ++ // Insert NAT2.5 RX here! ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ void *br_port = NULL; ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ br_port = padapter->pnetdev->br_port; ++#else // (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ rcu_read_lock(); ++ br_port = rcu_dereference(padapter->pnetdev->rx_handler_data); ++ rcu_read_unlock(); ++#endif // (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ ++ ++ if( br_port && (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) == _TRUE) ) ++ { ++ int nat25_handle_frame(_adapter *priv, struct sk_buff *skb); ++ if (nat25_handle_frame(padapter, sub_skb) == -1) { ++ //priv->ext_stats.rx_data_drops++; ++ //DEBUG_ERR("RX DROP: nat25_handle_frame fail!\n"); ++ //return FAIL; ++ ++#if 1 ++ // bypass this frame to upper layer!! ++#else ++ rtw_skb_free(sub_skb); ++ continue; ++#endif ++ } ++ } ++#endif // CONFIG_BR_EXT ++ ++ sub_skb->protocol = eth_type_trans(sub_skb, padapter->pnetdev); ++ sub_skb->dev = padapter->pnetdev; ++ ++#ifdef CONFIG_TCP_CSUM_OFFLOAD_RX ++ if ( (pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1) ) { ++ sub_skb->ip_summed = CHECKSUM_UNNECESSARY; ++ } else { ++ sub_skb->ip_summed = CHECKSUM_NONE; ++ } ++#else /* !CONFIG_TCP_CSUM_OFFLOAD_RX */ ++ sub_skb->ip_summed = CHECKSUM_NONE; ++#endif //CONFIG_TCP_CSUM_OFFLOAD_RX ++ ++ rtw_netif_rx(padapter->pnetdev, sub_skb); ++ } ++#else //PLATFORM_FREEBSD ++ ++ //PLATFORM_FREEBSD ++ sub_m = subframes[i]; ++ ptr=mtod(sub_m, u8 *); ++ offset=ETH_HLEN; ++ /* convert hdr + possible LLC headers into Ethernet header */ ++#ifdef ENDIAN_FREE ++ eth_type = ntohs(*(u16*)&ptr[offset+6]); ++#else // ENDIAN_FREE ++ eth_type = ( ptr[offset+6] << 8) | ptr[offset+7]; ++#endif // ENDIAN_FREE ++ if (sub_m->m_pkthdr.len >= ETH_HLEN+8 && ++ ((_rtw_memcmp(ptr+ETH_HLEN, rtw_rfc1042_header, SNAP_SIZE) && ++ eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || ++ _rtw_memcmp(ptr+ETH_HLEN, rtw_bridge_tunnel_header, SNAP_SIZE) )) { ++ /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */ ++ offset+=SNAP_SIZE; ++ _rtw_memcpy(&ptr[offset-ETH_ALEN], pattrib->src, ETH_ALEN); ++ offset-=ETH_ALEN; ++ _rtw_memcpy(&ptr[offset-ETH_ALEN], pattrib->dst, ETH_ALEN); ++ offset-=ETH_ALEN; ++ } else { ++ u16 len; ++ /* Leave Ethernet header part of hdr and full payload */ ++ len = htons(sub_m->m_pkthdr.len-offset); ++ _rtw_memcpy(&ptr[offset- 2], &len, 2); ++ offset-=2; ++ _rtw_memcpy(&ptr[offset-ETH_ALEN], pattrib->src, ETH_ALEN); ++ offset-=ETH_ALEN; ++ _rtw_memcpy(&ptr[offset-ETH_ALEN], pattrib->dst, ETH_ALEN); ++ offset-=ETH_ALEN; ++ } ++ ++ m_adj(sub_m,offset); ++ ++ /* Indicat the packets to upper layer */ ++ if (sub_m) { ++ ++#if 0 ++#ifdef CONFIG_TCP_CSUM_OFFLOAD_RX ++ if ( (pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1) ) { ++ sub_skb->ip_summed = CHECKSUM_UNNECESSARY; ++ } else { ++ sub_skb->ip_summed = CHECKSUM_NONE; ++ } ++#else /* !CONFIG_TCP_CSUM_OFFLOAD_RX */ ++ sub_skb->ip_summed = CHECKSUM_NONE; ++#endif //CONFIG_TCP_CSUM_OFFLOAD_RX ++#endif //0 ++ ++ if ( ((u32)(mtod(sub_m, caddr_t) + 14) % 4) != 0) ++ printf("%s()-%d: mtod(sub_m) = %p\n", __FUNCTION__, __LINE__, mtod(sub_m, caddr_t)); ++#ifdef CONFIG_RX_INDICATE_QUEUE ++ IF_ENQUEUE(&precvpriv->rx_indicate_queue, sub_m); ++ if (_IF_QLEN(&precvpriv->rx_indicate_queue) <= 1) { ++ taskqueue_enqueue(taskqueue_thread, &precvpriv->rx_indicate_tasklet); ++ } ++#else // CONFIG_RX_INDICATE_QUEUE ++ (*padapter->pifp->if_input)(padapter->pifp, sub_m); ++#endif // CONFIG_RX_INDICATE_QUEUE ++ } ++ ++#endif //PLATFORM_FREEBSD ++ } ++ ++exit: ++ ++ prframe->u.hdr.len=0; ++ rtw_free_recvframe(prframe, pfree_recv_queue);//free this recv_frame ++ ++ return ret; ++#else // || defined (PLATFORM_LINUX) || defined (PLATFORM_FREEBSD) ++#ifdef PLATFORM_WINDOWS ++ _irqL irql; ++#endif //PLATFORM_WINDOWS ++ unsigned char *ptr, *pdata, *pbuf, *psnap_type; ++ union recv_frame *pnrframe, *pnrframe_new; ++ int a_len, mv_len, padding_len; ++ u16 eth_type, type_len; ++ u8 bsnaphdr; ++ struct ieee80211_snap_hdr *psnap; ++ struct _vlan *pvlan; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ _queue *pfree_recv_queue = &(precvpriv->free_recv_queue); ++ int ret = _SUCCESS; ++#ifdef PLATFORM_WINDOWS ++ struct recv_buf *precvbuf = prframe->u.hdr.precvbuf; ++#endif //PLATFORM_WINDOWS ++ a_len = prframe->u.hdr.len - prframe->u.hdr.attrib.hdrlen; ++ ++ recvframe_pull(prframe, prframe->u.hdr.attrib.hdrlen); ++ ++ if(prframe->u.hdr.attrib.iv_len >0) ++ { ++ recvframe_pull(prframe, prframe->u.hdr.attrib.iv_len); ++ } ++ ++ pdata = prframe->u.hdr.rx_data; ++ ++ prframe->u.hdr.len=0; ++ ++ pnrframe = prframe; ++ ++ ++ do{ ++ ++ mv_len=0; ++ pnrframe->u.hdr.rx_data = pnrframe->u.hdr.rx_tail = pdata; ++ ptr = pdata; ++ ++ ++ _rtw_memcpy(pnrframe->u.hdr.attrib.dst, ptr, ETH_ALEN); ++ ptr+=ETH_ALEN; ++ _rtw_memcpy(pnrframe->u.hdr.attrib.src, ptr, ETH_ALEN); ++ ptr+=ETH_ALEN; ++ ++ _rtw_memcpy(&type_len, ptr, 2); ++ type_len= ntohs((unsigned short )type_len); ++ ptr +=2; ++ mv_len += ETH_HLEN; ++ ++ recvframe_put(pnrframe, type_len+ETH_HLEN);//update tail; ++ ++ if(pnrframe->u.hdr.rx_data >= pnrframe->u.hdr.rx_tail || type_len<8) ++ { ++ //panic("pnrframe->u.hdr.rx_data >= pnrframe->u.hdr.rx_tail || type_len<8\n"); ++ ++ rtw_free_recvframe(pnrframe, pfree_recv_queue); ++ ++ goto exit; ++ } ++ ++ psnap=(struct ieee80211_snap_hdr *)(ptr); ++ psnap_type=ptr+SNAP_SIZE; ++ if (psnap->dsap==0xaa && psnap->ssap==0xaa && psnap->ctrl==0x03) ++ { ++ if ( _rtw_memcmp(psnap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN)) ++ { ++ bsnaphdr=_TRUE;//wlan_pkt_format = WLAN_PKT_FORMAT_SNAP_RFC1042; ++ } ++ else if (_rtw_memcmp(psnap->oui, SNAP_HDR_APPLETALK_DDP, WLAN_IEEE_OUI_LEN) && ++ _rtw_memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_DDP, 2) ) ++ { ++ bsnaphdr=_TRUE; //wlan_pkt_format = WLAN_PKT_FORMAT_APPLETALK; ++ } ++ else if (_rtw_memcmp( psnap->oui, oui_8021h, WLAN_IEEE_OUI_LEN)) ++ { ++ bsnaphdr=_TRUE; //wlan_pkt_format = WLAN_PKT_FORMAT_SNAP_TUNNEL; ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("drop pkt due to invalid frame format!\n")); ++ ++ //KeBugCheckEx(0x87123333, 0xe0, 0x4c, 0x87, 0xdd); ++ ++ //panic("0x87123333, 0xe0, 0x4c, 0x87, 0xdd\n"); ++ ++ rtw_free_recvframe(pnrframe, pfree_recv_queue); ++ ++ goto exit; ++ } ++ ++ } ++ else ++ { ++ bsnaphdr=_FALSE;//wlan_pkt_format = WLAN_PKT_FORMAT_OTHERS; ++ } ++ ++ ptr += (bsnaphdr?SNAP_SIZE:0); ++ _rtw_memcpy(ð_type, ptr, 2); ++ eth_type= ntohs((unsigned short )eth_type); //pattrib->ether_type ++ ++ mv_len+= 2+(bsnaphdr?SNAP_SIZE:0); ++ ptr += 2;//now move to iphdr; ++ ++ pvlan = NULL; ++ if(eth_type == 0x8100) //vlan ++ { ++ pvlan = (struct _vlan *)ptr; ++ ptr+=4; ++ mv_len+=4; ++ } ++ ++ if(eth_type==0x0800)//ip ++ { ++ struct iphdr* piphdr = (struct iphdr*)ptr; ++ ++ ++ if (piphdr->protocol == 0x06) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("@@@===recv tcp len:%d @@@===\n", pnrframe->u.hdr.len)); ++ } ++ } ++#ifdef PLATFORM_OS_XP ++ else ++ { ++ NDIS_PACKET_8021Q_INFO VlanPriInfo; ++ UINT32 UserPriority = pnrframe->u.hdr.attrib.priority; ++ UINT32 VlanID = (pvlan!=NULL ? get_vlan_id(pvlan) : 0 ); ++ ++ VlanPriInfo.Value = // Get current value. ++ NDIS_PER_PACKET_INFO_FROM_PACKET(pnrframe->u.hdr.pkt, Ieee8021QInfo); ++ ++ VlanPriInfo.TagHeader.UserPriority = UserPriority; ++ VlanPriInfo.TagHeader.VlanId = VlanID; ++ ++ VlanPriInfo.TagHeader.CanonicalFormatId = 0; // Should be zero. ++ VlanPriInfo.TagHeader.Reserved = 0; // Should be zero. ++ NDIS_PER_PACKET_INFO_FROM_PACKET(pnrframe->u.hdr.pkt, Ieee8021QInfo) = VlanPriInfo.Value; ++ ++ } ++#endif //PLATFORM_OS_XP ++ ++ pbuf = recvframe_pull(pnrframe, (mv_len-sizeof(struct ethhdr))); ++ ++ _rtw_memcpy(pbuf, pnrframe->u.hdr.attrib.dst, ETH_ALEN); ++ _rtw_memcpy(pbuf+ETH_ALEN, pnrframe->u.hdr.attrib.src, ETH_ALEN); ++ ++ eth_type = htons((unsigned short)eth_type) ; ++ _rtw_memcpy(pbuf+12, ð_type, 2); ++ ++ padding_len = (4) - ((type_len + ETH_HLEN)&(4-1)); ++ ++ a_len -= (type_len + ETH_HLEN + padding_len) ; ++ ++ ++#if 0 ++ ++ if(a_len > ETH_HLEN) ++ { ++ pnrframe_new = rtw_alloc_recvframe(pfree_recv_queue); ++ if(pnrframe_new) ++ { ++ _pkt *pskb_copy; ++ unsigned int copy_len = pnrframe->u.hdr.len; ++ ++ _rtw_init_listhead(&pnrframe_new->u.hdr.list); ++ ++ pskb_copy = rtw_skb_alloc(copy_len+64); ++ ++ if(pskb_copy==NULL) ++ { ++ DBG_871X("amsdu_to_msdu:can not all(ocate memory for skb copy\n"); ++ } ++ ++ pnrframe_new->u.hdr.pkt = pskb_copy; ++ ++ _rtw_memcpy(pskb_copy->data, pnrframe->u.hdr.rx_data, copy_len); ++ ++ pnrframe_new->u.hdr.rx_data = pnrframe->u.hdr.rx_data; ++ pnrframe_new->u.hdr.rx_tail = pnrframe->u.hdr.rx_data + copy_len; ++ ++ ++ if ((padapter->bDriverStopped ==_FALSE)&&( padapter->bSurpriseRemoved==_FALSE)) ++ { ++ rtw_recv_indicatepkt(padapter, pnrframe_new);//indicate this recv_frame ++ } ++ else ++ { ++ rtw_free_recvframe(pnrframe_new, pfree_recv_queue);//free this recv_frame ++ } ++ ++ } ++ else ++ { ++ DBG_871X("amsdu_to_msdu:can not allocate memory for pnrframe_new\n"); ++ } ++ ++ } ++ else ++ { ++ if ((padapter->bDriverStopped ==_FALSE)&&( padapter->bSurpriseRemoved==_FALSE)) ++ { ++ rtw_recv_indicatepkt(padapter, pnrframe);//indicate this recv_frame ++ } ++ else ++ { ++ rtw_free_recvframe(pnrframe, pfree_recv_queue);//free this recv_frame ++ } ++ ++ pnrframe = NULL; ++ ++ } ++ ++#else // 0 ++ ++ //padding_len = (4) - ((type_len + ETH_HLEN)&(4-1)); ++ ++ //a_len -= (type_len + ETH_HLEN + padding_len) ; ++ ++ pnrframe_new = NULL; ++ ++ ++ if(a_len > ETH_HLEN) ++ { ++ pnrframe_new = rtw_alloc_recvframe(pfree_recv_queue); ++ ++ if(pnrframe_new) ++ { ++ ++ ++ //pnrframe_new->u.hdr.precvbuf = precvbuf;//precvbuf is assigned before call rtw_init_recvframe() ++ //rtw_init_recvframe(pnrframe_new, precvpriv); ++ { ++#ifdef PLATFORM_LINUX ++ _pkt *pskb = pnrframe->u.hdr.pkt; ++#endif //PLATFORM_LINUX ++ _rtw_init_listhead(&pnrframe_new->u.hdr.list); ++ ++ pnrframe_new->u.hdr.len=0; ++ ++#ifdef PLATFORM_LINUX ++ if(pskb) ++ { ++ pnrframe_new->u.hdr.pkt = rtw_skb_clone(pskb); ++ } ++#endif //PLATFORM_LINUX ++ ++ } ++ ++ pdata += (type_len + ETH_HLEN + padding_len); ++ pnrframe_new->u.hdr.rx_head = pnrframe_new->u.hdr.rx_data = pnrframe_new->u.hdr.rx_tail = pdata; ++ pnrframe_new->u.hdr.rx_end = pdata + a_len + padding_len;// ++ ++#ifdef PLATFORM_WINDOWS ++ pnrframe_new->u.hdr.precvbuf=precvbuf; ++ _enter_critical_bh(&precvbuf->recvbuf_lock, &irql); ++ precvbuf->ref_cnt++; ++ _exit_critical_bh(&precvbuf->recvbuf_lock, &irql); ++#endif //PLATFORM_WINDOWS ++ ++ } ++ else ++ { ++ //panic("pnrframe_new=%x\n", pnrframe_new); ++ } ++ } ++ ++ ++ if ((padapter->bDriverStopped ==_FALSE)&&( padapter->bSurpriseRemoved==_FALSE) ) ++ { ++ rtw_recv_indicatepkt(padapter, pnrframe);//indicate this recv_frame ++ } ++ else ++ { ++ rtw_free_recvframe(pnrframe, pfree_recv_queue);//free this recv_frame ++ } ++ ++ ++ pnrframe = NULL; ++ if(pnrframe_new) ++ { ++ pnrframe = pnrframe_new; ++ } ++ ++ ++#endif // end defined (PLATFORM_LINUX) || defined (PLATFORM_FREEBSD) ++ ++ }while(pnrframe); ++ ++exit: ++ ++ return ret; ++#endif ++} ++ ++int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num); ++int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num) ++{ ++ u8 wsize = preorder_ctrl->wsize_b; ++ u16 wend = (preorder_ctrl->indicate_seq + wsize -1) & 0xFFF;//% 4096; ++ ++ // Rx Reorder initialize condition. ++ if (preorder_ctrl->indicate_seq == 0xFFFF) ++ { ++ preorder_ctrl->indicate_seq = seq_num; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d init IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, ++ preorder_ctrl->indicate_seq, seq_num); ++ #endif ++ ++ //DbgPrint("check_indicate_seq, 1st->indicate_seq=%d\n", precvpriv->indicate_seq); ++ } ++ ++ //DbgPrint("enter->check_indicate_seq(): IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); ++ ++ // Drop out the packet which SeqNum is smaller than WinStart ++ if( SN_LESS(seq_num, preorder_ctrl->indicate_seq) ) ++ { ++ //RT_TRACE(COMP_RX_REORDER, DBG_LOUD, ("CheckRxTsIndicateSeq(): Packet Drop! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, NewSeqNum)); ++ //DbgPrint("CheckRxTsIndicateSeq(): Packet Drop! IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); ++ ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("%s IndicateSeq: %d > NewSeq: %d\n", __FUNCTION__, ++ preorder_ctrl->indicate_seq, seq_num); ++ #endif ++ ++ ++ return _FALSE; ++ } ++ ++ // ++ // Sliding window manipulation. Conditions includes: ++ // 1. Incoming SeqNum is equal to WinStart =>Window shift 1 ++ // 2. Incoming SeqNum is larger than the WinEnd => Window shift N ++ // ++ if( SN_EQUAL(seq_num, preorder_ctrl->indicate_seq) ) ++ { ++ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d SN_EQUAL IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, ++ preorder_ctrl->indicate_seq, seq_num); ++ #endif ++ } ++ else if(SN_LESS(wend, seq_num)) ++ { ++ //RT_TRACE(COMP_RX_REORDER, DBG_LOUD, ("CheckRxTsIndicateSeq(): Window Shift! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, NewSeqNum)); ++ //DbgPrint("CheckRxTsIndicateSeq(): Window Shift! IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); ++ ++ // boundary situation, when seq_num cross 0xFFF ++ if(seq_num >= (wsize - 1)) ++ preorder_ctrl->indicate_seq = seq_num + 1 -wsize; ++ else ++ preorder_ctrl->indicate_seq = 0xFFF - (wsize - (seq_num + 1)) + 1; ++ ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d SN_LESS(wend, seq_num) IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, ++ preorder_ctrl->indicate_seq, seq_num); ++ #endif ++ } ++ ++ //DbgPrint("exit->check_indicate_seq(): IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); ++ ++ return _TRUE; ++} ++ ++int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union recv_frame *prframe); ++int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union recv_frame *prframe) ++{ ++ struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; ++ _queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; ++ _list *phead, *plist; ++ union recv_frame *pnextrframe; ++ struct rx_pkt_attrib *pnextattrib; ++ ++ //DbgPrint("+enqueue_reorder_recvframe()\n"); ++ ++ //_enter_critical_ex(&ppending_recvframe_queue->lock, &irql); ++ //_rtw_spinlock_ex(&ppending_recvframe_queue->lock); ++ ++ ++ phead = get_list_head(ppending_recvframe_queue); ++ plist = get_next(phead); ++ ++ while(rtw_end_of_queue_search(phead, plist) == _FALSE) ++ { ++ pnextrframe = LIST_CONTAINOR(plist, union recv_frame, u); ++ pnextattrib = &pnextrframe->u.hdr.attrib; ++ ++ if(SN_LESS(pnextattrib->seq_num, pattrib->seq_num)) ++ { ++ plist = get_next(plist); ++ } ++ else if( SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num)) ++ { ++ //Duplicate entry is found!! Do not insert current entry. ++ //RT_TRACE(COMP_RX_REORDER, DBG_TRACE, ("InsertRxReorderList(): Duplicate packet is dropped!! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, SeqNum)); ++ ++ //_exit_critical_ex(&ppending_recvframe_queue->lock, &irql); ++ ++ return _FALSE; ++ } ++ else ++ { ++ break; ++ } ++ ++ //DbgPrint("enqueue_reorder_recvframe():while\n"); ++ ++ } ++ ++ ++ //_enter_critical_ex(&ppending_recvframe_queue->lock, &irql); ++ //_rtw_spinlock_ex(&ppending_recvframe_queue->lock); ++ ++ rtw_list_delete(&(prframe->u.hdr.list)); ++ ++ rtw_list_insert_tail(&(prframe->u.hdr.list), plist); ++ ++ //_rtw_spinunlock_ex(&ppending_recvframe_queue->lock); ++ //_exit_critical_ex(&ppending_recvframe_queue->lock, &irql); ++ ++ ++ //RT_TRACE(COMP_RX_REORDER, DBG_TRACE, ("InsertRxReorderList(): Pkt insert into buffer!! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, SeqNum)); ++ return _TRUE; ++ ++} ++ ++int recv_indicatepkts_in_order(_adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced); ++int recv_indicatepkts_in_order(_adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced) ++{ ++ //_irqL irql; ++ //u8 bcancelled; ++ _list *phead, *plist; ++ union recv_frame *prframe; ++ struct rx_pkt_attrib *pattrib; ++ //u8 index = 0; ++ int bPktInBuf = _FALSE; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ _queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; ++ ++ //DbgPrint("+recv_indicatepkts_in_order\n"); ++ ++ //_enter_critical_ex(&ppending_recvframe_queue->lock, &irql); ++ //_rtw_spinlock_ex(&ppending_recvframe_queue->lock); ++ ++ phead = get_list_head(ppending_recvframe_queue); ++ plist = get_next(phead); ++ ++#if 0 ++ // Check if there is any other indication thread running. ++ if(pTS->RxIndicateState == RXTS_INDICATE_PROCESSING) ++ return; ++#endif ++ ++ // Handling some condition for forced indicate case. ++ if(bforced==_TRUE) ++ { ++ if(rtw_is_list_empty(phead)) ++ { ++ // _exit_critical_ex(&ppending_recvframe_queue->lock, &irql); ++ //_rtw_spinunlock_ex(&ppending_recvframe_queue->lock); ++ return _TRUE; ++ } ++ ++ prframe = LIST_CONTAINOR(plist, union recv_frame, u); ++ pattrib = &prframe->u.hdr.attrib; ++ preorder_ctrl->indicate_seq = pattrib->seq_num; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, ++ preorder_ctrl->indicate_seq, pattrib->seq_num); ++ #endif ++ } ++ ++ // Prepare indication list and indication. ++ // Check if there is any packet need indicate. ++ while(!rtw_is_list_empty(phead)) ++ { ++ ++ prframe = LIST_CONTAINOR(plist, union recv_frame, u); ++ pattrib = &prframe->u.hdr.attrib; ++ ++ if(!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ++ ("recv_indicatepkts_in_order: indicate=%d seq=%d amsdu=%d\n", ++ preorder_ctrl->indicate_seq, pattrib->seq_num, pattrib->amsdu)); ++ ++#if 0 ++ // This protect buffer from overflow. ++ if(index >= REORDER_WIN_SIZE) ++ { ++ RT_ASSERT(FALSE, ("IndicateRxReorderList(): Buffer overflow!! \n")); ++ bPktInBuf = TRUE; ++ break; ++ } ++#endif ++ ++ plist = get_next(plist); ++ rtw_list_delete(&(prframe->u.hdr.list)); ++ ++ if(SN_EQUAL(preorder_ctrl->indicate_seq, pattrib->seq_num)) ++ { ++ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, ++ preorder_ctrl->indicate_seq, pattrib->seq_num); ++ #endif ++ } ++ ++#if 0 ++ index++; ++ if(index==1) ++ { ++ //Cancel previous pending timer. ++ //PlatformCancelTimer(Adapter, &pTS->RxPktPendingTimer); ++ if(bforced!=_TRUE) ++ { ++ //DBG_871X("_cancel_timer(&preorder_ctrl->reordering_ctrl_timer, &bcancelled);\n"); ++ _cancel_timer(&preorder_ctrl->reordering_ctrl_timer, &bcancelled); ++ } ++ } ++#endif ++ ++ //Set this as a lock to make sure that only one thread is indicating packet. ++ //pTS->RxIndicateState = RXTS_INDICATE_PROCESSING; ++ ++ // Indicate packets ++ //RT_ASSERT((index<=REORDER_WIN_SIZE), ("RxReorderIndicatePacket(): Rx Reorder buffer full!! \n")); ++ ++ ++ //indicate this recv_frame ++ //DbgPrint("recv_indicatepkts_in_order, indicate_seq=%d, seq_num=%d\n", precvpriv->indicate_seq, pattrib->seq_num); ++ if(!pattrib->amsdu) ++ { ++ //DBG_871X("recv_indicatepkts_in_order, amsdu!=1, indicate_seq=%d, seq_num=%d\n", preorder_ctrl->indicate_seq, pattrib->seq_num); ++ ++ if ((padapter->bDriverStopped == _FALSE) && ++ (padapter->bSurpriseRemoved == _FALSE)) ++ { ++ ++ rtw_recv_indicatepkt(padapter, prframe);//indicate this recv_frame ++ ++ } ++ } ++ else if(pattrib->amsdu==1) ++ { ++ if(amsdu_to_msdu(padapter, prframe)!=_SUCCESS) ++ { ++ rtw_free_recvframe(prframe, &precvpriv->free_recv_queue); ++ } ++ } ++ else ++ { ++ //error condition; ++ } ++ ++ ++ //Update local variables. ++ bPktInBuf = _FALSE; ++ ++ } ++ else ++ { ++ bPktInBuf = _TRUE; ++ break; ++ } ++ ++ //DbgPrint("recv_indicatepkts_in_order():while\n"); ++ ++ } ++ ++ //_rtw_spinunlock_ex(&ppending_recvframe_queue->lock); ++ //_exit_critical_ex(&ppending_recvframe_queue->lock, &irql); ++ ++/* ++ //Release the indication lock and set to new indication step. ++ if(bPktInBuf) ++ { ++ // Set new pending timer. ++ //pTS->RxIndicateState = RXTS_INDICATE_REORDER; ++ //PlatformSetTimer(Adapter, &pTS->RxPktPendingTimer, pHTInfo->RxReorderPendingTime); ++ //DBG_871X("_set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME)\n"); ++ _set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME); ++ } ++ else ++ { ++ //pTS->RxIndicateState = RXTS_INDICATE_IDLE; ++ } ++*/ ++ //_exit_critical_ex(&ppending_recvframe_queue->lock, &irql); ++ ++ //return _TRUE; ++ return bPktInBuf; ++ ++} ++ ++int recv_indicatepkt_reorder(_adapter *padapter, union recv_frame *prframe); ++int recv_indicatepkt_reorder(_adapter *padapter, union recv_frame *prframe) ++{ ++ _irqL irql; ++ int retval = _SUCCESS; ++ struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; ++ struct recv_reorder_ctrl *preorder_ctrl = prframe->u.hdr.preorder_ctrl; ++ _queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; ++ ++ if(!pattrib->amsdu) ++ { ++ //s1. ++ wlanhdr_to_ethhdr(prframe); ++ ++ //if ((pattrib->qos!=1) /*|| pattrib->priority!=0 || IS_MCAST(pattrib->ra)*/ ++ // || (pattrib->eth_type==0x0806) || (pattrib->ack_policy!=0)) ++ if (pattrib->qos!=1) ++ { ++ if ((padapter->bDriverStopped == _FALSE) && ++ (padapter->bSurpriseRemoved == _FALSE)) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ recv_indicatepkt_reorder -recv_func recv_indicatepkt\n" )); ++ ++ rtw_recv_indicatepkt(padapter, prframe); ++ return _SUCCESS; ++ ++ } ++ ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s pattrib->qos !=1\n", __FUNCTION__); ++ #endif ++ ++ return _FAIL; ++ ++ } ++ ++ if (preorder_ctrl->enable == _FALSE) ++ { ++ //indicate this recv_frame ++ preorder_ctrl->indicate_seq = pattrib->seq_num; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, ++ preorder_ctrl->indicate_seq, pattrib->seq_num); ++ #endif ++ ++ rtw_recv_indicatepkt(padapter, prframe); ++ ++ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1)%4096; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, ++ preorder_ctrl->indicate_seq, pattrib->seq_num); ++ #endif ++ ++ return _SUCCESS; ++ } ++ ++#ifndef CONFIG_RECV_REORDERING_CTRL ++ //indicate this recv_frame ++ rtw_recv_indicatepkt(padapter, prframe); ++ return _SUCCESS; ++#endif ++ ++ } ++ else if(pattrib->amsdu==1) //temp filter -> means didn't support A-MSDUs in a A-MPDU ++ { ++ if (preorder_ctrl->enable == _FALSE) ++ { ++ preorder_ctrl->indicate_seq = pattrib->seq_num; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, ++ preorder_ctrl->indicate_seq, pattrib->seq_num); ++ #endif ++ ++ retval = amsdu_to_msdu(padapter, prframe); ++ ++ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1)%4096; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, ++ preorder_ctrl->indicate_seq, pattrib->seq_num); ++ #endif ++ ++ if(retval != _SUCCESS){ ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s amsdu_to_msdu fail\n", __FUNCTION__); ++ #endif ++ } ++ ++ return retval; ++ } ++ } ++ else ++ { ++ ++ } ++ ++ _enter_critical_bh(&ppending_recvframe_queue->lock, &irql); ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ++ ("recv_indicatepkt_reorder: indicate=%d seq=%d\n", ++ preorder_ctrl->indicate_seq, pattrib->seq_num)); ++ ++ //s2. check if winstart_b(indicate_seq) needs to been updated ++ if(!check_indicate_seq(preorder_ctrl, pattrib->seq_num)) ++ { ++ //pHTInfo->RxReorderDropCounter++; ++ //ReturnRFDList(Adapter, pRfd); ++ //RT_TRACE(COMP_RX_REORDER, DBG_TRACE, ("RxReorderIndicatePacket() ==> Packet Drop!!\n")); ++ //_exit_critical_ex(&ppending_recvframe_queue->lock, &irql); ++ //return _FAIL; ++ ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s check_indicate_seq fail\n", __FUNCTION__); ++ #endif ++#if 0 ++ rtw_recv_indicatepkt(padapter, prframe); ++ ++ _exit_critical_bh(&ppending_recvframe_queue->lock, &irql); ++ ++ goto _success_exit; ++#else ++ goto _err_exit; ++#endif ++ } ++ ++ ++ //s3. Insert all packet into Reorder Queue to maintain its ordering. ++ if(!enqueue_reorder_recvframe(preorder_ctrl, prframe)) ++ { ++ //DbgPrint("recv_indicatepkt_reorder, enqueue_reorder_recvframe fail!\n"); ++ //_exit_critical_ex(&ppending_recvframe_queue->lock, &irql); ++ //return _FAIL; ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s enqueue_reorder_recvframe fail\n", __FUNCTION__); ++ #endif ++ goto _err_exit; ++ } ++ ++ ++ //s4. ++ // Indication process. ++ // After Packet dropping and Sliding Window shifting as above, we can now just indicate the packets ++ // with the SeqNum smaller than latest WinStart and buffer other packets. ++ // ++ // For Rx Reorder condition: ++ // 1. All packets with SeqNum smaller than WinStart => Indicate ++ // 2. All packets with SeqNum larger than or equal to WinStart => Buffer it. ++ // ++ ++ //recv_indicatepkts_in_order(padapter, preorder_ctrl, _TRUE); ++ if(recv_indicatepkts_in_order(padapter, preorder_ctrl, _FALSE)==_TRUE) ++ { ++ _set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME); ++ _exit_critical_bh(&ppending_recvframe_queue->lock, &irql); ++ } ++ else ++ { ++ _exit_critical_bh(&ppending_recvframe_queue->lock, &irql); ++ _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer); ++ } ++ ++ ++_success_exit: ++ ++ return _SUCCESS; ++ ++_err_exit: ++ ++ _exit_critical_bh(&ppending_recvframe_queue->lock, &irql); ++ ++ return _FAIL; ++} ++ ++ ++void rtw_reordering_ctrl_timeout_handler(void *pcontext) ++{ ++ _irqL irql; ++ struct recv_reorder_ctrl *preorder_ctrl = (struct recv_reorder_ctrl *)pcontext; ++ _adapter *padapter = preorder_ctrl->padapter; ++ _queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; ++ ++ ++ if(padapter->bDriverStopped ||padapter->bSurpriseRemoved) ++ { ++ return; ++ } ++ ++ //DBG_871X("+rtw_reordering_ctrl_timeout_handler()=>\n"); ++ ++ _enter_critical_bh(&ppending_recvframe_queue->lock, &irql); ++ ++ if(recv_indicatepkts_in_order(padapter, preorder_ctrl, _TRUE)==_TRUE) ++ { ++ _set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME); ++ } ++ ++ _exit_critical_bh(&ppending_recvframe_queue->lock, &irql); ++ ++} ++ ++int process_recv_indicatepkts(_adapter *padapter, union recv_frame *prframe); ++int process_recv_indicatepkts(_adapter *padapter, union recv_frame *prframe) ++{ ++ int retval = _SUCCESS; ++ //struct recv_priv *precvpriv = &padapter->recvpriv; ++ //struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++#ifdef CONFIG_TDLS ++ struct sta_info *psta = prframe->u.hdr.psta; ++#endif //CONFIG_TDLS ++ ++#ifdef CONFIG_80211N_HT ++ ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ ++#ifdef CONFIG_TDLS ++ if( (phtpriv->ht_option==_TRUE) || ++ ((psta->tdls_sta_state & TDLS_LINKED_STATE) && ++ (psta->htpriv.ht_option==_TRUE) && ++ (psta->htpriv.ampdu_enable==_TRUE))) //B/G/N Mode ++#else ++ if(phtpriv->ht_option==_TRUE) //B/G/N Mode ++#endif //CONFIG_TDLS ++ { ++ //prframe->u.hdr.preorder_ctrl = &precvpriv->recvreorder_ctrl[pattrib->priority]; ++ ++ if(recv_indicatepkt_reorder(padapter, prframe)!=_SUCCESS)// including perform A-MPDU Rx Ordering Buffer Control ++ { ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s recv_indicatepkt_reorder error!\n", __FUNCTION__); ++ #endif ++ ++ if ((padapter->bDriverStopped == _FALSE) && ++ (padapter->bSurpriseRemoved == _FALSE)) ++ { ++ retval = _FAIL; ++ return retval; ++ } ++ } ++ } ++ else //B/G mode ++#endif ++ { ++ retval=wlanhdr_to_ethhdr (prframe); ++ if(retval != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("wlanhdr_to_ethhdr: drop pkt \n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s wlanhdr_to_ethhdr error!\n", __FUNCTION__); ++ #endif ++ return retval; ++ } ++ ++ if ((padapter->bDriverStopped ==_FALSE)&&( padapter->bSurpriseRemoved==_FALSE)) ++ { ++ //indicate this recv_frame ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func recv_indicatepkt\n" )); ++ rtw_recv_indicatepkt(padapter, prframe); ++ ++ ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func free_indicatepkt\n" )); ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_func:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); ++ retval = _FAIL; ++ return retval; ++ } ++ ++ } ++ ++ return retval; ++ ++} ++ ++int recv_func_prehandle(_adapter *padapter, union recv_frame *rframe) ++{ ++ int ret = _SUCCESS; ++ struct rx_pkt_attrib *pattrib = &rframe->u.hdr.attrib; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ _queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; ++ ++ ++#ifdef CONFIG_MP_INCLUDED ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++#endif //CONFIG_MP_INCLUDED ++ ++#ifdef CONFIG_MP_INCLUDED ++ if (padapter->registrypriv.mp_mode == 1) ++ { ++ if (pattrib->crc_err == 1) ++ { ++ padapter->mppriv.rx_crcerrpktcount++; ++ } ++ else ++ { ++ padapter->mppriv.rx_pktcount++; ++ } ++ if (check_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE) == _FALSE) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_alert_, ("MP - Not in loopback mode , drop pkt \n")); ++ ret = _FAIL; ++ rtw_free_recvframe(rframe, pfree_recv_queue);//free this recv_frame ++ goto exit; ++ } ++ } ++#endif ++ ++ //check the frame crtl field and decache ++ ret = validate_recv_frame(padapter, rframe); ++ if (ret != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("recv_func: validate_recv_frame fail! drop pkt\n")); ++ rtw_free_recvframe(rframe, pfree_recv_queue);//free this recv_frame ++ goto exit; ++ } ++ ++exit: ++ return ret; ++} ++ ++int recv_func_posthandle(_adapter *padapter, union recv_frame *prframe) ++{ ++ int ret = _SUCCESS; ++ union recv_frame *orig_prframe = prframe; ++ struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ _queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; ++ ++ ++#ifdef CONFIG_TDLS ++ u8 *psnap_type, *pcategory; ++ struct sta_info *ptdls_sta = NULL; ++#endif //CONFIG_TDLS ++ ++ ++ // DATA FRAME ++ rtw_led_control(padapter, LED_CTL_RX); ++ ++ prframe = decryptor(padapter, prframe); ++ if (prframe == NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("decryptor: drop pkt\n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s decryptor: drop pkt\n", __FUNCTION__); ++ #endif ++ ret = _FAIL; ++ goto _recv_data_drop; ++ } ++ ++#if 0 ++ if ( padapter->adapter_type == PRIMARY_ADAPTER ) ++ { ++ DBG_871X("+++\n"); ++ { ++ int i; ++ u8 *ptr = get_recvframe_data(prframe); ++ for(i=0; i<140;i=i+8) ++ DBG_871X("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:", *(ptr+i), ++ *(ptr+i+1), *(ptr+i+2) ,*(ptr+i+3) ,*(ptr+i+4),*(ptr+i+5), *(ptr+i+6), *(ptr+i+7)); ++ ++ } ++ DBG_871X("---\n"); ++ } ++#endif ++ ++#ifdef CONFIG_TDLS ++ //check TDLS frame ++ psnap_type = get_recvframe_data(orig_prframe); ++ psnap_type+=pattrib->hdrlen + pattrib->iv_len+SNAP_SIZE; ++ pcategory = psnap_type + ETH_TYPE_LEN + PAYLOAD_TYPE_LEN; ++ ++ if((_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_TDLS, ETH_TYPE_LEN)) && ++ ((*pcategory==RTW_WLAN_CATEGORY_TDLS) || (*pcategory==RTW_WLAN_CATEGORY_P2P))){ ++ ret = OnTDLS(padapter, prframe); //all of functions will return _FAIL ++ goto _exit_recv_func; ++ } ++#endif //CONFIG_TDLS ++ ++ prframe = recvframe_chk_defrag(padapter, prframe); ++ if(prframe==NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("recvframe_chk_defrag: drop pkt\n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s recvframe_chk_defrag: drop pkt\n", __FUNCTION__); ++ #endif ++ goto _recv_data_drop; ++ } ++ ++ prframe=portctrl(padapter, prframe); ++ if (prframe == NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("portctrl: drop pkt \n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s portctrl: drop pkt\n", __FUNCTION__); ++ #endif ++ ret = _FAIL; ++ goto _recv_data_drop; ++ } ++ ++#ifdef CONFIG_TDLS ++ if(padapter->tdlsinfo.setup_state == TDLS_LINKED_STATE) ++ ptdls_sta = rtw_get_stainfo(&padapter->stapriv, pattrib->src); ++ count_rx_stats(padapter, prframe, ptdls_sta); ++#else ++ count_rx_stats(padapter, prframe, NULL); ++#endif //CONFIG_TDLS ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ rtw_wapi_update_info(padapter, prframe); ++#endif ++ ++#ifdef CONFIG_80211N_HT ++ ret = process_recv_indicatepkts(padapter, prframe); ++ if (ret != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("recv_func: process_recv_indicatepkts fail! \n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s process_recv_indicatepkts fail!\n", __FUNCTION__); ++ #endif ++ rtw_free_recvframe(orig_prframe, pfree_recv_queue);//free this recv_frame ++ goto _recv_data_drop; ++ } ++#else // CONFIG_80211N_HT ++ if (!pattrib->amsdu) ++ { ++ ret = wlanhdr_to_ethhdr (prframe); ++ if (ret != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("wlanhdr_to_ethhdr: drop pkt \n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s wlanhdr_to_ethhdr: drop pkt\n", __FUNCTION__); ++ #endif ++ rtw_free_recvframe(orig_prframe, pfree_recv_queue);//free this recv_frame ++ goto _recv_data_drop; ++ } ++ ++ if ((padapter->bDriverStopped == _FALSE) && (padapter->bSurpriseRemoved == _FALSE)) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_alert_, ("@@@@ recv_func: recv_func rtw_recv_indicatepkt\n" )); ++ //indicate this recv_frame ++ ret = rtw_recv_indicatepkt(padapter, prframe); ++ if (ret != _SUCCESS) ++ { ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s rtw_recv_indicatepkt fail!\n", __FUNCTION__); ++ #endif ++ goto _recv_data_drop; ++ } ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_alert_, ("@@@@ recv_func: rtw_free_recvframe\n" )); ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_debug_, ("recv_func:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s ecv_func:bDriverStopped(%d) OR bSurpriseRemoved(%d)\n", __FUNCTION__, ++ padapter->bDriverStopped, padapter->bSurpriseRemoved); ++ #endif ++ ret = _FAIL; ++ rtw_free_recvframe(orig_prframe, pfree_recv_queue); //free this recv_frame ++ } ++ ++ } ++ else if(pattrib->amsdu==1) ++ { ++ ++ ret = amsdu_to_msdu(padapter, prframe); ++ if(ret != _SUCCESS) ++ { ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s amsdu_to_msdu fail\n", __FUNCTION__); ++ #endif ++ rtw_free_recvframe(orig_prframe, pfree_recv_queue); ++ goto _recv_data_drop; ++ } ++ } ++ else ++ { ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s what is this condition??\n", __FUNCTION__); ++ #endif ++ goto _recv_data_drop; ++ } ++#endif // CONFIG_80211N_HT ++ ++_exit_recv_func: ++ return ret; ++ ++_recv_data_drop: ++ precvpriv->rx_drop++; ++ return ret; ++} ++ ++ ++int recv_func(_adapter *padapter, union recv_frame *rframe); ++int recv_func(_adapter *padapter, union recv_frame *rframe) ++{ ++ int ret; ++ struct rx_pkt_attrib *prxattrib = &rframe->u.hdr.attrib; ++ struct recv_priv *recvpriv = &padapter->recvpriv; ++ struct security_priv *psecuritypriv=&padapter->securitypriv; ++ struct mlme_priv *mlmepriv = &padapter->mlmepriv; ++ ++ /* check if need to handle uc_swdec_pending_queue*/ ++ if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && psecuritypriv->busetkipkey) ++ { ++ union recv_frame *pending_frame; ++ int cnt = 0; ++ ++ while((pending_frame=rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue))) { ++ cnt++; ++ recv_func_posthandle(padapter, pending_frame); ++ } ++ ++ if (cnt) ++ DBG_871X(FUNC_ADPT_FMT" dequeue %d from uc_swdec_pending_queue\n", ++ FUNC_ADPT_ARG(padapter), cnt); ++ } ++ ++ ret = recv_func_prehandle(padapter, rframe); ++ ++ if(ret == _SUCCESS) { ++ ++ /* check if need to enqueue into uc_swdec_pending_queue*/ ++ if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && ++ !IS_MCAST(prxattrib->ra) && prxattrib->encrypt>0 && ++ (prxattrib->bdecrypted == 0 ||psecuritypriv->sw_decrypt == _TRUE) && ++ psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPAPSK && ++ !psecuritypriv->busetkipkey) ++ { ++ rtw_enqueue_recvframe(rframe, &padapter->recvpriv.uc_swdec_pending_queue); ++ //DBG_871X("%s: no key, enqueue uc_swdec_pending_queue\n", __func__); ++ ++ if (recvpriv->free_recvframe_cnt < NR_RECVFRAME/4) { ++ /* to prevent from recvframe starvation, get recvframe from uc_swdec_pending_queue to free_recvframe_cnt */ ++ rframe = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue); ++ if (rframe) ++ goto do_posthandle; ++ } ++ goto exit; ++ } ++ ++do_posthandle: ++ ret = recv_func_posthandle(padapter, rframe); ++ } ++ ++exit: ++ return ret; ++} ++ ++ ++s32 rtw_recv_entry(union recv_frame *precvframe) ++{ ++ _adapter *padapter; ++ struct recv_priv *precvpriv; ++ s32 ret=_SUCCESS; ++ ++_func_enter_; ++ ++// RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("+rtw_recv_entry\n")); ++ ++ padapter = precvframe->u.hdr.adapter; ++ ++ precvpriv = &padapter->recvpriv; ++ ++ ++ if ((ret = recv_func(padapter, precvframe)) == _FAIL) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("rtw_recv_entry: recv_func return fail!!!\n")); ++ goto _recv_entry_drop; ++ } ++ ++ ++ precvpriv->rx_pkts++; ++ ++_func_exit_; ++ ++ return ret; ++ ++_recv_entry_drop: ++ ++#ifdef CONFIG_MP_INCLUDED ++ if (padapter->registrypriv.mp_mode == 1) ++ padapter->mppriv.rx_pktloss = precvpriv->rx_drop; ++#endif ++ ++ //RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("_recv_entry_drop\n")); ++ ++_func_exit_; ++ ++ return ret; ++} ++ ++#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS ++void rtw_signal_stat_timer_hdl(RTW_TIMER_HDL_ARGS){ ++ _adapter *adapter = (_adapter *)FunctionContext; ++ struct recv_priv *recvpriv = &adapter->recvpriv; ++ ++ u32 tmp_s, tmp_q; ++ u8 avg_signal_strength = 0; ++ u8 avg_signal_qual = 0; ++ u32 num_signal_strength = 0; ++ u32 num_signal_qual = 0; ++ u8 _alpha = 3; // this value is based on converging_constant = 5000 and sampling_interval = 1000 ++ ++ if(adapter->recvpriv.is_signal_dbg) { ++ //update the user specific value, signal_strength_dbg, to signal_strength, rssi ++ adapter->recvpriv.signal_strength= adapter->recvpriv.signal_strength_dbg; ++ adapter->recvpriv.rssi=(s8)translate_percentage_to_dbm((u8)adapter->recvpriv.signal_strength_dbg); ++ } else { ++ ++ if(recvpriv->signal_strength_data.update_req == 0) {// update_req is clear, means we got rx ++ avg_signal_strength = recvpriv->signal_strength_data.avg_val; ++ num_signal_strength = recvpriv->signal_strength_data.total_num; ++ // after avg_vals are accquired, we can re-stat the signal values ++ recvpriv->signal_strength_data.update_req = 1; ++ } ++ ++ if(recvpriv->signal_qual_data.update_req == 0) {// update_req is clear, means we got rx ++ avg_signal_qual = recvpriv->signal_qual_data.avg_val; ++ num_signal_qual = recvpriv->signal_qual_data.total_num; ++ // after avg_vals are accquired, we can re-stat the signal values ++ recvpriv->signal_qual_data.update_req = 1; ++ } ++ ++ if (num_signal_strength == 0) { ++ if (rtw_get_on_cur_ch_time(adapter) == 0 ++ || rtw_get_passing_time_ms(rtw_get_on_cur_ch_time(adapter)) < 2 * adapter->mlmeextpriv.mlmext_info.bcn_interval ++#ifdef CONFIG_BT_COEXIST ++ || ((BTDM_IsBtDisabled(adapter) == _FALSE) && (BT_IsBtInquiryPage(adapter) == _TRUE)) ++#endif ++ ) { ++ goto set_timer; ++ } ++ } ++ ++ if(check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY) == _TRUE ++ || check_fwstate(&adapter->mlmepriv, _FW_LINKED) == _FALSE ++ ) { ++ goto set_timer; ++ } ++ ++ #ifdef CONFIG_CONCURRENT_MODE ++ if (check_buddy_fwstate(adapter, _FW_UNDER_SURVEY) == _TRUE) ++ goto set_timer; ++ #endif ++ ++ //update value of signal_strength, rssi, signal_qual ++ tmp_s = (avg_signal_strength+(_alpha-1)*recvpriv->signal_strength); ++ if(tmp_s %_alpha) ++ tmp_s = tmp_s/_alpha + 1; ++ else ++ tmp_s = tmp_s/_alpha; ++ if(tmp_s>100) ++ tmp_s = 100; ++ ++ tmp_q = (avg_signal_qual+(_alpha-1)*recvpriv->signal_qual); ++ if(tmp_q %_alpha) ++ tmp_q = tmp_q/_alpha + 1; ++ else ++ tmp_q = tmp_q/_alpha; ++ if(tmp_q>100) ++ tmp_q = 100; ++ ++ recvpriv->signal_strength = tmp_s; ++ recvpriv->rssi = (s8)translate_percentage_to_dbm(tmp_s); ++ recvpriv->signal_qual = tmp_q; ++ ++ #if defined(DBG_RX_SIGNAL_DISPLAY_PROCESSING) && 1 ++ DBG_871X(FUNC_ADPT_FMT" signal_strength:%3u, rssi:%3d, signal_qual:%3u" ++ ", num_signal_strength:%u, num_signal_qual:%u" ++ ", on_cur_ch_ms:%d" ++ "\n" ++ , FUNC_ADPT_ARG(adapter) ++ , recvpriv->signal_strength ++ , recvpriv->rssi ++ , recvpriv->signal_qual ++ , num_signal_strength, num_signal_qual ++ , rtw_get_on_cur_ch_time(adapter) ? rtw_get_passing_time_ms(rtw_get_on_cur_ch_time(adapter)) : 0 ++ ); ++ #endif ++ } ++ ++set_timer: ++ rtw_set_signal_stat_timer(recvpriv); ++ ++} ++#endif //CONFIG_NEW_SIGNAL_STAT_PROCESS ++ ++ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_rf.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_rf.c +new file mode 100644 +index 00000000..7ae86351 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_rf.c +@@ -0,0 +1,95 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_RF_C_ ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++struct ch_freq { ++ u32 channel; ++ u32 frequency; ++}; ++ ++struct ch_freq ch_freq_map[] = { ++ {1, 2412},{2, 2417},{3, 2422},{4, 2427},{5, 2432}, ++ {6, 2437},{7, 2442},{8, 2447},{9, 2452},{10, 2457}, ++ {11, 2462},{12, 2467},{13, 2472},{14, 2484}, ++ /* UNII */ ++ {36, 5180},{40, 5200},{44, 5220},{48, 5240},{52, 5260}, ++ {56, 5280},{60, 5300},{64, 5320},{149, 5745},{153, 5765}, ++ {157, 5785},{161, 5805},{165, 5825},{167, 5835},{169, 5845}, ++ {171, 5855},{173, 5865}, ++ /* HiperLAN2 */ ++ {100, 5500},{104, 5520},{108, 5540},{112, 5560},{116, 5580}, ++ {120, 5600},{124, 5620},{128, 5640},{132, 5660},{136, 5680}, ++ {140, 5700}, ++ /* Japan MMAC */ ++ {34, 5170},{38, 5190},{42, 5210},{46, 5230}, ++ /* Japan */ ++ {184, 4920},{188, 4940},{192, 4960},{196, 4980}, ++ {208, 5040},/* Japan, means J08 */ ++ {212, 5060},/* Japan, means J12 */ ++ {216, 5080},/* Japan, means J16 */ ++}; ++ ++int ch_freq_map_num = (sizeof(ch_freq_map) / sizeof(struct ch_freq)); ++ ++u32 rtw_ch2freq(u32 channel) ++{ ++ u8 i; ++ u32 freq = 0; ++ ++ for (i = 0; i < ch_freq_map_num; i++) ++ { ++ if (channel == ch_freq_map[i].channel) ++ { ++ freq = ch_freq_map[i].frequency; ++ break; ++ } ++ } ++ if (i == ch_freq_map_num) ++ freq = 2412; ++ ++ return freq; ++} ++ ++u32 rtw_freq2ch(u32 freq) ++{ ++ u8 i; ++ u32 ch = 0; ++ ++ for (i = 0; i < ch_freq_map_num; i++) ++ { ++ if (freq == ch_freq_map[i].frequency) ++ { ++ ch = ch_freq_map[i].channel; ++ break; ++ } ++ } ++ if (i == ch_freq_map_num) ++ ch = 1; ++ ++ return ch; ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_security.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_security.c +new file mode 100644 +index 00000000..66df244e +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_security.c +@@ -0,0 +1,3159 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_SECURITY_C_ ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++//=====WEP related===== ++ ++#define CRC32_POLY 0x04c11db7 ++ ++struct arc4context ++{ ++ u32 x; ++ u32 y; ++ u8 state[256]; ++}; ++ ++ ++static void arcfour_init(struct arc4context *parc4ctx, u8 * key,u32 key_len) ++{ ++ u32 t, u; ++ u32 keyindex; ++ u32 stateindex; ++ u8 * state; ++ u32 counter; ++_func_enter_; ++ state = parc4ctx->state; ++ parc4ctx->x = 0; ++ parc4ctx->y = 0; ++ for (counter = 0; counter < 256; counter++) ++ state[counter] = (u8)counter; ++ keyindex = 0; ++ stateindex = 0; ++ for (counter = 0; counter < 256; counter++) ++ { ++ t = state[counter]; ++ stateindex = (stateindex + key[keyindex] + t) & 0xff; ++ u = state[stateindex]; ++ state[stateindex] = (u8)t; ++ state[counter] = (u8)u; ++ if (++keyindex >= key_len) ++ keyindex = 0; ++ } ++_func_exit_; ++} ++static u32 arcfour_byte( struct arc4context *parc4ctx) ++{ ++ u32 x; ++ u32 y; ++ u32 sx, sy; ++ u8 * state; ++_func_enter_; ++ state = parc4ctx->state; ++ x = (parc4ctx->x + 1) & 0xff; ++ sx = state[x]; ++ y = (sx + parc4ctx->y) & 0xff; ++ sy = state[y]; ++ parc4ctx->x = x; ++ parc4ctx->y = y; ++ state[y] = (u8)sx; ++ state[x] = (u8)sy; ++_func_exit_; ++ return state[(sx + sy) & 0xff]; ++} ++ ++ ++static void arcfour_encrypt( struct arc4context *parc4ctx, ++ u8 * dest, ++ u8 * src, ++ u32 len) ++{ ++ u32 i; ++_func_enter_; ++ for (i = 0; i < len; i++) ++ dest[i] = src[i] ^ (unsigned char)arcfour_byte(parc4ctx); ++_func_exit_; ++} ++ ++static sint bcrc32initialized = 0; ++static u32 crc32_table[256]; ++ ++ ++static u8 crc32_reverseBit( u8 data) ++{ ++ return( (u8)((data<<7)&0x80) | ((data<<5)&0x40) | ((data<<3)&0x20) | ((data<<1)&0x10) | ((data>>1)&0x08) | ((data>>3)&0x04) | ((data>>5)&0x02) | ((data>>7)&0x01) ); ++} ++ ++static void crc32_init(void) ++{ ++_func_enter_; ++ if (bcrc32initialized == 1) ++ goto exit; ++ else{ ++ sint i, j; ++ u32 c; ++ u8 *p=(u8 *)&c, *p1; ++ u8 k; ++ ++ c = 0x12340000; ++ ++ for (i = 0; i < 256; ++i) ++ { ++ k = crc32_reverseBit((u8)i); ++ for (c = ((u32)k) << 24, j = 8; j > 0; --j){ ++ c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : (c << 1); ++ } ++ p1 = (u8 *)&crc32_table[i]; ++ ++ p1[0] = crc32_reverseBit(p[3]); ++ p1[1] = crc32_reverseBit(p[2]); ++ p1[2] = crc32_reverseBit(p[1]); ++ p1[3] = crc32_reverseBit(p[0]); ++ } ++ bcrc32initialized= 1; ++ } ++exit: ++_func_exit_; ++} ++ ++static u32 getcrc32(u8 *buf, sint len) ++{ ++ u8 *p; ++ u32 crc; ++_func_enter_; ++ if (bcrc32initialized == 0) crc32_init(); ++ ++ crc = 0xffffffff; /* preload shift register, per CRC-32 spec */ ++ ++ for (p = buf; len > 0; ++p, --len) ++ { ++ crc = crc32_table[ (crc ^ *p) & 0xff] ^ (crc >> 8); ++ } ++_func_exit_; ++ return ~crc; /* transmit complement, per CRC-32 spec */ ++} ++ ++ ++/* ++ Need to consider the fragment situation ++*/ ++void rtw_wep_encrypt(_adapter *padapter, u8 *pxmitframe) ++{ // exclude ICV ++ ++ unsigned char crc[4]; ++ struct arc4context mycontext; ++ ++ sint curfragnum,length; ++ u32 keylength; ++ ++ u8 *pframe, *payload,*iv; //,*wepkey ++ u8 wepkey[16]; ++ u8 hw_hdr_offset=0; ++ struct pkt_attrib *pattrib = &((struct xmit_frame*)pxmitframe)->attrib; ++ struct security_priv *psecuritypriv=&padapter->securitypriv; ++ struct xmit_priv *pxmitpriv=&padapter->xmitpriv; ++ ++_func_enter_; ++ ++ ++ if(((struct xmit_frame*)pxmitframe)->buf_addr==NULL) ++ return; ++ ++#ifdef CONFIG_USB_TX_AGGREGATION ++ hw_hdr_offset = TXDESC_SIZE + ++ (((struct xmit_frame*)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ); ++#else ++ #ifdef CONFIG_TX_EARLY_MODE ++ hw_hdr_offset = TXDESC_OFFSET+EARLY_MODE_INFO_SIZE; ++ #else ++ hw_hdr_offset = TXDESC_OFFSET; ++ #endif ++#endif ++ ++ pframe = ((struct xmit_frame*)pxmitframe)->buf_addr + hw_hdr_offset; ++ ++ //start to encrypt each fragment ++ if((pattrib->encrypt==_WEP40_)||(pattrib->encrypt==_WEP104_)) ++ { ++ keylength=psecuritypriv->dot11DefKeylen[psecuritypriv->dot11PrivacyKeyIndex]; ++ ++ for(curfragnum=0;curfragnumnr_frags;curfragnum++) ++ { ++ iv=pframe+pattrib->hdrlen; ++ _rtw_memcpy(&wepkey[0], iv, 3); ++ _rtw_memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[psecuritypriv->dot11PrivacyKeyIndex].skey[0],keylength); ++ payload=pframe+pattrib->iv_len+pattrib->hdrlen; ++ ++ if((curfragnum+1)==pattrib->nr_frags) ++ { //the last fragment ++ ++ length=pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len- pattrib->icv_len; ++ ++ *((u32 *)crc)=cpu_to_le32(getcrc32(payload,length)); ++ ++ arcfour_init(&mycontext, wepkey,3+keylength); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ arcfour_encrypt(&mycontext, payload+length, crc, 4); ++ ++ } ++ else ++ { ++ length=pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len ; ++ *((u32 *)crc)=cpu_to_le32(getcrc32(payload,length)); ++ arcfour_init(&mycontext, wepkey,3+keylength); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ arcfour_encrypt(&mycontext, payload+length, crc, 4); ++ ++ pframe+=pxmitpriv->frag_len; ++ pframe=(u8 *)RND4((SIZE_PTR)(pframe)); ++ ++ } ++ ++ } ++ ++ } ++ ++_func_exit_; ++ ++} ++ ++void rtw_wep_decrypt(_adapter *padapter, u8 *precvframe) ++{ ++ // exclude ICV ++ u8 crc[4]; ++ struct arc4context mycontext; ++ sint length; ++ u32 keylength; ++ u8 *pframe, *payload,*iv,wepkey[16]; ++ u8 keyindex; ++ struct rx_pkt_attrib *prxattrib = &(((union recv_frame*)precvframe)->u.hdr.attrib); ++ struct security_priv *psecuritypriv=&padapter->securitypriv; ++ ++_func_enter_; ++ ++ pframe=(unsigned char *)((union recv_frame*)precvframe)->u.hdr.rx_data; ++ ++ //start to decrypt recvframe ++ if((prxattrib->encrypt==_WEP40_)||(prxattrib->encrypt==_WEP104_)) ++ { ++ iv=pframe+prxattrib->hdrlen; ++ //keyindex=(iv[3]&0x3); ++ keyindex = prxattrib->key_index; ++ keylength=psecuritypriv->dot11DefKeylen[keyindex]; ++ _rtw_memcpy(&wepkey[0], iv, 3); ++ //_rtw_memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[psecuritypriv->dot11PrivacyKeyIndex].skey[0],keylength); ++ _rtw_memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[keyindex].skey[0],keylength); ++ length= ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len; ++ ++ payload=pframe+prxattrib->iv_len+prxattrib->hdrlen; ++ ++ //decrypt payload include icv ++ arcfour_init(&mycontext, wepkey,3+keylength); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ ++ //calculate icv and compare the icv ++ *((u32 *)crc)=le32_to_cpu(getcrc32(payload,length-4)); ++ ++ if(crc[3]!=payload[length-1] || crc[2]!=payload[length-2] || crc[1]!=payload[length-3] || crc[0]!=payload[length-4]) ++ { ++ RT_TRACE(_module_rtl871x_security_c_,_drv_err_,("rtw_wep_decrypt:icv error crc[3](%x)!=payload[length-1](%x) || crc[2](%x)!=payload[length-2](%x) || crc[1](%x)!=payload[length-3](%x) || crc[0](%x)!=payload[length-4](%x)\n", ++ crc[3],payload[length-1],crc[2],payload[length-2],crc[1],payload[length-3],crc[0],payload[length-4])); ++ } ++ ++ } ++ ++_func_exit_; ++ ++ return; ++ ++} ++ ++//3 =====TKIP related===== ++ ++static u32 secmicgetuint32( u8 * p ) ++// Convert from Byte[] to Us4Byte32 in a portable way ++{ ++ s32 i; ++ u32 res = 0; ++_func_enter_; ++ for( i=0; i<4; i++ ) ++ { ++ res |= ((u32)(*p++)) << (8*i); ++ } ++_func_exit_; ++ return res; ++} ++ ++static void secmicputuint32( u8 * p, u32 val ) ++// Convert from Us4Byte32 to Byte[] in a portable way ++{ ++ long i; ++_func_enter_; ++ for( i=0; i<4; i++ ) ++ { ++ *p++ = (u8) (val & 0xff); ++ val >>= 8; ++ } ++_func_exit_; ++} ++ ++static void secmicclear(struct mic_data *pmicdata) ++{ ++// Reset the state to the empty message. ++_func_enter_; ++ pmicdata->L = pmicdata->K0; ++ pmicdata->R = pmicdata->K1; ++ pmicdata->nBytesInM = 0; ++ pmicdata->M = 0; ++_func_exit_; ++} ++ ++void rtw_secmicsetkey(struct mic_data *pmicdata, u8 * key ) ++{ ++ // Set the key ++_func_enter_; ++ pmicdata->K0 = secmicgetuint32( key ); ++ pmicdata->K1 = secmicgetuint32( key + 4 ); ++ // and reset the message ++ secmicclear(pmicdata); ++_func_exit_; ++} ++ ++void rtw_secmicappendbyte(struct mic_data *pmicdata, u8 b ) ++{ ++_func_enter_; ++ // Append the byte to our word-sized buffer ++ pmicdata->M |= ((unsigned long)b) << (8*pmicdata->nBytesInM); ++ pmicdata->nBytesInM++; ++ // Process the word if it is full. ++ if( pmicdata->nBytesInM >= 4 ) ++ { ++ pmicdata->L ^= pmicdata->M; ++ pmicdata->R ^= ROL32( pmicdata->L, 17 ); ++ pmicdata->L += pmicdata->R; ++ pmicdata->R ^= ((pmicdata->L & 0xff00ff00) >> 8) | ((pmicdata->L & 0x00ff00ff) << 8); ++ pmicdata->L += pmicdata->R; ++ pmicdata->R ^= ROL32( pmicdata->L, 3 ); ++ pmicdata->L += pmicdata->R; ++ pmicdata->R ^= ROR32( pmicdata->L, 2 ); ++ pmicdata->L += pmicdata->R; ++ // Clear the buffer ++ pmicdata->M = 0; ++ pmicdata->nBytesInM = 0; ++ } ++_func_exit_; ++} ++ ++void rtw_secmicappend(struct mic_data *pmicdata, u8 * src, u32 nbytes ) ++{ ++_func_enter_; ++ // This is simple ++ while( nbytes > 0 ) ++ { ++ rtw_secmicappendbyte(pmicdata, *src++ ); ++ nbytes--; ++ } ++_func_exit_; ++} ++ ++void rtw_secgetmic(struct mic_data *pmicdata, u8 * dst ) ++{ ++_func_enter_; ++ // Append the minimum padding ++ rtw_secmicappendbyte(pmicdata, 0x5a ); ++ rtw_secmicappendbyte(pmicdata, 0 ); ++ rtw_secmicappendbyte(pmicdata, 0 ); ++ rtw_secmicappendbyte(pmicdata, 0 ); ++ rtw_secmicappendbyte(pmicdata, 0 ); ++ // and then zeroes until the length is a multiple of 4 ++ while( pmicdata->nBytesInM != 0 ) ++ { ++ rtw_secmicappendbyte(pmicdata, 0 ); ++ } ++ // The appendByte function has already computed the result. ++ secmicputuint32( dst, pmicdata->L ); ++ secmicputuint32( dst+4, pmicdata->R ); ++ // Reset to the empty message. ++ secmicclear(pmicdata); ++_func_exit_; ++} ++ ++ ++void rtw_seccalctkipmic(u8 * key,u8 *header,u8 *data,u32 data_len,u8 *mic_code, u8 pri) ++{ ++ ++ struct mic_data micdata; ++ u8 priority[4]={0x0,0x0,0x0,0x0}; ++_func_enter_; ++ rtw_secmicsetkey(&micdata, key); ++ priority[0]=pri; ++ ++ /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */ ++ if(header[1]&1){ //ToDS==1 ++ rtw_secmicappend(&micdata, &header[16], 6); //DA ++ if(header[1]&2) //From Ds==1 ++ rtw_secmicappend(&micdata, &header[24], 6); ++ else ++ rtw_secmicappend(&micdata, &header[10], 6); ++ } ++ else{ //ToDS==0 ++ rtw_secmicappend(&micdata, &header[4], 6); //DA ++ if(header[1]&2) //From Ds==1 ++ rtw_secmicappend(&micdata, &header[16], 6); ++ else ++ rtw_secmicappend(&micdata, &header[10], 6); ++ ++ } ++ rtw_secmicappend(&micdata, &priority[0], 4); ++ ++ ++ rtw_secmicappend(&micdata, data, data_len); ++ ++ rtw_secgetmic(&micdata,mic_code); ++_func_exit_; ++} ++ ++ ++ ++ ++/* macros for extraction/creation of unsigned char/unsigned short values */ ++#define RotR1(v16) ((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15)) ++#define Lo8(v16) ((u8)( (v16) & 0x00FF)) ++#define Hi8(v16) ((u8)(((v16) >> 8) & 0x00FF)) ++#define Lo16(v32) ((u16)( (v32) & 0xFFFF)) ++#define Hi16(v32) ((u16)(((v32) >>16) & 0xFFFF)) ++#define Mk16(hi,lo) ((lo) ^ (((u16)(hi)) << 8)) ++ ++/* select the Nth 16-bit word of the temporal key unsigned char array TK[] */ ++#define TK16(N) Mk16(tk[2*(N)+1],tk[2*(N)]) ++ ++/* S-box lookup: 16 bits --> 16 bits */ ++#define _S_(v16) (Sbox1[0][Lo8(v16)] ^ Sbox1[1][Hi8(v16)]) ++ ++/* fixed algorithm "parameters" */ ++#define PHASE1_LOOP_CNT 8 /* this needs to be "big enough" */ ++#define TA_SIZE 6 /* 48-bit transmitter address */ ++#define TK_SIZE 16 /* 128-bit temporal key */ ++#define P1K_SIZE 10 /* 80-bit Phase1 key */ ++#define RC4_KEY_SIZE 16 /* 128-bit RC4KEY (104 bits unknown) */ ++ ++ ++/* 2-unsigned char by 2-unsigned char subset of the full AES S-box table */ ++static const unsigned short Sbox1[2][256]= /* Sbox for hash (can be in ROM) */ ++{ { ++ 0xC6A5,0xF884,0xEE99,0xF68D,0xFF0D,0xD6BD,0xDEB1,0x9154, ++ 0x6050,0x0203,0xCEA9,0x567D,0xE719,0xB562,0x4DE6,0xEC9A, ++ 0x8F45,0x1F9D,0x8940,0xFA87,0xEF15,0xB2EB,0x8EC9,0xFB0B, ++ 0x41EC,0xB367,0x5FFD,0x45EA,0x23BF,0x53F7,0xE496,0x9B5B, ++ 0x75C2,0xE11C,0x3DAE,0x4C6A,0x6C5A,0x7E41,0xF502,0x834F, ++ 0x685C,0x51F4,0xD134,0xF908,0xE293,0xAB73,0x6253,0x2A3F, ++ 0x080C,0x9552,0x4665,0x9D5E,0x3028,0x37A1,0x0A0F,0x2FB5, ++ 0x0E09,0x2436,0x1B9B,0xDF3D,0xCD26,0x4E69,0x7FCD,0xEA9F, ++ 0x121B,0x1D9E,0x5874,0x342E,0x362D,0xDCB2,0xB4EE,0x5BFB, ++ 0xA4F6,0x764D,0xB761,0x7DCE,0x527B,0xDD3E,0x5E71,0x1397, ++ 0xA6F5,0xB968,0x0000,0xC12C,0x4060,0xE31F,0x79C8,0xB6ED, ++ 0xD4BE,0x8D46,0x67D9,0x724B,0x94DE,0x98D4,0xB0E8,0x854A, ++ 0xBB6B,0xC52A,0x4FE5,0xED16,0x86C5,0x9AD7,0x6655,0x1194, ++ 0x8ACF,0xE910,0x0406,0xFE81,0xA0F0,0x7844,0x25BA,0x4BE3, ++ 0xA2F3,0x5DFE,0x80C0,0x058A,0x3FAD,0x21BC,0x7048,0xF104, ++ 0x63DF,0x77C1,0xAF75,0x4263,0x2030,0xE51A,0xFD0E,0xBF6D, ++ 0x814C,0x1814,0x2635,0xC32F,0xBEE1,0x35A2,0x88CC,0x2E39, ++ 0x9357,0x55F2,0xFC82,0x7A47,0xC8AC,0xBAE7,0x322B,0xE695, ++ 0xC0A0,0x1998,0x9ED1,0xA37F,0x4466,0x547E,0x3BAB,0x0B83, ++ 0x8CCA,0xC729,0x6BD3,0x283C,0xA779,0xBCE2,0x161D,0xAD76, ++ 0xDB3B,0x6456,0x744E,0x141E,0x92DB,0x0C0A,0x486C,0xB8E4, ++ 0x9F5D,0xBD6E,0x43EF,0xC4A6,0x39A8,0x31A4,0xD337,0xF28B, ++ 0xD532,0x8B43,0x6E59,0xDAB7,0x018C,0xB164,0x9CD2,0x49E0, ++ 0xD8B4,0xACFA,0xF307,0xCF25,0xCAAF,0xF48E,0x47E9,0x1018, ++ 0x6FD5,0xF088,0x4A6F,0x5C72,0x3824,0x57F1,0x73C7,0x9751, ++ 0xCB23,0xA17C,0xE89C,0x3E21,0x96DD,0x61DC,0x0D86,0x0F85, ++ 0xE090,0x7C42,0x71C4,0xCCAA,0x90D8,0x0605,0xF701,0x1C12, ++ 0xC2A3,0x6A5F,0xAEF9,0x69D0,0x1791,0x9958,0x3A27,0x27B9, ++ 0xD938,0xEB13,0x2BB3,0x2233,0xD2BB,0xA970,0x0789,0x33A7, ++ 0x2DB6,0x3C22,0x1592,0xC920,0x8749,0xAAFF,0x5078,0xA57A, ++ 0x038F,0x59F8,0x0980,0x1A17,0x65DA,0xD731,0x84C6,0xD0B8, ++ 0x82C3,0x29B0,0x5A77,0x1E11,0x7BCB,0xA8FC,0x6DD6,0x2C3A, ++ }, ++ ++ ++ { /* second half of table is unsigned char-reversed version of first! */ ++ 0xA5C6,0x84F8,0x99EE,0x8DF6,0x0DFF,0xBDD6,0xB1DE,0x5491, ++ 0x5060,0x0302,0xA9CE,0x7D56,0x19E7,0x62B5,0xE64D,0x9AEC, ++ 0x458F,0x9D1F,0x4089,0x87FA,0x15EF,0xEBB2,0xC98E,0x0BFB, ++ 0xEC41,0x67B3,0xFD5F,0xEA45,0xBF23,0xF753,0x96E4,0x5B9B, ++ 0xC275,0x1CE1,0xAE3D,0x6A4C,0x5A6C,0x417E,0x02F5,0x4F83, ++ 0x5C68,0xF451,0x34D1,0x08F9,0x93E2,0x73AB,0x5362,0x3F2A, ++ 0x0C08,0x5295,0x6546,0x5E9D,0x2830,0xA137,0x0F0A,0xB52F, ++ 0x090E,0x3624,0x9B1B,0x3DDF,0x26CD,0x694E,0xCD7F,0x9FEA, ++ 0x1B12,0x9E1D,0x7458,0x2E34,0x2D36,0xB2DC,0xEEB4,0xFB5B, ++ 0xF6A4,0x4D76,0x61B7,0xCE7D,0x7B52,0x3EDD,0x715E,0x9713, ++ 0xF5A6,0x68B9,0x0000,0x2CC1,0x6040,0x1FE3,0xC879,0xEDB6, ++ 0xBED4,0x468D,0xD967,0x4B72,0xDE94,0xD498,0xE8B0,0x4A85, ++ 0x6BBB,0x2AC5,0xE54F,0x16ED,0xC586,0xD79A,0x5566,0x9411, ++ 0xCF8A,0x10E9,0x0604,0x81FE,0xF0A0,0x4478,0xBA25,0xE34B, ++ 0xF3A2,0xFE5D,0xC080,0x8A05,0xAD3F,0xBC21,0x4870,0x04F1, ++ 0xDF63,0xC177,0x75AF,0x6342,0x3020,0x1AE5,0x0EFD,0x6DBF, ++ 0x4C81,0x1418,0x3526,0x2FC3,0xE1BE,0xA235,0xCC88,0x392E, ++ 0x5793,0xF255,0x82FC,0x477A,0xACC8,0xE7BA,0x2B32,0x95E6, ++ 0xA0C0,0x9819,0xD19E,0x7FA3,0x6644,0x7E54,0xAB3B,0x830B, ++ 0xCA8C,0x29C7,0xD36B,0x3C28,0x79A7,0xE2BC,0x1D16,0x76AD, ++ 0x3BDB,0x5664,0x4E74,0x1E14,0xDB92,0x0A0C,0x6C48,0xE4B8, ++ 0x5D9F,0x6EBD,0xEF43,0xA6C4,0xA839,0xA431,0x37D3,0x8BF2, ++ 0x32D5,0x438B,0x596E,0xB7DA,0x8C01,0x64B1,0xD29C,0xE049, ++ 0xB4D8,0xFAAC,0x07F3,0x25CF,0xAFCA,0x8EF4,0xE947,0x1810, ++ 0xD56F,0x88F0,0x6F4A,0x725C,0x2438,0xF157,0xC773,0x5197, ++ 0x23CB,0x7CA1,0x9CE8,0x213E,0xDD96,0xDC61,0x860D,0x850F, ++ 0x90E0,0x427C,0xC471,0xAACC,0xD890,0x0506,0x01F7,0x121C, ++ 0xA3C2,0x5F6A,0xF9AE,0xD069,0x9117,0x5899,0x273A,0xB927, ++ 0x38D9,0x13EB,0xB32B,0x3322,0xBBD2,0x70A9,0x8907,0xA733, ++ 0xB62D,0x223C,0x9215,0x20C9,0x4987,0xFFAA,0x7850,0x7AA5, ++ 0x8F03,0xF859,0x8009,0x171A,0xDA65,0x31D7,0xC684,0xB8D0, ++ 0xC382,0xB029,0x775A,0x111E,0xCB7B,0xFCA8,0xD66D,0x3A2C, ++ } ++}; ++ ++ /* ++********************************************************************** ++* Routine: Phase 1 -- generate P1K, given TA, TK, IV32 ++* ++* Inputs: ++* tk[] = temporal key [128 bits] ++* ta[] = transmitter's MAC address [ 48 bits] ++* iv32 = upper 32 bits of IV [ 32 bits] ++* Output: ++* p1k[] = Phase 1 key [ 80 bits] ++* ++* Note: ++* This function only needs to be called every 2**16 packets, ++* although in theory it could be called every packet. ++* ++********************************************************************** ++*/ ++static void phase1(u16 *p1k,const u8 *tk,const u8 *ta,u32 iv32) ++{ ++ sint i; ++_func_enter_; ++ /* Initialize the 80 bits of P1K[] from IV32 and TA[0..5] */ ++ p1k[0] = Lo16(iv32); ++ p1k[1] = Hi16(iv32); ++ p1k[2] = Mk16(ta[1],ta[0]); /* use TA[] as little-endian */ ++ p1k[3] = Mk16(ta[3],ta[2]); ++ p1k[4] = Mk16(ta[5],ta[4]); ++ ++ /* Now compute an unbalanced Feistel cipher with 80-bit block */ ++ /* size on the 80-bit block P1K[], using the 128-bit key TK[] */ ++ for (i=0; i < PHASE1_LOOP_CNT ;i++) ++ { /* Each add operation here is mod 2**16 */ ++ p1k[0] += _S_(p1k[4] ^ TK16((i&1)+0)); ++ p1k[1] += _S_(p1k[0] ^ TK16((i&1)+2)); ++ p1k[2] += _S_(p1k[1] ^ TK16((i&1)+4)); ++ p1k[3] += _S_(p1k[2] ^ TK16((i&1)+6)); ++ p1k[4] += _S_(p1k[3] ^ TK16((i&1)+0)); ++ p1k[4] += (unsigned short)i; /* avoid "slide attacks" */ ++ } ++_func_exit_; ++} ++ ++ ++/* ++********************************************************************** ++* Routine: Phase 2 -- generate RC4KEY, given TK, P1K, IV16 ++* ++* Inputs: ++* tk[] = Temporal key [128 bits] ++* p1k[] = Phase 1 output key [ 80 bits] ++* iv16 = low 16 bits of IV counter [ 16 bits] ++* Output: ++* rc4key[] = the key used to encrypt the packet [128 bits] ++* ++* Note: ++* The value {TA,IV32,IV16} for Phase1/Phase2 must be unique ++* across all packets using the same key TK value. Then, for a ++* given value of TK[], this TKIP48 construction guarantees that ++* the final RC4KEY value is unique across all packets. ++* ++* Suggested implementation optimization: if PPK[] is "overlaid" ++* appropriately on RC4KEY[], there is no need for the final ++* for loop below that copies the PPK[] result into RC4KEY[]. ++* ++********************************************************************** ++*/ ++static void phase2(u8 *rc4key,const u8 *tk,const u16 *p1k,u16 iv16) ++{ ++ sint i; ++ u16 PPK[6]; /* temporary key for mixing */ ++_func_enter_; ++ /* Note: all adds in the PPK[] equations below are mod 2**16 */ ++ for (i=0;i<5;i++) PPK[i]=p1k[i]; /* first, copy P1K to PPK */ ++ PPK[5] = p1k[4] +iv16; /* next, add in IV16 */ ++ ++ /* Bijective non-linear mixing of the 96 bits of PPK[0..5] */ ++ PPK[0] += _S_(PPK[5] ^ TK16(0)); /* Mix key in each "round" */ ++ PPK[1] += _S_(PPK[0] ^ TK16(1)); ++ PPK[2] += _S_(PPK[1] ^ TK16(2)); ++ PPK[3] += _S_(PPK[2] ^ TK16(3)); ++ PPK[4] += _S_(PPK[3] ^ TK16(4)); ++ PPK[5] += _S_(PPK[4] ^ TK16(5)); /* Total # S-box lookups == 6 */ ++ ++ /* Final sweep: bijective, "linear". Rotates kill LSB correlations */ ++ PPK[0] += RotR1(PPK[5] ^ TK16(6)); ++ PPK[1] += RotR1(PPK[0] ^ TK16(7)); /* Use all of TK[] in Phase2 */ ++ PPK[2] += RotR1(PPK[1]); ++ PPK[3] += RotR1(PPK[2]); ++ PPK[4] += RotR1(PPK[3]); ++ PPK[5] += RotR1(PPK[4]); ++ /* Note: At this point, for a given key TK[0..15], the 96-bit output */ ++ /* value PPK[0..5] is guaranteed to be unique, as a function */ ++ /* of the 96-bit "input" value {TA,IV32,IV16}. That is, P1K */ ++ /* is now a keyed permutation of {TA,IV32,IV16}. */ ++ ++ /* Set RC4KEY[0..3], which includes "cleartext" portion of RC4 key */ ++ rc4key[0] = Hi8(iv16); /* RC4KEY[0..2] is the WEP IV */ ++ rc4key[1] =(Hi8(iv16) | 0x20) & 0x7F; /* Help avoid weak (FMS) keys */ ++ rc4key[2] = Lo8(iv16); ++ rc4key[3] = Lo8((PPK[5] ^ TK16(0)) >> 1); ++ ++ ++ /* Copy 96 bits of PPK[0..5] to RC4KEY[4..15] (little-endian) */ ++ for (i=0;i<6;i++) ++ { ++ rc4key[4+2*i] = Lo8(PPK[i]); ++ rc4key[5+2*i] = Hi8(PPK[i]); ++ } ++_func_exit_; ++} ++ ++ ++//The hlen isn't include the IV ++u32 rtw_tkip_encrypt(_adapter *padapter, u8 *pxmitframe) ++{ // exclude ICV ++ u16 pnl; ++ u32 pnh; ++ u8 rc4key[16]; ++ u8 ttkey[16]; ++ u8 crc[4]; ++ u8 hw_hdr_offset = 0; ++ struct arc4context mycontext; ++ sint curfragnum,length; ++ u32 prwskeylen; ++ ++ u8 *pframe, *payload,*iv,*prwskey; ++ union pn48 dot11txpn; ++ struct sta_info *stainfo; ++ struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; ++ struct security_priv *psecuritypriv=&padapter->securitypriv; ++ struct xmit_priv *pxmitpriv=&padapter->xmitpriv; ++ u32 res=_SUCCESS; ++_func_enter_; ++ ++ if(((struct xmit_frame*)pxmitframe)->buf_addr==NULL) ++ return _FAIL; ++ ++#ifdef CONFIG_USB_TX_AGGREGATION ++ hw_hdr_offset = TXDESC_SIZE + ++ (((struct xmit_frame*)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ); ++#else ++ #ifdef CONFIG_TX_EARLY_MODE ++ hw_hdr_offset = TXDESC_OFFSET+EARLY_MODE_INFO_SIZE; ++ #else ++ hw_hdr_offset = TXDESC_OFFSET; ++ #endif ++#endif ++ ++ pframe = ((struct xmit_frame*)pxmitframe)->buf_addr + hw_hdr_offset; ++ //4 start to encrypt each fragment ++ if(pattrib->encrypt==_TKIP_){ ++ ++ if(pattrib->psta) ++ { ++ stainfo = pattrib->psta; ++ } ++ else ++ { ++ DBG_871X("%s, call rtw_get_stainfo()\n", __func__); ++ stainfo=rtw_get_stainfo(&padapter->stapriv ,&pattrib->ra[0] ); ++ } ++ ++ if (stainfo!=NULL){ ++ ++ if(!(stainfo->state &_FW_LINKED)) ++ { ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, stainfo->state); ++ return _FAIL; ++ } ++ ++ RT_TRACE(_module_rtl871x_security_c_,_drv_err_,("rtw_tkip_encrypt: stainfo!=NULL!!!\n")); ++ ++ if(IS_MCAST(pattrib->ra)) ++ { ++ prwskey=psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; ++ } ++ else ++ { ++ prwskey=&stainfo->dot118021x_UncstKey.skey[0]; ++ } ++ ++ prwskeylen=16; ++ ++ for(curfragnum=0;curfragnumnr_frags;curfragnum++){ ++ iv=pframe+pattrib->hdrlen; ++ payload=pframe+pattrib->iv_len+pattrib->hdrlen; ++ ++ GET_TKIP_PN(iv, dot11txpn); ++ ++ pnl=(u16)(dot11txpn.val); ++ pnh=(u32)(dot11txpn.val>>16); ++ ++ phase1((u16 *)&ttkey[0],prwskey,&pattrib->ta[0],pnh); ++ ++ phase2(&rc4key[0],prwskey,(u16 *)&ttkey[0],pnl); ++ ++ if((curfragnum+1)==pattrib->nr_frags){ //4 the last fragment ++ length=pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len- pattrib->icv_len; ++ RT_TRACE(_module_rtl871x_security_c_,_drv_info_,("pattrib->iv_len =%x, pattrib->icv_len =%x\n", pattrib->iv_len,pattrib->icv_len)); ++ *((u32 *)crc)=cpu_to_le32(getcrc32(payload,length));/* modified by Amy*/ ++ ++ arcfour_init(&mycontext, rc4key,16); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ arcfour_encrypt(&mycontext, payload+length, crc, 4); ++ ++ } ++ else{ ++ length=pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len ; ++ *((u32 *)crc)=cpu_to_le32(getcrc32(payload,length));/* modified by Amy*/ ++ arcfour_init(&mycontext,rc4key,16); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ arcfour_encrypt(&mycontext, payload+length, crc, 4); ++ ++ pframe+=pxmitpriv->frag_len; ++ pframe=(u8 *)RND4((SIZE_PTR)(pframe)); ++ ++ } ++ } ++ ++ ++ } ++ else{ ++ RT_TRACE(_module_rtl871x_security_c_,_drv_err_,("rtw_tkip_encrypt: stainfo==NULL!!!\n")); ++ DBG_871X("%s, psta==NUL\n", __func__); ++ res=_FAIL; ++ } ++ ++ } ++_func_exit_; ++ return res; ++ ++} ++ ++ ++//The hlen isn't include the IV ++u32 rtw_tkip_decrypt(_adapter *padapter, u8 *precvframe) ++{ // exclude ICV ++ u16 pnl; ++ u32 pnh; ++ u8 rc4key[16]; ++ u8 ttkey[16]; ++ u8 crc[4]; ++ struct arc4context mycontext; ++ sint length; ++ u32 prwskeylen; ++ ++ u8 *pframe, *payload,*iv,*prwskey; ++ union pn48 dot11txpn; ++ struct sta_info *stainfo; ++ struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib; ++ struct security_priv *psecuritypriv=&padapter->securitypriv; ++// struct recv_priv *precvpriv=&padapter->recvpriv; ++ u32 res=_SUCCESS; ++ ++_func_enter_; ++ ++ pframe=(unsigned char *)((union recv_frame*)precvframe)->u.hdr.rx_data; ++ ++ //4 start to decrypt recvframe ++ if(prxattrib->encrypt==_TKIP_){ ++ ++ stainfo=rtw_get_stainfo(&padapter->stapriv ,&prxattrib->ta[0] ); ++ if (stainfo!=NULL){ ++ ++ if(IS_MCAST(prxattrib->ra)) ++ { ++ static u32 start = 0; ++ static u32 no_gkey_bc_cnt = 0; ++ static u32 no_gkey_mc_cnt = 0; ++ ++ if(psecuritypriv->binstallGrpkey==_FALSE) ++ { ++ res=_FAIL; ++ ++ if (start == 0) ++ start = rtw_get_current_time(); ++ ++ if (is_broadcast_mac_addr(prxattrib->ra)) ++ no_gkey_bc_cnt++; ++ else ++ no_gkey_mc_cnt++; ++ ++ if (rtw_get_passing_time_ms(start) > 1000) { ++ if (no_gkey_bc_cnt || no_gkey_mc_cnt) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", ++ FUNC_ADPT_ARG(padapter), no_gkey_bc_cnt, no_gkey_mc_cnt); ++ } ++ start = rtw_get_current_time(); ++ no_gkey_bc_cnt = 0; ++ no_gkey_mc_cnt = 0; ++ } ++ goto exit; ++ } ++ ++ if (no_gkey_bc_cnt || no_gkey_mc_cnt) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" gkey installed. no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", ++ FUNC_ADPT_ARG(padapter), no_gkey_bc_cnt, no_gkey_mc_cnt); ++ } ++ start = 0; ++ no_gkey_bc_cnt = 0; ++ no_gkey_mc_cnt = 0; ++ ++ //DBG_871X("rx bc/mc packets, to perform sw rtw_tkip_decrypt\n"); ++ //prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; ++ prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; ++ prwskeylen=16; ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_security_c_,_drv_err_,("rtw_tkip_decrypt: stainfo!=NULL!!!\n")); ++ prwskey=&stainfo->dot118021x_UncstKey.skey[0]; ++ prwskeylen=16; ++ } ++ ++ iv=pframe+prxattrib->hdrlen; ++ payload=pframe+prxattrib->iv_len+prxattrib->hdrlen; ++ length= ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len; ++ ++ GET_TKIP_PN(iv, dot11txpn); ++ ++ pnl=(u16)(dot11txpn.val); ++ pnh=(u32)(dot11txpn.val>>16); ++ ++ phase1((u16 *)&ttkey[0],prwskey,&prxattrib->ta[0],pnh); ++ phase2(&rc4key[0],prwskey,(unsigned short *)&ttkey[0],pnl); ++ ++ //4 decrypt payload include icv ++ ++ arcfour_init(&mycontext, rc4key,16); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ ++ *((u32 *)crc)=le32_to_cpu(getcrc32(payload,length-4)); ++ ++ if(crc[3]!=payload[length-1] || crc[2]!=payload[length-2] || crc[1]!=payload[length-3] || crc[0]!=payload[length-4]) ++ { ++ RT_TRACE(_module_rtl871x_security_c_,_drv_err_,("rtw_wep_decrypt:icv error crc[3](%x)!=payload[length-1](%x) || crc[2](%x)!=payload[length-2](%x) || crc[1](%x)!=payload[length-3](%x) || crc[0](%x)!=payload[length-4](%x)\n", ++ crc[3],payload[length-1],crc[2],payload[length-2],crc[1],payload[length-3],crc[0],payload[length-4])); ++ res=_FAIL; ++ } ++ ++ ++ } ++ else{ ++ RT_TRACE(_module_rtl871x_security_c_,_drv_err_,("rtw_tkip_decrypt: stainfo==NULL!!!\n")); ++ res=_FAIL; ++ } ++ ++ } ++_func_exit_; ++exit: ++ return res; ++ ++} ++ ++ ++//3 =====AES related===== ++ ++ ++ ++#define MAX_MSG_SIZE 2048 ++/*****************************/ ++/******** SBOX Table *********/ ++/*****************************/ ++ ++ static u8 sbox_table[256] = ++ { ++ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, ++ 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, ++ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, ++ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, ++ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, ++ 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, ++ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, ++ 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, ++ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, ++ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, ++ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, ++ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, ++ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, ++ 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, ++ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, ++ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, ++ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, ++ 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, ++ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, ++ 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, ++ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, ++ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, ++ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, ++ 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, ++ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, ++ 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, ++ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, ++ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, ++ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, ++ 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, ++ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, ++ 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ++ }; ++ ++/*****************************/ ++/**** Function Prototypes ****/ ++/*****************************/ ++ ++static void bitwise_xor(u8 *ina, u8 *inb, u8 *out); ++static void construct_mic_iv( ++ u8 *mic_header1, ++ sint qc_exists, ++ sint a4_exists, ++ u8 *mpdu, ++ uint payload_length, ++ u8 * pn_vector, ++ uint frtype);// add for CONFIG_IEEE80211W, none 11w also can use ++static void construct_mic_header1( ++ u8 *mic_header1, ++ sint header_length, ++ u8 *mpdu, ++ uint frtype);// add for CONFIG_IEEE80211W, none 11w also can use ++static void construct_mic_header2( ++ u8 *mic_header2, ++ u8 *mpdu, ++ sint a4_exists, ++ sint qc_exists); ++static void construct_ctr_preload( ++ u8 *ctr_preload, ++ sint a4_exists, ++ sint qc_exists, ++ u8 *mpdu, ++ u8 *pn_vector, ++ sint c, ++ uint frtype);// add for CONFIG_IEEE80211W, none 11w also can use ++static void xor_128(u8 *a, u8 *b, u8 *out); ++static void xor_32(u8 *a, u8 *b, u8 *out); ++static u8 sbox(u8 a); ++static void next_key(u8 *key, sint round); ++static void byte_sub(u8 *in, u8 *out); ++static void shift_row(u8 *in, u8 *out); ++static void mix_column(u8 *in, u8 *out); ++#ifndef PLATFORM_FREEBSD ++static void add_round_key( u8 *shiftrow_in, ++ u8 *mcol_in, ++ u8 *block_in, ++ sint round, ++ u8 *out); ++#endif //PLATFORM_FREEBSD ++static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext); ++ ++ ++/****************************************/ ++/* aes128k128d() */ ++/* Performs a 128 bit AES encrypt with */ ++/* 128 bit data. */ ++/****************************************/ ++static void xor_128(u8 *a, u8 *b, u8 *out) ++{ ++ sint i; ++_func_enter_; ++ for (i=0;i<16; i++) ++ { ++ out[i] = a[i] ^ b[i]; ++ } ++_func_exit_; ++} ++ ++ ++static void xor_32(u8 *a, u8 *b, u8 *out) ++{ ++ sint i; ++_func_enter_; ++ for (i=0;i<4; i++) ++ { ++ out[i] = a[i] ^ b[i]; ++ } ++_func_exit_; ++} ++ ++ ++static u8 sbox(u8 a) ++{ ++ return sbox_table[(sint)a]; ++} ++ ++ ++static void next_key(u8 *key, sint round) ++{ ++ u8 rcon; ++ u8 sbox_key[4]; ++ u8 rcon_table[12] = ++ { ++ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, ++ 0x1b, 0x36, 0x36, 0x36 ++ }; ++_func_enter_; ++ sbox_key[0] = sbox(key[13]); ++ sbox_key[1] = sbox(key[14]); ++ sbox_key[2] = sbox(key[15]); ++ sbox_key[3] = sbox(key[12]); ++ ++ rcon = rcon_table[round]; ++ ++ xor_32(&key[0], sbox_key, &key[0]); ++ key[0] = key[0] ^ rcon; ++ ++ xor_32(&key[4], &key[0], &key[4]); ++ xor_32(&key[8], &key[4], &key[8]); ++ xor_32(&key[12], &key[8], &key[12]); ++_func_exit_; ++} ++ ++ ++static void byte_sub(u8 *in, u8 *out) ++{ ++ sint i; ++_func_enter_; ++ for (i=0; i< 16; i++) ++ { ++ out[i] = sbox(in[i]); ++ } ++_func_exit_; ++} ++ ++ ++static void shift_row(u8 *in, u8 *out) ++{ ++_func_enter_; ++ out[0] = in[0]; ++ out[1] = in[5]; ++ out[2] = in[10]; ++ out[3] = in[15]; ++ out[4] = in[4]; ++ out[5] = in[9]; ++ out[6] = in[14]; ++ out[7] = in[3]; ++ out[8] = in[8]; ++ out[9] = in[13]; ++ out[10] = in[2]; ++ out[11] = in[7]; ++ out[12] = in[12]; ++ out[13] = in[1]; ++ out[14] = in[6]; ++ out[15] = in[11]; ++_func_exit_; ++} ++ ++ ++static void mix_column(u8 *in, u8 *out) ++{ ++ sint i; ++ u8 add1b[4]; ++ u8 add1bf7[4]; ++ u8 rotl[4]; ++ u8 swap_halfs[4]; ++ u8 andf7[4]; ++ u8 rotr[4]; ++ u8 temp[4]; ++ u8 tempb[4]; ++_func_enter_; ++ for (i=0 ; i<4; i++) ++ { ++ if ((in[i] & 0x80)== 0x80) ++ add1b[i] = 0x1b; ++ else ++ add1b[i] = 0x00; ++ } ++ ++ swap_halfs[0] = in[2]; /* Swap halfs */ ++ swap_halfs[1] = in[3]; ++ swap_halfs[2] = in[0]; ++ swap_halfs[3] = in[1]; ++ ++ rotl[0] = in[3]; /* Rotate left 8 bits */ ++ rotl[1] = in[0]; ++ rotl[2] = in[1]; ++ rotl[3] = in[2]; ++ ++ andf7[0] = in[0] & 0x7f; ++ andf7[1] = in[1] & 0x7f; ++ andf7[2] = in[2] & 0x7f; ++ andf7[3] = in[3] & 0x7f; ++ ++ for (i = 3; i>0; i--) /* logical shift left 1 bit */ ++ { ++ andf7[i] = andf7[i] << 1; ++ if ((andf7[i-1] & 0x80) == 0x80) ++ { ++ andf7[i] = (andf7[i] | 0x01); ++ } ++ } ++ andf7[0] = andf7[0] << 1; ++ andf7[0] = andf7[0] & 0xfe; ++ ++ xor_32(add1b, andf7, add1bf7); ++ ++ xor_32(in, add1bf7, rotr); ++ ++ temp[0] = rotr[0]; /* Rotate right 8 bits */ ++ rotr[0] = rotr[1]; ++ rotr[1] = rotr[2]; ++ rotr[2] = rotr[3]; ++ rotr[3] = temp[0]; ++ ++ xor_32(add1bf7, rotr, temp); ++ xor_32(swap_halfs, rotl,tempb); ++ xor_32(temp, tempb, out); ++_func_exit_; ++} ++ ++ ++static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext) ++{ ++ sint round; ++ sint i; ++ u8 intermediatea[16]; ++ u8 intermediateb[16]; ++ u8 round_key[16]; ++_func_enter_; ++ for(i=0; i<16; i++) round_key[i] = key[i]; ++ ++ for (round = 0; round < 11; round++) ++ { ++ if (round == 0) ++ { ++ xor_128(round_key, data, ciphertext); ++ next_key(round_key, round); ++ } ++ else if (round == 10) ++ { ++ byte_sub(ciphertext, intermediatea); ++ shift_row(intermediatea, intermediateb); ++ xor_128(intermediateb, round_key, ciphertext); ++ } ++ else /* 1 - 9 */ ++ { ++ byte_sub(ciphertext, intermediatea); ++ shift_row(intermediatea, intermediateb); ++ mix_column(&intermediateb[0], &intermediatea[0]); ++ mix_column(&intermediateb[4], &intermediatea[4]); ++ mix_column(&intermediateb[8], &intermediatea[8]); ++ mix_column(&intermediateb[12], &intermediatea[12]); ++ xor_128(intermediatea, round_key, ciphertext); ++ next_key(round_key, round); ++ } ++ } ++_func_exit_; ++} ++ ++ ++/************************************************/ ++/* construct_mic_iv() */ ++/* Builds the MIC IV from header fields and PN */ ++/* Baron think the function is construct CCM */ ++/* nonce */ ++/************************************************/ ++static void construct_mic_iv( ++ u8 *mic_iv, ++ sint qc_exists, ++ sint a4_exists, ++ u8 *mpdu, ++ uint payload_length, ++ u8 *pn_vector, ++ uint frtype// add for CONFIG_IEEE80211W, none 11w also can use ++ ) ++{ ++ sint i; ++_func_enter_; ++ mic_iv[0] = 0x59; ++ if (qc_exists && a4_exists) mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */ ++ if (qc_exists && !a4_exists) mic_iv[1] = mpdu[24] & 0x0f; /* mute bits 7-4 */ ++ if (!qc_exists) mic_iv[1] = 0x00; ++#ifdef CONFIG_IEEE80211W ++ //802.11w management frame should set management bit(4) ++ if(frtype == WIFI_MGT_TYPE) ++ mic_iv[1] |= BIT(4); ++#endif //CONFIG_IEEE80211W ++ for (i = 2; i < 8; i++) ++ mic_iv[i] = mpdu[i + 8]; /* mic_iv[2:7] = A2[0:5] = mpdu[10:15] */ ++ #ifdef CONSISTENT_PN_ORDER ++ for (i = 8; i < 14; i++) ++ mic_iv[i] = pn_vector[i - 8]; /* mic_iv[8:13] = PN[0:5] */ ++ #else ++ for (i = 8; i < 14; i++) ++ mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */ ++ #endif ++ mic_iv[14] = (unsigned char) (payload_length / 256); ++ mic_iv[15] = (unsigned char) (payload_length % 256); ++_func_exit_; ++} ++ ++ ++/************************************************/ ++/* construct_mic_header1() */ ++/* Builds the first MIC header block from */ ++/* header fields. */ ++/* Build AAD SC,A1,A2 */ ++/************************************************/ ++static void construct_mic_header1( ++ u8 *mic_header1, ++ sint header_length, ++ u8 *mpdu, ++ uint frtype// add for CONFIG_IEEE80211W, none 11w also can use ++ ) ++{ ++_func_enter_; ++ mic_header1[0] = (u8)((header_length - 2) / 256); ++ mic_header1[1] = (u8)((header_length - 2) % 256); ++#ifdef CONFIG_IEEE80211W ++ //802.11w management frame don't AND subtype bits 4,5,6 of frame control field ++ if(frtype == WIFI_MGT_TYPE) ++ mic_header1[2] = mpdu[0]; /* Mute CF poll & CF ack bits */ ++ else ++#endif //CONFIG_IEEE80211W ++ mic_header1[2] = mpdu[0] & 0xcf; /* Mute CF poll & CF ack bits */ ++ ++ mic_header1[3] = mpdu[1] & 0xc7; /* Mute retry, more data and pwr mgt bits */ ++ mic_header1[4] = mpdu[4]; /* A1 */ ++ mic_header1[5] = mpdu[5]; ++ mic_header1[6] = mpdu[6]; ++ mic_header1[7] = mpdu[7]; ++ mic_header1[8] = mpdu[8]; ++ mic_header1[9] = mpdu[9]; ++ mic_header1[10] = mpdu[10]; /* A2 */ ++ mic_header1[11] = mpdu[11]; ++ mic_header1[12] = mpdu[12]; ++ mic_header1[13] = mpdu[13]; ++ mic_header1[14] = mpdu[14]; ++ mic_header1[15] = mpdu[15]; ++_func_exit_; ++} ++ ++ ++/************************************************/ ++/* construct_mic_header2() */ ++/* Builds the last MIC header block from */ ++/* header fields. */ ++/************************************************/ ++static void construct_mic_header2( ++ u8 *mic_header2, ++ u8 *mpdu, ++ sint a4_exists, ++ sint qc_exists ++ ) ++{ ++ sint i; ++_func_enter_; ++ for (i = 0; i<16; i++) mic_header2[i]=0x00; ++ ++ mic_header2[0] = mpdu[16]; /* A3 */ ++ mic_header2[1] = mpdu[17]; ++ mic_header2[2] = mpdu[18]; ++ mic_header2[3] = mpdu[19]; ++ mic_header2[4] = mpdu[20]; ++ mic_header2[5] = mpdu[21]; ++ ++ //mic_header2[6] = mpdu[22] & 0xf0; /* SC */ ++ mic_header2[6] = 0x00; ++ mic_header2[7] = 0x00; /* mpdu[23]; */ ++ ++ ++ if (!qc_exists && a4_exists) ++ { ++ for (i=0;i<6;i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ ++ ++ } ++ ++ if (qc_exists && !a4_exists) ++ { ++ mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */ ++ mic_header2[9] = mpdu[25] & 0x00; ++ } ++ ++ if (qc_exists && a4_exists) ++ { ++ for (i=0;i<6;i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ ++ ++ mic_header2[14] = mpdu[30] & 0x0f; ++ mic_header2[15] = mpdu[31] & 0x00; ++ } ++ ++_func_exit_; ++} ++ ++ ++/************************************************/ ++/* construct_mic_header2() */ ++/* Builds the last MIC header block from */ ++/* header fields. */ ++/* Baron think the function is construct CCM */ ++/* nonce */ ++/************************************************/ ++static void construct_ctr_preload( ++ u8 *ctr_preload, ++ sint a4_exists, ++ sint qc_exists, ++ u8 *mpdu, ++ u8 *pn_vector, ++ sint c, ++ uint frtype // add for CONFIG_IEEE80211W, none 11w also can use ++ ) ++{ ++ sint i = 0; ++_func_enter_; ++ for (i=0; i<16; i++) ctr_preload[i] = 0x00; ++ i = 0; ++ ++ ctr_preload[0] = 0x01; /* flag */ ++ if (qc_exists && a4_exists) ++ ctr_preload[1] = mpdu[30] & 0x0f; /* QoC_Control */ ++ if (qc_exists && !a4_exists) ++ ctr_preload[1] = mpdu[24] & 0x0f; ++#ifdef CONFIG_IEEE80211W ++ //802.11w management frame should set management bit(4) ++ if(frtype == WIFI_MGT_TYPE) ++ ctr_preload[1] |= BIT(4); ++#endif //CONFIG_IEEE80211W ++ for (i = 2; i < 8; i++) ++ ctr_preload[i] = mpdu[i + 8]; /* ctr_preload[2:7] = A2[0:5] = mpdu[10:15] */ ++ #ifdef CONSISTENT_PN_ORDER ++ for (i = 8; i < 14; i++) ++ ctr_preload[i] = pn_vector[i - 8]; /* ctr_preload[8:13] = PN[0:5] */ ++ #else ++ for (i = 8; i < 14; i++) ++ ctr_preload[i] = pn_vector[13 - i]; /* ctr_preload[8:13] = PN[5:0] */ ++ #endif ++ ctr_preload[14] = (unsigned char) (c / 256); /* Ctr */ ++ ctr_preload[15] = (unsigned char) (c % 256); ++_func_exit_; ++} ++ ++ ++/************************************/ ++/* bitwise_xor() */ ++/* A 128 bit, bitwise exclusive or */ ++/************************************/ ++static void bitwise_xor(u8 *ina, u8 *inb, u8 *out) ++{ ++ sint i; ++_func_enter_; ++ for (i=0; i<16; i++) ++ { ++ out[i] = ina[i] ^ inb[i]; ++ } ++_func_exit_; ++} ++ ++ ++static sint aes_cipher(u8 *key, uint hdrlen, ++ u8 *pframe, uint plen) ++{ ++// /*static*/ unsigned char message[MAX_MSG_SIZE]; ++ uint qc_exists, a4_exists, i, j, payload_remainder, ++ num_blocks, payload_index; ++ ++ u8 pn_vector[6]; ++ u8 mic_iv[16]; ++ u8 mic_header1[16]; ++ u8 mic_header2[16]; ++ u8 ctr_preload[16]; ++ ++ /* Intermediate Buffers */ ++ u8 chain_buffer[16]; ++ u8 aes_out[16]; ++ u8 padded_buffer[16]; ++ u8 mic[8]; ++// uint offset = 0; ++ uint frtype = GetFrameType(pframe); ++ uint frsubtype = GetFrameSubType(pframe); ++ ++_func_enter_; ++ frsubtype=frsubtype>>4; ++ ++ ++ _rtw_memset((void *)mic_iv, 0, 16); ++ _rtw_memset((void *)mic_header1, 0, 16); ++ _rtw_memset((void *)mic_header2, 0, 16); ++ _rtw_memset((void *)ctr_preload, 0, 16); ++ _rtw_memset((void *)chain_buffer, 0, 16); ++ _rtw_memset((void *)aes_out, 0, 16); ++ _rtw_memset((void *)padded_buffer, 0, 16); ++ ++ if ((hdrlen == WLAN_HDR_A3_LEN )||(hdrlen == WLAN_HDR_A3_QOS_LEN)) ++ a4_exists = 0; ++ else ++ a4_exists = 1; ++ ++ if ( ++ ((frtype|frsubtype) == WIFI_DATA_CFACK) || ++ ((frtype|frsubtype) == WIFI_DATA_CFPOLL)|| ++ ((frtype|frsubtype) == WIFI_DATA_CFACKPOLL)) ++ { ++ qc_exists = 1; ++ if(hdrlen != WLAN_HDR_A3_QOS_LEN){ ++ ++ hdrlen += 2; ++ } ++ } ++ // add for CONFIG_IEEE80211W, none 11w also can use ++ else if ((frtype == WIFI_DATA) && ++ ((frsubtype == 0x08) || ++ (frsubtype == 0x09)|| ++ (frsubtype == 0x0a)|| ++ (frsubtype == 0x0b))) ++ { ++ if(hdrlen != WLAN_HDR_A3_QOS_LEN){ ++ ++ hdrlen += 2; ++ } ++ qc_exists = 1; ++ } ++ else ++ qc_exists = 0; ++ ++ pn_vector[0]=pframe[hdrlen]; ++ pn_vector[1]=pframe[hdrlen+1]; ++ pn_vector[2]=pframe[hdrlen+4]; ++ pn_vector[3]=pframe[hdrlen+5]; ++ pn_vector[4]=pframe[hdrlen+6]; ++ pn_vector[5]=pframe[hdrlen+7]; ++ ++ construct_mic_iv( ++ mic_iv, ++ qc_exists, ++ a4_exists, ++ pframe, //message, ++ plen, ++ pn_vector, ++ frtype // add for CONFIG_IEEE80211W, none 11w also can use ++ ); ++ ++ construct_mic_header1( ++ mic_header1, ++ hdrlen, ++ pframe, //message ++ frtype // add for CONFIG_IEEE80211W, none 11w also can use ++ ); ++ construct_mic_header2( ++ mic_header2, ++ pframe, //message, ++ a4_exists, ++ qc_exists ++ ); ++ ++ ++ payload_remainder = plen % 16; ++ num_blocks = plen / 16; ++ ++ /* Find start of payload */ ++ payload_index = (hdrlen + 8); ++ ++ /* Calculate MIC */ ++ aes128k128d(key, mic_iv, aes_out); ++ bitwise_xor(aes_out, mic_header1, chain_buffer); ++ aes128k128d(key, chain_buffer, aes_out); ++ bitwise_xor(aes_out, mic_header2, chain_buffer); ++ aes128k128d(key, chain_buffer, aes_out); ++ ++ for (i = 0; i < num_blocks; i++) ++ { ++ bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);//bitwise_xor(aes_out, &message[payload_index], chain_buffer); ++ ++ payload_index += 16; ++ aes128k128d(key, chain_buffer, aes_out); ++ } ++ ++ /* Add on the final payload block if it needs padding */ ++ if (payload_remainder > 0) ++ { ++ for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; ++ for (j = 0; j < payload_remainder; j++) ++ { ++ padded_buffer[j] = pframe[payload_index++];//padded_buffer[j] = message[payload_index++]; ++ } ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ aes128k128d(key, chain_buffer, aes_out); ++ ++ } ++ ++ for (j = 0 ; j < 8; j++) mic[j] = aes_out[j]; ++ ++ /* Insert MIC into payload */ ++ for (j = 0; j < 8; j++) ++ pframe[payload_index+j] = mic[j]; //message[payload_index+j] = mic[j]; ++ ++ payload_index = hdrlen + 8; ++ for (i=0; i< num_blocks; i++) ++ { ++ construct_ctr_preload( ++ ctr_preload, ++ a4_exists, ++ qc_exists, ++ pframe, //message, ++ pn_vector, ++ i+1, ++ frtype); // add for CONFIG_IEEE80211W, none 11w also can use ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);//bitwise_xor(aes_out, &message[payload_index], chain_buffer); ++ for (j=0; j<16;j++) pframe[payload_index++] = chain_buffer[j];//for (j=0; j<16;j++) message[payload_index++] = chain_buffer[j]; ++ } ++ ++ if (payload_remainder > 0) /* If there is a short final block, then pad it,*/ ++ { /* encrypt it and copy the unpadded part back */ ++ construct_ctr_preload( ++ ctr_preload, ++ a4_exists, ++ qc_exists, ++ pframe, //message, ++ pn_vector, ++ num_blocks+1, ++ frtype); // add for CONFIG_IEEE80211W, none 11w also can use ++ ++ for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; ++ for (j = 0; j < payload_remainder; j++) ++ { ++ padded_buffer[j] = pframe[payload_index+j];//padded_buffer[j] = message[payload_index+j]; ++ } ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ for (j=0; jattrib; ++ struct security_priv *psecuritypriv=&padapter->securitypriv; ++ struct xmit_priv *pxmitpriv=&padapter->xmitpriv; ++ ++// uint offset = 0; ++ u32 res=_SUCCESS; ++_func_enter_; ++ ++ if(((struct xmit_frame*)pxmitframe)->buf_addr==NULL) ++ return _FAIL; ++ ++#ifdef CONFIG_USB_TX_AGGREGATION ++ hw_hdr_offset = TXDESC_SIZE + ++ (((struct xmit_frame*)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ); ++#else ++ #ifdef CONFIG_TX_EARLY_MODE ++ hw_hdr_offset = TXDESC_OFFSET+EARLY_MODE_INFO_SIZE; ++ #else ++ hw_hdr_offset = TXDESC_OFFSET; ++ #endif ++#endif ++ ++ pframe = ((struct xmit_frame*)pxmitframe)->buf_addr + hw_hdr_offset; ++ ++ //4 start to encrypt each fragment ++ if((pattrib->encrypt==_AES_)){ ++ ++ if(pattrib->psta) ++ { ++ stainfo = pattrib->psta; ++ } ++ else ++ { ++ DBG_871X("%s, call rtw_get_stainfo()\n", __func__); ++ stainfo=rtw_get_stainfo(&padapter->stapriv ,&pattrib->ra[0] ); ++ } ++ ++ if (stainfo!=NULL){ ++ ++ if(!(stainfo->state &_FW_LINKED)) ++ { ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, stainfo->state); ++ return _FAIL; ++ } ++ ++ RT_TRACE(_module_rtl871x_security_c_,_drv_err_,("rtw_aes_encrypt: stainfo!=NULL!!!\n")); ++ ++ if(IS_MCAST(pattrib->ra)) ++ { ++ prwskey=psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; ++ } ++ else ++ { ++ prwskey=&stainfo->dot118021x_UncstKey.skey[0]; ++ } ++ ++#ifdef CONFIG_TDLS //swencryption ++ { ++ struct sta_info *ptdls_sta; ++ ptdls_sta=rtw_get_stainfo(&padapter->stapriv ,&pattrib->dst[0] ); ++ if((ptdls_sta != NULL) && (ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE) ) ++ { ++ DBG_871X("[%s] for tdls link\n", __FUNCTION__); ++ prwskey=&ptdls_sta->tpk.tk[0]; ++ } ++ } ++#endif //CONFIG_TDLS ++ ++ prwskeylen=16; ++ ++ for(curfragnum=0;curfragnumnr_frags;curfragnum++){ ++ ++ if((curfragnum+1)==pattrib->nr_frags){ //4 the last fragment ++ length=pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len- pattrib->icv_len; ++ ++ aes_cipher(prwskey,pattrib->hdrlen,pframe, length); ++ } ++ else{ ++ length=pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len ; ++ ++ aes_cipher(prwskey,pattrib->hdrlen,pframe, length); ++ pframe+=pxmitpriv->frag_len; ++ pframe=(u8*)RND4((SIZE_PTR)(pframe)); ++ ++ } ++ } ++ ++ ++ } ++ else{ ++ RT_TRACE(_module_rtl871x_security_c_,_drv_err_,("rtw_aes_encrypt: stainfo==NULL!!!\n")); ++ DBG_871X("%s, psta==NUL\n", __func__); ++ res=_FAIL; ++ } ++ ++ } ++ ++ ++ ++_func_exit_; ++ return res; ++} ++ ++static sint aes_decipher(u8 *key, uint hdrlen, ++ u8 *pframe, uint plen) ++{ ++ static u8 message[MAX_MSG_SIZE]; ++ uint qc_exists, a4_exists, i, j, payload_remainder, ++ num_blocks, payload_index; ++ sint res = _SUCCESS; ++ u8 pn_vector[6]; ++ u8 mic_iv[16]; ++ u8 mic_header1[16]; ++ u8 mic_header2[16]; ++ u8 ctr_preload[16]; ++ ++ /* Intermediate Buffers */ ++ u8 chain_buffer[16]; ++ u8 aes_out[16]; ++ u8 padded_buffer[16]; ++ u8 mic[8]; ++ ++ ++// uint offset = 0; ++ uint frtype = GetFrameType(pframe); ++ uint frsubtype = GetFrameSubType(pframe); ++_func_enter_; ++ frsubtype=frsubtype>>4; ++ ++ ++ _rtw_memset((void *)mic_iv, 0, 16); ++ _rtw_memset((void *)mic_header1, 0, 16); ++ _rtw_memset((void *)mic_header2, 0, 16); ++ _rtw_memset((void *)ctr_preload, 0, 16); ++ _rtw_memset((void *)chain_buffer, 0, 16); ++ _rtw_memset((void *)aes_out, 0, 16); ++ _rtw_memset((void *)padded_buffer, 0, 16); ++ ++ //start to decrypt the payload ++ ++ num_blocks = (plen-8) / 16; //(plen including LLC, payload_length and mic ) ++ ++ payload_remainder = (plen-8) % 16; ++ ++ pn_vector[0] = pframe[hdrlen]; ++ pn_vector[1] = pframe[hdrlen+1]; ++ pn_vector[2] = pframe[hdrlen+4]; ++ pn_vector[3] = pframe[hdrlen+5]; ++ pn_vector[4] = pframe[hdrlen+6]; ++ pn_vector[5] = pframe[hdrlen+7]; ++ ++ if ((hdrlen == WLAN_HDR_A3_LEN )||(hdrlen == WLAN_HDR_A3_QOS_LEN)) ++ a4_exists = 0; ++ else ++ a4_exists = 1; ++ ++ if ( ++ ((frtype|frsubtype) == WIFI_DATA_CFACK) || ++ ((frtype|frsubtype) == WIFI_DATA_CFPOLL)|| ++ ((frtype|frsubtype) == WIFI_DATA_CFACKPOLL)) ++ { ++ qc_exists = 1; ++ if(hdrlen != WLAN_HDR_A3_QOS_LEN){ ++ ++ hdrlen += 2; ++ } ++ }//only for data packet . add for CONFIG_IEEE80211W, none 11w also can use ++ else if ((frtype == WIFI_DATA) && ++ ((frsubtype == 0x08) || ++ (frsubtype == 0x09)|| ++ (frsubtype == 0x0a)|| ++ (frsubtype == 0x0b))) ++ { ++ if(hdrlen != WLAN_HDR_A3_QOS_LEN){ ++ ++ hdrlen += 2; ++ } ++ qc_exists = 1; ++ } ++ else ++ qc_exists = 0; ++ ++ ++ // now, decrypt pframe with hdrlen offset and plen long ++ ++ payload_index = hdrlen + 8; // 8 is for extiv ++ ++ for (i=0; i< num_blocks; i++) ++ { ++ construct_ctr_preload( ++ ctr_preload, ++ a4_exists, ++ qc_exists, ++ pframe, ++ pn_vector, ++ i+1, ++ frtype ++ ); ++ ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); ++ ++ for (j=0; j<16;j++) pframe[payload_index++] = chain_buffer[j]; ++ } ++ ++ if (payload_remainder > 0) /* If there is a short final block, then pad it,*/ ++ { /* encrypt it and copy the unpadded part back */ ++ construct_ctr_preload( ++ ctr_preload, ++ a4_exists, ++ qc_exists, ++ pframe, ++ pn_vector, ++ num_blocks+1, ++ frtype // add for CONFIG_IEEE80211W, none 11w also can use ++ ); ++ ++ for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; ++ for (j = 0; j < payload_remainder; j++) ++ { ++ padded_buffer[j] = pframe[payload_index+j]; ++ } ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ for (j=0; j 0) ++ { ++ for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; ++ for (j = 0; j < payload_remainder; j++) ++ { ++ padded_buffer[j] = message[payload_index++]; ++ } ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ aes128k128d(key, chain_buffer, aes_out); ++ ++ } ++ ++ for (j = 0 ; j < 8; j++) mic[j] = aes_out[j]; ++ ++ /* Insert MIC into payload */ ++ for (j = 0; j < 8; j++) ++ message[payload_index+j] = mic[j]; ++ ++ payload_index = hdrlen + 8; ++ for (i=0; i< num_blocks; i++) ++ { ++ construct_ctr_preload( ++ ctr_preload, ++ a4_exists, ++ qc_exists, ++ message, ++ pn_vector, ++ i+1, ++ frtype); // add for CONFIG_IEEE80211W, none 11w also can use ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, &message[payload_index], chain_buffer); ++ for (j=0; j<16;j++) message[payload_index++] = chain_buffer[j]; ++ } ++ ++ if (payload_remainder > 0) /* If there is a short final block, then pad it,*/ ++ { /* encrypt it and copy the unpadded part back */ ++ construct_ctr_preload( ++ ctr_preload, ++ a4_exists, ++ qc_exists, ++ message, ++ pn_vector, ++ num_blocks+1, ++ frtype); // add for CONFIG_IEEE80211W, none 11w also can use ++ ++ for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; ++ for (j = 0; j < payload_remainder; j++) ++ { ++ padded_buffer[j] = message[payload_index+j]; ++ } ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ for (j=0; ju.hdr.attrib; ++ struct security_priv *psecuritypriv=&padapter->securitypriv; ++// struct recv_priv *precvpriv=&padapter->recvpriv; ++ u32 res=_SUCCESS; ++_func_enter_; ++ pframe=(unsigned char *)((union recv_frame*)precvframe)->u.hdr.rx_data; ++ //4 start to encrypt each fragment ++ if((prxattrib->encrypt==_AES_)){ ++ ++ stainfo=rtw_get_stainfo(&padapter->stapriv ,&prxattrib->ta[0] ); ++ if (stainfo!=NULL){ ++ RT_TRACE(_module_rtl871x_security_c_,_drv_err_,("rtw_aes_decrypt: stainfo!=NULL!!!\n")); ++ ++ if(IS_MCAST(prxattrib->ra)) ++ { ++ static u32 start = 0; ++ static u32 no_gkey_bc_cnt = 0; ++ static u32 no_gkey_mc_cnt = 0; ++ ++ //in concurrent we should use sw descrypt in group key, so we remove this message ++ //DBG_871X("rx bc/mc packets, to perform sw rtw_aes_decrypt\n"); ++ //prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; ++ if(psecuritypriv->binstallGrpkey==_FALSE) ++ { ++ res=_FAIL; ++ ++ if (start == 0) ++ start = rtw_get_current_time(); ++ ++ if (is_broadcast_mac_addr(prxattrib->ra)) ++ no_gkey_bc_cnt++; ++ else ++ no_gkey_mc_cnt++; ++ ++ if (rtw_get_passing_time_ms(start) > 1000) { ++ if (no_gkey_bc_cnt || no_gkey_mc_cnt) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", ++ FUNC_ADPT_ARG(padapter), no_gkey_bc_cnt, no_gkey_mc_cnt); ++ } ++ start = rtw_get_current_time(); ++ no_gkey_bc_cnt = 0; ++ no_gkey_mc_cnt = 0; ++ } ++ ++ goto exit; ++ } ++ ++ if (no_gkey_bc_cnt || no_gkey_mc_cnt) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" gkey installed. no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", ++ FUNC_ADPT_ARG(padapter), no_gkey_bc_cnt, no_gkey_mc_cnt); ++ } ++ start = 0; ++ no_gkey_bc_cnt = 0; ++ no_gkey_mc_cnt = 0; ++ ++ prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; ++ if(psecuritypriv->dot118021XGrpKeyid != prxattrib->key_index) ++ { ++ DBG_871X("not match packet_index=%d, install_index=%d \n" ++ , prxattrib->key_index, psecuritypriv->dot118021XGrpKeyid); ++ res=_FAIL; ++ goto exit; ++ } ++ } ++ else ++ { ++ prwskey=&stainfo->dot118021x_UncstKey.skey[0]; ++ } ++ ++ length= ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len; ++ /*// add for CONFIG_IEEE80211W, debug ++ if(0) ++ printk("@@@@@@@@@@@@@@@@@@ length=%d, prxattrib->hdrlen=%d, prxattrib->pkt_len=%d \n" ++ , length, prxattrib->hdrlen, prxattrib->pkt_len); ++ if(0) ++ { ++ int no; ++ //test print PSK ++ printk("PSK key below:\n"); ++ for(no=0;no<16;no++) ++ printk(" %02x ", prwskey[no]); ++ printk("\n"); ++ } ++ if(0) ++ { ++ int no; ++ //test print PSK ++ printk("frame:\n"); ++ for(no=0;nopkt_len;no++) ++ printk(" %02x ", pframe[no]); ++ printk("\n"); ++ }*/ ++ ++ res= aes_decipher(prwskey,prxattrib->hdrlen,pframe, length); ++ ++ ++ } ++ else{ ++ RT_TRACE(_module_rtl871x_security_c_,_drv_err_,("rtw_aes_encrypt: stainfo==NULL!!!\n")); ++ res=_FAIL; ++ } ++ ++ } ++_func_exit_; ++exit: ++ return res; ++} ++ ++#ifdef CONFIG_IEEE80211W ++u32 rtw_BIP_verify(_adapter *padapter, u8 *precvframe) ++{ ++ struct rx_pkt_attrib *pattrib = &((union recv_frame *)precvframe)->u.hdr.attrib; ++ u8 *pframe; ++ u8 *BIP_AAD, *p; ++ u32 res=_FAIL; ++ uint len, ori_len; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ u8 mic[16]; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ori_len = pattrib->pkt_len-WLAN_HDR_A3_LEN+BIP_AAD_SIZE; ++ BIP_AAD = rtw_zmalloc(ori_len); ++ ++ if(BIP_AAD == NULL) ++ { ++ DBG_871X("BIP AAD allocate fail\n"); ++ return _FAIL; ++ } ++ //PKT start ++ pframe=(unsigned char *)((union recv_frame*)precvframe)->u.hdr.rx_data; ++ //mapping to wlan header ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ //save the frame body + MME ++ _rtw_memcpy(BIP_AAD+BIP_AAD_SIZE, pframe+WLAN_HDR_A3_LEN, pattrib->pkt_len-WLAN_HDR_A3_LEN); ++ //find MME IE pointer ++ p = rtw_get_ie(BIP_AAD+BIP_AAD_SIZE, _MME_IE_, &len, pattrib->pkt_len-WLAN_HDR_A3_LEN); ++ //Baron ++ if(p) ++ { ++ u16 keyid=0; ++ u64 temp_ipn=0; ++ //save packet number ++ _rtw_memcpy(&temp_ipn, p+4, 6); ++ temp_ipn = le64_to_cpu(temp_ipn); ++ //BIP packet number should bigger than previous BIP packet ++ if(temp_ipn <= pmlmeext->mgnt_80211w_IPN_rx) ++ { ++ DBG_871X("replay BIP packet\n"); ++ goto BIP_exit; ++ } ++ //copy key index ++ _rtw_memcpy(&keyid, p+2, 2); ++ keyid = le16_to_cpu(keyid); ++ if(keyid != padapter->securitypriv.dot11wBIPKeyid) ++ { ++ DBG_871X("BIP key index error!\n"); ++ goto BIP_exit; ++ } ++ //clear the MIC field of MME to zero ++ _rtw_memset(p+2+len-8, 0, 8); ++ ++ //conscruct AAD, copy frame control field ++ _rtw_memcpy(BIP_AAD, &pwlanhdr->frame_ctl, 2); ++ ClearRetry(BIP_AAD); ++ ClearPwrMgt(BIP_AAD); ++ ClearMData(BIP_AAD); ++ //conscruct AAD, copy address 1 to address 3 ++ _rtw_memcpy(BIP_AAD+2, pwlanhdr->addr1, 18); ++ ++ if(omac1_aes_128(padapter->securitypriv.dot11wBIPKey[padapter->securitypriv.dot11wBIPKeyid].skey ++ , BIP_AAD, ori_len, mic)) ++ goto BIP_exit; ++ ++ /*//management packet content ++ { ++ int pp; ++ DBG_871X("pkt: "); ++ for(pp=0;pp< pattrib->pkt_len; pp++) ++ printk(" %02x ", pframe[pp]); ++ DBG_871X("\n"); ++ //BIP AAD + management frame body + MME(MIC is zero) ++ DBG_871X("AAD+PKT: "); ++ for(pp=0;pp< ori_len; pp++) ++ DBG_871X(" %02x ", BIP_AAD[pp]); ++ DBG_871X("\n"); ++ //show the MIC result ++ DBG_871X("mic: "); ++ for(pp=0;pp<16; pp++) ++ DBG_871X(" %02x ", mic[pp]); ++ DBG_871X("\n"); ++ } ++ */ ++ //MIC field should be last 8 bytes of packet (packet without FCS) ++ if(_rtw_memcmp(mic, pframe+pattrib->pkt_len-8, 8)) ++ { ++ pmlmeext->mgnt_80211w_IPN_rx = temp_ipn; ++ res=_SUCCESS; ++ } ++ else ++ DBG_871X("BIP MIC error!\n"); ++ ++ } ++ else ++ res = RTW_RX_HANDLED; ++BIP_exit: ++ ++ rtw_mfree(BIP_AAD, ori_len); ++ return res; ++} ++#endif //CONFIG_IEEE80211W ++ ++#ifndef PLATFORM_FREEBSD ++/* compress 512-bits */ ++static int sha256_compress(struct sha256_state *md, unsigned char *buf) ++{ ++ u32 S[8], W[64], t0, t1; ++ u32 t; ++ int i; ++ ++ /* copy state into S */ ++ for (i = 0; i < 8; i++) { ++ S[i] = md->state[i]; ++ } ++ ++ /* copy the state into 512-bits into W[0..15] */ ++ for (i = 0; i < 16; i++) ++ W[i] = WPA_GET_BE32(buf + (4 * i)); ++ ++ /* fill W[16..63] */ ++ for (i = 16; i < 64; i++) { ++ W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + ++ W[i - 16]; ++ } ++ ++ /* Compress */ ++#define RND(a,b,c,d,e,f,g,h,i) \ ++ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ ++ t1 = Sigma0(a) + Maj(a, b, c); \ ++ d += t0; \ ++ h = t0 + t1; ++ ++ for (i = 0; i < 64; ++i) { ++ RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i); ++ t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; ++ S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; ++ } ++ ++ /* feedback */ ++ for (i = 0; i < 8; i++) { ++ md->state[i] = md->state[i] + S[i]; ++ } ++ return 0; ++} ++ ++/* Initialize the hash state */ ++static void sha256_init(struct sha256_state *md) ++{ ++ md->curlen = 0; ++ md->length = 0; ++ md->state[0] = 0x6A09E667UL; ++ md->state[1] = 0xBB67AE85UL; ++ md->state[2] = 0x3C6EF372UL; ++ md->state[3] = 0xA54FF53AUL; ++ md->state[4] = 0x510E527FUL; ++ md->state[5] = 0x9B05688CUL; ++ md->state[6] = 0x1F83D9ABUL; ++ md->state[7] = 0x5BE0CD19UL; ++} ++ ++/** ++ Process a block of memory though the hash ++ @param md The hash state ++ @param in The data to hash ++ @param inlen The length of the data (octets) ++ @return CRYPT_OK if successful ++*/ ++static int sha256_process(struct sha256_state *md, unsigned char *in, ++ unsigned long inlen) ++{ ++ unsigned long n; ++#define block_size 64 ++ ++ if (md->curlen > sizeof(md->buf)) ++ return -1; ++ ++ while (inlen > 0) { ++ if (md->curlen == 0 && inlen >= block_size) { ++ if (sha256_compress(md, (unsigned char *) in) < 0) ++ return -1; ++ md->length += block_size * 8; ++ in += block_size; ++ inlen -= block_size; ++ } else { ++ n = MIN(inlen, (block_size - md->curlen)); ++ _rtw_memcpy(md->buf + md->curlen, in, n); ++ md->curlen += n; ++ in += n; ++ inlen -= n; ++ if (md->curlen == block_size) { ++ if (sha256_compress(md, md->buf) < 0) ++ return -1; ++ md->length += 8 * block_size; ++ md->curlen = 0; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++ ++/** ++ Terminate the hash to get the digest ++ @param md The hash state ++ @param out [out] The destination of the hash (32 bytes) ++ @return CRYPT_OK if successful ++*/ ++static int sha256_done(struct sha256_state *md, unsigned char *out) ++{ ++ int i; ++ ++ if (md->curlen >= sizeof(md->buf)) ++ return -1; ++ ++ /* increase the length of the message */ ++ md->length += md->curlen * 8; ++ ++ /* append the '1' bit */ ++ md->buf[md->curlen++] = (unsigned char) 0x80; ++ ++ /* if the length is currently above 56 bytes we append zeros ++ * then compress. Then we can fall back to padding zeros and length ++ * encoding like normal. ++ */ ++ if (md->curlen > 56) { ++ while (md->curlen < 64) { ++ md->buf[md->curlen++] = (unsigned char) 0; ++ } ++ sha256_compress(md, md->buf); ++ md->curlen = 0; ++ } ++ ++ /* pad upto 56 bytes of zeroes */ ++ while (md->curlen < 56) { ++ md->buf[md->curlen++] = (unsigned char) 0; ++ } ++ ++ /* store length */ ++ WPA_PUT_BE64(md->buf + 56, md->length); ++ sha256_compress(md, md->buf); ++ ++ /* copy output */ ++ for (i = 0; i < 8; i++) ++ WPA_PUT_BE32(out + (4 * i), md->state[i]); ++ ++ return 0; ++} ++ ++/** ++ * sha256_vector - SHA256 hash for data vector ++ * @num_elem: Number of elements in the data vector ++ * @addr: Pointers to the data areas ++ * @len: Lengths of the data blocks ++ * @mac: Buffer for the hash ++ * Returns: 0 on success, -1 of failure ++ */ ++static int sha256_vector(size_t num_elem, u8 *addr[], size_t *len, ++ u8 *mac) ++{ ++ struct sha256_state ctx; ++ size_t i; ++ ++ sha256_init(&ctx); ++ for (i = 0; i < num_elem; i++) ++ if (sha256_process(&ctx, addr[i], len[i])) ++ return -1; ++ if (sha256_done(&ctx, mac)) ++ return -1; ++ return 0; ++} ++ ++static u8 os_strlen(const char *s) ++{ ++ const char *p = s; ++ while (*p) ++ p++; ++ return p - s; ++} ++ ++static int os_memcmp(void *s1, void *s2, u8 n) ++{ ++ unsigned char *p1 = s1, *p2 = s2; ++ ++ if (n == 0) ++ return 0; ++ ++ while (*p1 == *p2) { ++ p1++; ++ p2++; ++ n--; ++ if (n == 0) ++ return 0; ++ } ++ ++ return *p1 - *p2; ++} ++ ++/** ++ * hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104) ++ * @key: Key for HMAC operations ++ * @key_len: Length of the key in bytes ++ * @num_elem: Number of elements in the data vector ++ * @addr: Pointers to the data areas ++ * @len: Lengths of the data blocks ++ * @mac: Buffer for the hash (32 bytes) ++ */ ++static void hmac_sha256_vector(u8 *key, size_t key_len, size_t num_elem, ++ u8 *addr[], size_t *len, u8 *mac) ++{ ++ unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ ++ unsigned char tk[32]; ++ u8 *_addr[6]; ++ size_t _len[6], i; ++ ++ if (num_elem > 5) { ++ /* ++ * Fixed limit on the number of fragments to avoid having to ++ * allocate memory (which could fail). ++ */ ++ return; ++ } ++ ++ /* if key is longer than 64 bytes reset it to key = SHA256(key) */ ++ if (key_len > 64) { ++ sha256_vector(1, &key, &key_len, tk); ++ key = tk; ++ key_len = 32; ++ } ++ ++ /* the HMAC_SHA256 transform looks like: ++ * ++ * SHA256(K XOR opad, SHA256(K XOR ipad, text)) ++ * ++ * where K is an n byte key ++ * ipad is the byte 0x36 repeated 64 times ++ * opad is the byte 0x5c repeated 64 times ++ * and text is the data being protected */ ++ ++ /* start out by storing key in ipad */ ++ _rtw_memset(k_pad, 0, sizeof(k_pad)); ++ _rtw_memcpy(k_pad, key, key_len); ++ /* XOR key with ipad values */ ++ for (i = 0; i < 64; i++) ++ k_pad[i] ^= 0x36; ++ ++ /* perform inner SHA256 */ ++ _addr[0] = k_pad; ++ _len[0] = 64; ++ for (i = 0; i < num_elem; i++) { ++ _addr[i + 1] = addr[i]; ++ _len[i + 1] = len[i]; ++ } ++ sha256_vector(1 + num_elem, _addr, _len, mac); ++ ++ _rtw_memset(k_pad, 0, sizeof(k_pad)); ++ _rtw_memcpy(k_pad, key, key_len); ++ /* XOR key with opad values */ ++ for (i = 0; i < 64; i++) ++ k_pad[i] ^= 0x5c; ++ ++ /* perform outer SHA256 */ ++ _addr[0] = k_pad; ++ _len[0] = 64; ++ _addr[1] = mac; ++ _len[1] = 32; ++ sha256_vector(2, _addr, _len, mac); ++} ++#endif //PLATFORM_FREEBSD ++/** ++ * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2) ++ * @key: Key for PRF ++ * @key_len: Length of the key in bytes ++ * @label: A unique label for each purpose of the PRF ++ * @data: Extra data to bind into the key ++ * @data_len: Length of the data ++ * @buf: Buffer for the generated pseudo-random key ++ * @buf_len: Number of bytes of key to generate ++ * ++ * This function is used to derive new, cryptographically separate keys from a ++ * given key. ++ */ ++#ifndef PLATFORM_FREEBSD //Baron ++static void sha256_prf(u8 *key, size_t key_len, char *label, ++ u8 *data, size_t data_len, u8 *buf, size_t buf_len) ++{ ++ u16 counter = 1; ++ size_t pos, plen; ++ u8 hash[SHA256_MAC_LEN]; ++ u8 *addr[4]; ++ size_t len[4]; ++ u8 counter_le[2], length_le[2]; ++ ++ addr[0] = counter_le; ++ len[0] = 2; ++ addr[1] = (u8 *) label; ++ len[1] = os_strlen(label); ++ addr[2] = data; ++ len[2] = data_len; ++ addr[3] = length_le; ++ len[3] = sizeof(length_le); ++ ++ WPA_PUT_LE16(length_le, buf_len * 8); ++ pos = 0; ++ while (pos < buf_len) { ++ plen = buf_len - pos; ++ WPA_PUT_LE16(counter_le, counter); ++ if (plen >= SHA256_MAC_LEN) { ++ hmac_sha256_vector(key, key_len, 4, addr, len, ++ &buf[pos]); ++ pos += SHA256_MAC_LEN; ++ } else { ++ hmac_sha256_vector(key, key_len, 4, addr, len, hash); ++ _rtw_memcpy(&buf[pos], hash, plen); ++ break; ++ } ++ counter++; ++ } ++} ++#endif //PLATFORM_FREEBSD Baron ++ ++/* AES tables*/ ++const u32 Te0[256] = { ++ 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, ++ 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, ++ 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, ++ 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, ++ 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, ++ 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, ++ 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, ++ 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, ++ 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, ++ 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, ++ 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, ++ 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, ++ 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, ++ 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, ++ 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, ++ 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, ++ 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, ++ 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, ++ 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, ++ 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, ++ 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, ++ 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, ++ 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, ++ 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, ++ 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, ++ 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, ++ 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, ++ 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, ++ 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, ++ 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, ++ 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, ++ 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, ++ 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, ++ 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, ++ 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, ++ 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, ++ 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, ++ 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, ++ 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, ++ 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, ++ 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, ++ 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, ++ 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, ++ 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, ++ 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, ++ 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, ++ 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, ++ 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, ++ 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, ++ 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, ++ 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, ++ 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, ++ 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, ++ 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, ++ 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, ++ 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, ++ 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, ++ 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, ++ 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, ++ 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, ++ 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, ++ 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, ++ 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, ++ 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, ++}; ++const u32 Td0[256] = { ++ 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, ++ 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, ++ 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, ++ 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, ++ 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, ++ 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, ++ 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, ++ 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, ++ 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, ++ 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, ++ 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, ++ 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, ++ 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, ++ 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, ++ 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, ++ 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, ++ 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, ++ 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, ++ 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, ++ 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, ++ 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, ++ 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, ++ 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, ++ 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, ++ 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, ++ 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, ++ 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, ++ 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, ++ 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, ++ 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, ++ 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, ++ 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, ++ 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, ++ 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, ++ 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, ++ 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, ++ 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, ++ 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, ++ 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, ++ 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, ++ 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, ++ 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, ++ 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, ++ 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, ++ 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, ++ 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, ++ 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, ++ 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, ++ 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, ++ 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, ++ 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, ++ 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, ++ 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, ++ 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, ++ 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, ++ 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, ++ 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, ++ 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, ++ 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, ++ 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, ++ 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, ++ 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, ++ 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, ++ 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, ++}; ++const u8 Td4s[256] = { ++ 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, ++ 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, ++ 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, ++ 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, ++ 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, ++ 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, ++ 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, ++ 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, ++ 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, ++ 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, ++ 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, ++ 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, ++ 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, ++ 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, ++ 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, ++ 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, ++ 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, ++ 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, ++ 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, ++ 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, ++ 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, ++ 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, ++ 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, ++ 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, ++ 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, ++ 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, ++ 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, ++ 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, ++ 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, ++ 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, ++ 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, ++ 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, ++}; ++const u8 rcons[] = { ++ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 ++ /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ ++}; ++ ++/** ++ * Expand the cipher key into the encryption key schedule. ++ * ++ * @return the number of rounds for the given cipher key size. ++ */ ++#ifndef PLATFORM_FREEBSD //Baron ++static void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[]) ++{ ++ int i; ++ u32 temp; ++ ++ rk[0] = GETU32(cipherKey ); ++ rk[1] = GETU32(cipherKey + 4); ++ rk[2] = GETU32(cipherKey + 8); ++ rk[3] = GETU32(cipherKey + 12); ++ for (i = 0; i < 10; i++) { ++ temp = rk[3]; ++ rk[4] = rk[0] ^ ++ TE421(temp) ^ TE432(temp) ^ TE443(temp) ^ TE414(temp) ^ ++ RCON(i); ++ rk[5] = rk[1] ^ rk[4]; ++ rk[6] = rk[2] ^ rk[5]; ++ rk[7] = rk[3] ^ rk[6]; ++ rk += 4; ++ } ++} ++ ++static void rijndaelEncrypt(u32 rk[/*44*/], u8 pt[16], u8 ct[16]) ++{ ++ u32 s0, s1, s2, s3, t0, t1, t2, t3; ++ int Nr = 10; ++#ifndef FULL_UNROLL ++ int r; ++#endif /* ?FULL_UNROLL */ ++ ++ /* ++ * map byte array block to cipher state ++ * and add initial round key: ++ */ ++ s0 = GETU32(pt ) ^ rk[0]; ++ s1 = GETU32(pt + 4) ^ rk[1]; ++ s2 = GETU32(pt + 8) ^ rk[2]; ++ s3 = GETU32(pt + 12) ^ rk[3]; ++ ++#define ROUND(i,d,s) \ ++d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \ ++d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \ ++d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \ ++d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3] ++ ++#ifdef FULL_UNROLL ++ ++ ROUND(1,t,s); ++ ROUND(2,s,t); ++ ROUND(3,t,s); ++ ROUND(4,s,t); ++ ROUND(5,t,s); ++ ROUND(6,s,t); ++ ROUND(7,t,s); ++ ROUND(8,s,t); ++ ROUND(9,t,s); ++ ++ rk += Nr << 2; ++ ++#else /* !FULL_UNROLL */ ++ ++ /* Nr - 1 full rounds: */ ++ r = Nr >> 1; ++ for (;;) { ++ ROUND(1,t,s); ++ rk += 8; ++ if (--r == 0) ++ break; ++ ROUND(0,s,t); ++ } ++ ++#endif /* ?FULL_UNROLL */ ++ ++#undef ROUND ++ ++ /* ++ * apply last round and ++ * map cipher state to byte array block: ++ */ ++ s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0]; ++ PUTU32(ct , s0); ++ s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1]; ++ PUTU32(ct + 4, s1); ++ s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2]; ++ PUTU32(ct + 8, s2); ++ s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3]; ++ PUTU32(ct + 12, s3); ++} ++ ++static void * aes_encrypt_init(u8 *key, size_t len) ++{ ++ u32 *rk; ++ if (len != 16) ++ return NULL; ++ rk = (u32*)rtw_malloc(AES_PRIV_SIZE); ++ if (rk == NULL) ++ return NULL; ++ rijndaelKeySetupEnc(rk, key); ++ return rk; ++} ++ ++static void aes_128_encrypt(void *ctx, u8 *plain, u8 *crypt) ++{ ++ rijndaelEncrypt(ctx, plain, crypt); ++} ++ ++ ++static void gf_mulx(u8 *pad) ++{ ++ int i, carry; ++ ++ carry = pad[0] & 0x80; ++ for (i = 0; i < AES_BLOCK_SIZE - 1; i++) ++ pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7); ++ pad[AES_BLOCK_SIZE - 1] <<= 1; ++ if (carry) ++ pad[AES_BLOCK_SIZE - 1] ^= 0x87; ++} ++ ++static void aes_encrypt_deinit(void *ctx) ++{ ++ _rtw_memset(ctx, 0, AES_PRIV_SIZE); ++ rtw_mfree(ctx, AES_PRIV_SIZE); ++} ++ ++ ++/** ++ * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128 ++ * @key: 128-bit key for the hash operation ++ * @num_elem: Number of elements in the data vector ++ * @addr: Pointers to the data areas ++ * @len: Lengths of the data blocks ++ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) ++ * Returns: 0 on success, -1 on failure ++ * ++ * This is a mode for using block cipher (AES in this case) for authentication. ++ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication ++ * (SP) 800-38B. ++ */ ++static int omac1_aes_128_vector(u8 *key, size_t num_elem, ++ u8 *addr[], size_t *len, u8 *mac) ++{ ++ void *ctx; ++ u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; ++ u8 *pos, *end; ++ size_t i, e, left, total_len; ++ ++ ctx = aes_encrypt_init(key, 16); ++ if (ctx == NULL) ++ return -1; ++ _rtw_memset(cbc, 0, AES_BLOCK_SIZE); ++ ++ total_len = 0; ++ for (e = 0; e < num_elem; e++) ++ total_len += len[e]; ++ left = total_len; ++ ++ e = 0; ++ pos = addr[0]; ++ end = pos + len[0]; ++ ++ while (left >= AES_BLOCK_SIZE) { ++ for (i = 0; i < AES_BLOCK_SIZE; i++) { ++ cbc[i] ^= *pos++; ++ if (pos >= end) { ++ e++; ++ pos = addr[e]; ++ end = pos + len[e]; ++ } ++ } ++ if (left > AES_BLOCK_SIZE) ++ aes_128_encrypt(ctx, cbc, cbc); ++ left -= AES_BLOCK_SIZE; ++ } ++ ++ _rtw_memset(pad, 0, AES_BLOCK_SIZE); ++ aes_128_encrypt(ctx, pad, pad); ++ gf_mulx(pad); ++ ++ if (left || total_len == 0) { ++ for (i = 0; i < left; i++) { ++ cbc[i] ^= *pos++; ++ if (pos >= end) { ++ e++; ++ pos = addr[e]; ++ end = pos + len[e]; ++ } ++ } ++ cbc[left] ^= 0x80; ++ gf_mulx(pad); ++ } ++ ++ for (i = 0; i < AES_BLOCK_SIZE; i++) ++ pad[i] ^= cbc[i]; ++ aes_128_encrypt(ctx, pad, mac); ++ aes_encrypt_deinit(ctx); ++ return 0; ++} ++ ++ ++/** ++ * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC) ++ * @key: 128-bit key for the hash operation ++ * @data: Data buffer for which a MAC is determined ++ * @data_len: Length of data buffer in bytes ++ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) ++ * Returns: 0 on success, -1 on failure ++ * ++ * This is a mode for using block cipher (AES in this case) for authentication. ++ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication ++ * (SP) 800-38B. ++ */ //modify for CONFIG_IEEE80211W ++int omac1_aes_128(u8 *key, u8 *data, size_t data_len, u8 *mac) ++{ ++ return omac1_aes_128_vector(key, 1, &data, &data_len, mac); ++} ++#endif //PLATFORM_FREEBSD Baron ++ ++#ifdef CONFIG_TDLS ++void wpa_tdls_generate_tpk(_adapter *padapter, struct sta_info *psta) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 *SNonce = psta->SNonce; ++ u8 *ANonce = psta->ANonce; ++ ++ u8 key_input[SHA256_MAC_LEN]; ++ u8 *nonce[2]; ++ size_t len[2]; ++ u8 data[3 * ETH_ALEN]; ++ ++ /* IEEE Std 802.11z-2010 8.5.9.1: ++ * TPK-Key-Input = SHA-256(min(SNonce, ANonce) || max(SNonce, ANonce)) ++ */ ++ len[0] = 32; ++ len[1] = 32; ++ if (os_memcmp(SNonce, ANonce, 32) < 0) { ++ nonce[0] = SNonce; ++ nonce[1] = ANonce; ++ } else { ++ nonce[0] = ANonce; ++ nonce[1] = SNonce; ++ } ++ ++ sha256_vector(2, nonce, len, key_input); ++ ++ /* ++ * TPK-Key-Data = KDF-N_KEY(TPK-Key-Input, "TDLS PMK", ++ * min(MAC_I, MAC_R) || max(MAC_I, MAC_R) || BSSID || N_KEY) ++ * TODO: is N_KEY really included in KDF Context and if so, in which ++ * presentation format (little endian 16-bit?) is it used? It gets ++ * added by the KDF anyway.. ++ */ ++ ++ if (os_memcmp(myid(&(padapter->eeprompriv)), psta->hwaddr, ETH_ALEN) < 0) { ++ _rtw_memcpy(data, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(data + ETH_ALEN, psta->hwaddr, ETH_ALEN); ++ } else { ++ _rtw_memcpy(data, psta->hwaddr, ETH_ALEN); ++ _rtw_memcpy(data + ETH_ALEN, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ } ++ _rtw_memcpy(data + 2 * ETH_ALEN, get_bssid(pmlmepriv), ETH_ALEN); ++ ++ sha256_prf(key_input, SHA256_MAC_LEN, "TDLS PMK", data, sizeof(data), (u8 *) &psta->tpk, sizeof(psta->tpk)); ++ ++ ++} ++ ++/** ++ * wpa_tdls_ftie_mic - Calculate TDLS FTIE MIC ++ * @kck: TPK-KCK ++ * @lnkid: Pointer to the beginning of Link Identifier IE ++ * @rsnie: Pointer to the beginning of RSN IE used for handshake ++ * @timeoutie: Pointer to the beginning of Timeout IE used for handshake ++ * @ftie: Pointer to the beginning of FT IE ++ * @mic: Pointer for writing MIC ++ * ++ * Calculate MIC for TDLS frame. ++ */ ++int wpa_tdls_ftie_mic(u8 *kck, u8 trans_seq, ++ u8 *lnkid, u8 *rsnie, u8 *timeoutie, u8 *ftie, ++ u8 *mic) ++{ ++ u8 *buf, *pos; ++ struct wpa_tdls_ftie *_ftie; ++ struct wpa_tdls_lnkid *_lnkid; ++ int ret; ++ int len = 2 * ETH_ALEN + 1 + 2 + lnkid[1] + 2 + rsnie[1] + ++ 2 + timeoutie[1] + 2 + ftie[1]; ++ buf = rtw_zmalloc(len); ++ if (!buf) { ++ DBG_871X("TDLS: No memory for MIC calculation\n"); ++ return -1; ++ } ++ ++ pos = buf; ++ _lnkid = (struct wpa_tdls_lnkid *) lnkid; ++ /* 1) TDLS initiator STA MAC address */ ++ _rtw_memcpy(pos, _lnkid->init_sta, ETH_ALEN); ++ pos += ETH_ALEN; ++ /* 2) TDLS responder STA MAC address */ ++ _rtw_memcpy(pos, _lnkid->resp_sta, ETH_ALEN); ++ pos += ETH_ALEN; ++ /* 3) Transaction Sequence number */ ++ *pos++ = trans_seq; ++ /* 4) Link Identifier IE */ ++ _rtw_memcpy(pos, lnkid, 2 + lnkid[1]); ++ pos += 2 + lnkid[1]; ++ /* 5) RSN IE */ ++ _rtw_memcpy(pos, rsnie, 2 + rsnie[1]); ++ pos += 2 + rsnie[1]; ++ /* 6) Timeout Interval IE */ ++ _rtw_memcpy(pos, timeoutie, 2 + timeoutie[1]); ++ pos += 2 + timeoutie[1]; ++ /* 7) FTIE, with the MIC field of the FTIE set to 0 */ ++ _rtw_memcpy(pos, ftie, 2 + ftie[1]); ++ _ftie = (struct wpa_tdls_ftie *) pos; ++ _rtw_memset(_ftie->mic, 0, TDLS_MIC_LEN); ++ pos += 2 + ftie[1]; ++ ++ ret = omac1_aes_128(kck, buf, pos - buf, mic); ++ rtw_mfree(buf, len); ++ return ret; ++ ++} ++ ++int tdls_verify_mic(u8 *kck, u8 trans_seq, ++ u8 *lnkid, u8 *rsnie, u8 *timeoutie, u8 *ftie) ++{ ++ u8 *buf, *pos; ++ int len; ++ u8 mic[16]; ++ int ret; ++ u8 *rx_ftie, *tmp_ftie; ++ ++ if (lnkid == NULL || rsnie == NULL || ++ timeoutie == NULL || ftie == NULL){ ++ return 0; ++ } ++ ++ len = 2 * ETH_ALEN + 1 + 2 + 18 + 2 + *(rsnie+1) + 2 + *(timeoutie+1) + 2 + *(ftie+1); ++ ++ buf = rtw_zmalloc(len); ++ if (buf == NULL) ++ return 0; ++ ++ pos = buf; ++ /* 1) TDLS initiator STA MAC address */ ++ _rtw_memcpy(pos, lnkid + ETH_ALEN + 2, ETH_ALEN); ++ pos += ETH_ALEN; ++ /* 2) TDLS responder STA MAC address */ ++ _rtw_memcpy(pos, lnkid + 2 * ETH_ALEN + 2, ETH_ALEN); ++ pos += ETH_ALEN; ++ /* 3) Transaction Sequence number */ ++ *pos++ = trans_seq; ++ /* 4) Link Identifier IE */ ++ _rtw_memcpy(pos, lnkid, 2 + 18); ++ pos += 2 + 18; ++ /* 5) RSN IE */ ++ _rtw_memcpy(pos, rsnie, 2 + *(rsnie+1)); ++ pos += 2 + *(rsnie+1); ++ /* 6) Timeout Interval IE */ ++ _rtw_memcpy(pos, timeoutie, 2 + *(timeoutie+1)); ++ pos += 2 + *(timeoutie+1); ++ /* 7) FTIE, with the MIC field of the FTIE set to 0 */ ++ _rtw_memcpy(pos, ftie, 2 + *(ftie+1)); ++ pos += 2; ++ tmp_ftie = (u8 *) (pos+2); ++ _rtw_memset(tmp_ftie, 0, 16); ++ pos += *(ftie+1); ++ ++ ret = omac1_aes_128(kck, buf, pos - buf, mic); ++ rtw_mfree(buf, len); ++ if (ret) ++ return 0; ++ rx_ftie = ftie+4; ++ ++ if (os_memcmp(mic, rx_ftie, 16) == 0) { ++ //Valid MIC ++ return 1; ++ } ++ ++ //Invalid MIC ++ DBG_871X( "[%s] Invalid MIC\n", __FUNCTION__); ++ return 0; ++ ++} ++#endif //CONFIG_TDLS ++ ++#ifdef PLATFORM_WINDOWS ++void rtw_use_tkipkey_handler ( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3 ++ ) ++#endif ++#ifdef PLATFORM_LINUX ++void rtw_use_tkipkey_handler(void *FunctionContext) ++#endif ++#ifdef PLATFORM_FREEBSD ++void rtw_use_tkipkey_handler(void *FunctionContext) ++#endif ++{ ++ _adapter *padapter = (_adapter *)FunctionContext; ++ ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_security_c_,_drv_err_,("^^^rtw_use_tkipkey_handler ^^^\n")); ++ ++/* ++ if(padapter->bDriverStopped ||padapter->bSurpriseRemoved){ ++ RT_TRACE(_module_rtl871x_security_c_,_drv_err_,("^^^rtw_use_tkipkey_handler (padapter->bDriverStopped %d)(padapter->bSurpriseRemoved %d)^^^\n",padapter->bDriverStopped,padapter->bSurpriseRemoved)); ++ ++ return; ++ } ++ */ ++ ++ padapter->securitypriv.busetkipkey=_TRUE; ++ ++ RT_TRACE(_module_rtl871x_security_c_,_drv_err_,("^^^rtw_use_tkipkey_handler padapter->securitypriv.busetkipkey=%d^^^\n",padapter->securitypriv.busetkipkey)); ++ ++_func_exit_; ++ ++} ++ ++/* Restore HW wep key setting according to key_mask */ ++void rtw_sec_restore_wep_key(_adapter *adapter) ++{ ++ struct security_priv* securitypriv=&(adapter->securitypriv); ++ sint keyid; ++ ++ if((_WEP40_ == securitypriv->dot11PrivacyAlgrthm) ||(_WEP104_ == securitypriv->dot11PrivacyAlgrthm)) { ++ for(keyid=0;keyid<4;keyid++){ ++ if(securitypriv->key_mask & BIT(keyid)){ ++ if(keyid == securitypriv->dot11PrivacyKeyIndex) ++ rtw_set_key(adapter,securitypriv, keyid, 1, _TRUE); ++ else ++ rtw_set_key(adapter,securitypriv, keyid, 0, _TRUE); ++ } ++ } ++ } ++} ++ ++u8 rtw_handle_tkip_countermeasure(_adapter* adapter, const char *caller) ++{ ++ struct security_priv* securitypriv=&(adapter->securitypriv); ++ u8 status = _SUCCESS; ++ ++ if (securitypriv->btkip_countermeasure == _TRUE) { ++ u32 passing_ms = rtw_get_passing_time_ms(securitypriv->btkip_countermeasure_time); ++ if (passing_ms > 60*1000) { ++ DBG_871X_LEVEL(_drv_always_, "%s("ADPT_FMT") countermeasure time:%ds > 60s \n", ++ caller, ADPT_ARG(adapter), passing_ms/1000); ++ securitypriv->btkip_countermeasure = _FALSE; ++ securitypriv->btkip_countermeasure_time = 0; ++ } else { ++ DBG_871X_LEVEL(_drv_always_, "%s("ADPT_FMT") countermeasure time:%ds < 60s \n", ++ caller, ADPT_ARG(adapter), passing_ms/1000); ++ status = _FAIL; ++ } ++ } ++ ++ return status; ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_sreset.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_sreset.c +new file mode 100644 +index 00000000..bc34827b +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_sreset.c +@@ -0,0 +1,356 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#include ++ ++void sreset_init_value(_adapter *padapter) ++{ ++#if defined(DBG_CONFIG_ERROR_DETECT) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct sreset_priv *psrtpriv = &pHalData->srestpriv; ++ ++ _rtw_mutex_init(&psrtpriv->silentreset_mutex); ++ psrtpriv->silent_reset_inprogress = _FALSE; ++ psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS; ++ psrtpriv->last_tx_time =0; ++ psrtpriv->last_tx_complete_time =0; ++#endif ++} ++void sreset_reset_value(_adapter *padapter) ++{ ++#if defined(DBG_CONFIG_ERROR_DETECT) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct sreset_priv *psrtpriv = &pHalData->srestpriv; ++ ++ //psrtpriv->silent_reset_inprogress = _FALSE; ++ psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS; ++ psrtpriv->last_tx_time =0; ++ psrtpriv->last_tx_complete_time =0; ++#endif ++} ++ ++u8 sreset_get_wifi_status(_adapter *padapter) ++{ ++#if defined(DBG_CONFIG_ERROR_DETECT) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct sreset_priv *psrtpriv = &pHalData->srestpriv; ++ ++ u8 status = WIFI_STATUS_SUCCESS; ++ u32 val32 = 0; ++ _irqL irqL; ++ if(psrtpriv->silent_reset_inprogress == _TRUE) ++ { ++ return status; ++ } ++ val32 =rtw_read32(padapter,REG_TXDMA_STATUS); ++ if(val32==0xeaeaeaea){ ++ psrtpriv->Wifi_Error_Status = WIFI_IF_NOT_EXIST; ++ } ++ else if(val32!=0){ ++ DBG_8192C("txdmastatu(%x)\n",val32); ++ psrtpriv->Wifi_Error_Status = WIFI_MAC_TXDMA_ERROR; ++ } ++ ++ if(WIFI_STATUS_SUCCESS !=psrtpriv->Wifi_Error_Status) ++ { ++ DBG_8192C("==>%s error_status(0x%x) \n",__FUNCTION__,psrtpriv->Wifi_Error_Status); ++ status = (psrtpriv->Wifi_Error_Status &( ~(USB_READ_PORT_FAIL|USB_WRITE_PORT_FAIL))); ++ } ++ DBG_8192C("==> %s wifi_status(0x%x)\n",__FUNCTION__,status); ++ ++ //status restore ++ psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS; ++ ++ return status; ++#else ++ return WIFI_STATUS_SUCCESS; ++#endif ++} ++ ++void sreset_set_wifi_error_status(_adapter *padapter, u32 status) ++{ ++#if defined(DBG_CONFIG_ERROR_DETECT) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ pHalData->srestpriv.Wifi_Error_Status = status; ++#endif ++} ++ ++void sreset_set_trigger_point(_adapter *padapter, s32 tgp) ++{ ++#if defined(DBG_CONFIG_ERROR_DETECT) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ pHalData->srestpriv.dbg_trigger_point = tgp; ++#endif ++} ++ ++bool sreset_inprogress(_adapter *padapter) ++{ ++#if defined(DBG_CONFIG_ERROR_RESET) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ return pHalData->srestpriv.silent_reset_inprogress; ++#else ++ return _FALSE; ++#endif ++} ++ ++void sreset_restore_security_station(_adapter *padapter) ++{ ++ u8 EntryId = 0; ++ struct mlme_priv *mlmepriv = &padapter->mlmepriv; ++ struct sta_priv * pstapriv = &padapter->stapriv; ++ struct sta_info *psta; ++ struct security_priv* psecuritypriv=&(padapter->securitypriv); ++ struct mlme_ext_info *pmlmeinfo = &padapter->mlmeextpriv.mlmext_info; ++ ++ { ++ u8 val8; ++ ++ if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X) { ++ val8 = 0xcc; ++ #ifdef CONFIG_WAPI_SUPPORT ++ } else if (padapter->wapiInfo.bWapiEnable && pmlmeinfo->auth_algo == dot11AuthAlgrthm_WAPI) { ++ //Disable TxUseDefaultKey, RxUseDefaultKey, RxBroadcastUseDefaultKey. ++ val8 = 0x4c; ++ #endif ++ } else { ++ val8 = 0xcf; ++ } ++ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); ++ } ++ ++ #if 0 ++ if ( ( padapter->securitypriv.dot11PrivacyAlgrthm == _WEP40_ ) || ++ ( padapter->securitypriv.dot11PrivacyAlgrthm == _WEP104_ )) ++ { ++ ++ for(EntryId=0; EntryId<4; EntryId++) ++ { ++ if(EntryId == psecuritypriv->dot11PrivacyKeyIndex) ++ rtw_set_key(padapter,&padapter->securitypriv, EntryId, 1,_FALSE); ++ else ++ rtw_set_key(padapter,&padapter->securitypriv, EntryId, 0,_FALSE); ++ } ++ ++ } ++ else ++ #endif ++ if((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) || ++ (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) ++ { ++ psta = rtw_get_stainfo(pstapriv, get_bssid(mlmepriv)); ++ if (psta == NULL) { ++ //DEBUG_ERR( ("Set wpa_set_encryption: Obtain Sta_info fail \n")); ++ } ++ else ++ { ++ //pairwise key ++ rtw_setstakey_cmd(padapter, (unsigned char *)psta, _TRUE,_FALSE); ++ //group key ++ rtw_set_key(padapter,&padapter->securitypriv,padapter->securitypriv.dot118021XGrpKeyid, 0,_FALSE); ++ } ++ } ++} ++ ++void sreset_restore_network_station(_adapter *padapter) ++{ ++ struct mlme_priv *mlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ #if 0 ++ { ++ //======================================================= ++ // reset related register of Beacon control ++ ++ //set MSR to nolink ++ Set_MSR(padapter, _HW_STATE_NOLINK_); ++ // reject all data frame ++ rtw_write16(padapter, REG_RXFLTMAP2,0x00); ++ //reset TSF ++ rtw_write8(padapter, REG_DUAL_TSF_RST, (BIT(0)|BIT(1))); ++ ++ // disable update TSF ++ SetBcnCtrlReg(padapter, BIT(4), 0); ++ ++ //======================================================= ++ } ++ #endif ++ ++ rtw_setopmode_cmd(padapter, Ndis802_11Infrastructure,_FALSE); ++ ++ { ++ u8 threshold; ++ #ifdef CONFIG_USB_HCI ++ // TH=1 => means that invalidate usb rx aggregation ++ // TH=0 => means that validate usb rx aggregation, use init value. ++ if(mlmepriv->htpriv.ht_option) { ++ if(padapter->registrypriv.wifi_spec==1) ++ threshold = 1; ++ else ++ threshold = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); ++ } else { ++ threshold = 1; ++ rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); ++ } ++ #endif ++ } ++ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ ++ //disable dynamic functions, such as high power, DIG ++ //Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, _FALSE); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pmlmeinfo->network.MacAddress); ++ ++ { ++ u8 join_type = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); ++ } ++ ++ Set_MSR(padapter, (pmlmeinfo->state & 0x3)); ++ ++ mlmeext_joinbss_event_callback(padapter, 1); ++ //restore Sequence No. ++ rtw_write8(padapter,0x4dc,padapter->xmitpriv.nqos_ssn); ++ ++ sreset_restore_security_station(padapter); ++} ++ ++ ++void sreset_restore_network_status(_adapter *padapter) ++{ ++ struct mlme_priv *mlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if (check_fwstate(mlmepriv, WIFI_STATION_STATE)) { ++ DBG_871X(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_STATION_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); ++ sreset_restore_network_station(padapter); ++ } else if (check_fwstate(mlmepriv, WIFI_AP_STATE)) { ++ DBG_871X(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_AP_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); ++ rtw_ap_restore_network(padapter); ++ } else if (check_fwstate(mlmepriv, WIFI_ADHOC_STATE)) { ++ DBG_871X(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_ADHOC_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); ++ } else { ++ DBG_871X(FUNC_ADPT_FMT" fwstate:0x%08x - ???\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); ++ } ++} ++ ++void sreset_stop_adapter(_adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ if (padapter == NULL) ++ return; ++ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++ ++ if (!rtw_netif_queue_stopped(padapter->pnetdev)) ++ rtw_netif_stop_queue(padapter->pnetdev); ++ ++ rtw_cancel_all_timer(padapter); ++ ++ /* TODO: OS and HCI independent */ ++ #if defined(PLATFORM_LINUX) && defined(CONFIG_USB_HCI) ++ tasklet_kill(&pxmitpriv->xmit_tasklet); ++ #endif ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) ++ rtw_scan_abort(padapter); ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) ++ { ++ rtw_set_roaming(padapter, 0); ++ _rtw_join_timeout_handler(padapter); ++ } ++ ++} ++ ++void sreset_start_adapter(_adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ if (padapter == NULL) ++ return; ++ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ sreset_restore_network_status(padapter); ++ } ++ ++ /* TODO: OS and HCI independent */ ++ #if defined(PLATFORM_LINUX) && defined(CONFIG_USB_HCI) ++ tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); ++ #endif ++ ++ _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 2000); ++ ++ if (rtw_netif_queue_stopped(padapter->pnetdev)) ++ rtw_netif_wake_queue(padapter->pnetdev); ++ ++} ++ ++void sreset_reset(_adapter *padapter) ++{ ++#ifdef DBG_CONFIG_ERROR_RESET ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct sreset_priv *psrtpriv = &pHalData->srestpriv; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ _irqL irqL; ++ u32 start = rtw_get_current_time(); ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS; ++ ++ _enter_pwrlock(&pwrpriv->lock); ++ ++ psrtpriv->silent_reset_inprogress = _TRUE; ++ pwrpriv->change_rfpwrstate = rf_off; ++ ++ sreset_stop_adapter(padapter); ++ #ifdef CONFIG_CONCURRENT_MODE ++ sreset_stop_adapter(padapter->pbuddy_adapter); ++ #endif ++ ++ #ifdef CONFIG_IPS ++ _ips_enter(padapter); ++ _ips_leave(padapter); ++ #endif ++ ++ sreset_start_adapter(padapter); ++ #ifdef CONFIG_CONCURRENT_MODE ++ sreset_start_adapter(padapter->pbuddy_adapter); ++ #endif ++ ++ psrtpriv->silent_reset_inprogress = _FALSE; ++ ++ _exit_pwrlock(&pwrpriv->lock); ++ ++ DBG_871X("%s done in %d ms\n", __FUNCTION__, rtw_get_passing_time_ms(start)); ++#endif ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_sta_mgt.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_sta_mgt.c +new file mode 100644 +index 00000000..084b5002 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_sta_mgt.c +@@ -0,0 +1,870 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_STA_MGT_C_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#if defined (PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) ++ ++#error "Shall be Linux or Windows, but not both!\n" ++ ++#endif ++ ++#include ++ ++void _rtw_init_stainfo(struct sta_info *psta); ++void _rtw_init_stainfo(struct sta_info *psta) ++{ ++ ++_func_enter_; ++ ++ _rtw_memset((u8 *)psta, 0, sizeof (struct sta_info)); ++ ++ _rtw_spinlock_init(&psta->lock); ++ _rtw_init_listhead(&psta->list); ++ _rtw_init_listhead(&psta->hash_list); ++ //_rtw_init_listhead(&psta->asoc_list); ++ //_rtw_init_listhead(&psta->sleep_list); ++ //_rtw_init_listhead(&psta->wakeup_list); ++ ++ _rtw_init_queue(&psta->sleep_q); ++ psta->sleepq_len = 0; ++ ++ _rtw_init_sta_xmit_priv(&psta->sta_xmitpriv); ++ _rtw_init_sta_recv_priv(&psta->sta_recvpriv); ++ ++#ifdef CONFIG_AP_MODE ++ ++ _rtw_init_listhead(&psta->asoc_list); ++ ++ _rtw_init_listhead(&psta->auth_list); ++ ++ psta->expire_to = 0; ++ ++ psta->flags = 0; ++ ++ psta->capability = 0; ++ ++ psta->bpairwise_key_installed = _FALSE; ++ ++ ++#ifdef CONFIG_NATIVEAP_MLME ++ psta->nonerp_set = 0; ++ psta->no_short_slot_time_set = 0; ++ psta->no_short_preamble_set = 0; ++ psta->no_ht_gf_set = 0; ++ psta->no_ht_set = 0; ++ psta->ht_20mhz_set = 0; ++#endif ++ ++#ifdef CONFIG_TX_MCAST2UNI ++ psta->under_exist_checking = 0; ++#endif // CONFIG_TX_MCAST2UNI ++ ++ psta->keep_alive_trycnt = 0; ++ ++#endif // CONFIG_AP_MODE ++ ++#ifdef DBG_TRX_STA_PKTS ++ psta->tx_be_cnt = 0; ++ psta->tx_bk_cnt = 0; ++ psta->tx_vi_cnt = 0; ++ psta->tx_vo_cnt = 0; ++ ++ psta->rx_be_cnt = 0; ++ psta->rx_bk_cnt = 0; ++ psta->rx_vi_cnt = 0; ++ psta->rx_vo_cnt = 0; ++#endif ++_func_exit_; ++ ++} ++ ++u32 _rtw_init_sta_priv(struct sta_priv *pstapriv) ++{ ++ struct sta_info *psta; ++ s32 i; ++ ++_func_enter_; ++ ++ pstapriv->pallocated_stainfo_buf = rtw_zvmalloc (sizeof(struct sta_info) * NUM_STA+ 4); ++ ++ if(!pstapriv->pallocated_stainfo_buf) ++ return _FAIL; ++ ++ pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 - ++ ((SIZE_PTR)(pstapriv->pallocated_stainfo_buf ) & 3); ++ ++ _rtw_init_queue(&pstapriv->free_sta_queue); ++ ++ _rtw_spinlock_init(&pstapriv->sta_hash_lock); ++ ++ //_rtw_init_queue(&pstapriv->asoc_q); ++ pstapriv->asoc_sta_count = 0; ++ _rtw_init_queue(&pstapriv->sleep_q); ++ _rtw_init_queue(&pstapriv->wakeup_q); ++ ++ psta = (struct sta_info *)(pstapriv->pstainfo_buf); ++ ++ ++ for(i = 0; i < NUM_STA; i++) ++ { ++ _rtw_init_stainfo(psta); ++ ++ _rtw_init_listhead(&(pstapriv->sta_hash[i])); ++ ++ rtw_list_insert_tail(&psta->list, get_list_head(&pstapriv->free_sta_queue)); ++ ++ psta++; ++ } ++ ++ ++ ++#ifdef CONFIG_AP_MODE ++ ++ pstapriv->sta_dz_bitmap = 0; ++ pstapriv->tim_bitmap = 0; ++ ++ _rtw_init_listhead(&pstapriv->asoc_list); ++ _rtw_init_listhead(&pstapriv->auth_list); ++ _rtw_spinlock_init(&pstapriv->asoc_list_lock); ++ _rtw_spinlock_init(&pstapriv->auth_list_lock); ++ pstapriv->asoc_list_cnt = 0; ++ pstapriv->auth_list_cnt = 0; ++ ++ pstapriv->auth_to = 3; // 3*2 = 6 sec ++ pstapriv->assoc_to = 3; ++ //pstapriv->expire_to = 900;// 900*2 = 1800 sec = 30 min, expire after no any traffic. ++ //pstapriv->expire_to = 30;// 30*2 = 60 sec = 1 min, expire after no any traffic. ++#ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK ++ pstapriv->expire_to = 3; // 3*2 = 6 sec ++#else ++ pstapriv->expire_to = 60;// 60*2 = 120 sec = 2 min, expire after no any traffic. ++#endif ++#ifdef CONFIG_ATMEL_RC_PATCH ++ _rtw_memset( pstapriv->atmel_rc_pattern, 0, ETH_ALEN); ++#endif ++ pstapriv->max_num_sta = NUM_STA; ++ ++#endif ++ ++_func_exit_; ++ ++ return _SUCCESS; ++ ++} ++ ++inline int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta) ++{ ++ int offset = (((u8 *)sta) - stapriv->pstainfo_buf)/sizeof(struct sta_info); ++ ++ if (!stainfo_offset_valid(offset)) ++ DBG_871X("%s invalid offset(%d), out of range!!!", __func__, offset); ++ ++ return offset; ++} ++ ++inline struct sta_info *rtw_get_stainfo_by_offset(struct sta_priv *stapriv, int offset) ++{ ++ if (!stainfo_offset_valid(offset)) ++ DBG_871X("%s invalid offset(%d), out of range!!!", __func__, offset); ++ ++ return (struct sta_info *)(stapriv->pstainfo_buf + offset * sizeof(struct sta_info)); ++} ++ ++void _rtw_free_sta_xmit_priv_lock(struct sta_xmit_priv *psta_xmitpriv); ++void _rtw_free_sta_xmit_priv_lock(struct sta_xmit_priv *psta_xmitpriv) ++{ ++_func_enter_; ++ ++ _rtw_spinlock_free(&psta_xmitpriv->lock); ++ ++ _rtw_spinlock_free(&(psta_xmitpriv->be_q.sta_pending.lock)); ++ _rtw_spinlock_free(&(psta_xmitpriv->bk_q.sta_pending.lock)); ++ _rtw_spinlock_free(&(psta_xmitpriv->vi_q.sta_pending.lock)); ++ _rtw_spinlock_free(&(psta_xmitpriv->vo_q.sta_pending.lock)); ++_func_exit_; ++} ++ ++static void _rtw_free_sta_recv_priv_lock(struct sta_recv_priv *psta_recvpriv) ++{ ++_func_enter_; ++ ++ _rtw_spinlock_free(&psta_recvpriv->lock); ++ ++ _rtw_spinlock_free(&(psta_recvpriv->defrag_q.lock)); ++ ++_func_exit_; ++ ++} ++ ++void rtw_mfree_stainfo(struct sta_info *psta); ++void rtw_mfree_stainfo(struct sta_info *psta) ++{ ++_func_enter_; ++ ++ if(&psta->lock != NULL) ++ _rtw_spinlock_free(&psta->lock); ++ ++ _rtw_free_sta_xmit_priv_lock(&psta->sta_xmitpriv); ++ _rtw_free_sta_recv_priv_lock(&psta->sta_recvpriv); ++ ++_func_exit_; ++} ++ ++ ++// this function is used to free the memory of lock || sema for all stainfos ++void rtw_mfree_all_stainfo(struct sta_priv *pstapriv ); ++void rtw_mfree_all_stainfo(struct sta_priv *pstapriv ) ++{ ++ _irqL irqL; ++ _list *plist, *phead; ++ struct sta_info *psta = NULL; ++ ++_func_enter_; ++ ++ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ ++ phead = get_list_head(&pstapriv->free_sta_queue); ++ plist = get_next(phead); ++ ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info ,list); ++ plist = get_next(plist); ++ ++ rtw_mfree_stainfo(psta); ++ } ++ ++ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ ++_func_exit_; ++ ++} ++ ++void rtw_mfree_sta_priv_lock(struct sta_priv *pstapriv); ++void rtw_mfree_sta_priv_lock(struct sta_priv *pstapriv) ++{ ++#ifdef CONFIG_AP_MODE ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++#endif ++ ++ rtw_mfree_all_stainfo(pstapriv); //be done before free sta_hash_lock ++ ++ _rtw_spinlock_free(&pstapriv->free_sta_queue.lock); ++ ++ _rtw_spinlock_free(&pstapriv->sta_hash_lock); ++ _rtw_spinlock_free(&pstapriv->wakeup_q.lock); ++ _rtw_spinlock_free(&pstapriv->sleep_q.lock); ++ ++#ifdef CONFIG_AP_MODE ++ _rtw_spinlock_free(&pstapriv->asoc_list_lock); ++ _rtw_spinlock_free(&pstapriv->auth_list_lock); ++ _rtw_spinlock_free(&pacl_list->acl_node_q.lock); ++#endif ++ ++} ++ ++u32 _rtw_free_sta_priv(struct sta_priv *pstapriv) ++{ ++ _irqL irqL; ++ _list *phead, *plist; ++ struct sta_info *psta = NULL; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ int index; ++ ++_func_enter_; ++ if(pstapriv){ ++ ++ /* delete all reordering_ctrl_timer */ ++ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ for(index = 0; index < NUM_STA; index++) ++ { ++ phead = &(pstapriv->sta_hash[index]); ++ plist = get_next(phead); ++ ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ int i; ++ psta = LIST_CONTAINOR(plist, struct sta_info ,hash_list); ++ plist = get_next(plist); ++ ++ for(i=0; i < 16 ; i++) ++ { ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer); ++ } ++ } ++ } ++ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ /*===============================*/ ++ ++ rtw_mfree_sta_priv_lock(pstapriv); ++ ++ if(pstapriv->pallocated_stainfo_buf) { ++ rtw_vmfree(pstapriv->pallocated_stainfo_buf, sizeof(struct sta_info)*NUM_STA+4); ++ } ++ } ++ ++_func_exit_; ++ return _SUCCESS; ++} ++ ++ ++//struct sta_info *rtw_alloc_stainfo(_queue *pfree_sta_queue, unsigned char *hwaddr) ++struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) ++{ ++ _irqL irqL, irqL2; ++ uint tmp_aid; ++ s32 index; ++ _list *phash_list; ++ struct sta_info *psta; ++ _queue *pfree_sta_queue; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ int i = 0; ++ u16 wRxSeqInitialValue = 0xffff; ++ ++_func_enter_; ++ ++ pfree_sta_queue = &pstapriv->free_sta_queue; ++ ++ //_enter_critical_bh(&(pfree_sta_queue->lock), &irqL); ++ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); ++ ++ if (_rtw_queue_empty(pfree_sta_queue) == _TRUE) ++ { ++ //_exit_critical_bh(&(pfree_sta_queue->lock), &irqL); ++ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); ++ psta = NULL; ++ } ++ else ++ { ++ psta = LIST_CONTAINOR(get_next(&pfree_sta_queue->queue), struct sta_info, list); ++ ++ rtw_list_delete(&(psta->list)); ++ ++ //_exit_critical_bh(&(pfree_sta_queue->lock), &irqL); ++ ++ tmp_aid = psta->aid; ++ ++ _rtw_init_stainfo(psta); ++ ++ psta->padapter = pstapriv->padapter; ++ ++ _rtw_memcpy(psta->hwaddr, hwaddr, ETH_ALEN); ++ ++ index = wifi_mac_hash(hwaddr); ++ ++ RT_TRACE(_module_rtl871x_sta_mgt_c_,_drv_info_,("rtw_alloc_stainfo: index = %x", index)); ++ ++ if(index >= NUM_STA){ ++ RT_TRACE(_module_rtl871x_sta_mgt_c_,_drv_err_,("ERROR=> rtw_alloc_stainfo: index >= NUM_STA")); ++ psta= NULL; ++ goto exit; ++ } ++ phash_list = &(pstapriv->sta_hash[index]); ++ ++ //_enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); ++ ++ rtw_list_insert_tail(&psta->hash_list, phash_list); ++ ++ pstapriv->asoc_sta_count ++ ; ++ ++ //_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); ++ ++// Commented by Albert 2009/08/13 ++// For the SMC router, the sequence number of first packet of WPS handshake will be 0. ++// In this case, this packet will be dropped by recv_decache function if we use the 0x00 as the default value for tid_rxseq variable. ++// So, we initialize the tid_rxseq variable as the 0xffff. ++ ++ for( i = 0; i < 16; i++ ) ++ { ++ _rtw_memcpy( &psta->sta_recvpriv.rxcache.tid_rxseq[ i ], &wRxSeqInitialValue, 2 ); ++ } ++ ++ RT_TRACE(_module_rtl871x_sta_mgt_c_,_drv_info_,("alloc number_%d stainfo with hwaddr = %x %x %x %x %x %x \n", ++ pstapriv->asoc_sta_count , hwaddr[0], hwaddr[1], hwaddr[2],hwaddr[3],hwaddr[4],hwaddr[5])); ++ ++ init_addba_retry_timer(pstapriv->padapter, psta); ++ ++#ifdef CONFIG_TDLS ++ psta->padapter = pstapriv->padapter; ++ init_TPK_timer(pstapriv->padapter, psta); ++ init_ch_switch_timer(pstapriv->padapter, psta); ++ init_base_ch_timer(pstapriv->padapter, psta); ++ init_off_ch_timer(pstapriv->padapter, psta); ++ init_handshake_timer(pstapriv->padapter, psta); ++ init_tdls_alive_timer(pstapriv->padapter, psta); ++#endif //CONFIG_TDLS ++ ++ //for A-MPDU Rx reordering buffer control ++ for(i=0; i < 16 ; i++) ++ { ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ ++ preorder_ctrl->padapter = pstapriv->padapter; ++ ++ preorder_ctrl->enable = _FALSE; ++ ++ preorder_ctrl->indicate_seq = 0xffff; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d\n", __FUNCTION__, __LINE__, ++ preorder_ctrl->indicate_seq); ++ #endif ++ preorder_ctrl->wend_b= 0xffff; ++ //preorder_ctrl->wsize_b = (NR_RECVBUFF-2); ++ preorder_ctrl->wsize_b = 64;//64; ++ ++ _rtw_init_queue(&preorder_ctrl->pending_recvframe_queue); ++ ++ rtw_init_recv_timer(preorder_ctrl); ++ } ++ ++ ++ //init for DM ++ psta->rssi_stat.UndecoratedSmoothedPWDB = (-1); ++ psta->rssi_stat.UndecoratedSmoothedCCK = (-1); ++#ifdef CONFIG_ATMEL_RC_PATCH ++ psta->flag_atmel_rc = 0; ++#endif ++ /* init for the sequence number of received management frame */ ++ psta->RxMgmtFrameSeqNum = 0xffff; ++ } ++ ++exit: ++ ++ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); ++ ++_func_exit_; ++ ++ return psta; ++ ++ ++} ++ ++ ++// using pstapriv->sta_hash_lock to protect ++u32 rtw_free_stainfo(_adapter *padapter , struct sta_info *psta) ++{ ++ int i; ++ _irqL irqL0; ++ _queue *pfree_sta_queue; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ struct sta_xmit_priv *pstaxmitpriv; ++ struct xmit_priv *pxmitpriv= &padapter->xmitpriv; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct hw_xmit *phwxmit; ++ ++ ++_func_enter_; ++ ++ if (psta == NULL) ++ goto exit; ++ ++ ++ _enter_critical_bh(&psta->lock, &irqL0); ++ psta->state &= ~_FW_LINKED; ++ _exit_critical_bh(&psta->lock, &irqL0); ++ ++ pfree_sta_queue = &pstapriv->free_sta_queue; ++ ++ ++ pstaxmitpriv = &psta->sta_xmitpriv; ++ ++ //rtw_list_delete(&psta->sleep_list); ++ ++ //rtw_list_delete(&psta->wakeup_list); ++ ++ _enter_critical_bh(&pxmitpriv->lock, &irqL0); ++ ++ rtw_free_xmitframe_queue(pxmitpriv, &psta->sleep_q); ++ psta->sleepq_len = 0; ++ ++ //vo ++ //_enter_critical_bh(&(pxmitpriv->vo_pending.lock), &irqL0); ++ rtw_free_xmitframe_queue( pxmitpriv, &pstaxmitpriv->vo_q.sta_pending); ++ rtw_list_delete(&(pstaxmitpriv->vo_q.tx_pending)); ++ phwxmit = pxmitpriv->hwxmits; ++ phwxmit->accnt -= pstaxmitpriv->vo_q.qcnt; ++ pstaxmitpriv->vo_q.qcnt = 0; ++ //_exit_critical_bh(&(pxmitpriv->vo_pending.lock), &irqL0); ++ ++ //vi ++ //_enter_critical_bh(&(pxmitpriv->vi_pending.lock), &irqL0); ++ rtw_free_xmitframe_queue( pxmitpriv, &pstaxmitpriv->vi_q.sta_pending); ++ rtw_list_delete(&(pstaxmitpriv->vi_q.tx_pending)); ++ phwxmit = pxmitpriv->hwxmits+1; ++ phwxmit->accnt -= pstaxmitpriv->vi_q.qcnt; ++ pstaxmitpriv->vi_q.qcnt = 0; ++ //_exit_critical_bh(&(pxmitpriv->vi_pending.lock), &irqL0); ++ ++ //be ++ //_enter_critical_bh(&(pxmitpriv->be_pending.lock), &irqL0); ++ rtw_free_xmitframe_queue( pxmitpriv, &pstaxmitpriv->be_q.sta_pending); ++ rtw_list_delete(&(pstaxmitpriv->be_q.tx_pending)); ++ phwxmit = pxmitpriv->hwxmits+2; ++ phwxmit->accnt -= pstaxmitpriv->be_q.qcnt; ++ pstaxmitpriv->be_q.qcnt = 0; ++ //_exit_critical_bh(&(pxmitpriv->be_pending.lock), &irqL0); ++ ++ //bk ++ //_enter_critical_bh(&(pxmitpriv->bk_pending.lock), &irqL0); ++ rtw_free_xmitframe_queue( pxmitpriv, &pstaxmitpriv->bk_q.sta_pending); ++ rtw_list_delete(&(pstaxmitpriv->bk_q.tx_pending)); ++ phwxmit = pxmitpriv->hwxmits+3; ++ phwxmit->accnt -= pstaxmitpriv->bk_q.qcnt; ++ pstaxmitpriv->bk_q.qcnt = 0; ++ //_exit_critical_bh(&(pxmitpriv->bk_pending.lock), &irqL0); ++ ++ _exit_critical_bh(&pxmitpriv->lock, &irqL0); ++ ++ rtw_list_delete(&psta->hash_list); ++ RT_TRACE(_module_rtl871x_sta_mgt_c_,_drv_err_,("\n free number_%d stainfo with hwaddr = 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x \n",pstapriv->asoc_sta_count , psta->hwaddr[0], psta->hwaddr[1], psta->hwaddr[2],psta->hwaddr[3],psta->hwaddr[4],psta->hwaddr[5])); ++ pstapriv->asoc_sta_count --; ++ ++ ++ // re-init sta_info; 20061114 // will be init in alloc_stainfo ++ //_rtw_init_sta_xmit_priv(&psta->sta_xmitpriv); ++ //_rtw_init_sta_recv_priv(&psta->sta_recvpriv); ++ ++ _cancel_timer_ex(&psta->addba_retry_timer); ++ ++#ifdef CONFIG_TDLS ++ _cancel_timer_ex(&psta->TPK_timer); ++ _cancel_timer_ex(&psta->option_timer); ++ _cancel_timer_ex(&psta->base_ch_timer); ++ _cancel_timer_ex(&psta->off_ch_timer); ++ _cancel_timer_ex(&psta->alive_timer1); ++ _cancel_timer_ex(&psta->alive_timer2); ++#endif //CONFIG_TDLS ++ ++ //for A-MPDU Rx reordering buffer control, cancel reordering_ctrl_timer ++ for(i=0; i < 16 ; i++) ++ { ++ _irqL irqL; ++ _list *phead, *plist; ++ union recv_frame *prframe; ++ _queue *ppending_recvframe_queue; ++ _queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; ++ ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ ++ _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer); ++ ++ ++ ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; ++ ++ _enter_critical_bh(&ppending_recvframe_queue->lock, &irqL); ++ ++ phead = get_list_head(ppending_recvframe_queue); ++ plist = get_next(phead); ++ ++ while(!rtw_is_list_empty(phead)) ++ { ++ prframe = LIST_CONTAINOR(plist, union recv_frame, u); ++ ++ plist = get_next(plist); ++ ++ rtw_list_delete(&(prframe->u.hdr.list)); ++ ++ rtw_free_recvframe(prframe, pfree_recv_queue); ++ } ++ ++ _exit_critical_bh(&ppending_recvframe_queue->lock, &irqL); ++ ++ } ++ ++ if (!(psta->state & WIFI_AP_STATE)) ++ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, _FALSE); ++ ++#ifdef CONFIG_AP_MODE ++ ++/* ++ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL0); ++ rtw_list_delete(&psta->asoc_list); ++ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL0); ++*/ ++ _enter_critical_bh(&pstapriv->auth_list_lock, &irqL0); ++ if (!rtw_is_list_empty(&psta->auth_list)) { ++ rtw_list_delete(&psta->auth_list); ++ pstapriv->auth_list_cnt--; ++ } ++ _exit_critical_bh(&pstapriv->auth_list_lock, &irqL0); ++ ++ psta->expire_to = 0; ++#ifdef CONFIG_ATMEL_RC_PATCH ++ psta->flag_atmel_rc = 0; ++#endif ++ psta->sleepq_ac_len = 0; ++ psta->qos_info = 0; ++ ++ psta->max_sp_len = 0; ++ psta->uapsd_bk = 0; ++ psta->uapsd_be = 0; ++ psta->uapsd_vi = 0; ++ psta->uapsd_vo = 0; ++ ++ psta->has_legacy_ac = 0; ++ ++#ifdef CONFIG_NATIVEAP_MLME ++ ++ pstapriv->sta_dz_bitmap &=~BIT(psta->aid); ++ pstapriv->tim_bitmap &=~BIT(psta->aid); ++ ++ //rtw_indicate_sta_disassoc_event(padapter, psta); ++ ++ if ((psta->aid >0)&&(pstapriv->sta_aid[psta->aid - 1] == psta)) ++ { ++ pstapriv->sta_aid[psta->aid - 1] = NULL; ++ psta->aid = 0; ++ } ++ ++#endif // CONFIG_NATIVEAP_MLME ++ ++#ifdef CONFIG_TX_MCAST2UNI ++ psta->under_exist_checking = 0; ++#endif // CONFIG_TX_MCAST2UNI ++ ++#endif // CONFIG_AP_MODE ++ ++ _rtw_spinlock_free(&psta->lock); ++ ++ //_enter_critical_bh(&(pfree_sta_queue->lock), &irqL0); ++ rtw_list_insert_tail(&psta->list, get_list_head(pfree_sta_queue)); ++ //_exit_critical_bh(&(pfree_sta_queue->lock), &irqL0); ++ ++exit: ++ ++_func_exit_; ++ ++ return _SUCCESS; ++ ++} ++ ++// free all stainfo which in sta_hash[all] ++void rtw_free_all_stainfo(_adapter *padapter) ++{ ++ _irqL irqL; ++ _list *plist, *phead; ++ s32 index; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info* pbcmc_stainfo =rtw_get_bcmc_stainfo( padapter); ++ ++_func_enter_; ++ ++ if(pstapriv->asoc_sta_count==1) ++ goto exit; ++ ++ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ ++ for(index=0; index< NUM_STA; index++) ++ { ++ phead = &(pstapriv->sta_hash[index]); ++ plist = get_next(phead); ++ ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info ,hash_list); ++ ++ plist = get_next(plist); ++ ++ if(pbcmc_stainfo!=psta) ++ rtw_free_stainfo(padapter , psta); ++ ++ } ++ } ++ ++ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ ++exit: ++ ++_func_exit_; ++ ++} ++ ++/* any station allocated can be searched by hash list */ ++struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) ++{ ++ ++ _irqL irqL; ++ ++ _list *plist, *phead; ++ ++ struct sta_info *psta = NULL; ++ ++ u32 index; ++ ++ u8 *addr; ++ ++ u8 bc_addr[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; ++ ++_func_enter_; ++ ++ if(hwaddr==NULL) ++ return NULL; ++ ++ if(IS_MCAST(hwaddr)) ++ { ++ addr = bc_addr; ++ } ++ else ++ { ++ addr = hwaddr; ++ } ++ ++ index = wifi_mac_hash(addr); ++ ++ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ ++ phead = &(pstapriv->sta_hash[index]); ++ plist = get_next(phead); ++ ++ ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ ++ psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); ++ ++ if ((_rtw_memcmp(psta->hwaddr, addr, ETH_ALEN))== _TRUE) ++ { // if found the matched address ++ break; ++ } ++ psta=NULL; ++ plist = get_next(plist); ++ } ++ ++ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++_func_exit_; ++ return psta; ++ ++} ++ ++u32 rtw_init_bcmc_stainfo(_adapter* padapter) ++{ ++ ++ struct sta_info *psta; ++ struct tx_servq *ptxservq; ++ u32 res=_SUCCESS; ++ NDIS_802_11_MAC_ADDRESS bcast_addr= {0xff,0xff,0xff,0xff,0xff,0xff}; ++ ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ //_queue *pstapending = &padapter->xmitpriv.bm_pending; ++ ++_func_enter_; ++ ++ psta = rtw_alloc_stainfo(pstapriv, bcast_addr); ++ ++ if(psta==NULL){ ++ res=_FAIL; ++ RT_TRACE(_module_rtl871x_sta_mgt_c_,_drv_err_,("rtw_alloc_stainfo fail")); ++ goto exit; ++ } ++ ++ // default broadcast & multicast use macid 1 ++ psta->mac_id = 1; ++ ++ ptxservq= &(psta->sta_xmitpriv.be_q); ++ ++/* ++ _enter_critical(&pstapending->lock, &irqL0); ++ ++ if (rtw_is_list_empty(&ptxservq->tx_pending)) ++ rtw_list_insert_tail(&ptxservq->tx_pending, get_list_head(pstapending)); ++ ++ _exit_critical(&pstapending->lock, &irqL0); ++*/ ++ ++exit: ++_func_exit_; ++ return _SUCCESS; ++ ++} ++ ++ ++struct sta_info* rtw_get_bcmc_stainfo(_adapter* padapter) ++{ ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 bc_addr[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; ++_func_enter_; ++ psta = rtw_get_stainfo(pstapriv, bc_addr); ++_func_exit_; ++ return psta; ++ ++} ++ ++u8 rtw_access_ctrl(_adapter *padapter, u8 *mac_addr) ++{ ++ u8 res = _TRUE; ++#ifdef CONFIG_AP_MODE ++ _irqL irqL; ++ _list *plist, *phead; ++ struct rtw_wlan_acl_node *paclnode; ++ u8 match = _FALSE; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ _queue *pacl_node_q =&pacl_list->acl_node_q; ++ ++ _enter_critical_bh(&(pacl_node_q->lock), &irqL); ++ phead = get_list_head(pacl_node_q); ++ plist = get_next(phead); ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list); ++ plist = get_next(plist); ++ ++ if(_rtw_memcmp(paclnode->addr, mac_addr, ETH_ALEN)) ++ { ++ if(paclnode->valid == _TRUE) ++ { ++ match = _TRUE; ++ break; ++ } ++ } ++ } ++ _exit_critical_bh(&(pacl_node_q->lock), &irqL); ++ ++ ++ if(pacl_list->mode == 1)//accept unless in deny list ++ { ++ res = (match == _TRUE) ? _FALSE:_TRUE; ++ } ++ else if(pacl_list->mode == 2)//deny unless in accept list ++ { ++ res = (match == _TRUE) ? _TRUE:_FALSE; ++ } ++ else ++ { ++ res = _TRUE; ++ } ++ ++#endif ++ ++ return res; ++ ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_tdls.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_tdls.c +new file mode 100644 +index 00000000..f7ca24aa +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_tdls.c +@@ -0,0 +1,2941 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_TDLS_C_ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_TDLS ++extern unsigned char MCS_rate_2R[16]; ++extern unsigned char MCS_rate_1R[16]; ++extern void process_wmmps_data(_adapter *padapter, union recv_frame *precv_frame); ++extern s32 rtw_dump_xframe(_adapter *padapter, struct xmit_frame *pxmitframe); ++ ++void rtw_reset_tdls_info(_adapter* padapter) ++{ ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ ++ ptdlsinfo->ap_prohibited = _FALSE; ++ ptdlsinfo->setup_state = TDLS_STATE_NONE; ++ ptdlsinfo->sta_cnt = 0; ++ ptdlsinfo->sta_maximum = _FALSE; ++ ptdlsinfo->macid_index= 6; ++ ptdlsinfo->clear_cam= 0; ++ ptdlsinfo->ch_sensing = 0; ++ ptdlsinfo->cur_channel = 0; ++ ptdlsinfo->candidate_ch = 1; //when inplement channel switching, default candidate channel is 1 ++ ptdlsinfo->watchdog_count = 0; ++ ptdlsinfo->dev_discovered = 0; ++ ++#ifdef CONFIG_WFD ++ ptdlsinfo->wfd_info = &padapter->wfd_info; ++#endif //CONFIG_WFD ++} ++ ++int rtw_init_tdls_info(_adapter* padapter) ++{ ++ int res = _SUCCESS; ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ ++ ptdlsinfo->enable = 1; ++ rtw_reset_tdls_info(padapter); ++ ++ _rtw_spinlock_init(&ptdlsinfo->cmd_lock); ++ _rtw_spinlock_init(&ptdlsinfo->hdl_lock); ++ ++ return res; ++ ++} ++ ++void rtw_free_tdls_info(struct tdls_info *ptdlsinfo) ++{ ++ _rtw_spinlock_free(&ptdlsinfo->cmd_lock); ++ _rtw_spinlock_free(&ptdlsinfo->hdl_lock); ++ ++ _rtw_memset(ptdlsinfo, 0, sizeof(struct tdls_info) ); ++ ++} ++ ++void issue_nulldata_to_TDLS_peer_STA(_adapter *padapter, struct sta_info *ptdls_sta, unsigned int power_mode) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++// SetToDs(fctrl); ++ if (power_mode) ++ { ++ SetPwrMgt(fctrl); ++ } ++ ++ _rtw_memcpy(pwlanhdr->addr1, ptdls_sta->hwaddr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ ptdls_sta->sta_xmitpriv.txseq_tid[pattrib->priority]++; ++ ptdls_sta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF; ++ pattrib->seqnum = ptdls_sta->sta_xmitpriv.txseq_tid[pattrib->priority]; ++ SetSeqNum(pwlanhdr, pattrib->seqnum); ++ ++ SetFrameSubType(pframe, WIFI_DATA_NULL); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ dump_mgntframe(padapter, pmgntframe); ++ ++ return; ++} ++ ++s32 update_tdls_attrib(_adapter *padapter, struct pkt_attrib *pattrib) ++{ ++ ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct qos_priv *pqospriv= &pmlmepriv->qospriv; ++ ++ s32 res=_SUCCESS; ++ sint bmcast; ++ ++ bmcast = IS_MCAST(pattrib->ra); ++ ++ psta = rtw_get_stainfo(pstapriv, pattrib->ra); ++ if (psta == NULL) { ++ res =_FAIL; ++ goto exit; ++ } ++ ++ pattrib->mac_id = psta->mac_id; ++ ++ pattrib->psta = psta; ++ ++ pattrib->ack_policy = 0; ++ // get ether_hdr_len ++ pattrib->pkt_hdrlen = ETH_HLEN;//(pattrib->ether_type == 0x8100) ? (14 + 4 ): 14; //vlan tag ++ ++ if (pqospriv->qos_option && psta->qos_option) { ++ pattrib->priority = 1; //tdls management frame should be AC_BK ++ pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN; ++ pattrib->subtype = WIFI_QOS_DATA_TYPE; ++ } else { ++ pattrib->hdrlen = WLAN_HDR_A3_LEN; ++ pattrib->subtype = WIFI_DATA_TYPE; ++ pattrib->priority = 0; ++ } ++ ++ if (psta->ieee8021x_blocked == _TRUE) ++ { ++ pattrib->encrypt = 0; ++ } ++ else ++ { ++ GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast); ++ ++ switch(psecuritypriv->dot11AuthAlgrthm) ++ { ++ case dot11AuthAlgrthm_Open: ++ case dot11AuthAlgrthm_Shared: ++ case dot11AuthAlgrthm_Auto: ++ pattrib->key_idx = (u8)psecuritypriv->dot11PrivacyKeyIndex; ++ break; ++ case dot11AuthAlgrthm_8021X: ++ pattrib->key_idx = 0; ++ break; ++ default: ++ pattrib->key_idx = 0; ++ break; ++ } ++ } ++ ++ switch (pattrib->encrypt) ++ { ++ case _WEP40_: ++ case _WEP104_: ++ pattrib->iv_len = 4; ++ pattrib->icv_len = 4; ++ break; ++ case _TKIP_: ++ pattrib->iv_len = 8; ++ pattrib->icv_len = 4; ++ if(padapter->securitypriv.busetkipkey==_FAIL) ++ { ++ res =_FAIL; ++ goto exit; ++ } ++ break; ++ case _AES_: ++ pattrib->iv_len = 8; ++ pattrib->icv_len = 8; ++ break; ++ default: ++ pattrib->iv_len = 0; ++ pattrib->icv_len = 0; ++ break; ++ } ++ ++ if (pattrib->encrypt && ++ ((padapter->securitypriv.sw_encrypt == _TRUE) || (psecuritypriv->hw_decrypted == _FALSE))) ++ { ++ pattrib->bswenc = _TRUE; ++ } else { ++ pattrib->bswenc = _FALSE; ++ } ++ ++ //qos_en, ht_en, init rate, ,bw, ch_offset, sgi ++ pattrib->qos_en = psta->qos_option; ++ pattrib->ht_en = psta->htpriv.ht_option; ++ pattrib->raid = psta->raid; ++ pattrib->bwmode = psta->htpriv.bwmode; ++ pattrib->ch_offset = psta->htpriv.ch_offset; ++ pattrib->sgi= psta->htpriv.sgi; ++ pattrib->ampdu_en = _FALSE; ++ ++ //if(pattrib->ht_en && psta->htpriv.ampdu_enable) ++ //{ ++ // if(psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority)) ++ // pattrib->ampdu_en = _TRUE; ++ //} ++ ++exit: ++ ++ return res; ++} ++ ++void free_tdls_sta(_adapter *padapter, struct sta_info *ptdls_sta) ++{ ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ _irqL irqL; ++ ++ //free peer sta_info ++ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ if(ptdlsinfo->sta_cnt != 0) ++ ptdlsinfo->sta_cnt--; ++ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ if( ptdlsinfo->sta_cnt < (NUM_STA - 2) ) // -2: AP + BC/MC sta ++ { ++ ptdlsinfo->sta_maximum = _FALSE; ++ _rtw_memset( &ptdlsinfo->ss_record, 0x00, sizeof(struct tdls_ss_record) ); ++ } ++ //ready to clear cam ++ if(ptdls_sta->mac_id!=0){ ++ ptdlsinfo->clear_cam=ptdls_sta->mac_id; ++ rtw_setstakey_cmd(padapter, (u8 *)ptdls_sta, _TRUE, _TRUE); ++ } ++ ++ if(ptdlsinfo->sta_cnt==0){ ++ rtw_tdls_cmd(padapter, myid(&(padapter->eeprompriv)), TDLS_RS_RCR); ++ ptdlsinfo->setup_state=TDLS_STATE_NONE; ++ } ++ else ++ DBG_871X("Remain tdls sta:%02x\n", ptdlsinfo->sta_cnt); ++ ++ rtw_free_stainfo(padapter, ptdls_sta); ++ ++} ++ ++// cam entry will be the same as mac_id ++void rtw_tdls_set_mac_id(struct tdls_info *ptdlsinfo, struct sta_info *ptdls_sta) ++{ ++ if(ptdls_sta->mac_id==0) ++ { ++ ptdls_sta->mac_id = ptdlsinfo->macid_index; ++ if( (++ptdlsinfo->macid_index) > (NUM_STA -2) ) ++ ptdlsinfo->macid_index= TDLS_INI_MACID_ENTRY; ++ } ++} ++ ++//TDLS encryption(if needed) will always be CCMP ++void rtw_tdls_set_key(_adapter *adapter, struct rx_pkt_attrib *prx_pkt_attrib, struct sta_info *ptdls_sta) ++{ ++ if(prx_pkt_attrib->encrypt) ++ { ++ ptdls_sta->dot118021XPrivacy=_AES_; ++ rtw_setstakey_cmd(adapter, (u8*)ptdls_sta, _TRUE, _TRUE); ++ } ++} ++ ++void rtw_tdls_process_ht_cap(_adapter *adapter, struct sta_info *ptdls_sta, u8 *data, u8 Length) ++{ ++ /* save HT capabilities in the sta object */ ++ _rtw_memset(&ptdls_sta->htpriv.ht_cap, 0, sizeof(struct rtw_ieee80211_ht_cap)); ++ if (data && Length >= sizeof(struct rtw_ieee80211_ht_cap) ) ++ { ++ ptdls_sta->flags |= WLAN_STA_HT; ++ ++ ptdls_sta->flags |= WLAN_STA_WME; ++ ++ _rtw_memcpy(&ptdls_sta->htpriv.ht_cap, data, sizeof(struct rtw_ieee80211_ht_cap)); ++ ++ } else ++ ptdls_sta->flags &= ~WLAN_STA_HT; ++ ++ if(ptdls_sta->flags & WLAN_STA_HT) ++ { ++ if(adapter->registrypriv.ht_enable == _TRUE) ++ { ++ ptdls_sta->htpriv.ht_option = _TRUE; ++ } ++ else ++ { ++ ptdls_sta->htpriv.ht_option = _FALSE; ++ ptdls_sta->stat_code = _STATS_FAILURE_; ++ } ++ } ++ ++ //HT related cap ++ if(ptdls_sta->htpriv.ht_option) ++ { ++ //check if sta supports rx ampdu ++ if(adapter->registrypriv.ampdu_enable==1) ++ ptdls_sta->htpriv.ampdu_enable = _TRUE; ++ ++ //check if sta support s Short GI ++ if(ptdls_sta->htpriv.ht_cap.cap_info & cpu_to_le16(IEEE80211_HT_CAP_SGI_20|IEEE80211_HT_CAP_SGI_40)) ++ { ++ ptdls_sta->htpriv.sgi = _TRUE; ++ } ++ ++ // bwmode would still followed AP's setting ++ if(ptdls_sta->htpriv.ht_cap.cap_info & cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH)) ++ { ++ ptdls_sta->htpriv.bwmode = adapter->mlmeextpriv.cur_bwmode; ++ ptdls_sta->htpriv.ch_offset = adapter->mlmeextpriv.cur_ch_offset; ++ } ++ } ++} ++ ++u8 *rtw_tdls_set_ht_cap(_adapter *padapter, u8 *pframe, struct pkt_attrib *pattrib) ++{ ++ struct rtw_ieee80211_ht_cap ht_capie; ++ u8 rf_type; ++ ++ //HT capabilities ++ _rtw_memset(&ht_capie, 0, sizeof(struct rtw_ieee80211_ht_cap)); ++ ++ ht_capie.cap_info = IEEE80211_HT_CAP_SUP_WIDTH |IEEE80211_HT_CAP_SGI_20 |IEEE80211_HT_CAP_SM_PS | ++ IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_TX_STBC |IEEE80211_HT_CAP_DSSSCCK40; ++ ++ { ++ u32 rx_packet_offset, max_recvbuf_sz; ++ padapter->HalFunc.GetHalDefVarHandler(padapter, HAL_DEF_RX_PACKET_OFFSET, &rx_packet_offset); ++ padapter->HalFunc.GetHalDefVarHandler(padapter, HAL_DEF_MAX_RECVBUF_SZ, &max_recvbuf_sz); ++ if(max_recvbuf_sz-rx_packet_offset>(8191-256)) ++ ht_capie.cap_info = ht_capie.cap_info |IEEE80211_HT_CAP_MAX_AMSDU; ++ } ++ ++ ht_capie.ampdu_params_info = (IEEE80211_HT_CAP_AMPDU_FACTOR&0x03); ++ ++ padapter->HalFunc.GetHwRegHandler(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ switch(rf_type) ++ { ++ case RF_1T1R: ++ ht_capie.cap_info |= 0x0100;//RX STBC One spatial stream ++ _rtw_memcpy(ht_capie.supp_mcs_set, MCS_rate_1R, 16); ++ break; ++ ++ case RF_2T2R: ++ case RF_1T2R: ++ default: ++ ht_capie.cap_info|= 0x0200;//RX STBC two spatial stream ++ _rtw_memcpy(ht_capie.supp_mcs_set, MCS_rate_2R, 16); ++ break; ++ } ++ ++ return(rtw_set_ie(pframe, _HT_CAPABILITY_IE_, ++ sizeof(struct rtw_ieee80211_ht_cap), (unsigned char*)&ht_capie, &(pattrib->pktlen))); ++} ++ ++u8 *rtw_tdls_set_sup_ch(struct mlme_ext_priv *pmlmeext, u8 *pframe, struct pkt_attrib *pattrib) ++{ ++ u8 sup_ch[ 30 * 2 ] = { 0x00 }, sup_ch_idx = 0, idx_5g = 2; //For supported channel ++ do{ ++ if( pmlmeext->channel_set[sup_ch_idx].ChannelNum <= 14 ) ++ { ++ sup_ch[0] = 1; //First channel number ++ sup_ch[1] = pmlmeext->channel_set[sup_ch_idx].ChannelNum; //Number of channel ++ } ++ else ++ { ++ sup_ch[idx_5g++] = pmlmeext->channel_set[sup_ch_idx].ChannelNum; ++ sup_ch[idx_5g++] = 1; ++ } ++ ++ sup_ch_idx++; ++ } ++ while( pmlmeext->channel_set[sup_ch_idx].ChannelNum != 0 ); ++ return(rtw_set_ie(pframe, _SUPPORTED_CH_IE_, idx_5g, sup_ch, &(pattrib->pktlen))); ++} ++ ++#ifdef CONFIG_WFD ++void rtw_tdls_process_wfd_ie(struct tdls_info *ptdlsinfo, u8 *ptr, u8 length) ++{ ++ u8 wfd_ie[ 128 ] = { 0x00 }; ++ u32 wfd_ielen = 0; ++ u32 wfd_offset = 0; ++ // Try to get the TCP port information when receiving the negotiation response. ++ // ++ ++ wfd_offset = 0; ++ wfd_offset = rtw_get_wfd_ie( ptr + wfd_offset, length - wfd_offset, wfd_ie, &wfd_ielen ); ++ while( wfd_offset ) ++ { ++ u8 attr_content[ 10 ] = { 0x00 }; ++ u32 attr_contentlen = 0; ++ int i; ++ ++ DBG_871X( "[%s] WFD IE Found!!\n", __FUNCTION__ ); ++ rtw_get_wfd_attr_content( wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); ++ if ( attr_contentlen ) ++ { ++ ptdlsinfo->wfd_info->peer_rtsp_ctrlport = RTW_GET_BE16( attr_content + 2 ); ++ DBG_871X( "[%s] Peer PORT NUM = %d\n", __FUNCTION__, ptdlsinfo->wfd_info->peer_rtsp_ctrlport ); ++ } ++ ++ _rtw_memset( attr_content, 0x00, 10); ++ attr_contentlen = 0; ++ rtw_get_wfd_attr_content( wfd_ie, wfd_ielen, WFD_ATTR_LOCAL_IP_ADDR, attr_content, &attr_contentlen); ++ if ( attr_contentlen ) ++ { ++ _rtw_memcpy(ptdlsinfo->wfd_info->peer_ip_address, ( attr_content + 1 ), 4); ++ DBG_871X( "[%s] Peer IP = %02u.%02u.%02u.%02u \n", __FUNCTION__, ++ ptdlsinfo->wfd_info->peer_ip_address[0], ptdlsinfo->wfd_info->peer_ip_address[1], ++ ptdlsinfo->wfd_info->peer_ip_address[2], ptdlsinfo->wfd_info->peer_ip_address[3] ++ ); ++ } ++ wfd_offset = rtw_get_wfd_ie( ptr + wfd_offset, length - wfd_offset, wfd_ie, &wfd_ielen ); ++ } ++} ++ ++void issue_tunneled_probe_req(_adapter *padapter) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ u8 baddr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ DBG_871X("[%s]\n", __FUNCTION__); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ ++ pmgntframe->frame_tag = DATA_FRAMETAG; ++ pattrib->ether_type = 0x890d; ++ pattrib->pctrl =0; ++ ++ _rtw_memcpy(pattrib->dst, baddr, ETH_ALEN); ++ ++ _rtw_memcpy(pattrib->src, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ ++ update_tdls_attrib(padapter, pattrib); ++ pattrib->qsel=pattrib->priority; ++ if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, TUNNELED_PROBE_REQ) != _SUCCESS) { ++ rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ goto exit; ++ } ++ rtw_dump_xframe(padapter, pmgntframe); ++ ++exit: ++ ++ return; ++} ++ ++void issue_tunneled_probe_rsp(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct rx_pkt_attrib *rx_pkt_pattrib = &precv_frame->u.hdr.attrib; ++ ++ DBG_871X("[%s]\n", __FUNCTION__); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ ++ pmgntframe->frame_tag = DATA_FRAMETAG; ++ pattrib->ether_type = 0x890d; ++ pattrib->pctrl =0; ++ ++ _rtw_memcpy(pattrib->dst, rx_pkt_pattrib->src, ETH_ALEN); ++ ++ _rtw_memcpy(pattrib->src, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ ++ update_tdls_attrib(padapter, pattrib); ++ pattrib->qsel=pattrib->priority; ++ if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, TUNNELED_PROBE_RSP) != _SUCCESS) { ++ rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ goto exit; ++ } ++ rtw_dump_xframe(padapter, pmgntframe); ++ ++exit: ++ ++ return; ++} ++#endif //CONFIG_WFD ++ ++void issue_tdls_setup_req(_adapter *padapter, u8 *mac_addr) ++{ ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *ptdls_sta= NULL; ++ _irqL irqL; ++ static u8 dialogtoken = 0; ++ u32 timeout_interval= TPK_RESEND_COUNT * 1000; //retry timer should set at least 301 sec, using TPK_count counting 301 times. ++ ++ if(ptdlsinfo->ap_prohibited == _TRUE) ++ goto exit; ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ ++ pmgntframe->frame_tag = DATA_FRAMETAG; ++ pattrib->ether_type = 0x890d; ++ pattrib->pctrl =0; ++ ++ _rtw_memcpy(pattrib->dst, mac_addr, ETH_ALEN); ++ _rtw_memcpy(pattrib->src, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ ++ update_tdls_attrib(padapter, pattrib); ++ ++ //init peer sta_info ++ ptdls_sta = rtw_get_stainfo(pstapriv, mac_addr); ++ if(ptdls_sta==NULL) ++ { ++ ptdls_sta = rtw_alloc_stainfo(pstapriv, mac_addr); ++ if(ptdls_sta) ++ { ++ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ if(!(ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE)) ++ ptdlsinfo->sta_cnt++; ++ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ if( ptdlsinfo->sta_cnt == (NUM_STA - 2) ) // -2: AP + BC/MC sta ++ { ++ ptdlsinfo->sta_maximum = _TRUE; ++ } ++ } ++ else ++ { ++ rtw_free_xmitbuf(pxmitpriv,pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ goto exit; ++ } ++ } ++ ++ if(ptdls_sta){ ++ ptdls_sta->tdls_sta_state |= TDLS_RESPONDER_STATE; ++ //for tdls; ptdls_sta->aid is used to fill dialogtoken ++ ptdls_sta->dialog = dialogtoken; ++ dialogtoken = (dialogtoken+1)%256; ++ ptdls_sta->TDLS_PeerKey_Lifetime = timeout_interval; ++ _set_timer( &ptdls_sta->handshake_timer, TDLS_HANDSHAKE_TIME ); ++ } ++ ++ pattrib->qsel=pattrib->priority; ++ if(rtw_xmit_tdls_coalesce(padapter, pmgntframe, TDLS_SETUP_REQUEST) !=_SUCCESS ){ ++ rtw_free_xmitbuf(pxmitpriv,pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ goto exit; ++ } ++ rtw_dump_xframe(padapter, pmgntframe); ++ ++exit: ++ ++ return; ++} ++ ++void issue_tdls_teardown(_adapter *padapter, u8 *mac_addr) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *ptdls_sta=NULL; ++ _irqL irqL; ++ ++ ptdls_sta = rtw_get_stainfo(pstapriv, mac_addr); ++ if(ptdls_sta==NULL){ ++ DBG_871X("issue tdls teardown unsuccessful\n"); ++ return; ++ }else{ ++ ptdls_sta->tdls_sta_state=TDLS_STATE_NONE; ++ } ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ ++ pmgntframe->frame_tag = DATA_FRAMETAG; ++ pattrib->ether_type = 0x890d; ++ pattrib->pctrl =0; ++ ++ _rtw_memcpy(pattrib->dst, mac_addr, ETH_ALEN); ++ _rtw_memcpy(pattrib->src, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ ++ update_tdls_attrib(padapter, pattrib); ++ pattrib->qsel=pattrib->priority; ++ if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, TDLS_TEARDOWN) != _SUCCESS) { ++ rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ goto exit; ++ } ++ rtw_dump_xframe(padapter, pmgntframe); ++ ++ if(ptdls_sta->tdls_sta_state & TDLS_CH_SWITCH_ON_STATE){ ++ rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CS_OFF); ++ } ++ ++ if( ptdls_sta->timer_flag == 1 ) ++ { ++ _enter_critical_bh(&(padapter->tdlsinfo.hdl_lock), &irqL); ++ ptdls_sta->timer_flag = 2; ++ _exit_critical_bh(&(padapter->tdlsinfo.hdl_lock), &irqL); ++ } ++ else ++ rtw_tdls_cmd(padapter, mac_addr, TDLS_FREE_STA ); ++ ++ ++exit: ++ ++ return; ++} ++ ++void issue_tdls_dis_req(_adapter *padapter, u8 *mac_addr) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ u8 baddr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ ++ pmgntframe->frame_tag = DATA_FRAMETAG; ++ pattrib->ether_type = 0x890d; ++ pattrib->pctrl =0; ++ ++ if(mac_addr == NULL) ++ _rtw_memcpy(pattrib->dst, baddr, ETH_ALEN); ++ else ++ _rtw_memcpy(pattrib->dst, mac_addr, ETH_ALEN); ++ ++ _rtw_memcpy(pattrib->src, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ ++ update_tdls_attrib(padapter, pattrib); ++ pattrib->qsel=pattrib->priority; ++ if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, TDLS_DISCOVERY_REQUEST) != _SUCCESS) { ++ rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ goto exit; ++ } ++ rtw_dump_xframe(padapter, pmgntframe); ++ DBG_871X("issue tdls dis req\n"); ++ ++exit: ++ ++ return; ++} ++ ++void issue_tdls_setup_rsp(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct rx_pkt_attrib *rx_pkt_pattrib = &precv_frame->u.hdr.attrib; ++ _irqL irqL; ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ ++ pmgntframe->frame_tag = DATA_FRAMETAG; ++ pattrib->ether_type = 0x890d; ++ pattrib->pctrl =0; ++ ++ _rtw_memcpy(pattrib->dst, rx_pkt_pattrib->src, ETH_ALEN); ++ _rtw_memcpy(pattrib->src, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ _rtw_memcpy(pattrib->ra, rx_pkt_pattrib->bssid, ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ ++ update_tdls_attrib(padapter, pattrib); ++ pattrib->qsel=pattrib->priority; ++ if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, TDLS_SETUP_RESPONSE) != _SUCCESS) { ++ rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ goto exit; ++ } ++ rtw_dump_xframe(padapter, pmgntframe); ++ ++exit: ++ ++ return; ++ ++} ++ ++void issue_tdls_setup_cfm(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct sta_info *ptdls_sta=NULL; ++ _irqL irqL; ++ ++ struct rx_pkt_attrib *rx_pkt_pattrib = & precv_frame->u.hdr.attrib; ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ ++ pmgntframe->frame_tag = DATA_FRAMETAG; ++ pattrib->ether_type = 0x890d; ++ pattrib->pctrl =0; ++ ++ _rtw_memcpy(pattrib->dst, rx_pkt_pattrib->src, ETH_ALEN); ++ _rtw_memcpy(pattrib->src, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ _rtw_memcpy(pattrib->ra, rx_pkt_pattrib->bssid, ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ ++ update_tdls_attrib(padapter, pattrib); ++ pattrib->qsel=pattrib->priority; ++ if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, TDLS_SETUP_CONFIRM) != _SUCCESS) { ++ rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ goto exit; ++ } ++ ++ rtw_dump_xframe(padapter, pmgntframe); ++ ++exit: ++ ++ return; ++ ++} ++ ++//TDLS Discovery Response frame is a management action frame ++void issue_tdls_dis_rsp(_adapter *padapter, union recv_frame *precv_frame, u8 dialog) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ ++ struct rx_pkt_attrib *rx_pkt_pattrib = &precv_frame->u.hdr.attrib; ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ // unicast probe request frame ++ _rtw_memcpy(pwlanhdr->addr1, rx_pkt_pattrib->src, ETH_ALEN); ++ _rtw_memcpy(pattrib->dst, pwlanhdr->addr1, ETH_ALEN); ++ ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pattrib->src, pwlanhdr->addr2, ETH_ALEN); ++ ++ _rtw_memcpy(pwlanhdr->addr3, rx_pkt_pattrib->bssid, ETH_ALEN); ++ _rtw_memcpy(pattrib->ra, pwlanhdr->addr3, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof (struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof (struct rtw_ieee80211_hdr_3addr); ++ ++ rtw_build_tdls_dis_rsp_ies(padapter, pmgntframe, pframe, dialog); ++ ++ pattrib->nr_frags = 1; ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++ return; ++} ++ ++void issue_tdls_peer_traffic_indication(_adapter *padapter, struct sta_info *ptdls_sta) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ ++ static u8 dialogtoken=0; ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ ++ pmgntframe->frame_tag = DATA_FRAMETAG; ++ pattrib->ether_type = 0x890d; ++ pattrib->pctrl =0; ++ ++ _rtw_memcpy(pattrib->dst, ptdls_sta->hwaddr, ETH_ALEN); ++ _rtw_memcpy(pattrib->src, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ ++ //for tdls; pattrib->nr_frags is used to fill dialogtoken ++ ptdls_sta->dialog = dialogtoken; ++ dialogtoken = (dialogtoken+1)%256; ++ //PTI frame's priority should be AC_VO ++ pattrib->priority = 7; ++ ++ update_tdls_attrib(padapter, pattrib); ++ pattrib->qsel=pattrib->priority; ++ if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, TDLS_PEER_TRAFFIC_INDICATION) != _SUCCESS) { ++ rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ goto exit; ++ } ++ rtw_dump_xframe(padapter, pmgntframe); ++ ++exit: ++ ++ return; ++} ++ ++void issue_tdls_ch_switch_req(_adapter *padapter, u8 *mac_addr) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ ++ pmgntframe->frame_tag = DATA_FRAMETAG; ++ pattrib->ether_type = 0x890d; ++ pattrib->pctrl =0; ++ ++ _rtw_memcpy(pattrib->dst, mac_addr, ETH_ALEN); ++ _rtw_memcpy(pattrib->src, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ ++ update_tdls_attrib(padapter, pattrib); ++ ++ pattrib->qsel=pattrib->priority; ++ if(rtw_xmit_tdls_coalesce(padapter, pmgntframe, TDLS_CHANNEL_SWITCH_REQUEST) !=_SUCCESS ){ ++ rtw_free_xmitbuf(pxmitpriv,pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ goto exit; ++ } ++ rtw_dump_xframe(padapter, pmgntframe); ++ ++exit: ++ ++ return; ++} ++ ++void issue_tdls_ch_switch_rsp(_adapter *padapter, u8 *mac_addr) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ ++ _irqL irqL; ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ ++ pmgntframe->frame_tag = DATA_FRAMETAG; ++ pattrib->ether_type = 0x890d; ++ pattrib->pctrl =0; ++ ++ _rtw_memcpy(pattrib->dst, mac_addr, ETH_ALEN); ++ _rtw_memcpy(pattrib->src, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ ++ update_tdls_attrib(padapter, pattrib); ++ ++ pattrib->qsel=pattrib->priority; ++/* ++ _enter_critical_bh(&pxmitpriv->lock, &irqL); ++ if(xmitframe_enqueue_for_tdls_sleeping_sta(padapter, pmgntframe)==_TRUE){ ++ _exit_critical_bh(&pxmitpriv->lock, &irqL); ++ return _FALSE; ++ } ++*/ ++ if(rtw_xmit_tdls_coalesce(padapter, pmgntframe, TDLS_CHANNEL_SWITCH_RESPONSE) !=_SUCCESS ){ ++ rtw_free_xmitbuf(pxmitpriv,pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ goto exit; ++ } ++ rtw_dump_xframe(padapter, pmgntframe); ++ ++exit: ++ ++ return; ++} ++ ++sint On_TDLS_Dis_Rsp(_adapter *adapter, union recv_frame *precv_frame) ++{ ++ struct sta_info *ptdls_sta = NULL, *psta = rtw_get_stainfo(&(adapter->stapriv), get_bssid(&(adapter->mlmepriv))); ++ struct recv_priv *precvpriv = &(adapter->recvpriv); ++ u8 *ptr = precv_frame->u.hdr.rx_data, *psa; ++ struct rx_pkt_attrib *pattrib = &(precv_frame->u.hdr.attrib); ++ struct tdls_info *ptdlsinfo = &(adapter->tdlsinfo); ++ u8 empty_addr[ETH_ALEN] = { 0x00 }; ++ int UndecoratedSmoothedPWDB; ++ ++ ++ //WFDTDLS: for sigma test, not to setup direct link automatically ++ ptdlsinfo->dev_discovered = 1; ++ ++#ifdef CONFIG_TDLS_AUTOSETUP ++ psa = get_sa(ptr); ++ ptdls_sta = rtw_get_stainfo(&(adapter->stapriv), psa); ++ ++ if(ptdls_sta != NULL) ++ { ++ ptdls_sta->tdls_sta_state |= TDLS_ALIVE_STATE; ++ ++ //Record the tdls sta with lowest signal strength ++ if( (ptdlsinfo->sta_maximum == _TRUE) && (ptdls_sta->alive_count >= 1) ) ++ { ++ if( _rtw_memcmp(ptdlsinfo->ss_record.macaddr, empty_addr, ETH_ALEN) ) ++ { ++ _rtw_memcpy(ptdlsinfo->ss_record.macaddr, psa, ETH_ALEN); ++ ptdlsinfo->ss_record.RxPWDBAll = pattrib->RxPWDBAll; ++ } ++ else ++ { ++ if( ptdlsinfo->ss_record.RxPWDBAll < pattrib->RxPWDBAll ) ++ { ++ _rtw_memcpy(ptdlsinfo->ss_record.macaddr, psa, ETH_ALEN); ++ ptdlsinfo->ss_record.RxPWDBAll = pattrib->RxPWDBAll; ++ } ++ } ++ } ++ ++ } ++ else ++ { ++ if( ptdlsinfo->sta_maximum == _TRUE) ++ { ++ if( _rtw_memcmp( ptdlsinfo->ss_record.macaddr, empty_addr, ETH_ALEN ) ) ++ { ++ //All traffics are busy, do not set up another direct link. ++ return _FAIL; ++ } ++ else ++ { ++ if( pattrib->RxPWDBAll > ptdlsinfo->ss_record.RxPWDBAll ) ++ { ++ issue_tdls_teardown(adapter, ptdlsinfo->ss_record.macaddr); ++ } ++ else ++ { ++ return _FAIL; ++ } ++ } ++ } ++ ++ adapter->HalFunc.GetHalDefVarHandler(adapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &UndecoratedSmoothedPWDB); ++ ++ if( pattrib->RxPWDBAll + TDLS_SIGNAL_THRESH >= UndecoratedSmoothedPWDB); ++ { ++ DBG_871X("pattrib->RxPWDBAll=%d, pdmpriv->UndecoratedSmoothedPWDB=%d\n", pattrib->RxPWDBAll, UndecoratedSmoothedPWDB); ++ issue_tdls_setup_req(adapter, psa); ++ } ++ } ++#endif //CONFIG_TDLS_AUTOSETUP ++ ++ return _SUCCESS; ++} ++ ++sint On_TDLS_Setup_Req(_adapter *adapter, union recv_frame *precv_frame) ++{ ++ struct tdls_info *ptdlsinfo = &adapter->tdlsinfo; ++ u8 *psa, *pmyid; ++ struct sta_info *ptdls_sta= NULL; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ struct security_priv *psecuritypriv = &adapter->securitypriv; ++ _irqL irqL; ++ struct rx_pkt_attrib *prx_pkt_attrib = &precv_frame->u.hdr.attrib; ++ u8 *prsnie, *ppairwise_cipher; ++ u8 i, k, pairwise_count; ++ u8 ccmp_have=0, rsnie_have=0; ++ u16 j; ++ u8 SNonce[32]; ++ u32 *timeout_interval; ++ sint parsing_length; //frame body length, without icv_len ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ u8 FIXED_IE = 5; ++ unsigned char supportRate[16]; ++ int supportRateNum = 0; ++ ++ psa = get_sa(ptr); ++ ptdls_sta = rtw_get_stainfo(pstapriv, psa); ++ ++ pmyid=myid(&(adapter->eeprompriv)); ++ ptr +=prx_pkt_attrib->hdrlen + prx_pkt_attrib->iv_len+LLC_HEADER_SIZE+TYPE_LENGTH_FIELD_SIZE+1; ++ parsing_length= ((union recv_frame *)precv_frame)->u.hdr.len ++ -prx_pkt_attrib->hdrlen ++ -prx_pkt_attrib->iv_len ++ -prx_pkt_attrib->icv_len ++ -LLC_HEADER_SIZE ++ -ETH_TYPE_LEN ++ -PAYLOAD_TYPE_LEN ++ -FIXED_IE; ++ ++ if(ptdlsinfo->ap_prohibited == _TRUE) ++ { ++ goto exit; ++ } ++ ++ if(ptdls_sta==NULL){ ++ ptdls_sta = rtw_alloc_stainfo(pstapriv, psa); ++ }else{ ++ if(ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE){ ++ //If the direct link is already set up ++ //Process as re-setup after tear down ++ DBG_871X("re-setup a direct link\n"); ++ } ++ //already receiving TDLS setup request ++ else if(ptdls_sta->tdls_sta_state & TDLS_INITIATOR_STATE){ ++ DBG_871X("receive duplicated TDLS setup request frame in handshaking\n"); ++ goto exit; ++ } ++ //When receiving and sending setup_req to the same link at the same time, STA with higher MAC_addr would be initiator ++ //following is to check out MAC_addr ++ else if(ptdls_sta->tdls_sta_state & TDLS_RESPONDER_STATE){ ++ DBG_871X("receive setup_req after sending setup_req\n"); ++ for (i=0;i<6;i++){ ++ if(*(pmyid+i)==*(psa+i)){ ++ } ++ else if(*(pmyid+i)>*(psa+i)){ ++ goto exit; ++ }else if(*(pmyid+i)<*(psa+i)){ ++ ptdls_sta->tdls_sta_state=TDLS_INITIATOR_STATE; ++ break; ++ } ++ } ++ } ++ } ++ ++ if(ptdls_sta) ++ { ++ ptdls_sta->dialog = *(ptr+2); //copy dialog token ++ ptdls_sta->stat_code = 0; ++ ++ //parsing information element ++ for(j=FIXED_IE; jElementID) ++ { ++ case _SUPPORTEDRATES_IE_: ++ _rtw_memcpy(supportRate, pIE->data, pIE->Length); ++ supportRateNum = pIE->Length; ++ break; ++ case _COUNTRY_IE_: ++ break; ++ case _EXT_SUPPORTEDRATES_IE_: ++ if(supportRateNum<=sizeof(supportRate)) ++ { ++ _rtw_memcpy(supportRate+supportRateNum, pIE->data, pIE->Length); ++ supportRateNum += pIE->Length; ++ } ++ break; ++ case _SUPPORTED_CH_IE_: ++ break; ++ case _RSN_IE_2_: ++ rsnie_have=1; ++ if(prx_pkt_attrib->encrypt){ ++ prsnie=(u8*)pIE; ++ //check whether initiator STA has CCMP pairwise_cipher. ++ ppairwise_cipher=prsnie+10; ++ _rtw_memcpy(&pairwise_count, (u16*)(ppairwise_cipher-2), 1); ++ for(k=0;kstat_code=72; ++ } ++ } ++ break; ++ case _EXT_CAP_IE_: ++ break; ++ case _VENDOR_SPECIFIC_IE_: ++ break; ++ case _FTIE_: ++ if(prx_pkt_attrib->encrypt) ++ _rtw_memcpy(SNonce, (ptr+j+52), 32); ++ break; ++ case _TIMEOUT_ITVL_IE_: ++ if(prx_pkt_attrib->encrypt) ++ timeout_interval = (u32 *)(ptr+j+3); ++ break; ++ case _RIC_Descriptor_IE_: ++ break; ++ case _HT_CAPABILITY_IE_: ++ rtw_tdls_process_ht_cap(adapter, ptdls_sta, pIE->data, pIE->Length); ++ break; ++ case EID_BSSCoexistence: ++ break; ++ case _LINK_ID_IE_: ++ if(_rtw_memcmp(get_bssid(pmlmepriv), pIE->data, 6) == _FALSE) ++ { ++ //not in the same BSS ++ ptdls_sta->stat_code=7; ++ } ++ break; ++ default: ++ break; ++ } ++ ++ j += (pIE->Length + 2); ++ ++ } ++ ++ //update station supportRate ++ ptdls_sta->bssratelen = supportRateNum; ++ _rtw_memcpy(ptdls_sta->bssrateset, supportRate, supportRateNum); ++ ++ //check status code ++ //if responder STA has/hasn't security on AP, but request hasn't/has RSNIE, it should reject ++ if(ptdls_sta->stat_code == 0 ) ++ { ++ if(rsnie_have && (prx_pkt_attrib->encrypt==0)){ ++ //security disabled ++ ptdls_sta->stat_code = 5; ++ }else if(rsnie_have==0 && (prx_pkt_attrib->encrypt)){ ++ //request haven't RSNIE ++ ptdls_sta->stat_code = 38; ++ } ++ ++#ifdef CONFIG_WFD ++ //WFD test plan version 0.18.2 test item 5.1.5 ++ //SoUT does not use TDLS if AP uses weak security ++ if ( adapter->wdinfo.wfd_tdls_enable ) ++ { ++ if(rsnie_have && (prx_pkt_attrib->encrypt != _AES_)) ++ { ++ ptdls_sta->stat_code = 5; ++ } ++ } ++#endif //CONFIG_WFD ++ } ++ ++ ptdls_sta->tdls_sta_state|= TDLS_INITIATOR_STATE; ++ if(prx_pkt_attrib->encrypt){ ++ _rtw_memcpy(ptdls_sta->SNonce, SNonce, 32); ++ _rtw_memcpy(&(ptdls_sta->TDLS_PeerKey_Lifetime), timeout_interval, 4); ++ } ++ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ if(!(ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE)) ++ ptdlsinfo->sta_cnt++; ++ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ if( ptdlsinfo->sta_cnt == (NUM_STA - 2) ) // -2: AP + BC/MC sta ++ { ++ ptdlsinfo->sta_maximum = _TRUE; ++ } ++ ++#ifdef CONFIG_WFD ++ rtw_tdls_process_wfd_ie(ptdlsinfo, ptr + FIXED_IE, parsing_length - FIXED_IE); ++#endif // CONFIG_WFD ++ ++ } ++ else ++ { ++ goto exit; ++ } ++ ++ issue_tdls_setup_rsp(adapter, precv_frame); ++ ++ if(ptdls_sta->stat_code==0) ++ { ++ _set_timer( &ptdls_sta->handshake_timer, TDLS_HANDSHAKE_TIME); ++ } ++ else //status code!=0 ; setup unsuccess ++ { ++ free_tdls_sta(adapter, ptdls_sta); ++ } ++ ++exit: ++ ++ return _FAIL; ++} ++ ++sint On_TDLS_Setup_Rsp(_adapter *adapter, union recv_frame *precv_frame) ++{ ++ struct tdls_info *ptdlsinfo = &adapter->tdlsinfo; ++ struct sta_info *ptdls_sta= NULL; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ _irqL irqL; ++ struct rx_pkt_attrib *prx_pkt_attrib = &precv_frame->u.hdr.attrib; ++ u8 *psa; ++ u16 stat_code; ++ sint parsing_length; //frame body length, without icv_len ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ u8 FIXED_IE =7; ++ u8 *pftie, *ptimeout_ie, *plinkid_ie, *prsnie, *pftie_mic, *ppairwise_cipher; ++ u16 pairwise_count, j, k; ++ u8 verify_ccmp=0; ++ unsigned char supportRate[16]; ++ int supportRateNum = 0; ++ ++ psa = get_sa(ptr); ++ ptdls_sta = rtw_get_stainfo(pstapriv, psa); ++ ++ if ( NULL == ptdls_sta ) ++ { ++ return _FAIL; ++ } ++ ++ ptr +=prx_pkt_attrib->hdrlen + prx_pkt_attrib->iv_len+LLC_HEADER_SIZE+TYPE_LENGTH_FIELD_SIZE+1; ++ parsing_length= ((union recv_frame *)precv_frame)->u.hdr.len ++ -prx_pkt_attrib->hdrlen ++ -prx_pkt_attrib->iv_len ++ -prx_pkt_attrib->icv_len ++ -LLC_HEADER_SIZE ++ -TYPE_LENGTH_FIELD_SIZE ++ -1 ++ -FIXED_IE; ++ ++ _rtw_memcpy(&stat_code, ptr+2, 2); ++ ++ if(stat_code!=0) ++ { ++ DBG_871X( "[%s] status_code = %d, free_tdls_sta\n", __FUNCTION__, stat_code ); ++ free_tdls_sta(adapter, ptdls_sta); ++ return _FAIL; ++ } ++ ++ stat_code = 0; ++ ++ //parsing information element ++ for(j=FIXED_IE; jElementID) ++ { ++ case _SUPPORTEDRATES_IE_: ++ _rtw_memcpy(supportRate, pIE->data, pIE->Length); ++ supportRateNum = pIE->Length; ++ break; ++ case _COUNTRY_IE_: ++ break; ++ case _EXT_SUPPORTEDRATES_IE_: ++ if(supportRateNum<=sizeof(supportRate)) ++ { ++ _rtw_memcpy(supportRate+supportRateNum, pIE->data, pIE->Length); ++ supportRateNum += pIE->Length; ++ } ++ break; ++ case _SUPPORTED_CH_IE_: ++ break; ++ case _RSN_IE_2_: ++ prsnie=(u8*)pIE; ++ //check whether responder STA has CCMP pairwise_cipher. ++ ppairwise_cipher=prsnie+10; ++ _rtw_memcpy(&pairwise_count, (u16*)(ppairwise_cipher-2), 2); ++ for(k=0;kANonce, (ptr+j+20), 32); ++ break; ++ case _TIMEOUT_ITVL_IE_: ++ ptimeout_ie=(u8*)pIE; ++ break; ++ case _RIC_Descriptor_IE_: ++ break; ++ case _HT_CAPABILITY_IE_: ++ rtw_tdls_process_ht_cap(adapter, ptdls_sta, pIE->data, pIE->Length); ++ break; ++ case EID_BSSCoexistence: ++ break; ++ case _LINK_ID_IE_: ++ plinkid_ie=(u8*)pIE; ++ break; ++ default: ++ break; ++ } ++ ++ j += (pIE->Length + 2); ++ ++ } ++ ++ //update station supportRate ++ ptdls_sta->bssratelen = supportRateNum; ++ _rtw_memcpy(ptdls_sta->bssrateset, supportRate, supportRateNum); ++ ++#ifdef CONFIG_WFD ++ rtw_tdls_process_wfd_ie(ptdlsinfo, ptr + FIXED_IE, parsing_length - FIXED_IE); ++#endif // CONFIG_WFD ++ ++ if(stat_code != 0) ++ { ++ ptdls_sta->stat_code = stat_code; ++ } ++ else ++ { ++ if(prx_pkt_attrib->encrypt) ++ { ++ if(verify_ccmp==1) ++ { ++ wpa_tdls_generate_tpk(adapter, ptdls_sta); ++ ptdls_sta->stat_code=0; ++ if(tdls_verify_mic(ptdls_sta->tpk.kck, 2, plinkid_ie, prsnie, ptimeout_ie, pftie)==0) //0: Invalid, 1: valid ++ { ++ free_tdls_sta(adapter, ptdls_sta); ++ return _FAIL; ++ } ++ } ++ else ++ { ++ ptdls_sta->stat_code=72; //invalide contents of RSNIE ++ } ++ ++ }else{ ++ ptdls_sta->stat_code=0; ++ } ++ } ++ ++ DBG_871X("issue_tdls_setup_cfm\n"); ++ issue_tdls_setup_cfm(adapter, precv_frame); ++ ++ if(ptdls_sta->stat_code==0) ++ { ++ ptdlsinfo->setup_state = TDLS_LINKED_STATE; ++ ++ if( ptdls_sta->tdls_sta_state & TDLS_RESPONDER_STATE ) ++ { ++ ptdls_sta->tdls_sta_state |= TDLS_LINKED_STATE; ++ _cancel_timer_ex( &ptdls_sta->handshake_timer); ++#ifdef CONFIG_TDLS_AUTOCHECKALIVE ++ _set_timer( &ptdls_sta->alive_timer1, TDLS_ALIVE_TIMER_PH1); ++#endif //CONFIG_TDLS_AUTOSETUP ++ } ++ ++ rtw_tdls_set_mac_id(ptdlsinfo, ptdls_sta); ++ rtw_tdls_set_key(adapter, prx_pkt_attrib, ptdls_sta); ++ ++ rtw_tdls_cmd(adapter, ptdls_sta->hwaddr, TDLS_WRCR); ++ ++ } ++ else //status code!=0 ; setup unsuccessful ++ { ++ free_tdls_sta(adapter, ptdls_sta); ++ } ++ ++ return _FAIL; ++ ++} ++ ++sint On_TDLS_Setup_Cfm(_adapter *adapter, union recv_frame *precv_frame) ++{ ++ struct tdls_info *ptdlsinfo = &adapter->tdlsinfo; ++ struct sta_info *ptdls_sta= NULL; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ _irqL irqL; ++ struct rx_pkt_attrib *prx_pkt_attrib = &precv_frame->u.hdr.attrib; ++ u8 *psa; ++ u16 stat_code; ++ sint parsing_length; ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ u8 FIXED_IE =5; ++ u8 *pftie, *ptimeout_ie, *plinkid_ie, *prsnie, *pftie_mic, *ppairwise_cipher; ++ u16 j, pairwise_count; ++ ++ psa = get_sa(ptr); ++ ptdls_sta = rtw_get_stainfo(pstapriv, psa); ++ ++ ptr +=prx_pkt_attrib->hdrlen + prx_pkt_attrib->iv_len+LLC_HEADER_SIZE+TYPE_LENGTH_FIELD_SIZE+1; ++ parsing_length= ((union recv_frame *)precv_frame)->u.hdr.len ++ -prx_pkt_attrib->hdrlen ++ -prx_pkt_attrib->iv_len ++ -prx_pkt_attrib->icv_len ++ -LLC_HEADER_SIZE ++ -ETH_TYPE_LEN ++ -PAYLOAD_TYPE_LEN ++ -FIXED_IE; ++ _rtw_memcpy(&stat_code, ptr+2, 2); ++ ++ if(stat_code!=0){ ++ DBG_871X( "[%s] stat_code = %d\n, free_tdls_sta", __FUNCTION__, stat_code ); ++ free_tdls_sta(adapter, ptdls_sta); ++ return _FAIL; ++ } ++ ++ if(prx_pkt_attrib->encrypt){ ++ //parsing information element ++ for(j=FIXED_IE; jElementID) ++ { ++ case _RSN_IE_2_: ++ prsnie=(u8*)pIE; ++ break; ++ case _VENDOR_SPECIFIC_IE_: ++ break; ++ case _FTIE_: ++ pftie=(u8*)pIE; ++ break; ++ case _TIMEOUT_ITVL_IE_: ++ ptimeout_ie=(u8*)pIE; ++ break; ++ case _HT_EXTRA_INFO_IE_: ++ break; ++ case _LINK_ID_IE_: ++ plinkid_ie=(u8*)pIE; ++ break; ++ default: ++ break; ++ } ++ ++ j += (pIE->Length + 2); ++ ++ } ++ ++ //verify mic in FTIE MIC field ++ if(tdls_verify_mic(ptdls_sta->tpk.kck, 3, plinkid_ie, prsnie, ptimeout_ie, pftie)==0){ //0: Invalid, 1: Valid ++ free_tdls_sta(adapter, ptdls_sta); ++ return _FAIL; ++ } ++ ++ } ++ ++ ptdlsinfo->setup_state = TDLS_LINKED_STATE; ++ if( ptdls_sta->tdls_sta_state & TDLS_INITIATOR_STATE ) ++ { ++ ptdls_sta->tdls_sta_state|=TDLS_LINKED_STATE; ++ _cancel_timer_ex( &ptdls_sta->handshake_timer); ++#ifdef CONFIG_TDLS_AUTOCHECKALIVE ++ _set_timer( &ptdls_sta->alive_timer1, TDLS_ALIVE_TIMER_PH1); ++#endif //CONFIG_TDLS_AUTOCHECKALIVE ++ } ++ ++ rtw_tdls_set_mac_id(ptdlsinfo, ptdls_sta); ++ rtw_tdls_set_key(adapter, prx_pkt_attrib, ptdls_sta); ++ ++ rtw_tdls_cmd(adapter, ptdls_sta->hwaddr, TDLS_WRCR); ++ ++ return _FAIL; ++ ++} ++ ++sint On_TDLS_Dis_Req(_adapter *adapter, union recv_frame *precv_frame) ++{ ++ struct rx_pkt_attrib *prx_pkt_attrib = &precv_frame->u.hdr.attrib; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct sta_info *psta_ap; ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ sint parsing_length; //frame body length, without icv_len ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ u8 FIXED_IE = 3, *dst, *pdialog = NULL; ++ u16 j; ++ ++ ptr +=prx_pkt_attrib->hdrlen + prx_pkt_attrib->iv_len + LLC_HEADER_SIZE+TYPE_LENGTH_FIELD_SIZE + 1; ++ pdialog=ptr+2; ++ ++ parsing_length= ((union recv_frame *)precv_frame)->u.hdr.len ++ -prx_pkt_attrib->hdrlen ++ -prx_pkt_attrib->iv_len ++ -prx_pkt_attrib->icv_len ++ -LLC_HEADER_SIZE ++ -TYPE_LENGTH_FIELD_SIZE ++ -1 ++ -FIXED_IE; ++ ++ //parsing information element ++ for(j=FIXED_IE; jElementID) ++ { ++ case _LINK_ID_IE_: ++ psta_ap = rtw_get_stainfo(pstapriv, pIE->data); ++ if(psta_ap == NULL) ++ { ++ goto exit; ++ } ++ dst = pIE->data + 12; ++ if( (MacAddr_isBcst(dst) == _FALSE) && (_rtw_memcmp(myid(&(adapter->eeprompriv)), dst, 6) == _FALSE) ) ++ { ++ goto exit; ++ } ++ break; ++ default: ++ break; ++ } ++ ++ j += (pIE->Length + 2); ++ ++ } ++ ++ //check frame contents ++ ++ issue_tdls_dis_rsp(adapter, precv_frame, *(pdialog) ); ++ ++exit: ++ ++ return _FAIL; ++ ++} ++ ++sint On_TDLS_Teardown(_adapter *adapter, union recv_frame *precv_frame) ++{ ++ u8 *psa; ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ struct rx_pkt_attrib *prx_pkt_attrib = &precv_frame->u.hdr.attrib; ++ struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct sta_info *ptdls_sta= NULL; ++ _irqL irqL; ++ ++ psa = get_sa(ptr); ++ ++ ptdls_sta = rtw_get_stainfo(pstapriv, psa); ++ if(ptdls_sta!=NULL){ ++ if(ptdls_sta->tdls_sta_state & TDLS_CH_SWITCH_ON_STATE){ ++ rtw_tdls_cmd(adapter, ptdls_sta->hwaddr, TDLS_CS_OFF); ++ } ++ free_tdls_sta(adapter, ptdls_sta); ++ } ++ ++ return _FAIL; ++ ++} ++ ++u8 TDLS_check_ch_state(uint state){ ++ if( (state & TDLS_CH_SWITCH_ON_STATE) && ++ (state & TDLS_AT_OFF_CH_STATE) && ++ (state & TDLS_PEER_AT_OFF_STATE) ){ ++ ++ if(state & TDLS_PEER_SLEEP_STATE) ++ return 2; //U-APSD + ch. switch ++ else ++ return 1; //ch. switch ++ }else ++ return 0; ++} ++ ++//we process buffered data for 1. U-APSD, 2. ch. switch, 3. U-APSD + ch. switch here ++sint On_TDLS_Peer_Traffic_Rsp(_adapter *adapter, union recv_frame *precv_frame) ++{ ++ struct tdls_info *ptdlsinfo = &adapter->tdlsinfo; ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ struct rx_pkt_attrib *pattrib = & precv_frame->u.hdr.attrib; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ //get peer sta infomation ++ struct sta_info *ptdls_sta = rtw_get_stainfo(pstapriv, pattrib->src); ++ u8 wmmps_ac=0, state=TDLS_check_ch_state(ptdls_sta->tdls_sta_state); ++ int i; ++ ++ ptdls_sta->sta_stats.rx_data_pkts++; ++ ++ //receive peer traffic response frame, sleeping STA wakes up ++ //ptdls_sta->tdls_sta_state &= ~(TDLS_PEER_SLEEP_STATE); ++ process_wmmps_data( adapter, precv_frame); ++ ++ // if noticed peer STA wakes up by receiving peer traffic response ++ // and we want to do channel swtiching, then we will transmit channel switch request first ++ if(ptdls_sta->tdls_sta_state & TDLS_APSD_CHSW_STATE){ ++ issue_tdls_ch_switch_req(adapter, pattrib->src); ++ ptdls_sta->tdls_sta_state &= ~(TDLS_APSD_CHSW_STATE); ++ return _FAIL; ++ } ++ ++ //check 4-AC queue bit ++ if(ptdls_sta->uapsd_vo || ptdls_sta->uapsd_vi || ptdls_sta->uapsd_be || ptdls_sta->uapsd_bk) ++ wmmps_ac=1; ++ ++ //if it's a direct link and have buffered frame ++ if(ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE){ ++ if(wmmps_ac && state) ++ { ++ _irqL irqL; ++ _list *xmitframe_plist, *xmitframe_phead; ++ struct xmit_frame *pxmitframe=NULL; ++ ++ _enter_critical_bh(&ptdls_sta->sleep_q.lock, &irqL); ++ ++ xmitframe_phead = get_list_head(&ptdls_sta->sleep_q); ++ xmitframe_plist = get_next(xmitframe_phead); ++ ++ //transmit buffered frames ++ while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) ++ { ++ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); ++ xmitframe_plist = get_next(xmitframe_plist); ++ rtw_list_delete(&pxmitframe->list); ++ ++ ptdls_sta->sleepq_len--; ++ if(ptdls_sta->sleepq_len>0){ ++ pxmitframe->attrib.mdata = 1; ++ pxmitframe->attrib.eosp = 0; ++ }else{ ++ pxmitframe->attrib.mdata = 0; ++ pxmitframe->attrib.eosp = 1; ++ } ++ //pxmitframe->attrib.triggered = 1; //maybe doesn't need in TDLS ++ if(adapter->HalFunc.hal_xmit(adapter, pxmitframe) == _TRUE) ++ { ++ rtw_os_xmit_complete(adapter, pxmitframe); ++ } ++ ++ } ++ ++ if(ptdls_sta->sleepq_len==0) ++ { ++ DBG_871X("no buffered packets for tdls to xmit\n"); ++ //on U-APSD + CH. switch state, when there is no buffered date to xmit, ++ // we should go back to base channel ++ if(state==2){ ++ rtw_tdls_cmd(adapter, ptdls_sta->hwaddr, TDLS_CS_OFF); ++ }else if(ptdls_sta->tdls_sta_state&TDLS_SW_OFF_STATE){ ++ ptdls_sta->tdls_sta_state &= ~(TDLS_SW_OFF_STATE); ++ ptdlsinfo->candidate_ch= pmlmeext->cur_channel; ++ issue_tdls_ch_switch_req(adapter, pattrib->src); ++ DBG_871X("issue tdls ch switch req back to base channel\n"); ++ } ++ ++ } ++ else ++ { ++ DBG_871X("error!psta->sleepq_len=%d\n", ptdls_sta->sleepq_len); ++ ptdls_sta->sleepq_len=0; ++ } ++ ++ _exit_critical_bh(&ptdls_sta->sleep_q.lock, &irqL); ++ ++ } ++ ++ } ++ ++ return _FAIL; ++} ++ ++sint On_TDLS_Ch_Switch_Req(_adapter *adapter, union recv_frame *precv_frame) ++{ ++ struct sta_info *ptdls_sta= NULL; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ struct rx_pkt_attrib *prx_pkt_attrib = &precv_frame->u.hdr.attrib; ++ u8 *psa; ++ sint parsing_length; ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ u8 FIXED_IE =3; ++ u16 j; ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ ++ psa = get_sa(ptr); ++ ptdls_sta = rtw_get_stainfo(pstapriv, psa); ++ ++ ptr +=prx_pkt_attrib->hdrlen + prx_pkt_attrib->iv_len+LLC_HEADER_SIZE+TYPE_LENGTH_FIELD_SIZE+1; ++ parsing_length= ((union recv_frame *)precv_frame)->u.hdr.len ++ -prx_pkt_attrib->hdrlen ++ -prx_pkt_attrib->iv_len ++ -prx_pkt_attrib->icv_len ++ -LLC_HEADER_SIZE ++ -ETH_TYPE_LEN ++ -PAYLOAD_TYPE_LEN ++ -FIXED_IE; ++ ++ ptdls_sta->off_ch = *(ptr+2); ++ ++ //parsing information element ++ for(j=FIXED_IE; jElementID) ++ { ++ case _COUNTRY_IE_: ++ break; ++ case _CH_SWTICH_ANNOUNCE_: ++ break; ++ case _LINK_ID_IE_: ++ break; ++ case _CH_SWITCH_TIMING_: ++ _rtw_memcpy(&ptdls_sta->ch_switch_time, pIE->data, 2); ++ _rtw_memcpy(&ptdls_sta->ch_switch_timeout, pIE->data+2, 2); ++ default: ++ break; ++ } ++ ++ j += (pIE->Length + 2); ++ ++ } ++ ++ //todo: check status ++ ptdls_sta->stat_code=0; ++ ptdls_sta->tdls_sta_state |= TDLS_CH_SWITCH_ON_STATE; ++ ++ issue_nulldata(adapter, NULL, 1, 0, 0); ++ ++ issue_tdls_ch_switch_rsp(adapter, psa); ++ ++ DBG_871X("issue tdls channel switch response\n"); ++ ++ if((ptdls_sta->tdls_sta_state & TDLS_CH_SWITCH_ON_STATE) && ptdls_sta->off_ch==pmlmeext->cur_channel){ ++ DBG_871X("back to base channel %x\n", pmlmeext->cur_channel); ++ ptdls_sta->option=7; ++ rtw_tdls_cmd(adapter, ptdls_sta->hwaddr, TDLS_BASE_CH); ++ }else{ ++ ptdls_sta->option=6; ++ rtw_tdls_cmd(adapter, ptdls_sta->hwaddr, TDLS_OFF_CH); ++ } ++ return _FAIL; ++} ++ ++sint On_TDLS_Ch_Switch_Rsp(_adapter *adapter, union recv_frame *precv_frame) ++{ ++ struct sta_info *ptdls_sta= NULL; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ struct rx_pkt_attrib *prx_pkt_attrib = &precv_frame->u.hdr.attrib; ++ u8 *psa; ++ sint parsing_length; ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ u8 FIXED_IE =4; ++ u16 stat_code, j, switch_time, switch_timeout; ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ ++ psa = get_sa(ptr); ++ ptdls_sta = rtw_get_stainfo(pstapriv, psa); ++ ++ //if channel switch is running and receiving Unsolicited TDLS Channel Switch Response, ++ //it will go back to base channel and terminate this channel switch procedure ++ if(ptdls_sta->tdls_sta_state & TDLS_CH_SWITCH_ON_STATE ){ ++ if(pmlmeext->cur_channel==ptdls_sta->off_ch){ ++ DBG_871X("back to base channel %x\n", pmlmeext->cur_channel); ++ ptdls_sta->option=7; ++ rtw_tdls_cmd(adapter, ptdls_sta->hwaddr, TDLS_OFF_CH); ++ }else{ ++ DBG_871X("receive unsolicited channel switch response \n"); ++ rtw_tdls_cmd(adapter, ptdls_sta->hwaddr, TDLS_CS_OFF); ++ } ++ return _FAIL; ++ } ++ ++ //avoiding duplicated or unconditional ch. switch. rsp ++ if((ptdls_sta->tdls_sta_state & TDLS_CH_SW_INITIATOR_STATE) != TDLS_CH_SW_INITIATOR_STATE) ++ return _FAIL; ++ ++ ptr +=prx_pkt_attrib->hdrlen + prx_pkt_attrib->iv_len+LLC_HEADER_SIZE+TYPE_LENGTH_FIELD_SIZE+1; ++ parsing_length= ((union recv_frame *)precv_frame)->u.hdr.len ++ -prx_pkt_attrib->hdrlen ++ -prx_pkt_attrib->iv_len ++ -prx_pkt_attrib->icv_len ++ -LLC_HEADER_SIZE ++ -ETH_TYPE_LEN ++ -PAYLOAD_TYPE_LEN ++ -FIXED_IE; ++ ++ _rtw_memcpy(&stat_code, ptr+2, 2); ++ ++ if(stat_code!=0){ ++ return _FAIL; ++ } ++ ++ //parsing information element ++ for(j=FIXED_IE; jElementID) ++ { ++ case _LINK_ID_IE_: ++ break; ++ case _CH_SWITCH_TIMING_: ++ _rtw_memcpy(&switch_time, pIE->data, 2); ++ if(switch_time > ptdls_sta->ch_switch_time) ++ _rtw_memcpy(&ptdls_sta->ch_switch_time, &switch_time, 2); ++ ++ _rtw_memcpy(&switch_timeout, pIE->data+2, 2); ++ if(switch_timeout > ptdls_sta->ch_switch_timeout) ++ _rtw_memcpy(&ptdls_sta->ch_switch_timeout, &switch_timeout, 2); ++ ++ default: ++ break; ++ } ++ ++ j += (pIE->Length + 2); ++ ++ } ++ ++ ptdls_sta->tdls_sta_state &= ~(TDLS_CH_SW_INITIATOR_STATE); ++ ptdls_sta->tdls_sta_state |=TDLS_CH_SWITCH_ON_STATE; ++ ++ //goto set_channel_workitem_callback() ++ ptdls_sta->option=6; ++ rtw_tdls_cmd(adapter, ptdls_sta->hwaddr, TDLS_OFF_CH); ++ ++ return _FAIL; ++} ++ ++#ifdef CONFIG_WFD ++void wfd_ie_tdls(_adapter * padapter, u8 *pframe, u32 *pktlen ) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wifi_display_info *pwfd_info = padapter->tdlsinfo.wfd_info; ++ u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; ++ u32 wfdielen = 0; ++ ++ // WFD OUI ++ wfdielen = 0; ++ wfdie[ wfdielen++ ] = 0x50; ++ wfdie[ wfdielen++ ] = 0x6F; ++ wfdie[ wfdielen++ ] = 0x9A; ++ wfdie[ wfdielen++ ] = 0x0A; // WFA WFD v1.0 ++ ++ // Commented by Albert 20110825 ++ // According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes ++ // 1. WFD Device Information ++ // 2. Associated BSSID ( Optional ) ++ // 3. Local IP Adress ( Optional ) ++ ++ // WFD Device Information ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value1: ++ // WFD device information ++ // available for WFD session + Preferred TDLS + WSD ( WFD Service Discovery ) ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL ++ | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_WSD); ++ wfdielen += 2; ++ ++ // Value2: ++ // Session Management Control Port ++ // Default TCP port for RTSP messages is 554 ++ RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport ); ++ wfdielen += 2; ++ ++ // Value3: ++ // WFD Device Maximum Throughput ++ // 300Mbps is the maximum throughput ++ RTW_PUT_BE16(wfdie + wfdielen, 300); ++ wfdielen += 2; ++ ++ // Associated BSSID ATTR ++ // Type: ++ wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0006); ++ wfdielen += 2; ++ ++ // Value: ++ // Associated BSSID ++ if ( check_fwstate( pmlmepriv, _FW_LINKED) == _TRUE ) ++ { ++ _rtw_memcpy( wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN ); ++ } ++ else ++ { ++ _rtw_memset( wfdie + wfdielen, 0x00, ETH_ALEN ); ++ } ++ ++ // Local IP Address ATTR ++ wfdie[ wfdielen++ ] = WFD_ATTR_LOCAL_IP_ADDR; ++ ++ // Length: ++ // Note: In the WFD specification, the size of length field is 2. ++ RTW_PUT_BE16(wfdie + wfdielen, 0x0005); ++ wfdielen += 2; ++ ++ // Version: ++ // 0x01: Version1;IPv4 ++ wfdie[ wfdielen++ ] = 0x01; ++ ++ // IPv4 Address ++ _rtw_memcpy( wfdie + wfdielen, pwfd_info->ip_address, 4 ); ++ wfdielen += 4; ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, pktlen); ++ ++} ++#endif //CONFIG_WFD ++ ++void rtw_build_tdls_setup_req_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct sta_info *ptdls_sta=rtw_get_stainfo( (&padapter->stapriv) , pattrib->dst); ++ ++ u8 payload_type = 0x02; ++ u8 category = RTW_WLAN_CATEGORY_TDLS; ++ u8 action = TDLS_SETUP_REQUEST; ++ u8 bssrate[NDIS_802_11_LENGTH_RATES_EX]; //Use NDIS_802_11_LENGTH_RATES_EX in order to call func.rtw_set_supported_rate ++ int bssrate_len = 0, i = 0 ; ++ u8 more_supportedrates = 0; ++ unsigned int ie_len; ++ u8 *p; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 link_id_addr[18] = {0}; ++ u8 iedata=0; ++ u8 sup_ch[ 30 * 2 ] = {0x00 }, sup_ch_idx = 0, idx_5g = 2; //For supported channel ++ u8 timeout_itvl[5]; //set timeout interval to maximum value ++ u32 time; ++ ++ //SNonce ++ if(pattrib->encrypt){ ++ for(i=0;i<8;i++){ ++ time=rtw_get_current_time(); ++ _rtw_memcpy(&ptdls_sta->SNonce[4*i], (u8 *)&time, 4); ++ } ++ } ++ ++ //payload type ++ pframe = rtw_set_fixed_ie(pframe, 1, &(payload_type), &(pattrib->pktlen)); ++ //category, action, dialog token ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(ptdls_sta->dialog), &(pattrib->pktlen)); ++ ++ //capability ++ _rtw_memcpy(pframe, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2); ++ ++ if(pattrib->encrypt) ++ *pframe =*pframe | BIT(4); ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ //supported rates ++ rtw_set_supported_rate(bssrate, WIRELESS_11BG_24N); ++ bssrate_len = IEEE80211_CCK_RATE_LEN + IEEE80211_NUM_OFDM_RATESLEN; ++ ++ if (bssrate_len > 8) ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen)); ++ more_supportedrates = 1; ++ } ++ else ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen)); ++ } ++ ++ //country(optional) ++ //extended supported rates ++ if(more_supportedrates==1){ ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen)); ++ } ++ ++ //supported channels ++ pframe = rtw_tdls_set_sup_ch(pmlmeext, pframe, pattrib); ++ ++ // SRC IE ++ pframe = rtw_set_ie( pframe, _SRC_IE_, 16, TDLS_SRC, &(pattrib->pktlen)); ++ ++ //RSNIE ++ if(pattrib->encrypt) ++ pframe = rtw_set_ie(pframe, _RSN_IE_2_, 20, TDLS_RSNIE, &(pattrib->pktlen)); ++ ++ //extended capabilities ++ pframe = rtw_set_ie(pframe, _EXT_CAP_IE_ , 5, TDLS_EXT_CAPIE, &(pattrib->pktlen)); ++ ++ //QoS capability(WMM_IE) ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 7, TDLS_WMMIE, &(pattrib->pktlen)); ++ ++ ++ if(pattrib->encrypt){ ++ //FTIE ++ _rtw_memset(pframe, 0, 84); //All fields except SNonce shall be set to 0 ++ _rtw_memset(pframe, _FTIE_, 1); //version ++ _rtw_memset((pframe+1), 82, 1); //length ++ _rtw_memcpy((pframe+52), ptdls_sta->SNonce, 32); ++ pframe += 84; ++ pattrib->pktlen += 84; ++ ++ //Timeout interval ++ timeout_itvl[0]=0x02; ++ _rtw_memcpy(timeout_itvl+1, (u8 *)(&ptdls_sta->TDLS_PeerKey_Lifetime), 4); ++ pframe = rtw_set_ie(pframe, _TIMEOUT_ITVL_IE_, 5, timeout_itvl, &(pattrib->pktlen)); ++ } ++ ++ //Sup_reg_classes(optional) ++ //HT capabilities ++ pframe = rtw_tdls_set_ht_cap(padapter, pframe, pattrib); ++ ++ //20/40 BSS coexistence ++ if(pmlmepriv->num_FortyMHzIntolerant>0) ++ iedata |= BIT(2);//20 MHz BSS Width Request ++ pframe = rtw_set_ie(pframe, EID_BSSCoexistence, 1, &iedata, &(pattrib->pktlen)); ++ ++ //Link identifier ++ _rtw_memcpy(link_id_addr, pattrib->ra, 6); ++ _rtw_memcpy((link_id_addr+6), pattrib->src, 6); ++ _rtw_memcpy((link_id_addr+12), pattrib->dst, 6); ++ pframe = rtw_set_ie(pframe, _LINK_ID_IE_, 18, link_id_addr, &(pattrib->pktlen)); ++ ++#ifdef CONFIG_WFD ++ wfd_ie_tdls( padapter, pframe, &(pattrib->pktlen) ); ++#endif //CONFIG_WFD ++ ++} ++ ++void rtw_build_tdls_setup_rsp_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe) ++{ ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct sta_info *ptdls_sta; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ ++ u8 payload_type = 0x02; ++ unsigned char category = RTW_WLAN_CATEGORY_TDLS; ++ unsigned char action = TDLS_SETUP_RESPONSE; ++ unsigned char bssrate[NDIS_802_11_LENGTH_RATES_EX]; ++ int bssrate_len = 0; ++ u8 more_supportedrates = 0; ++ unsigned int ie_len; ++ unsigned char *p; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 link_id_addr[18] = {0}; ++ u8 iedata=0; ++ u8 timeout_itvl[5]; //setup response timeout interval will copy from request ++ u8 ANonce[32]; //maybe it can put in ontdls_req ++ u8 k; //for random ANonce ++ u8 *pftie, *ptimeout_ie, *plinkid_ie, *prsnie, *pftie_mic; ++ u32 time; ++ ++ ptdls_sta = rtw_get_stainfo( &(padapter->stapriv) , pattrib->dst); ++ ++ if(ptdls_sta == NULL ) ++ { ++ DBG_871X("[%s] %d\n", __FUNCTION__, __LINE__); ++ return; ++ } ++ ++ if(pattrib->encrypt){ ++ for(k=0;k<8;k++){ ++ time=rtw_get_current_time(); ++ _rtw_memcpy(&ptdls_sta->ANonce[4*k], (u8*)&time, 4); ++ } ++ } ++ ++ //payload type ++ pframe = rtw_set_fixed_ie(pframe, 1, &(payload_type), &(pattrib->pktlen)); ++ //category, action, status code ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 2, (u8 *)&ptdls_sta->stat_code, &(pattrib->pktlen)); ++ ++ if(ptdls_sta->stat_code!=0) //invalid setup request ++ { ++ DBG_871X("ptdls_sta->stat_code:%04x \n", ptdls_sta->stat_code); ++ return; ++ } ++ ++ //dialog token ++ pframe = rtw_set_fixed_ie(pframe, 1, &(ptdls_sta->dialog), &(pattrib->pktlen)); ++ ++ //capability ++ _rtw_memcpy(pframe, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2); ++ ++ if(pattrib->encrypt ) ++ *pframe =*pframe | BIT(4); ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ //supported rates ++ rtw_set_supported_rate(bssrate, WIRELESS_11BG_24N); ++ bssrate_len = IEEE80211_CCK_RATE_LEN + IEEE80211_NUM_OFDM_RATESLEN; ++ ++ if (bssrate_len > 8) ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen)); ++ more_supportedrates = 1; ++ } ++ else ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen)); ++ } ++ ++ //country(optional) ++ //extended supported rates ++ if(more_supportedrates==1){ ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen)); ++ } ++ ++ //supported channels ++ pframe = rtw_tdls_set_sup_ch(pmlmeext, pframe, pattrib); ++ ++ // SRC IE ++ pframe = rtw_set_ie(pframe, _SRC_IE_ , 16, TDLS_SRC, &(pattrib->pktlen)); ++ ++ //RSNIE ++ if(pattrib->encrypt){ ++ prsnie = pframe; ++ pframe = rtw_set_ie(pframe, _RSN_IE_2_, 20, TDLS_RSNIE, &(pattrib->pktlen)); ++ } ++ ++ //extended capabilities ++ pframe = rtw_set_ie(pframe, _EXT_CAP_IE_ , 5, TDLS_EXT_CAPIE, &(pattrib->pktlen)); ++ ++ //QoS capability(WMM_IE) ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 7, TDLS_WMMIE, &(pattrib->pktlen)); ++ ++ if(pattrib->encrypt){ ++ wpa_tdls_generate_tpk(padapter, ptdls_sta); ++ ++ //FTIE ++ pftie = pframe; ++ pftie_mic = pframe+4; ++ _rtw_memset(pframe, 0, 84); //All fields except SNonce shall be set to 0 ++ _rtw_memset(pframe, _FTIE_, 1); //version ++ _rtw_memset((pframe+1), 82, 1); //length ++ _rtw_memcpy((pframe+20), ptdls_sta->ANonce, 32); ++ _rtw_memcpy((pframe+52), ptdls_sta->SNonce, 32); ++ pframe += 84; ++ pattrib->pktlen += 84; ++ ++ //Timeout interval ++ ptimeout_ie = pframe; ++ timeout_itvl[0]=0x02; ++ _rtw_memcpy(timeout_itvl+1, (u8 *)(&ptdls_sta->TDLS_PeerKey_Lifetime), 4); ++ pframe = rtw_set_ie(pframe, _TIMEOUT_ITVL_IE_, 5, timeout_itvl, &(pattrib->pktlen)); ++ } ++ ++ //Sup_reg_classes(optional) ++ //HT capabilities ++ pframe = rtw_tdls_set_ht_cap(padapter, pframe, pattrib); ++ ++ //20/40 BSS coexistence ++ if(pmlmepriv->num_FortyMHzIntolerant>0) ++ iedata |= BIT(2);//20 MHz BSS Width Request ++ pframe = rtw_set_ie(pframe, EID_BSSCoexistence, 1, &iedata, &(pattrib->pktlen)); ++ ++ //Link identifier ++ plinkid_ie = pframe; ++ _rtw_memcpy(link_id_addr, pattrib->ra, 6); ++ _rtw_memcpy((link_id_addr+6), pattrib->dst, 6); ++ _rtw_memcpy((link_id_addr+12), pattrib->src, 6); ++ pframe = rtw_set_ie(pframe, _LINK_ID_IE_, 18, link_id_addr, &(pattrib->pktlen)); ++ ++ //fill FTIE mic ++ if(pattrib->encrypt) ++ wpa_tdls_ftie_mic(ptdls_sta->tpk.kck, 2, plinkid_ie, prsnie, ptimeout_ie, pftie, pftie_mic); ++ ++#ifdef CONFIG_WFD ++ wfd_ie_tdls( padapter, pframe, &(pattrib->pktlen) ); ++#endif //CONFIG_WFD ++ ++} ++ ++void rtw_build_tdls_setup_cfm_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe) ++{ ++ ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct sta_info *ptdls_sta=rtw_get_stainfo( (&padapter->stapriv) , pattrib->dst); ++ ++ u8 payload_type = 0x02; ++ unsigned char category = RTW_WLAN_CATEGORY_TDLS; ++ unsigned char action = TDLS_SETUP_CONFIRM; ++ u8 more_supportedrates = 0; ++ unsigned int ie_len; ++ unsigned char *p; ++ u8 timeout_itvl[5]; //set timeout interval to maximum value ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 link_id_addr[18] = {0}; ++ u8 *pftie, *ptimeout_ie, *plinkid_ie, *prsnie, *pftie_mic; ++ ++ //payload type ++ pframe = rtw_set_fixed_ie(pframe, 1, &(payload_type), &(pattrib->pktlen)); ++ //category, action, status code, dialog token ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 2, (u8 *)&ptdls_sta->stat_code, &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(ptdls_sta->dialog), &(pattrib->pktlen)); ++ ++ if(ptdls_sta->stat_code!=0) //invalid setup request ++ return; ++ ++ //RSNIE ++ if(pattrib->encrypt){ ++ prsnie = pframe; ++ pframe = rtw_set_ie(pframe, _RSN_IE_2_, 20, TDLS_RSNIE, &(pattrib->pktlen)); ++ } ++ ++ //EDCA param set; WMM param ele. ++ if(pattrib->encrypt){ ++ //FTIE ++ pftie = pframe; ++ pftie_mic = pframe+4; ++ _rtw_memset(pframe, 0, 84); //All fields except SNonce shall be set to 0 ++ _rtw_memset(pframe, _FTIE_, 1); //version ++ _rtw_memset((pframe+1), 82, 1); //length ++ _rtw_memcpy((pframe+20), ptdls_sta->ANonce, 32); ++ _rtw_memcpy((pframe+52), ptdls_sta->SNonce, 32); ++ pframe += 84; ++ pattrib->pktlen += 84; ++ ++ //Timeout interval ++ ptimeout_ie = pframe; ++ timeout_itvl[0]=0x02; ++ _rtw_memcpy(timeout_itvl+1, (u8 *)(&ptdls_sta->TDLS_PeerKey_Lifetime), 4); ++ ptdls_sta->TPK_count=0; ++ _set_timer(&ptdls_sta->TPK_timer, ptdls_sta->TDLS_PeerKey_Lifetime/TPK_RESEND_COUNT); ++ pframe = rtw_set_ie(pframe, _TIMEOUT_ITVL_IE_, 5, timeout_itvl, &(pattrib->pktlen)); ++ } ++ ++ //HT operation; todo ++ //Link identifier ++ plinkid_ie = pframe; ++ _rtw_memcpy(link_id_addr, pattrib->ra, 6); ++ _rtw_memcpy((link_id_addr+6), pattrib->src, 6); ++ _rtw_memcpy((link_id_addr+12), pattrib->dst, 6); ++ pframe = rtw_set_ie(pframe, _LINK_ID_IE_, 18, link_id_addr, &(pattrib->pktlen)); ++ ++ //fill FTIE mic ++ if(pattrib->encrypt) ++ wpa_tdls_ftie_mic(ptdls_sta->tpk.kck, 3, plinkid_ie, prsnie, ptimeout_ie, pftie, pftie_mic); ++ ++} ++ ++void rtw_build_tdls_teardown_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe) ++{ ++ ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ u8 payload_type = 0x02; ++ unsigned char category = RTW_WLAN_CATEGORY_TDLS; ++ unsigned char action = TDLS_TEARDOWN; ++ u8 link_id_addr[18] = {0}; ++ ++ struct sta_info *ptdls_sta = rtw_get_stainfo( &(padapter->stapriv) , pattrib->dst); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ //payload type ++ pframe = rtw_set_fixed_ie(pframe, 1, &(payload_type), &(pattrib->pktlen)); ++ //category, action, reason code ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, (u8 *)&ptdls_sta->stat_code, &(pattrib->pktlen)); ++ ++ //Link identifier ++ if(ptdls_sta->tdls_sta_state & TDLS_INITIATOR_STATE){ ++ _rtw_memcpy(link_id_addr, pattrib->ra, 6); ++ _rtw_memcpy((link_id_addr+6), pattrib->src, 6); ++ _rtw_memcpy((link_id_addr+12), pattrib->dst, 6); ++ }else if(ptdls_sta->tdls_sta_state & TDLS_RESPONDER_STATE){ ++ _rtw_memcpy(link_id_addr, pattrib->ra, 6); ++ _rtw_memcpy((link_id_addr+6), pattrib->dst, 6); ++ _rtw_memcpy((link_id_addr+12), pattrib->src, 6); ++ } ++ pframe = rtw_set_ie(pframe, _LINK_ID_IE_, 18, link_id_addr, &(pattrib->pktlen)); ++ ++} ++ ++void rtw_build_tdls_dis_req_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe) ++{ ++ ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ u8 payload_type = 0x02; ++ u8 category = RTW_WLAN_CATEGORY_TDLS; ++ u8 action = TDLS_DISCOVERY_REQUEST; ++ u8 link_id_addr[18] = {0}; ++ static u8 dialogtoken=0; ++ ++ //payload type ++ pframe = rtw_set_fixed_ie(pframe, 1, &(payload_type), &(pattrib->pktlen)); ++ //category, action, reason code ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogtoken), &(pattrib->pktlen)); ++ dialogtoken = (dialogtoken+1)%256; ++ ++ //Link identifier ++ _rtw_memcpy(link_id_addr, pattrib->ra, 6); ++ _rtw_memcpy((link_id_addr+6), pattrib->src, 6); ++ _rtw_memcpy((link_id_addr+12), pattrib->dst, 6); ++ pframe = rtw_set_ie(pframe, _LINK_ID_IE_, 18, link_id_addr, &(pattrib->pktlen)); ++ ++} ++ ++void rtw_build_tdls_dis_rsp_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe, u8 dialog) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ ++ u8 category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = TDLS_DISCOVERY_RESPONSE; ++ u8 bssrate[NDIS_802_11_LENGTH_RATES_EX]; ++ int bssrate_len = 0; ++ u8 more_supportedrates = 0; ++ u8 *p; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 link_id_addr[18] = {0}; ++ u8 iedata=0; ++ u8 timeout_itvl[5]; //set timeout interval to maximum value ++ u32 timeout_interval= TPK_RESEND_COUNT * 1000; ++ ++ //category, action, dialog token ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(dialog), &(pattrib->pktlen)); ++ ++ //capability ++ _rtw_memcpy(pframe, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2); ++ ++ if(pattrib->encrypt) ++ *pframe =*pframe | BIT(4); ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ //supported rates ++ rtw_set_supported_rate(bssrate, WIRELESS_11BG_24N); ++ bssrate_len = IEEE80211_CCK_RATE_LEN + IEEE80211_NUM_OFDM_RATESLEN; ++ ++ if (bssrate_len > 8) ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen)); ++ more_supportedrates = 1; ++ } ++ else ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen)); ++ } ++ ++ //extended supported rates ++ if(more_supportedrates==1){ ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen)); ++ } ++ ++ //supported channels ++ pframe = rtw_tdls_set_sup_ch(pmlmeext, pframe, pattrib); ++ ++ //RSNIE ++ if(pattrib->encrypt) ++ pframe = rtw_set_ie(pframe, _RSN_IE_2_, 20, TDLS_RSNIE, &(pattrib->pktlen)); ++ ++ //extended capability ++ pframe = rtw_set_ie(pframe, _EXT_CAP_IE_ , 5, TDLS_EXT_CAPIE, &(pattrib->pktlen)); ++ ++ if(pattrib->encrypt){ ++ //FTIE ++ _rtw_memset(pframe, 0, 84); //All fields shall be set to 0 ++ _rtw_memset(pframe, _FTIE_, 1); //version ++ _rtw_memset((pframe+1), 82, 1); //length ++ pframe += 84; ++ pattrib->pktlen += 84; ++ ++ //Timeout interval ++ timeout_itvl[0]=0x02; ++ _rtw_memcpy(timeout_itvl+1, &timeout_interval, 4); ++ pframe = rtw_set_ie(pframe, _TIMEOUT_ITVL_IE_, 5, timeout_itvl, &(pattrib->pktlen)); ++ } ++ ++ //Sup_reg_classes(optional) ++ //HT capabilities ++ pframe = rtw_tdls_set_ht_cap(padapter, pframe, pattrib); ++ ++ //20/40 BSS coexistence ++ if(pmlmepriv->num_FortyMHzIntolerant>0) ++ iedata |= BIT(2);//20 MHz BSS Width Request ++ pframe = rtw_set_ie(pframe, EID_BSSCoexistence, 1, &iedata, &(pattrib->pktlen)); ++ ++ //Link identifier ++ _rtw_memcpy(link_id_addr, pattrib->ra, 6); ++ _rtw_memcpy((link_id_addr+6), pattrib->dst, 6); ++ _rtw_memcpy((link_id_addr+12), pattrib->src, 6); ++ pframe = rtw_set_ie(pframe, _LINK_ID_IE_, 18, link_id_addr, &(pattrib->pktlen)); ++ ++} ++ ++void rtw_build_tdls_peer_traffic_indication_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe) ++{ ++ ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ u8 payload_type = 0x02; ++ unsigned char category = RTW_WLAN_CATEGORY_TDLS; ++ unsigned char action = TDLS_PEER_TRAFFIC_INDICATION; ++ ++ u8 link_id_addr[18] = {0}; ++ u8 AC_queue=0; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *ptdls_sta = rtw_get_stainfo(pstapriv, pattrib->dst); ++ ++ //payload type ++ pframe = rtw_set_fixed_ie(pframe, 1, &(payload_type), &(pattrib->pktlen)); ++ //category, action, reason code ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(ptdls_sta->dialog), &(pattrib->pktlen)); ++ ++ //Link identifier ++ _rtw_memcpy(link_id_addr, pattrib->ra, 6); ++ _rtw_memcpy((link_id_addr+6), pattrib->src, 6); ++ _rtw_memcpy((link_id_addr+12), pattrib->dst, 6); ++ pframe = rtw_set_ie(pframe, _LINK_ID_IE_, 18, link_id_addr, &(pattrib->pktlen)); ++ ++ //PTI control ++ //PU buffer status ++ if(ptdls_sta->uapsd_bk&BIT(1)) ++ AC_queue=BIT(0); ++ if(ptdls_sta->uapsd_be&BIT(1)) ++ AC_queue=BIT(1); ++ if(ptdls_sta->uapsd_vi&BIT(1)) ++ AC_queue=BIT(2); ++ if(ptdls_sta->uapsd_vo&BIT(1)) ++ AC_queue=BIT(3); ++ pframe = rtw_set_ie(pframe, _PTI_BUFFER_STATUS_, 1, &AC_queue, &(pattrib->pktlen)); ++ ++} ++ ++void rtw_build_tdls_ch_switch_req_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe) ++{ ++ ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ u8 payload_type = 0x02; ++ unsigned char category = RTW_WLAN_CATEGORY_TDLS; ++ unsigned char action = TDLS_CHANNEL_SWITCH_REQUEST; ++ u8 link_id_addr[18] = {0}; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *ptdls_sta = rtw_get_stainfo(pstapriv, pattrib->dst); ++ u8 ch_switch_timing[4] = {0}; ++ u16 switch_time= CH_SWITCH_TIME, switch_timeout=CH_SWITCH_TIMEOUT; ++ ++ //payload type ++ pframe = rtw_set_fixed_ie(pframe, 1, &(payload_type), &(pattrib->pktlen)); ++ //category, action, target_ch ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(ptdlsinfo->candidate_ch), &(pattrib->pktlen)); ++ ++ //Link identifier ++ _rtw_memcpy(link_id_addr, pattrib->ra, 6); ++ _rtw_memcpy((link_id_addr+6), pattrib->src, 6); ++ _rtw_memcpy((link_id_addr+12), pattrib->dst, 6); ++ pframe = rtw_set_ie(pframe, _LINK_ID_IE_, 18, link_id_addr, &(pattrib->pktlen)); ++ ++ //ch switch timing ++ _rtw_memcpy(ch_switch_timing, &switch_time, 2); ++ _rtw_memcpy(ch_switch_timing+2, &switch_timeout, 2); ++ pframe = rtw_set_ie(pframe, _CH_SWITCH_TIMING_, 4, ch_switch_timing, &(pattrib->pktlen)); ++ ++ //update ch switch attrib to sta_info ++ ptdls_sta->off_ch=ptdlsinfo->candidate_ch; ++ ptdls_sta->ch_switch_time=switch_time; ++ ptdls_sta->ch_switch_timeout=switch_timeout; ++ ++} ++ ++void rtw_build_tdls_ch_switch_rsp_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe) ++{ ++ ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ u8 payload_type = 0x02; ++ unsigned char category = RTW_WLAN_CATEGORY_TDLS; ++ unsigned char action = TDLS_CHANNEL_SWITCH_RESPONSE; ++ u8 link_id_addr[18] = {0}; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *ptdls_sta = rtw_get_stainfo(pstapriv, pattrib->dst); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u8 ch_switch_timing[4] = {0}; ++ ++ //payload type ++ pframe = rtw_set_fixed_ie(pframe, 1, &(payload_type), &(pattrib->pktlen)); ++ //category, action, status_code ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 2, (u8 *)&ptdls_sta->stat_code, &(pattrib->pktlen)); ++ ++ //Link identifier ++ _rtw_memcpy(link_id_addr, pattrib->ra, 6); ++ _rtw_memcpy((link_id_addr+6), pattrib->src, 6); ++ _rtw_memcpy((link_id_addr+12), pattrib->dst, 6); ++ pframe = rtw_set_ie(pframe, _LINK_ID_IE_, 18, link_id_addr, &(pattrib->pktlen)); ++ ++ //ch switch timing ++ _rtw_memcpy(ch_switch_timing, &ptdls_sta->ch_switch_time, 2); ++ _rtw_memcpy(ch_switch_timing+2, &ptdls_sta->ch_switch_timeout, 2); ++ pframe = rtw_set_ie(pframe, _CH_SWITCH_TIMING_, 4, ch_switch_timing, &(pattrib->pktlen)); ++ ++} ++ ++#ifdef CONFIG_WFD ++void rtw_build_tunneled_probe_req_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe) ++{ ++ ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ struct wifidirect_info *pbuddy_wdinfo = &padapter->pbuddy_adapter->wdinfo; ++ u8 payload_type = 0x02; ++ u8 category = RTW_WLAN_CATEGORY_P2P; ++ u8 WFA_OUI[3] = { 0x50, 0x6f, 0x9a}; ++ u8 probe_req = 4; ++ u8 wfdielen = 0; ++ ++ //payload type ++ pframe = rtw_set_fixed_ie(pframe, 1, &(payload_type), &(pattrib->pktlen)); ++ //category, OUI, frame_body_type ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 3, WFA_OUI, &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(probe_req), &(pattrib->pktlen)); ++ ++ if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ wfdielen = build_probe_req_wfd_ie(pwdinfo, pframe); ++ pframe += wfdielen; ++ pattrib->pktlen += wfdielen; ++ } ++ else if(!rtw_p2p_chk_state(pbuddy_wdinfo, P2P_STATE_NONE)) ++ { ++ wfdielen = build_probe_req_wfd_ie(pbuddy_wdinfo, pframe); ++ pframe += wfdielen; ++ pattrib->pktlen += wfdielen; ++ } ++ ++} ++ ++void rtw_build_tunneled_probe_rsp_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe) ++{ ++ ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ struct wifidirect_info *pbuddy_wdinfo = &padapter->pbuddy_adapter->wdinfo; ++ u8 payload_type = 0x02; ++ u8 category = RTW_WLAN_CATEGORY_P2P; ++ u8 WFA_OUI[3] = { 0x50, 0x6f, 0x9a}; ++ u8 probe_rsp = 5; ++ u8 wfdielen = 0; ++ ++ //payload type ++ pframe = rtw_set_fixed_ie(pframe, 1, &(payload_type), &(pattrib->pktlen)); ++ //category, OUI, frame_body_type ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 3, WFA_OUI, &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(probe_rsp), &(pattrib->pktlen)); ++ ++ if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ wfdielen = build_probe_resp_wfd_ie(pwdinfo, pframe, 1); ++ pframe += wfdielen; ++ pattrib->pktlen += wfdielen; ++ } ++ else if(!rtw_p2p_chk_state(pbuddy_wdinfo, P2P_STATE_NONE)) ++ { ++ wfdielen = build_probe_resp_wfd_ie(pbuddy_wdinfo, pframe, 1); ++ pframe += wfdielen; ++ pattrib->pktlen += wfdielen; ++ } ++ ++} ++#endif //CONFIG_WFD ++ ++void _TPK_timer_hdl(void *FunctionContext) ++{ ++ struct sta_info *ptdls_sta = (struct sta_info *)FunctionContext; ++ ++ ptdls_sta->TPK_count++; ++ //TPK_timer set 1000 as default ++ //retry timer should set at least 301 sec. ++ if(ptdls_sta->TPK_count==TPK_RESEND_COUNT){ ++ ptdls_sta->TPK_count=0; ++ issue_tdls_setup_req(ptdls_sta->padapter, ptdls_sta->hwaddr); ++ } ++ ++ _set_timer(&ptdls_sta->TPK_timer, ptdls_sta->TDLS_PeerKey_Lifetime/TPK_RESEND_COUNT); ++} ++ ++void init_TPK_timer(_adapter *padapter, struct sta_info *psta) ++{ ++ psta->padapter=padapter; ++ ++ _init_timer(&psta->TPK_timer, padapter->pnetdev, _TPK_timer_hdl, psta); ++} ++ ++// TDLS_DONE_CH_SEN: channel sensing and report candidate channel ++// TDLS_OFF_CH: first time set channel to off channel ++// TDLS_BASE_CH: when go back to the channel linked with AP, send null data to peer STA as an indication ++void _ch_switch_timer_hdl(void *FunctionContext) ++{ ++ ++ struct sta_info *ptdls_sta = (struct sta_info *)FunctionContext; ++ _adapter *padapter = ptdls_sta->padapter; ++ ++ if( ptdls_sta->option == TDLS_DONE_CH_SEN ){ ++ rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_DONE_CH_SEN); ++ }else if( ptdls_sta->option == TDLS_OFF_CH ){ ++ issue_nulldata_to_TDLS_peer_STA(ptdls_sta->padapter, ptdls_sta, 0); ++ _set_timer(&ptdls_sta->base_ch_timer, 500); ++ }else if( ptdls_sta->option == TDLS_BASE_CH){ ++ issue_nulldata_to_TDLS_peer_STA(ptdls_sta->padapter, ptdls_sta, 0); ++ } ++} ++ ++void init_ch_switch_timer(_adapter *padapter, struct sta_info *psta) ++{ ++ psta->padapter=padapter; ++ _init_timer(&psta->option_timer, padapter->pnetdev, _ch_switch_timer_hdl, psta); ++} ++ ++void _base_ch_timer_hdl(void *FunctionContext) ++{ ++ struct sta_info *ptdls_sta = (struct sta_info *)FunctionContext; ++ rtw_tdls_cmd(ptdls_sta->padapter, ptdls_sta->hwaddr, TDLS_P_OFF_CH); ++} ++ ++void init_base_ch_timer(_adapter *padapter, struct sta_info *psta) ++{ ++ psta->padapter=padapter; ++ _init_timer(&psta->base_ch_timer, padapter->pnetdev, _base_ch_timer_hdl, psta); ++} ++ ++void _off_ch_timer_hdl(void *FunctionContext) ++{ ++ struct sta_info *ptdls_sta = (struct sta_info *)FunctionContext; ++ rtw_tdls_cmd(ptdls_sta->padapter, ptdls_sta->hwaddr, TDLS_P_BASE_CH ); ++} ++ ++void init_off_ch_timer(_adapter *padapter, struct sta_info *psta) ++{ ++ psta->padapter=padapter; ++ _init_timer(&psta->off_ch_timer, padapter->pnetdev, _off_ch_timer_hdl, psta); ++} ++ ++void _tdls_handshake_timer_hdl(void *FunctionContext) ++{ ++ struct sta_info *ptdls_sta = (struct sta_info *)FunctionContext; ++ ++ if(ptdls_sta != NULL) ++ { ++ if( !(ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE) ) ++ { ++ DBG_871X("tdls handshake time out\n"); ++ free_tdls_sta(ptdls_sta->padapter, ptdls_sta); ++ } ++ } ++} ++ ++void init_handshake_timer(_adapter *padapter, struct sta_info *psta) ++{ ++ psta->padapter=padapter; ++ _init_timer(&psta->handshake_timer, padapter->pnetdev, _tdls_handshake_timer_hdl, psta); ++} ++ ++//Check tdls peer sta alive. ++void _tdls_alive_timer_phase1_hdl(void *FunctionContext) ++{ ++ _irqL irqL; ++ struct sta_info *ptdls_sta = (struct sta_info *)FunctionContext; ++ _adapter *padapter = ptdls_sta->padapter; ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ ++ _enter_critical_bh(&ptdlsinfo->hdl_lock, &irqL); ++ ptdls_sta->timer_flag = 1; ++ _exit_critical_bh(&ptdlsinfo->hdl_lock, &irqL); ++ ++ ptdls_sta->tdls_sta_state &= (~TDLS_ALIVE_STATE); ++ ++ DBG_871X("issue_tdls_dis_req to check alive\n"); ++ issue_tdls_dis_req( padapter, ptdls_sta->hwaddr); ++ rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CKALV_PH1); ++ sta_update_last_rx_pkts(ptdls_sta); ++ ++ if ( ptdls_sta->timer_flag == 2 ) ++ rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_FREE_STA); ++ else ++ { ++ _enter_critical_bh(&ptdlsinfo->hdl_lock, &irqL); ++ ptdls_sta->timer_flag = 0; ++ _exit_critical_bh(&ptdlsinfo->hdl_lock, &irqL); ++ } ++ ++} ++ ++void _tdls_alive_timer_phase2_hdl(void *FunctionContext) ++{ ++ _irqL irqL; ++ struct sta_info *ptdls_sta = (struct sta_info *)FunctionContext; ++ _adapter *padapter = ptdls_sta->padapter; ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ ++ _enter_critical_bh(&(ptdlsinfo->hdl_lock), &irqL); ++ ptdls_sta->timer_flag = 1; ++ _exit_critical_bh(&ptdlsinfo->hdl_lock, &irqL); ++ ++ if( (ptdls_sta->tdls_sta_state & TDLS_ALIVE_STATE) && ++ (sta_last_rx_pkts(ptdls_sta) + 3 <= sta_rx_pkts(ptdls_sta)) ) ++ { ++ DBG_871X("TDLS STA ALIVE, ptdls_sta->sta_stats.last_rx_pkts:%llu, ptdls_sta->sta_stats.rx_pkts:%llu\n", ++ sta_last_rx_pkts(ptdls_sta), sta_rx_pkts(ptdls_sta)); ++ ++ ptdls_sta->alive_count = 0; ++ rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CKALV_PH2); ++ } ++ else ++ { ++ if( !(ptdls_sta->tdls_sta_state & TDLS_ALIVE_STATE) ) ++ DBG_871X("TDLS STA TOO FAR\n"); ++ if( !(sta_last_rx_pkts(ptdls_sta) + 3 <= sta_rx_pkts(ptdls_sta))) ++ DBG_871X("TDLS LINK WITH LOW TRAFFIC, ptdls_sta->sta_stats.last_rx_pkts:%llu, ptdls_sta->sta_stats.rx_pkts:%llu\n", ++ sta_last_rx_pkts(ptdls_sta), sta_rx_pkts(ptdls_sta)); ++ ++ ptdls_sta->alive_count++; ++ if( ptdls_sta->alive_count == TDLS_ALIVE_COUNT ) ++ { ++ ptdls_sta->stat_code = _RSON_TDLS_TEAR_TOOFAR_; ++ issue_tdls_teardown(padapter, ptdls_sta->hwaddr); ++ } ++ else ++ { ++ rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CKALV_PH2); ++ } ++ } ++ ++ if ( ptdls_sta->timer_flag == 2 ) ++ rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_FREE_STA); ++ else ++ { ++ _enter_critical_bh(&(ptdlsinfo->hdl_lock), &irqL); ++ ptdls_sta->timer_flag = 0; ++ _exit_critical_bh(&ptdlsinfo->hdl_lock, &irqL); ++} ++ ++} ++ ++void init_tdls_alive_timer(_adapter *padapter, struct sta_info *psta) ++{ ++ psta->padapter=padapter; ++ _init_timer(&psta->alive_timer1, padapter->pnetdev, _tdls_alive_timer_phase1_hdl, psta); ++ _init_timer(&psta->alive_timer2, padapter->pnetdev, _tdls_alive_timer_phase2_hdl, psta); ++} ++ ++int update_sgi_tdls(_adapter *padapter, struct sta_info *psta) ++{ ++ struct ht_priv *psta_ht = NULL; ++ psta_ht = &psta->htpriv; ++ ++ if(psta_ht->ht_option) ++ { ++ return psta_ht->sgi; ++ } ++ else ++ return _FALSE; ++} ++ ++u32 update_mask_tdls(_adapter *padapter, struct sta_info *psta) ++{ ++ int i; ++ u8 rf_type, id; ++ unsigned char sta_band = 0; ++ unsigned char limit; ++ unsigned int tx_ra_bitmap=0; ++ struct ht_priv *psta_ht = NULL; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ WLAN_BSSID_EX *pcur_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; ++ ++ psta_ht = &psta->htpriv; ++ //b/g mode ra_bitmap ++ for (i=0; ibssrateset); i++) ++ { ++ if (psta->bssrateset[i]) ++ tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i]&0x7f); ++ } ++ ++ //n mode ra_bitmap ++ if(psta_ht->ht_option) ++ { ++ padapter->HalFunc.GetHwRegHandler(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ if(rf_type == RF_2T2R) ++ limit=16;// 2R ++ else ++ limit=8;// 1R ++ ++ for (i=0; iht_cap.supp_mcs_set[i/8] & BIT(i%8)) ++ tx_ra_bitmap |= BIT(i+12); ++ } ++ } ++ ++ if ( pcur_network->Configuration.DSConfig > 14 ) { ++ // 5G band ++ if (tx_ra_bitmap & 0xffff000) ++ sta_band |= WIRELESS_11_5N | WIRELESS_11A; ++ else ++ sta_band |= WIRELESS_11A; ++ } else { ++ if (tx_ra_bitmap & 0xffff000) ++ sta_band |= WIRELESS_11_24N | WIRELESS_11G | WIRELESS_11B; ++ else if (tx_ra_bitmap & 0xff0) ++ sta_band |= WIRELESS_11G |WIRELESS_11B; ++ else ++ sta_band |= WIRELESS_11B; ++ } ++ ++ id = networktype_to_raid(sta_band); ++ tx_ra_bitmap |= ((id<<28)&0xf0000000); ++ return tx_ra_bitmap; ++} ++ ++#endif //CONFIG_TDLS ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_wapi.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_wapi.c +new file mode 100644 +index 00000000..6c6268c0 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_wapi.c +@@ -0,0 +1,1326 @@ ++#ifdef CONFIG_WAPI_SUPPORT ++ ++#include ++#include ++#include ++#include ++ ++ ++u32 wapi_debug_component = ++// WAPI_INIT | ++// WAPI_API | ++// WAPI_TX | ++// WAPI_RX | ++ WAPI_ERR ; //always open err flags on ++ ++void WapiFreeAllStaInfo(_adapter *padapter) ++{ ++ PRT_WAPI_T pWapiInfo; ++ PRT_WAPI_STA_INFO pWapiStaInfo; ++ PRT_WAPI_BKID pWapiBkid; ++ ++ WAPI_TRACE(WAPI_INIT, "===========> %s\n", __FUNCTION__); ++ pWapiInfo = &padapter->wapiInfo; ++ ++ //Pust to Idle List ++ rtw_wapi_return_all_sta_info(padapter); ++ ++ //Sta Info List ++ while(!list_empty(&(pWapiInfo->wapiSTAIdleList))) ++ { ++ pWapiStaInfo = (PRT_WAPI_STA_INFO)list_entry(pWapiInfo->wapiSTAIdleList.next, RT_WAPI_STA_INFO, list); ++ list_del_init(&pWapiStaInfo->list); ++ } ++ ++ //BKID List ++ while(!list_empty(&(pWapiInfo->wapiBKIDIdleList))) ++ { ++ pWapiBkid = (PRT_WAPI_BKID)list_entry(pWapiInfo->wapiBKIDIdleList.next, RT_WAPI_BKID, list); ++ list_del_init(&pWapiBkid->list); ++ } ++ WAPI_TRACE(WAPI_INIT, "<=========== %s\n", __FUNCTION__); ++ return; ++} ++ ++void WapiSetIE(_adapter *padapter) ++{ ++ PRT_WAPI_T pWapiInfo = &(padapter->wapiInfo); ++ //PRT_WAPI_BKID pWapiBkid; ++ u16 protocolVer = 1; ++ u16 akmCnt = 1; ++ u16 suiteCnt = 1; ++ u16 capability = 0; ++ u8 OUI[3]; ++ ++ OUI[0] = 0x00; ++ OUI[1] = 0x14; ++ OUI[2] = 0x72; ++ ++ pWapiInfo->wapiIELength = 0; ++//protocol version ++ memcpy(pWapiInfo->wapiIE+pWapiInfo->wapiIELength, &protocolVer, 2); ++ pWapiInfo->wapiIELength +=2; ++//akm ++ memcpy(pWapiInfo->wapiIE+pWapiInfo->wapiIELength, &akmCnt, 2); ++ pWapiInfo->wapiIELength +=2; ++ ++ if(pWapiInfo->bWapiPSK){ ++ memcpy(pWapiInfo->wapiIE+pWapiInfo->wapiIELength,OUI, 3); ++ pWapiInfo->wapiIELength +=3; ++ pWapiInfo->wapiIE[pWapiInfo->wapiIELength] = 0x2; ++ pWapiInfo->wapiIELength +=1; ++ }else{ ++ memcpy(pWapiInfo->wapiIE+pWapiInfo->wapiIELength,OUI, 3); ++ pWapiInfo->wapiIELength +=3; ++ pWapiInfo->wapiIE[pWapiInfo->wapiIELength] = 0x1; ++ pWapiInfo->wapiIELength +=1; ++ } ++ ++//usk ++ memcpy(pWapiInfo->wapiIE+pWapiInfo->wapiIELength, &suiteCnt, 2); ++ pWapiInfo->wapiIELength +=2; ++ memcpy(pWapiInfo->wapiIE+pWapiInfo->wapiIELength,OUI, 3); ++ pWapiInfo->wapiIELength +=3; ++ pWapiInfo->wapiIE[pWapiInfo->wapiIELength] = 0x1; ++ pWapiInfo->wapiIELength +=1; ++ ++//msk ++ memcpy(pWapiInfo->wapiIE+pWapiInfo->wapiIELength,OUI, 3); ++ pWapiInfo->wapiIELength +=3; ++ pWapiInfo->wapiIE[pWapiInfo->wapiIELength] = 0x1; ++ pWapiInfo->wapiIELength +=1; ++ ++//Capbility ++ memcpy(pWapiInfo->wapiIE+pWapiInfo->wapiIELength, &capability, 2); ++ pWapiInfo->wapiIELength +=2; ++} ++ ++ ++/* PN1 > PN2, return 1, ++ * else return 0. ++ */ ++u32 WapiComparePN(u8 *PN1, u8 *PN2) ++{ ++ char i; ++ ++ if ((NULL == PN1) || (NULL == PN2)) ++ return 1; ++ ++ // overflow case ++ if ((PN2[15] - PN1[15]) & 0x80) ++ return 1; ++ ++ for (i=16; i>0; i--) ++ { ++ if(PN1[i-1] == PN2[i-1]) ++ continue; ++ else if(PN1[i-1] > PN2[i-1]) ++ return 1; ++ else ++ return 0; ++ } ++ ++ return 0; ++} ++ ++u8 ++WapiGetEntryForCamWrite(_adapter *padapter,u8 *pMacAddr,u8 KID,BOOLEAN IsMsk) ++{ ++ PRT_WAPI_T pWapiInfo=NULL; ++ //PRT_WAPI_CAM_ENTRY pEntry=NULL; ++ u8 i=0; ++ u8 ret = 0xff; ++ ++ WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); ++ ++ pWapiInfo = &padapter->wapiInfo; ++ ++ //exist? ++ for(i=0;iwapiCamEntry[i].IsUsed ++ && (_rtw_memcmp(pMacAddr, pWapiInfo->wapiCamEntry[i].PeerMacAddr, ETH_ALEN) == _TRUE) ++ && pWapiInfo->wapiCamEntry[i].keyidx == KID ++ && pWapiInfo->wapiCamEntry[i].type == IsMsk) ++ { ++ ret = pWapiInfo->wapiCamEntry[i].entry_idx; //cover it ++ break; ++ } ++ } ++ ++ if(i == WAPI_CAM_ENTRY_NUM) //not found ++ { ++ for(i=0;iwapiCamEntry[i].IsUsed == 0) ++ { ++ pWapiInfo->wapiCamEntry[i].IsUsed = 1; ++ pWapiInfo->wapiCamEntry[i].type = IsMsk; ++ pWapiInfo->wapiCamEntry[i].keyidx = KID; ++ _rtw_memcpy(pWapiInfo->wapiCamEntry[i].PeerMacAddr, pMacAddr,ETH_ALEN); ++ ret = pWapiInfo->wapiCamEntry[i].entry_idx; ++ break; ++ } ++ } ++ } ++ ++ WAPI_TRACE(WAPI_API, "<========== %s\n", __FUNCTION__); ++ return ret; ++ ++/* ++ if(RTIsListEmpty(&pWapiInfo->wapiCamIdleList)){ ++ RT_TRACE(COMP_SEC,DBG_LOUD,("No Entry for wapi!!!\n")); ++ return 0; ++ } ++ ++ pEntry = (PRT_WAPI_CAM_ENTRY)RTRemoveHeadList(&pWapiInfo->wapiCamIdleList); ++ RTInsertTailList(&pWapiInfo->wapiCamUsedList, &pEntry->list); ++ ++ RT_TRACE(COMP_SEC,DBG_LOUD,("<====WapiGetCamEntry(),Get Entry Idx:%d.but we just return 4 for test\n",pEntry->entry_idx)); ++ ++ return pEntry->entry_idx;*/ ++} ++ ++u8 WapiGetEntryForCamClear(_adapter *padapter,u8 *pPeerMac,u8 keyid,u8 IsMsk) ++{ ++ PRT_WAPI_T pWapiInfo=NULL; ++ u8 i=0; ++ ++ WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); ++ ++ pWapiInfo = &padapter->wapiInfo; ++ ++ for(i=0;iwapiCamEntry[i].IsUsed ++ && (_rtw_memcmp(pPeerMac, pWapiInfo->wapiCamEntry[i].PeerMacAddr, ETH_ALEN) == _TRUE) ++ && pWapiInfo->wapiCamEntry[i].keyidx == keyid ++ && pWapiInfo->wapiCamEntry[i].type == IsMsk) ++ { ++ pWapiInfo->wapiCamEntry[i].IsUsed = 0; ++ pWapiInfo->wapiCamEntry[i].keyidx = 2; ++ _rtw_memset(pWapiInfo->wapiCamEntry[i].PeerMacAddr,0,ETH_ALEN); ++ ++ WAPI_TRACE(WAPI_API, "<========== %s\n", __FUNCTION__); ++ return pWapiInfo->wapiCamEntry[i].entry_idx; ++ } ++ } ++ ++ WAPI_TRACE(WAPI_API,"<====WapiGetReturnCamEntry(), No this cam entry.\n"); ++ return 0xff; ++/* ++ if(RTIsListEmpty(&pWapiInfo->wapiCamUsedList)){ ++ RT_TRACE(COMP_SEC,DBG_LOUD,("No Entry for wapi!!!\n")); ++ return FALSE; ++ } ++ ++ pList = &pWapiInfo->wapiCamUsedList; ++ while(pList->Flink != &pWapiInfo->wapiCamUsedList) ++ { ++ pEntry = (PRT_WAPI_CAM_ENTRY)pList->Flink; ++ if(PlatformCompareMemory(pPeerMac,pEntry->PeerMacAddr, ETHER_ADDRLEN)== 0 ++ && keyid == pEntry->keyidx) ++ { ++ RTRemoveEntryList(pList); ++ RTInsertHeadList(&pWapiInfo->wapiCamIdleList, pList); ++ return pEntry->entry_idx; ++ } ++ pList = pList->Flink; ++ } ++ ++ return 0; ++*/ ++} ++ ++void ++WapiResetAllCamEntry(_adapter *padapter) ++{ ++ PRT_WAPI_T pWapiInfo; ++ int i; ++ ++ WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); ++ ++ pWapiInfo = &padapter->wapiInfo; ++ ++ for (i=0;iwapiCamEntry[i].PeerMacAddr, 0, ETH_ALEN); ++ pWapiInfo->wapiCamEntry[i].IsUsed = 0; ++ pWapiInfo->wapiCamEntry[i].keyidx = 2; //invalid ++ pWapiInfo->wapiCamEntry[i].entry_idx = 4+i*2; ++ } ++ ++ WAPI_TRACE(WAPI_API, "<========== %s\n", __FUNCTION__); ++ ++ return; ++} ++ ++u8 WapiWriteOneCamEntry( ++ _adapter *padapter, ++ u8 *pMacAddr, ++ u8 KeyId, ++ u8 EntryId, ++ u8 EncAlg, ++ u8 bGroupKey, ++ u8 *pKey ++) ++{ ++ u8 retVal = 0; ++ u16 usConfig = 0; ++ ++ WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); ++ ++ if(EntryId >= 32) ++ { ++ WAPI_TRACE(WAPI_ERR, "<=== CamAddOneEntry(): ulKeyId exceed!\n"); ++ return retVal; ++ } ++ ++ usConfig=usConfig|(0x01<<15)|((u16)(EncAlg)<<2)|(KeyId); ++ ++ if(EncAlg == _SMS4_ ) ++ { ++ if(bGroupKey == 1) ++ usConfig |= (0x01<<6); ++ if((EntryId % 2)==1) // ==0 sec key; == 1mic key ++ usConfig |= (0x01<<5); ++ } ++ ++ write_cam(padapter, EntryId, usConfig, pMacAddr, pKey); ++ ++ WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); ++ return 1; ++} ++ ++void rtw_wapi_init(_adapter *padapter) ++{ ++ PRT_WAPI_T pWapiInfo; ++ int i; ++ ++ WAPI_TRACE(WAPI_INIT, "===========> %s\n", __FUNCTION__); ++ RT_ASSERT_RET(padapter); ++ ++ if (!padapter->WapiSupport) ++ { ++ WAPI_TRACE(WAPI_INIT, "<========== %s, WAPI not supported!\n", __FUNCTION__); ++ return; ++ } ++ ++ pWapiInfo = &padapter->wapiInfo; ++ pWapiInfo->bWapiEnable = false; ++ ++ //Init BKID List ++ INIT_LIST_HEAD(&pWapiInfo->wapiBKIDIdleList); ++ INIT_LIST_HEAD(&pWapiInfo->wapiBKIDStoreList); ++ for(i=0;iwapiBKID[i].list, &pWapiInfo->wapiBKIDIdleList); ++ } ++ ++ //Init STA List ++ INIT_LIST_HEAD(&pWapiInfo->wapiSTAIdleList); ++ INIT_LIST_HEAD(&pWapiInfo->wapiSTAUsedList); ++ for(i=0;iwapiSta[i].list, &pWapiInfo->wapiSTAIdleList); ++ } ++ ++ for (i=0;iwapiCamEntry[i].IsUsed = 0; ++ pWapiInfo->wapiCamEntry[i].keyidx = 2; //invalid ++ pWapiInfo->wapiCamEntry[i].entry_idx = 4+i*2; ++ } ++ ++ WAPI_TRACE(WAPI_INIT, "<========== %s\n", __FUNCTION__); ++} ++ ++void rtw_wapi_free(_adapter *padapter) ++{ ++ WAPI_TRACE(WAPI_INIT, "===========> %s\n", __FUNCTION__); ++ RT_ASSERT_RET(padapter); ++ ++ if (!padapter->WapiSupport) ++ { ++ WAPI_TRACE(WAPI_INIT, "<========== %s, WAPI not supported!\n", __FUNCTION__); ++ return; ++ } ++ ++ WapiFreeAllStaInfo(padapter); ++ ++ WAPI_TRACE(WAPI_INIT, "<========== %s\n", __FUNCTION__); ++} ++ ++void rtw_wapi_disable_tx(_adapter *padapter) ++{ ++ WAPI_TRACE(WAPI_INIT, "===========> %s\n", __FUNCTION__); ++ RT_ASSERT_RET(padapter); ++ ++ if (!padapter->WapiSupport) ++ { ++ WAPI_TRACE(WAPI_INIT, "<========== %s, WAPI not supported!\n", __FUNCTION__); ++ return; ++ } ++ ++ padapter->wapiInfo.wapiTxMsk.bTxEnable = false; ++ padapter->wapiInfo.wapiTxMsk.bSet = false; ++ ++ WAPI_TRACE(WAPI_INIT, "<========== %s\n", __FUNCTION__); ++} ++ ++u8 rtw_wapi_is_wai_packet(_adapter* padapter,u8 *pkt_data) ++{ ++ PRT_WAPI_T pWapiInfo = &(padapter->wapiInfo); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ PRT_WAPI_STA_INFO pWapiSta = NULL; ++ u8 WaiPkt = 0, *pTaddr, bFind = false; ++ u8 Offset_TypeWAI = 0 ; // (mac header len + llc length) ++ ++ WAPI_TRACE(WAPI_TX|WAPI_RX, "===========> %s\n", __FUNCTION__); ++ ++ if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) ++ { ++ WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); ++ return 0; ++ } ++ ++ Offset_TypeWAI = 24 + 6 ; ++ ++ //YJ,add,091103. Data frame may also have skb->data[30]=0x88 and skb->data[31]=0xb4. ++ if ((pkt_data[1]&0x40) !=0) ++ { ++ DBG_871X("data is privacy \n"); ++ return 0; ++ } ++ ++ pTaddr = GetAddr2Ptr(pkt_data); ++ if(list_empty(&pWapiInfo->wapiSTAUsedList)){ ++ bFind = false; ++ }else{ ++ list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list){ ++ if (_rtw_memcmp(pTaddr, pWapiSta->PeerMacAddr, 6) == _TRUE) { ++ bFind = true; ++ break; ++ } ++ } ++ } ++ ++ WAPI_TRACE(WAPI_TX|WAPI_RX, "%s: bFind=%d pTaddr="MAC_FMT"\n", __FUNCTION__, bFind, MAC_ARG(pTaddr)); ++ ++ if (pkt_data[0] == WIFI_QOS_DATA_TYPE) ++ { ++ Offset_TypeWAI += 2; ++ } ++ ++ // 88b4? ++ if( (pkt_data[Offset_TypeWAI]==0x88) && (pkt_data[Offset_TypeWAI+1]==0xb4) ){ ++ WaiPkt = pkt_data[Offset_TypeWAI+5]; ++ ++ psecuritypriv->hw_decrypted = _TRUE; ++ }else{ ++ WAPI_TRACE(WAPI_TX|WAPI_RX, "%s(): non wai packet\n",__FUNCTION__); ++ } ++ ++ WAPI_TRACE(WAPI_TX|WAPI_RX, "%s(): Recvd WAI frame. IsWAIPkt(%d)\n",__FUNCTION__, WaiPkt); ++ ++ return WaiPkt; ++} ++ ++ ++void rtw_wapi_update_info(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ PRT_WAPI_T pWapiInfo = &(padapter->wapiInfo); ++ struct recv_frame_hdr *precv_hdr; ++ u8 *ptr; ++ u8 *pTA; ++ u8 *pRecvPN; ++ ++ ++ WAPI_TRACE(WAPI_RX, "===========> %s\n", __FUNCTION__); ++ ++ if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) ++ { ++ WAPI_TRACE(WAPI_RX, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); ++ return; ++ } ++ ++ precv_hdr = &precv_frame->u.hdr; ++ ptr = precv_hdr->rx_data; ++ ++ if (precv_hdr->attrib.qos == 1) ++ { ++ precv_hdr->UserPriority = GetTid(ptr); ++ } ++ else ++ { ++ precv_hdr->UserPriority = 0; ++ } ++ ++ pTA = GetAddr2Ptr(ptr); ++ _rtw_memcpy((u8 *)precv_hdr->WapiSrcAddr, pTA, 6); ++ pRecvPN = ptr + precv_hdr->attrib.hdrlen + 2; ++ _rtw_memcpy((u8 *)precv_hdr->WapiTempPN, pRecvPN, 16); ++ ++ WAPI_TRACE(WAPI_RX, "<========== %s\n", __FUNCTION__); ++} ++ ++/**************************************************************************** ++TRUE-----------------Drop ++FALSE---------------- handle ++add to support WAPI to N-mode ++*****************************************************************************/ ++u8 rtw_wapi_check_for_drop( ++ _adapter *padapter, ++ union recv_frame *precv_frame ++) ++{ ++ PRT_WAPI_T pWapiInfo = &(padapter->wapiInfo); ++ u8 *pLastRecvPN = NULL; ++ u8 bFind = false; ++ PRT_WAPI_STA_INFO pWapiSta = NULL; ++ u8 bDrop = false; ++ struct recv_frame_hdr *precv_hdr = &precv_frame->u.hdr; ++ u8 WapiAEPNInitialValueSrc[16] = {0x37,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ; ++ u8 WapiAEMultiCastPNInitialValueSrc[16] = {0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ; ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ int i; ++ ++ WAPI_TRACE(WAPI_RX, "===========> %s\n", __FUNCTION__); ++ ++ if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) ++ { ++ WAPI_TRACE(WAPI_RX, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); ++ return false; ++ } ++ ++ if(precv_hdr->bIsWaiPacket !=0) ++ { ++ if(precv_hdr->bIsWaiPacket== 0x8) ++ { ++ ++ DBG_871X("rtw_wapi_check_for_drop: dump packet \n"); ++ for(i=0;i<50;i++) ++ { ++ DBG_871X("%02X ",ptr[i]); ++ if((i+1) %8 ==0) ++ DBG_871X("\n"); ++ } ++ DBG_871X("\n rtw_wapi_check_for_drop: dump packet \n"); ++ ++ for(i=0;i<16;i++) ++ { ++ if(ptr[i+27] !=0) ++ break; ++ } ++ ++ if(i== 16) ++ { ++ WAPI_TRACE(WAPI_RX,"rtw_wapi_check_for_drop: drop with zero BKID \n"); ++ return true; ++ } ++ else ++ { ++ return false; ++ } ++ } ++ else ++ return false; ++ } ++ ++ if(list_empty(&pWapiInfo->wapiSTAUsedList)){ ++ bFind = false; ++ }else{ ++ list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { ++ if (_rtw_memcmp(precv_hdr->WapiSrcAddr, pWapiSta->PeerMacAddr, ETH_ALEN) == _TRUE) { ++ bFind = true; ++ break; ++ } ++ } ++ } ++ WAPI_TRACE(WAPI_RX, "%s: bFind=%d prxb->WapiSrcAddr="MAC_FMT"\n", __FUNCTION__, bFind, MAC_ARG(precv_hdr->WapiSrcAddr)); ++ ++ if(bFind) ++ { ++ if(IS_MCAST(precv_hdr->attrib.ra)) ++ { ++ WAPI_TRACE(WAPI_RX,"rtw_wapi_check_for_drop: multicast case \n"); ++ pLastRecvPN = pWapiSta->lastRxMulticastPN; ++ } ++ else ++ { ++ WAPI_TRACE(WAPI_RX,"rtw_wapi_check_for_drop: unicast case \n"); ++ switch(precv_hdr->UserPriority) ++ { ++ case 0: ++ case 3: ++ pLastRecvPN = pWapiSta->lastRxUnicastPNBEQueue; ++ break; ++ case 1: ++ case 2: ++ pLastRecvPN = pWapiSta->lastRxUnicastPNBKQueue; ++ break; ++ case 4: ++ case 5: ++ pLastRecvPN = pWapiSta->lastRxUnicastPNVIQueue; ++ break; ++ case 6: ++ case 7: ++ pLastRecvPN = pWapiSta->lastRxUnicastPNVOQueue; ++ break; ++ default: ++ WAPI_TRACE(WAPI_ERR,"%s: Unknown TID \n",__FUNCTION__); ++ break; ++ } ++ } ++ ++ if(!WapiComparePN(precv_hdr->WapiTempPN,pLastRecvPN)) ++ { ++ WAPI_TRACE(WAPI_RX,"%s: Equal PN!!\n",__FUNCTION__); ++ if(IS_MCAST(precv_hdr->attrib.ra)) ++ _rtw_memcpy(pLastRecvPN,WapiAEMultiCastPNInitialValueSrc,16); ++ else ++ _rtw_memcpy(pLastRecvPN,WapiAEPNInitialValueSrc,16); ++ bDrop = true; ++ } ++ else ++ { ++ _rtw_memcpy(pLastRecvPN,precv_hdr->WapiTempPN,16); ++ } ++ } ++ ++ WAPI_TRACE(WAPI_RX, "<========== %s\n", __FUNCTION__); ++ return bDrop; ++} ++ ++void rtw_build_probe_resp_wapi_ie(_adapter *padapter, unsigned char *pframe, struct pkt_attrib *pattrib) ++{ ++ PRT_WAPI_T pWapiInfo = &(padapter->wapiInfo); ++ u8 WapiIELength = 0; ++ ++ WAPI_TRACE(WAPI_MLME, "===========> %s\n", __FUNCTION__); ++ ++ if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) ++ { ++ WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported!\n", __FUNCTION__); ++ return; ++ } ++ ++ WapiSetIE(padapter); ++ WapiIELength = pWapiInfo->wapiIELength; ++ pframe[0] = _WAPI_IE_; ++ pframe[1] = WapiIELength; ++ _rtw_memcpy(pframe+2, pWapiInfo->wapiIE, WapiIELength); ++ pframe += WapiIELength+2; ++ pattrib->pktlen += WapiIELength+2; ++ ++ WAPI_TRACE(WAPI_MLME, "<========== %s\n", __FUNCTION__); ++} ++ ++void rtw_build_beacon_wapi_ie(_adapter *padapter, unsigned char *pframe, struct pkt_attrib *pattrib) ++{ ++ PRT_WAPI_T pWapiInfo = &(padapter->wapiInfo); ++ u8 WapiIELength = 0; ++ WAPI_TRACE(WAPI_MLME, "===========> %s\n", __FUNCTION__); ++ ++ if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) ++ { ++ WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported!\n", __FUNCTION__); ++ return; ++ } ++ ++ WapiSetIE(padapter); ++ WapiIELength = pWapiInfo->wapiIELength; ++ pframe[0] = _WAPI_IE_; ++ pframe[1] = WapiIELength; ++ _rtw_memcpy(pframe+2, pWapiInfo->wapiIE, WapiIELength); ++ pframe += WapiIELength+2; ++ pattrib->pktlen += WapiIELength+2; ++ ++ WAPI_TRACE(WAPI_MLME, "<========== %s\n", __FUNCTION__); ++} ++ ++void rtw_build_assoc_req_wapi_ie(_adapter *padapter, unsigned char *pframe, struct pkt_attrib *pattrib) ++{ ++ PRT_WAPI_BKID pWapiBKID; ++ u16 bkidNum; ++ PRT_WAPI_T pWapiInfo = &(padapter->wapiInfo); ++ u8 WapiIELength = 0; ++ ++ WAPI_TRACE(WAPI_MLME, "===========> %s\n", __FUNCTION__); ++ ++ if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) ++ { ++ WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported!\n", __FUNCTION__); ++ return; ++ } ++ ++ WapiSetIE(padapter); ++ WapiIELength = pWapiInfo->wapiIELength; ++ bkidNum = 0; ++ if(!list_empty(&(pWapiInfo->wapiBKIDStoreList))){ ++ list_for_each_entry(pWapiBKID, &pWapiInfo->wapiBKIDStoreList, list) { ++ bkidNum ++; ++ _rtw_memcpy(pWapiInfo->wapiIE+WapiIELength+2, pWapiBKID->bkid,16); ++ WapiIELength += 16; ++ } ++ } ++ _rtw_memcpy(pWapiInfo->wapiIE+WapiIELength, &bkidNum, 2); ++ WapiIELength += 2; ++ ++ pframe[0] = _WAPI_IE_; ++ pframe[1] = WapiIELength; ++ _rtw_memcpy(pframe+2, pWapiInfo->wapiIE, WapiIELength); ++ pframe += WapiIELength+2; ++ pattrib->pktlen += WapiIELength+2; ++ WAPI_TRACE(WAPI_MLME, "<========== %s\n", __FUNCTION__); ++} ++ ++void rtw_wapi_on_assoc_ok(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) ++{ ++ PRT_WAPI_T pWapiInfo = &(padapter->wapiInfo); ++ PRT_WAPI_STA_INFO pWapiSta; ++ u8 WapiAEPNInitialValueSrc[16] = {0x37,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ; ++ //u8 WapiASUEPNInitialValueSrc[16] = {0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ; ++ u8 WapiAEMultiCastPNInitialValueSrc[16] = {0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ; ++ ++ WAPI_TRACE(WAPI_MLME, "===========> %s\n", __FUNCTION__); ++ ++ if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) ++ { ++ WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); ++ return; ++ } ++ ++ pWapiSta =(PRT_WAPI_STA_INFO)list_entry(pWapiInfo->wapiSTAIdleList.next, RT_WAPI_STA_INFO, list); ++ list_del_init(&pWapiSta->list); ++ list_add_tail(&pWapiSta->list, &pWapiInfo->wapiSTAUsedList); ++ _rtw_memcpy(pWapiSta->PeerMacAddr,padapter->mlmeextpriv.mlmext_info.network.MacAddress,6); ++ _rtw_memcpy(pWapiSta->lastRxMulticastPN, WapiAEMultiCastPNInitialValueSrc, 16); ++ _rtw_memcpy(pWapiSta->lastRxUnicastPN, WapiAEPNInitialValueSrc, 16); ++ ++ //For chenk PN error with Qos Data after s3: add by ylb 20111114 ++ _rtw_memcpy(pWapiSta->lastRxUnicastPNBEQueue,WapiAEPNInitialValueSrc,16); ++ _rtw_memcpy(pWapiSta->lastRxUnicastPNBKQueue,WapiAEPNInitialValueSrc,16); ++ _rtw_memcpy(pWapiSta->lastRxUnicastPNVIQueue,WapiAEPNInitialValueSrc,16); ++ _rtw_memcpy(pWapiSta->lastRxUnicastPNVOQueue,WapiAEPNInitialValueSrc,16); ++ ++ WAPI_TRACE(WAPI_MLME, "<========== %s\n", __FUNCTION__); ++} ++ ++ ++void rtw_wapi_return_one_sta_info(_adapter *padapter, u8 *MacAddr) ++{ ++ PRT_WAPI_T pWapiInfo; ++ PRT_WAPI_STA_INFO pWapiStaInfo = NULL; ++ PRT_WAPI_BKID pWapiBkid = NULL; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ pWapiInfo = &padapter->wapiInfo; ++ ++ WAPI_TRACE(WAPI_API, "==========> %s\n", __FUNCTION__); ++ ++ if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) ++ { ++ WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); ++ return; ++ } ++ ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE)) ++ { ++ while(!list_empty(&(pWapiInfo->wapiBKIDStoreList))) ++ { ++ pWapiBkid = (PRT_WAPI_BKID)list_entry(pWapiInfo->wapiBKIDStoreList.next, RT_WAPI_BKID, list); ++ list_del_init(&pWapiBkid->list); ++ _rtw_memset(pWapiBkid->bkid,0,16); ++ list_add_tail(&pWapiBkid->list, &pWapiInfo->wapiBKIDIdleList); ++ } ++ } ++ ++ ++ WAPI_TRACE(WAPI_API, " %s: after clear bkid \n", __FUNCTION__); ++ ++ ++ //Remove STA info ++ if(list_empty(&(pWapiInfo->wapiSTAUsedList))){ ++ WAPI_TRACE(WAPI_API, " %s: wapiSTAUsedList is null \n", __FUNCTION__); ++ return; ++ }else{ ++ ++ WAPI_TRACE(WAPI_API, " %s: wapiSTAUsedList is not null \n", __FUNCTION__); ++#if 0 ++ pWapiStaInfo=(PRT_WAPI_STA_INFO)list_entry((pWapiInfo->wapiSTAUsedList.next),RT_WAPI_STA_INFO,list); ++ ++ list_for_each_entry(pWapiStaInfo, &(pWapiInfo->wapiSTAUsedList), list) { ++ ++ DBG_871X("MAC Addr %02x-%02x-%02x-%02x-%02x-%02x \n",MacAddr[0],MacAddr[1],MacAddr[2],MacAddr[3],MacAddr[4],MacAddr[5]); ++ ++ ++ DBG_871X("peer Addr %02x-%02x-%02x-%02x-%02x-%02x \n",pWapiStaInfo->PeerMacAddr[0],pWapiStaInfo->PeerMacAddr[1],pWapiStaInfo->PeerMacAddr[2],pWapiStaInfo->PeerMacAddr[3],pWapiStaInfo->PeerMacAddr[4],pWapiStaInfo->PeerMacAddr[5]); ++ ++ if(pWapiStaInfo == NULL) ++ { ++ WAPI_TRACE(WAPI_API, " %s: pWapiStaInfo == NULL Case \n", __FUNCTION__); ++ return; ++ } ++ ++ if(pWapiStaInfo->PeerMacAddr == NULL) ++ { ++ WAPI_TRACE(WAPI_API, " %s: pWapiStaInfo->PeerMacAddr == NULL Case \n", __FUNCTION__); ++ return; ++ } ++ ++ if(MacAddr == NULL) ++ { ++ WAPI_TRACE(WAPI_API, " %s: MacAddr == NULL Case \n", __FUNCTION__); ++ return; ++ } ++ ++ if (_rtw_memcmp(pWapiStaInfo->PeerMacAddr, MacAddr, ETH_ALEN) == _TRUE) { ++ pWapiStaInfo->bAuthenticateInProgress = false; ++ pWapiStaInfo->bSetkeyOk = false; ++ _rtw_memset(pWapiStaInfo->PeerMacAddr,0,ETH_ALEN); ++ list_del_init(&pWapiStaInfo->list); ++ list_add_tail(&pWapiStaInfo->list, &pWapiInfo->wapiSTAIdleList); ++ break; ++ } ++ ++ } ++#endif ++ ++ while(!list_empty(&(pWapiInfo->wapiSTAUsedList))) ++ { ++ pWapiStaInfo = (PRT_WAPI_STA_INFO)list_entry(pWapiInfo->wapiSTAUsedList.next, RT_WAPI_STA_INFO, list); ++ ++ DBG_871X("peer Addr %02x-%02x-%02x-%02x-%02x-%02x \n",pWapiStaInfo->PeerMacAddr[0],pWapiStaInfo->PeerMacAddr[1],pWapiStaInfo->PeerMacAddr[2],pWapiStaInfo->PeerMacAddr[3],pWapiStaInfo->PeerMacAddr[4],pWapiStaInfo->PeerMacAddr[5]); ++ ++ list_del_init(&pWapiStaInfo->list); ++ memset(pWapiStaInfo->PeerMacAddr,0,ETH_ALEN); ++ pWapiStaInfo->bSetkeyOk = 0; ++ list_add_tail(&pWapiStaInfo->list, &pWapiInfo->wapiSTAIdleList); ++ } ++ ++ } ++ ++ WAPI_TRACE(WAPI_API, "<========== %s\n", __FUNCTION__); ++ return; ++} ++ ++void rtw_wapi_return_all_sta_info(_adapter *padapter) ++{ ++ PRT_WAPI_T pWapiInfo; ++ PRT_WAPI_STA_INFO pWapiStaInfo; ++ PRT_WAPI_BKID pWapiBkid; ++ WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); ++ ++ pWapiInfo = &padapter->wapiInfo; ++ ++ if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) ++ { ++ WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); ++ return; ++ } ++ ++ //Sta Info List ++ while(!list_empty(&(pWapiInfo->wapiSTAUsedList))) ++ { ++ pWapiStaInfo = (PRT_WAPI_STA_INFO)list_entry(pWapiInfo->wapiSTAUsedList.next, RT_WAPI_STA_INFO, list); ++ list_del_init(&pWapiStaInfo->list); ++ memset(pWapiStaInfo->PeerMacAddr,0,ETH_ALEN); ++ pWapiStaInfo->bSetkeyOk = 0; ++ list_add_tail(&pWapiStaInfo->list, &pWapiInfo->wapiSTAIdleList); ++ } ++ ++ //BKID List ++ while(!list_empty(&(pWapiInfo->wapiBKIDStoreList))) ++ { ++ pWapiBkid = (PRT_WAPI_BKID)list_entry(pWapiInfo->wapiBKIDStoreList.next, RT_WAPI_BKID, list); ++ list_del_init(&pWapiBkid->list); ++ memset(pWapiBkid->bkid,0,16); ++ list_add_tail(&pWapiBkid->list, &pWapiInfo->wapiBKIDIdleList); ++ } ++ WAPI_TRACE(WAPI_API, "<========== %s\n", __FUNCTION__); ++} ++ ++void rtw_wapi_clear_cam_entry(_adapter *padapter, u8 *pMacAddr) ++{ ++ u8 UcIndex = 0; ++ ++ WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); ++ ++ if ((!padapter->WapiSupport) || (!padapter->wapiInfo.bWapiEnable)) ++ { ++ WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); ++ return; ++ } ++ ++ UcIndex = WapiGetEntryForCamClear(padapter, pMacAddr, 0, 0); ++ if(UcIndex != 0xff){ ++ //CAM_mark_invalid(Adapter, UcIndex); ++ CAM_empty_entry(padapter, UcIndex); ++ } ++ ++ UcIndex = WapiGetEntryForCamClear(padapter, pMacAddr, 1, 0); ++ if(UcIndex != 0xff){ ++ //CAM_mark_invalid(Adapter, UcIndex); ++ CAM_empty_entry(padapter, UcIndex); ++ } ++ ++ UcIndex = WapiGetEntryForCamClear(padapter, pMacAddr, 0, 1); ++ if(UcIndex != 0xff){ ++ //CAM_mark_invalid(Adapter, UcIndex); ++ CAM_empty_entry(padapter, UcIndex); ++ } ++ ++ UcIndex = WapiGetEntryForCamClear(padapter, pMacAddr, 1, 1); ++ if(UcIndex != 0xff){ ++ //CAM_mark_invalid(padapter, UcIndex); ++ CAM_empty_entry(padapter, UcIndex); ++ } ++ ++ WAPI_TRACE(WAPI_API, "<========== %s\n", __FUNCTION__); ++} ++ ++void rtw_wapi_clear_all_cam_entry(_adapter *padapter) ++{ ++ WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); ++ ++ if ((!padapter->WapiSupport) || (!padapter->wapiInfo.bWapiEnable)) ++ { ++ WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); ++ return; ++ } ++ ++ invalidate_cam_all(padapter); // is this ok? ++ WapiResetAllCamEntry(padapter); ++ ++ WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); ++} ++ ++void rtw_wapi_set_key(_adapter *padapter, RT_WAPI_KEY *pWapiKey, RT_WAPI_STA_INFO *pWapiSta, u8 bGroupKey, u8 bUseDefaultKey) ++{ ++ PRT_WAPI_T pWapiInfo = &padapter->wapiInfo; ++ u8 *pMacAddr = pWapiSta->PeerMacAddr; ++ u32 EntryId = 0; ++ BOOLEAN IsPairWise = false ; ++ u8 EncAlgo; ++ ++ WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); ++ ++ if ((!padapter->WapiSupport) || (!padapter->wapiInfo.bWapiEnable)) ++ { ++ WAPI_TRACE(WAPI_API, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); ++ return; ++ } ++ ++ EncAlgo = _SMS4_; ++ ++ //For Tx bc/mc pkt,use defualt key entry ++ if(bUseDefaultKey) ++ { ++ // when WAPI update key, keyid will be 0 or 1 by turns. ++ if (pWapiKey->keyId == 0) ++ EntryId = 0; ++ else ++ EntryId = 2; ++ } ++ else ++ { ++ // tx/rx unicast pkt, or rx broadcast, find the key entry by peer's MacAddr ++ EntryId = WapiGetEntryForCamWrite(padapter,pMacAddr,pWapiKey->keyId,bGroupKey); ++ } ++ ++ if(EntryId == 0xff){ ++ WAPI_TRACE(WAPI_API, "===>No entry for WAPI setkey! !!\n"); ++ return; ++ } ++ ++ //EntryId is also used to diff Sec key and Mic key ++ //Sec Key ++ WapiWriteOneCamEntry(padapter, ++ pMacAddr, ++ pWapiKey->keyId, //keyid ++ EntryId, //entry ++ EncAlgo, //type ++ bGroupKey, //pairwise or group key ++ pWapiKey->dataKey); ++ //MIC key ++ WapiWriteOneCamEntry(padapter, ++ pMacAddr, ++ pWapiKey->keyId, //keyid ++ EntryId+1, //entry ++ EncAlgo, //type ++ bGroupKey, //pairwise or group key ++ pWapiKey->micKey); ++ ++ WAPI_TRACE(WAPI_API, "Set Wapi Key :KeyId:%d,EntryId:%d,PairwiseKey:%d.\n",pWapiKey->keyId,EntryId,!bGroupKey); ++ WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); ++ ++} ++ ++#if 0 ++//YJ,test,091013 ++void wapi_test_set_key(struct _adapter *padapter, u8* buf) ++{ /*Data: keyType(1) + bTxEnable(1) + bAuthenticator(1) + bUpdate(1) + PeerAddr(6) + DataKey(16) + MicKey(16) + KeyId(1)*/ ++ PRT_WAPI_T pWapiInfo = &padapter->wapiInfo; ++ PRT_WAPI_BKID pWapiBkid; ++ PRT_WAPI_STA_INFO pWapiSta; ++ u8 data[43]; ++ bool bTxEnable; ++ bool bUpdate; ++ bool bAuthenticator; ++ u8 PeerAddr[6]; ++ u8 WapiAEPNInitialValueSrc[16] = {0x37,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ; ++ u8 WapiASUEPNInitialValueSrc[16] = {0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ; ++ u8 WapiAEMultiCastPNInitialValueSrc[16] = {0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ; ++ ++ WAPI_TRACE(WAPI_INIT, "===========>%s\n", __FUNCTION__); ++ ++ if (!padapter->WapiSupport){ ++ return; ++ } ++ ++ copy_from_user(data, buf, 43); ++ bTxEnable = data[1]; ++ bAuthenticator = data[2]; ++ bUpdate = data[3]; ++ memcpy(PeerAddr,data+4,6); ++ ++ if(data[0] == 0x3){ ++ if(!list_empty(&(pWapiInfo->wapiBKIDIdleList))){ ++ pWapiBkid = (PRT_WAPI_BKID)list_entry(pWapiInfo->wapiBKIDIdleList.next, RT_WAPI_BKID, list); ++ list_del_init(&pWapiBkid->list); ++ memcpy(pWapiBkid->bkid, data+10, 16); ++ WAPI_DATA(WAPI_INIT, "SetKey - BKID", pWapiBkid->bkid, 16); ++ list_add_tail(&pWapiBkid->list, &pWapiInfo->wapiBKIDStoreList); ++ } ++ }else{ ++ list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { ++ if(!memcmp(pWapiSta->PeerMacAddr,PeerAddr,6)){ ++ pWapiSta->bAuthenticatorInUpdata = false; ++ switch(data[0]){ ++ case 1: //usk ++ if(bAuthenticator){ //authenticator ++ memcpy(pWapiSta->lastTxUnicastPN,WapiAEPNInitialValueSrc,16); ++ if(!bUpdate) { //first ++ WAPI_TRACE(WAPI_INIT,"AE fisrt set usk \n"); ++ pWapiSta->wapiUsk.bSet = true; ++ memcpy(pWapiSta->wapiUsk.dataKey,data+10,16); ++ memcpy(pWapiSta->wapiUsk.micKey,data+26,16); ++ pWapiSta->wapiUsk.keyId = *(data+42); ++ pWapiSta->wapiUsk.bTxEnable = true; ++ WAPI_DATA(WAPI_INIT, "SetKey - AE USK Data Key", pWapiSta->wapiUsk.dataKey, 16); ++ WAPI_DATA(WAPI_INIT, "SetKey - AE USK Mic Key", pWapiSta->wapiUsk.micKey, 16); ++ } ++ else //update ++ { ++ WAPI_TRACE(WAPI_INIT, "AE update usk \n"); ++ pWapiSta->wapiUskUpdate.bSet = true; ++ pWapiSta->bAuthenticatorInUpdata = true; ++ memcpy(pWapiSta->wapiUskUpdate.dataKey,data+10,16); ++ memcpy(pWapiSta->wapiUskUpdate.micKey,data+26,16); ++ memcpy(pWapiSta->lastRxUnicastPNBEQueue,WapiASUEPNInitialValueSrc,16); ++ memcpy(pWapiSta->lastRxUnicastPNBKQueue,WapiASUEPNInitialValueSrc,16); ++ memcpy(pWapiSta->lastRxUnicastPNVIQueue,WapiASUEPNInitialValueSrc,16); ++ memcpy(pWapiSta->lastRxUnicastPNVOQueue,WapiASUEPNInitialValueSrc,16); ++ memcpy(pWapiSta->lastRxUnicastPN,WapiASUEPNInitialValueSrc,16); ++ pWapiSta->wapiUskUpdate.keyId = *(data+42); ++ pWapiSta->wapiUskUpdate.bTxEnable = true; ++ } ++ } ++ else{ ++ if(!bUpdate){ ++ WAPI_TRACE(WAPI_INIT,"ASUE fisrt set usk \n"); ++ if(bTxEnable){ ++ pWapiSta->wapiUsk.bTxEnable = true; ++ memcpy(pWapiSta->lastTxUnicastPN,WapiASUEPNInitialValueSrc,16); ++ }else{ ++ pWapiSta->wapiUsk.bSet = true; ++ memcpy(pWapiSta->wapiUsk.dataKey,data+10,16); ++ memcpy(pWapiSta->wapiUsk.micKey,data+26,16); ++ pWapiSta->wapiUsk.keyId = *(data+42); ++ pWapiSta->wapiUsk.bTxEnable = false; ++ } ++ }else{ ++ WAPI_TRACE(WAPI_INIT,"ASUE update usk \n"); ++ if(bTxEnable){ ++ pWapiSta->wapiUskUpdate.bTxEnable = true; ++ if(pWapiSta->wapiUskUpdate.bSet){ ++ memcpy(pWapiSta->wapiUsk.dataKey,pWapiSta->wapiUskUpdate.dataKey,16); ++ memcpy(pWapiSta->wapiUsk.micKey,pWapiSta->wapiUskUpdate.micKey,16); ++ pWapiSta->wapiUsk.keyId=pWapiSta->wapiUskUpdate.keyId; ++ memcpy(pWapiSta->lastRxUnicastPNBEQueue,WapiASUEPNInitialValueSrc,16); ++ memcpy(pWapiSta->lastRxUnicastPNBKQueue,WapiASUEPNInitialValueSrc,16); ++ memcpy(pWapiSta->lastRxUnicastPNVIQueue,WapiASUEPNInitialValueSrc,16); ++ memcpy(pWapiSta->lastRxUnicastPNVOQueue,WapiASUEPNInitialValueSrc,16); ++ memcpy(pWapiSta->lastRxUnicastPN,WapiASUEPNInitialValueSrc,16); ++ pWapiSta->wapiUskUpdate.bTxEnable = false; ++ pWapiSta->wapiUskUpdate.bSet = false; ++ } ++ memcpy(pWapiSta->lastTxUnicastPN,WapiASUEPNInitialValueSrc,16); ++ }else{ ++ pWapiSta->wapiUskUpdate.bSet = true; ++ memcpy(pWapiSta->wapiUskUpdate.dataKey,data+10,16); ++ memcpy(pWapiSta->wapiUskUpdate.micKey,data+26,16); ++ pWapiSta->wapiUskUpdate.keyId = *(data+42); ++ pWapiSta->wapiUskUpdate.bTxEnable = false; ++ } ++ } ++ } ++ break; ++ case 2: //msk ++ if(bAuthenticator){ //authenticator ++ pWapiInfo->wapiTxMsk.bSet = true; ++ memcpy(pWapiInfo->wapiTxMsk.dataKey,data+10,16); ++ memcpy(pWapiInfo->wapiTxMsk.micKey,data+26,16); ++ pWapiInfo->wapiTxMsk.keyId = *(data+42); ++ pWapiInfo->wapiTxMsk.bTxEnable = true; ++ memcpy(pWapiInfo->lastTxMulticastPN,WapiAEMultiCastPNInitialValueSrc,16); ++ ++ if(!bUpdate){ //first ++ WAPI_TRACE(WAPI_INIT, "AE fisrt set msk \n"); ++ if(!pWapiSta->bSetkeyOk) ++ pWapiSta->bSetkeyOk = true; ++ pWapiInfo->bFirstAuthentiateInProgress= false; ++ }else{ //update ++ WAPI_TRACE(WAPI_INIT,"AE update msk \n"); ++ } ++ ++ WAPI_DATA(WAPI_INIT, "SetKey - AE MSK Data Key", pWapiInfo->wapiTxMsk.dataKey, 16); ++ WAPI_DATA(WAPI_INIT, "SetKey - AE MSK Mic Key", pWapiInfo->wapiTxMsk.micKey, 16); ++ } ++ else{ ++ if(!bUpdate){ ++ WAPI_TRACE(WAPI_INIT,"ASUE fisrt set msk \n"); ++ pWapiSta->wapiMsk.bSet = true; ++ memcpy(pWapiSta->wapiMsk.dataKey,data+10,16); ++ memcpy(pWapiSta->wapiMsk.micKey,data+26,16); ++ pWapiSta->wapiMsk.keyId = *(data+42); ++ pWapiSta->wapiMsk.bTxEnable = false; ++ if(!pWapiSta->bSetkeyOk) ++ pWapiSta->bSetkeyOk = true; ++ pWapiInfo->bFirstAuthentiateInProgress= false; ++ WAPI_DATA(WAPI_INIT, "SetKey - ASUE MSK Data Key", pWapiSta->wapiMsk.dataKey, 16); ++ WAPI_DATA(WAPI_INIT, "SetKey - ASUE MSK Mic Key", pWapiSta->wapiMsk.micKey, 16); ++ }else{ ++ WAPI_TRACE(WAPI_INIT,"ASUE update msk \n"); ++ pWapiSta->wapiMskUpdate.bSet = true; ++ memcpy(pWapiSta->wapiMskUpdate.dataKey,data+10,16); ++ memcpy(pWapiSta->wapiMskUpdate.micKey,data+26,16); ++ pWapiSta->wapiMskUpdate.keyId = *(data+42); ++ pWapiSta->wapiMskUpdate.bTxEnable = false; ++ } ++ } ++ break; ++ default: ++ WAPI_TRACE(WAPI_ERR,"Unknown Flag \n"); ++ break; ++ } ++ } ++ } ++ } ++ WAPI_TRACE(WAPI_INIT, "<===========%s\n", __FUNCTION__); ++} ++ ++ ++void wapi_test_init(struct _adapter *padapter) ++{ ++ u8 keybuf[100]; ++ u8 mac_addr[6]={0x00,0xe0,0x4c,0x72,0x04,0x70}; ++ u8 UskDataKey[16]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; ++ u8 UskMicKey[16]={0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f}; ++ u8 UskId = 0; ++ u8 MskDataKey[16]={0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f}; ++ u8 MskMicKey[16]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f}; ++ u8 MskId = 0; ++ ++ WAPI_TRACE(WAPI_INIT, "===========>%s\n", __FUNCTION__); ++ ++ //Enable Wapi ++ WAPI_TRACE(WAPI_INIT, "%s: Enable wapi!!!!\n", __FUNCTION__); ++ padapter->wapiInfo.bWapiEnable = true; ++ padapter->pairwise_key_type = KEY_TYPE_SMS4; ++ ieee->group_key_type = KEY_TYPE_SMS4; ++ padapter->wapiInfo.extra_prefix_len = WAPI_EXT_LEN; ++ padapter->wapiInfo.extra_postfix_len = SMS4_MIC_LEN; ++ ++ //set usk ++ WAPI_TRACE(WAPI_INIT, "%s: Set USK!!!!\n", __FUNCTION__); ++ memset(keybuf,0,100); ++ keybuf[0] = 1; //set usk ++ keybuf[1] = 1; //enable tx ++ keybuf[2] = 1; //AE ++ keybuf[3] = 0; //not update ++ ++ memcpy(keybuf+4,mac_addr,6); ++ memcpy(keybuf+10,UskDataKey,16); ++ memcpy(keybuf+26,UskMicKey,16); ++ keybuf[42]=UskId; ++ wapi_test_set_key(padapter, keybuf); ++ ++ memset(keybuf,0,100); ++ keybuf[0] = 1; //set usk ++ keybuf[1] = 1; //enable tx ++ keybuf[2] = 0; //AE ++ keybuf[3] = 0; //not update ++ ++ memcpy(keybuf+4,mac_addr,6); ++ memcpy(keybuf+10,UskDataKey,16); ++ memcpy(keybuf+26,UskMicKey,16); ++ keybuf[42]=UskId; ++ wapi_test_set_key(padapter, keybuf); ++ ++ //set msk ++ WAPI_TRACE(WAPI_INIT, "%s: Set MSK!!!!\n", __FUNCTION__); ++ memset(keybuf,0,100); ++ keybuf[0] = 2; //set msk ++ keybuf[1] = 1; //Enable TX ++ keybuf[2] = 1; //AE ++ keybuf[3] = 0; //not update ++ memcpy(keybuf+4,mac_addr,6); ++ memcpy(keybuf+10,MskDataKey,16); ++ memcpy(keybuf+26,MskMicKey,16); ++ keybuf[42] = MskId; ++ wapi_test_set_key(padapter, keybuf); ++ ++ memset(keybuf,0,100); ++ keybuf[0] = 2; //set msk ++ keybuf[1] = 1; //Enable TX ++ keybuf[2] = 0; //AE ++ keybuf[3] = 0; //not update ++ memcpy(keybuf+4,mac_addr,6); ++ memcpy(keybuf+10,MskDataKey,16); ++ memcpy(keybuf+26,MskMicKey,16); ++ keybuf[42] = MskId; ++ wapi_test_set_key(padapter, keybuf); ++ WAPI_TRACE(WAPI_INIT, "<===========%s\n", __FUNCTION__); ++} ++#endif ++ ++void rtw_wapi_get_iv(_adapter *padapter,u8 *pRA, u8*IV) ++{ ++ PWLAN_HEADER_WAPI_EXTENSION pWapiExt = NULL; ++ PRT_WAPI_T pWapiInfo = &padapter->wapiInfo; ++ bool bPNOverflow = false; ++ bool bFindMatchPeer = false; ++ PRT_WAPI_STA_INFO pWapiSta = NULL; ++ ++ pWapiExt = (PWLAN_HEADER_WAPI_EXTENSION)IV; ++ ++ WAPI_DATA(WAPI_RX,"wapi_get_iv: pra",pRA,6); ++ ++ if(IS_MCAST(pRA)){ ++ if(!pWapiInfo->wapiTxMsk.bTxEnable){ ++ WAPI_TRACE(WAPI_ERR,"%s: bTxEnable = 0!!\n",__FUNCTION__); ++ return; ++ } ++ ++ if(pWapiInfo->wapiTxMsk.keyId <= 1){ ++ pWapiExt->KeyIdx = pWapiInfo->wapiTxMsk.keyId; ++ pWapiExt->Reserved = 0; ++ bPNOverflow = WapiIncreasePN(pWapiInfo->lastTxMulticastPN, 1); ++ memcpy(pWapiExt->PN, pWapiInfo->lastTxMulticastPN, 16); ++ } ++ } ++ else ++ { ++ if(list_empty(&pWapiInfo->wapiSTAUsedList)){ ++ WAPI_TRACE(WAPI_RX,"rtw_wapi_get_iv: list is empty \n"); ++ _rtw_memset(IV,10,18); ++ return; ++ } ++ else{ ++ list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list){ ++ WAPI_DATA(WAPI_RX,"rtw_wapi_get_iv: peermacaddr ",pWapiSta->PeerMacAddr,6); ++ if (_rtw_memcmp((u8*)pWapiSta->PeerMacAddr, pRA, 6) == _TRUE) { ++ bFindMatchPeer = true; ++ break; ++ } ++ } ++ ++ WAPI_TRACE(WAPI_RX,"bFindMatchPeer: %d \n",bFindMatchPeer); ++ WAPI_DATA(WAPI_RX,"Addr",pRA,6); ++ ++ if (bFindMatchPeer){ ++ if((!pWapiSta->wapiUskUpdate.bTxEnable) && (!pWapiSta->wapiUsk.bTxEnable)) ++ return; ++ ++ if (pWapiSta->wapiUsk.keyId <= 1){ ++ if(pWapiSta->wapiUskUpdate.bTxEnable) ++ pWapiExt->KeyIdx = pWapiSta->wapiUskUpdate.keyId; ++ else ++ pWapiExt->KeyIdx = pWapiSta->wapiUsk.keyId; ++ ++ pWapiExt->Reserved = 0; ++ bPNOverflow = WapiIncreasePN(pWapiSta->lastTxUnicastPN, 2); ++ _rtw_memcpy(pWapiExt->PN, pWapiSta->lastTxUnicastPN, 16); ++ ++ } ++ } ++ } ++ ++ } ++ ++} ++ ++bool rtw_wapi_drop_for_key_absent(_adapter *padapter,u8 *pRA) ++{ ++ PRT_WAPI_T pWapiInfo = &padapter->wapiInfo; ++ bool bFindMatchPeer = false; ++ bool bDrop = false; ++ PRT_WAPI_STA_INFO pWapiSta = NULL; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ WAPI_DATA(WAPI_RX,"rtw_wapi_drop_for_key_absent: ra ",pRA,6); ++ ++ if(psecuritypriv->dot11PrivacyAlgrthm == _SMS4_) ++ { ++ if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) ++ return true; ++ ++ if(IS_MCAST(pRA)){ ++ if(!pWapiInfo->wapiTxMsk.bTxEnable){ ++ bDrop = true; ++ WAPI_TRACE(WAPI_RX,"rtw_wapi_drop_for_key_absent: multicast key is absent \n"); ++ return bDrop; ++ } ++ } ++ else{ ++ if(!list_empty(&pWapiInfo->wapiSTAUsedList)){ ++ list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list){ ++ WAPI_DATA(WAPI_RX,"rtw_wapi_drop_for_key_absent: pWapiSta->PeerMacAddr ",pWapiSta->PeerMacAddr,6); ++ if (_rtw_memcmp(pRA, pWapiSta->PeerMacAddr, 6) == _TRUE){ ++ bFindMatchPeer = true; ++ break; ++ } ++ } ++ if (bFindMatchPeer) { ++ if (!pWapiSta->wapiUsk.bTxEnable){ ++ bDrop = true; ++ WAPI_TRACE(WAPI_RX,"rtw_wapi_drop_for_key_absent: unicast key is absent \n"); ++ return bDrop; ++ } ++ } ++ else{ ++ bDrop = true; ++ WAPI_TRACE(WAPI_RX,"rtw_wapi_drop_for_key_absent: no peer find \n"); ++ return bDrop; ++ } ++ ++ } ++ else{ ++ bDrop = true; ++ WAPI_TRACE(WAPI_RX,"rtw_wapi_drop_for_key_absent: no sta exist \n"); ++ return bDrop; ++ } ++ } ++ } ++ else ++ { ++ return bDrop; ++ } ++ ++ return bDrop; ++} ++ ++#endif +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_wapi_sms4.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_wapi_sms4.c +new file mode 100644 +index 00000000..6126ed9a +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_wapi_sms4.c +@@ -0,0 +1,923 @@ ++#ifdef CONFIG_WAPI_SUPPORT ++ ++#include ++#include ++#include ++#include ++ ++ ++#ifdef CONFIG_WAPI_SW_SMS4 ++ ++#define WAPI_LITTLE_ENDIAN ++//#define BIG_ENDIAN ++#define ENCRYPT 0 ++#define DECRYPT 1 ++ ++ ++/********************************************************** ++ **********************************************************/ ++const u8 Sbox[256] = { ++0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05, ++0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99, ++0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62, ++0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6, ++0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8, ++0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35, ++0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87, ++0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e, ++0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1, ++0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3, ++0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f, ++0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51, ++0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8, ++0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0, ++0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84, ++0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48 ++}; ++ ++const u32 CK[32] = { ++ 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, ++ 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, ++ 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, ++ 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, ++ 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, ++ 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, ++ 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, ++ 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279 }; ++ ++#define Rotl(_x, _y) (((_x) << (_y)) | ((_x) >> (32 - (_y)))) ++ ++#define ByteSub(_A) (Sbox[(_A) >> 24 & 0xFF] << 24 | \ ++ Sbox[(_A) >> 16 & 0xFF] << 16 | \ ++ Sbox[(_A) >> 8 & 0xFF] << 8 | \ ++ Sbox[(_A) & 0xFF]) ++ ++#define L1(_B) ((_B) ^ Rotl(_B, 2) ^ Rotl(_B, 10) ^ Rotl(_B, 18) ^ Rotl(_B, 24)) ++#define L2(_B) ((_B) ^ Rotl(_B, 13) ^ Rotl(_B, 23)) ++ ++static void ++xor_block(void *dst, void *src1, void *src2) ++/* 128-bit xor: *dst = *src1 xor *src2. Pointers must be 32-bit aligned */ ++{ ++ ((u32 *)dst)[0] = ((u32 *)src1)[0] ^ ((u32 *)src2)[0]; ++ ((u32 *)dst)[1] = ((u32 *)src1)[1] ^ ((u32 *)src2)[1]; ++ ((u32 *)dst)[2] = ((u32 *)src1)[2] ^ ((u32 *)src2)[2]; ++ ((u32 *)dst)[3] = ((u32 *)src1)[3] ^ ((u32 *)src2)[3]; ++} ++ ++ ++void SMS4Crypt(u8 *Input, u8 *Output, u32 *rk) ++{ ++ u32 r, mid, x0, x1, x2, x3, *p; ++ p = (u32 *)Input; ++ x0 = p[0]; ++ x1 = p[1]; ++ x2 = p[2]; ++ x3 = p[3]; ++#ifdef WAPI_LITTLE_ENDIAN ++ x0 = Rotl(x0, 16); x0 = ((x0 & 0x00FF00FF) << 8) | ((x0 & 0xFF00FF00) >> 8); ++ x1 = Rotl(x1, 16); x1 = ((x1 & 0x00FF00FF) << 8) | ((x1 & 0xFF00FF00) >> 8); ++ x2 = Rotl(x2, 16); x2 = ((x2 & 0x00FF00FF) << 8) | ((x2 & 0xFF00FF00) >> 8); ++ x3 = Rotl(x3, 16); x3 = ((x3 & 0x00FF00FF) << 8) | ((x3 & 0xFF00FF00) >> 8); ++#endif ++ for (r = 0; r < 32; r += 4) ++ { ++ mid = x1 ^ x2 ^ x3 ^ rk[r + 0]; ++ mid = ByteSub(mid); ++ x0 ^= L1(mid); ++ mid = x2 ^ x3 ^ x0 ^ rk[r + 1]; ++ mid = ByteSub(mid); ++ x1 ^= L1(mid); ++ mid = x3 ^ x0 ^ x1 ^ rk[r + 2]; ++ mid = ByteSub(mid); ++ x2 ^= L1(mid); ++ mid = x0 ^ x1 ^ x2 ^ rk[r + 3]; ++ mid = ByteSub(mid); ++ x3 ^= L1(mid); ++ } ++#ifdef WAPI_LITTLE_ENDIAN ++ x0 = Rotl(x0, 16); x0 = ((x0 & 0x00FF00FF) << 8) | ((x0 & 0xFF00FF00) >> 8); ++ x1 = Rotl(x1, 16); x1 = ((x1 & 0x00FF00FF) << 8) | ((x1 & 0xFF00FF00) >> 8); ++ x2 = Rotl(x2, 16); x2 = ((x2 & 0x00FF00FF) << 8) | ((x2 & 0xFF00FF00) >> 8); ++ x3 = Rotl(x3, 16); x3 = ((x3 & 0x00FF00FF) << 8) | ((x3 & 0xFF00FF00) >> 8); ++#endif ++ p = (u32 *)Output; ++ p[0] = x3; ++ p[1] = x2; ++ p[2] = x1; ++ p[3] = x0; ++} ++ ++ ++ ++void SMS4KeyExt(u8 *Key, u32 *rk, u32 CryptFlag) ++{ ++ u32 r, mid, x0, x1, x2, x3, *p; ++ ++ p = (u32 *)Key; ++ x0 = p[0]; ++ x1 = p[1]; ++ x2 = p[2]; ++ x3 = p[3]; ++#ifdef WAPI_LITTLE_ENDIAN ++ x0 = Rotl(x0, 16); x0 = ((x0 & 0xFF00FF) << 8) | ((x0 & 0xFF00FF00) >> 8); ++ x1 = Rotl(x1, 16); x1 = ((x1 & 0xFF00FF) << 8) | ((x1 & 0xFF00FF00) >> 8); ++ x2 = Rotl(x2, 16); x2 = ((x2 & 0xFF00FF) << 8) | ((x2 & 0xFF00FF00) >> 8); ++ x3 = Rotl(x3, 16); x3 = ((x3 & 0xFF00FF) << 8) | ((x3 & 0xFF00FF00) >> 8); ++#endif ++ ++ x0 ^= 0xa3b1bac6; ++ x1 ^= 0x56aa3350; ++ x2 ^= 0x677d9197; ++ x3 ^= 0xb27022dc; ++ for (r = 0; r < 32; r += 4) ++ { ++ mid = x1 ^ x2 ^ x3 ^ CK[r + 0]; ++ mid = ByteSub(mid); ++ rk[r + 0] = x0 ^= L2(mid); ++ mid = x2 ^ x3 ^ x0 ^ CK[r + 1]; ++ mid = ByteSub(mid); ++ rk[r + 1] = x1 ^= L2(mid); ++ mid = x3 ^ x0 ^ x1 ^ CK[r + 2]; ++ mid = ByteSub(mid); ++ rk[r + 2] = x2 ^= L2(mid); ++ mid = x0 ^ x1 ^ x2 ^ CK[r + 3]; ++ mid = ByteSub(mid); ++ rk[r + 3] = x3 ^= L2(mid); ++ } ++ if (CryptFlag == DECRYPT) ++ { ++ for (r = 0; r < 16; r++) ++ mid = rk[r], rk[r] = rk[31 - r], rk[31 - r] = mid; ++ } ++} ++ ++ ++void WapiSMS4Cryption(u8 *Key, u8 *IV, u8 *Input, u16 InputLength, ++ u8 *Output, u16 *OutputLength, u32 CryptFlag) ++{ ++ u32 blockNum,i,j, rk[32]; ++ u16 remainder; ++ u8 blockIn[16],blockOut[16], tempIV[16], k; ++ ++ *OutputLength = 0; ++ remainder = InputLength & 0x0F; ++ blockNum = InputLength >> 4; ++ if(remainder !=0) ++ blockNum++; ++ else ++ remainder = 16; ++ ++ for(k=0;k<16;k++) ++ tempIV[k] = IV[15-k]; ++ ++ memcpy(blockIn, tempIV, 16); ++ ++ SMS4KeyExt((u8 *)Key, rk,CryptFlag); ++ ++ for(i=0; i> 4; ++ ++ for(k=0;k<16;k++) ++ tempIV[k] = IV[15-k]; ++ ++ memcpy(BlockIn, tempIV, 16); ++ ++ SMS4KeyExt((u8 *)Key, rk, ENCRYPT); ++ ++ SMS4Crypt((u8 *)BlockIn, BlockOut, rk); ++ ++ for(i=0; i> 4; ++ ++ for(i=0; i%s\n", __FUNCTION__); ++ ++ header = (struct ieee80211_hdr_3addr_qos *)pHeader; ++ memset(TempBuf, 0, 34); ++ memcpy(TempBuf, pHeader, 2); //FrameCtrl ++ pTemp = (u16*)TempBuf; ++ *pTemp &= 0xc78f; //bit4,5,6,11,12,13 ++ ++ memcpy((TempBuf+2), (pHeader+4), 12); //Addr1, Addr2 ++ memcpy((TempBuf+14), (pHeader+22), 2); // SeqCtrl ++ pTemp = (u16*)(TempBuf + 14); ++ *pTemp &= 0x000f; ++ ++ memcpy((TempBuf+16), (pHeader+16), 6); //Addr3 ++ ++ fc = le16_to_cpu(header->frame_ctl); ++ ++ ++ ++ if (GetFrDs((u16*)&fc) && GetToDs((u16 *)&fc)) ++ { ++ memcpy((TempBuf+22), (pHeader+24), 6); ++ QosOffset = 30; ++ }else{ ++ memset((TempBuf+22), 0, 6); ++ QosOffset = 24; ++ } ++ ++ if((fc & 0x0088) == 0x0088){ ++ memcpy((TempBuf+28), (pHeader+QosOffset), 2); ++ TempLen += 2; ++ //IV = pHeader + QosOffset + 2 + SNAP_SIZE + sizeof(u16) + 2; ++ IV = pHeader + QosOffset + 2 + 2; ++ }else{ ++ IV = pHeader + QosOffset + 2; ++ //IV = pHeader + QosOffset + SNAP_SIZE + sizeof(u16) + 2; ++ } ++ ++ TempBuf[TempLen-1] = (u8)(DataLen & 0xff); ++ TempBuf[TempLen-2] = (u8)((DataLen & 0xff00)>>8); ++ TempBuf[TempLen-4] = KeyIdx; ++ ++ WAPI_DATA(WAPI_TX, "CalculateMic - KEY", MicKey, 16); ++ WAPI_DATA(WAPI_TX, "CalculateMic - IV", IV, 16); ++ WAPI_DATA(WAPI_TX, "CalculateMic - TempBuf", TempBuf, TempLen); ++ WAPI_DATA(WAPI_TX, "CalculateMic - pData", pData, DataLen); ++ ++ WapiSMS4CalculateMic(MicKey, IV, TempBuf, TempLen, ++ pData, DataLen, MicBuffer, &MicLen); ++ ++ if (MicLen != 16) ++ WAPI_TRACE(WAPI_ERR,"%s: MIC Length Error!!\n",__FUNCTION__); ++ ++ WAPI_TRACE(WAPI_TX|WAPI_RX, "<=========%s\n", __FUNCTION__); ++#endif ++} ++ ++/* AddCount: 1 or 2. ++ * If overflow, return 1, ++ * else return 0. ++ */ ++u8 WapiIncreasePN(u8 *PN, u8 AddCount) ++{ ++ u8 i; ++ ++ if (NULL == PN) ++ return 1; ++ //YJ,test,091102 ++ /* ++ if(AddCount == 2){ ++ DBG_8192C("############################%s(): PN[0]=0x%x\n", __FUNCTION__, PN[0]); ++ if(PN[0] == 0x48){ ++ PN[0] += AddCount; ++ return 1; ++ }else{ ++ PN[0] += AddCount; ++ return 0; ++ } ++ } ++ */ ++ //YJ,test,091102,end ++ ++ for (i=0; i<16; i++) ++ { ++ if (PN[i] + AddCount <= 0xff) ++ { ++ PN[i] += AddCount; ++ return 0; ++ } ++ else ++ { ++ PN[i] += AddCount; ++ AddCount = 1; ++ } ++ } ++ return 1; ++} ++ ++ ++void WapiGetLastRxUnicastPNForQoSData( ++ u8 UserPriority, ++ PRT_WAPI_STA_INFO pWapiStaInfo, ++ u8 *PNOut ++) ++{ ++ WAPI_TRACE(WAPI_RX, "===========> %s\n", __FUNCTION__); ++ switch(UserPriority) ++ { ++ case 0: ++ case 3: ++ memcpy(PNOut,pWapiStaInfo->lastRxUnicastPNBEQueue,16); ++ break; ++ case 1: ++ case 2: ++ memcpy(PNOut,pWapiStaInfo->lastRxUnicastPNBKQueue,16); ++ break; ++ case 4: ++ case 5: ++ memcpy(PNOut,pWapiStaInfo->lastRxUnicastPNVIQueue,16); ++ break; ++ case 6: ++ case 7: ++ memcpy(PNOut,pWapiStaInfo->lastRxUnicastPNVOQueue,16); ++ break; ++ default: ++ WAPI_TRACE(WAPI_ERR, "%s: Unknown TID \n", __FUNCTION__); ++ break; ++ } ++ WAPI_TRACE(WAPI_RX, "<=========== %s\n", __FUNCTION__); ++} ++ ++ ++void WapiSetLastRxUnicastPNForQoSData( ++ u8 UserPriority, ++ u8 *PNIn, ++ PRT_WAPI_STA_INFO pWapiStaInfo ++) ++{ ++ WAPI_TRACE(WAPI_RX, "===========> %s\n", __FUNCTION__); ++ switch(UserPriority) ++ { ++ case 0: ++ case 3: ++ memcpy(pWapiStaInfo->lastRxUnicastPNBEQueue,PNIn,16); ++ break; ++ case 1: ++ case 2: ++ memcpy(pWapiStaInfo->lastRxUnicastPNBKQueue,PNIn,16); ++ break; ++ case 4: ++ case 5: ++ memcpy(pWapiStaInfo->lastRxUnicastPNVIQueue,PNIn,16); ++ break; ++ case 6: ++ case 7: ++ memcpy(pWapiStaInfo->lastRxUnicastPNVOQueue,PNIn,16); ++ break; ++ default: ++ WAPI_TRACE(WAPI_ERR, "%s: Unknown TID \n", __FUNCTION__); ++ break; ++ } ++ WAPI_TRACE(WAPI_RX, "<=========== %s\n", __FUNCTION__); ++} ++ ++ ++/**************************************************************************** ++ FALSE not RX-Reorder ++ TRUE do RX Reorder ++add to support WAPI to N-mode ++*****************************************************************************/ ++u8 WapiCheckPnInSwDecrypt( ++ _adapter *padapter, ++ struct sk_buff *pskb ++) ++{ ++ u8 ret = false; ++ ++#if 0 ++ struct ieee80211_hdr_3addr_qos *header; ++ u16 fc; ++ u8 *pDaddr, *pTaddr, *pRaddr; ++ ++ header = (struct ieee80211_hdr_3addr_qos *)pskb->data; ++ pTaddr = header->addr2; ++ pRaddr = header->addr1; ++ fc = le16_to_cpu(header->frame_ctl); ++ ++ if(GetToDs(&fc)) ++ pDaddr = header->addr3; ++ else ++ pDaddr = header->addr1; ++ ++ if ((_rtw_memcmp(pRaddr, padapter->pnetdev->dev_addr, ETH_ALEN) == 0) ++ && ! (pDaddr) ++ && (GetFrameType(&fc) == WIFI_QOS_DATA_TYPE)) ++ //&& ieee->pHTInfo->bCurrentHTSupport && ++ //ieee->pHTInfo->bCurRxReorderEnable) ++ ret = false; ++ else ++ ret = true; ++#endif ++ WAPI_TRACE(WAPI_RX, "%s: return %d\n", __FUNCTION__, ret); ++ return ret; ++} ++ ++int SecSMS4HeaderFillIV(_adapter *padapter, u8 *pxmitframe) ++{ ++ struct pkt_attrib *pattrib = &((struct xmit_frame*)pxmitframe)->attrib; ++ u8 * frame = ((struct xmit_frame *)pxmitframe)->buf_addr + TXDESC_OFFSET; ++ u8 *pSecHeader = NULL, *pos = NULL, *pRA = NULL; ++ u8 bPNOverflow = false, bFindMatchPeer = false, hdr_len = 0; ++ PWLAN_HEADER_WAPI_EXTENSION pWapiExt = NULL; ++ PRT_WAPI_T pWapiInfo = &padapter->wapiInfo; ++ PRT_WAPI_STA_INFO pWapiSta = NULL; ++ int ret = 0; ++ ++ WAPI_TRACE(WAPI_TX, "=========>%s\n", __FUNCTION__); ++ ++ return ret; ++#if 0 ++ hdr_len = sMacHdrLng; ++ if (GetFrameType(pskb->data) == WIFI_QOS_DATA_TYPE) ++ { ++ hdr_len += 2; ++ } ++ //hdr_len += SNAP_SIZE + sizeof(u16); ++ ++ pos = skb_push(pskb, padapter->wapiInfo.extra_prefix_len); ++ memmove(pos, pos+padapter->wapiInfo.extra_prefix_len, hdr_len); ++ ++ pSecHeader = pskb->data + hdr_len; ++ pWapiExt = (PWLAN_HEADER_WAPI_EXTENSION)pSecHeader; ++ pRA = pskb->data + 4; ++ ++ WAPI_DATA(WAPI_TX, "FillIV - Before Fill IV", pskb->data, pskb->len); ++ ++ //Address 1 is always receiver's address ++ if( IS_MCAST(pRA) ){ ++ if(!pWapiInfo->wapiTxMsk.bTxEnable){ ++ WAPI_TRACE(WAPI_ERR,"%s: bTxEnable = 0!!\n",__FUNCTION__); ++ return -2; ++ } ++ if(pWapiInfo->wapiTxMsk.keyId <= 1){ ++ pWapiExt->KeyIdx = pWapiInfo->wapiTxMsk.keyId; ++ pWapiExt->Reserved = 0; ++ bPNOverflow = WapiIncreasePN(pWapiInfo->lastTxMulticastPN, 1); ++ memcpy(pWapiExt->PN, pWapiInfo->lastTxMulticastPN, 16); ++ if (bPNOverflow){ ++ // Update MSK Notification. ++ WAPI_TRACE(WAPI_ERR,"===============>%s():multicast PN overflow\n",__FUNCTION__); ++ rtw_wapi_app_event_handler(padapter,NULL,0,pRA, false, false, true, 0, false); ++ } ++ }else{ ++ WAPI_TRACE(WAPI_ERR,"%s: Invalid Wapi Multicast KeyIdx!!\n",__FUNCTION__); ++ ret = -3; ++ } ++ } ++ else{ ++ list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { ++ if(!memcmp(pWapiSta->PeerMacAddr,pRA,6)){ ++ bFindMatchPeer = true; ++ break; ++ } ++ } ++ if (bFindMatchPeer){ ++ if((!pWapiSta->wapiUskUpdate.bTxEnable) && (!pWapiSta->wapiUsk.bTxEnable)){ ++ WAPI_TRACE(WAPI_ERR,"%s: bTxEnable = 0!!\n",__FUNCTION__); ++ return -4; ++ } ++ if (pWapiSta->wapiUsk.keyId <= 1){ ++ if(pWapiSta->wapiUskUpdate.bTxEnable) ++ pWapiExt->KeyIdx = pWapiSta->wapiUskUpdate.keyId; ++ else ++ pWapiExt->KeyIdx = pWapiSta->wapiUsk.keyId; ++ ++ pWapiExt->Reserved = 0; ++ bPNOverflow = WapiIncreasePN(pWapiSta->lastTxUnicastPN, 2); ++ memcpy(pWapiExt->PN, pWapiSta->lastTxUnicastPN, 16); ++ if (bPNOverflow){ ++ // Update USK Notification. ++ WAPI_TRACE(WAPI_ERR,"===============>%s():unicast PN overflow\n",__FUNCTION__); ++ rtw_wapi_app_event_handler(padapter,NULL,0,pWapiSta->PeerMacAddr, false, true, false, 0, false); ++ } ++ }else{ ++ WAPI_TRACE(WAPI_ERR,"%s: Invalid Wapi Unicast KeyIdx!!\n",__FUNCTION__); ++ ret = -5; ++ } ++ } ++ else{ ++ WAPI_TRACE(WAPI_ERR,"%s: Can not find Peer Sta "MAC_FMT"!!\n",__FUNCTION__, MAC_ARG(pRA)); ++ ret = -6; ++ } ++ } ++ ++ WAPI_DATA(WAPI_TX, "FillIV - After Fill IV", pskb->data, pskb->len); ++ WAPI_TRACE(WAPI_TX, "<=========%s\n", __FUNCTION__); ++ return ret; ++#endif ++} ++ ++// WAPI SW Enc: must have done Coalesce! ++void SecSWSMS4Encryption( ++ _adapter *padapter, ++ u8 * pxmitframe ++ ) ++{ ++ PRT_WAPI_T pWapiInfo = &padapter->wapiInfo; ++ PRT_WAPI_STA_INFO pWapiSta = NULL; ++ u8 *pframe = ((struct xmit_frame*)pxmitframe)->buf_addr + TXDESC_SIZE; ++ struct pkt_attrib *pattrib = &((struct xmit_frame*)pxmitframe)->attrib; ++ ++ u8 *SecPtr = NULL, *pRA, *pMicKey = NULL, *pDataKey = NULL, *pIV = NULL; ++ u8 IVOffset, DataOffset, bFindMatchPeer = false, KeyIdx = 0, MicBuffer[16]; ++ u16 OutputLength; ++ ++ WAPI_TRACE(WAPI_TX, "=========>%s\n", __FUNCTION__); ++ ++ WAPI_TRACE(WAPI_TX,"hdrlen: %d \n",pattrib->hdrlen); ++ ++ return; ++ ++ DataOffset = pattrib->hdrlen + pattrib->iv_len; ++ ++ pRA = pframe + 4; ++ ++ ++ if( IS_MCAST(pRA) ){ ++ KeyIdx = pWapiInfo->wapiTxMsk.keyId; ++ pIV = pWapiInfo->lastTxMulticastPN; ++ pMicKey = pWapiInfo->wapiTxMsk.micKey; ++ pDataKey = pWapiInfo->wapiTxMsk.dataKey; ++ }else{ ++ if (!list_empty(&(pWapiInfo->wapiSTAUsedList))){ ++ list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { ++ if (0 == memcmp(pWapiSta->PeerMacAddr, pRA, 6)){ ++ bFindMatchPeer = true; ++ break; ++ } ++ } ++ ++ if (bFindMatchPeer){ ++ if (pWapiSta->wapiUskUpdate.bTxEnable){ ++ KeyIdx = pWapiSta->wapiUskUpdate.keyId; ++ WAPI_TRACE(WAPI_TX, "%s(): Use update USK!! KeyIdx=%d\n", __FUNCTION__, KeyIdx); ++ pIV = pWapiSta->lastTxUnicastPN; ++ pMicKey = pWapiSta->wapiUskUpdate.micKey; ++ pDataKey = pWapiSta->wapiUskUpdate.dataKey; ++ }else{ ++ KeyIdx = pWapiSta->wapiUsk.keyId; ++ WAPI_TRACE(WAPI_TX, "%s(): Use USK!! KeyIdx=%d\n", __FUNCTION__, KeyIdx); ++ pIV = pWapiSta->lastTxUnicastPN; ++ pMicKey = pWapiSta->wapiUsk.micKey; ++ pDataKey = pWapiSta->wapiUsk.dataKey; ++ } ++ }else{ ++ WAPI_TRACE(WAPI_ERR,"%s: Can not find Peer Sta!!\n",__FUNCTION__); ++ return; ++ } ++ }else{ ++ WAPI_TRACE(WAPI_ERR,"%s: wapiSTAUsedList is empty!!\n",__FUNCTION__); ++ return; ++ } ++ } ++ ++ SecPtr = pframe; ++ SecCalculateMicSMS4(KeyIdx, pMicKey, SecPtr, (SecPtr+DataOffset), pattrib->pktlen, MicBuffer); ++ ++ WAPI_DATA(WAPI_TX, "Encryption - MIC", MicBuffer, padapter->wapiInfo.extra_postfix_len); ++ ++ memcpy(pframe+pattrib->hdrlen+pattrib->iv_len+pattrib->pktlen-pattrib->icv_len, ++ (u8 *)MicBuffer, ++ padapter->wapiInfo.extra_postfix_len ++ ); ++ ++ ++ WapiSMS4Encryption(pDataKey, pIV, (SecPtr+DataOffset),pattrib->pktlen+pattrib->icv_len, (SecPtr+DataOffset), &OutputLength); ++ ++ WAPI_DATA(WAPI_TX, "Encryption - After SMS4 encryption",pframe,pattrib->hdrlen+pattrib->iv_len+pattrib->pktlen); ++ ++ WAPI_TRACE(WAPI_TX, "<=========%s\n", __FUNCTION__); ++} ++ ++u8 SecSWSMS4Decryption( ++ _adapter *padapter, ++ u8 *precv_frame, ++ struct recv_priv *precv_priv ++ ) ++{ ++ PRT_WAPI_T pWapiInfo = &padapter->wapiInfo; ++ struct recv_frame_hdr *precv_hdr; ++ PRT_WAPI_STA_INFO pWapiSta = NULL; ++ u8 IVOffset, DataOffset, bFindMatchPeer = false, bUseUpdatedKey = false; ++ u8 KeyIdx, MicBuffer[16], lastRxPNforQoS[16]; ++ u8 *pRA, *pTA, *pMicKey, *pDataKey, *pLastRxPN, *pRecvPN, *pSecData, *pRecvMic, *pos; ++ u8 TID = 0; ++ u16 OutputLength, DataLen; ++ u8 bQosData; ++ struct sk_buff * pskb; ++ ++ WAPI_TRACE(WAPI_RX, "=========>%s\n", __FUNCTION__); ++ ++ return 0; ++ ++ precv_hdr = &((union recv_frame*)precv_frame)->u.hdr; ++ pskb = (struct sk_buff *)(precv_hdr->rx_data); ++ precv_hdr->bWapiCheckPNInDecrypt = WapiCheckPnInSwDecrypt(padapter, pskb); ++ WAPI_TRACE(WAPI_RX, "=========>%s: check PN %d\n", __FUNCTION__,precv_hdr->bWapiCheckPNInDecrypt); ++ WAPI_DATA(WAPI_RX, "Decryption - Before decryption", pskb->data, pskb->len); ++ ++ IVOffset = sMacHdrLng; ++ bQosData = GetFrameType(pskb->data) == WIFI_QOS_DATA_TYPE; ++ if (bQosData){ ++ IVOffset += 2; ++ } ++ ++ //if(GetHTC()) ++ // IVOffset += 4; ++ ++ //IVOffset += SNAP_SIZE + sizeof(u16); ++ ++ DataOffset = IVOffset + padapter->wapiInfo.extra_prefix_len; ++ ++ pRA = pskb->data + 4; ++ pTA = pskb->data + 10; ++ KeyIdx = *(pskb->data + IVOffset); ++ pRecvPN = pskb->data + IVOffset + 2; ++ pSecData = pskb->data + DataOffset; ++ DataLen = pskb->len - DataOffset; ++ pRecvMic = pskb->data + pskb->len - padapter->wapiInfo.extra_postfix_len; ++ TID = GetTid(pskb->data); ++ ++ if (!list_empty(&(pWapiInfo->wapiSTAUsedList))){ ++ list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { ++ if (0 == memcmp(pWapiSta->PeerMacAddr, pTA, 6)){ ++ bFindMatchPeer = true; ++ break; ++ } ++ } ++ } ++ ++ if (!bFindMatchPeer){ ++ WAPI_TRACE(WAPI_ERR, "%s: Can not find Peer Sta "MAC_FMT" for Key Info!!!\n", __FUNCTION__, MAC_ARG(pTA)); ++ return false; ++ } ++ ++ if( IS_MCAST(pRA) ){ ++ WAPI_TRACE(WAPI_RX, "%s: Multicast decryption !!!\n", __FUNCTION__); ++ if (pWapiSta->wapiMsk.keyId == KeyIdx && pWapiSta->wapiMsk.bSet){ ++ pLastRxPN = pWapiSta->lastRxMulticastPN; ++ if (!WapiComparePN(pRecvPN, pLastRxPN)){ ++ WAPI_TRACE(WAPI_ERR, "%s: MSK PN is not larger than last, Dropped!!!\n", __FUNCTION__); ++ WAPI_DATA(WAPI_ERR, "pRecvPN:", pRecvPN, 16); ++ WAPI_DATA(WAPI_ERR, "pLastRxPN:", pLastRxPN, 16); ++ return false; ++ } ++ ++ memcpy(pLastRxPN, pRecvPN, 16); ++ pMicKey = pWapiSta->wapiMsk.micKey; ++ pDataKey = pWapiSta->wapiMsk.dataKey; ++ }else if (pWapiSta->wapiMskUpdate.keyId == KeyIdx && pWapiSta->wapiMskUpdate.bSet){ ++ WAPI_TRACE(WAPI_RX, "%s: Use Updated MSK for Decryption !!!\n", __FUNCTION__); ++ bUseUpdatedKey = true; ++ memcpy(pWapiSta->lastRxMulticastPN, pRecvPN, 16); ++ pMicKey = pWapiSta->wapiMskUpdate.micKey; ++ pDataKey = pWapiSta->wapiMskUpdate.dataKey; ++ }else{ ++ WAPI_TRACE(WAPI_ERR, "%s: Can not find MSK with matched KeyIdx(%d), Dropped !!!\n", __FUNCTION__,KeyIdx); ++ return false; ++ } ++ } ++ else{ ++ WAPI_TRACE(WAPI_RX, "%s: Unicast decryption !!!\n", __FUNCTION__); ++ if (pWapiSta->wapiUsk.keyId == KeyIdx && pWapiSta->wapiUsk.bSet){ ++ WAPI_TRACE(WAPI_RX, "%s: Use USK for Decryption!!!\n", __FUNCTION__); ++ if(precv_hdr->bWapiCheckPNInDecrypt){ ++ if(GetFrameType(pskb->data) == WIFI_QOS_DATA_TYPE){ ++ WapiGetLastRxUnicastPNForQoSData(TID, pWapiSta, lastRxPNforQoS); ++ pLastRxPN = lastRxPNforQoS; ++ }else{ ++ pLastRxPN = pWapiSta->lastRxUnicastPN; ++ } ++ if (!WapiComparePN(pRecvPN, pLastRxPN)){ ++ return false; ++ } ++ if(bQosData){ ++ WapiSetLastRxUnicastPNForQoSData(TID, pRecvPN, pWapiSta); ++ }else{ ++ memcpy(pWapiSta->lastRxUnicastPN, pRecvPN, 16); ++ } ++ }else{ ++ memcpy(precv_hdr->WapiTempPN,pRecvPN,16); ++ } ++ ++ if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE)) ++ { ++ if ((pRecvPN[0] & 0x1) == 0){ ++ WAPI_TRACE(WAPI_ERR, "%s: Rx USK PN is not odd when Infra STA mode, Dropped !!!\n", __FUNCTION__); ++ return false; ++ } ++ } ++ ++ pMicKey = pWapiSta->wapiUsk.micKey; ++ pDataKey = pWapiSta->wapiUsk.dataKey; ++ } ++ else if (pWapiSta->wapiUskUpdate.keyId == KeyIdx && pWapiSta->wapiUskUpdate.bSet ){ ++ WAPI_TRACE(WAPI_RX, "%s: Use Updated USK for Decryption!!!\n", __FUNCTION__); ++ if(pWapiSta->bAuthenticatorInUpdata) ++ bUseUpdatedKey = true; ++ else ++ bUseUpdatedKey = false; ++ ++ if(bQosData){ ++ WapiSetLastRxUnicastPNForQoSData(TID, pRecvPN, pWapiSta); ++ }else{ ++ memcpy(pWapiSta->lastRxUnicastPN, pRecvPN, 16); ++ } ++ pMicKey = pWapiSta->wapiUskUpdate.micKey; ++ pDataKey = pWapiSta->wapiUskUpdate.dataKey; ++ }else{ ++ WAPI_TRACE(WAPI_ERR, "%s: No valid USK!!!KeyIdx=%d pWapiSta->wapiUsk.keyId=%d pWapiSta->wapiUskUpdate.keyId=%d\n", __FUNCTION__, KeyIdx, pWapiSta->wapiUsk.keyId, pWapiSta->wapiUskUpdate.keyId); ++ //dump_buf(pskb->data,pskb->len); ++ return false; ++ } ++ } ++ ++ WAPI_DATA(WAPI_RX, "Decryption - DataKey", pDataKey, 16); ++ WAPI_DATA(WAPI_RX, "Decryption - IV", pRecvPN, 16); ++ WapiSMS4Decryption(pDataKey, pRecvPN, pSecData, DataLen, pSecData, &OutputLength); ++ ++ if (OutputLength != DataLen) ++ WAPI_TRACE(WAPI_ERR, "%s: Output Length Error!!!!\n", __FUNCTION__); ++ ++ WAPI_DATA(WAPI_RX, "Decryption - After decryption", pskb->data, pskb->len); ++ ++ DataLen -= padapter->wapiInfo.extra_postfix_len; ++ ++ SecCalculateMicSMS4(KeyIdx, pMicKey, pskb->data, pSecData, DataLen, MicBuffer); ++ ++ WAPI_DATA(WAPI_RX, "Decryption - MIC received", pRecvMic, SMS4_MIC_LEN); ++ WAPI_DATA(WAPI_RX, "Decryption - MIC calculated", MicBuffer, SMS4_MIC_LEN); ++ ++ if (0 == memcmp(MicBuffer, pRecvMic, padapter->wapiInfo.extra_postfix_len)){ ++ WAPI_TRACE(WAPI_RX, "%s: Check MIC OK!!\n", __FUNCTION__); ++ if (bUseUpdatedKey){ ++ // delete the old key ++ if ( IS_MCAST(pRA) ){ ++ WAPI_TRACE(WAPI_API, "%s(): AE use new update MSK!!\n", __FUNCTION__); ++ pWapiSta->wapiMsk.keyId = pWapiSta->wapiMskUpdate.keyId; ++ memcpy(pWapiSta->wapiMsk.dataKey, pWapiSta->wapiMskUpdate.dataKey, 16); ++ memcpy(pWapiSta->wapiMsk.micKey, pWapiSta->wapiMskUpdate.micKey, 16); ++ pWapiSta->wapiMskUpdate.bTxEnable = pWapiSta->wapiMskUpdate.bSet = false; ++ }else{ ++ WAPI_TRACE(WAPI_API, "%s(): AE use new update USK!!\n", __FUNCTION__); ++ pWapiSta->wapiUsk.keyId = pWapiSta->wapiUskUpdate.keyId; ++ memcpy(pWapiSta->wapiUsk.dataKey, pWapiSta->wapiUskUpdate.dataKey, 16); ++ memcpy(pWapiSta->wapiUsk.micKey, pWapiSta->wapiUskUpdate.micKey, 16); ++ pWapiSta->wapiUskUpdate.bTxEnable = pWapiSta->wapiUskUpdate.bSet = false; ++ } ++ } ++ }else{ ++ WAPI_TRACE(WAPI_ERR, "%s: Check MIC Error, Dropped !!!!\n", __FUNCTION__); ++ return false; ++ } ++ ++ pos = pskb->data; ++ memmove(pos+padapter->wapiInfo.extra_prefix_len, pos, IVOffset); ++ skb_pull(pskb, padapter->wapiInfo.extra_prefix_len); ++ ++ WAPI_TRACE(WAPI_RX, "<=========%s\n", __FUNCTION__); ++ ++ return true; ++} ++ ++u32 rtw_sms4_encrypt(_adapter *padapter, u8 *pxmitframe) ++{ ++ ++ u8 *pframe; ++ u32 res = _SUCCESS; ++ ++ WAPI_TRACE(WAPI_TX, "=========>%s\n", __FUNCTION__); ++ ++ if ((!padapter->WapiSupport) || (!padapter->wapiInfo.bWapiEnable)) ++ { ++ WAPI_TRACE(WAPI_TX, "<========== %s, WAPI not supported or enabled!\n", __FUNCTION__); ++ return _FAIL; ++ } ++ ++ if(((struct xmit_frame*)pxmitframe)->buf_addr==NULL) ++ return _FAIL; ++ ++ pframe = ((struct xmit_frame*)pxmitframe)->buf_addr + TXDESC_OFFSET; ++ ++ SecSWSMS4Encryption(padapter, pxmitframe); ++ ++ WAPI_TRACE(WAPI_TX, "<=========%s\n", __FUNCTION__); ++ return res; ++} ++ ++u32 rtw_sms4_decrypt(_adapter *padapter, u8 *precvframe) ++{ ++ u8 *pframe; ++ u32 res = _SUCCESS; ++ ++ WAPI_TRACE(WAPI_RX, "=========>%s\n", __FUNCTION__); ++ ++ if ((!padapter->WapiSupport) || (!padapter->wapiInfo.bWapiEnable)) ++ { ++ WAPI_TRACE(WAPI_RX, "<========== %s, WAPI not supported or enabled!\n", __FUNCTION__); ++ return _FAIL; ++ } ++ ++ ++ //drop packet when hw decrypt fail ++ //return tempraily ++ return _FAIL; ++ ++ //pframe=(unsigned char *)((union recv_frame*)precvframe)->u.hdr.rx_data; ++ ++ if (false == SecSWSMS4Decryption(padapter, precvframe, &padapter->recvpriv)) ++ { ++ WAPI_TRACE(WAPI_ERR, "%s():SMS4 decrypt frame error\n",__FUNCTION__); ++ return _FAIL; ++ } ++ ++ WAPI_TRACE(WAPI_RX, "<=========%s\n", __FUNCTION__); ++ return res; ++} ++ ++#else ++ ++u32 rtw_sms4_encrypt(_adapter *padapter, u8 *pxmitframe) ++{ ++ WAPI_TRACE(WAPI_TX, "=========>Dummy %s\n", __FUNCTION__); ++ WAPI_TRACE(WAPI_TX, "<=========Dummy %s\n", __FUNCTION__); ++ return _SUCCESS; ++} ++ ++u32 rtw_sms4_decrypt(_adapter *padapter, u8 *precvframe) ++{ ++ WAPI_TRACE(WAPI_RX, "=========>Dummy %s\n", __FUNCTION__); ++ WAPI_TRACE(WAPI_RX, "<=========Dummy %s\n", __FUNCTION__); ++ return _SUCCESS; ++} ++ ++#endif ++ ++#endif +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_wlan_util.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_wlan_util.c +new file mode 100644 +index 00000000..8bac6dc5 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_wlan_util.c +@@ -0,0 +1,2663 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_WLAN_UTIL_C_ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_WOWLAN ++#include ++#endif ++ ++unsigned char ARTHEROS_OUI1[] = {0x00, 0x03, 0x7f}; ++unsigned char ARTHEROS_OUI2[] = {0x00, 0x13, 0x74}; ++ ++unsigned char BROADCOM_OUI1[] = {0x00, 0x10, 0x18}; ++unsigned char BROADCOM_OUI2[] = {0x00, 0x0a, 0xf7}; ++unsigned char BROADCOM_OUI3[] = {0x00, 0x05, 0xb5}; ++ ++unsigned char CISCO_OUI[] = {0x00, 0x40, 0x96}; ++unsigned char MARVELL_OUI[] = {0x00, 0x50, 0x43}; ++unsigned char RALINK_OUI[] = {0x00, 0x0c, 0x43}; ++unsigned char REALTEK_OUI[] = {0x00, 0xe0, 0x4c}; ++unsigned char AIRGOCAP_OUI[] = {0x00, 0x0a, 0xf5}; ++unsigned char EPIGRAM_OUI[] = {0x00, 0x90, 0x4c}; ++ ++unsigned char REALTEK_96B_IE[] = {0x00, 0xe0, 0x4c, 0x02, 0x01, 0x20}; ++ ++extern unsigned char MCS_rate_2R[16]; ++#ifdef CONFIG_DISABLE_MCS13TO15 ++extern unsigned char MCS_rate_2R_MCS13TO15_OFF[16]; ++#endif //CONFIG_DISABLE_MCS13TO15 ++extern unsigned char MCS_rate_1R[16]; ++extern unsigned char RTW_WPA_OUI[]; ++extern unsigned char WPA_TKIP_CIPHER[4]; ++extern unsigned char RSN_TKIP_CIPHER[4]; ++ ++#define R2T_PHY_DELAY (0) ++ ++//#define WAIT_FOR_BCN_TO_MIN (3000) ++#define WAIT_FOR_BCN_TO_MIN (6000) ++#define WAIT_FOR_BCN_TO_MAX (20000) ++ ++static u8 rtw_basic_rate_cck[4] = { ++ IEEE80211_CCK_RATE_1MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB|IEEE80211_BASIC_RATE_MASK, ++ IEEE80211_CCK_RATE_5MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB|IEEE80211_BASIC_RATE_MASK ++}; ++ ++static u8 rtw_basic_rate_ofdm[3] = { ++ IEEE80211_OFDM_RATE_6MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB|IEEE80211_BASIC_RATE_MASK, ++ IEEE80211_OFDM_RATE_24MB|IEEE80211_BASIC_RATE_MASK ++}; ++ ++static u8 rtw_basic_rate_mix[7] = { ++ IEEE80211_CCK_RATE_1MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB|IEEE80211_BASIC_RATE_MASK, ++ IEEE80211_CCK_RATE_5MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB|IEEE80211_BASIC_RATE_MASK, ++ IEEE80211_OFDM_RATE_6MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB|IEEE80211_BASIC_RATE_MASK, ++ IEEE80211_OFDM_RATE_24MB|IEEE80211_BASIC_RATE_MASK ++}; ++ ++ ++int cckrates_included(unsigned char *rate, int ratelen) ++{ ++ int i; ++ ++ for(i = 0; i < ratelen; i++) ++ { ++ if ( (((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || ++ (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22) ) ++ return _TRUE; ++ } ++ ++ return _FALSE; ++ ++} ++ ++int cckratesonly_included(unsigned char *rate, int ratelen) ++{ ++ int i; ++ ++ for(i = 0; i < ratelen; i++) ++ { ++ if ( (((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && ++ (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22) ) ++ return _FALSE; ++ } ++ ++ return _TRUE; ++} ++ ++unsigned char networktype_to_raid(unsigned char network_type) ++{ ++ unsigned char raid; ++ ++ switch(network_type) ++ { ++ case WIRELESS_11B: ++ raid = RATR_INX_WIRELESS_B; ++ break; ++ case WIRELESS_11A: ++ case WIRELESS_11G: ++ raid = RATR_INX_WIRELESS_G; ++ break; ++ case WIRELESS_11BG: ++ raid = RATR_INX_WIRELESS_GB; ++ break; ++ case WIRELESS_11_24N: ++ case WIRELESS_11_5N: ++ raid = RATR_INX_WIRELESS_N; ++ break; ++ case WIRELESS_11A_5N: ++ case WIRELESS_11G_24N: ++ raid = RATR_INX_WIRELESS_NG; ++ break; ++ case WIRELESS_11BG_24N: ++ raid = RATR_INX_WIRELESS_NGB; ++ break; ++ default: ++ raid = RATR_INX_WIRELESS_GB; ++ break; ++ ++ } ++ ++ return raid; ++ ++} ++ ++u8 judge_network_type(_adapter *padapter, unsigned char *rate, int ratelen) ++{ ++ u8 network_type = 0; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ ++ if(pmlmeext->cur_channel > 14) ++ { ++ if (pmlmeinfo->HT_enable) ++ { ++ network_type = WIRELESS_11_5N; ++ } ++ ++ network_type |= WIRELESS_11A; ++ } ++ else ++ { ++ if (pmlmeinfo->HT_enable) ++ { ++ network_type = WIRELESS_11_24N; ++ } ++ ++ if ((cckratesonly_included(rate, ratelen)) == _TRUE) ++ { ++ network_type |= WIRELESS_11B; ++ } ++ else if((cckrates_included(rate, ratelen)) == _TRUE) ++ { ++ network_type |= WIRELESS_11BG; ++ } ++ else ++ { ++ network_type |= WIRELESS_11G; ++ } ++ } ++ ++ return network_type; ++} ++ ++unsigned char ratetbl_val_2wifirate(unsigned char rate); ++unsigned char ratetbl_val_2wifirate(unsigned char rate) ++{ ++ unsigned char val = 0; ++ ++ switch (rate & 0x7f) ++ { ++ case 0: ++ val = IEEE80211_CCK_RATE_1MB; ++ break; ++ ++ case 1: ++ val = IEEE80211_CCK_RATE_2MB; ++ break; ++ ++ case 2: ++ val = IEEE80211_CCK_RATE_5MB; ++ break; ++ ++ case 3: ++ val = IEEE80211_CCK_RATE_11MB; ++ break; ++ ++ case 4: ++ val = IEEE80211_OFDM_RATE_6MB; ++ break; ++ ++ case 5: ++ val = IEEE80211_OFDM_RATE_9MB; ++ break; ++ ++ case 6: ++ val = IEEE80211_OFDM_RATE_12MB; ++ break; ++ ++ case 7: ++ val = IEEE80211_OFDM_RATE_18MB; ++ break; ++ ++ case 8: ++ val = IEEE80211_OFDM_RATE_24MB; ++ break; ++ ++ case 9: ++ val = IEEE80211_OFDM_RATE_36MB; ++ break; ++ ++ case 10: ++ val = IEEE80211_OFDM_RATE_48MB; ++ break; ++ ++ case 11: ++ val = IEEE80211_OFDM_RATE_54MB; ++ break; ++ ++ } ++ ++ return val; ++ ++} ++ ++int is_basicrate(_adapter *padapter, unsigned char rate); ++int is_basicrate(_adapter *padapter, unsigned char rate) ++{ ++ int i; ++ unsigned char val; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ for(i = 0; i < NumRates; i++) ++ { ++ val = pmlmeext->basicrate[i]; ++ ++ if ((val != 0xff) && (val != 0xfe)) ++ { ++ if (rate == ratetbl_val_2wifirate(val)) ++ { ++ return _TRUE; ++ } ++ } ++ } ++ ++ return _FALSE; ++} ++ ++unsigned int ratetbl2rateset(_adapter *padapter, unsigned char *rateset); ++unsigned int ratetbl2rateset(_adapter *padapter, unsigned char *rateset) ++{ ++ int i; ++ unsigned char rate; ++ unsigned int len = 0; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ for (i = 0; i < NumRates; i++) ++ { ++ rate = pmlmeext->datarate[i]; ++ ++ switch (rate) ++ { ++ case 0xff: ++ return len; ++ ++ case 0xfe: ++ continue; ++ ++ default: ++ rate = ratetbl_val_2wifirate(rate); ++ ++ if (is_basicrate(padapter, rate) == _TRUE) ++ { ++ rate |= IEEE80211_BASIC_RATE_MASK; ++ } ++ ++ rateset[len] = rate; ++ len++; ++ break; ++ } ++ } ++ return len; ++} ++ ++void get_rate_set(_adapter *padapter, unsigned char *pbssrate, int *bssrate_len) ++{ ++ unsigned char supportedrates[NumRates]; ++ ++ _rtw_memset(supportedrates, 0, NumRates); ++ *bssrate_len = ratetbl2rateset(padapter, supportedrates); ++ _rtw_memcpy(pbssrate, supportedrates, *bssrate_len); ++} ++ ++void UpdateBrateTbl( ++ IN PADAPTER Adapter, ++ IN u8 *mBratesOS ++) ++{ ++ u8 i; ++ u8 rate; ++ ++ // 1M, 2M, 5.5M, 11M, 6M, 12M, 24M are mandatory. ++ for(i=0;iiface_type == IFACE_PORT1) ++ { ++ Set_NETYPE1_MSR(padapter, type); ++ } ++ else ++#endif ++ { ++ Set_NETYPE0_MSR(padapter, type); ++ } ++} ++ ++inline u8 rtw_get_oper_ch(_adapter *adapter) ++{ ++ return adapter_to_dvobj(adapter)->oper_channel; ++} ++ ++inline void rtw_set_oper_ch(_adapter *adapter, u8 ch) ++{ ++ if (adapter_to_dvobj(adapter)->oper_channel != ch) ++ adapter_to_dvobj(adapter)->on_oper_ch_time = rtw_get_current_time(); ++ ++ adapter_to_dvobj(adapter)->oper_channel = ch; ++} ++ ++inline u8 rtw_get_oper_bw(_adapter *adapter) ++{ ++ return adapter_to_dvobj(adapter)->oper_bwmode; ++} ++ ++inline void rtw_set_oper_bw(_adapter *adapter, u8 bw) ++{ ++ adapter_to_dvobj(adapter)->oper_bwmode = bw; ++} ++ ++inline u8 rtw_get_oper_choffset(_adapter *adapter) ++{ ++ return adapter_to_dvobj(adapter)->oper_ch_offset; ++} ++ ++inline void rtw_set_oper_choffset(_adapter *adapter, u8 offset) ++{ ++ adapter_to_dvobj(adapter)->oper_ch_offset = offset; ++} ++ ++inline u32 rtw_get_on_oper_ch_time(_adapter *adapter) ++{ ++ return adapter_to_dvobj(adapter)->on_oper_ch_time; ++} ++ ++inline u32 rtw_get_on_cur_ch_time(_adapter *adapter) ++{ ++ if (adapter->mlmeextpriv.cur_channel == adapter_to_dvobj(adapter)->oper_channel) ++ return adapter_to_dvobj(adapter)->on_oper_ch_time; ++ else ++ return 0; ++} ++ ++void SelectChannel(_adapter *padapter, unsigned char channel) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ //saved channel info ++ rtw_set_oper_ch(padapter, channel); ++ dc_SelectChannel(padapter, channel); ++#else //CONFIG_DUALMAC_CONCURRENT ++ ++ _enter_critical_mutex(&(adapter_to_dvobj(padapter)->setch_mutex), NULL); ++ ++ //saved channel info ++ rtw_set_oper_ch(padapter, channel); ++ ++ rtw_hal_set_chan(padapter, channel); ++ ++ _exit_critical_mutex(&(adapter_to_dvobj(padapter)->setch_mutex), NULL); ++ ++#endif // CONFIG_DUALMAC_CONCURRENT ++} ++ ++void SetBWMode(_adapter *padapter, unsigned short bwmode, unsigned char channel_offset) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ //saved bw info ++ rtw_set_oper_bw(padapter, bwmode); ++ rtw_set_oper_choffset(padapter, channel_offset); ++ dc_SetBWMode(padapter, bwmode, channel_offset); ++#else //CONFIG_DUALMAC_CONCURRENT ++ ++ _enter_critical_mutex(&(adapter_to_dvobj(padapter)->setbw_mutex), NULL); ++ ++ //saved bw info ++ rtw_set_oper_bw(padapter, bwmode); ++ rtw_set_oper_choffset(padapter, channel_offset); ++ ++ rtw_hal_set_bwmode(padapter, (HT_CHANNEL_WIDTH)bwmode, channel_offset); ++ ++ _exit_critical_mutex(&(adapter_to_dvobj(padapter)->setbw_mutex), NULL); ++ ++#endif // CONFIG_DUALMAC_CONCURRENT ++} ++ ++void set_channel_bwmode(_adapter *padapter, unsigned char channel, unsigned char channel_offset, unsigned short bwmode) ++{ ++ u8 center_ch; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ if ( padapter->bNotifyChannelChange ) ++ { ++ DBG_871X( "[%s] ch = %d, offset = %d, bwmode = %d\n", __FUNCTION__, channel, channel_offset, bwmode ); ++ } ++ ++ if((bwmode == HT_CHANNEL_WIDTH_20)||(channel_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)) ++ { ++ //SelectChannel(padapter, channel); ++ center_ch = channel; ++ } ++ else ++ { ++ //switch to the proper channel ++ if (channel_offset == HAL_PRIME_CHNL_OFFSET_LOWER) ++ { ++ //SelectChannel(padapter, channel + 2); ++ center_ch = channel + 2; ++ } ++ else ++ { ++ //SelectChannel(padapter, channel - 2); ++ center_ch = channel - 2; ++ } ++ } ++ ++ //set Channel ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ //saved channel/bw info ++ rtw_set_oper_ch(padapter, channel); ++ rtw_set_oper_bw(padapter, bwmode); ++ rtw_set_oper_choffset(padapter, channel_offset); ++ dc_SelectChannel(padapter, center_ch);// set center channel ++#else //CONFIG_DUALMAC_CONCURRENT ++ ++ _enter_critical_mutex(&(adapter_to_dvobj(padapter)->setch_mutex), NULL); ++ ++ //saved channel/bw info ++ rtw_set_oper_ch(padapter, channel); ++ rtw_set_oper_bw(padapter, bwmode); ++ rtw_set_oper_choffset(padapter, channel_offset); ++ ++ rtw_hal_set_chan(padapter, center_ch); // set center channel ++ ++ _exit_critical_mutex(&(adapter_to_dvobj(padapter)->setch_mutex), NULL); ++ ++#endif // CONFIG_DUALMAC_CONCURRENT ++ ++ ++ SetBWMode(padapter, bwmode, channel_offset); ++ ++} ++ ++int get_bsstype(unsigned short capability) ++{ ++ if (capability & BIT(0)) ++ { ++ return WIFI_FW_AP_STATE; ++ } ++ else if (capability & BIT(1)) ++ { ++ return WIFI_FW_ADHOC_STATE; ++ } ++ else ++ { ++ return 0; ++ } ++} ++ ++__inline u8 *get_my_bssid(WLAN_BSSID_EX *pnetwork) ++{ ++ return (pnetwork->MacAddress); ++} ++ ++u16 get_beacon_interval(WLAN_BSSID_EX *bss) ++{ ++ unsigned short val; ++ _rtw_memcpy((unsigned char *)&val, rtw_get_beacon_interval_from_ie(bss->IEs), 2); ++ ++ return le16_to_cpu(val); ++ ++} ++ ++int is_client_associated_to_ap(_adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ ++ if(!padapter) ++ return _FAIL; ++ ++ pmlmeext = &padapter->mlmeextpriv; ++ pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)) ++ { ++ return _TRUE; ++ } ++ else ++ { ++ return _FAIL; ++ } ++} ++ ++int is_client_associated_to_ibss(_adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)) ++ { ++ return _TRUE; ++ } ++ else ++ { ++ return _FAIL; ++ } ++} ++ ++int is_IBSS_empty(_adapter *padapter) ++{ ++ unsigned int i; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) ++ { ++ if (pmlmeinfo->FW_sta_info[i].status == 1) ++ { ++ return _FAIL; ++ } ++ } ++ ++ return _TRUE; ++ ++} ++ ++unsigned int decide_wait_for_beacon_timeout(unsigned int bcn_interval) ++{ ++ if ((bcn_interval << 2) < WAIT_FOR_BCN_TO_MIN) ++ { ++ return WAIT_FOR_BCN_TO_MIN; ++ } ++ else if ((bcn_interval << 2) > WAIT_FOR_BCN_TO_MAX) ++ { ++ return WAIT_FOR_BCN_TO_MAX; ++ } ++ else ++ { ++ return ((bcn_interval << 2)); ++ } ++} ++ ++void CAM_empty_entry( ++ PADAPTER Adapter, ++ u8 ucIndex ++) ++{ ++ rtw_hal_set_hwreg(Adapter, HW_VAR_CAM_EMPTY_ENTRY, (u8 *)(&ucIndex)); ++} ++ ++void invalidate_cam_all(_adapter *padapter) ++{ ++ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_INVALID_ALL, 0); ++} ++#if 0 ++static u32 _ReadCAM(_adapter *padapter ,u32 addr) ++{ ++ u32 count = 0, cmd; ++ cmd = CAM_POLLINIG |addr ; ++ rtw_write32(padapter, RWCAM, cmd); ++ ++ do{ ++ if(0 == (rtw_read32(padapter,REG_CAMCMD) & CAM_POLLINIG)){ ++ break; ++ } ++ }while(count++ < 100); ++ ++ return rtw_read32(padapter,REG_CAMREAD); ++} ++#endif ++void read_cam(_adapter *padapter ,u8 entry) ++{ ++ u32 j,count = 0, addr; ++ u32 cam_val[2]; //cam_val[0] is read_val, cam_val[1] is the address ++ addr = entry << 3; ++ ++ DBG_8192C("********* DUMP CAM Entry_#%02d***************\n",entry); ++ for (j = 0; j < 6; j++) ++ { ++ //cmd = _ReadCAM(padapter ,addr+j); ++ //HW_VAR_CAM_READ ++ cam_val[1]=addr+j; ++ rtw_hal_get_hwreg(padapter, HW_VAR_CAM_READ, (u8 *)cam_val); ++ DBG_8192C("offset:0x%02x => 0x%08x \n",addr+j,cam_val[0]); ++ } ++ DBG_8192C("*********************************\n"); ++} ++ ++ ++void write_cam(_adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key) ++{ ++ unsigned int i, val, addr; ++ //unsigned int cmd; ++ int j; ++ u32 cam_val[2]; ++ ++ addr = entry << 3; ++ ++ for (j = 5; j >= 0; j--) ++ { ++ switch (j) ++ { ++ case 0: ++ val = (ctrl | (mac[0] << 16) | (mac[1] << 24) ); ++ break; ++ ++ case 1: ++ val = (mac[2] | ( mac[3] << 8) | (mac[4] << 16) | (mac[5] << 24)); ++ break; ++ ++ default: ++ i = (j - 2) << 2; ++ val = (key[i] | (key[i+1] << 8) | (key[i+2] << 16) | (key[i+3] << 24)); ++ break; ++ ++ } ++ ++ cam_val[0] = val; ++ cam_val[1] = addr + (unsigned int)j; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_WRITE, (u8 *)cam_val); ++ ++ //rtw_write32(padapter, WCAMI, val); ++ ++ //cmd = CAM_POLLINIG | CAM_WRITE | (addr + j); ++ //rtw_write32(padapter, RWCAM, cmd); ++ ++ //DBG_871X("%s=> cam write: %x, %x\n",__FUNCTION__, cmd, val); ++ ++ } ++ ++} ++ ++void clear_cam_entry(_adapter *padapter, u8 entry) ++{ ++#if 0 ++ u32 addr, val=0; ++ u32 cam_val[2]; ++ ++ addr = entry << 3; ++ ++ ++ cam_val[0] = val; ++ cam_val[1] = addr + (unsigned int)0; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_WRITE, (u8 *)cam_val); ++ ++ ++ ++ cam_val[0] = val; ++ cam_val[1] = addr + (unsigned int)1; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_WRITE, (u8 *)cam_val); ++#else ++ ++ unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++ ++ unsigned char null_key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00}; ++ ++ write_cam(padapter, entry, 0, null_sta, null_key); ++ ++#endif ++} ++ ++int allocate_fw_sta_entry(_adapter *padapter) ++{ ++ unsigned int mac_id; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ for (mac_id = IBSS_START_MAC_ID; mac_id < NUM_STA; mac_id++) ++ { ++ if (pmlmeinfo->FW_sta_info[mac_id].status == 0) ++ { ++ pmlmeinfo->FW_sta_info[mac_id].status = 1; ++ pmlmeinfo->FW_sta_info[mac_id].retry = 0; ++ break; ++ } ++ } ++ ++ return mac_id; ++} ++ ++void flush_all_cam_entry(_adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ //if(check_buddy_mlmeinfo_state(padapter, _HW_STATE_NOLINK_)) ++ if(check_buddy_fwstate(padapter, _FW_LINKED) == _FALSE) ++ { ++ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_INVALID_ALL, 0); ++ } ++ else ++ { ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE)) ++ { ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *psta; ++ u8 cam_id;//cam_entry ++ ++ psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress); ++ if(psta) { ++ if(psta->state & WIFI_AP_STATE) ++ {} //clear cam when ap free per sta_info ++ else { ++ if(psta->mac_id==2) ++ cam_id = 5; ++ else ++ cam_id = 4; ++ } ++ //clear_cam_entry(padapter, cam_id); ++ rtw_clearstakey_cmd(padapter, (u8*)psta, cam_id, _FALSE); ++ } ++ } ++ else if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ { ++ //clear cam when ap free per sta_info ++ } ++ } ++#else //CONFIG_CONCURRENT_MODE ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_INVALID_ALL, 0); ++ ++#endif //CONFIG_CONCURRENT_MODE ++ ++ _rtw_memset((u8 *)(pmlmeinfo->FW_sta_info), 0, sizeof(pmlmeinfo->FW_sta_info)); ++ ++} ++ ++#if defined(CONFIG_P2P) && defined(CONFIG_WFD) ++int WFD_info_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) ++{ ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wifidirect_info *pwdinfo; ++ u8 wfd_ie[ 128 ] = { 0x00 }; ++ u32 wfd_ielen = 0; ++ ++ ++ pwdinfo = &padapter->wdinfo; ++ if ( rtw_get_wfd_ie( ( u8* ) pIE, pIE->Length, wfd_ie, &wfd_ielen ) ) ++ { ++ u8 attr_content[ 10 ] = { 0x00 }; ++ u32 attr_contentlen = 0; ++ ++ DBG_871X( "[%s] Found WFD IE\n", __FUNCTION__ ); ++ rtw_get_wfd_attr_content( wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); ++ if ( attr_contentlen ) ++ { ++ pwdinfo->wfd_info->peer_rtsp_ctrlport = RTW_GET_BE16( attr_content + 2 ); ++ DBG_8192C( "[%s] Peer PORT NUM = %d\n", __FUNCTION__, pwdinfo->wfd_info->peer_rtsp_ctrlport ); ++ return( _TRUE ); ++ } ++ } ++ else ++ { ++ DBG_871X( "[%s] NO WFD IE\n", __FUNCTION__ ); ++ ++ } ++ return( _FAIL ); ++} ++#endif ++ ++int WMM_param_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) ++{ ++ //struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if(pmlmepriv->qospriv.qos_option==0) ++ { ++ pmlmeinfo->WMM_enable = 0; ++ return _FAIL; ++ } ++ ++ pmlmeinfo->WMM_enable = 1; ++ _rtw_memcpy(&(pmlmeinfo->WMM_param), (pIE->data + 6), sizeof(struct WMM_para_element)); ++ return _TRUE; ++ ++ /*if (pregpriv->wifi_spec == 1) ++ { ++ if (pmlmeinfo->WMM_enable == 1) ++ { ++ //todo: compare the parameter set count & decide wheher to update or not ++ return _FAIL; ++ } ++ else ++ { ++ pmlmeinfo->WMM_enable = 1; ++ _rtw_rtw_memcpy(&(pmlmeinfo->WMM_param), (pIE->data + 6), sizeof(struct WMM_para_element)); ++ return _TRUE; ++ } ++ } ++ else ++ { ++ pmlmeinfo->WMM_enable = 0; ++ return _FAIL; ++ }*/ ++ ++} ++ ++void WMMOnAssocRsp(_adapter *padapter) ++{ ++ u8 ACI, ACM, AIFS, ECWMin, ECWMax, aSifsTime; ++ u8 acm_mask; ++ u16 TXOP; ++ u32 acParm, i; ++ u32 edca[4], inx[4]; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ if (pmlmeinfo->WMM_enable == 0) ++ { ++ padapter->mlmepriv.acm_mask = 0; ++ return; ++ } ++ ++ acm_mask = 0; ++ ++ if( pmlmeext->cur_wireless_mode == WIRELESS_11B) ++ aSifsTime = 10; ++ else ++ aSifsTime = 16; ++ ++ for (i = 0; i < 4; i++) ++ { ++ ACI = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 5) & 0x03; ++ ACM = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 4) & 0x01; ++ ++ //AIFS = AIFSN * slot time + SIFS - r2t phy delay ++ AIFS = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN & 0x0f) * pmlmeinfo->slotTime + aSifsTime; ++ ++ ECWMin = (pmlmeinfo->WMM_param.ac_param[i].CW & 0x0f); ++ ECWMax = (pmlmeinfo->WMM_param.ac_param[i].CW & 0xf0) >> 4; ++ TXOP = le16_to_cpu(pmlmeinfo->WMM_param.ac_param[i].TXOP_limit); ++ ++ acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); ++ ++ switch (ACI) ++ { ++ case 0x0: ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm)); ++ acm_mask |= (ACM? BIT(1):0); ++ edca[XMIT_BE_QUEUE] = acParm; ++ break; ++ ++ case 0x1: ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm)); ++ //acm_mask |= (ACM? BIT(0):0); ++ edca[XMIT_BK_QUEUE] = acParm; ++ break; ++ ++ case 0x2: ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm)); ++ acm_mask |= (ACM? BIT(2):0); ++ edca[XMIT_VI_QUEUE] = acParm; ++ break; ++ ++ case 0x3: ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm)); ++ acm_mask |= (ACM? BIT(3):0); ++ edca[XMIT_VO_QUEUE] = acParm; ++ break; ++ } ++ ++ DBG_871X("WMM(%x): %x, %x\n", ACI, ACM, acParm); ++ } ++ ++ if(padapter->registrypriv.acm_method == 1) ++ rtw_hal_set_hwreg(padapter, HW_VAR_ACM_CTRL, (u8 *)(&acm_mask)); ++ else ++ padapter->mlmepriv.acm_mask = acm_mask; ++ ++ inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3; ++ ++ if(pregpriv->wifi_spec==1) ++ { ++ u32 j, tmp, change_inx; ++ ++ //entry indx: 0->vo, 1->vi, 2->be, 3->bk. ++ for(i=0; i<4; i++) ++ { ++ for(j=i+1; j<4; j++) ++ { ++ //compare CW and AIFS ++ if((edca[j] & 0xFFFF) < (edca[i] & 0xFFFF)) ++ { ++ change_inx = _TRUE; ++ } ++ else if((edca[j] & 0xFFFF) == (edca[i] & 0xFFFF)) ++ { ++ //compare TXOP ++ if((edca[j] >> 16) > (edca[i] >> 16)) ++ change_inx = _TRUE; ++ } ++ ++ if(change_inx) ++ { ++ tmp = edca[i]; ++ edca[i] = edca[j]; ++ edca[j] = tmp; ++ ++ tmp = inx[i]; ++ inx[i] = inx[j]; ++ inx[j] = tmp; ++ ++ change_inx = _FALSE; ++ } ++ } ++ } ++ } ++ ++ for(i=0; i<4; i++) { ++ pxmitpriv->wmm_para_seq[i] = inx[i]; ++ DBG_871X("wmm_para_seq(%d): %d\n", i, pxmitpriv->wmm_para_seq[i]); ++ } ++ ++ return; ++} ++ ++static void bwmode_update_check(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) ++{ ++#ifdef CONFIG_80211N_HT ++ unsigned char new_bwmode; ++ unsigned char new_ch_offset; ++ struct HT_info_element *pHT_info; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ ++ if(!pIE) ++ return; ++ ++ if(phtpriv->ht_option == _FALSE) return; ++ ++ if(pIE->Length > sizeof(struct HT_info_element)) ++ return; ++ ++ pHT_info = (struct HT_info_element *)pIE->data; ++ ++ if((pHT_info->infos[0] & BIT(2)) && pregistrypriv->cbw40_enable ) ++ { ++ new_bwmode = HT_CHANNEL_WIDTH_40; ++ ++ switch (pHT_info->infos[0] & 0x3) ++ { ++ case 1: ++ new_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ break; ++ ++ case 3: ++ new_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ break; ++ ++ default: ++ new_bwmode = HT_CHANNEL_WIDTH_20; ++ new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ break; ++ } ++ } ++ else ++ { ++ new_bwmode = HT_CHANNEL_WIDTH_20; ++ new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ } ++ ++ ++ if((new_bwmode!= pmlmeext->cur_bwmode) || (new_ch_offset!=pmlmeext->cur_ch_offset)) ++ { ++ pmlmeinfo->bwmode_updated = _TRUE; ++ ++ pmlmeext->cur_bwmode = new_bwmode; ++ pmlmeext->cur_ch_offset = new_ch_offset; ++ ++ //update HT info also ++ HT_info_handler(padapter, pIE); ++ } ++ else ++ { ++ pmlmeinfo->bwmode_updated = _FALSE; ++ } ++ ++ ++ if(_TRUE == pmlmeinfo->bwmode_updated) ++ { ++ struct sta_info *psta; ++ WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ //set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ ++ ++ //update ap's stainfo ++ psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress); ++ if(psta) ++ { ++ struct ht_priv *phtpriv_sta = &psta->htpriv; ++ ++ if(phtpriv_sta->ht_option) ++ { ++ // bwmode ++ phtpriv_sta->bwmode = pmlmeext->cur_bwmode; ++ phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset; ++ } ++ else ++ { ++ phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_20; ++ phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ } ++ ++ } ++ ++ //pmlmeinfo->bwmode_updated = _FALSE;//bwmode_updated done, reset it! ++ ++ } ++#endif //CONFIG_80211N_HT ++} ++ ++void HT_caps_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) ++{ ++#ifdef CONFIG_80211N_HT ++ unsigned int i; ++ u8 rf_type; ++ u8 max_AMPDU_len, min_MPDU_spacing; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ ++ if(pIE==NULL) return; ++ ++ if(phtpriv->ht_option == _FALSE) return; ++ ++ pmlmeinfo->HT_caps_enable = 1; ++ ++ for (i = 0; i < (pIE->Length); i++) ++ { ++ if (i != 2) ++ { ++ // Commented by Albert 2010/07/12 ++ // Got the endian issue here. ++ pmlmeinfo->HT_caps.u.HT_cap[i] &= (pIE->data[i]); ++ } ++ else ++ { ++ //modify from fw by Thomas 2010/11/17 ++ if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3) > (pIE->data[i] & 0x3)) ++ { ++ max_AMPDU_len = (pIE->data[i] & 0x3); ++ } ++ else ++ { ++ max_AMPDU_len = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3); ++ } ++ ++ if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) > (pIE->data[i] & 0x1c)) ++ { ++ min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c); ++ } ++ else ++ { ++ min_MPDU_spacing = (pIE->data[i] & 0x1c); ++ } ++ ++ pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para = max_AMPDU_len | min_MPDU_spacing; ++ } ++ } ++ ++ // Commented by Albert 2010/07/12 ++ // Have to handle the endian issue after copying. ++ // HT_ext_caps didn't be used yet. ++ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info = le16_to_cpu( pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info ); ++ pmlmeinfo->HT_caps.u.HT_cap_element.HT_ext_caps = le16_to_cpu( pmlmeinfo->HT_caps.u.HT_cap_element.HT_ext_caps ); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ ++ //update the MCS rates ++ for (i = 0; i < 16; i++) ++ { ++ if((rf_type == RF_1T1R) || (rf_type == RF_1T2R)) ++ { ++ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i]; ++ } ++ else ++ { ++ #ifdef CONFIG_DISABLE_MCS13TO15 ++ if(pmlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40 && (pregistrypriv->wifi_spec!=1)) ++ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R_MCS13TO15_OFF[i]; ++ else ++ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R[i]; ++ #else ++ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R[i]; ++ #endif //CONFIG_DISABLE_MCS13TO15 ++ } ++ #ifdef RTL8192C_RECONFIG_TO_1T1R ++ { ++ pmlmeinfo->HT_caps.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i]; ++ } ++ #endif ++ } ++#endif //CONFIG_80211N_HT ++ return; ++} ++ ++void HT_info_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) ++{ ++#ifdef CONFIG_80211N_HT ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ ++ if(pIE==NULL) return; ++ ++ if(phtpriv->ht_option == _FALSE) return; ++ ++ ++ if(pIE->Length > sizeof(struct HT_info_element)) ++ return; ++ ++ pmlmeinfo->HT_info_enable = 1; ++ _rtw_memcpy(&(pmlmeinfo->HT_info), pIE->data, pIE->Length); ++#endif //CONFIG_80211N_HT ++ return; ++} ++ ++void HTOnAssocRsp(_adapter *padapter) ++{ ++ unsigned char max_AMPDU_len; ++ unsigned char min_MPDU_spacing; ++ //struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) ++ { ++ pmlmeinfo->HT_enable = 1; ++ } ++ else ++ { ++ pmlmeinfo->HT_enable = 0; ++ //set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ return; ++ } ++ ++ //handle A-MPDU parameter field ++ /* ++ AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k ++ AMPDU_para [4:2]:Min MPDU Start Spacing ++ */ ++ max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; ++ ++ min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); ++ ++#if 0 //move to rtw_update_ht_cap() ++ if ((pregpriv->cbw40_enable) && ++ (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & BIT(1)) && ++ (pmlmeinfo->HT_info.infos[0] & BIT(2))) ++ { ++ //switch to the 40M Hz mode accoring to the AP ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; ++ switch ((pmlmeinfo->HT_info.infos[0] & 0x3)) ++ { ++ case HT_EXTCHNL_OFFSET_UPPER: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ break; ++ ++ case HT_EXTCHNL_OFFSET_LOWER: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ break; ++ ++ default: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ break; ++ } ++ ++ //SelectChannel(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset); ++ } ++#endif ++ ++ //set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ ++#if 0 //move to rtw_update_ht_cap() ++ // ++ // Config SM Power Save setting ++ // ++ pmlmeinfo->SM_PS = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2; ++ if(pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) ++ { ++ /*u8 i; ++ //update the MCS rates ++ for (i = 0; i < 16; i++) ++ { ++ pmlmeinfo->HT_caps.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i]; ++ }*/ ++ DBG_871X("%s(): WLAN_HT_CAP_SM_PS_STATIC\n",__FUNCTION__); ++ } ++ ++ // ++ // Config current HT Protection mode. ++ // ++ pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3; ++#endif ++ ++} ++ ++void ERP_IE_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if(pIE->Length>1) ++ return; ++ ++ pmlmeinfo->ERP_enable = 1; ++ _rtw_memcpy(&(pmlmeinfo->ERP_IE), pIE->data, pIE->Length); ++} ++ ++void VCS_update(_adapter *padapter, struct sta_info *psta) ++{ ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ switch (pregpriv->vrtl_carrier_sense)/* 0:off 1:on 2:auto */ ++ { ++ case 0: //off ++ psta->rtsen = 0; ++ psta->cts2self = 0; ++ break; ++ ++ case 1: //on ++ if (pregpriv->vcs_type == 1) /* 1:RTS/CTS 2:CTS to self */ ++ { ++ psta->rtsen = 1; ++ psta->cts2self = 0; ++ } ++ else ++ { ++ psta->rtsen = 0; ++ psta->cts2self = 1; ++ } ++ break; ++ ++ case 2: //auto ++ default: ++ if ((pmlmeinfo->ERP_enable) && (pmlmeinfo->ERP_IE & BIT(1))) ++ { ++ if (pregpriv->vcs_type == 1) ++ { ++ psta->rtsen = 1; ++ psta->cts2self = 0; ++ } ++ else ++ { ++ psta->rtsen = 0; ++ psta->cts2self = 1; ++ } ++ } ++ else ++ { ++ psta->rtsen = 0; ++ psta->cts2self = 0; ++ } ++ break; ++ } ++} ++ ++#ifdef CONFIG_TDLS ++int check_ap_tdls_prohibited(u8 *pframe, u8 pkt_len) ++{ ++ u8 tdls_prohibited_bit = 0x40; //bit(38); TDLS_prohibited ++ ++ if(pkt_len < 5) ++ { ++ return _FALSE; ++ } ++ ++ pframe += 4; ++ if( (*pframe) & tdls_prohibited_bit ) ++ return _TRUE; ++ ++ return _FALSE; ++} ++#endif //CONFIG_TDLS ++ ++int rtw_check_bcn_info(ADAPTER *Adapter, u8 *pframe, u32 packet_len) ++{ ++ unsigned int len; ++ unsigned char *p; ++ unsigned short val16, subtype; ++ struct wlan_network *cur_network = &(Adapter->mlmepriv.cur_network); ++ //u8 wpa_ie[255],rsn_ie[255]; ++ u16 wpa_len=0,rsn_len=0; ++ u8 encryp_protocol = 0; ++ WLAN_BSSID_EX *bssid; ++ int group_cipher = 0, pairwise_cipher = 0, is_8021x = 0; ++ unsigned char *pbuf; ++ u32 wpa_ielen = 0; ++ u8 *pbssid = GetAddr3Ptr(pframe); ++ u32 hidden_ssid = 0; ++ u8 cur_network_type, network_type=0; ++ struct HT_info_element *pht_info = NULL; ++ struct rtw_ieee80211_ht_cap *pht_cap = NULL; ++ u32 bcn_channel; ++ unsigned short ht_cap_info; ++ unsigned char ht_info_infos_0; ++ ++ if (is_client_associated_to_ap(Adapter) == _FALSE) ++ return _TRUE; ++ ++ len = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ if (len > MAX_IE_SZ) { ++ DBG_871X("%s IE too long for survey event\n", __func__); ++ return _FAIL; ++ } ++ ++ if (_rtw_memcmp(cur_network->network.MacAddress, pbssid, 6) == _FALSE) { ++ DBG_871X("Oops: rtw_check_network_encrypt linked but recv other bssid bcn\n" MAC_FMT MAC_FMT, ++ MAC_ARG(pbssid), MAC_ARG(cur_network->network.MacAddress)); ++ return _TRUE; ++ } ++ ++ bssid = (WLAN_BSSID_EX *)rtw_zmalloc(sizeof(WLAN_BSSID_EX)); ++ ++ subtype = GetFrameSubType(pframe) >> 4; ++ ++ if(subtype==WIFI_BEACON) ++ bssid->Reserved[0] = 1; ++ ++ bssid->Length = sizeof(WLAN_BSSID_EX) - MAX_IE_SZ + len; ++ ++ /* below is to copy the information element */ ++ bssid->IELength = len; ++ _rtw_memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength); ++ ++ /* check bw and channel offset */ ++ /* parsing HT_CAP_IE */ ++ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); ++ if(p && len>0) { ++ pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2); ++ ht_cap_info = pht_cap->cap_info; ++ } else { ++ ht_cap_info = 0; ++ } ++ /* parsing HT_INFO_IE */ ++ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); ++ if(p && len>0) { ++ pht_info = (struct HT_info_element *)(p + 2); ++ ht_info_infos_0 = pht_info->infos[0]; ++ } else { ++ ht_info_infos_0 = 0; ++ } ++ if (ht_cap_info != cur_network->BcnInfo.ht_cap_info || ++ ((ht_info_infos_0&0x03) != (cur_network->BcnInfo.ht_info_infos_0&0x03))) { ++ DBG_871X("%s bcn now: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, ++ ht_cap_info, ht_info_infos_0); ++ DBG_871X("%s bcn link: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, ++ cur_network->BcnInfo.ht_cap_info, cur_network->BcnInfo.ht_info_infos_0); ++ DBG_871X("%s bw mode change, disconnect\n", __func__); ++ { ++ //bcn_info_update ++ cur_network->BcnInfo.ht_cap_info = ht_cap_info; ++ cur_network->BcnInfo.ht_info_infos_0 = ht_info_infos_0; ++ //to do : need to check that whether modify related register of BB or not ++ } ++ //goto _mismatch; ++ } ++ ++ /* Checking for channel */ ++ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _DSSET_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); ++ if (p) { ++ bcn_channel = *(p + 2); ++ } else {/* In 5G, some ap do not have DSSET IE checking HT info for channel */ ++ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); ++ if(pht_info) { ++ bcn_channel = pht_info->primary_channel; ++ } else { /* we don't find channel IE, so don't check it */ ++ DBG_871X("Oops: %s we don't find channel IE, so don't check it \n", __func__); ++ bcn_channel = Adapter->mlmeextpriv.cur_channel; ++ } ++ } ++ if (bcn_channel != Adapter->mlmeextpriv.cur_channel) { ++ DBG_871X("%s beacon channel:%d cur channel:%d disconnect\n", __func__, ++ bcn_channel, Adapter->mlmeextpriv.cur_channel); ++ goto _mismatch; ++ } ++ ++ /* checking SSID */ ++ if ((p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _SSID_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_)) == NULL) { ++ DBG_871X("%s marc: cannot find SSID for survey event\n", __func__); ++ hidden_ssid = _TRUE; ++ } else { ++ hidden_ssid = _FALSE; ++ } ++ ++ if((NULL != p) && (_FALSE == hidden_ssid && (*(p + 1)))) { ++ _rtw_memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1)); ++ bssid->Ssid.SsidLength = *(p + 1); ++ } else { ++ bssid->Ssid.SsidLength = 0; ++ bssid->Ssid.Ssid[0] = '\0'; ++ } ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("%s bssid.Ssid.Ssid:%s bssid.Ssid.SsidLength:%d " ++ "cur_network->network.Ssid.Ssid:%s len:%d\n", __func__, bssid->Ssid.Ssid, ++ bssid->Ssid.SsidLength, cur_network->network.Ssid.Ssid, ++ cur_network->network.Ssid.SsidLength)); ++ ++ if (_rtw_memcmp(bssid->Ssid.Ssid, cur_network->network.Ssid.Ssid, 32) == _FALSE || ++ bssid->Ssid.SsidLength != cur_network->network.Ssid.SsidLength) { ++ if (bssid->Ssid.Ssid[0] != '\0' && bssid->Ssid.SsidLength != 0) { /* not hidden ssid */ ++ DBG_871X("%s(), SSID is not match return FAIL\n", __func__); ++ goto _mismatch; ++ } ++ } ++ ++ /* check encryption info */ ++ val16 = rtw_get_capability((WLAN_BSSID_EX *)bssid); ++ ++ if (val16 & BIT(4)) ++ bssid->Privacy = 1; ++ else ++ bssid->Privacy = 0; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_, ++ ("%s(): cur_network->network.Privacy is %d, bssid.Privacy is %d\n", ++ __func__, cur_network->network.Privacy,bssid->Privacy)); ++ if (cur_network->network.Privacy != bssid->Privacy) { ++ DBG_871X("%s(), privacy is not match return FAIL\n",__func__); ++ goto _mismatch; ++ } ++ ++ rtw_get_sec_ie(bssid->IEs, bssid->IELength, NULL,&rsn_len,NULL,&wpa_len); ++ ++ if (rsn_len > 0) { ++ encryp_protocol = ENCRYP_PROTOCOL_WPA2; ++ } else if (wpa_len > 0) { ++ encryp_protocol = ENCRYP_PROTOCOL_WPA; ++ } else { ++ if (bssid->Privacy) ++ encryp_protocol = ENCRYP_PROTOCOL_WEP; ++ } ++ ++ if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) { ++ DBG_871X("%s(): enctyp is not match ,return FAIL\n",__func__); ++ goto _mismatch; ++ } ++ ++ if (encryp_protocol == ENCRYP_PROTOCOL_WPA || encryp_protocol == ENCRYP_PROTOCOL_WPA2) { ++ pbuf = rtw_get_wpa_ie(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12); ++ if(pbuf && (wpa_ielen>0)) { ++ if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_, ++ ("%s pnetwork->pairwise_cipher: %d, group_cipher is %d, is_8021x is %d\n", __func__, ++ pairwise_cipher, group_cipher, is_8021x)); ++ } ++ } else { ++ pbuf = rtw_get_wpa2_ie(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12); ++ ++ if(pbuf && (wpa_ielen>0)) { ++ if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) { ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_, ++ ("%s pnetwork->pairwise_cipher: %d, pnetwork->group_cipher is %d, is_802x is %d\n", ++ __func__, pairwise_cipher, group_cipher, is_8021x)); ++ } ++ } ++ } ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_, ++ ("%s cur_network->group_cipher is %d: %d\n",__func__, cur_network->BcnInfo.group_cipher, group_cipher)); ++ if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || group_cipher != cur_network->BcnInfo.group_cipher) { ++ DBG_871X("%s pairwise_cipher(%x:%x) or group_cipher(%x:%x) is not match ,return FAIL\n",__func__, ++ pairwise_cipher, cur_network->BcnInfo.pairwise_cipher, ++ group_cipher, cur_network->BcnInfo.group_cipher); ++ goto _mismatch; ++ } ++ ++ if (is_8021x != cur_network->BcnInfo.is_8021x) { ++ DBG_871X("%s authentication is not match ,return FAIL\n", __func__); ++ goto _mismatch; ++ } ++ } ++ ++ rtw_mfree((u8 *)bssid, sizeof(WLAN_BSSID_EX)); ++ return _SUCCESS; ++ ++_mismatch: ++ rtw_mfree((u8 *)bssid, sizeof(WLAN_BSSID_EX)); ++ return _FAIL; ++ ++ _func_exit_; ++} ++ ++void update_beacon_info(_adapter *padapter, u8 *pframe, uint pkt_len, struct sta_info *psta) ++{ ++ unsigned int i; ++ unsigned int len; ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ ++#ifdef CONFIG_TDLS ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ u8 tdls_prohibited[] = { 0x00, 0x00, 0x00, 0x00, 0x10 }; //bit(38): TDLS_prohibited ++#endif //CONFIG_TDLS ++ ++ len = pkt_len - (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN); ++ ++ for (i = 0; i < len;) ++ { ++ pIE = (PNDIS_802_11_VARIABLE_IEs)(pframe + (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN) + i); ++ ++ switch (pIE->ElementID) ++ { ++#if 0 ++ case _VENDOR_SPECIFIC_IE_: ++ //todo: to update WMM paramter set while receiving beacon ++ if (_rtw_memcmp(pIE->data, WMM_PARA_OUI, 6)) //WMM ++ { ++ (WMM_param_handler(padapter, pIE))? WMMOnAssocRsp(padapter): 0; ++ } ++ break; ++#endif ++ ++ case _HT_EXTRA_INFO_IE_: //HT info ++ //HT_info_handler(padapter, pIE); ++ bwmode_update_check(padapter, pIE); ++ break; ++ ++ case _ERPINFO_IE_: ++ ERP_IE_handler(padapter, pIE); ++ VCS_update(padapter, psta); ++ break; ++ ++#ifdef CONFIG_TDLS ++ case _EXT_CAP_IE_: ++ if( check_ap_tdls_prohibited(pIE->data, pIE->Length) == _TRUE ) ++ ptdlsinfo->ap_prohibited = _TRUE; ++ break; ++#endif //CONFIG_TDLS ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++} ++ ++#ifdef CONFIG_DFS ++void process_csa_ie(_adapter *padapter, u8 *pframe, uint pkt_len) ++{ ++ unsigned int i; ++ unsigned int len; ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ u8 new_ch_no = 0; ++ ++ len = pkt_len - (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN); ++ ++ for (i = 0; i < len;) ++ { ++ pIE = (PNDIS_802_11_VARIABLE_IEs)(pframe + (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN) + i); ++ ++ switch (pIE->ElementID) ++ { ++ case _CH_SWTICH_ANNOUNCE_: ++ _rtw_memcpy(&new_ch_no, pIE->data+1, 1); ++ rtw_set_csa_cmd(padapter, new_ch_no); ++ break; ++ ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++} ++#endif //CONFIG_DFS ++ ++unsigned int is_ap_in_tkip(_adapter *padapter) ++{ ++ u32 i; ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); ++ ++ if (rtw_get_capability((WLAN_BSSID_EX *)cur_network) & WLAN_CAPABILITY_PRIVACY) ++ { ++ for (i = sizeof(NDIS_802_11_FIXED_IEs); i < pmlmeinfo->network.IELength;) ++ { ++ pIE = (PNDIS_802_11_VARIABLE_IEs)(pmlmeinfo->network.IEs + i); ++ ++ switch (pIE->ElementID) ++ { ++ case _VENDOR_SPECIFIC_IE_: ++ if ((_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4)) && (_rtw_memcmp((pIE->data + 12), WPA_TKIP_CIPHER, 4))) ++ { ++ return _TRUE; ++ } ++ break; ++ ++ case _RSN_IE_2_: ++ if (_rtw_memcmp((pIE->data + 8), RSN_TKIP_CIPHER, 4)) ++ { ++ return _TRUE; ++ } ++ ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ ++ return _FALSE; ++ } ++ else ++ { ++ return _FALSE; ++ } ++ ++} ++ ++unsigned int should_forbid_n_rate(_adapter * padapter) ++{ ++ u32 i; ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ WLAN_BSSID_EX *cur_network = &pmlmepriv->cur_network.network; ++ ++ if (rtw_get_capability((WLAN_BSSID_EX *)cur_network) & WLAN_CAPABILITY_PRIVACY) ++ { ++ for (i = sizeof(NDIS_802_11_FIXED_IEs); i < cur_network->IELength;) ++ { ++ pIE = (PNDIS_802_11_VARIABLE_IEs)(cur_network->IEs + i); ++ ++ switch (pIE->ElementID) ++ { ++ case _VENDOR_SPECIFIC_IE_: ++ if (_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4) && ++ ((_rtw_memcmp((pIE->data + 12), WPA_CIPHER_SUITE_CCMP, 4)) || ++ (_rtw_memcmp((pIE->data + 16), WPA_CIPHER_SUITE_CCMP, 4)))) ++ return _FALSE; ++ break; ++ ++ case _RSN_IE_2_: ++ if ((_rtw_memcmp((pIE->data + 8), RSN_CIPHER_SUITE_CCMP, 4)) || ++ (_rtw_memcmp((pIE->data + 12), RSN_CIPHER_SUITE_CCMP, 4))) ++ return _FALSE; ++ ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ ++ return _TRUE; ++ } ++ else ++ { ++ return _FALSE; ++ } ++ ++} ++ ++ ++unsigned int is_ap_in_wep(_adapter *padapter) ++{ ++ u32 i; ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); ++ ++ if (rtw_get_capability((WLAN_BSSID_EX *)cur_network) & WLAN_CAPABILITY_PRIVACY) ++ { ++ for (i = sizeof(NDIS_802_11_FIXED_IEs); i < pmlmeinfo->network.IELength;) ++ { ++ pIE = (PNDIS_802_11_VARIABLE_IEs)(pmlmeinfo->network.IEs + i); ++ ++ switch (pIE->ElementID) ++ { ++ case _VENDOR_SPECIFIC_IE_: ++ if (_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4)) ++ return _FALSE; ++ break; ++ ++ case _RSN_IE_2_: ++ return _FALSE; ++ ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ ++ return _TRUE; ++ } ++ else ++ { ++ return _FALSE; ++ } ++ ++} ++ ++int wifirate2_ratetbl_inx(unsigned char rate); ++int wifirate2_ratetbl_inx(unsigned char rate) ++{ ++ int inx = 0; ++ rate = rate & 0x7f; ++ ++ switch (rate) ++ { ++ case 54*2: ++ inx = 11; ++ break; ++ ++ case 48*2: ++ inx = 10; ++ break; ++ ++ case 36*2: ++ inx = 9; ++ break; ++ ++ case 24*2: ++ inx = 8; ++ break; ++ ++ case 18*2: ++ inx = 7; ++ break; ++ ++ case 12*2: ++ inx = 6; ++ break; ++ ++ case 9*2: ++ inx = 5; ++ break; ++ ++ case 6*2: ++ inx = 4; ++ break; ++ ++ case 11*2: ++ inx = 3; ++ break; ++ case 11: ++ inx = 2; ++ break; ++ ++ case 2*2: ++ inx = 1; ++ break; ++ ++ case 1*2: ++ inx = 0; ++ break; ++ ++ } ++ return inx; ++} ++ ++unsigned int update_basic_rate(unsigned char *ptn, unsigned int ptn_sz) ++{ ++ unsigned int i, num_of_rate; ++ unsigned int mask = 0; ++ ++ num_of_rate = (ptn_sz > NumRates)? NumRates: ptn_sz; ++ ++ for (i = 0; i < num_of_rate; i++) ++ { ++ if ((*(ptn + i)) & 0x80) ++ { ++ mask |= 0x1 << wifirate2_ratetbl_inx(*(ptn + i)); ++ } ++ } ++ return mask; ++} ++ ++unsigned int update_supported_rate(unsigned char *ptn, unsigned int ptn_sz) ++{ ++ unsigned int i, num_of_rate; ++ unsigned int mask = 0; ++ ++ num_of_rate = (ptn_sz > NumRates)? NumRates: ptn_sz; ++ ++ for (i = 0; i < num_of_rate; i++) ++ { ++ mask |= 0x1 << wifirate2_ratetbl_inx(*(ptn + i)); ++ } ++ ++ return mask; ++} ++ ++unsigned int update_MSC_rate(struct HT_caps_element *pHT_caps) ++{ ++ unsigned int mask = 0; ++ ++ mask = ((pHT_caps->u.HT_cap_element.MCS_rate[0] << 12) | (pHT_caps->u.HT_cap_element.MCS_rate[1] << 20)); ++ ++ return mask; ++} ++ ++int support_short_GI(_adapter *padapter, struct HT_caps_element *pHT_caps) ++{ ++ unsigned char bit_offset; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if (!(pmlmeinfo->HT_enable)) ++ return _FAIL; ++ ++ if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_RALINK)) ++ return _FAIL; ++ ++ bit_offset = (pmlmeext->cur_bwmode & HT_CHANNEL_WIDTH_40)? 6: 5; ++ ++ if (pHT_caps->u.HT_cap_element.HT_caps_info & (0x1 << bit_offset)) ++ { ++ return _SUCCESS; ++ } ++ else ++ { ++ return _FAIL; ++ } ++} ++ ++unsigned char get_highest_rate_idx(u32 mask) ++{ ++ int i; ++ unsigned char rate_idx=0; ++ ++ for(i=27; i>=0; i--) ++ { ++ if(mask & BIT(i)) ++ { ++ rate_idx = i; ++ break; ++ } ++ } ++ ++ return rate_idx; ++} ++ ++unsigned char get_highest_mcs_rate(struct HT_caps_element *pHT_caps); ++unsigned char get_highest_mcs_rate(struct HT_caps_element *pHT_caps) ++{ ++ int i, mcs_rate; ++ ++ mcs_rate = (pHT_caps->u.HT_cap_element.MCS_rate[0] | (pHT_caps->u.HT_cap_element.MCS_rate[1] << 8)); ++ ++ for (i = 15; i >= 0; i--) ++ { ++ if (mcs_rate & (0x1 << i)) ++ { ++ break; ++ } ++ } ++ ++ return i; ++} ++ ++void Update_RA_Entry(_adapter *padapter, struct sta_info *psta) ++{ ++ rtw_hal_update_ra_mask(psta, 0); ++} ++ ++void enable_rate_adaptive(_adapter *padapter, struct sta_info *psta); ++void enable_rate_adaptive(_adapter *padapter, struct sta_info *psta) ++{ ++ Update_RA_Entry(padapter, psta); ++} ++ ++void set_sta_rate(_adapter *padapter, struct sta_info *psta) ++{ ++ //rate adaptive ++ enable_rate_adaptive(padapter, psta); ++} ++ ++// Update RRSR and Rate for USERATE ++void update_tx_basic_rate(_adapter *padapter, u8 wirelessmode) ++{ ++ NDIS_802_11_RATES_EX supported_rates; ++#ifdef CONFIG_P2P ++ struct wifidirect_info* pwdinfo = &padapter->wdinfo; ++ ++ // Added by Albert 2011/03/22 ++ // In the P2P mode, the driver should not support the b mode. ++ // So, the Tx packet shouldn't use the CCK rate ++ if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ return; ++#endif //CONFIG_P2P ++#ifdef CONFIG_INTEL_WIDI ++ if (padapter->mlmepriv.widi_state != INTEL_WIDI_STATE_NONE) ++ return; ++#endif //CONFIG_INTEL_WIDI ++ ++ _rtw_memset(supported_rates, 0, NDIS_802_11_LENGTH_RATES_EX); ++ ++ if ((wirelessmode & WIRELESS_11B) && (wirelessmode == WIRELESS_11B)) { ++ _rtw_memcpy(supported_rates, rtw_basic_rate_cck, 4); ++ } else if (wirelessmode & WIRELESS_11B) { ++ _rtw_memcpy(supported_rates, rtw_basic_rate_mix, 7); ++ } else { ++ _rtw_memcpy(supported_rates, rtw_basic_rate_ofdm, 3); ++ } ++ ++ if (wirelessmode & WIRELESS_11B) ++ update_mgnt_tx_rate(padapter, IEEE80211_CCK_RATE_1MB); ++ else ++ update_mgnt_tx_rate(padapter, IEEE80211_OFDM_RATE_6MB); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, supported_rates); ++} ++ ++unsigned char check_assoc_AP(u8 *pframe, uint len) ++{ ++ unsigned int i; ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ u8 epigram_vendor_flag; ++ u8 ralink_vendor_flag; ++ epigram_vendor_flag = 0; ++ ralink_vendor_flag = 0; ++ ++ for (i = sizeof(NDIS_802_11_FIXED_IEs); i < len;) ++ { ++ pIE = (PNDIS_802_11_VARIABLE_IEs)(pframe + i); ++ ++ switch (pIE->ElementID) ++ { ++ case _VENDOR_SPECIFIC_IE_: ++ if ((_rtw_memcmp(pIE->data, ARTHEROS_OUI1, 3)) || (_rtw_memcmp(pIE->data, ARTHEROS_OUI2, 3))) ++ { ++ DBG_871X("link to Artheros AP\n"); ++ return HT_IOT_PEER_ATHEROS; ++ } ++ else if ((_rtw_memcmp(pIE->data, BROADCOM_OUI1, 3)) ++ || (_rtw_memcmp(pIE->data, BROADCOM_OUI2, 3)) ++ || (_rtw_memcmp(pIE->data, BROADCOM_OUI2, 3))) ++ { ++ DBG_871X("link to Broadcom AP\n"); ++ return HT_IOT_PEER_BROADCOM; ++ } ++ else if (_rtw_memcmp(pIE->data, MARVELL_OUI, 3)) ++ { ++ DBG_871X("link to Marvell AP\n"); ++ return HT_IOT_PEER_MARVELL; ++ } ++ else if (_rtw_memcmp(pIE->data, RALINK_OUI, 3)) ++ { ++ if (!ralink_vendor_flag) { ++ ralink_vendor_flag = 1; ++ } else { ++ DBG_871X("link to Ralink AP\n"); ++ return HT_IOT_PEER_RALINK; ++ } ++ } ++ else if (_rtw_memcmp(pIE->data, CISCO_OUI, 3)) ++ { ++ DBG_871X("link to Cisco AP\n"); ++ return HT_IOT_PEER_CISCO; ++ } ++ else if (_rtw_memcmp(pIE->data, REALTEK_OUI, 3)) ++ { ++ DBG_871X("link to Realtek 96B\n"); ++ return HT_IOT_PEER_REALTEK; ++ } ++ else if (_rtw_memcmp(pIE->data, AIRGOCAP_OUI,3)) ++ { ++ DBG_871X("link to Airgo Cap\n"); ++ return HT_IOT_PEER_AIRGO; ++ } ++ else if (_rtw_memcmp(pIE->data, EPIGRAM_OUI, 3)) ++ { ++ epigram_vendor_flag = 1; ++ if(ralink_vendor_flag) { ++ DBG_871X("link to Tenda W311R AP\n"); ++ return HT_IOT_PEER_TENDA; ++ } else { ++ DBG_871X("Capture EPIGRAM_OUI\n"); ++ } ++ } ++ else ++ { ++ break; ++ } ++ ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ ++ if (ralink_vendor_flag && !epigram_vendor_flag) { ++ DBG_871X("link to Ralink AP\n"); ++ return HT_IOT_PEER_RALINK; ++ } else if (ralink_vendor_flag && epigram_vendor_flag){ ++ DBG_871X("link to Tenda W311R AP\n"); ++ return HT_IOT_PEER_TENDA; ++ } else { ++ DBG_871X("link to new AP\n"); ++ return HT_IOT_PEER_UNKNOWN; ++ } ++} ++ ++void update_IOT_info(_adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ switch (pmlmeinfo->assoc_AP_vendor) ++ { ++ case HT_IOT_PEER_MARVELL: ++ pmlmeinfo->turboMode_cts2self = 1; ++ pmlmeinfo->turboMode_rtsen = 0; ++ break; ++ ++ case HT_IOT_PEER_RALINK: ++ pmlmeinfo->turboMode_cts2self = 0; ++ pmlmeinfo->turboMode_rtsen = 1; ++ //disable high power ++ Switch_DM_Func(padapter, (~DYNAMIC_BB_DYNAMIC_TXPWR), _FALSE); ++ break; ++ case HT_IOT_PEER_REALTEK: ++ //rtw_write16(padapter, 0x4cc, 0xffff); ++ //rtw_write16(padapter, 0x546, 0x01c0); ++ //disable high power ++ Switch_DM_Func(padapter, (~DYNAMIC_BB_DYNAMIC_TXPWR), _FALSE); ++ break; ++ default: ++ pmlmeinfo->turboMode_cts2self = 0; ++ pmlmeinfo->turboMode_rtsen = 1; ++ break; ++ } ++ ++} ++ ++void update_capinfo(PADAPTER Adapter, u16 updateCap) ++{ ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ BOOLEAN ShortPreamble; ++ ++ // Check preamble mode, 2005.01.06, by rcnjko. ++ // Mark to update preamble value forever, 2008.03.18 by lanhsin ++ //if( pMgntInfo->RegPreambleMode == PREAMBLE_AUTO ) ++ { ++ ++ if(updateCap & cShortPreamble) ++ { // Short Preamble ++ if(pmlmeinfo->preamble_mode != PREAMBLE_SHORT) // PREAMBLE_LONG or PREAMBLE_AUTO ++ { ++ ShortPreamble = _TRUE; ++ pmlmeinfo->preamble_mode = PREAMBLE_SHORT; ++ rtw_hal_set_hwreg( Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble ); ++ } ++ } ++ else ++ { // Long Preamble ++ if(pmlmeinfo->preamble_mode != PREAMBLE_LONG) // PREAMBLE_SHORT or PREAMBLE_AUTO ++ { ++ ShortPreamble = _FALSE; ++ pmlmeinfo->preamble_mode = PREAMBLE_LONG; ++ rtw_hal_set_hwreg( Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble ); ++ } ++ } ++ } ++ ++ if ( updateCap & cIBSS ) { ++ //Filen: See 802.11-2007 p.91 ++ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; ++ } ++ else ++ { ++ //Filen: See 802.11-2007 p.90 ++ if( pmlmeext->cur_wireless_mode & (WIRELESS_11G | WIRELESS_11_24N)) ++ { ++ if( (updateCap & cShortSlotTime) /* && (!(pMgntInfo->pHTInfo->RT2RT_HT_Mode & RT_HT_CAP_USE_LONG_PREAMBLE)) */) ++ { // Short Slot Time ++ if(pmlmeinfo->slotTime != SHORT_SLOT_TIME) ++ { ++ pmlmeinfo->slotTime = SHORT_SLOT_TIME; ++ } ++ } ++ else ++ { // Long Slot Time ++ if(pmlmeinfo->slotTime != NON_SHORT_SLOT_TIME) ++ { ++ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; ++ } ++ } ++ } ++ else if( pmlmeext->cur_wireless_mode & (WIRELESS_11A | WIRELESS_11_5N)) ++ { ++ pmlmeinfo->slotTime = SHORT_SLOT_TIME; ++ } ++ else ++ { ++ //B Mode ++ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; ++ } ++ } ++ ++ rtw_hal_set_hwreg( Adapter, HW_VAR_SLOT_TIME, &pmlmeinfo->slotTime ); ++ ++} ++ ++void update_wireless_mode(_adapter *padapter) ++{ ++ int ratelen, network_type = 0; ++ u32 SIFS_Timer; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); ++ unsigned char *rate = cur_network->SupportedRates; ++ ++ ratelen = rtw_get_rateset_len(cur_network->SupportedRates); ++ ++ if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) ++ { ++ pmlmeinfo->HT_enable = 1; ++ } ++ ++ if(pmlmeext->cur_channel > 14) ++ { ++ if (pmlmeinfo->HT_enable) ++ { ++ network_type = WIRELESS_11_5N; ++ } ++ ++ network_type |= WIRELESS_11A; ++ } ++ else ++ { ++ if (pmlmeinfo->HT_enable) ++ { ++ network_type = WIRELESS_11_24N; ++ } ++ ++ if ((cckratesonly_included(rate, ratelen)) == _TRUE) ++ { ++ network_type |= WIRELESS_11B; ++ } ++ else if((cckrates_included(rate, ratelen)) == _TRUE) ++ { ++ network_type |= WIRELESS_11BG; ++ } ++ else ++ { ++ network_type |= WIRELESS_11G; ++ } ++ } ++ ++ pmlmeext->cur_wireless_mode = network_type & padapter->registrypriv.wireless_mode; ++/* ++ if((pmlmeext->cur_wireless_mode==WIRELESS_11G) || ++ (pmlmeext->cur_wireless_mode==WIRELESS_11BG))//WIRELESS_MODE_G) ++ SIFS_Timer = 0x0a0a;//CCK ++ else ++ SIFS_Timer = 0x0e0e;//pHalData->SifsTime; //OFDM ++*/ ++ ++ SIFS_Timer = 0x0a0a0808; //0x0808 -> for CCK, 0x0a0a -> for OFDM ++ //change this value if having IOT issues. ++ ++ padapter->HalFunc.SetHwRegHandler( padapter, HW_VAR_RESP_SIFS, (u8 *)&SIFS_Timer); ++ ++ if (pmlmeext->cur_wireless_mode & WIRELESS_11B) ++ update_mgnt_tx_rate(padapter, IEEE80211_CCK_RATE_1MB); ++ else ++ update_mgnt_tx_rate(padapter, IEEE80211_OFDM_RATE_6MB); ++} ++ ++void fire_write_MAC_cmd(_adapter *padapter, unsigned int addr, unsigned int value); ++void fire_write_MAC_cmd(_adapter *padapter, unsigned int addr, unsigned int value) ++{ ++#if 0 ++ struct cmd_obj *ph2c; ++ struct reg_rw_parm *pwriteMacPara; ++ struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); ++ ++ if ((ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ return; ++ } ++ ++ if ((pwriteMacPara = (struct reg_rw_parm*)rtw_malloc(sizeof(struct reg_rw_parm))) == NULL) ++ { ++ rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ return; ++ } ++ ++ pwriteMacPara->rw = 1; ++ pwriteMacPara->addr = addr; ++ pwriteMacPara->value = value; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pwriteMacPara, GEN_CMD_CODE(_Write_MACREG)); ++ rtw_enqueue_cmd(pcmdpriv, ph2c); ++#endif ++} ++ ++void update_bmc_sta_support_rate(_adapter *padapter, u32 mac_id) ++{ ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if(pmlmeext->cur_wireless_mode & WIRELESS_11B) ++ { ++ // Only B, B/G, and B/G/N AP could use CCK rate ++ _rtw_memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), rtw_basic_rate_cck, 4); ++ } ++ else ++ { ++ _rtw_memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), rtw_basic_rate_ofdm, 4); ++ } ++} ++ ++int update_sta_support_rate(_adapter *padapter, u8* pvar_ie, uint var_ie_len, int cam_idx) ++{ ++ unsigned int ie_len; ++ PNDIS_802_11_VARIABLE_IEs pIE; ++ int supportRateNum = 0; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ pIE = (PNDIS_802_11_VARIABLE_IEs)rtw_get_ie(pvar_ie, _SUPPORTEDRATES_IE_, &ie_len, var_ie_len); ++ if (pIE == NULL) ++ { ++ return _FAIL; ++ } ++ ++ _rtw_memcpy(pmlmeinfo->FW_sta_info[cam_idx].SupportedRates, pIE->data, ie_len); ++ supportRateNum = ie_len; ++ ++ pIE = (PNDIS_802_11_VARIABLE_IEs)rtw_get_ie(pvar_ie, _EXT_SUPPORTEDRATES_IE_, &ie_len, var_ie_len); ++ if (pIE) ++ { ++ _rtw_memcpy((pmlmeinfo->FW_sta_info[cam_idx].SupportedRates + supportRateNum), pIE->data, ie_len); ++ } ++ ++ return _SUCCESS; ++ ++} ++ ++void process_addba_req(_adapter *padapter, u8 *paddba_req, u8 *addr) ++{ ++ struct sta_info *psta; ++ u16 tid, start_seq, param; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct ADDBA_request *preq = (struct ADDBA_request*)paddba_req; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ psta = rtw_get_stainfo(pstapriv, addr); ++ ++ if(psta) ++ { ++ start_seq = le16_to_cpu(preq->BA_starting_seqctrl) >> 4; ++ ++ param = le16_to_cpu(preq->BA_para_set); ++ tid = (param>>2)&0x0f; ++ ++ preorder_ctrl = &psta->recvreorder_ctrl[tid]; ++ ++ #ifdef CONFIG_UPDATE_INDICATE_SEQ_WHILE_PROCESS_ADDBA_REQ ++ preorder_ctrl->indicate_seq = start_seq; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, start_seq: %d\n", __FUNCTION__, __LINE__, ++ preorder_ctrl->indicate_seq, start_seq); ++ #endif ++ #else ++ preorder_ctrl->indicate_seq = 0xffff; ++ #endif ++ ++ preorder_ctrl->enable =(pmlmeinfo->bAcceptAddbaReq == _TRUE)? _TRUE :_FALSE; ++ } ++ ++} ++ ++void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) ++{ ++ u8* pIE; ++ u32 *pbuf; ++ ++ pIE = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); ++ pbuf = (u32*)pIE; ++ ++ pmlmeext->TSFValue = le32_to_cpu(*(pbuf+1)); ++ ++ pmlmeext->TSFValue = pmlmeext->TSFValue << 32; ++ ++ pmlmeext->TSFValue |= le32_to_cpu(*pbuf); ++} ++ ++void correct_TSF(_adapter *padapter, struct mlme_ext_priv *pmlmeext) ++{ ++ rtw_hal_set_hwreg(padapter, HW_VAR_CORRECT_TSF, 0); ++} ++ ++void beacon_timing_control(_adapter *padapter) ++{ ++ rtw_hal_bcn_related_reg_setting(padapter); ++} ++ ++#if 0 ++unsigned int setup_beacon_frame(_adapter *padapter, unsigned char *beacon_frame) ++{ ++ unsigned short ATIMWindow; ++ unsigned char *pframe; ++ struct tx_desc *ptxdesc; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ unsigned int rate_len, len = 0; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); ++ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ _rtw_memset(beacon_frame, 0, 256); ++ ++ pframe = beacon_frame + TXDESC_SIZE; ++ ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); ++ ++ SetFrameSubType(pframe, WIFI_BEACON); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ len = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ //timestamp will be inserted by hardware ++ pframe += 8; ++ len += 8; ++ ++ // beacon interval: 2 bytes ++ _rtw_memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ len += 2; ++ ++ // capability info: 2 bytes ++ _rtw_memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ len += 2; ++ ++ // SSID ++ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &len); ++ ++ // supported rates... ++ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8)? 8: rate_len), cur_network->SupportedRates, &len); ++ ++ // DS parameter set ++ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &len); ++ ++ // IBSS Parameter Set... ++ //ATIMWindow = cur->Configuration.ATIMWindow; ++ ATIMWindow = 0; ++ pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &len); ++ ++ //todo: ERP IE ++ ++ // EXTERNDED SUPPORTED RATE ++ if (rate_len > 8) ++ { ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &len); ++ } ++ ++ if ((len + TXDESC_SIZE) > 256) ++ { ++ //DBG_871X("marc: beacon frame too large\n"); ++ return 0; ++ } ++ ++ //fill the tx descriptor ++ ptxdesc = (struct tx_desc *)beacon_frame; ++ ++ //offset 0 ++ ptxdesc->txdw0 |= cpu_to_le32(len & 0x0000ffff); ++ ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) << OFFSET_SHT) & 0x00ff0000); //default = 32 bytes for TX Desc ++ ++ //offset 4 ++ ptxdesc->txdw1 |= cpu_to_le32((0x10 << QSEL_SHT) & 0x00001f00); ++ ++ //offset 8 ++ ptxdesc->txdw2 |= cpu_to_le32(BMC); ++ ptxdesc->txdw2 |= cpu_to_le32(BK); ++ ++ //offset 16 ++ ptxdesc->txdw4 = 0x80000000; ++ ++ //offset 20 ++ ptxdesc->txdw5 = 0x00000000; //1M ++ ++ return (len + TXDESC_SIZE); ++} ++#endif ++ ++static _adapter *pbuddy_padapter = NULL; ++ ++int rtw_handle_dualmac(_adapter *adapter, bool init) ++{ ++ int status = _SUCCESS; ++ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); ++ ++ if (init) { ++ #if 0 ++ /* For SMSP on 92DU-VC, driver do not probe another Interface. */ ++ if(dvobj->NumInterfaces == 2 && dvobj->InterfaceNumber != 0 && ++ adapter->registrypriv.mac_phy_mode == 1) { ++ DBG_871X("%s(): Do not init another USB Interface because SMSP\n",__FUNCTION__); ++ status = _FAIL; ++ goto exit; ++ } ++ #endif ++ ++ if (pbuddy_padapter == NULL) { ++ pbuddy_padapter = adapter; ++ DBG_871X("%s(): pbuddy_padapter == NULL, Set pbuddy_padapter\n",__FUNCTION__); ++ } else { ++ adapter->pbuddy_adapter = pbuddy_padapter; ++ pbuddy_padapter->pbuddy_adapter = adapter; ++ // clear global value ++ pbuddy_padapter = NULL; ++ DBG_871X("%s(): pbuddy_padapter exist, Exchange Information\n",__FUNCTION__); ++ } ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ if (dvobj->InterfaceNumber == 0) { ++ //set adapter_type/iface type ++ adapter->isprimary = _TRUE; ++ adapter->adapter_type = PRIMARY_ADAPTER; ++ adapter->iface_type = IFACE_PORT0; ++ DBG_871X("%s(): PRIMARY_ADAPTER\n",__FUNCTION__); ++ } else { ++ //set adapter_type/iface type ++ adapter->isprimary = _FALSE; ++ adapter->adapter_type = SECONDARY_ADAPTER; ++ adapter->iface_type = IFACE_PORT1; ++ DBG_871X("%s(): SECONDARY_ADAPTER\n",__FUNCTION__); ++ } ++#endif ++ }else { ++ pbuddy_padapter = NULL; ++ } ++exit: ++ return status; ++} ++#ifdef CONFIG_WOWLAN ++void rtw_get_current_ip_address(PADAPTER padapter, u8 *pcurrentip) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct in_device *my_ip_ptr = padapter->pnetdev->ip_ptr; ++ u8 ipaddress[4]; ++ ++ if ( (pmlmeinfo->state & WIFI_FW_LINKING_STATE) ) { ++ if ( my_ip_ptr != NULL ) { ++ struct in_ifaddr *my_ifa_list = my_ip_ptr->ifa_list ; ++ if ( my_ifa_list != NULL ) { ++ ipaddress[0] = my_ifa_list->ifa_address & 0xFF; ++ ipaddress[1] = (my_ifa_list->ifa_address >> 8) & 0xFF; ++ ipaddress[2] = (my_ifa_list->ifa_address >> 16) & 0xFF; ++ ipaddress[3] = my_ifa_list->ifa_address >> 24; ++ DBG_871X("%s: %d.%d.%d.%d ==========\n", __func__, ++ ipaddress[0], ipaddress[1], ipaddress[2], ipaddress[3]); ++ _rtw_memcpy(pcurrentip, ipaddress, 4); ++ } ++ } ++ } ++} ++void rtw_get_sec_iv(PADAPTER padapter, u8*pcur_dot11txpn, u8 *StaAddr) ++{ ++ struct sta_info *psta; ++ struct security_priv *psecpriv = &padapter->securitypriv; ++ ++ _rtw_memset(pcur_dot11txpn, 0, 8); ++ if(NULL == StaAddr) ++ return; ++ psta = rtw_get_stainfo(&padapter->stapriv, StaAddr); ++ DBG_871X("%s(): StaAddr: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", ++ __func__, StaAddr[0], StaAddr[1], StaAddr[2], StaAddr[3], StaAddr[4], StaAddr[5]); ++ ++ if(psta) ++ { ++ if (psecpriv->dot11PrivacyAlgrthm != _NO_PRIVACY_ && psta->dot11txpn.val > 0) ++ psta->dot11txpn.val--; ++ ++ _rtw_memcpy(pcur_dot11txpn, (u8*)&psta->dot11txpn, 8); ++ ++ DBG_871X("%s(): CurrentIV: 0x%016llx\n", __func__, psta->dot11txpn.val); ++ } ++} ++void rtw_set_sec_iv(PADAPTER padapter) ++{ ++ struct sta_info *psta; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct security_priv *psecpriv = &padapter->securitypriv; ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, get_my_bssid(&pmlmeinfo->network)); ++ ++ if(psta) ++ { ++ if (pwrpriv->wowlan_fw_iv > psta->dot11txpn.val) ++ { ++ if (psecpriv->dot11PrivacyAlgrthm != _NO_PRIVACY_) ++ psta->dot11txpn.val = pwrpriv->wowlan_fw_iv + 2; ++ } else { ++ DBG_871X("%s(): FW IV is smaller than driver\n", __func__); ++ psta->dot11txpn.val += 2; ++ } ++ DBG_871X("%s: dot11txpn: 0x%016llx\n", __func__ ,psta->dot11txpn.val); ++ } ++} ++#endif //CONFIG_WOWLAN +diff --git a/drivers/net/wireless/rtl818x/rtl8189/core/rtw_xmit.c b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_xmit.c +new file mode 100644 +index 00000000..73043534 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/core/rtw_xmit.c +@@ -0,0 +1,4469 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTW_XMIT_C_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if defined (PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) ++#error "Shall be Linux or Windows, but not both!\n" ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++#include ++#endif ++ ++#ifdef CONFIG_USB_HCI ++#include ++#endif ++ ++ ++static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; ++static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; ++ ++static void _init_txservq(struct tx_servq *ptxservq) ++{ ++_func_enter_; ++ _rtw_init_listhead(&ptxservq->tx_pending); ++ _rtw_init_queue(&ptxservq->sta_pending); ++ ptxservq->qcnt = 0; ++_func_exit_; ++} ++ ++ ++void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv) ++{ ++ ++_func_enter_; ++ ++ _rtw_memset((unsigned char *)psta_xmitpriv, 0, sizeof (struct sta_xmit_priv)); ++ ++ _rtw_spinlock_init(&psta_xmitpriv->lock); ++ ++ //for(i = 0 ; i < MAX_NUMBLKS; i++) ++ // _init_txservq(&(psta_xmitpriv->blk_q[i])); ++ ++ _init_txservq(&psta_xmitpriv->be_q); ++ _init_txservq(&psta_xmitpriv->bk_q); ++ _init_txservq(&psta_xmitpriv->vi_q); ++ _init_txservq(&psta_xmitpriv->vo_q); ++ _rtw_init_listhead(&psta_xmitpriv->legacy_dz); ++ _rtw_init_listhead(&psta_xmitpriv->apsd); ++ ++_func_exit_; ++ ++} ++ ++s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, _adapter *padapter) ++{ ++ int i; ++ struct xmit_buf *pxmitbuf; ++ struct xmit_frame *pxframe; ++ sint res=_SUCCESS; ++ u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; ++ u32 num_xmit_extbuf = NR_XMIT_EXTBUFF; ++ ++#if defined(CONFIG_MP_INCLUDED) && defined(CONFIG_RTL8723A) ++ if (padapter->registrypriv.mp_mode) { ++ max_xmit_extbuf_size = 6000; ++ num_xmit_extbuf = 8; ++ } ++#endif ++ ++_func_enter_; ++ ++ // We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). ++ //_rtw_memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv)); ++ ++ _rtw_spinlock_init(&pxmitpriv->lock); ++ _rtw_spinlock_init(&pxmitpriv->lock_sctx); ++ _rtw_init_sema(&pxmitpriv->xmit_sema, 0); ++ _rtw_init_sema(&pxmitpriv->terminate_xmitthread_sema, 0); ++ ++ /* ++ Please insert all the queue initializaiton using _rtw_init_queue below ++ */ ++ ++ pxmitpriv->adapter = padapter; ++ ++ //for(i = 0 ; i < MAX_NUMBLKS; i++) ++ // _rtw_init_queue(&pxmitpriv->blk_strms[i]); ++ ++ _rtw_init_queue(&pxmitpriv->be_pending); ++ _rtw_init_queue(&pxmitpriv->bk_pending); ++ _rtw_init_queue(&pxmitpriv->vi_pending); ++ _rtw_init_queue(&pxmitpriv->vo_pending); ++ _rtw_init_queue(&pxmitpriv->bm_pending); ++ ++ //_rtw_init_queue(&pxmitpriv->legacy_dz_queue); ++ //_rtw_init_queue(&pxmitpriv->apsd_queue); ++ ++ _rtw_init_queue(&pxmitpriv->free_xmit_queue); ++ ++ /* ++ Please allocate memory with the sz = (struct xmit_frame) * NR_XMITFRAME, ++ and initialize free_xmit_frame below. ++ Please also apply free_txobj to link_up all the xmit_frames... ++ */ ++ ++ pxmitpriv->pallocated_frame_buf = rtw_zvmalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4); ++ ++ if (pxmitpriv->pallocated_frame_buf == NULL){ ++ pxmitpriv->pxmit_frame_buf =NULL; ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("alloc xmit_frame fail!\n")); ++ res= _FAIL; ++ goto exit; ++ } ++ pxmitpriv->pxmit_frame_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->pallocated_frame_buf), 4); ++ //pxmitpriv->pxmit_frame_buf = pxmitpriv->pallocated_frame_buf + 4 - ++ // ((SIZE_PTR) (pxmitpriv->pallocated_frame_buf) &3); ++ ++ pxframe = (struct xmit_frame*) pxmitpriv->pxmit_frame_buf; ++ ++ for (i = 0; i < NR_XMITFRAME; i++) ++ { ++ _rtw_init_listhead(&(pxframe->list)); ++ ++ pxframe->padapter = padapter; ++ pxframe->frame_tag = NULL_FRAMETAG; ++ ++ pxframe->pkt = NULL; ++ ++ pxframe->buf_addr = NULL; ++ pxframe->pxmitbuf = NULL; ++ ++ rtw_list_insert_tail(&(pxframe->list), &(pxmitpriv->free_xmit_queue.queue)); ++ ++ pxframe++; ++ } ++ ++ pxmitpriv->free_xmitframe_cnt = NR_XMITFRAME; ++ ++ pxmitpriv->frag_len = MAX_FRAG_THRESHOLD; ++ ++ ++ //init xmit_buf ++ _rtw_init_queue(&pxmitpriv->free_xmitbuf_queue); ++ _rtw_init_queue(&pxmitpriv->pending_xmitbuf_queue); ++ ++ pxmitpriv->pallocated_xmitbuf = rtw_zvmalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4); ++ ++ if (pxmitpriv->pallocated_xmitbuf == NULL){ ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("alloc xmit_buf fail!\n")); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pxmitpriv->pxmitbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->pallocated_xmitbuf), 4); ++ //pxmitpriv->pxmitbuf = pxmitpriv->pallocated_xmitbuf + 4 - ++ // ((SIZE_PTR) (pxmitpriv->pallocated_xmitbuf) &3); ++ ++ pxmitbuf = (struct xmit_buf*)pxmitpriv->pxmitbuf; ++ ++ for (i = 0; i < NR_XMITBUFF; i++) ++ { ++ _rtw_init_listhead(&pxmitbuf->list); ++ ++ pxmitbuf->priv_data = NULL; ++ pxmitbuf->padapter = padapter; ++ pxmitbuf->ext_tag = _FALSE; ++ ++/* ++ pxmitbuf->pallocated_buf = rtw_zmalloc(MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ); ++ if (pxmitbuf->pallocated_buf == NULL) ++ { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ); ++ //pxmitbuf->pbuf = pxmitbuf->pallocated_buf + XMITBUF_ALIGN_SZ -((SIZE_PTR) (pxmitbuf->pallocated_buf) &(XMITBUF_ALIGN_SZ-1)); ++*/ ++ /* Tx buf allocation may fail sometimes, so sleep and retry. */ ++ if((res=rtw_os_xmit_resource_alloc(padapter, pxmitbuf,(MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ))) == _FAIL) { ++ rtw_msleep_os(10); ++ res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf,(MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ)); ++ if (res == _FAIL) { ++ goto exit; ++ } ++ } ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ pxmitbuf->phead = pxmitbuf->pbuf; ++ pxmitbuf->pend = pxmitbuf->pbuf + MAX_XMITBUF_SZ; ++ pxmitbuf->len = 0; ++ pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; ++#endif ++ ++ pxmitbuf->flags = XMIT_VO_QUEUE; ++ ++ rtw_list_insert_tail(&pxmitbuf->list, &(pxmitpriv->free_xmitbuf_queue.queue)); ++ #ifdef DBG_XMIT_BUF ++ pxmitbuf->no=i; ++ #endif ++ ++ pxmitbuf++; ++ ++ } ++ ++ pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF; ++ ++ /* init xframe_ext queue, the same count as extbuf */ ++ _rtw_init_queue(&pxmitpriv->free_xframe_ext_queue); ++ ++ pxmitpriv->xframe_ext_alloc_addr = rtw_zvmalloc(num_xmit_extbuf * sizeof(struct xmit_frame) + 4); ++ ++ if (pxmitpriv->xframe_ext_alloc_addr == NULL){ ++ pxmitpriv->xframe_ext = NULL; ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("alloc xframe_ext fail!\n")); ++ res= _FAIL; ++ goto exit; ++ } ++ pxmitpriv->xframe_ext = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->xframe_ext_alloc_addr), 4); ++ pxframe = (struct xmit_frame*)pxmitpriv->xframe_ext; ++ ++ for (i = 0; i < num_xmit_extbuf; i++) { ++ _rtw_init_listhead(&(pxframe->list)); ++ ++ pxframe->padapter = padapter; ++ pxframe->frame_tag = NULL_FRAMETAG; ++ ++ pxframe->pkt = NULL; ++ ++ pxframe->buf_addr = NULL; ++ pxframe->pxmitbuf = NULL; ++ ++ pxframe->ext_tag = 1; ++ ++ rtw_list_insert_tail(&(pxframe->list), &(pxmitpriv->free_xframe_ext_queue.queue)); ++ ++ pxframe++; ++ } ++ pxmitpriv->free_xframe_ext_cnt = num_xmit_extbuf; ++ ++ // Init xmit extension buff ++ _rtw_init_queue(&pxmitpriv->free_xmit_extbuf_queue); ++ ++ pxmitpriv->pallocated_xmit_extbuf = rtw_zvmalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4); ++ ++ if (pxmitpriv->pallocated_xmit_extbuf == NULL){ ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("alloc xmit_extbuf fail!\n")); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ pxmitpriv->pxmit_extbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->pallocated_xmit_extbuf), 4); ++ ++ pxmitbuf = (struct xmit_buf*)pxmitpriv->pxmit_extbuf; ++ ++ for (i = 0; i < num_xmit_extbuf; i++) ++ { ++ _rtw_init_listhead(&pxmitbuf->list); ++ ++ pxmitbuf->priv_data = NULL; ++ pxmitbuf->padapter = padapter; ++ pxmitbuf->ext_tag = _TRUE; ++ ++/* ++ pxmitbuf->pallocated_buf = rtw_zmalloc(max_xmit_extbuf_size); ++ if (pxmitbuf->pallocated_buf == NULL) ++ { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), 4); ++*/ ++ ++ if((res=rtw_os_xmit_resource_alloc(padapter, pxmitbuf,max_xmit_extbuf_size + XMITBUF_ALIGN_SZ)) == _FAIL) { ++ res= _FAIL; ++ goto exit; ++ } ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ pxmitbuf->phead = pxmitbuf->pbuf; ++ pxmitbuf->pend = pxmitbuf->pbuf + max_xmit_extbuf_size; ++ pxmitbuf->len = 0; ++ pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; ++#endif ++ ++ rtw_list_insert_tail(&pxmitbuf->list, &(pxmitpriv->free_xmit_extbuf_queue.queue)); ++ #ifdef DBG_XMIT_BUF_EXT ++ pxmitbuf->no=i; ++ #endif ++ pxmitbuf++; ++ ++ } ++ ++ pxmitpriv->free_xmit_extbuf_cnt = num_xmit_extbuf; ++ ++ rtw_alloc_hwxmits(padapter); ++ rtw_init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); ++ ++ for (i = 0; i < 4; i ++) ++ { ++ pxmitpriv->wmm_para_seq[i] = i; ++ } ++ ++#ifdef CONFIG_USB_HCI ++ pxmitpriv->txirp_cnt=1; ++ ++ _rtw_init_sema(&(pxmitpriv->tx_retevt), 0); ++ ++ //per AC pending irp ++ pxmitpriv->beq_cnt = 0; ++ pxmitpriv->bkq_cnt = 0; ++ pxmitpriv->viq_cnt = 0; ++ pxmitpriv->voq_cnt = 0; ++#endif ++ ++ ++#ifdef CONFIG_XMIT_ACK ++ pxmitpriv->ack_tx = _FALSE; ++ _rtw_mutex_init(&pxmitpriv->ack_tx_mutex); ++ rtw_sctx_init(&pxmitpriv->ack_tx_ops, 0); ++#endif ++ ++ rtw_hal_init_xmit_priv(padapter); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++void rtw_mfree_xmit_priv_lock (struct xmit_priv *pxmitpriv); ++void rtw_mfree_xmit_priv_lock (struct xmit_priv *pxmitpriv) ++{ ++ _rtw_spinlock_free(&pxmitpriv->lock); ++ _rtw_free_sema(&pxmitpriv->xmit_sema); ++ _rtw_free_sema(&pxmitpriv->terminate_xmitthread_sema); ++ ++ _rtw_spinlock_free(&pxmitpriv->be_pending.lock); ++ _rtw_spinlock_free(&pxmitpriv->bk_pending.lock); ++ _rtw_spinlock_free(&pxmitpriv->vi_pending.lock); ++ _rtw_spinlock_free(&pxmitpriv->vo_pending.lock); ++ _rtw_spinlock_free(&pxmitpriv->bm_pending.lock); ++ ++ //_rtw_spinlock_free(&pxmitpriv->legacy_dz_queue.lock); ++ //_rtw_spinlock_free(&pxmitpriv->apsd_queue.lock); ++ ++ _rtw_spinlock_free(&pxmitpriv->free_xmit_queue.lock); ++ _rtw_spinlock_free(&pxmitpriv->free_xmitbuf_queue.lock); ++ _rtw_spinlock_free(&pxmitpriv->pending_xmitbuf_queue.lock); ++} ++ ++ ++void _rtw_free_xmit_priv (struct xmit_priv *pxmitpriv) ++{ ++ int i; ++ _adapter *padapter = pxmitpriv->adapter; ++ struct xmit_frame *pxmitframe = (struct xmit_frame*) pxmitpriv->pxmit_frame_buf; ++ struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; ++ u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; ++ u32 num_xmit_extbuf = NR_XMIT_EXTBUFF; ++ ++#if defined(CONFIG_MP_INCLUDED) && defined(CONFIG_RTL8723A) ++ if (padapter->registrypriv.mp_mode) { ++ max_xmit_extbuf_size = 6000; ++ num_xmit_extbuf = 8; ++ } ++#endif ++ ++ _func_enter_; ++ ++ rtw_hal_free_xmit_priv(padapter); ++ ++ rtw_mfree_xmit_priv_lock(pxmitpriv); ++ ++ if(pxmitpriv->pxmit_frame_buf==NULL) ++ goto out; ++ ++ for(i=0; ipallocated_buf) ++ // rtw_mfree(pxmitbuf->pallocated_buf, MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ); ++ ++ pxmitbuf++; ++ } ++ ++ if(pxmitpriv->pallocated_frame_buf) { ++ rtw_vmfree(pxmitpriv->pallocated_frame_buf, NR_XMITFRAME * sizeof(struct xmit_frame) + 4); ++ } ++ ++ ++ if(pxmitpriv->pallocated_xmitbuf) { ++ rtw_vmfree(pxmitpriv->pallocated_xmitbuf, NR_XMITBUFF * sizeof(struct xmit_buf) + 4); ++ } ++ ++ /* free xframe_ext queue, the same count as extbuf */ ++ if ((pxmitframe = (struct xmit_frame*)pxmitpriv->xframe_ext)) { ++ for (i=0; ixframe_ext_alloc_addr) ++ rtw_vmfree(pxmitpriv->xframe_ext_alloc_addr, num_xmit_extbuf * sizeof(struct xmit_frame) + 4); ++ _rtw_spinlock_free(&pxmitpriv->free_xframe_ext_queue.lock); ++ ++ // free xmit extension buff ++ _rtw_spinlock_free(&pxmitpriv->free_xmit_extbuf_queue.lock); ++ ++ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; ++ for(i=0; ipallocated_buf) ++ // rtw_mfree(pxmitbuf->pallocated_buf, max_xmit_extbuf_size); ++ ++ pxmitbuf++; ++ } ++ ++ if(pxmitpriv->pallocated_xmit_extbuf) { ++ rtw_vmfree(pxmitpriv->pallocated_xmit_extbuf, num_xmit_extbuf * sizeof(struct xmit_buf) + 4); ++ } ++ ++ rtw_free_hwxmits(padapter); ++ ++#ifdef CONFIG_XMIT_ACK ++ _rtw_mutex_free(&pxmitpriv->ack_tx_mutex); ++#endif ++ ++out: ++ ++_func_exit_; ++ ++} ++ ++static void update_attrib_vcs_info(_adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ u32 sz; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct sta_info *psta = pattrib->psta; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if(pattrib->psta) ++ { ++ psta = pattrib->psta; ++ } ++ else ++ { ++ DBG_871X("%s, call rtw_get_stainfo()\n", __func__); ++ psta=rtw_get_stainfo(&padapter->stapriv ,&pattrib->ra[0] ); ++ } ++ ++ if(psta==NULL) ++ { ++ DBG_871X("%s, psta==NUL\n", __func__); ++ return; ++ } ++ ++ if(!(psta->state &_FW_LINKED)) ++ { ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); ++ return; ++ } ++ ++ if (pattrib->nr_frags != 1) ++ { ++ sz = padapter->xmitpriv.frag_len; ++ } ++ else //no frag ++ { ++ sz = pattrib->last_txcmdsz; ++ } ++ ++ // (1) RTS_Threshold is compared to the MPDU, not MSDU. ++ // (2) If there are more than one frag in this MSDU, only the first frag uses protection frame. ++ // Other fragments are protected by previous fragment. ++ // So we only need to check the length of first fragment. ++ if(pmlmeext->cur_wireless_mode < WIRELESS_11_24N || padapter->registrypriv.wifi_spec) ++ { ++ if(sz > padapter->registrypriv.rts_thresh) ++ { ++ pattrib->vcs_mode = RTS_CTS; ++ } ++ else ++ { ++ if(psta->rtsen) ++ pattrib->vcs_mode = RTS_CTS; ++ else if(psta->cts2self) ++ pattrib->vcs_mode = CTS_TO_SELF; ++ else ++ pattrib->vcs_mode = NONE_VCS; ++ } ++ } ++ else ++ { ++ while (_TRUE) ++ { ++#if 0 //Todo ++ //check IOT action ++ if(pHTInfo->IOTAction & HT_IOT_ACT_FORCED_CTS2SELF) ++ { ++ pattrib->vcs_mode = CTS_TO_SELF; ++ pattrib->rts_rate = MGN_24M; ++ break; ++ } ++ else if(pHTInfo->IOTAction & (HT_IOT_ACT_FORCED_RTS|HT_IOT_ACT_PURE_N_MODE)) ++ { ++ pattrib->vcs_mode = RTS_CTS; ++ pattrib->rts_rate = MGN_24M; ++ break; ++ } ++#endif ++ ++ //IOT action ++ if((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS) && (pattrib->ampdu_en==_TRUE) && ++ (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_ )) ++ { ++ pattrib->vcs_mode = CTS_TO_SELF; ++ break; ++ } ++ ++ ++ //check ERP protection ++ if(psta->rtsen || psta->cts2self) ++ { ++ if(psta->rtsen) ++ pattrib->vcs_mode = RTS_CTS; ++ else if(psta->cts2self) ++ pattrib->vcs_mode = CTS_TO_SELF; ++ ++ break; ++ } ++ ++ //check HT op mode ++ if(pattrib->ht_en) ++ { ++ u8 HTOpMode = pmlmeinfo->HT_protection; ++ if((pmlmeext->cur_bwmode && (HTOpMode == 2 || HTOpMode == 3)) || ++ (!pmlmeext->cur_bwmode && HTOpMode == 3) ) ++ { ++ pattrib->vcs_mode = RTS_CTS; ++ break; ++ } ++ } ++ ++ //check rts ++ if(sz > padapter->registrypriv.rts_thresh) ++ { ++ pattrib->vcs_mode = RTS_CTS; ++ break; ++ } ++ ++ //to do list: check MIMO power save condition. ++ ++ //check AMPDU aggregation for TXOP ++ if(pattrib->ampdu_en==_TRUE) ++ { ++ pattrib->vcs_mode = RTS_CTS; ++ break; ++ } ++ ++ pattrib->vcs_mode = NONE_VCS; ++ break; ++ } ++ } ++} ++ ++static void update_attrib_phy_info(struct pkt_attrib *pattrib, struct sta_info *psta) ++{ ++ /*if(psta->rtsen) ++ pattrib->vcs_mode = RTS_CTS; ++ else if(psta->cts2self) ++ pattrib->vcs_mode = CTS_TO_SELF; ++ else ++ pattrib->vcs_mode = NONE_VCS;*/ ++ ++ pattrib->mdata = 0; ++ pattrib->eosp = 0; ++ pattrib->triggered=0; ++ ++ //qos_en, ht_en, init rate, ,bw, ch_offset, sgi ++ pattrib->qos_en = psta->qos_option; ++ ++ pattrib->raid = psta->raid; ++#ifdef CONFIG_80211N_HT ++ pattrib->ht_en = psta->htpriv.ht_option; ++ pattrib->bwmode = psta->htpriv.bwmode; ++ pattrib->ch_offset = psta->htpriv.ch_offset; ++ pattrib->sgi= psta->htpriv.sgi; ++ pattrib->ampdu_en = _FALSE; ++#endif //CONFIG_80211N_HT ++ //if(pattrib->ht_en && psta->htpriv.ampdu_enable) ++ //{ ++ // if(psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority)) ++ // pattrib->ampdu_en = _TRUE; ++ //} ++ ++ ++ pattrib->retry_ctrl = _FALSE; ++ ++} ++ ++u8 qos_acm(u8 acm_mask, u8 priority) ++{ ++ u8 change_priority = priority; ++ ++ switch (priority) ++ { ++ case 0: ++ case 3: ++ if(acm_mask & BIT(1)) ++ change_priority = 1; ++ break; ++ case 1: ++ case 2: ++ break; ++ case 4: ++ case 5: ++ if(acm_mask & BIT(2)) ++ change_priority = 0; ++ break; ++ case 6: ++ case 7: ++ if(acm_mask & BIT(3)) ++ change_priority = 5; ++ break; ++ default: ++ DBG_871X("qos_acm(): invalid pattrib->priority: %d!!!\n", priority); ++ break; ++ } ++ ++ return change_priority; ++} ++ ++static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) ++{ ++ struct ethhdr etherhdr; ++ struct iphdr ip_hdr; ++ s32 UserPriority = 0; ++ ++ ++ _rtw_open_pktfile(ppktfile->pkt, ppktfile); ++ _rtw_pktfile_read(ppktfile, (unsigned char*)ðerhdr, ETH_HLEN); ++ ++ // get UserPriority from IP hdr ++ if (pattrib->ether_type == 0x0800) { ++ _rtw_pktfile_read(ppktfile, (u8*)&ip_hdr, sizeof(ip_hdr)); ++// UserPriority = (ntohs(ip_hdr.tos) >> 5) & 0x3; ++ UserPriority = ip_hdr.tos >> 5; ++ } else if (pattrib->ether_type == 0x888e) { ++ // "When priority processing of data frames is supported, ++ // a STA's SME should send EAPOL-Key frames at the highest priority." ++ UserPriority = 7; ++ } ++ ++ pattrib->priority = UserPriority; ++ pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN; ++ pattrib->subtype = WIFI_QOS_DATA_TYPE; ++} ++ ++static s32 update_attrib(_adapter *padapter, _pkt *pkt, struct pkt_attrib *pattrib) ++{ ++ uint i; ++ struct pkt_file pktfile; ++ struct sta_info *psta = NULL; ++ struct ethhdr etherhdr; ++ ++ sint bmcast; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct qos_priv *pqospriv= &pmlmepriv->qospriv; ++ sint res = _SUCCESS; ++ ++ _func_enter_; ++ ++ _rtw_open_pktfile(pkt, &pktfile); ++ i = _rtw_pktfile_read(&pktfile, (u8*)ðerhdr, ETH_HLEN); ++ ++ pattrib->ether_type = ntohs(etherhdr.h_proto); ++ ++ ++ _rtw_memcpy(pattrib->dst, ðerhdr.h_dest, ETH_ALEN); ++ _rtw_memcpy(pattrib->src, ðerhdr.h_source, ETH_ALEN); ++ ++ pattrib->pctrl = 0; ++ ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE)) { ++ _rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ } ++ else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { ++ _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ } ++ else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ _rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); ++ } ++ ++ pattrib->pktlen = pktfile.pkt_len; ++ ++ if (ETH_P_IP == pattrib->ether_type) ++ { ++ // The following is for DHCP and ARP packet, we use cck1M to tx these packets and let LPS awake some time ++ // to prevent DHCP protocol fail ++ u8 tmp[24]; ++ _rtw_pktfile_read(&pktfile, &tmp[0], 24); ++ pattrib->dhcp_pkt = 0; ++ if (pktfile.pkt_len > 282) {//MINIMUM_DHCP_PACKET_SIZE) { ++ if (ETH_P_IP == pattrib->ether_type) {// IP header ++ if (((tmp[21] == 68) && (tmp[23] == 67)) || ++ ((tmp[21] == 67) && (tmp[23] == 68))) { ++ // 68 : UDP BOOTP client ++ // 67 : UDP BOOTP server ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("======================update_attrib: get DHCP Packet \n")); ++ // Use low rate to send DHCP packet. ++ //if(pMgntInfo->IOTAction & HT_IOT_ACT_WA_IOT_Broadcom) ++ //{ ++ // tcb_desc->DataRate = MgntQuery_TxRateExcludeCCKRates(ieee);//0xc;//ofdm 6m ++ // tcb_desc->bTxDisableRateFallBack = false; ++ //} ++ //else ++ // pTcb->DataRate = Adapter->MgntInfo.LowestBasicRate; ++ //RTPRINT(FDM, WA_IOT, ("DHCP TranslateHeader(), pTcb->DataRate = 0x%x\n", pTcb->DataRate)); ++ pattrib->dhcp_pkt = 1; ++ } ++ } ++ } ++ } else if (0x888e == pattrib->ether_type) { ++ DBG_871X_LEVEL(_drv_always_, "send eapol packet\n"); ++ } ++ ++ if ( (pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1) ) ++ { ++ rtw_set_scan_deny(padapter, 3000); ++ } ++ ++#ifdef CONFIG_LPS ++ // If EAPOL , ARP , OR DHCP packet, driver must be in active mode. ++#ifdef CONFIG_WAPI_SUPPORT ++ if ( (pattrib->ether_type == 0x88B4) || (pattrib->ether_type == 0x0806) || (pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1) ) ++#else ++ if ( (pattrib->ether_type == 0x0806) || (pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1) ) ++#endif ++ { ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SPECIAL_PACKET, 1); ++ } ++#endif ++ ++ bmcast = IS_MCAST(pattrib->ra); ++ ++ // get sta_info ++ if (bmcast) { ++ psta = rtw_get_bcmc_stainfo(padapter); ++ } else { ++ psta = rtw_get_stainfo(pstapriv, pattrib->ra); ++ if (psta == NULL) { // if we cannot get psta => drrp the pkt ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:" MAC_FMT"\n", MAC_ARG(pattrib->ra))); ++ #ifdef DBG_TX_DROP_FRAME ++ DBG_871X("DBG_TX_DROP_FRAME %s get sta_info fail, ra:" MAC_FMT"\n", __FUNCTION__, MAC_ARG(pattrib->ra)); ++ #endif ++ res =_FAIL; ++ goto exit; ++ } ++ else if((check_fwstate(pmlmepriv, WIFI_AP_STATE)==_TRUE)&&(!(psta->state & _FW_LINKED))) ++ { ++ res =_FAIL; ++ goto exit; ++ } ++ } ++ ++ if (psta) ++ { ++ pattrib->mac_id = psta->mac_id; ++ //DBG_8192C("%s ==> mac_id(%d)\n",__FUNCTION__,pattrib->mac_id ); ++ pattrib->psta = psta; ++ } ++ else ++ { ++ // if we cannot get psta => drop the pkt ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:" MAC_FMT "\n", MAC_ARG(pattrib->ra))); ++ #ifdef DBG_TX_DROP_FRAME ++ DBG_871X("DBG_TX_DROP_FRAME %s get sta_info fail, ra:" MAC_FMT"\n", __FUNCTION__, MAC_ARG(pattrib->ra)); ++ #endif ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pattrib->ack_policy = 0; ++ // get ether_hdr_len ++ pattrib->pkt_hdrlen = ETH_HLEN;//(pattrib->ether_type == 0x8100) ? (14 + 4 ): 14; //vlan tag ++ ++ pattrib->hdrlen = WLAN_HDR_A3_LEN; ++ pattrib->subtype = WIFI_DATA_TYPE; ++ pattrib->priority = 0; ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE|WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) ++ { ++ if(psta->qos_option) ++ set_qos(&pktfile, pattrib); ++ } ++ else ++ { ++ if(pqospriv->qos_option) ++ { ++ set_qos(&pktfile, pattrib); ++ ++ if(pmlmepriv->acm_mask != 0) ++ { ++ pattrib->priority = qos_acm(pmlmepriv->acm_mask, pattrib->priority); ++ } ++ } ++ } ++ ++ //pattrib->priority = 5; //force to used VI queue, for testing ++ ++ if (psta->ieee8021x_blocked == _TRUE) ++ { ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("\n psta->ieee8021x_blocked == _TRUE \n")); ++ ++ pattrib->encrypt = 0; ++ ++ if((pattrib->ether_type != 0x888e) && (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _FALSE)) ++ { ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("\npsta->ieee8021x_blocked == _TRUE, pattrib->ether_type(%.4x) != 0x888e\n",pattrib->ether_type)); ++ #ifdef DBG_TX_DROP_FRAME ++ DBG_871X("DBG_TX_DROP_FRAME %s psta->ieee8021x_blocked == _TRUE, pattrib->ether_type(%04x) != 0x888e\n", __FUNCTION__,pattrib->ether_type); ++ #endif ++ res = _FAIL; ++ goto exit; ++ } ++ } ++ else ++ { ++ GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast); ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ if(pattrib->ether_type == 0x88B4) ++ pattrib->encrypt=_NO_PRIVACY_; ++#endif ++ ++ switch(psecuritypriv->dot11AuthAlgrthm) ++ { ++ case dot11AuthAlgrthm_Open: ++ case dot11AuthAlgrthm_Shared: ++ case dot11AuthAlgrthm_Auto: ++ pattrib->key_idx = (u8)psecuritypriv->dot11PrivacyKeyIndex; ++ break; ++ case dot11AuthAlgrthm_8021X: ++ if(bmcast) ++ pattrib->key_idx = (u8)psecuritypriv->dot118021XGrpKeyid; ++ else ++ pattrib->key_idx = 0; ++ break; ++ default: ++ pattrib->key_idx = 0; ++ break; ++ } ++ ++ ++ } ++ ++ switch (pattrib->encrypt) ++ { ++ case _WEP40_: ++ case _WEP104_: ++ pattrib->iv_len = 4; ++ pattrib->icv_len = 4; ++ break; ++ ++ case _TKIP_: ++ pattrib->iv_len = 8; ++ pattrib->icv_len = 4; ++ ++ if(padapter->securitypriv.busetkipkey==_FAIL) ++ { ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("\npadapter->securitypriv.busetkipkey(%d)==_FAIL drop packet\n", padapter->securitypriv.busetkipkey)); ++ #ifdef DBG_TX_DROP_FRAME ++ DBG_871X("DBG_TX_DROP_FRAME %s padapter->securitypriv.busetkipkey(%d)==_FAIL drop packet\n", __FUNCTION__, padapter->securitypriv.busetkipkey); ++ #endif ++ res =_FAIL; ++ goto exit; ++ } ++ ++ break; ++ case _AES_: ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("pattrib->encrypt=%d (_AES_)\n",pattrib->encrypt)); ++ pattrib->iv_len = 8; ++ pattrib->icv_len = 8; ++ break; ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ case _SMS4_: ++ pattrib->iv_len = 18; ++ pattrib->icv_len = 16; ++ break; ++#endif ++ ++ default: ++ pattrib->iv_len = 0; ++ pattrib->icv_len = 0; ++ break; ++ } ++ ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ++ ("update_attrib: encrypt=%d securitypriv.sw_encrypt=%d\n", ++ pattrib->encrypt, padapter->securitypriv.sw_encrypt)); ++ ++ if (pattrib->encrypt && ++ ((padapter->securitypriv.sw_encrypt == _TRUE) || (psecuritypriv->hw_decrypted == _FALSE))) ++ { ++ pattrib->bswenc = _TRUE; ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_, ++ ("update_attrib: encrypt=%d securitypriv.hw_decrypted=%d bswenc=_TRUE\n", ++ pattrib->encrypt, padapter->securitypriv.sw_encrypt)); ++ } else { ++ pattrib->bswenc = _FALSE; ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("update_attrib: bswenc=_FALSE\n")); ++ } ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if((pattrib->encrypt && bmcast) || (pattrib->encrypt ==_WEP40_) || (pattrib->encrypt ==_WEP104_)) ++ { ++ pattrib->bswenc = _TRUE;//force using sw enc. ++ } ++#endif ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ if(pattrib->encrypt == _SMS4_) ++ pattrib->bswenc = _FALSE; ++#endif ++ ++ rtw_set_tx_chksum_offload(pkt, pattrib); ++ ++ update_attrib_phy_info(pattrib, psta); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++static s32 xmitframe_addmic(_adapter *padapter, struct xmit_frame *pxmitframe){ ++ sint curfragnum,length; ++ u8 *pframe, *payload,mic[8]; ++ struct mic_data micdata; ++ struct sta_info *stainfo; ++ struct qos_priv *pqospriv= &(padapter->mlmepriv.qospriv); ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct security_priv *psecuritypriv=&padapter->securitypriv; ++ struct xmit_priv *pxmitpriv=&padapter->xmitpriv; ++ u8 priority[4]={0x0,0x0,0x0,0x0}; ++ u8 hw_hdr_offset = 0; ++ sint bmcst = IS_MCAST(pattrib->ra); ++ ++ if(pattrib->psta) ++ { ++ stainfo = pattrib->psta; ++ } ++ else ++ { ++ DBG_871X("%s, call rtw_get_stainfo()\n", __func__); ++ stainfo=rtw_get_stainfo(&padapter->stapriv ,&pattrib->ra[0]); ++ } ++ ++ if(stainfo==NULL) ++ { ++ DBG_871X("%s, psta==NUL\n", __func__); ++ return _FAIL; ++ } ++ ++ if(!(stainfo->state &_FW_LINKED)) ++ { ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, stainfo->state); ++ return _FAIL; ++ } ++ ++_func_enter_; ++ ++#ifdef CONFIG_USB_TX_AGGREGATION ++ hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ);; ++#else ++ #ifdef CONFIG_TX_EARLY_MODE ++ hw_hdr_offset = TXDESC_OFFSET+ EARLY_MODE_INFO_SIZE; ++ #else ++ hw_hdr_offset = TXDESC_OFFSET; ++ #endif ++#endif ++ ++ if(pattrib->encrypt ==_TKIP_)//if(psecuritypriv->dot11PrivacyAlgrthm==_TKIP_PRIVACY_) ++ { ++ //encode mic code ++ if(stainfo!= NULL){ ++ u8 null_key[16]={0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}; ++ ++ pframe = pxmitframe->buf_addr + hw_hdr_offset; ++ ++ if(bmcst) ++ { ++ if(_rtw_memcmp(psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey, null_key, 16)==_TRUE){ ++ //DbgPrint("\nxmitframe_addmic:stainfo->dot11tkiptxmickey==0\n"); ++ //rtw_msleep_os(10); ++ return _FAIL; ++ } ++ //start to calculate the mic code ++ rtw_secmicsetkey(&micdata, psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey); ++ } ++ else ++ { ++ if(_rtw_memcmp(&stainfo->dot11tkiptxmickey.skey[0],null_key, 16)==_TRUE){ ++ //DbgPrint("\nxmitframe_addmic:stainfo->dot11tkiptxmickey==0\n"); ++ //rtw_msleep_os(10); ++ return _FAIL; ++ } ++ //start to calculate the mic code ++ rtw_secmicsetkey(&micdata, &stainfo->dot11tkiptxmickey.skey[0]); ++ } ++ ++ if(pframe[1]&1){ //ToDS==1 ++ rtw_secmicappend(&micdata, &pframe[16], 6); //DA ++ if(pframe[1]&2) //From Ds==1 ++ rtw_secmicappend(&micdata, &pframe[24], 6); ++ else ++ rtw_secmicappend(&micdata, &pframe[10], 6); ++ } ++ else{ //ToDS==0 ++ rtw_secmicappend(&micdata, &pframe[4], 6); //DA ++ if(pframe[1]&2) //From Ds==1 ++ rtw_secmicappend(&micdata, &pframe[16], 6); ++ else ++ rtw_secmicappend(&micdata, &pframe[10], 6); ++ ++ } ++ ++ //if(pqospriv->qos_option==1) ++ if(pattrib->qos_en) ++ priority[0]=(u8)pxmitframe->attrib.priority; ++ ++ ++ rtw_secmicappend(&micdata, &priority[0], 4); ++ ++ payload=pframe; ++ ++ for(curfragnum=0;curfragnumnr_frags;curfragnum++){ ++ payload=(u8 *)RND4((SIZE_PTR)(payload)); ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("===curfragnum=%d, pframe= 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x,!!!\n", ++ curfragnum,*payload, *(payload+1),*(payload+2),*(payload+3),*(payload+4),*(payload+5),*(payload+6),*(payload+7))); ++ ++ payload=payload+pattrib->hdrlen+pattrib->iv_len; ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("curfragnum=%d pattrib->hdrlen=%d pattrib->iv_len=%d",curfragnum,pattrib->hdrlen,pattrib->iv_len)); ++ if((curfragnum+1)==pattrib->nr_frags){ ++ length=pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-( (pattrib->bswenc) ? pattrib->icv_len : 0); ++ rtw_secmicappend(&micdata, payload,length); ++ payload=payload+length; ++ } ++ else{ ++ length=pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-( (pattrib->bswenc) ? pattrib->icv_len : 0); ++ rtw_secmicappend(&micdata, payload, length); ++ payload=payload+length+pattrib->icv_len; ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("curfragnum=%d length=%d pattrib->icv_len=%d",curfragnum,length,pattrib->icv_len)); ++ } ++ } ++ rtw_secgetmic(&micdata,&(mic[0])); ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("xmitframe_addmic: before add mic code!!!\n")); ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("xmitframe_addmic: pattrib->last_txcmdsz=%d!!!\n",pattrib->last_txcmdsz)); ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("xmitframe_addmic: mic[0]=0x%.2x ,mic[1]=0x%.2x ,mic[2]=0x%.2x ,mic[3]=0x%.2x \n\ ++ mic[4]=0x%.2x ,mic[5]=0x%.2x ,mic[6]=0x%.2x ,mic[7]=0x%.2x !!!!\n", ++ mic[0],mic[1],mic[2],mic[3],mic[4],mic[5],mic[6],mic[7])); ++ //add mic code and add the mic code length in last_txcmdsz ++ ++ _rtw_memcpy(payload, &(mic[0]),8); ++ pattrib->last_txcmdsz+=8; ++ ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("\n ========last pkt========\n")); ++ payload=payload-pattrib->last_txcmdsz+8; ++ for(curfragnum=0;curfragnumlast_txcmdsz;curfragnum=curfragnum+8) ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,(" %.2x, %.2x, %.2x, %.2x, %.2x, %.2x, %.2x, %.2x ", ++ *(payload+curfragnum), *(payload+curfragnum+1), *(payload+curfragnum+2),*(payload+curfragnum+3), ++ *(payload+curfragnum+4),*(payload+curfragnum+5),*(payload+curfragnum+6),*(payload+curfragnum+7))); ++ } ++ else{ ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("xmitframe_addmic: rtw_get_stainfo==NULL!!!\n")); ++ } ++ } ++ ++_func_exit_; ++ ++ return _SUCCESS; ++} ++ ++static s32 xmitframe_swencrypt(_adapter *padapter, struct xmit_frame *pxmitframe){ ++ ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ //struct security_priv *psecuritypriv=&padapter->securitypriv; ++ ++_func_enter_; ++ ++ //if((psecuritypriv->sw_encrypt)||(pattrib->bswenc)) ++ if(pattrib->bswenc) ++ { ++ //DBG_871X("start xmitframe_swencrypt\n"); ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_alert_,("### xmitframe_swencrypt\n")); ++ switch(pattrib->encrypt){ ++ case _WEP40_: ++ case _WEP104_: ++ rtw_wep_encrypt(padapter, (u8 *)pxmitframe); ++ break; ++ case _TKIP_: ++ rtw_tkip_encrypt(padapter, (u8 *)pxmitframe); ++ break; ++ case _AES_: ++ rtw_aes_encrypt(padapter, (u8 * )pxmitframe); ++ break; ++#ifdef CONFIG_WAPI_SUPPORT ++ case _SMS4_: ++ rtw_sms4_encrypt(padapter, (u8 * )pxmitframe); ++#endif ++ default: ++ break; ++ } ++ ++ } else { ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_notice_,("### xmitframe_hwencrypt\n")); ++ } ++ ++_func_exit_; ++ ++ return _SUCCESS; ++} ++ ++s32 rtw_make_wlanhdr (_adapter *padapter , u8 *hdr, struct pkt_attrib *pattrib) ++{ ++ u16 *qc; ++ ++ struct rtw_ieee80211_hdr *pwlanhdr = (struct rtw_ieee80211_hdr *)hdr; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct qos_priv *pqospriv = &pmlmepriv->qospriv; ++ u8 qos_option = _FALSE; ++#ifdef CONFIG_TDLS ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *ptdls_sta=NULL, *psta_backup=NULL; ++ u8 direct_link=0; ++#endif //CONFIG_TDLS ++ ++ sint res = _SUCCESS; ++ u16 *fctrl = &pwlanhdr->frame_ctl; ++ ++ struct sta_info *psta; ++ ++ sint bmcst = IS_MCAST(pattrib->ra); ++ ++_func_enter_; ++ ++ if (pattrib->psta) { ++ psta = pattrib->psta; ++ } else { ++ DBG_871X("%s, call rtw_get_stainfo()\n", __func__); ++ if(bmcst) { ++ psta = rtw_get_bcmc_stainfo(padapter); ++ } else { ++ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); ++ } ++ } ++ ++ if(psta==NULL) ++ { ++ DBG_871X("%s, psta==NUL\n", __func__); ++ return _FAIL; ++ } ++ ++ if(!(psta->state &_FW_LINKED)) ++ { ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); ++ return _FAIL; ++ } ++ ++ _rtw_memset(hdr, 0, WLANHDR_OFFSET); ++ ++ SetFrameSubType(fctrl, pattrib->subtype); ++ ++ if (pattrib->subtype & WIFI_DATA_TYPE) ++ { ++ if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE)) { ++ //to_ds = 1, fr_ds = 0; ++#ifdef CONFIG_TDLS ++ if((ptdlsinfo->setup_state == TDLS_LINKED_STATE)){ ++ ptdls_sta = rtw_get_stainfo(pstapriv, pattrib->dst); ++ if((ptdls_sta!=NULL)&&(ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE)&&(pattrib->ether_type!=0x0806)){ ++ //TDLS data transfer, ToDS=0, FrDs=0 ++ _rtw_memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN); ++ direct_link=1; ++ }else{ ++ // 1.Data transfer to AP ++ // 2.Arp pkt will relayed by AP ++ SetToDs(fctrl); ++ _rtw_memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN); ++ } ++ }else ++#endif //CONFIG_TDLS ++ { ++ //Data transfer to AP ++ SetToDs(fctrl); ++ _rtw_memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN); ++ } ++ ++ if (pqospriv->qos_option) ++ qos_option = _TRUE; ++ ++ } ++ else if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ) { ++ //to_ds = 0, fr_ds = 1; ++ SetFrDs(fctrl); ++ _rtw_memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN); ++ ++ if(psta->qos_option) ++ qos_option = _TRUE; ++ } ++ else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE)) { ++ _rtw_memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN); ++ ++ if(psta->qos_option) ++ qos_option = _TRUE; ++ } ++ else { ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("fw_state:%x is not allowed to xmit frame\n", get_fwstate(pmlmepriv))); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ if(pattrib->mdata) ++ SetMData(fctrl); ++ ++ if (pattrib->encrypt) ++ SetPrivacy(fctrl); ++ ++ if (qos_option) ++ { ++ qc = (unsigned short *)(hdr + pattrib->hdrlen - 2); ++ ++ if (pattrib->priority) ++ SetPriority(qc, pattrib->priority); ++ ++ SetEOSP(qc, pattrib->eosp); ++ ++ SetAckpolicy(qc, pattrib->ack_policy); ++ } ++ ++ //TODO: fill HT Control Field ++ ++ //Update Seq Num will be handled by f/w ++ { ++ if(psta){ ++#ifdef CONFIG_TDLS ++ if(direct_link==1) ++ { ++ psta_backup = psta; ++ psta = ptdls_sta; ++ } ++#endif //CONFIG_TDLS ++ ++ psta->sta_xmitpriv.txseq_tid[pattrib->priority]++; ++ psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF; ++ ++ pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority]; ++ ++ SetSeqNum(hdr, pattrib->seqnum); ++ ++#ifdef CONFIG_80211N_HT ++ //check if enable ampdu ++ if(pattrib->ht_en && psta->htpriv.ampdu_enable) ++ { ++ if(psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority)) ++ pattrib->ampdu_en = _TRUE; ++ } ++ ++ //re-check if enable ampdu by BA_starting_seqctrl ++ if(pattrib->ampdu_en == _TRUE) ++ { ++ u16 tx_seq; ++ ++ tx_seq = psta->BA_starting_seqctrl[pattrib->priority & 0x0f]; ++ ++ //check BA_starting_seqctrl ++ if(SN_LESS(pattrib->seqnum, tx_seq)) ++ { ++ //DBG_871X("tx ampdu seqnum(%d) < tx_seq(%d)\n", pattrib->seqnum, tx_seq); ++ pattrib->ampdu_en = _FALSE;//AGG BK ++ } ++ else if(SN_EQUAL(pattrib->seqnum, tx_seq)) ++ { ++ psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq+1)&0xfff; ++ ++ pattrib->ampdu_en = _TRUE;//AGG EN ++ } ++ else ++ { ++ //DBG_871X("tx ampdu over run\n"); ++ psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum+1)&0xfff; ++ pattrib->ampdu_en = _TRUE;//AGG EN ++ } ++ ++ } ++#endif //CONFIG_80211N_HT ++#ifdef CONFIG_TDLS ++ if(direct_link==1) ++ { ++ if (pattrib->encrypt){ ++ pattrib->encrypt= _AES_; ++ pattrib->iv_len=8; ++ pattrib->icv_len=8; ++ } ++ ++ //qos_en, ht_en, init rate, ,bw, ch_offset, sgi ++ //pattrib->qos_en = ptdls_sta->qos_option; ++ ++ pattrib->raid = ptdls_sta->raid; ++#ifdef CONFIG_80211N_HT ++ pattrib->bwmode = ptdls_sta->htpriv.bwmode; ++ pattrib->ht_en = ptdls_sta->htpriv.ht_option; ++ pattrib->ch_offset = ptdls_sta->htpriv.ch_offset; ++ pattrib->sgi= ptdls_sta->htpriv.sgi; ++#endif //CONFIG_80211N_HT ++ pattrib->mac_id = ptdls_sta->mac_id; ++ ++ psta = psta_backup; ++ } ++#endif //CONFIG_TDLS ++ ++ } ++ } ++ ++ } ++ else ++ { ++ ++ } ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++s32 rtw_txframes_pending(_adapter *padapter) ++{ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ return ((_rtw_queue_empty(&pxmitpriv->be_pending) == _FALSE) || ++ (_rtw_queue_empty(&pxmitpriv->bk_pending) == _FALSE) || ++ (_rtw_queue_empty(&pxmitpriv->vi_pending) == _FALSE) || ++ (_rtw_queue_empty(&pxmitpriv->vo_pending) == _FALSE)); ++} ++ ++s32 rtw_txframes_sta_ac_pending(_adapter *padapter, struct pkt_attrib *pattrib) ++{ ++ struct sta_info *psta; ++ struct tx_servq *ptxservq; ++ int priority = pattrib->priority; ++ ++ if(pattrib->psta) ++ { ++ psta = pattrib->psta; ++ } ++ else ++ { ++ DBG_871X("%s, call rtw_get_stainfo()\n", __func__); ++ psta=rtw_get_stainfo(&padapter->stapriv ,&pattrib->ra[0]); ++ } ++ ++ if(psta==NULL) ++ { ++ DBG_871X("%s, psta==NUL\n", __func__); ++ return 0; ++ } ++ ++ if(!(psta->state &_FW_LINKED)) ++ { ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); ++ return 0; ++ } ++ ++ switch(priority) ++ { ++ case 1: ++ case 2: ++ ptxservq = &(psta->sta_xmitpriv.bk_q); ++ break; ++ case 4: ++ case 5: ++ ptxservq = &(psta->sta_xmitpriv.vi_q); ++ break; ++ case 6: ++ case 7: ++ ptxservq = &(psta->sta_xmitpriv.vo_q); ++ break; ++ case 0: ++ case 3: ++ default: ++ ptxservq = &(psta->sta_xmitpriv.be_q); ++ break; ++ ++ } ++ ++ return ptxservq->qcnt; ++} ++ ++#ifdef CONFIG_TDLS ++ ++int rtw_build_tdls_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe, u8 action) ++{ ++ int res=_SUCCESS; ++ ++ switch(action){ ++ case TDLS_SETUP_REQUEST: ++ rtw_build_tdls_setup_req_ies(padapter, pxmitframe, pframe); ++ break; ++ case TDLS_SETUP_RESPONSE: ++ rtw_build_tdls_setup_rsp_ies(padapter, pxmitframe, pframe); ++ break; ++ case TDLS_SETUP_CONFIRM: ++ rtw_build_tdls_setup_cfm_ies(padapter, pxmitframe, pframe); ++ break; ++ case TDLS_TEARDOWN: ++ rtw_build_tdls_teardown_ies(padapter, pxmitframe, pframe); ++ break; ++ case TDLS_DISCOVERY_REQUEST: ++ rtw_build_tdls_dis_req_ies(padapter, pxmitframe, pframe); ++ break; ++ case TDLS_PEER_TRAFFIC_INDICATION: ++ rtw_build_tdls_peer_traffic_indication_ies(padapter, pxmitframe, pframe); ++ break; ++ case TDLS_CHANNEL_SWITCH_REQUEST: ++ rtw_build_tdls_ch_switch_req_ies(padapter, pxmitframe, pframe); ++ break; ++ case TDLS_CHANNEL_SWITCH_RESPONSE: ++ rtw_build_tdls_ch_switch_rsp_ies(padapter, pxmitframe, pframe); ++ break; ++#ifdef CONFIG_WFD ++ case TUNNELED_PROBE_REQ: ++ rtw_build_tunneled_probe_req_ies(padapter, pxmitframe, pframe); ++ break; ++ case TUNNELED_PROBE_RSP: ++ rtw_build_tunneled_probe_rsp_ies(padapter, pxmitframe, pframe); ++ break; ++#endif //CONFIG_WFD ++ default: ++ res=_FAIL; ++ break; ++ } ++ ++ return res; ++} ++ ++s32 rtw_make_tdls_wlanhdr (_adapter *padapter , u8 *hdr, struct pkt_attrib *pattrib, u8 action) ++{ ++ u16 *qc; ++ struct rtw_ieee80211_hdr *pwlanhdr = (struct rtw_ieee80211_hdr *)hdr; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct qos_priv *pqospriv = &pmlmepriv->qospriv; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *psta=NULL, *ptdls_sta=NULL; ++ u8 tdls_seq=0, baddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; ++ ++ sint res = _SUCCESS; ++ u16 *fctrl = &pwlanhdr->frame_ctl; ++ ++_func_enter_; ++ ++ _rtw_memset(hdr, 0, WLANHDR_OFFSET); ++ ++ SetFrameSubType(fctrl, pattrib->subtype); ++ ++ switch(action){ ++ case TDLS_SETUP_REQUEST: ++ case TDLS_SETUP_RESPONSE: ++ case TDLS_SETUP_CONFIRM: ++ case TDLS_TEARDOWN: //directly to peer STA or via AP ++ case TDLS_PEER_TRAFFIC_INDICATION: ++ case TDLS_PEER_PSM_REQUEST: //directly to peer STA or via AP ++ case TUNNELED_PROBE_REQ: ++ case TUNNELED_PROBE_RSP: ++ SetToDs(fctrl); ++ _rtw_memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN); ++ break; ++ case TDLS_CHANNEL_SWITCH_REQUEST: ++ case TDLS_CHANNEL_SWITCH_RESPONSE: ++ case TDLS_PEER_PSM_RESPONSE: ++ case TDLS_PEER_TRAFFIC_RESPONSE: ++ _rtw_memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN); ++ tdls_seq=1; ++ break; ++ case TDLS_DISCOVERY_REQUEST: //unicast: directly to peer sta, Bcast: via AP ++ if(_rtw_memcmp(pattrib->dst, baddr, ETH_ALEN) ) ++ { ++ SetToDs(fctrl); ++ _rtw_memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN); ++ } ++ else ++ { ++ _rtw_memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN); ++ tdls_seq=1; ++ } ++ break; ++ } ++ ++ if (pattrib->encrypt) ++ SetPrivacy(fctrl); ++ ++ if (pqospriv->qos_option) ++ { ++ qc = (unsigned short *)(hdr + pattrib->hdrlen - 2); ++ if (pattrib->priority) ++ SetPriority(qc, pattrib->priority); ++ SetAckpolicy(qc, pattrib->ack_policy); ++ } ++ ++ psta = pattrib->psta; ++ ++ // 1. update seq_num per link by sta_info ++ // 2. rewrite encrypt to _AES_, also rewrite iv_len, icv_len ++ if(tdls_seq==1){ ++ ptdls_sta=rtw_get_stainfo(pstapriv, pattrib->dst); ++ if(ptdls_sta){ ++ ptdls_sta->sta_xmitpriv.txseq_tid[pattrib->priority]++; ++ ptdls_sta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF; ++ pattrib->seqnum = ptdls_sta->sta_xmitpriv.txseq_tid[pattrib->priority]; ++ SetSeqNum(hdr, pattrib->seqnum); ++ ++ if (pattrib->encrypt){ ++ pattrib->encrypt= _AES_; ++ pattrib->iv_len=8; ++ pattrib->icv_len=8; ++ } ++ }else{ ++ res=_FAIL; ++ goto exit; ++ } ++ }else if(psta){ ++ psta->sta_xmitpriv.txseq_tid[pattrib->priority]++; ++ psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF; ++ pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority]; ++ SetSeqNum(hdr, pattrib->seqnum); ++ } ++ ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++s32 rtw_xmit_tdls_coalesce(_adapter * padapter, struct xmit_frame * pxmitframe, u8 action) ++{ ++ s32 llc_sz; ++ ++ u8 *pframe, *mem_start; ++ ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ u8 *pbuf_start; ++ s32 bmcst = IS_MCAST(pattrib->ra); ++ s32 res = _SUCCESS; ++ ++_func_enter_; ++ ++ if (pattrib->psta) { ++ psta = pattrib->psta; ++ } else { ++ if(bmcst) { ++ psta = rtw_get_bcmc_stainfo(padapter); ++ } else { ++ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); ++ } ++ } ++ ++ if(psta==NULL) ++ return _FAIL; ++ ++ if (pxmitframe->buf_addr == NULL) ++ return _FAIL; ++ ++ pbuf_start = pxmitframe->buf_addr; ++ mem_start = pbuf_start + TXDESC_OFFSET; ++ ++ if (rtw_make_tdls_wlanhdr(padapter, mem_start, pattrib, action) == _FAIL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pframe = mem_start; ++ pframe += pattrib->hdrlen; ++ ++ //adding icv, if necessary... ++ if (pattrib->iv_len) ++ { ++ if (psta != NULL) ++ { ++ switch(pattrib->encrypt) ++ { ++ case _WEP40_: ++ case _WEP104_: ++ WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); ++ break; ++ case _TKIP_: ++ if(bmcst) ++ TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); ++ else ++ TKIP_IV(pattrib->iv, psta->dot11txpn, 0); ++ break; ++ case _AES_: ++ if(bmcst) ++ AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); ++ else ++ AES_IV(pattrib->iv, psta->dot11txpn, 0); ++ break; ++ } ++ } ++ ++ _rtw_memcpy(pframe, pattrib->iv, pattrib->iv_len); ++ pframe += pattrib->iv_len; ++ ++ } ++ ++ llc_sz = rtw_put_snap(pframe, pattrib->ether_type); ++ pframe += llc_sz; ++ ++ //pattrib->pktlen will be counted in rtw_build_tdls_ies ++ pattrib->pktlen = 0; ++ ++ rtw_build_tdls_ies(padapter, pxmitframe, pframe, action); ++ ++ if ((pattrib->icv_len >0 )&& (pattrib->bswenc)) { ++ pframe += pattrib->pktlen; ++ _rtw_memcpy(pframe, pattrib->icv, pattrib->icv_len); ++ pframe += pattrib->icv_len; ++ } ++ ++ pattrib->nr_frags = 1; ++ pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->iv_len + llc_sz + ++ ((pattrib->bswenc) ? pattrib->icv_len : 0) + pattrib->pktlen; ++ ++ if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) ++ { ++ goto exit; ++ } ++ ++ xmitframe_swencrypt(padapter, pxmitframe); ++ ++ update_attrib_vcs_info(padapter, pxmitframe); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++#endif //CONFIG_TDLS ++ ++/* ++ * Calculate wlan 802.11 packet MAX size from pkt_attrib ++ * This function doesn't consider fragment case ++ */ ++u32 rtw_calculate_wlan_pkt_size_by_attribue(struct pkt_attrib *pattrib) ++{ ++ u32 len = 0; ++ ++ len = pattrib->hdrlen + pattrib->iv_len; // WLAN Header and IV ++ len += SNAP_SIZE + sizeof(u16); // LLC ++ len += pattrib->pktlen; ++ if (pattrib->encrypt == _TKIP_) len += 8; // MIC ++ len += ((pattrib->bswenc) ? pattrib->icv_len : 0); // ICV ++ ++ return len; ++} ++ ++/* ++ ++This sub-routine will perform all the following: ++ ++1. remove 802.3 header. ++2. create wlan_header, based on the info in pxmitframe ++3. append sta's iv/ext-iv ++4. append LLC ++5. move frag chunk from pframe to pxmitframe->mem ++6. apply sw-encrypt, if necessary. ++ ++*/ ++s32 rtw_xmitframe_coalesce(_adapter *padapter, _pkt *pkt, struct xmit_frame *pxmitframe) ++{ ++ struct pkt_file pktfile; ++ ++ s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz; ++ ++ SIZE_PTR addr; ++ ++ u8 *pframe, *mem_start; ++ u8 hw_hdr_offset; ++ ++ struct sta_info *psta; ++ //struct sta_priv *pstapriv = &padapter->stapriv; ++ //struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ ++ u8 *pbuf_start; ++ ++ s32 bmcst = IS_MCAST(pattrib->ra); ++ s32 res = _SUCCESS; ++ ++_func_enter_; ++ ++ if (pattrib->psta) ++ { ++ psta = pattrib->psta; ++ } else ++ { ++ DBG_871X("%s, call rtw_get_stainfo()\n", __func__); ++ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); ++ } ++ ++ if(psta==NULL) ++ { ++ ++ DBG_871X("%s, psta==NUL\n", __func__); ++ return _FAIL; ++ } ++ ++ ++ if(!(psta->state &_FW_LINKED)) ++ { ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); ++ return _FAIL; ++ } ++ ++ if (pxmitframe->buf_addr == NULL){ ++ DBG_8192C("==> %s buf_addr==NULL \n",__FUNCTION__); ++ return _FAIL; ++ } ++ ++ pbuf_start = pxmitframe->buf_addr; ++ ++#ifdef CONFIG_USB_TX_AGGREGATION ++ hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ); ++#else ++ #ifdef CONFIG_TX_EARLY_MODE //for SDIO && Tx Agg ++ hw_hdr_offset = TXDESC_OFFSET + EARLY_MODE_INFO_SIZE; ++ #else ++ hw_hdr_offset = TXDESC_OFFSET; ++ #endif ++#endif ++ ++ mem_start = pbuf_start + hw_hdr_offset; ++ ++ if (rtw_make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n")); ++ DBG_8192C("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n"); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ _rtw_open_pktfile(pkt, &pktfile); ++ _rtw_pktfile_read(&pktfile, NULL, pattrib->pkt_hdrlen); ++ ++ frg_inx = 0; ++ frg_len = pxmitpriv->frag_len - 4;//2346-4 = 2342 ++ ++ while (1) ++ { ++ llc_sz = 0; ++ ++ mpdu_len = frg_len; ++ ++ pframe = mem_start; ++ ++ SetMFrag(mem_start); ++ ++ pframe += pattrib->hdrlen; ++ mpdu_len -= pattrib->hdrlen; ++ ++ //adding icv, if necessary... ++ if (pattrib->iv_len) ++ { ++ //if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) ++ // psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); ++ //else ++ // psta = rtw_get_stainfo(pstapriv, pattrib->ra); ++ ++ if (psta != NULL) ++ { ++ switch(pattrib->encrypt) ++ { ++ case _WEP40_: ++ case _WEP104_: ++ WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); ++ break; ++ case _TKIP_: ++ if(bmcst) ++ TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); ++ else ++ TKIP_IV(pattrib->iv, psta->dot11txpn, 0); ++ break; ++ case _AES_: ++ if(bmcst) ++ AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); ++ else ++ AES_IV(pattrib->iv, psta->dot11txpn, 0); ++ break; ++#ifdef CONFIG_WAPI_SUPPORT ++ case _SMS4_: ++ rtw_wapi_get_iv(padapter,pattrib->ra,pattrib->iv); ++ break; ++#endif ++ } ++ } ++ ++ _rtw_memcpy(pframe, pattrib->iv, pattrib->iv_len); ++ ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, ++ ("rtw_xmitframe_coalesce: keyid=%d pattrib->iv[3]=%.2x pframe=%.2x %.2x %.2x %.2x\n", ++ padapter->securitypriv.dot11PrivacyKeyIndex, pattrib->iv[3], *pframe, *(pframe+1), *(pframe+2), *(pframe+3))); ++ ++ pframe += pattrib->iv_len; ++ ++ mpdu_len -= pattrib->iv_len; ++ } ++ ++ if (frg_inx == 0) { ++ llc_sz = rtw_put_snap(pframe, pattrib->ether_type); ++ pframe += llc_sz; ++ mpdu_len -= llc_sz; ++ } ++ ++ if ((pattrib->icv_len >0) && (pattrib->bswenc)) { ++ mpdu_len -= pattrib->icv_len; ++ } ++ ++ ++ if (bmcst) { ++ // don't do fragment to broadcat/multicast packets ++ mem_sz = _rtw_pktfile_read(&pktfile, pframe, pattrib->pktlen); ++ } else { ++ mem_sz = _rtw_pktfile_read(&pktfile, pframe, mpdu_len); ++ } ++ ++ pframe += mem_sz; ++ ++ if ((pattrib->icv_len >0 )&& (pattrib->bswenc)) { ++ _rtw_memcpy(pframe, pattrib->icv, pattrib->icv_len); ++ pframe += pattrib->icv_len; ++ } ++ ++ frg_inx++; ++ ++ if (bmcst || (rtw_endofpktfile(&pktfile) == _TRUE)) ++ { ++ pattrib->nr_frags = frg_inx; ++ ++ pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->iv_len + ((pattrib->nr_frags==1)? llc_sz:0) + ++ ((pattrib->bswenc) ? pattrib->icv_len : 0) + mem_sz; ++ ++ ClearMFrag(mem_start); ++ ++ break; ++ } else { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: There're still something in packet!\n", __FUNCTION__)); ++ } ++ ++ addr = (SIZE_PTR)(pframe); ++ ++ mem_start = (unsigned char *)RND4(addr) + hw_hdr_offset; ++ _rtw_memcpy(mem_start, pbuf_start + hw_hdr_offset, pattrib->hdrlen); ++ ++ } ++ ++ if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) ++ { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic(padapter, pxmitframe)==_FAIL\n")); ++ DBG_8192C("xmitframe_addmic(padapter, pxmitframe)==_FAIL\n"); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ xmitframe_swencrypt(padapter, pxmitframe); ++ ++ if(bmcst == _FALSE) ++ update_attrib_vcs_info(padapter, pxmitframe); ++ else ++ pattrib->vcs_mode = NONE_VCS; ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++#ifdef CONFIG_IEEE80211W ++//broadcast or multicast management pkt use BIP, unicast management pkt use CCMP encryption ++s32 rtw_mgmt_xmitframe_coalesce(_adapter *padapter, _pkt *pkt, struct xmit_frame *pxmitframe) ++{ ++ struct pkt_file pktfile; ++ s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz; ++ SIZE_PTR addr; ++ u8 *pframe, *mem_start = NULL, *tmp_buf=NULL; ++ u8 hw_hdr_offset, subtype ; ++ struct sta_info *psta = NULL; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ u8 *pbuf_start; ++ s32 bmcst = IS_MCAST(pattrib->ra); ++ s32 res = _FAIL; ++ u8 *BIP_AAD; ++ u8 *MGMT_body=NULL; ++ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ u8 MME[_MME_IE_LENGTH_]; ++ ++ _irqL irqL; ++ u32 ori_len; ++ mem_start = pframe = (u8 *)(pxmitframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ tmp_buf = BIP_AAD; ++ ++_func_enter_; ++ ori_len = BIP_AAD_SIZE+pattrib->pktlen; ++ tmp_buf = BIP_AAD = rtw_zmalloc(ori_len); ++ subtype = GetFrameSubType(pframe); //bit(7)~bit(2) ++ ++ if(BIP_AAD == NULL) ++ return _FAIL; ++ ++ _enter_critical_bh(&padapter->security_key_mutex, &irqL); ++ ++ //only support station mode ++ if(!check_fwstate(pmlmepriv, WIFI_STATION_STATE) || !check_fwstate(pmlmepriv, _FW_LINKED)) ++ goto xmitframe_coalesce_success; ++ ++ //IGTK key is not install, it may not support 802.11w ++ if(padapter->securitypriv.binstallBIPkey != _TRUE) ++ { ++ DBG_871X("no instll BIP key\n"); ++ goto xmitframe_coalesce_success; ++ } ++ //station mode doesn't need TX BIP, just ready the code ++ if(bmcst) ++ { ++ int frame_body_len; ++ u8 mic[16]; ++ ++ _rtw_memset(MME, 0, 18); ++ ++ //other types doesn't need the BIP ++ if(GetFrameSubType(pframe) != WIFI_DEAUTH && GetFrameSubType(pframe) != WIFI_DISASSOC) ++ goto xmitframe_coalesce_fail; ++ ++ MGMT_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); ++ pframe += pattrib->pktlen; ++ ++ //octent 0 and 1 is key index ,BIP keyid is 4 or 5, LSB only need octent 0 ++ MME[0]=padapter->securitypriv.dot11wBIPKeyid; ++ //copy packet number ++ _rtw_memcpy(&MME[2], &pmlmeext->mgnt_80211w_IPN, 6); ++ //increase the packet number ++ pmlmeext->mgnt_80211w_IPN++; ++ ++ //add MME IE with MIC all zero, MME string doesn't include element id and length ++ pframe = rtw_set_ie(pframe, _MME_IE_ , 16 , MME, &(pattrib->pktlen)); ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ // total frame length - header length ++ frame_body_len = pattrib->pktlen - sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ //conscruct AAD, copy frame control field ++ _rtw_memcpy(BIP_AAD, &pwlanhdr->frame_ctl, 2); ++ ClearRetry(BIP_AAD); ++ ClearPwrMgt(BIP_AAD); ++ ClearMData(BIP_AAD); ++ //conscruct AAD, copy address 1 to address 3 ++ _rtw_memcpy(BIP_AAD+2, pwlanhdr->addr1, 18); ++ //copy management fram body ++ _rtw_memcpy(BIP_AAD+BIP_AAD_SIZE, MGMT_body, frame_body_len); ++ /*//dump total packet include MME with zero MIC ++ { ++ int i; ++ printk("Total packet: "); ++ for(i=0; i < BIP_AAD_SIZE+frame_body_len; i++) ++ printk(" %02x ", BIP_AAD[i]); ++ printk("\n"); ++ }*/ ++ //calculate mic ++ if(omac1_aes_128(padapter->securitypriv.dot11wBIPKey[padapter->securitypriv.dot11wBIPKeyid].skey ++ , BIP_AAD, BIP_AAD_SIZE+frame_body_len, mic)) ++ goto xmitframe_coalesce_fail; ++ ++ /*//dump calculated mic result ++ { ++ int i; ++ printk("Calculated mic result: "); ++ for(i=0; i<16; i++) ++ printk(" %02x ", mic[i]); ++ printk("\n"); ++ }*/ ++ //copy right BIP mic value, total is 128bits, we use the 0~63 bits ++ _rtw_memcpy(pframe-8, mic, 8); ++ /*/dump all packet after mic ok ++ { ++ int pp; ++ printk("pattrib->pktlen = %d \n", pattrib->pktlen); ++ for(pp=0;pp< pattrib->pktlen; pp++) ++ printk(" %02x ", mem_start[pp]); ++ printk("\n"); ++ }*/ ++ } ++ else //unicast mgmt frame TX ++ { ++ //start to encrypt mgmt frame ++ if(subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC || ++ subtype == WIFI_REASSOCREQ || subtype == WIFI_ACTION) ++ { ++ if (pattrib->psta) ++ psta = pattrib->psta; ++ else ++ { ++ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); ++ } ++ ++ if(psta==NULL) ++ { ++ ++ DBG_871X("%s, psta==NUL\n", __func__); ++ goto xmitframe_coalesce_fail; ++ } ++ ++ if(!(psta->state & _FW_LINKED) || pxmitframe->buf_addr==NULL) ++ { ++ DBG_871X("%s, not _FW_LINKED or addr null\n", __func__); ++ goto xmitframe_coalesce_fail; ++ } ++ ++ //DBG_871X("%s, action frame category=%d \n", __func__, pframe[WLAN_HDR_A3_LEN]); ++ //according 802.11-2012 standard, these five types are not robust types ++ if(subtype == WIFI_ACTION && ++ (pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_PUBLIC || ++ pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_HT || ++ pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_UNPROTECTED_WNM || ++ pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_SELF_PROTECTED || ++ pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_P2P)) ++ goto xmitframe_coalesce_fail; ++ /*//before encrypt dump the management packet content ++ { ++ int i; ++ printk("Management pkt: "); ++ for(i=0; ipktlen; i++) ++ printk(" %02x ", pframe[i]); ++ printk("=======\n"); ++ }*/ ++ ++ //bakeup original management packet ++ _rtw_memcpy(tmp_buf, pframe, pattrib->pktlen); ++ //move to data portion ++ pframe += pattrib->hdrlen; ++ ++ //802.11w unicast management packet must be _AES_ ++ pattrib->iv_len = 8; ++ //it's MIC of AES ++ pattrib->icv_len = 8; ++ ++ switch(pattrib->encrypt) ++ { ++ case _AES_: ++ //set AES IV header ++ AES_IV(pattrib->iv, psta->dot11wtxpn, 0); ++ break; ++ default: ++ goto xmitframe_coalesce_fail; ++ } ++ //insert iv header into management frame ++ _rtw_memcpy(pframe, pattrib->iv, pattrib->iv_len); ++ pframe += pattrib->iv_len; ++ //copy mgmt data portion after CCMP header ++ _rtw_memcpy(pframe, tmp_buf+pattrib->hdrlen, pattrib->pktlen-pattrib->hdrlen); ++ //move pframe to end of mgmt pkt ++ pframe += pattrib->pktlen-pattrib->hdrlen; ++ //add 8 bytes CCMP IV header to length ++ pattrib->pktlen += pattrib->iv_len; ++ /*//dump management packet include AES IV header ++ { ++ int i; ++ printk("Management pkt + IV: "); ++ //for(i=0; ipktlen; i++) ++ //printk(" %02x ", mem_start[i]); ++ printk("@@@@@@@@@@@@@\n"); ++ }*/ ++ ++ if ((pattrib->icv_len >0 )&& (pattrib->bswenc)) { ++ _rtw_memcpy(pframe, pattrib->icv, pattrib->icv_len); ++ pframe += pattrib->icv_len; ++ } ++ //add 8 bytes MIC ++ pattrib->pktlen += pattrib->icv_len; ++ //set final tx command size ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ //set protected bit must be beofre SW encrypt ++ SetPrivacy(mem_start); ++ /*//dump management packet include AES header ++ { ++ int i; ++ printk("prepare to enc Management pkt + IV: "); ++ for(i=0; ipktlen; i++) ++ printk(" %02x ", mem_start[i]); ++ printk("@@@@@@@@@@@@@\n"); ++ }*/ ++ //software encrypt ++ xmitframe_swencrypt(padapter, pxmitframe); ++ } ++ } ++ ++xmitframe_coalesce_success: ++ _exit_critical_bh(&padapter->security_key_mutex, &irqL); ++ rtw_mfree(BIP_AAD, ori_len); ++_func_exit_; ++ return _SUCCESS; ++ ++xmitframe_coalesce_fail: ++ _exit_critical_bh(&padapter->security_key_mutex, &irqL); ++ rtw_mfree(BIP_AAD, ori_len); ++_func_exit_; ++ ++ return _FAIL; ++} ++#endif //CONFIG_IEEE80211W ++ ++/* Logical Link Control(LLC) SubNetwork Attachment Point(SNAP) header ++ * IEEE LLC/SNAP header contains 8 octets ++ * First 3 octets comprise the LLC portion ++ * SNAP portion, 5 octets, is divided into two fields: ++ * Organizationally Unique Identifier(OUI), 3 octets, ++ * type, defined by that organization, 2 octets. ++ */ ++s32 rtw_put_snap(u8 *data, u16 h_proto) ++{ ++ struct ieee80211_snap_hdr *snap; ++ u8 *oui; ++ ++_func_enter_; ++ ++ snap = (struct ieee80211_snap_hdr *)data; ++ snap->dsap = 0xaa; ++ snap->ssap = 0xaa; ++ snap->ctrl = 0x03; ++ ++ if (h_proto == 0x8137 || h_proto == 0x80f3) ++ oui = P802_1H_OUI; ++ else ++ oui = RFC1042_OUI; ++ ++ snap->oui[0] = oui[0]; ++ snap->oui[1] = oui[1]; ++ snap->oui[2] = oui[2]; ++ ++ *(u16 *)(data + SNAP_SIZE) = htons(h_proto); ++ ++_func_exit_; ++ ++ return SNAP_SIZE + sizeof(u16); ++} ++ ++void rtw_update_protection(_adapter *padapter, u8 *ie, uint ie_len) ++{ ++ ++ uint protection; ++ u8 *perp; ++ sint erp_len; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ ++_func_enter_; ++ ++ switch(pxmitpriv->vcs_setting) ++ { ++ case DISABLE_VCS: ++ pxmitpriv->vcs = NONE_VCS; ++ break; ++ ++ case ENABLE_VCS: ++ break; ++ ++ case AUTO_VCS: ++ default: ++ perp = rtw_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len); ++ if(perp == NULL) ++ { ++ pxmitpriv->vcs = NONE_VCS; ++ } ++ else ++ { ++ protection = (*(perp + 2)) & BIT(1); ++ if (protection) ++ { ++ if(pregistrypriv->vcs_type == RTS_CTS) ++ pxmitpriv->vcs = RTS_CTS; ++ else ++ pxmitpriv->vcs = CTS_TO_SELF; ++ } ++ else ++ pxmitpriv->vcs = NONE_VCS; ++ } ++ ++ break; ++ ++ } ++ ++_func_exit_; ++ ++} ++ ++void rtw_count_tx_stats(PADAPTER padapter, struct xmit_frame *pxmitframe, int sz) ++{ ++ struct sta_info *psta = NULL; ++ struct stainfo_stats *pstats = NULL; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) ++ { ++ pxmitpriv->tx_bytes += sz; ++#if defined(CONFIG_USB_TX_AGGREGATION) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod += pxmitframe->agg_num; ++#else ++ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod++; ++#endif ++ ++ psta = pxmitframe->attrib.psta; ++ if (psta) ++ { ++ pstats = &psta->sta_stats; ++#if defined(CONFIG_USB_TX_AGGREGATION) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ pstats->tx_pkts += pxmitframe->agg_num; ++#else ++ pstats->tx_pkts++; ++#endif ++ pstats->tx_bytes += sz; ++ } ++ } ++} ++ ++struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv) ++{ ++ _irqL irqL; ++ struct xmit_buf *pxmitbuf = NULL; ++ _list *plist, *phead; ++ _queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; ++ ++_func_enter_; ++ ++ _enter_critical(&pfree_queue->lock, &irqL); ++ ++ if(_rtw_queue_empty(pfree_queue) == _TRUE) { ++ pxmitbuf = NULL; ++ } else { ++ ++ phead = get_list_head(pfree_queue); ++ ++ plist = get_next(phead); ++ ++ pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); ++ ++ rtw_list_delete(&(pxmitbuf->list)); ++ } ++ ++ if (pxmitbuf != NULL) ++ { ++ pxmitpriv->free_xmit_extbuf_cnt--; ++ #ifdef DBG_XMIT_BUF_EXT ++ DBG_871X("DBG_XMIT_BUF_EXT ALLOC no=%d, free_xmit_extbuf_cnt=%d\n",pxmitbuf->no, pxmitpriv->free_xmit_extbuf_cnt); ++ #endif ++ ++ ++ pxmitbuf->priv_data = NULL; ++ //pxmitbuf->ext_tag = _TRUE; ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ pxmitbuf->len = 0; ++ pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; ++#endif ++#ifdef CONFIG_PCI_HCI ++ pxmitbuf->len = 0; ++#endif ++ ++ if (pxmitbuf->sctx) { ++ DBG_871X("%s pxmitbuf->sctx is not NULL\n", __func__); ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); ++ } ++ ++ } ++ ++ _exit_critical(&pfree_queue->lock, &irqL); ++ ++_func_exit_; ++ ++ return pxmitbuf; ++} ++ ++s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) ++{ ++ _irqL irqL; ++ _queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; ++ ++_func_enter_; ++ ++ if(pxmitbuf==NULL) ++ { ++ return _FAIL; ++ } ++ ++ _enter_critical(&pfree_queue->lock, &irqL); ++ ++ rtw_list_delete(&pxmitbuf->list); ++ ++ rtw_list_insert_tail(&(pxmitbuf->list), get_list_head(pfree_queue)); ++ pxmitpriv->free_xmit_extbuf_cnt++; ++ #ifdef DBG_XMIT_BUF_EXT ++ DBG_871X("DBG_XMIT_BUF_EXT FREE no=%d, free_xmit_extbuf_cnt=%d\n",pxmitbuf->no ,pxmitpriv->free_xmit_extbuf_cnt); ++ #endif ++ ++ _exit_critical(&pfree_queue->lock, &irqL); ++ ++_func_exit_; ++ ++ return _SUCCESS; ++} ++ ++struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv) ++{ ++ _irqL irqL; ++ struct xmit_buf *pxmitbuf = NULL; ++ _list *plist, *phead; ++ _queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; ++ ++_func_enter_; ++ ++ //DBG_871X("+rtw_alloc_xmitbuf\n"); ++ ++ _enter_critical(&pfree_xmitbuf_queue->lock, &irqL); ++ ++ if(_rtw_queue_empty(pfree_xmitbuf_queue) == _TRUE) { ++ pxmitbuf = NULL; ++ } else { ++ ++ phead = get_list_head(pfree_xmitbuf_queue); ++ ++ plist = get_next(phead); ++ ++ pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); ++ ++ rtw_list_delete(&(pxmitbuf->list)); ++ } ++ ++ if (pxmitbuf != NULL) ++ { ++ pxmitpriv->free_xmitbuf_cnt--; ++ #ifdef DBG_XMIT_BUF ++ DBG_871X("DBG_XMIT_BUF ALLOC no=%d, free_xmitbuf_cnt=%d\n",pxmitbuf->no, pxmitpriv->free_xmitbuf_cnt); ++ #endif ++ //DBG_871X("alloc, free_xmitbuf_cnt=%d\n", pxmitpriv->free_xmitbuf_cnt); ++ ++ pxmitbuf->priv_data = NULL; ++ //pxmitbuf->ext_tag = _FALSE; ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ pxmitbuf->len = 0; ++ pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; ++ pxmitbuf->agg_num = 0; ++ pxmitbuf->pg_num = 0; ++#endif ++#ifdef CONFIG_PCI_HCI ++ pxmitbuf->len = 0; ++#endif ++ ++ if (pxmitbuf->sctx) { ++ DBG_871X("%s pxmitbuf->sctx is not NULL\n", __func__); ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); ++ } ++ } ++ #ifdef DBG_XMIT_BUF ++ else ++ { ++ DBG_871X("DBG_XMIT_BUF rtw_alloc_xmitbuf return NULL\n"); ++ } ++ #endif ++ ++ _exit_critical(&pfree_xmitbuf_queue->lock, &irqL); ++ ++_func_exit_; ++ ++ return pxmitbuf; ++} ++ ++s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) ++{ ++ _irqL irqL; ++ _queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; ++ ++_func_enter_; ++ ++ //DBG_871X("+rtw_free_xmitbuf\n"); ++ ++ if(pxmitbuf==NULL) ++ { ++ return _FAIL; ++ } ++ ++ if (pxmitbuf->sctx) { ++ DBG_871X("%s pxmitbuf->sctx is not NULL\n", __func__); ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_FREE); ++ } ++ ++ if(pxmitbuf->ext_tag) ++ { ++ rtw_free_xmitbuf_ext(pxmitpriv, pxmitbuf); ++ } ++ else ++ { ++ _enter_critical(&pfree_xmitbuf_queue->lock, &irqL); ++ ++ rtw_list_delete(&pxmitbuf->list); ++ ++ rtw_list_insert_tail(&(pxmitbuf->list), get_list_head(pfree_xmitbuf_queue)); ++ ++ pxmitpriv->free_xmitbuf_cnt++; ++ //DBG_871X("FREE, free_xmitbuf_cnt=%d\n", pxmitpriv->free_xmitbuf_cnt); ++ #ifdef DBG_XMIT_BUF ++ DBG_871X("DBG_XMIT_BUF FREE no=%d, free_xmitbuf_cnt=%d\n",pxmitbuf->no ,pxmitpriv->free_xmitbuf_cnt); ++ #endif ++ _exit_critical(&pfree_xmitbuf_queue->lock, &irqL); ++ } ++ ++_func_exit_; ++ ++ return _SUCCESS; ++} ++ ++void rtw_init_xmitframe(struct xmit_frame *pxframe) ++{ ++ if (pxframe != NULL)//default value setting ++ { ++ pxframe->buf_addr = NULL; ++ pxframe->pxmitbuf = NULL; ++ ++ _rtw_memset(&pxframe->attrib, 0, sizeof(struct pkt_attrib)); ++ //pxframe->attrib.psta = NULL; ++ ++ pxframe->frame_tag = DATA_FRAMETAG; ++ ++#ifdef CONFIG_USB_HCI ++ pxframe->pkt = NULL; ++ pxframe->pkt_offset = 1;//default use pkt_offset to fill tx desc ++ ++#ifdef CONFIG_USB_TX_AGGREGATION ++ pxframe->agg_num = 1; ++#endif ++ ++#endif //#ifdef CONFIG_USB_HCI ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ pxframe->pg_num = 1; ++ pxframe->agg_num = 1; ++#endif ++ ++#ifdef CONFIG_XMIT_ACK ++ pxframe->ack_report = 0; ++#endif ++ ++ } ++} ++ ++/* ++Calling context: ++1. OS_TXENTRY ++2. RXENTRY (rx_thread or RX_ISR/RX_CallBack) ++ ++If we turn on USE_RXTHREAD, then, no need for critical section. ++Otherwise, we must use _enter/_exit critical to protect free_xmit_queue... ++ ++Must be very very cautious... ++ ++*/ ++struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)//(_queue *pfree_xmit_queue) ++{ ++ /* ++ Please remember to use all the osdep_service api, ++ and lock/unlock or _enter/_exit critical to protect ++ pfree_xmit_queue ++ */ ++ ++ _irqL irqL; ++ struct xmit_frame *pxframe = NULL; ++ _list *plist, *phead; ++ _queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; ++#ifdef PLATFORM_LINUX ++ _adapter *padapter = pxmitpriv->adapter; ++#endif //PLATFORM_LINUX ++ ++_func_enter_; ++ ++ _enter_critical_bh(&pfree_xmit_queue->lock, &irqL); ++ ++ if (_rtw_queue_empty(pfree_xmit_queue) == _TRUE) { ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("rtw_alloc_xmitframe:%d\n", pxmitpriv->free_xmitframe_cnt)); ++ pxframe = NULL; ++ } else { ++ phead = get_list_head(pfree_xmit_queue); ++ ++ plist = get_next(phead); ++ ++ pxframe = LIST_CONTAINOR(plist, struct xmit_frame, list); ++ ++ rtw_list_delete(&(pxframe->list)); ++ pxmitpriv->free_xmitframe_cnt--; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe():free_xmitframe_cnt=%d\n", pxmitpriv->free_xmitframe_cnt)); ++ } ++ ++ _exit_critical_bh(&pfree_xmit_queue->lock, &irqL); ++ ++ rtw_init_xmitframe(pxframe); ++ ++_func_exit_; ++ ++ return pxframe; ++} ++ ++struct xmit_frame *rtw_alloc_xmitframe_ext(struct xmit_priv *pxmitpriv) ++{ ++ _irqL irqL; ++ struct xmit_frame *pxframe = NULL; ++ _list *plist, *phead; ++ _queue *queue = &pxmitpriv->free_xframe_ext_queue; ++ ++_func_enter_; ++ ++ _enter_critical_bh(&queue->lock, &irqL); ++ ++ if (_rtw_queue_empty(queue) == _TRUE) { ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("rtw_alloc_xmitframe_ext:%d\n", pxmitpriv->free_xframe_ext_cnt)); ++ pxframe = NULL; ++ } else { ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ pxframe = LIST_CONTAINOR(plist, struct xmit_frame, list); ++ ++ rtw_list_delete(&(pxframe->list)); ++ pxmitpriv->free_xframe_ext_cnt--; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe_ext():free_xmitframe_cnt=%d\n", pxmitpriv->free_xframe_ext_cnt)); ++ } ++ ++ _exit_critical_bh(&queue->lock, &irqL); ++ ++ rtw_init_xmitframe(pxframe); ++ ++_func_exit_; ++ ++ return pxframe; ++} ++ ++struct xmit_frame *rtw_alloc_xmitframe_once(struct xmit_priv *pxmitpriv) ++{ ++ struct xmit_frame *pxframe = NULL; ++ u8 *alloc_addr; ++ ++ alloc_addr = rtw_zmalloc(sizeof(struct xmit_frame) + 4); ++ ++ if (alloc_addr == NULL) ++ goto exit; ++ ++ pxframe = (struct xmit_frame *)N_BYTE_ALIGMENT((SIZE_PTR)(alloc_addr), 4); ++ pxframe->alloc_addr = alloc_addr; ++ ++ pxframe->padapter = pxmitpriv->adapter; ++ pxframe->frame_tag = NULL_FRAMETAG; ++ ++ pxframe->pkt = NULL; ++ ++ pxframe->buf_addr = NULL; ++ pxframe->pxmitbuf = NULL; ++ ++ rtw_init_xmitframe(pxframe); ++ ++ DBG_871X("################## %s ##################\n", __func__); ++ ++exit: ++ return pxframe; ++} ++ ++s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitframe) ++{ ++ _irqL irqL; ++ _queue *queue; ++ _adapter *padapter = pxmitpriv->adapter; ++ _pkt *pndis_pkt = NULL; ++ ++_func_enter_; ++ ++ if (pxmitframe == NULL) { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("======rtw_free_xmitframe():pxmitframe==NULL!!!!!!!!!!\n")); ++ goto exit; ++ } ++ ++ if (pxmitframe->pkt){ ++ pndis_pkt = pxmitframe->pkt; ++ pxmitframe->pkt = NULL; ++ } ++ ++ if (pxmitframe->alloc_addr) { ++ DBG_871X("################## %s with alloc_addr ##################\n", __func__); ++ rtw_mfree(pxmitframe->alloc_addr, sizeof(struct xmit_frame) + 4); ++ goto check_pkt_complete; ++ } ++ ++ if (pxmitframe->ext_tag == 0) ++ queue = &pxmitpriv->free_xmit_queue; ++ else if(pxmitframe->ext_tag == 1) ++ queue = &pxmitpriv->free_xframe_ext_queue; ++ else ++ {} ++ ++ _enter_critical_bh(&queue->lock, &irqL); ++ ++ rtw_list_delete(&pxmitframe->list); ++ rtw_list_insert_tail(&pxmitframe->list, get_list_head(queue)); ++ if (pxmitframe->ext_tag == 0) { ++ pxmitpriv->free_xmitframe_cnt++; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe():free_xmitframe_cnt=%d\n", pxmitpriv->free_xmitframe_cnt)); ++ } else if(pxmitframe->ext_tag == 1) { ++ pxmitpriv->free_xframe_ext_cnt++; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe():free_xframe_ext_cnt=%d\n", pxmitpriv->free_xframe_ext_cnt)); ++ } else { ++ } ++ ++ _exit_critical_bh(&queue->lock, &irqL); ++ ++check_pkt_complete: ++ ++ if(pndis_pkt) ++ rtw_os_pkt_complete(padapter, pndis_pkt); ++ ++exit: ++ ++_func_exit_; ++ ++ return _SUCCESS; ++} ++ ++void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, _queue *pframequeue) ++{ ++ _irqL irqL; ++ _list *plist, *phead; ++ struct xmit_frame *pxmitframe; ++ ++_func_enter_; ++ ++ _enter_critical_bh(&(pframequeue->lock), &irqL); ++ ++ phead = get_list_head(pframequeue); ++ plist = get_next(phead); ++ ++ while (rtw_end_of_queue_search(phead, plist) == _FALSE) ++ { ++ ++ pxmitframe = LIST_CONTAINOR(plist, struct xmit_frame, list); ++ ++ plist = get_next(plist); ++ ++ rtw_free_xmitframe(pxmitpriv,pxmitframe); ++ ++ } ++ _exit_critical_bh(&(pframequeue->lock), &irqL); ++ ++_func_exit_; ++} ++ ++s32 rtw_xmitframe_enqueue(_adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL) ++ { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ++ ("rtw_xmitframe_enqueue: drop xmit pkt for classifier fail\n")); ++// pxmitframe->pkt = NULL; ++ return _FAIL; ++ } ++ ++ return _SUCCESS; ++} ++ ++static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit, struct tx_servq *ptxservq, _queue *pframe_queue) ++{ ++ _list *xmitframe_plist, *xmitframe_phead; ++ struct xmit_frame *pxmitframe=NULL; ++ ++ xmitframe_phead = get_list_head(pframe_queue); ++ xmitframe_plist = get_next(xmitframe_phead); ++ ++ while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) ++ { ++ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = get_next(xmitframe_plist); ++ ++/*#ifdef RTK_DMP_PLATFORM ++#ifdef CONFIG_USB_TX_AGGREGATION ++ if((ptxservq->qcnt>0) && (ptxservq->qcnt<=2)) ++ { ++ pxmitframe = NULL; ++ ++ tasklet_schedule(&pxmitpriv->xmit_tasklet); ++ ++ break; ++ } ++#endif ++#endif*/ ++ rtw_list_delete(&pxmitframe->list); ++ ++ ptxservq->qcnt--; ++ ++ //rtw_list_insert_tail(&pxmitframe->list, &phwxmit->pending); ++ ++ //ptxservq->qcnt--; ++ ++ break; ++ ++ pxmitframe = NULL; ++ ++ } ++ ++ return pxmitframe; ++} ++ ++struct xmit_frame* rtw_dequeue_xframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit_i, sint entry) ++{ ++ _irqL irqL0; ++ _list *sta_plist, *sta_phead; ++ struct hw_xmit *phwxmit; ++ struct tx_servq *ptxservq = NULL; ++ _queue *pframe_queue = NULL; ++ struct xmit_frame *pxmitframe = NULL; ++ _adapter *padapter = pxmitpriv->adapter; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ int i, inx[4]; ++#ifdef CONFIG_USB_HCI ++// int j, tmp, acirp_cnt[4]; ++#endif ++ ++_func_enter_; ++ ++ inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3; ++ ++ if(pregpriv->wifi_spec==1) ++ { ++ int j, tmp, acirp_cnt[4]; ++#if 0 ++ if(flagswmm_para_seq[j]; ++#endif ++ } ++ ++ _enter_critical_bh(&pxmitpriv->lock, &irqL0); ++ ++ for(i = 0; i < entry; i++) ++ { ++ phwxmit = phwxmit_i + inx[i]; ++ ++ //_enter_critical_ex(&phwxmit->sta_queue->lock, &irqL0); ++ ++ sta_phead = get_list_head(phwxmit->sta_queue); ++ sta_plist = get_next(sta_phead); ++ ++ while ((rtw_end_of_queue_search(sta_phead, sta_plist)) == _FALSE) ++ { ++ ++ ptxservq= LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending); ++ ++ pframe_queue = &ptxservq->sta_pending; ++ ++ pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit, ptxservq, pframe_queue); ++ ++ if(pxmitframe) ++ { ++ phwxmit->accnt--; ++ ++ //Remove sta node when there is no pending packets. ++ if(_rtw_queue_empty(pframe_queue)) //must be done after get_next and before break ++ rtw_list_delete(&ptxservq->tx_pending); ++ ++ //_exit_critical_ex(&phwxmit->sta_queue->lock, &irqL0); ++ ++ goto exit; ++ } ++ ++ sta_plist = get_next(sta_plist); ++ ++ } ++ ++ //_exit_critical_ex(&phwxmit->sta_queue->lock, &irqL0); ++ ++ } ++ ++exit: ++ ++ _exit_critical_bh(&pxmitpriv->lock, &irqL0); ++ ++_func_exit_; ++ ++ return pxmitframe; ++} ++ ++#if 1 ++struct tx_servq *rtw_get_sta_pending(_adapter *padapter, struct sta_info *psta, sint up, u8 *ac) ++{ ++ struct tx_servq *ptxservq=NULL; ++ ++_func_enter_; ++ ++ switch (up) ++ { ++ case 1: ++ case 2: ++ ptxservq = &(psta->sta_xmitpriv.bk_q); ++ *(ac) = 3; ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("rtw_get_sta_pending : BK \n")); ++ break; ++ ++ case 4: ++ case 5: ++ ptxservq = &(psta->sta_xmitpriv.vi_q); ++ *(ac) = 1; ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("rtw_get_sta_pending : VI\n")); ++ break; ++ ++ case 6: ++ case 7: ++ ptxservq = &(psta->sta_xmitpriv.vo_q); ++ *(ac) = 0; ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("rtw_get_sta_pending : VO \n")); ++ break; ++ ++ case 0: ++ case 3: ++ default: ++ ptxservq = &(psta->sta_xmitpriv.be_q); ++ *(ac) = 2; ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("rtw_get_sta_pending : BE \n")); ++ break; ++ ++ } ++ ++_func_exit_; ++ ++ return ptxservq; ++} ++#else ++__inline static struct tx_servq *rtw_get_sta_pending ++ (_adapter *padapter, _queue **ppstapending, struct sta_info *psta, sint up) ++{ ++ struct tx_servq *ptxservq; ++ struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; ++ ++_func_enter_; ++ ++#ifdef CONFIG_RTL8711 ++ ++ if(IS_MCAST(psta->hwaddr)) ++ { ++ ptxservq = &(psta->sta_xmitpriv.be_q); // we will use be_q to queue bc/mc frames in BCMC_stainfo ++ *ppstapending = &padapter->xmitpriv.bm_pending; ++ } ++ else ++#endif ++ { ++ switch (up) ++ { ++ case 1: ++ case 2: ++ ptxservq = &(psta->sta_xmitpriv.bk_q); ++ *ppstapending = &padapter->xmitpriv.bk_pending; ++ (phwxmits+3)->accnt++; ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("rtw_get_sta_pending : BK \n")); ++ break; ++ ++ case 4: ++ case 5: ++ ptxservq = &(psta->sta_xmitpriv.vi_q); ++ *ppstapending = &padapter->xmitpriv.vi_pending; ++ (phwxmits+1)->accnt++; ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("rtw_get_sta_pending : VI\n")); ++ break; ++ ++ case 6: ++ case 7: ++ ptxservq = &(psta->sta_xmitpriv.vo_q); ++ *ppstapending = &padapter->xmitpriv.vo_pending; ++ (phwxmits+0)->accnt++; ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("rtw_get_sta_pending : VO \n")); ++ break; ++ ++ case 0: ++ case 3: ++ default: ++ ptxservq = &(psta->sta_xmitpriv.be_q); ++ *ppstapending = &padapter->xmitpriv.be_pending; ++ (phwxmits+2)->accnt++; ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("rtw_get_sta_pending : BE \n")); ++ break; ++ ++ } ++ ++ } ++ ++_func_exit_; ++ ++ return ptxservq; ++} ++#endif ++ ++/* ++ * Will enqueue pxmitframe to the proper queue, ++ * and indicate it to xx_pending list..... ++ */ ++s32 rtw_xmit_classifier(_adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ //_irqL irqL0; ++ u8 ac_index; ++ struct sta_info *psta; ++ struct tx_servq *ptxservq; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; ++ sint res = _SUCCESS; ++ ++_func_enter_; ++ ++ if (pattrib->psta) { ++ psta = pattrib->psta; ++ } else { ++ DBG_871X("%s, call rtw_get_stainfo()\n", __func__); ++ psta = rtw_get_stainfo(pstapriv, pattrib->ra); ++ } ++ ++ if (psta == NULL) { ++ res = _FAIL; ++ DBG_8192C("rtw_xmit_classifier: psta == NULL\n"); ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("rtw_xmit_classifier: psta == NULL\n")); ++ goto exit; ++ } ++ ++ if(!(psta->state &_FW_LINKED)) ++ { ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); ++ return _FAIL; ++ } ++ ++ ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index)); ++ ++ //_enter_critical(&pstapending->lock, &irqL0); ++ ++ if (rtw_is_list_empty(&ptxservq->tx_pending)) { ++ rtw_list_insert_tail(&ptxservq->tx_pending, get_list_head(phwxmits[ac_index].sta_queue)); ++ } ++ ++ //_enter_critical(&ptxservq->sta_pending.lock, &irqL1); ++ ++ rtw_list_insert_tail(&pxmitframe->list, get_list_head(&ptxservq->sta_pending)); ++ ptxservq->qcnt++; ++ phwxmits[ac_index].accnt++; ++ ++ //_exit_critical(&ptxservq->sta_pending.lock, &irqL1); ++ ++ //_exit_critical(&pstapending->lock, &irqL0); ++ ++exit: ++ ++_func_exit_; ++ ++ return res; ++} ++ ++void rtw_alloc_hwxmits(_adapter *padapter) ++{ ++ struct hw_xmit *hwxmits; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ pxmitpriv->hwxmit_entry = HWXMIT_ENTRY; ++ ++ pxmitpriv->hwxmits = (struct hw_xmit *)rtw_zmalloc(sizeof (struct hw_xmit) * pxmitpriv->hwxmit_entry); ++ ++ hwxmits = pxmitpriv->hwxmits; ++ ++ if(pxmitpriv->hwxmit_entry == 5) ++ { ++ //pxmitpriv->bmc_txqueue.head = 0; ++ //hwxmits[0] .phwtxqueue = &pxmitpriv->bmc_txqueue; ++ hwxmits[0] .sta_queue = &pxmitpriv->bm_pending; ++ ++ //pxmitpriv->vo_txqueue.head = 0; ++ //hwxmits[1] .phwtxqueue = &pxmitpriv->vo_txqueue; ++ hwxmits[1] .sta_queue = &pxmitpriv->vo_pending; ++ ++ //pxmitpriv->vi_txqueue.head = 0; ++ //hwxmits[2] .phwtxqueue = &pxmitpriv->vi_txqueue; ++ hwxmits[2] .sta_queue = &pxmitpriv->vi_pending; ++ ++ //pxmitpriv->bk_txqueue.head = 0; ++ //hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; ++ hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; ++ ++ //pxmitpriv->be_txqueue.head = 0; ++ //hwxmits[4] .phwtxqueue = &pxmitpriv->be_txqueue; ++ hwxmits[4] .sta_queue = &pxmitpriv->be_pending; ++ ++ } ++ else if(pxmitpriv->hwxmit_entry == 4) ++ { ++ ++ //pxmitpriv->vo_txqueue.head = 0; ++ //hwxmits[0] .phwtxqueue = &pxmitpriv->vo_txqueue; ++ hwxmits[0] .sta_queue = &pxmitpriv->vo_pending; ++ ++ //pxmitpriv->vi_txqueue.head = 0; ++ //hwxmits[1] .phwtxqueue = &pxmitpriv->vi_txqueue; ++ hwxmits[1] .sta_queue = &pxmitpriv->vi_pending; ++ ++ //pxmitpriv->be_txqueue.head = 0; ++ //hwxmits[2] .phwtxqueue = &pxmitpriv->be_txqueue; ++ hwxmits[2] .sta_queue = &pxmitpriv->be_pending; ++ ++ //pxmitpriv->bk_txqueue.head = 0; ++ //hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; ++ hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; ++ } ++ else ++ { ++ ++ ++ } ++ ++ ++} ++ ++void rtw_free_hwxmits(_adapter *padapter) ++{ ++ struct hw_xmit *hwxmits; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ hwxmits = pxmitpriv->hwxmits; ++ if(hwxmits) ++ rtw_mfree((u8 *)hwxmits, (sizeof (struct hw_xmit) * pxmitpriv->hwxmit_entry)); ++} ++ ++void rtw_init_hwxmits(struct hw_xmit *phwxmit, sint entry) ++{ ++ sint i; ++_func_enter_; ++ for(i = 0; i < entry; i++, phwxmit++) ++ { ++ //_rtw_spinlock_init(&phwxmit->xmit_lock); ++ //_rtw_init_listhead(&phwxmit->pending); ++ //phwxmit->txcmdcnt = 0; ++ phwxmit->accnt = 0; ++ } ++_func_exit_; ++} ++ ++#ifdef CONFIG_BR_EXT ++int rtw_br_client_tx(_adapter *padapter, struct sk_buff **pskb) ++{ ++ struct sk_buff *skb = *pskb; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ _irqL irqL; ++ //if(check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) == _TRUE) ++ { ++ void dhcp_flag_bcast(_adapter *priv, struct sk_buff *skb); ++ int res, is_vlan_tag=0, i, do_nat25=1; ++ unsigned short vlan_hdr=0; ++ void *br_port = NULL; ++ ++ //mac_clone_handle_frame(priv, skb); ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ br_port = padapter->pnetdev->br_port; ++#else // (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ rcu_read_lock(); ++ br_port = rcu_dereference(padapter->pnetdev->rx_handler_data); ++ rcu_read_unlock(); ++#endif // (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ _enter_critical_bh(&padapter->br_ext_lock, &irqL); ++ if ( !(skb->data[0] & 1) && ++ br_port && ++ memcmp(skb->data+MACADDRLEN, padapter->br_mac, MACADDRLEN) && ++ *((unsigned short *)(skb->data+MACADDRLEN*2)) != __constant_htons(ETH_P_8021Q) && ++ *((unsigned short *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_IP) && ++ !memcmp(padapter->scdb_mac, skb->data+MACADDRLEN, MACADDRLEN) && padapter->scdb_entry) { ++ memcpy(skb->data+MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN); ++ padapter->scdb_entry->ageing_timer = jiffies; ++ _exit_critical_bh(&padapter->br_ext_lock, &irqL); ++ } ++ else ++ //if (!priv->pmib->ethBrExtInfo.nat25_disable) ++ { ++// if (priv->dev->br_port && ++// !memcmp(skb->data+MACADDRLEN, priv->br_mac, MACADDRLEN)) { ++#if 1 ++ if (*((unsigned short *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_8021Q)) { ++ is_vlan_tag = 1; ++ vlan_hdr = *((unsigned short *)(skb->data+MACADDRLEN*2+2)); ++ for (i=0; i<6; i++) ++ *((unsigned short *)(skb->data+MACADDRLEN*2+2-i*2)) = *((unsigned short *)(skb->data+MACADDRLEN*2-2-i*2)); ++ skb_pull(skb, 4); ++ } ++ //if SA == br_mac && skb== IP => copy SIP to br_ip ?? why ++ if (!memcmp(skb->data+MACADDRLEN, padapter->br_mac, MACADDRLEN) && ++ (*((unsigned short *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_IP))) ++ memcpy(padapter->br_ip, skb->data+WLAN_ETHHDR_LEN+12, 4); ++ ++ if (*((unsigned short *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_IP)) { ++ if (memcmp(padapter->scdb_mac, skb->data+MACADDRLEN, MACADDRLEN)) { ++ void *scdb_findEntry(_adapter *priv, unsigned char *macAddr, unsigned char *ipAddr); ++ ++ if ((padapter->scdb_entry = (struct nat25_network_db_entry *)scdb_findEntry(padapter, ++ skb->data+MACADDRLEN, skb->data+WLAN_ETHHDR_LEN+12)) != NULL) { ++ memcpy(padapter->scdb_mac, skb->data+MACADDRLEN, MACADDRLEN); ++ memcpy(padapter->scdb_ip, skb->data+WLAN_ETHHDR_LEN+12, 4); ++ padapter->scdb_entry->ageing_timer = jiffies; ++ do_nat25 = 0; ++ } ++ } ++ else { ++ if (padapter->scdb_entry) { ++ padapter->scdb_entry->ageing_timer = jiffies; ++ do_nat25 = 0; ++ } ++ else { ++ memset(padapter->scdb_mac, 0, MACADDRLEN); ++ memset(padapter->scdb_ip, 0, 4); ++ } ++ } ++ } ++ _exit_critical_bh(&padapter->br_ext_lock, &irqL); ++#endif // 1 ++ if (do_nat25) ++ { ++ int nat25_db_handle(_adapter *priv, struct sk_buff *skb, int method); ++ if (nat25_db_handle(padapter, skb, NAT25_CHECK) == 0) { ++ struct sk_buff *newskb; ++ ++ if (is_vlan_tag) { ++ skb_push(skb, 4); ++ for (i=0; i<6; i++) ++ *((unsigned short *)(skb->data+i*2)) = *((unsigned short *)(skb->data+4+i*2)); ++ *((unsigned short *)(skb->data+MACADDRLEN*2)) = __constant_htons(ETH_P_8021Q); ++ *((unsigned short *)(skb->data+MACADDRLEN*2+2)) = vlan_hdr; ++ } ++ ++ newskb = rtw_skb_copy(skb); ++ if (newskb == NULL) { ++ //priv->ext_stats.tx_drops++; ++ DEBUG_ERR("TX DROP: rtw_skb_copy fail!\n"); ++ //goto stop_proc; ++ return -1; ++ } ++ rtw_skb_free(skb); ++ ++ *pskb = skb = newskb; ++ if (is_vlan_tag) { ++ vlan_hdr = *((unsigned short *)(skb->data+MACADDRLEN*2+2)); ++ for (i=0; i<6; i++) ++ *((unsigned short *)(skb->data+MACADDRLEN*2+2-i*2)) = *((unsigned short *)(skb->data+MACADDRLEN*2-2-i*2)); ++ skb_pull(skb, 4); ++ } ++ } ++ ++ if (skb_is_nonlinear(skb)) ++ DEBUG_ERR("%s(): skb_is_nonlinear!!\n", __FUNCTION__); ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) ++ res = skb_linearize(skb, GFP_ATOMIC); ++#else // (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) ++ res = skb_linearize(skb); ++#endif // (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) ++ if (res < 0) { ++ DEBUG_ERR("TX DROP: skb_linearize fail!\n"); ++ //goto free_and_stop; ++ return -1; ++ } ++ ++ res = nat25_db_handle(padapter, skb, NAT25_INSERT); ++ if (res < 0) { ++ if (res == -2) { ++ //priv->ext_stats.tx_drops++; ++ DEBUG_ERR("TX DROP: nat25_db_handle fail!\n"); ++ //goto free_and_stop; ++ return -1; ++ ++ } ++ // we just print warning message and let it go ++ //DEBUG_WARN("%s()-%d: nat25_db_handle INSERT Warning!\n", __FUNCTION__, __LINE__); ++ //return -1; // return -1 will cause system crash on 2011/08/30! ++ return 0; ++ } ++ } ++ ++ memcpy(skb->data+MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN); ++ ++ dhcp_flag_bcast(padapter, skb); ++ ++ if (is_vlan_tag) { ++ skb_push(skb, 4); ++ for (i=0; i<6; i++) ++ *((unsigned short *)(skb->data+i*2)) = *((unsigned short *)(skb->data+4+i*2)); ++ *((unsigned short *)(skb->data+MACADDRLEN*2)) = __constant_htons(ETH_P_8021Q); ++ *((unsigned short *)(skb->data+MACADDRLEN*2+2)) = vlan_hdr; ++ } ++ } ++#if 0 ++ else{ ++ if (*((unsigned short *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_8021Q)) { ++ is_vlan_tag = 1; ++ } ++ ++ if(is_vlan_tag){ ++ if(ICMPV6_MCAST_MAC(skb->data) && ICMPV6_PROTO1A_VALN(skb->data)){ ++ memcpy(skb->data+MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN); ++ } ++ }else ++ { ++ if(ICMPV6_MCAST_MAC(skb->data) && ICMPV6_PROTO1A(skb->data)){ ++ memcpy(skb->data+MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN); ++ } ++ } ++ } ++#endif // 0 ++ ++ // check if SA is equal to our MAC ++ if (memcmp(skb->data+MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN)) { ++ //priv->ext_stats.tx_drops++; ++ DEBUG_ERR("TX DROP: untransformed frame SA:%02X%02X%02X%02X%02X%02X!\n", ++ skb->data[6],skb->data[7],skb->data[8],skb->data[9],skb->data[10],skb->data[11]); ++ //goto free_and_stop; ++ return -1; ++ } ++ } ++ return 0; ++} ++#endif // CONFIG_BR_EXT ++ ++u32 rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe) ++{ ++ u32 addr; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ ++ switch(pattrib->qsel) ++ { ++ case 0: ++ case 3: ++ addr = BE_QUEUE_INX; ++ break; ++ case 1: ++ case 2: ++ addr = BK_QUEUE_INX; ++ break; ++ case 4: ++ case 5: ++ addr = VI_QUEUE_INX; ++ break; ++ case 6: ++ case 7: ++ addr = VO_QUEUE_INX; ++ break; ++ case 0x10: ++ addr = BCN_QUEUE_INX; ++ break; ++ case 0x11://BC/MC in PS (HIQ) ++ addr = HIGH_QUEUE_INX; ++ break; ++ case 0x12: ++ default: ++ addr = MGT_QUEUE_INX; ++ break; ++ ++ } ++ ++ return addr; ++ ++} ++ ++static void do_queue_select(_adapter *padapter, struct pkt_attrib *pattrib) ++{ ++ u8 qsel; ++ ++ qsel = pattrib->priority; ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("### do_queue_select priority=%d ,qsel = %d\n",pattrib->priority ,qsel)); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++// if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE) ++// qsel = 7;// ++#endif ++ ++ pattrib->qsel = qsel; ++} ++ ++/* ++ * The main transmit(tx) entry ++ * ++ * Return ++ * 1 enqueue ++ * 0 success, hardware will handle this xmit frame(packet) ++ * <0 fail ++ */ ++s32 rtw_xmit(_adapter *padapter, _pkt **ppkt) ++{ ++ static u32 start = 0; ++ static u32 drop_cnt = 0; ++#ifdef CONFIG_AP_MODE ++ _irqL irqL0; ++#endif ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct xmit_frame *pxmitframe = NULL; ++#ifdef CONFIG_BR_EXT ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ void *br_port = NULL; ++#endif // CONFIG_BR_EXT ++ ++ s32 res; ++ ++ if (start == 0) ++ start = rtw_get_current_time(); ++ ++ pxmitframe = rtw_alloc_xmitframe(pxmitpriv); ++ ++ if (rtw_get_passing_time_ms(start) > 2000) { ++ if (drop_cnt) ++ DBG_871X("DBG_TX_DROP_FRAME %s no more pxmitframe, drop_cnt:%u\n", __FUNCTION__, drop_cnt); ++ start = rtw_get_current_time(); ++ drop_cnt = 0; ++ } ++ ++ if (pxmitframe == NULL) { ++ drop_cnt ++; ++ RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: no more pxmitframe\n")); ++ return -1; ++ } ++ ++#ifdef CONFIG_BR_EXT ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ br_port = padapter->pnetdev->br_port; ++#else // (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ rcu_read_lock(); ++ br_port = rcu_dereference(padapter->pnetdev->rx_handler_data); ++ rcu_read_unlock(); ++#endif // (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ ++ if( br_port && check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) == _TRUE) ++ { ++ res = rtw_br_client_tx(padapter, ppkt); ++ if (res == -1) ++ { ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ return -1; ++ } ++ } ++ ++#endif // CONFIG_BR_EXT ++ ++ res = update_attrib(padapter, *ppkt, &pxmitframe->attrib); ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ if(pxmitframe->attrib.ether_type != 0x88B4) ++ { ++ if(rtw_wapi_drop_for_key_absent(padapter, pxmitframe->attrib.ra)) ++ { ++ WAPI_TRACE(WAPI_RX,"drop for key absend when tx \n"); ++ res = _FAIL; ++ } ++ } ++#endif ++ if (res == _FAIL) { ++ RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: update attrib fail\n")); ++ #ifdef DBG_TX_DROP_FRAME ++ DBG_871X("DBG_TX_DROP_FRAME %s update attrib fail\n", __FUNCTION__); ++ #endif ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ return -1; ++ } ++ pxmitframe->pkt = *ppkt; ++ ++ rtw_led_control(padapter, LED_CTL_TX); ++ ++ do_queue_select(padapter, &pxmitframe->attrib); ++ ++#ifdef CONFIG_AP_MODE ++ _enter_critical_bh(&pxmitpriv->lock, &irqL0); ++ if(xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe) == _TRUE) ++ { ++ _exit_critical_bh(&pxmitpriv->lock, &irqL0); ++ return 1; ++ } ++ _exit_critical_bh(&pxmitpriv->lock, &irqL0); ++#endif ++ ++ if (rtw_hal_xmit(padapter, pxmitframe) == _FALSE) ++ return 1; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_TDLS ++sint xmitframe_enqueue_for_tdls_sleeping_sta(_adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ sint ret=_FALSE; ++ ++ _irqL irqL; ++ struct sta_info *ptdls_sta=NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ int i; ++ ++ ptdls_sta=rtw_get_stainfo(pstapriv, pattrib->dst); ++ if(ptdls_sta==NULL){ ++ return ret; ++ }else if(ptdls_sta->tdls_sta_state&TDLS_LINKED_STATE){ ++ ++ if(pattrib->triggered==1) ++ { ++ ret = _TRUE; ++ return ret; ++ } ++ ++ _enter_critical_bh(&ptdls_sta->sleep_q.lock, &irqL); ++ ++ if(ptdls_sta->state&WIFI_SLEEP_STATE) ++ { ++ rtw_list_delete(&pxmitframe->list); ++ ++ //_enter_critical_bh(&psta->sleep_q.lock, &irqL); ++ ++ rtw_list_insert_tail(&pxmitframe->list, get_list_head(&ptdls_sta->sleep_q)); ++ ++ ptdls_sta->sleepq_len++; ++ ptdls_sta->sleepq_ac_len++; ++ ++ //indicate 4-AC queue bit in TDLS peer traffic indication ++ switch(pattrib->priority) ++ { ++ case 1: ++ case 2: ++ ptdls_sta->uapsd_bk = ptdls_sta->uapsd_bk | BIT(1); ++ break; ++ case 4: ++ case 5: ++ ptdls_sta->uapsd_vi = ptdls_sta->uapsd_vi | BIT(1); ++ break; ++ case 6: ++ case 7: ++ ptdls_sta->uapsd_vo = ptdls_sta->uapsd_vo | BIT(1); ++ break; ++ case 0: ++ case 3: ++ default: ++ ptdls_sta->uapsd_be = ptdls_sta->uapsd_be | BIT(1); ++ break; ++ } ++ ++ if(ptdls_sta->sleepq_len==1) ++ { ++ //transmit TDLS PTI via AP ++ rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_SD_PTI); ++ } ++ ret = _TRUE; ++ ++ } ++ ++ _exit_critical_bh(&ptdls_sta->sleep_q.lock, &irqL); ++ } ++ ++ return ret; ++ ++} ++#endif //CONFIG_TDLS ++ ++#if defined(CONFIG_AP_MODE) || defined(CONFIG_TDLS) ++ ++sint xmitframe_enqueue_for_sleeping_sta(_adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ _irqL irqL; ++ sint ret=_FALSE; ++ struct sta_info *psta=NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ sint bmcst = IS_MCAST(pattrib->ra); ++#ifdef CONFIG_TDLS ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ ++ if( ptdlsinfo->setup_state == TDLS_LINKED_STATE ) ++ { ++ ret = xmitframe_enqueue_for_tdls_sleeping_sta(padapter, pxmitframe); ++ return ret; ++ } ++#endif //CONFIG_TDLS ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _FALSE) ++ return ret; ++ ++ if(pattrib->psta) ++ { ++ psta = pattrib->psta; ++ } ++ else ++ { ++ DBG_871X("%s, call rtw_get_stainfo()\n", __func__); ++ psta=rtw_get_stainfo(pstapriv, pattrib->ra); ++ } ++ ++ if(psta==NULL) ++ { ++ DBG_871X("%s, psta==NUL\n", __func__); ++ return _FALSE; ++ } ++ ++ if(!(psta->state &_FW_LINKED)) ++ { ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); ++ return _FALSE; ++ } ++ ++ if(pattrib->triggered==1) ++ { ++ //DBG_871X("directly xmit pspoll_triggered packet\n"); ++ ++ //pattrib->triggered=0; ++ ++ if(bmcst) ++ pattrib->qsel = 0x11;//HIQ ++ ++ ++ return ret; ++ } ++ ++ ++ if(bmcst) ++ { ++ _enter_critical_bh(&psta->sleep_q.lock, &irqL); ++ ++ if(pstapriv->sta_dz_bitmap)//if anyone sta is in ps mode ++ { ++ //pattrib->qsel = 0x11;//HIQ ++ ++ rtw_list_delete(&pxmitframe->list); ++ ++ //_enter_critical_bh(&psta->sleep_q.lock, &irqL); ++ ++ rtw_list_insert_tail(&pxmitframe->list, get_list_head(&psta->sleep_q)); ++ ++ psta->sleepq_len++; ++ ++ pstapriv->tim_bitmap |= BIT(0);// ++ pstapriv->sta_dz_bitmap |= BIT(0); ++ ++ //DBG_871X("enqueue, sq_len=%d, tim=%x\n", psta->sleepq_len, pstapriv->tim_bitmap); ++ ++ update_beacon(padapter, _TIM_IE_, NULL, _FALSE);//tx bc/mc packets after upate bcn ++ ++ //_exit_critical_bh(&psta->sleep_q.lock, &irqL); ++ ++ ret = _TRUE; ++ ++ } ++ ++ _exit_critical_bh(&psta->sleep_q.lock, &irqL); ++ ++ return ret; ++ ++ } ++ ++ ++ _enter_critical_bh(&psta->sleep_q.lock, &irqL); ++ ++ if(psta->state&WIFI_SLEEP_STATE) ++ { ++ u8 wmmps_ac=0; ++ ++ if(pstapriv->sta_dz_bitmap&BIT(psta->aid)) ++ { ++ rtw_list_delete(&pxmitframe->list); ++ ++ //_enter_critical_bh(&psta->sleep_q.lock, &irqL); ++ ++ rtw_list_insert_tail(&pxmitframe->list, get_list_head(&psta->sleep_q)); ++ ++ psta->sleepq_len++; ++ ++ switch(pattrib->priority) ++ { ++ case 1: ++ case 2: ++ wmmps_ac = psta->uapsd_bk&BIT(0); ++ break; ++ case 4: ++ case 5: ++ wmmps_ac = psta->uapsd_vi&BIT(0); ++ break; ++ case 6: ++ case 7: ++ wmmps_ac = psta->uapsd_vo&BIT(0); ++ break; ++ case 0: ++ case 3: ++ default: ++ wmmps_ac = psta->uapsd_be&BIT(0); ++ break; ++ } ++ ++ if(wmmps_ac) ++ psta->sleepq_ac_len++; ++ ++ if(((psta->has_legacy_ac) && (!wmmps_ac)) ||((!psta->has_legacy_ac)&&(wmmps_ac))) ++ { ++ pstapriv->tim_bitmap |= BIT(psta->aid); ++ ++ //DBG_871X("enqueue, sq_len=%d, tim=%x\n", psta->sleepq_len, pstapriv->tim_bitmap); ++ ++ if(psta->sleepq_len==1) ++ { ++ //DBG_871X("sleepq_len==1, update BCNTIM\n"); ++ //upate BCN for TIM IE ++ update_beacon(padapter, _TIM_IE_, NULL, _FALSE); ++ } ++ } ++ ++ //_exit_critical_bh(&psta->sleep_q.lock, &irqL); ++ ++ //if(psta->sleepq_len > (NR_XMITFRAME>>3)) ++ //{ ++ // wakeup_sta_to_xmit(padapter, psta); ++ //} ++ ++ ret = _TRUE; ++ ++ } ++ ++ } ++ ++ _exit_critical_bh(&psta->sleep_q.lock, &irqL); ++ ++ return ret; ++ ++} ++ ++static void dequeue_xmitframes_to_sleeping_queue(_adapter *padapter, struct sta_info *psta, _queue *pframequeue) ++{ ++ sint ret; ++ _list *plist, *phead; ++ u8 ac_index; ++ struct tx_servq *ptxservq; ++ struct pkt_attrib *pattrib; ++ struct xmit_frame *pxmitframe; ++ struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; ++ ++ phead = get_list_head(pframequeue); ++ plist = get_next(phead); ++ ++ while (rtw_end_of_queue_search(phead, plist) == _FALSE) ++ { ++ pxmitframe = LIST_CONTAINOR(plist, struct xmit_frame, list); ++ ++ plist = get_next(plist); ++ ++ ret = xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe); ++ ++ if(_TRUE == ret) ++ { ++ pattrib = &pxmitframe->attrib; ++ ++ ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index)); ++ ++ ptxservq->qcnt--; ++ phwxmits[ac_index].accnt--; ++ } ++ else ++ { ++ //DBG_871X("xmitframe_enqueue_for_sleeping_sta return _FALSE\n"); ++ } ++ ++ } ++ ++} ++ ++void stop_sta_xmit(_adapter *padapter, struct sta_info *psta) ++{ ++ _irqL irqL0; ++ struct sta_info *psta_bmc; ++ struct sta_xmit_priv *pstaxmitpriv; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ pstaxmitpriv = &psta->sta_xmitpriv; ++ ++ //for BC/MC Frames ++ psta_bmc = rtw_get_bcmc_stainfo(padapter); ++ ++ ++ _enter_critical_bh(&pxmitpriv->lock, &irqL0); ++ ++ psta->state |= WIFI_SLEEP_STATE; ++ ++#ifdef CONFIG_TDLS ++ if( !(psta->tdls_sta_state & TDLS_LINKED_STATE) ) ++#endif //CONFIG_TDLS ++ pstapriv->sta_dz_bitmap |= BIT(psta->aid); ++ ++ ++ ++ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vo_q.sta_pending); ++ rtw_list_delete(&(pstaxmitpriv->vo_q.tx_pending)); ++ ++ ++ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vi_q.sta_pending); ++ rtw_list_delete(&(pstaxmitpriv->vi_q.tx_pending)); ++ ++ ++ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->be_q.sta_pending); ++ rtw_list_delete(&(pstaxmitpriv->be_q.tx_pending)); ++ ++ ++ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->bk_q.sta_pending); ++ rtw_list_delete(&(pstaxmitpriv->bk_q.tx_pending)); ++ ++#ifdef CONFIG_TDLS ++ if( !(psta->tdls_sta_state & TDLS_LINKED_STATE) ) ++ { ++ if( psta_bmc != NULL ) ++ { ++#endif //CONFIG_TDLS ++ ++ ++ //for BC/MC Frames ++ pstaxmitpriv = &psta_bmc->sta_xmitpriv; ++ dequeue_xmitframes_to_sleeping_queue(padapter, psta_bmc, &pstaxmitpriv->be_q.sta_pending); ++ rtw_list_delete(&(pstaxmitpriv->be_q.tx_pending)); ++ ++ ++#ifdef CONFIG_TDLS ++ } ++ } ++#endif //CONFIG_TDLS ++ _exit_critical_bh(&pxmitpriv->lock, &irqL0); ++ ++ ++} ++ ++void wakeup_sta_to_xmit(_adapter *padapter, struct sta_info *psta) ++{ ++ _irqL irqL; ++ u8 update_mask=0, wmmps_ac=0; ++ struct sta_info *psta_bmc; ++ _list *xmitframe_plist, *xmitframe_phead; ++ struct xmit_frame *pxmitframe=NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ psta_bmc = rtw_get_bcmc_stainfo(padapter); ++ ++ ++ //_enter_critical_bh(&psta->sleep_q.lock, &irqL); ++ _enter_critical_bh(&pxmitpriv->lock, &irqL); ++ ++ xmitframe_phead = get_list_head(&psta->sleep_q); ++ xmitframe_plist = get_next(xmitframe_phead); ++ ++ while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) ++ { ++ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = get_next(xmitframe_plist); ++ ++ rtw_list_delete(&pxmitframe->list); ++ ++ switch(pxmitframe->attrib.priority) ++ { ++ case 1: ++ case 2: ++ wmmps_ac = psta->uapsd_bk&BIT(1); ++ break; ++ case 4: ++ case 5: ++ wmmps_ac = psta->uapsd_vi&BIT(1); ++ break; ++ case 6: ++ case 7: ++ wmmps_ac = psta->uapsd_vo&BIT(1); ++ break; ++ case 0: ++ case 3: ++ default: ++ wmmps_ac = psta->uapsd_be&BIT(1); ++ break; ++ } ++ ++ psta->sleepq_len--; ++ if(psta->sleepq_len>0) ++ pxmitframe->attrib.mdata = 1; ++ else ++ pxmitframe->attrib.mdata = 0; ++ ++ if(wmmps_ac) ++ { ++ psta->sleepq_ac_len--; ++ if(psta->sleepq_ac_len>0) ++ { ++ pxmitframe->attrib.mdata = 1; ++ pxmitframe->attrib.eosp = 0; ++ } ++ else ++ { ++ pxmitframe->attrib.mdata = 0; ++ pxmitframe->attrib.eosp = 1; ++ } ++ } ++ ++ pxmitframe->attrib.triggered = 1; ++ ++/* ++ _exit_critical_bh(&psta->sleep_q.lock, &irqL); ++ if(rtw_hal_xmit(padapter, pxmitframe) == _TRUE) ++ { ++ rtw_os_xmit_complete(padapter, pxmitframe); ++ } ++ _enter_critical_bh(&psta->sleep_q.lock, &irqL); ++*/ ++ rtw_hal_xmitframe_enqueue(padapter, pxmitframe); ++ ++ ++ } ++ ++ //for BC/MC Frames ++ if(!psta_bmc) ++ goto _exit; ++ ++ if((pstapriv->sta_dz_bitmap&0xfffe) == 0x0)//no any sta in ps mode ++ { ++ xmitframe_phead = get_list_head(&psta_bmc->sleep_q); ++ xmitframe_plist = get_next(xmitframe_phead); ++ ++ while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) ++ { ++ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = get_next(xmitframe_plist); ++ ++ rtw_list_delete(&pxmitframe->list); ++ ++ psta_bmc->sleepq_len--; ++ if(psta_bmc->sleepq_len>0) ++ pxmitframe->attrib.mdata = 1; ++ else ++ pxmitframe->attrib.mdata = 0; ++ ++ ++ pxmitframe->attrib.triggered = 1; ++/* ++ _exit_critical_bh(&psta_bmc->sleep_q.lock, &irqL); ++ if(rtw_hal_xmit(padapter, pxmitframe) == _TRUE) ++ { ++ rtw_os_xmit_complete(padapter, pxmitframe); ++ } ++ _enter_critical_bh(&psta_bmc->sleep_q.lock, &irqL); ++ ++*/ ++ rtw_hal_xmitframe_enqueue(padapter, pxmitframe); ++ ++ } ++ ++ if(psta_bmc->sleepq_len==0) ++ { ++ pstapriv->tim_bitmap &= ~BIT(0); ++ pstapriv->sta_dz_bitmap &= ~BIT(0); ++ ++ //DBG_871X("wakeup to xmit, qlen==0, update_BCNTIM, tim=%x\n", pstapriv->tim_bitmap); ++ //upate BCN for TIM IE ++ //update_BCNTIM(padapter); ++ update_mask |= BIT(1); ++ } ++ ++ } ++ ++ if(psta->sleepq_len==0) ++ { ++#ifdef CONFIG_TDLS ++ if( psta->tdls_sta_state & TDLS_LINKED_STATE ) ++ { ++ if(psta->state&WIFI_SLEEP_STATE) ++ psta->state ^= WIFI_SLEEP_STATE; ++ ++ goto _exit; ++ } ++#endif //CONFIG_TDLS ++ pstapriv->tim_bitmap &= ~BIT(psta->aid); ++ ++ //DBG_871X("wakeup to xmit, qlen==0, update_BCNTIM, tim=%x\n", pstapriv->tim_bitmap); ++ //upate BCN for TIM IE ++ //update_BCNTIM(padapter); ++ update_mask = BIT(0); ++ ++ if(psta->state&WIFI_SLEEP_STATE) ++ psta->state ^= WIFI_SLEEP_STATE; ++ ++ if(psta->state & WIFI_STA_ALIVE_CHK_STATE) ++ { ++ psta->expire_to = pstapriv->expire_to; ++ psta->state ^= WIFI_STA_ALIVE_CHK_STATE; ++ } ++ ++ pstapriv->sta_dz_bitmap &= ~BIT(psta->aid); ++ } ++ ++_exit: ++ ++ //_exit_critical_bh(&psta_bmc->sleep_q.lock, &irqL); ++ _exit_critical_bh(&pxmitpriv->lock, &irqL); ++ ++ if(update_mask) ++ { ++ //update_BCNTIM(padapter); ++ //printk("%s => call update_beacon\n",__FUNCTION__); ++ update_beacon(padapter, _TIM_IE_, NULL, _FALSE); ++ } ++ ++} ++ ++void xmit_delivery_enabled_frames(_adapter *padapter, struct sta_info *psta) ++{ ++ _irqL irqL; ++ u8 wmmps_ac=0; ++ _list *xmitframe_plist, *xmitframe_phead; ++ struct xmit_frame *pxmitframe=NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ ++ //_enter_critical_bh(&psta->sleep_q.lock, &irqL); ++ _enter_critical_bh(&pxmitpriv->lock, &irqL); ++ ++ xmitframe_phead = get_list_head(&psta->sleep_q); ++ xmitframe_plist = get_next(xmitframe_phead); ++ ++ while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) ++ { ++ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = get_next(xmitframe_plist); ++ ++ switch(pxmitframe->attrib.priority) ++ { ++ case 1: ++ case 2: ++ wmmps_ac = psta->uapsd_bk&BIT(1); ++ break; ++ case 4: ++ case 5: ++ wmmps_ac = psta->uapsd_vi&BIT(1); ++ break; ++ case 6: ++ case 7: ++ wmmps_ac = psta->uapsd_vo&BIT(1); ++ break; ++ case 0: ++ case 3: ++ default: ++ wmmps_ac = psta->uapsd_be&BIT(1); ++ break; ++ } ++ ++ if(!wmmps_ac) ++ continue; ++ ++ rtw_list_delete(&pxmitframe->list); ++ ++ psta->sleepq_len--; ++ psta->sleepq_ac_len--; ++ ++ if(psta->sleepq_ac_len>0) ++ { ++ pxmitframe->attrib.mdata = 1; ++ pxmitframe->attrib.eosp = 0; ++ } ++ else ++ { ++ pxmitframe->attrib.mdata = 0; ++ pxmitframe->attrib.eosp = 1; ++ } ++ ++ pxmitframe->attrib.triggered = 1; ++ ++/* ++ if(rtw_hal_xmit(padapter, pxmitframe) == _TRUE) ++ { ++ rtw_os_xmit_complete(padapter, pxmitframe); ++ } ++*/ ++ rtw_hal_xmitframe_enqueue(padapter, pxmitframe); ++ ++ if((psta->sleepq_ac_len==0) && (!psta->has_legacy_ac) && (wmmps_ac)) ++ { ++#ifdef CONFIG_TDLS ++ if(psta->tdls_sta_state & TDLS_LINKED_STATE ) ++ { ++ //_exit_critical_bh(&psta->sleep_q.lock, &irqL); ++ _exit_critical_bh(&pxmitpriv->lock, &irqL); ++ return; ++ } ++#endif //CONFIG_TDLS ++ pstapriv->tim_bitmap &= ~BIT(psta->aid); ++ ++ //DBG_871X("wakeup to xmit, qlen==0, update_BCNTIM, tim=%x\n", pstapriv->tim_bitmap); ++ //upate BCN for TIM IE ++ //update_BCNTIM(padapter); ++ update_beacon(padapter, _TIM_IE_, NULL, _FALSE); ++ //update_mask = BIT(0); ++ } ++ ++ } ++ ++ //_exit_critical_bh(&psta->sleep_q.lock, &irqL); ++ _exit_critical_bh(&pxmitpriv->lock, &irqL); ++ ++} ++ ++#endif ++ ++#ifdef CONFIG_XMIT_THREAD_MODE ++void enqueue_pending_xmitbuf( ++ struct xmit_priv *pxmitpriv, ++ struct xmit_buf *pxmitbuf) ++{ ++ _irqL irql; ++ _queue *pqueue; ++ _adapter *pri_adapter = pxmitpriv->adapter; ++ ++ pqueue = &pxmitpriv->pending_xmitbuf_queue; ++ ++ _enter_critical_bh(&pqueue->lock, &irql); ++ rtw_list_delete(&pxmitbuf->list); ++ rtw_list_insert_tail(&pxmitbuf->list, get_list_head(pqueue)); ++ _exit_critical_bh(&pqueue->lock, &irql); ++ ++ ++ ++#if defined(CONFIG_SDIO_HCI) && defined(CONFIG_CONCURRENT_MODE) ++ if (pri_adapter->adapter_type > PRIMARY_ADAPTER) ++ pri_adapter = pri_adapter->pbuddy_adapter; ++#endif //SDIO_HCI + CONCURRENT ++ _rtw_up_sema(&(pri_adapter->xmitpriv.xmit_sema)); ++ ++} ++ ++struct xmit_buf* dequeue_pending_xmitbuf( ++ struct xmit_priv *pxmitpriv) ++{ ++ _irqL irql; ++ struct xmit_buf *pxmitbuf; ++ _queue *pqueue; ++ ++ ++ pxmitbuf = NULL; ++ pqueue = &pxmitpriv->pending_xmitbuf_queue; ++ ++ _enter_critical_bh(&pqueue->lock, &irql); ++ ++ if (_rtw_queue_empty(pqueue) == _FALSE) ++ { ++ _list *plist, *phead; ++ ++ phead = get_list_head(pqueue); ++ plist = get_next(phead); ++ pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); ++ rtw_list_delete(&pxmitbuf->list); ++ } ++ ++ _exit_critical_bh(&pqueue->lock, &irql); ++ ++ return pxmitbuf; ++} ++ ++struct xmit_buf* dequeue_pending_xmitbuf_under_survey( ++ struct xmit_priv *pxmitpriv) ++{ ++ _irqL irql; ++ struct xmit_buf *pxmitbuf; ++#ifdef CONFIG_USB_HCI ++ struct xmit_frame *pxmitframe; ++#endif ++ _queue *pqueue; ++ ++ ++ pxmitbuf = NULL; ++ pqueue = &pxmitpriv->pending_xmitbuf_queue; ++ ++ _enter_critical_bh(&pqueue->lock, &irql); ++ ++ if (_rtw_queue_empty(pqueue) == _FALSE) ++ { ++ _list *plist, *phead; ++ u8 type; ++ ++ phead = get_list_head(pqueue); ++ plist = phead; ++ do { ++ plist = get_next(plist); ++ if (plist == phead) break; ++ ++ pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); ++ ++#ifdef CONFIG_USB_HCI ++ pxmitframe = (struct xmit_frame*)pxmitbuf->priv_data; ++ if(pxmitframe) ++ { ++ type = GetFrameSubType(pxmitbuf->pbuf + TXDESC_SIZE + pxmitframe->pkt_offset * PACKET_OFFSET_SZ); ++ } ++ else ++ { ++ DBG_871X("%s, !!!ERROR!!! For USB, TODO ITEM \n", __FUNCTION__); ++ } ++#else ++ type = GetFrameSubType(pxmitbuf->pbuf + TXDESC_OFFSET); ++#endif ++ ++ if ((type == WIFI_PROBEREQ) || ++ (type == WIFI_DATA_NULL) || ++ (type == WIFI_QOS_DATA_NULL)) ++ { ++ rtw_list_delete(&pxmitbuf->list); ++ break; ++ } ++ pxmitbuf = NULL; ++ } while (1); ++ } ++ ++ _exit_critical_bh(&pqueue->lock, &irql); ++ ++ return pxmitbuf; ++} ++ ++sint check_pending_xmitbuf( ++ struct xmit_priv *pxmitpriv) ++{ ++ _queue *pqueue; ++ ++ pqueue = &pxmitpriv->pending_xmitbuf_queue; ++ ++ if(_rtw_queue_empty(pqueue) == _FALSE) ++ return _TRUE; ++ else ++ return _FALSE; ++} ++ ++thread_return rtw_xmit_thread(thread_context context) ++{ ++ s32 err; ++ PADAPTER padapter; ++ ++ ++ err = _SUCCESS; ++ padapter = (PADAPTER)context; ++ ++ thread_enter("RTW_XMIT_THREAD"); ++ ++ do { ++ err = rtw_hal_xmit_thread_handler(padapter); ++ flush_signals_thread(); ++ } while (_SUCCESS == err); ++ ++ _rtw_up_sema(&padapter->xmitpriv.terminate_xmitthread_sema); ++ ++ thread_exit(); ++} ++#endif ++ ++void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms) ++{ ++ sctx->timeout_ms = timeout_ms; ++ sctx->submit_time= rtw_get_current_time(); ++#ifdef PLATFORM_LINUX /* TODO: add condition wating interface for other os */ ++ init_completion(&sctx->done); ++#endif ++ sctx->status = RTW_SCTX_SUBMITTED; ++} ++ ++int rtw_sctx_wait(struct submit_ctx *sctx) ++{ ++ int ret = _FAIL; ++ unsigned long expire; ++ int status = 0; ++ ++#ifdef PLATFORM_LINUX ++ expire= sctx->timeout_ms ? msecs_to_jiffies(sctx->timeout_ms) : MAX_SCHEDULE_TIMEOUT; ++ if (!wait_for_completion_timeout(&sctx->done, expire)) { ++ /* timeout, do something?? */ ++ status = RTW_SCTX_DONE_TIMEOUT; ++ DBG_871X("%s timeout\n", __func__); ++ } else { ++ status = sctx->status; ++ } ++#endif ++ ++ if (status == RTW_SCTX_DONE_SUCCESS) { ++ ret = _SUCCESS; ++ } ++ ++ return ret; ++} ++ ++bool rtw_sctx_chk_waring_status(int status) ++{ ++ switch(status) { ++ case RTW_SCTX_DONE_UNKNOWN: ++ case RTW_SCTX_DONE_BUF_ALLOC: ++ case RTW_SCTX_DONE_BUF_FREE: ++ ++ case RTW_SCTX_DONE_DRV_STOP: ++ case RTW_SCTX_DONE_DEV_REMOVE: ++ return _TRUE; ++ default: ++ return _FALSE; ++ } ++} ++ ++void rtw_sctx_done_err(struct submit_ctx **sctx, int status) ++{ ++ if (*sctx) { ++ if (rtw_sctx_chk_waring_status(status)) ++ DBG_871X("%s status:%d\n", __func__, status); ++ (*sctx)->status = status; ++ #ifdef PLATFORM_LINUX ++ complete(&((*sctx)->done)); ++ #endif ++ *sctx = NULL; ++ } ++} ++ ++void rtw_sctx_done(struct submit_ctx **sctx) ++{ ++ rtw_sctx_done_err(sctx, RTW_SCTX_DONE_SUCCESS); ++} ++ ++#ifdef CONFIG_XMIT_ACK ++ ++#ifdef CONFIG_XMIT_ACK_POLLING ++s32 c2h_evt_hdl(_adapter *adapter, struct c2h_evt_hdr *c2h_evt, c2h_id_filter filter); ++ ++/** ++ * rtw_ack_tx_polling - ++ * @pxmitpriv: xmit_priv to address ack_tx_ops ++ * @timeout_ms: timeout msec ++ * ++ * Init ack_tx_ops and then do c2h_evt_hdl() and polling ack_tx_ops repeatedly ++ * till tx report or timeout ++ * Returns: _SUCCESS if TX report ok, _FAIL for others ++ */ ++int rtw_ack_tx_polling(struct xmit_priv *pxmitpriv, u32 timeout_ms) ++{ ++ int ret = _FAIL; ++ struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; ++ _adapter *adapter = container_of(pxmitpriv, _adapter, xmitpriv); ++ ++ pack_tx_ops->submit_time = rtw_get_current_time(); ++ pack_tx_ops->timeout_ms = timeout_ms; ++ pack_tx_ops->status = RTW_SCTX_SUBMITTED; ++ ++ do { ++ c2h_evt_hdl(adapter, NULL, rtw_hal_c2h_id_filter_ccx(adapter)); ++ if (pack_tx_ops->status != RTW_SCTX_SUBMITTED) ++ break; ++ ++ if (adapter->bDriverStopped) { ++ pack_tx_ops->status = RTW_SCTX_DONE_DRV_STOP; ++ break; ++ } ++ if (adapter->bSurpriseRemoved) { ++ pack_tx_ops->status = RTW_SCTX_DONE_DEV_REMOVE; ++ break; ++ } ++ ++ rtw_msleep_os(10); ++ } while (rtw_get_passing_time_ms(pack_tx_ops->submit_time) < timeout_ms); ++ ++ if (pack_tx_ops->status == RTW_SCTX_SUBMITTED) { ++ pack_tx_ops->status = RTW_SCTX_DONE_TIMEOUT; ++ DBG_871X("%s timeout\n", __func__); ++ } ++ ++ if (pack_tx_ops->status == RTW_SCTX_DONE_SUCCESS) ++ ret = _SUCCESS; ++ ++ return ret; ++} ++#endif ++ ++#ifdef CONFIG_DETECT_C2H_BY_POLLING ++s32 c2h_evt_hdl(_adapter *adapter, struct c2h_evt_hdr *c2h_evt, c2h_id_filter filter); ++#endif ++ ++int rtw_ack_tx_wait(struct xmit_priv *pxmitpriv, u32 timeout_ms) ++{ ++#ifdef CONFIG_DETECT_C2H_BY_POLLING ++ _adapter *adapter = container_of(pxmitpriv, _adapter, xmitpriv); ++ c2h_id_filter ccx_id_filter = rtw_hal_c2h_id_filter_ccx(adapter); ++ struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; ++ u8 check_c2hcmd; ++ u8 check_ccx; ++ int ret = _FAIL; ++ ++ pack_tx_ops->submit_time = rtw_get_current_time(); ++ pack_tx_ops->timeout_ms = timeout_ms; ++ pack_tx_ops->status = RTW_SCTX_SUBMITTED; ++ ++ do { ++ rtw_msleep_os(10); ++ //check_c2hcmd = rtw_read8(adapter, 0x1AF); ++ //check_ccx = rtw_read8(adapter, 0x1A0); ++ rtw_hal_get_hwreg(adapter, HW_VAR_C2HEVT_CLEAR, (u8 *)(&check_c2hcmd)); ++ rtw_hal_get_hwreg(adapter, HW_VAR_C2HEVT_MSG_NORMAL, (u8 *)(&check_ccx)); ++ ++ ++ if (check_c2hcmd != 0) ++ { ++ if (check_c2hcmd != 0xFF) ++ { ++ c2h_evt_clear(adapter); ++ } ++ else if (ccx_id_filter(check_ccx & 0x0F) == _TRUE) ++ { ++ c2h_evt_hdl(adapter, NULL, ccx_id_filter); ++ if (pack_tx_ops->status != RTW_SCTX_SUBMITTED) ++ break; ++ ++ if (adapter->bDriverStopped) { ++ pack_tx_ops->status = RTW_SCTX_DONE_DRV_STOP; ++ break; ++ } ++ if (adapter->bSurpriseRemoved) { ++ pack_tx_ops->status = RTW_SCTX_DONE_DEV_REMOVE; ++ break; ++ } ++ } ++ } ++ } while (rtw_get_passing_time_ms(pack_tx_ops->submit_time) < timeout_ms); ++ ++ if (pack_tx_ops->status == RTW_SCTX_SUBMITTED) { ++ pack_tx_ops->status = RTW_SCTX_DONE_TIMEOUT; ++ DBG_871X("%s timeout\n", __func__); ++ } ++ ++ if (pack_tx_ops->status == RTW_SCTX_DONE_SUCCESS) ++ ret = _SUCCESS; ++ ++ return ret; ++#else ++#ifdef CONFIG_XMIT_ACK_POLLING ++ return rtw_ack_tx_polling(pxmitpriv, timeout_ms); ++#else ++ struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; ++ ++ pack_tx_ops->submit_time = rtw_get_current_time(); ++ pack_tx_ops->timeout_ms = timeout_ms; ++ pack_tx_ops->status = RTW_SCTX_SUBMITTED; ++ ++ return rtw_sctx_wait(pack_tx_ops); ++#endif ++#endif ++} ++ ++void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status) ++{ ++ struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; ++ ++ if (pxmitpriv->ack_tx) { ++ rtw_sctx_done_err(&pack_tx_ops, status); ++ } else { ++ DBG_871X("%s ack_tx not set\n", __func__); ++ } ++} ++#endif //CONFIG_XMIT_ACK ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/HalPwrSeqCmd.c b/drivers/net/wireless/rtl818x/rtl8189/hal/HalPwrSeqCmd.c +new file mode 100644 +index 00000000..2948242c +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/HalPwrSeqCmd.c +@@ -0,0 +1,187 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++/*++ ++Copyright (c) Realtek Semiconductor Corp. All rights reserved. ++ ++Module Name: ++ HalPwrSeqCmd.c ++ ++Abstract: ++ Implement HW Power sequence configuration CMD handling routine for Realtek devices. ++ ++Major Change History: ++ When Who What ++ ---------- --------------- ------------------------------- ++ 2011-10-26 Lucas Modify to be compatible with SD4-CE driver. ++ 2011-07-07 Roger Create. ++ ++--*/ ++#include ++#ifdef CONFIG_SDIO_HCI ++#include ++#elif defined(CONFIG_GSPI_HCI) ++#include ++#endif ++ ++// ++// Description: ++// This routine deal with the Power Configuration CMDs parsing for RTL8723/RTL8188E Series IC. ++// ++// Assumption: ++// We should follow specific format which was released from HW SD. ++// ++// 2011.07.07, added by Roger. ++// ++u8 HalPwrSeqCmdParsing( ++ PADAPTER padapter, ++ u8 CutVersion, ++ u8 FabVersion, ++ u8 InterfaceType, ++ WLAN_PWR_CFG PwrSeqCmd[]) ++{ ++ WLAN_PWR_CFG PwrCfgCmd = {0}; ++ u8 bPollingBit = _FALSE; ++ u32 AryIdx = 0; ++ u8 value = 0; ++ u32 offset = 0; ++ u32 pollingCount = 0; // polling autoload done. ++ u32 maxPollingCnt = 5000; ++ ++ do { ++ PwrCfgCmd = PwrSeqCmd[AryIdx]; ++ ++ RT_TRACE(_module_hal_init_c_ , _drv_info_, ++ ("HalPwrSeqCmdParsing: offset(%#x) cut_msk(%#x) fab_msk(%#x) interface_msk(%#x) base(%#x) cmd(%#x) msk(%#x) value(%#x)\n", ++ GET_PWR_CFG_OFFSET(PwrCfgCmd), ++ GET_PWR_CFG_CUT_MASK(PwrCfgCmd), ++ GET_PWR_CFG_FAB_MASK(PwrCfgCmd), ++ GET_PWR_CFG_INTF_MASK(PwrCfgCmd), ++ GET_PWR_CFG_BASE(PwrCfgCmd), ++ GET_PWR_CFG_CMD(PwrCfgCmd), ++ GET_PWR_CFG_MASK(PwrCfgCmd), ++ GET_PWR_CFG_VALUE(PwrCfgCmd))); ++ ++ //2 Only Handle the command whose FAB, CUT, and Interface are matched ++ if ((GET_PWR_CFG_FAB_MASK(PwrCfgCmd) & FabVersion) && ++ (GET_PWR_CFG_CUT_MASK(PwrCfgCmd) & CutVersion) && ++ (GET_PWR_CFG_INTF_MASK(PwrCfgCmd) & InterfaceType)) ++ { ++ switch (GET_PWR_CFG_CMD(PwrCfgCmd)) ++ { ++ case PWR_CMD_READ: ++ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_READ\n")); ++ break; ++ ++ case PWR_CMD_WRITE: ++ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_WRITE\n")); ++ offset = GET_PWR_CFG_OFFSET(PwrCfgCmd); ++ ++#ifdef CONFIG_SDIO_HCI ++ // ++ // We should deal with interface specific address mapping for some interfaces, e.g., SDIO interface ++ // 2011.07.07. ++ // ++ if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) ++ { ++ // Read Back SDIO Local value ++ value = SdioLocalCmd52Read1Byte(padapter, offset); ++ ++ value &= ~(GET_PWR_CFG_MASK(PwrCfgCmd)); ++ value |= (GET_PWR_CFG_VALUE(PwrCfgCmd) & GET_PWR_CFG_MASK(PwrCfgCmd)); ++ ++ // Write Back SDIO Local value ++ SdioLocalCmd52Write1Byte(padapter, offset, value); ++ } ++ else ++#endif ++ { ++#ifdef CONFIG_GSPI_HCI ++ if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) ++ offset = SPI_LOCAL_OFFSET | offset; ++#endif ++ // Read the value from system register ++ value = rtw_read8(padapter, offset); ++ ++ value &= ~(GET_PWR_CFG_MASK(PwrCfgCmd)); ++ value |= (GET_PWR_CFG_VALUE(PwrCfgCmd) & GET_PWR_CFG_MASK(PwrCfgCmd)); ++ ++ // Write the value back to sytem register ++ rtw_write8(padapter, offset, value); ++ } ++ break; ++ ++ case PWR_CMD_POLLING: ++ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_POLLING\n")); ++ ++ bPollingBit = _FALSE; ++ offset = GET_PWR_CFG_OFFSET(PwrCfgCmd); ++#ifdef CONFIG_GSPI_HCI ++ if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) ++ offset = SPI_LOCAL_OFFSET | offset; ++#endif ++ do { ++#ifdef CONFIG_SDIO_HCI ++ if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) ++ value = SdioLocalCmd52Read1Byte(padapter, offset); ++ else ++#endif ++ value = rtw_read8(padapter, offset); ++ ++ value &= GET_PWR_CFG_MASK(PwrCfgCmd); ++ if (value == (GET_PWR_CFG_VALUE(PwrCfgCmd) & GET_PWR_CFG_MASK(PwrCfgCmd))) ++ bPollingBit = _TRUE; ++ else ++ rtw_udelay_os(10); ++ ++ if (pollingCount++ > maxPollingCnt) { ++ DBG_871X("Fail to polling Offset[%#x]\n", offset); ++ return _FALSE; ++ } ++ } while (!bPollingBit); ++ ++ break; ++ ++ case PWR_CMD_DELAY: ++ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_DELAY\n")); ++ if (GET_PWR_CFG_VALUE(PwrCfgCmd) == PWRSEQ_DELAY_US) ++ rtw_udelay_os(GET_PWR_CFG_OFFSET(PwrCfgCmd)); ++ else ++ rtw_udelay_os(GET_PWR_CFG_OFFSET(PwrCfgCmd)*1000); ++ break; ++ ++ case PWR_CMD_END: ++ // When this command is parsed, end the process ++ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_END\n")); ++ return _TRUE; ++ break; ++ ++ default: ++ RT_TRACE(_module_hal_init_c_ , _drv_err_, ("HalPwrSeqCmdParsing: Unknown CMD!!\n")); ++ break; ++ } ++ } ++ ++ AryIdx++;//Add Array Index ++ }while(1); ++ ++ return _TRUE; ++} ++ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/HalPhyRf.c b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/HalPhyRf.c +new file mode 100644 +index 00000000..ceed28c7 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/HalPhyRf.c +@@ -0,0 +1,1561 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++ #include "odm_precomp.h" ++ ++#if(DM_ODM_SUPPORT_TYPE & ODM_MP) ++#include "Mp_Precomp.h" ++ ++VOID ++phy_PathAStandBy( ++ IN PADAPTER pAdapter ++ ) ++{ ++ RTPRINT(FINIT, INIT_IQK, ("Path-A standby mode!\n")); ++ ++ PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0x0); ++ PHY_SetBBReg(pAdapter, 0x840, bMaskDWord, 0x00010000); ++ PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0x80800000); ++} ++ ++//1 7. IQK ++//#define MAX_TOLERANCE 5 ++//#define IQK_DELAY_TIME 1 //ms ++ ++u1Byte //bit0 = 1 => Tx OK, bit1 = 1 => Rx OK ++phy_PathA_IQK_8192C( ++ IN PADAPTER pAdapter, ++ IN BOOLEAN configPathB ++ ) ++{ ++ ++ u4Byte regEAC, regE94, regE9C, regEA4; ++ u1Byte result = 0x00; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ RTPRINT(FINIT, INIT_IQK, ("Path A IQK!\n")); ++ ++ //path-A IQK setting ++ RTPRINT(FINIT, INIT_IQK, ("Path-A IQK setting!\n")); ++ if(pAdapter->interfaceIndex == 0) ++ { ++ PHY_SetBBReg(pAdapter, rTx_IQK_Tone_A, bMaskDWord, 0x10008c1f); ++ PHY_SetBBReg(pAdapter, rRx_IQK_Tone_A, bMaskDWord, 0x10008c1f); ++ } ++ else ++ { ++ PHY_SetBBReg(pAdapter, rTx_IQK_Tone_A, bMaskDWord, 0x10008c22); ++ PHY_SetBBReg(pAdapter, rRx_IQK_Tone_A, bMaskDWord, 0x10008c22); ++ } ++ ++ PHY_SetBBReg(pAdapter, rTx_IQK_PI_A, bMaskDWord, 0x82140102); ++ ++ PHY_SetBBReg(pAdapter, rRx_IQK_PI_A, bMaskDWord, configPathB ? 0x28160202 : ++ IS_81xxC_VENDOR_UMC_B_CUT(pHalData->VersionID)?0x28160202:0x28160502); ++ ++ //path-B IQK setting ++ if(configPathB) ++ { ++ PHY_SetBBReg(pAdapter, rTx_IQK_Tone_B, bMaskDWord, 0x10008c22); ++ PHY_SetBBReg(pAdapter, rRx_IQK_Tone_B, bMaskDWord, 0x10008c22); ++ PHY_SetBBReg(pAdapter, rTx_IQK_PI_B, bMaskDWord, 0x82140102); ++ if(IS_HARDWARE_TYPE_8192D(pAdapter)) ++ PHY_SetBBReg(pAdapter, rRx_IQK_PI_B, bMaskDWord, 0x28160206); ++ else ++ PHY_SetBBReg(pAdapter, rRx_IQK_PI_B, bMaskDWord, 0x28160202); ++ } ++ ++ //LO calibration setting ++ RTPRINT(FINIT, INIT_IQK, ("LO calibration setting!\n")); ++ if(IS_HARDWARE_TYPE_8192D(pAdapter)) ++ PHY_SetBBReg(pAdapter, rIQK_AGC_Rsp, bMaskDWord, 0x00462911); ++ else ++ PHY_SetBBReg(pAdapter, rIQK_AGC_Rsp, bMaskDWord, 0x001028d1); ++ ++ //One shot, path A LOK & IQK ++ RTPRINT(FINIT, INIT_IQK, ("One shot, path A LOK & IQK!\n")); ++ PHY_SetBBReg(pAdapter, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); ++ PHY_SetBBReg(pAdapter, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); ++ ++ // delay x ms ++ RTPRINT(FINIT, INIT_IQK, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME)); ++ PlatformStallExecution(IQK_DELAY_TIME*1000); ++ ++ // Check failed ++ regEAC = PHY_QueryBBReg(pAdapter, rRx_Power_After_IQK_A_2, bMaskDWord); ++ RTPRINT(FINIT, INIT_IQK, ("0xeac = 0x%x\n", regEAC)); ++ regE94 = PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_A, bMaskDWord); ++ RTPRINT(FINIT, INIT_IQK, ("0xe94 = 0x%x\n", regE94)); ++ regE9C= PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_A, bMaskDWord); ++ RTPRINT(FINIT, INIT_IQK, ("0xe9c = 0x%x\n", regE9C)); ++ regEA4= PHY_QueryBBReg(pAdapter, rRx_Power_Before_IQK_A_2, bMaskDWord); ++ RTPRINT(FINIT, INIT_IQK, ("0xea4 = 0x%x\n", regEA4)); ++ ++ if(!(regEAC & BIT28) && ++ (((regE94 & 0x03FF0000)>>16) != 0x142) && ++ (((regE9C & 0x03FF0000)>>16) != 0x42) ) ++ result |= 0x01; ++ else //if Tx not OK, ignore Rx ++ return result; ++ ++ if(!(regEAC & BIT27) && //if Tx is OK, check whether Rx is OK ++ (((regEA4 & 0x03FF0000)>>16) != 0x132) && ++ (((regEAC & 0x03FF0000)>>16) != 0x36)) ++ result |= 0x02; ++ else ++ RTPRINT(FINIT, INIT_IQK, ("Path A Rx IQK fail!!\n")); ++ ++ return result; ++ ++ ++} ++ ++u1Byte //bit0 = 1 => Tx OK, bit1 = 1 => Rx OK ++phy_PathB_IQK_8192C( ++ IN PADAPTER pAdapter ++ ) ++{ ++ u4Byte regEAC, regEB4, regEBC, regEC4, regECC; ++ u1Byte result = 0x00; ++ RTPRINT(FINIT, INIT_IQK, ("Path B IQK!\n")); ++ ++ //One shot, path B LOK & IQK ++ RTPRINT(FINIT, INIT_IQK, ("One shot, path A LOK & IQK!\n")); ++ PHY_SetBBReg(pAdapter, rIQK_AGC_Cont, bMaskDWord, 0x00000002); ++ PHY_SetBBReg(pAdapter, rIQK_AGC_Cont, bMaskDWord, 0x00000000); ++ ++ // delay x ms ++ RTPRINT(FINIT, INIT_IQK, ("Delay %d ms for One shot, path B LOK & IQK.\n", IQK_DELAY_TIME)); ++ PlatformStallExecution(IQK_DELAY_TIME*1000); ++ ++ // Check failed ++ regEAC = PHY_QueryBBReg(pAdapter, rRx_Power_After_IQK_A_2, bMaskDWord); ++ RTPRINT(FINIT, INIT_IQK, ("0xeac = 0x%x\n", regEAC)); ++ regEB4 = PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_B, bMaskDWord); ++ RTPRINT(FINIT, INIT_IQK, ("0xeb4 = 0x%x\n", regEB4)); ++ regEBC= PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_B, bMaskDWord); ++ RTPRINT(FINIT, INIT_IQK, ("0xebc = 0x%x\n", regEBC)); ++ regEC4= PHY_QueryBBReg(pAdapter, rRx_Power_Before_IQK_B_2, bMaskDWord); ++ RTPRINT(FINIT, INIT_IQK, ("0xec4 = 0x%x\n", regEC4)); ++ regECC= PHY_QueryBBReg(pAdapter, rRx_Power_After_IQK_B_2, bMaskDWord); ++ RTPRINT(FINIT, INIT_IQK, ("0xecc = 0x%x\n", regECC)); ++ ++ if(!(regEAC & BIT31) && ++ (((regEB4 & 0x03FF0000)>>16) != 0x142) && ++ (((regEBC & 0x03FF0000)>>16) != 0x42)) ++ result |= 0x01; ++ else ++ return result; ++ ++ if(!(regEAC & BIT30) && ++ (((regEC4 & 0x03FF0000)>>16) != 0x132) && ++ (((regECC & 0x03FF0000)>>16) != 0x36)) ++ result |= 0x02; ++ else ++ RTPRINT(FINIT, INIT_IQK, ("Path B Rx IQK fail!!\n")); ++ ++ ++ return result; ++ ++} ++ ++VOID ++phy_PathAFillIQKMatrix( ++ IN PADAPTER pAdapter, ++ IN BOOLEAN bIQKOK, ++ IN s4Byte result[][8], ++ IN u1Byte final_candidate, ++ IN BOOLEAN bTxOnly ++ ) ++{ ++ u4Byte Oldval_0, X, TX0_A, reg; ++ s4Byte Y, TX0_C; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ RTPRINT(FINIT, INIT_IQK, ("Path A IQ Calibration %s !\n",(bIQKOK)?"Success":"Failed")); ++ ++ if(final_candidate == 0xFF) ++ return; ++ ++ else if(bIQKOK) ++ { ++ Oldval_0 = (PHY_QueryBBReg(pAdapter, rOFDM0_XATxIQImbalance, bMaskDWord) >> 22) & 0x3FF; ++ ++ X = result[final_candidate][0]; ++ if ((X & 0x00000200) != 0) ++ X = X | 0xFFFFFC00; ++ TX0_A = (X * Oldval_0) >> 8; ++ RTPRINT(FINIT, INIT_IQK, ("X = 0x%x, TX0_A = 0x%x, Oldval_0 0x%x\n", X, TX0_A, Oldval_0)); ++ PHY_SetBBReg(pAdapter, rOFDM0_XATxIQImbalance, 0x3FF, TX0_A); ++ if(IS_HARDWARE_TYPE_8192D(pAdapter)) ++ PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT24, ((X* Oldval_0>>7) & 0x1)); ++ else ++ PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT(31), ((X* Oldval_0>>7) & 0x1)); ++ ++ Y = result[final_candidate][1]; ++ if ((Y & 0x00000200) != 0) ++ Y = Y | 0xFFFFFC00; ++ ++ //path B IQK result + 3 ++ if(pAdapter->interfaceIndex == 1 && pHalData->CurrentBandType92D == BAND_ON_5G) ++ Y += 3; ++ ++ TX0_C = (Y * Oldval_0) >> 8; ++ RTPRINT(FINIT, INIT_IQK, ("Y = 0x%x, TX = 0x%x\n", Y, TX0_C)); ++ PHY_SetBBReg(pAdapter, rOFDM0_XCTxAFE, 0xF0000000, ((TX0_C&0x3C0)>>6)); ++ PHY_SetBBReg(pAdapter, rOFDM0_XATxIQImbalance, 0x003F0000, (TX0_C&0x3F)); ++ if(IS_HARDWARE_TYPE_8192D(pAdapter)/*&&is2T*/) ++ PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT26, ((Y* Oldval_0>>7) & 0x1)); ++ else ++ PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT(29), ((Y* Oldval_0>>7) & 0x1)); ++ ++ if(bTxOnly) ++ { ++ RTPRINT(FINIT, INIT_IQK, ("phy_PathAFillIQKMatrix only Tx OK\n")); ++ return; ++ } ++ ++ reg = result[final_candidate][2]; ++ PHY_SetBBReg(pAdapter, rOFDM0_XARxIQImbalance, 0x3FF, reg); ++ ++ reg = result[final_candidate][3] & 0x3F; ++ PHY_SetBBReg(pAdapter, rOFDM0_XARxIQImbalance, 0xFC00, reg); ++ ++ reg = (result[final_candidate][3] >> 6) & 0xF; ++ PHY_SetBBReg(pAdapter, rOFDM0_RxIQExtAnta, 0xF0000000, reg); ++ } ++} ++ ++VOID ++phy_PathBFillIQKMatrix( ++ IN PADAPTER pAdapter, ++ IN BOOLEAN bIQKOK, ++ IN s4Byte result[][8], ++ IN u1Byte final_candidate, ++ IN BOOLEAN bTxOnly //do Tx only ++ ) ++{ ++ u4Byte Oldval_1, X, TX1_A, reg; ++ s4Byte Y, TX1_C; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ RTPRINT(FINIT, INIT_IQK, ("Path B IQ Calibration %s !\n",(bIQKOK)?"Success":"Failed")); ++ ++ if(final_candidate == 0xFF) ++ return; ++ ++ else if(bIQKOK) ++ { ++ Oldval_1 = (PHY_QueryBBReg(pAdapter, rOFDM0_XBTxIQImbalance, bMaskDWord) >> 22) & 0x3FF; ++ ++ X = result[final_candidate][4]; ++ if ((X & 0x00000200) != 0) ++ X = X | 0xFFFFFC00; ++ TX1_A = (X * Oldval_1) >> 8; ++ RTPRINT(FINIT, INIT_IQK, ("X = 0x%x, TX1_A = 0x%x\n", X, TX1_A)); ++ PHY_SetBBReg(pAdapter, rOFDM0_XBTxIQImbalance, 0x3FF, TX1_A); ++ if(IS_HARDWARE_TYPE_8192D(pAdapter)) ++ PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT28, ((X* Oldval_1>>7) & 0x1)); ++ else ++ PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT(27), ((X* Oldval_1>>7) & 0x1)); ++ ++ Y = result[final_candidate][5]; ++ if ((Y & 0x00000200) != 0) ++ Y = Y | 0xFFFFFC00; ++ if(pHalData->CurrentBandType92D == BAND_ON_5G) ++ Y += 3; //temp modify for preformance ++ TX1_C = (Y * Oldval_1) >> 8; ++ RTPRINT(FINIT, INIT_IQK, ("Y = 0x%x, TX1_C = 0x%x\n", Y, TX1_C)); ++ PHY_SetBBReg(pAdapter, rOFDM0_XDTxAFE, 0xF0000000, ((TX1_C&0x3C0)>>6)); ++ PHY_SetBBReg(pAdapter, rOFDM0_XBTxIQImbalance, 0x003F0000, (TX1_C&0x3F)); ++ if(IS_HARDWARE_TYPE_8192D(pAdapter)) ++ PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT30, ((Y* Oldval_1>>7) & 0x1)); ++ else ++ PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT(25), ((Y* Oldval_1>>7) & 0x1)); ++ ++ if(bTxOnly) ++ return; ++ ++ reg = result[final_candidate][6]; ++ PHY_SetBBReg(pAdapter, rOFDM0_XBRxIQImbalance, 0x3FF, reg); ++ ++ reg = result[final_candidate][7] & 0x3F; ++ PHY_SetBBReg(pAdapter, rOFDM0_XBRxIQImbalance, 0xFC00, reg); ++ ++ reg = (result[final_candidate][7] >> 6) & 0xF; ++ PHY_SetBBReg(pAdapter, rOFDM0_AGCRSSITable, 0x0000F000, reg); ++ } ++} ++ ++ ++BOOLEAN ++phy_SimularityCompare_92C( ++ IN PADAPTER pAdapter, ++ IN s4Byte result[][8], ++ IN u1Byte c1, ++ IN u1Byte c2 ++ ) ++{ ++ u4Byte i, j, diff, SimularityBitMap, bound = 0; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ u1Byte final_candidate[2] = {0xFF, 0xFF}; //for path A and path B ++ BOOLEAN bResult = TRUE, is2T = IS_92C_SERIAL( pHalData->VersionID); ++ ++ if(is2T) ++ bound = 8; ++ else ++ bound = 4; ++ ++ SimularityBitMap = 0; ++ ++ for( i = 0; i < bound; i++ ) ++ { ++ diff = (result[c1][i] > result[c2][i]) ? (result[c1][i] - result[c2][i]) : (result[c2][i] - result[c1][i]); ++ if (diff > MAX_TOLERANCE) ++ { ++ if((i == 2 || i == 6) && !SimularityBitMap) ++ { ++ if(result[c1][i]+result[c1][i+1] == 0) ++ final_candidate[(i/4)] = c2; ++ else if (result[c2][i]+result[c2][i+1] == 0) ++ final_candidate[(i/4)] = c1; ++ else ++ SimularityBitMap = SimularityBitMap|(1< do IQK again ++*/ ++BOOLEAN ++phy_SimularityCompare( ++ IN PADAPTER pAdapter, ++ IN s4Byte result[][8], ++ IN u1Byte c1, ++ IN u1Byte c2 ++ ) ++{ ++ if(IS_HARDWARE_TYPE_8192D(pAdapter)) ++ return phy_SimularityCompare_92D(pAdapter, result, c1, c2); ++ else ++ return phy_SimularityCompare_92C(pAdapter, result, c1, c2); ++ ++} ++ ++VOID ++phy_IQCalibrate_8192C( ++ IN PADAPTER pAdapter, ++ IN s4Byte result[][8], ++ IN u1Byte t, ++ IN BOOLEAN is2T ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ u4Byte i; ++ u1Byte PathAOK, PathBOK; ++ u4Byte ADDA_REG[IQK_ADDA_REG_NUM] = { ++ rFPGA0_XCD_SwitchControl, rBlue_Tooth, ++ rRx_Wait_CCA, rTx_CCK_RFON, ++ rTx_CCK_BBON, rTx_OFDM_RFON, ++ rTx_OFDM_BBON, rTx_To_Rx, ++ rTx_To_Tx, rRx_CCK, ++ rRx_OFDM, rRx_Wait_RIFS, ++ rRx_TO_Rx, rStandby, ++ rSleep, rPMPD_ANAEN }; ++ u4Byte IQK_MAC_REG[IQK_MAC_REG_NUM] = { ++ REG_TXPAUSE, REG_BCN_CTRL, ++ REG_BCN_CTRL_1, REG_GPIO_MUXCFG}; ++ ++ //since 92C & 92D have the different define in IQK_BB_REG ++ u4Byte IQK_BB_REG_92C[IQK_BB_REG_NUM] = { ++ rOFDM0_TRxPathEnable, rOFDM0_TRMuxPar, ++ rFPGA0_XCD_RFInterfaceSW, rConfig_AntA, rConfig_AntB, ++ rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE, ++ rFPGA0_XB_RFInterfaceOE, rFPGA0_RFMOD ++ }; ++ ++ u4Byte IQK_BB_REG_92D[IQK_BB_REG_NUM_92D] = { //for normal ++ rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE, ++ rFPGA0_XB_RFInterfaceOE, rOFDM0_TRMuxPar, ++ rFPGA0_XCD_RFInterfaceSW, rOFDM0_TRxPathEnable, ++ rFPGA0_RFMOD, rFPGA0_AnalogParameter4, ++ rOFDM0_XAAGCCore1, rOFDM0_XBAGCCore1 ++ }; ++ u4Byte retryCount; ++#if MP_DRIVER ++ if (pAdapter->registrypriv.mp_mode == 1) ++ retryCount = 9; ++ else ++#endif ++ retryCount = 2; ++ ++ ++ //Neil Chen--2011--05--19-- ++ //3 Path Div ++ u1Byte rfPathSwitch=0x0; ++ ++ // Note: IQ calibration must be performed after loading ++ // PHY_REG.txt , and radio_a, radio_b.txt ++ ++ u4Byte bbvalue; ++ ++ if(t==0) ++ { ++ bbvalue = PHY_QueryBBReg(pAdapter, rFPGA0_RFMOD, bMaskDWord); ++ RTPRINT(FINIT, INIT_IQK, ("phy_IQCalibrate_8192C()==>0x%08x\n",bbvalue)); ++ ++ RTPRINT(FINIT, INIT_IQK, ("IQ Calibration for %s\n", (is2T ? "2T2R" : "1T1R"))); ++ ++ // Save ADDA parameters, turn Path A ADDA on ++ phy_SaveADDARegisters(pAdapter, ADDA_REG, pHalData->ADDA_backup, IQK_ADDA_REG_NUM); ++ phy_SaveMACRegisters(pAdapter, IQK_MAC_REG, pHalData->IQK_MAC_backup); ++ if(IS_HARDWARE_TYPE_8192D(pAdapter)) ++ phy_SaveADDARegisters(pAdapter, IQK_BB_REG_92D, pHalData->IQK_BB_backup, IQK_BB_REG_NUM_92D); ++ else ++ phy_SaveADDARegisters(pAdapter, IQK_BB_REG_92C, pHalData->IQK_BB_backup, IQK_BB_REG_NUM); ++ } ++ ++ phy_PathADDAOn(pAdapter, ADDA_REG, TRUE, is2T); ++ ++ ++ ++ if(IS_HARDWARE_TYPE_8192D(pAdapter)){ ++ //============================== ++ //3 Path Diversity ++ ////Neil Chen--2011--05--20 ++ rfPathSwitch =(u1Byte) (PHY_QueryBBReg(pAdapter, 0xB30, bMaskDWord)>>27); ++ //rfPathSwitch = (u1Byte) DataB30; ++ rfPathSwitch = rfPathSwitch&(0x01); ++ ++ if(rfPathSwitch) // Path Div On ++ { ++ phy_PathADDAOn(pAdapter, ADDA_REG, TRUE, is2T); ++ //DbgPrint("=STEP= change ADDA Path from B to A Path\n"); ++ } ++ else ++ { ++ phy_PathADDAOn(pAdapter, ADDA_REG, FALSE, is2T); ++ } ++ //3 end ++ //===================================== ++ ++ PHY_SetBBReg(pAdapter, rPdp_AntA, bMaskDWord, 0x01017038); ++ } ++ ++ if(t==0) ++ { ++ pHalData->bRfPiEnable = (u1Byte)PHY_QueryBBReg(pAdapter, rFPGA0_XA_HSSIParameter1, BIT(8)); ++ } ++ ++ if(!pHalData->bRfPiEnable){ ++ // Switch BB to PI mode to do IQ Calibration. ++ phy_PIModeSwitch(pAdapter, TRUE); ++ } ++ ++ PHY_SetBBReg(pAdapter, rFPGA0_RFMOD, BIT24, 0x00); ++ PHY_SetBBReg(pAdapter, rOFDM0_TRxPathEnable, bMaskDWord, 0x03a05600); ++ PHY_SetBBReg(pAdapter, rOFDM0_TRMuxPar, bMaskDWord, 0x000800e4); ++ PHY_SetBBReg(pAdapter, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22204000); ++ if(IS_HARDWARE_TYPE_8192D(pAdapter)) ++ PHY_SetBBReg(pAdapter, rFPGA0_AnalogParameter4, 0xf00000, 0x0f); ++ else ++ { ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 0x01); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 0x01); ++ PHY_SetBBReg(pAdapter, rFPGA0_XA_RFInterfaceOE, BIT10, 0x00); ++ PHY_SetBBReg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT10, 0x00); ++ } ++ ++ if(is2T) ++ { ++ PHY_SetBBReg(pAdapter, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00010000); ++ PHY_SetBBReg(pAdapter, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00010000); ++ } ++ ++ //MAC settings ++ phy_MACSettingCalibration(pAdapter, IQK_MAC_REG, pHalData->IQK_MAC_backup); ++ ++ if(IS_HARDWARE_TYPE_8192D(pAdapter)) ++ { ++ PHY_SetBBReg(pAdapter, rConfig_AntA, bMaskDWord, 0x0f600000); ++ ++ if(is2T) ++ { ++ PHY_SetBBReg(pAdapter, rConfig_AntB, bMaskDWord, 0x0f600000); ++ } ++ } ++ else ++ { ++ //Page B init ++ PHY_SetBBReg(pAdapter, rConfig_AntA, bMaskDWord, 0x00080000); ++ ++ if(is2T) ++ { ++ PHY_SetBBReg(pAdapter, rConfig_AntB, bMaskDWord, 0x00080000); ++ } ++ } ++ // IQ calibration setting ++ RTPRINT(FINIT, INIT_IQK, ("IQK setting!\n")); ++ PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0x80800000); ++ PHY_SetBBReg(pAdapter, rTx_IQK, bMaskDWord, 0x01007c00); ++ PHY_SetBBReg(pAdapter, rRx_IQK, bMaskDWord, 0x01004800); ++ ++ for(i = 0 ; i < retryCount ; i++){ ++ PathAOK = phy_PathA_IQK_8192C(pAdapter, is2T); ++ if(PathAOK == 0x03){ ++ RTPRINT(FINIT, INIT_IQK, ("Path A IQK Success!!\n")); ++ result[t][0] = (PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; ++ result[t][1] = (PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; ++ result[t][2] = (PHY_QueryBBReg(pAdapter, rRx_Power_Before_IQK_A_2, bMaskDWord)&0x3FF0000)>>16; ++ result[t][3] = (PHY_QueryBBReg(pAdapter, rRx_Power_After_IQK_A_2, bMaskDWord)&0x3FF0000)>>16; ++ break; ++ } ++ else if (i == (retryCount-1) && PathAOK == 0x01) //Tx IQK OK ++ { ++ RTPRINT(FINIT, INIT_IQK, ("Path A IQK Only Tx Success!!\n")); ++ ++ result[t][0] = (PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; ++ result[t][1] = (PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; ++ } ++ } ++ ++ if(0x00 == PathAOK){ ++ RTPRINT(FINIT, INIT_IQK, ("Path A IQK failed!!\n")); ++ } ++ ++ if(is2T){ ++ phy_PathAStandBy(pAdapter); ++ ++ // Turn Path B ADDA on ++ phy_PathADDAOn(pAdapter, ADDA_REG, FALSE, is2T); ++ ++ for(i = 0 ; i < retryCount ; i++){ ++ PathBOK = phy_PathB_IQK_8192C(pAdapter); ++ if(PathBOK == 0x03){ ++ RTPRINT(FINIT, INIT_IQK, ("Path B IQK Success!!\n")); ++ result[t][4] = (PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_B, bMaskDWord)&0x3FF0000)>>16; ++ result[t][5] = (PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_B, bMaskDWord)&0x3FF0000)>>16; ++ result[t][6] = (PHY_QueryBBReg(pAdapter, rRx_Power_Before_IQK_B_2, bMaskDWord)&0x3FF0000)>>16; ++ result[t][7] = (PHY_QueryBBReg(pAdapter, rRx_Power_After_IQK_B_2, bMaskDWord)&0x3FF0000)>>16; ++ break; ++ } ++ else if (i == (retryCount - 1) && PathBOK == 0x01) //Tx IQK OK ++ { ++ RTPRINT(FINIT, INIT_IQK, ("Path B Only Tx IQK Success!!\n")); ++ result[t][4] = (PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_B, bMaskDWord)&0x3FF0000)>>16; ++ result[t][5] = (PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_B, bMaskDWord)&0x3FF0000)>>16; ++ } ++ } ++ ++ if(0x00 == PathBOK){ ++ RTPRINT(FINIT, INIT_IQK, ("Path B IQK failed!!\n")); ++ } ++ } ++ ++ //Back to BB mode, load original value ++ RTPRINT(FINIT, INIT_IQK, ("IQK:Back to BB mode, load original value!\n")); ++ PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0); ++ ++ if(t!=0) ++ { ++ if(!pHalData->bRfPiEnable){ ++ // Switch back BB to SI mode after finish IQ Calibration. ++ phy_PIModeSwitch(pAdapter, FALSE); ++ } ++ ++ // Reload ADDA power saving parameters ++ phy_ReloadADDARegisters(pAdapter, ADDA_REG, pHalData->ADDA_backup, IQK_ADDA_REG_NUM); ++ ++ // Reload MAC parameters ++ phy_ReloadMACRegisters(pAdapter, IQK_MAC_REG, pHalData->IQK_MAC_backup); ++ ++ // Reload BB parameters ++ if(IS_HARDWARE_TYPE_8192D(pAdapter)) ++ { ++ if(is2T) ++ phy_ReloadADDARegisters(pAdapter, IQK_BB_REG_92D, pHalData->IQK_BB_backup, IQK_BB_REG_NUM_92D); ++ else ++ phy_ReloadADDARegisters(pAdapter, IQK_BB_REG_92D, pHalData->IQK_BB_backup, IQK_BB_REG_NUM_92D -1); ++ } ++ else ++ phy_ReloadADDARegisters(pAdapter, IQK_BB_REG_92C, pHalData->IQK_BB_backup, IQK_BB_REG_NUM); ++ ++ if(!IS_HARDWARE_TYPE_8192D(pAdapter)) ++ { ++ // Restore RX initial gain ++ PHY_SetBBReg(pAdapter, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00032ed3); ++ if(is2T){ ++ PHY_SetBBReg(pAdapter, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00032ed3); ++ } ++ } ++ //load 0xe30 IQC default value ++ PHY_SetBBReg(pAdapter, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00); ++ PHY_SetBBReg(pAdapter, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00); ++ ++ } ++ RTPRINT(FINIT, INIT_IQK, ("phy_IQCalibrate_8192C() <==\n")); ++ ++} ++ ++ ++VOID ++phy_LCCalibrate92C( ++ IN PADAPTER pAdapter, ++ IN BOOLEAN is2T ++ ) ++{ ++ u1Byte tmpReg; ++ u4Byte RF_Amode=0, RF_Bmode=0, LC_Cal; ++// HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ //Check continuous TX and Packet TX ++ tmpReg = PlatformEFIORead1Byte(pAdapter, 0xd03); ++ ++ if((tmpReg&0x70) != 0) //Deal with contisuous TX case ++ PlatformEFIOWrite1Byte(pAdapter, 0xd03, tmpReg&0x8F); //disable all continuous TX ++ else // Deal with Packet TX case ++ PlatformEFIOWrite1Byte(pAdapter, REG_TXPAUSE, 0xFF); // block all queues ++ ++ if((tmpReg&0x70) != 0) ++ { ++ //1. Read original RF mode ++ //Path-A ++ RF_Amode = PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_AC, bMask12Bits); ++ ++ //Path-B ++ if(is2T) ++ RF_Bmode = PHY_QueryRFReg(pAdapter, RF_PATH_B, RF_AC, bMask12Bits); ++ ++ //2. Set RF mode = standby mode ++ //Path-A ++ PHY_SetRFReg(pAdapter, RF_PATH_A, RF_AC, bMask12Bits, (RF_Amode&0x8FFFF)|0x10000); ++ ++ //Path-B ++ if(is2T) ++ PHY_SetRFReg(pAdapter, RF_PATH_B, RF_AC, bMask12Bits, (RF_Bmode&0x8FFFF)|0x10000); ++ } ++ ++ //3. Read RF reg18 ++ LC_Cal = PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_CHNLBW, bMask12Bits); ++ ++ //4. Set LC calibration begin bit15 ++ PHY_SetRFReg(pAdapter, RF_PATH_A, RF_CHNLBW, bMask12Bits, LC_Cal|0x08000); ++ ++ delay_ms(100); ++ ++ ++ //Restore original situation ++ if((tmpReg&0x70) != 0) //Deal with contisuous TX case ++ { ++ //Path-A ++ PlatformEFIOWrite1Byte(pAdapter, 0xd03, tmpReg); ++ PHY_SetRFReg(pAdapter, RF_PATH_A, RF_AC, bMask12Bits, RF_Amode); ++ ++ //Path-B ++ if(is2T) ++ PHY_SetRFReg(pAdapter, RF_PATH_B, RF_AC, bMask12Bits, RF_Bmode); ++ } ++ else // Deal with Packet TX case ++ { ++ PlatformEFIOWrite1Byte(pAdapter, REG_TXPAUSE, 0x00); ++ } ++} ++ ++ ++VOID ++phy_LCCalibrate( ++ IN PADAPTER pAdapter, ++ IN BOOLEAN is2T ++ ) ++{ ++ if(IS_HARDWARE_TYPE_8192D(pAdapter)) ++ { ++#if SWLCK == 1 ++ phy_LCCalibrate92DSW(pAdapter, is2T); ++#else ++ phy_LCCalibrate92D(pAdapter, is2T); ++#endif ++ } ++ else ++ { ++ phy_LCCalibrate92C(pAdapter, is2T); ++ } ++} ++ ++ ++ ++//Analog Pre-distortion calibration ++#define APK_BB_REG_NUM 8 ++#define APK_CURVE_REG_NUM 4 ++#define PATH_NUM 2 ++ ++VOID ++phy_APCalibrate_8192C( ++ IN PADAPTER pAdapter, ++ IN s1Byte delta, ++ IN BOOLEAN is2T ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ u4Byte regD[PATH_NUM]; ++ u4Byte tmpReg, index, offset, i, apkbound; ++ u1Byte path, pathbound = PATH_NUM; ++ u4Byte BB_backup[APK_BB_REG_NUM]; ++ u4Byte BB_REG[APK_BB_REG_NUM] = { ++ rFPGA1_TxBlock, rOFDM0_TRxPathEnable, ++ rFPGA0_RFMOD, rOFDM0_TRMuxPar, ++ rFPGA0_XCD_RFInterfaceSW, rFPGA0_XAB_RFInterfaceSW, ++ rFPGA0_XA_RFInterfaceOE, rFPGA0_XB_RFInterfaceOE }; ++ u4Byte BB_AP_MODE[APK_BB_REG_NUM] = { ++ 0x00000020, 0x00a05430, 0x02040000, ++ 0x000800e4, 0x00204000 }; ++ u4Byte BB_normal_AP_MODE[APK_BB_REG_NUM] = { ++ 0x00000020, 0x00a05430, 0x02040000, ++ 0x000800e4, 0x22204000 }; ++ ++ u4Byte AFE_backup[IQK_ADDA_REG_NUM]; ++ u4Byte AFE_REG[IQK_ADDA_REG_NUM] = { ++ rFPGA0_XCD_SwitchControl, rBlue_Tooth, ++ rRx_Wait_CCA, rTx_CCK_RFON, ++ rTx_CCK_BBON, rTx_OFDM_RFON, ++ rTx_OFDM_BBON, rTx_To_Rx, ++ rTx_To_Tx, rRx_CCK, ++ rRx_OFDM, rRx_Wait_RIFS, ++ rRx_TO_Rx, rStandby, ++ rSleep, rPMPD_ANAEN }; ++ ++ u4Byte MAC_backup[IQK_MAC_REG_NUM]; ++ u4Byte MAC_REG[IQK_MAC_REG_NUM] = { ++ REG_TXPAUSE, REG_BCN_CTRL, ++ REG_BCN_CTRL_1, REG_GPIO_MUXCFG}; ++ ++ u4Byte APK_RF_init_value[PATH_NUM][APK_BB_REG_NUM] = { ++ {0x0852c, 0x1852c, 0x5852c, 0x1852c, 0x5852c}, ++ {0x2852e, 0x0852e, 0x3852e, 0x0852e, 0x0852e} ++ }; ++ ++ u4Byte APK_normal_RF_init_value[PATH_NUM][APK_BB_REG_NUM] = { ++ {0x0852c, 0x0a52c, 0x3a52c, 0x5a52c, 0x5a52c}, //path settings equal to path b settings ++ {0x0852c, 0x0a52c, 0x5a52c, 0x5a52c, 0x5a52c} ++ }; ++ ++ u4Byte APK_RF_value_0[PATH_NUM][APK_BB_REG_NUM] = { ++ {0x52019, 0x52014, 0x52013, 0x5200f, 0x5208d}, ++ {0x5201a, 0x52019, 0x52016, 0x52033, 0x52050} ++ }; ++ ++ u4Byte APK_normal_RF_value_0[PATH_NUM][APK_BB_REG_NUM] = { ++ {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a}, //path settings equal to path b settings ++ {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a} ++ }; ++#if 0 ++ u4Byte APK_RF_value_A[PATH_NUM][APK_BB_REG_NUM] = { ++ {0x1adb0, 0x1adb0, 0x1ada0, 0x1ad90, 0x1ad80}, ++ {0x00fb0, 0x00fb0, 0x00fa0, 0x00f90, 0x00f80} ++ }; ++#endif ++ u4Byte AFE_on_off[PATH_NUM] = { ++ 0x04db25a4, 0x0b1b25a4}; //path A on path B off / path A off path B on ++ ++ u4Byte APK_offset[PATH_NUM] = { ++ rConfig_AntA, rConfig_AntB}; ++ ++ u4Byte APK_normal_offset[PATH_NUM] = { ++ rConfig_Pmpd_AntA, rConfig_Pmpd_AntB}; ++ ++ u4Byte APK_value[PATH_NUM] = { ++ 0x92fc0000, 0x12fc0000}; ++ ++ u4Byte APK_normal_value[PATH_NUM] = { ++ 0x92680000, 0x12680000}; ++ ++ s1Byte APK_delta_mapping[APK_BB_REG_NUM][13] = { ++ {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, ++ {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, ++ {-6, -4, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, ++ {-1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6}, ++ {-11, -9, -7, -5, -3, -1, 0, 0, 0, 0, 0, 0, 0} ++ }; ++ ++ u4Byte APK_normal_setting_value_1[13] = { ++ 0x01017018, 0xf7ed8f84, 0x1b1a1816, 0x2522201e, 0x322e2b28, ++ 0x433f3a36, 0x5b544e49, 0x7b726a62, 0xa69a8f84, 0xdfcfc0b3, ++ 0x12680000, 0x00880000, 0x00880000 ++ }; ++ ++ u4Byte APK_normal_setting_value_2[16] = { ++ 0x01c7021d, 0x01670183, 0x01000123, 0x00bf00e2, 0x008d00a3, ++ 0x0068007b, 0x004d0059, 0x003a0042, 0x002b0031, 0x001f0025, ++ 0x0017001b, 0x00110014, 0x000c000f, 0x0009000b, 0x00070008, ++ 0x00050006 ++ }; ++ ++ u4Byte APK_result[PATH_NUM][APK_BB_REG_NUM]; //val_1_1a, val_1_2a, val_2a, val_3a, val_4a ++// u4Byte AP_curve[PATH_NUM][APK_CURVE_REG_NUM]; ++ ++ s4Byte BB_offset, delta_V, delta_offset; ++ ++#if MP_DRIVER == 1 ++if (pAdapter->registrypriv.mp_mode == 1) ++{ ++ PMPT_CONTEXT pMptCtx = &(pAdapter->MptCtx); ++ ++ pMptCtx->APK_bound[0] = 45; ++ pMptCtx->APK_bound[1] = 52; ++} ++#endif ++ ++ RTPRINT(FINIT, INIT_IQK, ("==>phy_APCalibrate_8192C() delta %d\n", delta)); ++ RTPRINT(FINIT, INIT_IQK, ("AP Calibration for %s\n", (is2T ? "2T2R" : "1T1R"))); ++ if(!is2T) ++ pathbound = 1; ++ ++ //2 FOR NORMAL CHIP SETTINGS ++ ++// Temporarily do not allow normal driver to do the following settings because these offset ++// and value will cause RF internal PA to be unpredictably disabled by HW, such that RF Tx signal ++// will disappear after disable/enable card many times on 88CU. RF SD and DD have not find the ++// root cause, so we remove these actions temporarily. Added by tynli and SD3 Allen. 2010.05.31. ++#if MP_DRIVER != 1 ++ return; ++#endif ++ ++ if (pAdapter->registrypriv.mp_mode != 1) ++ return; ++ ++ //settings adjust for normal chip ++ for(index = 0; index < PATH_NUM; index ++) ++ { ++ APK_offset[index] = APK_normal_offset[index]; ++ APK_value[index] = APK_normal_value[index]; ++ AFE_on_off[index] = 0x6fdb25a4; ++ } ++ ++ for(index = 0; index < APK_BB_REG_NUM; index ++) ++ { ++ for(path = 0; path < pathbound; path++) ++ { ++ APK_RF_init_value[path][index] = APK_normal_RF_init_value[path][index]; ++ APK_RF_value_0[path][index] = APK_normal_RF_value_0[path][index]; ++ } ++ BB_AP_MODE[index] = BB_normal_AP_MODE[index]; ++ } ++ ++ apkbound = 6; ++ ++ //save BB default value ++ for(index = 0; index < APK_BB_REG_NUM ; index++) ++ { ++ if(index == 0) //skip ++ continue; ++ BB_backup[index] = PHY_QueryBBReg(pAdapter, BB_REG[index], bMaskDWord); ++ } ++ ++ //save MAC default value ++ phy_SaveMACRegisters(pAdapter, MAC_REG, MAC_backup); ++ ++ //save AFE default value ++ phy_SaveADDARegisters(pAdapter, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); ++ ++ for(path = 0; path < pathbound; path++) ++ { ++ ++ ++ if(path == RF_PATH_A) ++ { ++ //path A APK ++ //load APK setting ++ //path-A ++ offset = rPdp_AntA; ++ for(index = 0; index < 11; index ++) ++ { ++ PHY_SetBBReg(pAdapter, offset, bMaskDWord, APK_normal_setting_value_1[index]); ++ RTPRINT(FINIT, INIT_IQK, ("phy_APCalibrate_8192C() offset 0x%x value 0x%x\n", offset, PHY_QueryBBReg(pAdapter, offset, bMaskDWord))); ++ ++ offset += 0x04; ++ } ++ ++ PHY_SetBBReg(pAdapter, rConfig_Pmpd_AntB, bMaskDWord, 0x12680000); ++ ++ offset = rConfig_AntA; ++ for(; index < 13; index ++) ++ { ++ PHY_SetBBReg(pAdapter, offset, bMaskDWord, APK_normal_setting_value_1[index]); ++ RTPRINT(FINIT, INIT_IQK, ("phy_APCalibrate_8192C() offset 0x%x value 0x%x\n", offset, PHY_QueryBBReg(pAdapter, offset, bMaskDWord))); ++ ++ offset += 0x04; ++ } ++ ++ //page-B1 ++ PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0x40000000); ++ ++ //path A ++ offset = rPdp_AntA; ++ for(index = 0; index < 16; index++) ++ { ++ PHY_SetBBReg(pAdapter, offset, bMaskDWord, APK_normal_setting_value_2[index]); ++ RTPRINT(FINIT, INIT_IQK, ("phy_APCalibrate_8192C() offset 0x%x value 0x%x\n", offset, PHY_QueryBBReg(pAdapter, offset, bMaskDWord))); ++ ++ offset += 0x04; ++ } ++ PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ } ++ else if(path == RF_PATH_B) ++ { ++ //path B APK ++ //load APK setting ++ //path-B ++ offset = rPdp_AntB; ++ for(index = 0; index < 10; index ++) ++ { ++ PHY_SetBBReg(pAdapter, offset, bMaskDWord, APK_normal_setting_value_1[index]); ++ RTPRINT(FINIT, INIT_IQK, ("phy_APCalibrate_8192C() offset 0x%x value 0x%x\n", offset, PHY_QueryBBReg(pAdapter, offset, bMaskDWord))); ++ ++ offset += 0x04; ++ } ++ PHY_SetBBReg(pAdapter, rConfig_Pmpd_AntA, bMaskDWord, 0x12680000); ++ ++ PHY_SetBBReg(pAdapter, rConfig_Pmpd_AntB, bMaskDWord, 0x12680000); ++ ++ offset = rConfig_AntA; ++ index = 11; ++ for(; index < 13; index ++) //offset 0xb68, 0xb6c ++ { ++ PHY_SetBBReg(pAdapter, offset, bMaskDWord, APK_normal_setting_value_1[index]); ++ RTPRINT(FINIT, INIT_IQK, ("phy_APCalibrate_8192C() offset 0x%x value 0x%x\n", offset, PHY_QueryBBReg(pAdapter, offset, bMaskDWord))); ++ ++ offset += 0x04; ++ } ++ ++ //page-B1 ++ PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0x40000000); ++ ++ //path B ++ offset = 0xb60; ++ for(index = 0; index < 16; index++) ++ { ++ PHY_SetBBReg(pAdapter, offset, bMaskDWord, APK_normal_setting_value_2[index]); ++ RTPRINT(FINIT, INIT_IQK, ("phy_APCalibrate_8192C() offset 0x%x value 0x%x\n", offset, PHY_QueryBBReg(pAdapter, offset, bMaskDWord))); ++ ++ offset += 0x04; ++ } ++ PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ } ++ ++ //save RF default value ++ regD[path] = PHY_QueryRFReg(pAdapter, path, RF_TXBIAS_A, bRFRegOffsetMask); ++ ++ //Path A AFE all on, path B AFE All off or vise versa ++ for(index = 0; index < IQK_ADDA_REG_NUM ; index++) ++ PHY_SetBBReg(pAdapter, AFE_REG[index], bMaskDWord, AFE_on_off[path]); ++ RTPRINT(FINIT, INIT_IQK, ("phy_APCalibrate_8192C() offset 0xe70 %x\n", PHY_QueryBBReg(pAdapter, rRx_Wait_CCA, bMaskDWord))); ++ ++ //BB to AP mode ++ if(path == 0) ++ { ++ for(index = 0; index < APK_BB_REG_NUM ; index++) ++ { ++ ++ if(index == 0) //skip ++ continue; ++ else if (index < 5) ++ PHY_SetBBReg(pAdapter, BB_REG[index], bMaskDWord, BB_AP_MODE[index]); ++ else if (BB_REG[index] == 0x870) ++ PHY_SetBBReg(pAdapter, BB_REG[index], bMaskDWord, BB_backup[index]|BIT10|BIT26); ++ else ++ PHY_SetBBReg(pAdapter, BB_REG[index], BIT10, 0x0); ++ } ++ ++ PHY_SetBBReg(pAdapter, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00); ++ PHY_SetBBReg(pAdapter, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00); ++ } ++ else //path B ++ { ++ PHY_SetBBReg(pAdapter, rTx_IQK_Tone_B, bMaskDWord, 0x01008c00); ++ PHY_SetBBReg(pAdapter, rRx_IQK_Tone_B, bMaskDWord, 0x01008c00); ++ ++ } ++ ++ RTPRINT(FINIT, INIT_IQK, ("phy_APCalibrate_8192C() offset 0x800 %x\n", PHY_QueryBBReg(pAdapter, 0x800, bMaskDWord))); ++ ++ //MAC settings ++ phy_MACSettingCalibration(pAdapter, MAC_REG, MAC_backup); ++ ++ if(path == RF_PATH_A) //Path B to standby mode ++ { ++ PHY_SetRFReg(pAdapter, RF_PATH_B, RF_AC, bRFRegOffsetMask, 0x10000); ++ } ++ else //Path A to standby mode ++ { ++ PHY_SetRFReg(pAdapter, RF_PATH_A, RF_AC, bRFRegOffsetMask, 0x10000); ++ PHY_SetRFReg(pAdapter, RF_PATH_A, RF_MODE1, bRFRegOffsetMask, 0x1000f); ++ PHY_SetRFReg(pAdapter, RF_PATH_A, RF_MODE2, bRFRegOffsetMask, 0x20103); ++ } ++ ++ delta_offset = ((delta+14)/2); ++ if(delta_offset < 0) ++ delta_offset = 0; ++ else if (delta_offset > 12) ++ delta_offset = 12; ++ ++ //AP calibration ++ for(index = 0; index < APK_BB_REG_NUM; index++) ++ { ++ if(index != 1) //only DO PA11+PAD01001, AP RF setting ++ continue; ++ ++ tmpReg = APK_RF_init_value[path][index]; ++#if 1 ++ if(!pHalData->bAPKThermalMeterIgnore) ++ { ++ BB_offset = (tmpReg & 0xF0000) >> 16; ++ ++ if(!(tmpReg & BIT15)) //sign bit 0 ++ { ++ BB_offset = -BB_offset; ++ } ++ ++ delta_V = APK_delta_mapping[index][delta_offset]; ++ ++ BB_offset += delta_V; ++ ++ RTPRINT(FINIT, INIT_IQK, ("phy_APCalibrate_8192C() APK index %d tmpReg 0x%x delta_V %d delta_offset %d\n", index, tmpReg, delta_V, delta_offset)); ++ ++ if(BB_offset < 0) ++ { ++ tmpReg = tmpReg & (~BIT15); ++ BB_offset = -BB_offset; ++ } ++ else ++ { ++ tmpReg = tmpReg | BIT15; ++ } ++ tmpReg = (tmpReg & 0xFFF0FFFF) | (BB_offset << 16); ++ } ++#endif ++ ++#if DEV_BUS_TYPE==RT_PCI_INTERFACE ++ if(IS_81xxC_VENDOR_UMC_B_CUT(pHalData->VersionID)) ++ PHY_SetRFReg(pAdapter, path, RF_IPA_A, bRFRegOffsetMask, 0x894ae); ++ else ++#endif ++ PHY_SetRFReg(pAdapter, path, RF_IPA_A, bRFRegOffsetMask, 0x8992e); ++ RTPRINT(FINIT, INIT_IQK, ("phy_APCalibrate_8192C() offset 0xc %x\n", PHY_QueryRFReg(pAdapter, path, RF_IPA_A, bRFRegOffsetMask))); ++ PHY_SetRFReg(pAdapter, path, RF_AC, bRFRegOffsetMask, APK_RF_value_0[path][index]); ++ RTPRINT(FINIT, INIT_IQK, ("phy_APCalibrate_8192C() offset 0x0 %x\n", PHY_QueryRFReg(pAdapter, path, RF_AC, bRFRegOffsetMask))); ++ PHY_SetRFReg(pAdapter, path, RF_TXBIAS_A, bRFRegOffsetMask, tmpReg); ++ RTPRINT(FINIT, INIT_IQK, ("phy_APCalibrate_8192C() offset 0xd %x\n", PHY_QueryRFReg(pAdapter, path, RF_TXBIAS_A, bRFRegOffsetMask))); ++ ++ // PA11+PAD01111, one shot ++ i = 0; ++ do ++ { ++ PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0x80000000); ++ { ++ PHY_SetBBReg(pAdapter, APK_offset[path], bMaskDWord, APK_value[0]); ++ RTPRINT(FINIT, INIT_IQK, ("phy_APCalibrate_8192C() offset 0x%x value 0x%x\n", APK_offset[path], PHY_QueryBBReg(pAdapter, APK_offset[path], bMaskDWord))); ++ delay_ms(3); ++ PHY_SetBBReg(pAdapter, APK_offset[path], bMaskDWord, APK_value[1]); ++ RTPRINT(FINIT, INIT_IQK, ("phy_APCalibrate_8192C() offset 0x%x value 0x%x\n", APK_offset[path], PHY_QueryBBReg(pAdapter, APK_offset[path], bMaskDWord))); ++ ++ delay_ms(20); ++ } ++ PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ ++ if(path == RF_PATH_A) ++ tmpReg = PHY_QueryBBReg(pAdapter, rAPK, 0x03E00000); ++ else ++ tmpReg = PHY_QueryBBReg(pAdapter, rAPK, 0xF8000000); ++ RTPRINT(FINIT, INIT_IQK, ("phy_APCalibrate_8192C() offset 0xbd8[25:21] %x\n", tmpReg)); ++ ++ ++ i++; ++ } ++ while(tmpReg > apkbound && i < 4); ++ ++ APK_result[path][index] = tmpReg; ++ } ++ } ++ ++ //reload MAC default value ++ phy_ReloadMACRegisters(pAdapter, MAC_REG, MAC_backup); ++ ++ //reload BB default value ++ for(index = 0; index < APK_BB_REG_NUM ; index++) ++ { ++ ++ if(index == 0) //skip ++ continue; ++ PHY_SetBBReg(pAdapter, BB_REG[index], bMaskDWord, BB_backup[index]); ++ } ++ ++ //reload AFE default value ++ phy_ReloadADDARegisters(pAdapter, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); ++ ++ //reload RF path default value ++ for(path = 0; path < pathbound; path++) ++ { ++ PHY_SetRFReg(pAdapter, path, RF_TXBIAS_A, bRFRegOffsetMask, regD[path]); ++ if(path == RF_PATH_B) ++ { ++ PHY_SetRFReg(pAdapter, RF_PATH_A, RF_MODE1, bRFRegOffsetMask, 0x1000f); ++ PHY_SetRFReg(pAdapter, RF_PATH_A, RF_MODE2, bRFRegOffsetMask, 0x20101); ++ } ++ ++ //note no index == 0 ++ if (APK_result[path][1] > 6) ++ APK_result[path][1] = 6; ++ RTPRINT(FINIT, INIT_IQK, ("apk path %d result %d 0x%x \t", path, 1, APK_result[path][1])); ++ } ++ ++ RTPRINT(FINIT, INIT_IQK, ("\n")); ++ ++ ++ for(path = 0; path < pathbound; path++) ++ { ++ PHY_SetRFReg(pAdapter, path, RF_BS_PA_APSET_G1_G4, bRFRegOffsetMask, ++ ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (APK_result[path][1] << 5) | APK_result[path][1])); ++ if(path == RF_PATH_A) ++ PHY_SetRFReg(pAdapter, path, RF_BS_PA_APSET_G5_G8, bRFRegOffsetMask, ++ ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (0x00 << 5) | 0x05)); ++ else ++ PHY_SetRFReg(pAdapter, path, RF_BS_PA_APSET_G5_G8, bRFRegOffsetMask, ++ ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (0x02 << 5) | 0x05)); ++ ++ if(!IS_HARDWARE_TYPE_8723A(pAdapter)) ++ PHY_SetRFReg(pAdapter, path, RF_BS_PA_APSET_G9_G11, bRFRegOffsetMask, ++ ((0x08 << 15) | (0x08 << 10) | (0x08 << 5) | 0x08)); ++ } ++ ++ pHalData->bAPKdone = TRUE; ++ ++ RTPRINT(FINIT, INIT_IQK, ("<==phy_APCalibrate_8192C()\n")); ++} ++ ++ ++VOID ++PHY_IQCalibrate_8192C( ++ IN PADAPTER pAdapter, ++ IN BOOLEAN bReCovery ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ s4Byte result[4][8]; //last is final result ++ u1Byte i, final_candidate, Indexforchannel; ++ BOOLEAN bPathAOK, bPathBOK; ++ s4Byte RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC, RegTmp = 0; ++ BOOLEAN is12simular, is13simular, is23simular; ++ BOOLEAN bStartContTx = FALSE, bSingleTone = FALSE, bCarrierSuppression = FALSE; ++ u4Byte IQK_BB_REG_92C[IQK_BB_REG_NUM] = { ++ rOFDM0_XARxIQImbalance, rOFDM0_XBRxIQImbalance, ++ rOFDM0_ECCAThreshold, rOFDM0_AGCRSSITable, ++ rOFDM0_XATxIQImbalance, rOFDM0_XBTxIQImbalance, ++ rOFDM0_XCTxAFE, rOFDM0_XDTxAFE, ++ rOFDM0_RxIQExtAnta}; ++ ++ if (ODM_CheckPowerStatus(pAdapter) == FALSE) ++ return; ++ ++#if MP_DRIVER == 1 ++if (pAdapter->registrypriv.mp_mode == 1) ++{ ++ bStartContTx = pAdapter->MptCtx.bStartContTx; ++ bSingleTone = pAdapter->MptCtx.bSingleTone; ++ bCarrierSuppression = pAdapter->MptCtx.bCarrierSuppression; ++} ++#endif ++ ++ //ignore IQK when continuous Tx ++ if(bStartContTx || bSingleTone || bCarrierSuppression) ++ return; ++ ++#if DISABLE_BB_RF ++ return; ++#endif ++ if(pAdapter->bSlaveOfDMSP) ++ return; ++ ++ if(!IS_HARDWARE_TYPE_8192D(pAdapter)) ++ { ++ if(bReCovery) ++ { ++ phy_ReloadADDARegisters(pAdapter, IQK_BB_REG_92C, pHalData->IQK_BB_backup_recover, 9); ++ return; ++ ++ } ++ } ++ RTPRINT(FINIT, INIT_IQK, ("IQK:Start!!!\n")); ++ ++ for(i = 0; i < 8; i++) ++ { ++ result[0][i] = 0; ++ result[1][i] = 0; ++ result[2][i] = 0; ++ result[3][i] = 0; ++ } ++ final_candidate = 0xff; ++ bPathAOK = FALSE; ++ bPathBOK = FALSE; ++ is12simular = FALSE; ++ is23simular = FALSE; ++ is13simular = FALSE; ++ ++ ++ RTPRINT(FINIT, INIT_IQK, ("IQK !!!interface %d currentband %d ishardwareD %d \n", pAdapter->interfaceIndex, pHalData->CurrentBandType92D, IS_HARDWARE_TYPE_8192D(pAdapter))); ++ AcquireCCKAndRWPageAControl(pAdapter); ++// RT_TRACE(COMP_INIT,DBG_LOUD,("Acquire Mutex in IQCalibrate \n")); ++ for (i=0; i<3; i++) ++ { ++// if(IS_HARDWARE_TYPE_8192C(pAdapter) || IS_HARDWARE_TYPE_8723A(pAdapter)) ++ if(!IS_HARDWARE_TYPE_8192D(pAdapter)) ++ { ++ if(IS_92C_SERIAL( pHalData->VersionID)) ++ { ++ phy_IQCalibrate_8192C(pAdapter, result, i, TRUE); ++ } ++ else ++ { ++ // For 88C 1T1R ++ phy_IQCalibrate_8192C(pAdapter, result, i, FALSE); ++ } ++ } ++ else/* if(IS_HARDWARE_TYPE_8192D(pAdapter))*/ ++ { ++ if(pHalData->CurrentBandType92D == BAND_ON_5G) ++ { ++ phy_IQCalibrate_5G_Normal(pAdapter, result, i); ++ } ++ else if(pHalData->CurrentBandType92D == BAND_ON_2_4G) ++ { ++ if(IS_92D_SINGLEPHY(pHalData->VersionID)) ++ phy_IQCalibrate_8192C(pAdapter, result, i, TRUE); ++ else ++ phy_IQCalibrate_8192C(pAdapter, result, i, FALSE); ++ } ++ } ++ ++ if(i == 1) ++ { ++ is12simular = phy_SimularityCompare(pAdapter, result, 0, 1); ++ if(is12simular) ++ { ++ final_candidate = 0; ++ break; ++ } ++ } ++ ++ if(i == 2) ++ { ++ is13simular = phy_SimularityCompare(pAdapter, result, 0, 2); ++ if(is13simular) ++ { ++ final_candidate = 0; ++ break; ++ } ++ ++ is23simular = phy_SimularityCompare(pAdapter, result, 1, 2); ++ if(is23simular) ++ final_candidate = 1; ++ else ++ { ++ for(i = 0; i < 8; i++) ++ RegTmp += result[3][i]; ++ ++ if(RegTmp != 0) ++ final_candidate = 3; ++ else ++ final_candidate = 0xFF; ++ } ++ } ++ } ++// RT_TRACE(COMP_INIT,DBG_LOUD,("Release Mutex in IQCalibrate \n")); ++ ReleaseCCKAndRWPageAControl(pAdapter); ++ ++ for (i=0; i<4; i++) ++ { ++ RegE94 = result[i][0]; ++ RegE9C = result[i][1]; ++ RegEA4 = result[i][2]; ++ RegEAC = result[i][3]; ++ RegEB4 = result[i][4]; ++ RegEBC = result[i][5]; ++ RegEC4 = result[i][6]; ++ RegECC = result[i][7]; ++ RTPRINT(FINIT, INIT_IQK, ("IQK: RegE94=%x RegE9C=%x RegEA4=%x RegEAC=%x RegEB4=%x RegEBC=%x RegEC4=%x RegECC=%x\n ", RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC)); ++ } ++ ++ if(final_candidate != 0xff) ++ { ++ pHalData->RegE94 = RegE94 = result[final_candidate][0]; ++ pHalData->RegE9C = RegE9C = result[final_candidate][1]; ++ RegEA4 = result[final_candidate][2]; ++ RegEAC = result[final_candidate][3]; ++ pHalData->RegEB4 = RegEB4 = result[final_candidate][4]; ++ pHalData->RegEBC = RegEBC = result[final_candidate][5]; ++ RegEC4 = result[final_candidate][6]; ++ RegECC = result[final_candidate][7]; ++ RTPRINT(FINIT, INIT_IQK, ("IQK: final_candidate is %x\n",final_candidate)); ++ RTPRINT(FINIT, INIT_IQK, ("IQK: RegE94=%x RegE9C=%x RegEA4=%x RegEAC=%x RegEB4=%x RegEBC=%x RegEC4=%x RegECC=%x\n ", RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC)); ++ bPathAOK = bPathBOK = TRUE; ++ } ++ else ++ { ++ RegE94 = RegEB4 = pHalData->RegE94 = pHalData->RegEB4 = 0x100; //X default value ++ RegE9C = RegEBC = pHalData->RegE9C = pHalData->RegEBC = 0x0; //Y default value ++ } ++ ++ if((RegE94 != 0)/*&&(RegEA4 != 0)*/) ++ { ++ if(pHalData->CurrentBandType92D == BAND_ON_5G) ++ phy_PathAFillIQKMatrix_5G_Normal(pAdapter, bPathAOK, result, final_candidate, (RegEA4 == 0)); ++ else ++ phy_PathAFillIQKMatrix(pAdapter, bPathAOK, result, final_candidate, (RegEA4 == 0)); ++ ++ } ++ ++ if (IS_92C_SERIAL(pHalData->VersionID) || IS_92D_SINGLEPHY(pHalData->VersionID)) ++ { ++ if((RegEB4 != 0)/*&&(RegEC4 != 0)*/) ++ { ++ if(pHalData->CurrentBandType92D == BAND_ON_5G) ++ phy_PathBFillIQKMatrix_5G_Normal(pAdapter, bPathBOK, result, final_candidate, (RegEC4 == 0)); ++ else ++ phy_PathBFillIQKMatrix(pAdapter, bPathBOK, result, final_candidate, (RegEC4 == 0)); ++ } ++ } ++ ++ if(IS_HARDWARE_TYPE_8192D(pAdapter) && final_candidate != 0xFF) ++ { ++ Indexforchannel = GetRightChnlPlaceforIQK(pHalData->CurrentChannel); ++ ++ for(i = 0; i < IQK_Matrix_REG_NUM; i++) ++ pHalData->IQKMatrixRegSetting[Indexforchannel].Value[0][i] = ++ result[final_candidate][i]; ++ ++ pHalData->IQKMatrixRegSetting[Indexforchannel].bIQKDone = TRUE; ++ ++ RTPRINT(FINIT, INIT_IQK, ("\nIQK OK Indexforchannel %d.\n", Indexforchannel)); ++ } ++ ++ if(!IS_HARDWARE_TYPE_8192D(pAdapter)) ++ phy_SaveADDARegisters(pAdapter, IQK_BB_REG_92C, pHalData->IQK_BB_backup_recover, 9); ++ ++} ++ ++ ++VOID ++PHY_LCCalibrate_8192C( ++ IN PADAPTER pAdapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ BOOLEAN bStartContTx = FALSE, bSingleTone = FALSE, bCarrierSuppression = FALSE; ++ PMGNT_INFO pMgntInfo=&pAdapter->MgntInfo; ++ PMGNT_INFO pMgntInfoBuddyAdapter; ++ u4Byte timeout = 2000, timecount = 0; ++ PADAPTER BuddyAdapter = pAdapter->BuddyAdapter; ++ ++#if MP_DRIVER == 1 ++if (pAdapter->registrypriv.mp_mode == 1) ++{ ++ bStartContTx = pAdapter->MptCtx.bStartContTx; ++ bSingleTone = pAdapter->MptCtx.bSingleTone; ++ bCarrierSuppression = pAdapter->MptCtx.bCarrierSuppression; ++} ++#endif ++ ++#if DISABLE_BB_RF ++ return; ++#endif ++ ++ //ignore LCK when continuous Tx ++ if(bStartContTx || bSingleTone || bCarrierSuppression) ++ return; ++ ++ if(BuddyAdapter != NULL && ++ ((pAdapter->interfaceIndex == 0 && pHalData->CurrentBandType92D == BAND_ON_2_4G) || ++ (pAdapter->interfaceIndex == 1 && pHalData->CurrentBandType92D == BAND_ON_5G))) ++ { ++ pMgntInfoBuddyAdapter=&BuddyAdapter->MgntInfo; ++ while(pMgntInfoBuddyAdapter->bScanInProgress && timecount < timeout) ++ { ++ delay_ms(50); ++ timecount += 50; ++ } ++ } ++ ++ while(pMgntInfo->bScanInProgress && timecount < timeout) ++ { ++ delay_ms(50); ++ timecount += 50; ++ } ++ ++ pHalData->bLCKInProgress = TRUE; ++ ++ RTPRINT(FINIT, INIT_IQK, ("LCK:Start!!!interface %d currentband %x delay %d ms\n", pAdapter->interfaceIndex, pHalData->CurrentBandType92D, timecount)); ++ ++ //if(IS_92C_SERIAL(pHalData->VersionID) || IS_92D_SINGLEPHY(pHalData->VersionID)) ++ if(IS_2T2R(pHalData->VersionID)) ++ { ++ phy_LCCalibrate(pAdapter, TRUE); ++ } ++ else{ ++ // For 88C 1T1R ++ phy_LCCalibrate(pAdapter, FALSE); ++ } ++ ++ pHalData->bLCKInProgress = FALSE; ++ ++ RTPRINT(FINIT, INIT_IQK, ("LCK:Finish!!!interface %d\n", pAdapter->interfaceIndex)); ++ ++ ++} ++ ++VOID ++PHY_APCalibrate_8192C( ++ IN PADAPTER pAdapter, ++ IN s1Byte delta ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ //default disable APK, because Tx NG issue, suggest by Jenyu, 2011.11.25 ++ return; ++ ++#if DISABLE_BB_RF ++ return; ++#endif ++ ++ if(IS_HARDWARE_TYPE_8192D(pAdapter) || IS_HARDWARE_TYPE_8723A(pAdapter)) ++ return; ++ ++#if FOR_BRAZIL_PRETEST != 1 ++ if(pHalData->bAPKdone) ++#endif ++ return; ++ ++ if(IS_92C_SERIAL( pHalData->VersionID)){ ++ phy_APCalibrate_8192C(pAdapter, delta, TRUE); ++ } ++ else{ ++ // For 88C 1T1R ++ phy_APCalibrate_8192C(pAdapter, delta, FALSE); ++ } ++} ++ ++ ++#endif ++ ++ ++//3============================================================ ++//3 IQ Calibration ++//3============================================================ ++ ++VOID ++ODM_ResetIQKResult( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ u1Byte i; ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP || DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ ++ if (!IS_HARDWARE_TYPE_8192D(Adapter)) ++ return; ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD,("PHY_ResetIQKResult:: settings regs %d default regs %d\n", (u32)(sizeof(pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting)/sizeof(IQK_MATRIX_REGS_SETTING)), IQK_Matrix_Settings_NUM)); ++ //0xe94, 0xe9c, 0xea4, 0xeac, 0xeb4, 0xebc, 0xec4, 0xecc ++ ++ for(i = 0; i < IQK_Matrix_Settings_NUM; i++) ++ { ++ { ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].Value[0][0] = ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].Value[0][2] = ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].Value[0][4] = ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].Value[0][6] = 0x100; ++ ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].Value[0][1] = ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].Value[0][3] = ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].Value[0][5] = ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].Value[0][7] = 0x0; ++ ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].bIQKDone = FALSE; ++ ++ } ++ } ++ ++} ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++u1Byte ODM_GetRightChnlPlaceforIQK(u1Byte chnl) ++{ ++ u1Byte channel_all[ODM_TARGET_CHNL_NUM_2G_5G] = ++ {1,2,3,4,5,6,7,8,9,10,11,12,13,14,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,149,151,153,155,157,159,161,163,165}; ++ u1Byte place = chnl; ++ ++ ++ if(chnl > 14) ++ { ++ for(place = 14; place To DO modify ++u4Byte EDCAParam[HT_IOT_PEER_MAX][3] = ++{ // UL DL ++ {0x5ea42b, 0x5ea42b, 0x5ea42b}, //0:unknown AP ++ {0xa44f, 0x5ea44f, 0x5e431c}, // 1:realtek AP ++ {0x5ea42b, 0x5ea42b, 0x5ea42b}, // 2:unknown AP => realtek_92SE ++ {0x5ea32b, 0x5ea42b, 0x5e4322}, // 3:broadcom AP ++ {0x5ea422, 0x00a44f, 0x00a44f}, // 4:ralink AP ++ {0x5ea322, 0x00a630, 0x00a44f}, // 5:atheros AP ++ //{0x5ea42b, 0x5ea42b, 0x5ea42b},// 6:cisco AP ++ {0x5e4322, 0x5e4322, 0x5e4322},// 6:cisco AP ++ //{0x3ea430, 0x00a630, 0x3ea44f}, // 7:cisco AP ++ {0x5ea44f, 0x00a44f, 0x5ea42b}, // 8:marvell AP ++ //{0x5ea44f, 0x5ea44f, 0x5ea44f}, // 9realtek AP ++ {0x5ea42b, 0x5ea42b, 0x5ea42b}, // 10:unknown AP=> 92U AP ++ {0x5ea42b, 0xa630, 0x5e431c}, // 11:airgocap AP ++// {0x5e4322, 0x00a44f, 0x5ea44f}, // 12:unknown AP ++}; ++//============================================================ ++// EDCA Paramter for AP/ADSL by Mingzhi 2011-11-22 ++//============================================================ ++#elif (DM_ODM_SUPPORT_TYPE &ODM_ADSL) ++enum qos_prio { BK, BE, VI, VO, VI_AG, VO_AG }; ++ ++static const struct ParaRecord rtl_ap_EDCA[] = ++{ ++//ACM,AIFSN, ECWmin, ECWmax, TXOplimit ++ {0, 7, 4, 10, 0}, //BK ++ {0, 3, 4, 6, 0}, //BE ++ {0, 1, 3, 4, 188}, //VI ++ {0, 1, 2, 3, 102}, //VO ++ {0, 1, 3, 4, 94}, //VI_AG ++ {0, 1, 2, 3, 47}, //VO_AG ++}; ++ ++static const struct ParaRecord rtl_sta_EDCA[] = ++{ ++//ACM,AIFSN, ECWmin, ECWmax, TXOplimit ++ {0, 7, 4, 10, 0}, ++ {0, 3, 4, 10, 0}, ++ {0, 2, 3, 4, 188}, ++ {0, 2, 2, 3, 102}, ++ {0, 2, 3, 4, 94}, ++ {0, 2, 2, 3, 47}, ++}; ++#endif ++ ++//============================================================ ++// Global var ++//============================================================ ++u4Byte OFDMSwingTable[OFDM_TABLE_SIZE_92D] = { ++ 0x7f8001fe, // 0, +6.0dB ++ 0x788001e2, // 1, +5.5dB ++ 0x71c001c7, // 2, +5.0dB ++ 0x6b8001ae, // 3, +4.5dB ++ 0x65400195, // 4, +4.0dB ++ 0x5fc0017f, // 5, +3.5dB ++ 0x5a400169, // 6, +3.0dB ++ 0x55400155, // 7, +2.5dB ++ 0x50800142, // 8, +2.0dB ++ 0x4c000130, // 9, +1.5dB ++ 0x47c0011f, // 10, +1.0dB ++ 0x43c0010f, // 11, +0.5dB ++ 0x40000100, // 12, +0dB ++ 0x3c8000f2, // 13, -0.5dB ++ 0x390000e4, // 14, -1.0dB ++ 0x35c000d7, // 15, -1.5dB ++ 0x32c000cb, // 16, -2.0dB ++ 0x300000c0, // 17, -2.5dB ++ 0x2d4000b5, // 18, -3.0dB ++ 0x2ac000ab, // 19, -3.5dB ++ 0x288000a2, // 20, -4.0dB ++ 0x26000098, // 21, -4.5dB ++ 0x24000090, // 22, -5.0dB ++ 0x22000088, // 23, -5.5dB ++ 0x20000080, // 24, -6.0dB ++ 0x1e400079, // 25, -6.5dB ++ 0x1c800072, // 26, -7.0dB ++ 0x1b00006c, // 27. -7.5dB ++ 0x19800066, // 28, -8.0dB ++ 0x18000060, // 29, -8.5dB ++ 0x16c0005b, // 30, -9.0dB ++ 0x15800056, // 31, -9.5dB ++ 0x14400051, // 32, -10.0dB ++ 0x1300004c, // 33, -10.5dB ++ 0x12000048, // 34, -11.0dB ++ 0x11000044, // 35, -11.5dB ++ 0x10000040, // 36, -12.0dB ++ 0x0f00003c,// 37, -12.5dB ++ 0x0e400039,// 38, -13.0dB ++ 0x0d800036,// 39, -13.5dB ++ 0x0cc00033,// 40, -14.0dB ++ 0x0c000030,// 41, -14.5dB ++ 0x0b40002d,// 42, -15.0dB ++}; ++ ++ ++u1Byte CCKSwingTable_Ch1_Ch13[CCK_TABLE_SIZE][8] = { ++ {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, // 0, +0dB ++ {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, // 1, -0.5dB ++ {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, // 2, -1.0dB ++ {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, // 3, -1.5dB ++ {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, // 4, -2.0dB ++ {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, // 5, -2.5dB ++ {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, // 6, -3.0dB ++ {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, // 7, -3.5dB ++ {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, // 8, -4.0dB ++ {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, // 9, -4.5dB ++ {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, // 10, -5.0dB ++ {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, // 11, -5.5dB ++ {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, // 12, -6.0dB ++ {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, // 13, -6.5dB ++ {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, // 14, -7.0dB ++ {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, // 15, -7.5dB ++ {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, // 16, -8.0dB ++ {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, // 17, -8.5dB ++ {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, // 18, -9.0dB ++ {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, // 19, -9.5dB ++ {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, // 20, -10.0dB ++ {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, // 21, -10.5dB ++ {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, // 22, -11.0dB ++ {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, // 23, -11.5dB ++ {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, // 24, -12.0dB ++ {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, // 25, -12.5dB ++ {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, // 26, -13.0dB ++ {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, // 27, -13.5dB ++ {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, // 28, -14.0dB ++ {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, // 29, -14.5dB ++ {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, // 30, -15.0dB ++ {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, // 31, -15.5dB ++ {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01} // 32, -16.0dB ++}; ++ ++ ++u1Byte CCKSwingTable_Ch14 [CCK_TABLE_SIZE][8]= { ++ {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, // 0, +0dB ++ {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, // 1, -0.5dB ++ {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, // 2, -1.0dB ++ {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, // 3, -1.5dB ++ {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, // 4, -2.0dB ++ {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, // 5, -2.5dB ++ {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, // 6, -3.0dB ++ {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, // 7, -3.5dB ++ {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, // 8, -4.0dB ++ {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, // 9, -4.5dB ++ {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, // 10, -5.0dB ++ {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, // 11, -5.5dB ++ {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, // 12, -6.0dB ++ {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, // 13, -6.5dB ++ {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, // 14, -7.0dB ++ {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, // 15, -7.5dB ++ {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, // 16, -8.0dB ++ {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, // 17, -8.5dB ++ {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, // 18, -9.0dB ++ {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, // 19, -9.5dB ++ {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, // 20, -10.0dB ++ {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, // 21, -10.5dB ++ {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, // 22, -11.0dB ++ {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, // 23, -11.5dB ++ {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, // 24, -12.0dB ++ {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, // 25, -12.5dB ++ {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, // 26, -13.0dB ++ {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, // 27, -13.5dB ++ {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, // 28, -14.0dB ++ {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, // 29, -14.5dB ++ {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, // 30, -15.0dB ++ {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, // 31, -15.5dB ++ {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} // 32, -16.0dB ++}; ++ ++ ++#ifdef AP_BUILD_WORKAROUND ++ ++unsigned int TxPwrTrk_OFDM_SwingTbl[TxPwrTrk_OFDM_SwingTbl_Len] = { ++ /* +6.0dB */ 0x7f8001fe, ++ /* +5.5dB */ 0x788001e2, ++ /* +5.0dB */ 0x71c001c7, ++ /* +4.5dB */ 0x6b8001ae, ++ /* +4.0dB */ 0x65400195, ++ /* +3.5dB */ 0x5fc0017f, ++ /* +3.0dB */ 0x5a400169, ++ /* +2.5dB */ 0x55400155, ++ /* +2.0dB */ 0x50800142, ++ /* +1.5dB */ 0x4c000130, ++ /* +1.0dB */ 0x47c0011f, ++ /* +0.5dB */ 0x43c0010f, ++ /* 0.0dB */ 0x40000100, ++ /* -0.5dB */ 0x3c8000f2, ++ /* -1.0dB */ 0x390000e4, ++ /* -1.5dB */ 0x35c000d7, ++ /* -2.0dB */ 0x32c000cb, ++ /* -2.5dB */ 0x300000c0, ++ /* -3.0dB */ 0x2d4000b5, ++ /* -3.5dB */ 0x2ac000ab, ++ /* -4.0dB */ 0x288000a2, ++ /* -4.5dB */ 0x26000098, ++ /* -5.0dB */ 0x24000090, ++ /* -5.5dB */ 0x22000088, ++ /* -6.0dB */ 0x20000080, ++ /* -6.5dB */ 0x1a00006c, ++ /* -7.0dB */ 0x1c800072, ++ /* -7.5dB */ 0x18000060, ++ /* -8.0dB */ 0x19800066, ++ /* -8.5dB */ 0x15800056, ++ /* -9.0dB */ 0x26c0005b, ++ /* -9.5dB */ 0x14400051, ++ /* -10.0dB */ 0x24400051, ++ /* -10.5dB */ 0x1300004c, ++ /* -11.0dB */ 0x12000048, ++ /* -11.5dB */ 0x11000044, ++ /* -12.0dB */ 0x10000040 ++}; ++#endif ++ ++//============================================================ ++// Local Function predefine. ++//============================================================ ++ ++//START------------COMMON INFO RELATED---------------// ++VOID ++odm_CommonInfoSelfInit( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_CommonInfoSelfUpdate( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_CmnInfoInit_Debug( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_CmnInfoHook_Debug( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_CmnInfoUpdate_Debug( ++ IN PDM_ODM_T pDM_Odm ++ ); ++/* ++VOID ++odm_FindMinimumRSSI( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_IsLinked( ++ IN PDM_ODM_T pDM_Odm ++ ); ++*/ ++//END------------COMMON INFO RELATED---------------// ++ ++//START---------------DIG---------------------------// ++VOID ++odm_FalseAlarmCounterStatistics( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_DIGInit( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_DIG( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_CCKPacketDetectionThresh( ++ IN PDM_ODM_T pDM_Odm ++ ); ++//END---------------DIG---------------------------// ++ ++//START-------BB POWER SAVE-----------------------// ++VOID ++odm_DynamicBBPowerSavingInit( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_DynamicBBPowerSaving( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_1R_CCA( ++ IN PDM_ODM_T pDM_Odm ++ ); ++VOID ++odm_AdaptivityInit( ++ IN PDM_ODM_T pDM_Odm ++); ++ ++VOID ++odm_Adaptivity( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte IGI ++); ++//END---------BB POWER SAVE-----------------------// ++ ++//START-----------------PSD-----------------------// ++#if(DM_ODM_SUPPORT_TYPE & (ODM_MP)) ++//============================================================ ++// Function predefine. ++//============================================================ ++VOID odm_PathDiversityInit_92C( IN PADAPTER Adapter); ++VOID odm_2TPathDiversityInit_92C( IN PADAPTER Adapter); ++VOID odm_1TPathDiversityInit_92C( IN PADAPTER Adapter); ++BOOLEAN odm_IsConnected_92C(IN PADAPTER Adapter); ++VOID odm_PathDiversityAfterLink_92C( IN PADAPTER Adapter); ++ ++VOID ++odm_CCKTXPathDiversityCallback( ++ PRT_TIMER pTimer ++ ); ++ ++VOID ++odm_CCKTXPathDiversityWorkItemCallback( ++ IN PVOID pContext ++ ); ++ ++VOID ++odm_PathDivChkAntSwitchCallback( ++ PRT_TIMER pTimer ++ ); ++ ++VOID ++odm_PathDivChkAntSwitchWorkitemCallback( ++ IN PVOID pContext ++ ); ++ ++VOID odm_SetRespPath_92C( IN PADAPTER Adapter, IN u1Byte DefaultRespPath); ++VOID odm_OFDMTXPathDiversity_92C( IN PADAPTER Adapter); ++VOID odm_CCKTXPathDiversity_92C( IN PADAPTER Adapter); ++VOID odm_ResetPathDiversity_92C( IN PADAPTER Adapter); ++ ++//Start-------------------- RX High Power------------------------// ++VOID odm_RXHPInit( IN PDM_ODM_T pDM_Odm); ++VOID odm_RXHP( IN PDM_ODM_T pDM_Odm); ++VOID odm_Write_RXHP( IN PDM_ODM_T pDM_Odm); ++ ++VOID odm_PSD_RXHP( IN PDM_ODM_T pDM_Odm); ++VOID odm_PSD_RXHPCallback( PRT_TIMER pTimer); ++VOID odm_PSD_RXHPWorkitemCallback( IN PVOID pContext); ++//End--------------------- RX High Power -----------------------// ++ ++VOID ++odm_PathDivInit( IN PDM_ODM_T pDM_Odm); ++ ++VOID ++odm_SetRespPath_92C( ++ IN PADAPTER Adapter, ++ IN u1Byte DefaultRespPath ++ ); ++ ++#endif ++//END-------------------PSD-----------------------// ++ ++VOID ++odm_RefreshRateAdaptiveMaskMP( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_RefreshRateAdaptiveMaskCE( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_RefreshRateAdaptiveMaskAPADSL( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_DynamicTxPowerInit( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_DynamicTxPowerRestorePowerIndex( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_DynamicTxPowerNIC( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE)) ++VOID ++odm_DynamicTxPowerSavePowerIndex( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_DynamicTxPowerWritePowerIndex( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte Value); ++ ++VOID ++odm_DynamicTxPower_92C( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_DynamicTxPower_92D( ++ IN PDM_ODM_T pDM_Odm ++ ); ++#endif ++ ++ ++VOID ++odm_RSSIMonitorInit( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_RSSIMonitorCheckMP( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_RSSIMonitorCheckCE( ++ IN PDM_ODM_T pDM_Odm ++ ); ++VOID ++odm_RSSIMonitorCheckAP( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++ ++ ++VOID ++odm_RSSIMonitorCheck( ++ IN PDM_ODM_T pDM_Odm ++ ); ++VOID ++odm_DynamicTxPower( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_DynamicTxPowerAP( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++ ++VOID ++odm_SwAntDivInit( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_SwAntDivInit_NIC( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_SwAntDivChkAntSwitch( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte Step ++ ); ++ ++VOID ++odm_SwAntDivChkAntSwitchNIC( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte Step ++ ); ++ ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++VOID ++odm_SwAntDivChkAntSwitchCallback( ++ PRT_TIMER pTimer ++); ++VOID ++odm_SwAntDivChkAntSwitchWorkitemCallback( ++ IN PVOID pContext ++ ); ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++VOID odm_SwAntDivChkAntSwitchCallback(void *FunctionContext); ++#elif (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++VOID odm_SwAntDivChkAntSwitchCallback(void *FunctionContext); ++#endif ++ ++ ++ ++VOID ++odm_GlobalAdapterCheck( ++ IN VOID ++ ); ++ ++VOID ++odm_RefreshRateAdaptiveMask( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++ODM_TXPowerTrackingCheck( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_TXPowerTrackingCheckAP( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++ ++ ++ ++ ++ ++ ++VOID ++odm_RateAdaptiveMaskInit( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_TXPowerTrackingThermalMeterInit( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++ ++VOID ++odm_TXPowerTrackingInit( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_TXPowerTrackingCheckMP( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++ ++VOID ++odm_TXPowerTrackingCheckCE( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_MP)) ++ ++VOID ++ODM_RateAdaptiveStateApInit( ++ IN PADAPTER Adapter , ++ IN PRT_WLAN_STA pEntry ++ ); ++ ++VOID ++odm_TXPowerTrackingCallbackThermalMeter92C( ++ IN PADAPTER Adapter ++ ); ++ ++VOID ++odm_TXPowerTrackingCallbackRXGainThermalMeter92D( ++ IN PADAPTER Adapter ++ ); ++ ++VOID ++odm_TXPowerTrackingCallbackThermalMeter92D( ++ IN PADAPTER Adapter ++ ); ++ ++VOID ++odm_TXPowerTrackingDirectCall92C( ++ IN PADAPTER Adapter ++ ); ++ ++VOID ++odm_TXPowerTrackingThermalMeterCheck( ++ IN PADAPTER Adapter ++ ); ++ ++#endif ++ ++VOID ++odm_EdcaTurboCheck( ++ IN PDM_ODM_T pDM_Odm ++ ); ++VOID ++ODM_EdcaTurboInit( ++ IN PDM_ODM_T pDM_Odm ++); ++ ++#if(DM_ODM_SUPPORT_TYPE==ODM_MP) ++VOID ++odm_EdcaTurboCheckMP( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++//check if edca turbo is disabled ++BOOLEAN ++odm_IsEdcaTurboDisable( ++ IN PDM_ODM_T pDM_Odm ++); ++//choose edca paramter for special IOT case ++VOID ++ODM_EdcaParaSelByIot( ++ IN PDM_ODM_T pDM_Odm, ++ OUT u4Byte *EDCA_BE_UL, ++ OUT u4Byte *EDCA_BE_DL ++ ); ++//check if it is UL or DL ++VOID ++odm_EdcaChooseTrafficIdx( ++ IN PDM_ODM_T pDM_Odm, ++ IN u8Byte cur_tx_bytes, ++ IN u8Byte cur_rx_bytes, ++ IN BOOLEAN bBiasOnRx, ++ OUT BOOLEAN *pbIsCurRDLState ++ ); ++ ++#elif (DM_ODM_SUPPORT_TYPE==ODM_CE) ++VOID ++odm_EdcaTurboCheckCE( ++ IN PDM_ODM_T pDM_Odm ++ ); ++#else ++VOID ++odm_IotEngine( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++odm_EdcaParaInit( ++ IN PDM_ODM_T pDM_Odm ++ ); ++#endif ++ ++ ++ ++#define RxDefaultAnt1 0x65a9 ++#define RxDefaultAnt2 0x569a ++ ++VOID ++odm_InitHybridAntDiv( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++BOOLEAN ++odm_StaDefAntSel( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte OFDM_Ant1_Cnt, ++ IN u4Byte OFDM_Ant2_Cnt, ++ IN u4Byte CCK_Ant1_Cnt, ++ IN u4Byte CCK_Ant2_Cnt, ++ OUT u1Byte *pDefAnt ++ ); ++ ++VOID ++odm_SetRxIdleAnt( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte Ant, ++ IN BOOLEAN bDualPath ++); ++ ++ ++ ++VOID ++odm_HwAntDiv( ++ IN PDM_ODM_T pDM_Odm ++); ++ ++ ++ ++ ++ ++#if 0 ++//#if ((DM_ODM_SUPPORT_TYPE==ODM_AP)&&defined(HW_ANT_SWITCH)) ++VOID ++odm_HW_AntennaSwitchInit( ++ IN PDM_ODM_T pDM_Odm ++); ++ ++VOID ++odm_SetRxIdleAnt( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte Ant ++); ++ ++VOID ++odm_StaAntSelect( ++ IN PDM_ODM_T pDM_Odm, ++ IN struct stat_info *pstat ++); ++ ++VOID ++odm_HW_IdleAntennaSelect( ++ IN PDM_ODM_T pDM_Odm ++); ++ ++u1Byte ++ODM_Diversity_AntennaSelect( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte *data ++); ++#endif ++ ++ ++//============================================================ ++//3 Export Interface ++//============================================================ ++ ++// ++// 2011/09/21 MH Add to describe different team necessary resource allocate?? ++// ++VOID ++ODM_DMInit( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ ++#if (FPGA_TWO_MAC_VERIFICATION == 1) ++ odm_RateAdaptiveMaskInit(pDM_Odm); ++ return; ++#endif ++ ++ //2012.05.03 Luke: For all IC series ++ odm_CommonInfoSelfInit(pDM_Odm); ++ odm_CmnInfoInit_Debug(pDM_Odm); ++ odm_DIGInit(pDM_Odm); ++ odm_AdaptivityInit(pDM_Odm); ++ odm_RateAdaptiveMaskInit(pDM_Odm); ++ ++ if(pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) ++ { ++ ++ } ++ else if(pDM_Odm->SupportICType & ODM_IC_11N_SERIES) ++ { ++ #if (RTL8188E_SUPPORT == 1) ++ odm_PrimaryCCA_Init(pDM_Odm); // Gary ++ #endif ++ odm_DynamicBBPowerSavingInit(pDM_Odm); ++ odm_DynamicTxPowerInit(pDM_Odm); ++ odm_TXPowerTrackingInit(pDM_Odm); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ odm_PSDMonitorInit(pDM_Odm); ++ odm_RXHPInit(pDM_Odm); ++ odm_PathDivInit(pDM_Odm); //92D Path Div Init //Neil Chen ++ #endif ++ ODM_EdcaTurboInit(pDM_Odm); ++ #if (RTL8188E_SUPPORT == 1) ++ ODM_RAInfo_Init_all(pDM_Odm); ++ #endif ++ if( ( pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV ) || ++ ( pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV ) || ++ ( pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV )) ++ { ++ odm_InitHybridAntDiv(pDM_Odm); ++ } ++ else if( pDM_Odm->AntDivType == CGCS_RX_SW_ANTDIV) ++ { ++ odm_SwAntDivInit(pDM_Odm); ++ } ++ } ++} ++ ++// ++// 2011/09/20 MH This is the entry pointer for all team to execute HW out source DM. ++// You can not add any dummy function here, be care, you can only use DM structure ++// to perform any new ODM_DM. ++// ++VOID ++ODM_DMWatchdog( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ //2012.05.03 Luke: For all IC series ++ odm_GlobalAdapterCheck(); ++ odm_CmnInfoHook_Debug(pDM_Odm); ++ odm_CmnInfoUpdate_Debug(pDM_Odm); ++ odm_CommonInfoSelfUpdate(pDM_Odm); ++ odm_FalseAlarmCounterStatistics(pDM_Odm); ++ odm_RSSIMonitorCheck(pDM_Odm); ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++//#ifdef CONFIG_PLATFORM_SPRD ++ //For CE Platform(SPRD or Tablet) ++ //8723A or 8189ES platform ++ //NeilChen--2012--08--24-- ++ //Fix Leave LPS issue ++ if( (adapter_to_pwrctl(pDM_Odm->Adapter)->pwr_mode != PS_MODE_ACTIVE) &&// in LPS mode ++ ( ++ (pDM_Odm->SupportICType & (ODM_RTL8723A ) )|| ++ (pDM_Odm->SupportICType & (ODM_RTL8188E) )//&&((pDM_Odm->SupportInterface == ODM_ITRF_SDIO)) ) ++ ++ ) ++ ) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("----Step1: odm_DIG is in LPS mode\n")); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("---Step2: 8723AS is in LPS mode\n")); ++ odm_DIGbyRSSI_LPS(pDM_Odm); ++ } ++ else ++//#endif ++#endif ++ { ++ odm_DIG(pDM_Odm); ++ } ++ ++ ++ odm_CCKPacketDetectionThresh(pDM_Odm); ++ ++ if(*(pDM_Odm->pbPowerSaving)==TRUE) ++ return; ++ ++ odm_Adaptivity(pDM_Odm, pDM_Odm->DM_DigTable.CurIGValue); ++ ++ ++ odm_RefreshRateAdaptiveMask(pDM_Odm); ++ ++ #if (RTL8192D_SUPPORT == 1) ++ ODM_DynamicEarlyMode(pDM_Odm); ++ #endif ++ odm_DynamicBBPowerSaving(pDM_Odm); ++ #if (RTL8188E_SUPPORT == 1) ++ odm_DynamicPrimaryCCA(pDM_Odm); ++ #endif ++ if( ( pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV ) || ++ ( pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV ) || ++ ( pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV )) ++ { ++ odm_HwAntDiv(pDM_Odm); ++ } ++ else if( pDM_Odm->AntDivType == CGCS_RX_SW_ANTDIV) ++ { ++ odm_SwAntDivChkAntSwitch(pDM_Odm, SWAW_STEP_PEAK); ++ } ++ ++ if(pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) ++ { ++ ++ } ++ else if(pDM_Odm->SupportICType & ODM_IC_11N_SERIES) ++ { ++ ODM_TXPowerTrackingCheck(pDM_Odm); ++ odm_EdcaTurboCheck(pDM_Odm); ++ odm_DynamicTxPower(pDM_Odm); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ odm_RXHP(pDM_Odm); ++ #endif ++ } ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ odm_dtc(pDM_Odm); ++#endif ++} ++ ++ ++// ++// Init /.. Fixed HW value. Only init time. ++// ++VOID ++ODM_CmnInfoInit( ++ IN PDM_ODM_T pDM_Odm, ++ IN ODM_CMNINFO_E CmnInfo, ++ IN u4Byte Value ++ ) ++{ ++ //ODM_RT_TRACE(pDM_Odm,); ++ ++ // ++ // This section is used for init value ++ // ++ switch (CmnInfo) ++ { ++ // ++ // Fixed ODM value. ++ // ++ case ODM_CMNINFO_ABILITY: ++ pDM_Odm->SupportAbility = (u4Byte)Value; ++ break; ++ case ODM_CMNINFO_PLATFORM: ++ pDM_Odm->SupportPlatform = (u1Byte)Value; ++ break; ++ ++ case ODM_CMNINFO_INTERFACE: ++ pDM_Odm->SupportInterface = (u1Byte)Value; ++ break; ++ ++ case ODM_CMNINFO_MP_TEST_CHIP: ++ pDM_Odm->bIsMPChip= (u1Byte)Value; ++ break; ++ ++ case ODM_CMNINFO_IC_TYPE: ++ pDM_Odm->SupportICType = Value; ++ break; ++ ++ case ODM_CMNINFO_CUT_VER: ++ pDM_Odm->CutVersion = (u1Byte)Value; ++ break; ++ ++ case ODM_CMNINFO_FAB_VER: ++ pDM_Odm->FabVersion = (u1Byte)Value; ++ break; ++ ++ case ODM_CMNINFO_RF_TYPE: ++ pDM_Odm->RFType = (u1Byte)Value; ++ break; ++ ++ case ODM_CMNINFO_RF_ANTENNA_TYPE: ++ pDM_Odm->AntDivType= (u1Byte)Value; ++ break; ++ ++ case ODM_CMNINFO_BOARD_TYPE: ++ pDM_Odm->BoardType = (u1Byte)Value; ++ break; ++ ++ case ODM_CMNINFO_EXT_LNA: ++ pDM_Odm->ExtLNA = (u1Byte)Value; ++ break; ++ ++ case ODM_CMNINFO_EXT_PA: ++ pDM_Odm->ExtPA = (u1Byte)Value; ++ break; ++ ++ case ODM_CMNINFO_EXT_TRSW: ++ pDM_Odm->ExtTRSW = (u1Byte)Value; ++ break; ++ case ODM_CMNINFO_PATCH_ID: ++ pDM_Odm->PatchID = (u1Byte)Value; ++ break; ++ case ODM_CMNINFO_BINHCT_TEST: ++ pDM_Odm->bInHctTest = (BOOLEAN)Value; ++ break; ++ case ODM_CMNINFO_BWIFI_TEST: ++ pDM_Odm->bWIFITest = (BOOLEAN)Value; ++ break; ++ ++ case ODM_CMNINFO_SMART_CONCURRENT: ++ pDM_Odm->bDualMacSmartConcurrent = (BOOLEAN )Value; ++ break; ++ ++ //To remove the compiler warning, must add an empty default statement to handle the other values. ++ default: ++ //do nothing ++ break; ++ ++ } ++ ++ ++} ++ ++ ++VOID ++ODM_CmnInfoHook( ++ IN PDM_ODM_T pDM_Odm, ++ IN ODM_CMNINFO_E CmnInfo, ++ IN PVOID pValue ++ ) ++{ ++ // ++ // Hook call by reference pointer. ++ // ++ switch (CmnInfo) ++ { ++ // ++ // Dynamic call by reference pointer. ++ // ++ case ODM_CMNINFO_MAC_PHY_MODE: ++ pDM_Odm->pMacPhyMode = (u1Byte *)pValue; ++ break; ++ ++ case ODM_CMNINFO_TX_UNI: ++ pDM_Odm->pNumTxBytesUnicast = (u8Byte *)pValue; ++ break; ++ ++ case ODM_CMNINFO_RX_UNI: ++ pDM_Odm->pNumRxBytesUnicast = (u8Byte *)pValue; ++ break; ++ ++ case ODM_CMNINFO_WM_MODE: ++ pDM_Odm->pWirelessMode = (u1Byte *)pValue; ++ break; ++ ++ case ODM_CMNINFO_BAND: ++ pDM_Odm->pBandType = (u1Byte *)pValue; ++ break; ++ ++ case ODM_CMNINFO_SEC_CHNL_OFFSET: ++ pDM_Odm->pSecChOffset = (u1Byte *)pValue; ++ break; ++ ++ case ODM_CMNINFO_SEC_MODE: ++ pDM_Odm->pSecurity = (u1Byte *)pValue; ++ break; ++ ++ case ODM_CMNINFO_BW: ++ pDM_Odm->pBandWidth = (u1Byte *)pValue; ++ break; ++ ++ case ODM_CMNINFO_CHNL: ++ pDM_Odm->pChannel = (u1Byte *)pValue; ++ break; ++ ++ case ODM_CMNINFO_DMSP_GET_VALUE: ++ pDM_Odm->pbGetValueFromOtherMac = (BOOLEAN *)pValue; ++ break; ++ ++ case ODM_CMNINFO_BUDDY_ADAPTOR: ++ pDM_Odm->pBuddyAdapter = (PADAPTER *)pValue; ++ break; ++ ++ case ODM_CMNINFO_DMSP_IS_MASTER: ++ pDM_Odm->pbMasterOfDMSP = (BOOLEAN *)pValue; ++ break; ++ ++ case ODM_CMNINFO_SCAN: ++ pDM_Odm->pbScanInProcess = (BOOLEAN *)pValue; ++ break; ++ ++ case ODM_CMNINFO_POWER_SAVING: ++ pDM_Odm->pbPowerSaving = (BOOLEAN *)pValue; ++ break; ++ ++ case ODM_CMNINFO_ONE_PATH_CCA: ++ pDM_Odm->pOnePathCCA = (u1Byte *)pValue; ++ break; ++ ++ case ODM_CMNINFO_DRV_STOP: ++ pDM_Odm->pbDriverStopped = (BOOLEAN *)pValue; ++ break; ++ ++ case ODM_CMNINFO_PNP_IN: ++ pDM_Odm->pbDriverIsGoingToPnpSetPowerSleep = (BOOLEAN *)pValue; ++ break; ++ ++ case ODM_CMNINFO_INIT_ON: ++ pDM_Odm->pinit_adpt_in_progress = (BOOLEAN *)pValue; ++ break; ++ ++ case ODM_CMNINFO_ANT_TEST: ++ pDM_Odm->pAntennaTest = (u1Byte *)pValue; ++ break; ++ ++ case ODM_CMNINFO_NET_CLOSED: ++ pDM_Odm->pbNet_closed = (BOOLEAN *)pValue; ++ break; ++ case ODM_CMNINFO_MP_MODE: ++ pDM_Odm->mp_mode = (u1Byte *)pValue; ++ break; ++ ++ //case ODM_CMNINFO_BT_COEXIST: ++ // pDM_Odm->BTCoexist = (BOOLEAN *)pValue; ++ ++ //case ODM_CMNINFO_STA_STATUS: ++ //pDM_Odm->pODM_StaInfo[] = (PSTA_INFO_T)pValue; ++ //break; ++ ++ //case ODM_CMNINFO_PHY_STATUS: ++ // pDM_Odm->pPhyInfo = (ODM_PHY_INFO *)pValue; ++ // break; ++ ++ //case ODM_CMNINFO_MAC_STATUS: ++ // pDM_Odm->pMacInfo = (ODM_MAC_INFO *)pValue; ++ // break; ++ //To remove the compiler warning, must add an empty default statement to handle the other values. ++ default: ++ //do nothing ++ break; ++ ++ } ++ ++} ++ ++ ++VOID ++ODM_CmnInfoPtrArrayHook( ++ IN PDM_ODM_T pDM_Odm, ++ IN ODM_CMNINFO_E CmnInfo, ++ IN u2Byte Index, ++ IN PVOID pValue ++ ) ++{ ++ // ++ // Hook call by reference pointer. ++ // ++ switch (CmnInfo) ++ { ++ // ++ // Dynamic call by reference pointer. ++ // ++ case ODM_CMNINFO_STA_STATUS: ++ pDM_Odm->pODM_StaInfo[Index] = (PSTA_INFO_T)pValue; ++ break; ++ //To remove the compiler warning, must add an empty default statement to handle the other values. ++ default: ++ //do nothing ++ break; ++ } ++ ++} ++ ++ ++// ++// Update Band/CHannel/.. The values are dynamic but non-per-packet. ++// ++VOID ++ODM_CmnInfoUpdate( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte CmnInfo, ++ IN u8Byte Value ++ ) ++{ ++ // ++ // This init variable may be changed in run time. ++ // ++ switch (CmnInfo) ++ { ++ case ODM_CMNINFO_ABILITY: ++ pDM_Odm->SupportAbility = (u4Byte)Value; ++ break; ++ ++ case ODM_CMNINFO_RF_TYPE: ++ pDM_Odm->RFType = (u1Byte)Value; ++ break; ++ ++ case ODM_CMNINFO_WIFI_DIRECT: ++ pDM_Odm->bWIFI_Direct = (BOOLEAN)Value; ++ break; ++ ++ case ODM_CMNINFO_WIFI_DISPLAY: ++ pDM_Odm->bWIFI_Display = (BOOLEAN)Value; ++ break; ++ ++ case ODM_CMNINFO_LINK: ++ pDM_Odm->bLinked = (BOOLEAN)Value; ++ break; ++ case ODM_CMNINFO_STATION_STATE: ++ pDM_Odm->bsta_state = (BOOLEAN)Value; ++ break; ++ case ODM_CMNINFO_RSSI_MIN: ++ pDM_Odm->RSSI_Min= (u1Byte)Value; ++ break; ++ ++ case ODM_CMNINFO_DBG_COMP: ++ pDM_Odm->DebugComponents = Value; ++ break; ++ ++ case ODM_CMNINFO_DBG_LEVEL: ++ pDM_Odm->DebugLevel = (u4Byte)Value; ++ break; ++ case ODM_CMNINFO_RA_THRESHOLD_HIGH: ++ pDM_Odm->RateAdaptive.HighRSSIThresh = (u1Byte)Value; ++ break; ++ ++ case ODM_CMNINFO_RA_THRESHOLD_LOW: ++ pDM_Odm->RateAdaptive.LowRSSIThresh = (u1Byte)Value; ++ break; ++#if(BT_30_SUPPORT == 1) ++ // The following is for BT HS mode and BT coexist mechanism. ++ case ODM_CMNINFO_BT_DISABLED: ++ pDM_Odm->bBtDisabled = (BOOLEAN)Value; ++ break; ++ ++ case ODM_CMNINFO_BT_OPERATION: ++ pDM_Odm->bBtHsOperation = (BOOLEAN)Value; ++ break; ++ ++ case ODM_CMNINFO_BT_DIG: ++ pDM_Odm->btHsDigVal = (u1Byte)Value; ++ break; ++ ++ case ODM_CMNINFO_BT_BUSY: ++ pDM_Odm->bBtBusy = (BOOLEAN)Value; ++ break; ++ ++ case ODM_CMNINFO_BT_DISABLE_EDCA: ++ pDM_Odm->bBtDisableEdcaTurbo = (BOOLEAN)Value; ++ break; ++#endif ++ ++ } ++ ++ ++} ++ ++VOID ++odm_CommonInfoSelfInit( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ pDM_Odm->bCckHighPower = (BOOLEAN) ODM_GetBBReg(pDM_Odm, 0x824, BIT9); ++ pDM_Odm->RFPathRxEnable = (u1Byte) ODM_GetBBReg(pDM_Odm, 0xc04, 0x0F); ++#if (DM_ODM_SUPPORT_TYPE != ODM_CE) ++ pDM_Odm->pbNet_closed = &pDM_Odm->BOOLEAN_temp; ++#endif ++ if(pDM_Odm->SupportICType & (ODM_RTL8192C|ODM_RTL8192D)) ++ { ++#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) ++ pDM_Odm->AntDivType = CG_TRX_HW_ANTDIV; ++#elif (defined(CONFIG_SW_ANTENNA_DIVERSITY)) ++ pDM_Odm->AntDivType = CGCS_RX_SW_ANTDIV; ++#endif ++ } ++ if(pDM_Odm->SupportICType & (ODM_RTL8723A)) ++ pDM_Odm->AntDivType = CGCS_RX_SW_ANTDIV; ++ ++ ODM_InitDebugSetting(pDM_Odm); ++} ++ ++VOID ++odm_CommonInfoSelfUpdate( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ u1Byte EntryCnt=0; ++ u1Byte i; ++ PSTA_INFO_T pEntry; ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ ++ pEntry = pDM_Odm->pODM_StaInfo[0]; ++ if(pMgntInfo->mAssoc) ++ { ++ pEntry->bUsed=TRUE; ++ for (i=0; i<6; i++) ++ pEntry->MacAddr[i] = pMgntInfo->Bssid[i]; ++ } ++ else ++ { ++ pEntry->bUsed=FALSE; ++ for (i=0; i<6; i++) ++ pEntry->MacAddr[i] = 0; ++ } ++#endif ++ ++ ++ if(*(pDM_Odm->pBandWidth) == ODM_BW40M) ++ { ++ if(*(pDM_Odm->pSecChOffset) == 1) ++ pDM_Odm->ControlChannel = *(pDM_Odm->pChannel) -2; ++ else if(*(pDM_Odm->pSecChOffset) == 2) ++ pDM_Odm->ControlChannel = *(pDM_Odm->pChannel) +2; ++ } ++ else ++ pDM_Odm->ControlChannel = *(pDM_Odm->pChannel); ++ ++ for (i=0; ipODM_StaInfo[i]; ++ if(IS_STA_VALID(pEntry)) ++ EntryCnt++; ++ } ++ if(EntryCnt == 1) ++ pDM_Odm->bOneEntryOnly = TRUE; ++ else ++ pDM_Odm->bOneEntryOnly = FALSE; ++} ++ ++VOID ++odm_CmnInfoInit_Debug( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoInit_Debug==>\n")); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportPlatform=%d\n",pDM_Odm->SupportPlatform) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportAbility=0x%x\n",pDM_Odm->SupportAbility) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportInterface=%d\n",pDM_Odm->SupportInterface) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportICType=0x%x\n",pDM_Odm->SupportICType) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("CutVersion=%d\n",pDM_Odm->CutVersion) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("FabVersion=%d\n",pDM_Odm->FabVersion) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("RFType=%d\n",pDM_Odm->RFType) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("BoardType=%d\n",pDM_Odm->BoardType) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtLNA=%d\n",pDM_Odm->ExtLNA) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtPA=%d\n",pDM_Odm->ExtPA) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtTRSW=%d\n",pDM_Odm->ExtTRSW) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("PatchID=%d\n",pDM_Odm->PatchID) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("bInHctTest=%d\n",pDM_Odm->bInHctTest) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFITest=%d\n",pDM_Odm->bWIFITest) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("bDualMacSmartConcurrent=%d\n",pDM_Odm->bDualMacSmartConcurrent) ); ++ ++} ++ ++VOID ++odm_CmnInfoHook_Debug( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoHook_Debug==>\n")); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pNumTxBytesUnicast=%llu\n",*(pDM_Odm->pNumTxBytesUnicast)) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pNumRxBytesUnicast=%llu\n",*(pDM_Odm->pNumRxBytesUnicast)) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pWirelessMode=0x%x\n",*(pDM_Odm->pWirelessMode)) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pSecChOffset=%d\n",*(pDM_Odm->pSecChOffset)) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pSecurity=%d\n",*(pDM_Odm->pSecurity)) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pBandWidth=%d\n",*(pDM_Odm->pBandWidth)) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pChannel=%d\n",*(pDM_Odm->pChannel)) ); ++ ++#if (RTL8192D_SUPPORT==1) ++ if(pDM_Odm->pBandType) ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pBandType=%d\n",*(pDM_Odm->pBandType)) ); ++ if(pDM_Odm->pMacPhyMode) ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pMacPhyMode=%d\n",*(pDM_Odm->pMacPhyMode)) ); ++ if(pDM_Odm->pBuddyAdapter) ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbGetValueFromOtherMac=%d\n",*(pDM_Odm->pbGetValueFromOtherMac)) ); ++ if(pDM_Odm->pBuddyAdapter) ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pBuddyAdapter=%p\n",*(pDM_Odm->pBuddyAdapter)) ); ++ if(pDM_Odm->pbMasterOfDMSP) ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbMasterOfDMSP=%d\n",*(pDM_Odm->pbMasterOfDMSP)) ); ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbScanInProcess=%d\n",*(pDM_Odm->pbScanInProcess)) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbPowerSaving=%d\n",*(pDM_Odm->pbPowerSaving)) ); ++ ++ if(pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pOnePathCCA=%d\n",*(pDM_Odm->pOnePathCCA)) ); ++} ++ ++VOID ++odm_CmnInfoUpdate_Debug( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoUpdate_Debug==>\n")); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFI_Direct=%d\n",pDM_Odm->bWIFI_Direct) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFI_Display=%d\n",pDM_Odm->bWIFI_Display) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("bLinked=%d\n",pDM_Odm->bLinked) ); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("RSSI_Min=%d\n",pDM_Odm->RSSI_Min) ); ++} ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++VOID ++ODM_InitAllWorkItems(IN PDM_ODM_T pDM_Odm ) ++{ ++#if USE_WORKITEM ++ PADAPTER pAdapter = pDM_Odm->Adapter; ++ ++ ODM_InitializeWorkItem( pDM_Odm, ++ &pDM_Odm->DM_SWAT_Table.SwAntennaSwitchWorkitem, ++ (RT_WORKITEM_CALL_BACK)odm_SwAntDivChkAntSwitchWorkitemCallback, ++ (PVOID)pAdapter, ++ "AntennaSwitchWorkitem" ++ ); ++ ++ ODM_InitializeWorkItem( ++ pDM_Odm, ++ &(pDM_Odm->PathDivSwitchWorkitem), ++ (RT_WORKITEM_CALL_BACK)odm_PathDivChkAntSwitchWorkitemCallback, ++ (PVOID)pAdapter, ++ "SWAS_WorkItem"); ++ ++ ODM_InitializeWorkItem( ++ pDM_Odm, ++ &(pDM_Odm->CCKPathDiversityWorkitem), ++ (RT_WORKITEM_CALL_BACK)odm_CCKTXPathDiversityWorkItemCallback, ++ (PVOID)pAdapter, ++ "CCKTXPathDiversityWorkItem"); ++#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) ++#if (RTL8188E_SUPPORT == 1) ++ ODM_InitializeWorkItem( ++ pDM_Odm, ++ &(pDM_Odm->FastAntTrainingWorkitem), ++ (RT_WORKITEM_CALL_BACK)odm_FastAntTrainingWorkItemCallback, ++ (PVOID)pAdapter, ++ "FastAntTrainingWorkitem"); ++#endif ++#endif ++ ODM_InitializeWorkItem( ++ pDM_Odm, ++ &(pDM_Odm->DM_RXHP_Table.PSDTimeWorkitem), ++ (RT_WORKITEM_CALL_BACK)odm_PSD_RXHPWorkitemCallback, ++ (PVOID)pAdapter, ++ "PSDRXHP_WorkItem"); ++#endif ++} ++ ++VOID ++ODM_FreeAllWorkItems(IN PDM_ODM_T pDM_Odm ) ++{ ++#if USE_WORKITEM ++ ODM_FreeWorkItem( &(pDM_Odm->DM_SWAT_Table.SwAntennaSwitchWorkitem)); ++ ++ ODM_FreeWorkItem(&(pDM_Odm->PathDivSwitchWorkitem)); ++ ++ ODM_FreeWorkItem(&(pDM_Odm->CCKPathDiversityWorkitem)); ++ ++ ODM_FreeWorkItem(&(pDM_Odm->FastAntTrainingWorkitem)); ++ ++ ODM_FreeWorkItem((&pDM_Odm->DM_RXHP_Table.PSDTimeWorkitem)); ++#endif ++ ++} ++#endif ++ ++/* ++VOID ++odm_FindMinimumRSSI( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ u4Byte i; ++ u1Byte RSSI_Min = 0xFF; ++ ++ for(i=0; ipODM_StaInfo[i] != NULL) ++ if(IS_STA_VALID(pDM_Odm->pODM_StaInfo[i]) ) ++ { ++ if(pDM_Odm->pODM_StaInfo[i]->RSSI_Ave < RSSI_Min) ++ { ++ RSSI_Min = pDM_Odm->pODM_StaInfo[i]->RSSI_Ave; ++ } ++ } ++ } ++ ++ pDM_Odm->RSSI_Min = RSSI_Min; ++ ++} ++ ++VOID ++odm_IsLinked( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ u4Byte i; ++ BOOLEAN Linked = FALSE; ++ ++ for(i=0; ipODM_StaInfo[i]) ) ++ { ++ Linked = TRUE; ++ break; ++ } ++ ++ } ++ ++ pDM_Odm->bLinked = Linked; ++} ++*/ ++ ++ ++//3============================================================ ++//3 DIG ++//3============================================================ ++/*----------------------------------------------------------------------------- ++ * Function: odm_DIGInit() ++ * ++ * Overview: Set DIG scheme init value. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * ++ *---------------------------------------------------------------------------*/ ++VOID ++ODM_ChangeDynamicInitGainThresh( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte DM_Type, ++ IN u4Byte DM_Value ++ ) ++{ ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ ++ if (DM_Type == DIG_TYPE_THRESH_HIGH) ++ { ++ pDM_DigTable->RssiHighThresh = DM_Value; ++ } ++ else if (DM_Type == DIG_TYPE_THRESH_LOW) ++ { ++ pDM_DigTable->RssiLowThresh = DM_Value; ++ } ++ else if (DM_Type == DIG_TYPE_ENABLE) ++ { ++ pDM_DigTable->Dig_Enable_Flag = TRUE; ++ } ++ else if (DM_Type == DIG_TYPE_DISABLE) ++ { ++ pDM_DigTable->Dig_Enable_Flag = FALSE; ++ } ++ else if (DM_Type == DIG_TYPE_BACKOFF) ++ { ++ if(DM_Value > 30) ++ DM_Value = 30; ++ pDM_DigTable->BackoffVal = (u1Byte)DM_Value; ++ } ++ else if(DM_Type == DIG_TYPE_RX_GAIN_MIN) ++ { ++ if(DM_Value == 0) ++ DM_Value = 0x1; ++ pDM_DigTable->rx_gain_range_min = (u1Byte)DM_Value; ++ } ++ else if(DM_Type == DIG_TYPE_RX_GAIN_MAX) ++ { ++ if(DM_Value > 0x50) ++ DM_Value = 0x50; ++ pDM_DigTable->rx_gain_range_max = (u1Byte)DM_Value; ++ } ++} /* DM_ChangeDynamicInitGainThresh */ ++ ++int getIGIForDiff(int value_IGI) ++{ ++ #define ONERCCA_LOW_TH 0x30 ++ #define ONERCCA_LOW_DIFF 8 ++ ++ if (value_IGI < ONERCCA_LOW_TH) { ++ if ((ONERCCA_LOW_TH - value_IGI) < ONERCCA_LOW_DIFF) ++ return ONERCCA_LOW_TH; ++ else ++ return value_IGI + ONERCCA_LOW_DIFF; ++ } else { ++ return value_IGI; ++ } ++} ++ ++ ++// Add by Neil Chen to enable edcca to MP Platform ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ++VOID ++odm_EnableEDCCA( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ ++ // This should be moved out of OUTSRC ++ PADAPTER pAdapter = pDM_Odm->Adapter; ++ // Enable EDCCA. The value is suggested by SD3 Wilson. ++ ++ // ++ // Revised for ASUS 11b/g performance issues, suggested by BB Neil, 2012.04.13. ++ // ++ if((pDM_Odm->SupportICType == ODM_RTL8723A)&&(IS_WIRELESS_MODE_G(pAdapter))) ++ { ++ //PlatformEFIOWrite1Byte(Adapter, rOFDM0_ECCAThreshold, 0x00); ++ ODM_Write1Byte(pDM_Odm,rOFDM0_ECCAThreshold,0x00); ++ ODM_Write1Byte(pDM_Odm,rOFDM0_ECCAThreshold+2,0xFD); ++ ++ } ++ else ++ { ++ //PlatformEFIOWrite1Byte(Adapter, rOFDM0_ECCAThreshold, 0x03); ++ ODM_Write1Byte(pDM_Odm,rOFDM0_ECCAThreshold,0x03); ++ ODM_Write1Byte(pDM_Odm,rOFDM0_ECCAThreshold+2,0x00); ++ } ++ ++ //PlatformEFIOWrite1Byte(Adapter, rOFDM0_ECCAThreshold+2, 0x00); ++} ++ ++VOID ++odm_DisableEDCCA( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ // Disable EDCCA.. ++ ODM_Write1Byte(pDM_Odm, rOFDM0_ECCAThreshold, 0x7f); ++ ODM_Write1Byte(pDM_Odm, rOFDM0_ECCAThreshold+2, 0x7f); ++} ++ ++// ++// Description: According to initial gain value to determine to enable or disable EDCCA. ++// ++// Suggested by SD3 Wilson. Added by tynli. 2011.11.25. ++// ++VOID ++odm_DynamicEDCCA( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ PADAPTER pAdapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ u1Byte RegC50, RegC58; ++ BOOLEAN bEDCCAenable = FALSE; ++ ++ RegC50 = (u1Byte)ODM_GetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskByte0); ++ RegC58 = (u1Byte)ODM_GetBBReg(pDM_Odm, rOFDM0_XBAGCCore1, bMaskByte0); ++ ++ ++ if((RegC50 > 0x28 && RegC58 > 0x28) || ++ ((pDM_Odm->SupportICType == ODM_RTL8723A && IS_WIRELESS_MODE_G(pAdapter) && RegC50>0x26)) || ++ (pDM_Odm->SupportICType == ODM_RTL8188E && RegC50 > 0x28)) ++ { ++ if(!pHalData->bPreEdccaEnable) ++ { ++ odm_EnableEDCCA(pDM_Odm); ++ pHalData->bPreEdccaEnable = TRUE; ++ } ++ ++ } ++ else if((RegC50 < 0x25 && RegC58 < 0x25) || (pDM_Odm->SupportICType == ODM_RTL8188E && RegC50 < 0x25)) ++ { ++ if(pHalData->bPreEdccaEnable) ++ { ++ odm_DisableEDCCA(pDM_Odm); ++ pHalData->bPreEdccaEnable = FALSE; ++ } ++ } ++} ++ ++ ++#endif // end MP platform support ++ ++VOID ++ODM_Write_DIG( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte CurrentIGI ++ ) ++{ ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("ODM_REG(IGI_A,pDM_Odm)=0x%x, ODM_BIT(IGI,pDM_Odm)=0x%x \n", ++ ODM_REG(IGI_A,pDM_Odm),ODM_BIT(IGI,pDM_Odm))); ++ ++ if(pDM_DigTable->CurIGValue != CurrentIGI)//if(pDM_DigTable->PreIGValue != CurrentIGI) ++ { ++ if(pDM_Odm->SupportPlatform & (ODM_CE|ODM_MP)) ++ { ++ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A,pDM_Odm), ODM_BIT(IGI,pDM_Odm), CurrentIGI); ++ if(pDM_Odm->SupportICType != ODM_RTL8188E) ++ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B,pDM_Odm), ODM_BIT(IGI,pDM_Odm), CurrentIGI); ++ } ++ else if(pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) ++ { ++ switch(*(pDM_Odm->pOnePathCCA)) ++ { ++ case ODM_CCA_2R: ++ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A,pDM_Odm), ODM_BIT(IGI,pDM_Odm), CurrentIGI); ++ if(pDM_Odm->SupportICType != ODM_RTL8188E) ++ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B,pDM_Odm), ODM_BIT(IGI,pDM_Odm), CurrentIGI); ++ break; ++ case ODM_CCA_1R_A: ++ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A,pDM_Odm), ODM_BIT(IGI,pDM_Odm), CurrentIGI); ++ if(pDM_Odm->SupportICType != ODM_RTL8188E) ++ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B,pDM_Odm), ODM_BIT(IGI,pDM_Odm), getIGIForDiff(CurrentIGI)); ++ break; ++ case ODM_CCA_1R_B: ++ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A,pDM_Odm), ODM_BIT(IGI,pDM_Odm), getIGIForDiff(CurrentIGI)); ++ if(pDM_Odm->SupportICType != ODM_RTL8188E) ++ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B,pDM_Odm), ODM_BIT(IGI,pDM_Odm), CurrentIGI); ++ break; ++ } ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("CurrentIGI(0x%02x). \n",CurrentIGI)); ++ //pDM_DigTable->PreIGValue = pDM_DigTable->CurIGValue; ++ pDM_DigTable->CurIGValue = CurrentIGI; ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("ODM_Write_DIG():CurrentIGI=0x%x \n",CurrentIGI)); ++ ++// Add by Neil Chen to enable edcca to MP Platform ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ // Adjust EDCCA. ++ if(pDM_Odm->SupportICType & ODM_IC_11N_SERIES) ++ odm_DynamicEDCCA(pDM_Odm); ++#endif ++ ++ ++} ++ ++ ++//Need LPS mode for CE platform --2012--08--24--- ++//8723AS/8189ES ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ ++VOID ++odm_DIGbyRSSI_LPS( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ PADAPTER pAdapter =pDM_Odm->Adapter; ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ PFALSE_ALARM_STATISTICS pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; ++ ++#if 0 //and 2.3.5 coding rule ++ struct mlme_priv *pmlmepriv = &(pAdapter->mlmepriv); ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++#endif ++ ++ u1Byte RSSI_Lower=DM_DIG_MIN_NIC; //0x1E or 0x1C ++ u1Byte bFwCurrentInPSMode = FALSE; ++ u1Byte CurrentIGI=pDM_Odm->RSSI_Min; ++ ++ if(! (pDM_Odm->SupportICType & (ODM_RTL8723A |ODM_RTL8188E))) ++ return; ++ ++ //if((pDM_Odm->SupportInterface==ODM_ITRF_PCIE)||(pDM_Odm->SupportInterface ==ODM_ITRF_USB)) ++ // return; ++ ++ CurrentIGI=CurrentIGI+RSSI_OFFSET_DIG; ++#ifdef CONFIG_LPS ++ bFwCurrentInPSMode = adapter_to_pwrctl(pAdapter)->bFwCurrentInPSMode; ++#endif ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("==>pDM_Odm->RSSI_Min=%d ()\n",pDM_Odm->RSSI_Min)); ++ ++ // Using FW PS mode to make IGI ++ if(bFwCurrentInPSMode) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("---Neil---odm_DIG is in LPS mode\n")); ++ //Adjust by FA in LPS MODE ++ if(pFalseAlmCnt->Cnt_all> DM_DIG_FA_TH2_LPS) ++ CurrentIGI = CurrentIGI+2; ++ else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1_LPS) ++ CurrentIGI = CurrentIGI+1; ++ else if(pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0_LPS) ++ CurrentIGI = CurrentIGI-1; ++ } ++ else ++ { ++ CurrentIGI = RSSI_Lower; ++ } ++ ++ //Lower bound checking ++ ++ //RSSI Lower bound check ++ if((pDM_Odm->RSSI_Min-10) > DM_DIG_MIN_NIC) ++ RSSI_Lower =(pDM_Odm->RSSI_Min-10); ++ else ++ RSSI_Lower =DM_DIG_MIN_NIC; ++ ++ //Upper and Lower Bound checking ++ if(CurrentIGI > DM_DIG_MAX_NIC) ++ CurrentIGI=DM_DIG_MAX_NIC; ++ else if(CurrentIGI < RSSI_Lower) ++ CurrentIGI =RSSI_Lower; ++ ++ ODM_Write_DIG(pDM_Odm, CurrentIGI);//ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); ++ ++} ++#endif ++ ++VOID ++odm_AdaptivityInit( ++IN PDM_ODM_T pDM_Odm ++) ++{ ++ if(pDM_Odm->SupportICType == ODM_RTL8723B) ++ { ++ pDM_Odm->TH_L2H_ini = 0xf8; // -8 ++ } ++ if((pDM_Odm->SupportICType == ODM_RTL8192E)&&(pDM_Odm->SupportInterface == ODM_ITRF_PCIE)) ++ { ++ pDM_Odm->TH_L2H_ini = 0xf0; // -16 ++ } ++ else ++ { ++ pDM_Odm->TH_L2H_ini = 0xf9; // -7 ++ } ++ ++ pDM_Odm->TH_EDCCA_HL_diff = 7; ++ pDM_Odm->IGI_Base = 0x32; ++ pDM_Odm->IGI_target = 0x1c; ++ pDM_Odm->ForceEDCCA = 0; ++ pDM_Odm->AdapEn_RSSI = 20; ++ ++ //Reg524[11]=0 is easily to transmit packets during adaptivity test ++ ++ //ODM_SetBBReg(pDM_Odm, 0x524, BIT11, 1);// stop counting if EDCCA is asserted ++} ++ ++ ++VOID ++odm_Adaptivity( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte IGI ++) ++{ ++ s1Byte TH_L2H_dmc, TH_H2L_dmc; ++ s1Byte TH_L2H, TH_H2L, Diff, IGI_target; ++ u4Byte value32; ++ BOOLEAN EDCCA_State = 0; ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PADAPTER pAdapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ BOOLEAN bFwCurrentInPSMode=FALSE; ++ PMGNT_INFO pMgntInfo = &(pAdapter->MgntInfo); ++ ++ pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_FW_PSMODE_STATUS, (pu1Byte)(&bFwCurrentInPSMode)); ++ ++ // Disable EDCCA mode while under LPS mode, added by Roger, 2012.09.14. ++ if(bFwCurrentInPSMode) ++ return; ++#endif ++ ++ if(!(pDM_Odm->SupportAbility & ODM_BB_ADAPTIVITY)) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("Go to odm_DynamicEDCCA() \n")); ++ // Add by Neil Chen to enable edcca to MP Platform ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ // Adjust EDCCA. ++ if(pDM_Odm->SupportICType & ODM_IC_11N_SERIES) ++ odm_DynamicEDCCA(pDM_Odm); ++#endif ++ return; ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_Adaptivity() =====> \n")); ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("ForceEDCCA=%d, IGI_Base=0x%x, TH_L2H_ini = %d, TH_EDCCA_HL_diff = %d, AdapEn_RSSI = %d\n", ++ pDM_Odm->ForceEDCCA, pDM_Odm->IGI_Base, pDM_Odm->TH_L2H_ini, pDM_Odm->TH_EDCCA_HL_diff, pDM_Odm->AdapEn_RSSI)); ++ ++ if(pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) ++ ODM_SetBBReg(pDM_Odm, 0x800, BIT10, 0); //ADC_mask enable ++ ++ if((!pDM_Odm->bLinked)||(*pDM_Odm->pChannel > 149)) // Band4 doesn't need adaptivity ++ { ++ if(pDM_Odm->SupportICType & ODM_IC_11N_SERIES) ++ { ++ ODM_SetBBReg(pDM_Odm,rOFDM0_ECCAThreshold, bMaskByte0, 0x7f); ++ ODM_SetBBReg(pDM_Odm,rOFDM0_ECCAThreshold, bMaskByte2, 0x7f); ++ } ++ else ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XB_LSSIReadBack, 0xFFFF, (0x7f<<8) | 0x7f); ++ return; ++ } ++ ++#if (DM_ODM_SUPPORT_TYPE==ODM_MP) ++ if(pMgntInfo->IOTPeer == HT_IOT_PEER_BROADCOM) ++ ODM_Write1Byte(pDM_Odm, REG_TRX_SIFS_OFDM, 0x0a); ++ else ++ ODM_Write1Byte(pDM_Odm, REG_TRX_SIFS_OFDM, 0x0e); ++#endif ++ if(!pDM_Odm->ForceEDCCA) ++ { ++ if(pDM_Odm->RSSI_Min > pDM_Odm->AdapEn_RSSI) ++ EDCCA_State = 1; ++ else if(pDM_Odm->RSSI_Min < (pDM_Odm->AdapEn_RSSI - 5)) ++ EDCCA_State = 0; ++ } ++ else ++ EDCCA_State = 1; ++ //if((pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) && (*pDM_Odm->pBandType == BAND_ON_5G)) ++ //IGI_target = pDM_Odm->IGI_Base; ++ //else ++ { ++ ++ if(*pDM_Odm->pBandWidth == ODM_BW20M) //CHANNEL_WIDTH_20 ++ IGI_target = pDM_Odm->IGI_Base; ++ else if(*pDM_Odm->pBandWidth == ODM_BW40M) ++ IGI_target = pDM_Odm->IGI_Base + 2; ++ else if(*pDM_Odm->pBandWidth == ODM_BW80M) ++ IGI_target = pDM_Odm->IGI_Base + 6; ++ else ++ IGI_target = pDM_Odm->IGI_Base; ++ } ++ ++ pDM_Odm->IGI_target = (u1Byte) IGI_target; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("BandWidth=%s, IGI_target=0x%x, EDCCA_State=%d\n", ++ (*pDM_Odm->pBandWidth==ODM_BW80M)?"80M":((*pDM_Odm->pBandWidth==ODM_BW40M)?"40M":"20M"), IGI_target, EDCCA_State)); ++ ++ if(EDCCA_State == 1) ++ { ++ Diff = IGI_target -(s1Byte)IGI; ++ TH_L2H_dmc = pDM_Odm->TH_L2H_ini + Diff; ++ if(TH_L2H_dmc > 10) TH_L2H_dmc = 10; ++ TH_H2L_dmc = TH_L2H_dmc - pDM_Odm->TH_EDCCA_HL_diff; ++ } ++ else ++ { ++ TH_L2H_dmc = 0x7f; ++ TH_H2L_dmc = 0x7f; ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("IGI=0x%x, TH_L2H_dmc = %d, TH_H2L_dmc = %d\n", ++ IGI, TH_L2H_dmc, TH_H2L_dmc)); ++ ++ if(pDM_Odm->SupportICType & ODM_IC_11N_SERIES) ++ { ++ ODM_SetBBReg(pDM_Odm,rOFDM0_ECCAThreshold, bMaskByte0, (u1Byte)TH_L2H_dmc); ++ ODM_SetBBReg(pDM_Odm,rOFDM0_ECCAThreshold, bMaskByte2, (u1Byte)TH_H2L_dmc); ++ } ++ else ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XB_LSSIReadBack, 0xFFFF, ((u1Byte)TH_H2L_dmc<<8) | (u1Byte)TH_L2H_dmc); ++} ++ ++#if 1 ++VOID ++odm_DIGInit( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ ++ //pDM_DigTable->Dig_Enable_Flag = TRUE; ++ //pDM_DigTable->Dig_Ext_Port_Stage = DIG_EXT_PORT_STAGE_MAX; ++ pDM_DigTable->CurIGValue = (u1Byte) ODM_GetBBReg(pDM_Odm, ODM_REG(IGI_A,pDM_Odm), ODM_BIT(IGI,pDM_Odm)); ++ //pDM_DigTable->PreIGValue = 0x0; ++ //pDM_DigTable->CurSTAConnectState = pDM_DigTable->PreSTAConnectState = DIG_STA_DISCONNECT; ++ //pDM_DigTable->CurMultiSTAConnectState = DIG_MultiSTA_DISCONNECT; ++ pDM_DigTable->RssiLowThresh = DM_DIG_THRESH_LOW; ++ pDM_DigTable->RssiHighThresh = DM_DIG_THRESH_HIGH; ++ pDM_DigTable->FALowThresh = DM_FALSEALARM_THRESH_LOW; ++ pDM_DigTable->FAHighThresh = DM_FALSEALARM_THRESH_HIGH; ++ if(pDM_Odm->BoardType & (ODM_BOARD_EXT_PA|ODM_BOARD_EXT_LNA)) ++ { ++ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; ++ pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC; ++ } ++ else ++ { ++ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; ++ pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC; ++ } ++ pDM_DigTable->BackoffVal = DM_DIG_BACKOFF_DEFAULT; ++ pDM_DigTable->BackoffVal_range_max = DM_DIG_BACKOFF_MAX; ++ pDM_DigTable->BackoffVal_range_min = DM_DIG_BACKOFF_MIN; ++ pDM_DigTable->PreCCK_CCAThres = 0xFF; ++ pDM_DigTable->CurCCK_CCAThres = 0x83; ++ pDM_DigTable->ForbiddenIGI = DM_DIG_MIN_NIC; ++ pDM_DigTable->LargeFAHit = 0; ++ pDM_DigTable->Recover_cnt = 0; ++ pDM_DigTable->DIG_Dynamic_MIN_0 = DM_DIG_MIN_NIC; ++ pDM_DigTable->DIG_Dynamic_MIN_1 = DM_DIG_MIN_NIC; ++ pDM_DigTable->bMediaConnect_0 = FALSE; ++ pDM_DigTable->bMediaConnect_1 = FALSE; ++ ++ //To Initialize pDM_Odm->bDMInitialGainEnable == FALSE to avoid DIG error ++ pDM_Odm->bDMInitialGainEnable = TRUE; ++ ++ //To Initi BT30 IGI ++ pDM_DigTable->BT30_CurIGI=0x32; ++ ++} ++ ++VOID ++odm_DigForBtHsMode( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ pDIG_T pDM_DigTable=&pDM_Odm->DM_DigTable; ++ u1Byte digForBtHs=0; ++ u1Byte digUpBound=0x5a; ++ ++ if(pDM_Odm->bBtConnectProcess) ++ { ++ if(pDM_Odm->SupportICType&(ODM_RTL8723A)) ++ digForBtHs = 0x28; ++ else ++ digForBtHs = 0x22; ++ } ++ else ++ { ++ // ++ // Decide DIG value by BT HS RSSI. ++ // ++ digForBtHs = pDM_Odm->btHsRssi+4; ++ ++ //DIG Bound ++ if(pDM_Odm->SupportICType&(ODM_RTL8723A)) ++ digUpBound = 0x3e; ++ ++ if(digForBtHs > digUpBound) ++ digForBtHs = digUpBound; ++ if(digForBtHs < 0x1c) ++ digForBtHs = 0x1c; ++ ++ // update Current IGI ++ pDM_DigTable->BT30_CurIGI = digForBtHs; ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DigForBtHsMode() : set DigValue=0x%x\n", digForBtHs)); ++#endif ++} ++ ++VOID ++odm_DIG( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ PFALSE_ALARM_STATISTICS pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; ++ pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; ++ u1Byte DIG_Dynamic_MIN; ++ u1Byte DIG_MaxOfMin; ++ BOOLEAN FirstConnect, FirstDisConnect; ++ u1Byte dm_dig_max, dm_dig_min, offset; ++ u1Byte CurrentIGI = pDM_DigTable->CurIGValue; ++ u1Byte Adap_IGI_Upper = pDM_Odm->IGI_target + 30 + (u1Byte) pDM_Odm->TH_L2H_ini -(u1Byte) pDM_Odm->TH_EDCCA_HL_diff; ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++// This should be moved out of OUTSRC ++ PADAPTER pAdapter = pDM_Odm->Adapter; ++#if OS_WIN_FROM_WIN7(OS_VERSION) ++ if(IsAPModeExist( pAdapter) && pAdapter->bInHctTest) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: Is AP mode or In HCT Test \n")); ++ return; ++ } ++#endif ++/* ++ if (pDM_Odm->SupportICType==ODM_RTL8723B) ++ return; ++*/ ++#if(BT_30_SUPPORT == 1) ++ if(pDM_Odm->bBtHsOperation) ++ { ++ odm_DigForBtHsMode(pDM_Odm); ++ } ++#endif ++ if(!(pDM_Odm->SupportICType &(ODM_RTL8723A|ODM_RTL8188E))) ++ { ++ if(pRX_HP_Table->RXHP_flag == 1) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: In RXHP Operation \n")); ++ return; ++ } ++ } ++#endif ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++#ifdef CONFIG_SPECIAL_SETTING_FOR_FUNAI_TV ++ if((pDM_Odm->bLinked) && (pDM_Odm->Adapter->registrypriv.force_igi !=0)) ++ { ++ printk("pDM_Odm->RSSI_Min=%d \n",pDM_Odm->RSSI_Min); ++ ODM_Write_DIG(pDM_Odm,pDM_Odm->Adapter->registrypriv.force_igi); ++ return; ++ } ++#endif ++#endif ++#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ if (!((priv->up_time > 5) && (priv->up_time % 2)) ) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: Not In DIG Operation Period \n")); ++ return; ++ } ++#endif ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG()==>\n")); ++ //if(!(pDM_Odm->SupportAbility & (ODM_BB_DIG|ODM_BB_FA_CNT))) ++ if((!(pDM_Odm->SupportAbility&ODM_BB_DIG)) ||(!(pDM_Odm->SupportAbility&ODM_BB_FA_CNT))) ++ { ++#if 0 ++ if(pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) ++ { ++ if ((pDM_Odm->SupportICType == ODM_RTL8192C) && (pDM_Odm->ExtLNA == 1)) ++ CurrentIGI = 0x30; //pDM_DigTable->CurIGValue = 0x30; ++ else ++ CurrentIGI = 0x20; //pDM_DigTable->CurIGValue = 0x20; ++ ODM_Write_DIG(pDM_Odm, CurrentIGI);//ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); ++ } ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: SupportAbility ODM_BB_DIG or ODM_BB_FA_CNT is disabled\n")); ++ return; ++ } ++ ++ if(*(pDM_Odm->pbScanInProcess)) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: In Scan Progress \n")); ++ return; ++ } ++ ++ //add by Neil Chen to avoid PSD is processing ++ if(pDM_Odm->SupportICType==ODM_RTL8723A) ++ { ++ if(pDM_Odm->bDMInitialGainEnable == FALSE) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: PSD is Processing \n")); ++ return; ++ } ++ } ++ ++ if(pDM_Odm->SupportICType == ODM_RTL8192D) ++ { ++ if(*(pDM_Odm->pMacPhyMode) == ODM_DMSP) ++ { ++ if(*(pDM_Odm->pbMasterOfDMSP)) ++ { ++ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0; ++ FirstConnect = (pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == FALSE); ++ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == TRUE); ++ } ++ else ++ { ++ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_1; ++ FirstConnect = (pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1 == FALSE); ++ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1 == TRUE); ++ } ++ } ++ else ++ { ++ if(*(pDM_Odm->pBandType) == ODM_BAND_5G) ++ { ++ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0; ++ FirstConnect = (pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == FALSE); ++ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == TRUE); ++ } ++ else ++ { ++ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_1; ++ FirstConnect = (pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1 == FALSE); ++ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1 == TRUE); ++ } ++ } ++ } ++ else ++ { ++ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0; ++ FirstConnect = (pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == FALSE); ++ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == TRUE); ++ } ++ ++ //1 Boundary Decision ++ if(pDM_Odm->SupportICType & (ODM_RTL8192C) &&(pDM_Odm->BoardType & (ODM_BOARD_EXT_LNA | ODM_BOARD_EXT_PA))) ++ { ++ if(pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) ++ { ++ ++ dm_dig_max = DM_DIG_MAX_AP_HP; ++ dm_dig_min = DM_DIG_MIN_AP_HP; ++ } ++ else ++ { ++ dm_dig_max = DM_DIG_MAX_NIC_HP; ++ dm_dig_min = DM_DIG_MIN_NIC_HP; ++ } ++ DIG_MaxOfMin = DM_DIG_MAX_AP_HP; ++ } ++ else ++ { ++ if(pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) ++ { ++#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++#ifdef DFS ++ if (!priv->pmib->dot11DFSEntry.disable_DFS && ++ (OPMODE & WIFI_AP_STATE) && ++ (((pDM_Odm->ControlChannel >= 52) && ++ (pDM_Odm->ControlChannel <= 64)) || ++ ((pDM_Odm->ControlChannel >= 100) && ++ (pDM_Odm->ControlChannel <= 140)))) ++ dm_dig_max = 0x24; ++ else ++#endif ++ if (priv->pmib->dot11RFEntry.tx2path) { ++ if (*(pDM_Odm->pWirelessMode) == ODM_WM_B)//(priv->pmib->dot11BssType.net_work_type == WIRELESS_11B) ++ dm_dig_max = 0x2A; ++ else ++ dm_dig_max = 0x32; ++ } ++ else ++#endif ++ dm_dig_max = DM_DIG_MAX_AP; ++ dm_dig_min = DM_DIG_MIN_AP; ++ DIG_MaxOfMin = dm_dig_max; ++ } ++ else ++ { ++ if((pDM_Odm->SupportICType >= ODM_RTL8188E) && (pDM_Odm->SupportPlatform & (ODM_MP|ODM_CE))) ++ dm_dig_max = 0x5A; ++ else ++ dm_dig_max = DM_DIG_MAX_NIC; ++ ++ if(pDM_Odm->SupportICType != ODM_RTL8821) ++ dm_dig_min = DM_DIG_MIN_NIC; ++ else ++ dm_dig_min = 0x1C; ++ ++ DIG_MaxOfMin = DM_DIG_MAX_AP; ++ } ++ } ++ ++ ++ if(pDM_Odm->bLinked) ++ { ++ if(pDM_Odm->SupportICType&(ODM_RTL8723A/*|ODM_RTL8821*/)) ++ { ++ //2 Upper Bound ++ if(( pDM_Odm->RSSI_Min + 10) > DM_DIG_MAX_NIC ) ++ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; ++ else if(( pDM_Odm->RSSI_Min + 10) < DM_DIG_MIN_NIC ) ++ pDM_DigTable->rx_gain_range_max = DM_DIG_MIN_NIC; ++ else ++ pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 10; ++ ++ //BT is Concurrent ++ ++ if(pDM_Odm->bBtLimitedDig) ++ { ++ if(pDM_Odm->RSSI_Min>10) ++ { ++ if((pDM_Odm->RSSI_Min - 10) > DM_DIG_MAX_NIC) ++ DIG_Dynamic_MIN = DM_DIG_MAX_NIC; ++ else if((pDM_Odm->RSSI_Min - 10) < DM_DIG_MIN_NIC) ++ DIG_Dynamic_MIN = DM_DIG_MIN_NIC; ++ else ++ DIG_Dynamic_MIN = pDM_Odm->RSSI_Min - 10; ++ } ++ else ++ DIG_Dynamic_MIN=DM_DIG_MIN_NIC; ++ } ++ else ++ { ++ if((pDM_Odm->RSSI_Min + 20) > dm_dig_max ) ++ pDM_DigTable->rx_gain_range_max = dm_dig_max; ++ else if((pDM_Odm->RSSI_Min + 20) < dm_dig_min ) ++ pDM_DigTable->rx_gain_range_max = dm_dig_min; ++ else ++ pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 20; ++ ++ } ++ } ++ else ++ { ++ if((pDM_Odm->SupportICType & (ODM_RTL8192E|ODM_RTL8723B|ODM_RTL8812|ODM_RTL8821)) && (pDM_Odm->bBtLimitedDig==1)){ ++ //2 Modify DIG upper bound for 92E, 8723B, 8821 & 8812 BT ++ if((pDM_Odm->RSSI_Min + 10) > dm_dig_max ) ++ pDM_DigTable->rx_gain_range_max = dm_dig_max; ++ else if((pDM_Odm->RSSI_Min + 10) < dm_dig_min ) ++ pDM_DigTable->rx_gain_range_max = dm_dig_min; ++ else ++ pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 10; ++ } ++ else{ ++ ++ //2 Modify DIG upper bound ++ //2013.03.19 Luke: Modified upper bound for Netgear rental house test ++ if(pDM_Odm->SupportICType != ODM_RTL8821) ++ offset = 20; ++ else ++ offset = 10; ++ ++ if((pDM_Odm->RSSI_Min + offset) > dm_dig_max ) ++ pDM_DigTable->rx_gain_range_max = dm_dig_max; ++ else if((pDM_Odm->RSSI_Min + offset) < dm_dig_min ) ++ pDM_DigTable->rx_gain_range_max = dm_dig_min; ++ else ++ pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + offset; ++ ++ } ++ ++ //2 Modify DIG lower bound ++ /* ++ if((pFalseAlmCnt->Cnt_all > 500)&&(DIG_Dynamic_MIN < 0x25)) ++ DIG_Dynamic_MIN++; ++ else if(((pFalseAlmCnt->Cnt_all < 500)||(pDM_Odm->RSSI_Min < 8))&&(DIG_Dynamic_MIN > dm_dig_min)) ++ DIG_Dynamic_MIN--; ++ */ ++ ++ ++ //1 Lower Bound for 88E AntDiv ++#if (RTL8188E_SUPPORT == 1) ++ if((pDM_Odm->SupportICType == ODM_RTL8188E)&&(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) ++ { ++ if((pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) ||(pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV)) ++ { ++ DIG_Dynamic_MIN = (u1Byte) pDM_DigTable->AntDiv_RSSI_max; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_DIG(): pDM_DigTable->AntDiv_RSSI_max=%d \n",pDM_DigTable->AntDiv_RSSI_max)); ++ } ++ } ++ else ++#endif ++ { ++ if(pDM_Odm->SupportICType != ODM_RTL8723B) ++ offset = 0; ++ else ++ offset = 12; ++ ++ if(pDM_Odm->RSSI_Min - offset < dm_dig_min) ++ DIG_Dynamic_MIN = dm_dig_min; ++ else if (pDM_Odm->RSSI_Min - offset > DIG_MaxOfMin) ++ DIG_Dynamic_MIN = DIG_MaxOfMin; ++ else ++ DIG_Dynamic_MIN = pDM_Odm->RSSI_Min - offset; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() : bOneEntryOnly=TRUE, DIG_Dynamic_MIN=0x%x\n",DIG_Dynamic_MIN)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() : pDM_Odm->RSSI_Min=%d\n",pDM_Odm->RSSI_Min)); ++ } ++ ++ ++ } ++ } ++ else ++ { ++ pDM_DigTable->rx_gain_range_max = dm_dig_max; ++ DIG_Dynamic_MIN = dm_dig_min; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() : No Link\n")); ++ } ++ ++ //1 Modify DIG lower bound, deal with abnorally large false alarm ++ if(pFalseAlmCnt->Cnt_all > 10000) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("dm_DIG(): Abnornally false alarm case. \n")); ++ ++ if(pDM_DigTable->LargeFAHit != 3) ++ pDM_DigTable->LargeFAHit++; ++ if(pDM_DigTable->ForbiddenIGI < CurrentIGI)//if(pDM_DigTable->ForbiddenIGI < pDM_DigTable->CurIGValue) ++ { ++ pDM_DigTable->ForbiddenIGI = (u1Byte)CurrentIGI;//pDM_DigTable->ForbiddenIGI = pDM_DigTable->CurIGValue; ++ pDM_DigTable->LargeFAHit = 1; ++ } ++ ++ if(pDM_DigTable->LargeFAHit >= 3) ++ { ++ if((pDM_DigTable->ForbiddenIGI+1) >pDM_DigTable->rx_gain_range_max) ++ pDM_DigTable->rx_gain_range_min = pDM_DigTable->rx_gain_range_max; ++ else ++ pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1); ++ pDM_DigTable->Recover_cnt = 3600; //3600=2hr ++ } ++ ++ } ++ else ++ { ++ //Recovery mechanism for IGI lower bound ++ if(pDM_DigTable->Recover_cnt != 0) ++ pDM_DigTable->Recover_cnt --; ++ else ++ { ++ if(pDM_DigTable->LargeFAHit < 3) ++ { ++ if((pDM_DigTable->ForbiddenIGI -1) < DIG_Dynamic_MIN) //DM_DIG_MIN) ++ { ++ pDM_DigTable->ForbiddenIGI = DIG_Dynamic_MIN; //DM_DIG_MIN; ++ pDM_DigTable->rx_gain_range_min = DIG_Dynamic_MIN; //DM_DIG_MIN; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: At Lower Bound\n")); ++ } ++ else ++ { ++ pDM_DigTable->ForbiddenIGI --; ++ pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: Approach Lower Bound\n")); ++ } ++ } ++ else ++ { ++ pDM_DigTable->LargeFAHit = 0; ++ } ++ } ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): pDM_DigTable->LargeFAHit=%d\n",pDM_DigTable->LargeFAHit)); ++ ++ if((pDM_Odm->SupportPlatform&(ODM_MP|ODM_CE))&&(pDM_Odm->PhyDbgInfo.NumQryBeaconPkt < 10) && (pDM_Odm->bsta_state)) ++ pDM_DigTable->rx_gain_range_min = dm_dig_min; ++ ++ if(pDM_DigTable->rx_gain_range_min > pDM_DigTable->rx_gain_range_max) ++ pDM_DigTable->rx_gain_range_min = pDM_DigTable->rx_gain_range_max; ++ ++ //1 Adjust initial gain by false alarm ++ if(pDM_Odm->bLinked) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG AfterLink\n")); ++ if(FirstConnect) ++ { ++ if(pDM_Odm->RSSI_Min <= DIG_MaxOfMin) ++ CurrentIGI = pDM_Odm->RSSI_Min; ++ else ++ CurrentIGI = DIG_MaxOfMin; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("DIG: First Connect\n")); ++ ++ //ODM_ConfigBBWithHeaderFile(pDM_Odm, CONFIG_BB_AGC_TAB_DIFF); ++ } ++ else ++ { ++ if(pDM_Odm->SupportICType == ODM_RTL8192D) ++ { ++ if(pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2_92D) ++ CurrentIGI = CurrentIGI + 4;//pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; ++ else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1_92D) ++ CurrentIGI = CurrentIGI + 2; //pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; ++ else if(pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0_92D) ++ CurrentIGI = CurrentIGI - 2;//pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; ++ } ++ else ++ { ++ //FA for Combo IC--NeilChen--2012--09--28 ++ if(pDM_Odm->SupportICType == ODM_RTL8723A) ++ { ++ //WLAN and BT ConCurrent ++ if(pDM_Odm->bBtLimitedDig) ++ { ++ if(pFalseAlmCnt->Cnt_all > 0x300) ++ CurrentIGI = CurrentIGI + 4; ++ else if (pFalseAlmCnt->Cnt_all > 0x250) ++ CurrentIGI = CurrentIGI + 2; ++ else if(pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0) ++ CurrentIGI = CurrentIGI -2; ++ } ++ else //Not Concurrent ++ { ++ if(pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2) ++ CurrentIGI = CurrentIGI + 4;//pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; ++ else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1) ++ CurrentIGI = CurrentIGI + 2;//pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; ++ else if(pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0) ++ CurrentIGI = CurrentIGI - 2;//pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; ++ } ++ } ++ else ++ { ++ if(pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2) ++ CurrentIGI = CurrentIGI + 4;//pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; ++ else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1) ++ CurrentIGI = CurrentIGI + 2;//pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; ++ else if(pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0) ++ CurrentIGI = CurrentIGI - 2;//pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; ++ ++ if((pDM_Odm->SupportPlatform&(ODM_MP|ODM_CE))&&(pDM_Odm->PhyDbgInfo.NumQryBeaconPkt < 10) ++ &&(pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH1) && (pDM_Odm->bsta_state)) ++ { ++ CurrentIGI = pDM_DigTable->rx_gain_range_min; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Beacon is less than 10 and FA is less than 768, IGI GOES TO 0x1E!!!!!!!!!!!!\n")); ++ } ++ } ++ } ++ } ++ } ++ else ++ { ++ //CurrentIGI = pDM_DigTable->rx_gain_range_min;//pDM_DigTable->CurIGValue = pDM_DigTable->rx_gain_range_min ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG BeforeLink\n")); ++ if(FirstDisConnect) ++ { ++ CurrentIGI = pDM_DigTable->rx_gain_range_min; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): First DisConnect \n")); ++ } ++ else ++ { ++ //2012.03.30 LukeLee: enable DIG before link but with very high thresholds ++ if(pFalseAlmCnt->Cnt_all > 10000) ++ CurrentIGI = CurrentIGI + 4; ++ else if (pFalseAlmCnt->Cnt_all > 8000) ++ CurrentIGI = CurrentIGI + 2; ++ else if(pFalseAlmCnt->Cnt_all < 500) ++ CurrentIGI = CurrentIGI - 2; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): England DIG \n")); ++ } ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG End Adjust IGI\n")); ++ //1 Check initial gain by upper/lower bound ++ ++ if(CurrentIGI > pDM_DigTable->rx_gain_range_max) ++ CurrentIGI = pDM_DigTable->rx_gain_range_max; ++ if(CurrentIGI < pDM_DigTable->rx_gain_range_min) ++ CurrentIGI = pDM_DigTable->rx_gain_range_min; ++ ++ if(pDM_Odm->SupportAbility & ODM_BB_ADAPTIVITY) ++ { ++ if(CurrentIGI > Adap_IGI_Upper) ++ CurrentIGI = Adap_IGI_Upper; ++ ++ if(CurrentIGI > (pDM_Odm->IGI_target + 4)) ++ CurrentIGI = (u1Byte)pDM_Odm->IGI_target + 4; ++ } ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): rx_gain_range_max=0x%x, rx_gain_range_min=0x%x\n", ++ pDM_DigTable->rx_gain_range_max, pDM_DigTable->rx_gain_range_min)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): TotalFA=%d\n", pFalseAlmCnt->Cnt_all)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): CurIGValue=0x%x\n", CurrentIGI)); ++ ++ //2 High power RSSI threshold ++#if (DM_ODM_SUPPORT_TYPE & ODM_MP) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pDM_Odm->Adapter); ++ //PMGNT_INFO pMgntInfo = &(pAdapter->MgntInfo); ++ // for LC issue to dymanic modify DIG lower bound----------LC Mocca Issue ++ u8Byte curTxOkCnt=0, curRxOkCnt=0; ++ static u8Byte lastTxOkCnt=0, lastRxOkCnt=0; ++ ++ //u8Byte OKCntAll=0; ++ //static u8Byte TXByteCnt_A=0, TXByteCnt_B=0, RXByteCnt_A=0, RXByteCnt_B=0; ++ //u8Byte CurByteCnt=0, PreByteCnt=0; ++ ++ curTxOkCnt = pAdapter->TxStats.NumTxBytesUnicast - lastTxOkCnt; ++ curRxOkCnt =pAdapter->RxStats.NumRxBytesUnicast - lastRxOkCnt; ++ lastTxOkCnt = pAdapter->TxStats.NumTxBytesUnicast; ++ lastRxOkCnt = pAdapter->RxStats.NumRxBytesUnicast; ++ //----------------------------------------------------------end for LC Mocca issue ++ if((pDM_Odm->SupportICType == ODM_RTL8723A)&& (pHalData->UndecoratedSmoothedPWDB > DM_DIG_HIGH_PWR_THRESHOLD)) ++ { ++ // High power IGI lower bound ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): UndecoratedSmoothedPWDB(%#x)\n", pHalData->UndecoratedSmoothedPWDB)); ++ if(CurrentIGI < DM_DIG_HIGH_PWR_IGI_LOWER_BOUND) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): CurIGValue(%#x)\n", pDM_DigTable->CurIGValue)); ++ //pDM_DigTable->CurIGValue = DM_DIG_HIGH_PWR_IGI_LOWER_BOUND; ++ CurrentIGI=DM_DIG_HIGH_PWR_IGI_LOWER_BOUND; ++ } ++ } ++ if((pDM_Odm->SupportICType & ODM_RTL8723A) && ++ IS_WIRELESS_MODE_G(pAdapter)) ++ { ++ if(pHalData->UndecoratedSmoothedPWDB > 0x28) ++ { ++ if(CurrentIGI < DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND) ++ { ++ //pDM_DigTable->CurIGValue = DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND; ++ CurrentIGI = DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND; ++ } ++ } ++ } ++#if 0 ++ if((pDM_Odm->SupportICType & ODM_RTL8723A)&&(pMgntInfo->CustomerID = RT_CID_LENOVO_CHINA)) ++ { ++ OKCntAll = (curTxOkCnt+curRxOkCnt); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): CurIGValue(%#x)\n", CurrentIGI)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): UndecoratedSmoothedPWDB(%#x)\n", pHalData->UndecoratedSmoothedPWDB)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): OKCntAll(%#x)\n", OKCntAll)); ++ //8723AS_VAU ++ if(pDM_Odm->SupportInterface==ODM_ITRF_USB) ++ { ++ if(pHalData->UndecoratedSmoothedPWDB < 12) ++ { ++ if(CurrentIGI > DM_DIG_MIN_NIC) ++ { ++ if(OKCntAll >= 1500000) // >=6Mbps ++ CurrentIGI=0x1B; ++ else if(OKCntAll >= 1000000) //4Mbps ++ CurrentIGI=0x1A; ++ else if(OKCntAll >= 500000) //2Mbps ++ CurrentIGI=0x19; ++ else if(OKCntAll >= 250000) //1Mbps ++ CurrentIGI=0x18; ++ else ++ { ++ CurrentIGI=0x17; //SCAN mode ++ } ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("Modify---->CurIGValue(%#x)\n", CurrentIGI)); ++ } ++ } ++ } ++#endif ++} ++#endif ++ ++#if (RTL8192D_SUPPORT==1) ++ if(pDM_Odm->SupportICType == ODM_RTL8192D) ++ { ++ //sherry delete DualMacSmartConncurrent 20110517 ++ if(*(pDM_Odm->pMacPhyMode) == ODM_DMSP) ++ { ++ ODM_Write_DIG_DMSP(pDM_Odm, (u1Byte)CurrentIGI);//ODM_Write_DIG_DMSP(pDM_Odm, pDM_DigTable->CurIGValue); ++ if(*(pDM_Odm->pbMasterOfDMSP)) ++ { ++ pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked; ++ pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN; ++ } ++ else ++ { ++ pDM_DigTable->bMediaConnect_1 = pDM_Odm->bLinked; ++ pDM_DigTable->DIG_Dynamic_MIN_1 = DIG_Dynamic_MIN; ++ } ++ } ++ else ++ { ++ ODM_Write_DIG(pDM_Odm, CurrentIGI);//ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); ++ if(*(pDM_Odm->pBandType) == ODM_BAND_5G) ++ { ++ pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked; ++ pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN; ++ } ++ else ++ { ++ pDM_DigTable->bMediaConnect_1 = pDM_Odm->bLinked; ++ pDM_DigTable->DIG_Dynamic_MIN_1 = DIG_Dynamic_MIN; ++ } ++ } ++ } ++ else ++#endif ++ { ++ #if(BT_30_SUPPORT == 1) ++ if(pDM_Odm->bBtHsOperation) ++ { ++ if(pDM_Odm->bLinked) ++ { ++ if(pDM_DigTable->BT30_CurIGI > (CurrentIGI)) ++ { ++ ODM_Write_DIG(pDM_Odm, CurrentIGI); ++ ++ } ++ else ++ { ++ ODM_Write_DIG(pDM_Odm, pDM_DigTable->BT30_CurIGI); ++ } ++ pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked; ++ pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN; ++ } ++ else ++ { ++ if(pDM_Odm->bLinkInProcess) ++ { ++ ODM_Write_DIG(pDM_Odm, 0x1c); ++ } ++ else if(pDM_Odm->bBtConnectProcess) ++ { ++ ODM_Write_DIG(pDM_Odm, 0x28); ++ } ++ else ++ { ++ ODM_Write_DIG(pDM_Odm, pDM_DigTable->BT30_CurIGI);//ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); ++ } ++ } ++ } ++ else // BT is not using ++ #endif ++ { ++ ODM_Write_DIG(pDM_Odm, CurrentIGI);//ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); ++ pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked; ++ pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN; ++ } ++ } ++} ++ ++ ++BOOLEAN ++odm_DigAbort( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++// This should be moved out of OUTSRC ++ PADAPTER pAdapter = pDM_Odm->Adapter; ++ pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; ++ ++#if OS_WIN_FROM_WIN7(OS_VERSION) ++ if(IsAPModeExist( pAdapter) && pAdapter->bInHctTest) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: Is AP mode or In HCT Test \n")); ++ return TRUE; ++ } ++#endif ++ ++ if(pRX_HP_Table->RXHP_flag == 1) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: In RXHP Operation \n")); ++ return TRUE; ++ } ++ ++ return FALSE; ++#else // For Other team any special case for DIG? ++ return FALSE; ++#endif ++ ++ ++} ++ ++ ++#else ++VOID ++odm_DIGInit( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ ++ //pDM_DigTable->Dig_Enable_Flag = TRUE; ++ //pDM_DigTable->Dig_Ext_Port_Stage = DIG_EXT_PORT_STAGE_MAX; ++ pDM_DigTable->CurIGValue = (u1Byte) ODM_GetBBReg(pDM_Odm, ODM_REG(IGI_A,pDM_Odm), ODM_BIT(IGI,pDM_Odm)); ++ //pDM_DigTable->PreIGValue = 0x0; ++ //pDM_DigTable->CurSTAConnectState = pDM_DigTable->PreSTAConnectState = DIG_STA_DISCONNECT; ++ //pDM_DigTable->CurMultiSTAConnectState = DIG_MultiSTA_DISCONNECT; ++ pDM_DigTable->RssiLowThresh = DM_DIG_THRESH_LOW; ++ pDM_DigTable->RssiHighThresh = DM_DIG_THRESH_HIGH; ++ pDM_DigTable->FALowThresh = DM_FALSEALARM_THRESH_LOW; ++ pDM_DigTable->FAHighThresh = DM_FALSEALARM_THRESH_HIGH; ++ if(pDM_Odm->BoardType & (ODM_BOARD_EXT_LNA | ODM_BOARD_EXT_PA)) ++ { ++ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; ++ pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC; ++ } ++ else ++ { ++ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; ++ pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC; ++ } ++ pDM_DigTable->BackoffVal = DM_DIG_BACKOFF_DEFAULT; ++ pDM_DigTable->BackoffVal_range_max = DM_DIG_BACKOFF_MAX; ++ pDM_DigTable->BackoffVal_range_min = DM_DIG_BACKOFF_MIN; ++ pDM_DigTable->PreCCK_CCAThres = 0xFF; ++ pDM_DigTable->CurCCK_CCAThres = 0x83; ++ pDM_DigTable->ForbiddenIGI = DM_DIG_MIN_NIC; ++ pDM_DigTable->LargeFAHit = 0; ++ pDM_DigTable->Recover_cnt = 0; ++ pDM_DigTable->DIG_Dynamic_MIN_0 =DM_DIG_MIN_NIC; ++ pDM_DigTable->DIG_Dynamic_MIN_1 = DM_DIG_MIN_NIC; ++ pDM_DigTable->bMediaConnect_0 = FALSE; ++ pDM_DigTable->bMediaConnect_1 = FALSE; ++ ++ //To Initialize pDM_Odm->bDMInitialGainEnable == FALSE to avoid DIG error ++ pDM_Odm->bDMInitialGainEnable = TRUE; ++ ++} ++ ++ ++VOID ++odm_DIG( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ PFALSE_ALARM_STATISTICS pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; ++ pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; ++ u1Byte DIG_Dynamic_MIN; ++ u1Byte DIG_MaxOfMin; ++ BOOLEAN FirstConnect, FirstDisConnect; ++ u1Byte dm_dig_max, dm_dig_min; ++ u1Byte CurrentIGI = pDM_DigTable->CurIGValue; ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++// This should be moved out of OUTSRC ++ PADAPTER pAdapter = pDM_Odm->Adapter; ++#if OS_WIN_FROM_WIN7(OS_VERSION) ++ if(IsAPModeExist( pAdapter) && pAdapter->bInHctTest) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: Is AP mode or In HCT Test \n")); ++ return; ++ } ++#endif ++#if(BT_30_SUPPORT == 1) ++ if(pDM_Odm->bBtHsOperation) ++ { ++ odm_DigForBtHsMode(pDM_Odm); ++ return; ++ } ++#endif ++ ++ if(pRX_HP_Table->RXHP_flag == 1) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: In RXHP Operation \n")); ++ return; ++ } ++#endif //end ODM_MP type ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++#ifdef CONFIG_SPECIAL_SETTING_FOR_FUNAI_TV ++ if((pDM_Odm->bLinked) && (pDM_Odm->Adapter->registrypriv.force_igi !=0)) ++ { ++ printk("pDM_Odm->RSSI_Min=%d \n",pDM_Odm->RSSI_Min); ++ ODM_Write_DIG(pDM_Odm,pDM_Odm->Adapter->registrypriv.force_igi); ++ return; ++ } ++#endif ++#endif ++#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ if (!((priv->up_time > 5) && (priv->up_time % 2)) ) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: Not In DIG Operation Period \n")); ++ return; ++ } ++#endif ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG()==>\n")); ++ //if(!(pDM_Odm->SupportAbility & (ODM_BB_DIG|ODM_BB_FA_CNT))) ++ if((!(pDM_Odm->SupportAbility&ODM_BB_DIG)) ||(!(pDM_Odm->SupportAbility&ODM_BB_FA_CNT))) ++ { ++#if 0 ++ if(pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) ++ { ++ if ((pDM_Odm->SupportICType == ODM_RTL8192C) && (pDM_Odm->ExtLNA == 1)) ++ CurrentIGI = 0x30; //pDM_DigTable->CurIGValue = 0x30; ++ else ++ CurrentIGI = 0x20; //pDM_DigTable->CurIGValue = 0x20; ++ ODM_Write_DIG(pDM_Odm, CurrentIGI);//ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); ++ } ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: SupportAbility ODM_BB_DIG or ODM_BB_FA_CNT is disabled\n")); ++ return; ++ } ++ ++ if(*(pDM_Odm->pbScanInProcess)) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: In Scan Progress \n")); ++ return; ++ } ++ ++ //add by Neil Chen to avoid PSD is processing ++ if(pDM_Odm->bDMInitialGainEnable == FALSE) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: PSD is Processing \n")); ++ return; ++ } ++ ++ if(pDM_Odm->SupportICType == ODM_RTL8192D) ++ { ++ if(*(pDM_Odm->pMacPhyMode) == ODM_DMSP) ++ { ++ if(*(pDM_Odm->pbMasterOfDMSP)) ++ { ++ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0; ++ FirstConnect = (pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == FALSE); ++ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == TRUE); ++ } ++ else ++ { ++ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_1; ++ FirstConnect = (pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1 == FALSE); ++ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1 == TRUE); ++ } ++ } ++ else ++ { ++ if(*(pDM_Odm->pBandType) == ODM_BAND_5G) ++ { ++ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0; ++ FirstConnect = (pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == FALSE); ++ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == TRUE); ++ } ++ else ++ { ++ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_1; ++ FirstConnect = (pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1 == FALSE); ++ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1 == TRUE); ++ } ++ } ++ } ++ else ++ { ++ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0; ++ FirstConnect = (pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == FALSE); ++ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == TRUE); ++ } ++ ++ //1 Boundary Decision ++ if((pDM_Odm->SupportICType & (ODM_RTL8192C|ODM_RTL8723A)) && ++ ((if(pDM_Odm->BoardType & (ODM_BOARD_EXT_LNA | ODM_BOARD_EXT_PA))) || pDM_Odm->ExtLNA)) ++ { ++ if(pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) ++ { ++ ++ dm_dig_max = DM_DIG_MAX_AP_HP; ++ dm_dig_min = DM_DIG_MIN_AP_HP; ++ } ++ else ++ { ++ dm_dig_max = DM_DIG_MAX_NIC_HP; ++ dm_dig_min = DM_DIG_MIN_NIC_HP; ++ } ++ DIG_MaxOfMin = DM_DIG_MAX_AP_HP; ++ } ++ else ++ { ++ if(pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) ++ { ++#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++#ifdef DFS ++ if (!priv->pmib->dot11DFSEntry.disable_DFS && ++ (OPMODE & WIFI_AP_STATE) && ++ (((pDM_Odm->ControlChannel >= 52) && ++ (pDM_Odm->ControlChannel <= 64)) || ++ ((pDM_Odm->ControlChannel >= 100) && ++ (pDM_Odm->ControlChannel <= 140)))) ++ dm_dig_max = 0x24; ++ else ++#endif ++ if (priv->pmib->dot11RFEntry.tx2path) { ++ if (*(pDM_Odm->pWirelessMode) == ODM_WM_B)//(priv->pmib->dot11BssType.net_work_type == WIRELESS_11B) ++ dm_dig_max = 0x2A; ++ else ++ dm_dig_max = 0x32; ++ } ++ else ++#endif ++ dm_dig_max = DM_DIG_MAX_AP; ++ dm_dig_min = DM_DIG_MIN_AP; ++ DIG_MaxOfMin = dm_dig_max; ++ } ++ else ++ { ++ dm_dig_max = DM_DIG_MAX_NIC; ++ dm_dig_min = DM_DIG_MIN_NIC; ++ DIG_MaxOfMin = DM_DIG_MAX_AP; ++ } ++ } ++ ++ ++ if(pDM_Odm->bLinked) ++ { ++ //2 8723A Series, offset need to be 10 //neil ++ if(pDM_Odm->SupportICType==(ODM_RTL8723A)) ++ { ++ //2 Upper Bound ++ if(( pDM_Odm->RSSI_Min + 10) > DM_DIG_MAX_NIC ) ++ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; ++ else if(( pDM_Odm->RSSI_Min + 10) < DM_DIG_MIN_NIC ) ++ pDM_DigTable->rx_gain_range_max = DM_DIG_MIN_NIC; ++ else ++ pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 10; ++ ++ //2 If BT is Concurrent, need to set Lower Bound ++ ++#if(BT_30_SUPPORT == 1) ++ if(pDM_Odm->bBtBusy) ++ { ++ if(pDM_Odm->RSSI_Min>10) ++ { ++ if((pDM_Odm->RSSI_Min - 10) > DM_DIG_MAX_NIC) ++ DIG_Dynamic_MIN = DM_DIG_MAX_NIC; ++ else if((pDM_Odm->RSSI_Min - 10) < DM_DIG_MIN_NIC) ++ DIG_Dynamic_MIN = DM_DIG_MIN_NIC; ++ else ++ DIG_Dynamic_MIN = pDM_Odm->RSSI_Min - 10; ++ } ++ else ++ DIG_Dynamic_MIN=DM_DIG_MIN_NIC; ++ } ++ else ++#endif ++ { ++ DIG_Dynamic_MIN=DM_DIG_MIN_NIC; ++ } ++ } ++ else ++ { ++ //2 Modify DIG upper bound ++ if((pDM_Odm->RSSI_Min + 20) > dm_dig_max ) ++ pDM_DigTable->rx_gain_range_max = dm_dig_max; ++ else if((pDM_Odm->RSSI_Min + 20) < dm_dig_min ) ++ pDM_DigTable->rx_gain_range_max = dm_dig_min; ++ else ++ pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 20; ++ ++ ++ //2 Modify DIG lower bound ++ /* ++ if((pFalseAlmCnt->Cnt_all > 500)&&(DIG_Dynamic_MIN < 0x25)) ++ DIG_Dynamic_MIN++; ++ else if(((pFalseAlmCnt->Cnt_all < 500)||(pDM_Odm->RSSI_Min < 8))&&(DIG_Dynamic_MIN > dm_dig_min)) ++ DIG_Dynamic_MIN--; ++ */ ++ if(pDM_Odm->bOneEntryOnly) ++ { ++ if(pDM_Odm->RSSI_Min < dm_dig_min) ++ DIG_Dynamic_MIN = dm_dig_min; ++ else if (pDM_Odm->RSSI_Min > DIG_MaxOfMin) ++ DIG_Dynamic_MIN = DIG_MaxOfMin; ++ else ++ DIG_Dynamic_MIN = pDM_Odm->RSSI_Min; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() : bOneEntryOnly=TRUE, DIG_Dynamic_MIN=0x%x\n",DIG_Dynamic_MIN)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() : pDM_Odm->RSSI_Min=%d\n",pDM_Odm->RSSI_Min)); ++ } ++ //1 Lower Bound for 88E AntDiv ++#if (RTL8188E_SUPPORT == 1) ++ else if((pDM_Odm->SupportICType == ODM_RTL8188E)&&(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) ++ { ++ if(pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) ++ { ++ DIG_Dynamic_MIN = (u1Byte) pDM_DigTable->AntDiv_RSSI_max; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_DIG(): pDM_DigTable->AntDiv_RSSI_max=%d \n",pDM_DigTable->AntDiv_RSSI_max)); ++ } ++ } ++#endif ++ else ++ { ++ DIG_Dynamic_MIN=dm_dig_min; ++ } ++ } ++ } ++ else ++ { ++ pDM_DigTable->rx_gain_range_max = dm_dig_max; ++ DIG_Dynamic_MIN = dm_dig_min; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() : No Link\n")); ++ } ++ ++ //1 Modify DIG lower bound, deal with abnormally large false alarm ++ if(pFalseAlmCnt->Cnt_all > 10000) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("dm_DIG(): Abnornally false alarm case. \n")); ++ ++ if(pDM_DigTable->LargeFAHit != 3) ++ pDM_DigTable->LargeFAHit++; ++ if(pDM_DigTable->ForbiddenIGI < CurrentIGI)//if(pDM_DigTable->ForbiddenIGI < pDM_DigTable->CurIGValue) ++ { ++ pDM_DigTable->ForbiddenIGI = CurrentIGI;//pDM_DigTable->ForbiddenIGI = pDM_DigTable->CurIGValue; ++ pDM_DigTable->LargeFAHit = 1; ++ } ++ ++ if(pDM_DigTable->LargeFAHit >= 3) ++ { ++ if((pDM_DigTable->ForbiddenIGI+1) >pDM_DigTable->rx_gain_range_max) ++ pDM_DigTable->rx_gain_range_min = pDM_DigTable->rx_gain_range_max; ++ else ++ pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1); ++ pDM_DigTable->Recover_cnt = 3600; //3600=2hr ++ } ++ ++ } ++ else ++ { ++ //Recovery mechanism for IGI lower bound ++ if(pDM_DigTable->Recover_cnt != 0) ++ pDM_DigTable->Recover_cnt --; ++ else ++ { ++ if(pDM_DigTable->LargeFAHit < 3) ++ { ++ if((pDM_DigTable->ForbiddenIGI -1) < DIG_Dynamic_MIN) //DM_DIG_MIN) ++ { ++ pDM_DigTable->ForbiddenIGI = DIG_Dynamic_MIN; //DM_DIG_MIN; ++ pDM_DigTable->rx_gain_range_min = DIG_Dynamic_MIN; //DM_DIG_MIN; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: At Lower Bound\n")); ++ } ++ else ++ { ++ pDM_DigTable->ForbiddenIGI --; ++ pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: Approach Lower Bound\n")); ++ } ++ } ++ else ++ { ++ pDM_DigTable->LargeFAHit = 0; ++ } ++ } ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): pDM_DigTable->LargeFAHit=%d\n",pDM_DigTable->LargeFAHit)); ++ ++ //1 Adjust initial gain by false alarm ++ if(pDM_Odm->bLinked) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG AfterLink\n")); ++ if(FirstConnect) ++ { ++ CurrentIGI = pDM_Odm->RSSI_Min; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("DIG: First Connect\n")); ++ } ++ else ++ { ++ if(pDM_Odm->SupportICType == ODM_RTL8192D) ++ { ++ if(pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2_92D) ++ CurrentIGI = CurrentIGI + 2;//pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; ++ else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1_92D) ++ CurrentIGI = CurrentIGI + 1; //pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; ++ else if(pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0_92D) ++ CurrentIGI = CurrentIGI - 1;//pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; ++ } ++ else ++ { ++#if(BT_30_SUPPORT == 1) ++ if(pDM_Odm->bBtBusy) ++ { ++ if(pFalseAlmCnt->Cnt_all > 0x300) ++ CurrentIGI = CurrentIGI + 2; ++ else if (pFalseAlmCnt->Cnt_all > 0x250) ++ CurrentIGI = CurrentIGI + 1; ++ else if(pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0) ++ CurrentIGI = CurrentIGI -1; ++ } ++ else ++#endif ++ { ++ if(pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2) ++ CurrentIGI = CurrentIGI + 4;//pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; ++ else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1) ++ CurrentIGI = CurrentIGI + 2;//pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; ++ else if(pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0) ++ CurrentIGI = CurrentIGI - 2;//pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; ++ ++ ++ } ++ } ++ } ++ } ++ else ++ { ++ //CurrentIGI = pDM_DigTable->rx_gain_range_min;//pDM_DigTable->CurIGValue = pDM_DigTable->rx_gain_range_min ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG BeforeLink\n")); ++ if(FirstDisConnect) ++ { ++ CurrentIGI = pDM_DigTable->rx_gain_range_min; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): First DisConnect \n")); ++ } ++ else ++ { ++ //2012.03.30 LukeLee: enable DIG before link but with very high thresholds ++ if(pFalseAlmCnt->Cnt_all > 10000) ++ CurrentIGI = CurrentIGI + 2;//pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; ++ else if (pFalseAlmCnt->Cnt_all > 8000) ++ CurrentIGI = CurrentIGI + 1;//pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; ++ else if(pFalseAlmCnt->Cnt_all < 500) ++ CurrentIGI = CurrentIGI - 1;//pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): England DIG \n")); ++ } ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG End Adjust IGI\n")); ++ //1 Check initial gain by upper/lower bound ++/* ++ if(pDM_DigTable->CurIGValue > pDM_DigTable->rx_gain_range_max) ++ pDM_DigTable->CurIGValue = pDM_DigTable->rx_gain_range_max; ++ if(pDM_DigTable->CurIGValue < pDM_DigTable->rx_gain_range_min) ++ pDM_DigTable->CurIGValue = pDM_DigTable->rx_gain_range_min; ++*/ ++ if(CurrentIGI > pDM_DigTable->rx_gain_range_max) ++ CurrentIGI = pDM_DigTable->rx_gain_range_max; ++ if(CurrentIGI < pDM_DigTable->rx_gain_range_min) ++ CurrentIGI = pDM_DigTable->rx_gain_range_min; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): rx_gain_range_max=0x%x, rx_gain_range_min=0x%x\n", ++ pDM_DigTable->rx_gain_range_max, pDM_DigTable->rx_gain_range_min)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): TotalFA=%d\n", pFalseAlmCnt->Cnt_all)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): CurIGValue=0x%x\n", CurrentIGI)); ++ ++ //2 High power RSSI threshold ++#if (DM_ODM_SUPPORT_TYPE & ODM_MP) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pDM_Odm->Adapter); ++ ++ // for LC issue to dymanic modify DIG lower bound----------LC Mocca Issue ++ u8Byte curTxOkCnt=0, curRxOkCnt=0; ++ static u8Byte lastTxOkCnt=0, lastRxOkCnt=0; ++ ++ u8Byte OKCntAll=0; ++ //static u8Byte TXByteCnt_A=0, TXByteCnt_B=0, RXByteCnt_A=0, RXByteCnt_B=0; ++ //u8Byte CurByteCnt=0, PreByteCnt=0; ++ ++ curTxOkCnt = pAdapter->TxStats.NumTxBytesUnicast - lastTxOkCnt; ++ curRxOkCnt =pAdapter->RxStats.NumRxBytesUnicast - lastRxOkCnt; ++ lastTxOkCnt = pAdapter->TxStats.NumTxBytesUnicast; ++ lastRxOkCnt = pAdapter->RxStats.NumRxBytesUnicast; ++ //----------------------------------------------------------end for LC Mocca issue ++ if((pDM_Odm->SupportICType == ODM_RTL8723A)&& (pHalData->UndecoratedSmoothedPWDB > DM_DIG_HIGH_PWR_THRESHOLD)) ++ { ++ // High power IGI lower bound ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): UndecoratedSmoothedPWDB(%#x)\n", pHalData->UndecoratedSmoothedPWDB)); ++ if(CurrentIGI < DM_DIG_HIGH_PWR_IGI_LOWER_BOUND) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): CurIGValue(%#x)\n", pDM_DigTable->CurIGValue)); ++ //pDM_DigTable->CurIGValue = DM_DIG_HIGH_PWR_IGI_LOWER_BOUND; ++ CurrentIGI=DM_DIG_HIGH_PWR_IGI_LOWER_BOUND; ++ } ++ } ++ if((pDM_Odm->SupportICType & ODM_RTL8723A) && IS_WIRELESS_MODE_G(pAdapter)) ++ { ++ if(pHalData->UndecoratedSmoothedPWDB > 0x28) ++ { ++ if(CurrentIGI < DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND) ++ { ++ //pDM_DigTable->CurIGValue = DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND; ++ CurrentIGI = DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND; ++ } ++ } ++ } ++} ++#endif ++ ++#if (RTL8192D_SUPPORT==1) ++ if(pDM_Odm->SupportICType == ODM_RTL8192D) ++ { ++ //sherry delete DualMacSmartConncurrent 20110517 ++ if(*(pDM_Odm->pMacPhyMode) == ODM_DMSP) ++ { ++ ODM_Write_DIG_DMSP(pDM_Odm, CurrentIGI);//ODM_Write_DIG_DMSP(pDM_Odm, pDM_DigTable->CurIGValue); ++ if(*(pDM_Odm->pbMasterOfDMSP)) ++ { ++ pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked; ++ pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN; ++ } ++ else ++ { ++ pDM_DigTable->bMediaConnect_1 = pDM_Odm->bLinked; ++ pDM_DigTable->DIG_Dynamic_MIN_1 = DIG_Dynamic_MIN; ++ } ++ } ++ else ++ { ++ ODM_Write_DIG(pDM_Odm, CurrentIGI);//ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); ++ if(*(pDM_Odm->pBandType) == ODM_BAND_5G) ++ { ++ pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked; ++ pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN; ++ } ++ else ++ { ++ pDM_DigTable->bMediaConnect_1 = pDM_Odm->bLinked; ++ pDM_DigTable->DIG_Dynamic_MIN_1 = DIG_Dynamic_MIN; ++ } ++ } ++ } ++ else ++#endif ++ { ++ ODM_Write_DIG(pDM_Odm, CurrentIGI);//ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); ++ pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked; ++ pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN; ++ } ++ ++} ++#endif ++//3============================================================ ++//3 FASLE ALARM CHECK ++//3============================================================ ++ ++VOID ++odm_FalseAlarmCounterStatistics( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ u4Byte ret_value; ++ PFALSE_ALARM_STATISTICS FalseAlmCnt = &(pDM_Odm->FalseAlmCnt); ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ if( (priv->auto_channel != 0) && (priv->auto_channel != 2) ) ++ return; ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ if((pDM_Odm->SupportICType == ODM_RTL8192D) && ++ (*(pDM_Odm->pMacPhyMode)==ODM_DMSP)&& ////modify by Guo.Mingzhi 2011-12-29 ++ (!(*(pDM_Odm->pbMasterOfDMSP)))) ++ { ++ odm_FalseAlarmCounterStatistics_ForSlaveOfDMSP(pDM_Odm); ++ return; ++ } ++#endif ++ ++ if(!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT)) ++ return; ++ ++// if(pDM_Odm->SupportICType != ODM_RTL8812) ++ if(pDM_Odm->SupportICType & ODM_IC_11N_SERIES) ++ { ++ ++ //hold ofdm counter ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_HOLDC_11N, BIT31, 1); //hold page C counter ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT31, 1); //hold page D counter ++ ++ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE1_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_Fast_Fsync = (ret_value&0xffff); ++ FalseAlmCnt->Cnt_SB_Search_fail = ((ret_value&0xffff0000)>>16); ++ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE2_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_OFDM_CCA = (ret_value&0xffff); ++ FalseAlmCnt->Cnt_Parity_Fail = ((ret_value&0xffff0000)>>16); ++ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE3_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_Rate_Illegal = (ret_value&0xffff); ++ FalseAlmCnt->Cnt_Crc8_fail = ((ret_value&0xffff0000)>>16); ++ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE4_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_Mcs_fail = (ret_value&0xffff); ++ ++ FalseAlmCnt->Cnt_Ofdm_fail = FalseAlmCnt->Cnt_Parity_Fail + FalseAlmCnt->Cnt_Rate_Illegal + ++ FalseAlmCnt->Cnt_Crc8_fail + FalseAlmCnt->Cnt_Mcs_fail + ++ FalseAlmCnt->Cnt_Fast_Fsync + FalseAlmCnt->Cnt_SB_Search_fail; ++ ++#if (RTL8188E_SUPPORT==1) ++ if(pDM_Odm->SupportICType == ODM_RTL8188E) ++ { ++ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_SC_CNT_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_BW_LSC = (ret_value&0xffff); ++ FalseAlmCnt->Cnt_BW_USC = ((ret_value&0xffff0000)>>16); ++ } ++#endif ++ ++#if (RTL8192D_SUPPORT==1) ++ if(pDM_Odm->SupportICType == ODM_RTL8192D) ++ { ++ odm_GetCCKFalseAlarm_92D(pDM_Odm); ++ } ++ else ++#endif ++ { ++ //hold cck counter ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT12, 1); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT14, 1); ++ ++ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_LSB_11N, bMaskByte0); ++ FalseAlmCnt->Cnt_Cck_fail = ret_value; ++ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_MSB_11N, bMaskByte3); ++ FalseAlmCnt->Cnt_Cck_fail += (ret_value& 0xff)<<8; ++ ++ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_CCA_CNT_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_CCK_CCA = ((ret_value&0xFF)<<8) |((ret_value&0xFF00)>>8); ++ } ++ ++ FalseAlmCnt->Cnt_all = ( FalseAlmCnt->Cnt_Fast_Fsync + ++ FalseAlmCnt->Cnt_SB_Search_fail + ++ FalseAlmCnt->Cnt_Parity_Fail + ++ FalseAlmCnt->Cnt_Rate_Illegal + ++ FalseAlmCnt->Cnt_Crc8_fail + ++ FalseAlmCnt->Cnt_Mcs_fail + ++ FalseAlmCnt->Cnt_Cck_fail); ++ ++ FalseAlmCnt->Cnt_CCA_all = FalseAlmCnt->Cnt_OFDM_CCA + FalseAlmCnt->Cnt_CCK_CCA; ++ ++#if (RTL8192C_SUPPORT==1) ++ if(pDM_Odm->SupportICType == ODM_RTL8192C) ++ odm_ResetFACounter_92C(pDM_Odm); ++#endif ++ ++#if (RTL8192D_SUPPORT==1) ++ if(pDM_Odm->SupportICType == ODM_RTL8192D) ++ odm_ResetFACounter_92D(pDM_Odm); ++#endif ++ ++ if(pDM_Odm->SupportICType >=ODM_RTL8723A) ++ { ++ //reset false alarm counter registers ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT31, 1); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT31, 0); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT27, 1); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT27, 0); ++ //update ofdm counter ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_HOLDC_11N, BIT31, 0); //update page C counter ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT31, 0); //update page D counter ++ ++ //reset CCK CCA counter ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT13|BIT12, 0); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT13|BIT12, 2); ++ //reset CCK FA counter ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT15|BIT14, 0); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT15|BIT14, 2); ++ } ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Enter odm_FalseAlarmCounterStatistics\n")); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Fast_Fsync=%d, Cnt_SB_Search_fail=%d\n", ++ FalseAlmCnt->Cnt_Fast_Fsync, FalseAlmCnt->Cnt_SB_Search_fail)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Parity_Fail=%d, Cnt_Rate_Illegal=%d\n", ++ FalseAlmCnt->Cnt_Parity_Fail, FalseAlmCnt->Cnt_Rate_Illegal)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Crc8_fail=%d, Cnt_Mcs_fail=%d\n", ++ FalseAlmCnt->Cnt_Crc8_fail, FalseAlmCnt->Cnt_Mcs_fail)); ++ } ++ else //FOR ODM_IC_11AC_SERIES ++ { ++ //read OFDM FA counter ++ FalseAlmCnt->Cnt_Ofdm_fail = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_11AC, bMaskLWord); ++ FalseAlmCnt->Cnt_Cck_fail = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_11AC, bMaskLWord); ++ FalseAlmCnt->Cnt_all = FalseAlmCnt->Cnt_Ofdm_fail + FalseAlmCnt->Cnt_Cck_fail; ++ ++ // reset OFDM FA coutner ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RST_11AC, BIT17, 1); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RST_11AC, BIT17, 0); ++ // reset CCK FA counter ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11AC, BIT15, 0); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11AC, BIT15, 1); ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Cck_fail=%d\n", FalseAlmCnt->Cnt_Cck_fail)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Ofdm_fail=%d\n", FalseAlmCnt->Cnt_Ofdm_fail)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Total False Alarm=%d\n", FalseAlmCnt->Cnt_all)); ++} ++ ++//3============================================================ ++//3 CCK Packet Detect Threshold ++//3============================================================ ++ ++VOID ++odm_CCKPacketDetectionThresh( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ u1Byte CurCCK_CCAThres; ++ PFALSE_ALARM_STATISTICS FalseAlmCnt = &(pDM_Odm->FalseAlmCnt); ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++//modify by Guo.Mingzhi 2011-12-29 ++ if (pDM_Odm->bDualMacSmartConcurrent == TRUE) ++// if (pDM_Odm->bDualMacSmartConcurrent == FALSE) ++ return; ++#if(BT_30_SUPPORT == 1) ++ if(pDM_Odm->bBtHsOperation) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_CCKPacketDetectionThresh() write 0xcd for BT HS mode!!\n")); ++ ODM_Write_CCK_CCA_Thres(pDM_Odm, 0xcd); ++ return; ++ } ++#endif ++#endif ++ ++ if(!(pDM_Odm->SupportAbility & (ODM_BB_CCK_PD|ODM_BB_FA_CNT))) ++ return; ++ ++ if(pDM_Odm->ExtLNA) ++ return; ++ ++ if(pDM_Odm->bLinked) ++ { ++ if(pDM_Odm->RSSI_Min > 25) ++ CurCCK_CCAThres = 0xcd; ++ else if((pDM_Odm->RSSI_Min <= 25) && (pDM_Odm->RSSI_Min > 10)) ++ CurCCK_CCAThres = 0x83; ++ else ++ { ++ if(FalseAlmCnt->Cnt_Cck_fail > 1000) ++ CurCCK_CCAThres = 0x83; ++ else ++ CurCCK_CCAThres = 0x40; ++ } ++ } ++ else ++ { ++ if(FalseAlmCnt->Cnt_Cck_fail > 1000) ++ CurCCK_CCAThres = 0x83; ++ else ++ CurCCK_CCAThres = 0x40; ++ } ++ ++#if (RTL8192D_SUPPORT==1) ++ if(pDM_Odm->SupportICType == ODM_RTL8192D) ++ ODM_Write_CCK_CCA_Thres_92D(pDM_Odm, CurCCK_CCAThres); ++ else ++#endif ++ ODM_Write_CCK_CCA_Thres(pDM_Odm, CurCCK_CCAThres); ++} ++ ++VOID ++ODM_Write_CCK_CCA_Thres( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte CurCCK_CCAThres ++ ) ++{ ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ ++ if(pDM_DigTable->CurCCK_CCAThres!=CurCCK_CCAThres) //modify by Guo.Mingzhi 2012-01-03 ++ { ++ ODM_Write1Byte(pDM_Odm, ODM_REG(CCK_CCA,pDM_Odm), CurCCK_CCAThres); ++ } ++ pDM_DigTable->PreCCK_CCAThres = pDM_DigTable->CurCCK_CCAThres; ++ pDM_DigTable->CurCCK_CCAThres = CurCCK_CCAThres; ++ ++} ++ ++//3============================================================ ++//3 BB Power Save ++//3============================================================ ++VOID ++odm_DynamicBBPowerSavingInit( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ pPS_T pDM_PSTable = &pDM_Odm->DM_PSTable; ++ ++ pDM_PSTable->PreCCAState = CCA_MAX; ++ pDM_PSTable->CurCCAState = CCA_MAX; ++ pDM_PSTable->PreRFState = RF_MAX; ++ pDM_PSTable->CurRFState = RF_MAX; ++ pDM_PSTable->Rssi_val_min = 0; ++ pDM_PSTable->initialize = 0; ++} ++ ++ ++VOID ++odm_DynamicBBPowerSaving( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE)) ++ ++ if ((pDM_Odm->SupportICType != ODM_RTL8192C) && (pDM_Odm->SupportICType != ODM_RTL8723A)) ++ return; ++ if(!(pDM_Odm->SupportAbility & ODM_BB_PWR_SAVE)) ++ return; ++ if(!(pDM_Odm->SupportPlatform & (ODM_MP|ODM_CE))) ++ return; ++ ++ //1 2.Power Saving for 92C ++ if((pDM_Odm->SupportICType == ODM_RTL8192C) &&(pDM_Odm->RFType == ODM_2T2R)) ++ { ++ odm_1R_CCA(pDM_Odm); ++ } ++ ++ // 20100628 Joseph: Turn off BB power save for 88CE because it makesthroughput unstable. ++ // 20100831 Joseph: Turn ON BB power save again after modifying AGC delay from 900ns ot 600ns. ++ //1 3.Power Saving for 88C ++ else ++ { ++ ODM_RF_Saving(pDM_Odm, FALSE); ++ } ++#endif // #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ++} ++ ++VOID ++odm_1R_CCA( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ pPS_T pDM_PSTable = &pDM_Odm->DM_PSTable; ++ ++ if(pDM_Odm->RSSI_Min!= 0xFF) ++ { ++ ++ if(pDM_PSTable->PreCCAState == CCA_2R) ++ { ++ if(pDM_Odm->RSSI_Min >= 35) ++ pDM_PSTable->CurCCAState = CCA_1R; ++ else ++ pDM_PSTable->CurCCAState = CCA_2R; ++ ++ } ++ else{ ++ if(pDM_Odm->RSSI_Min <= 30) ++ pDM_PSTable->CurCCAState = CCA_2R; ++ else ++ pDM_PSTable->CurCCAState = CCA_1R; ++ } ++ } ++ else{ ++ pDM_PSTable->CurCCAState=CCA_MAX; ++ } ++ ++ if(pDM_PSTable->PreCCAState != pDM_PSTable->CurCCAState) ++ { ++ if(pDM_PSTable->CurCCAState == CCA_1R) ++ { ++ if( pDM_Odm->RFType ==ODM_2T2R ) ++ { ++ ODM_SetBBReg(pDM_Odm, 0xc04 , bMaskByte0, 0x13); ++ //PHY_SetBBReg(pAdapter, 0xe70, bMaskByte3, 0x20); ++ } ++ else ++ { ++ ODM_SetBBReg(pDM_Odm, 0xc04 , bMaskByte0, 0x23); ++ //PHY_SetBBReg(pAdapter, 0xe70, 0x7fc00000, 0x10c); // Set RegE70[30:22] = 9b'100001100 ++ } ++ } ++ else ++ { ++ ODM_SetBBReg(pDM_Odm, 0xc04 , bMaskByte0, 0x33); ++ //PHY_SetBBReg(pAdapter,0xe70, bMaskByte3, 0x63); ++ } ++ pDM_PSTable->PreCCAState = pDM_PSTable->CurCCAState; ++ } ++ //ODM_RT_TRACE(pDM_Odm, COMP_BB_POWERSAVING, DBG_LOUD, ("CCAStage = %s\n",(pDM_PSTable->CurCCAState==0)?"1RCCA":"2RCCA")); ++} ++ ++void ++ODM_RF_Saving( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte bForceInNormal ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE != ODM_AP) ++ pPS_T pDM_PSTable = &pDM_Odm->DM_PSTable; ++ u1Byte Rssi_Up_bound = 30 ; ++ u1Byte Rssi_Low_bound = 25; ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ if(pDM_Odm->PatchID == 40 ) //RT_CID_819x_FUNAI_TV ++ { ++ Rssi_Up_bound = 50 ; ++ Rssi_Low_bound = 45; ++ } ++ #endif ++ if(pDM_PSTable->initialize == 0){ ++ ++ pDM_PSTable->Reg874 = (ODM_GetBBReg(pDM_Odm, 0x874, bMaskDWord)&0x1CC000)>>14; ++ pDM_PSTable->RegC70 = (ODM_GetBBReg(pDM_Odm, 0xc70, bMaskDWord)&BIT3)>>3; ++ pDM_PSTable->Reg85C = (ODM_GetBBReg(pDM_Odm, 0x85c, bMaskDWord)&0xFF000000)>>24; ++ pDM_PSTable->RegA74 = (ODM_GetBBReg(pDM_Odm, 0xa74, bMaskDWord)&0xF000)>>12; ++ //Reg818 = PHY_QueryBBReg(pAdapter, 0x818, bMaskDWord); ++ pDM_PSTable->initialize = 1; ++ } ++ ++ if(!bForceInNormal) ++ { ++ if(pDM_Odm->RSSI_Min != 0xFF) ++ { ++ if(pDM_PSTable->PreRFState == RF_Normal) ++ { ++ if(pDM_Odm->RSSI_Min >= Rssi_Up_bound) ++ pDM_PSTable->CurRFState = RF_Save; ++ else ++ pDM_PSTable->CurRFState = RF_Normal; ++ } ++ else{ ++ if(pDM_Odm->RSSI_Min <= Rssi_Low_bound) ++ pDM_PSTable->CurRFState = RF_Normal; ++ else ++ pDM_PSTable->CurRFState = RF_Save; ++ } ++ } ++ else ++ pDM_PSTable->CurRFState=RF_MAX; ++ } ++ else ++ { ++ pDM_PSTable->CurRFState = RF_Normal; ++ } ++ ++ if(pDM_PSTable->PreRFState != pDM_PSTable->CurRFState) ++ { ++ if(pDM_PSTable->CurRFState == RF_Save) ++ { ++ // 8723 RSSI report will be wrong. Set 0x874[5]=1 when enter BB power saving mode. ++ // Suggested by SD3 Yu-Nan. 2011.01.20. ++ if(pDM_Odm->SupportICType == ODM_RTL8723A) ++ { ++ ODM_SetBBReg(pDM_Odm, 0x874 , BIT5, 0x1); //Reg874[5]=1b'1 ++ } ++ ODM_SetBBReg(pDM_Odm, 0x874 , 0x1C0000, 0x2); //Reg874[20:18]=3'b010 ++ ODM_SetBBReg(pDM_Odm, 0xc70, BIT3, 0); //RegC70[3]=1'b0 ++ ODM_SetBBReg(pDM_Odm, 0x85c, 0xFF000000, 0x63); //Reg85C[31:24]=0x63 ++ ODM_SetBBReg(pDM_Odm, 0x874, 0xC000, 0x2); //Reg874[15:14]=2'b10 ++ ODM_SetBBReg(pDM_Odm, 0xa74, 0xF000, 0x3); //RegA75[7:4]=0x3 ++ ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x0); //Reg818[28]=1'b0 ++ ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x1); //Reg818[28]=1'b1 ++ //ODM_RT_TRACE(pDM_Odm, COMP_BB_POWERSAVING, DBG_LOUD, (" RF_Save")); ++ } ++ else ++ { ++ ODM_SetBBReg(pDM_Odm, 0x874 , 0x1CC000, pDM_PSTable->Reg874); ++ ODM_SetBBReg(pDM_Odm, 0xc70, BIT3, pDM_PSTable->RegC70); ++ ODM_SetBBReg(pDM_Odm, 0x85c, 0xFF000000, pDM_PSTable->Reg85C); ++ ODM_SetBBReg(pDM_Odm, 0xa74, 0xF000, pDM_PSTable->RegA74); ++ ODM_SetBBReg(pDM_Odm,0x818, BIT28, 0x0); ++ ++ if(pDM_Odm->SupportICType == ODM_RTL8723A) ++ { ++ ODM_SetBBReg(pDM_Odm,0x874 , BIT5, 0x0); //Reg874[5]=1b'0 ++ } ++ //ODM_RT_TRACE(pDM_Odm, COMP_BB_POWERSAVING, DBG_LOUD, (" RF_Normal")); ++ } ++ pDM_PSTable->PreRFState =pDM_PSTable->CurRFState; ++ } ++#endif ++} ++ ++ ++//3============================================================ ++//3 RATR MASK ++//3============================================================ ++//3============================================================ ++//3 Rate Adaptive ++//3============================================================ ++ ++VOID ++odm_RateAdaptiveMaskInit( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ PODM_RATE_ADAPTIVE pOdmRA = &pDM_Odm->RateAdaptive; ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PMGNT_INFO pMgntInfo = &pDM_Odm->Adapter->MgntInfo; ++ PRATE_ADAPTIVE pRA = (PRATE_ADAPTIVE)&pMgntInfo->RateAdaptive; ++ ++ pRA->RATRState = DM_RATR_STA_INIT; ++ if (pMgntInfo->DM_Type == DM_Type_ByDriver) ++ pMgntInfo->bUseRAMask = TRUE; ++ else ++ pMgntInfo->bUseRAMask = FALSE; ++ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ pOdmRA->Type = DM_Type_ByDriver; ++ if (pOdmRA->Type == DM_Type_ByDriver) ++ pDM_Odm->bUseRAMask = _TRUE; ++ else ++ pDM_Odm->bUseRAMask = _FALSE; ++ ++#endif ++ ++ pOdmRA->RATRState = DM_RATR_STA_INIT; ++ pOdmRA->HighRSSIThresh = 50; ++ pOdmRA->LowRSSIThresh = 20; ++} ++ ++#if (DM_ODM_SUPPORT_TYPE & ODM_MP) ++VOID ++ODM_RateAdaptiveStateApInit( ++ IN PADAPTER Adapter , ++ IN PRT_WLAN_STA pEntry ++ ) ++{ ++ PRATE_ADAPTIVE pRA = (PRATE_ADAPTIVE)&pEntry->RateAdaptive; ++ pRA->RATRState = DM_RATR_STA_INIT; ++} ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++u4Byte ODM_Get_Rate_Bitmap( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte macid, ++ IN u4Byte ra_mask, ++ IN u1Byte rssi_level) ++{ ++ PSTA_INFO_T pEntry; ++ u4Byte rate_bitmap = 0x0fffffff; ++ u1Byte WirelessMode; ++ //u1Byte WirelessMode =*(pDM_Odm->pWirelessMode); ++ ++ ++ pEntry = pDM_Odm->pODM_StaInfo[macid]; ++ if(!IS_STA_VALID(pEntry)) ++ return ra_mask; ++ ++ WirelessMode = pEntry->wireless_mode; ++ ++ switch(WirelessMode) ++ { ++ case ODM_WM_B: ++ if(ra_mask & 0x0000000c) //11M or 5.5M enable ++ rate_bitmap = 0x0000000d; ++ else ++ rate_bitmap = 0x0000000f; ++ break; ++ ++ case (ODM_WM_A|ODM_WM_G): ++ if(rssi_level == DM_RATR_STA_HIGH) ++ rate_bitmap = 0x00000f00; ++ else ++ rate_bitmap = 0x00000ff0; ++ break; ++ ++ case (ODM_WM_B|ODM_WM_G): ++ if(rssi_level == DM_RATR_STA_HIGH) ++ rate_bitmap = 0x00000f00; ++ else if(rssi_level == DM_RATR_STA_MIDDLE) ++ rate_bitmap = 0x00000ff0; ++ else ++ rate_bitmap = 0x00000ff5; ++ break; ++ ++ case (ODM_WM_G|ODM_WM_N24G) : ++ case (ODM_WM_B|ODM_WM_G|ODM_WM_N24G) : ++ case (ODM_WM_A|ODM_WM_B|ODM_WM_G|ODM_WM_N24G) : ++ { ++ if ( pDM_Odm->RFType == ODM_1T2R ||pDM_Odm->RFType == ODM_1T1R) ++ { ++ if(rssi_level == DM_RATR_STA_HIGH) ++ { ++ rate_bitmap = 0x000f0000; ++ } ++ else if(rssi_level == DM_RATR_STA_MIDDLE) ++ { ++ rate_bitmap = 0x000ff000; ++ } ++ else{ ++ if (*(pDM_Odm->pBandWidth) == ODM_BW40M) ++ rate_bitmap = 0x000ff015; ++ else ++ rate_bitmap = 0x000ff005; ++ } ++ } ++ else ++ { ++ if(rssi_level == DM_RATR_STA_HIGH) ++ { ++ rate_bitmap = 0x0f8f0000; ++ } ++ else if(rssi_level == DM_RATR_STA_MIDDLE) ++ { ++ rate_bitmap = 0x0f8ff000; ++ } ++ else ++ { ++ if (*(pDM_Odm->pBandWidth) == ODM_BW40M) ++ rate_bitmap = 0x0f8ff015; ++ else ++ rate_bitmap = 0x0f8ff005; ++ } ++ } ++ } ++ break; ++ default: ++ //case WIRELESS_11_24N: ++ //case WIRELESS_11_5N: ++ if(pDM_Odm->RFType == RF_1T2R) ++ rate_bitmap = 0x000fffff; ++ else ++ rate_bitmap = 0x0fffffff; ++ break; ++ ++ } ++ ++ //printk("%s ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x \n",__FUNCTION__,rssi_level,WirelessMode,rate_bitmap); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, (" ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x \n",rssi_level,WirelessMode,rate_bitmap)); ++ ++ return rate_bitmap; ++ ++} ++#endif ++ ++/*----------------------------------------------------------------------------- ++ * Function: odm_RefreshRateAdaptiveMask() ++ * ++ * Overview: Update rate table mask according to rssi ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/27/2009 hpfan Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++VOID ++odm_RefreshRateAdaptiveMask( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_RA_MASK)) ++ return; ++ // ++ // 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate ++ // at the same time. In the stage2/3, we need to prive universal interface and merge all ++ // HW dynamic mechanism. ++ // ++ switch (pDM_Odm->SupportPlatform) ++ { ++ case ODM_MP: ++ odm_RefreshRateAdaptiveMaskMP(pDM_Odm); ++ break; ++ ++ case ODM_CE: ++ odm_RefreshRateAdaptiveMaskCE(pDM_Odm); ++ break; ++ ++ case ODM_AP: ++ case ODM_ADSL: ++ odm_RefreshRateAdaptiveMaskAPADSL(pDM_Odm); ++ break; ++ } ++ ++} ++ ++VOID ++odm_RefreshRateAdaptiveMaskMP( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PADAPTER pAdapter = pDM_Odm->Adapter; ++ PADAPTER pTargetAdapter = NULL; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ PMGNT_INFO pMgntInfo = GetDefaultMgntInfo(pAdapter); ++ //PRATE_ADAPTIVE pRA = (PRATE_ADAPTIVE)&pMgntInfo->RateAdaptive; ++ PODM_RATE_ADAPTIVE pRA = &pDM_Odm->RateAdaptive; ++ ++ if(pAdapter->bDriverStopped) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("<---- odm_RefreshRateAdaptiveMask(): driver is going to unload\n")); ++ return; ++ } ++ ++ if(!pMgntInfo->bUseRAMask) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("<---- odm_RefreshRateAdaptiveMask(): driver does not control rate adaptive mask\n")); ++ return; ++ } ++ ++ // if default port is connected, update RA table for default port (infrastructure mode only) ++ if(pAdapter->MgntInfo.mAssoc && (!ACTING_AS_AP(pAdapter))) ++ { ++ if( ODM_RAStateCheck(pDM_Odm, pHalData->UndecoratedSmoothedPWDB, pMgntInfo->bSetTXPowerTrainingByOid, &pRA->RATRState) ) ++ { ++ ODM_PRINT_ADDR(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("Target AP addr : "), pMgntInfo->Bssid); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI:%d, RSSI_LEVEL:%d\n", pHalData->UndecoratedSmoothedPWDB, pRA->RATRState)); ++ pAdapter->HalFunc.UpdateHalRAMaskHandler( ++ pAdapter, ++ FALSE, ++ 0, ++ NULL, ++ NULL, ++ pRA->RATRState, ++ RAMask_Normal); ++ } ++ } ++ ++ // ++ // The following part configure AP/VWifi/IBSS rate adaptive mask. ++ // ++ ++ if(pMgntInfo->mIbss) ++ { ++ // Target: AP/IBSS peer. ++ pTargetAdapter = GetDefaultAdapter(pAdapter); ++ } ++ else ++ { ++ pTargetAdapter = GetFirstAPAdapter(pAdapter); ++ } ++ ++ // if extension port (softap) is started, updaet RA table for more than one clients associate ++ if(pTargetAdapter != NULL) ++ { ++ int i; ++ PRT_WLAN_STA pEntry; ++ PRATE_ADAPTIVE pEntryRA; ++ ++ for(i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) ++ { ++#if 0 //By YJ,120208 ++ if( pTargetAdapter->MgntInfo.AsocEntry[i].bUsed && pTargetAdapter->MgntInfo.AsocEntry[i].bAssociated) ++ { ++ pEntry = pTargetAdapter->MgntInfo.AsocEntry+i; ++ pEntryRA = &pEntry->RateAdaptive; ++ if( ODM_RAStateCheck(pDM_Odm, pEntry->rssi_stat.UndecoratedSmoothedPWDB, pMgntInfo->bSetTXPowerTrainingByOid, &pEntryRA->RATRState) ) ++ { ++ ODM_PRINT_ADDR(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("Target STA addr : "), pEntry->MacAddr); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI:%d, RSSI_LEVEL:%d\n", pEntry->rssi_stat.UndecoratedSmoothedPWDB, pEntryRA->RATRState)); ++ pAdapter->HalFunc.UpdateHalRAMaskHandler( ++ pTargetAdapter, ++ FALSE, ++ pEntry->AID+1, ++ pEntry->MacAddr, ++ pEntry, ++ pEntryRA->RATRState, ++ RAMask_Normal); ++ } ++ } ++#else ++ pEntry = AsocEntry_EnumStation(pTargetAdapter, i); ++ if(NULL != pEntry) ++ { ++ if(pEntry->bAssociated) ++ { ++ pEntryRA = &pEntry->RateAdaptive; ++ if( ODM_RAStateCheck(pDM_Odm, pEntry->rssi_stat.UndecoratedSmoothedPWDB, pMgntInfo->bSetTXPowerTrainingByOid, &pEntryRA->RATRState) ) ++ { ++ ODM_PRINT_ADDR(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("Target STA addr : "), pEntry->MacAddr); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI:%d, RSSI_LEVEL:%d\n", pEntry->rssi_stat.UndecoratedSmoothedPWDB, pEntryRA->RATRState)); ++ pAdapter->HalFunc.UpdateHalRAMaskHandler( ++ pTargetAdapter, ++ FALSE, ++ pEntry->AID+1, ++ pEntry->MacAddr, ++ pEntry, ++ pEntryRA->RATRState, ++ RAMask_Normal); ++ } ++ } ++ } ++#endif ++ } ++ } ++ ++ if(pMgntInfo->bSetTXPowerTrainingByOid) ++ pMgntInfo->bSetTXPowerTrainingByOid = FALSE; ++#endif // #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++} ++ ++ ++VOID ++odm_RefreshRateAdaptiveMaskCE( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ u1Byte i; ++ PADAPTER pAdapter = pDM_Odm->Adapter; ++ ++ if(pAdapter->bDriverStopped) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("<---- odm_RefreshRateAdaptiveMask(): driver is going to unload\n")); ++ return; ++ } ++ ++ if(!pDM_Odm->bUseRAMask) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("<---- odm_RefreshRateAdaptiveMask(): driver does not control rate adaptive mask\n")); ++ return; ++ } ++ ++ //printk("==> %s \n",__FUNCTION__); ++ ++ for(i=0; ipODM_StaInfo[i]; ++ if(IS_STA_VALID(pstat) ) { ++ if(IS_MCAST( pstat->hwaddr)) //if(psta->mac_id ==1) ++ continue; ++ if( TRUE == ODM_RAStateCheck(pDM_Odm, pstat->rssi_stat.UndecoratedSmoothedPWDB, FALSE , &pstat->rssi_level) ) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI:%d, RSSI_LEVEL:%d\n", pstat->rssi_stat.UndecoratedSmoothedPWDB, pstat->rssi_level)); ++ //printk("RSSI:%d, RSSI_LEVEL:%d\n", pstat->rssi_stat.UndecoratedSmoothedPWDB, pstat->rssi_level); ++ rtw_hal_update_ra_mask(pstat, pstat->rssi_level); ++ } ++ ++ } ++ } ++ ++#endif ++} ++ ++VOID ++odm_RefreshRateAdaptiveMaskAPADSL( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ struct rtl8192cd_priv *priv = pDM_Odm->priv; ++ struct stat_info *pstat; ++ ++ if (!priv->pmib->dot11StationConfigEntry.autoRate) ++ return; ++ ++ if (list_empty(&priv->asoc_list)) ++ return; ++ ++ list_for_each_entry(pstat, &priv->asoc_list, asoc_list) { ++ if(ODM_RAStateCheck(pDM_Odm, (s4Byte)pstat->rssi, FALSE, &pstat->rssi_level) ) { ++ ODM_PRINT_ADDR(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("Target STA addr : "), pstat->hwaddr); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI:%d, RSSI_LEVEL:%d\n", pstat->rssi, pstat->rssi_level)); ++ ++#ifdef CONFIG_RTL_88E_SUPPORT ++ if (GET_CHIP_VER(priv)==VERSION_8188E) { ++#ifdef TXREPORT ++ add_RATid(priv, pstat); ++#endif ++ } else ++#endif ++ { ++#if defined(CONFIG_RTL_92D_SUPPORT) || defined(CONFIG_RTL_92C_SUPPORT) ++ add_update_RATid(priv, pstat); ++#endif ++ } ++ } ++ } ++#endif ++} ++ ++// Return Value: BOOLEAN ++// - TRUE: RATRState is changed. ++BOOLEAN ++ODM_RAStateCheck( ++ IN PDM_ODM_T pDM_Odm, ++ IN s4Byte RSSI, ++ IN BOOLEAN bForceUpdate, ++ OUT pu1Byte pRATRState ++ ) ++{ ++ PODM_RATE_ADAPTIVE pRA = &pDM_Odm->RateAdaptive; ++ const u1Byte GoUpGap = 5; ++ u1Byte HighRSSIThreshForRA = pRA->HighRSSIThresh; ++ u1Byte LowRSSIThreshForRA = pRA->LowRSSIThresh; ++ u1Byte RATRState; ++ ++ // Threshold Adjustment: ++ // when RSSI state trends to go up one or two levels, make sure RSSI is high enough. ++ // Here GoUpGap is added to solve the boundary's level alternation issue. ++ switch (*pRATRState) ++ { ++ case DM_RATR_STA_INIT: ++ case DM_RATR_STA_HIGH: ++ break; ++ ++ case DM_RATR_STA_MIDDLE: ++ HighRSSIThreshForRA += GoUpGap; ++ break; ++ ++ case DM_RATR_STA_LOW: ++ HighRSSIThreshForRA += GoUpGap; ++ LowRSSIThreshForRA += GoUpGap; ++ break; ++ ++ default: ++ ODM_RT_ASSERT(pDM_Odm, FALSE, ("wrong rssi level setting %d !", *pRATRState) ); ++ break; ++ } ++ ++ // Decide RATRState by RSSI. ++ if(RSSI > HighRSSIThreshForRA) ++ RATRState = DM_RATR_STA_HIGH; ++ else if(RSSI > LowRSSIThreshForRA) ++ RATRState = DM_RATR_STA_MIDDLE; ++ else ++ RATRState = DM_RATR_STA_LOW; ++ //printk("==>%s,RATRState:0x%02x ,RSSI:%d \n",__FUNCTION__,RATRState,RSSI); ++ ++ if( *pRATRState!=RATRState || bForceUpdate) ++ { ++ ODM_RT_TRACE( pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI Level %d -> %d\n", *pRATRState, RATRState) ); ++ *pRATRState = RATRState; ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++ ++//============================================================ ++ ++//3============================================================ ++//3 Dynamic Tx Power ++//3============================================================ ++ ++VOID ++odm_DynamicTxPowerInit( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ #if DEV_BUS_TYPE==RT_USB_INTERFACE ++ if(RT_GetInterfaceSelection(Adapter) == INTF_SEL1_USB_High_Power) ++ { ++ odm_DynamicTxPowerSavePowerIndex(pDM_Odm); ++ pMgntInfo->bDynamicTxPowerEnable = TRUE; ++ } ++ else ++ #else ++ //so 92c pci do not need dynamic tx power? vivi check it later ++ if(IS_HARDWARE_TYPE_8192D(Adapter)) ++ pMgntInfo->bDynamicTxPowerEnable = TRUE; ++ else ++ pMgntInfo->bDynamicTxPowerEnable = FALSE; ++ #endif ++ ++ ++ pHalData->LastDTPLvl = TxHighPwrLevel_Normal; ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ pdmpriv->bDynamicTxPowerEnable = _FALSE; ++ ++ #if (RTL8192C_SUPPORT==1) ++ #ifdef CONFIG_USB_HCI ++ ++ #ifdef CONFIG_INTEL_PROXIM ++ if((pHalData->BoardType == BOARD_USB_High_PA)||(Adapter->proximity.proxim_support==_TRUE)) ++ #else ++ if(pHalData->BoardType == BOARD_USB_High_PA) ++ #endif ++ ++ { ++ //odm_SavePowerIndex(Adapter); ++ odm_DynamicTxPowerSavePowerIndex(pDM_Odm); ++ pdmpriv->bDynamicTxPowerEnable = _TRUE; ++ } ++ else ++ #else ++ pdmpriv->bDynamicTxPowerEnable = _FALSE; ++ #endif ++ #endif ++ ++ pdmpriv->LastDTPLvl = TxHighPwrLevel_Normal; ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++ ++#endif ++ ++} ++ ++VOID ++odm_DynamicTxPowerSavePowerIndex( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ u1Byte index; ++ u4Byte Power_Index_REG[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a}; ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ for(index = 0; index< 6; index++) ++ pHalData->PowerIndex_backup[index] = PlatformEFIORead1Byte(Adapter, Power_Index_REG[index]); ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ for(index = 0; index< 6; index++) ++ pdmpriv->PowerIndex_backup[index] = rtw_read8(Adapter, Power_Index_REG[index]); ++#endif ++} ++ ++VOID ++odm_DynamicTxPowerRestorePowerIndex( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ u1Byte index; ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_MP)) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u4Byte Power_Index_REG[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a}; ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ for(index = 0; index< 6; index++) ++ PlatformEFIOWrite1Byte(Adapter, Power_Index_REG[index], pHalData->PowerIndex_backup[index]); ++#elif(DM_ODM_SUPPORT_TYPE == ODM_CE) ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ for(index = 0; index< 6; index++) ++ rtw_write8(Adapter, Power_Index_REG[index], pdmpriv->PowerIndex_backup[index]); ++#endif ++#endif ++} ++ ++VOID ++odm_DynamicTxPowerWritePowerIndex( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte Value) ++{ ++ ++ u1Byte index; ++ u4Byte Power_Index_REG[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a}; ++ ++ for(index = 0; index< 6; index++) ++ //PlatformEFIOWrite1Byte(Adapter, Power_Index_REG[index], Value); ++ ODM_Write1Byte(pDM_Odm, Power_Index_REG[index], Value); ++ ++} ++ ++ ++VOID ++odm_DynamicTxPower( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ // ++ // For AP/ADSL use prtl8192cd_priv ++ // For CE/NIC use PADAPTER ++ // ++ //PADAPTER pAdapter = pDM_Odm->Adapter; ++// prtl8192cd_priv priv = pDM_Odm->priv; ++ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_DYNAMIC_TXPWR)) ++ return; ++ ++ // 2012/01/12 MH According to Luke's suggestion, only high power will support the feature. ++ if (pDM_Odm->ExtPA == FALSE) ++ return; ++ ++ ++ // ++ // 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate ++ // at the same time. In the stage2/3, we need to prive universal interface and merge all ++ // HW dynamic mechanism. ++ // ++ switch (pDM_Odm->SupportPlatform) ++ { ++ case ODM_MP: ++ case ODM_CE: ++ odm_DynamicTxPowerNIC(pDM_Odm); ++ break; ++ case ODM_AP: ++ odm_DynamicTxPowerAP(pDM_Odm); ++ break; ++ ++ case ODM_ADSL: ++ //odm_DIGAP(pDM_Odm); ++ break; ++ } ++ ++ ++} ++ ++ ++VOID ++odm_DynamicTxPowerNIC( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_DYNAMIC_TXPWR)) ++ return; ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE)) ++ ++ if(pDM_Odm->SupportICType == ODM_RTL8192C) ++ { ++ odm_DynamicTxPower_92C(pDM_Odm); ++ } ++ else if(pDM_Odm->SupportICType == ODM_RTL8192D) ++ { ++ odm_DynamicTxPower_92D(pDM_Odm); ++ } ++ else if (pDM_Odm->SupportICType & ODM_RTL8188E) ++ { ++ // Add Later. ++ } ++ else if (pDM_Odm->SupportICType == ODM_RTL8188E) ++ { ++ // ??? ++ // This part need to be redefined. ++ } ++#endif ++} ++ ++VOID ++odm_DynamicTxPowerAP( ++ IN PDM_ODM_T pDM_Odm ++ ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ s4Byte i; ++ ++ if(!priv->pshare->rf_ft_var.tx_pwr_ctrl) ++ return; ++ ++#ifdef HIGH_POWER_EXT_PA ++ if(pDM_Odm->ExtPA) ++ tx_power_control(priv); ++#endif ++ ++ /* ++ * Check if station is near by to use lower tx power ++ */ ++ ++ if ((priv->up_time % 3) == 0 ) { ++ for(i=0; ipODM_StaInfo[i]; ++ if(IS_STA_VALID(pstat) ) { ++ if ((pstat->hp_level == 0) && (pstat->rssi > TX_POWER_NEAR_FIELD_THRESH_AP+4)) ++ pstat->hp_level = 1; ++ else if ((pstat->hp_level == 1) && (pstat->rssi < TX_POWER_NEAR_FIELD_THRESH_AP)) ++ pstat->hp_level = 0; ++ } ++ } ++ } ++ ++#endif ++} ++ ++ ++VOID ++odm_DynamicTxPower_92C( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ s4Byte UndecoratedSmoothedPWDB; ++ ++ ++ // STA not connected and AP not connected ++ if((!pMgntInfo->bMediaConnect) && ++ (pHalData->EntryMinUndecoratedSmoothedPWDB == 0)) ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("Not connected to any \n")); ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++ ++ //the LastDTPlvl should reset when disconnect, ++ //otherwise the tx power level wouldn't change when disconnect and connect again. ++ // Maddest 20091220. ++ pHalData->LastDTPLvl=TxHighPwrLevel_Normal; ++ return; ++ } ++ ++#if (INTEL_PROXIMITY_SUPPORT == 1) ++ // Intel set fixed tx power ++ if(pMgntInfo->IntelProximityModeInfo.PowerOutput > 0) ++ { ++ switch(pMgntInfo->IntelProximityModeInfo.PowerOutput){ ++ case 1: ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_100; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_100\n")); ++ break; ++ case 2: ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_70; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_70\n")); ++ break; ++ case 3: ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_50; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_50\n")); ++ break; ++ case 4: ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_35; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_35\n")); ++ break; ++ case 5: ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_15; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_15\n")); ++ break; ++ default: ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_100; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_100\n")); ++ break; ++ } ++ } ++ else ++#endif ++ { ++ if( (pMgntInfo->bDynamicTxPowerEnable != TRUE) || ++ (pHalData->DMFlag & HAL_DM_HIPWR_DISABLE) || ++ pMgntInfo->IOTAction & HT_IOT_ACT_DISABLE_HIGH_POWER) ++ { ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++ } ++ else ++ { ++ if(pMgntInfo->bMediaConnect) // Default port ++ { ++ if(ACTING_AS_AP(Adapter) || ACTING_AS_IBSS(Adapter)) ++ { ++ UndecoratedSmoothedPWDB = pHalData->EntryMinUndecoratedSmoothedPWDB; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("AP Client PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); ++ } ++ else ++ { ++ UndecoratedSmoothedPWDB = pHalData->UndecoratedSmoothedPWDB; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("STA Default Port PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); ++ } ++ } ++ else // associated entry pwdb ++ { ++ UndecoratedSmoothedPWDB = pHalData->EntryMinUndecoratedSmoothedPWDB; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("AP Ext Port PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); ++ } ++ ++ if(UndecoratedSmoothedPWDB >= TX_POWER_NEAR_FIELD_THRESH_LVL2) ++ { ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Level2; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Level1 (TxPwr=0x0)\n")); ++ } ++ else if((UndecoratedSmoothedPWDB < (TX_POWER_NEAR_FIELD_THRESH_LVL2-3)) && ++ (UndecoratedSmoothedPWDB >= TX_POWER_NEAR_FIELD_THRESH_LVL1) ) ++ { ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Level1; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Level1 (TxPwr=0x10)\n")); ++ } ++ else if(UndecoratedSmoothedPWDB < (TX_POWER_NEAR_FIELD_THRESH_LVL1-5)) ++ { ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Normal\n")); ++ } ++ } ++ } ++ if( pHalData->DynamicTxHighPowerLvl != pHalData->LastDTPLvl ) ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("PHY_SetTxPowerLevel8192C() Channel = %d \n" , pHalData->CurrentChannel)); ++ PHY_SetTxPowerLevel8192C(Adapter, pHalData->CurrentChannel); ++ if( (pHalData->DynamicTxHighPowerLvl == TxHighPwrLevel_Normal) && ++ (pHalData->LastDTPLvl == TxHighPwrLevel_Level1 || pHalData->LastDTPLvl == TxHighPwrLevel_Level2)) //TxHighPwrLevel_Normal ++ odm_DynamicTxPowerRestorePowerIndex(pDM_Odm); ++ else if(pHalData->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) ++ odm_DynamicTxPowerWritePowerIndex(pDM_Odm, 0x14); ++ else if(pHalData->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) ++ odm_DynamicTxPowerWritePowerIndex(pDM_Odm, 0x10); ++ } ++ pHalData->LastDTPLvl = pHalData->DynamicTxHighPowerLvl; ++ ++ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ ++ #if (RTL8192C_SUPPORT==1) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ int UndecoratedSmoothedPWDB; ++ ++ if(!pdmpriv->bDynamicTxPowerEnable) ++ return; ++ ++#ifdef CONFIG_INTEL_PROXIM ++ if(Adapter->proximity.proxim_on== _TRUE){ ++ struct proximity_priv *prox_priv=Adapter->proximity.proximity_priv; ++ // Intel set fixed tx power ++ printk("\n %s Adapter->proximity.proxim_on=%d prox_priv->proxim_modeinfo->power_output=%d \n",__FUNCTION__,Adapter->proximity.proxim_on,prox_priv->proxim_modeinfo->power_output); ++ if(prox_priv!=NULL){ ++ if(prox_priv->proxim_modeinfo->power_output> 0) ++ { ++ switch(prox_priv->proxim_modeinfo->power_output) ++ { ++ case 1: ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_100; ++ printk("TxHighPwrLevel_100\n"); ++ break; ++ case 2: ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_70; ++ printk("TxHighPwrLevel_70\n"); ++ break; ++ case 3: ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_50; ++ printk("TxHighPwrLevel_50\n"); ++ break; ++ case 4: ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_35; ++ printk("TxHighPwrLevel_35\n"); ++ break; ++ case 5: ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_15; ++ printk("TxHighPwrLevel_15\n"); ++ break; ++ default: ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_100; ++ printk("TxHighPwrLevel_100\n"); ++ break; ++ } ++ } ++ } ++ } ++ else ++#endif ++ { ++ // STA not connected and AP not connected ++ if((check_fwstate(pmlmepriv, _FW_LINKED) != _TRUE) && ++ (pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0)) ++ { ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("Not connected to any \n")); ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++ ++ //the LastDTPlvl should reset when disconnect, ++ //otherwise the tx power level wouldn't change when disconnect and connect again. ++ // Maddest 20091220. ++ pdmpriv->LastDTPLvl=TxHighPwrLevel_Normal; ++ return; ++ } ++ ++ if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) // Default port ++ { ++ #if 0 ++ //todo: AP Mode ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE)) ++ { ++ UndecoratedSmoothedPWDB = pdmpriv->EntryMinUndecoratedSmoothedPWDB; ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("AP Client PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); ++ } ++ else ++ { ++ UndecoratedSmoothedPWDB = pdmpriv->UndecoratedSmoothedPWDB; ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("STA Default Port PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); ++ } ++ #else ++ UndecoratedSmoothedPWDB = pdmpriv->EntryMinUndecoratedSmoothedPWDB; ++ #endif ++ } ++ else // associated entry pwdb ++ { ++ UndecoratedSmoothedPWDB = pdmpriv->EntryMinUndecoratedSmoothedPWDB; ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("AP Ext Port PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); ++ } ++ ++ if(UndecoratedSmoothedPWDB >= TX_POWER_NEAR_FIELD_THRESH_LVL2) ++ { ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Level2; ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Level1 (TxPwr=0x0)\n")); ++ } ++ else if((UndecoratedSmoothedPWDB < (TX_POWER_NEAR_FIELD_THRESH_LVL2-3)) && ++ (UndecoratedSmoothedPWDB >= TX_POWER_NEAR_FIELD_THRESH_LVL1) ) ++ { ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Level1; ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Level1 (TxPwr=0x10)\n")); ++ } ++ else if(UndecoratedSmoothedPWDB < (TX_POWER_NEAR_FIELD_THRESH_LVL1-5)) ++ { ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Normal\n")); ++ } ++ } ++ if( (pdmpriv->DynamicTxHighPowerLvl != pdmpriv->LastDTPLvl) ) ++ { ++ PHY_SetTxPowerLevel8192C(Adapter, pHalData->CurrentChannel); ++ if(pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Normal) // HP1 -> Normal or HP2 -> Normal ++ odm_DynamicTxPowerRestorePowerIndex(pDM_Odm); ++ else if(pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) ++ odm_DynamicTxPowerWritePowerIndex(pDM_Odm, 0x14); ++ else if(pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) ++ odm_DynamicTxPowerWritePowerIndex(pDM_Odm, 0x10); ++ } ++ pdmpriv->LastDTPLvl = pdmpriv->DynamicTxHighPowerLvl; ++ #endif ++#endif // #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ++} ++ ++ ++VOID ++odm_DynamicTxPower_92D( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ s4Byte UndecoratedSmoothedPWDB; ++ ++ PADAPTER BuddyAdapter = Adapter->BuddyAdapter; ++ BOOLEAN bGetValueFromBuddyAdapter = dm_DualMacGetParameterFromBuddyAdapter(Adapter); ++ u1Byte HighPowerLvlBackForMac0 = TxHighPwrLevel_Level1; ++ ++ ++ // If dynamic high power is disabled. ++ if( (pMgntInfo->bDynamicTxPowerEnable != TRUE) || ++ (pHalData->DMFlag & HAL_DM_HIPWR_DISABLE) || ++ pMgntInfo->IOTAction & HT_IOT_ACT_DISABLE_HIGH_POWER) ++ { ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++ return; ++ } ++ ++ // STA not connected and AP not connected ++ if((!pMgntInfo->bMediaConnect) && ++ (pHalData->EntryMinUndecoratedSmoothedPWDB == 0)) ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("Not connected to any \n")); ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++ ++ //the LastDTPlvl should reset when disconnect, ++ //otherwise the tx power level wouldn't change when disconnect and connect again. ++ // Maddest 20091220. ++ pHalData->LastDTPLvl=TxHighPwrLevel_Normal; ++ return; ++ } ++ ++ if(pMgntInfo->bMediaConnect) // Default port ++ { ++ if(ACTING_AS_AP(Adapter) || pMgntInfo->mIbss) ++ { ++ UndecoratedSmoothedPWDB = pHalData->EntryMinUndecoratedSmoothedPWDB; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("AP Client PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); ++ } ++ else ++ { ++ UndecoratedSmoothedPWDB = pHalData->UndecoratedSmoothedPWDB; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("STA Default Port PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); ++ } ++ } ++ else // associated entry pwdb ++ { ++ UndecoratedSmoothedPWDB = pHalData->EntryMinUndecoratedSmoothedPWDB; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("AP Ext Port PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); ++ } ++ ++ if(IS_HARDWARE_TYPE_8192D(Adapter) && GET_HAL_DATA(Adapter)->CurrentBandType92D == 1){ ++ if(UndecoratedSmoothedPWDB >= 0x33) ++ { ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Level2; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("5G:TxHighPwrLevel_Level2 (TxPwr=0x0)\n")); ++ } ++ else if((UndecoratedSmoothedPWDB <0x33) && ++ (UndecoratedSmoothedPWDB >= 0x2b) ) ++ { ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Level1; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("5G:TxHighPwrLevel_Level1 (TxPwr=0x10)\n")); ++ } ++ else if(UndecoratedSmoothedPWDB < 0x2b) ++ { ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("5G:TxHighPwrLevel_Normal\n")); ++ } ++ ++ } ++ else ++ ++ { ++ if(UndecoratedSmoothedPWDB >= TX_POWER_NEAR_FIELD_THRESH_LVL2) ++ { ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Level1; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Level1 (TxPwr=0x0)\n")); ++ } ++ else if((UndecoratedSmoothedPWDB < (TX_POWER_NEAR_FIELD_THRESH_LVL2-3)) && ++ (UndecoratedSmoothedPWDB >= TX_POWER_NEAR_FIELD_THRESH_LVL1) ) ++ { ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Level1; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Level1 (TxPwr=0x10)\n")); ++ } ++ else if(UndecoratedSmoothedPWDB < (TX_POWER_NEAR_FIELD_THRESH_LVL1-5)) ++ { ++ pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Normal\n")); ++ } ++ ++ } ++ ++//sherry delete flag 20110517 ++ if(bGetValueFromBuddyAdapter) ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() mac 0 for mac 1 \n")); ++ if(Adapter->DualMacDMSPControl.bChangeTxHighPowerLvlForAnotherMacOfDMSP) ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() change value \n")); ++ HighPowerLvlBackForMac0 = pHalData->DynamicTxHighPowerLvl; ++ pHalData->DynamicTxHighPowerLvl = Adapter->DualMacDMSPControl.CurTxHighLvlForAnotherMacOfDMSP; ++ PHY_SetTxPowerLevel8192C(Adapter, pHalData->CurrentChannel); ++ pHalData->DynamicTxHighPowerLvl = HighPowerLvlBackForMac0; ++ Adapter->DualMacDMSPControl.bChangeTxHighPowerLvlForAnotherMacOfDMSP = FALSE; ++ } ++ } ++ ++ if( (pHalData->DynamicTxHighPowerLvl != pHalData->LastDTPLvl) ) ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("PHY_SetTxPowerLevel8192S() Channel = %d \n" , pHalData->CurrentChannel)); ++ if(Adapter->DualMacSmartConcurrent == TRUE) ++ { ++ if(BuddyAdapter == NULL) ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() BuddyAdapter == NULL case \n")); ++ if(!Adapter->bSlaveOfDMSP) ++ { ++ PHY_SetTxPowerLevel8192C(Adapter, pHalData->CurrentChannel); ++ } ++ } ++ else ++ { ++ if(pHalData->MacPhyMode92D == DUALMAC_SINGLEPHY) ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() BuddyAdapter DMSP \n")); ++ if(Adapter->bSlaveOfDMSP) ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() bslave case \n")); ++ BuddyAdapter->DualMacDMSPControl.bChangeTxHighPowerLvlForAnotherMacOfDMSP = TRUE; ++ BuddyAdapter->DualMacDMSPControl.CurTxHighLvlForAnotherMacOfDMSP = pHalData->DynamicTxHighPowerLvl; ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() master case \n")); ++ if(!bGetValueFromBuddyAdapter) ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() mac 0 for mac 0 \n")); ++ PHY_SetTxPowerLevel8192C(Adapter, pHalData->CurrentChannel); ++ } ++ } ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() BuddyAdapter DMDP\n")); ++ PHY_SetTxPowerLevel8192C(Adapter, pHalData->CurrentChannel); ++ } ++ } ++ } ++ else ++ { ++ PHY_SetTxPowerLevel8192C(Adapter, pHalData->CurrentChannel); ++ } ++ ++ } ++ pHalData->LastDTPLvl = pHalData->DynamicTxHighPowerLvl; ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++#if (RTL8192D_SUPPORT==1) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); ++ ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ DM_ODM_T *podmpriv = &pHalData->odmpriv; ++ int UndecoratedSmoothedPWDB; ++ #if (RTL8192D_EASY_SMART_CONCURRENT == 1) ++ PADAPTER BuddyAdapter = Adapter->BuddyAdapter; ++ BOOLEAN bGetValueFromBuddyAdapter = DualMacGetParameterFromBuddyAdapter(Adapter); ++ u8 HighPowerLvlBackForMac0 = TxHighPwrLevel_Level1; ++ #endif ++ ++ // If dynamic high power is disabled. ++ if( (pdmpriv->bDynamicTxPowerEnable != _TRUE) || ++ (!(podmpriv->SupportAbility& ODM_BB_DYNAMIC_TXPWR)) ) ++ { ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++ return; ++ } ++ ++ // STA not connected and AP not connected ++ if((check_fwstate(pmlmepriv, _FW_LINKED) != _TRUE) && ++ (pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0)) ++ { ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("Not connected to any \n")); ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++ //the LastDTPlvl should reset when disconnect, ++ //otherwise the tx power level wouldn't change when disconnect and connect again. ++ // Maddest 20091220. ++ pdmpriv->LastDTPLvl=TxHighPwrLevel_Normal; ++ return; ++ } ++ ++ if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) // Default port ++ { ++ #if 0 ++ //todo: AP Mode ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE)) ++ { ++ UndecoratedSmoothedPWDB = pdmpriv->EntryMinUndecoratedSmoothedPWDB; ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("AP Client PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); ++ } ++ else ++ { ++ UndecoratedSmoothedPWDB = pdmpriv->UndecoratedSmoothedPWDB; ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("STA Default Port PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); ++ } ++ #else ++ UndecoratedSmoothedPWDB = pdmpriv->EntryMinUndecoratedSmoothedPWDB; ++ #endif ++ } ++ else // associated entry pwdb ++ { ++ UndecoratedSmoothedPWDB = pdmpriv->EntryMinUndecoratedSmoothedPWDB; ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("AP Ext Port PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); ++ } ++#if TX_POWER_FOR_5G_BAND == 1 ++ if(pHalData->CurrentBandType92D == BAND_ON_5G){ ++ if(UndecoratedSmoothedPWDB >= 0x33) ++ { ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Level2; ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("5G:TxHighPwrLevel_Level2 (TxPwr=0x0)\n")); ++ } ++ else if((UndecoratedSmoothedPWDB <0x33) && ++ (UndecoratedSmoothedPWDB >= 0x2b) ) ++ { ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Level1; ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("5G:TxHighPwrLevel_Level1 (TxPwr=0x10)\n")); ++ } ++ else if(UndecoratedSmoothedPWDB < 0x2b) ++ { ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("5G:TxHighPwrLevel_Normal\n")); ++ } ++ } ++ else ++#endif ++ { ++ if(UndecoratedSmoothedPWDB >= TX_POWER_NEAR_FIELD_THRESH_LVL2) ++ { ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Level2; ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Level1 (TxPwr=0x0)\n")); ++ } ++ else if((UndecoratedSmoothedPWDB < (TX_POWER_NEAR_FIELD_THRESH_LVL2-3)) && ++ (UndecoratedSmoothedPWDB >= TX_POWER_NEAR_FIELD_THRESH_LVL1) ) ++ { ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Level1; ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Level1 (TxPwr=0x10)\n")); ++ } ++ else if(UndecoratedSmoothedPWDB < (TX_POWER_NEAR_FIELD_THRESH_LVL1-5)) ++ { ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Normal\n")); ++ } ++ } ++#if (RTL8192D_EASY_SMART_CONCURRENT == 1) ++ if(bGetValueFromBuddyAdapter) ++ { ++ //ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() mac 0 for mac 1 \n")); ++ if(Adapter->DualMacDMSPControl.bChangeTxHighPowerLvlForAnotherMacOfDMSP) ++ { ++ //ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() change value \n")); ++ HighPowerLvlBackForMac0 = pHalData->DynamicTxHighPowerLvl; ++ pHalData->DynamicTxHighPowerLvl = Adapter->DualMacDMSPControl.CurTxHighLvlForAnotherMacOfDMSP; ++ PHY_SetTxPowerLevel8192D(Adapter, pHalData->CurrentChannel); ++ pHalData->DynamicTxHighPowerLvl = HighPowerLvlBackForMac0; ++ Adapter->DualMacDMSPControl.bChangeTxHighPowerLvlForAnotherMacOfDMSP = _FALSE; ++ } ++ } ++#endif ++ ++ if( (pdmpriv->DynamicTxHighPowerLvl != pdmpriv->LastDTPLvl) ) ++ { ++ //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("PHY_SetTxPowerLevel8192S() Channel = %d \n" , pHalData->CurrentChannel)); ++#if (RTL8192D_EASY_SMART_CONCURRENT == 1) ++ if(BuddyAdapter == NULL) ++ { ++ //ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() BuddyAdapter == NULL case \n")); ++ if(!Adapter->bSlaveOfDMSP) ++ { ++ PHY_SetTxPowerLevel8192D(Adapter, pHalData->CurrentChannel); ++ } ++ } ++ else ++ { ++ if(pHalData->MacPhyMode92D == DUALMAC_SINGLEPHY) ++ { ++ //ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() BuddyAdapter DMSP \n")); ++ if(Adapter->bSlaveOfDMSP) ++ { ++ //ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() bslave case \n")); ++ BuddyAdapter->DualMacDMSPControl.bChangeTxHighPowerLvlForAnotherMacOfDMSP = _TRUE; ++ BuddyAdapter->DualMacDMSPControl.CurTxHighLvlForAnotherMacOfDMSP = pHalData->DynamicTxHighPowerLvl; ++ } ++ else ++ { ++ //ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() master case \n")); ++ if(!bGetValueFromBuddyAdapter) ++ { ++ //ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() mac 0 for mac 0 \n")); ++ PHY_SetTxPowerLevel8192D(Adapter, pHalData->CurrentChannel); ++ } ++ } ++ } ++ else ++ { ++ //ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() BuddyAdapter DMDP\n")); ++ PHY_SetTxPowerLevel8192D(Adapter, pHalData->CurrentChannel); ++ } ++ } ++#else ++ PHY_SetTxPowerLevel8192D(Adapter, pHalData->CurrentChannel); ++#endif ++ } ++ pdmpriv->LastDTPLvl = pdmpriv->DynamicTxHighPowerLvl; ++#endif ++#endif // #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ++} ++ ++ ++//3============================================================ ++//3 RSSI Monitor ++//3============================================================ ++ ++VOID ++odm_RSSIMonitorInit( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++} ++ ++VOID ++odm_RSSIMonitorCheck( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ // ++ // For AP/ADSL use prtl8192cd_priv ++ // For CE/NIC use PADAPTER ++ // ++ PADAPTER pAdapter = pDM_Odm->Adapter; ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_RSSI_MONITOR)) ++ return; ++ ++ // ++ // 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate ++ // at the same time. In the stage2/3, we need to prive universal interface and merge all ++ // HW dynamic mechanism. ++ // ++ switch (pDM_Odm->SupportPlatform) ++ { ++ case ODM_MP: ++ odm_RSSIMonitorCheckMP(pDM_Odm); ++ break; ++ ++ case ODM_CE: ++ odm_RSSIMonitorCheckCE(pDM_Odm); ++ break; ++ ++ case ODM_AP: ++ odm_RSSIMonitorCheckAP(pDM_Odm); ++ break; ++ ++ case ODM_ADSL: ++ //odm_DIGAP(pDM_Odm); ++ break; ++ } ++ ++} // odm_RSSIMonitorCheck ++ ++ ++VOID ++odm_RSSIMonitorCheckMP( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PRT_WLAN_STA pEntry; ++ u1Byte i; ++ s4Byte tmpEntryMaxPWDB=0, tmpEntryMinPWDB=0xff; ++ ++ RTPRINT(FDM, DM_PWDB, ("pHalData->UndecoratedSmoothedPWDB = 0x%x( %d)\n", ++ pHalData->UndecoratedSmoothedPWDB, ++ pHalData->UndecoratedSmoothedPWDB)); ++ ++ for(i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) ++ { ++ if(IsAPModeExist(Adapter) && GetFirstExtAdapter(Adapter) != NULL) ++ { ++ pEntry = AsocEntry_EnumStation(GetFirstExtAdapter(Adapter), i); ++ } ++ else ++ { ++ pEntry = AsocEntry_EnumStation(GetDefaultAdapter(Adapter), i); ++ } ++ ++ if(pEntry!=NULL) ++ { ++ if(pEntry->bAssociated) ++ { ++ RTPRINT_ADDR(FDM, DM_PWDB, ("pEntry->MacAddr ="), pEntry->MacAddr); ++ RTPRINT(FDM, DM_PWDB, ("pEntry->rssi = 0x%x(%d)\n", ++ pEntry->rssi_stat.UndecoratedSmoothedPWDB, ++ pEntry->rssi_stat.UndecoratedSmoothedPWDB)); ++ if(pEntry->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB) ++ tmpEntryMinPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB; ++ if(pEntry->rssi_stat.UndecoratedSmoothedPWDB > tmpEntryMaxPWDB) ++ tmpEntryMaxPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB; ++ } ++ } ++ else ++ { ++ break; ++ } ++ } ++ ++ if(tmpEntryMaxPWDB != 0) // If associated entry is found ++ { ++ pHalData->EntryMaxUndecoratedSmoothedPWDB = tmpEntryMaxPWDB; ++ RTPRINT(FDM, DM_PWDB, ("EntryMaxPWDB = 0x%x(%d)\n", ++ tmpEntryMaxPWDB, tmpEntryMaxPWDB)); ++ } ++ else ++ { ++ pHalData->EntryMaxUndecoratedSmoothedPWDB = 0; ++ } ++ if(tmpEntryMinPWDB != 0xff) // If associated entry is found ++ { ++ pHalData->EntryMinUndecoratedSmoothedPWDB = tmpEntryMinPWDB; ++ RTPRINT(FDM, DM_PWDB, ("EntryMinPWDB = 0x%x(%d)\n", ++ tmpEntryMinPWDB, tmpEntryMinPWDB)); ++ } ++ else ++ { ++ pHalData->EntryMinUndecoratedSmoothedPWDB = 0; ++ } ++ ++ // Indicate Rx signal strength to FW. ++ if(Adapter->MgntInfo.bUseRAMask) ++ { ++ u1Byte H2C_Parameter[3] ={0}; ++ // DbgPrint("RxSS: %lx =%ld\n", pHalData->UndecoratedSmoothedPWDB, pHalData->UndecoratedSmoothedPWDB); ++ H2C_Parameter[2] = (u1Byte)(pHalData->UndecoratedSmoothedPWDB & 0xFF); ++ H2C_Parameter[1] = 0x20; // fw v12 cmdid 5:use max macid ,for nic ,default macid is 0 ,max macid is 1 ++ ++ ODM_FillH2CCmd(Adapter, ODM_H2C_RSSI_REPORT, 3, H2C_Parameter); ++ } ++ else ++ { ++ PlatformEFIOWrite1Byte(Adapter, 0x4fe, (u1Byte)pHalData->UndecoratedSmoothedPWDB); ++ //DbgPrint("0x4fe write %x %d\n", pHalData->UndecoratedSmoothedPWDB, pHalData->UndecoratedSmoothedPWDB); ++ } ++#endif // #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++} ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++// ++//sherry move from DUSC to here 20110517 ++// ++static VOID ++FindMinimumRSSI_Dmsp( ++ IN PADAPTER pAdapter ++) ++{ ++#if 0 ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ s32 Rssi_val_min_back_for_mac0; ++ BOOLEAN bGetValueFromBuddyAdapter = dm_DualMacGetParameterFromBuddyAdapter(pAdapter); ++ BOOLEAN bRestoreRssi = _FALSE; ++ PADAPTER BuddyAdapter = pAdapter->BuddyAdapter; ++ ++ if(pHalData->MacPhyMode92D == DUALMAC_SINGLEPHY) ++ { ++ if(BuddyAdapter!= NULL) ++ { ++ if(pHalData->bSlaveOfDMSP) ++ { ++ //ODM_RT_TRACE(pDM_Odm,COMP_EASY_CONCURRENT,DBG_LOUD,("bSlavecase of dmsp\n")); ++ BuddyAdapter->DualMacDMSPControl.RssiValMinForAnotherMacOfDMSP = pdmpriv->MinUndecoratedPWDBForDM; ++ } ++ else ++ { ++ if(bGetValueFromBuddyAdapter) ++ { ++ //ODM_RT_TRACE(pDM_Odm,COMP_EASY_CONCURRENT,DBG_LOUD,("get new RSSI\n")); ++ bRestoreRssi = _TRUE; ++ Rssi_val_min_back_for_mac0 = pdmpriv->MinUndecoratedPWDBForDM; ++ pdmpriv->MinUndecoratedPWDBForDM = pAdapter->DualMacDMSPControl.RssiValMinForAnotherMacOfDMSP; ++ } ++ } ++ } ++ ++ } ++ ++ if(bRestoreRssi) ++ { ++ bRestoreRssi = _FALSE; ++ pdmpriv->MinUndecoratedPWDBForDM = Rssi_val_min_back_for_mac0; ++ } ++#endif ++} ++ ++static void ++FindMinimumRSSI( ++IN PADAPTER pAdapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ ++ //1 1.Determine the minimum RSSI ++ ++ if((pDM_Odm->bLinked != _TRUE) && ++ (pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0)) ++ { ++ pdmpriv->MinUndecoratedPWDBForDM = 0; ++ //ODM_RT_TRACE(pDM_Odm,COMP_BB_POWERSAVING, DBG_LOUD, ("Not connected to any \n")); ++ } ++ else ++ { ++ pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB; ++ } ++ ++ //DBG_8192C("%s=>MinUndecoratedPWDBForDM(%d)\n",__FUNCTION__,pdmpriv->MinUndecoratedPWDBForDM); ++ //ODM_RT_TRACE(pDM_Odm,COMP_DIG, DBG_LOUD, ("MinUndecoratedPWDBForDM =%d\n",pHalData->MinUndecoratedPWDBForDM)); ++} ++#endif ++ ++VOID ++odm_RSSIMonitorCheckCE( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ int i; ++ int tmpEntryMaxPWDB=0, tmpEntryMinPWDB=0xff; ++ u8 sta_cnt=0; ++ u32 PWDB_rssi[NUM_STA]={0};//[0~15]:MACID, [16~31]:PWDB_rssi ++ ++ if(pDM_Odm->bLinked != _TRUE) ++ return; ++ ++ //if(check_fwstate(&Adapter->mlmepriv, WIFI_AP_STATE|WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) == _TRUE) ++ { ++ #if 1 ++ struct sta_info *psta; ++ ++ for(i=0; ipODM_StaInfo[i])) ++ { ++ if(IS_MCAST( psta->hwaddr)) //if(psta->mac_id ==1) ++ continue; ++ ++ if(psta->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB) ++ tmpEntryMinPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; ++ ++ if(psta->rssi_stat.UndecoratedSmoothedPWDB > tmpEntryMaxPWDB) ++ tmpEntryMaxPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; ++ ++ #if 0 ++ DBG_871X("%s mac_id:%u, mac:"MAC_FMT", rssi:%d\n", __func__, ++ psta->mac_id, MAC_ARG(psta->hwaddr), psta->rssi_stat.UndecoratedSmoothedPWDB); ++ #endif ++ ++ if(psta->rssi_stat.UndecoratedSmoothedPWDB != (-1)) { ++ #if(RTL8192D_SUPPORT==1) ++ PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16) | ((Adapter->stapriv.asoc_sta_count+1) << 8)); ++ #else ++ PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16) ); ++ #endif ++ } ++ } ++ } ++ #else ++ _irqL irqL; ++ _list *plist, *phead; ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &Adapter->stapriv; ++ u8 bcast_addr[ETH_ALEN]= {0xff,0xff,0xff,0xff,0xff,0xff}; ++ ++ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ ++ for(i=0; i< NUM_STA; i++) ++ { ++ phead = &(pstapriv->sta_hash[i]); ++ plist = get_next(phead); ++ ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); ++ ++ plist = get_next(plist); ++ ++ if(_rtw_memcmp(psta->hwaddr, bcast_addr, ETH_ALEN) || ++ _rtw_memcmp(psta->hwaddr, myid(&Adapter->eeprompriv), ETH_ALEN)) ++ continue; ++ ++ if(psta->state & WIFI_ASOC_STATE) ++ { ++ ++ if(psta->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB) ++ tmpEntryMinPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; ++ ++ if(psta->rssi_stat.UndecoratedSmoothedPWDB > tmpEntryMaxPWDB) ++ tmpEntryMaxPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; ++ ++ if(psta->rssi_stat.UndecoratedSmoothedPWDB != (-1)){ ++ //printk("%s==> mac_id(%d),rssi(%d)\n",__FUNCTION__,psta->mac_id,psta->rssi_stat.UndecoratedSmoothedPWDB); ++ #if(RTL8192D_SUPPORT==1) ++ PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16) | ((Adapter->stapriv.asoc_sta_count+1) << 8)); ++ #else ++ PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16) ); ++ #endif ++ } ++ } ++ ++ } ++ ++ } ++ ++ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ #endif ++ ++ //printk("%s==> sta_cnt(%d)\n",__FUNCTION__,sta_cnt); ++ ++ for(i=0; i< sta_cnt; i++) ++ { ++ if(PWDB_rssi[i] != (0)){ ++ if(pHalData->fw_ractrl == _TRUE)// Report every sta's RSSI to FW ++ { ++ #if(RTL8192D_SUPPORT==1) ++ FillH2CCmd92D(Adapter, H2C_RSSI_REPORT, 3, (u8 *)(&PWDB_rssi[i])); ++ #elif((RTL8192C_SUPPORT==1)||(RTL8723A_SUPPORT==1)) ++ rtl8192c_set_rssi_cmd(Adapter, (u8*)&PWDB_rssi[i]); ++ #endif ++ } ++ else{ ++ #if((RTL8188E_SUPPORT==1)&&(RATE_ADAPTIVE_SUPPORT == 1)) ++ ODM_RA_SetRSSI_8188E( ++ &(pHalData->odmpriv), (PWDB_rssi[i]&0xFF), (u8)((PWDB_rssi[i]>>16) & 0xFF)); ++ #endif ++ } ++ } ++ } ++ } ++ ++ if(tmpEntryMaxPWDB != 0) // If associated entry is found ++ { ++ pdmpriv->EntryMaxUndecoratedSmoothedPWDB = tmpEntryMaxPWDB; ++ } ++ else ++ { ++ pdmpriv->EntryMaxUndecoratedSmoothedPWDB = 0; ++ } ++ ++ if(tmpEntryMinPWDB != 0xff) // If associated entry is found ++ { ++ pdmpriv->EntryMinUndecoratedSmoothedPWDB = tmpEntryMinPWDB; ++ } ++ else ++ { ++ pdmpriv->EntryMinUndecoratedSmoothedPWDB = 0; ++ } ++ ++ FindMinimumRSSI(Adapter);//get pdmpriv->MinUndecoratedPWDBForDM ++ ++ #if(RTL8192D_SUPPORT==1) ++ FindMinimumRSSI_Dmsp(Adapter); ++ #endif ++ pDM_Odm->RSSI_Min = pdmpriv->MinUndecoratedPWDBForDM; ++ //ODM_CmnInfoUpdate(&pHalData->odmpriv ,ODM_CMNINFO_RSSI_MIN, pdmpriv->MinUndecoratedPWDBForDM); ++#endif//if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++} ++VOID ++odm_RSSIMonitorCheckAP( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++#ifdef CONFIG_RTL_92C_SUPPORT || defined(CONFIG_RTL_92D_SUPPORT) ++ ++ u4Byte i; ++ PSTA_INFO_T pstat; ++ ++ for(i=0; ipODM_StaInfo[i]; ++ if(IS_STA_VALID(pstat) ) ++ { ++#ifdef STA_EXT ++ if (REMAP_AID(pstat) < (FW_NUM_STAT - 1)) ++#endif ++ add_update_rssi(pDM_Odm->priv, pstat); ++ ++ } ++ } ++#endif ++#endif ++ ++} ++ ++ ++ ++VOID ++ODM_InitAllTimers( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ ODM_InitializeTimer(pDM_Odm,&pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer, ++ (RT_TIMER_CALL_BACK)odm_SwAntDivChkAntSwitchCallback, NULL, "SwAntennaSwitchTimer"); ++ ++#if (!(DM_ODM_SUPPORT_TYPE == ODM_CE)) ++#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) ++#if (RTL8188E_SUPPORT == 1) ++ ODM_InitializeTimer(pDM_Odm,&pDM_Odm->FastAntTrainingTimer, ++ (RT_TIMER_CALL_BACK)odm_FastAntTrainingCallback, NULL, "FastAntTrainingTimer"); ++#endif ++#endif ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ODM_InitializeTimer(pDM_Odm, &pDM_Odm->PSDTimer, ++ (RT_TIMER_CALL_BACK)dm_PSDMonitorCallback, NULL, "PSDTimer"); ++ // ++ //Path Diversity ++ //Neil Chen--2011--06--16-- / 2012/02/23 MH Revise Arch. ++ // ++ ODM_InitializeTimer(pDM_Odm, &pDM_Odm->PathDivSwitchTimer, ++ (RT_TIMER_CALL_BACK)odm_PathDivChkAntSwitchCallback, NULL, "PathDivTimer"); ++ ++ ODM_InitializeTimer(pDM_Odm, &pDM_Odm->CCKPathDiversityTimer, ++ (RT_TIMER_CALL_BACK)odm_CCKTXPathDiversityCallback, NULL, "CCKPathDiversityTimer"); ++ ++ ODM_InitializeTimer(pDM_Odm, &pDM_Odm->DM_RXHP_Table.PSDTimer, ++ (RT_TIMER_CALL_BACK)odm_PSD_RXHPCallback, NULL, "PSDRXHPTimer"); ++#endif ++} ++ ++VOID ++ODM_CancelAllTimers( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ // ++ // 2012/01/12 MH Temp BSOD fix. We need to find NIC allocate mem fail reason in ++ // win7 platform. ++ // ++ HAL_ADAPTER_STS_CHK(pDM_Odm) ++#endif ++ ++ ODM_CancelTimer(pDM_Odm,&pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer); ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ++#if (RTL8188E_SUPPORT == 1) ++ ODM_CancelTimer(pDM_Odm,&pDM_Odm->FastAntTrainingTimer); ++#endif ++ ODM_CancelTimer(pDM_Odm, &pDM_Odm->PSDTimer); ++ // ++ //Path Diversity ++ //Neil Chen--2011--06--16-- / 2012/02/23 MH Revise Arch. ++ // ++ ODM_CancelTimer(pDM_Odm, &pDM_Odm->PathDivSwitchTimer); ++ ++ ODM_CancelTimer(pDM_Odm, &pDM_Odm->CCKPathDiversityTimer); ++ ++ ODM_CancelTimer(pDM_Odm, &pDM_Odm->DM_RXHP_Table.PSDTimer); ++#endif ++} ++ ++ ++VOID ++ODM_ReleaseAllTimers( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ ODM_ReleaseTimer(pDM_Odm,&pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer); ++ ++#if (RTL8188E_SUPPORT == 1) ++ ODM_ReleaseTimer(pDM_Odm,&pDM_Odm->FastAntTrainingTimer); ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ++ ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->PSDTimer); ++ // ++ //Path Diversity ++ //Neil Chen--2011--06--16-- / 2012/02/23 MH Revise Arch. ++ // ++ ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->PathDivSwitchTimer); ++ ++ ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->CCKPathDiversityTimer); ++ ++ ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->DM_RXHP_Table.PSDTimer); ++#endif ++} ++ ++ ++ ++//#endif ++//3============================================================ ++//3 Tx Power Tracking ++//3============================================================ ++ ++VOID ++odm_TXPowerTrackingInit( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ odm_TXPowerTrackingThermalMeterInit(pDM_Odm); ++} ++ ++ ++VOID ++odm_TXPowerTrackingThermalMeterInit( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ pMgntInfo->bTXPowerTracking = TRUE; ++ pHalData->TXPowercount = 0; ++ pHalData->bTXPowerTrackingInit = FALSE; ++ #if MP_DRIVER != 1 //for mp driver, turn off txpwrtracking as default ++ pHalData->TxPowerTrackControl = TRUE; ++ #endif//#if (MP_DRIVER != 1) ++ ODM_RT_TRACE(pDM_Odm,COMP_POWER_TRACKING, DBG_LOUD, ("pMgntInfo->bTXPowerTracking = %d\n", pMgntInfo->bTXPowerTracking)); ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #ifdef CONFIG_RTL8188E ++ { ++ pDM_Odm->RFCalibrateInfo.bTXPowerTracking = _TRUE; ++ pDM_Odm->RFCalibrateInfo.TXPowercount = 0; ++ pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = _FALSE; ++ //#if (MP_DRIVER != 1) //for mp driver, turn off txpwrtracking as default ++ if ( *(pDM_Odm->mp_mode) != 1) ++ pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = _TRUE; ++ //#endif//#if (MP_DRIVER != 1) ++ MSG_8192C("pDM_Odm TxPowerTrackControl = %d\n", pDM_Odm->RFCalibrateInfo.TxPowerTrackControl); ++ } ++ #else ++ { ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ ++ //if(IS_HARDWARE_TYPE_8192C(pHalData)) ++ { ++ pdmpriv->bTXPowerTracking = _TRUE; ++ pdmpriv->TXPowercount = 0; ++ pdmpriv->bTXPowerTrackingInit = _FALSE; ++ //#if (MP_DRIVER != 1) //for mp driver, turn off txpwrtracking as default ++ ++ if (*(pDM_Odm->mp_mode) != 1) ++ pdmpriv->TxPowerTrackControl = _TRUE; ++ //#endif//#if (MP_DRIVER != 1) ++ } ++ MSG_8192C("pdmpriv->TxPowerTrackControl = %d\n", pdmpriv->TxPowerTrackControl); ++ ++ } ++ #endif//endif (CONFIG_RTL8188E==1) ++#elif (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ #ifdef RTL8188E_SUPPORT ++ { ++ pDM_Odm->RFCalibrateInfo.bTXPowerTracking = _TRUE; ++ pDM_Odm->RFCalibrateInfo.TXPowercount = 0; ++ pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = _FALSE; ++ pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = _TRUE; ++ } ++ #endif ++#endif ++ ++ pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = TRUE; ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndex = 0; ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast = 0; ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset = 0; ++ pDM_Odm->RFCalibrateInfo.ThermalValue = 0; ++ pDM_Odm->DefaultOfdmIndex = 12; ++ pDM_Odm->DefaultCckIndex = 12; ++ pDM_Odm->BbSwingIdxOfdmBase = pDM_Odm->DefaultOfdmIndex; ++ pDM_Odm->BbSwingIdxCckBase = pDM_Odm->DefaultCckIndex; ++ pDM_Odm->BbSwingIdxOfdm = pDM_Odm->DefaultOfdmIndex; ++ pDM_Odm->BbSwingIdxCck = pDM_Odm->DefaultCckIndex; ++ ++ pDM_Odm->RFCalibrateInfo.CCK_index = pDM_Odm->DefaultCckIndex; ++ pDM_Odm->RFCalibrateInfo.OFDM_index[RF_PATH_A] = pDM_Odm->DefaultOfdmIndex; ++ pDM_Odm->RFCalibrateInfo.OFDM_index[RF_PATH_B] = pDM_Odm->DefaultOfdmIndex; ++ ++} ++ ++ ++VOID ++ODM_TXPowerTrackingCheck( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ // ++ // For AP/ADSL use prtl8192cd_priv ++ // For CE/NIC use PADAPTER ++ // ++ PADAPTER pAdapter = pDM_Odm->Adapter; ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ ++ //if (!(pDM_Odm->SupportAbility & ODM_RF_TX_PWR_TRACK)) ++ //return; ++ ++ // ++ // 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate ++ // at the same time. In the stage2/3, we need to prive universal interface and merge all ++ // HW dynamic mechanism. ++ // ++ switch (pDM_Odm->SupportPlatform) ++ { ++ case ODM_MP: ++ odm_TXPowerTrackingCheckMP(pDM_Odm); ++ break; ++ ++ case ODM_CE: ++ odm_TXPowerTrackingCheckCE(pDM_Odm); ++ break; ++ ++ case ODM_AP: ++ odm_TXPowerTrackingCheckAP(pDM_Odm); ++ break; ++ ++ case ODM_ADSL: ++ //odm_DIGAP(pDM_Odm); ++ break; ++ } ++ ++} ++ ++VOID ++odm_TXPowerTrackingCheckCE( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ #if( (RTL8192C_SUPPORT==1) || (RTL8723A_SUPPORT==1) ) ++ rtl8192c_odm_CheckTXPowerTracking(Adapter); ++ #endif ++ ++ #if (RTL8192D_SUPPORT==1) ++ #if (RTL8192D_EASY_SMART_CONCURRENT == 1) ++ if(!Adapter->bSlaveOfDMSP) ++ #endif ++ rtl8192d_odm_CheckTXPowerTracking(Adapter); ++ #endif ++ #if(RTL8188E_SUPPORT==1) ++ ++ //if(!pMgntInfo->bTXPowerTracking /*|| (!pdmpriv->TxPowerTrackControl && pdmpriv->bAPKdone)*/) ++ if(!(pDM_Odm->SupportAbility & ODM_RF_TX_PWR_TRACK)) ++ { ++ return; ++ } ++ ++ if(!pDM_Odm->RFCalibrateInfo.TM_Trigger) //at least delay 1 sec ++ { ++ //pHalData->TxPowerCheckCnt++; //cosa add for debug ++ //ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_T_METER, bRFRegOffsetMask, 0x60); ++ PHY_SetRFReg(Adapter, RF_PATH_A, RF_T_METER_88E, BIT17 | BIT16, 0x03); ++ //DBG_8192C("Trigger 92C Thermal Meter!!\n"); ++ ++ pDM_Odm->RFCalibrateInfo.TM_Trigger = 1; ++ return; ++ ++ } ++ else ++ { ++ //DBG_8192C("Schedule TxPowerTracking direct call!!\n"); ++ odm_TXPowerTrackingCallback_ThermalMeter_8188E(Adapter); ++ pDM_Odm->RFCalibrateInfo.TM_Trigger = 0; ++ } ++ #endif ++ ++#endif ++} ++ ++VOID ++odm_TXPowerTrackingCheckMP( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ ++ if (ODM_CheckPowerStatus(Adapter) == FALSE) ++ return; ++ ++ if(IS_HARDWARE_TYPE_8723A(Adapter)) ++ return; ++ ++ if(!Adapter->bSlaveOfDMSP || Adapter->DualMacSmartConcurrent == FALSE) ++ odm_TXPowerTrackingThermalMeterCheck(Adapter); ++#endif ++ ++} ++ ++ ++VOID ++odm_TXPowerTrackingCheckAP( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ ++ if ( (priv->pmib->dot11RFEntry.ther) && ((priv->up_time % priv->pshare->rf_ft_var.tpt_period) == 0)){ ++#ifdef CONFIG_RTL_92D_SUPPORT ++ if (GET_CHIP_VER(priv)==VERSION_8192D){ ++ tx_power_tracking_92D(priv); ++ } else ++#endif ++ { ++#ifdef CONFIG_RTL_92C_SUPPORT ++ tx_power_tracking(priv); ++#endif ++ } ++ } ++#endif ++ ++} ++ ++ ++ ++//antenna mapping info ++// 1: right-side antenna ++// 2/0: left-side antenna ++//PDM_SWAT_Table->CCK_Ant1_Cnt /OFDM_Ant1_Cnt: for right-side antenna: Ant:1 RxDefaultAnt1 ++//PDM_SWAT_Table->CCK_Ant2_Cnt /OFDM_Ant2_Cnt: for left-side antenna: Ant:0 RxDefaultAnt2 ++// We select left antenna as default antenna in initial process, modify it as needed ++// ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ++VOID ++odm_TXPowerTrackingThermalMeterCheck( ++ IN PADAPTER Adapter ++ ) ++{ ++#ifndef AP_BUILD_WORKAROUND ++#if (HAL_CODE_BASE==RTL8192_C) ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ static u1Byte TM_Trigger = 0; ++ //u1Byte TxPowerCheckCnt = 5; //10 sec ++ ++ if(!pMgntInfo->bTXPowerTracking /*|| (!pHalData->TxPowerTrackControl && pHalData->bAPKdone)*/) ++ { ++ return; ++ } ++ ++ if(!TM_Trigger) //at least delay 1 sec ++ { ++ if(IS_HARDWARE_TYPE_8192D(Adapter)) ++ PHY_SetRFReg(Adapter, RF_PATH_A, RF_T_METER_92D, BIT17 | BIT16, 0x03); ++ else if(IS_HARDWARE_TYPE_8188E(Adapter)) ++ PHY_SetRFReg(Adapter, RF_PATH_A, RF_T_METER_88E, BIT17 | BIT16, 0x03); ++ else ++ PHY_SetRFReg(Adapter, RF_PATH_A, RF_T_METER, bRFRegOffsetMask, 0x60); ++ RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD,("Trigger 92C Thermal Meter!!\n")); ++ ++ TM_Trigger = 1; ++ return; ++ } ++ else ++ { ++ RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD,("Schedule TxPowerTracking direct call!!\n")); ++ odm_TXPowerTrackingDirectCall(Adapter); //Using direct call is instead, added by Roger, 2009.06.18. ++ TM_Trigger = 0; ++ } ++#endif ++#endif ++} ++ ++#endif ++ ++ ++ ++//3============================================================ ++//3 SW Antenna Diversity ++//3============================================================ ++#if(defined(CONFIG_SW_ANTENNA_DIVERSITY)) ++VOID ++odm_SwAntDivInit( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE)) ++ odm_SwAntDivInit_NIC(pDM_Odm); ++#elif(DM_ODM_SUPPORT_TYPE == ODM_AP) ++ dm_SW_AntennaSwitchInit(pDM_Odm->priv); ++#endif ++} ++#if (RTL8723A_SUPPORT==1) ++// Only for 8723A SW ANT DIV INIT--2012--07--17 ++VOID ++odm_SwAntDivInit_NIC_8723A( ++ IN PDM_ODM_T pDM_Odm) ++{ ++ pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ u1Byte btAntNum=BT_GetPGAntNum(Adapter); ++ ++ ++ if(IS_HARDWARE_TYPE_8723A(Adapter)) ++ { ++ pDM_SWAT_Table->ANTA_ON =TRUE; ++ ++ // Set default antenna B status by PG ++ if(btAntNum == Ant_x2) ++ pDM_SWAT_Table->ANTB_ON = TRUE; ++ else if(btAntNum ==Ant_x1) ++ pDM_SWAT_Table->ANTB_ON = FALSE; ++ else ++ pDM_SWAT_Table->ANTB_ON = TRUE; ++ } ++ ++} ++#endif ++VOID ++odm_SwAntDivInit_NIC( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++// Init SW ANT DIV mechanism for 8723AE/AU/AS// Neil Chen--2012--07--17--- ++// CE/AP/ADSL no using SW ANT DIV for 8723A Series IC ++//#if (DM_ODM_SUPPORT_TYPE==ODM_MP) ++#if (RTL8723A_SUPPORT==1) ++ if(pDM_Odm->SupportICType == ODM_RTL8723A) ++ { ++ odm_SwAntDivInit_NIC_8723A(pDM_Odm); ++ } ++#endif ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS:Init SW Antenna Switch\n")); ++ pDM_SWAT_Table->RSSI_sum_A = 0; ++ pDM_SWAT_Table->RSSI_cnt_A = 0; ++ pDM_SWAT_Table->RSSI_sum_B = 0; ++ pDM_SWAT_Table->RSSI_cnt_B = 0; ++ pDM_SWAT_Table->CurAntenna = Antenna_A; ++ pDM_SWAT_Table->PreAntenna = Antenna_A; ++ pDM_SWAT_Table->try_flag = 0xff; ++ pDM_SWAT_Table->PreRSSI = 0; ++ pDM_SWAT_Table->SWAS_NoLink_State = 0; ++ pDM_SWAT_Table->bTriggerAntennaSwitch = 0; ++ pDM_SWAT_Table->SelectAntennaMap=0xAA; ++ pDM_SWAT_Table->lastTxOkCnt = 0; ++ pDM_SWAT_Table->lastRxOkCnt = 0; ++ pDM_SWAT_Table->TXByteCnt_A = 0; ++ pDM_SWAT_Table->TXByteCnt_B = 0; ++ pDM_SWAT_Table->RXByteCnt_A = 0; ++ pDM_SWAT_Table->RXByteCnt_B = 0; ++ pDM_SWAT_Table->TrafficLoad = TRAFFIC_LOW; ++ pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 = ODM_Read4Byte(pDM_Odm, 0x860); ++} ++ ++// ++// 20100514 Joseph: ++// Add new function to reset the state of antenna diversity before link. ++// ++VOID ++ODM_SwAntDivResetBeforeLink( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ ++ pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ ++ pDM_SWAT_Table->SWAS_NoLink_State = 0; ++ ++} ++ ++// ++// 20100514 Luke/Joseph: ++// Add new function to reset antenna diversity state after link. ++// ++VOID ++ODM_SwAntDivRestAfterLink( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ ++ pDM_SWAT_Table->RSSI_cnt_A = 0; ++ pDM_SWAT_Table->RSSI_cnt_B = 0; ++ pDM_Odm->RSSI_test = FALSE; ++ pDM_SWAT_Table->try_flag = 0xff; ++ pDM_SWAT_Table->RSSI_Trying = 0; ++ pDM_SWAT_Table->SelectAntennaMap=0xAA; ++} ++ ++VOID ++ODM_SwAntDivChkPerPktRssi( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte StationID, ++ IN PODM_PHY_INFO_T pPhyInfo ++ ) ++{ ++ SWAT_T *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ ++ if(!(pDM_Odm->SupportAbility & (ODM_BB_ANT_DIV))) ++ return; ++ ++ if(StationID == pDM_SWAT_Table->RSSI_target) ++ { ++ //1 RSSI for SW Antenna Switch ++ if(pDM_SWAT_Table->CurAntenna == Antenna_A) ++ { ++ pDM_SWAT_Table->RSSI_sum_A += pPhyInfo->RxPWDBAll; ++ pDM_SWAT_Table->RSSI_cnt_A++; ++ } ++ else ++ { ++ pDM_SWAT_Table->RSSI_sum_B += pPhyInfo->RxPWDBAll; ++ pDM_SWAT_Table->RSSI_cnt_B++; ++ ++ } ++ } ++ ++} ++ ++// ++VOID ++odm_SwAntDivChkAntSwitch( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte Step ++ ) ++{ ++ // ++ // For AP/ADSL use prtl8192cd_priv ++ // For CE/NIC use PADAPTER ++ // ++ PADAPTER pAdapter = pDM_Odm->Adapter; ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ ++ // ++ // 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate ++ // at the same time. In the stage2/3, we need to prive universal interface and merge all ++ // HW dynamic mechanism. ++ // ++ switch (pDM_Odm->SupportPlatform) ++ { ++ case ODM_MP: ++ case ODM_CE: ++ odm_SwAntDivChkAntSwitchNIC(pDM_Odm, Step); ++ break; ++ ++ case ODM_AP: ++ case ODM_ADSL: ++#if (DM_ODM_SUPPORT_TYPE & (ODM_AP |ODM_ADSL)) ++ if (priv->pshare->rf_ft_var.antSw_enable && (priv->up_time % 4==1)) ++ dm_SW_AntennaSwitch(priv, SWAW_STEP_PEAK); ++#endif ++ break; ++ } ++ ++} ++ ++// ++// 20100514 Luke/Joseph: ++// Add new function for antenna diversity after link. ++// This is the main function of antenna diversity after link. ++// This function is called in HalDmWatchDog() and ODM_SwAntDivChkAntSwitchCallback(). ++// HalDmWatchDog() calls this function with SWAW_STEP_PEAK to initialize the antenna test. ++// In SWAW_STEP_PEAK, another antenna and a 500ms timer will be set for testing. ++// After 500ms, ODM_SwAntDivChkAntSwitchCallback() calls this function to compare the signal just ++// listened on the air with the RSSI of original antenna. ++// It chooses the antenna with better RSSI. ++// There is also a aged policy for error trying. Each error trying will cost more 5 seconds waiting ++// penalty to get next try. ++ ++ ++VOID ++ODM_SetAntenna( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte Antenna) ++{ ++ ODM_SetBBReg(pDM_Odm, 0x860, BIT8|BIT9, Antenna); ++} ++//--------------------------------2012--09--06-- ++//Note: Antenna_Main--> Antenna_A ++// Antenna_Aux---> Antenna_B ++//---------------------------------- ++VOID ++odm_SwAntDivChkAntSwitchNIC( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte Step ++ ) ++{ ++#if ((RTL8192C_SUPPORT==1)||(RTL8723A_SUPPORT==1)) ++ //PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ s4Byte curRSSI=100, RSSI_A, RSSI_B; ++ u1Byte nextAntenna=Antenna_B; ++ //static u8Byte lastTxOkCnt=0, lastRxOkCnt=0; ++ u8Byte curTxOkCnt, curRxOkCnt; ++ //static u8Byte TXByteCnt_A=0, TXByteCnt_B=0, RXByteCnt_A=0, RXByteCnt_B=0; ++ u8Byte CurByteCnt=0, PreByteCnt=0; ++ //static u1Byte TrafficLoad = TRAFFIC_LOW; ++ u1Byte Score_A=0, Score_B=0; ++ u1Byte i; ++ ++ if(!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) ++ return; ++ ++ if (pDM_Odm->SupportICType & (ODM_RTL8192D|ODM_RTL8188E)) ++ return; ++ ++ if((pDM_Odm->SupportICType == ODM_RTL8192C) &&(pDM_Odm->RFType == ODM_2T2R)) ++ return; ++ ++ if(pDM_Odm->SupportPlatform & ODM_MP) ++ { ++ if(*(pDM_Odm->pAntennaTest)) ++ return; ++ } ++ ++ if((pDM_SWAT_Table->ANTA_ON == FALSE) ||(pDM_SWAT_Table->ANTB_ON == FALSE)) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ++ ("odm_SwAntDivChkAntSwitch(): No AntDiv Mechanism, Antenna A or B is off\n")); ++ return; ++ } ++ ++ // Radio off: Status reset to default and return. ++ if(*(pDM_Odm->pbPowerSaving)==TRUE) //pHalData->eRFPowerState==eRfOff ++ { ++ ODM_SwAntDivRestAfterLink(pDM_Odm); ++ return; ++ } ++ ++ ++ // Handling step mismatch condition. ++ // Peak step is not finished at last time. Recover the variable and check again. ++ if( Step != pDM_SWAT_Table->try_flag ) ++ { ++ ODM_SwAntDivRestAfterLink(pDM_Odm); ++ } ++ ++#if (DM_ODM_SUPPORT_TYPE &( ODM_MP| ODM_CE )) ++ ++ if(pDM_SWAT_Table->try_flag == 0xff) ++ { ++ pDM_SWAT_Table->RSSI_target = 0xff; ++ ++ #if(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ { ++ u1Byte index = 0; ++ PSTA_INFO_T pEntry = NULL; ++ ++ ++ for(index=0; indexpODM_StaInfo[index]; ++ if(IS_STA_VALID(pEntry) ) { ++ break; ++ } ++ } ++ if(pEntry == NULL) ++ { ++ ODM_SwAntDivRestAfterLink(pDM_Odm); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_SwAntDivChkAntSwitch(): No Link.\n")); ++ return; ++ } ++ else ++ { ++ pDM_SWAT_Table->RSSI_target = index; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_SwAntDivChkAntSwitch(): RSSI_target is PEER STA\n")); ++ } ++ } ++ #elif (DM_ODM_SUPPORT_TYPE & ODM_MP) ++ { ++ PADAPTER pAdapter = pDM_Odm->Adapter; ++ PMGNT_INFO pMgntInfo=&pAdapter->MgntInfo; ++ ++ // Select RSSI checking target ++ if(pMgntInfo->mAssoc && !ACTING_AS_AP(pAdapter)) ++ { ++ // Target: Infrastructure mode AP. ++ //pDM_SWAT_Table->RSSI_target = NULL; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("odm_SwAntDivChkAntSwitch(): RSSI_target is DEF AP!\n")); ++ } ++ else ++ { ++ u1Byte index = 0; ++ PSTA_INFO_T pEntry = NULL; ++ PADAPTER pTargetAdapter = NULL; ++ ++ if(pMgntInfo->mIbss ) ++ { ++ // Target: AP/IBSS peer. ++ pTargetAdapter = pAdapter; ++ } ++ else ++ { ++ pTargetAdapter = GetFirstAPAdapter(pAdapter); ++ } ++ ++ if(pTargetAdapter != NULL) ++ { ++ for(index=0; indexbAssociated) ++ break; ++ } ++ ++ } ++ ++ } ++ ++ if(pEntry == NULL) ++ { ++ ODM_SwAntDivRestAfterLink(pDM_Odm); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_SwAntDivChkAntSwitch(): No Link.\n")); ++ return; ++ } ++ else ++ { ++ //pDM_SWAT_Table->RSSI_target = pEntry; ++ pDM_SWAT_Table->RSSI_target = index; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_SwAntDivChkAntSwitch(): RSSI_target is PEER STA\n")); ++ } ++ }//end if(pMgntInfo->mAssoc && !ACTING_AS_AP(Adapter)) ++ ++ } ++ #endif ++ ++ pDM_SWAT_Table->RSSI_cnt_A = 0; ++ pDM_SWAT_Table->RSSI_cnt_B = 0; ++ pDM_SWAT_Table->try_flag = 0; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("odm_SwAntDivChkAntSwitch(): Set try_flag to 0 prepare for peak!\n")); ++ return; ++ } ++ else ++ { ++#if (DM_ODM_SUPPORT_TYPE &( ODM_MP)) ++ //PADAPTER Adapter = pDM_Odm->Adapter; ++ curTxOkCnt = pAdapter->TxStats.NumTxBytesUnicast - pDM_SWAT_Table->lastTxOkCnt; ++ curRxOkCnt =pAdapter->RxStats.NumRxBytesUnicast - pDM_SWAT_Table->lastRxOkCnt; ++ pDM_SWAT_Table->lastTxOkCnt = pAdapter->TxStats.NumTxBytesUnicast; ++ pDM_SWAT_Table->lastRxOkCnt = pAdapter->RxStats.NumRxBytesUnicast; ++#else ++ curTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast) - pDM_SWAT_Table->lastTxOkCnt; ++ curRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast) - pDM_SWAT_Table->lastRxOkCnt; ++ pDM_SWAT_Table->lastTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast); ++ pDM_SWAT_Table->lastRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast); ++#endif ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("curTxOkCnt = %lld\n",curTxOkCnt)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("curRxOkCnt = %lld\n",curRxOkCnt)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("lastTxOkCnt = %lld\n",pDM_SWAT_Table->lastTxOkCnt)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("lastRxOkCnt = %lld\n",pDM_SWAT_Table->lastRxOkCnt)); ++ ++ if(pDM_SWAT_Table->try_flag == 1) ++ { ++ if(pDM_SWAT_Table->CurAntenna == Antenna_A) ++ { ++ pDM_SWAT_Table->TXByteCnt_A += curTxOkCnt; ++ pDM_SWAT_Table->RXByteCnt_A += curRxOkCnt; ++ } ++ else ++ { ++ pDM_SWAT_Table->TXByteCnt_B += curTxOkCnt; ++ pDM_SWAT_Table->RXByteCnt_B += curRxOkCnt; ++ } ++ ++ nextAntenna = (pDM_SWAT_Table->CurAntenna == Antenna_A)? Antenna_B : Antenna_A; ++ pDM_SWAT_Table->RSSI_Trying--; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("RSSI_Trying = %d\n",pDM_SWAT_Table->RSSI_Trying)); ++ if(pDM_SWAT_Table->RSSI_Trying == 0) ++ { ++ CurByteCnt = (pDM_SWAT_Table->CurAntenna == Antenna_A)? (pDM_SWAT_Table->TXByteCnt_A+pDM_SWAT_Table->RXByteCnt_A) : (pDM_SWAT_Table->TXByteCnt_B+pDM_SWAT_Table->RXByteCnt_B); ++ PreByteCnt = (pDM_SWAT_Table->CurAntenna == Antenna_A)? (pDM_SWAT_Table->TXByteCnt_B+pDM_SWAT_Table->RXByteCnt_B) : (pDM_SWAT_Table->TXByteCnt_A+pDM_SWAT_Table->RXByteCnt_A); ++ ++ if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_HIGH) ++ //CurByteCnt = PlatformDivision64(CurByteCnt, 9); ++ PreByteCnt = PreByteCnt*9; ++ else if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_LOW) ++ //CurByteCnt = PlatformDivision64(CurByteCnt, 2); ++ PreByteCnt = PreByteCnt*2; ++ ++ if(pDM_SWAT_Table->RSSI_cnt_A > 0) ++ RSSI_A = pDM_SWAT_Table->RSSI_sum_A/pDM_SWAT_Table->RSSI_cnt_A; ++ else ++ RSSI_A = 0; ++ if(pDM_SWAT_Table->RSSI_cnt_B > 0) ++ RSSI_B = pDM_SWAT_Table->RSSI_sum_B/pDM_SWAT_Table->RSSI_cnt_B; ++ else ++ RSSI_B = 0; ++ curRSSI = (pDM_SWAT_Table->CurAntenna == Antenna_A)? RSSI_A : RSSI_B; ++ pDM_SWAT_Table->PreRSSI = (pDM_SWAT_Table->CurAntenna == Antenna_A)? RSSI_B : RSSI_A; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Luke:PreRSSI = %d, CurRSSI = %d\n",pDM_SWAT_Table->PreRSSI, curRSSI)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: preAntenna= %s, curAntenna= %s \n", ++ (pDM_SWAT_Table->PreAntenna == Antenna_A?"A":"B"), (pDM_SWAT_Table->CurAntenna == Antenna_A?"A":"B"))); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Luke:RSSI_A= %d, RSSI_cnt_A = %d, RSSI_B= %d, RSSI_cnt_B = %d\n", ++ RSSI_A, pDM_SWAT_Table->RSSI_cnt_A, RSSI_B, pDM_SWAT_Table->RSSI_cnt_B)); ++ } ++ ++ } ++ else ++ { ++ ++ if(pDM_SWAT_Table->RSSI_cnt_A > 0) ++ RSSI_A = pDM_SWAT_Table->RSSI_sum_A/pDM_SWAT_Table->RSSI_cnt_A; ++ else ++ RSSI_A = 0; ++ if(pDM_SWAT_Table->RSSI_cnt_B > 0) ++ RSSI_B = pDM_SWAT_Table->RSSI_sum_B/pDM_SWAT_Table->RSSI_cnt_B; ++ else ++ RSSI_B = 0; ++ curRSSI = (pDM_SWAT_Table->CurAntenna == Antenna_A)? RSSI_A : RSSI_B; ++ pDM_SWAT_Table->PreRSSI = (pDM_SWAT_Table->PreAntenna == Antenna_A)? RSSI_A : RSSI_B; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ekul:PreRSSI = %d, CurRSSI = %d\n", pDM_SWAT_Table->PreRSSI, curRSSI)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: preAntenna= %s, curAntenna= %s \n", ++ (pDM_SWAT_Table->PreAntenna == Antenna_A?"A":"B"), (pDM_SWAT_Table->CurAntenna == Antenna_A?"A":"B"))); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ekul:RSSI_A= %d, RSSI_cnt_A = %d, RSSI_B= %d, RSSI_cnt_B = %d\n", ++ RSSI_A, pDM_SWAT_Table->RSSI_cnt_A, RSSI_B, pDM_SWAT_Table->RSSI_cnt_B)); ++ //RT_TRACE(COMP_SWAS, DBG_LOUD, ("Ekul:curTxOkCnt = %d\n", curTxOkCnt)); ++ //RT_TRACE(COMP_SWAS, DBG_LOUD, ("Ekul:curRxOkCnt = %d\n", curRxOkCnt)); ++ } ++ ++ //1 Trying State ++ if((pDM_SWAT_Table->try_flag == 1)&&(pDM_SWAT_Table->RSSI_Trying == 0)) ++ { ++ ++ if(pDM_SWAT_Table->TestMode == TP_MODE) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: TestMode = TP_MODE")); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("TRY:CurByteCnt = %lld,", CurByteCnt)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("TRY:PreByteCnt = %lld\n",PreByteCnt)); ++ if(CurByteCnt < PreByteCnt) ++ { ++ if(pDM_SWAT_Table->CurAntenna == Antenna_A) ++ pDM_SWAT_Table->SelectAntennaMap=pDM_SWAT_Table->SelectAntennaMap<<1; ++ else ++ pDM_SWAT_Table->SelectAntennaMap=(pDM_SWAT_Table->SelectAntennaMap<<1)+1; ++ } ++ else ++ { ++ if(pDM_SWAT_Table->CurAntenna == Antenna_A) ++ pDM_SWAT_Table->SelectAntennaMap=(pDM_SWAT_Table->SelectAntennaMap<<1)+1; ++ else ++ pDM_SWAT_Table->SelectAntennaMap=pDM_SWAT_Table->SelectAntennaMap<<1; ++ } ++ for (i= 0; i<8; i++) ++ { ++ if(((pDM_SWAT_Table->SelectAntennaMap>>i)&BIT0) == 1) ++ Score_A++; ++ else ++ Score_B++; ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SelectAntennaMap=%x\n ",pDM_SWAT_Table->SelectAntennaMap)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Score_A=%d, Score_B=%d\n", Score_A, Score_B)); ++ ++ if(pDM_SWAT_Table->CurAntenna == Antenna_A) ++ { ++ nextAntenna = (Score_A > Score_B)?Antenna_A:Antenna_B; ++ } ++ else ++ { ++ nextAntenna = (Score_B > Score_A)?Antenna_B:Antenna_A; ++ } ++ //RT_TRACE(COMP_SWAS, DBG_LOUD, ("nextAntenna=%s\n",(nextAntenna==Antenna_A)?"A":"B")); ++ //RT_TRACE(COMP_SWAS, DBG_LOUD, ("preAntenna= %s, curAntenna= %s \n", ++ //(DM_SWAT_Table.PreAntenna == Antenna_A?"A":"B"), (DM_SWAT_Table.CurAntenna == Antenna_A?"A":"B"))); ++ ++ if(nextAntenna != pDM_SWAT_Table->CurAntenna) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: Switch back to another antenna")); ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: current anntena is good\n")); ++ } ++ } ++ ++ if(pDM_SWAT_Table->TestMode == RSSI_MODE) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: TestMode = RSSI_MODE")); ++ pDM_SWAT_Table->SelectAntennaMap=0xAA; ++ if(curRSSI < pDM_SWAT_Table->PreRSSI) //Current antenna is worse than previous antenna ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: Switch back to another antenna")); ++ nextAntenna = (pDM_SWAT_Table->CurAntenna == Antenna_A)? Antenna_B : Antenna_A; ++ } ++ else // current anntena is good ++ { ++ nextAntenna =pDM_SWAT_Table->CurAntenna; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: current anntena is good\n")); ++ } ++ } ++ pDM_SWAT_Table->try_flag = 0; ++ pDM_Odm->RSSI_test = FALSE; ++ pDM_SWAT_Table->RSSI_sum_A = 0; ++ pDM_SWAT_Table->RSSI_cnt_A = 0; ++ pDM_SWAT_Table->RSSI_sum_B = 0; ++ pDM_SWAT_Table->RSSI_cnt_B = 0; ++ pDM_SWAT_Table->TXByteCnt_A = 0; ++ pDM_SWAT_Table->TXByteCnt_B = 0; ++ pDM_SWAT_Table->RXByteCnt_A = 0; ++ pDM_SWAT_Table->RXByteCnt_B = 0; ++ ++ } ++ ++ //1 Normal State ++ else if(pDM_SWAT_Table->try_flag == 0) ++ { ++ if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_HIGH) ++ { ++ if ((curTxOkCnt+curRxOkCnt) > 3750000)//if(PlatformDivision64(curTxOkCnt+curRxOkCnt, 2) > 1875000) ++ pDM_SWAT_Table->TrafficLoad = TRAFFIC_HIGH; ++ else ++ pDM_SWAT_Table->TrafficLoad = TRAFFIC_LOW; ++ } ++ else if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_LOW) ++ { ++ if ((curTxOkCnt+curRxOkCnt) > 3750000) //if(PlatformDivision64(curTxOkCnt+curRxOkCnt, 2) > 1875000) ++ pDM_SWAT_Table->TrafficLoad = TRAFFIC_HIGH; ++ else ++ pDM_SWAT_Table->TrafficLoad = TRAFFIC_LOW; ++ } ++ if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_HIGH) ++ pDM_SWAT_Table->bTriggerAntennaSwitch = 0; ++ //RT_TRACE(COMP_SWAS, DBG_LOUD, ("Normal:TrafficLoad = %llu\n", curTxOkCnt+curRxOkCnt)); ++ ++ //Prepare To Try Antenna ++ nextAntenna = (pDM_SWAT_Table->CurAntenna == Antenna_A)? Antenna_B : Antenna_A; ++ pDM_SWAT_Table->try_flag = 1; ++ pDM_Odm->RSSI_test = TRUE; ++ if((curRxOkCnt+curTxOkCnt) > 1000) ++ { ++ pDM_SWAT_Table->RSSI_Trying = 4; ++ pDM_SWAT_Table->TestMode = TP_MODE; ++ } ++ else ++ { ++ pDM_SWAT_Table->RSSI_Trying = 2; ++ pDM_SWAT_Table->TestMode = RSSI_MODE; ++ ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: Normal State -> Begin Trying!\n")); ++ ++ ++ pDM_SWAT_Table->RSSI_sum_A = 0; ++ pDM_SWAT_Table->RSSI_cnt_A = 0; ++ pDM_SWAT_Table->RSSI_sum_B = 0; ++ pDM_SWAT_Table->RSSI_cnt_B = 0; ++ } ++ } ++ ++ //1 4.Change TRX antenna ++ if(nextAntenna != pDM_SWAT_Table->CurAntenna) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: Change TX Antenna!\n ")); ++ //PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300, nextAntenna); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ODM_SetAntenna(pDM_Odm,nextAntenna); ++ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ { ++ BOOLEAN bEnqueue; ++ bEnqueue = (pDM_Odm->SupportInterface == ODM_ITRF_PCIE)?FALSE :TRUE; ++ rtw_antenna_select_cmd(pDM_Odm->Adapter, nextAntenna, bEnqueue); ++ } ++ #endif ++ ++ } ++ ++ //1 5.Reset Statistics ++ pDM_SWAT_Table->PreAntenna = pDM_SWAT_Table->CurAntenna; ++ pDM_SWAT_Table->CurAntenna = nextAntenna; ++ pDM_SWAT_Table->PreRSSI = curRSSI; ++ ++ //1 6.Set next timer ++ { ++ PADAPTER pAdapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ ++ if(pDM_SWAT_Table->RSSI_Trying == 0) ++ return; ++ ++ if(pDM_SWAT_Table->RSSI_Trying%2 == 0) ++ { ++ if(pDM_SWAT_Table->TestMode == TP_MODE) ++ { ++ if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_HIGH) ++ { ++ //PlatformSetTimer( pAdapter, &pHalData->SwAntennaSwitchTimer, 10 ); //ms ++ ODM_SetTimer(pDM_Odm,&pDM_SWAT_Table->SwAntennaSwitchTimer, 10 ); //ms ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("dm_SW_AntennaSwitch(): Test another antenna for 10 ms\n")); ++ } ++ else if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_LOW) ++ { ++ //PlatformSetTimer( pAdapter, &pHalData->SwAntennaSwitchTimer, 50 ); //ms ++ ODM_SetTimer(pDM_Odm,&pDM_SWAT_Table->SwAntennaSwitchTimer, 50 ); //ms ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("dm_SW_AntennaSwitch(): Test another antenna for 50 ms\n")); ++ } ++ } ++ else ++ { ++ //PlatformSetTimer( pAdapter, &pHalData->SwAntennaSwitchTimer, 500 ); //ms ++ ODM_SetTimer(pDM_Odm,&pDM_SWAT_Table->SwAntennaSwitchTimer, 500 ); //ms ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("dm_SW_AntennaSwitch(): Test another antenna for 500 ms\n")); ++ } ++ } ++ else ++ { ++ if(pDM_SWAT_Table->TestMode == TP_MODE) ++ { ++ if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_HIGH) ++ //PlatformSetTimer( pAdapter, &pHalData->SwAntennaSwitchTimer, 90 ); //ms ++ ODM_SetTimer(pDM_Odm,&pDM_SWAT_Table->SwAntennaSwitchTimer, 90 ); //ms ++ else if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_LOW) ++ //PlatformSetTimer( pAdapter, &pHalData->SwAntennaSwitchTimer, 100 ); //ms ++ ODM_SetTimer(pDM_Odm,&pDM_SWAT_Table->SwAntennaSwitchTimer, 100 ); //ms ++ } ++ else ++ //PlatformSetTimer( pAdapter, &pHalData->SwAntennaSwitchTimer, 500 ); //ms ++ ODM_SetTimer(pDM_Odm,&pDM_SWAT_Table->SwAntennaSwitchTimer, 500 ); //ms ++ } ++ } ++#endif // #if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE)) ++#endif // #if (RTL8192C_SUPPORT==1) ++} ++ ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ++u1Byte ++odm_SwAntDivSelectChkChnl( ++ IN PADAPTER Adapter ++ ) ++{ ++#if (RT_MEM_SIZE_LEVEL != RT_MEM_SIZE_MINIMUM) ++ u1Byte index, target_chnl=0; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ u1Byte chnl_peer_cnt[14] = {0}; ++ ++ if(Adapter->MgntInfo.tmpNumBssDesc==0) ++ { ++ return 0; ++ } ++ else ++ { ++ // 20100519 Joseph: Select checking channel from current scan list. ++ // We just choose the channel with most APs to be the test scan channel. ++ for(index=0; indexMgntInfo.tmpNumBssDesc; index++) ++ { ++ // Add by hpfan: prevent access invalid channel number ++ // TODO: Verify channel number by channel plan ++ if(Adapter->MgntInfo.tmpbssDesc[index].ChannelNumber == 0 || ++ Adapter->MgntInfo.tmpbssDesc[index].ChannelNumber > 13) ++ continue; ++ ++ chnl_peer_cnt[Adapter->MgntInfo.tmpbssDesc[index].ChannelNumber-1]++; ++ } ++ for(index=0; index<14; index++) ++ { ++ if(chnl_peer_cnt[index]>chnl_peer_cnt[target_chnl]) ++ target_chnl = index; ++ } ++ target_chnl+=1; ++ ODM_RT_TRACE(pDM_Odm,COMP_SWAS, DBG_LOUD, ++ ("odm_SwAntDivSelectChkChnl(): Channel %d is select as test channel.\n", target_chnl)); ++ ++ return target_chnl; ++ } ++#else ++ return 0; ++#endif ++} ++ ++ ++VOID ++odm_SwAntDivConsructChkScanChnl( ++ IN PADAPTER Adapter, ++ IN u1Byte ChkChnl ++ ) ++{ ++ ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ PRT_CHANNEL_LIST pChannelList = GET_RT_CHANNEL_LIST(pMgntInfo); ++ u1Byte index; ++ ++ if(ChkChnl==0) ++ { ++ // 20100519 Joseph: Original antenna scanned nothing. ++ // Test antenna shall scan all channel with half period in this condition. ++ RtActChannelList(Adapter, RT_CHNL_LIST_ACTION_CONSTRUCT_SCAN_LIST, NULL, NULL); ++ for(index=0; indexChannelLen; index++) ++ pChannelList->ChannelInfo[index].ScanPeriod /= 2; ++ } ++ else ++ { ++ // The using of this CustomizedScanRequest is a trick to rescan the two channels ++ // under the NORMAL scanning process. It will not affect MGNT_INFO.CustomizedScanRequest. ++ CUSTOMIZED_SCAN_REQUEST CustomScanReq; ++ ++ CustomScanReq.bEnabled = TRUE; ++ CustomScanReq.Channels[0] = ChkChnl; ++ CustomScanReq.Channels[1] = pMgntInfo->dot11CurrentChannelNumber; ++ CustomScanReq.nChannels = 2; ++ CustomScanReq.ScanType = SCAN_ACTIVE; ++ CustomScanReq.Duration = DEFAULT_ACTIVE_SCAN_PERIOD; ++ ++ RtActChannelList(Adapter, RT_CHNL_LIST_ACTION_CONSTRUCT_SCAN_LIST, &CustomScanReq, NULL); ++ } ++ ++} ++#endif //#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ++// ++// 20100514 Luke/Joseph: ++// Callback function for 500ms antenna test trying. ++// ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++VOID ++odm_SwAntDivChkAntSwitchCallback( ++ PRT_TIMER pTimer ++) ++{ ++ PADAPTER Adapter = (PADAPTER)pTimer->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ pSWAT_T pDM_SWAT_Table = &pHalData->DM_OutSrc.DM_SWAT_Table; ++ ++ #if DEV_BUS_TYPE==RT_PCI_INTERFACE ++ #if USE_WORKITEM ++ ODM_ScheduleWorkItem(&pDM_SWAT_Table->SwAntennaSwitchWorkitem); ++ #else ++ odm_SwAntDivChkAntSwitch(&pHalData->DM_OutSrc, SWAW_STEP_DETERMINE); ++ #endif ++#else ++ ODM_ScheduleWorkItem(&pDM_SWAT_Table->SwAntennaSwitchWorkitem); ++ #endif ++ ++} ++VOID ++odm_SwAntDivChkAntSwitchWorkitemCallback( ++ IN PVOID pContext ++ ) ++{ ++ ++ PADAPTER pAdapter = (PADAPTER)pContext; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ odm_SwAntDivChkAntSwitch(&pHalData->DM_OutSrc, SWAW_STEP_DETERMINE); ++ ++} ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++VOID odm_SwAntDivChkAntSwitchCallback(void *FunctionContext) ++{ ++ PDM_ODM_T pDM_Odm= (PDM_ODM_T)FunctionContext; ++ PADAPTER padapter = pDM_Odm->Adapter; ++ if(padapter->net_closed == _TRUE) ++ return; ++ odm_SwAntDivChkAntSwitch(pDM_Odm, SWAW_STEP_DETERMINE); ++} ++#elif (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++VOID odm_SwAntDivChkAntSwitchCallback(void *FunctionContext) ++{ ++ PDM_ODM_T pDM_Odm= (PDM_ODM_T)FunctionContext; ++ odm_SwAntDivChkAntSwitch(pDM_Odm, SWAW_STEP_DETERMINE); ++} ++#endif ++ ++#else //#if(defined(CONFIG_SW_ANTENNA_DIVERSITY)) ++ ++VOID odm_SwAntDivInit( IN PDM_ODM_T pDM_Odm ) {} ++VOID ODM_SwAntDivChkPerPktRssi( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte StationID, ++ IN PODM_PHY_INFO_T pPhyInfo ++ ) {} ++VOID odm_SwAntDivChkAntSwitch( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte Step ++ ) {} ++VOID ODM_SwAntDivResetBeforeLink( IN PDM_ODM_T pDM_Odm ){} ++VOID ODM_SwAntDivRestAfterLink( IN PDM_ODM_T pDM_Odm ){} ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++u1Byte odm_SwAntDivSelectChkChnl( IN PADAPTER Adapter ){ return 0;} ++VOID ++odm_SwAntDivConsructChkScanChnl( ++ IN PADAPTER Adapter, ++ IN u1Byte ChkChnl ++ ){} ++#endif ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++VOID odm_SwAntDivChkAntSwitchCallback( PRT_TIMER pTimer){} ++VOID odm_SwAntDivChkAntSwitchWorkitemCallback( IN PVOID pContext ){} ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++VOID odm_SwAntDivChkAntSwitchCallback(void *FunctionContext){} ++#elif (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++VOID odm_SwAntDivChkAntSwitchCallback(void *FunctionContext){} ++#endif ++ ++#endif //#if(defined(CONFIG_SW_ANTENNA_DIVERSITY)) ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++#if((defined(CONFIG_SW_ANTENNA_DIVERSITY))||(defined(CONFIG_HW_ANTENNA_DIVERSITY))) ++BOOLEAN ++ODM_SwAntDivCheckBeforeLink8192C( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ ++#if (RT_MEM_SIZE_LEVEL != RT_MEM_SIZE_MINIMUM) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData=NULL; ++ PMGNT_INFO pMgntInfo = NULL; ++ //pSWAT_T pDM_SWAT_Table = &Adapter->DM_SWAT_Table; ++ pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; ++ ++ s1Byte Score = 0; ++ PRT_WLAN_BSS pTmpBssDesc; ++ PRT_WLAN_BSS pTestBssDesc; ++ ++ u1Byte target_chnl = 0; ++ u1Byte index; ++ ++return FALSE; ++ if (pDM_Odm->Adapter == NULL) //For BSOD when plug/unplug fast. //By YJ,120413 ++ { // The ODM structure is not initialized. ++ return FALSE; ++ } ++ // 2012/04/26 MH Prevent no-checked IC to execute antenna diversity. ++ if(pDM_Odm->SupportICType == ODM_RTL8188E && pDM_Odm->SupportInterface != ODM_ITRF_PCIE) ++ return FALSE; ++ pHalData = GET_HAL_DATA(Adapter); ++ pMgntInfo = &Adapter->MgntInfo; ++ ++ // Condition that does not need to use antenna diversity. ++ if(IS_8723_SERIES(pHalData->VersionID) || ++ IS_92C_SERIAL(pHalData->VersionID) || ++ (pHalData->AntDivCfg==0) || ++ pMgntInfo->AntennaTest || ++ Adapter->bInHctTest) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ++ ("ODM_SwAntDivCheckBeforeLink8192C(): No AntDiv Mechanism.\n")); ++ return FALSE; ++ } ++ ++ if(IS_8723_SERIES(pHalData->VersionID) || IS_92C_SERIAL(pHalData->VersionID) ) ++ { ++ if((pDM_SWAT_Table->ANTA_ON == FALSE) ||(pDM_SWAT_Table->ANTB_ON == FALSE)) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ++ ("ODM_SwAntDivCheckBeforeLink8192C(): No AntDiv Mechanism, Antenna A or B is off\n")); ++ return FALSE; ++ } ++ } ++ ++ // Since driver is going to set BB register, it shall check if there is another thread controlling BB/RF. ++ PlatformAcquireSpinLock(Adapter, RT_RF_STATE_SPINLOCK); ++ if(pHalData->eRFPowerState!=eRfOn || pMgntInfo->RFChangeInProgress || pMgntInfo->bMediaConnect) ++ { ++ PlatformReleaseSpinLock(Adapter, RT_RF_STATE_SPINLOCK); ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ++ ("ODM_SwAntDivCheckBeforeLink8192C(): RFChangeInProgress(%x), eRFPowerState(%x)\n", ++ pMgntInfo->RFChangeInProgress, ++ pHalData->eRFPowerState)); ++ ++ pDM_SWAT_Table->SWAS_NoLink_State = 0; ++ ++ return FALSE; ++ } ++ else ++ { ++ PlatformReleaseSpinLock(Adapter, RT_RF_STATE_SPINLOCK); ++ } ++ ++ //1 Run AntDiv mechanism "Before Link" part. ++ if(pDM_SWAT_Table->SWAS_NoLink_State == 0) ++ { ++ //1 Prepare to do Scan again to check current antenna state. ++ ++ // Set check state to next step. ++ pDM_SWAT_Table->SWAS_NoLink_State = 1; ++ ++ // Copy Current Scan list. ++ Adapter->MgntInfo.tmpNumBssDesc = pMgntInfo->NumBssDesc; ++ PlatformMoveMemory((PVOID)Adapter->MgntInfo.tmpbssDesc, (PVOID)pMgntInfo->bssDesc, sizeof(RT_WLAN_BSS)*MAX_BSS_DESC); ++ ++ if(pDM_Odm->SupportICType == ODM_RTL8188E) ++ { ++ if(pDM_FatTable->RxIdleAnt == MAIN_ANT) ++ ODM_UpdateRxIdleAnt_88E(pDM_Odm, AUX_ANT); ++ else ++ ODM_UpdateRxIdleAnt_88E(pDM_Odm, MAIN_ANT); ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ++ ("ODM_SwAntDivCheckBeforeLink8192C: Change to %s for testing.\n", ((pDM_FatTable->RxIdleAnt == MAIN_ANT)?"MAIN_ANT":"AUX_ANT"))); ++ } ++ if(pDM_Odm->SupportICType != ODM_RTL8188E) ++ { ++ // Switch Antenna to another one. ++ pDM_SWAT_Table->PreAntenna = pDM_SWAT_Table->CurAntenna; ++ pDM_SWAT_Table->CurAntenna = (pDM_SWAT_Table->CurAntenna==Antenna_A)?Antenna_B:Antenna_A; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ++ ("ODM_SwAntDivCheckBeforeLink8192C: Change to Ant(%s) for testing.\n", (pDM_SWAT_Table->CurAntenna==Antenna_A)?"A":"B")); ++ //PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300, DM_SWAT_Table.CurAntenna); ++ pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 = ((pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 & 0xfffffcff) | (pDM_SWAT_Table->CurAntenna<<8)); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, bMaskDWord, pDM_SWAT_Table->SWAS_NoLink_BK_Reg860); ++ } ++ // Go back to scan function again. ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SwAntDivCheckBeforeLink8192C: Scan one more time\n")); ++ pMgntInfo->ScanStep=0; ++ target_chnl = odm_SwAntDivSelectChkChnl(Adapter); ++ odm_SwAntDivConsructChkScanChnl(Adapter, target_chnl); ++ HTReleaseChnlOpLock(Adapter); ++ PlatformSetTimer(Adapter, &pMgntInfo->ScanTimer, 5); ++ ++ return TRUE; ++ } ++ else ++ { ++ //1 ScanComple() is called after antenna swiched. ++ //1 Check scan result and determine which antenna is going ++ //1 to be used. ++ ++ for(index=0; indexMgntInfo.tmpNumBssDesc; index++) ++ { ++ pTmpBssDesc = &(Adapter->MgntInfo.tmpbssDesc[index]); ++ pTestBssDesc = &(pMgntInfo->bssDesc[index]); ++ ++ if(PlatformCompareMemory(pTestBssDesc->bdBssIdBuf, pTmpBssDesc->bdBssIdBuf, 6)!=0) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SwAntDivCheckBeforeLink8192C(): ERROR!! This shall not happen.\n")); ++ continue; ++ } ++ ++ if(pTmpBssDesc->RecvSignalPower > pTestBssDesc->RecvSignalPower) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SwAntDivCheckBeforeLink8192C: Compare scan entry: Score++\n")); ++ RT_PRINT_STR(ODM_COMP_ANT_DIV, ODM_DBG_LOUD, "SSID: ", pTestBssDesc->bdSsIdBuf, pTestBssDesc->bdSsIdLen); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Original: %d, Test: %d\n", pTmpBssDesc->RecvSignalPower, pTestBssDesc->RecvSignalPower)); ++ ++ Score++; ++ PlatformMoveMemory(pTestBssDesc, pTmpBssDesc, sizeof(RT_WLAN_BSS)); ++ } ++ else if(pTmpBssDesc->RecvSignalPower < pTestBssDesc->RecvSignalPower) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SwAntDivCheckBeforeLink8192C: Compare scan entry: Score--\n")); ++ RT_PRINT_STR(ODM_COMP_ANT_DIV, ODM_DBG_LOUD, "SSID: ", pTestBssDesc->bdSsIdBuf, pTestBssDesc->bdSsIdLen); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Original: %d, Test: %d\n", pTmpBssDesc->RecvSignalPower, pTestBssDesc->RecvSignalPower)); ++ Score--; ++ } ++ ++ } ++ ++ if(pDM_Odm->SupportICType == ODM_RTL8188E) ++ { ++ if(pMgntInfo->NumBssDesc!=0 && Score<=0) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ++ ("ODM_SwAntDivCheckBeforeLink8192C(): Using Ant(%s)\n", (pDM_FatTable->RxIdleAnt==MAIN_ANT)?"MAIN_ANT":"AUX_ANT")); ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ++ ("ODM_SwAntDivCheckBeforeLink8192C(): Remain Ant(%s)\n", (pDM_FatTable->RxIdleAnt==MAIN_ANT)?"AUX_ANT":"MAIN_ANT")); ++ ++ if(pDM_FatTable->RxIdleAnt == MAIN_ANT) ++ ODM_UpdateRxIdleAnt_88E(pDM_Odm, AUX_ANT); ++ else ++ ODM_UpdateRxIdleAnt_88E(pDM_Odm, MAIN_ANT); ++ } ++ } ++ ++ if(pDM_Odm->SupportICType != ODM_RTL8188E) ++ { ++ if(pMgntInfo->NumBssDesc!=0 && Score<=0) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ++ ("ODM_SwAntDivCheckBeforeLink8192C(): Using Ant(%s)\n", (pDM_SWAT_Table->CurAntenna==Antenna_A)?"Antenna_A":"Antenna_B")); ++ ++ pDM_SWAT_Table->PreAntenna = pDM_SWAT_Table->CurAntenna; ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ++ ("ODM_SwAntDivCheckBeforeLink8192C(): Remain Ant(%s)\n", (pDM_SWAT_Table->CurAntenna==Antenna_A)?"Antenna_B":"Antenna_A")); ++ ++ pDM_SWAT_Table->CurAntenna = pDM_SWAT_Table->PreAntenna; ++ ++ //PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300, DM_SWAT_Table.CurAntenna); ++ pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 = ((pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 & 0xfffffcff) | (pDM_SWAT_Table->CurAntenna<<8)); ++ PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, bMaskDWord, pDM_SWAT_Table->SWAS_NoLink_BK_Reg860); ++ } ++ } ++ // Check state reset to default and wait for next time. ++ pDM_SWAT_Table->SWAS_NoLink_State = 0; ++ ++ return FALSE; ++ } ++#else ++ return FALSE; ++#endif ++ ++return FALSE; ++} ++#else ++BOOLEAN ++ODM_SwAntDivCheckBeforeLink8192C( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ ++ return FALSE; ++ ++} ++#endif //#if((defined(CONFIG_SW_ANTENNA_DIVERSITY))||(defined(CONFIG_HW_ANTENNA_DIVERSITY))) ++#endif //#if(DM_ODM_SUPPORT_TYPE==ODM_MP) ++ ++ ++//3============================================================ ++//3 SW Antenna Diversity ++//3============================================================ ++ ++#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) ++VOID ++odm_InitHybridAntDiv_88C_92D( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ ++#if((DM_ODM_SUPPORT_TYPE==ODM_AP)||(DM_ODM_SUPPORT_TYPE==ODM_ADSL)) ++ struct rtl8192cd_priv *priv=pDM_Odm->priv; ++#endif ++ SWAT_T *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ u1Byte bTxPathSel=0; //0:Path-A 1:Path-B ++ u1Byte i; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("odm_InitHybridAntDiv==============>\n")); ++ ++ //whether to do antenna diversity or not ++#if(DM_ODM_SUPPORT_TYPE==ODM_AP) ++ if(priv==NULL) return; ++ if(!priv->pshare->rf_ft_var.antHw_enable) ++ return; ++ ++ #ifdef SW_ANT_SWITCH ++ priv->pshare->rf_ft_var.antSw_enable =0; ++ #endif ++#endif ++ ++ if((pDM_Odm->SupportICType != ODM_RTL8192C) && (pDM_Odm->SupportICType != ODM_RTL8192D)) ++ return; ++ ++ ++ bTxPathSel=(pDM_Odm->RFType==ODM_1T1R)?FALSE:TRUE; ++ ++ ODM_SetBBReg(pDM_Odm,ODM_REG_BB_PWR_SAV1_11N, BIT23, 0); //No update ANTSEL during GNT_BT=1 ++ ODM_SetBBReg(pDM_Odm,ODM_REG_TX_ANT_CTRL_11N, BIT21, 1); //TX atenna selection from tx_info ++ ODM_SetBBReg(pDM_Odm,ODM_REG_ANTSEL_PIN_11N, BIT23, 1); //enable LED[1:0] pin as ANTSEL ++ ODM_SetBBReg(pDM_Odm,ODM_REG_ANTSEL_CTRL_11N, BIT8|BIT9, 0x01); // 0x01: left antenna, 0x02: right antenna ++ // check HW setting: ANTSEL pin connection ++ #if(DM_ODM_SUPPORT_TYPE==ODM_AP) ++ ODM_Write2Byte(pDM_Odm,ODM_REG_RF_PIN_11N, (ODM_Read2Byte(pDM_Odm,0x804)&0xf0ff )| BIT(8) ); // b11-b8=0001,update RFPin setting ++ #endif ++ ++ // only AP support different path selection temperarly ++ if(!bTxPathSel){ //PATH-A ++ ODM_SetBBReg(pDM_Odm,ODM_REG_PIN_CTRL_11N, BIT8|BIT9, 0 ); // ANTSEL as HW control ++ ODM_SetBBReg(pDM_Odm,ODM_REG_ANTSEL_PATH_11N, BIT13, 1); //select TX ANTESEL from path A ++ } ++ else { ++ ODM_SetBBReg(pDM_Odm,ODM_REG_PIN_CTRL_11N, BIT24|BIT25, 0 ); // ANTSEL as HW control ++ ODM_SetBBReg(pDM_Odm,ODM_REG_ANTSEL_PATH_11N, BIT13, 0); //select ANTESEL from path B ++ } ++ ++ //Set OFDM HW RX Antenna Diversity ++ ODM_SetBBReg(pDM_Odm,ODM_REG_ANTDIV_PARA1_11N, 0x7FF, 0x0c0); //Pwdb threshold=8dB ++ ODM_SetBBReg(pDM_Odm,ODM_REG_ANTDIV_PARA1_11N, BIT11, 0); //Switch to another antenna by checking pwdb threshold ++ ODM_SetBBReg(pDM_Odm,ODM_REG_ANTDIV_PARA3_11N, BIT23, 1); // Decide final antenna by comparing 2 antennas' pwdb ++ ++ //Set CCK HW RX Antenna Diversity ++ ODM_SetBBReg(pDM_Odm,ODM_REG_CCK_ANTDIV_PARA2_11N, BIT4, 0); //Antenna diversity decision period = 32 sample ++ ODM_SetBBReg(pDM_Odm,ODM_REG_CCK_ANTDIV_PARA2_11N, 0xf, 0xf); //Threshold for antenna diversity. Check another antenna power if input power < ANT_lim*4 ++ ODM_SetBBReg(pDM_Odm,ODM_REG_CCK_ANTDIV_PARA3_11N, BIT13, 1); //polarity ana_A=1 and ana_B=0 ++ ODM_SetBBReg(pDM_Odm,ODM_REG_CCK_ANTDIV_PARA4_11N, 0x1f, 0x8); //default antenna power = inpwr*(0.5 + r_ant_step/16) ++ ++ ++ //Enable HW Antenna Diversity ++ if(!bTxPathSel) //PATH-A ++ ODM_SetBBReg(pDM_Odm,ODM_REG_IGI_A_11N, BIT7,1); // Enable Hardware antenna switch ++ else ++ ODM_SetBBReg(pDM_Odm,ODM_REG_IGI_B_11N, BIT7,1); // Enable Hardware antenna switch ++ ODM_SetBBReg(pDM_Odm,ODM_REG_CCK_ANTDIV_PARA1_11N, BIT15, 1);//Enable antenna diversity ++ ++ pDM_SWAT_Table->CurAntenna=0; //choose left antenna as default antenna ++ pDM_SWAT_Table->PreAntenna=0; ++ for(i=0; iCCK_Ant1_Cnt[i] = 0; ++ pDM_SWAT_Table->CCK_Ant2_Cnt[i] = 0; ++ pDM_SWAT_Table->OFDM_Ant1_Cnt[i] = 0; ++ pDM_SWAT_Table->OFDM_Ant2_Cnt[i] = 0; ++ pDM_SWAT_Table->RSSI_Ant1_Sum[i] = 0; ++ pDM_SWAT_Table->RSSI_Ant2_Sum[i] = 0; ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("<==============odm_InitHybridAntDiv\n")); ++} ++ ++ ++VOID ++odm_InitHybridAntDiv( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ if(!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("Return: Not Support HW AntDiv\n")); ++ return; ++ } ++ ++ if(pDM_Odm->SupportICType & (ODM_RTL8192C | ODM_RTL8192D)) ++ { ++#if ((RTL8192C_SUPPORT == 1)||(RTL8192D_SUPPORT == 1)) ++ odm_InitHybridAntDiv_88C_92D(pDM_Odm); ++#endif ++ } ++ else if(pDM_Odm->SupportICType == ODM_RTL8188E) ++ { ++#if (RTL8188E_SUPPORT == 1) ++ ODM_AntennaDiversityInit_88E(pDM_Odm); ++#endif ++ } ++ ++} ++ ++ ++BOOLEAN ++odm_StaDefAntSel( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte OFDM_Ant1_Cnt, ++ IN u4Byte OFDM_Ant2_Cnt, ++ IN u4Byte CCK_Ant1_Cnt, ++ IN u4Byte CCK_Ant2_Cnt, ++ OUT u1Byte *pDefAnt ++ ++ ) ++{ ++#if 1 ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("odm_StaDefAntSelect==============>\n")); ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("OFDM_Ant1_Cnt:%d, OFDM_Ant2_Cnt:%d\n",OFDM_Ant1_Cnt,OFDM_Ant2_Cnt)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("CCK_Ant1_Cnt:%d, CCK_Ant2_Cnt:%d\n",CCK_Ant1_Cnt,CCK_Ant2_Cnt)); ++ ++ ++ if(((OFDM_Ant1_Cnt+OFDM_Ant2_Cnt)==0)&&((CCK_Ant1_Cnt + CCK_Ant2_Cnt) <10)){ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("odm_StaDefAntSelect Fail: No enough packet info!\n")); ++ return FALSE; ++ } ++ ++ if(OFDM_Ant1_Cnt || OFDM_Ant2_Cnt ) { ++ //if RX OFDM packet number larger than 0 ++ if(OFDM_Ant1_Cnt > OFDM_Ant2_Cnt) ++ (*pDefAnt)=1; ++ else ++ (*pDefAnt)=0; ++ } ++ // else if RX CCK packet number larger than 10 ++ else if((CCK_Ant1_Cnt + CCK_Ant2_Cnt) >=10 ) ++ { ++ if(CCK_Ant1_Cnt > (5*CCK_Ant2_Cnt)) ++ (*pDefAnt)=1; ++ else if(CCK_Ant2_Cnt > (5*CCK_Ant1_Cnt)) ++ (*pDefAnt)=0; ++ else if(CCK_Ant1_Cnt > CCK_Ant2_Cnt) ++ (*pDefAnt)=0; ++ else ++ (*pDefAnt)=1; ++ ++ } ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("TxAnt = %s\n",((*pDefAnt)==1)?"Ant1":"Ant2")); ++ ++#endif ++ //u4Byte antsel = ODM_GetBBReg(pDM_Odm, 0xc88, bMaskByte0); ++ //(*pDefAnt)= (u1Byte) antsel; ++ ++ ++ ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("<==============odm_StaDefAntSelect\n")); ++ ++ return TRUE; ++ ++ ++} ++ ++ ++VOID ++odm_SetRxIdleAnt( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte Ant, ++ IN BOOLEAN bDualPath ++) ++{ ++ SWAT_T *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ ++ //ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("odm_SetRxIdleAnt==============>\n")); ++ ++ if(Ant != pDM_SWAT_Table->RxIdleAnt) ++ { ++ //for path-A ++ if(Ant==1) ++ ODM_SetBBReg(pDM_Odm,ODM_REG_RX_DEFUALT_A_11N, 0xFFFF, 0x65a9); //right-side antenna ++ else ++ ODM_SetBBReg(pDM_Odm,ODM_REG_RX_DEFUALT_A_11N, 0xFFFF, 0x569a); //left-side antenna ++ ++ //for path-B ++ if(bDualPath){ ++ if(Ant==0) ++ ODM_SetBBReg(pDM_Odm,ODM_REG_RX_DEFUALT_A_11N, 0xFFFF0000, 0x65a9); //right-side antenna ++ else ++ ODM_SetBBReg(pDM_Odm,ODM_REG_RX_DEFUALT_A_11N, 0xFFFF0000, 0x569a); //left-side antenna ++ } ++ } ++ pDM_SWAT_Table->RxIdleAnt = Ant; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("RxIdleAnt: %s Reg858=0x%x\n",(Ant==1)?"Ant1":"Ant2",(Ant==1)?0x65a9:0x569a)); ++ ++ //ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("<==============odm_SetRxIdleAnt\n")); ++ ++ } ++ ++VOID ++ODM_AntselStatistics_88C( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacId, ++ IN u4Byte PWDBAll, ++ IN BOOLEAN isCCKrate ++) ++{ ++ SWAT_T *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ ++ if(pDM_SWAT_Table->antsel == 1) ++ { ++ if(isCCKrate) ++ pDM_SWAT_Table->CCK_Ant1_Cnt[MacId]++; ++ else ++ { ++ pDM_SWAT_Table->OFDM_Ant1_Cnt[MacId]++; ++ pDM_SWAT_Table->RSSI_Ant1_Sum[MacId] += PWDBAll; ++ } ++ } ++ else ++ { ++ if(isCCKrate) ++ pDM_SWAT_Table->CCK_Ant2_Cnt[MacId]++; ++ else ++ { ++ pDM_SWAT_Table->OFDM_Ant2_Cnt[MacId]++; ++ pDM_SWAT_Table->RSSI_Ant2_Sum[MacId] += PWDBAll; ++ } ++ } ++ ++} ++ ++ ++ ++ ++#if(DM_ODM_SUPPORT_TYPE==ODM_MP) ++VOID ++ODM_SetTxAntByTxInfo_88C_92D( ++ IN PDM_ODM_T pDM_Odm, ++ IN pu1Byte pDesc, ++ IN u1Byte macId ++) ++{ ++ SWAT_T *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ u1Byte antsel; ++ ++ if(!(pDM_Odm->SupportAbility&ODM_BB_ANT_DIV)) ++ return; ++ ++ if(pDM_SWAT_Table->RxIdleAnt == 1) ++ antsel=(pDM_SWAT_Table->TxAnt[macId] == 1)?0:1; ++ else ++ antsel=(pDM_SWAT_Table->TxAnt[macId] == 1)?1:0; ++ ++ SET_TX_DESC_ANTSEL_A_92C(pDesc, antsel); ++ //SET_TX_DESC_ANTSEL_B_92C(pDesc, antsel); ++ //ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("SET_TX_DESC_ANTSEL_A_92C=%d\n", pDM_SWAT_Table->TxAnt[macId])); ++} ++#elif(DM_ODM_SUPPORT_TYPE==ODM_CE) ++VOID ++ODM_SetTxAntByTxInfo_88C_92D( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ ++} ++#elif(DM_ODM_SUPPORT_TYPE==ODM_AP) ++VOID ++ODM_SetTxAntByTxInfo_88C_92D( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ ++} ++#endif ++ ++VOID ++odm_HwAntDiv_92C_92D( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ SWAT_T *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ u4Byte RSSI_Min=0xFF, RSSI, RSSI_Ant1, RSSI_Ant2; ++ u1Byte RxIdleAnt, i; ++ BOOLEAN bRet=FALSE; ++ PSTA_INFO_T pEntry; ++ ++#if (DM_ODM_SUPPORT_TYPE==ODM_AP) ++ struct rtl8192cd_priv *priv=pDM_Odm->priv; ++ //if test, return ++ if(priv->pshare->rf_ft_var.CurAntenna & 0x80) ++ return; ++#endif ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("odm_HwAntDiv==============>\n")); ++ ++ if(!(pDM_Odm->SupportAbility&ODM_BB_ANT_DIV)) //if don't support antenna diveristy ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("odm_HwAntDiv: Not supported!\n")); ++ return; ++ } ++ ++ if((pDM_Odm->SupportICType != ODM_RTL8192C) && (pDM_Odm->SupportICType != ODM_RTL8192D)) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("Return: IC Type is not 92C or 92D\n")); ++ return; ++ } ++ ++#if (DM_ODM_SUPPORT_TYPE&(ODM_MP|ODM_CE)) ++ if(!pDM_Odm->bLinked) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("Return: bLinked is FALSE\n")); ++ return; ++ } ++#endif ++ ++ for (i=0; ipODM_StaInfo[i]; ++ if(IS_STA_VALID(pEntry)) ++ { ++ ++ RSSI_Ant1 = (pDM_SWAT_Table->OFDM_Ant1_Cnt[i] == 0)?0:(pDM_SWAT_Table->RSSI_Ant1_Sum[i]/pDM_SWAT_Table->OFDM_Ant1_Cnt[i]); ++ RSSI_Ant2 = (pDM_SWAT_Table->OFDM_Ant2_Cnt[i] == 0)?0:(pDM_SWAT_Table->RSSI_Ant2_Sum[i]/pDM_SWAT_Table->OFDM_Ant2_Cnt[i]); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("RSSI_Ant1=%d, RSSI_Ant2=%d\n", RSSI_Ant1, RSSI_Ant2)); ++ ++ if(RSSI_Ant1 ||RSSI_Ant2) ++ { ++#if (DM_ODM_SUPPORT_TYPE==ODM_AP) ++ if(pDM_Odm->pODM_StaInfo[i]->expire_to) ++#endif ++ { ++ RSSI = (RSSI_Ant1 < RSSI_Ant2) ? RSSI_Ant1 : RSSI_Ant2; ++ if((!RSSI) || ( RSSI < RSSI_Min) ) { ++ pDM_SWAT_Table->TargetSTA = i; ++ RSSI_Min = RSSI; ++ } ++ } ++ } ++ ///STA: found out default antenna ++ bRet=odm_StaDefAntSel(pDM_Odm, ++ pDM_SWAT_Table->OFDM_Ant1_Cnt[i], ++ pDM_SWAT_Table->OFDM_Ant2_Cnt[i], ++ pDM_SWAT_Table->CCK_Ant1_Cnt[i], ++ pDM_SWAT_Table->CCK_Ant2_Cnt[i], ++ &pDM_SWAT_Table->TxAnt[i]); ++ ++ //if Tx antenna selection: successful ++ if(bRet){ ++ pDM_SWAT_Table->RSSI_Ant1_Sum[i] = 0; ++ pDM_SWAT_Table->RSSI_Ant2_Sum[i] = 0; ++ pDM_SWAT_Table->OFDM_Ant1_Cnt[i] = 0; ++ pDM_SWAT_Table->OFDM_Ant2_Cnt[i] = 0; ++ pDM_SWAT_Table->CCK_Ant1_Cnt[i] = 0; ++ pDM_SWAT_Table->CCK_Ant2_Cnt[i] = 0; ++ } ++ } ++ } ++ ++ //set RX Idle Ant ++ RxIdleAnt = pDM_SWAT_Table->TxAnt[pDM_SWAT_Table->TargetSTA]; ++ odm_SetRxIdleAnt(pDM_Odm, RxIdleAnt, FALSE); ++ ++#if (DM_ODM_SUPPORT_TYPE==ODM_AP) ++#ifdef TX_SHORTCUT ++ if (!priv->pmib->dot11OperationEntry.disable_txsc) { ++ plist = phead->next; ++ while(plist != phead) { ++ pstat = list_entry(plist, struct stat_info, asoc_list); ++ if(pstat->expire_to) { ++ for (i=0; itx_sc_ent[i].hwdesc1); ++ pdesc->Dword2 &= set_desc(~ (BIT(24)|BIT(25))); ++ if((pstat->CurAntenna^priv->pshare->rf_ft_var.CurAntenna)&1) ++ pdesc->Dword2 |= set_desc(BIT(24)|BIT(25)); ++ pdesc= &(pstat->tx_sc_ent[i].hwdesc2); ++ pdesc->Dword2 &= set_desc(~ (BIT(24)|BIT(25))); ++ if((pstat->CurAntenna^priv->pshare->rf_ft_var.CurAntenna)&1) ++ pdesc->Dword2 |= set_desc(BIT(24)|BIT(25)); ++ } ++ } ++ ++ if (plist == plist->next) ++ break; ++ plist = plist->next; ++ }; ++ } ++#endif ++#endif ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("<==============odm_HwAntDiv\n")); ++ ++} ++ ++VOID ++odm_HwAntDiv( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ if(!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("Return: Not Support HW AntDiv\n")); ++ return; ++ } ++ ++ if(pDM_Odm->SupportICType & (ODM_RTL8192C | ODM_RTL8192D)) ++ { ++#if ((RTL8192C_SUPPORT == 1)||(RTL8192D_SUPPORT == 1)) ++ odm_HwAntDiv_92C_92D(pDM_Odm); ++#endif ++ } ++ else if(pDM_Odm->SupportICType == ODM_RTL8188E) ++ { ++#if (RTL8188E_SUPPORT == 1) ++ ODM_AntennaDiversity_88E(pDM_Odm); ++#endif ++ } ++ ++} ++ ++ ++#if(DM_ODM_SUPPORT_TYPE==ODM_AP) ++#if 0 ++VOID ++odm_HwAntDiv( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ struct rtl8192cd_priv *priv=pDM_Odm->priv; ++ struct stat_info *pstat, *pstat_min=NULL; ++ struct list_head *phead, *plist; ++ int rssi_min= 0xff, i; ++ u1Byte idleAnt=priv->pshare->rf_ft_var.CurAntenna; ++ u1Byte nextAnt; ++ BOOLEAN bRet=FALSE; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("odm_HwAntDiv==============>\n")); ++ ++ if((!priv->pshare->rf_ft_var.antHw_enable) ||(!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV))) ++ return; ++ ++ //if test, return ++ if(priv->pshare->rf_ft_var.CurAntenna & 0x80) ++ return; ++ ++ phead = &priv->asoc_list; ++ plist = phead->next; ++ ////========================= ++ //find mimum rssi sta ++ ////========================= ++ while(plist != phead) { ++ pstat = list_entry(plist, struct stat_info, asoc_list); ++ if((pstat->expire_to) && (pstat->AntRSSI[0] || pstat->AntRSSI[1])) { ++ int rssi = (pstat->AntRSSI[0] < pstat->AntRSSI[1]) ? pstat->AntRSSI[0] : pstat->AntRSSI[1]; ++ if((!pstat_min) || ( rssi < rssi_min) ) { ++ pstat_min = pstat; ++ rssi_min = rssi; ++ } ++ } ++ ///STA: found out default antenna ++ bRet=odm_StaDefAntSel(pDM_Odm, ++ pstat->hwRxAntSel[1], ++ pstat->hwRxAntSel[0], ++ pstat->cckPktCount[1], ++ pstat->cckPktCount[0], ++ &nextAnt ++ ); ++ ++ //if default antenna selection: successful ++ if(bRet){ ++ pstat->CurAntenna = nextAnt; ++ //update rssi ++ for(i=0; i<2; i++) { ++ if(pstat->cckPktCount[i]==0 && pstat->hwRxAntSel[i]==0) ++ pstat->AntRSSI[i] = 0; ++ } ++ if(pstat->AntRSSI[idleAnt]==0) ++ pstat->AntRSSI[idleAnt] = pstat->AntRSSI[idleAnt^1]; ++ // reset variables ++ pstat->hwRxAntSel[1] = pstat->hwRxAntSel[0] =0; ++ pstat->cckPktCount[1]= pstat->cckPktCount[0] =0; ++ } ++ ++ if (plist == plist->next) ++ break; ++ plist = plist->next; ++ ++ }; ++ ////========================= ++ //Choose RX Idle antenna according to minmum rssi ++ ////========================= ++ if(pstat_min) { ++ if(priv->pshare->rf_ft_var.CurAntenna!=pstat_min->CurAntenna) ++ odm_SetRxIdleAnt(pDM_Odm,pstat_min->CurAntenna,TRUE); ++ priv->pshare->rf_ft_var.CurAntenna = pstat_min->CurAntenna; ++ } ++ ++ ++#ifdef TX_SHORTCUT ++ if (!priv->pmib->dot11OperationEntry.disable_txsc) { ++ plist = phead->next; ++ while(plist != phead) { ++ pstat = list_entry(plist, struct stat_info, asoc_list); ++ if(pstat->expire_to) { ++ for (i=0; itx_sc_ent[i].hwdesc1); ++ pdesc->Dword2 &= set_desc(~ (BIT(24)|BIT(25))); ++ if((pstat->CurAntenna^priv->pshare->rf_ft_var.CurAntenna)&1) ++ pdesc->Dword2 |= set_desc(BIT(24)|BIT(25)); ++ pdesc= &(pstat->tx_sc_ent[i].hwdesc2); ++ pdesc->Dword2 &= set_desc(~ (BIT(24)|BIT(25))); ++ if((pstat->CurAntenna^priv->pshare->rf_ft_var.CurAntenna)&1) ++ pdesc->Dword2 |= set_desc(BIT(24)|BIT(25)); ++ } ++ } ++ ++ if (plist == plist->next) ++ break; ++ plist = plist->next; ++ }; ++ } ++#endif ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,"<==============odm_HwAntDiv\n"); ++} ++#endif ++ ++u1Byte ++ODM_Diversity_AntennaSelect( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte *data ++) ++{ ++ struct rtl8192cd_priv *priv=pDM_Odm->priv; ++ ++ int ant = _atoi(data, 16); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("ODM_Diversity_AntennaSelect==============>\n")); ++ ++ #ifdef PCIE_POWER_SAVING ++ PCIeWakeUp(priv, POWER_DOWN_T0); ++ #endif ++ ++ if (ant==Antenna_B || ant==Antenna_A) ++ { ++ if ( !priv->pshare->rf_ft_var.antSw_select) { ++ ODM_Write4Byte(pDM_Odm,0x870, ODM_Read4Byte(pDM_Odm,0x870) | BIT(8)| BIT(9) ); // ANTSEL A as SW control ++ ODM_Write1Byte(pDM_Odm,0xc50, ODM_Read1Byte(pDM_Odm,0xc50) & (~ BIT(7))); // rx OFDM SW control ++ PHY_SetBBReg(priv, 0x860, 0x300, ant); ++ } else { ++ ODM_Write4Byte(pDM_Odm,0x870, ODM_Read4Byte(pDM_Odm,0x870) | BIT(24)| BIT(25) ); // ANTSEL B as HW control ++ PHY_SetBBReg(priv, 0x864, 0x300, ant); ++ ODM_Write1Byte(pDM_Odm,0xc58, ODM_Read1Byte(pDM_Odm,0xc58) & (~ BIT(7))); // rx OFDM SW control ++ } ++ ++ ODM_Write1Byte(pDM_Odm,0xa01, ODM_Read1Byte(pDM_Odm,0xa01) & (~ BIT(7))); // rx CCK SW control ++ ODM_Write4Byte(pDM_Odm,0x80c, ODM_Read4Byte(pDM_Odm,0x80c) & (~ BIT(21))); // select ant by tx desc ++ ODM_Write4Byte(pDM_Odm,0x858, 0x569a569a); ++ ++ priv->pshare->rf_ft_var.antHw_enable = 0; ++ priv->pshare->rf_ft_var.CurAntenna = (ant%2); ++ ++ #ifdef SW_ANT_SWITCH ++ priv->pshare->rf_ft_var.antSw_enable = 0; ++ priv->pshare->DM_SWAT_Table.CurAntenna = ant; ++ priv->pshare->RSSI_test =0; ++ #endif ++ } ++ else if(ant==0){ ++ ++ if ( !priv->pshare->rf_ft_var.antSw_select) { ++ ODM_Write4Byte(pDM_Odm,0x870, ODM_Read4Byte(pDM_Odm,0x870) & ~(BIT(8)| BIT(9)) ); ++ ODM_Write1Byte(pDM_Odm,0xc50, ODM_Read1Byte(pDM_Odm,0xc50) | BIT(7)); // OFDM HW control ++ } else { ++ ODM_Write4Byte(pDM_Odm,0x870, ODM_Read4Byte(pDM_Odm,0x870) & ~(BIT(24)| BIT(25)) ); ++ ODM_Write1Byte(pDM_Odm,0xc58, ODM_Read1Byte(pDM_Odm,0xc58) | BIT(7)); // OFDM HW control ++ } ++ ++ ODM_Write1Byte(pDM_Odm,0xa01, ODM_Read1Byte(pDM_Odm,0xa01) | BIT(7)); // CCK HW control ++ ODM_Write4Byte(pDM_Odm,0x80c, ODM_Read4Byte(pDM_Odm,0x80c) | BIT(21) ); // by tx desc ++ priv->pshare->rf_ft_var.CurAntenna = 0; ++ ODM_Write4Byte(pDM_Odm,0x858, 0x569a569a); ++ priv->pshare->rf_ft_var.antHw_enable = 1; ++#ifdef SW_ANT_SWITCH ++ priv->pshare->rf_ft_var.antSw_enable = 0; ++ priv->pshare->RSSI_test =0; ++#endif ++ } ++#ifdef SW_ANT_SWITCH ++ else if(ant==3) { ++ if(!priv->pshare->rf_ft_var.antSw_enable) { ++ ++ dm_SW_AntennaSwitchInit(priv); ++ ODM_Write4Byte(pDM_Odm,0x858, 0x569a569a); ++ priv->pshare->lastTxOkCnt = priv->net_stats.tx_bytes; ++ priv->pshare->lastRxOkCnt = priv->net_stats.rx_bytes; ++ } ++ if ( !priv->pshare->rf_ft_var.antSw_select) ++ ODM_Write1Byte(pDM_Odm,0xc50, ODM_Read1Byte(pDM_Odm,0xc50) & (~ BIT(7))); // rx OFDM SW control ++ else ++ ODM_Write1Byte(pDM_Odm,0xc58, ODM_Read1Byte(pDM_Odm,0xc58) & (~ BIT(7))); // rx OFDM SW control ++ ++ ODM_Write1Byte(pDM_Odm,0xa01, ODM_Read1Byte(pDM_Odm,0xa01) & (~ BIT(7))); // rx CCK SW control ++ ODM_Write4Byte(pDM_Odm,0x80c, ODM_Read4Byte(pDM_Odm,0x80c) & (~ BIT(21))); // select ant by tx desc ++ priv->pshare->rf_ft_var.antHw_enable = 0; ++ priv->pshare->rf_ft_var.antSw_enable = 1; ++ ++ } ++#endif ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("<==============ODM_Diversity_AntennaSelect\n")); ++ ++ return 1; ++} ++#endif ++ ++#else //#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) ++ ++VOID odm_InitHybridAntDiv( IN PDM_ODM_T pDM_Odm ){} ++VOID odm_HwAntDiv( IN PDM_ODM_T pDM_Odm){} ++#if(DM_ODM_SUPPORT_TYPE==ODM_MP) ++VOID ODM_SetTxAntByTxInfo_88C_92D( ++ IN PDM_ODM_T pDM_Odm, ++ IN pu1Byte pDesc, ++ IN u1Byte macId ++){} ++#elif(DM_ODM_SUPPORT_TYPE==ODM_CE) ++VOID ODM_SetTxAntByTxInfo_88C_92D( IN PDM_ODM_T pDM_Odm){ } ++#elif(DM_ODM_SUPPORT_TYPE==ODM_AP) ++VOID ODM_SetTxAntByTxInfo_88C_92D( IN PDM_ODM_T pDM_Odm){ } ++#endif ++ ++#endif //#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) ++ ++ ++ ++//============================================================ ++//EDCA Turbo ++//============================================================ ++VOID ++ODM_EdcaTurboInit( ++ IN PDM_ODM_T pDM_Odm) ++{ ++ ++#if ((DM_ODM_SUPPORT_TYPE == ODM_AP)||(DM_ODM_SUPPORT_TYPE==ODM_ADSL)) ++ odm_EdcaParaInit(pDM_Odm); ++#elif (DM_ODM_SUPPORT_TYPE==ODM_MP) ++ PADAPTER Adapter = NULL; ++ HAL_DATA_TYPE *pHalData = NULL; ++ ++ if(pDM_Odm->Adapter==NULL) { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("EdcaTurboInit fail!!!\n")); ++ return; ++ } ++ ++ Adapter=pDM_Odm->Adapter; ++ pHalData=GET_HAL_DATA(Adapter); ++ ++ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = FALSE; ++ pDM_Odm->DM_EDCA_Table.bIsCurRDLState = FALSE; ++ pHalData->bIsAnyNonBEPkts = FALSE; ++ ++#elif(DM_ODM_SUPPORT_TYPE==ODM_CE) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = FALSE; ++ pDM_Odm->DM_EDCA_Table.bIsCurRDLState = FALSE; ++ Adapter->recvpriv.bIsAnyNonBEPkts =FALSE; ++ ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Orginial VO PARAM: 0x%x\n",ODM_Read4Byte(pDM_Odm,ODM_EDCA_VO_PARAM))); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Orginial VI PARAM: 0x%x\n",ODM_Read4Byte(pDM_Odm,ODM_EDCA_VI_PARAM))); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Orginial BE PARAM: 0x%x\n",ODM_Read4Byte(pDM_Odm,ODM_EDCA_BE_PARAM))); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Orginial BK PARAM: 0x%x\n",ODM_Read4Byte(pDM_Odm,ODM_EDCA_BK_PARAM))); ++ ++ ++} // ODM_InitEdcaTurbo ++ ++VOID ++odm_EdcaTurboCheck( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ // ++ // For AP/ADSL use prtl8192cd_priv ++ // For CE/NIC use PADAPTER ++ // ++ PADAPTER pAdapter = pDM_Odm->Adapter; ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ ++ // ++ // 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate ++ // at the same time. In the stage2/3, we need to prive universal interface and merge all ++ // HW dynamic mechanism. ++ // ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("odm_EdcaTurboCheck========================>\n")); ++ ++ if(!(pDM_Odm->SupportAbility& ODM_MAC_EDCA_TURBO )) ++ return; ++ ++ switch (pDM_Odm->SupportPlatform) ++ { ++ case ODM_MP: ++ ++#if(DM_ODM_SUPPORT_TYPE==ODM_MP) ++ odm_EdcaTurboCheckMP(pDM_Odm); ++#endif ++ break; ++ ++ case ODM_CE: ++#if(DM_ODM_SUPPORT_TYPE==ODM_CE) ++ odm_EdcaTurboCheckCE(pDM_Odm); ++#endif ++ break; ++ ++ case ODM_AP: ++ case ODM_ADSL: ++ ++#if ((DM_ODM_SUPPORT_TYPE == ODM_AP)||(DM_ODM_SUPPORT_TYPE==ODM_ADSL)) ++ odm_IotEngine(pDM_Odm); ++#endif ++ break; ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("<========================odm_EdcaTurboCheck\n")); ++ ++} // odm_CheckEdcaTurbo ++ ++#if(DM_ODM_SUPPORT_TYPE==ODM_CE) ++ ++ ++VOID ++odm_EdcaTurboCheckCE( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ ++#if(DM_ODM_SUPPORT_TYPE==ODM_CE) ++ ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ ++ u32 trafficIndex; ++ u32 edca_param; ++ u64 cur_tx_bytes = 0; ++ u64 cur_rx_bytes = 0; ++ u8 bbtchange = _FALSE; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv); ++ struct recv_priv *precvpriv = &(Adapter->recvpriv); ++ struct registry_priv *pregpriv = &Adapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &(Adapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ ++ if ((pregpriv->wifi_spec == 1) )//|| (pmlmeinfo->HT_enable == 0)) ++ { ++ goto dm_CheckEdcaTurbo_EXIT; ++ } ++ ++ if (pmlmeinfo->assoc_AP_vendor >= HT_IOT_PEER_MAX) ++ { ++ goto dm_CheckEdcaTurbo_EXIT; ++ } ++ ++#ifdef CONFIG_BT_COEXIST ++ if (BT_DisableEDCATurbo(Adapter)) ++ { ++ goto dm_CheckEdcaTurbo_EXIT; ++ } ++#endif ++ ++ // Check if the status needs to be changed. ++ if((bbtchange) || (!precvpriv->bIsAnyNonBEPkts) ) ++ { ++ cur_tx_bytes = pxmitpriv->tx_bytes - pxmitpriv->last_tx_bytes; ++ cur_rx_bytes = precvpriv->rx_bytes - precvpriv->last_rx_bytes; ++ ++ //traffic, TX or RX ++ if((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_RALINK)||(pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS)) ++ { ++ if (cur_tx_bytes > (cur_rx_bytes << 2)) ++ { // Uplink TP is present. ++ trafficIndex = UP_LINK; ++ } ++ else ++ { // Balance TP is present. ++ trafficIndex = DOWN_LINK; ++ } ++ } ++ else ++ { ++ if (cur_rx_bytes > (cur_tx_bytes << 2)) ++ { // Downlink TP is present. ++ trafficIndex = DOWN_LINK; ++ } ++ else ++ { // Balance TP is present. ++ trafficIndex = UP_LINK; ++ } ++ } ++ ++ if ((pDM_Odm->DM_EDCA_Table.prv_traffic_idx != trafficIndex) || (!pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA)) ++ { ++ ++#if 0 ++ //adjust EDCA parameter for BE queue ++ edca_param = EDCAParam[pmlmeinfo->assoc_AP_vendor][trafficIndex]; ++#else ++ ++ if((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_CISCO) && (pmlmeext->cur_wireless_mode & WIRELESS_11_24N)) ++ { ++ edca_param = EDCAParam[pmlmeinfo->assoc_AP_vendor][trafficIndex]; ++ } ++ else ++ { ++ edca_param = EDCAParam[HT_IOT_PEER_UNKNOWN][trafficIndex]; ++ } ++#endif ++ ++#ifdef CONFIG_PCI_HCI ++ if(IS_92C_SERIAL(pHalData->VersionID)) ++ { ++ edca_param = 0x60a42b; ++ } ++ else ++ { ++ edca_param = 0x6ea42b; ++ } ++#endif ++ rtw_write32(Adapter, REG_EDCA_BE_PARAM, edca_param); ++ ++ pDM_Odm->DM_EDCA_Table.prv_traffic_idx = trafficIndex; ++ } ++ ++ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = _TRUE; ++ } ++ else ++ { ++ // ++ // Turn Off EDCA turbo here. ++ // Restore original EDCA according to the declaration of AP. ++ // ++ if(pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA) ++ { ++ rtw_write32(Adapter, REG_EDCA_BE_PARAM, pHalData->AcParam_BE); ++ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = _FALSE; ++ } ++ } ++ ++dm_CheckEdcaTurbo_EXIT: ++ // Set variables for next time. ++ precvpriv->bIsAnyNonBEPkts = _FALSE; ++ pxmitpriv->last_tx_bytes = pxmitpriv->tx_bytes; ++ precvpriv->last_rx_bytes = precvpriv->rx_bytes; ++#endif ++} ++ ++ ++#elif(DM_ODM_SUPPORT_TYPE==ODM_MP) ++VOID ++odm_EdcaTurboCheckMP( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ ++ ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++#if(DM_ODM_SUPPORT_TYPE==ODM_MP) ++ PADAPTER pDefaultAdapter = GetDefaultAdapter(Adapter); ++ PADAPTER pExtAdapter = GetFirstExtAdapter(Adapter);//NULL; ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ PSTA_QOS pStaQos = Adapter->MgntInfo.pStaQos; ++ //[Win7 Count Tx/Rx statistic for Extension Port] odm_CheckEdcaTurbo's Adapter is always Default. 2009.08.20, by Bohn ++ u8Byte Ext_curTxOkCnt = 0; ++ u8Byte Ext_curRxOkCnt = 0; ++ static u8Byte Ext_lastTxOkCnt = 0; ++ static u8Byte Ext_lastRxOkCnt = 0; ++ //For future Win7 Enable Default Port to modify AMPDU size dynamically, 2009.08.20, Bohn. ++ u1Byte TwoPortStatus = (u1Byte)TWO_PORT_STATUS__WITHOUT_ANY_ASSOCIATE; ++ ++#elif (DM_ODM_SUPPORT_TYPE==ODM_CE) ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv); ++ struct recv_priv *precvpriv = &(Adapter->recvpriv); ++ struct registry_priv *pregpriv = &Adapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &(Adapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ #ifdef CONFIG_BT_COEXIST ++ struct btcoexist_priv *pbtpriv = &(pHalData->bt_coexist); ++ #endif ++ u1Byte bbtchange =FALSE; ++#endif ++ // Keep past Tx/Rx packet count for RT-to-RT EDCA turbo. ++ u8Byte curTxOkCnt = 0; ++ u8Byte curRxOkCnt = 0; ++ u8Byte lastTxOkCnt = 0; ++ u8Byte lastRxOkCnt = 0; ++ u4Byte EDCA_BE_UL = 0x5ea42b;//Parameter suggested by Scott //edca_setting_UL[pMgntInfo->IOTPeer]; ++ u4Byte EDCA_BE_DL = 0x5ea42b;//Parameter suggested by Scott //edca_setting_DL[pMgntInfo->IOTPeer]; ++ u4Byte EDCA_BE = 0x5ea42b; ++ u4Byte IOTPeer=0; ++ BOOLEAN *pbIsCurRDLState=NULL; ++ BOOLEAN bLastIsCurRDLState=FALSE; ++ BOOLEAN bBiasOnRx=FALSE; ++ BOOLEAN bEdcaTurboOn=FALSE; ++ ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("odm_EdcaTurboCheckMP========================>")); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Orginial BE PARAM: 0x%x\n",ODM_Read4Byte(pDM_Odm,ODM_EDCA_BE_PARAM))); ++ ++////=============================== ++////list paramter for different platform ++////=============================== ++ bLastIsCurRDLState=pDM_Odm->DM_EDCA_Table.bIsCurRDLState; ++ pbIsCurRDLState=&(pDM_Odm->DM_EDCA_Table.bIsCurRDLState); ++#if (DM_ODM_SUPPORT_TYPE==ODM_MP) ++ // Caculate TX/RX TP: ++ curTxOkCnt = Adapter->TxStats.NumTxBytesUnicast - pMgntInfo->lastTxOkCnt; ++ curRxOkCnt = Adapter->RxStats.NumRxBytesUnicast - pMgntInfo->lastRxOkCnt; ++ if(pExtAdapter == NULL) ++ pExtAdapter = pDefaultAdapter; ++ ++ Ext_curTxOkCnt = pExtAdapter->TxStats.NumTxBytesUnicast - pMgntInfo->Ext_lastTxOkCnt; ++ Ext_curRxOkCnt = pExtAdapter->RxStats.NumRxBytesUnicast - pMgntInfo->Ext_lastRxOkCnt; ++ GetTwoPortSharedResource(Adapter,TWO_PORT_SHARED_OBJECT__STATUS,NULL,&TwoPortStatus); ++ //For future Win7 Enable Default Port to modify AMPDU size dynamically, 2009.08.20, Bohn. ++ if(TwoPortStatus == TWO_PORT_STATUS__EXTENSION_ONLY) ++ { ++ curTxOkCnt = Ext_curTxOkCnt ; ++ curRxOkCnt = Ext_curRxOkCnt ; ++ } ++ // ++ IOTPeer=pMgntInfo->IOTPeer; ++ bBiasOnRx=(pMgntInfo->IOTAction & HT_IOT_ACT_EDCA_BIAS_ON_RX)?TRUE:FALSE; ++ bEdcaTurboOn=((!pHalData->bIsAnyNonBEPkts) && (!pMgntInfo->bDisableFrameBursting))?TRUE:FALSE; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("bIsAnyNonBEPkts : 0x%lx bDisableFrameBursting : 0x%lx \n",pHalData->bIsAnyNonBEPkts,pMgntInfo->bDisableFrameBursting)); ++ ++#elif(DM_ODM_SUPPORT_TYPE==ODM_CE) ++ // Caculate TX/RX TP: ++ curTxOkCnt = pxmitpriv->tx_bytes - pxmitpriv->last_tx_bytes; ++ curRxOkCnt = precvpriv->rx_bytes - precvpriv->last_rx_bytes; ++ #ifdef CONFIG_BT_COEXIST ++ if(pbtpriv->BT_Coexist) ++ { ++ if( (pbtpriv->BT_EDCA[UP_LINK]!=0) || (pbtpriv->BT_EDCA[DOWN_LINK]!=0)) ++ bbtchange = TRUE; ++ } ++ #endif ++ IOTPeer=pmlmeinfo->assoc_AP_vendor; ++ bBiasOnRx=((IOTPeer == HT_IOT_PEER_RALINK)||(IOTPeer == HT_IOT_PEER_ATHEROS))?TRUE:FALSE; ++ bEdcaTurboOn=(bbtchange || (!precvpriv->bIsAnyNonBEPkts))?TRUE:FALSE; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("bbtchange : 0x%lx bIsAnyNonBEPkts : 0x%lx \n",bbtchange,precvpriv->bIsAnyNonBEPkts)); ++#endif ++ ++ ++////=============================== ++////check if edca turbo is disabled ++////=============================== ++ if(odm_IsEdcaTurboDisable(pDM_Odm)) ++ goto dm_CheckEdcaTurbo_EXIT; ++ ++ ++////=============================== ++////remove iot case out ++////=============================== ++ ODM_EdcaParaSelByIot(pDM_Odm, &EDCA_BE_UL, &EDCA_BE_DL); ++ ++ ++////=============================== ++////Check if the status needs to be changed. ++////=============================== ++ if(bEdcaTurboOn) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("bEdcaTurboOn : 0x%x bBiasOnRx : 0x%x\n",bEdcaTurboOn,bBiasOnRx)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("curTxOkCnt : 0x%lx \n",curTxOkCnt)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("curRxOkCnt : 0x%lx \n",curRxOkCnt)); ++ if(bBiasOnRx) ++ odm_EdcaChooseTrafficIdx(pDM_Odm,curTxOkCnt, curRxOkCnt, TRUE, pbIsCurRDLState); ++ else ++ odm_EdcaChooseTrafficIdx(pDM_Odm,curTxOkCnt, curRxOkCnt, FALSE, pbIsCurRDLState); ++ ++//modify by Guo.Mingzhi 2011-12-29 ++ EDCA_BE=((*pbIsCurRDLState)==TRUE)?EDCA_BE_DL:EDCA_BE_UL; ++ ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,EDCA_BE); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("EDCA Turbo on: EDCA_BE:0x%lx\n",EDCA_BE)); ++ ++// if(((*pbIsCurRDLState)!=bLastIsCurRDLState)||(!pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA)) ++// { ++// EDCA_BE=((*pbIsCurRDLState)==TRUE)?EDCA_BE_DL:EDCA_BE_UL; ++// ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,EDCA_BE); ++ // } ++ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = TRUE; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("EDCA_BE_DL : 0x%lx EDCA_BE_UL : 0x%lx EDCA_BE : 0x%lx \n",EDCA_BE_DL,EDCA_BE_UL,EDCA_BE)); ++ ++ } ++ else ++ { ++ // Turn Off EDCA turbo here. ++ // Restore original EDCA according to the declaration of AP. ++ if(pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA) ++ { ++#if (DM_ODM_SUPPORT_TYPE==ODM_MP) ++ Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_AC_PARAM, GET_WMM_PARAM_ELE_SINGLE_AC_PARAM(pStaQos->WMMParamEle, AC0_BE) ); ++#elif(DM_ODM_SUPPORT_TYPE==ODM_CE) ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, pHalData->AcParam_BE); ++#endif ++ ++ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = FALSE; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Restore EDCA BE: 0x%lx \n",pDM_Odm->WMMEDCA_BE)); ++ ++ } ++ } ++ ++////=============================== ++////Set variables for next time. ++////=============================== ++dm_CheckEdcaTurbo_EXIT: ++#if (DM_ODM_SUPPORT_TYPE==ODM_MP) ++ pHalData->bIsAnyNonBEPkts = FALSE; ++ pMgntInfo->lastTxOkCnt = Adapter->TxStats.NumTxBytesUnicast; ++ pMgntInfo->lastRxOkCnt = Adapter->RxStats.NumRxBytesUnicast; ++ pMgntInfo->Ext_lastTxOkCnt = pExtAdapter->TxStats.NumTxBytesUnicast; ++ pMgntInfo->Ext_lastRxOkCnt = pExtAdapter->RxStats.NumRxBytesUnicast; ++#elif (DM_ODM_SUPPORT_TYPE==ODM_CE) ++ precvpriv->bIsAnyNonBEPkts = FALSE; ++ pxmitpriv->last_tx_bytes = pxmitpriv->tx_bytes; ++ precvpriv->last_rx_bytes = precvpriv->rx_bytes; ++#endif ++ ++} ++ ++ ++//check if edca turbo is disabled ++BOOLEAN ++odm_IsEdcaTurboDisable( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++#if(DM_ODM_SUPPORT_TYPE==ODM_MP) ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ u4Byte IOTPeer=pMgntInfo->IOTPeer; ++#elif (DM_ODM_SUPPORT_TYPE==ODM_CE) ++ struct registry_priv *pregpriv = &Adapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &(Adapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u4Byte IOTPeer=pmlmeinfo->assoc_AP_vendor; ++ u1Byte WirelessMode=0xFF; //invalid value ++ ++ if(pDM_Odm->pWirelessMode!=NULL) ++ WirelessMode=*(pDM_Odm->pWirelessMode); ++ ++#endif ++ ++#if(BT_30_SUPPORT == 1) ++ if(pDM_Odm->bBtDisableEdcaTurbo) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD, ("EdcaTurboDisable for BT!!\n")); ++ return TRUE; ++ } ++#endif ++ ++ if((!(pDM_Odm->SupportAbility& ODM_MAC_EDCA_TURBO ))|| ++ (pDM_Odm->bWIFITest)|| ++ (IOTPeer>= HT_IOT_PEER_MAX)) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD, ("EdcaTurboDisable\n")); ++ return TRUE; ++ } ++ ++ ++#if (DM_ODM_SUPPORT_TYPE ==ODM_MP) ++ // 1. We do not turn on EDCA turbo mode for some AP that has IOT issue ++ // 2. User may disable EDCA Turbo mode with OID settings. ++ if((pMgntInfo->IOTAction & HT_IOT_ACT_DISABLE_EDCA_TURBO) ||pHalData->bForcedDisableTurboEDCA){ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD, ("IOTAction:EdcaTurboDisable\n")); ++ return TRUE; ++ } ++ ++#elif(DM_ODM_SUPPORT_TYPE==ODM_CE) ++ //suggested by Jr.Luke: open TXOP for B/G/BG/A mode 2012-0215 ++ if((WirelessMode==ODM_WM_B)||(WirelessMode==(ODM_WM_B|ODM_WM_G)||(WirelessMode==ODM_WM_G)||(WirelessMode=ODM_WM_A)) ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, ODM_Read4Byte(pDM_Odm, ODM_EDCA_BE_PARAM)|0x5E0000); ++ ++ if(pDM_Odm->SupportICType==ODM_RTL8192D) { ++ if ((pregpriv->wifi_spec == 1) || (pmlmeext->cur_wireless_mode == WIRELESS_11B)) { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD, ("92D:EdcaTurboDisable\n")); ++ return TRUE; ++ } ++ } ++ else ++ { ++ if((pregpriv->wifi_spec == 1) || (pmlmeinfo->HT_enable == 0)){ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD, ("Others:EdcaTurboDisable\n")); ++ return TRUE; ++ } ++ } ++#ifdef CONFIG_BT_COEXIST ++ if (BT_DisableEDCATurbo(Adapter)) ++ { ++ goto dm_CheckEdcaTurbo_EXIT; ++ } ++#endif ++ ++#endif ++ ++ return FALSE; ++ ++ ++} ++ ++//add iot case here: for MP/CE ++VOID ++ODM_EdcaParaSelByIot( ++ IN PDM_ODM_T pDM_Odm, ++ OUT u4Byte *EDCA_BE_UL, ++ OUT u4Byte *EDCA_BE_DL ++ ) ++{ ++ ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u4Byte IOTPeer=0; ++ u4Byte ICType=pDM_Odm->SupportICType; ++ u1Byte WirelessMode=0xFF; //invalid value ++ u4Byte RFType=pDM_Odm->RFType; ++ ++#if(DM_ODM_SUPPORT_TYPE==ODM_MP) ++ PADAPTER pDefaultAdapter = GetDefaultAdapter(Adapter); ++ PADAPTER pExtAdapter = GetFirstExtAdapter(Adapter);//NULL; ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ u1Byte TwoPortStatus = (u1Byte)TWO_PORT_STATUS__WITHOUT_ANY_ASSOCIATE; ++ ++#elif(DM_ODM_SUPPORT_TYPE==ODM_CE) ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ #ifdef CONFIG_BT_COEXIST ++ struct btcoexist_priv *pbtpriv = &(pHalData->bt_coexist); ++ #endif ++ u1Byte bbtchange =FALSE; ++#endif ++ ++ if(pDM_Odm->pWirelessMode!=NULL) ++ WirelessMode=*(pDM_Odm->pWirelessMode); ++ ++/////////////////////////////////////////////////////////// ++////list paramter for different platform ++#if (DM_ODM_SUPPORT_TYPE==ODM_MP) ++ IOTPeer=pMgntInfo->IOTPeer; ++ GetTwoPortSharedResource(Adapter,TWO_PORT_SHARED_OBJECT__STATUS,NULL,&TwoPortStatus); ++ ++#elif(DM_ODM_SUPPORT_TYPE==ODM_CE) ++ IOTPeer=pmlmeinfo->assoc_AP_vendor; ++ #ifdef CONFIG_BT_COEXIST ++ if(pbtpriv->BT_Coexist) ++ { ++ if( (pbtpriv->BT_EDCA[UP_LINK]!=0) || (pbtpriv->BT_EDCA[DOWN_LINK]!=0)) ++ bbtchange = TRUE; ++ } ++ #endif ++ ++#endif ++ ++ if(ICType==ODM_RTL8192D) ++ { ++ // Single PHY ++ if(pDM_Odm->RFType==ODM_2T2R) ++ { ++ (*EDCA_BE_UL) = 0x60a42b; //0x5ea42b; ++ (*EDCA_BE_DL) = 0x60a42b; //0x5ea42b; ++ ++ } ++ else ++ { ++ (*EDCA_BE_UL) = 0x6ea42b; ++ (*EDCA_BE_DL) = 0x6ea42b; ++ } ++ ++ } ++////============================ ++/// IOT case for MP ++////============================ ++#if (DM_ODM_SUPPORT_TYPE==ODM_MP) ++ else ++ { ++ ++ if(pDM_Odm->SupportInterface==ODM_ITRF_PCIE){ ++ if((ICType==ODM_RTL8192C)&&(pDM_Odm->RFType==ODM_2T2R)) { ++ (*EDCA_BE_UL) = 0x60a42b; ++ (*EDCA_BE_DL) = 0x60a42b; ++ } ++ else ++ { ++ (*EDCA_BE_UL) = 0x6ea42b; ++ (*EDCA_BE_DL) = 0x6ea42b; ++ } ++ } ++ } ++ ++ if(TwoPortStatus == TWO_PORT_STATUS__EXTENSION_ONLY) ++ { ++ (*EDCA_BE_UL) = 0x5ea42b;//Parameter suggested by Scott //edca_setting_UL[ExtAdapter->MgntInfo.IOTPeer]; ++ (*EDCA_BE_DL) = 0x5ea42b;//Parameter suggested by Scott //edca_setting_DL[ExtAdapter->MgntInfo.IOTPeer]; ++ } ++ ++ #if (INTEL_PROXIMITY_SUPPORT == 1) ++ if(pMgntInfo->IntelClassModeInfo.bEnableCA == TRUE) ++ { ++ (*EDCA_BE_UL) = (*EDCA_BE_DL) = 0xa44f; ++ } ++ else ++ #endif ++ { ++ if((!pMgntInfo->bDisableFrameBursting) && ++ (pMgntInfo->IOTAction & (HT_IOT_ACT_FORCED_ENABLE_BE_TXOP|HT_IOT_ACT_AMSDU_ENABLE))) ++ {// To check whether we shall force turn on TXOP configuration. ++ if(!((*EDCA_BE_UL) & 0xffff0000)) ++ (*EDCA_BE_UL) |= 0x005e0000; // Force TxOP limit to 0x005e for UL. ++ if(!((*EDCA_BE_DL) & 0xffff0000)) ++ (*EDCA_BE_DL) |= 0x005e0000; // Force TxOP limit to 0x005e for DL. ++ } ++ ++ //92D txop can't be set to 0x3e for cisco1250 ++ if((ICType!=ODM_RTL8192D) && (IOTPeer== HT_IOT_PEER_CISCO) &&(WirelessMode==ODM_WM_N24G)) ++ { ++ (*EDCA_BE_DL) = edca_setting_DL[IOTPeer]; ++ (*EDCA_BE_UL) = edca_setting_UL[IOTPeer]; ++ } ++ //merge from 92s_92c_merge temp brunch v2445 20120215 ++ else if((IOTPeer == HT_IOT_PEER_CISCO) &&((WirelessMode==ODM_WM_G)||(WirelessMode==ODM_WM_A)||(WirelessMode==ODM_WM_B))) ++ { ++ (*EDCA_BE_DL) = edca_setting_DL_GMode[IOTPeer]; ++ } ++ else if((IOTPeer== HT_IOT_PEER_AIRGO )&& ((WirelessMode==ODM_WM_G)||(WirelessMode==ODM_WM_A))) ++ { ++ (*EDCA_BE_DL) = 0xa630; ++ } ++ ++ else if(IOTPeer == HT_IOT_PEER_MARVELL) ++ { ++ (*EDCA_BE_DL) = edca_setting_DL[IOTPeer]; ++ (*EDCA_BE_UL) = edca_setting_UL[IOTPeer]; ++ } ++ else if(IOTPeer == HT_IOT_PEER_ATHEROS) ++ { ++ // Set DL EDCA for Atheros peer to 0x3ea42b. Suggested by SD3 Wilson for ASUS TP issue. ++ (*EDCA_BE_DL) = edca_setting_DL[IOTPeer]; ++ } ++ } ++////============================ ++/// IOT case for CE ++////============================ ++#elif (DM_ODM_SUPPORT_TYPE==ODM_CE) ++ ++ if(RFType==ODM_RTL8192D) ++ { ++ if((IOTPeer == HT_IOT_PEER_CISCO) &&(WirelessMode==ODM_WM_N24G)) ++ { ++ (*EDCA_BE_UL) = EDCAParam[IOTPeer][UP_LINK]; ++ (*EDCA_BE_DL)=EDCAParam[IOTPeer][DOWN_LINK]; ++ } ++ else if((IOTPeer == HT_IOT_PEER_AIRGO) && ++ ((WirelessMode==ODM_WM_B)||(WirelessMode==(ODM_WM_B|ODM_WM_G)))) ++ (*EDCA_BE_DL)=0x00a630; ++ ++ else if((IOTPeer== HT_IOT_PEER_ATHEROS) && ++ (WirelessMode&ODM_WM_N5G) && ++ (Adapter->securitypriv.dot11PrivacyAlgrthm == _AES_ )) ++ (*EDCA_BE_DL)=0xa42b; ++ ++ } ++ //92C IOT case: ++ else ++ { ++ #ifdef CONFIG_BT_COEXIST ++ if(bbtchange) ++ { ++ (*EDCA_BE_UL) = pbtpriv->BT_EDCA[UP_LINK]; ++ (*EDCA_BE_DL) = pbtpriv->BT_EDCA[DOWN_LINK]; ++ } ++ else ++ #endif ++ { ++ if((IOTPeer == HT_IOT_PEER_CISCO) &&(WirelessMode==ODM_WM_N24G)) ++ { ++ (*EDCA_BE_UL) = EDCAParam[IOTPeer][UP_LINK]; ++ (*EDCA_BE_DL)=EDCAParam[IOTPeer][DOWN_LINK]; ++ } ++ else ++ { ++ (*EDCA_BE_UL)=EDCAParam[HT_IOT_PEER_UNKNOWN][UP_LINK]; ++ (*EDCA_BE_DL)=EDCAParam[HT_IOT_PEER_UNKNOWN][DOWN_LINK]; ++ } ++ } ++ if(pDM_Odm->SupportInterface==ODM_ITRF_PCIE){ ++ if((ICType==ODM_RTL8192C)&&(pDM_Odm->RFType==ODM_2T2R)) ++ { ++ (*EDCA_BE_UL) = 0x60a42b; ++ (*EDCA_BE_DL) = 0x60a42b; ++ } ++ else ++ { ++ (*EDCA_BE_UL) = 0x6ea42b; ++ (*EDCA_BE_DL) = 0x6ea42b; ++ } ++ } ++ ++ } ++#endif ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Special: EDCA_BE_UL=0x%lx EDCA_BE_DL =0x%lx",(*EDCA_BE_UL),(*EDCA_BE_DL))); ++ ++} ++ ++ ++VOID ++odm_EdcaChooseTrafficIdx( ++ IN PDM_ODM_T pDM_Odm, ++ IN u8Byte cur_tx_bytes, ++ IN u8Byte cur_rx_bytes, ++ IN BOOLEAN bBiasOnRx, ++ OUT BOOLEAN *pbIsCurRDLState ++ ) ++{ ++ ++ ++ if(bBiasOnRx) ++ { ++ ++ if(cur_tx_bytes>(cur_rx_bytes*4)) ++ { ++ *pbIsCurRDLState=FALSE; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Uplink Traffic\n ")); ++ ++ } ++ else ++ { ++ *pbIsCurRDLState=TRUE; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Balance Traffic\n")); ++ ++ } ++ } ++ else ++ { ++ if(cur_rx_bytes>(cur_tx_bytes*4)) ++ { ++ *pbIsCurRDLState=TRUE; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Downlink Traffic\n")); ++ ++ } ++ else ++ { ++ *pbIsCurRDLState=FALSE; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Balance Traffic\n")); ++ } ++ } ++ ++ return ; ++} ++ ++#endif ++ ++#if((DM_ODM_SUPPORT_TYPE==ODM_AP)||(DM_ODM_SUPPORT_TYPE==ODM_ADSL)) ++ ++void odm_EdcaParaInit( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ int mode=priv->pmib->dot11BssType.net_work_type; ++ ++ static unsigned int slot_time, VO_TXOP, VI_TXOP, sifs_time; ++ struct ParaRecord EDCA[4]; ++ ++ memset(EDCA, 0, 4*sizeof(struct ParaRecord)); ++ ++ sifs_time = 10; ++ slot_time = 20; ++ ++ if (mode & (ODM_WM_N24G|ODM_WM_N5G)) ++ sifs_time = 16; ++ ++ if (mode & (ODM_WM_N24G|ODM_WM_N5G| ODM_WM_G|ODM_WM_A)) ++ slot_time = 9; ++ ++ ++#if((defined(RTL_MANUAL_EDCA))&&(DM_ODM_SUPPORT_TYPE==ODM_AP)) ++ if( priv->pmib->dot11QosEntry.ManualEDCA ) { ++ if( OPMODE & WIFI_AP_STATE ) ++ memcpy(EDCA, priv->pmib->dot11QosEntry.AP_manualEDCA, 4*sizeof(struct ParaRecord)); ++ else ++ memcpy(EDCA, priv->pmib->dot11QosEntry.STA_manualEDCA, 4*sizeof(struct ParaRecord)); ++ ++ #ifdef WIFI_WMM ++ if (QOS_ENABLE) ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_VI_PARAM, (EDCA[VI].TXOPlimit<< 16) | (EDCA[VI].ECWmax<< 12) | (EDCA[VI].ECWmin<< 8) | (sifs_time + EDCA[VI].AIFSN* slot_time)); ++ else ++ #endif ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_VI_PARAM, (EDCA[BE].TXOPlimit<< 16) | (EDCA[BE].ECWmax<< 12) | (EDCA[BE].ECWmin<< 8) | (sifs_time + EDCA[VI].AIFSN* slot_time)); ++ ++ }else ++ #endif //RTL_MANUAL_EDCA ++ { ++ ++ if(OPMODE & WIFI_AP_STATE) ++ { ++ memcpy(EDCA, rtl_ap_EDCA, 2*sizeof(struct ParaRecord)); ++ ++ if(mode & (ODM_WM_A|ODM_WM_G|ODM_WM_N24G|ODM_WM_N5G)) ++ memcpy(&EDCA[VI], &rtl_ap_EDCA[VI_AG], 2*sizeof(struct ParaRecord)); ++ else ++ memcpy(&EDCA[VI], &rtl_ap_EDCA[VI], 2*sizeof(struct ParaRecord)); ++ } ++ else ++ { ++ memcpy(EDCA, rtl_sta_EDCA, 2*sizeof(struct ParaRecord)); ++ ++ if(mode & (ODM_WM_A|ODM_WM_G|ODM_WM_N24G|ODM_WM_N5G)) ++ memcpy(&EDCA[VI], &rtl_sta_EDCA[VI_AG], 2*sizeof(struct ParaRecord)); ++ else ++ memcpy(&EDCA[VI], &rtl_sta_EDCA[VI], 2*sizeof(struct ParaRecord)); ++ } ++ ++ #ifdef WIFI_WMM ++ if (QOS_ENABLE) ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_VI_PARAM, (EDCA[VI].TXOPlimit<< 16) | (EDCA[VI].ECWmax<< 12) | (EDCA[VI].ECWmin<< 8) | (sifs_time + EDCA[VI].AIFSN* slot_time)); ++ else ++ #endif ++ ++#if (DM_ODM_SUPPORT_TYPE==ODM_AP) ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_VI_PARAM, (EDCA[BK].ECWmax<< 12) | (EDCA[BK].ECWmin<< 8) | (sifs_time + EDCA[VI].AIFSN* slot_time)); ++#elif(DM_ODM_SUPPORT_TYPE==ODM_ADSL) ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_VI_PARAM, (EDCA[BK].ECWmax<< 12) | (EDCA[BK].ECWmin<< 8) | (sifs_time + 2* slot_time)); ++#endif ++ ++ ++ } ++ ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_VO_PARAM, (EDCA[VO].TXOPlimit<< 16) | (EDCA[VO].ECWmax<< 12) | (EDCA[VO].ECWmin<< 8) | (sifs_time + EDCA[VO].AIFSN* slot_time)); ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (EDCA[BE].TXOPlimit<< 16) | (EDCA[BE].ECWmax<< 12) | (EDCA[BE].ECWmin<< 8) | (sifs_time + EDCA[BE].AIFSN* slot_time)); ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_BK_PARAM, (EDCA[BK].TXOPlimit<< 16) | (EDCA[BK].ECWmax<< 12) | (EDCA[BK].ECWmin<< 8) | (sifs_time + EDCA[BK].AIFSN* slot_time)); ++// ODM_Write1Byte(pDM_Odm,ACMHWCTRL, 0x00); ++ ++ priv->pshare->iot_mode_enable = 0; ++#if(DM_ODM_SUPPORT_TYPE==ODM_AP) ++ if (priv->pshare->rf_ft_var.wifi_beq_iot) ++ priv->pshare->iot_mode_VI_exist = 0; ++ ++ #ifdef WMM_VIBE_PRI ++ priv->pshare->iot_mode_BE_exist = 0; ++ #endif ++ ++ #ifdef LOW_TP_TXOP ++ priv->pshare->BE_cwmax_enhance = 0; ++ #endif ++ ++#elif (DM_ODM_SUPPORT_TYPE==ODM_ADSL) ++ priv->pshare->iot_mode_BE_exist = 0; ++#endif ++ priv->pshare->iot_mode_VO_exist = 0; ++} ++ ++BOOLEAN ++ODM_ChooseIotMainSTA( ++ IN PDM_ODM_T pDM_Odm, ++ IN PSTA_INFO_T pstat ++ ) ++{ ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ BOOLEAN bhighTP_found_pstat=FALSE; ++ ++ if ((GET_ROOT(priv)->up_time % 2) == 0) { ++ unsigned int tx_2s_avg = 0; ++ unsigned int rx_2s_avg = 0; ++ int i=0, aggReady=0; ++ unsigned long total_sum = (priv->pshare->current_tx_bytes+priv->pshare->current_rx_bytes); ++ ++ pstat->current_tx_bytes += pstat->tx_byte_cnt; ++ pstat->current_rx_bytes += pstat->rx_byte_cnt; ++ ++ if (total_sum != 0) { ++ if (total_sum <= 100) { ++ tx_2s_avg = (unsigned int)((pstat->current_tx_bytes*100) / total_sum); ++ rx_2s_avg = (unsigned int)((pstat->current_rx_bytes*100) / total_sum); ++ } else { ++ tx_2s_avg = (unsigned int)(pstat->current_tx_bytes / (total_sum / 100)); ++ rx_2s_avg = (unsigned int)(pstat->current_rx_bytes / (total_sum / 100)); ++ } ++ ++ } ++ ++#if(DM_ODM_SUPPORT_TYPE==ODM_ADSL) ++ if (pstat->ht_cap_len) { ++ if ((tx_2s_avg + rx_2s_avg) >=25 /*50*/) { ++ ++ priv->pshare->highTP_found_pstat = pstat; ++ bhighTP_found_pstat=TRUE; ++ } ++ } ++#elif(DM_ODM_SUPPORT_TYPE==ODM_AP) ++ for(i=0; i<8; i++) ++ aggReady += (pstat->ADDBA_ready[i]); ++ if (pstat->ht_cap_len && aggReady) ++ { ++ if ((tx_2s_avg + rx_2s_avg >= 25)) { ++ priv->pshare->highTP_found_pstat = pstat; ++ } ++ ++ #ifdef CLIENT_MODE ++ if (OPMODE & WIFI_STATION_STATE) { ++#if (DM_ODM_SUPPORT_TYPE &ODM_AP) && defined(USE_OUT_SRC) ++ if ((pstat->IOTPeer==HT_IOT_PEER_RALINK) && ((tx_2s_avg + rx_2s_avg) >= 45)) ++#else ++ if(pstat->is_ralink_sta && ((tx_2s_avg + rx_2s_avg) >= 45)) ++#endif ++ priv->pshare->highTP_found_pstat = pstat; ++ } ++ #endif ++ } ++#endif ++ } else { ++ pstat->current_tx_bytes = pstat->tx_byte_cnt; ++ pstat->current_rx_bytes = pstat->rx_byte_cnt; ++ } ++ ++ return bhighTP_found_pstat; ++} ++ ++ ++#ifdef WIFI_WMM ++VOID ++ODM_IotEdcaSwitch( ++ IN PDM_ODM_T pDM_Odm, ++ IN unsigned char enable ++ ) ++{ ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ int mode=priv->pmib->dot11BssType.net_work_type; ++ unsigned int slot_time = 20, sifs_time = 10, BE_TXOP = 47, VI_TXOP = 94; ++ unsigned int vi_cw_max = 4, vi_cw_min = 3, vi_aifs; ++ ++#if (DM_ODM_SUPPORT_TYPE==ODM_AP) ++ if (!(!priv->pmib->dot11OperationEntry.wifi_specific || ++ ((OPMODE & WIFI_AP_STATE) && (priv->pmib->dot11OperationEntry.wifi_specific == 2)) ++ #ifdef CLIENT_MODE ++ || ((OPMODE & WIFI_STATION_STATE) && (priv->pmib->dot11OperationEntry.wifi_specific == 2)) ++ #endif ++ )) ++ return; ++#endif ++ ++ if ((mode & (ODM_WM_N24G|ODM_WM_N5G)) && (priv->pshare->ht_sta_num ++ #ifdef WDS ++ || ((OPMODE & WIFI_AP_STATE) && priv->pmib->dot11WdsInfo.wdsEnabled && priv->pmib->dot11WdsInfo.wdsNum) ++ #endif ++ )) ++ sifs_time = 16; ++ ++ if (mode & (ODM_WM_N24G|ODM_WM_N5G|ODM_WM_G|ODM_WM_A)) { ++ slot_time = 9; ++ } ++ else ++ { ++ BE_TXOP = 94; ++ VI_TXOP = 188; ++ } ++ ++#if (DM_ODM_SUPPORT_TYPE==ODM_ADSL) ++ if (priv->pshare->iot_mode_VO_exist) { ++ // to separate AC_VI and AC_BE to avoid using the same EDCA settings ++ if (priv->pshare->iot_mode_BE_exist) { ++ vi_cw_max = 5; ++ vi_cw_min = 3; ++ } else { ++ vi_cw_max = 6; ++ vi_cw_min = 4; ++ } ++ } ++ vi_aifs = (sifs_time + ((OPMODE & WIFI_AP_STATE)?1:2) * slot_time); ++ ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_VI_PARAM, ((VI_TXOP*(1-priv->pshare->iot_mode_VO_exist)) << 16)| (vi_cw_max << 12) | (vi_cw_min << 8) | vi_aifs); ++ ++ ++#elif (DM_ODM_SUPPORT_TYPE==ODM_AP) ++ if ((OPMODE & WIFI_AP_STATE) && priv->pmib->dot11OperationEntry.wifi_specific) { ++ if (priv->pshare->iot_mode_VO_exist) { ++ #ifdef WMM_VIBE_PRI ++ if (priv->pshare->iot_mode_BE_exist) ++ { ++ vi_cw_max = 5; ++ vi_cw_min = 3; ++ vi_aifs = (sifs_time + ((OPMODE & WIFI_AP_STATE)?1:2) * slot_time); ++ } ++ else ++ #endif ++ { ++ vi_cw_max = 6; ++ vi_cw_min = 4; ++ vi_aifs = 0x2b; ++ } ++ } ++ else { ++ vi_aifs = (sifs_time + ((OPMODE & WIFI_AP_STATE)?1:2) * slot_time); ++ } ++ ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_VI_PARAM, ((VI_TXOP*(1-priv->pshare->iot_mode_VO_exist)) << 16) ++ | (vi_cw_max << 12) | (vi_cw_min << 8) | vi_aifs); ++ } ++#endif ++ ++ ++ ++#if (DM_ODM_SUPPORT_TYPE==ODM_AP) ++ if (priv->pshare->rf_ft_var.wifi_beq_iot && priv->pshare->iot_mode_VI_exist) ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (10 << 12) | (4 << 8) | 0x4f); ++ else if(!enable) ++#elif(DM_ODM_SUPPORT_TYPE==ODM_ADSL) ++ if(!enable) //if iot is disable ,maintain original BEQ PARAM ++#endif ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (((OPMODE & WIFI_AP_STATE)?6:10) << 12) | (4 << 8) ++ | (sifs_time + 3 * slot_time)); ++ else ++ { ++ int txop_enlarge; ++ int txop; ++ unsigned int cw_max; ++ unsigned int txop_close; ++ ++ #if((DM_ODM_SUPPORT_TYPE==ODM_AP)&&(defined LOW_TP_TXOP)) ++ cw_max = ((priv->pshare->BE_cwmax_enhance) ? 10 : 6); ++ txop_close = ((priv->pshare->rf_ft_var.low_tp_txop && priv->pshare->rf_ft_var.low_tp_txop_close) ? 1 : 0); ++ ++ if(priv->pshare->txop_enlarge == 0xe) //if intel case ++ txop = (txop_close ? 0 : (BE_TXOP*2)); ++ else //if other case ++ txop = (txop_close ? 0: (BE_TXOP*priv->pshare->txop_enlarge)); ++ #else ++ cw_max=6; ++ if((priv->pshare->txop_enlarge==0xe)||(priv->pshare->txop_enlarge==0xd)) ++ txop=BE_TXOP*2; ++ else ++ txop=BE_TXOP*priv->pshare->txop_enlarge; ++ ++ #endif ++ ++ if (priv->pshare->ht_sta_num ++ #ifdef WDS ++ || ((OPMODE & WIFI_AP_STATE) && (mode & (ODM_WM_N24G|ODM_WM_N5G)) && ++ priv->pmib->dot11WdsInfo.wdsEnabled && priv->pmib->dot11WdsInfo.wdsNum) ++ #endif ++ ) ++ { ++ ++ if (priv->pshare->txop_enlarge == 0xe) { ++ // is intel client, use a different edca value ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (txop<< 16) | (cw_max<< 12) | (4 << 8) | 0x1f); ++ priv->pshare->txop_enlarge = 2; ++ } ++#if(DM_ODM_SUPPORT_TYPE==ODM_AP) ++ #ifndef LOW_TP_TXOP ++ else if (priv->pshare->txop_enlarge == 0xd) { ++ // is intel ralink, use a different edca value ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (txop << 16) | (4 << 12) | (3 << 8) | 0x19); ++ priv->pshare->txop_enlarge = 2; ++ } ++ #endif ++#endif ++ else ++ { ++ if (pDM_Odm->RFType==ODM_2T2R) ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (txop << 16) | ++ (cw_max << 12) | (4 << 8) | (sifs_time + 3 * slot_time)); ++ else ++ #if(DM_ODM_SUPPORT_TYPE==ODM_AP)&&(defined LOW_TP_TXOP) ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (txop << 16) | ++ (((priv->pshare->BE_cwmax_enhance) ? 10 : 5) << 12) | (3 << 8) | (sifs_time + 2 * slot_time)); ++ #else ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (txop << 16) | ++ (5 << 12) | (3 << 8) | (sifs_time + 2 * slot_time)); ++ ++ #endif ++ } ++ } ++ else ++ { ++ #if((DM_ODM_SUPPORT_TYPE==ODM_AP)&&(defined LOW_TP_TXOP)) ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (BE_TXOP << 16) | (cw_max << 12) | (4 << 8) | (sifs_time + 3 * slot_time)); ++ #else ++ #if defined(CONFIG_RTL_8196D) || defined(CONFIG_RTL_8196E) || (defined(CONFIG_RTL_8197D) && !defined(CONFIG_PORT0_EXT_GIGA)) ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (BE_TXOP*2 << 16) | (cw_max << 12) | (5 << 8) | (sifs_time + 3 * slot_time)); ++ #else ++ ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (BE_TXOP*2 << 16) | (cw_max << 12) | (4 << 8) | (sifs_time + 3 * slot_time)); ++ #endif ++ ++ #endif ++ } ++ ++ } ++} ++#endif ++ ++VOID ++odm_IotEngine( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ ++ struct rtl8192cd_priv *priv=pDM_Odm->priv; ++ PSTA_INFO_T pstat = NULL; ++ u4Byte i; ++ ++#ifdef WIFI_WMM ++ unsigned int switch_turbo = 0; ++#endif ++//////////////////////////////////////////////////////// ++// if EDCA Turbo function is not supported or Manual EDCA Setting ++// then return ++//////////////////////////////////////////////////////// ++ if(!(pDM_Odm->SupportAbility&ODM_MAC_EDCA_TURBO)){ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("ODM_MAC_EDCA_TURBO NOT SUPPORTED\n")); ++ return; ++ } ++ ++#if((DM_ODM_SUPPORT_TYPE==ODM_AP)&& defined(RTL_MANUAL_EDCA) && defined(WIFI_WMM)) ++ if(priv->pmib->dot11QosEntry.ManualEDCA){ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("ODM_MAC_EDCA_TURBO OFF: MANUAL SETTING\n")); ++ return ; ++ } ++#endif ++ ++#if !(DM_ODM_SUPPORT_TYPE &ODM_AP) ++ ////////////////////////////////////////////////////// ++ //find high TP STA every 2s ++////////////////////////////////////////////////////// ++ if ((GET_ROOT(priv)->up_time % 2) == 0) ++ priv->pshare->highTP_found_pstat==NULL; ++ ++#if 0 ++ phead = &priv->asoc_list; ++ plist = phead->next; ++ while(plist != phead) { ++ pstat = list_entry(plist, struct stat_info, asoc_list); ++ ++ if(ODM_ChooseIotMainSTA(pDM_Odm, pstat)); //find the correct station ++ break; ++ if (plist == plist->next) //the last plist ++ break; ++ plist = plist->next; ++ }; ++#endif ++ ++ //find highTP STA ++ for(i=0; ipODM_StaInfo[i]; ++ if(IS_STA_VALID(pstat) && (ODM_ChooseIotMainSTA(pDM_Odm, pstat))) //find the correct station ++ break; ++ } ++ ++ ////////////////////////////////////////////////////// ++ //if highTP STA is not found, then return ++ ////////////////////////////////////////////////////// ++ if(priv->pshare->highTP_found_pstat==NULL) { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("ODM_MAC_EDCA_TURBO OFF: NO HT STA FOUND\n")); ++ return; ++ } ++#endif ++ ++ pstat=priv->pshare->highTP_found_pstat; ++ ++ ++#ifdef WIFI_WMM ++ if (QOS_ENABLE) { ++ if (!priv->pmib->dot11OperationEntry.wifi_specific ++ #if(DM_ODM_SUPPORT_TYPE==ODM_AP) ++ ||((OPMODE & WIFI_AP_STATE) && (priv->pmib->dot11OperationEntry.wifi_specific == 2)) ++ #elif(DM_ODM_SUPPORT_TYPE==ODM_ADSL) ++ || (priv->pmib->dot11OperationEntry.wifi_specific == 2) ++ #endif ++ ) { ++ if (priv->pshare->iot_mode_enable && ++ ((priv->pshare->phw->VO_pkt_count > 50) || ++ (priv->pshare->phw->VI_pkt_count > 50) || ++ (priv->pshare->phw->BK_pkt_count > 50))) { ++ priv->pshare->iot_mode_enable = 0; ++ switch_turbo++; ++ } else if ((!priv->pshare->iot_mode_enable) && ++ ((priv->pshare->phw->VO_pkt_count < 50) && ++ (priv->pshare->phw->VI_pkt_count < 50) && ++ (priv->pshare->phw->BK_pkt_count < 50))) { ++ priv->pshare->iot_mode_enable++; ++ switch_turbo++; ++ } ++ } ++ ++ ++ #if(DM_ODM_SUPPORT_TYPE==ODM_AP) ++ if ((OPMODE & WIFI_AP_STATE) && priv->pmib->dot11OperationEntry.wifi_specific) ++ #elif (DM_ODM_SUPPORT_TYPE==ODM_ADSL) ++ if (priv->pmib->dot11OperationEntry.wifi_specific) ++ #endif ++ { ++ if (!priv->pshare->iot_mode_VO_exist && (priv->pshare->phw->VO_pkt_count > 50)) { ++ priv->pshare->iot_mode_VO_exist++; ++ switch_turbo++; ++ } else if (priv->pshare->iot_mode_VO_exist && (priv->pshare->phw->VO_pkt_count < 50)) { ++ priv->pshare->iot_mode_VO_exist = 0; ++ switch_turbo++; ++ } ++#if((DM_ODM_SUPPORT_TYPE==ODM_ADSL)||((DM_ODM_SUPPORT_TYPE==ODM_AP)&&(defined WMM_VIBE_PRI))) ++ if (priv->pshare->iot_mode_VO_exist) { ++ //printk("[%s %d] BE_pkt_count=%d\n", __FUNCTION__, __LINE__, priv->pshare->phw->BE_pkt_count); ++ if (!priv->pshare->iot_mode_BE_exist && (priv->pshare->phw->BE_pkt_count > 250)) { ++ priv->pshare->iot_mode_BE_exist++; ++ switch_turbo++; ++ } else if (priv->pshare->iot_mode_BE_exist && (priv->pshare->phw->BE_pkt_count < 250)) { ++ priv->pshare->iot_mode_BE_exist = 0; ++ switch_turbo++; ++ } ++ } ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE==ODM_AP) ++ if (priv->pshare->rf_ft_var.wifi_beq_iot) ++ { ++ if (!priv->pshare->iot_mode_VI_exist && (priv->pshare->phw->VI_rx_pkt_count > 50)) { ++ priv->pshare->iot_mode_VI_exist++; ++ switch_turbo++; ++ } else if (priv->pshare->iot_mode_VI_exist && (priv->pshare->phw->VI_rx_pkt_count < 50)) { ++ priv->pshare->iot_mode_VI_exist = 0; ++ switch_turbo++; ++ } ++ } ++#endif ++ ++ } ++ else if (!pstat || pstat->rssi < priv->pshare->rf_ft_var.txop_enlarge_lower) { ++ if (priv->pshare->txop_enlarge) { ++ priv->pshare->txop_enlarge = 0; ++ if (priv->pshare->iot_mode_enable) ++ switch_turbo++; ++ } ++ } ++ ++#if(defined(CLIENT_MODE) && (DM_ODM_SUPPORT_TYPE==ODM_AP)) ++ if ((OPMODE & WIFI_STATION_STATE) && (priv->pmib->dot11OperationEntry.wifi_specific == 2)) ++ { ++ if (priv->pshare->iot_mode_enable && ++ (((priv->pshare->phw->VO_pkt_count > 50) || ++ (priv->pshare->phw->VI_pkt_count > 50) || ++ (priv->pshare->phw->BK_pkt_count > 50)) || ++ (pstat && (!pstat->ADDBA_ready[0]) & (!pstat->ADDBA_ready[3])))) ++ { ++ priv->pshare->iot_mode_enable = 0; ++ switch_turbo++; ++ } ++ else if ((!priv->pshare->iot_mode_enable) && ++ (((priv->pshare->phw->VO_pkt_count < 50) && ++ (priv->pshare->phw->VI_pkt_count < 50) && ++ (priv->pshare->phw->BK_pkt_count < 50)) && ++ (pstat && (pstat->ADDBA_ready[0] | pstat->ADDBA_ready[3])))) ++ { ++ priv->pshare->iot_mode_enable++; ++ switch_turbo++; ++ } ++ } ++#endif ++ ++ priv->pshare->phw->VO_pkt_count = 0; ++ priv->pshare->phw->VI_pkt_count = 0; ++ priv->pshare->phw->BK_pkt_count = 0; ++ ++ #if((DM_ODM_SUPPORT_TYPE==ODM_ADSL)||((DM_ODM_SUPPORT_TYPE==ODM_AP)&&(defined WMM_VIBE_PRI))) ++ priv->pshare->phw->BE_pkt_count = 0; ++ #endif ++ ++ #if(DM_ODM_SUPPORT_TYPE==ODM_AP) ++ if (priv->pshare->rf_ft_var.wifi_beq_iot) ++ priv->pshare->phw->VI_rx_pkt_count = 0; ++ #endif ++ ++ } ++#endif ++ ++ if ((priv->up_time % 2) == 0) { ++ /* ++ * decide EDCA content for different chip vendor ++ */ ++#ifdef WIFI_WMM ++ #if(DM_ODM_SUPPORT_TYPE==ODM_ADSL) ++ if (QOS_ENABLE && (!priv->pmib->dot11OperationEntry.wifi_specific || (priv->pmib->dot11OperationEntry.wifi_specific == 2) ++ ++ #elif(DM_ODM_SUPPORT_TYPE==ODM_AP) ++ if (QOS_ENABLE && (!priv->pmib->dot11OperationEntry.wifi_specific || ++ ((OPMODE & WIFI_AP_STATE) && (priv->pmib->dot11OperationEntry.wifi_specific == 2)) ++ #ifdef CLIENT_MODE ++ || ((OPMODE & WIFI_STATION_STATE) && (priv->pmib->dot11OperationEntry.wifi_specific == 2)) ++ #endif ++ #endif ++ )) ++ ++ { ++ ++ if (pstat && pstat->rssi >= priv->pshare->rf_ft_var.txop_enlarge_upper) { ++#ifdef LOW_TP_TXOP ++#if (DM_ODM_SUPPORT_TYPE &ODM_AP) && defined(USE_OUT_SRC) ++ if (pstat->IOTPeer==HT_IOT_PEER_INTEL) ++#else ++ if (pstat->is_intel_sta) ++#endif ++ { ++ if (priv->pshare->txop_enlarge != 0xe) ++ { ++ priv->pshare->txop_enlarge = 0xe; ++ ++ if (priv->pshare->iot_mode_enable) ++ switch_turbo++; ++ } ++ } ++ else if (priv->pshare->txop_enlarge != 2) ++ { ++ priv->pshare->txop_enlarge = 2; ++ if (priv->pshare->iot_mode_enable) ++ switch_turbo++; ++ } ++#else ++ if (priv->pshare->txop_enlarge != 2) ++ { ++#if (DM_ODM_SUPPORT_TYPE &ODM_AP) && defined(USE_OUT_SRC) ++ if (pstat->IOTPeer==HT_IOT_PEER_INTEL) ++#else ++ if (pstat->is_intel_sta) ++#endif ++ priv->pshare->txop_enlarge = 0xe; ++#if (DM_ODM_SUPPORT_TYPE &ODM_AP) && defined(USE_OUT_SRC) ++ else if (pstat->IOTPeer==HT_IOT_PEER_RALINK) ++#else ++ else if (pstat->is_ralink_sta) ++#endif ++ priv->pshare->txop_enlarge = 0xd; ++ else ++ priv->pshare->txop_enlarge = 2; ++ ++ if (priv->pshare->iot_mode_enable) ++ switch_turbo++; ++ } ++#endif ++#if 0 ++ if (priv->pshare->txop_enlarge != 2) ++ { ++ #if(DM_ODM_SUPPORT_TYPE==ODM_AP) ++ if (pstat->IOTPeer==HT_IOT_PEER_INTEL) ++ #else ++ if (pstat->is_intel_sta) ++ #endif ++ priv->pshare->txop_enlarge = 0xe; ++ #if(DM_ODM_SUPPORT_TYPE==ODM_AP) ++ else if (pstat->IOTPeer==HT_IOT_PEER_RALINK) ++ priv->pshare->txop_enlarge = 0xd; ++ #endif ++ else ++ priv->pshare->txop_enlarge = 2; ++ if (priv->pshare->iot_mode_enable) ++ switch_turbo++; ++ } ++#endif ++ } ++ else if (!pstat || pstat->rssi < priv->pshare->rf_ft_var.txop_enlarge_lower) ++ { ++ if (priv->pshare->txop_enlarge) { ++ priv->pshare->txop_enlarge = 0; ++ if (priv->pshare->iot_mode_enable) ++ switch_turbo++; ++ } ++ } ++ ++#if((DM_ODM_SUPPORT_TYPE==ODM_AP)&&( defined LOW_TP_TXOP)) ++ // for Intel IOT, need to enlarge CW MAX from 6 to 10 ++ if (pstat && pstat->is_intel_sta && (((pstat->tx_avarage+pstat->rx_avarage)>>10) < ++ priv->pshare->rf_ft_var.cwmax_enhance_thd)) ++ { ++ if (!priv->pshare->BE_cwmax_enhance && priv->pshare->iot_mode_enable) ++ { ++ priv->pshare->BE_cwmax_enhance = 1; ++ switch_turbo++; ++ } ++ } else { ++ if (priv->pshare->BE_cwmax_enhance) { ++ priv->pshare->BE_cwmax_enhance = 0; ++ switch_turbo++; ++ } ++ } ++#endif ++ } ++#endif ++ priv->pshare->current_tx_bytes = 0; ++ priv->pshare->current_rx_bytes = 0; ++ } ++ ++#if((DM_ODM_SUPPORT_TYPE==ODM_AP)&& defined( SW_TX_QUEUE)) ++ if ((priv->assoc_num > 1) && (AMPDU_ENABLE)) ++ { ++ if (priv->swq_txmac_chg >= priv->pshare->rf_ft_var.swq_en_highthd){ ++ if ((priv->swq_en == 0)){ ++ switch_turbo++; ++ if (priv->pshare->txop_enlarge == 0) ++ priv->pshare->txop_enlarge = 2; ++ priv->swq_en = 1; ++ } ++ else ++ { ++ if ((switch_turbo > 0) && (priv->pshare->txop_enlarge == 0) && (priv->pshare->iot_mode_enable != 0)) ++ { ++ priv->pshare->txop_enlarge = 2; ++ switch_turbo--; ++ } ++ } ++ } ++ else if(priv->swq_txmac_chg <= priv->pshare->rf_ft_var.swq_dis_lowthd){ ++ priv->swq_en = 0; ++ } ++ else if ((priv->swq_en == 1) && (switch_turbo > 0) && (priv->pshare->txop_enlarge == 0) && (priv->pshare->iot_mode_enable != 0)) { ++ priv->pshare->txop_enlarge = 2; ++ switch_turbo--; ++ } ++ } ++#if ((DM_ODM_SUPPORT_TYPE==ODM_AP)&&(defined CONFIG_RTL_819XD)) ++ else if( (priv->assoc_num == 1) && (AMPDU_ENABLE)) { ++ if (pstat) { ++ int en_thd = 14417920>>(priv->up_time % 2); ++ if ((priv->swq_en == 0) && (pstat->current_tx_bytes > en_thd) && (pstat->current_rx_bytes > en_thd) ) { //50Mbps ++ priv->swq_en = 1; ++ priv->swqen_keeptime = priv->up_time; ++ } ++ else if ((priv->swq_en == 1) && ((pstat->tx_avarage < 4587520) || (pstat->rx_avarage < 4587520))) { //35Mbps ++ priv->swq_en = 0; ++ priv->swqen_keeptime = 0; ++ } ++ } ++ else { ++ priv->swq_en = 0; ++ priv->swqen_keeptime = 0; ++ } ++ } ++#endif ++#endif ++ ++#ifdef WIFI_WMM ++#ifdef LOW_TP_TXOP ++ if ((!priv->pmib->dot11OperationEntry.wifi_specific || (priv->pmib->dot11OperationEntry.wifi_specific == 2)) ++ && QOS_ENABLE) { ++ if (switch_turbo || priv->pshare->rf_ft_var.low_tp_txop) { ++ unsigned int thd_tp; ++ unsigned char under_thd; ++ unsigned int curr_tp; ++ ++ if (priv->pmib->dot11BssType.net_work_type & (ODM_WM_N24G|ODM_WM_N5G| ODM_WM_G)) ++ { ++ // Determine the upper bound throughput threshold. ++ if (priv->pmib->dot11BssType.net_work_type & (ODM_WM_N24G|ODM_WM_N5G)) { ++ if (priv->assoc_num && priv->assoc_num != priv->pshare->ht_sta_num) ++ thd_tp = priv->pshare->rf_ft_var.low_tp_txop_thd_g; ++ else ++ thd_tp = priv->pshare->rf_ft_var.low_tp_txop_thd_n; ++ } ++ else ++ thd_tp = priv->pshare->rf_ft_var.low_tp_txop_thd_g; ++ ++ // Determine to close txop. ++ curr_tp = (unsigned int)(priv->ext_stats.tx_avarage>>17) + (unsigned int)(priv->ext_stats.rx_avarage>>17); ++ if (curr_tp <= thd_tp && curr_tp >= priv->pshare->rf_ft_var.low_tp_txop_thd_low) ++ under_thd = 1; ++ else ++ under_thd = 0; ++ } ++ else ++ { ++ under_thd = 0; ++ } ++ ++ if (switch_turbo) ++ { ++ priv->pshare->rf_ft_var.low_tp_txop_close = under_thd; ++ priv->pshare->rf_ft_var.low_tp_txop_count = 0; ++ } ++ else if (priv->pshare->iot_mode_enable && (priv->pshare->rf_ft_var.low_tp_txop_close != under_thd)) { ++ priv->pshare->rf_ft_var.low_tp_txop_count++; ++ if (priv->pshare->rf_ft_var.low_tp_txop_close) { ++ priv->pshare->rf_ft_var.low_tp_txop_count = priv->pshare->rf_ft_var.low_tp_txop_delay;; ++ } ++ if (priv->pshare->rf_ft_var.low_tp_txop_count ==priv->pshare->rf_ft_var.low_tp_txop_delay) ++ ++ { ++ priv->pshare->rf_ft_var.low_tp_txop_count = 0; ++ priv->pshare->rf_ft_var.low_tp_txop_close = under_thd; ++ switch_turbo++; ++ } ++ } ++ else ++ { ++ priv->pshare->rf_ft_var.low_tp_txop_count = 0; ++ } ++ } ++ } ++#endif ++ ++ if (switch_turbo) ++ ODM_IotEdcaSwitch( pDM_Odm, priv->pshare->iot_mode_enable ); ++#endif ++} ++#endif ++ ++ ++#if( DM_ODM_SUPPORT_TYPE == ODM_MP) ++// ++// 2011/07/26 MH Add an API for testing IQK fail case. ++// ++BOOLEAN ++ODM_CheckPowerStatus( ++ IN PADAPTER Adapter) ++{ ++ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ RT_RF_POWER_STATE rtState; ++ PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ ++ // 2011/07/27 MH We are not testing ready~~!! We may fail to get correct value when init sequence. ++ if (pMgntInfo->init_adpt_in_progress == TRUE) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("ODM_CheckPowerStatus Return TRUE, due to initadapter")); ++ return TRUE; ++ } ++ ++ // ++ // 2011/07/19 MH We can not execute tx pwoer tracking/ LLC calibrate or IQK. ++ // ++ Adapter->HalFunc.GetHwRegHandler(Adapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState)); ++ if(Adapter->bDriverStopped || Adapter->bDriverIsGoingToPnpSetPowerSleep || rtState == eRfOff) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("ODM_CheckPowerStatus Return FALSE, due to %d/%d/%d\n", ++ Adapter->bDriverStopped, Adapter->bDriverIsGoingToPnpSetPowerSleep, rtState)); ++ return FALSE; ++ } ++ return TRUE; ++} ++#endif ++ ++// need to ODM CE Platform ++//move to here for ANT detection mechanism using ++ ++#if ((DM_ODM_SUPPORT_TYPE == ODM_MP)||(DM_ODM_SUPPORT_TYPE == ODM_CE)) ++u4Byte ++GetPSDData( ++ IN PDM_ODM_T pDM_Odm, ++ unsigned int point, ++ u1Byte initial_gain_psd) ++{ ++ //unsigned int val, rfval; ++ //int psd_report; ++ u4Byte psd_report; ++ ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ //Debug Message ++ //val = PHY_QueryBBReg(Adapter,0x908, bMaskDWord); ++ //DbgPrint("Reg908 = 0x%x\n",val); ++ //val = PHY_QueryBBReg(Adapter,0xDF4, bMaskDWord); ++ //rfval = PHY_QueryRFReg(Adapter, RF_PATH_A, 0x00, bRFRegOffsetMask); ++ //DbgPrint("RegDF4 = 0x%x, RFReg00 = 0x%x\n",val, rfval); ++ //DbgPrint("PHYTXON = %x, OFDMCCA_PP = %x, CCKCCA_PP = %x, RFReg00 = %x\n", ++ //(val&BIT25)>>25, (val&BIT14)>>14, (val&BIT15)>>15, rfval); ++ ++ //Set DCO frequency index, offset=(40MHz/SamplePts)*point ++ ODM_SetBBReg(pDM_Odm, 0x808, 0x3FF, point); ++ ++ //Start PSD calculation, Reg808[22]=0->1 ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT22, 1); ++ //Need to wait for HW PSD report ++ ODM_StallExecution(30); ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT22, 0); ++ //Read PSD report, Reg8B4[15:0] ++ psd_report = ODM_GetBBReg(pDM_Odm,0x8B4, bMaskDWord) & 0x0000FFFF; ++ ++#if 1//(DEV_BUS_TYPE == RT_PCI_INTERFACE) && ( (RT_PLATFORM == PLATFORM_LINUX) || (RT_PLATFORM == PLATFORM_MACOSX)) ++ psd_report = (u4Byte) (ConvertTo_dB(psd_report))+(u4Byte)(initial_gain_psd-0x1c); ++#else ++ psd_report = (int) (20*log10((double)psd_report))+(int)(initial_gain_psd-0x1c); ++#endif ++ ++ return psd_report; ++ ++} ++ ++u4Byte ++ConvertTo_dB( ++ u4Byte Value) ++{ ++ u1Byte i; ++ u1Byte j; ++ u4Byte dB; ++ ++ Value = Value & 0xFFFF; ++ ++ for (i=0;i<8;i++) ++ { ++ if (Value <= dB_Invert_Table[i][11]) ++ { ++ break; ++ } ++ } ++ ++ if (i >= 8) ++ { ++ return (96); // maximum 96 dB ++ } ++ ++ for (j=0;j<12;j++) ++ { ++ if (Value <= dB_Invert_Table[i][j]) ++ { ++ break; ++ } ++ } ++ ++ dB = i*12 + j + 1; ++ ++ return (dB); ++} ++ ++#endif ++ ++// ++// LukeLee: ++// PSD function will be moved to FW in future IC, but now is only implemented in MP platform ++// So PSD function will not be incorporated to common ODM ++// ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ++#define AFH_PSD 1 //0:normal PSD scan, 1: only do 20 pts PSD ++#define MODE_40M 0 //0:20M, 1:40M ++#define PSD_TH2 3 ++#define PSD_CHMIN 20 // Minimum channel number for BT AFH ++#define SIR_STEP_SIZE 3 ++#define Smooth_Size_1 5 ++#define Smooth_TH_1 3 ++#define Smooth_Size_2 10 ++#define Smooth_TH_2 4 ++#define Smooth_Size_3 20 ++#define Smooth_TH_3 4 ++#define Smooth_Step_Size 5 ++#define Adaptive_SIR 1 ++//#if(RTL8723_FPGA_VERIFICATION == 1) ++//#define PSD_RESCAN 1 ++//#else ++//#define PSD_RESCAN 4 ++//#endif ++#define SCAN_INTERVAL 700 //ms ++#define SYN_Length 5 // for 92D ++ ++#define LNA_Low_Gain_1 0x64 ++#define LNA_Low_Gain_2 0x5A ++#define LNA_Low_Gain_3 0x58 ++ ++#define pw_th_10dB 0x0 ++#define pw_th_16dB 0x3 ++ ++#define FA_RXHP_TH1 5000 ++#define FA_RXHP_TH2 1500 ++#define FA_RXHP_TH3 800 ++#define FA_RXHP_TH4 600 ++#define FA_RXHP_TH5 500 ++ ++#define Idle_Mode 0 ++#define High_TP_Mode 1 ++#define Low_TP_Mode 2 ++ ++ ++VOID ++odm_PSDMonitorInit( ++ IN PDM_ODM_T pDM_Odm) ++{ ++#if (DEV_BUS_TYPE == RT_PCI_INTERFACE)|(DEV_BUS_TYPE == RT_USB_INTERFACE) ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ //PSD Monitor Setting ++ //Which path in ADC/DAC is turnned on for PSD: both I/Q ++ ODM_SetBBReg(pDM_Odm, ODM_PSDREG, BIT10|BIT11, 0x3); ++ //Ageraged number: 8 ++ ODM_SetBBReg(pDM_Odm, ODM_PSDREG, BIT12|BIT13, 0x1); ++ pDM_Odm->bPSDinProcess = FALSE; ++ pDM_Odm->bUserAssignLevel = FALSE; ++ ++ //pDM_Odm->bDMInitialGainEnable=TRUE; //change the initialization to DIGinit ++ //Set Debug Port ++ //PHY_SetBBReg(Adapter, 0x908, bMaskDWord, 0x803); ++ //PHY_SetBBReg(Adapter, 0xB34, bMaskByte0, 0x00); // pause PSD ++ //PHY_SetBBReg(Adapter, 0xB38, bMaskByte0, 10); //rescan ++ //PHY_SetBBReg(Adapter, 0xB38, bMaskByte1, 0x32); // PSDDelay ++ //PHY_SetBBReg(Adapter, 0xB38, bMaskByte2|bMaskByte3, 100); //interval ++ ++ //PlatformSetTimer( Adapter, &pHalData->PSDTriggerTimer, 0); //ms ++#endif ++} ++ ++VOID ++PatchDCTone( ++ IN PDM_ODM_T pDM_Odm, ++ pu4Byte PSD_report, ++ u1Byte initial_gain_psd ++) ++{ ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ //PADAPTER pAdapter; ++ ++ u4Byte psd_report; ++ ++ //2 Switch to CH11 to patch CH9 and CH13 DC tone ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, 0x3FF, 11); ++ ++ if(pDM_Odm->SupportICType== ODM_RTL8192D) ++ { ++ if((*(pDM_Odm->pMacPhyMode) == ODM_SMSP)||(*(pDM_Odm->pMacPhyMode) == ODM_DMSP)) ++ { ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, RF_CHNLBW, 0x3FF, 11); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, 0x25, 0xfffff, 0x643BC); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, 0x26, 0xfffff, 0xFC038); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, 0x27, 0xfffff, 0x77C1A); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, 0x2B, 0xfffff, 0x41289); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, 0x2C, 0xfffff, 0x01840); ++ } ++ else ++ { ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x25, 0xfffff, 0x643BC); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x26, 0xfffff, 0xFC038); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x27, 0xfffff, 0x77C1A); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x2B, 0xfffff, 0x41289); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x2C, 0xfffff, 0x01840); ++ } ++ } ++ ++ //Ch9 DC tone patch ++ psd_report = GetPSDData(pDM_Odm, 96, initial_gain_psd); ++ PSD_report[50] = psd_report; ++ //Ch13 DC tone patch ++ psd_report = GetPSDData(pDM_Odm, 32, initial_gain_psd); ++ PSD_report[70] = psd_report; ++ ++ //2 Switch to CH3 to patch CH1 and CH5 DC tone ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, 0x3FF, 3); ++ ++ ++ if(pDM_Odm->SupportICType==ODM_RTL8192D) ++ { ++ if((*(pDM_Odm->pMacPhyMode) == ODM_SMSP)||(*(pDM_Odm->pMacPhyMode) == ODM_DMSP)) ++ { ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, RF_CHNLBW, 0x3FF, 3); ++ //PHY_SetRFReg(Adapter, RF_PATH_B, 0x25, 0xfffff, 0x643BC); ++ //PHY_SetRFReg(Adapter, RF_PATH_B, 0x26, 0xfffff, 0xFC038); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, 0x27, 0xfffff, 0x07C1A); ++ //PHY_SetRFReg(Adapter, RF_PATH_B, 0x2B, 0xfffff, 0x61289); ++ //PHY_SetRFReg(Adapter, RF_PATH_B, 0x2C, 0xfffff, 0x01C41); ++ } ++ else ++ { ++ //PHY_SetRFReg(Adapter, RF_PATH_A, 0x25, 0xfffff, 0x643BC); ++ //PHY_SetRFReg(Adapter, RF_PATH_A, 0x26, 0xfffff, 0xFC038); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x27, 0xfffff, 0x07C1A); ++ //PHY_SetRFReg(Adapter, RF_PATH_A, 0x2B, 0xfffff, 0x61289); ++ //PHY_SetRFReg(Adapter, RF_PATH_A, 0x2C, 0xfffff, 0x01C41); ++ } ++ } ++ ++ //Ch1 DC tone patch ++ psd_report = GetPSDData(pDM_Odm, 96, initial_gain_psd); ++ PSD_report[10] = psd_report; ++ //Ch5 DC tone patch ++ psd_report = GetPSDData(pDM_Odm, 32, initial_gain_psd); ++ PSD_report[30] = psd_report; ++ ++} ++ ++ ++VOID ++GoodChannelDecision( ++ PDM_ODM_T pDM_Odm, ++ ps4Byte PSD_report, ++ pu1Byte PSD_bitmap, ++ u1Byte RSSI_BT, ++ pu1Byte PSD_bitmap_memory) ++{ ++ pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; ++ //s4Byte TH1 = SSBT-0x15; // modify TH by Neil Chen ++ s4Byte TH1= RSSI_BT+0x14; ++ s4Byte TH2 = RSSI_BT+85; ++ //u2Byte TH3; ++// s4Byte RegB34; ++ u1Byte bitmap, Smooth_size[3], Smooth_TH[3]; ++ //u1Byte psd_bit; ++ u4Byte i,n,j, byte_idx, bit_idx, good_cnt, good_cnt_smoothing, Smooth_Interval[3]; ++ int start_byte_idx,start_bit_idx,cur_byte_idx, cur_bit_idx,NOW_byte_idx ; ++ ++// RegB34 = PHY_QueryBBReg(Adapter,0xB34, bMaskDWord)&0xFF; ++ ++ if((pDM_Odm->SupportICType == ODM_RTL8192C)||(pDM_Odm->SupportICType == ODM_RTL8192D)) ++ { ++ TH1 = RSSI_BT + 0x14; ++ } ++ ++ Smooth_size[0]=Smooth_Size_1; ++ Smooth_size[1]=Smooth_Size_2; ++ Smooth_size[2]=Smooth_Size_3; ++ Smooth_TH[0]=Smooth_TH_1; ++ Smooth_TH[1]=Smooth_TH_2; ++ Smooth_TH[2]=Smooth_TH_3; ++ Smooth_Interval[0]=16; ++ Smooth_Interval[1]=15; ++ Smooth_Interval[2]=13; ++ good_cnt = 0; ++ if(pDM_Odm->SupportICType==ODM_RTL8723A) ++ { ++ //2 Threshold ++ ++ if(RSSI_BT >=41) ++ TH1 = 113; ++ else if(RSSI_BT >=38) // >= -15dBm ++ TH1 = 105; //0x69 ++ else if((RSSI_BT >=33)&(RSSI_BT <38)) ++ TH1 = 99+(RSSI_BT-33); //0x63 ++ else if((RSSI_BT >=26)&(RSSI_BT<33)) ++ TH1 = 99-(33-RSSI_BT)+2; //0x5e ++ else if((RSSI_BT >=24)&(RSSI_BT<26)) ++ TH1 = 88-((RSSI_BT-24)*3); //0x58 ++ else if((RSSI_BT >=18)&(RSSI_BT<24)) ++ TH1 = 77+((RSSI_BT-18)*2); ++ else if((RSSI_BT >=14)&(RSSI_BT<18)) ++ TH1 = 63+((RSSI_BT-14)*2); ++ else if((RSSI_BT >=8)&(RSSI_BT<14)) ++ TH1 = 58+((RSSI_BT-8)*2); ++ else if((RSSI_BT >=3)&(RSSI_BT<8)) ++ TH1 = 52+(RSSI_BT-3); ++ else ++ TH1 = 51; ++ } ++ ++ for (i = 0; i< 10; i++) ++ PSD_bitmap[i] = 0; ++ ++ ++ // Add By Gary ++ for (i=0; i<80; i++) ++ pRX_HP_Table->PSD_bitmap_RXHP[i] = 0; ++ // End ++ ++ ++ ++ if(pDM_Odm->SupportICType==ODM_RTL8723A) ++ { ++ TH1 =TH1-SIR_STEP_SIZE; ++ } ++ while (good_cnt < PSD_CHMIN) ++ { ++ good_cnt = 0; ++ if(pDM_Odm->SupportICType==ODM_RTL8723A) ++ { ++ if(TH1 ==TH2) ++ break; ++ if((TH1+SIR_STEP_SIZE) < TH2) ++ TH1 += SIR_STEP_SIZE; ++ else ++ TH1 = TH2; ++ } ++ else ++ { ++ if(TH1==(RSSI_BT+0x1E)) ++ break; ++ if((TH1+2) < (RSSI_BT+0x1E)) ++ TH1+=3; ++ else ++ TH1 = RSSI_BT+0x1E; ++ ++ } ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD,DBG_LOUD,("PSD: decision threshold is: %d", TH1)); ++ ++ for (i = 0; i< 80; i++) ++ { ++ if(PSD_report[i] < TH1) ++ { ++ byte_idx = i / 8; ++ bit_idx = i -8*byte_idx; ++ bitmap = PSD_bitmap[byte_idx]; ++ PSD_bitmap[byte_idx] = bitmap | (u1Byte) (1 << bit_idx); ++ } ++ } ++ ++#if DBG ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("PSD: before smoothing\n")); ++ for(n=0;n<10;n++) ++ { ++ //DbgPrint("PSD_bitmap[%u]=%x\n", n, PSD_bitmap[n]); ++ for (i = 0; i<8; i++) ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("PSD_bitmap[%u] = %d\n", 2402+n*8+i, (PSD_bitmap[n]&BIT(i))>>i)); ++ } ++#endif ++ ++ //1 Start of smoothing function ++ ++ for (j=0;j<3;j++) ++ { ++ start_byte_idx=0; ++ start_bit_idx=0; ++ for(n=0; n 7 ) ++ { ++ start_byte_idx= start_byte_idx+start_bit_idx/8; ++ start_bit_idx = start_bit_idx%8; ++ } ++ } ++ ++ ODM_RT_TRACE( pDM_Odm,COMP_PSD, DBG_LOUD,("PSD: after %u smoothing", j+1)); ++ for(n=0;n<10;n++) ++ { ++ for (i = 0; i<8; i++) ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("PSD_bitmap[%u] = %d\n", 2402+n*8+i, (PSD_bitmap[n]&BIT(i))>>i)); ++ ++ if ( ((PSD_bitmap[n]&BIT(i))>>i) ==1) //----- Add By Gary ++ { ++ pRX_HP_Table->PSD_bitmap_RXHP[8*n+i] = 1; ++ } // ------end by Gary ++ } ++ } ++ ++ } ++ ++ ++ good_cnt = 0; ++ for ( i = 0; i < 10; i++) ++ { ++ for (n = 0; n < 8; n++) ++ if((PSD_bitmap[i]& BIT(n)) != 0) ++ good_cnt++; ++ } ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("PSD: good channel cnt = %u",good_cnt)); ++ } ++ ++ //RT_TRACE(COMP_PSD, DBG_LOUD,("PSD: SSBT=%d, TH2=%d, TH1=%d",SSBT,TH2,TH1)); ++ for (i = 0; i <10; i++) ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("PSD: PSD_bitmap[%u]=%x",i,PSD_bitmap[i])); ++/* ++ //Update bitmap memory ++ for(i = 0; i < 80; i++) ++ { ++ byte_idx = i / 8; ++ bit_idx = i -8*byte_idx; ++ psd_bit = (PSD_bitmap[byte_idx] & BIT(bit_idx)) >> bit_idx; ++ bitmap = PSD_bitmap_memory[i]; ++ PSD_bitmap_memory[i] = (bitmap << 1) |psd_bit; ++ } ++*/ ++} ++ ++ ++ ++VOID ++odm_PSD_Monitor( ++ PDM_ODM_T pDM_Odm ++) ++{ ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ //PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ ++ ++ unsigned int pts, start_point, stop_point, initial_gain ; ++ static u1Byte PSD_bitmap_memory[80], init_memory = 0; ++ static u1Byte psd_cnt=0; ++ static u4Byte PSD_report[80], PSD_report_tmp; ++ static u8Byte lastTxOkCnt=0, lastRxOkCnt=0; ++ u1Byte H2C_PSD_DATA[5]={0,0,0,0,0}; ++ static u1Byte H2C_PSD_DATA_last[5] ={0,0,0,0,0}; ++ u1Byte idx[20]={96,99,102,106,109,112,115,118,122,125, ++ 0,3,6,10,13,16,19,22,26,29}; ++ u1Byte n, i, channel, BBReset,tone_idx; ++ u1Byte PSD_bitmap[10], SSBT=0,initial_gain_psd=0, RSSI_BT=0, initialGainUpper; ++ s4Byte PSD_skip_start, PSD_skip_stop; ++ u4Byte CurrentChannel, RXIQI, RxIdleLowPwr, wlan_channel; ++ u4Byte ReScan, Interval, Is40MHz; ++ u8Byte curTxOkCnt, curRxOkCnt; ++ int cur_byte_idx, cur_bit_idx; ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ //--------------2G band synthesizer for 92D switch RF channel using----------------- ++ u1Byte group_idx=0; ++ u4Byte SYN_RF25=0, SYN_RF26=0, SYN_RF27=0, SYN_RF2B=0, SYN_RF2C=0; ++ u4Byte SYN[5] = {0x25, 0x26, 0x27, 0x2B, 0x2C}; // synthesizer RF register for 2G channel ++ u4Byte SYN_group[3][5] = {{0x643BC, 0xFC038, 0x77C1A, 0x41289, 0x01840}, // For CH1,2,4,9,10.11.12 {0x643BC, 0xFC038, 0x77C1A, 0x41289, 0x01840} ++ {0x643BC, 0xFC038, 0x07C1A, 0x41289, 0x01840}, // For CH3,13,14 ++ {0x243BC, 0xFC438, 0x07C1A, 0x4128B, 0x0FC41}}; // For Ch5,6,7,8 ++ //--------------------- Add by Gary for Debug setting ---------------------- ++ s4Byte psd_result = 0; ++ u1Byte RSSI_BT_new = (u1Byte) ODM_GetBBReg(pDM_Odm, 0xB9C, 0xFF); ++ u1Byte rssi_ctrl = (u1Byte) ODM_GetBBReg(pDM_Odm, 0xB38, 0xFF); ++ //--------------------------------------------------------------------- ++ ++ if(*(pDM_Odm->pbScanInProcess)) ++ { ++ if((pDM_Odm->SupportICType==ODM_RTL8723A)&(pDM_Odm->SupportInterface==ODM_ITRF_PCIE)) ++ { ++ //pHalData->bPSDactive=FALSE; ++ //ODM_SetTimer(pDM_Odm,&pDM_SWAT_Table->SwAntennaSwitchTimer, 100 ) ++ ODM_SetTimer( pDM_Odm, &pDM_Odm->PSDTimer, 900); //ms ++ //psd_cnt=0; ++ } ++ return; ++ } ++ ++ ReScan = PSD_RESCAN; ++ Interval = SCAN_INTERVAL; ++ ++ ++ //1 Initialization ++ if(init_memory == 0) ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("Init memory\n")); ++ for(i = 0; i < 80; i++) ++ PSD_bitmap_memory[i] = 0xFF; // channel is always good ++ init_memory = 1; ++ } ++ if(psd_cnt == 0) ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("Enter dm_PSD_Monitor\n")); ++ for(i = 0; i < 80; i++) ++ PSD_report[i] = 0; ++ } ++#if 0 //for test only ++ DbgPrint("cosa odm_PSD_Monitor call()\n"); ++ DbgPrint("cosa pHalData->RSSI_BT = %d\n", pHalData->RSSI_BT); ++ DbgPrint("cosa pHalData->bUserAssignLevel = %d\n", pHalData->bUserAssignLevel); ++#if 0 ++ psd_cnt++; ++ if (psd_cnt < ReScan) ++ PlatformSetTimer( Adapter, &pHalData->PSDTimer, Interval); //ms ++ else ++ psd_cnt = 0; ++ return; ++#endif ++#endif ++ //1 Backup Current Settings ++ CurrentChannel = ODM_GetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask); ++/* ++ if(pDM_Odm->SupportICType==ODM_RTL8192D) ++ { ++ //2 Record Current synthesizer parameters based on current channel ++ if((*pDM_Odm->MacPhyMode92D == SINGLEMAC_SINGLEPHY)||(*pDM_Odm->MacPhyMode92D == DUALMAC_SINGLEPHY)) ++ { ++ SYN_RF25 = ODM_GetRFReg(Adapter, RF_PATH_B, 0x25, bMaskDWord); ++ SYN_RF26 = ODM_GetRFReg(Adapter, RF_PATH_B, 0x26, bMaskDWord); ++ SYN_RF27 = ODM_GetRFReg(Adapter, RF_PATH_B, 0x27, bMaskDWord); ++ SYN_RF2B = ODM_GetRFReg(Adapter, RF_PATH_B, 0x2B, bMaskDWord); ++ SYN_RF2C = ODM_GetRFReg(Adapter, RF_PATH_B, 0x2C, bMaskDWord); ++ } ++ else // DualMAC_DualPHY 2G ++ { ++ SYN_RF25 = ODM_GetRFReg(Adapter, RF_PATH_A, 0x25, bMaskDWord); ++ SYN_RF26 = ODM_GetRFReg(Adapter, RF_PATH_A, 0x26, bMaskDWord); ++ SYN_RF27 = ODM_GetRFReg(Adapter, RF_PATH_A, 0x27, bMaskDWord); ++ SYN_RF2B = ODM_GetRFReg(Adapter, RF_PATH_A, 0x2B, bMaskDWord); ++ SYN_RF2C = ODM_GetRFReg(Adapter, RF_PATH_A, 0x2C, bMaskDWord); ++ } ++ } ++*/ ++ //RXIQI = PHY_QueryBBReg(Adapter, 0xC14, bMaskDWord); ++ RXIQI = ODM_GetBBReg(pDM_Odm, 0xC14, bMaskDWord); ++ ++ //RxIdleLowPwr = (PHY_QueryBBReg(Adapter, 0x818, bMaskDWord)&BIT28)>>28; ++ RxIdleLowPwr = (ODM_GetBBReg(pDM_Odm, 0x818, bMaskDWord)&BIT28)>>28; ++ ++ //2??? ++ Is40MHz = pMgntInfo->pHTInfo->bCurBW40MHz; ++ ++ ODM_RT_TRACE(pDM_Odm, COMP_PSD, DBG_LOUD,("PSD Scan Start\n")); ++ //1 Turn off CCK ++ //PHY_SetBBReg(Adapter, rFPGA0_RFMOD, BIT24, 0); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_RFMOD, BIT24, 0); ++ //1 Turn off TX ++ //Pause TX Queue ++ //PlatformEFIOWrite1Byte(Adapter, REG_TXPAUSE, 0xFF); ++ ODM_Write1Byte(pDM_Odm,REG_TXPAUSE, 0xFF); ++ ++ //Force RX to stop TX immediately ++ //PHY_SetRFReg(Adapter, RF_PATH_A, RF_AC, bRFRegOffsetMask, 0x32E13); ++ ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_AC, bRFRegOffsetMask, 0x32E13); ++ //1 Turn off RX ++ //Rx AGC off RegC70[0]=0, RegC7C[20]=0 ++ //PHY_SetBBReg(Adapter, 0xC70, BIT0, 0); ++ //PHY_SetBBReg(Adapter, 0xC7C, BIT20, 0); ++ ++ ODM_SetBBReg(pDM_Odm, 0xC70, BIT0, 0); ++ ODM_SetBBReg(pDM_Odm, 0xC7C, BIT20, 0); ++ ++ ++ //Turn off CCA ++ //PHY_SetBBReg(Adapter, 0xC14, bMaskDWord, 0x0); ++ ODM_SetBBReg(pDM_Odm, 0xC14, bMaskDWord, 0x0); ++ ++ //BB Reset ++ //BBReset = PlatformEFIORead1Byte(Adapter, 0x02); ++ BBReset = ODM_Read1Byte(pDM_Odm, 0x02); ++ ++ //PlatformEFIOWrite1Byte(Adapter, 0x02, BBReset&(~BIT0)); ++ //PlatformEFIOWrite1Byte(Adapter, 0x02, BBReset|BIT0); ++ ++ ODM_Write1Byte(pDM_Odm, 0x02, BBReset&(~BIT0)); ++ ODM_Write1Byte(pDM_Odm, 0x02, BBReset|BIT0); ++ ++ //1 Leave RX idle low power ++ //PHY_SetBBReg(Adapter, 0x818, BIT28, 0x0); ++ ++ ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x0); ++ //1 Fix initial gain ++ //if (IS_HARDWARE_TYPE_8723AE(Adapter)) ++ //RSSI_BT = pHalData->RSSI_BT; ++ //else if((IS_HARDWARE_TYPE_8192C(Adapter))||(IS_HARDWARE_TYPE_8192D(Adapter))) // Add by Gary ++ // RSSI_BT = RSSI_BT_new; ++ ++ if((pDM_Odm->SupportICType==ODM_RTL8723A)&(pDM_Odm->SupportInterface==ODM_ITRF_PCIE)) ++ RSSI_BT=pDM_Odm->RSSI_BT; //need to check C2H to pDM_Odm RSSI BT ++ ++ else if((pDM_Odm->SupportICType==ODM_RTL8192C)||(pDM_Odm->SupportICType==ODM_RTL8192D)) ++ RSSI_BT = RSSI_BT_new; ++ ++ ++ ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("PSD: RSSI_BT= %d\n", RSSI_BT)); ++ ++ if(pDM_Odm->SupportICType==ODM_RTL8723A) ++ { ++ //Neil add--2011--10--12 ++ //2 Initial Gain index ++ if(RSSI_BT >=35) // >= -15dBm ++ initial_gain_psd = RSSI_BT*2; ++ else if((RSSI_BT >=33)&(RSSI_BT<35)) ++ initial_gain_psd = RSSI_BT*2+6; ++ else if((RSSI_BT >=24)&(RSSI_BT<33)) ++ initial_gain_psd = 70-(31-RSSI_BT); ++ else if((RSSI_BT >=19)&(RSSI_BT<24)) ++ initial_gain_psd = 64-((24-RSSI_BT)*4); ++ else if((RSSI_BT >=14)&(RSSI_BT<19)) ++ initial_gain_psd = 44-((18-RSSI_BT)*2); ++ else if((RSSI_BT >=8)&(RSSI_BT<14)) ++ initial_gain_psd = 35-(14-RSSI_BT); ++ else ++ initial_gain_psd = 0x1B; ++ } ++ else ++ { ++ if(rssi_ctrl == 1) // just for debug!! ++ initial_gain_psd = RSSI_BT_new ; ++ else ++ { ++ //need to do ++ initial_gain_psd = pDM_Odm->RSSI_Min; // PSD report based on RSSI ++ } ++ } ++ //if(RSSI_BT<0x17) ++ // RSSI_BT +=3; ++ //DbgPrint("PSD: RSSI_BT= %d\n", RSSI_BT); ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("PSD: RSSI_BT= %d\n", RSSI_BT)); ++ ++ //initialGainUpper = 0x5E; //Modify by neil chen ++ ++ if(pDM_Odm->bUserAssignLevel) ++ { ++ pDM_Odm->bUserAssignLevel = FALSE; ++ initialGainUpper = 0x7f; ++ } ++ else ++ { ++ initialGainUpper = 0x5E; ++ } ++ ++ /* ++ if (initial_gain_psd < 0x1a) ++ initial_gain_psd = 0x1a; ++ if (initial_gain_psd > initialGainUpper) ++ initial_gain_psd = initialGainUpper; ++ */ ++ ++ if(pDM_Odm->SupportICType==ODM_RTL8723A) ++ SSBT = RSSI_BT * 2 +0x3E; ++ else if((pDM_Odm->SupportICType==ODM_RTL8192C)||(pDM_Odm->SupportICType==ODM_RTL8192D)) ++ { ++ RSSI_BT = initial_gain_psd; ++ SSBT = RSSI_BT; ++ } ++ ++ //if(IS_HARDWARE_TYPE_8723AE(Adapter)) ++ // SSBT = RSSI_BT * 2 +0x3E; ++ //else if((IS_HARDWARE_TYPE_8192C(Adapter))||(IS_HARDWARE_TYPE_8192D(Adapter))) // Add by Gary ++ //{ ++ // RSSI_BT = initial_gain_psd; ++ // SSBT = RSSI_BT; ++ //} ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("PSD: SSBT= %d\n", SSBT)); ++ ODM_RT_TRACE( pDM_Odm,COMP_PSD, DBG_LOUD,("PSD: initial gain= 0x%x\n", initial_gain_psd)); ++ //DbgPrint("PSD: SSBT= %d", SSBT); ++ //need to do ++ //pMgntInfo->bDMInitialGainEnable = FALSE; ++ pDM_Odm->bDMInitialGainEnable = FALSE; ++ initial_gain = ODM_GetBBReg(pDM_Odm, 0xc50, bMaskDWord) & 0x7F; ++ ODM_SetBBReg(pDM_Odm, 0xc50, 0x7F, initial_gain_psd); ++ //1 Turn off 3-wire ++ ODM_SetBBReg(pDM_Odm, 0x88c, BIT20|BIT21|BIT22|BIT23, 0xF); ++ ++ //pts value = 128, 256, 512, 1024 ++ pts = 128; ++ ++ if(pts == 128) ++ { ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x0); ++ start_point = 64; ++ stop_point = 192; ++ } ++ else if(pts == 256) ++ { ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x1); ++ start_point = 128; ++ stop_point = 384; ++ } ++ else if(pts == 512) ++ { ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x2); ++ start_point = 256; ++ stop_point = 768; ++ } ++ else ++ { ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x3); ++ start_point = 512; ++ stop_point = 1536; ++ } ++ ++ ++//3 Skip WLAN channels if WLAN busy ++ ++ curTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast) - lastTxOkCnt; ++ curRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast) - lastRxOkCnt; ++ lastTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast); ++ lastRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast); ++ ++ PSD_skip_start=80; ++ PSD_skip_stop = 0; ++ wlan_channel = CurrentChannel & 0x0f; ++ ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD,DBG_LOUD,("PSD: current channel: %x, BW:%d \n", wlan_channel, Is40MHz)); ++ if(pDM_Odm->SupportICType==ODM_RTL8723A) ++ { ++#if(BT_30_SUPPORT == 1) ++ if(pDM_Odm->bBtHsOperation) ++ { ++ if(pDM_Odm->bLinked) ++ { ++ if(Is40MHz) ++ { ++ PSD_skip_start = ((wlan_channel-1)*5 -Is40MHz*10)-2; // Modify by Neil to add 10 chs to mask ++ PSD_skip_stop = (PSD_skip_start + (1+Is40MHz)*20)+4; ++ } ++ else ++ { ++ PSD_skip_start = ((wlan_channel-1)*5 -Is40MHz*10)-10; // Modify by Neil to add 10 chs to mask ++ PSD_skip_stop = (PSD_skip_start + (1+Is40MHz)*20)+18; ++ } ++ } ++ else ++ { ++ // mask for 40MHz ++ PSD_skip_start = ((wlan_channel-1)*5 -Is40MHz*10)-2; // Modify by Neil to add 10 chs to mask ++ PSD_skip_stop = (PSD_skip_start + (1+Is40MHz)*20)+4; ++ } ++ if(PSD_skip_start < 0) ++ PSD_skip_start = 0; ++ if(PSD_skip_stop >80) ++ PSD_skip_stop = 80; ++ } ++ else ++#endif ++ { ++ if((curRxOkCnt+curTxOkCnt) > 5) ++ { ++ if(Is40MHz) ++ { ++ PSD_skip_start = ((wlan_channel-1)*5 -Is40MHz*10)-2; // Modify by Neil to add 10 chs to mask ++ PSD_skip_stop = (PSD_skip_start + (1+Is40MHz)*20)+4; ++ } ++ else ++ { ++ PSD_skip_start = ((wlan_channel-1)*5 -Is40MHz*10)-10; // Modify by Neil to add 10 chs to mask ++ PSD_skip_stop = (PSD_skip_start + (1+Is40MHz)*20)+18; ++ } ++ ++ if(PSD_skip_start < 0) ++ PSD_skip_start = 0; ++ if(PSD_skip_stop >80) ++ PSD_skip_stop = 80; ++ } ++ } ++ } ++ else ++ { ++ if((curRxOkCnt+curTxOkCnt) > 1000) ++ { ++ PSD_skip_start = (wlan_channel-1)*5 -Is40MHz*10; ++ PSD_skip_stop = PSD_skip_start + (1+Is40MHz)*20; ++ } ++ } ++ ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD,DBG_LOUD,("PSD: Skip tone from %d to %d \n", PSD_skip_start, PSD_skip_stop)); ++ ++ for (n=0;n<80;n++) ++ { ++ if((n%20)==0) ++ { ++ channel = (n/20)*4 + 1; ++ /* ++ if(pDM_Odm->SupportICType==ODM_RTL8192D) ++ { ++ switch(channel) ++ { ++ case 1: ++ case 9: ++ group_idx = 0; ++ break; ++ case 5: ++ group_idx = 2; ++ break; ++ case 13: ++ group_idx = 1; ++ break; ++ } ++ ++ if((pHalData->MacPhyMode92D == SINGLEMAC_SINGLEPHY)||(pHalData->MacPhyMode92D == DUALMAC_SINGLEPHY)) ++ { ++ for(i = 0; i < SYN_Length; i++) ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, SYN[i], bMaskDWord, SYN_group[group_idx][i]); ++ ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, 0x3FF, channel); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, RF_CHNLBW, 0x3FF, channel); ++ } ++ else // DualMAC_DualPHY 2G ++ { ++ for(i = 0; i < SYN_Length; i++) ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, SYN[i], bMaskDWord, SYN_group[group_idx][i]); ++ ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, 0x3FF, channel); ++ } ++ } ++ else */ ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, 0x3FF, channel); ++ } ++ tone_idx = n%20; ++ if ((n>=PSD_skip_start) && (n PSD_report[n]) ++ PSD_report[n] = PSD_report_tmp; ++ ++ } ++ } ++ ++ PatchDCTone(pDM_Odm, PSD_report, initial_gain_psd); ++ ++ //----end ++ //1 Turn on RX ++ //Rx AGC on ++ ODM_SetBBReg(pDM_Odm, 0xC70, BIT0, 1); ++ ODM_SetBBReg(pDM_Odm, 0xC7C, BIT20, 1); ++ //CCK on ++ ODM_SetBBReg(pDM_Odm, rFPGA0_RFMOD, BIT24, 1); ++ //1 Turn on TX ++ //Resume TX Queue ++ ++ ODM_Write1Byte(pDM_Odm,REG_TXPAUSE, 0x00); ++ //Turn on 3-wire ++ ODM_SetBBReg(pDM_Odm, 0x88c, BIT20|BIT21|BIT22|BIT23, 0x0); ++ //1 Restore Current Settings ++ //Resume DIG ++ pDM_Odm->bDMInitialGainEnable = TRUE; ++ ODM_SetBBReg(pDM_Odm, 0xc50, 0x7F, initial_gain); ++ // restore originl center frequency ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, CurrentChannel); ++ ++ /* ++ if(pDM_Odm->SupportICType==ODM_RTL8192D) ++ { ++ if((pHalData->MacPhyMode92D == SINGLEMAC_SINGLEPHY)||(pHalData->MacPhyMode92D == DUALMAC_SINGLEPHY)) ++ { ++ PHY_SetRFReg(Adapter, RF_PATH_B, RF_CHNLBW, bMaskDWord, CurrentChannel); ++ PHY_SetRFReg(Adapter, RF_PATH_B, 0x25, bMaskDWord, SYN_RF25); ++ PHY_SetRFReg(Adapter, RF_PATH_B, 0x26, bMaskDWord, SYN_RF26); ++ PHY_SetRFReg(Adapter, RF_PATH_B, 0x27, bMaskDWord, SYN_RF27); ++ PHY_SetRFReg(Adapter, RF_PATH_B, 0x2B, bMaskDWord, SYN_RF2B); ++ PHY_SetRFReg(Adapter, RF_PATH_B, 0x2C, bMaskDWord, SYN_RF2C); ++ } ++ else // DualMAC_DualPHY ++ { ++ PHY_SetRFReg(Adapter, RF_PATH_A, 0x25, bMaskDWord, SYN_RF25); ++ PHY_SetRFReg(Adapter, RF_PATH_A, 0x26, bMaskDWord, SYN_RF26); ++ PHY_SetRFReg(Adapter, RF_PATH_A, 0x27, bMaskDWord, SYN_RF27); ++ PHY_SetRFReg(Adapter, RF_PATH_A, 0x2B, bMaskDWord, SYN_RF2B); ++ PHY_SetRFReg(Adapter, RF_PATH_A, 0x2C, bMaskDWord, SYN_RF2C); ++ } ++ }*/ ++ //Turn on CCA ++ ODM_SetBBReg(pDM_Odm, 0xC14, bMaskDWord, RXIQI); ++ //Restore RX idle low power ++ if(RxIdleLowPwr == TRUE) ++ ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 1); ++ ++ psd_cnt++; ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("PSD:psd_cnt = %d \n",psd_cnt)); ++ if (psd_cnt < ReScan) ++ ODM_SetTimer(pDM_Odm, &pDM_Odm->PSDTimer, Interval); ++ else ++ { ++ psd_cnt = 0; ++ for(i=0;i<80;i++) ++ //DbgPrint("psd_report[%d]= %d \n", 2402+i, PSD_report[i]); ++ RT_TRACE( COMP_PSD, DBG_LOUD,("psd_report[%d]= %d \n", 2402+i, PSD_report[i])); ++ ++ ++ GoodChannelDecision(pDM_Odm, PSD_report, PSD_bitmap,RSSI_BT, PSD_bitmap_memory); ++ ++ if(pDM_Odm->SupportICType==ODM_RTL8723A) ++ { ++ cur_byte_idx=0; ++ cur_bit_idx=0; ++ ++ //2 Restore H2C PSD Data to Last Data ++ H2C_PSD_DATA_last[0] = H2C_PSD_DATA[0]; ++ H2C_PSD_DATA_last[1] = H2C_PSD_DATA[1]; ++ H2C_PSD_DATA_last[2] = H2C_PSD_DATA[2]; ++ H2C_PSD_DATA_last[3] = H2C_PSD_DATA[3]; ++ H2C_PSD_DATA_last[4] = H2C_PSD_DATA[4]; ++ ++ ++ //2 Translate 80bit channel map to 40bit channel ++ for ( i=0;i<5;i++) ++ { ++ for(n=0;n<8;n++) ++ { ++ cur_byte_idx = i*2 + n/4; ++ cur_bit_idx = (n%4)*2; ++ if ( ((PSD_bitmap[cur_byte_idx]& BIT(cur_bit_idx)) != 0) && ((PSD_bitmap[cur_byte_idx]& BIT(cur_bit_idx+1)) != 0)) ++ H2C_PSD_DATA[i] = H2C_PSD_DATA[i] | (u1Byte) (1 << n); ++ } ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("H2C_PSD_DATA[%d]=0x%x\n" ,i, H2C_PSD_DATA[i])); ++ } ++ ++ //3 To Compare the difference ++ for ( i=0;i<5;i++) ++ { ++ if(H2C_PSD_DATA[i] !=H2C_PSD_DATA_last[i]) ++ { ++ FillH2CCmd(Adapter, H2C_92C_PSD_RESULT, 5, H2C_PSD_DATA); ++ ODM_RT_TRACE(pDM_Odm, COMP_PSD, DBG_LOUD,("Need to Update the AFH Map \n")); ++ break; ++ } ++ else ++ { ++ if(i==5) ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("Not need to Update\n")); ++ } ++ } ++ //pHalData->bPSDactive=FALSE; ++ ODM_SetTimer(pDM_Odm, &pDM_Odm->PSDTimer, 900); ++ ODM_RT_TRACE( pDM_Odm,COMP_PSD, DBG_LOUD,("Leave dm_PSD_Monitor\n")); ++ } ++ } ++} ++/* ++//Neil for Get BT RSSI ++// Be Triggered by BT C2H CMD ++VOID ++ODM_PSDGetRSSI( ++ IN u1Byte RSSI_BT) ++{ ++ ++ ++} ++ ++*/ ++ ++VOID ++ODM_PSDMonitor( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ //if(IS_HARDWARE_TYPE_8723AE(Adapter)) ++ ++ if(pDM_Odm->SupportICType == ODM_RTL8723A) //may need to add other IC type ++ { ++ if(pDM_Odm->SupportInterface==ODM_ITRF_PCIE) ++ { ++#if(BT_30_SUPPORT == 1) ++ if(pDM_Odm->bBtDisabled) //need to check upper layer connection ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD, ("odm_PSDMonitor, return for BT is disabled!!!\n")); ++ return; ++ } ++#endif ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD, ("odm_PSDMonitor\n")); ++ //if(pHalData->bPSDactive ==FALSE) ++ //{ ++ pDM_Odm->bPSDinProcess = TRUE; ++ //pHalData->bPSDactive=TRUE; ++ odm_PSD_Monitor(pDM_Odm); ++ pDM_Odm->bPSDinProcess = FALSE; ++ } ++ } ++ ++} ++VOID ++odm_PSDMonitorCallback( ++ PRT_TIMER pTimer ++) ++{ ++ PADAPTER Adapter = (PADAPTER)pTimer->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ ++ ++#if USE_WORKITEM ++ PlatformScheduleWorkItem(&pHalData->PSDMonitorWorkitem); ++#else ++ ODM_PSDMonitor(pDM_Odm); ++#endif ++} ++ ++VOID ++odm_PSDMonitorWorkItemCallback( ++ IN PVOID pContext ++ ) ++{ ++ PADAPTER Adapter = (PADAPTER)pContext; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ ++ ++ ODM_PSDMonitor(pDM_Odm); ++} ++ ++ ++ ++ //cosa debug tool need to modify ++ ++VOID ++ODM_PSDDbgControl( ++ IN PADAPTER Adapter, ++ IN u4Byte mode, ++ IN u4Byte btRssi ++ ) ++{ ++#if (DEV_BUS_TYPE == RT_PCI_INTERFACE) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD, (" Monitor mode=%d, btRssi=%d\n", mode, btRssi)); ++ if(mode) ++ { ++ pDM_Odm->RSSI_BT = (u1Byte)btRssi; ++ pDM_Odm->bUserAssignLevel = TRUE; ++ ODM_SetTimer( pDM_Odm, &pDM_Odm->PSDTimer, 0); //ms ++ } ++ else ++ { ++ ODM_CancelTimer(pDM_Odm, &pDM_Odm->PSDTimer); ++ } ++#endif ++} ++ ++ ++//#if(DEV_BUS_TYPE == RT_PCI_INTERFACE)|(DEV_BUS_TYPE == RT_USB_INTERFACE) ++ ++void odm_RXHPInit( ++ IN PDM_ODM_T pDM_Odm) ++{ ++#if (DEV_BUS_TYPE == RT_PCI_INTERFACE)|(DEV_BUS_TYPE == RT_USB_INTERFACE) ++ pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; ++ u1Byte index; ++ ++ pRX_HP_Table->RXHP_enable = TRUE; ++ pRX_HP_Table->RXHP_flag = 0; ++ pRX_HP_Table->PSD_func_trigger = 0; ++ pRX_HP_Table->Pre_IGI = 0x20; ++ pRX_HP_Table->Cur_IGI = 0x20; ++ pRX_HP_Table->Cur_pw_th = pw_th_10dB; ++ pRX_HP_Table->Pre_pw_th = pw_th_10dB; ++ for(index=0; index<80; index++) ++ pRX_HP_Table->PSD_bitmap_RXHP[index] = 1; ++ ++#if(DEV_BUS_TYPE == RT_USB_INTERFACE) ++ pRX_HP_Table->TP_Mode = Idle_Mode; ++#endif ++#endif ++} ++ ++void odm_RXHP( ++ IN PDM_ODM_T pDM_Odm) ++{ ++#if( DM_ODM_SUPPORT_TYPE & (ODM_MP)) ++#if (DEV_BUS_TYPE == RT_PCI_INTERFACE) | (DEV_BUS_TYPE == RT_USB_INTERFACE) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; ++ PFALSE_ALARM_STATISTICS FalseAlmCnt = &(pDM_Odm->FalseAlmCnt); ++ ++ u1Byte i, j, sum; ++ u1Byte Is40MHz; ++ s1Byte Intf_diff_idx, MIN_Intf_diff_idx = 16; ++ s4Byte cur_channel; ++ u1Byte ch_map_intf_5M[17] = {0}; ++ static u4Byte FA_TH = 0; ++ static u1Byte psd_intf_flag = 0; ++ static s4Byte curRssi = 0; ++ static s4Byte preRssi = 0; ++ static u1Byte PSDTriggerCnt = 1; ++ ++ u1Byte RX_HP_enable = (u1Byte)(ODM_GetBBReg(pDM_Odm, rOFDM0_XAAGCCore2, bMaskDWord)>>31); // for debug!! ++ ++#if(DEV_BUS_TYPE == RT_USB_INTERFACE) ++ static s8Byte lastTxOkCnt = 0, lastRxOkCnt = 0; ++ s8Byte curTxOkCnt, curRxOkCnt; ++ s8Byte curTPOkCnt; ++ s8Byte TP_Acc3, TP_Acc5; ++ static s8Byte TP_Buff[5] = {0}; ++ static u1Byte pre_state = 0, pre_state_flag = 0; ++ static u1Byte Intf_HighTP_flag = 0, De_counter = 16; ++ static u1Byte TP_Degrade_flag = 0; ++#endif ++ static u1Byte LatchCnt = 0; ++ ++ if((pDM_Odm->SupportICType == ODM_RTL8723A)||(pDM_Odm->SupportICType == ODM_RTL8188E)) ++ return; ++ //AGC RX High Power Mode is only applied on 2G band in 92D!!! ++ if(pDM_Odm->SupportICType == ODM_RTL8192D) ++ { ++ if(*(pDM_Odm->pBandType) != ODM_BAND_2_4G) ++ return; ++ } ++ ++ if(!(pDM_Odm->SupportAbility==ODM_BB_RXHP)) ++ return; ++ ++ ++ //RX HP ON/OFF ++ if(RX_HP_enable == 1) ++ pRX_HP_Table->RXHP_enable = FALSE; ++ else ++ pRX_HP_Table->RXHP_enable = TRUE; ++ ++ if(pRX_HP_Table->RXHP_enable == FALSE) ++ { ++ if(pRX_HP_Table->RXHP_flag == 1) ++ { ++ pRX_HP_Table->RXHP_flag = 0; ++ psd_intf_flag = 0; ++ } ++ return; ++ } ++ ++#if(DEV_BUS_TYPE == RT_USB_INTERFACE) ++ //2 Record current TP for USB interface ++ curTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast)-lastTxOkCnt; ++ curRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast)-lastRxOkCnt; ++ lastTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast); ++ lastRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast); ++ ++ curTPOkCnt = curTxOkCnt+curRxOkCnt; ++ TP_Buff[0] = curTPOkCnt; // current TP ++ TP_Acc3 = PlatformDivision64((TP_Buff[1]+TP_Buff[2]+TP_Buff[3]), 3); ++ TP_Acc5 = PlatformDivision64((TP_Buff[0]+TP_Buff[1]+TP_Buff[2]+TP_Buff[3]+TP_Buff[4]), 5); ++ ++ if(TP_Acc5 < 1000) ++ pRX_HP_Table->TP_Mode = Idle_Mode; ++ else if((1000 < TP_Acc5)&&(TP_Acc5 < 3750000)) ++ pRX_HP_Table->TP_Mode = Low_TP_Mode; ++ else ++ pRX_HP_Table->TP_Mode = High_TP_Mode; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RX HP TP Mode = %d\n", pRX_HP_Table->TP_Mode)); ++ // Since TP result would be sampled every 2 sec, it needs to delay 4sec to wait PSD processing. ++ // When LatchCnt = 0, we would Get PSD result. ++ if(TP_Degrade_flag == 1) ++ { ++ LatchCnt--; ++ if(LatchCnt == 0) ++ { ++ TP_Degrade_flag = 0; ++ } ++ } ++ // When PSD function triggered by TP degrade 20%, and Interference Flag = 1 ++ // Set a De_counter to wait IGI = upper bound. If time is UP, the Interference flag will be pull down. ++ if(Intf_HighTP_flag == 1) ++ { ++ De_counter--; ++ if(De_counter == 0) ++ { ++ Intf_HighTP_flag = 0; ++ psd_intf_flag = 0; ++ } ++ } ++#endif ++ ++ //2 AGC RX High Power Mode by PSD only applied to STA Mode ++ //3 NOT applied 1. Ad Hoc Mode. ++ //3 NOT applied 2. AP Mode ++ if ((pMgntInfo->mAssoc) && (!pMgntInfo->mIbss) && (!ACTING_AS_AP(Adapter))) ++ { ++ Is40MHz = *(pDM_Odm->pBandWidth); ++ curRssi = pDM_Odm->RSSI_Min; ++ cur_channel = ODM_GetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, 0x0fff) & 0x0f; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RXHP RX HP flag = %d\n", pRX_HP_Table->RXHP_flag)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RXHP FA = %d\n", FalseAlmCnt->Cnt_all)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RXHP cur RSSI = %d, pre RSSI=%d\n", curRssi, preRssi)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RXHP current CH = %d\n", cur_channel)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RXHP Is 40MHz = %d\n", Is40MHz)); ++ //2 PSD function would be triggered ++ //3 1. Every 4 sec for PCIE ++ //3 2. Before TP Mode (Idle TP<4kbps) for USB ++ //3 3. After TP Mode (High TP) for USB ++ if((curRssi > 68) && (pRX_HP_Table->RXHP_flag == 0)) // Only RSSI>TH and RX_HP_flag=0 will Do PSD process ++ { ++#if (DEV_BUS_TYPE == RT_USB_INTERFACE) ++ //2 Before TP Mode ==> PSD would be trigger every 4 sec ++ if(pRX_HP_Table->TP_Mode == Idle_Mode) //2.1 less wlan traffic <4kbps ++ { ++#endif ++ if(PSDTriggerCnt == 1) ++ { ++ odm_PSD_RXHP(pDM_Odm); ++ pRX_HP_Table->PSD_func_trigger = 1; ++ PSDTriggerCnt = 0; ++ } ++ else ++ { ++ PSDTriggerCnt++; ++ } ++#if(DEV_BUS_TYPE == RT_USB_INTERFACE) ++ } ++ //2 After TP Mode ==> Check if TP degrade larger than 20% would trigger PSD function ++ if(pRX_HP_Table->TP_Mode == High_TP_Mode) ++ { ++ if((pre_state_flag == 0)&&(LatchCnt == 0)) ++ { ++ // TP var < 5% ++ if((((curTPOkCnt-TP_Acc3)*20)<(TP_Acc3))&&(((curTPOkCnt-TP_Acc3)*20)>(-TP_Acc3))) ++ { ++ pre_state++; ++ if(pre_state == 3) // hit pre_state condition => consecutive 3 times ++ { ++ pre_state_flag = 1; ++ pre_state = 0; ++ } ++ ++ } ++ else ++ { ++ pre_state = 0; ++ } ++ } ++ //3 If pre_state_flag=1 ==> start to monitor TP degrade 20% ++ if(pre_state_flag == 1) ++ { ++ if(((TP_Acc3-curTPOkCnt)*5)>(TP_Acc3)) // degrade 20% ++ { ++ odm_PSD_RXHP(pDM_Odm); ++ pRX_HP_Table->PSD_func_trigger = 1; ++ TP_Degrade_flag = 1; ++ LatchCnt = 2; ++ pre_state_flag = 0; ++ } ++ else if(((TP_Buff[2]-curTPOkCnt)*5)>TP_Buff[2]) ++ { ++ odm_PSD_RXHP(pDM_Odm); ++ pRX_HP_Table->PSD_func_trigger = 1; ++ TP_Degrade_flag = 1; ++ LatchCnt = 2; ++ pre_state_flag = 0; ++ } ++ else if(((TP_Buff[3]-curTPOkCnt)*5)>TP_Buff[3]) ++ { ++ odm_PSD_RXHP(pDM_Odm); ++ pRX_HP_Table->PSD_func_trigger = 1; ++ TP_Degrade_flag = 1; ++ LatchCnt = 2; ++ pre_state_flag = 0; ++ } ++ } ++ } ++#endif ++} ++ ++#if (DEV_BUS_TYPE == RT_USB_INTERFACE) ++ for (i=0;i<4;i++) ++ { ++ TP_Buff[4-i] = TP_Buff[3-i]; ++ } ++#endif ++ //2 Update PSD bitmap according to PSD report ++ if((pRX_HP_Table->PSD_func_trigger == 1)&&(LatchCnt == 0)) ++ { ++ //2 Separate 80M bandwidth into 16 group with smaller 5M BW. ++ for (i = 0 ; i < 16 ; i++) ++ { ++ sum = 0; ++ for(j = 0; j < 5 ; j++) ++ sum += pRX_HP_Table->PSD_bitmap_RXHP[5*i + j]; ++ ++ if(sum < 5) ++ { ++ ch_map_intf_5M[i] = 1; // interference flag ++ } ++ } ++ //=============just for debug========================= ++ //for(i=0;i<16;i++) ++ //DbgPrint("RX HP: ch_map_intf_5M[%d] = %d\n", i, ch_map_intf_5M[i]); ++ //=============================================== ++ //2 Mask target channel 5M index ++ for(i = 0; i < (4+4*Is40MHz) ; i++) ++ { ++ ch_map_intf_5M[cur_channel - (1+2*Is40MHz) + i] = 0; ++ } ++ ++ psd_intf_flag = 0; ++ for(i = 0; i < 16; i++) ++ { ++ if(ch_map_intf_5M[i] == 1) ++ { ++ psd_intf_flag = 1; // interference is detected!!! ++ break; ++ } ++ } ++ ++#if (DEV_BUS_TYPE == RT_USB_INTERFACE) ++ if(pRX_HP_Table->TP_Mode!=Idle_Mode) ++ { ++ if(psd_intf_flag == 1) // to avoid psd_intf_flag always 1 ++ { ++ Intf_HighTP_flag = 1; ++ De_counter = 32; // 0x1E -> 0x3E needs 32 times by each IGI step =1 ++ } ++ } ++#endif ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RX HP psd_intf_flag = %d\n", psd_intf_flag)); ++ //2 Distance between target channel and interference ++ for(i = 0; i < 16; i++) ++ { ++ if(ch_map_intf_5M[i] == 1) ++ { ++ Intf_diff_idx = ((cur_channel+Is40MHz-(i+1))>0) ? (s1Byte)(cur_channel-2*Is40MHz-(i-2)) : (s1Byte)((i+1)-(cur_channel+2*Is40MHz)); ++ if(Intf_diff_idx < MIN_Intf_diff_idx) ++ MIN_Intf_diff_idx = Intf_diff_idx; // the min difference index between interference and target ++ } ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RX HP MIN_Intf_diff_idx = %d\n", MIN_Intf_diff_idx)); ++ //2 Choose False Alarm Threshold ++ switch (MIN_Intf_diff_idx){ ++ case 0: ++ case 1: ++ case 2: ++ case 3: ++ FA_TH = FA_RXHP_TH1; ++ break; ++ case 4: // CH5 ++ case 5: // CH6 ++ FA_TH = FA_RXHP_TH2; ++ break; ++ case 6: // CH7 ++ case 7: // CH8 ++ FA_TH = FA_RXHP_TH3; ++ break; ++ case 8: // CH9 ++ case 9: //CH10 ++ FA_TH = FA_RXHP_TH4; ++ break; ++ case 10: ++ case 11: ++ case 12: ++ case 13: ++ case 14: ++ case 15: ++ FA_TH = FA_RXHP_TH5; ++ break; ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RX HP FA_TH = %d\n", FA_TH)); ++ pRX_HP_Table->PSD_func_trigger = 0; ++ } ++ //1 Monitor RSSI variation to choose the suitable IGI or Exit AGC RX High Power Mode ++ if(pRX_HP_Table->RXHP_flag == 1) ++ { ++ if ((curRssi > 80)&&(preRssi < 80)) ++ { ++ pRX_HP_Table->Cur_IGI = LNA_Low_Gain_1; ++ } ++ else if ((curRssi < 80)&&(preRssi > 80)) ++ { ++ pRX_HP_Table->Cur_IGI = LNA_Low_Gain_2; ++ } ++ else if ((curRssi > 72)&&(preRssi < 72)) ++ { ++ pRX_HP_Table->Cur_IGI = LNA_Low_Gain_2; ++ } ++ else if ((curRssi < 72)&&( preRssi > 72)) ++ { ++ pRX_HP_Table->Cur_IGI = LNA_Low_Gain_3; ++ } ++ else if (curRssi < 68) //RSSI is NOT large enough!!==> Exit AGC RX High Power Mode ++ { ++ pRX_HP_Table->Cur_pw_th = pw_th_10dB; ++ pRX_HP_Table->RXHP_flag = 0; // Back to Normal DIG Mode ++ psd_intf_flag = 0; ++ } ++ } ++ else // pRX_HP_Table->RXHP_flag == 0 ++ { ++ //1 Decide whether to enter AGC RX High Power Mode ++ if ((curRssi > 70) && (psd_intf_flag == 1) && (FalseAlmCnt->Cnt_all > FA_TH) && ++ (pDM_DigTable->CurIGValue == pDM_DigTable->rx_gain_range_max)) ++ { ++ if (curRssi > 80) ++ { ++ pRX_HP_Table->Cur_IGI = LNA_Low_Gain_1; ++ } ++ else if (curRssi > 72) ++ { ++ pRX_HP_Table->Cur_IGI = LNA_Low_Gain_2; ++ } ++ else ++ { ++ pRX_HP_Table->Cur_IGI = LNA_Low_Gain_3; ++ } ++ pRX_HP_Table->Cur_pw_th = pw_th_16dB; //RegC54[9:8]=2'b11: to enter AGC Flow 3 ++ pRX_HP_Table->First_time_enter = TRUE; ++ pRX_HP_Table->RXHP_flag = 1; // RXHP_flag=1: AGC RX High Power Mode, RXHP_flag=0: Normal DIG Mode ++ } ++ } ++ preRssi = curRssi; ++ odm_Write_RXHP(pDM_Odm); ++ } ++#endif //#if( DM_ODM_SUPPORT_TYPE & (ODM_MP)) ++#endif //#if (DEV_BUS_TYPE == RT_PCI_INTERFACE) | (DEV_BUS_TYPE == RT_USB_INTERFACE) ++} ++ ++void odm_Write_RXHP( ++ IN PDM_ODM_T pDM_Odm) ++{ ++ pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; ++ u4Byte currentIGI; ++ ++ if(pRX_HP_Table->Cur_IGI != pRX_HP_Table->Pre_IGI) ++ { ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskByte0, pRX_HP_Table->Cur_IGI); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XBAGCCore1, bMaskByte0, pRX_HP_Table->Cur_IGI); ++ } ++ ++ if(pRX_HP_Table->Cur_pw_th != pRX_HP_Table->Pre_pw_th) ++{ ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore2, BIT8|BIT9, pRX_HP_Table->Cur_pw_th); // RegC54[9:8]=2'b11: AGC Flow 3 ++ } ++ ++ if(pRX_HP_Table->RXHP_flag == 0) ++ { ++ pRX_HP_Table->Cur_IGI = 0x20; ++ } ++ else ++ { ++ currentIGI = ODM_GetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskByte0); ++ if(currentIGI<0x50) ++ { ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskByte0, pRX_HP_Table->Cur_IGI); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XBAGCCore1, bMaskByte0, pRX_HP_Table->Cur_IGI); ++ } ++ } ++ pRX_HP_Table->Pre_IGI = pRX_HP_Table->Cur_IGI; ++ pRX_HP_Table->Pre_pw_th = pRX_HP_Table->Cur_pw_th; ++ ++} ++ ++VOID ++odm_PSD_RXHP( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ unsigned int pts, start_point, stop_point, initial_gain ; ++ static u1Byte PSD_bitmap_memory[80], init_memory = 0; ++ static u1Byte psd_cnt=0; ++ static u4Byte PSD_report[80], PSD_report_tmp; ++ static u8Byte lastTxOkCnt=0, lastRxOkCnt=0; ++ u1Byte idx[20]={96,99,102,106,109,112,115,118,122,125, ++ 0,3,6,10,13,16,19,22,26,29}; ++ u1Byte n, i, channel, BBReset,tone_idx; ++ u1Byte PSD_bitmap[10], SSBT=0,initial_gain_psd=0, RSSI_BT=0, initialGainUpper; ++ s4Byte PSD_skip_start, PSD_skip_stop; ++ u4Byte CurrentChannel, RXIQI, RxIdleLowPwr, wlan_channel; ++ u4Byte ReScan, Interval, Is40MHz; ++ u8Byte curTxOkCnt, curRxOkCnt; ++ //--------------2G band synthesizer for 92D switch RF channel using----------------- ++ u1Byte group_idx=0; ++ u4Byte SYN_RF25=0, SYN_RF26=0, SYN_RF27=0, SYN_RF2B=0, SYN_RF2C=0; ++ u4Byte SYN[5] = {0x25, 0x26, 0x27, 0x2B, 0x2C}; // synthesizer RF register for 2G channel ++ u4Byte SYN_group[3][5] = {{0x643BC, 0xFC038, 0x77C1A, 0x41289, 0x01840}, // For CH1,2,4,9,10.11.12 {0x643BC, 0xFC038, 0x77C1A, 0x41289, 0x01840} ++ {0x643BC, 0xFC038, 0x07C1A, 0x41289, 0x01840}, // For CH3,13,14 ++ {0x243BC, 0xFC438, 0x07C1A, 0x4128B, 0x0FC41}}; // For Ch5,6,7,8 ++ //--------------------- Add by Gary for Debug setting ---------------------- ++ s4Byte psd_result = 0; ++ u1Byte RSSI_BT_new = (u1Byte) ODM_GetBBReg(pDM_Odm, 0xB9C, 0xFF); ++ u1Byte rssi_ctrl = (u1Byte) ODM_GetBBReg(pDM_Odm, 0xB38, 0xFF); ++ //--------------------------------------------------------------------- ++ ++ if(pMgntInfo->bScanInProgress) ++ { ++ return; ++ } ++ ++ ReScan = PSD_RESCAN; ++ Interval = SCAN_INTERVAL; ++ ++ ++ //1 Initialization ++ if(init_memory == 0) ++ { ++ RT_TRACE( COMP_PSD, DBG_LOUD,("Init memory\n")); ++ for(i = 0; i < 80; i++) ++ PSD_bitmap_memory[i] = 0xFF; // channel is always good ++ init_memory = 1; ++ } ++ if(psd_cnt == 0) ++ { ++ RT_TRACE(COMP_PSD, DBG_LOUD,("Enter dm_PSD_Monitor\n")); ++ for(i = 0; i < 80; i++) ++ PSD_report[i] = 0; ++ } ++ ++ //1 Backup Current Settings ++ CurrentChannel = ODM_GetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask); ++ if(pDM_Odm->SupportICType == ODM_RTL8192D) ++ { ++ //2 Record Current synthesizer parameters based on current channel ++ if((*(pDM_Odm->pMacPhyMode)==ODM_SMSP)||(*(pDM_Odm->pMacPhyMode)==ODM_DMSP)) ++ { ++ SYN_RF25 = ODM_GetRFReg(pDM_Odm, RF_PATH_B, 0x25, bMaskDWord); ++ SYN_RF26 = ODM_GetRFReg(pDM_Odm, RF_PATH_B, 0x26, bMaskDWord); ++ SYN_RF27 = ODM_GetRFReg(pDM_Odm, RF_PATH_B, 0x27, bMaskDWord); ++ SYN_RF2B = ODM_GetRFReg(pDM_Odm, RF_PATH_B, 0x2B, bMaskDWord); ++ SYN_RF2C = ODM_GetRFReg(pDM_Odm, RF_PATH_B, 0x2C, bMaskDWord); ++ } ++ else // DualMAC_DualPHY 2G ++ { ++ SYN_RF25 = ODM_GetRFReg(pDM_Odm, RF_PATH_A, 0x25, bMaskDWord); ++ SYN_RF26 = ODM_GetRFReg(pDM_Odm, RF_PATH_A, 0x26, bMaskDWord); ++ SYN_RF27 = ODM_GetRFReg(pDM_Odm, RF_PATH_A, 0x27, bMaskDWord); ++ SYN_RF2B = ODM_GetRFReg(pDM_Odm, RF_PATH_A, 0x2B, bMaskDWord); ++ SYN_RF2C = ODM_GetRFReg(pDM_Odm, RF_PATH_A, 0x2C, bMaskDWord); ++ } ++ } ++ RXIQI = ODM_GetBBReg(pDM_Odm, 0xC14, bMaskDWord); ++ RxIdleLowPwr = (ODM_GetBBReg(pDM_Odm, 0x818, bMaskDWord)&BIT28)>>28; ++ Is40MHz = *(pDM_Odm->pBandWidth); ++ ODM_RT_TRACE(pDM_Odm, COMP_PSD, DBG_LOUD,("PSD Scan Start\n")); ++ //1 Turn off CCK ++ ODM_SetBBReg(pDM_Odm, rFPGA0_RFMOD, BIT24, 0); ++ //1 Turn off TX ++ //Pause TX Queue ++ ODM_Write1Byte(pDM_Odm, REG_TXPAUSE, 0xFF); ++ //Force RX to stop TX immediately ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_AC, bRFRegOffsetMask, 0x32E13); ++ //1 Turn off RX ++ //Rx AGC off RegC70[0]=0, RegC7C[20]=0 ++ ODM_SetBBReg(pDM_Odm, 0xC70, BIT0, 0); ++ ODM_SetBBReg(pDM_Odm, 0xC7C, BIT20, 0); ++ //Turn off CCA ++ ODM_SetBBReg(pDM_Odm, 0xC14, bMaskDWord, 0x0); ++ //BB Reset ++ BBReset = ODM_Read1Byte(pDM_Odm, 0x02); ++ ODM_Write1Byte(pDM_Odm, 0x02, BBReset&(~BIT0)); ++ ODM_Write1Byte(pDM_Odm, 0x02, BBReset|BIT0); ++ //1 Leave RX idle low power ++ ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x0); ++ //1 Fix initial gain ++ RSSI_BT = RSSI_BT_new; ++ RT_TRACE(COMP_PSD, DBG_LOUD,("PSD: RSSI_BT= %d\n", RSSI_BT)); ++ ++ if(rssi_ctrl == 1) // just for debug!! ++ initial_gain_psd = RSSI_BT_new; ++ else ++ initial_gain_psd = pDM_Odm->RSSI_Min; // PSD report based on RSSI ++ ++ RT_TRACE(COMP_PSD, DBG_LOUD,("PSD: RSSI_BT= %d\n", RSSI_BT)); ++ ++ initialGainUpper = 0x54; ++ ++ RSSI_BT = initial_gain_psd; ++ //SSBT = RSSI_BT; ++ ++ //RT_TRACE( COMP_PSD, DBG_LOUD,("PSD: SSBT= %d\n", SSBT)); ++ RT_TRACE( COMP_PSD, DBG_LOUD,("PSD: initial gain= 0x%x\n", initial_gain_psd)); ++ ++ pDM_Odm->bDMInitialGainEnable = FALSE; ++ initial_gain = ODM_GetBBReg(pDM_Odm, 0xc50, bMaskDWord) & 0x7F; ++ ODM_SetBBReg(pDM_Odm, 0xc50, 0x7F, initial_gain_psd); ++ //1 Turn off 3-wire ++ ODM_SetBBReg(pDM_Odm, 0x88c, BIT20|BIT21|BIT22|BIT23, 0xF); ++ ++ //pts value = 128, 256, 512, 1024 ++ pts = 128; ++ ++ if(pts == 128) ++ { ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x0); ++ start_point = 64; ++ stop_point = 192; ++ } ++ else if(pts == 256) ++ { ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x1); ++ start_point = 128; ++ stop_point = 384; ++ } ++ else if(pts == 512) ++ { ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x2); ++ start_point = 256; ++ stop_point = 768; ++ } ++ else ++ { ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x3); ++ start_point = 512; ++ stop_point = 1536; ++ } ++ ++ ++//3 Skip WLAN channels if WLAN busy ++ curTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast) - lastTxOkCnt; ++ curRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast) - lastRxOkCnt; ++ lastTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast); ++ lastRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast); ++ ++ PSD_skip_start=80; ++ PSD_skip_stop = 0; ++ wlan_channel = CurrentChannel & 0x0f; ++ ++ RT_TRACE(COMP_PSD,DBG_LOUD,("PSD: current channel: %x, BW:%d \n", wlan_channel, Is40MHz)); ++ ++ if((curRxOkCnt+curTxOkCnt) > 1000) ++ { ++ PSD_skip_start = (wlan_channel-1)*5 -Is40MHz*10; ++ PSD_skip_stop = PSD_skip_start + (1+Is40MHz)*20; ++ } ++ ++ RT_TRACE(COMP_PSD,DBG_LOUD,("PSD: Skip tone from %d to %d \n", PSD_skip_start, PSD_skip_stop)); ++ ++ for (n=0;n<80;n++) ++ { ++ if((n%20)==0) ++ { ++ channel = (n/20)*4 + 1; ++ if(pDM_Odm->SupportICType == ODM_RTL8192D) ++ { ++ switch(channel) ++ { ++ case 1: ++ case 9: ++ group_idx = 0; ++ break; ++ case 5: ++ group_idx = 2; ++ break; ++ case 13: ++ group_idx = 1; ++ break; ++ } ++ if((*(pDM_Odm->pMacPhyMode)==ODM_SMSP)||(*(pDM_Odm->pMacPhyMode)==ODM_DMSP)) ++ { ++ for(i = 0; i < SYN_Length; i++) ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, SYN[i], bMaskDWord, SYN_group[group_idx][i]); ++ ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, 0x3FF, channel); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, RF_CHNLBW, 0x3FF, channel); ++ } ++ else // DualMAC_DualPHY 2G ++ { ++ for(i = 0; i < SYN_Length; i++) ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, SYN[i], bMaskDWord, SYN_group[group_idx][i]); ++ ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, 0x3FF, channel); ++ } ++ } ++ else ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, 0x3FF, channel); ++ } ++ tone_idx = n%20; ++ if ((n>=PSD_skip_start) && (n PSD_report[n]) ++ PSD_report[n] = PSD_report_tmp; ++ ++ } ++ } ++ ++ PatchDCTone(pDM_Odm, PSD_report, initial_gain_psd); ++ ++ //----end ++ //1 Turn on RX ++ //Rx AGC on ++ ODM_SetBBReg(pDM_Odm, 0xC70, BIT0, 1); ++ ODM_SetBBReg(pDM_Odm, 0xC7C, BIT20, 1); ++ //CCK on ++ ODM_SetBBReg(pDM_Odm, rFPGA0_RFMOD, BIT24, 1); ++ //1 Turn on TX ++ //Resume TX Queue ++ ODM_Write1Byte(pDM_Odm, REG_TXPAUSE, 0x00); ++ //Turn on 3-wire ++ ODM_SetBBReg(pDM_Odm, 0x88c, BIT20|BIT21|BIT22|BIT23, 0x0); ++ //1 Restore Current Settings ++ //Resume DIG ++ pDM_Odm->bDMInitialGainEnable= TRUE; ++ ODM_SetBBReg(pDM_Odm, 0xc50, 0x7F, initial_gain); ++ // restore originl center frequency ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, CurrentChannel); ++ if(pDM_Odm->SupportICType == ODM_RTL8192D) ++ { ++ if((*(pDM_Odm->pMacPhyMode)==ODM_SMSP)||(*(pDM_Odm->pMacPhyMode)==ODM_DMSP)) ++ { ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, RF_CHNLBW, bMaskDWord, CurrentChannel); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, 0x25, bMaskDWord, SYN_RF25); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, 0x26, bMaskDWord, SYN_RF26); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, 0x27, bMaskDWord, SYN_RF27); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, 0x2B, bMaskDWord, SYN_RF2B); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, 0x2C, bMaskDWord, SYN_RF2C); ++ } ++ else // DualMAC_DualPHY ++ { ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x25, bMaskDWord, SYN_RF25); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x26, bMaskDWord, SYN_RF26); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x27, bMaskDWord, SYN_RF27); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x2B, bMaskDWord, SYN_RF2B); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x2C, bMaskDWord, SYN_RF2C); ++ } ++ } ++ //Turn on CCA ++ ODM_SetBBReg(pDM_Odm, 0xC14, bMaskDWord, RXIQI); ++ //Restore RX idle low power ++ if(RxIdleLowPwr == TRUE) ++ ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 1); ++ ++ psd_cnt++; ++ //gPrint("psd cnt=%d\n", psd_cnt); ++ ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("PSD:psd_cnt = %d \n",psd_cnt)); ++ if (psd_cnt < ReScan) ++ { ++ ODM_SetTimer(pDM_Odm, &pRX_HP_Table->PSDTimer, Interval); //ms ++ } ++ else ++ { ++ psd_cnt = 0; ++ for(i=0;i<80;i++) ++ RT_TRACE( COMP_PSD, DBG_LOUD,("psd_report[%d]= %d \n", 2402+i, PSD_report[i])); ++ //DbgPrint("psd_report[%d]= %d \n", 2402+i, PSD_report[i]); ++ ++ GoodChannelDecision(pDM_Odm, PSD_report, PSD_bitmap,RSSI_BT, PSD_bitmap_memory); ++ ++ } ++ } ++ ++VOID ++odm_PSD_RXHPCallback( ++ PRT_TIMER pTimer ++) ++{ ++ PADAPTER Adapter = (PADAPTER)pTimer->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; ++ ++#if DEV_BUS_TYPE==RT_PCI_INTERFACE ++ #if USE_WORKITEM ++ ODM_ScheduleWorkItem(&pRX_HP_Table->PSDTimeWorkitem); ++ #else ++ odm_PSD_RXHP(pDM_Odm); ++ #endif ++#else ++ ODM_ScheduleWorkItem(&pRX_HP_Table->PSDTimeWorkitem); ++#endif ++ ++ } ++ ++VOID ++odm_PSD_RXHPWorkitemCallback( ++ IN PVOID pContext ++ ) ++{ ++ PADAPTER pAdapter = (PADAPTER)pContext; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ ++ odm_PSD_RXHP(pDM_Odm); ++} ++ ++#endif //#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ++// ++// 2011/09/22 MH Add for 92D global spin lock utilization. ++// ++VOID ++odm_GlobalAdapterCheck( ++ IN VOID ++ ) ++{ ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ++ //sherry delete flag 20110517 ++#if (DEV_BUS_TYPE == RT_PCI_INTERFACE) ++ ACQUIRE_GLOBAL_SPINLOCK(&GlobalSpinlockForGlobalAdapterList); ++#else ++ ACQUIRE_GLOBAL_MUTEX(GlobalMutexForGlobalAdapterList); ++#endif ++ ++#if (DEV_BUS_TYPE == RT_PCI_INTERFACE) ++ RELEASE_GLOBAL_SPINLOCK(&GlobalSpinlockForGlobalAdapterList); ++#else ++ RELEASE_GLOBAL_MUTEX(GlobalMutexForGlobalAdapterList); ++#endif ++ ++#endif ++ ++} // odm_GlobalAdapterCheck ++ ++ ++ ++// ++// 2011/12/02 MH Copy from MP oursrc for temporarily test. ++// ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++VOID ++odm_OFDMTXPathDiversity_92C( ++ IN PADAPTER Adapter) ++{ ++// HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ PRT_WLAN_STA pEntry; ++ u1Byte i, DefaultRespPath = 0; ++ s4Byte MinRSSI = 0xFF; ++ pPD_T pDM_PDTable = &Adapter->DM_PDTable; ++ pDM_PDTable->OFDMTXPath = 0; ++ ++ //1 Default Port ++ if(pMgntInfo->mAssoc) ++ { ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_OFDMTXPathDiversity_92C: Default port RSSI[0]=%d, RSSI[1]=%d\n", ++ Adapter->RxStats.RxRSSIPercentage[0], Adapter->RxStats.RxRSSIPercentage[1])); ++ if(Adapter->RxStats.RxRSSIPercentage[0] > Adapter->RxStats.RxRSSIPercentage[1]) ++ { ++ pDM_PDTable->OFDMTXPath = pDM_PDTable->OFDMTXPath & (~BIT0); ++ MinRSSI = Adapter->RxStats.RxRSSIPercentage[1]; ++ DefaultRespPath = 0; ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_OFDMTXPathDiversity_92C: Default port Select Path-0\n")); ++ } ++ else ++ { ++ pDM_PDTable->OFDMTXPath = pDM_PDTable->OFDMTXPath | BIT0; ++ MinRSSI = Adapter->RxStats.RxRSSIPercentage[0]; ++ DefaultRespPath = 1; ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_OFDMTXPathDiversity_92C: Default port Select Path-1\n")); ++ } ++ //RT_TRACE( COMP_SWAS, DBG_LOUD, ("pDM_PDTable->OFDMTXPath =0x%x\n",pDM_PDTable->OFDMTXPath)); ++ } ++ //1 Extension Port ++ for(i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) ++ { ++ if(IsAPModeExist(Adapter) && GetFirstExtAdapter(Adapter) != NULL) ++ pEntry = AsocEntry_EnumStation(GetFirstExtAdapter(Adapter), i); ++ else ++ pEntry = AsocEntry_EnumStation(GetDefaultAdapter(Adapter), i); ++ ++ if(pEntry!=NULL) ++ { ++ if(pEntry->bAssociated) ++ { ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_OFDMTXPathDiversity_92C: MACID=%d, RSSI_0=%d, RSSI_1=%d\n", ++ pEntry->AID+1, pEntry->rssi_stat.RxRSSIPercentage[0], pEntry->rssi_stat.RxRSSIPercentage[1])); ++ ++ if(pEntry->rssi_stat.RxRSSIPercentage[0] > pEntry->rssi_stat.RxRSSIPercentage[1]) ++ { ++ pDM_PDTable->OFDMTXPath = pDM_PDTable->OFDMTXPath & ~(BIT(pEntry->AID+1)); ++ //pHalData->TXPath = pHalData->TXPath & ~(1<<(pEntry->AID+1)); ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_OFDMTXPathDiversity_92C: MACID=%d Select Path-0\n", pEntry->AID+1)); ++ if(pEntry->rssi_stat.RxRSSIPercentage[1] < MinRSSI) ++ { ++ MinRSSI = pEntry->rssi_stat.RxRSSIPercentage[1]; ++ DefaultRespPath = 0; ++ } ++ } ++ else ++ { ++ pDM_PDTable->OFDMTXPath = pDM_PDTable->OFDMTXPath | BIT(pEntry->AID+1); ++ //pHalData->TXPath = pHalData->TXPath | (1 << (pEntry->AID+1)); ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_OFDMTXPathDiversity_92C: MACID=%d Select Path-1\n", pEntry->AID+1)); ++ if(pEntry->rssi_stat.RxRSSIPercentage[0] < MinRSSI) ++ { ++ MinRSSI = pEntry->rssi_stat.RxRSSIPercentage[0]; ++ DefaultRespPath = 1; ++ } ++ } ++ } ++ } ++ else ++ { ++ break; ++ } ++ } ++ ++ pDM_PDTable->OFDMDefaultRespPath = DefaultRespPath; ++} ++ ++ ++BOOLEAN ++odm_IsConnected_92C( ++ IN PADAPTER Adapter ++) ++{ ++ PRT_WLAN_STA pEntry; ++ PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ u4Byte i; ++ BOOLEAN bConnected=FALSE; ++ ++ if(pMgntInfo->mAssoc) ++ { ++ bConnected = TRUE; ++ } ++ else ++ { ++ for(i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) ++ { ++ if(IsAPModeExist(Adapter) && GetFirstExtAdapter(Adapter) != NULL) ++ pEntry = AsocEntry_EnumStation(GetFirstExtAdapter(Adapter), i); ++ else ++ pEntry = AsocEntry_EnumStation(GetDefaultAdapter(Adapter), i); ++ ++ if(pEntry!=NULL) ++ { ++ if(pEntry->bAssociated) ++ { ++ bConnected = TRUE; ++ break; ++ } ++ } ++ else ++ { ++ break; ++ } ++ } ++ } ++ return bConnected; ++} ++ ++ ++VOID ++odm_ResetPathDiversity_92C( ++ IN PADAPTER Adapter ++) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ pPD_T pDM_PDTable = &Adapter->DM_PDTable; ++ PRT_WLAN_STA pEntry; ++ u4Byte i; ++ ++ pHalData->RSSI_test = FALSE; ++ pDM_PDTable->CCK_Pkt_Cnt = 0; ++ pDM_PDTable->OFDM_Pkt_Cnt = 0; ++ pHalData->CCK_Pkt_Cnt =0; ++ pHalData->OFDM_Pkt_Cnt =0; ++ ++ if(pDM_PDTable->CCKPathDivEnable == TRUE) ++ PHY_SetBBReg(Adapter, rCCK0_AFESetting , 0x0F000000, 0x01); //RX path = PathAB ++ ++ for(i=0; i<2; i++) ++ { ++ pDM_PDTable->RSSI_CCK_Path_cnt[i]=0; ++ pDM_PDTable->RSSI_CCK_Path[i] = 0; ++ } ++ for(i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) ++ { ++ if(IsAPModeExist(Adapter) && GetFirstExtAdapter(Adapter) != NULL) ++ pEntry = AsocEntry_EnumStation(GetFirstExtAdapter(Adapter), i); ++ else ++ pEntry = AsocEntry_EnumStation(GetDefaultAdapter(Adapter), i); ++ ++ if(pEntry!=NULL) ++ { ++ pEntry->rssi_stat.CCK_Pkt_Cnt = 0; ++ pEntry->rssi_stat.OFDM_Pkt_Cnt = 0; ++ for(i=0; i<2; i++) ++ { ++ pEntry->rssi_stat.RSSI_CCK_Path_cnt[i] = 0; ++ pEntry->rssi_stat.RSSI_CCK_Path[i] = 0; ++ } ++ } ++ else ++ break; ++ } ++} ++ ++ ++VOID ++odm_CCKTXPathDiversity_92C( ++ IN PADAPTER Adapter ++) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ PRT_WLAN_STA pEntry; ++ s4Byte MinRSSI = 0xFF; ++ u1Byte i, DefaultRespPath = 0; ++// BOOLEAN bBModePathDiv = FALSE; ++ pPD_T pDM_PDTable = &Adapter->DM_PDTable; ++ ++ //1 Default Port ++ if(pMgntInfo->mAssoc) ++ { ++ if(pHalData->OFDM_Pkt_Cnt == 0) ++ { ++ for(i=0; i<2; i++) ++ { ++ if(pDM_PDTable->RSSI_CCK_Path_cnt[i] > 1) //Because the first packet is discarded ++ pDM_PDTable->RSSI_CCK_Path[i] = pDM_PDTable->RSSI_CCK_Path[i] / (pDM_PDTable->RSSI_CCK_Path_cnt[i]-1); ++ else ++ pDM_PDTable->RSSI_CCK_Path[i] = 0; ++ } ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: pDM_PDTable->RSSI_CCK_Path[0]=%d, pDM_PDTable->RSSI_CCK_Path[1]=%d\n", ++ pDM_PDTable->RSSI_CCK_Path[0], pDM_PDTable->RSSI_CCK_Path[1])); ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: pDM_PDTable->RSSI_CCK_Path_cnt[0]=%d, pDM_PDTable->RSSI_CCK_Path_cnt[1]=%d\n", ++ pDM_PDTable->RSSI_CCK_Path_cnt[0], pDM_PDTable->RSSI_CCK_Path_cnt[1])); ++ ++ if(pDM_PDTable->RSSI_CCK_Path[0] > pDM_PDTable->RSSI_CCK_Path[1]) ++ { ++ pDM_PDTable->CCKTXPath = pDM_PDTable->CCKTXPath & (~BIT0); ++ MinRSSI = pDM_PDTable->RSSI_CCK_Path[1]; ++ DefaultRespPath = 0; ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: Default port Select CCK Path-0\n")); ++ } ++ else if(pDM_PDTable->RSSI_CCK_Path[0] < pDM_PDTable->RSSI_CCK_Path[1]) ++ { ++ pDM_PDTable->CCKTXPath = pDM_PDTable->CCKTXPath | BIT0; ++ MinRSSI = pDM_PDTable->RSSI_CCK_Path[0]; ++ DefaultRespPath = 1; ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: Default port Select CCK Path-1\n")); ++ } ++ else ++ { ++ if((pDM_PDTable->RSSI_CCK_Path[0] != 0) && (pDM_PDTable->RSSI_CCK_Path[0] < MinRSSI)) ++ { ++ pDM_PDTable->CCKTXPath = pDM_PDTable->CCKTXPath & (~BIT0); ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: Default port Select CCK Path-0\n")); ++ MinRSSI = pDM_PDTable->RSSI_CCK_Path[1]; ++ DefaultRespPath = 0; ++ } ++ else ++ { ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: Default port unchange CCK Path\n")); ++ } ++ } ++ } ++ else //Follow OFDM decision ++ { ++ pDM_PDTable->CCKTXPath = (pDM_PDTable->CCKTXPath & (~BIT0)) | (pDM_PDTable->OFDMTXPath &BIT0); ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: Follow OFDM decision, Default port Select CCK Path-%d\n", ++ pDM_PDTable->CCKTXPath &BIT0)); ++ } ++ } ++ //1 Extension Port ++ for(i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) ++ { ++ if(IsAPModeExist(Adapter) && GetFirstExtAdapter(Adapter) != NULL) ++ pEntry = AsocEntry_EnumStation(GetFirstExtAdapter(Adapter), i); ++ else ++ pEntry = AsocEntry_EnumStation(GetDefaultAdapter(Adapter), i); ++ ++ if(pEntry!=NULL) ++ { ++ if(pEntry->bAssociated) ++ { ++ if(pEntry->rssi_stat.OFDM_Pkt_Cnt == 0) ++ { ++ for(i=0; i<2; i++) ++ { ++ if(pEntry->rssi_stat.RSSI_CCK_Path_cnt[i] > 1) ++ pEntry->rssi_stat.RSSI_CCK_Path[i] = pEntry->rssi_stat.RSSI_CCK_Path[i] / (pEntry->rssi_stat.RSSI_CCK_Path_cnt[i]-1); ++ else ++ pEntry->rssi_stat.RSSI_CCK_Path[i] = 0; ++ } ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: MACID=%d, RSSI_CCK0=%d, RSSI_CCK1=%d\n", ++ pEntry->AID+1, pEntry->rssi_stat.RSSI_CCK_Path[0], pEntry->rssi_stat.RSSI_CCK_Path[1])); ++ ++ if(pEntry->rssi_stat.RSSI_CCK_Path[0] >pEntry->rssi_stat.RSSI_CCK_Path[1]) ++ { ++ pDM_PDTable->CCKTXPath = pDM_PDTable->CCKTXPath & ~(BIT(pEntry->AID+1)); ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: MACID=%d Select CCK Path-0\n", pEntry->AID+1)); ++ if(pEntry->rssi_stat.RSSI_CCK_Path[1] < MinRSSI) ++ { ++ MinRSSI = pEntry->rssi_stat.RSSI_CCK_Path[1]; ++ DefaultRespPath = 0; ++ } ++ } ++ else if(pEntry->rssi_stat.RSSI_CCK_Path[0] rssi_stat.RSSI_CCK_Path[1]) ++ { ++ pDM_PDTable->CCKTXPath = pDM_PDTable->CCKTXPath | BIT(pEntry->AID+1); ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: MACID=%d Select CCK Path-1\n", pEntry->AID+1)); ++ if(pEntry->rssi_stat.RSSI_CCK_Path[0] < MinRSSI) ++ { ++ MinRSSI = pEntry->rssi_stat.RSSI_CCK_Path[0]; ++ DefaultRespPath = 1; ++ } ++ } ++ else ++ { ++ if((pEntry->rssi_stat.RSSI_CCK_Path[0] != 0) && (pEntry->rssi_stat.RSSI_CCK_Path[0] < MinRSSI)) ++ { ++ pDM_PDTable->CCKTXPath = pDM_PDTable->CCKTXPath & ~(BIT(pEntry->AID+1)); ++ MinRSSI = pEntry->rssi_stat.RSSI_CCK_Path[1]; ++ DefaultRespPath = 0; ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: MACID=%d Select CCK Path-0\n", pEntry->AID+1)); ++ } ++ else ++ { ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: MACID=%d unchange CCK Path\n", pEntry->AID+1)); ++ } ++ } ++ } ++ else //Follow OFDM decision ++ { ++ pDM_PDTable->CCKTXPath = (pDM_PDTable->CCKTXPath & (~(BIT(pEntry->AID+1)))) | (pDM_PDTable->OFDMTXPath & BIT(pEntry->AID+1)); ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: Follow OFDM decision, MACID=%d Select CCK Path-%d\n", ++ pEntry->AID+1, (pDM_PDTable->CCKTXPath & BIT(pEntry->AID+1))>>(pEntry->AID+1))); ++ } ++ } ++ } ++ else ++ { ++ break; ++ } ++ } ++ ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C:MinRSSI=%d\n",MinRSSI)); ++ ++ if(MinRSSI == 0xFF) ++ DefaultRespPath = pDM_PDTable->CCKDefaultRespPath; ++ ++ pDM_PDTable->CCKDefaultRespPath = DefaultRespPath; ++} ++ ++ ++ ++VOID ++odm_PathDiversityAfterLink_92C( ++ IN PADAPTER Adapter ++) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ pPD_T pDM_PDTable = &Adapter->DM_PDTable; ++ u1Byte DefaultRespPath=0; ++ ++ if((!IS_92C_SERIAL(pHalData->VersionID)) || (pHalData->PathDivCfg != 1) || (pHalData->eRFPowerState == eRfOff)) ++ { ++ if(pHalData->PathDivCfg == 0) ++ { ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("No ODM_TXPathDiversity()\n")); ++ } ++ else ++ { ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("2T ODM_TXPathDiversity()\n")); ++ } ++ return; ++ } ++ if(!odm_IsConnected_92C(Adapter)) ++ { ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("ODM_TXPathDiversity(): No Connections\n")); ++ return; ++ } ++ ++ ++ if(pDM_PDTable->TrainingState == 0) ++ { ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("ODM_TXPathDiversity() ==>\n")); ++ odm_OFDMTXPathDiversity_92C(Adapter); ++ ++ if((pDM_PDTable->CCKPathDivEnable == TRUE) && (pDM_PDTable->OFDM_Pkt_Cnt < 100)) ++ { ++ //RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: TrainingState=0\n")); ++ ++ if(pDM_PDTable->CCK_Pkt_Cnt > 300) ++ pDM_PDTable->Timer = 20; ++ else if(pDM_PDTable->CCK_Pkt_Cnt > 100) ++ pDM_PDTable->Timer = 60; ++ else ++ pDM_PDTable->Timer = 250; ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: timer=%d\n",pDM_PDTable->Timer)); ++ ++ PHY_SetBBReg(Adapter, rCCK0_AFESetting , 0x0F000000, 0x00); // RX path = PathA ++ pDM_PDTable->TrainingState = 1; ++ pHalData->RSSI_test = TRUE; ++ ODM_SetTimer( pDM_Odm, &pDM_Odm->CCKPathDiversityTimer, pDM_PDTable->Timer); //ms ++ } ++ else ++ { ++ pDM_PDTable->CCKTXPath = pDM_PDTable->OFDMTXPath; ++ DefaultRespPath = pDM_PDTable->OFDMDefaultRespPath; ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_SetRespPath_92C: Skip odm_CCKTXPathDiversity_92C, DefaultRespPath is OFDM\n")); ++ odm_SetRespPath_92C(Adapter, DefaultRespPath); ++ odm_ResetPathDiversity_92C(Adapter); ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("ODM_TXPathDiversity() <==\n")); ++ } ++ } ++ else if(pDM_PDTable->TrainingState == 1) ++ { ++ //RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: TrainingState=1\n")); ++ PHY_SetBBReg(Adapter, rCCK0_AFESetting , 0x0F000000, 0x05); // RX path = PathB ++ pDM_PDTable->TrainingState = 2; ++ ODM_SetTimer( pDM_Odm, &pDM_Odm->CCKPathDiversityTimer, pDM_PDTable->Timer); //ms ++ } ++ else ++ { ++ //RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: TrainingState=2\n")); ++ pDM_PDTable->TrainingState = 0; ++ odm_CCKTXPathDiversity_92C(Adapter); ++ if(pDM_PDTable->OFDM_Pkt_Cnt != 0) ++ { ++ DefaultRespPath = pDM_PDTable->OFDMDefaultRespPath; ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_SetRespPath_92C: DefaultRespPath is OFDM\n")); ++ } ++ else ++ { ++ DefaultRespPath = pDM_PDTable->CCKDefaultRespPath; ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_SetRespPath_92C: DefaultRespPath is CCK\n")); ++ } ++ odm_SetRespPath_92C(Adapter, DefaultRespPath); ++ odm_ResetPathDiversity_92C(Adapter); ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("ODM_TXPathDiversity() <==\n")); ++ } ++ ++} ++ ++ ++ ++VOID ++odm_CCKTXPathDiversityCallback( ++ PRT_TIMER pTimer ++) ++{ ++#if USE_WORKITEM ++ PADAPTER Adapter = (PADAPTER)pTimer->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++#else ++ PADAPTER Adapter = (PADAPTER)pTimer->Adapter; ++#endif ++ ++#if DEV_BUS_TYPE==RT_PCI_INTERFACE ++#if USE_WORKITEM ++ PlatformScheduleWorkItem(&pDM_Odm->CCKPathDiversityWorkitem); ++#else ++ odm_PathDiversityAfterLink_92C(Adapter); ++#endif ++#else ++ PlatformScheduleWorkItem(&pDM_Odm->CCKPathDiversityWorkitem); ++#endif ++ ++} ++ ++ ++VOID ++odm_CCKTXPathDiversityWorkItemCallback( ++ IN PVOID pContext ++ ) ++{ ++ PADAPTER Adapter = (PADAPTER)pContext; ++ ++ odm_CCKTXPathDiversity_92C(Adapter); ++} ++ ++ ++VOID ++ODM_CCKPathDiversityChkPerPktRssi( ++ PADAPTER Adapter, ++ BOOLEAN bIsDefPort, ++ BOOLEAN bMatchBSSID, ++ PRT_WLAN_STA pEntry, ++ PRT_RFD pRfd, ++ pu1Byte pDesc ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ BOOLEAN bCount = FALSE; ++ pPD_T pDM_PDTable = &Adapter->DM_PDTable; ++ //BOOLEAN isCCKrate = RX_HAL_IS_CCK_RATE_92C(pDesc); ++#if DEV_BUS_TYPE != RT_SDIO_INTERFACE ++ BOOLEAN isCCKrate = RX_HAL_IS_CCK_RATE(Adapter, pDesc); ++#else //below code would be removed if we have verified SDIO ++ BOOLEAN isCCKrate = IS_HARDWARE_TYPE_8188E(Adapter) ? RX_HAL_IS_CCK_RATE_88E(pDesc) : RX_HAL_IS_CCK_RATE_92C(pDesc); ++#endif ++ ++ if((pHalData->PathDivCfg != 1) || (pHalData->RSSI_test == FALSE)) ++ return; ++ ++ if(pHalData->RSSI_target==NULL && bIsDefPort && bMatchBSSID) ++ bCount = TRUE; ++ else if(pHalData->RSSI_target!=NULL && pEntry!=NULL && pHalData->RSSI_target==pEntry) ++ bCount = TRUE; ++ ++ if(bCount && isCCKrate) ++ { ++ if(pDM_PDTable->TrainingState == 1 ) ++ { ++ if(pEntry) ++ { ++ if(pEntry->rssi_stat.RSSI_CCK_Path_cnt[0] != 0) ++ pEntry->rssi_stat.RSSI_CCK_Path[0] += pRfd->Status.RxPWDBAll; ++ pEntry->rssi_stat.RSSI_CCK_Path_cnt[0]++; ++ } ++ else ++ { ++ if(pDM_PDTable->RSSI_CCK_Path_cnt[0] != 0) ++ pDM_PDTable->RSSI_CCK_Path[0] += pRfd->Status.RxPWDBAll; ++ pDM_PDTable->RSSI_CCK_Path_cnt[0]++; ++ } ++ } ++ else if(pDM_PDTable->TrainingState == 2 ) ++ { ++ if(pEntry) ++ { ++ if(pEntry->rssi_stat.RSSI_CCK_Path_cnt[1] != 0) ++ pEntry->rssi_stat.RSSI_CCK_Path[1] += pRfd->Status.RxPWDBAll; ++ pEntry->rssi_stat.RSSI_CCK_Path_cnt[1]++; ++ } ++ else ++ { ++ if(pDM_PDTable->RSSI_CCK_Path_cnt[1] != 0) ++ pDM_PDTable->RSSI_CCK_Path[1] += pRfd->Status.RxPWDBAll; ++ pDM_PDTable->RSSI_CCK_Path_cnt[1]++; ++ } ++ } ++ } ++} ++ ++ ++BOOLEAN ++ODM_PathDiversityBeforeLink92C( ++ //IN PADAPTER Adapter ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++#if (RT_MEM_SIZE_LEVEL != RT_MEM_SIZE_MINIMUM) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE* pHalData = NULL; ++ PMGNT_INFO pMgntInfo = NULL; ++ //pSWAT_T pDM_SWAT_Table = &Adapter->DM_SWAT_Table; ++ pPD_T pDM_PDTable = NULL; ++ ++ s1Byte Score = 0; ++ PRT_WLAN_BSS pTmpBssDesc; ++ PRT_WLAN_BSS pTestBssDesc; ++ ++ u1Byte target_chnl = 0; ++ u1Byte index; ++ ++ if (pDM_Odm->Adapter == NULL) //For BSOD when plug/unplug fast. //By YJ,120413 ++ { // The ODM structure is not initialized. ++ return FALSE; ++ } ++ pHalData = GET_HAL_DATA(Adapter); ++ pMgntInfo = &Adapter->MgntInfo; ++ pDM_PDTable = &Adapter->DM_PDTable; ++ ++ // Condition that does not need to use path diversity. ++ if((!IS_92C_SERIAL(pHalData->VersionID)) || (pHalData->PathDivCfg!=1) || pMgntInfo->AntennaTest ) ++ { ++ RT_TRACE(COMP_SWAS, DBG_LOUD, ++ ("ODM_PathDiversityBeforeLink92C(): No PathDiv Mechanism before link.\n")); ++ return FALSE; ++ } ++ ++ // Since driver is going to set BB register, it shall check if there is another thread controlling BB/RF. ++ PlatformAcquireSpinLock(Adapter, RT_RF_STATE_SPINLOCK); ++ if(pHalData->eRFPowerState!=eRfOn || pMgntInfo->RFChangeInProgress || pMgntInfo->bMediaConnect) ++ { ++ PlatformReleaseSpinLock(Adapter, RT_RF_STATE_SPINLOCK); ++ ++ RT_TRACE(COMP_SWAS, DBG_LOUD, ++ ("ODM_PathDiversityBeforeLink92C(): RFChangeInProgress(%x), eRFPowerState(%x)\n", ++ pMgntInfo->RFChangeInProgress, ++ pHalData->eRFPowerState)); ++ ++ //pDM_SWAT_Table->SWAS_NoLink_State = 0; ++ pDM_PDTable->PathDiv_NoLink_State = 0; ++ ++ return FALSE; ++ } ++ else ++ { ++ PlatformReleaseSpinLock(Adapter, RT_RF_STATE_SPINLOCK); ++ } ++ ++ //1 Run AntDiv mechanism "Before Link" part. ++ //if(pDM_SWAT_Table->SWAS_NoLink_State == 0) ++ if(pDM_PDTable->PathDiv_NoLink_State == 0) ++ { ++ //1 Prepare to do Scan again to check current antenna state. ++ ++ // Set check state to next step. ++ //pDM_SWAT_Table->SWAS_NoLink_State = 1; ++ pDM_PDTable->PathDiv_NoLink_State = 1; ++ ++ // Copy Current Scan list. ++ Adapter->MgntInfo.tmpNumBssDesc = pMgntInfo->NumBssDesc; ++ PlatformMoveMemory((PVOID)Adapter->MgntInfo.tmpbssDesc, (PVOID)pMgntInfo->bssDesc, sizeof(RT_WLAN_BSS)*MAX_BSS_DESC); ++ ++ // Switch Antenna to another one. ++ if(pDM_PDTable->DefaultRespPath == 0) ++ { ++ PHY_SetBBReg(Adapter, rCCK0_AFESetting , 0x0F000000, 0x05); // TRX path = PathB ++ odm_SetRespPath_92C(Adapter, 1); ++ pDM_PDTable->OFDMTXPath = 0xFFFFFFFF; ++ pDM_PDTable->CCKTXPath = 0xFFFFFFFF; ++ } ++ else ++ { ++ PHY_SetBBReg(Adapter, rCCK0_AFESetting , 0x0F000000, 0x00); // TRX path = PathA ++ odm_SetRespPath_92C(Adapter, 0); ++ pDM_PDTable->OFDMTXPath = 0x0; ++ pDM_PDTable->CCKTXPath = 0x0; ++ } ++#if 0 ++ ++ pDM_SWAT_Table->PreAntenna = pDM_SWAT_Table->CurAntenna; ++ pDM_SWAT_Table->CurAntenna = (pDM_SWAT_Table->CurAntenna==Antenna_A)?Antenna_B:Antenna_A; ++ ++ RT_TRACE(COMP_SWAS, DBG_LOUD, ++ ("ODM_SwAntDivCheckBeforeLink8192C: Change to Ant(%s) for testing.\n", (pDM_SWAT_Table->CurAntenna==Antenna_A)?"A":"B")); ++ //PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300, DM_SWAT_Table.CurAntenna); ++ pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 = ((pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 & 0xfffffcff) | (pDM_SWAT_Table->CurAntenna<<8)); ++ PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, bMaskDWord, pDM_SWAT_Table->SWAS_NoLink_BK_Reg860); ++#endif ++ ++ // Go back to scan function again. ++ RT_TRACE(COMP_SWAS, DBG_LOUD, ("ODM_PathDiversityBeforeLink92C: Scan one more time\n")); ++ pMgntInfo->ScanStep=0; ++ target_chnl = odm_SwAntDivSelectChkChnl(Adapter); ++ odm_SwAntDivConsructChkScanChnl(Adapter, target_chnl); ++ HTReleaseChnlOpLock(Adapter); ++ PlatformSetTimer(Adapter, &pMgntInfo->ScanTimer, 5); ++ ++ return TRUE; ++ } ++ else ++ { ++ //1 ScanComple() is called after antenna swiched. ++ //1 Check scan result and determine which antenna is going ++ //1 to be used. ++ ++ for(index=0; indexMgntInfo.tmpNumBssDesc; index++) ++ { ++ pTmpBssDesc = &(Adapter->MgntInfo.tmpbssDesc[index]); ++ pTestBssDesc = &(pMgntInfo->bssDesc[index]); ++ ++ if(PlatformCompareMemory(pTestBssDesc->bdBssIdBuf, pTmpBssDesc->bdBssIdBuf, 6)!=0) ++ { ++ RT_TRACE(COMP_SWAS, DBG_LOUD, ("ODM_PathDiversityBeforeLink92C(): ERROR!! This shall not happen.\n")); ++ continue; ++ } ++ ++ if(pTmpBssDesc->RecvSignalPower > pTestBssDesc->RecvSignalPower) ++ { ++ RT_TRACE(COMP_SWAS, DBG_LOUD, ("ODM_PathDiversityBeforeLink92C: Compare scan entry: Score++\n")); ++ RT_PRINT_STR(COMP_SWAS, DBG_LOUD, "SSID: ", pTestBssDesc->bdSsIdBuf, pTestBssDesc->bdSsIdLen); ++ RT_TRACE(COMP_SWAS, DBG_LOUD, ("Original: %d, Test: %d\n", pTmpBssDesc->RecvSignalPower, pTestBssDesc->RecvSignalPower)); ++ ++ Score++; ++ PlatformMoveMemory(pTestBssDesc, pTmpBssDesc, sizeof(RT_WLAN_BSS)); ++ } ++ else if(pTmpBssDesc->RecvSignalPower < pTestBssDesc->RecvSignalPower) ++ { ++ RT_TRACE(COMP_SWAS, DBG_LOUD, ("ODM_PathDiversityBeforeLink92C: Compare scan entry: Score--\n")); ++ RT_PRINT_STR(COMP_SWAS, DBG_LOUD, "SSID: ", pTestBssDesc->bdSsIdBuf, pTestBssDesc->bdSsIdLen); ++ RT_TRACE(COMP_SWAS, DBG_LOUD, ("Original: %d, Test: %d\n", pTmpBssDesc->RecvSignalPower, pTestBssDesc->RecvSignalPower)); ++ Score--; ++ } ++ ++ } ++ ++ if(pMgntInfo->NumBssDesc!=0 && Score<=0) ++ { ++ RT_TRACE(COMP_SWAS, DBG_LOUD, ++ ("ODM_PathDiversityBeforeLink92C(): DefaultRespPath=%d\n", pDM_PDTable->DefaultRespPath)); ++ ++ //pDM_SWAT_Table->PreAntenna = pDM_SWAT_Table->CurAntenna; ++ } ++ else ++ { ++ RT_TRACE(COMP_SWAS, DBG_LOUD, ++ ("ODM_PathDiversityBeforeLink92C(): DefaultRespPath=%d\n", pDM_PDTable->DefaultRespPath)); ++ ++ if(pDM_PDTable->DefaultRespPath == 0) ++ { ++ pDM_PDTable->OFDMTXPath = 0xFFFFFFFF; ++ pDM_PDTable->CCKTXPath = 0xFFFFFFFF; ++ odm_SetRespPath_92C(Adapter, 1); ++ } ++ else ++ { ++ pDM_PDTable->OFDMTXPath = 0x0; ++ pDM_PDTable->CCKTXPath = 0x0; ++ odm_SetRespPath_92C(Adapter, 0); ++ } ++ PHY_SetBBReg(Adapter, rCCK0_AFESetting , 0x0F000000, 0x01); // RX path = PathAB ++ ++ //pDM_SWAT_Table->CurAntenna = pDM_SWAT_Table->PreAntenna; ++ ++ //PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300, DM_SWAT_Table.CurAntenna); ++ //pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 = ((pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 & 0xfffffcff) | (pDM_SWAT_Table->CurAntenna<<8)); ++ //PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, bMaskDWord, pDM_SWAT_Table->SWAS_NoLink_BK_Reg860); ++ } ++ ++ // Check state reset to default and wait for next time. ++ //pDM_SWAT_Table->SWAS_NoLink_State = 0; ++ pDM_PDTable->PathDiv_NoLink_State = 0; ++ ++ return FALSE; ++ } ++#else ++ return FALSE; ++#endif ++ ++} ++ ++ ++//Neil Chen---2011--06--22 ++//----92D Path Diversity----// ++//#ifdef PathDiv92D ++//================================== ++//3 Path Diversity ++//================================== ++// ++// 20100514 Luke/Joseph: ++// Add new function for antenna diversity after link. ++// This is the main function of antenna diversity after link. ++// This function is called in HalDmWatchDog() and ODM_SwAntDivChkAntSwitchCallback(). ++// HalDmWatchDog() calls this function with SWAW_STEP_PEAK to initialize the antenna test. ++// In SWAW_STEP_PEAK, another antenna and a 500ms timer will be set for testing. ++// After 500ms, ODM_SwAntDivChkAntSwitchCallback() calls this function to compare the signal just ++// listened on the air with the RSSI of original antenna. ++// It chooses the antenna with better RSSI. ++// There is also a aged policy for error trying. Each error trying will cost more 5 seconds waiting ++// penalty to get next try. ++// ++// ++// 20100503 Joseph: ++// Add new function SwAntDivCheck8192C(). ++// This is the main function of Antenna diversity function before link. ++// Mainly, it just retains last scan result and scan again. ++// After that, it compares the scan result to see which one gets better RSSI. ++// It selects antenna with better receiving power and returns better scan result. ++// ++ ++ ++// ++// 20100514 Luke/Joseph: ++// This function is used to gather the RSSI information for antenna testing. ++// It selects the RSSI of the peer STA that we want to know. ++// ++VOID ++ODM_PathDivChkPerPktRssi( ++ PADAPTER Adapter, ++ BOOLEAN bIsDefPort, ++ BOOLEAN bMatchBSSID, ++ PRT_WLAN_STA pEntry, ++ PRT_RFD pRfd ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ BOOLEAN bCount = FALSE; ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ ++ if(pHalData->RSSI_target==NULL && bIsDefPort && bMatchBSSID) ++ bCount = TRUE; ++ else if(pHalData->RSSI_target!=NULL && pEntry!=NULL && pHalData->RSSI_target==pEntry) ++ bCount = TRUE; ++ ++ if(bCount) ++ { ++ //1 RSSI for SW Antenna Switch ++ if(pDM_SWAT_Table->CurAntenna == Antenna_A) ++ { ++ pHalData->RSSI_sum_A += pRfd->Status.RxPWDBAll; ++ pHalData->RSSI_cnt_A++; ++ } ++ else ++ { ++ pHalData->RSSI_sum_B += pRfd->Status.RxPWDBAll; ++ pHalData->RSSI_cnt_B++; ++ ++ } ++ } ++} ++ ++ ++ ++// ++// 20100514 Luke/Joseph: ++// Add new function to reset antenna diversity state after link. ++// ++VOID ++ODM_PathDivRestAfterLink( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ PADAPTER Adapter=pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ ++ pHalData->RSSI_cnt_A = 0; ++ pHalData->RSSI_cnt_B = 0; ++ pHalData->RSSI_test = FALSE; ++ pDM_SWAT_Table->try_flag = 0x0; // NOT 0xff ++ pDM_SWAT_Table->RSSI_Trying = 0; ++ pDM_SWAT_Table->SelectAntennaMap=0xAA; ++ pDM_SWAT_Table->CurAntenna = Antenna_A; ++} ++ ++ ++// ++// 20100514 Luke/Joseph: ++// Callback function for 500ms antenna test trying. ++// ++VOID ++odm_PathDivChkAntSwitchCallback( ++ PRT_TIMER pTimer ++) ++{ ++ PADAPTER Adapter = (PADAPTER)pTimer->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ ++#if DEV_BUS_TYPE==RT_PCI_INTERFACE ++ ++#if USE_WORKITEM ++ PlatformScheduleWorkItem(&pDM_Odm->PathDivSwitchWorkitem); ++#else ++ odm_PathDivChkAntSwitch(pDM_Odm); ++#endif ++#else ++ PlatformScheduleWorkItem(&pDM_Odm->PathDivSwitchWorkitem); ++#endif ++ ++//odm_SwAntDivChkAntSwitch(Adapter, SWAW_STEP_DETERMINE); ++ ++} ++ ++ ++VOID ++odm_PathDivChkAntSwitchWorkitemCallback( ++ IN PVOID pContext ++ ) ++{ ++ PADAPTER pAdapter = (PADAPTER)pContext; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ ++ odm_PathDivChkAntSwitch(pDM_Odm); ++} ++ ++ ++ //MAC0_ACCESS_PHY1 ++ ++// 2011-06-22 Neil Chen & Gary Hsin ++// Refer to Jr.Luke's SW ANT DIV ++// 92D Path Diversity Main function ++// refer to 88C software antenna diversity ++// ++VOID ++odm_PathDivChkAntSwitch( ++ PDM_ODM_T pDM_Odm ++ //PADAPTER Adapter, ++ //u1Byte Step ++) ++{ ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ ++ ++ pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ s4Byte curRSSI=100, RSSI_A, RSSI_B; ++ u1Byte nextAntenna=Antenna_B; ++ static u8Byte lastTxOkCnt=0, lastRxOkCnt=0; ++ u8Byte curTxOkCnt, curRxOkCnt; ++ static u8Byte TXByteCnt_A=0, TXByteCnt_B=0, RXByteCnt_A=0, RXByteCnt_B=0; ++ u8Byte CurByteCnt=0, PreByteCnt=0; ++ static u1Byte TrafficLoad = TRAFFIC_LOW; ++ u1Byte Score_A=0, Score_B=0; ++ u1Byte i=0x0; ++ // Neil Chen ++ static u1Byte pathdiv_para=0x0; ++ static u1Byte switchfirsttime=0x00; ++ // u1Byte regB33 = (u1Byte) PHY_QueryBBReg(Adapter, 0xB30,BIT27); ++ u1Byte regB33 = (u1Byte)ODM_GetBBReg(pDM_Odm, PATHDIV_REG, BIT27); ++ ++ ++ //u1Byte reg637 =0x0; ++ static u1Byte fw_value=0x0; ++ u1Byte n=0; ++ static u8Byte lastTxOkCnt_tmp=0, lastRxOkCnt_tmp=0; ++ //u8Byte curTxOkCnt_tmp, curRxOkCnt_tmp; ++ PADAPTER BuddyAdapter = Adapter->BuddyAdapter; // another adapter MAC ++ // Path Diversity //Neil Chen--2011--06--22 ++ ++ //u1Byte PathDiv_Trigger = (u1Byte) PHY_QueryBBReg(Adapter, 0xBA0,BIT31); ++ u1Byte PathDiv_Trigger = (u1Byte) ODM_GetBBReg(pDM_Odm, PATHDIV_TRI,BIT31); ++ u1Byte PathDiv_Enable = pHalData->bPathDiv_Enable; ++ ++ ++ //DbgPrint("Path Div PG Value:%x \n",PathDiv_Enable); ++ if((BuddyAdapter==NULL)||(!PathDiv_Enable)||(PathDiv_Trigger)||(pHalData->CurrentBandType92D == BAND_ON_2_4G)) ++ { ++ return; ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD,("===================>odm_PathDivChkAntSwitch()\n")); ++ ++ // The first time to switch path excluding 2nd, 3rd, ....etc.... ++ if(switchfirsttime==0) ++ { ++ if(regB33==0) ++ { ++ pDM_SWAT_Table->CurAntenna = Antenna_A; // Default MAC0_5G-->Path A (current antenna) ++ } ++ } ++ ++ // Condition that does not need to use antenna diversity. ++ if(pDM_Odm->SupportICType != ODM_RTL8192D) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("odm_PathDiversityMechanims(): No PathDiv Mechanism.\n")); ++ return; ++ } ++ ++ // Radio off: Status reset to default and return. ++ if(pHalData->eRFPowerState==eRfOff) ++ { ++ //ODM_SwAntDivRestAfterLink(Adapter); ++ return; ++ } ++ ++ /* ++ // Handling step mismatch condition. ++ // Peak step is not finished at last time. Recover the variable and check again. ++ if( Step != pDM_SWAT_Table->try_flag ) ++ { ++ ODM_SwAntDivRestAfterLink(Adapter); ++ } */ ++ ++ if(pDM_SWAT_Table->try_flag == 0xff) ++ { ++ // Select RSSI checking target ++ if(pMgntInfo->mAssoc && !ACTING_AS_AP(Adapter)) ++ { ++ // Target: Infrastructure mode AP. ++ pHalData->RSSI_target = NULL; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("odm_PathDivMechanism(): RSSI_target is DEF AP!\n")); ++ } ++ else ++ { ++ u1Byte index = 0; ++ PRT_WLAN_STA pEntry = NULL; ++ PADAPTER pTargetAdapter = NULL; ++ ++ if( pMgntInfo->mIbss || ACTING_AS_AP(Adapter) ) ++ { ++ // Target: AP/IBSS peer. ++ pTargetAdapter = Adapter; ++ } ++ else if(IsAPModeExist(Adapter) && GetFirstExtAdapter(Adapter) != NULL) ++ { ++ // Target: VWIFI peer. ++ pTargetAdapter = GetFirstExtAdapter(Adapter); ++ } ++ ++ if(pTargetAdapter != NULL) ++ { ++ for(index=0; indexbAssociated) ++ break; ++ } ++ } ++ } ++ ++ if(pEntry == NULL) ++ { ++ ODM_PathDivRestAfterLink(pDM_Odm); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("odm_SwAntDivChkAntSwitch(): No Link.\n")); ++ return; ++ } ++ else ++ { ++ pHalData->RSSI_target = pEntry; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("odm_SwAntDivChkAntSwitch(): RSSI_target is PEER STA\n")); ++ } ++ } ++ ++ pHalData->RSSI_cnt_A = 0; ++ pHalData->RSSI_cnt_B = 0; ++ pDM_SWAT_Table->try_flag = 0; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("odm_SwAntDivChkAntSwitch(): Set try_flag to 0 prepare for peak!\n")); ++ return; ++ } ++ else ++ { ++ // 1st step ++ curTxOkCnt = Adapter->TxStats.NumTxBytesUnicast - lastTxOkCnt; ++ curRxOkCnt = Adapter->RxStats.NumRxBytesUnicast - lastRxOkCnt; ++ lastTxOkCnt = Adapter->TxStats.NumTxBytesUnicast; ++ lastRxOkCnt = Adapter->RxStats.NumRxBytesUnicast; ++ ++ if(pDM_SWAT_Table->try_flag == 1) // Training State ++ { ++ if(pDM_SWAT_Table->CurAntenna == Antenna_A) ++ { ++ TXByteCnt_A += curTxOkCnt; ++ RXByteCnt_A += curRxOkCnt; ++ } ++ else ++ { ++ TXByteCnt_B += curTxOkCnt; ++ RXByteCnt_B += curRxOkCnt; ++ } ++ ++ nextAntenna = (pDM_SWAT_Table->CurAntenna == Antenna_A)? Antenna_B : Antenna_A; ++ pDM_SWAT_Table->RSSI_Trying--; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH DIV=: RSSI_Trying = %d\n",pDM_SWAT_Table->RSSI_Trying)); ++ if(pDM_SWAT_Table->RSSI_Trying == 0) ++ { ++ CurByteCnt = (pDM_SWAT_Table->CurAntenna == Antenna_A)? (TXByteCnt_A+RXByteCnt_A) : (TXByteCnt_B+RXByteCnt_B); ++ PreByteCnt = (pDM_SWAT_Table->CurAntenna == Antenna_A)? (TXByteCnt_B+RXByteCnt_B) : (TXByteCnt_A+RXByteCnt_A); ++ ++ if(TrafficLoad == TRAFFIC_HIGH) ++ { ++ //CurByteCnt = PlatformDivision64(CurByteCnt, 9); ++ PreByteCnt =PreByteCnt*9; ++ } ++ else if(TrafficLoad == TRAFFIC_LOW) ++ { ++ //CurByteCnt = PlatformDivision64(CurByteCnt, 2); ++ PreByteCnt =PreByteCnt*2; ++ } ++ if(pHalData->RSSI_cnt_A > 0) ++ RSSI_A = pHalData->RSSI_sum_A/pHalData->RSSI_cnt_A; ++ else ++ RSSI_A = 0; ++ if(pHalData->RSSI_cnt_B > 0) ++ RSSI_B = pHalData->RSSI_sum_B/pHalData->RSSI_cnt_B; ++ else ++ RSSI_B = 0; ++ curRSSI = (pDM_SWAT_Table->CurAntenna == Antenna_A)? RSSI_A : RSSI_B; ++ pDM_SWAT_Table->PreRSSI = (pDM_SWAT_Table->CurAntenna == Antenna_A)? RSSI_B : RSSI_A; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH DIV=: PreRSSI = %d, CurRSSI = %d\n",pDM_SWAT_Table->PreRSSI, curRSSI)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH DIV=: preAntenna= %s, curAntenna= %s \n", ++ (pDM_SWAT_Table->PreAntenna == Antenna_A?"A":"B"), (pDM_SWAT_Table->CurAntenna == Antenna_A?"A":"B"))); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH DIV=: RSSI_A= %d, RSSI_cnt_A = %d, RSSI_B= %d, RSSI_cnt_B = %d\n", ++ RSSI_A, pHalData->RSSI_cnt_A, RSSI_B, pHalData->RSSI_cnt_B)); ++ } ++ ++ } ++ else // try_flag=0 ++ { ++ ++ if(pHalData->RSSI_cnt_A > 0) ++ RSSI_A = pHalData->RSSI_sum_A/pHalData->RSSI_cnt_A; ++ else ++ RSSI_A = 0; ++ if(pHalData->RSSI_cnt_B > 0) ++ RSSI_B = pHalData->RSSI_sum_B/pHalData->RSSI_cnt_B; ++ else ++ RSSI_B = 0; ++ curRSSI = (pDM_SWAT_Table->CurAntenna == Antenna_A)? RSSI_A : RSSI_B; ++ pDM_SWAT_Table->PreRSSI = (pDM_SWAT_Table->PreAntenna == Antenna_A)? RSSI_A : RSSI_B; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH DIV=: PreRSSI = %d, CurRSSI = %d\n", pDM_SWAT_Table->PreRSSI, curRSSI)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH DIV=: preAntenna= %s, curAntenna= %s \n", ++ (pDM_SWAT_Table->PreAntenna == Antenna_A?"A":"B"), (pDM_SWAT_Table->CurAntenna == Antenna_A?"A":"B"))); ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH DIV=: RSSI_A= %d, RSSI_cnt_A = %d, RSSI_B= %d, RSSI_cnt_B = %d\n", ++ RSSI_A, pHalData->RSSI_cnt_A, RSSI_B, pHalData->RSSI_cnt_B)); ++ //RT_TRACE(COMP_SWAS, DBG_LOUD, ("Ekul:curTxOkCnt = %d\n", curTxOkCnt)); ++ //RT_TRACE(COMP_SWAS, DBG_LOUD, ("Ekul:curRxOkCnt = %d\n", curRxOkCnt)); ++ } ++ ++ //1 Trying State ++ if((pDM_SWAT_Table->try_flag == 1)&&(pDM_SWAT_Table->RSSI_Trying == 0)) ++ { ++ ++ if(pDM_SWAT_Table->TestMode == TP_MODE) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: TestMode = TP_MODE")); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH= TRY:CurByteCnt = %"i64fmt"d,", CurByteCnt)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH= TRY:PreByteCnt = %"i64fmt"d\n",PreByteCnt)); ++ if(CurByteCnt < PreByteCnt) ++ { ++ if(pDM_SWAT_Table->CurAntenna == Antenna_A) ++ pDM_SWAT_Table->SelectAntennaMap=pDM_SWAT_Table->SelectAntennaMap<<1; ++ else ++ pDM_SWAT_Table->SelectAntennaMap=(pDM_SWAT_Table->SelectAntennaMap<<1)+1; ++ } ++ else ++ { ++ if(pDM_SWAT_Table->CurAntenna == Antenna_A) ++ pDM_SWAT_Table->SelectAntennaMap=(pDM_SWAT_Table->SelectAntennaMap<<1)+1; ++ else ++ pDM_SWAT_Table->SelectAntennaMap=pDM_SWAT_Table->SelectAntennaMap<<1; ++ } ++ for (i= 0; i<8; i++) ++ { ++ if(((pDM_SWAT_Table->SelectAntennaMap>>i)&BIT0) == 1) ++ Score_A++; ++ else ++ Score_B++; ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("SelectAntennaMap=%x\n ",pDM_SWAT_Table->SelectAntennaMap)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Score_A=%d, Score_B=%d\n", Score_A, Score_B)); ++ ++ if(pDM_SWAT_Table->CurAntenna == Antenna_A) ++ { ++ nextAntenna = (Score_A >= Score_B)?Antenna_A:Antenna_B; ++ } ++ else ++ { ++ nextAntenna = (Score_B >= Score_A)?Antenna_B:Antenna_A; ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: nextAntenna=%s\n",(nextAntenna==Antenna_A)?"A":"B")); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: preAntenna= %s, curAntenna= %s \n", ++ (pDM_SWAT_Table->PreAntenna == Antenna_A?"A":"B"), (pDM_SWAT_Table->CurAntenna == Antenna_A?"A":"B"))); ++ ++ if(nextAntenna != pDM_SWAT_Table->CurAntenna) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Switch back to another antenna")); ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: current anntena is good\n")); ++ } ++ } ++ ++ ++ if(pDM_SWAT_Table->TestMode == RSSI_MODE) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: TestMode = RSSI_MODE")); ++ pDM_SWAT_Table->SelectAntennaMap=0xAA; ++ if(curRSSI < pDM_SWAT_Table->PreRSSI) //Current antenna is worse than previous antenna ++ { ++ //RT_TRACE(COMP_SWAS, DBG_LOUD, ("SWAS: Switch back to another antenna")); ++ nextAntenna = (pDM_SWAT_Table->CurAntenna == Antenna_A)? Antenna_B : Antenna_A; ++ } ++ else // current anntena is good ++ { ++ nextAntenna =pDM_SWAT_Table->CurAntenna; ++ //RT_TRACE(COMP_SWAS, DBG_LOUD, ("SWAS: current anntena is good\n")); ++ } ++ } ++ ++ pDM_SWAT_Table->try_flag = 0; ++ pHalData->RSSI_test = FALSE; ++ pHalData->RSSI_sum_A = 0; ++ pHalData->RSSI_cnt_A = 0; ++ pHalData->RSSI_sum_B = 0; ++ pHalData->RSSI_cnt_B = 0; ++ TXByteCnt_A = 0; ++ TXByteCnt_B = 0; ++ RXByteCnt_A = 0; ++ RXByteCnt_B = 0; ++ ++ } ++ ++ //1 Normal State ++ else if(pDM_SWAT_Table->try_flag == 0) ++ { ++ if(TrafficLoad == TRAFFIC_HIGH) ++ { ++ if ((curTxOkCnt+curRxOkCnt) > 3750000)//if(PlatformDivision64(curTxOkCnt+curRxOkCnt, 2) > 1875000) ++ TrafficLoad = TRAFFIC_HIGH; ++ else ++ TrafficLoad = TRAFFIC_LOW; ++ } ++ else if(TrafficLoad == TRAFFIC_LOW) ++ { ++ if ((curTxOkCnt+curRxOkCnt) > 3750000)//if(PlatformDivision64(curTxOkCnt+curRxOkCnt, 2) > 1875000) ++ TrafficLoad = TRAFFIC_HIGH; ++ else ++ TrafficLoad = TRAFFIC_LOW; ++ } ++ if(TrafficLoad == TRAFFIC_HIGH) ++ pDM_SWAT_Table->bTriggerAntennaSwitch = 0; ++ //RT_TRACE(COMP_SWAS, DBG_LOUD, ("Normal:TrafficLoad = %llu\n", curTxOkCnt+curRxOkCnt)); ++ ++ //Prepare To Try Antenna ++ nextAntenna = (pDM_SWAT_Table->CurAntenna == Antenna_A)? Antenna_B : Antenna_A; ++ pDM_SWAT_Table->try_flag = 1; ++ pHalData->RSSI_test = TRUE; ++ if((curRxOkCnt+curTxOkCnt) > 1000) ++ { ++#if DEV_BUS_TYPE==RT_PCI_INTERFACE ++ pDM_SWAT_Table->RSSI_Trying = 4; ++#else ++ pDM_SWAT_Table->RSSI_Trying = 2; ++#endif ++ pDM_SWAT_Table->TestMode = TP_MODE; ++ } ++ else ++ { ++ pDM_SWAT_Table->RSSI_Trying = 2; ++ pDM_SWAT_Table->TestMode = RSSI_MODE; ++ ++ } ++ ++ //RT_TRACE(COMP_SWAS, DBG_LOUD, ("SWAS: Normal State -> Begin Trying!\n")); ++ pHalData->RSSI_sum_A = 0; ++ pHalData->RSSI_cnt_A = 0; ++ pHalData->RSSI_sum_B = 0; ++ pHalData->RSSI_cnt_B = 0; ++ } // end of try_flag=0 ++ } ++ ++ //1 4.Change TRX antenna ++ if(nextAntenna != pDM_SWAT_Table->CurAntenna) ++ { ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Change TX Antenna!\n ")); ++ //PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300, nextAntenna); for 88C ++ if(nextAntenna==Antenna_A) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Next Antenna is RF PATH A\n ")); ++ pathdiv_para = 0x02; //02 to switchback to RF path A ++ fw_value = 0x03; ++#if DEV_BUS_TYPE==RT_PCI_INTERFACE ++ odm_PathDiversity_8192D(pDM_Odm, pathdiv_para); ++#else ++ ODM_FillH2CCmd(Adapter, ODM_H2C_PathDiv,1,(pu1Byte)(&fw_value)); ++#endif ++ } ++ else if(nextAntenna==Antenna_B) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Next Antenna is RF PATH B\n ")); ++ if(switchfirsttime==0) // First Time To Enter Path Diversity ++ { ++ switchfirsttime=0x01; ++ pathdiv_para = 0x00; ++ fw_value=0x00; // to backup RF Path A Releated Registers ++ ++#if DEV_BUS_TYPE==RT_PCI_INTERFACE ++ odm_PathDiversity_8192D(pDM_Odm, pathdiv_para); ++#else ++ ODM_FillH2CCmd(Adapter, ODM_H2C_PathDiv,1,(pu1Byte)(&fw_value)); ++ //for(u1Byte n=0; n<80,n++) ++ //{ ++ //delay_us(500); ++ ODM_delay_ms(500); ++ odm_PathDiversity_8192D(pDM_Odm, pathdiv_para); ++ ++ fw_value=0x01; // to backup RF Path A Releated Registers ++ ODM_FillH2CCmd(Adapter, ODM_H2C_PathDiv,1,(pu1Byte)(&fw_value)); ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: FIRST TIME To DO PATH SWITCH!\n ")); ++ } ++ else ++ { ++ pathdiv_para = 0x01; ++ fw_value = 0x02; ++#if DEV_BUS_TYPE==RT_PCI_INTERFACE ++ odm_PathDiversity_8192D(pDM_Odm, pathdiv_para); ++#else ++ ODM_FillH2CCmd(Adapter, ODM_H2C_PathDiv,1,(pu1Byte)(&fw_value)); ++#endif ++ } ++ } ++ // odm_PathDiversity_8192D(Adapter, pathdiv_para); ++ } ++ ++ //1 5.Reset Statistics ++ pDM_SWAT_Table->PreAntenna = pDM_SWAT_Table->CurAntenna; ++ pDM_SWAT_Table->CurAntenna = nextAntenna; ++ pDM_SWAT_Table->PreRSSI = curRSSI; ++ //lastTxOkCnt = Adapter->TxStats.NumTxBytesUnicast; ++ //lastRxOkCnt = Adapter->RxStats.NumRxBytesUnicast; ++ ++ //1 6.Set next timer ++ ++ if(pDM_SWAT_Table->RSSI_Trying == 0) ++ return; ++ ++ if(pDM_SWAT_Table->RSSI_Trying%2 == 0) ++ { ++ if(pDM_SWAT_Table->TestMode == TP_MODE) ++ { ++ if(TrafficLoad == TRAFFIC_HIGH) ++ { ++#if DEV_BUS_TYPE==RT_PCI_INTERFACE ++ ODM_SetTimer( pDM_Odm, &pDM_Odm->PathDivSwitchTimer, 10 ); //ms ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Test another antenna for 10 ms\n")); ++#else ++ ODM_SetTimer( pDM_Odm, &pDM_Odm->PathDivSwitchTimer, 20 ); //ms ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Test another antenna for 20 ms\n")); ++#endif ++ } ++ else if(TrafficLoad == TRAFFIC_LOW) ++ { ++ ODM_SetTimer( pDM_Odm, &pDM_Odm->PathDivSwitchTimer, 50 ); //ms ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Test another antenna for 50 ms\n")); ++ } ++ } ++ else // TestMode == RSSI_MODE ++ { ++ ODM_SetTimer( pDM_Odm, &pDM_Odm->PathDivSwitchTimer, 500 ); //ms ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Test another antenna for 500 ms\n")); ++ } ++ } ++ else ++ { ++ if(pDM_SWAT_Table->TestMode == TP_MODE) ++ { ++ if(TrafficLoad == TRAFFIC_HIGH) ++ ++#if DEV_BUS_TYPE==RT_PCI_INTERFACE ++ ODM_SetTimer( pDM_Odm, &pDM_Odm->PathDivSwitchTimer, 90 ); //ms ++ //ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Test another antenna for 90 ms\n")); ++#else ++ ODM_SetTimer( pDM_Odm, &pDM_Odm->PathDivSwitchTimer, 180); //ms ++#endif ++ else if(TrafficLoad == TRAFFIC_LOW) ++ ODM_SetTimer( pDM_Odm, &pDM_Odm->PathDivSwitchTimer, 100 ); //ms ++ } ++ else ++ ODM_SetTimer( pDM_Odm, &pDM_Odm->PathDivSwitchTimer, 500 ); //ms ++ } ++} ++ ++//================================================== ++//3 PathDiv End ++//================================================== ++ ++VOID ++odm_SetRespPath_92C( ++ IN PADAPTER Adapter, ++ IN u1Byte DefaultRespPath ++ ) ++{ ++ pPD_T pDM_PDTable = &Adapter->DM_PDTable; ++ ++ RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_SetRespPath_92C: Select Response Path=%d\n",DefaultRespPath)); ++ if(DefaultRespPath != pDM_PDTable->DefaultRespPath) ++ { ++ if(DefaultRespPath == 0) ++ { ++ PlatformEFIOWrite1Byte(Adapter, 0x6D8, (PlatformEFIORead1Byte(Adapter, 0x6D8)&0xc0)|0x15); ++ } ++ else ++ { ++ PlatformEFIOWrite1Byte(Adapter, 0x6D8, (PlatformEFIORead1Byte(Adapter, 0x6D8)&0xc0)|0x2A); ++ } ++ } ++ pDM_PDTable->DefaultRespPath = DefaultRespPath; ++} ++ ++ ++VOID ++ODM_FillTXPathInTXDESC( ++ IN PADAPTER Adapter, ++ IN PRT_TCB pTcb, ++ IN pu1Byte pDesc ++) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u4Byte TXPath; ++ pPD_T pDM_PDTable = &Adapter->DM_PDTable; ++ ++ //2011.09.05 Add by Luke Lee for path diversity ++ if(pHalData->PathDivCfg == 1) ++ { ++ TXPath = (pDM_PDTable->OFDMTXPath >> pTcb->macId) & BIT0; ++ //RT_TRACE( COMP_SWAS, DBG_LOUD, ("Fill TXDESC: macID=%d, TXPath=%d\n", pTcb->macId, TXPath)); ++ //SET_TX_DESC_TX_ANT_CCK(pDesc,TXPath); ++ if(TXPath == 0) ++ { ++ SET_TX_DESC_TX_ANTL_92C(pDesc,1); ++ SET_TX_DESC_TX_ANT_HT_92C(pDesc,1); ++ } ++ else ++ { ++ SET_TX_DESC_TX_ANTL_92C(pDesc,2); ++ SET_TX_DESC_TX_ANT_HT_92C(pDesc,2); ++ } ++ TXPath = (pDM_PDTable->CCKTXPath >> pTcb->macId) & BIT0; ++ if(TXPath == 0) ++ { ++ SET_TX_DESC_TX_ANT_CCK_92C(pDesc,1); ++ } ++ else ++ { ++ SET_TX_DESC_TX_ANT_CCK_92C(pDesc,2); ++ } ++ } ++} ++ ++//Only for MP //Neil Chen--2012--0502-- ++VOID ++odm_PathDivInit( ++IN PDM_ODM_T pDM_Odm) ++{ ++ pPATHDIV_PARA pathIQK = &pDM_Odm->pathIQK; ++ ++ pathIQK->org_2g_RegC14=0x0; ++ pathIQK->org_2g_RegC4C=0x0; ++ pathIQK->org_2g_RegC80=0x0; ++ pathIQK->org_2g_RegC94=0x0; ++ pathIQK->org_2g_RegCA0=0x0; ++ pathIQK->org_5g_RegC14=0x0; ++ pathIQK->org_5g_RegCA0=0x0; ++ pathIQK->org_5g_RegE30=0x0; ++ pathIQK->swt_2g_RegC14=0x0; ++ pathIQK->swt_2g_RegC4C=0x0; ++ pathIQK->swt_2g_RegC80=0x0; ++ pathIQK->swt_2g_RegC94=0x0; ++ pathIQK->swt_2g_RegCA0=0x0; ++ pathIQK->swt_5g_RegC14=0x0; ++ pathIQK->swt_5g_RegCA0=0x0; ++ pathIQK->swt_5g_RegE30=0x0; ++ ++} ++#endif // #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ++#if ((DM_ODM_SUPPORT_TYPE == ODM_MP)||(DM_ODM_SUPPORT_TYPE == ODM_CE)) ++ ++ ++// ++// Description: ++// Set Single/Dual Antenna default setting for products that do not do detection in advance. ++// ++// Added by Joseph, 2012.03.22 ++// ++VOID ++ODM_SingleDualAntennaDefaultSetting( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ pDM_SWAT_Table->ANTA_ON=TRUE; ++ pDM_SWAT_Table->ANTB_ON=TRUE; ++} ++ ++ ++//2 8723A ANT DETECT ++ ++ ++VOID ++odm_PHY_SaveAFERegisters( ++ IN PDM_ODM_T pDM_Odm, ++ IN pu4Byte AFEReg, ++ IN pu4Byte AFEBackup, ++ IN u4Byte RegisterNum ++ ) ++{ ++ u4Byte i; ++ ++ //RTPRINT(FINIT, INIT_IQK, ("Save ADDA parameters.\n")); ++ for( i = 0 ; i < RegisterNum ; i++){ ++ AFEBackup[i] = ODM_GetBBReg(pDM_Odm, AFEReg[i], bMaskDWord); ++ } ++} ++ ++VOID ++odm_PHY_ReloadAFERegisters( ++ IN PDM_ODM_T pDM_Odm, ++ IN pu4Byte AFEReg, ++ IN pu4Byte AFEBackup, ++ IN u4Byte RegiesterNum ++ ) ++{ ++ u4Byte i; ++ ++ //RTPRINT(FINIT, INIT_IQK, ("Reload ADDA power saving parameters !\n")); ++ for(i = 0 ; i < RegiesterNum; i++) ++ { ++ ++ ODM_SetBBReg(pDM_Odm, AFEReg[i], bMaskDWord, AFEBackup[i]); ++ } ++} ++ ++//2 8723A ANT DETECT ++// ++// Description: ++// Implement IQK single tone for RF DPK loopback and BB PSD scanning. ++// This function is cooperated with BB team Neil. ++// ++// Added by Roger, 2011.12.15 ++// ++BOOLEAN ++ODM_SingleDualAntennaDetection( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte mode ++ ) ++{ ++ ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ //PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ u4Byte CurrentChannel,RfLoopReg; ++ u1Byte n; ++ u4Byte Reg88c, Regc08, Reg874, Regc50; ++ u1Byte initial_gain = 0x5a; ++ u4Byte PSD_report_tmp; ++ u4Byte AntA_report = 0x0, AntB_report = 0x0,AntO_report=0x0; ++ BOOLEAN bResult = TRUE; ++ u4Byte AFE_Backup[16]; ++ u4Byte AFE_REG_8723A[16] = { ++ rRx_Wait_CCA, rTx_CCK_RFON, ++ rTx_CCK_BBON, rTx_OFDM_RFON, ++ rTx_OFDM_BBON, rTx_To_Rx, ++ rTx_To_Tx, rRx_CCK, ++ rRx_OFDM, rRx_Wait_RIFS, ++ rRx_TO_Rx, rStandby, ++ rSleep, rPMPD_ANAEN, ++ rFPGA0_XCD_SwitchControl, rBlue_Tooth}; ++ ++ if(!(pDM_Odm->SupportICType & (ODM_RTL8723A|ODM_RTL8192C))) ++ return bResult; ++ ++ if(!(pDM_Odm->SupportAbility&ODM_BB_ANT_DIV)) ++ return bResult; ++ ++ if(pDM_Odm->SupportICType == ODM_RTL8192C) ++ { ++ //Which path in ADC/DAC is turnned on for PSD: both I/Q ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT10|BIT11, 0x3); ++ //Ageraged number: 8 ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT12|BIT13, 0x1); ++ //pts = 128; ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x0); ++ } ++ ++ //1 Backup Current RF/BB Settings ++ ++ CurrentChannel = ODM_GetRFReg(pDM_Odm, RF_PATH_A, ODM_CHANNEL, bRFRegOffsetMask); ++ RfLoopReg = ODM_GetRFReg(pDM_Odm, RF_PATH_A, 0x00, bRFRegOffsetMask); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, ODM_DPDT, Antenna_A); // change to Antenna A ++ // Step 1: USE IQK to transmitter single tone ++ ++ ODM_StallExecution(10); ++ ++ //Store A Path Register 88c, c08, 874, c50 ++ Reg88c = ODM_GetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord); ++ Regc08 = ODM_GetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord); ++ Reg874 = ODM_GetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord); ++ Regc50 = ODM_GetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskDWord); ++ ++ // Store AFE Registers ++ odm_PHY_SaveAFERegisters(pDM_Odm, AFE_REG_8723A, AFE_Backup, 16); ++ ++ //Set PSD 128 pts ++ ODM_SetBBReg(pDM_Odm, rFPGA0_PSDFunction, BIT14|BIT15, 0x0); //128 pts ++ ++ // To SET CH1 to do ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, ODM_CHANNEL, bRFRegOffsetMask, 0x01); //Channel 1 ++ ++ // AFE all on step ++ ODM_SetBBReg(pDM_Odm, rRx_Wait_CCA, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rTx_CCK_RFON, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rTx_CCK_BBON, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rTx_OFDM_RFON, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rTx_OFDM_BBON, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rTx_To_Rx, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rTx_To_Tx, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rRx_CCK, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rRx_OFDM, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rRx_Wait_RIFS, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rRx_TO_Rx, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rStandby, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rSleep, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rPMPD_ANAEN, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_SwitchControl, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rBlue_Tooth, bMaskDWord, 0x6FDB25A4); ++ ++ // 3 wire Disable ++ ODM_SetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord, 0xCCF000C0); ++ ++ //BB IQK Setting ++ ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, 0x000800E4); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22208000); ++ ++ //IQK setting tone@ 4.34Mhz ++ ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008C1C); ++ ODM_SetBBReg(pDM_Odm, rTx_IQK, bMaskDWord, 0x01007c00); ++ ++ ++ //Page B init ++ ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x00080000); ++ ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x0f600000); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK, bMaskDWord, 0x01004800); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x10008c1f); ++ ODM_SetBBReg(pDM_Odm, rTx_IQK_PI_A, bMaskDWord, 0x82150008); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK_PI_A, bMaskDWord, 0x28150008); ++ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Rsp, bMaskDWord, 0x001028d0); ++ ++ //RF loop Setting ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x0, 0xFFFFF, 0x50008); ++ ++ //IQK Single tone start ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80800000); ++ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); ++ ODM_StallExecution(1000); ++ PSD_report_tmp=0x0; ++ ++ for (n=0;n<2;n++) ++ { ++ PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain); ++ if(PSD_report_tmp >AntA_report) ++ AntA_report=PSD_report_tmp; ++ } ++ ++ PSD_report_tmp=0x0; ++ ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_B); // change to Antenna B ++ ODM_StallExecution(10); ++ ++ ++ for (n=0;n<2;n++) ++ { ++ PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain); ++ if(PSD_report_tmp > AntB_report) ++ AntB_report=PSD_report_tmp; ++ } ++ ++ // change to open case ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, 0); // change to Ant A and B all open case ++ ODM_StallExecution(10); ++ ++ for (n=0;n<2;n++) ++ { ++ PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain); ++ if(PSD_report_tmp > AntO_report) ++ AntO_report=PSD_report_tmp; ++ } ++ ++ //Close IQK Single Tone function ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ PSD_report_tmp = 0x0; ++ ++ //1 Return to antanna A ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_A); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord, Reg88c); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, Regc08); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, Reg874); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, 0x7F, 0x40); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskDWord, Regc50); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask,CurrentChannel); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x00, bRFRegOffsetMask,RfLoopReg); ++ ++ //Reload AFE Registers ++ odm_PHY_ReloadAFERegisters(pDM_Odm, AFE_REG_8723A, AFE_Backup, 16); ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_A[%d]= %d \n", 2416, AntA_report)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_B[%d]= %d \n", 2416, AntB_report)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_O[%d]= %d \n", 2416, AntO_report)); ++ ++ ++ if(pDM_Odm->SupportICType == ODM_RTL8723A) ++ { ++ //2 Test Ant B based on Ant A is ON ++ if(mode==ANTTESTB) ++ { ++ if(AntA_report >= 100) ++ { ++ if(AntB_report > (AntA_report+1)) ++ { ++ pDM_SWAT_Table->ANTB_ON=FALSE; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna A\n")); ++ } ++ else ++ { ++ pDM_SWAT_Table->ANTB_ON=TRUE; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Dual Antenna is A and B\n")); ++ } ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n")); ++ pDM_SWAT_Table->ANTB_ON=FALSE; // Set Antenna B off as default ++ bResult = FALSE; ++ } ++ } ++ //2 Test Ant A and B based on DPDT Open ++ else if(mode==ANTTESTALL) ++ { ++ if((AntO_report >=100)&(AntO_report <118)) ++ { ++ if(AntA_report > (AntO_report+1)) ++ { ++ pDM_SWAT_Table->ANTA_ON=FALSE; ++ //RT_TRACE(COMP_ANTENNA, DBG_LOUD, ("ODM_AntennaDetection(): Antenna A is OFF\n")); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("Ant A is OFF")); ++ } ++ else ++ { ++ pDM_SWAT_Table->ANTA_ON=TRUE; ++ //RT_TRACE(COMP_ANTENNA, DBG_LOUD, ("ODM_AntennaDetection(): Antenna A is ON\n")); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("Ant A is ON")); ++ } ++ ++ if(AntB_report > (AntO_report+2)) ++ { ++ pDM_SWAT_Table->ANTB_ON=FALSE; ++ //RT_TRACE(COMP_ANTENNA, DBG_LOUD, ("ODM_AntennaDetection(): Antenna B is OFF\n")); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("Ant B is OFF")); ++ } ++ else ++ { ++ pDM_SWAT_Table->ANTB_ON=TRUE; ++ //RT_TRACE(COMP_ANTENNA, DBG_LOUD, ("ODM_AntennaDetection(): Antenna B is ON\n")); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("Ant B is ON")); ++ } ++ } ++ } ++ } ++ else if(pDM_Odm->SupportICType == ODM_RTL8192C) ++ { ++ if(AntA_report >= 100) ++ { ++ if(AntB_report > (AntA_report+2)) ++ { ++ pDM_SWAT_Table->ANTA_ON=FALSE; ++ pDM_SWAT_Table->ANTB_ON=TRUE; ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_B); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna B\n")); ++ } ++ else if(AntA_report > (AntB_report+2)) ++ { ++ pDM_SWAT_Table->ANTA_ON=TRUE; ++ pDM_SWAT_Table->ANTB_ON=FALSE; ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_A); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna A\n")); ++ } ++ else ++ { ++ pDM_SWAT_Table->ANTA_ON=TRUE; ++ pDM_SWAT_Table->ANTB_ON=TRUE; ++ RT_TRACE(COMP_ANTENNA, DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Dual Antenna \n")); ++ } ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n")); ++ pDM_SWAT_Table->ANTA_ON=TRUE; // Set Antenna A on as default ++ pDM_SWAT_Table->ANTB_ON=FALSE; // Set Antenna B off as default ++ bResult = FALSE; ++ } ++ } ++ return bResult; ++ ++} ++ ++ ++#endif // end odm_CE ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++/* Justin: According to the current RRSI to adjust Response Frame TX power, 2012/11/05 */ ++void odm_dtc(PDM_ODM_T pDM_Odm) ++{ ++#ifdef CONFIG_DM_RESP_TXAGC ++ #define DTC_BASE 35 /* RSSI higher than this value, start to decade TX power */ ++ #define DTC_DWN_BASE (DTC_BASE-5) /* RSSI lower than this value, start to increase TX power */ ++ ++ /* RSSI vs TX power step mapping: decade TX power */ ++ static const u8 dtc_table_down[]={ ++ DTC_BASE, ++ (DTC_BASE+5), ++ (DTC_BASE+10), ++ (DTC_BASE+15), ++ (DTC_BASE+20), ++ (DTC_BASE+25) ++ }; ++ ++ /* RSSI vs TX power step mapping: increase TX power */ ++ static const u8 dtc_table_up[]={ ++ DTC_DWN_BASE, ++ (DTC_DWN_BASE-5), ++ (DTC_DWN_BASE-10), ++ (DTC_DWN_BASE-15), ++ (DTC_DWN_BASE-15), ++ (DTC_DWN_BASE-20), ++ (DTC_DWN_BASE-20), ++ (DTC_DWN_BASE-25), ++ (DTC_DWN_BASE-25), ++ (DTC_DWN_BASE-30), ++ (DTC_DWN_BASE-35) ++ }; ++ ++ u8 i; ++ u8 dtc_steps=0; ++ u8 sign; ++ u8 resp_txagc=0; ++ ++ #if 0 ++ /* As DIG is disabled, DTC is also disable */ ++ if(!(pDM_Odm->SupportAbility & ODM_XXXXXX)) ++ return; ++ #endif ++ ++ if (DTC_BASE < pDM_Odm->RSSI_Min) { ++ /* need to decade the CTS TX power */ ++ sign = 1; ++ for (i=0;i= pDM_Odm->RSSI_Min) || (dtc_steps >= 6)) ++ break; ++ else ++ dtc_steps++; ++ } ++ } ++#if 0 ++ else if (DTC_DWN_BASE > pDM_Odm->RSSI_Min) ++ { ++ /* needs to increase the CTS TX power */ ++ sign = 0; ++ dtc_steps = 1; ++ for (i=0;iRSSI_Min) || (dtc_steps>=10)) ++ break; ++ else ++ dtc_steps++; ++ } ++ } ++#endif ++ else ++ { ++ sign = 0; ++ dtc_steps = 0; ++ } ++ ++ resp_txagc = dtc_steps | (sign << 4); ++ resp_txagc = resp_txagc | (resp_txagc << 5); ++ ODM_Write1Byte(pDM_Odm, 0x06d9, resp_txagc); ++ ++ DBG_871X("%s RSSI_Min:%u, set RESP_TXAGC to %s %u\n", ++ __func__, pDM_Odm->RSSI_Min, sign?"minus":"plus", dtc_steps); ++#endif /* CONFIG_RESP_TXAGC_ADJUST */ ++} ++ ++#endif /* #if (DM_ODM_SUPPORT_TYPE == ODM_CE) */ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm.h +new file mode 100644 +index 00000000..f5add651 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm.h +@@ -0,0 +1,2063 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++ ++#ifndef __HALDMOUTSRC_H__ ++#define __HALDMOUTSRC_H__ ++ ++//============================================================ ++// Definition ++//============================================================ ++// ++// 2011/09/22 MH Define all team supprt ability. ++// ++ ++// ++// 2011/09/22 MH Define for all teams. Please Define the constan in your precomp header. ++// ++//#define DM_ODM_SUPPORT_AP 0 ++//#define DM_ODM_SUPPORT_ADSL 0 ++//#define DM_ODM_SUPPORT_CE 0 ++//#define DM_ODM_SUPPORT_MP 1 ++ ++// ++// 2011/09/28 MH Define ODM SW team support flag. ++// ++ ++ ++ ++// ++// Antenna Switch Relative Definition. ++// ++ ++// ++// 20100503 Joseph: ++// Add new function SwAntDivCheck8192C(). ++// This is the main function of Antenna diversity function before link. ++// Mainly, it just retains last scan result and scan again. ++// After that, it compares the scan result to see which one gets better RSSI. ++// It selects antenna with better receiving power and returns better scan result. ++// ++#define TP_MODE 0 ++#define RSSI_MODE 1 ++#define TRAFFIC_LOW 0 ++#define TRAFFIC_HIGH 1 ++ ++ ++//============================================================ ++//3 Tx Power Tracking ++//3============================================================ ++#define DPK_DELTA_MAPPING_NUM 13 ++#define index_mapping_HP_NUM 15 ++ ++ ++//============================================================ ++//3 PSD Handler ++//3============================================================ ++ ++#define AFH_PSD 1 //0:normal PSD scan, 1: only do 20 pts PSD ++#define MODE_40M 0 //0:20M, 1:40M ++#define PSD_TH2 3 ++#define PSD_CHMIN 20 // Minimum channel number for BT AFH ++#define SIR_STEP_SIZE 3 ++#define Smooth_Size_1 5 ++#define Smooth_TH_1 3 ++#define Smooth_Size_2 10 ++#define Smooth_TH_2 4 ++#define Smooth_Size_3 20 ++#define Smooth_TH_3 4 ++#define Smooth_Step_Size 5 ++#define Adaptive_SIR 1 ++#if(RTL8723_FPGA_VERIFICATION == 1) ++#define PSD_RESCAN 1 ++#else ++#define PSD_RESCAN 4 ++#endif ++#define PSD_SCAN_INTERVAL 700 //ms ++ ++ ++ ++//8723A High Power IGI Setting ++#define DM_DIG_HIGH_PWR_IGI_LOWER_BOUND 0x22 ++#define DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND 0x28 ++#define DM_DIG_HIGH_PWR_THRESHOLD 0x3a ++#define DM_DIG_LOW_PWR_THRESHOLD 0x14 ++ ++//ANT Test ++#define ANTTESTALL 0x00 //Ant A or B will be Testing ++#define ANTTESTA 0x01 //Ant A will be Testing ++#define ANTTESTB 0x02 //Ant B will be testing ++ ++// LPS define ++#define DM_DIG_FA_TH0_LPS 4 //-> 4 in lps ++#define DM_DIG_FA_TH1_LPS 15 //-> 15 lps ++#define DM_DIG_FA_TH2_LPS 30 //-> 30 lps ++#define RSSI_OFFSET_DIG 0x05; ++ ++//ANT Test ++#define ANTTESTALL 0x00 //Ant A or B will be Testing ++#define ANTTESTA 0x01 //Ant A will be Testing ++#define ANTTESTB 0x02 //Ant B will be testing ++ ++ ++//============================================================ ++// structure and define ++//============================================================ ++ ++// ++// 2011/09/20 MH Add for AP/ADSLpseudo DM structuer requirement. ++// We need to remove to other position??? ++// ++#if(DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_MP)) ++typedef struct rtl8192cd_priv { ++ u1Byte temp; ++ ++}rtl8192cd_priv, *prtl8192cd_priv; ++#endif ++ ++ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++typedef struct _ADAPTER{ ++ u1Byte temp; ++ #ifdef AP_BUILD_WORKAROUND ++ HAL_DATA_TYPE* temp2; ++ prtl8192cd_priv priv; ++ #endif ++}ADAPTER, *PADAPTER; ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ ++typedef struct _WLAN_STA{ ++ u1Byte temp; ++} WLAN_STA, *PRT_WLAN_STA; ++ ++#endif ++ ++typedef struct _Dynamic_Initial_Gain_Threshold_ ++{ ++ u1Byte Dig_Enable_Flag; ++ u1Byte Dig_Ext_Port_Stage; ++ ++ int RssiLowThresh; ++ int RssiHighThresh; ++ ++ u4Byte FALowThresh; ++ u4Byte FAHighThresh; ++ ++ u1Byte CurSTAConnectState; ++ u1Byte PreSTAConnectState; ++ u1Byte CurMultiSTAConnectState; ++ ++ u1Byte PreIGValue; ++ u1Byte CurIGValue; ++ u1Byte BT30_CurIGI; ++ u1Byte BackupIGValue; ++ ++ s1Byte BackoffVal; ++ s1Byte BackoffVal_range_max; ++ s1Byte BackoffVal_range_min; ++ u1Byte rx_gain_range_max; ++ u1Byte rx_gain_range_min; ++ u1Byte Rssi_val_min; ++ ++ u1Byte PreCCK_CCAThres; ++ u1Byte CurCCK_CCAThres; ++ u1Byte PreCCKPDState; ++ u1Byte CurCCKPDState; ++ ++ u1Byte LargeFAHit; ++ u1Byte ForbiddenIGI; ++ u4Byte Recover_cnt; ++ ++ u1Byte DIG_Dynamic_MIN_0; ++ u1Byte DIG_Dynamic_MIN_1; ++ BOOLEAN bMediaConnect_0; ++ BOOLEAN bMediaConnect_1; ++ ++ u4Byte AntDiv_RSSI_max; ++ u4Byte RSSI_max; ++}DIG_T,*pDIG_T; ++ ++typedef struct _Dynamic_Power_Saving_ ++{ ++ u1Byte PreCCAState; ++ u1Byte CurCCAState; ++ ++ u1Byte PreRFState; ++ u1Byte CurRFState; ++ ++ int Rssi_val_min; ++ ++ u1Byte initialize; ++ u4Byte Reg874,RegC70,Reg85C,RegA74; ++ ++}PS_T,*pPS_T; ++ ++typedef struct _FALSE_ALARM_STATISTICS{ ++ u4Byte Cnt_Parity_Fail; ++ u4Byte Cnt_Rate_Illegal; ++ u4Byte Cnt_Crc8_fail; ++ u4Byte Cnt_Mcs_fail; ++ u4Byte Cnt_Ofdm_fail; ++ u4Byte Cnt_Cck_fail; ++ u4Byte Cnt_all; ++ u4Byte Cnt_Fast_Fsync; ++ u4Byte Cnt_SB_Search_fail; ++ u4Byte Cnt_OFDM_CCA; ++ u4Byte Cnt_CCK_CCA; ++ u4Byte Cnt_CCA_all; ++ u4Byte Cnt_BW_USC; //Gary ++ u4Byte Cnt_BW_LSC; //Gary ++}FALSE_ALARM_STATISTICS, *PFALSE_ALARM_STATISTICS; ++ ++typedef struct _Dynamic_Primary_CCA{ ++ u1Byte PriCCA_flag; ++ u1Byte intf_flag; ++ u1Byte intf_type; ++ u1Byte DupRTS_flag; ++ u1Byte Monitor_flag; ++}Pri_CCA_T, *pPri_CCA_T; ++ ++typedef struct _RX_High_Power_ ++{ ++ u1Byte RXHP_flag; ++ u1Byte PSD_func_trigger; ++ u1Byte PSD_bitmap_RXHP[80]; ++ u1Byte Pre_IGI; ++ u1Byte Cur_IGI; ++ u1Byte Pre_pw_th; ++ u1Byte Cur_pw_th; ++ BOOLEAN First_time_enter; ++ BOOLEAN RXHP_enable; ++ u1Byte TP_Mode; ++ RT_TIMER PSDTimer; ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ #if USE_WORKITEM ++ RT_WORK_ITEM PSDTimeWorkitem; ++ #endif ++#endif ++ ++}RXHP_T, *pRXHP_T; ++ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_CE)) ++#define ASSOCIATE_ENTRY_NUM 32 // Max size of AsocEntry[]. ++#define ODM_ASSOCIATE_ENTRY_NUM ASSOCIATE_ENTRY_NUM ++ ++#elif(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++#define ASSOCIATE_ENTRY_NUM NUM_STAT ++#define ODM_ASSOCIATE_ENTRY_NUM ASSOCIATE_ENTRY_NUM+1 ++ ++#else ++// ++// 2012/01/12 MH Revise for compatiable with other SW team. ++// 0 is for STA 1-n is for AP clients. ++// ++#define ODM_ASSOCIATE_ENTRY_NUM ASSOCIATE_ENTRY_NUM+1// Default port only one ++#endif ++ ++//#ifdef CONFIG_ANTENNA_DIVERSITY ++// This indicates two different the steps. ++// In SWAW_STEP_PEAK, driver needs to switch antenna and listen to the signal on the air. ++// In SWAW_STEP_DETERMINE, driver just compares the signal captured in SWAW_STEP_PEAK ++// with original RSSI to determine if it is necessary to switch antenna. ++#define SWAW_STEP_PEAK 0 ++#define SWAW_STEP_DETERMINE 1 ++ ++#define TP_MODE 0 ++#define RSSI_MODE 1 ++#define TRAFFIC_LOW 0 ++#define TRAFFIC_HIGH 1 ++ ++typedef struct _SW_Antenna_Switch_ ++{ ++ u1Byte try_flag; ++ s4Byte PreRSSI; ++ u1Byte CurAntenna; ++ u1Byte PreAntenna; ++ u1Byte RSSI_Trying; ++ u1Byte TestMode; ++ u1Byte bTriggerAntennaSwitch; ++ u1Byte SelectAntennaMap; ++ u1Byte RSSI_target; ++ ++ // Before link Antenna Switch check ++ u1Byte SWAS_NoLink_State; ++ u4Byte SWAS_NoLink_BK_Reg860; ++ BOOLEAN ANTA_ON; //To indicate Ant A is or not ++ BOOLEAN ANTB_ON; //To indicate Ant B is on or not ++ ++ s4Byte RSSI_sum_A; ++ s4Byte RSSI_sum_B; ++ s4Byte RSSI_cnt_A; ++ s4Byte RSSI_cnt_B; ++ ++ u8Byte lastTxOkCnt; ++ u8Byte lastRxOkCnt; ++ u8Byte TXByteCnt_A; ++ u8Byte TXByteCnt_B; ++ u8Byte RXByteCnt_A; ++ u8Byte RXByteCnt_B; ++ u1Byte TrafficLoad; ++ RT_TIMER SwAntennaSwitchTimer; ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ #if USE_WORKITEM ++ RT_WORK_ITEM SwAntennaSwitchWorkitem; ++ #endif ++#endif ++/* CE Platform use ++#ifdef CONFIG_SW_ANTENNA_DIVERSITY ++ _timer SwAntennaSwitchTimer; ++ u8Byte lastTxOkCnt; ++ u8Byte lastRxOkCnt; ++ u8Byte TXByteCnt_A; ++ u8Byte TXByteCnt_B; ++ u8Byte RXByteCnt_A; ++ u8Byte RXByteCnt_B; ++ u1Byte DoubleComfirm; ++ u1Byte TrafficLoad; ++ //SW Antenna Switch ++ ++ ++#endif ++*/ ++#ifdef CONFIG_HW_ANTENNA_DIVERSITY ++ //Hybrid Antenna Diversity ++ u4Byte CCK_Ant1_Cnt[ASSOCIATE_ENTRY_NUM]; ++ u4Byte CCK_Ant2_Cnt[ASSOCIATE_ENTRY_NUM]; ++ u4Byte OFDM_Ant1_Cnt[ASSOCIATE_ENTRY_NUM]; ++ u4Byte OFDM_Ant2_Cnt[ASSOCIATE_ENTRY_NUM]; ++ u4Byte RSSI_Ant1_Sum[ASSOCIATE_ENTRY_NUM]; ++ u4Byte RSSI_Ant2_Sum[ASSOCIATE_ENTRY_NUM]; ++ u1Byte TxAnt[ASSOCIATE_ENTRY_NUM]; ++ u1Byte TargetSTA; ++ u1Byte antsel; ++ u1Byte RxIdleAnt; ++ ++#endif ++ ++}SWAT_T, *pSWAT_T; ++//#endif ++ ++typedef struct _EDCA_TURBO_ ++{ ++ BOOLEAN bCurrentTurboEDCA; ++ BOOLEAN bIsCurRDLState; ++ #if(DM_ODM_SUPPORT_TYPE == ODM_CE ) ++ u4Byte prv_traffic_idx; // edca turbo ++ #endif ++ ++}EDCA_T,*pEDCA_T; ++ ++typedef struct _ODM_RATE_ADAPTIVE ++{ ++ u1Byte Type; // DM_Type_ByFW/DM_Type_ByDriver ++ u1Byte HighRSSIThresh; // if RSSI > HighRSSIThresh => RATRState is DM_RATR_STA_HIGH ++ u1Byte LowRSSIThresh; // if RSSI <= LowRSSIThresh => RATRState is DM_RATR_STA_LOW ++ u1Byte RATRState; // Current RSSI level, DM_RATR_STA_HIGH/DM_RATR_STA_MIDDLE/DM_RATR_STA_LOW ++ u4Byte LastRATR; // RATR Register Content ++ ++} ODM_RATE_ADAPTIVE, *PODM_RATE_ADAPTIVE; ++ ++ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ ++ ++#ifdef ADSL_AP_BUILD_WORKAROUND ++#define MAX_TOLERANCE 5 ++#define IQK_DELAY_TIME 1 //ms ++#endif ++ ++// ++// Indicate different AP vendor for IOT issue. ++// ++typedef enum _HT_IOT_PEER ++{ ++ HT_IOT_PEER_UNKNOWN = 0, ++ HT_IOT_PEER_REALTEK = 1, ++ HT_IOT_PEER_REALTEK_92SE = 2, ++ HT_IOT_PEER_BROADCOM = 3, ++ HT_IOT_PEER_RALINK = 4, ++ HT_IOT_PEER_ATHEROS = 5, ++ HT_IOT_PEER_CISCO = 6, ++ HT_IOT_PEER_MERU = 7, ++ HT_IOT_PEER_MARVELL = 8, ++ HT_IOT_PEER_REALTEK_SOFTAP = 9,// peer is RealTek SOFT_AP, by Bohn, 2009.12.17 ++ HT_IOT_PEER_SELF_SOFTAP = 10, // Self is SoftAP ++ HT_IOT_PEER_AIRGO = 11, ++ HT_IOT_PEER_INTEL = 12, ++ HT_IOT_PEER_RTK_APCLIENT = 13, ++ HT_IOT_PEER_REALTEK_81XX = 14, ++ HT_IOT_PEER_REALTEK_WOW = 15, ++ HT_IOT_PEER_MAX = 16 ++}HT_IOT_PEER_E, *PHTIOT_PEER_E; ++#endif//#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ ++ ++ ++#define IQK_MAC_REG_NUM 4 ++#define IQK_ADDA_REG_NUM 16 ++#define IQK_BB_REG_NUM_MAX 10 ++#if (RTL8192D_SUPPORT==1) ++#define IQK_BB_REG_NUM 10 ++#else ++#define IQK_BB_REG_NUM 9 ++#endif ++#define HP_THERMAL_NUM 8 ++ ++#define AVG_THERMAL_NUM 8 ++#define IQK_Matrix_REG_NUM 8 ++#define IQK_Matrix_Settings_NUM 1+24+21 ++ ++#define DM_Type_ByFW 0 ++#define DM_Type_ByDriver 1 ++ ++// ++// Declare for common info ++// ++// Declare for common info ++// ++#define MAX_PATH_NUM_92CS 2 ++ ++typedef struct _ODM_Phy_Status_Info_ ++{ ++ u1Byte RxPWDBAll; ++ u1Byte SignalQuality; // in 0-100 index. ++ u1Byte RxMIMOSignalQuality[MAX_PATH_NUM_92CS]; //EVM ++ u1Byte RxMIMOSignalStrength[MAX_PATH_NUM_92CS];// in 0~100 index ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE)) ++ s1Byte RxPower; // in dBm Translate from PWdB ++ s1Byte RecvSignalPower;// Real power in dBm for this packet, no beautification and aggregation. Keep this raw info to be used for the other procedures. ++ u1Byte BTRxRSSIPercentage; ++ u1Byte SignalStrength; // in 0-100 index. ++ u1Byte RxPwr[MAX_PATH_NUM_92CS];//per-path's pwdb ++#endif ++ u1Byte RxSNR[MAX_PATH_NUM_92CS];//per-path's SNR ++}ODM_PHY_INFO_T,*PODM_PHY_INFO_T; ++ ++ ++typedef struct _ODM_Phy_Dbg_Info_ ++{ ++ //ODM Write,debug info ++ s1Byte RxSNRdB[MAX_PATH_NUM_92CS]; ++ u8Byte NumQryPhyStatus; ++ u8Byte NumQryPhyStatusCCK; ++ u8Byte NumQryPhyStatusOFDM; ++ u1Byte NumQryBeaconPkt; ++ //Others ++ s4Byte RxEVM[MAX_PATH_NUM_92CS]; ++ ++}ODM_PHY_DBG_INFO_T; ++ ++ ++typedef struct _ODM_Per_Pkt_Info_ ++{ ++ u1Byte Rate; ++ u1Byte StationID; ++ BOOLEAN bPacketMatchBSSID; ++ BOOLEAN bPacketToSelf; ++ BOOLEAN bPacketBeacon; ++}ODM_PACKET_INFO_T,*PODM_PACKET_INFO_T; ++ ++typedef struct _ODM_Mac_Status_Info_ ++{ ++ u1Byte test; ++ ++}ODM_MAC_INFO; ++ ++ ++typedef enum tag_Dynamic_ODM_Support_Ability_Type ++{ ++ // BB Team ++ ODM_DIG = 0x00000001, ++ ODM_HIGH_POWER = 0x00000002, ++ ODM_CCK_CCA_TH = 0x00000004, ++ ODM_FA_STATISTICS = 0x00000008, ++ ODM_RAMASK = 0x00000010, ++ ODM_RSSI_MONITOR = 0x00000020, ++ ODM_SW_ANTDIV = 0x00000040, ++ ODM_HW_ANTDIV = 0x00000080, ++ ODM_BB_PWRSV = 0x00000100, ++ ODM_2TPATHDIV = 0x00000200, ++ ODM_1TPATHDIV = 0x00000400, ++ ODM_PSD2AFH = 0x00000800 ++}ODM_Ability_E; ++ ++// ++// 2011/20/20 MH For MP driver RT_WLAN_STA = STA_INFO_T ++// Please declare below ODM relative info in your STA info structure. ++// ++#if 1 ++typedef struct _ODM_STA_INFO{ ++ // Driver Write ++ BOOLEAN bUsed; // record the sta status link or not? ++ //u1Byte WirelessMode; // ++ u1Byte IOTPeer; // Enum value. HT_IOT_PEER_E ++ ++ // ODM Write ++ //1 PHY_STATUS_INFO ++ u1Byte RSSI_Path[4]; // ++ u1Byte RSSI_Ave; ++ u1Byte RXEVM[4]; ++ u1Byte RXSNR[4]; ++ ++ // ODM Write ++ //1 TX_INFO (may changed by IC) ++ //TX_INFO_T pTxInfo; // Define in IC folder. Move lower layer. ++#if 0 ++ u1Byte ANTSEL_A; //in Jagar: 4bit; others: 2bit ++ u1Byte ANTSEL_B; //in Jagar: 4bit; others: 2bit ++ u1Byte ANTSEL_C; //only in Jagar: 4bit ++ u1Byte ANTSEL_D; //only in Jagar: 4bit ++ u1Byte TX_ANTL; //not in Jagar: 2bit ++ u1Byte TX_ANT_HT; //not in Jagar: 2bit ++ u1Byte TX_ANT_CCK; //not in Jagar: 2bit ++ u1Byte TXAGC_A; //not in Jagar: 4bit ++ u1Byte TXAGC_B; //not in Jagar: 4bit ++ u1Byte TXPWR_OFFSET; //only in Jagar: 3bit ++ u1Byte TX_ANT; //only in Jagar: 4bit for TX_ANTL/TX_ANTHT/TX_ANT_CCK ++#endif ++ ++ // ++ // Please use compile flag to disabe the strcutrue for other IC except 88E. ++ // Move To lower layer. ++ // ++ // ODM Write Wilson will handle this part(said by Luke.Lee) ++ //TX_RPT_T pTxRpt; // Define in IC folder. Move lower layer. ++#if 0 ++ //1 For 88E RA (don't redefine the naming) ++ u1Byte rate_id; ++ u1Byte rate_SGI; ++ u1Byte rssi_sta_ra; ++ u1Byte SGI_enable; ++ u1Byte Decision_rate; ++ u1Byte Pre_rate; ++ u1Byte Active; ++ ++ // Driver write Wilson handle. ++ //1 TX_RPT (don't redefine the naming) ++ u2Byte RTY[4]; // ??? ++ u2Byte TOTAL; // ??? ++ u2Byte DROP; // ??? ++ // ++ // Please use compile flag to disabe the strcutrue for other IC except 88E. ++ // ++#endif ++ ++}ODM_STA_INFO_T, *PODM_STA_INFO_T; ++#endif ++ ++// ++// 2011/10/20 MH Define Common info enum for all team. ++// ++typedef enum _ODM_Common_Info_Definition ++{ ++//-------------REMOVED CASE-----------// ++ //ODM_CMNINFO_CCK_HP, ++ //ODM_CMNINFO_RFPATH_ENABLE, // Define as ODM write??? ++ //ODM_CMNINFO_BT_COEXIST, // ODM_BT_COEXIST_E ++ //ODM_CMNINFO_OP_MODE, // ODM_OPERATION_MODE_E ++//-------------REMOVED CASE-----------// ++ ++ // ++ // Fixed value: ++ // ++ ++ //-----------HOOK BEFORE REG INIT-----------// ++ ODM_CMNINFO_PLATFORM = 0, ++ ODM_CMNINFO_ABILITY, // ODM_ABILITY_E ++ ODM_CMNINFO_INTERFACE, // ODM_INTERFACE_E ++ ODM_CMNINFO_MP_TEST_CHIP, ++ ODM_CMNINFO_IC_TYPE, // ODM_IC_TYPE_E ++ ODM_CMNINFO_CUT_VER, // ODM_CUT_VERSION_E ++ ODM_CMNINFO_FAB_VER, // ODM_FAB_E ++ ODM_CMNINFO_RF_TYPE, // ODM_RF_PATH_E or ODM_RF_TYPE_E? ++ ODM_CMNINFO_BOARD_TYPE, // ODM_BOARD_TYPE_E ++ ODM_CMNINFO_EXT_LNA, // TRUE ++ ODM_CMNINFO_EXT_PA, ++ ODM_CMNINFO_EXT_TRSW, ++ ODM_CMNINFO_PATCH_ID, //CUSTOMER ID ++ ODM_CMNINFO_BINHCT_TEST, ++ ODM_CMNINFO_BWIFI_TEST, ++ ODM_CMNINFO_SMART_CONCURRENT, ++ //-----------HOOK BEFORE REG INIT-----------// ++ ++ ++ // ++ // Dynamic value: ++ // ++//--------- POINTER REFERENCE-----------// ++ ODM_CMNINFO_MAC_PHY_MODE, // ODM_MAC_PHY_MODE_E ++ ODM_CMNINFO_TX_UNI, ++ ODM_CMNINFO_RX_UNI, ++ ODM_CMNINFO_WM_MODE, // ODM_WIRELESS_MODE_E ++ ODM_CMNINFO_BAND, // ODM_BAND_TYPE_E ++ ODM_CMNINFO_SEC_CHNL_OFFSET, // ODM_SEC_CHNL_OFFSET_E ++ ODM_CMNINFO_SEC_MODE, // ODM_SECURITY_E ++ ODM_CMNINFO_BW, // ODM_BW_E ++ ODM_CMNINFO_CHNL, ++ ++ ODM_CMNINFO_DMSP_GET_VALUE, ++ ODM_CMNINFO_BUDDY_ADAPTOR, ++ ODM_CMNINFO_DMSP_IS_MASTER, ++ ODM_CMNINFO_SCAN, ++ ODM_CMNINFO_POWER_SAVING, ++ ODM_CMNINFO_ONE_PATH_CCA, // ODM_CCA_PATH_E ++ ODM_CMNINFO_DRV_STOP, ++ ODM_CMNINFO_PNP_IN, ++ ODM_CMNINFO_INIT_ON, ++ ODM_CMNINFO_ANT_TEST, ++ ODM_CMNINFO_NET_CLOSED, ++ ODM_CMNINFO_MP_MODE, ++//--------- POINTER REFERENCE-----------// ++ ++//------------CALL BY VALUE-------------// ++ ODM_CMNINFO_WIFI_DIRECT, ++ ODM_CMNINFO_WIFI_DISPLAY, ++ ODM_CMNINFO_LINK, ++ ODM_CMNINFO_RSSI_MIN, ++ ODM_CMNINFO_DBG_COMP, // u8Byte ++ ODM_CMNINFO_DBG_LEVEL, // u4Byte ++ ODM_CMNINFO_RA_THRESHOLD_HIGH, // u1Byte ++ ODM_CMNINFO_RA_THRESHOLD_LOW, // u1Byte ++ ODM_CMNINFO_RF_ANTENNA_TYPE, // u1Byte ++ ODM_CMNINFO_BT_DISABLED, ++ ODM_CMNINFO_BT_OPERATION, ++ ODM_CMNINFO_BT_DIG, ++ ODM_CMNINFO_BT_BUSY, //Check Bt is using or not//neil ++ ODM_CMNINFO_BT_DISABLE_EDCA, ++ ODM_CMNINFO_STATION_STATE, ++//------------CALL BY VALUE-------------// ++ ++ // ++ // Dynamic ptr array hook itms. ++ // ++ ODM_CMNINFO_STA_STATUS, ++ ODM_CMNINFO_PHY_STATUS, ++ ODM_CMNINFO_MAC_STATUS, ++ ++ ODM_CMNINFO_MAX, ++ ++ ++}ODM_CMNINFO_E; ++ ++// ++// 2011/10/20 MH Define ODM support ability. ODM_CMNINFO_ABILITY ++// ++typedef enum _ODM_Support_Ability_Definition ++{ ++ // ++ // BB ODM section BIT 0-15 ++ // ++ ODM_BB_DIG = BIT0, ++ ODM_BB_RA_MASK = BIT1, ++ ODM_BB_DYNAMIC_TXPWR = BIT2, ++ ODM_BB_FA_CNT = BIT3, ++ ODM_BB_RSSI_MONITOR = BIT4, ++ ODM_BB_CCK_PD = BIT5, ++ ODM_BB_ANT_DIV = BIT6, ++ ODM_BB_PWR_SAVE = BIT7, ++ ODM_BB_PWR_TRAIN = BIT8, ++ ODM_BB_RATE_ADAPTIVE = BIT9, ++ ODM_BB_PATH_DIV = BIT10, ++ ODM_BB_PSD = BIT11, ++ ODM_BB_RXHP = BIT12, ++ ODM_BB_ADAPTIVITY = BIT13, ++ ODM_BB_DYNAMIC_ATC = BIT14, ++ ++ // ++ // MAC DM section BIT 16-23 ++ // ++ ODM_MAC_EDCA_TURBO = BIT16, ++ ODM_MAC_EARLY_MODE = BIT17, ++ ++ // ++ // RF ODM section BIT 24-31 ++ // ++ ODM_RF_TX_PWR_TRACK = BIT24, ++ ODM_RF_RX_GAIN_TRACK = BIT25, ++ ODM_RF_CALIBRATION = BIT26, ++ ++}ODM_ABILITY_E; ++ ++// ODM_CMNINFO_INTERFACE ++typedef enum tag_ODM_Support_Interface_Definition ++{ ++ ODM_ITRF_PCIE = 0x1, ++ ODM_ITRF_USB = 0x2, ++ ODM_ITRF_SDIO = 0x4, ++ ODM_ITRF_ALL = 0x7, ++}ODM_INTERFACE_E; ++ ++// ODM_CMNINFO_IC_TYPE ++typedef enum tag_ODM_Support_IC_Type_Definition ++{ ++ ODM_RTL8192S = BIT0, ++ ODM_RTL8192C = BIT1, ++ ODM_RTL8192D = BIT2, ++ ODM_RTL8723A = BIT3, ++ ODM_RTL8188E = BIT4, ++ ODM_RTL8812 = BIT5, ++ ODM_RTL8821 = BIT6, ++ ODM_RTL8192E = BIT7, ++ ODM_RTL8723B = BIT8, ++ ODM_RTL8813A = BIT9, ++ ODM_RTL8881A = BIT10 ++}ODM_IC_TYPE_E; ++ ++#define ODM_IC_11N_SERIES (ODM_RTL8192S|ODM_RTL8192C|ODM_RTL8192D|ODM_RTL8723A|ODM_RTL8188E) ++#define ODM_IC_11AC_SERIES (ODM_RTL8812) ++ ++//ODM_CMNINFO_CUT_VER ++typedef enum tag_ODM_Cut_Version_Definition ++{ ++ ODM_CUT_A = 1, ++ ODM_CUT_B = 2, ++ ODM_CUT_C = 3, ++ ODM_CUT_D = 4, ++ ODM_CUT_E = 5, ++ ODM_CUT_F = 6, ++ ODM_CUT_TEST = 7, ++}ODM_CUT_VERSION_E; ++ ++// ODM_CMNINFO_FAB_VER ++typedef enum tag_ODM_Fab_Version_Definition ++{ ++ ODM_TSMC = 0, ++ ODM_UMC = 1, ++}ODM_FAB_E; ++ ++// ODM_CMNINFO_RF_TYPE ++// ++// For example 1T2R (A+AB = BIT0|BIT4|BIT5) ++// ++typedef enum tag_ODM_RF_Path_Bit_Definition ++{ ++ ODM_RF_TX_A = BIT0, ++ ODM_RF_TX_B = BIT1, ++ ODM_RF_TX_C = BIT2, ++ ODM_RF_TX_D = BIT3, ++ ODM_RF_RX_A = BIT4, ++ ODM_RF_RX_B = BIT5, ++ ODM_RF_RX_C = BIT6, ++ ODM_RF_RX_D = BIT7, ++}ODM_RF_PATH_E; ++ ++ ++typedef enum tag_ODM_RF_Type_Definition ++{ ++ ODM_1T1R = 0, ++ ODM_1T2R = 1, ++ ODM_2T2R = 2, ++ ODM_2T3R = 3, ++ ODM_2T4R = 4, ++ ODM_3T3R = 5, ++ ODM_3T4R = 6, ++ ODM_4T4R = 7, ++}ODM_RF_TYPE_E; ++ ++ ++// ++// ODM Dynamic common info value definition ++// ++ ++//typedef enum _MACPHY_MODE_8192D{ ++// SINGLEMAC_SINGLEPHY, ++// DUALMAC_DUALPHY, ++// DUALMAC_SINGLEPHY, ++//}MACPHY_MODE_8192D,*PMACPHY_MODE_8192D; ++// Above is the original define in MP driver. Please use the same define. THX. ++typedef enum tag_ODM_MAC_PHY_Mode_Definition ++{ ++ ODM_SMSP = 0, ++ ODM_DMSP = 1, ++ ODM_DMDP = 2, ++}ODM_MAC_PHY_MODE_E; ++ ++ ++typedef enum tag_BT_Coexist_Definition ++{ ++ ODM_BT_BUSY = 1, ++ ODM_BT_ON = 2, ++ ODM_BT_OFF = 3, ++ ODM_BT_NONE = 4, ++}ODM_BT_COEXIST_E; ++ ++// ODM_CMNINFO_OP_MODE ++typedef enum tag_Operation_Mode_Definition ++{ ++ ODM_NO_LINK = BIT0, ++ ODM_LINK = BIT1, ++ ODM_SCAN = BIT2, ++ ODM_POWERSAVE = BIT3, ++ ODM_AP_MODE = BIT4, ++ ODM_CLIENT_MODE = BIT5, ++ ODM_AD_HOC = BIT6, ++ ODM_WIFI_DIRECT = BIT7, ++ ODM_WIFI_DISPLAY = BIT8, ++}ODM_OPERATION_MODE_E; ++ ++// ODM_CMNINFO_WM_MODE ++typedef enum tag_Wireless_Mode_Definition ++{ ++ ODM_WM_UNKNOW = 0x0, ++ ODM_WM_B = BIT0, ++ ODM_WM_G = BIT1, ++ ODM_WM_A = BIT2, ++ ODM_WM_N24G = BIT3, ++ ODM_WM_N5G = BIT4, ++ ODM_WM_AUTO = BIT5, ++ ODM_WM_AC = BIT6, ++}ODM_WIRELESS_MODE_E; ++ ++// ODM_CMNINFO_BAND ++typedef enum tag_Band_Type_Definition ++{ ++ ODM_BAND_2_4G = BIT0, ++ ODM_BAND_5G = BIT1, ++ ++}ODM_BAND_TYPE_E; ++ ++// ODM_CMNINFO_SEC_CHNL_OFFSET ++typedef enum tag_Secondary_Channel_Offset_Definition ++{ ++ ODM_DONT_CARE = 0, ++ ODM_BELOW = 1, ++ ODM_ABOVE = 2 ++}ODM_SEC_CHNL_OFFSET_E; ++ ++// ODM_CMNINFO_SEC_MODE ++typedef enum tag_Security_Definition ++{ ++ ODM_SEC_OPEN = 0, ++ ODM_SEC_WEP40 = 1, ++ ODM_SEC_TKIP = 2, ++ ODM_SEC_RESERVE = 3, ++ ODM_SEC_AESCCMP = 4, ++ ODM_SEC_WEP104 = 5, ++ ODM_WEP_WPA_MIXED = 6, // WEP + WPA ++ ODM_SEC_SMS4 = 7, ++}ODM_SECURITY_E; ++ ++// ODM_CMNINFO_BW ++typedef enum tag_Bandwidth_Definition ++{ ++ ODM_BW20M = 0, ++ ODM_BW40M = 1, ++ ODM_BW80M = 2, ++ ODM_BW160M = 3, ++ ODM_BW10M = 4, ++}ODM_BW_E; ++ ++// ODM_CMNINFO_CHNL ++ ++// ODM_CMNINFO_BOARD_TYPE ++#if 1 ++typedef enum tag_Board_Definition ++{ ++ ODM_BOARD_DEFAULT = 0, // The DEFAULT case. ++ ODM_BOARD_MINICARD = BIT(0), // 0 = non-mini card, 1= mini card. ++ ODM_BOARD_SLIM = BIT(1), // 0 = non-slim card, 1 = slim card ++ ODM_BOARD_BT = BIT(2), // 0 = without BT card, 1 = with BT ++ ODM_BOARD_EXT_PA = BIT(3), // 0 = no 2G ext-PA, 1 = existing 2G ext-PA ++ ODM_BOARD_EXT_LNA = BIT(4), // 0 = no 2G ext-LNA, 1 = existing 2G ext-LNA ++ ODM_BOARD_EXT_TRSW = BIT(5), // 0 = no ext-TRSW, 1 = existing ext-TRSW ++ ODM_BOARD_EXT_PA_5G = BIT(6), // 0 = no 5G ext-PA, 1 = existing 5G ext-PA ++ ODM_BOARD_EXT_LNA_5G = BIT(7), // 0 = no 5G ext-LNA, 1 = existing 5G ext-LNA ++}ODM_BOARD_TYPE_E; ++#else ++typedef enum tag_Board_Definition ++{ ++ ODM_BOARD_NORMAL = 0, ++ ODM_BOARD_HIGHPWR = 1, ++ ODM_BOARD_MINICARD = 2, ++ ODM_BOARD_SLIM = 3, ++ ODM_BOARD_COMBO = 4, ++ ++}ODM_BOARD_TYPE_E; ++#endif ++ ++ ++ ++// ODM_CMNINFO_ONE_PATH_CCA ++typedef enum tag_CCA_Path ++{ ++ ODM_CCA_2R = 0, ++ ODM_CCA_1R_A = 1, ++ ODM_CCA_1R_B = 2, ++}ODM_CCA_PATH_E; ++ ++ ++typedef struct _ODM_RA_Info_ ++{ ++ u1Byte RateID; ++ u4Byte RateMask; ++ u4Byte RAUseRate; ++ u1Byte RateSGI; ++ u1Byte RssiStaRA; ++ u1Byte PreRssiStaRA; ++ u1Byte SGIEnable; ++ u1Byte DecisionRate; ++ u1Byte PreRate; ++ u1Byte HighestRate; ++ u1Byte LowestRate; ++ u4Byte NscUp; ++ u4Byte NscDown; ++ u2Byte RTY[5]; ++ u4Byte TOTAL; ++ u2Byte DROP;//Retry over or drop ++ u2Byte DROP1;//LifeTime over ++ u1Byte Active; ++ u2Byte RptTime; ++ u1Byte RAWaitingCounter; ++ u1Byte RAPendingCounter; ++#if 1 //POWER_TRAINING_ACTIVE == 1 // For compile pass only~! ++ u1Byte PTActive; // on or off ++ u1Byte PTTryState; // 0 trying state, 1 for decision state ++ u1Byte PTStage; // 0~6 ++ u1Byte PTStopCount; //Stop PT counter ++ u1Byte PTPreRate; // if rate change do PT ++ u1Byte PTPreRssi; // if RSSI change 5% do PT ++ u1Byte PTModeSS; // decide whitch rate should do PT ++ u1Byte RAstage; // StageRA, decide how many times RA will be done between PT ++ u1Byte PTSmoothFactor; ++#endif ++} ODM_RA_INFO_T,*PODM_RA_INFO_T; ++ ++typedef struct _IQK_MATRIX_REGS_SETTING{ ++ BOOLEAN bIQKDone; ++ s4Byte Value[1][IQK_Matrix_REG_NUM]; ++}IQK_MATRIX_REGS_SETTING,*PIQK_MATRIX_REGS_SETTING; ++ ++#if (DM_ODM_SUPPORT_TYPE & ODM_MP) ++typedef struct _PathDiv_Parameter_define_ ++{ ++ u4Byte org_5g_RegE30; ++ u4Byte org_5g_RegC14; ++ u4Byte org_5g_RegCA0; ++ u4Byte swt_5g_RegE30; ++ u4Byte swt_5g_RegC14; ++ u4Byte swt_5g_RegCA0; ++ //for 2G IQK information ++ u4Byte org_2g_RegC80; ++ u4Byte org_2g_RegC4C; ++ u4Byte org_2g_RegC94; ++ u4Byte org_2g_RegC14; ++ u4Byte org_2g_RegCA0; ++ ++ u4Byte swt_2g_RegC80; ++ u4Byte swt_2g_RegC4C; ++ u4Byte swt_2g_RegC94; ++ u4Byte swt_2g_RegC14; ++ u4Byte swt_2g_RegCA0; ++}PATHDIV_PARA,*pPATHDIV_PARA; ++#endif ++ ++ ++typedef struct ODM_RF_Calibration_Structure ++{ ++ //for tx power tracking ++ ++ u4Byte RegA24; // for TempCCK ++ s4Byte RegE94; ++ s4Byte RegE9C; ++ s4Byte RegEB4; ++ s4Byte RegEBC; ++ ++ //u1Byte bTXPowerTracking; ++ u1Byte TXPowercount; ++ BOOLEAN bTXPowerTrackingInit; ++ BOOLEAN bTXPowerTracking; ++ u1Byte TxPowerTrackControl; //for mp mode, turn off txpwrtracking as default ++ u1Byte TM_Trigger; ++ u1Byte InternalPA5G[2]; //pathA / pathB ++ ++ u1Byte ThermalMeter[2]; // ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 ++ u1Byte ThermalValue; ++ u1Byte ThermalValue_LCK; ++ u1Byte ThermalValue_IQK; ++ u1Byte ThermalValue_DPK; ++ u1Byte ThermalValue_AVG[AVG_THERMAL_NUM]; ++ u1Byte ThermalValue_AVG_index; ++ u1Byte ThermalValue_RxGain; ++ u1Byte ThermalValue_Crystal; ++ u1Byte ThermalValue_DPKstore; ++ u1Byte ThermalValue_DPKtrack; ++ BOOLEAN TxPowerTrackingInProgress; ++ BOOLEAN bDPKenable; ++ ++ BOOLEAN bReloadtxpowerindex; ++ u1Byte bRfPiEnable; ++ u4Byte TXPowerTrackingCallbackCnt; //cosa add for debug ++ ++ u1Byte bCCKinCH14; ++ u1Byte CCK_index; ++ u1Byte OFDM_index[2]; ++ BOOLEAN bDoneTxpower; ++ s1Byte PowerIndexOffset; ++ s1Byte DeltaPowerIndex; ++ s1Byte DeltaPowerIndexLast; ++ BOOLEAN bTxPowerChanged; ++ ++ u1Byte ThermalValue_HP[HP_THERMAL_NUM]; ++ u1Byte ThermalValue_HP_index; ++ IQK_MATRIX_REGS_SETTING IQKMatrixRegSetting[IQK_Matrix_Settings_NUM]; ++ ++ u1Byte Delta_IQK; ++ u1Byte Delta_LCK; ++ ++ //for IQK ++ u4Byte RegC04; ++ u4Byte Reg874; ++ u4Byte RegC08; ++ u4Byte RegB68; ++ u4Byte RegB6C; ++ u4Byte Reg870; ++ u4Byte Reg860; ++ u4Byte Reg864; ++ ++ BOOLEAN bIQKInitialized; ++ BOOLEAN bLCKInProgress; ++ BOOLEAN bAntennaDetected; ++ u4Byte ADDA_backup[IQK_ADDA_REG_NUM]; ++ u4Byte IQK_MAC_backup[IQK_MAC_REG_NUM]; ++ u4Byte IQK_BB_backup_recover[9]; ++ u4Byte IQK_BB_backup[IQK_BB_REG_NUM]; ++ ++ //for APK ++ u4Byte APKoutput[2][2]; //path A/B; output1_1a/output1_2a ++ u1Byte bAPKdone; ++ u1Byte bAPKThermalMeterIgnore; ++ u1Byte bDPdone; ++ u1Byte bDPPathAOK; ++ u1Byte bDPPathBOK; ++}ODM_RF_CAL_T,*PODM_RF_CAL_T; ++// ++// ODM Dynamic common info value definition ++// ++ ++typedef struct _FAST_ANTENNA_TRAINNING_ ++{ ++ u1Byte Bssid[6]; ++ u1Byte antsel_rx_keep_0; ++ u1Byte antsel_rx_keep_1; ++ u1Byte antsel_rx_keep_2; ++ u4Byte antSumRSSI[7]; ++ u4Byte antRSSIcnt[7]; ++ u4Byte antAveRSSI[7]; ++ u1Byte FAT_State; ++ u4Byte TrainIdx; ++ u1Byte antsel_a[ODM_ASSOCIATE_ENTRY_NUM]; ++ u1Byte antsel_b[ODM_ASSOCIATE_ENTRY_NUM]; ++ u1Byte antsel_c[ODM_ASSOCIATE_ENTRY_NUM]; ++ u4Byte MainAnt_Sum[ODM_ASSOCIATE_ENTRY_NUM]; ++ u4Byte AuxAnt_Sum[ODM_ASSOCIATE_ENTRY_NUM]; ++ u4Byte MainAnt_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; ++ u4Byte AuxAnt_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; ++ u1Byte RxIdleAnt; ++ BOOLEAN bBecomeLinked; ++ ++}FAT_T,*pFAT_T; ++ ++typedef enum _FAT_STATE ++{ ++ FAT_NORMAL_STATE = 0, ++ FAT_TRAINING_STATE = 1, ++}FAT_STATE_E, *PFAT_STATE_E; ++ ++typedef enum _ANT_DIV_TYPE ++{ ++ NO_ANTDIV = 0xFF, ++ CG_TRX_HW_ANTDIV = 0x01, ++ CGCS_RX_HW_ANTDIV = 0x02, ++ FIXED_HW_ANTDIV = 0x03, ++ CG_TRX_SMART_ANTDIV = 0x04, ++ CGCS_RX_SW_ANTDIV = 0x05, ++ ++}ANT_DIV_TYPE_E, *PANT_DIV_TYPE_E; ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++// ++// 2011/09/22 MH Copy from SD4 defined structure. We use to support PHY DM integration. ++// ++#if(DM_ODM_SUPPORT_TYPE & ODM_MP) ++#if (RT_PLATFORM != PLATFORM_LINUX) ++typedef ++#endif ++struct DM_Out_Source_Dynamic_Mechanism_Structure ++#else// for AP,ADSL,CE Team ++typedef struct DM_Out_Source_Dynamic_Mechanism_Structure ++#endif ++{ ++ //RT_TIMER FastAntTrainingTimer; ++ // ++ // Add for different team use temporarily ++ // ++ PADAPTER Adapter; // For CE/NIC team ++ prtl8192cd_priv priv; // For AP/ADSL team ++ // WHen you use Adapter or priv pointer, you must make sure the pointer is ready. ++ BOOLEAN odm_ready; ++ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_MP)) ++ rtl8192cd_priv fake_priv; ++#endif ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ // ADSL_AP_BUILD_WORKAROUND ++ ADAPTER fake_adapter; ++#endif ++ ++ u8Byte DebugComponents; ++ u4Byte DebugLevel; ++ ++//------ ODM HANDLE, DRIVER NEEDS NOT TO HOOK------// ++ BOOLEAN bCckHighPower; ++ u1Byte RFPathRxEnable; // ODM_CMNINFO_RFPATH_ENABLE ++ u1Byte ControlChannel; ++//------ ODM HANDLE, DRIVER NEEDS NOT TO HOOK------// ++ ++//--------REMOVED COMMON INFO----------// ++ //u1Byte PseudoMacPhyMode; ++ //BOOLEAN *BTCoexist; ++ //BOOLEAN PseudoBtCoexist; ++ //u1Byte OPMode; ++ //BOOLEAN bAPMode; ++ //BOOLEAN bClientMode; ++ //BOOLEAN bAdHocMode; ++ //BOOLEAN bSlaveOfDMSP; ++//--------REMOVED COMMON INFO----------// ++ ++ ++//1 COMMON INFORMATION ++ ++ // ++ // Init Value ++ // ++//-----------HOOK BEFORE REG INIT-----------// ++ // ODM Platform info AP/ADSL/CE/MP = 1/2/3/4 ++ u1Byte SupportPlatform; ++ // ODM Support Ability DIG/RATR/TX_PWR_TRACK/ ¡K¡K = 1/2/3/¡K ++ u4Byte SupportAbility; ++ // ODM PCIE/USB/SDIO/GSPI = 0/1/2/3 ++ u1Byte SupportInterface; ++ // ODM composite or independent. Bit oriented/ 92C+92D+ .... or any other type = 1/2/3/... ++ u4Byte SupportICType; ++ // Cut Version TestChip/A-cut/B-cut... = 0/1/2/3/... ++ u1Byte CutVersion; ++ // Fab Version TSMC/UMC = 0/1 ++ u1Byte FabVersion; ++ // RF Type 4T4R/3T3R/2T2R/1T2R/1T1R/... ++ u1Byte RFType; ++ // Board Type Normal/HighPower/MiniCard/SLIM/Combo/... = 0/1/2/3/4/... ++ u1Byte BoardType; ++ // with external LNA NO/Yes = 0/1 ++ u1Byte ExtLNA; ++ // with external PA NO/Yes = 0/1 ++ u1Byte ExtPA; ++ // with external TRSW NO/Yes = 0/1 ++ u1Byte ExtTRSW; ++ u1Byte PatchID; //Customer ID ++ BOOLEAN bInHctTest; ++ BOOLEAN bWIFITest; ++ ++ BOOLEAN bDualMacSmartConcurrent; ++ u4Byte BK_SupportAbility; ++ u1Byte AntDivType; ++//-----------HOOK BEFORE REG INIT-----------// ++ ++ // ++ // Dynamic Value ++ // ++//--------- POINTER REFERENCE-----------// ++ ++ u1Byte u1Byte_temp; ++ BOOLEAN BOOLEAN_temp; ++ PADAPTER PADAPTER_temp; ++ ++ // MAC PHY Mode SMSP/DMSP/DMDP = 0/1/2 ++ u1Byte *pMacPhyMode; ++ //TX Unicast byte count ++ u8Byte *pNumTxBytesUnicast; ++ //RX Unicast byte count ++ u8Byte *pNumRxBytesUnicast; ++ // Wireless mode B/G/A/N = BIT0/BIT1/BIT2/BIT3 ++ u1Byte *pWirelessMode; //ODM_WIRELESS_MODE_E ++ // Frequence band 2.4G/5G = 0/1 ++ u1Byte *pBandType; ++ // Secondary channel offset don't_care/below/above = 0/1/2 ++ u1Byte *pSecChOffset; ++ // Security mode Open/WEP/AES/TKIP = 0/1/2/3 ++ u1Byte *pSecurity; ++ // BW info 20M/40M/80M = 0/1/2 ++ u1Byte *pBandWidth; ++ // Central channel location Ch1/Ch2/.... ++ u1Byte *pChannel; //central channel number ++ // Common info for 92D DMSP ++ ++ BOOLEAN *pbGetValueFromOtherMac; ++ PADAPTER *pBuddyAdapter; ++ BOOLEAN *pbMasterOfDMSP; //MAC0: master, MAC1: slave ++ // Common info for Status ++ BOOLEAN *pbScanInProcess; ++ BOOLEAN *pbPowerSaving; ++ // CCA Path 2-path/path-A/path-B = 0/1/2; using ODM_CCA_PATH_E. ++ u1Byte *pOnePathCCA; ++ //pMgntInfo->AntennaTest ++ u1Byte *pAntennaTest; ++ BOOLEAN *pbNet_closed; ++//--------- POINTER REFERENCE-----------// ++ // ++//------------CALL BY VALUE-------------// ++ BOOLEAN bLinkInProcess; ++ BOOLEAN bWIFI_Direct; ++ BOOLEAN bWIFI_Display; ++ BOOLEAN bLinked; ++ BOOLEAN bsta_state; ++ u1Byte RSSI_Min; ++ u1Byte InterfaceIndex; // Add for 92D dual MAC: 0--Mac0 1--Mac1 ++ BOOLEAN bIsMPChip; ++ BOOLEAN bOneEntryOnly; ++ // Common info for BTDM ++ BOOLEAN bBtDisabled; // BT is disabled ++ BOOLEAN bBtConnectProcess; // BT HS is under connection progress. ++ u1Byte btHsRssi; // BT HS mode wifi rssi value. ++ BOOLEAN bBtHsOperation; // BT HS mode is under progress ++ u1Byte btHsDigVal; // use BT rssi to decide the DIG value ++ BOOLEAN bBtDisableEdcaTurbo; // Under some condition, don't enable the EDCA Turbo ++ BOOLEAN bBtLimitedDig; // BT is busy. ++//------------CALL BY VALUE-------------// ++ u1Byte RSSI_A; ++ u1Byte RSSI_B; ++ u8Byte RSSI_TRSW; ++ u8Byte RSSI_TRSW_H; ++ u8Byte RSSI_TRSW_L; ++ u8Byte RSSI_TRSW_iso; ++ ++ u1Byte RxRate; ++ BOOLEAN StopDIG; ++ u1Byte TxRate; ++ u1Byte LinkedInterval; ++ u1Byte preChannel; ++ u4Byte TxagcOffsetValueA; ++ BOOLEAN IsTxagcOffsetPositiveA; ++ u4Byte TxagcOffsetValueB; ++ BOOLEAN IsTxagcOffsetPositiveB; ++ u8Byte lastTxOkCnt; ++ u8Byte lastRxOkCnt; ++ u4Byte BbSwingOffsetA; ++ BOOLEAN IsBbSwingOffsetPositiveA; ++ u4Byte BbSwingOffsetB; ++ BOOLEAN IsBbSwingOffsetPositiveB; ++ s1Byte TH_L2H_ini; ++ s1Byte TH_EDCCA_HL_diff; ++ u4Byte IGI_Base; ++ u4Byte IGI_target; ++ BOOLEAN ForceEDCCA; ++ u1Byte AdapEn_RSSI; ++ u1Byte AntType; ++ u1Byte antdiv_rssi; ++ u1Byte antdiv_period; ++ u4Byte Force_TH_H; ++ u4Byte Force_TH_L; ++ u1Byte IGI_LowerBound; ++ ++ //2 Define STA info. ++ // _ODM_STA_INFO ++ // 2012/01/12 MH For MP, we need to reduce one array pointer for default port.?? ++ PSTA_INFO_T pODM_StaInfo[ODM_ASSOCIATE_ENTRY_NUM]; ++ ++#if (RATE_ADAPTIVE_SUPPORT == 1) ++ u2Byte CurrminRptTime; ++ ODM_RA_INFO_T RAInfo[ODM_ASSOCIATE_ENTRY_NUM]; //Use MacID as array index. STA MacID=0, VWiFi Client MacID={1, ODM_ASSOCIATE_ENTRY_NUM-1} //YJ,add,120119 ++#endif ++ // ++ // 2012/02/14 MH Add to share 88E ra with other SW team. ++ // We need to colelct all support abilit to a proper area. ++ // ++ BOOLEAN RaSupport88E; ++ ++ // Define ........... ++ ++ // Latest packet phy info (ODM write) ++ ODM_PHY_DBG_INFO_T PhyDbgInfo; ++ //PHY_INFO_88E PhyInfo; ++ ++ // Latest packet phy info (ODM write) ++ ODM_MAC_INFO *pMacInfo; ++ //MAC_INFO_88E MacInfo; ++ ++ // Different Team independt structure?? ++ ++ // ++ //TX_RTP_CMN TX_retrpo; ++ //TX_RTP_88E TX_retrpo; ++ //TX_RTP_8195 TX_retrpo; ++ ++ // ++ //ODM Structure ++ // ++ FAT_T DM_FatTable; ++ DIG_T DM_DigTable; ++ PS_T DM_PSTable; ++ Pri_CCA_T DM_PriCCA; ++ RXHP_T DM_RXHP_Table; ++ FALSE_ALARM_STATISTICS FalseAlmCnt; ++ FALSE_ALARM_STATISTICS FlaseAlmCntBuddyAdapter; ++ //#ifdef CONFIG_ANTENNA_DIVERSITY ++ SWAT_T DM_SWAT_Table; ++ BOOLEAN RSSI_test; ++ //#endif ++ ++#if (DM_ODM_SUPPORT_TYPE & ODM_MP) ++ //Path Div Struct ++ PATHDIV_PARA pathIQK; ++#endif ++ ++ EDCA_T DM_EDCA_Table; ++ u4Byte WMMEDCA_BE; ++ // Copy from SD4 structure ++ // ++ // ================================================== ++ // ++ ++ //common ++ //u1Byte DM_Type; ++ //u1Byte PSD_Report_RXHP[80]; // Add By Gary ++ //u1Byte PSD_func_flag; // Add By Gary ++ //for DIG ++ //u1Byte bDMInitialGainEnable; ++ //u1Byte binitialized; // for dm_initial_gain_Multi_STA use. ++ //for Antenna diversity ++ //u8 AntDivCfg;// 0:OFF , 1:ON, 2:by efuse ++ //PSTA_INFO_T RSSI_target; ++ ++ BOOLEAN *pbDriverStopped; ++ BOOLEAN *pbDriverIsGoingToPnpSetPowerSleep; ++ BOOLEAN *pinit_adpt_in_progress; ++ ++ //PSD ++ BOOLEAN bUserAssignLevel; ++ RT_TIMER PSDTimer; ++ u1Byte RSSI_BT; //come from BT ++ BOOLEAN bPSDinProcess; ++ BOOLEAN bDMInitialGainEnable; ++ ++ //for rate adaptive, in fact, 88c/92c fw will handle this ++ u1Byte bUseRAMask; ++ ++ ODM_RATE_ADAPTIVE RateAdaptive; ++ ++ ++ ODM_RF_CAL_T RFCalibrateInfo; ++ ++ // ++ // TX power tracking ++ // ++ u1Byte BbSwingIdxOfdm; ++ u1Byte BbSwingIdxOfdmCurrent; ++ u1Byte BbSwingIdxOfdmBase; ++ BOOLEAN BbSwingFlagOfdm; ++ u1Byte BbSwingIdxCck; ++ u1Byte BbSwingIdxCckCurrent; ++ u1Byte BbSwingIdxCckBase; ++ u1Byte DefaultOfdmIndex; ++ u1Byte DefaultCckIndex; ++ BOOLEAN BbSwingFlagCck; ++ ++ ++ u1Byte *mp_mode; ++ // ++ // ODM system resource. ++ // ++ ++ // ODM relative time. ++ RT_TIMER PathDivSwitchTimer; ++ //2011.09.27 add for Path Diversity ++ RT_TIMER CCKPathDiversityTimer; ++ RT_TIMER FastAntTrainingTimer; ++ ++ // ODM relative workitem. ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ #if USE_WORKITEM ++ RT_WORK_ITEM PathDivSwitchWorkitem; ++ RT_WORK_ITEM CCKPathDiversityWorkitem; ++ RT_WORK_ITEM FastAntTrainingWorkitem; ++ #endif ++#endif ++ ++#if(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ ++#if (RT_PLATFORM != PLATFORM_LINUX) ++} DM_ODM_T, *PDM_ODM_T; // DM_Dynamic_Mechanism_Structure ++#else ++}; ++#endif ++ ++#else// for AP,ADSL,CE Team ++} DM_ODM_T, *PDM_ODM_T; // DM_Dynamic_Mechanism_Structure ++#endif ++ ++ ++ ++#if 1 //92c-series ++#define ODM_RF_PATH_MAX 2 ++#else //jaguar - series ++#define ODM_RF_PATH_MAX 4 ++#endif ++ ++typedef enum _ODM_RF_RADIO_PATH { ++ ODM_RF_PATH_A = 0, //Radio Path A ++ ODM_RF_PATH_B = 1, //Radio Path B ++ ODM_RF_PATH_C = 2, //Radio Path C ++ ODM_RF_PATH_D = 3, //Radio Path D ++ // ODM_RF_PATH_MAX, //Max RF number 90 support ++} ODM_RF_RADIO_PATH_E, *PODM_RF_RADIO_PATH_E; ++ ++ typedef enum _ODM_RF_CONTENT{ ++ odm_radioa_txt = 0x1000, ++ odm_radiob_txt = 0x1001, ++ odm_radioc_txt = 0x1002, ++ odm_radiod_txt = 0x1003 ++} ODM_RF_CONTENT; ++ ++typedef enum _ODM_BB_Config_Type{ ++ CONFIG_BB_PHY_REG, ++ CONFIG_BB_AGC_TAB, ++ CONFIG_BB_AGC_TAB_2G, ++ CONFIG_BB_AGC_TAB_5G, ++ CONFIG_BB_PHY_REG_PG, ++} ODM_BB_Config_Type, *PODM_BB_Config_Type; ++ ++// Status code ++#if (DM_ODM_SUPPORT_TYPE != ODM_MP) ++typedef enum _RT_STATUS{ ++ RT_STATUS_SUCCESS, ++ RT_STATUS_FAILURE, ++ RT_STATUS_PENDING, ++ RT_STATUS_RESOURCE, ++ RT_STATUS_INVALID_CONTEXT, ++ RT_STATUS_INVALID_PARAMETER, ++ RT_STATUS_NOT_SUPPORT, ++ RT_STATUS_OS_API_FAILED, ++}RT_STATUS,*PRT_STATUS; ++#endif // end of RT_STATUS definition ++ ++#ifdef REMOVE_PACK ++#pragma pack() ++#endif ++ ++//#include "odm_function.h" ++ ++//3=========================================================== ++//3 DIG ++//3=========================================================== ++ ++typedef enum tag_Dynamic_Init_Gain_Operation_Type_Definition ++{ ++ DIG_TYPE_THRESH_HIGH = 0, ++ DIG_TYPE_THRESH_LOW = 1, ++ DIG_TYPE_BACKOFF = 2, ++ DIG_TYPE_RX_GAIN_MIN = 3, ++ DIG_TYPE_RX_GAIN_MAX = 4, ++ DIG_TYPE_ENABLE = 5, ++ DIG_TYPE_DISABLE = 6, ++ DIG_OP_TYPE_MAX ++}DM_DIG_OP_E; ++/* ++typedef enum tag_CCK_Packet_Detection_Threshold_Type_Definition ++{ ++ CCK_PD_STAGE_LowRssi = 0, ++ CCK_PD_STAGE_HighRssi = 1, ++ CCK_PD_STAGE_MAX = 3, ++}DM_CCK_PDTH_E; ++ ++typedef enum tag_DIG_EXT_PORT_ALGO_Definition ++{ ++ DIG_EXT_PORT_STAGE_0 = 0, ++ DIG_EXT_PORT_STAGE_1 = 1, ++ DIG_EXT_PORT_STAGE_2 = 2, ++ DIG_EXT_PORT_STAGE_3 = 3, ++ DIG_EXT_PORT_STAGE_MAX = 4, ++}DM_DIG_EXT_PORT_ALG_E; ++ ++typedef enum tag_DIG_Connect_Definition ++{ ++ DIG_STA_DISCONNECT = 0, ++ DIG_STA_CONNECT = 1, ++ DIG_STA_BEFORE_CONNECT = 2, ++ DIG_MultiSTA_DISCONNECT = 3, ++ DIG_MultiSTA_CONNECT = 4, ++ DIG_CONNECT_MAX ++}DM_DIG_CONNECT_E; ++ ++ ++#define DM_MultiSTA_InitGainChangeNotify(Event) {DM_DigTable.CurMultiSTAConnectState = Event;} ++ ++#define DM_MultiSTA_InitGainChangeNotify_CONNECT(_ADAPTER) \ ++ DM_MultiSTA_InitGainChangeNotify(DIG_MultiSTA_CONNECT) ++ ++#define DM_MultiSTA_InitGainChangeNotify_DISCONNECT(_ADAPTER) \ ++ DM_MultiSTA_InitGainChangeNotify(DIG_MultiSTA_DISCONNECT) ++*/ ++ ++#define DM_DIG_THRESH_HIGH 40 ++#define DM_DIG_THRESH_LOW 35 ++ ++#define DM_FALSEALARM_THRESH_LOW 400 ++#define DM_FALSEALARM_THRESH_HIGH 1000 ++ ++#define DM_DIG_MAX_NIC 0x4A ++#define DM_DIG_MIN_NIC 0x1e //0x22//0x1c ++ ++#define DM_DIG_MAX_AP 0x32 ++#define DM_DIG_MIN_AP 0x20 ++ ++#define DM_DIG_MAX_NIC_HP 0x46 ++#define DM_DIG_MIN_NIC_HP 0x2e ++ ++#define DM_DIG_MAX_AP_HP 0x42 ++#define DM_DIG_MIN_AP_HP 0x30 ++ ++//vivi 92c&92d has different definition, 20110504 ++//this is for 92c ++#ifdef CONFIG_SPECIAL_SETTING_FOR_FUNAI_TV ++#define DM_DIG_FA_TH0 0x80//0x20 ++#else ++#define DM_DIG_FA_TH0 0x200//0x20 ++#endif ++#define DM_DIG_FA_TH1 0x300//0x100 ++#define DM_DIG_FA_TH2 0x400//0x200 ++//this is for 92d ++#define DM_DIG_FA_TH0_92D 0x100 ++#define DM_DIG_FA_TH1_92D 0x400 ++#define DM_DIG_FA_TH2_92D 0x600 ++ ++#define DM_DIG_BACKOFF_MAX 12 ++#define DM_DIG_BACKOFF_MIN -4 ++#define DM_DIG_BACKOFF_DEFAULT 10 ++ ++//3=========================================================== ++//3 AGC RX High Power Mode ++//3=========================================================== ++#define LNA_Low_Gain_1 0x64 ++#define LNA_Low_Gain_2 0x5A ++#define LNA_Low_Gain_3 0x58 ++ ++#define FA_RXHP_TH1 5000 ++#define FA_RXHP_TH2 1500 ++#define FA_RXHP_TH3 800 ++#define FA_RXHP_TH4 600 ++#define FA_RXHP_TH5 500 ++ ++//3=========================================================== ++//3 EDCA ++//3=========================================================== ++ ++//3=========================================================== ++//3 Dynamic Tx Power ++//3=========================================================== ++//Dynamic Tx Power Control Threshold ++#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 ++#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 ++#define TX_POWER_NEAR_FIELD_THRESH_AP 0x3F ++ ++#define TxHighPwrLevel_Normal 0 ++#define TxHighPwrLevel_Level1 1 ++#define TxHighPwrLevel_Level2 2 ++#define TxHighPwrLevel_BT1 3 ++#define TxHighPwrLevel_BT2 4 ++#define TxHighPwrLevel_15 5 ++#define TxHighPwrLevel_35 6 ++#define TxHighPwrLevel_50 7 ++#define TxHighPwrLevel_70 8 ++#define TxHighPwrLevel_100 9 ++ ++//3=========================================================== ++//3 Tx Power Tracking ++//3=========================================================== ++#if 0 //mask this, since these have been defined in typdef.h, vivi ++#define OFDM_TABLE_SIZE 37 ++#define OFDM_TABLE_SIZE_92D 43 ++#define CCK_TABLE_SIZE 33 ++#endif ++ ++ ++//3=========================================================== ++//3 Rate Adaptive ++//3=========================================================== ++#define DM_RATR_STA_INIT 0 ++#define DM_RATR_STA_HIGH 1 ++#define DM_RATR_STA_MIDDLE 2 ++#define DM_RATR_STA_LOW 3 ++ ++//3=========================================================== ++//3 BB Power Save ++//3=========================================================== ++ ++ ++typedef enum tag_1R_CCA_Type_Definition ++{ ++ CCA_1R =0, ++ CCA_2R = 1, ++ CCA_MAX = 2, ++}DM_1R_CCA_E; ++ ++typedef enum tag_RF_Type_Definition ++{ ++ RF_Save =0, ++ RF_Normal = 1, ++ RF_MAX = 2, ++}DM_RF_E; ++ ++//3=========================================================== ++//3 Antenna Diversity ++//3=========================================================== ++typedef enum tag_SW_Antenna_Switch_Definition ++{ ++ Antenna_A = 1, ++ Antenna_B = 2, ++ Antenna_MAX = 3, ++}DM_SWAS_E; ++ ++ ++// Maximal number of antenna detection mechanism needs to perform, added by Roger, 2011.12.28. ++#define MAX_ANTENNA_DETECTION_CNT 10 ++ ++// ++// Extern Global Variables. ++// ++#define OFDM_TABLE_SIZE_92C 37 ++#define OFDM_TABLE_SIZE_92D 43 ++#define CCK_TABLE_SIZE 33 ++ ++extern u4Byte OFDMSwingTable[OFDM_TABLE_SIZE_92D]; ++extern u1Byte CCKSwingTable_Ch1_Ch13[CCK_TABLE_SIZE][8]; ++extern u1Byte CCKSwingTable_Ch14 [CCK_TABLE_SIZE][8]; ++ ++ ++ ++// ++// check Sta pointer valid or not ++// ++#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++#define IS_STA_VALID(pSta) (pSta && pSta->expire_to) ++#elif (DM_ODM_SUPPORT_TYPE & ODM_MP) ++#define IS_STA_VALID(pSta) (pSta && pSta->bUsed) ++#else ++#define IS_STA_VALID(pSta) (pSta) ++#endif ++// 20100514 Joseph: Add definition for antenna switching test after link. ++// This indicates two different the steps. ++// In SWAW_STEP_PEAK, driver needs to switch antenna and listen to the signal on the air. ++// In SWAW_STEP_DETERMINE, driver just compares the signal captured in SWAW_STEP_PEAK ++// with original RSSI to determine if it is necessary to switch antenna. ++#define SWAW_STEP_PEAK 0 ++#define SWAW_STEP_DETERMINE 1 ++ ++VOID ODM_Write_DIG(IN PDM_ODM_T pDM_Odm, IN u1Byte CurrentIGI); ++VOID ODM_Write_CCK_CCA_Thres(IN PDM_ODM_T pDM_Odm, IN u1Byte CurCCK_CCAThres); ++ ++VOID ++ODM_SetAntenna( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte Antenna); ++ ++ ++#define dm_RF_Saving ODM_RF_Saving ++void ODM_RF_Saving( IN PDM_ODM_T pDM_Odm, ++ IN u1Byte bForceInNormal ); ++ ++#define SwAntDivRestAfterLink ODM_SwAntDivRestAfterLink ++VOID ODM_SwAntDivRestAfterLink( IN PDM_ODM_T pDM_Odm); ++ ++#define dm_CheckTXPowerTracking ODM_TXPowerTrackingCheck ++VOID ++ODM_TXPowerTrackingCheck( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++BOOLEAN ++ODM_RAStateCheck( ++ IN PDM_ODM_T pDM_Odm, ++ IN s4Byte RSSI, ++ IN BOOLEAN bForceUpdate, ++ OUT pu1Byte pRATRState ++ ); ++ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_AP|ODM_ADSL)) ++//============================================================ ++// function prototype ++//============================================================ ++//#define DM_ChangeDynamicInitGainThresh ODM_ChangeDynamicInitGainThresh ++//void ODM_ChangeDynamicInitGainThresh(IN PADAPTER pAdapter, ++// IN INT32 DM_Type, ++// IN INT32 DM_Value); ++VOID ++ODM_ChangeDynamicInitGainThresh( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte DM_Type, ++ IN u4Byte DM_Value ++ ); ++ ++BOOLEAN ++ODM_CheckPowerStatus( ++ IN PADAPTER Adapter ++ ); ++ ++ ++#if (DM_ODM_SUPPORT_TYPE != ODM_ADSL) ++VOID ++ODM_RateAdaptiveStateApInit( ++ IN PADAPTER Adapter , ++ IN PRT_WLAN_STA pEntry ++ ); ++#endif ++#define AP_InitRateAdaptiveState ODM_RateAdaptiveStateApInit ++ ++ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++#ifdef WIFI_WMM ++VOID ++ODM_IotEdcaSwitch( ++ IN PDM_ODM_T pDM_Odm, ++ IN unsigned char enable ++ ); ++#endif ++ ++BOOLEAN ++ODM_ChooseIotMainSTA( ++ IN PDM_ODM_T pDM_Odm, ++ IN PSTA_INFO_T pstat ++ ); ++#endif ++ ++#if(DM_ODM_SUPPORT_TYPE==ODM_AP) ++#ifdef HW_ANT_SWITCH ++u1Byte ++ODM_Diversity_AntennaSelect( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte *data ++); ++#endif ++#endif ++ ++#define SwAntDivResetBeforeLink ODM_SwAntDivResetBeforeLink ++VOID ODM_SwAntDivResetBeforeLink(IN PDM_ODM_T pDM_Odm); ++ ++//#define SwAntDivCheckBeforeLink8192C ODM_SwAntDivCheckBeforeLink8192C ++#define SwAntDivCheckBeforeLink ODM_SwAntDivCheckBeforeLink8192C ++BOOLEAN ++ODM_SwAntDivCheckBeforeLink8192C( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++ ++#endif ++ ++#define dm_SWAW_RSSI_Check ODM_SwAntDivChkPerPktRssi ++VOID ODM_SwAntDivChkPerPktRssi( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte StationID, ++ IN PODM_PHY_INFO_T pPhyInfo ++ ); ++ ++#if((DM_ODM_SUPPORT_TYPE==ODM_MP)||(DM_ODM_SUPPORT_TYPE==ODM_CE)) ++ ++u4Byte ConvertTo_dB(u4Byte Value); ++ ++u4Byte ++GetPSDData( ++ PDM_ODM_T pDM_Odm, ++ unsigned int point, ++ u1Byte initial_gain_psd); ++ ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ ++VOID ++odm_DIGbyRSSI_LPS( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++u4Byte ODM_Get_Rate_Bitmap( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte macid, ++ IN u4Byte ra_mask, ++ IN u1Byte rssi_level); ++#endif ++ ++ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_MP)) ++#define dm_PSDMonitorCallback odm_PSDMonitorCallback ++VOID odm_PSDMonitorCallback(PRT_TIMER pTimer); ++ ++VOID ++odm_PSDMonitorWorkItemCallback( ++ IN PVOID pContext ++ ); ++ ++ ++VOID ++PatchDCTone( ++ IN PDM_ODM_T pDM_Odm, ++ pu4Byte PSD_report, ++ u1Byte initial_gain_psd ++); ++VOID ++ODM_PSDMonitor( ++ IN PDM_ODM_T pDM_Odm ++ ); ++VOID odm_PSD_Monitor(PDM_ODM_T pDM_Odm); ++VOID odm_PSDMonitorInit(PDM_ODM_T pDM_Odm); ++ ++VOID ++ODM_PSDDbgControl( ++ IN PADAPTER Adapter, ++ IN u4Byte mode, ++ IN u4Byte btRssi ++ ); ++ ++#endif // DM_ODM_SUPPORT_TYPE ++ ++ ++ ++VOID ODM_DMInit( IN PDM_ODM_T pDM_Odm); ++ ++VOID ++ODM_DMWatchdog( ++ IN PDM_ODM_T pDM_Odm // For common use in the future ++ ); ++ ++VOID ++ODM_CmnInfoInit( ++ IN PDM_ODM_T pDM_Odm, ++ IN ODM_CMNINFO_E CmnInfo, ++ IN u4Byte Value ++ ); ++ ++VOID ++ODM_CmnInfoHook( ++ IN PDM_ODM_T pDM_Odm, ++ IN ODM_CMNINFO_E CmnInfo, ++ IN PVOID pValue ++ ); ++ ++VOID ++ODM_CmnInfoPtrArrayHook( ++ IN PDM_ODM_T pDM_Odm, ++ IN ODM_CMNINFO_E CmnInfo, ++ IN u2Byte Index, ++ IN PVOID pValue ++ ); ++ ++VOID ++ODM_CmnInfoUpdate( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte CmnInfo, ++ IN u8Byte Value ++ ); ++ ++VOID ++ODM_InitAllTimers( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++ODM_CancelAllTimers( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++ODM_ReleaseAllTimers( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++ODM_ResetIQKResult( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++VOID ODM_InitAllWorkItems(IN PDM_ODM_T pDM_Odm ); ++VOID ODM_FreeAllWorkItems(IN PDM_ODM_T pDM_Odm ); ++ ++VOID odm_PathDivChkAntSwitch(PDM_ODM_T pDM_Odm); ++VOID ODM_PathDivRestAfterLink( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++ ++//===========================================// ++// Neil Chen----2011--06--15-- ++ ++//3 Path Diversity ++//=========================================================== ++ ++#define TP_MODE 0 ++#define RSSI_MODE 1 ++#define TRAFFIC_LOW 0 ++#define TRAFFIC_HIGH 1 ++ ++//#define PATHDIV_ENABLE 1 ++ ++//VOID odm_PathDivChkAntSwitch(PADAPTER Adapter,u1Byte Step); ++VOID ODM_PathDivRestAfterLink( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++#define dm_PathDiv_RSSI_Check ODM_PathDivChkPerPktRssi ++VOID ODM_PathDivChkPerPktRssi(PADAPTER Adapter, ++ BOOLEAN bIsDefPort, ++ BOOLEAN bMatchBSSID, ++ PRT_WLAN_STA pEntry, ++ PRT_RFD pRfd ); ++ ++u8Byte ++PlatformDivision64( ++ IN u8Byte x, ++ IN u8Byte y ++); ++ ++ ++// 20100514 Joseph: Add definition for antenna switching test after link. ++// This indicates two different the steps. ++// In SWAW_STEP_PEAK, driver needs to switch antenna and listen to the signal on the air. ++// In SWAW_STEP_DETERMINE, driver just compares the signal captured in SWAW_STEP_PEAK ++// with original RSSI to determine if it is necessary to switch antenna. ++#define SWAW_STEP_PEAK 0 ++#define SWAW_STEP_DETERMINE 1 ++ ++//==================================================== ++//3 PathDiV End ++//==================================================== ++ ++#define PathDivCheckBeforeLink8192C ODM_PathDiversityBeforeLink92C ++BOOLEAN ++ODM_PathDiversityBeforeLink92C( ++ //IN PADAPTER Adapter ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++#define DM_ChangeDynamicInitGainThresh ODM_ChangeDynamicInitGainThresh ++//void ODM_ChangeDynamicInitGainThresh(IN PADAPTER pAdapter, ++// IN INT32 DM_Type, ++// IN INT32 DM_Value); ++// ++ ++ ++VOID ++ODM_CCKPathDiversityChkPerPktRssi( ++ PADAPTER Adapter, ++ BOOLEAN bIsDefPort, ++ BOOLEAN bMatchBSSID, ++ PRT_WLAN_STA pEntry, ++ PRT_RFD pRfd, ++ pu1Byte pDesc ++ ); ++ ++ ++typedef enum tag_DIG_Connect_Definition ++{ ++ DIG_STA_DISCONNECT = 0, ++ DIG_STA_CONNECT = 1, ++ DIG_STA_BEFORE_CONNECT = 2, ++ DIG_MultiSTA_DISCONNECT = 3, ++ DIG_MultiSTA_CONNECT = 4, ++ DIG_CONNECT_MAX ++}DM_DIG_CONNECT_E; ++ ++ ++VOID ++ODM_FillTXPathInTXDESC( ++ IN PADAPTER Adapter, ++ IN PRT_TCB pTcb, ++ IN pu1Byte pDesc ++); ++ ++ ++#define dm_SWAW_RSSI_Check ODM_SwAntDivChkPerPktRssi ++ ++// ++// 2012/01/12 MH Check afapter status. Temp fix BSOD. ++// ++#define HAL_ADAPTER_STS_CHK(pDM_Odm)\ ++ if (pDM_Odm->Adapter == NULL)\ ++ {\ ++ return;\ ++ }\ ++ ++ ++// ++// For new definition in MP temporarily fro power tracking, ++// ++#define odm_TXPowerTrackingDirectCall(_Adapter) \ ++ IS_HARDWARE_TYPE_8192D(_Adapter) ? odm_TXPowerTrackingCallback_ThermalMeter_92D(_Adapter) : \ ++ IS_HARDWARE_TYPE_8192C(_Adapter) ? odm_TXPowerTrackingCallback_ThermalMeter_92C(_Adapter) : \ ++ IS_HARDWARE_TYPE_8723A(_Adapter) ? odm_TXPowerTrackingCallback_ThermalMeter_8723A(_Adapter) :\ ++ odm_TXPowerTrackingCallback_ThermalMeter_8188E(_Adapter) ++ ++VOID ++ODM_SetTxAntByTxInfo_88C_92D( ++ IN PDM_ODM_T pDM_Odm, ++ IN pu1Byte pDesc, ++ IN u1Byte macId ++ ); ++#endif // #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++VOID ++ODM_AntselStatistics_88C( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacId, ++ IN u4Byte PWDBAll, ++ IN BOOLEAN isCCKrate ++); ++ ++#if( DM_ODM_SUPPORT_TYPE & (ODM_MP |ODM_CE)) ++ ++VOID ++ODM_SingleDualAntennaDefaultSetting( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++BOOLEAN ++ODM_SingleDualAntennaDetection( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte mode ++ ); ++ ++#endif // #if((DM_ODM_SUPPORT_TYPE==ODM_MP)||(DM_ODM_SUPPORT_TYPE==ODM_CE)) ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++void odm_dtc(PDM_ODM_T pDM_Odm); ++#endif /* #if (DM_ODM_SUPPORT_TYPE == ODM_CE) */ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_HWConfig.c b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_HWConfig.c +new file mode 100644 +index 00000000..a11a8154 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_HWConfig.c +@@ -0,0 +1,1198 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++//============================================================ ++// include files ++//============================================================ ++ ++#include "odm_precomp.h" ++ ++#if (RTL8188E_FOR_TEST_CHIP > 1) ++ #define READ_AND_CONFIG(ic, txt) do {\ ++ if (pDM_Odm->bIsMPChip)\ ++ READ_AND_CONFIG_MP(ic,txt);\ ++ else\ ++ READ_AND_CONFIG_TC(ic,txt);\ ++ } while(0) ++#elif (RTL8188E_FOR_TEST_CHIP == 1) ++ #define READ_AND_CONFIG READ_AND_CONFIG_TC ++#else ++ #define READ_AND_CONFIG READ_AND_CONFIG_MP ++#endif ++ ++#define READ_AND_CONFIG_MP(ic, txt) (ODM_ReadAndConfig##txt##ic(pDM_Odm)) ++#define READ_AND_CONFIG_TC(ic, txt) (ODM_ReadAndConfig_TC##txt##ic(pDM_Odm)) ++ ++u1Byte ++odm_QueryRxPwrPercentage( ++ IN s1Byte AntPower ++ ) ++{ ++ if ((AntPower <= -100) || (AntPower >= 20)) ++ { ++ return 0; ++ } ++ else if (AntPower >= 0) ++ { ++ return 100; ++ } ++ else ++ { ++ return (100+AntPower); ++ } ++ ++} ++ ++#if (DM_ODM_SUPPORT_TYPE != ODM_MP) ++// ++// 2012/01/12 MH MOve some signal strength smooth method to MP HAL layer. ++// IF other SW team do not support the feature, remove this section.?? ++// ++s4Byte ++odm_SignalScaleMapping_92CSeries_patch_RT_CID_819x_Lenovo( ++ IN OUT PDM_ODM_T pDM_Odm, ++ s4Byte CurrSig ++) ++{ ++ s4Byte RetSig; ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ //if(pDM_Odm->SupportInterface == ODM_ITRF_PCIE) ++ { ++ // Step 1. Scale mapping. ++ // 20100611 Joseph: Re-tunning RSSI presentation for Lenovo. ++ // 20100426 Joseph: Modify Signal strength mapping. ++ // This modification makes the RSSI indication similar to Intel solution. ++ // 20100414 Joseph: Tunning RSSI for Lenovo according to RTL8191SE. ++ if(CurrSig >= 54 && CurrSig <= 100) ++ { ++ RetSig = 100; ++ } ++ else if(CurrSig>=42 && CurrSig <= 53 ) ++ { ++ RetSig = 95; ++ } ++ else if(CurrSig>=36 && CurrSig <= 41 ) ++ { ++ RetSig = 74 + ((CurrSig - 36) *20)/6; ++ } ++ else if(CurrSig>=33 && CurrSig <= 35 ) ++ { ++ RetSig = 65 + ((CurrSig - 33) *8)/2; ++ } ++ else if(CurrSig>=18 && CurrSig <= 32 ) ++ { ++ RetSig = 62 + ((CurrSig - 18) *2)/15; ++ } ++ else if(CurrSig>=15 && CurrSig <= 17 ) ++ { ++ RetSig = 33 + ((CurrSig - 15) *28)/2; ++ } ++ else if(CurrSig>=10 && CurrSig <= 14 ) ++ { ++ RetSig = 39; ++ } ++ else if(CurrSig>=8 && CurrSig <= 9 ) ++ { ++ RetSig = 33; ++ } ++ else if(CurrSig <= 8 ) ++ { ++ RetSig = 19; ++ } ++ } ++#endif //ENDIF (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ return RetSig; ++} ++ ++s4Byte ++odm_SignalScaleMapping_92CSeries_patch_RT_CID_819x_Netcore( ++ IN OUT PDM_ODM_T pDM_Odm, ++ s4Byte CurrSig ++) ++{ ++ s4Byte RetSig; ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ //if(pDM_Odm->SupportInterface == ODM_ITRF_USB) ++ { ++ // Netcore request this modification because 2009.04.13 SU driver use it. ++ if(CurrSig >= 31 && CurrSig <= 100) ++ { ++ RetSig = 100; ++ } ++ else if(CurrSig >= 21 && CurrSig <= 30) ++ { ++ RetSig = 90 + ((CurrSig - 20) / 1); ++ } ++ else if(CurrSig >= 11 && CurrSig <= 20) ++ { ++ RetSig = 80 + ((CurrSig - 10) / 1); ++ } ++ else if(CurrSig >= 7 && CurrSig <= 10) ++ { ++ RetSig = 69 + (CurrSig - 7); ++ } ++ else if(CurrSig == 6) ++ { ++ RetSig = 54; ++ } ++ else if(CurrSig == 5) ++ { ++ RetSig = 45; ++ } ++ else if(CurrSig == 4) ++ { ++ RetSig = 36; ++ } ++ else if(CurrSig == 3) ++ { ++ RetSig = 27; ++ } ++ else if(CurrSig == 2) ++ { ++ RetSig = 18; ++ } ++ else if(CurrSig == 1) ++ { ++ RetSig = 9; ++ } ++ else ++ { ++ RetSig = CurrSig; ++ } ++ } ++#endif //ENDIF (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ return RetSig; ++} ++ ++ ++s4Byte ++odm_SignalScaleMapping_92CSeries( ++ IN OUT PDM_ODM_T pDM_Odm, ++ IN s4Byte CurrSig ++) ++{ ++ s4Byte RetSig; ++#if (DEV_BUS_TYPE == RT_PCI_INTERFACE) ++ if(pDM_Odm->SupportInterface == ODM_ITRF_PCIE) ++ { ++ // Step 1. Scale mapping. ++ if(CurrSig >= 61 && CurrSig <= 100) ++ { ++ RetSig = 90 + ((CurrSig - 60) / 4); ++ } ++ else if(CurrSig >= 41 && CurrSig <= 60) ++ { ++ RetSig = 78 + ((CurrSig - 40) / 2); ++ } ++ else if(CurrSig >= 31 && CurrSig <= 40) ++ { ++ RetSig = 66 + (CurrSig - 30); ++ } ++ else if(CurrSig >= 21 && CurrSig <= 30) ++ { ++ RetSig = 54 + (CurrSig - 20); ++ } ++ else if(CurrSig >= 5 && CurrSig <= 20) ++ { ++ RetSig = 42 + (((CurrSig - 5) * 2) / 3); ++ } ++ else if(CurrSig == 4) ++ { ++ RetSig = 36; ++ } ++ else if(CurrSig == 3) ++ { ++ RetSig = 27; ++ } ++ else if(CurrSig == 2) ++ { ++ RetSig = 18; ++ } ++ else if(CurrSig == 1) ++ { ++ RetSig = 9; ++ } ++ else ++ { ++ RetSig = CurrSig; ++ } ++ } ++#endif ++ ++#if ((DEV_BUS_TYPE == RT_USB_INTERFACE) ||(DEV_BUS_TYPE == RT_SDIO_INTERFACE)) ++ if((pDM_Odm->SupportInterface == ODM_ITRF_USB) || (pDM_Odm->SupportInterface == ODM_ITRF_SDIO) ) ++ { ++ if(CurrSig >= 51 && CurrSig <= 100) ++ { ++ RetSig = 100; ++ } ++ else if(CurrSig >= 41 && CurrSig <= 50) ++ { ++ RetSig = 80 + ((CurrSig - 40)*2); ++ } ++ else if(CurrSig >= 31 && CurrSig <= 40) ++ { ++ RetSig = 66 + (CurrSig - 30); ++ } ++ else if(CurrSig >= 21 && CurrSig <= 30) ++ { ++ RetSig = 54 + (CurrSig - 20); ++ } ++ else if(CurrSig >= 10 && CurrSig <= 20) ++ { ++ RetSig = 42 + (((CurrSig - 10) * 2) / 3); ++ } ++ else if(CurrSig >= 5 && CurrSig <= 9) ++ { ++ RetSig = 22 + (((CurrSig - 5) * 3) / 2); ++ } ++ else if(CurrSig >= 1 && CurrSig <= 4) ++ { ++ RetSig = 6 + (((CurrSig - 1) * 3) / 2); ++ } ++ else ++ { ++ RetSig = CurrSig; ++ } ++ } ++#endif ++ return RetSig; ++} ++s4Byte ++odm_SignalScaleMapping( ++ IN OUT PDM_ODM_T pDM_Odm, ++ IN s4Byte CurrSig ++) ++{ ++ if( (pDM_Odm->SupportPlatform == ODM_MP) && ++ (pDM_Odm->SupportInterface != ODM_ITRF_PCIE) && //USB & SDIO ++ (pDM_Odm->PatchID==10))//pMgntInfo->CustomerID == RT_CID_819x_Netcore ++ { ++ return odm_SignalScaleMapping_92CSeries_patch_RT_CID_819x_Netcore(pDM_Odm,CurrSig); ++ } ++ else if( (pDM_Odm->SupportPlatform == ODM_MP) && ++ (pDM_Odm->SupportInterface == ODM_ITRF_PCIE) && ++ (pDM_Odm->PatchID==19))//pMgntInfo->CustomerID == RT_CID_819x_Lenovo) ++ { ++ return odm_SignalScaleMapping_92CSeries_patch_RT_CID_819x_Lenovo(pDM_Odm, CurrSig); ++ } ++ else{ ++ return odm_SignalScaleMapping_92CSeries(pDM_Odm,CurrSig); ++ } ++ ++} ++#endif ++ ++//pMgntInfo->CustomerID == RT_CID_819x_Lenovo ++static u1Byte odm_SQ_process_patch_RT_CID_819x_Lenovo( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte isCCKrate, ++ IN u1Byte PWDB_ALL, ++ IN u1Byte path, ++ IN u1Byte RSSI ++) ++{ ++ u1Byte SQ; ++#if (DM_ODM_SUPPORT_TYPE & ODM_MP) ++ // mapping to 5 bars for vista signal strength ++ // signal quality in driver will be displayed to signal strength ++ if(isCCKrate){ ++ // in vista. ++ if(PWDB_ALL >= 50) ++ SQ = 100; ++ else if(PWDB_ALL >= 35 && PWDB_ALL < 50) ++ SQ = 80; ++ else if(PWDB_ALL >= 22 && PWDB_ALL < 35) ++ SQ = 60; ++ else if(PWDB_ALL >= 18 && PWDB_ALL < 22) ++ SQ = 40; ++ else ++ SQ = 20; ++ } ++ else{//OFDM rate ++ ++ // mapping to 5 bars for vista signal strength ++ // signal quality in driver will be displayed to signal strength ++ // in vista. ++ if(RSSI >= 50) ++ SQ = 100; ++ else if(RSSI >= 35 && RSSI < 50) ++ SQ = 80; ++ else if(RSSI >= 22 && RSSI < 35) ++ SQ = 60; ++ else if(RSSI >= 18 && RSSI < 22) ++ SQ = 40; ++ else ++ SQ = 20; ++ } ++#endif ++ return SQ; ++} ++ ++static u1Byte ++odm_EVMdbToPercentage( ++ IN s1Byte Value ++ ) ++{ ++ // ++ // -33dB~0dB to 0%~99% ++ // ++ s1Byte ret_val; ++ ++ ret_val = Value; ++ //ret_val /= 2; ++ ++ //ODM_RTPRINT(FRX, RX_PHY_SQ, ("EVMdbToPercentage92C Value=%d / %x \n", ret_val, ret_val)); ++ ++ if(ret_val >= 0) ++ ret_val = 0; ++ if(ret_val <= -33) ++ ret_val = -33; ++ ++ ret_val = 0 - ret_val; ++ ret_val*=3; ++ ++ if(ret_val == 99) ++ ret_val = 100; ++ ++ return(ret_val); ++} ++ ++ ++ ++VOID ++odm_RxPhyStatus92CSeries_Parsing( ++ IN OUT PDM_ODM_T pDM_Odm, ++ OUT PODM_PHY_INFO_T pPhyInfo, ++ IN pu1Byte pPhyStatus, ++ IN PODM_PACKET_INFO_T pPktinfo ++ ) ++{ ++ SWAT_T *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ u1Byte i, Max_spatial_stream; ++ s1Byte rx_pwr[4], rx_pwr_all=0; ++ u1Byte EVM, PWDB_ALL = 0, PWDB_ALL_BT; ++ u1Byte RSSI, total_rssi=0; ++ u1Byte isCCKrate=0; ++ u1Byte rf_rx_num = 0; ++ u1Byte cck_highpwr = 0; ++ u1Byte LNA_idx, VGA_idx; ++ ++ PPHY_STATUS_RPT_8192CD_T pPhyStaRpt = (PPHY_STATUS_RPT_8192CD_T)pPhyStatus; ++ ++ isCCKrate = ((pPktinfo->Rate >= DESC92C_RATE1M ) && (pPktinfo->Rate <= DESC92C_RATE11M ))?TRUE :FALSE; ++ ++ pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_A] = -1; ++ pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_B] = -1; ++ ++ ++ if(isCCKrate) ++ { ++ u1Byte report; ++ u1Byte cck_agc_rpt; ++ ++ pDM_Odm->PhyDbgInfo.NumQryPhyStatusCCK++; ++ // ++ // (1)Hardware does not provide RSSI for CCK ++ // (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) ++ // ++ ++ //if(pHalData->eRFPowerState == eRfOn) ++ cck_highpwr = pDM_Odm->bCckHighPower; ++ //else ++ // cck_highpwr = FALSE; ++ ++ cck_agc_rpt = pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a ; ++ ++ //2011.11.28 LukeLee: 88E use different LNA & VGA gain table ++ //The RSSI formula should be modified according to the gain table ++ //In 88E, cck_highpwr is always set to 1 ++ if(pDM_Odm->SupportICType & (ODM_RTL8188E|ODM_RTL8812)) ++ { ++ LNA_idx = ((cck_agc_rpt & 0xE0) >>5); ++ VGA_idx = (cck_agc_rpt & 0x1F); ++ switch(LNA_idx) ++ { ++ case 7: ++ if(VGA_idx <= 27) ++ rx_pwr_all = -100 + 2*(27-VGA_idx); //VGA_idx = 27~2 ++ else ++ rx_pwr_all = -100; ++ break; ++ case 6: ++ rx_pwr_all = -48 + 2*(2-VGA_idx); //VGA_idx = 2~0 ++ break; ++ case 5: ++ rx_pwr_all = -42 + 2*(7-VGA_idx); //VGA_idx = 7~5 ++ break; ++ case 4: ++ rx_pwr_all = -36 + 2*(7-VGA_idx); //VGA_idx = 7~4 ++ break; ++ case 3: ++ //rx_pwr_all = -28 + 2*(7-VGA_idx); //VGA_idx = 7~0 ++ rx_pwr_all = -24 + 2*(7-VGA_idx); //VGA_idx = 7~0 ++ break; ++ case 2: ++ if(cck_highpwr) ++ rx_pwr_all = -12 + 2*(5-VGA_idx); //VGA_idx = 5~0 ++ else ++ rx_pwr_all = -6+ 2*(5-VGA_idx); ++ break; ++ case 1: ++ rx_pwr_all = 8-2*VGA_idx; ++ break; ++ case 0: ++ rx_pwr_all = 14-2*VGA_idx; ++ break; ++ default: ++ //DbgPrint("CCK Exception default\n"); ++ break; ++ } ++ rx_pwr_all += 6; ++ PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); ++ if(cck_highpwr == FALSE) ++ { ++ if(PWDB_ALL >= 80) ++ PWDB_ALL = ((PWDB_ALL-80)<<1)+((PWDB_ALL-80)>>1)+80; ++ else if((PWDB_ALL <= 78) && (PWDB_ALL >= 20)) ++ PWDB_ALL += 3; ++ if(PWDB_ALL>100) ++ PWDB_ALL = 100; ++ } ++ } ++ else ++ { ++ if(!cck_highpwr) ++ { ++ report =( cck_agc_rpt & 0xc0 )>>6; ++ switch(report) ++ { ++ // 03312009 modified by cosa ++ // Modify the RF RNA gain value to -40, -20, -2, 14 by Jenyu's suggestion ++ // Note: different RF with the different RNA gain. ++ case 0x3: ++ rx_pwr_all = -46 - (cck_agc_rpt & 0x3e); ++ break; ++ case 0x2: ++ rx_pwr_all = -26 - (cck_agc_rpt & 0x3e); ++ break; ++ case 0x1: ++ rx_pwr_all = -12 - (cck_agc_rpt & 0x3e); ++ break; ++ case 0x0: ++ rx_pwr_all = 16 - (cck_agc_rpt & 0x3e); ++ break; ++ } ++ } ++ else ++ { ++ //report = pDrvInfo->cfosho[0] & 0x60; ++ //report = pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a& 0x60; ++ ++ report = (cck_agc_rpt & 0x60)>>5; ++ switch(report) ++ { ++ case 0x3: ++ rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f)<<1) ; ++ break; ++ case 0x2: ++ rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f)<<1); ++ break; ++ case 0x1: ++ rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f)<<1) ; ++ break; ++ case 0x0: ++ rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f)<<1) ; ++ break; ++ } ++ } ++ ++ PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); ++ ++ //Modification for ext-LNA board ++ if(pDM_Odm->BoardType & (ODM_BOARD_EXT_LNA | ODM_BOARD_EXT_PA)) ++ { ++ if((cck_agc_rpt>>7) == 0){ ++ PWDB_ALL = (PWDB_ALL>94)?100:(PWDB_ALL +6); ++ } ++ else ++ { ++ if(PWDB_ALL > 38) ++ PWDB_ALL -= 16; ++ else ++ PWDB_ALL = (PWDB_ALL<=16)?(PWDB_ALL>>2):(PWDB_ALL -12); ++ } ++ ++ //CCK modification ++ if(PWDB_ALL > 25 && PWDB_ALL <= 60) ++ PWDB_ALL += 6; ++ //else if (PWDB_ALL <= 25) ++ // PWDB_ALL += 8; ++ } ++ else//Modification for int-LNA board ++ { ++ if(PWDB_ALL > 99) ++ PWDB_ALL -= 8; ++ else if(PWDB_ALL > 50 && PWDB_ALL <= 68) ++ PWDB_ALL += 4; ++ } ++ } ++ ++ pPhyInfo->RxPWDBAll = PWDB_ALL; ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE)) ++ pPhyInfo->BTRxRSSIPercentage = PWDB_ALL; ++ pPhyInfo->RecvSignalPower = rx_pwr_all; ++#endif ++ // ++ // (3) Get Signal Quality (EVM) ++ // ++ if(pPktinfo->bPacketMatchBSSID) ++ { ++ u1Byte SQ,SQ_rpt; ++ ++ if((pDM_Odm->SupportPlatform == ODM_MP) &&(pDM_Odm->PatchID==19)){//pMgntInfo->CustomerID == RT_CID_819x_Lenovo ++ SQ = odm_SQ_process_patch_RT_CID_819x_Lenovo(pDM_Odm,isCCKrate,PWDB_ALL,0,0); ++ } ++ else if(pPhyInfo->RxPWDBAll > 40 && !pDM_Odm->bInHctTest){ ++ SQ = 100; ++ } ++ else{ ++ SQ_rpt = pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all; ++ ++ if(SQ_rpt > 64) ++ SQ = 0; ++ else if (SQ_rpt < 20) ++ SQ = 100; ++ else ++ SQ = ((64-SQ_rpt) * 100) / 44; ++ ++ } ++ ++ //DbgPrint("cck SQ = %d\n", SQ); ++ pPhyInfo->SignalQuality = SQ; ++ pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_A] = SQ; ++ pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_B] = -1; ++ } ++ } ++ else //is OFDM rate ++ { ++ pDM_Odm->PhyDbgInfo.NumQryPhyStatusOFDM++; ++ ++ // ++ // (1)Get RSSI for HT rate ++ // ++ ++ for(i = ODM_RF_PATH_A; i < ODM_RF_PATH_MAX; i++) ++ { ++ // 2008/01/30 MH we will judge RF RX path now. ++ if (pDM_Odm->RFPathRxEnable & BIT(i)) ++ rf_rx_num++; ++ //else ++ //continue; ++ ++ rx_pwr[i] = ((pPhyStaRpt->path_agc[i].gain& 0x3F)*2) - 110; ++ ++ #if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE)) ++ pPhyInfo->RxPwr[i] = rx_pwr[i]; ++ #endif ++ ++ /* Translate DBM to percentage. */ ++ RSSI = odm_QueryRxPwrPercentage(rx_pwr[i]); ++ total_rssi += RSSI; ++ //RTPRINT(FRX, RX_PHY_SS, ("RF-%d RXPWR=%x RSSI=%d\n", i, rx_pwr[i], RSSI)); ++ ++ //Modification for ext-LNA board ++ if(pDM_Odm->BoardType & (ODM_BOARD_EXT_LNA | ODM_BOARD_EXT_PA)) ++ { ++ if((pPhyStaRpt->path_agc[i].trsw) == 1) ++ RSSI = (RSSI>94)?100:(RSSI +6); ++ else ++ RSSI = (RSSI<=16)?(RSSI>>3):(RSSI -16); ++ ++ if((RSSI <= 34) && (RSSI >=4)) ++ RSSI -= 4; ++ } ++ ++ pPhyInfo->RxMIMOSignalStrength[i] =(u1Byte) RSSI; ++ ++ #if (DM_ODM_SUPPORT_TYPE & (/*ODM_MP|*/ODM_CE|ODM_AP|ODM_ADSL)) ++ //Get Rx snr value in DB ++ pPhyInfo->RxSNR[i] = pDM_Odm->PhyDbgInfo.RxSNRdB[i] = (s4Byte)(pPhyStaRpt->path_rxsnr[i]/2); ++ #endif ++ ++ /* Record Signal Strength for next packet */ ++ if(pPktinfo->bPacketMatchBSSID) ++ { ++ if((pDM_Odm->SupportPlatform == ODM_MP) &&(pDM_Odm->PatchID==19)) ++ { ++ if(i==ODM_RF_PATH_A) ++ pPhyInfo->SignalQuality = odm_SQ_process_patch_RT_CID_819x_Lenovo(pDM_Odm,isCCKrate,PWDB_ALL,i,RSSI); ++ ++ } ++ ++ } ++ } ++ ++ ++ // ++ // (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) ++ // ++ rx_pwr_all = (((pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all) >> 1 )& 0x7f) -110; ++ //RTPRINT(FRX, RX_PHY_SS, ("PWDB_ALL=%d\n", PWDB_ALL)); ++ ++ PWDB_ALL_BT = PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); ++ //RTPRINT(FRX, RX_PHY_SS, ("PWDB_ALL=%d\n",PWDB_ALL)); ++ ++ pPhyInfo->RxPWDBAll = PWDB_ALL; ++ //ODM_RT_TRACE(pDM_Odm,ODM_COMP_RSSI_MONITOR, ODM_DBG_LOUD, ("ODM OFDM RSSI=%d\n",pPhyInfo->RxPWDBAll)); ++ #if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE)) ++ pPhyInfo->BTRxRSSIPercentage = PWDB_ALL_BT; ++ pPhyInfo->RxPower = rx_pwr_all; ++ pPhyInfo->RecvSignalPower = rx_pwr_all; ++ #endif ++ ++ if((pDM_Odm->SupportPlatform == ODM_MP) &&(pDM_Odm->PatchID==19)){ ++ //do nothing ++ } ++ else{//pMgntInfo->CustomerID != RT_CID_819x_Lenovo ++ // ++ // (3)EVM of HT rate ++ // ++ if(pPktinfo->Rate >=DESC92C_RATEMCS8 && pPktinfo->Rate <=DESC92C_RATEMCS15) ++ Max_spatial_stream = 2; //both spatial stream make sense ++ else ++ Max_spatial_stream = 1; //only spatial stream 1 makes sense ++ ++ for(i=0; i>= 1" because the compilor of free build environment ++ // fill most significant bit to "zero" when doing shifting operation which may change a negative ++ // value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore. ++ EVM = odm_EVMdbToPercentage( (pPhyStaRpt->stream_rxevm[i] )); //dbm ++ ++ //RTPRINT(FRX, RX_PHY_SQ, ("RXRATE=%x RXEVM=%x EVM=%s%d\n", ++ //GET_RX_STATUS_DESC_RX_MCS(pDesc), pDrvInfo->rxevm[i], "%", EVM)); ++ ++ if(pPktinfo->bPacketMatchBSSID) ++ { ++ if(i==ODM_RF_PATH_A) // Fill value in RFD, Get the first spatial stream only ++ { ++ pPhyInfo->SignalQuality = (u1Byte)(EVM & 0xff); ++ } ++ pPhyInfo->RxMIMOSignalQuality[i] = (u1Byte)(EVM & 0xff); ++ } ++ } ++ } ++ ++ } ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE)) ++ //UI BSS List signal strength(in percentage), make it good looking, from 0~100. ++ //It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). ++ if(isCCKrate) ++ { ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ // 2012/01/12 MH Use customeris signal strength from HalComRxdDesc.c/ ++ pPhyInfo->SignalStrength = (u1Byte)(SignalScaleMapping(pDM_Odm->Adapter, PWDB_ALL));//PWDB_ALL; ++#else ++ pPhyInfo->SignalStrength = (u1Byte)(odm_SignalScaleMapping(pDM_Odm, PWDB_ALL));//PWDB_ALL; ++#endif ++ } ++ else ++ { ++ if (rf_rx_num != 0) ++ { ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ // 2012/01/12 MH Use customeris signal strength from HalComRxdDesc.c/ ++ pPhyInfo->SignalStrength = (u1Byte)(SignalScaleMapping(pDM_Odm->Adapter, total_rssi/=rf_rx_num));//PWDB_ALL; ++#else ++ pPhyInfo->SignalStrength = (u1Byte)(odm_SignalScaleMapping(pDM_Odm, total_rssi/=rf_rx_num)); ++#endif ++ } ++ } ++#endif ++ ++ //For 92C/92D HW (Hybrid) Antenna Diversity ++#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) ++ pDM_SWAT_Table->antsel = pPhyStaRpt->ant_sel; ++ //For 88E HW Antenna Diversity ++ pDM_Odm->DM_FatTable.antsel_rx_keep_0 = pPhyStaRpt->ant_sel; ++ pDM_Odm->DM_FatTable.antsel_rx_keep_1 = pPhyStaRpt->ant_sel_b; ++ pDM_Odm->DM_FatTable.antsel_rx_keep_2 = pPhyStaRpt->antsel_rx_keep_2; ++#endif ++} ++ ++VOID ++odm_Init_RSSIForDM( ++ IN OUT PDM_ODM_T pDM_Odm ++ ) ++{ ++ ++} ++ ++VOID ++odm_Process_RSSIForDM( ++ IN OUT PDM_ODM_T pDM_Odm, ++ IN PODM_PHY_INFO_T pPhyInfo, ++ IN PODM_PACKET_INFO_T pPktinfo ++ ) ++{ ++ ++ s4Byte UndecoratedSmoothedPWDB, UndecoratedSmoothedCCK, UndecoratedSmoothedOFDM, RSSI_Ave; ++ u1Byte isCCKrate=0; ++ u1Byte RSSI_max, RSSI_min, i; ++ u4Byte OFDM_pkt=0; ++ u4Byte Weighting=0; ++ ++ PSTA_INFO_T pEntry; ++ ++ if(pPktinfo->StationID == 0xFF) ++ return; ++ ++ // 2011/11/17 MH Need to debug ++ //if (pDM_Odm->SupportPlatform == ODM_MP) ++ { ++ ++ } ++ ++ pEntry = pDM_Odm->pODM_StaInfo[pPktinfo->StationID]; ++ if(!IS_STA_VALID(pEntry) ){ ++ return; ++ } ++ if((!pPktinfo->bPacketMatchBSSID) ) ++ { ++ return; ++ } ++ ++ isCCKrate = ((pPktinfo->Rate >= DESC92C_RATE1M ) && (pPktinfo->Rate <= DESC92C_RATE11M ))?TRUE :FALSE; ++ if(pPktinfo->bPacketBeacon) ++ pDM_Odm->PhyDbgInfo.NumQryBeaconPkt++; ++ ++ pDM_Odm->RxRate = pPktinfo->Rate; ++#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) ++#if ((RTL8192C_SUPPORT == 1) ||(RTL8192D_SUPPORT == 1)) ++ if(pDM_Odm->SupportICType & ODM_RTL8192C|ODM_RTL8192D) ++ { ++ if(pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) ++ { ++ //if(pPktinfo->bPacketBeacon) ++ //{ ++ // DbgPrint("This is beacon, isCCKrate=%d\n", isCCKrate); ++ //} ++ ODM_AntselStatistics_88C(pDM_Odm, pPktinfo->StationID, pPhyInfo->RxPWDBAll, isCCKrate); ++ } ++ } ++#endif ++ //-----------------Smart Antenna Debug Message------------------// ++#if (RTL8188E_SUPPORT == 1) ++ if(pDM_Odm->SupportICType == ODM_RTL8188E) ++ { ++ u1Byte antsel_tr_mux; ++ pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; ++ ++ if(pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV) ++ { ++ if(pDM_FatTable->FAT_State == FAT_TRAINING_STATE) ++ { ++ if(pPktinfo->bPacketToSelf) //(pPktinfo->bPacketMatchBSSID && (!pPktinfo->bPacketBeacon)) ++ { ++ antsel_tr_mux = (pDM_FatTable->antsel_rx_keep_2<<2) |(pDM_FatTable->antsel_rx_keep_1 <<1) |pDM_FatTable->antsel_rx_keep_0; ++ pDM_FatTable->antSumRSSI[antsel_tr_mux] += pPhyInfo->RxPWDBAll; ++ pDM_FatTable->antRSSIcnt[antsel_tr_mux]++; ++ //ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("isCCKrate=%d, PWDB_ALL=%d\n",isCCKrate, pPhyInfo->RxPWDBAll)); ++ //ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("antsel_tr_mux=3'b%d%d%d\n", ++ //pDM_FatTable->antsel_rx_keep_2, pDM_FatTable->antsel_rx_keep_1, pDM_FatTable->antsel_rx_keep_0)); ++ ++ } ++ } ++ } ++ else if((pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV)||(pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV)) ++ { ++ if(pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) ++ { ++ antsel_tr_mux = (pDM_FatTable->antsel_rx_keep_2<<2) |(pDM_FatTable->antsel_rx_keep_1 <<1) |pDM_FatTable->antsel_rx_keep_0; ++ //ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("antsel_tr_mux=3'b%d%d%d\n", ++ // pDM_FatTable->antsel_rx_keep_2, pDM_FatTable->antsel_rx_keep_1, pDM_FatTable->antsel_rx_keep_0)); ++ ++ ODM_AntselStatistics_88E(pDM_Odm, antsel_tr_mux, pPktinfo->StationID, pPhyInfo->RxPWDBAll); ++ } ++ } ++ ++ } ++#endif ++#endif //#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) ++ //-----------------Smart Antenna Debug Message------------------// ++ ++ UndecoratedSmoothedCCK = pEntry->rssi_stat.UndecoratedSmoothedCCK; ++ UndecoratedSmoothedOFDM = pEntry->rssi_stat.UndecoratedSmoothedOFDM; ++ UndecoratedSmoothedPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB; ++ ++ if(pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) ++ { ++ ++ if(!isCCKrate)//ofdm rate ++ { ++ if(pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B] == 0){ ++ RSSI_Ave = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; ++ pDM_Odm->RSSI_A = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; ++ pDM_Odm->RSSI_B = 0; ++ } ++ else ++ { ++ //DbgPrint("pRfd->Status.RxMIMOSignalStrength[0] = %d, pRfd->Status.RxMIMOSignalStrength[1] = %d \n", ++ //pRfd->Status.RxMIMOSignalStrength[0], pRfd->Status.RxMIMOSignalStrength[1]); ++ pDM_Odm->RSSI_A = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; ++ pDM_Odm->RSSI_B = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]; ++ ++ if(pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A] > pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]) ++ { ++ RSSI_max = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; ++ RSSI_min = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]; ++ } ++ else ++ { ++ RSSI_max = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]; ++ RSSI_min = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; ++ } ++ if((RSSI_max -RSSI_min) < 3) ++ RSSI_Ave = RSSI_max; ++ else if((RSSI_max -RSSI_min) < 6) ++ RSSI_Ave = RSSI_max - 1; ++ else if((RSSI_max -RSSI_min) < 10) ++ RSSI_Ave = RSSI_max - 2; ++ else ++ RSSI_Ave = RSSI_max - 3; ++ } ++ ++ //1 Process OFDM RSSI ++ if(UndecoratedSmoothedOFDM <= 0) // initialize ++ { ++ UndecoratedSmoothedOFDM = pPhyInfo->RxPWDBAll; ++ } ++ else ++ { ++ if(pPhyInfo->RxPWDBAll > (u4Byte)UndecoratedSmoothedOFDM) ++ { ++ UndecoratedSmoothedOFDM = ++ ( ((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) + ++ (RSSI_Ave)) /(Rx_Smooth_Factor); ++ UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM + 1; ++ } ++ else ++ { ++ UndecoratedSmoothedOFDM = ++ ( ((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) + ++ (RSSI_Ave)) /(Rx_Smooth_Factor); ++ } ++ } ++ ++ pEntry->rssi_stat.PacketMap = (pEntry->rssi_stat.PacketMap<<1) | BIT0; ++ ++ } ++ else ++ { ++ RSSI_Ave = pPhyInfo->RxPWDBAll; ++ pDM_Odm->RSSI_A = (u1Byte) pPhyInfo->RxPWDBAll; ++ pDM_Odm->RSSI_B = 0xFF; ++ ++ //1 Process CCK RSSI ++ if(UndecoratedSmoothedCCK <= 0) // initialize ++ { ++ UndecoratedSmoothedCCK = pPhyInfo->RxPWDBAll; ++ } ++ else ++ { ++ if(pPhyInfo->RxPWDBAll > (u4Byte)UndecoratedSmoothedCCK) ++ { ++ UndecoratedSmoothedCCK = ++ ( ((UndecoratedSmoothedCCK)*(Rx_Smooth_Factor-1)) + ++ (pPhyInfo->RxPWDBAll)) /(Rx_Smooth_Factor); ++ UndecoratedSmoothedCCK = UndecoratedSmoothedCCK + 1; ++ } ++ else ++ { ++ UndecoratedSmoothedCCK = ++ ( ((UndecoratedSmoothedCCK)*(Rx_Smooth_Factor-1)) + ++ (pPhyInfo->RxPWDBAll)) /(Rx_Smooth_Factor); ++ } ++ } ++ pEntry->rssi_stat.PacketMap = pEntry->rssi_stat.PacketMap<<1; ++ } ++ ++ //if(pEntry) ++ { ++ //2011.07.28 LukeLee: modified to prevent unstable CCK RSSI ++ if(pEntry->rssi_stat.ValidBit >= 64) ++ pEntry->rssi_stat.ValidBit = 64; ++ else ++ pEntry->rssi_stat.ValidBit++; ++ ++ for(i=0; irssi_stat.ValidBit; i++) ++ OFDM_pkt += (u1Byte)(pEntry->rssi_stat.PacketMap>>i)&BIT0; ++ ++ if(pEntry->rssi_stat.ValidBit == 64) ++ { ++ Weighting = ((OFDM_pkt<<4) > 64)?64:(OFDM_pkt<<4); ++ UndecoratedSmoothedPWDB = (Weighting*UndecoratedSmoothedOFDM+(64-Weighting)*UndecoratedSmoothedCCK)>>6; ++ } ++ else ++ { ++ if(pEntry->rssi_stat.ValidBit != 0) ++ UndecoratedSmoothedPWDB = (OFDM_pkt*UndecoratedSmoothedOFDM+(pEntry->rssi_stat.ValidBit-OFDM_pkt)*UndecoratedSmoothedCCK)/pEntry->rssi_stat.ValidBit; ++ else ++ UndecoratedSmoothedPWDB = 0; ++ } ++ ++ pEntry->rssi_stat.UndecoratedSmoothedCCK = UndecoratedSmoothedCCK; ++ pEntry->rssi_stat.UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM; ++ pEntry->rssi_stat.UndecoratedSmoothedPWDB = UndecoratedSmoothedPWDB; ++ ++ //DbgPrint("OFDM_pkt=%d, Weighting=%d\n", OFDM_pkt, Weighting); ++ //DbgPrint("UndecoratedSmoothedOFDM=%d, UndecoratedSmoothedPWDB=%d, UndecoratedSmoothedCCK=%d\n", ++ // UndecoratedSmoothedOFDM, UndecoratedSmoothedPWDB, UndecoratedSmoothedCCK); ++ ++ } ++ ++ } ++} ++ ++// ++// Endianness before calling this API ++// ++VOID ++ODM_PhyStatusQuery_92CSeries( ++ IN OUT PDM_ODM_T pDM_Odm, ++ OUT PODM_PHY_INFO_T pPhyInfo, ++ IN pu1Byte pPhyStatus, ++ IN PODM_PACKET_INFO_T pPktinfo ++ ) ++{ ++ ++ odm_RxPhyStatus92CSeries_Parsing( ++ pDM_Odm, ++ pPhyInfo, ++ pPhyStatus, ++ pPktinfo); ++ ++ if( pDM_Odm->RSSI_test == TRUE) ++ { ++ // Select the packets to do RSSI checking for antenna switching. ++ if(pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon ) ++ { ++ /* ++ #if 0//(DM_ODM_SUPPORT_TYPE == ODM_MP) ++ dm_SWAW_RSSI_Check( ++ Adapter, ++ (tmppAdapter!=NULL)?(tmppAdapter==Adapter):TRUE, ++ bPacketMatchBSSID, ++ pEntry, ++ pRfd); ++ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ // Select the packets to do RSSI checking for antenna switching. ++ //odm_SwAntDivRSSICheck8192C(padapter, precvframe->u.hdr.attrib.RxPWDBAll); ++ #endif ++ */ ++ ODM_SwAntDivChkPerPktRssi(pDM_Odm,pPktinfo->StationID,pPhyInfo); ++ } ++ } ++ else ++ { ++ odm_Process_RSSIForDM(pDM_Odm,pPhyInfo,pPktinfo); ++ } ++ ++} ++ ++ ++ ++// ++// Endianness before calling this API ++// ++VOID ++ODM_PhyStatusQuery_JaguarSeries( ++ IN OUT PDM_ODM_T pDM_Odm, ++ OUT PODM_PHY_INFO_T pPhyInfo, ++ IN pu1Byte pPhyStatus, ++ IN PODM_PACKET_INFO_T pPktinfo ++ ) ++{ ++ ++ ++} ++ ++VOID ++ODM_PhyStatusQuery( ++ IN OUT PDM_ODM_T pDM_Odm, ++ OUT PODM_PHY_INFO_T pPhyInfo, ++ IN pu1Byte pPhyStatus, ++ IN PODM_PACKET_INFO_T pPktinfo ++ ) ++{ ++#if 0 // How to jaguar jugar series?? ++ if(pDM_Odm->SupportICType >= ODM_RTL8195 ) ++ { ++ ODM_PhyStatusQuery_JaguarSeries(pDM_Odm,pPhyInfo,pPhyStatus,pPktinfo); ++ } ++ else ++#endif ++ { ++ ODM_PhyStatusQuery_92CSeries(pDM_Odm,pPhyInfo,pPhyStatus,pPktinfo); ++ } ++} ++ ++// For future use. ++VOID ++ODM_MacStatusQuery( ++ IN OUT PDM_ODM_T pDM_Odm, ++ IN pu1Byte pMacStatus, ++ IN u1Byte MacID, ++ IN BOOLEAN bPacketMatchBSSID, ++ IN BOOLEAN bPacketToSelf, ++ IN BOOLEAN bPacketBeacon ++ ) ++{ ++ // 2011/10/19 Driver team will handle in the future. ++ ++} ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE|ODM_AP)) ++ ++HAL_STATUS ++ODM_ConfigRFWithHeaderFile( ++ IN PDM_ODM_T pDM_Odm, ++ IN ODM_RF_RADIO_PATH_E Content, ++ IN ODM_RF_RADIO_PATH_E eRFPath ++ ) ++{ ++ //RT_STATUS rtStatus = RT_STATUS_SUCCESS; ++ ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("===>ODM_ConfigRFWithHeaderFile\n")); ++#if (RTL8723A_SUPPORT == 1) ++ if (pDM_Odm->SupportICType == ODM_RTL8723A) ++ { ++ if(eRFPath == ODM_RF_PATH_A) ++ READ_AND_CONFIG_MP(8723A,_RadioA_1T_); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, (" ===> ODM_ConfigRFWithHeaderFile() Radio_A:Rtl8723RadioA_1TArray\n")); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, (" ===> ODM_ConfigRFWithHeaderFile() Radio_B:Rtl8723RadioB_1TArray\n")); ++ } ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("ODM_ConfigRFWithHeaderFile: Radio No %x\n", eRFPath)); ++ //rtStatus = RT_STATUS_SUCCESS; ++#endif ++#if (RTL8188E_SUPPORT == 1) ++ if (pDM_Odm->SupportICType == ODM_RTL8188E) ++ { ++ if(IS_VENDOR_8188E_I_CUT_SERIES(pDM_Odm->Adapter)) ++ READ_AND_CONFIG(8188E,_RadioA_1T_ICUT_); ++ else ++ READ_AND_CONFIG(8188E,_RadioA_1T_); ++ ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, (" ===> ODM_ConfigRFWithHeaderFile() Radio_A:Rtl8188ERadioA_1TArray\n")); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, (" ===> ODM_ConfigRFWithHeaderFile() Radio_B:Rtl8188ERadioB_1TArray\n")); ++ } ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("ODM_ConfigRFWithHeaderFile: Radio No %x\n", eRFPath)); ++ //rtStatus = RT_STATUS_SUCCESS; ++#endif ++ return HAL_STATUS_SUCCESS; ++} ++ ++ ++HAL_STATUS ++ODM_ConfigBBWithHeaderFile( ++ IN PDM_ODM_T pDM_Odm, ++ IN ODM_BB_Config_Type ConfigType ++ ) ++{ ++#if (RTL8723A_SUPPORT == 1) ++ if(pDM_Odm->SupportICType == ODM_RTL8723A) ++ { ++ ++ if(ConfigType == CONFIG_BB_PHY_REG) ++ { ++ READ_AND_CONFIG_MP(8723A,_PHY_REG_1T_); ++ } ++ else if(ConfigType == CONFIG_BB_AGC_TAB) ++ { ++ READ_AND_CONFIG_MP(8723A,_AGC_TAB_1T_); ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_INIT, ODM_DBG_LOUD, (" ===> phy_ConfigBBWithHeaderFile() phy:Rtl8723AGCTAB_1TArray\n")); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_INIT, ODM_DBG_LOUD, (" ===> phy_ConfigBBWithHeaderFile() agc:Rtl8723PHY_REG_1TArray\n")); ++ } ++#endif ++ ++#if (RTL8188E_SUPPORT == 1) ++ if(pDM_Odm->SupportICType == ODM_RTL8188E) ++ { ++ ++ if(ConfigType == CONFIG_BB_PHY_REG) ++ { ++ if(IS_VENDOR_8188E_I_CUT_SERIES(pDM_Odm->Adapter)) ++ READ_AND_CONFIG(8188E,_PHY_REG_1T_ICUT_); ++ else ++ READ_AND_CONFIG(8188E,_PHY_REG_1T_); ++ } ++ else if(ConfigType == CONFIG_BB_AGC_TAB) ++ { ++ if(IS_VENDOR_8188E_I_CUT_SERIES(pDM_Odm->Adapter)) ++ READ_AND_CONFIG(8188E,_AGC_TAB_1T_ICUT_); ++ else ++ READ_AND_CONFIG(8188E,_AGC_TAB_1T_); ++ } ++ else if(ConfigType == CONFIG_BB_PHY_REG_PG) ++ { ++ READ_AND_CONFIG(8188E,_PHY_REG_PG_); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_INIT, ODM_DBG_LOUD, (" ===> phy_ConfigBBWithHeaderFile() agc:Rtl8188EPHY_REG_PGArray\n")); ++ } ++ } ++#endif ++ ++ return HAL_STATUS_SUCCESS; ++} ++ ++HAL_STATUS ++ODM_ConfigMACWithHeaderFile( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ u1Byte result = HAL_STATUS_SUCCESS; ++#if (RTL8723A_SUPPORT == 1) ++ if (pDM_Odm->SupportICType == ODM_RTL8723A) ++ { ++ READ_AND_CONFIG_MP(8723A,_MAC_REG_); ++ } ++#endif ++#if (RTL8188E_SUPPORT == 1) ++ if (pDM_Odm->SupportICType == ODM_RTL8188E) ++ { ++ if(IS_VENDOR_8188E_I_CUT_SERIES(pDM_Odm->Adapter)) ++ READ_AND_CONFIG(8188E,_MAC_REG_ICUT_); ++ else ++ result =READ_AND_CONFIG(8188E,_MAC_REG_); ++ } ++#endif ++ ++ return result; ++} ++ ++ ++#endif // end of (#if DM_ODM_SUPPORT_TYPE) ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_HWConfig.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_HWConfig.h +new file mode 100644 +index 00000000..9b53a8aa +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_HWConfig.h +@@ -0,0 +1,195 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++ ++#ifndef __HALHWOUTSRC_H__ ++#define __HALHWOUTSRC_H__ ++ ++//============================================================ ++// Definition ++//============================================================ ++// ++//----------------------------------------------------------- ++// CCK Rates, TxHT = 0 ++#define DESC92C_RATE1M 0x00 ++#define DESC92C_RATE2M 0x01 ++#define DESC92C_RATE5_5M 0x02 ++#define DESC92C_RATE11M 0x03 ++ ++// OFDM Rates, TxHT = 0 ++#define DESC92C_RATE6M 0x04 ++#define DESC92C_RATE9M 0x05 ++#define DESC92C_RATE12M 0x06 ++#define DESC92C_RATE18M 0x07 ++#define DESC92C_RATE24M 0x08 ++#define DESC92C_RATE36M 0x09 ++#define DESC92C_RATE48M 0x0a ++#define DESC92C_RATE54M 0x0b ++ ++// MCS Rates, TxHT = 1 ++#define DESC92C_RATEMCS0 0x0c ++#define DESC92C_RATEMCS1 0x0d ++#define DESC92C_RATEMCS2 0x0e ++#define DESC92C_RATEMCS3 0x0f ++#define DESC92C_RATEMCS4 0x10 ++#define DESC92C_RATEMCS5 0x11 ++#define DESC92C_RATEMCS6 0x12 ++#define DESC92C_RATEMCS7 0x13 ++#define DESC92C_RATEMCS8 0x14 ++#define DESC92C_RATEMCS9 0x15 ++#define DESC92C_RATEMCS10 0x16 ++#define DESC92C_RATEMCS11 0x17 ++#define DESC92C_RATEMCS12 0x18 ++#define DESC92C_RATEMCS13 0x19 ++#define DESC92C_RATEMCS14 0x1a ++#define DESC92C_RATEMCS15 0x1b ++#define DESC92C_RATEMCS15_SG 0x1c ++#define DESC92C_RATEMCS32 0x20 ++ ++ ++//============================================================ ++// structure and define ++//============================================================ ++ ++typedef struct _Phy_Rx_AGC_Info ++{ ++ #if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) ++ u1Byte gain:7,trsw:1; ++ #else ++ u1Byte trsw:1,gain:7; ++ #endif ++} PHY_RX_AGC_INFO_T,*pPHY_RX_AGC_INFO_T; ++ ++typedef struct _Phy_Status_Rpt_8192cd ++{ ++ PHY_RX_AGC_INFO_T path_agc[2]; ++ u1Byte ch_corr[2]; ++ u1Byte cck_sig_qual_ofdm_pwdb_all; ++ u1Byte cck_agc_rpt_ofdm_cfosho_a; ++ u1Byte cck_rpt_b_ofdm_cfosho_b; ++ u1Byte rsvd_1;//ch_corr_msb; ++ u1Byte noise_power_db_msb; ++ u1Byte path_cfotail[2]; ++ u1Byte pcts_mask[2]; ++ s1Byte stream_rxevm[2]; ++ u1Byte path_rxsnr[2]; ++ u1Byte noise_power_db_lsb; ++ u1Byte rsvd_2[3]; ++ u1Byte stream_csi[2]; ++ u1Byte stream_target_csi[2]; ++ s1Byte sig_evm; ++ u1Byte rsvd_3; ++ ++#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) ++ u1Byte antsel_rx_keep_2:1; //ex_intf_flg:1; ++ u1Byte sgi_en:1; ++ u1Byte rxsc:2; ++ u1Byte idle_long:1; ++ u1Byte r_ant_train_en:1; ++ u1Byte ant_sel_b:1; ++ u1Byte ant_sel:1; ++#else // _BIG_ENDIAN_ ++ u1Byte ant_sel:1; ++ u1Byte ant_sel_b:1; ++ u1Byte r_ant_train_en:1; ++ u1Byte idle_long:1; ++ u1Byte rxsc:2; ++ u1Byte sgi_en:1; ++ u1Byte antsel_rx_keep_2:1; //ex_intf_flg:1; ++#endif ++} PHY_STATUS_RPT_8192CD_T,*PPHY_STATUS_RPT_8192CD_T; ++ ++ ++typedef struct _Phy_Status_Rpt_8195 ++{ ++ PHY_RX_AGC_INFO_T path_agc[2]; ++ u1Byte ch_num[2]; ++ u1Byte cck_sig_qual_ofdm_pwdb_all; ++ u1Byte cck_agc_rpt_ofdm_cfosho_a; ++ u1Byte cck_bb_pwr_ofdm_cfosho_b; ++ u1Byte cck_rx_path; //CCK_RX_PATH [3:0] (with regA07[3:0] definition) ++ u1Byte rsvd_1; ++ u1Byte path_cfotail[2]; ++ u1Byte pcts_mask[2]; ++ s1Byte stream_rxevm[2]; ++ u1Byte path_rxsnr[2]; ++ u1Byte rsvd_2[2]; ++ u1Byte stream_snr[2]; ++ u1Byte stream_csi[2]; ++ u1Byte rsvd_3[2]; ++ s1Byte sig_evm; ++ u1Byte rsvd_4; ++#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) ++ u1Byte antidx_anta:3; ++ u1Byte antidx_antb:3; ++ u1Byte rsvd_5:2; ++#else // _BIG_ENDIAN_ ++ u1Byte rsvd_5:2; ++ u1Byte antidx_antb:3; ++ u1Byte antidx_anta:3; ++#endif ++} PHY_STATUS_RPT_8195_T,*pPHY_STATUS_RPT_8195_T; ++ ++ ++VOID ++odm_Init_RSSIForDM( ++ IN OUT PDM_ODM_T pDM_Odm ++ ); ++ ++VOID ++ODM_PhyStatusQuery( ++ IN OUT PDM_ODM_T pDM_Odm, ++ OUT PODM_PHY_INFO_T pPhyInfo, ++ IN pu1Byte pPhyStatus, ++ IN PODM_PACKET_INFO_T pPktinfo ++ ); ++ ++VOID ++ODM_MacStatusQuery( ++ IN OUT PDM_ODM_T pDM_Odm, ++ IN pu1Byte pMacStatus, ++ IN u1Byte MacID, ++ IN BOOLEAN bPacketMatchBSSID, ++ IN BOOLEAN bPacketToSelf, ++ IN BOOLEAN bPacketBeacon ++ ); ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE|ODM_AP)) ++HAL_STATUS ++ODM_ConfigRFWithHeaderFile( ++ IN PDM_ODM_T pDM_Odm, ++ IN ODM_RF_RADIO_PATH_E Content, ++ IN ODM_RF_RADIO_PATH_E eRFPath ++ ); ++ ++HAL_STATUS ++ODM_ConfigBBWithHeaderFile( ++ IN PDM_ODM_T pDM_Odm, ++ IN ODM_BB_Config_Type ConfigType ++ ); ++ ++HAL_STATUS ++ODM_ConfigMACWithHeaderFile( ++ IN PDM_ODM_T pDM_Odm ++ ); ++#endif ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_RegDefine11AC.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_RegDefine11AC.h +new file mode 100644 +index 00000000..b2a318a9 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_RegDefine11AC.h +@@ -0,0 +1,55 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#ifndef __ODM_REGDEFINE11AC_H__ ++#define __ODM_REGDEFINE11AC_H__ ++ ++//2 RF REG LIST ++ ++ ++ ++//2 BB REG LIST ++//PAGE 8 ++//PAGE 9 ++#define ODM_REG_OFDM_FA_RST_11AC 0x9A4 ++//PAGE A ++#define ODM_REG_CCK_CCA_11AC 0xA0A ++#define ODM_REG_CCK_FA_RST_11AC 0xA2C ++#define ODM_REG_CCK_FA_11AC 0xA5C ++//PAGE C ++#define ODM_REG_IGI_A_11AC 0xC50 ++//PAGE E ++#define ODM_REG_IGI_B_11AC 0xE50 ++//PAGE F ++#define ODM_REG_OFDM_FA_11AC 0xF48 ++ ++ ++//2 MAC REG LIST ++ ++ ++ ++ ++//DIG Related ++#define ODM_BIT_IGI_11AC 0xFFFFFFFF ++ ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_RegDefine11N.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_RegDefine11N.h +new file mode 100644 +index 00000000..841b1b42 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_RegDefine11N.h +@@ -0,0 +1,172 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#ifndef __ODM_REGDEFINE11N_H__ ++#define __ODM_REGDEFINE11N_H__ ++ ++ ++//2 RF REG LIST ++#define ODM_REG_RF_MODE_11N 0x00 ++#define ODM_REG_RF_0B_11N 0x0B ++#define ODM_REG_CHNBW_11N 0x18 ++#define ODM_REG_T_METER_11N 0x24 ++#define ODM_REG_RF_25_11N 0x25 ++#define ODM_REG_RF_26_11N 0x26 ++#define ODM_REG_RF_27_11N 0x27 ++#define ODM_REG_RF_2B_11N 0x2B ++#define ODM_REG_RF_2C_11N 0x2C ++#define ODM_REG_RXRF_A3_11N 0x3C ++#define ODM_REG_T_METER_92D_11N 0x42 ++#define ODM_REG_T_METER_88E_11N 0x42 ++ ++ ++ ++//2 BB REG LIST ++//PAGE 8 ++#define ODM_REG_BB_CTRL_11N 0x800 ++#define ODM_REG_RF_PIN_11N 0x804 ++#define ODM_REG_PSD_CTRL_11N 0x808 ++#define ODM_REG_TX_ANT_CTRL_11N 0x80C ++#define ODM_REG_BB_PWR_SAV5_11N 0x818 ++#define ODM_REG_CCK_RPT_FORMAT_11N 0x824 ++#define ODM_REG_RX_DEFUALT_A_11N 0x858 ++#define ODM_REG_RX_DEFUALT_B_11N 0x85A ++#define ODM_REG_BB_PWR_SAV3_11N 0x85C ++#define ODM_REG_ANTSEL_CTRL_11N 0x860 ++#define ODM_REG_RX_ANT_CTRL_11N 0x864 ++#define ODM_REG_PIN_CTRL_11N 0x870 ++#define ODM_REG_BB_PWR_SAV1_11N 0x874 ++#define ODM_REG_ANTSEL_PATH_11N 0x878 ++#define ODM_REG_BB_3WIRE_11N 0x88C ++#define ODM_REG_SC_CNT_11N 0x8C4 ++#define ODM_REG_PSD_DATA_11N 0x8B4 ++//PAGE 9 ++#define ODM_REG_ANT_MAPPING1_11N 0x914 ++#define ODM_REG_ANT_MAPPING2_11N 0x918 ++//PAGE A ++#define ODM_REG_CCK_ANTDIV_PARA1_11N 0xA00 ++#define ODM_REG_CCK_CCA_11N 0xA0A ++#define ODM_REG_CCK_ANTDIV_PARA2_11N 0xA0C ++#define ODM_REG_CCK_ANTDIV_PARA3_11N 0xA10 ++#define ODM_REG_CCK_ANTDIV_PARA4_11N 0xA14 ++#define ODM_REG_CCK_FILTER_PARA1_11N 0xA22 ++#define ODM_REG_CCK_FILTER_PARA2_11N 0xA23 ++#define ODM_REG_CCK_FILTER_PARA3_11N 0xA24 ++#define ODM_REG_CCK_FILTER_PARA4_11N 0xA25 ++#define ODM_REG_CCK_FILTER_PARA5_11N 0xA26 ++#define ODM_REG_CCK_FILTER_PARA6_11N 0xA27 ++#define ODM_REG_CCK_FILTER_PARA7_11N 0xA28 ++#define ODM_REG_CCK_FILTER_PARA8_11N 0xA29 ++#define ODM_REG_CCK_FA_RST_11N 0xA2C ++#define ODM_REG_CCK_FA_MSB_11N 0xA58 ++#define ODM_REG_CCK_FA_LSB_11N 0xA5C ++#define ODM_REG_CCK_CCA_CNT_11N 0xA60 ++#define ODM_REG_BB_PWR_SAV4_11N 0xA74 ++//PAGE B ++#define ODM_REG_LNA_SWITCH_11N 0xB2C ++#define ODM_REG_PATH_SWITCH_11N 0xB30 ++#define ODM_REG_RSSI_CTRL_11N 0xB38 ++#define ODM_REG_CONFIG_ANTA_11N 0xB68 ++#define ODM_REG_RSSI_BT_11N 0xB9C ++//PAGE C ++#define ODM_REG_OFDM_FA_HOLDC_11N 0xC00 ++#define ODM_REG_RX_PATH_11N 0xC04 ++#define ODM_REG_TRMUX_11N 0xC08 ++#define ODM_REG_OFDM_FA_RSTC_11N 0xC0C ++#define ODM_REG_RXIQI_MATRIX_11N 0xC14 ++#define ODM_REG_TXIQK_MATRIX_LSB1_11N 0xC4C ++#define ODM_REG_IGI_A_11N 0xC50 ++#define ODM_REG_ANTDIV_PARA2_11N 0xC54 ++#define ODM_REG_IGI_B_11N 0xC58 ++#define ODM_REG_ANTDIV_PARA3_11N 0xC5C ++#define ODM_REG_BB_PWR_SAV2_11N 0xC70 ++#define ODM_REG_RX_OFF_11N 0xC7C ++#define ODM_REG_TXIQK_MATRIXA_11N 0xC80 ++#define ODM_REG_TXIQK_MATRIXB_11N 0xC88 ++#define ODM_REG_TXIQK_MATRIXA_LSB2_11N 0xC94 ++#define ODM_REG_TXIQK_MATRIXB_LSB2_11N 0xC9C ++#define ODM_REG_RXIQK_MATRIX_LSB_11N 0xCA0 ++#define ODM_REG_ANTDIV_PARA1_11N 0xCA4 ++#define ODM_REG_OFDM_FA_TYPE1_11N 0xCF0 ++//PAGE D ++#define ODM_REG_OFDM_FA_RSTD_11N 0xD00 ++#define ODM_REG_OFDM_FA_TYPE2_11N 0xDA0 ++#define ODM_REG_OFDM_FA_TYPE3_11N 0xDA4 ++#define ODM_REG_OFDM_FA_TYPE4_11N 0xDA8 ++//PAGE E ++#define ODM_REG_TXAGC_A_6_18_11N 0xE00 ++#define ODM_REG_TXAGC_A_24_54_11N 0xE04 ++#define ODM_REG_TXAGC_A_1_MCS32_11N 0xE08 ++#define ODM_REG_TXAGC_A_MCS0_3_11N 0xE10 ++#define ODM_REG_TXAGC_A_MCS4_7_11N 0xE14 ++#define ODM_REG_TXAGC_A_MCS8_11_11N 0xE18 ++#define ODM_REG_TXAGC_A_MCS12_15_11N 0xE1C ++#define ODM_REG_FPGA0_IQK_11N 0xE28 ++#define ODM_REG_TXIQK_TONE_A_11N 0xE30 ++#define ODM_REG_RXIQK_TONE_A_11N 0xE34 ++#define ODM_REG_TXIQK_PI_A_11N 0xE38 ++#define ODM_REG_RXIQK_PI_A_11N 0xE3C ++#define ODM_REG_TXIQK_11N 0xE40 ++#define ODM_REG_RXIQK_11N 0xE44 ++#define ODM_REG_IQK_AGC_PTS_11N 0xE48 ++#define ODM_REG_IQK_AGC_RSP_11N 0xE4C ++#define ODM_REG_BLUETOOTH_11N 0xE6C ++#define ODM_REG_RX_WAIT_CCA_11N 0xE70 ++#define ODM_REG_TX_CCK_RFON_11N 0xE74 ++#define ODM_REG_TX_CCK_BBON_11N 0xE78 ++#define ODM_REG_OFDM_RFON_11N 0xE7C ++#define ODM_REG_OFDM_BBON_11N 0xE80 ++#define ODM_REG_TX2RX_11N 0xE84 ++#define ODM_REG_TX2TX_11N 0xE88 ++#define ODM_REG_RX_CCK_11N 0xE8C ++#define ODM_REG_RX_OFDM_11N 0xED0 ++#define ODM_REG_RX_WAIT_RIFS_11N 0xED4 ++#define ODM_REG_RX2RX_11N 0xED8 ++#define ODM_REG_STANDBY_11N 0xEDC ++#define ODM_REG_SLEEP_11N 0xEE0 ++#define ODM_REG_PMPD_ANAEN_11N 0xEEC ++ ++ ++ ++ ++ ++ ++ ++//2 MAC REG LIST ++#define ODM_REG_BB_RST_11N 0x02 ++#define ODM_REG_ANTSEL_PIN_11N 0x4C ++#define ODM_REG_EARLY_MODE_11N 0x4D0 ++#define ODM_REG_RSSI_MONITOR_11N 0x4FE ++#define ODM_REG_EDCA_VO_11N 0x500 ++#define ODM_REG_EDCA_VI_11N 0x504 ++#define ODM_REG_EDCA_BE_11N 0x508 ++#define ODM_REG_EDCA_BK_11N 0x50C ++#define ODM_REG_TXPAUSE_11N 0x522 ++#define ODM_REG_RESP_TX_11N 0x6D8 ++#define ODM_REG_ANT_TRAIN_PARA1_11N 0x7b0 ++#define ODM_REG_ANT_TRAIN_PARA2_11N 0x7b4 ++ ++ ++//DIG Related ++#define ODM_BIT_IGI_11N 0x0000007F ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_debug.c b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_debug.c +new file mode 100644 +index 00000000..7db60cf5 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_debug.c +@@ -0,0 +1,627 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++//============================================================ ++// include files ++//============================================================ ++ ++#include "odm_precomp.h" ++ ++VOID ++ODM_InitDebugSetting( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++pDM_Odm->DebugLevel = ODM_DBG_TRACE; ++ ++pDM_Odm->DebugComponents = ++\ ++#if DBG ++//BB Functions ++// ODM_COMP_DIG | ++// ODM_COMP_RA_MASK | ++// ODM_COMP_DYNAMIC_TXPWR | ++// ODM_COMP_FA_CNT | ++// ODM_COMP_RSSI_MONITOR | ++// ODM_COMP_CCK_PD | ++// ODM_COMP_ANT_DIV | ++// ODM_COMP_PWR_SAVE | ++// ODM_COMP_PWR_TRAIN | ++// ODM_COMP_RATE_ADAPTIVE | ++// ODM_COMP_PATH_DIV | ++// ODM_COMP_DYNAMIC_PRICCA | ++// ODM_COMP_RXHP | ++ ++//MAC Functions ++// ODM_COMP_EDCA_TURBO | ++// ODM_COMP_EARLY_MODE | ++//RF Functions ++// ODM_COMP_TX_PWR_TRACK | ++// ODM_COMP_RX_GAIN_TRACK | ++// ODM_COMP_CALIBRATION | ++//Common ++// ODM_COMP_COMMON | ++// ODM_COMP_INIT | ++#endif ++ 0; ++} ++ ++#if 0 ++/*------------------Declare variable----------------------- ++// Define debug flag array for common debug print macro. */ ++u4Byte ODM_DBGP_Type[ODM_DBGP_TYPE_MAX]; ++ ++/* Define debug print header for every service module. */ ++ODM_DBGP_HEAD_T ODM_DBGP_Head; ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: DBGP_Flag_Init ++ * ++ * Overview: Refresh all debug print control flag content to zero. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 10/20/2006 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++extern void ODM_DBGP_Flag_Init(void) ++{ ++ u1Byte i; ++ ++ for (i = 0; i < ODM_DBGP_TYPE_MAX; i++) ++ { ++ ODM_DBGP_Type[i] = 0; ++ } ++ ++#ifndef ADSL_AP_BUILD_WORKAROUND ++#if DBG ++ // 2010/06/02 MH Free build driver can not out any debug message!!! ++ // Init Debug flag enable condition ++ ++ ODM_DBGP_Type[FINIT] = \ ++// INIT_EEPROM | ++// INIT_TxPower | ++// INIT_IQK | ++// INIT_RF | ++ 0; ++ ++ ODM_DBGP_Type[FDM] = \ ++// WA_IOT | ++// DM_PWDB | ++// DM_Monitor | ++// DM_DIG | ++// DM_EDCA_Turbo | ++// DM_BT30 | ++ 0; ++ ++ ODM_DBGP_Type[FIOCTL] = \ ++// IOCTL_IRP | ++// IOCTL_IRP_DETAIL | ++// IOCTL_IRP_STATISTICS | ++// IOCTL_IRP_HANDLE | ++// IOCTL_BT_HCICMD | ++// IOCTL_BT_HCICMD_DETAIL | ++// IOCTL_BT_HCICMD_EXT | ++// IOCTL_BT_EVENT | ++// IOCTL_BT_EVENT_DETAIL | ++// IOCTL_BT_EVENT_PERIODICAL | ++// IOCTL_BT_TX_ACLDATA | ++// IOCTL_BT_TX_ACLDATA_DETAIL | ++// IOCTL_BT_RX_ACLDATA | ++// IOCTL_BT_RX_ACLDATA_DETAIL | ++// IOCTL_BT_TP | ++// IOCTL_STATE | ++// IOCTL_BT_LOGO | ++// IOCTL_CALLBACK_FUN | ++// IOCTL_PARSE_BT_PKT | ++ 0; ++ ++ ODM_DBGP_Type[FBT] = \ ++// BT_TRACE | ++ 0; ++ ++ ODM_DBGP_Type[FEEPROM] = \ ++// EEPROM_W | ++// EFUSE_PG | ++// EFUSE_READ_ALL | ++// EFUSE_ANALYSIS | ++// EFUSE_PG_DETAIL | ++ 0; ++ ++ ODM_DBGP_Type[FDBG_CTRL] = \ ++// DBG_CTRL_TRACE | ++// DBG_CTRL_INBAND_NOISE | ++ 0; ++ ++ // 2011/07/20 MH Add for short cut ++ ODM_DBGP_Type[FSHORT_CUT] = \ ++// SHCUT_TX | ++// SHCUT_RX | ++ 0; ++ ++#endif ++#endif ++ /* Define debug header of every service module. */ ++ //ODM_DBGP_Head.pMANS = "\n\r[MANS] "; ++ //ODM_DBGP_Head.pRTOS = "\n\r[RTOS] "; ++ //ODM_DBGP_Head.pALM = "\n\r[ALM] "; ++ //ODM_DBGP_Head.pPEM = "\n\r[PEM] "; ++ //ODM_DBGP_Head.pCMPK = "\n\r[CMPK] "; ++ //ODM_DBGP_Head.pRAPD = "\n\r[RAPD] "; ++ //ODM_DBGP_Head.pTXPB = "\n\r[TXPB] "; ++ //ODM_DBGP_Head.pQUMG = "\n\r[QUMG] "; ++ ++} /* DBGP_Flag_Init */ ++ ++#endif ++ ++ ++#if 0 ++u4Byte GlobalDebugLevel = DBG_LOUD; ++// ++// 2009/06/22 MH Allow Fre build to print none debug info at init time. ++// ++#if DBG ++u8Byte GlobalDebugComponents = \ ++// COMP_TRACE | ++// COMP_DBG | ++// COMP_INIT | ++// COMP_OID_QUERY | ++// COMP_OID_SET | ++// COMP_RECV | ++// COMP_SEND | ++// COMP_IO | ++// COMP_POWER | ++// COMP_MLME | ++// COMP_SCAN | ++// COMP_SYSTEM | ++// COMP_SEC | ++// COMP_AP | ++// COMP_TURBO | ++// COMP_QOS | ++// COMP_AUTHENTICATOR | ++// COMP_BEACON | ++// COMP_ANTENNA | ++// COMP_RATE | ++// COMP_EVENTS | ++// COMP_FPGA | ++// COMP_RM | ++// COMP_MP | ++// COMP_RXDESC | ++// COMP_CKIP | ++// COMP_DIG | ++// COMP_TXAGC | ++// COMP_HIPWR | ++// COMP_HALDM | ++// COMP_RSNA | ++// COMP_INDIC | ++// COMP_LED | ++// COMP_RF | ++// COMP_DUALMACSWITCH | ++// COMP_EASY_CONCURRENT | ++ ++//1!!!!!!!!!!!!!!!!!!!!!!!!!!! ++//1//1Attention Please!!!<11n or 8190 specific code should be put below this line> ++//1!!!!!!!!!!!!!!!!!!!!!!!!!!! ++ ++// COMP_HT | ++// COMP_POWER_TRACKING | ++// COMP_RX_REORDER | ++// COMP_AMSDU | ++// COMP_WPS | ++// COMP_RATR | ++// COMP_RESET | ++// COMP_CMD | ++// COMP_EFUSE | ++// COMP_MESH_INTERWORKING | ++// COMP_CCX | ++// COMP_IOCTL | ++// COMP_GP | ++// COMP_TXAGG | ++// COMP_BB_POWERSAVING | ++// COMP_SWAS | ++// COMP_P2P | ++// COMP_MUX | ++// COMP_FUNC | ++// COMP_TDLS | ++// COMP_OMNIPEEK | ++// COMP_PSD | ++ 0; ++ ++ ++#else ++#define FuncEntry ++#define FuncExit ++u8Byte GlobalDebugComponents = 0; ++#endif ++ ++#if (RT_PLATFORM==PLATFORM_LINUX) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) ++EXPORT_SYMBOL(GlobalDebugComponents); ++EXPORT_SYMBOL(GlobalDebugLevel); ++#endif ++#endif ++ ++/*------------------Declare variable----------------------- ++// Define debug flag array for common debug print macro. */ ++u4Byte DBGP_Type[DBGP_TYPE_MAX]; ++ ++/* Define debug print header for every service module. */ ++DBGP_HEAD_T DBGP_Head; ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: DBGP_Flag_Init ++ * ++ * Overview: Refresh all debug print control flag content to zero. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 10/20/2006 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++extern void DBGP_Flag_Init(void) ++{ ++ u1Byte i; ++ ++ for (i = 0; i < DBGP_TYPE_MAX; i++) ++ { ++ DBGP_Type[i] = 0; ++ } ++ ++#if DBG ++ // 2010/06/02 MH Free build driver can not out any debug message!!! ++ // Init Debug flag enable condition ++ ++ DBGP_Type[FINIT] = \ ++// INIT_EEPROM | ++// INIT_TxPower | ++// INIT_IQK | ++// INIT_RF | ++ 0; ++ ++ DBGP_Type[FDM] = \ ++// WA_IOT | ++// DM_PWDB | ++// DM_Monitor | ++// DM_DIG | ++// DM_EDCA_Turbo | ++// DM_BT30 | ++ 0; ++ ++ DBGP_Type[FIOCTL] = \ ++// IOCTL_IRP | ++// IOCTL_IRP_DETAIL | ++// IOCTL_IRP_STATISTICS | ++// IOCTL_IRP_HANDLE | ++// IOCTL_BT_HCICMD | ++// IOCTL_BT_HCICMD_DETAIL | ++// IOCTL_BT_HCICMD_EXT | ++// IOCTL_BT_EVENT | ++// IOCTL_BT_EVENT_DETAIL | ++// IOCTL_BT_EVENT_PERIODICAL | ++// IOCTL_BT_TX_ACLDATA | ++// IOCTL_BT_TX_ACLDATA_DETAIL | ++// IOCTL_BT_RX_ACLDATA | ++// IOCTL_BT_RX_ACLDATA_DETAIL | ++// IOCTL_BT_TP | ++// IOCTL_STATE | ++// IOCTL_BT_LOGO | ++// IOCTL_CALLBACK_FUN | ++// IOCTL_PARSE_BT_PKT | ++ 0; ++ ++ DBGP_Type[FBT] = \ ++// BT_TRACE | ++ 0; ++ ++ DBGP_Type[FEEPROM] = \ ++// EEPROM_W | ++// EFUSE_PG | ++// EFUSE_READ_ALL | ++// EFUSE_ANALYSIS | ++// EFUSE_PG_DETAIL | ++ 0; ++ ++ DBGP_Type[FDBG_CTRL] = \ ++// DBG_CTRL_TRACE | ++// DBG_CTRL_INBAND_NOISE | ++ 0; ++ ++ // 2011/07/20 MH Add for short cut ++ DBGP_Type[FSHORT_CUT] = \ ++// SHCUT_TX | ++// SHCUT_RX | ++ 0; ++ ++#endif ++ /* Define debug header of every service module. */ ++ DBGP_Head.pMANS = "\n\r[MANS] "; ++ DBGP_Head.pRTOS = "\n\r[RTOS] "; ++ DBGP_Head.pALM = "\n\r[ALM] "; ++ DBGP_Head.pPEM = "\n\r[PEM] "; ++ DBGP_Head.pCMPK = "\n\r[CMPK] "; ++ DBGP_Head.pRAPD = "\n\r[RAPD] "; ++ DBGP_Head.pTXPB = "\n\r[TXPB] "; ++ DBGP_Head.pQUMG = "\n\r[QUMG] "; ++ ++} /* DBGP_Flag_Init */ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: DBG_PrintAllFlag ++ * ++ * Overview: Print All debug flag ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 12/10/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++extern void DBG_PrintAllFlag(void) ++{ ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 0 FQoS\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 1 FTX\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 2 FRX\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 3 FSEC\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 4 FMGNT\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 5 FMLME\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 6 FRESOURCE\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 7 FBEACON\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 8 FISR\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 9 FPHY\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 11 FMP\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 12 FPWR\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 13 FDM\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 14 FDBG_CTRL\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 15 FC2H\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 16 FBT\n")); ++} // DBG_PrintAllFlag ++ ++ ++extern void DBG_PrintAllComp(void) ++{ ++ u1Byte i; ++ ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("GlobalDebugComponents Definition\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT0 COMP_TRACE\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT1 COMP_DBG\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT2 COMP_INIT\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT3 COMP_OID_QUERY\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT4 COMP_OID_SET\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT5 COMP_RECV\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT6 COMP_SEND\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT7 COMP_IO\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT8 COMP_POWER\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT9 COMP_MLME\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT10 COMP_SCAN\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT11 COMP_SYSTEM\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT12 COMP_SEC\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT13 COMP_AP\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT14 COMP_TURBO\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT15 COMP_QOS\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT16 COMP_AUTHENTICATOR\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT17 COMP_BEACON\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT18 COMP_BEACON\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT19 COMP_RATE\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT20 COMP_EVENTS\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT21 COMP_FPGA\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT22 COMP_RM\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT23 COMP_MP\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT24 COMP_RXDESC\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT25 COMP_CKIP\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT26 COMP_DIG\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT27 COMP_TXAGC\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT28 COMP_HIPWR\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT29 COMP_HALDM\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT30 COMP_RSNA\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT31 COMP_INDIC\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT32 COMP_LED\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT33 COMP_RF\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT34 COMP_HT\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT35 COMP_POWER_TRACKING\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT36 COMP_POWER_TRACKING\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT37 COMP_AMSDU\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT38 COMP_WPS\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT39 COMP_RATR\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT40 COMP_RESET\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT41 COMP_CMD\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT42 COMP_EFUSE\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT43 COMP_MESH_INTERWORKING\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT43 COMP_CCX\n")); ++ ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("GlobalDebugComponents = %"i64fmt"x\n", GlobalDebugComponents)); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("Enable DBG COMP =")); ++ for (i = 0; i < 64; i++) ++ { ++ if (GlobalDebugComponents & ((u8Byte)0x1 << i) ) ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT%02d |\n", i)); ++ } ++ } ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("\n")); ++ ++} // DBG_PrintAllComp ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: DBG_PrintFlagEvent ++ * ++ * Overview: Print dedicated debug flag event ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 12/10/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++extern void DBG_PrintFlagEvent(u1Byte DbgFlag) ++{ ++ switch(DbgFlag) ++ { ++ case FQoS: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 QoS_INIT\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 QoS_VISTA\n")); ++ break; ++ ++ case FTX: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 TX_DESC\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 TX_DESC_TID\n")); ++ break; ++ ++ case FRX: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 RX_DATA\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 RX_PHY_STS\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 2 RX_PHY_SS\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 3 RX_PHY_SQ\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 4 RX_PHY_ASTS\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 5 RX_ERR_LEN\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 6 RX_DEFRAG\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 7 RX_ERR_RATE\n")); ++ break; ++ ++ case FSEC: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("NA\n")); ++ break; ++ ++ case FMGNT: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("NA\n")); ++ break; ++ ++ case FMLME: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 MEDIA_STS\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 LINK_STS\n")); ++ break; ++ ++ case FRESOURCE: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 OS_CHK\n")); ++ break; ++ ++ case FBEACON: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 BCN_SHOW\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 BCN_PEER\n")); ++ break; ++ ++ case FISR: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 ISR_CHK\n")); ++ break; ++ ++ case FPHY: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 PHY_BBR\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 PHY_BBW\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 2 PHY_RFR\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 3 PHY_RFW\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 4 PHY_MACR\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 5 PHY_MACW\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 6 PHY_ALLR\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 7 PHY_ALLW\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 8 PHY_TXPWR\n")); ++ break; ++ ++ case FMP: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 MP_RX\n")); ++ break; ++ ++ case FEEPROM: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 EEPROM_W\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 EFUSE_PG\n")); ++ break; ++ ++ case FPWR: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 LPS\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 IPS\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 2 PWRSW\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 3 PWRHW\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 4 PWRHAL\n")); ++ break; ++ ++ case FDM: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 WA_IOT\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 DM_PWDB\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 2 DM_Monitor\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 3 DM_DIG\n")); ++ break; ++ ++ case FDBG_CTRL: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 DBG_CTRL_TRACE\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 DBG_CTRL_INBAND_NOISE\n")); ++ break; ++ ++ case FC2H: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 C2H_Summary\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 C2H_PacketData\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 2 C2H_ContentData\n")); ++ break; ++ ++ case FBT: ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 BT_TRACE\n")); ++ ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 BT_RFPoll\n")); ++ break; ++ ++ default: ++ break; ++ } ++ ++} // DBG_PrintFlagEvent ++ ++ ++extern void DBG_DumpMem(const u1Byte DbgComp, ++ const u1Byte DbgLevel, ++ pu1Byte pMem, ++ u2Byte Len) ++{ ++ u2Byte i; ++ ++ for (i=0;i<((Len>>3) + 1);i++) ++ { ++ ODM_RT_TRACE(pDM_Odm,DbgComp, DbgLevel, ("%02X %02X %02X %02X %02X %02X %02X %02X\n", ++ *(pMem+(i*8)), *(pMem+(i*8+1)), *(pMem+(i*8+2)), *(pMem+(i*8+3)), ++ *(pMem+(i*8+4)), *(pMem+(i*8+5)), *(pMem+(i*8+6)), *(pMem+(i*8+7)))); ++ ++ } ++} ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_debug.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_debug.h +new file mode 100644 +index 00000000..f8670c9a +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_debug.h +@@ -0,0 +1,905 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++ ++#ifndef __ODM_DBG_H__ ++#define __ODM_DBG_H__ ++ ++ ++//----------------------------------------------------------------------------- ++// Define the debug levels ++// ++// 1. DBG_TRACE and DBG_LOUD are used for normal cases. ++// So that, they can help SW engineer to develope or trace states changed ++// and also help HW enginner to trace every operation to and from HW, ++// e.g IO, Tx, Rx. ++// ++// 2. DBG_WARNNING and DBG_SERIOUS are used for unusual or error cases, ++// which help us to debug SW or HW. ++// ++//----------------------------------------------------------------------------- ++// ++// Never used in a call to ODM_RT_TRACE()! ++// ++#define ODM_DBG_OFF 1 ++ ++// ++// Fatal bug. ++// For example, Tx/Rx/IO locked up, OS hangs, memory access violation, ++// resource allocation failed, unexpected HW behavior, HW BUG and so on. ++// ++#define ODM_DBG_SERIOUS 2 ++ ++// ++// Abnormal, rare, or unexpeted cases. ++// For example, IRP/Packet/OID canceled, device suprisely unremoved and so on. ++// ++#define ODM_DBG_WARNING 3 ++ ++// ++// Normal case with useful information about current SW or HW state. ++// For example, Tx/Rx descriptor to fill, Tx/Rx descriptor completed status, ++// SW protocol state change, dynamic mechanism state change and so on. ++// ++#define ODM_DBG_LOUD 4 ++ ++// ++// Normal case with detail execution flow or information. ++// ++#define ODM_DBG_TRACE 5 ++ ++//----------------------------------------------------------------------------- ++// Define the tracing components ++// ++//----------------------------------------------------------------------------- ++//BB Functions ++#define ODM_COMP_DIG BIT0 ++#define ODM_COMP_RA_MASK BIT1 ++#define ODM_COMP_DYNAMIC_TXPWR BIT2 ++#define ODM_COMP_FA_CNT BIT3 ++#define ODM_COMP_RSSI_MONITOR BIT4 ++#define ODM_COMP_CCK_PD BIT5 ++#define ODM_COMP_ANT_DIV BIT6 ++#define ODM_COMP_PWR_SAVE BIT7 ++#define ODM_COMP_PWR_TRAIN BIT8 ++#define ODM_COMP_RATE_ADAPTIVE BIT9 ++#define ODM_COMP_PATH_DIV BIT10 ++#define ODM_COMP_PSD BIT11 ++#define ODM_COMP_DYNAMIC_PRICCA BIT12 ++#define ODM_COMP_RXHP BIT13 ++//MAC Functions ++#define ODM_COMP_EDCA_TURBO BIT16 ++#define ODM_COMP_EARLY_MODE BIT17 ++//RF Functions ++#define ODM_COMP_TX_PWR_TRACK BIT24 ++#define ODM_COMP_RX_GAIN_TRACK BIT25 ++#define ODM_COMP_CALIBRATION BIT26 ++//Common Functions ++#define ODM_COMP_COMMON BIT30 ++#define ODM_COMP_INIT BIT31 ++ ++/*------------------------Export Marco Definition---------------------------*/ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++#define RT_PRINTK DbgPrint ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #define DbgPrint printk ++ #define RT_PRINTK(fmt, args...) DbgPrint( "%s(): " fmt, __FUNCTION__, ## args); ++#else ++ #define DbgPrint panic_printk ++#define RT_PRINTK(fmt, args...) DbgPrint( "%s(): " fmt, __FUNCTION__, ## args); ++#endif ++ ++#ifndef ASSERT ++ #define ASSERT(expr) ++#endif ++ ++#if DBG ++#define ODM_RT_TRACE(pDM_Odm, comp, level, fmt) \ ++ if(((comp) & pDM_Odm->DebugComponents) && (level <= pDM_Odm->DebugLevel)) \ ++ { \ ++ if(pDM_Odm->SupportICType == ODM_RTL8192C) \ ++ DbgPrint("[ODM-92C] "); \ ++ else if(pDM_Odm->SupportICType == ODM_RTL8192D) \ ++ DbgPrint("[ODM-92D] "); \ ++ else if(pDM_Odm->SupportICType == ODM_RTL8723A) \ ++ DbgPrint("[ODM-8723A] "); \ ++ else if(pDM_Odm->SupportICType == ODM_RTL8188E) \ ++ DbgPrint("[ODM-8188E] "); \ ++ else if(pDM_Odm->SupportICType == ODM_RTL8812) \ ++ DbgPrint("[ODM-8812] "); \ ++ else if(pDM_Odm->SupportICType == ODM_RTL8821) \ ++ DbgPrint("[ODM-8821] "); \ ++ RT_PRINTK fmt; \ ++ } ++ ++#define ODM_RT_TRACE_F(pDM_Odm, comp, level, fmt) \ ++ if(((comp) & pDM_Odm->DebugComponents) && (level <= pDM_Odm->DebugLevel)) \ ++ { \ ++ RT_PRINTK fmt; \ ++ } ++ ++#define ODM_RT_ASSERT(pDM_Odm, expr, fmt) \ ++ if(!(expr)) { \ ++ DbgPrint( "Assertion failed! %s at ......\n", #expr); \ ++ DbgPrint( " ......%s,%s,line=%d\n",__FILE__,__FUNCTION__,__LINE__); \ ++ RT_PRINTK fmt; \ ++ ASSERT(FALSE); \ ++ } ++#define ODM_dbg_enter() { DbgPrint("==> %s\n", __FUNCTION__); } ++#define ODM_dbg_exit() { DbgPrint("<== %s\n", __FUNCTION__); } ++#define ODM_dbg_trace(str) { DbgPrint("%s:%s\n", __FUNCTION__, str); } ++ ++#define ODM_PRINT_ADDR(pDM_Odm, comp, level, title_str, ptr) \ ++ if(((comp) & pDM_Odm->DebugComponents) && (level <= pDM_Odm->DebugLevel)) \ ++ { \ ++ int __i; \ ++ pu1Byte __ptr = (pu1Byte)ptr; \ ++ DbgPrint("[ODM] "); \ ++ DbgPrint(title_str); \ ++ DbgPrint(" "); \ ++ for( __i=0; __i<6; __i++ ) \ ++ DbgPrint("%02X%s", __ptr[__i], (__i==5)?"":"-"); \ ++ DbgPrint("\n"); \ ++ } ++#else ++#define ODM_RT_TRACE(pDM_Odm, comp, level, fmt) ++#define ODM_RT_TRACE_F(pDM_Odm, comp, level, fmt) ++#define ODM_RT_ASSERT(pDM_Odm, expr, fmt) ++#define ODM_dbg_enter() ++#define ODM_dbg_exit() ++#define ODM_dbg_trace(str) ++#define ODM_PRINT_ADDR(pDM_Odm, comp, level, title_str, ptr) ++#endif ++ ++ ++VOID ++ODM_InitDebugSetting( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++ ++ ++#if 0 ++#if DBG ++#define DbgPrint printk ++ ++#define PRINT_DATA(_TitleString, _HexData, _HexDataLen) \ ++ { \ ++ char *szTitle = _TitleString; \ ++ pu1Byte pbtHexData = _HexData; \ ++ u4Byte u4bHexDataLen = _HexDataLen; \ ++ u4Byte __i; \ ++ DbgPrint("%s", szTitle); \ ++ for (__i=0;__i=' ' &&_ch<='~' ) // I want to see ASCII 33 to 126 only. Otherwise, I print '?'. Annie, 2005-11-22. ++ ++#define RT_PRINT_STR(_Comp, _Level, _TitleString, _Ptr, _Len) \ ++ if(((_Comp) & ODM_GlobalDebugComponents) && (_Level <= ODM_GlobalDebugLevel)) \ ++ { \ ++ int __i; \ ++ u1Byte buffer[MAX_STR_LEN]; \ ++ int length = (_Len\n", _Len, buffer); \ ++ } ++ ++#else // of #if DBG ++#define DbgPrint(...) ++#define PRINT_DATA(_TitleString, _HexData, _HexDataLen) ++#define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData, _HexDataLen) ++#define RT_PRINT_ADDR(_Comp, _Level, _TitleString, _Ptr) ++#define RT_PRINT_ADDRS(_Comp, _Level, _TitleString, _Ptr, _AddNum) ++#define RT_PRINT_STR(_Comp, _Level, _TitleString, _Ptr, _Len) ++#endif // of #if DBG ++ ++#endif ++ ++ ++#if 0 ++/* Define debug print header for every service module.*/ ++typedef struct tag_ODM_DBGP_Service_Module_Header_Name_Structure ++{ ++ const char *pMANS; ++ const char *pRTOS; ++ const char *pALM; ++ const char *pPEM; ++ const char *pCMPK; ++ const char *pRAPD; ++ const char *pTXPB; ++ const char *pQUMG; ++}ODM_DBGP_HEAD_T; ++ ++ ++/* Define different debug flag for dedicated service modules in debug flag array. */ ++// Each module has independt 32 bit debug flag you cnn define the flag as yout require. ++typedef enum tag_ODM_DBGP_Flag_Type_Definition ++{ ++ ODM_FTX = 0, ++ ODM_FRX , ++ ODM_FPHY , ++ ODM_FPWR , ++ ODM_FDM , ++ ODM_FC2H , ++ ODM_FBT , ++ ODM_DBGP_TYPE_MAX ++}ODM_DBGP_FLAG_E; ++ ++ ++// Define TX relative debug bit --> FTX ++#define ODM_TX_DESC BIT0 ++#define ODM_TX_DESC_TID BIT1 ++#define ODM_TX_PATH BIT2 ++ ++// Define RX relative debug bit --> FRX ++#define ODM_RX_DATA BIT0 ++#define ODM_RX_PHY_STS BIT1 ++#define ODM_RX_PHY_SS BIT2 ++#define ODM_RX_PHY_SQ BIT3 ++#define ODM_RX_PHY_ASTS BIT4 ++#define ODM_RX_ERR_LEN BIT5 ++#define ODM_RX_DEFRAG BIT6 ++#define ODM_RX_ERR_RATE BIT7 ++#define ODM_RX_PATH BIT8 ++#define ODM_RX_BEACON BIT9 ++ ++// Define PHY-BB/RF/MAC check module bit --> FPHY ++#define ODM_PHY_BBR BIT0 ++#define ODM_PHY_BBW BIT1 ++#define ODM_PHY_RFR BIT2 ++#define ODM_PHY_RFW BIT3 ++#define ODM_PHY_MACR BIT4 ++#define ODM_PHY_MACW BIT5 ++#define ODM_PHY_ALLR BIT6 ++#define ODM_PHY_ALLW BIT7 ++#define ODM_PHY_TXPWR BIT8 ++#define ODM_PHY_PWRDIFF BIT9 ++#define ODM_PHY_SICR BIT10 ++#define ODM_PHY_SICW BIT11 ++ ++ ++ ++ ++extern u4Byte ODM_GlobalDebugLevel; ++ ++ ++#if DBG ++extern u8Byte ODM_GlobalDebugComponents; ++#endif ++#endif ++#if 0 ++ ++//----------------------------------------------------------------------------- ++// Define the debug levels ++// ++// 1. DBG_TRACE and DBG_LOUD are used for normal cases. ++// So that, they can help SW engineer to develope or trace states changed ++// and also help HW enginner to trace every operation to and from HW, ++// e.g IO, Tx, Rx. ++// ++// 2. DBG_WARNNING and DBG_SERIOUS are used for unusual or error cases, ++// which help us to debug SW or HW. ++// ++//----------------------------------------------------------------------------- ++// ++// Never used in a call to ODM_RT_TRACE(pDM_Odm,)! ++// ++#define DBG_OFF 0 ++ ++// ++// Deprecated! Don't use it! ++// TODO: fix related debug message! ++// ++//#define DBG_SEC 1 ++ ++// ++// Fatal bug. ++// For example, Tx/Rx/IO locked up, OS hangs, memory access violation, ++// resource allocation failed, unexpected HW behavior, HW BUG and so on. ++// ++#define DBG_SERIOUS 2 ++ ++// ++// Abnormal, rare, or unexpeted cases. ++// For example, IRP/Packet/OID canceled, device suprisely unremoved and so on. ++// ++#define DBG_WARNING 3 ++ ++// ++// Normal case with useful information about current SW or HW state. ++// For example, Tx/Rx descriptor to fill, Tx/Rx descriptor completed status, ++// SW protocol state change, dynamic mechanism state change and so on. ++// ++#define DBG_LOUD 4 ++ ++// ++// Normal case with detail execution flow or information. ++// ++#define DBG_TRACE 5 ++ ++ ++ ++//----------------------------------------------------------------------------- ++// Define the tracing components ++// ++//----------------------------------------------------------------------------- ++#define COMP_TRACE BIT0 // For function call tracing. ++#define COMP_DBG BIT1 // Only for temporary debug message. ++#define COMP_INIT BIT2 // during driver initialization / halt / reset. ++#define COMP_OID_QUERY BIT3 // Query OID. ++#define COMP_OID_SET BIT4 // Set OID. ++#define COMP_RECV BIT5 // Reveive part data path. ++#define COMP_SEND BIT6 // Send part path. ++#define COMP_IO BIT7 // I/O Related. Added by Annie, 2006-03-02. ++#define COMP_POWER BIT8 // 802.11 Power Save mode or System/Device Power state related. ++#define COMP_MLME BIT9 // 802.11 link related: join/start BSS, leave BSS. ++#define COMP_SCAN BIT10 // For site survey. ++#define COMP_SYSTEM BIT11 // For general platform function. ++#define COMP_SEC BIT12 // For Security. ++#define COMP_AP BIT13 // For AP mode related. ++#define COMP_TURBO BIT14 // For Turbo Mode related. By Annie, 2005-10-21. ++#define COMP_QOS BIT15 // For QoS. ++#define COMP_AUTHENTICATOR BIT16 // For AP mode Authenticator. Added by Annie, 2006-01-30. ++#define COMP_BEACON BIT17 // For Beacon related, by rcnjko. ++#define COMP_ANTENNA BIT18 // For Antenna diversity related, by rcnjko. ++#define COMP_RATE BIT19 // For Rate Adaptive mechanism, 2006.07.02, by rcnjko. #define COMP_EVENTS 0x00000080 // Event handling ++#define COMP_EVENTS BIT20 // Event handling ++#define COMP_FPGA BIT21 // For FPGA verfication ++#define COMP_RM BIT22 // For Radio Measurement. ++#define COMP_MP BIT23 // For mass production test, by shien chang, 2006.07.13 ++#define COMP_RXDESC BIT24 // Show Rx desc information for SD3 debug. Added by Annie, 2006-07-15. ++#define COMP_CKIP BIT25 // For CCX 1 S13: CKIP. Added by Annie, 2006-08-14. ++#define COMP_DIG BIT26 // For DIG, 2006.09.25, by rcnjko. ++#define COMP_TXAGC BIT27 // For Tx power, 060928, by rcnjko. ++#define COMP_HIPWR BIT28 // For High Power Mechanism, 060928, by rcnjko. ++#define COMP_HALDM BIT29 // For HW Dynamic Mechanism, 061010, by rcnjko. ++#define COMP_RSNA BIT30 // For RSNA IBSS , 061201, by CCW. ++#define COMP_INDIC BIT31 // For link indication ++#define COMP_LED BIT32 // For LED. ++#define COMP_RF BIT33 // For RF. ++//1!!!!!!!!!!!!!!!!!!!!!!!!!!! ++//1//1Attention Please!!!<11n or 8190 specific code should be put below this line> ++//1!!!!!!!!!!!!!!!!!!!!!!!!!!! ++ ++#define COMP_HT BIT34 // For 802.11n HT related information. by Emily 2006-8-11 ++#define COMP_POWER_TRACKING BIT35 //FOR 8190 TX POWER TRACKING ++#define COMP_RX_REORDER BIT36 // 8190 Rx Reorder ++#define COMP_AMSDU BIT37 // For A-MSDU Debugging ++#define COMP_WPS BIT38 //WPS Debug Message ++#define COMP_RATR BIT39 ++#define COMP_RESET BIT40 ++// For debug command to print on dbgview!! ++#define COMP_CMD BIT41 ++#define COMP_EFUSE BIT42 ++#define COMP_MESH_INTERWORKING BIT43 ++#define COMP_CCX BIT44 //CCX Debug Flag ++#define COMP_IOCTL BIT45 // IO Control ++#define COMP_GP BIT46 // For generic parser. ++#define COMP_TXAGG BIT47 ++#define COMP_HVL BIT48 // For Ndis 6.2 Context Swirch and Hardware Virtualiztion Layer ++#define COMP_TEST BIT49 ++#define COMP_BB_POWERSAVING BIT50 ++#define COMP_SWAS BIT51 // For SW Antenna Switch ++#define COMP_P2P BIT52 ++#define COMP_MUX BIT53 ++#define COMP_FUNC BIT54 ++#define COMP_TDLS BIT55 ++#define COMP_OMNIPEEK BIT56 ++#define COMP_DUALMACSWITCH BIT60 // 2010/12/27 Add for Dual mac mode debug ++#define COMP_EASY_CONCURRENT BIT61 // 2010/12/27 Add for easy cncurrent mode debug ++#define COMP_PSD BIT63 //2011/3/9 Add for WLAN PSD for BT AFH ++ ++#define COMP_DFS BIT62 ++ ++#define COMP_ALL UINT64_C(0xFFFFFFFFFFFFFFFF) // All components ++// For debug print flag to use ++/*------------------------------Define structure----------------------------*/ ++/* 2007/07/13 MH *//*------For DeBuG Print modeue------*/ ++ ++/* Defnie structure to store different debug flag variable. Every debug flag ++ is a UINT32 integer and you can assign 32 different events. */ ++typedef struct tag_DBGP_Debug_Flag_Structure ++{ ++ u4Byte Mans; /* Main Scheduler module. */ ++ u4Byte Rtos; /* RTOS module. */ ++ u4Byte Alarm; /* Alarm module. */ ++ u4Byte Pm; /* Performance monitor module. */ ++}DBGP_FLAG_T; ++ ++/* Define debug print header for every service module.*/ ++typedef struct tag_DBGP_Service_Module_Header_Name_Structure ++{ ++ const char *pMANS; ++ const char *pRTOS; ++ const char *pALM; ++ const char *pPEM; ++ const char *pCMPK; ++ const char *pRAPD; ++ const char *pTXPB; ++ const char *pQUMG; ++}DBGP_HEAD_T; ++ ++ ++/* Define different debug flag for dedicated service modules in debug flag array. */ ++// Each module has independt 32 bit debug flag you cnn define the flag as yout require. ++typedef enum tag_DBGP_Flag_Type_Definition ++{ ++ FQoS = 0, ++ FTX = 1, ++ FRX = 2, ++ FSEC = 3, ++ FMGNT = 4, ++ FMLME = 5, ++ FRESOURCE = 6, ++ FBEACON = 7, ++ FISR = 8, ++ FPHY = 9, ++ FMP = 10, ++ FEEPROM = 11, ++ FPWR = 12, ++ FDM = 13, ++ FDBG_CTRL = 14, ++ FC2H = 15, ++ FBT = 16, ++ FINIT = 17, ++ FIOCTL = 18, ++ FSHORT_CUT = 19, ++ DBGP_TYPE_MAX ++}DBGP_FLAG_E; ++ ++ ++// Define Qos Relative debug flag bit --> FQoS ++#define QoS_INIT BIT0 ++#define QoS_VISTA BIT1 ++ ++// Define TX relative debug bit --> FTX ++#define TX_DESC BIT0 ++#define TX_DESC_TID BIT1 ++#define TX_PATH BIT2 ++ ++// Define RX relative debug bit --> FRX ++#define RX_DATA BIT0 ++#define RX_PHY_STS BIT1 ++#define RX_PHY_SS BIT2 ++#define RX_PHY_SQ BIT3 ++#define RX_PHY_ASTS BIT4 ++#define RX_ERR_LEN BIT5 ++#define RX_DEFRAG BIT6 ++#define RX_ERR_RATE BIT7 ++#define RX_PATH BIT8 ++#define RX_BEACON BIT9 ++ ++// Define Security relative debug bit --> FSEC ++ ++// Define MGNT relative debug bit --> FMGNT ++ ++// Define MLME relative debug bit --> FMLME ++#define MEDIA_STS BIT0 ++#define LINK_STS BIT1 ++ ++// Define OS resource check module bit --> FRESOURCE ++#define OS_CHK BIT0 ++ ++// Define beacon content check module bit --> FBEACON ++#define BCN_SHOW BIT0 ++#define BCN_PEER BIT1 ++ ++// Define ISR/IMR check module bit --> FISR ++#define ISR_CHK BIT0 ++ ++// Define PHY-BB/RF/MAC check module bit --> FPHY ++#define PHY_BBR BIT0 ++#define PHY_BBW BIT1 ++#define PHY_RFR BIT2 ++#define PHY_RFW BIT3 ++#define PHY_MACR BIT4 ++#define PHY_MACW BIT5 ++#define PHY_ALLR BIT6 ++#define PHY_ALLW BIT7 ++#define PHY_TXPWR BIT8 ++#define PHY_PWRDIFF BIT9 ++#define PHY_SICR BIT10 ++#define PHY_SICW BIT11 ++ ++// Define MPT driver check module bit --> FMP ++#define MP_RX BIT0 ++#define MP_SWICH_CH BIT1 ++ ++// Define EEPROM and EFUSE check module bit --> FEEPROM ++#define EEPROM_W BIT0 ++#define EFUSE_PG BIT1 ++#define EFUSE_READ_ALL BIT2 ++#define EFUSE_ANALYSIS BIT3 ++#define EFUSE_PG_DETAIL BIT4 ++ ++// Define power save check module bit --> FPWR ++#define LPS BIT0 ++#define IPS BIT1 ++#define PWRSW BIT2 ++#define PWRHW BIT3 ++#define PWRHAL BIT4 ++ ++// Define Dynamic Mechanism check module bit --> FDM ++#define WA_IOT BIT0 ++#define DM_PWDB BIT1 ++#define DM_Monitor BIT2 ++#define DM_DIG BIT3 ++#define DM_EDCA_Turbo BIT4 ++#define DM_BT30 BIT5 ++ ++// Define Dbg Control module bit --> FDBG_CTRL ++#define DBG_CTRL_TRACE BIT0 ++#define DBG_CTRL_INBAND_NOISE BIT1 ++ ++// Define FW C2H Cmd check module bit --> FC2H ++#define C2H_Summary BIT0 ++#define C2H_PacketData BIT1 ++#define C2H_ContentData BIT2 ++// Define BT Cmd check module bit --> FBT ++#define BT_TRACE BIT0 ++#define BT_RFPoll BIT1 ++ ++// Define init check for module bit --> FINIT ++#define INIT_EEPROM BIT0 ++#define INIT_TxPower BIT1 ++#define INIT_IQK BIT2 ++#define INIT_RF BIT3 ++ ++// Define IOCTL Cmd check module bit --> FIOCTL ++// section 1 : IRP related ++#define IOCTL_IRP BIT0 ++#define IOCTL_IRP_DETAIL BIT1 ++#define IOCTL_IRP_STATISTICS BIT2 ++#define IOCTL_IRP_HANDLE BIT3 ++// section 2 : HCI command/event ++#define IOCTL_BT_HCICMD BIT8 ++#define IOCTL_BT_HCICMD_DETAIL BIT9 ++#define IOCTL_BT_HCICMD_EXT BIT10 ++#define IOCTL_BT_EVENT BIT11 ++#define IOCTL_BT_EVENT_DETAIL BIT12 ++#define IOCTL_BT_EVENT_PERIODICAL BIT13 ++// section 3 : BT tx/rx data and throughput ++#define IOCTL_BT_TX_ACLDATA BIT16 ++#define IOCTL_BT_TX_ACLDATA_DETAIL BIT17 ++#define IOCTL_BT_RX_ACLDATA BIT18 ++#define IOCTL_BT_RX_ACLDATA_DETAIL BIT19 ++#define IOCTL_BT_TP BIT20 ++// section 4 : BT connection state machine. ++#define IOCTL_STATE BIT21 ++#define IOCTL_BT_LOGO BIT22 ++// section 5 : BT function trace ++#define IOCTL_CALLBACK_FUN BIT24 ++#define IOCTL_PARSE_BT_PKT BIT25 ++#define IOCTL_BT_TX_PKT BIT26 ++#define IOCTL_BT_FLAG_MON BIT27 ++ ++// ++// Define init check for module bit --> FSHORT_CUT ++// 2011/07/20 MH Add for short but definition. ++// ++#define SHCUT_TX BIT0 ++#define SHCUT_RX BIT1 ++ ++ ++/* 2007/07/13 MH *//*------For DeBuG Print modeue------*/ ++/*------------------------------Define structure----------------------------*/ ++ ++ ++/*------------------------Export Marco Definition---------------------------*/ ++#if (DM_ODM_SUPPORT_TYPE != ODM_MP) ++#define RT_PRINTK(fmt, args...) printk( "%s(): " fmt, __FUNCTION__, ## args); ++ ++#if DBG ++#define ODM_RT_TRACE(pDM_Odm,comp, level, fmt) \ ++ if(((comp) & GlobalDebugComponents) && (level <= GlobalDebugLevel)) \ ++ { \ ++ RT_PRINTK fmt; \ ++ } ++ ++#define RT_TRACE_F(comp, level, fmt) \ ++ if(((comp) & GlobalDebugComponents) && (level <= GlobalDebugLevel)) \ ++ { \ ++ RT_PRINTK fmt; \ ++ } ++ ++#define RT_ASSERT(expr,fmt) \ ++ if(!(expr)) { \ ++ printk( "Assertion failed! %s at ......\n", #expr); \ ++ printk( " ......%s,%s,line=%d\n",__FILE__,__FUNCTION__,__LINE__); \ ++ } ++#define dbg_enter() { printk("==> %s\n", __FUNCTION__); } ++#define dbg_exit() { printk("<== %s\n", __FUNCTION__); } ++#define dbg_trace(str) { printk("%s:%s\n", __FUNCTION__, str); } ++#else ++#define ODM_RT_TRACE(pDM_Odm,comp, level, fmt) ++#define RT_TRACE_F(comp, level, fmt) ++#define RT_ASSERT(expr, fmt) ++#define dbg_enter() ++#define dbg_exit() ++#define dbg_trace(str) ++#endif ++ ++#if DBG ++#define DbgPrint printk ++ ++#define PRINT_DATA(_TitleString, _HexData, _HexDataLen) \ ++ { \ ++ char *szTitle = _TitleString; \ ++ pu1Byte pbtHexData = _HexData; \ ++ u4Byte u4bHexDataLen = _HexDataLen; \ ++ u4Byte __i; \ ++ DbgPrint("%s", szTitle); \ ++ for (__i=0;__i=' ' &&_ch<='~' ) // I want to see ASCII 33 to 126 only. Otherwise, I print '?'. Annie, 2005-11-22. ++ ++#define RT_PRINT_STR(_Comp, _Level, _TitleString, _Ptr, _Len) \ ++ if(((_Comp) & GlobalDebugComponents) && (_Level <= GlobalDebugLevel)) \ ++ { \ ++ int __i; \ ++ u1Byte buffer[MAX_STR_LEN]; \ ++ int length = (_Len\n", _Len, buffer); \ ++ } ++ ++#else // of #if DBG ++#define DbgPrint(...) ++#define PRINT_DATA(_TitleString, _HexData, _HexDataLen) ++#define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData, _HexDataLen) ++#define RT_PRINT_ADDR(_Comp, _Level, _TitleString, _Ptr) ++#define RT_PRINT_ADDRS(_Comp, _Level, _TitleString, _Ptr, _AddNum) ++#define RT_PRINT_STR(_Comp, _Level, _TitleString, _Ptr, _Len) ++#endif // of #if DBG ++ ++ ++ ++#endif // #if (DM_ODM_SUPPORT_TYPE != ODM_MP) ++ ++#define DEBUG_PRINT 1 ++ ++// Please add new OS's print API by yourself ++ ++//#if (RT_PLATFORM==PLATFORM_WINDOWS) ++#if (DEBUG_PRINT == 1) && DBG ++#define RTPRINT(dbgtype, dbgflag, printstr)\ ++{\ ++ if (DBGP_Type[dbgtype] & dbgflag)\ ++ {\ ++ DbgPrint printstr;\ ++ }\ ++} ++ ++#define RTPRINT_ADDR(dbgtype, dbgflag, printstr, _Ptr)\ ++{\ ++ if (DBGP_Type[dbgtype] & dbgflag)\ ++ {\ ++ int __i; \ ++ pu1Byte ptr = (pu1Byte)_Ptr; \ ++ DbgPrint printstr; \ ++ DbgPrint(" "); \ ++ for( __i=0; __i<6; __i++ ) \ ++ DbgPrint("%02X%s", ptr[__i], (__i==5)?"":"-"); \ ++ DbgPrint("\n"); \ ++ }\ ++} ++ ++#define RTPRINT_DATA(dbgtype, dbgflag, _TitleString, _HexData, _HexDataLen)\ ++{\ ++ if (DBGP_Type[dbgtype] & dbgflag)\ ++ {\ ++ int __i; \ ++ pu1Byte ptr = (pu1Byte)_HexData; \ ++ DbgPrint(_TitleString); \ ++ for( __i=0; __i<(int)_HexDataLen; __i++ ) \ ++ { \ ++ DbgPrint("%02X%s", ptr[__i], (((__i + 1) % 4) == 0)?" ":" ");\ ++ if (((__i + 1) % 16) == 0) DbgPrint("\n");\ ++ } \ ++ DbgPrint("\n"); \ ++ }\ ++} ++#define FuncEntry FunctionIn(COMP_FUNC) ++#define FuncExit FunctionOut(COMP_FUNC) ++ ++#define FunctionIn(_comp) ODM_RT_TRACE(pDM_Odm,(_comp), DBG_LOUD, ("==========> %s\n", __FUNCTION__)) ++#define FunctionOut(_comp) ODM_RT_TRACE(pDM_Odm,(_comp), DBG_LOUD, ("<========== %s\n", __FUNCTION__)) ++ ++ ++#else ++ ++#define DBGP(dbgtype, dbgflag, printstr) ++#define RTPRINT(dbgtype, dbgflag, printstr) ++#define RTPRINT_ADDR(dbgtype, dbgflag, printstr, _Ptr) ++#define RTPRINT_DATA(dbgtype, dbgflag, _TitleString, _HexData, _HexDataLen) ++#define FuncEntry ++#define FuncExit ++#define FunctionIn(_comp) ++#define FunctionOut(_comp) ++#endif ++/*------------------------Export Marco Definition---------------------------*/ ++ ++ ++/*------------------------Export global variable----------------------------*/ ++extern u4Byte DBGP_Type[DBGP_TYPE_MAX]; ++extern DBGP_HEAD_T DBGP_Head; ++ ++/*------------------------Export global variable----------------------------*/ ++ ++ ++/*--------------------------Exported Function prototype---------------------*/ ++extern void DBGP_Flag_Init(void); ++extern void DBG_PrintAllFlag(void); ++extern void DBG_PrintAllComp(void); ++extern void DBG_PrintFlagEvent(u1Byte DbgFlag); ++extern void DBG_DumpMem(const u1Byte DbgComp, ++ const u1Byte DbgLevel, ++ pu1Byte pMem, ++ u2Byte Len); ++ ++/*--------------------------Exported Function prototype---------------------*/ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++extern u4Byte GlobalDebugLevel; ++extern u8Byte GlobalDebugComponents; ++ ++ ++#endif ++ ++ ++#endif // __ODM_DBG_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_interface.c b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_interface.c +new file mode 100644 +index 00000000..7f6dd58b +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_interface.c +@@ -0,0 +1,666 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++//============================================================ ++// include files ++//============================================================ ++ ++#include "odm_precomp.h" ++// ++// ODM IO Relative API. ++// ++ ++u1Byte ++ODM_Read1Byte( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ return RTL_R8(RegAddr); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ return rtw_read8(Adapter,RegAddr); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ return PlatformEFIORead1Byte(Adapter, RegAddr); ++#endif ++ ++} ++ ++ ++u2Byte ++ODM_Read2Byte( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ return RTL_R16(RegAddr); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ return rtw_read16(Adapter,RegAddr); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ return PlatformEFIORead2Byte(Adapter, RegAddr); ++#endif ++ ++} ++ ++ ++u4Byte ++ODM_Read4Byte( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ return RTL_R32(RegAddr); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ return rtw_read32(Adapter,RegAddr); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ return PlatformEFIORead4Byte(Adapter, RegAddr); ++#endif ++ ++} ++ ++ ++VOID ++ODM_Write1Byte( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr, ++ IN u1Byte Data ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ RTL_W8(RegAddr, Data); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ rtw_write8(Adapter,RegAddr, Data); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PlatformEFIOWrite1Byte(Adapter, RegAddr, Data); ++#endif ++ ++} ++ ++ ++VOID ++ODM_Write2Byte( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr, ++ IN u2Byte Data ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ RTL_W16(RegAddr, Data); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ rtw_write16(Adapter,RegAddr, Data); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PlatformEFIOWrite2Byte(Adapter, RegAddr, Data); ++#endif ++ ++} ++ ++ ++VOID ++ODM_Write4Byte( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr, ++ IN u4Byte Data ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ RTL_W32(RegAddr, Data); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ rtw_write32(Adapter,RegAddr, Data); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PlatformEFIOWrite4Byte(Adapter, RegAddr, Data); ++#endif ++ ++} ++ ++ ++VOID ++ODM_SetMACReg( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr, ++ IN u4Byte BitMask, ++ IN u4Byte Data ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ PHY_SetBBReg(pDM_Odm->priv, RegAddr, BitMask, Data); ++#elif(DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_MP)) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PHY_SetBBReg(Adapter, RegAddr, BitMask, Data); ++#endif ++} ++ ++ ++u4Byte ++ODM_GetMACReg( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr, ++ IN u4Byte BitMask ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ return PHY_QueryBBReg(pDM_Odm->priv, RegAddr, BitMask); ++#elif(DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_MP)) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ return PHY_QueryBBReg(Adapter, RegAddr, BitMask); ++#endif ++} ++ ++ ++VOID ++ODM_SetBBReg( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr, ++ IN u4Byte BitMask, ++ IN u4Byte Data ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ PHY_SetBBReg(pDM_Odm->priv, RegAddr, BitMask, Data); ++#elif(DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_MP)) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PHY_SetBBReg(Adapter, RegAddr, BitMask, Data); ++#endif ++} ++ ++ ++u4Byte ++ODM_GetBBReg( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr, ++ IN u4Byte BitMask ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ return PHY_QueryBBReg(pDM_Odm->priv, RegAddr, BitMask); ++#elif(DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_MP)) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ return PHY_QueryBBReg(Adapter, RegAddr, BitMask); ++#endif ++} ++ ++ ++VOID ++ODM_SetRFReg( ++ IN PDM_ODM_T pDM_Odm, ++ IN ODM_RF_RADIO_PATH_E eRFPath, ++ IN u4Byte RegAddr, ++ IN u4Byte BitMask, ++ IN u4Byte Data ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ PHY_SetRFReg(pDM_Odm->priv, eRFPath, RegAddr, BitMask, Data); ++#elif(DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_MP)) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PHY_SetRFReg(Adapter, eRFPath, RegAddr, BitMask, Data); ++#endif ++} ++ ++ ++u4Byte ++ODM_GetRFReg( ++ IN PDM_ODM_T pDM_Odm, ++ IN ODM_RF_RADIO_PATH_E eRFPath, ++ IN u4Byte RegAddr, ++ IN u4Byte BitMask ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ return PHY_QueryRFReg(pDM_Odm->priv, eRFPath, RegAddr, BitMask, 1); ++#elif(DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_MP)) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ return PHY_QueryRFReg(Adapter, eRFPath, RegAddr, BitMask); ++#endif ++} ++ ++ ++ ++ ++// ++// ODM Memory relative API. ++// ++VOID ++ODM_AllocateMemory( ++ IN PDM_ODM_T pDM_Odm, ++ OUT PVOID *pPtr, ++ IN u4Byte length ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ *pPtr = kmalloc(length, GFP_ATOMIC); ++#elif (DM_ODM_SUPPORT_TYPE & ODM_CE ) ++ *pPtr = rtw_zvmalloc(length); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PlatformAllocateMemory(Adapter, pPtr, length); ++#endif ++} ++ ++// length could be ignored, used to detect memory leakage. ++VOID ++ODM_FreeMemory( ++ IN PDM_ODM_T pDM_Odm, ++ OUT PVOID pPtr, ++ IN u4Byte length ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ kfree(pPtr); ++#elif (DM_ODM_SUPPORT_TYPE & ODM_CE ) ++ rtw_vmfree(pPtr, length); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ //PADAPTER Adapter = pDM_Odm->Adapter; ++ PlatformFreeMemory(pPtr, length); ++#endif ++} ++s4Byte ODM_CompareMemory( ++ IN PDM_ODM_T pDM_Odm, ++ IN PVOID pBuf1, ++ IN PVOID pBuf2, ++ IN u4Byte length ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ return memcmp(pBuf1,pBuf2,length); ++#elif (DM_ODM_SUPPORT_TYPE & ODM_CE ) ++ return _rtw_memcmp(pBuf1,pBuf2,length); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ return PlatformCompareMemory(pBuf1,pBuf2,length); ++#endif ++} ++ ++ ++ ++// ++// ODM MISC relative API. ++// ++VOID ++ODM_AcquireSpinLock( ++ IN PDM_ODM_T pDM_Odm, ++ IN RT_SPINLOCK_TYPE type ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ ++#elif (DM_ODM_SUPPORT_TYPE & ODM_CE ) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PlatformAcquireSpinLock(Adapter, type); ++#endif ++} ++VOID ++ODM_ReleaseSpinLock( ++ IN PDM_ODM_T pDM_Odm, ++ IN RT_SPINLOCK_TYPE type ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ ++#elif (DM_ODM_SUPPORT_TYPE & ODM_CE ) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PlatformReleaseSpinLock(Adapter, type); ++#endif ++} ++ ++// ++// Work item relative API. FOr MP driver only~! ++// ++VOID ++ODM_InitializeWorkItem( ++ IN PDM_ODM_T pDM_Odm, ++ IN PRT_WORK_ITEM pRtWorkItem, ++ IN RT_WORKITEM_CALL_BACK RtWorkItemCallback, ++ IN PVOID pContext, ++ IN const char* szID ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PlatformInitializeWorkItem(Adapter, pRtWorkItem, RtWorkItemCallback, pContext, szID); ++#endif ++} ++ ++ ++VOID ++ODM_StartWorkItem( ++ IN PRT_WORK_ITEM pRtWorkItem ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PlatformStartWorkItem(pRtWorkItem); ++#endif ++} ++ ++ ++VOID ++ODM_StopWorkItem( ++ IN PRT_WORK_ITEM pRtWorkItem ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PlatformStopWorkItem(pRtWorkItem); ++#endif ++} ++ ++ ++VOID ++ODM_FreeWorkItem( ++ IN PRT_WORK_ITEM pRtWorkItem ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PlatformFreeWorkItem(pRtWorkItem); ++#endif ++} ++ ++ ++VOID ++ODM_ScheduleWorkItem( ++ IN PRT_WORK_ITEM pRtWorkItem ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PlatformScheduleWorkItem(pRtWorkItem); ++#endif ++} ++ ++ ++VOID ++ODM_IsWorkItemScheduled( ++ IN PRT_WORK_ITEM pRtWorkItem ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PlatformIsWorkItemScheduled(pRtWorkItem); ++#endif ++} ++ ++ ++ ++// ++// ODM Timer relative API. ++// ++VOID ++ODM_StallExecution( ++ IN u4Byte usDelay ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ rtw_udelay_os(usDelay); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PlatformStallExecution(usDelay); ++#endif ++} ++ ++VOID ++ODM_delay_ms(IN u4Byte ms) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ delay_ms(ms); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ rtw_mdelay_os(ms); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ delay_ms(ms); ++#endif ++} ++ ++VOID ++ODM_delay_us(IN u4Byte us) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ delay_us(us); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ rtw_udelay_os(us); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PlatformStallExecution(us); ++#endif ++} ++ ++VOID ++ODM_sleep_ms(IN u4Byte ms) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ rtw_msleep_os(ms); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++#endif ++} ++ ++VOID ++ODM_sleep_us(IN u4Byte us) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ rtw_usleep_os(us); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++#endif ++} ++ ++VOID ++ODM_SetTimer( ++ IN PDM_ODM_T pDM_Odm, ++ IN PRT_TIMER pTimer, ++ IN u4Byte msDelay ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ mod_timer(pTimer, jiffies + (msDelay+9)/10); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ _set_timer(pTimer,msDelay ); //ms ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PlatformSetTimer(Adapter, pTimer, msDelay); ++#endif ++ ++} ++ ++VOID ++ODM_InitializeTimer( ++ IN PDM_ODM_T pDM_Odm, ++ IN PRT_TIMER pTimer, ++ IN RT_TIMER_CALL_BACK CallBackFunc, ++ IN PVOID pContext, ++ IN const char* szID ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ pTimer->function = CallBackFunc; ++ pTimer->data = (unsigned long)pDM_Odm; ++ init_timer(pTimer); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ _init_timer(pTimer,Adapter->pnetdev,CallBackFunc,pDM_Odm); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PlatformInitializeTimer(Adapter, pTimer, CallBackFunc,pContext,szID); ++#endif ++} ++ ++ ++VOID ++ODM_CancelTimer( ++ IN PDM_ODM_T pDM_Odm, ++ IN PRT_TIMER pTimer ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ del_timer_sync(pTimer); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ _cancel_timer_ex(pTimer); ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PlatformCancelTimer(Adapter, pTimer); ++#endif ++} ++ ++ ++VOID ++ODM_ReleaseTimer( ++ IN PDM_ODM_T pDM_Odm, ++ IN PRT_TIMER pTimer ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ ++ // <20120301, Kordan> If the initilization fails, InitializeAdapterXxx will return regardless of InitHalDm. ++ // Hence, uninitialized timers cause BSOD when the driver releases resources since the init fail. ++ if (pTimer == 0) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_SERIOUS, ("=====>ODM_ReleaseTimer(), The timer is NULL! Please check it!\n")); ++ return; ++ } ++ ++ PlatformReleaseTimer(Adapter, pTimer); ++#endif ++} ++ ++ ++// ++// ODM FW relative API. ++// ++#if (DM_ODM_SUPPORT_TYPE & ODM_MP) ++VOID ++ODM_FillH2CCmd( ++ IN PADAPTER Adapter, ++ IN u1Byte ElementID, ++ IN u4Byte CmdLen, ++ IN pu1Byte pCmdBuffer ++) ++{ ++ if(IS_HARDWARE_TYPE_JAGUAR(Adapter)) ++ { ++ switch(ElementID) ++ { ++ case ODM_H2C_RSSI_REPORT: ++ FillH2CCmd8812(Adapter, H2C_8812_RSSI_REPORT, CmdLen, pCmdBuffer); ++ default: ++ break; ++ } ++ ++ } ++ else if(IS_HARDWARE_TYPE_8188E(Adapter)) ++ { ++ switch(ElementID) ++ { ++ case ODM_H2C_PSD_RESULT: ++ FillH2CCmd88E(Adapter, H2C_88E_PSD_RESULT, CmdLen, pCmdBuffer); ++ default: ++ break; ++ } ++ } ++ else ++ { ++ switch(ElementID) ++ { ++ case ODM_H2C_RSSI_REPORT: ++ FillH2CCmd92C(Adapter, H2C_RSSI_REPORT, CmdLen, pCmdBuffer); ++ case ODM_H2C_PSD_RESULT: ++ FillH2CCmd92C(Adapter, H2C_92C_PSD_RESULT, CmdLen, pCmdBuffer); ++ default: ++ break; ++ } ++ } ++} ++#else ++u4Byte ++ODM_FillH2CCmd( ++ IN pu1Byte pH2CBuffer, ++ IN u4Byte H2CBufferLen, ++ IN u4Byte CmdNum, ++ IN pu4Byte pElementID, ++ IN pu4Byte pCmdLen, ++ IN pu1Byte* pCmbBuffer, ++ IN pu1Byte CmdStartSeq ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) ++ ++#elif(DM_ODM_SUPPORT_TYPE & ODM_MP) ++ //FillH2CCmd(pH2CBuffer, H2CBufferLen, CmdNum, pElementID, pCmdLen, pCmbBuffer, CmdStartSeq); ++ return FALSE; ++#endif ++ ++ return TRUE; ++} ++#endif ++ ++ ++ ++ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_interface.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_interface.h +new file mode 100644 +index 00000000..a5e86801 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_interface.h +@@ -0,0 +1,374 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++ ++#ifndef __ODM_INTERFACE_H__ ++#define __ODM_INTERFACE_H__ ++ ++ ++ ++// ++// =========== Constant/Structure/Enum/... Define ++// ++ ++ ++ ++// ++// =========== Macro Define ++// ++ ++#define _reg_all(_name) ODM_##_name ++#define _reg_ic(_name, _ic) ODM_##_name##_ic ++#define _bit_all(_name) BIT_##_name ++#define _bit_ic(_name, _ic) BIT_##_name##_ic ++ ++// _cat: implemented by Token-Pasting Operator. ++#if 0 ++#define _cat(_name, _ic_type, _func) \ ++ ( \ ++ _func##_all(_name) \ ++ ) ++#endif ++ ++/*=================================== ++ ++#define ODM_REG_DIG_11N 0xC50 ++#define ODM_REG_DIG_11AC 0xDDD ++ ++ODM_REG(DIG,_pDM_Odm) ++=====================================*/ ++ ++#define _reg_11N(_name) ODM_REG_##_name##_11N ++#define _reg_11AC(_name) ODM_REG_##_name##_11AC ++#define _bit_11N(_name) ODM_BIT_##_name##_11N ++#define _bit_11AC(_name) ODM_BIT_##_name##_11AC ++ ++#if 1 //TODO: enable it if we need to support run-time to differentiate between 92C_SERIES and JAGUAR_SERIES. ++#define _cat(_name, _ic_type, _func) \ ++ ( \ ++ ((_ic_type) & ODM_IC_11N_SERIES)? _func##_11N(_name): \ ++ _func##_11AC(_name) \ ++ ) ++#endif ++#if 0 // only sample code ++#define _cat(_name, _ic_type, _func) \ ++ ( \ ++ ((_ic_type) & ODM_RTL8192C)? _func##_ic(_name, _8192C): \ ++ ((_ic_type) & ODM_RTL8192D)? _func##_ic(_name, _8192D): \ ++ ((_ic_type) & ODM_RTL8192S)? _func##_ic(_name, _8192S): \ ++ ((_ic_type) & ODM_RTL8723A)? _func##_ic(_name, _8723A): \ ++ ((_ic_type) & ODM_RTL8188E)? _func##_ic(_name, _8188E): \ ++ _func##_ic(_name, _8195) \ ++ ) ++#endif ++ ++// _name: name of register or bit. ++// Example: "ODM_REG(R_A_AGC_CORE1, pDM_Odm)" ++// gets "ODM_R_A_AGC_CORE1" or "ODM_R_A_AGC_CORE1_8192C", depends on SupportICType. ++#define ODM_REG(_name, _pDM_Odm) _cat(_name, _pDM_Odm->SupportICType, _reg) ++#define ODM_BIT(_name, _pDM_Odm) _cat(_name, _pDM_Odm->SupportICType, _bit) ++ ++typedef enum _ODM_H2C_CMD ++{ ++ ODM_H2C_RSSI_REPORT = 0, ++ ODM_H2C_PSD_RESULT=1, ++ ODM_H2C_PathDiv = 2, ++ ODM_MAX_H2CCMD ++}ODM_H2C_CMD; ++ ++ ++// ++// 2012/02/17 MH For non-MP compile pass only. Linux does not support workitem. ++// Suggest HW team to use thread instead of workitem. Windows also support the feature. ++// ++#if (DM_ODM_SUPPORT_TYPE != ODM_MP) ++typedef void *PRT_WORK_ITEM ; ++typedef void RT_WORKITEM_HANDLE,*PRT_WORKITEM_HANDLE; ++typedef VOID (*RT_WORKITEM_CALL_BACK)(PVOID pContext); ++ ++#if 0 ++typedef struct tasklet_struct RT_WORKITEM_HANDLE, *PRT_WORKITEM_HANDLE; ++ ++typedef struct _RT_WORK_ITEM ++{ ++ ++ RT_WORKITEM_HANDLE Handle; // Platform-dependent handle for this workitem, e.g. Ndis Workitem object. ++ PVOID Adapter; // Pointer to Adapter object. ++ PVOID pContext; // Parameter to passed to CallBackFunc(). ++ RT_WORKITEM_CALL_BACK CallbackFunc; // Callback function of the workitem. ++ u1Byte RefCount; // 0: driver is going to unload, 1: No such workitem scheduled, 2: one workitem is schedueled. ++ PVOID pPlatformExt; // Pointer to platform-dependent extension. ++ BOOLEAN bFree; ++ char szID[36]; // An identity string of this workitem. ++}RT_WORK_ITEM, *PRT_WORK_ITEM; ++ ++#endif ++ ++ ++#endif ++ ++// ++// =========== Extern Variable ??? It should be forbidden. ++// ++ ++ ++// ++// =========== EXtern Function Prototype ++// ++ ++ ++u1Byte ++ODM_Read1Byte( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr ++ ); ++ ++u2Byte ++ODM_Read2Byte( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr ++ ); ++ ++u4Byte ++ODM_Read4Byte( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr ++ ); ++ ++VOID ++ODM_Write1Byte( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr, ++ IN u1Byte Data ++ ); ++ ++VOID ++ODM_Write2Byte( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr, ++ IN u2Byte Data ++ ); ++ ++VOID ++ODM_Write4Byte( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr, ++ IN u4Byte Data ++ ); ++ ++VOID ++ODM_SetMACReg( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr, ++ IN u4Byte BitMask, ++ IN u4Byte Data ++ ); ++ ++u4Byte ++ODM_GetMACReg( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr, ++ IN u4Byte BitMask ++ ); ++ ++VOID ++ODM_SetBBReg( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr, ++ IN u4Byte BitMask, ++ IN u4Byte Data ++ ); ++ ++u4Byte ++ODM_GetBBReg( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte RegAddr, ++ IN u4Byte BitMask ++ ); ++ ++VOID ++ODM_SetRFReg( ++ IN PDM_ODM_T pDM_Odm, ++ IN ODM_RF_RADIO_PATH_E eRFPath, ++ IN u4Byte RegAddr, ++ IN u4Byte BitMask, ++ IN u4Byte Data ++ ); ++ ++u4Byte ++ODM_GetRFReg( ++ IN PDM_ODM_T pDM_Odm, ++ IN ODM_RF_RADIO_PATH_E eRFPath, ++ IN u4Byte RegAddr, ++ IN u4Byte BitMask ++ ); ++ ++ ++// ++// Memory Relative Function. ++// ++VOID ++ODM_AllocateMemory( ++ IN PDM_ODM_T pDM_Odm, ++ OUT PVOID *pPtr, ++ IN u4Byte length ++ ); ++VOID ++ODM_FreeMemory( ++ IN PDM_ODM_T pDM_Odm, ++ OUT PVOID pPtr, ++ IN u4Byte length ++ ); ++ ++s4Byte ODM_CompareMemory( ++ IN PDM_ODM_T pDM_Odm, ++ IN PVOID pBuf1, ++ IN PVOID pBuf2, ++ IN u4Byte length ++ ); ++ ++// ++// ODM MISC-spin lock relative API. ++// ++VOID ++ODM_AcquireSpinLock( ++ IN PDM_ODM_T pDM_Odm, ++ IN RT_SPINLOCK_TYPE type ++ ); ++ ++VOID ++ODM_ReleaseSpinLock( ++ IN PDM_ODM_T pDM_Odm, ++ IN RT_SPINLOCK_TYPE type ++ ); ++ ++ ++// ++// ODM MISC-workitem relative API. ++// ++VOID ++ODM_InitializeWorkItem( ++ IN PDM_ODM_T pDM_Odm, ++ IN PRT_WORK_ITEM pRtWorkItem, ++ IN RT_WORKITEM_CALL_BACK RtWorkItemCallback, ++ IN PVOID pContext, ++ IN const char* szID ++ ); ++ ++VOID ++ODM_StartWorkItem( ++ IN PRT_WORK_ITEM pRtWorkItem ++ ); ++ ++VOID ++ODM_StopWorkItem( ++ IN PRT_WORK_ITEM pRtWorkItem ++ ); ++ ++VOID ++ODM_FreeWorkItem( ++ IN PRT_WORK_ITEM pRtWorkItem ++ ); ++ ++VOID ++ODM_ScheduleWorkItem( ++ IN PRT_WORK_ITEM pRtWorkItem ++ ); ++ ++VOID ++ODM_IsWorkItemScheduled( ++ IN PRT_WORK_ITEM pRtWorkItem ++ ); ++ ++// ++// ODM Timer relative API. ++// ++VOID ++ODM_StallExecution( ++ IN u4Byte usDelay ++ ); ++ ++VOID ++ODM_delay_ms(IN u4Byte ms); ++ ++ ++VOID ++ODM_delay_us(IN u4Byte us); ++ ++VOID ++ODM_sleep_ms(IN u4Byte ms); ++ ++VOID ++ODM_sleep_us(IN u4Byte us); ++ ++VOID ++ODM_SetTimer( ++ IN PDM_ODM_T pDM_Odm, ++ IN PRT_TIMER pTimer, ++ IN u4Byte msDelay ++ ); ++ ++VOID ++ODM_InitializeTimer( ++ IN PDM_ODM_T pDM_Odm, ++ IN PRT_TIMER pTimer, ++ IN RT_TIMER_CALL_BACK CallBackFunc, ++ IN PVOID pContext, ++ IN const char* szID ++ ); ++ ++VOID ++ODM_CancelTimer( ++ IN PDM_ODM_T pDM_Odm, ++ IN PRT_TIMER pTimer ++ ); ++ ++VOID ++ODM_ReleaseTimer( ++ IN PDM_ODM_T pDM_Odm, ++ IN PRT_TIMER pTimer ++ ); ++ ++ ++// ++// ODM FW relative API. ++// ++#if (DM_ODM_SUPPORT_TYPE & ODM_MP) ++VOID ++ODM_FillH2CCmd( ++ IN PADAPTER Adapter, ++ IN u1Byte ElementID, ++ IN u4Byte CmdLen, ++ IN pu1Byte pCmdBuffer ++); ++#else ++u4Byte ++ODM_FillH2CCmd( ++ IN pu1Byte pH2CBuffer, ++ IN u4Byte H2CBufferLen, ++ IN u4Byte CmdNum, ++ IN pu4Byte pElementID, ++ IN pu4Byte pCmdLen, ++ IN pu1Byte* pCmbBuffer, ++ IN pu1Byte CmdStartSeq ++ ); ++#endif ++#endif // __ODM_INTERFACE_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_precomp.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_precomp.h +new file mode 100644 +index 00000000..f40a1277 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_precomp.h +@@ -0,0 +1,222 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#ifndef __ODM_PRECOMP_H__ ++#define __ODM_PRECOMP_H__ ++ ++#include "odm_types.h" ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++#include "Precomp.h" // We need to include mp_precomp.h due to batch file setting. ++ ++#else ++ ++#define TEST_FALG___ 1 ++ ++#endif ++ ++//2 Config Flags and Structs - defined by each ODM Type ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ #include "../8192cd_cfg.h" ++ #include "../odm_inc.h" ++ ++ #include "../8192cd.h" ++ #include "../8192cd_util.h" ++ #ifdef _BIG_ENDIAN_ ++ #define ODM_ENDIAN_TYPE ODM_ENDIAN_BIG ++ #else ++ #define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE ++ #endif ++ ++ #ifdef AP_BUILD_WORKAROUND ++ #include "../8192cd_headers.h" ++ #include "../8192cd_debug.h" ++ #endif ++ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_ADSL) ++ // Flags ++ #include "../8192cd_cfg.h" // OUTSRC needs ADSL config flags. ++ #include "../odm_inc.h" // OUTSRC needs some extra flags. ++ // Data Structure ++ #include "../common_types.h" // OUTSRC and rtl8192cd both needs basic type such as UINT8 and BIT0. ++ #include "../8192cd.h" // OUTSRC needs basic ADSL struct definition. ++ #include "../8192cd_util.h" // OUTSRC needs basic I/O function. ++ #ifdef _BIG_ENDIAN_ ++ #define ODM_ENDIAN_TYPE ODM_ENDIAN_BIG ++ #else ++ #define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE ++ #endif ++ ++ #ifdef ADSL_AP_BUILD_WORKAROUND ++ // NESTED_INC: Functions defined outside should not be included!! Marked by Annie, 2011-10-14. ++ #include "../8192cd_headers.h" ++ #include "../8192cd_debug.h" ++ #endif ++ ++#elif (DM_ODM_SUPPORT_TYPE ==ODM_CE) ++ #include ++ #include ++ #include ++ #include ++ #include ++ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ #include "Mp_Precomp.h" ++ #define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE ++#endif ++ ++ ++//2 Hardware Parameter Files ++ ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++#if (RTL8192C_SUPPORT==1) ++ #include "rtl8192c/Hal8192CEFWImg_AP.h" ++ #include "rtl8192c/Hal8192CEPHYImg_AP.h" ++ #include "rtl8192c/Hal8192CEMACImg_AP.h" ++#endif ++#elif (DM_ODM_SUPPORT_TYPE == ODM_ADSL) ++ #include "rtl8192c/Hal8192CEFWImg_ADSL.h" ++ #include "rtl8192c/Hal8192CEPHYImg_ADSL.h" ++ #include "rtl8192c/Hal8192CEMACImg_ADSL.h" ++ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #if(RTL8192CE_SUPPORT ==1) ++ #include "rtl8192c/Hal8192CEFWImg_CE.h" ++ #include "rtl8192c/Hal8192CEPHYImg_CE.h" ++ #include "rtl8192c/Hal8192CEMACImg_CE.h" ++ #elif(RTL8192CU_SUPPORT ==1) ++ #include "rtl8192c/Hal8192CUFWImg_CE.h" ++ #include "rtl8192c/Hal8192CUPHYImg_CE.h" ++ #include "rtl8192c/Hal8192CUMACImg_CE.h" ++ #elif(RTL8192DE_SUPPORT ==1) ++ #include "rtl8192d/Hal8192DEFWImg_CE.h" ++ #include "rtl8192d/Hal8192DEPHYImg_CE.h" ++ #include "rtl8192d/Hal8192DEMACImg_CE.h" ++ #elif(RTL8192DU_SUPPORT ==1) ++ #include "rtl8192d/Hal8192DUFWImg_CE.h" ++ #include "rtl8192d/Hal8192DUPHYImg_CE.h" ++ #include "rtl8192d/Hal8192DUMACImg_CE.h" ++ #elif(RTL8723AS_SUPPORT==1) ++ #include "rtl8723a/Hal8723SHWImg_CE.h" ++ #elif(RTL8723AU_SUPPORT==1) ++ #include "rtl8723a/Hal8723UHWImg_CE.h" ++ #elif(RTL8188E_SUPPORT==1) ++ #include "rtl8188e/Hal8188EFWImg_CE.h" ++ #endif ++#elif (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ++#endif ++ ++ ++//2 OutSrc Header Files ++ ++#include "odm.h" ++#include "odm_HWConfig.h" ++#include "odm_debug.h" ++#include "odm_RegDefine11AC.h" ++#include "odm_RegDefine11N.h" ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++#if (RTL8192C_SUPPORT==1) ++ #include "rtl8192c/HalDMOutSrc8192C_AP.h" ++#endif ++#if (RTL8188E_SUPPORT==1) ++ #include "rtl8188e/Hal8188ERateAdaptive.h"//for RA,Power training ++#endif ++ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_ADSL) ++ #include "rtl8192c/HalDMOutSrc8192C_ADSL.h" ++ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include "HalPhyRf.h" ++ #if (RTL8192C_SUPPORT==1) ++ #ifdef CONFIG_INTEL_PROXIM ++ #include "../proxim/intel_proxim.h" ++ #endif ++ #include "rtl8192c/HalDMOutSrc8192C_CE.h" ++ #include ++ #elif (RTL8192D_SUPPORT==1) ++ #include "rtl8192d/HalDMOutSrc8192D_CE.h" ++ #include "rtl8192d_hal.h" ++ #elif (RTL8723A_SUPPORT==1) ++ #include "rtl8192c/HalDMOutSrc8192C_CE.h" //for IQK,LCK,Power-tracking ++ #include "rtl8723a_hal.h" ++ #elif (RTL8188E_SUPPORT==1) ++ #include "rtl8188e/HalPhyRf_8188e.h"//for IQK,LCK,Power-tracking ++ #include "rtl8188e/Hal8188ERateAdaptive.h"//for RA,Power training ++ #include "rtl8188e_hal.h" ++ #endif ++ ++#endif ++ ++#include "odm_interface.h" ++#include "odm_reg.h" ++ ++#if (RTL8192C_SUPPORT==1) ++#if (DM_ODM_SUPPORT_TYPE == ODM_AP) ++#include "rtl8192c/Hal8192CHWImg_MAC.h" ++#include "rtl8192c/Hal8192CHWImg_RF.h" ++#include "rtl8192c/Hal8192CHWImg_BB.h" ++#include "rtl8192c/Hal8192CHWImg_FW.h" ++#endif ++#include "rtl8192c/odm_RTL8192C.h" ++#endif ++#if (RTL8192D_SUPPORT==1) ++#include "rtl8192d/odm_RTL8192D.h" ++#endif ++ ++#if (RTL8723A_SUPPORT==1) ++#include "rtl8723a/HalHWImg8723A_MAC.h" ++#include "rtl8723a/HalHWImg8723A_RF.h" ++#include "rtl8723a/HalHWImg8723A_BB.h" ++#include "rtl8723a/HalHWImg8723A_FW.h" ++#include "rtl8723a/odm_RegConfig8723A.h" ++#endif ++ ++#if (RTL8188E_SUPPORT==1) ++#include "rtl8188e/HalHWImg8188E_MAC.h" ++#include "rtl8188e/HalHWImg8188E_RF.h" ++#include "rtl8188e/HalHWImg8188E_BB.h" ++#include "rtl8188e/Hal8188EReg.h" ++ ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++#include "rtl8188e/HalPhyRf_8188e.h" ++#endif ++ ++#if (RTL8188E_FOR_TEST_CHIP >= 1) ++#include "rtl8188e/HalHWImg8188E_TestChip_MAC.h" ++#include "rtl8188e/HalHWImg8188E_TestChip_RF.h" ++#include "rtl8188e/HalHWImg8188E_TestChip_BB.h" ++#endif ++ ++#ifdef CONFIG_WOWLAN ++#if (RTL8188E_SUPPORT==1) ++#include "rtl8188e/HalHWImg8188E_FW.h" ++#endif ++#endif //CONFIG_WOWLAN ++ ++#include "rtl8188e/odm_RegConfig8188E.h" ++#include "rtl8188e/odm_RTL8188E.h" ++#endif ++ ++#endif // __ODM_PRECOMP_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_reg.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_reg.h +new file mode 100644 +index 00000000..361ac79c +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_reg.h +@@ -0,0 +1,120 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++//============================================================ ++// File Name: odm_reg.h ++// ++// Description: ++// ++// This file is for general register definition. ++// ++// ++//============================================================ ++#ifndef __HAL_ODM_REG_H__ ++#define __HAL_ODM_REG_H__ ++ ++// ++// Register Definition ++// ++ ++//MAC REG ++#define ODM_BB_RESET 0x002 ++#define ODM_DUMMY 0x4fe ++#define ODM_EDCA_VO_PARAM 0x500 ++#define ODM_EDCA_VI_PARAM 0x504 ++#define ODM_EDCA_BE_PARAM 0x508 ++#define ODM_EDCA_BK_PARAM 0x50C ++#define ODM_TXPAUSE 0x522 ++ ++//BB REG ++#define ODM_FPGA_PHY0_PAGE8 0x800 ++#define ODM_PSD_SETTING 0x808 ++#define ODM_AFE_SETTING 0x818 ++#define ODM_TXAGC_B_6_18 0x830 ++#define ODM_TXAGC_B_24_54 0x834 ++#define ODM_TXAGC_B_MCS32_5 0x838 ++#define ODM_TXAGC_B_MCS0_MCS3 0x83c ++#define ODM_TXAGC_B_MCS4_MCS7 0x848 ++#define ODM_TXAGC_B_MCS8_MCS11 0x84c ++#define ODM_ANALOG_REGISTER 0x85c ++#define ODM_RF_INTERFACE_OUTPUT 0x860 ++#define ODM_TXAGC_B_MCS12_MCS15 0x868 ++#define ODM_TXAGC_B_11_A_2_11 0x86c ++#define ODM_AD_DA_LSB_MASK 0x874 ++#define ODM_ENABLE_3_WIRE 0x88c ++#define ODM_PSD_REPORT 0x8b4 ++#define ODM_R_ANT_SELECT 0x90c ++#define ODM_CCK_ANT_SELECT 0xa07 ++#define ODM_CCK_PD_THRESH 0xa0a ++#define ODM_CCK_RF_REG1 0xa11 ++#define ODM_CCK_MATCH_FILTER 0xa20 ++#define ODM_CCK_RAKE_MAC 0xa2e ++#define ODM_CCK_CNT_RESET 0xa2d ++#define ODM_CCK_TX_DIVERSITY 0xa2f ++#define ODM_CCK_FA_CNT_MSB 0xa5b ++#define ODM_CCK_FA_CNT_LSB 0xa5c ++#define ODM_CCK_NEW_FUNCTION 0xa75 ++#define ODM_OFDM_PHY0_PAGE_C 0xc00 ++#define ODM_OFDM_RX_ANT 0xc04 ++#define ODM_R_A_RXIQI 0xc14 ++#define ODM_R_A_AGC_CORE1 0xc50 ++#define ODM_R_A_AGC_CORE2 0xc54 ++#define ODM_R_B_AGC_CORE1 0xc58 ++#define ODM_R_AGC_PAR 0xc70 ++#define ODM_R_HTSTF_AGC_PAR 0xc7c ++#define ODM_TX_PWR_TRAINING_A 0xc90 ++#define ODM_TX_PWR_TRAINING_B 0xc98 ++#define ODM_OFDM_FA_CNT1 0xcf0 ++#define ODM_OFDM_PHY0_PAGE_D 0xd00 ++#define ODM_OFDM_FA_CNT2 0xda0 ++#define ODM_OFDM_FA_CNT3 0xda4 ++#define ODM_OFDM_FA_CNT4 0xda8 ++#define ODM_TXAGC_A_6_18 0xe00 ++#define ODM_TXAGC_A_24_54 0xe04 ++#define ODM_TXAGC_A_1_MCS32 0xe08 ++#define ODM_TXAGC_A_MCS0_MCS3 0xe10 ++#define ODM_TXAGC_A_MCS4_MCS7 0xe14 ++#define ODM_TXAGC_A_MCS8_MCS11 0xe18 ++#define ODM_TXAGC_A_MCS12_MCS15 0xe1c ++ ++//RF REG ++#define ODM_GAIN_SETTING 0x00 ++#define ODM_CHANNEL 0x18 ++ ++//Ant Detect Reg ++#define ODM_DPDT 0x300 ++ ++//PSD Init ++#define ODM_PSDREG 0x808 ++ ++//92D Path Div ++#define PATHDIV_REG 0xB30 ++#define PATHDIV_TRI 0xBA0 ++ ++ ++// ++// Bitmap Definition ++// ++ ++#define BIT_FA_RESET BIT0 ++ ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_types.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_types.h +new file mode 100644 +index 00000000..b243d74d +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/odm_types.h +@@ -0,0 +1,252 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __ODM_TYPES_H__ ++#define __ODM_TYPES_H__ ++ ++// ++// Define Different SW team support ++// ++#define ODM_AP 0x01 //BIT0 ++#define ODM_ADSL 0x02 //BIT1 ++#define ODM_CE 0x04 //BIT2 ++#define ODM_MP 0x08 //BIT3 ++ ++#define DM_ODM_SUPPORT_TYPE ODM_CE ++ ++// Deifne HW endian support ++#define ODM_ENDIAN_BIG 0 ++#define ODM_ENDIAN_LITTLE 1 ++ ++#if (DM_ODM_SUPPORT_TYPE != ODM_MP) ++#define RT_PCI_INTERFACE 1 ++#define RT_USB_INTERFACE 2 ++#define RT_SDIO_INTERFACE 3 ++#endif ++ ++typedef enum _HAL_STATUS{ ++ HAL_STATUS_SUCCESS, ++ HAL_STATUS_FAILURE, ++ /*RT_STATUS_PENDING, ++ RT_STATUS_RESOURCE, ++ RT_STATUS_INVALID_CONTEXT, ++ RT_STATUS_INVALID_PARAMETER, ++ RT_STATUS_NOT_SUPPORT, ++ RT_STATUS_OS_API_FAILED,*/ ++}HAL_STATUS,*PHAL_STATUS; ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++typedef enum _RT_SPINLOCK_TYPE{ ++ RT_TEMP =1, ++}RT_SPINLOCK_TYPE; ++#elif( (DM_ODM_SUPPORT_TYPE == ODM_AP) ||(DM_ODM_SUPPORT_TYPE == ODM_ADSL)) ++ ++#define VISTA_USB_RX_REVISE 0 ++ ++// ++// Declare for ODM spin lock defintion temporarily fro compile pass. ++// ++typedef enum _RT_SPINLOCK_TYPE{ ++ RT_TX_SPINLOCK = 1, ++ RT_RX_SPINLOCK = 2, ++ RT_RM_SPINLOCK = 3, ++ RT_CAM_SPINLOCK = 4, ++ RT_SCAN_SPINLOCK = 5, ++ RT_LOG_SPINLOCK = 7, ++ RT_BW_SPINLOCK = 8, ++ RT_CHNLOP_SPINLOCK = 9, ++ RT_RF_OPERATE_SPINLOCK = 10, ++ RT_INITIAL_SPINLOCK = 11, ++ RT_RF_STATE_SPINLOCK = 12, // For RF state. Added by Bruce, 2007-10-30. ++#if VISTA_USB_RX_REVISE ++ RT_USBRX_CONTEXT_SPINLOCK = 13, ++ RT_USBRX_POSTPROC_SPINLOCK = 14, // protect data of Adapter->IndicateW/ IndicateR ++#endif ++ //Shall we define Ndis 6.2 SpinLock Here ? ++ RT_PORT_SPINLOCK=16, ++ RT_VNIC_SPINLOCK=17, ++ RT_HVL_SPINLOCK=18, ++ RT_H2C_SPINLOCK = 20, // For H2C cmd. Added by tynli. 2009.11.09. ++ ++ RT_BTData_SPINLOCK=25, ++ ++ RT_WAPI_OPTION_SPINLOCK=26, ++ RT_WAPI_RX_SPINLOCK=27, ++ ++ // add for 92D CCK control issue ++ RT_CCK_PAGEA_SPINLOCK = 28, ++ RT_BUFFER_SPINLOCK = 29, ++ RT_CHANNEL_AND_BANDWIDTH_SPINLOCK = 30, ++ RT_GEN_TEMP_BUF_SPINLOCK = 31, ++ RT_AWB_SPINLOCK = 32, ++ RT_FW_PS_SPINLOCK = 33, ++ RT_HW_TIMER_SPIN_LOCK = 34, ++ RT_MPT_WI_SPINLOCK = 35 ++}RT_SPINLOCK_TYPE; ++ ++#endif ++ ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ #define STA_INFO_T RT_WLAN_STA ++ #define PSTA_INFO_T PRT_WLAN_STA ++ ++// typedef unsigned long u4Byte,*pu4Byte; ++ #define CONFIG_HW_ANTENNA_DIVERSITY ++#define CONFIG_SW_ANTENNA_DIVERSITY ++ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ ++ // To let ADSL/AP project compile ok; it should be removed after all conflict are solved. Added by Annie, 2011-10-07. ++ #define ADSL_AP_BUILD_WORKAROUND ++ #define AP_BUILD_WORKAROUND ++ // ++ ++ #ifdef AP_BUILD_WORKAROUND ++ #include "../typedef.h" ++ #else ++ typedef void VOID,*PVOID; ++ typedef unsigned char BOOLEAN,*PBOOLEAN; ++ typedef unsigned char u1Byte,*pu1Byte; ++ typedef unsigned short u2Byte,*pu2Byte; ++ typedef unsigned int u4Byte,*pu4Byte; ++ typedef unsigned long long u8Byte,*pu8Byte; ++ typedef char s1Byte,*ps1Byte; ++ typedef short s2Byte,*ps2Byte; ++ typedef long s4Byte,*ps4Byte; ++ typedef long long s8Byte,*ps8Byte; ++ #endif ++ ++ typedef struct rtl8192cd_priv *prtl8192cd_priv; ++ typedef struct stat_info STA_INFO_T,*PSTA_INFO_T; ++ typedef struct timer_list RT_TIMER, *PRT_TIMER; ++ typedef void * RT_TIMER_CALL_BACK; ++ ++ #define DEV_BUS_TYPE RT_PCI_INTERFACE ++ ++ #define _TRUE 1 ++ #define _FALSE 0 ++ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_ADSL) ++ ++ // To let ADSL/AP project compile ok; it should be removed after all conflict are solved. Added by Annie, 2011-10-07. ++ #define ADSL_AP_BUILD_WORKAROUND ++ #define ADSL_BUILD_WORKAROUND ++ // ++ ++ typedef unsigned char BOOLEAN,*PBOOLEAN; ++ typedef unsigned char u1Byte,*pu1Byte; ++ typedef unsigned short u2Byte,*pu2Byte; ++ typedef unsigned int u4Byte,*pu4Byte; ++ typedef unsigned long long u8Byte,*pu8Byte; ++ typedef char s1Byte,*ps1Byte; ++ typedef short s2Byte,*ps2Byte; ++ typedef long s4Byte,*ps4Byte; ++ typedef long long s8Byte,*ps8Byte; ++ ++ typedef struct rtl8192cd_priv *prtl8192cd_priv; ++ typedef struct stat_info STA_INFO_T,*PSTA_INFO_T; ++ typedef struct timer_list RT_TIMER, *PRT_TIMER; ++ typedef void * RT_TIMER_CALL_BACK; ++ ++ #define DEV_BUS_TYPE RT_PCI_INTERFACE ++ ++ #define _TRUE 1 ++ #define _FALSE 0 ++ ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ #include ++ ++#if 0 ++ typedef u8 u1Byte, *pu1Byte; ++ typedef u16 u2Byte,*pu2Byte; ++ typedef u32 u4Byte,*pu4Byte; ++ typedef u64 u8Byte,*pu8Byte; ++ typedef s8 s1Byte,*ps1Byte; ++ typedef s16 s2Byte,*ps2Byte; ++ typedef s32 s4Byte,*ps4Byte; ++ typedef s64 s8Byte,*ps8Byte; ++#else ++ #define u1Byte u8 ++ #define pu1Byte u8* ++ ++ #define u2Byte u16 ++ #define pu2Byte u16* ++ ++ #define u4Byte u32 ++ #define pu4Byte u32* ++ ++ #define u8Byte u64 ++ #define pu8Byte u64* ++ ++ #define s1Byte s8 ++ #define ps1Byte s8* ++ ++ #define s2Byte s16 ++ #define ps2Byte s16* ++ ++ #define s4Byte s32 ++ #define ps4Byte s32* ++ ++ #define s8Byte s64 ++ #define ps8Byte s64* ++ ++#endif ++ #ifdef CONFIG_USB_HCI ++ #define DEV_BUS_TYPE RT_USB_INTERFACE ++ #elif defined(CONFIG_PCI_HCI) ++ #define DEV_BUS_TYPE RT_PCI_INTERFACE ++ #elif defined(CONFIG_SDIO_HCI) ++ #define DEV_BUS_TYPE RT_SDIO_INTERFACE ++ #elif defined(CONFIG_GSPI_HCI) ++ #define DEV_BUS_TYPE RT_SDIO_INTERFACE ++ #endif ++ ++ ++ #if defined(CONFIG_LITTLE_ENDIAN) ++ #define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE ++ #elif defined (CONFIG_BIG_ENDIAN) ++ #define ODM_ENDIAN_TYPE ODM_ENDIAN_BIG ++ #endif ++ ++ typedef struct timer_list RT_TIMER, *PRT_TIMER; ++ typedef void * RT_TIMER_CALL_BACK; ++ #define STA_INFO_T struct sta_info ++ #define PSTA_INFO_T struct sta_info * ++ ++ ++ ++ #define TRUE _TRUE ++ #define FALSE _FALSE ++ ++ ++ #define SET_TX_DESC_ANTSEL_A_88E(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 24, 1, __Value) ++ #define SET_TX_DESC_ANTSEL_B_88E(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 25, 1, __Value) ++ #define SET_TX_DESC_ANTSEL_C_88E(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+28, 29, 1, __Value) ++ ++ //define useless flag to avoid compile warning ++ #define USE_WORKITEM 0 ++ #define FOR_BRAZIL_PRETEST 0 ++ #define BT_30_SUPPORT 0 ++ #define FPGA_TWO_MAC_VERIFICATION 0 ++#endif ++ ++ ++#endif // __ODM_TYPES_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/Hal8188EFWImg_CE.c b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/Hal8188EFWImg_CE.c +new file mode 100644 +index 00000000..815a357b +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/Hal8188EFWImg_CE.c +@@ -0,0 +1,892 @@ ++/****************************************************************************** ++* ++* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++* ++* This program is free software; you can redistribute it and/or modify it ++* under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++* ++* ++******************************************************************************/ ++#include "../odm_precomp.h" ++ ++const u8 Rtl8188EFwImgArray[Rtl8188EFWImgArrayLength] = { ++0xE1, 0x88, 0x10, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01, 0x21, 0x11, 0x27, 0x30, 0x36, 0x00, 0x00, ++0x2D, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0x45, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0xC1, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0xA1, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x56, 0xF7, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0xC2, 0xAF, 0x80, 0xFE, 0x32, 0x12, 0x42, 0x04, 0x85, 0xD0, 0x0B, 0x75, 0xD0, 0x08, 0xAA, 0xE0, ++0xC2, 0x8C, 0xE5, 0x8A, 0x24, 0x67, 0xF5, 0x8A, 0xE5, 0x8C, 0x34, 0x79, 0xF5, 0x8C, 0xD2, 0x8C, ++0xEC, 0x24, 0x89, 0xF8, 0xE6, 0xBC, 0x03, 0x02, 0x74, 0xFF, 0xC3, 0x95, 0x81, 0xB4, 0x40, 0x00, ++0x40, 0xCE, 0x79, 0x04, 0x78, 0x80, 0x16, 0xE6, 0x08, 0x70, 0x0B, 0xC2, 0xAF, 0xE6, 0x30, 0xE1, ++0x03, 0x44, 0x18, 0xF6, 0xD2, 0xAF, 0x08, 0xD9, 0xED, 0xEA, 0x8B, 0xD0, 0x22, 0xE5, 0x0C, 0xFF, ++0x23, 0x24, 0x81, 0xF8, 0x0F, 0x08, 0x08, 0xBF, 0x04, 0x04, 0x7F, 0x00, 0x78, 0x81, 0xE6, 0x30, ++0xE4, 0xF2, 0x00, 0xE5, 0x0C, 0xC3, 0x9F, 0x50, 0x20, 0x05, 0x0C, 0x74, 0x88, 0x25, 0x0C, 0xF8, ++0xE6, 0xFD, 0xA6, 0x81, 0x08, 0xE6, 0xAE, 0x0C, 0xBE, 0x03, 0x02, 0x74, 0xFF, 0xCD, 0xF8, 0xE8, ++0x6D, 0x60, 0xE0, 0x08, 0xE6, 0xC0, 0xE0, 0x80, 0xF6, 0xE5, 0x0C, 0xD3, 0x9F, 0x40, 0x27, 0xE5, ++0x0C, 0x24, 0x89, 0xF8, 0xE6, 0xAE, 0x0C, 0xBE, 0x03, 0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xCD, ++0xF8, 0xE5, 0x81, 0x6D, 0x60, 0x06, 0xD0, 0xE0, 0xF6, 0x18, 0x80, 0xF5, 0xE5, 0x0C, 0x24, 0x88, ++0xC8, 0xF6, 0x15, 0x0C, 0x80, 0xD3, 0xE5, 0x0C, 0x23, 0x24, 0x81, 0xF8, 0x7F, 0x04, 0xC2, 0xAF, ++0xE6, 0x30, 0xE0, 0x03, 0x10, 0xE2, 0x0C, 0x7F, 0x00, 0x30, 0xE1, 0x07, 0x30, 0xE3, 0x04, 0x7F, ++0x08, 0x54, 0xF4, 0x54, 0x7C, 0xC6, 0xD2, 0xAF, 0x54, 0x80, 0x42, 0x07, 0x22, 0x78, 0x88, 0xA6, ++0x81, 0x74, 0x03, 0x60, 0x06, 0xFF, 0x08, 0x76, 0xFF, 0xDF, 0xFB, 0x7F, 0x04, 0xE4, 0x78, 0x80, ++0xF6, 0x08, 0xF6, 0x08, 0xDF, 0xFA, 0x78, 0x81, 0x76, 0x30, 0x90, 0x45, 0xDE, 0x74, 0x01, 0x93, ++0xC0, 0xE0, 0xE4, 0x93, 0xC0, 0xE0, 0x43, 0x89, 0x01, 0x75, 0x8A, 0x60, 0x75, 0x8C, 0x79, 0xD2, ++0x8C, 0xD2, 0xAF, 0x22, 0x03, 0xEF, 0xD3, 0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0x74, 0x81, ++0x2F, 0x2F, 0xF8, 0xE6, 0x20, 0xE5, 0xF4, 0xC2, 0xAF, 0xE6, 0x44, 0x30, 0xF6, 0xD2, 0xAF, 0xAE, ++0x0C, 0xEE, 0xC3, 0x9F, 0x50, 0x21, 0x0E, 0x74, 0x88, 0x2E, 0xF8, 0xE6, 0xF9, 0x08, 0xE6, 0x18, ++0xBE, 0x03, 0x02, 0x74, 0xFF, 0xFD, 0xED, 0x69, 0x60, 0x09, 0x09, 0xE7, 0x19, 0x19, 0xF7, 0x09, ++0x09, 0x80, 0xF3, 0x16, 0x16, 0x80, 0xDA, 0xEE, 0xD3, 0x9F, 0x40, 0x04, 0x05, 0x81, 0x05, 0x81, ++0xEE, 0xD3, 0x9F, 0x40, 0x22, 0x74, 0x88, 0x2E, 0xF8, 0x08, 0xE6, 0xF9, 0xEE, 0xB5, 0x0C, 0x02, ++0xA9, 0x81, 0x18, 0x06, 0x06, 0xE6, 0xFD, 0xED, 0x69, 0x60, 0x09, 0x19, 0x19, 0xE7, 0x09, 0x09, ++0xF7, 0x19, 0x80, 0xF3, 0x1E, 0x80, 0xD9, 0xEF, 0x24, 0x88, 0xF8, 0xE6, 0x04, 0xF8, 0xEF, 0x2F, ++0x04, 0x90, 0x45, 0xDE, 0x93, 0xF6, 0x08, 0xEF, 0x2F, 0x93, 0xF6, 0x7F, 0x00, 0x22, 0xEF, 0xD3, ++0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0xEF, 0x23, 0x24, 0x81, 0xF8, 0xE6, 0x30, 0xE5, 0xF4, ++0xC2, 0xAF, 0xE6, 0x54, 0x8C, 0xF6, 0xD2, 0xAF, 0xE5, 0x0C, 0xB5, 0x07, 0x0A, 0x74, 0x88, 0x2F, ++0xF8, 0xE6, 0xF5, 0x81, 0x02, 0x42, 0x4D, 0x50, 0x2E, 0x74, 0x89, 0x2F, 0xF8, 0xE6, 0xBF, 0x03, ++0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xF9, 0x74, 0x88, 0x2F, 0xF8, 0xFB, 0xE6, 0xFC, 0xE9, 0x6C, ++0x60, 0x08, 0xA8, 0x05, 0xE7, 0xF6, 0x1D, 0x19, 0x80, 0xF4, 0xA8, 0x03, 0xA6, 0x05, 0x1F, 0xE5, ++0x0C, 0xB5, 0x07, 0xE3, 0x7F, 0x00, 0x22, 0x74, 0x89, 0x2F, 0xF8, 0xE6, 0xFD, 0x18, 0x86, 0x01, ++0x0F, 0x74, 0x88, 0x2F, 0xF8, 0xA6, 0x01, 0x08, 0x86, 0x04, 0xE5, 0x0C, 0xB5, 0x07, 0x02, 0xAC, ++0x81, 0xED, 0x6C, 0x60, 0x08, 0x0D, 0x09, 0xA8, 0x05, 0xE6, 0xF7, 0x80, 0xF4, 0xE5, 0x0C, 0xB5, ++0x07, 0xDE, 0x89, 0x81, 0x7F, 0x00, 0x22, 0xEF, 0xD3, 0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, ++0xEF, 0x23, 0x24, 0x81, 0xF8, 0xC2, 0xAF, 0xE6, 0x30, 0xE5, 0x05, 0x30, 0xE0, 0x02, 0xD2, 0xE4, ++0xD2, 0xE2, 0xC6, 0xD2, 0xAF, 0x7F, 0x00, 0x30, 0xE2, 0x01, 0x0F, 0x02, 0x42, 0x4C, 0x8F, 0xF0, ++0xE4, 0xFF, 0xFE, 0xE5, 0x0C, 0x23, 0x24, 0x80, 0xF8, 0xC2, 0xA9, 0x30, 0xF7, 0x0D, 0x7F, 0x08, ++0xE6, 0x60, 0x0B, 0x2D, 0xF6, 0x60, 0x30, 0x50, 0x2E, 0x80, 0x07, 0x30, 0xF1, 0x06, 0xED, 0xF6, ++0x60, 0x25, 0x7E, 0x02, 0x08, 0x30, 0xF0, 0x10, 0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x23, 0x0E, 0x30, ++0xE2, 0x0C, 0xD2, 0xAF, 0x7F, 0x04, 0x80, 0x12, 0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x13, 0x54, 0xEC, ++0x4E, 0xF6, 0xD2, 0xAF, 0x02, 0x42, 0x4D, 0x7F, 0x08, 0x08, 0xEF, 0x44, 0x83, 0xF4, 0xC2, 0xAF, ++0x56, 0xC6, 0xD2, 0xAF, 0x54, 0x80, 0x4F, 0xFF, 0x22, 0xC5, 0xF0, 0xF8, 0xA3, 0xE0, 0x28, 0xF0, ++0xC5, 0xF0, 0xF8, 0xE5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 0x83, 0xE0, 0x38, 0xF0, 0x22, 0xEF, ++0x5B, 0xFF, 0xEE, 0x5A, 0xFE, 0xED, 0x59, 0xFD, 0xEC, 0x58, 0xFC, 0x22, 0xEF, 0x4B, 0xFF, 0xEE, ++0x4A, 0xFE, 0xED, 0x49, 0xFD, 0xEC, 0x48, 0xFC, 0x22, 0xE0, 0xFC, 0xA3, 0xE0, 0xFD, 0xA3, 0xE0, ++0xFE, 0xA3, 0xE0, 0xFF, 0x22, 0xE2, 0xFC, 0x08, 0xE2, 0xFD, 0x08, 0xE2, 0xFE, 0x08, 0xE2, 0xFF, ++0x22, 0xE2, 0xFB, 0x08, 0xE2, 0xF9, 0x08, 0xE2, 0xFA, 0x08, 0xE2, 0xCB, 0xF8, 0x22, 0xEC, 0xF2, ++0x08, 0xED, 0xF2, 0x08, 0xEE, 0xF2, 0x08, 0xEF, 0xF2, 0x22, 0xA4, 0x25, 0x82, 0xF5, 0x82, 0xE5, ++0xF0, 0x35, 0x83, 0xF5, 0x83, 0x22, 0xE0, 0xFB, 0xA3, 0xE0, 0xFA, 0xA3, 0xE0, 0xF9, 0x22, 0xEB, ++0xF0, 0xA3, 0xEA, 0xF0, 0xA3, 0xE9, 0xF0, 0x22, 0xD0, 0x83, 0xD0, 0x82, 0xF8, 0xE4, 0x93, 0x70, ++0x12, 0x74, 0x01, 0x93, 0x70, 0x0D, 0xA3, 0xA3, 0x93, 0xF8, 0x74, 0x01, 0x93, 0xF5, 0x82, 0x88, ++0x83, 0xE4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xEF, 0xA3, 0xA3, 0xA3, 0x80, 0xDF, 0x02, 0x45, ++0x8C, 0x02, 0x42, 0xDD, 0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93, 0xA3, 0x40, 0x03, 0xF6, 0x80, 0x01, ++0xF2, 0x08, 0xDF, 0xF4, 0x80, 0x29, 0xE4, 0x93, 0xA3, 0xF8, 0x54, 0x07, 0x24, 0x0C, 0xC8, 0xC3, ++0x33, 0xC4, 0x54, 0x0F, 0x44, 0x20, 0xC8, 0x83, 0x40, 0x04, 0xF4, 0x56, 0x80, 0x01, 0x46, 0xF6, ++0xDF, 0xE4, 0x80, 0x0B, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x45, 0xD1, 0xE4, ++0x7E, 0x01, 0x93, 0x60, 0xBC, 0xA3, 0xFF, 0x54, 0x3F, 0x30, 0xE5, 0x09, 0x54, 0x1F, 0xFE, 0xE4, ++0x93, 0xA3, 0x60, 0x01, 0x0E, 0xCF, 0x54, 0xC0, 0x25, 0xE0, 0x60, 0xA8, 0x40, 0xB8, 0xE4, 0x93, ++0xA3, 0xFA, 0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA, 0xC5, 0x83, ++0xCA, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA, 0xC5, 0x83, 0xCA, 0xDF, 0xE9, 0xDE, 0xE7, 0x80, ++0xBE, 0x00, 0x41, 0x82, 0x09, 0x00, 0x41, 0x82, 0x0A, 0x00, 0x41, 0x82, 0x17, 0x00, 0x59, 0xE2, ++0x5C, 0x24, 0x5E, 0x5D, 0x5F, 0xA1, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0, ++0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0, ++0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0xE6, 0xF0, 0x74, 0x45, 0xA3, 0xF0, 0xD1, 0x35, 0x74, ++0xE6, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x45, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, ++0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, ++0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x00, 0x54, 0xE0, 0x55, 0x35, 0xF5, 0x39, 0xA3, 0xE0, 0x55, ++0x36, 0xF5, 0x3A, 0xA3, 0xE0, 0x55, 0x37, 0xF5, 0x3B, 0xA3, 0xE0, 0x55, 0x38, 0xF5, 0x3C, 0xAD, ++0x39, 0x7F, 0x54, 0x12, 0x32, 0x1E, 0xAD, 0x3A, 0x7F, 0x55, 0x12, 0x32, 0x1E, 0xAD, 0x3B, 0x7F, ++0x56, 0x12, 0x32, 0x1E, 0xAD, 0x3C, 0x7F, 0x57, 0x12, 0x32, 0x1E, 0x53, 0x91, 0xEF, 0x22, 0xC0, ++0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, ++0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, ++0x6F, 0xF0, 0x74, 0x46, 0xA3, 0xF0, 0x12, 0x6C, 0x78, 0xE5, 0x41, 0x30, 0xE4, 0x04, 0x7F, 0x02, ++0x91, 0x27, 0xE5, 0x41, 0x30, 0xE6, 0x03, 0x12, 0x6C, 0xD5, 0xE5, 0x43, 0x30, 0xE0, 0x03, 0x12, ++0x51, 0xC2, 0xE5, 0x43, 0x30, 0xE1, 0x03, 0x12, 0x4D, 0x0C, 0xE5, 0x43, 0x30, 0xE2, 0x03, 0x12, ++0x4C, 0xC1, 0xE5, 0x43, 0x30, 0xE3, 0x03, 0x12, 0x6C, 0xE2, 0xE5, 0x43, 0x30, 0xE4, 0x03, 0x12, ++0x6D, 0x04, 0xE5, 0x43, 0x30, 0xE5, 0x03, 0x12, 0x6D, 0x33, 0xE5, 0x43, 0x30, 0xE6, 0x02, 0xF1, ++0x0F, 0xE5, 0x44, 0x30, 0xE1, 0x03, 0x12, 0x51, 0x7F, 0x74, 0x6F, 0x04, 0x90, 0x01, 0xC4, 0xF0, ++0x74, 0x46, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, ++0xD0, 0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, ++0x80, 0xDE, 0xE0, 0xB4, 0x01, 0x13, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x0D, 0x90, 0x81, 0x2B, 0xE0, ++0x54, 0xFE, 0xF0, 0x54, 0x07, 0x70, 0x02, 0xF1, 0x2A, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0x90, 0x81, ++0x29, 0x30, 0xE0, 0x05, 0xE0, 0xFF, 0x02, 0x74, 0x8F, 0xE0, 0xFF, 0x7D, 0x01, 0xD3, 0x10, 0xAF, ++0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x82, 0x13, 0xED, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x90, 0x82, 0x14, ++0xF0, 0x90, 0x81, 0x24, 0xE0, 0xFE, 0xC4, 0x13, 0x13, 0x54, 0x03, 0x30, 0xE0, 0x03, 0x02, 0x48, ++0xA0, 0xEE, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x30, 0xE0, 0x03, 0x02, 0x48, 0xA0, 0x90, 0x82, ++0x14, 0xE0, 0xFE, 0x6F, 0x70, 0x03, 0x02, 0x48, 0xA0, 0xEF, 0x70, 0x03, 0x02, 0x48, 0x17, 0x24, ++0xFE, 0x70, 0x03, 0x02, 0x48, 0x50, 0x24, 0xFE, 0x60, 0x51, 0x24, 0xFC, 0x70, 0x03, 0x02, 0x48, ++0x8B, 0x24, 0xFC, 0x60, 0x03, 0x02, 0x48, 0xA0, 0xEE, 0xB4, 0x0E, 0x03, 0x12, 0x49, 0x5E, 0x90, ++0x82, 0x14, 0xE0, 0x70, 0x05, 0x7F, 0x01, 0x12, 0x49, 0x93, 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x06, ++0x03, 0x12, 0x49, 0x34, 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x04, 0x0F, 0x90, 0x82, 0x13, 0xE0, 0xFF, ++0x60, 0x05, 0x12, 0x73, 0x75, 0x80, 0x03, 0x12, 0x66, 0x26, 0x90, 0x82, 0x14, 0xE0, 0x64, 0x08, ++0x60, 0x03, 0x02, 0x48, 0xA0, 0x12, 0x73, 0xD3, 0x02, 0x48, 0xA0, 0x90, 0x82, 0x14, 0xE0, 0x70, ++0x05, 0x7F, 0x01, 0x12, 0x49, 0x93, 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x06, 0x03, 0x12, 0x49, 0x34, ++0x90, 0x82, 0x14, 0xE0, 0xB4, 0x0E, 0x09, 0x12, 0x48, 0xA5, 0xBF, 0x01, 0x03, 0x12, 0x49, 0x5E, ++0x90, 0x82, 0x14, 0xE0, 0x64, 0x0C, 0x60, 0x02, 0x01, 0xA0, 0x11, 0xA5, 0xEF, 0x64, 0x01, 0x60, ++0x02, 0x01, 0xA0, 0x11, 0xFA, 0x01, 0xA0, 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x0E, 0x07, 0x11, 0xA5, ++0xBF, 0x01, 0x02, 0x31, 0x5E, 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x06, 0x02, 0x31, 0x34, 0x90, 0x82, ++0x14, 0xE0, 0xB4, 0x0C, 0x07, 0x11, 0xA5, 0xBF, 0x01, 0x02, 0x11, 0xFA, 0x90, 0x82, 0x14, 0xE0, ++0x64, 0x04, 0x70, 0x5C, 0x12, 0x72, 0xF5, 0xEF, 0x64, 0x01, 0x70, 0x54, 0x31, 0xBE, 0x80, 0x50, ++0x90, 0x82, 0x14, 0xE0, 0xB4, 0x0E, 0x07, 0x11, 0xA5, 0xBF, 0x01, 0x02, 0x31, 0x5E, 0x90, 0x82, ++0x14, 0xE0, 0xB4, 0x06, 0x02, 0x31, 0x34, 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x0C, 0x07, 0x11, 0xA5, ++0xBF, 0x01, 0x02, 0x11, 0xFA, 0x90, 0x82, 0x14, 0xE0, 0x70, 0x04, 0x7F, 0x01, 0x31, 0x93, 0x90, ++0x82, 0x14, 0xE0, 0xB4, 0x04, 0x1A, 0x12, 0x73, 0xBB, 0x80, 0x15, 0x90, 0x82, 0x14, 0xE0, 0xB4, ++0x0C, 0x0E, 0x90, 0x81, 0x25, 0xE0, 0xFF, 0x13, 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x02, 0x31, 0xB1, ++0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD1, 0xAB, 0xEF, 0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, ++0x01, 0xF0, 0x80, 0x3D, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, ++0x08, 0x90, 0x01, 0xB8, 0x74, 0x02, 0xF0, 0x80, 0x28, 0xEF, 0xC4, 0x54, 0x0F, 0x30, 0xE0, 0x08, ++0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x19, 0x90, 0x81, 0x29, 0xE0, 0xD3, 0x94, 0x04, 0x40, ++0x08, 0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4, 0xF0, 0x7F, 0x01, ++0x22, 0x90, 0x01, 0xB9, 0x74, 0x02, 0xF0, 0x7F, 0x00, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, ++0x70, 0x31, 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFD, 0xF0, 0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x7F, ++0x01, 0xF1, 0x0D, 0xBF, 0x01, 0x12, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x80, 0xF0, 0x90, 0x81, 0x2A, ++0x74, 0x0E, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, ++0xB8, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x25, 0xE0, 0x90, 0x06, 0x04, 0x20, 0xE0, 0x0C, 0xE0, 0x44, ++0x40, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x04, 0xF0, 0x80, 0x0E, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x81, ++0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x22, 0x90, 0x81, ++0x25, 0xE0, 0xC3, 0x13, 0x20, 0xE0, 0x08, 0x90, 0x81, 0x2A, 0x74, 0x0C, 0xF0, 0x80, 0x1E, 0x90, ++0x06, 0x04, 0xE0, 0x44, 0x40, 0xF0, 0xE0, 0x44, 0x80, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x04, 0xF0, ++0x90, 0x05, 0x27, 0xE0, 0x44, 0x80, 0xF0, 0x90, 0x81, 0x23, 0x74, 0x04, 0xF0, 0x90, 0x05, 0x22, ++0xE4, 0xF0, 0x22, 0x90, 0x82, 0x15, 0xEF, 0xF0, 0x12, 0x54, 0x65, 0x90, 0x82, 0x15, 0xE0, 0x60, ++0x05, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x04, 0xF0, 0x90, 0x81, 0x23, 0xF0, ++0x22, 0x31, 0xE3, 0x90, 0x81, 0x2A, 0x74, 0x08, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x05, ++0x22, 0x74, 0xFF, 0xF0, 0xF1, 0x3A, 0x90, 0x01, 0x37, 0x74, 0x02, 0xF0, 0xFD, 0x7F, 0x03, 0x51, ++0x57, 0x31, 0xE3, 0xE4, 0x90, 0x81, 0x2A, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x05, 0x22, ++0x74, 0xFF, 0xF0, 0xF1, 0x3A, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, 0xCC, 0xF0, 0x00, 0xC0, 0x7F, ++0x8C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x14, ++0x7F, 0x70, 0x7E, 0x0E, 0x12, 0x2E, 0xA2, 0x90, 0x81, 0xF9, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, ++0x00, 0xE4, 0xFD, 0xFF, 0x12, 0x55, 0x1C, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x44, ++0x80, 0xFC, 0x90, 0x82, 0x05, 0x12, 0x20, 0xCE, 0x90, 0x82, 0x05, 0x12, 0x44, 0xD9, 0x90, 0x85, ++0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x01, 0x00, 0x74, 0x3F, ++0xF0, 0xA3, 0xE0, 0x54, 0xFD, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x20, 0xF0, 0x22, 0x90, 0x01, ++0x34, 0x74, 0x40, 0xF0, 0xFD, 0xE4, 0xFF, 0x74, 0x3D, 0x2F, 0xF8, 0xE6, 0x4D, 0xFE, 0xF6, 0x74, ++0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, ++0xC3, 0xC0, 0xD0, 0xE4, 0x90, 0x81, 0xCB, 0xF0, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, ++0x81, 0x1F, 0xE0, 0x54, 0xFE, 0x4E, 0xFE, 0xF0, 0xEF, 0x54, 0x02, 0xFF, 0xEE, 0x54, 0xFD, 0x4F, ++0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x04, 0xFD, 0xEF, 0x54, 0xFB, 0x4D, 0xFF, 0x90, 0x81, ++0x1F, 0xF0, 0xEE, 0x54, 0x08, 0xFE, 0xEF, 0x54, 0xF7, 0x4E, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, ++0x54, 0x10, 0xFD, 0xEF, 0x54, 0xEF, 0x4D, 0xFF, 0x90, 0x81, 0x1F, 0xF0, 0xEE, 0x54, 0x20, 0xFE, ++0xEF, 0x54, 0xDF, 0x4E, 0xF0, 0x12, 0x1F, 0xA4, 0xC3, 0x13, 0x20, 0xE0, 0x02, 0x61, 0x5E, 0x90, ++0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x6D, 0x90, 0x81, 0xCB, 0x74, 0x21, 0xF0, 0xEF, 0x13, 0x13, ++0x54, 0x3F, 0x30, 0xE0, 0x0B, 0x51, 0x4E, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x08, 0xF0, 0x80, 0x0C, ++0xE4, 0x90, 0x81, 0x20, 0xF0, 0xA3, 0xF0, 0x7D, 0x40, 0xFF, 0x91, 0x26, 0x90, 0x81, 0x1F, 0xE0, ++0xFD, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x12, 0xF0, ++0xED, 0xC4, 0x54, 0x0F, 0x30, 0xE0, 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x14, 0xF0, 0x90, 0x81, ++0x1F, 0xE0, 0xC4, 0x13, 0x54, 0x07, 0x30, 0xE0, 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x80, 0xF0, ++0x90, 0x81, 0xCB, 0xE0, 0x90, 0x05, 0x27, 0xF0, 0x90, 0x81, 0x22, 0xE0, 0x60, 0x02, 0x81, 0x17, ++0x7F, 0x01, 0x80, 0x15, 0x90, 0x81, 0xCB, 0x74, 0x01, 0xF0, 0x90, 0x05, 0x27, 0xF0, 0x90, 0x81, ++0x22, 0xE0, 0x64, 0x04, 0x60, 0x02, 0x81, 0x17, 0xFF, 0x12, 0x53, 0x0E, 0x81, 0x17, 0x90, 0x81, ++0x1F, 0xE0, 0xFF, 0x20, 0xE0, 0x02, 0x61, 0xE7, 0x90, 0x81, 0xCB, 0x74, 0x31, 0xF0, 0xEF, 0x13, ++0x13, 0x54, 0x3F, 0x30, 0xE0, 0x0B, 0x51, 0x4E, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x08, 0xF0, 0x80, ++0x06, 0x7D, 0x40, 0xE4, 0xFF, 0x91, 0x26, 0x90, 0x81, 0x1F, 0xE0, 0xFD, 0x13, 0x13, 0x13, 0x54, ++0x1F, 0x30, 0xE0, 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x02, 0xF0, 0xED, 0xC4, 0x54, 0x0F, 0x30, ++0xE0, 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x04, 0xF0, 0x90, 0x81, 0xCB, 0xE0, 0x90, 0x05, 0x27, ++0xF0, 0x90, 0x81, 0x23, 0xE0, 0x64, 0x02, 0x70, 0x1D, 0xFD, 0x7F, 0x04, 0x12, 0x47, 0x3D, 0x12, ++0x51, 0x73, 0xBF, 0x01, 0x09, 0x90, 0x81, 0x29, 0xE0, 0xFF, 0x7D, 0x01, 0x80, 0x03, 0xE4, 0xFD, ++0xFF, 0x12, 0x47, 0x3D, 0x80, 0x41, 0x90, 0x81, 0x2A, 0xE0, 0x90, 0x81, 0x23, 0xF0, 0x90, 0x05, ++0x27, 0xE0, 0x44, 0x40, 0xF0, 0x80, 0x30, 0x90, 0x81, 0xCB, 0x74, 0x01, 0xF0, 0x90, 0x05, 0x27, ++0xF0, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x02, 0x06, 0x7D, 0x01, 0x7F, 0x04, 0x80, 0x0B, 0x90, 0x81, ++0x23, 0xE0, 0xB4, 0x08, 0x07, 0x7D, 0x01, 0x7F, 0x0C, 0x12, 0x47, 0x3D, 0xD1, 0x34, 0x90, 0x81, ++0x29, 0x12, 0x47, 0x39, 0x12, 0x5A, 0xA7, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x7D, 0x02, 0x7F, 0x02, ++0x91, 0x26, 0x7D, 0x01, 0x7F, 0x02, 0x74, 0x3D, 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, 0xFE, ++0xF6, 0x74, 0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0xEF, 0x70, ++0x37, 0x7D, 0x78, 0x7F, 0x02, 0x91, 0x26, 0x7D, 0x02, 0x7F, 0x03, 0x91, 0x26, 0x7D, 0xC8, 0x7F, ++0x02, 0x12, 0x71, 0x8F, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0xF0, 0x7D, ++0x01, 0x7F, 0x0C, 0x12, 0x47, 0x3D, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, ++0x90, 0x06, 0x0A, 0xE0, 0x54, 0xF8, 0xF0, 0x22, 0x90, 0x01, 0x36, 0x74, 0x78, 0xF0, 0xA3, 0x74, ++0x02, 0xF0, 0x7D, 0x78, 0xFF, 0x51, 0x57, 0x7D, 0x02, 0x7F, 0x03, 0x51, 0x57, 0x90, 0x06, 0x0A, ++0xE0, 0x44, 0x07, 0xF0, 0x90, 0x81, 0x32, 0xA3, 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90, 0x80, 0xDE, ++0xE0, 0xB4, 0x01, 0x15, 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x20, ++0xE2, 0x0E, 0x7D, 0x01, 0x7F, 0x04, 0x02, 0x47, 0x3D, 0x90, 0x81, 0x25, 0xE0, 0x44, 0x04, 0xF0, ++0x22, 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x08, 0x90, 0x81, 0x23, 0xE0, 0x64, 0x02, 0x60, ++0x3A, 0x90, 0x81, 0x27, 0xE0, 0x70, 0x04, 0xEF, 0x30, 0xE0, 0x0A, 0x90, 0x81, 0x2A, 0xE0, 0x64, ++0x02, 0x60, 0x28, 0xB1, 0x83, 0x90, 0x81, 0x25, 0xE0, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, ++0x14, 0x90, 0x81, 0x2D, 0xE0, 0xFF, 0xA3, 0xE0, 0x6F, 0x70, 0x0A, 0xF1, 0xCD, 0x91, 0x1C, 0x90, ++0x81, 0x2E, 0xE0, 0x14, 0xF0, 0x90, 0x01, 0xE6, 0xE0, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x1F, 0xE0, ++0x30, 0xE0, 0x06, 0x90, 0x81, 0x21, 0x74, 0x01, 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x45, 0x90, ++0x81, 0x25, 0xE0, 0xFF, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, 0x12, 0x90, 0x01, 0x3B, 0xE0, ++0x30, 0xE4, 0x0B, 0x91, 0x1C, 0x90, 0x81, 0x2D, 0xE0, 0x14, 0x90, 0x05, 0x73, 0xF0, 0x90, 0x82, ++0x0B, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9, 0xC3, 0x90, 0x82, 0x0C, 0xE0, 0x94, 0x80, 0x90, ++0x82, 0x0B, 0xE0, 0x64, 0x80, 0x94, 0x80, 0x40, 0x0B, 0x90, 0x01, 0x98, 0xE0, 0x54, 0xFE, 0xF0, ++0xE0, 0x44, 0x01, 0xF0, 0x12, 0x75, 0xF8, 0xD1, 0xD6, 0x90, 0x81, 0x3F, 0xE0, 0x30, 0xE0, 0x0C, ++0xE4, 0xF5, 0x1D, 0xA3, 0xF1, 0xFB, 0x90, 0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, 0x01, 0xBE, 0xE0, ++0x04, 0xF0, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x60, 0x02, 0xC1, 0x23, 0x90, 0x81, 0x27, ++0xE0, 0x70, 0x02, 0xC1, 0x23, 0x90, 0x81, 0x26, 0xE0, 0xC4, 0x54, 0x0F, 0x64, 0x01, 0x70, 0x22, ++0x90, 0x06, 0xAB, 0xE0, 0x90, 0x81, 0x2E, 0xF0, 0x90, 0x06, 0xAA, 0xE0, 0x90, 0x81, 0x2D, 0xF0, ++0xA3, 0xE0, 0xFF, 0x70, 0x08, 0x90, 0x81, 0x2D, 0xE0, 0xFE, 0xFF, 0x80, 0x00, 0x90, 0x81, 0x2E, ++0xEF, 0xF0, 0x90, 0x81, 0x25, 0xE0, 0x44, 0x04, 0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90, 0x81, ++0x32, 0xA3, 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, ++0x02, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x26, 0xE0, ++0xFF, 0xC4, 0x54, 0x0F, 0x24, 0xFD, 0x50, 0x02, 0x80, 0x0F, 0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0, ++0x05, 0x12, 0x6D, 0xF2, 0x80, 0x03, 0x12, 0x6E, 0xC9, 0x90, 0x81, 0x25, 0xE0, 0x13, 0x13, 0x13, ++0x54, 0x1F, 0x30, 0xE0, 0x0E, 0x90, 0x81, 0x2D, 0xE0, 0xFF, 0xA3, 0xE0, 0xB5, 0x07, 0x04, 0xF1, ++0xCD, 0x91, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0xC3, 0x13, 0x20, 0xE0, 0x07, 0x90, 0x81, 0x25, 0xE0, ++0x44, 0x04, 0xF0, 0x22, 0xD1, 0xAB, 0xEF, 0x70, 0x02, 0xD1, 0x3C, 0x22, 0x90, 0x81, 0x27, 0xE0, ++0x64, 0x01, 0x70, 0x66, 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x60, 0x51, 0x90, 0x81, 0x2A, 0xE0, ++0x70, 0x03, 0xFF, 0x31, 0x93, 0x90, 0x81, 0x2A, 0xE0, 0x64, 0x0C, 0x60, 0x03, 0x12, 0x66, 0x26, ++0x90, 0x01, 0x5B, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x04, 0xF0, 0xD1, 0xAB, 0xEF, 0x64, 0x01, ++0x60, 0x38, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A, 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4, ++0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0x12, 0x50, 0x05, 0x90, 0x01, 0x5B, 0x74, 0x05, 0xF0, 0x90, ++0x06, 0x92, 0x74, 0x01, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x08, 0xF0, 0x22, 0x90, 0x81, 0x2A, ++0xE0, 0x70, 0x07, 0x7D, 0x01, 0x7F, 0x04, 0x12, 0x47, 0x3D, 0x22, 0x90, 0x04, 0x1A, 0xE0, 0xF4, ++0x60, 0x03, 0x7F, 0x00, 0x22, 0x90, 0x04, 0x1B, 0xE0, 0x54, 0x07, 0x64, 0x07, 0x7F, 0x01, 0x60, ++0x02, 0x7F, 0x00, 0x22, 0x12, 0x50, 0x60, 0x90, 0x81, 0x2D, 0xE0, 0x14, 0x90, 0x05, 0x73, 0xF0, ++0x7D, 0x02, 0x7F, 0x02, 0x51, 0x57, 0x90, 0x81, 0x42, 0xE0, 0x30, 0xE0, 0x2D, 0x90, 0x80, 0xDE, ++0xE0, 0xB4, 0x01, 0x26, 0x90, 0x82, 0x17, 0xE0, 0x04, 0xF0, 0xE0, 0xB4, 0x0A, 0x0B, 0x90, 0x81, ++0x44, 0xE0, 0x04, 0xF0, 0xE4, 0x90, 0x82, 0x17, 0xF0, 0x90, 0x81, 0x44, 0xE0, 0xFF, 0x90, 0x81, ++0x43, 0xE0, 0xB5, 0x07, 0x05, 0xE4, 0xA3, 0xF0, 0xF1, 0x0B, 0x22, 0xE4, 0xFF, 0x8F, 0x53, 0x90, ++0x04, 0x1D, 0xE0, 0x60, 0x19, 0x90, 0x05, 0x22, 0xE0, 0xF5, 0x56, 0x74, 0xFF, 0xF0, 0xF1, 0x3A, ++0xBF, 0x01, 0x03, 0x12, 0x74, 0xFB, 0x90, 0x05, 0x22, 0xE5, 0x56, 0xF0, 0x80, 0x03, 0x12, 0x74, ++0xFB, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, 0x7F, 0x01, 0x22, 0xE4, 0x90, 0x82, 0x0F, 0xF0, 0xA3, ++0xF0, 0x90, 0x05, 0xF8, 0xE0, 0x70, 0x0F, 0xA3, 0xE0, 0x70, 0x0B, 0xA3, 0xE0, 0x70, 0x07, 0xA3, ++0xE0, 0x70, 0x03, 0x7F, 0x01, 0x22, 0xD3, 0x90, 0x82, 0x10, 0xE0, 0x94, 0xE8, 0x90, 0x82, 0x0F, ++0xE0, 0x94, 0x03, 0x40, 0x0A, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x20, 0xF0, 0x7F, 0x00, 0x22, 0x7F, ++0x32, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x90, 0x82, 0x0F, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9, ++0x80, 0xBF, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0x3F, 0xF0, ++0xEF, 0x60, 0x1D, 0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x10, ++0xF0, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0x22, ++0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xEF, 0xF0, 0x74, 0x1F, ++0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x40, 0xF0, 0x22, 0xEF, 0x14, 0x90, ++0x05, 0x73, 0xF0, 0x90, 0x01, 0x3F, 0x74, 0x10, 0xF0, 0xFD, 0x7F, 0x03, 0x74, 0x45, 0x2F, 0xF8, ++0xE6, 0x4D, 0xFE, 0xF6, 0x74, 0x38, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, ++0x22, 0xE0, 0x44, 0x02, 0xF0, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x39, 0xE0, 0xF5, 0x1E, 0xE4, 0xFB, ++0xFD, 0x7F, 0x54, 0x7E, 0x01, 0x8E, 0x19, 0x8F, 0x1A, 0xE5, 0x1E, 0x54, 0x07, 0xC4, 0x33, 0x54, ++0xE0, 0x85, 0x19, 0x83, 0x85, 0x1A, 0x82, 0xF0, 0xE5, 0x1D, 0x54, 0x07, 0xC4, 0x33, 0x54, 0xE0, ++0xFF, 0xE5, 0x1E, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x4F, 0xA3, 0xF0, 0xEB, 0x54, 0x07, 0xC4, 0x33, ++0x54, 0xE0, 0xFF, 0xE5, 0x1D, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x4F, 0x85, 0x1A, 0x82, 0x85, 0x19, ++0x83, 0xA3, 0xA3, 0xF0, 0xBD, 0x01, 0x0C, 0x85, 0x1A, 0x82, 0x8E, 0x83, 0xA3, 0xA3, 0xA3, 0x74, ++0x03, 0xF0, 0x22, 0x85, 0x1A, 0x82, 0x85, 0x19, 0x83, 0xA3, 0xA3, 0xA3, 0x74, 0x01, 0xF0, 0x22, ++0xE4, 0x90, 0x81, 0x4D, 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x58, 0x90, 0x80, 0xDE, 0xE0, 0x64, ++0x01, 0x70, 0x50, 0x90, 0x81, 0x4D, 0x04, 0xF0, 0xE4, 0x90, 0x81, 0x2E, 0xF0, 0x90, 0x81, 0x1F, ++0xE0, 0x30, 0xE0, 0x15, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x02, 0x05, 0xE4, 0x90, 0x81, 0x4D, 0xF0, ++0x31, 0x73, 0xEF, 0x70, 0x04, 0x90, 0x81, 0x4D, 0xF0, 0x90, 0x81, 0x4D, 0xE0, 0x60, 0x24, 0x90, ++0x81, 0x2B, 0xE0, 0x44, 0x10, 0xF0, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x2F, 0x12, 0x4F, 0xFB, 0x90, ++0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x20, 0xE2, 0x07, 0x7D, 0x01, 0x7F, 0x04, ++0x12, 0x47, 0x3D, 0x22, 0xE4, 0x90, 0x81, 0x4C, 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x70, 0x02, 0x21, ++0x72, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x60, 0x02, 0x21, 0x72, 0x90, 0x81, 0x26, 0xE0, 0xFF, ++0xC4, 0x54, 0x0F, 0x60, 0x22, 0x24, 0xFE, 0x60, 0x03, 0x04, 0x70, 0x21, 0x90, 0x81, 0x2E, 0xE0, ++0x14, 0xF0, 0xE0, 0xFF, 0x60, 0x06, 0x90, 0x81, 0x30, 0xE0, 0x60, 0x11, 0xEF, 0x70, 0x08, 0x90, ++0x81, 0x2D, 0xE0, 0xA3, 0xF0, 0x80, 0x00, 0x90, 0x81, 0x4C, 0x74, 0x01, 0xF0, 0x90, 0x81, 0x1F, ++0xE0, 0x30, 0xE0, 0x15, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x02, 0x05, 0xE4, 0x90, 0x81, 0x4C, 0xF0, ++0x31, 0x73, 0xEF, 0x70, 0x04, 0x90, 0x81, 0x4C, 0xF0, 0x90, 0x81, 0x4C, 0xE0, 0x60, 0x43, 0x90, ++0x81, 0x2B, 0xE0, 0x44, 0x10, 0xF0, 0x90, 0x81, 0x30, 0xE0, 0x60, 0x03, 0xB4, 0x01, 0x09, 0xE4, ++0xF5, 0x1D, 0x90, 0x81, 0x30, 0xE0, 0x80, 0x0D, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x30, 0xE0, 0x75, ++0xF0, 0x03, 0xA4, 0x24, 0xFE, 0xFF, 0x90, 0x81, 0x2F, 0xE0, 0x2F, 0x12, 0x4F, 0xFC, 0x90, 0x01, ++0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x20, 0xE2, 0x07, 0x7D, 0x01, 0x7F, 0x04, 0x12, ++0x47, 0x3D, 0x22, 0x90, 0x05, 0x43, 0xE0, 0x7F, 0x00, 0x30, 0xE7, 0x02, 0x7F, 0x01, 0x22, 0x90, ++0x81, 0x27, 0xE0, 0x70, 0x07, 0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0, 0x11, 0x90, 0x81, 0x1F, 0xE0, ++0x30, 0xE0, 0x07, 0x31, 0x73, 0xBF, 0x01, 0x05, 0x41, 0x5B, 0x12, 0x4E, 0x3C, 0x22, 0xD3, 0x10, ++0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0x1E, 0xE0, 0xB4, 0x01, 0x04, 0x7F, 0x04, 0x80, 0x0B, ++0x31, 0x73, 0xBF, 0x01, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x02, 0x71, 0x0E, 0xD0, 0xD0, 0x92, ++0xAF, 0x22, 0x90, 0x81, 0x4B, 0xE0, 0x60, 0x0F, 0xE4, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x02, ++0xF0, 0x90, 0x05, 0xFC, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0, 0x10, 0xA3, 0x74, ++0x01, 0xF0, 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0xC3, 0x13, 0x30, 0xE0, 0x02, 0x31, 0x9E, 0x11, 0xC4, ++0x90, 0x81, 0x3F, 0xE0, 0x30, 0xE0, 0x07, 0x91, 0x65, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x22, 0x90, ++0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x3D, 0x90, 0x81, 0x23, 0xE0, 0x7E, 0x00, 0xB4, 0x02, 0x02, ++0x7E, 0x01, 0x90, 0x81, 0x22, 0xE0, 0x7D, 0x00, 0xB4, 0x04, 0x02, 0x7D, 0x01, 0xED, 0x4E, 0x70, ++0x23, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x02, 0x21, 0x9E, 0x51, 0x45, 0x90, 0x81, 0x23, 0xE0, 0xB4, ++0x08, 0x06, 0xE4, 0xFD, 0x7F, 0x0C, 0x80, 0x09, 0x90, 0x81, 0x23, 0xE0, 0x70, 0x06, 0xFD, 0x7F, ++0x04, 0x12, 0x47, 0x3D, 0x22, 0x90, 0x81, 0x1E, 0xE0, 0xB4, 0x01, 0x0F, 0x90, 0x81, 0x23, 0xE0, ++0x64, 0x02, 0x60, 0x07, 0x7D, 0x01, 0x7F, 0x02, 0x12, 0x47, 0x3D, 0x90, 0x81, 0x27, 0xE0, 0x64, ++0x02, 0x60, 0x14, 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x60, 0x0C, 0x12, 0x4E, 0xAB, 0xEF, 0x70, ++0x06, 0xFD, 0x7F, 0x0C, 0x12, 0x47, 0x3D, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x3F, ++0x90, 0x81, 0x23, 0xE0, 0x7E, 0x00, 0xB4, 0x02, 0x02, 0x7E, 0x01, 0x90, 0x81, 0x22, 0xE0, 0x7D, ++0x00, 0xB4, 0x04, 0x02, 0x7D, 0x01, 0xED, 0x4E, 0x70, 0x25, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x02, ++0x21, 0x9E, 0x12, 0x74, 0xAC, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x0C, 0x06, 0xE4, 0xFD, 0x7F, 0x08, ++0x80, 0x0A, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x04, 0x06, 0xE4, 0xFD, 0xFF, 0x12, 0x47, 0x3D, 0x22, ++0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x1F, 0x12, 0x1F, 0xA4, ++0xFF, 0x90, 0x81, 0x1E, 0xF0, 0xBF, 0x01, 0x12, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16, 0x90, 0x00, ++0x01, 0x12, 0x1F, 0xBD, 0x64, 0x01, 0x60, 0x21, 0x80, 0x1D, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16, ++0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x64, 0x01, 0x60, 0x0F, 0x90, 0x81, 0x1F, 0xE0, 0x20, 0xE0, ++0x06, 0xE4, 0xFF, 0x71, 0x0E, 0x80, 0x02, 0x31, 0x9E, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, ++0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0x22, 0xE0, 0x90, 0x82, 0x16, 0xF0, 0x6F, 0x70, 0x02, ++0x81, 0x04, 0xEF, 0x14, 0x60, 0x3E, 0x14, 0x60, 0x62, 0x14, 0x70, 0x02, 0x61, 0xB8, 0x14, 0x70, ++0x02, 0x61, 0xDF, 0x24, 0x04, 0x60, 0x02, 0x81, 0x04, 0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x04, ++0x04, 0x91, 0x41, 0x81, 0x04, 0xEF, 0xB4, 0x02, 0x04, 0x91, 0x50, 0x81, 0x04, 0x90, 0x82, 0x16, ++0xE0, 0xFF, 0xB4, 0x03, 0x04, 0x91, 0x54, 0x81, 0x04, 0xEF, 0x64, 0x01, 0x60, 0x02, 0x81, 0x04, ++0x91, 0x43, 0x81, 0x04, 0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x04, 0x04, 0x91, 0xF3, 0x81, 0x04, ++0xEF, 0xB4, 0x02, 0x04, 0x91, 0x58, 0x81, 0x04, 0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x03, 0x04, ++0x91, 0xE8, 0x81, 0x04, 0xEF, 0x70, 0x7D, 0x91, 0x2B, 0x80, 0x79, 0x90, 0x82, 0x16, 0xE0, 0xB4, ++0x04, 0x05, 0x12, 0x74, 0x60, 0x80, 0x6D, 0x90, 0x82, 0x16, 0xE0, 0xB4, 0x01, 0x04, 0x91, 0x21, ++0x80, 0x62, 0x90, 0x82, 0x16, 0xE0, 0xB4, 0x03, 0x05, 0x12, 0x74, 0x71, 0x80, 0x56, 0x90, 0x82, ++0x16, 0xE0, 0x70, 0x50, 0x91, 0x1F, 0x80, 0x4C, 0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x04, 0x05, ++0x12, 0x74, 0x4C, 0x80, 0x3F, 0xEF, 0xB4, 0x01, 0x04, 0x91, 0x34, 0x80, 0x37, 0xEF, 0xB4, 0x02, ++0x04, 0x91, 0xDF, 0x80, 0x2F, 0x90, 0x82, 0x16, 0xE0, 0x70, 0x29, 0x91, 0x32, 0x80, 0x25, 0x90, ++0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x03, 0x05, 0x12, 0x74, 0x7B, 0x80, 0x18, 0xEF, 0xB4, 0x01, 0x04, ++0x91, 0x0B, 0x80, 0x10, 0xEF, 0xB4, 0x02, 0x04, 0xB1, 0x06, 0x80, 0x08, 0x90, 0x82, 0x16, 0xE0, ++0x70, 0x02, 0x91, 0x09, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x91, 0x2B, 0x90, 0x05, 0x22, 0x74, 0x6F, ++0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0, 0x90, 0x81, 0x22, 0x74, 0x04, 0xF0, 0x22, 0x91, ++0x2B, 0x12, 0x49, 0xDD, 0x90, 0x81, 0x22, 0x74, 0x02, 0xF0, 0x22, 0x90, 0x81, 0x22, 0x74, 0x01, ++0xF0, 0x22, 0x91, 0x2B, 0x90, 0x05, 0x22, 0x74, 0xFF, 0xF0, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0, ++0x22, 0x91, 0xF3, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0, 0xE4, 0x90, 0x81, 0x22, 0xF0, 0x22, ++0x91, 0x58, 0x80, 0xEF, 0x91, 0xE8, 0x80, 0xEB, 0x91, 0x65, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, ++0x81, 0x22, 0x04, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x01, 0x01, 0xE0, ++0x44, 0x02, 0xF0, 0x90, 0x01, 0x00, 0x74, 0xFF, 0xF0, 0x90, 0x06, 0xB7, 0x74, 0x09, 0xF0, 0x90, ++0x06, 0xB4, 0x74, 0x86, 0xF0, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x54, 0x7F, 0xFC, ++0x90, 0x82, 0x01, 0x12, 0x20, 0xCE, 0x90, 0x82, 0x01, 0x12, 0x44, 0xD9, 0x90, 0x85, 0xBB, 0x12, ++0x20, 0xCE, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, 0xCC, ++0xC0, 0x00, 0xC0, 0x7F, 0x8C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, ++0x00, 0xC0, 0x00, 0x14, 0x7F, 0x70, 0x7E, 0x0E, 0x12, 0x2E, 0xA2, 0x90, 0x81, 0xF9, 0x12, 0x20, ++0xDA, 0x00, 0x03, 0x3E, 0x60, 0xE4, 0xFD, 0xFF, 0xB1, 0x1C, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x91, ++0x65, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0, 0x22, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81, 0x22, ++0x04, 0xF0, 0x22, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x90, ++0x81, 0x22, 0x74, 0x01, 0xF0, 0x22, 0x91, 0x65, 0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x90, 0x05, ++0x27, 0xE0, 0x54, 0xBF, 0xF0, 0x90, 0x81, 0x22, 0x74, 0x04, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, ++0xC3, 0xC0, 0xD0, 0xC0, 0x07, 0xC0, 0x05, 0x90, 0x81, 0xF9, 0x12, 0x44, 0xD9, 0x90, 0x81, 0xE5, ++0x12, 0x20, 0xCE, 0xD0, 0x05, 0xD0, 0x07, 0x12, 0x60, 0xF5, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, ++0x81, 0xC8, 0x12, 0x45, 0x1F, 0xEF, 0x12, 0x45, 0x28, 0x55, 0x71, 0x00, 0x55, 0x7A, 0x01, 0x55, ++0x83, 0x02, 0x55, 0x8B, 0x03, 0x55, 0x94, 0x04, 0x55, 0x9C, 0x20, 0x55, 0xA4, 0x21, 0x55, 0xAD, ++0x23, 0x55, 0xB5, 0x24, 0x55, 0xBE, 0x25, 0x55, 0xC7, 0x26, 0x55, 0xCF, 0xC0, 0x00, 0x00, 0x55, ++0xD8, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, 0x02, 0x6A, 0xB0, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, ++0x02, 0x65, 0x81, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, 0x41, 0xC0, 0x90, 0x81, 0xC8, 0x12, 0x45, ++0x16, 0x02, 0x75, 0xD8, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, 0x80, 0x44, 0x90, 0x81, 0xC8, 0x12, ++0x45, 0x16, 0xC1, 0x4B, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, 0x02, 0x6A, 0xF8, 0x90, 0x81, 0xC8, ++0x12, 0x45, 0x16, 0xE1, 0xE1, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, 0x02, 0x4A, 0x6C, 0x90, 0x81, ++0xC8, 0x12, 0x45, 0x16, 0x02, 0x6B, 0x3E, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, 0x80, 0x3E, 0x90, ++0x81, 0xC8, 0x12, 0x45, 0x16, 0x02, 0x6B, 0x4E, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x01, 0xF0, 0x22, ++0x12, 0x5A, 0x4B, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, 0x81, 0x45, 0xE0, 0x54, 0xFE, ++0x4E, 0xF0, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x14, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x81, ++0x46, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x47, 0xF0, 0x22, 0x12, 0x1F, 0xA4, ++0xFF, 0x54, 0x01, 0xFE, 0x90, 0x81, 0x3F, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0x90, 0x00, 0x01, 0x12, ++0x1F, 0xBD, 0xFE, 0x90, 0x05, 0x54, 0xE0, 0xC3, 0x9E, 0x90, 0x81, 0x40, 0xF0, 0xEF, 0x20, 0xE0, ++0x07, 0x91, 0x65, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81, 0x3F, 0xE0, 0x54, 0x01, 0x90, 0x01, ++0xBC, 0xF0, 0x90, 0x81, 0x40, 0xE0, 0x90, 0x01, 0xBD, 0xF0, 0x22, 0x12, 0x1F, 0xA4, 0xFF, 0x54, ++0x7F, 0x90, 0x81, 0x27, 0xF0, 0xEF, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0xA3, 0xF0, 0x90, 0x00, ++0x01, 0x12, 0x1F, 0xBD, 0xFF, 0x54, 0xF0, 0xC4, 0x54, 0x0F, 0xFE, 0x90, 0x81, 0x26, 0xE0, 0x54, ++0xF0, 0x4E, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0x54, 0x01, 0x25, 0xE0, 0xFE, 0x90, 0x81, ++0x24, 0xE0, 0x54, 0xFD, 0x4E, 0xF0, 0xEF, 0x54, 0x0F, 0xC4, 0x54, 0xF0, 0xFF, 0x90, 0x81, 0x26, ++0xE0, 0x54, 0x0F, 0x4F, 0xF0, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x29, 0xF0, 0xD1, ++0xC6, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x90, ++0x01, 0xBA, 0xF0, 0x90, 0x81, 0x29, 0xE0, 0x90, 0x01, 0xBB, 0xF0, 0x90, 0x81, 0x26, 0xE0, 0x54, ++0x0F, 0x90, 0x01, 0xBE, 0xF0, 0x22, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x1F, 0x12, 0x72, 0xB3, 0x90, ++0x81, 0x27, 0xE0, 0xFF, 0x12, 0x4C, 0x3E, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x19, 0x90, 0x81, 0xCB, ++0x12, 0x45, 0x16, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x54, 0x0F, 0xFF, 0x90, 0x00, 0x02, 0x12, ++0x1F, 0xBD, 0xFD, 0x12, 0x72, 0xC4, 0x22, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, ++0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, ++0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0xF7, 0xF0, 0x74, 0x56, 0xA3, 0xF0, 0x12, 0x6C, ++0xA5, 0xE5, 0x49, 0x30, 0xE1, 0x03, 0x12, 0x6F, 0x79, 0xE5, 0x49, 0x30, 0xE2, 0x02, 0xF1, 0xA5, ++0xE5, 0x49, 0x30, 0xE3, 0x03, 0x12, 0x6F, 0x8D, 0xE5, 0x4A, 0x30, 0xE0, 0x03, 0x12, 0x6F, 0xC9, ++0xE5, 0x4A, 0x30, 0xE4, 0x03, 0x12, 0x70, 0x22, 0xE5, 0x4B, 0x30, 0xE1, 0x02, 0x51, 0x78, 0xE5, ++0x4B, 0x30, 0xE0, 0x02, 0x31, 0xFF, 0xE5, 0x4B, 0x30, 0xE3, 0x02, 0xF1, 0xE0, 0xE5, 0x4C, 0x30, ++0xE1, 0x05, 0x7F, 0x03, 0x12, 0x44, 0x27, 0xE5, 0x4C, 0x30, 0xE4, 0x03, 0x12, 0x4E, 0xC4, 0xE5, ++0x4C, 0x30, 0xE5, 0x03, 0x12, 0x70, 0x38, 0xE5, 0x4C, 0x30, 0xE6, 0x03, 0x12, 0x70, 0xCE, 0x74, ++0xF7, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x56, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, ++0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, ++0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x34, 0x90, 0x06, 0x92, 0xE0, 0x30, ++0xE0, 0x23, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A, 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4, ++0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0x11, 0x05, 0x90, 0x01, 0x5B, 0x74, 0x05, 0xF0, 0x90, 0x06, ++0x92, 0x74, 0x01, 0xF0, 0x22, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xF7, 0xF0, 0x12, 0x47, 0x2A, 0x22, ++0x22, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0x31, 0xF0, 0x22, 0x90, 0x01, 0xC8, 0xE4, 0xF0, 0xA3, 0xF0, ++0xA3, 0xF0, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x51, 0x7F, 0xFF, 0xFE, 0x12, 0x2B, 0x27, 0xBF, 0x01, ++0x09, 0x90, 0x81, 0x51, 0xE0, 0x64, 0x03, 0x60, 0x03, 0x22, 0x01, 0xAB, 0xE4, 0x90, 0x81, 0x56, ++0xF0, 0x90, 0x81, 0x56, 0xE0, 0xFF, 0xC3, 0x94, 0x02, 0x40, 0x02, 0x01, 0xE6, 0xC3, 0x74, 0xFE, ++0x9F, 0xFF, 0xE4, 0x94, 0x00, 0xFE, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x52, 0x12, 0x2B, 0x27, 0xEF, ++0x64, 0x01, 0x70, 0x77, 0x90, 0x81, 0x52, 0xE0, 0xFF, 0x54, 0xC0, 0xFE, 0x60, 0x05, 0xEF, 0x54, ++0x0C, 0x70, 0x16, 0x90, 0x81, 0x52, 0xE0, 0xFF, 0x54, 0x30, 0x60, 0x67, 0xEF, 0x54, 0x03, 0x60, ++0x62, 0x90, 0x81, 0x53, 0x74, 0x01, 0xF0, 0x80, 0x05, 0xE4, 0x90, 0x81, 0x53, 0xF0, 0x90, 0x81, ++0x53, 0xE0, 0x90, 0x81, 0x52, 0x70, 0x16, 0xE0, 0xFF, 0xEE, 0x13, 0x13, 0x54, 0x3F, 0x90, 0x81, ++0x54, 0xF0, 0xEF, 0x54, 0x0C, 0x13, 0x13, 0x54, 0x3F, 0xA3, 0xF0, 0x80, 0x0D, 0xE0, 0xFE, 0x54, ++0x30, 0x90, 0x81, 0x54, 0xF0, 0xEE, 0x54, 0x03, 0xA3, 0xF0, 0x90, 0x81, 0x54, 0xE0, 0x64, 0x30, ++0x70, 0x54, 0xA3, 0xE0, 0x64, 0x02, 0x70, 0x4E, 0x90, 0x00, 0xF5, 0xE0, 0x54, 0x40, 0x90, 0x81, ++0x57, 0xF0, 0xE0, 0x70, 0x41, 0xA3, 0x74, 0x02, 0xF0, 0x80, 0x10, 0x90, 0x81, 0x58, 0x74, 0x01, ++0xF0, 0x80, 0x08, 0x90, 0x81, 0x56, 0xE0, 0x04, 0xF0, 0x01, 0x11, 0x90, 0x01, 0xC4, 0x74, 0xE9, ++0xF0, 0x74, 0x57, 0xA3, 0xF0, 0x90, 0x81, 0x58, 0xE0, 0x90, 0x01, 0xC8, 0xF0, 0x90, 0x81, 0x52, ++0xE0, 0x90, 0x01, 0xC9, 0xF0, 0x90, 0x81, 0x53, 0xE0, 0x90, 0x01, 0xCA, 0xF0, 0xE4, 0xFD, 0x7F, ++0x1F, 0x12, 0x32, 0x1E, 0x80, 0xD5, 0x22, 0x90, 0x00, 0xF7, 0xE0, 0x20, 0xE7, 0x09, 0xE0, 0x7F, ++0x01, 0x20, 0xE6, 0x0C, 0x7F, 0x02, 0x22, 0x90, 0x00, 0xF7, 0xE0, 0x30, 0xE6, 0x02, 0x7F, 0x03, ++0x22, 0x11, 0xE7, 0x90, 0x80, 0x3C, 0xEF, 0xF0, 0x31, 0x13, 0x90, 0x01, 0x64, 0x74, 0x01, 0xF0, ++0x02, 0x2D, 0xA7, 0x31, 0x81, 0x31, 0xB1, 0x31, 0x40, 0x31, 0x5F, 0xE4, 0xF5, 0x35, 0xF5, 0x36, ++0xF5, 0x37, 0xF5, 0x38, 0xAD, 0x35, 0x7F, 0x50, 0x12, 0x32, 0x1E, 0xAD, 0x36, 0x7F, 0x51, 0x12, ++0x32, 0x1E, 0xAD, 0x37, 0x7F, 0x52, 0x12, 0x32, 0x1E, 0xAD, 0x38, 0x7F, 0x53, 0x02, 0x32, 0x1E, ++0x75, 0x3D, 0x10, 0xE4, 0xF5, 0x3E, 0x75, 0x3F, 0x07, 0x75, 0x40, 0x02, 0x90, 0x01, 0x30, 0xE5, ++0x3D, 0xF0, 0xA3, 0xE5, 0x3E, 0xF0, 0xA3, 0xE5, 0x3F, 0xF0, 0xA3, 0xE5, 0x40, 0xF0, 0x22, 0x75, ++0x45, 0x0E, 0x75, 0x46, 0x01, 0x43, 0x46, 0x10, 0x75, 0x47, 0x03, 0x75, 0x48, 0x62, 0x90, 0x01, ++0x38, 0xE5, 0x45, 0xF0, 0xA3, 0xE5, 0x46, 0xF0, 0xA3, 0xE5, 0x47, 0xF0, 0xA3, 0xE5, 0x48, 0xF0, ++0x22, 0x90, 0x01, 0x30, 0xE4, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x38, 0xF0, ++0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, 0x7F, 0x50, 0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x51, ++0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x52, 0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x53, 0x02, 0x32, ++0x1E, 0x90, 0x01, 0x34, 0x74, 0xFF, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x3C, ++0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, 0x7F, 0x54, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, ++0x55, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x56, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x57, 0x02, ++0x32, 0x1E, 0x90, 0x00, 0x80, 0xE0, 0x44, 0x80, 0xFD, 0x7F, 0x80, 0x12, 0x32, 0x1E, 0x90, 0xFD, ++0x00, 0xE0, 0x54, 0xBF, 0xF0, 0x12, 0x57, 0xE9, 0x51, 0x77, 0x12, 0x32, 0x77, 0x51, 0xC9, 0x51, ++0x5E, 0x7F, 0x01, 0x12, 0x43, 0x15, 0x90, 0x81, 0x41, 0x74, 0x02, 0xF0, 0xFF, 0x12, 0x43, 0x15, ++0x90, 0x81, 0x41, 0xE0, 0x04, 0xF0, 0x7F, 0x03, 0x12, 0x43, 0x15, 0x90, 0x81, 0x41, 0xE0, 0x04, ++0xF0, 0x31, 0x01, 0x51, 0x3F, 0x90, 0x00, 0x80, 0xE0, 0x44, 0x40, 0xFD, 0x7F, 0x80, 0x12, 0x32, ++0x1E, 0x75, 0x20, 0xFF, 0x51, 0x68, 0x51, 0xF9, 0x51, 0x7F, 0xE4, 0xFF, 0x02, 0x43, 0x9E, 0x51, ++0x62, 0x51, 0x6F, 0x51, 0xA7, 0x71, 0x4F, 0x51, 0x8A, 0x51, 0x95, 0x90, 0x81, 0x45, 0xE0, 0x54, ++0xFE, 0xF0, 0xA3, 0x74, 0x03, 0xF0, 0xA3, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0x22, 0xE4, 0xF5, ++0x4D, 0x22, 0xE4, 0x90, 0x80, 0xDE, 0xF0, 0x22, 0x75, 0xE8, 0x03, 0x75, 0xA8, 0x84, 0x22, 0xE4, ++0x90, 0x80, 0xD8, 0xF0, 0xA3, 0xF0, 0x22, 0x90, 0x01, 0x94, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90, ++0x01, 0xE4, 0x74, 0x0B, 0xF0, 0xA3, 0x74, 0x01, 0xF0, 0x22, 0x90, 0x81, 0x3F, 0xE0, 0x54, 0xFE, ++0xF0, 0xE4, 0xA3, 0xF0, 0x22, 0x90, 0x81, 0x42, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0x7F, 0xF0, 0xA3, ++0x74, 0x0A, 0xF0, 0xE4, 0xA3, 0xF0, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0xFD, ++0xF0, 0x54, 0xFB, 0xF0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x54, 0xDF, 0xF0, 0xE4, 0xA3, 0xF0, ++0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0x74, 0x0C, 0xF0, 0x22, 0x90, 0x01, 0x01, 0xE0, 0x44, 0x04, 0xF0, ++0x90, 0x01, 0x9C, 0x74, 0x7E, 0xF0, 0xA3, 0x74, 0x92, 0xF0, 0xA3, 0x74, 0xA0, 0xF0, 0xA3, 0x74, ++0x24, 0xF0, 0x90, 0x01, 0x9B, 0x74, 0x49, 0xF0, 0x90, 0x01, 0x9A, 0x74, 0xE0, 0xF0, 0x90, 0x01, ++0x99, 0xE4, 0xF0, 0x90, 0x01, 0x98, 0x04, 0xF0, 0x22, 0xE4, 0x90, 0x81, 0x51, 0xF0, 0xA3, 0xF0, ++0x90, 0x01, 0x98, 0xE0, 0x7F, 0x00, 0x30, 0xE4, 0x02, 0x7F, 0x01, 0xEF, 0x64, 0x01, 0x60, 0x3E, ++0xC3, 0x90, 0x81, 0x52, 0xE0, 0x94, 0x88, 0x90, 0x81, 0x51, 0xE0, 0x94, 0x13, 0x40, 0x08, 0x90, ++0x01, 0xC1, 0xE0, 0x44, 0x10, 0xF0, 0x22, 0x90, 0x81, 0x51, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44, ++0xA9, 0x7F, 0x14, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0xD3, 0x90, 0x81, 0x52, 0xE0, 0x94, 0x32, 0x90, ++0x81, 0x51, 0xE0, 0x94, 0x00, 0x40, 0xB9, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE3, 0xB2, 0x22, 0xE4, ++0x90, 0x81, 0x27, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0xF0, 0x54, 0xF0, 0xF0, ++0x90, 0x81, 0x24, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x2D, ++0x74, 0x01, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xFB, 0xF0, 0xA3, 0xE0, 0x54, 0xFB, ++0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90, 0x81, 0x2F, 0x74, 0x07, 0xF0, 0x90, 0x81, 0x32, 0xE4, ++0xF0, 0xA3, 0x74, 0x02, 0xF0, 0xE4, 0x90, 0x81, 0x2B, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xFE, ++0xF0, 0x90, 0x81, 0x29, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xDF, 0xF0, 0x90, 0x81, ++0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xBF, 0xF0, 0x54, 0x7F, 0xF0, 0xA3, 0xE0, ++0x54, 0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x54, 0xF7, 0xF0, 0x90, 0x81, 0x34, 0x12, 0x20, 0xDA, 0x00, ++0x00, 0x00, 0x00, 0x90, 0x80, 0x3C, 0xE0, 0xB4, 0x01, 0x08, 0x90, 0x81, 0x31, 0x74, 0x99, 0xF0, ++0x80, 0x12, 0x90, 0x80, 0x3C, 0xE0, 0x90, 0x81, 0x31, 0xB4, 0x03, 0x05, 0x74, 0x90, 0xF0, 0x80, ++0x03, 0x74, 0x40, 0xF0, 0x90, 0x81, 0x38, 0x74, 0x01, 0xF0, 0xA3, 0x74, 0x05, 0xF0, 0xA3, 0xE0, ++0x54, 0x01, 0x44, 0x28, 0xF0, 0xA3, 0x74, 0x05, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xE0, 0x54, 0xFD, ++0xF0, 0x54, 0xFB, 0xF0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x54, 0xDF, 0xF0, 0x54, 0xBF, 0xF0, ++0xE4, 0xA3, 0xF0, 0x22, 0xE4, 0x90, 0x81, 0x59, 0xF0, 0x90, 0x81, 0x59, 0xE0, 0x64, 0x01, 0xF0, ++0x24, 0x24, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x5C, 0xA3, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0xFF, 0x90, ++0x81, 0x29, 0xE0, 0x6F, 0x60, 0x03, 0x12, 0x47, 0x2A, 0xD1, 0x08, 0xBF, 0x01, 0x02, 0x91, 0x5F, ++0xB1, 0xF2, 0x12, 0x32, 0x9E, 0xBF, 0x01, 0x02, 0xB1, 0x67, 0x12, 0x42, 0x4D, 0x80, 0xCA, 0xD3, ++0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0x24, 0xE0, 0x30, 0xE0, 0x24, 0x90, 0x81, 0x1F, ++0xE0, 0xFF, 0x30, 0xE0, 0x1A, 0xC3, 0x13, 0x30, 0xE0, 0x07, 0xB1, 0xFB, 0xBF, 0x01, 0x12, 0x80, ++0x0A, 0x90, 0x81, 0x23, 0xE0, 0xFF, 0x60, 0x03, 0xB4, 0x08, 0x06, 0x91, 0x96, 0x80, 0x02, 0x91, ++0xA6, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xB1, 0x22, 0x91, ++0xBA, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x81, 0x2A, 0xE0, 0x70, 0x0D, 0xD1, 0x2F, 0xBF, 0x01, ++0x08, 0x91, 0x96, 0x90, 0x01, 0xE5, 0xE0, 0x04, 0xF0, 0x22, 0xB1, 0xF3, 0x90, 0x00, 0x08, 0xE0, ++0x54, 0xEF, 0xFD, 0x7F, 0x08, 0x12, 0x32, 0x1E, 0xE4, 0xFF, 0x8F, 0x50, 0xE4, 0x90, 0x81, 0x5A, ++0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x09, 0xE0, 0x7F, 0x00, 0x30, 0xE7, 0x02, 0x7F, 0x01, 0xEF, 0x65, ++0x50, 0x60, 0x3E, 0xC3, 0x90, 0x81, 0x5B, 0xE0, 0x94, 0x88, 0x90, 0x81, 0x5A, 0xE0, 0x94, 0x13, ++0x40, 0x08, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x10, 0xF0, 0x22, 0x90, 0x81, 0x5A, 0xE4, 0x75, 0xF0, ++0x01, 0x12, 0x44, 0xA9, 0x7F, 0x14, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0xD3, 0x90, 0x81, 0x5B, 0xE0, ++0x94, 0x32, 0x90, 0x81, 0x5A, 0xE0, 0x94, 0x00, 0x40, 0xB9, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE0, ++0xB2, 0x22, 0x90, 0x81, 0x31, 0xE0, 0xFD, 0x7F, 0x93, 0x12, 0x32, 0x1E, 0x90, 0x81, 0x28, 0xE0, ++0x60, 0x12, 0x90, 0x01, 0x2F, 0xE0, 0x30, 0xE7, 0x05, 0x74, 0x10, 0xF0, 0x80, 0x06, 0x90, 0x01, ++0x2F, 0x74, 0x90, 0xF0, 0x90, 0x00, 0x08, 0xE0, 0x44, 0x10, 0xFD, 0x7F, 0x08, 0x12, 0x32, 0x1E, ++0x7F, 0x01, 0x91, 0xCA, 0x90, 0x00, 0x90, 0xE0, 0x44, 0x01, 0xFD, 0x7F, 0x90, 0x12, 0x32, 0x1E, ++0x7F, 0x14, 0x7E, 0x00, 0x02, 0x32, 0xAA, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x2D, ++0xA7, 0xE4, 0xF5, 0x52, 0x12, 0x32, 0x9E, 0xEF, 0x60, 0x73, 0x63, 0x52, 0x01, 0xE5, 0x52, 0x24, ++0x67, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x5D, 0xA3, 0xF0, 0x90, 0x00, 0x88, 0xE0, 0xF5, 0x50, 0xF5, ++0x51, 0x54, 0x0F, 0x60, 0xDF, 0xE5, 0x50, 0x30, 0xE0, 0x0B, 0x20, 0xE4, 0x03, 0x12, 0x29, 0xC5, ++0x53, 0x51, 0xEE, 0x80, 0x3F, 0xE5, 0x50, 0x30, 0xE1, 0x16, 0x20, 0xE5, 0x0E, 0x12, 0x11, 0xBD, ++0xEF, 0x70, 0x03, 0x43, 0x51, 0x20, 0x90, 0x01, 0x06, 0xE4, 0xF0, 0x53, 0x51, 0xFD, 0x80, 0x24, ++0xE5, 0x50, 0x30, 0xE2, 0x0B, 0x20, 0xE6, 0x03, 0x12, 0x67, 0x06, 0x53, 0x51, 0xFB, 0x80, 0x14, ++0xE5, 0x50, 0x30, 0xE3, 0x0F, 0x20, 0xE7, 0x09, 0x12, 0x61, 0x6E, 0xEF, 0x70, 0x03, 0x43, 0x51, ++0x80, 0x53, 0x51, 0xF7, 0xAD, 0x51, 0x7F, 0x88, 0x12, 0x32, 0x1E, 0x80, 0x87, 0xD0, 0xD0, 0x92, ++0xAF, 0x22, 0x22, 0x90, 0x00, 0x90, 0xE0, 0x20, 0xE0, 0xF9, 0x22, 0x90, 0x81, 0x22, 0xE0, 0x64, ++0x02, 0x7F, 0x01, 0x60, 0x02, 0x7F, 0x00, 0x22, 0x7F, 0x02, 0x90, 0x81, 0x41, 0xE0, 0xFE, 0xEF, ++0xC3, 0x9E, 0x50, 0x18, 0xEF, 0x25, 0xE0, 0x24, 0x81, 0xF8, 0xE6, 0x30, 0xE4, 0x0B, 0x90, 0x01, ++0xB8, 0x74, 0x08, 0xF0, 0xA3, 0xF0, 0x7F, 0x00, 0x22, 0x0F, 0x80, 0xDE, 0x7F, 0x01, 0x22, 0x90, ++0x02, 0x87, 0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x01, 0xF0, 0x80, 0x17, 0x90, 0x02, 0x86, ++0xE0, 0x20, 0xE1, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4, ++0xF0, 0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74, 0x08, 0xF0, 0x7F, 0x00, 0x22, 0xE4, 0xFB, 0xFA, ++0xFD, 0x7F, 0x01, 0x12, 0x44, 0x4E, 0x90, 0x81, 0xBD, 0xEF, 0xF0, 0x60, 0xF0, 0xD1, 0x71, 0x80, ++0xEC, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x01, 0xCC, 0xE0, 0x54, 0x0F, 0x90, 0x81, ++0xBE, 0xF0, 0x90, 0x81, 0xBE, 0xE0, 0xFD, 0x70, 0x02, 0xE1, 0x9C, 0x90, 0x82, 0x09, 0xE0, 0xFF, ++0x74, 0x01, 0x7E, 0x00, 0xA8, 0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, ++0xFF, 0xEF, 0x5D, 0x70, 0x02, 0xE1, 0x95, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, ++0xD0, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xBF, 0xF0, 0x75, 0x13, 0x01, 0x75, 0x14, 0x81, 0x75, ++0x15, 0xBF, 0x75, 0x16, 0x01, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0xC0, 0x12, 0x2B, 0xED, 0x90, 0x82, ++0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD1, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xC1, 0xF0, ++0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD2, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, ++0xC2, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD3, 0x12, 0x45, 0x0A, 0xE0, ++0x90, 0x81, 0xC3, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF0, 0x12, 0x45, ++0x0A, 0xE0, 0x90, 0x81, 0xC4, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF1, ++0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xC5, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, ++0x01, 0xF2, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xC6, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, ++0x04, 0x90, 0x01, 0xF3, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xC7, 0xF0, 0x90, 0x81, 0xBE, 0xE0, ++0xFF, 0x90, 0x82, 0x09, 0xE0, 0xFE, 0x74, 0x01, 0xA8, 0x06, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, ++0xFC, 0xF4, 0x5F, 0x90, 0x81, 0xBE, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, ++0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0x90, 0x01, 0xCC, 0xF0, 0x90, 0x81, 0xC0, 0xE0, 0xFF, ++0x7B, 0x01, 0x7A, 0x81, 0x79, 0xC1, 0x12, 0x55, 0x3F, 0x90, 0x82, 0x09, 0xE0, 0x04, 0xF0, 0xE0, ++0x54, 0x03, 0xF0, 0xC1, 0x82, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x02, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, ++0x22, 0xE4, 0xFB, 0xFA, 0xFD, 0x7F, 0x01, 0x12, 0x44, 0x4E, 0x90, 0x81, 0xD0, 0xEF, 0xF0, 0x60, ++0xF0, 0x12, 0x6C, 0x19, 0x80, 0xEB, 0x90, 0x81, 0xD4, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0xA3, 0x12, ++0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x90, 0x81, 0xE2, 0xF0, 0x7F, 0x24, 0x7E, 0x08, 0x12, ++0x2D, 0x5C, 0x90, 0x81, 0xDA, 0x12, 0x20, 0xCE, 0x90, 0x81, 0xD4, 0xE0, 0xFB, 0x70, 0x08, 0x90, ++0x81, 0xDA, 0x12, 0x44, 0xD9, 0x80, 0x16, 0xEB, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, 0x82, ++0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x12, 0x2D, 0x5C, 0x90, 0x81, 0xDE, ++0x12, 0x20, 0xCE, 0x90, 0x81, 0xD5, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x17, 0x12, 0x20, ++0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, 0x07, 0x90, 0x81, 0xDE, 0x12, 0x44, 0xD9, 0xED, ++0x54, 0x7F, 0xFD, 0xEC, 0x54, 0x80, 0xFC, 0x12, 0x44, 0xCC, 0xEC, 0x44, 0x80, 0xFC, 0x90, 0x81, ++0xDE, 0x12, 0x20, 0xCE, 0x90, 0x81, 0xDA, 0x12, 0x44, 0xD9, 0xEC, 0x54, 0x7F, 0xFC, 0x90, 0x85, ++0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x24, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x81, 0xD4, 0xE0, 0x75, ++0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, 0x82, 0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, ++0xFF, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x81, 0xDE, 0x12, 0x44, 0xD9, 0x90, 0x85, 0xBB, 0x12, 0x20, ++0xCE, 0xD0, 0x07, 0xD0, 0x06, 0x12, 0x2E, 0xA2, 0x90, 0x81, 0xDA, 0x12, 0x44, 0xD9, 0xEC, 0x44, ++0x80, 0xFC, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x24, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, ++0x81, 0xD4, 0xE0, 0x70, 0x04, 0x7F, 0x20, 0x80, 0x09, 0x90, 0x81, 0xD4, 0xE0, 0xB4, 0x01, 0x16, ++0x7F, 0x28, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0x78, 0x08, 0x12, 0x20, 0xA8, 0xEF, 0x54, 0x01, 0xFF, ++0xE4, 0x90, 0x81, 0xE2, 0xEF, 0xF0, 0x90, 0x81, 0xE2, 0xE0, 0x90, 0x81, 0xD4, 0x60, 0x0E, 0xE0, ++0x75, 0xF0, 0x08, 0xA4, 0x24, 0x66, 0xF5, 0x82, 0xE4, 0x34, 0x87, 0x80, 0x0C, 0xE0, 0x75, 0xF0, ++0x08, 0xA4, 0x24, 0x64, 0xF5, 0x82, 0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, ++0x12, 0x2D, 0x5C, 0xED, 0x54, 0x0F, 0xFD, 0xE4, 0xFC, 0x90, 0x81, 0xD6, 0x12, 0x20, 0xCE, 0x90, ++0x81, 0xD6, 0x02, 0x44, 0xD9, 0x90, 0x81, 0xE3, 0xEF, 0xF0, 0xAB, 0x05, 0x90, 0x81, 0xE9, 0x12, ++0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x03, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x14, 0x12, 0x20, ++0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, 0x07, 0x90, 0x81, 0xE5, 0x12, 0x44, 0xD9, 0xED, ++0x54, 0x0F, 0xFD, 0xE4, 0xFC, 0x12, 0x44, 0xCC, 0xEC, 0x54, 0x0F, 0xFC, 0x90, 0x81, 0xE9, 0x12, ++0x20, 0xCE, 0x90, 0x81, 0xE3, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x60, 0xF5, 0x82, 0xE4, 0x34, ++0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x81, 0xE9, 0x12, ++0x44, 0xD9, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0xD0, 0x07, 0xD0, 0x06, 0x02, 0x2E, 0xA2, 0xD3, ++0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x5F, 0xB6, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x78, 0x10, ++0x74, 0x01, 0xF2, 0x90, 0x02, 0x09, 0xE0, 0x78, 0x00, 0xF2, 0x08, 0x74, 0x20, 0xF2, 0x18, 0xE2, ++0xFF, 0x30, 0xE0, 0x05, 0x08, 0xE2, 0x24, 0x80, 0xF2, 0xEF, 0xC3, 0x13, 0x90, 0xFD, 0x10, 0xF0, ++0x78, 0x01, 0xE2, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x78, 0x03, 0xF2, ++0x64, 0x04, 0x60, 0x0D, 0xE2, 0xFF, 0x64, 0x08, 0x60, 0x07, 0xEF, 0x64, 0x0C, 0x60, 0x02, 0x61, ++0xDE, 0xE4, 0x78, 0x02, 0xF2, 0x78, 0x03, 0xE2, 0xFF, 0x18, 0xE2, 0xC3, 0x9F, 0x50, 0x2D, 0xE2, ++0xFD, 0x18, 0xE2, 0x2D, 0x90, 0x81, 0x5A, 0xF0, 0xE0, 0xFF, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, ++0xFC, 0xF5, 0x83, 0xE0, 0xFE, 0x74, 0x04, 0x2D, 0xF8, 0xEE, 0xF2, 0xEF, 0xB4, 0xFF, 0x06, 0x90, ++0xFD, 0x10, 0xE0, 0x04, 0xF0, 0x78, 0x02, 0xE2, 0x04, 0xF2, 0x80, 0xC9, 0x78, 0x04, 0xE2, 0x78, ++0x12, 0xF2, 0xFF, 0x78, 0x05, 0xE2, 0x78, 0x11, 0xF2, 0x78, 0x06, 0xE2, 0x78, 0x13, 0xF2, 0x78, ++0x07, 0xE2, 0x78, 0x14, 0xF2, 0x78, 0x08, 0xE2, 0x78, 0x33, 0xF2, 0x78, 0x09, 0xE2, 0x78, 0x34, ++0xF2, 0x78, 0x0A, 0xE2, 0x78, 0x35, 0xF2, 0x78, 0x0B, 0xE2, 0x78, 0x36, 0xF2, 0x78, 0x0C, 0xE2, ++0x78, 0x37, 0xF2, 0x78, 0x0D, 0xE2, 0x78, 0x38, 0xF2, 0x78, 0x0E, 0xE2, 0x78, 0x39, 0xF2, 0x78, ++0x0F, 0xE2, 0x78, 0x3A, 0xF2, 0xE4, 0x78, 0x15, 0xF2, 0xEF, 0x24, 0xF8, 0x60, 0x75, 0x24, 0xFC, ++0x60, 0x6C, 0x24, 0x08, 0x60, 0x02, 0x61, 0xC0, 0x78, 0x11, 0xE2, 0xB4, 0x01, 0x05, 0x12, 0x29, ++0xC5, 0x61, 0xC5, 0x78, 0x11, 0xE2, 0xB4, 0x02, 0x05, 0x12, 0x11, 0xBD, 0x61, 0xC5, 0x78, 0x11, ++0xE2, 0xB4, 0x03, 0x04, 0xF1, 0x06, 0x61, 0xC5, 0x78, 0x11, 0xE2, 0xB4, 0x10, 0x17, 0x78, 0x14, ++0xE2, 0xFE, 0x18, 0xE2, 0xFD, 0xED, 0xFF, 0x78, 0x16, 0xEE, 0xF2, 0xFE, 0x08, 0xEF, 0xF2, 0xFF, ++0x12, 0x32, 0xAA, 0x61, 0xC5, 0x78, 0x11, 0xE2, 0xB4, 0x11, 0x17, 0x78, 0x14, 0xE2, 0xFE, 0x18, ++0xE2, 0xFD, 0xED, 0xFF, 0x78, 0x16, 0xEE, 0xF2, 0xFE, 0x08, 0xEF, 0xF2, 0xFF, 0x12, 0x32, 0x06, ++0x61, 0xC5, 0x78, 0x11, 0xE2, 0xF4, 0x60, 0x02, 0x61, 0xC5, 0x18, 0xF2, 0x61, 0xC5, 0x78, 0x15, ++0x74, 0x01, 0xF2, 0x78, 0x11, 0xE2, 0x64, 0x07, 0x60, 0x02, 0x61, 0xAA, 0x78, 0x34, 0xE2, 0xFF, ++0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x08, 0x12, 0x20, 0xBB, 0xC0, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, ++0x07, 0x78, 0x33, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0xC0, 0x04, ++0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x78, 0x35, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x10, ++0x12, 0x20, 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x78, 0x18, ++0x12, 0x44, 0xFE, 0x78, 0x15, 0xE2, 0x70, 0x02, 0x61, 0x93, 0x18, 0xE2, 0xFF, 0x18, 0xE2, 0xFD, ++0x31, 0x5F, 0x78, 0x1C, 0x12, 0x44, 0xFE, 0x78, 0x38, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, ++0x08, 0x12, 0x20, 0xBB, 0xC0, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, 0x07, 0x78, 0x37, 0xE2, 0xFF, ++0xE4, 0xFC, 0xFD, 0xFE, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, ++0x07, 0x78, 0x39, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x10, 0x12, 0x20, 0xBB, 0xD0, 0x03, ++0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x78, 0x20, 0x12, 0x44, 0xFE, 0x78, 0x20, ++0x12, 0x44, 0xE5, 0x12, 0x20, 0x9B, 0x78, 0x1C, 0x12, 0x44, 0xF1, 0x12, 0x44, 0xBF, 0xC0, 0x04, ++0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x78, 0x18, 0x12, 0x44, 0xE5, 0x78, 0x20, 0x12, 0x44, 0xF1, ++0x12, 0x44, 0xBF, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x78, 0x18, ++0x12, 0x44, 0xFE, 0x78, 0x18, 0x12, 0x44, 0xE5, 0x90, 0x81, 0xF9, 0x12, 0x20, 0xCE, 0x78, 0x13, ++0xE2, 0xFD, 0x08, 0xE2, 0xFF, 0x12, 0x55, 0x1C, 0x80, 0x1B, 0x78, 0x13, 0xE2, 0xFF, 0x08, 0xE2, ++0xFD, 0x78, 0x11, 0xE2, 0xFB, 0x78, 0x15, 0xE2, 0x90, 0x81, 0xBC, 0xF0, 0x71, 0xE1, 0x80, 0x05, ++0x78, 0x10, 0x74, 0x02, 0xF2, 0x78, 0x10, 0xE2, 0xFF, 0xC3, 0x94, 0x02, 0x50, 0x10, 0xEF, 0x60, ++0x0A, 0x78, 0x02, 0xE2, 0xFF, 0x18, 0xE2, 0x2F, 0xF2, 0x21, 0x90, 0x7F, 0x01, 0x22, 0x7F, 0x00, ++0x22, 0xAC, 0x07, 0xED, 0xAD, 0x04, 0x78, 0x24, 0xF2, 0xED, 0x08, 0xF2, 0xEB, 0xB4, 0x04, 0x07, ++0x78, 0x27, 0x74, 0x01, 0xF2, 0x80, 0x0E, 0xEB, 0x78, 0x27, 0xB4, 0x05, 0x05, 0x74, 0x02, 0xF2, ++0x80, 0x03, 0x74, 0x04, 0xF2, 0xD3, 0x78, 0x25, 0xE2, 0x94, 0xFF, 0x18, 0xE2, 0x94, 0x00, 0x50, ++0x63, 0xE4, 0x78, 0x26, 0xF2, 0x78, 0x27, 0xE2, 0xFF, 0x18, 0xE2, 0xFE, 0xC3, 0x9F, 0x40, 0x02, ++0xA1, 0x7F, 0x74, 0x33, 0x2E, 0xF8, 0xE2, 0x78, 0x28, 0xF2, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x2D, ++0x74, 0x37, 0x2E, 0xF8, 0xE2, 0x78, 0x32, 0xF2, 0xEE, 0xFF, 0x78, 0x25, 0xE2, 0x2F, 0xFF, 0x18, ++0xE2, 0x34, 0x00, 0x8F, 0x82, 0xF5, 0x83, 0xE0, 0x78, 0x29, 0xF2, 0x78, 0x32, 0xE2, 0xFF, 0xF4, ++0xFE, 0x78, 0x29, 0xE2, 0x5E, 0xFE, 0x18, 0xE2, 0xFD, 0xEF, 0x5D, 0x4E, 0xF2, 0x78, 0x24, 0x08, ++0xE2, 0xFF, 0x08, 0xE2, 0x2F, 0xFF, 0x78, 0x28, 0xE2, 0xFD, 0x12, 0x32, 0x1E, 0x78, 0x26, 0xE2, ++0x04, 0xF2, 0x80, 0xA1, 0xD3, 0x78, 0x25, 0xE2, 0x94, 0xFF, 0x18, 0xE2, 0x94, 0x07, 0x50, 0x69, ++0xE4, 0x78, 0x26, 0xF2, 0x78, 0x27, 0xE2, 0xFF, 0x18, 0xE2, 0xFE, 0xC3, 0x9F, 0x40, 0x02, 0xA1, ++0x7F, 0x74, 0x33, 0x2E, 0xF8, 0xE2, 0x78, 0x28, 0xF2, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x2D, 0x78, ++0x26, 0xE2, 0xFF, 0xFD, 0x18, 0xE2, 0x2D, 0xFD, 0x18, 0xE2, 0x34, 0x00, 0x8D, 0x82, 0xF5, 0x83, ++0xE0, 0x78, 0x29, 0xF2, 0x74, 0x37, 0x2F, 0xF8, 0xE2, 0x78, 0x32, 0xF2, 0xE2, 0xFF, 0xF4, 0xFE, ++0x78, 0x29, 0xE2, 0x5E, 0xFE, 0x18, 0xE2, 0xFD, 0xEF, 0x5D, 0x4E, 0xF2, 0x78, 0x28, 0xE2, 0xFF, ++0x78, 0x26, 0xE2, 0xFD, 0x18, 0xE2, 0x2D, 0xFD, 0x18, 0xE2, 0x34, 0x00, 0x8D, 0x82, 0xF5, 0x83, ++0xEF, 0xF0, 0x78, 0x26, 0xE2, 0x04, 0xF2, 0x80, 0x9B, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x0F, 0x78, ++0x24, 0xE2, 0xFE, 0x08, 0xE2, 0xFF, 0x12, 0x2D, 0x5C, 0x78, 0x2E, 0x12, 0x44, 0xFE, 0xE4, 0x78, ++0x26, 0xF2, 0x78, 0x27, 0xE2, 0xFF, 0x18, 0xE2, 0xFE, 0xC3, 0x9F, 0x50, 0x5D, 0x74, 0x33, 0x2E, ++0xF8, 0xE2, 0x78, 0x28, 0xF2, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x2B, 0x78, 0x2E, 0x12, 0x44, 0xE5, ++0x78, 0x26, 0xE2, 0xFB, 0x75, 0xF0, 0x08, 0xA4, 0xF9, 0xF8, 0x12, 0x20, 0xA8, 0x78, 0x29, 0xEF, ++0xF2, 0x74, 0x37, 0x2B, 0xF8, 0xE2, 0x78, 0x32, 0xF2, 0xE2, 0xFE, 0xF4, 0x5F, 0xFF, 0x78, 0x28, ++0xE2, 0xFD, 0xEE, 0x5D, 0x4F, 0xF2, 0x78, 0x28, 0xE2, 0xFF, 0x78, 0x26, 0xE2, 0xFD, 0xC3, 0x74, ++0x03, 0x9D, 0xFD, 0xE4, 0x94, 0x00, 0xFC, 0x7B, 0xFE, 0x74, 0x2A, 0x2D, 0xF9, 0x74, 0x80, 0x3C, ++0xFA, 0xEF, 0x12, 0x1F, 0xEA, 0xE2, 0x04, 0xF2, 0x80, 0x98, 0x78, 0x2A, 0x12, 0x44, 0xE5, 0x90, ++0x85, 0xBB, 0x12, 0x20, 0xCE, 0x78, 0x24, 0xE2, 0xFE, 0x08, 0xE2, 0xFF, 0x12, 0x2E, 0xA2, 0x22, ++0x22, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x1F, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0xFE, 0x12, ++0x1F, 0xA4, 0xFD, 0xC3, 0x13, 0x30, 0xE0, 0x12, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16, 0x90, 0x00, ++0x02, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0xCF, 0xF0, 0x80, 0x05, 0x90, 0x81, 0xCF, 0xEF, 0xF0, 0x90, ++0x81, 0xCE, 0xEE, 0xF0, 0x90, 0x81, 0xCF, 0xE0, 0xFE, 0x90, 0x81, 0xCE, 0xE0, 0xFF, 0xD3, 0x9E, ++0x50, 0x38, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16, 0x12, 0x1F, 0xA4, 0x54, 0x01, 0xFE, 0x74, 0xDE, ++0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x80, 0xF5, 0x83, 0xEE, 0xF0, 0x74, 0xDE, 0x2F, 0xF5, 0x82, 0xE4, ++0x34, 0x80, 0xF5, 0x83, 0xE0, 0x70, 0x04, 0xD1, 0x25, 0x80, 0x07, 0x90, 0x81, 0xCE, 0xE0, 0xFF, ++0xB1, 0x80, 0x90, 0x81, 0xCE, 0xE0, 0x04, 0xF0, 0x80, 0xBA, 0x90, 0x80, 0xDE, 0xE0, 0x70, 0x24, ++0x90, 0x81, 0x2A, 0xE0, 0x70, 0x04, 0xFF, 0x12, 0x49, 0x93, 0x90, 0x81, 0x2A, 0xE0, 0x64, 0x0C, ++0x60, 0x02, 0xD1, 0x26, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x54, 0xBF, ++0xF0, 0x54, 0x7F, 0xF0, 0x22, 0x22, 0x90, 0x06, 0x04, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x05, 0x22, ++0xE4, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x0C, 0xF0, 0x22, 0x90, 0x81, 0xED, 0xEF, 0xF0, 0xA3, 0xED, ++0xF0, 0xAD, 0x03, 0xAC, 0x02, 0xE4, 0x90, 0x81, 0xF5, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0xC4, 0x74, ++0x39, 0xF0, 0x74, 0x66, 0xA3, 0xF0, 0xEC, 0x54, 0x3F, 0xFC, 0x90, 0x01, 0x40, 0xED, 0xF0, 0xAE, ++0x04, 0xEE, 0xA3, 0xF0, 0x90, 0x81, 0xED, 0xE0, 0x24, 0x81, 0x60, 0x34, 0x24, 0xDA, 0x60, 0x1C, ++0x24, 0x3C, 0x70, 0x41, 0x90, 0x81, 0xEE, 0xE0, 0xC4, 0x33, 0x33, 0x33, 0x54, 0x80, 0x90, 0x81, ++0xF2, 0xF0, 0xA3, 0x74, 0x69, 0xF0, 0xA3, 0x74, 0x80, 0xF0, 0x80, 0x2C, 0x90, 0x81, 0xEE, 0xE0, ++0x54, 0x01, 0x90, 0x81, 0xF2, 0xF0, 0xA3, 0x74, 0xA5, 0xF0, 0xA3, 0x74, 0x01, 0xF0, 0x80, 0x18, ++0x90, 0x81, 0xEE, 0xE0, 0xC4, 0x54, 0x10, 0x90, 0x81, 0xF2, 0xF0, 0xA3, 0x74, 0x7F, 0xF0, 0xA3, ++0x74, 0x10, 0xF0, 0x80, 0x03, 0x7F, 0x00, 0x22, 0x90, 0x81, 0xF3, 0xE0, 0x90, 0x01, 0x06, 0xF0, ++0x90, 0x81, 0xF2, 0xE0, 0x60, 0x0E, 0x90, 0x01, 0x42, 0xF0, 0x90, 0x81, 0xF1, 0xE0, 0x90, 0x01, ++0x43, 0xF0, 0x80, 0x0D, 0x90, 0x01, 0x43, 0xE4, 0xF0, 0x90, 0x81, 0xF2, 0xE0, 0x90, 0x01, 0x42, ++0xF0, 0x90, 0x81, 0xF4, 0xE0, 0xFF, 0x90, 0x01, 0x42, 0xE0, 0x5F, 0xFF, 0x90, 0x81, 0xF2, 0xE0, ++0x6F, 0x60, 0xEE, 0x74, 0x39, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x66, 0xA3, 0xF0, 0x90, 0x01, ++0x43, 0xE4, 0xF0, 0x7F, 0x01, 0x22, 0xE4, 0x90, 0x81, 0x6A, 0xF0, 0x90, 0x87, 0x5F, 0xE0, 0x90, ++0x81, 0x69, 0xF0, 0xE4, 0x90, 0x81, 0x76, 0xF0, 0x90, 0x81, 0x66, 0xF0, 0x90, 0x81, 0x66, 0xE0, ++0xFF, 0xC3, 0x94, 0x40, 0x50, 0x15, 0x74, 0x79, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, ++0x74, 0xFF, 0xF0, 0x90, 0x81, 0x66, 0xE0, 0x04, 0xF0, 0x80, 0xE1, 0xE4, 0x90, 0x81, 0x66, 0xF0, ++0x90, 0x81, 0x69, 0xE0, 0xFF, 0x90, 0x81, 0x66, 0xE0, 0xFE, 0xC3, 0x9F, 0x40, 0x03, 0x02, 0x68, ++0x12, 0x74, 0xDF, 0x2E, 0xF9, 0xE4, 0x34, 0x86, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, ++0x16, 0x0A, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x5B, 0x12, 0x2B, 0xED, 0x90, 0x81, 0x5C, 0xE0, 0xFF, ++0x12, 0x2F, 0x27, 0xEF, 0x04, 0x90, 0x81, 0x76, 0xF0, 0x90, 0x81, 0x5B, 0xE0, 0xFF, 0xA3, 0xE0, ++0xFD, 0x12, 0x31, 0xEA, 0xEF, 0x24, 0xC8, 0x90, 0x81, 0x78, 0xF0, 0x75, 0xF0, 0x08, 0xA4, 0xF0, ++0x90, 0x81, 0x5C, 0xE0, 0x54, 0x0F, 0x90, 0x81, 0x77, 0xF0, 0xE4, 0x90, 0x81, 0x65, 0xF0, 0x90, ++0x81, 0x67, 0xF0, 0x90, 0x81, 0x67, 0xE0, 0xFF, 0xC3, 0x94, 0x04, 0x50, 0x57, 0x90, 0x81, 0x77, ++0xE0, 0xFE, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x13, 0xD8, 0xFC, 0x20, 0xE0, 0x3E, 0x90, 0x81, ++0x67, 0xE0, 0x25, 0xE0, 0xFF, 0x90, 0x81, 0x78, 0xE0, 0x2F, 0x24, 0x79, 0xF9, 0xE4, 0x34, 0x81, ++0xFA, 0x7B, 0x01, 0xC0, 0x03, 0xC0, 0x01, 0x90, 0x81, 0x65, 0xE0, 0x75, 0xF0, 0x02, 0xA4, 0x24, ++0x5D, 0xF9, 0x74, 0x81, 0x35, 0xF0, 0x8B, 0x13, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x02, 0xD0, ++0x01, 0xD0, 0x03, 0x12, 0x2B, 0xED, 0x90, 0x81, 0x65, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x67, 0xE0, ++0x04, 0xF0, 0x80, 0x9F, 0x90, 0x81, 0x76, 0xE0, 0xFF, 0x90, 0x81, 0x66, 0xE0, 0x2F, 0xF0, 0x02, ++0x67, 0x40, 0xE4, 0x90, 0x81, 0x6A, 0xF0, 0x90, 0x81, 0x6A, 0xE0, 0xC3, 0x94, 0x40, 0x40, 0x02, ++0x41, 0xAF, 0xE0, 0xFF, 0x24, 0x79, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0x90, 0x81, ++0x6C, 0xF0, 0xE0, 0xFE, 0x54, 0xF0, 0xC4, 0x54, 0x0F, 0xFD, 0x90, 0x81, 0x6B, 0xF0, 0xEE, 0x54, ++0x0F, 0xFE, 0xA3, 0xF0, 0x74, 0x7A, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0x90, ++0x81, 0x6D, 0xF0, 0xFC, 0xEE, 0xFE, 0xEC, 0xFB, 0xEB, 0xFF, 0x90, 0x81, 0x72, 0xEE, 0xF0, 0xA3, ++0xEF, 0xF0, 0xED, 0x12, 0x45, 0x28, 0x68, 0x8B, 0x00, 0x68, 0xC2, 0x01, 0x69, 0x73, 0x02, 0x6A, ++0xA0, 0x03, 0x69, 0x8E, 0x04, 0x69, 0xAF, 0x05, 0x69, 0xAF, 0x06, 0x69, 0xAF, 0x07, 0x69, 0xAF, ++0x08, 0x6A, 0x33, 0x09, 0x6A, 0x69, 0x0A, 0x00, 0x00, 0x6A, 0xAF, 0x90, 0x81, 0x6A, 0xE0, 0xFD, ++0x24, 0x7C, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFE, 0x74, 0x7B, 0x2D, 0xF5, 0x82, ++0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFD, 0xED, 0xFF, 0x90, 0x81, 0x74, 0xEE, 0xF0, 0xFC, 0xA3, ++0xEF, 0xF0, 0x90, 0x81, 0x6D, 0xE0, 0xFF, 0x12, 0x2F, 0x96, 0x90, 0x81, 0x68, 0x74, 0x02, 0xF0, ++0x41, 0xA0, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7C, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, ++0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x08, 0x12, 0x20, 0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, ++0xAB, 0x07, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, ++0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x12, 0x44, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, ++0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7D, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFF, 0xE4, ++0xFC, 0xFD, 0xFE, 0x78, 0x10, 0x12, 0x20, 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, ++0x12, 0x44, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x81, 0x6A, 0xE0, 0x24, ++0x7E, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x18, ++0x12, 0x20, 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x90, 0x81, ++0x6E, 0x12, 0x20, 0xCE, 0x90, 0x81, 0x6E, 0x12, 0x44, 0xD9, 0x90, 0x85, 0x96, 0x12, 0x20, 0xCE, ++0x90, 0x81, 0x72, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x12, 0x2E, 0xE4, 0x90, 0x81, 0x68, 0x74, 0x04, ++0xF0, 0x41, 0xA0, 0x90, 0x81, 0x6D, 0xE0, 0xFD, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF5, 0x82, ++0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFB, 0xE4, 0xFF, 0x12, 0x30, 0xC7, 0x80, 0x19, 0x90, 0x81, ++0x6D, 0xE0, 0xFD, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, ++0xE0, 0xFB, 0xE4, 0xFF, 0x12, 0x30, 0x6A, 0x90, 0x81, 0x68, 0x74, 0x01, 0xF0, 0x41, 0xA0, 0x90, ++0x81, 0x68, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7C, 0xF5, 0x82, 0xE4, 0x34, 0x81, ++0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x08, 0x12, 0x20, 0xBB, 0xA8, 0x04, 0xA9, ++0x05, 0xAA, 0x06, 0xAB, 0x07, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF5, 0x82, 0xE4, 0x34, 0x81, ++0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x12, 0x44, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0, ++0x06, 0xC0, 0x07, 0x90, 0x81, 0x6C, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x10, 0x12, 0x20, ++0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x90, 0x81, 0x6E, 0x12, ++0x20, 0xCE, 0x90, 0x81, 0x6B, 0xE0, 0x24, 0xFB, 0xFF, 0xC0, 0x07, 0x90, 0x81, 0x6E, 0x12, 0x44, ++0xD9, 0x90, 0x81, 0xF9, 0x12, 0x20, 0xCE, 0x90, 0x81, 0x6D, 0xE0, 0xFD, 0xD0, 0x07, 0x12, 0x55, ++0x1C, 0x80, 0x6D, 0x90, 0x81, 0x68, 0x74, 0x01, 0xF0, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF9, ++0xE4, 0x34, 0x81, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x01, 0x7B, 0xFE, 0x7A, ++0x80, 0x79, 0x33, 0x12, 0x2B, 0xED, 0x90, 0x81, 0x6D, 0xE0, 0xFF, 0x90, 0x81, 0x6C, 0xE0, 0xFD, ++0xE4, 0x90, 0x81, 0xBC, 0xF0, 0x7B, 0x04, 0x80, 0x34, 0x90, 0x81, 0x68, 0x74, 0x04, 0xF0, 0x90, ++0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF9, 0xE4, 0x34, 0x81, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, ++0x75, 0x16, 0x04, 0x7B, 0xFE, 0x7A, 0x80, 0x79, 0x33, 0x12, 0x2B, 0xED, 0x90, 0x81, 0x6D, 0xE0, ++0xFF, 0x90, 0x81, 0x6C, 0xE0, 0xFD, 0xE4, 0x90, 0x81, 0xBC, 0xF0, 0x7B, 0x06, 0x12, 0x63, 0xE1, ++0x90, 0x81, 0x68, 0xE0, 0x24, 0x02, 0xFF, 0x90, 0x81, 0x6A, 0xE0, 0x2F, 0xF0, 0x01, 0x17, 0x22, ++0x90, 0x02, 0x09, 0xE0, 0xFD, 0x12, 0x1F, 0xA4, 0xFE, 0xAF, 0x05, 0xED, 0x2E, 0x90, 0x80, 0x3D, ++0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x80, 0x3E, 0xF0, 0x90, 0x00, ++0x02, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x80, 0x3F, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, ++0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x80, 0x40, 0xF0, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFF, 0xAE, ++0x05, 0xED, 0x2F, 0x90, 0x80, 0x41, 0xF0, 0x22, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xFF, 0x30, ++0xE0, 0x26, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0x38, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, ++0x81, 0x39, 0xF0, 0xEF, 0x54, 0xFE, 0xFF, 0xA3, 0xE0, 0x54, 0x01, 0x4F, 0xF0, 0x90, 0x00, 0x03, ++0x12, 0x1F, 0xBD, 0x90, 0x81, 0x3B, 0xF0, 0x22, 0x90, 0x81, 0x38, 0x74, 0x01, 0xF0, 0xA3, 0x74, ++0x05, 0xF0, 0xA3, 0xE0, 0x54, 0x01, 0x44, 0x28, 0xF0, 0xA3, 0x74, 0x05, 0xF0, 0x22, 0x12, 0x1F, ++0xA4, 0x90, 0x81, 0x3E, 0xF0, 0x90, 0x81, 0x3E, 0xE0, 0x90, 0x01, 0xE7, 0xF0, 0x22, 0x12, 0x1F, ++0xA4, 0x90, 0x81, 0x4A, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x4B, 0xF0, 0x22, ++0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0xFD, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xE4, ++0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0xFD, 0xE0, 0xFE, 0xA3, 0xE0, 0xF5, 0x82, 0x8E, 0x83, 0xE0, ++0x60, 0x2D, 0xC3, 0x90, 0x82, 0x00, 0xE0, 0x94, 0xE8, 0x90, 0x81, 0xFF, 0xE0, 0x94, 0x03, 0x40, ++0x0B, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x80, 0xF0, 0x7F, 0x00, 0x80, 0x15, 0x90, 0x81, 0xFF, 0xE4, ++0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9, 0x7F, 0x0A, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x80, 0xC5, 0x7F, ++0x01, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0xD1, ++0x12, 0x45, 0x1F, 0x90, 0x82, 0x0A, 0xE0, 0xFF, 0x04, 0xF0, 0x90, 0x00, 0x01, 0xEF, 0x12, 0x1F, ++0xFC, 0x7F, 0xAF, 0x7E, 0x01, 0x71, 0x60, 0xEF, 0x60, 0x3A, 0x90, 0x81, 0xD1, 0x12, 0x45, 0x16, ++0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x90, 0x00, 0x0E, 0x12, 0x1F, 0xBD, 0x24, 0x02, 0xF5, 0x16, ++0x7B, 0x01, 0x7A, 0x01, 0x79, 0xA0, 0x12, 0x2B, 0xED, 0x90, 0x81, 0xD1, 0x12, 0x45, 0x16, 0x90, ++0x00, 0x0E, 0x12, 0x1F, 0xBD, 0x90, 0x01, 0xAE, 0xF0, 0xA3, 0x74, 0xFF, 0xF0, 0x90, 0x01, 0xCB, ++0xE0, 0x64, 0x80, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, ++0xE4, 0xFF, 0x90, 0x80, 0xD9, 0xE0, 0xFE, 0x90, 0x80, 0xD8, 0xE0, 0xFD, 0xB5, 0x06, 0x04, 0x7E, ++0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x64, 0x01, 0x60, 0x32, 0x90, 0x01, 0xAF, 0xE0, 0x70, 0x13, ++0xED, 0x75, 0xF0, 0x0F, 0xA4, 0x24, 0x42, 0xF9, 0x74, 0x80, 0x35, 0xF0, 0xFA, 0x7B, 0x01, 0x71, ++0xB6, 0x7F, 0x01, 0xEF, 0x60, 0x16, 0x90, 0x80, 0xD8, 0xE0, 0x04, 0xF0, 0xE0, 0x7F, 0x00, 0xB4, ++0x0A, 0x02, 0x7F, 0x01, 0xEF, 0x60, 0x05, 0xE4, 0x90, 0x80, 0xD8, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, ++0x22, 0x8F, 0x0D, 0x22, 0x8F, 0x0E, 0x22, 0x22, 0x90, 0x01, 0x34, 0xE0, 0x55, 0x3D, 0xF5, 0x41, ++0xA3, 0xE0, 0x55, 0x3E, 0xF5, 0x42, 0xA3, 0xE0, 0x55, 0x3F, 0xF5, 0x43, 0xA3, 0xE0, 0x55, 0x40, ++0xF5, 0x44, 0x90, 0x01, 0x34, 0xE5, 0x41, 0xF0, 0xA3, 0xE5, 0x42, 0xF0, 0xA3, 0xE5, 0x43, 0xF0, ++0xA3, 0xE5, 0x44, 0xF0, 0x22, 0x90, 0x01, 0x3C, 0xE0, 0x55, 0x45, 0xF5, 0x49, 0xA3, 0xE0, 0x55, ++0x46, 0xF5, 0x4A, 0xA3, 0xE0, 0x55, 0x47, 0xF5, 0x4B, 0xA3, 0xE0, 0x55, 0x48, 0xF5, 0x4C, 0x90, ++0x01, 0x3C, 0xE5, 0x49, 0xF0, 0xA3, 0xE5, 0x4A, 0xF0, 0xA3, 0xE5, 0x4B, 0xF0, 0xA3, 0xE5, 0x4C, ++0xF0, 0x53, 0x91, 0xDF, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0, 0x05, 0xE4, 0xA3, 0xF0, 0xA3, ++0xF0, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x70, 0x19, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x13, ++0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0x12, 0x4F, 0xF4, 0x90, 0x01, 0x57, ++0x74, 0x05, 0xF0, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x70, 0x26, 0x90, 0x81, 0x27, 0xE0, ++0x60, 0x20, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x24, ++0xE0, 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0x07, 0x70, 0x03, 0x12, ++0x47, 0x2A, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0xB4, 0x01, 0x14, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x0E, ++0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x02, 0x80, 0x03, 0xD1, 0x7F, 0x22, 0x90, ++0x04, 0x1D, 0xE0, 0x70, 0x13, 0x90, 0x80, 0x3E, 0xE0, 0xFF, 0xE4, 0xFD, 0xB1, 0x69, 0x8E, 0x4E, ++0x8F, 0x4F, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, ++0x90, 0x82, 0x0E, 0xED, 0xF0, 0x90, 0x82, 0x0D, 0xEF, 0xF0, 0xE4, 0xFD, 0xFC, 0xF1, 0x37, 0x7C, ++0x00, 0xAD, 0x07, 0x90, 0x82, 0x0D, 0xE0, 0x90, 0x04, 0x25, 0xF0, 0x90, 0x82, 0x0E, 0xE0, 0x60, ++0x0E, 0x74, 0x0F, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0xAF, ++0x05, 0x74, 0x08, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE4, 0xF0, 0x74, 0x09, 0x2F, ++0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xF0, 0xF0, 0x74, 0x21, 0x2D, 0xF5, 0x82, ++0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xF7, 0xF0, 0xAE, 0x04, 0xAF, 0x05, 0xD0, 0xD0, 0x92, ++0xAF, 0x22, 0x8F, 0x4E, 0xF1, 0x4B, 0xBF, 0x01, 0x18, 0x90, 0x80, 0x40, 0xE0, 0xFF, 0x7D, 0x01, ++0xB1, 0x69, 0xAD, 0x07, 0xAC, 0x06, 0xAF, 0x4E, 0x12, 0x4F, 0x82, 0x90, 0x04, 0x1F, 0x74, 0x20, ++0xF0, 0x22, 0x90, 0x06, 0xA9, 0xE0, 0x90, 0x81, 0x4C, 0xF0, 0xE0, 0xFD, 0x54, 0xC0, 0x70, 0x09, ++0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x80, 0x72, 0xED, 0x30, 0xE6, 0x4B, 0x90, 0x81, 0x27, ++0xE0, 0x64, 0x02, 0x70, 0x2A, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0xC3, 0x13, 0x20, 0xE0, 0x09, 0x90, ++0x81, 0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x80, 0x28, 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x01, ++0x70, 0x2D, 0x90, 0x81, 0x2B, 0xE0, 0x44, 0x04, 0xF0, 0x7F, 0x01, 0xB1, 0xD2, 0x80, 0x20, 0x90, ++0x81, 0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x04, ++0xB1, 0x4F, 0x80, 0x0B, 0xD1, 0x7F, 0x80, 0x07, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x90, ++0x81, 0x4C, 0xE0, 0x90, 0x81, 0x2B, 0x30, 0xE7, 0x11, 0x12, 0x4F, 0xF1, 0x90, 0x01, 0x57, 0x74, ++0x05, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x04, 0xF0, 0x22, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90, ++0x01, 0x5F, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x08, 0xF0, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A, ++0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4, 0xFB, 0xFD, 0x7F, 0x5C, 0x7E, 0x01, 0x12, 0x50, ++0x05, 0x90, 0x01, 0x5F, 0x74, 0x05, 0xF0, 0x90, 0x06, 0x92, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x24, ++0xE0, 0x44, 0x10, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x64, 0x0C, 0x60, 0x0C, 0xE4, 0xFD, 0x7F, 0x0C, ++0x12, 0x47, 0x3D, 0xE4, 0xFF, 0x12, 0x4F, 0x0D, 0x22, 0xE4, 0x90, 0x81, 0x4C, 0xF0, 0x90, 0x06, ++0xA9, 0xE0, 0x90, 0x81, 0x4C, 0xF0, 0xE0, 0x54, 0xC0, 0x70, 0x0D, 0x90, 0x81, 0x2B, 0xE0, 0x54, ++0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x02, 0x47, 0x2A, 0x90, 0x81, 0x4C, 0xE0, 0x30, 0xE6, 0x21, 0x90, ++0x81, 0x27, 0xE0, 0x64, 0x01, 0x70, 0x20, 0x90, 0x81, 0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x81, ++0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x04, 0xB1, 0x4F, 0x80, 0x0B, 0xD1, 0x7F, 0x80, 0x07, ++0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x81, 0x4C, 0xE0, 0x90, 0x81, 0x2B, 0x30, 0xE7, ++0x11, 0x12, 0x4F, 0xF1, 0x90, 0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x04, ++0xF0, 0x22, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0xE4, 0xFE, 0xEF, 0xC3, 0x13, 0xFD, 0xEF, 0x30, 0xE0, ++0x02, 0x7E, 0x80, 0x90, 0xFD, 0x10, 0xED, 0xF0, 0xAF, 0x06, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, ++0xC0, 0xD0, 0x90, 0x04, 0x1D, 0xE0, 0x60, 0x1A, 0x90, 0x05, 0x22, 0xE0, 0x54, 0x90, 0x60, 0x07, ++0x90, 0x01, 0xC0, 0xE0, 0x44, 0x08, 0xF0, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE1, 0xE4, 0x7F, 0x00, ++0x80, 0x02, 0x7F, 0x01, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x03, 0x12, ++0x73, 0xE1, 0x90, 0x81, 0x3F, 0xE0, 0x30, 0xE0, 0x03, 0x12, 0x49, 0xDD, 0x22, 0x90, 0x81, 0x27, ++0xE0, 0x60, 0x35, 0x90, 0x06, 0x92, 0xE0, 0x30, 0xE1, 0x24, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A, ++0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4, 0xFB, 0xFD, 0x7F, 0x5C, 0x7E, 0x01, 0x12, 0x50, ++0x05, 0x90, 0x01, 0x5F, 0x74, 0x05, 0xF0, 0x90, 0x06, 0x92, 0x74, 0x02, 0xF0, 0x22, 0x90, 0x81, ++0x24, 0xE0, 0x54, 0xEF, 0xF0, 0x12, 0x47, 0x2A, 0x22, 0x12, 0x71, 0x48, 0x90, 0x81, 0x4D, 0xEF, ++0xF0, 0x90, 0x81, 0x24, 0x30, 0xE0, 0x06, 0xE0, 0x44, 0x01, 0xF0, 0x80, 0x04, 0xE0, 0x54, 0xFE, ++0xF0, 0x90, 0x81, 0x4D, 0xE0, 0x30, 0xE6, 0x11, 0x90, 0x01, 0x2F, 0xE0, 0x30, 0xE7, 0x04, 0xE4, ++0xF0, 0x80, 0x06, 0x90, 0x01, 0x2F, 0x74, 0x80, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x30, 0xE0, 0x1A, ++0x90, 0x81, 0x32, 0xE4, 0xF0, 0xA3, 0x74, 0x07, 0xF0, 0x90, 0x81, 0x32, 0xA3, 0xE0, 0x90, 0x05, ++0x58, 0xF0, 0x90, 0x04, 0xEC, 0xE0, 0x54, 0xDD, 0xF0, 0x22, 0x90, 0x04, 0xEC, 0xE0, 0x44, 0x22, ++0xF0, 0x22, 0x90, 0x81, 0x4A, 0xE0, 0x60, 0x0F, 0xE4, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x01, ++0xF0, 0x90, 0x05, 0xFD, 0xE0, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0xC4, 0x13, 0x13, ++0x54, 0x03, 0x30, 0xE0, 0x27, 0xEF, 0x54, 0xBF, 0xF0, 0x90, 0x04, 0xE0, 0xE0, 0x90, 0x81, 0x25, ++0x30, 0xE0, 0x06, 0xE0, 0x44, 0x01, 0xF0, 0x80, 0x10, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x01, 0xB9, ++0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x12, 0x47, 0x2A, 0xE4, 0xFF, 0x90, 0x81, ++0x45, 0xE0, 0x30, 0xE0, 0x48, 0x90, 0x81, 0x49, 0xE0, 0xFD, 0x60, 0x41, 0x74, 0x01, 0x7E, 0x00, ++0xA8, 0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, 0xFF, 0x90, 0x04, 0xE0, ++0xE0, 0xFB, 0xEF, 0x5B, 0x60, 0x06, 0xE4, 0x90, 0x81, 0x49, 0xF0, 0x22, 0x90, 0x81, 0x47, 0xE0, ++0xD3, 0x9D, 0x50, 0x10, 0x90, 0x01, 0xC7, 0x74, 0x10, 0xF0, 0x11, 0xBE, 0x90, 0x81, 0x45, 0xE0, ++0x54, 0xFE, 0xF0, 0x22, 0x12, 0x4F, 0x0B, 0x90, 0x81, 0x49, 0xE0, 0x04, 0xF0, 0x22, 0x90, 0x80, ++0x3C, 0xE0, 0x64, 0x02, 0x60, 0x07, 0x90, 0x06, 0x90, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90, 0x81, ++0x24, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x30, 0xE0, 0x2C, 0xEF, 0x54, 0x7F, 0xF0, ++0x90, 0x04, 0xE0, 0xE0, 0x90, 0x81, 0x25, 0x30, 0xE1, 0x06, 0xE0, 0x44, 0x02, 0xF0, 0x80, 0x0F, ++0xE0, 0x54, 0xFD, 0xF0, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x04, 0xF0, 0x90, ++0x81, 0x27, 0xE0, 0x60, 0x03, 0x12, 0x47, 0x2A, 0x7F, 0x01, 0x01, 0x6E, 0xC3, 0xEE, 0x94, 0x01, ++0x40, 0x0A, 0x0D, 0xED, 0x13, 0x90, 0xFD, 0x10, 0xF0, 0xE4, 0x2F, 0xFF, 0x22, 0xC3, 0xEE, 0x94, ++0x01, 0x40, 0x24, 0x90, 0xFD, 0x11, 0xE0, 0x6D, 0x70, 0x1A, 0x90, 0x01, 0x17, 0xE0, 0xB5, 0x05, ++0x0D, 0x90, 0x01, 0xE4, 0x74, 0x77, 0xF0, 0x90, 0xFD, 0x11, 0xE4, 0xF0, 0x80, 0x06, 0xED, 0x04, ++0x90, 0xFD, 0x11, 0xF0, 0xE4, 0x2F, 0xFF, 0x22, 0xE4, 0x90, 0x81, 0x4E, 0xF0, 0xA3, 0xF0, 0xA3, ++0xF0, 0x90, 0x00, 0x83, 0xE0, 0x90, 0x81, 0x4E, 0xF0, 0x90, 0x00, 0x83, 0xE0, 0xFE, 0x90, 0x81, ++0x4E, 0xE0, 0xFF, 0xB5, 0x06, 0x01, 0x22, 0xC3, 0x90, 0x81, 0x50, 0xE0, 0x94, 0x64, 0x90, 0x81, ++0x4F, 0xE0, 0x94, 0x00, 0x40, 0x0D, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x81, 0x4E, ++0xE0, 0xFF, 0x22, 0x90, 0x81, 0x4F, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9, 0x80, 0xC2, 0x74, ++0x45, 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, 0xFE, 0xF6, 0x74, 0x38, 0x2F, 0xF5, 0x82, 0xE4, ++0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x82, ++0x12, 0xED, 0xF0, 0x90, 0x82, 0x11, 0xEF, 0xF0, 0xD3, 0x94, 0x07, 0x50, 0x70, 0xE0, 0xFF, 0x74, ++0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x47, 0xE0, ++0x5F, 0xFD, 0x7F, 0x47, 0x12, 0x32, 0x1E, 0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, ++0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x46, 0xE0, 0x4F, 0xFD, 0x7F, 0x46, ++0x12, 0x32, 0x1E, 0x90, 0x82, 0x12, 0xE0, 0x60, 0x18, 0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01, ++0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x45, 0xE0, 0x4F, 0x80, ++0x17, 0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, ++0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x45, 0xE0, 0x5F, 0xFD, 0x7F, 0x45, 0x80, 0x7E, 0x90, 0x82, 0x11, ++0xE0, 0x24, 0xF8, 0xF0, 0xE0, 0x24, 0x04, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, ++0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x43, 0xE0, 0x5F, 0xFD, 0x7F, 0x43, 0x12, 0x32, 0x1E, ++0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, ++0xFF, 0x90, 0x00, 0x43, 0xE0, 0x4F, 0xFD, 0x7F, 0x43, 0x12, 0x32, 0x1E, 0x90, 0x82, 0x12, 0xE0, ++0x60, 0x1D, 0x90, 0x82, 0x11, 0xE0, 0x24, 0x04, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, ++0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x42, 0xE0, 0x4F, 0xFD, 0x7F, 0x42, 0x80, 0x1C, 0x90, ++0x82, 0x11, 0xE0, 0x24, 0x04, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, ++0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x42, 0xE0, 0x5F, 0xFD, 0x7F, 0x42, 0x12, 0x32, 0x1E, 0xD0, 0xD0, ++0x92, 0xAF, 0x22, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xFB, 0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90, ++0x81, 0x2B, 0xF0, 0x22, 0xEF, 0x24, 0xFE, 0x60, 0x0C, 0x04, 0x70, 0x28, 0x90, 0x81, 0x2D, 0x74, ++0x01, 0xF0, 0xA3, 0xF0, 0x22, 0xED, 0x70, 0x0A, 0x90, 0x81, 0x3B, 0xE0, 0x90, 0x81, 0x2D, 0xF0, ++0x80, 0x05, 0x90, 0x81, 0x2D, 0xED, 0xF0, 0x90, 0x81, 0x2D, 0xE0, 0xA3, 0xF0, 0x90, 0x81, 0x25, ++0xE0, 0x44, 0x08, 0xF0, 0x22, 0x12, 0x4E, 0xAB, 0xEF, 0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8, ++0x74, 0x01, 0xF0, 0x80, 0x67, 0x90, 0x81, 0x2B, 0xE0, 0xFF, 0x54, 0x03, 0x60, 0x08, 0x90, 0x01, ++0xB8, 0x74, 0x02, 0xF0, 0x80, 0x56, 0x90, 0x81, 0x29, 0xE0, 0xFE, 0xE4, 0xC3, 0x9E, 0x50, 0x08, ++0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x44, 0xEF, 0x30, 0xE2, 0x08, 0x90, 0x01, 0xB8, 0x74, ++0x08, 0xF0, 0x80, 0x38, 0x90, 0x81, 0x2B, 0xE0, 0x30, 0xE4, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x10, ++0xF0, 0x80, 0x29, 0x90, 0x81, 0x25, 0xE0, 0x13, 0x13, 0x54, 0x3F, 0x20, 0xE0, 0x08, 0x90, 0x01, ++0xB8, 0x74, 0x20, 0xF0, 0x80, 0x16, 0x90, 0x81, 0x3E, 0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, ++0x80, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4, 0xF0, 0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74, ++0x04, 0xF0, 0x7F, 0x00, 0x22, 0xEF, 0x60, 0x42, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x70, 0x3A, ++0x90, 0x81, 0x25, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x05, 0x22, 0x74, 0x0F, 0xF0, 0x90, 0x06, 0x04, ++0xE0, 0x54, 0xBF, 0xF0, 0xE4, 0xFF, 0x12, 0x4F, 0x0D, 0xBF, 0x01, 0x12, 0x90, 0x81, 0x24, 0xE0, ++0x44, 0x40, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x06, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x01, ++0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0x22, 0x90, 0x05, 0x22, 0x74, 0x6F, ++0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x02, 0xF0, 0x90, 0x81, ++0x23, 0xF0, 0x22, 0x12, 0x54, 0x65, 0x90, 0x81, 0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x23, 0xF0, ++0x22, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0x13, 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x11, 0xEF, 0x54, 0xFB, ++0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0x07, 0x70, 0x42, 0x80, 0x3D, 0x90, 0x81, ++0x30, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x30, 0xE0, 0xFF, ++0xB4, 0x01, 0x02, 0x80, 0x04, 0xEF, 0xB4, 0x02, 0x06, 0x90, 0x05, 0x58, 0xE0, 0x04, 0xF0, 0x90, ++0x81, 0x38, 0xE0, 0xFF, 0x90, 0x81, 0x30, 0xE0, 0xD3, 0x9F, 0x40, 0x0F, 0x90, 0x80, 0xDE, 0xE0, ++0xB4, 0x01, 0x0B, 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFB, 0xF0, 0x22, 0x12, 0x47, 0x2A, 0x22, 0x22, ++0x90, 0x05, 0x2B, 0xE0, 0x7F, 0x00, 0x30, 0xE7, 0x02, 0x7F, 0x01, 0x22, 0x90, 0x05, 0x22, 0x74, ++0xFF, 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0, 0x22, ++0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x12, 0x49, 0xDD, 0x90, 0x81, 0x22, 0x74, 0x02, 0xF0, ++0x22, 0x12, 0x49, 0xE3, 0x90, 0x81, 0x22, 0x74, 0x02, 0xF0, 0x22, 0x90, 0x05, 0x22, 0x74, 0x6F, ++0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0, 0x90, 0x81, 0x22, 0x74, 0x04, 0xF0, 0x22, 0xAE, ++0x07, 0x12, 0x51, 0x73, 0xBF, 0x01, 0x12, 0x90, 0x81, 0x23, 0xE0, 0x64, 0x02, 0x60, 0x0A, 0xAF, ++0x06, 0x7D, 0x01, 0x12, 0x47, 0x3D, 0x7F, 0x01, 0x22, 0x7F, 0x00, 0x22, 0x90, 0x01, 0x57, 0xE0, ++0x60, 0x48, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0x13, ++0x13, 0x54, 0x3F, 0x30, 0xE0, 0x0C, 0xEF, 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, ++0xF0, 0x22, 0x90, 0x81, 0x30, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xEF, 0xF0, 0x90, ++0x81, 0x38, 0xE0, 0xFF, 0x90, 0x81, 0x30, 0xE0, 0xD3, 0x9F, 0x40, 0x0E, 0x90, 0x80, 0xDE, 0xE0, ++0xB4, 0x01, 0x07, 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFB, 0xF0, 0x22, 0x90, 0x80, 0x3F, 0xE0, 0xFF, ++0x7D, 0x01, 0x12, 0x6D, 0x69, 0x8E, 0x54, 0x8F, 0x55, 0xAD, 0x55, 0xAC, 0x54, 0xAF, 0x53, 0x12, ++0x4F, 0x82, 0xAF, 0x55, 0xAE, 0x54, 0x90, 0x04, 0x80, 0xE0, 0x54, 0x0F, 0xFD, 0xAC, 0x07, 0x74, ++0x11, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x01, 0xF0, 0x74, 0x11, 0x2C, ++0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xFB, 0xF0, 0xAC, 0x07, 0x74, 0x16, 0x2C, ++0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0xFA, 0xF0, 0x74, 0x15, 0x2C, 0xF5, 0x82, ++0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x1F, 0xF0, 0xAC, 0x07, 0x74, 0x06, 0x2C, 0xF5, 0x82, ++0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x0F, 0xF0, 0x90, 0x04, 0x53, 0xE4, 0xF0, 0x90, 0x04, ++0x52, 0xF0, 0x90, 0x04, 0x51, 0x74, 0xFF, 0xF0, 0x90, 0x04, 0x50, 0x74, 0xFD, 0xF0, 0x74, 0x14, ++0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xC0, 0x4D, 0xFD, 0x74, 0x14, 0x2F, ++0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xED, 0xF0, 0x22, 0xAB, 0x07, 0xAA, 0x06, 0xED, 0x2B, ++0xFB, 0xE4, 0x3A, 0xFA, 0xC3, 0x90, 0x80, 0xDB, 0xE0, 0x9B, 0x90, 0x80, 0xDA, 0xE0, 0x9A, 0x50, ++0x13, 0xA3, 0xE0, 0x24, 0x01, 0xFF, 0x90, 0x80, 0xDA, 0xE0, 0x34, 0x00, 0xFE, 0xC3, 0xEB, 0x9F, ++0xFB, 0xEA, 0x9E, 0xFA, 0xEA, 0x90, 0xFD, 0x11, 0xF0, 0xAF, 0x03, 0x74, 0x00, 0x2F, 0xF5, 0x82, ++0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFF, 0x22, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, ++0x81, 0x42, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x0A, 0x90, 0x00, 0x01, ++0x12, 0x1F, 0xBD, 0x90, 0x81, 0x43, 0xF0, 0x22, 0x90, 0x81, 0x45, 0xE0, 0x30, 0xE0, 0x2D, 0x90, ++0x81, 0x48, 0xE0, 0x04, 0xF0, 0xE0, 0xFF, 0x90, 0x81, 0x46, 0xE0, 0xB5, 0x07, 0x1E, 0x90, 0x06, ++0x92, 0xE0, 0x54, 0x1C, 0x70, 0x0B, 0x12, 0x4F, 0x0B, 0x90, 0x81, 0x49, 0xE0, 0x04, 0xF0, 0x80, ++0x06, 0x90, 0x06, 0x92, 0x74, 0x1C, 0xF0, 0xE4, 0x90, 0x81, 0x48, 0xF0, 0x22, 0x00, 0xBB, 0x8E, ++}; +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/Hal8188EFWImg_CE.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/Hal8188EFWImg_CE.h +new file mode 100644 +index 00000000..2328ec3c +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/Hal8188EFWImg_CE.h +@@ -0,0 +1,29 @@ ++/****************************************************************************** ++* ++* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++* ++* This program is free software; you can redistribute it and/or modify it ++* under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++* ++* ++******************************************************************************/ ++#ifndef __INC_HAL8188E_FW_IMG_H ++#define __INC_HAL8188E_FW_IMG_H ++ ++//V10(1641) ++#define Rtl8188EFWImgArrayLength 13904 ++ ++extern const u8 Rtl8188EFwImgArray[Rtl8188EFWImgArrayLength]; ++ ++#endif //__INC_HAL8188E_FW_IMG_H ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/Hal8188ERateAdaptive.c b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/Hal8188ERateAdaptive.c +new file mode 100644 +index 00000000..972f45ee +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/Hal8188ERateAdaptive.c +@@ -0,0 +1,1108 @@ ++/*++ ++Copyright (c) Realtek Semiconductor Corp. All rights reserved. ++ ++Module Name: ++ RateAdaptive.c ++ ++Abstract: ++ Implement Rate Adaptive functions for common operations. ++ ++Major Change History: ++ When Who What ++ ---------- --------------- ------------------------------- ++ 2011-08-12 Page Create. ++ ++--*/ ++#include "../odm_precomp.h" ++ ++//#if( DM_ODM_SUPPORT_TYPE == ODM_MP) ++//#include "Mp_Precomp.h" ++//#endif ++ ++#if (RATE_ADAPTIVE_SUPPORT == 1) ++// Rate adaptive parameters ++ ++ ++static u1Byte RETRY_PENALTY[PERENTRY][RETRYSIZE+1] = {{5,4,3,2,0,3},//92 , idx=0 ++ {6,5,4,3,0,4},//86 , idx=1 ++ {6,5,4,2,0,4},//81 , idx=2 ++ {8,7,6,4,0,6},//75 , idx=3 ++ {10,9,8,6,0,8},//71 , idx=4 ++ {10,9,8,4,0,8},//66 , idx=5 ++ {10,9,8,2,0,8},//62 , idx=6 ++ {10,9,8,0,0,8},//59 , idx=7 ++ {18,17,16,8,0,16},//53 , idx=8 ++ {26,25,24,16,0,24},//50 , idx=9 ++ {34,33,32,24,0,32},//47 , idx=0x0a ++ //{34,33,32,16,0,32},//43 , idx=0x0b ++ //{34,33,32,8,0,32},//40 , idx=0x0c ++ //{34,33,28,8,0,32},//37 , idx=0x0d ++ //{34,33,20,8,0,32},//32 , idx=0x0e ++ //{34,32,24,8,0,32},//26 , idx=0x0f ++ //{49,48,32,16,0,48},//20 , idx=0x10 ++ //{49,48,24,0,0,48},//17 , idx=0x11 ++ //{49,47,16,16,0,48},//15 , idx=0x12 ++ //{49,44,16,16,0,48},//12 , idx=0x13 ++ //{49,40,16,0,0,48},//9 , idx=0x14 ++ {34,31,28,20,0,32},//43 , idx=0x0b ++ {34,31,27,18,0,32},//40 , idx=0x0c ++ {34,31,26,16,0,32},//37 , idx=0x0d ++ {34,30,22,16,0,32},//32 , idx=0x0e ++ {34,30,24,16,0,32},//26 , idx=0x0f ++ {49,46,40,16,0,48},//20 , idx=0x10 ++ {49,45,32,0,0,48},//17 , idx=0x11 ++ {49,45,22,18,0,48},//15 , idx=0x12 ++ {49,40,24,16,0,48},//12 , idx=0x13 ++ {49,32,18,12,0,48},//9 , idx=0x14 ++ {49,22,18,14,0,48},//6 , idx=0x15 ++ {49,16,16,0,0,48}};//3 //3, idx=0x16 ++ ++static u1Byte RETRY_PENALTY_UP[RETRYSIZE+1]={49,44,16,16,0,48}; // 12% for rate up ++ ++static u1Byte PT_PENALTY[RETRYSIZE+1]={34,31,30,24,0,32}; ++ ++#if 0 ++static u1Byte RETRY_PENALTY_IDX[2][RATESIZE] = {{4,4,4,5,4,4,5,7,7,7,8,0x0a, // SS>TH ++ 4,4,4,4,6,0x0a,0x0b,0x0d, ++ 5,5,7,7,8,0x0b,0x0d,0x0f}, // 0329 R01 ++ {4,4,4,5,7,7,9,9,0x0c,0x0e,0x10,0x12, // SSTH ++ 4,4,4,4,6,0x0a,0x0b,0x0d, ++ 5,5,7,7,8,0x0b,0x0d,0x0f}, // 0329 R01 ++ {0x0a,0x0a,0x0a,0x0a,0x0c,0x0c,0x0e,0x10,0x11,0x12,0x12,0x13, // SSTH ++ 0x13,0x13,0x14,0x14,0x15,0x15,0x15,0x15, ++ 0x11,0x11,0x12,0x13,0x13,0x13,0x14,0x15}; ++ ++static u1Byte RSSI_THRESHOLD[RATESIZE] = {0,0,0,0, ++ 0,0,0,0,0,0x24,0x26,0x2a, ++ 0x13,0x15,0x17,0x18,0x1a,0x1c,0x1d,0x1f, ++ 0,0,0,0x1f,0x23,0x28,0x2a,0x2c}; ++#else ++ ++// wilson modify ++static u1Byte RETRY_PENALTY_IDX[2][RATESIZE] = {{4,4,4,5,4,4,5,7,7,7,8,0x0a, // SS>TH ++ 4,4,4,4,6,0x0a,0x0b,0x0d, ++ 5,5,7,7,8,0x0b,0x0d,0x0f}, // 0329 R01 ++ {0x0a,0x0a,0x0b,0x0c,0x0a,0x0a,0x0b,0x0c,0x0d,0x10,0x13,0x14, // SSTH ++ 0x0f,0x10,0x10,0x12,0x12,0x13,0x14,0x15, ++ 0x11,0x11,0x12,0x13,0x13,0x13,0x14,0x15}; ++ ++static u1Byte RSSI_THRESHOLD[RATESIZE] = {0,0,0,0, ++ 0,0,0,0,0,0x24,0x26,0x2a, ++ 0x18,0x1a,0x1d,0x1f,0x21,0x27,0x29,0x2a, ++ 0,0,0,0x1f,0x23,0x28,0x2a,0x2c}; ++ ++#endif ++ ++/*static u1Byte RSSI_THRESHOLD[RATESIZE] = {0,0,0,0, ++ 0,0,0,0,0,0x24,0x26,0x2a, ++ 0x1a,0x1c,0x1e,0x21,0x24,0x2a,0x2b,0x2d, ++ 0,0,0,0x1f,0x23,0x28,0x2a,0x2c};*/ ++static u2Byte N_THRESHOLD_HIGH[RATESIZE] = {4,4,8,16, ++ 24,36,48,72,96,144,192,216, ++ 60,80,100,160,240,400,560,640, ++ 300,320,480,720,1000,1200,1600,2000}; ++static u2Byte N_THRESHOLD_LOW[RATESIZE] = {2,2,4,8, ++ 12,18,24,36,48,72,96,108, ++ 30,40,50,80,120,200,280,320, ++ 150,160,240,360,500,600,800,1000}; ++static u1Byte TRYING_NECESSARY[RATESIZE] = {2,2,2,2, ++ 2,2,3,3,4,4,5,7, ++ 4,4,7,10,10,12,12,18, ++ 5,7,7,8,11,18,36,60}; // 0329 // 1207 ++#if 0 ++static u1Byte POOL_RETRY_TH[RATESIZE] = {30,30,30,30, ++ 30,30,25,25,20,15,15,10, ++ 30,25,25,20,15,10,10,10, ++ 30,25,25,20,15,10,10,10}; ++#endif ++ ++static u1Byte DROPING_NECESSARY[RATESIZE] = {1,1,1,1, ++ 1,2,3,4,5,6,7,8, ++ 1,2,3,4,5,6,7,8, ++ 5,6,7,8,9,10,11,12}; ++ ++ ++static u4Byte INIT_RATE_FALLBACK_TABLE[16]={0x0f8ff015, // 0: 40M BGN mode ++ 0x0f8ff010, // 1: 40M GN mode ++ 0x0f8ff005, // 2: BN mode/ 40M BGN mode ++ 0x0f8ff000, // 3: N mode ++ 0x00000ff5, // 4: BG mode ++ 0x00000ff0, // 5: G mode ++ 0x0000000d, // 6: B mode ++ 0, // 7: ++ 0, // 8: ++ 0, // 9: ++ 0, // 10: ++ 0, // 11: ++ 0, // 12: ++ 0, // 13: ++ 0, // 14: ++ 0, // 15: ++ ++ }; ++static u1Byte PendingForRateUpFail[5]={2,10,24,40,60}; ++static u2Byte DynamicTxRPTTiming[6]={0x186a, 0x30d4, 0x493e, 0x61a8, 0x7a12 ,0x927c}; // 200ms-1200ms ++ ++// End Rate adaptive parameters ++ ++static void ++odm_SetTxRPTTiming_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN PODM_RA_INFO_T pRaInfo, ++ IN u1Byte extend ++ ) ++{ ++ u1Byte idx = 0; ++ ++ for(idx=0; idx<5; idx++) ++ if(DynamicTxRPTTiming[idx] == pRaInfo->RptTime) ++ break; ++ ++ if (extend==0) // back to default timing ++ idx=0; //200ms ++ else if (extend==1) {// increase the timing ++ idx+=1; ++ if (idx>5) ++ idx=5; ++ } ++ else if (extend==2) {// decrease the timing ++ if(idx!=0) ++ idx-=1; ++ } ++ pRaInfo->RptTime=DynamicTxRPTTiming[idx]; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("pRaInfo->RptTime=0x%x\n", pRaInfo->RptTime)); ++} ++ ++static int ++odm_RateDown_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN PODM_RA_INFO_T pRaInfo ++ ) ++{ ++ u1Byte RateID, LowestRate, HighestRate; ++ u1Byte i; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateDown_8188E()\n")); ++ if(NULL == pRaInfo) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateDown_8188E(): pRaInfo is NULL\n")); ++ return -1; ++ } ++ RateID = pRaInfo->PreRate; ++ LowestRate = pRaInfo->LowestRate; ++ HighestRate = pRaInfo->HighestRate; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ++ (" RateID=%d LowestRate=%d HighestRate=%d RateSGI=%d\n", ++ RateID, LowestRate, HighestRate, pRaInfo->RateSGI)); ++ if (RateID > HighestRate) ++ { ++ RateID=HighestRate; ++ } ++ else if(pRaInfo->RateSGI) ++ { ++ pRaInfo->RateSGI=0; ++ } ++ else if (RateID > LowestRate) ++ { ++ if (RateID > 0) ++ { ++ for (i=RateID-1; i>LowestRate;i--) ++ { ++ if (pRaInfo->RAUseRate & BIT(i)) ++ { ++ RateID=i; ++ goto RateDownFinish; ++ ++ } ++ } ++ } ++ } ++ else if (RateID <= LowestRate) ++ { ++ RateID = LowestRate; ++ } ++RateDownFinish: ++ if (pRaInfo->RAWaitingCounter==1){ ++ pRaInfo->RAWaitingCounter+=1; ++ pRaInfo->RAPendingCounter+=1; ++ } ++ else if(pRaInfo->RAWaitingCounter==0){ ++ } ++ else{ ++ pRaInfo->RAWaitingCounter=0; ++ pRaInfo->RAPendingCounter=0; ++ } ++ ++ if(pRaInfo->RAPendingCounter>=4) ++ pRaInfo->RAPendingCounter=4; ++ ++ pRaInfo->DecisionRate=RateID; ++ odm_SetTxRPTTiming_8188E(pDM_Odm,pRaInfo, 2); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate down, RPT Timing default\n")); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("RAWaitingCounter %d, RAPendingCounter %d",pRaInfo->RAWaitingCounter,pRaInfo->RAPendingCounter)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate down to RateID %d RateSGI %d\n", RateID, pRaInfo->RateSGI)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<=====odm_RateDown_8188E() \n")); ++ return 0; ++} ++ ++static int ++odm_RateUp_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN PODM_RA_INFO_T pRaInfo ++ ) ++{ ++ u1Byte RateID, HighestRate; ++ u1Byte i; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateUp_8188E() \n")); ++ if(NULL == pRaInfo) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateUp_8188E(): pRaInfo is NULL\n")); ++ return -1; ++ } ++ RateID = pRaInfo->PreRate; ++ HighestRate = pRaInfo->HighestRate; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ++ (" RateID=%d HighestRate=%d\n", ++ RateID, HighestRate)); ++ if (pRaInfo->RAWaitingCounter==1){ ++ pRaInfo->RAWaitingCounter=0; ++ pRaInfo->RAPendingCounter=0; ++ } ++ else if (pRaInfo->RAWaitingCounter>1){ ++ pRaInfo->PreRssiStaRA=pRaInfo->RssiStaRA; ++ goto RateUpfinish; ++ } ++ odm_SetTxRPTTiming_8188E(pDM_Odm,pRaInfo, 0); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateUp_8188E():Decrease RPT Timing\n")); ++ ++ if (RateID < HighestRate) ++ { ++ for (i=RateID+1; i<=HighestRate; i++) ++ { ++ if (pRaInfo->RAUseRate & BIT(i)) ++ { ++ RateID=i; ++ goto RateUpfinish; ++ } ++ } ++ } ++ else if(RateID == HighestRate) ++ { ++ if (pRaInfo->SGIEnable && (pRaInfo->RateSGI != 1)) ++ pRaInfo->RateSGI = 1; ++ else if((pRaInfo->SGIEnable) !=1 ) ++ pRaInfo->RateSGI = 0; ++ } ++ else //if((sta_info_ra->Decision_rate) > (sta_info_ra->Highest_rate)) ++ { ++ RateID = HighestRate; ++ ++ } ++RateUpfinish: ++ //if(pRaInfo->RAWaitingCounter==10) ++ if(pRaInfo->RAWaitingCounter==(4+PendingForRateUpFail[pRaInfo->RAPendingCounter])) ++ pRaInfo->RAWaitingCounter=0; ++ else ++ pRaInfo->RAWaitingCounter++; ++ ++ pRaInfo->DecisionRate=RateID; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate up to RateID %d\n", RateID)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("RAWaitingCounter %d, RAPendingCounter %d",pRaInfo->RAWaitingCounter,pRaInfo->RAPendingCounter)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<=====odm_RateUp_8188E() \n")); ++ return 0; ++} ++ ++static void odm_ResetRaCounter_8188E( IN PODM_RA_INFO_T pRaInfo){ ++ u1Byte RateID; ++ RateID=pRaInfo->DecisionRate; ++ pRaInfo->NscUp=(N_THRESHOLD_HIGH[RateID]+N_THRESHOLD_LOW[RateID])>>1; ++ pRaInfo->NscDown=(N_THRESHOLD_HIGH[RateID]+N_THRESHOLD_LOW[RateID])>>1; ++} ++ ++static void ++odm_RateDecision_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN PODM_RA_INFO_T pRaInfo ++ ) ++{ ++ u1Byte RateID = 0, RtyPtID = 0, PenaltyID1 = 0, PenaltyID2 = 0; ++ //u4Byte pool_retry; ++ static u1Byte DynamicTxRPTTimingCounter=0; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateDecision_8188E() \n")); ++ ++ if (pRaInfo->Active && (pRaInfo->TOTAL > 0)) // STA used and data packet exits ++ { ++ if ( (pRaInfo->RssiStaRA<(pRaInfo->PreRssiStaRA-3))|| (pRaInfo->RssiStaRA>(pRaInfo->PreRssiStaRA+3))){ ++ pRaInfo->RAWaitingCounter=0; ++ pRaInfo->RAPendingCounter=0; ++ } ++ // Start RA decision ++ if (pRaInfo->PreRate > pRaInfo->HighestRate) ++ RateID = pRaInfo->HighestRate; ++ else ++ RateID = pRaInfo->PreRate; ++ if (pRaInfo->RssiStaRA > RSSI_THRESHOLD[RateID]) ++ RtyPtID=0; ++ else ++ RtyPtID=1; ++ PenaltyID1 = RETRY_PENALTY_IDX[RtyPtID][RateID]; //TODO by page ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ++ (" NscDown init is %d\n", pRaInfo->NscDown)); ++ //pool_retry=pRaInfo->RTY[2]+pRaInfo->RTY[3]+pRaInfo->RTY[4]+pRaInfo->DROP; ++ pRaInfo->NscDown += pRaInfo->RTY[0] * RETRY_PENALTY[PenaltyID1][0]; ++ pRaInfo->NscDown += pRaInfo->RTY[1] * RETRY_PENALTY[PenaltyID1][1]; ++ pRaInfo->NscDown += pRaInfo->RTY[2] * RETRY_PENALTY[PenaltyID1][2]; ++ pRaInfo->NscDown += pRaInfo->RTY[3] * RETRY_PENALTY[PenaltyID1][3]; ++ pRaInfo->NscDown += pRaInfo->RTY[4] * RETRY_PENALTY[PenaltyID1][4]; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ++ (" NscDown is %d, total*penalty[5] is %d\n", ++ pRaInfo->NscDown, (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5]))); ++ if (pRaInfo->NscDown > (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5])) ++ pRaInfo->NscDown -= pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5]; ++ else ++ pRaInfo->NscDown=0; ++ ++ // rate up ++ PenaltyID2 = RETRY_PENALTY_UP_IDX[RateID]; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ++ (" NscUp init is %d\n", pRaInfo->NscUp)); ++ pRaInfo->NscUp += pRaInfo->RTY[0] * RETRY_PENALTY[PenaltyID2][0]; ++ pRaInfo->NscUp += pRaInfo->RTY[1] * RETRY_PENALTY[PenaltyID2][1]; ++ pRaInfo->NscUp += pRaInfo->RTY[2] * RETRY_PENALTY[PenaltyID2][2]; ++ pRaInfo->NscUp += pRaInfo->RTY[3] * RETRY_PENALTY[PenaltyID2][3]; ++ pRaInfo->NscUp += pRaInfo->RTY[4] * RETRY_PENALTY[PenaltyID2][4]; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ++ ("NscUp is %d, total*up[5] is %d\n", ++ pRaInfo->NscUp, (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5]))); ++ if (pRaInfo->NscUp > (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5])) ++ pRaInfo->NscUp -= pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5]; ++ else ++ pRaInfo->NscUp = 0; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE|ODM_COMP_INIT, ODM_DBG_LOUD, ++ (" RssiStaRa= %d RtyPtID=%d PenaltyID1=0x%x PenaltyID2=0x%x RateID=%d NscDown=%d NscUp=%d SGI=%d\n", ++ pRaInfo->RssiStaRA,RtyPtID, PenaltyID1,PenaltyID2, RateID, pRaInfo->NscDown, pRaInfo->NscUp, pRaInfo->RateSGI)); ++ if ((pRaInfo->NscDown < N_THRESHOLD_LOW[RateID]) ||(pRaInfo->DROP>DROPING_NECESSARY[RateID])) ++ odm_RateDown_8188E(pDM_Odm,pRaInfo); ++ //else if ((pRaInfo->NscUp > N_THRESHOLD_HIGH[RateID])&&(pool_retryNscUp > N_THRESHOLD_HIGH[RateID]) ++ odm_RateUp_8188E(pDM_Odm,pRaInfo); ++ ++ if(pRaInfo->DecisionRate > pRaInfo->HighestRate) ++ pRaInfo->DecisionRate = pRaInfo->HighestRate; ++ ++ if ((pRaInfo->DecisionRate)==(pRaInfo->PreRate)) ++ DynamicTxRPTTimingCounter+=1; ++ else ++ DynamicTxRPTTimingCounter=0; ++ ++ if (DynamicTxRPTTimingCounter>=4) { ++ odm_SetTxRPTTiming_8188E(pDM_Odm,pRaInfo, 1); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("<=====Rate don't change 4 times, Extend RPT Timing\n")); ++ DynamicTxRPTTimingCounter=0; ++ } ++ ++ pRaInfo->PreRate = pRaInfo->DecisionRate; //YJ,add,120120 ++ ++ odm_ResetRaCounter_8188E( pRaInfo); ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<=====odm_RateDecision_8188E() \n")); ++} ++ ++static int ++odm_ARFBRefresh_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN PODM_RA_INFO_T pRaInfo ++ ) ++{ // Wilson 2011/10/26 ++ u4Byte MaskFromReg; ++ s1Byte i; ++ ++ switch(pRaInfo->RateID){ ++ case RATR_INX_WIRELESS_NGB: ++ pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x0f8ff015; ++ break; ++ case RATR_INX_WIRELESS_NG: ++ pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x0f8ff010; ++ break; ++ case RATR_INX_WIRELESS_NB: ++ pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x0f8ff005; ++ break; ++ case RATR_INX_WIRELESS_N: ++ pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x0f8ff000; ++ break; ++ case RATR_INX_WIRELESS_GB: ++ pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x00000ff5; ++ break; ++ case RATR_INX_WIRELESS_G: ++ pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x00000ff0; ++ break; ++ case RATR_INX_WIRELESS_B: ++ pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x0000000d; ++ break; ++ case 12: ++ MaskFromReg=ODM_Read4Byte(pDM_Odm, REG_ARFR0); ++ pRaInfo->RAUseRate=(pRaInfo->RateMask)&MaskFromReg; ++ break; ++ case 13: ++ MaskFromReg=ODM_Read4Byte(pDM_Odm, REG_ARFR1); ++ pRaInfo->RAUseRate=(pRaInfo->RateMask)&MaskFromReg; ++ break; ++ case 14: ++ MaskFromReg=ODM_Read4Byte(pDM_Odm, REG_ARFR2); ++ pRaInfo->RAUseRate=(pRaInfo->RateMask)&MaskFromReg; ++ break; ++ case 15: ++ MaskFromReg=ODM_Read4Byte(pDM_Odm, REG_ARFR3); ++ pRaInfo->RAUseRate=(pRaInfo->RateMask)&MaskFromReg; ++ break; ++ ++ default: ++ pRaInfo->RAUseRate=(pRaInfo->RateMask); ++ break; ++ } ++ // Highest rate ++ if (pRaInfo->RAUseRate){ ++ for (i=RATESIZE;i>=0;i--) ++ { ++ if((pRaInfo->RAUseRate)&BIT(i)){ ++ pRaInfo->HighestRate=i; ++ break; ++ } ++ } ++ } ++ else{ ++ pRaInfo->HighestRate=0; ++ } ++ // Lowest rate ++ if (pRaInfo->RAUseRate){ ++ for (i=0;iRAUseRate)&BIT(i)) ++ { ++ pRaInfo->LowestRate=i; ++ break; ++ } ++ } ++ } ++ else{ ++ pRaInfo->LowestRate=0; ++ } ++ ++#if POWER_TRAINING_ACTIVE == 1 ++ if (pRaInfo->HighestRate >0x13) ++ pRaInfo->PTModeSS=3; ++ else if(pRaInfo->HighestRate >0x0b) ++ pRaInfo->PTModeSS=2; ++ else if(pRaInfo->HighestRate >0x0b) ++ pRaInfo->PTModeSS=1; ++ else ++ pRaInfo->PTModeSS=0; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ++ ("ODM_ARFBRefresh_8188E(): PTModeSS=%d\n", pRaInfo->PTModeSS)); ++ ++#endif ++ ++ if(pRaInfo->DecisionRate > pRaInfo->HighestRate) ++ pRaInfo->DecisionRate = pRaInfo->HighestRate; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ++ ("ODM_ARFBRefresh_8188E(): RateID=%d RateMask=%8.8x RAUseRate=%8.8x HighestRate=%d,DecisionRate=%d \n", ++ pRaInfo->RateID, pRaInfo->RateMask, pRaInfo->RAUseRate, pRaInfo->HighestRate,pRaInfo->DecisionRate)); ++ return 0; ++} ++ ++#if POWER_TRAINING_ACTIVE == 1 ++static void ++odm_PTTryState_8188E( ++ IN PODM_RA_INFO_T pRaInfo ++ ) ++{ ++ pRaInfo->PTTryState=0; ++ switch (pRaInfo->PTModeSS) ++ { ++ case 3: ++ if (pRaInfo->DecisionRate>=0x19) ++ pRaInfo->PTTryState=1; ++ break; ++ case 2: ++ if (pRaInfo->DecisionRate>=0x11) ++ pRaInfo->PTTryState=1; ++ break; ++ case 1: ++ if (pRaInfo->DecisionRate>=0x0a) ++ pRaInfo->PTTryState=1; ++ break; ++ case 0: ++ if (pRaInfo->DecisionRate>=0x03) ++ pRaInfo->PTTryState=1; ++ break; ++ default: ++ pRaInfo->PTTryState=0; ++ } ++ ++ if (pRaInfo->RssiStaRA<48) ++ { ++ pRaInfo->PTStage=0; ++ } ++ else if (pRaInfo->PTTryState==1) ++ { ++ if ((pRaInfo->PTStopCount>=10)||(pRaInfo->PTPreRssi>pRaInfo->RssiStaRA+5) ++ ||(pRaInfo->PTPreRssiRssiStaRA-5)||(pRaInfo->DecisionRate!=pRaInfo->PTPreRate)) ++ { ++ if (pRaInfo->PTStage==0) ++ pRaInfo->PTStage=1; ++ else if(pRaInfo->PTStage==1) ++ pRaInfo->PTStage=3; ++ else ++ pRaInfo->PTStage=5; ++ ++ pRaInfo->PTPreRssi=pRaInfo->RssiStaRA; ++ pRaInfo->PTStopCount=0; ++ ++ } ++ else{ ++ pRaInfo->RAstage=0; ++ pRaInfo->PTStopCount++; ++ } ++ } ++ else{ ++ pRaInfo->PTStage=0; ++ pRaInfo->RAstage=0; ++ } ++ pRaInfo->PTPreRate=pRaInfo->DecisionRate; ++} ++ ++static void ++odm_PTDecision_8188E( ++ IN PODM_RA_INFO_T pRaInfo ++ ) ++{ ++ u1Byte stage_BUF; ++ u1Byte j; ++ u1Byte temp_stage; ++ u4Byte numsc; ++ u4Byte num_total; ++ u1Byte stage_id; ++ ++ stage_BUF=pRaInfo->PTStage; ++ numsc = 0; ++ num_total= pRaInfo->TOTAL* PT_PENALTY[5]; ++ for(j=0;j<=4;j++) ++ { ++ numsc += pRaInfo->RTY[j] * PT_PENALTY[j]; ++ if(numsc>num_total) ++ break; ++ } ++ ++ j=j>>1; ++ temp_stage= (pRaInfo->PTStage +1)>>1; ++ if (temp_stage>j) ++ stage_id=temp_stage-j; ++ else ++ stage_id=0; ++ ++ pRaInfo->PTSmoothFactor=(pRaInfo->PTSmoothFactor>>1) + (pRaInfo->PTSmoothFactor>>2) + stage_id*16+2; ++ if (pRaInfo->PTSmoothFactor>192) ++ pRaInfo->PTSmoothFactor=192; ++ stage_id =pRaInfo->PTSmoothFactor>>6; ++ temp_stage=stage_id*2; ++ if (temp_stage!=0) ++ temp_stage-=1; ++ if (pRaInfo->DROP>3) ++ temp_stage=0; ++ pRaInfo->PTStage=temp_stage; ++ ++} ++#endif ++ ++static VOID ++odm_RATxRPTTimerSetting( ++ IN PDM_ODM_T pDM_Odm, ++ IN u2Byte minRptTime ++) ++{ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,(" =====>odm_RATxRPTTimerSetting()\n")); ++ ++ ++ if(pDM_Odm->CurrminRptTime != minRptTime){ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ++ (" CurrminRptTime =0x%04x minRptTime=0x%04x\n", pDM_Odm->CurrminRptTime, minRptTime)); ++ #if(DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_AP)) ++ ODM_RA_Set_TxRPT_Time(pDM_Odm,minRptTime); ++ #else ++ rtw_rpt_timer_cfg_cmd(pDM_Odm->Adapter,minRptTime); ++ #endif ++ pDM_Odm->CurrminRptTime = minRptTime; ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,(" <=====odm_RATxRPTTimerSetting()\n")); ++} ++ ++ ++VOID ++ODM_RASupport_Init( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("=====>ODM_RASupport_Init()\n")); ++ ++ // 2012/02/14 MH Be noticed, the init must be after IC type is recognized!!!!! ++ if (pDM_Odm->SupportICType == ODM_RTL8188E) ++ pDM_Odm->RaSupport88E = TRUE; ++ ++} ++ ++ ++ ++int ++ODM_RAInfo_Init( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID ++ ) ++{ ++ PODM_RA_INFO_T pRaInfo = &pDM_Odm->RAInfo[MacID]; ++ #if 1 ++ u1Byte WirelessMode=0xFF; //invalid value ++ u1Byte max_rate_idx = 0x13; //MCS7 ++ if(pDM_Odm->pWirelessMode!=NULL){ ++ WirelessMode=*(pDM_Odm->pWirelessMode); ++ } ++ ++ if(WirelessMode != 0xFF ){ ++ if(WirelessMode & ODM_WM_N24G) ++ max_rate_idx = 0x13; ++ else if(WirelessMode & ODM_WM_G) ++ max_rate_idx = 0x0b; ++ else if(WirelessMode & ODM_WM_B) ++ max_rate_idx = 0x03; ++ } ++ ++ //printk("%s ==>WirelessMode:0x%08x ,max_raid_idx:0x%02x\n ",__FUNCTION__,WirelessMode,max_rate_idx); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ++ ("ODM_RAInfo_Init(): WirelessMode:0x%08x ,max_raid_idx:0x%02x \n", ++ WirelessMode,max_rate_idx)); ++ ++ pRaInfo->DecisionRate = max_rate_idx; ++ pRaInfo->PreRate = max_rate_idx; ++ pRaInfo->HighestRate=max_rate_idx; ++ #else ++ pRaInfo->DecisionRate = 0x13; ++ pRaInfo->PreRate = 0x13; ++ pRaInfo->HighestRate= 0x13; ++ #endif ++ pRaInfo->LowestRate=0; ++ pRaInfo->RateID=0; ++ pRaInfo->RateMask=0xffffffff; ++ pRaInfo->RssiStaRA=0; ++ pRaInfo->PreRssiStaRA=0; ++ pRaInfo->SGIEnable=0; ++ pRaInfo->RAUseRate=0xffffffff; ++ pRaInfo->NscDown=(N_THRESHOLD_HIGH[0x13]+N_THRESHOLD_LOW[0x13])/2; ++ pRaInfo->NscUp=(N_THRESHOLD_HIGH[0x13]+N_THRESHOLD_LOW[0x13])/2; ++ pRaInfo->RateSGI=0; ++ pRaInfo->Active=1; //Active is not used at present. by page, 110819 ++ pRaInfo->RptTime = 0x927c; ++ pRaInfo->DROP=0; ++ pRaInfo->DROP1=0; ++ pRaInfo->RTY[0]=0; ++ pRaInfo->RTY[1]=0; ++ pRaInfo->RTY[2]=0; ++ pRaInfo->RTY[3]=0; ++ pRaInfo->RTY[4]=0; ++ pRaInfo->TOTAL=0; ++ pRaInfo->RAWaitingCounter=0; ++ pRaInfo->RAPendingCounter=0; ++#if POWER_TRAINING_ACTIVE == 1 ++ pRaInfo->PTActive=1; // Active when this STA is use ++ pRaInfo->PTTryState=0; ++ pRaInfo->PTStage=5; // Need to fill into HW_PWR_STATUS ++ pRaInfo->PTSmoothFactor=192; ++ pRaInfo->PTStopCount=0; ++ pRaInfo->PTPreRate=0; ++ pRaInfo->PTPreRssi=0; ++ pRaInfo->PTModeSS=0; ++ pRaInfo->RAstage=0; ++#endif ++ return 0; ++} ++ ++int ++ODM_RAInfo_Init_all( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ u1Byte MacID = 0; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("=====>\n")); ++ pDM_Odm->CurrminRptTime = 0; ++ ++ for(MacID=0; MacID= ASSOCIATE_ENTRY_NUM)) ++ return 0; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ++ ("MacID=%d SGI=%d\n", MacID, pDM_Odm->RAInfo[MacID].RateSGI)); ++ return pDM_Odm->RAInfo[MacID].RateSGI; ++} ++ ++u1Byte ++ODM_RA_GetDecisionRate_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID ++ ) ++{ ++ u1Byte DecisionRate = 0; ++ ++ if((NULL == pDM_Odm) || (MacID >= ASSOCIATE_ENTRY_NUM)) ++ return 0; ++ DecisionRate = (pDM_Odm->RAInfo[MacID].DecisionRate); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ++ (" MacID=%d DecisionRate=0x%x\n", MacID, DecisionRate)); ++ return DecisionRate; ++} ++ ++u1Byte ++ODM_RA_GetHwPwrStatus_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID ++ ) ++{ ++ u1Byte PTStage = 5; ++ if((NULL == pDM_Odm) || (MacID >= ASSOCIATE_ENTRY_NUM)) ++ return 0; ++ PTStage = (pDM_Odm->RAInfo[MacID].PTStage); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ++ ("MacID=%d PTStage=0x%x\n", MacID, PTStage)); ++ return PTStage; ++} ++ ++VOID ++ODM_RA_UpdateRateInfo_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID, ++ IN u1Byte RateID, ++ IN u4Byte RateMask, ++ IN u1Byte SGIEnable ++ ) ++{ ++ PODM_RA_INFO_T pRaInfo = NULL; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ++ ("MacID=%d RateID=0x%x RateMask=0x%x SGIEnable=%d\n", ++ MacID, RateID, RateMask, SGIEnable)); ++ if((NULL == pDM_Odm) || (MacID >= ASSOCIATE_ENTRY_NUM)) ++ return; ++ ++ pRaInfo = &(pDM_Odm->RAInfo[MacID]); ++ pRaInfo->RateID = RateID; ++ pRaInfo->RateMask = RateMask; ++ pRaInfo->SGIEnable = SGIEnable; ++ odm_ARFBRefresh_8188E(pDM_Odm, pRaInfo); ++} ++ ++VOID ++ODM_RA_SetRSSI_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID, ++ IN u1Byte Rssi ++ ) ++{ ++ PODM_RA_INFO_T pRaInfo = NULL; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ++ (" MacID=%d Rssi=%d\n", MacID, Rssi)); ++ if((NULL == pDM_Odm) || (MacID >= ASSOCIATE_ENTRY_NUM)) ++ return; ++ ++ pRaInfo = &(pDM_Odm->RAInfo[MacID]); ++ pRaInfo->RssiStaRA = Rssi; ++} ++ ++VOID ++ODM_RA_Set_TxRPT_Time( ++ IN PDM_ODM_T pDM_Odm, ++ IN u2Byte minRptTime ++ ) ++{ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP)) ++ if (minRptTime != 0xffff) ++#endif ++ ODM_Write2Byte(pDM_Odm, REG_TX_RPT_TIME, minRptTime); ++} ++ ++ ++VOID ++ODM_RA_TxRPT2Handle_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN pu1Byte TxRPT_Buf, ++ IN u2Byte TxRPT_Len, ++ IN u4Byte MacIDValidEntry0, ++ IN u4Byte MacIDValidEntry1 ++ ) ++{ ++ PODM_RA_INFO_T pRAInfo = NULL; ++ u1Byte MacId = 0; ++ pu1Byte pBuffer = NULL; ++ u4Byte valid = 0, ItemNum = 0; ++ u2Byte minRptTime = 0x927c; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("=====>ODM_RA_TxRPT2Handle_8188E(): valid0=%d valid1=%d BufferLength=%d\n", ++ MacIDValidEntry0, MacIDValidEntry1, TxRPT_Len)); ++ ++ ItemNum = TxRPT_Len >> 3; ++ pBuffer = TxRPT_Buf; ++ ++ do ++ { ++ if(MacId >= ASSOCIATE_ENTRY_NUM) ++ valid = 0; ++ else if(MacId >= 32) ++ valid = (1<<(MacId-32)) & MacIDValidEntry1; ++ else ++ valid = (1<RAInfo[MacId]); ++ if(valid) ++ { ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE)) ++ pRAInfo->RTY[0] = (u2Byte)GET_TX_REPORT_TYPE1_RERTY_0(pBuffer); ++ pRAInfo->RTY[1] = (u2Byte)GET_TX_REPORT_TYPE1_RERTY_1(pBuffer); ++ pRAInfo->RTY[2] = (u2Byte)GET_TX_REPORT_TYPE1_RERTY_2(pBuffer); ++ pRAInfo->RTY[3] = (u2Byte)GET_TX_REPORT_TYPE1_RERTY_3(pBuffer); ++ pRAInfo->RTY[4] = (u2Byte)GET_TX_REPORT_TYPE1_RERTY_4(pBuffer); ++ pRAInfo->DROP = (u2Byte)GET_TX_REPORT_TYPE1_DROP_0(pBuffer); ++ pRAInfo->DROP1= (u2Byte)GET_TX_REPORT_TYPE1_DROP_1(pBuffer); ++#else ++ pRAInfo->RTY[0] = (unsigned short)(pBuffer[1] << 8 | pBuffer[0]); ++ pRAInfo->RTY[1] = pBuffer[2]; ++ pRAInfo->RTY[2] = pBuffer[3]; ++ pRAInfo->RTY[3] = pBuffer[4]; ++ pRAInfo->RTY[4] = pBuffer[5]; ++ pRAInfo->DROP = pBuffer[6]; ++ pRAInfo->DROP1= pBuffer[7]; ++#endif ++ pRAInfo->TOTAL = pRAInfo->RTY[0] + \ ++ pRAInfo->RTY[1] + \ ++ pRAInfo->RTY[2] + \ ++ pRAInfo->RTY[3] + \ ++ pRAInfo->RTY[4] + \ ++ pRAInfo->DROP; ++ if(pRAInfo->TOTAL != 0) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ++ ("macid=%d Total=%d R0=%d R1=%d R2=%d R3=%d R4=%d D0=%d valid0=%x valid1=%x\n", ++ MacId, ++ pRAInfo->TOTAL, ++ pRAInfo->RTY[0], ++ pRAInfo->RTY[1], ++ pRAInfo->RTY[2], ++ pRAInfo->RTY[3], ++ pRAInfo->RTY[4], ++ pRAInfo->DROP, ++ MacIDValidEntry0 , ++ MacIDValidEntry1)); ++#if POWER_TRAINING_ACTIVE == 1 ++ if (pRAInfo->PTActive){ ++ if(pRAInfo->RAstage<5){ ++ odm_RateDecision_8188E(pDM_Odm,pRAInfo); ++ } ++ else if(pRAInfo->RAstage==5){ // Power training try state ++ odm_PTTryState_8188E(pRAInfo); ++ } ++ else {// RAstage==6 ++ odm_PTDecision_8188E(pRAInfo); ++ } ++ ++ // Stage_RA counter ++ if (pRAInfo->RAstage<=5) ++ pRAInfo->RAstage++; ++ else ++ pRAInfo->RAstage=0; ++ } ++ else{ ++ odm_RateDecision_8188E(pDM_Odm,pRAInfo); ++ } ++#else ++ odm_RateDecision_8188E(pDM_Odm, pRAInfo); ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ extern void RTL8188E_SetStationTxRateInfo(PDM_ODM_T, PODM_RA_INFO_T, int); ++ RTL8188E_SetStationTxRateInfo(pDM_Odm, pRAInfo, MacId); ++#ifdef DETECT_STA_EXISTANCE ++ void RTL8188E_DetectSTAExistance(PDM_ODM_T pDM_Odm, PODM_RA_INFO_T pRAInfo, int MacID); ++ RTL8188E_DetectSTAExistance(pDM_Odm, pRAInfo, MacId); ++#endif ++#endif ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ++ ("macid=%d R0=%d R1=%d R2=%d R3=%d R4=%d drop=%d valid0=%x RateID=%d SGI=%d\n", ++ MacId, ++ pRAInfo->RTY[0], ++ pRAInfo->RTY[1], ++ pRAInfo->RTY[2], ++ pRAInfo->RTY[3], ++ pRAInfo->RTY[4], ++ pRAInfo->DROP, ++ MacIDValidEntry0, ++ pRAInfo->DecisionRate, ++ pRAInfo->RateSGI)); ++ } ++ else ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, (" TOTAL=0!!!!\n")); ++ } ++ ++ if(minRptTime > pRAInfo->RptTime) ++ minRptTime = pRAInfo->RptTime; ++ ++ pBuffer += TX_RPT2_ITEM_SIZE; ++ MacId++; ++ }while(MacId < ItemNum); ++ ++ odm_RATxRPTTimerSetting(pDM_Odm,minRptTime); ++ ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("<===== ODM_RA_TxRPT2Handle_8188E()\n")); ++} ++ ++#else ++ ++static VOID ++odm_RATxRPTTimerSetting( ++ IN PDM_ODM_T pDM_Odm, ++ IN u2Byte minRptTime ++) ++{ ++ return; ++} ++ ++ ++VOID ++ODM_RASupport_Init( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ return; ++} ++ ++int ++ODM_RAInfo_Init( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID ++ ) ++{ ++ return 0; ++} ++ ++int ++ODM_RAInfo_Init_all( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ return 0; ++} ++ ++u1Byte ++ODM_RA_GetShortGI_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID ++ ) ++{ ++ return 0; ++} ++ ++u1Byte ++ODM_RA_GetDecisionRate_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID ++ ) ++{ ++ return 0; ++} ++u1Byte ++ODM_RA_GetHwPwrStatus_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID ++ ) ++{ ++ return 0; ++} ++ ++VOID ++ODM_RA_UpdateRateInfo_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID, ++ IN u1Byte RateID, ++ IN u4Byte RateMask, ++ IN u1Byte SGIEnable ++ ) ++{ ++ return; ++} ++ ++VOID ++ODM_RA_SetRSSI_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID, ++ IN u1Byte Rssi ++ ) ++{ ++ return; ++} ++ ++VOID ++ODM_RA_Set_TxRPT_Time( ++ IN PDM_ODM_T pDM_Odm, ++ IN u2Byte minRptTime ++ ) ++{ ++ return; ++} ++ ++VOID ++ODM_RA_TxRPT2Handle_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN pu1Byte TxRPT_Buf, ++ IN u2Byte TxRPT_Len, ++ IN u4Byte MacIDValidEntry0, ++ IN u4Byte MacIDValidEntry1 ++ ) ++{ ++ return; ++} ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/Hal8188ERateAdaptive.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/Hal8188ERateAdaptive.h +new file mode 100644 +index 00000000..e7c1e125 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/Hal8188ERateAdaptive.h +@@ -0,0 +1,108 @@ ++#ifndef __INC_RA_H ++#define __INC_RA_H ++/*++ ++Copyright (c) Realtek Semiconductor Corp. All rights reserved. ++ ++Module Name: ++ RateAdaptive.h ++ ++Abstract: ++ Prototype of RA and related data structure. ++ ++Major Change History: ++ When Who What ++ ---------- --------------- ------------------------------- ++ 2011-08-12 Page Create. ++--*/ ++ ++// Rate adaptive define ++#define PERENTRY 23 ++#define RETRYSIZE 5 ++#define RATESIZE 28 ++#define TX_RPT2_ITEM_SIZE 8 ++ ++#if (DM_ODM_SUPPORT_TYPE != ODM_MP) ++// ++// TX report 2 format in Rx desc ++// ++#define GET_TX_RPT2_DESC_PKT_LEN_88E(__pRxStatusDesc) LE_BITS_TO_4BYTE( __pRxStatusDesc, 0, 9) ++#define GET_TX_RPT2_DESC_MACID_VALID_1_88E(__pRxStatusDesc) LE_BITS_TO_4BYTE( __pRxStatusDesc+16, 0, 32) ++#define GET_TX_RPT2_DESC_MACID_VALID_2_88E(__pRxStatusDesc) LE_BITS_TO_4BYTE( __pRxStatusDesc+20, 0, 32) ++ ++#define GET_TX_REPORT_TYPE1_RERTY_0(__pAddr) LE_BITS_TO_4BYTE( __pAddr, 0, 16) ++#define GET_TX_REPORT_TYPE1_RERTY_1(__pAddr) LE_BITS_TO_1BYTE( __pAddr+2, 0, 8) ++#define GET_TX_REPORT_TYPE1_RERTY_2(__pAddr) LE_BITS_TO_1BYTE( __pAddr+3, 0, 8) ++#define GET_TX_REPORT_TYPE1_RERTY_3(__pAddr) LE_BITS_TO_1BYTE( __pAddr+4, 0, 8) ++#define GET_TX_REPORT_TYPE1_RERTY_4(__pAddr) LE_BITS_TO_1BYTE( __pAddr+4+1, 0, 8) ++#define GET_TX_REPORT_TYPE1_DROP_0(__pAddr) LE_BITS_TO_1BYTE( __pAddr+4+2, 0, 8) ++#define GET_TX_REPORT_TYPE1_DROP_1(__pAddr) LE_BITS_TO_1BYTE( __pAddr+4+3, 0, 8) ++#endif ++ ++// End rate adaptive define ++ ++VOID ++ODM_RASupport_Init( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++int ++ODM_RAInfo_Init_all( ++ IN PDM_ODM_T pDM_Odm ++ ); ++ ++int ++ODM_RAInfo_Init( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID ++ ); ++ ++u1Byte ++ODM_RA_GetShortGI_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID ++ ); ++ ++u1Byte ++ODM_RA_GetDecisionRate_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID ++ ); ++ ++u1Byte ++ODM_RA_GetHwPwrStatus_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID ++ ); ++VOID ++ODM_RA_UpdateRateInfo_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID, ++ IN u1Byte RateID, ++ IN u4Byte RateMask, ++ IN u1Byte SGIEnable ++ ); ++ ++VOID ++ODM_RA_SetRSSI_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte MacID, ++ IN u1Byte Rssi ++ ); ++ ++VOID ++ODM_RA_TxRPT2Handle_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN pu1Byte TxRPT_Buf, ++ IN u2Byte TxRPT_Len, ++ IN u4Byte MacIDValidEntry0, ++ IN u4Byte MacIDValidEntry1 ++ ); ++ ++ ++VOID ++ODM_RA_Set_TxRPT_Time( ++ IN PDM_ODM_T pDM_Odm, ++ IN u2Byte minRptTime ++ ); ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/Hal8188EReg.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/Hal8188EReg.h +new file mode 100644 +index 00000000..a5086c9b +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/Hal8188EReg.h +@@ -0,0 +1,47 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++//============================================================ ++// File Name: Hal8188EReg.h ++// ++// Description: ++// ++// This file is for RTL8188E register definition. ++// ++// ++//============================================================ ++#ifndef __HAL_8188E_REG_H__ ++#define __HAL_8188E_REG_H__ ++ ++// ++// Register Definition ++// ++#define TRX_ANTDIV_PATH 0x860 ++#define RX_ANTDIV_PATH 0xb2c ++#define ODM_R_A_AGC_CORE1_8188E 0xc50 ++ ++ ++// ++// Bitmap Definition ++// ++#define BIT_FA_RESET_8188E BIT0 ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_BB.c b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_BB.c +new file mode 100644 +index 00000000..0b218744 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_BB.c +@@ -0,0 +1,1448 @@ ++/****************************************************************************** ++* ++* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++* ++* This program is free software; you can redistribute it and/or modify it ++* under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++* ++* ++******************************************************************************/ ++ ++#include "../odm_precomp.h" ++ ++#ifdef CONFIG_IOL_IOREG_CFG ++#include ++#endif ++ ++#if (RTL8188E_SUPPORT == 1) ++static BOOLEAN ++CheckCondition( ++ const u4Byte Condition, ++ const u4Byte Hex ++ ) ++{ ++ u4Byte _board = (Hex & 0x000000FF); ++ u4Byte _interface = (Hex & 0x0000FF00) >> 8; ++ u4Byte _platform = (Hex & 0x00FF0000) >> 16; ++ u4Byte cond = Condition; ++ ++ if ( Condition == 0xCDCDCDCD ) ++ return TRUE; ++ ++ cond = Condition & 0x000000FF; ++ if ( (_board != cond) && (cond != 0xFF) ) ++ return FALSE; ++ ++ cond = Condition & 0x0000FF00; ++ cond = cond >> 8; ++ if ( ((_interface & cond) == 0) && (cond != 0x07) ) ++ return FALSE; ++ ++ cond = Condition & 0x00FF0000; ++ cond = cond >> 16; ++ if ( ((_platform & cond) == 0) && (cond != 0x0F) ) ++ return FALSE; ++ return TRUE; ++} ++ ++ ++/****************************************************************************** ++* AGC_TAB_1T.TXT ++******************************************************************************/ ++ ++u4Byte Array_AGC_TAB_1T_8188E[] = { ++0xFF0F0718, 0xABCD, ++ 0xC78, 0xF7000001, ++ 0xC78, 0xF6010001, ++ 0xC78, 0xF5020001, ++ 0xC78, 0xF4030001, ++ 0xC78, 0xF3040001, ++ 0xC78, 0xF2050001, ++ 0xC78, 0xF1060001, ++ 0xC78, 0xF0070001, ++ 0xC78, 0xEF080001, ++ 0xC78, 0xEE090001, ++ 0xC78, 0xED0A0001, ++ 0xC78, 0xEC0B0001, ++ 0xC78, 0xEB0C0001, ++ 0xC78, 0xEA0D0001, ++ 0xC78, 0xE90E0001, ++ 0xC78, 0xE80F0001, ++ 0xC78, 0xE7100001, ++ 0xC78, 0xE6110001, ++ 0xC78, 0xE5120001, ++ 0xC78, 0xE4130001, ++ 0xC78, 0xE3140001, ++ 0xC78, 0xE2150001, ++ 0xC78, 0xE1160001, ++ 0xC78, 0x89170001, ++ 0xC78, 0x88180001, ++ 0xC78, 0x87190001, ++ 0xC78, 0x861A0001, ++ 0xC78, 0x851B0001, ++ 0xC78, 0x841C0001, ++ 0xC78, 0x831D0001, ++ 0xC78, 0x821E0001, ++ 0xC78, 0x811F0001, ++ 0xC78, 0x6B200001, ++ 0xC78, 0x6A210001, ++ 0xC78, 0x69220001, ++ 0xC78, 0x68230001, ++ 0xC78, 0x67240001, ++ 0xC78, 0x66250001, ++ 0xC78, 0x65260001, ++ 0xC78, 0x64270001, ++ 0xC78, 0x63280001, ++ 0xC78, 0x62290001, ++ 0xC78, 0x612A0001, ++ 0xC78, 0x462B0001, ++ 0xC78, 0x452C0001, ++ 0xC78, 0x442D0001, ++ 0xC78, 0x432E0001, ++ 0xC78, 0x422F0001, ++ 0xC78, 0x41300001, ++ 0xC78, 0x40310001, ++ 0xC78, 0x40320001, ++ 0xC78, 0x40330001, ++ 0xC78, 0x40340001, ++ 0xC78, 0x40350001, ++ 0xC78, 0x40360001, ++ 0xC78, 0x40370001, ++ 0xC78, 0x40380001, ++ 0xC78, 0x40390001, ++ 0xC78, 0x403A0001, ++ 0xC78, 0x403B0001, ++ 0xC78, 0x403C0001, ++ 0xC78, 0x403D0001, ++ 0xC78, 0x403E0001, ++ 0xC78, 0x403F0001, ++ 0xCDCDCDCD, 0xCDCD, ++ 0xC78, 0xFB000001, ++ 0xC78, 0xFB010001, ++ 0xC78, 0xFB020001, ++ 0xC78, 0xFB030001, ++ 0xC78, 0xFB040001, ++ 0xC78, 0xFB050001, ++ 0xC78, 0xFA060001, ++ 0xC78, 0xF9070001, ++ 0xC78, 0xF8080001, ++ 0xC78, 0xF7090001, ++ 0xC78, 0xF60A0001, ++ 0xC78, 0xF50B0001, ++ 0xC78, 0xF40C0001, ++ 0xC78, 0xF30D0001, ++ 0xC78, 0xF20E0001, ++ 0xC78, 0xF10F0001, ++ 0xC78, 0xF0100001, ++ 0xC78, 0xEF110001, ++ 0xC78, 0xEE120001, ++ 0xC78, 0xED130001, ++ 0xC78, 0xEC140001, ++ 0xC78, 0xEB150001, ++ 0xC78, 0xEA160001, ++ 0xC78, 0xE9170001, ++ 0xC78, 0xE8180001, ++ 0xC78, 0xE7190001, ++ 0xC78, 0xE61A0001, ++ 0xC78, 0xE51B0001, ++ 0xC78, 0xE41C0001, ++ 0xC78, 0xE31D0001, ++ 0xC78, 0xE21E0001, ++ 0xC78, 0xE11F0001, ++ 0xC78, 0x8A200001, ++ 0xC78, 0x89210001, ++ 0xC78, 0x88220001, ++ 0xC78, 0x87230001, ++ 0xC78, 0x86240001, ++ 0xC78, 0x85250001, ++ 0xC78, 0x84260001, ++ 0xC78, 0x83270001, ++ 0xC78, 0x82280001, ++ 0xC78, 0x6B290001, ++ 0xC78, 0x6A2A0001, ++ 0xC78, 0x692B0001, ++ 0xC78, 0x682C0001, ++ 0xC78, 0x672D0001, ++ 0xC78, 0x662E0001, ++ 0xC78, 0x652F0001, ++ 0xC78, 0x64300001, ++ 0xC78, 0x63310001, ++ 0xC78, 0x62320001, ++ 0xC78, 0x61330001, ++ 0xC78, 0x46340001, ++ 0xC78, 0x45350001, ++ 0xC78, 0x44360001, ++ 0xC78, 0x43370001, ++ 0xC78, 0x42380001, ++ 0xC78, 0x41390001, ++ 0xC78, 0x403A0001, ++ 0xC78, 0x403B0001, ++ 0xC78, 0x403C0001, ++ 0xC78, 0x403D0001, ++ 0xC78, 0x403E0001, ++ 0xC78, 0x403F0001, ++ 0xFF0F0718, 0xDEAD, ++ 0xFF0F0718, 0xABCD, ++ 0xC78, 0xFB400001, ++ 0xC78, 0xFA410001, ++ 0xC78, 0xF9420001, ++ 0xC78, 0xF8430001, ++ 0xC78, 0xF7440001, ++ 0xC78, 0xF6450001, ++ 0xC78, 0xF5460001, ++ 0xC78, 0xF4470001, ++ 0xC78, 0xF3480001, ++ 0xC78, 0xF2490001, ++ 0xC78, 0xF14A0001, ++ 0xC78, 0xF04B0001, ++ 0xC78, 0xEF4C0001, ++ 0xC78, 0xEE4D0001, ++ 0xC78, 0xED4E0001, ++ 0xC78, 0xEC4F0001, ++ 0xC78, 0xEB500001, ++ 0xC78, 0xEA510001, ++ 0xC78, 0xE9520001, ++ 0xC78, 0xE8530001, ++ 0xC78, 0xE7540001, ++ 0xC78, 0xE6550001, ++ 0xC78, 0xE5560001, ++ 0xC78, 0xE4570001, ++ 0xC78, 0xE3580001, ++ 0xC78, 0xE2590001, ++ 0xC78, 0xC35A0001, ++ 0xC78, 0xC25B0001, ++ 0xC78, 0xC15C0001, ++ 0xC78, 0x8B5D0001, ++ 0xC78, 0x8A5E0001, ++ 0xC78, 0x895F0001, ++ 0xC78, 0x88600001, ++ 0xC78, 0x87610001, ++ 0xC78, 0x86620001, ++ 0xC78, 0x85630001, ++ 0xC78, 0x84640001, ++ 0xC78, 0x67650001, ++ 0xC78, 0x66660001, ++ 0xC78, 0x65670001, ++ 0xC78, 0x64680001, ++ 0xC78, 0x63690001, ++ 0xC78, 0x626A0001, ++ 0xC78, 0x616B0001, ++ 0xC78, 0x606C0001, ++ 0xC78, 0x466D0001, ++ 0xC78, 0x456E0001, ++ 0xC78, 0x446F0001, ++ 0xC78, 0x43700001, ++ 0xC78, 0x42710001, ++ 0xC78, 0x41720001, ++ 0xC78, 0x40730001, ++ 0xC78, 0x40740001, ++ 0xC78, 0x40750001, ++ 0xC78, 0x40760001, ++ 0xC78, 0x40770001, ++ 0xC78, 0x40780001, ++ 0xC78, 0x40790001, ++ 0xC78, 0x407A0001, ++ 0xC78, 0x407B0001, ++ 0xC78, 0x407C0001, ++ 0xC78, 0x407D0001, ++ 0xC78, 0x407E0001, ++ 0xC78, 0x407F0001, ++ 0xCDCDCDCD, 0xCDCD, ++ 0xC78, 0xFB400001, ++ 0xC78, 0xFB410001, ++ 0xC78, 0xFB420001, ++ 0xC78, 0xFB430001, ++ 0xC78, 0xFB440001, ++ 0xC78, 0xFB450001, ++ 0xC78, 0xFB460001, ++ 0xC78, 0xFB470001, ++ 0xC78, 0xFB480001, ++ 0xC78, 0xFA490001, ++ 0xC78, 0xF94A0001, ++ 0xC78, 0xF84B0001, ++ 0xC78, 0xF74C0001, ++ 0xC78, 0xF64D0001, ++ 0xC78, 0xF54E0001, ++ 0xC78, 0xF44F0001, ++ 0xC78, 0xF3500001, ++ 0xC78, 0xF2510001, ++ 0xC78, 0xF1520001, ++ 0xC78, 0xF0530001, ++ 0xC78, 0xEF540001, ++ 0xC78, 0xEE550001, ++ 0xC78, 0xED560001, ++ 0xC78, 0xEC570001, ++ 0xC78, 0xEB580001, ++ 0xC78, 0xEA590001, ++ 0xC78, 0xE95A0001, ++ 0xC78, 0xE85B0001, ++ 0xC78, 0xE75C0001, ++ 0xC78, 0xE65D0001, ++ 0xC78, 0xE55E0001, ++ 0xC78, 0xE45F0001, ++ 0xC78, 0xE3600001, ++ 0xC78, 0xE2610001, ++ 0xC78, 0xC3620001, ++ 0xC78, 0xC2630001, ++ 0xC78, 0xC1640001, ++ 0xC78, 0x8B650001, ++ 0xC78, 0x8A660001, ++ 0xC78, 0x89670001, ++ 0xC78, 0x88680001, ++ 0xC78, 0x87690001, ++ 0xC78, 0x866A0001, ++ 0xC78, 0x856B0001, ++ 0xC78, 0x846C0001, ++ 0xC78, 0x676D0001, ++ 0xC78, 0x666E0001, ++ 0xC78, 0x656F0001, ++ 0xC78, 0x64700001, ++ 0xC78, 0x63710001, ++ 0xC78, 0x62720001, ++ 0xC78, 0x61730001, ++ 0xC78, 0x60740001, ++ 0xC78, 0x46750001, ++ 0xC78, 0x45760001, ++ 0xC78, 0x44770001, ++ 0xC78, 0x43780001, ++ 0xC78, 0x42790001, ++ 0xC78, 0x417A0001, ++ 0xC78, 0x407B0001, ++ 0xC78, 0x407C0001, ++ 0xC78, 0x407D0001, ++ 0xC78, 0x407E0001, ++ 0xC78, 0x407F0001, ++ 0xFF0F0718, 0xDEAD, ++ 0xC50, 0x69553422, ++ 0xC50, 0x69553420, ++ ++}; ++ ++HAL_STATUS ++ODM_ReadAndConfig_AGC_TAB_1T_8188E( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) ++ ++ u4Byte hex = 0; ++ u4Byte i = 0; ++ u2Byte count = 0; ++ pu4Byte ptr_array = NULL; ++ u1Byte platform = pDM_Odm->SupportPlatform; ++ u1Byte interfaceValue = pDM_Odm->SupportInterface; ++ u1Byte board = pDM_Odm->BoardType; ++ u4Byte ArrayLen = sizeof(Array_AGC_TAB_1T_8188E)/sizeof(u4Byte); ++ pu4Byte Array = Array_AGC_TAB_1T_8188E; ++ BOOLEAN biol = FALSE; ++#ifdef CONFIG_IOL_IOREG_CFG ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ struct xmit_frame *pxmit_frame; ++ u8 bndy_cnt=1; ++#endif//#ifdef CONFIG_IOL_IOREG_CFG ++ HAL_STATUS rst =HAL_STATUS_SUCCESS; ++ ++ hex += board; ++ hex += interfaceValue << 8; ++ hex += platform << 16; ++ hex += 0xFF000000; ++#ifdef CONFIG_IOL_IOREG_CFG ++ biol = rtw_IOL_applied(Adapter); ++ ++ if(biol){ ++ if((pxmit_frame= rtw_IOL_accquire_xmit_frame(Adapter)) == NULL){ ++ printk("rtw_IOL_accquire_xmit_frame failed\n"); ++ return HAL_STATUS_FAILURE; ++ } ++ } ++#endif//#ifdef CONFIG_IOL_IOREG_CFG ++ ++ for (i = 0; i < ArrayLen; i += 2 ) ++ { ++ u4Byte v1 = Array[i]; ++ u4Byte v2 = Array[i+1]; ++ ++ // This (offset, data) pair meets the condition. ++ if ( v1 < 0xCDCDCDCD ) ++ { ++ #ifdef CONFIG_IOL_IOREG_CFG ++ if(biol){ ++ if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) ++ bndy_cnt++; ++ rtw_IOL_append_WD_cmd(pxmit_frame,(u2Byte)v1, v2,bMaskDWord); ++ } ++ else ++ #endif //#ifdef CONFIG_IOL_IOREG_CFG ++ { ++ odm_ConfigBB_AGC_8188E(pDM_Odm, v1, bMaskDWord, v2); ++ } ++ continue; ++ } ++ else ++ { // This line is the start line of branch. ++ if ( !CheckCondition(Array[i], hex) ) ++ { // Discard the following (offset, data) pairs. ++ READ_NEXT_PAIR(v1, v2, i); ++ while ( v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen -2) ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ i -= 2; // prevent from for-loop += 2 ++ } ++ else // Configure matched pairs and skip to end of if-else. ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ while ( v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen -2) ++ { ++ #ifdef CONFIG_IOL_IOREG_CFG ++ if(biol){ ++ if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) ++ bndy_cnt++; ++ rtw_IOL_append_WD_cmd(pxmit_frame,(u2Byte)v1, v2,bMaskDWord); ++ } ++ else ++ #endif //#ifdef CONFIG_IOL_IOREG_CFG ++ { ++ odm_ConfigBB_AGC_8188E(pDM_Odm, v1, bMaskDWord, v2); ++ } ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ while (v2 != 0xDEAD && i < ArrayLen -2) ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ } ++ } ++ } ++#ifdef CONFIG_IOL_IOREG_CFG ++ if(biol){ ++ //printk("==> %s, pktlen = %d,bndy_cnt = %d\n",__FUNCTION__,pxmit_frame->attrib.pktlen+4+32,bndy_cnt); ++ if(rtw_IOL_exec_cmds_sync(pDM_Odm->Adapter, pxmit_frame, 1000, bndy_cnt)) ++ { ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ printk("~~~ %s Success !!! \n",__FUNCTION__); ++ { ++ //dump data from TX packet buffer ++ rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); ++ } ++ #endif //CONFIG_IOL_IOREG_CFG_DBG ++ ++ } ++ else{ ++ printk("~~~ %s IOL_exec_cmds Failed !!! \n",__FUNCTION__); ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ { ++ //dump data from TX packet buffer ++ rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); ++ } ++ #endif //CONFIG_IOL_IOREG_CFG_DBG ++ ++ rst = HAL_STATUS_FAILURE; ++ } ++ } ++#endif //#ifdef CONFIG_IOL_IOREG_CFG ++ return rst; ++} ++ ++/****************************************************************************** ++* AGC_TAB_1T_ICUT.TXT ++******************************************************************************/ ++ ++u4Byte Array_MP_8188E_AGC_TAB_1T_ICUT[] = { ++ 0xC78, 0xFB000001, ++ 0xC78, 0xFB010001, ++ 0xC78, 0xFB020001, ++ 0xC78, 0xFB030001, ++ 0xC78, 0xFB040001, ++ 0xC78, 0xFA050001, ++ 0xC78, 0xF9060001, ++ 0xC78, 0xF8070001, ++ 0xC78, 0xF7080001, ++ 0xC78, 0xF6090001, ++ 0xC78, 0xF50A0001, ++ 0xC78, 0xF40B0001, ++ 0xC78, 0xF30C0001, ++ 0xC78, 0xF20D0001, ++ 0xC78, 0xF10E0001, ++ 0xC78, 0xF00F0001, ++ 0xC78, 0xEF100001, ++ 0xC78, 0xEE110001, ++ 0xC78, 0xED120001, ++ 0xC78, 0xEC130001, ++ 0xC78, 0xEB140001, ++ 0xC78, 0xEA150001, ++ 0xC78, 0xE9160001, ++ 0xC78, 0xE8170001, ++ 0xC78, 0xE7180001, ++ 0xC78, 0xE6190001, ++ 0xC78, 0xE51A0001, ++ 0xC78, 0xE41B0001, ++ 0xC78, 0xC71C0001, ++ 0xC78, 0xC61D0001, ++ 0xC78, 0xC51E0001, ++ 0xC78, 0xC41F0001, ++ 0xC78, 0xC3200001, ++ 0xC78, 0xC2210001, ++ 0xC78, 0x88220001, ++ 0xC78, 0x87230001, ++ 0xC78, 0x86240001, ++ 0xC78, 0x85250001, ++ 0xC78, 0x84260001, ++ 0xC78, 0x83270001, ++ 0xC78, 0x82280001, ++ 0xC78, 0x81290001, ++ 0xC78, 0x242A0001, ++ 0xC78, 0x232B0001, ++ 0xC78, 0x222C0001, ++ 0xC78, 0x672D0001, ++ 0xC78, 0x662E0001, ++ 0xC78, 0x652F0001, ++ 0xC78, 0x64300001, ++ 0xC78, 0x63310001, ++ 0xC78, 0x62320001, ++ 0xC78, 0x61330001, ++ 0xC78, 0x60340001, ++ 0xC78, 0x4A350001, ++ 0xC78, 0x49360001, ++ 0xC78, 0x48370001, ++ 0xC78, 0x47380001, ++ 0xC78, 0x46390001, ++ 0xC78, 0x453A0001, ++ 0xC78, 0x443B0001, ++ 0xC78, 0x433C0001, ++ 0xC78, 0x423D0001, ++ 0xC78, 0x413E0001, ++ 0xC78, 0x403F0001, ++ 0xC78, 0xFB400001, ++ 0xC78, 0xFB410001, ++ 0xC78, 0xFB420001, ++ 0xC78, 0xFB430001, ++ 0xC78, 0xFB440001, ++ 0xC78, 0xFB450001, ++ 0xC78, 0xFB460001, ++ 0xC78, 0xFB470001, ++ 0xC78, 0xFA480001, ++ 0xC78, 0xF9490001, ++ 0xC78, 0xF84A0001, ++ 0xC78, 0xF74B0001, ++ 0xC78, 0xF64C0001, ++ 0xC78, 0xF54D0001, ++ 0xC78, 0xF44E0001, ++ 0xC78, 0xF34F0001, ++ 0xC78, 0xF2500001, ++ 0xC78, 0xF1510001, ++ 0xC78, 0xF0520001, ++ 0xC78, 0xEF530001, ++ 0xC78, 0xEE540001, ++ 0xC78, 0xED550001, ++ 0xC78, 0xEC560001, ++ 0xC78, 0xEB570001, ++ 0xC78, 0xEA580001, ++ 0xC78, 0xE9590001, ++ 0xC78, 0xE85A0001, ++ 0xC78, 0xE75B0001, ++ 0xC78, 0xE65C0001, ++ 0xC78, 0xE55D0001, ++ 0xC78, 0xC65E0001, ++ 0xC78, 0xC55F0001, ++ 0xC78, 0xC4600001, ++ 0xC78, 0xC3610001, ++ 0xC78, 0xC2620001, ++ 0xC78, 0xC1630001, ++ 0xC78, 0xC0640001, ++ 0xC78, 0xA3650001, ++ 0xC78, 0xA2660001, ++ 0xC78, 0xA1670001, ++ 0xC78, 0x88680001, ++ 0xC78, 0x87690001, ++ 0xC78, 0x866A0001, ++ 0xC78, 0x856B0001, ++ 0xC78, 0x846C0001, ++ 0xC78, 0x836D0001, ++ 0xC78, 0x826E0001, ++ 0xC78, 0x666F0001, ++ 0xC78, 0x65700001, ++ 0xC78, 0x64710001, ++ 0xC78, 0x63720001, ++ 0xC78, 0x62730001, ++ 0xC78, 0x61740001, ++ 0xC78, 0x48750001, ++ 0xC78, 0x47760001, ++ 0xC78, 0x46770001, ++ 0xC78, 0x45780001, ++ 0xC78, 0x44790001, ++ 0xC78, 0x437A0001, ++ 0xC78, 0x427B0001, ++ 0xC78, 0x417C0001, ++ 0xC78, 0x407D0001, ++ 0xC78, 0x407E0001, ++ 0xC78, 0x407F0001, ++ 0xC50, 0x69553422, ++ 0xC50, 0x69553420, ++ ++}; ++ ++void ++ODM_ReadAndConfig_AGC_TAB_1T_ICUT_8188E( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) ++ ++ u4Byte hex = 0; ++ u4Byte i = 0; ++ u2Byte count = 0; ++ pu4Byte ptr_array = NULL; ++ u1Byte platform = pDM_Odm->SupportPlatform; ++ u1Byte _interface = pDM_Odm->SupportInterface; ++ u1Byte board = pDM_Odm->BoardType; ++ u4Byte ArrayLen = sizeof(Array_MP_8188E_AGC_TAB_1T_ICUT)/sizeof(u4Byte); ++ pu4Byte Array = Array_MP_8188E_AGC_TAB_1T_ICUT; ++ ++ ++ hex += board; ++ hex += _interface << 8; ++ hex += platform << 16; ++ hex += 0xFF000000; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ReadAndConfig_MP_8188E_AGC_TAB_1T_ICUT, hex = 0x%X\n", hex)); ++ ++ for (i = 0; i < ArrayLen; i += 2 ) ++ { ++ u4Byte v1 = Array[i]; ++ u4Byte v2 = Array[i+1]; ++ ++ // This (offset, data) pair meets the condition. ++ if ( v1 < 0xCDCDCDCD ) ++ { ++ odm_ConfigBB_AGC_8188E(pDM_Odm, v1, bMaskDWord, v2); ++ continue; ++ } ++ else ++ { // This line is the start line of branch. ++ if ( !CheckCondition(Array[i], hex) ) ++ { // Discard the following (offset, data) pairs. ++ READ_NEXT_PAIR(v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen -2) ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ i -= 2; // prevent from for-loop += 2 ++ } ++ else // Configure matched pairs and skip to end of if-else. ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen -2) ++ { ++ odm_ConfigBB_AGC_8188E(pDM_Odm, v1, bMaskDWord, v2); ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ while (v2 != 0xDEAD && i < ArrayLen -2) ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ } ++ } ++ } ++ ++} ++ ++/****************************************************************************** ++* PHY_REG_1T.TXT ++******************************************************************************/ ++ ++u4Byte Array_PHY_REG_1T_8188E[] = { ++ 0x800, 0x80040000, ++ 0x804, 0x00000003, ++ 0x808, 0x0000FC00, ++ 0x80C, 0x0000000A, ++ 0x810, 0x10001331, ++ 0x814, 0x020C3D10, ++ 0x818, 0x02200385, ++ 0x81C, 0x00000000, ++ 0x820, 0x01000100, ++ 0x824, 0x00390204, ++ 0x828, 0x00000000, ++ 0x82C, 0x00000000, ++ 0x830, 0x00000000, ++ 0x834, 0x00000000, ++ 0x838, 0x00000000, ++ 0x83C, 0x00000000, ++ 0x840, 0x00010000, ++ 0x844, 0x00000000, ++ 0x848, 0x00000000, ++ 0x84C, 0x00000000, ++ 0x850, 0x00000000, ++ 0x854, 0x00000000, ++ 0x858, 0x569A11A9, ++ 0x85C, 0x01000014, ++ 0x860, 0x66F60110, ++ 0x864, 0x061F0649, ++ 0x868, 0x00000000, ++ 0x86C, 0x27272700, ++ 0xFF0F0718, 0xABCD, ++ 0x870, 0x07000300, ++ 0xCDCDCDCD, 0xCDCD, ++ 0x870, 0x07000760, ++ 0xFF0F0718, 0xDEAD, ++ 0x874, 0x25004000, ++ 0x878, 0x00000808, ++ 0x87C, 0x00000000, ++ 0x880, 0xB0000C1C, ++ 0x884, 0x00000001, ++ 0x888, 0x00000000, ++ 0x88C, 0xCCC000C0, ++ 0x890, 0x00000800, ++ 0x894, 0xFFFFFFFE, ++ 0x898, 0x40302010, ++ 0x89C, 0x00706050, ++ 0x900, 0x00000000, ++ 0x904, 0x00000023, ++ 0x908, 0x00000000, ++ 0x90C, 0x81121111, ++ 0x910, 0x00000002, ++ 0x914, 0x00000201, ++ 0xA00, 0x00D047C8, ++ 0xA04, 0x80FF000C, ++ 0xA08, 0x8C838300, ++ 0xA0C, 0x2E7F120F, ++ 0xA10, 0x9500BB78, ++ 0xA14, 0x1114D028, ++ 0xA18, 0x00881117, ++ 0xA1C, 0x89140F00, ++ 0xFF0F0718, 0xABCD, ++ 0xA20, 0x13130000, ++ 0xA24, 0x060A0D10, ++ 0xA28, 0x00000103, ++ 0xCDCDCDCD, 0xCDCD, ++ 0xA20, 0x1A1B0000, ++ 0xA24, 0x090E1317, ++ 0xA28, 0x00000204, ++ 0xFF0F0718, 0xDEAD, ++ 0xA2C, 0x00D30000, ++ 0xA70, 0x101FBF00, ++ 0xA74, 0x00000007, ++ 0xA78, 0x00000900, ++ 0xA7C, 0x225B0606, ++ 0xA80, 0x218075B1, ++ 0xFF0F0718, 0xABCD, ++ 0xB2C, 0x00000000, ++ 0xCDCDCDCD, 0xCDCD, ++ 0xB2C, 0x80000000, ++ 0xFF0F0718, 0xDEAD, ++ 0xC00, 0x48071D40, ++ 0xC04, 0x03A05611, ++ 0xC08, 0x000000E4, ++ 0xC0C, 0x6C6C6C6C, ++ 0xC10, 0x08800000, ++ 0xC14, 0x40000100, ++ 0xC18, 0x08800000, ++ 0xC1C, 0x40000100, ++ 0xC20, 0x00000000, ++ 0xC24, 0x00000000, ++ 0xC28, 0x00000000, ++ 0xC2C, 0x00000000, ++ 0xC30, 0x69E9AC47, ++ 0xC34, 0x469652AF, ++ 0xC38, 0x49795994, ++ 0xC3C, 0x0A97971C, ++ 0xC40, 0x1F7C403F, ++ 0xC44, 0x000100B7, ++ 0xC48, 0xEC020107, ++ 0xC4C, 0x007F037F, ++ 0xC50, 0x69553420, ++ 0xC54, 0x43BC0094, ++ 0xC58, 0x00013169, ++ 0xC5C, 0x00250492, ++ 0xC60, 0x00000000, ++ 0xC64, 0x7112848B, ++ 0xC68, 0x47C00BFF, ++ 0xC6C, 0x00000036, ++ 0xC70, 0x2C7F000D, ++ 0xC74, 0x020610DB, ++ 0xC78, 0x0000001F, ++ 0xC7C, 0x00B91612, ++ 0xFF0F0718, 0xABCD, ++ 0xC80, 0x2D4000B5, ++ 0xCDCDCDCD, 0xCDCD, ++ 0xC80, 0x390000E4, ++ 0xFF0F0718, 0xDEAD, ++ 0xC84, 0x20F60000, ++ 0xC88, 0x40000100, ++ 0xC8C, 0x20200000, ++ 0xC90, 0x00091521, ++ 0xC94, 0x00000000, ++ 0xC98, 0x00121820, ++ 0xC9C, 0x00007F7F, ++ 0xCA0, 0x00000000, ++ 0xCA4, 0x000300A0, ++ 0xCA8, 0x00000000, ++ 0xCAC, 0x00000000, ++ 0xCB0, 0x00000000, ++ 0xCB4, 0x00000000, ++ 0xCB8, 0x00000000, ++ 0xCBC, 0x28000000, ++ 0xCC0, 0x00000000, ++ 0xCC4, 0x00000000, ++ 0xCC8, 0x00000000, ++ 0xCCC, 0x00000000, ++ 0xCD0, 0x00000000, ++ 0xCD4, 0x00000000, ++ 0xCD8, 0x64B22427, ++ 0xCDC, 0x00766932, ++ 0xCE0, 0x00222222, ++ 0xCE4, 0x00000000, ++ 0xCE8, 0x37644302, ++ 0xCEC, 0x2F97D40C, ++ 0xD00, 0x00000740, ++ 0xD04, 0x00020401, ++ 0xD08, 0x0000907F, ++ 0xD0C, 0x20010201, ++ 0xD10, 0xA0633333, ++ 0xD14, 0x3333BC43, ++ 0xD18, 0x7A8F5B6F, ++ 0xD2C, 0xCC979975, ++ 0xD30, 0x00000000, ++ 0xD34, 0x80608000, ++ 0xD38, 0x00000000, ++ 0xD3C, 0x00127353, ++ 0xD40, 0x00000000, ++ 0xD44, 0x00000000, ++ 0xD48, 0x00000000, ++ 0xD4C, 0x00000000, ++ 0xD50, 0x6437140A, ++ 0xD54, 0x00000000, ++ 0xD58, 0x00000282, ++ 0xD5C, 0x30032064, ++ 0xD60, 0x4653DE68, ++ 0xD64, 0x04518A3C, ++ 0xD68, 0x00002101, ++ 0xD6C, 0x2A201C16, ++ 0xD70, 0x1812362E, ++ 0xD74, 0x322C2220, ++ 0xD78, 0x000E3C24, ++ 0xE00, 0x2D2D2D2D, ++ 0xE04, 0x2D2D2D2D, ++ 0xE08, 0x0390272D, ++ 0xE10, 0x2D2D2D2D, ++ 0xE14, 0x2D2D2D2D, ++ 0xE18, 0x2D2D2D2D, ++ 0xE1C, 0x2D2D2D2D, ++ 0xE28, 0x00000000, ++ 0xE30, 0x1000DC1F, ++ 0xE34, 0x10008C1F, ++ 0xE38, 0x02140102, ++ 0xE3C, 0x681604C2, ++ 0xE40, 0x01007C00, ++ 0xE44, 0x01004800, ++ 0xE48, 0xFB000000, ++ 0xE4C, 0x000028D1, ++ 0xE50, 0x1000DC1F, ++ 0xE54, 0x10008C1F, ++ 0xE58, 0x02140102, ++ 0xE5C, 0x28160D05, ++ 0xE60, 0x00000008, ++ 0xE68, 0x001B25A4, ++ 0xE6C, 0x00C00014, ++ 0xE70, 0x00C00014, ++ 0xE74, 0x01000014, ++ 0xE78, 0x01000014, ++ 0xE7C, 0x01000014, ++ 0xE80, 0x01000014, ++ 0xE84, 0x00C00014, ++ 0xE88, 0x01000014, ++ 0xE8C, 0x00C00014, ++ 0xED0, 0x00C00014, ++ 0xED4, 0x00C00014, ++ 0xED8, 0x00C00014, ++ 0xEDC, 0x00000014, ++ 0xEE0, 0x00000014, ++ 0xFF0F0718, 0xABCD, ++ 0xEE8, 0x32555448, ++ 0xCDCDCDCD, 0xCDCD, ++ 0xEE8, 0x21555448, ++ 0xFF0F0718, 0xDEAD, ++ 0xEEC, 0x01C00014, ++ 0xF14, 0x00000003, ++ 0xF4C, 0x00000000, ++ 0xF00, 0x00000300, ++}; ++ ++ ++HAL_STATUS ++ODM_ReadAndConfig_PHY_REG_1T_8188E( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) ++ ++ u4Byte hex = 0; ++ u4Byte i = 0; ++ u2Byte count = 0; ++ pu4Byte ptr_array = NULL; ++ u1Byte platform = pDM_Odm->SupportPlatform; ++ u1Byte interfaceValue = pDM_Odm->SupportInterface; ++ u1Byte board = pDM_Odm->BoardType; ++ u4Byte ArrayLen = sizeof(Array_PHY_REG_1T_8188E)/sizeof(u4Byte); ++ pu4Byte Array = Array_PHY_REG_1T_8188E; ++ BOOLEAN biol = FALSE; ++#ifdef CONFIG_IOL_IOREG_CFG ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ struct xmit_frame *pxmit_frame; ++ u8 bndy_cnt=1; ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ struct cmd_cmp cmpdata[ArrayLen]; ++ u4Byte cmpdata_idx=0; ++ #endif ++#endif//#ifdef CONFIG_IOL_IOREG_CFG ++ HAL_STATUS rst =HAL_STATUS_SUCCESS; ++ hex += board; ++ hex += interfaceValue << 8; ++ hex += platform << 16; ++ hex += 0xFF000000; ++#ifdef CONFIG_IOL_IOREG_CFG ++ biol = rtw_IOL_applied(Adapter); ++ ++ if(biol){ ++ if((pxmit_frame=rtw_IOL_accquire_xmit_frame(Adapter)) == NULL) ++ { ++ printk("rtw_IOL_accquire_xmit_frame failed\n"); ++ return HAL_STATUS_FAILURE; ++ } ++ } ++#endif//#ifdef CONFIG_IOL_IOREG_CFG ++ ++ for (i = 0; i < ArrayLen; i += 2 ) ++ { ++ u4Byte v1 = Array[i]; ++ u4Byte v2 = Array[i+1]; ++ ++ ++ // This (offset, data) pair meets the condition. ++ if ( v1 < 0xCDCDCDCD ) ++ { ++ #ifdef CONFIG_IOL_IOREG_CFG ++ if(biol){ ++ if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) ++ bndy_cnt++; ++ ++ ++ if (v1 == 0xfe){ ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,50); ++ } ++ else if (v1 == 0xfd){ ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,5); ++ } ++ else if (v1 == 0xfc){ ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,1); ++ } ++ else if (v1 == 0xfb){ ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame,50); ++ } ++ else if (v1 == 0xfa){ ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5); ++ } ++ else if (v1 == 0xf9){ ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame,1); ++ } ++ else{ ++ if (v1 == 0xa24) ++ pDM_Odm->RFCalibrateInfo.RegA24 = v2; ++ ++ rtw_IOL_append_WD_cmd(pxmit_frame,(u2Byte)v1, v2,bMaskDWord); ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ cmpdata[cmpdata_idx].addr = v1; ++ cmpdata[cmpdata_idx].value= v2; ++ cmpdata_idx++; ++ #endif ++ } ++ } ++ else ++ #endif //#ifdef CONFIG_IOL_IOREG_CFG ++ { ++ odm_ConfigBB_PHY_8188E(pDM_Odm, v1, bMaskDWord, v2); ++ } ++ continue; ++ } ++ else ++ { // This line is the start line of branch. ++ if ( !CheckCondition(Array[i], hex) ) ++ { // Discard the following (offset, data) pairs. ++ READ_NEXT_PAIR(v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen -2) ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ i -= 2; // prevent from for-loop += 2 ++ } ++ else // Configure matched pairs and skip to end of if-else. ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen -2) ++ { ++ #ifdef CONFIG_IOL_IOREG_CFG ++ if(biol){ ++ if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) ++ bndy_cnt++; ++ if (v1 == 0xfe){ ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,50); ++ } ++ else if (v1 == 0xfd){ ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,5); ++ } ++ else if (v1 == 0xfc){ ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,1); ++ } ++ else if (v1 == 0xfb){ ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame,50); ++ } ++ else if (v1 == 0xfa){ ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame,5); ++ } ++ else if (v1 == 0xf9){ ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame,1); ++ } ++ else{ ++ if (v1 == 0xa24) ++ pDM_Odm->RFCalibrateInfo.RegA24 = v2; ++ ++ rtw_IOL_append_WD_cmd(pxmit_frame,(u2Byte)v1, v2,bMaskDWord); ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ cmpdata[cmpdata_idx].addr = v1; ++ cmpdata[cmpdata_idx].value= v2; ++ cmpdata_idx++; ++ #endif ++ } ++ } ++ else ++ #endif //#ifdef CONFIG_IOL_IOREG_CFG ++ { ++ odm_ConfigBB_PHY_8188E(pDM_Odm, v1, bMaskDWord, v2); ++ } ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ while (v2 != 0xDEAD && i < ArrayLen -2) ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ } ++ } ++ } ++#ifdef CONFIG_IOL_IOREG_CFG ++ if(biol){ ++ //printk("==> %s, pktlen = %d,bndy_cnt = %d\n",__FUNCTION__,pxmit_frame->attrib.pktlen+4+32,bndy_cnt); ++ if(rtw_IOL_exec_cmds_sync(pDM_Odm->Adapter, pxmit_frame, 1000, bndy_cnt)) ++ { ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ printk("~~~ %s IOL_exec_cmds Success !!! \n",__FUNCTION__); ++ { ++ u4Byte idx; ++ u4Byte cdata; ++ printk(" %s data compare => array_len:%d \n",__FUNCTION__,cmpdata_idx); ++ printk("### %s data compared !!###\n",__FUNCTION__); ++ for(idx=0;idx< cmpdata_idx;idx++) ++ { ++ cdata = ODM_Read4Byte(pDM_Odm, cmpdata[idx].addr); ++ if(cdata != cmpdata[idx].value){ ++ printk(" addr:0x%04x, data:(0x%02x : 0x%02x) \n", ++ cmpdata[idx].addr,cmpdata[idx].value,cdata); ++ rst = HAL_STATUS_FAILURE; ++ } ++ } ++ printk("### %s data compared !!###\n",__FUNCTION__); ++ //if(rst == HAL_STATUS_FAILURE) ++ {//dump data from TX packet buffer ++ rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); ++ } ++ ++ } ++ #endif //CONFIG_IOL_IOREG_CFG_DBG ++ ++ } ++ else{ ++ rst = HAL_STATUS_FAILURE; ++ printk("~~~ IOL Config %s Failed !!! \n",__FUNCTION__); ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ { ++ //dump data from TX packet buffer ++ rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); ++ } ++ #endif //CONFIG_IOL_IOREG_CFG_DBG ++ } ++ } ++#endif //#ifdef CONFIG_IOL_IOREG_CFG ++ return rst; ++} ++/****************************************************************************** ++* PHY_REG_1T_ICUT.TXT ++******************************************************************************/ ++ ++u4Byte Array_MP_8188E_PHY_REG_1T_ICUT[] = { ++ 0x800, 0x80040000, ++ 0x804, 0x00000003, ++ 0x808, 0x0000FC00, ++ 0x80C, 0x0000000A, ++ 0x810, 0x10001331, ++ 0x814, 0x020C3D10, ++ 0x818, 0x02200385, ++ 0x81C, 0x00000000, ++ 0x820, 0x01000100, ++ 0x824, 0x00390204, ++ 0x828, 0x00000000, ++ 0x82C, 0x00000000, ++ 0x830, 0x00000000, ++ 0x834, 0x00000000, ++ 0x838, 0x00000000, ++ 0x83C, 0x00000000, ++ 0x840, 0x00010000, ++ 0x844, 0x00000000, ++ 0x848, 0x00000000, ++ 0x84C, 0x00000000, ++ 0x850, 0x00000000, ++ 0x854, 0x00000000, ++ 0x858, 0x569A11A9, ++ 0x85C, 0x01000014, ++ 0x860, 0x66F60110, ++ 0x864, 0x061F0649, ++ 0x868, 0x00000000, ++ 0x86C, 0x27272700, ++ 0x870, 0x07000760, ++ 0x874, 0x25004000, ++ 0x878, 0x00000808, ++ 0x87C, 0x00000000, ++ 0x880, 0xB0000C1C, ++ 0x884, 0x00000001, ++ 0x888, 0x00000000, ++ 0x88C, 0xCCC000C0, ++ 0x890, 0x00000800, ++ 0x894, 0xFFFFFFFE, ++ 0x898, 0x40302010, ++ 0x89C, 0x00706050, ++ 0x900, 0x00000000, ++ 0x904, 0x00000023, ++ 0x908, 0x00000000, ++ 0x90C, 0x81121111, ++ 0x910, 0x00000002, ++ 0x914, 0x00000201, ++ 0xA00, 0x00D047C8, ++ 0xA04, 0x80FF000C, ++ 0xA08, 0x8C838300, ++ 0xA0C, 0x2E7F120F, ++ 0xA10, 0x9500BB78, ++ 0xA14, 0x1114D028, ++ 0xA18, 0x00881117, ++ 0xA1C, 0x89140F00, ++ 0xA20, 0x1A1B0000, ++ 0xA24, 0x090E1317, ++ 0xA28, 0x00000204, ++ 0xA2C, 0x00D30000, ++ 0xA70, 0x101FBF00, ++ 0xA74, 0x00000007, ++ 0xA78, 0x00000900, ++ 0xA7C, 0x225B0606, ++ 0xA80, 0x218075B1, ++ 0xB2C, 0x80000000, ++ 0xC00, 0x48071D40, ++ 0xC04, 0x03A05611, ++ 0xC08, 0x000000E4, ++ 0xC0C, 0x6C6C6C6C, ++ 0xC10, 0x08800000, ++ 0xC14, 0x40000100, ++ 0xC18, 0x08800000, ++ 0xC1C, 0x40000100, ++ 0xC20, 0x00000000, ++ 0xC24, 0x00000000, ++ 0xC28, 0x00000000, ++ 0xC2C, 0x00000000, ++ 0xC30, 0x69E9AC47, ++ 0xC34, 0x469652AF, ++ 0xC38, 0x49795994, ++ 0xC3C, 0x0A97971C, ++ 0xC40, 0x1F7C403F, ++ 0xC44, 0x000100B7, ++ 0xC48, 0xEC020107, ++ 0xC4C, 0x007F037F, ++ 0xC50, 0x69553420, ++ 0xC54, 0x43BC0094, ++ 0xC58, 0x00013159, ++ 0xC5C, 0x00250492, ++ 0xC60, 0x00000000, ++ 0xC64, 0x7112848B, ++ 0xC68, 0x47C00BFF, ++ 0xC6C, 0x00000036, ++ 0xC70, 0x2C7F000D, ++ 0xC74, 0x028610DB, ++ 0xC78, 0x0000001F, ++ 0xC7C, 0x00B91612, ++ 0xC80, 0x390000E4, ++ 0xC84, 0x20F60000, ++ 0xC88, 0x40000100, ++ 0xC8C, 0x20200000, ++ 0xC90, 0x00091521, ++ 0xC94, 0x00000000, ++ 0xC98, 0x00121820, ++ 0xC9C, 0x00007F7F, ++ 0xCA0, 0x00000000, ++ 0xCA4, 0x000300A0, ++ 0xCA8, 0xFFFF0000, ++ 0xCAC, 0x00000000, ++ 0xCB0, 0x00000000, ++ 0xCB4, 0x00000000, ++ 0xCB8, 0x00000000, ++ 0xCBC, 0x28000000, ++ 0xCC0, 0x00000000, ++ 0xCC4, 0x00000000, ++ 0xCC8, 0x00000000, ++ 0xCCC, 0x00000000, ++ 0xCD0, 0x00000000, ++ 0xCD4, 0x00000000, ++ 0xCD8, 0x64B22427, ++ 0xCDC, 0x00766932, ++ 0xCE0, 0x00222222, ++ 0xCE4, 0x00000000, ++ 0xCE8, 0x37644302, ++ 0xCEC, 0x2F97D40C, ++ 0xD00, 0x00000740, ++ 0xD04, 0x00020401, ++ 0xD08, 0x0000907F, ++ 0xD0C, 0x20010201, ++ 0xD10, 0xA0633333, ++ 0xD14, 0x3333BC43, ++ 0xD18, 0x7A8F5B6F, ++ 0xD2C, 0xCC979975, ++ 0xD30, 0x00000000, ++ 0xD34, 0x80608000, ++ 0xD38, 0x00000000, ++ 0xD3C, 0x00127353, ++ 0xD40, 0x00000000, ++ 0xD44, 0x00000000, ++ 0xD48, 0x00000000, ++ 0xD4C, 0x00000000, ++ 0xD50, 0x6437140A, ++ 0xD54, 0x00000000, ++ 0xD58, 0x00000282, ++ 0xD5C, 0x30032064, ++ 0xD60, 0x4653DE68, ++ 0xD64, 0x04518A3C, ++ 0xD68, 0x00002101, ++ 0xD6C, 0x2A201C16, ++ 0xD70, 0x1812362E, ++ 0xD74, 0x322C2220, ++ 0xD78, 0x000E3C24, ++ 0xE00, 0x2D2D2D2D, ++ 0xE04, 0x2D2D2D2D, ++ 0xE08, 0x0390272D, ++ 0xE10, 0x2D2D2D2D, ++ 0xE14, 0x2D2D2D2D, ++ 0xE18, 0x2D2D2D2D, ++ 0xE1C, 0x2D2D2D2D, ++ 0xE28, 0x00000000, ++ 0xE30, 0x1000DC1F, ++ 0xE34, 0x10008C1F, ++ 0xE38, 0x02140102, ++ 0xE3C, 0x681604C2, ++ 0xE40, 0x01007C00, ++ 0xE44, 0x01004800, ++ 0xE48, 0xFB000000, ++ 0xE4C, 0x000028D1, ++ 0xE50, 0x1000DC1F, ++ 0xE54, 0x10008C1F, ++ 0xE58, 0x02140102, ++ 0xE5C, 0x28160D05, ++ 0xE60, 0x00000008, ++ 0xE68, 0x001B25A4, ++ 0xE6C, 0x00C00014, ++ 0xE70, 0x00C00014, ++ 0xE74, 0x01000014, ++ 0xE78, 0x01000014, ++ 0xE7C, 0x01000014, ++ 0xE80, 0x01000014, ++ 0xE84, 0x00C00014, ++ 0xE88, 0x01000014, ++ 0xE8C, 0x00C00014, ++ 0xED0, 0x00C00014, ++ 0xED4, 0x00C00014, ++ 0xED8, 0x00C00014, ++ 0xEDC, 0x00000014, ++ 0xEE0, 0x00000014, ++ 0xEEC, 0x01C00014, ++ 0xF14, 0x00000003, ++ 0xF4C, 0x00000000, ++ 0xF00, 0x00000300, ++ ++}; ++ ++void ++ODM_ReadAndConfig_PHY_REG_1T_ICUT_8188E( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) ++ ++ u4Byte hex = 0; ++ u4Byte i = 0; ++ u2Byte count = 0; ++ pu4Byte ptr_array = NULL; ++ u1Byte platform = pDM_Odm->SupportPlatform; ++ u1Byte _interface = pDM_Odm->SupportInterface; ++ u1Byte board = pDM_Odm->BoardType; ++ u4Byte ArrayLen = sizeof(Array_MP_8188E_PHY_REG_1T_ICUT)/sizeof(u4Byte); ++ pu4Byte Array = Array_MP_8188E_PHY_REG_1T_ICUT; ++ ++ ++ hex += board; ++ hex += _interface << 8; ++ hex += platform << 16; ++ hex += 0xFF000000; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ReadAndConfig_MP_8188E_PHY_REG_1T_ICUT, hex = 0x%X\n", hex)); ++ ++ for (i = 0; i < ArrayLen; i += 2 ) ++ { ++ u4Byte v1 = Array[i]; ++ u4Byte v2 = Array[i+1]; ++ ++ // This (offset, data) pair meets the condition. ++ if ( v1 < 0xCDCDCDCD ) ++ { ++ odm_ConfigBB_PHY_8188E(pDM_Odm, v1, bMaskDWord, v2); ++ continue; ++ } ++ else ++ { // This line is the start line of branch. ++ if ( !CheckCondition(Array[i], hex) ) ++ { // Discard the following (offset, data) pairs. ++ READ_NEXT_PAIR(v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen -2) ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ i -= 2; // prevent from for-loop += 2 ++ } ++ else // Configure matched pairs and skip to end of if-else. ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen -2) ++ { ++ odm_ConfigBB_PHY_8188E(pDM_Odm, v1, bMaskDWord, v2); ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ while (v2 != 0xDEAD && i < ArrayLen -2) ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ } ++ } ++ } ++ ++} ++ ++ ++/****************************************************************************** ++* PHY_REG_PG.TXT ++******************************************************************************/ ++ ++u4Byte Array_PHY_REG_PG_8188E[] = { ++ 0, 0, 0, 0x00000e08, 0x0000ff00, 0x00004000, ++ 0, 0, 0, 0x0000086c, 0xffffff00, 0x34363800, ++ 0, 0, 0, 0x00000e00, 0xffffffff, 0x42444646, ++ 0, 0, 0, 0x00000e04, 0xffffffff, 0x30343840, ++ 0, 0, 0, 0x00000e10, 0xffffffff, 0x38404244, ++ 0, 0, 0, 0x00000e14, 0xffffffff, 0x26303436 ++ ++}; ++ ++void ++ODM_ReadAndConfig_PHY_REG_PG_8188E( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ u4Byte hex = 0; ++ u4Byte i = 0; ++ u2Byte count = 0; ++ pu4Byte ptr_array = NULL; ++ u1Byte platform = pDM_Odm->SupportPlatform; ++ u1Byte interfaceValue = pDM_Odm->SupportInterface; ++ u1Byte board = pDM_Odm->BoardType; ++ u4Byte ArrayLen = sizeof(Array_PHY_REG_PG_8188E)/sizeof(u4Byte); ++ pu4Byte Array = Array_PHY_REG_PG_8188E; ++ BOOLEAN biol = FALSE; ++ ++ hex += board; ++ hex += interfaceValue << 8; ++ hex += platform << 16; ++ hex += 0xFF000000; ++ for (i = 0; i < ArrayLen; i += 6 ) ++ { ++ u4Byte v1 = Array[i]; ++ u4Byte v2 = Array[i+1]; ++ u4Byte v3 = Array[i+2]; ++ u4Byte v4 = Array[i+3]; ++ u4Byte v5 = Array[i+4]; ++ u4Byte v6 = Array[i+5]; ++ ++ // this line is a line of pure_body ++ if ( v1 < 0xCDCDCDCD ) ++ { ++ ++ odm_ConfigBB_PHY_REG_PG_8188E(pDM_Odm, v1, v2, v3); ++ ++ continue; ++ } ++ else ++ { // this line is the start of branch ++ if ( !CheckCondition(Array[i], hex) ) ++ { // don't need the hw_body ++ i += 2; // skip the pair of expression ++ v1 = Array[i]; ++ v2 = Array[i+1]; ++ v3 = Array[i+2]; ++ while (v2 != 0xDEAD) ++ { ++ i += 3; ++ v1 = Array[i]; ++ v2 = Array[i+1]; ++ v3 = Array[i+1]; ++ } ++ } ++ } ++ } ++ ++} ++ ++ ++ ++#endif // end of HWIMG_SUPPORT ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_BB.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_BB.h +new file mode 100644 +index 00000000..8fbf9b55 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_BB.h +@@ -0,0 +1,71 @@ ++/****************************************************************************** ++* ++* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++* ++* This program is free software; you can redistribute it and/or modify it ++* under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++* ++* ++******************************************************************************/ ++ ++#if (RTL8188E_SUPPORT == 1) ++#ifndef __INC_BB_8188E_HW_IMG_H ++#define __INC_BB_8188E_HW_IMG_H ++ ++//static BOOLEAN CheckCondition(const u4Byte Condition, const u4Byte Hex); ++ ++/****************************************************************************** ++* AGC_TAB_1T.TXT ++******************************************************************************/ ++ ++HAL_STATUS ++ODM_ReadAndConfig_AGC_TAB_1T_8188E( ++ IN PDM_ODM_T pDM_Odm ++); ++/****************************************************************************** ++* AGC_TAB_1T_ICUT.TXT ++******************************************************************************/ ++ ++void ++ODM_ReadAndConfig_AGC_TAB_1T_ICUT_8188E( // TC: Test Chip, MP: MP Chip ++ IN PDM_ODM_T pDM_Odm ++); ++/****************************************************************************** ++* PHY_REG_1T.TXT ++******************************************************************************/ ++ ++HAL_STATUS ++ODM_ReadAndConfig_PHY_REG_1T_8188E( ++ IN PDM_ODM_T pDM_Odm ++); ++/****************************************************************************** ++* PHY_REG_1T_ICUT.TXT ++******************************************************************************/ ++ ++void ++ODM_ReadAndConfig_PHY_REG_1T_ICUT_8188E( // TC: Test Chip, MP: MP Chip ++ IN PDM_ODM_T pDM_Odm ++); ++ ++/****************************************************************************** ++* PHY_REG_PG.TXT ++******************************************************************************/ ++ ++void ++ODM_ReadAndConfig_PHY_REG_PG_8188E( ++ IN PDM_ODM_T pDM_Odm ++); ++ ++#endif ++#endif // end of HWIMG_SUPPORT ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_FW.c b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_FW.c +new file mode 100644 +index 00000000..9b3134b5 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_FW.c +@@ -0,0 +1,1034 @@ ++/****************************************************************************** ++* ++* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++* ++* This program is free software; you can redistribute it and/or modify it ++* under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++* ++* ++******************************************************************************/ ++#if 0 ++#include "Mp_Precomp.h" ++#endif ++#include "../odm_precomp.h" ++ ++#if (RTL8188E_SUPPORT == 1) ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP)) ++ ++ ++u1Byte Array_8188E_FW_AP[] = { ++ ++}; ++u4Byte ArrayLength_8188E_FW_AP = 0; ++ ++ ++void ++ODM_ReadFirmware_8188E_FW_AP( ++ IN PDM_ODM_T pDM_Odm, ++ OUT u1Byte *pFirmware, ++ OUT u4Byte *pFirmwareSize ++) ++{ ++ ODM_MoveMemory(pDM_Odm, pFirmware, Array_8188E_FW_AP, ArrayLength_8188E_FW_AP); ++ *pFirmwareSize = ArrayLength_8188E_FW_AP; ++} ++ ++ ++#else ++ ++#if 0 ++u1Byte Array_8188E_FW_NIC[] = { ++ ++}; ++u4Byte ArrayLength_8188E_FW_NIC = 0; ++ ++ ++void ++ODM_ReadFirmware_8188E_FW_NIC( ++ IN PDM_ODM_T pDM_Odm, ++ OUT u1Byte *pFirmware, ++ OUT u4Byte *pFirmwareSize ++) ++{ ++ ODM_MoveMemory(pDM_Odm, pFirmware, Array_8188E_FW_NIC, ArrayLength_8188E_FW_NIC); ++ *pFirmwareSize = ArrayLength_8188E_FW_NIC; ++} ++#endif ++ ++const u8 Array_8188E_FW_WoWLAN[] = { ++0xE1, 0x88, 0x30, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x06, 0x27, 0x15, 0x23, 0xC8, 0x3A, 0x00, 0x00, ++0x6E, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0x46, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0xE1, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0xE1, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x4F, 0xE9, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0xE7, 0x09, 0xF6, 0x08, 0xDF, 0xFA, 0x80, 0x46, 0xE7, 0x09, 0xF2, 0x08, 0xDF, 0xFA, 0x80, 0x3E, ++0x88, 0x82, 0x8C, 0x83, 0xE7, 0x09, 0xF0, 0xA3, 0xDF, 0xFA, 0x80, 0x32, 0xE3, 0x09, 0xF6, 0x08, ++0xDF, 0xFA, 0x80, 0x78, 0xE3, 0x09, 0xF2, 0x08, 0xDF, 0xFA, 0x80, 0x70, 0x88, 0x82, 0x8C, 0x83, ++0xE3, 0x09, 0xF0, 0xA3, 0xDF, 0xFA, 0x80, 0x64, 0x89, 0x82, 0x8A, 0x83, 0xE0, 0xA3, 0xF6, 0x08, ++0xDF, 0xFA, 0x80, 0x58, 0x89, 0x82, 0x8A, 0x83, 0xE0, 0xA3, 0xF2, 0x08, 0xDF, 0xFA, 0x80, 0x4C, ++0x80, 0xD2, 0x80, 0xFA, 0x80, 0xC6, 0x80, 0xD4, 0x80, 0x69, 0x80, 0xF2, 0x80, 0x33, 0x80, 0x10, ++0x80, 0xA6, 0x80, 0xEA, 0x80, 0x9A, 0x80, 0xA8, 0x80, 0xDA, 0x80, 0xE2, 0x80, 0xCA, 0x80, 0x33, ++0x89, 0x82, 0x8A, 0x83, 0xEC, 0xFA, 0xE4, 0x93, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, ++0xCC, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xDF, 0xE9, 0xDE, 0xE7, 0x80, ++0x0D, 0x89, 0x82, 0x8A, 0x83, 0xE4, 0x93, 0xA3, 0xF6, 0x08, 0xDF, 0xF9, 0xEC, 0xFA, 0xA9, 0xF0, ++0xED, 0xFB, 0x22, 0x89, 0x82, 0x8A, 0x83, 0xEC, 0xFA, 0xE0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, ++0xC5, 0x83, 0xCC, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xDF, 0xEA, 0xDE, ++0xE8, 0x80, 0xDB, 0x89, 0x82, 0x8A, 0x83, 0xE4, 0x93, 0xA3, 0xF2, 0x08, 0xDF, 0xF9, 0x80, 0xCC, ++0x88, 0xF0, 0xEF, 0x60, 0x01, 0x0E, 0x4E, 0x60, 0xC3, 0x88, 0xF0, 0xED, 0x24, 0x02, 0xB4, 0x04, ++0x00, 0x50, 0xB9, 0xF5, 0x82, 0xEB, 0x24, 0x02, 0xB4, 0x04, 0x00, 0x50, 0xAF, 0x23, 0x23, 0x45, ++0x82, 0x23, 0x90, 0x41, 0x50, 0x73, 0xC5, 0xF0, 0xF8, 0xA3, 0xE0, 0x28, 0xF0, 0xC5, 0xF0, 0xF8, ++0xE5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 0x83, 0xE0, 0x38, 0xF0, 0x22, 0xEF, 0x5B, 0xFF, 0xEE, ++0x5A, 0xFE, 0xED, 0x59, 0xFD, 0xEC, 0x58, 0xFC, 0x22, 0xEF, 0x4B, 0xFF, 0xEE, 0x4A, 0xFE, 0xED, ++0x49, 0xFD, 0xEC, 0x48, 0xFC, 0x22, 0xE0, 0xFC, 0xA3, 0xE0, 0xFD, 0xA3, 0xE0, 0xFE, 0xA3, 0xE0, ++0xFF, 0x22, 0xE0, 0xF8, 0xA3, 0xE0, 0xF9, 0xA3, 0xE0, 0xFA, 0xA3, 0xE0, 0xFB, 0x22, 0xA4, 0x25, ++0x82, 0xF5, 0x82, 0xE5, 0xF0, 0x35, 0x83, 0xF5, 0x83, 0x22, 0xE0, 0xFB, 0xA3, 0xE0, 0xFA, 0xA3, ++0xE0, 0xF9, 0x22, 0xEB, 0xF0, 0xA3, 0xEA, 0xF0, 0xA3, 0xE9, 0xF0, 0x22, 0xD0, 0x83, 0xD0, 0x82, ++0xF8, 0xE4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0D, 0xA3, 0xA3, 0x93, 0xF8, 0x74, 0x01, ++0x93, 0xF5, 0x82, 0x88, 0x83, 0xE4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xEF, 0xA3, 0xA3, 0xA3, ++0x80, 0xDF, 0xE3, 0xF5, 0xF0, 0x09, 0xE2, 0x08, 0xB5, 0xF0, 0x6B, 0xDF, 0xF5, 0x80, 0x67, 0xE3, ++0xF5, 0xF0, 0x09, 0xE6, 0x08, 0xB5, 0xF0, 0x5E, 0xDF, 0xF5, 0x80, 0x5A, 0x87, 0xF0, 0x09, 0xE6, ++0x08, 0xB5, 0xF0, 0x52, 0xDF, 0xF6, 0x80, 0x4E, 0x87, 0xF0, 0x09, 0xE2, 0x08, 0xB5, 0xF0, 0x46, ++0xDF, 0xF6, 0x80, 0x42, 0x88, 0x82, 0x8C, 0x83, 0x87, 0xF0, 0x09, 0xE0, 0xA3, 0xB5, 0xF0, 0x36, ++0xDF, 0xF6, 0x80, 0x32, 0x88, 0x82, 0x8C, 0x83, 0x87, 0xF0, 0x09, 0xE4, 0x93, 0xA3, 0xB5, 0xF0, ++0x25, 0xDF, 0xF5, 0x80, 0x21, 0x88, 0x82, 0x8C, 0x83, 0xE3, 0xF5, 0xF0, 0x09, 0xE0, 0xA3, 0xB5, ++0xF0, 0x14, 0xDF, 0xF5, 0x80, 0x10, 0x88, 0x82, 0x8C, 0x83, 0xE3, 0xF5, 0xF0, 0x09, 0xE4, 0x93, ++0xA3, 0xB5, 0xF0, 0x02, 0xDF, 0xF4, 0x02, 0x43, 0xB1, 0x80, 0x87, 0x80, 0xE9, 0x80, 0x90, 0x80, ++0xD4, 0x80, 0x3E, 0x80, 0x15, 0x80, 0x6E, 0x80, 0x7E, 0x80, 0x9D, 0x80, 0xB7, 0x80, 0x8D, 0x80, ++0xA3, 0x80, 0x51, 0x80, 0x74, 0x80, 0x3C, 0x02, 0x43, 0xBD, 0x89, 0x82, 0x8A, 0x83, 0xEC, 0xFA, ++0xE4, 0x93, 0xF5, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xE4, 0x93, 0xA3, ++0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xB5, 0xF0, 0x76, 0xDF, 0xE3, 0xDE, 0xE1, 0x80, ++0x70, 0x89, 0x82, 0x8A, 0x83, 0xE4, 0x93, 0xF5, 0xF0, 0xA3, 0xE2, 0x08, 0xB5, 0xF0, 0x62, 0xDF, ++0xF4, 0x80, 0x5E, 0x89, 0x82, 0x8A, 0x83, 0xE0, 0xF5, 0xF0, 0xA3, 0xE6, 0x08, 0xB5, 0xF0, 0x51, ++0xDF, 0xF5, 0x80, 0x4D, 0x89, 0x82, 0x8A, 0x83, 0xE0, 0xF5, 0xF0, 0xA3, 0xE2, 0x08, 0xB5, 0xF0, ++0x40, 0xDF, 0xF5, 0x80, 0x3C, 0x89, 0x82, 0x8A, 0x83, 0xE4, 0x93, 0xF5, 0xF0, 0xA3, 0xE6, 0x08, ++0xB5, 0xF0, 0x2E, 0xDF, 0xF4, 0x80, 0x2A, 0x80, 0x02, 0x80, 0x57, 0x89, 0x82, 0x8A, 0x83, 0xEC, ++0xFA, 0xE4, 0x93, 0xF5, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xE0, 0xA3, ++0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xB5, 0xF0, 0x06, 0xDF, 0xE4, 0xDE, 0xE2, 0x80, ++0x00, 0x7F, 0xFF, 0xB5, 0xF0, 0x02, 0x0F, 0x22, 0x40, 0x02, 0x7F, 0x01, 0x22, 0x89, 0x82, 0x8A, ++0x83, 0xEC, 0xFA, 0xE0, 0xF5, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xE0, ++0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xB5, 0xF0, 0xD5, 0xDF, 0xE5, 0xDE, 0xE3, ++0x80, 0xCF, 0x89, 0x82, 0x8A, 0x83, 0xEC, 0xFA, 0xE0, 0xF5, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, ++0xCC, 0xC5, 0x83, 0xCC, 0xE4, 0x93, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xB5, ++0xF0, 0xAF, 0xDF, 0xE4, 0xDE, 0xE2, 0x80, 0xA9, 0x88, 0xF0, 0xEF, 0x60, 0x01, 0x0E, 0x4E, 0x60, ++0xAB, 0xED, 0x24, 0x02, 0xB4, 0x04, 0x00, 0x50, 0x98, 0xF5, 0x82, 0xEB, 0x24, 0x02, 0xB4, 0x04, ++0x00, 0x50, 0x8E, 0x23, 0x23, 0x45, 0x82, 0x23, 0x90, 0x42, 0xF9, 0x73, 0xC2, 0xAF, 0x80, 0xFE, ++0x32, 0x12, 0x44, 0x30, 0x85, 0xD0, 0x0B, 0x75, 0xD0, 0x08, 0xAA, 0xE0, 0xC2, 0x8C, 0xE5, 0x8A, ++0x24, 0x67, 0xF5, 0x8A, 0xE5, 0x8C, 0x34, 0x79, 0xF5, 0x8C, 0xD2, 0x8C, 0xEC, 0x24, 0x87, 0xF8, ++0xE6, 0xBC, 0x02, 0x02, 0x74, 0xFF, 0xC3, 0x95, 0x81, 0xB4, 0x40, 0x00, 0x40, 0xCE, 0x79, 0x03, ++0x78, 0x80, 0x16, 0xE6, 0x08, 0x70, 0x0B, 0xC2, 0xAF, 0xE6, 0x30, 0xE1, 0x03, 0x44, 0x18, 0xF6, ++0xD2, 0xAF, 0x08, 0xD9, 0xED, 0xEA, 0x8B, 0xD0, 0x22, 0xE5, 0x0C, 0xFF, 0x23, 0x24, 0x81, 0xF8, ++0x0F, 0x08, 0x08, 0xBF, 0x03, 0x04, 0x7F, 0x00, 0x78, 0x81, 0xE6, 0x30, 0xE4, 0xF2, 0x00, 0xE5, ++0x0C, 0xC3, 0x9F, 0x50, 0x20, 0x05, 0x0C, 0x74, 0x86, 0x25, 0x0C, 0xF8, 0xE6, 0xFD, 0xA6, 0x81, ++0x08, 0xE6, 0xAE, 0x0C, 0xBE, 0x02, 0x02, 0x74, 0xFF, 0xCD, 0xF8, 0xE8, 0x6D, 0x60, 0xE0, 0x08, ++0xE6, 0xC0, 0xE0, 0x80, 0xF6, 0xE5, 0x0C, 0xD3, 0x9F, 0x40, 0x27, 0xE5, 0x0C, 0x24, 0x87, 0xF8, ++0xE6, 0xAE, 0x0C, 0xBE, 0x02, 0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xCD, 0xF8, 0xE5, 0x81, 0x6D, ++0x60, 0x06, 0xD0, 0xE0, 0xF6, 0x18, 0x80, 0xF5, 0xE5, 0x0C, 0x24, 0x86, 0xC8, 0xF6, 0x15, 0x0C, ++0x80, 0xD3, 0xE5, 0x0C, 0x23, 0x24, 0x81, 0xF8, 0x7F, 0x04, 0xC2, 0xAF, 0xE6, 0x30, 0xE0, 0x03, ++0x10, 0xE2, 0x0C, 0x7F, 0x00, 0x30, 0xE1, 0x07, 0x30, 0xE3, 0x04, 0x7F, 0x08, 0x54, 0xF4, 0x54, ++0x7C, 0xC6, 0xD2, 0xAF, 0x54, 0x80, 0x42, 0x07, 0x22, 0x78, 0x86, 0xA6, 0x81, 0x74, 0x02, 0x60, ++0x06, 0xFF, 0x08, 0x76, 0xFF, 0xDF, 0xFB, 0x7F, 0x03, 0xE4, 0x78, 0x80, 0xF6, 0x08, 0xF6, 0x08, ++0xDF, 0xFA, 0x78, 0x81, 0x76, 0x30, 0x90, 0x47, 0x69, 0x74, 0x01, 0x93, 0xC0, 0xE0, 0xE4, 0x93, ++0xC0, 0xE0, 0x43, 0x89, 0x01, 0x75, 0x8A, 0x60, 0x75, 0x8C, 0x79, 0xD2, 0x8C, 0xD2, 0xAF, 0x22, ++0x02, 0xEF, 0xD3, 0x94, 0x02, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0x74, 0x81, 0x2F, 0x2F, 0xF8, 0xE6, ++0x20, 0xE5, 0xF4, 0xC2, 0xAF, 0xE6, 0x44, 0x30, 0xF6, 0xD2, 0xAF, 0xAE, 0x0C, 0xEE, 0xC3, 0x9F, ++0x50, 0x21, 0x0E, 0x74, 0x86, 0x2E, 0xF8, 0xE6, 0xF9, 0x08, 0xE6, 0x18, 0xBE, 0x02, 0x02, 0x74, ++0xFF, 0xFD, 0xED, 0x69, 0x60, 0x09, 0x09, 0xE7, 0x19, 0x19, 0xF7, 0x09, 0x09, 0x80, 0xF3, 0x16, ++0x16, 0x80, 0xDA, 0xEE, 0xD3, 0x9F, 0x40, 0x04, 0x05, 0x81, 0x05, 0x81, 0xEE, 0xD3, 0x9F, 0x40, ++0x22, 0x74, 0x86, 0x2E, 0xF8, 0x08, 0xE6, 0xF9, 0xEE, 0xB5, 0x0C, 0x02, 0xA9, 0x81, 0x18, 0x06, ++0x06, 0xE6, 0xFD, 0xED, 0x69, 0x60, 0x09, 0x19, 0x19, 0xE7, 0x09, 0x09, 0xF7, 0x19, 0x80, 0xF3, ++0x1E, 0x80, 0xD9, 0xEF, 0x24, 0x86, 0xF8, 0xE6, 0x04, 0xF8, 0xEF, 0x2F, 0x04, 0x90, 0x47, 0x69, ++0x93, 0xF6, 0x08, 0xEF, 0x2F, 0x93, 0xF6, 0x7F, 0x00, 0x22, 0xEF, 0xD3, 0x94, 0x02, 0x40, 0x03, ++0x7F, 0xFF, 0x22, 0xEF, 0x23, 0x24, 0x81, 0xF8, 0xE6, 0x30, 0xE5, 0xF4, 0xC2, 0xAF, 0xE6, 0x54, ++0x8C, 0xF6, 0xD2, 0xAF, 0xE5, 0x0C, 0xB5, 0x07, 0x0A, 0x74, 0x86, 0x2F, 0xF8, 0xE6, 0xF5, 0x81, ++0x02, 0x44, 0x79, 0x50, 0x2E, 0x74, 0x87, 0x2F, 0xF8, 0xE6, 0xBF, 0x02, 0x02, 0x74, 0xFF, 0xFD, ++0x18, 0xE6, 0xF9, 0x74, 0x86, 0x2F, 0xF8, 0xFB, 0xE6, 0xFC, 0xE9, 0x6C, 0x60, 0x08, 0xA8, 0x05, ++0xE7, 0xF6, 0x1D, 0x19, 0x80, 0xF4, 0xA8, 0x03, 0xA6, 0x05, 0x1F, 0xE5, 0x0C, 0xB5, 0x07, 0xE3, ++0x7F, 0x00, 0x22, 0x74, 0x87, 0x2F, 0xF8, 0xE6, 0xFD, 0x18, 0x86, 0x01, 0x0F, 0x74, 0x86, 0x2F, ++0xF8, 0xA6, 0x01, 0x08, 0x86, 0x04, 0xE5, 0x0C, 0xB5, 0x07, 0x02, 0xAC, 0x81, 0xED, 0x6C, 0x60, ++0x08, 0x0D, 0x09, 0xA8, 0x05, 0xE6, 0xF7, 0x80, 0xF4, 0xE5, 0x0C, 0xB5, 0x07, 0xDE, 0x89, 0x81, ++0x7F, 0x00, 0x22, 0xEF, 0xD3, 0x94, 0x02, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0xEF, 0x23, 0x24, 0x81, ++0xF8, 0xC2, 0xAF, 0xE6, 0x30, 0xE5, 0x05, 0x30, 0xE0, 0x02, 0xD2, 0xE4, 0xD2, 0xE2, 0xC6, 0xD2, ++0xAF, 0x7F, 0x00, 0x30, 0xE2, 0x01, 0x0F, 0x02, 0x44, 0x78, 0x8F, 0xF0, 0xE4, 0xFF, 0xFE, 0xE5, ++0x0C, 0x23, 0x24, 0x80, 0xF8, 0xC2, 0xA9, 0x30, 0xF7, 0x0D, 0x7F, 0x08, 0xE6, 0x60, 0x0B, 0x2D, ++0xF6, 0x60, 0x30, 0x50, 0x2E, 0x80, 0x07, 0x30, 0xF1, 0x06, 0xED, 0xF6, 0x60, 0x25, 0x7E, 0x02, ++0x08, 0x30, 0xF0, 0x10, 0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x23, 0x0E, 0x30, 0xE2, 0x0C, 0xD2, 0xAF, ++0x7F, 0x04, 0x80, 0x12, 0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x13, 0x54, 0xEC, 0x4E, 0xF6, 0xD2, 0xAF, ++0x02, 0x44, 0x79, 0x7F, 0x08, 0x08, 0xEF, 0x44, 0x83, 0xF4, 0xC2, 0xAF, 0x56, 0xC6, 0xD2, 0xAF, ++0x54, 0x80, 0x4F, 0xFF, 0x22, 0x02, 0x47, 0x13, 0x02, 0x45, 0x09, 0xE4, 0x93, 0xA3, 0xF8, 0xE4, ++0x93, 0xA3, 0x40, 0x03, 0xF6, 0x80, 0x01, 0xF2, 0x08, 0xDF, 0xF4, 0x80, 0x29, 0xE4, 0x93, 0xA3, ++0xF8, 0x54, 0x07, 0x24, 0x0C, 0xC8, 0xC3, 0x33, 0xC4, 0x54, 0x0F, 0x44, 0x20, 0xC8, 0x83, 0x40, ++0x04, 0xF4, 0x56, 0x80, 0x01, 0x46, 0xF6, 0xDF, 0xE4, 0x80, 0x0B, 0x01, 0x02, 0x04, 0x08, 0x10, ++0x20, 0x40, 0x80, 0x90, 0x47, 0x58, 0xE4, 0x7E, 0x01, 0x93, 0x60, 0xBC, 0xA3, 0xFF, 0x54, 0x3F, ++0x30, 0xE5, 0x09, 0x54, 0x1F, 0xFE, 0xE4, 0x93, 0xA3, 0x60, 0x01, 0x0E, 0xCF, 0x54, 0xC0, 0x25, ++0xE0, 0x60, 0xA8, 0x40, 0xB8, 0xE4, 0x93, 0xA3, 0xFA, 0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93, 0xA3, ++0xC8, 0xC5, 0x82, 0xC8, 0xCA, 0xC5, 0x83, 0xCA, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA, 0xC5, ++0x83, 0xCA, 0xDF, 0xE9, 0xDE, 0xE7, 0x80, 0xBE, 0x00, 0x41, 0x83, 0x23, 0x00, 0x41, 0x83, 0x24, ++0x00, 0x41, 0x83, 0x37, 0x00, 0x41, 0x83, 0x38, 0x00, 0x59, 0x22, 0x5F, 0xE0, 0x63, 0x3F, 0xC0, ++0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, ++0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, ++0x6F, 0xF0, 0x74, 0x47, 0xA3, 0xF0, 0xF1, 0xBE, 0x74, 0x6F, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, ++0x47, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, ++0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x00, ++0x54, 0xE0, 0x55, 0x35, 0xF5, 0x39, 0xA3, 0xE0, 0x55, 0x36, 0xF5, 0x3A, 0xA3, 0xE0, 0x55, 0x37, ++0xF5, 0x3B, 0xA3, 0xE0, 0x55, 0x38, 0xF5, 0x3C, 0xAD, 0x39, 0x7F, 0x54, 0x12, 0x32, 0x1E, 0xAD, ++0x3A, 0x7F, 0x55, 0x12, 0x32, 0x1E, 0xAD, 0x3B, 0x7F, 0x56, 0x12, 0x32, 0x1E, 0xAD, 0x3C, 0x7F, ++0x57, 0x12, 0x32, 0x1E, 0x53, 0x91, 0xEF, 0x22, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, ++0xC0, 0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, ++0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0xF8, 0xF0, 0x74, 0x47, 0xA3, 0xF0, 0x12, ++0x6E, 0x11, 0xE5, 0x41, 0x30, 0xE3, 0x02, 0x71, 0x8D, 0xE5, 0x41, 0x30, 0xE4, 0x02, 0x71, 0x66, ++0xE5, 0x43, 0x30, 0xE0, 0x02, 0x11, 0x90, 0xE5, 0x43, 0x30, 0xE1, 0x03, 0x12, 0x5B, 0x66, 0xE5, ++0x43, 0x30, 0xE2, 0x03, 0x12, 0x5A, 0xAD, 0xE5, 0x43, 0x30, 0xE3, 0x02, 0xF1, 0x53, 0xE5, 0x43, ++0x30, 0xE4, 0x02, 0xF1, 0x97, 0xE5, 0x43, 0x30, 0xE5, 0x02, 0x91, 0x36, 0xE5, 0x43, 0x30, 0xE6, ++0x02, 0xF1, 0x38, 0xE5, 0x44, 0x30, 0xE1, 0x02, 0x71, 0x7A, 0x74, 0xF8, 0x04, 0x90, 0x01, 0xC4, ++0xF0, 0x74, 0x47, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, 0xD0, 0x04, 0xD0, 0x03, 0xD0, ++0x02, 0xD0, 0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0x32, ++0xE4, 0xFF, 0x90, 0x81, 0x3B, 0xE0, 0x60, 0x77, 0x90, 0x80, 0xF7, 0xE0, 0x64, 0x01, 0x70, 0x6F, ++0x90, 0x81, 0x3A, 0xE0, 0xC4, 0x54, 0x0F, 0x60, 0x24, 0x24, 0xFE, 0x60, 0x03, 0x04, 0x70, 0x1F, ++0x90, 0x81, 0x42, 0xE0, 0x14, 0xF0, 0xE0, 0xFE, 0x60, 0x06, 0x90, 0x81, 0x44, 0xE0, 0x60, 0x0F, ++0xEE, 0x70, 0x06, 0x90, 0x81, 0x41, 0xE0, 0xA3, 0xF0, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x01, 0xEF, ++0x60, 0x3D, 0x90, 0x81, 0x3F, 0xE0, 0x44, 0x10, 0xF0, 0x90, 0x81, 0x44, 0xE0, 0x60, 0x03, 0xB4, ++0x01, 0x09, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x44, 0xE0, 0x80, 0x0D, 0xE4, 0xF5, 0x1D, 0x90, 0x81, ++0x44, 0xE0, 0x75, 0xF0, 0x03, 0xA4, 0x24, 0xFE, 0xFF, 0x90, 0x81, 0x43, 0xE0, 0x2F, 0xD1, 0xD4, ++0x90, 0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x3E, 0xE0, 0x20, 0xE2, 0x02, 0x31, 0x10, 0x22, ++0x7D, 0x01, 0x7F, 0x04, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x83, 0x36, 0xED, 0xF0, ++0x90, 0x81, 0x38, 0xE0, 0xFE, 0xC4, 0x13, 0x13, 0x54, 0x03, 0x30, 0xE0, 0x02, 0x41, 0x5D, 0xEE, ++0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x30, 0xE0, 0x02, 0x41, 0x5D, 0x90, 0x81, 0x3E, 0xE0, 0xFE, ++0x6F, 0x70, 0x02, 0x41, 0x5D, 0xEF, 0x70, 0x02, 0x21, 0xD4, 0x24, 0xFE, 0x70, 0x02, 0x41, 0x0E, ++0x24, 0xFE, 0x60, 0x48, 0x24, 0xFC, 0x70, 0x02, 0x41, 0x48, 0x24, 0xFC, 0x60, 0x02, 0x41, 0x5D, ++0xEE, 0xB4, 0x0E, 0x02, 0x51, 0xCE, 0x90, 0x81, 0x3E, 0xE0, 0x70, 0x04, 0x7F, 0x01, 0x51, 0xF6, ++0x90, 0x81, 0x3E, 0xE0, 0xB4, 0x06, 0x02, 0x51, 0xA8, 0x90, 0x81, 0x3E, 0xE0, 0xB4, 0x04, 0x0E, ++0x90, 0x83, 0x36, 0xE0, 0xFF, 0x60, 0x05, 0x12, 0x72, 0x2D, 0x80, 0x02, 0xF1, 0xD6, 0x90, 0x81, ++0x3E, 0xE0, 0x64, 0x08, 0x60, 0x02, 0x41, 0x5D, 0x71, 0x99, 0x41, 0x5D, 0x90, 0x81, 0x3E, 0xE0, ++0x70, 0x04, 0x7F, 0x01, 0x51, 0xF6, 0x90, 0x81, 0x3E, 0xE0, 0xB4, 0x06, 0x02, 0x51, 0xA8, 0x90, ++0x81, 0x3E, 0xE0, 0xB4, 0x0E, 0x07, 0x51, 0x62, 0xBF, 0x01, 0x02, 0x51, 0xCE, 0x90, 0x81, 0x3E, ++0xE0, 0x64, 0x0C, 0x60, 0x02, 0x41, 0x5D, 0x51, 0x62, 0xEF, 0x64, 0x01, 0x60, 0x02, 0x41, 0x5D, ++0x71, 0x0F, 0x41, 0x5D, 0x90, 0x81, 0x3E, 0xE0, 0xB4, 0x0E, 0x07, 0x51, 0x62, 0xBF, 0x01, 0x02, ++0x51, 0xCE, 0x90, 0x81, 0x3E, 0xE0, 0xB4, 0x06, 0x02, 0x51, 0xA8, 0x90, 0x81, 0x3E, 0xE0, 0xB4, ++0x0C, 0x07, 0x51, 0x62, 0xBF, 0x01, 0x02, 0x71, 0x0F, 0x90, 0x81, 0x3E, 0xE0, 0x64, 0x04, 0x70, ++0x5C, 0x12, 0x71, 0x7D, 0xEF, 0x64, 0x01, 0x70, 0x54, 0x12, 0x50, 0xD7, 0x80, 0x4F, 0x90, 0x81, ++0x3E, 0xE0, 0xB4, 0x0E, 0x07, 0x51, 0x62, 0xBF, 0x01, 0x02, 0x51, 0xCE, 0x90, 0x81, 0x3E, 0xE0, ++0xB4, 0x06, 0x02, 0x51, 0xA8, 0x90, 0x81, 0x3E, 0xE0, 0xB4, 0x0C, 0x07, 0x51, 0x62, 0xBF, 0x01, ++0x02, 0x71, 0x0F, 0x90, 0x81, 0x3E, 0xE0, 0x70, 0x04, 0x7F, 0x01, 0x51, 0xF6, 0x90, 0x81, 0x3E, ++0xE0, 0xB4, 0x04, 0x19, 0xF1, 0xC9, 0x80, 0x15, 0x90, 0x81, 0x3E, 0xE0, 0xB4, 0x0C, 0x0E, 0x90, ++0x81, 0x39, 0xE0, 0xFF, 0x13, 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x02, 0x71, 0x83, 0xD0, 0xD0, 0x92, ++0xAF, 0x22, 0x12, 0x71, 0x64, 0xEF, 0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x01, 0xF0, ++0x80, 0x2D, 0x90, 0x81, 0x38, 0xE0, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, 0x08, 0x90, 0x01, ++0xB8, 0x74, 0x02, 0xF0, 0x80, 0x19, 0x90, 0x81, 0x3D, 0xE0, 0xD3, 0x94, 0x04, 0x40, 0x08, 0x90, ++0x01, 0xB8, 0x74, 0x08, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4, 0xF0, 0x7F, 0x01, 0x22, 0x90, ++0x01, 0xB9, 0x74, 0x02, 0xF0, 0x7F, 0x00, 0x22, 0x90, 0x81, 0x39, 0xE0, 0x90, 0x06, 0x04, 0x20, ++0xE0, 0x0C, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x81, 0x3E, 0x74, 0x04, 0xF0, 0x80, 0x0A, 0xE0, 0x54, ++0x7F, 0xF0, 0x90, 0x81, 0x3E, 0x74, 0x0C, 0xF0, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x22, 0x90, 0x81, ++0x39, 0xE0, 0xC3, 0x13, 0x20, 0xE0, 0x08, 0x90, 0x81, 0x3E, 0x74, 0x0C, 0xF0, 0x80, 0x11, 0x90, ++0x06, 0x04, 0xE0, 0x44, 0x40, 0xF0, 0xE0, 0x44, 0x80, 0xF0, 0x90, 0x81, 0x3E, 0x74, 0x04, 0xF0, ++0x90, 0x05, 0x22, 0xE4, 0xF0, 0x22, 0x90, 0x83, 0x35, 0xEF, 0xF0, 0x71, 0xA7, 0x90, 0x83, 0x35, ++0xE0, 0x60, 0x05, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81, 0x3E, 0x74, 0x04, 0xF0, 0x22, 0x90, ++0x80, 0xF7, 0xE0, 0x64, 0x01, 0x70, 0x2D, 0x90, 0x81, 0x39, 0xE0, 0x54, 0xFD, 0xF0, 0x90, 0x05, ++0x22, 0x74, 0x6F, 0xF0, 0x7F, 0x01, 0x91, 0x52, 0xBF, 0x01, 0x0E, 0x90, 0x81, 0x38, 0xE0, 0x44, ++0x80, 0xF0, 0x90, 0x81, 0x3E, 0x74, 0x0E, 0xF0, 0x22, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, ++0x01, 0xB8, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x3B, 0xE0, 0x64, 0x01, 0x70, 0x18, 0x90, 0x81, 0x3A, ++0xE0, 0x54, 0x0F, 0x60, 0x08, 0xE4, 0xFD, 0x7F, 0x0C, 0x31, 0x14, 0x81, 0x8E, 0x90, 0x81, 0x3E, ++0xE0, 0x70, 0x02, 0x31, 0x10, 0x22, 0x12, 0x6B, 0x60, 0x7F, 0x02, 0x8F, 0x1F, 0x7F, 0x02, 0x12, ++0x46, 0x53, 0x90, 0x80, 0x01, 0xE0, 0x45, 0x1F, 0xF0, 0x22, 0x90, 0x81, 0x3B, 0xE0, 0x60, 0x02, ++0x71, 0x45, 0x22, 0x12, 0x5C, 0xFE, 0x90, 0x81, 0x3E, 0x74, 0x08, 0xF0, 0x22, 0x90, 0x81, 0x53, ++0xE0, 0x30, 0xE0, 0x04, 0x7F, 0x10, 0x71, 0x6B, 0x22, 0x71, 0xA7, 0x90, 0x05, 0x22, 0xE4, 0xF0, ++0x90, 0x81, 0x3E, 0x74, 0x0C, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x01, ++0x01, 0xE0, 0x44, 0x02, 0xF0, 0x90, 0x01, 0x00, 0x74, 0xFF, 0xF0, 0x90, 0x06, 0xB7, 0x74, 0x09, ++0xF0, 0x90, 0x06, 0xB4, 0x74, 0x86, 0xF0, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x54, ++0x7F, 0xFC, 0x90, 0x83, 0x11, 0x12, 0x20, 0xCE, 0x90, 0x83, 0x11, 0x12, 0x42, 0x26, 0x90, 0x85, ++0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, ++0xDA, 0xCC, 0xC0, 0x00, 0xC0, 0x7F, 0x8C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x85, 0xBB, 0x12, ++0x20, 0xDA, 0x00, 0xC0, 0x00, 0x14, 0x7F, 0x70, 0x7E, 0x0E, 0x12, 0x2E, 0xA2, 0x90, 0x83, 0x03, ++0x12, 0x20, 0xDA, 0x00, 0x03, 0x3E, 0x60, 0xE4, 0xFD, 0xFF, 0xF1, 0x74, 0xD0, 0xD0, 0x92, 0xAF, ++0x22, 0x91, 0x8E, 0x90, 0x81, 0x3E, 0xE0, 0x64, 0x0C, 0x60, 0x0A, 0xE4, 0xFD, 0x7F, 0x0C, 0x31, ++0x14, 0xE4, 0xFF, 0x91, 0x52, 0x22, 0x90, 0x80, 0xF7, 0xE0, 0xB4, 0x01, 0x14, 0x90, 0x81, 0x3B, ++0xE0, 0x60, 0x0E, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x02, 0xC1, 0xB2, 0x91, ++0x21, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x8F, 0x4E, 0x90, 0x04, 0x1D, 0xE0, 0x60, ++0x1E, 0x90, 0x05, 0x22, 0xE0, 0xF5, 0x51, 0x74, 0xFF, 0xF0, 0x12, 0x6F, 0xBF, 0xBF, 0x01, 0x07, ++0xAF, 0x4E, 0x12, 0x73, 0x0F, 0xB1, 0x1A, 0x90, 0x05, 0x22, 0xE5, 0x51, 0xF0, 0x80, 0x02, 0xB1, ++0x1A, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, 0x7F, 0x01, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x81, ++0x38, 0xE0, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, 0x05, 0x90, 0x01, 0x5B, 0xE4, 0xF0, 0x90, ++0x06, 0x92, 0x74, 0x02, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x04, 0xF0, 0xE4, 0xF5, 0x1D, 0x90, 0x81, ++0x4E, 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4, 0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0xD1, ++0xDD, 0x90, 0x01, 0x5B, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x38, 0xE0, 0x44, 0x08, 0xF0, 0x22, 0x74, ++0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0x3F, 0xF0, 0xEF, 0x60, 0x1D, ++0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x10, 0xF0, 0x74, 0x1F, ++0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0x22, 0x74, 0x21, 0x2D, ++0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xEF, 0xF0, 0x74, 0x1F, 0x2D, 0xF5, 0x82, ++0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x40, 0xF0, 0x22, 0x90, 0x80, 0x08, 0xE0, 0xFF, 0x7D, ++0x01, 0xB1, 0xB7, 0x8E, 0x4F, 0x8F, 0x50, 0xAD, 0x50, 0xAC, 0x4F, 0xAF, 0x4E, 0x91, 0xCF, 0xAF, ++0x50, 0xAE, 0x4F, 0x90, 0x04, 0x80, 0xE0, 0x54, 0x0F, 0xFD, 0xAC, 0x07, 0x74, 0x11, 0x2C, 0xF5, ++0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x01, 0xF0, 0x74, 0x11, 0x2C, 0xF5, 0x82, 0xE4, ++0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xFB, 0xF0, 0xAC, 0x07, 0x74, 0x16, 0x2C, 0xF5, 0x82, 0xE4, ++0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0xFA, 0xF0, 0x74, 0x15, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, ++0xF5, 0x83, 0xE0, 0x44, 0x1F, 0xF0, 0xAC, 0x07, 0x74, 0x06, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, ++0xF5, 0x83, 0xE0, 0x44, 0x0F, 0xF0, 0x90, 0x04, 0x53, 0xE4, 0xF0, 0x90, 0x04, 0x52, 0xF0, 0x90, ++0x04, 0x51, 0x74, 0xFF, 0xF0, 0x90, 0x04, 0x50, 0x74, 0xFD, 0xF0, 0x74, 0x14, 0x2C, 0xF5, 0x82, ++0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xC0, 0x4D, 0xFD, 0x74, 0x14, 0x2F, 0xF5, 0x82, 0xE4, ++0x34, 0xFC, 0xF5, 0x83, 0xED, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x83, ++0x28, 0xED, 0xF0, 0x90, 0x83, 0x27, 0xEF, 0xF0, 0xE4, 0xFD, 0xFC, 0x12, 0x5E, 0x61, 0x7C, 0x00, ++0xAD, 0x07, 0x90, 0x83, 0x27, 0xE0, 0x90, 0x04, 0x25, 0xF0, 0x90, 0x83, 0x28, 0xE0, 0x60, 0x0E, ++0x74, 0x0F, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0xAF, 0x05, ++0x74, 0x08, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE4, 0xF0, 0x74, 0x09, 0x2F, 0xF5, ++0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xF0, 0xF0, 0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, ++0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xF7, 0xF0, 0xAE, 0x04, 0xAF, 0x05, 0xD0, 0xD0, 0x92, 0xAF, ++0x22, 0x90, 0x81, 0x3B, 0xE0, 0x60, 0x12, 0x90, 0x06, 0x92, 0xE0, 0x30, 0xE1, 0x02, 0x81, 0x8E, ++0x90, 0x81, 0x38, 0xE0, 0x54, 0xF7, 0xF0, 0xD1, 0x3A, 0x22, 0x90, 0x81, 0x3D, 0xE0, 0xFF, 0x7D, ++0x01, 0x21, 0x14, 0xE4, 0x90, 0x82, 0x71, 0xF0, 0x90, 0x06, 0xA9, 0xE0, 0x90, 0x82, 0x71, 0xF0, ++0xE0, 0x54, 0xC0, 0x70, 0x0C, 0x90, 0x81, 0x3F, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x80, ++0xD9, 0x90, 0x82, 0x71, 0xE0, 0x30, 0xE6, 0x21, 0x90, 0x81, 0x3B, 0xE0, 0x64, 0x01, 0x70, 0x20, ++0x90, 0x81, 0x3F, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, ++0x04, 0xD1, 0xB2, 0x80, 0x0B, 0x91, 0x21, 0x80, 0x07, 0x90, 0x81, 0x3F, 0xE0, 0x54, 0xFE, 0xF0, ++0x90, 0x82, 0x71, 0xE0, 0x90, 0x81, 0x3F, 0x30, 0xE7, 0x13, 0xE0, 0x44, 0x02, 0xD1, 0xCC, 0x90, ++0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x38, 0xE0, 0x44, 0x04, 0xF0, 0x22, 0xE0, 0x54, 0xFD, ++0xF0, 0x22, 0x90, 0x04, 0x1D, 0xE0, 0x70, 0x13, 0x90, 0x80, 0x07, 0xE0, 0xFF, 0xE4, 0xFD, 0xB1, ++0xB7, 0x8E, 0x0D, 0x8F, 0x0E, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, 0x22, 0xF0, 0xE4, 0xF5, 0x1D, ++0x90, 0x81, 0x4D, 0xE0, 0xF5, 0x1E, 0xE4, 0xFB, 0xFD, 0x7F, 0x54, 0x7E, 0x01, 0x8E, 0x19, 0x8F, ++0x1A, 0xE5, 0x1E, 0x54, 0x07, 0xC4, 0x33, 0x54, 0xE0, 0x85, 0x19, 0x83, 0x85, 0x1A, 0x82, 0xF0, ++0xE5, 0x1D, 0x54, 0x07, 0xC4, 0x33, 0x54, 0xE0, 0xFF, 0xE5, 0x1E, 0x13, 0x13, 0x13, 0x54, 0x1F, ++0x4F, 0xA3, 0xF0, 0xEB, 0x54, 0x07, 0xC4, 0x33, 0x54, 0xE0, 0xFF, 0xE5, 0x1D, 0x13, 0x13, 0x13, ++0x54, 0x1F, 0x4F, 0x85, 0x1A, 0x82, 0x85, 0x19, 0x83, 0xA3, 0xA3, 0xF0, 0xBD, 0x01, 0x0C, 0x85, ++0x1A, 0x82, 0x8E, 0x83, 0xA3, 0xA3, 0xA3, 0x74, 0x03, 0xF0, 0x22, 0x85, 0x1A, 0x82, 0x85, 0x19, ++0x83, 0xA3, 0xA3, 0xA3, 0x74, 0x01, 0xF0, 0x22, 0x90, 0x80, 0xF7, 0xE0, 0xB4, 0x01, 0x13, 0x90, ++0x81, 0x3B, 0xE0, 0x60, 0x0D, 0x90, 0x81, 0x3F, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0x07, 0x70, 0x02, ++0xD1, 0x3A, 0x22, 0x90, 0x80, 0xF7, 0xE0, 0x64, 0x01, 0x70, 0x18, 0x90, 0x81, 0x3B, 0xE0, 0x60, ++0x12, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0xD1, 0xCC, 0x90, 0x01, 0x57, ++0x74, 0x05, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xC0, 0x07, 0xC0, 0x05, 0x90, ++0x83, 0x03, 0x12, 0x42, 0x26, 0x90, 0x82, 0xF1, 0x12, 0x20, 0xCE, 0xD0, 0x05, 0xD0, 0x07, 0x12, ++0x69, 0x1D, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x80, 0xF7, 0xE0, 0x64, 0x01, 0x70, 0x25, 0x90, ++0x81, 0x3B, 0xE0, 0x60, 0x1F, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0xF0, ++0x90, 0x81, 0x38, 0xE0, 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x3F, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0x07, ++0x70, 0x02, 0xD1, 0x3A, 0x22, 0xE4, 0xFF, 0x81, 0x52, 0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x90, ++0x81, 0x3E, 0x74, 0x02, 0xF0, 0x22, 0x90, 0x06, 0x04, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x05, 0x22, ++0xE4, 0xF0, 0x90, 0x81, 0x3E, 0x74, 0x0C, 0xF0, 0x22, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, ++0x82, 0xC0, 0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, ++0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0xE9, 0xF0, 0x74, 0x4F, 0xA3, 0xF0, ++0x12, 0x6E, 0x3E, 0xE5, 0x49, 0x30, 0xE1, 0x02, 0x11, 0x70, 0xE5, 0x49, 0x30, 0xE2, 0x03, 0x12, ++0x4E, 0x21, 0xE5, 0x4A, 0x30, 0xE0, 0x03, 0x12, 0x6E, 0x7D, 0xE5, 0x4C, 0x30, 0xE1, 0x05, 0x7F, ++0x04, 0x12, 0x4B, 0x6B, 0xE5, 0x4C, 0x30, 0xE4, 0x02, 0x11, 0x7A, 0xE5, 0x4C, 0x30, 0xE5, 0x02, ++0x11, 0xF4, 0xE5, 0x4C, 0x30, 0xE6, 0x03, 0x12, 0x6F, 0x1C, 0x74, 0xE9, 0x04, 0x90, 0x01, 0xC4, ++0xF0, 0x74, 0x4F, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, 0xD0, 0x04, 0xD0, 0x03, 0xD0, ++0x02, 0xD0, 0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0x32, ++0x90, 0x81, 0x3B, 0xE0, 0x60, 0x03, 0x12, 0x72, 0xB1, 0x22, 0x12, 0x72, 0x7B, 0x90, 0x81, 0x41, ++0xE0, 0x14, 0x90, 0x05, 0x73, 0xF0, 0x7D, 0x02, 0x7F, 0x02, 0x11, 0xC2, 0x90, 0x82, 0x65, 0xE0, ++0x30, 0xE0, 0x2E, 0x90, 0x80, 0xF7, 0xE0, 0xB4, 0x01, 0x27, 0x90, 0x83, 0x37, 0xE0, 0x04, 0xF0, ++0xE0, 0xB4, 0x0A, 0x0B, 0x90, 0x82, 0x67, 0xE0, 0x04, 0xF0, 0xE4, 0x90, 0x83, 0x37, 0xF0, 0x90, ++0x82, 0x67, 0xE0, 0xFF, 0x90, 0x82, 0x66, 0xE0, 0xB5, 0x07, 0x06, 0xE4, 0xA3, 0xF0, 0x12, 0x4F, ++0xC5, 0x22, 0x74, 0x3D, 0x2F, 0xF8, 0xE6, 0x4D, 0xFE, 0xF6, 0x74, 0x30, 0x2F, 0xF5, 0x82, 0xE4, ++0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0x90, 0x05, 0x22, 0x74, 0xFF, 0xF0, 0x12, 0x6F, 0xBF, ++0x90, 0x01, 0x37, 0x74, 0x02, 0xF0, 0xFD, 0x7F, 0x03, 0x11, 0xC2, 0x12, 0x5D, 0x04, 0xE4, 0x90, ++0x81, 0x3E, 0xF0, 0x22, 0x90, 0x81, 0x38, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x54, 0x03, 0x30, 0xE0, ++0x27, 0xEF, 0x54, 0xBF, 0xF0, 0x90, 0x04, 0xE0, 0xE0, 0x90, 0x81, 0x39, 0x30, 0xE0, 0x06, 0xE0, ++0x44, 0x01, 0xF0, 0x80, 0x10, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, ++0x01, 0xB8, 0x74, 0x04, 0xF0, 0x12, 0x4E, 0x3A, 0xE4, 0xFF, 0x90, 0x82, 0x68, 0xE0, 0x30, 0xE0, ++0x48, 0x90, 0x82, 0x6C, 0xE0, 0xFD, 0x60, 0x41, 0x74, 0x01, 0x7E, 0x00, 0xA8, 0x07, 0x08, 0x80, ++0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, 0xFF, 0x90, 0x04, 0xE0, 0xE0, 0xFB, 0xEF, 0x5B, ++0x60, 0x06, 0xE4, 0x90, 0x82, 0x6C, 0xF0, 0x22, 0x90, 0x82, 0x6A, 0xE0, 0xD3, 0x9D, 0x50, 0x10, ++0x90, 0x01, 0xC7, 0x74, 0x10, 0xF0, 0x31, 0x7A, 0x90, 0x82, 0x68, 0xE0, 0x54, 0xFE, 0xF0, 0x22, ++0x12, 0x4F, 0xC5, 0x90, 0x82, 0x6C, 0xE0, 0x04, 0xF0, 0x22, 0x90, 0x80, 0x05, 0xE0, 0xB4, 0x02, ++0x16, 0x90, 0x81, 0x55, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x30, 0xE0, 0x0F, 0x90, ++0x01, 0x4D, 0xE0, 0x64, 0x80, 0xF0, 0x22, 0x90, 0x06, 0x90, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x82, ++0x6F, 0xE0, 0x75, 0xF0, 0x20, 0xA4, 0xFF, 0x90, 0x83, 0x19, 0xE5, 0xF0, 0xF0, 0xA3, 0xEF, 0xF0, ++0x90, 0x82, 0x70, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0xAE, 0xF0, 0x90, 0x83, 0x1B, 0xF0, 0xEE, 0xA3, ++0xF0, 0x90, 0x82, 0x6E, 0xE0, 0xFE, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x30, 0xE0, 0x77, 0xEE, ++0x54, 0x0F, 0xFF, 0xEE, 0xC4, 0x13, 0x13, 0x54, 0x03, 0x7D, 0x00, 0x20, 0xE0, 0x02, 0x7D, 0x01, ++0x51, 0x47, 0x90, 0x82, 0x6E, 0xE0, 0xFE, 0x54, 0x0F, 0xFF, 0xEE, 0xC4, 0x13, 0x13, 0x54, 0x01, ++0xFD, 0x51, 0x47, 0x90, 0x82, 0x6E, 0xE0, 0xC4, 0x13, 0x54, 0x07, 0x30, 0xE0, 0x22, 0x90, 0x83, ++0x19, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x12, 0x32, 0xAA, 0x90, 0x82, 0x6E, 0xE0, 0xFE, 0x54, 0x0F, ++0xFF, 0xEE, 0xC4, 0x13, 0x13, 0x54, 0x03, 0x7D, 0x00, 0x20, 0xE0, 0x02, 0x7D, 0x01, 0x51, 0x47, ++0x90, 0x82, 0x6E, 0xE0, 0xC4, 0x54, 0x0F, 0x30, 0xE0, 0x1C, 0x90, 0x83, 0x1C, 0xE0, 0xF5, 0x1D, ++0x90, 0x83, 0x1B, 0xE0, 0xF5, 0x1E, 0xE4, 0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0x12, 0x4E, 0xDD, ++0x90, 0x01, 0x5B, 0x74, 0x05, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x83, ++0x2C, 0xED, 0xF0, 0x90, 0x83, 0x2B, 0xEF, 0xF0, 0xD3, 0x94, 0x07, 0x50, 0x70, 0xE0, 0xFF, 0x74, ++0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x47, 0xE0, ++0x5F, 0xFD, 0x7F, 0x47, 0x12, 0x32, 0x1E, 0x90, 0x83, 0x2B, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, ++0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x46, 0xE0, 0x4F, 0xFD, 0x7F, 0x46, ++0x12, 0x32, 0x1E, 0x90, 0x83, 0x2C, 0xE0, 0x60, 0x18, 0x90, 0x83, 0x2B, 0xE0, 0xFF, 0x74, 0x01, ++0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x45, 0xE0, 0x4F, 0x80, ++0x17, 0x90, 0x83, 0x2B, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, ++0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x45, 0xE0, 0x5F, 0xFD, 0x7F, 0x45, 0x80, 0x7E, 0x90, 0x83, 0x2B, ++0xE0, 0x24, 0xF8, 0xF0, 0xE0, 0x24, 0x04, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, ++0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x43, 0xE0, 0x5F, 0xFD, 0x7F, 0x43, 0x12, 0x32, 0x1E, ++0x90, 0x83, 0x2B, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, ++0xFF, 0x90, 0x00, 0x43, 0xE0, 0x4F, 0xFD, 0x7F, 0x43, 0x12, 0x32, 0x1E, 0x90, 0x83, 0x2C, 0xE0, ++0x60, 0x1D, 0x90, 0x83, 0x2B, 0xE0, 0x24, 0x04, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, ++0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x42, 0xE0, 0x4F, 0xFD, 0x7F, 0x42, 0x80, 0x1C, 0x90, ++0x83, 0x2B, 0xE0, 0x24, 0x04, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, ++0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x42, 0xE0, 0x5F, 0xFD, 0x7F, 0x42, 0x12, 0x32, 0x1E, 0xD0, 0xD0, ++0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x82, 0x82, 0x74, 0x08, 0xF0, ++0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x82, 0x89, 0xF0, 0xA3, 0xF0, 0x90, ++0x01, 0x1F, 0xE0, 0xFE, 0x90, 0x01, 0x1E, 0xE0, 0x7C, 0x00, 0x24, 0x00, 0xFF, 0xEC, 0x3E, 0x90, ++0x82, 0x7B, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x02, 0x82, 0xE0, 0x90, 0x82, 0x81, 0xF0, 0x90, 0x81, ++0x53, 0xE0, 0x20, 0xE0, 0x02, 0xA1, 0xBD, 0x90, 0x81, 0x58, 0xE0, 0x20, 0xE0, 0x07, 0x90, 0x01, ++0x3F, 0xE0, 0x30, 0xE2, 0x17, 0x90, 0x80, 0x05, 0xE0, 0xB4, 0x01, 0x0E, 0x90, 0xFD, 0x01, 0xE0, ++0x20, 0xE6, 0x07, 0x90, 0xFD, 0x00, 0xE0, 0x44, 0x10, 0xF0, 0x31, 0x7A, 0xE4, 0x90, 0x82, 0x80, ++0xF0, 0x90, 0x82, 0x81, 0xE0, 0xFF, 0x90, 0x82, 0x80, 0xE0, 0xC3, 0x9F, 0x40, 0x02, 0xA1, 0xBD, ++0x90, 0x82, 0x7B, 0xE0, 0xFC, 0xA3, 0xE0, 0xFD, 0xEC, 0xFF, 0x90, 0xFD, 0x11, 0xF0, 0xAE, 0x05, ++0xAB, 0x06, 0x90, 0x82, 0x84, 0xEF, 0xF0, 0x74, 0x02, 0x2B, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, ++0x83, 0xE0, 0x54, 0x0F, 0x33, 0x33, 0x33, 0x54, 0xF8, 0xFF, 0x74, 0x03, 0x2B, 0xF5, 0x82, 0xE4, ++0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x54, 0x03, 0xFE, 0xEF, 0x24, 0x18, 0x2E, 0x90, 0x82, 0x89, 0xF0, ++0xE0, 0xFF, 0x2B, 0xFA, 0x7E, 0x00, 0x90, 0x82, 0x7B, 0xE0, 0xFC, 0xA3, 0xE0, 0x2F, 0xFF, 0xEE, ++0x3C, 0xA3, 0xF0, 0xA3, 0xEF, 0xF0, 0x74, 0x00, 0x2A, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, ++0xE0, 0xFF, 0x54, 0xFC, 0x90, 0x82, 0x7F, 0xF0, 0x74, 0x04, 0x2A, 0xF5, 0x82, 0xE4, 0x34, 0xFB, ++0x12, 0x5E, 0x8E, 0x90, 0x82, 0x83, 0xEF, 0xF0, 0x74, 0x01, 0x2B, 0xF5, 0x82, 0xE4, 0x34, 0xFB, ++0xF5, 0x83, 0xE0, 0xFE, 0x74, 0x00, 0x2B, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x7C, ++0x00, 0x24, 0x00, 0xFF, 0xEC, 0x3E, 0x54, 0x3F, 0xFE, 0x90, 0x82, 0x85, 0xF0, 0xA3, 0xEF, 0xF0, ++0x90, 0x82, 0x89, 0xE0, 0x2F, 0xFF, 0xEC, 0x3E, 0xFE, 0x12, 0x73, 0x6E, 0x74, 0x0F, 0x2B, 0xF5, ++0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFD, 0x90, 0x82, 0x7B, 0xEE, 0x8F, 0xF0, 0x12, 0x41, ++0xF6, 0x90, 0x80, 0xF5, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x90, 0x82, 0x7B, 0xE0, 0xF8, 0xA3, 0xE0, ++0xD3, 0x9F, 0xE8, 0x9E, 0x40, 0x26, 0x90, 0x82, 0x7B, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x90, 0x80, ++0xF5, 0xE0, 0xF8, 0xA3, 0xE0, 0x24, 0x01, 0xF5, 0x82, 0xE4, 0x38, 0xF5, 0x83, 0xC3, 0xEF, 0x95, ++0x82, 0xFF, 0xEE, 0x95, 0x83, 0x90, 0x82, 0x7B, 0xF0, 0xA3, 0xEF, 0xF0, 0xED, 0x30, 0xE7, 0x06, ++0x90, 0x01, 0xC7, 0x74, 0x21, 0xF0, 0xED, 0x30, 0xE6, 0x06, 0x90, 0x01, 0xC7, 0x74, 0x22, 0xF0, ++0xED, 0x30, 0xE5, 0x06, 0x90, 0x01, 0xC7, 0x74, 0x23, 0xF0, 0x90, 0x82, 0x7F, 0xE0, 0x24, 0x40, ++0x60, 0x04, 0x24, 0x20, 0x70, 0x20, 0x90, 0x81, 0x54, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54, ++0x01, 0x30, 0xE0, 0x64, 0xAF, 0x02, 0x12, 0x75, 0xD9, 0xEF, 0x60, 0x5C, 0x90, 0x82, 0x7F, 0xE0, ++0xFF, 0x12, 0x75, 0xC2, 0x80, 0x52, 0x90, 0x82, 0x7D, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x90, 0x82, ++0x83, 0xE0, 0xFD, 0x90, 0x82, 0x82, 0xE0, 0xFB, 0x90, 0x82, 0x84, 0xE0, 0x90, 0x82, 0x8F, 0xF0, ++0xB1, 0xC2, 0x90, 0x81, 0x53, 0xE0, 0xC3, 0x13, 0x30, 0xE0, 0x10, 0x90, 0x82, 0x7D, 0xE0, 0xFE, ++0xA3, 0xE0, 0xFF, 0x90, 0x82, 0x83, 0xE0, 0xFD, 0x12, 0x76, 0x14, 0x90, 0x81, 0x53, 0xE0, 0xFF, ++0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x30, 0xE0, 0x0F, 0x90, 0x82, 0x7D, 0xE0, 0xFE, 0xA3, 0xE0, ++0xFF, 0x90, 0x82, 0x83, 0xE0, 0xFD, 0xD1, 0x9D, 0x90, 0x81, 0x58, 0xE0, 0x20, 0xE0, 0x07, 0x90, ++0x01, 0x3F, 0xE0, 0x30, 0xE2, 0x02, 0x31, 0x7A, 0x12, 0x75, 0x9C, 0xEF, 0x64, 0x01, 0x70, 0x3D, ++0xF1, 0xD8, 0x90, 0x82, 0x8A, 0xEF, 0xF0, 0x64, 0x01, 0x60, 0x25, 0x90, 0x81, 0x58, 0xE0, 0x44, ++0x01, 0xF0, 0x90, 0x82, 0x8A, 0xE0, 0xFF, 0xB4, 0x02, 0x08, 0x90, 0x01, 0xC7, 0x74, 0x42, 0xF0, ++0x80, 0x0A, 0xEF, 0xB4, 0x04, 0x06, 0x90, 0x01, 0xC7, 0x74, 0x43, 0xF0, 0x31, 0x7A, 0x80, 0x0D, ++0x90, 0x82, 0x7B, 0xF1, 0xC5, 0x90, 0x82, 0x80, 0xE0, 0x04, 0xF0, 0x61, 0xC1, 0xD0, 0xD0, 0x92, ++0xAF, 0x22, 0x90, 0x82, 0x8D, 0xED, 0xF0, 0xA3, 0xEB, 0xF0, 0x90, 0x82, 0x8B, 0xEE, 0xF0, 0xA3, ++0xEF, 0xF0, 0xE4, 0xFD, 0xD1, 0x5F, 0xEF, 0x54, 0x0C, 0x64, 0x08, 0x70, 0x6F, 0x90, 0x82, 0x8B, ++0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xA3, 0xE0, 0x24, 0x06, 0xFD, 0xD1, 0x5F, 0xEF, 0x64, 0x88, 0x70, ++0x5B, 0x90, 0x82, 0x8B, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xA3, 0xE0, 0x24, 0x07, 0xFD, 0xD1, 0x5F, ++0xEF, 0x64, 0x8E, 0x70, 0x47, 0x90, 0x82, 0x8B, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x90, 0x82, 0x8E, ++0xE0, 0xFD, 0x90, 0x82, 0x8D, 0xE0, 0x2D, 0x04, 0xFD, 0xD1, 0x5F, 0xEF, 0x64, 0x03, 0x70, 0x2C, ++0x90, 0x82, 0x8B, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x90, 0x82, 0x8E, 0xE0, 0xFD, 0x90, 0x82, 0x8D, ++0xE0, 0x2D, 0x24, 0x06, 0xFD, 0xD1, 0x5F, 0xEF, 0x90, 0x01, 0xC7, 0x30, 0xE3, 0x04, 0x74, 0x01, ++0x80, 0x02, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x58, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0xFD, 0x90, 0x82, ++0x8B, 0xE0, 0x34, 0x00, 0xFC, 0x7E, 0x00, 0xED, 0x2F, 0xFF, 0xEE, 0x3C, 0xFE, 0xE4, 0xFD, 0xAB, ++0x07, 0xAA, 0x06, 0xED, 0x2B, 0xFB, 0xE4, 0x3A, 0xFA, 0xC3, 0x90, 0x80, 0xF6, 0xE0, 0x9B, 0x90, ++0x80, 0xF5, 0xE0, 0x9A, 0x50, 0x13, 0xA3, 0xE0, 0x24, 0x01, 0xFF, 0x90, 0x80, 0xF5, 0xE0, 0x34, ++0x00, 0xFE, 0xC3, 0xEB, 0x9F, 0xFB, 0xEA, 0x9E, 0xFA, 0xEA, 0x90, 0xFD, 0x11, 0xF0, 0xAF, 0x03, ++0x74, 0x00, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFF, 0x22, 0x90, 0x82, 0x8B, ++0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0x78, 0x8E, 0x7C, 0x82, 0x7D, 0x01, 0x7B, 0xFF, ++0x7A, 0x40, 0x79, 0xCE, 0x7E, 0x00, 0x7F, 0x06, 0x12, 0x41, 0xD0, 0x78, 0x95, 0x7C, 0x82, 0x7D, ++0x01, 0x7B, 0xFF, 0x7A, 0x40, 0x79, 0xD4, 0x7E, 0x00, 0x7F, 0x04, 0x12, 0x41, 0xD0, 0xE4, 0x90, ++0x82, 0x94, 0xF0, 0x90, 0x82, 0x94, 0xE0, 0xFF, 0xC3, 0x94, 0x06, 0x50, 0x1F, 0x90, 0x82, 0x8C, ++0xE0, 0x24, 0x04, 0xD1, 0x4D, 0x90, 0x82, 0x94, 0xE0, 0x24, 0x8E, 0xF5, 0x82, 0xE4, 0x34, 0x82, ++0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x82, 0x94, 0xE0, 0x04, 0xF0, 0x80, 0xD7, 0xE4, 0x90, 0x82, 0x94, ++0xF0, 0x90, 0x82, 0x94, 0xE0, 0xFF, 0xC3, 0x94, 0x04, 0x50, 0x2E, 0x90, 0x82, 0x8D, 0xE0, 0xFD, ++0x90, 0x82, 0x8C, 0xE0, 0x2D, 0xFD, 0x90, 0x82, 0x8B, 0xE0, 0x34, 0x00, 0xCD, 0x24, 0x18, 0xCD, ++0xD1, 0x52, 0x90, 0x82, 0x94, 0xE0, 0x24, 0x95, 0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, 0xEF, ++0xF0, 0x90, 0x82, 0x94, 0xE0, 0x04, 0xF0, 0x80, 0xC8, 0x78, 0x8E, 0x7C, 0x82, 0x7D, 0x01, 0x7B, ++0x01, 0x7A, 0x81, 0x79, 0x59, 0x7E, 0x00, 0x7F, 0x06, 0x12, 0x44, 0x08, 0xEF, 0x70, 0x75, 0x90, ++0x82, 0x8B, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xE4, 0xFD, 0xD1, 0x5F, 0xEF, 0x54, 0x0C, 0x64, 0x08, ++0x70, 0x62, 0x90, 0x82, 0x8D, 0xE0, 0xFF, 0x90, 0x82, 0x8C, 0xE0, 0x2F, 0xFF, 0x90, 0x82, 0x8B, ++0xE0, 0x34, 0x00, 0xCF, 0x24, 0x06, 0xCF, 0x34, 0x00, 0xFE, 0xE4, 0xFD, 0xD1, 0x5F, 0xEF, 0x64, ++0x08, 0x70, 0x41, 0x90, 0x82, 0x8D, 0xE0, 0xFF, 0x90, 0x82, 0x8C, 0xE0, 0x2F, 0xFF, 0x90, 0x82, ++0x8B, 0xE0, 0x34, 0x00, 0xCF, 0x24, 0x07, 0xCF, 0x34, 0x00, 0xFE, 0xE4, 0xFD, 0xD1, 0x5F, 0xEF, ++0x70, 0x22, 0x78, 0x95, 0x7C, 0x82, 0x7D, 0x01, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x6C, 0xFE, 0x7F, ++0x04, 0x12, 0x44, 0x08, 0xEF, 0x70, 0x0D, 0x90, 0x01, 0xC7, 0x74, 0x22, 0xF0, 0x90, 0x81, 0x58, ++0xE0, 0x44, 0x01, 0xF0, 0x22, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x90, 0x02, 0x84, 0xEF, 0xF0, 0xEE, ++0xA3, 0xF0, 0xA3, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90, 0x02, 0x86, 0xE0, 0x20, 0xE2, 0x03, 0x7F, ++0x04, 0x22, 0x90, 0x02, 0x86, 0xE0, 0x7F, 0x01, 0x20, 0xE1, 0x02, 0x7F, 0x02, 0x22, 0x90, 0x00, ++0xF7, 0xE0, 0x20, 0xE7, 0x09, 0xE0, 0x7F, 0x01, 0x20, 0xE6, 0x0C, 0x7F, 0x02, 0x22, 0x90, 0x00, ++0xF7, 0xE0, 0x30, 0xE6, 0x02, 0x7F, 0x03, 0x22, 0x12, 0x57, 0xEE, 0x90, 0x80, 0x05, 0xEF, 0xF0, ++0x11, 0x1B, 0x90, 0x01, 0x64, 0x74, 0x01, 0xF0, 0x02, 0x2D, 0xA7, 0x11, 0x86, 0x11, 0xB6, 0x11, ++0x48, 0x11, 0x67, 0xE4, 0xF5, 0x35, 0xF5, 0x36, 0xF5, 0x37, 0xF5, 0x38, 0xAD, 0x35, 0x7F, 0x50, ++0x12, 0x32, 0x1E, 0xAD, 0x36, 0x7F, 0x51, 0x12, 0x32, 0x1E, 0xAD, 0x37, 0x7F, 0x52, 0x12, 0x32, ++0x1E, 0xAD, 0x38, 0x7F, 0x53, 0x02, 0x32, 0x1E, 0x75, 0x3D, 0x10, 0xE4, 0xF5, 0x3E, 0x75, 0x3F, ++0x07, 0x75, 0x40, 0x02, 0x90, 0x01, 0x30, 0xE5, 0x3D, 0xF0, 0xA3, 0xE5, 0x3E, 0xF0, 0xA3, 0xE5, ++0x3F, 0xF0, 0xA3, 0xE5, 0x40, 0xF0, 0x22, 0x75, 0x45, 0x06, 0x75, 0x46, 0x01, 0x75, 0x47, 0x03, ++0x75, 0x48, 0x62, 0x90, 0x01, 0x38, 0xE5, 0x45, 0xF0, 0xA3, 0xE5, 0x46, 0xF0, 0xA3, 0xE5, 0x47, ++0xF0, 0xA3, 0xE5, 0x48, 0xF0, 0x22, 0x90, 0x01, 0x30, 0xE4, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, ++0xF0, 0x90, 0x01, 0x38, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, 0x7F, 0x50, 0x12, 0x32, ++0x1E, 0xE4, 0xFD, 0x7F, 0x51, 0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x52, 0x12, 0x32, 0x1E, 0xE4, ++0xFD, 0x7F, 0x53, 0x02, 0x32, 0x1E, 0x90, 0x01, 0x34, 0x74, 0xFF, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, ++0xA3, 0xF0, 0x90, 0x01, 0x3C, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, 0x7F, 0x54, 0x12, ++0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x55, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x56, 0x12, 0x32, 0x1E, ++0x7D, 0xFF, 0x7F, 0x57, 0x02, 0x32, 0x1E, 0x90, 0x01, 0xCF, 0xE0, 0x90, 0x83, 0x34, 0xF0, 0xE0, ++0xFF, 0x30, 0xE0, 0x07, 0x90, 0x01, 0xCF, 0xE0, 0x54, 0xFE, 0xF0, 0xEF, 0x30, 0xE5, 0x22, 0x90, ++0x01, 0xCF, 0xE0, 0x54, 0xDF, 0xF0, 0x90, 0x01, 0x34, 0x74, 0x20, 0xF0, 0xE4, 0xF5, 0xA8, 0xF5, ++0xE8, 0x11, 0x86, 0x90, 0x00, 0x03, 0xE0, 0x54, 0xFB, 0xFD, 0x7F, 0x03, 0x12, 0x32, 0x1E, 0x80, ++0xFE, 0x22, 0x90, 0x00, 0x80, 0xE0, 0x44, 0x80, 0xFD, 0x7F, 0x80, 0x12, 0x32, 0x1E, 0x90, 0xFD, ++0x00, 0xE0, 0x54, 0xBF, 0xF0, 0xF1, 0xC5, 0x12, 0x32, 0x77, 0xF1, 0x8C, 0xF1, 0xB9, 0x7F, 0x01, ++0x12, 0x45, 0x41, 0x90, 0x82, 0x64, 0x74, 0x02, 0xF0, 0xFF, 0x12, 0x45, 0x41, 0x90, 0x82, 0x64, ++0xE0, 0x04, 0xF0, 0x11, 0x08, 0x31, 0x71, 0x90, 0x00, 0x80, 0xE0, 0x44, 0x40, 0xFD, 0x7F, 0x80, ++0x12, 0x32, 0x1E, 0x75, 0x20, 0xFF, 0xF1, 0xA1, 0xF1, 0xA8, 0xF1, 0xAF, 0xE4, 0xFF, 0x02, 0x45, ++0xCA, 0xF1, 0x8F, 0xF1, 0xD2, 0x12, 0x70, 0x81, 0x31, 0x94, 0x12, 0x73, 0x5C, 0x12, 0x65, 0x97, ++0x90, 0x82, 0x6E, 0xE0, 0x54, 0x7F, 0xF0, 0x54, 0xBF, 0xF0, 0x54, 0xDF, 0xF0, 0x54, 0xF0, 0xF0, ++0xE4, 0xA3, 0xF0, 0x22, 0x90, 0x81, 0x53, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x81, 0x58, 0xE0, 0x54, ++0xFE, 0xF0, 0xE4, 0x90, 0x81, 0x65, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, ++0xF0, 0xA3, 0xF0, 0x90, 0x06, 0x90, 0xE0, 0x44, 0x20, 0xF0, 0x90, 0x81, 0x54, 0xE0, 0x54, 0xFE, ++0xF0, 0x54, 0xFD, 0xF0, 0x54, 0xFB, 0xF0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x54, 0xDF, 0xF0, ++0x54, 0xBF, 0xF0, 0x54, 0x7F, 0xF0, 0xA3, 0xE0, 0x54, 0x80, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xE0, ++0x54, 0xFE, 0xF0, 0x90, 0x81, 0x55, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x81, 0x57, 0xE0, 0x54, 0xFD, ++0xF0, 0x22, 0xEF, 0x60, 0x57, 0x90, 0x04, 0xEC, 0xE0, 0x54, 0xDD, 0xF0, 0x90, 0x82, 0x57, 0xE0, ++0xFF, 0x60, 0x02, 0x51, 0x6D, 0x90, 0x01, 0xC7, 0xE4, 0xF0, 0x90, 0x01, 0x17, 0xE0, 0xFE, 0x90, ++0x01, 0x16, 0xE0, 0x7C, 0x00, 0x24, 0x00, 0xFF, 0xEC, 0x3E, 0x90, 0x80, 0xF5, 0xF0, 0xA3, 0xEF, ++0xF0, 0x90, 0x06, 0x09, 0xE0, 0x54, 0xFE, 0xF0, 0x91, 0xFE, 0x90, 0x02, 0x86, 0xE0, 0x44, 0x04, ++0xF0, 0x91, 0xC3, 0xF1, 0x8D, 0x12, 0x4B, 0xA7, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x12, 0x78, 0xB3, ++0x90, 0x01, 0x34, 0x74, 0x08, 0xF0, 0xFD, 0xE4, 0xFF, 0x02, 0x50, 0xC2, 0x90, 0x04, 0xEC, 0xE0, ++0x44, 0x22, 0xF0, 0x7D, 0x08, 0xE4, 0xFF, 0x51, 0x95, 0x90, 0x06, 0x90, 0xE0, 0x54, 0xF0, 0xF0, ++0x90, 0x02, 0x86, 0xE0, 0x54, 0xFB, 0xF0, 0x91, 0x70, 0xF1, 0x8E, 0x21, 0x94, 0xD1, 0x61, 0x7E, ++0x00, 0x74, 0x00, 0x2F, 0xF9, 0xE4, 0x34, 0xFC, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, ++0x16, 0x08, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x71, 0x02, 0x2B, 0xED, 0x7D, 0x02, 0x7F, 0x02, 0x51, ++0x95, 0x7D, 0x01, 0x7F, 0x02, 0x74, 0x3D, 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, 0xFE, 0xF6, ++0x74, 0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0x90, 0x82, 0x6D, ++0xE0, 0x04, 0xF0, 0x90, 0x81, 0x3E, 0xE0, 0x64, 0x02, 0x60, 0x28, 0x71, 0xB7, 0x90, 0x81, 0x39, ++0xE0, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, 0x14, 0x90, 0x81, 0x41, 0xE0, 0xFF, 0xA3, 0xE0, ++0x6F, 0x70, 0x0A, 0x91, 0x4C, 0x51, 0x8B, 0x90, 0x81, 0x42, 0xE0, 0x14, 0xF0, 0x90, 0x01, 0xE6, ++0xE0, 0x04, 0xF0, 0x22, 0xEF, 0x70, 0x34, 0x7D, 0x78, 0x7F, 0x02, 0x51, 0x95, 0x7D, 0x02, 0x7F, ++0x03, 0x51, 0x95, 0x7D, 0xC8, 0x7F, 0x02, 0x12, 0x70, 0x07, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, ++0x01, 0x3C, 0x74, 0x02, 0xF0, 0x7D, 0x01, 0x7F, 0x0C, 0x12, 0x49, 0x14, 0x90, 0x81, 0x38, 0xE0, ++0x54, 0xF7, 0xF0, 0x90, 0x06, 0x0A, 0xE0, 0x54, 0xF8, 0xF0, 0x22, 0x90, 0x01, 0x36, 0x74, 0x78, ++0xF0, 0xA3, 0x74, 0x02, 0xF0, 0x7D, 0x78, 0xFF, 0x12, 0x50, 0xC2, 0x7D, 0x02, 0x7F, 0x03, 0x12, ++0x50, 0xC2, 0x90, 0x06, 0x0A, 0xE0, 0x44, 0x07, 0xF0, 0x90, 0x81, 0x46, 0xA3, 0xE0, 0x90, 0x05, ++0x58, 0xF0, 0x90, 0x80, 0xF7, 0xE0, 0xB4, 0x01, 0x15, 0x90, 0x81, 0x39, 0xE0, 0x54, 0xFB, 0xF0, ++0x90, 0x81, 0x3E, 0xE0, 0x20, 0xE2, 0x0E, 0x7D, 0x01, 0x7F, 0x04, 0x02, 0x49, 0x14, 0x90, 0x81, ++0x39, 0xE0, 0x44, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x3B, 0xE0, 0x60, 0x45, 0x90, 0x81, 0x39, 0xE0, ++0xFF, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, 0x12, 0x90, 0x01, 0x3B, 0xE0, 0x30, 0xE4, 0x0B, ++0x51, 0x8B, 0x90, 0x81, 0x41, 0xE0, 0x14, 0x90, 0x05, 0x73, 0xF0, 0x90, 0x83, 0x25, 0xE4, 0x75, ++0xF0, 0x01, 0x12, 0x41, 0xF6, 0xC3, 0x90, 0x83, 0x26, 0xE0, 0x94, 0x80, 0x90, 0x83, 0x25, 0xE0, ++0x64, 0x80, 0x94, 0x80, 0x40, 0x0B, 0x90, 0x01, 0x98, 0xE0, 0x54, 0xFE, 0xF0, 0xE0, 0x44, 0x01, ++0xF0, 0x12, 0x78, 0xEB, 0x02, 0x50, 0x8C, 0x90, 0x80, 0xF7, 0xE0, 0x64, 0x01, 0x60, 0x02, 0x81, ++0x4B, 0x90, 0x81, 0x3B, 0xE0, 0x70, 0x02, 0x81, 0x4B, 0x90, 0x81, 0x3A, 0xE0, 0xC4, 0x54, 0x0F, ++0x64, 0x01, 0x70, 0x22, 0x90, 0x06, 0xAB, 0xE0, 0x90, 0x81, 0x42, 0xF0, 0x90, 0x06, 0xAA, 0xE0, ++0x90, 0x81, 0x41, 0xF0, 0xA3, 0xE0, 0xFF, 0x70, 0x08, 0x90, 0x81, 0x41, 0xE0, 0xFE, 0xFF, 0x80, ++0x00, 0x90, 0x81, 0x42, 0xEF, 0xF0, 0x90, 0x81, 0x39, 0xE0, 0x44, 0x04, 0xF0, 0xE4, 0x90, 0x81, ++0x44, 0xF0, 0x90, 0x81, 0x46, 0xA3, 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90, 0x01, 0x57, 0xE4, 0xF0, ++0x90, 0x01, 0x3C, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x3F, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0xEF, 0xF0, ++0x90, 0x81, 0x3A, 0xE0, 0xFF, 0xC4, 0x54, 0x0F, 0x24, 0xFD, 0x50, 0x02, 0x80, 0x03, 0x12, 0x4E, ++0x43, 0x90, 0x81, 0x39, 0xE0, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, 0x0E, 0x90, 0x81, 0x41, ++0xE0, 0xFF, 0xA3, 0xE0, 0xB5, 0x07, 0x04, 0x91, 0x4C, 0x51, 0x91, 0x22, 0xEF, 0x14, 0x90, 0x05, ++0x73, 0xF0, 0x90, 0x01, 0x3F, 0x74, 0x10, 0xF0, 0xFD, 0x7F, 0x03, 0x74, 0x45, 0x2F, 0xF8, 0xE6, ++0x4D, 0xFE, 0xF6, 0x74, 0x38, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, ++0x31, 0xBA, 0x90, 0x01, 0x3F, 0x74, 0x04, 0xF0, 0x90, 0x80, 0x05, 0xE0, 0xFF, 0xB4, 0x01, 0x07, ++0x90, 0xFD, 0x00, 0xE0, 0x54, 0xEF, 0xF0, 0xEF, 0xB4, 0x01, 0x07, 0x90, 0xFE, 0x10, 0xE0, 0x54, ++0xFB, 0xF0, 0x22, 0x90, 0x82, 0x7E, 0x12, 0x42, 0x53, 0x12, 0x71, 0x53, 0x90, 0x81, 0x3B, 0xE0, ++0xFF, 0x51, 0xE4, 0x90, 0x81, 0x3B, 0xE0, 0x60, 0x19, 0x90, 0x82, 0x7E, 0x12, 0x42, 0x4A, 0x90, ++0x00, 0x01, 0x12, 0x1F, 0xBD, 0x54, 0x0F, 0xFF, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xFD, 0x12, ++0x71, 0xFC, 0x22, 0x12, 0x57, 0xD8, 0xAD, 0x07, 0xEF, 0x64, 0x01, 0x60, 0x20, 0x90, 0x81, 0x58, ++0xE0, 0x44, 0x01, 0xF0, 0xED, 0xB4, 0x02, 0x08, 0x90, 0x01, 0xC7, 0x74, 0x40, 0xF0, 0x80, 0x0A, ++0xED, 0xB4, 0x04, 0x06, 0x90, 0x01, 0xC7, 0x74, 0x41, 0xF0, 0x02, 0x51, 0x7A, 0x12, 0x73, 0x97, ++0x90, 0x02, 0x87, 0xE0, 0x70, 0xF7, 0x90, 0x06, 0x90, 0xE0, 0x44, 0x02, 0xF0, 0x22, 0x90, 0x05, ++0x22, 0x74, 0xFF, 0xF0, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x6F, 0xBF, 0x90, 0x85, ++0xBB, 0x12, 0x20, 0xDA, 0xCC, 0xF0, 0x00, 0xC0, 0x7F, 0x8C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, ++0x85, 0xBB, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x14, 0x7F, 0x70, 0x7E, 0x0E, 0x12, 0x2E, 0xA2, ++0x90, 0x83, 0x03, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xFD, 0xFF, 0x12, 0x4F, 0x74, ++0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x44, 0x80, 0xFC, 0x90, 0x83, 0x15, 0x12, 0x20, ++0xCE, 0x90, 0x83, 0x15, 0x12, 0x42, 0x26, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x7C, 0x7E, ++0x08, 0x12, 0x2E, 0xA2, 0x90, 0x01, 0x00, 0x74, 0x3F, 0xF0, 0xA3, 0xE0, 0x54, 0xFD, 0xF0, 0x90, ++0x05, 0x53, 0xE0, 0x44, 0x20, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, ++0xC0, 0xD0, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, 0x81, 0x53, 0xE0, 0x54, 0xFE, 0x4E, ++0xFE, 0xF0, 0xEF, 0x54, 0x02, 0xFF, 0xEE, 0x54, 0xFD, 0x4F, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, ++0x54, 0x04, 0xFD, 0xEF, 0x54, 0xFB, 0x4D, 0xFF, 0x90, 0x81, 0x53, 0xF0, 0xEE, 0x54, 0x08, 0xFE, ++0xEF, 0x54, 0xF7, 0x4E, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x10, 0xFD, 0xEF, 0x54, 0xEF, ++0x4D, 0xFF, 0x90, 0x81, 0x53, 0xF0, 0xEE, 0x54, 0x20, 0xFE, 0xEF, 0x54, 0xDF, 0x4E, 0xFF, 0xF0, ++0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x40, 0xFD, 0xEF, 0x54, 0xBF, 0x4D, 0xFF, 0x90, 0x81, 0x53, 0xF0, ++0xEE, 0x54, 0x80, 0xFE, 0xEF, 0x54, 0x7F, 0x4E, 0xF0, 0x90, 0x01, 0x17, 0xE0, 0xFE, 0x90, 0x01, ++0x16, 0xE0, 0x7C, 0x00, 0x24, 0x00, 0xFF, 0xEC, 0x3E, 0x90, 0x80, 0xF5, 0xF0, 0xA3, 0xEF, 0xF0, ++0x90, 0x81, 0x53, 0xE0, 0xC3, 0x13, 0x54, 0x01, 0xFF, 0xD1, 0x2E, 0x90, 0x81, 0x53, 0xE0, 0x13, ++0x13, 0x54, 0x01, 0xFF, 0xF1, 0x95, 0x90, 0x81, 0x53, 0xE0, 0xC4, 0x54, 0x01, 0xFF, 0xF1, 0x9B, ++0x90, 0x81, 0x53, 0xE0, 0x54, 0x01, 0xFF, 0x31, 0xF2, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xEF, 0x60, ++0x07, 0x90, 0x82, 0x58, 0xE0, 0xFF, 0xD1, 0x39, 0x22, 0xD1, 0x61, 0x7E, 0x00, 0x90, 0x83, 0x2F, ++0xD1, 0x75, 0x90, 0x83, 0x2F, 0xA3, 0xE0, 0x2F, 0x24, 0x36, 0xF9, 0xE4, 0x34, 0xFC, 0x75, 0x13, ++0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x04, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x6C, 0x02, 0x2B, ++0xED, 0xE4, 0xFE, 0xEF, 0xC3, 0x13, 0xFD, 0xEF, 0x30, 0xE0, 0x02, 0x7E, 0x80, 0x90, 0xFD, 0x10, ++0xED, 0xF0, 0xAF, 0x06, 0x22, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xFE, 0x24, 0x20, 0xF5, 0x82, 0xE4, ++0x34, 0xFC, 0xF5, 0x83, 0xE0, 0xFF, 0x74, 0x24, 0x2E, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, ++0xE0, 0xFD, 0xE4, 0xFE, 0xEF, 0x30, 0xE7, 0x04, 0x7C, 0x02, 0x80, 0x02, 0xE4, 0xFC, 0xAF, 0x05, ++0xF1, 0x4D, 0xAE, 0x07, 0xEC, 0x24, 0x18, 0x2E, 0xFF, 0x22, 0x90, 0x83, 0x0A, 0xED, 0xF0, 0x90, ++0x83, 0x07, 0x12, 0x42, 0x53, 0xE4, 0x90, 0x83, 0x0B, 0xF0, 0xA3, 0xF0, 0x12, 0x1F, 0xA4, 0xFF, ++0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFD, 0xD1, 0x92, 0x90, 0x83, 0x0B, 0xEF, 0xF0, 0x90, 0x83, ++0x07, 0x12, 0x42, 0x4A, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFF, 0xF1, 0x4D, 0x90, 0x83, 0x0C, ++0xEF, 0xF0, 0x90, 0x81, 0x70, 0xE0, 0x24, 0xFE, 0x60, 0x1E, 0x24, 0xFE, 0x60, 0x1A, 0x14, 0x60, ++0x07, 0x14, 0x60, 0x04, 0x24, 0x05, 0x70, 0x54, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x71, 0x90, 0x83, ++0x0A, 0xE0, 0xFD, 0x12, 0x7A, 0x4B, 0x80, 0x16, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x71, 0x90, 0x83, ++0x0A, 0xE0, 0xFD, 0x90, 0x81, 0x70, 0xE0, 0x90, 0x82, 0xE5, 0xF0, 0x12, 0x79, 0x29, 0x90, 0x83, ++0x0C, 0xE0, 0xFF, 0x90, 0x83, 0x07, 0x12, 0x42, 0x4A, 0x90, 0x83, 0x0B, 0xE0, 0x7C, 0x00, 0x29, ++0xF9, 0xEC, 0x3A, 0xFA, 0xC3, 0xE9, 0x9F, 0xF9, 0xEA, 0x94, 0x00, 0xFA, 0x75, 0x13, 0x01, 0x75, ++0x14, 0x81, 0x75, 0x15, 0x71, 0xA3, 0xE0, 0xF5, 0x16, 0x12, 0x2B, 0xED, 0x22, 0xD3, 0x10, 0xAF, ++0x01, 0xC3, 0xC0, 0xD0, 0xEF, 0x20, 0xE0, 0x05, 0x90, 0x82, 0x55, 0x80, 0x03, 0x90, 0x82, 0x56, ++0xE0, 0x90, 0x81, 0x70, 0xF0, 0x90, 0x81, 0x70, 0xE0, 0x14, 0x60, 0x13, 0x14, 0x60, 0x14, 0x24, ++0xFE, 0x60, 0x10, 0x14, 0x60, 0x09, 0x14, 0x60, 0x06, 0x24, 0x06, 0xE4, 0xFE, 0x80, 0x06, 0x7E, ++0x04, 0x80, 0x02, 0x7E, 0x08, 0xAF, 0x06, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x22, 0x22, 0x22, 0xE4, ++0x90, 0x80, 0xF7, 0xF0, 0x22, 0x90, 0x82, 0x7E, 0xEF, 0xF0, 0x22, 0x90, 0x82, 0x7E, 0xEF, 0xF0, ++0x22, 0x75, 0xE8, 0x03, 0x75, 0xA8, 0x84, 0x22, 0x90, 0x01, 0xC7, 0x74, 0x05, 0xF0, 0x22, 0x90, ++0x01, 0xE4, 0x74, 0x0D, 0xF0, 0xA3, 0xE4, 0xF0, 0x22, 0xE4, 0x90, 0x80, 0x01, 0xF0, 0xA3, 0xF0, ++0xA3, 0xF0, 0xA3, 0xF0, 0x22, 0x90, 0x01, 0x94, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x01, 0xC7, 0xE4, ++0xF0, 0x22, 0xE4, 0x90, 0x80, 0xF3, 0xF0, 0xA3, 0xF0, 0x90, 0x80, 0x5B, 0xF0, 0xA3, 0xF0, 0x22, ++0xE4, 0x90, 0x82, 0x76, 0xF0, 0x90, 0x82, 0x76, 0xE0, 0x64, 0x01, 0xF0, 0x24, 0xE0, 0x90, 0x01, ++0xC4, 0xF0, 0x74, 0x5F, 0xA3, 0xF0, 0x90, 0x81, 0x3B, 0xE0, 0x60, 0x0F, 0x90, 0x81, 0x3E, 0xE0, ++0xFF, 0x90, 0x81, 0x3D, 0xE0, 0x6F, 0x60, 0x03, 0x12, 0x4E, 0x3A, 0xC2, 0xAF, 0x51, 0xC6, 0xBF, ++0x01, 0x02, 0x31, 0xDF, 0xD2, 0xAF, 0x11, 0x1D, 0x12, 0x44, 0x79, 0x80, 0xC8, 0xD3, 0x10, 0xAF, ++0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x00, 0x8F, 0xE0, 0x20, 0xE6, 0x02, 0x21, 0xAF, 0x90, 0x00, 0x8C, ++0xE0, 0x90, 0x82, 0x77, 0xF0, 0x90, 0x00, 0x8D, 0xE0, 0x90, 0x82, 0x78, 0xF0, 0x90, 0x00, 0x8E, ++0xE0, 0x90, 0x82, 0x79, 0xF0, 0x90, 0x82, 0x78, 0xE0, 0x24, 0xF1, 0x70, 0x02, 0x21, 0x0E, 0x24, ++0x07, 0x60, 0x02, 0x21, 0xA1, 0x90, 0x81, 0x3B, 0xE0, 0xFB, 0xE4, 0xFD, 0xFF, 0x31, 0xB7, 0x90, ++0x81, 0x3A, 0xE0, 0x54, 0x0F, 0xFB, 0x0D, 0x31, 0xB7, 0x90, 0x81, 0x3D, 0x31, 0xB4, 0x90, 0x81, ++0x3E, 0xE0, 0xFB, 0x0D, 0x31, 0xB7, 0x90, 0x82, 0x77, 0xE0, 0x24, 0xF7, 0xF5, 0x82, 0xE4, 0x34, ++0x80, 0xF5, 0x83, 0xE0, 0xFB, 0xE4, 0xFD, 0x0F, 0x31, 0xB7, 0x90, 0x81, 0x38, 0xE0, 0x54, 0x01, ++0xFB, 0x0D, 0x31, 0xB7, 0x90, 0x81, 0x38, 0xE0, 0xC4, 0x13, 0x13, 0x54, 0x01, 0xFB, 0x0D, 0x7F, ++0x01, 0x31, 0xB7, 0x90, 0x81, 0x38, 0xE0, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0xFB, 0x0D, 0x7F, ++0x01, 0x31, 0xB7, 0x90, 0x80, 0x03, 0xE0, 0xFB, 0xE4, 0xFD, 0x0F, 0x31, 0xB7, 0x90, 0x80, 0x04, ++0xE0, 0xFB, 0x0D, 0x31, 0xB7, 0x90, 0x81, 0x42, 0xE0, 0xFB, 0x0D, 0x31, 0xB7, 0x90, 0x81, 0x41, ++0xE0, 0xFB, 0x0D, 0x31, 0xB7, 0x90, 0x81, 0x3A, 0xE0, 0xC4, 0x54, 0x0F, 0xFB, 0xE4, 0xFD, 0x7F, ++0x03, 0x31, 0xB7, 0x90, 0x81, 0x39, 0xE0, 0x13, 0x13, 0x54, 0x01, 0xFB, 0x0D, 0x7F, 0x03, 0x31, ++0xB7, 0x90, 0x81, 0x39, 0xE0, 0x13, 0x13, 0x13, 0x54, 0x01, 0xFB, 0x0D, 0x7F, 0x03, 0x31, 0xB7, ++0x90, 0x81, 0x38, 0xE0, 0x13, 0x13, 0x54, 0x01, 0xFB, 0x0D, 0x7F, 0x03, 0x21, 0x9F, 0x90, 0x81, ++0x53, 0xE0, 0x54, 0x01, 0xFB, 0xE4, 0xFD, 0xFF, 0x31, 0xB7, 0x90, 0x81, 0x54, 0xE0, 0xC4, 0x13, ++0x13, 0x13, 0x54, 0x01, 0xFB, 0x0D, 0xE4, 0xFF, 0x31, 0xB7, 0x90, 0x81, 0x54, 0xE0, 0xC4, 0x54, ++0x01, 0xFB, 0x0D, 0xE4, 0xFF, 0x31, 0xB7, 0x90, 0x81, 0x58, 0xE0, 0x54, 0x01, 0xFB, 0x0D, 0x31, ++0xB7, 0x90, 0x81, 0x65, 0xE0, 0xFB, 0xE4, 0xFD, 0x0F, 0x31, 0xB7, 0x90, 0x81, 0x66, 0xE0, 0xFB, ++0x0D, 0x31, 0xB7, 0x90, 0x81, 0x67, 0xE0, 0xFB, 0x0D, 0x31, 0xB7, 0x90, 0x81, 0x68, 0xE0, 0xFB, ++0x0D, 0x31, 0xB7, 0x90, 0x81, 0x69, 0xE0, 0xFB, 0xE4, 0xFD, 0x0F, 0x31, 0xB7, 0x90, 0x81, 0x6A, ++0xE0, 0xFB, 0x0D, 0x31, 0xB7, 0x90, 0x81, 0x6B, 0xE0, 0xFB, 0x0D, 0x31, 0xB7, 0x90, 0x82, 0x5A, ++0xE0, 0xFB, 0x0D, 0x31, 0xB7, 0x90, 0x80, 0x07, 0xE0, 0xFB, 0xE4, 0xFD, 0x0F, 0x31, 0xB7, 0x90, ++0x80, 0x08, 0xE0, 0xFB, 0x0D, 0x31, 0xB7, 0x90, 0x82, 0x58, 0x31, 0xB4, 0xE4, 0xFB, 0x0D, 0x31, ++0xB7, 0x90, 0x00, 0x8F, 0xE0, 0x30, 0xE0, 0x07, 0xE4, 0xFD, 0x7F, 0x8D, 0x12, 0x32, 0x1E, 0xD0, ++0xD0, 0x92, 0xAF, 0x22, 0xE0, 0xFB, 0x0D, 0xEF, 0x70, 0x04, 0x74, 0xF0, 0x80, 0x16, 0xEF, 0xB4, ++0x01, 0x04, 0x74, 0xF4, 0x80, 0x0E, 0xEF, 0xB4, 0x02, 0x04, 0x74, 0xF8, 0x80, 0x06, 0xEF, 0xB4, ++0x03, 0x0C, 0x74, 0xFC, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0x02, 0xF5, 0x83, 0xEB, 0xF0, 0x22, 0x90, ++0x81, 0x38, 0xE0, 0x30, 0xE0, 0x02, 0x31, 0xE9, 0x22, 0x90, 0x81, 0x3E, 0xE0, 0xFF, 0x60, 0x03, ++0xB4, 0x08, 0x0D, 0x51, 0xED, 0xBF, 0x01, 0x08, 0x51, 0x01, 0x90, 0x01, 0xE5, 0xE0, 0x04, 0xF0, ++0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x51, 0x79, 0x51, 0x11, 0xD0, 0xD0, 0x92, 0xAF, ++0x22, 0x51, 0xBE, 0x90, 0x00, 0x08, 0xE0, 0x54, 0xEF, 0xFD, 0x7F, 0x08, 0x12, 0x32, 0x1E, 0xE4, ++0xFF, 0x8F, 0x0F, 0xE4, 0x90, 0x82, 0x77, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x09, 0xE0, 0x7F, 0x00, ++0x30, 0xE7, 0x02, 0x7F, 0x01, 0xEF, 0x65, 0x0F, 0x60, 0x3E, 0xC3, 0x90, 0x82, 0x78, 0xE0, 0x94, ++0x88, 0x90, 0x82, 0x77, 0xE0, 0x94, 0x13, 0x40, 0x08, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x10, 0xF0, ++0x22, 0x90, 0x82, 0x77, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x41, 0xF6, 0x7F, 0x14, 0x7E, 0x00, 0x12, ++0x32, 0xAA, 0xD3, 0x90, 0x82, 0x78, 0xE0, 0x94, 0x32, 0x90, 0x82, 0x77, 0xE0, 0x94, 0x00, 0x40, ++0xB9, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE0, 0xB2, 0x22, 0x90, 0x81, 0x45, 0xE0, 0xFD, 0x7F, 0x93, ++0x12, 0x32, 0x1E, 0x90, 0x81, 0x3C, 0xE0, 0x60, 0x12, 0x90, 0x01, 0x2F, 0xE0, 0x30, 0xE7, 0x05, ++0x74, 0x10, 0xF0, 0x80, 0x06, 0x90, 0x01, 0x2F, 0x74, 0x90, 0xF0, 0x90, 0x00, 0x08, 0xE0, 0x44, ++0x10, 0xFD, 0x7F, 0x08, 0x12, 0x32, 0x1E, 0x7F, 0x01, 0x51, 0x21, 0x90, 0x00, 0x90, 0xE0, 0x44, ++0x01, 0xFD, 0x7F, 0x90, 0x12, 0x32, 0x1E, 0x7F, 0x14, 0x7E, 0x00, 0x02, 0x32, 0xAA, 0x90, 0x00, ++0x90, 0xE0, 0x20, 0xE0, 0xF9, 0x22, 0x7F, 0x02, 0x90, 0x82, 0x64, 0xE0, 0xFE, 0xEF, 0xC3, 0x9E, ++0x50, 0x18, 0xEF, 0x25, 0xE0, 0x24, 0x81, 0xF8, 0xE6, 0x30, 0xE4, 0x0B, 0x90, 0x01, 0xB8, 0x74, ++0x08, 0xF0, 0xA3, 0xF0, 0x7F, 0x00, 0x22, 0x0F, 0x80, 0xDE, 0x7F, 0x01, 0x22, 0x90, 0x02, 0x87, ++0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x01, 0xF0, 0x80, 0x3B, 0x90, 0x81, 0x53, 0xE0, 0x30, ++0xE0, 0x0E, 0x90, 0x02, 0x82, 0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x02, 0xF0, 0x80, 0x26, ++0x90, 0x81, 0x58, 0xE0, 0x30, 0xE0, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0x80, 0x17, 0x90, ++0x02, 0x86, 0xE0, 0x20, 0xE1, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x08, 0x90, 0x01, ++0xB8, 0xE4, 0xF0, 0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74, 0x08, 0xF0, 0x7F, 0x00, 0x22, 0xE4, ++0xFB, 0xFA, 0xFD, 0x7F, 0x01, 0x12, 0x46, 0x7A, 0x90, 0x82, 0x7A, 0xEF, 0xF0, 0x60, 0xF0, 0x90, ++0x80, 0x01, 0xE0, 0xFF, 0x60, 0xE9, 0xC2, 0xAF, 0x30, 0xE1, 0x05, 0x54, 0xFD, 0xF0, 0x71, 0x8C, ++0xD2, 0xAF, 0xC2, 0xAF, 0x90, 0x80, 0x01, 0xE0, 0xFF, 0x30, 0xE2, 0x05, 0x54, 0xFB, 0xF0, 0xD1, ++0x5B, 0xD2, 0xAF, 0xC2, 0xAF, 0x90, 0x80, 0x01, 0xE0, 0xFF, 0x30, 0xE4, 0x0B, 0x54, 0xEF, 0xF0, ++0xD1, 0x1E, 0xBF, 0x01, 0x03, 0x12, 0x53, 0x53, 0xD2, 0xAF, 0x80, 0xC3, 0xD3, 0x10, 0xAF, 0x01, ++0xC3, 0xC0, 0xD0, 0x90, 0x80, 0x5C, 0xE0, 0xFF, 0x90, 0x80, 0x5B, 0xE0, 0xB5, 0x07, 0x04, 0x7F, ++0x01, 0x80, 0x02, 0x7F, 0x00, 0xEF, 0x70, 0x43, 0x90, 0x80, 0x5B, 0xE0, 0xFE, 0x75, 0xF0, 0x08, ++0x90, 0x80, 0x0B, 0x12, 0x42, 0x3E, 0xE0, 0xFD, 0xEE, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x0C, 0xF9, ++0x74, 0x80, 0x35, 0xF0, 0xFA, 0x7B, 0x01, 0xAF, 0x05, 0x71, 0xF0, 0x90, 0x80, 0x5B, 0xE0, 0x04, ++0xF0, 0xE0, 0x7F, 0x00, 0xB4, 0x0A, 0x02, 0x7F, 0x01, 0xEF, 0x60, 0x05, 0xE4, 0x90, 0x80, 0x5B, ++0xF0, 0x12, 0x6B, 0x60, 0x90, 0x80, 0x01, 0xE0, 0x44, 0x02, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, ++0x90, 0x82, 0x7B, 0x12, 0x42, 0x53, 0xEF, 0x12, 0x42, 0x5C, 0x64, 0x2B, 0x00, 0x64, 0x33, 0x01, ++0x64, 0x3B, 0x02, 0x64, 0x43, 0x03, 0x64, 0x4B, 0x04, 0x64, 0x53, 0x13, 0x64, 0x5C, 0x20, 0x64, ++0x65, 0x21, 0x64, 0x6D, 0x23, 0x64, 0x75, 0x25, 0x64, 0x86, 0x80, 0x64, 0x7D, 0x81, 0x64, 0x8F, ++0x82, 0x64, 0x97, 0x83, 0x64, 0x9F, 0x84, 0x00, 0x00, 0x64, 0xA7, 0x90, 0x82, 0x7B, 0x12, 0x42, ++0x4A, 0xC1, 0xDF, 0x90, 0x82, 0x7B, 0x12, 0x42, 0x4A, 0x81, 0xDB, 0x90, 0x82, 0x7B, 0x12, 0x42, ++0x4A, 0xA1, 0xE6, 0x90, 0x82, 0x7B, 0x12, 0x42, 0x4A, 0xA1, 0xC6, 0x90, 0x82, 0x7B, 0x12, 0x42, ++0x4A, 0x80, 0x5C, 0x90, 0x82, 0x7B, 0x12, 0x42, 0x4A, 0x02, 0x6A, 0x66, 0x90, 0x82, 0x7B, 0x12, ++0x42, 0x4A, 0x02, 0x6A, 0xD4, 0x90, 0x82, 0x7B, 0x12, 0x42, 0x4A, 0xC1, 0x99, 0x90, 0x82, 0x7B, ++0x12, 0x42, 0x4A, 0xA1, 0x7F, 0x90, 0x82, 0x7B, 0x12, 0x42, 0x4A, 0xA1, 0x87, 0x90, 0x82, 0x7B, ++0x12, 0x42, 0x4A, 0x02, 0x5D, 0x7B, 0x90, 0x82, 0x7B, 0x12, 0x42, 0x4A, 0x02, 0x74, 0x90, 0x90, ++0x82, 0x7B, 0x12, 0x42, 0x4A, 0xA1, 0xAC, 0x90, 0x82, 0x7B, 0x12, 0x42, 0x4A, 0xE1, 0x27, 0x90, ++0x82, 0x7B, 0x12, 0x42, 0x4A, 0xE1, 0x7C, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0xB1, ++0x97, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, 0x82, 0x68, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, ++0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x14, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x82, 0x69, 0xF0, ++0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0x90, 0x82, 0x6A, 0xF0, 0x22, 0x90, 0x82, 0x7E, 0x12, 0x42, ++0x53, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0xFE, 0x12, 0x1F, 0xA4, 0xFD, 0xC3, 0x13, 0x30, ++0xE0, 0x12, 0x90, 0x82, 0x7E, 0x12, 0x42, 0x4A, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0x90, 0x82, ++0x82, 0xF0, 0x80, 0x05, 0x90, 0x82, 0x82, 0xEF, 0xF0, 0x90, 0x82, 0x81, 0xEE, 0xF0, 0x90, 0x82, ++0x82, 0xE0, 0xFE, 0x90, 0x82, 0x81, 0xE0, 0xFF, 0xD3, 0x9E, 0x50, 0x38, 0x90, 0x82, 0x7E, 0x12, ++0x42, 0x4A, 0x12, 0x1F, 0xA4, 0x54, 0x01, 0xFE, 0x74, 0xF7, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x80, ++0xF5, 0x83, 0xEE, 0xF0, 0x74, 0xF7, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x80, 0xF5, 0x83, 0xE0, 0x70, ++0x04, 0xB1, 0x7E, 0x80, 0x07, 0x90, 0x82, 0x81, 0xE0, 0xFF, 0xB1, 0x7D, 0x90, 0x82, 0x81, 0xE0, ++0x04, 0xF0, 0x80, 0xBA, 0x90, 0x80, 0xF7, 0xE0, 0x70, 0x22, 0x90, 0x81, 0x3E, 0xE0, 0x70, 0x04, ++0xFF, 0x12, 0x4A, 0xF6, 0x90, 0x81, 0x3E, 0xE0, 0x64, 0x0C, 0x60, 0x03, 0x12, 0x4F, 0xD6, 0x90, ++0x81, 0x38, 0xE0, 0x54, 0xF7, 0xF0, 0x54, 0xBF, 0xF0, 0x54, 0x7F, 0xF0, 0x22, 0x22, 0x22, 0x12, ++0x1F, 0xA4, 0x90, 0x81, 0x45, 0xF0, 0x22, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0x52, 0xF0, 0x90, 0x81, ++0x52, 0xE0, 0x90, 0x01, 0xE7, 0xF0, 0x22, 0x90, 0x82, 0x68, 0xE0, 0x54, 0xFE, 0xF0, 0xA3, 0x74, ++0x03, 0xF0, 0xA3, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x22, 0x90, 0x02, 0x09, 0xE0, ++0x90, 0x82, 0x7E, 0xF0, 0x12, 0x1F, 0xA4, 0x90, 0x82, 0x55, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, ++0xBD, 0x90, 0x82, 0x56, 0xF0, 0x22, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, 0x82, 0x65, ++0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x0A, 0x90, 0x00, 0x01, 0x12, 0x1F, ++0xBD, 0x90, 0x82, 0x66, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x1F, 0xA4, ++0xFF, 0x90, 0x81, 0x37, 0xF0, 0xBF, 0x01, 0x12, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x64, 0x01, ++0x60, 0x17, 0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x80, 0x0F, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, ++0x64, 0x01, 0x60, 0x05, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xE4, 0x90, ++0x83, 0x2D, 0xF0, 0xA3, 0xF0, 0x90, 0x02, 0x86, 0xE0, 0x20, 0xE1, 0x2C, 0xC3, 0x90, 0x83, 0x2E, ++0xE0, 0x94, 0xD0, 0x90, 0x83, 0x2D, 0xE0, 0x94, 0x07, 0x40, 0x0A, 0x90, 0x01, 0xC1, 0xE0, 0x44, ++0x04, 0xF0, 0x7F, 0x00, 0x22, 0x90, 0x83, 0x2D, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x41, 0xF6, 0x7F, ++0x0A, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x80, 0xCD, 0x7F, 0x01, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, ++0xC0, 0xD0, 0xE4, 0xFF, 0x90, 0x80, 0xF4, 0xE0, 0xFE, 0x90, 0x80, 0xF3, 0xE0, 0xB5, 0x06, 0x04, ++0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x64, 0x01, 0x60, 0x19, 0xEF, 0x60, 0x16, 0x90, 0x80, ++0xF3, 0xE0, 0x04, 0xF0, 0xE0, 0x7F, 0x00, 0xB4, 0x0A, 0x02, 0x7F, 0x01, 0xEF, 0x60, 0x05, 0xE4, ++0x90, 0x80, 0xF3, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xFF, ++0x30, 0xE0, 0x26, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0x4C, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, ++0x90, 0x81, 0x4D, 0xF0, 0xEF, 0x54, 0xFE, 0xFF, 0xA3, 0xE0, 0x54, 0x01, 0x4F, 0xF0, 0x90, 0x00, ++0x03, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x4F, 0xF0, 0x22, 0x90, 0x81, 0x4C, 0x74, 0x01, 0xF0, 0xA3, ++0x74, 0x05, 0xF0, 0xA3, 0xE0, 0x54, 0x01, 0x44, 0x28, 0xF0, 0xA3, 0x74, 0x05, 0xF0, 0x22, 0x90, ++0x02, 0x09, 0xE0, 0xFD, 0x12, 0x1F, 0xA4, 0xFE, 0xAF, 0x05, 0xED, 0x2E, 0x90, 0x80, 0x06, 0xF0, ++0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x80, 0x07, 0xF0, 0x90, 0x00, 0x02, ++0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x80, 0x08, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, ++0xFF, 0xED, 0x2F, 0x90, 0x80, 0x09, 0xF0, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFF, 0xAE, 0x05, ++0xED, 0x2F, 0x90, 0x80, 0x0A, 0xF0, 0x22, 0x90, 0x02, 0x09, 0xE0, 0xFD, 0x12, 0x1F, 0xA4, 0xFE, ++0xAF, 0x05, 0xED, 0x2E, 0x90, 0x82, 0x57, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0xED, ++0x2F, 0x90, 0x82, 0x58, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x82, ++0x59, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x82, 0x5A, 0xF0, 0x90, ++0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x82, 0x5B, 0xF0, 0x90, 0x00, 0x05, 0x12, ++0x1F, 0xBD, 0xFF, 0xAE, 0x05, 0xED, 0x2F, 0x90, 0x82, 0x5C, 0xF0, 0x22, 0x90, 0x02, 0x09, 0xE0, ++0xFD, 0x12, 0x1F, 0xA4, 0xFE, 0xAF, 0x05, 0xED, 0x2E, 0x90, 0x82, 0x5D, 0xF0, 0x90, 0x00, 0x01, ++0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x82, 0x5E, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, ++0xFF, 0xED, 0x2F, 0x90, 0x82, 0x5F, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, ++0x90, 0x82, 0x60, 0xF0, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x82, 0x61, ++0xF0, 0x90, 0x00, 0x05, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x82, 0x62, 0xF0, 0x90, 0x00, ++0x06, 0x12, 0x1F, 0xBD, 0xFF, 0xAE, 0x05, 0xED, 0x2F, 0x90, 0x82, 0x63, 0xF0, 0x22, 0x90, 0x82, ++0xD2, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0xA3, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x90, ++0x82, 0xE0, 0xF0, 0x7F, 0x24, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0x90, 0x82, 0xD8, 0x12, 0x20, 0xCE, ++0x90, 0x82, 0xD2, 0xE0, 0xFB, 0x70, 0x08, 0x90, 0x82, 0xD8, 0x12, 0x42, 0x26, 0x80, 0x16, 0xEB, ++0x75, 0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, 0x82, 0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, ++0xE0, 0xFF, 0x12, 0x2D, 0x5C, 0x90, 0x82, 0xDC, 0x12, 0x20, 0xCE, 0x90, 0x82, 0xD3, 0xE0, 0xFF, ++0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x17, 0x12, 0x20, 0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, ++0x07, 0x90, 0x82, 0xDC, 0x12, 0x42, 0x26, 0xED, 0x54, 0x7F, 0xFD, 0xEC, 0x54, 0x80, 0xFC, 0x12, ++0x42, 0x19, 0xEC, 0x44, 0x80, 0xFC, 0x90, 0x82, 0xDC, 0x12, 0x20, 0xCE, 0x90, 0x82, 0xD8, 0x12, ++0x42, 0x26, 0xEC, 0x54, 0x7F, 0xFC, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x24, 0x7E, 0x08, ++0x12, 0x2E, 0xA2, 0x90, 0x82, 0xD2, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, 0x82, 0xE4, ++0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x82, 0xDC, ++0x12, 0x42, 0x26, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0xD0, 0x07, 0xD0, 0x06, 0x12, 0x2E, 0xA2, ++0x90, 0x82, 0xD8, 0x12, 0x42, 0x26, 0xEC, 0x44, 0x80, 0xFC, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, ++0x7F, 0x24, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x82, 0xD2, 0xE0, 0x70, 0x04, 0x7F, 0x20, 0x80, ++0x09, 0x90, 0x82, 0xD2, 0xE0, 0xB4, 0x01, 0x16, 0x7F, 0x28, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0x78, ++0x08, 0x12, 0x20, 0xA8, 0xEF, 0x54, 0x01, 0xFF, 0xE4, 0x90, 0x82, 0xE0, 0xEF, 0xF0, 0x90, 0x82, ++0xE0, 0xE0, 0x90, 0x82, 0xD2, 0x60, 0x0E, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x66, 0xF5, 0x82, ++0xE4, 0x34, 0x87, 0x80, 0x0C, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x64, 0xF5, 0x82, 0xE4, 0x34, ++0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x12, 0x2D, 0x5C, 0xED, 0x54, 0x0F, 0xFD, 0xE4, ++0xFC, 0x90, 0x82, 0xD4, 0x12, 0x20, 0xCE, 0x90, 0x82, 0xD4, 0x02, 0x42, 0x26, 0x90, 0x82, 0xEF, ++0xEF, 0xF0, 0xAB, 0x05, 0x90, 0x82, 0xF5, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x03, ++0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x14, 0x12, 0x20, 0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, ++0x07, 0x90, 0x82, 0xF1, 0x12, 0x42, 0x26, 0xED, 0x54, 0x0F, 0xFD, 0xE4, 0xFC, 0x12, 0x42, 0x19, ++0xEC, 0x54, 0x0F, 0xFC, 0x90, 0x82, 0xF5, 0x12, 0x20, 0xCE, 0x90, 0x82, 0xEF, 0xE0, 0x75, 0xF0, ++0x08, 0xA4, 0x24, 0x60, 0xF5, 0x82, 0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, ++0xC0, 0x06, 0xC0, 0x07, 0x90, 0x82, 0xF5, 0x12, 0x42, 0x26, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, ++0xD0, 0x07, 0xD0, 0x06, 0x02, 0x2E, 0xA2, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x67, ++0xDE, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x82, 0xAE, 0xEC, 0xF0, 0xA3, 0xED, 0xF0, 0x90, 0x82, ++0xAD, 0xEF, 0xF0, 0xA3, 0xA3, 0xE0, 0xFD, 0x31, 0x87, 0x90, 0x82, 0xB8, 0x12, 0x20, 0xCE, 0x90, ++0x82, 0xB0, 0x12, 0x42, 0x26, 0x12, 0x20, 0x9B, 0x90, 0x82, 0xB8, 0x12, 0x42, 0x32, 0x12, 0x42, ++0x0C, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x82, 0xB0, 0x12, 0x42, 0x26, 0x90, ++0x82, 0xB4, 0x12, 0x42, 0x32, 0x12, 0x42, 0x0C, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, ++0x12, 0x42, 0x19, 0x90, 0x82, 0xBC, 0x12, 0x20, 0xCE, 0x90, 0x82, 0xAE, 0xA3, 0xE0, 0xFD, 0xC0, ++0x05, 0x90, 0x82, 0xBC, 0x12, 0x42, 0x26, 0x90, 0x85, 0x96, 0x12, 0x20, 0xCE, 0x90, 0x82, 0xAD, ++0xE0, 0xFF, 0xD0, 0x05, 0x02, 0x31, 0x4D, 0x90, 0x83, 0x1D, 0x12, 0x42, 0x53, 0xE4, 0xFF, 0x90, ++0x83, 0x1D, 0x12, 0x42, 0x4A, 0x8F, 0x82, 0x75, 0x83, 0x00, 0x12, 0x1F, 0xBD, 0xFE, 0x74, 0xF0, ++0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x02, 0xF5, 0x83, 0xEE, 0xF0, 0x0F, 0xEF, 0xB4, 0x10, 0xE0, 0x22, ++0x90, 0x83, 0x31, 0xEF, 0xF0, 0x7F, 0x02, 0x12, 0x46, 0x53, 0x90, 0x80, 0x01, 0xE0, 0xFF, 0x90, ++0x83, 0x31, 0xE0, 0xFE, 0xEF, 0x4E, 0x90, 0x80, 0x01, 0xF0, 0x22, 0x90, 0x83, 0x32, 0xEF, 0xF0, ++0x7F, 0x02, 0x12, 0x46, 0x53, 0x90, 0x80, 0x02, 0xE0, 0xFF, 0x90, 0x83, 0x32, 0xE0, 0xFE, 0xEF, ++0x4E, 0x90, 0x80, 0x02, 0xF0, 0x22, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x80, 0xFE, 0x90, 0x82, 0x6E, ++0xE0, 0x54, 0x7F, 0x4E, 0xFE, 0xF0, 0xEF, 0x54, 0x40, 0xFF, 0xEE, 0x54, 0xBF, 0x4F, 0xFF, 0xF0, ++0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x20, 0xFD, 0xEF, 0x54, 0xDF, 0x4D, 0xFF, 0x90, 0x82, 0x6E, 0xF0, ++0xEE, 0x54, 0x10, 0xFE, 0xEF, 0x54, 0xEF, 0x4E, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0x54, 0x0F, 0xFE, ++0xEF, 0x54, 0xF0, 0x4E, 0x90, 0x82, 0x6E, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x82, ++0x6F, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0x90, 0x82, 0x70, 0xF0, 0x90, 0x82, 0x6E, 0xE0, ++0xFE, 0x54, 0x0F, 0xFF, 0xEE, 0xC4, 0x13, 0x13, 0x54, 0x03, 0x7D, 0x00, 0x20, 0xE0, 0x02, 0x7D, ++0x01, 0x02, 0x52, 0x47, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x7F, 0x90, 0x81, 0x3B, 0xF0, 0xEF, 0xC4, ++0x13, 0x13, 0x13, 0x54, 0x01, 0xA3, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0x54, 0xF0, ++0xC4, 0x54, 0x0F, 0xFE, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0xF0, 0x4E, 0xF0, 0x90, 0x00, 0x03, 0x12, ++0x1F, 0xBD, 0x54, 0x01, 0x25, 0xE0, 0xFE, 0x90, 0x81, 0x38, 0xE0, 0x54, 0xFD, 0x4E, 0xF0, 0x90, ++0x81, 0x53, 0xE0, 0x30, 0xE0, 0x09, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0x0F, 0xF0, 0x80, 0x0F, 0xEF, ++0x54, 0x0F, 0xC4, 0x54, 0xF0, 0xFF, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0x0F, 0x4F, 0xF0, 0x90, 0x00, ++0x04, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x3D, 0xF0, 0x12, 0x5C, 0x93, 0x90, 0x01, 0xB9, 0x74, 0x01, ++0xF0, 0x90, 0x01, 0xB8, 0xF0, 0x90, 0x81, 0x3B, 0xE0, 0x90, 0x01, 0xBA, 0xF0, 0x90, 0x81, 0x3D, ++0xE0, 0x90, 0x01, 0xBB, 0xF0, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0x0F, 0x90, 0x01, 0xBE, 0xF0, 0x22, ++0x90, 0x01, 0xCC, 0xE0, 0x54, 0x0F, 0x90, 0x83, 0x33, 0xF0, 0x90, 0x83, 0x33, 0xE0, 0xFD, 0x70, ++0x02, 0x81, 0xED, 0x90, 0x80, 0x5B, 0xE0, 0xFF, 0x70, 0x06, 0xA3, 0xE0, 0x64, 0x09, 0x60, 0x0A, ++0xEF, 0x14, 0xFF, 0x90, 0x80, 0x5C, 0xE0, 0xB5, 0x07, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, ++0xEF, 0x60, 0x08, 0x90, 0x01, 0xC1, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90, 0x83, 0x23, 0xE0, 0xFF, ++0x74, 0x01, 0x7E, 0x00, 0xA8, 0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, ++0xFF, 0xEF, 0x5D, 0x70, 0x02, 0x81, 0xE6, 0x90, 0x83, 0x23, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, ++0xD0, 0x12, 0x42, 0x3E, 0xE0, 0xFF, 0x90, 0x80, 0x5C, 0xE0, 0xFE, 0x75, 0xF0, 0x08, 0x90, 0x80, ++0x0B, 0x12, 0x42, 0x3E, 0xEF, 0xF0, 0x90, 0x83, 0x23, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD1, ++0x12, 0x42, 0x3E, 0xE0, 0xFF, 0x75, 0xF0, 0x08, 0xEE, 0x90, 0x80, 0x0C, 0x12, 0x42, 0x3E, 0xEF, ++0xF0, 0x90, 0x83, 0x23, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD2, 0x12, 0x42, 0x3E, 0xE0, 0xFF, ++0x75, 0xF0, 0x08, 0xEE, 0x90, 0x80, 0x0D, 0x12, 0x42, 0x3E, 0xEF, 0xF0, 0x90, 0x83, 0x23, 0xE0, ++0x75, 0xF0, 0x04, 0x90, 0x01, 0xD3, 0x12, 0x42, 0x3E, 0xE0, 0xFF, 0x75, 0xF0, 0x08, 0xEE, 0x90, ++0x80, 0x0E, 0x12, 0x42, 0x3E, 0xEF, 0xF0, 0x90, 0x83, 0x23, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, ++0xF0, 0x12, 0x42, 0x3E, 0xE0, 0xFF, 0x75, 0xF0, 0x08, 0xEE, 0x90, 0x80, 0x0F, 0x12, 0x42, 0x3E, ++0xEF, 0xF0, 0x90, 0x83, 0x23, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF1, 0x12, 0x42, 0x3E, 0xE0, ++0xFF, 0x75, 0xF0, 0x08, 0xEE, 0x90, 0x80, 0x10, 0x12, 0x42, 0x3E, 0xEF, 0xF0, 0x90, 0x83, 0x23, ++0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF2, 0x12, 0x42, 0x3E, 0xE0, 0xFF, 0x75, 0xF0, 0x08, 0xEE, ++0x90, 0x80, 0x11, 0x12, 0x42, 0x3E, 0xEF, 0xF0, 0x90, 0x83, 0x23, 0xE0, 0x75, 0xF0, 0x04, 0x90, ++0x01, 0xF3, 0x12, 0x42, 0x3E, 0xE0, 0xFF, 0x75, 0xF0, 0x08, 0xEE, 0x90, 0x80, 0x12, 0x12, 0x42, ++0x3E, 0xEF, 0xF0, 0x90, 0x83, 0x33, 0xE0, 0xFF, 0x90, 0x83, 0x23, 0xE0, 0xFE, 0x74, 0x01, 0xA8, ++0x06, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xF4, 0x5F, 0x90, 0x83, 0x33, 0xF0, 0x90, 0x83, ++0x23, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0x90, 0x01, ++0xCC, 0xF0, 0x90, 0x83, 0x23, 0xE0, 0x04, 0xF0, 0xE0, 0x54, 0x03, 0xF0, 0x90, 0x80, 0x5C, 0xE0, ++0x04, 0xF0, 0xE0, 0x7F, 0x00, 0xB4, 0x0A, 0x02, 0x7F, 0x01, 0xEF, 0x70, 0x02, 0x61, 0x6A, 0xE4, ++0x90, 0x80, 0x5C, 0xF0, 0x61, 0x6A, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x02, 0xF0, 0x22, 0xD3, 0x10, ++0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x83, 0x0D, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xE4, 0xA3, 0xF0, ++0xA3, 0xF0, 0x90, 0x83, 0x0D, 0xE0, 0xFE, 0xA3, 0xE0, 0xF5, 0x82, 0x8E, 0x83, 0xE0, 0x60, 0x2D, ++0xC3, 0x90, 0x83, 0x10, 0xE0, 0x94, 0xE8, 0x90, 0x83, 0x0F, 0xE0, 0x94, 0x03, 0x40, 0x0B, 0x90, ++0x01, 0xC0, 0xE0, 0x44, 0x80, 0xF0, 0x7F, 0x00, 0x80, 0x15, 0x90, 0x83, 0x0F, 0xE4, 0x75, 0xF0, ++0x01, 0x12, 0x41, 0xF6, 0x7F, 0x0A, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x80, 0xC5, 0x7F, 0x01, 0xD0, ++0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x83, 0x20, 0x12, 0x42, ++0x53, 0x90, 0x83, 0x24, 0xE0, 0xFF, 0x04, 0xF0, 0x90, 0x00, 0x01, 0xEF, 0x12, 0x1F, 0xFC, 0x7F, ++0xAF, 0x7E, 0x01, 0x91, 0xEE, 0xEF, 0x60, 0x3A, 0x90, 0x83, 0x20, 0x12, 0x42, 0x4A, 0x8B, 0x13, ++0x8A, 0x14, 0x89, 0x15, 0x90, 0x00, 0x0E, 0x12, 0x1F, 0xBD, 0x24, 0x02, 0xF5, 0x16, 0x7B, 0x01, ++0x7A, 0x01, 0x79, 0xA0, 0x12, 0x2B, 0xED, 0x90, 0x83, 0x20, 0x12, 0x42, 0x4A, 0x90, 0x00, 0x0E, ++0x12, 0x1F, 0xBD, 0x90, 0x01, 0xAE, 0xF0, 0xA3, 0x74, 0xFF, 0xF0, 0x90, 0x01, 0xCB, 0xE0, 0x64, ++0x80, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x80, ++0xF3, 0xE0, 0xFF, 0x70, 0x06, 0xA3, 0xE0, 0x64, 0x09, 0x60, 0x0A, 0xEF, 0x14, 0xFF, 0x90, 0x80, ++0xF4, 0xE0, 0xB5, 0x07, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xEF, 0x60, 0x09, 0x90, 0x01, ++0xC1, 0xE0, 0x44, 0x02, 0xF0, 0x80, 0x35, 0xC0, 0x01, 0x90, 0x80, 0xF4, 0xE0, 0x75, 0xF0, 0x0F, ++0xA4, 0x24, 0x5D, 0xF9, 0x74, 0x80, 0x35, 0xF0, 0xA8, 0x01, 0xFC, 0x7D, 0x01, 0xD0, 0x01, 0x7E, ++0x00, 0x7F, 0x0F, 0x12, 0x41, 0xD0, 0x90, 0x80, 0xF4, 0xE0, 0x04, 0xF0, 0xE0, 0x7F, 0x00, 0xB4, ++0x0A, 0x02, 0x7F, 0x01, 0xEF, 0x60, 0x05, 0xE4, 0x90, 0x80, 0xF4, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, ++0x22, 0x90, 0x01, 0x34, 0xE0, 0x55, 0x3D, 0xF5, 0x41, 0xA3, 0xE0, 0x55, 0x3E, 0xF5, 0x42, 0xA3, ++0xE0, 0x55, 0x3F, 0xF5, 0x43, 0xA3, 0xE0, 0x55, 0x40, 0xF5, 0x44, 0x90, 0x01, 0x34, 0xE5, 0x41, ++0xF0, 0xA3, 0xE5, 0x42, 0xF0, 0xA3, 0xE5, 0x43, 0xF0, 0xA3, 0xE5, 0x44, 0xF0, 0x22, 0x90, 0x01, ++0x3C, 0xE0, 0x55, 0x45, 0xF5, 0x49, 0xA3, 0xE0, 0x55, 0x46, 0xF5, 0x4A, 0xA3, 0xE0, 0x55, 0x47, ++0xF5, 0x4B, 0xA3, 0xE0, 0x55, 0x48, 0xF5, 0x4C, 0x90, 0x01, 0x3C, 0xE5, 0x49, 0xF0, 0xA3, 0xE5, ++0x4A, 0xF0, 0xA3, 0xE5, 0x4B, 0xF0, 0xA3, 0xE5, 0x4C, 0xF0, 0x53, 0x91, 0xDF, 0x22, 0x8F, 0x52, ++0x7F, 0x02, 0x12, 0x46, 0x53, 0x90, 0x80, 0x02, 0xE0, 0x45, 0x52, 0xF0, 0x22, 0xD1, 0xD5, 0x90, ++0x82, 0x72, 0xEF, 0xF0, 0x90, 0x81, 0x38, 0x30, 0xE0, 0x06, 0xE0, 0x44, 0x01, 0xF0, 0x80, 0x04, ++0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x82, 0x72, 0xE0, 0x30, 0xE6, 0x11, 0x90, 0x01, 0x2F, 0xE0, 0x30, ++0xE7, 0x04, 0xE4, 0xF0, 0x80, 0x06, 0x90, 0x01, 0x2F, 0x74, 0x80, 0xF0, 0x90, 0x81, 0x38, 0xE0, ++0x30, 0xE0, 0x1A, 0x90, 0x81, 0x46, 0xE4, 0xF0, 0xA3, 0x74, 0x07, 0xF0, 0x90, 0x81, 0x46, 0xA3, ++0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90, 0x04, 0xEC, 0xE0, 0x54, 0xDD, 0xF0, 0x22, 0x90, 0x04, 0xEC, ++0xE0, 0x44, 0x22, 0xF0, 0x22, 0xE4, 0x90, 0x82, 0x73, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x00, ++0x83, 0xE0, 0x90, 0x82, 0x73, 0xF0, 0x90, 0x00, 0x83, 0xE0, 0xFE, 0x90, 0x82, 0x73, 0xE0, 0xFF, ++0xB5, 0x06, 0x01, 0x22, 0xC3, 0x90, 0x82, 0x75, 0xE0, 0x94, 0x64, 0x90, 0x82, 0x74, 0xE0, 0x94, ++0x00, 0x40, 0x0D, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x82, 0x73, 0xE0, 0xFF, 0x22, ++0x90, 0x82, 0x74, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x41, 0xF6, 0x80, 0xC2, 0x90, 0x81, 0x38, 0xE0, ++0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x30, 0xE0, 0x2C, 0xEF, 0x54, 0x7F, 0xF0, 0x90, 0x04, ++0xE0, 0xE0, 0x90, 0x81, 0x39, 0x30, 0xE1, 0x06, 0xE0, 0x44, 0x02, 0xF0, 0x80, 0x0F, 0xE0, 0x54, ++0xFD, 0xF0, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x04, 0xF0, 0x90, 0x81, 0x3B, ++0xE0, 0x60, 0x03, 0x12, 0x4E, 0x3A, 0x7F, 0x01, 0x02, 0x51, 0x2A, 0xD3, 0x10, 0xAF, 0x01, 0xC3, ++0xC0, 0xD0, 0x90, 0x04, 0x1D, 0xE0, 0x60, 0x1A, 0x90, 0x05, 0x22, 0xE0, 0x54, 0x90, 0x60, 0x07, ++0x90, 0x01, 0xC0, 0xE0, 0x44, 0x08, 0xF0, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE1, 0xE4, 0x7F, 0x00, ++0x80, 0x02, 0x7F, 0x01, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xC3, 0xEE, 0x94, 0x01, 0x40, 0x0A, 0x0D, ++0xED, 0x13, 0x90, 0xFD, 0x10, 0xF0, 0xE4, 0x2F, 0xFF, 0x22, 0xC3, 0xEE, 0x94, 0x01, 0x40, 0x1E, ++0x90, 0xFD, 0x11, 0xE0, 0xB5, 0x05, 0x14, 0x90, 0x01, 0x17, 0xE0, 0xB5, 0x05, 0x07, 0x90, 0xFD, ++0x11, 0xE4, 0xF0, 0x80, 0x06, 0xED, 0x04, 0x90, 0xFD, 0x11, 0xF0, 0xE4, 0x2F, 0xFF, 0x22, 0xE4, ++0x90, 0x83, 0x29, 0xF0, 0xA3, 0xF0, 0x90, 0x05, 0xF8, 0xE0, 0x70, 0x0F, 0xA3, 0xE0, 0x70, 0x0B, ++0xA3, 0xE0, 0x70, 0x07, 0xA3, 0xE0, 0x70, 0x03, 0x7F, 0x01, 0x22, 0xD3, 0x90, 0x83, 0x2A, 0xE0, ++0x94, 0xE8, 0x90, 0x83, 0x29, 0xE0, 0x94, 0x03, 0x40, 0x0A, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x20, ++0xF0, 0x7F, 0x00, 0x22, 0x7F, 0x32, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x90, 0x83, 0x29, 0xE4, 0x75, ++0xF0, 0x01, 0x12, 0x41, 0xF6, 0x80, 0xBF, 0x74, 0x45, 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, ++0xFE, 0xF6, 0x74, 0x38, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0x90, ++0x82, 0xC0, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x12, 0x2D, 0x5C, 0x90, 0x82, 0xCA, 0x12, 0x20, 0xCE, ++0x90, 0x82, 0xC2, 0x12, 0x42, 0x26, 0x12, 0x20, 0x9B, 0x90, 0x82, 0xCA, 0x12, 0x42, 0x32, 0x12, ++0x42, 0x0C, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x82, 0xC2, 0x12, 0x42, 0x26, ++0x90, 0x82, 0xC6, 0x12, 0x42, 0x32, 0x12, 0x42, 0x0C, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, ++0x00, 0x12, 0x42, 0x19, 0x90, 0x82, 0xCE, 0x12, 0x20, 0xCE, 0x90, 0x82, 0xCE, 0x12, 0x42, 0x26, ++0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0x90, 0x82, 0xC0, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x02, 0x2E, ++0xA2, 0xE4, 0x90, 0x81, 0x3B, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0x0F, 0xF0, 0x54, ++0xF0, 0xF0, 0x90, 0x81, 0x38, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0xF7, 0xF0, 0x90, 0x81, 0x41, 0x74, ++0x01, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0x38, 0xE0, 0x54, 0xFB, 0xF0, 0xA3, 0xE0, 0x54, 0xFB, 0xF0, ++0xE4, 0x90, 0x81, 0x44, 0xF0, 0x90, 0x81, 0x43, 0x74, 0x07, 0xF0, 0x90, 0x81, 0x46, 0xE4, 0xF0, ++0xA3, 0x74, 0x02, 0xF0, 0xE4, 0x90, 0x81, 0x3F, 0xF0, 0x90, 0x81, 0x38, 0xE0, 0x54, 0xFE, 0xF0, ++0x90, 0x81, 0x3D, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x38, 0xE0, 0x54, 0xDF, 0xF0, 0x90, 0x81, 0x3E, ++0x74, 0x0C, 0xF0, 0x90, 0x81, 0x38, 0xE0, 0x54, 0xBF, 0xF0, 0x54, 0x7F, 0xF0, 0xA3, 0xE0, 0x54, ++0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x54, 0xF7, 0xF0, 0x90, 0x81, 0x48, 0x12, 0x20, 0xDA, 0x00, 0x00, ++0x00, 0x00, 0x90, 0x80, 0x05, 0xE0, 0xB4, 0x01, 0x08, 0x90, 0x81, 0x45, 0x74, 0x99, 0xF0, 0x80, ++0x12, 0x90, 0x80, 0x05, 0xE0, 0x90, 0x81, 0x45, 0xB4, 0x03, 0x05, 0x74, 0x90, 0xF0, 0x80, 0x03, ++0x74, 0x40, 0xF0, 0x90, 0x81, 0x4C, 0x74, 0x01, 0xF0, 0xA3, 0x74, 0x05, 0xF0, 0xA3, 0xE0, 0x54, ++0x01, 0x44, 0x28, 0xF0, 0xA3, 0x74, 0x05, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xE0, 0x54, 0xFD, 0xF0, ++0x54, 0xFB, 0xF0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x54, 0xDF, 0xF0, 0x54, 0xBF, 0xF0, 0xE4, ++0xA3, 0xF0, 0x22, 0x90, 0x81, 0x38, 0xE0, 0x54, 0xFB, 0xF0, 0xE4, 0x90, 0x81, 0x44, 0xF0, 0x90, ++0x81, 0x3F, 0xF0, 0x22, 0x90, 0x04, 0x1A, 0xE0, 0xF4, 0x60, 0x03, 0x7F, 0x00, 0x22, 0x90, 0x04, ++0x1B, 0xE0, 0x54, 0x07, 0x64, 0x07, 0x7F, 0x01, 0x60, 0x02, 0x7F, 0x00, 0x22, 0x31, 0x64, 0xEF, ++0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x01, 0xF0, 0x80, 0x67, 0x90, 0x81, 0x3F, 0xE0, ++0xFF, 0x54, 0x03, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x02, 0xF0, 0x80, 0x56, 0x90, 0x81, 0x3D, ++0xE0, 0xFE, 0xE4, 0xC3, 0x9E, 0x50, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x44, 0xEF, ++0x30, 0xE2, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0x80, 0x38, 0x90, 0x81, 0x3F, 0xE0, 0x30, ++0xE4, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x10, 0xF0, 0x80, 0x29, 0x90, 0x81, 0x39, 0xE0, 0x13, 0x13, ++0x54, 0x3F, 0x20, 0xE0, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x20, 0xF0, 0x80, 0x16, 0x90, 0x81, 0x52, ++0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x80, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4, 0xF0, ++0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74, 0x04, 0xF0, 0x7F, 0x00, 0x22, 0xEF, 0x24, 0xFE, 0x60, ++0x0C, 0x04, 0x70, 0x28, 0x90, 0x81, 0x41, 0x74, 0x01, 0xF0, 0xA3, 0xF0, 0x22, 0xED, 0x70, 0x0A, ++0x90, 0x81, 0x4F, 0xE0, 0x90, 0x81, 0x41, 0xF0, 0x80, 0x05, 0x90, 0x81, 0x41, 0xED, 0xF0, 0x90, ++0x81, 0x41, 0xE0, 0xA3, 0xF0, 0x90, 0x81, 0x39, 0xE0, 0x44, 0x08, 0xF0, 0x22, 0xEF, 0x60, 0x3E, ++0x90, 0x80, 0xF7, 0xE0, 0x64, 0x01, 0x70, 0x36, 0x90, 0x81, 0x39, 0xE0, 0x54, 0xFE, 0xF0, 0x90, ++0x05, 0x22, 0x74, 0x0F, 0xF0, 0x90, 0x06, 0x04, 0xE0, 0x54, 0xBF, 0xF0, 0xE4, 0xFF, 0x12, 0x4C, ++0x52, 0xBF, 0x01, 0x0E, 0x90, 0x81, 0x38, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x81, 0x3E, 0x74, 0x06, ++0xF0, 0x22, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0x22, 0x90, ++0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81, 0x3E, 0x74, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x3B, 0xE0, 0x60, ++0x2F, 0x90, 0x80, 0xF7, 0xE0, 0x64, 0x01, 0x70, 0x27, 0x90, 0x81, 0x42, 0xF0, 0x04, 0x60, 0x20, ++0x90, 0x81, 0x3F, 0xE0, 0x44, 0x10, 0xF0, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x43, 0x12, 0x4E, 0xD3, ++0x90, 0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x3E, 0xE0, 0x20, 0xE2, 0x03, 0x12, 0x49, 0x10, ++0x22, 0x90, 0x81, 0x38, 0xE0, 0xFF, 0x13, 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x11, 0xEF, 0x54, 0xFB, ++0xF0, 0x90, 0x81, 0x3F, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0x07, 0x70, 0x42, 0x80, 0x3D, 0x90, 0x81, ++0x44, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x3F, 0xE0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x44, 0xE0, 0xFF, ++0xB4, 0x01, 0x02, 0x80, 0x04, 0xEF, 0xB4, 0x02, 0x06, 0x90, 0x05, 0x58, 0xE0, 0x04, 0xF0, 0x90, ++0x81, 0x4C, 0xE0, 0xFF, 0x90, 0x81, 0x44, 0xE0, 0xD3, 0x9F, 0x40, 0x0F, 0x90, 0x80, 0xF7, 0xE0, ++0xB4, 0x01, 0x0B, 0x90, 0x81, 0x39, 0xE0, 0x54, 0xFB, 0xF0, 0x22, 0x12, 0x4E, 0x3A, 0x22, 0x90, ++0x80, 0x08, 0xE0, 0xFE, 0x90, 0x04, 0x1C, 0xE0, 0x6E, 0x70, 0x40, 0x90, 0x81, 0x3E, 0xE0, 0xFE, ++0xB4, 0x0E, 0x18, 0xEF, 0x70, 0x35, 0x90, 0x81, 0x38, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x06, 0x04, ++0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x81, 0x3E, 0x74, 0x0C, 0xF0, 0x22, 0xEE, 0x64, 0x06, 0x70, 0x1B, ++0xEF, 0x60, 0x18, 0x90, 0x81, 0x38, 0xE0, 0x54, 0xBF, 0xF0, 0x90, 0x06, 0x04, 0xE0, 0x44, 0x40, ++0xF0, 0xE0, 0x44, 0x80, 0xF0, 0x90, 0x81, 0x3E, 0x74, 0x04, 0xF0, 0x22, 0x90, 0x82, 0x65, 0xE0, ++0x54, 0xFE, 0xF0, 0x54, 0x7F, 0xF0, 0xA3, 0x74, 0x0A, 0xF0, 0xE4, 0xA3, 0xF0, 0x22, 0x7D, 0x7F, ++0xEF, 0x5D, 0xC3, 0x60, 0x14, 0x74, 0xFF, 0x9D, 0xFD, 0x74, 0xFF, 0x94, 0x00, 0x5E, 0xFE, 0xED, ++0x5F, 0x24, 0x80, 0xFF, 0xE4, 0x3E, 0xFE, 0x80, 0x0D, 0x74, 0xFF, 0x9D, 0xFD, 0x74, 0xFF, 0x94, ++0x00, 0x5E, 0xFE, 0xED, 0x5F, 0xFF, 0x22, 0x90, 0x01, 0x1F, 0xE0, 0xFE, 0x90, 0x01, 0x1E, 0xE0, ++0x7C, 0x00, 0x24, 0x00, 0xFF, 0xEC, 0x3E, 0x90, 0x82, 0x7E, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x02, ++0x87, 0xE0, 0x90, 0x82, 0x82, 0xF0, 0x90, 0x81, 0x53, 0xE0, 0x20, 0xE0, 0x02, 0x81, 0x8F, 0x90, ++0x82, 0x82, 0xE0, 0xFF, 0xEC, 0xC3, 0x9F, 0x40, 0x02, 0x81, 0x8F, 0x90, 0x82, 0x7E, 0xE0, 0xFA, ++0xA3, 0xE0, 0xFB, 0xEA, 0x90, 0xFD, 0x11, 0xF0, 0xAF, 0x03, 0xAD, 0x07, 0x74, 0x02, 0x2D, 0xF5, ++0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x54, 0x0F, 0x33, 0x33, 0x33, 0x54, 0xF8, 0xF9, 0x74, ++0x01, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFE, 0x74, 0x00, 0x2D, 0xF5, 0x82, ++0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x7A, 0x00, 0x24, 0x00, 0xFF, 0xEA, 0x3E, 0x54, 0x3F, 0x90, ++0x82, 0x80, 0xF0, 0xA3, 0xEF, 0xF0, 0x74, 0x03, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, ++0xE0, 0x54, 0x03, 0xFF, 0x7E, 0x00, 0xAD, 0x01, 0xED, 0x24, 0x18, 0xFB, 0xEA, 0x33, 0xCB, 0x2F, ++0xFF, 0xEE, 0x3B, 0x90, 0x82, 0x80, 0x8F, 0xF0, 0x12, 0x41, 0xF6, 0x90, 0x82, 0x80, 0xE0, 0xFE, ++0xA3, 0xE0, 0xFF, 0x71, 0x6E, 0x90, 0x82, 0x80, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x82, 0x7E, ++0xEE, 0x8F, 0xF0, 0x12, 0x41, 0xF6, 0x90, 0x80, 0xF5, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xD3, 0x90, ++0x82, 0x7F, 0xE0, 0x9F, 0x90, 0x82, 0x7E, 0xE0, 0x9E, 0x40, 0x1B, 0x90, 0x80, 0xF6, 0xE0, 0x24, ++0x01, 0xFF, 0x90, 0x80, 0xF5, 0xE0, 0x34, 0x00, 0xFE, 0xC3, 0x90, 0x82, 0x7F, 0xE0, 0x9F, 0xF0, ++0x90, 0x82, 0x7E, 0xE0, 0x9E, 0xF0, 0x90, 0x82, 0x7E, 0x12, 0x57, 0xC5, 0x0C, 0x61, 0xBF, 0x22, ++0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x1F, 0xA4, 0xFC, 0x20, 0xE0, 0x05, 0x12, 0x5C, ++0x70, 0xA1, 0x97, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, 0x81, 0x54, 0xE0, 0x54, 0xFE, ++0x4E, 0xFE, 0xF0, 0xEF, 0x54, 0x02, 0xFF, 0xEE, 0x54, 0xFD, 0x4F, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, ++0xFE, 0x54, 0x04, 0xFD, 0xEF, 0x54, 0xFB, 0x4D, 0xFF, 0x90, 0x81, 0x54, 0xF0, 0xEE, 0x54, 0x08, ++0xFE, 0xEF, 0x54, 0xF7, 0x4E, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x10, 0xFD, 0xEF, 0x54, ++0xEF, 0x4D, 0xFF, 0x90, 0x81, 0x54, 0xF0, 0xEE, 0x54, 0x20, 0xFE, 0xEF, 0x54, 0xDF, 0x4E, 0xFF, ++0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x40, 0xFD, 0xEF, 0x54, 0xBF, 0x4D, 0xFF, 0x90, 0x81, 0x54, ++0xF0, 0xEE, 0x54, 0x80, 0xFE, 0xEF, 0x54, 0x7F, 0x4E, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, ++0xFD, 0x54, 0x80, 0xFF, 0x90, 0x81, 0x55, 0xE0, 0x54, 0x7F, 0x4F, 0xF0, 0xEC, 0x13, 0x13, 0x54, ++0x3F, 0x30, 0xE0, 0x07, 0x90, 0x06, 0x90, 0xE0, 0x44, 0x04, 0xF0, 0x12, 0x1F, 0xA4, 0x13, 0x13, ++0x13, 0x54, 0x1F, 0x30, 0xE0, 0x07, 0x90, 0x06, 0x90, 0xE0, 0x44, 0x08, 0xF0, 0x90, 0x80, 0x05, ++0xE0, 0x64, 0x02, 0x70, 0x44, 0x90, 0x81, 0x55, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, ++0x20, 0xE0, 0x36, 0xED, 0x54, 0x7F, 0xFE, 0xEF, 0x54, 0x80, 0x4E, 0x90, 0x81, 0x55, 0xF0, 0x90, ++0x00, 0x02, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x56, 0xF0, 0x90, 0x81, 0x54, 0xE0, 0xC4, 0x13, 0x54, ++0x07, 0x30, 0xE0, 0x09, 0xA3, 0xE0, 0x54, 0x7F, 0xFF, 0xE4, 0xFD, 0x80, 0x09, 0x90, 0x81, 0x55, ++0xE0, 0x54, 0x7F, 0xFF, 0x7D, 0x01, 0x12, 0x52, 0x47, 0x90, 0x80, 0x05, 0xE0, 0xB4, 0x01, 0x07, ++0x90, 0xFE, 0x10, 0xE0, 0x44, 0x04, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x81, 0x58, 0xE0, ++0xFF, 0x20, 0xE0, 0x07, 0x90, 0x01, 0x3F, 0xE0, 0x30, 0xE2, 0x14, 0xEF, 0x44, 0x01, 0x90, 0x81, ++0x58, 0xF0, 0x90, 0x81, 0x54, 0xE0, 0xC4, 0x54, 0x0F, 0x20, 0xE0, 0x03, 0x7F, 0x00, 0x22, 0x7F, ++0x01, 0x22, 0xEF, 0x90, 0x01, 0xC7, 0xB4, 0xA0, 0x05, 0x74, 0x04, 0xF0, 0x80, 0x03, 0x74, 0x08, ++0xF0, 0x90, 0x81, 0x58, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0xE4, 0xFE, 0xEF, 0x2E, 0x24, 0x04, 0xF5, ++0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFD, 0x74, 0x8B, 0x2E, 0xF5, 0x82, 0xE4, 0x34, 0x82, ++0xF5, 0x83, 0xED, 0xF0, 0x0E, 0xEE, 0xB4, 0x06, 0xE2, 0x78, 0x59, 0x7C, 0x81, 0x7D, 0x01, 0x7B, ++0x01, 0x7A, 0x82, 0x79, 0x8B, 0x7E, 0x00, 0x7F, 0x06, 0x12, 0x44, 0x08, 0xEF, 0x7F, 0x00, 0x70, ++0x02, 0x7F, 0x01, 0x22, 0x90, 0x82, 0x8B, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0x78, ++0x94, 0x7C, 0x82, 0x7D, 0x01, 0x7B, 0xFF, 0x7A, 0x40, 0x79, 0xC0, 0x7E, 0x00, 0x7F, 0x06, 0x12, ++0x41, 0xD0, 0x78, 0x9A, 0x7C, 0x82, 0x7D, 0x01, 0x7B, 0xFF, 0x7A, 0x40, 0x79, 0xC6, 0x7E, 0x00, ++0x7F, 0x04, 0x12, 0x41, 0xD0, 0x78, 0x9E, 0x7C, 0x82, 0x7D, 0x01, 0x7B, 0xFF, 0x7A, 0x40, 0x79, ++0xCA, 0x7E, 0x00, 0x7F, 0x04, 0x12, 0x41, 0xD0, 0x90, 0x82, 0x8D, 0xE0, 0xFF, 0x90, 0x82, 0x8C, ++0xE0, 0x2F, 0xFF, 0x90, 0x82, 0x8B, 0xE0, 0x34, 0x00, 0xCF, 0x24, 0x06, 0xCF, 0x34, 0x00, 0xFE, ++0xE4, 0xFD, 0x12, 0x56, 0x5F, 0xEF, 0x64, 0x08, 0x60, 0x02, 0xE1, 0xD9, 0x90, 0x82, 0x8D, 0xE0, ++0xFF, 0x90, 0x82, 0x8C, 0xE0, 0x2F, 0xFF, 0x90, 0x82, 0x8B, 0xE0, 0x34, 0x00, 0xCF, 0x24, 0x07, ++0xCF, 0x34, 0x00, 0xFE, 0xE4, 0xFD, 0x12, 0x56, 0x5F, 0xEF, 0x64, 0x06, 0x60, 0x02, 0xE1, 0xD9, ++0x90, 0x82, 0xA2, 0xF0, 0x90, 0x82, 0xA2, 0xE0, 0xFF, 0xC3, 0x94, 0x06, 0x50, 0x20, 0x90, 0x82, ++0x8C, 0xE0, 0x24, 0x0A, 0x12, 0x56, 0x4D, 0x90, 0x82, 0xA2, 0xE0, 0x24, 0x8E, 0xF5, 0x82, 0xE4, ++0x34, 0x82, 0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x82, 0xA2, 0xE0, 0x04, 0xF0, 0x80, 0xD6, 0xE4, 0x90, ++0x82, 0xA2, 0xF0, 0x90, 0x82, 0xA2, 0xE0, 0xFF, 0xC3, 0x94, 0x06, 0x50, 0x2F, 0x90, 0x82, 0x8D, ++0xE0, 0xFD, 0x90, 0x82, 0x8C, 0xE0, 0x2D, 0xFD, 0x90, 0x82, 0x8B, 0xE0, 0x34, 0x00, 0xCD, 0x24, ++0x10, 0xCD, 0x12, 0x56, 0x52, 0x90, 0x82, 0xA2, 0xE0, 0x24, 0x94, 0xF5, 0x82, 0xE4, 0x34, 0x82, ++0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x82, 0xA2, 0xE0, 0x04, 0xF0, 0x80, 0xC7, 0xE4, 0x90, 0x82, 0xA2, ++0xF0, 0x90, 0x82, 0xA2, 0xE0, 0xFF, 0xC3, 0x94, 0x04, 0x50, 0x2F, 0x90, 0x82, 0x8D, 0xE0, 0xFD, ++0x90, 0x82, 0x8C, 0xE0, 0x2D, 0xFD, 0x90, 0x82, 0x8B, 0xE0, 0x34, 0x00, 0xCD, 0x24, 0x16, 0xCD, ++0x12, 0x56, 0x52, 0x90, 0x82, 0xA2, 0xE0, 0x24, 0x9A, 0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, ++0xEF, 0xF0, 0x90, 0x82, 0xA2, 0xE0, 0x04, 0xF0, 0x80, 0xC7, 0x78, 0x8E, 0x7C, 0x82, 0x7D, 0x01, ++0x7B, 0x01, 0x7A, 0x81, 0x79, 0x5F, 0x7E, 0x00, 0x7F, 0x06, 0x12, 0x44, 0x08, 0xEF, 0x70, 0x79, ++0x90, 0x82, 0xA2, 0xF0, 0x90, 0x82, 0xA2, 0xE0, 0xFF, 0xC3, 0x94, 0x04, 0x50, 0x2F, 0x90, 0x82, ++0x8D, 0xE0, 0xFD, 0x90, 0x82, 0x8C, 0xE0, 0x2D, 0xFD, 0x90, 0x82, 0x8B, 0xE0, 0x34, 0x00, 0xCD, ++0x24, 0x20, 0xCD, 0x12, 0x56, 0x52, 0x90, 0x82, 0xA2, 0xE0, 0x24, 0x9E, 0xF5, 0x82, 0xE4, 0x34, ++0x82, 0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x82, 0xA2, 0xE0, 0x04, 0xF0, 0x80, 0xC7, 0x78, 0x9E, 0x7C, ++0x82, 0x7D, 0x01, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x6C, 0x7E, 0x00, 0x7F, 0x04, 0x12, 0x44, 0x08, ++0xEF, 0x90, 0x06, 0x30, 0x70, 0x1D, 0xE0, 0x44, 0x01, 0x54, 0xDF, 0xF0, 0x7B, 0x01, 0x7A, 0x82, ++0x79, 0x94, 0x90, 0x82, 0xA6, 0x12, 0x42, 0x53, 0xE4, 0x90, 0x82, 0xA9, 0xF0, 0x7A, 0x82, 0x79, ++0x9A, 0x80, 0x07, 0xE0, 0x44, 0x21, 0x54, 0xEF, 0xF0, 0x22, 0x90, 0x82, 0xA3, 0x12, 0x42, 0x53, ++0x90, 0x82, 0x58, 0xE0, 0xFF, 0x7D, 0x01, 0x12, 0x4D, 0xB7, 0x90, 0x82, 0xAA, 0x12, 0x5E, 0x75, ++0x90, 0x82, 0xAC, 0xEF, 0xF0, 0x90, 0x82, 0xAA, 0xA3, 0xE0, 0x24, 0x20, 0xF9, 0xE4, 0x34, 0xFC, ++0xFA, 0x7B, 0x01, 0x90, 0x82, 0xA9, 0xE0, 0xFD, 0x12, 0x5E, 0xAA, 0x90, 0x82, 0xAA, 0xA3, 0xE0, ++0x24, 0x30, 0xF9, 0xE4, 0x34, 0xFC, 0xFA, 0x7B, 0x01, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, ++0x82, 0xA6, 0x12, 0x42, 0x4A, 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x75, 0x16, 0x06, 0xD0, 0x01, ++0xD0, 0x02, 0xD0, 0x03, 0x12, 0x2B, 0xED, 0x90, 0x82, 0xAA, 0xA3, 0xE0, 0xFF, 0xA3, 0xE0, 0x2F, ++0x24, 0x3A, 0xF9, 0xE4, 0x34, 0xFC, 0xFA, 0x7B, 0x01, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, ++0x82, 0xA6, 0x12, 0x42, 0x4A, 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x75, 0x16, 0x06, 0xD0, 0x01, ++0xD0, 0x02, 0xD0, 0x03, 0x12, 0x2B, 0xED, 0x90, 0x82, 0xAA, 0xA3, 0xE0, 0xFF, 0xA3, 0xE0, 0x2F, ++0x24, 0x40, 0xF9, 0xE4, 0x34, 0xFC, 0xFA, 0x7B, 0x01, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, ++0x82, 0xA3, 0x12, 0x42, 0x4A, 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x75, 0x16, 0x04, 0xD0, 0x01, ++0xD0, 0x02, 0xD0, 0x03, 0x12, 0x2B, 0xED, 0x90, 0x06, 0x30, 0xE0, 0x44, 0x10, 0xF0, 0x12, 0x6F, ++0x5B, 0xBF, 0x01, 0x0E, 0x90, 0x82, 0x58, 0xE0, 0x90, 0x04, 0x25, 0xF0, 0x90, 0x04, 0x1F, 0x74, ++0x20, 0xF0, 0x22, 0xE4, 0xFF, 0x74, 0x18, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x06, 0xF5, 0x83, 0xE0, ++0xFE, 0x74, 0x5F, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xEE, 0xF0, 0x74, 0x10, 0x2F, ++0xF5, 0x82, 0xE4, 0x34, 0x06, 0xF5, 0x83, 0xE0, 0xFE, 0x74, 0x59, 0x2F, 0xF5, 0x82, 0xE4, 0x34, ++0x81, 0xF5, 0x83, 0xEE, 0xF0, 0x0F, 0xEF, 0xB4, 0x06, 0xCB, 0x22, 0x90, 0x82, 0x68, 0xE0, 0x30, ++0xE0, 0x36, 0x90, 0x82, 0x6B, 0xE0, 0x04, 0xF0, 0xE0, 0xFF, 0x90, 0x82, 0x69, 0xE0, 0x6F, 0x70, ++0x27, 0x90, 0x06, 0x92, 0xE0, 0x20, 0xE2, 0x11, 0x90, 0x82, 0x6D, 0xE0, 0x70, 0x0B, 0x12, 0x4F, ++0xC5, 0x90, 0x82, 0x6C, 0xE0, 0x04, 0xF0, 0x80, 0x06, 0x90, 0x06, 0x92, 0x74, 0x04, 0xF0, 0xE4, ++0x90, 0x82, 0x6B, 0xF0, 0x90, 0x82, 0x6D, 0xF0, 0x22, 0x90, 0x82, 0xE1, 0x12, 0x42, 0x53, 0x12, ++0x1F, 0xA4, 0x90, 0x82, 0xE6, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x82, 0xE7, 0xF0, ++0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0x90, 0x82, 0xE8, 0xF0, 0x90, 0x00, 0x05, 0x12, 0x1F, 0xBD, ++0x90, 0x82, 0xE9, 0xF0, 0x90, 0x00, 0x06, 0x12, 0x1F, 0xBD, 0x90, 0x82, 0xEA, 0xF0, 0x90, 0x00, ++0x07, 0x12, 0x1F, 0xBD, 0x90, 0x82, 0xEB, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0x90, 0x82, ++0xEE, 0xF0, 0xED, 0x70, 0x31, 0xFF, 0x74, 0xE6, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, ++0xE0, 0xB4, 0xFF, 0x0E, 0x74, 0xE6, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, 0xE4, 0xF0, ++0x80, 0x0F, 0x74, 0xE6, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, 0xE0, 0x04, 0xF0, 0x80, ++0x05, 0x0F, 0xEF, 0xB4, 0x06, 0xD0, 0x90, 0x82, 0xE5, 0xE0, 0xFF, 0xB4, 0x04, 0x25, 0xA3, 0xE0, ++0xFE, 0x90, 0x82, 0xE1, 0x12, 0x42, 0x4A, 0xEE, 0x12, 0x1F, 0xEA, 0x90, 0x82, 0xE7, 0xE0, 0xFE, ++0x90, 0x82, 0xE1, 0x12, 0x42, 0x4A, 0x90, 0x00, 0x01, 0xEE, 0x12, 0x1F, 0xFC, 0x90, 0x00, 0x02, ++0xE4, 0x80, 0x30, 0xEF, 0xB4, 0x02, 0x2F, 0x90, 0x82, 0xE7, 0xE0, 0xFF, 0x90, 0x82, 0xE1, 0x12, ++0x42, 0x4A, 0xEF, 0x12, 0x1F, 0xEA, 0x90, 0x82, 0xE7, 0xE0, 0x44, 0x20, 0x54, 0x7F, 0xFF, 0x90, ++0x82, 0xE1, 0x12, 0x42, 0x4A, 0x90, 0x00, 0x01, 0xEF, 0x12, 0x1F, 0xFC, 0x90, 0x82, 0xE6, 0xE0, ++0x90, 0x00, 0x02, 0x12, 0x1F, 0xFC, 0x90, 0x82, 0xE1, 0x12, 0x42, 0x4A, 0xE9, 0x24, 0x03, 0xF9, ++0xE4, 0x3A, 0xFA, 0x12, 0x1F, 0xA4, 0x44, 0x20, 0x12, 0x1F, 0xEA, 0x90, 0x82, 0xE8, 0xE0, 0xFF, ++0x90, 0x82, 0xE1, 0x12, 0x42, 0x4A, 0x90, 0x00, 0x04, 0xEF, 0x12, 0x1F, 0xFC, 0x90, 0x82, 0xE9, ++0xE0, 0x90, 0x00, 0x05, 0x12, 0x1F, 0xFC, 0x90, 0x82, 0xEA, 0xE0, 0x90, 0x00, 0x06, 0x12, 0x1F, ++0xFC, 0x90, 0x82, 0xEB, 0xE0, 0x90, 0x00, 0x07, 0x02, 0x1F, 0xFC, 0x90, 0x82, 0xFC, 0xED, 0xF0, ++0x90, 0x82, 0xF9, 0x12, 0x42, 0x53, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0x90, 0x83, 0x00, 0xF0, ++0x90, 0x82, 0xF9, 0x12, 0x42, 0x4A, 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x75, 0x16, 0x03, 0x7B, ++0x01, 0x7A, 0x82, 0x79, 0xFD, 0x12, 0x2B, 0xED, 0x90, 0x82, 0xFC, 0xE0, 0x70, 0x46, 0xFF, 0x74, ++0xFD, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, 0xE0, 0xB4, 0xFF, 0x0E, 0x74, 0xFD, 0x2F, ++0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, 0xE4, 0xF0, 0x80, 0x0F, 0x74, 0xFD, 0x2F, 0xF5, 0x82, ++0xE4, 0x34, 0x82, 0xF5, 0x83, 0xE0, 0x04, 0xF0, 0x80, 0x05, 0x0F, 0xEF, 0xB4, 0x03, 0xD0, 0x75, ++0x13, 0x01, 0x75, 0x14, 0x82, 0x75, 0x15, 0xFD, 0x75, 0x16, 0x03, 0x90, 0x82, 0xF9, 0x12, 0x42, ++0x4A, 0x12, 0x2B, 0xED, 0x22, 0x00, 0xDB, 0x90, ++}; ++#if 0 ++u4Byte ArrayLength_8188E_FW_WoWLAN = 15554; ++ ++ ++void ++ODM_ReadFirmware_8188E_FW_WoWLAN( ++ IN PDM_ODM_T pDM_Odm, ++ OUT u1Byte *pFirmware, ++ OUT u4Byte *pFirmwareSize ++) ++{ ++ ODM_MoveMemory(pDM_Odm, pFirmware, Array_8188E_FW_WoWLAN, ArrayLength_8188E_FW_WoWLAN); ++ *pFirmwareSize = ArrayLength_8188E_FW_WoWLAN; ++} ++ ++#endif ++ ++#endif // end of DM_ODM_SUPPORT_TYPE & (ODM_AP) ++ ++ ++#endif // end of HWIMG_SUPPORT ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_FW.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_FW.h +new file mode 100644 +index 00000000..b62d5191 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_FW.h +@@ -0,0 +1,65 @@ ++/****************************************************************************** ++* ++* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++* ++* This program is free software; you can redistribute it and/or modify it ++* under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++* ++* ++******************************************************************************/ ++ ++#if (RTL8188E_SUPPORT == 1) ++#ifndef __INC_FW_8188E_HW_IMG_H ++#define __INC_FW_8188E_HW_IMG_H ++ ++ ++/****************************************************************************** ++* FW_AP.TXT ++******************************************************************************/ ++#if(DM_ODM_SUPPORT_TYPE & (ODM_AP)) ++void ++ODM_ReadFirmware_8188E_FW_AP( ++ IN PDM_ODM_T pDM_Odm, ++ OUT u1Byte *pFirmware, ++ OUT u4Byte *pFirmwareSize ++); ++ ++#else ++/****************************************************************************** ++* FW_NIC.TXT ++******************************************************************************/ ++#if 0 ++void ++ODM_ReadFirmware_8188E_FW_NIC( ++ IN PDM_ODM_T pDM_Odm, ++ OUT u1Byte *pFirmware, ++ OUT u4Byte *pFirmwareSize ++); ++#endif ++/****************************************************************************** ++* FW_WoWLAN.TXT ++******************************************************************************/ ++#if 0 ++void ++ODM_ReadFirmware_8188E_FW_WoWLAN( ++ IN PDM_ODM_T pDM_Odm, ++ OUT u1Byte *pFirmware, ++ OUT u4Byte *pFirmwareSize ++); ++#endif ++#define ArrayLength_8188E_FW_WoWLAN 15080 ++extern const u8 Array_8188E_FW_WoWLAN[ArrayLength_8188E_FW_WoWLAN]; ++#endif ++ ++#endif ++#endif // end of HWIMG_SUPPORT +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_MAC.c b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_MAC.c +new file mode 100644 +index 00000000..5483de97 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_MAC.c +@@ -0,0 +1,502 @@ ++/****************************************************************************** ++* ++* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++* ++* This program is free software; you can redistribute it and/or modify it ++* under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++* ++* ++******************************************************************************/ ++ ++#include "../odm_precomp.h" ++#ifdef CONFIG_IOL_IOREG_CFG ++#include ++#endif ++#if (RTL8188E_SUPPORT == 1) ++static BOOLEAN ++CheckCondition( ++ const u4Byte Condition, ++ const u4Byte Hex ++ ) ++{ ++ u4Byte _board = (Hex & 0x000000FF); ++ u4Byte _interface = (Hex & 0x0000FF00) >> 8; ++ u4Byte _platform = (Hex & 0x00FF0000) >> 16; ++ u4Byte cond = Condition; ++ ++ if ( Condition == 0xCDCDCDCD ) ++ return TRUE; ++ ++ cond = Condition & 0x000000FF; ++ if ( (_board != cond) && (cond != 0xFF) ) ++ return FALSE; ++ ++ cond = Condition & 0x0000FF00; ++ cond = cond >> 8; ++ if ( ((_interface & cond) == 0) && (cond != 0x07) ) ++ return FALSE; ++ ++ cond = Condition & 0x00FF0000; ++ cond = cond >> 16; ++ if ( ((_platform & cond) == 0) && (cond != 0x0F) ) ++ return FALSE; ++ return TRUE; ++} ++ ++ ++/****************************************************************************** ++* MAC_REG.TXT ++******************************************************************************/ ++ ++u4Byte Array_MAC_REG_8188E[] = { ++ 0x026, 0x00000041, ++ 0x027, 0x00000035, ++ 0xFF0F0718, 0xABCD, ++ 0x040, 0x0000000C, ++ 0xCDCDCDCD, 0xCDCD, ++ 0x040, 0x00000000, ++ 0xFF0F0718, 0xDEAD, ++ 0x428, 0x0000000A, ++ 0x429, 0x00000010, ++ 0x430, 0x00000000, ++ 0x431, 0x00000001, ++ 0x432, 0x00000002, ++ 0x433, 0x00000004, ++ 0x434, 0x00000005, ++ 0x435, 0x00000006, ++ 0x436, 0x00000007, ++ 0x437, 0x00000008, ++ 0x438, 0x00000000, ++ 0x439, 0x00000000, ++ 0x43A, 0x00000001, ++ 0x43B, 0x00000002, ++ 0x43C, 0x00000004, ++ 0x43D, 0x00000005, ++ 0x43E, 0x00000006, ++ 0x43F, 0x00000007, ++ 0x440, 0x0000005D, ++ 0x441, 0x00000001, ++ 0x442, 0x00000000, ++ 0x444, 0x00000015, ++ 0x445, 0x000000F0, ++ 0x446, 0x0000000F, ++ 0x447, 0x00000000, ++ 0x458, 0x00000041, ++ 0x459, 0x000000A8, ++ 0x45A, 0x00000072, ++ 0x45B, 0x000000B9, ++ 0x460, 0x00000066, ++ 0x461, 0x00000066, ++ 0x480, 0x00000008, ++ 0x4C8, 0x000000FF, ++ 0x4C9, 0x00000008, ++ 0x4CC, 0x000000FF, ++ 0x4CD, 0x000000FF, ++ 0x4CE, 0x00000001, ++ 0x4D3, 0x00000001, ++ 0x500, 0x00000026, ++ 0x501, 0x000000A2, ++ 0x502, 0x0000002F, ++ 0x503, 0x00000000, ++ 0x504, 0x00000028, ++ 0x505, 0x000000A3, ++ 0x506, 0x0000005E, ++ 0x507, 0x00000000, ++ 0x508, 0x0000002B, ++ 0x509, 0x000000A4, ++ 0x50A, 0x0000005E, ++ 0x50B, 0x00000000, ++ 0x50C, 0x0000004F, ++ 0x50D, 0x000000A4, ++ 0x50E, 0x00000000, ++ 0x50F, 0x00000000, ++ 0x512, 0x0000001C, ++ 0x514, 0x0000000A, ++ 0x516, 0x0000000A, ++ 0x525, 0x0000004F, ++ 0x550, 0x00000010, ++ 0x551, 0x00000010, ++ 0x559, 0x00000002, ++ 0x55D, 0x000000FF, ++ 0x605, 0x00000030, ++ 0x608, 0x0000000E, ++ 0x609, 0x0000002A, ++ 0x620, 0x000000FF, ++ 0x621, 0x000000FF, ++ 0x622, 0x000000FF, ++ 0x623, 0x000000FF, ++ 0x624, 0x000000FF, ++ 0x625, 0x000000FF, ++ 0x626, 0x000000FF, ++ 0x627, 0x000000FF, ++ 0x652, 0x00000020, ++ 0x63C, 0x0000000A, ++ 0x63D, 0x0000000A, ++ 0x63E, 0x0000000E, ++ 0x63F, 0x0000000E, ++ 0x640, 0x00000040, ++ 0x66E, 0x00000005, ++ 0x700, 0x00000021, ++ 0x701, 0x00000043, ++ 0x702, 0x00000065, ++ 0x703, 0x00000087, ++ 0x708, 0x00000021, ++ 0x709, 0x00000043, ++ 0x70A, 0x00000065, ++ 0x70B, 0x00000087, ++}; ++ ++HAL_STATUS ++ODM_ReadAndConfig_MAC_REG_8188E( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) ++ ++ u4Byte hex = 0; ++ u4Byte i = 0; ++ u2Byte count = 0; ++ pu4Byte ptr_array = NULL; ++ u1Byte platform = pDM_Odm->SupportPlatform; ++ u1Byte interfaceValue = pDM_Odm->SupportInterface; ++ u1Byte board = pDM_Odm->BoardType; ++ u4Byte ArrayLen = sizeof(Array_MAC_REG_8188E)/sizeof(u4Byte); ++ pu4Byte Array = Array_MAC_REG_8188E; ++ BOOLEAN biol = FALSE; ++ ++#ifdef CONFIG_IOL_IOREG_CFG ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ struct xmit_frame *pxmit_frame; ++ u8 bndy_cnt = 1; ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ struct cmd_cmp cmpdata[ArrayLen]; ++ u4Byte cmpdata_idx=0; ++ #endif ++#endif //CONFIG_IOL_IOREG_CFG ++ HAL_STATUS rst =HAL_STATUS_SUCCESS; ++ hex += board; ++ hex += interfaceValue << 8; ++ hex += platform << 16; ++ hex += 0xFF000000; ++ ++#ifdef CONFIG_IOL_IOREG_CFG ++ biol = rtw_IOL_applied(Adapter); ++ ++ if(biol){ ++ if((pxmit_frame=rtw_IOL_accquire_xmit_frame(Adapter)) == NULL) ++ { ++ printk("rtw_IOL_accquire_xmit_frame failed\n"); ++ return HAL_STATUS_FAILURE; ++ } ++ } ++ ++#endif //CONFIG_IOL_IOREG_CFG ++ ++ for (i = 0; i < ArrayLen; i += 2 ) ++ { ++ u4Byte v1 = Array[i]; ++ u4Byte v2 = Array[i+1]; ++ ++ // This (offset, data) pair meets the condition. ++ if ( v1 < 0xCDCDCDCD ) ++ { ++ #ifdef CONFIG_IOL_IOREG_CFG ++ ++ if(biol){ ++ ++ if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) ++ bndy_cnt++; ++ rtw_IOL_append_WB_cmd(pxmit_frame,(u2Byte)v1, (u1Byte)v2,0xFF); ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ cmpdata[cmpdata_idx].addr = v1; ++ cmpdata[cmpdata_idx].value= v2; ++ cmpdata_idx++; ++ #endif ++ } ++ else ++ #endif //endif CONFIG_IOL_IOREG_CFG ++ { ++ odm_ConfigMAC_8188E(pDM_Odm, v1, (u1Byte)v2); ++ } ++ continue; ++ } ++ else ++ { // This line is the start line of branch. ++ if ( !CheckCondition(Array[i], hex) ) ++ { // Discard the following (offset, data) pairs. ++ READ_NEXT_PAIR(v1, v2, i); ++ while ( v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen -2) ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ i -= 2; // prevent from for-loop += 2 ++ } ++ else // Configure matched pairs and skip to end of if-else. ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ while ( v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen -2) ++ { ++ #ifdef CONFIG_IOL_IOREG_CFG ++ if(biol){ ++ if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) ++ bndy_cnt++; ++ rtw_IOL_append_WB_cmd(pxmit_frame,(u2Byte)v1, (u1Byte)v2,0xFF); ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ cmpdata[cmpdata_idx].addr = v1; ++ cmpdata[cmpdata_idx].value= v2; ++ cmpdata_idx++; ++ #endif ++ } ++ else ++ #endif //#ifdef CONFIG_IOL_IOREG_CFG ++ { ++ odm_ConfigMAC_8188E(pDM_Odm, v1, (u1Byte)v2); ++ } ++ ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ while (v2 != 0xDEAD && i < ArrayLen -2) ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ } ++ } ++ } ++ ++#ifdef CONFIG_IOL_IOREG_CFG ++ if(biol){ ++ //printk("==> %s, pktlen = %d,bndy_cnt = %d\n",__FUNCTION__,pxmit_frame->attrib.pktlen+4+32,bndy_cnt); ++ ++ if(rtw_IOL_exec_cmds_sync(pDM_Odm->Adapter, pxmit_frame, 1000, bndy_cnt)) ++ { ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ printk("~~~ IOL Config MAC Success !!! \n"); ++ //compare writed data ++ { ++ u4Byte idx; ++ u1Byte cdata; ++ // HAL_STATUS_FAILURE; ++ printk(" MAC data compare => array_len:%d \n",cmpdata_idx); ++ for(idx=0;idx< cmpdata_idx;idx++) ++ { ++ cdata = ODM_Read1Byte(pDM_Odm, cmpdata[idx].addr); ++ if(cdata != cmpdata[idx].value){ ++ printk("### MAC data compared failed !! addr:0x%04x, data:(0x%02x : 0x%02x) ###\n", ++ cmpdata[idx].addr,cmpdata[idx].value,cdata); ++ //rst = HAL_STATUS_FAILURE; ++ } ++ } ++ ++ ++ //dump data from TX packet buffer ++ //if(rst == HAL_STATUS_FAILURE) ++ { ++ rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); ++ } ++ ++ } ++ #endif //CONFIG_IOL_IOREG_CFG_DBG ++ ++ } ++ else{ ++ printk("~~~ MAC IOL_exec_cmds Failed !!! \n"); ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ { ++ //dump data from TX packet buffer ++ rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); ++ } ++ #endif //CONFIG_IOL_IOREG_CFG_DBG ++ rst = HAL_STATUS_FAILURE; ++ } ++ ++ } ++#endif //#ifdef CONFIG_IOL_IOREG_CFG ++ return rst; ++} ++ ++/****************************************************************************** ++* MAC_REG_ICUT.TXT ++******************************************************************************/ ++ ++u4Byte Array_MP_8188E_MAC_REG_ICUT[] = { ++ 0x026, 0x00000041, ++ 0x027, 0x00000035, ++ 0x428, 0x0000000A, ++ 0x429, 0x00000010, ++ 0x430, 0x00000000, ++ 0x431, 0x00000001, ++ 0x432, 0x00000002, ++ 0x433, 0x00000004, ++ 0x434, 0x00000005, ++ 0x435, 0x00000006, ++ 0x436, 0x00000007, ++ 0x437, 0x00000008, ++ 0x438, 0x00000000, ++ 0x439, 0x00000000, ++ 0x43A, 0x00000001, ++ 0x43B, 0x00000002, ++ 0x43C, 0x00000004, ++ 0x43D, 0x00000005, ++ 0x43E, 0x00000006, ++ 0x43F, 0x00000007, ++ 0x440, 0x0000005D, ++ 0x441, 0x00000001, ++ 0x442, 0x00000000, ++ 0x444, 0x00000015, ++ 0x445, 0x000000F0, ++ 0x446, 0x0000000F, ++ 0x447, 0x00000000, ++ 0x458, 0x00000041, ++ 0x459, 0x000000A8, ++ 0x45A, 0x00000072, ++ 0x45B, 0x000000B9, ++ 0x460, 0x00000066, ++ 0x461, 0x00000066, ++ 0x480, 0x00000008, ++ 0x4C8, 0x000000FF, ++ 0x4C9, 0x00000008, ++ 0x4CC, 0x000000FF, ++ 0x4CD, 0x000000FF, ++ 0x4CE, 0x00000001, ++ 0x4D3, 0x00000001, ++ 0x500, 0x00000026, ++ 0x501, 0x000000A2, ++ 0x502, 0x0000002F, ++ 0x503, 0x00000000, ++ 0x504, 0x00000028, ++ 0x505, 0x000000A3, ++ 0x506, 0x0000005E, ++ 0x507, 0x00000000, ++ 0x508, 0x0000002B, ++ 0x509, 0x000000A4, ++ 0x50A, 0x0000005E, ++ 0x50B, 0x00000000, ++ 0x50C, 0x0000004F, ++ 0x50D, 0x000000A4, ++ 0x50E, 0x00000000, ++ 0x50F, 0x00000000, ++ 0x512, 0x0000001C, ++ 0x514, 0x0000000A, ++ 0x516, 0x0000000A, ++ 0x525, 0x0000004F, ++ 0x550, 0x00000010, ++ 0x551, 0x00000010, ++ 0x559, 0x00000002, ++ 0x55D, 0x000000FF, ++ 0x605, 0x00000030, ++ 0x608, 0x0000000E, ++ 0x609, 0x0000002A, ++ 0x620, 0x000000FF, ++ 0x621, 0x000000FF, ++ 0x622, 0x000000FF, ++ 0x623, 0x000000FF, ++ 0x624, 0x000000FF, ++ 0x625, 0x000000FF, ++ 0x626, 0x000000FF, ++ 0x627, 0x000000FF, ++ 0x652, 0x00000020, ++ 0x63C, 0x0000000A, ++ 0x63D, 0x0000000A, ++ 0x63E, 0x0000000E, ++ 0x63F, 0x0000000E, ++ 0x640, 0x00000040, ++ 0x66E, 0x00000005, ++ 0x700, 0x00000021, ++ 0x701, 0x00000043, ++ 0x702, 0x00000065, ++ 0x703, 0x00000087, ++ 0x708, 0x00000021, ++ 0x709, 0x00000043, ++ 0x70A, 0x00000065, ++ 0x70B, 0x00000087, ++ ++}; ++ ++void ++ODM_ReadAndConfig_MAC_REG_ICUT_8188E( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) ++ ++ u4Byte hex = 0; ++ u4Byte i = 0; ++ u2Byte count = 0; ++ pu4Byte ptr_array = NULL; ++ u1Byte platform = pDM_Odm->SupportPlatform; ++ u1Byte _interface = pDM_Odm->SupportInterface; ++ u1Byte board = pDM_Odm->BoardType; ++ u4Byte ArrayLen = sizeof(Array_MP_8188E_MAC_REG_ICUT)/sizeof(u4Byte); ++ pu4Byte Array = Array_MP_8188E_MAC_REG_ICUT; ++ ++ ++ hex += board; ++ hex += _interface << 8; ++ hex += platform << 16; ++ hex += 0xFF000000; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ReadAndConfig_MP_8188E_MAC_REG_ICUT, hex = 0x%X\n", hex)); ++ ++ for (i = 0; i < ArrayLen; i += 2 ) ++ { ++ u4Byte v1 = Array[i]; ++ u4Byte v2 = Array[i+1]; ++ ++ // This (offset, data) pair meets the condition. ++ if ( v1 < 0xCDCDCDCD ) ++ { ++ odm_ConfigMAC_8188E(pDM_Odm, v1, (u1Byte)v2); ++ continue; ++ } ++ else ++ { // This line is the start line of branch. ++ if ( !CheckCondition(Array[i], hex) ) ++ { // Discard the following (offset, data) pairs. ++ READ_NEXT_PAIR(v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen -2) ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ i -= 2; // prevent from for-loop += 2 ++ } ++ else // Configure matched pairs and skip to end of if-else. ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen -2) ++ { ++ odm_ConfigMAC_8188E(pDM_Odm, v1, (u1Byte)v2); ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ while (v2 != 0xDEAD && i < ArrayLen -2) ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ } ++ } ++ } ++ ++} ++ ++#endif // end of HWIMG_SUPPORT ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_MAC.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_MAC.h +new file mode 100644 +index 00000000..f2c2e475 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_MAC.h +@@ -0,0 +1,47 @@ ++/****************************************************************************** ++* ++* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++* ++* This program is free software; you can redistribute it and/or modify it ++* under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++* ++* ++******************************************************************************/ ++ ++#if (RTL8188E_SUPPORT == 1) ++#ifndef __INC_MAC_8188E_HW_IMG_H ++#define __INC_MAC_8188E_HW_IMG_H ++ ++//static BOOLEAN CheckCondition(const u4Byte Condition, const u4Byte Hex); ++ ++/****************************************************************************** ++* MAC_REG.TXT ++******************************************************************************/ ++ ++HAL_STATUS ++ODM_ReadAndConfig_MAC_REG_8188E( ++ IN PDM_ODM_T pDM_Odm ++); ++ ++/****************************************************************************** ++* MAC_REG_ICUT.TXT ++******************************************************************************/ ++ ++void ++ODM_ReadAndConfig_MAC_REG_ICUT_8188E( // TC: Test Chip, MP: MP Chip ++ IN PDM_ODM_T pDM_Odm ++); ++ ++#endif ++#endif // end of HWIMG_SUPPORT ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_RF.c b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_RF.c +new file mode 100644 +index 00000000..3941ec2e +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_RF.c +@@ -0,0 +1,569 @@ ++/****************************************************************************** ++* ++* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++* ++* This program is free software; you can redistribute it and/or modify it ++* under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++* ++* ++******************************************************************************/ ++ ++#include "../odm_precomp.h" ++ ++#ifdef CONFIG_IOL_IOREG_CFG ++#include ++#endif ++ ++#if (RTL8188E_SUPPORT == 1) ++static BOOLEAN ++CheckCondition( ++ const u4Byte Condition, ++ const u4Byte Hex ++ ) ++{ ++ u4Byte _board = (Hex & 0x000000FF); ++ u4Byte _interface = (Hex & 0x0000FF00) >> 8; ++ u4Byte _platform = (Hex & 0x00FF0000) >> 16; ++ u4Byte cond = Condition; ++ ++ if ( Condition == 0xCDCDCDCD ) ++ return TRUE; ++ ++ cond = Condition & 0x000000FF; ++ if ( (_board != cond) && (cond != 0xFF) ) ++ return FALSE; ++ ++ cond = Condition & 0x0000FF00; ++ cond = cond >> 8; ++ if ( ((_interface & cond) == 0) && (cond != 0x07) ) ++ return FALSE; ++ ++ cond = Condition & 0x00FF0000; ++ cond = cond >> 16; ++ if ( ((_platform & cond) == 0) && (cond != 0x0F) ) ++ return FALSE; ++ return TRUE; ++} ++ ++ ++/****************************************************************************** ++* RadioA_1T.TXT ++******************************************************************************/ ++ ++u4Byte Array_RadioA_1T_8188E[] = { ++ 0x000, 0x00030000, ++ 0x008, 0x00084000, ++ 0x018, 0x00000407, ++ 0x019, 0x00000012, ++ 0x01E, 0x00080009, ++ 0x01F, 0x00000880, ++ 0x02F, 0x0001A060, ++ 0x03F, 0x00000000, ++ 0x042, 0x000060C0, ++ 0x057, 0x000D0000, ++ 0x058, 0x000BE180, ++ 0x067, 0x00001552, ++ 0x083, 0x00000000, ++ 0x0B0, 0x000FF8FC, ++ 0x0B1, 0x00054400, ++ 0x0B2, 0x000CCC19, ++ 0x0B4, 0x00043003, ++ 0x0B6, 0x0004953E, ++ 0x0B7, 0x0001C718, ++ 0x0B8, 0x000060FF, ++ 0x0B9, 0x00080001, ++ 0x0BA, 0x00040000, ++ 0x0BB, 0x00000400, ++ 0x0BF, 0x000C0000, ++ 0x0C2, 0x00002400, ++ 0x0C3, 0x00000009, ++ 0x0C4, 0x00040C91, ++ 0x0C5, 0x00099999, ++ 0x0C6, 0x000000A3, ++ 0x0C7, 0x00088820, ++ 0x0C8, 0x00076C06, ++ 0x0C9, 0x00000000, ++ 0x0CA, 0x00080000, ++ 0x0DF, 0x00000180, ++ 0x0EF, 0x000001A0, ++ 0x051, 0x0006B27D, ++ 0xFF0F0400, 0xABCD, ++ 0x052, 0x0007E4DD, ++ 0xCDCDCDCD, 0xCDCD, ++ 0x052, 0x0007E49D, ++ 0xFF0F0400, 0xDEAD, ++ 0x053, 0x00000073, ++ 0x056, 0x00051FF3, ++ 0x035, 0x00000086, ++ 0x035, 0x00000186, ++ 0x035, 0x00000286, ++ 0x036, 0x00001C25, ++ 0x036, 0x00009C25, ++ 0x036, 0x00011C25, ++ 0x036, 0x00019C25, ++ 0x0B6, 0x00048538, ++ 0x018, 0x00000C07, ++ 0x05A, 0x0004BD00, ++ 0x019, 0x000739D0, ++ 0xFF0F0718, 0xABCD, ++ 0x034, 0x0000A093, ++ 0x034, 0x0000908F, ++ 0x034, 0x0000808C, ++ 0x034, 0x0000704F, ++ 0x034, 0x0000604C, ++ 0x034, 0x00005049, ++ 0x034, 0x0000400C, ++ 0x034, 0x00003009, ++ 0x034, 0x00002006, ++ 0x034, 0x00001003, ++ 0x034, 0x00000000, ++ 0xCDCDCDCD, 0xCDCD, ++ 0x034, 0x0000ADF3, ++ 0x034, 0x00009DF0, ++ 0x034, 0x00008DED, ++ 0x034, 0x00007DEA, ++ 0x034, 0x00006DE7, ++ 0x034, 0x000054EE, ++ 0x034, 0x000044EB, ++ 0x034, 0x000034E8, ++ 0x034, 0x0000246B, ++ 0x034, 0x00001468, ++ 0x034, 0x0000006D, ++ 0xFF0F0718, 0xDEAD, ++ 0x000, 0x00030159, ++ 0x084, 0x00068200, ++ 0x086, 0x000000CE, ++ 0x087, 0x00048A00, ++ 0x08E, 0x00065540, ++ 0x08F, 0x00088000, ++ 0x0EF, 0x000020A0, ++ 0x03B, 0x000F02B0, ++ 0x03B, 0x000EF7B0, ++ 0x03B, 0x000D4FB0, ++ 0x03B, 0x000CF060, ++ 0x03B, 0x000B0090, ++ 0x03B, 0x000A0080, ++ 0x03B, 0x00090080, ++ 0x03B, 0x0008F780, ++ 0x03B, 0x000722B0, ++ 0x03B, 0x0006F7B0, ++ 0x03B, 0x00054FB0, ++ 0x03B, 0x0004F060, ++ 0x03B, 0x00030090, ++ 0x03B, 0x00020080, ++ 0x03B, 0x00010080, ++ 0x03B, 0x0000F780, ++ 0x0EF, 0x000000A0, ++ 0x000, 0x00010159, ++ 0x018, 0x0000F407, ++ 0xFFE, 0x00000000, ++ 0xFFE, 0x00000000, ++ 0x01F, 0x00080003, ++ 0xFFE, 0x00000000, ++ 0xFFE, 0x00000000, ++ 0x01E, 0x00000001, ++ 0x01F, 0x00080000, ++ 0x000, 0x00033E60, ++ ++}; ++ ++HAL_STATUS ++ODM_ReadAndConfig_RadioA_1T_8188E( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) ++ ++ u4Byte hex = 0; ++ u4Byte i = 0; ++ u2Byte count = 0; ++ pu4Byte ptr_array = NULL; ++ u1Byte platform = pDM_Odm->SupportPlatform; ++ u1Byte interfaceValue = pDM_Odm->SupportInterface; ++ u1Byte board = pDM_Odm->BoardType; ++ u4Byte ArrayLen = sizeof(Array_RadioA_1T_8188E)/sizeof(u4Byte); ++ pu4Byte Array = Array_RadioA_1T_8188E; ++ BOOLEAN biol = FALSE; ++#ifdef CONFIG_IOL_IOREG_CFG ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ struct xmit_frame *pxmit_frame; ++ u8 bndy_cnt = 1; ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ struct cmd_cmp cmpdata[ArrayLen]; ++ u4Byte cmpdata_idx=0; ++ #endif ++#endif//#ifdef CONFIG_IOL_IOREG_CFG ++ HAL_STATUS rst =HAL_STATUS_SUCCESS; ++ ++ hex += board; ++ hex += interfaceValue << 8; ++ hex += platform << 16; ++ hex += 0xFF000000; ++#ifdef CONFIG_IOL_IOREG_CFG ++ biol = rtw_IOL_applied(Adapter); ++ ++ if(biol){ ++ if((pxmit_frame=rtw_IOL_accquire_xmit_frame(Adapter)) == NULL) ++ { ++ printk("rtw_IOL_accquire_xmit_frame failed\n"); ++ return HAL_STATUS_FAILURE; ++ } ++ } ++#endif//#ifdef CONFIG_IOL_IOREG_CFG ++ ++ for (i = 0; i < ArrayLen; i += 2 ) ++ { ++ u4Byte v1 = Array[i]; ++ u4Byte v2 = Array[i+1]; ++ ++ // This (offset, data) pair meets the condition. ++ if ( v1 < 0xCDCDCDCD ) ++ { ++ #ifdef CONFIG_IOL_IOREG_CFG ++ if(biol){ ++ if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) ++ bndy_cnt++; ++ ++ if(v1 == 0xffe) ++ { ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,50); ++ } ++ else if (v1 == 0xfd){ ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,5); ++ } ++ else if (v1 == 0xfc){ ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,1); ++ } ++ else if (v1 == 0xfb){ ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame,50); ++ } ++ else if (v1 == 0xfa){ ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame,5); ++ } ++ else if (v1 == 0xf9){ ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame,1); ++ } ++ else{ ++ rtw_IOL_append_WRF_cmd(pxmit_frame, ODM_RF_PATH_A,(u2Byte)v1, v2,bRFRegOffsetMask) ; ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ cmpdata[cmpdata_idx].addr = v1; ++ cmpdata[cmpdata_idx].value= v2; ++ cmpdata_idx++; ++ #endif ++ } ++ ++ } ++ else ++ #endif //#ifdef CONFIG_IOL_IOREG_CFG ++ { ++ odm_ConfigRF_RadioA_8188E(pDM_Odm, v1, v2); ++ } ++ continue; ++ } ++ else ++ { // This line is the start line of branch. ++ if ( !CheckCondition(Array[i], hex) ) ++ { // Discard the following (offset, data) pairs. ++ READ_NEXT_PAIR(v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen -2) ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ i -= 2; // prevent from for-loop += 2 ++ } ++ else // Configure matched pairs and skip to end of if-else. ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen -2) ++ { ++ #ifdef CONFIG_IOL_IOREG_CFG ++ if(biol){ ++ if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) ++ bndy_cnt++; ++ ++ if(v1 == 0xffe) ++ { ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,50); ++ } ++ else if (v1 == 0xfd){ ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,5); ++ } ++ else if (v1 == 0xfc){ ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,1); ++ } ++ else if (v1 == 0xfb){ ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame,50); ++ } ++ else if (v1 == 0xfa){ ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame,5); ++ } ++ else if (v1 == 0xf9){ ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame,1); ++ } ++ else{ ++ rtw_IOL_append_WRF_cmd(pxmit_frame, ODM_RF_PATH_A,(u2Byte)v1, v2,bRFRegOffsetMask) ; ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ cmpdata[cmpdata_idx].addr = v1; ++ cmpdata[cmpdata_idx].value= v2; ++ cmpdata_idx++; ++ #endif ++ ++ } ++ ++ } ++ else ++ #endif //#ifdef CONFIG_IOL_IOREG_CFG ++ { ++ odm_ConfigRF_RadioA_8188E(pDM_Odm, v1, v2); ++ } ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ while (v2 != 0xDEAD && i < ArrayLen -2) ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ } ++ } ++ } ++#ifdef CONFIG_IOL_IOREG_CFG ++ if(biol){ ++ //printk("==> %s, pktlen = %d,bndy_cnt = %d\n",__FUNCTION__,pxmit_frame->attrib.pktlen+4+32,bndy_cnt); ++ if(rtw_IOL_exec_cmds_sync(pDM_Odm->Adapter, pxmit_frame, 1000, bndy_cnt)) ++ { ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ printk("~~~ %s Success !!! \n",__FUNCTION__); ++ { ++ u4Byte idx; ++ u4Byte cdata; ++ printk(" %s data compare => array_len:%d \n",__FUNCTION__,cmpdata_idx); ++ printk("### %s data compared !!###\n",__FUNCTION__); ++ for(idx=0;idx< cmpdata_idx;idx++) ++ { ++ cdata = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A,cmpdata[idx].addr,bRFRegOffsetMask); ++ if(cdata != cmpdata[idx].value){ ++ printk("addr:0x%04x, data:(0x%02x : 0x%02x) \n", ++ cmpdata[idx].addr,cmpdata[idx].value,cdata); ++ rst = HAL_STATUS_FAILURE; ++ } ++ } ++ printk("### %s data compared !!###\n",__FUNCTION__); ++ //if(rst == HAL_STATUS_FAILURE) ++ {//dump data from TX packet buffer ++ rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); ++ } ++ } ++ #endif //CONFIG_IOL_IOREG_CFG_DBG ++ ++ } ++ else{ ++ rst = HAL_STATUS_FAILURE; ++ printk("~~~ IOL Config %s Failed !!! \n",__FUNCTION__); ++ #ifdef CONFIG_IOL_IOREG_CFG_DBG ++ { ++ //dump data from TX packet buffer ++ rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); ++ } ++ #endif //CONFIG_IOL_IOREG_CFG_DBG ++ } ++ } ++ ++ ++#endif //#ifdef CONFIG_IOL_IOREG_CFG ++ return rst; ++} ++/****************************************************************************** ++* RadioA_1T_ICUT.TXT ++******************************************************************************/ ++ ++u4Byte Array_MP_8188E_RadioA_1T_ICUT[] = { ++ 0x000, 0x00030000, ++ 0x008, 0x00084000, ++ 0x018, 0x00000407, ++ 0x019, 0x00000012, ++ 0x01E, 0x00080009, ++ 0x01F, 0x00000880, ++ 0x02F, 0x0001A060, ++ 0x03F, 0x00000000, ++ 0x042, 0x000060C0, ++ 0x057, 0x000D0000, ++ 0x058, 0x000BE180, ++ 0x067, 0x00001552, ++ 0x083, 0x00000000, ++ 0x0B0, 0x000FF8FC, ++ 0x0B1, 0x00054400, ++ 0x0B2, 0x000CCC19, ++ 0x0B4, 0x00043003, ++ 0x0B6, 0x0004953E, ++ 0x0B7, 0x0001C718, ++ 0x0B8, 0x000060FF, ++ 0x0B9, 0x00080001, ++ 0x0BA, 0x00040000, ++ 0x0BB, 0x00000400, ++ 0x0BF, 0x000C0000, ++ 0x0C2, 0x00002400, ++ 0x0C3, 0x00000009, ++ 0x0C4, 0x00040C91, ++ 0x0C5, 0x00099999, ++ 0x0C6, 0x000000A3, ++ 0x0C7, 0x00088820, ++ 0x0C8, 0x00076C06, ++ 0x0C9, 0x00000000, ++ 0x0CA, 0x00080000, ++ 0x0DF, 0x00000180, ++ 0x0EF, 0x000001A0, ++ 0x051, 0x0006B27D, ++ 0xFF0F0400, 0xABCD, ++ 0x052, 0x0007E4DD, ++ 0xCDCDCDCD, 0xCDCD, ++ 0x052, 0x0007E49D, ++ 0xFF0F0400, 0xDEAD, ++ 0x053, 0x00000073, ++ 0x056, 0x00051FF3, ++ 0x035, 0x00000086, ++ 0x035, 0x00000186, ++ 0x035, 0x00000286, ++ 0x036, 0x00001C25, ++ 0x036, 0x00009C25, ++ 0x036, 0x00011C25, ++ 0x036, 0x00019C25, ++ 0x0B6, 0x00048538, ++ 0x018, 0x00000C07, ++ 0x05A, 0x0004BD00, ++ 0x019, 0x000739D0, ++ 0x034, 0x0000ADF3, ++ 0x034, 0x00009DF0, ++ 0x034, 0x00008DED, ++ 0x034, 0x00007DEA, ++ 0x034, 0x00006DE7, ++ 0x034, 0x000054EE, ++ 0x034, 0x000044EB, ++ 0x034, 0x000034E8, ++ 0x034, 0x0000246B, ++ 0x034, 0x00001468, ++ 0x034, 0x0000006D, ++ 0x000, 0x00030159, ++ 0x084, 0x00068200, ++ 0x086, 0x000000CE, ++ 0x087, 0x00048A00, ++ 0x08E, 0x00065540, ++ 0x08F, 0x00088000, ++ 0x0EF, 0x000020A0, ++ 0x03B, 0x000F02B0, ++ 0x03B, 0x000EF7B0, ++ 0x03B, 0x000D4FB0, ++ 0x03B, 0x000CF060, ++ 0x03B, 0x000B0090, ++ 0x03B, 0x000A0080, ++ 0x03B, 0x00090080, ++ 0x03B, 0x0008F780, ++ 0x03B, 0x000722B0, ++ 0x03B, 0x0006F7B0, ++ 0x03B, 0x00054FB0, ++ 0x03B, 0x0004F060, ++ 0x03B, 0x00030090, ++ 0x03B, 0x00020080, ++ 0x03B, 0x00010080, ++ 0x03B, 0x0000F780, ++ 0x0EF, 0x000000A0, ++ 0x000, 0x00010159, ++ 0x018, 0x0000F407, ++ 0xFFE, 0x00000000, ++ 0xFFE, 0x00000000, ++ 0x01F, 0x00080003, ++ 0xFFE, 0x00000000, ++ 0xFFE, 0x00000000, ++ 0x01E, 0x00000001, ++ 0x01F, 0x00080000, ++ 0x000, 0x00033E60, ++ ++}; ++ ++void ++ODM_ReadAndConfig_RadioA_1T_ICUT_8188E( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) ++ ++ u4Byte hex = 0; ++ u4Byte i = 0; ++ u2Byte count = 0; ++ pu4Byte ptr_array = NULL; ++ u1Byte platform = pDM_Odm->SupportPlatform; ++ u1Byte _interface = pDM_Odm->SupportInterface; ++ u1Byte board = pDM_Odm->BoardType; ++ u4Byte ArrayLen = sizeof(Array_MP_8188E_RadioA_1T_ICUT)/sizeof(u4Byte); ++ pu4Byte Array = Array_MP_8188E_RadioA_1T_ICUT; ++ ++ ++ hex += board; ++ hex += _interface << 8; ++ hex += platform << 16; ++ hex += 0xFF000000; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ReadAndConfig_MP_8188E_RadioA_1T_ICUT, hex = 0x%X\n", hex)); ++ ++ for (i = 0; i < ArrayLen; i += 2 ) ++ { ++ u4Byte v1 = Array[i]; ++ u4Byte v2 = Array[i+1]; ++ ++ // This (offset, data) pair meets the condition. ++ if ( v1 < 0xCDCDCDCD ) ++ { ++ odm_ConfigRF_RadioA_8188E(pDM_Odm, v1, v2); ++ continue; ++ } ++ else ++ { // This line is the start line of branch. ++ if ( !CheckCondition(Array[i], hex) ) ++ { // Discard the following (offset, data) pairs. ++ READ_NEXT_PAIR(v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen -2) ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ i -= 2; // prevent from for-loop += 2 ++ } ++ else // Configure matched pairs and skip to end of if-else. ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen -2) ++ { ++ odm_ConfigRF_RadioA_8188E(pDM_Odm, v1, v2); ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ while (v2 != 0xDEAD && i < ArrayLen -2) ++ { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ } ++ } ++ } ++ ++} ++ ++ ++#endif // end of HWIMG_SUPPORT ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_RF.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_RF.h +new file mode 100644 +index 00000000..46a029fc +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalHWImg8188E_RF.h +@@ -0,0 +1,45 @@ ++/****************************************************************************** ++* ++* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++* ++* This program is free software; you can redistribute it and/or modify it ++* under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++* ++* ++******************************************************************************/ ++ ++#if (RTL8188E_SUPPORT == 1) ++#ifndef __INC_RF_8188E_HW_IMG_H ++#define __INC_RF_8188E_HW_IMG_H ++ ++//static BOOLEAN CheckCondition(const u4Byte Condition, const u4Byte Hex); ++ ++/****************************************************************************** ++* RadioA_1T.TXT ++******************************************************************************/ ++ ++HAL_STATUS ++ODM_ReadAndConfig_RadioA_1T_8188E( ++ IN PDM_ODM_T pDM_Odm ++); ++/****************************************************************************** ++* RadioA_1T_ICUT.TXT ++******************************************************************************/ ++ ++void ++ODM_ReadAndConfig_RadioA_1T_ICUT_8188E( // TC: Test Chip, MP: MP Chip ++ IN PDM_ODM_T pDM_Odm ++); ++#endif ++#endif // end of HWIMG_SUPPORT ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalPhyRf_8188e.c b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalPhyRf_8188e.c +new file mode 100644 +index 00000000..9817b7b6 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalPhyRf_8188e.c +@@ -0,0 +1,3468 @@ ++ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#include "../odm_precomp.h" ++ ++ ++ ++/*---------------------------Define Local Constant---------------------------*/ ++// 2010/04/25 MH Define the max tx power tracking tx agc power. ++#define ODM_TXPWRTRACK_MAX_IDX_88E 6 ++ ++#define CALCULATE_SWINGTALBE_OFFSET(_offset, _direction, _size, _deltaThermal) \ ++ do {\ ++ for(_offset = 0; _offset < _size; _offset++)\ ++ {\ ++ if(_deltaThermal < thermalThreshold[_direction][_offset])\ ++ {\ ++ if(_offset != 0)\ ++ _offset--;\ ++ break;\ ++ }\ ++ } \ ++ if(_offset >= _size)\ ++ _offset = _size-1;\ ++ } while(0) ++ ++//3============================================================ ++//3 Tx Power Tracking ++//3============================================================ ++void setIqkMatrix( ++ PDM_ODM_T pDM_Odm, ++ u1Byte OFDM_index, ++ u1Byte RFPath, ++ s4Byte IqkResult_X, ++ s4Byte IqkResult_Y ++ ) ++{ ++ s4Byte ele_A=0, ele_D, ele_C=0, TempCCk, value32; ++ ++ //printk("%s==> OFDM_index:%d \n",__FUNCTION__,OFDM_index); ++ ++ //if(OFDM_index> OFDM_TABLE_SIZE_92D) ++ //{ ++ //printk("%s==> OFDM_index> 43\n",__FUNCTION__); ++ //} ++ ele_D = (OFDMSwingTable[OFDM_index] & 0xFFC00000)>>22; ++ ++ //new element A = element D x X ++ if((IqkResult_X != 0) && (*(pDM_Odm->pBandType) == ODM_BAND_2_4G)) ++ { ++ if ((IqkResult_X & 0x00000200) != 0) //consider minus ++ IqkResult_X = IqkResult_X | 0xFFFFFC00; ++ ele_A = ((IqkResult_X * ele_D)>>8)&0x000003FF; ++ ++ //new element C = element D x Y ++ if ((IqkResult_Y & 0x00000200) != 0) ++ IqkResult_Y = IqkResult_Y | 0xFFFFFC00; ++ ele_C = ((IqkResult_Y * ele_D)>>8)&0x000003FF; ++ ++ if (RFPath == RF_PATH_A) ++ switch (RFPath) ++ { ++ case RF_PATH_A: ++ //wirte new elements A, C, D to regC80 and regC94, element B is always 0 ++ value32 = (ele_D<<22)|((ele_C&0x3F)<<16)|ele_A; ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XATxIQImbalance, bMaskDWord, value32); ++ ++ value32 = (ele_C&0x000003C0)>>6; ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XCTxAFE, bMaskH4Bits, value32); ++ ++ value32 = ((IqkResult_X * ele_D)>>7)&0x01; ++ ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, BIT24, value32); ++ break; ++ case RF_PATH_B: ++ //wirte new elements A, C, D to regC88 and regC9C, element B is always 0 ++ value32=(ele_D<<22)|((ele_C&0x3F)<<16) |ele_A; ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XBTxIQImbalance, bMaskDWord, value32); ++ ++ value32 = (ele_C&0x000003C0)>>6; ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XDTxAFE, bMaskH4Bits, value32); ++ ++ value32 = ((IqkResult_X * ele_D)>>7)&0x01; ++ ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, BIT28, value32); ++ ++ break; ++ default: ++ break; ++ } ++ } ++ else ++ { ++ switch (RFPath) ++ { ++ case RF_PATH_A: ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XATxIQImbalance, bMaskDWord, OFDMSwingTable[OFDM_index]); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XCTxAFE, bMaskH4Bits, 0x00); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, BIT24, 0x00); ++ break; ++ ++ case RF_PATH_B: ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XBTxIQImbalance, bMaskDWord, OFDMSwingTable[OFDM_index]); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XDTxAFE, bMaskH4Bits, 0x00); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, BIT28, 0x00); ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("TxPwrTracking path B: X = 0x%x, Y = 0x%x ele_A = 0x%x ele_C = 0x%x ele_D = 0x%x 0xeb4 = 0x%x 0xebc = 0x%x\n", ++ (u4Byte)IqkResult_X, (u4Byte)IqkResult_Y, (u4Byte)ele_A, (u4Byte)ele_C, (u4Byte)ele_D, (u4Byte)IqkResult_X, (u4Byte)IqkResult_Y)); ++} ++ ++ ++void doIQK( ++ PDM_ODM_T pDM_Odm, ++ u1Byte DeltaThermalIndex, ++ u1Byte ThermalValue, ++ u1Byte Threshold ++ ) ++{ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++#endif ++ ++ ODM_ResetIQKResult(pDM_Odm); ++ ++#if(DM_ODM_SUPPORT_TYPE & ODM_MP) ++#if (DEV_BUS_TYPE == RT_PCI_INTERFACE) ++#if USE_WORKITEM ++ PlatformAcquireMutex(&pHalData->mxChnlBwControl); ++#else ++ PlatformAcquireSpinLock(Adapter, RT_CHANNEL_AND_BANDWIDTH_SPINLOCK); ++#endif ++#elif((DEV_BUS_TYPE == RT_USB_INTERFACE) || (DEV_BUS_TYPE == RT_SDIO_INTERFACE)) ++ PlatformAcquireMutex(&pHalData->mxChnlBwControl); ++#endif ++#endif ++ ++ ++ pDM_Odm->RFCalibrateInfo.ThermalValue_IQK= ThermalValue; ++ PHY_IQCalibrate_8188E(Adapter, FALSE); ++ ++ ++#if(DM_ODM_SUPPORT_TYPE & ODM_MP) ++#if (DEV_BUS_TYPE == RT_PCI_INTERFACE) ++#if USE_WORKITEM ++ PlatformReleaseMutex(&pHalData->mxChnlBwControl); ++#else ++ PlatformReleaseSpinLock(Adapter, RT_CHANNEL_AND_BANDWIDTH_SPINLOCK); ++#endif ++#elif((DEV_BUS_TYPE == RT_USB_INTERFACE) || (DEV_BUS_TYPE == RT_SDIO_INTERFACE)) ++ PlatformReleaseMutex(&pHalData->mxChnlBwControl); ++#endif ++#endif ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: ODM_TxPwrTrackAdjust88E() ++ * ++ * Overview: 88E we can not write 0xc80/c94/c4c/ 0xa2x. Instead of write TX agc. ++ * No matter OFDM & CCK use the same method. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 04/23/2012 MHC Create Version 0. ++ * 04/23/2012 MHC Adjust TX agc directly not throughput BB digital. ++ * ++ *---------------------------------------------------------------------------*/ ++VOID ++ODM_TxPwrTrackAdjust88E( ++ PDM_ODM_T pDM_Odm, ++ u1Byte Type, // 0 = OFDM, 1 = CCK ++ pu1Byte pDirection, // 1 = +(increase) 2 = -(decrease) ++ pu4Byte pOutWriteVal // Tx tracking CCK/OFDM BB swing index adjust ++ ) ++{ ++ u1Byte pwr_value = 0; ++ // ++ // Tx power tracking BB swing table. ++ // The base index = 12. +((12-n)/2)dB 13~?? = decrease tx pwr by -((n-12)/2)dB ++ // ++ if (Type == 0) // For OFDM afjust ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("BbSwingIdxOfdm = %d BbSwingFlagOfdm=%d\n", pDM_Odm->BbSwingIdxOfdm, pDM_Odm->BbSwingFlagOfdm)); ++ ++ //printk("BbSwingIdxOfdm = %d BbSwingFlagOfdm=%d\n", pDM_Odm->BbSwingIdxOfdm, pDM_Odm->BbSwingFlagOfdm); ++ if (pDM_Odm->BbSwingIdxOfdm <= pDM_Odm->BbSwingIdxOfdmBase) ++ { ++ *pDirection = 1; ++ pwr_value = (pDM_Odm->BbSwingIdxOfdmBase - pDM_Odm->BbSwingIdxOfdm); ++ } ++ else ++ { ++ *pDirection = 2; ++ pwr_value = (pDM_Odm->BbSwingIdxOfdm - pDM_Odm->BbSwingIdxOfdmBase); ++ } ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("BbSwingIdxOfdm = %d BbSwingIdxOfdmBase=%d\n", pDM_Odm->BbSwingIdxOfdm, pDM_Odm->BbSwingIdxOfdmBase)); ++ //printk("BbSwingIdxOfdm = %d BbSwingIdxOfdmBase=%d pwr_value=%d\n", pDM_Odm->BbSwingIdxOfdm, pDM_Odm->BbSwingIdxOfdmBase,pwr_value); ++ ++ } ++ else if (Type == 1) // For CCK adjust. ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("pDM_Odm->BbSwingIdxCck = %d pDM_Odm->BbSwingIdxCckBase = %d\n", pDM_Odm->BbSwingIdxCck, pDM_Odm->BbSwingIdxCckBase)); ++ ++ //printk("pDM_Odm->BbSwingIdxCck = %d pDM_Odm->BbSwingIdxCckBase = %d\n", pDM_Odm->BbSwingIdxCck, pDM_Odm->BbSwingIdxCckBase); ++ if (pDM_Odm->BbSwingIdxCck <= pDM_Odm->BbSwingIdxCckBase) ++ { ++ *pDirection = 1; ++ pwr_value = (pDM_Odm->BbSwingIdxCckBase - pDM_Odm->BbSwingIdxCck); ++ } ++ else ++ { ++ *pDirection = 2; ++ pwr_value = (pDM_Odm->BbSwingIdxCck - pDM_Odm->BbSwingIdxCckBase); ++ } ++ //printk("pDM_Odm->BbSwingIdxCck = %d pDM_Odm->BbSwingIdxCckBase = %d pwr_value:%d\n", pDM_Odm->BbSwingIdxCck, pDM_Odm->BbSwingIdxCckBase,pwr_value); ++ } ++ ++ // ++ // 2012/04/25 MH According to Ed/Luke.Lees estimate for EVM the max tx power tracking ++ // need to be less than 6 power index for 88E. ++ // ++ if (pwr_value >= ODM_TXPWRTRACK_MAX_IDX_88E && *pDirection == 1) ++ pwr_value = ODM_TXPWRTRACK_MAX_IDX_88E; ++ ++ *pOutWriteVal = pwr_value | (pwr_value<<8) | (pwr_value<<16) | (pwr_value<<24); ++ ++} // ODM_TxPwrTrackAdjust88E ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: odm_TxPwrTrackSetPwr88E() ++ * ++ * Overview: 88E change all channel tx power accordign to flag. ++ * OFDM & CCK are all different. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 04/23/2012 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++VOID ++odm_TxPwrTrackSetPwr88E( ++ PDM_ODM_T pDM_Odm, ++ PWRTRACK_METHOD Method, ++ u1Byte RFPath, ++ u1Byte ChannelMappedIndex ++ ) ++{ ++ if (Method == TXAGC) ++ { ++ u1Byte cckPowerLevel[MAX_TX_COUNT], ofdmPowerLevel[MAX_TX_COUNT]; ++ u1Byte BW20PowerLevel[MAX_TX_COUNT], BW40PowerLevel[MAX_TX_COUNT]; ++ u1Byte rf = 0; ++ u4Byte pwr = 0, TxAGC = 0; ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ //printk("odm_TxPwrTrackSetPwr88E CH=%d, modify TXAGC \n", *(pDM_Odm->pChannel)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("odm_TxPwrTrackSetPwr88E CH=%d\n", *(pDM_Odm->pChannel))); ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE )) ++ ++ //#if (MP_DRIVER != 1) ++ if ( *(pDM_Odm->mp_mode) != 1){ ++ PHY_SetTxPowerLevel8188E(pDM_Odm->Adapter, *pDM_Odm->pChannel); ++ } ++ else ++ //#else ++ { ++ pwr = PHY_QueryBBReg(Adapter, rTxAGC_A_Rate18_06, 0xFF); ++ pwr += (pDM_Odm->BbSwingIdxCck - pDM_Odm->BbSwingIdxCckBase); ++ PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, pwr); ++ TxAGC = (pwr<<16)|(pwr<<8)|(pwr); ++ PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, TxAGC); ++ DBG_871X("ODM_TxPwrTrackSetPwr88E: CCK Tx-rf(A) Power = 0x%x\n", TxAGC); ++ ++ pwr = PHY_QueryBBReg(Adapter, rTxAGC_A_Rate18_06, 0xFF); ++ pwr += (pDM_Odm->BbSwingIdxOfdm - pDM_Odm->BbSwingIdxOfdmBase); ++ TxAGC |= ((pwr<<24)|(pwr<<16)|(pwr<<8)|pwr); ++ PHY_SetBBReg(Adapter, rTxAGC_A_Rate18_06, bMaskDWord, TxAGC); ++ PHY_SetBBReg(Adapter, rTxAGC_A_Rate54_24, bMaskDWord, TxAGC); ++ PHY_SetBBReg(Adapter, rTxAGC_A_Mcs03_Mcs00, bMaskDWord, TxAGC); ++ PHY_SetBBReg(Adapter, rTxAGC_A_Mcs07_Mcs04, bMaskDWord, TxAGC); ++ PHY_SetBBReg(Adapter, rTxAGC_A_Mcs11_Mcs08, bMaskDWord, TxAGC); ++ PHY_SetBBReg(Adapter, rTxAGC_A_Mcs15_Mcs12, bMaskDWord, TxAGC); ++ DBG_871X("ODM_TxPwrTrackSetPwr88E: OFDM Tx-rf(A) Power = 0x%x\n", TxAGC); ++ } ++ //#endif ++ ++#endif ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ PHY_RF6052SetCCKTxPower(pDM_Odm->priv, *(pDM_Odm->pChannel)); ++ PHY_RF6052SetOFDMTxPower(pDM_Odm->priv, *(pDM_Odm->pChannel)); ++#endif ++ ++ } ++ else if (Method == BBSWING) ++ { ++ //printk("odm_TxPwrTrackSetPwr88E CH=%d, modify BBSWING BbSwingIdxCck:%d \n", *(pDM_Odm->pChannel),pDM_Odm->BbSwingIdxCck); ++ // Adjust BB swing by CCK filter coefficient ++ //if(!pDM_Odm->RFCalibrateInfo.bCCKinCH14) ++ if(* (pDM_Odm->pChannel) < 14) ++ { ++ ODM_Write1Byte(pDM_Odm, 0xa22, CCKSwingTable_Ch1_Ch13[pDM_Odm->BbSwingIdxCck][0]); ++ ODM_Write1Byte(pDM_Odm, 0xa23, CCKSwingTable_Ch1_Ch13[pDM_Odm->BbSwingIdxCck][1]); ++ ODM_Write1Byte(pDM_Odm, 0xa24, CCKSwingTable_Ch1_Ch13[pDM_Odm->BbSwingIdxCck][2]); ++ ODM_Write1Byte(pDM_Odm, 0xa25, CCKSwingTable_Ch1_Ch13[pDM_Odm->BbSwingIdxCck][3]); ++ ODM_Write1Byte(pDM_Odm, 0xa26, CCKSwingTable_Ch1_Ch13[pDM_Odm->BbSwingIdxCck][4]); ++ ODM_Write1Byte(pDM_Odm, 0xa27, CCKSwingTable_Ch1_Ch13[pDM_Odm->BbSwingIdxCck][5]); ++ ODM_Write1Byte(pDM_Odm, 0xa28, CCKSwingTable_Ch1_Ch13[pDM_Odm->BbSwingIdxCck][6]); ++ ODM_Write1Byte(pDM_Odm, 0xa29, CCKSwingTable_Ch1_Ch13[pDM_Odm->BbSwingIdxCck][7]); ++ } ++ else ++ { ++ ODM_Write1Byte(pDM_Odm, 0xa22, CCKSwingTable_Ch14[pDM_Odm->BbSwingIdxCck][0]); ++ ODM_Write1Byte(pDM_Odm, 0xa23, CCKSwingTable_Ch14[pDM_Odm->BbSwingIdxCck][1]); ++ ODM_Write1Byte(pDM_Odm, 0xa24, CCKSwingTable_Ch14[pDM_Odm->BbSwingIdxCck][2]); ++ ODM_Write1Byte(pDM_Odm, 0xa25, CCKSwingTable_Ch14[pDM_Odm->BbSwingIdxCck][3]); ++ ODM_Write1Byte(pDM_Odm, 0xa26, CCKSwingTable_Ch14[pDM_Odm->BbSwingIdxCck][4]); ++ ODM_Write1Byte(pDM_Odm, 0xa27, CCKSwingTable_Ch14[pDM_Odm->BbSwingIdxCck][5]); ++ ODM_Write1Byte(pDM_Odm, 0xa28, CCKSwingTable_Ch14[pDM_Odm->BbSwingIdxCck][6]); ++ ODM_Write1Byte(pDM_Odm, 0xa29, CCKSwingTable_Ch14[pDM_Odm->BbSwingIdxCck][7]); ++ } ++ ++ // Adjust BB swing by OFDM IQ matrix ++ if (RFPath == RF_PATH_A) ++ { ++ setIqkMatrix(pDM_Odm, pDM_Odm->BbSwingIdxOfdm, RF_PATH_A, ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][0], ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][1]); ++ } ++ /* ++ else if (RFPath == RF_PATH_B) ++ { ++ setIqkMatrix(pDM_Odm, pDM_Odm->BbSwingIdxOfdm[RF_PATH_B], RF_PATH_B, ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][4], ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][5]); ++ }*/ ++ } ++ else ++ { ++ return; ++ } ++} // odm_TxPwrTrackSetPwr88E ++ ++ ++VOID ++odm_TXPowerTrackingCallback_ThermalMeter_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm ++#else ++ IN PADAPTER Adapter ++#endif ++ ) ++{ ++ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ //PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++#endif ++ ++ u1Byte ThermalValue = 0, delta, delta_LCK, delta_IQK, offset; ++ u1Byte ThermalValue_AVG_count = 0; ++ u4Byte ThermalValue_AVG = 0; ++ s4Byte ele_A=0, ele_D, TempCCk, X, value32; ++ s4Byte Y, ele_C=0; ++ s1Byte OFDM_index[2], CCK_index=0, OFDM_index_old[2]={0,0}, CCK_index_old=0, index; ++ s1Byte deltaPowerIndex = 0; ++ u4Byte i = 0, j = 0; ++ BOOLEAN is2T = FALSE; ++ BOOLEAN bInteralPA = FALSE; ++ ++ u1Byte OFDM_min_index = 6, rf = (is2T) ? 2 : 1; //OFDM BB Swing should be less than +3.0dB, which is required by Arthur ++ u1Byte Indexforchannel = 0;/*GetRightChnlPlaceforIQK(pHalData->CurrentChannel)*/ ++ enum _POWER_DEC_INC { POWER_DEC, POWER_INC }; ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++ ++ //4 0.1 The following TWO tables decide the final index of OFDM/CCK swing table. ++ s1Byte deltaSwingTableIdx[2][index_mapping_NUM_88E] = { ++ // {{Power decreasing(lower temperature)}, {Power increasing(higher temperature)}} ++ {0,0,2,3,4,4,5,6,7,7,8,9,10,10,11}, {0,0,-1,-2,-3,-4,-4,-4,-4,-5,-7,-8,-9,-9,-10} ++ }; ++ u1Byte thermalThreshold[2][index_mapping_NUM_88E]={ ++ // {{Power decreasing(lower temperature)}, {Power increasing(higher temperature)}} ++ {0,2,4,6,8,10,12,14,16,18,20,22,24,26,27}, {0,2,4,6,8,10,12,14,16,18,20,22,25,25,25} ++ }; ++ ++ //4 0.1 Initilization ( 7 steps in total ) ++ ++ pDM_Odm->RFCalibrateInfo.TXPowerTrackingCallbackCnt++; //cosa add for debug ++ pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = TRUE; ++ ++#if (MP_DRIVER == 1) ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = pHalData->TxPowerTrackControl; // We should keep updating the control variable according to HalData. ++#endif ++ // RFCalibrateInfo.RegA24 will be initialized when ODM HW configuring, but MP configures with para files. ++ pDM_Odm->RFCalibrateInfo.RegA24 = 0x090e1317; ++#endif ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("===>odm_TXPowerTrackingCallback_ThermalMeter_8188E, pDM_Odm->BbSwingIdxCckBase: %d, pDM_Odm->BbSwingIdxOfdmBase: %d \n", pDM_Odm->BbSwingIdxCckBase, pDM_Odm->BbSwingIdxOfdmBase)); ++ ThermalValue = (u1Byte)ODM_GetRFReg(pDM_Odm, RF_PATH_A, RF_T_METER_88E, 0xfc00); //0x42: RF Reg[15:10] 88E ++ if( ! ThermalValue || ! pDM_Odm->RFCalibrateInfo.TxPowerTrackControl) ++ return; ++ ++ //4 3. Initialize ThermalValues of RFCalibrateInfo ++ ++ if( ! pDM_Odm->RFCalibrateInfo.ThermalValue) ++ { ++ pDM_Odm->RFCalibrateInfo.ThermalValue_LCK = ThermalValue; ++ pDM_Odm->RFCalibrateInfo.ThermalValue_IQK = ThermalValue; ++ } ++ ++ if(pDM_Odm->RFCalibrateInfo.bReloadtxpowerindex) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("reload ofdm index for band switch\n")); ++ } ++ ++ //4 4. Calculate average thermal meter ++ ++ pDM_Odm->RFCalibrateInfo.ThermalValue_AVG[pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index] = ThermalValue; ++ pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index++; ++ if(pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index == AVG_THERMAL_NUM_88E) ++ pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index = 0; ++ ++ for(i = 0; i < AVG_THERMAL_NUM_88E; i++) ++ { ++ if(pDM_Odm->RFCalibrateInfo.ThermalValue_AVG[i]) ++ { ++ ThermalValue_AVG += pDM_Odm->RFCalibrateInfo.ThermalValue_AVG[i]; ++ ThermalValue_AVG_count++; ++ } ++ } ++ ++ if(ThermalValue_AVG_count) ++ { ++ ThermalValue = (u1Byte)(ThermalValue_AVG / ThermalValue_AVG_count); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("AVG Thermal Meter = 0x%x \n", ThermalValue)); ++ } ++ ++ //4 5. Calculate delta, delta_LCK, delta_IQK. ++ ++ delta = (ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue)?(ThermalValue - pDM_Odm->RFCalibrateInfo.ThermalValue):(pDM_Odm->RFCalibrateInfo.ThermalValue - ThermalValue); ++ delta_LCK = (ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue_LCK)?(ThermalValue - pDM_Odm->RFCalibrateInfo.ThermalValue_LCK):(pDM_Odm->RFCalibrateInfo.ThermalValue_LCK - ThermalValue); ++ delta_IQK = (ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue_IQK)?(ThermalValue - pDM_Odm->RFCalibrateInfo.ThermalValue_IQK):(pDM_Odm->RFCalibrateInfo.ThermalValue_IQK - ThermalValue); ++ ++ //4 6. If necessary, do LCK. ++ ++ //if((delta_LCK > pHalData->Delta_LCK) && (pHalData->Delta_LCK != 0)) ++ if ((delta_LCK >= 8)) // Delta temperature is equal to or larger than 20 centigrade. ++ { ++ pDM_Odm->RFCalibrateInfo.ThermalValue_LCK = ThermalValue; ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ PHY_LCCalibrate_8188E(Adapter); ++#else ++ PHY_LCCalibrate_8188E(pDM_Odm); ++#endif ++ } ++ ++ //3 7. If necessary, move the index of swing table to adjust Tx power. ++ ++ if (delta > 0 && pDM_Odm->RFCalibrateInfo.TxPowerTrackControl) ++ { ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE)) ++ delta = ThermalValue > pHalData->EEPROMThermalMeter?(ThermalValue - pHalData->EEPROMThermalMeter):(pHalData->EEPROMThermalMeter - ThermalValue); ++#else ++ delta = (ThermalValue > pDM_Odm->priv->pmib->dot11RFEntry.ther)?(ThermalValue - pDM_Odm->priv->pmib->dot11RFEntry.ther):(pDM_Odm->priv->pmib->dot11RFEntry.ther - ThermalValue); ++#endif ++ ++ ++ //4 7.1 The Final Power Index = BaseIndex + PowerIndexOffset ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE)) ++ if(ThermalValue > pHalData->EEPROMThermalMeter) { ++#else ++ if(ThermalValue > pDM_Odm->priv->pmib->dot11RFEntry.ther) { ++#endif ++ CALCULATE_SWINGTALBE_OFFSET(offset, POWER_INC, index_mapping_NUM_88E, delta); ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast = pDM_Odm->RFCalibrateInfo.DeltaPowerIndex; ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndex = -1 * deltaSwingTableIdx[POWER_INC][offset]; ++ ++ } else { ++ ++ CALCULATE_SWINGTALBE_OFFSET(offset, POWER_DEC, index_mapping_NUM_88E, delta); ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast = pDM_Odm->RFCalibrateInfo.DeltaPowerIndex; ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndex = -1 * deltaSwingTableIdx[POWER_DEC][offset]; ++ } ++ ++ if (pDM_Odm->RFCalibrateInfo.DeltaPowerIndex == pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast) ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset = 0; ++ else ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset = pDM_Odm->RFCalibrateInfo.DeltaPowerIndex - pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast; ++ ++ for(i = 0; i < rf; i++) ++ pDM_Odm->RFCalibrateInfo.OFDM_index[i] = pDM_Odm->BbSwingIdxOfdmBase + pDM_Odm->RFCalibrateInfo.PowerIndexOffset; ++ pDM_Odm->RFCalibrateInfo.CCK_index = pDM_Odm->BbSwingIdxCckBase + pDM_Odm->RFCalibrateInfo.PowerIndexOffset; ++ ++ pDM_Odm->BbSwingIdxCck = pDM_Odm->RFCalibrateInfo.CCK_index; ++ pDM_Odm->BbSwingIdxOfdm = pDM_Odm->RFCalibrateInfo.OFDM_index[RF_PATH_A]; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("The 'CCK' final index(%d) = BaseIndex(%d) + PowerIndexOffset(%d)\n", pDM_Odm->BbSwingIdxCck, pDM_Odm->BbSwingIdxCckBase, pDM_Odm->RFCalibrateInfo.PowerIndexOffset)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("The 'OFDM' final index(%d) = BaseIndex(%d) + PowerIndexOffset(%d)\n", pDM_Odm->BbSwingIdxOfdm, pDM_Odm->BbSwingIdxOfdmBase, pDM_Odm->RFCalibrateInfo.PowerIndexOffset)); ++ ++ //4 7.1 Handle boundary conditions of index. ++ ++ ++ for(i = 0; i < rf; i++) ++ { ++ if(pDM_Odm->RFCalibrateInfo.OFDM_index[i] > OFDM_TABLE_SIZE_92D-1) ++ { ++ pDM_Odm->RFCalibrateInfo.OFDM_index[i] = OFDM_TABLE_SIZE_92D-1; ++ } ++ else if (pDM_Odm->RFCalibrateInfo.OFDM_index[i] < OFDM_min_index) ++ { ++ pDM_Odm->RFCalibrateInfo.OFDM_index[i] = OFDM_min_index; ++ } ++ } ++ ++ if(pDM_Odm->RFCalibrateInfo.CCK_index > CCK_TABLE_SIZE-1) ++ pDM_Odm->RFCalibrateInfo.CCK_index = CCK_TABLE_SIZE-1; ++ else if (pDM_Odm->RFCalibrateInfo.CCK_index < 0) ++ pDM_Odm->RFCalibrateInfo.CCK_index = 0; ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("The thermal meter is unchanged or TxPowerTracking OFF: ThermalValue: %d , pDM_Odm->RFCalibrateInfo.ThermalValue: %d)\n", ThermalValue, pDM_Odm->RFCalibrateInfo.ThermalValue)); ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset = 0; ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("TxPowerTracking: [CCK] Swing Current Index: %d, Swing Base Index: %d\n", pDM_Odm->RFCalibrateInfo.CCK_index, pDM_Odm->BbSwingIdxCckBase)); ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("TxPowerTracking: [OFDM] Swing Current Index: %d, Swing Base Index: %d\n", pDM_Odm->RFCalibrateInfo.OFDM_index[RF_PATH_A], pDM_Odm->BbSwingIdxOfdmBase)); ++ ++ if (pDM_Odm->RFCalibrateInfo.PowerIndexOffset != 0 && pDM_Odm->RFCalibrateInfo.TxPowerTrackControl) ++ { ++ //4 7.2 Configure the Swing Table to adjust Tx Power. ++ ++ pDM_Odm->RFCalibrateInfo.bTxPowerChanged = TRUE; // Always TRUE after Tx Power is adjusted by power tracking. ++ // ++ // 2012/04/23 MH According to Luke's suggestion, we can not write BB digital ++ // to increase TX power. Otherwise, EVM will be bad. ++ // ++ // 2012/04/25 MH Add for tx power tracking to set tx power in tx agc for 88E. ++ if (ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("Temperature Increasing: delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset, delta, ThermalValue, pHalData->EEPROMThermalMeter, pDM_Odm->RFCalibrateInfo.ThermalValue)); ++ } ++ else if (ThermalValue < pDM_Odm->RFCalibrateInfo.ThermalValue)// Low temperature ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("Temperature Decreasing: delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset, delta, ThermalValue, pHalData->EEPROMThermalMeter, pDM_Odm->RFCalibrateInfo.ThermalValue)); ++ } ++ ++ if (ThermalValue > pHalData->EEPROMThermalMeter) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("Temperature(%d) hugher than PG value(%d), increases the power by TxAGC\n", ThermalValue, pHalData->EEPROMThermalMeter)); ++ odm_TxPwrTrackSetPwr88E(pDM_Odm, TXAGC, 0, 0); ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("Temperature(%d) lower than PG value(%d), increases the power by TxAGC\n", ThermalValue, pHalData->EEPROMThermalMeter)); ++ odm_TxPwrTrackSetPwr88E(pDM_Odm, BBSWING, RF_PATH_A, Indexforchannel); ++ //if(is2T) ++ // odm_TxPwrTrackSetPwr88E(pDM_Odm, BBSWING, RF_PATH_B, Indexforchannel); ++ } ++ ++ pDM_Odm->BbSwingIdxCckBase = pDM_Odm->BbSwingIdxCck; ++ pDM_Odm->BbSwingIdxOfdmBase = pDM_Odm->BbSwingIdxOfdm; ++ pDM_Odm->RFCalibrateInfo.ThermalValue = ThermalValue; ++ ++ } ++ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ // if((delta_IQK > pHalData->Delta_IQK) && (pHalData->Delta_IQK != 0)) ++ if ((delta_IQK >= 8)){ // Delta temperature is equal to or larger than 20 centigrade. ++ //printk("delta_IQK(%d) >=8 do_IQK\n",delta_IQK); ++ doIQK(pDM_Odm, delta_IQK, ThermalValue, 8); ++ } ++#endif ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("<===dm_TXPowerTrackingCallback_ThermalMeter_8188E\n")); ++ ++ pDM_Odm->RFCalibrateInfo.TXPowercount = 0; ++} ++ ++ ++ ++ ++ ++ ++//1 7. IQK ++#define MAX_TOLERANCE 5 ++#define IQK_DELAY_TIME 1 //ms ++ ++u1Byte //bit0 = 1 => Tx OK, bit1 = 1 => Rx OK ++phy_PathA_IQK_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN BOOLEAN configPathB ++ ) ++{ ++ u4Byte regEAC, regE94, regE9C, regEA4; ++ u1Byte result = 0x00; ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQK!\n")); ++ ++ //1 Tx IQK ++ //path-A IQK setting ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A IQK setting!\n")); ++ ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008c1c); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x30008c1c); ++ ODM_SetBBReg(pDM_Odm, rTx_IQK_PI_A, bMaskDWord, 0x8214032a); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK_PI_A, bMaskDWord, 0x28160000); ++ ++ //LO calibration setting ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); ++ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Rsp, bMaskDWord, 0x00462911); ++ ++ //One shot, path A LOK & IQK ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); ++ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); ++ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); ++ ++ // delay x ms ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E)); ++ //PlatformStallExecution(IQK_DELAY_TIME_88E*1000); ++ ODM_delay_ms(IQK_DELAY_TIME_88E); ++ ++ // Check failed ++ regEAC = ODM_GetBBReg(pDM_Odm, rRx_Power_After_IQK_A_2, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC)); ++ regE94 = ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_A, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x\n", regE94)); ++ regE9C= ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_A, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe9c = 0x%x\n", regE9C)); ++ regEA4= ODM_GetBBReg(pDM_Odm, rRx_Power_Before_IQK_A_2, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea4 = 0x%x\n", regEA4)); ++ ++ if(!(regEAC & BIT28) && ++ (((regE94 & 0x03FF0000)>>16) != 0x142) && ++ (((regE9C & 0x03FF0000)>>16) != 0x42) ) ++ result |= 0x01; ++ else //if Tx not OK, ignore Rx ++ return result; ++ ++#if 0 ++ if(!(regEAC & BIT27) && //if Tx is OK, check whether Rx is OK ++ (((regEA4 & 0x03FF0000)>>16) != 0x132) && ++ (((regEAC & 0x03FF0000)>>16) != 0x36)) ++ result |= 0x02; ++ else ++ RTPRINT(FINIT, INIT_IQK, ("Path A Rx IQK fail!!\n")); ++#endif ++ ++ return result; ++ ++ ++ } ++ ++u1Byte //bit0 = 1 => Tx OK, bit1 = 1 => Rx OK ++phy_PathA_RxIQK( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN BOOLEAN configPathB ++ ) ++{ ++ u4Byte regEAC, regE94, regE9C, regEA4, u4tmp; ++ u1Byte result = 0x00; ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK!\n")); ++ ++ //1 Get TXIMR setting ++ //modify RXIQK mode table ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A Rx IQK modify RXIQK mode table!\n")); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_WE_LUT, bRFRegOffsetMask, 0x800a0 ); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x30000 ); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0000f ); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf117B ); ++ ++ //PA,PAD off ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0xdf, bRFRegOffsetMask, 0x980 ); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x56, bRFRegOffsetMask, 0x51000 ); ++ ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80800000); ++ ++ //IQK setting ++ ODM_SetBBReg(pDM_Odm, rTx_IQK, bMaskDWord, 0x01007c00); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK, bMaskDWord, 0x81004800); ++ ++ //path-A IQK setting ++ ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008c1c); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x30008c1c); ++ ODM_SetBBReg(pDM_Odm, rTx_IQK_PI_A, bMaskDWord, 0x82160c1f); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK_PI_A, bMaskDWord, 0x28160000); ++ ++ //LO calibration setting ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); ++ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Rsp, bMaskDWord, 0x0046a911); ++ ++ //One shot, path A LOK & IQK ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); ++ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); ++ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); ++ ++ // delay x ms ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E)); ++ //PlatformStallExecution(IQK_DELAY_TIME_88E*1000); ++ ODM_delay_ms(IQK_DELAY_TIME_88E); ++ ++ ++ // Check failed ++ regEAC = ODM_GetBBReg(pDM_Odm, rRx_Power_After_IQK_A_2, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC)); ++ regE94 = ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_A, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x\n", regE94)); ++ regE9C= ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_A, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe9c = 0x%x\n", regE9C)); ++ ++ if(!(regEAC & BIT28) && ++ (((regE94 & 0x03FF0000)>>16) != 0x142) && ++ (((regE9C & 0x03FF0000)>>16) != 0x42) ) ++ { ++ result |= 0x01; ++ } ++ else ++ { ++ //reload RF 0xdf ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0xdf, bRFRegOffsetMask, 0x180 );//if Tx not OK, ignore Rx ++ return result; ++ } ++ ++ u4tmp = 0x80007C00 | (regE94&0x3FF0000) | ((regE9C&0x3FF0000) >> 16); ++ ODM_SetBBReg(pDM_Odm, rTx_IQK, bMaskDWord, u4tmp); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe40 = 0x%x u4tmp = 0x%x \n", ODM_GetBBReg(pDM_Odm, rTx_IQK, bMaskDWord), u4tmp)); ++ ++ ++ //1 RX IQK ++ //modify RXIQK mode table ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A Rx IQK modify RXIQK mode table 2!\n")); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_WE_LUT, bRFRegOffsetMask, 0x800a0 ); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x30000 ); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0000f ); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf7ffa ); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80800000); ++ ++ //IQK setting ++ ODM_SetBBReg(pDM_Odm, rRx_IQK, bMaskDWord, 0x01004800); ++ ++ //path-A IQK setting ++ ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x38008c1c); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x18008c1c); ++ ODM_SetBBReg(pDM_Odm, rTx_IQK_PI_A, bMaskDWord, 0x82160c05); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK_PI_A, bMaskDWord, 0x28160c1f); ++ ++ //LO calibration setting ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); ++ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Rsp, bMaskDWord, 0x0046a911); ++ ++ //One shot, path A LOK & IQK ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); ++ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); ++ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); ++ ++ // delay x ms ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E)); ++ //PlatformStallExecution(IQK_DELAY_TIME_88E*1000); ++ ODM_delay_ms(IQK_DELAY_TIME_88E); ++ ++ ++ // Check failed ++ regEAC = ODM_GetBBReg(pDM_Odm, rRx_Power_After_IQK_A_2, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC)); ++ regE94 = ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_A, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x\n", regE94)); ++ regE9C= ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_A, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe9c = 0x%x\n", regE9C)); ++ regEA4= ODM_GetBBReg(pDM_Odm, rRx_Power_Before_IQK_A_2, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea4 = 0x%x\n", regEA4)); ++ ++ //reload RF 0xdf ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0xdf, bRFRegOffsetMask, 0x180 ); ++ ++#if 0 ++ if(!(regEAC & BIT28) && ++ (((regE94 & 0x03FF0000)>>16) != 0x142) && ++ (((regE9C & 0x03FF0000)>>16) != 0x42) ) ++ result |= 0x01; ++ else //if Tx not OK, ignore Rx ++ return result; ++#endif ++ ++ if(!(regEAC & BIT27) && //if Tx is OK, check whether Rx is OK ++ (((regEA4 & 0x03FF0000)>>16) != 0x132) && ++ (((regEAC & 0x03FF0000)>>16) != 0x36)) ++ result |= 0x02; ++ else ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK fail!!\n")); ++ ++ return result; ++ ++ ++ ++ ++} ++ ++u1Byte //bit0 = 1 => Tx OK, bit1 = 1 => Rx OK ++phy_PathB_IQK_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm ++#else ++ IN PADAPTER pAdapter ++#endif ++ ) ++{ ++ u4Byte regEAC, regEB4, regEBC, regEC4, regECC; ++ u1Byte result = 0x00; ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK!\n")); ++ ++ //One shot, path B LOK & IQK ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); ++ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Cont, bMaskDWord, 0x00000002); ++ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Cont, bMaskDWord, 0x00000000); ++ ++ // delay x ms ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path B LOK & IQK.\n", IQK_DELAY_TIME_88E)); ++ //PlatformStallExecution(IQK_DELAY_TIME_88E*1000); ++ ODM_delay_ms(IQK_DELAY_TIME_88E); ++ ++ // Check failed ++ regEAC = ODM_GetBBReg(pDM_Odm, rRx_Power_After_IQK_A_2, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC)); ++ regEB4 = ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_B, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeb4 = 0x%x\n", regEB4)); ++ regEBC= ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_B, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xebc = 0x%x\n", regEBC)); ++ regEC4= ODM_GetBBReg(pDM_Odm, rRx_Power_Before_IQK_B_2, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xec4 = 0x%x\n", regEC4)); ++ regECC= ODM_GetBBReg(pDM_Odm, rRx_Power_After_IQK_B_2, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xecc = 0x%x\n", regECC)); ++ ++ if(!(regEAC & BIT31) && ++ (((regEB4 & 0x03FF0000)>>16) != 0x142) && ++ (((regEBC & 0x03FF0000)>>16) != 0x42)) ++ result |= 0x01; ++ else ++ return result; ++ ++ if(!(regEAC & BIT30) && ++ (((regEC4 & 0x03FF0000)>>16) != 0x132) && ++ (((regECC & 0x03FF0000)>>16) != 0x36)) ++ result |= 0x02; ++ else ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Rx IQK fail!!\n")); ++ ++ ++ return result; ++ ++} ++ ++VOID ++_PHY_PathAFillIQKMatrix( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN BOOLEAN bIQKOK, ++ IN s4Byte result[][8], ++ IN u1Byte final_candidate, ++ IN BOOLEAN bTxOnly ++ ) ++{ ++ u4Byte Oldval_0, X, TX0_A, reg; ++ s4Byte Y, TX0_C; ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQ Calibration %s !\n",(bIQKOK)?"Success":"Failed")); ++ ++ if(final_candidate == 0xFF) ++ return; ++ ++ else if(bIQKOK) ++ { ++ Oldval_0 = (ODM_GetBBReg(pDM_Odm, rOFDM0_XATxIQImbalance, bMaskDWord) >> 22) & 0x3FF; ++ ++ X = result[final_candidate][0]; ++ if ((X & 0x00000200) != 0) ++ X = X | 0xFFFFFC00; ++ TX0_A = (X * Oldval_0) >> 8; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("X = 0x%x, TX0_A = 0x%x, Oldval_0 0x%x\n", X, TX0_A, Oldval_0)); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XATxIQImbalance, 0x3FF, TX0_A); ++ ++ ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, BIT(31), ((X* Oldval_0>>7) & 0x1)); ++ ++ Y = result[final_candidate][1]; ++ if ((Y & 0x00000200) != 0) ++ Y = Y | 0xFFFFFC00; ++ ++ ++ TX0_C = (Y * Oldval_0) >> 8; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Y = 0x%x, TX = 0x%x\n", Y, TX0_C)); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XCTxAFE, 0xF0000000, ((TX0_C&0x3C0)>>6)); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XATxIQImbalance, 0x003F0000, (TX0_C&0x3F)); ++ ++ ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, BIT(29), ((Y* Oldval_0>>7) & 0x1)); ++ ++ if(bTxOnly) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("_PHY_PathAFillIQKMatrix only Tx OK\n")); ++ return; ++ } ++ ++ reg = result[final_candidate][2]; ++#if (DM_ODM_SUPPORT_TYPE==ODM_AP) ++ if( RTL_ABS(reg ,0x100) >= 16) ++ reg = 0x100; ++#endif ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XARxIQImbalance, 0x3FF, reg); ++ ++ reg = result[final_candidate][3] & 0x3F; ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XARxIQImbalance, 0xFC00, reg); ++ ++ reg = (result[final_candidate][3] >> 6) & 0xF; ++ ODM_SetBBReg(pDM_Odm, rOFDM0_RxIQExtAnta, 0xF0000000, reg); ++ } ++} ++ ++VOID ++_PHY_PathBFillIQKMatrix( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN BOOLEAN bIQKOK, ++ IN s4Byte result[][8], ++ IN u1Byte final_candidate, ++ IN BOOLEAN bTxOnly //do Tx only ++ ) ++{ ++ u4Byte Oldval_1, X, TX1_A, reg; ++ s4Byte Y, TX1_C; ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQ Calibration %s !\n",(bIQKOK)?"Success":"Failed")); ++ ++ if(final_candidate == 0xFF) ++ return; ++ ++ else if(bIQKOK) ++ { ++ Oldval_1 = (ODM_GetBBReg(pDM_Odm, rOFDM0_XBTxIQImbalance, bMaskDWord) >> 22) & 0x3FF; ++ ++ X = result[final_candidate][4]; ++ if ((X & 0x00000200) != 0) ++ X = X | 0xFFFFFC00; ++ TX1_A = (X * Oldval_1) >> 8; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("X = 0x%x, TX1_A = 0x%x\n", X, TX1_A)); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XBTxIQImbalance, 0x3FF, TX1_A); ++ ++ ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, BIT(27), ((X* Oldval_1>>7) & 0x1)); ++ ++ Y = result[final_candidate][5]; ++ if ((Y & 0x00000200) != 0) ++ Y = Y | 0xFFFFFC00; ++ ++ TX1_C = (Y * Oldval_1) >> 8; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Y = 0x%x, TX1_C = 0x%x\n", Y, TX1_C)); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XDTxAFE, 0xF0000000, ((TX1_C&0x3C0)>>6)); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XBTxIQImbalance, 0x003F0000, (TX1_C&0x3F)); ++ ++ ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, BIT(25), ((Y* Oldval_1>>7) & 0x1)); ++ ++ if(bTxOnly) ++ return; ++ ++ reg = result[final_candidate][6]; ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XBRxIQImbalance, 0x3FF, reg); ++ ++ reg = result[final_candidate][7] & 0x3F; ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XBRxIQImbalance, 0xFC00, reg); ++ ++ reg = (result[final_candidate][7] >> 6) & 0xF; ++ ODM_SetBBReg(pDM_Odm, rOFDM0_AGCRSSITable, 0x0000F000, reg); ++ } ++} ++ ++// ++// 2011/07/26 MH Add an API for testing IQK fail case. ++// ++// MP Already declare in odm.c ++#if !(DM_ODM_SUPPORT_TYPE & ODM_MP) ++BOOLEAN ++ODM_CheckPowerStatus( ++ IN PADAPTER Adapter) ++{ ++/* ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ RT_RF_POWER_STATE rtState; ++ PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ ++ // 2011/07/27 MH We are not testing ready~~!! We may fail to get correct value when init sequence. ++ if (pMgntInfo->init_adpt_in_progress == TRUE) ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_INIT, DBG_LOUD, ("ODM_CheckPowerStatus Return TRUE, due to initadapter")); ++ return TRUE; ++ } ++ ++ // ++ // 2011/07/19 MH We can not execute tx pwoer tracking/ LLC calibrate or IQK. ++ // ++ Adapter->HalFunc.GetHwRegHandler(Adapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState)); ++ if(Adapter->bDriverStopped || Adapter->bDriverIsGoingToPnpSetPowerSleep || rtState == eRfOff) ++ { ++ ODM_RT_TRACE(pDM_Odm,COMP_INIT, DBG_LOUD, ("ODM_CheckPowerStatus Return FALSE, due to %d/%d/%d\n", ++ Adapter->bDriverStopped, Adapter->bDriverIsGoingToPnpSetPowerSleep, rtState)); ++ return FALSE; ++ } ++*/ ++ return TRUE; ++} ++#endif ++ ++VOID ++_PHY_SaveADDARegisters( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN pu4Byte ADDAReg, ++ IN pu4Byte ADDABackup, ++ IN u4Byte RegisterNum ++ ) ++{ ++ u4Byte i; ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++ ++ if (ODM_CheckPowerStatus(pAdapter) == FALSE) ++ return; ++#endif ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save ADDA parameters.\n")); ++ for( i = 0 ; i < RegisterNum ; i++){ ++ ADDABackup[i] = ODM_GetBBReg(pDM_Odm, ADDAReg[i], bMaskDWord); ++ } ++} ++ ++ ++VOID ++_PHY_SaveMACRegisters( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN pu4Byte MACReg, ++ IN pu4Byte MACBackup ++ ) ++{ ++ u4Byte i; ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save MAC parameters.\n")); ++ for( i = 0 ; i < (IQK_MAC_REG_NUM - 1); i++){ ++ MACBackup[i] = ODM_Read1Byte(pDM_Odm, MACReg[i]); ++ } ++ MACBackup[i] = ODM_Read4Byte(pDM_Odm, MACReg[i]); ++ ++} ++ ++ ++VOID ++_PHY_ReloadADDARegisters( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN pu4Byte ADDAReg, ++ IN pu4Byte ADDABackup, ++ IN u4Byte RegiesterNum ++ ) ++{ ++ u4Byte i; ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Reload ADDA power saving parameters !\n")); ++ for(i = 0 ; i < RegiesterNum; i++) ++ { ++ ODM_SetBBReg(pDM_Odm, ADDAReg[i], bMaskDWord, ADDABackup[i]); ++ } ++} ++ ++VOID ++_PHY_ReloadMACRegisters( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN pu4Byte MACReg, ++ IN pu4Byte MACBackup ++ ) ++{ ++ u4Byte i; ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Reload MAC parameters !\n")); ++ for(i = 0 ; i < (IQK_MAC_REG_NUM - 1); i++){ ++ ODM_Write1Byte(pDM_Odm, MACReg[i], (u1Byte)MACBackup[i]); ++ } ++ ODM_Write4Byte(pDM_Odm, MACReg[i], MACBackup[i]); ++} ++ ++ ++VOID ++_PHY_PathADDAOn( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN pu4Byte ADDAReg, ++ IN BOOLEAN isPathAOn, ++ IN BOOLEAN is2T ++ ) ++{ ++ u4Byte pathOn; ++ u4Byte i; ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("ADDA ON.\n")); ++ ++ pathOn = isPathAOn ? 0x04db25a4 : 0x0b1b25a4; ++ if(FALSE == is2T){ ++ pathOn = 0x0bdb25a0; ++ ODM_SetBBReg(pDM_Odm, ADDAReg[0], bMaskDWord, 0x0b1b25a0); ++ } ++ else{ ++ ODM_SetBBReg(pDM_Odm,ADDAReg[0], bMaskDWord, pathOn); ++ } ++ ++ for( i = 1 ; i < IQK_ADDA_REG_NUM ; i++){ ++ ODM_SetBBReg(pDM_Odm,ADDAReg[i], bMaskDWord, pathOn); ++ } ++ ++} ++ ++VOID ++_PHY_MACSettingCalibration( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN pu4Byte MACReg, ++ IN pu4Byte MACBackup ++ ) ++{ ++ u4Byte i = 0; ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("MAC settings for Calibration.\n")); ++ ++ ODM_Write1Byte(pDM_Odm, MACReg[i], 0x3F); ++ ++ for(i = 1 ; i < (IQK_MAC_REG_NUM - 1); i++){ ++ ODM_Write1Byte(pDM_Odm, MACReg[i], (u1Byte)(MACBackup[i]&(~BIT3))); ++ } ++ ODM_Write1Byte(pDM_Odm, MACReg[i], (u1Byte)(MACBackup[i]&(~BIT5))); ++ ++} ++ ++VOID ++_PHY_PathAStandBy( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm ++#else ++ IN PADAPTER pAdapter ++#endif ++ ) ++{ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A standby mode!\n")); ++ ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x0); ++ ODM_SetBBReg(pDM_Odm, 0x840, bMaskDWord, 0x00010000); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80800000); ++} ++ ++VOID ++_PHY_PIModeSwitch( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN BOOLEAN PIMode ++ ) ++{ ++ u4Byte mode; ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("BB Switch to %s mode!\n", (PIMode ? "PI" : "SI"))); ++ ++ mode = PIMode ? 0x01000100 : 0x01000000; ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_HSSIParameter1, bMaskDWord, mode); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XB_HSSIParameter1, bMaskDWord, mode); ++} ++ ++BOOLEAN ++phy_SimularityCompare_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN s4Byte result[][8], ++ IN u1Byte c1, ++ IN u1Byte c2 ++ ) ++{ ++ u4Byte i, j, diff, SimularityBitMap, bound = 0; ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ u1Byte final_candidate[2] = {0xFF, 0xFF}; //for path A and path B ++ BOOLEAN bResult = TRUE; ++ BOOLEAN is2T; ++ s4Byte tmp1 = 0,tmp2 = 0; ++ ++ if( (pDM_Odm->RFType ==ODM_2T2R )||(pDM_Odm->RFType ==ODM_2T3R )||(pDM_Odm->RFType ==ODM_2T4R )) ++ is2T = TRUE; ++ else ++ is2T = FALSE; ++ ++ if(is2T) ++ bound = 8; ++ else ++ bound = 4; ++ ++ ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("===> IQK:phy_SimularityCompare_8188E c1 %d c2 %d!!!\n", c1, c2)); ++ ++ ++ SimularityBitMap = 0; ++ ++ for( i = 0; i < bound; i++ ) ++ { ++// diff = (result[c1][i] > result[c2][i]) ? (result[c1][i] - result[c2][i]) : (result[c2][i] - result[c1][i]); ++ if((i==1) || (i==3) || (i==5) || (i==7)) ++ { ++ if((result[c1][i]& 0x00000200) != 0) ++ tmp1 = result[c1][i] | 0xFFFFFC00; ++ else ++ tmp1 = result[c1][i]; ++ ++ if((result[c2][i]& 0x00000200) != 0) ++ tmp2 = result[c2][i] | 0xFFFFFC00; ++ else ++ tmp2 = result[c2][i]; ++ } ++ else ++ { ++ tmp1 = result[c1][i]; ++ tmp2 = result[c2][i]; ++ } ++ ++ diff = (tmp1 > tmp2) ? (tmp1 - tmp2) : (tmp2 - tmp1); ++ ++ if (diff > MAX_TOLERANCE) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:phy_SimularityCompare_8188E differnece overflow index %d compare1 0x%x compare2 0x%x!!!\n", i, result[c1][i], result[c2][i])); ++ ++ if((i == 2 || i == 6) && !SimularityBitMap) ++ { ++ if(result[c1][i]+result[c1][i+1] == 0) ++ final_candidate[(i/4)] = c2; ++ else if (result[c2][i]+result[c2][i+1] == 0) ++ final_candidate[(i/4)] = c1; ++ else ++ SimularityBitMap = SimularityBitMap|(1<odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ u4Byte i; ++ u1Byte PathAOK, PathBOK; ++ u4Byte ADDA_REG[IQK_ADDA_REG_NUM] = { ++ rFPGA0_XCD_SwitchControl, rBlue_Tooth, ++ rRx_Wait_CCA, rTx_CCK_RFON, ++ rTx_CCK_BBON, rTx_OFDM_RFON, ++ rTx_OFDM_BBON, rTx_To_Rx, ++ rTx_To_Tx, rRx_CCK, ++ rRx_OFDM, rRx_Wait_RIFS, ++ rRx_TO_Rx, rStandby, ++ rSleep, rPMPD_ANAEN }; ++ u4Byte IQK_MAC_REG[IQK_MAC_REG_NUM] = { ++ REG_TXPAUSE, REG_BCN_CTRL, ++ REG_BCN_CTRL_1, REG_GPIO_MUXCFG}; ++ ++ //since 92C & 92D have the different define in IQK_BB_REG ++ u4Byte IQK_BB_REG_92C[IQK_BB_REG_NUM] = { ++ rOFDM0_TRxPathEnable, rOFDM0_TRMuxPar, ++ rFPGA0_XCD_RFInterfaceSW, rConfig_AntA, rConfig_AntB, ++ rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE, ++ rFPGA0_XB_RFInterfaceOE, rFPGA0_RFMOD ++ }; ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ u4Byte retryCount = 2; ++#else ++#if MP_DRIVER ++ u4Byte retryCount = 9; ++#else ++ u4Byte retryCount = 2; ++#endif ++#endif ++if ( *(pDM_Odm->mp_mode) == 1) ++ retryCount = 9; ++else ++ retryCount = 2; ++ // Note: IQ calibration must be performed after loading ++ // PHY_REG.txt , and radio_a, radio_b.txt ++ ++ //u4Byte bbvalue; ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++#ifdef MP_TEST ++ if(pDM_Odm->priv->pshare->rf_ft_var.mp_specific) ++ retryCount = 9; ++#endif ++#endif ++ ++ ++ if(t==0) ++ { ++// bbvalue = ODM_GetBBReg(pDM_Odm, rFPGA0_RFMOD, bMaskDWord); ++// RTPRINT(FINIT, INIT_IQK, ("phy_IQCalibrate_8188E()==>0x%08x\n",bbvalue)); ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQ Calibration for %s for %d times\n", (is2T ? "2T2R" : "1T1R"), t)); ++ ++ // Save ADDA parameters, turn Path A ADDA on ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ _PHY_SaveADDARegisters(pAdapter, ADDA_REG, pDM_Odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM); ++ _PHY_SaveMACRegisters(pAdapter, IQK_MAC_REG, pDM_Odm->RFCalibrateInfo.IQK_MAC_backup); ++ _PHY_SaveADDARegisters(pAdapter, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM); ++#else ++ _PHY_SaveADDARegisters(pDM_Odm, ADDA_REG, pDM_Odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM); ++ _PHY_SaveMACRegisters(pDM_Odm, IQK_MAC_REG, pDM_Odm->RFCalibrateInfo.IQK_MAC_backup); ++ _PHY_SaveADDARegisters(pDM_Odm, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM); ++#endif ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQ Calibration for %s for %d times\n", (is2T ? "2T2R" : "1T1R"), t)); ++ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ ++ _PHY_PathADDAOn(pAdapter, ADDA_REG, TRUE, is2T); ++#else ++ _PHY_PathADDAOn(pDM_Odm, ADDA_REG, TRUE, is2T); ++#endif ++ ++ ++ if(t==0) ++ { ++ pDM_Odm->RFCalibrateInfo.bRfPiEnable = (u1Byte)ODM_GetBBReg(pDM_Odm, rFPGA0_XA_HSSIParameter1, BIT(8)); ++ } ++ ++ if(!pDM_Odm->RFCalibrateInfo.bRfPiEnable){ ++ // Switch BB to PI mode to do IQ Calibration. ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ _PHY_PIModeSwitch(pAdapter, TRUE); ++#else ++ _PHY_PIModeSwitch(pDM_Odm, TRUE); ++#endif ++ } ++ ++ //BB setting ++ ODM_SetBBReg(pDM_Odm, rFPGA0_RFMOD, BIT24, 0x00); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_TRxPathEnable, bMaskDWord, 0x03a05600); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, 0x000800e4); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22204000); ++ ++ ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XAB_RFInterfaceSW, BIT10, 0x01); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XAB_RFInterfaceSW, BIT26, 0x01); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, BIT10, 0x00); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XB_RFInterfaceOE, BIT10, 0x00); ++ ++ ++ if(is2T) ++ { ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00010000); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00010000); ++ } ++ ++ //MAC settings ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ _PHY_MACSettingCalibration(pAdapter, IQK_MAC_REG, pDM_Odm->RFCalibrateInfo.IQK_MAC_backup); ++#else ++ _PHY_MACSettingCalibration(pDM_Odm, IQK_MAC_REG, pDM_Odm->RFCalibrateInfo.IQK_MAC_backup); ++#endif ++ ++ ++ //Page B init ++ //AP or IQK ++ ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x0f600000); ++ ++ if(is2T) ++ { ++ ODM_SetBBReg(pDM_Odm, rConfig_AntB, bMaskDWord, 0x0f600000); ++ } ++ ++ // IQ calibration setting ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK setting!\n")); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80800000); ++ ODM_SetBBReg(pDM_Odm, rTx_IQK, bMaskDWord, 0x01007c00); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK, bMaskDWord, 0x81004800); ++ ++ for(i = 0 ; i < retryCount ; i++){ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ PathAOK = phy_PathA_IQK_8188E(pAdapter, is2T); ++#else ++ PathAOK = phy_PathA_IQK_8188E(pDM_Odm, is2T); ++#endif ++// if(PathAOK == 0x03){ ++ if(PathAOK == 0x01){ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Tx IQK Success!!\n")); ++ result[t][0] = (ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; ++ result[t][1] = (ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; ++ break; ++ } ++#if 0 ++ else if (i == (retryCount-1) && PathAOK == 0x01) //Tx IQK OK ++ { ++ RTPRINT(FINIT, INIT_IQK, ("Path A IQK Only Tx Success!!\n")); ++ ++ result[t][0] = (ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; ++ result[t][1] = (ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; ++ } ++#endif ++ } ++ ++ for(i = 0 ; i < retryCount ; i++){ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ PathAOK = phy_PathA_RxIQK(pAdapter, is2T); ++#else ++ PathAOK = phy_PathA_RxIQK(pDM_Odm, is2T); ++#endif ++ if(PathAOK == 0x03){ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK Success!!\n")); ++// result[t][0] = (ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; ++// result[t][1] = (ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; ++ result[t][2] = (ODM_GetBBReg(pDM_Odm, rRx_Power_Before_IQK_A_2, bMaskDWord)&0x3FF0000)>>16; ++ result[t][3] = (ODM_GetBBReg(pDM_Odm, rRx_Power_After_IQK_A_2, bMaskDWord)&0x3FF0000)>>16; ++ break; ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK Fail!!\n")); ++ } ++ } ++ ++ if(0x00 == PathAOK){ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQK failed!!\n")); ++ } ++ ++ if(is2T){ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ _PHY_PathAStandBy(pAdapter); ++ ++ // Turn Path B ADDA on ++ _PHY_PathADDAOn(pAdapter, ADDA_REG, FALSE, is2T); ++#else ++ _PHY_PathAStandBy(pDM_Odm); ++ ++ // Turn Path B ADDA on ++ _PHY_PathADDAOn(pDM_Odm, ADDA_REG, FALSE, is2T); ++#endif ++ ++ for(i = 0 ; i < retryCount ; i++){ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ PathBOK = phy_PathB_IQK_8188E(pAdapter); ++#else ++ PathBOK = phy_PathB_IQK_8188E(pDM_Odm); ++#endif ++ if(PathBOK == 0x03){ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK Success!!\n")); ++ result[t][4] = (ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_B, bMaskDWord)&0x3FF0000)>>16; ++ result[t][5] = (ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_B, bMaskDWord)&0x3FF0000)>>16; ++ result[t][6] = (ODM_GetBBReg(pDM_Odm, rRx_Power_Before_IQK_B_2, bMaskDWord)&0x3FF0000)>>16; ++ result[t][7] = (ODM_GetBBReg(pDM_Odm, rRx_Power_After_IQK_B_2, bMaskDWord)&0x3FF0000)>>16; ++ break; ++ } ++ else if (i == (retryCount - 1) && PathBOK == 0x01) //Tx IQK OK ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Only Tx IQK Success!!\n")); ++ result[t][4] = (ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_B, bMaskDWord)&0x3FF0000)>>16; ++ result[t][5] = (ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_B, bMaskDWord)&0x3FF0000)>>16; ++ } ++ } ++ ++ if(0x00 == PathBOK){ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK failed!!\n")); ++ } ++ } ++ ++ //Back to BB mode, load original value ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:Back to BB mode, load original value!\n")); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0); ++ ++ if(t!=0) ++ { ++ if(!pDM_Odm->RFCalibrateInfo.bRfPiEnable){ ++ // Switch back BB to SI mode after finish IQ Calibration. ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ _PHY_PIModeSwitch(pAdapter, FALSE); ++#else ++ _PHY_PIModeSwitch(pDM_Odm, FALSE); ++#endif ++ } ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ ++ // Reload ADDA power saving parameters ++ _PHY_ReloadADDARegisters(pAdapter, ADDA_REG, pDM_Odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM); ++ ++ // Reload MAC parameters ++ _PHY_ReloadMACRegisters(pAdapter, IQK_MAC_REG, pDM_Odm->RFCalibrateInfo.IQK_MAC_backup); ++ ++ _PHY_ReloadADDARegisters(pAdapter, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM); ++#else ++ // Reload ADDA power saving parameters ++ _PHY_ReloadADDARegisters(pDM_Odm, ADDA_REG, pDM_Odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM); ++ ++ // Reload MAC parameters ++ _PHY_ReloadMACRegisters(pDM_Odm, IQK_MAC_REG, pDM_Odm->RFCalibrateInfo.IQK_MAC_backup); ++ ++ _PHY_ReloadADDARegisters(pDM_Odm, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM); ++#endif ++ ++ ++ // Restore RX initial gain ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00032ed3); ++ if(is2T){ ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00032ed3); ++ } ++ ++ //load 0xe30 IQC default value ++ ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00); ++ ++ ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_IQCalibrate_8188E() <==\n")); ++ ++} ++ ++ ++VOID ++phy_LCCalibrate_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN BOOLEAN is2T ++ ) ++{ ++ u1Byte tmpReg; ++ u4Byte RF_Amode=0, RF_Bmode=0, LC_Cal; ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ //Check continuous TX and Packet TX ++ tmpReg = ODM_Read1Byte(pDM_Odm, 0xd03); ++ ++ if((tmpReg&0x70) != 0) //Deal with contisuous TX case ++ ODM_Write1Byte(pDM_Odm, 0xd03, tmpReg&0x8F); //disable all continuous TX ++ else // Deal with Packet TX case ++ ODM_Write1Byte(pDM_Odm, REG_TXPAUSE, 0xFF); // block all queues ++ ++ if((tmpReg&0x70) != 0) ++ { ++ //1. Read original RF mode ++ //Path-A ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ RF_Amode = PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_AC, bMask12Bits); ++ ++ //Path-B ++ if(is2T) ++ RF_Bmode = PHY_QueryRFReg(pAdapter, RF_PATH_B, RF_AC, bMask12Bits); ++#else ++ RF_Amode = ODM_GetRFReg(pDM_Odm, RF_PATH_A, RF_AC, bMask12Bits); ++ ++ //Path-B ++ if(is2T) ++ RF_Bmode = ODM_GetRFReg(pDM_Odm, RF_PATH_B, RF_AC, bMask12Bits); ++#endif ++ ++ //2. Set RF mode = standby mode ++ //Path-A ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_AC, bMask12Bits, (RF_Amode&0x8FFFF)|0x10000); ++ ++ //Path-B ++ if(is2T) ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, RF_AC, bMask12Bits, (RF_Bmode&0x8FFFF)|0x10000); ++ } ++ ++ //3. Read RF reg18 ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ LC_Cal = PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_CHNLBW, bMask12Bits); ++#else ++ LC_Cal = ODM_GetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, bMask12Bits); ++#endif ++ ++ //4. Set LC calibration begin bit15 ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, bMask12Bits, LC_Cal|0x08000); ++ ++ ODM_sleep_ms(100); ++ ++ ++ //Restore original situation ++ if((tmpReg&0x70) != 0) //Deal with contisuous TX case ++ { ++ //Path-A ++ ODM_Write1Byte(pDM_Odm, 0xd03, tmpReg); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_AC, bMask12Bits, RF_Amode); ++ ++ //Path-B ++ if(is2T) ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, RF_AC, bMask12Bits, RF_Bmode); ++ } ++ else // Deal with Packet TX case ++ { ++ ODM_Write1Byte(pDM_Odm, REG_TXPAUSE, 0x00); ++ } ++} ++ ++//Analog Pre-distortion calibration ++#define APK_BB_REG_NUM 8 ++#define APK_CURVE_REG_NUM 4 ++#define PATH_NUM 2 ++ ++VOID ++phy_APCalibrate_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN s1Byte delta, ++ IN BOOLEAN is2T ++ ) ++{ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ u4Byte regD[PATH_NUM]; ++ u4Byte tmpReg, index, offset, apkbound; ++ u1Byte path, i, pathbound = PATH_NUM; ++ u4Byte BB_backup[APK_BB_REG_NUM]; ++ u4Byte BB_REG[APK_BB_REG_NUM] = { ++ rFPGA1_TxBlock, rOFDM0_TRxPathEnable, ++ rFPGA0_RFMOD, rOFDM0_TRMuxPar, ++ rFPGA0_XCD_RFInterfaceSW, rFPGA0_XAB_RFInterfaceSW, ++ rFPGA0_XA_RFInterfaceOE, rFPGA0_XB_RFInterfaceOE }; ++ u4Byte BB_AP_MODE[APK_BB_REG_NUM] = { ++ 0x00000020, 0x00a05430, 0x02040000, ++ 0x000800e4, 0x00204000 }; ++ u4Byte BB_normal_AP_MODE[APK_BB_REG_NUM] = { ++ 0x00000020, 0x00a05430, 0x02040000, ++ 0x000800e4, 0x22204000 }; ++ ++ u4Byte AFE_backup[IQK_ADDA_REG_NUM]; ++ u4Byte AFE_REG[IQK_ADDA_REG_NUM] = { ++ rFPGA0_XCD_SwitchControl, rBlue_Tooth, ++ rRx_Wait_CCA, rTx_CCK_RFON, ++ rTx_CCK_BBON, rTx_OFDM_RFON, ++ rTx_OFDM_BBON, rTx_To_Rx, ++ rTx_To_Tx, rRx_CCK, ++ rRx_OFDM, rRx_Wait_RIFS, ++ rRx_TO_Rx, rStandby, ++ rSleep, rPMPD_ANAEN }; ++ ++ u4Byte MAC_backup[IQK_MAC_REG_NUM]; ++ u4Byte MAC_REG[IQK_MAC_REG_NUM] = { ++ REG_TXPAUSE, REG_BCN_CTRL, ++ REG_BCN_CTRL_1, REG_GPIO_MUXCFG}; ++ ++ u4Byte APK_RF_init_value[PATH_NUM][APK_BB_REG_NUM] = { ++ {0x0852c, 0x1852c, 0x5852c, 0x1852c, 0x5852c}, ++ {0x2852e, 0x0852e, 0x3852e, 0x0852e, 0x0852e} ++ }; ++ ++ u4Byte APK_normal_RF_init_value[PATH_NUM][APK_BB_REG_NUM] = { ++ {0x0852c, 0x0a52c, 0x3a52c, 0x5a52c, 0x5a52c}, //path settings equal to path b settings ++ {0x0852c, 0x0a52c, 0x5a52c, 0x5a52c, 0x5a52c} ++ }; ++ ++ u4Byte APK_RF_value_0[PATH_NUM][APK_BB_REG_NUM] = { ++ {0x52019, 0x52014, 0x52013, 0x5200f, 0x5208d}, ++ {0x5201a, 0x52019, 0x52016, 0x52033, 0x52050} ++ }; ++ ++ u4Byte APK_normal_RF_value_0[PATH_NUM][APK_BB_REG_NUM] = { ++ {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a}, //path settings equal to path b settings ++ {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a} ++ }; ++ ++ u4Byte AFE_on_off[PATH_NUM] = { ++ 0x04db25a4, 0x0b1b25a4}; //path A on path B off / path A off path B on ++ ++ u4Byte APK_offset[PATH_NUM] = { ++ rConfig_AntA, rConfig_AntB}; ++ ++ u4Byte APK_normal_offset[PATH_NUM] = { ++ rConfig_Pmpd_AntA, rConfig_Pmpd_AntB}; ++ ++ u4Byte APK_value[PATH_NUM] = { ++ 0x92fc0000, 0x12fc0000}; ++ ++ u4Byte APK_normal_value[PATH_NUM] = { ++ 0x92680000, 0x12680000}; ++ ++ s1Byte APK_delta_mapping[APK_BB_REG_NUM][13] = { ++ {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, ++ {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, ++ {-6, -4, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, ++ {-1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6}, ++ {-11, -9, -7, -5, -3, -1, 0, 0, 0, 0, 0, 0, 0} ++ }; ++ ++ u4Byte APK_normal_setting_value_1[13] = { ++ 0x01017018, 0xf7ed8f84, 0x1b1a1816, 0x2522201e, 0x322e2b28, ++ 0x433f3a36, 0x5b544e49, 0x7b726a62, 0xa69a8f84, 0xdfcfc0b3, ++ 0x12680000, 0x00880000, 0x00880000 ++ }; ++ ++ u4Byte APK_normal_setting_value_2[16] = { ++ 0x01c7021d, 0x01670183, 0x01000123, 0x00bf00e2, 0x008d00a3, ++ 0x0068007b, 0x004d0059, 0x003a0042, 0x002b0031, 0x001f0025, ++ 0x0017001b, 0x00110014, 0x000c000f, 0x0009000b, 0x00070008, ++ 0x00050006 ++ }; ++ ++ u4Byte APK_result[PATH_NUM][APK_BB_REG_NUM]; //val_1_1a, val_1_2a, val_2a, val_3a, val_4a ++// u4Byte AP_curve[PATH_NUM][APK_CURVE_REG_NUM]; ++ ++ s4Byte BB_offset, delta_V, delta_offset; ++ ++#if MP_DRIVER == 1 ++if ( *(pDM_Odm->mp_mode) == 1) ++{ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.MptCtx); ++#else ++ PMPT_CONTEXT pMptCtx = &(pAdapter->MptCtx); ++#endif ++ pMptCtx->APK_bound[0] = 45; ++ pMptCtx->APK_bound[1] = 52; ++} ++#endif ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("==>phy_APCalibrate_8188E() delta %d\n", delta)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("AP Calibration for %s\n", (is2T ? "2T2R" : "1T1R"))); ++ if(!is2T) ++ pathbound = 1; ++ ++ //2 FOR NORMAL CHIP SETTINGS ++ ++// Temporarily do not allow normal driver to do the following settings because these offset ++// and value will cause RF internal PA to be unpredictably disabled by HW, such that RF Tx signal ++// will disappear after disable/enable card many times on 88CU. RF SD and DD have not find the ++// root cause, so we remove these actions temporarily. Added by tynli and SD3 Allen. 2010.05.31. ++//#if MP_DRIVER != 1 ++if (*(pDM_Odm->mp_mode) != 1) ++ return; ++//#endif ++ //settings adjust for normal chip ++ for(index = 0; index < PATH_NUM; index ++) ++ { ++ APK_offset[index] = APK_normal_offset[index]; ++ APK_value[index] = APK_normal_value[index]; ++ AFE_on_off[index] = 0x6fdb25a4; ++ } ++ ++ for(index = 0; index < APK_BB_REG_NUM; index ++) ++ { ++ for(path = 0; path < pathbound; path++) ++ { ++ APK_RF_init_value[path][index] = APK_normal_RF_init_value[path][index]; ++ APK_RF_value_0[path][index] = APK_normal_RF_value_0[path][index]; ++ } ++ BB_AP_MODE[index] = BB_normal_AP_MODE[index]; ++ } ++ ++ apkbound = 6; ++ ++ //save BB default value ++ for(index = 0; index < APK_BB_REG_NUM ; index++) ++ { ++ if(index == 0) //skip ++ continue; ++ BB_backup[index] = ODM_GetBBReg(pDM_Odm, BB_REG[index], bMaskDWord); ++ } ++ ++ //save MAC default value ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ _PHY_SaveMACRegisters(pAdapter, MAC_REG, MAC_backup); ++ ++ //save AFE default value ++ _PHY_SaveADDARegisters(pAdapter, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); ++#else ++ _PHY_SaveMACRegisters(pDM_Odm, MAC_REG, MAC_backup); ++ ++ //save AFE default value ++ _PHY_SaveADDARegisters(pDM_Odm, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); ++#endif ++ ++ for(path = 0; path < pathbound; path++) ++ { ++ ++ ++ if(path == RF_PATH_A) ++ { ++ //path A APK ++ //load APK setting ++ //path-A ++ offset = rPdp_AntA; ++ for(index = 0; index < 11; index ++) ++ { ++ ODM_SetBBReg(pDM_Odm, offset, bMaskDWord, APK_normal_setting_value_1[index]); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", offset, ODM_GetBBReg(pDM_Odm, offset, bMaskDWord))); ++ ++ offset += 0x04; ++ } ++ ++ ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x12680000); ++ ++ offset = rConfig_AntA; ++ for(; index < 13; index ++) ++ { ++ ODM_SetBBReg(pDM_Odm, offset, bMaskDWord, APK_normal_setting_value_1[index]); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", offset, ODM_GetBBReg(pDM_Odm, offset, bMaskDWord))); ++ ++ offset += 0x04; ++ } ++ ++ //page-B1 ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x40000000); ++ ++ //path A ++ offset = rPdp_AntA; ++ for(index = 0; index < 16; index++) ++ { ++ ODM_SetBBReg(pDM_Odm, offset, bMaskDWord, APK_normal_setting_value_2[index]); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", offset, ODM_GetBBReg(pDM_Odm, offset, bMaskDWord))); ++ ++ offset += 0x04; ++ } ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ } ++ else if(path == RF_PATH_B) ++ { ++ //path B APK ++ //load APK setting ++ //path-B ++ offset = rPdp_AntB; ++ for(index = 0; index < 10; index ++) ++ { ++ ODM_SetBBReg(pDM_Odm, offset, bMaskDWord, APK_normal_setting_value_1[index]); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", offset, ODM_GetBBReg(pDM_Odm, offset, bMaskDWord))); ++ ++ offset += 0x04; ++ } ++ ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntA, bMaskDWord, 0x12680000); ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ PHY_SetBBReg(pAdapter, rConfig_Pmpd_AntB, bMaskDWord, 0x12680000); ++#else ++ PHY_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x12680000); ++#endif ++ ++ offset = rConfig_AntA; ++ index = 11; ++ for(; index < 13; index ++) //offset 0xb68, 0xb6c ++ { ++ ODM_SetBBReg(pDM_Odm, offset, bMaskDWord, APK_normal_setting_value_1[index]); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", offset, ODM_GetBBReg(pDM_Odm, offset, bMaskDWord))); ++ ++ offset += 0x04; ++ } ++ ++ //page-B1 ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x40000000); ++ ++ //path B ++ offset = 0xb60; ++ for(index = 0; index < 16; index++) ++ { ++ ODM_SetBBReg(pDM_Odm, offset, bMaskDWord, APK_normal_setting_value_2[index]); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", offset, ODM_GetBBReg(pDM_Odm, offset, bMaskDWord))); ++ ++ offset += 0x04; ++ } ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0); ++ } ++ ++ //save RF default value ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ regD[path] = PHY_QueryRFReg(pAdapter, path, RF_TXBIAS_A, bMaskDWord); ++#else ++ regD[path] = ODM_GetRFReg(pDM_Odm, path, RF_TXBIAS_A, bMaskDWord); ++#endif ++ ++ //Path A AFE all on, path B AFE All off or vise versa ++ for(index = 0; index < IQK_ADDA_REG_NUM ; index++) ++ ODM_SetBBReg(pDM_Odm, AFE_REG[index], bMaskDWord, AFE_on_off[path]); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xe70 %x\n", ODM_GetBBReg(pDM_Odm, rRx_Wait_CCA, bMaskDWord))); ++ ++ //BB to AP mode ++ if(path == 0) ++ { ++ for(index = 0; index < APK_BB_REG_NUM ; index++) ++ { ++ ++ if(index == 0) //skip ++ continue; ++ else if (index < 5) ++ ODM_SetBBReg(pDM_Odm, BB_REG[index], bMaskDWord, BB_AP_MODE[index]); ++ else if (BB_REG[index] == 0x870) ++ ODM_SetBBReg(pDM_Odm, BB_REG[index], bMaskDWord, BB_backup[index]|BIT10|BIT26); ++ else ++ ODM_SetBBReg(pDM_Odm, BB_REG[index], BIT10, 0x0); ++ } ++ ++ ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00); ++ } ++ else //path B ++ { ++ ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_B, bMaskDWord, 0x01008c00); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_B, bMaskDWord, 0x01008c00); ++ ++ } ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x800 %x\n", ODM_GetBBReg(pDM_Odm, 0x800, bMaskDWord))); ++ ++ //MAC settings ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ _PHY_MACSettingCalibration(pAdapter, MAC_REG, MAC_backup); ++#else ++ _PHY_MACSettingCalibration(pDM_Odm, MAC_REG, MAC_backup); ++#endif ++ ++ if(path == RF_PATH_A) //Path B to standby mode ++ { ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, RF_AC, bMaskDWord, 0x10000); ++ } ++ else //Path A to standby mode ++ { ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_AC, bMaskDWord, 0x10000); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_MODE1, bMaskDWord, 0x1000f); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_MODE2, bMaskDWord, 0x20103); ++ } ++ ++ delta_offset = ((delta+14)/2); ++ if(delta_offset < 0) ++ delta_offset = 0; ++ else if (delta_offset > 12) ++ delta_offset = 12; ++ ++ //AP calibration ++ for(index = 0; index < APK_BB_REG_NUM; index++) ++ { ++ if(index != 1) //only DO PA11+PAD01001, AP RF setting ++ continue; ++ ++ tmpReg = APK_RF_init_value[path][index]; ++#if 1 ++ if(!pDM_Odm->RFCalibrateInfo.bAPKThermalMeterIgnore) ++ { ++ BB_offset = (tmpReg & 0xF0000) >> 16; ++ ++ if(!(tmpReg & BIT15)) //sign bit 0 ++ { ++ BB_offset = -BB_offset; ++ } ++ ++ delta_V = APK_delta_mapping[index][delta_offset]; ++ ++ BB_offset += delta_V; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() APK index %d tmpReg 0x%x delta_V %d delta_offset %d\n", index, tmpReg, delta_V, delta_offset)); ++ ++ if(BB_offset < 0) ++ { ++ tmpReg = tmpReg & (~BIT15); ++ BB_offset = -BB_offset; ++ } ++ else ++ { ++ tmpReg = tmpReg | BIT15; ++ } ++ tmpReg = (tmpReg & 0xFFF0FFFF) | (BB_offset << 16); ++ } ++#endif ++ ++ ODM_SetRFReg(pDM_Odm, path, RF_IPA_A, bMaskDWord, 0x8992e); ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xc %x\n", PHY_QueryRFReg(pAdapter, path, RF_IPA_A, bMaskDWord))); ++ ODM_SetRFReg(pDM_Odm, path, RF_AC, bMaskDWord, APK_RF_value_0[path][index]); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x0 %x\n", PHY_QueryRFReg(pAdapter, path, RF_AC, bMaskDWord))); ++ ODM_SetRFReg(pDM_Odm, path, RF_TXBIAS_A, bMaskDWord, tmpReg); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xd %x\n", PHY_QueryRFReg(pAdapter, path, RF_TXBIAS_A, bMaskDWord))); ++#else ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xc %x\n", ODM_GetRFReg(pDM_Odm, path, RF_IPA_A, bMaskDWord))); ++ ODM_SetRFReg(pDM_Odm, path, RF_AC, bMaskDWord, APK_RF_value_0[path][index]); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x0 %x\n", ODM_GetRFReg(pDM_Odm, path, RF_AC, bMaskDWord))); ++ ODM_SetRFReg(pDM_Odm, path, RF_TXBIAS_A, bMaskDWord, tmpReg); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xd %x\n", ODM_GetRFReg(pDM_Odm, path, RF_TXBIAS_A, bMaskDWord))); ++#endif ++ ++ // PA11+PAD01111, one shot ++ i = 0; ++ do ++ { ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80000000); ++ { ++ ODM_SetBBReg(pDM_Odm, APK_offset[path], bMaskDWord, APK_value[0]); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", APK_offset[path], ODM_GetBBReg(pDM_Odm, APK_offset[path], bMaskDWord))); ++ ODM_delay_ms(3); ++ ODM_SetBBReg(pDM_Odm, APK_offset[path], bMaskDWord, APK_value[1]); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", APK_offset[path], ODM_GetBBReg(pDM_Odm, APK_offset[path], bMaskDWord))); ++ ++ ODM_delay_ms(20); ++ } ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ ++ if(path == RF_PATH_A) ++ tmpReg = ODM_GetBBReg(pDM_Odm, rAPK, 0x03E00000); ++ else ++ tmpReg = ODM_GetBBReg(pDM_Odm, rAPK, 0xF8000000); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xbd8[25:21] %x\n", tmpReg)); ++ ++ ++ i++; ++ } ++ while(tmpReg > apkbound && i < 4); ++ ++ APK_result[path][index] = tmpReg; ++ } ++ } ++ ++ //reload MAC default value ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ _PHY_ReloadMACRegisters(pAdapter, MAC_REG, MAC_backup); ++#else ++ _PHY_ReloadMACRegisters(pDM_Odm, MAC_REG, MAC_backup); ++#endif ++ ++ //reload BB default value ++ for(index = 0; index < APK_BB_REG_NUM ; index++) ++ { ++ ++ if(index == 0) //skip ++ continue; ++ ODM_SetBBReg(pDM_Odm, BB_REG[index], bMaskDWord, BB_backup[index]); ++ } ++ ++ //reload AFE default value ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ _PHY_ReloadADDARegisters(pAdapter, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); ++#else ++ _PHY_ReloadADDARegisters(pDM_Odm, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); ++#endif ++ ++ //reload RF path default value ++ for(path = 0; path < pathbound; path++) ++ { ++ ODM_SetRFReg(pDM_Odm, path, 0xd, bMaskDWord, regD[path]); ++ if(path == RF_PATH_B) ++ { ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_MODE1, bMaskDWord, 0x1000f); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_MODE2, bMaskDWord, 0x20101); ++ } ++ ++ //note no index == 0 ++ if (APK_result[path][1] > 6) ++ APK_result[path][1] = 6; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("apk path %d result %d 0x%x \t", path, 1, APK_result[path][1])); ++ } ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("\n")); ++ ++ ++ for(path = 0; path < pathbound; path++) ++ { ++ ODM_SetRFReg(pDM_Odm, path, 0x3, bMaskDWord, ++ ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (APK_result[path][1] << 5) | APK_result[path][1])); ++ if(path == RF_PATH_A) ++ ODM_SetRFReg(pDM_Odm, path, 0x4, bMaskDWord, ++ ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (0x00 << 5) | 0x05)); ++ else ++ ODM_SetRFReg(pDM_Odm, path, 0x4, bMaskDWord, ++ ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (0x02 << 5) | 0x05)); ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ if(!IS_HARDWARE_TYPE_8723A(pAdapter)) ++ ODM_SetRFReg(pDM_Odm, path, RF_BS_PA_APSET_G9_G11, bMaskDWord, ++ ((0x08 << 15) | (0x08 << 10) | (0x08 << 5) | 0x08)); ++#endif ++ } ++ ++ pDM_Odm->RFCalibrateInfo.bAPKdone = TRUE; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("<==phy_APCalibrate_8188E()\n")); ++} ++ ++ ++ ++#define DP_BB_REG_NUM 7 ++#define DP_RF_REG_NUM 1 ++#define DP_RETRY_LIMIT 10 ++#define DP_PATH_NUM 2 ++#define DP_DPK_NUM 3 ++#define DP_DPK_VALUE_NUM 2 ++ ++ ++ ++ ++ ++VOID ++PHY_IQCalibrate_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN BOOLEAN bReCovery ++ ) ++{ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #else // (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ ++ #if (MP_DRIVER == 1) ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PMPT_CONTEXT pMptCtx = &(pAdapter->MptCtx); ++ #else// (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.MptCtx); ++ #endif ++ #endif//(MP_DRIVER == 1) ++#endif ++ ++ s4Byte result[4][8]; //last is final result ++ u1Byte i, final_candidate, Indexforchannel; ++ u1Byte channelToIQK = 7; ++ BOOLEAN bPathAOK, bPathBOK; ++ s4Byte RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC, RegTmp = 0; ++ BOOLEAN is12simular, is13simular, is23simular; ++ BOOLEAN bStartContTx = FALSE, bSingleTone = FALSE, bCarrierSuppression = FALSE; ++ u4Byte IQK_BB_REG_92C[IQK_BB_REG_NUM] = { ++ rOFDM0_XARxIQImbalance, rOFDM0_XBRxIQImbalance, ++ rOFDM0_ECCAThreshold, rOFDM0_AGCRSSITable, ++ rOFDM0_XATxIQImbalance, rOFDM0_XBTxIQImbalance, ++ rOFDM0_XCTxAFE, rOFDM0_XDTxAFE, ++ rOFDM0_RxIQExtAnta}; ++ BOOLEAN is2T; ++ ++ is2T = (pDM_Odm->RFType == ODM_2T2R)?TRUE:FALSE; ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE) ) ++ if (ODM_CheckPowerStatus(pAdapter) == FALSE) ++ return; ++#else ++ prtl8192cd_priv priv = pDM_Odm->priv; ++ ++#ifdef MP_TEST ++ if(priv->pshare->rf_ft_var.mp_specific) ++ { ++ if((OPMODE & WIFI_MP_CTX_PACKET) || (OPMODE & WIFI_MP_CTX_ST)) ++ return; ++ } ++#endif ++ ++ if(priv->pshare->IQK_88E_done) ++ bReCovery= 1; ++ priv->pshare->IQK_88E_done = 1; ++ ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ if(!(pDM_Odm->SupportAbility & ODM_RF_CALIBRATION)) ++ { ++ return; ++ } ++#endif ++ ++#if MP_DRIVER == 1 ++if (*(pDM_Odm->mp_mode) == 1) ++{ ++ bStartContTx = pMptCtx->bStartContTx; ++ bSingleTone = pMptCtx->bSingleTone; ++ bCarrierSuppression = pMptCtx->bCarrierSuppression; ++} ++#endif ++ ++ // 20120213 Turn on when continuous Tx to pass lab testing. (required by Edlu) ++ if(bSingleTone || bCarrierSuppression) ++ return; ++ ++#if DISABLE_BB_RF ++ return; ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_AP)) ++ if(bReCovery) ++#else//for ODM_MP ++ if(bReCovery && (!pAdapter->bInHctTest)) //YJ,add for PowerTest,120405 ++#endif ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("PHY_IQCalibrate_8188E: Return due to bReCovery!\n")); ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ _PHY_ReloadADDARegisters(pAdapter, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup_recover, 9); ++#else ++ _PHY_ReloadADDARegisters(pDM_Odm, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup_recover, 9); ++#endif ++ return; ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:Start!!!\n")); ++ ++#if 0//Suggested by Edlu,120413 ++ ++ // IQK on channel 7, should switch back when completed. ++ //originChannel = pHalData->CurrentChannel; ++ originChannel = *(pDM_Odm->pChannel); ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ pAdapter->HalFunc.SwChnlByTimerHandler(pAdapter, channelToIQK); ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ pAdapter->HalFunc.set_channel_handler(pAdapter, channelToIQK); ++#endif ++ ++#endif ++ ++ for(i = 0; i < 8; i++) ++ { ++ result[0][i] = 0; ++ result[1][i] = 0; ++ result[2][i] = 0; ++ if((i==0) ||(i==2) || (i==4) || (i==6)) ++ result[3][i] = 0x100; ++ else ++ result[3][i] = 0; ++ } ++ final_candidate = 0xff; ++ bPathAOK = FALSE; ++ bPathBOK = FALSE; ++ is12simular = FALSE; ++ is23simular = FALSE; ++ is13simular = FALSE; ++ ++ ++ //ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK !!!interface %d currentband %d ishardwareD %d \n", pDM_Odm->interfaceIndex, pHalData->CurrentBandType92D, IS_HARDWARE_TYPE_8192D(pAdapter))); ++// RT_TRACE(COMP_INIT,DBG_LOUD,("Acquire Mutex in IQCalibrate \n")); ++ for (i=0; i<3; i++) ++ { ++ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ phy_IQCalibrate_8188E(pAdapter, result, i, is2T); ++#else ++ phy_IQCalibrate_8188E(pDM_Odm, result, i, is2T); ++#endif ++ ++ ++ if(i == 1) ++ { ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ is12simular = phy_SimularityCompare_8188E(pAdapter, result, 0, 1); ++#else ++ is12simular = phy_SimularityCompare_8188E(pDM_Odm, result, 0, 1); ++#endif ++ if(is12simular) ++ { ++ final_candidate = 0; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is12simular final_candidate is %x\n",final_candidate)); ++ break; ++ } ++ } ++ ++ if(i == 2) ++ { ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ is13simular = phy_SimularityCompare_8188E(pAdapter, result, 0, 2); ++#else ++ is13simular = phy_SimularityCompare_8188E(pDM_Odm, result, 0, 2); ++#endif ++ if(is13simular) ++ { ++ final_candidate = 0; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is13simular final_candidate is %x\n",final_candidate)); ++ ++ break; ++ } ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ is23simular = phy_SimularityCompare_8188E(pAdapter, result, 1, 2); ++#else ++ is23simular = phy_SimularityCompare_8188E(pDM_Odm, result, 1, 2); ++#endif ++ if(is23simular) ++ { ++ final_candidate = 1; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is23simular final_candidate is %x\n",final_candidate)); ++ } ++ else ++ { ++ /* ++ for(i = 0; i < 8; i++) ++ RegTmp += result[3][i]; ++ ++ if(RegTmp != 0) ++ final_candidate = 3; ++ else ++ final_candidate = 0xFF; ++ */ ++ final_candidate = 3; ++ } ++ } ++ } ++// RT_TRACE(COMP_INIT,DBG_LOUD,("Release Mutex in IQCalibrate \n")); ++ ++ for (i=0; i<4; i++) ++ { ++ RegE94 = result[i][0]; ++ RegE9C = result[i][1]; ++ RegEA4 = result[i][2]; ++ RegEAC = result[i][3]; ++ RegEB4 = result[i][4]; ++ RegEBC = result[i][5]; ++ RegEC4 = result[i][6]; ++ RegECC = result[i][7]; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: RegE94=%x RegE9C=%x RegEA4=%x RegEAC=%x RegEB4=%x RegEBC=%x RegEC4=%x RegECC=%x\n ", RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC)); ++ } ++ ++ if(final_candidate != 0xff) ++ { ++ pDM_Odm->RFCalibrateInfo.RegE94 = RegE94 = result[final_candidate][0]; ++ pDM_Odm->RFCalibrateInfo.RegE9C = RegE9C = result[final_candidate][1]; ++ RegEA4 = result[final_candidate][2]; ++ RegEAC = result[final_candidate][3]; ++ pDM_Odm->RFCalibrateInfo.RegEB4 = RegEB4 = result[final_candidate][4]; ++ pDM_Odm->RFCalibrateInfo.RegEBC = RegEBC = result[final_candidate][5]; ++ RegEC4 = result[final_candidate][6]; ++ RegECC = result[final_candidate][7]; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: final_candidate is %x\n",final_candidate)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: RegE94=%x RegE9C=%x RegEA4=%x RegEAC=%x RegEB4=%x RegEBC=%x RegEC4=%x RegECC=%x\n ", RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC)); ++ bPathAOK = bPathBOK = TRUE; ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: FAIL use default value\n")); ++ ++ pDM_Odm->RFCalibrateInfo.RegE94 = pDM_Odm->RFCalibrateInfo.RegEB4 = 0x100; //X default value ++ pDM_Odm->RFCalibrateInfo.RegE9C = pDM_Odm->RFCalibrateInfo.RegEBC = 0x0; //Y default value ++ } ++ ++ if((RegE94 != 0)/*&&(RegEA4 != 0)*/) ++ { ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ _PHY_PathAFillIQKMatrix(pAdapter, bPathAOK, result, final_candidate, (RegEA4 == 0)); ++#else ++ _PHY_PathAFillIQKMatrix(pDM_Odm, bPathAOK, result, final_candidate, (RegEA4 == 0)); ++#endif ++ } ++ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ if (is2T) ++ { ++ if((RegEB4 != 0)/*&&(RegEC4 != 0)*/) ++ { ++ _PHY_PathBFillIQKMatrix(pAdapter, bPathBOK, result, final_candidate, (RegEC4 == 0)); ++ } ++ } ++#endif ++ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ Indexforchannel = ODM_GetRightChnlPlaceforIQK(pHalData->CurrentChannel); ++#else ++ Indexforchannel = 0; ++#endif ++ ++//To Fix BSOD when final_candidate is 0xff ++//by sherry 20120321 ++ if(final_candidate < 4) ++ { ++ for(i = 0; i < IQK_Matrix_REG_NUM; i++) ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][i] = result[final_candidate][i]; ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].bIQKDone = TRUE; ++ } ++ //RTPRINT(FINIT, INIT_IQK, ("\nIQK OK Indexforchannel %d.\n", Indexforchannel)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("\nIQK OK Indexforchannel %d.\n", Indexforchannel)); ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ ++ _PHY_SaveADDARegisters(pAdapter, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup_recover, 9); ++#else ++ _PHY_SaveADDARegisters(pDM_Odm, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup_recover, IQK_BB_REG_NUM); ++#endif ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK finished\n")); ++#if 0 //Suggested by Edlu,120413 ++ ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ pAdapter->HalFunc.SwChnlByTimerHandler(pAdapter, originChannel); ++ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ pAdapter->HalFunc.set_channel_handler(pAdapter, originChannel); ++ #endif ++ ++#endif ++ ++} ++ ++ ++VOID ++PHY_LCCalibrate_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm ++#else ++ IN PADAPTER pAdapter ++#endif ++ ) ++{ ++ BOOLEAN bStartContTx = FALSE, bSingleTone = FALSE, bCarrierSuppression = FALSE; ++ u4Byte timeout = 2000, timecount = 0; ++ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #else // (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ ++ #if (MP_DRIVER == 1) ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PMPT_CONTEXT pMptCtx = &(pAdapter->MptCtx); ++ #else// (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.MptCtx); ++ #endif ++ #endif//(MP_DRIVER == 1) ++#endif ++ ++ ++ ++ ++#if MP_DRIVER == 1 ++if (*(pDM_Odm->mp_mode) == 1) ++{ ++ bStartContTx = pMptCtx->bStartContTx; ++ bSingleTone = pMptCtx->bSingleTone; ++ bCarrierSuppression = pMptCtx->bCarrierSuppression; ++} ++#endif ++ ++ ++#if DISABLE_BB_RF ++ return; ++#endif ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ if(!(pDM_Odm->SupportAbility & ODM_RF_CALIBRATION)) ++ { ++ return; ++ } ++#endif ++ // 20120213 Turn on when continuous Tx to pass lab testing. (required by Edlu) ++ if(bSingleTone || bCarrierSuppression) ++ return; ++ ++ while(*(pDM_Odm->pbScanInProcess) && timecount < timeout) ++ { ++ ODM_delay_ms(50); ++ timecount += 50; ++ } ++ ++ pDM_Odm->RFCalibrateInfo.bLCKInProgress = TRUE; ++ ++ //ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LCK:Start!!!interface %d currentband %x delay %d ms\n", pDM_Odm->interfaceIndex, pHalData->CurrentBandType92D, timecount)); ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ ++ if(pDM_Odm->RFType == ODM_2T2R) ++ { ++ phy_LCCalibrate_8188E(pAdapter, TRUE); ++ } ++ else ++#endif ++ { ++ // For 88C 1T1R ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ phy_LCCalibrate_8188E(pAdapter, FALSE); ++#else ++ phy_LCCalibrate_8188E(pDM_Odm, FALSE); ++#endif ++ } ++ ++ pDM_Odm->RFCalibrateInfo.bLCKInProgress = FALSE; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LCK:Finish!!!interface %d\n", pDM_Odm->InterfaceIndex)); ++ ++} ++ ++VOID ++PHY_APCalibrate_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN s1Byte delta ++ ) ++{ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++#if DISABLE_BB_RF ++ return; ++#endif ++ ++ return; ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ if(!(pDM_Odm->SupportAbility & ODM_RF_CALIBRATION)) ++ { ++ return; ++ } ++#endif ++ ++#if FOR_BRAZIL_PRETEST != 1 ++ if(pDM_Odm->RFCalibrateInfo.bAPKdone) ++#endif ++ return; ++ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ if(pDM_Odm->RFType == ODM_2T2R){ ++ phy_APCalibrate_8188E(pAdapter, delta, TRUE); ++ } ++ else ++#endif ++ { ++ // For 88C 1T1R ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ phy_APCalibrate_8188E(pAdapter, delta, FALSE); ++#else ++ phy_APCalibrate_8188E(pDM_Odm, delta, FALSE); ++#endif ++ } ++} ++VOID phy_SetRFPathSwitch_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN BOOLEAN bMain, ++ IN BOOLEAN is2T ++ ) ++{ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #elif (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++ ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ if(!pAdapter->bHWInitReady) ++ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ if(pAdapter->hw_init_completed == _FALSE) ++ #endif ++ { ++ u1Byte u1bTmp; ++ u1bTmp = ODM_Read1Byte(pDM_Odm, REG_LEDCFG2) | BIT7; ++ ODM_Write1Byte(pDM_Odm, REG_LEDCFG2, u1bTmp); ++ //ODM_SetBBReg(pDM_Odm, REG_LEDCFG0, BIT23, 0x01); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XAB_RFParameter, BIT13, 0x01); ++ } ++ ++#endif ++ ++ if(is2T) //92C ++ { ++ if(bMain) ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XB_RFInterfaceOE, BIT5|BIT6, 0x1); //92C_Path_A ++ else ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XB_RFInterfaceOE, BIT5|BIT6, 0x2); //BT ++ } ++ else //88C ++ { ++ ++ if(bMain) ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, BIT8|BIT9, 0x2); //Main ++ else ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, BIT8|BIT9, 0x1); //Aux ++ } ++} ++VOID PHY_SetRFPathSwitch_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN BOOLEAN bMain ++ ) ++{ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ ++ ++#if DISABLE_BB_RF ++ return; ++#endif ++ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ if(pDM_Odm->RFType == ODM_2T2R) ++ { ++ phy_SetRFPathSwitch_8188E(pAdapter, bMain, TRUE); ++ } ++ else ++#endif ++ { ++ // For 88C 1T1R ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ phy_SetRFPathSwitch_8188E(pAdapter, bMain, FALSE); ++#else ++ phy_SetRFPathSwitch_8188E(pDM_Odm, bMain, FALSE); ++#endif ++ } ++} ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++//digital predistortion ++VOID ++phy_DigitalPredistortion( ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PADAPTER pAdapter, ++#else ++ IN PDM_ODM_T pDM_Odm, ++#endif ++ IN BOOLEAN is2T ++ ) ++{ ++#if ( RT_PLATFORM == PLATFORM_WINDOWS) ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ ++ u4Byte tmpReg, tmpReg2, index, i; ++ u1Byte path, pathbound = PATH_NUM; ++ u4Byte AFE_backup[IQK_ADDA_REG_NUM]; ++ u4Byte AFE_REG[IQK_ADDA_REG_NUM] = { ++ rFPGA0_XCD_SwitchControl, rBlue_Tooth, ++ rRx_Wait_CCA, rTx_CCK_RFON, ++ rTx_CCK_BBON, rTx_OFDM_RFON, ++ rTx_OFDM_BBON, rTx_To_Rx, ++ rTx_To_Tx, rRx_CCK, ++ rRx_OFDM, rRx_Wait_RIFS, ++ rRx_TO_Rx, rStandby, ++ rSleep, rPMPD_ANAEN }; ++ ++ u4Byte BB_backup[DP_BB_REG_NUM]; ++ u4Byte BB_REG[DP_BB_REG_NUM] = { ++ rOFDM0_TRxPathEnable, rFPGA0_RFMOD, ++ rOFDM0_TRMuxPar, rFPGA0_XCD_RFInterfaceSW, ++ rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE, ++ rFPGA0_XB_RFInterfaceOE}; ++ u4Byte BB_settings[DP_BB_REG_NUM] = { ++ 0x00a05430, 0x02040000, 0x000800e4, 0x22208000, ++ 0x0, 0x0, 0x0}; ++ ++ u4Byte RF_backup[DP_PATH_NUM][DP_RF_REG_NUM]; ++ u4Byte RF_REG[DP_RF_REG_NUM] = { ++ RF_TXBIAS_A}; ++ ++ u4Byte MAC_backup[IQK_MAC_REG_NUM]; ++ u4Byte MAC_REG[IQK_MAC_REG_NUM] = { ++ REG_TXPAUSE, REG_BCN_CTRL, ++ REG_BCN_CTRL_1, REG_GPIO_MUXCFG}; ++ ++ u4Byte Tx_AGC[DP_DPK_NUM][DP_DPK_VALUE_NUM] = { ++ {0x1e1e1e1e, 0x03901e1e}, ++ {0x18181818, 0x03901818}, ++ {0x0e0e0e0e, 0x03900e0e} ++ }; ++ ++ u4Byte AFE_on_off[PATH_NUM] = { ++ 0x04db25a4, 0x0b1b25a4}; //path A on path B off / path A off path B on ++ ++ u1Byte RetryCount = 0; ++ ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("==>phy_DigitalPredistortion()\n")); ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_DigitalPredistortion for %s %s\n", (is2T ? "2T2R" : "1T1R"))); ++ ++ //save BB default value ++ for(index=0; index tx_agc 1f ~11 ++ // PA gain = 11 & PAD2 => tx_agc 10~0e ++ // PA gain = 01 => tx_agc 0b~0d ++ // PA gain = 00 => tx_agc 0a~00 ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x40000000); ++ ODM_SetBBReg(pDM_Odm, 0xbc0, bMaskDWord, 0x0005361f); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ ++ //do inner loopback DPK 3 times ++ for(i = 0; i < 3; i++) ++ { ++ //PA gain = 11 & PAD2 => tx_agc = 0x0f/0x0c/0x07 ++ for(index = 0; index < 3; index++) ++ ODM_SetBBReg(pDM_Odm, 0xe00+index*4, bMaskDWord, Tx_AGC[i][0]); ++ ODM_SetBBReg(pDM_Odm,0xe00+index*4, bMaskDWord, Tx_AGC[i][1]); ++ for(index = 0; index < 4; index++) ++ ODM_SetBBReg(pDM_Odm,0xe10+index*4, bMaskDWord, Tx_AGC[i][0]); ++ ++ // PAGE_B for Path-A inner loopback DPK setting ++ ODM_SetBBReg(pDM_Odm,rPdp_AntA, bMaskDWord, 0x02097098); ++ ODM_SetBBReg(pDM_Odm,rPdp_AntA_4, bMaskDWord, 0xf76d9f84); ++ ODM_SetBBReg(pDM_Odm,rConfig_Pmpd_AntA, bMaskDWord, 0x0004ab87); ++ ODM_SetBBReg(pDM_Odm,rConfig_AntA, bMaskDWord, 0x00880000); ++ ++ //----send one shot signal----// ++ // Path A ++ ODM_SetBBReg(pDM_Odm,rConfig_Pmpd_AntA, bMaskDWord, 0x80047788); ++ ODM_delay_ms(1); ++ ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntA, bMaskDWord, 0x00047788); ++ ODM_delay_ms(50); ++ } ++ ++ //PA gain = 11 => tx_agc = 1a ++ for(index = 0; index < 3; index++) ++ ODM_SetBBReg(pDM_Odm,0xe00+index*4, bMaskDWord, 0x34343434); ++ ODM_SetBBReg(pDM_Odm,0xe08+index*4, bMaskDWord, 0x03903434); ++ for(index = 0; index < 4; index++) ++ ODM_SetBBReg(pDM_Odm,0xe10+index*4, bMaskDWord, 0x34343434); ++ ++ //==================================== ++ // PAGE_B for Path-A DPK setting ++ //==================================== ++ // open inner loopback @ b00[19]:10 od 0xb00 0x01097018 ++ ODM_SetBBReg(pDM_Odm,rPdp_AntA, bMaskDWord, 0x02017098); ++ ODM_SetBBReg(pDM_Odm,rPdp_AntA_4, bMaskDWord, 0xf76d9f84); ++ ODM_SetBBReg(pDM_Odm,rConfig_Pmpd_AntA, bMaskDWord, 0x0004ab87); ++ ODM_SetBBReg(pDM_Odm,rConfig_AntA, bMaskDWord, 0x00880000); ++ ++ //rf_lpbk_setup ++ //1.rf 00:5205a, rf 0d:0e52c ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x0c, bMaskDWord, 0x8992b); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x0d, bMaskDWord, 0x0e52c); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x00, bMaskDWord, 0x5205a ); ++ ++ //----send one shot signal----// ++ // Path A ++ ODM_SetBBReg(pDM_Odm,rConfig_Pmpd_AntA, bMaskDWord, 0x800477c0); ++ ODM_delay_ms(1); ++ ODM_SetBBReg(pDM_Odm,rConfig_Pmpd_AntA, bMaskDWord, 0x000477c0); ++ ODM_delay_ms(50); ++ ++ while(RetryCount < DP_RETRY_LIMIT && !pDM_Odm->RFCalibrateInfo.bDPPathAOK) ++ { ++ //----read back measurement results----// ++ ODM_SetBBReg(pDM_Odm, rPdp_AntA, bMaskDWord, 0x0c297018); ++ tmpReg = ODM_GetBBReg(pDM_Odm, 0xbe0, bMaskDWord); ++ ODM_delay_ms(10); ++ ODM_SetBBReg(pDM_Odm, rPdp_AntA, bMaskDWord, 0x0c29701f); ++ tmpReg2 = ODM_GetBBReg(pDM_Odm, 0xbe8, bMaskDWord); ++ ODM_delay_ms(10); ++ ++ tmpReg = (tmpReg & bMaskHWord) >> 16; ++ tmpReg2 = (tmpReg2 & bMaskHWord) >> 16; ++ if(tmpReg < 0xf0 || tmpReg > 0x105 || tmpReg2 > 0xff ) ++ { ++ ODM_SetBBReg(pDM_Odm, rPdp_AntA, bMaskDWord, 0x02017098); ++ ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80000000); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ ODM_delay_ms(1); ++ ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntA, bMaskDWord, 0x800477c0); ++ ODM_delay_ms(1); ++ ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntA, bMaskDWord, 0x000477c0); ++ ODM_delay_ms(50); ++ RetryCount++; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("path A DPK RetryCount %d 0xbe0[31:16] %x 0xbe8[31:16] %x\n", RetryCount, tmpReg, tmpReg2)); ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("path A DPK Sucess\n")); ++ pDM_Odm->RFCalibrateInfo.bDPPathAOK = TRUE; ++ break; ++ } ++ } ++ RetryCount = 0; ++ ++ //DPP path A ++ if(pDM_Odm->RFCalibrateInfo.bDPPathAOK) ++ { ++ // DP settings ++ ODM_SetBBReg(pDM_Odm, rPdp_AntA, bMaskDWord, 0x01017098); ++ ODM_SetBBReg(pDM_Odm, rPdp_AntA_4, bMaskDWord, 0x776d9f84); ++ ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntA, bMaskDWord, 0x0004ab87); ++ ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x00880000); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x40000000); ++ ++ for(i=rPdp_AntA; i<=0xb3c; i+=4) ++ { ++ ODM_SetBBReg(pDM_Odm, i, bMaskDWord, 0x40004000); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("path A ofsset = 0x%x\n", i)); ++ } ++ ++ //pwsf ++ ODM_SetBBReg(pDM_Odm, 0xb40, bMaskDWord, 0x40404040); ++ ODM_SetBBReg(pDM_Odm, 0xb44, bMaskDWord, 0x28324040); ++ ODM_SetBBReg(pDM_Odm, 0xb48, bMaskDWord, 0x10141920); ++ ++ for(i=0xb4c; i<=0xb5c; i+=4) ++ { ++ ODM_SetBBReg(pDM_Odm, i, bMaskDWord, 0x0c0c0c0c); ++ } ++ ++ //TX_AGC boundary ++ ODM_SetBBReg(pDM_Odm, 0xbc0, bMaskDWord, 0x0005361f); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ } ++ else ++ { ++ ODM_SetBBReg(pDM_Odm, rPdp_AntA, bMaskDWord, 0x00000000); ++ ODM_SetBBReg(pDM_Odm, rPdp_AntA_4, bMaskDWord, 0x00000000); ++ } ++ ++ //DPK path B ++ if(is2T) ++ { ++ //Path A to standby mode ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_AC, bMaskDWord, 0x10000); ++ ++ // LUTs => tx_agc ++ // PA gain = 11 & PAD1, => tx_agc 1f ~11 ++ // PA gain = 11 & PAD2, => tx_agc 10 ~0e ++ // PA gain = 01 => tx_agc 0b ~0d ++ // PA gain = 00 => tx_agc 0a ~00 ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x40000000); ++ ODM_SetBBReg(pDM_Odm, 0xbc4, bMaskDWord, 0x0005361f); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ ++ //do inner loopback DPK 3 times ++ for(i = 0; i < 3; i++) ++ { ++ //PA gain = 11 & PAD2 => tx_agc = 0x0f/0x0c/0x07 ++ for(index = 0; index < 4; index++) ++ ODM_SetBBReg(pDM_Odm, 0x830+index*4, bMaskDWord, Tx_AGC[i][0]); ++ for(index = 0; index < 2; index++) ++ ODM_SetBBReg(pDM_Odm, 0x848+index*4, bMaskDWord, Tx_AGC[i][0]); ++ for(index = 0; index < 2; index++) ++ ODM_SetBBReg(pDM_Odm, 0x868+index*4, bMaskDWord, Tx_AGC[i][0]); ++ ++ // PAGE_B for Path-A inner loopback DPK setting ++ ODM_SetBBReg(pDM_Odm, rPdp_AntB, bMaskDWord, 0x02097098); ++ ODM_SetBBReg(pDM_Odm, rPdp_AntB_4, bMaskDWord, 0xf76d9f84); ++ ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x0004ab87); ++ ODM_SetBBReg(pDM_Odm, rConfig_AntB, bMaskDWord, 0x00880000); ++ ++ //----send one shot signal----// ++ // Path B ++ ODM_SetBBReg(pDM_Odm,rConfig_Pmpd_AntB, bMaskDWord, 0x80047788); ++ ODM_delay_ms(1); ++ ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x00047788); ++ ODM_delay_ms(50); ++ } ++ ++ // PA gain = 11 => tx_agc = 1a ++ for(index = 0; index < 4; index++) ++ ODM_SetBBReg(pDM_Odm, 0x830+index*4, bMaskDWord, 0x34343434); ++ for(index = 0; index < 2; index++) ++ ODM_SetBBReg(pDM_Odm, 0x848+index*4, bMaskDWord, 0x34343434); ++ for(index = 0; index < 2; index++) ++ ODM_SetBBReg(pDM_Odm, 0x868+index*4, bMaskDWord, 0x34343434); ++ ++ // PAGE_B for Path-B DPK setting ++ ODM_SetBBReg(pDM_Odm, rPdp_AntB, bMaskDWord, 0x02017098); ++ ODM_SetBBReg(pDM_Odm, rPdp_AntB_4, bMaskDWord, 0xf76d9f84); ++ ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x0004ab87); ++ ODM_SetBBReg(pDM_Odm, rConfig_AntB, bMaskDWord, 0x00880000); ++ ++ // RF lpbk switches on ++ ODM_SetBBReg(pDM_Odm, 0x840, bMaskDWord, 0x0101000f); ++ ODM_SetBBReg(pDM_Odm, 0x840, bMaskDWord, 0x01120103); ++ ++ //Path-B RF lpbk ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, 0x0c, bMaskDWord, 0x8992b); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, 0x0d, bMaskDWord, 0x0e52c); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_B, RF_AC, bMaskDWord, 0x5205a); ++ ++ //----send one shot signal----// ++ ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x800477c0); ++ ODM_delay_ms(1); ++ ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x000477c0); ++ ODM_delay_ms(50); ++ ++ while(RetryCount < DP_RETRY_LIMIT && !pDM_Odm->RFCalibrateInfo.bDPPathBOK) ++ { ++ //----read back measurement results----// ++ ODM_SetBBReg(pDM_Odm, rPdp_AntB, bMaskDWord, 0x0c297018); ++ tmpReg = ODM_GetBBReg(pDM_Odm, 0xbf0, bMaskDWord); ++ ODM_SetBBReg(pDM_Odm, rPdp_AntB, bMaskDWord, 0x0c29701f); ++ tmpReg2 = ODM_GetBBReg(pDM_Odm, 0xbf8, bMaskDWord); ++ ++ tmpReg = (tmpReg & bMaskHWord) >> 16; ++ tmpReg2 = (tmpReg2 & bMaskHWord) >> 16; ++ ++ if(tmpReg < 0xf0 || tmpReg > 0x105 || tmpReg2 > 0xff) ++ { ++ ODM_SetBBReg(pDM_Odm, rPdp_AntB, bMaskDWord, 0x02017098); ++ ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80000000); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ ODM_delay_ms(1); ++ ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x800477c0); ++ ODM_delay_ms(1); ++ ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x000477c0); ++ ODM_delay_ms(50); ++ RetryCount++; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("path B DPK RetryCount %d 0xbf0[31:16] %x, 0xbf8[31:16] %x\n", RetryCount , tmpReg, tmpReg2)); ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("path B DPK Success\n")); ++ pDM_Odm->RFCalibrateInfo.bDPPathBOK = TRUE; ++ break; ++ } ++ } ++ ++ //DPP path B ++ if(pDM_Odm->RFCalibrateInfo.bDPPathBOK) ++ { ++ // DP setting ++ // LUT by SRAM ++ ODM_SetBBReg(pDM_Odm, rPdp_AntB, bMaskDWord, 0x01017098); ++ ODM_SetBBReg(pDM_Odm, rPdp_AntB_4, bMaskDWord, 0x776d9f84); ++ ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x0004ab87); ++ ODM_SetBBReg(pDM_Odm, rConfig_AntB, bMaskDWord, 0x00880000); ++ ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x40000000); ++ for(i=0xb60; i<=0xb9c; i+=4) ++ { ++ ODM_SetBBReg(pDM_Odm, i, bMaskDWord, 0x40004000); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("path B ofsset = 0x%x\n", i)); ++ } ++ ++ // PWSF ++ ODM_SetBBReg(pDM_Odm, 0xba0, bMaskDWord, 0x40404040); ++ ODM_SetBBReg(pDM_Odm, 0xba4, bMaskDWord, 0x28324050); ++ ODM_SetBBReg(pDM_Odm, 0xba8, bMaskDWord, 0x0c141920); ++ ++ for(i=0xbac; i<=0xbbc; i+=4) ++ { ++ ODM_SetBBReg(pDM_Odm, i, bMaskDWord, 0x0c0c0c0c); ++ } ++ ++ // tx_agc boundary ++ ODM_SetBBReg(pDM_Odm, 0xbc4, bMaskDWord, 0x0005361f); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ ++ } ++ else ++ { ++ ODM_SetBBReg(pDM_Odm, rPdp_AntB, bMaskDWord, 0x00000000); ++ ODM_SetBBReg(pDM_Odm, rPdp_AntB_4, bMaskDWord, 0x00000000); ++ } ++ } ++ ++ //reload BB default value ++ for(index=0; indexRFCalibrateInfo.bDPdone = TRUE; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("<==phy_DigitalPredistortion()\n")); ++#endif ++} ++ ++VOID ++PHY_DigitalPredistortion_8188E( ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PADAPTER pAdapter ++#else ++ IN PDM_ODM_T pDM_Odm ++#endif ++ ) ++{ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++#if DISABLE_BB_RF ++ return; ++#endif ++ ++ return; ++ ++ if(pDM_Odm->RFCalibrateInfo.bDPdone) ++ return; ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ ++ if(pDM_Odm->RFType == ODM_2T2R){ ++ phy_DigitalPredistortion(pAdapter, TRUE); ++ } ++ else ++#endif ++ { ++ // For 88C 1T1R ++ phy_DigitalPredistortion(pAdapter, FALSE); ++ } ++} ++ ++ ++ ++//return value TRUE => Main; FALSE => Aux ++ ++BOOLEAN phy_QueryRFPathSwitch_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN BOOLEAN is2T ++ ) ++{ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ if(!pAdapter->bHWInitReady) ++ { ++ u1Byte u1bTmp; ++ u1bTmp = ODM_Read1Byte(pDM_Odm, REG_LEDCFG2) | BIT7; ++ ODM_Write1Byte(pDM_Odm, REG_LEDCFG2, u1bTmp); ++ //ODM_SetBBReg(pDM_Odm, REG_LEDCFG0, BIT23, 0x01); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XAB_RFParameter, BIT13, 0x01); ++ } ++ ++ if(is2T) // ++ { ++ if(ODM_GetBBReg(pDM_Odm, rFPGA0_XB_RFInterfaceOE, BIT5|BIT6) == 0x01) ++ return TRUE; ++ else ++ return FALSE; ++ } ++ else ++ { ++ if(ODM_GetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, BIT8|BIT9) == 0x02) ++ return TRUE; ++ else ++ return FALSE; ++ } ++} ++ ++ ++ ++//return value TRUE => Main; FALSE => Aux ++BOOLEAN PHY_QueryRFPathSwitch_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm ++#else ++ IN PADAPTER pAdapter ++#endif ++ ) ++{ ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ #endif ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++ #endif ++#endif ++ ++ ++#if DISABLE_BB_RF ++ return TRUE; ++#endif ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ ++ //if(IS_92C_SERIAL( pHalData->VersionID)){ ++ if(pDM_Odm->RFType == ODM_2T2R){ ++ return phy_QueryRFPathSwitch_8188E(pAdapter, TRUE); ++ } ++ else ++#endif ++ { ++ // For 88C 1T1R ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ return phy_QueryRFPathSwitch_8188E(pAdapter, FALSE); ++#else ++ return phy_QueryRFPathSwitch_8188E(pDM_Odm, FALSE); ++#endif ++ } ++} ++#endif +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalPhyRf_8188e.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalPhyRf_8188e.h +new file mode 100644 +index 00000000..a8f4620b +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/HalPhyRf_8188e.h +@@ -0,0 +1,141 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#ifndef __HAL_PHY_RF_8188E_H__ ++#define __HAL_PHY_RF_8188E_H__ ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++#define IQK_DELAY_TIME_88E 10 //ms ++#define index_mapping_NUM_88E 15 ++#define AVG_THERMAL_NUM_88E 4 ++ ++typedef enum _PWRTRACK_CONTROL_METHOD { ++ BBSWING, ++ TXAGC ++} PWRTRACK_METHOD; ++ ++ ++VOID ++ODM_TxPwrTrackAdjust88E( ++ PDM_ODM_T pDM_Odm, ++ u1Byte Type, // 0 = OFDM, 1 = CCK ++ pu1Byte pDirection, // 1 = +(increase) 2 = -(decrease) ++ pu4Byte pOutWriteVal // Tx tracking CCK/OFDM BB swing index adjust ++ ); ++ ++ ++VOID ++odm_TXPowerTrackingCallback_ThermalMeter_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm ++#else ++ IN PADAPTER Adapter ++#endif ++ ); ++ ++ ++//1 7. IQK ++ ++void ++PHY_IQCalibrate_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER Adapter, ++#endif ++ IN BOOLEAN bReCovery); ++ ++ ++// ++// LC calibrate ++// ++void ++PHY_LCCalibrate_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm ++#else ++ IN PADAPTER pAdapter ++#endif ++); ++ ++// ++// AP calibrate ++// ++void ++PHY_APCalibrate_8188E( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN s1Byte delta); ++void ++PHY_DigitalPredistortion_8188E( IN PADAPTER pAdapter); ++ ++ ++VOID ++_PHY_SaveADDARegisters( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN pu4Byte ADDAReg, ++ IN pu4Byte ADDABackup, ++ IN u4Byte RegisterNum ++ ); ++ ++VOID ++_PHY_PathADDAOn( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN pu4Byte ADDAReg, ++ IN BOOLEAN isPathAOn, ++ IN BOOLEAN is2T ++ ); ++ ++VOID ++_PHY_MACSettingCalibration( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN pu4Byte MACReg, ++ IN pu4Byte MACBackup ++ ); ++ ++ ++VOID ++_PHY_PathAStandBy( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN PDM_ODM_T pDM_Odm ++#else ++ IN PADAPTER pAdapter ++#endif ++ ); ++ ++ ++#endif // #ifndef __HAL_PHY_RF_8188E_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/odm_RTL8188E.c b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/odm_RTL8188E.c +new file mode 100644 +index 00000000..fb99d0ee +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/odm_RTL8188E.c +@@ -0,0 +1,1290 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++//============================================================ ++// include files ++//============================================================ ++ ++#include "../odm_precomp.h" ++ ++#if (RTL8188E_SUPPORT == 1) ++ ++VOID ++ODM_DIG_LowerBound_88E( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ ++ if(pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) ++ { ++ pDM_DigTable->rx_gain_range_min = (u1Byte) pDM_DigTable->AntDiv_RSSI_max; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_DIG_LowerBound_88E(): pDM_DigTable->AntDiv_RSSI_max=%d \n",pDM_DigTable->AntDiv_RSSI_max)); ++ } ++ //If only one Entry connected ++ ++ ++ ++} ++ ++#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) ++VOID ++odm_RX_HWAntDivInit( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ u4Byte value32; ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ #if (MP_DRIVER == 1) ++ if (*(pDM_Odm->mp_mode) == 1) ++ { ++ pDM_Odm->AntDivType = CGCS_RX_SW_ANTDIV; ++ ODM_SetBBReg(pDM_Odm, ODM_REG_IGI_A_11N , BIT7, 0); // disable HW AntDiv ++ ODM_SetBBReg(pDM_Odm, ODM_REG_LNA_SWITCH_11N , BIT31, 1); // 1:CG, 0:CS ++ return; ++ } ++ #endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_RX_HWAntDivInit() \n")); ++ ++ //MAC Setting ++ value32 = ODM_GetMACReg(pDM_Odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord); ++ ODM_SetMACReg(pDM_Odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord, value32|(BIT23|BIT25)); //Reg4C[25]=1, Reg4C[23]=1 for pin output ++ //Pin Settings ++ ODM_SetBBReg(pDM_Odm, ODM_REG_PIN_CTRL_11N , BIT9|BIT8, 0);//Reg870[8]=1'b0, Reg870[9]=1'b0 //antsel antselb by HW ++ ODM_SetBBReg(pDM_Odm, ODM_REG_RX_ANT_CTRL_11N , BIT10, 0); //Reg864[10]=1'b0 //antsel2 by HW ++ ODM_SetBBReg(pDM_Odm, ODM_REG_LNA_SWITCH_11N , BIT22, 1); //Regb2c[22]=1'b0 //disable CS/CG switch ++ ODM_SetBBReg(pDM_Odm, ODM_REG_LNA_SWITCH_11N , BIT31, 1); //Regb2c[31]=1'b1 //output at CG only ++ //OFDM Settings ++ ODM_SetBBReg(pDM_Odm, ODM_REG_ANTDIV_PARA1_11N , bMaskDWord, 0x000000a0); ++ //CCK Settings ++ ODM_SetBBReg(pDM_Odm, ODM_REG_BB_PWR_SAV4_11N , BIT7, 1); //Fix CCK PHY status report issue ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_ANTDIV_PARA2_11N , BIT4, 1); //CCK complete HW AntDiv within 64 samples ++ ODM_UpdateRxIdleAnt_88E(pDM_Odm, MAIN_ANT); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_ANT_MAPPING1_11N , 0xFFFF, 0x0201); //antenna mapping table ++ ++ //ODM_SetBBReg(pDM_Odm, 0xc50 , BIT7, 1); //Enable HW AntDiv ++ //ODM_SetBBReg(pDM_Odm, 0xa00 , BIT15, 1); //Enable CCK AntDiv ++} ++ ++VOID ++odm_TRX_HWAntDivInit( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ u4Byte value32; ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ ++ #if (MP_DRIVER == 1) ++ if (*(pDM_Odm->mp_mode) == 1) ++ { ++ pDM_Odm->AntDivType = CGCS_RX_SW_ANTDIV; ++ ODM_SetBBReg(pDM_Odm, ODM_REG_IGI_A_11N , BIT7, 0); // disable HW AntDiv ++ ODM_SetBBReg(pDM_Odm, ODM_REG_RX_ANT_CTRL_11N , BIT5|BIT4|BIT3, 0); //Default RX (0/1) ++ return; ++ } ++ ++ #endif ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_TRX_HWAntDivInit() \n")); ++ ++ //MAC Setting ++ value32 = ODM_GetMACReg(pDM_Odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord); ++ ODM_SetMACReg(pDM_Odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord, value32|(BIT23|BIT25)); //Reg4C[25]=1, Reg4C[23]=1 for pin output ++ //Pin Settings ++ ODM_SetBBReg(pDM_Odm, ODM_REG_PIN_CTRL_11N , BIT9|BIT8, 0);//Reg870[8]=1'b0, Reg870[9]=1'b0 //antsel antselb by HW ++ ODM_SetBBReg(pDM_Odm, ODM_REG_RX_ANT_CTRL_11N , BIT10, 0); //Reg864[10]=1'b0 //antsel2 by HW ++ ODM_SetBBReg(pDM_Odm, ODM_REG_LNA_SWITCH_11N , BIT22, 0); //Regb2c[22]=1'b0 //disable CS/CG switch ++ ODM_SetBBReg(pDM_Odm, ODM_REG_LNA_SWITCH_11N , BIT31, 1); //Regb2c[31]=1'b1 //output at CG only ++ //OFDM Settings ++ ODM_SetBBReg(pDM_Odm, ODM_REG_ANTDIV_PARA1_11N , bMaskDWord, 0x000000a0); ++ //CCK Settings ++ ODM_SetBBReg(pDM_Odm, ODM_REG_BB_PWR_SAV4_11N , BIT7, 1); //Fix CCK PHY status report issue ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_ANTDIV_PARA2_11N , BIT4, 1); //CCK complete HW AntDiv within 64 samples ++ //Tx Settings ++ ODM_SetBBReg(pDM_Odm, ODM_REG_TX_ANT_CTRL_11N , BIT21, 0); //Reg80c[21]=1'b0 //from TX Reg ++ ODM_UpdateRxIdleAnt_88E(pDM_Odm, MAIN_ANT); ++ ++ //antenna mapping table ++ if(!pDM_Odm->bIsMPChip) //testchip ++ { ++ ODM_SetBBReg(pDM_Odm, ODM_REG_RX_DEFUALT_A_11N , BIT10|BIT9|BIT8, 1); //Reg858[10:8]=3'b001 ++ ODM_SetBBReg(pDM_Odm, ODM_REG_RX_DEFUALT_A_11N , BIT13|BIT12|BIT11, 2); //Reg858[13:11]=3'b010 ++ } ++ else //MPchip ++ ODM_SetBBReg(pDM_Odm, ODM_REG_ANT_MAPPING1_11N , bMaskDWord, 0x0201); //Reg914=3'b010, Reg915=3'b001 ++ ++ //ODM_SetBBReg(pDM_Odm, 0xc50 , BIT7, 1); //Enable HW AntDiv ++ //ODM_SetBBReg(pDM_Odm, 0xa00 , BIT15, 1); //Enable CCK AntDiv ++} ++ ++VOID ++odm_FastAntTrainingInit( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ u4Byte value32, i; ++ pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; ++ u4Byte AntCombination = 2; ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_FastAntTrainingInit() \n")); ++ ++#if (MP_DRIVER == 1) ++ if (*(pDM_Odm->mp_mode) == 1) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("pDM_Odm->AntDivType: %d\n", pDM_Odm->AntDivType)); ++ return; ++ } ++#endif ++ ++ for(i=0; i<6; i++) ++ { ++ pDM_FatTable->Bssid[i] = 0; ++ pDM_FatTable->antSumRSSI[i] = 0; ++ pDM_FatTable->antRSSIcnt[i] = 0; ++ pDM_FatTable->antAveRSSI[i] = 0; ++ } ++ pDM_FatTable->TrainIdx = 0; ++ pDM_FatTable->FAT_State = FAT_NORMAL_STATE; ++ ++ //MAC Setting ++ value32 = ODM_GetMACReg(pDM_Odm, 0x4c, bMaskDWord); ++ ODM_SetMACReg(pDM_Odm, 0x4c, bMaskDWord, value32|(BIT23|BIT25)); //Reg4C[25]=1, Reg4C[23]=1 for pin output ++ value32 = ODM_GetMACReg(pDM_Odm, 0x7B4, bMaskDWord); ++ ODM_SetMACReg(pDM_Odm, 0x7b4, bMaskDWord, value32|(BIT16|BIT17)); //Reg7B4[16]=1 enable antenna training, Reg7B4[17]=1 enable A2 match ++ //value32 = PlatformEFIORead4Byte(Adapter, 0x7B4); ++ //PlatformEFIOWrite4Byte(Adapter, 0x7b4, value32|BIT18); //append MACID in reponse packet ++ ++ //Match MAC ADDR ++ ODM_SetMACReg(pDM_Odm, 0x7b4, 0xFFFF, 0); ++ ODM_SetMACReg(pDM_Odm, 0x7b0, bMaskDWord, 0); ++ ++ ODM_SetBBReg(pDM_Odm, 0x870 , BIT9|BIT8, 0);//Reg870[8]=1'b0, Reg870[9]=1'b0 //antsel antselb by HW ++ ODM_SetBBReg(pDM_Odm, 0x864 , BIT10, 0); //Reg864[10]=1'b0 //antsel2 by HW ++ ODM_SetBBReg(pDM_Odm, 0xb2c , BIT22, 0); //Regb2c[22]=1'b0 //disable CS/CG switch ++ ODM_SetBBReg(pDM_Odm, 0xb2c , BIT31, 1); //Regb2c[31]=1'b1 //output at CG only ++ ODM_SetBBReg(pDM_Odm, 0xca4 , bMaskDWord, 0x000000a0); ++ ++ //antenna mapping table ++ if(AntCombination == 2) ++ { ++ if(!pDM_Odm->bIsMPChip) //testchip ++ { ++ ODM_SetBBReg(pDM_Odm, 0x858 , BIT10|BIT9|BIT8, 1); //Reg858[10:8]=3'b001 ++ ODM_SetBBReg(pDM_Odm, 0x858 , BIT13|BIT12|BIT11, 2); //Reg858[13:11]=3'b010 ++ } ++ else //MPchip ++ { ++ ODM_SetBBReg(pDM_Odm, 0x914 , bMaskByte0, 1); ++ ODM_SetBBReg(pDM_Odm, 0x914 , bMaskByte1, 2); ++ } ++ } ++ else if(AntCombination == 7) ++ { ++ if(!pDM_Odm->bIsMPChip) //testchip ++ { ++ ODM_SetBBReg(pDM_Odm, 0x858 , BIT10|BIT9|BIT8, 0); //Reg858[10:8]=3'b000 ++ ODM_SetBBReg(pDM_Odm, 0x858 , BIT13|BIT12|BIT11, 1); //Reg858[13:11]=3'b001 ++ ODM_SetBBReg(pDM_Odm, 0x878 , BIT16, 0); ++ ODM_SetBBReg(pDM_Odm, 0x858 , BIT15|BIT14, 2); //(Reg878[0],Reg858[14:15])=3'b010 ++ ODM_SetBBReg(pDM_Odm, 0x878 , BIT19|BIT18|BIT17, 3);//Reg878[3:1]=3b'011 ++ ODM_SetBBReg(pDM_Odm, 0x878 , BIT22|BIT21|BIT20, 4);//Reg878[6:4]=3b'100 ++ ODM_SetBBReg(pDM_Odm, 0x878 , BIT25|BIT24|BIT23, 5);//Reg878[9:7]=3b'101 ++ ODM_SetBBReg(pDM_Odm, 0x878 , BIT28|BIT27|BIT26, 6);//Reg878[12:10]=3b'110 ++ ODM_SetBBReg(pDM_Odm, 0x878 , BIT31|BIT30|BIT29, 7);//Reg878[15:13]=3b'111 ++ } ++ else //MPchip ++ { ++ ODM_SetBBReg(pDM_Odm, 0x914 , bMaskByte0, 0); ++ ODM_SetBBReg(pDM_Odm, 0x914 , bMaskByte1, 1); ++ ODM_SetBBReg(pDM_Odm, 0x914 , bMaskByte2, 2); ++ ODM_SetBBReg(pDM_Odm, 0x914 , bMaskByte3, 3); ++ ODM_SetBBReg(pDM_Odm, 0x918 , bMaskByte0, 4); ++ ODM_SetBBReg(pDM_Odm, 0x918 , bMaskByte1, 5); ++ ODM_SetBBReg(pDM_Odm, 0x918 , bMaskByte2, 6); ++ ODM_SetBBReg(pDM_Odm, 0x918 , bMaskByte3, 7); ++ } ++ } ++ ++ //Default Ant Setting when no fast training ++ ODM_SetBBReg(pDM_Odm, 0x80c , BIT21, 1); //Reg80c[21]=1'b1 //from TX Info ++ ODM_SetBBReg(pDM_Odm, 0x864 , BIT5|BIT4|BIT3, 0); //Default RX ++ ODM_SetBBReg(pDM_Odm, 0x864 , BIT8|BIT7|BIT6, 1); //Optional RX ++ //ODM_SetBBReg(pDM_Odm, 0x860 , BIT14|BIT13|BIT12, 1); //Default TX ++ ++ //Enter Traing state ++ ODM_SetBBReg(pDM_Odm, 0x864 , BIT2|BIT1|BIT0, (AntCombination-1)); //Reg864[2:0]=3'd6 //ant combination=reg864[2:0]+1 ++ //ODM_SetBBReg(pDM_Odm, 0xc50 , BIT7, 0); //RegC50[7]=1'b0 //disable HW AntDiv ++ //ODM_SetBBReg(pDM_Odm, 0xe08 , BIT16, 0); //RegE08[16]=1'b0 //disable fast training ++ //ODM_SetBBReg(pDM_Odm, 0xe08 , BIT16, 1); //RegE08[16]=1'b1 //enable fast training ++ ODM_SetBBReg(pDM_Odm, 0xc50 , BIT7, 1); //RegC50[7]=1'b1 //enable HW AntDiv ++ ++ ++ //SW Control ++ //PHY_SetBBReg(Adapter, 0x864 , BIT10, 1); ++ //PHY_SetBBReg(Adapter, 0x870 , BIT9, 1); ++ //PHY_SetBBReg(Adapter, 0x870 , BIT8, 1); ++ //PHY_SetBBReg(Adapter, 0x864 , BIT11, 1); ++ //PHY_SetBBReg(Adapter, 0x860 , BIT9, 0); ++ //PHY_SetBBReg(Adapter, 0x860 , BIT8, 0); ++} ++ ++VOID ++ODM_AntennaDiversityInit_88E( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++/* ++ //2012.03.27 LukeLee: For temp use, should be removed later ++ //pDM_Odm->AntDivType = CG_TRX_HW_ANTDIV; ++ //{ ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ HAL_DATA_TYPE* pHalData = GET_HAL_DATA(Adapter); ++ //pHalData->AntDivCfg = 1; ++ //} ++*/ ++ if(pDM_Odm->SupportICType != ODM_RTL8188E) ++ return; ++ ++ //ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("pDM_Odm->AntDivType=%d, pHalData->AntDivCfg=%d\n", ++ // pDM_Odm->AntDivType, pHalData->AntDivCfg)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("pDM_Odm->AntDivType=%d\n",pDM_Odm->AntDivType)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("pDM_Odm->bIsMPChip=%s\n",(pDM_Odm->bIsMPChip?"TRUE":"FALSE"))); ++ ++ if(pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) ++ odm_RX_HWAntDivInit(pDM_Odm); ++ else if(pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) ++ odm_TRX_HWAntDivInit(pDM_Odm); ++ else if(pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV) ++ odm_FastAntTrainingInit(pDM_Odm); ++} ++ ++ ++VOID ++ODM_UpdateRxIdleAnt_88E(IN PDM_ODM_T pDM_Odm, IN u1Byte Ant) ++{ ++ pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; ++ u4Byte DefaultAnt, OptionalAnt; ++ ++ if(pDM_FatTable->RxIdleAnt != Ant) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Need to Update Rx Idle Ant\n")); ++ if(Ant == MAIN_ANT) ++ { ++ DefaultAnt = (pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV)?MAIN_ANT_CG_TRX:MAIN_ANT_CGCS_RX; ++ OptionalAnt = (pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV)?AUX_ANT_CG_TRX:AUX_ANT_CGCS_RX; ++ } ++ else ++ { ++ DefaultAnt = (pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV)?AUX_ANT_CG_TRX:AUX_ANT_CGCS_RX; ++ OptionalAnt = (pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV)?MAIN_ANT_CG_TRX:MAIN_ANT_CGCS_RX; ++ } ++ ++ if(pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) ++ { ++ ODM_SetBBReg(pDM_Odm, ODM_REG_RX_ANT_CTRL_11N , BIT5|BIT4|BIT3, DefaultAnt); //Default RX ++ ODM_SetBBReg(pDM_Odm, ODM_REG_RX_ANT_CTRL_11N , BIT8|BIT7|BIT6, OptionalAnt); //Optional RX ++ ODM_SetBBReg(pDM_Odm, ODM_REG_ANTSEL_CTRL_11N , BIT14|BIT13|BIT12, DefaultAnt); //Default TX ++ ODM_SetMACReg(pDM_Odm, ODM_REG_RESP_TX_11N , BIT6|BIT7, DefaultAnt); //Resp Tx ++ ++ } ++ else if(pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) ++ { ++ ODM_SetBBReg(pDM_Odm, ODM_REG_RX_ANT_CTRL_11N , BIT5|BIT4|BIT3, DefaultAnt); //Default RX ++ ODM_SetBBReg(pDM_Odm, ODM_REG_RX_ANT_CTRL_11N , BIT8|BIT7|BIT6, OptionalAnt); //Optional RX ++ } ++ } ++ pDM_FatTable->RxIdleAnt = Ant; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("RxIdleAnt=%s\n",(Ant==MAIN_ANT)?"MAIN_ANT":"AUX_ANT")); ++ printk("RxIdleAnt=%s\n",(Ant==MAIN_ANT)?"MAIN_ANT":"AUX_ANT"); ++} ++ ++ ++VOID ++odm_UpdateTxAnt_88E(IN PDM_ODM_T pDM_Odm, IN u1Byte Ant, IN u4Byte MacId) ++{ ++ pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; ++ u1Byte TargetAnt; ++ ++ if(Ant == MAIN_ANT) ++ TargetAnt = MAIN_ANT_CG_TRX; ++ else ++ TargetAnt = AUX_ANT_CG_TRX; ++ ++ pDM_FatTable->antsel_a[MacId] = TargetAnt&BIT0; ++ pDM_FatTable->antsel_b[MacId] = (TargetAnt&BIT1)>>1; ++ pDM_FatTable->antsel_c[MacId] = (TargetAnt&BIT2)>>2; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Tx from TxInfo, TargetAnt=%s\n", ++ (Ant==MAIN_ANT)?"MAIN_ANT":"AUX_ANT")); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("antsel_tr_mux=3'b%d%d%d\n", ++ pDM_FatTable->antsel_c[MacId] , pDM_FatTable->antsel_b[MacId] , pDM_FatTable->antsel_a[MacId] )); ++} ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE)) ++VOID ++ODM_SetTxAntByTxInfo_88E( ++ IN PDM_ODM_T pDM_Odm, ++ IN pu1Byte pDesc, ++ IN u1Byte macId ++ ) ++{ ++ pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; ++ ++ if((pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV)||(pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV)) ++ { ++ SET_TX_DESC_ANTSEL_A_88E(pDesc, pDM_FatTable->antsel_a[macId]); ++ SET_TX_DESC_ANTSEL_B_88E(pDesc, pDM_FatTable->antsel_b[macId]); ++ SET_TX_DESC_ANTSEL_C_88E(pDesc, pDM_FatTable->antsel_c[macId]); ++ //ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SetTxAntByTxInfo_88E_WIN(): MacID=%d, antsel_tr_mux=3'b%d%d%d\n", ++ // macId, pDM_FatTable->antsel_c[macId], pDM_FatTable->antsel_b[macId], pDM_FatTable->antsel_a[macId])); ++ } ++} ++#else// (DM_ODM_SUPPORT_TYPE == ODM_AP) ++VOID ++ODM_SetTxAntByTxInfo_88E( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++} ++#endif ++ ++VOID ++ODM_AntselStatistics_88E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte antsel_tr_mux, ++ IN u4Byte MacId, ++ IN u1Byte RxPWDBAll ++) ++{ ++ pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; ++ if(pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) ++ { ++ if(antsel_tr_mux == MAIN_ANT_CG_TRX) ++ { ++ ++ pDM_FatTable->MainAnt_Sum[MacId]+=RxPWDBAll; ++ pDM_FatTable->MainAnt_Cnt[MacId]++; ++ } ++ else ++ { ++ pDM_FatTable->AuxAnt_Sum[MacId]+=RxPWDBAll; ++ pDM_FatTable->AuxAnt_Cnt[MacId]++; ++ ++ } ++ } ++ else if(pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) ++ { ++ if(antsel_tr_mux == MAIN_ANT_CGCS_RX) ++ { ++ ++ pDM_FatTable->MainAnt_Sum[MacId]+=RxPWDBAll; ++ pDM_FatTable->MainAnt_Cnt[MacId]++; ++ } ++ else ++ { ++ pDM_FatTable->AuxAnt_Sum[MacId]+=RxPWDBAll; ++ pDM_FatTable->AuxAnt_Cnt[MacId]++; ++ ++ } ++ } ++} ++ ++#define TX_BY_REG 0 ++VOID ++odm_HWAntDiv( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ u4Byte i, MinRSSI=0xFF, AntDivMaxRSSI=0, MaxRSSI=0, LocalMinRSSI, LocalMaxRSSI; ++ u4Byte Main_RSSI, Aux_RSSI; ++ u1Byte RxIdleAnt=0, TargetAnt=7; ++ pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ BOOLEAN bMatchBSSID; ++ BOOLEAN bPktFilterMacth = FALSE; ++ PSTA_INFO_T pEntry; ++ ++ for (i=0; ipODM_StaInfo[i]; ++ if(IS_STA_VALID(pEntry)) ++ { ++ //2 Caculate RSSI per Antenna ++ Main_RSSI = (pDM_FatTable->MainAnt_Cnt[i]!=0)?(pDM_FatTable->MainAnt_Sum[i]/pDM_FatTable->MainAnt_Cnt[i]):0; ++ Aux_RSSI = (pDM_FatTable->AuxAnt_Cnt[i]!=0)?(pDM_FatTable->AuxAnt_Sum[i]/pDM_FatTable->AuxAnt_Cnt[i]):0; ++ TargetAnt = (Main_RSSI>=Aux_RSSI)?MAIN_ANT:AUX_ANT; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("MacID=%d, MainAnt_Sum=%d, MainAnt_Cnt=%d\n", i, pDM_FatTable->MainAnt_Sum[i], pDM_FatTable->MainAnt_Cnt[i])); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("MacID=%d, AuxAnt_Sum=%d, AuxAnt_Cnt=%d\n",i, pDM_FatTable->AuxAnt_Sum[i], pDM_FatTable->AuxAnt_Cnt[i])); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("MacID=%d, Main_RSSI= %d, Aux_RSSI= %d\n", i, Main_RSSI, Aux_RSSI)); ++ ++ //2 Select MaxRSSI for DIG ++ LocalMaxRSSI = (Main_RSSI>Aux_RSSI)?Main_RSSI:Aux_RSSI; ++ if((LocalMaxRSSI > AntDivMaxRSSI) && (LocalMaxRSSI < 40)) ++ AntDivMaxRSSI = LocalMaxRSSI; ++ if(LocalMaxRSSI > MaxRSSI) ++ MaxRSSI = LocalMaxRSSI; ++ ++ //2 Select RX Idle Antenna ++ if((pDM_FatTable->RxIdleAnt == MAIN_ANT) && (Main_RSSI == 0)) ++ Main_RSSI = Aux_RSSI; ++ else if((pDM_FatTable->RxIdleAnt == AUX_ANT) && (Aux_RSSI == 0)) ++ Aux_RSSI = Main_RSSI; ++ ++ LocalMinRSSI = (Main_RSSI>Aux_RSSI)?Aux_RSSI:Main_RSSI; ++ if(LocalMinRSSI < MinRSSI) ++ { ++ MinRSSI = LocalMinRSSI; ++ RxIdleAnt = TargetAnt; ++ } ++#if TX_BY_REG ++ ++#else ++ //2 Select TRX Antenna ++ if(pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) ++ odm_UpdateTxAnt_88E(pDM_Odm, TargetAnt, i); ++#endif ++ } ++ pDM_FatTable->MainAnt_Sum[i] = 0; ++ pDM_FatTable->AuxAnt_Sum[i] = 0; ++ pDM_FatTable->MainAnt_Cnt[i] = 0; ++ pDM_FatTable->AuxAnt_Cnt[i] = 0; ++ } ++ ++ //2 Set RX Idle Antenna ++ ODM_UpdateRxIdleAnt_88E(pDM_Odm, RxIdleAnt); ++ ++ pDM_DigTable->AntDiv_RSSI_max = AntDivMaxRSSI; ++ pDM_DigTable->RSSI_max = MaxRSSI; ++} ++ ++ ++#if (!(DM_ODM_SUPPORT_TYPE == ODM_CE)) ++VOID ++odm_SetNextMACAddrTarget( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; ++ PSTA_INFO_T pEntry; ++ //u1Byte Bssid[6]; ++ u4Byte value32, i; ++ ++ // ++ //2012.03.26 LukeLee: The MAC address is changed according to MACID in turn ++ // ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_SetNextMACAddrTarget() ==>\n")); ++ if(pDM_Odm->bLinked) ++ { ++ for (i=0; iTrainIdx+1) == ODM_ASSOCIATE_ENTRY_NUM) ++ pDM_FatTable->TrainIdx = 0; ++ else ++ pDM_FatTable->TrainIdx++; ++ ++ pEntry = pDM_Odm->pODM_StaInfo[pDM_FatTable->TrainIdx]; ++ if(IS_STA_VALID(pEntry)) ++ { ++ //Match MAC ADDR ++#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ value32 = (pEntry->hwaddr[5]<<8)|pEntry->hwaddr[4]; ++#else ++ value32 = (pEntry->MacAddr[5]<<8)|pEntry->MacAddr[4]; ++#endif ++ ODM_SetMACReg(pDM_Odm, 0x7b4, 0xFFFF, value32); ++#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ value32 = (pEntry->hwaddr[3]<<24)|(pEntry->hwaddr[2]<<16) |(pEntry->hwaddr[1]<<8) |pEntry->hwaddr[0]; ++#else ++ value32 = (pEntry->MacAddr[3]<<24)|(pEntry->MacAddr[2]<<16) |(pEntry->MacAddr[1]<<8) |pEntry->MacAddr[0]; ++#endif ++ ODM_SetMACReg(pDM_Odm, 0x7b0, bMaskDWord, value32); ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("pDM_FatTable->TrainIdx=%d\n",pDM_FatTable->TrainIdx)); ++#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Training MAC Addr = %x:%x:%x:%x:%x:%x\n", ++ pEntry->hwaddr[5],pEntry->hwaddr[4],pEntry->hwaddr[3],pEntry->hwaddr[2],pEntry->hwaddr[1],pEntry->hwaddr[0])); ++#else ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Training MAC Addr = %x:%x:%x:%x:%x:%x\n", ++ pEntry->MacAddr[5],pEntry->MacAddr[4],pEntry->MacAddr[3],pEntry->MacAddr[2],pEntry->MacAddr[1],pEntry->MacAddr[0])); ++#endif ++ ++ break; ++ } ++ } ++ ++ } ++ ++#if 0 ++ // ++ //2012.03.26 LukeLee: This should be removed later, the MAC address is changed according to MACID in turn ++ // ++ #if( DM_ODM_SUPPORT_TYPE & ODM_MP) ++ { ++ PADAPTER Adapter = pDM_Odm->Adapter; ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ ++ for (i=0; i<6; i++) ++ { ++ Bssid[i] = pMgntInfo->Bssid[i]; ++ //DbgPrint("Bssid[%d]=%x\n", i, Bssid[i]); ++ } ++ } ++ #endif ++ ++ //odm_SetNextMACAddrTarget(pDM_Odm); ++ ++ //1 Select MAC Address Filter ++ for (i=0; i<6; i++) ++ { ++ if(Bssid[i] != pDM_FatTable->Bssid[i]) ++ { ++ bMatchBSSID = FALSE; ++ break; ++ } ++ } ++ if(bMatchBSSID == FALSE) ++ { ++ //Match MAC ADDR ++ value32 = (Bssid[5]<<8)|Bssid[4]; ++ ODM_SetMACReg(pDM_Odm, 0x7b4, 0xFFFF, value32); ++ value32 = (Bssid[3]<<24)|(Bssid[2]<<16) |(Bssid[1]<<8) |Bssid[0]; ++ ODM_SetMACReg(pDM_Odm, 0x7b0, bMaskDWord, value32); ++ } ++ ++ return bMatchBSSID; ++#endif ++ ++} ++ ++VOID ++odm_FastAntTraining( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ u4Byte i, MaxRSSI=0; ++ u1Byte TargetAnt=2; ++ pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; ++ BOOLEAN bPktFilterMacth = FALSE; ++ PSTA_INFO_T pEntry; ++ ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("==>odm_FastAntTraining()\n")); ++ ++ //1 TRAINING STATE ++ if(pDM_FatTable->FAT_State == FAT_TRAINING_STATE) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Enter FAT_TRAINING_STATE\n")); ++ //2 Caculate RSSI per Antenna ++ for (i=0; i<7; i++) ++ { ++ if(pDM_FatTable->antRSSIcnt[i] == 0) ++ pDM_FatTable->antAveRSSI[i] = 0; ++ else ++ { ++ pDM_FatTable->antAveRSSI[i] = pDM_FatTable->antSumRSSI[i] /pDM_FatTable->antRSSIcnt[i]; ++ bPktFilterMacth = TRUE; ++ } ++ if(pDM_FatTable->antAveRSSI[i] > MaxRSSI) ++ { ++ MaxRSSI = pDM_FatTable->antAveRSSI[i]; ++ TargetAnt = (u1Byte) i; ++ } ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("pDM_FatTable->antAveRSSI[%d] = %d, pDM_FatTable->antRSSIcnt[%d] = %d\n", ++ i, pDM_FatTable->antAveRSSI[i], i, pDM_FatTable->antRSSIcnt[i])); ++ } ++ ++ //2 Select TRX Antenna ++ if(bPktFilterMacth == FALSE) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("None Packet is matched\n")); ++ ++ ODM_SetBBReg(pDM_Odm, 0xe08 , BIT16, 0); //RegE08[16]=1'b0 //disable fast training ++ ODM_SetBBReg(pDM_Odm, 0xc50 , BIT7, 0); //RegC50[7]=1'b0 //disable HW AntDiv ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("TargetAnt=%d, MaxRSSI=%d\n",TargetAnt,MaxRSSI)); ++ ++ ODM_SetBBReg(pDM_Odm, 0xe08 , BIT16, 0); //RegE08[16]=1'b0 //disable fast training ++ //ODM_SetBBReg(pDM_Odm, 0xc50 , BIT7, 0); //RegC50[7]=1'b0 //disable HW AntDiv ++ ODM_SetBBReg(pDM_Odm, 0x864 , BIT8|BIT7|BIT6, TargetAnt); //Default RX is Omni, Optional RX is the best decision by FAT ++ //ODM_SetBBReg(pDM_Odm, 0x860 , BIT14|BIT13|BIT12, TargetAnt); //Default TX ++ ODM_SetBBReg(pDM_Odm, 0x80c , BIT21, 1); //Reg80c[21]=1'b1 //from TX Info ++ ++#if 0 ++ pEntry = pDM_Odm->pODM_StaInfo[pDM_FatTable->TrainIdx]; ++ ++ if(IS_STA_VALID(pEntry)) ++ { ++ pEntry->antsel_a = TargetAnt&BIT0; ++ pEntry->antsel_b = (TargetAnt&BIT1)>>1; ++ pEntry->antsel_c = (TargetAnt&BIT2)>>2; ++ } ++#else ++ pDM_FatTable->antsel_a[pDM_FatTable->TrainIdx] = TargetAnt&BIT0; ++ pDM_FatTable->antsel_b[pDM_FatTable->TrainIdx] = (TargetAnt&BIT1)>>1; ++ pDM_FatTable->antsel_c[pDM_FatTable->TrainIdx] = (TargetAnt&BIT2)>>2; ++#endif ++ ++ ++ if(TargetAnt == 0) ++ ODM_SetBBReg(pDM_Odm, 0xc50 , BIT7, 0); //RegC50[7]=1'b0 //disable HW AntDiv ++ ++ } ++ ++ //2 Reset Counter ++ for(i=0; i<7; i++) ++ { ++ pDM_FatTable->antSumRSSI[i] = 0; ++ pDM_FatTable->antRSSIcnt[i] = 0; ++ } ++ ++ pDM_FatTable->FAT_State = FAT_NORMAL_STATE; ++ return; ++ } ++ ++ //1 NORMAL STATE ++ if(pDM_FatTable->FAT_State == FAT_NORMAL_STATE) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Enter FAT_NORMAL_STATE\n")); ++ ++ odm_SetNextMACAddrTarget(pDM_Odm); ++ ++#if 0 ++ pEntry = pDM_Odm->pODM_StaInfo[pDM_FatTable->TrainIdx]; ++ if(IS_STA_VALID(pEntry)) ++ { ++ pEntry->antsel_a = TargetAnt&BIT0; ++ pEntry->antsel_b = (TargetAnt&BIT1)>>1; ++ pEntry->antsel_c = (TargetAnt&BIT2)>>2; ++ } ++#endif ++ ++ //2 Prepare Training ++ pDM_FatTable->FAT_State = FAT_TRAINING_STATE; ++ ODM_SetBBReg(pDM_Odm, 0xe08 , BIT16, 1); //RegE08[16]=1'b1 //enable fast training ++ ODM_SetBBReg(pDM_Odm, 0xc50 , BIT7, 1); //RegC50[7]=1'b1 //enable HW AntDiv ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Start FAT_TRAINING_STATE\n")); ++ ODM_SetTimer(pDM_Odm,&pDM_Odm->FastAntTrainingTimer, 500 ); //ms ++ ++ } ++ ++} ++ ++VOID ++odm_FastAntTrainingCallback( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PADAPTER padapter = pDM_Odm->Adapter; ++ if(padapter->net_closed == _TRUE) ++ return; ++ //if(*pDM_Odm->pbNet_closed == TRUE) ++ // return; ++#endif ++ ++#if USE_WORKITEM ++ ODM_ScheduleWorkItem(&pDM_Odm->FastAntTrainingWorkitem); ++#else ++ odm_FastAntTraining(pDM_Odm); ++#endif ++} ++ ++VOID ++odm_FastAntTrainingWorkItemCallback( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ odm_FastAntTraining(pDM_Odm); ++} ++#endif ++ ++VOID ++ODM_AntennaDiversity_88E( ++ IN PDM_ODM_T pDM_Odm ++) ++{ ++ pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; ++ if((pDM_Odm->SupportICType != ODM_RTL8188E) || (!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV))) ++ { ++ //ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_AntennaDiversity_88E: Not Support 88E AntDiv\n")); ++ return; ++ } ++#ifdef CONFIG_SPECIAL_SETTING_FOR_FUNAI_TV ++ if(pDM_Odm->bLinked){ ++ if(pDM_Odm->Adapter->registrypriv.force_ant != 0) ++ { ++ u4Byte Main_RSSI, Aux_RSSI; ++ u8 i=0; ++ Main_RSSI = (pDM_FatTable->MainAnt_Cnt[i]!=0)?(pDM_FatTable->MainAnt_Sum[i]/pDM_FatTable->MainAnt_Cnt[i]):0; ++ Aux_RSSI = (pDM_FatTable->AuxAnt_Cnt[i]!=0)?(pDM_FatTable->AuxAnt_Sum[i]/pDM_FatTable->AuxAnt_Cnt[i]):0; ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("MacID=%d, MainAnt_Sum=%d, MainAnt_Cnt=%d\n", i, pDM_FatTable->MainAnt_Sum[i], pDM_FatTable->MainAnt_Cnt[i])); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("MacID=%d, AuxAnt_Sum=%d, AuxAnt_Cnt=%d\n",i, pDM_FatTable->AuxAnt_Sum[i], pDM_FatTable->AuxAnt_Cnt[i])); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("MacID=%d, Main_RSSI= %d, Aux_RSSI= %d\n", i, Main_RSSI, Aux_RSSI)); ++ pDM_FatTable->MainAnt_Sum[i] = 0; ++ pDM_FatTable->AuxAnt_Sum[i] = 0; ++ pDM_FatTable->MainAnt_Cnt[i] = 0; ++ pDM_FatTable->AuxAnt_Cnt[i] = 0; ++ } ++ if(pDM_Odm->Adapter->registrypriv.force_ant==1){ ++ ODM_UpdateRxIdleAnt_88E(pDM_Odm, MAIN_ANT); ++ printk("%s fixed antenna in Main ant\n",__FUNCTION__); ++ return; ++ } ++ else if(pDM_Odm->Adapter->registrypriv.force_ant==2){ ++ ODM_UpdateRxIdleAnt_88E(pDM_Odm, AUX_ANT); ++ printk("%s fixed antenna in AUX ant\n",__FUNCTION__); ++ return; ++ } ++ } ++#endif ++ ++ ++ ++ if(!pDM_Odm->bLinked) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_AntennaDiversity_88E(): No Link.\n")); ++ if(pDM_FatTable->bBecomeLinked == TRUE) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Need to Turn off HW AntDiv\n")); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_IGI_A_11N , BIT7, 0); //RegC50[7]=1'b1 //enable HW AntDiv ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_ANTDIV_PARA1_11N , BIT15, 0); //Enable CCK AntDiv ++ if(pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) ++ ODM_SetBBReg(pDM_Odm, ODM_REG_TX_ANT_CTRL_11N , BIT21, 0); //Reg80c[21]=1'b0 //from TX Reg ++ pDM_FatTable->bBecomeLinked = pDM_Odm->bLinked; ++ } ++ return; ++ } ++ else ++ { ++ if(pDM_FatTable->bBecomeLinked ==FALSE) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Need to Turn on HW AntDiv\n")); ++ //Because HW AntDiv is disabled before Link, we enable HW AntDiv after link ++ ODM_SetBBReg(pDM_Odm, ODM_REG_IGI_A_11N , BIT7, 1); //RegC50[7]=1'b1 //enable HW AntDiv ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_ANTDIV_PARA1_11N , BIT15, 1); //Enable CCK AntDiv ++ //ODM_SetMACReg(pDM_Odm, 0x7B4 , BIT18, 1); //Response Tx by current HW antdiv ++ if(pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) ++ { ++#if TX_BY_REG ++ ODM_SetBBReg(pDM_Odm, ODM_REG_TX_ANT_CTRL_11N , BIT21, 0); //Reg80c[21]=1'b0 //from Reg ++#else ++ ODM_SetBBReg(pDM_Odm, ODM_REG_TX_ANT_CTRL_11N , BIT21, 1); //Reg80c[21]=1'b1 //from TX Info ++#endif ++ } ++ pDM_FatTable->bBecomeLinked = pDM_Odm->bLinked; ++ } ++ } ++ ++ ++ ++ if((pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV)||(pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV)) ++ odm_HWAntDiv(pDM_Odm); ++ #if (!(DM_ODM_SUPPORT_TYPE == ODM_CE)) ++ else if(pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV) ++ odm_FastAntTraining(pDM_Odm); ++ #endif ++} ++ ++ ++/* ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++VOID ++odm_FastAntTrainingCallback( ++ PRT_TIMER pTimer ++) ++{ ++ PADAPTER Adapter = (PADAPTER)pTimer->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ //#if DEV_BUS_TYPE==RT_PCI_INTERFACE ++ //#if USE_WORKITEM ++ //PlatformScheduleWorkItem(&pHalData->SwAntennaSwitchWorkitem); ++ //#else ++ odm_FastAntTraining(&pHalData->DM_OutSrc); ++ //#endif ++ //#else ++ //PlatformScheduleWorkItem(&pHalData->SwAntennaSwitchWorkitem); ++ //#endif ++ ++} ++#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) ++VOID odm_FastAntTrainingCallback(void *FunctionContext) ++{ ++ PDM_ODM_T pDM_Odm= (PDM_ODM_T)FunctionContext; ++ PADAPTER padapter = pDM_Odm->Adapter; ++ if(padapter->net_closed == _TRUE) ++ return; ++ odm_FastAntTraining(pDM_Odm); ++} ++#elif (DM_ODM_SUPPORT_TYPE == ODM_AP) ++VOID odm_FastAntTrainingCallback(void *FunctionContext) ++{ ++ PDM_ODM_T pDM_Odm= (PDM_ODM_T)FunctionContext; ++ odm_FastAntTraining(pDM_Odm); ++} ++ ++#endif ++*/ ++ ++#else //#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE)) ++VOID ++ODM_SetTxAntByTxInfo_88E( ++ IN PDM_ODM_T pDM_Odm, ++ IN pu1Byte pDesc, ++ IN u1Byte macId ++ ) ++{ ++} ++#else// (DM_ODM_SUPPORT_TYPE == ODM_AP) ++VOID ++ODM_SetTxAntByTxInfo_88E( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++} ++#endif ++#endif //#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) ++//3============================================================ ++//3 Dynamic Primary CCA ++//3============================================================ ++ ++VOID ++odm_PrimaryCCA_Init( ++ IN PDM_ODM_T pDM_Odm) ++{ ++ pPri_CCA_T PrimaryCCA = &(pDM_Odm->DM_PriCCA); ++ PrimaryCCA->DupRTS_flag = 0; ++ PrimaryCCA->intf_flag = 0; ++ PrimaryCCA->intf_type = 0; ++ PrimaryCCA->Monitor_flag = 0; ++ PrimaryCCA->PriCCA_flag = 0; ++} ++ ++BOOLEAN ++ODM_DynamicPrimaryCCA_DupRTS( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ pPri_CCA_T PrimaryCCA = &(pDM_Odm->DM_PriCCA); ++ ++ return PrimaryCCA->DupRTS_flag; ++} ++ ++VOID ++odm_DynamicPrimaryCCA( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ PADAPTER Adapter = pDM_Odm->Adapter; // for NIC ++ prtl8192cd_priv priv = pDM_Odm->priv; // for AP ++ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP)) ++ PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ PRT_WLAN_STA pEntry; ++#endif ++ ++ PFALSE_ALARM_STATISTICS FalseAlmCnt = &(pDM_Odm->FalseAlmCnt); ++ pPri_CCA_T PrimaryCCA = &(pDM_Odm->DM_PriCCA); ++ ++ BOOLEAN Is40MHz; ++ BOOLEAN Client_40MHz = FALSE, Client_tmp = FALSE; // connected client BW ++ BOOLEAN bConnected = FALSE; // connected or not ++ static u1Byte Client_40MHz_pre = 0; ++ static u8Byte lastTxOkCnt = 0; ++ static u8Byte lastRxOkCnt = 0; ++ static u4Byte Counter = 0; ++ static u1Byte Delay = 1; ++ u8Byte curTxOkCnt; ++ u8Byte curRxOkCnt; ++ u1Byte SecCHOffset; ++ u1Byte i; ++ ++#if((DM_ODM_SUPPORT_TYPE==ODM_ADSL) ||( DM_ODM_SUPPORT_TYPE==ODM_CE)) ++ return; ++#endif ++ ++ if(pDM_Odm->SupportICType != ODM_RTL8188E) ++ return; ++ ++ Is40MHz = *(pDM_Odm->pBandWidth); ++ SecCHOffset = *(pDM_Odm->pSecChOffset); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Second CH Offset = %d\n", SecCHOffset)); ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ if(Is40MHz==1) ++ SecCHOffset = SecCHOffset%2+1; // NIC's definition is reverse to AP 1:secondary below, 2: secondary above ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Second CH Offset = %d\n", SecCHOffset)); ++ //3 Check Current WLAN Traffic ++ curTxOkCnt = Adapter->TxStats.NumTxBytesUnicast - lastTxOkCnt; ++ curRxOkCnt = Adapter->RxStats.NumRxBytesUnicast - lastRxOkCnt; ++ lastTxOkCnt = Adapter->TxStats.NumTxBytesUnicast; ++ lastRxOkCnt = Adapter->RxStats.NumRxBytesUnicast; ++#elif (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ //3 Check Current WLAN Traffic ++ curTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast)-lastTxOkCnt; ++ curRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast)-lastRxOkCnt; ++ lastTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast); ++ lastRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast); ++#endif ++ ++ //==================Debug Message==================== ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("TP = %llu\n", curTxOkCnt+curRxOkCnt)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Is40MHz = %d\n", Is40MHz)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("BW_LSC = %d\n", FalseAlmCnt->Cnt_BW_LSC)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("BW_USC = %d\n", FalseAlmCnt->Cnt_BW_USC)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("CCA OFDM = %d\n", FalseAlmCnt->Cnt_OFDM_CCA)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("CCA CCK = %d\n", FalseAlmCnt->Cnt_CCK_CCA)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("OFDM FA = %d\n", FalseAlmCnt->Cnt_Ofdm_fail)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("CCK FA = %d\n", FalseAlmCnt->Cnt_Cck_fail)); ++ //================================================ ++ ++#if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ if (ACTING_AS_AP(Adapter)) // primary cca process only do at AP mode ++#endif ++ { ++ ++ #if (DM_ODM_SUPPORT_TYPE == ODM_MP) ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("ACTING as AP mode=%d\n", ACTING_AS_AP(Adapter))); ++ //3 To get entry's connection and BW infomation status. ++ for(i=0;iHTInfo.bBw40MHz; // client BW ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Client_BW=%d\n", Client_tmp)); ++ if(Client_tmp>Client_40MHz) ++ Client_40MHz = Client_tmp; // 40M/20M coexist => 40M priority is High ++ ++ if(pEntry->bAssociated) ++ { ++ bConnected=TRUE; // client is connected or not ++ break; ++ } ++ } ++ else ++ { ++ break; ++ } ++ } ++#elif (DM_ODM_SUPPORT_TYPE == ODM_AP) ++ //3 To get entry's connection and BW infomation status. ++ ++ PSTA_INFO_T pstat; ++ ++ for(i=0; ipODM_StaInfo[i]; ++ if(IS_STA_VALID(pstat) ) ++ { ++ Client_tmp = pstat->tx_bw; ++ if(Client_tmp>Client_40MHz) ++ Client_40MHz = Client_tmp; // 40M/20M coexist => 40M priority is High ++ ++ bConnected = TRUE; ++ } ++ } ++#endif ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("bConnected=%d\n", bConnected)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Is Client 40MHz=%d\n", Client_40MHz)); ++ //1 Monitor whether the interference exists or not ++ if(PrimaryCCA->Monitor_flag == 1) ++ { ++ if(SecCHOffset == 1) // secondary channel is below the primary channel ++ { ++ if((FalseAlmCnt->Cnt_OFDM_CCA > 500)&&(FalseAlmCnt->Cnt_BW_LSC > FalseAlmCnt->Cnt_BW_USC+500)) ++ { ++ if(FalseAlmCnt->Cnt_Ofdm_fail > FalseAlmCnt->Cnt_OFDM_CCA>>1) ++ { ++ PrimaryCCA->intf_type = 1; ++ PrimaryCCA->PriCCA_flag = 1; ++ ODM_SetBBReg(pDM_Odm, 0xc6c, BIT8|BIT7, 2); // USC MF ++ if(PrimaryCCA->DupRTS_flag == 1) ++ PrimaryCCA->DupRTS_flag = 0; ++ } ++ else ++ { ++ PrimaryCCA->intf_type = 2; ++ if(PrimaryCCA->DupRTS_flag == 0) ++ PrimaryCCA->DupRTS_flag = 1; ++ } ++ ++ } ++ else // interferecne disappear ++ { ++ PrimaryCCA->DupRTS_flag = 0; ++ PrimaryCCA->intf_flag = 0; ++ PrimaryCCA->intf_type = 0; ++ } ++ } ++ else if(SecCHOffset == 2) // secondary channel is above the primary channel ++ { ++ if((FalseAlmCnt->Cnt_OFDM_CCA > 500)&&(FalseAlmCnt->Cnt_BW_USC > FalseAlmCnt->Cnt_BW_LSC+500)) ++ { ++ if(FalseAlmCnt->Cnt_Ofdm_fail > FalseAlmCnt->Cnt_OFDM_CCA>>1) ++ { ++ PrimaryCCA->intf_type = 1; ++ PrimaryCCA->PriCCA_flag = 1; ++ ODM_SetBBReg(pDM_Odm, 0xc6c, BIT8|BIT7, 1); // LSC MF ++ if(PrimaryCCA->DupRTS_flag == 1) ++ PrimaryCCA->DupRTS_flag = 0; ++ } ++ else ++ { ++ PrimaryCCA->intf_type = 2; ++ if(PrimaryCCA->DupRTS_flag == 0) ++ PrimaryCCA->DupRTS_flag = 1; ++ } ++ ++ } ++ else // interferecne disappear ++ { ++ PrimaryCCA->DupRTS_flag = 0; ++ PrimaryCCA->intf_flag = 0; ++ PrimaryCCA->intf_type = 0; ++ } ++ ++ ++ } ++ PrimaryCCA->Monitor_flag = 0; ++ } ++ ++ //1 Dynamic Primary CCA Main Function ++ if(PrimaryCCA->Monitor_flag == 0) ++ { ++ if(Is40MHz) // if RFBW==40M mode which require to process primary cca ++ { ++ //2 STA is NOT Connected ++ if(!bConnected) ++ { ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("STA NOT Connected!!!!\n")); ++ ++ if(PrimaryCCA->PriCCA_flag == 1) // reset primary cca when STA is disconnected ++ { ++ PrimaryCCA->PriCCA_flag = 0; ++ ODM_SetBBReg(pDM_Odm, 0xc6c, BIT8|BIT7, 0); ++ } ++ if(PrimaryCCA->DupRTS_flag == 1) // reset Duplicate RTS when STA is disconnected ++ PrimaryCCA->DupRTS_flag = 0; ++ ++ if(SecCHOffset == 1) // secondary channel is below the primary channel ++ { ++ if((FalseAlmCnt->Cnt_OFDM_CCA > 800)&&(FalseAlmCnt->Cnt_BW_LSC*5 > FalseAlmCnt->Cnt_BW_USC*9)) ++ { ++ PrimaryCCA->intf_flag = 1; // secondary channel interference is detected!!! ++ if(FalseAlmCnt->Cnt_Ofdm_fail > FalseAlmCnt->Cnt_OFDM_CCA>>1) ++ PrimaryCCA->intf_type = 1; // interference is shift ++ else ++ PrimaryCCA->intf_type = 2; // interference is in-band ++ } ++ else ++ { ++ PrimaryCCA->intf_flag = 0; ++ PrimaryCCA->intf_type = 0; ++ } ++ } ++ else if(SecCHOffset == 2) // secondary channel is above the primary channel ++ { ++ if((FalseAlmCnt->Cnt_OFDM_CCA > 800)&&(FalseAlmCnt->Cnt_BW_USC*5 > FalseAlmCnt->Cnt_BW_LSC*9)) ++ { ++ PrimaryCCA->intf_flag = 1; // secondary channel interference is detected!!! ++ if(FalseAlmCnt->Cnt_Ofdm_fail > FalseAlmCnt->Cnt_OFDM_CCA>>1) ++ PrimaryCCA->intf_type = 1; // interference is shift ++ else ++ PrimaryCCA->intf_type = 2; // interference is in-band ++ } ++ else ++ { ++ PrimaryCCA->intf_flag = 0; ++ PrimaryCCA->intf_type = 0; ++ } ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("PrimaryCCA=%d\n",PrimaryCCA->PriCCA_flag)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Intf_Type=%d\n", PrimaryCCA->intf_type)); ++ } ++ //2 STA is Connected ++ else ++ { ++ if(Client_40MHz == 0) //3 // client BW = 20MHz ++ { ++ if(PrimaryCCA->PriCCA_flag == 0) ++ { ++ PrimaryCCA->PriCCA_flag = 1; ++ if(SecCHOffset==1) ++ ODM_SetBBReg(pDM_Odm, 0xc6c, BIT8|BIT7, 2); ++ else if(SecCHOffset==2) ++ ODM_SetBBReg(pDM_Odm, 0xc6c, BIT8|BIT7, 1); ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("STA Connected 20M!!! PrimaryCCA=%d\n", PrimaryCCA->PriCCA_flag)); ++ } ++ else //3 // client BW = 40MHz ++ { ++ if(PrimaryCCA->intf_flag == 1) // interference is detected!! ++ { ++ if(PrimaryCCA->intf_type == 1) ++ { ++ if(PrimaryCCA->PriCCA_flag!=1) ++ { ++ PrimaryCCA->PriCCA_flag = 1; ++ if(SecCHOffset==1) ++ ODM_SetBBReg(pDM_Odm, 0xc6c, BIT8|BIT7, 2); ++ else if(SecCHOffset==2) ++ ODM_SetBBReg(pDM_Odm, 0xc6c, BIT8|BIT7, 1); ++ } ++ } ++ else if(PrimaryCCA->intf_type == 2) ++ { ++ if(PrimaryCCA->DupRTS_flag!=1) ++ PrimaryCCA->DupRTS_flag = 1; ++ } ++ } ++ else // if intf_flag==0 ++ { ++ if((curTxOkCnt+curRxOkCnt)<10000) //idle mode or TP traffic is very low ++ { ++ if(SecCHOffset == 1) ++ { ++ if((FalseAlmCnt->Cnt_OFDM_CCA > 800)&&(FalseAlmCnt->Cnt_BW_LSC*5 > FalseAlmCnt->Cnt_BW_USC*9)) ++ { ++ PrimaryCCA->intf_flag = 1; ++ if(FalseAlmCnt->Cnt_Ofdm_fail > FalseAlmCnt->Cnt_OFDM_CCA>>1) ++ PrimaryCCA->intf_type = 1; // interference is shift ++ else ++ PrimaryCCA->intf_type = 2; // interference is in-band ++ } ++ } ++ else if(SecCHOffset == 2) ++ { ++ if((FalseAlmCnt->Cnt_OFDM_CCA > 800)&&(FalseAlmCnt->Cnt_BW_USC*5 > FalseAlmCnt->Cnt_BW_LSC*9)) ++ { ++ PrimaryCCA->intf_flag = 1; ++ if(FalseAlmCnt->Cnt_Ofdm_fail > FalseAlmCnt->Cnt_OFDM_CCA>>1) ++ PrimaryCCA->intf_type = 1; // interference is shift ++ else ++ PrimaryCCA->intf_type = 2; // interference is in-band ++ } ++ ++ } ++ } ++ else // TP Traffic is High ++ { ++ if(SecCHOffset == 1) ++ { ++ if(FalseAlmCnt->Cnt_BW_LSC > (FalseAlmCnt->Cnt_BW_USC+500)) ++ { ++ if(Delay == 0) // add delay to avoid interference occurring abruptly, jump one time ++ { ++ PrimaryCCA->intf_flag = 1; ++ if(FalseAlmCnt->Cnt_Ofdm_fail > FalseAlmCnt->Cnt_OFDM_CCA>>1) ++ PrimaryCCA->intf_type = 1; // interference is shift ++ else ++ PrimaryCCA->intf_type = 2; // interference is in-band ++ Delay = 1; ++ } ++ else ++ Delay = 0; ++ } ++ } ++ else if(SecCHOffset == 2) ++ { ++ if(FalseAlmCnt->Cnt_BW_USC > (FalseAlmCnt->Cnt_BW_LSC+500)) ++ { ++ if(Delay == 0) // add delay to avoid interference occurring abruptly ++ { ++ PrimaryCCA->intf_flag = 1; ++ if(FalseAlmCnt->Cnt_Ofdm_fail > FalseAlmCnt->Cnt_OFDM_CCA>>1) ++ PrimaryCCA->intf_type = 1; // interference is shift ++ else ++ PrimaryCCA->intf_type = 2; // interference is in-band ++ Delay = 1; ++ } ++ else ++ Delay = 0; ++ } ++ } ++ } ++ } ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Primary CCA=%d\n", PrimaryCCA->PriCCA_flag)); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Duplicate RTS=%d\n", PrimaryCCA->DupRTS_flag)); ++ } ++ ++ }// end of connected ++ } ++ } ++ //1 Dynamic Primary CCA Monitor Counter ++ if((PrimaryCCA->PriCCA_flag == 1)||(PrimaryCCA->DupRTS_flag == 1)) ++ { ++ if(Client_40MHz == 0) // client=20M no need to monitor primary cca flag ++ { ++ Client_40MHz_pre = Client_40MHz; ++ return; ++ } ++ Counter++; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Counter=%d\n", Counter)); ++ if((Counter == 30)||((Client_40MHz -Client_40MHz_pre)==1)) // Every 60 sec to monitor one time ++ { ++ PrimaryCCA->Monitor_flag = 1; // monitor flag is triggered!!!!! ++ if(PrimaryCCA->PriCCA_flag == 1) ++ { ++ PrimaryCCA->PriCCA_flag = 0; ++ ODM_SetBBReg(pDM_Odm, 0xc6c, BIT8|BIT7, 0); ++ } ++ Counter = 0; ++ } ++ } ++ } ++ ++ Client_40MHz_pre = Client_40MHz; ++} ++#else //#if (RTL8188E_SUPPORT == 1) ++VOID ++ODM_UpdateRxIdleAnt_88E(IN PDM_ODM_T pDM_Odm, IN u1Byte Ant) ++{ ++} ++VOID ++odm_PrimaryCCA_Init( ++ IN PDM_ODM_T pDM_Odm) ++{ ++} ++VOID ++odm_DynamicPrimaryCCA( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++} ++BOOLEAN ++ODM_DynamicPrimaryCCA_DupRTS( ++ IN PDM_ODM_T pDM_Odm ++ ) ++{ ++ return FALSE; ++} ++#endif //#if (RTL8188E_SUPPORT == 1) ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/odm_RTL8188E.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/odm_RTL8188E.h +new file mode 100644 +index 00000000..ac0e0067 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/odm_RTL8188E.h +@@ -0,0 +1,109 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __ODM_RTL8188E_H__ ++#define __ODM_RTL8188E_H__ ++ ++#define MAIN_ANT 0 ++#define AUX_ANT 1 ++#define MAIN_ANT_CG_TRX 1 ++#define AUX_ANT_CG_TRX 0 ++#define MAIN_ANT_CGCS_RX 0 ++#define AUX_ANT_CGCS_RX 1 ++ ++VOID ++ODM_DIG_LowerBound_88E( ++ IN PDM_ODM_T pDM_Odm ++); ++#if ( !(DM_ODM_SUPPORT_TYPE == ODM_CE)) ++VOID ++odm_FastAntTrainingInit( ++ IN PDM_ODM_T pDM_Odm ++); ++#endif ++ ++VOID ++ODM_AntennaDiversityInit_88E( ++ IN PDM_ODM_T pDM_Odm ++); ++ ++VOID ++ODM_AntennaDiversity_88E ++( ++ IN PDM_ODM_T pDM_Odm ++); ++ ++#if (DM_ODM_SUPPORT_TYPE & (ODM_MP|ODM_CE)) ++VOID ++ODM_SetTxAntByTxInfo_88E( ++ IN PDM_ODM_T pDM_Odm, ++ IN pu1Byte pDesc, ++ IN u1Byte macId ++); ++#else// (DM_ODM_SUPPORT_TYPE == ODM_AP) ++VOID ++ODM_SetTxAntByTxInfo_88E( ++ IN PDM_ODM_T pDM_Odm ++); ++#endif ++ ++VOID ++ODM_UpdateRxIdleAnt_88E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte Ant ++); ++ ++VOID ++ODM_AntselStatistics_88E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u1Byte antsel_tr_mux, ++ IN u4Byte MacId, ++ IN u1Byte RxPWDBAll ++); ++ ++#if ( !(DM_ODM_SUPPORT_TYPE == ODM_CE)) ++VOID ++odm_FastAntTraining( ++ IN PDM_ODM_T pDM_Odm ++); ++ ++VOID ++odm_FastAntTrainingCallback( ++ IN PDM_ODM_T pDM_Odm ++); ++ ++VOID ++odm_FastAntTrainingWorkItemCallback( ++ IN PDM_ODM_T pDM_Odm ++); ++#endif ++VOID ++odm_PrimaryCCA_Init( ++ IN PDM_ODM_T pDM_Odm); ++ ++BOOLEAN ++ODM_DynamicPrimaryCCA_DupRTS( ++ IN PDM_ODM_T pDM_Odm); ++ ++VOID ++odm_DynamicPrimaryCCA( ++ IN PDM_ODM_T pDM_Odm); ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/odm_RegConfig8188E.c b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/odm_RegConfig8188E.c +new file mode 100644 +index 00000000..e0e7c8b8 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/odm_RegConfig8188E.c +@@ -0,0 +1,209 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#include "../odm_precomp.h" ++ ++#if (RTL8188E_SUPPORT == 1) ++ ++void ++odm_ConfigRFReg_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte Addr, ++ IN u4Byte Data, ++ IN ODM_RF_RADIO_PATH_E RF_PATH, ++ IN u4Byte RegAddr ++ ) ++{ ++ if(Addr == 0xffe) ++ { ++ #ifdef CONFIG_LONG_DELAY_ISSUE ++ ODM_sleep_ms(50); ++ #else ++ ODM_delay_ms(50); ++ #endif ++ } ++ else if (Addr == 0xfd) ++ { ++ ODM_delay_ms(5); ++ } ++ else if (Addr == 0xfc) ++ { ++ ODM_delay_ms(1); ++ } ++ else if (Addr == 0xfb) ++ { ++ ODM_delay_us(50); ++ } ++ else if (Addr == 0xfa) ++ { ++ ODM_delay_us(5); ++ } ++ else if (Addr == 0xf9) ++ { ++ ODM_delay_us(1); ++ } ++ else ++ { ++ ODM_SetRFReg(pDM_Odm, RF_PATH, RegAddr, bRFRegOffsetMask, Data); ++ // Add 1us delay between BB/RF register setting. ++ ODM_delay_us(1); ++ } ++} ++ ++ ++void ++odm_ConfigRF_RadioA_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte Addr, ++ IN u4Byte Data ++ ) ++{ ++ u4Byte content = 0x1000; // RF_Content: radioa_txt ++ u4Byte maskforPhySet= (u4Byte)(content&0xE000); ++ ++ odm_ConfigRFReg_8188E(pDM_Odm, Addr, Data, ODM_RF_PATH_A, Addr|maskforPhySet); ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigRFWithHeaderFile: [RadioA] %08X %08X\n", Addr, Data)); ++} ++ ++void ++odm_ConfigRF_RadioB_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte Addr, ++ IN u4Byte Data ++ ) ++{ ++ u4Byte content = 0x1001; // RF_Content: radiob_txt ++ u4Byte maskforPhySet= (u4Byte)(content&0xE000); ++ ++ odm_ConfigRFReg_8188E(pDM_Odm, Addr, Data, ODM_RF_PATH_B, Addr|maskforPhySet); ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigRFWithHeaderFile: [RadioB] %08X %08X\n", Addr, Data)); ++ ++} ++ ++void ++odm_ConfigMAC_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte Addr, ++ IN u1Byte Data ++ ) ++{ ++ ODM_Write1Byte(pDM_Odm, Addr, Data); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigMACWithHeaderFile: [MAC_REG] %08X %08X\n", Addr, Data)); ++} ++ ++void ++odm_ConfigBB_AGC_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte Addr, ++ IN u4Byte Bitmask, ++ IN u4Byte Data ++ ) ++{ ++ ODM_SetBBReg(pDM_Odm, Addr, Bitmask, Data); ++ // Add 1us delay between BB/RF register setting. ++ ODM_delay_us(1); ++ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigBBWithHeaderFile: [AGC_TAB] %08X %08X\n", Addr, Data)); ++} ++ ++void ++odm_ConfigBB_PHY_REG_PG_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte Addr, ++ IN u4Byte Bitmask, ++ IN u4Byte Data ++ ) ++{ ++ if (Addr == 0xfe){ ++ #ifdef CONFIG_LONG_DELAY_ISSUE ++ ODM_sleep_ms(50); ++ #else ++ ODM_delay_ms(50); ++ #endif ++ } ++ else if (Addr == 0xfd){ ++ ODM_delay_ms(5); ++ } ++ else if (Addr == 0xfc){ ++ ODM_delay_ms(1); ++ } ++ else if (Addr == 0xfb){ ++ ODM_delay_us(50); ++ } ++ else if (Addr == 0xfa){ ++ ODM_delay_us(5); ++ } ++ else if (Addr == 0xf9){ ++ ODM_delay_us(1); ++ } ++ else{ ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_INIT, ODM_DBG_LOUD, ("===> @@@@@@@ ODM_ConfigBBWithHeaderFile: [PHY_REG] %08X %08X %08X\n", Addr, Bitmask, Data)); ++ ++ #if !(DM_ODM_SUPPORT_TYPE&ODM_AP) ++ storePwrIndexDiffRateOffset(pDM_Odm->Adapter, Addr, Bitmask, Data); ++ #endif ++ } ++ ++} ++ ++void ++odm_ConfigBB_PHY_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte Addr, ++ IN u4Byte Bitmask, ++ IN u4Byte Data ++ ) ++{ ++ if (Addr == 0xfe){ ++ #ifdef CONFIG_LONG_DELAY_ISSUE ++ ODM_sleep_ms(50); ++ #else ++ ODM_delay_ms(50); ++ #endif ++ } ++ else if (Addr == 0xfd){ ++ ODM_delay_ms(5); ++ } ++ else if (Addr == 0xfc){ ++ ODM_delay_ms(1); ++ } ++ else if (Addr == 0xfb){ ++ ODM_delay_us(50); ++ } ++ else if (Addr == 0xfa){ ++ ODM_delay_us(5); ++ } ++ else if (Addr == 0xf9){ ++ ODM_delay_us(1); ++ } ++ else{ ++ if (Addr == 0xa24) ++ pDM_Odm->RFCalibrateInfo.RegA24 = Data; ++ ODM_SetBBReg(pDM_Odm, Addr, Bitmask, Data); ++ ++ // Add 1us delay between BB/RF register setting. ++ ODM_delay_us(1); ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigBBWithHeaderFile: [PHY_REG] %08X %08X\n", Addr, Data)); ++ } ++} ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/odm_RegConfig8188E.h b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/odm_RegConfig8188E.h +new file mode 100644 +index 00000000..211b96de +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/OUTSRC/rtl8188e/odm_RegConfig8188E.h +@@ -0,0 +1,80 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __INC_ODM_REGCONFIG_H_8188E ++#define __INC_ODM_REGCONFIG_H_8188E ++ ++#if (RTL8188E_SUPPORT == 1) ++ ++void ++odm_ConfigRFReg_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte Addr, ++ IN u4Byte Data, ++ IN ODM_RF_RADIO_PATH_E RF_PATH, ++ IN u4Byte RegAddr ++ ); ++ ++void ++odm_ConfigRF_RadioA_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte Addr, ++ IN u4Byte Data ++ ); ++ ++void ++odm_ConfigRF_RadioB_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte Addr, ++ IN u4Byte Data ++ ); ++ ++void ++odm_ConfigMAC_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte Addr, ++ IN u1Byte Data ++ ); ++ ++void ++odm_ConfigBB_AGC_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte Addr, ++ IN u4Byte Bitmask, ++ IN u4Byte Data ++ ); ++ ++void ++odm_ConfigBB_PHY_REG_PG_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte Addr, ++ IN u4Byte Bitmask, ++ IN u4Byte Data ++ ); ++ ++void ++odm_ConfigBB_PHY_8188E( ++ IN PDM_ODM_T pDM_Odm, ++ IN u4Byte Addr, ++ IN u4Byte Bitmask, ++ IN u4Byte Data ++ ); ++#endif ++#endif // end of SUPPORT ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/hal_com.c b/drivers/net/wireless/rtl818x/rtl8189/hal/hal_com.c +new file mode 100644 +index 00000000..9f413a09 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/hal_com.c +@@ -0,0 +1,453 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#ifdef CONFIG_RTL8192C ++#include ++#endif ++#ifdef CONFIG_RTL8192D ++#include ++#endif ++#ifdef CONFIG_RTL8723A ++#include ++#endif ++#ifdef CONFIG_RTL8188E ++#include ++#endif ++ ++#define _HAL_INIT_C_ ++ ++void dump_chip_info(HAL_VERSION ChipVersion) ++{ ++ int cnt = 0; ++ u8 buf[128]; ++ ++ if(IS_81XXC(ChipVersion)){ ++ cnt += sprintf((buf+cnt), "Chip Version Info: %s_", IS_92C_SERIAL(ChipVersion)?"CHIP_8192C":"CHIP_8188C"); ++ } ++ else if(IS_92D(ChipVersion)){ ++ cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8192D_"); ++ } ++ else if(IS_8723_SERIES(ChipVersion)){ ++ cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8723A_"); ++ } ++ else if(IS_8188E(ChipVersion)){ ++ cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8188E_"); ++ } ++ ++ cnt += sprintf((buf+cnt), "%s_", IS_NORMAL_CHIP(ChipVersion)?"Normal_Chip":"Test_Chip"); ++ cnt += sprintf((buf+cnt), "%s_", IS_CHIP_VENDOR_TSMC(ChipVersion)?"TSMC":"UMC"); ++ if(IS_A_CUT(ChipVersion)) cnt += sprintf((buf+cnt), "A_CUT_"); ++ else if(IS_B_CUT(ChipVersion)) cnt += sprintf((buf+cnt), "B_CUT_"); ++ else if(IS_C_CUT(ChipVersion)) cnt += sprintf((buf+cnt), "C_CUT_"); ++ else if(IS_D_CUT(ChipVersion)) cnt += sprintf((buf+cnt), "D_CUT_"); ++ else if(IS_E_CUT(ChipVersion)) cnt += sprintf((buf+cnt), "E_CUT_"); ++ else if(IS_I_CUT(ChipVersion)) cnt += sprintf((buf+cnt), "I_CUT_"); ++ else if(IS_J_CUT(ChipVersion)) cnt += sprintf((buf+cnt), "J_CUT_"); ++ else if(IS_K_CUT(ChipVersion)) cnt += sprintf((buf+cnt), "K_CUT_"); ++ else cnt += sprintf((buf+cnt), "UNKNOWN_CUT(%d)_", ChipVersion.CUTVersion); ++ ++ if(IS_1T1R(ChipVersion)) cnt += sprintf((buf+cnt), "1T1R_"); ++ else if(IS_1T2R(ChipVersion)) cnt += sprintf((buf+cnt), "1T2R_"); ++ else if(IS_2T2R(ChipVersion)) cnt += sprintf((buf+cnt), "2T2R_"); ++ else cnt += sprintf((buf+cnt), "UNKNOWN_RFTYPE(%d)_", ChipVersion.RFType); ++ ++ cnt += sprintf((buf+cnt), "RomVer(%d)\n", ChipVersion.ROMVer); ++ ++ DBG_871X("%s", buf); ++} ++ ++ ++#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 ++ ++u8 //return the final channel plan decision ++hal_com_get_channel_plan( ++ IN PADAPTER padapter, ++ IN u8 hw_channel_plan, //channel plan from HW (efuse/eeprom) ++ IN u8 sw_channel_plan, //channel plan from SW (registry/module param) ++ IN u8 def_channel_plan, //channel plan used when the former two is invalid ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++ u8 swConfig; ++ u8 chnlPlan; ++ ++ swConfig = _TRUE; ++ if (!AutoLoadFail) ++ { ++ if (!rtw_is_channel_plan_valid(sw_channel_plan)) ++ swConfig = _FALSE; ++ if (hw_channel_plan & EEPROM_CHANNEL_PLAN_BY_HW_MASK) ++ swConfig = _FALSE; ++ } ++ ++ if (swConfig == _TRUE) ++ chnlPlan = sw_channel_plan; ++ else ++ chnlPlan = hw_channel_plan & (~EEPROM_CHANNEL_PLAN_BY_HW_MASK); ++ ++ if (!rtw_is_channel_plan_valid(chnlPlan)) ++ chnlPlan = def_channel_plan; ++ ++ return chnlPlan; ++} ++ ++u8 MRateToHwRate(u8 rate) ++{ ++ u8 ret = DESC_RATE1M; ++ ++ switch(rate) ++ { ++ // CCK and OFDM non-HT rates ++ case IEEE80211_CCK_RATE_1MB: ret = DESC_RATE1M; break; ++ case IEEE80211_CCK_RATE_2MB: ret = DESC_RATE2M; break; ++ case IEEE80211_CCK_RATE_5MB: ret = DESC_RATE5_5M; break; ++ case IEEE80211_CCK_RATE_11MB: ret = DESC_RATE11M; break; ++ case IEEE80211_OFDM_RATE_6MB: ret = DESC_RATE6M; break; ++ case IEEE80211_OFDM_RATE_9MB: ret = DESC_RATE9M; break; ++ case IEEE80211_OFDM_RATE_12MB: ret = DESC_RATE12M; break; ++ case IEEE80211_OFDM_RATE_18MB: ret = DESC_RATE18M; break; ++ case IEEE80211_OFDM_RATE_24MB: ret = DESC_RATE24M; break; ++ case IEEE80211_OFDM_RATE_36MB: ret = DESC_RATE36M; break; ++ case IEEE80211_OFDM_RATE_48MB: ret = DESC_RATE48M; break; ++ case IEEE80211_OFDM_RATE_54MB: ret = DESC_RATE54M; break; ++ ++ // HT rates since here ++ //case MGN_MCS0: ret = DESC_RATEMCS0; break; ++ //case MGN_MCS1: ret = DESC_RATEMCS1; break; ++ //case MGN_MCS2: ret = DESC_RATEMCS2; break; ++ //case MGN_MCS3: ret = DESC_RATEMCS3; break; ++ //case MGN_MCS4: ret = DESC_RATEMCS4; break; ++ //case MGN_MCS5: ret = DESC_RATEMCS5; break; ++ //case MGN_MCS6: ret = DESC_RATEMCS6; break; ++ //case MGN_MCS7: ret = DESC_RATEMCS7; break; ++ ++ default: break; ++ } ++ ++ return ret; ++} ++ ++void HalSetBrateCfg( ++ IN PADAPTER Adapter, ++ IN u8 *mBratesOS, ++ OUT u16 *pBrateCfg) ++{ ++ u8 i, is_brate, brate; ++ ++ for(i=0;iQueue2Pipe[0] = pdvobjpriv->RtOutPipe[0];//VO ++ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];//VI ++ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[0];//BE ++ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];//BK ++ ++ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];//BCN ++ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];//MGT ++ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];//HIGH ++ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];//TXCMD ++} ++ ++static VOID ++_TwoOutPipeMapping( ++ IN PADAPTER pAdapter, ++ IN BOOLEAN bWIFICfg ++ ) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter); ++ ++ if(bWIFICfg){ //WMM ++ ++ // BK, BE, VI, VO, BCN, CMD,MGT,HIGH,HCCA ++ //{ 0, 1, 0, 1, 0, 0, 0, 0, 0 }; ++ //0:H, 1:L ++ ++ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[1];//VO ++ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];//VI ++ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];//BE ++ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];//BK ++ ++ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];//BCN ++ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];//MGT ++ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];//HIGH ++ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];//TXCMD ++ ++ } ++ else{//typical setting ++ ++ ++ //BK, BE, VI, VO, BCN, CMD,MGT,HIGH,HCCA ++ //{ 1, 1, 0, 0, 0, 0, 0, 0, 0 }; ++ //0:H, 1:L ++ ++ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];//VO ++ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];//VI ++ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];//BE ++ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];//BK ++ ++ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];//BCN ++ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];//MGT ++ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];//HIGH ++ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];//TXCMD ++ ++ } ++ ++} ++ ++static VOID _ThreeOutPipeMapping( ++ IN PADAPTER pAdapter, ++ IN BOOLEAN bWIFICfg ++ ) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter); ++ ++ if(bWIFICfg){//for WMM ++ ++ // BK, BE, VI, VO, BCN, CMD,MGT,HIGH,HCCA ++ //{ 1, 2, 1, 0, 0, 0, 0, 0, 0 }; ++ //0:H, 1:N, 2:L ++ ++ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];//VO ++ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];//VI ++ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];//BE ++ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];//BK ++ ++ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];//BCN ++ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];//MGT ++ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];//HIGH ++ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];//TXCMD ++ ++ } ++ else{//typical setting ++ ++ ++ // BK, BE, VI, VO, BCN, CMD,MGT,HIGH,HCCA ++ //{ 2, 2, 1, 0, 0, 0, 0, 0, 0 }; ++ //0:H, 1:N, 2:L ++ ++ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];//VO ++ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];//VI ++ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];//BE ++ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[2];//BK ++ ++ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];//BCN ++ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];//MGT ++ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];//HIGH ++ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];//TXCMD ++ } ++ ++} ++ ++BOOLEAN ++Hal_MappingOutPipe( ++ IN PADAPTER pAdapter, ++ IN u8 NumOutPipe ++ ) ++{ ++ struct registry_priv *pregistrypriv = &pAdapter->registrypriv; ++ ++ BOOLEAN bWIFICfg = (pregistrypriv->wifi_spec) ?_TRUE:_FALSE; ++ ++ BOOLEAN result = _TRUE; ++ ++ switch(NumOutPipe) ++ { ++ case 2: ++ _TwoOutPipeMapping(pAdapter, bWIFICfg); ++ break; ++ case 3: ++ _ThreeOutPipeMapping(pAdapter, bWIFICfg); ++ break; ++ case 1: ++ _OneOutPipeMapping(pAdapter); ++ break; ++ default: ++ result = _FALSE; ++ break; ++ } ++ ++ return result; ++ ++} ++ ++void hal_init_macaddr(_adapter *adapter) ++{ ++ rtw_hal_set_hwreg(adapter, HW_VAR_MAC_ADDR, adapter->eeprompriv.mac_addr); ++#ifdef CONFIG_CONCURRENT_MODE ++ if (adapter->pbuddy_adapter) ++ rtw_hal_set_hwreg(adapter->pbuddy_adapter, HW_VAR_MAC_ADDR, adapter->pbuddy_adapter->eeprompriv.mac_addr); ++#endif ++} ++ ++/* ++* C2H event format: ++* Field TRIGGER CONTENT CMD_SEQ CMD_LEN CMD_ID ++* BITS [127:120] [119:16] [15:8] [7:4] [3:0] ++*/ ++ ++void c2h_evt_clear(_adapter *adapter) ++{ ++ rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE); ++} ++ ++s32 c2h_evt_read(_adapter *adapter, u8 *buf) ++{ ++ s32 ret = _FAIL; ++ struct c2h_evt_hdr *c2h_evt; ++ int i; ++ u8 trigger; ++ ++ if (buf == NULL) ++ goto exit; ++ ++ trigger = rtw_read8(adapter, REG_C2HEVT_CLEAR); ++ ++ if (trigger == C2H_EVT_HOST_CLOSE) { ++ goto exit; /* Not ready */ ++ } else if (trigger != C2H_EVT_FW_CLOSE) { ++ goto clear_evt; /* Not a valid value */ ++ } ++ ++ c2h_evt = (struct c2h_evt_hdr *)buf; ++ ++ _rtw_memset(c2h_evt, 0, 16); ++ ++ *buf = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL); ++ *(buf+1) = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 1); ++ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_info_, "c2h_evt_read(): ", ++ &c2h_evt , sizeof(c2h_evt)); ++ ++ if (0) { ++ DBG_871X("%s id:%u, len:%u, seq:%u, trigger:0x%02x\n", __func__ ++ , c2h_evt->id, c2h_evt->plen, c2h_evt->seq, trigger); ++ } ++ ++ /* Read the content */ ++ for (i = 0; i < c2h_evt->plen; i++) ++ c2h_evt->payload[i] = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + sizeof(*c2h_evt) + i); ++ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_info_, "c2h_evt_read(): Command Content:\n", ++ c2h_evt->payload, c2h_evt->plen); ++ ++ ret = _SUCCESS; ++ ++clear_evt: ++ /* ++ * Clear event to notify FW we have read the command. ++ * If this field isn't clear, the FW won't update the next command message. ++ */ ++ c2h_evt_clear(adapter); ++exit: ++ return ret; ++} ++ ++u8 ++SetHalDefVar(_adapter *adapter, HAL_DEF_VARIABLE variable, void *value) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ u8 bResult = _SUCCESS; ++ ++ switch(variable) { ++ case HW_DEF_FA_CNT_DUMP: ++ if(*((u8*)value)) ++ pDM_Odm->DebugComponents |= (ODM_COMP_DIG |ODM_COMP_FA_CNT); ++ else ++ pDM_Odm->DebugComponents &= ~(ODM_COMP_DIG |ODM_COMP_FA_CNT); ++ break; ++ case HW_DEF_ODM_DBG_FLAG: ++ ODM_CmnInfoUpdate(pDM_Odm, ODM_CMNINFO_DBG_COMP, *((u8Byte*)value)); ++ break; ++ case HW_DEF_ODM_DBG_LEVEL: ++ ODM_CmnInfoUpdate(pDM_Odm, ODM_CMNINFO_DBG_LEVEL, *((u4Byte*)value)); ++ break; ++ default: ++ DBG_871X_LEVEL(_drv_always_, "%s: [WARNING] HAL_DEF_VARIABLE(%d) not defined!\n", __FUNCTION__, variable); ++ bResult = _FAIL; ++ break; ++ } ++ ++ return bResult; ++} ++ ++u8 ++GetHalDefVar(_adapter *adapter, HAL_DEF_VARIABLE variable, void *value) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ u8 bResult = _SUCCESS; ++ ++ switch(variable) { ++ case HW_DEF_ODM_DBG_FLAG: ++ *((u8Byte*)value) = pDM_Odm->DebugComponents; ++ break; ++ case HW_DEF_ODM_DBG_LEVEL: ++ *((u4Byte*)value) = pDM_Odm->DebugLevel; ++ break; ++ case HAL_DEF_DBG_DM_FUNC: ++ *((u32*)value) = pHalData->odmpriv.SupportAbility; ++ break; ++ default: ++ DBG_871X_LEVEL(_drv_always_, "%s: [WARNING] HAL_DEF_VARIABLE(%d) not defined!\n", __FUNCTION__, variable); ++ bResult = _FAIL; ++ break; ++ } ++ ++ return bResult; ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/hal_intf.c b/drivers/net/wireless/rtl818x/rtl8189/hal/hal_intf.c +new file mode 100644 +index 00000000..8b785532 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/hal_intf.c +@@ -0,0 +1,591 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#define _HAL_INTF_C_ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#ifdef CONFIG_SDIO_HCI ++ #include ++#elif defined(CONFIG_USB_HCI) ++ #include ++#elif defined(CONFIG_GSPI_HCI) ++ #include ++#endif ++ ++void rtw_hal_chip_configure(_adapter *padapter) ++{ ++ if(padapter->HalFunc.intf_chip_configure) ++ padapter->HalFunc.intf_chip_configure(padapter); ++} ++ ++void rtw_hal_read_chip_info(_adapter *padapter) ++{ ++ if(padapter->HalFunc.read_adapter_info) ++ padapter->HalFunc.read_adapter_info(padapter); ++} ++ ++void rtw_hal_read_chip_version(_adapter *padapter) ++{ ++ if(padapter->HalFunc.read_chip_version) ++ padapter->HalFunc.read_chip_version(padapter); ++} ++ ++void rtw_hal_def_value_init(_adapter *padapter) ++{ ++ if (is_primary_adapter(padapter)) ++ if(padapter->HalFunc.init_default_value) ++ padapter->HalFunc.init_default_value(padapter); ++} ++void rtw_hal_free_data(_adapter *padapter) ++{ ++ if (is_primary_adapter(padapter)) ++ if(padapter->HalFunc.free_hal_data) ++ padapter->HalFunc.free_hal_data(padapter); ++} ++void rtw_hal_dm_init(_adapter *padapter) ++{ ++ if (is_primary_adapter(padapter)) ++ if(padapter->HalFunc.dm_init) ++ padapter->HalFunc.dm_init(padapter); ++} ++void rtw_hal_dm_deinit(_adapter *padapter) ++{ ++ // cancel dm timer ++ if (is_primary_adapter(padapter)) ++ if(padapter->HalFunc.dm_deinit) ++ padapter->HalFunc.dm_deinit(padapter); ++} ++void rtw_hal_sw_led_init(_adapter *padapter) ++{ ++ if(padapter->HalFunc.InitSwLeds) ++ padapter->HalFunc.InitSwLeds(padapter); ++} ++ ++void rtw_hal_sw_led_deinit(_adapter *padapter) ++{ ++ if(padapter->HalFunc.DeInitSwLeds) ++ padapter->HalFunc.DeInitSwLeds(padapter); ++} ++ ++u32 rtw_hal_power_on(_adapter *padapter) ++{ ++ if(padapter->HalFunc.hal_power_on) ++ return padapter->HalFunc.hal_power_on(padapter); ++ return _FAIL; ++} ++void rtw_hal_power_off(_adapter *padapter) ++{ ++ if(padapter->HalFunc.hal_power_off) ++ padapter->HalFunc.hal_power_off(padapter); ++} ++ ++ ++uint rtw_hal_init(_adapter *padapter) ++{ ++ uint status = _SUCCESS; ++ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); ++ int i; ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ if(padapter->hw_init_completed == _TRUE) ++ { ++ DBG_871X("rtw_hal_init: hw_init_completed == _TRUE\n"); ++ return status; ++ } ++ ++ // before init mac0, driver must init mac1 first to avoid usb rx error. ++ if((padapter->pbuddy_adapter != NULL) && (padapter->DualMacConcurrent == _TRUE) ++ && (padapter->adapter_type == PRIMARY_ADAPTER)) ++ { ++ if(padapter->pbuddy_adapter->hw_init_completed == _TRUE) ++ { ++ DBG_871X("rtw_hal_init: pbuddy_adapter hw_init_completed == _TRUE\n"); ++ } ++ else ++ { ++ status = padapter->HalFunc.hal_init(padapter->pbuddy_adapter); ++ if(status == _SUCCESS){ ++ padapter->pbuddy_adapter->hw_init_completed = _TRUE; ++ } ++ else{ ++ padapter->pbuddy_adapter->hw_init_completed = _FALSE; ++ RT_TRACE(_module_hal_init_c_,_drv_err_,("rtw_hal_init: hal__init fail(pbuddy_adapter)\n")); ++ DBG_871X("rtw_hal_init: hal__init fail(pbuddy_adapter)\n"); ++ return status; ++ } ++ } ++ } ++#endif ++ ++ status = padapter->HalFunc.hal_init(padapter); ++ ++ if(status == _SUCCESS){ ++ for (i = 0; iiface_nums; i++) { ++ padapter = dvobj->padapters[i]; ++ padapter->hw_init_completed = _TRUE; ++ } ++ ++ if (padapter->registrypriv.notch_filter == 1) ++ rtw_hal_notch_filter(padapter, 1); ++ ++ rtw_hal_reset_security_engine(padapter); ++ rtw_sec_restore_wep_key(padapter); ++ ++ init_hw_mlme_ext(padapter); ++ } ++ else{ ++ for (i = 0; iiface_nums; i++) { ++ padapter = dvobj->padapters[i]; ++ padapter->hw_init_completed = _FALSE; ++ } ++ DBG_871X("rtw_hal_init: hal__init fail\n"); ++ } ++ ++ RT_TRACE(_module_hal_init_c_,_drv_err_,("-rtl871x_hal_init:status=0x%x\n",status)); ++ ++ return status; ++ ++} ++ ++uint rtw_hal_deinit(_adapter *padapter) ++{ ++ uint status = _SUCCESS; ++ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); ++ int i; ++ ++_func_enter_; ++ if (!is_primary_adapter(padapter)){ ++ DBG_871X(" rtw_hal_deinit: Secondary adapter return l\n"); ++ return status; ++ } ++ ++ status = padapter->HalFunc.hal_deinit(padapter); ++ ++ if(status == _SUCCESS){ ++ for (i = 0; iiface_nums; i++) { ++ padapter = dvobj->padapters[i]; ++ padapter->hw_init_completed = _FALSE; ++ } ++ } ++ else ++ { ++ DBG_871X("\n rtw_hal_deinit: hal_init fail\n"); ++ } ++ ++_func_exit_; ++ ++ return status; ++} ++ ++void rtw_hal_set_hwreg(_adapter *padapter, u8 variable, u8 *val) ++{ ++ if (padapter->HalFunc.SetHwRegHandler) ++ padapter->HalFunc.SetHwRegHandler(padapter, variable, val); ++} ++ ++void rtw_hal_get_hwreg(_adapter *padapter, u8 variable, u8 *val) ++{ ++ if (padapter->HalFunc.GetHwRegHandler) ++ padapter->HalFunc.GetHwRegHandler(padapter, variable, val); ++} ++ ++u8 rtw_hal_set_def_var(_adapter *padapter, HAL_DEF_VARIABLE eVariable, PVOID pValue) ++{ ++ if(padapter->HalFunc.SetHalDefVarHandler) ++ return padapter->HalFunc.SetHalDefVarHandler(padapter,eVariable,pValue); ++ return _FAIL; ++} ++u8 rtw_hal_get_def_var(_adapter *padapter, HAL_DEF_VARIABLE eVariable, PVOID pValue) ++{ ++ if(padapter->HalFunc.GetHalDefVarHandler) ++ return padapter->HalFunc.GetHalDefVarHandler(padapter,eVariable,pValue); ++ return _FAIL; ++} ++ ++void rtw_hal_set_odm_var(_adapter *padapter, HAL_ODM_VARIABLE eVariable, PVOID pValue1,BOOLEAN bSet) ++{ ++ if(padapter->HalFunc.SetHalODMVarHandler) ++ padapter->HalFunc.SetHalODMVarHandler(padapter,eVariable,pValue1,bSet); ++} ++void rtw_hal_get_odm_var(_adapter *padapter, HAL_ODM_VARIABLE eVariable, PVOID pValue1,BOOLEAN bSet) ++{ ++ if(padapter->HalFunc.GetHalODMVarHandler) ++ padapter->HalFunc.GetHalODMVarHandler(padapter,eVariable,pValue1,bSet); ++} ++ ++void rtw_hal_enable_interrupt(_adapter *padapter) ++{ ++ if (!is_primary_adapter(padapter)){ ++ DBG_871X(" rtw_hal_enable_interrupt: Secondary adapter return l\n"); ++ return; ++ } ++ ++ if (padapter->HalFunc.enable_interrupt) ++ padapter->HalFunc.enable_interrupt(padapter); ++ else ++ DBG_871X("%s: HalFunc.enable_interrupt is NULL!\n", __FUNCTION__); ++ ++} ++void rtw_hal_disable_interrupt(_adapter *padapter) ++{ ++ if (!is_primary_adapter(padapter)){ ++ DBG_871X(" rtw_hal_disable_interrupt: Secondary adapter return l\n"); ++ return; ++ } ++ ++ if (padapter->HalFunc.disable_interrupt) ++ padapter->HalFunc.disable_interrupt(padapter); ++ else ++ DBG_871X("%s: HalFunc.disable_interrupt is NULL!\n", __FUNCTION__); ++ ++} ++ ++ ++u32 rtw_hal_inirp_init(_adapter *padapter) ++{ ++ u32 rst = _FAIL; ++ if(padapter->HalFunc.inirp_init) ++ rst = padapter->HalFunc.inirp_init(padapter); ++ else ++ DBG_871X(" %s HalFunc.inirp_init is NULL!!!\n",__FUNCTION__); ++ return rst; ++} ++ ++u32 rtw_hal_inirp_deinit(_adapter *padapter) ++{ ++ ++ if(padapter->HalFunc.inirp_deinit) ++ return padapter->HalFunc.inirp_deinit(padapter); ++ ++ return _FAIL; ++ ++} ++ ++u8 rtw_hal_intf_ps_func(_adapter *padapter,HAL_INTF_PS_FUNC efunc_id, u8* val) ++{ ++ if(padapter->HalFunc.interface_ps_func) ++ return padapter->HalFunc.interface_ps_func(padapter,efunc_id,val); ++ return _FAIL; ++} ++ ++s32 rtw_hal_xmitframe_enqueue(_adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ if(padapter->HalFunc.hal_xmitframe_enqueue) ++ return padapter->HalFunc.hal_xmitframe_enqueue(padapter, pxmitframe); ++ ++ return _FALSE; ++} ++ ++s32 rtw_hal_xmit(_adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ if(padapter->HalFunc.hal_xmit) ++ return padapter->HalFunc.hal_xmit(padapter, pxmitframe); ++ ++ return _FALSE; ++} ++ ++s32 rtw_hal_mgnt_xmit(_adapter *padapter, struct xmit_frame *pmgntframe) ++{ ++ s32 ret = _FAIL; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ _rtw_memcpy(pmgntframe->attrib.ra, pwlanhdr->addr1, ETH_ALEN); ++ ++#ifdef CONFIG_IEEE80211W ++ if(padapter->securitypriv.binstallBIPkey == _TRUE) ++ { ++ if(IS_MCAST(pmgntframe->attrib.ra)) ++ { ++ pmgntframe->attrib.encrypt = _BIP_; ++ //pmgntframe->attrib.bswenc = _TRUE; ++ } ++ else ++ { ++ pmgntframe->attrib.encrypt = _AES_; ++ pmgntframe->attrib.bswenc = _TRUE; ++ } ++ rtw_mgmt_xmitframe_coalesce(padapter, pmgntframe->pkt, pmgntframe); ++ } ++#endif //CONFIG_IEEE80211W ++ ++ if(padapter->HalFunc.mgnt_xmit) ++ ret = padapter->HalFunc.mgnt_xmit(padapter, pmgntframe); ++ return ret; ++} ++ ++s32 rtw_hal_init_xmit_priv(_adapter *padapter) ++{ ++ if(padapter->HalFunc.init_xmit_priv != NULL) ++ return padapter->HalFunc.init_xmit_priv(padapter); ++ return _FAIL; ++} ++void rtw_hal_free_xmit_priv(_adapter *padapter) ++{ ++ if(padapter->HalFunc.free_xmit_priv != NULL) ++ padapter->HalFunc.free_xmit_priv(padapter); ++} ++ ++s32 rtw_hal_init_recv_priv(_adapter *padapter) ++{ ++ if(padapter->HalFunc.init_recv_priv) ++ return padapter->HalFunc.init_recv_priv(padapter); ++ ++ return _FAIL; ++} ++void rtw_hal_free_recv_priv(_adapter *padapter) ++{ ++ if(padapter->HalFunc.free_recv_priv) ++ padapter->HalFunc.free_recv_priv(padapter); ++} ++ ++void rtw_hal_update_ra_mask(struct sta_info *psta, u8 rssi_level) ++{ ++ _adapter *padapter; ++ struct mlme_priv *pmlmepriv; ++ ++ if(!psta) ++ return; ++ ++ padapter = psta->padapter; ++ ++ pmlmepriv = &(padapter->mlmepriv); ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ { ++ add_RATid(padapter, psta, rssi_level); ++ } ++ else ++ { ++ if(padapter->HalFunc.UpdateRAMaskHandler) ++ padapter->HalFunc.UpdateRAMaskHandler(padapter, psta->mac_id, rssi_level); ++ } ++} ++ ++void rtw_hal_add_ra_tid(_adapter *padapter, u32 bitmap, u8 arg, u8 rssi_level) ++{ ++ if(padapter->HalFunc.Add_RateATid) ++ padapter->HalFunc.Add_RateATid(padapter, bitmap, arg, rssi_level); ++} ++ ++/* Start specifical interface thread */ ++void rtw_hal_start_thread(_adapter *padapter) ++{ ++ if(padapter->HalFunc.run_thread) ++ padapter->HalFunc.run_thread(padapter); ++} ++/* Start specifical interface thread */ ++void rtw_hal_stop_thread(_adapter *padapter) ++{ ++ if(padapter->HalFunc.cancel_thread) ++ padapter->HalFunc.cancel_thread(padapter); ++} ++ ++u32 rtw_hal_read_bbreg(_adapter *padapter, u32 RegAddr, u32 BitMask) ++{ ++ u32 data = 0; ++ if(padapter->HalFunc.read_bbreg) ++ data = padapter->HalFunc.read_bbreg(padapter, RegAddr, BitMask); ++ return data; ++} ++void rtw_hal_write_bbreg(_adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data) ++{ ++ if(padapter->HalFunc.write_bbreg) ++ padapter->HalFunc.write_bbreg(padapter, RegAddr, BitMask, Data); ++} ++ ++u32 rtw_hal_read_rfreg(_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask) ++{ ++ u32 data = 0; ++ if( padapter->HalFunc.read_rfreg) ++ data = padapter->HalFunc.read_rfreg(padapter, eRFPath, RegAddr, BitMask); ++ return data; ++} ++void rtw_hal_write_rfreg(_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask, u32 Data) ++{ ++ if(padapter->HalFunc.write_rfreg) ++ padapter->HalFunc.write_rfreg(padapter, eRFPath, RegAddr, BitMask, Data); ++} ++ ++s32 rtw_hal_interrupt_handler(_adapter *padapter) ++{ ++ if(padapter->HalFunc.interrupt_handler) ++ return padapter->HalFunc.interrupt_handler(padapter); ++ return _FAIL; ++} ++ ++void rtw_hal_set_bwmode(_adapter *padapter, HT_CHANNEL_WIDTH Bandwidth, u8 Offset) ++{ ++ if(padapter->HalFunc.set_bwmode_handler) ++ padapter->HalFunc.set_bwmode_handler(padapter, Bandwidth, Offset); ++} ++ ++void rtw_hal_set_chan(_adapter *padapter, u8 channel) ++{ ++ if(padapter->HalFunc.set_channel_handler) ++ padapter->HalFunc.set_channel_handler(padapter, channel); ++} ++ ++void rtw_hal_dm_watchdog(_adapter *padapter) ++{ ++#if defined(CONFIG_CONCURRENT_MODE) ++ if (padapter->adapter_type != PRIMARY_ADAPTER) ++ return; ++#endif ++ if(padapter->HalFunc.hal_dm_watchdog) ++ padapter->HalFunc.hal_dm_watchdog(padapter); ++} ++ ++void rtw_hal_bcn_related_reg_setting(_adapter *padapter) ++{ ++ if(padapter->HalFunc.SetBeaconRelatedRegistersHandler) ++ padapter->HalFunc.SetBeaconRelatedRegistersHandler(padapter); ++} ++ ++ ++#ifdef CONFIG_ANTENNA_DIVERSITY ++u8 rtw_hal_antdiv_before_linked(_adapter *padapter) ++{ ++ if(padapter->HalFunc.AntDivBeforeLinkHandler) ++ return padapter->HalFunc.AntDivBeforeLinkHandler(padapter); ++ return _FALSE; ++} ++void rtw_hal_antdiv_rssi_compared(_adapter *padapter, WLAN_BSSID_EX *dst, WLAN_BSSID_EX *src) ++{ ++ if(padapter->HalFunc.AntDivCompareHandler) ++ padapter->HalFunc.AntDivCompareHandler(padapter, dst, src); ++} ++#endif ++ ++#ifdef CONFIG_HOSTAPD_MLME ++s32 rtw_hal_hostap_mgnt_xmit_entry(_adapter *padapter, _pkt *pkt) ++{ ++ if(padapter->HalFunc.hostap_mgnt_xmit_entry) ++ return padapter->HalFunc.hostap_mgnt_xmit_entry(padapter, pkt); ++ return _FAIL; ++} ++#endif //CONFIG_HOSTAPD_MLME ++ ++#ifdef DBG_CONFIG_ERROR_DETECT ++void rtw_hal_sreset_init(_adapter *padapter) ++{ ++ if(padapter->HalFunc.sreset_init_value) ++ padapter->HalFunc.sreset_init_value(padapter); ++} ++void rtw_hal_sreset_reset(_adapter *padapter) ++{ ++ padapter = GET_PRIMARY_ADAPTER(padapter); ++ ++ if(padapter->HalFunc.silentreset) ++ padapter->HalFunc.silentreset(padapter); ++} ++ ++void rtw_hal_sreset_reset_value(_adapter *padapter) ++{ ++ if(padapter->HalFunc.sreset_reset_value) ++ padapter->HalFunc.sreset_reset_value(padapter); ++} ++ ++void rtw_hal_sreset_xmit_status_check(_adapter *padapter) ++{ ++ if (!is_primary_adapter(padapter)) ++ return; ++ ++ if(padapter->HalFunc.sreset_xmit_status_check) ++ padapter->HalFunc.sreset_xmit_status_check(padapter); ++} ++void rtw_hal_sreset_linked_status_check(_adapter *padapter) ++{ ++ if (!is_primary_adapter(padapter)) ++ return; ++ ++ if(padapter->HalFunc.sreset_linked_status_check) ++ padapter->HalFunc.sreset_linked_status_check(padapter); ++} ++u8 rtw_hal_sreset_get_wifi_status(_adapter *padapter) ++{ ++ u8 status = 0; ++ if(padapter->HalFunc.sreset_get_wifi_status) ++ status = padapter->HalFunc.sreset_get_wifi_status(padapter); ++ return status; ++} ++ ++bool rtw_hal_sreset_inprogress(_adapter *padapter) ++{ ++ bool inprogress = _FALSE; ++ ++ padapter = GET_PRIMARY_ADAPTER(padapter); ++ ++ if(padapter->HalFunc.sreset_inprogress) ++ inprogress = padapter->HalFunc.sreset_inprogress(padapter); ++ return inprogress; ++} ++#endif //DBG_CONFIG_ERROR_DETECT ++ ++#ifdef CONFIG_IOL ++int rtw_hal_iol_cmd(ADAPTER *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt) ++{ ++ if(adapter->HalFunc.IOL_exec_cmds_sync) ++ return adapter->HalFunc.IOL_exec_cmds_sync(adapter, xmit_frame, max_wating_ms,bndy_cnt); ++ return _FAIL; ++} ++#endif ++ ++#ifdef CONFIG_XMIT_THREAD_MODE ++s32 rtw_hal_xmit_thread_handler(_adapter *padapter) ++{ ++ if(padapter->HalFunc.xmit_thread_handler) ++ return padapter->HalFunc.xmit_thread_handler(padapter); ++ return _FAIL; ++} ++#endif ++ ++void rtw_hal_notch_filter(_adapter *adapter, bool enable) ++{ ++ if(adapter->HalFunc.hal_notch_filter) ++ adapter->HalFunc.hal_notch_filter(adapter,enable); ++} ++ ++void rtw_hal_reset_security_engine(_adapter * adapter) ++{ ++ if(adapter->HalFunc.hal_reset_security_engine) ++ adapter->HalFunc.hal_reset_security_engine(adapter); ++} ++ ++s32 rtw_hal_c2h_handler(_adapter *adapter, struct c2h_evt_hdr *c2h_evt) ++{ ++ s32 ret = _FAIL; ++ if (adapter->HalFunc.c2h_handler) ++ ret = adapter->HalFunc.c2h_handler(adapter, c2h_evt); ++ return ret; ++} ++ ++c2h_id_filter rtw_hal_c2h_id_filter_ccx(_adapter *adapter) ++{ ++ return adapter->HalFunc.c2h_id_filter_ccx; ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/Hal8188EPwrSeq.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/Hal8188EPwrSeq.c +new file mode 100644 +index 00000000..c38c25a0 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/Hal8188EPwrSeq.c +@@ -0,0 +1,97 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#include "Hal8188EPwrSeq.h" ++#include ++ ++/* ++ drivers should parse below arrays and do the corresponding actions ++*/ ++//3 Power on Array ++WLAN_PWR_CFG rtl8188E_power_on_flow[RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS+RTL8188E_TRANS_END_STEPS]= ++{ ++ RTL8188E_TRANS_CARDEMU_TO_ACT ++ RTL8188E_TRANS_END ++}; ++ ++//3Radio off Array ++WLAN_PWR_CFG rtl8188E_radio_off_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_END_STEPS]= ++{ ++ RTL8188E_TRANS_ACT_TO_CARDEMU ++ RTL8188E_TRANS_END ++}; ++ ++//3Card Disable Array ++WLAN_PWR_CFG rtl8188E_card_disable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS+RTL8188E_TRANS_END_STEPS]= ++{ ++ RTL8188E_TRANS_ACT_TO_CARDEMU ++ RTL8188E_TRANS_CARDEMU_TO_CARDDIS ++ RTL8188E_TRANS_END ++}; ++ ++//3 Card Enable Array ++WLAN_PWR_CFG rtl8188E_card_enable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS+RTL8188E_TRANS_END_STEPS]= ++{ ++ RTL8188E_TRANS_CARDDIS_TO_CARDEMU ++ RTL8188E_TRANS_CARDEMU_TO_ACT ++ RTL8188E_TRANS_END ++}; ++ ++//3Suspend Array ++WLAN_PWR_CFG rtl8188E_suspend_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS+RTL8188E_TRANS_END_STEPS]= ++{ ++ RTL8188E_TRANS_ACT_TO_CARDEMU ++ RTL8188E_TRANS_CARDEMU_TO_SUS ++ RTL8188E_TRANS_END ++}; ++ ++//3 Resume Array ++WLAN_PWR_CFG rtl8188E_resume_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS+RTL8188E_TRANS_END_STEPS]= ++{ ++ RTL8188E_TRANS_SUS_TO_CARDEMU ++ RTL8188E_TRANS_CARDEMU_TO_ACT ++ RTL8188E_TRANS_END ++}; ++ ++ ++//3HWPDN Array ++WLAN_PWR_CFG rtl8188E_hwpdn_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS+RTL8188E_TRANS_END_STEPS]= ++{ ++ RTL8188E_TRANS_ACT_TO_CARDEMU ++ RTL8188E_TRANS_CARDEMU_TO_PDN ++ RTL8188E_TRANS_END ++}; ++ ++//3 Enter LPS ++WLAN_PWR_CFG rtl8188E_enter_lps_flow[RTL8188E_TRANS_ACT_TO_LPS_STEPS+RTL8188E_TRANS_END_STEPS]= ++{ ++ //FW behavior ++ RTL8188E_TRANS_ACT_TO_LPS ++ RTL8188E_TRANS_END ++}; ++ ++//3 Leave LPS ++WLAN_PWR_CFG rtl8188E_leave_lps_flow[RTL8188E_TRANS_LPS_TO_ACT_STEPS+RTL8188E_TRANS_END_STEPS]= ++{ ++ //FW behavior ++ RTL8188E_TRANS_LPS_TO_ACT ++ RTL8188E_TRANS_END ++}; ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_cmd.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_cmd.c +new file mode 100644 +index 00000000..4decacc3 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_cmd.c +@@ -0,0 +1,1493 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTL8188E_CMD_C_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define CONFIG_H2C_EF ++ ++#define RTL88E_MAX_H2C_BOX_NUMS 4 ++#define RTL88E_MAX_CMD_LEN 7 ++#define RTL88E_MESSAGE_BOX_SIZE 4 ++#define RTL88E_EX_MESSAGE_BOX_SIZE 4 ++#define RTL88E_RSVDPAGE_SIZE 1024 ++ ++static u8 _is_fw_read_cmd_down(_adapter* padapter, u8 msgbox_num) ++{ ++ u8 read_down = _FALSE; ++ int retry_cnts = 100; ++ ++ u8 valid; ++ ++ //DBG_8192C(" _is_fw_read_cmd_down ,reg_1cc(%x),msg_box(%d)...\n",rtw_read8(padapter,REG_HMETFR),msgbox_num); ++ ++ do{ ++ valid = rtw_read8(padapter,REG_HMETFR) & BIT(msgbox_num); ++ if(0 == valid ){ ++ read_down = _TRUE; ++ } ++#ifdef CONFIG_WOWLAN ++ rtw_msleep_os(2); ++#endif ++ }while( (!read_down) && (retry_cnts--)); ++ ++ return read_down; ++ ++} ++ ++ ++/***************************************** ++* H2C Msg format : ++* 0x1DF - 0x1D0 ++*| 31 - 8 | 7-5 4 - 0 | ++*| h2c_msg |Class_ID CMD_ID | ++* ++* Extend 0x1FF - 0x1F0 ++*|31 - 0 | ++*|ext_msg| ++******************************************/ ++static s32 FillH2CCmd_88E(PADAPTER padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer) ++{ ++ u8 bcmd_down = _FALSE; ++ s32 retry_cnts = 100; ++ u8 h2c_box_num; ++ u32 msgbox_addr; ++ u32 msgbox_ex_addr; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ u8 cmd_idx,ext_cmd_len; ++ u32 h2c_cmd = 0; ++ u32 h2c_cmd_ex = 0; ++ s32 ret = _FAIL; ++ ++_func_enter_; ++ ++ padapter = GET_PRIMARY_ADAPTER(padapter); ++ pHalData = GET_HAL_DATA(padapter); ++ ++ if(padapter->bFWReady == _FALSE) ++ { ++ DBG_8192C("FillH2CCmd_88E(): return H2C cmd because fw is not ready\n"); ++ return ret; ++ } ++ ++ _enter_critical_mutex(&(adapter_to_dvobj(padapter)->h2c_fwcmd_mutex), NULL); ++ ++ if (!pCmdBuffer) { ++ goto exit; ++ } ++ if (CmdLen > RTL88E_MAX_CMD_LEN) { ++ goto exit; ++ } ++ if (padapter->bSurpriseRemoved == _TRUE) ++ goto exit; ++ ++ //pay attention to if race condition happened in H2C cmd setting. ++ do{ ++ h2c_box_num = pHalData->LastHMEBoxNum; ++ ++ if(!_is_fw_read_cmd_down(padapter, h2c_box_num)){ ++ DBG_8192C(" fw read cmd failed...\n"); ++ goto exit; ++ } ++ ++ *(u8*)(&h2c_cmd) = ElementID; ++ ++ if(CmdLen<=3) ++ { ++ _rtw_memcpy((u8*)(&h2c_cmd)+1, pCmdBuffer, CmdLen ); ++ } ++ else{ ++ _rtw_memcpy((u8*)(&h2c_cmd)+1, pCmdBuffer,3); ++ ext_cmd_len = CmdLen-3; ++ _rtw_memcpy((u8*)(&h2c_cmd_ex), pCmdBuffer+3,ext_cmd_len ); ++ ++ //Write Ext command ++ msgbox_ex_addr = REG_HMEBOX_EXT_0 + (h2c_box_num *RTL88E_EX_MESSAGE_BOX_SIZE); ++ #ifdef CONFIG_H2C_EF ++ for(cmd_idx=0;cmd_idxh2c_cmd:0x%x, reg:0x%x =>h2c_cmd_ex:0x%x ..\n" ++ // ,pHalData->LastHMEBoxNum ,CmdLen,msgbox_addr,h2c_cmd,msgbox_ex_addr,h2c_cmd_ex); ++ ++ pHalData->LastHMEBoxNum = (h2c_box_num+1) % RTL88E_MAX_H2C_BOX_NUMS; ++ ++ }while((!bcmd_down) && (retry_cnts--)); ++ ++ ret = _SUCCESS; ++ ++exit: ++ ++ _exit_critical_mutex(&(adapter_to_dvobj(padapter)->h2c_fwcmd_mutex), NULL); ++ ++_func_exit_; ++ ++ return ret; ++} ++ ++u8 rtl8192c_h2c_msg_hdl(_adapter *padapter, unsigned char *pbuf) ++{ ++ u8 ElementID, CmdLen; ++ u8 *pCmdBuffer; ++ struct cmd_msg_parm *pcmdmsg; ++ ++ if(!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ pcmdmsg = (struct cmd_msg_parm*)pbuf; ++ ElementID = pcmdmsg->eid; ++ CmdLen = pcmdmsg->sz; ++ pCmdBuffer = pcmdmsg->buf; ++ ++ FillH2CCmd_88E(padapter, ElementID, CmdLen, pCmdBuffer); ++ ++ return H2C_SUCCESS; ++} ++/* ++#if defined(CONFIG_AUTOSUSPEND) && defined(SUPPORT_HW_RFOFF_DETECTED) ++u8 rtl8192c_set_FwSelectSuspend_cmd(_adapter *padapter ,u8 bfwpoll, u16 period) ++{ ++ u8 res=_SUCCESS; ++ struct H2C_SS_RFOFF_PARAM param; ++ DBG_8192C("==>%s bfwpoll(%x)\n",__FUNCTION__,bfwpoll); ++ param.gpio_period = period;//Polling GPIO_11 period time ++ param.ROFOn = (_TRUE == bfwpoll)?1:0; ++ FillH2CCmd_88E(padapter, SELECTIVE_SUSPEND_ROF_CMD, sizeof(param), (u8*)(¶m)); ++ return res; ++} ++#endif //CONFIG_AUTOSUSPEND && SUPPORT_HW_RFOFF_DETECTED ++*/ ++u8 rtl8188e_set_rssi_cmd(_adapter*padapter, u8 *param) ++{ ++ u8 res=_SUCCESS; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++_func_enter_; ++ ++ if(pHalData->fw_ractrl == _TRUE){ ++ #if 0 ++ *((u32*) param ) = cpu_to_le32( *((u32*) param ) ); ++ ++ FillH2CCmd_88E(padapter, RSSI_SETTING_EID, 3, param); ++ #endif ++ }else{ ++ DBG_8192C("==>%s fw dont support RA \n",__FUNCTION__); ++ res=_FAIL; ++ } ++ ++_func_exit_; ++ ++ return res; ++} ++ ++u8 rtl8188e_set_raid_cmd(_adapter*padapter, u32 mask) ++{ ++ u8 buf[3]; ++ u8 res=_SUCCESS; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++_func_enter_; ++ if(pHalData->fw_ractrl == _TRUE){ ++ _rtw_memset(buf, 0, 3); ++ mask = cpu_to_le32( mask ); ++ _rtw_memcpy(buf, &mask, 3); ++ ++ FillH2CCmd_88E(padapter, H2C_DM_MACID_CFG, 3, buf); ++ }else{ ++ DBG_8192C("==>%s fw dont support RA \n",__FUNCTION__); ++ res=_FAIL; ++ } ++ ++_func_exit_; ++ ++ return res; ++ ++} ++ ++//bitmap[0:27] = tx_rate_bitmap ++//bitmap[28:31]= Rate Adaptive id ++//arg[0:4] = macid ++//arg[5] = Short GI ++void rtl8188e_Add_RateATid(PADAPTER pAdapter, u32 bitmap, u8 arg, u8 rssi_level) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ //struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ ++ u8 macid, init_rate, raid, shortGIrate=_FALSE; ++ ++ macid = arg&0x1f; ++ ++#ifdef CONFIG_ODM_REFRESH_RAMASK ++ raid = (bitmap>>28) & 0x0f; ++ bitmap &=0x0fffffff; ++ ++ if(rssi_level != DM_RATR_STA_INIT) ++ bitmap = ODM_Get_Rate_Bitmap(&pHalData->odmpriv, macid, bitmap, rssi_level); ++ ++ bitmap |= ((raid<<28)&0xf0000000); ++#endif //CONFIG_ODM_REFRESH_RAMASK ++ ++ ++ init_rate = get_highest_rate_idx(bitmap&0x0fffffff)&0x3f; ++ ++ shortGIrate = (arg&BIT(5)) ? _TRUE:_FALSE; ++ ++ if (shortGIrate==_TRUE) ++ init_rate |= BIT(6); ++ ++ ++ //rtw_write8(pAdapter, (REG_INIDATA_RATE_SEL+macid), (u8)init_rate); ++ ++ raid = (bitmap>>28) & 0x0f; ++ ++ bitmap &= 0x0fffffff; ++ ++ DBG_871X("%s=> mac_id:%d , raid:%d , ra_bitmap=0x%x, shortGIrate=0x%02x\n", ++ __FUNCTION__,macid ,raid ,bitmap, shortGIrate); ++ ++ ++#if(RATE_ADAPTIVE_SUPPORT == 1) ++ ODM_RA_UpdateRateInfo_8188E( ++ &(pHalData->odmpriv), ++ macid, ++ raid, ++ bitmap, ++ shortGIrate ++ ); ++#endif ++ ++} ++ ++void rtl8188e_set_FwPwrMode_cmd(PADAPTER padapter, u8 Mode) ++{ ++ SETPWRMODE_PARM H2CSetPwrMode; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ u8 RLBM = 0; // 0:Min, 1:Max , 2:User define ++_func_enter_; ++ ++ DBG_871X("%s: Mode=%d SmartPS=%d UAPSD=%d\n", __FUNCTION__, ++ Mode, pwrpriv->smart_ps, padapter->registrypriv.uapsd_enable); ++ ++ H2CSetPwrMode.AwakeInterval = 2; //DTIM =1 ++ ++ switch(Mode) ++ { ++ case PS_MODE_ACTIVE: ++ H2CSetPwrMode.Mode = 0; ++ break; ++ case PS_MODE_MIN: ++ H2CSetPwrMode.Mode = 1; ++ break; ++ case PS_MODE_MAX: ++ RLBM = 1; ++ H2CSetPwrMode.Mode = 1; ++ break; ++ case PS_MODE_DTIM: ++ RLBM = 2; ++ H2CSetPwrMode.Mode = 1; ++ break; ++ case PS_MODE_UAPSD_WMM: ++ H2CSetPwrMode.Mode = 2; ++ break; ++ default: ++ H2CSetPwrMode.Mode = 0; ++ break; ++ } ++ ++ //H2CSetPwrMode.Mode = Mode; ++ ++ H2CSetPwrMode.SmartPS_RLBM = (((pwrpriv->smart_ps<<4)&0xf0) | (RLBM & 0x0f)); ++ ++ H2CSetPwrMode.bAllQueueUAPSD = padapter->registrypriv.uapsd_enable; ++ ++ if(Mode > 0) ++ { ++ H2CSetPwrMode.PwrState = 0x00;// AllON(0x0C), RFON(0x04), RFOFF(0x00) ++#ifdef CONFIG_EXT_CLK ++ H2CSetPwrMode.Mode |= BIT(7);//supporting 26M XTAL CLK_Request feature. ++#endif //CONFIG_EXT_CLK ++ } ++ else ++ H2CSetPwrMode.PwrState = 0x0C;// AllON(0x0C), RFON(0x04), RFOFF(0x00) ++ ++ FillH2CCmd_88E(padapter, H2C_PS_PWR_MODE, sizeof(H2CSetPwrMode), (u8 *)&H2CSetPwrMode); ++ ++ ++_func_exit_; ++} ++ ++void rtl8188e_set_FwMediaStatus_cmd(PADAPTER padapter, u16 mstatus_rpt ) ++{ ++ u8 opmode,macid; ++ u16 mst_rpt = cpu_to_le16 (mstatus_rpt); ++ u32 reg_macid_no_link = REG_MACID_NO_LINK_0; ++ opmode = (u8) mst_rpt; ++ macid = (u8)(mst_rpt >> 8) ; ++ DBG_871X("### %s: MStatus=%x MACID=%d \n", __FUNCTION__,opmode,macid); ++ FillH2CCmd_88E(padapter, H2C_COM_MEDIA_STATUS_RPT, sizeof(mst_rpt), (u8 *)&mst_rpt); ++ ++ if(macid > 31){ ++ macid = macid-32; ++ reg_macid_no_link = REG_MACID_NO_LINK_1; ++ } ++ ++ //Delete select macid (MACID 0~63) from queue list. ++ if(opmode == 1)// 1:connect ++ { ++ rtw_write32(padapter,reg_macid_no_link, (rtw_read32(padapter,reg_macid_no_link) & (~BIT(macid)))); ++ } ++ else//0: disconnect ++ { ++ rtw_write32(padapter,reg_macid_no_link, (rtw_read32(padapter,reg_macid_no_link)|BIT(macid))); ++ } ++ ++ ++ ++} ++ ++void ConstructBeacon(_adapter *padapter, u8 *pframe, u32 *pLength) ++{ ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ u16 *fctrl; ++ u32 rate_len, pktlen; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); ++ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ ++ //DBG_871X("%s\n", __FUNCTION__); ++ ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); ++ //pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_BEACON); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pktlen = sizeof (struct rtw_ieee80211_hdr_3addr); ++ ++ //timestamp will be inserted by hardware ++ pframe += 8; ++ pktlen += 8; ++ ++ // beacon interval: 2 bytes ++ _rtw_memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pktlen += 2; ++ ++ // capability info: 2 bytes ++ _rtw_memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pktlen += 2; ++ ++ if( (pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ { ++ //DBG_871X("ie len=%d\n", cur_network->IELength); ++ pktlen += cur_network->IELength - sizeof(NDIS_802_11_FIXED_IEs); ++ _rtw_memcpy(pframe, cur_network->IEs+sizeof(NDIS_802_11_FIXED_IEs), pktlen); ++ ++ goto _ConstructBeacon; ++ } ++ ++ //below for ad-hoc mode ++ ++ // SSID ++ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pktlen); ++ ++ // supported rates... ++ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8)? 8: rate_len), cur_network->SupportedRates, &pktlen); ++ ++ // DS parameter set ++ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pktlen); ++ ++ if( (pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) ++ { ++ u32 ATIMWindow; ++ // IBSS Parameter Set... ++ //ATIMWindow = cur->Configuration.ATIMWindow; ++ ATIMWindow = 0; ++ pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pktlen); ++ } ++ ++ ++ //todo: ERP IE ++ ++ ++ // EXTERNDED SUPPORTED RATE ++ if (rate_len > 8) ++ { ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen); ++ } ++ ++ ++ //todo:HT for adhoc ++ ++_ConstructBeacon: ++ ++ if ((pktlen + TXDESC_SIZE) > 512) ++ { ++ DBG_871X("beacon frame too large\n"); ++ return; ++ } ++ ++ *pLength = pktlen; ++ ++ //DBG_871X("%s bcn_sz=%d\n", __FUNCTION__, pktlen); ++ ++} ++ ++void ConstructPSPoll(_adapter *padapter, u8 *pframe, u32 *pLength) ++{ ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ u16 *fctrl; ++ u32 pktlen; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ //DBG_871X("%s\n", __FUNCTION__); ++ ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ // Frame control. ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ SetPwrMgt(fctrl); ++ SetFrameSubType(pframe, WIFI_PSPOLL); ++ ++ // AID. ++ SetDuration(pframe, (pmlmeinfo->aid | 0xc000)); ++ ++ // BSSID. ++ _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ // TA. ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ *pLength = 16; ++} ++ ++void ConstructNullFunctionData( ++ PADAPTER padapter, ++ u8 *pframe, ++ u32 *pLength, ++ u8 *StaAddr, ++ u8 bQoS, ++ u8 AC, ++ u8 bEosp, ++ u8 bForcePowerSave) ++{ ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ u16 *fctrl; ++ u32 pktlen; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *cur_network = &pmlmepriv->cur_network; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ ++ //DBG_871X("%s:%d\n", __FUNCTION__, bForcePowerSave); ++ ++ pwlanhdr = (struct rtw_ieee80211_hdr*)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ if (bForcePowerSave) ++ { ++ SetPwrMgt(fctrl); ++ } ++ ++ switch(cur_network->network.InfrastructureMode) ++ { ++ case Ndis802_11Infrastructure: ++ SetToDs(fctrl); ++ _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN); ++ break; ++ case Ndis802_11APMode: ++ SetFrDs(fctrl); ++ _rtw_memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ break; ++ case Ndis802_11IBSS: ++ default: ++ _rtw_memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ break; ++ } ++ ++ SetSeqNum(pwlanhdr, 0); ++ ++ if (bQoS == _TRUE) { ++ struct rtw_ieee80211_hdr_3addr_qos *pwlanqoshdr; ++ ++ SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); ++ ++ pwlanqoshdr = (struct rtw_ieee80211_hdr_3addr_qos*)pframe; ++ SetPriority(&pwlanqoshdr->qc, AC); ++ SetEOSP(&pwlanqoshdr->qc, bEosp); ++ ++ pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos); ++ } else { ++ SetFrameSubType(pframe, WIFI_DATA_NULL); ++ ++ pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ } ++ ++ *pLength = pktlen; ++} ++ ++void ConstructProbeRsp(_adapter *padapter, u8 *pframe, u32 *pLength, u8 *StaAddr, BOOLEAN bHideSSID) ++{ ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ u16 *fctrl; ++ u8 *mac, *bssid; ++ u32 pktlen; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); ++ ++ ++ //DBG_871X("%s\n", __FUNCTION__); ++ ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ mac = myid(&(padapter->eeprompriv)); ++ bssid = cur_network->MacAddress; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ _rtw_memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, 0); ++ SetFrameSubType(fctrl, WIFI_PROBERSP); ++ ++ pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ pframe += pktlen; ++ ++ if(cur_network->IELength>MAX_IE_SZ) ++ return; ++ ++ _rtw_memcpy(pframe, cur_network->IEs, cur_network->IELength); ++ pframe += cur_network->IELength; ++ pktlen += cur_network->IELength; ++ ++ *pLength = pktlen; ++} ++ ++#ifdef CONFIG_WOWLAN ++// ++// Description: ++// Construct the ARP response packet to support ARP offload. ++// ++static void ConstructARPResponse( ++ PADAPTER padapter, ++ u8 *pframe, ++ u32 *pLength, ++ u8 *pIPAddress ++ ) ++{ ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *cur_network = &pmlmepriv->cur_network; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ static u8 ARPLLCHeader[8] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x08, 0x06}; ++ ++ u16 *fctrl; ++ u32 pktlen; ++ u8 *pARPRspPkt = pframe; ++ //for TKIP Cal MIC ++ u8 *payload = pframe; ++ u8 EncryptionHeadOverhead = 0; ++ ++ pwlanhdr = (struct rtw_ieee80211_hdr*)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ //------------------------------------------------------------------------- ++ // MAC Header. ++ //------------------------------------------------------------------------- ++ SetFrameType(fctrl, WIFI_DATA); ++ //SetFrameSubType(fctrl, 0); ++ SetToDs(fctrl); ++ _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, 0); ++ SetDuration(pwlanhdr, 0); ++ //SET_80211_HDR_FRAME_CONTROL(pARPRspPkt, 0); ++ //SET_80211_HDR_TYPE_AND_SUBTYPE(pARPRspPkt, Type_Data); ++ //SET_80211_HDR_TO_DS(pARPRspPkt, 1); ++ //SET_80211_HDR_ADDRESS1(pARPRspPkt, pMgntInfo->Bssid); ++ //SET_80211_HDR_ADDRESS2(pARPRspPkt, Adapter->CurrentAddress); ++ //SET_80211_HDR_ADDRESS3(pARPRspPkt, pMgntInfo->Bssid); ++ ++ //SET_80211_HDR_DURATION(pARPRspPkt, 0); ++ //SET_80211_HDR_FRAGMENT_SEQUENCE(pARPRspPkt, 0); ++ *pLength = 24; ++ ++//YJ,del,120503 ++#if 0 ++ //------------------------------------------------------------------------- ++ // Qos Header: leave space for it if necessary. ++ //------------------------------------------------------------------------- ++ if(pStaQos->CurrentQosMode > QOS_DISABLE) ++ { ++ SET_80211_HDR_QOS_EN(pARPRspPkt, 1); ++ PlatformZeroMemory(&(Buffer[*pLength]), sQoSCtlLng); ++ *pLength += sQoSCtlLng; ++ } ++#endif ++ //------------------------------------------------------------------------- ++ // Security Header: leave space for it if necessary. ++ //------------------------------------------------------------------------- ++ ++ switch (psecuritypriv->dot11PrivacyAlgrthm) ++ { ++ case _WEP40_: ++ case _WEP104_: ++ EncryptionHeadOverhead = 4; ++ break; ++ case _TKIP_: ++ EncryptionHeadOverhead = 8; ++ break; ++ case _AES_: ++ EncryptionHeadOverhead = 8; ++ break; ++#ifdef CONFIG_WAPI_SUPPORT ++ case _SMS4_: ++ EncryptionHeadOverhead = 18; ++ break; ++#endif ++ default: ++ EncryptionHeadOverhead = 0; ++ } ++ ++ if(EncryptionHeadOverhead > 0) ++ { ++ _rtw_memset(&(pframe[*pLength]), 0,EncryptionHeadOverhead); ++ *pLength += EncryptionHeadOverhead; ++ //SET_80211_HDR_WEP(pARPRspPkt, 1); //Suggested by CCW. ++ SetPrivacy(fctrl); ++ } ++ ++ //------------------------------------------------------------------------- ++ // Frame Body. ++ //------------------------------------------------------------------------- ++ pARPRspPkt = (u8*)(pframe+ *pLength); ++ // LLC header ++ _rtw_memcpy(pARPRspPkt, ARPLLCHeader, 8); ++ *pLength += 8; ++ ++ // ARP element ++ pARPRspPkt += 8; ++ SET_ARP_PKT_HW(pARPRspPkt, 0x0100); ++ SET_ARP_PKT_PROTOCOL(pARPRspPkt, 0x0008); // IP protocol ++ SET_ARP_PKT_HW_ADDR_LEN(pARPRspPkt, 6); ++ SET_ARP_PKT_PROTOCOL_ADDR_LEN(pARPRspPkt, 4); ++ SET_ARP_PKT_OPERATION(pARPRspPkt, 0x0200); // ARP response ++ SET_ARP_PKT_SENDER_MAC_ADDR(pARPRspPkt, myid(&(padapter->eeprompriv))); ++ SET_ARP_PKT_SENDER_IP_ADDR(pARPRspPkt, pIPAddress); ++#ifdef CONFIG_ARP_KEEP_ALIVE ++ if (rtw_gw_addr_query(padapter)==0) { ++ SET_ARP_PKT_TARGET_MAC_ADDR(pARPRspPkt, pmlmepriv->gw_mac_addr); ++ SET_ARP_PKT_TARGET_IP_ADDR(pARPRspPkt, pmlmepriv->gw_ip); ++ } ++ else ++#endif ++ { ++ SET_ARP_PKT_TARGET_MAC_ADDR(pARPRspPkt, get_my_bssid(&(pmlmeinfo->network))); ++ SET_ARP_PKT_TARGET_IP_ADDR(pARPRspPkt, pIPAddress); ++ DBG_871X("%s Target Mac Addr:" MAC_FMT "\n", __FUNCTION__, MAC_ARG(get_my_bssid(&(pmlmeinfo->network)))); ++ DBG_871X("%s Target IP Addr" IP_FMT "\n", __FUNCTION__, IP_ARG(pIPAddress)); ++ } ++ *pLength += 28; ++ if (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_) ++ { ++ u8 mic[8]; ++ struct mic_data micdata; ++ struct sta_info *psta = NULL; ++ u8 priority[4]={0x0,0x0,0x0,0x0}; ++ u8 null_key[16]={0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}; ++ ++ DBG_871X("%s(): Add MIC\n",__FUNCTION__); ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, get_my_bssid(&(pmlmeinfo->network))); ++ if (psta != NULL) { ++ if(_rtw_memcmp(&psta->dot11tkiptxmickey.skey[0],null_key, 16)==_TRUE){ ++ DBG_871X("%s(): STA dot11tkiptxmickey==0\n",__FUNCTION__); ++ } ++ //start to calculate the mic code ++ rtw_secmicsetkey(&micdata, &psta->dot11tkiptxmickey.skey[0]); ++ } ++ ++ rtw_secmicappend(&micdata, pwlanhdr->addr3, 6); //DA ++ ++ rtw_secmicappend(&micdata, pwlanhdr->addr2, 6); //SA ++ ++ priority[0]=0; ++ rtw_secmicappend(&micdata, &priority[0], 4); ++ ++ rtw_secmicappend(&micdata, payload, 36); //payload length = 8 + 28 ++ ++ rtw_secgetmic(&micdata,&(mic[0])); ++ ++ pARPRspPkt += 28; ++ _rtw_memcpy(pARPRspPkt, &(mic[0]),8); ++ ++ *pLength += 8; ++ } ++} ++#endif ++ ++void rtl8188e_set_FwRsvdPage_cmd(PADAPTER padapter, PRSVDPAGE_LOC rsvdpageloc) ++{ ++ u8 u1H2CRsvdPageParm[H2C_8188E_RSVDPAGE_LOC_LEN]={0}; ++ u8 u1H2CAoacRsvdPageParm[H2C_8188E_AOAC_RSVDPAGE_LOC_LEN]={0}; ++ ++ //DBG_871X("8188RsvdPageLoc: PsPoll=%d Null=%d QoSNull=%d\n", ++ // rsvdpageloc->LocPsPoll, rsvdpageloc->LocNullData, rsvdpageloc->LocQosNull); ++ ++ SET_8188E_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1H2CRsvdPageParm, rsvdpageloc->LocPsPoll); ++ SET_8188E_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocNullData); ++ SET_8188E_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocQosNull); ++ ++ FillH2CCmd_88E(padapter, H2C_COM_RSVD_PAGE, H2C_8188E_RSVDPAGE_LOC_LEN, u1H2CRsvdPageParm); ++ ++#ifdef CONFIG_WOWLAN ++ //DBG_871X("8188E_AOACRsvdPageLoc: RWC=%d ArpRsp=%d\n", rsvdpageloc->LocRemoteCtrlInfo, rsvdpageloc->LocArpRsp); ++ SET_8188E_H2CCMD_AOAC_RSVDPAGE_LOC_REMOTE_WAKE_CTRL_INFO(u1H2CAoacRsvdPageParm, rsvdpageloc->LocRemoteCtrlInfo); ++ SET_8188E_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(u1H2CAoacRsvdPageParm, rsvdpageloc->LocArpRsp); ++ ++ FillH2CCmd_88E(padapter, H2C_COM_AOAC_RSVD_PAGE, H2C_8188E_AOAC_RSVDPAGE_LOC_LEN, u1H2CAoacRsvdPageParm); ++#endif ++} ++ ++// To check if reserved page content is destroyed by beacon beacuse beacon is too large. ++// 2010.06.23. Added by tynli. ++VOID ++CheckFwRsvdPageContent( ++ IN PADAPTER Adapter ++) ++{ ++ HAL_DATA_TYPE* pHalData = GET_HAL_DATA(Adapter); ++ u32 MaxBcnPageNum; ++ ++ if(pHalData->FwRsvdPageStartOffset != 0) ++ { ++ /*MaxBcnPageNum = PageNum_128(pMgntInfo->MaxBeaconSize); ++ RT_ASSERT((MaxBcnPageNum <= pHalData->FwRsvdPageStartOffset), ++ ("CheckFwRsvdPageContent(): The reserved page content has been"\ ++ "destroyed by beacon!!! MaxBcnPageNum(%d) FwRsvdPageStartOffset(%d)\n!", ++ MaxBcnPageNum, pHalData->FwRsvdPageStartOffset));*/ ++ } ++} ++ ++// ++// Description: Fill the reserved packets that FW will use to RSVD page. ++// Now we just send 4 types packet to rsvd page. ++// (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. ++// Input: ++// bDLFinished - FALSE: At the first time we will send all the packets as a large packet to Hw, ++// so we need to set the packet length to total lengh. ++// TRUE: At the second time, we should send the first packet (default:beacon) ++// to Hw again and set the lengh in descriptor to the real beacon lengh. ++// 2009.10.15 by tynli. ++static void SetFwRsvdPagePkt(PADAPTER padapter, BOOLEAN bDLFinished) ++{ ++ PHAL_DATA_TYPE pHalData; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ struct xmit_priv *pxmitpriv; ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ u32 BeaconLength, ProbeRspLength, PSPollLength; ++ u32 NullDataLength, QosNullLength, BTQosNullLength; ++ u8 *ReservedPagePacket; ++ u8 PageNum, PageNeed, TxDescLen; ++ u16 BufIndex; ++ u32 TotalPacketLen; ++ RSVDPAGE_LOC RsvdPageLoc; ++#ifdef CONFIG_WOWLAN ++ u32 ARPLegnth = 0; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ u8 currentip[4]; ++ u8 cur_dot11txpn[8]; ++#endif ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ ReservedPagePacket = (u8*)rtw_zmalloc(RTL88E_RSVDPAGE_SIZE); ++ if (ReservedPagePacket == NULL) { ++ DBG_871X("%s: alloc ReservedPagePacket fail!\n", __FUNCTION__); ++ return; ++ } ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pxmitpriv = &padapter->xmitpriv; ++ pmlmeext = &padapter->mlmeextpriv; ++ pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ TxDescLen = TXDESC_SIZE; ++ PageNum = 0; ++ ++ //3 (1) beacon * 2 pages ++ BufIndex = TXDESC_OFFSET; ++ ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength); ++ ++ // When we count the first page size, we need to reserve description size for the RSVD ++ // packet, it will be filled in front of the packet in TXPKTBUF. ++ PageNeed = (u8)PageNum_128(TxDescLen + BeaconLength); ++ // To reserved 2 pages for beacon buffer. 2010.06.24. ++ if (PageNeed == 1) ++ PageNeed += 1; ++ PageNum += PageNeed; ++ pHalData->FwRsvdPageStartOffset = PageNum; ++ ++ BufIndex += PageNeed*128; ++ ++ //3 (2) ps-poll *1 page ++ RsvdPageLoc.LocPsPoll = PageNum; ++ ConstructPSPoll(padapter, &ReservedPagePacket[BufIndex], &PSPollLength); ++ rtl8188e_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, _TRUE, _FALSE); ++ ++ PageNeed = (u8)PageNum_128(TxDescLen + PSPollLength); ++ PageNum += PageNeed; ++ ++ BufIndex += PageNeed*128; ++ ++ //3 (3) null data * 1 page ++ RsvdPageLoc.LocNullData = PageNum; ++ ConstructNullFunctionData( ++ padapter, ++ &ReservedPagePacket[BufIndex], ++ &NullDataLength, ++ get_my_bssid(&pmlmeinfo->network), ++ _FALSE, 0, 0, _FALSE); ++ rtl8188e_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, _FALSE, _FALSE); ++ ++ PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength); ++ PageNum += PageNeed; ++ ++ BufIndex += PageNeed*128; ++ ++ //3 (5) Qos null data ++ RsvdPageLoc.LocQosNull = PageNum; ++ ConstructNullFunctionData( ++ padapter, ++ &ReservedPagePacket[BufIndex], ++ &QosNullLength, ++ get_my_bssid(&pmlmeinfo->network), ++ _TRUE, 0, 0, _FALSE); ++ rtl8188e_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, _FALSE, _FALSE); ++ ++ PageNeed = (u8)PageNum_128(TxDescLen + QosNullLength); ++ PageNum += PageNeed; ++ ++ BufIndex += PageNeed*128; ++ ++#ifdef CONFIG_WOWLAN ++ //3(7) ARP ++ rtw_get_current_ip_address(padapter, currentip); ++ RsvdPageLoc.LocArpRsp = PageNum; ++ ConstructARPResponse( ++ padapter, ++ &ReservedPagePacket[BufIndex], ++ &ARPLegnth, ++ currentip ++ ); ++ rtl8188e_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], ARPLegnth, _FALSE, _FALSE); ++ ++ switch (psecuritypriv->dot11PrivacyAlgrthm) ++ { ++ case _WEP40_: ++ case _WEP104_: ++ case _TKIP_: ++ ReservedPagePacket[BufIndex-TxDescLen+6] |= BIT(6); ++ break; ++ case _AES_: ++ ReservedPagePacket[BufIndex-TxDescLen+6] |= BIT(6)|BIT(7); ++ break; ++#ifdef CONFIG_WAPI_SUPPORT ++ case _SMS4_: ++ ReservedPagePacket[BufIndex-TxDescLen+6] |= BIT(7); ++ break; ++#endif ++ default: ++ ; ++ } ++ ++ PageNeed = (u8)PageNum_128(TxDescLen + ARPLegnth); ++ PageNum += PageNeed; ++ ++ BufIndex += PageNeed*128; ++ ++ //3(8) sec IV ++ rtw_get_sec_iv(padapter, cur_dot11txpn, get_my_bssid(&pmlmeinfo->network)); ++ RsvdPageLoc.LocRemoteCtrlInfo = PageNum; ++ _rtw_memcpy(ReservedPagePacket+BufIndex-TxDescLen, cur_dot11txpn, 8); ++ ++ TotalPacketLen = BufIndex-TxDescLen + sizeof (union pn48); //IV len ++#else ++ TotalPacketLen = BufIndex + QosNullLength; ++#endif ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (pmgntframe == NULL) ++ goto exit; ++ ++ // update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->qsel = 0x10; ++ pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TXDESC_OFFSET; ++ ++ if (TotalPacketLen < RTL88E_RSVDPAGE_SIZE) ++ _rtw_memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen); ++ else ++ DBG_871X("%s: memory copy fail at Line: %d\n", __FUNCTION__, __LINE__); ++ ++ rtw_hal_mgnt_xmit(padapter, pmgntframe); ++ ++ DBG_871X("%s: Set RSVD page location to Fw\n", __FUNCTION__); ++ rtl8188e_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc); ++ //FillH2CCmd_88E(padapter, H2C_COM_RSVD_PAGE, sizeof(RsvdPageLoc), (u8*)&RsvdPageLoc); ++ ++exit: ++ rtw_mfree(ReservedPagePacket, RTL88E_RSVDPAGE_SIZE); ++} ++ ++void rtl8188e_set_FwJoinBssReport_cmd(PADAPTER padapter, u8 mstatus) ++{ ++ JOINBSSRPT_PARM JoinBssRptParm; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++#ifdef CONFIG_WOWLAN ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct sta_info *psta = NULL; ++#endif ++ BOOLEAN bSendBeacon=_FALSE; ++ BOOLEAN bcn_valid = _FALSE; ++ u8 DLBcnCount=0; ++ u32 poll = 0; ++ ++_func_enter_; ++ ++ DBG_871X("%s mstatus(%x)\n", __FUNCTION__,mstatus); ++ ++ if(mstatus == 1) ++ { ++ // We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. ++ // Suggested by filen. Added by tynli. ++ rtw_write16(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid)); ++ // Do not set TSF again here or vWiFi beacon DMA INT will not work. ++ //correct_TSF(padapter, pmlmeext); ++ // Hw sequende enable by dedault. 2010.06.23. by tynli. ++ //rtw_write16(padapter, REG_NQOS_SEQ, ((pmlmeext->mgnt_seq+100)&0xFFF)); ++ //rtw_write8(padapter, REG_HWSEQ_CTRL, 0xFF); ++ ++ //Set REG_CR bit 8. DMA beacon by SW. ++ pHalData->RegCR_1 |= BIT0; ++ rtw_write8(padapter, REG_CR+1, pHalData->RegCR_1); ++ ++ // Disable Hw protection for a time which revserd for Hw sending beacon. ++ // Fix download reserved page packet fail that access collision with the protection time. ++ // 2010.05.11. Added by tynli. ++ //SetBcnCtrlReg(padapter, 0, BIT3); ++ //SetBcnCtrlReg(padapter, BIT4, 0); ++ rtw_write8(padapter, REG_BCN_CTRL, rtw_read8(padapter, REG_BCN_CTRL)&(~BIT(3))); ++ rtw_write8(padapter, REG_BCN_CTRL, rtw_read8(padapter, REG_BCN_CTRL)|BIT(4)); ++ ++ if(pHalData->RegFwHwTxQCtrl&BIT6) ++ { ++ DBG_871X("HalDownloadRSVDPage(): There is an Adapter is sending beacon.\n"); ++ bSendBeacon = _TRUE; ++ } ++ ++ // Set FWHW_TXQ_CTRL 0x422[6]=0 to tell Hw the packet is not a real beacon frame. ++ rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, (pHalData->RegFwHwTxQCtrl&(~BIT6))); ++ pHalData->RegFwHwTxQCtrl &= (~BIT6); ++ ++ // Clear beacon valid check bit. ++ rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); ++ DLBcnCount = 0; ++ poll = 0; ++ do ++ { ++ // download rsvd page. ++ SetFwRsvdPagePkt(padapter, _FALSE); ++ DLBcnCount++; ++ do ++ { ++ rtw_yield_os(); ++ //rtw_mdelay_os(10); ++ // check rsvd page download OK. ++ rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8*)(&bcn_valid)); ++ poll++; ++ } while(!bcn_valid && (poll%10)!=0 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); ++ ++ }while(!bcn_valid && DLBcnCount<=100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); ++ ++ //RT_ASSERT(bcn_valid, ("HalDownloadRSVDPage88ES(): 1 Download RSVD page failed!\n")); ++ if(padapter->bSurpriseRemoved || padapter->bDriverStopped) ++ { ++ } ++ else if(!bcn_valid) ++ DBG_871X("%s: 1 Download RSVD page failed! DLBcnCount:%u, poll:%u\n", __FUNCTION__ ,DLBcnCount, poll); ++ else ++ DBG_871X("%s: 1 Download RSVD success! DLBcnCount:%u, poll:%u\n", __FUNCTION__, DLBcnCount, poll); ++ // ++ // We just can send the reserved page twice during the time that Tx thread is stopped (e.g. pnpsetpower) ++ // becuase we need to free the Tx BCN Desc which is used by the first reserved page packet. ++ // At run time, we cannot get the Tx Desc until it is released in TxHandleInterrupt() so we will return ++ // the beacon TCB in the following code. 2011.11.23. by tynli. ++ // ++ //if(bcn_valid && padapter->bEnterPnpSleep) ++ if(0) ++ { ++ if(bSendBeacon) ++ { ++ rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); ++ DLBcnCount = 0; ++ poll = 0; ++ do ++ { ++ SetFwRsvdPagePkt(padapter, _TRUE); ++ DLBcnCount++; ++ ++ do ++ { ++ rtw_yield_os(); ++ //rtw_mdelay_os(10); ++ // check rsvd page download OK. ++ rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8*)(&bcn_valid)); ++ poll++; ++ } while(!bcn_valid && (poll%10)!=0 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); ++ }while(!bcn_valid && DLBcnCount<=100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); ++ ++ //RT_ASSERT(bcn_valid, ("HalDownloadRSVDPage(): 2 Download RSVD page failed!\n")); ++ if(padapter->bSurpriseRemoved || padapter->bDriverStopped) ++ { ++ } ++ else if(!bcn_valid) ++ DBG_871X("%s: 2 Download RSVD page failed! DLBcnCount:%u, poll:%u\n", __FUNCTION__ ,DLBcnCount, poll); ++ else ++ DBG_871X("%s: 2 Download RSVD success! DLBcnCount:%u, poll:%u\n", __FUNCTION__, DLBcnCount, poll); ++ } ++ } ++ ++ // Enable Bcn ++ //SetBcnCtrlReg(padapter, BIT3, 0); ++ //SetBcnCtrlReg(padapter, 0, BIT4); ++ rtw_write8(padapter, REG_BCN_CTRL, rtw_read8(padapter, REG_BCN_CTRL)|BIT(3)); ++ rtw_write8(padapter, REG_BCN_CTRL, rtw_read8(padapter, REG_BCN_CTRL)&(~BIT(4))); ++ ++ // To make sure that if there exists an adapter which would like to send beacon. ++ // If exists, the origianl value of 0x422[6] will be 1, we should check this to ++ // prevent from setting 0x422[6] to 0 after download reserved page, or it will cause ++ // the beacon cannot be sent by HW. ++ // 2010.06.23. Added by tynli. ++ if(bSendBeacon) ++ { ++ rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, (pHalData->RegFwHwTxQCtrl|BIT6)); ++ pHalData->RegFwHwTxQCtrl |= BIT6; ++ } ++ ++ // ++ // Update RSVD page location H2C to Fw. ++ // ++ if(bcn_valid) ++ { ++ rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); ++ DBG_871X("Set RSVD page location to Fw.\n"); ++ //FillH2CCmd88E(Adapter, H2C_88E_RSVDPAGE, H2C_RSVDPAGE_LOC_LENGTH, pMgntInfo->u1RsvdPageLoc); ++ } ++ ++ // Do not enable HW DMA BCN or it will cause Pcie interface hang by timing issue. 2011.11.24. by tynli. ++ //if(!padapter->bEnterPnpSleep) ++ { ++ // Clear CR[8] or beacon packet will not be send to TxBuf anymore. ++ pHalData->RegCR_1 &= (~BIT0); ++ rtw_write8(padapter, REG_CR+1, pHalData->RegCR_1); ++ } ++ } ++#ifdef CONFIG_WOWLAN ++ if (adapter_to_pwrctl(padapter)->wowlan_mode){ ++ JoinBssRptParm.OpMode = mstatus; ++ psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(pmlmepriv)); ++ if (psta != NULL) { ++ JoinBssRptParm.MacID = psta->mac_id; ++ } else { ++ JoinBssRptParm.MacID = 0; ++ } ++ FillH2CCmd_88E(padapter, H2C_COM_MEDIA_STATUS_RPT, sizeof(JoinBssRptParm), (u8 *)&JoinBssRptParm); ++ DBG_871X_LEVEL(_drv_info_, "%s opmode:%d MacId:%d\n", __func__, JoinBssRptParm.OpMode, JoinBssRptParm.MacID); ++ } else { ++ DBG_871X_LEVEL(_drv_info_, "%s wowlan_mode is off\n", __func__); ++ } ++#endif //CONFIG_WOWLAN ++_func_exit_; ++} ++ ++#ifdef CONFIG_P2P_PS ++void rtl8188e_set_p2p_ps_offload_cmd(_adapter* padapter, u8 p2p_ps_state) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ struct P2P_PS_Offload_t *p2p_ps_offload = &pHalData->p2p_ps_offload; ++ u8 i; ++ ++_func_enter_; ++ ++#if 1 ++ switch(p2p_ps_state) ++ { ++ case P2P_PS_DISABLE: ++ DBG_8192C("P2P_PS_DISABLE \n"); ++ _rtw_memset(p2p_ps_offload, 0 ,1); ++ break; ++ case P2P_PS_ENABLE: ++ DBG_8192C("P2P_PS_ENABLE \n"); ++ // update CTWindow value. ++ if( pwdinfo->ctwindow > 0 ) ++ { ++ p2p_ps_offload->CTWindow_En = 1; ++ rtw_write8(padapter, REG_P2P_CTWIN, pwdinfo->ctwindow); ++ } ++ ++ // hw only support 2 set of NoA ++ for( i=0 ; inoa_num ; i++) ++ { ++ // To control the register setting for which NOA ++ rtw_write8(padapter, REG_NOA_DESC_SEL, (i << 4)); ++ if(i == 0) ++ p2p_ps_offload->NoA0_En = 1; ++ else ++ p2p_ps_offload->NoA1_En = 1; ++ ++ // config P2P NoA Descriptor Register ++ //DBG_8192C("%s(): noa_duration = %x\n",__FUNCTION__,pwdinfo->noa_duration[i]); ++ rtw_write32(padapter, REG_NOA_DESC_DURATION, pwdinfo->noa_duration[i]); ++ ++ //DBG_8192C("%s(): noa_interval = %x\n",__FUNCTION__,pwdinfo->noa_interval[i]); ++ rtw_write32(padapter, REG_NOA_DESC_INTERVAL, pwdinfo->noa_interval[i]); ++ ++ //DBG_8192C("%s(): start_time = %x\n",__FUNCTION__,pwdinfo->noa_start_time[i]); ++ rtw_write32(padapter, REG_NOA_DESC_START, pwdinfo->noa_start_time[i]); ++ ++ //DBG_8192C("%s(): noa_count = %x\n",__FUNCTION__,pwdinfo->noa_count[i]); ++ rtw_write8(padapter, REG_NOA_DESC_COUNT, pwdinfo->noa_count[i]); ++ } ++ ++ if( (pwdinfo->opp_ps == 1) || (pwdinfo->noa_num > 0) ) ++ { ++ // rst p2p circuit ++ rtw_write8(padapter, REG_DUAL_TSF_RST, BIT(4)); ++ ++ p2p_ps_offload->Offload_En = 1; ++ ++ if(pwdinfo->role == P2P_ROLE_GO) ++ { ++ p2p_ps_offload->role= 1; ++ p2p_ps_offload->AllStaSleep = 0; ++ } ++ else ++ { ++ p2p_ps_offload->role= 0; ++ } ++ ++ p2p_ps_offload->discovery = 0; ++ } ++ break; ++ case P2P_PS_SCAN: ++ DBG_8192C("P2P_PS_SCAN \n"); ++ p2p_ps_offload->discovery = 1; ++ break; ++ case P2P_PS_SCAN_DONE: ++ DBG_8192C("P2P_PS_SCAN_DONE \n"); ++ p2p_ps_offload->discovery = 0; ++ pwdinfo->p2p_ps_state = P2P_PS_ENABLE; ++ break; ++ default: ++ break; ++ } ++ ++ FillH2CCmd_88E(padapter, H2C_PS_P2P_OFFLOAD, 1, (u8 *)p2p_ps_offload); ++#endif ++ ++_func_exit_; ++ ++} ++#endif //CONFIG_P2P_PS ++ ++#ifdef CONFIG_TSF_RESET_OFFLOAD ++/* ++ ask FW to Reset sync register at Beacon early interrupt ++*/ ++u8 rtl8188e_reset_tsf(_adapter *padapter, u8 reset_port ) ++{ ++ u8 buf[2]; ++ u8 res=_SUCCESS; ++ ++ s32 ret; ++_func_enter_; ++ if (IFACE_PORT0==reset_port) { ++ buf[0] = 0x1; buf[1] = 0; ++ } else{ ++ buf[0] = 0x0; buf[1] = 0x1; ++ } ++ ++ ret = FillH2CCmd_88E(padapter, H2C_RESET_TSF, 2, buf); ++ ++_func_exit_; ++ ++ return res; ++} ++ ++int reset_tsf(PADAPTER Adapter, u8 reset_port ) ++{ ++ u8 reset_cnt_before = 0, reset_cnt_after = 0, loop_cnt = 0; ++ u32 reg_reset_tsf_cnt = (IFACE_PORT0==reset_port) ? ++ REG_FW_RESET_TSF_CNT_0:REG_FW_RESET_TSF_CNT_1; ++ u32 reg_bcncrtl = (IFACE_PORT0==reset_port) ? ++ REG_BCN_CTRL_1:REG_BCN_CTRL; ++ ++ rtw_scan_abort(Adapter->pbuddy_adapter); /* site survey will cause reset_tsf fail */ ++ reset_cnt_after = reset_cnt_before = rtw_read8(Adapter,reg_reset_tsf_cnt); ++ rtl8188e_reset_tsf(Adapter, reset_port); ++ ++ while ((reset_cnt_after == reset_cnt_before ) && (loop_cnt < 10)) { ++ rtw_msleep_os(100); ++ loop_cnt++; ++ reset_cnt_after = rtw_read8(Adapter, reg_reset_tsf_cnt); ++ } ++ ++ return(loop_cnt >= 10) ? _FAIL : _TRUE; ++} ++ ++ ++#endif // CONFIG_TSF_RESET_OFFLOAD ++ ++#ifdef CONFIG_WOWLAN ++#ifdef CONFIG_GPIO_WAKEUP ++void rtl8188es_set_output_gpio(_adapter* padapter, u8 index, u8 outputval) ++{ ++ if ( index <= 7 ) { ++ /* config GPIO mode */ ++ rtw_write8(padapter, REG_GPIO_PIN_CTRL + 3, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 3) & ~BIT(index) ); ++ ++ /* config GPIO Sel */ ++ /* 0: input */ ++ /* 1: output */ ++ rtw_write8(padapter, REG_GPIO_PIN_CTRL + 2, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 2) | BIT(index)); ++ ++ /* set output value */ ++ if ( outputval ) { ++ rtw_write8(padapter, REG_GPIO_PIN_CTRL + 1, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 1) | BIT(index)); ++ } else { ++ rtw_write8(padapter, REG_GPIO_PIN_CTRL + 1, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 1) & ~BIT(index)); ++ } ++ } else { ++ /* 88C Series: */ ++ /* index: 11~8 transform to 3~0 */ ++ /* 8723 Series: */ ++ /* index: 12~8 transform to 4~0 */ ++ index -= 8; ++ ++ /* config GPIO mode */ ++ rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 3, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 3) & ~BIT(index) ); ++ ++ /* config GPIO Sel */ ++ /* 0: input */ ++ /* 1: output */ ++ rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 2, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 2) | BIT(index)); ++ ++ /* set output value */ ++ if ( outputval ) { ++ rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 1, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 1) | BIT(index)); ++ } else { ++ rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 1, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 1) & ~BIT(index)); ++ } ++ } ++} ++#endif //CONFIG_GPIO_WAKEUP ++ ++void rtl8188es_set_wowlan_cmd(_adapter* padapter, u8 enable) ++{ ++ u8 res=_SUCCESS; ++ u32 test=0; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ SETWOWLAN_PARM pwowlan_parm; ++ SETAOAC_GLOBAL_INFO paoac_global_info_parm; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct security_priv *psecpriv = &padapter->securitypriv; ++#ifdef CONFIG_GPIO_WAKEUP ++ u8 gpio_wake_pin = 7; ++ u8 gpio_high_active = 0; //default low active ++#endif ++ ++_func_enter_; ++ DBG_871X_LEVEL(_drv_always_, "+%s+\n", __func__); ++ ++ pwowlan_parm.mode =0; ++ pwowlan_parm.gpio_index=0; ++ pwowlan_parm.gpio_duration=0; ++ pwowlan_parm.second_mode =0; ++ pwowlan_parm.reserve=0; ++ ++ if(enable){ ++ ++ pwowlan_parm.mode |=FW_WOWLAN_FUN_EN; ++ pwrpriv->wowlan_magic =_TRUE; ++ if (psecpriv->dot11PrivacyAlgrthm == _WEP40_ || psecpriv->dot11PrivacyAlgrthm == _WEP104_) ++ pwrpriv->wowlan_unicast =_TRUE; ++ ++ if(pwrpriv->wowlan_pattern ==_TRUE){ ++ pwowlan_parm.mode |= FW_WOWLAN_PATTERN_MATCH; ++ DBG_871X_LEVEL(_drv_info_, "%s 2.pwowlan_parm.mode=0x%x \n",__FUNCTION__,pwowlan_parm.mode ); ++ } ++ if(pwrpriv->wowlan_magic ==_TRUE){ ++ pwowlan_parm.mode |=FW_WOWLAN_MAGIC_PKT; ++ DBG_871X_LEVEL(_drv_info_, "%s 3.pwowlan_parm.mode=0x%x \n",__FUNCTION__,pwowlan_parm.mode ); ++ } ++ if(pwrpriv->wowlan_unicast ==_TRUE){ ++ pwowlan_parm.mode |=FW_WOWLAN_UNICAST; ++ DBG_871X_LEVEL(_drv_info_, "%s 4.pwowlan_parm.mode=0x%x \n",__FUNCTION__,pwowlan_parm.mode ); ++ } ++ ++ pwowlan_parm.mode |=FW_WOWLAN_REKEY_WAKEUP; ++ pwowlan_parm.mode |=FW_WOWLAN_DEAUTH_WAKEUP; ++ ++ //DataPinWakeUp ++#ifdef CONFIG_USB_HCI ++ pwowlan_parm.gpio_index=0x0; ++#endif //CONFIG_USB_HCI ++ ++#ifdef CONFIG_SDIO_HCI ++ pwowlan_parm.gpio_index = 0x80; ++#endif //CONFIG_SDIO_HCI ++ ++#ifdef CONFIG_GPIO_WAKEUP ++ pwowlan_parm.gpio_index = gpio_wake_pin; ++ ++ //WOWLAN_GPIO_ACTIVE means GPIO high active ++ //pwowlan_parm.mode |=FW_WOWLAN_GPIO_ACTIVE; ++ if (gpio_high_active) ++ pwowlan_parm.mode |=FW_WOWLAN_GPIO_ACTIVE; ++#endif //CONFIG_GPIO_WAKEUP ++ ++ DBG_871X_LEVEL(_drv_info_, "%s 5.pwowlan_parm.mode=0x%x \n",__FUNCTION__,pwowlan_parm.mode); ++ DBG_871X_LEVEL(_drv_info_, "%s 6.pwowlan_parm.index=0x%x \n",__FUNCTION__,pwowlan_parm.gpio_index); ++ res = FillH2CCmd_88E(padapter, H2C_COM_WWLAN, 2, (u8 *)&pwowlan_parm); ++ ++ rtw_msleep_os(2); ++ ++ //disconnect decision ++ pwowlan_parm.mode =1; ++ pwowlan_parm.gpio_index=0; ++ pwowlan_parm.gpio_duration=0; ++ FillH2CCmd_88E(padapter, H2C_COM_DISCNT_DECISION, 3, (u8 *)&pwowlan_parm); ++ ++ //keep alive period = 10 * 10 BCN interval ++ pwowlan_parm.mode = FW_WOWLAN_KEEP_ALIVE_EN | FW_ADOPT_USER | FW_WOWLAN_KEEP_ALIVE_PKT_TYPE; ++ pwowlan_parm.gpio_index=10; ++ res = FillH2CCmd_88E(padapter, H2C_COM_KEEP_ALIVE, 2, (u8 *)&pwowlan_parm); ++ ++ rtw_msleep_os(2); ++ //Configure STA security information for GTK rekey wakeup event. ++ paoac_global_info_parm.pairwiseEncAlg= ++ padapter->securitypriv.dot11PrivacyAlgrthm; ++ paoac_global_info_parm.groupEncAlg= ++ padapter->securitypriv.dot118021XGrpPrivacy; ++ res = FillH2CCmd_88E(padapter, H2C_COM_AOAC_GLOBAL_INFO, 2, (u8 *)&paoac_global_info_parm); ++ ++ rtw_msleep_os(2); ++ //enable Remote wake ctrl ++ pwowlan_parm.mode = FW_REMOTE_WAKE_CTRL_EN | FW_WOW_FW_UNICAST_EN | FW_ARP_EN; ++ if (psecpriv->dot11PrivacyAlgrthm == _AES_ || psecpriv->dot11PrivacyAlgrthm == _NO_PRIVACY_) ++ { ++ pwowlan_parm.gpio_index=0; ++ } else { ++ pwowlan_parm.gpio_index=1; ++ } ++ pwowlan_parm.gpio_duration=0; ++ ++ res = FillH2CCmd_88E(padapter, H2C_COM_REMOTE_WAKE_CTRL, 3, (u8 *)&pwowlan_parm); ++ } else { ++ pwrpriv->wowlan_magic =_FALSE; ++#ifdef CONFIG_GPIO_WAKEUP ++ rtl8188es_set_output_gpio(padapter, gpio_wake_pin, !gpio_high_active); ++#endif //CONFIG_GPIO_WAKEUP ++ res = FillH2CCmd_88E(padapter, H2C_COM_WWLAN, 2, (u8 *)&pwowlan_parm); ++ rtw_msleep_os(2); ++ res = FillH2CCmd_88E(padapter, H2C_COM_REMOTE_WAKE_CTRL, 3, (u8 *)&pwowlan_parm); ++ } ++_func_exit_; ++ DBG_871X_LEVEL(_drv_always_, "-%s res:%d-\n", __func__, res); ++ return ; ++} ++#endif //CONFIG_WOWLAN +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_dm.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_dm.c +new file mode 100644 +index 00000000..55cfff96 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_dm.c +@@ -0,0 +1,650 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++//============================================================ ++// Description: ++// ++// This file is for 92CE/92CU dynamic mechanism only ++// ++// ++//============================================================ ++#define _RTL8188E_DM_C_ ++ ++//============================================================ ++// include files ++//============================================================ ++#include ++#include ++#include ++#include ++ ++#include ++ ++//============================================================ ++// Global var ++//============================================================ ++ ++ ++static VOID ++dm_CheckProtection( ++ IN PADAPTER Adapter ++ ) ++{ ++#if 0 ++ PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ u1Byte CurRate, RateThreshold; ++ ++ if(pMgntInfo->pHTInfo->bCurBW40MHz) ++ RateThreshold = MGN_MCS1; ++ else ++ RateThreshold = MGN_MCS3; ++ ++ if(Adapter->TxStats.CurrentInitTxRate <= RateThreshold) ++ { ++ pMgntInfo->bDmDisableProtect = TRUE; ++ DbgPrint("Forced disable protect: %x\n", Adapter->TxStats.CurrentInitTxRate); ++ } ++ else ++ { ++ pMgntInfo->bDmDisableProtect = FALSE; ++ DbgPrint("Enable protect: %x\n", Adapter->TxStats.CurrentInitTxRate); ++ } ++#endif ++} ++ ++static VOID ++dm_CheckStatistics( ++ IN PADAPTER Adapter ++ ) ++{ ++#if 0 ++ if(!Adapter->MgntInfo.bMediaConnect) ++ return; ++ ++ //2008.12.10 tynli Add for getting Current_Tx_Rate_Reg flexibly. ++ rtw_hal_get_hwreg( Adapter, HW_VAR_INIT_TX_RATE, (pu1Byte)(&Adapter->TxStats.CurrentInitTxRate) ); ++ ++ // Calculate current Tx Rate(Successful transmited!!) ++ ++ // Calculate current Rx Rate(Successful received!!) ++ ++ //for tx tx retry count ++ rtw_hal_get_hwreg( Adapter, HW_VAR_RETRY_COUNT, (pu1Byte)(&Adapter->TxStats.NumTxRetryCount) ); ++#endif ++} ++ ++static void dm_CheckPbcGPIO(_adapter *padapter) ++{ ++ u8 tmp1byte; ++ u8 bPbcPressed = _FALSE; ++ ++ if(!padapter->registrypriv.hw_wps_pbc) ++ return; ++ ++#ifdef CONFIG_USB_HCI ++ tmp1byte = rtw_read8(padapter, GPIO_IO_SEL); ++ tmp1byte |= (HAL_8188E_HW_GPIO_WPS_BIT); ++ rtw_write8(padapter, GPIO_IO_SEL, tmp1byte); //enable GPIO[2] as output mode ++ ++ tmp1byte &= ~(HAL_8188E_HW_GPIO_WPS_BIT); ++ rtw_write8(padapter, GPIO_IN, tmp1byte); //reset the floating voltage level ++ ++ tmp1byte = rtw_read8(padapter, GPIO_IO_SEL); ++ tmp1byte &= ~(HAL_8188E_HW_GPIO_WPS_BIT); ++ rtw_write8(padapter, GPIO_IO_SEL, tmp1byte); //enable GPIO[2] as input mode ++ ++ tmp1byte =rtw_read8(padapter, GPIO_IN); ++ ++ if (tmp1byte == 0xff) ++ return ; ++ ++ if (tmp1byte&HAL_8188E_HW_GPIO_WPS_BIT) ++ { ++ bPbcPressed = _TRUE; ++ } ++#else ++ tmp1byte = rtw_read8(padapter, GPIO_IN); ++ //RT_TRACE(COMP_IO, DBG_TRACE, ("dm_CheckPbcGPIO - %x\n", tmp1byte)); ++ ++ if (tmp1byte == 0xff || padapter->init_adpt_in_progress) ++ return ; ++ ++ if((tmp1byte&HAL_8188E_HW_GPIO_WPS_BIT)==0) ++ { ++ bPbcPressed = _TRUE; ++ } ++#endif ++ ++ if( _TRUE == bPbcPressed) ++ { ++ // Here we only set bPbcPressed to true ++ // After trigger PBC, the variable will be set to false ++ DBG_8192C("CheckPbcGPIO - PBC is pressed\n"); ++ ++#ifdef RTK_DMP_PLATFORM ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12)) ++ kobject_uevent(&padapter->pnetdev->dev.kobj, KOBJ_NET_PBC); ++#else ++ kobject_hotplug(&padapter->pnetdev->class_dev.kobj, KOBJ_NET_PBC); ++#endif ++#else ++ ++ if ( padapter->pid[0] == 0 ) ++ { // 0 is the default value and it means the application monitors the HW PBC doesn't privde its pid to driver. ++ return; ++ } ++ ++#ifdef PLATFORM_LINUX ++ rtw_signal_process(padapter->pid[0], SIGUSR1); ++#endif ++#endif ++ } ++} ++ ++#ifdef CONFIG_PCI_HCI ++// ++// Description: ++// Perform interrupt migration dynamically to reduce CPU utilization. ++// ++// Assumption: ++// 1. Do not enable migration under WIFI test. ++// ++// Created by Roger, 2010.03.05. ++// ++VOID ++dm_InterruptMigration( ++ IN PADAPTER Adapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); ++ BOOLEAN bCurrentIntMt, bCurrentACIntDisable; ++ BOOLEAN IntMtToSet = _FALSE; ++ BOOLEAN ACIntToSet = _FALSE; ++ ++ ++ // Retrieve current interrupt migration and Tx four ACs IMR settings first. ++ bCurrentIntMt = pHalData->bInterruptMigration; ++ bCurrentACIntDisable = pHalData->bDisableTxInt; ++ ++ // ++ // Currently we use busy traffic for reference instead of RxIntOK counts to prevent non-linear Rx statistics ++ // when interrupt migration is set before. 2010.03.05. ++ // ++ if(!Adapter->registrypriv.wifi_spec && ++ (check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE) && ++ pmlmepriv->LinkDetectInfo.bHigherBusyTraffic) ++ { ++ IntMtToSet = _TRUE; ++ ++ // To check whether we should disable Tx interrupt or not. ++ if(pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic ) ++ ACIntToSet = _TRUE; ++ } ++ ++ //Update current settings. ++ if( bCurrentIntMt != IntMtToSet ){ ++ DBG_8192C("%s(): Update interrrupt migration(%d)\n",__FUNCTION__,IntMtToSet); ++ if(IntMtToSet) ++ { ++ // ++ // Set interrrupt migration timer and corresponging Tx/Rx counter. ++ // timer 25ns*0xfa0=100us for 0xf packets. ++ // 2010.03.05. ++ // ++ rtw_write32(Adapter, REG_INT_MIG, 0xff000fa0);// 0x306:Rx, 0x307:Tx ++ pHalData->bInterruptMigration = IntMtToSet; ++ } ++ else ++ { ++ // Reset all interrupt migration settings. ++ rtw_write32(Adapter, REG_INT_MIG, 0); ++ pHalData->bInterruptMigration = IntMtToSet; ++ } ++ } ++ ++ /*if( bCurrentACIntDisable != ACIntToSet ){ ++ DBG_8192C("%s(): Update AC interrrupt(%d)\n",__FUNCTION__,ACIntToSet); ++ if(ACIntToSet) // Disable four ACs interrupts. ++ { ++ // ++ // Disable VO, VI, BE and BK four AC interrupts to gain more efficient CPU utilization. ++ // When extremely highly Rx OK occurs, we will disable Tx interrupts. ++ // 2010.03.05. ++ // ++ UpdateInterruptMask8192CE( Adapter, 0, RT_AC_INT_MASKS ); ++ pHalData->bDisableTxInt = ACIntToSet; ++ } ++ else// Enable four ACs interrupts. ++ { ++ UpdateInterruptMask8192CE( Adapter, RT_AC_INT_MASKS, 0 ); ++ pHalData->bDisableTxInt = ACIntToSet; ++ } ++ }*/ ++ ++} ++ ++#endif ++ ++// ++// Initialize GPIO setting registers ++// ++static void ++dm_InitGPIOSetting( ++ IN PADAPTER Adapter ++ ) ++{ ++ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); ++ ++ u8 tmp1byte; ++ ++ tmp1byte = rtw_read8(Adapter, REG_GPIO_MUXCFG); ++ tmp1byte &= (GPIOSEL_GPIO | ~GPIOSEL_ENBT); ++ ++#ifdef CONFIG_BT_COEXIST ++ // UMB-B cut bug. We need to support the modification. ++ if (IS_81xxC_VENDOR_UMC_B_CUT(pHalData->VersionID) && ++ pHalData->bt_coexist.BT_Coexist) ++ { ++ tmp1byte |= (BIT5); ++ } ++#endif ++ rtw_write8(Adapter, REG_GPIO_MUXCFG, tmp1byte); ++ ++} ++ ++//============================================================ ++// functions ++//============================================================ ++static void Init_ODM_ComInfo_88E(PADAPTER Adapter) ++{ ++ ++ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ u8 cut_ver,fab_ver; ++ ++ // ++ // Init Value ++ // ++ _rtw_memset(pDM_Odm,0,sizeof(pDM_Odm)); ++ ++ pDM_Odm->Adapter = Adapter; ++ ++ ODM_CmnInfoInit(pDM_Odm,ODM_CMNINFO_PLATFORM,ODM_CE); ++ ++ if(Adapter->interface_type == RTW_GSPI ) ++ ODM_CmnInfoInit(pDM_Odm,ODM_CMNINFO_INTERFACE,ODM_ITRF_SDIO); ++ else ++ ODM_CmnInfoInit(pDM_Odm,ODM_CMNINFO_INTERFACE,Adapter->interface_type);//RTL871X_HCI_TYPE ++ ++ ODM_CmnInfoInit(pDM_Odm,ODM_CMNINFO_IC_TYPE,ODM_RTL8188E); ++ ++ fab_ver = ODM_TSMC; ++ cut_ver = ODM_CUT_A; ++ ++ ODM_CmnInfoInit(pDM_Odm,ODM_CMNINFO_FAB_VER,fab_ver); ++ ODM_CmnInfoInit(pDM_Odm,ODM_CMNINFO_CUT_VER,cut_ver); ++ ++ ODM_CmnInfoInit(pDM_Odm, ODM_CMNINFO_MP_TEST_CHIP,IS_NORMAL_CHIP(pHalData->VersionID)); ++ ++#if 0 ++//#ifdef CONFIG_USB_HCI ++ ODM_CmnInfoInit(pDM_Odm,ODM_CMNINFO_BOARD_TYPE,pHalData->BoardType); ++ ++ if(pHalData->BoardType == BOARD_USB_High_PA){ ++ ODM_CmnInfoInit(pDM_Odm,ODM_CMNINFO_EXT_LNA,_TRUE); ++ ODM_CmnInfoInit(pDM_Odm,ODM_CMNINFO_EXT_PA,_TRUE); ++ } ++#endif ++ ODM_CmnInfoInit(pDM_Odm,ODM_CMNINFO_PATCH_ID,pHalData->CustomerID); ++ // ODM_CMNINFO_BINHCT_TEST only for MP Team ++ ODM_CmnInfoInit(pDM_Odm,ODM_CMNINFO_BWIFI_TEST,Adapter->registrypriv.wifi_spec); ++ ++ ++ if(pHalData->rf_type == RF_1T1R){ ++ ODM_CmnInfoUpdate(pDM_Odm,ODM_CMNINFO_RF_TYPE,ODM_1T1R); ++ } ++ else if(pHalData->rf_type == RF_2T2R){ ++ ODM_CmnInfoUpdate(pDM_Odm,ODM_CMNINFO_RF_TYPE,ODM_2T2R); ++ } ++ else if(pHalData->rf_type == RF_1T2R){ ++ ODM_CmnInfoUpdate(pDM_Odm,ODM_CMNINFO_RF_TYPE,ODM_1T2R); ++ } ++ ++ ODM_CmnInfoInit(pDM_Odm, ODM_CMNINFO_RF_ANTENNA_TYPE, pHalData->TRxAntDivType); ++ ++ #ifdef CONFIG_DISABLE_ODM ++ pdmpriv->InitODMFlag = 0; ++ #else ++ pdmpriv->InitODMFlag = ODM_RF_CALIBRATION | ++ ODM_RF_TX_PWR_TRACK //| ++ ; ++ //if(pHalData->AntDivCfg) ++ // pdmpriv->InitODMFlag |= ODM_BB_ANT_DIV; ++ #endif ++ ++ ODM_CmnInfoUpdate(pDM_Odm,ODM_CMNINFO_ABILITY,pdmpriv->InitODMFlag); ++ ++} ++static void Update_ODM_ComInfo_88E(PADAPTER Adapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(Adapter); ++ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ int i; ++ ++ pdmpriv->InitODMFlag = 0 ++ | ODM_BB_DIG ++#ifdef CONFIG_ODM_REFRESH_RAMASK ++ | ODM_BB_RA_MASK ++#endif ++ | ODM_BB_DYNAMIC_TXPWR ++ | ODM_BB_FA_CNT ++ | ODM_BB_RSSI_MONITOR ++ | ODM_BB_CCK_PD ++ | ODM_BB_PWR_SAVE ++ | ODM_RF_CALIBRATION ++ | ODM_RF_TX_PWR_TRACK ++#ifdef CONFIG_ODM_ADAPTIVITY ++ | ODM_BB_ADAPTIVITY ++#endif ++ ; ++ ++ if (!Adapter->registrypriv.qos_opt_enable) { ++ pdmpriv->InitODMFlag |= ODM_MAC_EDCA_TURBO; ++ } ++ ++ if(pHalData->AntDivCfg) ++ pdmpriv->InitODMFlag |= ODM_BB_ANT_DIV; ++ ++#if (MP_DRIVER==1) ++ if (Adapter->registrypriv.mp_mode == 1) { ++ pdmpriv->InitODMFlag = 0 ++ | ODM_RF_CALIBRATION ++ | ODM_RF_TX_PWR_TRACK ++ ; ++ } ++#endif//(MP_DRIVER==1) ++ ++#ifdef CONFIG_DISABLE_ODM ++ pdmpriv->InitODMFlag = 0; ++#endif//CONFIG_DISABLE_ODM ++ ++ ODM_CmnInfoUpdate(pDM_Odm,ODM_CMNINFO_ABILITY,pdmpriv->InitODMFlag); ++ ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_TX_UNI,&(Adapter->xmitpriv.tx_bytes)); ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_RX_UNI,&(Adapter->recvpriv.rx_bytes)); ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_WM_MODE,&(pmlmeext->cur_wireless_mode)); ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_SEC_CHNL_OFFSET,&(pHalData->nCur40MhzPrimeSC)); ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_SEC_MODE,&(Adapter->securitypriv.dot11PrivacyAlgrthm)); ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_BW,&(pHalData->CurrentChannelBW )); ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_CHNL,&( pHalData->CurrentChannel)); ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_NET_CLOSED,&( Adapter->net_closed)); ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_MP_MODE,&(Adapter->registrypriv.mp_mode)); ++ ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_BAND,&(pDM_Odm->u1Byte_temp)); ++ //================= only for 8192D ================= ++ /* ++ //pHalData->CurrentBandType92D ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_BAND,&(pDM_Odm->u1Byte_temp)); ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_DMSP_GET_VALUE,&(pDM_Odm->u1Byte_temp)); ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_BUDDY_ADAPTOR,&(pDM_Odm->PADAPTER_temp)); ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_DMSP_IS_MASTER,&(pDM_Odm->u1Byte_temp)); ++ //================= only for 8192D ================= ++ // driver havn't those variable now ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_BT_OPERATION,&(pDM_Odm->u1Byte_temp)); ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_BT_DISABLE_EDCA,&(pDM_Odm->u1Byte_temp)); ++ */ ++ ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_SCAN,&(pmlmepriv->bScanInProcess)); ++ ODM_CmnInfoHook(pDM_Odm,ODM_CMNINFO_POWER_SAVING,&(pwrctrlpriv->bpower_saving)); ++ ODM_CmnInfoInit(pDM_Odm, ODM_CMNINFO_RF_ANTENNA_TYPE, pHalData->TRxAntDivType); ++ ++ for(i=0; i< NUM_STA; i++) ++ { ++ //pDM_Odm->pODM_StaInfo[i] = NULL; ++ ODM_CmnInfoPtrArrayHook(pDM_Odm, ODM_CMNINFO_STA_STATUS,i,NULL); ++ } ++} ++ ++void ++rtl8188e_InitHalDm( ++ IN PADAPTER Adapter ++ ) ++{ ++ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ u8 i; ++ ++#ifdef CONFIG_USB_HCI ++ dm_InitGPIOSetting(Adapter); ++#endif ++ ++ pdmpriv->DM_Type = DM_Type_ByDriver; ++ pdmpriv->DMFlag = DYNAMIC_FUNC_DISABLE; ++ ++ Update_ODM_ComInfo_88E(Adapter); ++ ODM_DMInit(pDM_Odm); ++ ++ Adapter->fix_rate = 0xFF; ++ ++} ++ ++ ++VOID ++rtl8188e_HalDmWatchDog( ++ IN PADAPTER Adapter ++ ) ++{ ++ BOOLEAN bFwCurrentInPSMode = _FALSE; ++ BOOLEAN bFwPSAwake = _TRUE; ++ u8 hw_init_completed = _FALSE; ++ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++#ifdef CONFIG_CONCURRENT_MODE ++ PADAPTER pbuddy_adapter = Adapter->pbuddy_adapter; ++#endif //CONFIG_CONCURRENT_MODE ++ ++ _func_enter_; ++ ++ hw_init_completed = Adapter->hw_init_completed; ++ ++ if (hw_init_completed == _FALSE) ++ goto skip_dm; ++ ++#ifdef CONFIG_LPS ++ bFwCurrentInPSMode = adapter_to_pwrctl(Adapter)->bFwCurrentInPSMode; ++ rtw_hal_get_hwreg(Adapter, HW_VAR_FWLPS_RF_ON, (u8 *)(&bFwPSAwake)); ++#endif ++ ++#ifdef CONFIG_P2P_PS ++ // Fw is under p2p powersaving mode, driver should stop dynamic mechanism. ++ // modifed by thomas. 2011.06.11. ++ if(Adapter->wdinfo.p2p_ps_mode) ++ bFwPSAwake = _FALSE; ++#endif //CONFIG_P2P_PS ++ ++ if( (hw_init_completed == _TRUE) ++ && ((!bFwCurrentInPSMode) && bFwPSAwake)) ++ { ++ // ++ // Calculate Tx/Rx statistics. ++ // ++ dm_CheckStatistics(Adapter); ++ ++ // ++ // Dynamically switch RTS/CTS protection. ++ // ++ //dm_CheckProtection(Adapter); ++ ++#ifdef CONFIG_PCI_HCI ++ // 20100630 Joseph: Disable Interrupt Migration mechanism temporarily because it degrades Rx throughput. ++ // Tx Migration settings. ++ //dm_InterruptMigration(Adapter); ++ ++ //if(Adapter->HalFunc.TxCheckStuckHandler(Adapter)) ++ // PlatformScheduleWorkItem(&(GET_HAL_DATA(Adapter)->HalResetWorkItem)); ++#endif ++ ++ } ++ ++ ++ //ODM ++ if (hw_init_completed == _TRUE) ++ { ++ u8 bLinked=_FALSE; ++ u8 bsta_state = _FALSE; ++ ++ #ifdef CONFIG_DISABLE_ODM ++ pHalData->odmpriv.SupportAbility = 0; ++ #endif ++ ++ if(rtw_linked_check(Adapter)) ++ bLinked = _TRUE; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(pbuddy_adapter && rtw_linked_check(pbuddy_adapter)) ++ bLinked = _TRUE; ++#endif //CONFIG_CONCURRENT_MODE ++ ODM_CmnInfoUpdate(&pHalData->odmpriv ,ODM_CMNINFO_LINK, bLinked); ++ ++ ++ if (check_fwstate(&Adapter->mlmepriv, WIFI_STATION_STATE)) ++ bsta_state = _TRUE; ++#ifdef CONFIG_CONCURRENT_MODE ++ if(pbuddy_adapter && check_fwstate(&pbuddy_adapter->mlmepriv, WIFI_STATION_STATE)) ++ bsta_state = _TRUE; ++#endif //CONFIG_CONCURRENT_MODE ++ ODM_CmnInfoUpdate(&pHalData->odmpriv ,ODM_CMNINFO_STATION_STATE, bsta_state); ++ ++ ODM_DMWatchdog(&pHalData->odmpriv); ++ ++ } ++ ++skip_dm: ++ ++ // Check GPIO to determine current RF on/off and Pbc status. ++ // Check Hardware Radio ON/OFF or not ++#ifdef CONFIG_PCI_HCI ++ if(pHalData->bGpioHwWpsPbc) ++#endif ++ { ++ //temp removed ++ //dm_CheckPbcGPIO(Adapter); ++ } ++ return; ++} ++ ++void rtl8188e_init_dm_priv(IN PADAPTER Adapter) ++{ ++ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ PDM_ODM_T podmpriv = &pHalData->odmpriv; ++ _rtw_memset(pdmpriv, 0, sizeof(struct dm_priv)); ++ //_rtw_spinlock_init(&(pHalData->odm_stainfo_lock)); ++ Init_ODM_ComInfo_88E(Adapter); ++#ifdef CONFIG_SW_ANTENNA_DIVERSITY ++ //_init_timer(&(pdmpriv->SwAntennaSwitchTimer), Adapter->pnetdev , odm_SW_AntennaSwitchCallback, Adapter); ++ ODM_InitAllTimers(podmpriv ); ++#endif ++ ODM_InitDebugSetting(podmpriv); ++} ++ ++void rtl8188e_deinit_dm_priv(IN PADAPTER Adapter) ++{ ++ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ PDM_ODM_T podmpriv = &pHalData->odmpriv; ++ //_rtw_spinlock_free(&pHalData->odm_stainfo_lock); ++#ifdef CONFIG_SW_ANTENNA_DIVERSITY ++ //_cancel_timer_ex(&pdmpriv->SwAntennaSwitchTimer); ++ ODM_CancelAllTimers(podmpriv); ++#endif ++} ++ ++ ++#ifdef CONFIG_ANTENNA_DIVERSITY ++// Add new function to reset the state of antenna diversity before link. ++// ++// Compare RSSI for deciding antenna ++void AntDivCompare8188E(PADAPTER Adapter, WLAN_BSSID_EX *dst, WLAN_BSSID_EX *src) ++{ ++ //PADAPTER Adapter = pDM_Odm->Adapter ; ++ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ if(0 != pHalData->AntDivCfg ) ++ { ++ //DBG_8192C("update_network=> orgRSSI(%d)(%d),newRSSI(%d)(%d)\n",dst->Rssi,query_rx_pwr_percentage(dst->Rssi), ++ // src->Rssi,query_rx_pwr_percentage(src->Rssi)); ++ //select optimum_antenna for before linked =>For antenna diversity ++ if(dst->Rssi >= src->Rssi )//keep org parameter ++ { ++ src->Rssi = dst->Rssi; ++ src->PhyInfo.Optimum_antenna = dst->PhyInfo.Optimum_antenna; ++ } ++ } ++} ++ ++// Add new function to reset the state of antenna diversity before link. ++u8 AntDivBeforeLink8188E(PADAPTER Adapter ) ++{ ++ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm =&pHalData->odmpriv; ++ SWAT_T *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); ++ ++ // Condition that does not need to use antenna diversity. ++ if(pHalData->AntDivCfg==0) ++ { ++ //DBG_8192C("odm_AntDivBeforeLink8192C(): No AntDiv Mechanism.\n"); ++ return _FALSE; ++ } ++ ++ if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ++ { ++ return _FALSE; ++ } ++ ++ ++ if(pDM_SWAT_Table->SWAS_NoLink_State == 0){ ++ //switch channel ++ pDM_SWAT_Table->SWAS_NoLink_State = 1; ++ pDM_SWAT_Table->CurAntenna = (pDM_SWAT_Table->CurAntenna==Antenna_A)?Antenna_B:Antenna_A; ++ ++ //PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300, pDM_SWAT_Table->CurAntenna); ++ rtw_antenna_select_cmd(Adapter, pDM_SWAT_Table->CurAntenna, _FALSE); ++ //DBG_8192C("%s change antenna to ANT_( %s ).....\n",__FUNCTION__, (pDM_SWAT_Table->CurAntenna==Antenna_A)?"A":"B"); ++ return _TRUE; ++ } ++ else ++ { ++ pDM_SWAT_Table->SWAS_NoLink_State = 0; ++ return _FALSE; ++ } ++ ++} ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_hal_init.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_hal_init.c +new file mode 100644 +index 00000000..1e38e220 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_hal_init.c +@@ -0,0 +1,3800 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _HAL_INIT_C_ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#if defined(CONFIG_IOL) ++#ifdef CONFIG_USB_HCI ++#include ++#endif ++static void iol_mode_enable(PADAPTER padapter, u8 enable) ++{ ++ u8 reg_0xf0 = 0; ++ ++ if(enable) ++ { ++ //Enable initial offload ++ reg_0xf0 = rtw_read8(padapter, REG_SYS_CFG); ++ //DBG_871X("%s reg_0xf0:0x%02x, write 0x%02x\n", __FUNCTION__, reg_0xf0, reg_0xf0|SW_OFFLOAD_EN); ++ rtw_write8(padapter, REG_SYS_CFG, reg_0xf0|SW_OFFLOAD_EN); ++ ++ if(padapter->bFWReady == _FALSE) ++ { ++ printk("bFWReady == _FALSE call reset 8051...\n"); ++ _8051Reset88E(padapter); ++ } ++ ++ } ++ else ++ { ++ //disable initial offload ++ reg_0xf0 = rtw_read8(padapter, REG_SYS_CFG); ++ //DBG_871X("%s reg_0xf0:0x%02x, write 0x%02x\n", __FUNCTION__, reg_0xf0, reg_0xf0& ~SW_OFFLOAD_EN); ++ rtw_write8(padapter, REG_SYS_CFG, reg_0xf0 & ~SW_OFFLOAD_EN); ++ } ++} ++ ++static s32 iol_execute(PADAPTER padapter, u8 control) ++{ ++ s32 status = _FAIL; ++ u8 reg_0x88 = 0,reg_1c7=0; ++ u32 start = 0, passing_time = 0; ++ ++ u32 t1,t2; ++ control = control&0x0f; ++ reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0); ++ //DBG_871X("%s reg_0x88:0x%02x, write 0x%02x\n", __FUNCTION__, reg_0x88, reg_0x88|control); ++ rtw_write8(padapter, REG_HMEBOX_E0, reg_0x88|control); ++ ++ t1 = start = rtw_get_current_time(); ++ while( ++ //(reg_1c7 = rtw_read8(padapter, 0x1c7) >1) && ++ (reg_0x88=rtw_read8(padapter, REG_HMEBOX_E0)) & control ++ && (passing_time=rtw_get_passing_time_ms(start))<1000 ++ ) { ++ //DBG_871X("%s polling reg_0x88:0x%02x,reg_0x1c7:0x%02x\n", __FUNCTION__, reg_0x88,rtw_read8(padapter, 0x1c7) ); ++ //rtw_udelay_os(100); ++ } ++ ++ reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0); ++ status = (reg_0x88 & control)?_FAIL:_SUCCESS; ++ if(reg_0x88 & control<<4) ++ status = _FAIL; ++ t2= rtw_get_current_time(); ++ //printk("==> step iol_execute : %5u reg-0x1c0= 0x%02x\n",rtw_get_time_interval_ms(t1,t2),rtw_read8(padapter, 0x1c0)); ++ //DBG_871X("%s in %u ms, reg_0x88:0x%02x\n", __FUNCTION__, passing_time, reg_0x88); ++ ++ return status; ++} ++ ++static s32 iol_InitLLTTable( ++ PADAPTER padapter, ++ u8 txpktbuf_bndy ++ ) ++{ ++ s32 rst = _SUCCESS; ++ iol_mode_enable(padapter, 1); ++ //DBG_871X("%s txpktbuf_bndy:%u\n", __FUNCTION__, txpktbuf_bndy); ++ rtw_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy); ++ rst = iol_execute(padapter, CMD_INIT_LLT); ++ iol_mode_enable(padapter, 0); ++ return rst; ++} ++ ++static VOID ++efuse_phymap_to_logical(u8 * phymap, u16 _offset, u16 _size_byte, u8 *pbuf) ++{ ++ u8 *efuseTbl = NULL; ++ u8 rtemp8; ++ u16 eFuse_Addr = 0; ++ u8 offset, wren; ++ u16 i, j; ++ u16 **eFuseWord = NULL; ++ u16 efuse_utilized = 0; ++ u8 efuse_usage = 0; ++ u8 u1temp = 0; ++ ++ ++ efuseTbl = (u8*)rtw_zmalloc(EFUSE_MAP_LEN_88E); ++ if(efuseTbl == NULL) ++ { ++ DBG_871X("%s: alloc efuseTbl fail!\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ eFuseWord= (u16 **)rtw_malloc2d(EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16)); ++ if(eFuseWord == NULL) ++ { ++ DBG_871X("%s: alloc eFuseWord fail!\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ // 0. Refresh efuse init map as all oxFF. ++ for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) ++ for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) ++ eFuseWord[i][j] = 0xFFFF; ++ ++ // ++ // 1. Read the first byte to check if efuse is empty!!! ++ // ++ // ++ rtemp8 = *(phymap+eFuse_Addr); ++ if(rtemp8 != 0xFF) ++ { ++ efuse_utilized++; ++ //printk("efuse_Addr-%d efuse_data=%x\n", eFuse_Addr, *rtemp8); ++ eFuse_Addr++; ++ } ++ else ++ { ++ DBG_871X("EFUSE is empty efuse_Addr-%d efuse_data=%x\n", eFuse_Addr, rtemp8); ++ goto exit; ++ } ++ ++ ++ // ++ // 2. Read real efuse content. Filter PG header and every section data. ++ // ++ while((rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) ++ { ++ //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("efuse_Addr-%d efuse_data=%x\n", eFuse_Addr-1, *rtemp8)); ++ ++ // Check PG header for section num. ++ if((rtemp8 & 0x1F ) == 0x0F) //extended header ++ { ++ u1temp =( (rtemp8 & 0xE0) >> 5); ++ //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("extended header u1temp=%x *rtemp&0xE0 0x%x\n", u1temp, *rtemp8 & 0xE0)); ++ ++ //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("extended header u1temp=%x \n", u1temp)); ++ ++ rtemp8 = *(phymap+eFuse_Addr); ++ ++ //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("extended header efuse_Addr-%d efuse_data=%x\n", eFuse_Addr, *rtemp8)); ++ ++ if((rtemp8 & 0x0F) == 0x0F) ++ { ++ eFuse_Addr++; ++ rtemp8 = *(phymap+eFuse_Addr); ++ ++ if(rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) ++ { ++ eFuse_Addr++; ++ } ++ continue; ++ } ++ else ++ { ++ offset = ((rtemp8 & 0xF0) >> 1) | u1temp; ++ wren = (rtemp8 & 0x0F); ++ eFuse_Addr++; ++ } ++ } ++ else ++ { ++ offset = ((rtemp8 >> 4) & 0x0f); ++ wren = (rtemp8 & 0x0f); ++ } ++ ++ if(offset < EFUSE_MAX_SECTION_88E) ++ { ++ // Get word enable value from PG header ++ //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("Offset-%d Worden=%x\n", offset, wren)); ++ ++ for(i=0; i= EFUSE_REAL_CONTENT_LEN_88E) ++ break; ++ ++ //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("Addr=%d", eFuse_Addr)); ++ rtemp8 = *(phymap+eFuse_Addr); ++ eFuse_Addr++; ++ //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("Data=0x%x\n", *rtemp8)); ++ ++ efuse_utilized++; ++ eFuseWord[offset][i] |= (((u2Byte)rtemp8 << 8) & 0xff00); ++ ++ if(eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E) ++ break; ++ } ++ ++ wren >>= 1; ++ ++ } ++ } ++ ++ // Read next PG header ++ rtemp8 = *(phymap+eFuse_Addr); ++ //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("Addr=%d rtemp 0x%x\n", eFuse_Addr, *rtemp8)); ++ ++ if(rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) ++ { ++ efuse_utilized++; ++ eFuse_Addr++; ++ } ++ } ++ ++ // ++ // 3. Collect 16 sections and 4 word unit into Efuse map. ++ // ++ for(i=0; i> 8) & 0xff); ++ } ++ } ++ ++ ++ // ++ // 4. Copy from Efuse map to output pointer memory!!! ++ // ++ for(i=0; i<_size_byte; i++) ++ { ++ pbuf[i] = efuseTbl[_offset+i]; ++ } ++ ++ // ++ // 5. Calculate Efuse utilization. ++ // ++ efuse_usage = (u1Byte)((efuse_utilized*100)/EFUSE_REAL_CONTENT_LEN_88E); ++ //Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_utilized); ++ ++exit: ++ if(efuseTbl) ++ rtw_mfree(efuseTbl, EFUSE_MAP_LEN_88E); ++ ++ if(eFuseWord) ++ rtw_mfree2d((void *)eFuseWord, EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16)); ++} ++ ++void efuse_read_phymap_from_txpktbuf( ++ ADAPTER *adapter, ++ int bcnhead, //beacon head, where FW store len(2-byte) and efuse physical map. ++ u8 *content, //buffer to store efuse physical map ++ u16 *size //for efuse content: the max byte to read. will update to byte read ++ ) ++{ ++ u16 dbg_addr = 0; ++ u32 start = 0, passing_time = 0; ++ u8 reg_0x143 = 0; ++ u8 reg_0x106 = 0; ++ u32 lo32 = 0, hi32 = 0; ++ u16 len = 0, count = 0; ++ int i = 0; ++ u16 limit = *size; ++ ++ u8 *pos = content; ++ ++ if(bcnhead<0) //if not valid ++ bcnhead = rtw_read8(adapter, REG_TDECTRL+1); ++ ++ DBG_871X("%s bcnhead:%d\n", __FUNCTION__, bcnhead); ++ ++ //reg_0x106 = rtw_read8(adapter, REG_PKT_BUFF_ACCESS_CTRL); ++ //DBG_871X("%s reg_0x106:0x%02x, write 0x%02x\n", __FUNCTION__, reg_0x106, 0x69); ++ rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); ++ //DBG_871X("%s reg_0x106:0x%02x\n", __FUNCTION__, rtw_read8(adapter, 0x106)); ++ ++ dbg_addr = bcnhead*128/8; //8-bytes addressing ++ ++ while(1) ++ { ++ //DBG_871X("%s dbg_addr:0x%x\n", __FUNCTION__, dbg_addr+i); ++ rtw_write16(adapter, REG_PKTBUF_DBG_ADDR, dbg_addr+i); ++ ++ //DBG_871X("%s write reg_0x143:0x00\n", __FUNCTION__); ++ rtw_write8(adapter, REG_TXPKTBUF_DBG, 0); ++ start = rtw_get_current_time(); ++ while(!(reg_0x143=rtw_read8(adapter, REG_TXPKTBUF_DBG))//dbg ++ //while(rtw_read8(adapter, REG_TXPKTBUF_DBG) & BIT0 ++ && (passing_time=rtw_get_passing_time_ms(start))<1000 ++ ) { ++ DBG_871X("%s polling reg_0x143:0x%02x, reg_0x106:0x%02x\n", __FUNCTION__, reg_0x143, rtw_read8(adapter, 0x106)); ++ rtw_usleep_os(100); ++ } ++ ++ ++ lo32 = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_L); ++ hi32 = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_H); ++ ++ #if 0 ++ DBG_871X("%s lo32:0x%08x, %02x %02x %02x %02x\n", __FUNCTION__, lo32 ++ , rtw_read8(adapter, REG_PKTBUF_DBG_DATA_L) ++ , rtw_read8(adapter, REG_PKTBUF_DBG_DATA_L+1) ++ , rtw_read8(adapter, REG_PKTBUF_DBG_DATA_L+2) ++ , rtw_read8(adapter, REG_PKTBUF_DBG_DATA_L+3) ++ ); ++ DBG_871X("%s hi32:0x%08x, %02x %02x %02x %02x\n", __FUNCTION__, hi32 ++ , rtw_read8(adapter, REG_PKTBUF_DBG_DATA_H) ++ , rtw_read8(adapter, REG_PKTBUF_DBG_DATA_H+1) ++ , rtw_read8(adapter, REG_PKTBUF_DBG_DATA_H+2) ++ , rtw_read8(adapter, REG_PKTBUF_DBG_DATA_H+3) ++ ); ++ #endif ++ ++ if(i==0) ++ { ++ #if 1 //for debug ++ u8 lenc[2]; ++ u16 lenbak, aaabak; ++ u16 aaa; ++ lenc[0] = rtw_read8(adapter, REG_PKTBUF_DBG_DATA_L); ++ lenc[1] = rtw_read8(adapter, REG_PKTBUF_DBG_DATA_L+1); ++ ++ aaabak = le16_to_cpup((u16*)lenc); ++ lenbak = le16_to_cpu(*((u16*)lenc)); ++ aaa = le16_to_cpup((u16*)&lo32); ++ #endif ++ len = le16_to_cpu(*((u16*)&lo32)); ++ ++ limit = (len-2=count+2)?2:limit-count); ++ count+= (limit>=count+2)?2:limit-count; ++ pos=content+count; ++ ++ } ++ else ++ { ++ _rtw_memcpy(pos, ((u8*)&lo32), (limit>=count+4)?4:limit-count); ++ count+=(limit>=count+4)?4:limit-count; ++ pos=content+count; ++ ++ ++ } ++ ++ if(limit>count && len-2>count) { ++ _rtw_memcpy(pos, (u8*)&hi32, (limit>=count+4)?4:limit-count); ++ count+=(limit>=count+4)?4:limit-count; ++ pos=content+count; ++ } ++ ++ if(limit<=count || len-2<=count) ++ break; ++ ++ i++; ++ } ++ ++ rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, DISABLE_TRXPKT_BUF_ACCESS); ++ ++ DBG_871X("%s read count:%u\n", __FUNCTION__, count); ++ *size = count; ++ ++} ++ ++ ++static s32 iol_read_efuse( ++ PADAPTER padapter, ++ u8 txpktbuf_bndy, ++ u16 offset, ++ u16 size_byte, ++ u8 *logical_map ++ ) ++{ ++ s32 status = _FAIL; ++ u8 reg_0x106 = 0; ++ u8 physical_map[512]; ++ u16 size = 512; ++ int i; ++ ++ ++ rtw_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy); ++ _rtw_memset(physical_map, 0xFF, 512); ++ ++ ///reg_0x106 = rtw_read8(padapter, REG_PKT_BUFF_ACCESS_CTRL); ++ //DBG_871X("%s reg_0x106:0x%02x, write 0x%02x\n", __FUNCTION__, reg_0x106, 0x69); ++ rtw_write8(padapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); ++ //DBG_871X("%s reg_0x106:0x%02x\n", __FUNCTION__, rtw_read8(padapter, 0x106)); ++ ++ status = iol_execute(padapter, CMD_READ_EFUSE_MAP); ++ ++ if(status == _SUCCESS) ++ efuse_read_phymap_from_txpktbuf(padapter, txpktbuf_bndy, physical_map, &size); ++ ++ #if 0 ++ DBG_871X("%s physical map\n", __FUNCTION__); ++ for(i=0;i %s \n",__FUNCTION__); ++ ++ if(rtw_IOL_applied(padapter)){ ++ iol_mode_enable(padapter, 1); ++ result = iol_execute(padapter, CMD_READ_EFUSE_MAP); ++ if(result == _SUCCESS) ++ result = iol_execute(padapter, CMD_EFUSE_PATCH); ++ ++ iol_mode_enable(padapter, 0); ++ } ++ return result; ++} ++ ++static s32 iol_ioconfig( ++ PADAPTER padapter, ++ u8 iocfg_bndy ++ ) ++{ ++ s32 rst = _SUCCESS; ++ ++ //DBG_871X("%s iocfg_bndy:%u\n", __FUNCTION__, iocfg_bndy); ++ rtw_write8(padapter, REG_TDECTRL+1, iocfg_bndy); ++ rst = iol_execute(padapter, CMD_IOCONFIG); ++ ++ return rst; ++} ++ ++int rtl8188e_IOL_exec_cmds_sync(ADAPTER *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms,u32 bndy_cnt) ++{ ++ ++ u32 start_time = rtw_get_current_time(); ++ u32 passing_time_ms; ++ u8 polling_ret,i; ++ int ret = _FAIL; ++ u32 t1,t2; ++ ++ //printk("===> %s ,bndy_cnt = %d \n",__FUNCTION__,bndy_cnt); ++ if (rtw_IOL_append_END_cmd(xmit_frame) != _SUCCESS) ++ goto exit; ++#ifdef CONFIG_USB_HCI ++ { ++ struct pkt_attrib *pattrib = &xmit_frame->attrib; ++ if(rtw_usb_bulk_size_boundary(adapter,TXDESC_SIZE+pattrib->last_txcmdsz)) ++ { ++ if (rtw_IOL_append_END_cmd(xmit_frame) != _SUCCESS) ++ goto exit; ++ } ++ } ++#endif //CONFIG_USB_HCI ++ ++ //rtw_IOL_cmd_buf_dump(adapter,xmit_frame->attrib.pktlen+TXDESC_OFFSET,xmit_frame->buf_addr); ++ //rtw_hal_mgnt_xmit(adapter, xmit_frame); ++ //rtw_dump_xframe_sync(adapter, xmit_frame); ++ ++ dump_mgntframe_and_wait(adapter, xmit_frame, max_wating_ms); ++ ++ t1= rtw_get_current_time(); ++ iol_mode_enable(adapter, 1); ++ for(i=0;i %s : %5u\n",__FUNCTION__,rtw_get_time_interval_ms(t1,t2)); ++exit: ++ //restore BCN_HEAD ++ rtw_write8(adapter, REG_TDECTRL+1, 0); ++ return ret; ++} ++ ++void rtw_IOL_cmd_tx_pkt_buf_dump(ADAPTER *Adapter,int data_len) ++{ ++ u32 fifo_data,reg_140; ++ u32 addr,rstatus,loop=0; ++ ++ u16 data_cnts = (data_len/8)+1; ++ u8 *pbuf =rtw_zvmalloc(data_len+10); ++ printk("###### %s ######\n",__FUNCTION__); ++ ++ rtw_write8(Adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); ++ if(pbuf){ ++ for(addr=0;addr< data_cnts;addr++){ ++ //printk("==> addr:0x%02x\n",addr); ++ rtw_write32(Adapter,0x140,addr); ++ rtw_usleep_os(2); ++ loop=0; ++ do{ ++ rstatus=(reg_140=rtw_read32(Adapter,REG_PKTBUF_DBG_CTRL)&BIT24); ++ //printk("rstatus = %02x, reg_140:0x%08x\n",rstatus,reg_140); ++ if(rstatus){ ++ fifo_data = rtw_read32(Adapter,REG_PKTBUF_DBG_DATA_L); ++ //printk("fifo_data_144:0x%08x\n",fifo_data); ++ _rtw_memcpy(pbuf+(addr*8),&fifo_data , 4); ++ ++ fifo_data = rtw_read32(Adapter,REG_PKTBUF_DBG_DATA_H); ++ //printk("fifo_data_148:0x%08x\n",fifo_data); ++ _rtw_memcpy(pbuf+(addr*8+4), &fifo_data, 4); ++ ++ } ++ rtw_usleep_os(2); ++ }while( !rstatus && (loop++ <10)); ++ } ++ rtw_IOL_cmd_buf_dump(Adapter,data_len,pbuf); ++ rtw_vmfree(pbuf, data_len+10); ++ ++ } ++ printk("###### %s ######\n",__FUNCTION__); ++} ++ ++#endif /* defined(CONFIG_IOL) */ ++ ++ ++static VOID ++_FWDownloadEnable( ++ IN PADAPTER padapter, ++ IN BOOLEAN enable ++ ) ++{ ++ u8 tmp; ++ ++ if(enable) ++ { ++ // MCU firmware download enable. ++ tmp = rtw_read8(padapter, REG_MCUFWDL); ++ rtw_write8(padapter, REG_MCUFWDL, tmp|0x01); ++ ++ // 8051 reset ++ tmp = rtw_read8(padapter, REG_MCUFWDL+2); ++ rtw_write8(padapter, REG_MCUFWDL+2, tmp&0xf7); ++ } ++ else ++ { ++ ++ // MCU firmware download disable. ++ tmp = rtw_read8(padapter, REG_MCUFWDL); ++ rtw_write8(padapter, REG_MCUFWDL, tmp&0xfe); ++ ++ // Reserved for fw extension. ++ rtw_write8(padapter, REG_MCUFWDL+1, 0x00); ++ } ++} ++#define MAX_REG_BOLCK_SIZE 196 ++static int ++_BlockWrite( ++ IN PADAPTER padapter, ++ IN PVOID buffer, ++ IN u32 buffSize ++ ) ++{ ++ int ret = _SUCCESS; ++ ++ u32 blockSize_p1 = 4; // (Default) Phase #1 : PCI muse use 4-byte write to download FW ++ u32 blockSize_p2 = 8; // Phase #2 : Use 8-byte, if Phase#1 use big size to write FW. ++ u32 blockSize_p3 = 1; // Phase #3 : Use 1-byte, the remnant of FW image. ++ u32 blockCount_p1 = 0, blockCount_p2 = 0, blockCount_p3 = 0; ++ u32 remainSize_p1 = 0, remainSize_p2 = 0; ++ u8 *bufferPtr = (u8*)buffer; ++ u32 i=0, offset=0; ++#ifdef CONFIG_PCI_HCI ++ u8 remainFW[4] = {0, 0, 0, 0}; ++ u8 *p = NULL; ++#endif ++ ++#ifdef CONFIG_USB_HCI ++ blockSize_p1 = MAX_REG_BOLCK_SIZE; ++#endif ++ ++ //3 Phase #1 ++ blockCount_p1 = buffSize / blockSize_p1; ++ remainSize_p1 = buffSize % blockSize_p1; ++ ++ if (blockCount_p1) { ++ RT_TRACE(_module_hal_init_c_, _drv_notice_, ++ ("_BlockWrite: [P1] buffSize(%d) blockSize_p1(%d) blockCount_p1(%d) remainSize_p1(%d)\n", ++ buffSize, blockSize_p1, blockCount_p1, remainSize_p1)); ++ } ++ ++ for (i = 0; i < blockCount_p1; i++) ++ { ++#ifdef CONFIG_USB_HCI ++ ret = rtw_writeN(padapter, (FW_8188E_START_ADDRESS + i * blockSize_p1), blockSize_p1, (bufferPtr + i * blockSize_p1)); ++#else ++ ret = rtw_write32(padapter, (FW_8188E_START_ADDRESS + i * blockSize_p1), le32_to_cpu(*((u32*)(bufferPtr + i * blockSize_p1)))); ++#endif ++ ++ if(ret == _FAIL) ++ goto exit; ++ } ++ ++#ifdef CONFIG_PCI_HCI ++ p = (u8*)((u32*)(bufferPtr + blockCount_p1 * blockSize_p1)); ++ if (remainSize_p1) { ++ switch (remainSize_p1) { ++ case 0: ++ break; ++ case 3: ++ remainFW[2]=*(p+2); ++ case 2: ++ remainFW[1]=*(p+1); ++ case 1: ++ remainFW[0]=*(p); ++ ret = rtw_write32(padapter, (FW_8188E_START_ADDRESS + blockCount_p1 * blockSize_p1), ++ le32_to_cpu(*(u32*)remainFW)); ++ } ++ return ret; ++ } ++#endif ++ ++ //3 Phase #2 ++ if (remainSize_p1) ++ { ++ offset = blockCount_p1 * blockSize_p1; ++ ++ blockCount_p2 = remainSize_p1/blockSize_p2; ++ remainSize_p2 = remainSize_p1%blockSize_p2; ++ ++ if (blockCount_p2) { ++ RT_TRACE(_module_hal_init_c_, _drv_notice_, ++ ("_BlockWrite: [P2] buffSize_p2(%d) blockSize_p2(%d) blockCount_p2(%d) remainSize_p2(%d)\n", ++ (buffSize-offset), blockSize_p2 ,blockCount_p2, remainSize_p2)); ++ } ++ ++#ifdef CONFIG_USB_HCI ++ for (i = 0; i < blockCount_p2; i++) { ++ ret = rtw_writeN(padapter, (FW_8188E_START_ADDRESS + offset + i*blockSize_p2), blockSize_p2, (bufferPtr + offset + i*blockSize_p2)); ++ ++ if(ret == _FAIL) ++ goto exit; ++ } ++#endif ++ } ++ ++ //3 Phase #3 ++ if (remainSize_p2) ++ { ++ offset = (blockCount_p1 * blockSize_p1) + (blockCount_p2 * blockSize_p2); ++ ++ blockCount_p3 = remainSize_p2 / blockSize_p3; ++ ++ RT_TRACE(_module_hal_init_c_, _drv_notice_, ++ ("_BlockWrite: [P3] buffSize_p3(%d) blockSize_p3(%d) blockCount_p3(%d)\n", ++ (buffSize-offset), blockSize_p3, blockCount_p3)); ++ ++ for(i = 0 ; i < blockCount_p3 ; i++){ ++ ret =rtw_write8(padapter, (FW_8188E_START_ADDRESS + offset + i), *(bufferPtr + offset + i)); ++ ++ if(ret == _FAIL) ++ goto exit; ++ } ++ } ++ ++exit: ++ return ret; ++} ++ ++static int ++_PageWrite( ++ IN PADAPTER padapter, ++ IN u32 page, ++ IN PVOID buffer, ++ IN u32 size ++ ) ++{ ++ u8 value8; ++ u8 u8Page = (u8) (page & 0x07) ; ++ ++ value8 = (rtw_read8(padapter, REG_MCUFWDL+2) & 0xF8) | u8Page ; ++ rtw_write8(padapter, REG_MCUFWDL+2,value8); ++ ++ return _BlockWrite(padapter,buffer,size); ++} ++ ++static VOID ++_FillDummy( ++ u8* pFwBuf, ++ u32* pFwLen ++ ) ++{ ++ u32 FwLen = *pFwLen; ++ u8 remain = (u8)(FwLen%4); ++ remain = (remain==0)?0:(4-remain); ++ ++ while(remain>0) ++ { ++ pFwBuf[FwLen] = 0; ++ FwLen++; ++ remain--; ++ } ++ ++ *pFwLen = FwLen; ++} ++ ++static int ++_WriteFW( ++ IN PADAPTER padapter, ++ IN PVOID buffer, ++ IN u32 size ++ ) ++{ ++ // Since we need dynamic decide method of dwonload fw, so we call this function to get chip version. ++ // We can remove _ReadChipVersion from ReadpadapterInfo8192C later. ++ int ret = _SUCCESS; ++ u32 pageNums,remainSize ; ++ u32 page, offset; ++ u8 *bufferPtr = (u8*)buffer; ++ ++#ifdef CONFIG_PCI_HCI ++ // 20100120 Joseph: Add for 88CE normal chip. ++ // Fill in zero to make firmware image to dword alignment. ++// _FillDummy(bufferPtr, &size); ++#endif ++ ++ pageNums = size / MAX_PAGE_SIZE ; ++ //RT_ASSERT((pageNums <= 4), ("Page numbers should not greater then 4 \n")); ++ remainSize = size % MAX_PAGE_SIZE; ++ ++ for (page = 0; page < pageNums; page++) { ++ offset = page * MAX_PAGE_SIZE; ++ ret = _PageWrite(padapter, page, bufferPtr+offset, MAX_PAGE_SIZE); ++ ++ if(ret == _FAIL) ++ goto exit; ++ } ++ if (remainSize) { ++ offset = pageNums * MAX_PAGE_SIZE; ++ page = pageNums; ++ ret = _PageWrite(padapter, page, bufferPtr+offset, remainSize); ++ ++ if(ret == _FAIL) ++ goto exit; ++ ++ } ++ RT_TRACE(_module_hal_init_c_, _drv_info_, ("_WriteFW Done- for Normal chip.\n")); ++ ++exit: ++ return ret; ++} ++ ++void _MCUIO_Reset88E(PADAPTER padapter,u8 bReset) ++{ ++ u8 u1bTmp; ++ ++ if(bReset==_TRUE){ ++ // Reset MCU IO Wrapper- sugggest by SD1-Gimmy ++ u1bTmp = rtw_read8(padapter, REG_RSV_CTRL+1); ++ rtw_write8(padapter,REG_RSV_CTRL+1, (u1bTmp&(~BIT3))); ++ }else{ ++ // Enable MCU IO Wrapper ++ u1bTmp = rtw_read8(padapter, REG_RSV_CTRL+1); ++ rtw_write8(padapter, REG_RSV_CTRL+1, u1bTmp|BIT3); ++ } ++ ++} ++void _8051Reset88E(PADAPTER padapter) ++{ ++ u8 u1bTmp; ++ ++ _MCUIO_Reset88E(padapter,_TRUE); ++ u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN+1); ++ rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp&(~BIT2)); ++ _MCUIO_Reset88E(padapter,_FALSE); ++ rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp|(BIT2)); ++ ++ DBG_871X("=====> _8051Reset88E(): 8051 reset success .\n"); ++} ++ ++static s32 _FWFreeToGo(PADAPTER padapter) ++{ ++ u32 counter = 0; ++ u32 value32; ++ u8 value8; ++ ++ // polling CheckSum report ++ do { ++ value32 = rtw_read32(padapter, REG_MCUFWDL); ++ if (value32 & FWDL_ChkSum_rpt) break; ++ } while (counter++ < POLLING_READY_TIMEOUT_COUNT); ++ ++ if (counter >= POLLING_READY_TIMEOUT_COUNT) { ++ DBG_871X("%s: chksum report fail! REG_MCUFWDL:0x%08x\n", __FUNCTION__, value32); ++ return _FAIL; ++ } ++ DBG_871X("%s: Checksum report OK! REG_MCUFWDL:0x%08x\n", __FUNCTION__, value32); ++ ++ ++ value32 = rtw_read32(padapter, REG_MCUFWDL); ++ value32 |= MCUFWDL_RDY; ++ value32 &= ~WINTINI_RDY; ++ rtw_write32(padapter, REG_MCUFWDL, value32); ++ ++ _8051Reset88E(padapter); ++ ++ // polling for FW ready ++ counter = 0; ++ do { ++ value32 = rtw_read32(padapter, REG_MCUFWDL); ++ if (value32 & WINTINI_RDY) { ++ DBG_871X("%s: Polling FW ready success!! REG_MCUFWDL:0x%08x\n", __FUNCTION__, value32); ++ return _SUCCESS; ++ } ++ rtw_udelay_os(5); ++ } while (counter++ < POLLING_READY_TIMEOUT_COUNT); ++ ++ DBG_871X ("%s: Polling FW ready fail!! REG_MCUFWDL:0x%08x\n", __FUNCTION__, value32); ++ return _FAIL; ++} ++ ++#define IS_FW_81xxC(padapter) (((GET_HAL_DATA(padapter))->FirmwareSignature & 0xFFF0) == 0x88C0) ++ ++ ++#ifdef CONFIG_FILE_FWIMG ++extern char *rtw_fw_file_path; ++u8 FwBuffer8188E[FW_8188E_SIZE]; ++#endif //CONFIG_FILE_FWIMG ++#ifdef CONFIG_WOWLAN ++// ++// Description: ++// Download 8192C firmware code. ++// ++// ++s32 rtl8188e_FirmwareDownload(PADAPTER padapter, BOOLEAN bUsedWoWLANFw) ++#else ++s32 rtl8188e_FirmwareDownload(PADAPTER padapter) ++#endif ++{ ++ s32 rtStatus = _SUCCESS; ++ u8 writeFW_retry = 0; ++ u32 fwdl_start_time; ++ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); ++ ++ u8 *FwImage; ++ u32 FwImageLen; ++ u8 *pFwImageFileName; ++#ifdef CONFIG_WOWLAN ++ u8 *FwImageWoWLAN; ++ u32 FwImageWoWLANLen; ++#endif ++ u8 *pucMappedFile = NULL; ++ PRT_FIRMWARE_8188E pFirmware = NULL; ++ PRT_8188E_FIRMWARE_HDR pFwHdr = NULL; ++ u8 *pFirmwareBuf; ++ u32 FirmwareLen; ++ ++ ++ RT_TRACE(_module_hal_init_c_, _drv_info_, ("+%s\n", __FUNCTION__)); ++ pFirmware = (PRT_FIRMWARE_8188E)rtw_zmalloc(sizeof(RT_FIRMWARE_8188E)); ++ if(!pFirmware) ++ { ++ ++ rtStatus = _FAIL; ++ goto Exit; ++ } ++ ++ FwImage = (u8*)Rtl8188E_FwImageArray; ++ FwImageLen = Rtl8188E_FWImgArrayLength; ++ ++#ifdef CONFIG_WOWLAN ++ FwImageWoWLAN = (u8*)Rtl8188E_FwWoWImageArray; ++ FwImageWoWLANLen = Rtl8188E_FwWoWImgArrayLength; ++#endif //CONFIG_WOWLAN ++ ++// RT_TRACE(_module_hal_init_c_, _drv_err_, ("rtl8723a_FirmwareDownload: %s\n", pFwImageFileName)); ++ ++ #ifdef CONFIG_FILE_FWIMG ++ if(rtw_is_file_readable(rtw_fw_file_path) == _TRUE) ++ { ++ DBG_871X("%s accquire FW from file:%s\n", __FUNCTION__, rtw_fw_file_path); ++ pFirmware->eFWSource = FW_SOURCE_IMG_FILE; ++ } ++ else ++ #endif //CONFIG_FILE_FWIMG ++ { ++ pFirmware->eFWSource = FW_SOURCE_HEADER_FILE; ++ } ++ ++ switch(pFirmware->eFWSource) ++ { ++ case FW_SOURCE_IMG_FILE: ++ #ifdef CONFIG_FILE_FWIMG ++ rtStatus = rtw_retrive_from_file(rtw_fw_file_path, FwBuffer8188E, FW_8188E_SIZE); ++ pFirmware->ulFwLength = rtStatus>=0?rtStatus:0; ++ pFirmware->szFwBuffer = FwBuffer8188E; ++ #endif //CONFIG_FILE_FWIMG ++ break; ++ case FW_SOURCE_HEADER_FILE: ++ if (FwImageLen > FW_8188E_SIZE) { ++ rtStatus = _FAIL; ++ RT_TRACE(_module_hal_init_c_, _drv_err_, ("Firmware size exceed 0x%X. Check it.\n", FW_8188E_SIZE) ); ++ goto Exit; ++ } ++ ++ pFirmware->szFwBuffer = FwImage; ++ pFirmware->ulFwLength = FwImageLen; ++#ifdef CONFIG_WOWLAN ++ if(bUsedWoWLANFw){ ++ pFirmware->szWoWLANFwBuffer = FwImageWoWLAN; ++ pFirmware->ulWoWLANFwLength = FwImageWoWLANLen; ++ } ++#endif //CONFIG_WOWLAN ++ break; ++ } ++#ifdef CONFIG_WOWLAN ++ if(bUsedWoWLANFw) { ++ pFirmwareBuf = pFirmware->szWoWLANFwBuffer; ++ FirmwareLen = pFirmware->ulWoWLANFwLength; ++ pFwHdr = (PRT_8188E_FIRMWARE_HDR)pFirmware->szWoWLANFwBuffer; ++ } else ++#endif ++ { ++ pFirmwareBuf = pFirmware->szFwBuffer; ++ FirmwareLen = pFirmware->ulFwLength; ++ DBG_871X_LEVEL(_drv_info_, "+%s: !bUsedWoWLANFw, FmrmwareLen:%d+\n", __func__, FirmwareLen); ++ ++ // To Check Fw header. Added by tynli. 2009.12.04. ++ pFwHdr = (PRT_8188E_FIRMWARE_HDR)pFirmware->szFwBuffer; ++ } ++ ++ pHalData->FirmwareVersion = le16_to_cpu(pFwHdr->Version); ++ pHalData->FirmwareSubVersion = pFwHdr->Subversion; ++ pHalData->FirmwareSignature = le16_to_cpu(pFwHdr->Signature); ++ ++ DBG_871X ("%s: fw_ver=%d fw_subver=%d sig=0x%x\n", ++ __FUNCTION__, pHalData->FirmwareVersion, pHalData->FirmwareSubVersion, pHalData->FirmwareSignature); ++ ++ if (IS_FW_HEADER_EXIST(pFwHdr)) ++ { ++ // Shift 32 bytes for FW header ++ pFirmwareBuf = pFirmwareBuf + 32; ++ FirmwareLen = FirmwareLen - 32; ++ } ++ ++ // Suggested by Filen. If 8051 is running in RAM code, driver should inform Fw to reset by itself, ++ // or it will cause download Fw fail. 2010.02.01. by tynli. ++ if (rtw_read8(padapter, REG_MCUFWDL) & RAM_DL_SEL) //8051 RAM code ++ { ++ rtw_write8(padapter, REG_MCUFWDL, 0x00); ++ _8051Reset88E(padapter); ++ } ++ ++ _FWDownloadEnable(padapter, _TRUE); ++ fwdl_start_time = rtw_get_current_time(); ++ while(1) { ++ //reset the FWDL chksum ++ rtw_write8(padapter, REG_MCUFWDL, rtw_read8(padapter, REG_MCUFWDL)|FWDL_ChkSum_rpt); ++ ++ rtStatus = _WriteFW(padapter, pFirmwareBuf, FirmwareLen); ++ ++ if(rtStatus == _SUCCESS || padapter->bDriverStopped || padapter->bSurpriseRemoved ++ ||(writeFW_retry++ >= 3 && rtw_get_passing_time_ms(fwdl_start_time) > 500) ++ ) ++ break; ++ } ++ _FWDownloadEnable(padapter, _FALSE); ++ ++ DBG_871X("%s writeFW_retry:%u, time after fwdl_start_time:%ums\n", __FUNCTION__ ++ , writeFW_retry ++ , rtw_get_passing_time_ms(fwdl_start_time) ++ ); ++ ++ if(_SUCCESS != rtStatus){ ++ DBG_871X("DL Firmware failed!\n"); ++ goto Exit; ++ } ++ ++ rtStatus = _FWFreeToGo(padapter); ++ if (_SUCCESS != rtStatus) { ++ DBG_871X("DL Firmware failed!\n"); ++ goto Exit; ++ } ++ RT_TRACE(_module_hal_init_c_, _drv_info_, ("Firmware is ready to run!\n")); ++ ++Exit: ++ ++ if (pFirmware) ++ rtw_mfree((u8*)pFirmware, sizeof(RT_FIRMWARE_8188E)); ++ ++ //RT_TRACE(COMP_INIT, DBG_LOUD, (" <=== FirmwareDownload91C()\n")); ++#ifdef CONFIG_WOWLAN ++ if (adapter_to_pwrctl(padapter)->wowlan_mode) ++ rtl8188e_InitializeFirmwareVars(padapter); ++ else ++ DBG_871X_LEVEL(_drv_always_, "%s: wowland_mode:%d wowlan_wake_reason:%d\n", ++ __func__, adapter_to_pwrctl(padapter)->wowlan_mode, ++ adapter_to_pwrctl(padapter)->wowlan_wake_reason); ++#endif ++ ++ return rtStatus; ++} ++ ++#ifdef CONFIG_WOWLAN ++void rtl8188e_InitializeFirmwareVars(PADAPTER padapter) ++{ ++ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ ++ // Init Fw LPS related. ++ pwrpriv->bFwCurrentInPSMode = _FALSE; ++ // Init H2C counter. by tynli. 2009.12.09. ++ pHalData->LastHMEBoxNum = 0; ++} ++ ++//=========================================== ++ ++// ++// Description: Prepare some information to Fw for WoWLAN. ++// (1) Download wowlan Fw. ++// (2) Download RSVD page packets. ++// (3) Enable AP offload if needed. ++// ++// 2011.04.12 by tynli. ++// ++VOID ++SetFwRelatedForWoWLAN8188ES( ++ IN PADAPTER padapter, ++ IN u8 bHostIsGoingtoSleep ++) ++{ ++ int status=_FAIL; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ u8 bRecover = _FALSE; ++ // ++ // 1. Before WoWLAN we need to re-download WoWLAN Fw. ++ // ++ status = rtl8188e_FirmwareDownload(padapter, bHostIsGoingtoSleep); ++ if(status != _SUCCESS) { ++ DBG_871X("ConfigFwRelatedForWoWLAN8188ES(): Re-Download Firmware failed!!\n"); ++ return; ++ } else { ++ DBG_871X("ConfigFwRelatedForWoWLAN8188ES(): Re-Download Firmware Success !!\n"); ++ } ++ // ++ // 2. Re-Init the variables about Fw related setting. ++ // ++ rtl8188e_InitializeFirmwareVars(padapter); ++} ++#else ++void rtl8188e_InitializeFirmwareVars(PADAPTER padapter) ++{ ++ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); ++ ++ // Init Fw LPS related. ++ adapter_to_pwrctl(padapter)->bFwCurrentInPSMode = _FALSE; ++ ++ // Init H2C counter. by tynli. 2009.12.09. ++ pHalData->LastHMEBoxNum = 0; ++// pHalData->H2CQueueHead = 0; ++// pHalData->H2CQueueTail = 0; ++// pHalData->H2CStopInsertQueue = FALSE; ++} ++#endif //CONFIG_WOWLAN ++ ++static void rtl8188e_free_hal_data(PADAPTER padapter) ++{ ++_func_enter_; ++ ++ if(padapter->HalData) ++ { ++ rtw_mfree(padapter->HalData, sizeof(HAL_DATA_TYPE)); ++ padapter->HalData = NULL; ++ } ++ ++_func_exit_; ++} ++ ++//=========================================================== ++// Efuse related code ++//=========================================================== ++enum{ ++ VOLTAGE_V25 = 0x03, ++ LDOE25_SHIFT = 28 , ++ }; ++ ++static BOOLEAN ++hal_EfusePgPacketWrite2ByteHeader( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN u16 *pAddr, ++ IN PPGPKT_STRUCT pTargetPkt, ++ IN BOOLEAN bPseudoTest); ++static BOOLEAN ++hal_EfusePgPacketWrite1ByteHeader( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN u16 *pAddr, ++ IN PPGPKT_STRUCT pTargetPkt, ++ IN BOOLEAN bPseudoTest); ++static BOOLEAN ++hal_EfusePgPacketWriteData( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN u16 *pAddr, ++ IN PPGPKT_STRUCT pTargetPkt, ++ IN BOOLEAN bPseudoTest); ++ ++static VOID ++hal_EfusePowerSwitch_RTL8188E( ++ IN PADAPTER pAdapter, ++ IN u8 bWrite, ++ IN u8 PwrState) ++{ ++ u8 tempval; ++ u16 tmpV16; ++ ++ if (PwrState == _TRUE) ++ { ++ rtw_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON); ++ ++ // 1.2V Power: From VDDON with Power Cut(0x0000h[15]), defualt valid ++ tmpV16 = rtw_read16(pAdapter,REG_SYS_ISO_CTRL); ++ if( ! (tmpV16 & PWC_EV12V ) ){ ++ tmpV16 |= PWC_EV12V ; ++ rtw_write16(pAdapter,REG_SYS_ISO_CTRL,tmpV16); ++ } ++ // Reset: 0x0000h[28], default valid ++ tmpV16 = rtw_read16(pAdapter,REG_SYS_FUNC_EN); ++ if( !(tmpV16 & FEN_ELDR) ){ ++ tmpV16 |= FEN_ELDR ; ++ rtw_write16(pAdapter,REG_SYS_FUNC_EN,tmpV16); ++ } ++ ++ // Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid ++ tmpV16 = rtw_read16(pAdapter,REG_SYS_CLKR); ++ if( (!(tmpV16 & LOADER_CLK_EN) ) ||(!(tmpV16 & ANA8M) ) ){ ++ tmpV16 |= (LOADER_CLK_EN |ANA8M ) ; ++ rtw_write16(pAdapter,REG_SYS_CLKR,tmpV16); ++ } ++ ++ if(bWrite == _TRUE) ++ { ++ // Enable LDO 2.5V before read/write action ++ tempval = rtw_read8(pAdapter, EFUSE_TEST+3); ++ tempval &= 0x0F; ++ tempval |= (VOLTAGE_V25 << 4); ++ rtw_write8(pAdapter, EFUSE_TEST+3, (tempval | 0x80)); ++ } ++ } ++ else ++ { ++ rtw_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF); ++ ++ if(bWrite == _TRUE){ ++ // Disable LDO 2.5V after read/write action ++ tempval = rtw_read8(pAdapter, EFUSE_TEST+3); ++ rtw_write8(pAdapter, EFUSE_TEST+3, (tempval & 0x7F)); ++ } ++ } ++} ++ ++static VOID ++rtl8188e_EfusePowerSwitch( ++ IN PADAPTER pAdapter, ++ IN u8 bWrite, ++ IN u8 PwrState) ++{ ++ hal_EfusePowerSwitch_RTL8188E(pAdapter, bWrite, PwrState); ++} ++ ++ ++ ++static bool efuse_read_phymap( ++ PADAPTER Adapter, ++ u8 *pbuf, //buffer to store efuse physical map ++ u16 *size //the max byte to read. will update to byte read ++ ) ++{ ++ u8 *pos = pbuf; ++ u16 limit = *size; ++ u16 addr = 0; ++ bool reach_end = _FALSE; ++ ++ // ++ // Refresh efuse init map as all 0xFF. ++ // ++ _rtw_memset(pbuf, 0xFF, limit); ++ ++ ++ // ++ // Read physical efuse content. ++ // ++ while(addr < limit) ++ { ++ ReadEFuseByte(Adapter, addr, pos, _FALSE); ++ if(*pos != 0xFF) ++ { ++ pos++; ++ addr++; ++ } ++ else ++ { ++ reach_end = _TRUE; ++ break; ++ } ++ } ++ ++ *size = addr; ++ ++ return reach_end; ++ ++} ++ ++static VOID ++Hal_EfuseReadEFuse88E( ++ PADAPTER Adapter, ++ u16 _offset, ++ u16 _size_byte, ++ u8 *pbuf, ++ IN BOOLEAN bPseudoTest ++ ) ++{ ++ //u8 efuseTbl[EFUSE_MAP_LEN_88E]; ++ u8 *efuseTbl = NULL; ++ u8 rtemp8[1]; ++ u16 eFuse_Addr = 0; ++ u8 offset, wren; ++ u16 i, j; ++ //u16 eFuseWord[EFUSE_MAX_SECTION_88E][EFUSE_MAX_WORD_UNIT]; ++ u16 **eFuseWord = NULL; ++ u16 efuse_utilized = 0; ++ u8 efuse_usage = 0; ++ u8 u1temp = 0; ++ ++ // ++ // Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. ++ // ++ if((_offset + _size_byte)>EFUSE_MAP_LEN_88E) ++ {// total E-Fuse table is 512bytes ++ DBG_8192C("Hal_EfuseReadEFuse88E(): Invalid offset(%#x) with read bytes(%#x)!!\n",_offset, _size_byte); ++ goto exit; ++ } ++ ++ efuseTbl = (u8*)rtw_zmalloc(EFUSE_MAP_LEN_88E); ++ if(efuseTbl == NULL) ++ { ++ DBG_871X("%s: alloc efuseTbl fail!\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ eFuseWord= (u16 **)rtw_malloc2d(EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16)); ++ if(eFuseWord == NULL) ++ { ++ DBG_871X("%s: alloc eFuseWord fail!\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ // 0. Refresh efuse init map as all oxFF. ++ for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) ++ for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) ++ eFuseWord[i][j] = 0xFFFF; ++ ++ // ++ // 1. Read the first byte to check if efuse is empty!!! ++ // ++ // ++ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); ++ if(*rtemp8 != 0xFF) ++ { ++ efuse_utilized++; ++ //DBG_8192C("efuse_Addr-%d efuse_data=%x\n", eFuse_Addr, *rtemp8); ++ eFuse_Addr++; ++ } ++ else ++ { ++ DBG_871X("EFUSE is empty efuse_Addr-%d efuse_data=%x\n", eFuse_Addr, *rtemp8); ++ goto exit; ++ } ++ ++ ++ // ++ // 2. Read real efuse content. Filter PG header and every section data. ++ // ++ while((*rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) ++ { ++ //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("efuse_Addr-%d efuse_data=%x\n", eFuse_Addr-1, *rtemp8)); ++ ++ // Check PG header for section num. ++ if((*rtemp8 & 0x1F ) == 0x0F) //extended header ++ { ++ u1temp =( (*rtemp8 & 0xE0) >> 5); ++ //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("extended header u1temp=%x *rtemp&0xE0 0x%x\n", u1temp, *rtemp8 & 0xE0)); ++ ++ //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("extended header u1temp=%x \n", u1temp)); ++ ++ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); ++ ++ //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("extended header efuse_Addr-%d efuse_data=%x\n", eFuse_Addr, *rtemp8)); ++ ++ if((*rtemp8 & 0x0F) == 0x0F) ++ { ++ eFuse_Addr++; ++ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); ++ ++ if(*rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) ++ { ++ eFuse_Addr++; ++ } ++ continue; ++ } ++ else ++ { ++ offset = ((*rtemp8 & 0xF0) >> 1) | u1temp; ++ wren = (*rtemp8 & 0x0F); ++ eFuse_Addr++; ++ } ++ } ++ else ++ { ++ offset = ((*rtemp8 >> 4) & 0x0f); ++ wren = (*rtemp8 & 0x0f); ++ } ++ ++ if(offset < EFUSE_MAX_SECTION_88E) ++ { ++ // Get word enable value from PG header ++ //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("Offset-%d Worden=%x\n", offset, wren)); ++ ++ for(i=0; i= EFUSE_REAL_CONTENT_LEN_88E) ++ break; ++ ++ //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("Addr=%d", eFuse_Addr)); ++ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); ++ eFuse_Addr++; ++ //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("Data=0x%x\n", *rtemp8)); ++ ++ efuse_utilized++; ++ eFuseWord[offset][i] |= (((u2Byte)*rtemp8 << 8) & 0xff00); ++ ++ if(eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E) ++ break; ++ } ++ ++ wren >>= 1; ++ ++ } ++ } ++ ++ // Read next PG header ++ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); ++ //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("Addr=%d rtemp 0x%x\n", eFuse_Addr, *rtemp8)); ++ ++ if(*rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) ++ { ++ efuse_utilized++; ++ eFuse_Addr++; ++ } ++ } ++ ++ // ++ // 3. Collect 16 sections and 4 word unit into Efuse map. ++ // ++ for(i=0; i> 8) & 0xff); ++ } ++ } ++ ++ ++ // ++ // 4. Copy from Efuse map to output pointer memory!!! ++ // ++ for(i=0; i<_size_byte; i++) ++ { ++ pbuf[i] = efuseTbl[_offset+i]; ++ } ++ ++ // ++ // 5. Calculate Efuse utilization. ++ // ++ efuse_usage = (u1Byte)((eFuse_Addr*100)/EFUSE_REAL_CONTENT_LEN_88E); ++ rtw_hal_set_hwreg(Adapter, HW_VAR_EFUSE_BYTES, (u8 *)&eFuse_Addr); ++ ++exit: ++ if(efuseTbl) ++ rtw_mfree(efuseTbl, EFUSE_MAP_LEN_88E); ++ ++ if(eFuseWord) ++ rtw_mfree2d((void *)eFuseWord, EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16)); ++} ++ ++ ++static BOOLEAN ++Hal_EfuseSwitchToBank( ++ IN PADAPTER pAdapter, ++ IN u8 bank, ++ IN BOOLEAN bPseudoTest ++ ) ++{ ++ BOOLEAN bRet = _FALSE; ++ u32 value32=0; ++ ++ //RTPRINT(FEEPROM, EFUSE_PG, ("Efuse switch bank to %d\n", bank)); ++ if(bPseudoTest) ++ { ++ fakeEfuseBank = bank; ++ bRet = _TRUE; ++ } ++ else ++ { ++ if(IS_HARDWARE_TYPE_8723A(pAdapter) && ++ INCLUDE_MULTI_FUNC_BT(pAdapter)) ++ { ++ value32 = rtw_read32(pAdapter, EFUSE_TEST); ++ bRet = _TRUE; ++ switch(bank) ++ { ++ case 0: ++ value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); ++ break; ++ case 1: ++ value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_0); ++ break; ++ case 2: ++ value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_1); ++ break; ++ case 3: ++ value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_2); ++ break; ++ default: ++ value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); ++ bRet = _FALSE; ++ break; ++ } ++ rtw_write32(pAdapter, EFUSE_TEST, value32); ++ } ++ else ++ bRet = _TRUE; ++ } ++ return bRet; ++} ++ ++ ++ ++static VOID ++ReadEFuseByIC( ++ PADAPTER Adapter, ++ u8 efuseType, ++ u16 _offset, ++ u16 _size_byte, ++ u8 *pbuf, ++ IN BOOLEAN bPseudoTest ++ ) ++{ ++#ifdef DBG_IOL_READ_EFUSE_MAP ++ u8 logical_map[512]; ++#endif ++ ++#ifdef CONFIG_IOL_READ_EFUSE_MAP ++ if(!bPseudoTest )//&& rtw_IOL_applied(Adapter)) ++ { ++ int ret = _FAIL; ++ if(rtw_IOL_applied(Adapter)) ++ { ++ rtw_hal_power_on(Adapter); ++ ++ iol_mode_enable(Adapter, 1); ++ #ifdef DBG_IOL_READ_EFUSE_MAP ++ iol_read_efuse(Adapter, 0, _offset, _size_byte, logical_map); ++ #else ++ ret = iol_read_efuse(Adapter, 0, _offset, _size_byte, pbuf); ++ #endif ++ iol_mode_enable(Adapter, 0); ++ ++ if(_SUCCESS == ret) ++ goto exit; ++ } ++ } ++#endif ++ Hal_EfuseReadEFuse88E(Adapter, _offset, _size_byte, pbuf, bPseudoTest); ++ ++exit: ++ ++#ifdef DBG_IOL_READ_EFUSE_MAP ++ if(_rtw_memcmp(logical_map, Adapter->eeprompriv.efuse_eeprom_data, 0x130) == _FALSE) ++ { ++ int i; ++ DBG_871X("%s compare first 0x130 byte fail\n", __FUNCTION__); ++ for(i=0;i<512;i++) ++ { ++ if(i%16==0) ++ DBG_871X("0x%03x: ", i); ++ DBG_871X("%02x ", logical_map[i]); ++ if(i%16==15) ++ DBG_871X("\n"); ++ } ++ DBG_871X("\n"); ++ } ++#endif ++ ++ return; ++} ++ ++static VOID ++ReadEFuse_Pseudo( ++ PADAPTER Adapter, ++ u8 efuseType, ++ u16 _offset, ++ u16 _size_byte, ++ u8 *pbuf, ++ IN BOOLEAN bPseudoTest ++ ) ++{ ++ Hal_EfuseReadEFuse88E(Adapter, _offset, _size_byte, pbuf, bPseudoTest); ++} ++ ++static VOID ++rtl8188e_ReadEFuse( ++ PADAPTER Adapter, ++ u8 efuseType, ++ u16 _offset, ++ u16 _size_byte, ++ u8 *pbuf, ++ IN BOOLEAN bPseudoTest ++ ) ++{ ++ if(bPseudoTest) ++ { ++ ReadEFuse_Pseudo(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest); ++ } ++ else ++ { ++ ReadEFuseByIC(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest); ++ } ++} ++ ++//Do not support BT ++VOID ++Hal_EFUSEGetEfuseDefinition88E( ++ IN PADAPTER pAdapter, ++ IN u1Byte efuseType, ++ IN u1Byte type, ++ OUT PVOID pOut ++ ) ++{ ++ switch(type) ++ { ++ case TYPE_EFUSE_MAX_SECTION: ++ { ++ u8* pMax_section; ++ pMax_section = (u8*)pOut; ++ *pMax_section = EFUSE_MAX_SECTION_88E; ++ } ++ break; ++ case TYPE_EFUSE_REAL_CONTENT_LEN: ++ { ++ u16* pu2Tmp; ++ pu2Tmp = (u16*)pOut; ++ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E; ++ } ++ break; ++ case TYPE_EFUSE_CONTENT_LEN_BANK: ++ { ++ u16* pu2Tmp; ++ pu2Tmp = (u16*)pOut; ++ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E; ++ } ++ break; ++ case TYPE_AVAILABLE_EFUSE_BYTES_BANK: ++ { ++ u16* pu2Tmp; ++ pu2Tmp = (u16*)pOut; ++ *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E); ++ } ++ break; ++ case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL: ++ { ++ u16* pu2Tmp; ++ pu2Tmp = (u16*)pOut; ++ *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E); ++ } ++ break; ++ case TYPE_EFUSE_MAP_LEN: ++ { ++ u16* pu2Tmp; ++ pu2Tmp = (u16*)pOut; ++ *pu2Tmp = (u16)EFUSE_MAP_LEN_88E; ++ } ++ break; ++ case TYPE_EFUSE_PROTECT_BYTES_BANK: ++ { ++ u8* pu1Tmp; ++ pu1Tmp = (u8*)pOut; ++ *pu1Tmp = (u8)(EFUSE_OOB_PROTECT_BYTES_88E); ++ } ++ break; ++ default: ++ { ++ u8* pu1Tmp; ++ pu1Tmp = (u8*)pOut; ++ *pu1Tmp = 0; ++ } ++ break; ++ } ++} ++VOID ++Hal_EFUSEGetEfuseDefinition_Pseudo88E( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN u8 type, ++ OUT PVOID pOut ++ ) ++{ ++ switch(type) ++ { ++ case TYPE_EFUSE_MAX_SECTION: ++ { ++ u8* pMax_section; ++ pMax_section = (pu1Byte)pOut; ++ *pMax_section = EFUSE_MAX_SECTION_88E; ++ } ++ break; ++ case TYPE_EFUSE_REAL_CONTENT_LEN: ++ { ++ u16* pu2Tmp; ++ pu2Tmp = (pu2Byte)pOut; ++ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E; ++ } ++ break; ++ case TYPE_EFUSE_CONTENT_LEN_BANK: ++ { ++ u16* pu2Tmp; ++ pu2Tmp = (pu2Byte)pOut; ++ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E; ++ } ++ break; ++ case TYPE_AVAILABLE_EFUSE_BYTES_BANK: ++ { ++ u16* pu2Tmp; ++ pu2Tmp = (pu2Byte)pOut; ++ *pu2Tmp = (u2Byte)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E); ++ } ++ break; ++ case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL: ++ { ++ u16* pu2Tmp; ++ pu2Tmp = (pu2Byte)pOut; ++ *pu2Tmp = (u2Byte)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E); ++ } ++ break; ++ case TYPE_EFUSE_MAP_LEN: ++ { ++ u16* pu2Tmp; ++ pu2Tmp = (pu2Byte)pOut; ++ *pu2Tmp = (u2Byte)EFUSE_MAP_LEN_88E; ++ } ++ break; ++ case TYPE_EFUSE_PROTECT_BYTES_BANK: ++ { ++ u8* pu1Tmp; ++ pu1Tmp = (u8*)pOut; ++ *pu1Tmp = (u8)(EFUSE_OOB_PROTECT_BYTES_88E); ++ } ++ break; ++ default: ++ { ++ u8* pu1Tmp; ++ pu1Tmp = (u8*)pOut; ++ *pu1Tmp = 0; ++ } ++ break; ++ } ++} ++ ++ ++static VOID ++rtl8188e_EFUSE_GetEfuseDefinition( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN u8 type, ++ OUT void *pOut, ++ IN BOOLEAN bPseudoTest ++ ) ++{ ++ if(bPseudoTest) ++ { ++ Hal_EFUSEGetEfuseDefinition_Pseudo88E(pAdapter, efuseType, type, pOut); ++ } ++ else ++ { ++ Hal_EFUSEGetEfuseDefinition88E(pAdapter, efuseType, type, pOut); ++ } ++} ++ ++static u8 ++Hal_EfuseWordEnableDataWrite( IN PADAPTER pAdapter, ++ IN u16 efuse_addr, ++ IN u8 word_en, ++ IN u8 *data, ++ IN BOOLEAN bPseudoTest) ++{ ++ u16 tmpaddr = 0; ++ u16 start_addr = efuse_addr; ++ u8 badworden = 0x0F; ++ u8 tmpdata[8]; ++ ++ _rtw_memset((PVOID)tmpdata, 0xff, PGPKT_DATA_SIZE); ++ //RT_TRACE(COMP_EFUSE, DBG_LOUD, ("word_en = %x efuse_addr=%x\n", word_en, efuse_addr)); ++ ++ if(!(word_en&BIT0)) ++ { ++ tmpaddr = start_addr; ++ efuse_OneByteWrite(pAdapter,start_addr++, data[0], bPseudoTest); ++ efuse_OneByteWrite(pAdapter,start_addr++, data[1], bPseudoTest); ++ ++ efuse_OneByteRead(pAdapter,tmpaddr, &tmpdata[0], bPseudoTest); ++ efuse_OneByteRead(pAdapter,tmpaddr+1, &tmpdata[1], bPseudoTest); ++ if((data[0]!=tmpdata[0])||(data[1]!=tmpdata[1])){ ++ badworden &= (~BIT0); ++ } ++ } ++ if(!(word_en&BIT1)) ++ { ++ tmpaddr = start_addr; ++ efuse_OneByteWrite(pAdapter,start_addr++, data[2], bPseudoTest); ++ efuse_OneByteWrite(pAdapter,start_addr++, data[3], bPseudoTest); ++ ++ efuse_OneByteRead(pAdapter,tmpaddr , &tmpdata[2], bPseudoTest); ++ efuse_OneByteRead(pAdapter,tmpaddr+1, &tmpdata[3], bPseudoTest); ++ if((data[2]!=tmpdata[2])||(data[3]!=tmpdata[3])){ ++ badworden &=( ~BIT1); ++ } ++ } ++ if(!(word_en&BIT2)) ++ { ++ tmpaddr = start_addr; ++ efuse_OneByteWrite(pAdapter,start_addr++, data[4], bPseudoTest); ++ efuse_OneByteWrite(pAdapter,start_addr++, data[5], bPseudoTest); ++ ++ efuse_OneByteRead(pAdapter,tmpaddr, &tmpdata[4], bPseudoTest); ++ efuse_OneByteRead(pAdapter,tmpaddr+1, &tmpdata[5], bPseudoTest); ++ if((data[4]!=tmpdata[4])||(data[5]!=tmpdata[5])){ ++ badworden &=( ~BIT2); ++ } ++ } ++ if(!(word_en&BIT3)) ++ { ++ tmpaddr = start_addr; ++ efuse_OneByteWrite(pAdapter,start_addr++, data[6], bPseudoTest); ++ efuse_OneByteWrite(pAdapter,start_addr++, data[7], bPseudoTest); ++ ++ efuse_OneByteRead(pAdapter,tmpaddr, &tmpdata[6], bPseudoTest); ++ efuse_OneByteRead(pAdapter,tmpaddr+1, &tmpdata[7], bPseudoTest); ++ if((data[6]!=tmpdata[6])||(data[7]!=tmpdata[7])){ ++ badworden &=( ~BIT3); ++ } ++ } ++ return badworden; ++} ++ ++static u8 ++Hal_EfuseWordEnableDataWrite_Pseudo( IN PADAPTER pAdapter, ++ IN u16 efuse_addr, ++ IN u8 word_en, ++ IN u8 *data, ++ IN BOOLEAN bPseudoTest) ++{ ++ u8 ret=0; ++ ++ ret = Hal_EfuseWordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest); ++ ++ return ret; ++} ++ ++static u8 ++rtl8188e_Efuse_WordEnableDataWrite( IN PADAPTER pAdapter, ++ IN u16 efuse_addr, ++ IN u8 word_en, ++ IN u8 *data, ++ IN BOOLEAN bPseudoTest) ++{ ++ u8 ret=0; ++ ++ if(bPseudoTest) ++ { ++ ret = Hal_EfuseWordEnableDataWrite_Pseudo(pAdapter, efuse_addr, word_en, data, bPseudoTest); ++ } ++ else ++ { ++ ret = Hal_EfuseWordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest); ++ } ++ ++ return ret; ++} ++ ++ ++static u16 ++hal_EfuseGetCurrentSize_8188e(IN PADAPTER pAdapter, ++ IN BOOLEAN bPseudoTest) ++{ ++ int bContinual = _TRUE; ++ ++ u16 efuse_addr = 0; ++ u8 hoffset=0,hworden=0; ++ u8 efuse_data,word_cnts=0; ++ ++ if(bPseudoTest) ++ { ++ efuse_addr = (u16)(fakeEfuseUsedBytes); ++ } ++ else ++ { ++ rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr); ++ } ++ //RTPRINT(FEEPROM, EFUSE_PG, ("hal_EfuseGetCurrentSize_8723A(), start_efuse_addr = %d\n", efuse_addr)); ++ ++ while ( bContinual && ++ efuse_OneByteRead(pAdapter, efuse_addr ,&efuse_data, bPseudoTest) && ++ AVAILABLE_EFUSE_ADDR(efuse_addr)) ++ { ++ if(efuse_data!=0xFF) ++ { ++ if((efuse_data&0x1F) == 0x0F) //extended header ++ { ++ hoffset = efuse_data; ++ efuse_addr++; ++ efuse_OneByteRead(pAdapter, efuse_addr ,&efuse_data, bPseudoTest); ++ if((efuse_data & 0x0F) == 0x0F) ++ { ++ efuse_addr++; ++ continue; ++ } ++ else ++ { ++ hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); ++ hworden = efuse_data & 0x0F; ++ } ++ } ++ else ++ { ++ hoffset = (efuse_data>>4) & 0x0F; ++ hworden = efuse_data & 0x0F; ++ } ++ word_cnts = Efuse_CalculateWordCnts(hworden); ++ //read next header ++ efuse_addr = efuse_addr + (word_cnts*2)+1; ++ } ++ else ++ { ++ bContinual = _FALSE ; ++ } ++ } ++ ++ if(bPseudoTest) ++ { ++ fakeEfuseUsedBytes = efuse_addr; ++ //RTPRINT(FEEPROM, EFUSE_PG, ("hal_EfuseGetCurrentSize_8723A(), return %d\n", fakeEfuseUsedBytes)); ++ } ++ else ++ { ++ rtw_hal_set_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr); ++ //RTPRINT(FEEPROM, EFUSE_PG, ("hal_EfuseGetCurrentSize_8723A(), return %d\n", efuse_addr)); ++ } ++ ++ return efuse_addr; ++} ++ ++static u16 ++Hal_EfuseGetCurrentSize_Pseudo(IN PADAPTER pAdapter, ++ IN BOOLEAN bPseudoTest) ++{ ++ u16 ret=0; ++ ++ ret = hal_EfuseGetCurrentSize_8188e(pAdapter, bPseudoTest); ++ ++ return ret; ++} ++ ++ ++static u16 ++rtl8188e_EfuseGetCurrentSize( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN BOOLEAN bPseudoTest) ++{ ++ u16 ret=0; ++ ++ if(bPseudoTest) ++ { ++ ret = Hal_EfuseGetCurrentSize_Pseudo(pAdapter, bPseudoTest); ++ } ++ else ++ { ++ ret = hal_EfuseGetCurrentSize_8188e(pAdapter, bPseudoTest); ++ ++ } ++ ++ return ret; ++} ++ ++ ++static int ++hal_EfusePgPacketRead_8188e( ++ IN PADAPTER pAdapter, ++ IN u8 offset, ++ IN u8 *data, ++ IN BOOLEAN bPseudoTest) ++{ ++ u8 ReadState = PG_STATE_HEADER; ++ ++ int bContinual = _TRUE; ++ int bDataEmpty = _TRUE ; ++ ++ u8 efuse_data,word_cnts = 0; ++ u16 efuse_addr = 0; ++ u8 hoffset = 0,hworden = 0; ++ u8 tmpidx = 0; ++ u8 tmpdata[8]; ++ u8 max_section = 0; ++ u8 tmp_header = 0; ++ ++ EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAX_SECTION, (PVOID)&max_section, bPseudoTest); ++ ++ if(data==NULL) ++ return _FALSE; ++ if(offset>max_section) ++ return _FALSE; ++ ++ _rtw_memset((PVOID)data, 0xff, sizeof(u8)*PGPKT_DATA_SIZE); ++ _rtw_memset((PVOID)tmpdata, 0xff, sizeof(u8)*PGPKT_DATA_SIZE); ++ ++ ++ // ++ // Efuse has been pre-programmed dummy 5Bytes at the end of Efuse by CP. ++ // Skip dummy parts to prevent unexpected data read from Efuse. ++ // By pass right now. 2009.02.19. ++ // ++ while(bContinual && AVAILABLE_EFUSE_ADDR(efuse_addr) ) ++ { ++ //------- Header Read ------------- ++ if(ReadState & PG_STATE_HEADER) ++ { ++ if(efuse_OneByteRead(pAdapter, efuse_addr ,&efuse_data, bPseudoTest)&&(efuse_data!=0xFF)) ++ { ++ if(EXT_HEADER(efuse_data)) ++ { ++ tmp_header = efuse_data; ++ efuse_addr++; ++ efuse_OneByteRead(pAdapter, efuse_addr ,&efuse_data, bPseudoTest); ++ if(!ALL_WORDS_DISABLED(efuse_data)) ++ { ++ hoffset = ((tmp_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); ++ hworden = efuse_data & 0x0F; ++ } ++ else ++ { ++ DBG_8192C("Error, All words disabled\n"); ++ efuse_addr++; ++ continue; ++ } ++ } ++ else ++ { ++ hoffset = (efuse_data>>4) & 0x0F; ++ hworden = efuse_data & 0x0F; ++ } ++ word_cnts = Efuse_CalculateWordCnts(hworden); ++ bDataEmpty = _TRUE ; ++ ++ if(hoffset==offset) ++ { ++ for(tmpidx = 0;tmpidx< word_cnts*2 ;tmpidx++) ++ { ++ if(efuse_OneByteRead(pAdapter, efuse_addr+1+tmpidx ,&efuse_data, bPseudoTest) ) ++ { ++ tmpdata[tmpidx] = efuse_data; ++ if(efuse_data!=0xff) ++ { ++ bDataEmpty = _FALSE; ++ } ++ } ++ } ++ if(bDataEmpty==_FALSE){ ++ ReadState = PG_STATE_DATA; ++ }else{//read next header ++ efuse_addr = efuse_addr + (word_cnts*2)+1; ++ ReadState = PG_STATE_HEADER; ++ } ++ } ++ else{//read next header ++ efuse_addr = efuse_addr + (word_cnts*2)+1; ++ ReadState = PG_STATE_HEADER; ++ } ++ ++ } ++ else{ ++ bContinual = _FALSE ; ++ } ++ } ++ //------- Data section Read ------------- ++ else if(ReadState & PG_STATE_DATA) ++ { ++ efuse_WordEnableDataRead(hworden,tmpdata,data); ++ efuse_addr = efuse_addr + (word_cnts*2)+1; ++ ReadState = PG_STATE_HEADER; ++ } ++ ++ } ++ ++ if( (data[0]==0xff) &&(data[1]==0xff) && (data[2]==0xff) && (data[3]==0xff) && ++ (data[4]==0xff) &&(data[5]==0xff) && (data[6]==0xff) && (data[7]==0xff)) ++ return _FALSE; ++ else ++ return _TRUE; ++ ++} ++ ++static int ++Hal_EfusePgPacketRead( IN PADAPTER pAdapter, ++ IN u8 offset, ++ IN u8 *data, ++ IN BOOLEAN bPseudoTest) ++{ ++ int ret=0; ++ ++ ret = hal_EfusePgPacketRead_8188e(pAdapter, offset, data, bPseudoTest); ++ ++ ++ return ret; ++} ++ ++static int ++Hal_EfusePgPacketRead_Pseudo( IN PADAPTER pAdapter, ++ IN u8 offset, ++ IN u8 *data, ++ IN BOOLEAN bPseudoTest) ++{ ++ int ret=0; ++ ++ ret = hal_EfusePgPacketRead_8188e(pAdapter, offset, data, bPseudoTest); ++ ++ return ret; ++} ++ ++static int ++rtl8188e_Efuse_PgPacketRead( IN PADAPTER pAdapter, ++ IN u8 offset, ++ IN u8 *data, ++ IN BOOLEAN bPseudoTest) ++{ ++ int ret=0; ++ ++ if(bPseudoTest) ++ { ++ ret = Hal_EfusePgPacketRead_Pseudo(pAdapter, offset, data, bPseudoTest); ++ } ++ else ++ { ++ ret = Hal_EfusePgPacketRead(pAdapter, offset, data, bPseudoTest); ++ } ++ ++ return ret; ++} ++ ++static BOOLEAN ++hal_EfuseFixHeaderProcess( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN PPGPKT_STRUCT pFixPkt, ++ IN u16 *pAddr, ++ IN BOOLEAN bPseudoTest ++) ++{ ++ u8 originaldata[8], badworden=0; ++ u16 efuse_addr=*pAddr; ++ u32 PgWriteSuccess=0; ++ ++ _rtw_memset((PVOID)originaldata, 0xff, 8); ++ ++ if(Efuse_PgPacketRead(pAdapter, pFixPkt->offset, originaldata, bPseudoTest)) ++ { //check if data exist ++ badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pFixPkt->word_en, originaldata, bPseudoTest); ++ ++ if(badworden != 0xf) // write fail ++ { ++ PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pFixPkt->offset, badworden, originaldata, bPseudoTest); ++ ++ if(!PgWriteSuccess) ++ return _FALSE; ++ else ++ efuse_addr = Efuse_GetCurrentSize(pAdapter, efuseType, bPseudoTest); ++ } ++ else ++ { ++ efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) +1; ++ } ++ } ++ else ++ { ++ efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) +1; ++ } ++ *pAddr = efuse_addr; ++ return _TRUE; ++} ++ ++static BOOLEAN ++hal_EfusePgPacketWrite2ByteHeader( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN u16 *pAddr, ++ IN PPGPKT_STRUCT pTargetPkt, ++ IN BOOLEAN bPseudoTest) ++{ ++ BOOLEAN bRet=_FALSE, bContinual=_TRUE; ++ u16 efuse_addr=*pAddr, efuse_max_available_len=0; ++ u8 pg_header=0, tmp_header=0, pg_header_temp=0; ++ u8 repeatcnt=0; ++ ++ //RTPRINT(FEEPROM, EFUSE_PG, ("Wirte 2byte header\n")); ++ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (PVOID)&efuse_max_available_len, bPseudoTest); ++ ++ while(efuse_addr < efuse_max_available_len) ++ { ++ pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F; ++ //RTPRINT(FEEPROM, EFUSE_PG, ("pg_header = 0x%x\n", pg_header)); ++ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); ++ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); ++ ++ while(tmp_header == 0xFF) ++ { ++ if(repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) ++ { ++ //RTPRINT(FEEPROM, EFUSE_PG, ("Repeat over limit for pg_header!!\n")); ++ return _FALSE; ++ } ++ ++ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); ++ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); ++ } ++ ++ //to write ext_header ++ if(tmp_header == pg_header) ++ { ++ efuse_addr++; ++ pg_header_temp = pg_header; ++ pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en; ++ ++ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); ++ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); ++ ++ while(tmp_header == 0xFF) ++ { ++ if(repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) ++ { ++ //RTPRINT(FEEPROM, EFUSE_PG, ("Repeat over limit for ext_header!!\n")); ++ return _FALSE; ++ } ++ ++ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); ++ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); ++ } ++ ++ if((tmp_header & 0x0F) == 0x0F) //word_en PG fail ++ { ++ if(repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) ++ { ++ //RTPRINT(FEEPROM, EFUSE_PG, ("Repeat over limit for word_en!!\n")); ++ return _FALSE; ++ } ++ else ++ { ++ efuse_addr++; ++ continue; ++ } ++ } ++ else if(pg_header != tmp_header) //offset PG fail ++ { ++ PGPKT_STRUCT fixPkt; ++ //RTPRINT(FEEPROM, EFUSE_PG, ("Error condition for offset PG fail, need to cover the existed data\n")); ++ fixPkt.offset = ((pg_header_temp & 0xE0) >> 5) | ((tmp_header & 0xF0) >> 1); ++ fixPkt.word_en = tmp_header & 0x0F; ++ fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en); ++ if(!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr, bPseudoTest)) ++ return _FALSE; ++ } ++ else ++ { ++ bRet = _TRUE; ++ break; ++ } ++ } ++ else if ((tmp_header & 0x1F) == 0x0F) //wrong extended header ++ { ++ efuse_addr+=2; ++ continue; ++ } ++ } ++ ++ *pAddr = efuse_addr; ++ return bRet; ++} ++ ++static BOOLEAN ++hal_EfusePgPacketWrite1ByteHeader( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN u16 *pAddr, ++ IN PPGPKT_STRUCT pTargetPkt, ++ IN BOOLEAN bPseudoTest) ++{ ++ BOOLEAN bRet=_FALSE; ++ u8 pg_header=0, tmp_header=0; ++ u16 efuse_addr=*pAddr; ++ u8 repeatcnt=0; ++ ++ //RTPRINT(FEEPROM, EFUSE_PG, ("Wirte 1byte header\n")); ++ pg_header = ((pTargetPkt->offset << 4) & 0xf0) |pTargetPkt->word_en; ++ ++ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); ++ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); ++ ++ while(tmp_header == 0xFF) ++ { ++ if(repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) ++ { ++ return _FALSE; ++ } ++ efuse_OneByteWrite(pAdapter,efuse_addr, pg_header, bPseudoTest); ++ efuse_OneByteRead(pAdapter,efuse_addr, &tmp_header, bPseudoTest); ++ } ++ ++ if(pg_header == tmp_header) ++ { ++ bRet = _TRUE; ++ } ++ else ++ { ++ PGPKT_STRUCT fixPkt; ++ //RTPRINT(FEEPROM, EFUSE_PG, ("Error condition for fixed PG packet, need to cover the existed data\n")); ++ fixPkt.offset = (tmp_header>>4) & 0x0F; ++ fixPkt.word_en = tmp_header & 0x0F; ++ fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en); ++ if(!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr, bPseudoTest)) ++ return _FALSE; ++ } ++ ++ *pAddr = efuse_addr; ++ return bRet; ++} ++ ++static BOOLEAN ++hal_EfusePgPacketWriteData( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN u16 *pAddr, ++ IN PPGPKT_STRUCT pTargetPkt, ++ IN BOOLEAN bPseudoTest) ++{ ++ BOOLEAN bRet=_FALSE; ++ u16 efuse_addr=*pAddr; ++ u8 badworden=0; ++ u32 PgWriteSuccess=0; ++ ++ badworden = 0x0f; ++ badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pTargetPkt->word_en, pTargetPkt->data, bPseudoTest); ++ if(badworden == 0x0F) ++ { ++ // write ok ++ //RTPRINT(FEEPROM, EFUSE_PG, ("hal_EfusePgPacketWriteData ok!!\n")); ++ return _TRUE; ++ } ++ else ++ { ++ //RTPRINT(FEEPROM, EFUSE_PG, ("hal_EfusePgPacketWriteData Fail!!\n")); ++ //reorganize other pg packet ++ ++ PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest); ++ ++ if(!PgWriteSuccess) ++ return _FALSE; ++ else ++ return _TRUE; ++ } ++ ++ return bRet; ++} ++ ++static BOOLEAN ++hal_EfusePgPacketWriteHeader( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN u16 *pAddr, ++ IN PPGPKT_STRUCT pTargetPkt, ++ IN BOOLEAN bPseudoTest) ++{ ++ BOOLEAN bRet=_FALSE; ++ ++ if(pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE) ++ { ++ bRet = hal_EfusePgPacketWrite2ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt, bPseudoTest); ++ } ++ else ++ { ++ bRet = hal_EfusePgPacketWrite1ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt, bPseudoTest); ++ } ++ ++ return bRet; ++} ++ ++static BOOLEAN ++wordEnMatched( ++ IN PPGPKT_STRUCT pTargetPkt, ++ IN PPGPKT_STRUCT pCurPkt, ++ IN u8 *pWden ++) ++{ ++ u8 match_word_en = 0x0F; // default all words are disabled ++ u8 i; ++ ++ // check if the same words are enabled both target and current PG packet ++ if( ((pTargetPkt->word_en & BIT0) == 0) && ++ ((pCurPkt->word_en & BIT0) == 0) ) ++ { ++ match_word_en &= ~BIT0; // enable word 0 ++ } ++ if( ((pTargetPkt->word_en & BIT1) == 0) && ++ ((pCurPkt->word_en & BIT1) == 0) ) ++ { ++ match_word_en &= ~BIT1; // enable word 1 ++ } ++ if( ((pTargetPkt->word_en & BIT2) == 0) && ++ ((pCurPkt->word_en & BIT2) == 0) ) ++ { ++ match_word_en &= ~BIT2; // enable word 2 ++ } ++ if( ((pTargetPkt->word_en & BIT3) == 0) && ++ ((pCurPkt->word_en & BIT3) == 0) ) ++ { ++ match_word_en &= ~BIT3; // enable word 3 ++ } ++ ++ *pWden = match_word_en; ++ ++ if(match_word_en != 0xf) ++ return _TRUE; ++ else ++ return _FALSE; ++} ++ ++static BOOLEAN ++hal_EfuseCheckIfDatafollowed( ++ IN PADAPTER pAdapter, ++ IN u8 word_cnts, ++ IN u16 startAddr, ++ IN BOOLEAN bPseudoTest ++ ) ++{ ++ BOOLEAN bRet=_FALSE; ++ u8 i, efuse_data; ++ ++ for(i=0; i<(word_cnts*2) ; i++) ++ { ++ if(efuse_OneByteRead(pAdapter, (startAddr+i) ,&efuse_data, bPseudoTest)&&(efuse_data != 0xFF)) ++ bRet = _TRUE; ++ } ++ ++ return bRet; ++} ++ ++static BOOLEAN ++hal_EfusePartialWriteCheck( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN u16 *pAddr, ++ IN PPGPKT_STRUCT pTargetPkt, ++ IN BOOLEAN bPseudoTest ++ ) ++{ ++ BOOLEAN bRet=_FALSE; ++ u8 i, efuse_data=0, cur_header=0; ++ u8 new_wden=0, matched_wden=0, badworden=0; ++ u16 startAddr=0, efuse_max_available_len=0, efuse_max=0; ++ PGPKT_STRUCT curPkt; ++ ++ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (PVOID)&efuse_max_available_len, bPseudoTest); ++ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_REAL_CONTENT_LEN, (PVOID)&efuse_max, bPseudoTest); ++ ++ if(efuseType == EFUSE_WIFI) ++ { ++ if(bPseudoTest) ++ { ++ startAddr = (u16)(fakeEfuseUsedBytes%EFUSE_REAL_CONTENT_LEN); ++ } ++ else ++ { ++ rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&startAddr); ++ startAddr%=EFUSE_REAL_CONTENT_LEN; ++ } ++ } ++ else ++ { ++ if(bPseudoTest) ++ { ++ startAddr = (u16)(fakeBTEfuseUsedBytes%EFUSE_REAL_CONTENT_LEN); ++ } ++ else ++ { ++ startAddr = (u16)(BTEfuseUsedBytes%EFUSE_REAL_CONTENT_LEN); ++ } ++ } ++ //RTPRINT(FEEPROM, EFUSE_PG, ("hal_EfusePartialWriteCheck(), startAddr=%d\n", startAddr)); ++ ++ while(1) ++ { ++ if(startAddr >= efuse_max_available_len) ++ { ++ bRet = _FALSE; ++ break; ++ } ++ ++ if(efuse_OneByteRead(pAdapter, startAddr, &efuse_data, bPseudoTest) && (efuse_data!=0xFF)) ++ { ++ if(EXT_HEADER(efuse_data)) ++ { ++ cur_header = efuse_data; ++ startAddr++; ++ efuse_OneByteRead(pAdapter, startAddr, &efuse_data, bPseudoTest); ++ if(ALL_WORDS_DISABLED(efuse_data)) ++ { ++ //RTPRINT(FEEPROM, EFUSE_PG, ("Error condition, all words disabled")); ++ bRet = _FALSE; ++ break; ++ } ++ else ++ { ++ curPkt.offset = ((cur_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); ++ curPkt.word_en = efuse_data & 0x0F; ++ } ++ } ++ else ++ { ++ cur_header = efuse_data; ++ curPkt.offset = (cur_header>>4) & 0x0F; ++ curPkt.word_en = cur_header & 0x0F; ++ } ++ ++ curPkt.word_cnts = Efuse_CalculateWordCnts(curPkt.word_en); ++ // if same header is found but no data followed ++ // write some part of data followed by the header. ++ if( (curPkt.offset == pTargetPkt->offset) && ++ (!hal_EfuseCheckIfDatafollowed(pAdapter, curPkt.word_cnts, startAddr+1, bPseudoTest)) && ++ wordEnMatched(pTargetPkt, &curPkt, &matched_wden) ) ++ { ++ //RTPRINT(FEEPROM, EFUSE_PG, ("Need to partial write data by the previous wrote header\n")); ++ // Here to write partial data ++ badworden = Efuse_WordEnableDataWrite(pAdapter, startAddr+1, matched_wden, pTargetPkt->data, bPseudoTest); ++ if(badworden != 0x0F) ++ { ++ u32 PgWriteSuccess=0; ++ // if write fail on some words, write these bad words again ++ ++ PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest); ++ ++ if(!PgWriteSuccess) ++ { ++ bRet = _FALSE; // write fail, return ++ break; ++ } ++ } ++ // partial write ok, update the target packet for later use ++ for(i=0; i<4; i++) ++ { ++ if((matched_wden & (0x1<word_en |= (0x1<word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); ++ } ++ // read from next header ++ startAddr = startAddr + (curPkt.word_cnts*2) +1; ++ } ++ else ++ { ++ // not used header, 0xff ++ *pAddr = startAddr; ++ //RTPRINT(FEEPROM, EFUSE_PG, ("Started from unused header offset=%d\n", startAddr)); ++ bRet = _TRUE; ++ break; ++ } ++ } ++ return bRet; ++} ++ ++static BOOLEAN ++hal_EfusePgCheckAvailableAddr( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN BOOLEAN bPseudoTest ++ ) ++{ ++ u16 efuse_max_available_len=0; ++ ++ //Change to check TYPE_EFUSE_MAP_LEN ,beacuse 8188E raw 256,logic map over 256. ++ EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&efuse_max_available_len, _FALSE); ++ ++ //EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&efuse_max_available_len, bPseudoTest); ++ //RTPRINT(FEEPROM, EFUSE_PG, ("efuse_max_available_len = %d\n", efuse_max_available_len)); ++ ++ if(Efuse_GetCurrentSize(pAdapter, efuseType, bPseudoTest) >= efuse_max_available_len) ++ { ++ //RTPRINT(FEEPROM, EFUSE_PG, ("hal_EfusePgCheckAvailableAddr error!!\n")); ++ return _FALSE; ++ } ++ return _TRUE; ++} ++ ++static VOID ++hal_EfuseConstructPGPkt( ++ IN u8 offset, ++ IN u8 word_en, ++ IN u8 *pData, ++ IN PPGPKT_STRUCT pTargetPkt ++ ++) ++{ ++ _rtw_memset((PVOID)pTargetPkt->data, 0xFF, sizeof(u8)*8); ++ pTargetPkt->offset = offset; ++ pTargetPkt->word_en= word_en; ++ efuse_WordEnableDataRead(word_en, pData, pTargetPkt->data); ++ pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); ++ ++ //RTPRINT(FEEPROM, EFUSE_PG, ("hal_EfuseConstructPGPkt(), targetPkt, offset=%d, word_en=0x%x, word_cnts=%d\n", pTargetPkt->offset, pTargetPkt->word_en, pTargetPkt->word_cnts)); ++} ++ ++static BOOLEAN ++hal_EfusePgPacketWrite_BT( ++ IN PADAPTER pAdapter, ++ IN u8 offset, ++ IN u8 word_en, ++ IN u8 *pData, ++ IN BOOLEAN bPseudoTest ++ ) ++{ ++ PGPKT_STRUCT targetPkt; ++ u16 startAddr=0; ++ u8 efuseType=EFUSE_BT; ++ ++ if(!hal_EfusePgCheckAvailableAddr(pAdapter, efuseType, bPseudoTest)) ++ return _FALSE; ++ ++ hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt); ++ ++ if(!hal_EfusePartialWriteCheck(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) ++ return _FALSE; ++ ++ if(!hal_EfusePgPacketWriteHeader(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) ++ return _FALSE; ++ ++ if(!hal_EfusePgPacketWriteData(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) ++ return _FALSE; ++ ++ return _TRUE; ++} ++ ++static BOOLEAN ++hal_EfusePgPacketWrite_8188e( ++ IN PADAPTER pAdapter, ++ IN u8 offset, ++ IN u8 word_en, ++ IN u8 *pData, ++ IN BOOLEAN bPseudoTest ++ ) ++{ ++ PGPKT_STRUCT targetPkt; ++ u16 startAddr=0; ++ u8 efuseType=EFUSE_WIFI; ++ ++ if(!hal_EfusePgCheckAvailableAddr(pAdapter, efuseType, bPseudoTest)) ++ return _FALSE; ++ ++ hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt); ++ ++ if(!hal_EfusePartialWriteCheck(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) ++ return _FALSE; ++ ++ if(!hal_EfusePgPacketWriteHeader(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) ++ return _FALSE; ++ ++ if(!hal_EfusePgPacketWriteData(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) ++ return _FALSE; ++ ++ return _TRUE; ++} ++ ++ ++static int ++Hal_EfusePgPacketWrite_Pseudo(IN PADAPTER pAdapter, ++ IN u8 offset, ++ IN u8 word_en, ++ IN u8 *data, ++ IN BOOLEAN bPseudoTest) ++{ ++ int ret; ++ ++ ret = hal_EfusePgPacketWrite_8188e(pAdapter, offset, word_en, data, bPseudoTest); ++ ++ return ret; ++} ++ ++static int ++Hal_EfusePgPacketWrite(IN PADAPTER pAdapter, ++ IN u8 offset, ++ IN u8 word_en, ++ IN u8 *data, ++ IN BOOLEAN bPseudoTest) ++{ ++ int ret=0; ++ ret = hal_EfusePgPacketWrite_8188e(pAdapter, offset, word_en, data, bPseudoTest); ++ ++ ++ return ret; ++} ++ ++static int ++rtl8188e_Efuse_PgPacketWrite(IN PADAPTER pAdapter, ++ IN u8 offset, ++ IN u8 word_en, ++ IN u8 *data, ++ IN BOOLEAN bPseudoTest) ++{ ++ int ret; ++ ++ if(bPseudoTest) ++ { ++ ret = Hal_EfusePgPacketWrite_Pseudo(pAdapter, offset, word_en, data, bPseudoTest); ++ } ++ else ++ { ++ ret = Hal_EfusePgPacketWrite(pAdapter, offset, word_en, data, bPseudoTest); ++ } ++ return ret; ++} ++ ++static HAL_VERSION ++ReadChipVersion8188E( ++ IN PADAPTER padapter ++ ) ++{ ++ u32 value32; ++ HAL_VERSION ChipVersion; ++ HAL_DATA_TYPE *pHalData; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ value32 = rtw_read32(padapter, REG_SYS_CFG); ++ ChipVersion.ICType = CHIP_8188E ; ++ ChipVersion.ChipType = ((value32 & RTL_ID) ? TEST_CHIP : NORMAL_CHIP); ++ ++ ChipVersion.RFType = RF_TYPE_1T1R; ++ ChipVersion.VendorType = ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : CHIP_VENDOR_TSMC); ++ ChipVersion.CUTVersion = (value32 & CHIP_VER_RTL_MASK)>>CHIP_VER_RTL_SHIFT; // IC version (CUT) ++ ++ // For regulator mode. by tynli. 2011.01.14 ++ pHalData->RegulatorMode = ((value32 & TRP_BT_EN) ? RT_LDO_REGULATOR : RT_SWITCHING_REGULATOR); ++ ++ ChipVersion.ROMVer = 0; // ROM code version. ++ pHalData->MultiFunc = RT_MULTI_FUNC_NONE; ++ ++ ++//#if DBG ++#if 1 ++ dump_chip_info(ChipVersion); ++#endif ++ ++ pHalData->VersionID = ChipVersion; ++ ++ if (IS_1T2R(ChipVersion)){ ++ pHalData->rf_type = RF_1T2R; ++ pHalData->NumTotalRFPath = 2; ++ } ++ else if (IS_2T2R(ChipVersion)){ ++ pHalData->rf_type = RF_2T2R; ++ pHalData->NumTotalRFPath = 2; ++ } ++ else{ ++ pHalData->rf_type = RF_1T1R; ++ pHalData->NumTotalRFPath = 1; ++ } ++ ++ MSG_8192C("RF_Type is %x!!\n", pHalData->rf_type); ++ ++ return ChipVersion; ++} ++ ++static void rtl8188e_read_chip_version(PADAPTER padapter) ++{ ++ ReadChipVersion8188E(padapter); ++} ++void rtl8188e_GetHalODMVar( ++ PADAPTER Adapter, ++ HAL_ODM_VARIABLE eVariable, ++ PVOID pValue1, ++ BOOLEAN bSet) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T podmpriv = &pHalData->odmpriv; ++ switch(eVariable){ ++ case HAL_ODM_STA_INFO: ++ break; ++ default: ++ break; ++ } ++} ++void rtl8188e_SetHalODMVar( ++ PADAPTER Adapter, ++ HAL_ODM_VARIABLE eVariable, ++ PVOID pValue1, ++ BOOLEAN bSet) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T podmpriv = &pHalData->odmpriv; ++ //_irqL irqL; ++ switch(eVariable){ ++ case HAL_ODM_STA_INFO: ++ { ++ struct sta_info *psta = (struct sta_info *)pValue1; ++ if(bSet){ ++ DBG_8192C("### Set STA_(%d) info\n",psta->mac_id); ++ ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS,psta->mac_id,psta); ++ #if(RATE_ADAPTIVE_SUPPORT==1) ++ ODM_RAInfo_Init(podmpriv,psta->mac_id); ++ #endif ++ } ++ else{ ++ DBG_8192C("### Clean STA_(%d) info\n",psta->mac_id); ++ //_enter_critical_bh(&pHalData->odm_stainfo_lock, &irqL); ++ ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS,psta->mac_id,NULL); ++ ++ //_exit_critical_bh(&pHalData->odm_stainfo_lock, &irqL); ++ } ++ } ++ break; ++ case HAL_ODM_P2P_STATE: ++ ODM_CmnInfoUpdate(podmpriv,ODM_CMNINFO_WIFI_DIRECT,bSet); ++ break; ++ case HAL_ODM_WIFI_DISPLAY_STATE: ++ ODM_CmnInfoUpdate(podmpriv,ODM_CMNINFO_WIFI_DISPLAY,bSet); ++ break; ++ default: ++ break; ++ } ++} ++ ++void rtl8188e_start_thread(_adapter *padapter) ++{ ++#ifdef CONFIG_SDIO_HCI ++#ifndef CONFIG_SDIO_TX_TASKLET ++ struct xmit_priv *xmitpriv = &padapter->xmitpriv; ++ ++ xmitpriv->SdioXmitThread = kthread_run(rtl8188es_xmit_thread, padapter, "RTWHALXT"); ++ if (IS_ERR(xmitpriv->SdioXmitThread)) ++ { ++ RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("%s: start rtl8188es_xmit_thread FAIL!!\n", __FUNCTION__)); ++ } ++#endif ++#endif ++} ++ ++void rtl8188e_stop_thread(_adapter *padapter) ++{ ++#ifdef CONFIG_SDIO_HCI ++#ifndef CONFIG_SDIO_TX_TASKLET ++ struct xmit_priv *xmitpriv = &padapter->xmitpriv; ++ ++ // stop xmit_buf_thread ++ if (xmitpriv->SdioXmitThread ) { ++ _rtw_up_sema(&xmitpriv->SdioXmitSema); ++ _rtw_down_sema(&xmitpriv->SdioXmitTerminateSema); ++ xmitpriv->SdioXmitThread = 0; ++ } ++#endif ++#endif ++} ++void hal_notch_filter_8188e(_adapter *adapter, bool enable) ++{ ++ if (enable) { ++ DBG_871X("Enable notch filter\n"); ++ rtw_write8(adapter, rOFDM0_RxDSP+1, rtw_read8(adapter, rOFDM0_RxDSP+1) | BIT1); ++ } else { ++ DBG_871X("Disable notch filter\n"); ++ rtw_write8(adapter, rOFDM0_RxDSP+1, rtw_read8(adapter, rOFDM0_RxDSP+1) & ~BIT1); ++ } ++} ++void rtl8188e_set_hal_ops(struct hal_ops *pHalFunc) ++{ ++ pHalFunc->free_hal_data = &rtl8188e_free_hal_data; ++ ++ pHalFunc->dm_init = &rtl8188e_init_dm_priv; ++ pHalFunc->dm_deinit = &rtl8188e_deinit_dm_priv; ++ ++ pHalFunc->read_chip_version = &rtl8188e_read_chip_version; ++ ++ pHalFunc->set_bwmode_handler = &PHY_SetBWMode8188E; ++ pHalFunc->set_channel_handler = &PHY_SwChnl8188E; ++ ++ pHalFunc->hal_dm_watchdog = &rtl8188e_HalDmWatchDog; ++ ++ pHalFunc->Add_RateATid = &rtl8188e_Add_RateATid; ++ ++ pHalFunc->run_thread= &rtl8188e_start_thread; ++ pHalFunc->cancel_thread= &rtl8188e_stop_thread; ++ ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ pHalFunc->AntDivBeforeLinkHandler = &AntDivBeforeLink8188E; ++ pHalFunc->AntDivCompareHandler = &AntDivCompare8188E; ++#endif ++ ++ pHalFunc->read_bbreg = &rtl8188e_PHY_QueryBBReg; ++ pHalFunc->write_bbreg = &rtl8188e_PHY_SetBBReg; ++ pHalFunc->read_rfreg = &rtl8188e_PHY_QueryRFReg; ++ pHalFunc->write_rfreg = &rtl8188e_PHY_SetRFReg; ++ ++ ++ // Efuse related function ++ pHalFunc->EfusePowerSwitch = &rtl8188e_EfusePowerSwitch; ++ pHalFunc->ReadEFuse = &rtl8188e_ReadEFuse; ++ pHalFunc->EFUSEGetEfuseDefinition = &rtl8188e_EFUSE_GetEfuseDefinition; ++ pHalFunc->EfuseGetCurrentSize = &rtl8188e_EfuseGetCurrentSize; ++ pHalFunc->Efuse_PgPacketRead = &rtl8188e_Efuse_PgPacketRead; ++ pHalFunc->Efuse_PgPacketWrite = &rtl8188e_Efuse_PgPacketWrite; ++ pHalFunc->Efuse_WordEnableDataWrite = &rtl8188e_Efuse_WordEnableDataWrite; ++ ++#ifdef DBG_CONFIG_ERROR_DETECT ++ pHalFunc->sreset_init_value = &sreset_init_value; ++ pHalFunc->sreset_reset_value = &sreset_reset_value; ++ pHalFunc->silentreset = &sreset_reset; ++ pHalFunc->sreset_xmit_status_check = &rtl8188e_sreset_xmit_status_check; ++ pHalFunc->sreset_linked_status_check = &rtl8188e_sreset_linked_status_check; ++ pHalFunc->sreset_get_wifi_status = &sreset_get_wifi_status; ++ pHalFunc->sreset_inprogress= &sreset_inprogress; ++#endif //DBG_CONFIG_ERROR_DETECT ++ ++ pHalFunc->GetHalODMVarHandler = &rtl8188e_GetHalODMVar; ++ pHalFunc->SetHalODMVarHandler = &rtl8188e_SetHalODMVar; ++ ++#ifdef CONFIG_XMIT_THREAD_MODE ++ pHalFunc->xmit_thread_handler = &hal_xmit_handler; ++#endif ++ ++#ifdef CONFIG_IOL ++ pHalFunc->IOL_exec_cmds_sync = &rtl8188e_IOL_exec_cmds_sync; ++#endif ++ ++ pHalFunc->hal_notch_filter = &hal_notch_filter_8188e; ++ ++} ++ ++u8 GetEEPROMSize8188E(PADAPTER padapter) ++{ ++ u8 size = 0; ++ u32 cr; ++ ++ cr = rtw_read16(padapter, REG_9346CR); ++ // 6: EEPROM used is 93C46, 4: boot from E-Fuse. ++ size = (cr & BOOT_FROM_EEPROM) ? 6 : 4; ++ ++ MSG_8192C("EEPROM type is %s\n", size==4 ? "E-FUSE" : "93C46"); ++ ++ return size; ++} ++ ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_PCI_HCI) ++//------------------------------------------------------------------------- ++// ++// LLT R/W/Init function ++// ++//------------------------------------------------------------------------- ++s32 _LLTWrite(PADAPTER padapter, u32 address, u32 data) ++{ ++ s32 status = _SUCCESS; ++ s32 count = 0; ++ u32 value = _LLT_INIT_ADDR(address) | _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS); ++ u16 LLTReg = REG_LLT_INIT; ++ ++ ++ rtw_write32(padapter, LLTReg, value); ++ ++ //polling ++ do { ++ value = rtw_read32(padapter, LLTReg); ++ if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value)) { ++ break; ++ } ++ ++ if (count > POLLING_LLT_THRESHOLD) { ++ RT_TRACE(_module_hal_init_c_, _drv_err_, ("Failed to polling write LLT done at address %d!\n", address)); ++ status = _FAIL; ++ break; ++ } ++ } while (count++); ++ ++ return status; ++} ++ ++u8 _LLTRead(PADAPTER padapter, u32 address) ++{ ++ s32 count = 0; ++ u32 value = _LLT_INIT_ADDR(address) | _LLT_OP(_LLT_READ_ACCESS); ++ u16 LLTReg = REG_LLT_INIT; ++ ++ ++ rtw_write32(padapter, LLTReg, value); ++ ++ //polling and get value ++ do { ++ value = rtw_read32(padapter, LLTReg); ++ if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value)) { ++ return (u8)value; ++ } ++ ++ if (count > POLLING_LLT_THRESHOLD) { ++ RT_TRACE(_module_hal_init_c_, _drv_err_, ("Failed to polling read LLT done at address %d!\n", address)); ++ break; ++ } ++ } while (count++); ++ ++ return 0xFF; ++} ++void Read_LLT_Tab(PADAPTER padapter) ++{ ++ u32 addr,next_addr; ++ printk("############### %s ###################\n",__FUNCTION__); ++ for(addr=0;addr<176;addr++) ++ { ++ next_addr = _LLTRead(padapter,addr); ++ printk("%d->",next_addr); ++ if(((addr+1) %8) ==0) ++ printk("\n"); ++ } ++ printk("\n##################################\n"); ++ ++} ++ ++s32 InitLLTTable(PADAPTER padapter, u8 txpktbuf_bndy) ++{ ++ s32 status = _FAIL; ++ u32 i; ++ u32 Last_Entry_Of_TxPktBuf = LAST_ENTRY_OF_TX_PKT_BUFFER;// 176, 22k ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++#if defined(CONFIG_IOL_LLT) ++ if(rtw_IOL_applied(padapter)) ++ { ++ status = iol_InitLLTTable(padapter, txpktbuf_bndy); ++ } ++ else ++#endif ++ { ++ for (i = 0; i < (txpktbuf_bndy - 1); i++) { ++ status = _LLTWrite(padapter, i, i + 1); ++ if (_SUCCESS != status) { ++ return status; ++ } ++ } ++ ++ // end of list ++ status = _LLTWrite(padapter, (txpktbuf_bndy - 1), 0xFF); ++ if (_SUCCESS != status) { ++ return status; ++ } ++ ++ // Make the other pages as ring buffer ++ // This ring buffer is used as beacon buffer if we config this MAC as two MAC transfer. ++ // Otherwise used as local loopback buffer. ++ for (i = txpktbuf_bndy; i < Last_Entry_Of_TxPktBuf; i++) { ++ status = _LLTWrite(padapter, i, (i + 1)); ++ if (_SUCCESS != status) { ++ return status; ++ } ++ } ++ ++ // Let last entry point to the start entry of ring buffer ++ status = _LLTWrite(padapter, Last_Entry_Of_TxPktBuf, txpktbuf_bndy); ++ if (_SUCCESS != status) { ++ return status; ++ } ++ } ++ ++ return status; ++} ++#endif ++ ++ ++void ++Hal_InitPGData88E(PADAPTER padapter) ++{ ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++// HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ u32 i; ++ u16 value16; ++ ++ if(_FALSE == pEEPROM->bautoload_fail_flag) ++ { // autoload OK. ++ if (is_boot_from_eeprom(padapter)) ++ { ++ // Read all Content from EEPROM or EFUSE. ++ for(i = 0; i < HWSET_MAX_SIZE_88E; i += 2) ++ { ++// value16 = EF2Byte(ReadEEprom(pAdapter, (u2Byte) (i>>1))); ++// *((u16*)(&PROMContent[i])) = value16; ++ } ++ } ++ else ++ { ++ // Read EFUSE real map to shadow. ++ EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, _FALSE); ++ } ++ } ++ else ++ {//autoload fail ++ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("AutoLoad Fail reported from CR9346!!\n")); ++// pHalData->AutoloadFailFlag = _TRUE; ++ //update to default value 0xFF ++ if (!is_boot_from_eeprom(padapter)) ++ EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, _FALSE); ++ } ++} ++ ++void ++Hal_EfuseParseIDCode88E( ++ IN PADAPTER padapter, ++ IN u8 *hwinfo ++ ) ++{ ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++// HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ u16 EEPROMId; ++ ++ ++ // Checl 0x8129 again for making sure autoload status!! ++ EEPROMId = le16_to_cpu(*((u16*)hwinfo)); ++ if (EEPROMId != RTL_EEPROM_ID) ++ { ++ DBG_8192C("EEPROM ID(%#x) is invalid!!\n", EEPROMId); ++ pEEPROM->bautoload_fail_flag = _TRUE; ++ } ++ else ++ { ++ pEEPROM->bautoload_fail_flag = _FALSE; ++ } ++ ++ DBG_871X("EEPROM ID=0x%04x\n", EEPROMId); ++} ++ ++static void ++Hal_EEValueCheck( ++ IN u8 EEType, ++ IN PVOID pInValue, ++ OUT PVOID pOutValue ++ ) ++{ ++ switch(EEType) ++ { ++ case EETYPE_TX_PWR: ++ { ++ u8 *pIn, *pOut; ++ pIn = (u8*)pInValue; ++ pOut = (u8*)pOutValue; ++ if(*pIn >= 0 && *pIn <= 63) ++ { ++ *pOut = *pIn; ++ } ++ else ++ { ++ RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("EETYPE_TX_PWR, value=%d is invalid, set to default=0x%x\n", ++ *pIn, EEPROM_Default_TxPowerLevel)); ++ *pOut = EEPROM_Default_TxPowerLevel; ++ } ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static void ++Hal_ReadPowerValueFromPROM_8188E( ++ IN PADAPTER padapter, ++ IN PTxPowerInfo24G pwrInfo24G, ++ IN u8* PROMContent, ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++ u32 rfPath, eeAddr=EEPROM_TX_PWR_INX_88E, group,TxCount=0; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ _rtw_memset(pwrInfo24G, 0, sizeof(TxPowerInfo24G)); ++ ++ if(AutoLoadFail) ++ { ++ for(rfPath = 0 ; rfPath < pHalData->NumTotalRFPath ; rfPath++) ++ { ++ //2.4G default value ++ for(group = 0 ; group < MAX_CHNL_GROUP_24G; group++) ++ { ++ pwrInfo24G->IndexCCK_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; ++ pwrInfo24G->IndexBW40_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; ++ } ++ for(TxCount=0;TxCountBW20_Diff[rfPath][0] = EEPROM_DEFAULT_24G_HT20_DIFF; ++ pwrInfo24G->OFDM_Diff[rfPath][0] = EEPROM_DEFAULT_24G_OFDM_DIFF; ++ } ++ else ++ { ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ pwrInfo24G->BW40_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ pwrInfo24G->CCK_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ } ++ } ++ ++ ++ } ++ ++ //pHalData->bNOPG = TRUE; ++ return; ++ } ++ ++ for(rfPath = 0 ; rfPath < pHalData->NumTotalRFPath ; rfPath++) ++ { ++ //2.4G default value ++ for(group = 0 ; group < MAX_CHNL_GROUP_24G; group++) ++ { ++ //printk(" IndexCCK_Base rfPath:%d group:%d,eeAddr:0x%02x ",rfPath,group,eeAddr); ++ pwrInfo24G->IndexCCK_Base[rfPath][group] = PROMContent[eeAddr++]; ++ //printk(" IndexCCK_Base:%02x \n",pwrInfo24G->IndexCCK_Base[rfPath][group] ); ++ if(pwrInfo24G->IndexCCK_Base[rfPath][group] == 0xFF) ++ { ++ pwrInfo24G->IndexCCK_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; ++// pHalData->bNOPG = TRUE; ++ } ++ } ++ for(group = 0 ; group < MAX_CHNL_GROUP_24G-1; group++) ++ { ++ //printk(" IndexBW40_Base rfPath:%d group:%d,eeAddr:0x%02x ",rfPath,group,eeAddr); ++ pwrInfo24G->IndexBW40_Base[rfPath][group] = PROMContent[eeAddr++]; ++ //printk(" IndexBW40_Base: %02x \n",pwrInfo24G->IndexBW40_Base[rfPath][group] ); ++ if(pwrInfo24G->IndexBW40_Base[rfPath][group] == 0xFF) ++ pwrInfo24G->IndexBW40_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; ++ } ++ for(TxCount=0;TxCountBW40_Diff[rfPath][TxCount] = 0; ++ if(PROMContent[eeAddr] == 0xFF) ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_24G_HT20_DIFF; ++ else ++ { ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4; ++ if(pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT3) //4bit sign number to 8 bit sign number ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ ++ if(PROMContent[eeAddr] == 0xFF) ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_24G_OFDM_DIFF; ++ else ++ { ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f); ++ if(pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT3) //4bit sign number to 8 bit sign number ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ pwrInfo24G->CCK_Diff[rfPath][TxCount] = 0; ++ eeAddr++; ++ } ++ else ++ { ++ if(PROMContent[eeAddr] == 0xFF) ++ pwrInfo24G->BW40_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ else ++ { ++ pwrInfo24G->BW40_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4; ++ if(pwrInfo24G->BW40_Diff[rfPath][TxCount] & BIT3) //4bit sign number to 8 bit sign number ++ pwrInfo24G->BW40_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ ++ if(PROMContent[eeAddr] == 0xFF) ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ else ++ { ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f); ++ if(pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT3) //4bit sign number to 8 bit sign number ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ eeAddr++; ++ ++ if(PROMContent[eeAddr] == 0xFF) ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ else ++ { ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4; ++ if(pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT3) //4bit sign number to 8 bit sign number ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ ++ if(PROMContent[eeAddr] == 0xFF) ++ pwrInfo24G->CCK_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ else ++ { ++ pwrInfo24G->CCK_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f); ++ if(pwrInfo24G->CCK_Diff[rfPath][TxCount] & BIT3) //4bit sign number to 8 bit sign number ++ pwrInfo24G->CCK_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ eeAddr++; ++ } ++ } ++ ++ } ++ ++ ++} ++ ++static u8 ++Hal_GetChnlGroup( ++ IN u8 chnl ++ ) ++{ ++ u8 group=0; ++ ++ if (chnl < 3) // Cjanel 1-3 ++ group = 0; ++ else if (chnl < 9) // Channel 4-9 ++ group = 1; ++ else // Channel 10-14 ++ group = 2; ++ ++ return group; ++} ++static u8 ++Hal_GetChnlGroup88E( ++ IN u8 chnl, ++ OUT u8* pGroup ++ ) ++{ ++ u8 bIn24G=_TRUE; ++ ++ if(chnl<=14) ++ { ++ bIn24G=_TRUE; ++ ++ if (chnl < 3) // Chanel 1-2 ++ *pGroup = 0; ++ else if (chnl < 6) // Channel 3-5 ++ *pGroup = 1; ++ else if(chnl <9) // Channel 6-8 ++ *pGroup = 2; ++ else if(chnl <12) // Channel 9-11 ++ *pGroup = 3; ++ else if(chnl <14) // Channel 12-13 ++ *pGroup = 4; ++ else if(chnl ==14) // Channel 14 ++ *pGroup = 5; ++ else ++ { ++ //RT_TRACE(COMP_EFUSE,DBG_LOUD,("==>Hal_GetChnlGroup88E in 2.4 G, but Channel %d in Group not found \n",chnl)); ++ } ++ } ++ else ++ { ++ bIn24G=_FALSE; ++ ++ if (chnl <=40) ++ *pGroup = 0; ++ else if (chnl <=48) ++ *pGroup = 1; ++ else if(chnl <=56) ++ *pGroup = 2; ++ else if(chnl <=64) ++ *pGroup = 3; ++ else if(chnl <=104) ++ *pGroup = 4; ++ else if(chnl <=112) ++ *pGroup = 5; ++ else if(chnl <=120) ++ *pGroup = 5; ++ else if(chnl <=128) ++ *pGroup = 6; ++ else if(chnl <=136) ++ *pGroup = 7; ++ else if(chnl <=144) ++ *pGroup = 8; ++ else if(chnl <=153) ++ *pGroup = 9; ++ else if(chnl <=161) ++ *pGroup = 10; ++ else if(chnl <=177) ++ *pGroup = 11; ++ else ++ { ++ //RT_TRACE(COMP_EFUSE,DBG_LOUD,("==>Hal_GetChnlGroup88E in 5G, but Channel %d in Group not found \n",chnl)); ++ } ++ ++ } ++ //RT_TRACE(COMP_EFUSE,DBG_LOUD,("<==Hal_GetChnlGroup88E, Channel = %d, bIn24G =%d,\n",chnl,bIn24G)); ++ return bIn24G; ++} ++ ++void Hal_ReadPowerSavingMode88E( ++ PADAPTER padapter, ++ IN u8* hwinfo, ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); ++ u8 tmpvalue; ++ ++ if(AutoLoadFail){ ++ pwrctl->bHWPowerdown = _FALSE; ++ pwrctl->bSupportRemoteWakeup = _FALSE; ++ } ++ else { ++ ++ //hw power down mode selection , 0:rf-off / 1:power down ++ ++ if(padapter->registrypriv.hwpdn_mode==2) ++ pwrctl->bHWPowerdown = (hwinfo[EEPROM_RF_FEATURE_OPTION_88E] & BIT4)?_TRUE:_FALSE; ++ else ++ pwrctl->bHWPowerdown = padapter->registrypriv.hwpdn_mode; ++ ++ pwrctl->bHWPwrPindetect = padapter->registrypriv.hwpwrp_detect; ++ ++ // decide hw if support remote wakeup function ++ // if hw supported, 8051 (SIE) will generate WeakUP signal( D+/D- toggle) when autoresume ++#ifdef CONFIG_USB_HCI ++ pwrctl->bSupportRemoteWakeup = (hwinfo[EEPROM_USB_OPTIONAL_FUNCTION0] & BIT1)?_TRUE :_FALSE; ++#endif //CONFIG_USB_HCI ++ ++ //if(SUPPORT_HW_RADIO_DETECT(Adapter)) ++ //Adapter->registrypriv.usbss_enable = pwrctl->bSupportRemoteWakeup ; ++ ++ DBG_8192C("%s...bHWPwrPindetect(%x)-bHWPowerdown(%x) ,bSupportRemoteWakeup(%x)\n",__FUNCTION__, ++ pwrctl->bHWPwrPindetect, pwrctl->bHWPowerdown, pwrctl->bSupportRemoteWakeup); ++ ++ DBG_8192C("### PS params=> power_mgnt(%x),usbss_enable(%x) ###\n",padapter->registrypriv.power_mgnt,padapter->registrypriv.usbss_enable); ++ ++ } ++ ++} ++ ++void ++Hal_ReadTxPowerInfo88E( ++ IN PADAPTER padapter, ++ IN u8* PROMContent, ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ TxPowerInfo24G pwrInfo24G; ++ u8 rfPath, ch, group, rfPathMax=1; ++ u8 pwr, diff,bIn24G,TxCount; ++ ++ Hal_ReadPowerValueFromPROM_8188E(padapter,&pwrInfo24G, PROMContent, AutoLoadFail); ++ ++ if(!AutoLoadFail) ++ pHalData->bTXPowerDataReadFromEEPORM = TRUE; ++ ++ //for(rfPath = 0 ; rfPath < MAX_RF_PATH ; rfPath++) ++ for(rfPath = 0 ; rfPath < pHalData->NumTotalRFPath ; rfPath++) ++ { ++ for(ch = 0 ; ch < CHANNEL_MAX_NUMBER ; ch++) ++ { ++ bIn24G = Hal_GetChnlGroup88E(ch+1,&group); ++ if(bIn24G) ++ { ++ ++ pHalData->Index24G_CCK_Base[rfPath][ch]=pwrInfo24G.IndexCCK_Base[rfPath][group]; ++ ++ if(ch==(14-1)) ++ pHalData->Index24G_BW40_Base[rfPath][ch]=pwrInfo24G.IndexBW40_Base[rfPath][4]; ++ else ++ pHalData->Index24G_BW40_Base[rfPath][ch]=pwrInfo24G.IndexBW40_Base[rfPath][group]; ++ } ++ ++ if(bIn24G) ++ { ++ DBG_871X("======= Path %d, Channel %d =======\n",rfPath,ch+1 ); ++ DBG_871X("Index24G_CCK_Base[%d][%d] = 0x%x\n",rfPath,ch+1 ,pHalData->Index24G_CCK_Base[rfPath][ch]); ++ DBG_871X("Index24G_BW40_Base[%d][%d] = 0x%x\n",rfPath,ch+1 ,pHalData->Index24G_BW40_Base[rfPath][ch]); ++ } ++ } ++ ++ for(TxCount=0;TxCountCCK_24G_Diff[rfPath][TxCount]=pwrInfo24G.CCK_Diff[rfPath][TxCount]; ++ pHalData->OFDM_24G_Diff[rfPath][TxCount]=pwrInfo24G.OFDM_Diff[rfPath][TxCount]; ++ pHalData->BW20_24G_Diff[rfPath][TxCount]=pwrInfo24G.BW20_Diff[rfPath][TxCount]; ++ pHalData->BW40_24G_Diff[rfPath][TxCount]=pwrInfo24G.BW40_Diff[rfPath][TxCount]; ++#if DBG ++ DBG_871X("======= TxCount %d =======\n",TxCount ); ++ DBG_871X("CCK_24G_Diff[%d][%d]= %d\n",rfPath,TxCount,pHalData->CCK_24G_Diff[rfPath][TxCount]); ++ DBG_871X("OFDM_24G_Diff[%d][%d]= %d\n",rfPath,TxCount,pHalData->OFDM_24G_Diff[rfPath][TxCount]); ++ DBG_871X("BW20_24G_Diff[%d][%d]= %d\n",rfPath,TxCount,pHalData->BW20_24G_Diff[rfPath][TxCount]); ++ DBG_871X("BW40_24G_Diff[%d][%d]= %d\n",rfPath,TxCount,pHalData->BW40_24G_Diff[rfPath][TxCount]); ++#endif ++ } ++ } ++ ++ ++ // 2010/10/19 MH Add Regulator recognize for EU. ++ if(!AutoLoadFail) ++ { ++ struct registry_priv *registry_par = &padapter->registrypriv; ++ if( registry_par->regulatory_tid == 0xff){ ++ if(PROMContent[EEPROM_RF_BOARD_OPTION_88E] == 0xFF) ++ pHalData->EEPROMRegulatory = (EEPROM_DEFAULT_BOARD_OPTION&0x7); //bit0~2 ++ else ++ pHalData->EEPROMRegulatory = (PROMContent[EEPROM_RF_BOARD_OPTION_88E]&0x7); //bit0~2 ++ }else{ ++ pHalData->EEPROMRegulatory = registry_par->regulatory_tid; ++ } ++ } ++ else ++ { ++ pHalData->EEPROMRegulatory = 0; ++ } ++ DBG_871X("EEPROMRegulatory = 0x%x\n", pHalData->EEPROMRegulatory); ++ ++} ++ ++ ++VOID ++Hal_EfuseParseXtal_8188E( ++ IN PADAPTER pAdapter, ++ IN u8* hwinfo, ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ if(!AutoLoadFail) ++ { ++ pHalData->CrystalCap = hwinfo[EEPROM_XTAL_88E]; ++ if(pHalData->CrystalCap == 0xFF) ++ pHalData->CrystalCap = EEPROM_Default_CrystalCap_88E; ++ } ++ else ++ { ++ pHalData->CrystalCap = EEPROM_Default_CrystalCap_88E; ++ } ++ DBG_871X("CrystalCap: 0x%2x\n", pHalData->CrystalCap); ++} ++ ++void ++Hal_EfuseParseBoardType88E( ++ IN PADAPTER pAdapter, ++ IN u8* hwinfo, ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ if (!AutoLoadFail) ++ pHalData->BoardType = ((hwinfo[EEPROM_RF_BOARD_OPTION_88E]&0xE0)>>5); ++ else ++ pHalData->BoardType = 0; ++ DBG_871X("Board Type: 0x%2x\n", pHalData->BoardType); ++} ++ ++void ++Hal_EfuseParseEEPROMVer88E( ++ IN PADAPTER padapter, ++ IN u8* hwinfo, ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ if(!AutoLoadFail){ ++ pHalData->EEPROMVersion = hwinfo[EEPROM_VERSION_88E]; ++ if(pHalData->EEPROMVersion == 0xFF) ++ pHalData->EEPROMVersion = EEPROM_Default_Version; ++ } ++ else{ ++ pHalData->EEPROMVersion = 1; ++ } ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Hal_EfuseParseEEPROMVer(), EEVer = %d\n", ++ pHalData->EEPROMVersion)); ++} ++ ++void ++rtl8188e_EfuseParseChnlPlan( ++ IN PADAPTER padapter, ++ IN u8* hwinfo, ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++ padapter->mlmepriv.ChannelPlan = hal_com_get_channel_plan( ++ padapter ++ , hwinfo?hwinfo[EEPROM_ChannelPlan_88E]:0xFF ++ , padapter->registrypriv.channel_plan ++ , RT_CHANNEL_DOMAIN_WORLD_WIDE_13 ++ , AutoLoadFail ++ ); ++ ++ DBG_871X("mlmepriv.ChannelPlan = 0x%02x\n", padapter->mlmepriv.ChannelPlan); ++} ++ ++void ++Hal_EfuseParseCustomerID88E( ++ IN PADAPTER padapter, ++ IN u8* hwinfo, ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ if (!AutoLoadFail) ++ { ++ pHalData->EEPROMCustomerID = hwinfo[EEPROM_CUSTOMERID_88E]; ++ //pHalData->EEPROMSubCustomerID = hwinfo[EEPROM_CUSTOMERID_88E]; ++ } ++ else ++ { ++ pHalData->EEPROMCustomerID = 0; ++ pHalData->EEPROMSubCustomerID = 0; ++ } ++ DBG_871X("EEPROM Customer ID: 0x%2x\n", pHalData->EEPROMCustomerID); ++ //DBG_871X("EEPROM SubCustomer ID: 0x%02x\n", pHalData->EEPROMSubCustomerID); ++} ++ ++ ++void ++Hal_ReadAntennaDiversity88E( ++ IN PADAPTER pAdapter, ++ IN u8* PROMContent, ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ struct registry_priv *registry_par = &pAdapter->registrypriv; ++ ++ if(!AutoLoadFail) ++ { ++ // Antenna Diversity setting. ++ if(registry_par->antdiv_cfg == 2)// 2:By EFUSE ++ { ++ pHalData->AntDivCfg = (PROMContent[EEPROM_RF_BOARD_OPTION_88E]&0x18)>>3; ++ if(PROMContent[EEPROM_RF_BOARD_OPTION_88E] == 0xFF) ++ pHalData->AntDivCfg = (EEPROM_DEFAULT_BOARD_OPTION&0x18)>>3;; ++ } ++ else ++ { ++ pHalData->AntDivCfg = registry_par->antdiv_cfg ; // 0:OFF , 1:ON, 2:By EFUSE ++ } ++ ++ if(registry_par->antdiv_type == 0)// If TRxAntDivType is AUTO in advanced setting, use EFUSE value instead. ++ { ++ pHalData->TRxAntDivType = PROMContent[EEPROM_RF_ANTENNA_OPT_88E]; ++ if (pHalData->TRxAntDivType == 0xFF) ++ pHalData->TRxAntDivType = CG_TRX_HW_ANTDIV; // For 88EE, 1Tx and 1RxCG are fixed.(1Ant, Tx and RxCG are both on aux port) ++ } ++ else{ ++ pHalData->TRxAntDivType = registry_par->antdiv_type ; ++ } ++ ++ if (pHalData->TRxAntDivType == CG_TRX_HW_ANTDIV || pHalData->TRxAntDivType == CGCS_RX_HW_ANTDIV) ++ pHalData->AntDivCfg = 1; // 0xC1[3] is ignored. ++ } ++ else ++ { ++ pHalData->AntDivCfg = 0; ++ pHalData->TRxAntDivType = pHalData->TRxAntDivType; // The value in the driver setting of device manager. ++ } ++ ++ DBG_871X("EEPROM : AntDivCfg = %x, TRxAntDivType = %x\n",pHalData->AntDivCfg, pHalData->TRxAntDivType); ++ ++ ++} ++ ++void ++Hal_ReadThermalMeter_88E( ++ IN PADAPTER Adapter, ++ IN u8* PROMContent, ++ IN BOOLEAN AutoloadFail ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u1Byte tempval; ++ ++ // ++ // ThermalMeter from EEPROM ++ // ++ if(!AutoloadFail) ++ pHalData->EEPROMThermalMeter = PROMContent[EEPROM_THERMAL_METER_88E]; ++ else ++ pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_88E; ++// pHalData->EEPROMThermalMeter = (tempval&0x1f); //[4:0] ++ ++ if(pHalData->EEPROMThermalMeter == 0xff || AutoloadFail) ++ { ++ pHalData->bAPKThermalMeterIgnore = _TRUE; ++ pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_88E; ++ } ++ ++ //pHalData->ThermalMeter[0] = pHalData->EEPROMThermalMeter; ++ DBG_871X("ThermalMeter = 0x%x\n", pHalData->EEPROMThermalMeter); ++ ++} ++ ++ ++void ++Hal_InitChannelPlan( ++ IN PADAPTER padapter ++ ) ++{ ++#if 0 ++ PMGNT_INFO pMgntInfo = &(padapter->MgntInfo); ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ if((pMgntInfo->RegChannelPlan >= RT_CHANNEL_DOMAIN_MAX) || (pHalData->EEPROMChannelPlan & EEPROM_CHANNEL_PLAN_BY_HW_MASK)) ++ { ++ pMgntInfo->ChannelPlan = hal_MapChannelPlan8192C(padapter, (pHalData->EEPROMChannelPlan & (~(EEPROM_CHANNEL_PLAN_BY_HW_MASK)))); ++ pMgntInfo->bChnlPlanFromHW = (pHalData->EEPROMChannelPlan & EEPROM_CHANNEL_PLAN_BY_HW_MASK) ? TRUE : FALSE; // User cannot change channel plan. ++ } ++ else ++ { ++ pMgntInfo->ChannelPlan = (RT_CHANNEL_DOMAIN)pMgntInfo->RegChannelPlan; ++ } ++ ++ switch(pMgntInfo->ChannelPlan) ++ { ++ case RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN: ++ { ++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(pMgntInfo); ++ ++ pDot11dInfo->bEnabled = TRUE; ++ } ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("ReadAdapterInfo8187(): Enable dot11d when RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN!\n")); ++ break; ++ ++ default: //for MacOSX compiler warning. ++ break; ++ } ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("RegChannelPlan(%d) EEPROMChannelPlan(%d)", pMgntInfo->RegChannelPlan, pHalData->EEPROMChannelPlan)); ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Mgnt ChannelPlan = %d\n" , pMgntInfo->ChannelPlan)); ++#endif ++} ++ ++BOOLEAN HalDetectPwrDownMode88E(PADAPTER Adapter) ++{ ++ u8 tmpvalue = 0; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(Adapter); ++ ++ EFUSE_ShadowRead(Adapter, 1, EEPROM_RF_FEATURE_OPTION_88E, (u32 *)&tmpvalue); ++ ++ // 2010/08/25 MH INF priority > PDN Efuse value. ++ if(tmpvalue & BIT(4) && pwrctrlpriv->reg_pdnmode) ++ { ++ pHalData->pwrdown = _TRUE; ++ } ++ else ++ { ++ pHalData->pwrdown = _FALSE; ++ } ++ ++ DBG_8192C("HalDetectPwrDownMode(): PDN=%d\n", pHalData->pwrdown); ++ ++ return pHalData->pwrdown; ++} // HalDetectPwrDownMode ++ ++#ifdef CONFIG_WOWLAN ++void Hal_DetectWoWMode(PADAPTER pAdapter) ++{ ++ adapter_to_pwrctl(pAdapter)->bSupportRemoteWakeup = _TRUE; ++ DBG_871X("%s\n", __func__); ++} ++#endif ++ ++#ifdef CONFIG_RF_GAIN_OFFSET ++void Hal_ReadRFGainOffset( ++ IN PADAPTER Adapter, ++ IN u8* PROMContent, ++ IN BOOLEAN AutoloadFail) ++{ ++ u8 buff[EFUSE_MAX_SIZE]; ++ u32 res; ++ // ++ // BB_RF Gain Offset from EEPROM ++ // ++ //res = rtw_efuse_access(Adapter, _FALSE, 0, EFUSE_MAX_SIZE, buff); ++ if(!AutoloadFail ){ ++ Adapter->eeprompriv.EEPROMRFGainOffset = PROMContent[EEPROM_RF_GAIN_OFFSET_88E]; ++ Adapter->eeprompriv.EEPROMRFGainVal=EFUSE_Read1Byte(Adapter, EEPROM_RF_GAIN_VAL_88E); ++ } ++ else{ ++ Adapter->eeprompriv.EEPROMRFGainOffset = EEPROM_Default_RFGainOffset; ++ Adapter->eeprompriv.EEPROMRFGainVal=0xff; ++ } ++ DBG_871X("EEPRORFGainOffset = 0x%02x\n", Adapter->eeprompriv.EEPROMRFGainOffset); ++} ++#endif //CONFIG_RF_GAIN_OFFSET ++ ++//==================================================================================== ++// ++// 20100209 Joseph: ++// This function is used only for 92C to set REG_BCN_CTRL(0x550) register. ++// We just reserve the value of the register in variable pHalData->RegBcnCtrlVal and then operate ++// the value of the register via atomic operation. ++// This prevents from race condition when setting this register. ++// The value of pHalData->RegBcnCtrlVal is initialized in HwConfigureRTL8192CE() function. ++// ++void SetBcnCtrlReg( ++ PADAPTER padapter, ++ u8 SetBits, ++ u8 ClearBits) ++{ ++ PHAL_DATA_TYPE pHalData; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ pHalData->RegBcnCtrlVal |= SetBits; ++ pHalData->RegBcnCtrlVal &= ~ClearBits; ++ ++#if 0 ++//#ifdef CONFIG_SDIO_HCI ++ if (pHalData->sdio_himr & (SDIO_HIMR_TXBCNOK_MSK | SDIO_HIMR_TXBCNERR_MSK)) ++ pHalData->RegBcnCtrlVal |= EN_TXBCN_RPT; ++#endif ++ ++ rtw_write8(padapter, REG_BCN_CTRL, (u8)pHalData->RegBcnCtrlVal); ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_mp.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_mp.c +new file mode 100644 +index 00000000..e755d5cd +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_mp.c +@@ -0,0 +1,1157 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTL8188E_MP_C_ ++#ifdef CONFIG_MP_INCLUDED ++ ++#include ++#include ++ ++#include ++#include ++ ++ ++s32 Hal_SetPowerTracking(PADAPTER padapter, u8 enable) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ ++ ++ if (!netif_running(padapter->pnetdev)) { ++ RT_TRACE(_module_mp_, _drv_warning_, ("SetPowerTracking! Fail: interface not opened!\n")); ++ return _FAIL; ++ } ++ ++ if (check_fwstate(&padapter->mlmepriv, WIFI_MP_STATE) == _FALSE) { ++ RT_TRACE(_module_mp_, _drv_warning_, ("SetPowerTracking! Fail: not in MP mode!\n")); ++ return _FAIL; ++ } ++ ++ if (enable) ++ { ++ pDM_Odm->RFCalibrateInfo.bTXPowerTracking = _TRUE; ++ } ++ else ++ pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit= _FALSE; ++ ++ return _SUCCESS; ++} ++ ++void Hal_GetPowerTracking(PADAPTER padapter, u8 *enable) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ ++ ++ *enable = pDM_Odm->RFCalibrateInfo.TxPowerTrackControl; ++} ++ ++static void Hal_disable_dm(PADAPTER padapter) ++{ ++ u8 v8; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ ++ ++ //3 1. disable firmware dynamic mechanism ++ // disable Power Training, Rate Adaptive ++ v8 = rtw_read8(padapter, REG_BCN_CTRL); ++ v8 &= ~EN_BCN_FUNCTION; ++ rtw_write8(padapter, REG_BCN_CTRL, v8); ++ ++ //3 2. disable driver dynamic mechanism ++ // disable Dynamic Initial Gain ++ // disable High Power ++ // disable Power Tracking ++ Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, _FALSE); ++ ++ // enable APK, LCK and IQK but disable power tracking ++ pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = _FALSE; ++ Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, _TRUE); ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: mpt_SwitchRfSetting ++ * ++ * Overview: Change RF Setting when we siwthc channel/rate/BW for MP. ++ * ++ * Input: IN PADAPTER pAdapter ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 01/08/2009 MHC Suggestion from SD3 Willis for 92S series. ++ * 01/09/2009 MHC Add CCK modification for 40MHZ. Suggestion from SD3. ++ * ++ *---------------------------------------------------------------------------*/ ++void Hal_mpt_SwitchRfSetting(PADAPTER pAdapter) ++{ ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ struct mp_priv *pmp = &pAdapter->mppriv; ++ u1Byte ChannelToSw = pmp->channel; ++ ULONG ulRateIdx = pmp->rateidx; ++ ULONG ulbandwidth = pmp->bandwidth; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++#if 0 ++ // <20120525, Kordan> Dynamic mechanism for APK, asked by Dennis. ++ pmp->MptCtx.backup0x52_RF_A = (u1Byte)PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0); ++ pmp->MptCtx.backup0x52_RF_B = (u1Byte)PHY_QueryRFReg(pAdapter, RF_PATH_B, RF_0x52, 0x000F0); ++ PHY_SetRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0, 0xD); ++ PHY_SetRFReg(pAdapter, RF_PATH_B, RF_0x52, 0x000F0, 0xD); ++#else ++ // <20120525, Kordan> Dynamic mechanism for APK, asked by Dennis. ++ if (IS_HARDWARE_TYPE_8188ES(pAdapter) && (1 <= ChannelToSw && ChannelToSw <= 11) && ++ (ulRateIdx == MPT_RATE_MCS0 || ulRateIdx == MPT_RATE_1M || ulRateIdx == MPT_RATE_6M)) ++ { ++ pmp->MptCtx.backup0x52_RF_A = (u1Byte)PHY_QueryRFReg(pAdapter, ODM_RF_PATH_A, RF_0x52, 0x000F0); ++ pmp->MptCtx.backup0x52_RF_B = (u1Byte)PHY_QueryRFReg(pAdapter, ODM_RF_PATH_B, RF_0x52, 0x000F0); ++ PHY_SetRFReg(pAdapter, ODM_RF_PATH_A, RF_0x52, 0x000F0, 0xD); ++ PHY_SetRFReg(pAdapter, ODM_RF_PATH_B, RF_0x52, 0x000F0, 0xD); ++ } ++ else if (IS_HARDWARE_TYPE_8188E(pAdapter)) ++ { ++ PHY_SetRFReg(pAdapter, ODM_RF_PATH_A, RF_0x52, 0x000F0, pmp->MptCtx.backup0x52_RF_A); ++ PHY_SetRFReg(pAdapter, ODM_RF_PATH_B, RF_0x52, 0x000F0, pmp->MptCtx.backup0x52_RF_B); ++ } ++#endif ++ ++ return ; ++} ++/*---------------------------hal\rtl8192c\MPT_Phy.c---------------------------*/ ++ ++/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/ ++void Hal_MPT_CCKTxPowerAdjust(PADAPTER Adapter, BOOLEAN bInCH14) ++{ ++ u32 TempVal = 0, TempVal2 = 0, TempVal3 = 0; ++ u32 CurrCCKSwingVal = 0, CCKSwingIndex = 12; ++ u8 i; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ ++ // get current cck swing value and check 0xa22 & 0xa23 later to match the table. ++ CurrCCKSwingVal = read_bbreg(Adapter, rCCK0_TxFilter1, bMaskHWord); ++ ++ if (!bInCH14) ++ { ++ // Readback the current bb cck swing value and compare with the table to ++ // get the current swing index ++ for (i = 0; i < CCK_TABLE_SIZE; i++) ++ { ++ if (((CurrCCKSwingVal&0xff) == (u32)CCKSwingTable_Ch1_Ch13[i][0]) && ++ (((CurrCCKSwingVal&0xff00)>>8) == (u32)CCKSwingTable_Ch1_Ch13[i][1])) ++ { ++ CCKSwingIndex = i; ++// RT_TRACE(COMP_INIT, DBG_LOUD,("Ch1~13, Current reg0x%x = 0x%lx, CCKSwingIndex=0x%x\n", ++// (rCCK0_TxFilter1+2), CurrCCKSwingVal, CCKSwingIndex)); ++ break; ++ } ++ } ++ ++ //Write 0xa22 0xa23 ++ TempVal = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][0] + ++ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][1]<<8) ; ++ ++ ++ //Write 0xa24 ~ 0xa27 ++ TempVal2 = 0; ++ TempVal2 = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][2] + ++ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][3]<<8) + ++ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][4]<<16 )+ ++ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][5]<<24); ++ ++ //Write 0xa28 0xa29 ++ TempVal3 = 0; ++ TempVal3 = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][6] + ++ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][7]<<8) ; ++ } ++ else ++ { ++ for (i = 0; i < CCK_TABLE_SIZE; i++) ++ { ++ if (((CurrCCKSwingVal&0xff) == (u32)CCKSwingTable_Ch14[i][0]) && ++ (((CurrCCKSwingVal&0xff00)>>8) == (u32)CCKSwingTable_Ch14[i][1])) ++ { ++ CCKSwingIndex = i; ++// RT_TRACE(COMP_INIT, DBG_LOUD,("Ch14, Current reg0x%x = 0x%lx, CCKSwingIndex=0x%x\n", ++// (rCCK0_TxFilter1+2), CurrCCKSwingVal, CCKSwingIndex)); ++ break; ++ } ++ } ++ ++ //Write 0xa22 0xa23 ++ TempVal = CCKSwingTable_Ch14[CCKSwingIndex][0] + ++ (CCKSwingTable_Ch14[CCKSwingIndex][1]<<8) ; ++ ++ //Write 0xa24 ~ 0xa27 ++ TempVal2 = 0; ++ TempVal2 = CCKSwingTable_Ch14[CCKSwingIndex][2] + ++ (CCKSwingTable_Ch14[CCKSwingIndex][3]<<8) + ++ (CCKSwingTable_Ch14[CCKSwingIndex][4]<<16 )+ ++ (CCKSwingTable_Ch14[CCKSwingIndex][5]<<24); ++ ++ //Write 0xa28 0xa29 ++ TempVal3 = 0; ++ TempVal3 = CCKSwingTable_Ch14[CCKSwingIndex][6] + ++ (CCKSwingTable_Ch14[CCKSwingIndex][7]<<8) ; ++ } ++ ++ write_bbreg(Adapter, rCCK0_TxFilter1, bMaskHWord, TempVal); ++ write_bbreg(Adapter, rCCK0_TxFilter2, bMaskDWord, TempVal2); ++ write_bbreg(Adapter, rCCK0_DebugPort, bMaskLWord, TempVal3); ++} ++ ++void Hal_MPT_CCKTxPowerAdjustbyIndex(PADAPTER pAdapter, BOOLEAN beven) ++{ ++ s32 TempCCk; ++ u8 CCK_index, CCK_index_old; ++ u8 Action = 0; //0: no action, 1: even->odd, 2:odd->even ++ u8 TimeOut = 100; ++ s32 i = 0; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ PMPT_CONTEXT pMptCtx = &pAdapter->mppriv.MptCtx; ++ ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ ++ ++ if (!IS_92C_SERIAL(pHalData->VersionID)) ++ return; ++#if 0 ++ while(PlatformAtomicExchange(&Adapter->IntrCCKRefCount, TRUE) == TRUE) ++ { ++ PlatformSleepUs(100); ++ TimeOut--; ++ if(TimeOut <= 0) ++ { ++ RTPRINT(FINIT, INIT_TxPower, ++ ("!!!MPT_CCKTxPowerAdjustbyIndex Wait for check CCK gain index too long!!!\n" )); ++ break; ++ } ++ } ++#endif ++ if (beven && !pMptCtx->bMptIndexEven) //odd->even ++ { ++ Action = 2; ++ pMptCtx->bMptIndexEven = _TRUE; ++ } ++ else if (!beven && pMptCtx->bMptIndexEven) //even->odd ++ { ++ Action = 1; ++ pMptCtx->bMptIndexEven = _FALSE; ++ } ++ ++ if (Action != 0) ++ { ++ //Query CCK default setting From 0xa24 ++ TempCCk = read_bbreg(pAdapter, rCCK0_TxFilter2, bMaskDWord) & bMaskCCK; ++ for (i = 0; i < CCK_TABLE_SIZE; i++) ++ { ++ if (pDM_Odm->RFCalibrateInfo.bCCKinCH14) ++ { ++ if (_rtw_memcmp((void*)&TempCCk, (void*)&CCKSwingTable_Ch14[i][2], 4) == _TRUE) ++ { ++ CCK_index_old = (u8) i; ++// RTPRINT(FINIT, INIT_TxPower,("MPT_CCKTxPowerAdjustbyIndex: Initial reg0x%x = 0x%lx, CCK_index=0x%x, ch 14 %d\n", ++// rCCK0_TxFilter2, TempCCk, CCK_index_old, pHalData->bCCKinCH14)); ++ break; ++ } ++ } ++ else ++ { ++ if (_rtw_memcmp((void*)&TempCCk, (void*)&CCKSwingTable_Ch1_Ch13[i][2], 4) == _TRUE) ++ { ++ CCK_index_old = (u8) i; ++// RTPRINT(FINIT, INIT_TxPower,("MPT_CCKTxPowerAdjustbyIndex: Initial reg0x%x = 0x%lx, CCK_index=0x%x, ch14 %d\n", ++// rCCK0_TxFilter2, TempCCk, CCK_index_old, pHalData->bCCKinCH14)); ++ break; ++ } ++ } ++ } ++ ++ if (Action == 1) ++ CCK_index = CCK_index_old - 1; ++ else ++ CCK_index = CCK_index_old + 1; ++ ++// RTPRINT(FINIT, INIT_TxPower,("MPT_CCKTxPowerAdjustbyIndex: new CCK_index=0x%x\n", ++// CCK_index)); ++ ++ //Adjust CCK according to gain index ++ if (!pDM_Odm->RFCalibrateInfo.bCCKinCH14) { ++ rtw_write8(pAdapter, 0xa22, CCKSwingTable_Ch1_Ch13[CCK_index][0]); ++ rtw_write8(pAdapter, 0xa23, CCKSwingTable_Ch1_Ch13[CCK_index][1]); ++ rtw_write8(pAdapter, 0xa24, CCKSwingTable_Ch1_Ch13[CCK_index][2]); ++ rtw_write8(pAdapter, 0xa25, CCKSwingTable_Ch1_Ch13[CCK_index][3]); ++ rtw_write8(pAdapter, 0xa26, CCKSwingTable_Ch1_Ch13[CCK_index][4]); ++ rtw_write8(pAdapter, 0xa27, CCKSwingTable_Ch1_Ch13[CCK_index][5]); ++ rtw_write8(pAdapter, 0xa28, CCKSwingTable_Ch1_Ch13[CCK_index][6]); ++ rtw_write8(pAdapter, 0xa29, CCKSwingTable_Ch1_Ch13[CCK_index][7]); ++ } else { ++ rtw_write8(pAdapter, 0xa22, CCKSwingTable_Ch14[CCK_index][0]); ++ rtw_write8(pAdapter, 0xa23, CCKSwingTable_Ch14[CCK_index][1]); ++ rtw_write8(pAdapter, 0xa24, CCKSwingTable_Ch14[CCK_index][2]); ++ rtw_write8(pAdapter, 0xa25, CCKSwingTable_Ch14[CCK_index][3]); ++ rtw_write8(pAdapter, 0xa26, CCKSwingTable_Ch14[CCK_index][4]); ++ rtw_write8(pAdapter, 0xa27, CCKSwingTable_Ch14[CCK_index][5]); ++ rtw_write8(pAdapter, 0xa28, CCKSwingTable_Ch14[CCK_index][6]); ++ rtw_write8(pAdapter, 0xa29, CCKSwingTable_Ch14[CCK_index][7]); ++ } ++ } ++#if 0 ++ RTPRINT(FINIT, INIT_TxPower, ++ ("MPT_CCKTxPowerAdjustbyIndex 0xa20=%x\n", PlatformEFIORead4Byte(Adapter, 0xa20))); ++ ++ PlatformAtomicExchange(&Adapter->IntrCCKRefCount, FALSE); ++#endif ++} ++/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/ ++ ++/* ++ * SetChannel ++ * Description ++ * Use H2C command to change channel, ++ * not only modify rf register, but also other setting need to be done. ++ */ ++void Hal_SetChannel(PADAPTER pAdapter) ++{ ++#if 0 ++ struct mp_priv *pmp = &pAdapter->mppriv; ++ ++// SelectChannel(pAdapter, pmp->channel); ++ set_channel_bwmode(pAdapter, pmp->channel, pmp->channel_offset, pmp->bandwidth); ++#else ++ u8 eRFPath; ++ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ struct mp_priv *pmp = &pAdapter->mppriv; ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ ++ u8 channel = pmp->channel; ++ u8 bandwidth = pmp->bandwidth; ++ u8 rate = pmp->rateidx; ++ ++ ++ // set RF channel register ++ for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) ++ { ++ if(IS_HARDWARE_TYPE_8192D(pAdapter)) ++ _write_rfreg(pAdapter, (RF_RADIO_PATH_E)eRFPath, ODM_CHANNEL, 0xFF, channel); ++ else ++ _write_rfreg(pAdapter, eRFPath, ODM_CHANNEL, 0x3FF, channel); ++ } ++ Hal_mpt_SwitchRfSetting(pAdapter); ++ ++ SelectChannel(pAdapter, channel); ++ ++ if (pHalData->CurrentChannel == 14 && !pDM_Odm->RFCalibrateInfo.bCCKinCH14) { ++ pDM_Odm->RFCalibrateInfo.bCCKinCH14 = _TRUE; ++ Hal_MPT_CCKTxPowerAdjust(pAdapter, pDM_Odm->RFCalibrateInfo.bCCKinCH14); ++ } ++ else if (pHalData->CurrentChannel != 14 && pDM_Odm->RFCalibrateInfo.bCCKinCH14) { ++ pDM_Odm->RFCalibrateInfo.bCCKinCH14 = _FALSE; ++ Hal_MPT_CCKTxPowerAdjust(pAdapter, pDM_Odm->RFCalibrateInfo.bCCKinCH14); ++ } ++ ++#endif ++} ++ ++/* ++ * Notice ++ * Switch bandwitdth may change center frequency(channel) ++ */ ++void Hal_SetBandwidth(PADAPTER pAdapter) ++{ ++ struct mp_priv *pmp = &pAdapter->mppriv; ++ ++ ++ SetBWMode(pAdapter, pmp->bandwidth, pmp->prime_channel_offset); ++ Hal_mpt_SwitchRfSetting(pAdapter); ++} ++ ++void Hal_SetCCKTxPower(PADAPTER pAdapter, u8 *TxPower) ++{ ++ u32 tmpval = 0; ++ ++ ++ // rf-A cck tx power ++ write_bbreg(pAdapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, TxPower[RF_PATH_A]); ++ tmpval = (TxPower[RF_PATH_A]<<16) | (TxPower[RF_PATH_A]<<8) | TxPower[RF_PATH_A]; ++ write_bbreg(pAdapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); ++ ++ // rf-B cck tx power ++ write_bbreg(pAdapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, TxPower[RF_PATH_B]); ++ tmpval = (TxPower[RF_PATH_B]<<16) | (TxPower[RF_PATH_B]<<8) | TxPower[RF_PATH_B]; ++ write_bbreg(pAdapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval); ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ++ ("-SetCCKTxPower: A[0x%02x] B[0x%02x]\n", ++ TxPower[RF_PATH_A], TxPower[RF_PATH_B])); ++} ++ ++void Hal_SetOFDMTxPower(PADAPTER pAdapter, u8 *TxPower) ++{ ++ u32 TxAGC = 0; ++ u8 tmpval = 0; ++ PMPT_CONTEXT pMptCtx = &pAdapter->mppriv.MptCtx; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ ++ // HT Tx-rf(A) ++ tmpval = TxPower[RF_PATH_A]; ++ TxAGC = (tmpval<<24) | (tmpval<<16) | (tmpval<<8) | tmpval; ++ ++ write_bbreg(pAdapter, rTxAGC_A_Rate18_06, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_A_Rate54_24, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_A_Mcs03_Mcs00, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_A_Mcs07_Mcs04, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_A_Mcs11_Mcs08, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_A_Mcs15_Mcs12, bMaskDWord, TxAGC); ++ ++ // HT Tx-rf(B) ++ tmpval = TxPower[RF_PATH_B]; ++ TxAGC = (tmpval<<24) | (tmpval<<16) | (tmpval<<8) | tmpval; ++ ++ write_bbreg(pAdapter, rTxAGC_B_Rate18_06, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_B_Rate54_24, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_B_Mcs03_Mcs00, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_B_Mcs07_Mcs04, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_B_Mcs11_Mcs08, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_B_Mcs15_Mcs12, bMaskDWord, TxAGC); ++ ++} ++ ++void Hal_SetAntennaPathPower(PADAPTER pAdapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ u8 TxPowerLevel[MAX_RF_PATH_NUMS]; ++ u8 rfPath; ++ ++ TxPowerLevel[RF_PATH_A] = pAdapter->mppriv.txpoweridx; ++ TxPowerLevel[RF_PATH_B] = pAdapter->mppriv.txpoweridx_b; ++ ++ switch (pAdapter->mppriv.antenna_tx) ++ { ++ case ANTENNA_A: ++ default: ++ rfPath = RF_PATH_A; ++ break; ++ case ANTENNA_B: ++ rfPath = RF_PATH_B; ++ break; ++ case ANTENNA_C: ++ rfPath = RF_PATH_C; ++ break; ++ } ++ ++ switch (pHalData->rf_chip) ++ { ++ case RF_8225: ++ case RF_8256: ++ case RF_6052: ++ Hal_SetCCKTxPower(pAdapter, TxPowerLevel); ++ if (pAdapter->mppriv.rateidx < MPT_RATE_6M) // CCK rate ++ Hal_MPT_CCKTxPowerAdjustbyIndex(pAdapter, TxPowerLevel[rfPath]%2 == 0); ++ Hal_SetOFDMTxPower(pAdapter, TxPowerLevel); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++void Hal_SetTxPower(PADAPTER pAdapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ u8 TxPower = pAdapter->mppriv.txpoweridx; ++ u8 TxPowerLevel[MAX_RF_PATH_NUMS]; ++ u8 rf, rfPath; ++ ++ for (rf = 0; rf < MAX_RF_PATH_NUMS; rf++) { ++ TxPowerLevel[rf] = TxPower; ++ } ++ ++ switch (pAdapter->mppriv.antenna_tx) ++ { ++ case ANTENNA_A: ++ default: ++ rfPath = RF_PATH_A; ++ break; ++ case ANTENNA_B: ++ rfPath = RF_PATH_B; ++ break; ++ case ANTENNA_C: ++ rfPath = RF_PATH_C; ++ break; ++ } ++ ++ switch (pHalData->rf_chip) ++ { ++ // 2008/09/12 MH Test only !! We enable the TX power tracking for MP!!!!! ++ // We should call normal driver API later!! ++ case RF_8225: ++ case RF_8256: ++ case RF_6052: ++ Hal_SetCCKTxPower(pAdapter, TxPowerLevel); ++ if (pAdapter->mppriv.rateidx < MPT_RATE_6M) // CCK rate ++ Hal_MPT_CCKTxPowerAdjustbyIndex(pAdapter, TxPowerLevel[rfPath]%2 == 0); ++ Hal_SetOFDMTxPower(pAdapter, TxPowerLevel); ++ break; ++ ++ default: ++ break; ++ } ++ ++// SetCCKTxPower(pAdapter, TxPower); ++// SetOFDMTxPower(pAdapter, TxPower); ++} ++ ++void Hal_SetTxAGCOffset(PADAPTER pAdapter, u32 ulTxAGCOffset) ++{ ++ u32 TxAGCOffset_B, TxAGCOffset_C, TxAGCOffset_D,tmpAGC; ++ ++ TxAGCOffset_B = (ulTxAGCOffset&0x000000ff); ++ TxAGCOffset_C = ((ulTxAGCOffset&0x0000ff00)>>8); ++ TxAGCOffset_D = ((ulTxAGCOffset&0x00ff0000)>>16); ++ ++ tmpAGC = (TxAGCOffset_D<<8 | TxAGCOffset_C<<4 | TxAGCOffset_B); ++ write_bbreg(pAdapter, rFPGA0_TxGainStage, ++ (bXBTxAGC|bXCTxAGC|bXDTxAGC), tmpAGC); ++} ++ ++void Hal_SetDataRate(PADAPTER pAdapter) ++{ ++ Hal_mpt_SwitchRfSetting(pAdapter); ++} ++ ++void Hal_SetAntenna(PADAPTER pAdapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ R_ANTENNA_SELECT_OFDM *p_ofdm_tx; /* OFDM Tx register */ ++ R_ANTENNA_SELECT_CCK *p_cck_txrx; ++ ++ u8 r_rx_antenna_ofdm = 0, r_ant_select_cck_val = 0; ++ u8 chgTx = 0, chgRx = 0; ++ u32 r_ant_sel_cck_val = 0, r_ant_select_ofdm_val = 0, r_ofdm_tx_en_val = 0; ++ ++ ++ p_ofdm_tx = (R_ANTENNA_SELECT_OFDM *)&r_ant_select_ofdm_val; ++ p_cck_txrx = (R_ANTENNA_SELECT_CCK *)&r_ant_select_cck_val; ++ ++ p_ofdm_tx->r_ant_ht1 = 0x1; ++ p_ofdm_tx->r_ant_ht2 = 0x2; // Second TX RF path is A ++ p_ofdm_tx->r_ant_non_ht = 0x3; // 0x1+0x2=0x3 ++ ++ switch (pAdapter->mppriv.antenna_tx) ++ { ++ case ANTENNA_A: ++ p_ofdm_tx->r_tx_antenna = 0x1; ++ r_ofdm_tx_en_val = 0x1; ++ p_ofdm_tx->r_ant_l = 0x1; ++ p_ofdm_tx->r_ant_ht_s1 = 0x1; ++ p_ofdm_tx->r_ant_non_ht_s1 = 0x1; ++ p_cck_txrx->r_ccktx_enable = 0x8; ++ chgTx = 1; ++ ++ // From SD3 Willis suggestion !!! Set RF A=TX and B as standby ++// if (IS_HARDWARE_TYPE_8192S(pAdapter)) ++ { ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 1); ++ r_ofdm_tx_en_val = 0x3; ++ ++ // Power save ++ //cosa r_ant_select_ofdm_val = 0x11111111; ++ ++ // We need to close RFB by SW control ++ if (pHalData->rf_type == RF_2T2R) ++ { ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 0); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 1); ++ PHY_SetBBReg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT10, 0); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 1); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 0); ++ } ++ } ++ break; ++ ++ case ANTENNA_B: ++ p_ofdm_tx->r_tx_antenna = 0x2; ++ r_ofdm_tx_en_val = 0x2; ++ p_ofdm_tx->r_ant_l = 0x2; ++ p_ofdm_tx->r_ant_ht_s1 = 0x2; ++ p_ofdm_tx->r_ant_non_ht_s1 = 0x2; ++ p_cck_txrx->r_ccktx_enable = 0x4; ++ chgTx = 1; ++ ++ // From SD3 Willis suggestion !!! Set RF A as standby ++ //if (IS_HARDWARE_TYPE_8192S(pAdapter)) ++ { ++ PHY_SetBBReg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 1); ++ PHY_SetBBReg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2); ++// r_ofdm_tx_en_val = 0x3; ++ ++ // Power save ++ //cosa r_ant_select_ofdm_val = 0x22222222; ++ ++ // 2008/10/31 MH From SD3 Willi's suggestion. We must read RF 1T table. ++ // 2009/01/08 MH From Sd3 Willis. We need to close RFA by SW control ++ if (pHalData->rf_type == RF_2T2R || pHalData->rf_type == RF_1T2R) ++ { ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 1); ++ PHY_SetBBReg(pAdapter, rFPGA0_XA_RFInterfaceOE, BIT10, 0); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 0); ++// PHY_SetBBReg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT10, 0); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 0); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 1); ++ } ++ } ++ break; ++ ++ case ANTENNA_AB: // For 8192S ++ p_ofdm_tx->r_tx_antenna = 0x3; ++ r_ofdm_tx_en_val = 0x3; ++ p_ofdm_tx->r_ant_l = 0x3; ++ p_ofdm_tx->r_ant_ht_s1 = 0x3; ++ p_ofdm_tx->r_ant_non_ht_s1 = 0x3; ++ p_cck_txrx->r_ccktx_enable = 0xC; ++ chgTx = 1; ++ ++ // From SD3 Willis suggestion !!! Set RF B as standby ++ //if (IS_HARDWARE_TYPE_8192S(pAdapter)) ++ { ++ PHY_SetBBReg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2); ++ PHY_SetBBReg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2); ++ ++ // Disable Power save ++ //cosa r_ant_select_ofdm_val = 0x3321333; ++#if 0 ++ // 2008/10/31 MH From SD3 Willi's suggestion. We must read RFA 2T table. ++ if ((pHalData->VersionID == VERSION_8192S_ACUT)) // For RTL8192SU A-Cut only, by Roger, 2008.11.07. ++ { ++ mpt_RFConfigFromPreParaArrary(pAdapter, 1, RF_PATH_A); ++ } ++#endif ++ // 2009/01/08 MH From Sd3 Willis. We need to enable RFA/B by SW control ++ if (pHalData->rf_type == RF_2T2R) ++ { ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 0); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 0); ++// PHY_SetBBReg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT10, 0); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 1); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 1); ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ // ++ // r_rx_antenna_ofdm, bit0=A, bit1=B, bit2=C, bit3=D ++ // r_cckrx_enable : CCK default, 0=A, 1=B, 2=C, 3=D ++ // r_cckrx_enable_2 : CCK option, 0=A, 1=B, 2=C, 3=D ++ // ++ switch (pAdapter->mppriv.antenna_rx) ++ { ++ case ANTENNA_A: ++ r_rx_antenna_ofdm = 0x1; // A ++ p_cck_txrx->r_cckrx_enable = 0x0; // default: A ++ p_cck_txrx->r_cckrx_enable_2 = 0x0; // option: A ++ chgRx = 1; ++ break; ++ ++ case ANTENNA_B: ++ r_rx_antenna_ofdm = 0x2; // B ++ p_cck_txrx->r_cckrx_enable = 0x1; // default: B ++ p_cck_txrx->r_cckrx_enable_2 = 0x1; // option: B ++ chgRx = 1; ++ break; ++ ++ case ANTENNA_AB: ++ r_rx_antenna_ofdm = 0x3; // AB ++ p_cck_txrx->r_cckrx_enable = 0x0; // default:A ++ p_cck_txrx->r_cckrx_enable_2 = 0x1; // option:B ++ chgRx = 1; ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (chgTx && chgRx) ++ { ++ switch(pHalData->rf_chip) ++ { ++ case RF_8225: ++ case RF_8256: ++ case RF_6052: ++ //r_ant_sel_cck_val = r_ant_select_cck_val; ++ PHY_SetBBReg(pAdapter, rFPGA1_TxInfo, 0x7fffffff, r_ant_select_ofdm_val); //OFDM Tx ++ PHY_SetBBReg(pAdapter, rFPGA0_TxInfo, 0x0000000f, r_ofdm_tx_en_val); //OFDM Tx ++ PHY_SetBBReg(pAdapter, rOFDM0_TRxPathEnable, 0x0000000f, r_rx_antenna_ofdm); //OFDM Rx ++ PHY_SetBBReg(pAdapter, rOFDM1_TRxPathEnable, 0x0000000f, r_rx_antenna_ofdm); //OFDM Rx ++ PHY_SetBBReg(pAdapter, rCCK0_AFESetting, bMaskByte3, r_ant_select_cck_val);//r_ant_sel_cck_val); //CCK TxRx ++ ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ RT_TRACE(_module_mp_, _drv_notice_, ("-SwitchAntenna: finished\n")); ++} ++ ++s32 Hal_SetThermalMeter(PADAPTER pAdapter, u8 target_ther) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ ++ if (!netif_running(pAdapter->pnetdev)) { ++ RT_TRACE(_module_mp_, _drv_warning_, ("SetThermalMeter! Fail: interface not opened!\n")); ++ return _FAIL; ++ } ++ ++ if (check_fwstate(&pAdapter->mlmepriv, WIFI_MP_STATE) == _FALSE) { ++ RT_TRACE(_module_mp_, _drv_warning_, ("SetThermalMeter: Fail! not in MP mode!\n")); ++ return _FAIL; ++ } ++ ++ target_ther &= 0xff; ++ if (target_ther < 0x07) ++ target_ther = 0x07; ++ else if (target_ther > 0x1d) ++ target_ther = 0x1d; ++ ++ pHalData->EEPROMThermalMeter = target_ther; ++ ++ return _SUCCESS; ++} ++ ++void Hal_TriggerRFThermalMeter(PADAPTER pAdapter) ++{ ++ ++ _write_rfreg( pAdapter, RF_PATH_A , RF_T_METER_88E , BIT17 |BIT16 , 0x03 ); ++ ++// RT_TRACE(_module_mp_,_drv_alert_, ("TriggerRFThermalMeter() finished.\n" )); ++} ++ ++u8 Hal_ReadRFThermalMeter(PADAPTER pAdapter) ++{ ++ u32 ThermalValue = 0; ++ ++ //ThermalValue = _read_rfreg(pAdapter, RF_PATH_A, RF_T_METER, 0x1F); // 0x24: RF Reg[4:0] ++ ++ ThermalValue = _read_rfreg(pAdapter, RF_PATH_A, RF_T_METER_88E, 0xfc00); ++ ++// RT_TRACE(_module_mp_, _drv_alert_, ("ThermalValue = 0x%x\n", ThermalValue)); ++ return (u8)ThermalValue; ++} ++ ++void Hal_GetThermalMeter(PADAPTER pAdapter, u8 *value) ++{ ++#if 0 ++ fw_cmd(pAdapter, IOCMD_GET_THERMAL_METER); ++ rtw_msleep_os(1000); ++ fw_cmd_data(pAdapter, value, 1); ++ *value &= 0xFF; ++#else ++ ++ Hal_TriggerRFThermalMeter(pAdapter); ++ rtw_msleep_os(1000); ++ *value = Hal_ReadRFThermalMeter(pAdapter); ++#endif ++} ++ ++void Hal_SetSingleCarrierTx(PADAPTER pAdapter, u8 bStart) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ pAdapter->mppriv.MptCtx.bSingleCarrier = bStart; ++ if (bStart)// Start Single Carrier. ++ { ++ RT_TRACE(_module_mp_,_drv_alert_, ("SetSingleCarrierTx: test start\n")); ++ // 1. if OFDM block on? ++ if(!read_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn)) ++ write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable);//set OFDM block on ++ ++ { ++ // 2. set CCK test mode off, set to CCK normal mode ++ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, bDisable); ++ // 3. turn on scramble setting ++ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable); ++ } ++ // 4. Turn On Single Carrier Tx and turn off the other test modes. ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bEnable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); ++#ifdef CONFIG_RTL8192C ++ // 5. Disable TX power saving at STF & LLTF ++ write_bbreg(pAdapter, rOFDM1_LSTF, BIT22, 1); ++#endif ++ //for dynamic set Power index. ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); ++ ++ } ++ else// Stop Single Carrier. ++ { ++ RT_TRACE(_module_mp_,_drv_alert_, ("SetSingleCarrierTx: test stop\n")); ++ ++ // Turn off all test modes. ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); ++#ifdef CONFIG_RTL8192C ++ // Cancel disable TX power saving at STF&LLTF ++ write_bbreg(pAdapter, rOFDM1_LSTF, BIT22, 0); ++#endif ++ //Delay 10 ms //delay_ms(10); ++ rtw_msleep_os(10); ++ ++ //BB Reset ++ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); ++ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); ++ ++ //Stop for dynamic set Power index. ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); ++ ++ } ++} ++ ++ ++void Hal_SetSingleToneTx(PADAPTER pAdapter, u8 bStart) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ BOOLEAN is92C = IS_92C_SERIAL(pHalData->VersionID); ++ ++ u8 rfPath; ++ u32 reg58 = 0x0; ++ switch (pAdapter->mppriv.antenna_tx) ++ { ++ case ANTENNA_A: ++ default: ++ rfPath = RF_PATH_A; ++ break; ++ case ANTENNA_B: ++ rfPath = RF_PATH_B; ++ break; ++ case ANTENNA_C: ++ rfPath = RF_PATH_C; ++ break; ++ } ++ ++ pAdapter->mppriv.MptCtx.bSingleTone = bStart; ++ if (bStart)// Start Single Tone. ++ { ++ RT_TRACE(_module_mp_,_drv_alert_, ("SetSingleToneTx: test start\n")); ++ { // <20120326, Kordan> To amplify the power of tone for Xtal calibration. (asked by Edlu) ++ if (IS_HARDWARE_TYPE_8188E(pAdapter)) ++ { ++ reg58 = PHY_QueryRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask); ++ reg58 &= 0xFFFFFFF0; ++ reg58 += 2; ++ PHY_SetRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask, reg58); ++ } ++ PHY_SetBBReg(pAdapter, rFPGA0_RFMOD, bCCKEn, 0x0); ++ PHY_SetBBReg(pAdapter, rFPGA0_RFMOD, bOFDMEn, 0x0); ++ } ++ ++ if (is92C) ++ { ++ _write_rfreg(pAdapter, RF_PATH_A, 0x21, BIT19, 0x01); ++ rtw_usleep_os(100); ++ if (rfPath == RF_PATH_A) ++ write_rfreg(pAdapter, RF_PATH_B, 0x00, 0x10000); // PAD all on. ++ else if (rfPath == RF_PATH_B) ++ write_rfreg(pAdapter, RF_PATH_A, 0x00, 0x10000); // PAD all on. ++ write_rfreg(pAdapter, rfPath, 0x00, 0x2001f); // PAD all on. ++ rtw_usleep_os(100); ++ } ++ else ++ { ++ write_rfreg(pAdapter, rfPath, 0x21, 0xd4000); ++ rtw_usleep_os(100); ++ write_rfreg(pAdapter, rfPath, 0x00, 0x2001f); // PAD all on. ++ rtw_usleep_os(100); ++ } ++ ++ //for dynamic set Power index. ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); ++ ++ } ++ else// Stop Single Tone. ++ { ++ RT_TRACE(_module_mp_,_drv_alert_, ("SetSingleToneTx: test stop\n")); ++ ++ { // <20120326, Kordan> To amplify the power of tone for Xtal calibration. (asked by Edlu) ++ // <20120326, Kordan> Only in single tone mode. (asked by Edlu) ++ if (IS_HARDWARE_TYPE_8188E(pAdapter)) ++ { ++ reg58 = PHY_QueryRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask); ++ reg58 &= 0xFFFFFFF0; ++ PHY_SetRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask, reg58); ++ } ++ ++ write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, 0x1); ++ write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, 0x1); ++ } ++ if (is92C) { ++ _write_rfreg(pAdapter, RF_PATH_A, 0x21, BIT19, 0x00); ++ rtw_usleep_os(100); ++ write_rfreg(pAdapter, RF_PATH_A, 0x00, 0x32d75); // PAD all on. ++ write_rfreg(pAdapter, RF_PATH_B, 0x00, 0x32d75); // PAD all on. ++ rtw_usleep_os(100); ++ } else { ++ write_rfreg(pAdapter, rfPath, 0x21, 0x54000); ++ rtw_usleep_os(100); ++ write_rfreg(pAdapter, rfPath, 0x00, 0x30000); // PAD all on. ++ rtw_usleep_os(100); ++ } ++ ++ //Stop for dynamic set Power index. ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); ++ ++ } ++ ++} ++ ++ ++ ++void Hal_SetCarrierSuppressionTx(PADAPTER pAdapter, u8 bStart) ++{ ++ pAdapter->mppriv.MptCtx.bCarrierSuppression = bStart; ++ if (bStart) // Start Carrier Suppression. ++ { ++ RT_TRACE(_module_mp_,_drv_alert_, ("SetCarrierSuppressionTx: test start\n")); ++ //if(pMgntInfo->dot11CurrentWirelessMode == WIRELESS_MODE_B) ++ if (pAdapter->mppriv.rateidx <= MPT_RATE_11M) ++ { ++ // 1. if CCK block on? ++ if(!read_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn)) ++ write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable);//set CCK block on ++ ++ //Turn Off All Test Mode ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); ++ ++ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x2); //transmit mode ++ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, 0x0); //turn off scramble setting ++ ++ //Set CCK Tx Test Rate ++ //PHY_SetBBReg(pAdapter, rCCK0_System, bCCKTxRate, pMgntInfo->ForcedDataRate); ++ write_bbreg(pAdapter, rCCK0_System, bCCKTxRate, 0x0); //Set FTxRate to 1Mbps ++ } ++ ++ //for dynamic set Power index. ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); ++ ++ } ++ else// Stop Carrier Suppression. ++ { ++ RT_TRACE(_module_mp_,_drv_alert_, ("SetCarrierSuppressionTx: test stop\n")); ++ //if(pMgntInfo->dot11CurrentWirelessMode == WIRELESS_MODE_B) ++ if (pAdapter->mppriv.rateidx <= MPT_RATE_11M ) { ++ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x0); //normal mode ++ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, 0x1); //turn on scramble setting ++ ++ //BB Reset ++ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); ++ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); ++ } ++ ++ //Stop for dynamic set Power index. ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); ++ ++ } ++ //DbgPrint("\n MPT_ProSetCarrierSupp() is finished. \n"); ++} ++ ++void Hal_SetCCKContinuousTx(PADAPTER pAdapter, u8 bStart) ++{ ++ u32 cckrate; ++ ++ if (bStart) ++ { ++ RT_TRACE(_module_mp_, _drv_alert_, ++ ("SetCCKContinuousTx: test start\n")); ++ ++ // 1. if CCK block on? ++ if(!read_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn)) ++ write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable);//set CCK block on ++ ++ //Turn Off All Test Mode ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); ++ //Set CCK Tx Test Rate ++ #if 0 ++ switch(pAdapter->mppriv.rateidx) ++ { ++ case 2: ++ cckrate = 0; ++ break; ++ case 4: ++ cckrate = 1; ++ break; ++ case 11: ++ cckrate = 2; ++ break; ++ case 22: ++ cckrate = 3; ++ break; ++ default: ++ cckrate = 0; ++ break; ++ } ++ #else ++ cckrate = pAdapter->mppriv.rateidx; ++ #endif ++ write_bbreg(pAdapter, rCCK0_System, bCCKTxRate, cckrate); ++ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x2); //transmit mode ++ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable); //turn on scramble setting ++ ++ ++ // Patch for CCK 11M waveform ++ if (cckrate == MPT_RATE_1M) ++ write_bbreg(pAdapter, 0xA71, BIT(6), bDisable); ++ else ++ write_bbreg(pAdapter, 0xA71, BIT(6), bEnable); ++ ++ //for dynamic set Power index. ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); ++ ++ } ++ else { ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("SetCCKContinuousTx: test stop\n")); ++ ++ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x0); //normal mode ++ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable); //turn on scramble setting ++ ++ //BB Reset ++ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); ++ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); ++ ++ //Stop for dynamic set Power index. ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); ++ } ++ ++ pAdapter->mppriv.MptCtx.bCckContTx = bStart; ++ pAdapter->mppriv.MptCtx.bOfdmContTx = _FALSE; ++}/* mpt_StartCckContTx */ ++ ++void Hal_SetOFDMContinuousTx(PADAPTER pAdapter, u8 bStart) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ if (bStart) { ++ RT_TRACE(_module_mp_, _drv_info_, ("SetOFDMContinuousTx: test start\n")); ++ // 1. if OFDM block on? ++ if(!read_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn)) ++ write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable);//set OFDM block on ++ { ++ ++ // 2. set CCK test mode off, set to CCK normal mode ++ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, bDisable); ++ ++ // 3. turn on scramble setting ++ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable); ++ } ++ // 4. Turn On Continue Tx and turn off the other test modes. ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bEnable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); ++ ++ //for dynamic set Power index. ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); ++ ++ } else { ++ RT_TRACE(_module_mp_,_drv_info_, ("SetOFDMContinuousTx: test stop\n")); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); ++ //Delay 10 ms ++ rtw_msleep_os(10); ++ //BB Reset ++ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); ++ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); ++ ++ //Stop for dynamic set Power index. ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); ++ } ++ ++ pAdapter->mppriv.MptCtx.bCckContTx = _FALSE; ++ pAdapter->mppriv.MptCtx.bOfdmContTx = bStart; ++}/* mpt_StartOfdmContTx */ ++ ++void Hal_SetContinuousTx(PADAPTER pAdapter, u8 bStart) ++{ ++#if 0 ++ // ADC turn off [bit24-21] adc port0 ~ port1 ++ if (bStart) { ++ write_bbreg(pAdapter, rRx_Wait_CCCA, read_bbreg(pAdapter, rRx_Wait_CCCA) & 0xFE1FFFFF); ++ rtw_usleep_os(100); ++ } ++#endif ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("SetContinuousTx: rate:%d\n", pAdapter->mppriv.rateidx)); ++ ++ pAdapter->mppriv.MptCtx.bStartContTx = bStart; ++ if (pAdapter->mppriv.rateidx <= MPT_RATE_11M) ++ { ++ Hal_SetCCKContinuousTx(pAdapter, bStart); ++ } ++ else if ((pAdapter->mppriv.rateidx >= MPT_RATE_6M) && ++ (pAdapter->mppriv.rateidx <= MPT_RATE_MCS15)) ++ { ++ Hal_SetOFDMContinuousTx(pAdapter, bStart); ++ } ++#if 0 ++ // ADC turn on [bit24-21] adc port0 ~ port1 ++ if (!bStart) { ++ write_bbreg(pAdapter, rRx_Wait_CCCA, read_bbreg(pAdapter, rRx_Wait_CCCA) | 0x01E00000); ++ } ++#endif ++} ++ ++#endif // CONFIG_MP_INCLUDE ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_phycfg.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_phycfg.c +new file mode 100644 +index 00000000..99bc334c +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_phycfg.c +@@ -0,0 +1,3552 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTL8188E_PHYCFG_C_ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_IOL ++#include ++#endif ++ ++#include ++ ++ ++/*---------------------------Define Local Constant---------------------------*/ ++/* Channel switch:The size of command tables for switch channel*/ ++#define MAX_PRECMD_CNT 16 ++#define MAX_RFDEPENDCMD_CNT 16 ++#define MAX_POSTCMD_CNT 16 ++ ++#define MAX_DOZE_WAITING_TIMES_9x 64 ++ ++/*---------------------------Define Local Constant---------------------------*/ ++ ++ ++/*------------------------Define global variable-----------------------------*/ ++ ++/*------------------------Define local variable------------------------------*/ ++ ++ ++/*--------------------Define export function prototype-----------------------*/ ++// Please refer to header file ++/*--------------------Define export function prototype-----------------------*/ ++ ++/*----------------------------Function Body----------------------------------*/ ++// ++// 1. BB register R/W API ++// ++ ++/** ++* Function: phy_CalculateBitShift ++* ++* OverView: Get shifted position of the BitMask ++* ++* Input: ++* u4Byte BitMask, ++* ++* Output: none ++* Return: u4Byte Return the shift bit bit position of the mask ++*/ ++static u32 ++phy_CalculateBitShift( ++ u32 BitMask ++ ) ++{ ++ u32 i; ++ ++ for(i=0; i<=31; i++) ++ { ++ if ( ((BitMask>>i) & 0x1 ) == 1) ++ break; ++ } ++ ++ return (i); ++} ++ ++#if(SIC_ENABLE == 1) ++static BOOLEAN ++sic_IsSICReady( ++ IN PADAPTER Adapter ++ ) ++{ ++ BOOLEAN bRet=_FALSE; ++ u32 retryCnt=0; ++ u8 sic_cmd=0xff; ++ ++ while(1) ++ { ++ if(retryCnt++ >= SIC_MAX_POLL_CNT) ++ { ++ //RTPRINT(FPHY, (PHY_SICR|PHY_SICW), ("[SIC], sic_IsSICReady() return FALSE\n")); ++ return _FALSE; ++ } ++ ++ //if(RT_SDIO_CANNOT_IO(Adapter)) ++ // return _FALSE; ++ ++ sic_cmd = rtw_read8(Adapter, SIC_CMD_REG); ++ //sic_cmd = PlatformEFIORead1Byte(Adapter, SIC_CMD_REG); ++#if(SIC_HW_SUPPORT == 1) ++ sic_cmd &= 0xf0; // [7:4] ++#endif ++ //RTPRINT(FPHY, (PHY_SICR|PHY_SICW), ("[SIC], sic_IsSICReady(), readback 0x%x=0x%x\n", SIC_CMD_REG, sic_cmd)); ++ if(sic_cmd == SIC_CMD_READY) ++ return _TRUE; ++ else ++ { ++ rtw_msleep_os(1); ++ //delay_ms(1); ++ } ++ } ++ ++ return bRet; ++} ++ ++/* ++u32 ++sic_CalculateBitShift( ++ u32 BitMask ++ ) ++{ ++ u32 i; ++ ++ for(i=0; i<=31; i++) ++ { ++ if ( ((BitMask>>i) & 0x1 ) == 1) ++ break; ++ } ++ ++ return (i); ++} ++*/ ++ ++static u32 ++sic_Read4Byte( ++ PVOID Adapter, ++ u32 offset ++ ) ++{ ++ u32 u4ret=0xffffffff; ++#if RTL8188E_SUPPORT == 1 ++ u8 retry = 0; ++#endif ++ ++ //RTPRINT(FPHY, PHY_SICR, ("[SIC], sic_Read4Byte(): read offset(%#x)\n", offset)); ++ ++ if(sic_IsSICReady(Adapter)) ++ { ++#if(SIC_HW_SUPPORT == 1) ++ rtw_write8(Adapter, SIC_CMD_REG, SIC_CMD_PREREAD); ++ //PlatformEFIOWrite1Byte(Adapter, SIC_CMD_REG, SIC_CMD_PREREAD); ++ //RTPRINT(FPHY, PHY_SICR, ("write cmdreg 0x%x = 0x%x\n", SIC_CMD_REG, SIC_CMD_PREREAD)); ++#endif ++ rtw_write8(Adapter, SIC_ADDR_REG, (u8)(offset&0xff)); ++ //PlatformEFIOWrite1Byte(Adapter, SIC_ADDR_REG, (u1Byte)(offset&0xff)); ++ //RTPRINT(FPHY, PHY_SICR, ("write 0x%x = 0x%x\n", SIC_ADDR_REG, (u1Byte)(offset&0xff))); ++ rtw_write8(Adapter, SIC_ADDR_REG+1, (u8)((offset&0xff00)>>8)); ++ //PlatformEFIOWrite1Byte(Adapter, SIC_ADDR_REG+1, (u1Byte)((offset&0xff00)>>8)); ++ //RTPRINT(FPHY, PHY_SICR, ("write 0x%x = 0x%x\n", SIC_ADDR_REG+1, (u1Byte)((offset&0xff00)>>8))); ++ rtw_write8(Adapter, SIC_CMD_REG, SIC_CMD_READ); ++ //PlatformEFIOWrite1Byte(Adapter, SIC_CMD_REG, SIC_CMD_READ); ++ //RTPRINT(FPHY, PHY_SICR, ("write cmdreg 0x%x = 0x%x\n", SIC_CMD_REG, SIC_CMD_READ)); ++ ++#if RTL8188E_SUPPORT == 1 ++ retry = 4; ++ while(retry--){ ++ rtw_udelay_os(50); ++ //PlatformStallExecution(50); ++ } ++#else ++ rtw_udelay_os(200); ++ //PlatformStallExecution(200); ++#endif ++ ++ if(sic_IsSICReady(Adapter)) ++ { ++ u4ret = rtw_read32(Adapter, SIC_DATA_REG); ++ //u4ret = PlatformEFIORead4Byte(Adapter, SIC_DATA_REG); ++ //RTPRINT(FPHY, PHY_SICR, ("read 0x%x = 0x%x\n", SIC_DATA_REG, u4ret)); ++ //DbgPrint("<===Read 0x%x = 0x%x\n", offset, u4ret); ++ } ++ } ++ ++ return u4ret; ++} ++ ++static VOID ++sic_Write4Byte( ++ PVOID Adapter, ++ u32 offset, ++ u32 data ++ ) ++{ ++#if RTL8188E_SUPPORT == 1 ++ u8 retry = 6; ++#endif ++ //DbgPrint("=>Write 0x%x = 0x%x\n", offset, data); ++ //RTPRINT(FPHY, PHY_SICW, ("[SIC], sic_Write4Byte(): write offset(%#x)=0x%x\n", offset, data)); ++ if(sic_IsSICReady(Adapter)) ++ { ++#if(SIC_HW_SUPPORT == 1) ++ rtw_write8(Adapter, SIC_CMD_REG, SIC_CMD_PREWRITE); ++ //PlatformEFIOWrite1Byte(Adapter, SIC_CMD_REG, SIC_CMD_PREWRITE); ++ //RTPRINT(FPHY, PHY_SICW, ("write data 0x%x = 0x%x\n", SIC_CMD_REG, SIC_CMD_PREWRITE)); ++#endif ++ rtw_write8(Adapter, SIC_ADDR_REG, (u8)(offset&0xff)); ++ //PlatformEFIOWrite1Byte(Adapter, SIC_ADDR_REG, (u1Byte)(offset&0xff)); ++ //RTPRINT(FPHY, PHY_SICW, ("write 0x%x=0x%x\n", SIC_ADDR_REG, (u1Byte)(offset&0xff))); ++ rtw_write8(Adapter, SIC_ADDR_REG+1, (u8)((offset&0xff00)>>8)); ++ //PlatformEFIOWrite1Byte(Adapter, SIC_ADDR_REG+1, (u1Byte)((offset&0xff00)>>8)); ++ //RTPRINT(FPHY, PHY_SICW, ("write 0x%x=0x%x\n", (SIC_ADDR_REG+1), (u1Byte)((offset&0xff00)>>8))); ++ rtw_write32(Adapter, SIC_DATA_REG, (u32)data); ++ //PlatformEFIOWrite4Byte(Adapter, SIC_DATA_REG, (u4Byte)data); ++ //RTPRINT(FPHY, PHY_SICW, ("write data 0x%x = 0x%x\n", SIC_DATA_REG, data)); ++ rtw_write8(Adapter, SIC_CMD_REG, SIC_CMD_WRITE); ++ //PlatformEFIOWrite1Byte(Adapter, SIC_CMD_REG, SIC_CMD_WRITE); ++ //RTPRINT(FPHY, PHY_SICW, ("write data 0x%x = 0x%x\n", SIC_CMD_REG, SIC_CMD_WRITE)); ++#if RTL8188E_SUPPORT == 1 ++ while(retry--){ ++ rtw_udelay_os(50); ++ //PlatformStallExecution(50); ++ } ++#else ++ rtw_udelay_os(150); ++ //PlatformStallExecution(150); ++#endif ++ ++ } ++} ++//============================================================ ++// extern function ++//============================================================ ++static VOID ++SIC_SetBBReg( ++ IN PADAPTER Adapter, ++ IN u32 RegAddr, ++ IN u32 BitMask, ++ IN u32 Data ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u32 OriginalValue, BitShift; ++ u16 BBWaitCounter = 0; ++ ++ //RTPRINT(FPHY, PHY_SICW, ("[SIC], SIC_SetBBReg() start\n")); ++/* ++ while(PlatformAtomicExchange(&pHalData->bChangeBBInProgress, _TRUE) == _TRUE) ++ { ++ BBWaitCounter ++; ++ delay_ms(10); // 1 ms ++ ++ if((BBWaitCounter > 100) || RT_CANNOT_IO(Adapter)) ++ {// Wait too long, return FALSE to avoid to be stuck here. ++ RTPRINT(FPHY, PHY_SICW, ("[SIC], SIC_SetBBReg(), Fail to set BB offset(%#x)!!, WaitCnt(%d)\n", RegAddr, BBWaitCounter)); ++ return; ++ } ++ } ++*/ ++ // ++ // Critical section start ++ // ++ ++ //RTPRINT(FPHY, PHY_SICW, ("[SIC], SIC_SetBBReg(), mask=0x%x, addr[0x%x]=0x%x\n", BitMask, RegAddr, Data)); ++ ++ if(BitMask!= bMaskDWord){//if not "double word" write ++ OriginalValue = sic_Read4Byte(Adapter, RegAddr); ++ //BitShift = sic_CalculateBitShift(BitMask); ++ BitShift = phy_CalculateBitShift(BitMask); ++ Data = (((OriginalValue) & (~BitMask)) | (Data << BitShift)); ++ } ++ ++ sic_Write4Byte(Adapter, RegAddr, Data); ++ ++ //PlatformAtomicExchange(&pHalData->bChangeBBInProgress, _FALSE); ++ //RTPRINT(FPHY, PHY_SICW, ("[SIC], SIC_SetBBReg() end\n")); ++} ++ ++static u32 ++SIC_QueryBBReg( ++ IN PADAPTER Adapter, ++ IN u32 RegAddr, ++ IN u32 BitMask ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u32 ReturnValue = 0, OriginalValue, BitShift; ++ u16 BBWaitCounter = 0; ++ ++ //RTPRINT(FPHY, PHY_SICR, ("[SIC], SIC_QueryBBReg() start\n")); ++ ++/* ++ while(PlatformAtomicExchange(&pHalData->bChangeBBInProgress, _TRUE) == _TRUE) ++ { ++ BBWaitCounter ++; ++ delay_ms(10); // 10 ms ++ ++ if((BBWaitCounter > 100) || RT_CANNOT_IO(Adapter)) ++ {// Wait too long, return FALSE to avoid to be stuck here. ++ RTPRINT(FPHY, PHY_SICW, ("[SIC], SIC_QueryBBReg(), Fail to query BB offset(%#x)!!, WaitCnt(%d)\n", RegAddr, BBWaitCounter)); ++ return ReturnValue; ++ } ++ } ++*/ ++ OriginalValue = sic_Read4Byte(Adapter, RegAddr); ++ //BitShift = sic_CalculateBitShift(BitMask); ++ BitShift = phy_CalculateBitShift(BitMask); ++ ReturnValue = (OriginalValue & BitMask) >> BitShift; ++ ++ //RTPRINT(FPHY, PHY_SICR, ("[SIC], SIC_QueryBBReg(), 0x%x=0x%x\n", RegAddr, OriginalValue)); ++ //RTPRINT(FPHY, PHY_SICR, ("[SIC], SIC_QueryBBReg() end\n")); ++ ++ //PlatformAtomicExchange(&pHalData->bChangeBBInProgress, _FALSE); ++ return (ReturnValue); ++} ++ ++VOID ++SIC_Init( ++ IN PADAPTER Adapter ++ ) ++{ ++ // Here we need to write 0x1b8~0x1bf = 0 after fw is downloaded ++ // because for 8723E at beginning 0x1b8=0x1e, that will cause ++ // sic always not be ready ++#if(SIC_HW_SUPPORT == 1) ++ //RTPRINT(FPHY, PHY_SICR, ("[SIC], SIC_Init(), write 0x%x = 0x%x\n", ++ // SIC_INIT_REG, SIC_INIT_VAL)); ++ rtw_write8(Adapter, SIC_INIT_REG, SIC_INIT_VAL); ++ //PlatformEFIOWrite1Byte(Adapter, SIC_INIT_REG, SIC_INIT_VAL); ++ //RTPRINT(FPHY, PHY_SICR, ("[SIC], SIC_Init(), write 0x%x = 0x%x\n", ++ // SIC_CMD_REG, SIC_CMD_INIT)); ++ rtw_write8(Adapter, SIC_CMD_REG, SIC_CMD_INIT); ++ //PlatformEFIOWrite1Byte(Adapter, SIC_CMD_REG, SIC_CMD_INIT); ++#else ++ //RTPRINT(FPHY, PHY_SICR, ("[SIC], SIC_Init(), write 0x1b8~0x1bf = 0x0\n")); ++ rtw_write32(Adapter, SIC_CMD_REG, 0); ++ //PlatformEFIOWrite4Byte(Adapter, SIC_CMD_REG, 0); ++ rtw_write32(Adapter, SIC_CMD_REG+4, 0); ++ //PlatformEFIOWrite4Byte(Adapter, SIC_CMD_REG+4, 0); ++#endif ++} ++ ++static BOOLEAN ++SIC_LedOff( ++ IN PADAPTER Adapter ++ ) ++{ ++ // When SIC is enabled, led pin will be used as debug pin, ++ // so don't execute led function when SIC is enabled. ++ return _TRUE; ++} ++#endif ++ ++/** ++* Function: PHY_QueryBBReg ++* ++* OverView: Read "sepcific bits" from BB register ++* ++* Input: ++* PADAPTER Adapter, ++* u4Byte RegAddr, //The target address to be readback ++* u4Byte BitMask //The target bit position in the target address ++* //to be readback ++* Output: None ++* Return: u4Byte Data //The readback register value ++* Note: This function is equal to "GetRegSetting" in PHY programming guide ++*/ ++u32 ++rtl8188e_PHY_QueryBBReg( ++ IN PADAPTER Adapter, ++ IN u32 RegAddr, ++ IN u32 BitMask ++ ) ++{ ++ u32 ReturnValue = 0, OriginalValue, BitShift; ++ u16 BBWaitCounter = 0; ++ ++#if (DISABLE_BB_RF == 1) ++ return 0; ++#endif ++ ++#if(SIC_ENABLE == 1) ++ return SIC_QueryBBReg(Adapter, RegAddr, BitMask); ++#endif ++ ++ //RT_TRACE(COMP_RF, DBG_TRACE, ("--->PHY_QueryBBReg(): RegAddr(%#lx), BitMask(%#lx)\n", RegAddr, BitMask)); ++ ++ OriginalValue = rtw_read32(Adapter, RegAddr); ++ BitShift = phy_CalculateBitShift(BitMask); ++ ReturnValue = (OriginalValue & BitMask) >> BitShift; ++ ++ //RTPRINT(FPHY, PHY_BBR, ("BBR MASK=0x%lx Addr[0x%lx]=0x%lx\n", BitMask, RegAddr, OriginalValue)); ++ //RT_TRACE(COMP_RF, DBG_TRACE, ("<---PHY_QueryBBReg(): RegAddr(%#lx), BitMask(%#lx), OriginalValue(%#lx)\n", RegAddr, BitMask, OriginalValue)); ++ ++ return (ReturnValue); ++ ++} ++ ++ ++/** ++* Function: PHY_SetBBReg ++* ++* OverView: Write "Specific bits" to BB register (page 8~) ++* ++* Input: ++* PADAPTER Adapter, ++* u4Byte RegAddr, //The target address to be modified ++* u4Byte BitMask //The target bit position in the target address ++* //to be modified ++* u4Byte Data //The new register value in the target bit position ++* //of the target address ++* ++* Output: None ++* Return: None ++* Note: This function is equal to "PutRegSetting" in PHY programming guide ++*/ ++ ++VOID ++rtl8188e_PHY_SetBBReg( ++ IN PADAPTER Adapter, ++ IN u32 RegAddr, ++ IN u32 BitMask, ++ IN u32 Data ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ //u16 BBWaitCounter = 0; ++ u32 OriginalValue, BitShift; ++ ++#if (DISABLE_BB_RF == 1) ++ return; ++#endif ++ ++#if(SIC_ENABLE == 1) ++ SIC_SetBBReg(Adapter, RegAddr, BitMask, Data); ++ return; ++#endif ++ ++ //RT_TRACE(COMP_RF, DBG_TRACE, ("--->PHY_SetBBReg(): RegAddr(%#lx), BitMask(%#lx), Data(%#lx)\n", RegAddr, BitMask, Data)); ++ ++ if(BitMask!= bMaskDWord){//if not "double word" write ++ OriginalValue = rtw_read32(Adapter, RegAddr); ++ BitShift = phy_CalculateBitShift(BitMask); ++ Data = ((OriginalValue & (~BitMask)) | ((Data << BitShift) & BitMask)); ++ } ++ ++ rtw_write32(Adapter, RegAddr, Data); ++ ++ //RTPRINT(FPHY, PHY_BBW, ("BBW MASK=0x%lx Addr[0x%lx]=0x%lx\n", BitMask, RegAddr, Data)); ++ //RT_TRACE(COMP_RF, DBG_TRACE, ("<---PHY_SetBBReg(): RegAddr(%#lx), BitMask(%#lx), Data(%#lx)\n", RegAddr, BitMask, Data)); ++ ++} ++ ++ ++// ++// 2. RF register R/W API ++// ++/** ++* Function: phy_RFSerialRead ++* ++* OverView: Read regster from RF chips ++* ++* Input: ++* PADAPTER Adapter, ++* RF_RADIO_PATH_E eRFPath, //Radio path of A/B/C/D ++* u4Byte Offset, //The target address to be read ++* ++* Output: None ++* Return: u4Byte reback value ++* Note: Threre are three types of serial operations: ++* 1. Software serial write ++* 2. Hardware LSSI-Low Speed Serial Interface ++* 3. Hardware HSSI-High speed ++* serial write. Driver need to implement (1) and (2). ++* This function is equal to the combination of RF_ReadReg() and RFLSSIRead() ++*/ ++static u32 ++phy_RFSerialRead( ++ IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath, ++ IN u32 Offset ++ ) ++{ ++ u32 retValue = 0; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ BB_REGISTER_DEFINITION_T *pPhyReg = &pHalData->PHYRegDef[eRFPath]; ++ u32 NewOffset; ++ u32 tmplong,tmplong2; ++ u8 RfPiEnable=0; ++#if 0 ++ if(pHalData->RFChipID == RF_8225 && Offset > 0x24) //36 valid regs ++ return retValue; ++ if(pHalData->RFChipID == RF_8256 && Offset > 0x2D) //45 valid regs ++ return retValue; ++#endif ++ // ++ // Make sure RF register offset is correct ++ // ++ Offset &= 0xff; ++ ++ // ++ // Switch page for 8256 RF IC ++ // ++ NewOffset = Offset; ++ ++ // 2009/06/17 MH We can not execute IO for power save or other accident mode. ++ //if(RT_CANNOT_IO(Adapter)) ++ //{ ++ // RTPRINT(FPHY, PHY_RFR, ("phy_RFSerialRead return all one\n")); ++ // return 0xFFFFFFFF; ++ //} ++ ++ // For 92S LSSI Read RFLSSIRead ++ // For RF A/B write 0x824/82c(does not work in the future) ++ // We must use 0x824 for RF A and B to execute read trigger ++ tmplong = PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord); ++ if(eRFPath == RF_PATH_A) ++ tmplong2 = tmplong; ++ else ++ tmplong2 = PHY_QueryBBReg(Adapter, pPhyReg->rfHSSIPara2, bMaskDWord); ++ ++ tmplong2 = (tmplong2 & (~bLSSIReadAddress)) | (NewOffset<<23) | bLSSIReadEdge; //T65 RF ++ ++ PHY_SetBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord, tmplong&(~bLSSIReadEdge)); ++ rtw_udelay_os(10);// PlatformStallExecution(10); ++ ++ PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, bMaskDWord, tmplong2); ++ rtw_udelay_os(100);//PlatformStallExecution(100); ++ ++ //PHY_SetBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord, tmplong|bLSSIReadEdge); ++ rtw_udelay_os(10);//PlatformStallExecution(10); ++ ++ if(eRFPath == RF_PATH_A) ++ RfPiEnable = (u8)PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter1, BIT8); ++ else if(eRFPath == RF_PATH_B) ++ RfPiEnable = (u8)PHY_QueryBBReg(Adapter, rFPGA0_XB_HSSIParameter1, BIT8); ++ ++ if(RfPiEnable) ++ { // Read from BBreg8b8, 12 bits for 8190, 20bits for T65 RF ++ retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBackPi, bLSSIReadBackData); ++ //DBG_8192C("Readback from RF-PI : 0x%x\n", retValue); ++ } ++ else ++ { //Read from BBreg8a0, 12 bits for 8190, 20 bits for T65 RF ++ retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBack, bLSSIReadBackData); ++ //DBG_8192C("Readback from RF-SI : 0x%x\n", retValue); ++ } ++ //DBG_8192C("RFR-%d Addr[0x%x]=0x%x\n", eRFPath, pPhyReg->rfLSSIReadBack, retValue); ++ ++ return retValue; ++ ++} ++ ++ ++ ++/** ++* Function: phy_RFSerialWrite ++* ++* OverView: Write data to RF register (page 8~) ++* ++* Input: ++* PADAPTER Adapter, ++* RF_RADIO_PATH_E eRFPath, //Radio path of A/B/C/D ++* u4Byte Offset, //The target address to be read ++* u4Byte Data //The new register Data in the target bit position ++* //of the target to be read ++* ++* Output: None ++* Return: None ++* Note: Threre are three types of serial operations: ++* 1. Software serial write ++* 2. Hardware LSSI-Low Speed Serial Interface ++* 3. Hardware HSSI-High speed ++* serial write. Driver need to implement (1) and (2). ++* This function is equal to the combination of RF_ReadReg() and RFLSSIRead() ++ * ++ * Note: For RF8256 only ++ * The total count of RTL8256(Zebra4) register is around 36 bit it only employs ++ * 4-bit RF address. RTL8256 uses "register mode control bit" (Reg00[12], Reg00[10]) ++ * to access register address bigger than 0xf. See "Appendix-4 in PHY Configuration ++ * programming guide" for more details. ++ * Thus, we define a sub-finction for RTL8526 register address conversion ++ * =========================================================== ++ * Register Mode RegCTL[1] RegCTL[0] Note ++ * (Reg00[12]) (Reg00[10]) ++ * =========================================================== ++ * Reg_Mode0 0 x Reg 0 ~15(0x0 ~ 0xf) ++ * ------------------------------------------------------------------ ++ * Reg_Mode1 1 0 Reg 16 ~30(0x1 ~ 0xf) ++ * ------------------------------------------------------------------ ++ * Reg_Mode2 1 1 Reg 31 ~ 45(0x1 ~ 0xf) ++ * ------------------------------------------------------------------ ++ * ++ * 2008/09/02 MH Add 92S RF definition ++ * ++ * ++ * ++*/ ++static VOID ++phy_RFSerialWrite( ++ IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath, ++ IN u32 Offset, ++ IN u32 Data ++ ) ++{ ++ u32 DataAndAddr = 0; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ BB_REGISTER_DEFINITION_T *pPhyReg = &pHalData->PHYRegDef[eRFPath]; ++ u32 NewOffset; ++ ++#if 0 ++ // We should check valid regs for RF_6052 case. ++ if(pHalData->RFChipID == RF_8225 && Offset > 0x24) //36 valid regs ++ return; ++ if(pHalData->RFChipID == RF_8256 && Offset > 0x2D) //45 valid regs ++ return; ++#endif ++ ++ // 2009/06/17 MH We can not execute IO for power save or other accident mode. ++ //if(RT_CANNOT_IO(Adapter)) ++ //{ ++ // RTPRINT(FPHY, PHY_RFW, ("phy_RFSerialWrite stop\n")); ++ // return; ++ //} ++ ++ Offset &= 0xff; ++ ++ // ++ // Shadow Update ++ // ++ //PHY_RFShadowWrite(Adapter, eRFPath, Offset, Data); ++ ++ // ++ // Switch page for 8256 RF IC ++ // ++ NewOffset = Offset; ++ ++ // ++ // Put write addr in [5:0] and write data in [31:16] ++ // ++ //DataAndAddr = (Data<<16) | (NewOffset&0x3f); ++ DataAndAddr = ((NewOffset<<20) | (Data&0x000fffff)) & 0x0fffffff; // T65 RF ++ ++ // ++ // Write Operation ++ // ++ PHY_SetBBReg(Adapter, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr); ++ //RTPRINT(FPHY, PHY_RFW, ("RFW-%d Addr[0x%lx]=0x%lx\n", eRFPath, pPhyReg->rf3wireOffset, DataAndAddr)); ++ ++} ++ ++ ++/** ++* Function: PHY_QueryRFReg ++* ++* OverView: Query "Specific bits" to RF register (page 8~) ++* ++* Input: ++* PADAPTER Adapter, ++* RF_RADIO_PATH_E eRFPath, //Radio path of A/B/C/D ++* u4Byte RegAddr, //The target address to be read ++* u4Byte BitMask //The target bit position in the target address ++* //to be read ++* ++* Output: None ++* Return: u4Byte Readback value ++* Note: This function is equal to "GetRFRegSetting" in PHY programming guide ++*/ ++u32 ++rtl8188e_PHY_QueryRFReg( ++ IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath, ++ IN u32 RegAddr, ++ IN u32 BitMask ++ ) ++{ ++ u32 Original_Value, Readback_Value, BitShift; ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ //u8 RFWaitCounter = 0; ++ //_irqL irqL; ++ ++#if (DISABLE_BB_RF == 1) ++ return 0; ++#endif ++ ++ //RT_TRACE(COMP_RF, DBG_TRACE, ("--->PHY_QueryRFReg(): RegAddr(%#lx), eRFPath(%#x), BitMask(%#lx)\n", RegAddr, eRFPath,BitMask)); ++ ++#ifdef CONFIG_USB_HCI ++ //PlatformAcquireMutex(&pHalData->mxRFOperate); ++#else ++ //_enter_critical(&pHalData->rf_lock, &irqL); ++#endif ++ ++ ++ Original_Value = phy_RFSerialRead(Adapter, eRFPath, RegAddr); ++ ++ BitShift = phy_CalculateBitShift(BitMask); ++ Readback_Value = (Original_Value & BitMask) >> BitShift; ++ ++#ifdef CONFIG_USB_HCI ++ //PlatformReleaseMutex(&pHalData->mxRFOperate); ++#else ++ //_exit_critical(&pHalData->rf_lock, &irqL); ++#endif ++ ++ ++ //RTPRINT(FPHY, PHY_RFR, ("RFR-%d MASK=0x%lx Addr[0x%lx]=0x%lx\n", eRFPath, BitMask, RegAddr, Original_Value));//BitMask(%#lx),BitMask, ++ //RT_TRACE(COMP_RF, DBG_TRACE, ("<---PHY_QueryRFReg(): RegAddr(%#lx), eRFPath(%#x), Original_Value(%#lx)\n", ++ // RegAddr, eRFPath, Original_Value)); ++ ++ return (Readback_Value); ++} ++ ++/** ++* Function: PHY_SetRFReg ++* ++* OverView: Write "Specific bits" to RF register (page 8~) ++* ++* Input: ++* PADAPTER Adapter, ++* RF_RADIO_PATH_E eRFPath, //Radio path of A/B/C/D ++* u4Byte RegAddr, //The target address to be modified ++* u4Byte BitMask //The target bit position in the target address ++* //to be modified ++* u4Byte Data //The new register Data in the target bit position ++* //of the target address ++* ++* Output: None ++* Return: None ++* Note: This function is equal to "PutRFRegSetting" in PHY programming guide ++*/ ++VOID ++rtl8188e_PHY_SetRFReg( ++ IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath, ++ IN u32 RegAddr, ++ IN u32 BitMask, ++ IN u32 Data ++ ) ++{ ++ ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ //u1Byte RFWaitCounter = 0; ++ u32 Original_Value, BitShift; ++ //_irqL irqL; ++ ++#if (DISABLE_BB_RF == 1) ++ return; ++#endif ++ ++ //RT_TRACE(COMP_RF, DBG_TRACE, ("--->PHY_SetRFReg(): RegAddr(%#lx), BitMask(%#lx), Data(%#lx), eRFPath(%#x)\n", ++ // RegAddr, BitMask, Data, eRFPath)); ++ //RTPRINT(FINIT, INIT_RF, ("PHY_SetRFReg(): RegAddr(%#lx), BitMask(%#lx), Data(%#lx), eRFPath(%#x)\n", ++ // RegAddr, BitMask, Data, eRFPath)); ++ ++ ++#ifdef CONFIG_USB_HCI ++ //PlatformAcquireMutex(&pHalData->mxRFOperate); ++#else ++ //_enter_critical(&pHalData->rf_lock, &irqL); ++#endif ++ ++ ++ // RF data is 12 bits only ++ if (BitMask != bRFRegOffsetMask) ++ { ++ Original_Value = phy_RFSerialRead(Adapter, eRFPath, RegAddr); ++ BitShift = phy_CalculateBitShift(BitMask); ++ Data = ((Original_Value & (~BitMask)) | (Data<< BitShift)); ++ } ++ ++ phy_RFSerialWrite(Adapter, eRFPath, RegAddr, Data); ++ ++ ++#ifdef CONFIG_USB_HCI ++ //PlatformReleaseMutex(&pHalData->mxRFOperate); ++#else ++ //_exit_critical(&pHalData->rf_lock, &irqL); ++#endif ++ ++ //PHY_QueryRFReg(Adapter,eRFPath,RegAddr,BitMask); ++ //RT_TRACE(COMP_RF, DBG_TRACE, ("<---PHY_SetRFReg(): RegAddr(%#lx), BitMask(%#lx), Data(%#lx), eRFPath(%#x)\n", ++ // RegAddr, BitMask, Data, eRFPath)); ++ ++} ++ ++ ++// ++// 3. Initial MAC/BB/RF config by reading MAC/BB/RF txt. ++// ++ ++/*----------------------------------------------------------------------------- ++ * Function: phy_ConfigMACWithParaFile() ++ * ++ * Overview: This function read BB parameters from general file format, and do register ++ * Read/Write ++ * ++ * Input: PADAPTER Adapter ++ * ps1Byte pFileName ++ * ++ * Output: NONE ++ * ++ * Return: RT_STATUS_SUCCESS: configuration file exist ++ * ++ * Note: The format of MACPHY_REG.txt is different from PHY and RF. ++ * [Register][Mask][Value] ++ *---------------------------------------------------------------------------*/ ++static int ++phy_ConfigMACWithParaFile( ++ IN PADAPTER Adapter, ++ IN u8* pFileName ++) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ int rtStatus = _FAIL; ++ ++ return rtStatus; ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: phy_ConfigMACWithHeaderFile() ++ * ++ * Overview: This function read BB parameters from Header file we gen, and do register ++ * Read/Write ++ * ++ * Input: PADAPTER Adapter ++ * ps1Byte pFileName ++ * ++ * Output: NONE ++ * ++ * Return: RT_STATUS_SUCCESS: configuration file exist ++ * ++ * Note: The format of MACPHY_REG.txt is different from PHY and RF. ++ * [Register][Mask][Value] ++ *---------------------------------------------------------------------------*/ ++#ifndef CONFIG_PHY_SETTING_WITH_ODM ++static int ++phy_ConfigMACWithHeaderFile( ++ IN PADAPTER Adapter ++) ++{ ++ u32 i = 0; ++ u32 ArrayLength = 0; ++ u32* ptrArray; ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ //2008.11.06 Modified by tynli. ++ //RT_TRACE(COMP_INIT, DBG_LOUD, ("Read Rtl819XMACPHY_Array\n")); ++ ArrayLength = Rtl8188E_MAC_ArrayLength; ++ ptrArray = (u32*)Rtl8188E_MAC_Array; ++ ++#ifdef CONFIG_IOL_MAC ++ { ++ struct xmit_frame *xmit_frame; ++ if((xmit_frame=rtw_IOL_accquire_xmit_frame(Adapter)) == NULL) ++ return _FAIL; ++ ++ for(i = 0 ;i < ArrayLength;i=i+2){ // Add by tynli for 2 column ++ rtw_IOL_append_WB_cmd(xmit_frame, ptrArray[i], (u8)ptrArray[i+1]); ++ } ++ ++ return rtw_IOL_exec_cmds_sync(Adapter, xmit_frame, 1000,0); ++ } ++#else ++ for(i = 0 ;i < ArrayLength;i=i+2){ // Add by tynli for 2 column ++ rtw_write8(Adapter, ptrArray[i], (u8)ptrArray[i+1]); ++ } ++#endif ++ ++ return _SUCCESS; ++ ++} ++#endif //#ifndef CONFIG_PHY_SETTING_WITH_ODM ++ ++/*----------------------------------------------------------------------------- ++ * Function: PHY_MACConfig8192C ++ * ++ * Overview: Condig MAC by header file or parameter file. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 08/12/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++s32 PHY_MACConfig8188E(PADAPTER Adapter) ++{ ++ int rtStatus = _SUCCESS; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ s8 *pszMACRegFile; ++ s8 sz8188EMACRegFile[] = RTL8188E_PHY_MACREG; ++ ++ pszMACRegFile = sz8188EMACRegFile; ++ ++ // ++ // Config MAC ++ // ++#ifdef CONFIG_EMBEDDED_FWIMG ++ #ifdef CONFIG_PHY_SETTING_WITH_ODM ++ if(HAL_STATUS_FAILURE == ODM_ConfigMACWithHeaderFile(&pHalData->odmpriv)) ++ rtStatus = _FAIL; ++ #else ++ rtStatus = phy_ConfigMACWithHeaderFile(Adapter); ++ #endif//#ifdef CONFIG_PHY_SETTING_WITH_ODM ++#else ++ ++ // Not make sure EEPROM, add later ++ //RT_TRACE(COMP_INIT, DBG_LOUD, ("Read MACREG.txt\n")); ++ rtStatus = phy_ConfigMACWithParaFile(Adapter, pszMACRegFile); ++#endif//CONFIG_EMBEDDED_FWIMG ++ ++ ++ // 2010.07.13 AMPDU aggregation number B ++ rtw_write8(Adapter, REG_MAX_AGGR_NUM, MAX_AGGR_NUM); ++ //rtw_write8(Adapter, REG_MAX_AGGR_NUM, 0x0B); ++ ++ return rtStatus; ++ ++} ++ ++ ++/** ++* Function: phy_InitBBRFRegisterDefinition ++* ++* OverView: Initialize Register definition offset for Radio Path A/B/C/D ++* ++* Input: ++* PADAPTER Adapter, ++* ++* Output: None ++* Return: None ++* Note: The initialization value is constant and it should never be changes ++*/ ++static VOID ++phy_InitBBRFRegisterDefinition( ++ IN PADAPTER Adapter ++) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ // RF Interface Sowrtware Control ++ pHalData->PHYRegDef[RF_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 LSBs if read 32-bit from 0x870 ++ pHalData->PHYRegDef[RF_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) ++ pHalData->PHYRegDef[RF_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW;// 16 LSBs if read 32-bit from 0x874 ++ pHalData->PHYRegDef[RF_PATH_D].rfintfs = rFPGA0_XCD_RFInterfaceSW;// 16 MSBs if read 32-bit from 0x874 (16-bit for 0x876) ++ ++ // RF Interface Readback Value ++ pHalData->PHYRegDef[RF_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB; // 16 LSBs if read 32-bit from 0x8E0 ++ pHalData->PHYRegDef[RF_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB;// 16 MSBs if read 32-bit from 0x8E0 (16-bit for 0x8E2) ++ pHalData->PHYRegDef[RF_PATH_C].rfintfi = rFPGA0_XCD_RFInterfaceRB;// 16 LSBs if read 32-bit from 0x8E4 ++ pHalData->PHYRegDef[RF_PATH_D].rfintfi = rFPGA0_XCD_RFInterfaceRB;// 16 MSBs if read 32-bit from 0x8E4 (16-bit for 0x8E6) ++ ++ // RF Interface Output (and Enable) ++ pHalData->PHYRegDef[RF_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE; // 16 LSBs if read 32-bit from 0x860 ++ pHalData->PHYRegDef[RF_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE; // 16 LSBs if read 32-bit from 0x864 ++ ++ // RF Interface (Output and) Enable ++ pHalData->PHYRegDef[RF_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE; // 16 MSBs if read 32-bit from 0x860 (16-bit for 0x862) ++ pHalData->PHYRegDef[RF_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE; // 16 MSBs if read 32-bit from 0x864 (16-bit for 0x866) ++ ++ //Addr of LSSI. Wirte RF register by driver ++ pHalData->PHYRegDef[RF_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; //LSSI Parameter ++ pHalData->PHYRegDef[RF_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter; ++ ++ // RF parameter ++ pHalData->PHYRegDef[RF_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter; //BB Band Select ++ pHalData->PHYRegDef[RF_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter; ++ pHalData->PHYRegDef[RF_PATH_C].rfLSSI_Select = rFPGA0_XCD_RFParameter; ++ pHalData->PHYRegDef[RF_PATH_D].rfLSSI_Select = rFPGA0_XCD_RFParameter; ++ ++ // Tx AGC Gain Stage (same for all path. Should we remove this?) ++ pHalData->PHYRegDef[RF_PATH_A].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage ++ pHalData->PHYRegDef[RF_PATH_B].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage ++ pHalData->PHYRegDef[RF_PATH_C].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage ++ pHalData->PHYRegDef[RF_PATH_D].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage ++ ++ // Tranceiver A~D HSSI Parameter-1 ++ pHalData->PHYRegDef[RF_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1; //wire control parameter1 ++ pHalData->PHYRegDef[RF_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1; //wire control parameter1 ++ ++ // Tranceiver A~D HSSI Parameter-2 ++ pHalData->PHYRegDef[RF_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2; //wire control parameter2 ++ pHalData->PHYRegDef[RF_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2; //wire control parameter2 ++ ++ // RF switch Control ++ pHalData->PHYRegDef[RF_PATH_A].rfSwitchControl = rFPGA0_XAB_SwitchControl; //TR/Ant switch control ++ pHalData->PHYRegDef[RF_PATH_B].rfSwitchControl = rFPGA0_XAB_SwitchControl; ++ pHalData->PHYRegDef[RF_PATH_C].rfSwitchControl = rFPGA0_XCD_SwitchControl; ++ pHalData->PHYRegDef[RF_PATH_D].rfSwitchControl = rFPGA0_XCD_SwitchControl; ++ ++ // AGC control 1 ++ pHalData->PHYRegDef[RF_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1; ++ pHalData->PHYRegDef[RF_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1; ++ pHalData->PHYRegDef[RF_PATH_C].rfAGCControl1 = rOFDM0_XCAGCCore1; ++ pHalData->PHYRegDef[RF_PATH_D].rfAGCControl1 = rOFDM0_XDAGCCore1; ++ ++ // AGC control 2 ++ pHalData->PHYRegDef[RF_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2; ++ pHalData->PHYRegDef[RF_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2; ++ pHalData->PHYRegDef[RF_PATH_C].rfAGCControl2 = rOFDM0_XCAGCCore2; ++ pHalData->PHYRegDef[RF_PATH_D].rfAGCControl2 = rOFDM0_XDAGCCore2; ++ ++ // RX AFE control 1 ++ pHalData->PHYRegDef[RF_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance; ++ pHalData->PHYRegDef[RF_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance; ++ pHalData->PHYRegDef[RF_PATH_C].rfRxIQImbalance = rOFDM0_XCRxIQImbalance; ++ pHalData->PHYRegDef[RF_PATH_D].rfRxIQImbalance = rOFDM0_XDRxIQImbalance; ++ ++ // RX AFE control 1 ++ pHalData->PHYRegDef[RF_PATH_A].rfRxAFE = rOFDM0_XARxAFE; ++ pHalData->PHYRegDef[RF_PATH_B].rfRxAFE = rOFDM0_XBRxAFE; ++ pHalData->PHYRegDef[RF_PATH_C].rfRxAFE = rOFDM0_XCRxAFE; ++ pHalData->PHYRegDef[RF_PATH_D].rfRxAFE = rOFDM0_XDRxAFE; ++ ++ // Tx AFE control 1 ++ pHalData->PHYRegDef[RF_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance; ++ pHalData->PHYRegDef[RF_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance; ++ pHalData->PHYRegDef[RF_PATH_C].rfTxIQImbalance = rOFDM0_XCTxIQImbalance; ++ pHalData->PHYRegDef[RF_PATH_D].rfTxIQImbalance = rOFDM0_XDTxIQImbalance; ++ ++ // Tx AFE control 2 ++ pHalData->PHYRegDef[RF_PATH_A].rfTxAFE = rOFDM0_XATxAFE; ++ pHalData->PHYRegDef[RF_PATH_B].rfTxAFE = rOFDM0_XBTxAFE; ++ pHalData->PHYRegDef[RF_PATH_C].rfTxAFE = rOFDM0_XCTxAFE; ++ pHalData->PHYRegDef[RF_PATH_D].rfTxAFE = rOFDM0_XDTxAFE; ++ ++ // Tranceiver LSSI Readback SI mode ++ pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack; ++ pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack; ++ pHalData->PHYRegDef[RF_PATH_C].rfLSSIReadBack = rFPGA0_XC_LSSIReadBack; ++ pHalData->PHYRegDef[RF_PATH_D].rfLSSIReadBack = rFPGA0_XD_LSSIReadBack; ++ ++ // Tranceiver LSSI Readback PI mode ++ pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBackPi = TransceiverA_HSPI_Readback; ++ pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBackPi = TransceiverB_HSPI_Readback; ++ //pHalData->PHYRegDef[RF_PATH_C].rfLSSIReadBackPi = rFPGA0_XC_LSSIReadBack; ++ //pHalData->PHYRegDef[RF_PATH_D].rfLSSIReadBackPi = rFPGA0_XD_LSSIReadBack; ++ ++} ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: phy_ConfigBBWithParaFile() ++ * ++ * Overview: This function read BB parameters from general file format, and do register ++ * Read/Write ++ * ++ * Input: PADAPTER Adapter ++ * ps1Byte pFileName ++ * ++ * Output: NONE ++ * ++ * Return: RT_STATUS_SUCCESS: configuration file exist ++ * 2008/11/06 MH For 92S we do not support silent reset now. Disable ++ * parameter file compare!!!!!!?? ++ * ++ *---------------------------------------------------------------------------*/ ++static int ++phy_ConfigBBWithParaFile( ++ IN PADAPTER Adapter, ++ IN u8* pFileName ++) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ int rtStatus = _SUCCESS; ++ ++ return rtStatus; ++} ++ ++ ++ ++//**************************************** ++// The following is for High Power PA ++//**************************************** ++VOID ++phy_ConfigBBExternalPA( ++ IN PADAPTER Adapter ++) ++{ ++#ifdef CONFIG_USB_HCI ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u16 i=0; ++ u32 temp=0; ++ ++ if(!pHalData->ExternalPA) ++ { ++ return; ++ } ++ ++ // 2010/10/19 MH According to Jenyu/EEChou 's opinion, we need not to execute the ++ // same code as SU. It is already updated in PHY_REG_1T_HP.txt. ++#if 0 ++ PHY_SetBBReg(Adapter, 0xee8, BIT28, 1); ++ temp = PHY_QueryBBReg(Adapter, 0x860, bMaskDWord); ++ temp |= (BIT26|BIT21|BIT10|BIT5); ++ PHY_SetBBReg(Adapter, 0x860, bMaskDWord, temp); ++ PHY_SetBBReg(Adapter, 0x870, BIT10, 0); ++ PHY_SetBBReg(Adapter, 0xc80, bMaskDWord, 0x20000080); ++ PHY_SetBBReg(Adapter, 0xc88, bMaskDWord, 0x40000100); ++#endif ++ ++#endif ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: phy_ConfigBBWithHeaderFile() ++ * ++ * Overview: This function read BB parameters from general file format, and do register ++ * Read/Write ++ * ++ * Input: PADAPTER Adapter ++ * u1Byte ConfigType 0 => PHY_CONFIG ++ * 1 =>AGC_TAB ++ * ++ * Output: NONE ++ * ++ * Return: RT_STATUS_SUCCESS: configuration file exist ++ * ++ *---------------------------------------------------------------------------*/ ++#ifndef CONFIG_PHY_SETTING_WITH_ODM ++static int ++phy_ConfigBBWithHeaderFile( ++ IN PADAPTER Adapter, ++ IN u8 ConfigType ++) ++{ ++ int i; ++ u32* Rtl819XPHY_REGArray_Table; ++ u32* Rtl819XAGCTAB_Array_Table; ++ u16 PHY_REGArrayLen, AGCTAB_ArrayLen; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ DM_ODM_T *podmpriv = &pHalData->odmpriv; ++ int ret = _SUCCESS; ++ ++ ++ AGCTAB_ArrayLen = Rtl8188E_AGCTAB_1TArrayLength; ++ Rtl819XAGCTAB_Array_Table = (u32*)Rtl8188E_AGCTAB_1TArray; ++ PHY_REGArrayLen = Rtl8188E_PHY_REG_1TArrayLength; ++ Rtl819XPHY_REGArray_Table = (u32*)Rtl8188E_PHY_REG_1TArray; ++// RT_TRACE(COMP_INIT, DBG_LOUD, (" ===> phy_ConfigBBWithHeaderFile() phy:Rtl8188EAGCTAB_1TArray\n")); ++// RT_TRACE(COMP_INIT, DBG_LOUD, (" ===> phy_ConfigBBWithHeaderFile() agc:Rtl8188EPHY_REG_1TArray\n")); ++ ++ if(ConfigType == CONFIG_BB_PHY_REG) ++ { ++ #ifdef CONFIG_IOL_BB_PHY_REG ++ { ++ struct xmit_frame *xmit_frame; ++ u32 tmp_value; ++ ++ if((xmit_frame=rtw_IOL_accquire_xmit_frame(Adapter)) == NULL) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ for(i=0;iRFCalibrateInfo.RegA24 = Rtl819XPHY_REGArray_Table[i+1]; ++ ++ rtw_IOL_append_WD_cmd(xmit_frame, Rtl819XPHY_REGArray_Table[i], tmp_value); ++ //RT_TRACE(COMP_INIT, DBG_TRACE, ("The Rtl819XPHY_REGArray_Table[0] is %lx Rtl819XPHY_REGArray[1] is %lx \n",Rtl819XPHY_REGArray_Table[i], Rtl819XPHY_REGArray_Table[i+1])); ++ } ++ ++ ret = rtw_IOL_exec_cmds_sync(Adapter, xmit_frame, 1000,0); ++ } ++ #else ++ for(i=0;iRFCalibrateInfo.RegA24 = Rtl819XPHY_REGArray_Table[i+1]; ++ ++ PHY_SetBBReg(Adapter, Rtl819XPHY_REGArray_Table[i], bMaskDWord, Rtl819XPHY_REGArray_Table[i+1]); ++ ++ // Add 1us delay between BB/RF register setting. ++ rtw_udelay_os(1); ++ ++ //RT_TRACE(COMP_INIT, DBG_TRACE, ("The Rtl819XPHY_REGArray_Table[0] is %lx Rtl819XPHY_REGArray[1] is %lx \n",Rtl819XPHY_REGArray_Table[i], Rtl819XPHY_REGArray_Table[i+1])); ++ } ++ #endif ++ // for External PA ++ phy_ConfigBBExternalPA(Adapter); ++ } ++ else if(ConfigType == CONFIG_BB_AGC_TAB) ++ { ++ #ifdef CONFIG_IOL_BB_AGC_TAB ++ { ++ struct xmit_frame *xmit_frame; ++ ++ if((xmit_frame=rtw_IOL_accquire_xmit_frame(Adapter)) == NULL) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ for(i=0;iMCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][0] = Data; ++ //printk("MCSTxPowerLevelOriginalOffset[%d][0]-TxAGC_A_Rate18_06 = 0x%x\n", pHalData->pwrGroupCnt, ++ // pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][0]); ++ } ++ if(RegAddr == rTxAGC_A_Rate54_24) ++ { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][1] = Data; ++ //printk("MCSTxPowerLevelOriginalOffset[%d][1]-TxAGC_A_Rate54_24 = 0x%x\n", pHalData->pwrGroupCnt, ++ // pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][1]); ++ } ++ if(RegAddr == rTxAGC_A_CCK1_Mcs32) ++ { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][6] = Data; ++ //printk("MCSTxPowerLevelOriginalOffset[%d][6]-TxAGC_A_CCK1_Mcs32 = 0x%x\n", pHalData->pwrGroupCnt, ++ // pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][6]); ++ } ++ if(RegAddr == rTxAGC_B_CCK11_A_CCK2_11 && BitMask == 0xffffff00) ++ { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][7] = Data; ++ //printk("MCSTxPowerLevelOriginalOffset[%d][7]-TxAGC_B_CCK11_A_CCK2_11 = 0x%x\n", pHalData->pwrGroupCnt, ++ // pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][7]); ++ } ++ if(RegAddr == rTxAGC_A_Mcs03_Mcs00) ++ { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][2] = Data; ++ //printk("MCSTxPowerLevelOriginalOffset[%d][2]-TxAGC_A_Mcs03_Mcs00 = 0x%x\n", pHalData->pwrGroupCnt, ++ // pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][2]); ++ } ++ if(RegAddr == rTxAGC_A_Mcs07_Mcs04) ++ { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][3] = Data; ++ //printk("MCSTxPowerLevelOriginalOffset[%d][3]-TxAGC_A_Mcs07_Mcs04 = 0x%x\n", pHalData->pwrGroupCnt, ++ // pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][3]); ++ } ++ if(RegAddr == rTxAGC_A_Mcs11_Mcs08) ++ { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][4] = Data; ++ //printk("MCSTxPowerLevelOriginalOffset[%d][4]-TxAGC_A_Mcs11_Mcs08 = 0x%x\n", pHalData->pwrGroupCnt, ++ // pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][4]); ++ } ++ if(RegAddr == rTxAGC_A_Mcs15_Mcs12) ++ { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][5] = Data; ++ //printk("MCSTxPowerLevelOriginalOffset[%d][5]-TxAGC_A_Mcs15_Mcs12 = 0x%x\n", pHalData->pwrGroupCnt,pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][5]); ++ if(pHalData->rf_type== RF_1T1R) ++ { ++ //printk("pwrGroupCnt = %d\n", pHalData->pwrGroupCnt); ++ pHalData->pwrGroupCnt++; ++ } ++ } ++ if(RegAddr == rTxAGC_B_Rate18_06) ++ { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][8] = Data; ++ //printk("MCSTxPowerLevelOriginalOffset[%d][8]-TxAGC_B_Rate18_06 = 0x%x\n", pHalData->pwrGroupCnt, ++ // pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][8]); ++ } ++ if(RegAddr == rTxAGC_B_Rate54_24) ++ { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][9] = Data; ++ //printk("MCSTxPowerLevelOriginalOffset[%d][9]-TxAGC_B_Rate54_24 = 0x%x\n", pHalData->pwrGroupCnt, ++ // pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][9]); ++ } ++ if(RegAddr == rTxAGC_B_CCK1_55_Mcs32) ++ { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][14] = Data; ++ //printk("MCSTxPowerLevelOriginalOffset[%d][14]-TxAGC_B_CCK1_55_Mcs32 = 0x%x\n", pHalData->pwrGroupCnt, ++ // pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][14]); ++ } ++ if(RegAddr == rTxAGC_B_CCK11_A_CCK2_11 && BitMask == 0x000000ff) ++ { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][15] = Data; ++ //printk("MCSTxPowerLevelOriginalOffset[%d][15]-TxAGC_B_CCK11_A_CCK2_11 = 0x%x\n", pHalData->pwrGroupCnt, ++ // pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][15]); ++ } ++ if(RegAddr == rTxAGC_B_Mcs03_Mcs00) ++ { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][10] = Data; ++ //printk("MCSTxPowerLevelOriginalOffset[%d][10]-TxAGC_B_Mcs03_Mcs00 = 0x%x\n", pHalData->pwrGroupCnt, ++ // pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][10]); ++ } ++ if(RegAddr == rTxAGC_B_Mcs07_Mcs04) ++ { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][11] = Data; ++ //printk("MCSTxPowerLevelOriginalOffset[%d][11]-TxAGC_B_Mcs07_Mcs04 = 0x%x\n", pHalData->pwrGroupCnt, ++ // pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][11]); ++ } ++ if(RegAddr == rTxAGC_B_Mcs11_Mcs08) ++ { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][12] = Data; ++ //printk("MCSTxPowerLevelOriginalOffset[%d][12]-TxAGC_B_Mcs11_Mcs08 = 0x%x\n", pHalData->pwrGroupCnt, ++ // pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][12]); ++ } ++ if(RegAddr == rTxAGC_B_Mcs15_Mcs12) ++ { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][13] = Data; ++ //printk("MCSTxPowerLevelOriginalOffset[%d][13]-TxAGC_B_Mcs15_Mcs12 = 0x%x\n", pHalData->pwrGroupCnt, ++ // pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][13]); ++ ++ if(pHalData->rf_type != RF_1T1R) ++ { ++ //printk("pwrGroupCnt = %d\n", pHalData->pwrGroupCnt); ++ pHalData->pwrGroupCnt++; ++ } ++ } ++} ++/*----------------------------------------------------------------------------- ++ * Function: phy_ConfigBBWithPgParaFile ++ * ++ * Overview: ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/06/2008 MHC Create Version 0. ++ * 2009/07/29 tynli (porting from 92SE branch)2009/03/11 Add copy parameter file to buffer for silent reset ++ *---------------------------------------------------------------------------*/ ++static int ++phy_ConfigBBWithPgParaFile( ++ IN PADAPTER Adapter, ++ IN u8* pFileName) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ int rtStatus = _SUCCESS; ++ ++ ++ return rtStatus; ++ ++} /* phy_ConfigBBWithPgParaFile */ ++ ++#ifndef CONFIG_PHY_SETTING_WITH_ODM ++/*----------------------------------------------------------------------------- ++ * Function: phy_ConfigBBWithPgHeaderFile ++ * ++ * Overview: Config PHY_REG_PG array ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/06/2008 MHC Add later!!!!!!.. Please modify for new files!!!! ++ * 11/10/2008 tynli Modify to mew files. ++ *---------------------------------------------------------------------------*/ ++static int ++phy_ConfigBBWithPgHeaderFile( ++ IN PADAPTER Adapter, ++ IN u8 ConfigType) ++{ ++ int i; ++ u32* Rtl819XPHY_REGArray_Table_PG; ++ u16 PHY_REGArrayPGLen; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ ++ PHY_REGArrayPGLen = Rtl8188E_PHY_REG_Array_PGLength; ++ Rtl819XPHY_REGArray_Table_PG = (u32*)Rtl8188E_PHY_REG_Array_PG; ++ ++ if(ConfigType == CONFIG_BB_PHY_REG) ++ { ++ for(i=0;iphy_BB8192S_Config_ParaFile\n")); ++ ++ pszBBRegFile = sz8188EBBRegFile ; ++ pszAGCTableFile = sz8188EAGCTableFile; ++ pszBBRegPgFile = sz8188EBBRegPgFile; ++ pszBBRegMpFile = sz8188EBBRegMpFile; ++ ++ // ++ // 1. Read PHY_REG.TXT BB INIT!! ++ // We will seperate as 88C / 92C according to chip version ++ // ++#ifdef CONFIG_EMBEDDED_FWIMG ++ #ifdef CONFIG_PHY_SETTING_WITH_ODM ++ if(HAL_STATUS_FAILURE ==ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG)) ++ rtStatus = _FAIL; ++ #else ++ rtStatus = phy_ConfigBBWithHeaderFile(Adapter, CONFIG_BB_PHY_REG); ++ #endif//#ifdef CONFIG_PHY_SETTING_WITH_ODM ++#else ++ // No matter what kind of CHIP we always read PHY_REG.txt. We must copy different ++ // type of parameter files to phy_reg.txt at first. ++ rtStatus = phy_ConfigBBWithParaFile(Adapter,pszBBRegFile); ++#endif//#ifdef CONFIG_EMBEDDED_FWIMG ++ ++ if(rtStatus != _SUCCESS){ ++ //RT_TRACE(COMP_INIT, DBG_SERIOUS, ("phy_BB8192S_Config_ParaFile():Write BB Reg Fail!!")); ++ goto phy_BB8190_Config_ParaFile_Fail; ++ } ++ ++ // ++ // 20100318 Joseph: Config 2T2R to 1T2R if necessary. ++ // ++ //if(pHalData->rf_type == RF_1T2R) ++ //{ ++ //phy_BB8192C_Config_1T(Adapter); ++ //DBG_8192C("phy_BB8188E_Config_ParaFile():Config to 1T!!\n"); ++ //} ++ ++ // ++ // 2. If EEPROM or EFUSE autoload OK, We must config by PHY_REG_PG.txt ++ // ++ if (pEEPROM->bautoload_fail_flag == _FALSE) ++ { ++ pHalData->pwrGroupCnt = 0; ++ ++#ifdef CONFIG_EMBEDDED_FWIMG ++ #ifdef CONFIG_PHY_SETTING_WITH_ODM ++ if(HAL_STATUS_FAILURE ==ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG_PG)) ++ rtStatus = _FAIL; ++ #else ++ rtStatus = phy_ConfigBBWithPgHeaderFile(Adapter, CONFIG_BB_PHY_REG_PG); ++ #endif ++#else ++ rtStatus = phy_ConfigBBWithPgParaFile(Adapter, pszBBRegPgFile); ++#endif ++ } ++ ++ if(rtStatus != _SUCCESS){ ++ //RT_TRACE(COMP_INIT, DBG_SERIOUS, ("phy_BB8192S_Config_ParaFile():BB_PG Reg Fail!!")); ++ goto phy_BB8190_Config_ParaFile_Fail; ++ } ++ ++ // ++ // 3. BB AGC table Initialization ++ // ++#ifdef CONFIG_EMBEDDED_FWIMG ++ #ifdef CONFIG_PHY_SETTING_WITH_ODM ++ if(HAL_STATUS_FAILURE ==ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_AGC_TAB)) ++ rtStatus = _FAIL; ++ #else ++ rtStatus = phy_ConfigBBWithHeaderFile(Adapter, CONFIG_BB_AGC_TAB); ++ #endif//#ifdef CONFIG_PHY_SETTING_WITH_ODM ++#else ++ //RT_TRACE(COMP_INIT, DBG_LOUD, ("phy_BB8192S_Config_ParaFile AGC_TAB.txt\n")); ++ rtStatus = phy_ConfigBBWithParaFile(Adapter, pszAGCTableFile); ++#endif//#ifdef CONFIG_EMBEDDED_FWIMG ++ ++ if(rtStatus != _SUCCESS){ ++ //RT_TRACE(COMP_FPGA, DBG_SERIOUS, ("phy_BB8192S_Config_ParaFile():AGC Table Fail\n")); ++ goto phy_BB8190_Config_ParaFile_Fail; ++ } ++ ++ ++phy_BB8190_Config_ParaFile_Fail: ++ ++ return rtStatus; ++} ++ ++ ++int ++PHY_BBConfig8188E( ++ IN PADAPTER Adapter ++ ) ++{ ++ int rtStatus = _SUCCESS; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u32 RegVal; ++ u8 TmpU1B=0; ++ u8 value8,CrystalCap; ++ ++ phy_InitBBRFRegisterDefinition(Adapter); ++ ++ ++ // Enable BB and RF ++ RegVal = rtw_read16(Adapter, REG_SYS_FUNC_EN); ++ rtw_write16(Adapter, REG_SYS_FUNC_EN, (u16)(RegVal|BIT13|BIT0|BIT1)); ++ ++ // 20090923 Joseph: Advised by Steven and Jenyu. Power sequence before init RF. ++ //rtw_write8(Adapter, REG_AFE_PLL_CTRL, 0x83); ++ //rtw_write8(Adapter, REG_AFE_PLL_CTRL+1, 0xdb); ++ ++ rtw_write8(Adapter, REG_RF_CTRL, RF_EN|RF_RSTB|RF_SDMRSTB); ++ ++#ifdef CONFIG_USB_HCI ++ rtw_write8(Adapter, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD | FEN_BB_GLB_RSTn | FEN_BBRSTB); ++#else ++ rtw_write8(Adapter, REG_SYS_FUNC_EN, FEN_PPLL|FEN_PCIEA|FEN_DIO_PCIE|FEN_BB_GLB_RSTn|FEN_BBRSTB); ++#endif ++ ++#if 0 ++#ifdef CONFIG_USB_HCI ++ //To Fix MAC loopback mode fail. Suggested by SD4 Johnny. 2010.03.23. ++ rtw_write8(Adapter, REG_LDOHCI12_CTRL, 0x0f); ++ rtw_write8(Adapter, 0x15, 0xe9); ++#endif ++ ++ rtw_write8(Adapter, REG_AFE_XTAL_CTRL+1, 0x80); ++#endif ++ ++#ifdef CONFIG_USB_HCI ++ //rtw_write8(Adapter, 0x15, 0xe9); ++#endif ++ ++ ++#ifdef CONFIG_PCI_HCI ++ // Force use left antenna by default for 88C. ++ // if(!IS_92C_SERIAL(pHalData->VersionID) || IS_92C_1T2R(pHalData->VersionID)) ++ if(Adapter->ledpriv.LedStrategy != SW_LED_MODE10) ++ { ++ RegVal = rtw_read32(Adapter, REG_LEDCFG0); ++ rtw_write32(Adapter, REG_LEDCFG0, RegVal|BIT23); ++ } ++#endif ++ ++ // ++ // Config BB and AGC ++ // ++ rtStatus = phy_BB8188E_Config_ParaFile(Adapter); ++ ++ // write 0x24[16:11] = 0x24[22:17] = CrystalCap ++ CrystalCap = pHalData->CrystalCap & 0x3F; ++ PHY_SetBBReg(Adapter, REG_AFE_XTAL_CTRL, 0x7ff800, (CrystalCap | (CrystalCap << 6))); ++ ++ return rtStatus; ++ ++} ++ ++ ++int ++PHY_RFConfig8188E( ++ IN PADAPTER Adapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ int rtStatus = _SUCCESS; ++ ++ // ++ // RF config ++ // ++ rtStatus = PHY_RF6052_Config8188E(Adapter); ++#if 0 ++ switch(pHalData->rf_chip) ++ { ++ case RF_6052: ++ rtStatus = PHY_RF6052_Config(Adapter); ++ break; ++ case RF_8225: ++ rtStatus = PHY_RF8225_Config(Adapter); ++ break; ++ case RF_8256: ++ rtStatus = PHY_RF8256_Config(Adapter); ++ break; ++ case RF_8258: ++ break; ++ case RF_PSEUDO_11N: ++ rtStatus = PHY_RF8225_Config(Adapter); ++ break; ++ default: //for MacOs Warning: "RF_TYPE_MIN" not handled in switch ++ break; ++ } ++#endif ++ return rtStatus; ++} ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: PHY_ConfigRFWithParaFile() ++ * ++ * Overview: This function read RF parameters from general file format, and do RF 3-wire ++ * ++ * Input: PADAPTER Adapter ++ * ps1Byte pFileName ++ * RF_RADIO_PATH_E eRFPath ++ * ++ * Output: NONE ++ * ++ * Return: RT_STATUS_SUCCESS: configuration file exist ++ * ++ * Note: Delay may be required for RF configuration ++ *---------------------------------------------------------------------------*/ ++int ++rtl8188e_PHY_ConfigRFWithParaFile( ++ IN PADAPTER Adapter, ++ IN u8* pFileName, ++ RF_RADIO_PATH_E eRFPath ++) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ int rtStatus = _SUCCESS; ++ ++ ++ return rtStatus; ++ ++} ++ ++//**************************************** ++// The following is for High Power PA ++//**************************************** ++#define HighPowerRadioAArrayLen 22 ++//This is for High power PA ++u32 Rtl8192S_HighPower_RadioA_Array[HighPowerRadioAArrayLen] = { ++0x013,0x00029ea4, ++0x013,0x00025e74, ++0x013,0x00020ea4, ++0x013,0x0001ced0, ++0x013,0x00019f40, ++0x013,0x00014e70, ++0x013,0x000106a0, ++0x013,0x0000c670, ++0x013,0x000082a0, ++0x013,0x00004270, ++0x013,0x00000240, ++}; ++ ++int ++PHY_ConfigRFExternalPA( ++ IN PADAPTER Adapter, ++ RF_RADIO_PATH_E eRFPath ++) ++{ ++ int rtStatus = _SUCCESS; ++#ifdef CONFIG_USB_HCI ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u16 i=0; ++ ++ if(!pHalData->ExternalPA) ++ { ++ return rtStatus; ++ } ++ ++ // 2010/10/19 MH According to Jenyu/EEChou 's opinion, we need not to execute the ++ // same code as SU. It is already updated in radio_a_1T_HP.txt. ++#if 0 ++ //add for SU High Power PA ++ for(i = 0;i PHY_ConfigRFWithHeaderFile() Radio_A:Rtl8188ERadioA_1TArray\n")); ++// RT_TRACE(COMP_INIT, DBG_LOUD, (" ===> PHY_ConfigRFWithHeaderFile() Radio_B:Rtl8188ERadioB_1TArray\n")); ++ ++ switch (eRFPath) ++ { ++ case RF_PATH_A: ++ #ifdef CONFIG_IOL_RF_RF_PATH_A ++ { ++ struct xmit_frame *xmit_frame; ++ if((xmit_frame=rtw_IOL_accquire_xmit_frame(Adapter)) == NULL) { ++ rtStatus = _FAIL; ++ goto exit; ++ } ++ ++ for(i = 0;iPHYRegDef[eRFPath]; ++ u32 NewOffset = 0; ++ u32 DataAndAddr = 0; ++ ++ NewOffset = Rtl819XRadioA_Array_Table[i] & 0x3f; ++ DataAndAddr = ((NewOffset<<20) | (Rtl819XRadioA_Array_Table[i+1]&0x000fffff)) & 0x0fffffff; // T65 RF ++ rtw_IOL_append_WD_cmd(xmit_frame, pPhyReg->rf3wireOffset, DataAndAddr); ++ } ++ } ++ rtStatus = rtw_IOL_exec_cmds_sync(Adapter, xmit_frame, 1000,0); ++ } ++ #else ++ for(i = 0;iPHYRegDef[eRFPath]; ++ u32 NewOffset = 0; ++ u32 DataAndAddr = 0; ++ ++ NewOffset = Rtl819XRadioB_Array_Table[i] & 0x3f; ++ DataAndAddr = ((NewOffset<<20) | (Rtl819XRadioB_Array_Table[i+1]&0x000fffff)) & 0x0fffffff; // T65 RF ++ rtw_IOL_append_WD_cmd(xmit_frame, pPhyReg->rf3wireOffset, DataAndAddr); ++ } ++ } ++ rtStatus = rtw_IOL_exec_cmds_sync(Adapter, xmit_frame, 1000,0); ++ } ++ #else ++ for(i = 0;i actually we call PlatformStallExecution()) to do NdisStallExecution() ++ // [busy wait] instead of NdisMSleep(). So we acquire RT_INITIAL_SPINLOCK ++ // to run at Dispatch level to achive it. ++ //cosa PlatformAcquireSpinLock(Adapter, RT_INITIAL_SPINLOCK); ++ WriteData[i] &= 0xfff; ++ PHY_SetRFReg(Adapter, eRFPath, WriteAddr[HW90_BLOCK_RF], bRFRegOffsetMask, WriteData[i]); ++ // TODO: we should not delay for such a long time. Ask SD3 ++ rtw_mdelay_os(10); ++ ulRegRead = PHY_QueryRFReg(Adapter, eRFPath, WriteAddr[HW90_BLOCK_RF], bMaskDWord); ++ rtw_mdelay_os(10); ++ //cosa PlatformReleaseSpinLock(Adapter, RT_INITIAL_SPINLOCK); ++ break; ++ ++ default: ++ rtStatus = _FAIL; ++ break; ++ } ++ ++ ++ // ++ // Check whether readback data is correct ++ // ++ if(ulRegRead != WriteData[i]) ++ { ++ //RT_TRACE(COMP_FPGA, DBG_LOUD, ("ulRegRead: %lx, WriteData: %lx \n", ulRegRead, WriteData[i])); ++ rtStatus = _FAIL; ++ break; ++ } ++ } ++ ++ return rtStatus; ++} ++ ++ ++VOID ++rtl8192c_PHY_GetHWRegOriginalValue( ++ IN PADAPTER Adapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ // read rx initial gain ++ pHalData->DefaultInitialGain[0] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XAAGCCore1, bMaskByte0); ++ pHalData->DefaultInitialGain[1] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XBAGCCore1, bMaskByte0); ++ pHalData->DefaultInitialGain[2] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XCAGCCore1, bMaskByte0); ++ pHalData->DefaultInitialGain[3] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XDAGCCore1, bMaskByte0); ++ //RT_TRACE(COMP_INIT, DBG_LOUD, ++ //("Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x) \n", ++ //pHalData->DefaultInitialGain[0], pHalData->DefaultInitialGain[1], ++ //pHalData->DefaultInitialGain[2], pHalData->DefaultInitialGain[3])); ++ ++ // read framesync ++ pHalData->framesync = (u8)PHY_QueryBBReg(Adapter, rOFDM0_RxDetector3, bMaskByte0); ++ pHalData->framesyncC34 = PHY_QueryBBReg(Adapter, rOFDM0_RxDetector2, bMaskDWord); ++ //RT_TRACE(COMP_INIT, DBG_LOUD, ("Default framesync (0x%x) = 0x%x \n", ++ // rOFDM0_RxDetector3, pHalData->framesync)); ++} ++ ++ ++// ++// Description: ++// Map dBm into Tx power index according to ++// current HW model, for example, RF and PA, and ++// current wireless mode. ++// By Bruce, 2008-01-29. ++// ++static u8 ++phy_DbmToTxPwrIdx( ++ IN PADAPTER Adapter, ++ IN WIRELESS_MODE WirelessMode, ++ IN int PowerInDbm ++ ) ++{ ++ u8 TxPwrIdx = 0; ++ int Offset = 0; ++ ++ ++ // ++ // Tested by MP, we found that CCK Index 0 equals to 8dbm, OFDM legacy equals to ++ // 3dbm, and OFDM HT equals to 0dbm repectively. ++ // Note: ++ // The mapping may be different by different NICs. Do not use this formula for what needs accurate result. ++ // By Bruce, 2008-01-29. ++ // ++ switch(WirelessMode) ++ { ++ case WIRELESS_MODE_B: ++ Offset = -7; ++ break; ++ ++ case WIRELESS_MODE_G: ++ case WIRELESS_MODE_N_24G: ++ Offset = -8; ++ break; ++ default: ++ Offset = -8; ++ break; ++ } ++ ++ if((PowerInDbm - Offset) > 0) ++ { ++ TxPwrIdx = (u8)((PowerInDbm - Offset) * 2); ++ } ++ else ++ { ++ TxPwrIdx = 0; ++ } ++ ++ // Tx Power Index is too large. ++ if(TxPwrIdx > MAX_TXPWR_IDX_NMODE_92S) ++ TxPwrIdx = MAX_TXPWR_IDX_NMODE_92S; ++ ++ return TxPwrIdx; ++} ++ ++// ++// Description: ++// Map Tx power index into dBm according to ++// current HW model, for example, RF and PA, and ++// current wireless mode. ++// By Bruce, 2008-01-29. ++// ++int ++phy_TxPwrIdxToDbm( ++ IN PADAPTER Adapter, ++ IN WIRELESS_MODE WirelessMode, ++ IN u8 TxPwrIdx ++ ) ++{ ++ int Offset = 0; ++ int PwrOutDbm = 0; ++ ++ // ++ // Tested by MP, we found that CCK Index 0 equals to -7dbm, OFDM legacy equals to -8dbm. ++ // Note: ++ // The mapping may be different by different NICs. Do not use this formula for what needs accurate result. ++ // By Bruce, 2008-01-29. ++ // ++ switch(WirelessMode) ++ { ++ case WIRELESS_MODE_B: ++ Offset = -7; ++ break; ++ ++ case WIRELESS_MODE_G: ++ case WIRELESS_MODE_N_24G: ++ Offset = -8; ++ default: ++ Offset = -8; ++ break; ++ } ++ ++ PwrOutDbm = TxPwrIdx / 2 + Offset; // Discard the decimal part. ++ ++ return PwrOutDbm; ++} ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: GetTxPowerLevel8190() ++ * ++ * Overview: This function is export to "common" moudule ++ * ++ * Input: PADAPTER Adapter ++ * psByte Power Level ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ *---------------------------------------------------------------------------*/ ++VOID ++PHY_GetTxPowerLevel8188E( ++ IN PADAPTER Adapter, ++ OUT u32* powerlevel ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u8 TxPwrLevel = 0; ++ int TxPwrDbm; ++ ++ // ++ // Because the Tx power indexes are different, we report the maximum of them to ++ // meet the CCX TPC request. By Bruce, 2008-01-31. ++ // ++ ++ // CCK ++ TxPwrLevel = pHalData->CurrentCckTxPwrIdx; ++ TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_B, TxPwrLevel); ++ ++ // Legacy OFDM ++ TxPwrLevel = pHalData->CurrentOfdm24GTxPwrIdx + pHalData->LegacyHTTxPowerDiff; ++ ++ // Compare with Legacy OFDM Tx power. ++ if(phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_G, TxPwrLevel) > TxPwrDbm) ++ TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_G, TxPwrLevel); ++ ++ // HT OFDM ++ TxPwrLevel = pHalData->CurrentOfdm24GTxPwrIdx; ++ ++ // Compare with HT OFDM Tx power. ++ if(phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_N_24G, TxPwrLevel) > TxPwrDbm) ++ TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_N_24G, TxPwrLevel); ++ ++ *powerlevel = TxPwrDbm; ++} ++ ++#if 0 ++static void getTxPowerIndex( ++ IN PADAPTER Adapter, ++ IN u8 channel, ++ IN OUT u8* cckPowerLevel, ++ IN OUT u8* ofdmPowerLevel ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u8 index = (channel -1); ++ // 1. CCK ++ cckPowerLevel[RF_PATH_A] = pHalData->TxPwrLevelCck[RF_PATH_A][index]; //RF-A ++ cckPowerLevel[RF_PATH_B] = pHalData->TxPwrLevelCck[RF_PATH_B][index]; //RF-B ++ ++ // 2. OFDM for 1S or 2S ++ if (GET_RF_TYPE(Adapter) == RF_1T2R || GET_RF_TYPE(Adapter) == RF_1T1R) ++ { ++ // Read HT 40 OFDM TX power ++ ofdmPowerLevel[RF_PATH_A] = pHalData->TxPwrLevelHT40_1S[RF_PATH_A][index]; ++ ofdmPowerLevel[RF_PATH_B] = pHalData->TxPwrLevelHT40_1S[RF_PATH_B][index]; ++ } ++ else if (GET_RF_TYPE(Adapter) == RF_2T2R) ++ { ++ // Read HT 40 OFDM TX power ++ ofdmPowerLevel[RF_PATH_A] = pHalData->TxPwrLevelHT40_2S[RF_PATH_A][index]; ++ ofdmPowerLevel[RF_PATH_B] = pHalData->TxPwrLevelHT40_2S[RF_PATH_B][index]; ++ } ++ //RTPRINT(FPHY, PHY_TXPWR, ("Channel-%d, set tx power index !!\n", channel)); ++} ++#endif ++ ++void getTxPowerIndex88E( ++ IN PADAPTER Adapter, ++ IN u8 channel, ++ IN OUT u8* cckPowerLevel, ++ IN OUT u8* ofdmPowerLevel, ++ IN OUT u8* BW20PowerLevel, ++ IN OUT u8* BW40PowerLevel ++ ) ++{ ++ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u8 index = (channel -1); ++ u8 TxCount=0,path_nums; ++ ++ ++ if((RF_1T2R == pHalData->rf_type) ||(RF_1T1R ==pHalData->rf_type )) ++ path_nums = 1; ++ else ++ path_nums = 2; ++ ++ for(TxCount=0;TxCount< path_nums ;TxCount++) ++ { ++ if(TxCount==RF_PATH_A) ++ { ++ // 1. CCK ++ cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index]; ++ //2. OFDM ++ ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+ ++ pHalData->OFDM_24G_Diff[TxCount][RF_PATH_A]; ++ // 1. BW20 ++ BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+ ++ pHalData->BW20_24G_Diff[TxCount][RF_PATH_A]; ++ //2. BW40 ++ BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index]; ++ //RTPRINT(FPHY, PHY_TXPWR, ("getTxPowerIndex88E(): 40MBase=0x%x 20Mdiff=%d 20MBase=0x%x!!\n", ++ // pHalData->Index24G_BW40_Base[RF_PATH_A][index], ++ // pHalData->BW20_24G_Diff[TxCount][RF_PATH_A], ++ // BW20PowerLevel[TxCount])); ++ } ++ else if(TxCount==RF_PATH_B) ++ { ++ // 1. CCK ++ cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index]; ++ //2. OFDM ++ ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+ ++ pHalData->BW20_24G_Diff[RF_PATH_A][index]+ ++ pHalData->BW20_24G_Diff[TxCount][index]; ++ // 1. BW20 ++ BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+ ++ pHalData->BW20_24G_Diff[TxCount][RF_PATH_A]+ ++ pHalData->BW20_24G_Diff[TxCount][index]; ++ //2. BW40 ++ BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index]; ++ } ++ else if(TxCount==RF_PATH_C) ++ { ++ // 1. CCK ++ cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index]; ++ //2. OFDM ++ ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+ ++ pHalData->BW20_24G_Diff[RF_PATH_A][index]+ ++ pHalData->BW20_24G_Diff[RF_PATH_B][index]+ ++ pHalData->BW20_24G_Diff[TxCount][index]; ++ // 1. BW20 ++ BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+ ++ pHalData->BW20_24G_Diff[RF_PATH_A][index]+ ++ pHalData->BW20_24G_Diff[RF_PATH_B][index]+ ++ pHalData->BW20_24G_Diff[TxCount][index]; ++ //2. BW40 ++ BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index]; ++ } ++ else if(TxCount==RF_PATH_D) ++ { ++ // 1. CCK ++ cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index]; ++ //2. OFDM ++ ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+ ++ pHalData->BW20_24G_Diff[RF_PATH_A][index]+ ++ pHalData->BW20_24G_Diff[RF_PATH_B][index]+ ++ pHalData->BW20_24G_Diff[RF_PATH_C][index]+ ++ pHalData->BW20_24G_Diff[TxCount][index]; ++ ++ // 1. BW20 ++ BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+ ++ pHalData->BW20_24G_Diff[RF_PATH_A][index]+ ++ pHalData->BW20_24G_Diff[RF_PATH_B][index]+ ++ pHalData->BW20_24G_Diff[RF_PATH_C][index]+ ++ pHalData->BW20_24G_Diff[TxCount][index]; ++ ++ //2. BW40 ++ BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index]; ++ } ++ else ++ { ++ } ++ } ++ ++#if 0 // (INTEL_PROXIMITY_SUPPORT == 1) ++ switch(pMgntInfo->IntelProximityModeInfo.PowerOutput){ ++ case 1: // 100% ++ break; ++ case 2: // 70% ++ cckPowerLevel[0] -= 3; ++ cckPowerLevel[1] -= 3; ++ ofdmPowerLevel[0] -=3; ++ ofdmPowerLevel[1] -= 3; ++ break; ++ case 3: // 50% ++ cckPowerLevel[0] -= 6; ++ cckPowerLevel[1] -= 6; ++ ofdmPowerLevel[0] -=6; ++ ofdmPowerLevel[1] -= 6; ++ break; ++ case 4: // 35% ++ cckPowerLevel[0] -= 9; ++ cckPowerLevel[1] -= 9; ++ ofdmPowerLevel[0] -=9; ++ ofdmPowerLevel[1] -= 9; ++ break; ++ case 5: // 15% ++ cckPowerLevel[0] -= 17; ++ cckPowerLevel[1] -= 17; ++ ofdmPowerLevel[0] -=17; ++ ofdmPowerLevel[1] -= 17; ++ break; ++ ++ default: ++ break; ++ } ++#endif ++ //RTPRINT(FPHY, PHY_TXPWR, ("Channel-%d, set tx power index !!\n", channel)); ++} ++ ++void phy_PowerIndexCheck88E( ++ IN PADAPTER Adapter, ++ IN u8 channel, ++ IN OUT u8 * cckPowerLevel, ++ IN OUT u8 * ofdmPowerLevel, ++ IN OUT u8 * BW20PowerLevel, ++ IN OUT u8 * BW40PowerLevel ++ ) ++{ ++ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++#if 0 // (CCX_SUPPORT == 1) ++ PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ PRT_CCX_INFO pCcxInfo = GET_CCX_INFO(pMgntInfo); ++ ++ // ++ // CCX 2 S31, AP control of client transmit power: ++ // 1. We shall not exceed Cell Power Limit as possible as we can. ++ // 2. Tolerance is +/- 5dB. ++ // 3. 802.11h Power Contraint takes higher precedence over CCX Cell Power Limit. ++ // ++ // TODO: ++ // 1. 802.11h power contraint ++ // ++ // 071011, by rcnjko. ++ // ++ if( pMgntInfo->OpMode == RT_OP_MODE_INFRASTRUCTURE && ++ pMgntInfo->mAssoc && ++ pCcxInfo->bUpdateCcxPwr && ++ pCcxInfo->bWithCcxCellPwr && ++ channel == pMgntInfo->dot11CurrentChannelNumber) ++ { ++ u1Byte CckCellPwrIdx = phy_DbmToTxPwrIdx(Adapter, WIRELESS_MODE_B, pCcxInfo->CcxCellPwr); ++ u1Byte LegacyOfdmCellPwrIdx = phy_DbmToTxPwrIdx(Adapter, WIRELESS_MODE_G, pCcxInfo->CcxCellPwr); ++ u1Byte OfdmCellPwrIdx = phy_DbmToTxPwrIdx(Adapter, WIRELESS_MODE_N_24G, pCcxInfo->CcxCellPwr); ++ ++ RT_TRACE(COMP_TXAGC, DBG_LOUD, ++ ("CCX Cell Limit: %d dbm => CCK Tx power index : %d, Legacy OFDM Tx power index : %d, OFDM Tx power index: %d\n", ++ pCcxInfo->CcxCellPwr, CckCellPwrIdx, LegacyOfdmCellPwrIdx, OfdmCellPwrIdx)); ++ RT_TRACE(COMP_TXAGC, DBG_LOUD, ++ ("EEPROM channel(%d) => CCK Tx power index: %d, Legacy OFDM Tx power index : %d, OFDM Tx power index: %d\n", ++ channel, cckPowerLevel[0], ofdmPowerLevel[0] + pHalData->LegacyHTTxPowerDiff, ofdmPowerLevel[0])); ++ ++ // CCK ++ if(cckPowerLevel[0] > CckCellPwrIdx) ++ cckPowerLevel[0] = CckCellPwrIdx; ++ // Legacy OFDM, HT OFDM ++ if(ofdmPowerLevel[0] + pHalData->LegacyHTTxPowerDiff > LegacyOfdmCellPwrIdx) ++ { ++ if((OfdmCellPwrIdx - pHalData->LegacyHTTxPowerDiff) > 0) ++ { ++ ofdmPowerLevel[0] = OfdmCellPwrIdx - pHalData->LegacyHTTxPowerDiff; ++ } ++ else ++ { ++ ofdmPowerLevel[0] = 0; ++ } ++ } ++ ++ RT_TRACE(COMP_TXAGC, DBG_LOUD, ++ ("Altered CCK Tx power index : %d, Legacy OFDM Tx power index: %d, OFDM Tx power index: %d\n", ++ cckPowerLevel[0], ofdmPowerLevel[0] + pHalData->LegacyHTTxPowerDiff, ofdmPowerLevel[0])); ++ } ++#else ++ // Add or not ??? ++#endif ++ ++ pHalData->CurrentCckTxPwrIdx = cckPowerLevel[0]; ++ pHalData->CurrentOfdm24GTxPwrIdx = ofdmPowerLevel[0]; ++ pHalData->CurrentBW2024GTxPwrIdx = BW20PowerLevel[0]; ++ pHalData->CurrentBW4024GTxPwrIdx = BW40PowerLevel[0]; ++ ++ //DBG_871X("PHY_SetTxPowerLevel8188E(): CurrentCckTxPwrIdx : 0x%x,CurrentOfdm24GTxPwrIdx: 0x%x, CurrentBW2024GTxPwrIdx: 0x%dx, CurrentBW4024GTxPwrIdx: 0x%x \n", ++ // pHalData->CurrentCckTxPwrIdx, pHalData->CurrentOfdm24GTxPwrIdx, pHalData->CurrentBW2024GTxPwrIdx, pHalData->CurrentBW4024GTxPwrIdx); ++} ++/*----------------------------------------------------------------------------- ++ * Function: SetTxPowerLevel8190() ++ * ++ * Overview: This function is export to "HalCommon" moudule ++ * We must consider RF path later!!!!!!! ++ * ++ * Input: PADAPTER Adapter ++ * u1Byte channel ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * 2008/11/04 MHC We remove EEPROM_93C56. ++ * We need to move CCX relative code to independet file. ++ * 2009/01/21 MHC Support new EEPROM format from SD3 requirement. ++ * ++ *---------------------------------------------------------------------------*/ ++VOID ++PHY_SetTxPowerLevel8188E( ++ IN PADAPTER Adapter, ++ IN u8 channel ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ u8 cckPowerLevel[MAX_TX_COUNT], ofdmPowerLevel[MAX_TX_COUNT];// [0]:RF-A, [1]:RF-B ++ u8 BW20PowerLevel[MAX_TX_COUNT], BW40PowerLevel[MAX_TX_COUNT]; ++ u8 i=0; ++/* ++#if(MP_DRIVER == 1) ++ if (Adapter->registrypriv.mp_mode == 1) ++ return; ++#endif ++*/ ++ //getTxPowerIndex(Adapter, channel, &cckPowerLevel[0], &ofdmPowerLevel[0]); ++ getTxPowerIndex88E(Adapter, channel, &cckPowerLevel[0], &ofdmPowerLevel[0],&BW20PowerLevel[0],&BW40PowerLevel[0]); ++ ++ //printk("Channel-%d, cckPowerLevel = 0x%x, ofdmPowerLeve = 0x%x, BW20PowerLevel = 0x%x, BW40PowerLevel = 0x%x,\n", ++ // channel, cckPowerLevel[0], ofdmPowerLevel[0], BW20PowerLevel[0] ,BW40PowerLevel[0]); ++ ++ //RTPRINT(FPHY, PHY_TXPWR, ("Channel-%d, cckPowerLevel (A / B) = 0x%x / 0x%x, ofdmPowerLevel (A / B) = 0x%x / 0x%x\n", ++ // channel, cckPowerLevel[0], cckPowerLevel[1], ofdmPowerLevel[0], ofdmPowerLevel[1])); ++ ++ //ccxPowerIndexCheck(Adapter, channel, &cckPowerLevel[0], &ofdmPowerLevel[0]); ++ phy_PowerIndexCheck88E(Adapter, channel, &cckPowerLevel[0], &ofdmPowerLevel[0],&BW20PowerLevel[0],&BW40PowerLevel[0]); ++ ++ rtl8188e_PHY_RF6052SetCckTxPower(Adapter, &cckPowerLevel[0]); ++ rtl8188e_PHY_RF6052SetOFDMTxPower(Adapter, &ofdmPowerLevel[0],&BW20PowerLevel[0],&BW40PowerLevel[0], channel); ++ ++#if 0 ++ switch(pHalData->rf_chip) ++ { ++ case RF_8225: ++ PHY_SetRF8225CckTxPower(Adapter, cckPowerLevel[0]); ++ PHY_SetRF8225OfdmTxPower(Adapter, ofdmPowerLevel[0]); ++ break; ++ ++ case RF_8256: ++ PHY_SetRF8256CCKTxPower(Adapter, cckPowerLevel[0]); ++ PHY_SetRF8256OFDMTxPower(Adapter, ofdmPowerLevel[0]); ++ break; ++ ++ case RF_6052: ++ PHY_RF6052SetCckTxPower(Adapter, &cckPowerLevel[0]); ++ PHY_RF6052SetOFDMTxPower(Adapter, &ofdmPowerLevel[0], channel); ++ break; ++ ++ case RF_8258: ++ break; ++ } ++#endif ++ ++} ++ ++ ++// ++// Description: ++// Update transmit power level of all channel supported. ++// ++// TODO: ++// A mode. ++// By Bruce, 2008-02-04. ++// ++BOOLEAN ++PHY_UpdateTxPowerDbm8188E( ++ IN PADAPTER Adapter, ++ IN int powerInDbm ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u8 idx; ++ u8 rf_path; ++ ++ // TODO: A mode Tx power. ++ u8 CckTxPwrIdx = phy_DbmToTxPwrIdx(Adapter, WIRELESS_MODE_B, powerInDbm); ++ u8 OfdmTxPwrIdx = phy_DbmToTxPwrIdx(Adapter, WIRELESS_MODE_N_24G, powerInDbm); ++ ++ if(OfdmTxPwrIdx - pHalData->LegacyHTTxPowerDiff > 0) ++ OfdmTxPwrIdx -= pHalData->LegacyHTTxPowerDiff; ++ else ++ OfdmTxPwrIdx = 0; ++ ++ //RT_TRACE(COMP_TXAGC, DBG_LOUD, ("PHY_UpdateTxPowerDbm8192S(): %ld dBm , CckTxPwrIdx = %d, OfdmTxPwrIdx = %d\n", powerInDbm, CckTxPwrIdx, OfdmTxPwrIdx)); ++ ++ for(idx = 0; idx < 14; idx++) ++ { ++ for (rf_path = 0; rf_path < 2; rf_path++) ++ { ++ pHalData->TxPwrLevelCck[rf_path][idx] = CckTxPwrIdx; ++ pHalData->TxPwrLevelHT40_1S[rf_path][idx] = ++ pHalData->TxPwrLevelHT40_2S[rf_path][idx] = OfdmTxPwrIdx; ++ } ++ } ++ ++ //Adapter->HalFunc.SetTxPowerLevelHandler(Adapter, pHalData->CurrentChannel);//gtest:todo ++ ++ return _TRUE; ++} ++ ++ ++/* ++ Description: ++ When beacon interval is changed, the values of the ++ hw registers should be modified. ++ By tynli, 2008.10.24. ++ ++*/ ++ ++ ++void ++rtl8192c_PHY_SetBeaconHwReg( ++ IN PADAPTER Adapter, ++ IN u16 BeaconInterval ++ ) ++{ ++ ++} ++ ++ ++VOID ++PHY_ScanOperationBackup8188E( ++ IN PADAPTER Adapter, ++ IN u8 Operation ++ ) ++{ ++#if 0 ++ IO_TYPE IoType; ++ ++ if(!Adapter->bDriverStopped) ++ { ++ switch(Operation) ++ { ++ case SCAN_OPT_BACKUP: ++ IoType = IO_CMD_PAUSE_DM_BY_SCAN; ++ rtw_hal_set_hwreg(Adapter,HW_VAR_IO_CMD, (pu1Byte)&IoType); ++ ++ break; ++ ++ case SCAN_OPT_RESTORE: ++ IoType = IO_CMD_RESUME_DM_BY_SCAN; ++ rtw_hal_set_hwreg(Adapter,HW_VAR_IO_CMD, (pu1Byte)&IoType); ++ break; ++ ++ default: ++ RT_TRACE(COMP_SCAN, DBG_LOUD, ("Unknown Scan Backup Operation. \n")); ++ break; ++ } ++ } ++#endif ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: PHY_SetBWModeCallback8192C() ++ * ++ * Overview: Timer callback function for SetSetBWMode ++ * ++ * Input: PRT_TIMER pTimer ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Note: (1) We do not take j mode into consideration now ++ * (2) Will two workitem of "switch channel" and "switch channel bandwidth" run ++ * concurrently? ++ *---------------------------------------------------------------------------*/ ++static VOID ++_PHY_SetBWMode92C( ++ IN PADAPTER Adapter ++) ++{ ++// PADAPTER Adapter = (PADAPTER)pTimer->Adapter; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u8 regBwOpMode; ++ u8 regRRSR_RSC; ++ ++ //return; ++ ++ // Added it for 20/40 mhz switch time evaluation by guangan 070531 ++ //u4Byte NowL, NowH; ++ //u8Byte BeginTime, EndTime; ++ ++ /*RT_TRACE(COMP_SCAN, DBG_LOUD, ("==>PHY_SetBWModeCallback8192C() Switch to %s bandwidth\n", \ ++ pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20?"20MHz":"40MHz"))*/ ++ ++ if(pHalData->rf_chip == RF_PSEUDO_11N) ++ { ++ //pHalData->SetBWModeInProgress= _FALSE; ++ return; ++ } ++ ++ // There is no 40MHz mode in RF_8225. ++ if(pHalData->rf_chip==RF_8225) ++ return; ++ ++ if(Adapter->bDriverStopped) ++ return; ++ ++ // Added it for 20/40 mhz switch time evaluation by guangan 070531 ++ //NowL = PlatformEFIORead4Byte(Adapter, TSFR); ++ //NowH = PlatformEFIORead4Byte(Adapter, TSFR+4); ++ //BeginTime = ((u8Byte)NowH << 32) + NowL; ++ ++ //3// ++ //3//<1>Set MAC register ++ //3// ++ //Adapter->HalFunc.SetBWModeHandler(); ++ ++ regBwOpMode = rtw_read8(Adapter, REG_BWOPMODE); ++ regRRSR_RSC = rtw_read8(Adapter, REG_RRSR+2); ++ //regBwOpMode = rtw_hal_get_hwreg(Adapter,HW_VAR_BWMODE,(pu1Byte)®BwOpMode); ++ ++ switch(pHalData->CurrentChannelBW) ++ { ++ case HT_CHANNEL_WIDTH_20: ++ regBwOpMode |= BW_OPMODE_20MHZ; ++ // 2007/02/07 Mark by Emily becasue we have not verify whether this register works ++ rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode); ++ break; ++ ++ case HT_CHANNEL_WIDTH_40: ++ regBwOpMode &= ~BW_OPMODE_20MHZ; ++ // 2007/02/07 Mark by Emily becasue we have not verify whether this register works ++ rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode); ++ ++ regRRSR_RSC = (regRRSR_RSC&0x90) |(pHalData->nCur40MhzPrimeSC<<5); ++ rtw_write8(Adapter, REG_RRSR+2, regRRSR_RSC); ++ break; ++ ++ default: ++ /*RT_TRACE(COMP_DBG, DBG_LOUD, ("PHY_SetBWModeCallback8192C(): ++ unknown Bandwidth: %#X\n",pHalData->CurrentChannelBW));*/ ++ break; ++ } ++ ++ //3// ++ //3//<2>Set PHY related register ++ //3// ++ switch(pHalData->CurrentChannelBW) ++ { ++ /* 20 MHz channel*/ ++ case HT_CHANNEL_WIDTH_20: ++ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x0); ++ PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x0); ++ //PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter2, BIT10, 1); ++ ++ break; ++ ++ ++ /* 40 MHz channel*/ ++ case HT_CHANNEL_WIDTH_40: ++ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x1); ++ PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x1); ++ ++ // Set Control channel to upper or lower. These settings are required only for 40MHz ++ PHY_SetBBReg(Adapter, rCCK0_System, bCCKSideBand, (pHalData->nCur40MhzPrimeSC>>1)); ++ PHY_SetBBReg(Adapter, rOFDM1_LSTF, 0xC00, pHalData->nCur40MhzPrimeSC); ++ //PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter2, BIT10, 0); ++ ++ PHY_SetBBReg(Adapter, 0x818, (BIT26|BIT27), (pHalData->nCur40MhzPrimeSC==HAL_PRIME_CHNL_OFFSET_LOWER)?2:1); ++ ++ break; ++ ++ ++ ++ default: ++ /*RT_TRACE(COMP_DBG, DBG_LOUD, ("PHY_SetBWModeCallback8192C(): unknown Bandwidth: %#X\n"\ ++ ,pHalData->CurrentChannelBW));*/ ++ break; ++ ++ } ++ //Skip over setting of J-mode in BB register here. Default value is "None J mode". Emily 20070315 ++ ++ // Added it for 20/40 mhz switch time evaluation by guangan 070531 ++ //NowL = PlatformEFIORead4Byte(Adapter, TSFR); ++ //NowH = PlatformEFIORead4Byte(Adapter, TSFR+4); ++ //EndTime = ((u8Byte)NowH << 32) + NowL; ++ //RT_TRACE(COMP_SCAN, DBG_LOUD, ("SetBWModeCallback8190Pci: time of SetBWMode = %I64d us!\n", (EndTime - BeginTime))); ++ ++ //3<3>Set RF related register ++ switch(pHalData->rf_chip) ++ { ++ case RF_8225: ++ //PHY_SetRF8225Bandwidth(Adapter, pHalData->CurrentChannelBW); ++ break; ++ ++ case RF_8256: ++ // Please implement this function in Hal8190PciPhy8256.c ++ //PHY_SetRF8256Bandwidth(Adapter, pHalData->CurrentChannelBW); ++ break; ++ ++ case RF_8258: ++ // Please implement this function in Hal8190PciPhy8258.c ++ // PHY_SetRF8258Bandwidth(); ++ break; ++ ++ case RF_PSEUDO_11N: ++ // Do Nothing ++ break; ++ ++ case RF_6052: ++ rtl8188e_PHY_RF6052SetBandwidth(Adapter, pHalData->CurrentChannelBW); ++ break; ++ ++ default: ++ //RT_ASSERT(FALSE, ("Unknown RFChipID: %d\n", pHalData->RFChipID)); ++ break; ++ } ++ ++ //pHalData->SetBWModeInProgress= FALSE; ++ ++ //RT_TRACE(COMP_SCAN, DBG_LOUD, ("<==PHY_SetBWModeCallback8192C() \n" )); ++} ++ ++ ++ /*----------------------------------------------------------------------------- ++ * Function: SetBWMode8190Pci() ++ * ++ * Overview: This function is export to "HalCommon" moudule ++ * ++ * Input: PADAPTER Adapter ++ * HT_CHANNEL_WIDTH Bandwidth //20M or 40M ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Note: We do not take j mode into consideration now ++ *---------------------------------------------------------------------------*/ ++VOID ++PHY_SetBWMode8188E( ++ IN PADAPTER Adapter, ++ IN HT_CHANNEL_WIDTH Bandwidth, // 20M or 40M ++ IN unsigned char Offset // Upper, Lower, or Don't care ++) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ HT_CHANNEL_WIDTH tmpBW= pHalData->CurrentChannelBW; ++ // Modified it for 20/40 mhz switch by guangan 070531 ++ //PMGNT_INFO pMgntInfo=&Adapter->MgntInfo; ++ ++ //return; ++ ++ //if(pHalData->SwChnlInProgress) ++// if(pMgntInfo->bScanInProgress) ++// { ++// RT_TRACE(COMP_SCAN, DBG_LOUD, ("PHY_SetBWMode8192C() %s Exit because bScanInProgress!\n", ++// Bandwidth == HT_CHANNEL_WIDTH_20?"20MHz":"40MHz")); ++// return; ++// } ++ ++// if(pHalData->SetBWModeInProgress) ++// { ++// // Modified it for 20/40 mhz switch by guangan 070531 ++// RT_TRACE(COMP_SCAN, DBG_LOUD, ("PHY_SetBWMode8192C() %s cancel last timer because SetBWModeInProgress!\n", ++// Bandwidth == HT_CHANNEL_WIDTH_20?"20MHz":"40MHz")); ++// PlatformCancelTimer(Adapter, &pHalData->SetBWModeTimer); ++// //return; ++// } ++ ++ //if(pHalData->SetBWModeInProgress) ++ // return; ++ ++ //pHalData->SetBWModeInProgress= TRUE; ++ ++ pHalData->CurrentChannelBW = Bandwidth; ++ ++#if 0 ++ if(Offset==HT_EXTCHNL_OFFSET_LOWER) ++ pHalData->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_UPPER; ++ else if(Offset==HT_EXTCHNL_OFFSET_UPPER) ++ pHalData->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_LOWER; ++ else ++ pHalData->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++#else ++ pHalData->nCur40MhzPrimeSC = Offset; ++#endif ++ ++ if((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved)) ++ { ++ #if 0 ++ //PlatformSetTimer(Adapter, &(pHalData->SetBWModeTimer), 0); ++ #else ++ _PHY_SetBWMode92C(Adapter); ++ #endif ++ } ++ else ++ { ++ //RT_TRACE(COMP_SCAN, DBG_LOUD, ("PHY_SetBWMode8192C() SetBWModeInProgress FALSE driver sleep or unload\n")); ++ //pHalData->SetBWModeInProgress= FALSE; ++ pHalData->CurrentChannelBW = tmpBW; ++ } ++ ++} ++ ++ ++static void _PHY_SwChnl8192C(PADAPTER Adapter, u8 channel) ++{ ++ u8 eRFPath; ++ u32 param1, param2; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ if ( Adapter->bNotifyChannelChange ) ++ { ++ DBG_871X( "[%s] ch = %d\n", __FUNCTION__, channel ); ++ } ++ ++ //s1. pre common command - CmdID_SetTxPowerLevel ++ PHY_SetTxPowerLevel8188E(Adapter, channel); ++ ++ //s2. RF dependent command - CmdID_RF_WriteReg, param1=RF_CHNLBW, param2=channel ++ param1 = RF_CHNLBW; ++ param2 = channel; ++ for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) ++ { ++ pHalData->RfRegChnlVal[eRFPath] = ((pHalData->RfRegChnlVal[eRFPath] & 0xfffffc00) | param2); ++ PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)eRFPath, param1, bRFRegOffsetMask, pHalData->RfRegChnlVal[eRFPath]); ++ } ++ ++ ++ //s3. post common command - CmdID_End, None ++ ++} ++// <20130708, James> A workaround to eliminate the 2480MHz spur for 8188E I-Cut ++void ++phy_SpurCalibration_8188E( ++ IN PADAPTER Adapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ //DbgPrint("===> phy_SpurCalibration_8188E CurrentChannelBW = %d, CurrentChannel = %d\n", pHalData->CurrentChannelBW, pHalData->CurrentChannel); ++ if(pHalData->CurrentChannelBW == 0 && pHalData->CurrentChannel == 13){ ++ PHY_SetBBReg(Adapter, rOFDM1_CFOTracking, BIT(28), 0x1); //enable CSI Mask ++ PHY_SetBBReg(Adapter, rOFDM1_csi_fix_mask, BIT(26)|BIT(25), 0x3); //Fix CSI Mask Tone ++ } ++ else{ ++ PHY_SetBBReg(Adapter, rOFDM1_CFOTracking, BIT(28), 0x0); //disable CSI Mask ++ PHY_SetBBReg(Adapter, rOFDM1_csi_fix_mask, BIT(26)|BIT(25), 0x0); ++ } ++ ++} ++VOID ++PHY_SwChnl8188E( // Call after initialization ++ IN PADAPTER Adapter, ++ IN u8 channel ++ ) ++{ ++ //PADAPTER Adapter = ADJUST_TO_ADAPTIVE_ADAPTER(pAdapter, _TRUE); ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u8 tmpchannel = pHalData->CurrentChannel; ++ BOOLEAN bResult = _TRUE; ++ ++ if(pHalData->rf_chip == RF_PSEUDO_11N) ++ { ++ //pHalData->SwChnlInProgress=FALSE; ++ return; //return immediately if it is peudo-phy ++ } ++ ++ //if(pHalData->SwChnlInProgress) ++ // return; ++ ++ //if(pHalData->SetBWModeInProgress) ++ // return; ++ ++ //-------------------------------------------- ++ switch(pHalData->CurrentWirelessMode) ++ { ++ case WIRELESS_MODE_A: ++ case WIRELESS_MODE_N_5G: ++ //RT_ASSERT((channel>14), ("WIRELESS_MODE_A but channel<=14")); ++ break; ++ ++ case WIRELESS_MODE_B: ++ //RT_ASSERT((channel<=14), ("WIRELESS_MODE_B but channel>14")); ++ break; ++ ++ case WIRELESS_MODE_G: ++ case WIRELESS_MODE_N_24G: ++ //RT_ASSERT((channel<=14), ("WIRELESS_MODE_G but channel>14")); ++ break; ++ ++ default: ++ //RT_ASSERT(FALSE, ("Invalid WirelessMode(%#x)!!\n", pHalData->CurrentWirelessMode)); ++ break; ++ } ++ //-------------------------------------------- ++ ++ //pHalData->SwChnlInProgress = TRUE; ++ if(channel == 0) ++ channel = 1; ++ ++ pHalData->CurrentChannel=channel; ++ ++ //pHalData->SwChnlStage=0; ++ //pHalData->SwChnlStep=0; ++ ++ if((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved)) ++ { ++ #if 0 ++ //PlatformSetTimer(Adapter, &(pHalData->SwChnlTimer), 0); ++ #else ++ _PHY_SwChnl8192C(Adapter, channel); ++ #endif ++ if (IS_VENDOR_8188E_I_CUT_SERIES(Adapter)) ++ phy_SpurCalibration_8188E( Adapter); ++ if(bResult) ++ { ++ //RT_TRACE(COMP_SCAN, DBG_LOUD, ("PHY_SwChnl8192C SwChnlInProgress TRUE schdule workitem done\n")); ++ } ++ else ++ { ++ //RT_TRACE(COMP_SCAN, DBG_LOUD, ("PHY_SwChnl8192C SwChnlInProgress FALSE schdule workitem error\n")); ++ //if(IS_HARDWARE_TYPE_8192SU(Adapter)) ++ //{ ++ // pHalData->SwChnlInProgress = FALSE; ++ pHalData->CurrentChannel = tmpchannel; ++ //} ++ } ++ ++ } ++ else ++ { ++ //RT_TRACE(COMP_SCAN, DBG_LOUD, ("PHY_SwChnl8192C SwChnlInProgress FALSE driver sleep or unload\n")); ++ //if(IS_HARDWARE_TYPE_8192SU(Adapter)) ++ //{ ++ // pHalData->SwChnlInProgress = FALSE; ++ pHalData->CurrentChannel = tmpchannel; ++ //} ++ } ++} ++ ++ ++static BOOLEAN ++phy_SwChnlStepByStep( ++ IN PADAPTER Adapter, ++ IN u8 channel, ++ IN u8 *stage, ++ IN u8 *step, ++ OUT u32 *delay ++ ) ++{ ++#if 0 ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PCHANNEL_ACCESS_SETTING pChnlAccessSetting; ++ SwChnlCmd PreCommonCmd[MAX_PRECMD_CNT]; ++ u4Byte PreCommonCmdCnt; ++ SwChnlCmd PostCommonCmd[MAX_POSTCMD_CNT]; ++ u4Byte PostCommonCmdCnt; ++ SwChnlCmd RfDependCmd[MAX_RFDEPENDCMD_CNT]; ++ u4Byte RfDependCmdCnt; ++ SwChnlCmd *CurrentCmd; ++ u1Byte eRFPath; ++ u4Byte RfTXPowerCtrl; ++ BOOLEAN bAdjRfTXPowerCtrl = _FALSE; ++ ++ ++ RT_ASSERT((Adapter != NULL), ("Adapter should not be NULL\n")); ++#if(MP_DRIVER != 1) ++ RT_ASSERT(IsLegalChannel(Adapter, channel), ("illegal channel: %d\n", channel)); ++#endif ++ RT_ASSERT((pHalData != NULL), ("pHalData should not be NULL\n")); ++ ++ pChnlAccessSetting = &Adapter->MgntInfo.Info8185.ChannelAccessSetting; ++ RT_ASSERT((pChnlAccessSetting != NULL), ("pChnlAccessSetting should not be NULL\n")); ++ ++ //for(eRFPath = RF_PATH_A; eRFPath NumTotalRFPath; eRFPath++) ++ //for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) ++ //{ ++ // <1> Fill up pre common command. ++ PreCommonCmdCnt = 0; ++ phy_SetSwChnlCmdArray(PreCommonCmd, PreCommonCmdCnt++, MAX_PRECMD_CNT, ++ CmdID_SetTxPowerLevel, 0, 0, 0); ++ phy_SetSwChnlCmdArray(PreCommonCmd, PreCommonCmdCnt++, MAX_PRECMD_CNT, ++ CmdID_End, 0, 0, 0); ++ ++ // <2> Fill up post common command. ++ PostCommonCmdCnt = 0; ++ ++ phy_SetSwChnlCmdArray(PostCommonCmd, PostCommonCmdCnt++, MAX_POSTCMD_CNT, ++ CmdID_End, 0, 0, 0); ++ ++ // <3> Fill up RF dependent command. ++ RfDependCmdCnt = 0; ++ switch( pHalData->RFChipID ) ++ { ++ case RF_8225: ++ RT_ASSERT((channel >= 1 && channel <= 14), ("illegal channel for Zebra: %d\n", channel)); ++ // 2008/09/04 MH Change channel. ++ if(channel==14) channel++; ++ phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, ++ CmdID_RF_WriteReg, rZebra1_Channel, (0x10+channel-1), 10); ++ phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, ++ CmdID_End, 0, 0, 0); ++ break; ++ ++ case RF_8256: ++ // TEST!! This is not the table for 8256!! ++ RT_ASSERT((channel >= 1 && channel <= 14), ("illegal channel for Zebra: %d\n", channel)); ++ phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, ++ CmdID_RF_WriteReg, rRfChannel, channel, 10); ++ phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, ++ CmdID_End, 0, 0, 0); ++ break; ++ ++ case RF_6052: ++ RT_ASSERT((channel >= 1 && channel <= 14), ("illegal channel for Zebra: %d\n", channel)); ++ phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, ++ CmdID_RF_WriteReg, RF_CHNLBW, channel, 10); ++ phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, ++ CmdID_End, 0, 0, 0); ++ ++ break; ++ ++ case RF_8258: ++ break; ++ ++ // For FPGA two MAC verification ++ case RF_PSEUDO_11N: ++ return TRUE; ++ default: ++ RT_ASSERT(FALSE, ("Unknown RFChipID: %d\n", pHalData->RFChipID)); ++ return FALSE; ++ break; ++ } ++ ++ ++ do{ ++ switch(*stage) ++ { ++ case 0: ++ CurrentCmd=&PreCommonCmd[*step]; ++ break; ++ case 1: ++ CurrentCmd=&RfDependCmd[*step]; ++ break; ++ case 2: ++ CurrentCmd=&PostCommonCmd[*step]; ++ break; ++ } ++ ++ if(CurrentCmd->CmdID==CmdID_End) ++ { ++ if((*stage)==2) ++ { ++ return TRUE; ++ } ++ else ++ { ++ (*stage)++; ++ (*step)=0; ++ continue; ++ } ++ } ++ ++ switch(CurrentCmd->CmdID) ++ { ++ case CmdID_SetTxPowerLevel: ++ PHY_SetTxPowerLevel8192C(Adapter,channel); ++ break; ++ case CmdID_WritePortUlong: ++ PlatformEFIOWrite4Byte(Adapter, CurrentCmd->Para1, CurrentCmd->Para2); ++ break; ++ case CmdID_WritePortUshort: ++ PlatformEFIOWrite2Byte(Adapter, CurrentCmd->Para1, (u2Byte)CurrentCmd->Para2); ++ break; ++ case CmdID_WritePortUchar: ++ PlatformEFIOWrite1Byte(Adapter, CurrentCmd->Para1, (u1Byte)CurrentCmd->Para2); ++ break; ++ case CmdID_RF_WriteReg: // Only modify channel for the register now !!!!! ++ for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) ++ { ++#if 1 ++ pHalData->RfRegChnlVal[eRFPath] = ((pHalData->RfRegChnlVal[eRFPath] & 0xfffffc00) | CurrentCmd->Para2); ++ PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)eRFPath, CurrentCmd->Para1, bRFRegOffsetMask, pHalData->RfRegChnlVal[eRFPath]); ++#else ++ PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)eRFPath, CurrentCmd->Para1, bRFRegOffsetMask, (CurrentCmd->Para2)); ++#endif ++ } ++ break; ++ } ++ ++ break; ++ }while(TRUE); ++ //cosa }/*for(Number of RF paths)*/ ++ ++ (*delay)=CurrentCmd->msDelay; ++ (*step)++; ++ return FALSE; ++#endif ++ return _TRUE; ++} ++ ++ ++static BOOLEAN ++phy_SetSwChnlCmdArray( ++ SwChnlCmd* CmdTable, ++ u32 CmdTableIdx, ++ u32 CmdTableSz, ++ SwChnlCmdID CmdID, ++ u32 Para1, ++ u32 Para2, ++ u32 msDelay ++ ) ++{ ++ SwChnlCmd* pCmd; ++ ++ if(CmdTable == NULL) ++ { ++ //RT_ASSERT(FALSE, ("phy_SetSwChnlCmdArray(): CmdTable cannot be NULL.\n")); ++ return _FALSE; ++ } ++ if(CmdTableIdx >= CmdTableSz) ++ { ++ //RT_ASSERT(FALSE, ++ // ("phy_SetSwChnlCmdArray(): Access invalid index, please check size of the table, CmdTableIdx:%ld, CmdTableSz:%ld\n", ++ // CmdTableIdx, CmdTableSz)); ++ return _FALSE; ++ } ++ ++ pCmd = CmdTable + CmdTableIdx; ++ pCmd->CmdID = CmdID; ++ pCmd->Para1 = Para1; ++ pCmd->Para2 = Para2; ++ pCmd->msDelay = msDelay; ++ ++ return _TRUE; ++} ++ ++ ++static void ++phy_FinishSwChnlNow( // We should not call this function directly ++ IN PADAPTER Adapter, ++ IN u8 channel ++ ) ++{ ++#if 0 ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u32 delay; ++ ++ while(!phy_SwChnlStepByStep(Adapter,channel,&pHalData->SwChnlStage,&pHalData->SwChnlStep,&delay)) ++ { ++ if(delay>0) ++ rtw_mdelay_os(delay); ++ } ++#endif ++} ++ ++ ++ ++// ++// Description: ++// Switch channel synchronously. Called by SwChnlByDelayHandler. ++// ++// Implemented by Bruce, 2008-02-14. ++// The following procedure is operted according to SwChanlCallback8190Pci(). ++// However, this procedure is performed synchronously which should be running under ++// passive level. ++// ++VOID ++PHY_SwChnlPhy8192C( // Only called during initialize ++ IN PADAPTER Adapter, ++ IN u8 channel ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ //RT_TRACE(COMP_SCAN | COMP_RM, DBG_LOUD, ("==>PHY_SwChnlPhy8192S(), switch from channel %d to channel %d.\n", pHalData->CurrentChannel, channel)); ++ ++ // Cannot IO. ++ //if(RT_CANNOT_IO(Adapter)) ++ // return; ++ ++ // Channel Switching is in progress. ++ //if(pHalData->SwChnlInProgress) ++ // return; ++ ++ //return immediately if it is peudo-phy ++ if(pHalData->rf_chip == RF_PSEUDO_11N) ++ { ++ //pHalData->SwChnlInProgress=FALSE; ++ return; ++ } ++ ++ //pHalData->SwChnlInProgress = TRUE; ++ if( channel == 0) ++ channel = 1; ++ ++ pHalData->CurrentChannel=channel; ++ ++ //pHalData->SwChnlStage = 0; ++ //pHalData->SwChnlStep = 0; ++ ++ phy_FinishSwChnlNow(Adapter,channel); ++ ++ //pHalData->SwChnlInProgress = FALSE; ++} ++ ++ ++// ++// Description: ++// Configure H/W functionality to enable/disable Monitor mode. ++// Note, because we possibly need to configure BB and RF in this function, ++// so caller should in PASSIVE_LEVEL. 080118, by rcnjko. ++// ++VOID ++PHY_SetMonitorMode8192C( ++ IN PADAPTER pAdapter, ++ IN BOOLEAN bEnableMonitorMode ++ ) ++{ ++#if 0 ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ BOOLEAN bFilterOutNonAssociatedBSSID = FALSE; ++ ++ //2 Note: we may need to stop antenna diversity. ++ if(bEnableMonitorMode) ++ { ++ bFilterOutNonAssociatedBSSID = FALSE; ++ RT_TRACE(COMP_RM, DBG_LOUD, ("PHY_SetMonitorMode8192S(): enable monitor mode\n")); ++ ++ pHalData->bInMonitorMode = TRUE; ++ pAdapter->HalFunc.AllowAllDestAddrHandler(pAdapter, TRUE, TRUE); ++ rtw_hal_set_hwreg(pAdapter, HW_VAR_CHECK_BSSID, (pu1Byte)&bFilterOutNonAssociatedBSSID); ++ } ++ else ++ { ++ bFilterOutNonAssociatedBSSID = TRUE; ++ RT_TRACE(COMP_RM, DBG_LOUD, ("PHY_SetMonitorMode8192S(): disable monitor mode\n")); ++ ++ pAdapter->HalFunc.AllowAllDestAddrHandler(pAdapter, FALSE, TRUE); ++ pHalData->bInMonitorMode = FALSE; ++ rtw_hal_set_hwreg(pAdapter, HW_VAR_CHECK_BSSID, (pu1Byte)&bFilterOutNonAssociatedBSSID); ++ } ++#endif ++} ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: PHYCheckIsLegalRfPath8190Pci() ++ * ++ * Overview: Check different RF type to execute legal judgement. If RF Path is illegal ++ * We will return false. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/15/2007 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++BOOLEAN ++PHY_CheckIsLegalRfPath8192C( ++ IN PADAPTER pAdapter, ++ IN u32 eRFPath) ++{ ++// HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ BOOLEAN rtValue = _TRUE; ++ ++ // NOt check RF Path now.! ++#if 0 ++ if (pHalData->RF_Type == RF_1T2R && eRFPath != RF_PATH_A) ++ { ++ rtValue = FALSE; ++ } ++ if (pHalData->RF_Type == RF_1T2R && eRFPath != RF_PATH_A) ++ { ++ ++ } ++#endif ++ return rtValue; ++ ++} /* PHY_CheckIsLegalRfPath8192C */ ++ ++static VOID _PHY_SetRFPathSwitch( ++ IN PADAPTER pAdapter, ++ IN BOOLEAN bMain, ++ IN BOOLEAN is2T ++ ) ++{ ++ u8 u1bTmp; ++ ++ if(!pAdapter->hw_init_completed) ++ { ++ u1bTmp = rtw_read8(pAdapter, REG_LEDCFG2) | BIT7; ++ rtw_write8(pAdapter, REG_LEDCFG2, u1bTmp); ++ //PHY_SetBBReg(pAdapter, REG_LEDCFG0, BIT23, 0x01); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT13, 0x01); ++ } ++ ++ if(is2T) ++ { ++ if(bMain) ++ PHY_SetBBReg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT5|BIT6, 0x1); //92C_Path_A ++ else ++ PHY_SetBBReg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT5|BIT6, 0x2); //BT ++ } ++ else ++ { ++ ++ if(bMain) ++ PHY_SetBBReg(pAdapter, rFPGA0_XA_RFInterfaceOE, 0x300, 0x2); //Main ++ else ++ PHY_SetBBReg(pAdapter, rFPGA0_XA_RFInterfaceOE, 0x300, 0x1); //Aux ++ } ++ ++} ++ ++//return value TRUE => Main; FALSE => Aux ++ ++static BOOLEAN _PHY_QueryRFPathSwitch( ++ IN PADAPTER pAdapter, ++ IN BOOLEAN is2T ++ ) ++{ ++// if(is2T) ++// return _TRUE; ++ ++ if(!pAdapter->hw_init_completed) ++ { ++ PHY_SetBBReg(pAdapter, REG_LEDCFG0, BIT23, 0x01); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT13, 0x01); ++ } ++ ++ if(is2T) ++ { ++ if(PHY_QueryBBReg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT5|BIT6) == 0x01) ++ return _TRUE; ++ else ++ return _FALSE; ++ } ++ else ++ { ++ if(PHY_QueryBBReg(pAdapter, rFPGA0_XA_RFInterfaceOE, 0x300) == 0x02) ++ return _TRUE; ++ else ++ return _FALSE; ++ } ++} ++ ++ ++static VOID ++_PHY_DumpRFReg(IN PADAPTER pAdapter) ++{ ++ u32 rfRegValue,rfRegOffset; ++ ++ //RTPRINT(FINIT, INIT_RF, ("PHY_DumpRFReg()====>\n")); ++ ++ for(rfRegOffset = 0x00;rfRegOffset<=0x30;rfRegOffset++){ ++ rfRegValue = PHY_QueryRFReg(pAdapter,RF_PATH_A, rfRegOffset, bMaskDWord); ++ //RTPRINT(FINIT, INIT_RF, (" 0x%02x = 0x%08x\n",rfRegOffset,rfRegValue)); ++ } ++ //RTPRINT(FINIT, INIT_RF, ("<===== PHY_DumpRFReg()\n")); ++} ++ ++ ++// ++// Move from phycfg.c to gen.c to be code independent later ++// ++//-------------------------Move to other DIR later----------------------------*/ ++#ifdef CONFIG_USB_HCI ++ ++// ++// Description: ++// To dump all Tx FIFO LLT related link-list table. ++// Added by Roger, 2009.03.10. ++// ++VOID ++DumpBBDbgPort_92CU( ++ IN PADAPTER Adapter ++ ) ++{ ++ ++ //RT_TRACE(COMP_SEND, DBG_WARNING, ("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n")); ++ //RT_TRACE(COMP_SEND, DBG_WARNING, ("BaseBand Debug Ports:\n")); ++ ++ PHY_SetBBReg(Adapter, 0x0908, 0xffff, 0x0000); ++ //RT_TRACE(COMP_SEND, DBG_WARNING, ("Offset[%x]: %x\n", 0xdf4, PHY_QueryBBReg(Adapter, 0x0df4, bMaskDWord))); ++ ++ PHY_SetBBReg(Adapter, 0x0908, 0xffff, 0x0803); ++ //RT_TRACE(COMP_SEND, DBG_WARNING, ("Offset[%x]: %x\n", 0xdf4, PHY_QueryBBReg(Adapter, 0x0df4, bMaskDWord))); ++ ++ PHY_SetBBReg(Adapter, 0x0908, 0xffff, 0x0a06); ++ //RT_TRACE(COMP_SEND, DBG_WARNING, ("Offset[%x]: %x\n", 0xdf4, PHY_QueryBBReg(Adapter, 0x0df4, bMaskDWord))); ++ ++ PHY_SetBBReg(Adapter, 0x0908, 0xffff, 0x0007); ++ //RT_TRACE(COMP_SEND, DBG_WARNING, ("Offset[%x]: %x\n", 0xdf4, PHY_QueryBBReg(Adapter, 0x0df4, bMaskDWord))); ++ ++ PHY_SetBBReg(Adapter, 0x0908, 0xffff, 0x0100); ++ PHY_SetBBReg(Adapter, 0x0a28, 0x00ff0000, 0x000f0000); ++ //RT_TRACE(COMP_SEND, DBG_WARNING, ("Offset[%x]: %x\n", 0xdf4, PHY_QueryBBReg(Adapter, 0x0df4, bMaskDWord))); ++ ++ PHY_SetBBReg(Adapter, 0x0908, 0xffff, 0x0100); ++ PHY_SetBBReg(Adapter, 0x0a28, 0x00ff0000, 0x00150000); ++ //RT_TRACE(COMP_SEND, DBG_WARNING, ("Offset[%x]: %x\n", 0xdf4, PHY_QueryBBReg(Adapter, 0x0df4, bMaskDWord))); ++ ++ //RT_TRACE(COMP_SEND, DBG_WARNING, ("Offset[%x]: %x\n", 0x800, PHY_QueryBBReg(Adapter, 0x0800, bMaskDWord))); ++ //RT_TRACE(COMP_SEND, DBG_WARNING, ("Offset[%x]: %x\n", 0x900, PHY_QueryBBReg(Adapter, 0x0900, bMaskDWord))); ++ //RT_TRACE(COMP_SEND, DBG_WARNING, ("Offset[%x]: %x\n", 0xa00, PHY_QueryBBReg(Adapter, 0x0a00, bMaskDWord))); ++ //RT_TRACE(COMP_SEND, DBG_WARNING, ("Offset[%x]: %x\n", 0xa54, PHY_QueryBBReg(Adapter, 0x0a54, bMaskDWord))); ++ //RT_TRACE(COMP_SEND, DBG_WARNING, ("Offset[%x]: %x\n", 0xa58, PHY_QueryBBReg(Adapter, 0x0a58, bMaskDWord))); ++ ++} ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_rf6052.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_rf6052.c +new file mode 100644 +index 00000000..33f63978 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_rf6052.c +@@ -0,0 +1,1272 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++/****************************************************************************** ++ * ++ * ++ * Module: rtl8192c_rf6052.c ( Source C File) ++ * ++ * Note: Provide RF 6052 series relative API. ++ * ++ * Function: ++ * ++ * Export: ++ * ++ * Abbrev: ++ * ++ * History: ++ * Data Who Remark ++ * ++ * 09/25/2008 MHC Create initial version. ++ * 11/05/2008 MHC Add API for tw power setting. ++ * ++ * ++******************************************************************************/ ++ ++#define _RTL8188E_RF6052_C_ ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++/*---------------------------Define Local Constant---------------------------*/ ++// Define local structure for debug!!!!! ++typedef struct RF_Shadow_Compare_Map { ++ // Shadow register value ++ u32 Value; ++ // Compare or not flag ++ u8 Compare; ++ // Record If it had ever modified unpredicted ++ u8 ErrorOrNot; ++ // Recorver Flag ++ u8 Recorver; ++ // ++ u8 Driver_Write; ++}RF_SHADOW_T; ++/*---------------------------Define Local Constant---------------------------*/ ++ ++ ++/*------------------------Define global variable-----------------------------*/ ++/*------------------------Define global variable-----------------------------*/ ++ ++ ++/*------------------------Define local variable------------------------------*/ ++// 2008/11/20 MH For Debug only, RF ++//static RF_SHADOW_T RF_Shadow[RF6052_MAX_PATH][RF6052_MAX_REG] = {0}; ++static RF_SHADOW_T RF_Shadow[RF6052_MAX_PATH][RF6052_MAX_REG]; ++/*------------------------Define local variable------------------------------*/ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: RF_ChangeTxPath ++ * ++ * Overview: For RL6052, we must change some RF settign for 1T or 2T. ++ * ++ * Input: u2Byte DataRate // 0x80-8f, 0x90-9f ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 09/25/2008 MHC Create Version 0. ++ * Firmwaer support the utility later. ++ * ++ *---------------------------------------------------------------------------*/ ++void rtl8188e_RF_ChangeTxPath( IN PADAPTER Adapter, ++ IN u16 DataRate) ++{ ++// We do not support gain table change inACUT now !!!! Delete later !!! ++#if 0//(RTL92SE_FPGA_VERIFY == 0) ++ static u1Byte RF_Path_Type = 2; // 1 = 1T 2= 2T ++ static u4Byte tx_gain_tbl1[6] ++ = {0x17f50, 0x11f40, 0x0cf30, 0x08720, 0x04310, 0x00100}; ++ static u4Byte tx_gain_tbl2[6] ++ = {0x15ea0, 0x10e90, 0x0c680, 0x08250, 0x04040, 0x00030}; ++ u1Byte i; ++ ++ if (RF_Path_Type == 2 && (DataRate&0xF) <= 0x7) ++ { ++ // Set TX SYNC power G2G3 loop filter ++ PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)RF_PATH_A, ++ RF_TXPA_G2, bRFRegOffsetMask, 0x0f000); ++ PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)RF_PATH_A, ++ RF_TXPA_G3, bRFRegOffsetMask, 0xeacf1); ++ ++ // Change TX AGC gain table ++ for (i = 0; i < 6; i++) ++ PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)RF_PATH_A, ++ RF_TX_AGC, bRFRegOffsetMask, tx_gain_tbl1[i]); ++ ++ // Set PA to high value ++ PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)RF_PATH_A, ++ RF_TXPA_G2, bRFRegOffsetMask, 0x01e39); ++ } ++ else if (RF_Path_Type == 1 && (DataRate&0xF) >= 0x8) ++ { ++ // Set TX SYNC power G2G3 loop filter ++ PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)RF_PATH_A, ++ RF_TXPA_G2, bRFRegOffsetMask, 0x04440); ++ PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)RF_PATH_A, ++ RF_TXPA_G3, bRFRegOffsetMask, 0xea4f1); ++ ++ // Change TX AGC gain table ++ for (i = 0; i < 6; i++) ++ PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)RF_PATH_A, ++ RF_TX_AGC, bRFRegOffsetMask, tx_gain_tbl2[i]); ++ ++ // Set PA low gain ++ PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)RF_PATH_A, ++ RF_TXPA_G2, bRFRegOffsetMask, 0x01e19); ++ } ++#endif ++ ++} /* RF_ChangeTxPath */ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: PHY_RF6052SetBandwidth() ++ * ++ * Overview: This function is called by SetBWModeCallback8190Pci() only ++ * ++ * Input: PADAPTER Adapter ++ * WIRELESS_BANDWIDTH_E Bandwidth //20M or 40M ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Note: For RF type 0222D ++ *---------------------------------------------------------------------------*/ ++VOID ++rtl8188e_PHY_RF6052SetBandwidth( ++ IN PADAPTER Adapter, ++ IN HT_CHANNEL_WIDTH Bandwidth) //20M or 40M ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ switch(Bandwidth) ++ { ++ case HT_CHANNEL_WIDTH_20: ++ pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff) | BIT(10) | BIT(11)); ++ PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]); ++ break; ++ ++ case HT_CHANNEL_WIDTH_40: ++ pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff)| BIT(10)); ++ PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]); ++ break; ++ ++ default: ++ //RT_TRACE(COMP_DBG, DBG_LOUD, ("PHY_SetRF8225Bandwidth(): unknown Bandwidth: %#X\n",Bandwidth )); ++ break; ++ } ++ ++} ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: PHY_RF6052SetCckTxPower ++ * ++ * Overview: ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/05/2008 MHC Simulate 8192series.. ++ * ++ *---------------------------------------------------------------------------*/ ++ ++VOID ++rtl8188e_PHY_RF6052SetCckTxPower( ++ IN PADAPTER Adapter, ++ IN u8* pPowerlevel) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ //PMGNT_INFO pMgntInfo=&Adapter->MgntInfo; ++ u32 TxAGC[2]={0, 0}, tmpval=0,pwrtrac_value; ++ BOOLEAN TurboScanOff = _FALSE; ++ u8 idx1, idx2; ++ u8* ptr; ++ u8 direction; ++ //FOR CE ,must disable turbo scan ++ TurboScanOff = _TRUE; ++ ++ ++ if(pmlmeext->sitesurvey_res.state == SCAN_PROCESS) ++ { ++ TxAGC[RF_PATH_A] = 0x3f3f3f3f; ++ TxAGC[RF_PATH_B] = 0x3f3f3f3f; ++ ++ TurboScanOff = _TRUE;//disable turbo scan ++ ++ if(TurboScanOff) ++ { ++ for(idx1=RF_PATH_A; idx1<=RF_PATH_B; idx1++) ++ { ++ TxAGC[idx1] = ++ pPowerlevel[idx1] | (pPowerlevel[idx1]<<8) | ++ (pPowerlevel[idx1]<<16) | (pPowerlevel[idx1]<<24); ++#ifdef CONFIG_USB_HCI ++ // 2010/10/18 MH For external PA module. We need to limit power index to be less than 0x20. ++ if (TxAGC[idx1] > 0x20 && pHalData->ExternalPA) ++ TxAGC[idx1] = 0x20; ++#endif ++ } ++ } ++ } ++ else ++ { ++// 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. ++// Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. ++// In the future, two mechanism shall be separated from each other and maintained independantly. Thanks for Lanhsin's reminder. ++ if(pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) ++ { ++ TxAGC[RF_PATH_A] = 0x10101010; ++ TxAGC[RF_PATH_B] = 0x10101010; ++ } ++ else if(pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) ++ { ++ TxAGC[RF_PATH_A] = 0x00000000; ++ TxAGC[RF_PATH_B] = 0x00000000; ++ } ++ else ++ { ++ for(idx1=RF_PATH_A; idx1<=RF_PATH_B; idx1++) ++ { ++ TxAGC[idx1] = ++ pPowerlevel[idx1] | (pPowerlevel[idx1]<<8) | ++ (pPowerlevel[idx1]<<16) | (pPowerlevel[idx1]<<24); ++ } ++ ++ if(pHalData->EEPROMRegulatory==0) ++ { ++ tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][6]) + ++ (pHalData->MCSTxPowerLevelOriginalOffset[0][7]<<8); ++ TxAGC[RF_PATH_A] += tmpval; ++ ++ tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][14]) + ++ (pHalData->MCSTxPowerLevelOriginalOffset[0][15]<<24); ++ TxAGC[RF_PATH_B] += tmpval; ++ } ++ } ++ } ++ ++ ++ ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 1, &direction, &pwrtrac_value); ++ //printk("ODM_TxPwrTrackAdjust88E => direction:%02x, pwrtrac_value:%d \n", direction, pwrtrac_value); ++ //printk(" ==> TxAGC:0x%08x \n",TxAGC[0] ); ++ ++ if (direction == 1) // Increase TX pwoer ++ { ++ TxAGC[0] += pwrtrac_value; ++ TxAGC[1] += pwrtrac_value; ++ ++ } ++ else if (direction == 2) // Decrease TX pwoer ++ { ++ TxAGC[0] -= pwrtrac_value; ++ TxAGC[1] -= pwrtrac_value; ++ } ++ ++ for(idx1=RF_PATH_A; idx1<=RF_PATH_B; idx1++) ++ { ++ ptr = (u8*)(&(TxAGC[idx1])); ++ for(idx2=0; idx2<4; idx2++) ++ { ++ if(*ptr > RF6052_MAX_TX_PWR) ++ *ptr = RF6052_MAX_TX_PWR; ++ ptr++; ++ } ++ } ++ //printk(" ==> TxAGC:0x%08x \n",TxAGC[0] ); ++ ++ // rf-A cck tx power ++ tmpval = TxAGC[RF_PATH_A]&0xff; ++ PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval); ++ //printk("CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, rTxAGC_A_CCK1_Mcs32); ++ ++ ++ tmpval = TxAGC[RF_PATH_A]>>8; ++ PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); ++ //printk("CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, rTxAGC_B_CCK11_A_CCK2_11); ++ ++/* ++ // rf-B cck tx power ++ tmpval = TxAGC[RF_PATH_B]>>24; ++ PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval); ++ //printk("CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval, rTxAGC_B_CCK11_A_CCK2_11); ++ tmpval = TxAGC[RF_PATH_B]&0x00ffffff; ++ PHY_SetBBReg(Adapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval); ++ //printk("CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n",tmpval, rTxAGC_B_CCK1_55_Mcs32); ++*/ ++} /* PHY_RF6052SetCckTxPower */ ++ ++#if 0 ++// ++// powerbase0 for OFDM rates ++// powerbase1 for HT MCS rates ++// ++static void getPowerBase( ++ IN PADAPTER Adapter, ++ IN u8* pPowerLevel, ++ IN u8 Channel, ++ IN OUT u32* OfdmBase, ++ IN OUT u32* MCSBase ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u32 powerBase0, powerBase1; ++ u8 Legacy_pwrdiff=0, HT20_pwrdiff=0; ++ u8 i, powerlevel[2]; ++ ++ for(i=0; i<2; i++) ++ { ++ powerlevel[i] = pPowerLevel[i]; ++ Legacy_pwrdiff = pHalData->TxPwrLegacyHtDiff[i][Channel-1]; ++ powerBase0 = powerlevel[i] + Legacy_pwrdiff; ++ ++ powerBase0 = (powerBase0<<24) | (powerBase0<<16) |(powerBase0<<8) |powerBase0; ++ *(OfdmBase+i) = powerBase0; ++ //RTPRINT(FPHY, PHY_TXPWR, (" [OFDM power base index rf(%c) = 0x%x]\n", ((i==0)?'A':'B'), *(OfdmBase+i))); ++ } ++ ++ for(i=0; i<2; i++) ++ { ++ //Check HT20 to HT40 diff ++ if(pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) ++ { ++ HT20_pwrdiff = pHalData->TxPwrHt20Diff[i][Channel-1]; ++ powerlevel[i] += HT20_pwrdiff; ++ } ++ powerBase1 = powerlevel[i]; ++ powerBase1 = (powerBase1<<24) | (powerBase1<<16) |(powerBase1<<8) |powerBase1; ++ *(MCSBase+i) = powerBase1; ++ //RTPRINT(FPHY, PHY_TXPWR, (" [MCS power base index rf(%c) = 0x%x]\n", ((i==0)?'A':'B'), *(MCSBase+i))); ++ } ++} ++#endif ++// ++// powerbase0 for OFDM rates ++// powerbase1 for HT MCS rates ++// ++void getPowerBase88E( ++ IN PADAPTER Adapter, ++ IN u8* pPowerLevelOFDM, ++ IN u8* pPowerLevelBW20, ++ IN u8* pPowerLevelBW40, ++ IN u8 Channel, ++ IN OUT u32* OfdmBase, ++ IN OUT u32* MCSBase ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u32 powerBase0, powerBase1; ++ u8 Legacy_pwrdiff=0; ++ s8 HT20_pwrdiff=0; ++ u8 i, powerlevel[2]; ++ ++ for(i=0; i<2; i++) ++ { ++ powerBase0 = pPowerLevelOFDM[i]; ++ ++ powerBase0 = (powerBase0<<24) | (powerBase0<<16) |(powerBase0<<8) |powerBase0; ++ *(OfdmBase+i) = powerBase0; ++ //DBG_871X(" [OFDM power base index rf(%c) = 0x%x]\n", ((i==0)?'A':'B'), *(OfdmBase+i)); ++ } ++ ++ for(i=0; iNumTotalRFPath; i++) ++ { ++ //Check HT20 to HT40 diff ++ if(pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) ++ { ++ powerlevel[i] = pPowerLevelBW20[i]; ++ } ++ else ++ { ++ powerlevel[i] = pPowerLevelBW40[i]; ++ } ++ powerBase1 = powerlevel[i]; ++ powerBase1 = (powerBase1<<24) | (powerBase1<<16) |(powerBase1<<8) |powerBase1; ++ *(MCSBase+i) = powerBase1; ++ //DBG_871X(" [MCS power base index rf(%c) = 0x%x]\n", ((i==0)?'A':'B'), *(MCSBase+i)); ++ } ++} ++#if 0 ++static void getTxPowerWriteValByRegulatory( ++ IN PADAPTER Adapter, ++ IN u8 Channel, ++ IN u8 index, ++ IN u32* powerBase0, ++ IN u32* powerBase1, ++ OUT u32* pOutWriteVal ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ u8 i, chnlGroup, pwr_diff_limit[4]; ++ u32 writeVal, customer_limit, rf; ++ ++ // ++ // Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate ++ // ++ for(rf=0; rf<2; rf++) ++ { ++ switch(pHalData->EEPROMRegulatory) ++ { ++ case 0: // Realtek better performance ++ // increase power diff defined by Realtek for large power ++ chnlGroup = 0; ++ //RTPRINT(FPHY, PHY_TXPWR, ("MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n", ++ // chnlGroup, index, pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)])); ++ writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] + ++ ((index<2)?powerBase0[rf]:powerBase1[rf]); ++ //RTPRINT(FPHY, PHY_TXPWR, ("RTK better performance, writeVal(%c) = 0x%x\n", ((rf==0)?'A':'B'), writeVal)); ++ break; ++ case 1: // Realtek regulatory ++ // increase power diff defined by Realtek for regulatory ++ { ++ if(pHalData->pwrGroupCnt == 1) ++ chnlGroup = 0; ++ if(pHalData->pwrGroupCnt >= 3) ++ { ++ if(Channel <= 3) ++ chnlGroup = 0; ++ else if(Channel >= 4 && Channel <= 9) ++ chnlGroup = 1; ++ else if(Channel > 9) ++ chnlGroup = 2; ++ ++ if(pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) ++ chnlGroup++; ++ else ++ chnlGroup+=4; ++ } ++ //RTPRINT(FPHY, PHY_TXPWR, ("MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n", ++ //chnlGroup, index, pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)])); ++ writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] + ++ ((index<2)?powerBase0[rf]:powerBase1[rf]); ++ //RTPRINT(FPHY, PHY_TXPWR, ("Realtek regulatory, 20MHz, writeVal(%c) = 0x%x\n", ((rf==0)?'A':'B'), writeVal)); ++ } ++ break; ++ case 2: // Better regulatory ++ // don't increase any power diff ++ writeVal = ((index<2)?powerBase0[rf]:powerBase1[rf]); ++ //RTPRINT(FPHY, PHY_TXPWR, ("Better regulatory, writeVal(%c) = 0x%x\n", ((rf==0)?'A':'B'), writeVal)); ++ break; ++ case 3: // Customer defined power diff. ++ // increase power diff defined by customer. ++ chnlGroup = 0; ++ //RTPRINT(FPHY, PHY_TXPWR, ("MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n", ++ // chnlGroup, index, pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)])); ++ ++ if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40) ++ { ++ //RTPRINT(FPHY, PHY_TXPWR, ("customer's limit, 40MHz rf(%c) = 0x%x\n", ++ // ((rf==0)?'A':'B'), pHalData->PwrGroupHT40[rf][Channel-1])); ++ } ++ else ++ { ++ //RTPRINT(FPHY, PHY_TXPWR, ("customer's limit, 20MHz rf(%c) = 0x%x\n", ++ // ((rf==0)?'A':'B'), pHalData->PwrGroupHT20[rf][Channel-1])); ++ } ++ for (i=0; i<4; i++) ++ { ++ pwr_diff_limit[i] = (u8)((pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)]&(0x7f<<(i*8)))>>(i*8)); ++ if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40) ++ { ++ if(pwr_diff_limit[i] > pHalData->PwrGroupHT40[rf][Channel-1]) ++ pwr_diff_limit[i] = pHalData->PwrGroupHT40[rf][Channel-1]; ++ } ++ else ++ { ++ if(pwr_diff_limit[i] > pHalData->PwrGroupHT20[rf][Channel-1]) ++ pwr_diff_limit[i] = pHalData->PwrGroupHT20[rf][Channel-1]; ++ } ++ } ++ customer_limit = (pwr_diff_limit[3]<<24) | (pwr_diff_limit[2]<<16) | ++ (pwr_diff_limit[1]<<8) | (pwr_diff_limit[0]); ++ //RTPRINT(FPHY, PHY_TXPWR, ("Customer's limit rf(%c) = 0x%x\n", ((rf==0)?'A':'B'), customer_limit)); ++ ++ writeVal = customer_limit + ((index<2)?powerBase0[rf]:powerBase1[rf]); ++ //RTPRINT(FPHY, PHY_TXPWR, ("Customer, writeVal rf(%c)= 0x%x\n", ((rf==0)?'A':'B'), writeVal)); ++ break; ++ default: ++ chnlGroup = 0; ++ writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] + ++ ((index<2)?powerBase0[rf]:powerBase1[rf]); ++ //RTPRINT(FPHY, PHY_TXPWR, ("RTK better performance, writeVal rf(%c) = 0x%x\n", ((rf==0)?'A':'B'), writeVal)); ++ break; ++ } ++ ++// 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. ++// Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. ++// In the future, two mechanism shall be separated from each other and maintained independantly. Thanks for Lanhsin's reminder. ++ ++ if(pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) ++ writeVal = 0x14141414; ++ else if(pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) ++ writeVal = 0x00000000; ++ ++ ++ // 20100628 Joseph: High power mode for BT-Coexist mechanism. ++ // This mechanism is only applied when Driver-Highpower-Mechanism is OFF. ++ if(pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT1) ++ { ++ //RTPRINT(FBT, BT_TRACE, ("Tx Power (-6)\n")); ++ writeVal = writeVal - 0x06060606; ++ } ++ else if(pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT2) ++ { ++ //RTPRINT(FBT, BT_TRACE, ("Tx Power (-0)\n")); ++ writeVal = writeVal; ++ } ++ *(pOutWriteVal+rf) = writeVal; ++ } ++} ++#endif ++void getTxPowerWriteValByRegulatory88E( ++ IN PADAPTER Adapter, ++ IN u8 Channel, ++ IN u8 index, ++ IN u32* powerBase0, ++ IN u32* powerBase1, ++ OUT u32* pOutWriteVal ++ ) ++{ ++ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ u1Byte i, chnlGroup=0, pwr_diff_limit[4], customer_pwr_limit; ++ s1Byte pwr_diff=0; ++ u4Byte writeVal, customer_limit, rf; ++ u1Byte Regulatory = pHalData->EEPROMRegulatory; ++ ++ // ++ // Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate ++ // ++#if 0 // (INTEL_PROXIMITY_SUPPORT == 1) ++ if(pMgntInfo->IntelProximityModeInfo.PowerOutput > 0) ++ Regulatory = 2; ++#endif ++ ++ for(rf=0; rf<2; rf++) ++ { ++ switch(Regulatory) ++ { ++ case 0: // Realtek better performance ++ // increase power diff defined by Realtek for large power ++ chnlGroup = 0; ++ //RTPRINT(FPHY, PHY_TXPWR, ("MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n", ++ // chnlGroup, index, pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)])); ++ writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] + ++ ((index<2)?powerBase0[rf]:powerBase1[rf]); ++ //RTPRINT(FPHY, PHY_TXPWR, ("RTK better performance, writeVal(%c) = 0x%x\n", ((rf==0)?'A':'B'), writeVal)); ++ break; ++ case 1: // Realtek regulatory ++ // increase power diff defined by Realtek for regulatory ++ { ++ if(pHalData->pwrGroupCnt == 1) ++ chnlGroup = 0; ++ //if(pHalData->pwrGroupCnt >= pHalData->PGMaxGroup) ++ { ++ if (Channel < 3) // Chanel 1-2 ++ chnlGroup = 0; ++ else if (Channel < 6) // Channel 3-5 ++ chnlGroup = 1; ++ else if(Channel <9) // Channel 6-8 ++ chnlGroup = 2; ++ else if(Channel <12) // Channel 9-11 ++ chnlGroup = 3; ++ else if(Channel <14) // Channel 12-13 ++ chnlGroup = 4; ++ else if(Channel ==14) // Channel 14 ++ chnlGroup = 4; ++ ++ if(pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) ++ chnlGroup++; ++ else ++ chnlGroup+=6; ++ ++/* ++ if(Channel <= 3) ++ chnlGroup = 0; ++ else if(Channel >= 4 && Channel <= 9) ++ chnlGroup = 1; ++ else if(Channel > 9) ++ chnlGroup = 2; ++ ++ ++ if(pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) ++ chnlGroup++; ++ else ++ chnlGroup+=4; ++*/ ++ } ++ //RTPRINT(FPHY, PHY_TXPWR, ("MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n", ++ //chnlGroup, index, pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)])); ++ writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] + ++ ((index<2)?powerBase0[rf]:powerBase1[rf]); ++ //RTPRINT(FPHY, PHY_TXPWR, ("Realtek regulatory, 20MHz, writeVal(%c) = 0x%x\n", ((rf==0)?'A':'B'), writeVal)); ++ } ++ break; ++ case 2: // Better regulatory ++ // don't increase any power diff ++ writeVal = ((index<2)?powerBase0[rf]:powerBase1[rf]); ++ //RTPRINT(FPHY, PHY_TXPWR, ("Better regulatory, writeVal(%c) = 0x%x\n", ((rf==0)?'A':'B'), writeVal)); ++ break; ++ case 3: // Customer defined power diff. ++ // increase power diff defined by customer. ++ chnlGroup = 0; ++ //RTPRINT(FPHY, PHY_TXPWR, ("MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n", ++ // chnlGroup, index, pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)])); ++ ++ /* ++ if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20_40) ++ { ++ RTPRINT(FPHY, PHY_TXPWR, ("customer's limit, 40MHz rf(%c) = 0x%x\n", ++ ((rf==0)?'A':'B'), pHalData->PwrGroupHT40[rf][Channel-1])); ++ } ++ else ++ { ++ RTPRINT(FPHY, PHY_TXPWR, ("customer's limit, 20MHz rf(%c) = 0x%x\n", ++ ((rf==0)?'A':'B'), pHalData->PwrGroupHT20[rf][Channel-1])); ++ }*/ ++ ++ if(index < 2) ++ pwr_diff = pHalData->TxPwrLegacyHtDiff[rf][Channel-1]; ++ else if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) ++ pwr_diff = pHalData->TxPwrHt20Diff[rf][Channel-1]; ++ ++ //RTPRINT(FPHY, PHY_TXPWR, ("power diff rf(%c) = 0x%x\n", ((rf==0)?'A':'B'), pwr_diff)); ++ ++ if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40) ++ customer_pwr_limit = pHalData->PwrGroupHT40[rf][Channel-1]; ++ else ++ customer_pwr_limit = pHalData->PwrGroupHT20[rf][Channel-1]; ++ ++ //RTPRINT(FPHY, PHY_TXPWR, ("customer pwr limit rf(%c) = 0x%x\n", ((rf==0)?'A':'B'), customer_pwr_limit)); ++ ++ if(pwr_diff >= customer_pwr_limit) ++ pwr_diff = 0; ++ else ++ pwr_diff = customer_pwr_limit - pwr_diff; ++ ++ for (i=0; i<4; i++) ++ { ++ pwr_diff_limit[i] = (u1Byte)((pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)]&(0x7f<<(i*8)))>>(i*8)); ++ ++ if(pwr_diff_limit[i] > pwr_diff) ++ pwr_diff_limit[i] = pwr_diff; ++ } ++ customer_limit = (pwr_diff_limit[3]<<24) | (pwr_diff_limit[2]<<16) | ++ (pwr_diff_limit[1]<<8) | (pwr_diff_limit[0]); ++ //RTPRINT(FPHY, PHY_TXPWR, ("Customer's limit rf(%c) = 0x%x\n", ((rf==0)?'A':'B'), customer_limit)); ++ writeVal = customer_limit + ((index<2)?powerBase0[rf]:powerBase1[rf]); ++ //RTPRINT(FPHY, PHY_TXPWR, ("Customer, writeVal rf(%c)= 0x%x\n", ((rf==0)?'A':'B'), writeVal)); ++ break; ++ default: ++ chnlGroup = 0; ++ writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] + ++ ((index<2)?powerBase0[rf]:powerBase1[rf]); ++ //RTPRINT(FPHY, PHY_TXPWR, ("RTK better performance, writeVal rf(%c) = 0x%x\n", ((rf==0)?'A':'B'), writeVal)); ++ break; ++ } ++ ++// 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. ++// Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. ++// In the future, two mechanism shall be separated from each other and maintained independantly. Thanks for Lanhsin's reminder. ++ //92d do not need this ++ if(pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) ++ writeVal = 0x14141414; ++ else if(pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) ++ writeVal = 0x00000000; ++ ++ // 20100628 Joseph: High power mode for BT-Coexist mechanism. ++ // This mechanism is only applied when Driver-Highpower-Mechanism is OFF. ++ if(pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT1) ++ { ++ //RTPRINT(FBT, BT_TRACE, ("Tx Power (-6)\n")); ++ writeVal = writeVal - 0x06060606; ++ } ++ else if(pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT2) ++ { ++ //RTPRINT(FBT, BT_TRACE, ("Tx Power (-0)\n")); ++ writeVal = writeVal ; ++ } ++ /* ++ if(pMgntInfo->bDisableTXPowerByRate) ++ { ++ // add for OID_RT_11N_TX_POWER_BY_RATE ,disable tx powre change by rate ++ writeVal = 0x2c2c2c2c; ++ } ++ */ ++ *(pOutWriteVal+rf) = writeVal; ++ } ++} ++ ++static void writeOFDMPowerReg88E( ++ IN PADAPTER Adapter, ++ IN u8 index, ++ IN u32* pValue ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u16 RegOffset_A[6] = { rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24, ++ rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04, ++ rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12}; ++ u16 RegOffset_B[6] = { rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24, ++ rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04, ++ rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12}; ++ u8 i, rf, pwr_val[4]; ++ u32 writeVal; ++ u16 RegOffset; ++ ++ for(rf=0; rf<2; rf++) ++ { ++ writeVal = pValue[rf]; ++ for(i=0; i<4; i++) ++ { ++ pwr_val[i] = (u8)((writeVal & (0x7f<<(i*8)))>>(i*8)); ++ if (pwr_val[i] > RF6052_MAX_TX_PWR) ++ pwr_val[i] = RF6052_MAX_TX_PWR; ++ } ++ writeVal = (pwr_val[3]<<24) | (pwr_val[2]<<16) |(pwr_val[1]<<8) |pwr_val[0]; ++ ++ if(rf == 0) ++ RegOffset = RegOffset_A[index]; ++ else ++ RegOffset = RegOffset_B[index]; ++ ++ PHY_SetBBReg(Adapter, RegOffset, bMaskDWord, writeVal); ++ //printk("Set OFDM tx pwr- 0x%x = %08x\n", RegOffset, writeVal); ++ ++ // 201005115 Joseph: Set Tx Power diff for Tx power training mechanism. ++ if(((pHalData->rf_type == RF_2T2R) && ++ (RegOffset == rTxAGC_A_Mcs15_Mcs12 || RegOffset == rTxAGC_B_Mcs15_Mcs12))|| ++ ((pHalData->rf_type != RF_2T2R) && ++ (RegOffset == rTxAGC_A_Mcs07_Mcs04 || RegOffset == rTxAGC_B_Mcs07_Mcs04)) ) ++ { ++ writeVal = pwr_val[3]; ++ if(RegOffset == rTxAGC_A_Mcs15_Mcs12 || RegOffset == rTxAGC_A_Mcs07_Mcs04) ++ RegOffset = 0xc90; ++ if(RegOffset == rTxAGC_B_Mcs15_Mcs12 || RegOffset == rTxAGC_B_Mcs07_Mcs04) ++ RegOffset = 0xc98; ++ for(i=0; i<3; i++) ++ { ++ if(i!=2) ++ writeVal = (writeVal>8)?(writeVal-8):0; ++ else ++ writeVal = (writeVal>6)?(writeVal-6):0; ++ rtw_write8(Adapter, (u32)(RegOffset+i), (u8)writeVal); ++ } ++ } ++ } ++} ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: PHY_RF6052SetOFDMTxPower ++ * ++ * Overview: For legacy and HY OFDM, we must read EEPROM TX power index for ++ * different channel and read original value in TX power register area from ++ * 0xe00. We increase offset and original value to be correct tx pwr. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/05/2008 MHC Simulate 8192 series method. ++ * 01/06/2009 MHC 1. Prevent Path B tx power overflow or underflow dure to ++ * A/B pwr difference or legacy/HT pwr diff. ++ * 2. We concern with path B legacy/HT OFDM difference. ++ * 01/22/2009 MHC Support new EPRO format from SD3. ++ * ++ *---------------------------------------------------------------------------*/ ++ ++VOID ++rtl8188e_PHY_RF6052SetOFDMTxPower( ++ IN PADAPTER Adapter, ++ IN u8* pPowerLevelOFDM, ++ IN u8* pPowerLevelBW20, ++ IN u8* pPowerLevelBW40, ++ IN u8 Channel) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u32 writeVal[2], powerBase0[2], powerBase1[2], pwrtrac_value; ++ u8 direction; ++ u8 index = 0; ++ ++ ++ //DBG_871X("PHY_RF6052SetOFDMTxPower, channel(%d) \n", Channel); ++ ++ getPowerBase88E(Adapter, pPowerLevelOFDM,pPowerLevelBW20,pPowerLevelBW40, Channel, &powerBase0[0], &powerBase1[0]); ++ ++ // ++ // 2012/04/23 MH According to power tracking value, we need to revise OFDM tx power. ++ // This is ued to fix unstable power tracking mode. ++ // ++ ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 0, &direction, &pwrtrac_value); ++ ++ for(index=0; index<6; index++) ++ { ++ getTxPowerWriteValByRegulatory88E(Adapter, Channel, index, ++ &powerBase0[0], &powerBase1[0], &writeVal[0]); ++ ++ if (direction == 1) ++ { ++ writeVal[0] += pwrtrac_value; ++ writeVal[1] += pwrtrac_value; ++ } ++ else if (direction == 2) ++ { ++ writeVal[0] -= pwrtrac_value; ++ writeVal[1] -= pwrtrac_value; ++ } ++ ++ writeOFDMPowerReg88E(Adapter, index, &writeVal[0]); ++ } ++} ++ ++ ++static VOID ++phy_RF6052_Config_HardCode( ++ IN PADAPTER Adapter ++ ) ++{ ++ ++ // Set Default Bandwidth to 20M ++ //Adapter->HalFunc .SetBWModeHandler(Adapter, HT_CHANNEL_WIDTH_20); ++ ++ // TODO: Set Default Channel to channel one for RTL8225 ++ ++} ++ ++static int ++phy_RF6052_Config_ParaFile( ++ IN PADAPTER Adapter ++ ) ++{ ++ u32 u4RegValue; ++ u8 eRFPath; ++ BB_REGISTER_DEFINITION_T *pPhyReg; ++ ++ int rtStatus = _SUCCESS; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ static char sz88eRadioAFile[] = RTL8188E_PHY_RADIO_A; ++ static char sz88eRadioBFile[] = RTL8188E_PHY_RADIO_B; ++ char *pszRadioAFile, *pszRadioBFile; ++ ++ ++ ++ pszRadioAFile = sz88eRadioAFile; ++ pszRadioBFile = sz88eRadioBFile; ++ ++ ++ //3//----------------------------------------------------------------- ++ //3// <2> Initialize RF ++ //3//----------------------------------------------------------------- ++ //for(eRFPath = RF_PATH_A; eRFPath NumTotalRFPath; eRFPath++) ++ for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) ++ { ++ ++ pPhyReg = &pHalData->PHYRegDef[eRFPath]; ++ ++ /*----Store original RFENV control type----*/ ++ switch(eRFPath) ++ { ++ case RF_PATH_A: ++ case RF_PATH_C: ++ u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV); ++ break; ++ case RF_PATH_B : ++ case RF_PATH_D: ++ u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16); ++ break; ++ } ++ ++ /*----Set RF_ENV enable----*/ ++ PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1); ++ rtw_udelay_os(1);//PlatformStallExecution(1); ++ ++ /*----Set RF_ENV output high----*/ ++ PHY_SetBBReg(Adapter, pPhyReg->rfintfo, bRFSI_RFENV, 0x1); ++ rtw_udelay_os(1);//PlatformStallExecution(1); ++ ++ /* Set bit number of Address and Data for RF register */ ++ PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0); // Set 1 to 4 bits for 8255 ++ rtw_udelay_os(1);//PlatformStallExecution(1); ++ ++ PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); // Set 0 to 12 bits for 8255 ++ rtw_udelay_os(1);//PlatformStallExecution(1); ++ ++ /*----Initialize RF fom connfiguration file----*/ ++ switch(eRFPath) ++ { ++ case RF_PATH_A: ++#ifdef CONFIG_EMBEDDED_FWIMG ++ #ifdef CONFIG_PHY_SETTING_WITH_ODM ++ if(HAL_STATUS_FAILURE ==ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv,(ODM_RF_RADIO_PATH_E)eRFPath, (ODM_RF_RADIO_PATH_E)eRFPath)) ++ rtStatus= _FAIL; ++ #else ++ rtStatus= rtl8188e_PHY_ConfigRFWithHeaderFile(Adapter,(RF_RADIO_PATH_E)eRFPath); ++ #endif//#ifdef CONFIG_PHY_SETTING_WITH_ODM ++#else ++ rtStatus = rtl8188e_PHY_ConfigRFWithParaFile(Adapter, pszRadioAFile, (RF_RADIO_PATH_E)eRFPath); ++#endif//#ifdef CONFIG_EMBEDDED_FWIMG ++ break; ++ case RF_PATH_B: ++#ifdef CONFIG_EMBEDDED_FWIMG ++ #ifdef CONFIG_PHY_SETTING_WITH_ODM ++ if(HAL_STATUS_FAILURE ==ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv,(ODM_RF_RADIO_PATH_E)eRFPath, (ODM_RF_RADIO_PATH_E)eRFPath)) ++ rtStatus= _FAIL; ++ #else ++ rtStatus = rtl8188e_PHY_ConfigRFWithHeaderFile(Adapter,(RF_RADIO_PATH_E)eRFPath); ++ #endif //#ifdef CONFIG_PHY_SETTING_WITH_ODM ++#else ++ rtStatus =rtl8188e_PHY_ConfigRFWithParaFile(Adapter, pszRadioBFile, (RF_RADIO_PATH_E)eRFPath); ++#endif ++ break; ++ case RF_PATH_C: ++ break; ++ case RF_PATH_D: ++ break; ++ } ++ ++ /*----Restore RFENV control type----*/; ++ switch(eRFPath) ++ { ++ case RF_PATH_A: ++ case RF_PATH_C: ++ PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue); ++ break; ++ case RF_PATH_B : ++ case RF_PATH_D: ++ PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue); ++ break; ++ } ++ ++ if(rtStatus != _SUCCESS){ ++ //RT_TRACE(COMP_FPGA, DBG_LOUD, ("phy_RF6052_Config_ParaFile():Radio[%d] Fail!!", eRFPath)); ++ goto phy_RF6052_Config_ParaFile_Fail; ++ } ++ ++ } ++ ++ //RT_TRACE(COMP_INIT, DBG_LOUD, ("<---phy_RF6052_Config_ParaFile()\n")); ++ return rtStatus; ++ ++phy_RF6052_Config_ParaFile_Fail: ++ return rtStatus; ++} ++ ++ ++int ++PHY_RF6052_Config8188E( ++ IN PADAPTER Adapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ int rtStatus = _SUCCESS; ++ ++ // ++ // Initialize general global value ++ // ++ // TODO: Extend RF_PATH_C and RF_PATH_D in the future ++ if(pHalData->rf_type == RF_1T1R) ++ pHalData->NumTotalRFPath = 1; ++ else ++ pHalData->NumTotalRFPath = 2; ++ ++ // ++ // Config BB and RF ++ // ++ rtStatus = phy_RF6052_Config_ParaFile(Adapter); ++#if 0 ++ switch( Adapter->MgntInfo.bRegHwParaFile ) ++ { ++ case 0: ++ phy_RF6052_Config_HardCode(Adapter); ++ break; ++ ++ case 1: ++ rtStatus = phy_RF6052_Config_ParaFile(Adapter); ++ break; ++ ++ case 2: ++ // Partial Modify. ++ phy_RF6052_Config_HardCode(Adapter); ++ phy_RF6052_Config_ParaFile(Adapter); ++ break; ++ ++ default: ++ phy_RF6052_Config_HardCode(Adapter); ++ break; ++ } ++#endif ++ return rtStatus; ++ ++} ++ ++ ++// ++// ==> RF shadow Operation API Code Section!!! ++// ++/*----------------------------------------------------------------------------- ++ * Function: PHY_RFShadowRead ++ * PHY_RFShadowWrite ++ * PHY_RFShadowCompare ++ * PHY_RFShadowRecorver ++ * PHY_RFShadowCompareAll ++ * PHY_RFShadowRecorverAll ++ * PHY_RFShadowCompareFlagSet ++ * PHY_RFShadowRecorverFlagSet ++ * ++ * Overview: When we set RF register, we must write shadow at first. ++ * When we are running, we must compare shadow abd locate error addr. ++ * Decide to recorver or not. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/20/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++u32 ++PHY_RFShadowRead( ++ IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath, ++ IN u32 Offset) ++{ ++ return RF_Shadow[eRFPath][Offset].Value; ++ ++} /* PHY_RFShadowRead */ ++ ++ ++VOID ++PHY_RFShadowWrite( ++ IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath, ++ IN u32 Offset, ++ IN u32 Data) ++{ ++ RF_Shadow[eRFPath][Offset].Value = (Data & bRFRegOffsetMask); ++ RF_Shadow[eRFPath][Offset].Driver_Write = _TRUE; ++ ++} /* PHY_RFShadowWrite */ ++ ++ ++BOOLEAN ++PHY_RFShadowCompare( ++ IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath, ++ IN u32 Offset) ++{ ++ u32 reg; ++ // Check if we need to check the register ++ if (RF_Shadow[eRFPath][Offset].Compare == _TRUE) ++ { ++ reg = PHY_QueryRFReg(Adapter, eRFPath, Offset, bRFRegOffsetMask); ++ // Compare shadow and real rf register for 20bits!! ++ if (RF_Shadow[eRFPath][Offset].Value != reg) ++ { ++ // Locate error position. ++ RF_Shadow[eRFPath][Offset].ErrorOrNot = _TRUE; ++ //RT_TRACE(COMP_INIT, DBG_LOUD, ++ //("PHY_RFShadowCompare RF-%d Addr%02lx Err = %05lx\n", ++ //eRFPath, Offset, reg)); ++ } ++ return RF_Shadow[eRFPath][Offset].ErrorOrNot ; ++ } ++ return _FALSE; ++} /* PHY_RFShadowCompare */ ++ ++ ++VOID ++PHY_RFShadowRecorver( ++ IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath, ++ IN u32 Offset) ++{ ++ // Check if the address is error ++ if (RF_Shadow[eRFPath][Offset].ErrorOrNot == _TRUE) ++ { ++ // Check if we need to recorver the register. ++ if (RF_Shadow[eRFPath][Offset].Recorver == _TRUE) ++ { ++ PHY_SetRFReg(Adapter, eRFPath, Offset, bRFRegOffsetMask, ++ RF_Shadow[eRFPath][Offset].Value); ++ //RT_TRACE(COMP_INIT, DBG_LOUD, ++ //("PHY_RFShadowRecorver RF-%d Addr%02lx=%05lx", ++ //eRFPath, Offset, RF_Shadow[eRFPath][Offset].Value)); ++ } ++ } ++ ++} /* PHY_RFShadowRecorver */ ++ ++ ++VOID ++PHY_RFShadowCompareAll( ++ IN PADAPTER Adapter) ++{ ++ u32 eRFPath; ++ u32 Offset; ++ ++ for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) ++ { ++ for (Offset = 0; Offset <= RF6052_MAX_REG; Offset++) ++ { ++ PHY_RFShadowCompare(Adapter, (RF_RADIO_PATH_E)eRFPath, Offset); ++ } ++ } ++ ++} /* PHY_RFShadowCompareAll */ ++ ++ ++VOID ++PHY_RFShadowRecorverAll( ++ IN PADAPTER Adapter) ++{ ++ u32 eRFPath; ++ u32 Offset; ++ ++ for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) ++ { ++ for (Offset = 0; Offset <= RF6052_MAX_REG; Offset++) ++ { ++ PHY_RFShadowRecorver(Adapter, (RF_RADIO_PATH_E)eRFPath, Offset); ++ } ++ } ++ ++} /* PHY_RFShadowRecorverAll */ ++ ++ ++VOID ++PHY_RFShadowCompareFlagSet( ++ IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath, ++ IN u32 Offset, ++ IN u8 Type) ++{ ++ // Set True or False!!! ++ RF_Shadow[eRFPath][Offset].Compare = Type; ++ ++} /* PHY_RFShadowCompareFlagSet */ ++ ++ ++VOID ++PHY_RFShadowRecorverFlagSet( ++ IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath, ++ IN u32 Offset, ++ IN u8 Type) ++{ ++ // Set True or False!!! ++ RF_Shadow[eRFPath][Offset].Recorver= Type; ++ ++} /* PHY_RFShadowRecorverFlagSet */ ++ ++ ++VOID ++PHY_RFShadowCompareFlagSetAll( ++ IN PADAPTER Adapter) ++{ ++ u32 eRFPath; ++ u32 Offset; ++ ++ for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) ++ { ++ for (Offset = 0; Offset <= RF6052_MAX_REG; Offset++) ++ { ++ // 2008/11/20 MH For S3S4 test, we only check reg 26/27 now!!!! ++ if (Offset != 0x26 && Offset != 0x27) ++ PHY_RFShadowCompareFlagSet(Adapter, (RF_RADIO_PATH_E)eRFPath, Offset, _FALSE); ++ else ++ PHY_RFShadowCompareFlagSet(Adapter, (RF_RADIO_PATH_E)eRFPath, Offset, _TRUE); ++ } ++ } ++ ++} /* PHY_RFShadowCompareFlagSetAll */ ++ ++ ++VOID ++PHY_RFShadowRecorverFlagSetAll( ++ IN PADAPTER Adapter) ++{ ++ u32 eRFPath; ++ u32 Offset; ++ ++ for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) ++ { ++ for (Offset = 0; Offset <= RF6052_MAX_REG; Offset++) ++ { ++ // 2008/11/20 MH For S3S4 test, we only check reg 26/27 now!!!! ++ if (Offset != 0x26 && Offset != 0x27) ++ PHY_RFShadowRecorverFlagSet(Adapter, (RF_RADIO_PATH_E)eRFPath, Offset, _FALSE); ++ else ++ PHY_RFShadowRecorverFlagSet(Adapter, (RF_RADIO_PATH_E)eRFPath, Offset, _TRUE); ++ } ++ } ++ ++} /* PHY_RFShadowCompareFlagSetAll */ ++ ++VOID ++PHY_RFShadowRefresh( ++ IN PADAPTER Adapter) ++{ ++ u32 eRFPath; ++ u32 Offset; ++ ++ for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) ++ { ++ for (Offset = 0; Offset <= RF6052_MAX_REG; Offset++) ++ { ++ RF_Shadow[eRFPath][Offset].Value = 0; ++ RF_Shadow[eRFPath][Offset].Compare = _FALSE; ++ RF_Shadow[eRFPath][Offset].Recorver = _FALSE; ++ RF_Shadow[eRFPath][Offset].ErrorOrNot = _FALSE; ++ RF_Shadow[eRFPath][Offset].Driver_Write = _FALSE; ++ } ++ } ++ ++} /* PHY_RFShadowRead */ ++ ++/* End of HalRf6052.c */ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_rxdesc.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_rxdesc.c +new file mode 100644 +index 00000000..7489a66a +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_rxdesc.c +@@ -0,0 +1,350 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTL8188E_REDESC_C_ ++ ++#include ++#include ++#include ++#include ++ ++static s32 translate2dbm(u8 signal_strength_idx) ++{ ++ s32 signal_power; // in dBm. ++ ++ ++ // Translate to dBm (x=0.5y-95). ++ signal_power = (s32)((signal_strength_idx + 1) >> 1); ++ signal_power -= 95; ++ ++ return signal_power; ++} ++ ++ ++static void process_rssi(_adapter *padapter,union recv_frame *prframe) ++{ ++ u32 last_rssi, tmp_val; ++ struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; ++#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS ++ struct signal_stat * signal_stat = &padapter->recvpriv.signal_strength_data; ++#endif //CONFIG_NEW_SIGNAL_STAT_PROCESS ++ ++ //DBG_8192C("process_rssi=> pattrib->rssil(%d) signal_strength(%d)\n ",pattrib->RecvSignalPower,pattrib->signal_strength); ++ //if(pRfd->Status.bPacketToSelf || pRfd->Status.bPacketBeacon) ++ { ++ ++ #ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS ++ if(signal_stat->update_req) { ++ signal_stat->total_num = 0; ++ signal_stat->total_val = 0; ++ signal_stat->update_req = 0; ++ } ++ ++ signal_stat->total_num++; ++ signal_stat->total_val += pattrib->phy_info.SignalStrength; ++ signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num; ++ #else //CONFIG_NEW_SIGNAL_STAT_PROCESS ++ ++ //Adapter->RxStats.RssiCalculateCnt++; //For antenna Test ++ if(padapter->recvpriv.signal_strength_data.total_num++ >= PHY_RSSI_SLID_WIN_MAX) ++ { ++ padapter->recvpriv.signal_strength_data.total_num = PHY_RSSI_SLID_WIN_MAX; ++ last_rssi = padapter->recvpriv.signal_strength_data.elements[padapter->recvpriv.signal_strength_data.index]; ++ padapter->recvpriv.signal_strength_data.total_val -= last_rssi; ++ } ++ padapter->recvpriv.signal_strength_data.total_val +=pattrib->phy_info.SignalStrength; ++ ++ padapter->recvpriv.signal_strength_data.elements[padapter->recvpriv.signal_strength_data.index++] = pattrib->phy_info.SignalStrength; ++ if(padapter->recvpriv.signal_strength_data.index >= PHY_RSSI_SLID_WIN_MAX) ++ padapter->recvpriv.signal_strength_data.index = 0; ++ ++ ++ tmp_val = padapter->recvpriv.signal_strength_data.total_val/padapter->recvpriv.signal_strength_data.total_num; ++ ++ if(padapter->recvpriv.is_signal_dbg) { ++ padapter->recvpriv.signal_strength= padapter->recvpriv.signal_strength_dbg; ++ padapter->recvpriv.rssi=(s8)translate2dbm((u8)padapter->recvpriv.signal_strength_dbg); ++ } else { ++ padapter->recvpriv.signal_strength= tmp_val; ++ padapter->recvpriv.rssi=(s8)translate2dbm((u8)tmp_val); ++ } ++ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("UI RSSI = %d, ui_rssi.TotalVal = %d, ui_rssi.TotalNum = %d\n", tmp_val, padapter->recvpriv.signal_strength_data.total_val,padapter->recvpriv.signal_strength_data.total_num)); ++ #endif //CONFIG_NEW_SIGNAL_STAT_PROCESS ++ } ++ ++}// Process_UI_RSSI_8192C ++ ++ ++ ++static void process_link_qual(_adapter *padapter,union recv_frame *prframe) ++{ ++ u32 last_evm=0, tmpVal; ++ struct rx_pkt_attrib *pattrib; ++#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS ++ struct signal_stat * signal_stat; ++#endif //CONFIG_NEW_SIGNAL_STAT_PROCESS ++ ++ if(prframe == NULL || padapter==NULL){ ++ return; ++ } ++ ++ pattrib = &prframe->u.hdr.attrib; ++#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS ++ signal_stat = &padapter->recvpriv.signal_qual_data; ++#endif //CONFIG_NEW_SIGNAL_STAT_PROCESS ++ ++ //DBG_8192C("process_link_qual=> pattrib->signal_qual(%d)\n ",pattrib->signal_qual); ++ ++#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS ++ if(signal_stat->update_req) { ++ signal_stat->total_num = 0; ++ signal_stat->total_val = 0; ++ signal_stat->update_req = 0; ++ } ++ ++ signal_stat->total_num++; ++ signal_stat->total_val += pattrib->phy_info.SignalQuality; ++ signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num; ++ ++#else //CONFIG_NEW_SIGNAL_STAT_PROCESS ++ if(pattrib->phy_info.SignalQuality != 0) ++ { ++ // ++ // 1. Record the general EVM to the sliding window. ++ // ++ if(padapter->recvpriv.signal_qual_data.total_num++ >= PHY_LINKQUALITY_SLID_WIN_MAX) ++ { ++ padapter->recvpriv.signal_qual_data.total_num = PHY_LINKQUALITY_SLID_WIN_MAX; ++ last_evm = padapter->recvpriv.signal_qual_data.elements[padapter->recvpriv.signal_qual_data.index]; ++ padapter->recvpriv.signal_qual_data.total_val -= last_evm; ++ } ++ padapter->recvpriv.signal_qual_data.total_val += pattrib->phy_info.SignalQuality; ++ ++ padapter->recvpriv.signal_qual_data.elements[padapter->recvpriv.signal_qual_data.index++] = pattrib->phy_info.SignalQuality; ++ if(padapter->recvpriv.signal_qual_data.index >= PHY_LINKQUALITY_SLID_WIN_MAX) ++ padapter->recvpriv.signal_qual_data.index = 0; ++ ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("Total SQ=%d pattrib->signal_qual= %d\n", padapter->recvpriv.signal_qual_data.total_val, pattrib->phy_info.SignalQuality)); ++ ++ // <1> Showed on UI for user, in percentage. ++ tmpVal = padapter->recvpriv.signal_qual_data.total_val/padapter->recvpriv.signal_qual_data.total_num; ++ padapter->recvpriv.signal_qual=(u8)tmpVal; ++ ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,(" pattrib->signal_qual =%d\n", pattrib->phy_info.SignalQuality)); ++ } ++#endif //CONFIG_NEW_SIGNAL_STAT_PROCESS ++ ++} ++ ++//void rtl8188e_process_phy_info(_adapter *padapter, union recv_frame *prframe) ++void rtl8188e_process_phy_info(_adapter *padapter, void *prframe) ++{ ++ union recv_frame *precvframe = (union recv_frame *)prframe; ++ ++ // ++ // Check RSSI ++ // ++ process_rssi(padapter, precvframe); ++ // ++ // Check PWDB. ++ // ++ //process_PWDB(padapter, precvframe); ++ ++ //UpdateRxSignalStatistics8192C(Adapter, pRfd); ++ // ++ // Check EVM ++ // ++ process_link_qual(padapter, precvframe); ++ ++} ++ ++ ++void update_recvframe_attrib_88e( ++ union recv_frame *precvframe, ++ struct recv_stat *prxstat) ++{ ++ struct rx_pkt_attrib *pattrib; ++ struct recv_stat report; ++ PRXREPORT prxreport; ++ //struct recv_frame_hdr *phdr; ++ ++ //phdr = &precvframe->u.hdr; ++ ++ report.rxdw0 = le32_to_cpu(prxstat->rxdw0); ++ report.rxdw1 = le32_to_cpu(prxstat->rxdw1); ++ report.rxdw2 = le32_to_cpu(prxstat->rxdw2); ++ report.rxdw3 = le32_to_cpu(prxstat->rxdw3); ++ report.rxdw4 = le32_to_cpu(prxstat->rxdw4); ++ report.rxdw5 = le32_to_cpu(prxstat->rxdw5); ++ ++ prxreport = (PRXREPORT)&report; ++ ++ pattrib = &precvframe->u.hdr.attrib; ++ _rtw_memset(pattrib, 0, sizeof(struct rx_pkt_attrib)); ++ ++ pattrib->crc_err = (u8)((report.rxdw0 >> 14) & 0x1);;//(u8)prxreport->crc32; ++ ++ // update rx report to recv_frame attribute ++ pattrib->pkt_rpt_type = (u8)((report.rxdw3 >> 14) & 0x3);//prxreport->rpt_sel; ++ ++ if(pattrib->pkt_rpt_type == NORMAL_RX)//Normal rx packet ++ { ++ pattrib->pkt_len = (u16)(report.rxdw0 &0x00003fff);//(u16)prxreport->pktlen; ++ pattrib->drvinfo_sz = (u8)((report.rxdw0 >> 16) & 0xf) * 8;//(u8)(prxreport->drvinfosize << 3); ++ ++ pattrib->physt = (u8)((report.rxdw0 >> 26) & 0x1);//(u8)prxreport->physt; ++ ++ pattrib->bdecrypted = (report.rxdw0 & BIT(27))? 0:1;//(u8)(prxreport->swdec ? 0 : 1); ++ pattrib->encrypt = (u8)((report.rxdw0 >> 20) & 0x7);//(u8)prxreport->security; ++ ++ pattrib->qos = (u8)((report.rxdw0 >> 23) & 0x1);//(u8)prxreport->qos; ++ pattrib->priority = (u8)((report.rxdw1 >> 8) & 0xf);//(u8)prxreport->tid; ++ ++ pattrib->amsdu = (u8)((report.rxdw1 >> 13) & 0x1);//(u8)prxreport->amsdu; ++ ++ pattrib->seq_num = (u16)(report.rxdw2 & 0x00000fff);//(u16)prxreport->seq; ++ pattrib->frag_num = (u8)((report.rxdw2 >> 12) & 0xf);//(u8)prxreport->frag; ++ pattrib->mfrag = (u8)((report.rxdw1 >> 27) & 0x1);//(u8)prxreport->mf; ++ pattrib->mdata = (u8)((report.rxdw1 >> 26) & 0x1);//(u8)prxreport->md; ++ ++ pattrib->mcs_rate = (u8)(report.rxdw3 & 0x3f);//(u8)prxreport->rxmcs; ++ pattrib->rxht = (u8)((report.rxdw3 >> 6) & 0x1);//(u8)prxreport->rxht; ++ ++ pattrib->icv_err = (u8)((report.rxdw0 >> 15) & 0x1);//(u8)prxreport->icverr; ++ pattrib->shift_sz = (u8)((report.rxdw0 >> 24) & 0x3); ++ ++ } ++ else if(pattrib->pkt_rpt_type == TX_REPORT1)//CCX ++ { ++ pattrib->pkt_len = TX_RPT1_PKT_LEN; ++ pattrib->drvinfo_sz = 0; ++ } ++ else if(pattrib->pkt_rpt_type == TX_REPORT2)// TX RPT ++ { ++ pattrib->pkt_len =(u16)(report.rxdw0 & 0x3FF);//Rx length[9:0] ++ pattrib->drvinfo_sz = 0; ++ ++ // ++ // Get TX report MAC ID valid. ++ // ++ pattrib->MacIDValidEntry[0] = report.rxdw4; ++ pattrib->MacIDValidEntry[1] = report.rxdw5; ++ ++ } ++ else if(pattrib->pkt_rpt_type == HIS_REPORT)// USB HISR RPT ++ { ++ pattrib->pkt_len = (u16)(report.rxdw0 &0x00003fff);//(u16)prxreport->pktlen; ++ } ++ ++} ++ ++/* ++ * Notice: ++ * Before calling this function, ++ * precvframe->u.hdr.rx_data should be ready! ++ */ ++void update_recvframe_phyinfo_88e( ++ union recv_frame *precvframe, ++ struct phy_stat *pphy_status) ++{ ++ PADAPTER padapter = precvframe->u.hdr.adapter; ++ struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ PODM_PHY_INFO_T pPHYInfo = (PODM_PHY_INFO_T)(&pattrib->phy_info); ++ u8 *wlanhdr; ++ ODM_PACKET_INFO_T pkt_info; ++ u8 *sa; ++ struct sta_priv *pstapriv; ++ struct sta_info *psta; ++ //_irqL irqL; ++ ++ pkt_info.bPacketMatchBSSID =_FALSE; ++ pkt_info.bPacketToSelf = _FALSE; ++ pkt_info.bPacketBeacon = _FALSE; ++ ++ wlanhdr = get_recvframe_data(precvframe); ++ ++ pkt_info.bPacketMatchBSSID = ((!IsFrameTypeCtrl(wlanhdr)) && ++ !pattrib->icv_err && !pattrib->crc_err && ++ _rtw_memcmp(get_hdr_bssid(wlanhdr), get_bssid(&padapter->mlmepriv), ETH_ALEN)); ++ ++ pkt_info.bPacketToSelf = pkt_info.bPacketMatchBSSID && (_rtw_memcmp(get_da(wlanhdr), myid(&padapter->eeprompriv), ETH_ALEN)); ++ ++ pkt_info.bPacketBeacon = pkt_info.bPacketMatchBSSID && (GetFrameSubType(wlanhdr) == WIFI_BEACON); ++ ++ if(pkt_info.bPacketBeacon){ ++ if(check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE) == _TRUE){ ++ sa = padapter->mlmepriv.cur_network.network.MacAddress; ++ #if 0 ++ { ++ DBG_8192C("==> rx beacon from AP[%02x:%02x:%02x:%02x:%02x:%02x]\n", ++ sa[0],sa[1],sa[2],sa[3],sa[4],sa[5]); ++ } ++ #endif ++ } ++ else ++ sa = get_sa(wlanhdr); ++ } ++ else{ ++ sa = get_sa(wlanhdr); ++ } ++ ++ pstapriv = &padapter->stapriv; ++ pkt_info.StationID = 0xFF; ++ psta = rtw_get_stainfo(pstapriv, sa); ++ if (psta) ++ { ++ pkt_info.StationID = psta->mac_id; ++ //DBG_8192C("%s ==> StationID(%d)\n",__FUNCTION__,pkt_info.StationID); ++ } ++ pkt_info.Rate = pattrib->mcs_rate; ++ //rtl8188e_query_rx_phy_status(precvframe, pphy_status); ++ ++ //_enter_critical_bh(&pHalData->odm_stainfo_lock, &irqL); ++ ODM_PhyStatusQuery(&pHalData->odmpriv,pPHYInfo,(u8 *)pphy_status,&(pkt_info)); ++ //_exit_critical_bh(&pHalData->odm_stainfo_lock, &irqL); ++ ++ precvframe->u.hdr.psta = NULL; ++ if (pkt_info.bPacketMatchBSSID && ++ (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE)) ++ { ++ if (psta) ++ { ++ precvframe->u.hdr.psta = psta; ++ rtl8188e_process_phy_info(padapter, precvframe); ++ ++ } ++ } ++ else if (pkt_info.bPacketToSelf || pkt_info.bPacketBeacon) ++ { ++ if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) == _TRUE) ++ { ++ if (psta) ++ { ++ precvframe->u.hdr.psta = psta; ++ } ++ } ++ rtl8188e_process_phy_info(padapter, precvframe); ++ } ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_sreset.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_sreset.c +new file mode 100644 +index 00000000..7c588cb1 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_sreset.c +@@ -0,0 +1,125 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTL8188E_SRESET_C_ ++ ++#include ++#include ++ ++#ifdef DBG_CONFIG_ERROR_DETECT ++ ++void rtl8188e_sreset_xmit_status_check(_adapter *padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct sreset_priv *psrtpriv = &pHalData->srestpriv; ++ ++ unsigned long current_time; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ unsigned int diff_time; ++ u32 txdma_status; ++ ++ if( (txdma_status=rtw_read32(padapter, REG_TXDMA_STATUS)) !=0x00){ ++ DBG_871X("%s REG_TXDMA_STATUS:0x%08x\n", __FUNCTION__, txdma_status); ++ rtw_hal_sreset_reset(padapter); ++ } ++#ifdef CONFIG_USB_HCI ++ //total xmit irp = 4 ++ //DBG_8192C("==>%s free_xmitbuf_cnt(%d),txirp_cnt(%d)\n",__FUNCTION__,pxmitpriv->free_xmitbuf_cnt,pxmitpriv->txirp_cnt); ++ //if(pxmitpriv->txirp_cnt == NR_XMITBUFF+1) ++ current_time = rtw_get_current_time(); ++ ++ if(0 == pxmitpriv->free_xmitbuf_cnt || 0 == pxmitpriv->free_xmit_extbuf_cnt) { ++ ++ diff_time = rtw_get_passing_time_ms(psrtpriv->last_tx_time); ++ ++ if (diff_time > 2000) { ++ if (psrtpriv->last_tx_complete_time == 0) { ++ psrtpriv->last_tx_complete_time = current_time; ++ } ++ else{ ++ diff_time = rtw_get_passing_time_ms(psrtpriv->last_tx_complete_time); ++ if (diff_time > 4000) { ++ u32 ability; ++ ++ //padapter->Wifi_Error_Status = WIFI_TX_HANG; ++ rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &ability); ++ ++ DBG_871X("%s tx hang %s\n", __FUNCTION__, ++ (ability & ODM_BB_ADAPTIVITY)? "ODM_BB_ADAPTIVITY" : ""); ++ ++ if (!(ability & ODM_BB_ADAPTIVITY)) ++ rtw_hal_sreset_reset(padapter); ++ } ++ } ++ } ++ } ++#endif //CONFIG_USB_HCI ++ ++ if (psrtpriv->dbg_trigger_point == SRESET_TGP_XMIT_STATUS) { ++ psrtpriv->dbg_trigger_point = SRESET_TGP_NULL; ++ rtw_hal_sreset_reset(padapter); ++ return; ++ } ++} ++ ++void rtl8188e_sreset_linked_status_check(_adapter *padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct sreset_priv *psrtpriv = &pHalData->srestpriv; ++ ++ u32 rx_dma_status = 0; ++ u8 fw_status=0; ++ rx_dma_status = rtw_read32(padapter,REG_RXDMA_STATUS); ++ if(rx_dma_status!= 0x00){ ++ DBG_8192C("%s REG_RXDMA_STATUS:0x%08x \n",__FUNCTION__,rx_dma_status); ++ rtw_write32(padapter,REG_RXDMA_STATUS,rx_dma_status); ++ } ++ fw_status = rtw_read8(padapter,REG_FMETHR); ++ if(fw_status != 0x00) ++ { ++ if(fw_status == 1) ++ DBG_8192C("%s REG_FW_STATUS (0x%02x), Read_Efuse_Fail !! \n",__FUNCTION__,fw_status); ++ else if(fw_status == 2) ++ DBG_8192C("%s REG_FW_STATUS (0x%02x), Condition_No_Match !! \n",__FUNCTION__,fw_status); ++ } ++#if 0 ++ u32 regc50,regc58,reg824,reg800; ++ regc50 = rtw_read32(padapter,0xc50); ++ regc58 = rtw_read32(padapter,0xc58); ++ reg824 = rtw_read32(padapter,0x824); ++ reg800 = rtw_read32(padapter,0x800); ++ if( ((regc50&0xFFFFFF00)!= 0x69543400)|| ++ ((regc58&0xFFFFFF00)!= 0x69543400)|| ++ (((reg824&0xFFFFFF00)!= 0x00390000)&&(((reg824&0xFFFFFF00)!= 0x80390000)))|| ++ ( ((reg800&0xFFFFFF00)!= 0x03040000)&&((reg800&0xFFFFFF00)!= 0x83040000))) ++ { ++ DBG_8192C("%s regc50:0x%08x, regc58:0x%08x, reg824:0x%08x, reg800:0x%08x,\n", __FUNCTION__, ++ regc50, regc58, reg824, reg800); ++ rtw_hal_sreset_reset(padapter); ++ } ++#endif ++ ++ if (psrtpriv->dbg_trigger_point == SRESET_TGP_LINK_STATUS) { ++ psrtpriv->dbg_trigger_point = SRESET_TGP_NULL; ++ rtw_hal_sreset_reset(padapter); ++ return; ++ } ++} ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_xmit.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_xmit.c +new file mode 100644 +index 00000000..d472236c +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/rtl8188e_xmit.c +@@ -0,0 +1,292 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTL8188E_XMIT_C_ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_XMIT_ACK ++void dump_txrpt_ccx_88e(void *buf) ++{ ++ struct txrpt_ccx_88e *txrpt_ccx = (struct txrpt_ccx_88e *)buf; ++ ++ DBG_871X("%s:\n" ++ "tag1:%u, pkt_num:%u, txdma_underflow:%u, int_bt:%u, int_tri:%u, int_ccx:%u\n" ++ "mac_id:%u, pkt_ok:%u, bmc:%u\n" ++ "retry_cnt:%u, lifetime_over:%u, retry_over:%u\n" ++ "ccx_qtime:%u\n" ++ "final_data_rate:0x%02x\n" ++ "qsel:%u, sw:0x%03x\n" ++ , __func__ ++ , txrpt_ccx->tag1, txrpt_ccx->pkt_num, txrpt_ccx->txdma_underflow, txrpt_ccx->int_bt, txrpt_ccx->int_tri, txrpt_ccx->int_ccx ++ , txrpt_ccx->mac_id, txrpt_ccx->pkt_ok, txrpt_ccx->bmc ++ , txrpt_ccx->retry_cnt, txrpt_ccx->lifetime_over, txrpt_ccx->retry_over ++ , txrpt_ccx_qtime_88e(txrpt_ccx) ++ , txrpt_ccx->final_data_rate ++ , txrpt_ccx->qsel, txrpt_ccx_sw_88e(txrpt_ccx) ++ ); ++} ++ ++void handle_txrpt_ccx_88e(_adapter *adapter, u8 *buf) ++{ ++ struct txrpt_ccx_88e *txrpt_ccx = (struct txrpt_ccx_88e *)buf; ++ ++ #ifdef DBG_CCX ++ dump_txrpt_ccx_88e(buf); ++ #endif ++ ++ if (txrpt_ccx->int_ccx) { ++ if (txrpt_ccx->pkt_ok) ++ rtw_ack_tx_done(&adapter->xmitpriv, RTW_SCTX_DONE_SUCCESS); ++ else ++ rtw_ack_tx_done(&adapter->xmitpriv, RTW_SCTX_DONE_CCX_PKT_FAIL); ++ } ++} ++#endif //CONFIG_XMIT_ACK ++ ++void _dbg_dump_tx_info(_adapter *padapter,int frame_tag,struct tx_desc *ptxdesc) ++{ ++ u8 bDumpTxPkt; ++ u8 bDumpTxDesc = _FALSE; ++ rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DUMP_TXPKT, &(bDumpTxPkt)); ++ ++ if(bDumpTxPkt ==1){//dump txdesc for data frame ++ DBG_871X("dump tx_desc for data frame\n"); ++ if((frame_tag&0x0f) == DATA_FRAMETAG){ ++ bDumpTxDesc = _TRUE; ++ } ++ } ++ else if(bDumpTxPkt ==2){//dump txdesc for mgnt frame ++ DBG_871X("dump tx_desc for mgnt frame\n"); ++ if((frame_tag&0x0f) == MGNT_FRAMETAG){ ++ bDumpTxDesc = _TRUE; ++ } ++ } ++ else if(bDumpTxPkt ==3){//dump early info ++ } ++ ++ if(bDumpTxDesc){ ++ // ptxdesc->txdw4 = cpu_to_le32(0x00001006);//RTS Rate=24M ++ // ptxdesc->txdw6 = 0x6666f800; ++ DBG_8192C("=====================================\n"); ++ DBG_8192C("txdw0(0x%08x)\n",ptxdesc->txdw0); ++ DBG_8192C("txdw1(0x%08x)\n",ptxdesc->txdw1); ++ DBG_8192C("txdw2(0x%08x)\n",ptxdesc->txdw2); ++ DBG_8192C("txdw3(0x%08x)\n",ptxdesc->txdw3); ++ DBG_8192C("txdw4(0x%08x)\n",ptxdesc->txdw4); ++ DBG_8192C("txdw5(0x%08x)\n",ptxdesc->txdw5); ++ DBG_8192C("txdw6(0x%08x)\n",ptxdesc->txdw6); ++ DBG_8192C("txdw7(0x%08x)\n",ptxdesc->txdw7); ++ DBG_8192C("=====================================\n"); ++ } ++ ++} ++ ++/* ++ * Description: ++ * Aggregation packets and send to hardware ++ * ++ * Return: ++ * 0 Success ++ * -1 Hardware resource(TX FIFO) not ready ++ * -2 Software resource(xmitbuf) not ready ++ */ ++#ifdef CONFIG_TX_EARLY_MODE ++ ++//#define DBG_EMINFO ++ ++#if RTL8188E_EARLY_MODE_PKT_NUM_10 == 1 ++ #define EARLY_MODE_MAX_PKT_NUM 10 ++#else ++ #define EARLY_MODE_MAX_PKT_NUM 5 ++#endif ++ ++ ++struct EMInfo{ ++ u8 EMPktNum; ++ u16 EMPktLen[EARLY_MODE_MAX_PKT_NUM]; ++}; ++ ++ ++void ++InsertEMContent_8188E( ++ struct EMInfo *pEMInfo, ++ IN pu1Byte VirtualAddress) ++{ ++ ++#if RTL8188E_EARLY_MODE_PKT_NUM_10 == 1 ++ u1Byte index=0; ++ u4Byte dwtmp=0; ++#endif ++ ++ _rtw_memset(VirtualAddress, 0, EARLY_MODE_INFO_SIZE); ++ if(pEMInfo->EMPktNum==0) ++ return; ++ ++ #ifdef DBG_EMINFO ++ { ++ int i; ++ DBG_8192C("\n%s ==> pEMInfo->EMPktNum =%d\n",__FUNCTION__,pEMInfo->EMPktNum); ++ for(i=0;i< EARLY_MODE_MAX_PKT_NUM;i++){ ++ DBG_8192C("%s ==> pEMInfo->EMPktLen[%d] =%d\n",__FUNCTION__,i,pEMInfo->EMPktLen[i]); ++ } ++ ++ } ++ #endif ++ ++#if RTL8188E_EARLY_MODE_PKT_NUM_10 == 1 ++ SET_EARLYMODE_PKTNUM(VirtualAddress, pEMInfo->EMPktNum); ++ ++ if(pEMInfo->EMPktNum == 1){ ++ dwtmp = pEMInfo->EMPktLen[0]; ++ }else{ ++ dwtmp = pEMInfo->EMPktLen[0]; ++ dwtmp += ((dwtmp%4)?(4-dwtmp%4):0)+4; ++ dwtmp += pEMInfo->EMPktLen[1]; ++ } ++ SET_EARLYMODE_LEN0(VirtualAddress, dwtmp); ++ if(pEMInfo->EMPktNum <= 3){ ++ dwtmp = pEMInfo->EMPktLen[2]; ++ }else{ ++ dwtmp = pEMInfo->EMPktLen[2]; ++ dwtmp += ((dwtmp%4)?(4-dwtmp%4):0)+4; ++ dwtmp += pEMInfo->EMPktLen[3]; ++ } ++ SET_EARLYMODE_LEN1(VirtualAddress, dwtmp); ++ if(pEMInfo->EMPktNum <= 5){ ++ dwtmp = pEMInfo->EMPktLen[4]; ++ }else{ ++ dwtmp = pEMInfo->EMPktLen[4]; ++ dwtmp += ((dwtmp%4)?(4-dwtmp%4):0)+4; ++ dwtmp += pEMInfo->EMPktLen[5]; ++ } ++ SET_EARLYMODE_LEN2_1(VirtualAddress, dwtmp&0xF); ++ SET_EARLYMODE_LEN2_2(VirtualAddress, dwtmp>>4); ++ if(pEMInfo->EMPktNum <= 7){ ++ dwtmp = pEMInfo->EMPktLen[6]; ++ }else{ ++ dwtmp = pEMInfo->EMPktLen[6]; ++ dwtmp += ((dwtmp%4)?(4-dwtmp%4):0)+4; ++ dwtmp += pEMInfo->EMPktLen[7]; ++ } ++ SET_EARLYMODE_LEN3(VirtualAddress, dwtmp); ++ if(pEMInfo->EMPktNum <= 9){ ++ dwtmp = pEMInfo->EMPktLen[8]; ++ }else{ ++ dwtmp = pEMInfo->EMPktLen[8]; ++ dwtmp += ((dwtmp%4)?(4-dwtmp%4):0)+4; ++ dwtmp += pEMInfo->EMPktLen[9]; ++ } ++ SET_EARLYMODE_LEN4(VirtualAddress, dwtmp); ++#else ++ SET_EARLYMODE_PKTNUM(VirtualAddress, pEMInfo->EMPktNum); ++ SET_EARLYMODE_LEN0(VirtualAddress, pEMInfo->EMPktLen[0]); ++ SET_EARLYMODE_LEN1(VirtualAddress, pEMInfo->EMPktLen[1]); ++ SET_EARLYMODE_LEN2_1(VirtualAddress, pEMInfo->EMPktLen[2]&0xF); ++ SET_EARLYMODE_LEN2_2(VirtualAddress, pEMInfo->EMPktLen[2]>>4); ++ SET_EARLYMODE_LEN3(VirtualAddress, pEMInfo->EMPktLen[3]); ++ SET_EARLYMODE_LEN4(VirtualAddress, pEMInfo->EMPktLen[4]); ++#endif ++ //RT_PRINT_DATA(COMP_SEND, DBG_LOUD, "EMHdr:", VirtualAddress, 8); ++ ++} ++ ++ ++ ++void UpdateEarlyModeInfo8188E(struct xmit_priv *pxmitpriv,struct xmit_buf *pxmitbuf ) ++{ ++ //_adapter *padapter, struct xmit_frame *pxmitframe,struct tx_servq *ptxservq ++ int index,j; ++ u16 offset,pktlen; ++ PTXDESC ptxdesc; ++ ++ u8 *pmem,*pEMInfo_mem; ++ s8 node_num_0=0,node_num_1=0; ++ struct EMInfo eminfo; ++ struct agg_pkt_info *paggpkt; ++ struct xmit_frame *pframe = (struct xmit_frame*)pxmitbuf->priv_data; ++ pmem= pframe->buf_addr; ++ ++ #ifdef DBG_EMINFO ++ DBG_8192C("\n%s ==> agg_num:%d\n",__FUNCTION__, pframe->agg_num); ++ for(index=0;indexagg_num;index++){ ++ offset = pxmitpriv->agg_pkt[index].offset; ++ pktlen = pxmitpriv->agg_pkt[index].pkt_len; ++ DBG_8192C("%s ==> agg_pkt[%d].offset=%d\n",__FUNCTION__,index,offset); ++ DBG_8192C("%s ==> agg_pkt[%d].pkt_len=%d\n",__FUNCTION__,index,pktlen); ++ } ++ #endif ++ ++ if( pframe->agg_num > EARLY_MODE_MAX_PKT_NUM) ++ { ++ node_num_0 = pframe->agg_num; ++ node_num_1= EARLY_MODE_MAX_PKT_NUM-1; ++ } ++ ++ for(index=0;indexagg_num;index++){ ++ ++ offset = pxmitpriv->agg_pkt[index].offset; ++ pktlen = pxmitpriv->agg_pkt[index].pkt_len; ++ ++ _rtw_memset(&eminfo,0,sizeof(struct EMInfo)); ++ if( pframe->agg_num > EARLY_MODE_MAX_PKT_NUM){ ++ if(node_num_0 > EARLY_MODE_MAX_PKT_NUM){ ++ eminfo.EMPktNum = EARLY_MODE_MAX_PKT_NUM; ++ node_num_0--; ++ } ++ else{ ++ eminfo.EMPktNum = node_num_1; ++ node_num_1--; ++ } ++ } ++ else{ ++ eminfo.EMPktNum = pframe->agg_num-(index+1); ++ } ++ for(j=0;j< eminfo.EMPktNum ;j++){ ++ eminfo.EMPktLen[j] = pxmitpriv->agg_pkt[index+1+j].pkt_len+4;// 4 bytes CRC ++ } ++ ++ if(pmem){ ++ if(index==0){ ++ ptxdesc = (PTXDESC)(pmem); ++ pEMInfo_mem = ((u8 *)ptxdesc)+TXDESC_SIZE; ++ } ++ else{ ++ pmem = pmem + pxmitpriv->agg_pkt[index-1].offset; ++ ptxdesc = (PTXDESC)(pmem); ++ pEMInfo_mem = ((u8 *)ptxdesc)+TXDESC_SIZE; ++ } ++ ++ #ifdef DBG_EMINFO ++ DBG_8192C("%s ==> desc.pkt_len=%d\n",__FUNCTION__,ptxdesc->pktlen); ++ #endif ++ InsertEMContent_8188E(&eminfo,pEMInfo_mem); ++ } ++ ++ ++ } ++ _rtw_memset(pxmitpriv->agg_pkt,0,sizeof(struct agg_pkt_info)*MAX_AGG_PKT_NUM); ++ ++} ++#endif ++ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/sdio/rtl8189es_led.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/sdio/rtl8189es_led.c +new file mode 100644 +index 00000000..06c90c55 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/sdio/rtl8189es_led.c +@@ -0,0 +1,124 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTL8189ES_LED_C_ ++ ++#include "drv_types.h" ++#include "rtl8188e_hal.h" ++ ++//================================================================================ ++// LED object. ++//================================================================================ ++ ++ ++//================================================================================ ++// Prototype of protected function. ++//================================================================================ ++ ++//================================================================================ ++// LED_819xUsb routines. ++//================================================================================ ++ ++// ++// Description: ++// Turn on LED according to LedPin specified. ++// ++void ++SwLedOn( ++ _adapter *padapter, ++ PLED_871x pLed ++) ++{ ++ u8 LedCfg; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ if( (padapter->bSurpriseRemoved == _TRUE) || ( padapter->bDriverStopped == _TRUE)) ++ { ++ return; ++ } ++ ++ pLed->bLedOn = _TRUE; ++} ++ ++ ++// ++// Description: ++// Turn off LED according to LedPin specified. ++// ++void ++SwLedOff( ++ _adapter *padapter, ++ PLED_871x pLed ++) ++{ ++ u8 LedCfg; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ if((padapter->bSurpriseRemoved == _TRUE) || ( padapter->bDriverStopped == _TRUE)) ++ { ++ goto exit; ++ } ++ ++exit: ++ pLed->bLedOn = _FALSE; ++ ++} ++ ++//================================================================================ ++// Default LED behavior. ++//================================================================================ ++ ++// ++// Description: ++// Initialize all LED_871x objects. ++// ++void ++rtl8188es_InitSwLeds( ++ _adapter *padapter ++ ) ++{ ++ struct led_priv *pledpriv = &(padapter->ledpriv); ++ ++#if 0 ++ pledpriv->LedControlHandler = LedControl871x; ++ ++ InitLed871x(padapter, &(pledpriv->SwLed0), LED_PIN_LED0); ++ ++ InitLed871x(padapter,&(pledpriv->SwLed1), LED_PIN_LED1); ++#endif ++} ++ ++ ++// ++// Description: ++// DeInitialize all LED_819xUsb objects. ++// ++void ++rtl8188es_DeInitSwLeds( ++ _adapter *padapter ++ ) ++{ ++#if 0 ++ struct led_priv *ledpriv = &(padapter->ledpriv); ++ ++ DeInitLed871x( &(ledpriv->SwLed0) ); ++ DeInitLed871x( &(ledpriv->SwLed1) ); ++#endif ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/sdio/rtl8189es_recv.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/sdio/rtl8189es_recv.c +new file mode 100644 +index 00000000..ccbb3407 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/sdio/rtl8189es_recv.c +@@ -0,0 +1,861 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTL8189ES_RECV_C_ ++ ++#include ++ ++#if defined (PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) ++#error "Shall be Linux or Windows, but not both!\n" ++#endif ++ ++#include ++#include ++#include ++ ++static void rtl8188es_recv_tasklet(void *priv); ++ ++static s32 initrecvbuf(struct recv_buf *precvbuf, PADAPTER padapter) ++{ ++ _rtw_init_listhead(&precvbuf->list); ++ _rtw_spinlock_init(&precvbuf->recvbuf_lock); ++ ++ precvbuf->adapter = padapter; ++ ++ return _SUCCESS; ++} ++ ++static void freerecvbuf(struct recv_buf *precvbuf) ++{ ++ _rtw_spinlock_free(&precvbuf->recvbuf_lock); ++} ++ ++/* ++ * Initialize recv private variable for hardware dependent ++ * 1. recv buf ++ * 2. recv tasklet ++ * ++ */ ++s32 rtl8188es_init_recv_priv(PADAPTER padapter) ++{ ++ s32 res; ++ u32 i, n; ++ struct recv_priv *precvpriv; ++ struct recv_buf *precvbuf; ++ ++ ++ res = _SUCCESS; ++ precvpriv = &padapter->recvpriv; ++ ++ //3 1. init recv buffer ++ _rtw_init_queue(&precvpriv->free_recv_buf_queue); ++ _rtw_init_queue(&precvpriv->recv_buf_pending_queue); ++ ++ n = NR_RECVBUFF * sizeof(struct recv_buf) + 4; ++ precvpriv->pallocated_recv_buf = rtw_zmalloc(n); ++ if (precvpriv->pallocated_recv_buf == NULL) { ++ res = _FAIL; ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("alloc recv_buf fail!\n")); ++ goto exit; ++ } ++ ++ precvpriv->precv_buf = (u8*)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_recv_buf), 4); ++ ++ // init each recv buffer ++ precvbuf = (struct recv_buf*)precvpriv->precv_buf; ++ for (i = 0; i < NR_RECVBUFF; i++) ++ { ++ res = initrecvbuf(precvbuf, padapter); ++ if (res == _FAIL) ++ break; ++ ++ res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf); ++ if (res == _FAIL) { ++ freerecvbuf(precvbuf); ++ break; ++ } ++ ++#ifdef CONFIG_SDIO_RX_COPY ++ if (precvbuf->pskb == NULL) { ++ SIZE_PTR tmpaddr=0; ++ SIZE_PTR alignment=0; ++ ++ precvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); ++ ++ if(precvbuf->pskb) ++ { ++ precvbuf->pskb->dev = padapter->pnetdev; ++ ++ tmpaddr = (SIZE_PTR)precvbuf->pskb->data; ++ alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); ++ skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment)); ++ ++ precvbuf->phead = precvbuf->pskb->head; ++ precvbuf->pdata = precvbuf->pskb->data; ++ precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); ++ precvbuf->pend = skb_end_pointer(precvbuf->pskb); ++ precvbuf->len = 0; ++ } ++ ++ if (precvbuf->pskb == NULL) { ++ DBG_871X("%s: alloc_skb fail!\n", __FUNCTION__); ++ } ++ } ++#endif ++ ++ rtw_list_insert_tail(&precvbuf->list, &precvpriv->free_recv_buf_queue.queue); ++ ++ precvbuf++; ++ } ++ precvpriv->free_recv_buf_queue_cnt = i; ++ ++ if (res == _FAIL) ++ goto initbuferror; ++ ++ //3 2. init tasklet ++#ifdef PLATFORM_LINUX ++ tasklet_init(&precvpriv->recv_tasklet, ++ (void(*)(unsigned long))rtl8188es_recv_tasklet, ++ (unsigned long)padapter); ++#endif ++ ++ goto exit; ++ ++initbuferror: ++ precvbuf = (struct recv_buf*)precvpriv->precv_buf; ++ if (precvbuf) { ++ n = precvpriv->free_recv_buf_queue_cnt; ++ precvpriv->free_recv_buf_queue_cnt = 0; ++ for (i = 0; i < n ; i++) ++ { ++ rtw_list_delete(&precvbuf->list); ++ rtw_os_recvbuf_resource_free(padapter, precvbuf); ++ freerecvbuf(precvbuf); ++ precvbuf++; ++ } ++ precvpriv->precv_buf = NULL; ++ } ++ ++ if (precvpriv->pallocated_recv_buf) { ++ n = NR_RECVBUFF * sizeof(struct recv_buf) + 4; ++ rtw_mfree(precvpriv->pallocated_recv_buf, n); ++ precvpriv->pallocated_recv_buf = NULL; ++ } ++ ++exit: ++ return res; ++} ++ ++/* ++ * Free recv private variable of hardware dependent ++ * 1. recv buf ++ * 2. recv tasklet ++ * ++ */ ++void rtl8188es_free_recv_priv(PADAPTER padapter) ++{ ++ u32 i, n; ++ struct recv_priv *precvpriv; ++ struct recv_buf *precvbuf; ++ ++ ++ precvpriv = &padapter->recvpriv; ++ ++ //3 1. kill tasklet ++#ifdef PLATFORM_LINUX ++ tasklet_kill(&precvpriv->recv_tasklet); ++#endif ++ ++ //3 2. free all recv buffers ++ precvbuf = (struct recv_buf*)precvpriv->precv_buf; ++ if (precvbuf) { ++ n = NR_RECVBUFF; ++ precvpriv->free_recv_buf_queue_cnt = 0; ++ for (i = 0; i < n ; i++) ++ { ++ rtw_list_delete(&precvbuf->list); ++ rtw_os_recvbuf_resource_free(padapter, precvbuf); ++ freerecvbuf(precvbuf); ++ precvbuf++; ++ } ++ precvpriv->precv_buf = NULL; ++ } ++ ++ if (precvpriv->pallocated_recv_buf) { ++ n = NR_RECVBUFF * sizeof(struct recv_buf) + 4; ++ rtw_mfree(precvpriv->pallocated_recv_buf, n); ++ precvpriv->pallocated_recv_buf = NULL; ++ } ++} ++ ++#ifdef CONFIG_SDIO_RX_COPY ++static s32 pre_recv_entry(union recv_frame *precvframe, struct recv_buf *precvbuf, struct phy_stat *pphy_status) ++{ ++ s32 ret=_SUCCESS; ++#ifdef CONFIG_CONCURRENT_MODE ++ u8 *primary_myid, *secondary_myid, *paddr1; ++ union recv_frame *precvframe_if2 = NULL; ++ _adapter *primary_padapter = precvframe->u.hdr.adapter; ++ _adapter *secondary_padapter = primary_padapter->pbuddy_adapter; ++ struct recv_priv *precvpriv = &primary_padapter->recvpriv; ++ _queue *pfree_recv_queue = &precvpriv->free_recv_queue; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(primary_padapter); ++ ++ if(!secondary_padapter) ++ return ret; ++ ++ paddr1 = GetAddr1Ptr(precvframe->u.hdr.rx_data); ++ ++ if(IS_MCAST(paddr1) == _FALSE)//unicast packets ++ { ++ //primary_myid = myid(&primary_padapter->eeprompriv); ++ secondary_myid = myid(&secondary_padapter->eeprompriv); ++ ++ if(_rtw_memcmp(paddr1, secondary_myid, ETH_ALEN)) ++ { ++ //change to secondary interface ++ precvframe->u.hdr.adapter = secondary_padapter; ++ } ++ ++ //ret = recv_entry(precvframe); ++ ++ } ++ else // Handle BC/MC Packets ++ { ++ //clone/copy to if2 ++ _pkt *pkt_copy = NULL; ++ struct rx_pkt_attrib *pattrib = NULL; ++ ++ precvframe_if2 = rtw_alloc_recvframe(pfree_recv_queue); ++ ++ if(!precvframe_if2) ++ return _FAIL; ++ ++ precvframe_if2->u.hdr.adapter = secondary_padapter; ++ _rtw_memcpy(&precvframe_if2->u.hdr.attrib, &precvframe->u.hdr.attrib, sizeof(struct rx_pkt_attrib)); ++ pattrib = &precvframe_if2->u.hdr.attrib; ++ ++ //driver need to set skb len for rtw_skb_copy(). ++ //If skb->len is zero, rtw_skb_copy() will not copy data from original skb. ++ skb_put(precvframe->u.hdr.pkt, pattrib->pkt_len); ++ ++ pkt_copy = rtw_skb_copy( precvframe->u.hdr.pkt); ++ if (pkt_copy == NULL) ++ { ++ if((pattrib->mfrag == 1)&&(pattrib->frag_num == 0)) ++ { ++ DBG_8192C("pre_recv_entry(): rtw_skb_copy fail , drop frag frame \n"); ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ return ret; ++ } ++ ++ pkt_copy = rtw_skb_clone(precvframe->u.hdr.pkt); ++ if(pkt_copy == NULL) ++ { ++ DBG_8192C("pre_recv_entry(): rtw_skb_clone fail , drop frame\n"); ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ return ret; ++ } ++ } ++ ++ pkt_copy->dev = secondary_padapter->pnetdev; ++ ++ precvframe_if2->u.hdr.pkt = pkt_copy; ++ precvframe_if2->u.hdr.rx_head = pkt_copy->head; ++ precvframe_if2->u.hdr.rx_data = pkt_copy->data; ++ precvframe_if2->u.hdr.rx_tail = skb_tail_pointer(pkt_copy); ++ precvframe_if2->u.hdr.rx_end = skb_end_pointer(pkt_copy); ++ precvframe_if2->u.hdr.len = pkt_copy->len; ++ ++ //recvframe_put(precvframe_if2, pattrib->pkt_len); ++ ++ if ( pHalData->ReceiveConfig & RCR_APPFCS) ++ recvframe_pull_tail(precvframe_if2, IEEE80211_FCS_LEN); ++ ++ if (pattrib->physt) ++ update_recvframe_phyinfo_88e(precvframe_if2, pphy_status); ++ ++ if(rtw_recv_entry(precvframe_if2) != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_, ++ ("recvbuf2recvframe: rtw_recv_entry(precvframe) != _SUCCESS\n")); ++ } ++ } ++ ++ if (precvframe->u.hdr.attrib.physt) ++ update_recvframe_phyinfo_88e(precvframe, pphy_status); ++ ret = rtw_recv_entry(precvframe); ++ ++#endif ++ ++ return ret; ++ ++} ++ ++static void rtl8188es_recv_tasklet(void *priv) ++{ ++ PADAPTER padapter; ++ PHAL_DATA_TYPE pHalData; ++ struct recv_priv *precvpriv; ++ struct recv_buf *precvbuf; ++ union recv_frame *precvframe; ++ struct recv_frame_hdr *phdr; ++ struct rx_pkt_attrib *pattrib; ++ _irqL irql; ++ u8 *ptr; ++ u32 pkt_offset, skb_len, alloc_sz; ++ s32 transfer_len; ++ _pkt *pkt_copy = NULL; ++ struct phy_stat *pphy_status = NULL; ++ u8 shift_sz = 0, rx_report_sz = 0; ++ ++ ++ padapter = (PADAPTER)priv; ++ pHalData = GET_HAL_DATA(padapter); ++ precvpriv = &padapter->recvpriv; ++ ++ do { ++ if ((padapter->bDriverStopped == _TRUE)||(padapter->bSurpriseRemoved== _TRUE)) ++ { ++ DBG_8192C("recv_tasklet => bDriverStopped or bSurpriseRemoved \n"); ++ break; ++ } ++ ++ precvbuf = rtw_dequeue_recvbuf(&precvpriv->recv_buf_pending_queue); ++ if (NULL == precvbuf) break; ++ ++ transfer_len = (s32)precvbuf->len; ++ ptr = precvbuf->pdata; ++ ++ do { ++ precvframe = rtw_alloc_recvframe(&precvpriv->free_recv_queue); ++ if (precvframe == NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("%s: no enough recv frame!\n",__FUNCTION__)); ++ rtw_enqueue_recvbuf_to_head(precvbuf, &precvpriv->recv_buf_pending_queue); ++ ++ // The case of can't allocte recvframe should be temporary, ++ // schedule again and hope recvframe is available next time. ++#ifdef PLATFORM_LINUX ++ tasklet_schedule(&precvpriv->recv_tasklet); ++#endif ++ return; ++ } ++ ++ //rx desc parsing ++ update_recvframe_attrib_88e(precvframe, (struct recv_stat*)ptr); ++ ++ pattrib = &precvframe->u.hdr.attrib; ++ ++ // fix Hardware RX data error, drop whole recv_buffer ++ if ((!(pHalData->ReceiveConfig & RCR_ACRC32)) && pattrib->crc_err) ++ { ++ DBG_8192C("%s()-%d: RX Warning! rx CRC ERROR !!\n", __FUNCTION__, __LINE__); ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ break; ++ } ++ ++ if (pHalData->ReceiveConfig & RCR_APP_BA_SSN) ++ rx_report_sz = RXDESC_SIZE + 4 + pattrib->drvinfo_sz; ++ else ++ rx_report_sz = RXDESC_SIZE + pattrib->drvinfo_sz; ++ ++ pkt_offset = rx_report_sz + pattrib->shift_sz + pattrib->pkt_len; ++ ++ if ((pattrib->pkt_len==0) || (pkt_offset>transfer_len)) { ++ DBG_8192C("%s()-%d: RX Warning!,pkt_len==0 or pkt_offset(%d)> transfoer_len(%d) \n", __FUNCTION__, __LINE__, pkt_offset, transfer_len); ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ break; ++ } ++ ++ if ((pattrib->crc_err) || (pattrib->icv_err)) ++ { ++ #ifdef CONFIG_MP_INCLUDED ++ if (padapter->registrypriv.mp_mode == 1) ++ { ++ if ((check_fwstate(&padapter->mlmepriv, WIFI_MP_STATE) == _TRUE))//&&(padapter->mppriv.check_mp_pkt == 0)) ++ { ++ if (pattrib->crc_err == 1) ++ padapter->mppriv.rx_crcerrpktcount++; ++ } ++ } ++ #endif ++ DBG_8192C("%s: crc_err=%d icv_err=%d, skip!\n", __FUNCTION__, pattrib->crc_err, pattrib->icv_err); ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ } ++ else ++ { ++ // Modified by Albert 20101213 ++ // For 8 bytes IP header alignment. ++ if (pattrib->qos) // Qos data, wireless lan header length is 26 ++ { ++ shift_sz = 6; ++ } ++ else ++ { ++ shift_sz = 0; ++ } ++ ++ skb_len = pattrib->pkt_len; ++ ++ // for first fragment packet, driver need allocate 1536+drvinfo_sz+RXDESC_SIZE to defrag packet. ++ // modify alloc_sz for recvive crc error packet by thomas 2011-06-02 ++ if((pattrib->mfrag == 1)&&(pattrib->frag_num == 0)){ ++ //alloc_sz = 1664; //1664 is 128 alignment. ++ if(skb_len <= 1650) ++ alloc_sz = 1664; ++ else ++ alloc_sz = skb_len + 14; ++ } ++ else { ++ alloc_sz = skb_len; ++ // 6 is for IP header 8 bytes alignment in QoS packet case. ++ // 8 is for skb->data 4 bytes alignment. ++ alloc_sz += 14; ++ } ++ ++ pkt_copy = rtw_skb_alloc(alloc_sz); ++ ++ if(pkt_copy) ++ { ++ pkt_copy->dev = padapter->pnetdev; ++ precvframe->u.hdr.pkt = pkt_copy; ++ skb_reserve( pkt_copy, 8 - ((SIZE_PTR)( pkt_copy->data ) & 7 ));//force pkt_copy->data at 8-byte alignment address ++ skb_reserve( pkt_copy, shift_sz );//force ip_hdr at 8-byte alignment address according to shift_sz. ++ _rtw_memcpy(pkt_copy->data, (ptr + rx_report_sz + pattrib->shift_sz), skb_len); ++ precvframe->u.hdr.rx_head = pkt_copy->head; ++ precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail = pkt_copy->data; ++ precvframe->u.hdr.rx_end = skb_end_pointer(pkt_copy); ++ } ++ else ++ { ++ if((pattrib->mfrag == 1)&&(pattrib->frag_num == 0)) ++ { ++ DBG_8192C("rtl8188es_recv_tasklet: alloc_skb fail , drop frag frame \n"); ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ break; ++ } ++ ++ precvframe->u.hdr.pkt = rtw_skb_clone(precvbuf->pskb); ++ if(precvframe->u.hdr.pkt) ++ { ++ _pkt *pkt_clone = precvframe->u.hdr.pkt; ++ ++ pkt_clone->data = ptr + rx_report_sz + pattrib->shift_sz; ++ skb_reset_tail_pointer(pkt_clone); ++ precvframe->u.hdr.rx_head = precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail ++ = pkt_clone->data; ++ precvframe->u.hdr.rx_end = pkt_clone->data + skb_len; ++ } ++ else ++ { ++ DBG_8192C("rtl8188es_recv_tasklet: rtw_skb_clone fail\n"); ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ break; ++ } ++ } ++ ++ recvframe_put(precvframe, skb_len); ++ //recvframe_pull(precvframe, drvinfo_sz + RXDESC_SIZE); ++ ++ if (pHalData->ReceiveConfig & RCR_APPFCS) ++ recvframe_pull_tail(precvframe, IEEE80211_FCS_LEN); ++ ++ // update drv info ++ if (pHalData->ReceiveConfig & RCR_APP_BA_SSN) { ++ //rtl8723s_update_bassn(padapter, (ptr + RXDESC_SIZE)); ++ } ++ ++ if(pattrib->pkt_rpt_type == NORMAL_RX)//Normal rx packet ++ { ++ pphy_status = (struct phy_stat *)(ptr + (rx_report_sz - pattrib->drvinfo_sz)); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(rtw_buddy_adapter_up(padapter)) ++ { ++ if(pre_recv_entry(precvframe, precvbuf, (struct phy_stat*)pphy_status) != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_, ++ ("recvbuf2recvframe: recv_entry(precvframe) != _SUCCESS\n")); ++ } ++ } ++ else ++#endif ++ { ++ if (pattrib->physt) ++ update_recvframe_phyinfo_88e(precvframe, (struct phy_stat*)pphy_status); ++ ++ if (rtw_recv_entry(precvframe) != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("%s: rtw_recv_entry(precvframe) != _SUCCESS\n",__FUNCTION__)); ++ } ++ } ++ } ++ else{ // pkt_rpt_type == TX_REPORT1-CCX, TX_REPORT2-TX RTP,HIS_REPORT-USB HISR RTP ++ ++ //enqueue recvframe to txrtp queue ++ if(pattrib->pkt_rpt_type == TX_REPORT1){ ++ //DBG_8192C("rx CCX \n"); ++ //CCX-TXRPT ack for xmit mgmt frames. ++ handle_txrpt_ccx_88e(padapter, precvframe->u.hdr.rx_data); ++ } ++ else if(pattrib->pkt_rpt_type == TX_REPORT2){ ++ //printk("rx TX RPT \n"); ++ ODM_RA_TxRPT2Handle_8188E( ++ &pHalData->odmpriv, ++ precvframe->u.hdr.rx_data, ++ pattrib->pkt_len, ++ pattrib->MacIDValidEntry[0], ++ pattrib->MacIDValidEntry[1] ++ ); ++ ++ } ++ /* ++ else if(pattrib->pkt_rpt_type == HIS_REPORT){ ++ printk("rx USB HISR \n"); ++ }*/ ++ ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ ++ } ++ } ++ ++ // Page size of receive package is 128 bytes alignment =>DMA AGG ++ // refer to _InitTransferPageSize() ++ pkt_offset = _RND128(pkt_offset); ++ transfer_len -= pkt_offset; ++ ptr += pkt_offset; ++ precvframe = NULL; ++ pkt_copy = NULL; ++ }while(transfer_len>0); ++ ++ precvbuf->len = 0; ++ ++ rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue); ++ } while (1); ++ ++} ++#else ++static s32 pre_recv_entry(union recv_frame *precvframe, struct recv_buf *precvbuf, struct phy_stat *pphy_status) ++{ ++ s32 ret=_SUCCESS; ++#ifdef CONFIG_CONCURRENT_MODE ++ u8 *primary_myid, *secondary_myid, *paddr1; ++ union recv_frame *precvframe_if2 = NULL; ++ _adapter *primary_padapter = precvframe->u.hdr.adapter; ++ _adapter *secondary_padapter = primary_padapter->pbuddy_adapter; ++ struct recv_priv *precvpriv = &primary_padapter->recvpriv; ++ _queue *pfree_recv_queue = &precvpriv->free_recv_queue; ++ u8 *pbuf = precvframe->u.hdr.rx_head; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(primary_padapter); ++ ++ if(!secondary_padapter) ++ return ret; ++ ++ paddr1 = GetAddr1Ptr(precvframe->u.hdr.rx_data); ++ ++ if(IS_MCAST(paddr1) == _FALSE)//unicast packets ++ { ++ //primary_myid = myid(&primary_padapter->eeprompriv); ++ secondary_myid = myid(&secondary_padapter->eeprompriv); ++ ++ if(_rtw_memcmp(paddr1, secondary_myid, ETH_ALEN)) ++ { ++ //change to secondary interface ++ precvframe->u.hdr.adapter = secondary_padapter; ++ } ++ ++ //ret = recv_entry(precvframe); ++ ++ } ++ else // Handle BC/MC Packets ++ { ++ //clone/copy to if2 ++ u8 shift_sz = 0; ++ u32 alloc_sz, skb_len; ++ _pkt *pkt_copy = NULL; ++ struct rx_pkt_attrib *pattrib = NULL; ++ ++ precvframe_if2 = rtw_alloc_recvframe(pfree_recv_queue); ++ ++ if(!precvframe_if2) ++ return _FAIL; ++ ++ precvframe_if2->u.hdr.adapter = secondary_padapter; ++ _rtw_init_listhead(&precvframe_if2->u.hdr.list); ++ precvframe_if2->u.hdr.precvbuf = NULL; //can't access the precvbuf for new arch. ++ precvframe_if2->u.hdr.len=0; ++ _rtw_memcpy(&precvframe_if2->u.hdr.attrib, &precvframe->u.hdr.attrib, sizeof(struct rx_pkt_attrib)); ++ pattrib = &precvframe_if2->u.hdr.attrib; ++ ++ pkt_copy = rtw_skb_copy( precvframe->u.hdr.pkt); ++ if (pkt_copy == NULL) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_crit_, ("%s: no enough memory to allocate SKB!\n",__FUNCTION__)); ++ rtw_free_recvframe(precvframe_if2, &precvpriv->free_recv_queue); ++ rtw_enqueue_recvbuf_to_head(precvbuf, &precvpriv->recv_buf_pending_queue); ++ ++ // The case of can't allocte skb is serious and may never be recovered, ++ // once bDriverStopped is enable, this task should be stopped. ++ if (secondary_padapter->bDriverStopped == _FALSE) ++#ifdef PLATFORM_LINUX ++ tasklet_schedule(&precvpriv->recv_tasklet); ++#endif ++ return ret; ++ } ++ pkt_copy->dev = secondary_padapter->pnetdev; ++ ++ ++ ++ if((pattrib->mfrag == 1)&&(pattrib->frag_num == 0)){ ++ //alloc_sz = 1664; //1664 is 128 alignment. ++ if(skb_len <= 1650) ++ alloc_sz = 1664; ++ else ++ alloc_sz = skb_len + 14; ++ } ++ else { ++ alloc_sz = skb_len; ++ // 6 is for IP header 8 bytes alignment in QoS packet case. ++ // 8 is for skb->data 4 bytes alignment. ++ alloc_sz += 14; ++ } ++ ++#if 1 ++ precvframe_if2->u.hdr.pkt = pkt_copy; ++ precvframe_if2->u.hdr.rx_head = pkt_copy->head; ++ precvframe_if2->u.hdr.rx_data = precvframe_if2->u.hdr.rx_tail = pkt_copy->data; ++ precvframe_if2->u.hdr.rx_end = pkt_copy->data + alloc_sz; ++#endif ++ recvframe_put(precvframe_if2, pkt_offset); ++ recvframe_pull(precvframe_if2, RXDESC_SIZE + pattrib->drvinfo_sz); ++ ++ if ( pHalData->ReceiveConfig & RCR_APPFCS) ++ recvframe_pull_tail(precvframe_if2, IEEE80211_FCS_LEN); ++ ++ if (pattrib->physt) ++ update_recvframe_phyinfo_88e(precvframe_if2, pphy_status); ++ ++ if(rtw_recv_entry(precvframe_if2) != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_, ++ ("recvbuf2recvframe: rtw_recv_entry(precvframe) != _SUCCESS\n")); ++ } ++ } ++ ++ if (precvframe->u.hdr.attrib.physt) ++ update_recvframe_phyinfo_88e(precvframe, (struct phy_stat*)pphy_status); ++ ret = rtw_recv_entry(precvframe); ++ ++#endif ++ ++ return ret; ++ ++} ++ ++static void rtl8188es_recv_tasklet(void *priv) ++{ ++ PADAPTER padapter; ++ PHAL_DATA_TYPE pHalData; ++ struct recv_priv *precvpriv; ++ struct recv_buf *precvbuf; ++ union recv_frame *precvframe; ++ struct recv_frame_hdr *phdr; ++ struct rx_pkt_attrib *pattrib; ++ u8 *ptr; ++ _pkt *ppkt; ++ u32 pkt_offset; ++ _irqL irql; ++#ifdef CONFIG_CONCURRENT_MODE ++ struct recv_stat *prxstat; ++#endif ++ ++ padapter = (PADAPTER)priv; ++ pHalData = GET_HAL_DATA(padapter); ++ precvpriv = &padapter->recvpriv; ++ ++ do { ++ precvbuf = rtw_dequeue_recvbuf(&precvpriv->recv_buf_pending_queue); ++ if (NULL == precvbuf) break; ++ ++ ptr = precvbuf->pdata; ++ ++ while (ptr < precvbuf->ptail) ++ { ++ precvframe = rtw_alloc_recvframe(&precvpriv->free_recv_queue); ++ if (precvframe == NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("%s: no enough recv frame!\n",__FUNCTION__)); ++ rtw_enqueue_recvbuf_to_head(precvbuf, &precvpriv->recv_buf_pending_queue); ++ ++ // The case of can't allocte recvframe should be temporary, ++ // schedule again and hope recvframe is available next time. ++#ifdef PLATFORM_LINUX ++ tasklet_schedule(&precvpriv->recv_tasklet); ++#endif ++ return; ++ } ++ ++ phdr = &precvframe->u.hdr; ++ pattrib = &phdr->attrib; ++ ++ //rx desc parsing ++ update_recvframe_attrib_88e(precvframe, (struct recv_stat*)ptr); ++#ifdef CONFIG_CONCURRENT_MODE ++ prxstat = (struct recv_stat*)ptr; ++#endif ++ // fix Hardware RX data error, drop whole recv_buffer ++ if ((!(pHalData->ReceiveConfig & RCR_ACRC32)) && pattrib->crc_err) ++ { ++ DBG_8192C("%s()-%d: RX Warning! rx CRC ERROR !!\n", __FUNCTION__, __LINE__); ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ break; ++ } ++ ++ pkt_offset = RXDESC_SIZE + pattrib->drvinfo_sz + pattrib->pkt_len; ++ ++ if ((ptr + pkt_offset) > precvbuf->ptail) { ++ DBG_8192C("%s()-%d: : next pkt len(%p,%d) exceed ptail(%p)!\n", __FUNCTION__, __LINE__, ptr, pkt_offset, precvbuf->ptail); ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ break; ++ } ++ ++ if ((pattrib->crc_err) || (pattrib->icv_err)) ++ { ++ #ifdef CONFIG_MP_INCLUDED ++ if (padapter->registrypriv.mp_mode == 1) ++ { ++ if ((check_fwstate(&padapter->mlmepriv, WIFI_MP_STATE) == _TRUE))//&&(padapter->mppriv.check_mp_pkt == 0)) ++ { ++ if (pattrib->crc_err == 1) ++ padapter->mppriv.rx_crcerrpktcount++; ++ } ++ } ++ #endif ++ ++ DBG_8192C("%s: crc_err=%d icv_err=%d, skip!\n", __FUNCTION__, pattrib->crc_err, pattrib->icv_err); ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ } ++ else ++ { ++ ppkt = rtw_skb_clone(precvbuf->pskb); ++ if (ppkt == NULL) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_crit_, ("%s: no enough memory to allocate SKB!\n",__FUNCTION__)); ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ rtw_enqueue_recvbuf_to_head(precvbuf, &precvpriv->recv_buf_pending_queue); ++ ++ // The case of can't allocte skb is serious and may never be recovered, ++ // once bDriverStopped is enable, this task should be stopped. ++ if (padapter->bDriverStopped == _FALSE) { ++#ifdef PLATFORM_LINUX ++ tasklet_schedule(&precvpriv->recv_tasklet); ++#endif ++ } ++ ++ return; ++ } ++ ++ phdr->pkt = ppkt; ++ phdr->len = 0; ++ phdr->rx_head = precvbuf->phead; ++ phdr->rx_data = phdr->rx_tail = precvbuf->pdata; ++ phdr->rx_end = precvbuf->pend; ++ ++ recvframe_put(precvframe, pkt_offset); ++ recvframe_pull(precvframe, RXDESC_SIZE + pattrib->drvinfo_sz); ++ ++ if (pHalData->ReceiveConfig & RCR_APPFCS) ++ recvframe_pull_tail(precvframe, IEEE80211_FCS_LEN); ++ ++ // move to drv info position ++ ptr += RXDESC_SIZE; ++ ++ // update drv info ++ if (pHalData->ReceiveConfig & RCR_APP_BA_SSN) { ++// rtl8723s_update_bassn(padapter, pdrvinfo); ++ ptr += 4; ++ } ++ ++ if(pattrib->pkt_rpt_type == NORMAL_RX)//Normal rx packet ++ { ++#ifdef CONFIG_CONCURRENT_MODE ++ if(rtw_buddy_adapter_up(padapter)) ++ { ++ if(pre_recv_entry(precvframe, precvbuf, (struct phy_stat*)ptr) != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_, ++ ("recvbuf2recvframe: recv_entry(precvframe) != _SUCCESS\n")); ++ } ++ } ++ else ++#endif ++ { ++ if (pattrib->physt) ++ update_recvframe_phyinfo_88e(precvframe, (struct phy_stat*)ptr); ++ ++ if (rtw_recv_entry(precvframe) != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_, ++ ("recvbuf2recvframe: rtw_recv_entry(precvframe) != _SUCCESS\n")); ++ } ++ } ++ } ++ else{ // pkt_rpt_type == TX_REPORT1-CCX, TX_REPORT2-TX RTP,HIS_REPORT-USB HISR RTP ++ ++ //enqueue recvframe to txrtp queue ++ if(pattrib->pkt_rpt_type == TX_REPORT1){ ++ DBG_8192C("rx CCX \n"); ++ } ++ else if(pattrib->pkt_rpt_type == TX_REPORT2){ ++ //DBG_8192C("rx TX RPT \n"); ++ ODM_RA_TxRPT2Handle_8188E( ++ &pHalData->odmpriv, ++ precvframe->u.hdr.rx_data, ++ pattrib->pkt_len, ++ pattrib->MacIDValidEntry[0], ++ pattrib->MacIDValidEntry[1] ++ ); ++ ++ } ++ /* ++ else if(pattrib->pkt_rpt_type == HIS_REPORT){ ++ DBG_8192C("rx USB HISR \n"); ++ }*/ ++ ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ ++ } ++ } ++ ++ // Page size of receive package is 128 bytes alignment =>DMA AGG ++ // refer to _InitTransferPageSize() ++ pkt_offset = _RND128(pkt_offset); ++ precvbuf->pdata += pkt_offset; ++ ptr = precvbuf->pdata; ++ ++ } ++ ++ rtw_skb_free(precvbuf->pskb); ++ precvbuf->pskb = NULL; ++ rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue); ++ ++ } while (1); ++ ++} ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/sdio/rtl8189es_xmit.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/sdio/rtl8189es_xmit.c +new file mode 100644 +index 00000000..73c6a5a4 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/sdio/rtl8189es_xmit.c +@@ -0,0 +1,1720 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTL8189ES_XMIT_C_ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static void fill_txdesc_sectype(struct pkt_attrib *pattrib, PTXDESC ptxdesc) ++{ ++ if ((pattrib->encrypt > 0) && !pattrib->bswenc) ++ { ++ switch (pattrib->encrypt) ++ { ++ // SEC_TYPE ++ case _WEP40_: ++ case _WEP104_: ++ case _TKIP_: ++ case _TKIP_WTMIC_: ++ ptxdesc->sectype = 1; ++ break; ++#ifdef CONFIG_WAPI_SUPPORT ++ case _SMS4_: ++ ptxdesc->sectype = 2; ++ break; ++#endif ++ case _AES_: ++ ptxdesc->sectype = 3; ++ break; ++ ++ case _NO_PRIVACY_: ++ default: ++ break; ++ } ++ } ++} ++ ++ ++ static void fill_txdesc_vcs(struct pkt_attrib *pattrib, PTXDESC ptxdesc) ++{ ++ //DBG_8192C("cvs_mode=%d\n", pattrib->vcs_mode); ++ ++ switch (pattrib->vcs_mode) ++ { ++ case RTS_CTS: ++ ptxdesc->rtsen = 1; ++ break; ++ ++ case CTS_TO_SELF: ++ ptxdesc->cts2self = 1; ++ break; ++ ++ case NONE_VCS: ++ default: ++ break; ++ } ++ ++ if(pattrib->vcs_mode) { ++ ptxdesc->hw_rts_en = 1; // ENABLE HW RTS ++ ++ // Set RTS BW ++ if(pattrib->ht_en) ++ { ++ if (pattrib->bwmode & HT_CHANNEL_WIDTH_40) ++ ptxdesc->rts_bw = 1; ++ ++ switch (pattrib->ch_offset) ++ { ++ case HAL_PRIME_CHNL_OFFSET_DONT_CARE: ++ ptxdesc->rts_sc = 0; ++ break; ++ ++ case HAL_PRIME_CHNL_OFFSET_LOWER: ++ ptxdesc->rts_sc = 1; ++ break; ++ ++ case HAL_PRIME_CHNL_OFFSET_UPPER: ++ ptxdesc->rts_sc = 2; ++ break; ++ ++ default: ++ ptxdesc->rts_sc = 3; // Duplicate ++ break; ++ } ++ } ++ } ++} ++ ++static void fill_txdesc_phy(struct pkt_attrib *pattrib, PTXDESC ptxdesc) ++{ ++ //DBG_8192C("bwmode=%d, ch_off=%d\n", pattrib->bwmode, pattrib->ch_offset); ++ ++ if (pattrib->ht_en) ++ { ++ if (pattrib->bwmode & HT_CHANNEL_WIDTH_40) ++ ptxdesc->data_bw = 1; ++ ++ switch (pattrib->ch_offset) ++ { ++ case HAL_PRIME_CHNL_OFFSET_DONT_CARE: ++ ptxdesc->data_sc = 0; ++ break; ++ ++ case HAL_PRIME_CHNL_OFFSET_LOWER: ++ ptxdesc->data_sc = 1; ++ break; ++ ++ case HAL_PRIME_CHNL_OFFSET_UPPER: ++ ptxdesc->data_sc = 2; ++ break; ++ ++ default: ++ ptxdesc->data_sc = 3; // Duplicate ++ break; ++ } ++ } ++} ++ ++static void rtl8188e_cal_txdesc_chksum(struct tx_desc *ptxdesc) ++{ ++ u16 *usPtr = (u16*)ptxdesc; ++ u32 count = 16; // (32 bytes / 2 bytes per XOR) => 16 times ++ u32 index; ++ u16 checksum = 0; ++ ++ ++ // Clear first ++ ptxdesc->txdw7 &= cpu_to_le32(0xffff0000); ++ ++ for (index = 0; index < count; index++) { ++ checksum ^= le16_to_cpu(*(usPtr + index)); ++ } ++ ++ ptxdesc->txdw7 |= cpu_to_le32(checksum & 0x0000ffff); ++} ++// ++// Description: In normal chip, we should send some packet to Hw which will be used by Fw ++// in FW LPS mode. The function is to fill the Tx descriptor of this packets, then ++// Fw can tell Hw to send these packet derectly. ++// ++void rtl8188e_fill_fake_txdesc( ++ PADAPTER padapter, ++ u8* pDesc, ++ u32 BufferLen, ++ u8 IsPsPoll, ++ u8 IsBTQosNull) ++{ ++ struct tx_desc *ptxdesc; ++ ++ ++ // Clear all status ++ ptxdesc = (struct tx_desc*)pDesc; ++ _rtw_memset(pDesc, 0, TXDESC_SIZE); ++ ++ //offset 0 ++ ptxdesc->txdw0 |= cpu_to_le32( OWN | FSG | LSG); //own, bFirstSeg, bLastSeg; ++ ++ ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<txdw0 |= cpu_to_le32(BufferLen&0x0000ffff); // Buffer size + command header ++ ++ //offset 4 ++ ptxdesc->txdw1 |= cpu_to_le32((QSLT_MGNT<txdw1 |= cpu_to_le32(NAVUSEHDR); ++ } ++ else ++ { ++ ptxdesc->txdw4 |= cpu_to_le32(BIT(7)); // Hw set sequence number ++ ptxdesc->txdw3 |= cpu_to_le32((8 <<28)); //set bit3 to 1. Suugested by TimChen. 2009.12.29. ++ } ++ ++ if (_TRUE == IsBTQosNull) ++ { ++ ptxdesc->txdw2 |= cpu_to_le32(BIT(23)); // BT NULL ++ } ++ ++ //offset 16 ++ ptxdesc->txdw4 |= cpu_to_le32(BIT(8));//driver uses rate ++ ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) ++ // USB interface drop packet if the checksum of descriptor isn't correct. ++ // Using this checksum can let hardware recovery from packet bulk out error (e.g. Cancel URC, Bulk out error.). ++ rtl8188e_cal_txdesc_chksum(ptxdesc); ++#endif ++} ++ ++ ++#define SDIO_TX_AGG_MAX (5) ++//#define CONFIG_FIX_CORE_DUMP ==> have bug ++//#define DBG_EMINFO ++ ++#if 0 ++void rtl8188e_cal_txdesc_chksum(struct tx_desc *ptxdesc) ++{ ++ u16 *usPtr = (u16*)ptxdesc; ++ u32 count = 16; // (32 bytes / 2 bytes per XOR) => 16 times ++ u32 index; ++ u16 checksum = 0; ++ ++ ++ // Clear first ++ ptxdesc->txdw7 &= cpu_to_le32(0xffff0000); ++ ++ for (index = 0; index < count; index++) { ++ checksum ^= le16_to_cpu(*(usPtr + index)); ++ } ++ ++ ptxdesc->txdw7 |= cpu_to_le32(checksum & 0x0000ffff); ++} ++ ++static void fill_txdesc_sectype(struct pkt_attrib *pattrib, PTXDESC ptxdesc) ++{ ++ if ((pattrib->encrypt > 0) && !pattrib->bswenc) ++ { ++ switch (pattrib->encrypt) ++ { ++ // SEC_TYPE ++ case _WEP40_: ++ case _WEP104_: ++ case _TKIP_: ++ case _TKIP_WTMIC_: ++ ptxdesc->sectype = 1; ++ break; ++ ++ case _AES_: ++ ptxdesc->sectype = 3; ++ break; ++ ++ case _NO_PRIVACY_: ++ default: ++ break; ++ } ++ } ++} ++ ++static void fill_txdesc_vcs(struct pkt_attrib *pattrib, PTXDESC ptxdesc) ++{ ++ //DBG_8192C("cvs_mode=%d\n", pattrib->vcs_mode); ++ ++ switch (pattrib->vcs_mode) ++ { ++ case RTS_CTS: ++ ptxdesc->rtsen = 1; ++ break; ++ ++ case CTS_TO_SELF: ++ ptxdesc->cts2self = 1; ++ break; ++ ++ case NONE_VCS: ++ default: ++ break; ++ } ++ ++ if (pattrib->vcs_mode) ++ ptxdesc->hw_rts_en = 1; // ENABLE HW RTS ++} ++ ++static void fill_txdesc_phy(struct pkt_attrib *pattrib, PTXDESC ptxdesc) ++{ ++ //DBG_8192C("bwmode=%d, ch_off=%d\n", pattrib->bwmode, pattrib->ch_offset); ++ ++ if (pattrib->ht_en) ++ { ++ if (pattrib->bwmode & HT_CHANNEL_WIDTH_40) ++ ptxdesc->data_bw = 1; ++ ++ switch (pattrib->ch_offset) ++ { ++ case HAL_PRIME_CHNL_OFFSET_DONT_CARE: ++ ptxdesc->data_sc = 0; ++ break; ++ ++ case HAL_PRIME_CHNL_OFFSET_LOWER: ++ ptxdesc->data_sc = 1; ++ break; ++ ++ case HAL_PRIME_CHNL_OFFSET_UPPER: ++ ptxdesc->data_sc = 2; ++ break; ++ ++ default: ++ ptxdesc->data_sc = 3; // Duplicate ++ break; ++ } ++ } ++} ++#endif ++ ++void rtl8188es_fill_default_txdesc( ++ struct xmit_frame *pxmitframe, ++ u8 *pbuf) ++{ ++ PADAPTER padapter; ++ HAL_DATA_TYPE *pHalData; ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ struct dm_priv *pdmpriv; ++ struct pkt_attrib *pattrib; ++ PTXDESC ptxdesc; ++ s32 bmcst; ++ ++ ++ padapter = pxmitframe->padapter; ++ pHalData = GET_HAL_DATA(padapter); ++ //pdmpriv = &pHalData->dmpriv; ++ pmlmeext = &padapter->mlmeextpriv; ++ pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ pattrib = &pxmitframe->attrib; ++ bmcst = IS_MCAST(pattrib->ra); ++ ++ ptxdesc = (PTXDESC)pbuf; ++ ++ ++ if (pxmitframe->frame_tag == DATA_FRAMETAG) ++ { ++ ptxdesc->macid = pattrib->mac_id; // CAM_ID(MAC_ID) ++ ++ if (pattrib->ampdu_en == _TRUE) ++ ptxdesc->agg_en = 1; // AGG EN ++ else ++ ptxdesc->bk = 1; // AGG BK ++ ++ ptxdesc->qsel = pattrib->qsel; ++ ptxdesc->rate_id = pattrib->raid; ++ ++ fill_txdesc_sectype(pattrib, ptxdesc); ++ ++ ptxdesc->seq = pattrib->seqnum; ++ ++ //todo: qos_en ++ ++ ptxdesc->userate = 1; // driver uses rate ++ ++ if ((pattrib->ether_type != 0x888e) && ++ (pattrib->ether_type != 0x0806) && ++ (pattrib->dhcp_pkt != 1)) ++ { ++ // Non EAP & ARP & DHCP type data packet ++ ++ fill_txdesc_vcs(pattrib, ptxdesc); ++ fill_txdesc_phy(pattrib, ptxdesc); ++ ++ ptxdesc->rtsrate = 8; // RTS Rate=24M ++ ptxdesc->data_ratefb_lmt = 0x1F; ++ ptxdesc->rts_ratefb_lmt = 0xF; ++ #if (RATE_ADAPTIVE_SUPPORT == 1) ++ if(pattrib->ht_en){ ++ ptxdesc->sgi = ODM_RA_GetShortGI_8188E(&pHalData->odmpriv,pattrib->mac_id); ++ } ++ ptxdesc->datarate = ODM_RA_GetDecisionRate_8188E(&pHalData->odmpriv,pattrib->mac_id); ++ ++ //for debug ++ #if 1 ++ if(padapter->fix_rate!= 0xFF){ ++ ptxdesc->datarate = padapter->fix_rate; ++ } ++ #endif ++ #if (POWER_TRAINING_ACTIVE==1) ++ ptxdesc->pwr_status = ODM_RA_GetHwPwrStatus_8188E(&pHalData->odmpriv,pattrib->mac_id); ++ #endif ++ #else ++ ptxdesc->datarate = 0x13; //MCS7 ++ ptxdesc->sgi = 1; // SGI ++ if(padapter->fix_rate!= 0xFF){//modify datat by iwpriv ++ ptxdesc->datarate = padapter->fix_rate; ++ } ++ #endif ++ ++ ++ } ++ else ++ { ++ // EAP data packet and ARP and DHCP packet. ++ // Use the 1M or 6M data rate to send the EAP/ARP packet. ++ // This will maybe make the handshake smooth. ++ ++ ptxdesc->bk = 1; // AGG BK ++ ++ if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT) ++ ptxdesc->data_short = 1;// DATA_SHORT ++ ++ ptxdesc->datarate = MRateToHwRate(pmlmeext->tx_rate); ++ } ++ ++ ptxdesc->usb_txagg_num = pxmitframe->agg_num; ++ } ++ else if (pxmitframe->frame_tag == MGNT_FRAMETAG) ++ { ++// RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("%s: MGNT_FRAMETAG\n", __FUNCTION__)); ++ ++ ptxdesc->macid = pattrib->mac_id; // CAM_ID(MAC_ID) ++ ptxdesc->qsel = pattrib->qsel; ++ ptxdesc->rate_id = pattrib->raid; // Rate ID ++ ptxdesc->seq = pattrib->seqnum; ++ ptxdesc->userate = 1; // driver uses rate, 1M ++ ptxdesc->rty_lmt_en = 1; // retry limit enable ++ ptxdesc->data_rt_lmt = 6; // retry limit = 6 ++ ++#ifdef CONFIG_XMIT_ACK ++ //CCX-TXRPT ack for xmit mgmt frames. ++ if (pxmitframe->ack_report) { ++ #ifdef DBG_CCX ++ static u16 ccx_sw = 0x123; ++ txdesc_set_ccx_sw_88e(ptxdesc, ccx_sw); ++ DBG_871X("%s set ccx, sw:0x%03x\n", __func__, ccx_sw); ++ ccx_sw = (ccx_sw+1)%0xfff; ++ #endif ++ ptxdesc->ccx = 1; ++ } ++#endif //CONFIG_XMIT_ACK ++ ++#ifdef CONFIG_INTEL_PROXIM ++ if((padapter->proximity.proxim_on==_TRUE)&&(pattrib->intel_proxim==_TRUE)){ ++ DBG_871X("\n %s pattrib->rate=%d\n",__FUNCTION__,pattrib->rate); ++ ptxdesc->datarate = pattrib->rate; ++ } ++ else ++#endif ++ { ++ ptxdesc->datarate = MRateToHwRate(pmlmeext->tx_rate); ++ } ++ } ++ else if (pxmitframe->frame_tag == TXAGG_FRAMETAG) ++ { ++ RT_TRACE(_module_hal_xmit_c_, _drv_warning_, ("%s: TXAGG_FRAMETAG\n", __FUNCTION__)); ++ } ++#ifdef CONFIG_MP_INCLUDED ++ else if (pxmitframe->frame_tag == MP_FRAMETAG) ++ { ++ struct tx_desc *pdesc; ++ ++ pdesc = (struct tx_desc*)ptxdesc; ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("%s: MP_FRAMETAG\n", __FUNCTION__)); ++ fill_txdesc_for_mp(padapter, pdesc); ++ ++ pdesc->txdw0 = le32_to_cpu(pdesc->txdw0); ++ pdesc->txdw1 = le32_to_cpu(pdesc->txdw1); ++ pdesc->txdw2 = le32_to_cpu(pdesc->txdw2); ++ pdesc->txdw3 = le32_to_cpu(pdesc->txdw3); ++ pdesc->txdw4 = le32_to_cpu(pdesc->txdw4); ++ pdesc->txdw5 = le32_to_cpu(pdesc->txdw5); ++ pdesc->txdw6 = le32_to_cpu(pdesc->txdw6); ++ pdesc->txdw7 = le32_to_cpu(pdesc->txdw7); ++ } ++#endif // CONFIG_MP_INCLUDED ++ else ++ { ++ RT_TRACE(_module_hal_xmit_c_, _drv_warning_, ("%s: frame_tag=0x%x\n", __FUNCTION__, pxmitframe->frame_tag)); ++ ++ ptxdesc->macid = 4; // CAM_ID(MAC_ID) ++ ptxdesc->rate_id = 6; // Rate ID ++ ptxdesc->seq = pattrib->seqnum; ++ ptxdesc->userate = 1; // driver uses rate ++ ptxdesc->datarate = MRateToHwRate(pmlmeext->tx_rate); ++ } ++ ++ ptxdesc->pktlen = pattrib->last_txcmdsz; ++ if (pxmitframe->frame_tag == DATA_FRAMETAG){ ++ #ifdef CONFIG_TX_EARLY_MODE ++ ptxdesc->offset = TXDESC_SIZE +EARLY_MODE_INFO_SIZE ; ++ ptxdesc->pkt_offset = 0x01; ++ #else ++ ptxdesc->offset = TXDESC_SIZE ; ++ ptxdesc->pkt_offset = 0; ++ #endif ++ } ++ else{ ++ ptxdesc->offset = TXDESC_SIZE ; ++ } ++ ++ if (bmcst) ptxdesc->bmc = 1; ++ ptxdesc->ls = 1; ++ ptxdesc->fs = 1; ++ ptxdesc->own = 1; ++ ++ // 2009.11.05. tynli_test. Suggested by SD4 Filen for FW LPS. ++ // (1) The sequence number of each non-Qos frame / broadcast / multicast / ++ // mgnt frame should be controled by Hw because Fw will also send null data ++ // which we cannot control when Fw LPS enable. ++ // --> default enable non-Qos data sequense number. 2010.06.23. by tynli. ++ // (2) Enable HW SEQ control for beacon packet, because we use Hw beacon. ++ // (3) Use HW Qos SEQ to control the seq num of Ext port non-Qos packets. ++ // 2010.06.23. Added by tynli. ++ if (!pattrib->qos_en) ++ { ++ // Hw set sequence number ++ ptxdesc->hwseq_en = 1; // HWSEQ_EN ++ ptxdesc->hwseq_sel = 0; // HWSEQ_SEL ++ } ++ ++} ++ ++/* ++ * Description: ++ * ++ * Parameters: ++ * pxmitframe xmitframe ++ * pbuf where to fill tx desc ++ */ ++void rtl8188es_update_txdesc(struct xmit_frame *pxmitframe, u8 *pbuf) ++{ ++ struct tx_desc *pdesc; ++ ++ ++ pdesc = (struct tx_desc*)pbuf; ++ _rtw_memset(pdesc, 0, sizeof(struct tx_desc)); ++ ++ rtl8188es_fill_default_txdesc(pxmitframe, pbuf); ++ ++ pdesc->txdw0 = cpu_to_le32(pdesc->txdw0); ++ pdesc->txdw1 = cpu_to_le32(pdesc->txdw1); ++ pdesc->txdw2 = cpu_to_le32(pdesc->txdw2); ++ pdesc->txdw3 = cpu_to_le32(pdesc->txdw3); ++ pdesc->txdw4 = cpu_to_le32(pdesc->txdw4); ++ pdesc->txdw5 = cpu_to_le32(pdesc->txdw5); ++ pdesc->txdw6 = cpu_to_le32(pdesc->txdw6); ++ pdesc->txdw7 = cpu_to_le32(pdesc->txdw7); ++ ++ rtl8188e_cal_txdesc_chksum(pdesc); ++} ++ ++static inline u32 ffaddr2deviceId(struct dvobj_priv *pdvobj, u32 addr) ++{ ++ return pdvobj->Queue2Pipe[addr]; ++} ++ ++#ifdef CONFIG_SDIO_REDUCE_TX_POLLING ++static u8 rtl8188es_query_tx_freepage(_adapter *padapter, struct xmit_buf *pxmitbuf) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ u8 TxRequiredPageNum = 0; ++ u8 DedicatedPgNum = 0; ++ u8 RequiredPublicFreePgNum = 0; ++ u8 PageIdx = 0; ++ u8 CheckStep = 0; ++ u8 bResult = _TRUE; ++ u8 bUpdatePageNum = _FALSE; ++ u32 deviceId; ++ ++ ++ TxRequiredPageNum = pxmitbuf->pg_num; ++ ++ deviceId = ffaddr2deviceId(pdvobjpriv, pxmitbuf->ff_hwaddr); ++ ++ // translate fifo addr to queue index ++ switch (deviceId) { ++ case WLAN_TX_HIQ_DEVICE_ID: ++ PageIdx = HI_QUEUE_IDX; ++ break; ++ ++ case WLAN_TX_MIQ_DEVICE_ID: ++ PageIdx = MID_QUEUE_IDX; ++ break; ++ ++ case WLAN_TX_LOQ_DEVICE_ID: ++ PageIdx = LOW_QUEUE_IDX; ++ break; ++ } ++ ++ do { ++ if ( ++ (padapter->bSurpriseRemoved == _TRUE) || (padapter->bDriverStopped == _TRUE) ++#ifdef CONFIG_CONCURRENT_MODE ++ ||((padapter->pbuddy_adapter) ++ && ((padapter->pbuddy_adapter->bSurpriseRemoved) ||(padapter->pbuddy_adapter->bDriverStopped))) ++#endif ++ ++ ){ ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ++ ("%s: bSurpriseRemoved(update TX FIFO page)\n", __FUNCTION__)); ++ break; ++ } ++ ++ // The number of page which public page is included is available . ++ if ((pHalData->SdioTxFIFOFreePage[PageIdx]+pHalData->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX]) > (TxRequiredPageNum+1)) { ++ DedicatedPgNum = pHalData->SdioTxFIFOFreePage[PageIdx]; ++ if (TxRequiredPageNum <= DedicatedPgNum) { ++ pHalData->SdioTxFIFOFreePage[PageIdx] -= TxRequiredPageNum; ++ break; ++ } else { ++ pHalData->SdioTxFIFOFreePage[PageIdx] = 0; ++ RequiredPublicFreePgNum = TxRequiredPageNum - DedicatedPgNum; ++ pHalData->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX] -= RequiredPublicFreePgNum; ++ break; ++ } ++ } else { // Total number of page is NOT available, so update current FIFO status. ++ if (!bUpdatePageNum) { ++ bResult = HalQueryTxBufferStatus8189ESdio(padapter); // Set to default value. ++ bUpdatePageNum = _TRUE; ++ } else { ++ bResult = _FALSE; ++ } ++ } ++ }while(++CheckStep < 2); // step1: user page variables, step2: physical page number ++ ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("%s(): HIQ(%#x), MIQ(%#x), LOQ(%#x), PUBQ(%#x)\n", ++ __FUNCTION__, ++ pHalData->SdioTxFIFOFreePage[HI_QUEUE_IDX], ++ pHalData->SdioTxFIFOFreePage[MID_QUEUE_IDX], ++ pHalData->SdioTxFIFOFreePage[LOW_QUEUE_IDX], ++ pHalData->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX])); ++ ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("%s(): TxRequiredPageNum(%d) is available to send?(%d)\n", ++ __FUNCTION__, TxRequiredPageNum, bResult)); ++ ++ return bResult; ++} ++#else ++static u8 rtl8188es_query_tx_freepage(_adapter *padapter, struct xmit_buf *pxmitbuf) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ u8 TxRequiredPageNum = 0; ++ u8 DedicatedPgNum = 0; ++ u8 RequiredPublicFreePgNum = 0; ++ u8 PageIdx = 0; ++ u8 bResult = _TRUE; ++ u32 n, deviceId; ++ ++ TxRequiredPageNum = pxmitbuf->pg_num; ++ ++ deviceId = ffaddr2deviceId(pdvobjpriv, pxmitbuf->ff_hwaddr); ++ ++ // translate fifo addr to queue index ++ switch (deviceId) { ++ case WLAN_TX_HIQ_DEVICE_ID: ++ PageIdx = HI_QUEUE_IDX; ++ break; ++ ++ case WLAN_TX_MIQ_DEVICE_ID: ++ PageIdx = MID_QUEUE_IDX; ++ break; ++ ++ case WLAN_TX_LOQ_DEVICE_ID: ++ PageIdx = LOW_QUEUE_IDX; ++ break; ++ } ++ ++ // check if hardware tx fifo page is enough ++ n = 0; ++ do { ++ if ( ++ (padapter->bSurpriseRemoved == _TRUE) || (padapter->bDriverStopped == _TRUE) ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ ||((padapter->pbuddy_adapter) ++ && ((padapter->pbuddy_adapter->bSurpriseRemoved) ||(padapter->pbuddy_adapter->bDriverStopped))) ++#endif ++ ){ ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ++ ("%s: bSurpriseRemoved(update TX FIFO page)\n", __FUNCTION__)); ++ break; ++ } ++ ++ ++ // The number of page which public page is included is available . ++ if ((pHalData->SdioTxFIFOFreePage[PageIdx]+pHalData->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX]) > (TxRequiredPageNum+1)) { ++ DedicatedPgNum = pHalData->SdioTxFIFOFreePage[PageIdx]; ++ if (TxRequiredPageNum <= DedicatedPgNum) { ++ pHalData->SdioTxFIFOFreePage[PageIdx] -= TxRequiredPageNum; ++ break; ++ } else { ++ pHalData->SdioTxFIFOFreePage[PageIdx] = 0; ++ RequiredPublicFreePgNum = TxRequiredPageNum - DedicatedPgNum; ++ pHalData->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX] -= RequiredPublicFreePgNum; ++ break; ++ } ++ } ++ ++ n++; ++ ++#if 0 ++ if (n >= 5000) ++ { ++ u8 reg_value_1 = 0; ++ u8 reg_value_2 = 0; ++ u8 reg_value_3 = 0; ++ ++ //try to recover the transmission ++ reg_value_1 = rtw_read8(padapter, REG_SYS_FUNC_EN); ++ reg_value_2 = rtw_read8(padapter, REG_CR); ++ reg_value_3 = rtw_read8(padapter, REG_TXPAUSE); ++ DBG_871X("Before recovery: REG_SYS_FUNC_EN = 0x%X, REG_CR = 0x%X, REG_TXPAUSE = 0x%X\n", reg_value_1, reg_value_2, reg_value_3); ++ ++ rtw_write8(padapter, REG_SYS_FUNC_EN, reg_value_1 | 0x01); ++ rtw_write8(padapter, REG_CR, reg_value_2 | 0xC0); ++ rtw_write8(padapter, REG_TXPAUSE, 0); ++ DBG_871X("After recovery: REG_SYS_FUNC_EN = 0x%X, REG_CR = 0x%X, REG_TXPAUSE = 0x%X\n", ++ rtw_read8(padapter, REG_SYS_FUNC_EN), rtw_read8(padapter, REG_CR), rtw_read8(padapter, REG_TXPAUSE)); ++ } ++#endif ++ ++ if ((n % 60) == 0) {//or 80 ++ //DBG_871X("%s: FIFO starvation!(%d) len=%d agg=%d page=(R)%d(A)%d\n", ++ // __func__, n, pxmitbuf->len, pxmitbuf->agg_num, pframe->pg_num, freePage[PageIdx] + freePage[PUBLIC_QUEUE_IDX]); ++ rtw_msleep_os(10); ++ rtw_yield_os(); ++ } ++ ++ // Total number of page is NOT available, so update current FIFO status ++ HalQueryTxBufferStatus8189ESdio(padapter); ++ } while (1); ++ ++ return bResult; ++} ++#endif ++ ++//todo: static ++s32 rtl8188es_dequeue_writeport(PADAPTER padapter, u8 *freePage) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct xmit_buf *pxmitbuf; ++ PADAPTER pri_padapter = padapter; ++ s32 ret = 0; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (padapter->adapter_type > 0) ++ pri_padapter = padapter->pbuddy_adapter; ++ ++ if(rtw_buddy_adapter_up(padapter)) ++ ret = check_buddy_fwstate( padapter, _FW_UNDER_SURVEY); ++#endif ++ ++ ret = ret || check_fwstate(pmlmepriv, _FW_UNDER_SURVEY); ++ ++ if (_TRUE == ret) ++ pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv); ++ else ++ pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv); ++ ++ if (pxmitbuf == NULL) ++ return _TRUE; ++ ++query_free_page: ++ // check if hardware tx fifo page is enough ++ if( _FALSE == rtl8188es_query_tx_freepage(pri_padapter, pxmitbuf)) ++ { ++ rtw_msleep_os(1); ++ goto query_free_page; ++ } ++ ++ if ((padapter->bSurpriseRemoved == _TRUE) ++ || (padapter->bDriverStopped == _TRUE) ++#ifdef CONFIG_CONCURRENT_MODE ++ ||((padapter->pbuddy_adapter) ++ && ((padapter->pbuddy_adapter->bSurpriseRemoved) ||(padapter->pbuddy_adapter->bDriverStopped))) ++#endif ++ ){ ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ++ ("%s: bSurpriseRemoved(wirte port)\n", __FUNCTION__)); ++ goto free_xmitbuf; ++ } ++ ++ rtw_write_port(padapter, ffaddr2deviceId(pdvobjpriv, pxmitbuf->ff_hwaddr), pxmitbuf->len, (u8 *)pxmitbuf); ++ ++free_xmitbuf: ++ //rtw_free_xmitframe(pxmitpriv, pframe); ++ //pxmitbuf->priv_data = NULL; ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ ++#ifdef CONFIG_SDIO_TX_TASKLET ++ tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); ++#endif ++ ++ return _FAIL; ++} ++ ++/* ++ * Description ++ * Transmit xmitbuf to hardware tx fifo ++ * ++ * Return ++ * _SUCCESS ok ++ * _FAIL something error ++ */ ++s32 rtl8188es_xmit_buf_handler(PADAPTER padapter) ++{ ++ struct mlme_priv *pmlmepriv; ++ struct xmit_priv *pxmitpriv; ++ struct xmit_buf *pxmitbuf; ++ struct xmit_frame *pframe; ++ u8 *freePage; ++ u32 requiredPage; ++ u8 PageIdx , queue_empty; ++ _irqL irql; ++ u32 n; ++ s32 ret; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++#ifdef CONFIG_CONCURRENT_MODE ++ s32 buddy_rm_stop = _FAIL; ++#endif ++ ++ pmlmepriv = &padapter->mlmepriv; ++ pxmitpriv = &padapter->xmitpriv; ++ freePage = pHalData->SdioTxFIFOFreePage; ++ ++ ret = _rtw_down_sema(&pxmitpriv->xmit_sema); ++ if (ret == _FAIL) { ++ RT_TRACE(_module_hal_xmit_c_, _drv_emerg_, ("down SdioXmitBufSema fail!\n")); ++ return _FAIL; ++ } ++ ++//#ifdef CONFIG_CONCURRENT_MODE ++// if (padapter->pbuddy_adapter->bup){ ++// if ((padapter->pbuddy_adapter->bSurpriseRemoved == _TRUE) || ++// (padapter->pbuddy_adapter->bDriverStopped == _TRUE)) ++// buddy_rm_stop = _TRUE; ++// } ++//#endif ++ if ((padapter->bSurpriseRemoved == _TRUE) || ++ (padapter->bDriverStopped == _TRUE) ++//#ifdef CONFIG_CONCURRENT_MODE ++// ||(buddy_rm_stop == _TRUE) ++//#endif ++ ) { ++ ++#ifdef CONFIG_LPS_LCLK ++ rtw_unregister_tx_alive(padapter); ++#endif ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ++ ("%s: bDriverStopped(%d) bSurpriseRemoved(%d)\n", ++ __FUNCTION__, padapter->bDriverStopped, padapter->bSurpriseRemoved)); ++ return _FAIL; ++ } ++ ++#ifdef CONFIG_LPS_LCLK ++ ret = rtw_register_tx_alive(padapter); ++ if (ret != _SUCCESS) return _SUCCESS; ++#endif ++ ++ do { ++ queue_empty = rtl8188es_dequeue_writeport(padapter, freePage); ++// dump secondary adapter xmitbuf ++#ifdef CONFIG_CONCURRENT_MODE ++ if(rtw_buddy_adapter_up(padapter)) ++ queue_empty &= rtl8188es_dequeue_writeport(padapter->pbuddy_adapter, freePage); ++#endif ++ ++ } while ( !queue_empty); ++ ++#ifdef CONFIG_LPS_LCLK ++ rtw_unregister_tx_alive(padapter); ++#endif ++ return _SUCCESS; ++} ++ ++#if 0 ++/* ++ * Description: ++ * Aggregation packets and send to hardware ++ * ++ * Return: ++ * 0 Success ++ * -1 Hardware resource(TX FIFO) not ready ++ * -2 Software resource(xmitbuf) not ready ++ */ ++#ifdef CONFIG_TX_EARLY_MODE ++#if RTL8188E_EARLY_MODE_PKT_NUM_10 == 1 ++ #define EARLY_MODE_MAX_PKT_NUM 10 ++#else ++ #define EARLY_MODE_MAX_PKT_NUM 5 ++#endif ++ ++ ++struct EMInfo{ ++ u8 EMPktNum; ++ u16 EMPktLen[EARLY_MODE_MAX_PKT_NUM]; ++}; ++ ++ ++void ++InsertEMContent_8188E( ++ struct EMInfo *pEMInfo, ++ IN pu1Byte VirtualAddress) ++{ ++ ++#if RTL8188E_EARLY_MODE_PKT_NUM_10 == 1 ++ u1Byte index=0; ++ u4Byte dwtmp=0; ++#endif ++ ++ _rtw_memset(VirtualAddress, 0, EARLY_MODE_INFO_SIZE); ++ if(pEMInfo->EMPktNum==0) ++ return; ++ ++ #ifdef DBG_EMINFO ++ { ++ int i; ++ DBG_8192C("\n%s ==> pEMInfo->EMPktNum =%d\n",__FUNCTION__,pEMInfo->EMPktNum); ++ for(i=0;i< EARLY_MODE_MAX_PKT_NUM;i++){ ++ DBG_8192C("%s ==> pEMInfo->EMPktLen[%d] =%d\n",__FUNCTION__,i,pEMInfo->EMPktLen[i]); ++ } ++ ++ } ++ #endif ++ ++#if RTL8188E_EARLY_MODE_PKT_NUM_10 == 1 ++ SET_EARLYMODE_PKTNUM(VirtualAddress, pEMInfo->EMPktNum); ++ ++ if(pEMInfo->EMPktNum == 1){ ++ dwtmp = pEMInfo->EMPktLen[0]; ++ }else{ ++ dwtmp = pEMInfo->EMPktLen[0]; ++ dwtmp += ((dwtmp%4)?(4-dwtmp%4):0)+4; ++ dwtmp += pEMInfo->EMPktLen[1]; ++ } ++ SET_EARLYMODE_LEN0(VirtualAddress, dwtmp); ++ if(pEMInfo->EMPktNum <= 3){ ++ dwtmp = pEMInfo->EMPktLen[2]; ++ }else{ ++ dwtmp = pEMInfo->EMPktLen[2]; ++ dwtmp += ((dwtmp%4)?(4-dwtmp%4):0)+4; ++ dwtmp += pEMInfo->EMPktLen[3]; ++ } ++ SET_EARLYMODE_LEN1(VirtualAddress, dwtmp); ++ if(pEMInfo->EMPktNum <= 5){ ++ dwtmp = pEMInfo->EMPktLen[4]; ++ }else{ ++ dwtmp = pEMInfo->EMPktLen[4]; ++ dwtmp += ((dwtmp%4)?(4-dwtmp%4):0)+4; ++ dwtmp += pEMInfo->EMPktLen[5]; ++ } ++ SET_EARLYMODE_LEN2_1(VirtualAddress, dwtmp&0xF); ++ SET_EARLYMODE_LEN2_2(VirtualAddress, dwtmp>>4); ++ if(pEMInfo->EMPktNum <= 7){ ++ dwtmp = pEMInfo->EMPktLen[6]; ++ }else{ ++ dwtmp = pEMInfo->EMPktLen[6]; ++ dwtmp += ((dwtmp%4)?(4-dwtmp%4):0)+4; ++ dwtmp += pEMInfo->EMPktLen[7]; ++ } ++ SET_EARLYMODE_LEN3(VirtualAddress, dwtmp); ++ if(pEMInfo->EMPktNum <= 9){ ++ dwtmp = pEMInfo->EMPktLen[8]; ++ }else{ ++ dwtmp = pEMInfo->EMPktLen[8]; ++ dwtmp += ((dwtmp%4)?(4-dwtmp%4):0)+4; ++ dwtmp += pEMInfo->EMPktLen[9]; ++ } ++ SET_EARLYMODE_LEN4(VirtualAddress, dwtmp); ++#else ++ SET_EARLYMODE_PKTNUM(VirtualAddress, pEMInfo->EMPktNum); ++ SET_EARLYMODE_LEN0(VirtualAddress, pEMInfo->EMPktLen[0]); ++ SET_EARLYMODE_LEN1(VirtualAddress, pEMInfo->EMPktLen[1]); ++ SET_EARLYMODE_LEN2_1(VirtualAddress, pEMInfo->EMPktLen[2]&0xF); ++ SET_EARLYMODE_LEN2_2(VirtualAddress, pEMInfo->EMPktLen[2]>>4); ++ SET_EARLYMODE_LEN3(VirtualAddress, pEMInfo->EMPktLen[3]); ++ SET_EARLYMODE_LEN4(VirtualAddress, pEMInfo->EMPktLen[4]); ++#endif ++ //RT_PRINT_DATA(COMP_SEND, DBG_LOUD, "EMHdr:", VirtualAddress, 8); ++ ++} ++ ++ ++ ++void UpdateEarlyModeInfo8188E(struct xmit_priv *pxmitpriv,struct xmit_buf *pxmitbuf ) ++{ ++ //_adapter *padapter, struct xmit_frame *pxmitframe,struct tx_servq *ptxservq ++ int index,j; ++ u16 offset,pktlen; ++ PTXDESC ptxdesc; ++ ++ u8 *pmem,*pEMInfo_mem; ++ s8 node_num_0=0,node_num_1=0; ++ struct EMInfo eminfo; ++ struct agg_pkt_info *paggpkt; ++ struct xmit_frame *pframe = (struct xmit_frame*)pxmitbuf->priv_data; ++ pmem= pframe->buf_addr; ++ ++ #ifdef DBG_EMINFO ++ DBG_8192C("\n%s ==> agg_num:%d\n",__FUNCTION__, pframe->agg_num); ++ for(index=0;indexagg_num;index++){ ++ offset = pxmitpriv->agg_pkt[index].offset; ++ pktlen = pxmitpriv->agg_pkt[index].pkt_len; ++ DBG_8192C("%s ==> agg_pkt[%d].offset=%d\n",__FUNCTION__,index,offset); ++ DBG_8192C("%s ==> agg_pkt[%d].pkt_len=%d\n",__FUNCTION__,index,pktlen); ++ } ++ #endif ++ ++ if( pframe->agg_num > EARLY_MODE_MAX_PKT_NUM) ++ { ++ node_num_0 = pframe->agg_num; ++ node_num_1= EARLY_MODE_MAX_PKT_NUM-1; ++ } ++ ++ for(index=0;indexagg_num;index++){ ++ offset = pxmitpriv->agg_pkt[index].offset; ++ pktlen = pxmitpriv->agg_pkt[index].pkt_len; ++ ++ _rtw_memset(&eminfo,0,sizeof(struct EMInfo)); ++ if( pframe->agg_num > EARLY_MODE_MAX_PKT_NUM){ ++ if(node_num_0 > EARLY_MODE_MAX_PKT_NUM){ ++ eminfo.EMPktNum = EARLY_MODE_MAX_PKT_NUM; ++ node_num_0--; ++ } ++ else{ ++ eminfo.EMPktNum = node_num_1; ++ node_num_1--; ++ } ++ } ++ else{ ++ eminfo.EMPktNum = pframe->agg_num-(index+1); ++ } ++ for(j=0;j< eminfo.EMPktNum ;j++){ ++ eminfo.EMPktLen[j] = pxmitpriv->agg_pkt[index+1+j].pkt_len+4;//CRC ++ } ++ ++ if(pmem){ ++ ptxdesc = (PTXDESC)(pmem+offset); ++ pEMInfo_mem = pmem+offset+TXDESC_SIZE; ++ #ifdef DBG_EMINFO ++ DBG_8192C("%s ==> desc.pkt_len=%d\n",__FUNCTION__,ptxdesc->pktlen); ++ #endif ++ InsertEMContent_8188E(&eminfo,pEMInfo_mem); ++ } ++ ++ ++ } ++ _rtw_memset(pxmitpriv->agg_pkt,0,sizeof(struct agg_pkt_info)*MAX_AGG_PKT_NUM); ++ ++} ++#endif ++ ++#endif ++ ++#ifdef CONFIG_SDIO_TX_TASKLET ++static s32 xmit_xmitframes(PADAPTER padapter, struct xmit_priv *pxmitpriv) ++{ ++ s32 ret; ++ _irqL irqL; ++ struct xmit_buf *pxmitbuf; ++ struct hw_xmit *phwxmit = pxmitpriv->hwxmits; ++ struct tx_servq *ptxservq = NULL; ++ _list *xmitframe_plist = NULL, *xmitframe_phead = NULL; ++ struct xmit_frame *pxmitframe = NULL, *pfirstframe = NULL; ++ u32 pbuf = 0; // next pkt address ++ u32 pbuf_tail = 0; // last pkt tail ++ u32 txlen = 0; //packet length, except TXDESC_SIZE and PKT_OFFSET ++ u32 total_len = 0; ++ u8 ac_index = 0; ++ u8 bfirst = _TRUE;//first aggregation xmitframe ++ u8 bulkstart = _FALSE; ++#ifdef CONFIG_TX_EARLY_MODE ++ u8 pkt_index=0; ++#endif ++ ++ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); ++ if (pxmitbuf == NULL) { ++ RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("%s: xmit_buf is not enough!\n", __FUNCTION__)); ++ return _FALSE; ++ } ++ ++ do { ++ //3 1. pick up first frame ++ if(bfirst) ++ { ++ pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); ++ if (pxmitframe == NULL) { ++ // no more xmit frame, release xmit buffer ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ return _FALSE; ++ } ++ ++ pxmitframe->pxmitbuf = pxmitbuf; ++ pxmitframe->buf_addr = pxmitbuf->pbuf; ++ pxmitbuf->priv_data = pxmitframe; ++ pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe); ++ ++ pfirstframe = pxmitframe; ++ ++ _enter_critical_bh(&pxmitpriv->lock, &irqL); ++ ptxservq = rtw_get_sta_pending(padapter, pfirstframe->attrib.psta, pfirstframe->attrib.priority, (u8 *)(&ac_index)); ++ _exit_critical_bh(&pxmitpriv->lock, &irqL); ++ } ++ //3 2. aggregate same priority and same DA(AP or STA) frames ++ else ++ { ++ // dequeue same priority packet from station tx queue ++ _enter_critical_bh(&pxmitpriv->lock, &irqL); ++ ++ if (_rtw_queue_empty(&ptxservq->sta_pending) == _FALSE) ++ { ++ xmitframe_phead = get_list_head(&ptxservq->sta_pending); ++ xmitframe_plist = get_next(xmitframe_phead); ++ ++ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); ++ ++ // check xmit_buf size enough or not ++ txlen = TXDESC_SIZE + ++ #ifdef CONFIG_TX_EARLY_MODE ++ EARLY_MODE_INFO_SIZE + ++ #endif ++ rtw_wlan_pkt_size(pxmitframe); ++ ++ if (pbuf + _RND8(txlen) > MAX_XMITBUF_SZ) ++ { ++ bulkstart = _TRUE; ++ } ++ else ++ { ++ rtw_list_delete(&pxmitframe->list); ++ ptxservq->qcnt--; ++ phwxmit[ac_index].accnt--; ++ ++ //Remove sta node when there is no pending packets. ++ if (_rtw_queue_empty(&ptxservq->sta_pending) == _TRUE) ++ rtw_list_delete(&ptxservq->tx_pending); ++ } ++ } ++ else ++ { ++ bulkstart = _TRUE; ++ } ++ ++ _exit_critical_bh(&pxmitpriv->lock, &irqL); ++ ++ if(bulkstart) ++ { ++ break; ++ } ++ ++ pxmitframe->buf_addr = pxmitbuf->pbuf + pbuf; ++ ++ pxmitframe->agg_num = 0; // not first frame of aggregation ++ } ++ ++ ret = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); ++ if (ret == _FAIL) { ++ DBG_871X("%s: coalesce FAIL!", __FUNCTION__); ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ continue; ++ } ++ ++ // always return ndis_packet after rtw_xmitframe_coalesce ++ //rtw_os_xmit_complete(padapter, pxmitframe); ++ ++#ifdef CONFIG_TX_EARLY_MODE ++ pxmitpriv->agg_pkt[pkt_index].pkt_len = pxmitframe->attrib.last_txcmdsz; //get from rtw_xmitframe_coalesce ++ pxmitpriv->agg_pkt[pkt_index].offset = _RND8(pxmitframe->attrib.last_txcmdsz+ TXDESC_SIZE+EARLY_MODE_INFO_SIZE); ++ pkt_index++; ++#endif ++ ++ if(bfirst) ++ { ++ txlen = TXDESC_SIZE + ++ #ifdef CONFIG_TX_EARLY_MODE ++ EARLY_MODE_INFO_SIZE + ++ #endif ++ pxmitframe->attrib.last_txcmdsz; ++ ++ total_len = txlen; ++ ++ pxmitframe->pg_num = (txlen + 127)/128; ++ pxmitbuf->pg_num = (txlen + 127)/128; ++ pbuf_tail = txlen; ++ pbuf = _RND8(pbuf_tail); ++ bfirst = _FALSE; ++ } ++ else ++ { ++ rtl8188es_update_txdesc(pxmitframe, pxmitframe->buf_addr); ++ ++ // don't need xmitframe any more ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ ++ pxmitframe->pg_num = (txlen + 127)/128; ++ //pfirstframe->pg_num += pxmitframe->pg_num; ++ pxmitbuf->pg_num += (txlen + 127)/128; ++ ++ total_len += txlen; ++ ++ // handle pointer and stop condition ++ pbuf_tail = pbuf + txlen; ++ pbuf = _RND8(pbuf_tail); ++ ++ pfirstframe->agg_num++; ++ #ifdef SDIO_TX_AGG_MAX ++ if(pfirstframe->agg_num >= SDIO_TX_AGG_MAX) ++ break; ++ #endif ++ } ++ }while(1); ++ ++ //3 3. update first frame txdesc ++ rtl8188es_update_txdesc(pfirstframe, pfirstframe->buf_addr); ++#ifdef CONFIG_TX_EARLY_MODE ++ UpdateEarlyModeInfo8188E(pxmitpriv,pxmitbuf ); ++#endif ++ ++ // ++ pxmitbuf->agg_num = pfirstframe->agg_num; ++ pxmitbuf->priv_data = NULL; ++ ++ //3 4. write xmit buffer to USB FIFO ++ pxmitbuf->len = pbuf_tail; ++ enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf); ++ ++ //3 5. update statisitc ++ rtw_count_tx_stats(padapter, pfirstframe, total_len); ++ ++ rtw_free_xmitframe(pxmitpriv, pfirstframe); ++ ++ //rtw_yield_os(); ++ ++ return _TRUE; ++} ++ ++void rtl8188es_xmit_tasklet(void *priv) ++{ ++ int ret = _FALSE; ++ _adapter *padapter = (_adapter*)priv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ while(1) ++ { ++ if ((padapter->bDriverStopped == _TRUE)||(padapter->bSurpriseRemoved== _TRUE) || (padapter->bWritePortCancel == _TRUE)) ++ { ++ DBG_871X("xmit_tasklet => bDriverStopped or bSurpriseRemoved or bWritePortCancel\n"); ++ break; ++ } ++ ++ ret = xmit_xmitframes(padapter, pxmitpriv); ++ if(ret==_FALSE) ++ break; ++ ++ } ++} ++#else ++static s32 xmit_xmitframes(PADAPTER padapter, struct xmit_priv *pxmitpriv) ++{ ++ u32 err, agg_num=0; ++ u8 pkt_index=0; ++ struct hw_xmit *hwxmits, *phwxmit; ++ u8 idx, hwentry; ++ _irqL irql; ++ struct tx_servq *ptxservq; ++ _list *sta_plist, *sta_phead, *frame_plist, *frame_phead; ++ struct xmit_frame *pxmitframe; ++ _queue *pframe_queue; ++ struct xmit_buf *pxmitbuf; ++ u32 txlen; ++ s32 ret; ++ int inx[4]; ++ ++ err = 0; ++ hwxmits = pxmitpriv->hwxmits; ++ hwentry = pxmitpriv->hwxmit_entry; ++ ptxservq = NULL; ++ pxmitframe = NULL; ++ pframe_queue = NULL; ++ pxmitbuf = NULL; ++ ++ if (padapter->registrypriv.wifi_spec == 1) { ++ for(idx=0; idx<4; idx++) ++ inx[idx] = pxmitpriv->wmm_para_seq[idx]; ++ } else { ++ inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3; ++ } ++ ++ // 0(VO), 1(VI), 2(BE), 3(BK) ++ for (idx = 0; idx < hwentry; idx++) ++ { ++ phwxmit = hwxmits + inx[idx]; ++ ++// _enter_critical(&hwxmits->sta_queue->lock, &irqL0); ++ _enter_critical_bh(&pxmitpriv->lock, &irql); ++ ++ sta_phead = get_list_head(phwxmit->sta_queue); ++ sta_plist = get_next(sta_phead); ++ ++ while (rtw_end_of_queue_search(sta_phead, sta_plist) == _FALSE) ++ { ++ ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending); ++ ++ sta_plist = get_next(sta_plist); ++ ++ pframe_queue = &ptxservq->sta_pending; ++ ++// _enter_critical(&pframe_queue->lock, &irqL1); ++ //_enter_critical_bh(&pxmitpriv->lock, &irql); ++ ++ frame_phead = get_list_head(pframe_queue); ++ frame_plist = get_next(frame_phead); ++ ++ while (rtw_end_of_queue_search(frame_phead, frame_plist) == _FALSE) ++ { ++ pxmitframe = LIST_CONTAINOR(frame_plist, struct xmit_frame, list); ++ ++ // check xmit_buf size enough or not ++ #ifdef CONFIG_TX_EARLY_MODE ++ txlen = TXDESC_SIZE +EARLY_MODE_INFO_SIZE+ rtw_wlan_pkt_size(pxmitframe); ++ #else ++ txlen = TXDESC_SIZE + rtw_wlan_pkt_size(pxmitframe); ++ #endif ++ if ((NULL == pxmitbuf) || ++ ((pxmitbuf->ptail + txlen) > pxmitbuf->pend) ++ #ifdef SDIO_TX_AGG_MAX ++ || (agg_num>= SDIO_TX_AGG_MAX) ++ #endif ++ ) ++ { ++ if (pxmitbuf) { ++ struct xmit_frame *pframe; ++ pframe = (struct xmit_frame*)pxmitbuf->priv_data; ++ pframe->agg_num = agg_num; ++ pxmitbuf->agg_num = agg_num; ++ //DBG_8192C("==> agg_num:%d\n",agg_num); ++ rtl8188es_update_txdesc(pframe, pframe->buf_addr); ++ #ifdef CONFIG_TX_EARLY_MODE ++ UpdateEarlyModeInfo8188E(pxmitpriv, pxmitbuf); ++ #endif ++ rtw_free_xmitframe(pxmitpriv, pframe); ++ pxmitbuf->priv_data = NULL; ++ enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf); ++ //rtw_yield_os(); ++ } ++ ++ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); ++ if (pxmitbuf == NULL) { ++ RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("%s: xmit_buf is not enough!\n", __FUNCTION__)); ++ err = -2; ++ break; ++ } ++ agg_num = 0; ++ pkt_index =0; ++ } ++ ++ // ok to send, remove frame from queue ++ ++ ++ frame_plist = get_next(frame_plist); ++ rtw_list_delete(&pxmitframe->list); ++ ptxservq->qcnt--; ++ phwxmit->accnt--; ++ ++ ++ if (agg_num == 0) { ++ pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe); ++ pxmitbuf->priv_data = (u8*)pxmitframe; ++ } ++ ++ // coalesce the xmitframe to xmitbuf ++ pxmitframe->pxmitbuf = pxmitbuf; ++ pxmitframe->buf_addr = pxmitbuf->ptail; ++ ++ ret = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); ++ if (ret == _FAIL) { ++ DBG_871X("%s: coalesce FAIL!", __FUNCTION__); ++ // Todo: error handler ++ //rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ } else { ++ agg_num++; ++ if (agg_num != 1) ++ rtl8188es_update_txdesc(pxmitframe, pxmitframe->buf_addr); ++ rtw_count_tx_stats(padapter, pxmitframe, pxmitframe->attrib.last_txcmdsz); ++ #ifdef CONFIG_TX_EARLY_MODE ++ txlen = TXDESC_SIZE+ EARLY_MODE_INFO_SIZE+ pxmitframe->attrib.last_txcmdsz; ++ #else ++ txlen = TXDESC_SIZE + pxmitframe->attrib.last_txcmdsz; ++ #endif ++ pxmitframe->pg_num = (txlen + 127)/128; ++ pxmitbuf->pg_num += (txlen + 127)/128; ++ //if (agg_num != 1) ++ //((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num; ++ ++ #ifdef CONFIG_TX_EARLY_MODE ++ pxmitpriv->agg_pkt[pkt_index].pkt_len = pxmitframe->attrib.last_txcmdsz; //get from rtw_xmitframe_coalesce ++ pxmitpriv->agg_pkt[pkt_index].offset = _RND8(pxmitframe->attrib.last_txcmdsz+ TXDESC_SIZE+EARLY_MODE_INFO_SIZE); ++ #endif ++ ++ pkt_index++; ++ pxmitbuf->ptail += _RND(txlen, 8); // round to 8 bytes alignment ++ pxmitbuf->len = _RND(pxmitbuf->len, 8) + txlen; ++ } ++ ++ if (agg_num != 1) ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ pxmitframe = NULL; ++ } ++ ++ if (_rtw_queue_empty(pframe_queue)) { ++ rtw_list_delete(&ptxservq->tx_pending); ++ } ++ ++// _exit_critical(&pframe_queue->lock, &irqL1); ++ //_exit_critical_bh(&pxmitpriv->lock, &irql); ++ ++ } ++ ++// _exit_critical(&hwxmits->sta_queue->lock, &irqL0); ++ _exit_critical_bh(&pxmitpriv->lock, &irql); ++ ++ // dump xmit_buf to hw tx fifo ++ if (pxmitbuf) ++ { ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("pxmitbuf->len=%d enqueue\n",pxmitbuf->len)); ++ ++ if (pxmitbuf->len > 0) { ++ struct xmit_frame *pframe; ++ pframe = (struct xmit_frame*)pxmitbuf->priv_data; ++ pframe->agg_num = agg_num; ++ pxmitbuf->agg_num = agg_num; ++ rtl8188es_update_txdesc(pframe, pframe->buf_addr); ++ #ifdef CONFIG_TX_EARLY_MODE ++ UpdateEarlyModeInfo8188E(pxmitpriv,pxmitbuf ); ++ #endif ++ rtw_free_xmitframe(pxmitpriv, pframe); ++ pxmitbuf->priv_data = NULL; ++ enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf); ++ rtw_yield_os(); ++ } ++ else ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ ++ pxmitbuf = NULL; ++ ++ } ++ ++ } ++ ++ return err; ++ ++} ++ ++/* ++ * Description ++ * Transmit xmitframe from queue ++ * ++ * Return ++ * _SUCCESS ok ++ * _FAIL something error ++ */ ++s32 rtl8188es_xmit_handler(PADAPTER padapter) ++{ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv ; ++ s32 ret; ++ _irqL irql; ++//#ifdef CONFIG_CONCURRENT_MODE ++// s32 buddy_rm_stop = _FAIL; ++//#endif ++ ++ ++wait: ++ ret = _rtw_down_sema(&pxmitpriv->SdioXmitSema); ++ if (_FAIL == ret) { ++ RT_TRACE(_module_hal_xmit_c_, _drv_emerg_, ("%s: down sema fail!\n", __FUNCTION__)); ++ return _FAIL; ++ } ++ ++next: ++//#ifdef CONFIG_CONCURRENT_MODE ++// if (padapter->pbuddy_adapter){ ++// if ((padapter->pbuddy_adapter->bSurpriseRemoved == _TRUE) || ++// (padapter->pbuddy_adapter->bDriverStopped == _TRUE)) ++// buddy_rm_stop = _TRUE; ++// } ++//#endif ++ if ((padapter->bSurpriseRemoved == _TRUE) || ++ (padapter->bDriverStopped == _TRUE) ++//#ifdef CONFIG_CONCURRENT_MODE ++// ||(buddy_rm_stop == _TRUE) ++//#endif ++ ) { ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ++ ("%s: bDriverStopped(%d) bSurpriseRemoved(%d)\n", ++ __FUNCTION__, padapter->bDriverStopped, padapter->bSurpriseRemoved)); ++ return _FAIL; ++ } ++ _enter_critical_bh(&pxmitpriv->lock, &irql); ++ ret = rtw_txframes_pending(padapter); ++ _exit_critical_bh(&pxmitpriv->lock, &irql); ++ if (ret == 0) { ++ return _SUCCESS; ++ } ++ // dequeue frame and write to hardware ++ ++ ret = xmit_xmitframes(padapter, pxmitpriv); ++ if (ret == -2) { ++ rtw_msleep_os(1); ++ goto next; ++ } ++ _enter_critical_bh(&pxmitpriv->lock, &irql); ++ ret = rtw_txframes_pending(padapter); ++ _exit_critical_bh(&pxmitpriv->lock, &irql); ++ if (ret == 1) { ++ rtw_msleep_os(1); ++ goto next; ++ } ++ ++ return _SUCCESS; ++} ++ ++thread_return rtl8188es_xmit_thread(thread_context context) ++{ ++ s32 ret; ++ PADAPTER padapter= (PADAPTER)context; ++ struct xmit_priv *pxmitpriv= &padapter->xmitpriv; ++ ++ ret = _SUCCESS; ++ ++ thread_enter("RTWHALXT"); ++ ++ DBG_871X("start %s\n", __FUNCTION__); ++ ++ do { ++ ret = rtl8188es_xmit_handler(padapter); ++ if (signal_pending(current)) { ++ flush_signals(current); ++ } ++ } while (_SUCCESS == ret); ++ ++ _rtw_up_sema(&pxmitpriv->SdioXmitTerminateSema); ++ ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("-%s\n", __FUNCTION__)); ++ DBG_871X("exit %s\n", __FUNCTION__); ++ ++ thread_exit(); ++} ++#endif ++ ++#ifdef CONFIG_IOL_IOREG_CFG_DBG ++#include ++#endif ++s32 rtl8188es_mgnt_xmit(PADAPTER padapter, struct xmit_frame *pmgntframe) ++{ ++ s32 ret = _SUCCESS; ++ struct pkt_attrib *pattrib; ++ struct xmit_buf *pxmitbuf; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ u8 *pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ u8 pattrib_subtype; ++ ++ RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("+%s\n", __FUNCTION__)); ++ ++ pattrib = &pmgntframe->attrib; ++ pxmitbuf = pmgntframe->pxmitbuf; ++ ++ rtl8188es_update_txdesc(pmgntframe, pmgntframe->buf_addr); ++ ++ pxmitbuf->len = TXDESC_SIZE + pattrib->last_txcmdsz; ++ //pmgntframe->pg_num = (pxmitbuf->len + 127)/128; // 128 is tx page size ++ pxmitbuf->pg_num = (pxmitbuf->len + 127)/128; // 128 is tx page size ++ pxmitbuf->ptail = pmgntframe->buf_addr + pxmitbuf->len; ++ pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pmgntframe); ++ ++ rtw_count_tx_stats(padapter, pmgntframe, pattrib->last_txcmdsz); ++ pattrib_subtype = pattrib->subtype; ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ ++ pxmitbuf->priv_data = NULL; ++ ++ if((pattrib_subtype == WIFI_BEACON) || (GetFrameSubType(pframe)==WIFI_BEACON)) //dump beacon directly ++ { ++#ifdef CONFIG_IOL_IOREG_CFG_DBG ++ rtw_IOL_cmd_buf_dump(padapter,pxmitbuf->len,pxmitbuf->pdata); ++#endif ++ ++ rtw_write_port(padapter, ffaddr2deviceId(pdvobjpriv, pxmitbuf->ff_hwaddr), pxmitbuf->len, (u8 *)pxmitbuf); ++ ++ //rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ ++ //pxmitbuf->priv_data = NULL; ++ ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ } ++ else ++ { ++ enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf); ++ } ++ ++ if (ret != _SUCCESS) ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_UNKNOWN); ++ ++ return ret; ++} ++ ++/* ++ * Description: ++ * Handle xmitframe(packet) come from rtw_xmit() ++ * ++ * Return: ++ * _TRUE dump packet directly ok ++ * _FALSE enqueue, temporary can't transmit packets to hardware ++ */ ++s32 rtl8188es_hal_xmit(PADAPTER padapter, struct xmit_frame *pxmitframe) ++{ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ _irqL irql; ++ s32 err; ++ ++ //pxmitframe->attrib.qsel = pxmitframe->attrib.priority; ++ ++#ifdef CONFIG_80211N_HT ++ if ((pxmitframe->frame_tag == DATA_FRAMETAG) && ++ (pxmitframe->attrib.ether_type != 0x0806) && ++ (pxmitframe->attrib.ether_type != 0x888e) && ++ (pxmitframe->attrib.dhcp_pkt != 1)) ++ { ++ if (padapter->mlmepriv.LinkDetectInfo.bBusyTraffic == _TRUE) ++ rtw_issue_addbareq_cmd(padapter, pxmitframe); ++ } ++#endif ++ ++ _enter_critical_bh(&pxmitpriv->lock, &irql); ++ err = rtw_xmitframe_enqueue(padapter, pxmitframe); ++ _exit_critical_bh(&pxmitpriv->lock, &irql); ++ if (err != _SUCCESS) { ++ RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("%s: enqueue xmitframe fail\n",__FUNCTION__)); ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ ++ // Trick, make the statistics correct ++ pxmitpriv->tx_pkts--; ++ pxmitpriv->tx_drop++; ++ return _TRUE; ++ } ++ ++#ifdef CONFIG_SDIO_TX_TASKLET ++ tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); ++#else ++ _rtw_up_sema(&pxmitpriv->SdioXmitSema); ++#endif ++ ++ return _FALSE; ++} ++ ++s32 rtl8188es_hal_xmitframe_enqueue(_adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ s32 err; ++ ++ if ((err=rtw_xmitframe_enqueue(padapter, pxmitframe)) != _SUCCESS) ++ { ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ ++ // Trick, make the statistics correct ++ pxmitpriv->tx_pkts--; ++ pxmitpriv->tx_drop++; ++ } ++ else ++ { ++#ifdef CONFIG_SDIO_TX_TASKLET ++ tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); ++#else ++ _rtw_up_sema(&pxmitpriv->SdioXmitSema); ++#endif ++ } ++ ++ return err; ++ ++} ++ ++ ++/* ++ * Return ++ * _SUCCESS start thread ok ++ * _FAIL start thread fail ++ * ++ */ ++s32 rtl8188es_init_xmit_priv(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++#ifdef CONFIG_SDIO_TX_TASKLET ++#ifdef PLATFORM_LINUX ++ tasklet_init(&pxmitpriv->xmit_tasklet, ++ (void(*)(unsigned long))rtl8188es_xmit_tasklet, ++ (unsigned long)padapter); ++#endif ++#else //CONFIG_SDIO_TX_TASKLET ++ ++ _rtw_init_sema(&pxmitpriv->SdioXmitSema, 0); ++ _rtw_init_sema(&pxmitpriv->SdioXmitTerminateSema, 0); ++#endif //CONFIG_SDIO_TX_TASKLET ++ ++ _rtw_spinlock_init(&pHalData->SdioTxFIFOFreePageLock); ++ ++#ifdef CONFIG_TX_EARLY_MODE ++ pHalData->bEarlyModeEnable = padapter->registrypriv.early_mode; ++#endif ++ ++ return _SUCCESS; ++} ++ ++void rtl8188es_free_xmit_priv(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ _rtw_spinlock_free(&pHalData->SdioTxFIFOFreePageLock); ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/sdio/sdio_halinit.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/sdio/sdio_halinit.c +new file mode 100644 +index 00000000..c3ae471e +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/sdio/sdio_halinit.c +@@ -0,0 +1,4218 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _SDIO_HALINIT_C_ ++ ++#include ++#include ++#include ++ ++#ifndef CONFIG_SDIO_HCI ++#error "CONFIG_SDIO_HCI shall be on!\n" ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_EFUSE_CONFIG_FILE ++#include ++#include ++#endif //CONFIG_EFUSE_CONFIG_FILE ++ ++ ++/* ++ * Description: ++ * Call this function to make sure power on successfully ++ * ++ * Return: ++ * _SUCCESS enable success ++ * _FAIL enable fail ++ */ ++ ++static int PowerOnCheck(PADAPTER padapter) ++{ ++ u32 val_offset0, val_offset1, val_offset2, val_offset3; ++ u32 val_mix = 0; ++ u32 res = 0; ++ u8 ret = _FAIL; ++ int index = 0; ++ ++ val_offset0 = rtw_read8(padapter, REG_CR); ++ val_offset1 = rtw_read8(padapter, REG_CR+1); ++ val_offset2 = rtw_read8(padapter, REG_CR+2); ++ val_offset3 = rtw_read8(padapter, REG_CR+3); ++ ++ if (val_offset0 == 0xEA || val_offset1 == 0xEA || ++ val_offset2 == 0xEA || val_offset3 ==0xEA) { ++ DBG_871X("%s: power on fail, do Power on again\n", __func__); ++ return ret; ++ } ++ ++ val_mix = val_offset3 << 24 | val_mix; ++ val_mix = val_offset2 << 16 | val_mix; ++ val_mix = val_offset1 << 8 | val_mix; ++ val_mix = val_offset0 | val_mix; ++ ++ res = rtw_read32(padapter, REG_CR); ++ ++ DBG_871X("%s: val_mix:0x%08x, res:0x%08x\n", __func__, val_mix, res); ++ ++ while(index < 100) { ++ if (res == val_mix) { ++ DBG_871X("%s: 0x100 the result of cmd52 and cmd53 is the same.\n", __func__); ++ ret = _SUCCESS; ++ break; ++ } else { ++ DBG_871X("%s: 0x100 cmd52 and cmd53 is not the same(index:%d).\n", __func__, index); ++ res = rtw_read32(padapter, REG_CR); ++ index ++; ++ ret = _FAIL; ++ } ++ } ++ ++ if (ret) { ++ index = 0; ++ while(index < 100) { ++ rtw_write32(padapter, 0x1B8, 0x12345678); ++ res = rtw_read32(padapter, 0x1B8); ++ if (res == 0x12345678) { ++ DBG_871X("%s: 0x1B8 test Pass.\n", __func__); ++ ret = _SUCCESS; ++ break; ++ } else { ++ index ++; ++ DBG_871X("%s: 0x1B8 test Fail(index: %d).\n", __func__, index); ++ ret = _FAIL; ++ } ++ } ++ } else { ++ DBG_871X("%s: fail at cmd52, cmd53.\n", __func__); ++ } ++ return ret; ++} ++ ++#ifdef CONFIG_EXT_CLK ++void EnableGpio5ClockReq(PADAPTER Adapter, u8 in_interrupt, u32 Enable) ++{ ++ u32 value32; ++ HAL_DATA_TYPE *pHalData; ++ ++ pHalData = GET_HAL_DATA(Adapter); ++ if(IS_D_CUT(pHalData->VersionID)) ++ return; ++ ++ //dbgdump("%s Enable:%x time:%d", __RTL_FUNC__, Enable, rtw_get_current_time()); ++ ++ if(in_interrupt) ++ value32 = _sdio_read32(Adapter, REG_GPIO_PIN_CTRL); ++ else ++ value32 = rtw_read32(Adapter, REG_GPIO_PIN_CTRL); ++ ++ //open GPIO 5 ++ if (Enable) ++ value32 |= BIT(13);//5+8 ++ else ++ value32 &= ~BIT(13); ++ ++ //GPIO 5 out put ++ value32 |= BIT(21);//5+16 ++ ++ //if (Enable) ++ // rtw_write8(Adapter, REG_GPIO_PIN_CTRL + 1, 0x20); ++ //else ++ // rtw_write8(Adapter, REG_GPIO_PIN_CTRL + 1, 0x00); ++ ++ if(in_interrupt) ++ _sdio_write32(Adapter, REG_GPIO_PIN_CTRL, value32); ++ else ++ rtw_write32(Adapter, REG_GPIO_PIN_CTRL, value32); ++ ++} //end of _rtl8192cs_disable_gpio() ++ ++void _InitClockTo26MHz( ++ IN PADAPTER Adapter ++ ) ++{ ++ u8 u1temp = 0; ++ HAL_DATA_TYPE *pHalData; ++ ++ pHalData = GET_HAL_DATA(Adapter); ++ ++ if(IS_D_CUT(pHalData->VersionID)) { ++ //FW special init ++ u1temp = rtw_read8(Adapter, REG_XCK_OUT_CTRL); ++ u1temp |= 0x18; ++ rtw_write8(Adapter, REG_XCK_OUT_CTRL, u1temp); ++ MSG_8192C("D cut version\n"); ++ } ++ ++ EnableGpio5ClockReq(Adapter, _FALSE, 1); ++ ++ //0x2c[3:0] = 5 will set clock to 26MHz ++ u1temp = rtw_read8(Adapter, REG_APE_PLL_CTRL_EXT); ++ u1temp = (u1temp & 0xF0) | 0x05; ++ rtw_write8(Adapter, REG_APE_PLL_CTRL_EXT, u1temp); ++} ++#endif ++ ++ ++static void rtl8188es_interface_configure(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ BOOLEAN bWiFiConfig = pregistrypriv->wifi_spec; ++ ++ ++ pdvobjpriv->RtOutPipe[0] = WLAN_TX_HIQ_DEVICE_ID; ++ pdvobjpriv->RtOutPipe[1] = WLAN_TX_MIQ_DEVICE_ID; ++ pdvobjpriv->RtOutPipe[2] = WLAN_TX_LOQ_DEVICE_ID; ++ ++ if (bWiFiConfig) ++ pHalData->OutEpNumber = 2; ++ else ++ pHalData->OutEpNumber = SDIO_MAX_TX_QUEUE; ++ ++ switch(pHalData->OutEpNumber){ ++ case 3: ++ pHalData->OutEpQueueSel=TX_SELE_HQ| TX_SELE_LQ|TX_SELE_NQ; ++ break; ++ case 2: ++ pHalData->OutEpQueueSel=TX_SELE_HQ| TX_SELE_NQ; ++ break; ++ case 1: ++ pHalData->OutEpQueueSel=TX_SELE_HQ; ++ break; ++ default: ++ break; ++ } ++ ++ Hal_MappingOutPipe(padapter, pHalData->OutEpNumber); ++} ++ ++/* ++ * Description: ++ * Call power on sequence to enable card ++ * ++ * Return: ++ * _SUCCESS enable success ++ * _FAIL enable fail ++ */ ++static u8 _CardEnable(PADAPTER padapter) ++{ ++ u8 bMacPwrCtrlOn; ++ u8 ret; ++ ++ DBG_871X("=>%s\n", __FUNCTION__); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if (bMacPwrCtrlOn == _FALSE) ++ { ++#ifdef CONFIG_PLATFORM_SPRD ++ u8 val8; ++#endif // CONFIG_PLATFORM_SPRD ++ ++ // RSV_CTRL 0x1C[7:0] = 0x00 ++ // unlock ISO/CLK/Power control register ++ rtw_write8(padapter, REG_RSV_CTRL, 0x0); ++ ++#ifdef CONFIG_PLATFORM_SPRD ++#ifdef CONFIG_EXT_CLK ++ _InitClockTo26MHz(padapter); ++#endif //CONFIG_EXT_CLK ++ ++ val8 = rtw_read8(padapter, 0x4); ++ val8 = val8 & ~BIT(5); ++ rtw_write8(padapter, 0x4, val8); ++#endif // CONFIG_PLATFORM_SPRD ++ ++ ret = HalPwrSeqCmdParsing(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, Rtl8188E_NIC_ENABLE_FLOW); ++ if (ret == _SUCCESS) { ++ u8 bMacPwrCtrlOn = _TRUE; ++ rtw_hal_set_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ } ++ else ++ { ++ DBG_871X(KERN_ERR "%s: run power on flow fail\n", __func__); ++ return _FAIL; ++ } ++ ++ } ++ else ++ { ++ ret = _SUCCESS; ++ } ++ ++ DBG_871X("<=%s\n", __FUNCTION__); ++ ++ return ret; ++ ++} ++ ++static u32 InitPowerOn_rtl8188es(PADAPTER padapter) ++{ ++ u8 value8; ++ u16 value16; ++ u32 value32; ++ u8 ret; ++ ++ DBG_871X("=>%s\n", __FUNCTION__); ++ ++ ret = _CardEnable(padapter); ++ if (ret == _FAIL) { ++ return ret; ++ } ++ ++/* ++ // Radio-Off Pin Trigger ++ value8 = rtw_read8(padapter, REG_GPIO_INTM+1); ++ value8 |= BIT(1); // Enable falling edge triggering interrupt ++ rtw_write8(padapter, REG_GPIO_INTM+1, value8); ++ value8 = rtw_read8(padapter, REG_GPIO_IO_SEL_2+1); ++ value8 |= BIT(1); ++ rtw_write8(padapter, REG_GPIO_IO_SEL_2+1, value8); ++*/ ++ ++ // Enable power down and GPIO interrupt ++ value16 = rtw_read16(padapter, REG_APS_FSMCO); ++ value16 |= EnPDN; // Enable HW power down and RF on ++ rtw_write16(padapter, REG_APS_FSMCO, value16); ++ ++ ++ // Enable MAC DMA/WMAC/SCHEDULE/SEC block ++ value16 = rtw_read16(padapter, REG_CR); ++ value16 |= (HCI_TXDMA_EN | HCI_RXDMA_EN | TXDMA_EN | RXDMA_EN ++ | PROTOCOL_EN | SCHEDULE_EN | ENSEC | CALTMR_EN); ++ // for SDIO - Set CR bit10 to enable 32k calibration. Suggested by SD1 Gimmy. Added by tynli. 2011.08.31. ++ ++ rtw_write16(padapter, REG_CR, value16); ++ ++ ++ ++ // Enable CMD53 R/W Operation ++// bMacPwrCtrlOn = TRUE; ++// rtw_hal_set_hwreg(padapter, HW_VAR_APFM_ON_MAC, (pu8)(&bMacPwrCtrlOn)); ++ ++ DBG_871X("<=%s\n", __FUNCTION__); ++ ++ return _SUCCESS; ++ ++} ++ ++static void _InitQueueReservedPage(PADAPTER padapter) ++{ ++#ifdef RTL8188ES_MAC_LOOPBACK ++ ++//#define MAC_LOOPBACK_PAGE_NUM_PUBQ 0x26 ++//#define MAC_LOOPBACK_PAGE_NUM_HPQ 0x0b ++//#define MAC_LOOPBACK_PAGE_NUM_LPQ 0x0b ++//#define MAC_LOOPBACK_PAGE_NUM_NPQ 0x0b // 71 pages=>9088 bytes, 8.875k ++ ++ rtw_write16(padapter, REG_RQPN_NPQ, 0x0b0b); ++ rtw_write32(padapter, REG_RQPN, 0x80260b0b); ++ ++#else //TX_PAGE_BOUNDARY_LOOPBACK_MODE ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ u32 outEPNum = (u32)pHalData->OutEpNumber; ++ u32 numHQ = 0; ++ u32 numLQ = 0; ++ u32 numNQ = 0; ++ u32 numPubQ; ++ u32 value32; ++ u8 value8; ++ BOOLEAN bWiFiConfig = pregistrypriv->wifi_spec; ++ ++ if(bWiFiConfig) ++ { ++ if (pHalData->OutEpQueueSel & TX_SELE_HQ) ++ { ++ numHQ = 0x29; ++ } ++ ++ if (pHalData->OutEpQueueSel & TX_SELE_LQ) ++ { ++ numLQ = 0x1C; ++ } ++ ++ // NOTE: This step shall be proceed before writting REG_RQPN. ++ if (pHalData->OutEpQueueSel & TX_SELE_NQ) { ++ numNQ = 0x1C; ++ } ++ value8 = (u8)_NPQ(numNQ); ++ rtw_write8(padapter, REG_RQPN_NPQ, value8); ++ ++ numPubQ = 0xA9 - numHQ - numLQ - numNQ; ++ ++ // TX DMA ++ value32 = _HPQ(numHQ) | _LPQ(numLQ) | _PUBQ(numPubQ) | LD_RQPN; ++ rtw_write32(padapter, REG_RQPN, value32); ++ } ++ else ++ { ++ rtw_write16(padapter, REG_RQPN_NPQ, 0x0000); ++ rtw_write32(padapter,REG_RQPN, 0x80a00900); ++ } ++#endif ++ return; ++} ++ ++static void _InitTxBufferBoundary(PADAPTER padapter, u8 txpktbuf_bndy) ++{ ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ //u16 txdmactrl; ++ ++ rtw_write8(padapter, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy); ++ rtw_write8(padapter, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy); ++ rtw_write8(padapter, REG_TXPKTBUF_WMAC_LBK_BF_HD, txpktbuf_bndy); ++ rtw_write8(padapter, REG_TRXFF_BNDY, txpktbuf_bndy); ++ rtw_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy); ++ ++} ++ ++static VOID ++_InitNormalChipRegPriority( ++ IN PADAPTER Adapter, ++ IN u16 beQ, ++ IN u16 bkQ, ++ IN u16 viQ, ++ IN u16 voQ, ++ IN u16 mgtQ, ++ IN u16 hiQ ++ ) ++{ ++ u16 value16 = (rtw_read16(Adapter, REG_TRXDMA_CTRL) & 0x7); ++ ++ value16 |= _TXDMA_BEQ_MAP(beQ) | _TXDMA_BKQ_MAP(bkQ) | ++ _TXDMA_VIQ_MAP(viQ) | _TXDMA_VOQ_MAP(voQ) | ++ _TXDMA_MGQ_MAP(mgtQ)| _TXDMA_HIQ_MAP(hiQ); ++ ++ rtw_write16(Adapter, REG_TRXDMA_CTRL, value16); ++} ++ ++static VOID ++_InitNormalChipOneOutEpPriority( ++ IN PADAPTER Adapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ u16 value = 0; ++ switch(pHalData->OutEpQueueSel) ++ { ++ case TX_SELE_HQ: ++ value = QUEUE_HIGH; ++ break; ++ case TX_SELE_LQ: ++ value = QUEUE_LOW; ++ break; ++ case TX_SELE_NQ: ++ value = QUEUE_NORMAL; ++ break; ++ default: ++ //RT_ASSERT(FALSE,("Shall not reach here!\n")); ++ break; ++ } ++ ++ _InitNormalChipRegPriority(Adapter, ++ value, ++ value, ++ value, ++ value, ++ value, ++ value ++ ); ++ ++} ++ ++static VOID ++_InitNormalChipTwoOutEpPriority( ++ IN PADAPTER Adapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct registry_priv *pregistrypriv = &Adapter->registrypriv; ++ u16 beQ,bkQ,viQ,voQ,mgtQ,hiQ; ++ ++ ++ u16 valueHi = 0; ++ u16 valueLow = 0; ++ ++ switch(pHalData->OutEpQueueSel) ++ { ++ case (TX_SELE_HQ | TX_SELE_LQ): ++ valueHi = QUEUE_HIGH; ++ valueLow = QUEUE_LOW; ++ break; ++ case (TX_SELE_NQ | TX_SELE_LQ): ++ valueHi = QUEUE_NORMAL; ++ valueLow = QUEUE_LOW; ++ break; ++ case (TX_SELE_HQ | TX_SELE_NQ): ++ valueHi = QUEUE_HIGH; ++ valueLow = QUEUE_NORMAL; ++ break; ++ default: ++ //RT_ASSERT(FALSE,("Shall not reach here!\n")); ++ break; ++ } ++ ++ if(!pregistrypriv->wifi_spec ){ ++ beQ = valueLow; ++ bkQ = valueLow; ++ viQ = valueHi; ++ voQ = valueHi; ++ mgtQ = valueHi; ++ hiQ = valueHi; ++ } ++ else{//for WMM ,CONFIG_OUT_EP_WIFI_MODE ++ beQ = valueLow; ++ bkQ = valueHi; ++ viQ = valueHi; ++ voQ = valueLow; ++ mgtQ = valueHi; ++ hiQ = valueHi; ++ } ++ ++ _InitNormalChipRegPriority(Adapter,beQ,bkQ,viQ,voQ,mgtQ,hiQ); ++ ++} ++ ++static VOID ++_InitNormalChipThreeOutEpPriority( ++ IN PADAPTER padapter ++ ) ++{ ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ; ++ ++ if (!pregistrypriv->wifi_spec){// typical setting ++ beQ = QUEUE_LOW; ++ bkQ = QUEUE_LOW; ++ viQ = QUEUE_NORMAL; ++ voQ = QUEUE_HIGH; ++ mgtQ = QUEUE_HIGH; ++ hiQ = QUEUE_HIGH; ++ } ++ else {// for WMM ++ beQ = QUEUE_LOW; ++ bkQ = QUEUE_NORMAL; ++ viQ = QUEUE_NORMAL; ++ voQ = QUEUE_HIGH; ++ mgtQ = QUEUE_HIGH; ++ hiQ = QUEUE_HIGH; ++ } ++ _InitNormalChipRegPriority(padapter,beQ,bkQ,viQ,voQ,mgtQ,hiQ); ++} ++ ++static VOID ++_InitNormalChipQueuePriority( ++ IN PADAPTER Adapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ switch(pHalData->OutEpNumber) ++ { ++ case 1: ++ _InitNormalChipOneOutEpPriority(Adapter); ++ break; ++ case 2: ++ _InitNormalChipTwoOutEpPriority(Adapter); ++ break; ++ case 3: ++ _InitNormalChipThreeOutEpPriority(Adapter); ++ break; ++ default: ++ //RT_ASSERT(FALSE,("Shall not reach here!\n")); ++ break; ++ } ++ ++ ++} ++ ++ ++static void _InitQueuePriority(PADAPTER padapter) ++{ ++ _InitNormalChipQueuePriority(padapter); ++} ++ ++static void _InitPageBoundary(PADAPTER padapter) ++{ ++ // RX Page Boundary ++ u16 rxff_bndy = MAX_RX_DMA_BUFFER_SIZE_88E-1; ++ ++ rtw_write16(padapter, (REG_TRXFF_BNDY + 2), rxff_bndy); ++ ++} ++ ++static void _InitTransferPageSize(PADAPTER padapter) ++{ ++ // Tx page size is always 128. ++ ++ u8 value8; ++ value8 = _PSRX(PBP_128) | _PSTX(PBP_128); ++ rtw_write8(padapter, REG_PBP, value8); ++} ++ ++void _InitDriverInfoSize(PADAPTER padapter, u8 drvInfoSize) ++{ ++ rtw_write8(padapter, REG_RX_DRVINFO_SZ, drvInfoSize); ++} ++ ++void _InitNetworkType(PADAPTER padapter) ++{ ++ u32 value32; ++ ++ value32 = rtw_read32(padapter, REG_CR); ++ ++ // TODO: use the other function to set network type ++// value32 = (value32 & ~MASK_NETTYPE) | _NETTYPE(NT_LINK_AD_HOC); ++ value32 = (value32 & ~MASK_NETTYPE) | _NETTYPE(NT_LINK_AP); ++ ++ rtw_write32(padapter, REG_CR, value32); ++} ++ ++void _InitWMACSetting(PADAPTER padapter) ++{ ++ u16 value16; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ ++ //pHalData->ReceiveConfig = RCR_AAP | RCR_APM | RCR_AM | RCR_AB | RCR_CBSSID_DATA | RCR_CBSSID_BCN | RCR_AMF | RCR_HTC_LOC_CTRL | RCR_APP_PHYSTS | RCR_APP_ICV | RCR_APP_MIC; ++ // don't turn on AAP, it will allow all packets to driver ++ pHalData->ReceiveConfig = RCR_APM | RCR_AM | RCR_AB | RCR_CBSSID_DATA | RCR_CBSSID_BCN | RCR_AMF | RCR_HTC_LOC_CTRL | RCR_APP_PHYST_RXFF | RCR_APP_ICV | RCR_APP_MIC; ++ ++ rtw_write32(padapter, REG_RCR, pHalData->ReceiveConfig); ++ ++ // Accept all data frames ++ value16 = 0xFFFF; ++ rtw_write16(padapter, REG_RXFLTMAP2, value16); ++ ++ // 2010.09.08 hpfan ++ // Since ADF is removed from RCR, ps-poll will not be indicate to driver, ++ // RxFilterMap should mask ps-poll to gurantee AP mode can rx ps-poll. ++ value16 = 0x400; ++ rtw_write16(padapter, REG_RXFLTMAP1, value16); ++ ++ // Accept all management frames ++ value16 = 0xFFFF; ++ rtw_write16(padapter, REG_RXFLTMAP0, value16); ++ ++} ++ ++void _InitAdaptiveCtrl(PADAPTER padapter) ++{ ++ u16 value16; ++ u32 value32; ++ ++ // Response Rate Set ++ value32 = rtw_read32(padapter, REG_RRSR); ++ value32 &= ~RATE_BITMAP_ALL; ++ value32 |= RATE_RRSR_CCK_ONLY_1M; ++ rtw_write32(padapter, REG_RRSR, value32); ++ ++ // CF-END Threshold ++ //m_spIoBase->rtw_write8(REG_CFEND_TH, 0x1); ++ ++ // SIFS (used in NAV) ++ value16 = _SPEC_SIFS_CCK(0x10) | _SPEC_SIFS_OFDM(0x10); ++ rtw_write16(padapter, REG_SPEC_SIFS, value16); ++ ++ // Retry Limit ++ value16 = _LRL(0x30) | _SRL(0x30); ++ rtw_write16(padapter, REG_RL, value16); ++} ++ ++void _InitEDCA(PADAPTER padapter) ++{ ++ // Set Spec SIFS (used in NAV) ++ rtw_write16(padapter, REG_SPEC_SIFS, 0x100a); ++ rtw_write16(padapter, REG_MAC_SPEC_SIFS, 0x100a); ++ ++ // Set SIFS for CCK ++ rtw_write16(padapter, REG_SIFS_CTX, 0x100a); ++ ++ // Set SIFS for OFDM ++ rtw_write16(padapter, REG_SIFS_TRX, 0x100a); ++ ++ // TXOP ++ rtw_write32(padapter, REG_EDCA_BE_PARAM, 0x005EA42B); ++ rtw_write32(padapter, REG_EDCA_BK_PARAM, 0x0000A44F); ++ rtw_write32(padapter, REG_EDCA_VI_PARAM, 0x005EA324); ++ rtw_write32(padapter, REG_EDCA_VO_PARAM, 0x002FA226); ++} ++ ++void _InitRateFallback(PADAPTER padapter) ++{ ++ // Set Data Auto Rate Fallback Retry Count register. ++ rtw_write32(padapter, REG_DARFRC, 0x00000000); ++ rtw_write32(padapter, REG_DARFRC+4, 0x10080404); ++ rtw_write32(padapter, REG_RARFRC, 0x04030201); ++ rtw_write32(padapter, REG_RARFRC+4, 0x08070605); ++ ++} ++ ++void _InitRetryFunction(PADAPTER padapter) ++{ ++ u8 value8; ++ ++ value8 = rtw_read8(padapter, REG_FWHW_TXQ_CTRL); ++ value8 |= EN_AMPDU_RTY_NEW; ++ rtw_write8(padapter, REG_FWHW_TXQ_CTRL, value8); ++ ++ // Set ACK timeout ++ rtw_write8(padapter, REG_ACKTO, 0x40); ++} ++ ++static void HalRxAggr8188ESdio(PADAPTER padapter) ++{ ++#if 1 ++ struct registry_priv *pregistrypriv; ++ u8 valueDMATimeout; ++ u8 valueDMAPageCount; ++ ++ ++ pregistrypriv = &padapter->registrypriv; ++ ++ if (pregistrypriv->wifi_spec) ++ { ++ // 2010.04.27 hpfan ++ // Adjust RxAggrTimeout to close to zero disable RxAggr, suggested by designer ++ // Timeout value is calculated by 34 / (2^n) ++ valueDMATimeout = 0x0f; ++ valueDMAPageCount = 0x01; ++ } ++ else ++ { ++ valueDMATimeout = 0x06; ++ //valueDMAPageCount = 0x0F; ++ //valueDMATimeout = 0x0a; ++ valueDMAPageCount = 0x24; ++ } ++ ++ rtw_write8(padapter, REG_RXDMA_AGG_PG_TH+1, valueDMATimeout); ++ rtw_write8(padapter, REG_RXDMA_AGG_PG_TH, valueDMAPageCount); ++#endif ++} ++ ++void sdio_AggSettingRxUpdate(PADAPTER padapter) ++{ ++#if 1 ++ //HAL_DATA_TYPE *pHalData; ++ u8 valueDMA; ++ ++ ++ //pHalData = GET_HAL_DATA(padapter); ++ ++ valueDMA = rtw_read8(padapter, REG_TRXDMA_CTRL); ++ valueDMA |= RXDMA_AGG_EN; ++ rtw_write8(padapter, REG_TRXDMA_CTRL, valueDMA); ++ ++#if 0 ++ switch (RX_PAGE_SIZE_REG_VALUE) ++ { ++ case PBP_64: ++ pHalData->HwRxPageSize = 64; ++ break; ++ case PBP_128: ++ pHalData->HwRxPageSize = 128; ++ break; ++ case PBP_256: ++ pHalData->HwRxPageSize = 256; ++ break; ++ case PBP_512: ++ pHalData->HwRxPageSize = 512; ++ break; ++ case PBP_1024: ++ pHalData->HwRxPageSize = 1024; ++ break; ++ default: ++ RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ++ ("%s: RX_PAGE_SIZE_REG_VALUE definition is incorrect!\n", __FUNCTION__)); ++ break; ++ } ++#endif ++#endif ++} ++ ++void _initSdioAggregationSetting(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ // Tx aggregation setting ++ //sdio_AggSettingTxUpdate(padapter); ++ ++ // Rx aggregation setting ++ HalRxAggr8188ESdio(padapter); ++ sdio_AggSettingRxUpdate(padapter); ++ ++ // 201/12/10 MH Add for USB agg mode dynamic switch. ++ pHalData->UsbRxHighSpeedMode = _FALSE; ++} ++ ++ ++void _InitOperationMode(PADAPTER padapter) ++{ ++ PHAL_DATA_TYPE pHalData; ++ struct mlme_ext_priv *pmlmeext; ++ u8 regBwOpMode = 0; ++ u32 regRATR = 0, regRRSR = 0; ++ u8 MinSpaceCfg; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pmlmeext = &padapter->mlmeextpriv; ++ ++ //1 This part need to modified according to the rate set we filtered!! ++ // ++ // Set RRSR, RATR, and REG_BWOPMODE registers ++ // ++ switch(pmlmeext->cur_wireless_mode) ++ { ++ case WIRELESS_MODE_B: ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK; ++ regRRSR = RATE_ALL_CCK; ++ break; ++ case WIRELESS_MODE_A: ++// RT_ASSERT(FALSE,("Error wireless a mode\n")); ++#if 0 ++ regBwOpMode = BW_OPMODE_5G |BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_OFDM_AG; ++ regRRSR = RATE_ALL_OFDM_AG; ++#endif ++ break; ++ case WIRELESS_MODE_G: ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ break; ++ case WIRELESS_MODE_AUTO: ++#if 0 ++ if (padapter->bInHctTest) ++ { ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ } ++ else ++#endif ++ { ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; ++ regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ } ++ break; ++ case WIRELESS_MODE_N_24G: ++ // It support CCK rate by default. ++ // CCK rate will be filtered out only when associated AP does not support it. ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; ++ regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ break; ++ case WIRELESS_MODE_N_5G: ++// RT_ASSERT(FALSE,("Error wireless mode")); ++#if 0 ++ regBwOpMode = BW_OPMODE_5G; ++ regRATR = RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; ++ regRRSR = RATE_ALL_OFDM_AG; ++#endif ++ break; ++ ++ default: //for MacOSX compiler warning. ++ break; ++ } ++ ++ rtw_write8(padapter, REG_BWOPMODE, regBwOpMode); ++ ++ // For Min Spacing configuration. ++ switch(pHalData->rf_type) ++ { ++ case RF_1T2R: ++ case RF_1T1R: ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Initializepadapter: RF_Type%s\n", (pHalData->rf_type==RF_1T1R? "(1T1R)":"(1T2R)"))); ++// padapter->MgntInfo.MinSpaceCfg = (MAX_MSS_DENSITY_1T<<3); ++ MinSpaceCfg = (MAX_MSS_DENSITY_1T << 3); ++ break; ++ case RF_2T2R: ++ case RF_2T2R_GREEN: ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Initializepadapter:RF_Type(2T2R)\n")); ++// padapter->MgntInfo.MinSpaceCfg = (MAX_MSS_DENSITY_2T<<3); ++ MinSpaceCfg = (MAX_MSS_DENSITY_2T << 3); ++ break; ++ } ++ ++// rtw_write8(padapter, REG_AMPDU_MIN_SPACE, padapter->MgntInfo.MinSpaceCfg); ++ rtw_write8(padapter, REG_AMPDU_MIN_SPACE, MinSpaceCfg); ++} ++ ++ ++void _InitBeaconParameters(PADAPTER padapter) ++{ ++ PHAL_DATA_TYPE pHalData; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ rtw_write16(padapter, REG_BCN_CTRL, 0x1010); ++ ++ // TODO: Remove these magic number ++ rtw_write16(padapter, REG_TBTT_PROHIBIT, 0x6404);// ms ++ rtw_write8(padapter, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME);//ms ++ rtw_write8(padapter, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME); ++ ++ // Suggested by designer timchen. Change beacon AIFS to the largest number ++ // beacause test chip does not contension before sending beacon. by tynli. 2009.11.03 ++ rtw_write16(padapter, REG_BCNTCFG, 0x660F); ++ ++ ++ pHalData->RegBcnCtrlVal = rtw_read8(padapter, REG_BCN_CTRL); ++ pHalData->RegTxPause = rtw_read8(padapter, REG_TXPAUSE); ++ pHalData->RegFwHwTxQCtrl = rtw_read8(padapter, REG_FWHW_TXQ_CTRL+2); ++ pHalData->RegReg542 = rtw_read8(padapter, REG_TBTT_PROHIBIT+2); ++ pHalData->RegCR_1 = rtw_read8(padapter, REG_CR+1); ++ ++} ++ ++void _InitBeaconMaxError(PADAPTER padapter, BOOLEAN InfraMode) ++{ ++#ifdef RTL8192CU_ADHOC_WORKAROUND_SETTING ++ rtw_write8(padapter, REG_BCN_MAX_ERR, 0xFF); ++#endif ++} ++ ++void _InitInterrupt(PADAPTER padapter) ++{ ++ ++ //HISR write one to clear ++ rtw_write32(padapter, REG_HISR_88E, 0xFFFFFFFF); ++ ++ // HIMR - turn all off ++ rtw_write32(padapter, REG_HIMR_88E, 0); ++ ++ // ++ // Initialize and enable SDIO Host Interrupt. ++ // ++ InitInterrupt8188ESdio(padapter); ++ ++ ++ // ++ // Initialize and enable system Host Interrupt. ++ // ++ //InitSysInterrupt8188ESdio(Adapter);//TODO: ++ ++ // ++ // Enable SDIO Host Interrupt. ++ // ++ //EnableInterrupt8188ESdio(padapter);//Move to sd_intf_start()/stop ++ ++} ++ ++void _InitRDGSetting(PADAPTER padapter) ++{ ++ rtw_write8(padapter, REG_RD_CTRL, 0xFF); ++ rtw_write16(padapter, REG_RD_NAV_NXT, 0x200); ++ rtw_write8(padapter, REG_RD_RESP_PKT_TH, 0x05); ++} ++ ++ ++static void _InitRxSetting(PADAPTER padapter) ++{ ++ rtw_write32(padapter, REG_MACID, 0x87654321); ++ rtw_write32(padapter, 0x0700, 0x87654321); ++} ++ ++ ++static void _InitRFType(PADAPTER padapter) ++{ ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ //BOOLEAN is92CU = IS_92C_SERIAL(pHalData->VersionID); ++ BOOLEAN is2T2R = IS_2T2R(pHalData->VersionID); ++ ++#if DISABLE_BB_RF ++ pHalData->rf_chip = RF_PSEUDO_11N; ++ return; ++#endif ++ ++ pHalData->rf_chip = RF_6052; ++ ++ //if (_FALSE == is92CU) { ++ if(_FALSE == is2T2R){ ++ pHalData->rf_type = RF_1T1R; ++ DBG_8192C("Set RF Chip ID to RF_6052 and RF type to 1T1R.\n"); ++ return; ++ } ++ ++ // TODO: Consider that EEPROM set 92CU to 1T1R later. ++ // Force to overwrite setting according to chip version. Ignore EEPROM setting. ++ //pHalData->RF_Type = is92CU ? RF_2T2R : RF_1T1R; ++ MSG_8192C("Set RF Chip ID to RF_6052 and RF type to %d.\n", pHalData->rf_type); ++} ++ ++// Set CCK and OFDM Block "ON" ++static void _BBTurnOnBlock(PADAPTER padapter) ++{ ++#if (DISABLE_BB_RF) ++ return; ++#endif ++ ++ PHY_SetBBReg(padapter, rFPGA0_RFMOD, bCCKEn, 0x1); ++ PHY_SetBBReg(padapter, rFPGA0_RFMOD, bOFDMEn, 0x1); ++} ++ ++#if 0 ++static void _InitAntenna_Selection(PADAPTER padapter) ++{ ++ rtw_write8(padapter, REG_LEDCFG2, 0x82); ++} ++#endif ++ ++static void _InitPABias(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ u8 pa_setting; ++ BOOLEAN is92C = IS_92C_SERIAL(pHalData->VersionID); ++ ++ //FIXED PA current issue ++ //efuse_one_byte_read(padapter, 0x1FA, &pa_setting); ++ pa_setting = EFUSE_Read1Byte(padapter, 0x1FA); ++ ++ //RT_TRACE(COMP_INIT, DBG_LOUD, ("_InitPABias 0x1FA 0x%x \n",pa_setting)); ++ ++ if(!(pa_setting & BIT0)) ++ { ++ PHY_SetRFReg(padapter, RF_PATH_A, 0x15, 0x0FFFFF, 0x0F406); ++ PHY_SetRFReg(padapter, RF_PATH_A, 0x15, 0x0FFFFF, 0x4F406); ++ PHY_SetRFReg(padapter, RF_PATH_A, 0x15, 0x0FFFFF, 0x8F406); ++ PHY_SetRFReg(padapter, RF_PATH_A, 0x15, 0x0FFFFF, 0xCF406); ++ //RT_TRACE(COMP_INIT, DBG_LOUD, ("PA BIAS path A\n")); ++ } ++ ++ if(!(pa_setting & BIT1) && is92C) ++ { ++ PHY_SetRFReg(padapter,RF_PATH_B, 0x15, 0x0FFFFF, 0x0F406); ++ PHY_SetRFReg(padapter,RF_PATH_B, 0x15, 0x0FFFFF, 0x4F406); ++ PHY_SetRFReg(padapter,RF_PATH_B, 0x15, 0x0FFFFF, 0x8F406); ++ PHY_SetRFReg(padapter,RF_PATH_B, 0x15, 0x0FFFFF, 0xCF406); ++ //RT_TRACE(COMP_INIT, DBG_LOUD, ("PA BIAS path B\n")); ++ } ++ ++ if(!(pa_setting & BIT4)) ++ { ++ pa_setting = rtw_read8(padapter, 0x16); ++ pa_setting &= 0x0F; ++ rtw_write8(padapter, 0x16, pa_setting | 0x80); ++ rtw_write8(padapter, 0x16, pa_setting | 0x90); ++ } ++} ++ ++#if 0 ++VOID ++_InitRDGSetting_8188E( ++ IN PADAPTER Adapter ++ ) ++{ ++ PlatformEFIOWrite1Byte(Adapter,REG_RD_CTRL,0xFF); ++ PlatformEFIOWrite2Byte(Adapter, REG_RD_NAV_NXT, 0x200); ++ PlatformEFIOWrite1Byte(Adapter,REG_RD_RESP_PKT_TH,0x05); ++} ++#endif ++ ++static u32 rtl8188es_hal_init(PADAPTER padapter) ++{ ++ s32 ret; ++ u8 txpktbuf_bndy; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ u8 is92C = IS_92C_SERIAL(pHalData->VersionID); ++ rt_rf_power_state eRfPowerStateToSet; ++ u8 value8; ++ u16 value16; ++ ++ u32 init_start_time = rtw_get_current_time(); ++ ++#ifdef DBG_HAL_INIT_PROFILING ++ enum HAL_INIT_STAGES { ++ HAL_INIT_STAGES_BEGIN = 0, ++ HAL_INIT_STAGES_INIT_PW_ON, ++ HAL_INIT_STAGES_MISC01, ++ HAL_INIT_STAGES_DOWNLOAD_FW, ++ HAL_INIT_STAGES_MAC, ++ HAL_INIT_STAGES_BB, ++ HAL_INIT_STAGES_RF, ++ HAL_INIT_STAGES_EFUSE_PATCH, ++ HAL_INIT_STAGES_INIT_LLTT, ++ ++ HAL_INIT_STAGES_MISC02, ++ HAL_INIT_STAGES_TURN_ON_BLOCK, ++ HAL_INIT_STAGES_INIT_SECURITY, ++ HAL_INIT_STAGES_MISC11, ++ HAL_INIT_STAGES_INIT_HAL_DM, ++ //HAL_INIT_STAGES_RF_PS, ++ HAL_INIT_STAGES_IQK, ++ HAL_INIT_STAGES_PW_TRACK, ++ HAL_INIT_STAGES_LCK, ++ //HAL_INIT_STAGES_MISC21, ++ HAL_INIT_STAGES_INIT_PABIAS, ++ //HAL_INIT_STAGES_ANTENNA_SEL, ++ HAL_INIT_STAGES_MISC31, ++ HAL_INIT_STAGES_END, ++ HAL_INIT_STAGES_NUM ++ }; ++ ++ char * hal_init_stages_str[] = { ++ "HAL_INIT_STAGES_BEGIN", ++ "HAL_INIT_STAGES_INIT_PW_ON", ++ "HAL_INIT_STAGES_MISC01", ++ "HAL_INIT_STAGES_DOWNLOAD_FW", ++ "HAL_INIT_STAGES_MAC", ++ "HAL_INIT_STAGES_BB", ++ "HAL_INIT_STAGES_RF", ++ "HAL_INIT_STAGES_EFUSE_PATCH", ++ "HAL_INIT_STAGES_INIT_LLTT", ++ "HAL_INIT_STAGES_MISC02", ++ "HAL_INIT_STAGES_TURN_ON_BLOCK", ++ "HAL_INIT_STAGES_INIT_SECURITY", ++ "HAL_INIT_STAGES_MISC11", ++ "HAL_INIT_STAGES_INIT_HAL_DM", ++ //"HAL_INIT_STAGES_RF_PS", ++ "HAL_INIT_STAGES_IQK", ++ "HAL_INIT_STAGES_PW_TRACK", ++ "HAL_INIT_STAGES_LCK", ++ //"HAL_INIT_STAGES_MISC21", ++ "HAL_INIT_STAGES_INIT_PABIAS" ++ //"HAL_INIT_STAGES_ANTENNA_SEL", ++ "HAL_INIT_STAGES_MISC31", ++ "HAL_INIT_STAGES_END", ++ }; ++ ++ ++ int hal_init_profiling_i; ++ u32 hal_init_stages_timestamp[HAL_INIT_STAGES_NUM]; //used to record the time of each stage's starting point ++ ++ for(hal_init_profiling_i=0;hal_init_profiling_iwowlan_wake_reason & FWDecisionDisconnect)) { ++ u8 reg_val=0; ++ DBG_8192C("+Reset Entry+\n"); ++ rtw_write8(padapter, REG_MCUFWDL, 0x00); ++ _8051Reset88E(padapter); ++ //reset BB ++ reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN); ++ reg_val &= ~(BIT(0) | BIT(1)); ++ rtw_write8(padapter, REG_SYS_FUNC_EN, reg_val); ++ //reset RF ++ rtw_write8(padapter, REG_RF_CTRL, 0); ++ //reset TRX path ++ rtw_write16(padapter, REG_CR, 0); ++ //reset MAC, Digital Core ++ reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN+1); ++ reg_val &= ~(BIT(4) | BIT(7)); ++ rtw_write8(padapter, REG_SYS_FUNC_EN+1, reg_val); ++ reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN+1); ++ reg_val |= BIT(4) | BIT(7); ++ rtw_write8(padapter, REG_SYS_FUNC_EN+1, reg_val); ++ DBG_8192C("-Reset Entry-\n"); ++ } ++#endif //CONFIG_WOWLAN ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PW_ON); ++ ret = InitPowerOn_rtl8188es(padapter); ++ if (_FAIL == ret) { ++ RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("Failed to init Power On!\n")); ++ goto exit; ++ } ++ ++ ret = PowerOnCheck(padapter); ++ if (_FAIL == ret ) { ++ DBG_871X("Power on Fail! do it again\n"); ++ ret = InitPowerOn_rtl8188es(padapter); ++ if (_FAIL == ret) { ++ DBG_871X("Failed to init Power On!\n"); ++ goto exit; ++ } ++ } ++ DBG_871X("Power on ok!\n"); ++ ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC01); ++ if (!pregistrypriv->wifi_spec) { ++ txpktbuf_bndy = TX_PAGE_BOUNDARY_88E; ++ } else { ++ // for WMM ++ txpktbuf_bndy = WMM_NORMAL_TX_PAGE_BOUNDARY_88E; ++ } ++ _InitQueueReservedPage(padapter); ++ _InitQueuePriority(padapter); ++ _InitPageBoundary(padapter); ++ _InitTransferPageSize(padapter); ++#ifdef CONFIG_IOL_IOREG_CFG ++ _InitTxBufferBoundary(padapter, 0); ++#endif ++ // ++ // Configure SDIO TxRx Control to enable Rx DMA timer masking. ++ // 2010.02.24. ++ // ++ value8 = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_TX_CTRL); ++ SdioLocalCmd52Write1Byte(padapter, SDIO_REG_TX_CTRL, 0x02); ++ ++ rtw_write8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1, 0); ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_DOWNLOAD_FW); ++#if (MP_DRIVER == 1) ++ if (padapter->registrypriv.mp_mode == 1) ++ { ++ _InitRxSetting(padapter); ++ } ++#endif //MP_DRIVER == 1 ++ { ++#if 0 ++ padapter->bFWReady = _FALSE; //because no fw for test chip ++ pHalData->fw_ractrl = _FALSE; ++#else ++#ifdef CONFIG_WOWLAN ++ ret = rtl8188e_FirmwareDownload(padapter, _FALSE); ++#else ++ ret = rtl8188e_FirmwareDownload(padapter); ++#endif //CONFIG_WOWLAN ++ ++ if (ret != _SUCCESS) { ++ DBG_871X("%s: Download Firmware failed!!\n", __FUNCTION__); ++ padapter->bFWReady = _FALSE; ++ pHalData->fw_ractrl = _FALSE; ++ goto exit; ++ } else { ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Initializepadapter8192CSdio(): Download Firmware Success!!\n")); ++ padapter->bFWReady = _TRUE; ++ pHalData->fw_ractrl = _FALSE; ++ } ++#endif ++ } ++ ++ rtl8188e_InitializeFirmwareVars(padapter); ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MAC); ++#if (HAL_MAC_ENABLE == 1) ++ ret = PHY_MACConfig8188E(padapter); ++ if(ret != _SUCCESS){ ++// RT_TRACE(COMP_INIT, DBG_LOUD, ("Initializepadapter8192CSdio(): Fail to configure MAC!!\n")); ++ goto exit; ++ } ++#endif ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BB); ++ // ++ //d. Initialize BB related configurations. ++ // ++#if (HAL_BB_ENABLE == 1) ++ ret = PHY_BBConfig8188E(padapter); ++ if(ret != _SUCCESS){ ++// RT_TRACE(COMP_INIT, DBG_SERIOUS, ("Initializepadapter8192CSdio(): Fail to configure BB!!\n")); ++ goto exit; ++ } ++#endif ++ ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_RF); ++ ++#if (HAL_RF_ENABLE == 1) ++ ret = PHY_RFConfig8188E(padapter); ++ ++ if(ret != _SUCCESS){ ++// RT_TRACE(COMP_INIT, DBG_LOUD, ("Initializepadapter8192CSdio(): Fail to configure RF!!\n")); ++ goto exit; ++ } ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_EFUSE_PATCH); ++#if defined(CONFIG_IOL_EFUSE_PATCH) ++ ret = rtl8188e_iol_efuse_patch(padapter); ++ if(ret != _SUCCESS){ ++ DBG_871X("%s rtl8188e_iol_efuse_patch failed \n",__FUNCTION__); ++ goto exit; ++ } ++#endif ++ _InitTxBufferBoundary(padapter, txpktbuf_bndy); ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_LLTT); ++ ret = InitLLTTable(padapter, txpktbuf_bndy); ++ if (_SUCCESS != ret) { ++ RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("Failed to init LLT Table!\n")); ++ goto exit; ++ } ++ ++#if (RATE_ADAPTIVE_SUPPORT==1) ++ {//Enable TX Report ++ //Enable Tx Report Timer ++ value8 = rtw_read8(padapter, REG_TX_RPT_CTRL); ++ rtw_write8(padapter, REG_TX_RPT_CTRL, (value8|BIT1|BIT0)); ++ //Set MAX RPT MACID ++ rtw_write8(padapter, REG_TX_RPT_CTRL+1, 2);//FOR sta mode ,0: bc/mc ,1:AP ++ //Tx RPT Timer. Unit: 32us ++ rtw_write16(padapter, REG_TX_RPT_TIME, 0xCdf0); ++ } ++#endif ++ ++#if 0 ++ if(pHTInfo->bRDGEnable){ ++ _InitRDGSetting_8188E(Adapter); ++ } ++#endif ++ ++#ifdef CONFIG_TX_EARLY_MODE ++ if( pHalData->bEarlyModeEnable) ++ { ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_,("EarlyMode Enabled!!!\n")); ++ ++ value8 = rtw_read8(padapter, REG_EARLY_MODE_CONTROL); ++#if RTL8188E_EARLY_MODE_PKT_NUM_10 == 1 ++ value8 = value8|0x1f; ++#else ++ value8 = value8|0xf; ++#endif ++ rtw_write8(padapter, REG_EARLY_MODE_CONTROL, value8); ++ ++ rtw_write8(padapter, REG_EARLY_MODE_CONTROL+3, 0x80); ++ ++ value8 = rtw_read8(padapter, REG_TCR+1); ++ value8 = value8|0x40; ++ rtw_write8(padapter,REG_TCR+1, value8); ++ } ++ else ++#endif ++ { ++ rtw_write8(padapter, REG_EARLY_MODE_CONTROL, 0); ++ } ++ ++ ++#if(SIC_ENABLE == 1) ++ SIC_Init(padapter); ++#endif ++ ++ ++ if (pwrctrlpriv->reg_rfoff == _TRUE) { ++ pwrctrlpriv->rf_pwrstate = rf_off; ++ } ++ ++ // 2010/08/09 MH We need to check if we need to turnon or off RF after detecting ++ // HW GPIO pin. Before PHY_RFConfig8192C. ++ HalDetectPwrDownMode88E(padapter); ++ ++ ++ // Set RF type for BB/RF configuration ++ _InitRFType(padapter); ++ ++ // Save target channel ++ // Current Channel will be updated again later. ++ pHalData->CurrentChannel = 1; ++ ++ ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC02); ++ // Get Rx PHY status in order to report RSSI and others. ++ _InitDriverInfoSize(padapter, 4); ++ hal_init_macaddr(padapter); ++ _InitNetworkType(padapter); ++ _InitWMACSetting(padapter); ++ _InitAdaptiveCtrl(padapter); ++ _InitEDCA(padapter); ++ _InitRateFallback(padapter); ++ _InitRetryFunction(padapter); ++ _initSdioAggregationSetting(padapter); ++ _InitOperationMode(padapter); ++ _InitBeaconParameters(padapter); ++ _InitBeaconMaxError(padapter, _TRUE); ++ _InitInterrupt(padapter); ++ ++ // Enable MACTXEN/MACRXEN block ++ value16 = rtw_read16(padapter, REG_CR); ++ value16 |= (MACTXEN | MACRXEN); ++ rtw_write8(padapter, REG_CR, value16); ++ ++ rtw_write32(padapter,REG_MACID_NO_LINK_0,0xFFFFFFFF); ++ rtw_write32(padapter,REG_MACID_NO_LINK_1,0xFFFFFFFF); ++ ++#if defined(CONFIG_CONCURRENT_MODE) || defined(CONFIG_TX_MCAST2UNI) ++ ++#ifdef CONFIG_CHECK_AC_LIFETIME ++ // Enable lifetime check for the four ACs ++ rtw_write8(padapter, REG_LIFETIME_EN, 0x0F); ++#endif // CONFIG_CHECK_AC_LIFETIME ++ ++#ifdef CONFIG_TX_MCAST2UNI ++ rtw_write16(padapter, REG_PKT_VO_VI_LIFE_TIME, 0x0400); // unit: 256us. 256ms ++ rtw_write16(padapter, REG_PKT_BE_BK_LIFE_TIME, 0x0400); // unit: 256us. 256ms ++#else // CONFIG_TX_MCAST2UNI ++ rtw_write16(padapter, REG_PKT_VO_VI_LIFE_TIME, 0x3000); // unit: 256us. 3s ++ rtw_write16(padapter, REG_PKT_BE_BK_LIFE_TIME, 0x3000); // unit: 256us. 3s ++#endif // CONFIG_TX_MCAST2UNI ++#endif // CONFIG_CONCURRENT_MODE || CONFIG_TX_MCAST2UNI ++ ++ ++ ++ ++#endif //HAL_RF_ENABLE == 1 ++ ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_TURN_ON_BLOCK); ++ _BBTurnOnBlock(padapter); ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_SECURITY); ++#if 1 ++ invalidate_cam_all(padapter); ++#else ++ CamResetAllEntry(padapter); ++ padapter->HalFunc.EnableHWSecCfgHandler(padapter); ++#endif ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC11); ++ // 2010/12/17 MH We need to set TX power according to EFUSE content at first. ++ PHY_SetTxPowerLevel8188E(padapter, pHalData->CurrentChannel); ++ // Record original value for template. This is arough data, we can only use the data ++ // for power adjust. The value can not be adjustde according to different power!!! ++// pHalData->OriginalCckTxPwrIdx = pHalData->CurrentCckTxPwrIdx; ++// pHalData->OriginalOfdm24GTxPwrIdx = pHalData->CurrentOfdm24GTxPwrIdx; ++ ++// Move by Neo for USB SS to below setp ++//_RfPowerSave(padapter); ++#if 0 //ANTENNA_SELECTION_STATIC_SETTING ++#if 0 ++ if (!IS_92C_SERIAL( pHalData->VersionID) && (pHalData->AntDivCfg!=0)) ++#else ++ if (IS_1T1R( pHalData->VersionID) && (pHalData->AntDivCfg!=0)) ++#endif ++ { //for 88CU ,1T1R ++ _InitAntenna_Selection(padapter); ++ } ++#endif ++ ++ // ++ // Disable BAR, suggested by Scott ++ // 2010.04.09 add by hpfan ++ // ++ rtw_write32(padapter, REG_BAR_MODE_CTRL, 0x0201ffff); ++ ++ // HW SEQ CTRL ++ // set 0x0 to 0xFF by tynli. Default enable HW SEQ NUM. ++ rtw_write8(padapter, REG_HWSEQ_CTRL, 0xFF); ++ ++ ++#ifdef RTL8188ES_MAC_LOOPBACK ++ value8 = rtw_read8(padapter, REG_SYS_FUNC_EN); ++ value8 &= ~(FEN_BBRSTB|FEN_BB_GLB_RSTn); ++ rtw_write8(padapter, REG_SYS_FUNC_EN, value8);//disable BB, CCK/OFDM ++ ++ rtw_write8(padapter, REG_RD_CTRL, 0x0F); ++ rtw_write8(padapter, REG_RD_CTRL+1, 0xCF); ++ //rtw_write8(padapter, REG_TXPKTBUF_WMAC_LBK_BF_HD, 0x80);//to check _InitPageBoundary() ++ rtw_write32(padapter, REG_CR, 0x0b0202ff);//0x100[28:24]=0x01011, enable mac loopback, no HW Security Eng. ++#endif ++ ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_HAL_DM); ++ // InitHalDm(padapter); ++ rtl8188e_InitHalDm(padapter); ++ ++ ++#if (MP_DRIVER == 1) ++ if (padapter->registrypriv.mp_mode == 1) ++ { ++ padapter->mppriv.channel = pHalData->CurrentChannel; ++ MPT_InitializeAdapter(padapter, padapter->mppriv.channel); ++ } ++ else ++#endif //(MP_DRIVER == 1) ++ { ++ // ++ // 2010/08/11 MH Merge from 8192SE for Minicard init. We need to confirm current radio status ++ // and then decide to enable RF or not.!!!??? For Selective suspend mode. We may not ++ // call init_adapter. May cause some problem?? ++ // ++ // Fix the bug that Hw/Sw radio off before S3/S4, the RF off action will not be executed ++ // in MgntActSet_RF_State() after wake up, because the value of pHalData->eRFPowerState ++ // is the same as eRfOff, we should change it to eRfOn after we config RF parameters. ++ // Added by tynli. 2010.03.30. ++ pwrctrlpriv->rf_pwrstate = rf_on; ++ RT_CLEAR_PS_LEVEL(pwrctrlpriv, RT_RF_OFF_LEVL_HALT_NIC); ++ ++ // 20100326 Joseph: Copy from GPIOChangeRFWorkItemCallBack() function to check HW radio on/off. ++ // 20100329 Joseph: Revise and integrate the HW/SW radio off code in initialization. ++// pHalData->bHwRadioOff = _FALSE; ++ pwrctrlpriv->b_hw_radio_off = _FALSE; ++ eRfPowerStateToSet = rf_on; ++ ++ // 2010/-8/09 MH For power down module, we need to enable register block contrl reg at 0x1c. ++ // Then enable power down control bit of register 0x04 BIT4 and BIT15 as 1. ++ if(pHalData->pwrdown && eRfPowerStateToSet == rf_off) ++ { ++ // Enable register area 0x0-0xc. ++ rtw_write8(padapter, REG_RSV_CTRL, 0x0); ++ ++ // ++ // We should configure HW PDn source for WiFi ONLY, and then ++ // our HW will be set in power-down mode if PDn source from all functions are configured. ++ // 2010.10.06. ++ // ++ if(IS_HARDWARE_TYPE_8723AS(padapter)) ++ { ++ value8 = rtw_read8(padapter, REG_MULTI_FUNC_CTRL); ++ rtw_write8(padapter, REG_MULTI_FUNC_CTRL, (value8|WL_HWPDN_EN)); ++ } ++ else ++ { ++ rtw_write16(padapter, REG_APS_FSMCO, 0x8812); ++ } ++ } ++ //DrvIFIndicateCurrentPhyStatus(padapter); // 2010/08/17 MH Disable to prevent BSOD. ++ ++ // 2010/08/26 MH Merge from 8192CE. ++ if(pwrctrlpriv->rf_pwrstate == rf_on) ++ { ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_IQK); ++ if(pHalData->odmpriv.RFCalibrateInfo.bIQKInitialized){ ++// PHY_IQCalibrate(padapter, _TRUE); ++ PHY_IQCalibrate_8188E(padapter,_TRUE); ++ } ++ else ++ { ++// PHY_IQCalibrate(padapter, _FALSE); ++ PHY_IQCalibrate_8188E(padapter,_FALSE); ++ pHalData->odmpriv.RFCalibrateInfo.bIQKInitialized = _TRUE; ++ } ++ ++// dm_CheckTXPowerTracking(padapter); ++// PHY_LCCalibrate(padapter); ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_PW_TRACK); ++ ODM_TXPowerTrackingCheck(&pHalData->odmpriv ); ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_LCK); ++ PHY_LCCalibrate_8188E(padapter); ++ ++ ++ } ++} ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PABIAS); ++ //if(pHalData->eRFPowerState == eRfOn) ++ { ++ _InitPABias(padapter); ++ } ++ ++ // Init BT hw config. ++// HALBT_InitHwConfig(padapter); ++ ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC31); ++ // 2010/05/20 MH We need to init timer after update setting. Otherwise, we can not get correct inf setting. ++ // 2010/05/18 MH For SE series only now. Init GPIO detect time ++#if 0 ++ if(pDevice->RegUsbSS) ++ { ++ RT_TRACE(COMP_INIT, DBG_LOUD, (" call GpioDetectTimerStart\n")); ++ GpioDetectTimerStart(padapter); // Disable temporarily ++ } ++#endif ++ ++ // 2010/08/23 MH According to Alfred's suggestion, we need to to prevent HW enter ++ // suspend mode automatically. ++ //HwSuspendModeEnable92Cu(padapter, FALSE); ++ ++ // 2010/12/17 MH For TX power level OID modification from UI. ++// padapter->HalFunc.GetTxPowerLevelHandler( padapter, &pHalData->DefaultTxPwrDbm ); ++ //DbgPrint("pHalData->DefaultTxPwrDbm = %d\n", pHalData->DefaultTxPwrDbm); ++ ++// if(pHalData->SwBeaconType < HAL92CSDIO_DEFAULT_BEACON_TYPE) // The lowest Beacon Type that HW can support ++// pHalData->SwBeaconType = HAL92CSDIO_DEFAULT_BEACON_TYPE; ++ ++ // ++ // Update current Tx FIFO page status. ++ // ++ HalQueryTxBufferStatus8189ESdio(padapter); ++ ++ ++ if(pregistrypriv->wifi_spec) ++ rtw_write16(padapter,REG_FAST_EDCA_CTRL ,0); ++ ++ ++ //TODO:Setting HW_VAR_NAV_UPPER !!!!!!!!!!!!!!!!!!!! ++ //rtw_hal_set_hwreg(Adapter, HW_VAR_NAV_UPPER, ((pu1Byte)&NavUpper)); ++ ++ if(IS_HARDWARE_TYPE_8188ES(padapter)) ++ { ++ value8= rtw_read8(padapter, 0x4d3); ++ rtw_write8(padapter, 0x4d3, (value8|0x1)); ++ } ++ ++ //pHalData->PreRpwmVal = PlatformEFSdioLocalCmd52Read1Byte(Adapter, SDIO_REG_HRPWM1)&0x80; ++ ++ ++ // enable Tx report. ++ rtw_write8(padapter, REG_FWHW_TXQ_CTRL+1, 0x0F); ++/* ++ // Suggested by SD1 pisa. Added by tynli. 2011.10.21. ++ PlatformEFIOWrite1Byte(Adapter, REG_EARLY_MODE_CONTROL+3, 0x01); ++ ++*/ //tynli_test_tx_report. ++ rtw_write16(padapter, REG_TX_RPT_TIME, 0x3DF0); ++ //RT_TRACE(COMP_INIT, DBG_TRACE, ("InitializeAdapter8188EUsb() <====\n")); ++ ++ ++ //enable tx DMA to drop the redundate data of packet ++ rtw_write16(padapter,REG_TXDMA_OFFSET_CHK, (rtw_read16(padapter,REG_TXDMA_OFFSET_CHK) | DROP_DATA_EN)); ++ ++//#debug print for checking compile flags ++ //DBG_8192C("RTL8188E_FPGA_TRUE_PHY_VERIFICATION=%d\n", RTL8188E_FPGA_TRUE_PHY_VERIFICATION); ++ DBG_8192C("DISABLE_BB_RF=%d\n", DISABLE_BB_RF); ++ DBG_8192C("IS_HARDWARE_TYPE_8188ES=%d\n", IS_HARDWARE_TYPE_8188ES(padapter)); ++//# ++ ++#ifdef CONFIG_PLATFORM_SPRD ++ // For Power Consumption, set all GPIO pin to ouput mode ++ //0x44~0x47 (GPIO 0~7), Note:GPIO5 is enabled for controlling external 26MHz request ++ rtw_write8(padapter, GPIO_IO_SEL, 0xFF);//Reg0x46, set to o/p mode ++ ++ //0x42~0x43 (GPIO 8~11) ++ value8 = rtw_read8(padapter, REG_GPIO_IO_SEL); ++ rtw_write8(padapter, REG_GPIO_IO_SEL, (value8<<4)|value8); ++ value8 = rtw_read8(padapter, REG_GPIO_IO_SEL+1); ++ rtw_write8(padapter, REG_GPIO_IO_SEL+1, value8|0x0F);//Reg0x43 ++#endif //CONFIG_PLATFORM_SPRD ++ ++ ++#ifdef CONFIG_XMIT_ACK ++ //ack for xmit mgmt frames. ++ rtw_write32(padapter, REG_FWHW_TXQ_CTRL, rtw_read32(padapter, REG_FWHW_TXQ_CTRL)|BIT(12)); ++#endif //CONFIG_XMIT_ACK ++ ++ ++ ++ //RT_TRACE(COMP_INIT, DBG_LOUD, ("<---Initializepadapter8192CSdio()\n")); ++ DBG_8192C("-rtl8188es_hal_init\n"); ++ ++exit: ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_END); ++ ++ DBG_871X("%s in %dms\n", __FUNCTION__, rtw_get_passing_time_ms(init_start_time)); ++ ++ #ifdef DBG_HAL_INIT_PROFILING ++ hal_init_stages_timestamp[HAL_INIT_STAGES_END]=rtw_get_current_time(); ++ ++ for(hal_init_profiling_i=0;hal_init_profiling_i%s\n", __FUNCTION__); ++ ++ ++ //Stop Tx Report Timer. 0x4EC[Bit1]=b'0 ++ u1bTmp = rtw_read8(padapter, REG_TX_RPT_CTRL); ++ rtw_write8(padapter, REG_TX_RPT_CTRL, u1bTmp&(~BIT1)); ++ ++ // stop rx ++ rtw_write8(padapter,REG_CR, 0x0); ++ ++ ++#ifdef CONFIG_EXT_CLK //for sprd For Power Consumption. ++ EnableGpio5ClockReq(padapter, _FALSE, 0); ++#endif //CONFIG_EXT_CLK ++ ++#if 1 ++ // For Power Consumption. ++ u1bTmp = rtw_read8(padapter, GPIO_IN); ++ rtw_write8(padapter, GPIO_OUT, u1bTmp); ++ rtw_write8(padapter, GPIO_IO_SEL, 0xFF);//Reg0x46 ++ ++ u1bTmp = rtw_read8(padapter, REG_GPIO_IO_SEL); ++ rtw_write8(padapter, REG_GPIO_IO_SEL, (u1bTmp<<4)|u1bTmp); ++ u1bTmp = rtw_read8(padapter, REG_GPIO_IO_SEL+1); ++ rtw_write8(padapter, REG_GPIO_IO_SEL+1, u1bTmp|0x0F);//Reg0x43 ++#endif ++ ++ ++ // Run LPS WL RFOFF flow ++ ret = HalPwrSeqCmdParsing(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, Rtl8188E_NIC_LPS_ENTER_FLOW); ++ if (ret == _FALSE) { ++ DBG_871X("%s: run RF OFF flow fail!\n", __func__); ++ } ++ ++ // ==== Reset digital sequence ====== ++ ++ u1bTmp = rtw_read8(padapter, REG_MCUFWDL); ++ if ((u1bTmp & RAM_DL_SEL) && padapter->bFWReady) //8051 RAM code ++ { ++ //rtl8723a_FirmwareSelfReset(padapter); ++ //_8051Reset88E(padapter); ++ ++ // Reset MCU 0x2[10]=0. ++ u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN+1); ++ u1bTmp &= ~BIT(2); // 0x2[10], FEN_CPUEN ++ rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp); ++ } ++ ++ //u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN+1); ++ //u1bTmp &= ~BIT(2); // 0x2[10], FEN_CPUEN ++ //rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp); ++ ++ // MCUFWDL 0x80[1:0]=0 ++ // reset MCU ready status ++ rtw_write8(padapter, REG_MCUFWDL, 0); ++ ++ //==== Reset digital sequence end ====== ++ ++ ++ bMacPwrCtrlOn = _FALSE; // Disable CMD53 R/W ++ rtw_hal_set_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ ++ ++/* ++ if((pMgntInfo->RfOffReason & RF_CHANGE_BY_HW) && pHalData->pwrdown) ++ {// Power Down ++ ++ // Card disable power action flow ++ ret = HalPwrSeqCmdParsing(Adapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, Rtl8188E_NIC_PDN_FLOW); ++ } ++ else ++*/ ++ { // Non-Power Down ++ ++ // Card disable power action flow ++ ret = HalPwrSeqCmdParsing(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, Rtl8188E_NIC_DISABLE_FLOW); ++ ++ ++ if (ret == _FALSE) { ++ DBG_871X("%s: run CARD DISABLE flow fail!\n", __func__); ++ } ++ } ++ ++ ++/* ++ // Reset MCU IO Wrapper, added by Roger, 2011.08.30 ++ u1bTmp = rtw_read8(padapter, REG_RSV_CTRL+1); ++ u1bTmp &= ~BIT(0); ++ rtw_write8(padapter, REG_RSV_CTRL+1, u1bTmp); ++ u1bTmp = rtw_read8(padapter, REG_RSV_CTRL+1); ++ u1bTmp |= BIT(0); ++ rtw_write8(padapter, REG_RSV_CTRL+1, u1bTmp); ++*/ ++ ++ ++ // RSV_CTRL 0x1C[7:0]=0x0E ++ // lock ISO/CLK/Power control register ++ rtw_write8(padapter, REG_RSV_CTRL, 0x0E); ++ ++ padapter->bFWReady = _FALSE; ++ DBG_871X("<=%s\n", __FUNCTION__); ++ ++} ++ ++static u32 rtl8188es_hal_deinit(PADAPTER padapter) ++{ ++ DBG_871X("=>%s\n", __FUNCTION__); ++ ++ if (padapter->hw_init_completed == _TRUE) ++ hal_poweroff_rtl8188es(padapter); ++ ++ DBG_871X("<=%s\n", __FUNCTION__); ++ ++ return _SUCCESS; ++} ++ ++static u32 rtl8188es_inirp_init(PADAPTER padapter) ++{ ++ u32 status; ++ ++_func_enter_; ++ ++ status = _SUCCESS; ++ ++_func_exit_; ++ ++ return status; ++} ++ ++static u32 rtl8188es_inirp_deinit(PADAPTER padapter) ++{ ++ RT_TRACE(_module_hci_hal_init_c_,_drv_info_,("+rtl8188es_inirp_deinit\n")); ++ ++ RT_TRACE(_module_hci_hal_init_c_,_drv_info_,("-rtl8188es_inirp_deinit\n")); ++ ++ return _SUCCESS; ++} ++ ++static void rtl8188es_init_default_value(PADAPTER padapter) ++{ ++ PHAL_DATA_TYPE pHalData; ++ struct pwrctrl_priv *pwrctrlpriv; ++ struct dm_priv *pdmpriv; ++ u8 i; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pwrctrlpriv = adapter_to_pwrctl(padapter); ++ pdmpriv = &pHalData->dmpriv; ++ ++ ++ //init default value ++ pHalData->fw_ractrl = _FALSE; ++ if(!pwrctrlpriv->bkeepfwalive) ++ pHalData->LastHMEBoxNum = 0; ++ ++ //init dm default value ++ pHalData->odmpriv.RFCalibrateInfo.bIQKInitialized = _FALSE; ++ pHalData->odmpriv.RFCalibrateInfo.TM_Trigger = 0;//for IQK ++ //pdmpriv->binitialized = _FALSE; ++// pdmpriv->prv_traffic_idx = 3; ++// pdmpriv->initialize = 0; ++ pHalData->pwrGroupCnt = 0; ++ pHalData->PGMaxGroup= 13; ++ pHalData->odmpriv.RFCalibrateInfo.ThermalValue_HP_index = 0; ++ for(i = 0; i < HP_THERMAL_NUM; i++) ++ pHalData->odmpriv.RFCalibrateInfo.ThermalValue_HP[i] = 0; ++ ++ // interface related variable ++ pHalData->SdioRxFIFOCnt = 0; ++} ++ ++// ++// Description: ++// We should set Efuse cell selection to WiFi cell in default. ++// ++// Assumption: ++// PASSIVE_LEVEL ++// ++// Added by Roger, 2010.11.23. ++// ++static void _EfuseCellSel( ++ IN PADAPTER padapter ++ ) ++{ ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ u32 value32; ++ ++ //if(INCLUDE_MULTI_FUNC_BT(padapter)) ++ { ++ value32 = rtw_read32(padapter, EFUSE_TEST); ++ value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); ++ rtw_write32(padapter, EFUSE_TEST, value32); ++ } ++} ++ ++static VOID ++_ReadRFType( ++ IN PADAPTER Adapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++#if DISABLE_BB_RF ++ pHalData->rf_chip = RF_PSEUDO_11N; ++#else ++ pHalData->rf_chip = RF_6052; ++#endif ++} ++ ++static void ++Hal_EfuseParsePIDVID_8188ES( ++ IN PADAPTER pAdapter, ++ IN u8* hwinfo, ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++// HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ // ++ // The PID/VID info was parsed from CISTPL_MANFID Tuple in CIS area before. ++ // VID is parsed from Manufacture code field and PID is parsed from Manufacture information field. ++ // 2011.04.01. ++ // ++ ++// RT_TRACE(COMP_INIT, DBG_LOUD, ("EEPROM VID = 0x%4x\n", pHalData->EEPROMVID)); ++// RT_TRACE(COMP_INIT, DBG_LOUD, ("EEPROM PID = 0x%4x\n", pHalData->EEPROMPID)); ++} ++ ++static void ++Hal_EfuseParseMACAddr_8188ES( ++ IN PADAPTER padapter, ++ IN u8* hwinfo, ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++ u16 i, usValue; ++ u8 sMacAddr[6] = {0x00, 0xE0, 0x4C, 0x81, 0x88, 0x77}; ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ ++ if (AutoLoadFail) ++ { ++// sMacAddr[5] = (u1Byte)GetRandomNumber(1, 254); ++ for (i=0; i<6; i++) ++ pEEPROM->mac_addr[i] = sMacAddr[i]; ++ } ++ else ++ { ++ //Read Permanent MAC address ++ _rtw_memcpy(pEEPROM->mac_addr, &hwinfo[EEPROM_MAC_ADDR_88ES], ETH_ALEN); ++ ++ } ++// NicIFSetMacAddress(pAdapter, pAdapter->PermanentAddress); ++ ++ DBG_871X("Hal_EfuseParseMACAddr_8188ES: Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n", ++ pEEPROM->mac_addr[0], pEEPROM->mac_addr[1], ++ pEEPROM->mac_addr[2], pEEPROM->mac_addr[3], ++ pEEPROM->mac_addr[4], pEEPROM->mac_addr[5]); ++} ++ ++ ++#ifdef CONFIG_EFUSE_CONFIG_FILE ++static u32 Hal_readPGDataFromConfigFile( ++ PADAPTER padapter) ++{ ++ u32 i; ++ struct file *fp; ++ mm_segment_t fs; ++ u8 temp[3]; ++ loff_t pos = 0; ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ u8 *PROMContent = pEEPROM->efuse_eeprom_data; ++ ++ ++ temp[2] = 0; // add end of string '\0' ++ ++ fp = filp_open("/system/etc/wifi/wifi_efuse.map", O_RDONLY, 0); ++ if (IS_ERR(fp)) { ++ pEEPROM->bloadfile_fail_flag = _TRUE; ++ DBG_871X("Error, Efuse configure file doesn't exist.\n"); ++ return _FAIL; ++ } ++ ++ fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ DBG_871X("Efuse configure file:\n"); ++ for (i=0; ibloadfile_fail_flag = _FALSE; ++ return _SUCCESS; ++} ++ ++static void ++Hal_ReadMACAddrFromFile_8188ES( ++ PADAPTER padapter ++ ) ++{ ++ u32 i; ++ struct file *fp; ++ mm_segment_t fs; ++ u8 source_addr[18]; ++ loff_t pos = 0; ++ u32 curtime = rtw_get_current_time(); ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ u8 *head, *end; ++ ++ u8 null_mac_addr[ETH_ALEN] = {0, 0, 0,0, 0, 0}; ++ u8 multi_mac_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ _rtw_memset(source_addr, 0, 18); ++ _rtw_memset(pEEPROM->mac_addr, 0, ETH_ALEN); ++ ++ fp = filp_open("/data/wifimac.txt", O_RDWR, 0644); ++ if (IS_ERR(fp)) { ++ pEEPROM->bloadmac_fail_flag = _TRUE; ++ DBG_871X("Error, wifi mac address file doesn't exist.\n"); ++ } else { ++ fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ DBG_871X("wifi mac address:\n"); ++ vfs_read(fp, source_addr, 18, &pos); ++ source_addr[17] = ':'; ++ ++ head = end = source_addr; ++ for (i=0; imac_addr[i] = simple_strtoul(head, NULL, 16 ); ++ ++ if (end) { ++ end++; ++ head = end; ++ } ++ DBG_871X("%02x \n", pEEPROM->mac_addr[i]); ++ } ++ DBG_871X("\n"); ++ set_fs(fs); ++ pEEPROM->bloadmac_fail_flag = _FALSE; ++ filp_close(fp, NULL); ++ } ++ ++ if ( (_rtw_memcmp(pEEPROM->mac_addr, null_mac_addr, ETH_ALEN)) || ++ (_rtw_memcmp(pEEPROM->mac_addr, multi_mac_addr, ETH_ALEN)) ) { ++ pEEPROM->mac_addr[0] = 0x00; ++ pEEPROM->mac_addr[1] = 0xe0; ++ pEEPROM->mac_addr[2] = 0x4c; ++ pEEPROM->mac_addr[3] = (u8)(curtime & 0xff) ; ++ pEEPROM->mac_addr[4] = (u8)((curtime>>8) & 0xff) ; ++ pEEPROM->mac_addr[5] = (u8)((curtime>>16) & 0xff) ; ++ } ++ ++ DBG_871X("Hal_ReadMACAddrFromFile_8188ES: Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n", ++ pEEPROM->mac_addr[0], pEEPROM->mac_addr[1], ++ pEEPROM->mac_addr[2], pEEPROM->mac_addr[3], ++ pEEPROM->mac_addr[4], pEEPROM->mac_addr[5]); ++} ++#endif //CONFIG_EFUSE_CONFIG_FILE ++ ++static VOID ++readAdapterInfo_8188ES( ++ IN PADAPTER padapter ++ ) ++{ ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ ++ /* parse the eeprom/efuse content */ ++ Hal_EfuseParseIDCode88E(padapter, pEEPROM->efuse_eeprom_data); ++ Hal_EfuseParsePIDVID_8188ES(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ ++#ifdef CONFIG_EFUSE_CONFIG_FILE ++ Hal_ReadMACAddrFromFile_8188ES(padapter); ++#else //CONFIG_EFUSE_CONFIG_FILE ++ Hal_EfuseParseMACAddr_8188ES(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++#endif //CONFIG_EFUSE_CONFIG_FILE ++ ++ Hal_ReadPowerSavingMode88E(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ Hal_ReadTxPowerInfo88E(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ Hal_EfuseParseEEPROMVer88E(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ rtl8188e_EfuseParseChnlPlan(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ Hal_EfuseParseXtal_8188E(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ Hal_EfuseParseCustomerID88E(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ //Hal_ReadAntennaDiversity88E(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ Hal_EfuseParseBoardType88E(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ Hal_ReadThermalMeter_88E(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ // ++ // The following part initialize some vars by PG info. ++ // ++ Hal_InitChannelPlan(padapter); ++#ifdef CONFIG_WOWLAN ++ Hal_DetectWoWMode(padapter); ++#endif //CONFIG_WOWLAN ++#ifdef CONFIG_RF_GAIN_OFFSET ++ Hal_ReadRFGainOffset(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++#endif //CONFIG_RF_GAIN_OFFSET ++} ++ ++static void _ReadPROMContent( ++ IN PADAPTER padapter ++ ) ++{ ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ u8 eeValue; ++ ++ /* check system boot selection */ ++ eeValue = rtw_read8(padapter, REG_9346CR); ++ pEEPROM->EepromOrEfuse = (eeValue & BOOT_FROM_EEPROM) ? _TRUE : _FALSE; ++ pEEPROM->bautoload_fail_flag = (eeValue & EEPROM_EN) ? _FALSE : _TRUE; ++ ++ DBG_871X("%s: 9346CR=0x%02X, Boot from %s, Autoload %s\n", ++ __FUNCTION__, eeValue, ++ (pEEPROM->EepromOrEfuse ? "EEPROM" : "EFUSE"), ++ (pEEPROM->bautoload_fail_flag ? "Fail" : "OK")); ++ ++// pHalData->EEType = IS_BOOT_FROM_EEPROM(Adapter) ? EEPROM_93C46 : EEPROM_BOOT_EFUSE; ++ ++#ifdef CONFIG_EFUSE_CONFIG_FILE ++ Hal_readPGDataFromConfigFile(padapter); ++#else //CONFIG_EFUSE_CONFIG_FILE ++ Hal_InitPGData88E(padapter); ++#endif //CONFIG_EFUSE_CONFIG_FILE ++ readAdapterInfo_8188ES(padapter); ++} ++ ++static VOID ++_InitOtherVariable( ++ IN PADAPTER Adapter ++ ) ++{ ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ ++ //if(Adapter->bInHctTest){ ++ // pMgntInfo->PowerSaveControl.bInactivePs = FALSE; ++ // pMgntInfo->PowerSaveControl.bIPSModeBackup = FALSE; ++ // pMgntInfo->PowerSaveControl.bLeisurePs = FALSE; ++ // pMgntInfo->keepAliveLevel = 0; ++ //} ++ ++ ++} ++ ++// ++// Description: ++// Read HW adapter information by E-Fuse or EEPROM according CR9346 reported. ++// ++// Assumption: ++// PASSIVE_LEVEL (SDIO interface) ++// ++// ++static s32 _ReadAdapterInfo8188ES(PADAPTER padapter) ++{ ++ u32 start; ++ ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+_ReadAdapterInfo8188ES\n")); ++ ++ // before access eFuse, make sure card enable has been called ++ if(_CardEnable(padapter) == _FAIL) ++ { ++ DBG_871X(KERN_ERR "%s: run power on flow fail\n", __func__); ++ return _FAIL; ++ } ++ ++ start = rtw_get_current_time(); ++ ++// Efuse_InitSomeVar(Adapter); ++// pHalData->VersionID = ReadChipVersion(Adapter); ++// _EfuseCellSel(padapter); ++ ++ _ReadRFType(padapter);//rf_chip -> _InitRFType() ++ _ReadPROMContent(padapter); ++ ++ // 2010/10/25 MH THe function must be called after borad_type & IC-Version recognize. ++ //ReadSilmComboMode(Adapter); ++ _InitOtherVariable(padapter); ++ ++ ++ //MSG_8192C("%s()(done), rf_chip=0x%x, rf_type=0x%x\n", __FUNCTION__, pHalData->rf_chip, pHalData->rf_type); ++ MSG_8192C("<==== ReadAdapterInfo8188ES in %d ms\n", rtw_get_passing_time_ms(start)); ++ ++ return _SUCCESS; ++} ++ ++static void ReadAdapterInfo8188ES(PADAPTER padapter) ++{ ++ // Read EEPROM size before call any EEPROM function ++ padapter->EepromAddressSize = GetEEPROMSize8188E(padapter); ++ ++ _ReadAdapterInfo8188ES(padapter); ++} ++ ++static void ResumeTxBeacon(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE* pHalData = GET_HAL_DATA(padapter); ++ ++ // 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value ++ // which should be read from register to a global variable. ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+ResumeTxBeacon\n")); ++ ++ rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, (pHalData->RegFwHwTxQCtrl) | BIT6); ++ pHalData->RegFwHwTxQCtrl |= BIT6; ++ rtw_write8(padapter, REG_TBTT_PROHIBIT+1, 0xff); ++ pHalData->RegReg542 |= BIT0; ++ rtw_write8(padapter, REG_TBTT_PROHIBIT+2, pHalData->RegReg542); ++} ++ ++static void StopTxBeacon(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE* pHalData = GET_HAL_DATA(padapter); ++ ++ // 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value ++ // which should be read from register to a global variable. ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+StopTxBeacon\n")); ++ ++ rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, (pHalData->RegFwHwTxQCtrl) & (~BIT6)); ++ pHalData->RegFwHwTxQCtrl &= (~BIT6); ++ rtw_write8(padapter, REG_TBTT_PROHIBIT+1, 0x64); ++ pHalData->RegReg542 &= ~(BIT0); ++ rtw_write8(padapter, REG_TBTT_PROHIBIT+2, pHalData->RegReg542); ++ ++ CheckFwRsvdPageContent(padapter); // 2010.06.23. Added by tynli. ++} ++ ++// todo static ++void hw_var_set_opmode(PADAPTER Adapter, u8 variable, u8* val) ++{ ++ u8 val8; ++ u8 mode = *((u8 *)val); ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(Adapter->iface_type == IFACE_PORT1) ++ { ++ // disable Port1 TSF update ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)|BIT(4)); ++ ++ // set net_type ++ val8 = rtw_read8(Adapter, MSR)&0x03; ++ val8 |= (mode<<2); ++ rtw_write8(Adapter, MSR, val8); ++ ++ DBG_871X("%s()-%d mode = %d\n", __FUNCTION__, __LINE__, mode); ++ ++ if((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) ++ { ++ if(!check_buddy_mlmeinfo_state(Adapter, WIFI_FW_AP_STATE)) ++ { ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN ++ ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ rtw_write8(Adapter, REG_DRVERLYINT, 0x05);//restore early int time to 5ms ++ UpdateInterruptMask8188ESdio(Adapter, 0, SDIO_HIMR_BCNERLY_INT_MSK); ++ #endif // CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ UpdateInterruptMask8188ESdio(Adapter, 0, (SDIO_HIMR_TXBCNOK_MSK|SDIO_HIMR_TXBCNERR_MSK)); ++ #endif// CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ ++ #endif //CONFIG_INTERRUPT_BASED_TXBCN ++ ++ ++ StopTxBeacon(Adapter); ++ } ++ ++ rtw_write8(Adapter,REG_BCN_CTRL_1, 0x11);//disable atim wnd and disable beacon function ++ //rtw_write8(Adapter,REG_BCN_CTRL_1, 0x18); ++ } ++ else if((mode == _HW_STATE_ADHOC_) /*|| (mode == _HW_STATE_AP_)*/) ++ { ++ ResumeTxBeacon(Adapter); ++ rtw_write8(Adapter,REG_BCN_CTRL_1, 0x1a); ++ //BIT4 - If set 0, hw will clr bcnq when tx becon ok/fail or port 1 ++ rtw_write8(Adapter, REG_MBID_NUM, rtw_read8(Adapter, REG_MBID_NUM)|BIT(3)|BIT(4)); ++ } ++ else if(mode == _HW_STATE_AP_) ++ { ++#ifdef CONFIG_INTERRUPT_BASED_TXBCN ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ UpdateInterruptMask8188ESdio(Adapter, SDIO_HIMR_BCNERLY_INT_MSK, 0); ++ #endif//CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ UpdateInterruptMask8188ESdio(Adapter, (SDIO_HIMR_TXBCNOK_MSK|SDIO_HIMR_TXBCNERR_MSK), 0); ++ #endif//CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ ++#endif //CONFIG_INTERRUPT_BASED_TXBCN ++ ++ ResumeTxBeacon(Adapter); ++ ++ rtw_write8(Adapter, REG_BCN_CTRL_1, 0x12); ++ ++ //enable SW Beacon ++ rtw_write32(Adapter, REG_CR, rtw_read32(Adapter, REG_CR)|BIT(8)); ++ ++ //Set RCR ++ //rtw_write32(padapter, REG_RCR, 0x70002a8e);//CBSSID_DATA must set to 0 ++ rtw_write32(Adapter, REG_RCR, 0x7000208e);//CBSSID_DATA must set to 0,Reject ICV_ERROR packets ++ ++ //enable to rx data frame ++ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); ++ //enable to rx ps-poll ++ rtw_write16(Adapter, REG_RXFLTMAP1, 0x0400); ++ ++ //Beacon Control related register for first time ++ rtw_write8(Adapter, REG_BCNDMATIM, 0x02); // 2ms ++ ++ //rtw_write8(Adapter, REG_BCN_MAX_ERR, 0xFF); ++ rtw_write8(Adapter, REG_ATIMWND_1, 0x0a); // 10ms for port1 ++ rtw_write16(Adapter, REG_BCNTCFG, 0x00); ++ rtw_write16(Adapter, REG_TBTT_PROHIBIT, 0xff04); ++ rtw_write16(Adapter, REG_TSFTR_SYN_OFFSET, 0x7fff);// +32767 (~32ms) ++ ++ //reset TSF2 ++ rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(1)); ++ ++ ++ //BIT4 - If set 0, hw will clr bcnq when tx becon ok/fail or port 1 ++ rtw_write8(Adapter, REG_MBID_NUM, rtw_read8(Adapter, REG_MBID_NUM)|BIT(3)|BIT(4)); ++ //enable BCN1 Function for if2 ++ //don't enable update TSF1 for if2 (due to TSF update when beacon/probe rsp are received) ++ rtw_write8(Adapter, REG_BCN_CTRL_1, (DIS_TSF_UDT0_NORMAL_CHIP|EN_BCN_FUNCTION | EN_TXBCN_RPT|BIT(1))); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(check_buddy_fwstate(Adapter, WIFI_FW_NULL_STATE)) ++ rtw_write8(Adapter, REG_BCN_CTRL, ++ rtw_read8(Adapter, REG_BCN_CTRL) & ~EN_BCN_FUNCTION); ++#endif ++ //BCN1 TSF will sync to BCN0 TSF with offset(0x518) if if1_sta linked ++ //rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)|BIT(5)); ++ //rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(3)); ++ ++ //dis BCN0 ATIM WND if if1 is station ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(0)); ++ ++#ifdef CONFIG_TSF_RESET_OFFLOAD ++ // Reset TSF for STA+AP concurrent mode ++ if ( check_buddy_fwstate(Adapter, (WIFI_STATION_STATE|WIFI_ASOC_STATE)) ) { ++ if (reset_tsf(Adapter, IFACE_PORT1) == _FALSE) ++ DBG_871X("ERROR! %s()-%d: Reset port1 TSF fail\n", ++ __FUNCTION__, __LINE__); ++ } ++#endif // CONFIG_TSF_RESET_OFFLOAD ++ } ++ } ++ else ++#endif //CONFIG_CONCURRENT_MODE ++ { ++ // disable Port0 TSF update ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4)); ++ ++ // set net_type ++ val8 = rtw_read8(Adapter, MSR)&0x0c; ++ val8 |= mode; ++ rtw_write8(Adapter, MSR, val8); ++ ++ DBG_871X("%s()-%d mode = %d\n", __FUNCTION__, __LINE__, mode); ++ ++ if((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) ++ { ++#ifdef CONFIG_CONCURRENT_MODE ++ if(!check_buddy_mlmeinfo_state(Adapter, WIFI_FW_AP_STATE)) ++#endif //CONFIG_CONCURRENT_MODE ++ { ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ rtw_write8(Adapter, REG_DRVERLYINT, 0x05);//restore early int time to 5ms ++ UpdateInterruptMask8188ESdio(Adapter, 0, SDIO_HIMR_BCNERLY_INT_MSK); ++ #endif//CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ UpdateInterruptMask8188ESdio(Adapter, 0, (SDIO_HIMR_TXBCNOK_MSK|SDIO_HIMR_TXBCNERR_MSK)); ++ #endif //CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ #endif //CONFIG_INTERRUPT_BASED_TXBCN ++ StopTxBeacon(Adapter); ++ } ++ ++ rtw_write8(Adapter,REG_BCN_CTRL, 0x19);//disable atim wnd ++ //rtw_write8(Adapter,REG_BCN_CTRL, 0x18); ++ } ++ else if((mode == _HW_STATE_ADHOC_) /*|| (mode == _HW_STATE_AP_)*/) ++ { ++ ResumeTxBeacon(Adapter); ++ rtw_write8(Adapter,REG_BCN_CTRL, 0x1a); ++ //BIT3 - If set 0, hw will clr bcnq when tx becon ok/fail or port 0 ++ rtw_write8(Adapter, REG_MBID_NUM, rtw_read8(Adapter, REG_MBID_NUM)|BIT(3)|BIT(4)); ++ } ++ else if(mode == _HW_STATE_AP_) ++ { ++ ++#ifdef CONFIG_INTERRUPT_BASED_TXBCN ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ UpdateInterruptMask8188ESdio(Adapter, SDIO_HIMR_BCNERLY_INT_MSK, 0); ++ #endif//CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ UpdateInterruptMask8188ESdio(Adapter, (SDIO_HIMR_TXBCNOK_MSK|SDIO_HIMR_TXBCNERR_MSK), 0); ++ #endif//CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++#endif //CONFIG_INTERRUPT_BASED_TXBCN ++ ++ ++ ResumeTxBeacon(Adapter); ++ ++ rtw_write8(Adapter, REG_BCN_CTRL, 0x12); ++ ++ //enable SW Beacon ++ rtw_write32(Adapter, REG_CR, rtw_read32(Adapter, REG_CR)|BIT(8)); ++ ++ //Set RCR ++ //rtw_write32(padapter, REG_RCR, 0x70002a8e);//CBSSID_DATA must set to 0 ++ rtw_write32(Adapter, REG_RCR, 0x7000208e);//CBSSID_DATA must set to 0,reject ICV_ERR packet ++ //enable to rx data frame ++ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); ++ //enable to rx ps-poll ++ rtw_write16(Adapter, REG_RXFLTMAP1, 0x0400); ++ ++ //Beacon Control related register for first time ++ rtw_write8(Adapter, REG_BCNDMATIM, 0x02); // 2ms ++ ++ //rtw_write8(Adapter, REG_BCN_MAX_ERR, 0xFF); ++ rtw_write8(Adapter, REG_ATIMWND, 0x0a); // 10ms ++ rtw_write16(Adapter, REG_BCNTCFG, 0x00); ++ rtw_write16(Adapter, REG_TBTT_PROHIBIT, 0xff04); ++ rtw_write16(Adapter, REG_TSFTR_SYN_OFFSET, 0x7fff);// +32767 (~32ms) ++ ++ //reset TSF ++ rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(0)); ++ ++ //BIT3 - If set 0, hw will clr bcnq when tx becon ok/fail or port 0 ++ rtw_write8(Adapter, REG_MBID_NUM, rtw_read8(Adapter, REG_MBID_NUM)|BIT(3)|BIT(4)); ++ ++ //enable BCN0 Function for if1 ++ //don't enable update TSF0 for if1 (due to TSF update when beacon/probe rsp are received) ++ rtw_write8(Adapter, REG_BCN_CTRL, (DIS_TSF_UDT0_NORMAL_CHIP|EN_BCN_FUNCTION | EN_TXBCN_RPT|BIT(1))); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(check_buddy_fwstate(Adapter, WIFI_FW_NULL_STATE)) ++ rtw_write8(Adapter, REG_BCN_CTRL_1, ++ rtw_read8(Adapter, REG_BCN_CTRL_1) & ~EN_BCN_FUNCTION); ++#endif ++ ++ //dis BCN1 ATIM WND if if2 is station ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)|BIT(0)); ++#ifdef CONFIG_TSF_RESET_OFFLOAD ++ // Reset TSF for STA+AP concurrent mode ++ if ( check_buddy_fwstate(Adapter, (WIFI_STATION_STATE|WIFI_ASOC_STATE)) ) { ++ if (reset_tsf(Adapter, IFACE_PORT0) == _FALSE) ++ DBG_871X("ERROR! %s()-%d: Reset port0 TSF fail\n", ++ __FUNCTION__, __LINE__); ++ } ++#endif // CONFIG_TSF_RESET_OFFLOAD ++ } ++ } ++ ++} ++ ++static void hw_var_set_macaddr(PADAPTER Adapter, u8 variable, u8* val) ++{ ++ u8 idx = 0; ++ u32 reg_macid; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(Adapter->iface_type == IFACE_PORT1) ++ { ++ reg_macid = REG_MACID1; ++ } ++ else ++#endif ++ { ++ reg_macid = REG_MACID; ++ } ++ ++ for(idx = 0 ; idx < 6; idx++) ++ { ++ rtw_write8(Adapter, (reg_macid+idx), val[idx]); ++ } ++ ++} ++ ++static void hw_var_set_bssid(PADAPTER Adapter, u8 variable, u8* val) ++{ ++ u8 idx = 0; ++ u32 reg_bssid; ++ ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(Adapter->iface_type == IFACE_PORT1) ++ { ++ reg_bssid = REG_BSSID1; ++ } ++ else ++#endif ++ { ++ reg_bssid = REG_BSSID; ++ } ++ ++printk("hw_var_set_bssid reg=%x \n", reg_bssid); ++ ++ for(idx = 0 ; idx < 6; idx++) ++ { ++ rtw_write8(Adapter, (reg_bssid+idx), val[idx]); ++ } ++ ++} ++ ++static void hw_var_set_bcn_func(PADAPTER Adapter, u8 variable, u8* val) ++{ ++ u32 bcn_ctrl_reg; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(Adapter->iface_type == IFACE_PORT1) ++ { ++ bcn_ctrl_reg = REG_BCN_CTRL_1; ++ } ++ else ++#endif ++ { ++ bcn_ctrl_reg = REG_BCN_CTRL; ++ } ++ ++ if(*((u8 *)val)) ++ { ++ rtw_write8(Adapter, bcn_ctrl_reg, (EN_BCN_FUNCTION | EN_TXBCN_RPT)); ++ } ++ else ++ { ++ rtw_write8(Adapter, bcn_ctrl_reg, rtw_read8(Adapter, bcn_ctrl_reg)&(~(EN_BCN_FUNCTION | EN_TXBCN_RPT))); ++ } ++ ++ ++} ++ ++static void hw_var_set_correct_tsf(PADAPTER Adapter, u8 variable, u8* val) ++{ ++#ifdef CONFIG_CONCURRENT_MODE ++ u64 tsf; ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ PADAPTER pbuddy_adapter = Adapter->pbuddy_adapter; ++ ++ //tsf = pmlmeext->TSFValue - ((u32)pmlmeext->TSFValue % (pmlmeinfo->bcn_interval*1024)) -1024; //us ++ tsf = pmlmeext->TSFValue - rtw_modular64(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval*1024)) -1024; //us ++ ++ if(((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) ++ { ++ //pHalData->RegTxPause |= STOP_BCNQ;BIT(6) ++ //rtw_write8(Adapter, REG_TXPAUSE, (rtw_read8(Adapter, REG_TXPAUSE)|BIT(6))); ++ StopTxBeacon(Adapter); ++ } ++ ++ if(Adapter->iface_type == IFACE_PORT1) ++ { ++ //disable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)&(~BIT(3))); ++ ++ rtw_write32(Adapter, REG_TSFTR1, tsf); ++ rtw_write32(Adapter, REG_TSFTR1+4, tsf>>32); ++ //enable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)|BIT(3)); ++ // Update buddy port's TSF if it is SoftAP for beacon TX issue! ++ if ( (pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE ++ && check_buddy_fwstate(Adapter, WIFI_AP_STATE) ++ ) { ++ //disable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(3))); ++ ++ rtw_write32(Adapter, REG_TSFTR, tsf); ++ rtw_write32(Adapter, REG_TSFTR+4, tsf>>32); ++ ++ //enable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(3)); ++#ifdef CONFIG_TSF_RESET_OFFLOAD ++ // Update buddy port's TSF(TBTT) if it is SoftAP for beacon TX issue! ++ if (reset_tsf(Adapter, IFACE_PORT0) == _FALSE) ++ DBG_871X("ERROR! %s()-%d: Reset port0 TSF fail\n", ++ __FUNCTION__, __LINE__); ++ ++#endif // CONFIG_TSF_RESET_OFFLOAD ++ } ++ ++ } ++ else ++ { ++ //disable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(3))); ++ ++ rtw_write32(Adapter, REG_TSFTR, tsf); ++ rtw_write32(Adapter, REG_TSFTR+4, tsf>>32); ++ ++ //enable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(3)); ++ // Update buddy port's TSF if it is SoftAP for beacon TX issue! ++ if ( (pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE ++ && check_buddy_fwstate(Adapter, WIFI_AP_STATE) ++ ) { ++ //disable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)&(~BIT(3))); ++ ++ rtw_write32(Adapter, REG_TSFTR1, tsf); ++ rtw_write32(Adapter, REG_TSFTR1+4, tsf>>32); ++ ++ //enable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)|BIT(3)); ++#ifdef CONFIG_TSF_RESET_OFFLOAD ++ // Update buddy port's TSF if it is SoftAP for beacon TX issue! ++ if (reset_tsf(Adapter, IFACE_PORT1) == _FALSE) ++ DBG_871X("ERROR! %s()-%d: Reset port1 TSF fail\n", ++ __FUNCTION__, __LINE__); ++#endif // CONFIG_TSF_RESET_OFFLOAD ++ } ++ } ++ ++ ++ if(((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) ++ { ++ //pHalData->RegTxPause &= (~STOP_BCNQ); ++ //rtw_write8(Adapter, REG_TXPAUSE, (rtw_read8(Adapter, REG_TXPAUSE)&(~BIT(6)))); ++ ResumeTxBeacon(Adapter); ++ } ++#endif ++} ++ ++static void hw_var_set_mlme_disconnect(PADAPTER Adapter, u8 variable, u8* val) ++{ ++#ifdef CONFIG_CONCURRENT_MODE ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PADAPTER pbuddy_adapter = Adapter->pbuddy_adapter; ++ ++ ++ if(check_buddy_mlmeinfo_state(Adapter, _HW_STATE_NOLINK_)) ++ rtw_write16(Adapter, REG_RXFLTMAP2, 0x00); ++ ++ ++ if(Adapter->iface_type == IFACE_PORT1) ++ { ++ //reset TSF1 ++ rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(1)); ++ ++ //disable update TSF1 ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)|BIT(4)); ++ ++ // disable Port1's beacon function ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)&(~BIT(3))); ++ } ++ else ++ { ++ //reset TSF ++ rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(0)); ++ ++ //disable update TSF ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4)); ++ } ++#endif ++} ++ ++static void hw_var_set_mlme_sitesurvey(PADAPTER Adapter, u8 variable, u8* val) ++{ ++#ifdef CONFIG_CONCURRENT_MODE ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if(*((u8 *)val))//under sitesurvey ++ { ++ //config RCR to receive different BSSID & not to receive data frame ++ u32 v = rtw_read32(Adapter, REG_RCR); ++ v &= ~(RCR_CBSSID_BCN); ++ rtw_write32(Adapter, REG_RCR, v); ++ ++ //disable update TSF ++ if((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) ++ { ++ if(Adapter->iface_type == IFACE_PORT1) ++ { ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)|BIT(4)); ++ } ++ else ++ { ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4)); ++ } ++ } ++ ++ if(check_buddy_mlmeinfo_state(Adapter, WIFI_FW_AP_STATE) && ++ check_buddy_fwstate(Adapter, _FW_LINKED)) ++ { ++ StopTxBeacon(Adapter); ++ } ++ ++ } ++ else//sitesurvey done ++ { ++ //enable to rx data frame ++ //write32(Adapter, REG_RCR, read32(padapter, REG_RCR)|RCR_ADF); ++ rtw_write16(Adapter, REG_RXFLTMAP2,0xFFFF); ++ ++ //enable update TSF ++ if(Adapter->iface_type == IFACE_PORT1) ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)&(~BIT(4))); ++ else ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4))); ++ ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_BCN); ++ ++ if(check_buddy_mlmeinfo_state(Adapter, WIFI_FW_AP_STATE) && ++ check_buddy_fwstate(Adapter, _FW_LINKED)) ++ { ++ ResumeTxBeacon(Adapter); ++ } ++ ++ } ++#endif ++} ++ ++static void hw_var_set_mlme_join(PADAPTER Adapter, u8 variable, u8* val) ++{ ++#ifdef CONFIG_CONCURRENT_MODE ++ u8 RetryLimit = 0x30; ++ u8 type = *((u8 *)val); ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ ++ if(type == 0) // prepare to join ++ { ++ if(check_buddy_mlmeinfo_state(Adapter, WIFI_FW_AP_STATE) && ++ check_buddy_fwstate(Adapter, _FW_LINKED)) ++ { ++ StopTxBeacon(Adapter); ++ } ++ ++ //enable to rx data frame.Accept all data frame ++ //rtw_write32(padapter, REG_RCR, rtw_read32(padapter, REG_RCR)|RCR_ADF); ++ rtw_write16(Adapter, REG_RXFLTMAP2,0xFFFF); ++ ++ if(check_buddy_mlmeinfo_state(Adapter, WIFI_FW_AP_STATE)) ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_BCN); ++ else ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_DATA|RCR_CBSSID_BCN); ++ ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) ++ { ++ RetryLimit = (pHalData->CustomerID == RT_CID_CCX) ? 7 : 48; ++ } ++ else // Ad-hoc Mode ++ { ++ RetryLimit = 0x7; ++ } ++ } ++ else if(type == 1) //joinbss_event call back when join res < 0 ++ { ++ if(check_buddy_mlmeinfo_state(Adapter, _HW_STATE_NOLINK_)) ++ rtw_write16(Adapter, REG_RXFLTMAP2,0x00); ++ ++ if(check_buddy_mlmeinfo_state(Adapter, WIFI_FW_AP_STATE) && ++ check_buddy_fwstate(Adapter, _FW_LINKED)) ++ { ++ ResumeTxBeacon(Adapter); ++ ++ //reset TSF 1/2 after ResumeTxBeacon ++ rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(1)|BIT(0)); ++ ++ } ++ } ++ else if(type == 2) //sta add event call back ++ { ++ ++ //enable update TSF ++ if(Adapter->iface_type == IFACE_PORT1) ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)&(~BIT(4))); ++ else ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4))); ++ ++ ++ if(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) ++ { ++ //fixed beacon issue for 8191su........... ++ rtw_write8(Adapter,0x542 ,0x02); ++ RetryLimit = 0x7; ++ } ++ ++ ++ if(check_buddy_mlmeinfo_state(Adapter, WIFI_FW_AP_STATE) && ++ check_buddy_fwstate(Adapter, _FW_LINKED)) ++ { ++ ResumeTxBeacon(Adapter); ++ ++ //reset TSF 1/2 after ResumeTxBeacon ++ rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(1)|BIT(0)); ++ } ++ ++ } ++ ++ rtw_write16(Adapter, REG_RL, RetryLimit << RETRY_LIMIT_SHORT_SHIFT | RetryLimit << RETRY_LIMIT_LONG_SHIFT); ++ ++#endif ++} ++static void SetHwReg8188ES(PADAPTER Adapter, u8 variable, u8* val) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ DM_ODM_T *podmpriv = &pHalData->odmpriv; ++_func_enter_; ++ ++ switch(variable) ++ { ++ case HW_VAR_MEDIA_STATUS: ++ { ++ u8 val8; ++ ++ val8 = rtw_read8(Adapter, MSR)&0x0c; ++ val8 |= *((u8 *)val); ++ rtw_write8(Adapter, MSR, val8); ++ } ++ break; ++ case HW_VAR_MEDIA_STATUS1: ++ { ++ u8 val8; ++ ++ val8 = rtw_read8(Adapter, MSR)&0x03; ++ val8 |= *((u8 *)val) <<2; ++ rtw_write8(Adapter, MSR, val8); ++ } ++ break; ++ case HW_VAR_SET_OPMODE: ++ hw_var_set_opmode(Adapter, variable, val); ++ break; ++ case HW_VAR_MAC_ADDR: ++ hw_var_set_macaddr(Adapter, variable, val); ++ break; ++ case HW_VAR_BSSID: ++ hw_var_set_bssid(Adapter, variable, val); ++ break; ++ case HW_VAR_BASIC_RATE: ++ { ++ u16 BrateCfg = 0; ++ u8 RateIndex = 0; ++ ++ // 2007.01.16, by Emily ++ // Select RRSR (in Legacy-OFDM and CCK) ++ // For 8190, we select only 24M, 12M, 6M, 11M, 5.5M, 2M, and 1M from the Basic rate. ++ // We do not use other rates. ++ HalSetBrateCfg( Adapter, val, &BrateCfg ); ++ DBG_8192C("HW_VAR_BASIC_RATE: BrateCfg(%#x)\n", BrateCfg); ++ ++ //2011.03.30 add by Luke Lee ++ //CCK 2M ACK should be disabled for some BCM and Atheros AP IOT ++ //because CCK 2M has poor TXEVM ++ //CCK 5.5M & 11M ACK should be enabled for better performance ++ ++ pHalData->BasicRateSet = BrateCfg = (BrateCfg |0xd) & 0x15d; ++ ++ BrateCfg |= 0x01; // default enable 1M ACK rate ++ // Set RRSR rate table. ++ rtw_write8(Adapter, REG_RRSR, BrateCfg&0xff); ++ rtw_write8(Adapter, REG_RRSR+1, (BrateCfg>>8)&0xff); ++ rtw_write8(Adapter, REG_RRSR+2, rtw_read8(Adapter, REG_RRSR+2)&0xf0); ++ ++ // Set RTS initial rate ++ while(BrateCfg > 0x1) ++ { ++ BrateCfg = (BrateCfg>> 1); ++ RateIndex++; ++ } ++ // Ziv - Check ++ rtw_write8(Adapter, REG_INIRTS_RATE_SEL, RateIndex); ++ } ++ break; ++ case HW_VAR_TXPAUSE: ++ rtw_write8(Adapter, REG_TXPAUSE, *((u8 *)val)); ++ break; ++ case HW_VAR_BCN_FUNC: ++ hw_var_set_bcn_func(Adapter, variable, val); ++ break; ++ case HW_VAR_CORRECT_TSF: ++#ifdef CONFIG_CONCURRENT_MODE ++ hw_var_set_correct_tsf(Adapter, variable, val); ++#else ++ { ++ u64 tsf; ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ //f = pmlmeext->TSFValue - ((u32)pmlmeext->TSFValue % (pmlmeinfo->bcn_interval*1024)) -1024; //us ++ tsf = pmlmeext->TSFValue - rtw_modular64(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval*1024)) - 1024; //us ++ ++ if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ++ ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) ++ { ++ //pHalData->RegTxPause |= STOP_BCNQ;BIT(6) ++ //rtw_write8(Adapter, REG_TXPAUSE, (rtw_read8(Adapter, REG_TXPAUSE)|BIT(6))); ++ StopTxBeacon(Adapter); ++ } ++ ++ // disable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(3))); ++ ++ rtw_write32(Adapter, REG_TSFTR, tsf); ++ rtw_write32(Adapter, REG_TSFTR+4, tsf>>32); ++ ++ // enable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(3)); ++ ++ if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ++ ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) ++ { ++ //pHalData->RegTxPause &= (~STOP_BCNQ); ++ //rtw_write8(Adapter, REG_TXPAUSE, (rtw_read8(Adapter, REG_TXPAUSE)&(~BIT(6)))); ++ ResumeTxBeacon(Adapter); ++ } ++ } ++#endif ++ break; ++ case HW_VAR_CHECK_BSSID: ++ if(*((u8 *)val)) ++ { ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_DATA|RCR_CBSSID_BCN); ++ } ++ else ++ { ++ u32 val32; ++ ++ val32 = rtw_read32(Adapter, REG_RCR); ++ ++ val32 &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN); ++ ++ rtw_write32(Adapter, REG_RCR, val32); ++ } ++ break; ++ case HW_VAR_MLME_DISCONNECT: ++#ifdef CONFIG_CONCURRENT_MODE ++ hw_var_set_mlme_disconnect(Adapter, variable, val); ++#else ++ { ++ //Set RCR to not to receive data frame when NO LINK state ++ //rtw_write32(Adapter, REG_RCR, rtw_read32(padapter, REG_RCR) & ~RCR_ADF); ++ //reject all data frames ++ rtw_write16(Adapter, REG_RXFLTMAP2,0x00); ++ ++ //reset TSF ++ rtw_write8(Adapter, REG_DUAL_TSF_RST, (BIT(0)|BIT(1))); ++ ++ //disable update TSF ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4)); ++ } ++#endif ++ break; ++ case HW_VAR_MLME_SITESURVEY: ++#ifdef CONFIG_CONCURRENT_MODE ++ hw_var_set_mlme_sitesurvey(Adapter, variable, val); ++#else ++ if(*((u8 *)val))//under sitesurvey ++ { ++ //config RCR to receive different BSSID & not to receive data frame ++ u32 v = rtw_read32(Adapter, REG_RCR); ++ v &= ~(RCR_CBSSID_BCN); ++ rtw_write32(Adapter, REG_RCR, v); ++ //reject all data frame ++ rtw_write16(Adapter, REG_RXFLTMAP2,0x00); ++ ++ //disable update TSF ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4)); ++ } ++ else//sitesurvey done ++ { ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if ((is_client_associated_to_ap(Adapter) == _TRUE) || ++ ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) ) ++ { ++ //enable to rx data frame ++ //rtw_write32(Adapter, REG_RCR, rtw_read32(padapter, REG_RCR)|RCR_ADF); ++ rtw_write16(Adapter, REG_RXFLTMAP2,0xFFFF); ++ ++ //enable update TSF ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4))); ++ } ++ else if((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ { ++ //rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_ADF); ++ rtw_write16(Adapter, REG_RXFLTMAP2,0xFFFF); ++ ++ //enable update TSF ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4))); ++ } ++ ++ if(Adapter->in_cta_test) ++ { ++ if((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ { ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_BCN); ++ } ++ else ++ { ++ u32 v = rtw_read32(Adapter, REG_RCR); ++ v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN );//| RCR_ADF ++ rtw_write32(Adapter, REG_RCR, v); ++ } ++ } ++ else ++ { ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_BCN); ++ } ++ } ++#endif ++ break; ++ case HW_VAR_MLME_JOIN: ++#ifdef CONFIG_CONCURRENT_MODE ++ hw_var_set_mlme_join(Adapter, variable, val); ++#else ++ { ++ u8 RetryLimit = 0x30; ++ u8 type = *((u8 *)val); ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ ++ if(type == 0) // prepare to join ++ { ++ //enable to rx data frame.Accept all data frame ++ //rtw_write32(padapter, REG_RCR, rtw_read32(padapter, REG_RCR)|RCR_ADF); ++ rtw_write16(Adapter, REG_RXFLTMAP2,0xFFFF); ++ if(Adapter->in_cta_test) ++ { ++ u32 v = rtw_read32(Adapter, REG_RCR); ++ v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN );//| RCR_ADF ++ rtw_write32(Adapter, REG_RCR, v); ++ } ++ else ++ { ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_DATA|RCR_CBSSID_BCN); ++ } ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) ++ { ++ RetryLimit = (pHalData->CustomerID == RT_CID_CCX) ? 7 : 48; ++ } ++ else // Ad-hoc Mode ++ { ++ RetryLimit = 0x7; ++ } ++ } ++ else if(type == 1) //joinbss_event call back when join res < 0 ++ { ++ rtw_write16(Adapter, REG_RXFLTMAP2,0x00); ++ } ++ else if(type == 2) //sta add event call back ++ { ++ // enable update TSF ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4))); ++ ++ if(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) ++ { ++ RetryLimit = 0x7; ++ } ++ } ++ ++ rtw_write16(Adapter, REG_RL, RetryLimit << RETRY_LIMIT_SHORT_SHIFT | RetryLimit << RETRY_LIMIT_LONG_SHIFT); ++ } ++#endif ++ break; ++ case HW_VAR_ON_RCR_AM: ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_AM); ++ DBG_871X("%s, %d, RCR= %x \n", __FUNCTION__,__LINE__, rtw_read32(Adapter, REG_RCR)); ++ break; ++ case HW_VAR_OFF_RCR_AM: ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)& (~RCR_AM)); ++ DBG_871X("%s, %d, RCR= %x \n", __FUNCTION__,__LINE__, rtw_read32(Adapter, REG_RCR)); ++ break; ++ case HW_VAR_BEACON_INTERVAL: ++ rtw_write16(Adapter, REG_BCN_INTERVAL, *((u16 *)val)); ++ ++#ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ { ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u16 bcn_interval = *((u16 *)val); ++ if((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE){ ++ DBG_8192C("%s==> bcn_interval:%d, eraly_int:%d \n",__FUNCTION__,bcn_interval,bcn_interval>>1); ++ rtw_write8(Adapter, REG_DRVERLYINT, bcn_interval>>1);// 50ms for sdio ++ } ++ else{ ++ ++ } ++ } ++#endif//CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ ++ break; ++ case HW_VAR_SLOT_TIME: ++ { ++ u8 u1bAIFS, aSifsTime; ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ rtw_write8(Adapter, REG_SLOT, val[0]); ++ ++ if(pmlmeinfo->WMM_enable == 0) ++ { ++ if( pmlmeext->cur_wireless_mode == WIRELESS_11B) ++ aSifsTime = 10; ++ else ++ aSifsTime = 16; ++ ++ u1bAIFS = aSifsTime + (2 * pmlmeinfo->slotTime); ++ ++ // Temporary removed, 2008.06.20. ++ rtw_write8(Adapter, REG_EDCA_VO_PARAM, u1bAIFS); ++ rtw_write8(Adapter, REG_EDCA_VI_PARAM, u1bAIFS); ++ rtw_write8(Adapter, REG_EDCA_BE_PARAM, u1bAIFS); ++ rtw_write8(Adapter, REG_EDCA_BK_PARAM, u1bAIFS); ++ } ++ } ++ break; ++ case HW_VAR_RESP_SIFS: ++ { ++#if 0 ++ // SIFS for OFDM Data ACK ++ rtw_write8(Adapter, REG_SIFS_CTX+1, val[0]); ++ // SIFS for OFDM consecutive tx like CTS data! ++ rtw_write8(Adapter, REG_SIFS_TRX+1, val[1]); ++ ++ rtw_write8(Adapter,REG_SPEC_SIFS+1, val[0]); ++ rtw_write8(Adapter,REG_MAC_SPEC_SIFS+1, val[0]); ++ ++ // 20100719 Joseph: Revise SIFS setting due to Hardware register definition change. ++ rtw_write8(Adapter, REG_R2T_SIFS+1, val[0]); ++ rtw_write8(Adapter, REG_T2T_SIFS+1, val[0]); ++#else ++ //SIFS_Timer = 0x0a0a0808; ++ //RESP_SIFS for CCK ++ rtw_write8(Adapter, REG_R2T_SIFS, val[0]); // SIFS_T2T_CCK (0x08) ++ rtw_write8(Adapter, REG_R2T_SIFS+1, val[1]); //SIFS_R2T_CCK(0x08) ++ //RESP_SIFS for OFDM ++ rtw_write8(Adapter, REG_T2T_SIFS, val[2]); //SIFS_T2T_OFDM (0x0a) ++ rtw_write8(Adapter, REG_T2T_SIFS+1, val[3]); //SIFS_R2T_OFDM(0x0a) ++#endif ++ } ++ break; ++ case HW_VAR_ACK_PREAMBLE: ++ { ++ u8 regTmp; ++ u8 bShortPreamble = *( (PBOOLEAN)val ); ++ // Joseph marked out for Netgear 3500 TKIP channel 7 issue.(Temporarily) ++ regTmp = (pHalData->nCur40MhzPrimeSC)<<5; ++ //regTmp = 0; ++ if(bShortPreamble) ++ regTmp |= 0x80; ++ ++ rtw_write8(Adapter, REG_RRSR+2, regTmp); ++ } ++ break; ++ case HW_VAR_SEC_CFG: ++#ifdef CONFIG_CONCURRENT_MODE ++ rtw_write8(Adapter, REG_SECCFG, 0x0c|BIT(5));// enable tx enc and rx dec engine, and no key search for MC/BC ++#else ++ rtw_write8(Adapter, REG_SECCFG, *((u8 *)val)); ++#endif ++ break; ++ case HW_VAR_DM_FLAG: ++ podmpriv->SupportAbility = *((u8 *)val); ++ break; ++ case HW_VAR_DM_FUNC_OP: ++ if(val[0]) ++ {// save dm flag ++ podmpriv->BK_SupportAbility = podmpriv->SupportAbility; ++ } ++ else ++ {// restore dm flag ++ podmpriv->SupportAbility = podmpriv->BK_SupportAbility; ++ } ++ break; ++ case HW_VAR_DM_FUNC_SET: ++ if(*((u32 *)val) == DYNAMIC_ALL_FUNC_ENABLE){ ++ pdmpriv->DMFlag = pdmpriv->InitDMFlag; ++ podmpriv->SupportAbility = pdmpriv->InitODMFlag; ++ } ++ else{ ++ podmpriv->SupportAbility |= *((u32 *)val); ++ } ++ break; ++ case HW_VAR_DM_FUNC_CLR: ++ podmpriv->SupportAbility &= *((u32 *)val); ++ break; ++ case HW_VAR_CAM_EMPTY_ENTRY: ++ { ++ u8 ucIndex = *((u8 *)val); ++ u8 i; ++ u32 ulCommand=0; ++ u32 ulContent=0; ++ u32 ulEncAlgo=CAM_AES; ++ ++ for(i=0;iAcParam_BE = ((u32 *)(val))[0]; ++ rtw_write32(Adapter, REG_EDCA_BE_PARAM, ((u32 *)(val))[0]); ++ break; ++ case HW_VAR_AC_PARAM_BK: ++ rtw_write32(Adapter, REG_EDCA_BK_PARAM, ((u32 *)(val))[0]); ++ break; ++ case HW_VAR_AMPDU_MIN_SPACE: ++ { ++ u8 MinSpacingToSet; ++ u8 SecMinSpace; ++ ++ MinSpacingToSet = *((u8 *)val); ++ if(MinSpacingToSet <= 7) ++ { ++ switch(Adapter->securitypriv.dot11PrivacyAlgrthm) ++ { ++ case _NO_PRIVACY_: ++ case _AES_: ++ SecMinSpace = 0; ++ break; ++ ++ case _WEP40_: ++ case _WEP104_: ++ case _TKIP_: ++ case _TKIP_WTMIC_: ++ SecMinSpace = 6; ++ break; ++ default: ++ SecMinSpace = 7; ++ break; ++ } ++ ++ if(MinSpacingToSet < SecMinSpace){ ++ MinSpacingToSet = SecMinSpace; ++ } ++ ++ //RT_TRACE(COMP_MLME, DBG_LOUD, ("Set HW_VAR_AMPDU_MIN_SPACE: %#x\n", Adapter->MgntInfo.MinSpaceCfg)); ++ rtw_write8(Adapter, REG_AMPDU_MIN_SPACE, (rtw_read8(Adapter, REG_AMPDU_MIN_SPACE) & 0xf8) | MinSpacingToSet); ++ } ++ } ++ break; ++ case HW_VAR_AMPDU_FACTOR: ++ { ++ u8 RegToSet_Normal[4]={0x41,0xa8,0x72, 0xb9}; ++ u8 RegToSet_BT[4]={0x31,0x74,0x42, 0x97}; ++ u8 FactorToSet; ++ u8 *pRegToSet; ++ u8 index = 0; ++ ++#ifdef CONFIG_BT_COEXIST ++ if( (pHalData->bt_coexist.BT_Coexist) && ++ (pHalData->bt_coexist.BT_CoexistType == BT_CSR_BC4) ) ++ pRegToSet = RegToSet_BT; // 0x97427431; ++ else ++#endif ++ pRegToSet = RegToSet_Normal; // 0xb972a841; ++ ++ FactorToSet = *((u8 *)val); ++ if(FactorToSet <= 3) ++ { ++ FactorToSet = (1<<(FactorToSet + 2)); ++ if(FactorToSet>0xf) ++ FactorToSet = 0xf; ++ ++ for(index=0; index<4; index++) ++ { ++ if((pRegToSet[index] & 0xf0) > (FactorToSet<<4)) ++ pRegToSet[index] = (pRegToSet[index] & 0x0f) | (FactorToSet<<4); ++ ++ if((pRegToSet[index] & 0x0f) > FactorToSet) ++ pRegToSet[index] = (pRegToSet[index] & 0xf0) | (FactorToSet); ++ ++ rtw_write8(Adapter, (REG_AGGLEN_LMT+index), pRegToSet[index]); ++ } ++ ++ //RT_TRACE(COMP_MLME, DBG_LOUD, ("Set HW_VAR_AMPDU_FACTOR: %#x\n", FactorToSet)); ++ } ++ } ++ break; ++ case HW_VAR_RXDMA_AGG_PG_TH: ++ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH, *((u8 *)val)); ++ break; ++ case HW_VAR_SET_RPWM: ++#ifdef CONFIG_LPS_LCLK ++ { ++ u8 ps_state = *((u8 *)val); ++ DBG_871X_LEVEL(_drv_debug_, "+%s: ps_state:0x%02x+\n", __func__, ps_state); ++ //rpwm value only use BIT0(clock bit) ,BIT6(Ack bit), and BIT7(Toggle bit) for 88e. ++ //BIT0 value - 1: 32k, 0:40MHz. ++ //BIT6 value - 1: report cpwm value after success set, 0:do not report. ++ //BIT7 value - Toggle bit change. ++ //modify by Thomas. 2012/4/2. ++ ps_state = ps_state & 0xC1; ++ ++#ifdef CONFIG_EXT_CLK //for sprd ++ if(ps_state&BIT(6)) // want to leave 32k ++ { ++ //enable ext clock req before leave LPS-32K ++ //DBG_871X("enable ext clock req before leaving LPS-32K\n"); ++ EnableGpio5ClockReq(Adapter, _FALSE, 1); ++ } ++#endif //CONFIG_EXT_CLK ++ ++ //DBG_871X("##### Change RPWM value to = %x for switch clk #####\n",ps_state); ++ rtw_write8(Adapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1, ps_state); ++ DBG_871X_LEVEL(_drv_debug_, "-%s: ps_state:0x%02x-\n", __func__, ps_state); ++ } ++#endif ++ break; ++ case HW_VAR_H2C_FW_PWRMODE: ++ { ++ u8 psmode = (*(u8 *)val); ++ ++ // Forece leave RF low power mode for 1T1R to prevent conficting setting in Fw power ++ // saving sequence. 2010.06.07. Added by tynli. Suggested by SD3 yschang. ++ if( (psmode != PS_MODE_ACTIVE) && (!IS_92C_SERIAL(pHalData->VersionID))) ++ { ++ ODM_RF_Saving(podmpriv, _TRUE); ++ } ++ rtl8188e_set_FwPwrMode_cmd(Adapter, psmode); ++ } ++ break; ++ case HW_VAR_H2C_FW_JOINBSSRPT: ++ { ++ u8 mstatus = (*(u8 *)val); ++ rtl8188e_set_FwJoinBssReport_cmd(Adapter, mstatus); ++ } ++ break; ++#ifdef CONFIG_P2P_PS ++ case HW_VAR_H2C_FW_P2P_PS_OFFLOAD: ++ { ++ u8 p2p_ps_state = (*(u8 *)val); ++ rtl8188e_set_p2p_ps_offload_cmd(Adapter, p2p_ps_state); ++ } ++ break; ++#endif // CONFIG_P2P_PS ++ case HW_VAR_INITIAL_GAIN: ++ { ++ DIG_T *pDigTable = &podmpriv->DM_DigTable; ++ u32 rx_gain = ((u32 *)(val))[0]; ++ ++ if(rx_gain == 0xff){//restore rx gain ++ ODM_Write_DIG(podmpriv,pDigTable->BackupIGValue); ++ } ++ else{ ++ pDigTable->BackupIGValue = pDigTable->CurIGValue; ++ ODM_Write_DIG(podmpriv,rx_gain); ++ } ++ } ++ break; ++ case HW_VAR_TRIGGER_GPIO_0: ++// rtl8192cu_trigger_gpio_0(Adapter); ++ break; ++#ifdef CONFIG_BT_COEXIST ++ case HW_VAR_BT_SET_COEXIST: ++ { ++ u8 bStart = (*(u8 *)val); ++ rtl8192c_set_dm_bt_coexist(Adapter, bStart); ++ } ++ break; ++ case HW_VAR_BT_ISSUE_DELBA: ++ { ++ u8 dir = (*(u8 *)val); ++ rtl8192c_issue_delete_ba(Adapter, dir); ++ } ++ break; ++#endif ++#if (RATE_ADAPTIVE_SUPPORT==1) ++ case HW_VAR_RPT_TIMER_SETTING: ++ { ++ u16 min_rpt_time = (*(u16 *)val); ++ ++ //DBG_8192C("==> HW_VAR_ANTENNA_DIVERSITY_SELECT , Ant_(%s)\n",(Optimum_antenna==2)?"A":"B"); ++ ++ //PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300, Optimum_antenna); ++ ODM_RA_Set_TxRPT_Time(podmpriv,min_rpt_time); ++ } ++ break; ++#endif ++ ++#ifdef CONFIG_SW_ANTENNA_DIVERSITY ++ case HW_VAR_ANTENNA_DIVERSITY_LINK: ++ //SwAntDivRestAfterLink8192C(Adapter); ++ ODM_SwAntDivRestAfterLink(podmpriv); ++ break; ++#endif ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ case HW_VAR_ANTENNA_DIVERSITY_SELECT: ++ { ++ u8 Optimum_antenna = (*(u8 *)val); ++ u8 Ant ; ++ //switch antenna to Optimum_antenna ++ //DBG_8192C("==> HW_VAR_ANTENNA_DIVERSITY_SELECT , Ant_(%s)\n",(Optimum_antenna==2)?"A":"B"); ++ if(pHalData->CurAntenna != Optimum_antenna) ++ { ++ Ant = (Optimum_antenna==2)?MAIN_ANT:AUX_ANT; ++ ODM_UpdateRxIdleAnt_88E(&pHalData->odmpriv, Ant); ++ ++ pHalData->CurAntenna = Optimum_antenna ; ++ //DBG_8192C("==> HW_VAR_ANTENNA_DIVERSITY_SELECT , Ant_(%s)\n",(Optimum_antenna==2)?"A":"B"); ++ } ++ } ++ break; ++#endif ++ case HW_VAR_EFUSE_BYTES: // To set EFUE total used bytes, added by Roger, 2008.12.22. ++ pHalData->EfuseUsedBytes = *((u16 *)val); ++ break; ++ case HW_VAR_FIFO_CLEARN_UP: ++ { ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(Adapter); ++ u8 trycnt = 100; ++ ++ //pause tx ++ rtw_write8(Adapter,REG_TXPAUSE,0xff); ++ ++ //keep sn ++ Adapter->xmitpriv.nqos_ssn = rtw_read16(Adapter,REG_NQOS_SEQ); ++ ++ //RX DMA stop ++ rtw_write32(Adapter,REG_RXPKT_NUM,(rtw_read32(Adapter,REG_RXPKT_NUM)|RW_RELEASE_EN)); ++ do{ ++ if(!(rtw_read32(Adapter,REG_RXPKT_NUM)&RXDMA_IDLE)) ++ break; ++ }while(trycnt--); ++ if(trycnt ==0) ++ DBG_8192C("Stop RX DMA failed...... \n"); ++ ++ //RQPN Load 0 ++ rtw_write16(Adapter,REG_RQPN_NPQ,0x0); ++ rtw_write32(Adapter,REG_RQPN,0x80000000); ++ rtw_mdelay_os(10); ++ ++ } ++ break; ++ case HW_VAR_CHECK_TXBUF: ++#ifdef CONFIG_CONCURRENT_MODE ++ { ++ int i; ++ u8 RetryLimit = 0x01; ++ ++ rtw_write16(Adapter, REG_RL, RetryLimit << RETRY_LIMIT_SHORT_SHIFT | RetryLimit << RETRY_LIMIT_LONG_SHIFT); ++ for(i=0;i<1000;i++) ++ { ++ if(rtw_read32(Adapter, 0x200) != rtw_read32(Adapter, 0x204)) ++ { ++ //DBG_871X("packet in tx packet buffer - 0x204=%x, 0x200=%x (%d)\n", rtw_read32(Adapter, 0x204), rtw_read32(Adapter, 0x200), i); ++ rtw_msleep_os(10); ++ } ++ else ++ { ++ DBG_871X("no packet in tx packet buffer (%d)\n", i); ++ break; ++ } ++ } ++ ++ RetryLimit = 0x30; ++ rtw_write16(Adapter, REG_RL, RetryLimit << RETRY_LIMIT_SHORT_SHIFT | RetryLimit << RETRY_LIMIT_LONG_SHIFT); ++ ++ } ++#endif ++ break; ++#ifdef CONFIG_WOWLAN ++ case HW_VAR_WOWLAN: ++ { ++ struct wowlan_ioctl_param *poidparam; ++ struct recv_buf *precvbuf; ++ struct security_priv *psecuritypriv = &Adapter->securitypriv; ++ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(Adapter); ++ int res, i; ++ u32 tmp; ++ u16 len = 0; ++ u64 iv_low = 0, iv_high = 0; ++ u8 mstatus = (*(u8 *)val); ++ u8 trycnt = 100; ++ u8 data[4]; ++ u8 val8; ++ ++ poidparam = (struct wowlan_ioctl_param *)val; ++ switch (poidparam->subcode){ ++ case WOWLAN_ENABLE: ++ DBG_871X_LEVEL(_drv_always_, "WOWLAN_ENABLE\n"); ++ ++ val8 = (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)? 0xcc: 0xcf; ++ rtw_write8(Adapter, REG_SECCFG, val8); ++ DBG_871X_LEVEL(_drv_always_, "REG_SECCFG: %02x\n", rtw_read8(Adapter, REG_SECCFG)); ++ ++ SetFwRelatedForWoWLAN8188ES(Adapter, _TRUE); ++ ++ rtl8188e_set_FwJoinBssReport_cmd(Adapter, 1); ++ rtw_msleep_os(2); ++ ++ //Set Pattern ++ //if(adapter_to_pwrctl(Adapter)->wowlan_pattern==_TRUE) ++ // rtw_wowlan_reload_pattern(Adapter); ++ ++ //RX DMA stop ++ DBG_871X_LEVEL(_drv_always_, "Pause DMA\n"); ++ rtw_write32(Adapter,REG_RXPKT_NUM,(rtw_read32(Adapter,REG_RXPKT_NUM)|RW_RELEASE_EN)); ++ do{ ++ if((rtw_read32(Adapter, REG_RXPKT_NUM)&RXDMA_IDLE)) { ++ DBG_871X_LEVEL(_drv_always_, "RX_DMA_IDLE is true\n"); ++ break; ++ } else { ++ // If RX_DMA is not idle, receive one pkt from DMA ++ res = sdio_local_read(Adapter, SDIO_REG_RX0_REQ_LEN, 4, (u8*)&tmp); ++ //len = le16_to_cpu(*(u16*)data); ++ if (tmp == 0){ ++ res = sdio_local_read(Adapter, SDIO_REG_HISR, 4, (u8*)&tmp); ++ DBG_871X_LEVEL(_drv_info_, "read SDIO_REG_HISR: 0x%08x\n", tmp); ++ } ++ res = RecvOnePkt(Adapter, tmp); ++ DBG_871X_LEVEL(_drv_always_, "RecvOnePkt Result: %d\n", res); ++ } ++ }while(trycnt--); ++ if(trycnt ==0) ++ DBG_871X_LEVEL(_drv_always_, "Stop RX DMA failed...... \n"); ++ ++ //Enable CPWM2 only. ++ DBG_871X_LEVEL(_drv_always_, "Enable only CPWM2\n"); ++ res = sdio_local_read(Adapter, SDIO_REG_HIMR, 4, (u8*)&tmp); ++ if (!res) ++ DBG_871X_LEVEL(_drv_info_, "read SDIO_REG_HIMR: 0x%08x\n", tmp); ++ else ++ DBG_871X_LEVEL(_drv_info_, "sdio_local_read fail\n"); ++ ++ tmp = SDIO_HIMR_CPWM2_MSK; ++ ++ res = sdio_local_write(Adapter, SDIO_REG_HIMR, 4, (u8*)&tmp); ++ ++ if (!res){ ++ res = sdio_local_read(Adapter, SDIO_REG_HIMR, 4, (u8*)&tmp); ++ DBG_871X_LEVEL(_drv_info_, "read again SDIO_REG_HIMR: 0x%08x\n", tmp); ++ }else ++ DBG_871X_LEVEL(_drv_info_, "sdio_local_write fail\n"); ++ ++ //Set WOWLAN H2C command. ++ DBG_871X_LEVEL(_drv_always_, "Set WOWLan cmd\n"); ++ rtl8188es_set_wowlan_cmd(Adapter, 1); ++ ++ mstatus = rtw_read8(Adapter, REG_WOW_CTRL); ++ trycnt = 10; ++ ++ while(!(mstatus&BIT1) && trycnt>1) { ++ mstatus = rtw_read8(Adapter, REG_WOW_CTRL); ++ DBG_871X_LEVEL(_drv_always_, "Loop index: %d :0x%02x\n", trycnt, mstatus); ++ trycnt --; ++ rtw_msleep_os(2); ++ } ++ ++ pwrctl->wowlan_wake_reason = rtw_read8(Adapter, REG_WOWLAN_WAKE_REASON); ++ DBG_871X_LEVEL(_drv_always_, "wowlan_wake_reason: 0x%02x\n", pwrctl->wowlan_wake_reason); ++ ++ //rtw_msleep_os(10); ++ break; ++ case WOWLAN_DISABLE: ++ trycnt = 10; ++ ++ DBG_871X_LEVEL(_drv_always_, "WOWLAN_DISABLE\n"); ++ rtl8188e_set_FwJoinBssReport_cmd(Adapter, 0); ++ ++ rtw_write8( Adapter, REG_SECCFG, 0x0c|BIT(5));// enable tx enc and rx dec engine, and no key search for MC/BC ++ DBG_871X_LEVEL(_drv_always_, "REG_SECCFG: %02x\n", rtw_read8(Adapter, REG_SECCFG)); ++ ++ pwrctl->wowlan_wake_reason = rtw_read8(Adapter, REG_WOWLAN_WAKE_REASON); ++ DBG_871X_LEVEL(_drv_always_, "wakeup_reason: 0x%02x\n", pwrctl->wowlan_wake_reason); ++ rtl8188es_set_wowlan_cmd(Adapter, 0); ++ mstatus = rtw_read8(Adapter, REG_WOW_CTRL); ++ DBG_871X_LEVEL(_drv_info_, "%s mstatus:0x%02x\n", __func__, mstatus); ++ ++ while(mstatus&BIT1 && trycnt>1) { ++ mstatus = rtw_read8(Adapter, REG_WOW_CTRL); ++ DBG_871X_LEVEL(_drv_always_, "Loop index: %d :0x%02x\n", trycnt, mstatus); ++ trycnt --; ++ rtw_msleep_os(2); ++ } ++ ++ if (mstatus & BIT1) { ++ printk("System did not release RX_DMA\n"); ++ } else { ++ // 3.1 read fw iv ++ iv_low = rtw_read32(Adapter, REG_TXPKTBUF_IV_LOW); ++ iv_high = rtw_read32(Adapter, REG_TXPKTBUF_IV_HIGH); ++ pwrctl->wowlan_fw_iv = iv_high << 32 | iv_low; ++ DBG_871X_LEVEL(_drv_always_, "fw_iv: 0x%016llx\n", pwrctl->wowlan_fw_iv); ++ //Update TX iv data. ++ //rtw_set_sec_iv(Adapter); ++ SetFwRelatedForWoWLAN8188ES(Adapter, _FALSE); ++ } ++ if((pwrctl->wowlan_wake_reason != FWDecisionDisconnect) && ++ (pwrctl->wowlan_wake_reason != Rx_Pairwisekey) && ++ (pwrctl->wowlan_wake_reason != Rx_DisAssoc) && ++ (pwrctl->wowlan_wake_reason != Rx_DeAuth)) ++ rtl8188e_set_FwJoinBssReport_cmd(Adapter, 1); ++ ++ rtw_msleep_os(5); ++ ++ //rtw_msleep_os(10); ++ break; ++ default: ++ break; ++ } ++ } ++ break; ++#endif //CONFIG_WOWLAN ++ case HW_VAR_APFM_ON_MAC: ++ pHalData->bMacPwrCtrlOn = *val; ++ DBG_871X("%s: bMacPwrCtrlOn=%d\n", __func__, pHalData->bMacPwrCtrlOn); ++ break; ++#if (RATE_ADAPTIVE_SUPPORT == 1) ++ case HW_VAR_TX_RPT_MAX_MACID: ++ { ++ u8 maxMacid = *val; ++ DBG_8192C("### MacID(%d),Set Max Tx RPT MID(%d)\n",maxMacid,maxMacid+1); ++ rtw_write8(Adapter, REG_TX_RPT_CTRL+1, maxMacid+1); ++ } ++ break; ++#endif // (RATE_ADAPTIVE_SUPPORT == 1) ++ case HW_VAR_H2C_MEDIA_STATUS_RPT: ++ { ++ rtl8188e_set_FwMediaStatus_cmd(Adapter , (*(u16 *)val)); ++ } ++ break; ++ case HW_VAR_BCN_VALID: ++ //BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2, write 1 to clear, Clear by sw ++ rtw_write8(Adapter, REG_TDECTRL+2, rtw_read8(Adapter, REG_TDECTRL+2) | BIT0); ++ break; ++ default: ++ ++ break; ++ } ++ ++_func_exit_; ++} ++ ++static void GetHwReg8188ES(PADAPTER padapter, u8 variable, u8 *val) ++{ ++ PHAL_DATA_TYPE pHalData= GET_HAL_DATA(padapter); ++ DM_ODM_T *podmpriv = &pHalData->odmpriv; ++_func_enter_; ++ ++ switch (variable) ++ { ++ case HW_VAR_BASIC_RATE: ++ *((u16*)val) = pHalData->BasicRateSet; ++ break; ++ ++ case HW_VAR_TXPAUSE: ++ val[0] = rtw_read8(padapter, REG_TXPAUSE); ++ break; ++ ++ case HW_VAR_BCN_VALID: ++ //BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2 ++ val[0] = (BIT0 & rtw_read8(padapter, REG_TDECTRL+2))?_TRUE:_FALSE; ++ break; ++ ++ case HW_VAR_DM_FLAG: ++ val[0] = podmpriv->SupportAbility; ++ break; ++ ++ case HW_VAR_RF_TYPE: ++ val[0] = pHalData->rf_type; ++ break; ++ ++ case HW_VAR_FWLPS_RF_ON: ++ { ++ //When we halt NIC, we should check if FW LPS is leave. ++ if ((padapter->bSurpriseRemoved == _TRUE) || ++ (adapter_to_pwrctl(padapter)->rf_pwrstate == rf_off)) ++ { ++ // If it is in HW/SW Radio OFF or IPS state, we do not check Fw LPS Leave, ++ // because Fw is unload. ++ val[0] = _TRUE; ++ } ++ else ++ { ++ u32 valRCR; ++ valRCR = rtw_read32(padapter, REG_RCR); ++ valRCR &= 0x00070000; ++ if(valRCR) ++ val[0] = _FALSE; ++ else ++ val[0] = _TRUE; ++ } ++ } ++ break; ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ case HW_VAR_CURRENT_ANTENNA: ++ val[0] = pHalData->CurAntenna; ++ break; ++#endif ++ case HW_VAR_EFUSE_BYTES: // To get EFUE total used bytes, added by Roger, 2008.12.22. ++ *((u16*)val) = pHalData->EfuseUsedBytes; ++ break; ++ ++ case HW_VAR_APFM_ON_MAC: ++ *val = pHalData->bMacPwrCtrlOn; ++ break; ++ case HW_VAR_CHK_HI_QUEUE_EMPTY: ++ *val = ((rtw_read32(padapter, REG_HGQ_INFORMATION)&0x0000ff00)==0) ? _TRUE:_FALSE; ++ break; ++ case HW_VAR_GET_CPWM: ++ *val = rtw_read8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HCPWM1); ++ break; ++ case HW_VAR_C2HEVT_CLEAR: ++ *val = rtw_read8(padapter, REG_C2HEVT_CLEAR); ++ break; ++ case HW_VAR_C2HEVT_MSG_NORMAL: ++ *val = rtw_read8(padapter, REG_C2HEVT_MSG_NORMAL); ++ break; ++ case HW_VAR_SYS_CLKR: ++ *val = rtw_read8(padapter, REG_SYS_CLKR); ++ break; ++ default: ++ break; ++ } ++ ++_func_exit_; ++} ++ ++// ++// Description: ++// Query setting of specified variable. ++// ++u8 ++GetHalDefVar8188ESDIO( ++ IN PADAPTER Adapter, ++ IN HAL_DEF_VARIABLE eVariable, ++ IN PVOID pValue ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u8 bResult = _SUCCESS; ++ ++ switch(eVariable) ++ { ++ case HAL_DEF_UNDERCORATEDSMOOTHEDPWDB: ++ { ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ struct sta_priv * pstapriv = &Adapter->stapriv; ++ struct sta_info * psta; ++ psta = rtw_get_stainfo(pstapriv, pmlmepriv->cur_network.network.MacAddress); ++ if(psta) ++ { ++ *((int *)pValue) = psta->rssi_stat.UndecoratedSmoothedPWDB; ++ } ++ } ++ ++ break; ++ case HAL_DEF_IS_SUPPORT_ANT_DIV: ++ #ifdef CONFIG_ANTENNA_DIVERSITY ++ *((u8 *)pValue) = (pHalData->AntDivCfg==0)?_FALSE:_TRUE; ++ #endif ++ break; ++ case HAL_DEF_CURRENT_ANTENNA: ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ *(( u8*)pValue) = pHalData->CurAntenna; ++#endif ++ break; ++#if (RATE_ADAPTIVE_SUPPORT == 1) ++ case HAL_DEF_RA_DECISION_RATE: ++ { ++ u8 MacID = *((u8*)pValue); ++ *((u8*)pValue) = ODM_RA_GetDecisionRate_8188E(&(pHalData->odmpriv), MacID); ++ } ++ break; ++ ++ case HAL_DEF_RA_SGI: ++ { ++ u8 MacID = *((u8*)pValue); ++ *((u8*)pValue) = ODM_RA_GetShortGI_8188E(&(pHalData->odmpriv), MacID); ++ } ++ break; ++#endif ++ ++ ++ case HAL_DEF_PT_PWR_STATUS: ++#if(POWER_TRAINING_ACTIVE==1) ++ { ++ u8 MacID = *((u8*)pValue); ++ *((u8*)pValue) = ODM_RA_GetHwPwrStatus_8188E(&(pHalData->odmpriv), MacID); ++ } ++#endif //(POWER_TRAINING_ACTIVE==1) ++ break; ++ ++ case HW_VAR_MAX_RX_AMPDU_FACTOR: ++ *(( u32*)pValue) = MAX_AMPDU_FACTOR_16K; ++ break; ++ ++ case HW_DEF_RA_INFO_DUMP: ++#if (RATE_ADAPTIVE_SUPPORT == 1) ++ { ++ u8 entry_id = *((u8*)pValue); ++ u8 i; ++ u8 bLinked = _FALSE; ++#ifdef CONFIG_CONCURRENT_MODE ++ PADAPTER pbuddy_adapter = Adapter->pbuddy_adapter; ++#endif //CONFIG_CONCURRENT_MODE ++ ++ //if(check_fwstate(&Adapter->mlmepriv, _FW_LINKED)== _TRUE) ++ ++ if(rtw_linked_check(Adapter)) ++ bLinked = _TRUE; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(pbuddy_adapter && rtw_linked_check(pbuddy_adapter)) ++ bLinked = _TRUE; ++#endif ++ ++ if(bLinked){ ++ DBG_871X("============ RA status check ===================\n"); ++ if(Adapter->bRxRSSIDisplay >30) ++ Adapter->bRxRSSIDisplay = 1; ++ for(i=0;i< Adapter->bRxRSSIDisplay;i++){ ++ DBG_8192C("Mac_id:%d ,RSSI:%d ,RateID = %d,RAUseRate = 0x%08x,RateSGI = %d, DecisionRate = 0x%02x ,PTStage = %d\n", ++ i, ++ pHalData->odmpriv.RAInfo[i].RssiStaRA, ++ pHalData->odmpriv.RAInfo[i].RateID, ++ pHalData->odmpriv.RAInfo[i].RAUseRate, ++ pHalData->odmpriv.RAInfo[i].RateSGI, ++ pHalData->odmpriv.RAInfo[i].DecisionRate, ++ pHalData->odmpriv.RAInfo[i].PTStage); ++ } ++ } ++ } ++#endif // (RATE_ADAPTIVE_SUPPORT == 1) ++ break; ++ ++ case HAL_DEF_DBG_DUMP_RXPKT: ++ *(( u8*)pValue) = pHalData->bDumpRxPkt; ++ break; ++ case HAL_DEF_DBG_DUMP_TXPKT: ++ *(( u8*)pValue) = pHalData->bDumpTxPkt; ++ break; ++ default: ++ bResult = GetHalDefVar(Adapter, eVariable, pValue); ++ break; ++ } ++ ++ return bResult; ++} ++ ++ ++ ++ ++// ++// Description: ++// Change default setting of specified variable. ++// ++u8 ++SetHalDefVar8188ESDIO( ++ IN PADAPTER Adapter, ++ IN HAL_DEF_VARIABLE eVariable, ++ IN PVOID pValue ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u8 bResult = _TRUE; ++ ++ switch(eVariable) ++ { ++ case HAL_DEF_DBG_DM_FUNC: ++ { ++ u8 dm_func = *(( u8*)pValue); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ DM_ODM_T *podmpriv = &pHalData->odmpriv; ++ ++ if(dm_func == 0){ //disable all dynamic func ++ podmpriv->SupportAbility = DYNAMIC_FUNC_DISABLE; ++ DBG_8192C("==> Disable all dynamic function...\n"); ++ } ++ else if(dm_func == 1){//disable DIG ++ podmpriv->SupportAbility &= (~DYNAMIC_BB_DIG); ++ DBG_8192C("==> Disable DIG...\n"); ++ } ++ else if(dm_func == 2){//disable High power ++ podmpriv->SupportAbility &= (~DYNAMIC_BB_DYNAMIC_TXPWR); ++ } ++ else if(dm_func == 3){//disable tx power tracking ++ podmpriv->SupportAbility &= (~DYNAMIC_RF_CALIBRATION); ++ DBG_8192C("==> Disable tx power tracking...\n"); ++ } ++ //else if(dm_func == 4){//disable BT coexistence ++ // pdmpriv->DMFlag &= (~DYNAMIC_FUNC_BT); ++ //} ++ else if(dm_func == 5){//disable antenna diversity ++ podmpriv->SupportAbility &= (~DYNAMIC_BB_ANT_DIV); ++ } ++ else if(dm_func == 6){//turn on all dynamic func ++ if(!(podmpriv->SupportAbility & DYNAMIC_BB_DIG)) ++ { ++ DIG_T *pDigTable = &podmpriv->DM_DigTable; ++ pDigTable->CurIGValue= rtw_read8(Adapter,0xc50); ++ } ++ //pdmpriv->DMFlag |= DYNAMIC_FUNC_BT; ++ podmpriv->SupportAbility = DYNAMIC_ALL_FUNC_ENABLE; ++ DBG_8192C("==> Turn on all dynamic function...\n"); ++ } ++ } ++ break; ++ case HAL_DEF_DBG_DUMP_RXPKT: ++ pHalData->bDumpRxPkt = *(( u8*)pValue); ++ break; ++ case HAL_DEF_DBG_DUMP_TXPKT: ++ pHalData->bDumpTxPkt = *(( u8*)pValue); ++ break; ++ default: ++ bResult = SetHalDefVar(Adapter, eVariable, pValue); ++ break; ++ } ++ ++ return bResult; ++} ++ ++void UpdateHalRAMask8188ESdio(PADAPTER padapter, u32 mac_id, u8 rssi_level) ++{ ++ //volatile unsigned int result; ++ u8 init_rate=0; ++ u8 networkType, raid; ++ u32 mask,rate_bitmap; ++ u8 shortGIrate = _FALSE; ++ int supportRateNum = 0; ++ struct sta_info *psta; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ //struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); ++ ++ if (mac_id >= NUM_STA) //CAM_SIZE ++ { ++ return; ++ } ++ ++ psta = pmlmeinfo->FW_sta_info[mac_id].psta; ++ if(psta == NULL) ++ { ++ return; ++ } ++ ++ switch (mac_id) ++ { ++ case 0:// for infra mode ++#ifdef CONFIG_CONCURRENT_MODE ++ case 2:// first station uses macid=0, second station uses macid=2 ++#endif ++ supportRateNum = rtw_get_rateset_len(cur_network->SupportedRates); ++ networkType = judge_network_type(padapter, cur_network->SupportedRates, supportRateNum) & 0xf; ++ //pmlmeext->cur_wireless_mode = networkType; ++ raid = networktype_to_raid(networkType); ++ ++ mask = update_supported_rate(cur_network->SupportedRates, supportRateNum); ++ mask |= (pmlmeinfo->HT_enable)? update_MSC_rate(&(pmlmeinfo->HT_caps)): 0; ++ ++ ++ if (support_short_GI(padapter, &(pmlmeinfo->HT_caps))) ++ { ++ shortGIrate = _TRUE; ++ } ++ ++ break; ++ ++ case 1://for broadcast/multicast ++ supportRateNum = rtw_get_rateset_len(pmlmeinfo->FW_sta_info[mac_id].SupportedRates); ++ if(pmlmeext->cur_wireless_mode & WIRELESS_11B) ++ networkType = WIRELESS_11B; ++ else ++ networkType = WIRELESS_11G; ++ raid = networktype_to_raid(networkType); ++ mask = update_basic_rate(cur_network->SupportedRates, supportRateNum); ++ ++ ++ break; ++ ++ default: //for each sta in IBSS ++ supportRateNum = rtw_get_rateset_len(pmlmeinfo->FW_sta_info[mac_id].SupportedRates); ++ networkType = judge_network_type(padapter, pmlmeinfo->FW_sta_info[mac_id].SupportedRates, supportRateNum) & 0xf; ++ //pmlmeext->cur_wireless_mode = networkType; ++ raid = networktype_to_raid(networkType); ++ mask = update_supported_rate(cur_network->SupportedRates, supportRateNum); ++ ++ //todo: support HT in IBSS ++ ++ break; ++ } ++ ++ //mask &=0xffffffff; ++ rate_bitmap = 0x0fffffff; ++#ifdef CONFIG_ODM_REFRESH_RAMASK ++ { ++ rate_bitmap = ODM_Get_Rate_Bitmap(&pHalData->odmpriv,mac_id,mask,rssi_level); ++ DBG_8192C("%s => mac_id:%d, networkType:0x%02x, mask:0x%08x\n\t ==> rssi_level:%d, rate_bitmap:0x%08x\n", ++ __FUNCTION__,mac_id,networkType,mask,rssi_level,rate_bitmap); ++ } ++#endif ++ mask &= rate_bitmap; ++ ++ ++ init_rate = get_highest_rate_idx(mask)&0x3f; ++ ++ if(pHalData->fw_ractrl == _TRUE) ++ { ++ u8 arg = 0; ++ ++ //arg = (cam_idx-4)&0x1f;//MACID ++ arg = mac_id&0x1f;//MACID ++ ++ arg |= BIT(7); ++ ++ if (shortGIrate==_TRUE) ++ arg |= BIT(5); ++ mask |= ((raid<<28)&0xf0000000); ++ ++ DBG_871X("update raid entry, mask=0x%x, arg=0x%x\n", mask, arg); ++ psta->ra_mask=mask; ++#ifdef CONFIG_INTEL_PROXIM ++ if(padapter->proximity.proxim_on ==_TRUE){ ++ arg &= ~BIT(6); ++ } ++ else { ++ arg |= BIT(6); ++ } ++#endif //CONFIG_INTEL_PROXIM ++ rtl8188e_set_raid_cmd(padapter, mask); ++ ++ } ++ else ++ { ++ ++#if(RATE_ADAPTIVE_SUPPORT == 1) ++ ++ ODM_RA_UpdateRateInfo_8188E( ++ &(pHalData->odmpriv), ++ mac_id, ++ raid, ++ mask, ++ shortGIrate ++ ); ++ ++#endif ++ } ++ ++ ++ //set ra_id ++ psta->raid = raid; ++ psta->init_rate = init_rate; ++ ++ ++} ++ ++ ++static VOID ++_BeaconFunctionEnable( ++ IN PADAPTER padapter, ++ IN BOOLEAN Enable, ++ IN BOOLEAN Linked ++ ) ++{ ++ rtw_write8(padapter, REG_BCN_CTRL, (BIT4 | BIT3 | BIT1)); ++// RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("_BeaconFunctionEnable 0x550 0x%x\n", rtw_read8(padapter, 0x550))); ++ ++ rtw_write8(padapter, REG_RD_CTRL+1, 0x6F); ++} ++ ++void SetBeaconRelatedRegisters8188ESdio(PADAPTER padapter) ++{ ++ u32 value32; ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u32 bcn_ctrl_reg = REG_BCN_CTRL; ++ //reset TSF, enable update TSF, correcting TSF On Beacon ++ ++ //REG_BCN_INTERVAL ++ //REG_BCNDMATIM ++ //REG_ATIMWND ++ //REG_TBTT_PROHIBIT ++ //REG_DRVERLYINT ++ //REG_BCN_MAX_ERR ++ //REG_BCNTCFG //(0x510) ++ //REG_DUAL_TSF_RST ++ //REG_BCN_CTRL //(0x550) ++ ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (padapter->iface_type == IFACE_PORT1){ ++ bcn_ctrl_reg = REG_BCN_CTRL_1; ++ } ++#endif ++ // ++ // ATIM window ++ // ++ rtw_write16(padapter, REG_ATIMWND, 2); ++ ++ // ++ // Beacon interval (in unit of TU). ++ // ++ rtw_write16(padapter, REG_BCN_INTERVAL, pmlmeinfo->bcn_interval); ++ ++ _InitBeaconParameters(padapter); ++ ++ rtw_write8(padapter, REG_SLOT, 0x09); ++ ++ // ++ // Force beacon frame transmission even after receiving beacon frame from other ad hoc STA ++ // ++ //PlatformEFIOWrite1Byte(Adapter, BCN_ERR_THRESH, 0x0a); // We force beacon sent to prevent unexpect disconnect status in Ad hoc mode ++ ++ // ++ // Reset TSF Timer to zero, added by Roger. 2008.06.24 ++ // ++ value32 = rtw_read32(padapter, REG_TCR); ++ value32 &= ~TSFRST; ++ rtw_write32(padapter, REG_TCR, value32); ++ ++ value32 |= TSFRST; ++ rtw_write32(padapter, REG_TCR, value32); ++ ++ // TODO: Modify later (Find the right parameters) ++ // NOTE: Fix test chip's bug (about contention windows's randomness) ++// if (OpMode == RT_OP_MODE_IBSS || OpMode == RT_OP_MODE_AP) ++ if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_AP_STATE) == _TRUE) ++ { ++ rtw_write8(padapter, REG_RXTSF_OFFSET_CCK, 0x50); ++ rtw_write8(padapter, REG_RXTSF_OFFSET_OFDM, 0x50); ++ } ++ ++ _BeaconFunctionEnable(padapter, _TRUE, _TRUE); ++ ++ ResumeTxBeacon(padapter); ++ rtw_write8(padapter, bcn_ctrl_reg, rtw_read8(padapter, bcn_ctrl_reg)|BIT(1)); ++} ++ ++void rtl8188es_set_hal_ops(PADAPTER padapter) ++{ ++ struct hal_ops *pHalFunc = &padapter->HalFunc; ++ ++_func_enter_; ++ ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(padapter->isprimary) ++#endif //CONFIG_CONCURRENT_MODE ++ { ++ //set hardware operation functions ++ padapter->HalData = rtw_zmalloc(sizeof(HAL_DATA_TYPE)); ++ if(padapter->HalData == NULL){ ++ DBG_8192C("cant not alloc memory for HAL DATA \n"); ++ } ++ } ++ ++ padapter->hal_data_sz = sizeof(HAL_DATA_TYPE); ++ ++ pHalFunc->hal_power_on = InitPowerOn_rtl8188es; ++ pHalFunc->hal_power_off = hal_poweroff_rtl8188es; ++ ++ pHalFunc->hal_init = &rtl8188es_hal_init; ++ pHalFunc->hal_deinit = &rtl8188es_hal_deinit; ++ ++ pHalFunc->inirp_init = &rtl8188es_inirp_init; ++ pHalFunc->inirp_deinit = &rtl8188es_inirp_deinit; ++ ++ pHalFunc->init_xmit_priv = &rtl8188es_init_xmit_priv; ++ pHalFunc->free_xmit_priv = &rtl8188es_free_xmit_priv; ++ ++ pHalFunc->init_recv_priv = &rtl8188es_init_recv_priv; ++ pHalFunc->free_recv_priv = &rtl8188es_free_recv_priv; ++ ++ pHalFunc->InitSwLeds = &rtl8188es_InitSwLeds; ++ pHalFunc->DeInitSwLeds = &rtl8188es_DeInitSwLeds; ++ ++ pHalFunc->init_default_value = &rtl8188es_init_default_value; ++ pHalFunc->intf_chip_configure = &rtl8188es_interface_configure; ++ pHalFunc->read_adapter_info = &ReadAdapterInfo8188ES; ++ ++ pHalFunc->enable_interrupt = &EnableInterrupt8188ESdio; ++ pHalFunc->disable_interrupt = &DisableInterrupt8188ESdio; ++ ++#ifdef CONFIG_WOWLAN ++ pHalFunc->clear_interrupt = &ClearInterrupt8189ESdio; ++#endif ++ ++ pHalFunc->SetHwRegHandler = &SetHwReg8188ES; ++ pHalFunc->GetHwRegHandler = &GetHwReg8188ES; ++ ++ pHalFunc->GetHalDefVarHandler = &GetHalDefVar8188ESDIO; ++ pHalFunc->SetHalDefVarHandler = &SetHalDefVar8188ESDIO; ++ ++ pHalFunc->UpdateRAMaskHandler = &UpdateHalRAMask8188ESdio; ++ pHalFunc->SetBeaconRelatedRegistersHandler = &SetBeaconRelatedRegisters8188ESdio; ++ ++ pHalFunc->hal_xmit = &rtl8188es_hal_xmit; ++ pHalFunc->mgnt_xmit = &rtl8188es_mgnt_xmit; ++ pHalFunc->hal_xmitframe_enqueue = &rtl8188es_hal_xmitframe_enqueue; ++ ++#ifdef CONFIG_HOSTAPD_MLME ++ pHalFunc->hostap_mgnt_xmit_entry = NULL; ++// pHalFunc->hostap_mgnt_xmit_entry = &rtl8192cu_hostap_mgnt_xmit_entry; ++#endif ++ rtl8188e_set_hal_ops(pHalFunc); ++_func_exit_; ++ ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/sdio/sdio_ops.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/sdio/sdio_ops.c +new file mode 100644 +index 00000000..979518c5 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/sdio/sdio_ops.c +@@ -0,0 +1,1959 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ *******************************************************************************/ ++#define _SDIO_OPS_C_ ++ ++#include ++#include ++#include ++#include ++ ++//#define SDIO_DEBUG_IO 1 ++ ++#ifdef CONFIG_EXT_CLK ++void EnableGpio5ClockReq(PADAPTER Adapter, u8 in_interrupt, u32 Enable); ++#endif //CONFIG_EXT_CLK ++// ++// Description: ++// The following mapping is for SDIO host local register space. ++// ++// Creadted by Roger, 2011.01.31. ++// ++static void HalSdioGetCmdAddr8723ASdio( ++ IN PADAPTER padapter, ++ IN u8 DeviceID, ++ IN u32 Addr, ++ OUT u32* pCmdAddr ++ ) ++{ ++ switch (DeviceID) ++ { ++ case SDIO_LOCAL_DEVICE_ID: ++ *pCmdAddr = ((SDIO_LOCAL_DEVICE_ID << 13) | (Addr & SDIO_LOCAL_MSK)); ++ break; ++ ++ case WLAN_IOREG_DEVICE_ID: ++ *pCmdAddr = ((WLAN_IOREG_DEVICE_ID << 13) | (Addr & WLAN_IOREG_MSK)); ++ break; ++ ++ case WLAN_TX_HIQ_DEVICE_ID: ++ *pCmdAddr = ((WLAN_TX_HIQ_DEVICE_ID << 13) | (Addr & WLAN_FIFO_MSK)); ++ break; ++ ++ case WLAN_TX_MIQ_DEVICE_ID: ++ *pCmdAddr = ((WLAN_TX_MIQ_DEVICE_ID << 13) | (Addr & WLAN_FIFO_MSK)); ++ break; ++ ++ case WLAN_TX_LOQ_DEVICE_ID: ++ *pCmdAddr = ((WLAN_TX_LOQ_DEVICE_ID << 13) | (Addr & WLAN_FIFO_MSK)); ++ break; ++ ++ case WLAN_RX0FF_DEVICE_ID: ++ *pCmdAddr = ((WLAN_RX0FF_DEVICE_ID << 13) | (Addr & WLAN_RX0FF_MSK)); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static u8 get_deviceid(u32 addr) ++{ ++ u8 devideId; ++ u16 pseudoId; ++ ++ ++ pseudoId = (u16)(addr >> 16); ++ switch (pseudoId) ++ { ++ case 0x1025: ++ devideId = SDIO_LOCAL_DEVICE_ID; ++ break; ++ ++ case 0x1026: ++ devideId = WLAN_IOREG_DEVICE_ID; ++ break; ++ ++// case 0x1027: ++// devideId = SDIO_FIRMWARE_FIFO; ++// break; ++ ++ case 0x1031: ++ devideId = WLAN_TX_HIQ_DEVICE_ID; ++ break; ++ ++ case 0x1032: ++ devideId = WLAN_TX_MIQ_DEVICE_ID; ++ break; ++ ++ case 0x1033: ++ devideId = WLAN_TX_LOQ_DEVICE_ID; ++ break; ++ ++ case 0x1034: ++ devideId = WLAN_RX0FF_DEVICE_ID; ++ break; ++ ++ default: ++// devideId = (u8)((addr >> 13) & 0xF); ++ devideId = WLAN_IOREG_DEVICE_ID; ++ break; ++ } ++ ++ return devideId; ++} ++ ++/* ++ * Ref: ++ * HalSdioGetCmdAddr8723ASdio() ++ */ ++static u32 _cvrt2ftaddr(const u32 addr, u8 *pdeviceId, u16 *poffset) ++{ ++ u8 deviceId; ++ u16 offset; ++ u32 ftaddr; ++ ++ ++ deviceId = get_deviceid(addr); ++ offset = 0; ++ ++ switch (deviceId) ++ { ++ case SDIO_LOCAL_DEVICE_ID: ++ offset = addr & SDIO_LOCAL_MSK; ++ break; ++ ++ case WLAN_TX_HIQ_DEVICE_ID: ++ case WLAN_TX_MIQ_DEVICE_ID: ++ case WLAN_TX_LOQ_DEVICE_ID: ++ offset = addr & WLAN_FIFO_MSK; ++ break; ++ ++ case WLAN_RX0FF_DEVICE_ID: ++ offset = addr & WLAN_RX0FF_MSK; ++ break; ++ ++ case WLAN_IOREG_DEVICE_ID: ++ default: ++ deviceId = WLAN_IOREG_DEVICE_ID; ++ offset = addr & WLAN_IOREG_MSK; ++ break; ++ } ++ ftaddr = (deviceId << 13) | offset; ++ ++ if (pdeviceId) *pdeviceId = deviceId; ++ if (poffset) *poffset = offset; ++ ++ return ftaddr; ++} ++ ++u8 _sdio_read8(PADAPTER padapter, u32 addr) ++{ ++ struct intf_hdl * pintfhdl; ++ u32 ftaddr; ++ u8 val; ++ ++_func_enter_; ++ ++ pintfhdl=&padapter->iopriv.intf; ++ ++ ftaddr = _cvrt2ftaddr(addr, NULL, NULL); ++ val = _sd_read8(pintfhdl, ftaddr, NULL); ++ ++_func_exit_; ++ ++ return val; ++} ++ ++u8 sdio_read8(struct intf_hdl *pintfhdl, u32 addr) ++{ ++ u32 ftaddr; ++ u8 val; ++ ++_func_enter_; ++ ftaddr = _cvrt2ftaddr(addr, NULL, NULL); ++ val = sd_read8(pintfhdl, ftaddr, NULL); ++ ++_func_exit_; ++ ++ return val; ++} ++ ++u16 sdio_read16(struct intf_hdl *pintfhdl, u32 addr) ++{ ++ u32 ftaddr; ++ u16 val; ++ ++_func_enter_; ++ ++ ftaddr = _cvrt2ftaddr(addr, NULL, NULL); ++ sd_cmd52_read(pintfhdl, ftaddr, 2, (u8*)&val); ++ val = le16_to_cpu(val); ++ ++_func_exit_; ++ ++ return val; ++} ++ ++u32 _sdio_read32(PADAPTER padapter, u32 addr) ++{ ++ //PADAPTER padapter; ++ struct intf_hdl * pintfhdl; ++ u8 bMacPwrCtrlOn; ++ u8 deviceId; ++ u16 offset; ++ u32 ftaddr; ++ u8 shift; ++ u32 val; ++ s32 err; ++ ++_func_enter_; ++ ++ pintfhdl=&padapter->iopriv.intf; ++ ++ ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if (((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ++ || (_FALSE == bMacPwrCtrlOn) ++#ifdef CONFIG_LPS_LCLK ++ || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode) ++#endif ++ ) ++ { ++ err = _sd_cmd52_read(pintfhdl, ftaddr, 4, (u8*)&val); ++#ifdef SDIO_DEBUG_IO ++ if (!err) { ++#endif ++ val = le32_to_cpu(val); ++ return val; ++#ifdef SDIO_DEBUG_IO ++ } ++ ++ DBG_871X(KERN_ERR "%s: Mac Power off, Read FAIL(%d)! addr=0x%x\n", __func__, err, addr); ++ return SDIO_ERR_VAL32; ++#endif ++ } ++ ++ // 4 bytes alignment ++ shift = ftaddr & 0x3; ++ if (shift == 0) { ++ val = _sd_read32(pintfhdl, ftaddr, NULL); ++ } else { ++ u8 *ptmpbuf; ++ ++ ptmpbuf = (u8*)rtw_malloc(8); ++ if (NULL == ptmpbuf) { ++ DBG_871X(KERN_ERR "%s: Allocate memory FAIL!(size=8) addr=0x%x\n", __func__, addr); ++ return SDIO_ERR_VAL32; ++ } ++ ++ ftaddr &= ~(u16)0x3; ++ _sd_read(pintfhdl, ftaddr, 8, ptmpbuf); ++ _rtw_memcpy(&val, ptmpbuf+shift, 4); ++ val = le32_to_cpu(val); ++ ++ rtw_mfree(ptmpbuf, 8); ++ } ++ ++_func_exit_; ++ ++ return val; ++} ++ ++u32 sdio_read32(struct intf_hdl *pintfhdl, u32 addr) ++{ ++ PADAPTER padapter; ++ u8 bMacPwrCtrlOn; ++ u8 deviceId; ++ u16 offset; ++ u32 ftaddr; ++ u8 shift; ++ u32 val; ++ s32 err; ++ ++_func_enter_; ++ ++ padapter = pintfhdl->padapter; ++ ++ ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if (((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ++ || (_FALSE == bMacPwrCtrlOn) ++#ifdef CONFIG_LPS_LCLK ++ || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode) ++#endif ++ ) ++ { ++ err = sd_cmd52_read(pintfhdl, ftaddr, 4, (u8*)&val); ++#ifdef SDIO_DEBUG_IO ++ if (!err) { ++#endif ++ val = le32_to_cpu(val); ++ return val; ++#ifdef SDIO_DEBUG_IO ++ } ++ ++ DBG_871X(KERN_ERR "%s: Mac Power off, Read FAIL(%d)! addr=0x%x\n", __func__, err, addr); ++ return SDIO_ERR_VAL32; ++#endif ++ } ++ ++ // 4 bytes alignment ++ shift = ftaddr & 0x3; ++ if (shift == 0) { ++ val = sd_read32(pintfhdl, ftaddr, NULL); ++ } else { ++ u8 *ptmpbuf; ++ ++ ptmpbuf = (u8*)rtw_malloc(8); ++ if (NULL == ptmpbuf) { ++ DBG_871X(KERN_ERR "%s: Allocate memory FAIL!(size=8) addr=0x%x\n", __func__, addr); ++ return SDIO_ERR_VAL32; ++ } ++ ++ ftaddr &= ~(u16)0x3; ++ sd_read(pintfhdl, ftaddr, 8, ptmpbuf); ++ _rtw_memcpy(&val, ptmpbuf+shift, 4); ++ val = le32_to_cpu(val); ++ ++ rtw_mfree(ptmpbuf, 8); ++ } ++ ++_func_exit_; ++ ++ return val; ++} ++ ++s32 sdio_readN(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8* pbuf) ++{ ++ PADAPTER padapter; ++ u8 bMacPwrCtrlOn; ++ u8 deviceId; ++ u16 offset; ++ u32 ftaddr; ++ u8 shift; ++ s32 err; ++ ++_func_enter_; ++ ++ padapter = pintfhdl->padapter; ++ err = 0; ++ ++ ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if (((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ++ || (_FALSE == bMacPwrCtrlOn) ++#ifdef CONFIG_LPS_LCLK ++ || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode) ++#endif ++ ) ++ { ++ err = sd_cmd52_read(pintfhdl, ftaddr, cnt, pbuf); ++ return err; ++ } ++ ++ // 4 bytes alignment ++ shift = ftaddr & 0x3; ++ if (shift == 0) { ++ err = sd_read(pintfhdl, ftaddr, cnt, pbuf); ++ } else { ++ u8 *ptmpbuf; ++ u32 n; ++ ++ ftaddr &= ~(u16)0x3; ++ n = cnt + shift; ++ ptmpbuf = rtw_malloc(n); ++ if (NULL == ptmpbuf) return -1; ++ err = sd_read(pintfhdl, ftaddr, n, ptmpbuf); ++ if (!err) ++ _rtw_memcpy(pbuf, ptmpbuf+shift, cnt); ++ rtw_mfree(ptmpbuf, n); ++ } ++ ++_func_exit_; ++ ++ return err; ++} ++ ++s32 sdio_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val) ++{ ++ u32 ftaddr; ++ s32 err; ++ ++_func_enter_; ++ ftaddr = _cvrt2ftaddr(addr, NULL, NULL); ++ sd_write8(pintfhdl, ftaddr, val, &err); ++ ++_func_exit_; ++ ++ return err; ++} ++ ++s32 sdio_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val) ++{ ++ u32 ftaddr; ++ u8 shift; ++ s32 err; ++ ++_func_enter_; ++ ftaddr = _cvrt2ftaddr(addr, NULL, NULL); ++ val = cpu_to_le16(val); ++ err = sd_cmd52_write(pintfhdl, ftaddr, 2, (u8*)&val); ++ ++_func_exit_; ++ ++ return err; ++} ++ ++s32 _sdio_write32(PADAPTER padapter, u32 addr, u32 val) ++{ ++ //PADAPTER padapter; ++ struct intf_hdl * pintfhdl; ++ u8 bMacPwrCtrlOn; ++ u8 deviceId; ++ u16 offset; ++ u32 ftaddr; ++ u8 shift; ++ s32 err; ++ ++_func_enter_; ++ ++ pintfhdl=&padapter->iopriv.intf; ++ err = 0; ++ ++ ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if (((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ++ || (_FALSE == bMacPwrCtrlOn) ++#ifdef CONFIG_LPS_LCLK ++ || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode) ++#endif ++ ) ++ { ++ val = cpu_to_le32(val); ++ err = _sd_cmd52_write(pintfhdl, ftaddr, 4, (u8*)&val); ++ return err; ++ } ++ ++ // 4 bytes alignment ++ shift = ftaddr & 0x3; ++#if 1 ++ if (shift == 0) ++ { ++ _sd_write32(pintfhdl, ftaddr, val, &err); ++ } ++ else ++ { ++ val = cpu_to_le32(val); ++ err = _sd_cmd52_write(pintfhdl, ftaddr, 4, (u8*)&val); ++ } ++#else ++ if (shift == 0) { ++ sd_write32(pintfhdl, ftaddr, val, &err); ++ } else { ++ u8 *ptmpbuf; ++ ++ ptmpbuf = (u8*)rtw_malloc(8); ++ if (NULL == ptmpbuf) return (-1); ++ ++ ftaddr &= ~(u16)0x3; ++ err = sd_read(pintfhdl, ftaddr, 8, ptmpbuf); ++ if (err) { ++ rtw_mfree(ptmpbuf, 8); ++ return err; ++ } ++ val = cpu_to_le32(val); ++ _rtw_memcpy(ptmpbuf+shift, &val, 4); ++ err = sd_write(pintfhdl, ftaddr, 8, ptmpbuf); ++ ++ rtw_mfree(ptmpbuf, 8); ++ } ++#endif ++ ++_func_exit_; ++ ++ return err; ++} ++ ++ ++s32 sdio_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val) ++{ ++ PADAPTER padapter; ++ u8 bMacPwrCtrlOn; ++ u8 deviceId; ++ u16 offset; ++ u32 ftaddr; ++ u8 shift; ++ s32 err; ++ ++_func_enter_; ++ ++ padapter = pintfhdl->padapter; ++ err = 0; ++ ++ ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if (((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ++ || (_FALSE == bMacPwrCtrlOn) ++#ifdef CONFIG_LPS_LCLK ++ || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode) ++#endif ++ ) ++ { ++ val = cpu_to_le32(val); ++ err = sd_cmd52_write(pintfhdl, ftaddr, 4, (u8*)&val); ++ return err; ++ } ++ ++ // 4 bytes alignment ++ shift = ftaddr & 0x3; ++#if 1 ++ if (shift == 0) ++ { ++ sd_write32(pintfhdl, ftaddr, val, &err); ++ } ++ else ++ { ++ val = cpu_to_le32(val); ++ err = sd_cmd52_write(pintfhdl, ftaddr, 4, (u8*)&val); ++ } ++#else ++ if (shift == 0) { ++ sd_write32(pintfhdl, ftaddr, val, &err); ++ } else { ++ u8 *ptmpbuf; ++ ++ ptmpbuf = (u8*)rtw_malloc(8); ++ if (NULL == ptmpbuf) return (-1); ++ ++ ftaddr &= ~(u16)0x3; ++ err = sd_read(pintfhdl, ftaddr, 8, ptmpbuf); ++ if (err) { ++ rtw_mfree(ptmpbuf, 8); ++ return err; ++ } ++ val = cpu_to_le32(val); ++ _rtw_memcpy(ptmpbuf+shift, &val, 4); ++ err = sd_write(pintfhdl, ftaddr, 8, ptmpbuf); ++ ++ rtw_mfree(ptmpbuf, 8); ++ } ++#endif ++ ++_func_exit_; ++ ++ return err; ++} ++ ++s32 sdio_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8* pbuf) ++{ ++ PADAPTER padapter; ++ u8 bMacPwrCtrlOn; ++ u8 deviceId; ++ u16 offset; ++ u32 ftaddr; ++ u8 shift; ++ s32 err; ++ ++_func_enter_; ++ ++ padapter = pintfhdl->padapter; ++ err = 0; ++ ++ ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if (((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ++ || (_FALSE == bMacPwrCtrlOn) ++#ifdef CONFIG_LPS_LCLK ++ || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode) ++#endif ++ ) ++ { ++ err = sd_cmd52_write(pintfhdl, ftaddr, cnt, pbuf); ++ return err; ++ } ++ ++ shift = ftaddr & 0x3; ++ if (shift == 0) { ++ err = sd_write(pintfhdl, ftaddr, cnt, pbuf); ++ } else { ++ u8 *ptmpbuf; ++ u32 n; ++ ++ ftaddr &= ~(u16)0x3; ++ n = cnt + shift; ++ ptmpbuf = rtw_malloc(n); ++ if (NULL == ptmpbuf) return -1; ++ err = sd_read(pintfhdl, ftaddr, 4, ptmpbuf); ++ if (err) { ++ rtw_mfree(ptmpbuf, n); ++ return err; ++ } ++ _rtw_memcpy(ptmpbuf+shift, pbuf, cnt); ++ err = sd_write(pintfhdl, ftaddr, n, ptmpbuf); ++ rtw_mfree(ptmpbuf, n); ++ } ++ ++_func_exit_; ++ ++ return err; ++} ++ ++void sdio_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) ++{ ++ s32 err; ++ ++_func_enter_; ++ ++ err = sdio_readN(pintfhdl, addr, cnt, rmem); ++ ++_func_exit_; ++} ++ ++void sdio_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) ++{ ++_func_enter_; ++ ++ sdio_writeN(pintfhdl, addr, cnt, wmem); ++ ++_func_exit_; ++} ++ ++/* ++ * Description: ++ * Read from RX FIFO ++ * Round read size to block size, ++ * and make sure data transfer will be done in one command. ++ * ++ * Parameters: ++ * pintfhdl a pointer of intf_hdl ++ * addr port ID ++ * cnt size to read ++ * rmem address to put data ++ * ++ * Return: ++ * _SUCCESS(1) Success ++ * _FAIL(0) Fail ++ */ ++static u32 sdio_read_port( ++ struct intf_hdl *pintfhdl, ++ u32 addr, ++ u32 cnt, ++ u8 *mem) ++{ ++ PADAPTER padapter = pintfhdl->padapter; ++ PSDIO_DATA psdio= &adapter_to_dvobj(padapter)->intf_data; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ s32 err; ++ ++ HalSdioGetCmdAddr8723ASdio(padapter, addr, pHalData->SdioRxFIFOCnt++, &addr); ++ ++ ++ cnt = _RND4(cnt); ++ if (cnt > psdio->block_transfer_len) ++ cnt = _RND(cnt, psdio->block_transfer_len); ++ ++// cnt = sdio_align_size(cnt); ++ ++ err = _sd_read(pintfhdl, addr, cnt, mem); ++ //err = sd_read(pintfhdl, addr, cnt, mem); ++ ++ ++ ++ if (err) return _FAIL; ++ return _SUCCESS; ++} ++ ++/* ++ * Description: ++ * Write to TX FIFO ++ * Align write size block size, ++ * and make sure data could be written in one command. ++ * ++ * Parameters: ++ * pintfhdl a pointer of intf_hdl ++ * addr port ID ++ * cnt size to write ++ * wmem data pointer to write ++ * ++ * Return: ++ * _SUCCESS(1) Success ++ * _FAIL(0) Fail ++ */ ++static u32 sdio_write_port( ++ struct intf_hdl *pintfhdl, ++ u32 addr, ++ u32 cnt, ++ u8 *mem) ++{ ++ PADAPTER padapter; ++ PSDIO_DATA psdio; ++ s32 err; ++ struct xmit_buf *xmitbuf = (struct xmit_buf *)mem; ++ ++ padapter = pintfhdl->padapter; ++ psdio = &adapter_to_dvobj(padapter)->intf_data; ++ ++ if(padapter->hw_init_completed == _FALSE) ++ { ++ DBG_871X("%s [addr=0x%x cnt=%d] padapter->hw_init_completed == _FALSE \n",__func__,addr,cnt); ++ return _FAIL; ++ } ++ ++ cnt = _RND4(cnt); ++ HalSdioGetCmdAddr8723ASdio(padapter, addr, cnt >> 2, &addr); ++ ++ if (cnt > psdio->block_transfer_len) ++ cnt = _RND(cnt, psdio->block_transfer_len); ++// cnt = sdio_align_size(cnt); ++ ++ err = sd_write(pintfhdl, addr, cnt, xmitbuf->pdata); ++ ++ rtw_sctx_done_err(&xmitbuf->sctx, ++ err ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS); ++ ++ if (err) ++ { ++ DBG_871X("%s, error=%d\n", __func__, err); ++ ++ return _FAIL; ++ } ++ return _SUCCESS; ++} ++ ++void sdio_set_intf_ops(struct _io_ops *pops) ++{ ++_func_enter_; ++ ++ pops->_read8 = &sdio_read8; ++ pops->_read16 = &sdio_read16; ++ pops->_read32 = &sdio_read32; ++ pops->_read_mem = &sdio_read_mem; ++ pops->_read_port = &sdio_read_port; ++ ++ pops->_write8 = &sdio_write8; ++ pops->_write16 = &sdio_write16; ++ pops->_write32 = &sdio_write32; ++ pops->_writeN = &sdio_writeN; ++ pops->_write_mem = &sdio_write_mem; ++ pops->_write_port = &sdio_write_port; ++ ++_func_exit_; ++} ++ ++/* ++ * Todo: align address to 4 bytes. ++ */ ++s32 _sdio_local_read( ++ PADAPTER padapter, ++ u32 addr, ++ u32 cnt, ++ u8 *pbuf) ++{ ++ struct intf_hdl * pintfhdl; ++ u8 bMacPwrCtrlOn; ++ s32 err; ++ u8 *ptmpbuf; ++ u32 n; ++ ++ pintfhdl=&padapter->iopriv.intf; ++ ++ HalSdioGetCmdAddr8723ASdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if ((_FALSE == bMacPwrCtrlOn) ++#ifdef CONFIG_LPS_LCLK ++// || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode) ++#endif ++ ) ++ { ++ err = _sd_cmd52_read(pintfhdl, addr, cnt, pbuf); ++ return err; ++ } ++ ++ n = RND4(cnt); ++ ptmpbuf = (u8*)rtw_malloc(n); ++ if(!ptmpbuf) ++ return (-1); ++ ++ err = _sd_read(pintfhdl, addr, n, ptmpbuf); ++ if (!err) ++ _rtw_memcpy(pbuf, ptmpbuf, cnt); ++ ++ if(ptmpbuf) ++ rtw_mfree(ptmpbuf, n); ++ ++ return err; ++} ++ ++/* ++ * Todo: align address to 4 bytes. ++ */ ++s32 sdio_local_read( ++ PADAPTER padapter, ++ u32 addr, ++ u32 cnt, ++ u8 *pbuf) ++{ ++ struct intf_hdl * pintfhdl; ++ u8 bMacPwrCtrlOn; ++ s32 err; ++ u8 *ptmpbuf; ++ u32 n; ++ ++ pintfhdl=&padapter->iopriv.intf; ++ ++ HalSdioGetCmdAddr8723ASdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if ((_FALSE == bMacPwrCtrlOn) ++#ifdef CONFIG_LPS_LCLK ++ || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode) ++#endif ++ ) ++ { ++ err = sd_cmd52_read(pintfhdl, addr, cnt, pbuf); ++ return err; ++ } ++ ++ n = RND4(cnt); ++ ptmpbuf = (u8*)rtw_malloc(n); ++ if(!ptmpbuf) ++ return (-1); ++ ++ err = sd_read(pintfhdl, addr, n, ptmpbuf); ++ if (!err) ++ _rtw_memcpy(pbuf, ptmpbuf, cnt); ++ ++ if(ptmpbuf) ++ rtw_mfree(ptmpbuf, n); ++ ++ return err; ++} ++ ++/* ++ * Todo: align address to 4 bytes. ++ */ ++s32 _sdio_local_write( ++ PADAPTER padapter, ++ u32 addr, ++ u32 cnt, ++ u8 *pbuf) ++{ ++ struct intf_hdl * pintfhdl; ++ u8 bMacPwrCtrlOn; ++ s32 err; ++ u8 *ptmpbuf; ++ ++ if(addr & 0x3) ++ DBG_8192C("%s, address must be 4 bytes alignment\n", __FUNCTION__); ++ ++ if(cnt & 0x3) ++ DBG_8192C("%s, size must be the multiple of 4 \n", __FUNCTION__); ++ ++ pintfhdl=&padapter->iopriv.intf; ++ ++ HalSdioGetCmdAddr8723ASdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if ((_FALSE == bMacPwrCtrlOn) ++#ifdef CONFIG_LPS_LCLK ++// || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode) ++#endif ++ ) ++ { ++ err = _sd_cmd52_write(pintfhdl, addr, cnt, pbuf); ++ return err; ++ } ++ ++ ptmpbuf = (u8*)rtw_malloc(cnt); ++ if(!ptmpbuf) ++ return (-1); ++ ++ _rtw_memcpy(ptmpbuf, pbuf, cnt); ++ ++ err = _sd_write(pintfhdl, addr, cnt, ptmpbuf); ++ ++ if (ptmpbuf) ++ rtw_mfree(ptmpbuf, cnt); ++ ++ return err; ++} ++ ++/* ++ * Todo: align address to 4 bytes. ++ */ ++s32 sdio_local_write( ++ PADAPTER padapter, ++ u32 addr, ++ u32 cnt, ++ u8 *pbuf) ++{ ++ ++ struct intf_hdl * pintfhdl; ++ u8 bMacPwrCtrlOn; ++ s32 err; ++ u8 *ptmpbuf; ++ ++ if(addr & 0x3) ++ DBG_8192C("%s, address must be 4 bytes alignment\n", __FUNCTION__); ++ ++ if(cnt & 0x3) ++ DBG_8192C("%s, size must be the multiple of 4 \n", __FUNCTION__); ++ ++ pintfhdl=&padapter->iopriv.intf; ++ HalSdioGetCmdAddr8723ASdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if ((_FALSE == bMacPwrCtrlOn) ++#ifdef CONFIG_LPS_LCLK ++ || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode) ++#endif ++ ) ++ { ++ err = sd_cmd52_write(pintfhdl, addr, cnt, pbuf); ++ return err; ++ } ++ ++ ptmpbuf = (u8*)rtw_malloc(cnt); ++ if(!ptmpbuf) ++ return (-1); ++ ++ _rtw_memcpy(ptmpbuf, pbuf, cnt); ++ ++ err = sd_write(pintfhdl, addr, cnt, ptmpbuf); ++ ++ if (ptmpbuf) ++ rtw_mfree(ptmpbuf, cnt); ++ ++ return err; ++} ++ ++u8 SdioLocalCmd52Read1Byte(PADAPTER padapter, u32 addr) ++{ ++ struct intf_hdl * pintfhdl; ++ u8 val = 0; ++ ++ pintfhdl=&padapter->iopriv.intf; ++ ++ HalSdioGetCmdAddr8723ASdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ sd_cmd52_read(pintfhdl, addr, 1, &val); ++ ++ return val; ++} ++ ++u16 SdioLocalCmd52Read2Byte(PADAPTER padapter, u32 addr) ++{ ++ struct intf_hdl * pintfhdl; ++ u16 val = 0; ++ ++ pintfhdl=&padapter->iopriv.intf; ++ HalSdioGetCmdAddr8723ASdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ sd_cmd52_read(pintfhdl, addr, 2, (u8*)&val); ++ ++ val = le16_to_cpu(val); ++ ++ return val; ++} ++ ++u32 SdioLocalCmd52Read4Byte(PADAPTER padapter, u32 addr) ++{ ++ struct intf_hdl * pintfhdl; ++ u32 val = 0; ++ ++ ++ pintfhdl=&padapter->iopriv.intf; ++ HalSdioGetCmdAddr8723ASdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ sd_cmd52_read(pintfhdl, addr, 4, (u8*)&val); ++ ++ val = le32_to_cpu(val); ++ ++ return val; ++} ++ ++u32 SdioLocalCmd53Read4Byte(PADAPTER padapter, u32 addr) ++{ ++ struct intf_hdl * pintfhdl; ++ u8 bMacPwrCtrlOn; ++ u32 val=0; ++ ++ pintfhdl=&padapter->iopriv.intf; ++ HalSdioGetCmdAddr8723ASdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if ((_FALSE == bMacPwrCtrlOn) ++#ifdef CONFIG_LPS_LCLK ++ || (_TRUE == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode) ++#endif ++ ) ++ { ++ sd_cmd52_read(pintfhdl, addr, 4, (u8*)&val); ++ val = le32_to_cpu(val); ++ } ++ else ++ val = sd_read32(pintfhdl, addr, NULL); ++ ++ return val; ++} ++ ++void SdioLocalCmd52Write1Byte(PADAPTER padapter, u32 addr, u8 v) ++{ ++ struct intf_hdl * pintfhdl; ++ ++ pintfhdl=&padapter->iopriv.intf; ++ HalSdioGetCmdAddr8723ASdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ sd_cmd52_write(pintfhdl, addr, 1, &v); ++} ++ ++void SdioLocalCmd52Write2Byte(PADAPTER padapter, u32 addr, u16 v) ++{ ++ struct intf_hdl * pintfhdl; ++ ++ pintfhdl=&padapter->iopriv.intf; ++ HalSdioGetCmdAddr8723ASdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ v = cpu_to_le16(v); ++ sd_cmd52_write(pintfhdl, addr, 2, (u8*)&v); ++} ++ ++void SdioLocalCmd52Write4Byte(PADAPTER padapter, u32 addr, u32 v) ++{ ++ struct intf_hdl * pintfhdl; ++ ++ pintfhdl=&padapter->iopriv.intf; ++ HalSdioGetCmdAddr8723ASdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ v = cpu_to_le32(v); ++ sd_cmd52_write(pintfhdl, addr, 4, (u8*)&v); ++} ++ ++#if 0 ++void ++DumpLoggedInterruptHistory8723Sdio( ++ PADAPTER padapter ++) ++{ ++ HAL_DATA_TYPE *pHalData=GET_HAL_DATA(padapter); ++ u4Byte DebugLevel = DBG_LOUD; ++ ++ if (DBG_Var.DbgPrintIsr == 0) ++ return; ++ ++ DBG_ChkDrvResource(padapter); ++ ++ ++ if(pHalData->InterruptLog.nISR_RX_REQUEST) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# RX_REQUEST[%ld]\t\n", pHalData->InterruptLog.nISR_RX_REQUEST)); ++ ++ if(pHalData->InterruptLog.nISR_AVAL) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# AVAL[%ld]\t\n", pHalData->InterruptLog.nISR_AVAL)); ++ ++ if(pHalData->InterruptLog.nISR_TXERR) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# TXERR[%ld]\t\n", pHalData->InterruptLog.nISR_TXERR)); ++ ++ if(pHalData->InterruptLog.nISR_RXERR) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# RXERR[%ld]\t\n", pHalData->InterruptLog.nISR_RXERR)); ++ ++ if(pHalData->InterruptLog.nISR_TXFOVW) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# TXFOVW[%ld]\t\n", pHalData->InterruptLog.nISR_TXFOVW)); ++ ++ if(pHalData->InterruptLog.nISR_RXFOVW) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# RXFOVW[%ld]\t\n", pHalData->InterruptLog.nISR_RXFOVW)); ++ ++ if(pHalData->InterruptLog.nISR_TXBCNOK) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# TXBCNOK[%ld]\t\n", pHalData->InterruptLog.nISR_TXBCNOK)); ++ ++ if(pHalData->InterruptLog.nISR_TXBCNERR) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# TXBCNERR[%ld]\t\n", pHalData->InterruptLog.nISR_TXBCNERR)); ++ ++ if(pHalData->InterruptLog.nISR_BCNERLY_INT) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# BCNERLY_INT[%ld]\t\n", pHalData->InterruptLog.nISR_BCNERLY_INT)); ++ ++ if(pHalData->InterruptLog.nISR_C2HCMD) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# C2HCMD[%ld]\t\n", pHalData->InterruptLog.nISR_C2HCMD)); ++ ++ if(pHalData->InterruptLog.nISR_CPWM1) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# CPWM1L[%ld]\t\n", pHalData->InterruptLog.nISR_CPWM1)); ++ ++ if(pHalData->InterruptLog.nISR_CPWM2) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# CPWM2[%ld]\t\n", pHalData->InterruptLog.nISR_CPWM2)); ++ ++ if(pHalData->InterruptLog.nISR_HSISR_IND) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# HSISR_IND[%ld]\t\n", pHalData->InterruptLog.nISR_HSISR_IND)); ++ ++ if(pHalData->InterruptLog.nISR_GTINT3_IND) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# GTINT3_IND[%ld]\t\n", pHalData->InterruptLog.nISR_GTINT3_IND)); ++ ++ if(pHalData->InterruptLog.nISR_GTINT4_IND) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# GTINT4_IND[%ld]\t\n", pHalData->InterruptLog.nISR_GTINT4_IND)); ++ ++ if(pHalData->InterruptLog.nISR_PSTIMEOUT) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# PSTIMEOUT[%ld]\t\n", pHalData->InterruptLog.nISR_PSTIMEOUT)); ++ ++ if(pHalData->InterruptLog.nISR_OCPINT) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# OCPINT[%ld]\t\n", pHalData->InterruptLog.nISR_OCPINT)); ++ ++ if(pHalData->InterruptLog.nISR_ATIMEND) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# ATIMEND[%ld]\t\n", pHalData->InterruptLog.nISR_ATIMEND)); ++ ++ if(pHalData->InterruptLog.nISR_ATIMEND_E) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# ATIMEND_E[%ld]\t\n", pHalData->InterruptLog.nISR_ATIMEND_E)); ++ ++ if(pHalData->InterruptLog.nISR_CTWEND) ++ RT_TRACE(COMP_SEND|COMP_RECV, DebugLevel, ("# CTWEND[%ld]\t\n", pHalData->InterruptLog.nISR_CTWEND)); ++} ++ ++void ++LogInterruptHistory8723Sdio( ++ PADAPTER padapter, ++ PRT_ISR_CONTENT pIsrContent ++) ++{ ++ HAL_DATA_TYPE *pHalData=GET_HAL_DATA(padapter); ++ ++ if((pHalData->IntrMask[0] & SDIO_HIMR_RX_REQUEST_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_RX_REQUEST)) ++ pHalData->InterruptLog.nISR_RX_REQUEST ++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_AVAL_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_AVAL)) ++ pHalData->InterruptLog.nISR_AVAL++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_TXERR_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_TXERR)) ++ pHalData->InterruptLog.nISR_TXERR++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_RXERR_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_RXERR)) ++ pHalData->InterruptLog.nISR_RXERR++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_TXFOVW_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_TXFOVW)) ++ pHalData->InterruptLog.nISR_TXFOVW++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_RXFOVW_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_RXFOVW)) ++ pHalData->InterruptLog.nISR_RXFOVW++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_TXBCNOK_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_TXBCNOK)) ++ pHalData->InterruptLog.nISR_TXBCNOK++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_TXBCNERR_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_TXBCNERR)) ++ pHalData->InterruptLog.nISR_TXBCNERR++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_BCNERLY_INT_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_BCNERLY_INT)) ++ pHalData->InterruptLog.nISR_BCNERLY_INT ++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_C2HCMD_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_C2HCMD)) ++ pHalData->InterruptLog.nISR_C2HCMD++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_CPWM1_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_CPWM1)) ++ pHalData->InterruptLog.nISR_CPWM1++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_CPWM2_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_CPWM2)) ++ pHalData->InterruptLog.nISR_CPWM2++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_HSISR_IND_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_HSISR_IND)) ++ pHalData->InterruptLog.nISR_HSISR_IND++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_GTINT3_IND_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_GTINT3_IND)) ++ pHalData->InterruptLog.nISR_GTINT3_IND++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_GTINT4_IND_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_GTINT4_IND)) ++ pHalData->InterruptLog.nISR_GTINT4_IND++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_PSTIMEOUT_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_PSTIMEOUT)) ++ pHalData->InterruptLog.nISR_PSTIMEOUT++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_OCPINT_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_OCPINT)) ++ pHalData->InterruptLog.nISR_OCPINT++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_ATIMEND_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_ATIMEND)) ++ pHalData->InterruptLog.nISR_ATIMEND++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_ATIMEND_E_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_ATIMEND_E)) ++ pHalData->InterruptLog.nISR_ATIMEND_E++; ++ if((pHalData->IntrMask[0] & SDIO_HIMR_CTWEND_MSK) && ++ (pIsrContent->IntArray[0] & SDIO_HISR_CTWEND)) ++ pHalData->InterruptLog.nISR_CTWEND++; ++ ++} ++ ++void ++DumpHardwareProfile8723Sdio( ++ IN PADAPTER padapter ++) ++{ ++ DumpLoggedInterruptHistory8723Sdio(padapter); ++} ++#endif ++ ++#ifdef CONFIG_USING_CMD52_READ_INT ++static s32 ReadInterrupt8188ESdio(PADAPTER padapter, u32 *phisr) ++{ ++ u8 val8, hisr_len; ++ u32 hisr, himr; ++ ++ ++ if (phisr == NULL) ++ return _FALSE; ++ ++ himr = GET_HAL_DATA(padapter)->sdio_himr; ++ ++ // decide how many bytes need to be read ++ hisr_len = 0; ++ while (himr) ++ { ++ hisr_len++; ++ himr >>= 8; ++ } ++ ++ hisr = 0; ++ ++ while (hisr_len != 0) ++ { ++ hisr_len--; ++ val8 = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_HISR+hisr_len); ++ hisr |= (val8 << (8*hisr_len)); ++ } ++ ++ *phisr = hisr; ++ ++ return _TRUE; ++} ++#endif ++ ++// ++// Description: ++// Initialize SDIO Host Interrupt Mask configuration variables for future use. ++// ++// Assumption: ++// Using SDIO Local register ONLY for configuration. ++// ++// Created by Roger, 2011.02.11. ++// ++void InitInterrupt8188ESdio(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE *pHalData; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pHalData->sdio_himr = (u32)( \ ++ SDIO_HIMR_RX_REQUEST_MSK | ++// SDIO_HIMR_AVAL_MSK | ++// SDIO_HIMR_TXERR_MSK | ++// SDIO_HIMR_RXERR_MSK | ++// SDIO_HIMR_TXFOVW_MSK | ++// SDIO_HIMR_RXFOVW_MSK | ++// SDIO_HIMR_TXBCNOK_MSK | ++// SDIO_HIMR_TXBCNERR_MSK | ++#ifdef CONFIG_EXT_CLK ++//for sprd ++ SDIO_HIMR_BCNERLY_INT_MSK | ++#endif //CONFIG_EXT_CLK ++// SDIO_HIMR_C2HCMD_MSK | ++#if defined(CONFIG_LPS_LCLK) && (!defined(CONFIG_DETECT_CPWM_BY_POLLING)) ++ SDIO_HIMR_CPWM1_MSK | ++ SDIO_HIMR_CPWM2_MSK | ++#endif ++// SDIO_HIMR_HSISR_IND_MSK | ++// SDIO_HIMR_GTINT3_IND_MSK | ++// SDIO_HIMR_GTINT4_IND_MSK | ++// SDIO_HIMR_PSTIMEOUT_MSK | ++// SDIO_HIMR_OCPINT_MSK | ++// SDIO_HIMR_ATIMEND_MSK | ++// SDIO_HIMR_ATIMEND_E_MSK | ++// SDIO_HIMR_CTWEND_MSK | ++ 0); ++} ++ ++// ++// Description: ++// Clear corresponding SDIO Host ISR interrupt service. ++// ++// Assumption: ++// Using SDIO Local register ONLY for configuration. ++// ++// Created by Roger, 2011.02.11. ++// ++void ClearInterrupt8723ASdio(PADAPTER padapter) ++{ ++ u32 tmp = 0; ++ tmp = SdioLocalCmd52Read4Byte(padapter, SDIO_REG_HISR); ++ SdioLocalCmd52Write4Byte(padapter, SDIO_REG_HISR, tmp); ++// padapter->IsrContent.IntArray[0] = 0; ++ padapter->IsrContent = 0; ++} ++ ++// ++// Description: ++// Enalbe SDIO Host Interrupt Mask configuration on SDIO local domain. ++// ++// Assumption: ++// 1. Using SDIO Local register ONLY for configuration. ++// 2. PASSIVE LEVEL ++// ++// Created by Roger, 2011.02.11. ++// ++void EnableInterrupt8188ESdio(PADAPTER padapter) ++{ ++ PHAL_DATA_TYPE pHalData; ++ u32 himr; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ((padapter->isprimary == _FALSE) && padapter->pbuddy_adapter){ ++ padapter = padapter->pbuddy_adapter; ++ } ++#endif ++ pHalData = GET_HAL_DATA(padapter); ++ himr = cpu_to_le32(pHalData->sdio_himr); ++ sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8*)&himr); ++ ++ ++ // ++ // There are some C2H CMDs have been sent before system interrupt is enabled, e.g., C2H, CPWM. ++ // So we need to clear all C2H events that FW has notified, otherwise FW won't schedule any commands anymore. ++ // 2011.10.19. ++ // ++ rtw_write8(padapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE); ++ ++} ++ ++// ++// Description: ++// Disable SDIO Host IMR configuration to mask unnecessary interrupt service. ++// ++// Assumption: ++// Using SDIO Local register ONLY for configuration. ++// ++// Created by Roger, 2011.02.11. ++// ++void DisableInterrupt8188ESdio(PADAPTER padapter) ++{ ++ u32 himr; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ((padapter->isprimary == _FALSE) && padapter->pbuddy_adapter){ ++ padapter = padapter->pbuddy_adapter; ++ } ++#endif ++ himr = cpu_to_le32(SDIO_HIMR_DISABLED); ++ sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8*)&himr); ++ ++} ++ ++// ++// Description: ++// Update SDIO Host Interrupt Mask configuration on SDIO local domain. ++// ++// Assumption: ++// 1. Using SDIO Local register ONLY for configuration. ++// 2. PASSIVE LEVEL ++// ++// Created by Roger, 2011.02.11. ++// ++void UpdateInterruptMask8188ESdio(PADAPTER padapter, u32 AddMSR, u32 RemoveMSR) ++{ ++ HAL_DATA_TYPE *pHalData; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ((padapter->isprimary == _FALSE) && padapter->pbuddy_adapter){ ++ padapter = padapter->pbuddy_adapter; ++ } ++#endif ++ pHalData = GET_HAL_DATA(padapter); ++ ++ if (AddMSR) ++ pHalData->sdio_himr |= AddMSR; ++ ++ if (RemoveMSR) ++ pHalData->sdio_himr &= (~RemoveMSR); ++ ++ DisableInterrupt8188ESdio(padapter); ++ EnableInterrupt8188ESdio(padapter); ++} ++ ++#ifdef CONFIG_WOWLAN ++void ClearInterrupt8189ESdio(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ u32 v32 = 0; ++ ++ v32 = pHalData->sdio_himr | SDIO_HISR_CPWM2; ++ ++ pHalData->sdio_hisr &= v32; ++ ++ // clear HISR ++ v32 = pHalData->sdio_hisr & MASK_SDIO_HISR_CLEAR; ++ if (v32) { ++ v32 = cpu_to_le32(v32); ++ sdio_local_write(padapter, SDIO_REG_HISR, 4, (u8*)&v32); ++ } ++} ++#endif ++ ++#ifdef CONFIG_MAC_LOOPBACK_DRIVER ++static void sd_recv_loopback(PADAPTER padapter, u32 size) ++{ ++ PLOOPBACKDATA ploopback; ++ u32 readsize, allocsize; ++ u8 *preadbuf; ++ ++ ++ readsize = size; ++ DBG_8192C("%s: read size=%d\n", __func__, readsize); ++ allocsize = _RND(readsize, adapter_to_dvobj(padapter)->intf_data.block_transfer_len); ++ ++ ploopback = padapter->ploopback; ++ if (ploopback) { ++ ploopback->rxsize = readsize; ++ preadbuf = ploopback->rxbuf; ++ } ++ else { ++ preadbuf = rtw_malloc(allocsize); ++ if (preadbuf == NULL) { ++ DBG_8192C("%s: malloc fail size=%d\n", __func__, allocsize); ++ return; ++ } ++ } ++ ++// rtw_read_port(padapter, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); ++ sdio_read_port(&padapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); ++ ++ if (ploopback) ++ _rtw_up_sema(&ploopback->sema); ++ else { ++ u32 i; ++ ++ DBG_8192C("%s: drop pkt\n", __func__); ++ for (i = 0; i < readsize; i+=4) { ++ DBG_8192C("%08X", *(u32*)(preadbuf + i)); ++ if ((i+4) & 0x1F) printk(" "); ++ else printk("\n"); ++ } ++ printk("\n"); ++ rtw_mfree(preadbuf, allocsize); ++ } ++} ++#endif // CONFIG_MAC_LOOPBACK_DRIVER ++ ++#ifdef CONFIG_SDIO_RX_COPY ++static struct recv_buf* sd_recv_rxfifo(PADAPTER padapter, u32 size) ++{ ++ u32 readsize, ret; ++ u8 *preadbuf; ++ struct recv_priv *precvpriv; ++ struct recv_buf *precvbuf; ++ ++ ++ readsize = size; ++ ++ //3 1. alloc recvbuf ++ precvpriv = &padapter->recvpriv; ++ precvbuf = rtw_dequeue_recvbuf(&precvpriv->free_recv_buf_queue); ++ if (precvbuf == NULL) { ++ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: alloc recvbuf FAIL!\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ //3 2. alloc skb ++ if (precvbuf->pskb == NULL) { ++ SIZE_PTR tmpaddr=0; ++ SIZE_PTR alignment=0; ++ ++ DBG_871X("%s: alloc_skb for rx buffer\n", __FUNCTION__); ++ ++ precvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); ++ ++ if(precvbuf->pskb) ++ { ++ precvbuf->pskb->dev = padapter->pnetdev; ++ ++ tmpaddr = (SIZE_PTR)precvbuf->pskb->data; ++ alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); ++ skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment)); ++ ++ precvbuf->phead = precvbuf->pskb->head; ++ precvbuf->pdata = precvbuf->pskb->data; ++ precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); ++ precvbuf->pend = skb_end_pointer(precvbuf->pskb); ++ precvbuf->len = 0; ++ } ++ ++ if (precvbuf->pskb == NULL) { ++ DBG_871X("%s: alloc_skb fail! read=%d\n", __FUNCTION__, readsize); ++ return NULL; ++ } ++ } ++ ++ //3 3. read data from rxfifo ++ preadbuf = precvbuf->pdata; ++// rtw_read_port(padapter, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); ++ ret = sdio_read_port(&padapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); ++ if (ret == _FAIL) { ++ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: read port FAIL!\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ ++ //3 4. init recvbuf ++ precvbuf->len = readsize; ++ ++ return precvbuf; ++} ++#else ++static struct recv_buf* sd_recv_rxfifo(PADAPTER padapter, u32 size) ++{ ++ u32 readsize, allocsize, ret; ++ u8 *preadbuf; ++ _pkt *ppkt; ++ struct recv_priv *precvpriv; ++ struct recv_buf *precvbuf; ++ ++ ++ readsize = size; ++ ++ //3 1. alloc skb ++ // align to block size ++ allocsize = _RND(readsize, adapter_to_dvobj(padapter)->intf_data.block_transfer_len); ++ ++ ppkt = rtw_skb_alloc(allocsize); ++ ++ if (ppkt == NULL) { ++ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: alloc_skb fail! alloc=%d read=%d\n", __FUNCTION__, allocsize, readsize)); ++ return NULL; ++ } ++ ++ //3 2. read data from rxfifo ++ preadbuf = skb_put(ppkt, readsize); ++// rtw_read_port(padapter, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); ++ ret = sdio_read_port(&padapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); ++ if (ret == _FAIL) { ++ rtw_skb_free(ppkt); ++ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: read port FAIL!\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ //3 3. alloc recvbuf ++ precvpriv = &padapter->recvpriv; ++ precvbuf = rtw_dequeue_recvbuf(&precvpriv->free_recv_buf_queue); ++ if (precvbuf == NULL) { ++ rtw_skb_free(ppkt); ++ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: alloc recvbuf FAIL!\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ //3 4. init recvbuf ++ precvbuf->pskb = ppkt; ++ ++ precvbuf->len = ppkt->len; ++ ++ precvbuf->phead = ppkt->head; ++ precvbuf->pdata = ppkt->data; ++ precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); ++ precvbuf->pend = skb_end_pointer(precvbuf->pskb); ++ ++ return precvbuf; ++} ++#endif ++ ++static void sd_rxhandler(PADAPTER padapter, struct recv_buf *precvbuf) ++{ ++ struct recv_priv *precvpriv; ++ _queue *ppending_queue; ++ ++ ++ precvpriv = &padapter->recvpriv; ++ ppending_queue = &precvpriv->recv_buf_pending_queue; ++ ++ //3 1. enqueue recvbuf ++ rtw_enqueue_recvbuf(precvbuf, ppending_queue); ++ ++ //3 2. schedule tasklet ++#ifdef PLATFORM_LINUX ++ tasklet_schedule(&precvpriv->recv_tasklet); ++#endif ++} ++ ++void sd_int_dpc(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct intf_hdl * pintfhdl=&padapter->iopriv.intf; ++ if (pHalData->sdio_hisr & SDIO_HISR_CPWM1) ++ { ++ struct reportpwrstate_parm report; ++ ++#ifdef CONFIG_LPS_RPWM_TIMER ++ u8 bcancelled; ++ _cancel_timer(&(adapter_to_pwrctl(padapter)->pwr_rpwm_timer), &bcancelled); ++#endif // CONFIG_LPS_RPWM_TIMER ++ ++#ifdef CONFIG_USING_CMD52_READ_INT ++ report.state = SdioLocalCmd52Read1Byte(padapter,SDIO_REG_HCPWM1); ++#else //CONFIG_USING_CMD52_READ_INT ++ _sdio_local_read(padapter, SDIO_REG_HCPWM1, 1, &report.state); ++#endif ++ ++#ifdef CONFIG_LPS_LCLK ++ //88e's cpwm value only change BIT0, so driver need to add PS_STATE_S2 for LPS flow. ++ //modify by Thomas. 2012/4/2. ++ ++#ifdef CONFIG_EXT_CLK //for sprd ++ if(report.state & BIT(4)) //indicate FW entering 32k ++ { ++ u8 chk_cnt = 0; ++ ++ do{ ++ if(_sdio_read8(padapter, 0x90)&BIT(0))//FW in 32k already ++ { ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ ++ if(pwrpriv->rpwm < PS_STATE_S2) ++ { ++ //DBG_871X("disable ext clk when FW in LPS-32K already!\n"); ++ EnableGpio5ClockReq(padapter, _TRUE, 0); ++ } ++ ++ break; ++ } ++ ++ chk_cnt++; ++ ++ }while(chk_cnt<10); ++ ++ if(chk_cnt==10) ++ { ++ DBG_871X("polling fw in 32k already, fail!\n"); ++ } ++ ++ } ++ else //indicate fw leaving 32K ++#endif //CONFIG_EXT_CLK ++ { ++ report.state |= PS_STATE_S2; ++ //cpwm_int_hdl(padapter, &report); ++ _set_workitem(&(adapter_to_pwrctl(padapter)->cpwm_event)); ++ } ++#endif ++ } ++ ++#ifdef CONFIG_WOWLAN ++ if (pHalData->sdio_hisr & SDIO_HISR_CPWM2) { ++ u32 value; ++ value = rtw_read32(padapter, SDIO_LOCAL_BASE+SDIO_REG_HISR); ++ DBG_871X_LEVEL(_drv_always_, "Reset SDIO HISR(0x%08x) original:0x%08x\n", ++ SDIO_LOCAL_BASE+SDIO_REG_HISR, value); ++ value |= BIT19; ++ rtw_write32(padapter, SDIO_LOCAL_BASE+SDIO_REG_HISR, value); ++ ++ value = rtw_read8(padapter, SDIO_LOCAL_BASE+SDIO_REG_HIMR+2); ++ DBG_871X_LEVEL(_drv_always_, "Reset SDIO HIMR CPWM2(0x%08x) original:0x%02x\n", ++ SDIO_LOCAL_BASE+SDIO_REG_HIMR + 2, value); ++ } ++#endif ++ if (pHalData->sdio_hisr & SDIO_HISR_TXERR) ++ { ++ u8 *status; ++ u32 addr; ++ ++ status = rtw_malloc(4); ++ if (status) ++ { ++ addr = REG_TXDMA_STATUS; ++ HalSdioGetCmdAddr8723ASdio(padapter, WLAN_IOREG_DEVICE_ID, addr, &addr); ++ _sd_read(pintfhdl, addr, 4, status); ++ _sd_write(pintfhdl, addr, 4, status); ++ DBG_8192C("%s: SDIO_HISR_TXERR (0x%08x)\n", __func__, le32_to_cpu(*(u32*)status)); ++ rtw_mfree(status, 4); ++ } else { ++ DBG_8192C("%s: SDIO_HISR_TXERR, but can't allocate memory to read status!\n", __func__); ++ } ++ } ++ ++#ifdef CONFIG_INTERRUPT_BASED_TXBCN ++ ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ if (pHalData->sdio_hisr & SDIO_HISR_BCNERLY_INT) ++ #endif ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ if (pHalData->sdio_hisr & (SDIO_HISR_TXBCNOK|SDIO_HISR_TXBCNERR)) ++ #endif ++ { ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ #if 0 //for debug ++ if (pHalData->sdio_hisr & SDIO_HISR_BCNERLY_INT) ++ DBG_8192C("%s: SDIO_HISR_BCNERLY_INT\n", __func__); ++ ++ if (pHalData->sdio_hisr & SDIO_HISR_TXBCNOK) ++ DBG_8192C("%s: SDIO_HISR_TXBCNOK\n", __func__); ++ ++ if (pHalData->sdio_hisr & SDIO_HISR_TXBCNERR) ++ DBG_8192C("%s: SDIO_HISR_TXBCNERR\n", __func__); ++ #endif ++ ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ { ++ //send_beacon(padapter); ++ if(pmlmepriv->update_bcn == _TRUE) ++ { ++ //tx_beacon_hdl(padapter, NULL); ++ set_tx_beacon_cmd(padapter); ++ } ++ } ++#ifdef CONFIG_CONCURRENT_MODE ++ if(check_buddy_fwstate(padapter, WIFI_AP_STATE)) ++ { ++ //send_beacon(padapter); ++ if(padapter->pbuddy_adapter->mlmepriv.update_bcn == _TRUE) ++ { ++ //tx_beacon_hdl(padapter, NULL); ++ set_tx_beacon_cmd(padapter->pbuddy_adapter); ++ } ++ } ++#endif ++ } ++#endif //CONFIG_INTERRUPT_BASED_TXBCN ++ ++#ifdef CONFIG_EXT_CLK ++ if (pHalData->sdio_hisr & SDIO_HISR_BCNERLY_INT) ++ { ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ if(check_fwstate(pmlmepriv, _FW_LINKED) && check_fwstate(pmlmepriv, WIFI_STATION_STATE)) ++ { ++ //DBG_8192C("BCNERLY_INT for enabling ext clk\n"); ++ EnableGpio5ClockReq(padapter, _TRUE, 1); ++ } ++ } ++#endif //CONFIG_EXT_CLK ++ ++ if (pHalData->sdio_hisr & SDIO_HISR_C2HCMD) ++ { ++ DBG_8192C("%s: C2H Command\n", __func__); ++ } ++ ++ if (pHalData->sdio_hisr & SDIO_HISR_RX_REQUEST) ++ { ++ struct recv_buf *precvbuf; ++#ifdef CONFIG_USING_CMD52_READ_INT ++ u32 hisr; ++ u8 data[4]; ++ ++ //DBG_8192C("%s: RX Request, size=%d\n", __func__, phal->SdioRxFIFOSize); ++ pHalData->sdio_hisr ^= SDIO_HISR_RX_REQUEST; ++ ++#ifdef CONFIG_MAC_LOOPBACK_DRIVER ++ sd_recv_loopback(padapter, pHalData->SdioRxFIFOSize); ++#else ++ _sdio_local_read(padapter, SDIO_REG_RX0_REQ_LEN, 4, data); ++ pHalData->SdioRxFIFOSize = le16_to_cpu(*(u16*)data); ++ ++ do { ++ //pHalData->SdioRxFIFOSize = SdioLocalCmd52Read2Byte(padapter, SDIO_REG_RX0_REQ_LEN); ++ ++ if(pHalData->SdioRxFIFOSize == 0){ ++ _sdio_local_read(padapter, SDIO_REG_RX0_REQ_LEN, 4, data); ++ pHalData->SdioRxFIFOSize = le16_to_cpu(*(u16*)data); ++ } ++ ++ if(pHalData->SdioRxFIFOSize != 0) ++ { ++ precvbuf = sd_recv_rxfifo(padapter, pHalData->SdioRxFIFOSize); ++ ++ pHalData->SdioRxFIFOSize = 0; ++ ++ if (precvbuf) ++ sd_rxhandler(padapter, precvbuf); ++ else ++ break; ++ } ++ else ++ { ++ //DBG_871X("%s, WARNING!!, SdioRxFIFOSize = 0!!\n", __func__); ++ break; ++ } ++ ++#ifdef CONFIG_SDIO_DISABLE_RXFIFO_POLLING_LOOP ++ } while (0); ++#else ++ } while (1); ++ ++#endif //CONFIG_SDIO_DISABLE_RXFIFO_POLLING_LOOP ++#endif //CONFIG_MAC_LOOPBACK_DRIVER ++#else //!CONFIG_USING_CMD52_READ_INT ++ ++ //DBG_8192C("%s: RX Request, size=%d\n", __func__, phal->SdioRxFIFOSize); ++ pHalData->sdio_hisr ^= SDIO_HISR_RX_REQUEST; ++#ifdef CONFIG_MAC_LOOPBACK_DRIVER ++ sd_recv_loopback(padapter, pHalData->SdioRxFIFOSize); ++#else ++ do { ++ //Sometimes rx length will be zero. driver need to use cmd53 read again. ++ if(pHalData->SdioRxFIFOSize == 0) ++ { ++ u8 data[4]; ++ ++ _sdio_local_read(padapter, SDIO_REG_RX0_REQ_LEN, 4, data); ++ ++ pHalData->SdioRxFIFOSize = le16_to_cpu(*(u16*)data); ++ } ++ ++ if(pHalData->SdioRxFIFOSize) ++ { ++ precvbuf = sd_recv_rxfifo(padapter, pHalData->SdioRxFIFOSize); ++ ++ pHalData->SdioRxFIFOSize = 0; ++ ++ if (precvbuf) ++ sd_rxhandler(padapter, precvbuf); ++ else ++ break; ++ } ++ else{ ++ ++ break; ++ } ++#ifdef CONFIG_SDIO_DISABLE_RXFIFO_POLLING_LOOP ++ } while (0); ++#else ++ } while (1); ++#endif //CONFIG_SDIO_DISABLE_RXFIFO_POLLING_LOOP ++#endif //CONFIG_MAC_LOOPBACK_DRIVER ++#endif //CONFIG_USING_CMD52_READ_INT ++ } ++} ++ ++void sd_int_hdl(PADAPTER padapter) ++{ ++ u8 data[6]; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ if ((padapter->bDriverStopped == _TRUE) || ++ (padapter->bSurpriseRemoved == _TRUE)) ++ return; ++ ++#ifdef CONFIG_USING_CMD52_READ_INT ++ pHalData->sdio_hisr = 0; ++ //ReadInterrupt8188ESdio(padapter, &pHalData->sdio_hisr); ++ pHalData->sdio_hisr = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_HISR); ++#else //CONFIG_USING_CMD52_READ_INT ++ _sdio_local_read(padapter, SDIO_REG_HISR, 6, data); ++ pHalData->sdio_hisr = le32_to_cpu(*(u32*)data); ++ pHalData->SdioRxFIFOSize = le16_to_cpu(*(u16*)&data[4]); ++#endif ++ ++ if (pHalData->sdio_hisr & pHalData->sdio_himr) ++ { ++ u32 v32; ++ ++ pHalData->sdio_hisr &= pHalData->sdio_himr; ++ ++ // clear HISR ++ v32 = pHalData->sdio_hisr & MASK_SDIO_HISR_CLEAR; ++ if (v32) { ++#ifdef CONFIG_USING_CMD52_READ_INT ++ SdioLocalCmd52Write4Byte(padapter, SDIO_REG_HISR, v32); ++#else //CONFIG_USING_CMD52_READ_INT ++ v32 = cpu_to_le32(v32); ++ _sdio_local_write(padapter, SDIO_REG_HISR, 4, (u8*)&v32); ++#endif ++ } ++ ++ sd_int_dpc(padapter); ++ } ++ else ++ { ++ RT_TRACE(_module_hci_ops_c_, _drv_err_, ++ ("%s: HISR(0x%08x) and HIMR(0x%08x) not match!\n", ++ __FUNCTION__, pHalData->sdio_hisr, pHalData->sdio_himr)); ++ } ++ ++} ++ ++// ++// Description: ++// Query SDIO Local register to query current the number of Free TxPacketBuffer page. ++// ++// Assumption: ++// 1. Running at PASSIVE_LEVEL ++// 2. RT_TX_SPINLOCK is NOT acquired. ++// ++// Created by Roger, 2011.01.28. ++// ++u8 HalQueryTxBufferStatus8189ESdio(PADAPTER padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ u32 NumOfFreePage; ++// _irqL irql; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ NumOfFreePage = SdioLocalCmd53Read4Byte(padapter, SDIO_REG_FREE_TXPG); ++ ++// _enter_critical_bh(&phal->SdioTxFIFOFreePageLock, &irql); ++ _rtw_memcpy(pHalData->SdioTxFIFOFreePage, &NumOfFreePage, 4); ++ RT_TRACE(_module_hci_ops_c_, _drv_notice_, ++ ("%s: Free page for HIQ(%#x),MIDQ(%#x),LOWQ(%#x),PUBQ(%#x)\n", ++ __FUNCTION__, ++ pHalData->SdioTxFIFOFreePage[HI_QUEUE_IDX], ++ pHalData->SdioTxFIFOFreePage[MID_QUEUE_IDX], ++ pHalData->SdioTxFIFOFreePage[LOW_QUEUE_IDX], ++ pHalData->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX])); ++// _exit_critical_bh(&phal->SdioTxFIFOFreePageLock, &irql); ++ ++ return _TRUE; ++} ++ ++#ifdef CONFIG_WOWLAN ++u8 RecvOnePkt(PADAPTER padapter, u32 size) ++{ ++ struct recv_buf *precvbuf; ++ struct dvobj_priv *psddev; ++ PSDIO_DATA psdio_data; ++ struct sdio_func *func; ++ ++ u8 res = _FALSE; ++ ++ DBG_8192C("+%s: size: %d+\n", __func__, size); ++ ++ if (padapter == NULL) { ++ DBG_8192C(KERN_ERR "%s: padapter is NULL!\n", __func__); ++ return _FALSE; ++ } ++ ++ psddev = padapter->dvobj; ++ psdio_data = &psddev->intf_data; ++ func = psdio_data->func; ++ ++ if(size) { ++ sdio_claim_host(func); ++ precvbuf = sd_recv_rxfifo(padapter, size); ++ ++ if (precvbuf) { ++ //printk("Completed Recv One Pkt.\n"); ++ sd_rxhandler(padapter, precvbuf); ++ res = _TRUE; ++ }else{ ++ res = _FALSE; ++ } ++ sdio_release_host(func); ++ } ++ DBG_8192C("-%s-\n", __func__); ++ return res; ++} ++#endif //CONFIG_WOWLAN +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/usb/rtl8188eu_led.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/usb/rtl8188eu_led.c +new file mode 100644 +index 00000000..712965a8 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/usb/rtl8188eu_led.c +@@ -0,0 +1,170 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++ ++//================================================================================ ++// LED object. ++//================================================================================ ++ ++ ++//================================================================================ ++// Prototype of protected function. ++//================================================================================ ++ ++ ++//================================================================================ ++// LED_819xUsb routines. ++//================================================================================ ++ ++// ++// Description: ++// Turn on LED according to LedPin specified. ++// ++void ++SwLedOn( ++ _adapter *padapter, ++ PLED_871x pLed ++) ++{ ++ u8 LedCfg; ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ if( (padapter->bSurpriseRemoved == _TRUE) || ( padapter->bDriverStopped == _TRUE)) ++ { ++ return; ++ } ++ ++ LedCfg = rtw_read8(padapter, REG_LEDCFG2); ++ switch(pLed->LedPin) ++ { ++ case LED_PIN_LED0: ++ rtw_write8(padapter, REG_LEDCFG2, (LedCfg&0xf0)|BIT5|BIT6); // SW control led0 on. ++ break; ++ ++ case LED_PIN_LED1: ++ rtw_write8(padapter, REG_LEDCFG2, (LedCfg&0x0f)|BIT5); // SW control led1 on. ++ break; ++ ++ default: ++ break; ++ } ++ ++ pLed->bLedOn = _TRUE; ++} ++ ++ ++// ++// Description: ++// Turn off LED according to LedPin specified. ++// ++void ++SwLedOff( ++ _adapter *padapter, ++ PLED_871x pLed ++) ++{ ++ u8 LedCfg; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ if((padapter->bSurpriseRemoved == _TRUE) || ( padapter->bDriverStopped == _TRUE)) ++ { ++ goto exit; ++ } ++ ++ ++ LedCfg = rtw_read8(padapter, REG_LEDCFG2);//0x4E ++ ++ switch(pLed->LedPin) ++ { ++ case LED_PIN_LED0: ++ if(pHalData->bLedOpenDrain == _TRUE) // Open-drain arrangement for controlling the LED) ++ { ++ LedCfg &= 0x90; // Set to software control. ++ rtw_write8(padapter, REG_LEDCFG2, (LedCfg|BIT3)); ++ LedCfg = rtw_read8(padapter, REG_MAC_PINMUX_CFG); ++ LedCfg &= 0xFE; ++ rtw_write8(padapter, REG_MAC_PINMUX_CFG, LedCfg); ++ } ++ else ++ { ++ rtw_write8(padapter, REG_LEDCFG2, (LedCfg|BIT3|BIT5|BIT6)); ++ } ++ break; ++ ++ case LED_PIN_LED1: ++ LedCfg &= 0x0f; // Set to software control. ++ rtw_write8(padapter, REG_LEDCFG2, (LedCfg|BIT3)); ++ break; ++ ++ default: ++ break; ++ } ++exit: ++ pLed->bLedOn = _FALSE; ++ ++} ++ ++//================================================================================ ++// Interface to manipulate LED objects. ++//================================================================================ ++ ++ ++//================================================================================ ++// Default LED behavior. ++//================================================================================ ++ ++// ++// Description: ++// Initialize all LED_871x objects. ++// ++void ++rtl8188eu_InitSwLeds( ++ _adapter *padapter ++ ) ++{ ++ struct led_priv *pledpriv = &(padapter->ledpriv); ++ ++ pledpriv->LedControlHandler = LedControl871x; ++ ++ InitLed871x(padapter, &(pledpriv->SwLed0), LED_PIN_LED0); ++ ++ InitLed871x(padapter,&(pledpriv->SwLed1), LED_PIN_LED1); ++} ++ ++ ++// ++// Description: ++// DeInitialize all LED_819xUsb objects. ++// ++void ++rtl8188eu_DeInitSwLeds( ++ _adapter *padapter ++ ) ++{ ++ struct led_priv *ledpriv = &(padapter->ledpriv); ++ ++ DeInitLed871x( &(ledpriv->SwLed0) ); ++ DeInitLed871x( &(ledpriv->SwLed1) ); ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/usb/rtl8188eu_recv.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/usb/rtl8188eu_recv.c +new file mode 100644 +index 00000000..db833e2b +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/usb/rtl8188eu_recv.c +@@ -0,0 +1,234 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTL8188EU_RECV_C_ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#if defined (PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) ++ ++#error "Shall be Linux or Windows, but not both!\n" ++ ++#endif ++ ++#include ++#include ++ ++#include ++ ++ ++void rtl8188eu_init_recvbuf(_adapter *padapter, struct recv_buf *precvbuf) ++{ ++ ++ precvbuf->transfer_len = 0; ++ ++ precvbuf->len = 0; ++ ++ precvbuf->ref_cnt = 0; ++ ++ if(precvbuf->pbuf) ++ { ++ precvbuf->pdata = precvbuf->phead = precvbuf->ptail = precvbuf->pbuf; ++ precvbuf->pend = precvbuf->pdata + MAX_RECVBUF_SZ; ++ } ++ ++} ++ ++int rtl8188eu_init_recv_priv(_adapter *padapter) ++{ ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ int i, res = _SUCCESS; ++ struct recv_buf *precvbuf; ++ ++#ifdef CONFIG_RECV_THREAD_MODE ++ _rtw_init_sema(&precvpriv->recv_sema, 0);//will be removed ++ _rtw_init_sema(&precvpriv->terminate_recvthread_sema, 0);//will be removed ++#endif ++ ++#ifdef PLATFORM_LINUX ++ tasklet_init(&precvpriv->recv_tasklet, ++ (void(*)(unsigned long))rtl8188eu_recv_tasklet, ++ (unsigned long)padapter); ++#endif ++ ++#ifdef CONFIG_USB_INTERRUPT_IN_PIPE ++#ifdef PLATFORM_LINUX ++ precvpriv->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); ++ if(precvpriv->int_in_urb == NULL){ ++ res= _FAIL; ++ DBG_8192C("alloc_urb for interrupt in endpoint fail !!!!\n"); ++ goto exit; ++ } ++#endif ++ precvpriv->int_in_buf = rtw_zmalloc(INTERRUPT_MSG_FORMAT_LEN); ++ if(precvpriv->int_in_buf == NULL){ ++ res= _FAIL; ++ DBG_8192C("alloc_mem for interrupt in endpoint fail !!!!\n"); ++ goto exit; ++ } ++#endif ++ ++ //init recv_buf ++ _rtw_init_queue(&precvpriv->free_recv_buf_queue); ++ ++#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX ++ _rtw_init_queue(&precvpriv->recv_buf_pending_queue); ++#endif // CONFIG_USE_USB_BUFFER_ALLOC_RX ++ ++ precvpriv->pallocated_recv_buf = rtw_zmalloc(NR_RECVBUFF *sizeof(struct recv_buf) + 4); ++ if(precvpriv->pallocated_recv_buf==NULL){ ++ res= _FAIL; ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("alloc recv_buf fail!\n")); ++ goto exit; ++ } ++ _rtw_memset(precvpriv->pallocated_recv_buf, 0, NR_RECVBUFF *sizeof(struct recv_buf) + 4); ++ ++ precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_recv_buf), 4); ++ //precvpriv->precv_buf = precvpriv->pallocated_recv_buf + 4 - ++ // ((uint) (precvpriv->pallocated_recv_buf) &(4-1)); ++ ++ ++ precvbuf = (struct recv_buf*)precvpriv->precv_buf; ++ ++ for(i=0; i < NR_RECVBUFF ; i++) ++ { ++ _rtw_init_listhead(&precvbuf->list); ++ ++ _rtw_spinlock_init(&precvbuf->recvbuf_lock); ++ ++ precvbuf->alloc_sz = MAX_RECVBUF_SZ; ++ ++ res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf); ++ if(res==_FAIL) ++ break; ++ ++ precvbuf->ref_cnt = 0; ++ precvbuf->adapter =padapter; ++ ++ ++ //rtw_list_insert_tail(&precvbuf->list, &(precvpriv->free_recv_buf_queue.queue)); ++ ++ precvbuf++; ++ ++ } ++ ++ precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF; ++ ++#ifdef PLATFORM_LINUX ++ ++ skb_queue_head_init(&precvpriv->rx_skb_queue); ++ ++#ifdef CONFIG_PREALLOC_RECV_SKB ++ { ++ int i; ++ SIZE_PTR tmpaddr=0; ++ SIZE_PTR alignment=0; ++ struct sk_buff *pskb=NULL; ++ ++ skb_queue_head_init(&precvpriv->free_recv_skb_queue); ++ ++ for(i=0; idev = padapter->pnetdev; ++ ++ tmpaddr = (SIZE_PTR)pskb->data; ++ alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); ++ skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment)); ++ ++ skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); ++ } ++ ++ pskb=NULL; ++ ++ } ++ } ++#endif ++ ++#endif ++ ++exit: ++ ++ return res; ++ ++} ++ ++void rtl8188eu_free_recv_priv (_adapter *padapter) ++{ ++ int i; ++ struct recv_buf *precvbuf; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++ precvbuf = (struct recv_buf *)precvpriv->precv_buf; ++ ++ for(i=0; i < NR_RECVBUFF ; i++) ++ { ++ rtw_os_recvbuf_resource_free(padapter, precvbuf); ++ precvbuf++; ++ } ++ ++ if(precvpriv->pallocated_recv_buf) ++ rtw_mfree(precvpriv->pallocated_recv_buf, NR_RECVBUFF *sizeof(struct recv_buf) + 4); ++ ++#ifdef CONFIG_USB_INTERRUPT_IN_PIPE ++#ifdef PLATFORM_LINUX ++ if(precvpriv->int_in_urb) ++ { ++ usb_free_urb(precvpriv->int_in_urb); ++ } ++#endif//PLATFORM_LINUX ++ ++ if(precvpriv->int_in_buf) ++ rtw_mfree(precvpriv->int_in_buf, INTERRUPT_MSG_FORMAT_LEN); ++#endif//CONFIG_USB_INTERRUPT_IN_PIPE ++ ++#ifdef PLATFORM_LINUX ++ ++ if (skb_queue_len(&precvpriv->rx_skb_queue)) { ++ DBG_8192C(KERN_WARNING "rx_skb_queue not empty\n"); ++ } ++ ++ rtw_skb_queue_purge(&precvpriv->rx_skb_queue); ++ ++#ifdef CONFIG_PREALLOC_RECV_SKB ++ ++ if (skb_queue_len(&precvpriv->free_recv_skb_queue)) { ++ DBG_8192C(KERN_WARNING "free_recv_skb_queue not empty, %d\n", skb_queue_len(&precvpriv->free_recv_skb_queue)); ++ } ++ ++ rtw_skb_queue_purge(&precvpriv->free_recv_skb_queue); ++ ++#endif ++ ++#endif ++ ++} ++ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/usb/rtl8188eu_xmit.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/usb/rtl8188eu_xmit.c +new file mode 100644 +index 00000000..5a23b830 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/usb/rtl8188eu_xmit.c +@@ -0,0 +1,1370 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RTL8188E_XMIT_C_ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if defined (PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) ++#error "Shall be Linux or Windows, but not both!\n" ++#endif ++ ++s32 rtl8188eu_init_xmit_priv(_adapter *padapter) ++{ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++#ifdef PLATFORM_LINUX ++ tasklet_init(&pxmitpriv->xmit_tasklet, ++ (void(*)(unsigned long))rtl8188eu_xmit_tasklet, ++ (unsigned long)padapter); ++#endif ++#ifdef CONFIG_TX_EARLY_MODE ++ pHalData->bEarlyModeEnable = padapter->registrypriv.early_mode; ++#endif ++ ++ return _SUCCESS; ++} ++ ++void rtl8188eu_free_xmit_priv(_adapter *padapter) ++{ ++} ++ ++u8 urb_zero_packet_chk(_adapter *padapter, int sz) ++{ ++#if 1 ++ u8 blnSetTxDescOffset; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ blnSetTxDescOffset = (((sz + TXDESC_SIZE) % pHalData->UsbBulkOutSize) ==0)?1:0; ++ ++#else ++ ++ struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); ++ if ( pdvobj->ishighspeed ) ++ { ++ if ( ( (sz + TXDESC_SIZE) % 512 ) == 0 ) { ++ blnSetTxDescOffset = 1; ++ } else { ++ blnSetTxDescOffset = 0; ++ } ++ } ++ else ++ { ++ if ( ( (sz + TXDESC_SIZE) % 64 ) == 0 ) { ++ blnSetTxDescOffset = 1; ++ } else { ++ blnSetTxDescOffset = 0; ++ } ++ } ++#endif ++ return blnSetTxDescOffset; ++ ++} ++ ++void rtl8188eu_cal_txdesc_chksum(struct tx_desc *ptxdesc) ++{ ++ u16 *usPtr = (u16*)ptxdesc; ++ u32 count = 16; // (32 bytes / 2 bytes per XOR) => 16 times ++ u32 index; ++ u16 checksum = 0; ++ ++ //Clear first ++ ptxdesc->txdw7 &= cpu_to_le32(0xffff0000); ++ ++ for(index = 0 ; index < count ; index++){ ++ checksum = checksum ^ le16_to_cpu(*(usPtr + index)); ++ } ++ ++ ptxdesc->txdw7 |= cpu_to_le32(0x0000ffff&checksum); ++ ++} ++// ++// Description: In normal chip, we should send some packet to Hw which will be used by Fw ++// in FW LPS mode. The function is to fill the Tx descriptor of this packets, then ++// Fw can tell Hw to send these packet derectly. ++// ++void rtl8188e_fill_fake_txdesc( ++ PADAPTER padapter, ++ u8* pDesc, ++ u32 BufferLen, ++ u8 IsPsPoll, ++ u8 IsBTQosNull) ++{ ++ struct tx_desc *ptxdesc; ++ ++ ++ // Clear all status ++ ptxdesc = (struct tx_desc*)pDesc; ++ _rtw_memset(pDesc, 0, TXDESC_SIZE); ++ ++ //offset 0 ++ ptxdesc->txdw0 |= cpu_to_le32( OWN | FSG | LSG); //own, bFirstSeg, bLastSeg; ++ ++ ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<txdw0 |= cpu_to_le32(BufferLen&0x0000ffff); // Buffer size + command header ++ ++ //offset 4 ++ ptxdesc->txdw1 |= cpu_to_le32((QSLT_MGNT<txdw1 |= cpu_to_le32(NAVUSEHDR); ++ } ++ else ++ { ++ ptxdesc->txdw4 |= cpu_to_le32(BIT(7)); // Hw set sequence number ++ ptxdesc->txdw3 |= cpu_to_le32((8 <<28)); //set bit3 to 1. Suugested by TimChen. 2009.12.29. ++ } ++ ++ if (_TRUE == IsBTQosNull) ++ { ++ ptxdesc->txdw2 |= cpu_to_le32(BIT(23)); // BT NULL ++ } ++ ++ //offset 16 ++ ptxdesc->txdw4 |= cpu_to_le32(BIT(8));//driver uses rate ++ ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) ++ // USB interface drop packet if the checksum of descriptor isn't correct. ++ // Using this checksum can let hardware recovery from packet bulk out error (e.g. Cancel URC, Bulk out error.). ++ rtl8188eu_cal_txdesc_chksum(ptxdesc); ++#endif ++} ++ ++void fill_txdesc_sectype(struct pkt_attrib *pattrib, struct tx_desc *ptxdesc) ++{ ++ if ((pattrib->encrypt > 0) && !pattrib->bswenc) ++ { ++ switch (pattrib->encrypt) ++ { ++ //SEC_TYPE : 0:NO_ENC,1:WEP40/TKIP,2:WAPI,3:AES ++ case _WEP40_: ++ case _WEP104_: ++ ptxdesc->txdw1 |= cpu_to_le32((0x01<txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT); ++ break; ++ case _TKIP_: ++ case _TKIP_WTMIC_: ++ ptxdesc->txdw1 |= cpu_to_le32((0x01<txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT); ++ break; ++#ifdef CONFIG_WAPI_SUPPORT ++ case _SMS4_: ++ ptxdesc->txdw1 |= cpu_to_le32((0x02<txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT); ++ break; ++#endif ++ case _AES_: ++ ptxdesc->txdw1 |= cpu_to_le32((0x03<txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT); ++ break; ++ case _NO_PRIVACY_: ++ default: ++ break; ++ ++ } ++ ++ } ++ ++} ++ ++void fill_txdesc_vcs(struct pkt_attrib *pattrib, u32 *pdw) ++{ ++ //DBG_8192C("cvs_mode=%d\n", pattrib->vcs_mode); ++ ++ switch(pattrib->vcs_mode) ++ { ++ case RTS_CTS: ++ *pdw |= cpu_to_le32(RTS_EN); ++ break; ++ case CTS_TO_SELF: ++ *pdw |= cpu_to_le32(CTS_2_SELF); ++ break; ++ case NONE_VCS: ++ default: ++ break; ++ } ++ ++ if(pattrib->vcs_mode) { ++ *pdw |= cpu_to_le32(HW_RTS_EN); ++ ++ // Set RTS BW ++ if(pattrib->ht_en) ++ { ++ *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40)? cpu_to_le32(BIT(27)):0; ++ ++ if(pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) ++ *pdw |= cpu_to_le32((0x01<<28)&0x30000000); ++ else if(pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) ++ *pdw |= cpu_to_le32((0x02<<28)&0x30000000); ++ else if(pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) ++ *pdw |= 0; ++ else ++ *pdw |= cpu_to_le32((0x03<<28)&0x30000000); ++ } ++ } ++} ++ ++void fill_txdesc_phy(struct pkt_attrib *pattrib, u32 *pdw) ++{ ++ //DBG_8192C("bwmode=%d, ch_off=%d\n", pattrib->bwmode, pattrib->ch_offset); ++ ++ if(pattrib->ht_en) ++ { ++ *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40)? cpu_to_le32(BIT(25)):0; ++ ++ if(pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) ++ *pdw |= cpu_to_le32((0x01<ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) ++ *pdw |= cpu_to_le32((0x02<ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) ++ *pdw |= 0; ++ else ++ *pdw |= cpu_to_le32((0x03<padapter; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ //struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ struct tx_desc *ptxdesc = (struct tx_desc *)pmem; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ sint bmcst = IS_MCAST(pattrib->ra); ++ ++#ifdef CONFIG_P2P ++ struct wifidirect_info* pwdinfo = &padapter->wdinfo; ++#endif //CONFIG_P2P ++ ++#ifndef CONFIG_USE_USB_BUFFER_ALLOC_TX ++if (padapter->registrypriv.mp_mode == 0) ++{ ++ if((!bagg_pkt) &&(urb_zero_packet_chk(padapter, sz)==0))//(sz %512) != 0 ++ //if((!bagg_pkt) &&(rtw_usb_bulk_size_boundary(padapter,TXDESC_SIZE+sz)==_FALSE)) ++ { ++ ptxdesc = (struct tx_desc *)(pmem+PACKET_OFFSET_SZ); ++ //DBG_8192C("==> non-agg-pkt,shift pointer...\n"); ++ pull = 1; ++ } ++} ++#endif // CONFIG_USE_USB_BUFFER_ALLOC_TX ++ ++ _rtw_memset(ptxdesc, 0, sizeof(struct tx_desc)); ++ ++ //4 offset 0 ++ ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); ++ //DBG_8192C("%s==> pkt_len=%d,bagg_pkt=%02x\n",__FUNCTION__,sz,bagg_pkt); ++ ptxdesc->txdw0 |= cpu_to_le32(sz & 0x0000ffff);//update TXPKTSIZE ++ ++ offset = TXDESC_SIZE + OFFSET_SZ; ++ ++ #ifdef CONFIG_TX_EARLY_MODE ++ if(bagg_pkt){ ++ offset += EARLY_MODE_INFO_SIZE ;//0x28 ++ } ++ #endif ++ //DBG_8192C("%s==>offset(0x%02x) \n",__FUNCTION__,offset); ++ ptxdesc->txdw0 |= cpu_to_le32(((offset) << OFFSET_SHT) & 0x00ff0000);//32 bytes for TX Desc ++ ++ if (bmcst) ptxdesc->txdw0 |= cpu_to_le32(BMC); ++ ++#ifndef CONFIG_USE_USB_BUFFER_ALLOC_TX ++if (padapter->registrypriv.mp_mode == 0) ++{ ++ if(!bagg_pkt){ ++ if((pull) && (pxmitframe->pkt_offset>0)) { ++ pxmitframe->pkt_offset = pxmitframe->pkt_offset -1; ++ } ++ } ++} ++#endif ++ //DBG_8192C("%s, pkt_offset=0x%02x\n",__FUNCTION__,pxmitframe->pkt_offset); ++ ++ // pkt_offset, unit:8 bytes padding ++ if (pxmitframe->pkt_offset > 0) ++ ptxdesc->txdw1 |= cpu_to_le32((pxmitframe->pkt_offset << 26) & 0x7c000000); ++ ++ //driver uses rate ++ ptxdesc->txdw4 |= cpu_to_le32(USERATE);//rate control always by driver ++ ++ if((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) ++ { ++ //DBG_8192C("pxmitframe->frame_tag == DATA_FRAMETAG\n"); ++ ++ //offset 4 ++ ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id&0x3F); ++ ++ qsel = (uint)(pattrib->qsel & 0x0000001f); ++ //DBG_8192C("==> macid(%d) qsel:0x%02x \n",pattrib->mac_id,qsel); ++ ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); ++ ++ ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid<< RATE_ID_SHT) & 0x000F0000); ++ ++ fill_txdesc_sectype(pattrib, ptxdesc); ++ ++ if(pattrib->ampdu_en==_TRUE){ ++ ptxdesc->txdw2 |= cpu_to_le32(AGG_EN);//AGG EN ++ ++ //SET_TX_DESC_MAX_AGG_NUM_88E(pDesc, 0x1F); ++ //SET_TX_DESC_MCSG1_MAX_LEN_88E(pDesc, 0x6); ++ //SET_TX_DESC_MCSG2_MAX_LEN_88E(pDesc, 0x6); ++ //SET_TX_DESC_MCSG3_MAX_LEN_88E(pDesc, 0x6); ++ //SET_TX_DESC_MCS7_SGI_MAX_LEN_88E(pDesc, 0x6); ++ ptxdesc->txdw6 = 0x6666f800; ++ } ++ else{ ++ ptxdesc->txdw2 |= cpu_to_le32(AGG_BK);//AGG BK ++ } ++ ++ //offset 8 ++ ++ ++ //offset 12 ++ ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<< SEQ_SHT)&0x0FFF0000); ++ ++ ++ //offset 16 , offset 20 ++ if (pattrib->qos_en) ++ ptxdesc->txdw4 |= cpu_to_le32(QOS);//QoS ++ ++ //offset 20 ++ #ifdef CONFIG_USB_TX_AGGREGATION ++ if (pxmitframe->agg_num > 1){ ++ //DBG_8192C("%s agg_num:%d\n",__FUNCTION__,pxmitframe->agg_num ); ++ ptxdesc->txdw5 |= cpu_to_le32((pxmitframe->agg_num << USB_TXAGG_NUM_SHT) & 0xFF000000); ++ } ++ #endif ++ ++ if ((pattrib->ether_type != 0x888e) && ++ (pattrib->ether_type != 0x0806) && ++ (pattrib->ether_type != 0x88b4) && ++ (pattrib->dhcp_pkt != 1)) ++ { ++ //Non EAP & ARP & DHCP type data packet ++ ++ fill_txdesc_vcs(pattrib, &ptxdesc->txdw4); ++ fill_txdesc_phy(pattrib, &ptxdesc->txdw4); ++ ++ ptxdesc->txdw4 |= cpu_to_le32(0x00000008);//RTS Rate=24M ++ ptxdesc->txdw5 |= cpu_to_le32(0x0001ff00);//DATA/RTS Rate FB LMT ++ ++ #if (RATE_ADAPTIVE_SUPPORT == 1) ++ if(pattrib->ht_en){ ++ if( ODM_RA_GetShortGI_8188E(&pHalData->odmpriv,pattrib->mac_id)) ++ ptxdesc->txdw5 |= cpu_to_le32(SGI);//SGI ++ } ++ ++ data_rate =ODM_RA_GetDecisionRate_8188E(&pHalData->odmpriv,pattrib->mac_id); ++ //for debug ++ #if 1 ++ if(padapter->fix_rate!= 0xFF){ ++ ++ data_rate = padapter->fix_rate; ++ ptxdesc->txdw4 |= cpu_to_le32(DISDATAFB); ++ //printk("==> fix data_rate:0x%02x\n",data_rate); ++ } ++ #endif ++ ++ ptxdesc->txdw5 |= cpu_to_le32(data_rate & 0x3F); ++ ++ #if (POWER_TRAINING_ACTIVE==1) ++ pwr_status = ODM_RA_GetHwPwrStatus_8188E(&pHalData->odmpriv,pattrib->mac_id); ++ ptxdesc->txdw4 |=cpu_to_le32( (pwr_status & 0x7)<< PWR_STATUS_SHT); ++ #endif //(POWER_TRAINING_ACTIVE==1) ++ #else//if (RATE_ADAPTIVE_SUPPORT == 1) ++ ++ if(pattrib->ht_en) ++ ptxdesc->txdw5 |= cpu_to_le32(SGI);//SGI ++ ++ data_rate = 0x13; //default rate: MCS7 ++ if(padapter->fix_rate!= 0xFF){//rate control by iwpriv ++ data_rate = padapter->fix_rate; ++ ptxdesc->txdw4 | cpu_to_le32(DISDATAFB); ++ } ++ ptxdesc->txdw5 |= cpu_to_le32(data_rate & 0x3F); ++ ++ #endif//if (RATE_ADAPTIVE_SUPPORT == 1) ++ ++ } ++ else ++ { ++ // EAP data packet and ARP packet and DHCP. ++ // Use the 1M data rate to send the EAP/ARP packet. ++ // This will maybe make the handshake smooth. ++ ++ ptxdesc->txdw2 |= cpu_to_le32(AGG_BK);//AGG BK ++ ++ if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT) ++ ptxdesc->txdw4 |= cpu_to_le32(BIT(24));// DATA_SHORT ++ ++ ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate)); ++ } ++ ++#ifdef CONFIG_TCP_CSUM_OFFLOAD_TX ++ //offset 24 ++ if ( pattrib->hw_tcp_csum == 1 ) { ++ // ptxdesc->txdw6 = 0; // clear TCP_CHECKSUM and IP_CHECKSUM. It's zero already!! ++ u8 ip_hdr_offset = 32 + pattrib->hdrlen + pattrib->iv_len + 8; ++ ptxdesc->txdw7 = (1 << 31) | (ip_hdr_offset << 16); ++ DBG_8192C("ptxdesc->txdw7 = %08x\n", ptxdesc->txdw7); ++ } ++#endif ++ } ++ else if((pxmitframe->frame_tag&0x0f)== MGNT_FRAMETAG) ++ { ++ //DBG_8192C("pxmitframe->frame_tag == MGNT_FRAMETAG\n"); ++ ++ //offset 4 ++ ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id&0x3f); ++ ++ qsel = (uint)(pattrib->qsel&0x0000001f); ++ ptxdesc->txdw1 |= cpu_to_le32((qsel<txdw1 |= cpu_to_le32((pattrib->raid<< RATE_ID_SHT) & 0x000f0000); ++ ++ //fill_txdesc_sectype(pattrib, ptxdesc); ++ ++ //offset 8 ++#ifdef CONFIG_XMIT_ACK ++ //CCX-TXRPT ack for xmit mgmt frames. ++ if (pxmitframe->ack_report) { ++ #ifdef DBG_CCX ++ static u16 ccx_sw = 0x123; ++ ptxdesc->txdw7 |= cpu_to_le32(((ccx_sw)<<16)&0x0fff0000); ++ DBG_871X("%s set ccx, sw:0x%03x\n", __func__, ccx_sw); ++ ccx_sw = (ccx_sw+1)%0xfff; ++ #endif ++ ptxdesc->txdw2 |= cpu_to_le32(BIT(19)); ++ } ++#endif //CONFIG_XMIT_ACK ++ ++ //offset 12 ++ ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<txdw5 |= cpu_to_le32(RTY_LMT_EN);//retry limit enable ++ if(pattrib->retry_ctrl == _TRUE) ++ ptxdesc->txdw5 |= cpu_to_le32(0x00180000);//retry limit = 6 ++ else ++ ptxdesc->txdw5 |= cpu_to_le32(0x00300000);//retry limit = 12 ++ ++#ifdef CONFIG_INTEL_PROXIM ++ if((padapter->proximity.proxim_on==_TRUE)&&(pattrib->intel_proxim==_TRUE)){ ++ DBG_871X("\n %s pattrib->rate=%d\n",__FUNCTION__,pattrib->rate); ++ ptxdesc->txdw5 |= cpu_to_le32( pattrib->rate); ++ } ++ else ++#endif ++ { ++ ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate)); ++ } ++ } ++ else if((pxmitframe->frame_tag&0x0f) == TXAGG_FRAMETAG) ++ { ++ DBG_8192C("pxmitframe->frame_tag == TXAGG_FRAMETAG\n"); ++ } ++#ifdef CONFIG_MP_INCLUDED ++ else if(((pxmitframe->frame_tag&0x0f) == MP_FRAMETAG) && ++ (padapter->registrypriv.mp_mode == 1)) ++ { ++ fill_txdesc_for_mp(padapter, ptxdesc); ++ } ++#endif ++ else ++ { ++ DBG_8192C("pxmitframe->frame_tag = %d\n", pxmitframe->frame_tag); ++ ++ //offset 4 ++ ptxdesc->txdw1 |= cpu_to_le32((4)&0x3f);//CAM_ID(MAC_ID) ++ ++ ptxdesc->txdw1 |= cpu_to_le32((6<< RATE_ID_SHT) & 0x000f0000);//raid ++ ++ //offset 8 ++ ++ //offset 12 ++ ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate)); ++ } ++ ++ // 2009.11.05. tynli_test. Suggested by SD4 Filen for FW LPS. ++ // (1) The sequence number of each non-Qos frame / broadcast / multicast / ++ // mgnt frame should be controled by Hw because Fw will also send null data ++ // which we cannot control when Fw LPS enable. ++ // --> default enable non-Qos data sequense number. 2010.06.23. by tynli. ++ // (2) Enable HW SEQ control for beacon packet, because we use Hw beacon. ++ // (3) Use HW Qos SEQ to control the seq num of Ext port non-Qos packets. ++ // 2010.06.23. Added by tynli. ++ if(!pattrib->qos_en) ++ { ++ //ptxdesc->txdw4 |= cpu_to_le32(BIT(7)); // Hw set sequence number ++ //ptxdesc->txdw3 |= cpu_to_le32((8 <<28)); //set bit3 to 1. Suugested by TimChen. 2009.12.29. ++ ++ ptxdesc->txdw3 |= cpu_to_le32(EN_HWSEQ); // Hw set sequence number ++ ptxdesc->txdw4 |= cpu_to_le32(HW_SSN); // Hw set sequence number ++ ++ } ++ ++#ifdef CONFIG_HW_ANTENNA_DIVERSITY //CONFIG_ANTENNA_DIVERSITY ++ ODM_SetTxAntByTxInfo_88E(&pHalData->odmpriv, pmem, pattrib->mac_id); ++#endif ++ ++ rtl8188eu_cal_txdesc_chksum(ptxdesc); ++ _dbg_dump_tx_info(padapter,pxmitframe->frame_tag,ptxdesc); ++ return pull; ++ ++} ++ ++ ++#ifdef CONFIG_XMIT_THREAD_MODE ++/* ++ * Description ++ * Transmit xmitbuf to hardware tx fifo ++ * ++ * Return ++ * _SUCCESS ok ++ * _FAIL something error ++ */ ++s32 rtl8188eu_xmit_buf_handler(PADAPTER padapter) ++{ ++ //PHAL_DATA_TYPE phal; ++ struct xmit_priv *pxmitpriv; ++ struct xmit_buf *pxmitbuf; ++ s32 ret; ++ ++ ++ //phal = GET_HAL_DATA(padapter); ++ pxmitpriv = &padapter->xmitpriv; ++ ++ ret = _rtw_down_sema(&pxmitpriv->xmit_sema); ++ if (_FAIL == ret) { ++ RT_TRACE(_module_hal_xmit_c_, _drv_emerg_, ++ ("%s: down SdioXmitBufSema fail!\n", __FUNCTION__)); ++ return _FAIL; ++ } ++ ++ ret = (padapter->bDriverStopped == _TRUE) || (padapter->bSurpriseRemoved == _TRUE); ++ if (ret) { ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ++ ("%s: bDriverStopped(%d) bSurpriseRemoved(%d)!\n", ++ __FUNCTION__, padapter->bDriverStopped, padapter->bSurpriseRemoved)); ++ return _FAIL; ++ } ++ ++ if(check_pending_xmitbuf(pxmitpriv) == _FALSE) ++ return _SUCCESS; ++ ++#ifdef CONFIG_LPS_LCLK ++ ret = rtw_register_tx_alive(padapter); ++ if (ret != _SUCCESS) { ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ++ ("%s: wait to leave LPS_LCLK\n", __FUNCTION__)); ++ return _SUCCESS; ++ } ++#endif ++ ++ do { ++ pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv); ++ if (pxmitbuf == NULL) break; ++ ++ rtw_write_port(padapter, pxmitbuf->ff_hwaddr, pxmitbuf->len, (unsigned char*)pxmitbuf); ++ ++ } while (1); ++ ++#ifdef CONFIG_LPS_LCLK ++ rtw_unregister_tx_alive(padapter); ++#endif ++ ++ return _SUCCESS; ++} ++#endif ++ ++#ifdef CONFIG_IOL_IOREG_CFG_DBG ++#include ++#endif ++//for non-agg data frame or management frame ++static s32 rtw_dump_xframe(_adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ s32 ret = _SUCCESS; ++ s32 inner_ret = _SUCCESS; ++ int t, sz, w_sz, pull=0; ++ u8 *mem_addr; ++ u32 ff_hwaddr; ++ struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++#ifdef CONFIG_80211N_HT ++ if ((pxmitframe->frame_tag == DATA_FRAMETAG) && ++ (pxmitframe->attrib.ether_type != 0x0806) && ++ (pxmitframe->attrib.ether_type != 0x888e) && ++ (pxmitframe->attrib.ether_type != 0x88b4) && ++ (pxmitframe->attrib.dhcp_pkt != 1)) ++ { ++ rtw_issue_addbareq_cmd(padapter, pxmitframe); ++ } ++#endif //CONFIG_80211N_HT ++ mem_addr = pxmitframe->buf_addr; ++ ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("rtw_dump_xframe()\n")); ++ ++ for (t = 0; t < pattrib->nr_frags; t++) ++ { ++ if (inner_ret != _SUCCESS && ret == _SUCCESS) ++ ret = _FAIL; ++ ++ if (t != (pattrib->nr_frags - 1)) ++ { ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("pattrib->nr_frags=%d\n", pattrib->nr_frags)); ++ ++ sz = pxmitpriv->frag_len; ++ sz = sz - 4 - (psecuritypriv->sw_encrypt ? 0 : pattrib->icv_len); ++ } ++ else //no frag ++ { ++ sz = pattrib->last_txcmdsz; ++ } ++ ++ pull = update_txdesc(pxmitframe, mem_addr, sz, _FALSE); ++ ++ if(pull) ++ { ++ mem_addr += PACKET_OFFSET_SZ; //pull txdesc head ++ ++ //pxmitbuf ->pbuf = mem_addr; ++ pxmitframe->buf_addr = mem_addr; ++ ++ w_sz = sz + TXDESC_SIZE; ++ } ++ else ++ { ++ w_sz = sz + TXDESC_SIZE + PACKET_OFFSET_SZ; ++ } ++#ifdef CONFIG_IOL_IOREG_CFG_DBG ++ rtw_IOL_cmd_buf_dump(padapter,w_sz,pxmitframe->buf_addr); ++#endif ++ ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe); ++ ++#ifdef CONFIG_XMIT_THREAD_MODE ++ pxmitbuf->len = w_sz; ++ pxmitbuf->ff_hwaddr = ff_hwaddr; ++ enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf); ++#else ++ inner_ret = rtw_write_port(padapter, ff_hwaddr, w_sz, (unsigned char*)pxmitbuf); ++#endif ++ ++ rtw_count_tx_stats(padapter, pxmitframe, sz); ++ ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("rtw_write_port, w_sz=%d\n", w_sz)); ++ //DBG_8192C("rtw_write_port, w_sz=%d, sz=%d, txdesc_sz=%d, tid=%d\n", w_sz, sz, w_sz-sz, pattrib->priority); ++ ++ mem_addr += w_sz; ++ ++ mem_addr = (u8 *)RND4(((SIZE_PTR)(mem_addr))); ++ ++ } ++ ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ ++ if (ret != _SUCCESS) ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_UNKNOWN); ++ ++ return ret; ++} ++ ++#ifdef CONFIG_USB_TX_AGGREGATION ++static u32 xmitframe_need_length(struct xmit_frame *pxmitframe) ++{ ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ ++ u32 len = 0; ++ ++ // no consider fragement ++ len = pattrib->hdrlen + pattrib->iv_len + ++ SNAP_SIZE + sizeof(u16) + ++ pattrib->pktlen + ++ ((pattrib->bswenc) ? pattrib->icv_len : 0); ++ ++ if(pattrib->encrypt ==_TKIP_) ++ len += 8; ++ ++ return len; ++} ++ ++#define IDEA_CONDITION 1 // check all packets before enqueue ++s32 rtl8188eu_xmitframe_complete(_adapter *padapter, struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct xmit_frame *pxmitframe = NULL; ++ struct xmit_frame *pfirstframe = NULL; ++ ++ // aggregate variable ++ struct hw_xmit *phwxmit; ++ struct sta_info *psta = NULL; ++ struct tx_servq *ptxservq = NULL; ++ ++ _irqL irqL; ++ _list *xmitframe_plist = NULL, *xmitframe_phead = NULL; ++ ++ u32 pbuf; // next pkt address ++ u32 pbuf_tail; // last pkt tail ++ u32 len; // packet length, except TXDESC_SIZE and PKT_OFFSET ++ ++ u32 bulkSize = pHalData->UsbBulkOutSize; ++ u8 descCount; ++ u32 bulkPtr; ++ ++ // dump frame variable ++ u32 ff_hwaddr; ++ ++#ifndef IDEA_CONDITION ++ int res = _SUCCESS; ++#endif ++ ++ RT_TRACE(_module_rtl8192c_xmit_c_, _drv_info_, ("+xmitframe_complete\n")); ++ ++ ++ // check xmitbuffer is ok ++ if (pxmitbuf == NULL) { ++ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); ++ if (pxmitbuf == NULL){ ++ //DBG_871X("%s #1, connot alloc xmitbuf!!!! \n",__FUNCTION__); ++ return _FALSE; ++ } ++ } ++ ++//DBG_8192C("%s ===================================== \n",__FUNCTION__); ++ //3 1. pick up first frame ++ do { ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ ++ pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); ++ if (pxmitframe == NULL) { ++ // no more xmit frame, release xmit buffer ++ //DBG_8192C("no more xmit frame ,return\n"); ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ return _FALSE; ++ } ++ ++#ifndef IDEA_CONDITION ++ if (pxmitframe->frame_tag != DATA_FRAMETAG) { ++ RT_TRACE(_module_rtl8192c_xmit_c_, _drv_err_, ++ ("xmitframe_complete: frame tag(%d) is not DATA_FRAMETAG(%d)!\n", ++ pxmitframe->frame_tag, DATA_FRAMETAG)); ++// rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ continue; ++ } ++ ++ // TID 0~15 ++ if ((pxmitframe->attrib.priority < 0) || ++ (pxmitframe->attrib.priority > 15)) { ++ RT_TRACE(_module_rtl8192c_xmit_c_, _drv_err_, ++ ("xmitframe_complete: TID(%d) should be 0~15!\n", ++ pxmitframe->attrib.priority)); ++// rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ continue; ++ } ++#endif ++ //DBG_8192C("==> pxmitframe->attrib.priority:%d\n",pxmitframe->attrib.priority); ++ pxmitframe->pxmitbuf = pxmitbuf; ++ pxmitframe->buf_addr = pxmitbuf->pbuf; ++ pxmitbuf->priv_data = pxmitframe; ++ ++ pxmitframe->agg_num = 1; // alloc xmitframe should assign to 1. ++ #ifdef CONFIG_TX_EARLY_MODE ++ pxmitframe->pkt_offset = 2; // first frame of aggregation, reserve one offset for EM info ,another for usb bulk-out block check ++ #else ++ pxmitframe->pkt_offset = 1; // first frame of aggregation, reserve offset ++ #endif ++ ++ if (rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe) == _FALSE) { ++ DBG_871X("%s coalesce 1st xmitframe failed \n",__FUNCTION__); ++ continue; ++ } ++ ++ // always return ndis_packet after rtw_xmitframe_coalesce ++ rtw_os_xmit_complete(padapter, pxmitframe); ++ ++ break; ++ } while (1); ++ ++ //3 2. aggregate same priority and same DA(AP or STA) frames ++ pfirstframe = pxmitframe; ++ len = xmitframe_need_length(pfirstframe) + TXDESC_SIZE+(pfirstframe->pkt_offset*PACKET_OFFSET_SZ); ++ pbuf_tail = len; ++ pbuf = _RND8(pbuf_tail); ++ ++ // check pkt amount in one bulk ++ descCount = 0; ++ bulkPtr = bulkSize; ++ if (pbuf < bulkPtr) ++ descCount++; ++ else { ++ descCount = 0; ++ bulkPtr = ((pbuf / bulkSize) + 1) * bulkSize; // round to next bulkSize ++ } ++ ++ // dequeue same priority packet from station tx queue ++ //psta = pfirstframe->attrib.psta; ++ psta = rtw_get_stainfo(&padapter->stapriv, pfirstframe->attrib.ra); ++ if(pfirstframe->attrib.psta != psta){ ++ DBG_871X("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pfirstframe->attrib.psta, psta); ++ } ++ if (psta == NULL) { ++ DBG_8192C("rtw_xmit_classifier: psta == NULL\n"); ++ } ++ if(!(psta->state &_FW_LINKED)){ ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); ++ } ++ ++ switch (pfirstframe->attrib.priority) { ++ case 1: ++ case 2: ++ ptxservq = &(psta->sta_xmitpriv.bk_q); ++ phwxmit = pxmitpriv->hwxmits + 3; ++ break; ++ ++ case 4: ++ case 5: ++ ptxservq = &(psta->sta_xmitpriv.vi_q); ++ phwxmit = pxmitpriv->hwxmits + 1; ++ break; ++ ++ case 6: ++ case 7: ++ ptxservq = &(psta->sta_xmitpriv.vo_q); ++ phwxmit = pxmitpriv->hwxmits; ++ break; ++ ++ case 0: ++ case 3: ++ default: ++ ptxservq = &(psta->sta_xmitpriv.be_q); ++ phwxmit = pxmitpriv->hwxmits + 2; ++ break; ++ } ++//DBG_8192C("==> pkt_no=%d,pkt_len=%d,len=%d,RND8_LEN=%d,pkt_offset=0x%02x\n", ++ //pxmitframe->agg_num,pxmitframe->attrib.last_txcmdsz,len,pbuf,pxmitframe->pkt_offset ); ++ ++ _enter_critical_bh(&pxmitpriv->lock, &irqL); ++ ++ xmitframe_phead = get_list_head(&ptxservq->sta_pending); ++ xmitframe_plist = get_next(xmitframe_phead); ++ ++ while (rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist) == _FALSE) ++ { ++ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); ++ xmitframe_plist = get_next(xmitframe_plist); ++ ++ pxmitframe->agg_num = 0; // not first frame of aggregation ++ #ifdef CONFIG_TX_EARLY_MODE ++ pxmitframe->pkt_offset = 1;// not first frame of aggregation,reserve offset for EM Info ++ #else ++ pxmitframe->pkt_offset = 0; // not first frame of aggregation, no need to reserve offset ++ #endif ++ ++ len = xmitframe_need_length(pxmitframe) + TXDESC_SIZE +(pxmitframe->pkt_offset*PACKET_OFFSET_SZ); ++ ++ if (_RND8(pbuf + len) > MAX_XMITBUF_SZ) ++ //if (_RND8(pbuf + len) > (MAX_XMITBUF_SZ/2))//to do : for TX TP finial tune , Georgia 2012-0323 ++ { ++ //DBG_8192C("%s....len> MAX_XMITBUF_SZ\n",__FUNCTION__); ++ pxmitframe->agg_num = 1; ++ pxmitframe->pkt_offset = 1; ++ break; ++ } ++ rtw_list_delete(&pxmitframe->list); ++ ptxservq->qcnt--; ++ phwxmit->accnt--; ++ ++#ifndef IDEA_CONDITION ++ // suppose only data frames would be in queue ++ if (pxmitframe->frame_tag != DATA_FRAMETAG) { ++ RT_TRACE(_module_rtl8192c_xmit_c_, _drv_err_, ++ ("xmitframe_complete: frame tag(%d) is not DATA_FRAMETAG(%d)!\n", ++ pxmitframe->frame_tag, DATA_FRAMETAG)); ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ continue; ++ } ++ ++ // TID 0~15 ++ if ((pxmitframe->attrib.priority < 0) || ++ (pxmitframe->attrib.priority > 15)) { ++ RT_TRACE(_module_rtl8192c_xmit_c_, _drv_err_, ++ ("xmitframe_complete: TID(%d) should be 0~15!\n", ++ pxmitframe->attrib.priority)); ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ continue; ++ } ++#endif ++ ++// pxmitframe->pxmitbuf = pxmitbuf; ++ pxmitframe->buf_addr = pxmitbuf->pbuf + pbuf; ++ ++ if (rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe) == _FALSE) { ++ DBG_871X("%s coalesce failed \n",__FUNCTION__); ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ continue; ++ } ++ ++ //DBG_8192C("==> pxmitframe->attrib.priority:%d\n",pxmitframe->attrib.priority); ++ // always return ndis_packet after rtw_xmitframe_coalesce ++ rtw_os_xmit_complete(padapter, pxmitframe); ++ ++ // (len - TXDESC_SIZE) == pxmitframe->attrib.last_txcmdsz ++ update_txdesc(pxmitframe, pxmitframe->buf_addr, pxmitframe->attrib.last_txcmdsz,_TRUE); ++ ++ // don't need xmitframe any more ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ ++ // handle pointer and stop condition ++ pbuf_tail = pbuf + len; ++ pbuf = _RND8(pbuf_tail); ++ ++ ++ pfirstframe->agg_num++; ++#ifdef CONFIG_TX_EARLY_MODE ++ pxmitpriv->agg_pkt[pfirstframe->agg_num-1].offset = _RND8(len); ++ pxmitpriv->agg_pkt[pfirstframe->agg_num-1].pkt_len = pxmitframe->attrib.last_txcmdsz; ++#endif ++ if (MAX_TX_AGG_PACKET_NUMBER == pfirstframe->agg_num) ++ break; ++ ++ if (pbuf < bulkPtr) { ++ descCount++; ++ if (descCount == pHalData->UsbTxAggDescNum) ++ break; ++ } else { ++ descCount = 0; ++ bulkPtr = ((pbuf / bulkSize) + 1) * bulkSize; ++ } ++ }//end while( aggregate same priority and same DA(AP or STA) frames) ++ ++ ++ if (_rtw_queue_empty(&ptxservq->sta_pending) == _TRUE) ++ rtw_list_delete(&ptxservq->tx_pending); ++ ++ _exit_critical_bh(&pxmitpriv->lock, &irqL); ++#ifdef CONFIG_80211N_HT ++ if ((pfirstframe->attrib.ether_type != 0x0806) && ++ (pfirstframe->attrib.ether_type != 0x888e) && ++ (pfirstframe->attrib.ether_type != 0x88b4) && ++ (pfirstframe->attrib.dhcp_pkt != 1)) ++ { ++ rtw_issue_addbareq_cmd(padapter, pfirstframe); ++ } ++#endif //CONFIG_80211N_HT ++#ifndef CONFIG_USE_USB_BUFFER_ALLOC_TX ++ //3 3. update first frame txdesc ++ if ((pbuf_tail % bulkSize) == 0) { ++ // remove pkt_offset ++ pbuf_tail -= PACKET_OFFSET_SZ; ++ pfirstframe->buf_addr += PACKET_OFFSET_SZ; ++ pfirstframe->pkt_offset--; ++ //DBG_8192C("$$$$$ buf size equal to USB block size $$$$$$\n"); ++ } ++#endif // CONFIG_USE_USB_BUFFER_ALLOC_TX ++ ++ update_txdesc(pfirstframe, pfirstframe->buf_addr, pfirstframe->attrib.last_txcmdsz,_TRUE); ++ ++ #ifdef CONFIG_TX_EARLY_MODE ++ //prepare EM info for first frame, agg_num value start from 1 ++ pxmitpriv->agg_pkt[0].offset = _RND8(pfirstframe->attrib.last_txcmdsz +TXDESC_SIZE +(pfirstframe->pkt_offset*PACKET_OFFSET_SZ)); ++ pxmitpriv->agg_pkt[0].pkt_len = pfirstframe->attrib.last_txcmdsz;//get from rtw_xmitframe_coalesce ++ ++ UpdateEarlyModeInfo8188E(pxmitpriv,pxmitbuf ); ++ #endif ++ ++ //3 4. write xmit buffer to USB FIFO ++ ff_hwaddr = rtw_get_ff_hwaddr(pfirstframe); ++//DBG_8192C("%s ===================================== write port,buf_size(%d) \n",__FUNCTION__,pbuf_tail); ++ // xmit address == ((xmit_frame*)pxmitbuf->priv_data)->buf_addr ++ rtw_write_port(padapter, ff_hwaddr, pbuf_tail, (u8*)pxmitbuf); ++ ++ ++ //3 5. update statisitc ++ pbuf_tail -= (pfirstframe->agg_num * TXDESC_SIZE); ++ pbuf_tail -= (pfirstframe->pkt_offset * PACKET_OFFSET_SZ); ++ ++ ++ rtw_count_tx_stats(padapter, pfirstframe, pbuf_tail); ++ ++ rtw_free_xmitframe(pxmitpriv, pfirstframe); ++ ++ return _TRUE; ++} ++ ++#else ++ ++s32 rtl8188eu_xmitframe_complete(_adapter *padapter, struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) ++{ ++ ++ struct hw_xmit *phwxmits; ++ sint hwentry; ++ struct xmit_frame *pxmitframe=NULL; ++ int res=_SUCCESS, xcnt = 0; ++ ++ phwxmits = pxmitpriv->hwxmits; ++ hwentry = pxmitpriv->hwxmit_entry; ++ ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("xmitframe_complete()\n")); ++ ++ if(pxmitbuf==NULL) ++ { ++ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); ++ if(!pxmitbuf) ++ { ++ return _FALSE; ++ } ++ } ++ ++ ++ do ++ { ++ pxmitframe = rtw_dequeue_xframe(pxmitpriv, phwxmits, hwentry); ++ ++ if(pxmitframe) ++ { ++ pxmitframe->pxmitbuf = pxmitbuf; ++ ++ pxmitframe->buf_addr = pxmitbuf->pbuf; ++ ++ pxmitbuf->priv_data = pxmitframe; ++ ++ if((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) ++ { ++ if(pxmitframe->attrib.priority<=15)//TID0~15 ++ { ++ res = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); ++ } ++ //DBG_8192C("==> pxmitframe->attrib.priority:%d\n",pxmitframe->attrib.priority); ++ rtw_os_xmit_complete(padapter, pxmitframe);//always return ndis_packet after rtw_xmitframe_coalesce ++ } ++ ++ ++ RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("xmitframe_complete(): rtw_dump_xframe\n")); ++ ++ ++ if(res == _SUCCESS) ++ { ++ rtw_dump_xframe(padapter, pxmitframe); ++ } ++ else ++ { ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ } ++ ++ xcnt++; ++ ++ } ++ else ++ { ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ return _FALSE; ++ } ++ ++ break; ++ ++ }while(0/*xcnt < (NR_XMITFRAME >> 3)*/); ++ ++ return _TRUE; ++ ++} ++#endif ++ ++ ++ ++static s32 xmitframe_direct(_adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ s32 res = _SUCCESS; ++//DBG_8192C("==> %s \n",__FUNCTION__); ++ ++ res = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); ++ if (res == _SUCCESS) { ++ rtw_dump_xframe(padapter, pxmitframe); ++ } ++ else{ ++ DBG_8192C("==> %s xmitframe_coalsece failed\n",__FUNCTION__); ++ } ++ ++ return res; ++} ++ ++/* ++ * Return ++ * _TRUE dump packet directly ++ * _FALSE enqueue packet ++ */ ++static s32 pre_xmitframe(_adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ _irqL irqL; ++ s32 res; ++ struct xmit_buf *pxmitbuf = NULL; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++#ifdef CONFIG_CONCURRENT_MODE ++ PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_priv *pbuddy_mlmepriv = &(pbuddy_adapter->mlmepriv); ++#endif ++ ++ _enter_critical_bh(&pxmitpriv->lock, &irqL); ++ ++//DBG_8192C("==> %s \n",__FUNCTION__); ++ ++ if (rtw_txframes_sta_ac_pending(padapter, pattrib) > 0) ++ { ++ //DBG_8192C("enqueue AC(%d)\n",pattrib->priority); ++ goto enqueue; ++ } ++ ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE) ++ goto enqueue; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (check_fwstate(pbuddy_mlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE) ++ goto enqueue; ++#endif ++ ++ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); ++ if (pxmitbuf == NULL) ++ goto enqueue; ++ ++ _exit_critical_bh(&pxmitpriv->lock, &irqL); ++ ++ pxmitframe->pxmitbuf = pxmitbuf; ++ pxmitframe->buf_addr = pxmitbuf->pbuf; ++ pxmitbuf->priv_data = pxmitframe; ++ ++ if (xmitframe_direct(padapter, pxmitframe) != _SUCCESS) { ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ } ++ ++ return _TRUE; ++ ++enqueue: ++ res = rtw_xmitframe_enqueue(padapter, pxmitframe); ++ _exit_critical_bh(&pxmitpriv->lock, &irqL); ++ ++ if (res != _SUCCESS) { ++ RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("pre_xmitframe: enqueue xmitframe fail\n")); ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ ++ // Trick, make the statistics correct ++ pxmitpriv->tx_pkts--; ++ pxmitpriv->tx_drop++; ++ return _TRUE; ++ } ++ ++ return _FALSE; ++} ++ ++s32 rtl8188eu_mgnt_xmit(_adapter *padapter, struct xmit_frame *pmgntframe) ++{ ++ return rtw_dump_xframe(padapter, pmgntframe); ++} ++ ++/* ++ * Return ++ * _TRUE dump packet directly ok ++ * _FALSE temporary can't transmit packets to hardware ++ */ ++s32 rtl8188eu_hal_xmit(_adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ return pre_xmitframe(padapter, pxmitframe); ++} ++ ++s32 rtl8188eu_hal_xmitframe_enqueue(_adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ s32 err; ++ ++ if ((err=rtw_xmitframe_enqueue(padapter, pxmitframe)) != _SUCCESS) ++ { ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ ++ // Trick, make the statistics correct ++ pxmitpriv->tx_pkts--; ++ pxmitpriv->tx_drop++; ++ } ++ else ++ { ++#ifdef PLATFORM_LINUX ++ tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); ++#endif ++ } ++ ++ return err; ++ ++} ++ ++ ++#ifdef CONFIG_HOSTAPD_MLME ++ ++static void rtl8188eu_hostap_mgnt_xmit_cb(struct urb *urb) ++{ ++#ifdef PLATFORM_LINUX ++ struct sk_buff *skb = (struct sk_buff *)urb->context; ++ ++ //DBG_8192C("%s\n", __FUNCTION__); ++ ++ rtw_skb_free(skb); ++#endif ++} ++ ++s32 rtl8188eu_hostap_mgnt_xmit_entry(_adapter *padapter, _pkt *pkt) ++{ ++#ifdef PLATFORM_LINUX ++ u16 fc; ++ int rc, len, pipe; ++ unsigned int bmcst, tid, qsel; ++ struct sk_buff *skb, *pxmit_skb; ++ struct urb *urb; ++ unsigned char *pxmitbuf; ++ struct tx_desc *ptxdesc; ++ struct rtw_ieee80211_hdr *tx_hdr; ++ struct hostapd_priv *phostapdpriv = padapter->phostapdpriv; ++ struct net_device *pnetdev = padapter->pnetdev; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); ++ ++ ++ //DBG_8192C("%s\n", __FUNCTION__); ++ ++ skb = pkt; ++ ++ len = skb->len; ++ tx_hdr = (struct rtw_ieee80211_hdr *)(skb->data); ++ fc = le16_to_cpu(tx_hdr->frame_ctl); ++ bmcst = IS_MCAST(tx_hdr->addr1); ++ ++ if ((fc & RTW_IEEE80211_FCTL_FTYPE) != RTW_IEEE80211_FTYPE_MGMT) ++ goto _exit; ++ ++ pxmit_skb = rtw_skb_alloc(len + TXDESC_SIZE); ++ ++ if(!pxmit_skb) ++ goto _exit; ++ ++ pxmitbuf = pxmit_skb->data; ++ ++ urb = usb_alloc_urb(0, GFP_ATOMIC); ++ if (!urb) { ++ goto _exit; ++ } ++ ++ // ----- fill tx desc ----- ++ ptxdesc = (struct tx_desc *)pxmitbuf; ++ _rtw_memset(ptxdesc, 0, sizeof(*ptxdesc)); ++ ++ //offset 0 ++ ptxdesc->txdw0 |= cpu_to_le32(len&0x0000ffff); ++ ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<txdw0 |= cpu_to_le32(OWN | FSG | LSG); ++ ++ if(bmcst) ++ { ++ ptxdesc->txdw0 |= cpu_to_le32(BIT(24)); ++ } ++ ++ //offset 4 ++ ptxdesc->txdw1 |= cpu_to_le32(0x00);//MAC_ID ++ ++ ptxdesc->txdw1 |= cpu_to_le32((0x12<txdw1 |= cpu_to_le32((0x06<< 16) & 0x000f0000);//b mode ++ ++ //offset 8 ++ ++ //offset 12 ++ ptxdesc->txdw3 |= cpu_to_le32((le16_to_cpu(tx_hdr->seq_ctl)<<16)&0xffff0000); ++ ++ //offset 16 ++ ptxdesc->txdw4 |= cpu_to_le32(BIT(8));//driver uses rate ++ ++ //offset 20 ++ ++ ++ //HW append seq ++ ptxdesc->txdw4 |= cpu_to_le32(BIT(7)); // Hw set sequence number ++ ptxdesc->txdw3 |= cpu_to_le32((8 <<28)); //set bit3 to 1. Suugested by TimChen. 2009.12.29. ++ ++ ++ rtl8188eu_cal_txdesc_chksum(ptxdesc); ++ // ----- end of fill tx desc ----- ++ ++ // ++ skb_put(pxmit_skb, len + TXDESC_SIZE); ++ pxmitbuf = pxmitbuf + TXDESC_SIZE; ++ _rtw_memcpy(pxmitbuf, skb->data, len); ++ ++ //DBG_8192C("mgnt_xmit, len=%x\n", pxmit_skb->len); ++ ++ ++ // ----- prepare urb for submit ----- ++ ++ //translate DMA FIFO addr to pipehandle ++ //pipe = ffaddr2pipehdl(pdvobj, MGT_QUEUE_INX); ++ pipe = usb_sndbulkpipe(pdvobj->pusbdev, pHalData->Queue2EPNum[(u8)MGT_QUEUE_INX]&0x0f); ++ ++ usb_fill_bulk_urb(urb, pdvobj->pusbdev, pipe, ++ pxmit_skb->data, pxmit_skb->len, rtl8192cu_hostap_mgnt_xmit_cb, pxmit_skb); ++ ++ urb->transfer_flags |= URB_ZERO_PACKET; ++ usb_anchor_urb(urb, &phostapdpriv->anchored); ++ rc = usb_submit_urb(urb, GFP_ATOMIC); ++ if (rc < 0) { ++ usb_unanchor_urb(urb); ++ kfree_skb(skb); ++ } ++ usb_free_urb(urb); ++ ++ ++_exit: ++ ++ rtw_skb_free(skb); ++ ++#endif ++ ++ return 0; ++ ++} ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/usb/usb_halinit.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/usb/usb_halinit.c +new file mode 100644 +index 00000000..5408f6ea +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/usb/usb_halinit.c +@@ -0,0 +1,5370 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _HCI_HAL_INIT_C_ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#ifdef CONFIG_IOL ++#include ++#endif ++ ++#if defined (PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) ++ ++#error "Shall be Linux or Windows, but not both!\n" ++ ++#endif ++ ++#ifndef CONFIG_USB_HCI ++ ++#error "CONFIG_USB_HCI shall be on!\n" ++ ++#endif ++ ++#include ++#include ++#include ++ ++#ifdef CONFIG_EFUSE_CONFIG_FILE ++#include ++#include ++#endif //CONFIG_EFUSE_CONFIG_FILE ++ ++#if DISABLE_BB_RF ++ #define HAL_MAC_ENABLE 0 ++ #define HAL_BB_ENABLE 0 ++ #define HAL_RF_ENABLE 0 ++#else ++ #define HAL_MAC_ENABLE 1 ++ #define HAL_BB_ENABLE 1 ++ #define HAL_RF_ENABLE 1 ++#endif ++ ++ ++static VOID ++_ConfigNormalChipOutEP_8188E( ++ IN PADAPTER pAdapter, ++ IN u8 NumOutPipe ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ switch(NumOutPipe){ ++ case 3: ++ pHalData->OutEpQueueSel=TX_SELE_HQ| TX_SELE_LQ|TX_SELE_NQ; ++ pHalData->OutEpNumber=3; ++ break; ++ case 2: ++ pHalData->OutEpQueueSel=TX_SELE_HQ| TX_SELE_NQ; ++ pHalData->OutEpNumber=2; ++ break; ++ case 1: ++ pHalData->OutEpQueueSel=TX_SELE_HQ; ++ pHalData->OutEpNumber=1; ++ break; ++ default: ++ break; ++ ++ } ++ DBG_871X("%s OutEpQueueSel(0x%02x), OutEpNumber(%d) \n",__FUNCTION__,pHalData->OutEpQueueSel,pHalData->OutEpNumber ); ++ ++} ++ ++static BOOLEAN HalUsbSetQueuePipeMapping8188EUsb( ++ IN PADAPTER pAdapter, ++ IN u8 NumInPipe, ++ IN u8 NumOutPipe ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ BOOLEAN result = _FALSE; ++ ++ _ConfigNormalChipOutEP_8188E(pAdapter, NumOutPipe); ++ ++ // Normal chip with one IN and one OUT doesn't have interrupt IN EP. ++ if(1 == pHalData->OutEpNumber){ ++ if(1 != NumInPipe){ ++ return result; ++ } ++ } ++ ++ // All config other than above support one Bulk IN and one Interrupt IN. ++ //if(2 != NumInPipe){ ++ // return result; ++ //} ++ ++ result = Hal_MappingOutPipe(pAdapter, NumOutPipe); ++ ++ return result; ++ ++} ++ ++void rtl8188eu_interface_configure(_adapter *padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ ++ if (pdvobjpriv->ishighspeed == _TRUE) ++ { ++ pHalData->UsbBulkOutSize = USB_HIGH_SPEED_BULK_SIZE;//512 bytes ++ } ++ else ++ { ++ pHalData->UsbBulkOutSize = USB_FULL_SPEED_BULK_SIZE;//64 bytes ++ } ++ ++ pHalData->interfaceIndex = pdvobjpriv->InterfaceNumber; ++ ++#ifdef CONFIG_USB_TX_AGGREGATION ++ pHalData->UsbTxAggMode = 1; ++ pHalData->UsbTxAggDescNum = 0x6; // only 4 bits ++#endif ++ ++#ifdef CONFIG_USB_RX_AGGREGATION ++ pHalData->UsbRxAggMode = USB_RX_AGG_DMA;// USB_RX_AGG_DMA; ++ pHalData->UsbRxAggBlockCount = 8; //unit : 512b ++ pHalData->UsbRxAggBlockTimeout = 0x6; ++ pHalData->UsbRxAggPageCount = 48; //uint :128 b //0x0A; // 10 = MAX_RX_DMA_BUFFER_SIZE/2/pHalData->UsbBulkOutSize ++ pHalData->UsbRxAggPageTimeout = 0x4; //6, absolute time = 34ms/(2^6) ++#endif ++ ++ HalUsbSetQueuePipeMapping8188EUsb(padapter, ++ pdvobjpriv->RtNumInPipes, pdvobjpriv->RtNumOutPipes); ++ ++} ++ ++static u32 InitPowerOn_rtl8188eu(_adapter *padapter) ++{ ++ u16 value16; ++ u8 bMacPwrCtrlOn=_FALSE; ++ // HW Power on sequence ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if(bMacPwrCtrlOn == _TRUE) ++ return _SUCCESS; ++ ++ if(!HalPwrSeqCmdParsing(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, Rtl8188E_NIC_PWR_ON_FLOW)) ++ { ++ DBG_871X(KERN_ERR "%s: run power on flow fail\n", __func__); ++ return _FAIL; ++ } ++ ++ // Enable MAC DMA/WMAC/SCHEDULE/SEC block ++ // Set CR bit10 to enable 32k calibration. Suggested by SD1 Gimmy. Added by tynli. 2011.08.31. ++ rtw_write16(padapter, REG_CR, 0x00); //suggseted by zhouzhou, by page, 20111230 ++ ++ ++ // Enable MAC DMA/WMAC/SCHEDULE/SEC block ++ value16 = rtw_read16(padapter, REG_CR); ++ value16 |= (HCI_TXDMA_EN | HCI_RXDMA_EN | TXDMA_EN | RXDMA_EN ++ | PROTOCOL_EN | SCHEDULE_EN | ENSEC | CALTMR_EN); ++ // for SDIO - Set CR bit10 to enable 32k calibration. Suggested by SD1 Gimmy. Added by tynli. 2011.08.31. ++ ++ rtw_write16(padapter, REG_CR, value16); ++ ++ bMacPwrCtrlOn = _TRUE; ++ rtw_hal_set_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ ++ return _SUCCESS; ++ ++} ++ ++ ++static void _dbg_dump_macreg(_adapter *padapter) ++{ ++ u32 offset = 0; ++ u32 val32 = 0; ++ u32 index =0 ; ++ for(index=0;index<64;index++) ++ { ++ offset = index*4; ++ val32 = rtw_read32(padapter,offset); ++ DBG_8192C("offset : 0x%02x ,val:0x%08x\n",offset,val32); ++ } ++} ++ ++ ++static void _InitPABias(_adapter *padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ u8 pa_setting; ++ BOOLEAN is92C = IS_92C_SERIAL(pHalData->VersionID); ++ ++ //FIXED PA current issue ++ //efuse_one_byte_read(padapter, 0x1FA, &pa_setting); ++ pa_setting = EFUSE_Read1Byte(padapter, 0x1FA); ++ ++ //RT_TRACE(COMP_INIT, DBG_LOUD, ("_InitPABias 0x1FA 0x%x \n",pa_setting)); ++ ++ if(!(pa_setting & BIT0)) ++ { ++ PHY_SetRFReg(padapter, RF_PATH_A, 0x15, 0x0FFFFF, 0x0F406); ++ PHY_SetRFReg(padapter, RF_PATH_A, 0x15, 0x0FFFFF, 0x4F406); ++ PHY_SetRFReg(padapter, RF_PATH_A, 0x15, 0x0FFFFF, 0x8F406); ++ PHY_SetRFReg(padapter, RF_PATH_A, 0x15, 0x0FFFFF, 0xCF406); ++ //RT_TRACE(COMP_INIT, DBG_LOUD, ("PA BIAS path A\n")); ++ } ++ ++ if(!(pa_setting & BIT1) && is92C) ++ { ++ PHY_SetRFReg(padapter,RF_PATH_B, 0x15, 0x0FFFFF, 0x0F406); ++ PHY_SetRFReg(padapter,RF_PATH_B, 0x15, 0x0FFFFF, 0x4F406); ++ PHY_SetRFReg(padapter,RF_PATH_B, 0x15, 0x0FFFFF, 0x8F406); ++ PHY_SetRFReg(padapter,RF_PATH_B, 0x15, 0x0FFFFF, 0xCF406); ++ //RT_TRACE(COMP_INIT, DBG_LOUD, ("PA BIAS path B\n")); ++ } ++ ++ if(!(pa_setting & BIT4)) ++ { ++ pa_setting = rtw_read8(padapter, 0x16); ++ pa_setting &= 0x0F; ++ rtw_write8(padapter, 0x16, pa_setting | 0x80); ++ rtw_write8(padapter, 0x16, pa_setting | 0x90); ++ } ++} ++#ifdef CONFIG_BT_COEXIST ++static void _InitBTCoexist(_adapter *padapter) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct btcoexist_priv *pbtpriv = &(pHalData->bt_coexist); ++ u8 u1Tmp; ++ ++ if(pbtpriv->BT_Coexist && pbtpriv->BT_CoexistType == BT_CSR_BC4) ++ { ++ ++//#if MP_DRIVER != 1 ++ if (padapter->registrypriv.mp_mode == 0) ++ { ++ if(pbtpriv->BT_Ant_isolation) ++ { ++ rtw_write8( padapter,REG_GPIO_MUXCFG, 0xa0); ++ DBG_8192C("BT write 0x%x = 0x%x\n", REG_GPIO_MUXCFG, 0xa0); ++ } ++ } ++//#endif ++ ++ u1Tmp = rtw_read8(padapter, 0x4fd) & BIT0; ++ u1Tmp = u1Tmp | ++ ((pbtpriv->BT_Ant_isolation==1)?0:BIT1) | ++ ((pbtpriv->BT_Service==BT_SCO)?0:BIT2); ++ rtw_write8( padapter, 0x4fd, u1Tmp); ++ DBG_8192C("BT write 0x%x = 0x%x for non-isolation\n", 0x4fd, u1Tmp); ++ ++ ++ rtw_write32(padapter, REG_BT_COEX_TABLE+4, 0xaaaa9aaa); ++ DBG_8192C("BT write 0x%x = 0x%x\n", REG_BT_COEX_TABLE+4, 0xaaaa9aaa); ++ ++ rtw_write32(padapter, REG_BT_COEX_TABLE+8, 0xffbd0040); ++ DBG_8192C("BT write 0x%x = 0x%x\n", REG_BT_COEX_TABLE+8, 0xffbd0040); ++ ++ rtw_write32(padapter, REG_BT_COEX_TABLE+0xc, 0x40000010); ++ DBG_8192C("BT write 0x%x = 0x%x\n", REG_BT_COEX_TABLE+0xc, 0x40000010); ++ ++ //Config to 1T1R ++ u1Tmp = rtw_read8(padapter,rOFDM0_TRxPathEnable); ++ u1Tmp &= ~(BIT1); ++ rtw_write8( padapter, rOFDM0_TRxPathEnable, u1Tmp); ++ DBG_8192C("BT write 0xC04 = 0x%x\n", u1Tmp); ++ ++ u1Tmp = rtw_read8(padapter, rOFDM1_TRxPathEnable); ++ u1Tmp &= ~(BIT1); ++ rtw_write8( padapter, rOFDM1_TRxPathEnable, u1Tmp); ++ DBG_8192C("BT write 0xD04 = 0x%x\n", u1Tmp); ++ ++ } ++} ++#endif ++ ++ ++ ++//--------------------------------------------------------------- ++// ++// MAC init functions ++// ++//--------------------------------------------------------------- ++static VOID ++_SetMacID( ++ IN PADAPTER Adapter, u8* MacID ++ ) ++{ ++ u32 i; ++ for(i=0 ; i< MAC_ADDR_LEN ; i++){ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(Adapter->iface_type == IFACE_PORT1) ++ rtw_write32(Adapter, REG_MACID1+i, MacID[i]); ++ else ++#endif ++ rtw_write32(Adapter, REG_MACID+i, MacID[i]); ++ } ++} ++ ++static VOID ++_SetBSSID( ++ IN PADAPTER Adapter, u8* BSSID ++ ) ++{ ++ u32 i; ++ for(i=0 ; i< MAC_ADDR_LEN ; i++){ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(Adapter->iface_type == IFACE_PORT1) ++ rtw_write32(Adapter, REG_BSSID1+i, BSSID[i]); ++ else ++#endif ++ rtw_write32(Adapter, REG_BSSID+i, BSSID[i]); ++ } ++} ++ ++ ++// Shall USB interface init this? ++static VOID ++_InitInterrupt( ++ IN PADAPTER Adapter ++ ) ++{ ++ u32 imr,imr_ex; ++ u8 usb_opt; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ //HISR write one to clear ++ rtw_write32(Adapter, REG_HISR_88E, 0xFFFFFFFF); ++ // HIMR - ++ imr = IMR_PSTIMEOUT_88E | IMR_TBDER_88E | IMR_CPWM_88E | IMR_CPWM2_88E ; ++ rtw_write32(Adapter, REG_HIMR_88E, imr); ++ pHalData->IntrMask[0]=imr; ++ ++ imr_ex = IMR_TXERR_88E | IMR_RXERR_88E | IMR_TXFOVW_88E |IMR_RXFOVW_88E; ++ rtw_write32(Adapter, REG_HIMRE_88E, imr_ex); ++ pHalData->IntrMask[1]=imr_ex; ++ ++#ifdef CONFIG_SUPPORT_USB_INT ++ // REG_USB_SPECIAL_OPTION - BIT(4) ++ // 0; Use interrupt endpoint to upload interrupt pkt ++ // 1; Use bulk endpoint to upload interrupt pkt, ++ usb_opt = rtw_read8(Adapter, REG_USB_SPECIAL_OPTION); ++ ++ ++ if(!adapter_to_dvobj(Adapter)->ishighspeed ++ #ifdef CONFIG_USB_INTERRUPT_IN_PIPE ++ || pHalData->RtIntInPipe == 0x05 ++ #endif ++ ) ++ usb_opt = usb_opt & (~INT_BULK_SEL); ++ else ++ usb_opt = usb_opt | (INT_BULK_SEL); ++ ++ rtw_write8(Adapter, REG_USB_SPECIAL_OPTION, usb_opt ); ++ ++#endif//CONFIG_SUPPORT_USB_INT ++ ++} ++ ++ ++static VOID ++_InitQueueReservedPage( ++ IN PADAPTER Adapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct registry_priv *pregistrypriv = &Adapter->registrypriv; ++ u32 outEPNum = (u32)pHalData->OutEpNumber; ++ u32 numHQ = 0; ++ u32 numLQ = 0; ++ u32 numNQ = 0; ++ u32 numPubQ; ++ u32 value32; ++ u8 value8; ++ BOOLEAN bWiFiConfig = pregistrypriv->wifi_spec; ++ ++ if((bWiFiConfig)|| (pregistrypriv->qos_opt_enable)) ++ { ++ if (pHalData->OutEpQueueSel & TX_SELE_HQ) ++ { ++ numHQ = 0x29; ++ } ++ ++ if (pHalData->OutEpQueueSel & TX_SELE_LQ) ++ { ++ numLQ = 0x1C; ++ } ++ ++ // NOTE: This step shall be proceed before writting REG_RQPN. ++ if (pHalData->OutEpQueueSel & TX_SELE_NQ) { ++ numNQ = 0x1C; ++ } ++ value8 = (u8)_NPQ(numNQ); ++ rtw_write8(Adapter, REG_RQPN_NPQ, value8); ++ ++ numPubQ = 0xA8 - numHQ - numLQ - numNQ; ++ ++ // TX DMA ++ value32 = _HPQ(numHQ) | _LPQ(numLQ) | _PUBQ(numPubQ) | LD_RQPN; ++ rtw_write32(Adapter, REG_RQPN, value32); ++ } ++ else ++ { ++ rtw_write16(Adapter,REG_RQPN_NPQ, 0x0000);//Just follow MP Team,??? Georgia 03/28 ++ rtw_write16(Adapter,REG_RQPN_NPQ, 0x0d); ++ rtw_write32(Adapter,REG_RQPN, 0x808E000d);//reserve 7 page for LPS ++ } ++} ++ ++static VOID ++_InitTxBufferBoundary( ++ IN PADAPTER Adapter, ++ IN u8 txpktbuf_bndy ++ ) ++{ ++ struct registry_priv *pregistrypriv = &Adapter->registrypriv; ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ //u16 txdmactrl; ++ ++ rtw_write8(Adapter, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy); ++ rtw_write8(Adapter, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy); ++ rtw_write8(Adapter, REG_TXPKTBUF_WMAC_LBK_BF_HD, txpktbuf_bndy); ++ rtw_write8(Adapter, REG_TRXFF_BNDY, txpktbuf_bndy); ++ rtw_write8(Adapter, REG_TDECTRL+1, txpktbuf_bndy); ++ ++} ++ ++static VOID ++_InitPageBoundary( ++ IN PADAPTER Adapter ++ ) ++{ ++ // RX Page Boundary ++ // ++ u16 rxff_bndy = MAX_RX_DMA_BUFFER_SIZE_88E-1; ++ ++ #if 0 ++ ++ // RX Page Boundary ++ //srand(static_cast(time(NULL)) ); ++ if(bSupportRemoteWakeUp) ++ { ++ Offset = MAX_RX_DMA_BUFFER_SIZE_88E+MAX_TX_REPORT_BUFFER_SIZE-MAX_SUPPORT_WOL_PATTERN_NUM(Adapter)*WKFMCAM_SIZE; ++ Offset = Offset / 128; // RX page size = 128 byte ++ rxff_bndy= (Offset*128) -1; ++ } ++ else ++ ++ #endif ++ rtw_write16(Adapter, (REG_TRXFF_BNDY + 2), rxff_bndy); ++} ++ ++ ++static VOID ++_InitNormalChipRegPriority( ++ IN PADAPTER Adapter, ++ IN u16 beQ, ++ IN u16 bkQ, ++ IN u16 viQ, ++ IN u16 voQ, ++ IN u16 mgtQ, ++ IN u16 hiQ ++ ) ++{ ++ u16 value16 = (rtw_read16(Adapter, REG_TRXDMA_CTRL) & 0x7); ++ ++ value16 |= _TXDMA_BEQ_MAP(beQ) | _TXDMA_BKQ_MAP(bkQ) | ++ _TXDMA_VIQ_MAP(viQ) | _TXDMA_VOQ_MAP(voQ) | ++ _TXDMA_MGQ_MAP(mgtQ)| _TXDMA_HIQ_MAP(hiQ); ++ ++ rtw_write16(Adapter, REG_TRXDMA_CTRL, value16); ++} ++ ++static VOID ++_InitNormalChipOneOutEpPriority( ++ IN PADAPTER Adapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ u16 value = 0; ++ switch(pHalData->OutEpQueueSel) ++ { ++ case TX_SELE_HQ: ++ value = QUEUE_HIGH; ++ break; ++ case TX_SELE_LQ: ++ value = QUEUE_LOW; ++ break; ++ case TX_SELE_NQ: ++ value = QUEUE_NORMAL; ++ break; ++ default: ++ //RT_ASSERT(FALSE,("Shall not reach here!\n")); ++ break; ++ } ++ ++ _InitNormalChipRegPriority(Adapter, ++ value, ++ value, ++ value, ++ value, ++ value, ++ value ++ ); ++ ++} ++ ++static VOID ++_InitNormalChipTwoOutEpPriority( ++ IN PADAPTER Adapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct registry_priv *pregistrypriv = &Adapter->registrypriv; ++ u16 beQ,bkQ,viQ,voQ,mgtQ,hiQ; ++ ++ ++ u16 valueHi = 0; ++ u16 valueLow = 0; ++ ++ switch(pHalData->OutEpQueueSel) ++ { ++ case (TX_SELE_HQ | TX_SELE_LQ): ++ valueHi = QUEUE_HIGH; ++ valueLow = QUEUE_LOW; ++ break; ++ case (TX_SELE_NQ | TX_SELE_LQ): ++ valueHi = QUEUE_NORMAL; ++ valueLow = QUEUE_LOW; ++ break; ++ case (TX_SELE_HQ | TX_SELE_NQ): ++ valueHi = QUEUE_HIGH; ++ valueLow = QUEUE_NORMAL; ++ break; ++ default: ++ //RT_ASSERT(FALSE,("Shall not reach here!\n")); ++ break; ++ } ++ ++ if(!pregistrypriv->wifi_spec ){ ++ beQ = valueLow; ++ bkQ = valueLow; ++ viQ = valueHi; ++ voQ = valueHi; ++ mgtQ = valueHi; ++ hiQ = valueHi; ++ } ++ else{//for WMM ,CONFIG_OUT_EP_WIFI_MODE ++ beQ = valueLow; ++ bkQ = valueHi; ++ viQ = valueHi; ++ voQ = valueLow; ++ mgtQ = valueHi; ++ hiQ = valueHi; ++ } ++ ++ _InitNormalChipRegPriority(Adapter,beQ,bkQ,viQ,voQ,mgtQ,hiQ); ++ ++} ++ ++static VOID ++_InitNormalChipThreeOutEpPriority( ++ IN PADAPTER Adapter ++ ) ++{ ++ struct registry_priv *pregistrypriv = &Adapter->registrypriv; ++ u16 beQ,bkQ,viQ,voQ,mgtQ,hiQ; ++ ++ if(!pregistrypriv->wifi_spec ){// typical setting ++ beQ = QUEUE_LOW; ++ bkQ = QUEUE_LOW; ++ viQ = QUEUE_NORMAL; ++ voQ = QUEUE_HIGH; ++ mgtQ = QUEUE_HIGH; ++ hiQ = QUEUE_HIGH; ++ } ++ else{// for WMM ++ beQ = QUEUE_LOW; ++ bkQ = QUEUE_NORMAL; ++ viQ = QUEUE_NORMAL; ++ voQ = QUEUE_HIGH; ++ mgtQ = QUEUE_HIGH; ++ hiQ = QUEUE_HIGH; ++ } ++ _InitNormalChipRegPriority(Adapter,beQ,bkQ,viQ,voQ,mgtQ,hiQ); ++} ++ ++static VOID ++_InitQueuePriority( ++ IN PADAPTER Adapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ switch(pHalData->OutEpNumber) ++ { ++ case 1: ++ _InitNormalChipOneOutEpPriority(Adapter); ++ break; ++ case 2: ++ _InitNormalChipTwoOutEpPriority(Adapter); ++ break; ++ case 3: ++ _InitNormalChipThreeOutEpPriority(Adapter); ++ break; ++ default: ++ //RT_ASSERT(FALSE,("Shall not reach here!\n")); ++ break; ++ } ++ ++ ++} ++ ++ ++ ++static VOID ++_InitHardwareDropIncorrectBulkOut( ++ IN PADAPTER Adapter ++ ) ++{ ++#ifdef ENABLE_USB_DROP_INCORRECT_OUT ++ u32 value32 = rtw_read32(Adapter, REG_TXDMA_OFFSET_CHK); ++ value32 |= DROP_DATA_EN; ++ rtw_write32(Adapter, REG_TXDMA_OFFSET_CHK, value32); ++#endif ++} ++ ++static VOID ++_InitNetworkType( ++ IN PADAPTER Adapter ++ ) ++{ ++ u32 value32; ++ ++ value32 = rtw_read32(Adapter, REG_CR); ++ // TODO: use the other function to set network type ++ value32 = (value32 & ~MASK_NETTYPE) | _NETTYPE(NT_LINK_AP); ++ ++ rtw_write32(Adapter, REG_CR, value32); ++// RASSERT(pIoBase->rtw_read8(REG_CR + 2) == 0x2); ++} ++ ++static VOID ++_InitTransferPageSize( ++ IN PADAPTER Adapter ++ ) ++{ ++ // Tx page size is always 128. ++ ++ u8 value8; ++ value8 = _PSRX(PBP_128) | _PSTX(PBP_128); ++ rtw_write8(Adapter, REG_PBP, value8); ++} ++ ++static VOID ++_InitDriverInfoSize( ++ IN PADAPTER Adapter, ++ IN u8 drvInfoSize ++ ) ++{ ++ rtw_write8(Adapter,REG_RX_DRVINFO_SZ, drvInfoSize); ++} ++ ++static VOID ++_InitWMACSetting( ++ IN PADAPTER Adapter ++ ) ++{ ++ //u4Byte value32; ++ //u16 value16; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ //pHalData->ReceiveConfig = AAP | APM | AM | AB | APP_ICV | ADF | AMF | APP_FCS | HTC_LOC_CTRL | APP_MIC | APP_PHYSTS; ++ //pHalData->ReceiveConfig = ++ //RCR_AAP | RCR_APM | RCR_AM | RCR_AB |RCR_CBSSID_DATA| RCR_CBSSID_BCN| RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL | RCR_APP_MIC | RCR_APP_PHYSTS; ++ // don't turn on AAP, it will allow all packets to driver ++ pHalData->ReceiveConfig = RCR_APM | RCR_AM | RCR_AB |RCR_CBSSID_DATA| RCR_CBSSID_BCN| RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL | RCR_APP_MIC | RCR_APP_PHYSTS; ++ ++#if (1 == RTL8188E_RX_PACKET_INCLUDE_CRC) ++ pHalData->ReceiveConfig |= ACRC32; ++#endif ++ ++ // some REG_RCR will be modified later by phy_ConfigMACWithHeaderFile() ++ rtw_write32(Adapter, REG_RCR, pHalData->ReceiveConfig); ++ ++ // Accept all multicast address ++ rtw_write32(Adapter, REG_MAR, 0xFFFFFFFF); ++ rtw_write32(Adapter, REG_MAR + 4, 0xFFFFFFFF); ++ ++ ++ // Accept all data frames ++ //value16 = 0xFFFF; ++ //rtw_write16(Adapter, REG_RXFLTMAP2, value16); ++ ++ // 2010.09.08 hpfan ++ // Since ADF is removed from RCR, ps-poll will not be indicate to driver, ++ // RxFilterMap should mask ps-poll to gurantee AP mode can rx ps-poll. ++ //value16 = 0x400; ++ //rtw_write16(Adapter, REG_RXFLTMAP1, value16); ++ ++ // Accept all management frames ++ //value16 = 0xFFFF; ++ //rtw_write16(Adapter, REG_RXFLTMAP0, value16); ++ ++ //enable RX_SHIFT bits ++ //rtw_write8(Adapter, REG_TRXDMA_CTRL, rtw_read8(Adapter, REG_TRXDMA_CTRL)|BIT(1)); ++ ++} ++ ++static VOID ++_InitAdaptiveCtrl( ++ IN PADAPTER Adapter ++ ) ++{ ++ u16 value16; ++ u32 value32; ++ ++ // Response Rate Set ++ value32 = rtw_read32(Adapter, REG_RRSR); ++ value32 &= ~RATE_BITMAP_ALL; ++ value32 |= RATE_RRSR_CCK_ONLY_1M; ++ rtw_write32(Adapter, REG_RRSR, value32); ++ ++ // CF-END Threshold ++ //m_spIoBase->rtw_write8(REG_CFEND_TH, 0x1); ++ ++ // SIFS (used in NAV) ++ value16 = _SPEC_SIFS_CCK(0x10) | _SPEC_SIFS_OFDM(0x10); ++ rtw_write16(Adapter, REG_SPEC_SIFS, value16); ++ ++ // Retry Limit ++ value16 = _LRL(0x30) | _SRL(0x30); ++ rtw_write16(Adapter, REG_RL, value16); ++ ++} ++ ++static VOID ++_InitRateFallback( ++ IN PADAPTER Adapter ++ ) ++{ ++ // Set Data Auto Rate Fallback Retry Count register. ++ rtw_write32(Adapter, REG_DARFRC, 0x00000000); ++ rtw_write32(Adapter, REG_DARFRC+4, 0x10080404); ++ rtw_write32(Adapter, REG_RARFRC, 0x04030201); ++ rtw_write32(Adapter, REG_RARFRC+4, 0x08070605); ++ ++} ++ ++ ++static VOID ++_InitEDCA( ++ IN PADAPTER Adapter ++ ) ++{ ++ // Set Spec SIFS (used in NAV) ++ rtw_write16(Adapter,REG_SPEC_SIFS, 0x100a); ++ rtw_write16(Adapter,REG_MAC_SPEC_SIFS, 0x100a); ++ ++ // Set SIFS for CCK ++ rtw_write16(Adapter,REG_SIFS_CTX, 0x100a); ++ ++ // Set SIFS for OFDM ++ rtw_write16(Adapter,REG_SIFS_TRX, 0x100a); ++ ++ // TXOP ++ rtw_write32(Adapter, REG_EDCA_BE_PARAM, 0x005EA42B); ++ rtw_write32(Adapter, REG_EDCA_BK_PARAM, 0x0000A44F); ++ rtw_write32(Adapter, REG_EDCA_VI_PARAM, 0x005EA324); ++ rtw_write32(Adapter, REG_EDCA_VO_PARAM, 0x002FA226); ++} ++ ++ ++static VOID ++_InitBeaconMaxError( ++ IN PADAPTER Adapter, ++ IN BOOLEAN InfraMode ++ ) ++{ ++ ++} ++ ++ ++#ifdef CONFIG_LED ++static void _InitHWLed(PADAPTER Adapter) ++{ ++ struct led_priv *pledpriv = &(Adapter->ledpriv); ++ ++ if( pledpriv->LedStrategy != HW_LED) ++ return; ++ ++// HW led control ++// to do .... ++//must consider cases of antenna diversity/ commbo card/solo card/mini card ++ ++} ++#endif //CONFIG_LED ++ ++static VOID ++_InitRDGSetting( ++ IN PADAPTER Adapter ++ ) ++{ ++ rtw_write8(Adapter,REG_RD_CTRL,0xFF); ++ rtw_write16(Adapter, REG_RD_NAV_NXT, 0x200); ++ rtw_write8(Adapter,REG_RD_RESP_PKT_TH,0x05); ++} ++ ++static VOID ++_InitRxSetting( ++ IN PADAPTER Adapter ++ ) ++{ ++ rtw_write32(Adapter, REG_MACID, 0x87654321); ++ rtw_write32(Adapter, 0x0700, 0x87654321); ++} ++ ++static VOID ++_InitRetryFunction( ++ IN PADAPTER Adapter ++ ) ++{ ++ u8 value8; ++ //#if 0 //MAC SPEC ++ value8 = rtw_read8(Adapter, REG_FWHW_TXQ_CTRL); ++ value8 |= EN_AMPDU_RTY_NEW; ++ rtw_write8(Adapter, REG_FWHW_TXQ_CTRL, value8); ++ //#endif ++ // Set ACK timeout ++ rtw_write8(Adapter, REG_ACKTO, 0x40); ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: usb_AggSettingTxUpdate() ++ * ++ * Overview: Seperate TX/RX parameters update independent for TP detection and ++ * dynamic TX/RX aggreagtion parameters update. ++ * ++ * Input: PADAPTER ++ * ++ * Output/Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 12/10/2010 MHC Seperate to smaller function. ++ * ++ *---------------------------------------------------------------------------*/ ++static VOID ++usb_AggSettingTxUpdate( ++ IN PADAPTER Adapter ++ ) ++{ ++#ifdef CONFIG_USB_TX_AGGREGATION ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ //PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ u32 value32; ++ ++ if(Adapter->registrypriv.wifi_spec) ++ pHalData->UsbTxAggMode = _FALSE; ++ ++ if(pHalData->UsbTxAggMode){ ++ value32 = rtw_read32(Adapter, REG_TDECTRL); ++ value32 = value32 & ~(BLK_DESC_NUM_MASK << BLK_DESC_NUM_SHIFT); ++ value32 |= ((pHalData->UsbTxAggDescNum & BLK_DESC_NUM_MASK) << BLK_DESC_NUM_SHIFT); ++ ++ rtw_write32(Adapter, REG_TDECTRL, value32); ++ } ++ ++#endif ++} // usb_AggSettingTxUpdate ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: usb_AggSettingRxUpdate() ++ * ++ * Overview: Seperate TX/RX parameters update independent for TP detection and ++ * dynamic TX/RX aggreagtion parameters update. ++ * ++ * Input: PADAPTER ++ * ++ * Output/Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 12/10/2010 MHC Seperate to smaller function. ++ * ++ *---------------------------------------------------------------------------*/ ++static VOID ++usb_AggSettingRxUpdate( ++ IN PADAPTER Adapter ++ ) ++{ ++#ifdef CONFIG_USB_RX_AGGREGATION ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ //PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ u8 valueDMA; ++ u8 valueUSB; ++ ++ valueDMA = rtw_read8(Adapter, REG_TRXDMA_CTRL); ++ valueUSB = rtw_read8(Adapter, REG_USB_SPECIAL_OPTION); ++ ++ switch(pHalData->UsbRxAggMode) ++ { ++ case USB_RX_AGG_DMA: ++ valueDMA |= RXDMA_AGG_EN; ++ valueUSB &= ~USB_AGG_EN; ++ break; ++ case USB_RX_AGG_USB: ++ valueDMA &= ~RXDMA_AGG_EN; ++ valueUSB |= USB_AGG_EN; ++ break; ++ case USB_RX_AGG_MIX: ++ valueDMA |= RXDMA_AGG_EN; ++ valueUSB |= USB_AGG_EN; ++ break; ++ case USB_RX_AGG_DISABLE: ++ default: ++ valueDMA &= ~RXDMA_AGG_EN; ++ valueUSB &= ~USB_AGG_EN; ++ break; ++ } ++ ++ rtw_write8(Adapter, REG_TRXDMA_CTRL, valueDMA); ++ rtw_write8(Adapter, REG_USB_SPECIAL_OPTION, valueUSB); ++ ++ switch(pHalData->UsbRxAggMode) ++ { ++ case USB_RX_AGG_DMA: ++ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH, pHalData->UsbRxAggPageCount); ++ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH+1, pHalData->UsbRxAggPageTimeout); ++ break; ++ case USB_RX_AGG_USB: ++ rtw_write8(Adapter, REG_USB_AGG_TH, pHalData->UsbRxAggBlockCount); ++ rtw_write8(Adapter, REG_USB_AGG_TO, pHalData->UsbRxAggBlockTimeout); ++ break; ++ case USB_RX_AGG_MIX: ++ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH, pHalData->UsbRxAggPageCount); ++ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH+1, (pHalData->UsbRxAggPageTimeout& 0x1F));//0x280[12:8] ++ ++ rtw_write8(Adapter, REG_USB_AGG_TH, pHalData->UsbRxAggBlockCount); ++ rtw_write8(Adapter, REG_USB_AGG_TO, pHalData->UsbRxAggBlockTimeout); ++ ++ break; ++ case USB_RX_AGG_DISABLE: ++ default: ++ // TODO: ++ break; ++ } ++ ++ switch(PBP_128) ++ { ++ case PBP_128: ++ pHalData->HwRxPageSize = 128; ++ break; ++ case PBP_64: ++ pHalData->HwRxPageSize = 64; ++ break; ++ case PBP_256: ++ pHalData->HwRxPageSize = 256; ++ break; ++ case PBP_512: ++ pHalData->HwRxPageSize = 512; ++ break; ++ case PBP_1024: ++ pHalData->HwRxPageSize = 1024; ++ break; ++ default: ++ //RT_ASSERT(FALSE, ("RX_PAGE_SIZE_REG_VALUE definition is incorrect!\n")); ++ break; ++ } ++#endif ++} // usb_AggSettingRxUpdate ++ ++static VOID ++InitUsbAggregationSetting( ++ IN PADAPTER Adapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ // Tx aggregation setting ++ usb_AggSettingTxUpdate(Adapter); ++ ++ // Rx aggregation setting ++ usb_AggSettingRxUpdate(Adapter); ++ ++ // 201/12/10 MH Add for USB agg mode dynamic switch. ++ pHalData->UsbRxHighSpeedMode = _FALSE; ++} ++VOID ++HalRxAggr8188EUsb( ++ IN PADAPTER Adapter, ++ IN BOOLEAN Value ++ ) ++{ ++#if 0//USB_RX_AGGREGATION_92C ++ ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ u1Byte valueDMATimeout; ++ u1Byte valueDMAPageCount; ++ u1Byte valueUSBTimeout; ++ u1Byte valueUSBBlockCount; ++ ++ // selection to prevent bad TP. ++ if( IS_WIRELESS_MODE_B(Adapter) || IS_WIRELESS_MODE_G(Adapter) || IS_WIRELESS_MODE_A(Adapter)|| pMgntInfo->bWiFiConfg) ++ { ++ // 2010.04.27 hpfan ++ // Adjust RxAggrTimeout to close to zero disable RxAggr, suggested by designer ++ // Timeout value is calculated by 34 / (2^n) ++ valueDMATimeout = 0x0f; ++ valueDMAPageCount = 0x01; ++ valueUSBTimeout = 0x0f; ++ valueUSBBlockCount = 0x01; ++ rtw_hal_set_hwreg(Adapter, HW_VAR_RX_AGGR_PGTO, (pu1Byte)&valueDMATimeout); ++ rtw_hal_set_hwreg(Adapter, HW_VAR_RX_AGGR_PGTH, (pu1Byte)&valueDMAPageCount); ++ rtw_hal_set_hwreg(Adapter, HW_VAR_RX_AGGR_USBTO, (pu1Byte)&valueUSBTimeout); ++ rtw_hal_set_hwreg(Adapter, HW_VAR_RX_AGGR_USBTH, (pu1Byte)&valueUSBBlockCount); ++ } ++ else ++ { ++ rtw_hal_set_hwreg(Adapter, HW_VAR_RX_AGGR_USBTO, (pu1Byte)&pMgntInfo->RegRxAggBlockTimeout); ++ rtw_hal_set_hwreg(Adapter, HW_VAR_RX_AGGR_USBTH, (pu1Byte)&pMgntInfo->RegRxAggBlockCount); ++ } ++ ++#endif ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: USB_AggModeSwitch() ++ * ++ * Overview: When RX traffic is more than 40M, we need to adjust some parameters to increase ++ * RX speed by increasing batch indication size. This will decrease TCP ACK speed, we ++ * need to monitor the influence of FTP/network share. ++ * For TX mode, we are still ubder investigation. ++ * ++ * Input: PADAPTER ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 12/10/2010 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++VOID ++USB_AggModeSwitch( ++ IN PADAPTER Adapter ++ ) ++{ ++#if 0 ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ ++ //pHalData->UsbRxHighSpeedMode = FALSE; ++ // How to measure the RX speed? We assume that when traffic is more than ++ if (pMgntInfo->bRegAggDMEnable == FALSE) ++ { ++ return; // Inf not support. ++ } ++ ++ ++ if (pMgntInfo->LinkDetectInfo.bHigherBusyRxTraffic == TRUE && ++ pHalData->UsbRxHighSpeedMode == FALSE) ++ { ++ pHalData->UsbRxHighSpeedMode = TRUE; ++ RT_TRACE(COMP_INIT, DBG_LOUD, ("UsbAggModeSwitchCheck to HIGH\n")); ++ } ++ else if (pMgntInfo->LinkDetectInfo.bHigherBusyRxTraffic == FALSE && ++ pHalData->UsbRxHighSpeedMode == TRUE) ++ { ++ pHalData->UsbRxHighSpeedMode = FALSE; ++ RT_TRACE(COMP_INIT, DBG_LOUD, ("UsbAggModeSwitchCheck to LOW\n")); ++ } ++ else ++ { ++ return; ++ } ++ ++ ++#if USB_RX_AGGREGATION_92C ++ if (pHalData->UsbRxHighSpeedMode == TRUE) ++ { ++ // 2010/12/10 MH The parameter is tested by SD1 engineer and SD3 channel emulator. ++ // USB mode ++#if (RT_PLATFORM == PLATFORM_LINUX) ++ if (pMgntInfo->LinkDetectInfo.bTxBusyTraffic) ++ { ++ pHalData->RxAggBlockCount = 16; ++ pHalData->RxAggBlockTimeout = 7; ++ } ++ else ++#endif ++ { ++ pHalData->RxAggBlockCount = 40; ++ pHalData->RxAggBlockTimeout = 5; ++ } ++ // Mix mode ++ pHalData->RxAggPageCount = 72; ++ pHalData->RxAggPageTimeout = 6; ++ } ++ else ++ { ++ // USB mode ++ pHalData->RxAggBlockCount = pMgntInfo->RegRxAggBlockCount; ++ pHalData->RxAggBlockTimeout = pMgntInfo->RegRxAggBlockTimeout; ++ // Mix mode ++ pHalData->RxAggPageCount = pMgntInfo->RegRxAggPageCount; ++ pHalData->RxAggPageTimeout = pMgntInfo->RegRxAggPageTimeout; ++ } ++ ++ if (pHalData->RxAggBlockCount > MAX_RX_AGG_BLKCNT) ++ pHalData->RxAggBlockCount = MAX_RX_AGG_BLKCNT; ++#if (OS_WIN_FROM_VISTA(OS_VERSION)) || (RT_PLATFORM == PLATFORM_LINUX) // do not support WINXP to prevent usbehci.sys BSOD ++ if (IS_WIRELESS_MODE_N_24G(Adapter) || IS_WIRELESS_MODE_N_5G(Adapter)) ++ { ++ // ++ // 2010/12/24 MH According to V1012 QC IOT test, XP BSOD happen when running chariot test ++ // with the aggregation dynamic change!! We need to disable the function to prevent it is broken ++ // in usbehci.sys. ++ // ++ usb_AggSettingRxUpdate_8188E(Adapter); ++ ++ // 2010/12/27 MH According to designer's suggstion, we can only modify Timeout value. Otheriwse ++ // there might many HW incorrect behavior, the XP BSOD at usbehci.sys may be relative to the ++ // issue. Base on the newest test, we can not enable block cnt > 30, otherwise XP usbehci.sys may ++ // BSOD. ++ } ++#endif ++ ++#endif ++#endif ++} // USB_AggModeSwitch ++ ++static VOID ++_InitOperationMode( ++ IN PADAPTER Adapter ++ ) ++{ ++#if 0//gtest ++ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); ++ u1Byte regBwOpMode = 0; ++ u4Byte regRATR = 0, regRRSR = 0; ++ ++ ++ //1 This part need to modified according to the rate set we filtered!! ++ // ++ // Set RRSR, RATR, and REG_BWOPMODE registers ++ // ++ switch(Adapter->RegWirelessMode) ++ { ++ case WIRELESS_MODE_B: ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK; ++ regRRSR = RATE_ALL_CCK; ++ break; ++ case WIRELESS_MODE_A: ++ regBwOpMode = BW_OPMODE_5G |BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_OFDM_AG; ++ regRRSR = RATE_ALL_OFDM_AG; ++ break; ++ case WIRELESS_MODE_G: ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ break; ++ case WIRELESS_MODE_AUTO: ++ if (Adapter->bInHctTest) ++ { ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ } ++ else ++ { ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; ++ regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ } ++ break; ++ case WIRELESS_MODE_N_24G: ++ // It support CCK rate by default. ++ // CCK rate will be filtered out only when associated AP does not support it. ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; ++ regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ break; ++ case WIRELESS_MODE_N_5G: ++ regBwOpMode = BW_OPMODE_5G; ++ regRATR = RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; ++ regRRSR = RATE_ALL_OFDM_AG; ++ break; ++ ++ default: //for MacOSX compiler warning. ++ break; ++ } ++ ++ // Ziv ???????? ++ //PlatformEFIOWrite4Byte(Adapter, REG_INIRTS_RATE_SEL, regRRSR); ++ PlatformEFIOWrite1Byte(Adapter, REG_BWOPMODE, regBwOpMode); ++#endif ++} ++ ++ ++ static VOID ++_InitBeaconParameters( ++ IN PADAPTER Adapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ rtw_write16(Adapter, REG_BCN_CTRL, 0x1010); ++ ++ // TODO: Remove these magic number ++ rtw_write16(Adapter, REG_TBTT_PROHIBIT,0x6404);// ms ++ rtw_write8(Adapter, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME);// 5ms ++ rtw_write8(Adapter, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME); // 2ms ++ ++ // Suggested by designer timchen. Change beacon AIFS to the largest number ++ // beacause test chip does not contension before sending beacon. by tynli. 2009.11.03 ++ rtw_write16(Adapter, REG_BCNTCFG, 0x660F); ++ ++ pHalData->RegBcnCtrlVal = rtw_read8(Adapter, REG_BCN_CTRL); ++ pHalData->RegTxPause = rtw_read8(Adapter, REG_TXPAUSE); ++ pHalData->RegFwHwTxQCtrl = rtw_read8(Adapter, REG_FWHW_TXQ_CTRL+2); ++ pHalData->RegReg542 = rtw_read8(Adapter, REG_TBTT_PROHIBIT+2); ++ pHalData->RegCR_1 = rtw_read8(Adapter, REG_CR+1); ++} ++ ++static VOID ++_InitRFType( ++ IN PADAPTER Adapter ++ ) ++{ ++ struct registry_priv *pregpriv = &Adapter->registrypriv; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ BOOLEAN is92CU = IS_92C_SERIAL(pHalData->VersionID); ++ ++#if DISABLE_BB_RF ++ pHalData->rf_chip = RF_PSEUDO_11N; ++ return; ++#endif ++ ++ pHalData->rf_chip = RF_6052; ++ ++ if(_FALSE == is92CU){ ++ pHalData->rf_type = RF_1T1R; ++ DBG_8192C("Set RF Chip ID to RF_6052 and RF type to 1T1R.\n"); ++ return; ++ } ++ ++ // TODO: Consider that EEPROM set 92CU to 1T1R later. ++ // Force to overwrite setting according to chip version. Ignore EEPROM setting. ++ //pHalData->RF_Type = is92CU ? RF_2T2R : RF_1T1R; ++ MSG_8192C("Set RF Chip ID to RF_6052 and RF type to %d.\n", pHalData->rf_type); ++ ++} ++ ++ ++static VOID ++_BeaconFunctionEnable( ++ IN PADAPTER Adapter, ++ IN BOOLEAN Enable, ++ IN BOOLEAN Linked ++ ) ++{ ++ rtw_write8(Adapter, REG_BCN_CTRL, (BIT4 | BIT3 | BIT1)); ++ //SetBcnCtrlReg(Adapter, (BIT4 | BIT3 | BIT1), 0x00); ++ //RT_TRACE(COMP_BEACON, DBG_LOUD, ("_BeaconFunctionEnable 0x550 0x%x\n", PlatformEFIORead1Byte(Adapter, 0x550))); ++ ++ rtw_write8(Adapter, REG_RD_CTRL+1, 0x6F); ++} ++ ++ ++// Set CCK and OFDM Block "ON" ++static VOID _BBTurnOnBlock( ++ IN PADAPTER Adapter ++ ) ++{ ++#if (DISABLE_BB_RF) ++ return; ++#endif ++ ++ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bCCKEn, 0x1); ++ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bOFDMEn, 0x1); ++} ++ ++static VOID _RfPowerSave( ++ IN PADAPTER Adapter ++ ) ++{ ++#if 0 ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ u1Byte eRFPath; ++ ++#if (DISABLE_BB_RF) ++ return; ++#endif ++ ++ if(pMgntInfo->RegRfOff == TRUE){ // User disable RF via registry. ++ RT_TRACE((COMP_INIT|COMP_RF), DBG_LOUD, ("InitializeAdapter8192CUsb(): Turn off RF for RegRfOff.\n")); ++ MgntActSet_RF_State(Adapter, eRfOff, RF_CHANGE_BY_SW); ++ // Those action will be discard in MgntActSet_RF_State because off the same state ++ for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) ++ PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x0); ++ } ++ else if(pMgntInfo->RfOffReason > RF_CHANGE_BY_PS){ // H/W or S/W RF OFF before sleep. ++ RT_TRACE((COMP_INIT|COMP_RF), DBG_LOUD, ("InitializeAdapter8192CUsb(): Turn off RF for RfOffReason(%ld).\n", pMgntInfo->RfOffReason)); ++ MgntActSet_RF_State(Adapter, eRfOff, pMgntInfo->RfOffReason); ++ } ++ else{ ++ pHalData->eRFPowerState = eRfOn; ++ pMgntInfo->RfOffReason = 0; ++ if(Adapter->bInSetPower || Adapter->bResetInProgress) ++ PlatformUsbEnableInPipes(Adapter); ++ RT_TRACE((COMP_INIT|COMP_RF), DBG_LOUD, ("InitializeAdapter8192CUsb(): RF is on.\n")); ++ } ++#endif ++} ++ ++enum { ++ Antenna_Lfet = 1, ++ Antenna_Right = 2, ++}; ++ ++static VOID ++_InitAntenna_Selection(IN PADAPTER Adapter) ++{ ++ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ if(pHalData->AntDivCfg==0) ++ return; ++ DBG_8192C("==> %s ....\n",__FUNCTION__); ++ ++ rtw_write32(Adapter, REG_LEDCFG0, rtw_read32(Adapter, REG_LEDCFG0)|BIT23); ++ PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter, BIT13, 0x01); ++ ++ if(PHY_QueryBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300) == Antenna_A) ++ pHalData->CurAntenna = Antenna_A; ++ else ++ pHalData->CurAntenna = Antenna_B; ++ DBG_8192C("%s,Cur_ant:(%x)%s\n",__FUNCTION__,pHalData->CurAntenna,(pHalData->CurAntenna == Antenna_A)?"Antenna_A":"Antenna_B"); ++ ++ ++} ++ ++// ++// 2010/08/26 MH Add for selective suspend mode check. ++// If Efuse 0x0e bit1 is not enabled, we can not support selective suspend for Minicard and ++// slim card. ++// ++static VOID ++HalDetectSelectiveSuspendMode( ++ IN PADAPTER Adapter ++ ) ++{ ++#if 0 ++ u8 tmpvalue; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter); ++ ++ // If support HW radio detect, we need to enable WOL ability, otherwise, we ++ // can not use FW to notify host the power state switch. ++ ++ EFUSE_ShadowRead(Adapter, 1, EEPROM_USB_OPTIONAL1, (u32 *)&tmpvalue); ++ ++ DBG_8192C("HalDetectSelectiveSuspendMode(): SS "); ++ if(tmpvalue & BIT1) ++ { ++ DBG_8192C("Enable\n"); ++ } ++ else ++ { ++ DBG_8192C("Disable\n"); ++ pdvobjpriv->RegUsbSS = _FALSE; ++ } ++ ++ // 2010/09/01 MH According to Dongle Selective Suspend INF. We can switch SS mode. ++ if (pdvobjpriv->RegUsbSS && !SUPPORT_HW_RADIO_DETECT(pHalData)) ++ { ++ //PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ ++ //if (!pMgntInfo->bRegDongleSS) ++ //{ ++ // RT_TRACE(COMP_INIT, DBG_LOUD, ("Dongle disable SS\n")); ++ pdvobjpriv->RegUsbSS = _FALSE; ++ //} ++ } ++#endif ++} // HalDetectSelectiveSuspendMode ++/*----------------------------------------------------------------------------- ++ * Function: HwSuspendModeEnable92Cu() ++ * ++ * Overview: HW suspend mode switch. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 08/23/2010 MHC HW suspend mode switch test.. ++ *---------------------------------------------------------------------------*/ ++static VOID ++HwSuspendModeEnable_88eu( ++ IN PADAPTER pAdapter, ++ IN u8 Type ++ ) ++{ ++ //PRT_USB_DEVICE pDevice = GET_RT_USB_DEVICE(pAdapter); ++ u16 reg = rtw_read16(pAdapter, REG_GPIO_MUXCFG); ++ ++ //if (!pDevice->RegUsbSS) ++ { ++ return; ++ } ++ ++ // ++ // 2010/08/23 MH According to Alfred's suggestion, we need to to prevent HW ++ // to enter suspend mode automatically. Otherwise, it will shut down major power ++ // domain and 8051 will stop. When we try to enter selective suspend mode, we ++ // need to prevent HW to enter D2 mode aumotmatically. Another way, Host will ++ // issue a S10 signal to power domain. Then it will cleat SIC setting(from Yngli). ++ // We need to enable HW suspend mode when enter S3/S4 or disable. We need ++ // to disable HW suspend mode for IPS/radio_off. ++ // ++ //RT_TRACE(COMP_RF, DBG_LOUD, ("HwSuspendModeEnable92Cu = %d\n", Type)); ++ if (Type == _FALSE) ++ { ++ reg |= BIT14; ++ //RT_TRACE(COMP_RF, DBG_LOUD, ("REG_GPIO_MUXCFG = %x\n", reg)); ++ rtw_write16(pAdapter, REG_GPIO_MUXCFG, reg); ++ reg |= BIT12; ++ //RT_TRACE(COMP_RF, DBG_LOUD, ("REG_GPIO_MUXCFG = %x\n", reg)); ++ rtw_write16(pAdapter, REG_GPIO_MUXCFG, reg); ++ } ++ else ++ { ++ reg &= (~BIT12); ++ rtw_write16(pAdapter, REG_GPIO_MUXCFG, reg); ++ reg &= (~BIT14); ++ rtw_write16(pAdapter, REG_GPIO_MUXCFG, reg); ++ } ++ ++} // HwSuspendModeEnable92Cu ++rt_rf_power_state RfOnOffDetect(IN PADAPTER pAdapter ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ u8 val8; ++ rt_rf_power_state rfpowerstate = rf_off; ++ ++ if(adapter_to_pwrctl(pAdapter)->bHWPowerdown) ++ { ++ val8 = rtw_read8(pAdapter, REG_HSISR); ++ DBG_8192C("pwrdown, 0x5c(BIT7)=%02x\n", val8); ++ rfpowerstate = (val8 & BIT7) ? rf_off: rf_on; ++ } ++ else // rf on/off ++ { ++ rtw_write8( pAdapter, REG_MAC_PINMUX_CFG,rtw_read8(pAdapter, REG_MAC_PINMUX_CFG)&~(BIT3)); ++ val8 = rtw_read8(pAdapter, REG_GPIO_IO_SEL); ++ DBG_8192C("GPIO_IN=%02x\n", val8); ++ rfpowerstate = (val8 & BIT3) ? rf_on : rf_off; ++ } ++ return rfpowerstate; ++} // HalDetectPwrDownMode ++ ++void _ps_open_RF(_adapter *padapter); ++ ++u32 rtl8188eu_hal_init(PADAPTER Adapter) ++{ ++ u8 value8 = 0; ++ u16 value16; ++ u8 txpktbuf_bndy; ++ u32 status = _SUCCESS; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(Adapter); ++ struct registry_priv *pregistrypriv = &Adapter->registrypriv; ++ ++ rt_rf_power_state eRfPowerStateToSet; ++#ifdef CONFIG_BT_COEXIST ++ struct btcoexist_priv *pbtpriv = &(pHalData->bt_coexist); ++#endif ++ ++ u32 init_start_time = rtw_get_current_time(); ++ ++ ++#ifdef DBG_HAL_INIT_PROFILING ++ ++ enum HAL_INIT_STAGES { ++ HAL_INIT_STAGES_BEGIN = 0, ++ HAL_INIT_STAGES_INIT_PW_ON, ++ HAL_INIT_STAGES_MISC01, ++ HAL_INIT_STAGES_DOWNLOAD_FW, ++ HAL_INIT_STAGES_MAC, ++ HAL_INIT_STAGES_BB, ++ HAL_INIT_STAGES_RF, ++ HAL_INIT_STAGES_EFUSE_PATCH, ++ HAL_INIT_STAGES_INIT_LLTT, ++ ++ HAL_INIT_STAGES_MISC02, ++ HAL_INIT_STAGES_TURN_ON_BLOCK, ++ HAL_INIT_STAGES_INIT_SECURITY, ++ HAL_INIT_STAGES_MISC11, ++ HAL_INIT_STAGES_INIT_HAL_DM, ++ //HAL_INIT_STAGES_RF_PS, ++ HAL_INIT_STAGES_IQK, ++ HAL_INIT_STAGES_PW_TRACK, ++ HAL_INIT_STAGES_LCK, ++ //HAL_INIT_STAGES_MISC21, ++ //HAL_INIT_STAGES_INIT_PABIAS, ++ #ifdef CONFIG_BT_COEXIST ++ HAL_INIT_STAGES_BT_COEXIST, ++ #endif ++ //HAL_INIT_STAGES_ANTENNA_SEL, ++ //HAL_INIT_STAGES_MISC31, ++ HAL_INIT_STAGES_END, ++ HAL_INIT_STAGES_NUM ++ }; ++ ++ char * hal_init_stages_str[] = { ++ "HAL_INIT_STAGES_BEGIN", ++ "HAL_INIT_STAGES_INIT_PW_ON", ++ "HAL_INIT_STAGES_MISC01", ++ "HAL_INIT_STAGES_DOWNLOAD_FW", ++ "HAL_INIT_STAGES_MAC", ++ "HAL_INIT_STAGES_BB", ++ "HAL_INIT_STAGES_RF", ++ "HAL_INIT_STAGES_EFUSE_PATCH", ++ "HAL_INIT_STAGES_INIT_LLTT", ++ "HAL_INIT_STAGES_MISC02", ++ "HAL_INIT_STAGES_TURN_ON_BLOCK", ++ "HAL_INIT_STAGES_INIT_SECURITY", ++ "HAL_INIT_STAGES_MISC11", ++ "HAL_INIT_STAGES_INIT_HAL_DM", ++ //"HAL_INIT_STAGES_RF_PS", ++ "HAL_INIT_STAGES_IQK", ++ "HAL_INIT_STAGES_PW_TRACK", ++ "HAL_INIT_STAGES_LCK", ++ //"HAL_INIT_STAGES_MISC21", ++ #ifdef CONFIG_BT_COEXIST ++ "HAL_INIT_STAGES_BT_COEXIST", ++ #endif ++ //"HAL_INIT_STAGES_ANTENNA_SEL", ++ //"HAL_INIT_STAGES_MISC31", ++ "HAL_INIT_STAGES_END", ++ }; ++ ++ int hal_init_profiling_i; ++ u32 hal_init_stages_timestamp[HAL_INIT_STAGES_NUM]; //used to record the time of each stage's starting point ++ ++ for(hal_init_profiling_i=0;hal_init_profiling_iwowlan_wake_reason = rtw_read8(Adapter, REG_WOWLAN_WAKE_REASON); ++ DBG_8192C("%s wowlan_wake_reason: 0x%02x\n", ++ __func__, pwrctrlpriv->wowlan_wake_reason); ++ ++ if(rtw_read8(Adapter, REG_MCUFWDL)&BIT7){ /*&& ++ (pwrctrlpriv->wowlan_wake_reason & FWDecisionDisconnect)) {*/ ++ u8 reg_val=0; ++ DBG_8192C("+Reset Entry+\n"); ++ rtw_write8(Adapter, REG_MCUFWDL, 0x00); ++ _8051Reset88E(Adapter); ++ //reset BB ++ reg_val = rtw_read8(Adapter, REG_SYS_FUNC_EN); ++ reg_val &= ~(BIT(0) | BIT(1)); ++ rtw_write8(Adapter, REG_SYS_FUNC_EN, reg_val); ++ //reset RF ++ rtw_write8(Adapter, REG_RF_CTRL, 0); ++ //reset TRX path ++ rtw_write16(Adapter, REG_CR, 0); ++ //reset MAC, Digital Core ++ reg_val = rtw_read8(Adapter, REG_SYS_FUNC_EN+1); ++ reg_val &= ~(BIT(4) | BIT(7)); ++ rtw_write8(Adapter, REG_SYS_FUNC_EN+1, reg_val); ++ reg_val = rtw_read8(Adapter, REG_SYS_FUNC_EN+1); ++ reg_val |= BIT(4) | BIT(7); ++ rtw_write8(Adapter, REG_SYS_FUNC_EN+1, reg_val); ++ DBG_8192C("-Reset Entry-\n"); ++ } ++#endif //CONFIG_WOWLAN ++ ++ if(pwrctrlpriv->bkeepfwalive) ++ { ++ _ps_open_RF(Adapter); ++ ++ if(pHalData->odmpriv.RFCalibrateInfo.bIQKInitialized){ ++// PHY_IQCalibrate(padapter, _TRUE); ++ PHY_IQCalibrate_8188E(Adapter,_TRUE); ++ } ++ else ++ { ++// PHY_IQCalibrate(padapter, _FALSE); ++ PHY_IQCalibrate_8188E(Adapter,_FALSE); ++ pHalData->odmpriv.RFCalibrateInfo.bIQKInitialized = _TRUE; ++ } ++ ++// dm_CheckTXPowerTracking(padapter); ++// PHY_LCCalibrate(padapter); ++ ODM_TXPowerTrackingCheck(&pHalData->odmpriv ); ++ PHY_LCCalibrate_8188E(Adapter); ++ ++ goto exit; ++ } ++ ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PW_ON); ++ status = InitPowerOn_rtl8188eu(Adapter); ++ if(status == _FAIL){ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("Failed to init power on!\n")); ++ goto exit; ++ } ++ ++ // Save target channel ++ pHalData->CurrentChannel = 6;//default set to 6 ++ ++ ++ if(pwrctrlpriv->reg_rfoff == _TRUE){ ++ pwrctrlpriv->rf_pwrstate = rf_off; ++ } ++ ++ // 2010/08/09 MH We need to check if we need to turnon or off RF after detecting ++ // HW GPIO pin. Before PHY_RFConfig8192C. ++ //HalDetectPwrDownMode(Adapter); ++ // 2010/08/26 MH If Efuse does not support sective suspend then disable the function. ++ //HalDetectSelectiveSuspendMode(Adapter); ++ ++ if (!pregistrypriv->wifi_spec) { ++ txpktbuf_bndy = TX_PAGE_BOUNDARY_88E; ++ } else { ++ // for WMM ++ txpktbuf_bndy = WMM_NORMAL_TX_PAGE_BOUNDARY_88E; ++ } ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC01); ++ _InitQueueReservedPage(Adapter); ++ _InitQueuePriority(Adapter); ++ _InitPageBoundary(Adapter); ++ _InitTransferPageSize(Adapter); ++ ++#ifdef CONFIG_IOL_IOREG_CFG ++ _InitTxBufferBoundary(Adapter, 0); ++#endif ++ ++ ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_DOWNLOAD_FW); ++#if (MP_DRIVER == 1) ++ if (Adapter->registrypriv.mp_mode == 1) ++ { ++ _InitRxSetting(Adapter); ++ } ++#endif //MP_DRIVER == 1 ++ { ++ #if 0 ++ Adapter->bFWReady = _FALSE; //because no fw for test chip ++ pHalData->fw_ractrl = _FALSE; ++ #else ++ ++#ifdef CONFIG_WOWLAN ++ status = rtl8188e_FirmwareDownload(Adapter, _FALSE); ++#else ++ status = rtl8188e_FirmwareDownload(Adapter); ++#endif //CONFIG_WOWLAN ++ ++ if (status != _SUCCESS) { ++ DBG_871X("%s: Download Firmware failed!!\n", __FUNCTION__); ++ Adapter->bFWReady = _FALSE; ++ pHalData->fw_ractrl = _FALSE; ++ return status; ++ } else { ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Initializepadapter8192CSdio(): Download Firmware Success!!\n")); ++ Adapter->bFWReady = _TRUE; ++ pHalData->fw_ractrl = _FALSE; ++ } ++ #endif ++ } ++ ++ ++ rtl8188e_InitializeFirmwareVars(Adapter); ++ ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MAC); ++#if (HAL_MAC_ENABLE == 1) ++ status = PHY_MACConfig8188E(Adapter); ++ if(status == _FAIL) ++ { ++ DBG_871X(" ### Failed to init MAC ...... \n "); ++ goto exit; ++ } ++#endif ++ ++ // ++ //d. Initialize BB related configurations. ++ // ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BB); ++#if (HAL_BB_ENABLE == 1) ++ status = PHY_BBConfig8188E(Adapter); ++ if(status == _FAIL) ++ { ++ DBG_871X(" ### Failed to init BB ...... \n "); ++ goto exit; ++ } ++#endif ++ ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_RF); ++#if (HAL_RF_ENABLE == 1) ++ status = PHY_RFConfig8188E(Adapter); ++ if(status == _FAIL) ++ { ++ DBG_871X(" ### Failed to init RF ...... \n "); ++ goto exit; ++ } ++#endif ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_EFUSE_PATCH); ++#if defined(CONFIG_IOL_EFUSE_PATCH) ++ status = rtl8188e_iol_efuse_patch(Adapter); ++ if(status == _FAIL){ ++ DBG_871X("%s rtl8188e_iol_efuse_patch failed \n",__FUNCTION__); ++ goto exit; ++ } ++#endif ++ ++ _InitTxBufferBoundary(Adapter, txpktbuf_bndy); ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_LLTT); ++ status = InitLLTTable(Adapter, txpktbuf_bndy); ++ if(status == _FAIL){ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("Failed to init LLT table\n")); ++ goto exit; ++ } ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC02); ++ // Get Rx PHY status in order to report RSSI and others. ++ _InitDriverInfoSize(Adapter, DRVINFO_SZ); ++ ++ _InitInterrupt(Adapter); ++ hal_init_macaddr(Adapter);//set mac_address ++ _InitNetworkType(Adapter);//set msr ++ _InitWMACSetting(Adapter); ++ _InitAdaptiveCtrl(Adapter); ++ _InitEDCA(Adapter); ++ //_InitRateFallback(Adapter);//just follow MP Team ???Georgia ++ _InitRetryFunction(Adapter); ++ InitUsbAggregationSetting(Adapter); ++ _InitOperationMode(Adapter);//todo ++ _InitBeaconParameters(Adapter); ++ _InitBeaconMaxError(Adapter, _TRUE); ++ ++ // ++ // Init CR MACTXEN, MACRXEN after setting RxFF boundary REG_TRXFF_BNDY to patch ++ // Hw bug which Hw initials RxFF boundry size to a value which is larger than the real Rx buffer size in 88E. ++ // ++ // Enable MACTXEN/MACRXEN block ++ value16 = rtw_read16(Adapter, REG_CR); ++ value16 |= (MACTXEN | MACRXEN); ++ rtw_write8(Adapter, REG_CR, value16); ++ ++ ++ _InitHardwareDropIncorrectBulkOut(Adapter); ++ ++ ++ if(pHalData->bRDGEnable){ ++ _InitRDGSetting(Adapter); ++ } ++ ++#if (RATE_ADAPTIVE_SUPPORT==1) ++ {//Enable TX Report ++ //Enable Tx Report Timer ++ value8 = rtw_read8(Adapter, REG_TX_RPT_CTRL); ++ rtw_write8(Adapter, REG_TX_RPT_CTRL, (value8|BIT1|BIT0)); ++ //Set MAX RPT MACID ++ rtw_write8(Adapter, REG_TX_RPT_CTRL+1, 2);//FOR sta mode ,0: bc/mc ,1:AP ++ //Tx RPT Timer. Unit: 32us ++ rtw_write16(Adapter, REG_TX_RPT_TIME, 0xCdf0); ++ } ++#endif ++ ++#if 0 ++ if(pHTInfo->bRDGEnable){ ++ _InitRDGSetting_8188E(Adapter); ++ } ++#endif ++ ++#ifdef CONFIG_TX_EARLY_MODE ++ if( pHalData->bEarlyModeEnable) ++ { ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_,("EarlyMode Enabled!!!\n")); ++ ++ value8 = rtw_read8(Adapter, REG_EARLY_MODE_CONTROL); ++#if RTL8188E_EARLY_MODE_PKT_NUM_10 == 1 ++ value8 = value8|0x1f; ++#else ++ value8 = value8|0xf; ++#endif ++ rtw_write8(Adapter, REG_EARLY_MODE_CONTROL, value8); ++ ++ rtw_write8(Adapter, REG_EARLY_MODE_CONTROL+3, 0x80); ++ ++ value8 = rtw_read8(Adapter, REG_TCR+1); ++ value8 = value8|0x40; ++ rtw_write8(Adapter,REG_TCR+1, value8); ++ } ++ else ++#endif ++ { ++ rtw_write8(Adapter, REG_EARLY_MODE_CONTROL, 0); ++ } ++ ++ rtw_write32(Adapter,REG_MACID_NO_LINK_0,0xFFFFFFFF); ++ rtw_write32(Adapter,REG_MACID_NO_LINK_1,0xFFFFFFFF); ++ ++#if defined(CONFIG_CONCURRENT_MODE) || defined(CONFIG_TX_MCAST2UNI) ++ ++#ifdef CONFIG_CHECK_AC_LIFETIME ++ // Enable lifetime check for the four ACs ++ rtw_write8(Adapter, REG_LIFETIME_EN, 0x0F); ++#endif // CONFIG_CHECK_AC_LIFETIME ++ ++#ifdef CONFIG_TX_MCAST2UNI ++ rtw_write16(Adapter, REG_PKT_VO_VI_LIFE_TIME, 0x0400); // unit: 256us. 256ms ++ rtw_write16(Adapter, REG_PKT_BE_BK_LIFE_TIME, 0x0400); // unit: 256us. 256ms ++#else // CONFIG_TX_MCAST2UNI ++ rtw_write16(Adapter, REG_PKT_VO_VI_LIFE_TIME, 0x3000); // unit: 256us. 3s ++ rtw_write16(Adapter, REG_PKT_BE_BK_LIFE_TIME, 0x3000); // unit: 256us. 3s ++#endif // CONFIG_TX_MCAST2UNI ++#endif // CONFIG_CONCURRENT_MODE || CONFIG_TX_MCAST2UNI ++ ++ ++#ifdef CONFIG_LED ++ _InitHWLed(Adapter); ++#endif //CONFIG_LED ++ ++ ++ // ++ // Joseph Note: Keep RfRegChnlVal for later use. ++ // ++ pHalData->RfRegChnlVal[0] = PHY_QueryRFReg(Adapter, (RF_RADIO_PATH_E)0, RF_CHNLBW, bRFRegOffsetMask); ++ pHalData->RfRegChnlVal[1] = PHY_QueryRFReg(Adapter, (RF_RADIO_PATH_E)1, RF_CHNLBW, bRFRegOffsetMask); ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_TURN_ON_BLOCK); ++ _BBTurnOnBlock(Adapter); ++ //NicIFSetMacAddress(padapter, padapter->PermanentAddress); ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_SECURITY); ++ invalidate_cam_all(Adapter); ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC11); ++ // 2010/12/17 MH We need to set TX power according to EFUSE content at first. ++ PHY_SetTxPowerLevel8188E(Adapter, pHalData->CurrentChannel); ++ ++// Move by Neo for USB SS to below setp ++//_RfPowerSave(Adapter); ++ ++ _InitAntenna_Selection(Adapter); ++ ++ // ++ // Disable BAR, suggested by Scott ++ // 2010.04.09 add by hpfan ++ // ++ rtw_write32(Adapter, REG_BAR_MODE_CTRL, 0x0201ffff); ++ ++ // HW SEQ CTRL ++ //set 0x0 to 0xFF by tynli. Default enable HW SEQ NUM. ++ rtw_write8(Adapter,REG_HWSEQ_CTRL, 0xFF); ++ ++ if(pregistrypriv->wifi_spec) ++ rtw_write16(Adapter,REG_FAST_EDCA_CTRL ,0); ++ ++ //Nav limit , suggest by scott ++ rtw_write8(Adapter, 0x652, 0x0); ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_HAL_DM); ++ rtl8188e_InitHalDm(Adapter); ++ ++#if (MP_DRIVER == 1) ++ if (Adapter->registrypriv.mp_mode == 1) ++ { ++ Adapter->mppriv.channel = pHalData->CurrentChannel; ++ MPT_InitializeAdapter(Adapter, Adapter->mppriv.channel); ++ } ++ else ++#endif //#if (MP_DRIVER == 1) ++ { ++ // ++ // 2010/08/11 MH Merge from 8192SE for Minicard init. We need to confirm current radio status ++ // and then decide to enable RF or not.!!!??? For Selective suspend mode. We may not ++ // call init_adapter. May cause some problem?? ++ // ++ // Fix the bug that Hw/Sw radio off before S3/S4, the RF off action will not be executed ++ // in MgntActSet_RF_State() after wake up, because the value of pHalData->eRFPowerState ++ // is the same as eRfOff, we should change it to eRfOn after we config RF parameters. ++ // Added by tynli. 2010.03.30. ++ pwrctrlpriv->rf_pwrstate = rf_on; ++ ++#if 0 //to do ++ RT_CLEAR_PS_LEVEL(pwrctrlpriv, RT_RF_OFF_LEVL_HALT_NIC); ++#if 1 //Todo ++ // 20100326 Joseph: Copy from GPIOChangeRFWorkItemCallBack() function to check HW radio on/off. ++ // 20100329 Joseph: Revise and integrate the HW/SW radio off code in initialization. ++ ++ eRfPowerStateToSet = (rt_rf_power_state) RfOnOffDetect(Adapter); ++ pwrctrlpriv->rfoff_reason |= eRfPowerStateToSet==rf_on ? RF_CHANGE_BY_INIT : RF_CHANGE_BY_HW; ++ pwrctrlpriv->rfoff_reason |= (pwrctrlpriv->reg_rfoff) ? RF_CHANGE_BY_SW : 0; ++ ++ if(pwrctrlpriv->rfoff_reason&RF_CHANGE_BY_HW) ++ pwrctrlpriv->b_hw_radio_off = _TRUE; ++ ++ DBG_8192C("eRfPowerStateToSet=%d\n", eRfPowerStateToSet); ++ ++ if(pwrctrlpriv->reg_rfoff == _TRUE) ++ { // User disable RF via registry. ++ DBG_8192C("InitializeAdapter8192CU(): Turn off RF for RegRfOff.\n"); ++ //MgntActSet_RF_State(Adapter, rf_off, RF_CHANGE_BY_SW, _TRUE); ++ ++ // Those action will be discard in MgntActSet_RF_State because off the same state ++ //for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) ++ //PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x0); ++ } ++ else if(pwrctrlpriv->rfoff_reason > RF_CHANGE_BY_PS) ++ { // H/W or S/W RF OFF before sleep. ++ DBG_8192C(" Turn off RF for RfOffReason(%x) ----------\n", pwrctrlpriv->rfoff_reason); ++ //pwrctrlpriv->rfoff_reason = RF_CHANGE_BY_INIT; ++ pwrctrlpriv->rf_pwrstate = rf_on; ++ //MgntActSet_RF_State(Adapter, rf_off, pwrctrlpriv->rfoff_reason, _TRUE); ++ } ++ else ++ { ++ // Perform GPIO polling to find out current RF state. added by Roger, 2010.04.09. ++ if(pHalData->BoardType == BOARD_MINICARD /*&& (Adapter->MgntInfo.PowerSaveControl.bGpioRfSw)*/) ++ { ++ DBG_8192C("InitializeAdapter8192CU(): RF=%d \n", eRfPowerStateToSet); ++ if (eRfPowerStateToSet == rf_off) ++ { ++ //MgntActSet_RF_State(Adapter, rf_off, RF_CHANGE_BY_HW, _TRUE); ++ pwrctrlpriv->b_hw_radio_off = _TRUE; ++ } ++ else ++ { ++ pwrctrlpriv->rf_pwrstate = rf_off; ++ pwrctrlpriv->rfoff_reason = RF_CHANGE_BY_INIT; ++ pwrctrlpriv->b_hw_radio_off = _FALSE; ++ //MgntActSet_RF_State(Adapter, rf_on, pwrctrlpriv->rfoff_reason, _TRUE); ++ } ++ } ++ else ++ { ++ pwrctrlpriv->rf_pwrstate = rf_off; ++ pwrctrlpriv->rfoff_reason = RF_CHANGE_BY_INIT; ++ //MgntActSet_RF_State(Adapter, rf_on, pwrctrlpriv->rfoff_reason, _TRUE); ++ } ++ ++ pwrctrlpriv->rfoff_reason = 0; ++ pwrctrlpriv->b_hw_radio_off = _FALSE; ++ pwrctrlpriv->rf_pwrstate = rf_on; ++ rtw_led_control(Adapter, LED_CTL_POWER_ON); ++ ++ } ++ ++ // 2010/-8/09 MH For power down module, we need to enable register block contrl reg at 0x1c. ++ // Then enable power down control bit of register 0x04 BIT4 and BIT15 as 1. ++ if(pHalData->pwrdown && eRfPowerStateToSet == rf_off) ++ { ++ // Enable register area 0x0-0xc. ++ rtw_write8(Adapter, REG_RSV_CTRL, 0x0); ++ ++ // ++ // We should configure HW PDn source for WiFi ONLY, and then ++ // our HW will be set in power-down mode if PDn source from all functions are configured. ++ // 2010.10.06. ++ // ++ //if(IS_HARDWARE_TYPE_8723AU(Adapter)) ++ //{ ++ // u1bTmp = rtw_read8(Adapter, REG_MULTI_FUNC_CTRL); ++ // rtw_write8(Adapter, REG_MULTI_FUNC_CTRL, (u1bTmp|WL_HWPDN_EN)); ++ //} ++ //else ++ //{ ++ rtw_write16(Adapter, REG_APS_FSMCO, 0x8812); ++ //} ++ } ++ //DrvIFIndicateCurrentPhyStatus(Adapter); // 2010/08/17 MH Disable to prevent BSOD. ++#endif ++#endif ++ ++ ++ // enable Tx report. ++ rtw_write8(Adapter, REG_FWHW_TXQ_CTRL+1, 0x0F); ++ ++ // Suggested by SD1 pisa. Added by tynli. 2011.10.21. ++ rtw_write8(Adapter, REG_EARLY_MODE_CONTROL+3, 0x01);//Pretx_en, for WEP/TKIP SEC ++ ++ //tynli_test_tx_report. ++ rtw_write16(Adapter, REG_TX_RPT_TIME, 0x3DF0); ++ //RT_TRACE(COMP_INIT, DBG_TRACE, ("InitializeAdapter8188EUsb() <====\n")); ++ ++ //enable tx DMA to drop the redundate data of packet ++ rtw_write16(Adapter,REG_TXDMA_OFFSET_CHK, (rtw_read16(Adapter,REG_TXDMA_OFFSET_CHK) | DROP_DATA_EN)); ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_IQK); ++ // 2010/08/26 MH Merge from 8192CE. ++ if(pwrctrlpriv->rf_pwrstate == rf_on) ++ { ++ if(pHalData->odmpriv.RFCalibrateInfo.bIQKInitialized){ ++ PHY_IQCalibrate_8188E(Adapter,_TRUE); ++ } ++ else ++ { ++ PHY_IQCalibrate_8188E(Adapter,_FALSE); ++ pHalData->odmpriv.RFCalibrateInfo.bIQKInitialized = _TRUE; ++ } ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_PW_TRACK); ++ ++ ODM_TXPowerTrackingCheck(&pHalData->odmpriv ); ++ ++ ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_LCK); ++ PHY_LCCalibrate_8188E(Adapter); ++ } ++} ++ ++//HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PABIAS); ++// _InitPABias(Adapter); ++ rtw_write8(Adapter, REG_USB_HRPWM, 0); ++ ++#ifdef CONFIG_XMIT_ACK ++ //ack for xmit mgmt frames. ++ rtw_write32(Adapter, REG_FWHW_TXQ_CTRL, rtw_read32(Adapter, REG_FWHW_TXQ_CTRL)|BIT(12)); ++#endif //CONFIG_XMIT_ACK ++ ++exit: ++HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_END); ++ ++ DBG_871X("%s in %dms\n", __FUNCTION__, rtw_get_passing_time_ms(init_start_time)); ++ ++ #ifdef DBG_HAL_INIT_PROFILING ++ hal_init_stages_timestamp[HAL_INIT_STAGES_END]=rtw_get_current_time(); ++ ++ for(hal_init_profiling_i=0;hal_init_profiling_iMgntInfo); ++ u8 val8; ++ u16 val16; ++ u32 val32; ++ u8 bMacPwrCtrlOn=_FALSE; ++ ++ rtw_hal_get_hwreg(Adapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if(bMacPwrCtrlOn == _FALSE) ++ return ; ++ ++ RT_TRACE(COMP_INIT, DBG_LOUD, ("%s\n",__FUNCTION__)); ++ ++ //Stop Tx Report Timer. 0x4EC[Bit1]=b'0 ++ val8 = rtw_read8(Adapter, REG_TX_RPT_CTRL); ++ rtw_write8(Adapter, REG_TX_RPT_CTRL, val8&(~BIT1)); ++ ++ // stop rx ++ rtw_write8(Adapter, REG_CR, 0x0); ++ ++ // Run LPS WL RFOFF flow ++ HalPwrSeqCmdParsing(Adapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, Rtl8188E_NIC_LPS_ENTER_FLOW); ++ ++ ++ // 2. 0x1F[7:0] = 0 // turn off RF ++ //rtw_write8(Adapter, REG_RF_CTRL, 0x00); ++ ++ val8 = rtw_read8(Adapter, REG_MCUFWDL); ++ if ((val8 & RAM_DL_SEL) && Adapter->bFWReady) //8051 RAM code ++ { ++ //rtl8723a_FirmwareSelfReset(padapter); ++ //_8051Reset88E(padapter); ++ ++ // Reset MCU 0x2[10]=0. ++ val8 = rtw_read8(Adapter, REG_SYS_FUNC_EN+1); ++ val8 &= ~BIT(2); // 0x2[10], FEN_CPUEN ++ rtw_write8(Adapter, REG_SYS_FUNC_EN+1, val8); ++ } ++ ++ //val8 = rtw_read8(Adapter, REG_SYS_FUNC_EN+1); ++ //val8 &= ~BIT(2); // 0x2[10], FEN_CPUEN ++ //rtw_write8(Adapter, REG_SYS_FUNC_EN+1, val8); ++ ++ // MCUFWDL 0x80[1:0]=0 ++ // reset MCU ready status ++ rtw_write8(Adapter, REG_MCUFWDL, 0); ++ ++ //YJ,add,111212 ++ //Disable 32k ++ val8 = rtw_read8(Adapter, REG_32K_CTRL); ++ rtw_write8(Adapter, REG_32K_CTRL, val8&(~BIT0)); ++ ++ // Card disable power action flow ++ HalPwrSeqCmdParsing(Adapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, Rtl8188E_NIC_DISABLE_FLOW); ++ ++ // Reset MCU IO Wrapper ++ val8 = rtw_read8(Adapter, REG_RSV_CTRL+1); ++ rtw_write8(Adapter, REG_RSV_CTRL+1, (val8&(~BIT3))); ++ val8 = rtw_read8(Adapter, REG_RSV_CTRL+1); ++ rtw_write8(Adapter, REG_RSV_CTRL+1, val8|BIT3); ++ ++#if 0 ++ // 7. RSV_CTRL 0x1C[7:0] = 0x0E // lock ISO/CLK/Power control register ++ rtw_write8(Adapter, REG_RSV_CTRL, 0x0e); ++#endif ++#if 1 ++ //YJ,test add, 111207. For Power Consumption. ++ val8 = rtw_read8(Adapter, GPIO_IN); ++ rtw_write8(Adapter, GPIO_OUT, val8); ++ rtw_write8(Adapter, GPIO_IO_SEL, 0xFF);//Reg0x46 ++ ++ val8 = rtw_read8(Adapter, REG_GPIO_IO_SEL); ++ //rtw_write8(Adapter, REG_GPIO_IO_SEL, (val8<<4)|val8); ++ rtw_write8(Adapter, REG_GPIO_IO_SEL, (val8<<4)); ++ val8 = rtw_read8(Adapter, REG_GPIO_IO_SEL+1); ++ rtw_write8(Adapter, REG_GPIO_IO_SEL+1, val8|0x0F);//Reg0x43 ++ rtw_write32(Adapter, REG_BB_PAD_CTRL, 0x00080808);//set LNA ,TRSW,EX_PA Pin to output mode ++#endif ++ bMacPwrCtrlOn = _FALSE; ++ rtw_hal_set_hwreg(Adapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ Adapter->bFWReady = _FALSE; ++} ++static void rtl8188eu_hw_power_down(_adapter *padapter) ++{ ++ // 2010/-8/09 MH For power down module, we need to enable register block contrl reg at 0x1c. ++ // Then enable power down control bit of register 0x04 BIT4 and BIT15 as 1. ++ ++ // Enable register area 0x0-0xc. ++ rtw_write8(padapter,REG_RSV_CTRL, 0x0); ++ rtw_write16(padapter, REG_APS_FSMCO, 0x8812); ++} ++ ++u32 rtl8188eu_hal_deinit(PADAPTER Adapter) ++ { ++ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(Adapter); ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ DBG_8192C("==> %s \n",__FUNCTION__); ++ ++#ifdef CONFIG_SUPPORT_USB_INT ++ rtw_write32(Adapter, REG_HIMR_88E, IMR_DISABLED_88E); ++ rtw_write32(Adapter, REG_HIMRE_88E, IMR_DISABLED_88E); ++#endif ++ ++ #ifdef SUPPORT_HW_RFOFF_DETECTED ++ DBG_8192C("bkeepfwalive(%x)\n", pwrctl->bkeepfwalive); ++ if(pwrctl->bkeepfwalive) ++ { ++ _ps_close_RF(Adapter); ++ if((pwrctl->bHWPwrPindetect) && (pwrctl->bHWPowerdown)) ++ rtl8188eu_hw_power_down(Adapter); ++ } ++ else ++#endif ++ { ++ if(Adapter->hw_init_completed == _TRUE){ ++ hal_poweroff_rtl8188eu(Adapter); ++ ++ if((pwrctl->bHWPwrPindetect ) && (pwrctl->bHWPowerdown)) ++ rtl8188eu_hw_power_down(Adapter); ++ ++ } ++ } ++ return _SUCCESS; ++ } ++ ++ ++unsigned int rtl8188eu_inirp_init(PADAPTER Adapter) ++{ ++ u8 i; ++ struct recv_buf *precvbuf; ++ uint status; ++ struct dvobj_priv *pdev= adapter_to_dvobj(Adapter); ++ struct intf_hdl * pintfhdl=&Adapter->iopriv.intf; ++ struct recv_priv *precvpriv = &(Adapter->recvpriv); ++ u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++#ifdef CONFIG_USB_INTERRUPT_IN_PIPE ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u32 (*_read_interrupt)(struct intf_hdl *pintfhdl, u32 addr); ++#endif ++ ++_func_enter_; ++ ++ _read_port = pintfhdl->io_ops._read_port; ++ ++ status = _SUCCESS; ++ ++ RT_TRACE(_module_hci_hal_init_c_,_drv_info_,("===> usb_inirp_init \n")); ++ ++ precvpriv->ff_hwaddr = RECV_BULK_IN_ADDR; ++ ++ //issue Rx irp to receive data ++ precvbuf = (struct recv_buf *)precvpriv->precv_buf; ++ for(i=0; iff_hwaddr, 0, (unsigned char *)precvbuf) == _FALSE ) ++ { ++ RT_TRACE(_module_hci_hal_init_c_,_drv_err_,("usb_rx_init: usb_read_port error \n")); ++ status = _FAIL; ++ goto exit; ++ } ++ ++ precvbuf++; ++ precvpriv->free_recv_buf_queue_cnt--; ++ } ++ ++#ifdef CONFIG_USB_INTERRUPT_IN_PIPE ++ if(pHalData->RtIntInPipe != 0x05) ++ { ++ status = _FAIL; ++ DBG_871X("%s =>Warning !! Have not USB Int-IN pipe, pHalData->RtIntInPipe(%d)!!!\n",__FUNCTION__,pHalData->RtIntInPipe); ++ goto exit; ++ } ++ _read_interrupt = pintfhdl->io_ops._read_interrupt; ++ if(_read_interrupt(pintfhdl, RECV_INT_IN_ADDR) == _FALSE ) ++ { ++ RT_TRACE(_module_hci_hal_init_c_,_drv_err_,("usb_rx_init: usb_read_interrupt error \n")); ++ status = _FAIL; ++ } ++#endif ++ ++exit: ++ ++ RT_TRACE(_module_hci_hal_init_c_,_drv_info_,("<=== usb_inirp_init \n")); ++ ++_func_exit_; ++ ++ return status; ++ ++} ++ ++unsigned int rtl8188eu_inirp_deinit(PADAPTER Adapter) ++{ ++ RT_TRACE(_module_hci_hal_init_c_,_drv_info_,("\n ===> usb_rx_deinit \n")); ++ ++ rtw_read_port_cancel(Adapter); ++ ++ RT_TRACE(_module_hci_hal_init_c_,_drv_info_,("\n <=== usb_rx_deinit \n")); ++ ++ return _SUCCESS; ++} ++ ++ ++ ++//------------------------------------------------------------------------- ++// ++// EEPROM Power index mapping ++// ++//------------------------------------------------------------------------- ++#if 0 ++ static VOID ++_ReadPowerValueFromPROM( ++ IN PTxPowerInfo pwrInfo, ++ IN u8* PROMContent, ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++ u32 rfPath, eeAddr, group; ++ ++ _rtw_memset(pwrInfo, 0, sizeof(TxPowerInfo)); ++ ++ if(AutoLoadFail){ ++ for(group = 0 ; group < CHANNEL_GROUP_MAX ; group++){ ++ for(rfPath = 0 ; rfPath < RF_PATH_MAX ; rfPath++){ ++ pwrInfo->CCKIndex[rfPath][group] = EEPROM_Default_TxPowerLevel; ++ pwrInfo->HT40_1SIndex[rfPath][group] = EEPROM_Default_TxPowerLevel; ++ pwrInfo->HT40_2SIndexDiff[rfPath][group]= EEPROM_Default_HT40_2SDiff; ++ pwrInfo->HT20IndexDiff[rfPath][group] = EEPROM_Default_HT20_Diff; ++ pwrInfo->OFDMIndexDiff[rfPath][group] = EEPROM_Default_LegacyHTTxPowerDiff; ++ pwrInfo->HT40MaxOffset[rfPath][group] = EEPROM_Default_HT40_PwrMaxOffset; ++ pwrInfo->HT20MaxOffset[rfPath][group] = EEPROM_Default_HT20_PwrMaxOffset; ++ } ++ } ++ ++ pwrInfo->TSSI_A = EEPROM_Default_TSSI; ++ pwrInfo->TSSI_B = EEPROM_Default_TSSI; ++ ++ return; ++ } ++ ++ for(rfPath = 0 ; rfPath < RF_PATH_MAX ; rfPath++){ ++ for(group = 0 ; group < CHANNEL_GROUP_MAX ; group++){ ++ eeAddr = EEPROM_CCK_TX_PWR_INX + (rfPath * 3) + group; ++ pwrInfo->CCKIndex[rfPath][group] = PROMContent[eeAddr]; ++ ++ eeAddr = EEPROM_HT40_1S_TX_PWR_INX + (rfPath * 3) + group; ++ pwrInfo->HT40_1SIndex[rfPath][group] = PROMContent[eeAddr]; ++ } ++ } ++ ++ for(group = 0 ; group < CHANNEL_GROUP_MAX ; group++){ ++ for(rfPath = 0 ; rfPath < RF_PATH_MAX ; rfPath++){ ++ pwrInfo->HT40_2SIndexDiff[rfPath][group] = ++ (PROMContent[EEPROM_HT40_2S_TX_PWR_INX_DIFF + group] >> (rfPath * 4)) & 0xF; ++ ++#if 1 ++ pwrInfo->HT20IndexDiff[rfPath][group] = ++ (PROMContent[EEPROM_HT20_TX_PWR_INX_DIFF + group] >> (rfPath * 4)) & 0xF; ++ if(pwrInfo->HT20IndexDiff[rfPath][group] & BIT3) //4bit sign number to 8 bit sign number ++ pwrInfo->HT20IndexDiff[rfPath][group] |= 0xF0; ++#else ++ pwrInfo->HT20IndexDiff[rfPath][group] = ++ (PROMContent[EEPROM_HT20_TX_PWR_INX_DIFF + group] >> (rfPath * 4)) & 0xF; ++#endif ++ ++ pwrInfo->OFDMIndexDiff[rfPath][group] = ++ (PROMContent[EEPROM_OFDM_TX_PWR_INX_DIFF+ group] >> (rfPath * 4)) & 0xF; ++ ++ pwrInfo->HT40MaxOffset[rfPath][group] = ++ (PROMContent[EEPROM_HT40_MAX_PWR_OFFSET+ group] >> (rfPath * 4)) & 0xF; ++ ++ pwrInfo->HT20MaxOffset[rfPath][group] = ++ (PROMContent[EEPROM_HT20_MAX_PWR_OFFSET+ group] >> (rfPath * 4)) & 0xF; ++ } ++ } ++ ++ pwrInfo->TSSI_A = PROMContent[EEPROM_TSSI_A]; ++ pwrInfo->TSSI_B = PROMContent[EEPROM_TSSI_B]; ++ ++} ++ ++ ++static u32 ++_GetChannelGroup( ++ IN u32 channel ++ ) ++{ ++ //RT_ASSERT((channel < 14), ("Channel %d no is supported!\n")); ++ ++ if(channel < 3){ // Channel 1~3 ++ return 0; ++ } ++ else if(channel < 9){ // Channel 4~9 ++ return 1; ++ } ++ ++ return 2; // Channel 10~14 ++} ++ ++ ++static VOID ++ReadTxPowerInfo( ++ IN PADAPTER Adapter, ++ IN u8* PROMContent, ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ TxPowerInfo pwrInfo; ++ u32 rfPath, ch, group; ++ u8 pwr, diff; ++ ++ _ReadPowerValueFromPROM(&pwrInfo, PROMContent, AutoLoadFail); ++ ++ if(!AutoLoadFail) ++ pHalData->bTXPowerDataReadFromEEPORM = _TRUE; ++ ++ for(rfPath = 0 ; rfPath < RF_PATH_MAX ; rfPath++){ ++ for(ch = 0 ; ch < CHANNEL_MAX_NUMBER ; ch++){ ++ group = _GetChannelGroup(ch); ++ ++ pHalData->TxPwrLevelCck[rfPath][ch] = pwrInfo.CCKIndex[rfPath][group]; ++ pHalData->TxPwrLevelHT40_1S[rfPath][ch] = pwrInfo.HT40_1SIndex[rfPath][group]; ++ ++ pHalData->TxPwrHt20Diff[rfPath][ch] = pwrInfo.HT20IndexDiff[rfPath][group]; ++ pHalData->TxPwrLegacyHtDiff[rfPath][ch] = pwrInfo.OFDMIndexDiff[rfPath][group]; ++ pHalData->PwrGroupHT20[rfPath][ch] = pwrInfo.HT20MaxOffset[rfPath][group]; ++ pHalData->PwrGroupHT40[rfPath][ch] = pwrInfo.HT40MaxOffset[rfPath][group]; ++ ++ pwr = pwrInfo.HT40_1SIndex[rfPath][group]; ++ diff = pwrInfo.HT40_2SIndexDiff[rfPath][group]; ++ ++ pHalData->TxPwrLevelHT40_2S[rfPath][ch] = (pwr > diff) ? (pwr - diff) : 0; ++ } ++ } ++ ++#if 0 //DBG ++ ++ for(rfPath = 0 ; rfPath < RF_PATH_MAX ; rfPath++){ ++ for(ch = 0 ; ch < CHANNEL_MAX_NUMBER ; ch++){ ++ RTPRINT(FINIT, INIT_TxPower, ++ ("RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = [0x%x / 0x%x / 0x%x]\n", ++ rfPath, ch, pHalData->TxPwrLevelCck[rfPath][ch], ++ pHalData->TxPwrLevelHT40_1S[rfPath][ch], ++ pHalData->TxPwrLevelHT40_2S[rfPath][ch])); ++ ++ } ++ } ++ ++ for(ch = 0 ; ch < CHANNEL_MAX_NUMBER ; ch++){ ++ RTPRINT(FINIT, INIT_TxPower, ("RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", ch, pHalData->TxPwrHt20Diff[RF_PATH_A][ch])); ++ } ++ ++ for(ch = 0 ; ch < CHANNEL_MAX_NUMBER ; ch++){ ++ RTPRINT(FINIT, INIT_TxPower, ("RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", ch, pHalData->TxPwrLegacyHtDiff[RF_PATH_A][ch])); ++ } ++ ++ for(ch = 0 ; ch < CHANNEL_MAX_NUMBER ; ch++){ ++ RTPRINT(FINIT, INIT_TxPower, ("RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", ch, pHalData->TxPwrHt20Diff[RF_PATH_B][ch])); ++ } ++ ++ for(ch = 0 ; ch < CHANNEL_MAX_NUMBER ; ch++){ ++ RTPRINT(FINIT, INIT_TxPower, ("RF-B Legacy to HT40 Diff[%d] = 0x%x\n", ch, pHalData->TxPwrLegacyHtDiff[RF_PATH_B][ch])); ++ } ++ ++#endif ++ // 2010/10/19 MH Add Regulator recognize for CU. ++ if(!AutoLoadFail) ++ { ++ pHalData->EEPROMRegulatory = (PROMContent[RF_OPTION1]&0x7); //bit0~2 ++ } ++ else ++ { ++ pHalData->EEPROMRegulatory = 0; ++ } ++ DBG_8192C("EEPROMRegulatory = 0x%x\n", pHalData->EEPROMRegulatory); ++ ++} ++#endif ++ ++//------------------------------------------------------------------- ++// ++// EEPROM/EFUSE Content Parsing ++// ++//------------------------------------------------------------------- ++static void ++_ReadIDs( ++ IN PADAPTER Adapter, ++ IN u8* PROMContent, ++ IN BOOLEAN AutoloadFail ++ ) ++{ ++#if 0 ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ if(_FALSE == AutoloadFail){ ++ // VID, PID ++ pHalData->EEPROMVID = le16_to_cpu( *(u16 *)&PROMContent[EEPROM_VID]); ++ pHalData->EEPROMPID = le16_to_cpu( *(u16 *)&PROMContent[EEPROM_PID]); ++ ++ // Customer ID, 0x00 and 0xff are reserved for Realtek. ++ pHalData->EEPROMCustomerID = *(u8 *)&PROMContent[EEPROM_CUSTOMER_ID]; ++ pHalData->EEPROMSubCustomerID = *(u8 *)&PROMContent[EEPROM_SUBCUSTOMER_ID]; ++ ++ } ++ else{ ++ pHalData->EEPROMVID = EEPROM_Default_VID; ++ pHalData->EEPROMPID = EEPROM_Default_PID; ++ ++ // Customer ID, 0x00 and 0xff are reserved for Realtek. ++ pHalData->EEPROMCustomerID = EEPROM_Default_CustomerID; ++ pHalData->EEPROMSubCustomerID = EEPROM_Default_SubCustomerID; ++ ++ } ++ ++ // For customized behavior. ++ if((pHalData->EEPROMVID == 0x103C) && (pHalData->EEPROMVID == 0x1629))// HP Lite-On for RTL8188CUS Slim Combo. ++ pHalData->CustomerID = RT_CID_819x_HP; ++ ++ // Decide CustomerID according to VID/DID or EEPROM ++ switch(pHalData->EEPROMCustomerID) ++ { ++ case EEPROM_CID_DEFAULT: ++ if((pHalData->EEPROMVID == 0x2001) && (pHalData->EEPROMPID == 0x3308)) ++ pHalData->CustomerID = RT_CID_DLINK; ++ else if((pHalData->EEPROMVID == 0x2001) && (pHalData->EEPROMPID == 0x3309)) ++ pHalData->CustomerID = RT_CID_DLINK; ++ else if((pHalData->EEPROMVID == 0x2001) && (pHalData->EEPROMPID == 0x330a)) ++ pHalData->CustomerID = RT_CID_DLINK; ++ break; ++ case EEPROM_CID_WHQL: ++/* ++ Adapter->bInHctTest = TRUE; ++ ++ pMgntInfo->bSupportTurboMode = FALSE; ++ pMgntInfo->bAutoTurboBy8186 = FALSE; ++ ++ pMgntInfo->PowerSaveControl.bInactivePs = FALSE; ++ pMgntInfo->PowerSaveControl.bIPSModeBackup = FALSE; ++ pMgntInfo->PowerSaveControl.bLeisurePs = FALSE; ++ ++ pMgntInfo->keepAliveLevel = 0; ++ ++ Adapter->bUnloadDriverwhenS3S4 = FALSE; ++*/ ++ break; ++ default: ++ pHalData->CustomerID = RT_CID_DEFAULT; ++ break; ++ ++ } ++ ++ MSG_8192C("EEPROMVID = 0x%04x\n", pHalData->EEPROMVID); ++ MSG_8192C("EEPROMPID = 0x%04x\n", pHalData->EEPROMPID); ++ MSG_8192C("EEPROMCustomerID : 0x%02x\n", pHalData->EEPROMCustomerID); ++ MSG_8192C("EEPROMSubCustomerID: 0x%02x\n", pHalData->EEPROMSubCustomerID); ++ ++ MSG_8192C("RT_CustomerID: 0x%02x\n", pHalData->CustomerID); ++#endif ++} ++ ++ ++static VOID ++_ReadMACAddress( ++ IN PADAPTER Adapter, ++ IN u8* PROMContent, ++ IN BOOLEAN AutoloadFail ++ ) ++{ ++#if 0 ++ ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(Adapter); ++ ++ if(_FALSE == AutoloadFail){ ++ //Read Permanent MAC address and set value to hardware ++ _rtw_memcpy(pEEPROM->mac_addr, &PROMContent[EEPROM_MAC_ADDR], ETH_ALEN); ++ } ++ else{ ++ //Random assigh MAC address ++ u8 sMacAddr[MAC_ADDR_LEN] = {0x00, 0xE0, 0x4C, 0x81, 0x92, 0x00}; ++ //sMacAddr[5] = (u8)GetRandomNumber(1, 254); ++ _rtw_memcpy(pEEPROM->mac_addr, sMacAddr, ETH_ALEN); ++ } ++ DBG_8192C("%s MAC Address from EFUSE = "MAC_FMT"\n",__FUNCTION__, MAC_ARG(pEEPROM->mac_addr)); ++ //NicIFSetMacAddress(Adapter, Adapter->PermanentAddress); ++ //RT_PRINT_ADDR(COMP_INIT|COMP_EFUSE, DBG_LOUD, "MAC Addr: %s", Adapter->PermanentAddress); ++#endif ++} ++ ++static VOID ++_ReadBoardType( ++ IN PADAPTER Adapter, ++ IN u8* PROMContent, ++ IN BOOLEAN AutoloadFail ++ ) ++{ ++ ++} ++ ++ ++static VOID ++_ReadLEDSetting( ++ IN PADAPTER Adapter, ++ IN u8* PROMContent, ++ IN BOOLEAN AutoloadFail ++ ) ++{ ++ struct led_priv *pledpriv = &(Adapter->ledpriv); ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++#ifdef CONFIG_SW_LED ++ pledpriv->bRegUseLed = _TRUE; ++ ++ switch(pHalData->CustomerID) ++ { ++ default: ++ pledpriv->LedStrategy = SW_LED_MODE1; ++ break; ++ } ++ pHalData->bLedOpenDrain = _TRUE;// Support Open-drain arrangement for controlling the LED. Added by Roger, 2009.10.16. ++#else // HW LED ++ pledpriv->LedStrategy = HW_LED; ++#endif //CONFIG_SW_LED ++} ++ ++static VOID ++_ReadThermalMeter( ++ IN PADAPTER Adapter, ++ IN u8* PROMContent, ++ IN BOOLEAN AutoloadFail ++ ) ++{ ++#if 0 ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ u8 tempval; ++ ++ // ++ // ThermalMeter from EEPROM ++ // ++ if(!AutoloadFail) ++ tempval = PROMContent[EEPROM_THERMAL_METER]; ++ else ++ tempval = EEPROM_Default_ThermalMeter; ++ ++ pHalData->EEPROMThermalMeter = (tempval&0x1f); //[4:0] ++ ++ if(pHalData->EEPROMThermalMeter == 0x1f || AutoloadFail) ++ pdmpriv->bAPKThermalMeterIgnore = _TRUE; ++ ++#if 0 ++ if(pHalData->EEPROMThermalMeter < 0x06 || pHalData->EEPROMThermalMeter > 0x1c) ++ pHalData->EEPROMThermalMeter = 0x12; ++#endif ++ ++ pdmpriv->ThermalMeter[0] = pHalData->EEPROMThermalMeter; ++ ++ //RTPRINT(FINIT, INIT_TxPower, ("ThermalMeter = 0x%x\n", pHalData->EEPROMThermalMeter)); ++#endif ++} ++ ++static VOID ++_ReadRFSetting( ++ IN PADAPTER Adapter, ++ IN u8* PROMContent, ++ IN BOOLEAN AutoloadFail ++ ) ++{ ++} ++ ++static void ++_ReadPROMVersion( ++ IN PADAPTER Adapter, ++ IN u8* PROMContent, ++ IN BOOLEAN AutoloadFail ++ ) ++{ ++#if 0 ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ if(AutoloadFail){ ++ pHalData->EEPROMVersion = EEPROM_Default_Version; ++ } ++ else{ ++ pHalData->EEPROMVersion = *(u8 *)&PROMContent[EEPROM_VERSION]; ++ } ++#endif ++} ++ ++static VOID ++readAntennaDiversity( ++ IN PADAPTER pAdapter, ++ IN u8 *hwinfo, ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ struct registry_priv *registry_par = &pAdapter->registrypriv; ++ ++ pHalData->AntDivCfg = registry_par->antdiv_cfg ; // 0:OFF , 1:ON, ++#if 0 ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ struct registry_priv *registry_par = &pAdapter->registrypriv; ++ ++ if(!AutoLoadFail) ++ { ++ // Antenna Diversity setting. ++ if(registry_par->antdiv_cfg == 2) // 2: From Efuse ++ pHalData->AntDivCfg = (hwinfo[EEPROM_RF_OPT1]&0x18)>>3; ++ else ++ pHalData->AntDivCfg = registry_par->antdiv_cfg ; // 0:OFF , 1:ON, ++ ++ DBG_8192C("### AntDivCfg(%x)\n",pHalData->AntDivCfg); ++ ++ //if(pHalData->EEPROMBluetoothCoexist!=0 && pHalData->EEPROMBluetoothAntNum==Ant_x1) ++ // pHalData->AntDivCfg = 0; ++ } ++ else ++ { ++ pHalData->AntDivCfg = 0; ++ } ++#endif ++} ++ ++static VOID ++hal_InitPGData( ++ IN PADAPTER pAdapter, ++ IN OUT u8 *PROMContent ++ ) ++{ ++#if 0 ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ u32 i; ++ u16 value16; ++ ++ if(_FALSE == pEEPROM->bautoload_fail_flag) ++ { // autoload OK. ++ if (_TRUE == pEEPROM->EepromOrEfuse) ++ { ++ // Read all Content from EEPROM or EFUSE. ++ for(i = 0; i < HWSET_MAX_SIZE_88E; i += 2) ++ { ++ //value16 = EF2Byte(ReadEEprom(pAdapter, (u2Byte) (i>>1))); ++ //*((u16 *)(&PROMContent[i])) = value16; ++ } ++ } ++ else ++ { ++ // Read EFUSE real map to shadow. ++ EFUSE_ShadowMapUpdate(pAdapter, EFUSE_WIFI, _FALSE); ++ _rtw_memcpy((void*)PROMContent, (void*)pEEPROM->efuse_eeprom_data, HWSET_MAX_SIZE_88E); ++ } ++ } ++ else ++ {//autoload fail ++ //RT_TRACE(COMP_INIT, DBG_LOUD, ("AutoLoad Fail reported from CR9346!!\n")); ++ pEEPROM->bautoload_fail_flag = _TRUE; ++ //update to default value 0xFF ++ if (_FALSE == pEEPROM->EepromOrEfuse) ++ EFUSE_ShadowMapUpdate(pAdapter, EFUSE_WIFI, _FALSE); ++ } ++#endif ++} ++static void ++Hal_EfuseParsePIDVID_8188EU( ++ IN PADAPTER pAdapter, ++ IN u8* hwinfo, ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++ ++ if( !AutoLoadFail ) ++ { ++ // VID, PID ++ pHalData->EEPROMVID = EF2Byte( *(u16 *)&hwinfo[EEPROM_VID_88EU] ); ++ pHalData->EEPROMPID = EF2Byte( *(u16 *)&hwinfo[EEPROM_PID_88EU] ); ++ ++ // Customer ID, 0x00 and 0xff are reserved for Realtek. ++ pHalData->EEPROMCustomerID = *(u8 *)&hwinfo[EEPROM_CUSTOMERID_88E]; ++ pHalData->EEPROMSubCustomerID = EEPROM_Default_SubCustomerID; ++ ++ } ++ else ++ { ++ pHalData->EEPROMVID = EEPROM_Default_VID; ++ pHalData->EEPROMPID = EEPROM_Default_PID; ++ ++ // Customer ID, 0x00 and 0xff are reserved for Realtek. ++ pHalData->EEPROMCustomerID = EEPROM_Default_CustomerID; ++ pHalData->EEPROMSubCustomerID = EEPROM_Default_SubCustomerID; ++ ++ } ++ ++ DBG_871X("VID = 0x%04X, PID = 0x%04X\n", pHalData->EEPROMVID, pHalData->EEPROMPID); ++ DBG_871X("Customer ID: 0x%02X, SubCustomer ID: 0x%02X\n", pHalData->EEPROMCustomerID, pHalData->EEPROMSubCustomerID); ++} ++ ++static void ++Hal_EfuseParseMACAddr_8188EU( ++ IN PADAPTER padapter, ++ IN u8* hwinfo, ++ IN BOOLEAN AutoLoadFail ++ ) ++{ ++ u16 i, usValue; ++ u8 sMacAddr[6] = {0x00, 0xE0, 0x4C, 0x81, 0x88, 0x02}; ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ ++ if (AutoLoadFail) ++ { ++// sMacAddr[5] = (u1Byte)GetRandomNumber(1, 254); ++ for (i=0; i<6; i++) ++ pEEPROM->mac_addr[i] = sMacAddr[i]; ++ } ++ else ++ { ++ //Read Permanent MAC address ++ _rtw_memcpy(pEEPROM->mac_addr, &hwinfo[EEPROM_MAC_ADDR_88EU], ETH_ALEN); ++ ++ } ++// NicIFSetMacAddress(pAdapter, pAdapter->PermanentAddress); ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ++ ("Hal_EfuseParseMACAddr_8188EU: Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n", ++ pEEPROM->mac_addr[0], pEEPROM->mac_addr[1], ++ pEEPROM->mac_addr[2], pEEPROM->mac_addr[3], ++ pEEPROM->mac_addr[4], pEEPROM->mac_addr[5])); ++} ++ ++ ++static void ++Hal_CustomizeByCustomerID_8188EU( ++ IN PADAPTER padapter ++ ) ++{ ++#if 0 ++ PMGNT_INFO pMgntInfo = &(padapter->MgntInfo); ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ ++ // For customized behavior. ++ if((pHalData->EEPROMVID == 0x103C) && (pHalData->EEPROMVID == 0x1629))// HP Lite-On for RTL8188CUS Slim Combo. ++ pMgntInfo->CustomerID = RT_CID_819x_HP; ++ ++ // Decide CustomerID according to VID/DID or EEPROM ++ switch(pHalData->EEPROMCustomerID) ++ { ++ case EEPROM_CID_DEFAULT: ++ if((pHalData->EEPROMVID == 0x2001) && (pHalData->EEPROMPID == 0x3308)) ++ pMgntInfo->CustomerID = RT_CID_DLINK; ++ else if((pHalData->EEPROMVID == 0x2001) && (pHalData->EEPROMPID == 0x3309)) ++ pMgntInfo->CustomerID = RT_CID_DLINK; ++ else if((pHalData->EEPROMVID == 0x2001) && (pHalData->EEPROMPID == 0x330a)) ++ pMgntInfo->CustomerID = RT_CID_DLINK; ++ break; ++ case EEPROM_CID_WHQL: ++ padapter->bInHctTest = TRUE; ++ ++ pMgntInfo->bSupportTurboMode = FALSE; ++ pMgntInfo->bAutoTurboBy8186 = FALSE; ++ ++ pMgntInfo->PowerSaveControl.bInactivePs = FALSE; ++ pMgntInfo->PowerSaveControl.bIPSModeBackup = FALSE; ++ pMgntInfo->PowerSaveControl.bLeisurePs = FALSE; ++ pMgntInfo->PowerSaveControl.bLeisurePsModeBackup =FALSE; ++ pMgntInfo->keepAliveLevel = 0; ++ ++ padapter->bUnloadDriverwhenS3S4 = FALSE; ++ break; ++ default: ++ pMgntInfo->CustomerID = RT_CID_DEFAULT; ++ break; ++ ++ } ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Mgnt Customer ID: 0x%02x\n", pMgntInfo->CustomerID)); ++ ++ hal_CustomizedBehavior_8723U(padapter); ++#endif ++} ++ ++// Read HW power down mode selection ++static void _ReadPSSetting(IN PADAPTER Adapter,IN u8*PROMContent,IN u8 AutoloadFail) ++{ ++#if 0 ++ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(Adapter); ++ ++ if(AutoloadFail){ ++ pwrctl->bHWPowerdown = _FALSE; ++ pwrctl->bSupportRemoteWakeup = _FALSE; ++ } ++ else { ++ //if(SUPPORT_HW_RADIO_DETECT(Adapter)) ++ pwrctl->bHWPwrPindetect = Adapter->registrypriv.hwpwrp_detect; ++ //else ++ //pwrctl->bHWPwrPindetect = _FALSE;//dongle not support new ++ ++ ++ //hw power down mode selection , 0:rf-off / 1:power down ++ ++ if(Adapter->registrypriv.hwpdn_mode==2) ++ pwrctl->bHWPowerdown = (PROMContent[EEPROM_RF_OPT3] & BIT4); ++ else ++ pwrctl->bHWPowerdown = Adapter->registrypriv.hwpdn_mode; ++ ++ // decide hw if support remote wakeup function ++ // if hw supported, 8051 (SIE) will generate WeakUP signal( D+/D- toggle) when autoresume ++ pwrctl->bSupportRemoteWakeup = (PROMContent[EEPROM_TEST_USB_OPT] & BIT1)?_TRUE :_FALSE; ++ ++ //if(SUPPORT_HW_RADIO_DETECT(Adapter)) ++ //Adapter->registrypriv.usbss_enable = pwrctl->bSupportRemoteWakeup ; ++ ++ DBG_8192C("%s...bHWPwrPindetect(%x)-bHWPowerdown(%x) ,bSupportRemoteWakeup(%x)\n",__FUNCTION__, ++ pwrctl->bHWPwrPindetect,pwrctl->bHWPowerdown ,pwrctl->bSupportRemoteWakeup); ++ ++ DBG_8192C("### PS params=> power_mgnt(%x),usbss_enable(%x) ###\n",Adapter->registrypriv.power_mgnt,Adapter->registrypriv.usbss_enable); ++ ++ } ++#endif ++} ++ ++#ifdef CONFIG_EFUSE_CONFIG_FILE ++static u32 Hal_readPGDataFromConfigFile( ++ PADAPTER padapter) ++{ ++ u32 i; ++ struct file *fp; ++ mm_segment_t fs; ++ u8 temp[3]; ++ loff_t pos = 0; ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ u8 *PROMContent = pEEPROM->efuse_eeprom_data; ++ ++ ++ temp[2] = 0; // add end of string '\0' ++ ++ fp = filp_open("/system/etc/wifi/wifi_efuse.map", O_RDWR, 0644); ++ if (IS_ERR(fp)) { ++ pEEPROM->bloadfile_fail_flag = _TRUE; ++ DBG_871X("Error, Efuse configure file doesn't exist.\n"); ++ return _FAIL; ++ } ++ ++ fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ DBG_871X("Efuse configure file:\n"); ++ for (i=0; ibloadfile_fail_flag = _FALSE; ++ ++ return _SUCCESS; ++} ++ ++static void ++Hal_ReadMACAddrFromFile_8188EU( ++ PADAPTER padapter ++ ) ++{ ++ u32 i; ++ struct file *fp; ++ mm_segment_t fs; ++ u8 source_addr[18]; ++ loff_t pos = 0; ++ u32 curtime = rtw_get_current_time(); ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ u8 *head, *end; ++ ++ u8 null_mac_addr[ETH_ALEN] = {0, 0, 0,0, 0, 0}; ++ u8 multi_mac_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ _rtw_memset(source_addr, 0, 18); ++ _rtw_memset(pEEPROM->mac_addr, 0, ETH_ALEN); ++ ++ fp = filp_open("/data/wifimac.txt", O_RDWR, 0644); ++ if (IS_ERR(fp)) { ++ pEEPROM->bloadmac_fail_flag = _TRUE; ++ DBG_871X("Error, wifi mac address file doesn't exist.\n"); ++ } else { ++ fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ DBG_871X("wifi mac address:\n"); ++ vfs_read(fp, source_addr, 18, &pos); ++ source_addr[17] = ':'; ++ ++ head = end = source_addr; ++ for (i=0; imac_addr[i] = simple_strtoul(head, NULL, 16 ); ++ ++ if (end) { ++ end++; ++ head = end; ++ } ++ DBG_871X("%02x \n", pEEPROM->mac_addr[i]); ++ } ++ DBG_871X("\n"); ++ set_fs(fs); ++ pEEPROM->bloadmac_fail_flag = _FALSE; ++ filp_close(fp, NULL); ++ } ++ ++ if ( (_rtw_memcmp(pEEPROM->mac_addr, null_mac_addr, ETH_ALEN)) || ++ (_rtw_memcmp(pEEPROM->mac_addr, multi_mac_addr, ETH_ALEN)) ) { ++ pEEPROM->mac_addr[0] = 0x00; ++ pEEPROM->mac_addr[1] = 0xe0; ++ pEEPROM->mac_addr[2] = 0x4c; ++ pEEPROM->mac_addr[3] = (u8)(curtime & 0xff) ; ++ pEEPROM->mac_addr[4] = (u8)((curtime>>8) & 0xff) ; ++ pEEPROM->mac_addr[5] = (u8)((curtime>>16) & 0xff) ; ++ } ++ ++ DBG_871X("Hal_ReadMACAddrFromFile_8188ES: Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n", ++ pEEPROM->mac_addr[0], pEEPROM->mac_addr[1], ++ pEEPROM->mac_addr[2], pEEPROM->mac_addr[3], ++ pEEPROM->mac_addr[4], pEEPROM->mac_addr[5]); ++} ++#endif //CONFIG_EFUSE_CONFIG_FILE ++ ++static VOID ++readAdapterInfo_8188EU( ++ IN PADAPTER padapter ++ ) ++{ ++#if 1 ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ ++ /* parse the eeprom/efuse content */ ++ Hal_EfuseParseIDCode88E(padapter, pEEPROM->efuse_eeprom_data); ++ Hal_EfuseParsePIDVID_8188EU(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++#ifdef CONFIG_EFUSE_CONFIG_FILE ++ Hal_ReadMACAddrFromFile_8188EU(padapter); ++#else //CONFIG_EFUSE_CONFIG_FILE ++ Hal_EfuseParseMACAddr_8188EU(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++#endif //CONFIG_EFUSE_CONFIG_FILE ++ ++ Hal_ReadPowerSavingMode88E(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ Hal_ReadTxPowerInfo88E(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ Hal_EfuseParseEEPROMVer88E(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ rtl8188e_EfuseParseChnlPlan(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ Hal_EfuseParseXtal_8188E(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ Hal_EfuseParseCustomerID88E(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ Hal_ReadAntennaDiversity88E(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ Hal_EfuseParseBoardType88E(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ Hal_ReadThermalMeter_88E(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ ++ // ++ // The following part initialize some vars by PG info. ++ // ++ Hal_InitChannelPlan(padapter); ++#if defined(CONFIG_WOWLAN) && defined(CONFIG_SDIO_HCI) ++ Hal_DetectWoWMode(padapter); ++#endif //CONFIG_WOWLAN && CONFIG_SDIO_HCI ++ Hal_CustomizeByCustomerID_8188EU(padapter); ++ ++ _ReadLEDSetting(padapter, pEEPROM->efuse_eeprom_data, pEEPROM->bautoload_fail_flag); ++ ++#else ++ ++#ifdef CONFIG_INTEL_PROXIM ++ /* for intel proximity */ ++ if (pHalData->rf_type== RF_1T1R) { ++ Adapter->proximity.proxim_support = _TRUE; ++ } else if (pHalData->rf_type== RF_2T2R) { ++ if ((pHalData->EEPROMPID == 0x8186) && ++ (pHalData->EEPROMVID== 0x0bda)) ++ Adapter->proximity.proxim_support = _TRUE; ++ } else { ++ Adapter->proximity.proxim_support = _FALSE; ++ } ++#endif //CONFIG_INTEL_PROXIM ++#endif ++} ++ ++static void _ReadPROMContent( ++ IN PADAPTER Adapter ++ ) ++{ ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(Adapter); ++ u8 eeValue; ++ ++ /* check system boot selection */ ++ eeValue = rtw_read8(Adapter, REG_9346CR); ++ pEEPROM->EepromOrEfuse = (eeValue & BOOT_FROM_EEPROM) ? _TRUE : _FALSE; ++ pEEPROM->bautoload_fail_flag = (eeValue & EEPROM_EN) ? _FALSE : _TRUE; ++ ++ ++ DBG_8192C("Boot from %s, Autoload %s !\n", (pEEPROM->EepromOrEfuse ? "EEPROM" : "EFUSE"), ++ (pEEPROM->bautoload_fail_flag ? "Fail" : "OK") ); ++ ++ //pHalData->EEType = IS_BOOT_FROM_EEPROM(Adapter) ? EEPROM_93C46 : EEPROM_BOOT_EFUSE; ++#ifdef CONFIG_EFUSE_CONFIG_FILE ++ Hal_readPGDataFromConfigFile(Adapter); ++#else //CONFIG_EFUSE_CONFIG_FILE ++ Hal_InitPGData88E(Adapter); ++#endif //CONFIG_EFUSE_CONFIG_FILE ++ readAdapterInfo_8188EU(Adapter); ++} ++ ++ ++ ++static VOID ++_ReadRFType( ++ IN PADAPTER Adapter ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++#if DISABLE_BB_RF ++ pHalData->rf_chip = RF_PSEUDO_11N; ++#else ++ pHalData->rf_chip = RF_6052; ++#endif ++} ++ ++static int _ReadAdapterInfo8188EU(PADAPTER Adapter) ++{ ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ u32 start=rtw_get_current_time(); ++ ++ MSG_8192C("====> %s\n", __FUNCTION__); ++ ++ //Efuse_InitSomeVar(Adapter); ++ ++ //if(IS_HARDWARE_TYPE_8723A(Adapter)) ++ // _EfuseCellSel(Adapter); ++ ++ _ReadRFType(Adapter);//rf_chip -> _InitRFType() ++ _ReadPROMContent(Adapter); ++ ++ //MSG_8192C("%s()(done), rf_chip=0x%x, rf_type=0x%x\n", __FUNCTION__, pHalData->rf_chip, pHalData->rf_type); ++ ++ MSG_8192C("<==== %s in %d ms\n", __FUNCTION__, rtw_get_passing_time_ms(start)); ++ ++ return _SUCCESS; ++} ++ ++ ++static void ReadAdapterInfo8188EU(PADAPTER Adapter) ++{ ++ // Read EEPROM size before call any EEPROM function ++ Adapter->EepromAddressSize = GetEEPROMSize8188E(Adapter); ++ ++ _ReadAdapterInfo8188EU(Adapter); ++} ++ ++ ++#define GPIO_DEBUG_PORT_NUM 0 ++static void rtl8192cu_trigger_gpio_0(_adapter *padapter) ++{ ++#ifdef CONFIG_USB_SUPPORT_ASYNC_VDN_REQ ++ u32 gpioctrl; ++ DBG_8192C("==> trigger_gpio_0...\n"); ++ rtw_write16_async(padapter,REG_GPIO_PIN_CTRL,0); ++ rtw_write8_async(padapter,REG_GPIO_PIN_CTRL+2,0xFF); ++ gpioctrl = (BIT(GPIO_DEBUG_PORT_NUM)<<24 )|(BIT(GPIO_DEBUG_PORT_NUM)<<16); ++ rtw_write32_async(padapter,REG_GPIO_PIN_CTRL,gpioctrl); ++ gpioctrl |= (BIT(GPIO_DEBUG_PORT_NUM)<<8); ++ rtw_write32_async(padapter,REG_GPIO_PIN_CTRL,gpioctrl); ++ DBG_8192C("<=== trigger_gpio_0...\n"); ++#endif ++} ++ ++static void ResumeTxBeacon(_adapter *padapter) ++{ ++ HAL_DATA_TYPE* pHalData = GET_HAL_DATA(padapter); ++ ++ // 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value ++ // which should be read from register to a global variable. ++ ++ rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, (pHalData->RegFwHwTxQCtrl) | BIT6); ++ pHalData->RegFwHwTxQCtrl |= BIT6; ++ rtw_write8(padapter, REG_TBTT_PROHIBIT+1, 0xff); ++ pHalData->RegReg542 |= BIT0; ++ rtw_write8(padapter, REG_TBTT_PROHIBIT+2, pHalData->RegReg542); ++} ++void UpdateInterruptMask8188EU(PADAPTER padapter,u8 bHIMR0 ,u32 AddMSR, u32 RemoveMSR) ++{ ++ HAL_DATA_TYPE *pHalData; ++ ++ u32 *himr; ++ pHalData = GET_HAL_DATA(padapter); ++ ++ if(bHIMR0) ++ himr = &(pHalData->IntrMask[0]); ++ else ++ himr = &(pHalData->IntrMask[1]); ++ ++ if (AddMSR) ++ *himr |= AddMSR; ++ ++ if (RemoveMSR) ++ *himr &= (~RemoveMSR); ++ ++ if(bHIMR0) ++ rtw_write32(padapter, REG_HIMR_88E, *himr); ++ else ++ rtw_write32(padapter, REG_HIMRE_88E, *himr); ++ ++} ++ ++static void StopTxBeacon(_adapter *padapter) ++{ ++ HAL_DATA_TYPE* pHalData = GET_HAL_DATA(padapter); ++ ++ // 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value ++ // which should be read from register to a global variable. ++ ++ rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, (pHalData->RegFwHwTxQCtrl) & (~BIT6)); ++ pHalData->RegFwHwTxQCtrl &= (~BIT6); ++ rtw_write8(padapter, REG_TBTT_PROHIBIT+1, 0x64); ++ pHalData->RegReg542 &= ~(BIT0); ++ rtw_write8(padapter, REG_TBTT_PROHIBIT+2, pHalData->RegReg542); ++ ++ //todo: CheckFwRsvdPageContent(Adapter); // 2010.06.23. Added by tynli. ++ ++} ++ ++ ++static void hw_var_set_opmode(PADAPTER Adapter, u8 variable, u8* val) ++{ ++ u8 val8; ++ u8 mode = *((u8 *)val); ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(Adapter->iface_type == IFACE_PORT1) ++ { ++ // disable Port1 TSF update ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)|BIT(4)); ++ ++ // set net_type ++ val8 = rtw_read8(Adapter, MSR)&0x03; ++ val8 |= (mode<<2); ++ rtw_write8(Adapter, MSR, val8); ++ ++ DBG_871X("%s()-%d mode = %d\n", __FUNCTION__, __LINE__, mode); ++ ++ if((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) ++ { ++ if(!check_buddy_mlmeinfo_state(Adapter, WIFI_FW_AP_STATE)) ++ { ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN ++ ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ rtw_write8(Adapter, REG_DRVERLYINT, 0x05);//restore early int time to 5ms ++ UpdateInterruptMask8188EU(Adapter,_TRUE, 0, IMR_BCNDMAINT0_88E); ++ #endif // CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ UpdateInterruptMask8188EU(Adapter,_TRUE ,0, (IMR_TBDER_88E|IMR_TBDOK_88E)); ++ #endif// CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ ++ #endif //CONFIG_INTERRUPT_BASED_TXBCN ++ ++ ++ StopTxBeacon(Adapter); ++ } ++ ++ rtw_write8(Adapter,REG_BCN_CTRL_1, 0x11);//disable atim wnd and disable beacon function ++ //rtw_write8(Adapter,REG_BCN_CTRL_1, 0x18); ++ } ++ else if((mode == _HW_STATE_ADHOC_) /*|| (mode == _HW_STATE_AP_)*/) ++ { ++ ResumeTxBeacon(Adapter); ++ rtw_write8(Adapter,REG_BCN_CTRL_1, 0x1a); ++ //BIT4 - If set 0, hw will clr bcnq when tx becon ok/fail or port 1 ++ rtw_write8(Adapter, REG_MBID_NUM, rtw_read8(Adapter, REG_MBID_NUM)|BIT(3)|BIT(4)); ++ } ++ else if(mode == _HW_STATE_AP_) ++ { ++#ifdef CONFIG_INTERRUPT_BASED_TXBCN ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ UpdateInterruptMask8188EU(Adapter,_TRUE ,IMR_BCNDMAINT0_88E, 0); ++ #endif//CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ UpdateInterruptMask8188EU(Adapter,_TRUE ,(IMR_TBDER_88E|IMR_TBDOK_88E), 0); ++ #endif//CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ ++#endif //CONFIG_INTERRUPT_BASED_TXBCN ++ ++ ResumeTxBeacon(Adapter); ++ ++ rtw_write8(Adapter, REG_BCN_CTRL_1, 0x12); ++ ++ //Set RCR ++ //rtw_write32(padapter, REG_RCR, 0x70002a8e);//CBSSID_DATA must set to 0 ++ //rtw_write32(Adapter, REG_RCR, 0x7000228e);//CBSSID_DATA must set to 0 ++ rtw_write32(Adapter, REG_RCR, 0x7000208e);//CBSSID_DATA must set to 0,reject ICV_ERR packet ++ //enable to rx data frame ++ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); ++ //enable to rx ps-poll ++ rtw_write16(Adapter, REG_RXFLTMAP1, 0x0400); ++ ++ //Beacon Control related register for first time ++ rtw_write8(Adapter, REG_BCNDMATIM, 0x02); // 2ms ++ ++ //rtw_write8(Adapter, REG_BCN_MAX_ERR, 0xFF); ++ rtw_write8(Adapter, REG_ATIMWND_1, 0x0a); // 10ms for port1 ++ rtw_write16(Adapter, REG_BCNTCFG, 0x00); ++ rtw_write16(Adapter, REG_TBTT_PROHIBIT, 0xff04); ++ rtw_write16(Adapter, REG_TSFTR_SYN_OFFSET, 0x7fff);// +32767 (~32ms) ++ ++ //reset TSF2 ++ rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(1)); ++ ++ ++ //BIT4 - If set 0, hw will clr bcnq when tx becon ok/fail or port 1 ++ rtw_write8(Adapter, REG_MBID_NUM, rtw_read8(Adapter, REG_MBID_NUM)|BIT(3)|BIT(4)); ++ //enable BCN1 Function for if2 ++ //don't enable update TSF1 for if2 (due to TSF update when beacon/probe rsp are received) ++ rtw_write8(Adapter, REG_BCN_CTRL_1, (DIS_TSF_UDT0_NORMAL_CHIP|EN_BCN_FUNCTION | EN_TXBCN_RPT|BIT(1))); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(check_buddy_fwstate(Adapter, WIFI_FW_NULL_STATE)) ++ rtw_write8(Adapter, REG_BCN_CTRL, ++ rtw_read8(Adapter, REG_BCN_CTRL) & ~EN_BCN_FUNCTION); ++#endif ++ //BCN1 TSF will sync to BCN0 TSF with offset(0x518) if if1_sta linked ++ //rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)|BIT(5)); ++ //rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(3)); ++ ++ //dis BCN0 ATIM WND if if1 is station ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(0)); ++ ++#ifdef CONFIG_TSF_RESET_OFFLOAD ++ // Reset TSF for STA+AP concurrent mode ++ if ( check_buddy_fwstate(Adapter, (WIFI_STATION_STATE|WIFI_ASOC_STATE)) ) { ++ if (reset_tsf(Adapter, IFACE_PORT1) == _FALSE) ++ DBG_871X("ERROR! %s()-%d: Reset port1 TSF fail\n", ++ __FUNCTION__, __LINE__); ++ } ++#endif // CONFIG_TSF_RESET_OFFLOAD ++ } ++ } ++ else ++#endif //CONFIG_CONCURRENT_MODE ++ { ++ // disable Port0 TSF update ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4)); ++ ++ // set net_type ++ val8 = rtw_read8(Adapter, MSR)&0x0c; ++ val8 |= mode; ++ rtw_write8(Adapter, MSR, val8); ++ ++ DBG_871X("%s()-%d mode = %d\n", __FUNCTION__, __LINE__, mode); ++ ++ if((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) ++ { ++#ifdef CONFIG_CONCURRENT_MODE ++ if(!check_buddy_mlmeinfo_state(Adapter, WIFI_FW_AP_STATE)) ++#endif //CONFIG_CONCURRENT_MODE ++ { ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ rtw_write8(Adapter, REG_DRVERLYINT, 0x05);//restore early int time to 5ms ++ UpdateInterruptMask8188EU(Adapter,_TRUE, 0, IMR_BCNDMAINT0_88E); ++ #endif//CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ UpdateInterruptMask8188EU(Adapter,_TRUE ,0, (IMR_TBDER_88E|IMR_TBDOK_88E)); ++ #endif //CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ ++ #endif //CONFIG_INTERRUPT_BASED_TXBCN ++ StopTxBeacon(Adapter); ++ } ++ ++ rtw_write8(Adapter,REG_BCN_CTRL, 0x19);//disable atim wnd ++ //rtw_write8(Adapter,REG_BCN_CTRL, 0x18); ++ } ++ else if((mode == _HW_STATE_ADHOC_) /*|| (mode == _HW_STATE_AP_)*/) ++ { ++ ResumeTxBeacon(Adapter); ++ rtw_write8(Adapter,REG_BCN_CTRL, 0x1a); ++ //BIT3 - If set 0, hw will clr bcnq when tx becon ok/fail or port 0 ++ rtw_write8(Adapter, REG_MBID_NUM, rtw_read8(Adapter, REG_MBID_NUM)|BIT(3)|BIT(4)); ++ } ++ else if(mode == _HW_STATE_AP_) ++ { ++ ++#ifdef CONFIG_INTERRUPT_BASED_TXBCN ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ UpdateInterruptMask8188EU(Adapter,_TRUE ,IMR_BCNDMAINT0_88E, 0); ++ #endif//CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ UpdateInterruptMask8188EU(Adapter,_TRUE ,(IMR_TBDER_88E|IMR_TBDOK_88E), 0); ++ #endif//CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ ++#endif //CONFIG_INTERRUPT_BASED_TXBCN ++ ++ ++ ResumeTxBeacon(Adapter); ++ ++ rtw_write8(Adapter, REG_BCN_CTRL, 0x12); ++ ++ //Set RCR ++ //rtw_write32(padapter, REG_RCR, 0x70002a8e);//CBSSID_DATA must set to 0 ++ //rtw_write32(Adapter, REG_RCR, 0x7000228e);//CBSSID_DATA must set to 0 ++ rtw_write32(Adapter, REG_RCR, 0x7000208e);//CBSSID_DATA must set to 0,reject ICV_ERR packet ++ //enable to rx data frame ++ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); ++ //enable to rx ps-poll ++ rtw_write16(Adapter, REG_RXFLTMAP1, 0x0400); ++ ++ //Beacon Control related register for first time ++ rtw_write8(Adapter, REG_BCNDMATIM, 0x02); // 2ms ++ ++ //rtw_write8(Adapter, REG_BCN_MAX_ERR, 0xFF); ++ rtw_write8(Adapter, REG_ATIMWND, 0x0a); // 10ms ++ rtw_write16(Adapter, REG_BCNTCFG, 0x00); ++ rtw_write16(Adapter, REG_TBTT_PROHIBIT, 0xff04); ++ rtw_write16(Adapter, REG_TSFTR_SYN_OFFSET, 0x7fff);// +32767 (~32ms) ++ ++ //reset TSF ++ rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(0)); ++ ++ //BIT3 - If set 0, hw will clr bcnq when tx becon ok/fail or port 0 ++ rtw_write8(Adapter, REG_MBID_NUM, rtw_read8(Adapter, REG_MBID_NUM)|BIT(3)|BIT(4)); ++ ++ //enable BCN0 Function for if1 ++ //don't enable update TSF0 for if1 (due to TSF update when beacon/probe rsp are received) ++ #if defined(CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR) ++ rtw_write8(Adapter, REG_BCN_CTRL, (DIS_TSF_UDT0_NORMAL_CHIP|EN_BCN_FUNCTION | EN_TXBCN_RPT|BIT(1))); ++ #else ++ rtw_write8(Adapter, REG_BCN_CTRL, (DIS_TSF_UDT0_NORMAL_CHIP|EN_BCN_FUNCTION |BIT(1))); ++ #endif ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(check_buddy_fwstate(Adapter, WIFI_FW_NULL_STATE)) ++ rtw_write8(Adapter, REG_BCN_CTRL_1, ++ rtw_read8(Adapter, REG_BCN_CTRL_1) & ~EN_BCN_FUNCTION); ++#endif ++ ++ //dis BCN1 ATIM WND if if2 is station ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)|BIT(0)); ++#ifdef CONFIG_TSF_RESET_OFFLOAD ++ // Reset TSF for STA+AP concurrent mode ++ if ( check_buddy_fwstate(Adapter, (WIFI_STATION_STATE|WIFI_ASOC_STATE)) ) { ++ if (reset_tsf(Adapter, IFACE_PORT0) == _FALSE) ++ DBG_871X("ERROR! %s()-%d: Reset port0 TSF fail\n", ++ __FUNCTION__, __LINE__); ++ } ++#endif // CONFIG_TSF_RESET_OFFLOAD ++ } ++ } ++ ++} ++ ++static void hw_var_set_macaddr(PADAPTER Adapter, u8 variable, u8* val) ++{ ++ u8 idx = 0; ++ u32 reg_macid; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(Adapter->iface_type == IFACE_PORT1) ++ { ++ reg_macid = REG_MACID1; ++ } ++ else ++#endif ++ { ++ reg_macid = REG_MACID; ++ } ++ ++ for(idx = 0 ; idx < 6; idx++) ++ { ++ rtw_write8(Adapter, (reg_macid+idx), val[idx]); ++ } ++ ++} ++ ++static void hw_var_set_bssid(PADAPTER Adapter, u8 variable, u8* val) ++{ ++ u8 idx = 0; ++ u32 reg_bssid; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(Adapter->iface_type == IFACE_PORT1) ++ { ++ reg_bssid = REG_BSSID1; ++ } ++ else ++#endif ++ { ++ reg_bssid = REG_BSSID; ++ } ++ ++ for(idx = 0 ; idx < 6; idx++) ++ { ++ rtw_write8(Adapter, (reg_bssid+idx), val[idx]); ++ } ++ ++} ++ ++static void hw_var_set_bcn_func(PADAPTER Adapter, u8 variable, u8* val) ++{ ++ u32 bcn_ctrl_reg; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(Adapter->iface_type == IFACE_PORT1) ++ { ++ bcn_ctrl_reg = REG_BCN_CTRL_1; ++ } ++ else ++#endif ++ { ++ bcn_ctrl_reg = REG_BCN_CTRL; ++ } ++ ++ if(*((u8 *)val)) ++ { ++ rtw_write8(Adapter, bcn_ctrl_reg, (EN_BCN_FUNCTION | EN_TXBCN_RPT)); ++ } ++ else ++ { ++ rtw_write8(Adapter, bcn_ctrl_reg, rtw_read8(Adapter, bcn_ctrl_reg)&(~(EN_BCN_FUNCTION | EN_TXBCN_RPT))); ++ } ++ ++ ++} ++ ++static void hw_var_set_correct_tsf(PADAPTER Adapter, u8 variable, u8* val) ++{ ++#ifdef CONFIG_CONCURRENT_MODE ++ u64 tsf; ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ PADAPTER pbuddy_adapter = Adapter->pbuddy_adapter; ++ ++ //tsf = pmlmeext->TSFValue - ((u32)pmlmeext->TSFValue % (pmlmeinfo->bcn_interval*1024)) -1024; //us ++ tsf = pmlmeext->TSFValue - rtw_modular64(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval*1024)) -1024; //us ++ ++ if(((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) ++ { ++ //pHalData->RegTxPause |= STOP_BCNQ;BIT(6) ++ //rtw_write8(Adapter, REG_TXPAUSE, (rtw_read8(Adapter, REG_TXPAUSE)|BIT(6))); ++ StopTxBeacon(Adapter); ++ } ++ ++ if(Adapter->iface_type == IFACE_PORT1) ++ { ++ //disable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)&(~BIT(3))); ++ ++ rtw_write32(Adapter, REG_TSFTR1, tsf); ++ rtw_write32(Adapter, REG_TSFTR1+4, tsf>>32); ++ ++ ++ //enable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)|BIT(3)); ++ ++ // Update buddy port's TSF if it is SoftAP for beacon TX issue! ++ if ( (pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE ++ && check_buddy_fwstate(Adapter, WIFI_AP_STATE) ++ ) { ++ //disable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(3))); ++ ++ rtw_write32(Adapter, REG_TSFTR, tsf); ++ rtw_write32(Adapter, REG_TSFTR+4, tsf>>32); ++ ++ //enable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(3)); ++#ifdef CONFIG_TSF_RESET_OFFLOAD ++ // Update buddy port's TSF(TBTT) if it is SoftAP for beacon TX issue! ++ if (reset_tsf(Adapter, IFACE_PORT0) == _FALSE) ++ DBG_871X("ERROR! %s()-%d: Reset port0 TSF fail\n", ++ __FUNCTION__, __LINE__); ++ ++#endif // CONFIG_TSF_RESET_OFFLOAD ++ } ++ ++ ++ } ++ else ++ { ++ //disable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(3))); ++ ++ rtw_write32(Adapter, REG_TSFTR, tsf); ++ rtw_write32(Adapter, REG_TSFTR+4, tsf>>32); ++ ++ //enable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(3)); ++ ++ // Update buddy port's TSF if it is SoftAP for beacon TX issue! ++ if ( (pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE ++ && check_buddy_fwstate(Adapter, WIFI_AP_STATE) ++ ) { ++ //disable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)&(~BIT(3))); ++ ++ rtw_write32(Adapter, REG_TSFTR1, tsf); ++ rtw_write32(Adapter, REG_TSFTR1+4, tsf>>32); ++ ++ //enable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)|BIT(3)); ++#ifdef CONFIG_TSF_RESET_OFFLOAD ++ // Update buddy port's TSF if it is SoftAP for beacon TX issue! ++ if (reset_tsf(Adapter, IFACE_PORT1) == _FALSE) ++ DBG_871X("ERROR! %s()-%d: Reset port1 TSF fail\n", ++ __FUNCTION__, __LINE__); ++#endif // CONFIG_TSF_RESET_OFFLOAD ++ } ++ ++ } ++ ++ ++ if(((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) ++ { ++ //pHalData->RegTxPause &= (~STOP_BCNQ); ++ //rtw_write8(Adapter, REG_TXPAUSE, (rtw_read8(Adapter, REG_TXPAUSE)&(~BIT(6)))); ++ ResumeTxBeacon(Adapter); ++ } ++#endif ++} ++ ++static void hw_var_set_mlme_disconnect(PADAPTER Adapter, u8 variable, u8* val) ++{ ++#ifdef CONFIG_CONCURRENT_MODE ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ PADAPTER pbuddy_adapter = Adapter->pbuddy_adapter; ++ ++ ++ if(check_buddy_mlmeinfo_state(Adapter, _HW_STATE_NOLINK_)) ++ rtw_write16(Adapter, REG_RXFLTMAP2, 0x00); ++ ++ ++ if(Adapter->iface_type == IFACE_PORT1) ++ { ++ //reset TSF1 ++ rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(1)); ++ ++ //disable update TSF1 ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)|BIT(4)); ++ ++ // disable Port1's beacon function ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)&(~BIT(3))); ++ } ++ else ++ { ++ //reset TSF ++ rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(0)); ++ ++ //disable update TSF ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4)); ++ } ++#endif ++} ++ ++static void hw_var_set_mlme_sitesurvey(PADAPTER Adapter, u8 variable, u8* val) ++{ ++#ifdef CONFIG_CONCURRENT_MODE ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if(*((u8 *)val))//under sitesurvey ++ { ++ //config RCR to receive different BSSID & not to receive data frame ++ u32 v = rtw_read32(Adapter, REG_RCR); ++ v &= ~(RCR_CBSSID_BCN); ++ rtw_write32(Adapter, REG_RCR, v); ++ ++ //disable update TSF ++ if((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) ++ { ++ if(Adapter->iface_type == IFACE_PORT1) ++ { ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)|BIT(4)); ++ } ++ else ++ { ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4)); ++ } ++ } ++ ++ if(check_buddy_mlmeinfo_state(Adapter, WIFI_FW_AP_STATE) && ++ check_buddy_fwstate(Adapter, _FW_LINKED)) ++ { ++ StopTxBeacon(Adapter); ++ } ++ } ++ else//sitesurvey done ++ { ++ //enable to rx data frame ++ //write32(Adapter, REG_RCR, read32(padapter, REG_RCR)|RCR_ADF); ++ rtw_write16(Adapter, REG_RXFLTMAP2,0xFFFF); ++ ++ //enable update TSF ++ if(Adapter->iface_type == IFACE_PORT1) ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)&(~BIT(4))); ++ else ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4))); ++ ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_BCN); ++ ++ if(check_buddy_mlmeinfo_state(Adapter, WIFI_FW_AP_STATE) && ++ check_buddy_fwstate(Adapter, _FW_LINKED)) ++ { ++ ResumeTxBeacon(Adapter); ++ } ++ } ++#endif ++} ++ ++static void hw_var_set_mlme_join(PADAPTER Adapter, u8 variable, u8* val) ++{ ++#ifdef CONFIG_CONCURRENT_MODE ++ u8 RetryLimit = 0x30; ++ u8 type = *((u8 *)val); ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ ++ if(type == 0) // prepare to join ++ { ++ if(check_buddy_mlmeinfo_state(Adapter, WIFI_FW_AP_STATE) && ++ check_buddy_fwstate(Adapter, _FW_LINKED)) ++ { ++ StopTxBeacon(Adapter); ++ } ++ ++ //enable to rx data frame.Accept all data frame ++ //rtw_write32(padapter, REG_RCR, rtw_read32(padapter, REG_RCR)|RCR_ADF); ++ rtw_write16(Adapter, REG_RXFLTMAP2,0xFFFF); ++ ++ if(check_buddy_mlmeinfo_state(Adapter, WIFI_FW_AP_STATE)) ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_BCN); ++ else ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_DATA|RCR_CBSSID_BCN); ++ ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) ++ { ++ RetryLimit = (pHalData->CustomerID == RT_CID_CCX) ? 7 : 48; ++ } ++ else // Ad-hoc Mode ++ { ++ RetryLimit = 0x7; ++ } ++ } ++ else if(type == 1) //joinbss_event call back when join res < 0 ++ { ++ if(check_buddy_mlmeinfo_state(Adapter, _HW_STATE_NOLINK_)) ++ rtw_write16(Adapter, REG_RXFLTMAP2,0x00); ++ ++ if(check_buddy_mlmeinfo_state(Adapter, WIFI_FW_AP_STATE) && ++ check_buddy_fwstate(Adapter, _FW_LINKED)) ++ { ++ ResumeTxBeacon(Adapter); ++ ++ //reset TSF 1/2 after ResumeTxBeacon ++ rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(1)|BIT(0)); ++ ++ } ++ } ++ else if(type == 2) //sta add event call back ++ { ++ ++ //enable update TSF ++ if(Adapter->iface_type == IFACE_PORT1) ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1)&(~BIT(4))); ++ else ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4))); ++ ++ ++ if(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) ++ { ++ //fixed beacon issue for 8191su........... ++ rtw_write8(Adapter,0x542 ,0x02); ++ RetryLimit = 0x7; ++ } ++ ++ ++ if(check_buddy_mlmeinfo_state(Adapter, WIFI_FW_AP_STATE) && ++ check_buddy_fwstate(Adapter, _FW_LINKED)) ++ { ++ ResumeTxBeacon(Adapter); ++ ++ //reset TSF 1/2 after ResumeTxBeacon ++ rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(1)|BIT(0)); ++ } ++ ++ } ++ ++ rtw_write16(Adapter, REG_RL, RetryLimit << RETRY_LIMIT_SHORT_SHIFT | RetryLimit << RETRY_LIMIT_LONG_SHIFT); ++ ++#endif ++} ++ ++void SetHwReg8188EU(PADAPTER Adapter, u8 variable, u8* val) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ DM_ODM_T *podmpriv = &pHalData->odmpriv; ++_func_enter_; ++ ++ switch(variable) ++ { ++ case HW_VAR_MEDIA_STATUS: ++ { ++ u8 val8; ++ ++ val8 = rtw_read8(Adapter, MSR)&0x0c; ++ val8 |= *((u8 *)val); ++ rtw_write8(Adapter, MSR, val8); ++ } ++ break; ++ case HW_VAR_MEDIA_STATUS1: ++ { ++ u8 val8; ++ ++ val8 = rtw_read8(Adapter, MSR)&0x03; ++ val8 |= *((u8 *)val) <<2; ++ rtw_write8(Adapter, MSR, val8); ++ } ++ break; ++ case HW_VAR_SET_OPMODE: ++ hw_var_set_opmode(Adapter, variable, val); ++ break; ++ case HW_VAR_MAC_ADDR: ++ hw_var_set_macaddr(Adapter, variable, val); ++ break; ++ case HW_VAR_BSSID: ++ hw_var_set_bssid(Adapter, variable, val); ++ break; ++ case HW_VAR_BASIC_RATE: ++ { ++ u16 BrateCfg = 0; ++ u8 RateIndex = 0; ++ ++ // 2007.01.16, by Emily ++ // Select RRSR (in Legacy-OFDM and CCK) ++ // For 8190, we select only 24M, 12M, 6M, 11M, 5.5M, 2M, and 1M from the Basic rate. ++ // We do not use other rates. ++ HalSetBrateCfg( Adapter, val, &BrateCfg ); ++ DBG_8192C("HW_VAR_BASIC_RATE: BrateCfg(%#x)\n", BrateCfg); ++ ++ //2011.03.30 add by Luke Lee ++ //CCK 2M ACK should be disabled for some BCM and Atheros AP IOT ++ //because CCK 2M has poor TXEVM ++ //CCK 5.5M & 11M ACK should be enabled for better performance ++ ++ pHalData->BasicRateSet = BrateCfg = (BrateCfg |0xd) & 0x15d; ++ ++ BrateCfg |= 0x01; // default enable 1M ACK rate ++ // Set RRSR rate table. ++ rtw_write8(Adapter, REG_RRSR, BrateCfg&0xff); ++ rtw_write8(Adapter, REG_RRSR+1, (BrateCfg>>8)&0xff); ++ rtw_write8(Adapter, REG_RRSR+2, rtw_read8(Adapter, REG_RRSR+2)&0xf0); ++ ++ // Set RTS initial rate ++ while(BrateCfg > 0x1) ++ { ++ BrateCfg = (BrateCfg>> 1); ++ RateIndex++; ++ } ++ // Ziv - Check ++ rtw_write8(Adapter, REG_INIRTS_RATE_SEL, RateIndex); ++ } ++ break; ++ case HW_VAR_TXPAUSE: ++ rtw_write8(Adapter, REG_TXPAUSE, *((u8 *)val)); ++ break; ++ case HW_VAR_BCN_FUNC: ++ hw_var_set_bcn_func(Adapter, variable, val); ++ break; ++ case HW_VAR_CORRECT_TSF: ++#ifdef CONFIG_CONCURRENT_MODE ++ hw_var_set_correct_tsf(Adapter, variable, val); ++#else ++ { ++ u64 tsf; ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ //tsf = pmlmeext->TSFValue - ((u32)pmlmeext->TSFValue % (pmlmeinfo->bcn_interval*1024)) -1024; //us ++ tsf = pmlmeext->TSFValue - rtw_modular64(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval*1024)) -1024; //us ++ ++ if(((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) ++ { ++ //pHalData->RegTxPause |= STOP_BCNQ;BIT(6) ++ //rtw_write8(Adapter, REG_TXPAUSE, (rtw_read8(Adapter, REG_TXPAUSE)|BIT(6))); ++ StopTxBeacon(Adapter); ++ } ++ ++ //disable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(3))); ++ ++ rtw_write32(Adapter, REG_TSFTR, tsf); ++ rtw_write32(Adapter, REG_TSFTR+4, tsf>>32); ++ ++ //enable related TSF function ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(3)); ++ ++ ++ if(((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) ++ { ++ //pHalData->RegTxPause &= (~STOP_BCNQ); ++ //rtw_write8(Adapter, REG_TXPAUSE, (rtw_read8(Adapter, REG_TXPAUSE)&(~BIT(6)))); ++ ResumeTxBeacon(Adapter); ++ } ++ } ++#endif ++ break; ++ case HW_VAR_CHECK_BSSID: ++ if(*((u8 *)val)) ++ { ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_DATA|RCR_CBSSID_BCN); ++ } ++ else ++ { ++ u32 val32; ++ ++ val32 = rtw_read32(Adapter, REG_RCR); ++ ++ val32 &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN); ++ ++ rtw_write32(Adapter, REG_RCR, val32); ++ } ++ break; ++ case HW_VAR_MLME_DISCONNECT: ++#ifdef CONFIG_CONCURRENT_MODE ++ hw_var_set_mlme_disconnect(Adapter, variable, val); ++#else ++ { ++ //Set RCR to not to receive data frame when NO LINK state ++ //rtw_write32(Adapter, REG_RCR, rtw_read32(padapter, REG_RCR) & ~RCR_ADF); ++ //reject all data frames ++ rtw_write16(Adapter, REG_RXFLTMAP2,0x00); ++ ++ //reset TSF ++ rtw_write8(Adapter, REG_DUAL_TSF_RST, (BIT(0)|BIT(1))); ++ ++ //disable update TSF ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4)); ++ } ++#endif ++ break; ++ case HW_VAR_MLME_SITESURVEY: ++#ifdef CONFIG_CONCURRENT_MODE ++ hw_var_set_mlme_sitesurvey(Adapter, variable, val); ++#else ++ if(*((u8 *)val))//under sitesurvey ++ { ++ //config RCR to receive different BSSID & not to receive data frame ++ u32 v = rtw_read32(Adapter, REG_RCR); ++ v &= ~(RCR_CBSSID_BCN); ++ rtw_write32(Adapter, REG_RCR, v); ++ //reject all data frame ++ rtw_write16(Adapter, REG_RXFLTMAP2,0x00); ++ ++ //disable update TSF ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4)); ++ } ++ else//sitesurvey done ++ { ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if ((is_client_associated_to_ap(Adapter) == _TRUE) || ++ ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) ) ++ { ++ //enable to rx data frame ++ //rtw_write32(Adapter, REG_RCR, rtw_read32(padapter, REG_RCR)|RCR_ADF); ++ rtw_write16(Adapter, REG_RXFLTMAP2,0xFFFF); ++ ++ //enable update TSF ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4))); ++ } ++ else if((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ { ++ //rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_ADF); ++ rtw_write16(Adapter, REG_RXFLTMAP2,0xFFFF); ++ ++ //enable update TSF ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4))); ++ } ++ ++ if((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_BCN); ++ else ++ { ++ if(Adapter->in_cta_test) ++ { ++ u32 v = rtw_read32(Adapter, REG_RCR); ++ v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN );//| RCR_ADF ++ rtw_write32(Adapter, REG_RCR, v); ++ } ++ else ++ { ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_BCN); ++ } ++ } ++ } ++#endif ++ break; ++ case HW_VAR_MLME_JOIN: ++#ifdef CONFIG_CONCURRENT_MODE ++ hw_var_set_mlme_join(Adapter, variable, val); ++#else ++ { ++ u8 RetryLimit = 0x30; ++ u8 type = *((u8 *)val); ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ ++ if(type == 0) // prepare to join ++ { ++ //enable to rx data frame.Accept all data frame ++ //rtw_write32(padapter, REG_RCR, rtw_read32(padapter, REG_RCR)|RCR_ADF); ++ rtw_write16(Adapter, REG_RXFLTMAP2,0xFFFF); ++ ++ if(Adapter->in_cta_test) ++ { ++ u32 v = rtw_read32(Adapter, REG_RCR); ++ v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN );//| RCR_ADF ++ rtw_write32(Adapter, REG_RCR, v); ++ } ++ else ++ { ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_DATA|RCR_CBSSID_BCN); ++ } ++ ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) ++ { ++ RetryLimit = (pHalData->CustomerID == RT_CID_CCX) ? 7 : 48; ++ } ++ else // Ad-hoc Mode ++ { ++ RetryLimit = 0x7; ++ } ++ } ++ else if(type == 1) //joinbss_event call back when join res < 0 ++ { ++ rtw_write16(Adapter, REG_RXFLTMAP2,0x00); ++ } ++ else if(type == 2) //sta add event call back ++ { ++ //enable update TSF ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4))); ++ ++ if(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) ++ { ++ RetryLimit = 0x7; ++ } ++ } ++ ++ rtw_write16(Adapter, REG_RL, RetryLimit << RETRY_LIMIT_SHORT_SHIFT | RetryLimit << RETRY_LIMIT_LONG_SHIFT); ++ } ++#endif ++ break; ++ case HW_VAR_ON_RCR_AM: ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_AM); ++ DBG_871X("%s, %d, RCR= %x \n", __FUNCTION__,__LINE__, rtw_read32(Adapter, REG_RCR)); ++ break; ++ case HW_VAR_OFF_RCR_AM: ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)& (~RCR_AM)); ++ DBG_871X("%s, %d, RCR= %x \n", __FUNCTION__,__LINE__, rtw_read32(Adapter, REG_RCR)); ++ break; ++ case HW_VAR_BEACON_INTERVAL: ++ rtw_write16(Adapter, REG_BCN_INTERVAL, *((u16 *)val)); ++#ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ { ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u16 bcn_interval = *((u16 *)val); ++ if((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE){ ++ DBG_8192C("%s==> bcn_interval:%d, eraly_int:%d \n",__FUNCTION__,bcn_interval,bcn_interval>>1); ++ rtw_write8(Adapter, REG_DRVERLYINT, bcn_interval>>1);// 50ms for sdio ++ } ++ } ++#endif//CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ ++ break; ++ case HW_VAR_SLOT_TIME: ++ { ++ u8 u1bAIFS, aSifsTime; ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ rtw_write8(Adapter, REG_SLOT, val[0]); ++ ++ if(pmlmeinfo->WMM_enable == 0) ++ { ++ if( pmlmeext->cur_wireless_mode == WIRELESS_11B) ++ aSifsTime = 10; ++ else ++ aSifsTime = 16; ++ ++ u1bAIFS = aSifsTime + (2 * pmlmeinfo->slotTime); ++ ++ // Temporary removed, 2008.06.20. ++ rtw_write8(Adapter, REG_EDCA_VO_PARAM, u1bAIFS); ++ rtw_write8(Adapter, REG_EDCA_VI_PARAM, u1bAIFS); ++ rtw_write8(Adapter, REG_EDCA_BE_PARAM, u1bAIFS); ++ rtw_write8(Adapter, REG_EDCA_BK_PARAM, u1bAIFS); ++ } ++ } ++ break; ++ case HW_VAR_RESP_SIFS: ++ { ++#if 0 ++ // SIFS for OFDM Data ACK ++ rtw_write8(Adapter, REG_SIFS_CTX+1, val[0]); ++ // SIFS for OFDM consecutive tx like CTS data! ++ rtw_write8(Adapter, REG_SIFS_TRX+1, val[1]); ++ ++ rtw_write8(Adapter,REG_SPEC_SIFS+1, val[0]); ++ rtw_write8(Adapter,REG_MAC_SPEC_SIFS+1, val[0]); ++ ++ // 20100719 Joseph: Revise SIFS setting due to Hardware register definition change. ++ rtw_write8(Adapter, REG_R2T_SIFS+1, val[0]); ++ rtw_write8(Adapter, REG_T2T_SIFS+1, val[0]); ++#else ++ ++ //SIFS_Timer = 0x0a0a0808; ++ //RESP_SIFS for CCK ++ rtw_write8(Adapter, REG_R2T_SIFS, val[0]); // SIFS_T2T_CCK (0x08) ++ rtw_write8(Adapter, REG_R2T_SIFS+1, val[1]); //SIFS_R2T_CCK(0x08) ++ //RESP_SIFS for OFDM ++ rtw_write8(Adapter, REG_T2T_SIFS, val[2]); //SIFS_T2T_OFDM (0x0a) ++ rtw_write8(Adapter, REG_T2T_SIFS+1, val[3]); //SIFS_R2T_OFDM(0x0a) ++#endif ++ } ++ break; ++ case HW_VAR_ACK_PREAMBLE: ++ { ++ u8 regTmp; ++ u8 bShortPreamble = *( (PBOOLEAN)val ); ++ // Joseph marked out for Netgear 3500 TKIP channel 7 issue.(Temporarily) ++ regTmp = (pHalData->nCur40MhzPrimeSC)<<5; ++ //regTmp = 0; ++ if(bShortPreamble) ++ regTmp |= 0x80; ++ ++ rtw_write8(Adapter, REG_RRSR+2, regTmp); ++ } ++ break; ++ case HW_VAR_SEC_CFG: ++#ifdef CONFIG_CONCURRENT_MODE ++ rtw_write8(Adapter, REG_SECCFG, 0x0c|BIT(5));// enable tx enc and rx dec engine, and no key search for MC/BC ++#else ++ rtw_write8(Adapter, REG_SECCFG, *((u8 *)val)); ++#endif ++ break; ++ case HW_VAR_DM_FLAG: ++ podmpriv->SupportAbility = *((u8 *)val); ++ //DBG_871X("HW_VAR_DM_FLAG ==> SupportAbility:0x%08x \n",podmpriv->SupportAbility ); ++ break; ++ case HW_VAR_DM_FUNC_OP: ++ if(val[0]) ++ {// save dm flag ++ podmpriv->BK_SupportAbility = podmpriv->SupportAbility; ++ } ++ else ++ {// restore dm flag ++ podmpriv->SupportAbility = podmpriv->BK_SupportAbility; ++ } ++ //DBG_871X("HW_VAR_DM_FUNC_OP ==> %s SupportAbility:0x%08x \n", ++ // (val[0]==1)?"Save":"Restore", ++ // podmpriv->SupportAbility ++ // ); ++ break; ++ case HW_VAR_DM_FUNC_SET: ++ if(*((u32 *)val) == DYNAMIC_ALL_FUNC_ENABLE){ ++ pdmpriv->DMFlag = pdmpriv->InitDMFlag; ++ podmpriv->SupportAbility = pdmpriv->InitODMFlag; ++ } ++ else{ ++ podmpriv->SupportAbility |= *((u32 *)val); ++ } ++ //DBG_871X("HW_VAR_DM_FUNC_SET ==> SupportAbility:0x%08x \n",podmpriv->SupportAbility ); ++ break; ++ case HW_VAR_DM_FUNC_CLR: ++ podmpriv->SupportAbility &= *((u32 *)val); ++ break; ++ ++ case HW_VAR_CAM_EMPTY_ENTRY: ++ { ++ u8 ucIndex = *((u8 *)val); ++ u8 i; ++ u32 ulCommand=0; ++ u32 ulContent=0; ++ u32 ulEncAlgo=CAM_AES; ++ ++ for(i=0;iAcParam_BE = ((u32 *)(val))[0]; ++ rtw_write32(Adapter, REG_EDCA_BE_PARAM, ((u32 *)(val))[0]); ++ break; ++ case HW_VAR_AC_PARAM_BK: ++ rtw_write32(Adapter, REG_EDCA_BK_PARAM, ((u32 *)(val))[0]); ++ break; ++ case HW_VAR_ACM_CTRL: ++ { ++ u8 acm_ctrl = *((u8 *)val); ++ u8 AcmCtrl = rtw_read8( Adapter, REG_ACMHWCTRL); ++ ++ if(acm_ctrl > 1) ++ AcmCtrl = AcmCtrl | 0x1; ++ ++ if(acm_ctrl & BIT(3)) ++ AcmCtrl |= AcmHw_VoqEn; ++ else ++ AcmCtrl &= (~AcmHw_VoqEn); ++ ++ if(acm_ctrl & BIT(2)) ++ AcmCtrl |= AcmHw_ViqEn; ++ else ++ AcmCtrl &= (~AcmHw_ViqEn); ++ ++ if(acm_ctrl & BIT(1)) ++ AcmCtrl |= AcmHw_BeqEn; ++ else ++ AcmCtrl &= (~AcmHw_BeqEn); ++ ++ DBG_871X("[HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl ); ++ rtw_write8(Adapter, REG_ACMHWCTRL, AcmCtrl ); ++ } ++ break; ++ case HW_VAR_AMPDU_MIN_SPACE: ++ { ++ u8 MinSpacingToSet; ++ u8 SecMinSpace; ++ ++ MinSpacingToSet = *((u8 *)val); ++ if(MinSpacingToSet <= 7) ++ { ++ switch(Adapter->securitypriv.dot11PrivacyAlgrthm) ++ { ++ case _NO_PRIVACY_: ++ case _AES_: ++ SecMinSpace = 0; ++ break; ++ ++ case _WEP40_: ++ case _WEP104_: ++ case _TKIP_: ++ case _TKIP_WTMIC_: ++ SecMinSpace = 6; ++ break; ++ default: ++ SecMinSpace = 7; ++ break; ++ } ++ ++ if(MinSpacingToSet < SecMinSpace){ ++ MinSpacingToSet = SecMinSpace; ++ } ++ ++ //RT_TRACE(COMP_MLME, DBG_LOUD, ("Set HW_VAR_AMPDU_MIN_SPACE: %#x\n", Adapter->MgntInfo.MinSpaceCfg)); ++ rtw_write8(Adapter, REG_AMPDU_MIN_SPACE, (rtw_read8(Adapter, REG_AMPDU_MIN_SPACE) & 0xf8) | MinSpacingToSet); ++ } ++ } ++ break; ++ case HW_VAR_AMPDU_FACTOR: ++ { ++ u8 RegToSet_Normal[4]={0x41,0xa8,0x72, 0xb9}; ++ u8 RegToSet_BT[4]={0x31,0x74,0x42, 0x97}; ++ u8 FactorToSet; ++ u8 *pRegToSet; ++ u8 index = 0; ++ ++#ifdef CONFIG_BT_COEXIST ++ if( (pHalData->bt_coexist.BT_Coexist) && ++ (pHalData->bt_coexist.BT_CoexistType == BT_CSR_BC4) ) ++ pRegToSet = RegToSet_BT; // 0x97427431; ++ else ++#endif ++ pRegToSet = RegToSet_Normal; // 0xb972a841; ++ ++ FactorToSet = *((u8 *)val); ++ if(FactorToSet <= 3) ++ { ++ FactorToSet = (1<<(FactorToSet + 2)); ++ if(FactorToSet>0xf) ++ FactorToSet = 0xf; ++ ++ for(index=0; index<4; index++) ++ { ++ if((pRegToSet[index] & 0xf0) > (FactorToSet<<4)) ++ pRegToSet[index] = (pRegToSet[index] & 0x0f) | (FactorToSet<<4); ++ ++ if((pRegToSet[index] & 0x0f) > FactorToSet) ++ pRegToSet[index] = (pRegToSet[index] & 0xf0) | (FactorToSet); ++ ++ rtw_write8(Adapter, (REG_AGGLEN_LMT+index), pRegToSet[index]); ++ } ++ ++ //RT_TRACE(COMP_MLME, DBG_LOUD, ("Set HW_VAR_AMPDU_FACTOR: %#x\n", FactorToSet)); ++ } ++ } ++ break; ++ case HW_VAR_RXDMA_AGG_PG_TH: ++ #ifdef CONFIG_USB_RX_AGGREGATION ++ { ++ u8 threshold = *((u8 *)val); ++ if( threshold == 0) ++ { ++ threshold = pHalData->UsbRxAggPageCount; ++ } ++ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH, threshold); ++ } ++ #endif ++ break; ++ case HW_VAR_SET_RPWM: ++#ifdef CONFIG_LPS_LCLK ++ { ++ u8 ps_state = *((u8 *)val); ++ //rpwm value only use BIT0(clock bit) ,BIT6(Ack bit), and BIT7(Toggle bit) for 88e. ++ //BIT0 value - 1: 32k, 0:40MHz. ++ //BIT6 value - 1: report cpwm value after success set, 0:do not report. ++ //BIT7 value - Toggle bit change. ++ //modify by Thomas. 2012/4/2. ++ ps_state = ps_state & 0xC1; ++ //DBG_871X("##### Change RPWM value to = %x for switch clk #####\n",ps_state); ++ rtw_write8(Adapter, REG_USB_HRPWM, ps_state); ++ } ++#endif ++ break; ++ case HW_VAR_H2C_FW_PWRMODE: ++ { ++ u8 psmode = (*(u8 *)val); ++ ++ // Forece leave RF low power mode for 1T1R to prevent conficting setting in Fw power ++ // saving sequence. 2010.06.07. Added by tynli. Suggested by SD3 yschang. ++ if( (psmode != PS_MODE_ACTIVE) && (!IS_92C_SERIAL(pHalData->VersionID))) ++ { ++ ODM_RF_Saving(podmpriv, _TRUE); ++ } ++ rtl8188e_set_FwPwrMode_cmd(Adapter, psmode); ++ } ++ break; ++ case HW_VAR_H2C_FW_JOINBSSRPT: ++ { ++ u8 mstatus = (*(u8 *)val); ++ rtl8188e_set_FwJoinBssReport_cmd(Adapter, mstatus); ++ } ++ break; ++#ifdef CONFIG_P2P_PS ++ case HW_VAR_H2C_FW_P2P_PS_OFFLOAD: ++ { ++ u8 p2p_ps_state = (*(u8 *)val); ++ rtl8188e_set_p2p_ps_offload_cmd(Adapter, p2p_ps_state); ++ } ++ break; ++#endif //CONFIG_P2P_PS ++#ifdef CONFIG_TDLS ++ case HW_VAR_TDLS_WRCR: ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)&(~RCR_CBSSID_DATA )); ++ break; ++ case HW_VAR_TDLS_INIT_CH_SEN: ++ { ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)&(~ RCR_CBSSID_DATA )&(~RCR_CBSSID_BCN )); ++ rtw_write16(Adapter, REG_RXFLTMAP2,0xffff); ++ ++ //disable update TSF ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4)); ++ } ++ break; ++ case HW_VAR_TDLS_DONE_CH_SEN: ++ { ++ //enable update TSF ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~ BIT(4))); ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|(RCR_CBSSID_BCN )); ++ } ++ break; ++ case HW_VAR_TDLS_RS_RCR: ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|(RCR_CBSSID_DATA)); ++ break; ++#endif //CONFIG_TDLS ++ case HW_VAR_INITIAL_GAIN: ++ { ++ DIG_T *pDigTable = &podmpriv->DM_DigTable; ++ u32 rx_gain = ((u32 *)(val))[0]; ++ ++ if(rx_gain == 0xff){//restore rx gain ++ ODM_Write_DIG(podmpriv,pDigTable->BackupIGValue); ++ } ++ else{ ++ pDigTable->BackupIGValue = pDigTable->CurIGValue; ++ ODM_Write_DIG(podmpriv,rx_gain); ++ } ++ } ++ break; ++ case HW_VAR_TRIGGER_GPIO_0: ++ rtl8192cu_trigger_gpio_0(Adapter); ++ break; ++#ifdef CONFIG_BT_COEXIST ++ case HW_VAR_BT_SET_COEXIST: ++ { ++ u8 bStart = (*(u8 *)val); ++ rtl8192c_set_dm_bt_coexist(Adapter, bStart); ++ } ++ break; ++ case HW_VAR_BT_ISSUE_DELBA: ++ { ++ u8 dir = (*(u8 *)val); ++ rtl8192c_issue_delete_ba(Adapter, dir); ++ } ++ break; ++#endif ++#if (RATE_ADAPTIVE_SUPPORT==1) ++ case HW_VAR_RPT_TIMER_SETTING: ++ { ++ u16 min_rpt_time = (*(u16 *)val); ++ ODM_RA_Set_TxRPT_Time(podmpriv,min_rpt_time); ++ } ++ break; ++#endif ++#ifdef CONFIG_SW_ANTENNA_DIVERSITY ++ ++ case HW_VAR_ANTENNA_DIVERSITY_LINK: ++ //odm_SwAntDivRestAfterLink8192C(Adapter); ++ ODM_SwAntDivRestAfterLink(podmpriv); ++ break; ++#endif ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ case HW_VAR_ANTENNA_DIVERSITY_SELECT: ++ { ++ u8 Optimum_antenna = (*(u8 *)val); ++ u8 Ant ; ++ //switch antenna to Optimum_antenna ++ //DBG_8192C("==> HW_VAR_ANTENNA_DIVERSITY_SELECT , Ant_(%s)\n",(Optimum_antenna==2)?"A":"B"); ++ if(pHalData->CurAntenna != Optimum_antenna) ++ { ++ Ant = (Optimum_antenna==2)?MAIN_ANT:AUX_ANT; ++ ODM_UpdateRxIdleAnt_88E(&pHalData->odmpriv, Ant); ++ ++ pHalData->CurAntenna = Optimum_antenna ; ++ //DBG_8192C("==> HW_VAR_ANTENNA_DIVERSITY_SELECT , Ant_(%s)\n",(Optimum_antenna==2)?"A":"B"); ++ } ++ } ++ break; ++#endif ++ case HW_VAR_EFUSE_BYTES: // To set EFUE total used bytes, added by Roger, 2008.12.22. ++ pHalData->EfuseUsedBytes = *((u16 *)val); ++ break; ++ case HW_VAR_FIFO_CLEARN_UP: ++ { ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(Adapter); ++ u8 trycnt = 100; ++ ++ //pause tx ++ rtw_write8(Adapter,REG_TXPAUSE,0xff); ++ ++ //keep sn ++ Adapter->xmitpriv.nqos_ssn = rtw_read16(Adapter,REG_NQOS_SEQ); ++ ++ if(pwrpriv->bkeepfwalive != _TRUE) ++ { ++ //RX DMA stop ++ rtw_write32(Adapter,REG_RXPKT_NUM,(rtw_read32(Adapter,REG_RXPKT_NUM)|RW_RELEASE_EN)); ++ do{ ++ if(!(rtw_read32(Adapter,REG_RXPKT_NUM)&RXDMA_IDLE)) ++ break; ++ }while(trycnt--); ++ if(trycnt ==0) ++ DBG_8192C("Stop RX DMA failed...... \n"); ++ ++ //RQPN Load 0 ++ rtw_write16(Adapter,REG_RQPN_NPQ,0x0); ++ rtw_write32(Adapter,REG_RQPN,0x80000000); ++ rtw_mdelay_os(10); ++ } ++ } ++ break; ++ case HW_VAR_CHECK_TXBUF: ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ { ++ int i; ++ #if 0 //for Miracast source PKT lost issue ++ u8 RetryLimit = 0x01; ++ rtw_write16(Adapter, REG_RL, RetryLimit << RETRY_LIMIT_SHORT_SHIFT | RetryLimit << RETRY_LIMIT_LONG_SHIFT); ++ #endif ++ ++ for(i=0;i<1000;i++) ++ { ++ if(rtw_read32(Adapter, 0x200) != rtw_read32(Adapter, 0x204)) ++ { ++ //DBG_871X("packet in tx packet buffer - 0x204=%x, 0x200=%x (%d)\n", rtw_read32(Adapter, 0x204), rtw_read32(Adapter, 0x200), i); ++ rtw_msleep_os(10); ++ } ++ else ++ { ++ DBG_871X("no packet in tx packet buffer (%d)\n", i); ++ break; ++ } ++ } ++ #if 0 //for Miracast source PKT lost issue ++ RetryLimit = 0x30; ++ rtw_write16(Adapter, REG_RL, RetryLimit << RETRY_LIMIT_SHORT_SHIFT | RetryLimit << RETRY_LIMIT_LONG_SHIFT); ++ #endif ++ } ++#endif ++ break; ++ ++ case HW_VAR_APFM_ON_MAC: ++ pHalData->bMacPwrCtrlOn = *val; ++ DBG_871X("%s: bMacPwrCtrlOn=%d\n", __func__, pHalData->bMacPwrCtrlOn); ++ break; ++ ++#ifdef CONFIG_WOWLAN ++ case HW_VAR_WOWLAN: ++ { ++ struct wowlan_ioctl_param *poidparam; ++ struct recv_buf *precvbuf; ++ int res, i; ++ u32 tmp; ++ u16 len = 0; ++ u8 mstatus = (*(u8 *)val); ++ u8 trycnt = 100; ++ u8 data[4]; ++ ++ poidparam = (struct wowlan_ioctl_param *)val; ++ switch (poidparam->subcode){ ++ case WOWLAN_ENABLE: ++ DBG_871X_LEVEL(_drv_always_, "WOWLAN_ENABLE\n"); ++ ++ SetFwRelatedForWoWLAN8188ES(Adapter, _TRUE); ++ ++ //Set Pattern ++ //if(adapter_to_pwrctl(Adapter)->wowlan_pattern==_TRUE) ++ // rtw_wowlan_reload_pattern(Adapter); ++ ++ //RX DMA stop ++ DBG_871X_LEVEL(_drv_always_, "Pause DMA\n"); ++ rtw_write32(Adapter,REG_RXPKT_NUM,(rtw_read32(Adapter,REG_RXPKT_NUM)|RW_RELEASE_EN)); ++ do{ ++ if((rtw_read32(Adapter, REG_RXPKT_NUM)&RXDMA_IDLE)) { ++ DBG_871X_LEVEL(_drv_always_, "RX_DMA_IDLE is true\n"); ++ break; ++ } else { ++ // If RX_DMA is not idle, receive one pkt from DMA ++ DBG_871X_LEVEL(_drv_always_, "RX_DMA_IDLE is not true\n"); ++ } ++ }while(trycnt--); ++ if(trycnt ==0) ++ DBG_871X_LEVEL(_drv_always_, "Stop RX DMA failed...... \n"); ++ ++ //Set WOWLAN H2C command. ++ DBG_871X_LEVEL(_drv_always_, "Set WOWLan cmd\n"); ++ rtl8188es_set_wowlan_cmd(Adapter, 1); ++ ++ mstatus = rtw_read8(Adapter, REG_WOW_CTRL); ++ trycnt = 10; ++ ++ while(!(mstatus&BIT1) && trycnt>1) { ++ mstatus = rtw_read8(Adapter, REG_WOW_CTRL); ++ DBG_871X_LEVEL(_drv_always_, "Loop index: %d :0x%02x\n", trycnt, mstatus); ++ trycnt --; ++ rtw_msleep_os(2); ++ } ++ ++ adapter_to_pwrctl(Adapter)->wowlan_wake_reason = rtw_read8(Adapter, REG_WOWLAN_WAKE_REASON); ++ DBG_871X_LEVEL(_drv_always_, "wowlan_wake_reason: 0x%02x\n", ++ adapter_to_pwrctl(Adapter)->wowlan_wake_reason); ++ ++ /* Invoid SE0 reset signal during suspending*/ ++ rtw_write8(Adapter, REG_RSV_CTRL, 0x20); ++ rtw_write8(Adapter, REG_RSV_CTRL, 0x60); ++ ++ //rtw_msleep_os(10); ++ break; ++ case WOWLAN_DISABLE: ++ DBG_871X_LEVEL(_drv_always_, "WOWLAN_DISABLE\n"); ++ trycnt = 10; ++ rtl8188es_set_wowlan_cmd(Adapter, 0); ++ mstatus = rtw_read8(Adapter, REG_WOW_CTRL); ++ DBG_871X_LEVEL(_drv_info_, "%s mstatus:0x%02x\n", __func__, mstatus); ++ ++ while(mstatus&BIT1 && trycnt>1) { ++ mstatus = rtw_read8(Adapter, REG_WOW_CTRL); ++ DBG_871X_LEVEL(_drv_always_, "Loop index: %d :0x%02x\n", trycnt, mstatus); ++ trycnt --; ++ rtw_msleep_os(2); ++ } ++ ++ if (mstatus & BIT1) ++ printk("System did not release RX_DMA\n"); ++ else ++ SetFwRelatedForWoWLAN8188ES(Adapter, _FALSE); ++ ++ rtw_msleep_os(2); ++ if(!(adapter_to_pwrctl(Adapter)->wowlan_wake_reason & FWDecisionDisconnect)) ++ rtl8188e_set_FwJoinBssReport_cmd(Adapter, 1); ++ //rtw_msleep_os(10); ++ break; ++ default: ++ break; ++ } ++ } ++ break; ++#endif //CONFIG_WOWLAN ++ ++ ++ #if (RATE_ADAPTIVE_SUPPORT == 1) ++ case HW_VAR_TX_RPT_MAX_MACID: ++ { ++ u8 maxMacid = *val; ++ DBG_871X("### MacID(%d),Set Max Tx RPT MID(%d)\n",maxMacid,maxMacid+1); ++ rtw_write8(Adapter, REG_TX_RPT_CTRL+1, maxMacid+1); ++ } ++ break; ++ #endif ++ case HW_VAR_H2C_MEDIA_STATUS_RPT: ++ { ++ rtl8188e_set_FwMediaStatus_cmd(Adapter , (*(u16 *)val)); ++ } ++ break; ++ case HW_VAR_BCN_VALID: ++ //BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2, write 1 to clear, Clear by sw ++ rtw_write8(Adapter, REG_TDECTRL+2, rtw_read8(Adapter, REG_TDECTRL+2) | BIT0); ++ break; ++ default: ++ ++ break; ++ } ++ ++_func_exit_; ++} ++ ++void GetHwReg8188EU(PADAPTER Adapter, u8 variable, u8* val) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ DM_ODM_T *podmpriv = &pHalData->odmpriv; ++_func_enter_; ++ ++ switch(variable) ++ { ++ case HW_VAR_BASIC_RATE: ++ *((u16 *)(val)) = pHalData->BasicRateSet; ++ case HW_VAR_TXPAUSE: ++ val[0] = rtw_read8(Adapter, REG_TXPAUSE); ++ break; ++ case HW_VAR_BCN_VALID: ++ //BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2 ++ val[0] = (BIT0 & rtw_read8(Adapter, REG_TDECTRL+2))?_TRUE:_FALSE; ++ break; ++ case HW_VAR_DM_FLAG: ++ val[0] = podmpriv->SupportAbility; ++ break; ++ case HW_VAR_RF_TYPE: ++ val[0] = pHalData->rf_type; ++ break; ++ case HW_VAR_FWLPS_RF_ON: ++ { ++ //When we halt NIC, we should check if FW LPS is leave. ++ if(adapter_to_pwrctl(Adapter)->rf_pwrstate == rf_off) ++ { ++ // If it is in HW/SW Radio OFF or IPS state, we do not check Fw LPS Leave, ++ // because Fw is unload. ++ val[0] = _TRUE; ++ } ++ else ++ { ++ u32 valRCR; ++ valRCR = rtw_read32(Adapter, REG_RCR); ++ valRCR &= 0x00070000; ++ if(valRCR) ++ val[0] = _FALSE; ++ else ++ val[0] = _TRUE; ++ } ++ } ++ break; ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ case HW_VAR_CURRENT_ANTENNA: ++ val[0] = pHalData->CurAntenna; ++ break; ++#endif ++ case HW_VAR_EFUSE_BYTES: // To get EFUE total used bytes, added by Roger, 2008.12.22. ++ *((u16 *)(val)) = pHalData->EfuseUsedBytes; ++ break; ++ case HW_VAR_APFM_ON_MAC: ++ *val = pHalData->bMacPwrCtrlOn; ++ break; ++ case HW_VAR_CHK_HI_QUEUE_EMPTY: ++ *val = ((rtw_read32(Adapter, REG_HGQ_INFORMATION)&0x0000ff00)==0) ? _TRUE:_FALSE; ++ break; ++ ++ case HW_VAR_READ_LLT_TAB: ++ { ++ Read_LLT_Tab(Adapter); ++ } ++ break; ++ case HW_VAR_GET_CPWM: ++#ifdef CONFIG_LPS_LCLK ++ { ++ *val = rtw_read8(Adapter, REG_USB_HCPWM); ++ } ++#endif ++ break; ++ case HW_VAR_C2HEVT_CLEAR: ++ *val = rtw_read8(Adapter, REG_C2HEVT_CLEAR); ++ break; ++ case HW_VAR_C2HEVT_MSG_NORMAL: ++ *val = rtw_read8(Adapter, REG_C2HEVT_MSG_NORMAL); ++ break; ++ ++ default: ++ break; ++ } ++ ++_func_exit_; ++} ++ ++// ++// Description: ++// Query setting of specified variable. ++// ++u8 ++GetHalDefVar8188EUsb( ++ IN PADAPTER Adapter, ++ IN HAL_DEF_VARIABLE eVariable, ++ IN PVOID pValue ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ DM_ODM_T *podmpriv = &pHalData->odmpriv; ++ u8 bResult = _SUCCESS; ++ ++ switch(eVariable) ++ { ++ case HAL_DEF_UNDERCORATEDSMOOTHEDPWDB: ++#if 1 //trunk ++ { ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ struct sta_priv * pstapriv = &Adapter->stapriv; ++ struct sta_info * psta; ++ psta = rtw_get_stainfo(pstapriv, pmlmepriv->cur_network.network.MacAddress); ++ if(psta) ++ { ++ *((int *)pValue) = psta->rssi_stat.UndecoratedSmoothedPWDB; ++ } ++ } ++#else //V4 branch ++ if(check_fwstate(&Adapter->mlmepriv, WIFI_STATION_STATE) == _TRUE){ ++ *((int *)pValue) = pHalData->dmpriv.UndecoratedSmoothedPWDB; ++ } ++ else{ ++ ++ } ++#endif ++ break; ++ case HAL_DEF_IS_SUPPORT_ANT_DIV: ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ *((u8 *)pValue) = (pHalData->AntDivCfg==0)?_FALSE:_TRUE; ++#endif ++ break; ++ case HAL_DEF_CURRENT_ANTENNA: ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ *(( u8*)pValue) = pHalData->CurAntenna; ++#endif ++ break; ++ case HAL_DEF_DRVINFO_SZ: ++ *(( u32*)pValue) = DRVINFO_SZ; ++ break; ++ case HAL_DEF_MAX_RECVBUF_SZ: ++ *(( u32*)pValue) = MAX_RECVBUF_SZ; ++ break; ++ case HAL_DEF_RX_PACKET_OFFSET: ++ *(( u32*)pValue) = RXDESC_SIZE + DRVINFO_SZ; ++ break; ++#if (RATE_ADAPTIVE_SUPPORT == 1) ++ case HAL_DEF_RA_DECISION_RATE: ++ { ++ u8 MacID = *((u8*)pValue); ++ *((u8*)pValue) = ODM_RA_GetDecisionRate_8188E(podmpriv, MacID); ++ } ++ break; ++ ++ case HAL_DEF_RA_SGI: ++ { ++ u8 MacID = *((u8*)pValue); ++ *((u8*)pValue) = ODM_RA_GetShortGI_8188E(podmpriv, MacID); ++ } ++ break; ++#endif ++ ++ ++ case HAL_DEF_PT_PWR_STATUS: ++#if(POWER_TRAINING_ACTIVE==1) ++ { ++ u8 MacID = *((u8*)pValue); ++ *((u8*)pValue) = ODM_RA_GetHwPwrStatus_8188E(podmpriv, MacID); ++ } ++#endif//(POWER_TRAINING_ACTIVE==1) ++ break; ++ ++ case HW_VAR_MAX_RX_AMPDU_FACTOR: ++ *(( u32*)pValue) = MAX_AMPDU_FACTOR_64K; ++ break; ++ ++ case HW_DEF_RA_INFO_DUMP: ++#if (RATE_ADAPTIVE_SUPPORT == 1) ++ { ++ u8 entry_id = *((u8*)pValue); ++ u8 i; ++ u8 bLinked = _FALSE; ++#ifdef CONFIG_CONCURRENT_MODE ++ PADAPTER pbuddy_adapter = Adapter->pbuddy_adapter; ++#endif //CONFIG_CONCURRENT_MODE ++ ++ //if(check_fwstate(&Adapter->mlmepriv, _FW_LINKED)== _TRUE) ++ ++ if(rtw_linked_check(Adapter)) ++ bLinked = _TRUE; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(pbuddy_adapter && rtw_linked_check(pbuddy_adapter)) ++ bLinked = _TRUE; ++#endif ++ ++ if(bLinked){ ++ DBG_871X("============ RA status check ===================\n"); ++ if(Adapter->bRxRSSIDisplay >30) ++ Adapter->bRxRSSIDisplay = 1; ++ for(i=0;i< Adapter->bRxRSSIDisplay;i++){ ++ DBG_8192C("Mac_id:%d ,RSSI:%d,RateID = %d,RAUseRate = 0x%08x,RateSGI = %d, DecisionRate = 0x%02x ,PTStage = %d, RetryOver drop:%d, LifeTimeOver drop:%d\n", ++ i, ++ podmpriv->RAInfo[i].RssiStaRA, ++ podmpriv->RAInfo[i].RateID, ++ podmpriv->RAInfo[i].RAUseRate, ++ podmpriv->RAInfo[i].RateSGI, ++ podmpriv->RAInfo[i].DecisionRate, ++ podmpriv->RAInfo[i].PTStage, ++ podmpriv->RAInfo[i].DROP, ++ podmpriv->RAInfo[i].DROP1 ++ ); ++ } ++ } ++ } ++#endif //(RATE_ADAPTIVE_SUPPORT == 1) ++ break; ++ case HAL_DEF_DBG_DUMP_RXPKT: ++ *(( u8*)pValue) = pHalData->bDumpRxPkt; ++ break; ++ case HAL_DEF_DBG_DUMP_TXPKT: ++ *(( u8*)pValue) = pHalData->bDumpTxPkt; ++ break; ++ ++ default: ++ bResult = GetHalDefVar(Adapter, eVariable, pValue); ++ break; ++ } ++ ++ return bResult; ++} ++ ++ ++ ++ ++// ++// Description: ++// Change default setting of specified variable. ++// ++u8 ++SetHalDefVar8188EUsb( ++ IN PADAPTER Adapter, ++ IN HAL_DEF_VARIABLE eVariable, ++ IN PVOID pValue ++ ) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ DM_ODM_T *podmpriv = &pHalData->odmpriv; ++ u8 bResult = _SUCCESS; ++ ++ switch(eVariable) ++ { ++ case HAL_DEF_DBG_DM_FUNC: ++ { ++ u8 dm_func = *(( u8*)pValue); ++ ++ if(dm_func == 0){ //disable all dynamic func ++ podmpriv->SupportAbility = DYNAMIC_FUNC_DISABLE; ++ DBG_8192C("==> Disable all dynamic function...\n"); ++ } ++ else if(dm_func == 1){//disable DIG ++ podmpriv->SupportAbility &= (~DYNAMIC_BB_DIG); ++ DBG_8192C("==> Disable DIG...\n"); ++ } ++ else if(dm_func == 2){//disable High power ++ podmpriv->SupportAbility &= (~DYNAMIC_BB_DYNAMIC_TXPWR); ++ } ++ else if(dm_func == 3){//disable tx power tracking ++ podmpriv->SupportAbility &= (~DYNAMIC_RF_CALIBRATION); ++ DBG_8192C("==> Disable tx power tracking...\n"); ++ } ++ //else if(dm_func == 4){//disable BT coexistence ++ // pdmpriv->DMFlag &= (~DYNAMIC_FUNC_BT); ++ //} ++ else if(dm_func == 5){//disable antenna diversity ++ podmpriv->SupportAbility &= (~DYNAMIC_BB_ANT_DIV); ++ } ++ else if(dm_func == 6){//turn on all dynamic func ++ if(!(podmpriv->SupportAbility & DYNAMIC_BB_DIG)) ++ { ++ DIG_T *pDigTable = &podmpriv->DM_DigTable; ++ pDigTable->CurIGValue= rtw_read8(Adapter,0xc50); ++ } ++ //pdmpriv->DMFlag |= DYNAMIC_FUNC_BT; ++ podmpriv->SupportAbility = DYNAMIC_ALL_FUNC_ENABLE; ++ DBG_8192C("==> Turn on all dynamic function...\n"); ++ } ++ } ++ break; ++ case HAL_DEF_DBG_DUMP_RXPKT: ++ pHalData->bDumpRxPkt = *(( u8*)pValue); ++ break; ++ case HAL_DEF_DBG_DUMP_TXPKT: ++ pHalData->bDumpTxPkt = *(( u8*)pValue); ++ break; ++ default: ++ bResult = SetHalDefVar(Adapter, eVariable, pValue); ++ break; ++ } ++ ++ return bResult; ++} ++/* ++u32 _update_92cu_basic_rate(_adapter *padapter, unsigned int mask) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++#ifdef CONFIG_BT_COEXIST ++ struct btcoexist_priv *pbtpriv = &(pHalData->bt_coexist); ++#endif ++ unsigned int BrateCfg = 0; ++ ++#ifdef CONFIG_BT_COEXIST ++ if( (pbtpriv->BT_Coexist) && (pbtpriv->BT_CoexistType == BT_CSR_BC4) ) ++ { ++ BrateCfg = mask & 0x151; ++ //DBG_8192C("BT temp disable cck 2/5.5/11M, (0x%x = 0x%x)\n", REG_RRSR, BrateCfg & 0x151); ++ } ++ else ++#endif ++ { ++ //if(pHalData->VersionID != VERSION_TEST_CHIP_88C) ++ BrateCfg = mask & 0x15F; ++ //else //for 88CU 46PING setting, Disable CCK 2M, 5.5M, Others must tuning ++ // BrateCfg = mask & 0x159; ++ } ++ ++ BrateCfg |= 0x01; // default enable 1M ACK rate ++ ++ return BrateCfg; ++} ++*/ ++void _update_response_rate(_adapter *padapter,unsigned int mask) ++{ ++ u8 RateIndex = 0; ++ // Set RRSR rate table. ++ rtw_write8(padapter, REG_RRSR, mask&0xff); ++ rtw_write8(padapter,REG_RRSR+1, (mask>>8)&0xff); ++ ++ // Set RTS initial rate ++ while(mask > 0x1) ++ { ++ mask = (mask>> 1); ++ RateIndex++; ++ } ++ rtw_write8(padapter, REG_INIRTS_RATE_SEL, RateIndex); ++} ++ ++void UpdateHalRAMask8188EUsb(PADAPTER padapter, u32 mac_id, u8 rssi_level) ++{ ++ //volatile unsigned int result; ++ u8 init_rate=0; ++ u8 networkType, raid; ++ u32 mask,rate_bitmap; ++ u8 shortGIrate = _FALSE; ++ int supportRateNum = 0; ++ struct sta_info *psta; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ //struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); ++ ++ if (mac_id >= NUM_STA) //CAM_SIZE ++ { ++ return; ++ } ++ ++ psta = pmlmeinfo->FW_sta_info[mac_id].psta; ++ if(psta == NULL) ++ { ++ return; ++ } ++ ++ switch (mac_id) ++ { ++ case 0:// for infra mode ++#ifdef CONFIG_CONCURRENT_MODE ++ case 2:// first station uses macid=0, second station uses macid=2 ++#endif ++ supportRateNum = rtw_get_rateset_len(cur_network->SupportedRates); ++ networkType = judge_network_type(padapter, cur_network->SupportedRates, supportRateNum) & 0xf; ++ //pmlmeext->cur_wireless_mode = networkType; ++ raid = networktype_to_raid(networkType); ++ ++ mask = update_supported_rate(cur_network->SupportedRates, supportRateNum); ++ mask |= (pmlmeinfo->HT_enable)? update_MSC_rate(&(pmlmeinfo->HT_caps)): 0; ++ ++ ++ if (support_short_GI(padapter, &(pmlmeinfo->HT_caps))) ++ { ++ shortGIrate = _TRUE; ++ } ++ ++ break; ++ ++ case 1://for broadcast/multicast ++ supportRateNum = rtw_get_rateset_len(pmlmeinfo->FW_sta_info[mac_id].SupportedRates); ++ if(pmlmeext->cur_wireless_mode & WIRELESS_11B) ++ networkType = WIRELESS_11B; ++ else ++ networkType = WIRELESS_11G; ++ raid = networktype_to_raid(networkType); ++ mask = update_basic_rate(cur_network->SupportedRates, supportRateNum); ++ ++ ++ break; ++ ++ default: //for each sta in IBSS ++ supportRateNum = rtw_get_rateset_len(pmlmeinfo->FW_sta_info[mac_id].SupportedRates); ++ networkType = judge_network_type(padapter, pmlmeinfo->FW_sta_info[mac_id].SupportedRates, supportRateNum) & 0xf; ++ //pmlmeext->cur_wireless_mode = networkType; ++ raid = networktype_to_raid(networkType); ++ mask = update_supported_rate(cur_network->SupportedRates, supportRateNum); ++ ++ //todo: support HT in IBSS ++ ++ break; ++ } ++ ++ //mask &=0x0fffffff; ++ rate_bitmap = 0x0fffffff; ++#ifdef CONFIG_ODM_REFRESH_RAMASK ++ { ++ rate_bitmap = ODM_Get_Rate_Bitmap(&pHalData->odmpriv,mac_id,mask,rssi_level); ++ printk("%s => mac_id:%d, networkType:0x%02x, mask:0x%08x\n\t ==> rssi_level:%d, rate_bitmap:0x%08x\n", ++ __FUNCTION__,mac_id,networkType,mask,rssi_level,rate_bitmap); ++ } ++#endif ++ ++ mask &= rate_bitmap; ++ ++ init_rate = get_highest_rate_idx(mask)&0x3f; ++ ++ if(pHalData->fw_ractrl == _TRUE) ++ { ++ u8 arg = 0; ++ ++ //arg = (cam_idx-4)&0x1f;//MACID ++ arg = mac_id&0x1f;//MACID ++ ++ arg |= BIT(7); ++ ++ if (shortGIrate==_TRUE) ++ arg |= BIT(5); ++ mask |= ((raid<<28)&0xf0000000); ++ DBG_871X("update raid entry, mask=0x%x, arg=0x%x\n", mask, arg); ++ psta->ra_mask=mask; ++#ifdef CONFIG_INTEL_PROXIM ++ if(padapter->proximity.proxim_on ==_TRUE){ ++ arg &= ~BIT(6); ++ } ++ else { ++ arg |= BIT(6); ++ } ++#endif //CONFIG_INTEL_PROXIM ++ mask |= ((raid<<28)&0xf0000000); ++ ++ //to do ++ /* ++ *(pu4Byte)&RateMask=EF4Byte((ratr_bitmap&0x0fffffff) | (ratr_index<<28)); ++ RateMask[4] = macId | (bShortGI?0x20:0x00) | 0x80; ++ */ ++ rtl8188e_set_raid_cmd(padapter, mask); ++ ++ } ++ else ++ { ++ ++#if(RATE_ADAPTIVE_SUPPORT == 1) ++ ++ ODM_RA_UpdateRateInfo_8188E( ++ &(pHalData->odmpriv), ++ mac_id, ++ raid, ++ mask, ++ shortGIrate ++ ); ++ ++#endif ++ } ++ ++ ++ //set ra_id ++ psta->raid = raid; ++ psta->init_rate = init_rate; ++ ++ ++} ++ ++ ++void SetBeaconRelatedRegisters8188EUsb(PADAPTER padapter) ++{ ++ u32 value32; ++ //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u32 bcn_ctrl_reg = REG_BCN_CTRL; ++ //reset TSF, enable update TSF, correcting TSF On Beacon ++ ++ //REG_BCN_INTERVAL ++ //REG_BCNDMATIM ++ //REG_ATIMWND ++ //REG_TBTT_PROHIBIT ++ //REG_DRVERLYINT ++ //REG_BCN_MAX_ERR ++ //REG_BCNTCFG //(0x510) ++ //REG_DUAL_TSF_RST ++ //REG_BCN_CTRL //(0x550) ++ ++ //BCN interval ++#ifdef CONFIG_CONCURRENT_MODE ++ if (padapter->iface_type == IFACE_PORT1){ ++ bcn_ctrl_reg = REG_BCN_CTRL_1; ++ } ++#endif ++ rtw_write16(padapter, REG_BCN_INTERVAL, pmlmeinfo->bcn_interval); ++ rtw_write8(padapter, REG_ATIMWND, 0x02);// 2ms ++ ++ _InitBeaconParameters(padapter); ++ ++ rtw_write8(padapter, REG_SLOT, 0x09); ++ ++ value32 =rtw_read32(padapter, REG_TCR); ++ value32 &= ~TSFRST; ++ rtw_write32(padapter, REG_TCR, value32); ++ ++ value32 |= TSFRST; ++ rtw_write32(padapter, REG_TCR, value32); ++ ++ // NOTE: Fix test chip's bug (about contention windows's randomness) ++ rtw_write8(padapter, REG_RXTSF_OFFSET_CCK, 0x50); ++ rtw_write8(padapter, REG_RXTSF_OFFSET_OFDM, 0x50); ++ ++ _BeaconFunctionEnable(padapter, _TRUE, _TRUE); ++ ++ ResumeTxBeacon(padapter); ++ ++ //rtw_write8(padapter, 0x422, rtw_read8(padapter, 0x422)|BIT(6)); ++ ++ //rtw_write8(padapter, 0x541, 0xff); ++ ++ //rtw_write8(padapter, 0x542, rtw_read8(padapter, 0x541)|BIT(0)); ++ ++ rtw_write8(padapter, bcn_ctrl_reg, rtw_read8(padapter, bcn_ctrl_reg)|BIT(1)); ++ ++} ++ ++static void rtl8188eu_init_default_value(_adapter * padapter) ++{ ++ PHAL_DATA_TYPE pHalData; ++ struct pwrctrl_priv *pwrctrlpriv; ++ struct dm_priv *pdmpriv; ++ u8 i; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pwrctrlpriv = adapter_to_pwrctl(padapter); ++ pdmpriv = &pHalData->dmpriv; ++ ++ ++ //init default value ++ pHalData->fw_ractrl = _FALSE; ++ if(!pwrctrlpriv->bkeepfwalive) ++ pHalData->LastHMEBoxNum = 0; ++ ++ //init dm default value ++ pHalData->odmpriv.RFCalibrateInfo.bIQKInitialized = _FALSE; ++ pHalData->odmpriv.RFCalibrateInfo.TM_Trigger = 0;//for IQK ++ //pdmpriv->binitialized = _FALSE; ++// pdmpriv->prv_traffic_idx = 3; ++// pdmpriv->initialize = 0; ++ pHalData->pwrGroupCnt = 0; ++ pHalData->PGMaxGroup= 13; ++ pHalData->odmpriv.RFCalibrateInfo.ThermalValue_HP_index = 0; ++ for(i = 0; i < HP_THERMAL_NUM; i++) ++ pHalData->odmpriv.RFCalibrateInfo.ThermalValue_HP[i] = 0; ++} ++ ++static u8 rtl8188eu_ps_func(PADAPTER Adapter,HAL_INTF_PS_FUNC efunc_id, u8 *val) ++{ ++ u8 bResult = _TRUE; ++ switch(efunc_id){ ++ ++ #if defined(CONFIG_AUTOSUSPEND) && defined(SUPPORT_HW_RFOFF_DETECTED) ++ case HAL_USB_SELECT_SUSPEND: ++ { ++ u8 bfwpoll = *(( u8*)val); ++ //rtl8188e_set_FwSelectSuspend_cmd(Adapter,bfwpoll ,500);//note fw to support hw power down ping detect ++ } ++ break; ++ #endif //CONFIG_AUTOSUSPEND && SUPPORT_HW_RFOFF_DETECTED ++ ++ default: ++ break; ++ } ++ return bResult; ++} ++ ++void rtl8188eu_set_hal_ops(_adapter * padapter) ++{ ++ struct hal_ops *pHalFunc = &padapter->HalFunc; ++ ++_func_enter_; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(padapter->isprimary) ++#endif //CONFIG_CONCURRENT_MODE ++ { ++ padapter->HalData = rtw_zmalloc(sizeof(HAL_DATA_TYPE)); ++ if(padapter->HalData == NULL){ ++ DBG_8192C("cant not alloc memory for HAL DATA \n"); ++ } ++ } ++ ++ //_rtw_memset(padapter->HalData, 0, sizeof(HAL_DATA_TYPE)); ++ padapter->hal_data_sz = sizeof(HAL_DATA_TYPE); ++ ++ pHalFunc->hal_power_on = InitPowerOn_rtl8188eu; ++ pHalFunc->hal_power_off = hal_poweroff_rtl8188eu; ++ ++ pHalFunc->hal_init = &rtl8188eu_hal_init; ++ pHalFunc->hal_deinit = &rtl8188eu_hal_deinit; ++ ++ //pHalFunc->free_hal_data = &rtl8192c_free_hal_data; ++ ++ pHalFunc->inirp_init = &rtl8188eu_inirp_init; ++ pHalFunc->inirp_deinit = &rtl8188eu_inirp_deinit; ++ ++ pHalFunc->init_xmit_priv = &rtl8188eu_init_xmit_priv; ++ pHalFunc->free_xmit_priv = &rtl8188eu_free_xmit_priv; ++ ++ pHalFunc->init_recv_priv = &rtl8188eu_init_recv_priv; ++ pHalFunc->free_recv_priv = &rtl8188eu_free_recv_priv; ++#ifdef CONFIG_SW_LED ++ pHalFunc->InitSwLeds = &rtl8188eu_InitSwLeds; ++ pHalFunc->DeInitSwLeds = &rtl8188eu_DeInitSwLeds; ++#else //case of hw led or no led ++ pHalFunc->InitSwLeds = NULL; ++ pHalFunc->DeInitSwLeds = NULL; ++#endif//CONFIG_SW_LED ++ ++ pHalFunc->init_default_value = &rtl8188eu_init_default_value; ++ pHalFunc->intf_chip_configure = &rtl8188eu_interface_configure; ++ pHalFunc->read_adapter_info = &ReadAdapterInfo8188EU; ++ ++ //pHalFunc->set_bwmode_handler = &PHY_SetBWMode8192C; ++ //pHalFunc->set_channel_handler = &PHY_SwChnl8192C; ++ ++ //pHalFunc->hal_dm_watchdog = &rtl8192c_HalDmWatchDog; ++ ++ ++ pHalFunc->SetHwRegHandler = &SetHwReg8188EU; ++ pHalFunc->GetHwRegHandler = &GetHwReg8188EU; ++ pHalFunc->GetHalDefVarHandler = &GetHalDefVar8188EUsb; ++ pHalFunc->SetHalDefVarHandler = &SetHalDefVar8188EUsb; ++ ++ pHalFunc->UpdateRAMaskHandler = &UpdateHalRAMask8188EUsb; ++ pHalFunc->SetBeaconRelatedRegistersHandler = &SetBeaconRelatedRegisters8188EUsb; ++ ++ //pHalFunc->Add_RateATid = &rtl8192c_Add_RateATid; ++ ++ pHalFunc->hal_xmit = &rtl8188eu_hal_xmit; ++ pHalFunc->mgnt_xmit = &rtl8188eu_mgnt_xmit; ++ pHalFunc->hal_xmitframe_enqueue = &rtl8188eu_hal_xmitframe_enqueue; ++ ++ ++#ifdef CONFIG_HOSTAPD_MLME ++ pHalFunc->hostap_mgnt_xmit_entry = &rtl8188eu_hostap_mgnt_xmit_entry; ++#endif ++ pHalFunc->interface_ps_func = &rtl8188eu_ps_func; ++ ++ rtl8188e_set_hal_ops(pHalFunc); ++_func_exit_; ++ ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/usb/usb_ops_linux.c b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/usb/usb_ops_linux.c +new file mode 100644 +index 00000000..93f4604b +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/hal/rtl8188e/usb/usb_ops_linux.c +@@ -0,0 +1,1743 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _HCI_OPS_OS_C_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if defined (PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) ++ ++#error "Shall be Linux or Windows, but not both!\n" ++ ++#endif ++ ++static int usbctrl_vendorreq(struct intf_hdl *pintfhdl, u8 request, u16 value, u16 index, void *pdata, u16 len, u8 requesttype) ++{ ++ _adapter *padapter = pintfhdl->padapter; ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct usb_device *udev=pdvobjpriv->pusbdev; ++ ++ unsigned int pipe; ++ int status = 0; ++ u32 tmp_buflen=0; ++ u8 reqtype; ++ u8 *pIo_buf; ++ int vendorreq_times = 0; ++ ++ #ifdef CONFIG_USB_VENDOR_REQ_BUFFER_DYNAMIC_ALLOCATE ++ u8 *tmp_buf; ++ #else // use stack memory ++ u8 tmp_buf[MAX_USB_IO_CTL_SIZE]; ++ #endif ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(padapter->adapter_type > PRIMARY_ADAPTER) ++ { ++ padapter = padapter->pbuddy_adapter; ++ pdvobjpriv = adapter_to_dvobj(padapter); ++ udev = pdvobjpriv->pusbdev; ++ } ++#endif ++ ++ //DBG_871X("%s %s:%d\n",__FUNCTION__, current->comm, current->pid); ++ ++ if((padapter->bSurpriseRemoved) ||(dvobj_to_pwrctl(pdvobjpriv)->pnp_bstop_trx)){ ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usbctrl_vendorreq:(padapter->bSurpriseRemoved ||pwrctl->pnp_bstop_trx)!!!\n")); ++ status = -EPERM; ++ goto exit; ++ } ++ ++ if(len>MAX_VENDOR_REQ_CMD_SIZE){ ++ DBG_8192C( "[%s] Buffer len error ,vendor request failed\n", __FUNCTION__ ); ++ status = -EINVAL; ++ goto exit; ++ } ++ ++ #ifdef CONFIG_USB_VENDOR_REQ_MUTEX ++ _enter_critical_mutex(&pdvobjpriv->usb_vendor_req_mutex, NULL); ++ #endif ++ ++ ++ // Acquire IO memory for vendorreq ++#ifdef CONFIG_USB_VENDOR_REQ_BUFFER_PREALLOC ++ pIo_buf = pdvobjpriv->usb_vendor_req_buf; ++#else ++ #ifdef CONFIG_USB_VENDOR_REQ_BUFFER_DYNAMIC_ALLOCATE ++ tmp_buf = rtw_malloc( (u32) len + ALIGNMENT_UNIT); ++ tmp_buflen = (u32)len + ALIGNMENT_UNIT; ++ #else // use stack memory ++ tmp_buflen = MAX_USB_IO_CTL_SIZE; ++ #endif ++ ++ // Added by Albert 2010/02/09 ++ // For mstar platform, mstar suggests the address for USB IO should be 16 bytes alignment. ++ // Trying to fix it here. ++ pIo_buf = (tmp_buf==NULL)?NULL:tmp_buf + ALIGNMENT_UNIT -((SIZE_PTR)(tmp_buf) & 0x0f ); ++#endif ++ ++ if ( pIo_buf== NULL) { ++ DBG_8192C( "[%s] pIo_buf == NULL \n", __FUNCTION__ ); ++ status = -ENOMEM; ++ goto release_mutex; ++ } ++ ++ while(++vendorreq_times<= MAX_USBCTRL_VENDORREQ_TIMES) ++ { ++ _rtw_memset(pIo_buf, 0, len); ++ ++ if (requesttype == 0x01) ++ { ++ pipe = usb_rcvctrlpipe(udev, 0);//read_in ++ reqtype = REALTEK_USB_VENQT_READ; ++ } ++ else ++ { ++ pipe = usb_sndctrlpipe(udev, 0);//write_out ++ reqtype = REALTEK_USB_VENQT_WRITE; ++ _rtw_memcpy( pIo_buf, pdata, len); ++ } ++ ++ #if 0 ++ //timeout test for firmware downloading ++ status = rtw_usb_control_msg(udev, pipe, request, reqtype, value, index, pIo_buf, len ++ , (value == FW_8188E_START_ADDRESS) ?RTW_USB_CONTROL_MSG_TIMEOUT_TEST : RTW_USB_CONTROL_MSG_TIMEOUT ++ ); ++ #else ++ status = rtw_usb_control_msg(udev, pipe, request, reqtype, value, index, pIo_buf, len, RTW_USB_CONTROL_MSG_TIMEOUT); ++ #endif ++ ++ if ( status == len) // Success this control transfer. ++ { ++ rtw_reset_continual_io_error(pdvobjpriv); ++ if ( requesttype == 0x01 ) ++ { // For Control read transfer, we have to copy the read data from pIo_buf to pdata. ++ _rtw_memcpy( pdata, pIo_buf, len ); ++ } ++ } ++ else { // error cases ++ DBG_8192C("reg 0x%x, usb %s %u fail, status:%d value=0x%x, vendorreq_times:%d\n" ++ , value,(requesttype == 0x01)?"read":"write" , len, status, *(u32*)pdata, vendorreq_times); ++ ++ if (status < 0) { ++ if(status == (-ESHUTDOWN) || status == -ENODEV ) ++ { ++ padapter->bSurpriseRemoved = _TRUE; ++ } else { ++ #ifdef DBG_CONFIG_ERROR_DETECT ++ { ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ pHalData->srestpriv.Wifi_Error_Status = USB_VEN_REQ_CMD_FAIL; ++ } ++ #endif ++ } ++ } ++ else // status != len && status >= 0 ++ { ++ if(status > 0) { ++ if ( requesttype == 0x01 ) ++ { // For Control read transfer, we have to copy the read data from pIo_buf to pdata. ++ _rtw_memcpy( pdata, pIo_buf, len ); ++ } ++ } ++ } ++ ++ if(rtw_inc_and_chk_continual_io_error(pdvobjpriv) == _TRUE ){ ++ padapter->bSurpriseRemoved = _TRUE; ++ break; ++ } ++ ++ } ++ ++ // firmware download is checksumed, don't retry ++ if( (value >= FW_8188E_START_ADDRESS && value <= FW_8188E_END_ADDRESS) || status == len ) ++ break; ++ ++ } ++ ++ // release IO memory used by vendorreq ++ #ifdef CONFIG_USB_VENDOR_REQ_BUFFER_DYNAMIC_ALLOCATE ++ rtw_mfree(tmp_buf, tmp_buflen); ++ #endif ++ ++release_mutex: ++ #ifdef CONFIG_USB_VENDOR_REQ_MUTEX ++ _exit_critical_mutex(&pdvobjpriv->usb_vendor_req_mutex, NULL); ++ #endif ++exit: ++ return status; ++ ++} ++ ++static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr) ++{ ++ u8 request; ++ u8 requesttype; ++ u16 wvalue; ++ u16 index; ++ u16 len; ++ u8 data=0; ++ ++ _func_enter_; ++ ++ request = 0x05; ++ requesttype = 0x01;//read_in ++ index = 0;//n/a ++ ++ wvalue = (u16)(addr&0x0000ffff); ++ len = 1; ++ ++ usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); ++ ++ _func_exit_; ++ ++ return data; ++ ++} ++ ++static u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr) ++{ ++ u8 request; ++ u8 requesttype; ++ u16 wvalue; ++ u16 index; ++ u16 len; ++ u16 data=0; ++ ++ _func_enter_; ++ ++ request = 0x05; ++ requesttype = 0x01;//read_in ++ index = 0;//n/a ++ ++ wvalue = (u16)(addr&0x0000ffff); ++ len = 2; ++ ++ usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); ++ ++ _func_exit_; ++ ++ return data; ++ ++} ++ ++static u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr) ++{ ++ u8 request; ++ u8 requesttype; ++ u16 wvalue; ++ u16 index; ++ u16 len; ++ u32 data=0; ++ ++ _func_enter_; ++ ++ request = 0x05; ++ requesttype = 0x01;//read_in ++ index = 0;//n/a ++ ++ wvalue = (u16)(addr&0x0000ffff); ++ len = 4; ++ ++ usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); ++ ++ _func_exit_; ++ ++ return data; ++ ++} ++ ++static int usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val) ++{ ++ u8 request; ++ u8 requesttype; ++ u16 wvalue; ++ u16 index; ++ u16 len; ++ u8 data; ++ int ret; ++ ++ _func_enter_; ++ ++ request = 0x05; ++ requesttype = 0x00;//write_out ++ index = 0;//n/a ++ ++ wvalue = (u16)(addr&0x0000ffff); ++ len = 1; ++ ++ data = val; ++ ++ ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); ++ ++ _func_exit_; ++ ++ return ret; ++ ++} ++ ++static int usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val) ++{ ++ u8 request; ++ u8 requesttype; ++ u16 wvalue; ++ u16 index; ++ u16 len; ++ u16 data; ++ int ret; ++ ++ _func_enter_; ++ ++ request = 0x05; ++ requesttype = 0x00;//write_out ++ index = 0;//n/a ++ ++ wvalue = (u16)(addr&0x0000ffff); ++ len = 2; ++ ++ data = val; ++ ++ ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); ++ ++ _func_exit_; ++ ++ return ret; ++ ++} ++ ++static int usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val) ++{ ++ u8 request; ++ u8 requesttype; ++ u16 wvalue; ++ u16 index; ++ u16 len; ++ u32 data; ++ int ret; ++ ++ _func_enter_; ++ ++ request = 0x05; ++ requesttype = 0x00;//write_out ++ index = 0;//n/a ++ ++ wvalue = (u16)(addr&0x0000ffff); ++ len = 4; ++ data =val; ++ ++ ret =usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); ++ ++ _func_exit_; ++ ++ return ret; ++ ++} ++ ++static int usb_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata) ++{ ++ u8 request; ++ u8 requesttype; ++ u16 wvalue; ++ u16 index; ++ u16 len; ++ u8 buf[VENDOR_CMD_MAX_DATA_LEN]={0}; ++ int ret; ++ ++ _func_enter_; ++ ++ request = 0x05; ++ requesttype = 0x00;//write_out ++ index = 0;//n/a ++ ++ wvalue = (u16)(addr&0x0000ffff); ++ len = length; ++ _rtw_memcpy(buf, pdata, len ); ++ ++ ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, buf, len, requesttype); ++ ++ _func_exit_; ++ ++ return ret; ++ ++} ++ ++#ifdef CONFIG_SUPPORT_USB_INT ++void interrupt_handler_8188eu(_adapter *padapter,u16 pkt_len,u8 *pbuf) ++{ ++ HAL_DATA_TYPE *pHalData=GET_HAL_DATA(padapter); ++ struct reportpwrstate_parm pwr_rpt; ++ ++ if ( pkt_len != INTERRUPT_MSG_FORMAT_LEN ) ++ { ++ DBG_8192C("%s Invalid interrupt content length (%d)!\n", __FUNCTION__, pkt_len); ++ return ; ++ } ++ ++ // HISR ++ _rtw_memcpy(&(pHalData->IntArray[0]), &(pbuf[USB_INTR_CONTENT_HISR_OFFSET]), 4); ++ _rtw_memcpy(&(pHalData->IntArray[1]), &(pbuf[USB_INTR_CONTENT_HISRE_OFFSET]), 4); ++ ++ #if 0 //DBG ++ { ++ u32 hisr=0 ,hisr_ex=0; ++ _rtw_memcpy(&hisr,&(pHalData->IntArray[0]),4); ++ hisr = le32_to_cpu(hisr); ++ ++ _rtw_memcpy(&hisr_ex,&(pHalData->IntArray[1]),4); ++ hisr_ex = le32_to_cpu(hisr_ex); ++ ++ if((hisr != 0) || (hisr_ex!=0)) ++ DBG_871X("===> %s hisr:0x%08x ,hisr_ex:0x%08x \n",__FUNCTION__,hisr,hisr_ex); ++ } ++ #endif ++ ++ ++#ifdef CONFIG_LPS_LCLK ++ if( pHalData->IntArray[0] & IMR_CPWM_88E ) ++ { ++ _rtw_memcpy(&pwr_rpt.state, &(pbuf[USB_INTR_CONTENT_CPWM1_OFFSET]), 1); ++ //_rtw_memcpy(&pwr_rpt.state2, &(pbuf[USB_INTR_CONTENT_CPWM2_OFFSET]), 1); ++ ++ //88e's cpwm value only change BIT0, so driver need to add PS_STATE_S2 for LPS flow. ++ pwr_rpt.state |= PS_STATE_S2; ++ _set_workitem(&(adapter_to_pwrctl(padapter)->cpwm_event)); ++ } ++#endif//CONFIG_LPS_LCLK ++ ++#ifdef CONFIG_INTERRUPT_BASED_TXBCN ++ ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ if (pHalData->IntArray[0] & IMR_BCNDMAINT0_88E) ++ #endif ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ if (pHalData->IntArray[0] & (IMR_TBDER_88E|IMR_TBDOK_88E)) ++ #endif ++ { ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ #if 0 ++ if(pHalData->IntArray[0] & IMR_BCNDMAINT0_88E) ++ DBG_8192C("%s: HISR_BCNERLY_INT\n", __func__); ++ if(pHalData->IntArray[0] & IMR_TBDOK_88E) ++ DBG_8192C("%s: HISR_TXBCNOK\n", __func__); ++ if(pHalData->IntArray[0] & IMR_TBDER_88E) ++ DBG_8192C("%s: HISR_TXBCNERR\n", __func__); ++ #endif ++ ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ { ++ //send_beacon(padapter); ++ if(pmlmepriv->update_bcn == _TRUE) ++ { ++ //tx_beacon_hdl(padapter, NULL); ++ set_tx_beacon_cmd(padapter); ++ } ++ } ++#ifdef CONFIG_CONCURRENT_MODE ++ if(check_buddy_fwstate(padapter, WIFI_AP_STATE)) ++ { ++ //send_beacon(padapter); ++ if(padapter->pbuddy_adapter->mlmepriv.update_bcn == _TRUE) ++ { ++ //tx_beacon_hdl(padapter, NULL); ++ set_tx_beacon_cmd(padapter->pbuddy_adapter); ++ } ++ } ++#endif ++ ++ } ++#endif //CONFIG_INTERRUPT_BASED_TXBCN ++ ++ ++ ++ ++#ifdef DBG_CONFIG_ERROR_DETECT_INT ++ if( pHalData->IntArray[1] & IMR_TXERR_88E ) ++ DBG_871X("===> %s Tx Error Flag Interrupt Status \n",__FUNCTION__); ++ if( pHalData->IntArray[1] & IMR_RXERR_88E ) ++ DBG_871X("===> %s Rx Error Flag INT Status \n",__FUNCTION__); ++ if( pHalData->IntArray[1] & IMR_TXFOVW_88E ) ++ DBG_871X("===> %s Transmit FIFO Overflow \n",__FUNCTION__); ++ if( pHalData->IntArray[1] & IMR_RXFOVW_88E ) ++ DBG_871X("===> %s Receive FIFO Overflow \n",__FUNCTION__); ++#endif//DBG_CONFIG_ERROR_DETECT_INT ++ ++ ++ // C2H Event ++ if(pbuf[0]!= 0){ ++ _rtw_memcpy(&(pHalData->C2hArray[0]), &(pbuf[USB_INTR_CONTENT_C2H_OFFSET]), 16); ++ //rtw_c2h_wk_cmd(padapter); to do.. ++ } ++ ++} ++#endif ++ ++#ifdef CONFIG_USB_INTERRUPT_IN_PIPE ++static void usb_read_interrupt_complete(struct urb *purb, struct pt_regs *regs) ++{ ++ int err; ++ _adapter *padapter = (_adapter *)purb->context; ++ ++ if(padapter->bSurpriseRemoved || padapter->bDriverStopped||padapter->bReadPortCancel) ++ { ++ DBG_8192C("%s() RX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bReadPortCancel(%d)\n", ++ __FUNCTION__,padapter->bDriverStopped, padapter->bSurpriseRemoved,padapter->bReadPortCancel); ++ ++ return; ++ } ++ ++ if(purb->status==0)//SUCCESS ++ { ++ if (purb->actual_length > INTERRUPT_MSG_FORMAT_LEN) ++ { ++ DBG_8192C("usb_read_interrupt_complete: purb->actual_length > INTERRUPT_MSG_FORMAT_LEN(%d)\n",INTERRUPT_MSG_FORMAT_LEN); ++ } ++ ++ interrupt_handler_8188eu(padapter, purb->actual_length,purb->transfer_buffer ); ++ ++ err = usb_submit_urb(purb, GFP_ATOMIC); ++ if((err) && (err != (-EPERM))) ++ { ++ DBG_8192C("cannot submit interrupt in-token(err = 0x%08x),urb_status = %d\n",err, purb->status); ++ } ++ } ++ else ++ { ++ DBG_8192C("###=> usb_read_interrupt_complete => urb status(%d)\n", purb->status); ++ ++ switch(purb->status) { ++ case -EINVAL: ++ case -EPIPE: ++ case -ENODEV: ++ case -ESHUTDOWN: ++ //padapter->bSurpriseRemoved=_TRUE; ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port_complete:bSurpriseRemoved=TRUE\n")); ++ case -ENOENT: ++ padapter->bDriverStopped=_TRUE; ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port_complete:bDriverStopped=TRUE\n")); ++ break; ++ case -EPROTO: ++ break; ++ case -EINPROGRESS: ++ DBG_8192C("ERROR: URB IS IN PROGRESS!/n"); ++ break; ++ default: ++ break; ++ } ++ } ++ ++} ++ ++static u32 usb_read_interrupt(struct intf_hdl *pintfhdl, u32 addr) ++{ ++ int err; ++ unsigned int pipe; ++ u32 ret = _SUCCESS; ++ _adapter *adapter = pintfhdl->padapter; ++ struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter); ++ struct recv_priv *precvpriv = &adapter->recvpriv; ++ struct usb_device *pusbd = pdvobj->pusbdev; ++ ++_func_enter_; ++ ++ //translate DMA FIFO addr to pipehandle ++ pipe = ffaddr2pipehdl(pdvobj, addr); ++ ++ usb_fill_int_urb(precvpriv->int_in_urb, pusbd, pipe, ++ precvpriv->int_in_buf, ++ INTERRUPT_MSG_FORMAT_LEN, ++ usb_read_interrupt_complete, ++ adapter, ++ 1); ++ ++ err = usb_submit_urb(precvpriv->int_in_urb, GFP_ATOMIC); ++ if((err) && (err != (-EPERM))) ++ { ++ DBG_8192C("cannot submit interrupt in-token(err = 0x%08x),urb_status = %d\n",err, precvpriv->int_in_urb->status); ++ ret = _FAIL; ++ } ++ ++_func_exit_; ++ ++ return ret; ++} ++#endif ++ ++static s32 pre_recv_entry(union recv_frame *precvframe, struct recv_stat *prxstat, struct phy_stat *pphy_status) ++{ ++ s32 ret=_SUCCESS; ++#ifdef CONFIG_CONCURRENT_MODE ++ u8 *primary_myid, *secondary_myid, *paddr1; ++ union recv_frame *precvframe_if2 = NULL; ++ _adapter *primary_padapter = precvframe->u.hdr.adapter; ++ _adapter *secondary_padapter = primary_padapter->pbuddy_adapter; ++ struct recv_priv *precvpriv = &primary_padapter->recvpriv; ++ _queue *pfree_recv_queue = &precvpriv->free_recv_queue; ++ u8 *pbuf = precvframe->u.hdr.rx_data; ++ ++ if(!secondary_padapter) ++ return ret; ++ ++ paddr1 = GetAddr1Ptr(precvframe->u.hdr.rx_data); ++ ++ if(IS_MCAST(paddr1) == _FALSE)//unicast packets ++ { ++ //primary_myid = myid(&primary_padapter->eeprompriv); ++ secondary_myid = myid(&secondary_padapter->eeprompriv); ++ ++ if(_rtw_memcmp(paddr1, secondary_myid, ETH_ALEN)) ++ { ++ //change to secondary interface ++ precvframe->u.hdr.adapter = secondary_padapter; ++ } ++ ++ //ret = recv_entry(precvframe); ++ ++ } ++ else // Handle BC/MC Packets ++ { ++ ++ u8 clone = _TRUE; ++#if 0 ++ u8 type, subtype, *paddr2, *paddr3; ++ ++ type = GetFrameType(pbuf); ++ subtype = GetFrameSubType(pbuf); //bit(7)~bit(2) ++ ++ switch (type) ++ { ++ case WIFI_MGT_TYPE: //Handle BC/MC mgnt Packets ++ if(subtype == WIFI_BEACON) ++ { ++ paddr3 = GetAddr3Ptr(precvframe->u.hdr.rx_data); ++ ++ if (check_fwstate(&secondary_padapter->mlmepriv, _FW_LINKED) && ++ _rtw_memcmp(paddr3, get_bssid(&secondary_padapter->mlmepriv), ETH_ALEN)) ++ { ++ //change to secondary interface ++ precvframe->u.hdr.adapter = secondary_padapter; ++ clone = _FALSE; ++ } ++ ++ if(check_fwstate(&primary_padapter->mlmepriv, _FW_LINKED) && ++ _rtw_memcmp(paddr3, get_bssid(&primary_padapter->mlmepriv), ETH_ALEN)) ++ { ++ if(clone==_FALSE) ++ { ++ clone = _TRUE; ++ } ++ else ++ { ++ clone = _FALSE; ++ } ++ ++ precvframe->u.hdr.adapter = primary_padapter; ++ } ++ ++ if(check_fwstate(&primary_padapter->mlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) || ++ check_fwstate(&secondary_padapter->mlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) ++ { ++ clone = _TRUE; ++ precvframe->u.hdr.adapter = primary_padapter; ++ } ++ ++ } ++ else if(subtype == WIFI_PROBEREQ) ++ { ++ //probe req frame is only for interface2 ++ //change to secondary interface ++ precvframe->u.hdr.adapter = secondary_padapter; ++ clone = _FALSE; ++ } ++ break; ++ case WIFI_CTRL_TYPE: // Handle BC/MC ctrl Packets ++ ++ break; ++ case WIFI_DATA_TYPE: //Handle BC/MC data Packets ++ //Notes: AP MODE never rx BC/MC data packets ++ ++ paddr2 = GetAddr2Ptr(precvframe->u.hdr.rx_data); ++ ++ if(_rtw_memcmp(paddr2, get_bssid(&secondary_padapter->mlmepriv), ETH_ALEN)) ++ { ++ //change to secondary interface ++ precvframe->u.hdr.adapter = secondary_padapter; ++ clone = _FALSE; ++ } ++ ++ break; ++ default: ++ ++ break; ++ } ++#endif ++ ++ if(_TRUE == clone) ++ { ++ //clone/copy to if2 ++ u8 shift_sz = 0; ++ u32 alloc_sz, skb_len; ++ _pkt *pkt_copy = NULL; ++ struct rx_pkt_attrib *pattrib = NULL; ++ ++ precvframe_if2 = rtw_alloc_recvframe(pfree_recv_queue); ++ if(precvframe_if2) ++ { ++ precvframe_if2->u.hdr.adapter = secondary_padapter; ++ ++ _rtw_init_listhead(&precvframe_if2->u.hdr.list); ++ precvframe_if2->u.hdr.precvbuf = NULL; //can't access the precvbuf for new arch. ++ precvframe_if2->u.hdr.len=0; ++ ++ _rtw_memcpy(&precvframe_if2->u.hdr.attrib, &precvframe->u.hdr.attrib, sizeof(struct rx_pkt_attrib)); ++ ++ pattrib = &precvframe_if2->u.hdr.attrib; ++ ++ // Modified by Albert 20101213 ++ // For 8 bytes IP header alignment. ++ if (pattrib->qos) // Qos data, wireless lan header length is 26 ++ { ++ shift_sz = 6; ++ } ++ else ++ { ++ shift_sz = 0; ++ } ++ ++ skb_len = pattrib->pkt_len; ++ ++ // for first fragment packet, driver need allocate 1536+drvinfo_sz+RXDESC_SIZE to defrag packet. ++ // modify alloc_sz for recvive crc error packet by thomas 2011-06-02 ++ if((pattrib->mfrag == 1)&&(pattrib->frag_num == 0)){ ++ //alloc_sz = 1664; //1664 is 128 alignment. ++ if(skb_len <= 1650) ++ alloc_sz = 1664; ++ else ++ alloc_sz = skb_len + 14; ++ } ++ else { ++ alloc_sz = skb_len; ++ // 6 is for IP header 8 bytes alignment in QoS packet case. ++ // 8 is for skb->data 4 bytes alignment. ++ alloc_sz += 14; ++ } ++ ++ pkt_copy = rtw_skb_alloc(alloc_sz); ++ ++ if(pkt_copy) ++ { ++ pkt_copy->dev = secondary_padapter->pnetdev; ++ precvframe_if2->u.hdr.pkt = pkt_copy; ++ precvframe_if2->u.hdr.rx_head = pkt_copy->data; ++ precvframe_if2->u.hdr.rx_end = pkt_copy->data + alloc_sz; ++ skb_reserve( pkt_copy, 8 - ((SIZE_PTR)( pkt_copy->data ) & 7 ));//force pkt_copy->data at 8-byte alignment address ++ skb_reserve( pkt_copy, shift_sz );//force ip_hdr at 8-byte alignment address according to shift_sz. ++ _rtw_memcpy(pkt_copy->data, pbuf, skb_len); ++ precvframe_if2->u.hdr.rx_data = precvframe_if2->u.hdr.rx_tail = pkt_copy->data; ++ ++ ++ recvframe_put(precvframe_if2, skb_len); ++ if (pattrib->physt) ++ update_recvframe_phyinfo_88e(precvframe_if2, (struct phy_stat*)pphy_status); ++ ret = rtw_recv_entry(precvframe_if2); ++ ++ } ++ else { ++ rtw_free_recvframe(precvframe_if2, pfree_recv_queue); ++ DBG_8192C("%s()-%d: alloc_skb() failed!\n", __FUNCTION__, __LINE__); ++ } ++ ++ } ++ ++ } ++ ++ } ++ if (precvframe->u.hdr.attrib.physt) ++ update_recvframe_phyinfo_88e(precvframe, (struct phy_stat*)pphy_status); ++ ret = rtw_recv_entry(precvframe); ++ ++#endif ++ ++ return ret; ++ ++} ++ ++#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX ++static int recvbuf2recvframe(_adapter *padapter, struct recv_buf *precvbuf) ++{ ++ u8 *pbuf; ++ u8 shift_sz = 0; ++ u16 pkt_cnt, drvinfo_sz; ++ u32 pkt_offset, skb_len, alloc_sz; ++ s32 transfer_len; ++ struct recv_stat *prxstat; ++ struct phy_stat *pphy_status = NULL; ++ _pkt *pkt_copy = NULL; ++ union recv_frame *precvframe = NULL; ++ struct rx_pkt_attrib *pattrib = NULL; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ _queue *pfree_recv_queue = &precvpriv->free_recv_queue; ++ ++ ++ transfer_len = (s32)precvbuf->transfer_len; ++ pbuf = precvbuf->pbuf; ++ ++ prxstat = (struct recv_stat *)pbuf; ++ pkt_cnt = (le32_to_cpu(prxstat->rxdw2)>>16) & 0xff; ++ ++#if 0 //temp remove when disable usb rx aggregation ++ if((pkt_cnt > 10) || (pkt_cnt < 1) || (transfer_lenrxdw0, prxstat->rxdw1, prxstat->rxdw2, prxstat->rxdw4)); ++ ++ prxstat = (struct recv_stat *)pbuf; ++ ++ precvframe = rtw_alloc_recvframe(pfree_recv_queue); ++ if(precvframe==NULL) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("recvbuf2recvframe: precvframe==NULL\n")); ++ DBG_8192C("%s()-%d: rtw_alloc_recvframe() failed! RX Drop!\n", __FUNCTION__, __LINE__); ++ goto _exit_recvbuf2recvframe; ++ } ++ ++ _rtw_init_listhead(&precvframe->u.hdr.list); ++ precvframe->u.hdr.precvbuf = NULL; //can't access the precvbuf for new arch. ++ precvframe->u.hdr.len=0; ++ ++ //rtl8192c_query_rx_desc_status(precvframe, prxstat); ++ update_recvframe_attrib_88e(precvframe, prxstat); ++ ++ pattrib = &precvframe->u.hdr.attrib; ++ ++ if ((padapter->registrypriv.mp_mode == 0) &&((pattrib->crc_err) || (pattrib->icv_err))) ++ { ++ DBG_8192C("%s: RX Warning! crc_err=%d icv_err=%d, skip!\n", __FUNCTION__, pattrib->crc_err, pattrib->icv_err); ++ ++ rtw_free_recvframe(precvframe, pfree_recv_queue); ++ goto _exit_recvbuf2recvframe; ++ } ++ ++ ++ if( (pattrib->physt) && (pattrib->pkt_rpt_type == NORMAL_RX)) ++ { ++ pphy_status = (struct phy_stat *)(pbuf + RXDESC_OFFSET); ++ } ++ ++ pkt_offset = RXDESC_SIZE + pattrib->drvinfo_sz + pattrib->shift_sz + pattrib->pkt_len; ++ ++ if((pattrib->pkt_len<=0) || (pkt_offset>transfer_len)) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("recvbuf2recvframe: pkt_len<=0\n")); ++ DBG_8192C("%s()-%d: RX Warning!\n", __FUNCTION__, __LINE__); ++ rtw_free_recvframe(precvframe, pfree_recv_queue); ++ goto _exit_recvbuf2recvframe; ++ } ++ ++ // Modified by Albert 20101213 ++ // For 8 bytes IP header alignment. ++ if (pattrib->qos) // Qos data, wireless lan header length is 26 ++ { ++ shift_sz = 6; ++ } ++ else ++ { ++ shift_sz = 0; ++ } ++ ++ skb_len = pattrib->pkt_len; ++ ++ // for first fragment packet, driver need allocate 1536+drvinfo_sz+RXDESC_SIZE to defrag packet. ++ // modify alloc_sz for recvive crc error packet by thomas 2011-06-02 ++ if((pattrib->mfrag == 1)&&(pattrib->frag_num == 0)){ ++ //alloc_sz = 1664; //1664 is 128 alignment. ++ if(skb_len <= 1650) ++ alloc_sz = 1664; ++ else ++ alloc_sz = skb_len + 14; ++ } ++ else { ++ alloc_sz = skb_len; ++ // 6 is for IP header 8 bytes alignment in QoS packet case. ++ // 8 is for skb->data 4 bytes alignment. ++ alloc_sz += 14; ++ } ++ ++ pkt_copy = rtw_skb_alloc(alloc_sz); ++ ++ if(pkt_copy) ++ { ++ pkt_copy->dev = padapter->pnetdev; ++ precvframe->u.hdr.pkt = pkt_copy; ++ precvframe->u.hdr.rx_head = pkt_copy->data; ++ precvframe->u.hdr.rx_end = pkt_copy->data + alloc_sz; ++ skb_reserve( pkt_copy, 8 - ((SIZE_PTR)( pkt_copy->data ) & 7 ));//force pkt_copy->data at 8-byte alignment address ++ skb_reserve( pkt_copy, shift_sz );//force ip_hdr at 8-byte alignment address according to shift_sz. ++ _rtw_memcpy(pkt_copy->data, (pbuf + pattrib->drvinfo_sz + RXDESC_SIZE), skb_len); ++ precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail = pkt_copy->data; ++ } ++ else ++ { ++ DBG_8192C("recvbuf2recvframe:can not allocate memory for skb copy\n"); ++ //precvframe->u.hdr.pkt = rtw_skb_clone(pskb); ++ //precvframe->u.hdr.rx_head = precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail = pbuf; ++ //precvframe->u.hdr.rx_end = pbuf + (pkt_offset>1612?pkt_offset:1612); ++ ++ precvframe->u.hdr.pkt = NULL; ++ rtw_free_recvframe(precvframe, pfree_recv_queue); ++ ++ goto _exit_recvbuf2recvframe; ++ } ++ ++ recvframe_put(precvframe, skb_len); ++ //recvframe_pull(precvframe, drvinfo_sz + RXDESC_SIZE); ++ ++#ifdef CONFIG_USB_RX_AGGREGATION ++ switch(pHalData->UsbRxAggMode) ++ { ++ case USB_RX_AGG_DMA: ++ case USB_RX_AGG_MIX: ++ pkt_offset = (u16)_RND128(pkt_offset); ++ break; ++ case USB_RX_AGG_USB: ++ pkt_offset = (u16)_RND4(pkt_offset); ++ break; ++ case USB_RX_AGG_DISABLE: ++ default: ++ break; ++ } ++#endif ++ ++ if(pattrib->pkt_rpt_type == NORMAL_RX)//Normal rx packet ++ { ++#ifdef CONFIG_CONCURRENT_MODE ++ if(rtw_buddy_adapter_up(padapter)) ++ { ++ if(pre_recv_entry(precvframe, prxstat, pphy_status) != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_, ++ ("recvbuf2recvframe: recv_entry(precvframe) != _SUCCESS\n")); ++ } ++ } ++ else ++#endif ++ { ++ if (pattrib->physt) ++ update_recvframe_phyinfo_88e(precvframe, (struct phy_stat*)pphy_status); ++ if(rtw_recv_entry(precvframe) != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_, ++ ("recvbuf2recvframe: rtw_recv_entry(precvframe) != _SUCCESS\n")); ++ } ++ } ++ ++ } ++ else{ // pkt_rpt_type == TX_REPORT1-CCX, TX_REPORT2-TX RTP,HIS_REPORT-USB HISR RTP ++ ++ //enqueue recvframe to txrtp queue ++ if(pattrib->pkt_rpt_type == TX_REPORT1){ ++ //DBG_8192C("rx CCX \n"); ++ //CCX-TXRPT ack for xmit mgmt frames. ++ handle_txrpt_ccx_88e(padapter, precvframe->u.hdr.rx_data); ++ ++ } ++ else if(pattrib->pkt_rpt_type == TX_REPORT2){ ++ //DBG_8192C("rx TX RPT \n"); ++ ODM_RA_TxRPT2Handle_8188E( ++ &pHalData->odmpriv, ++ precvframe->u.hdr.rx_data, ++ pattrib->pkt_len, ++ pattrib->MacIDValidEntry[0], ++ pattrib->MacIDValidEntry[1] ++ ); ++ ++ } ++ else if(pattrib->pkt_rpt_type == HIS_REPORT) ++ { ++ //DBG_8192C("%s , rx USB HISR \n",__FUNCTION__); ++ #ifdef CONFIG_SUPPORT_USB_INT ++ interrupt_handler_8188eu(padapter,pattrib->pkt_len,precvframe->u.hdr.rx_data); ++ #endif ++ } ++ rtw_free_recvframe(precvframe, pfree_recv_queue); ++ ++ } ++ ++ pkt_cnt--; ++ transfer_len -= pkt_offset; ++ pbuf += pkt_offset; ++ precvframe = NULL; ++ pkt_copy = NULL; ++ ++ if(transfer_len>0 && pkt_cnt==0) ++ pkt_cnt = (le32_to_cpu(prxstat->rxdw2)>>16) & 0xff; ++ ++ }while((transfer_len>0) && (pkt_cnt>0)); ++ ++_exit_recvbuf2recvframe: ++ ++ return _SUCCESS; ++} ++ ++void rtl8188eu_recv_tasklet(void *priv) ++{ ++ struct recv_buf *precvbuf = NULL; ++ _adapter *padapter = (_adapter*)priv; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++ while (NULL != (precvbuf = rtw_dequeue_recvbuf(&precvpriv->recv_buf_pending_queue))) ++ { ++ if ((padapter->bDriverStopped == _TRUE)||(padapter->bSurpriseRemoved== _TRUE)) ++ { ++ DBG_8192C("recv_tasklet => bDriverStopped or bSurpriseRemoved \n"); ++ ++ break; ++ } ++ ++ ++ recvbuf2recvframe(padapter, precvbuf); ++ ++ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf); ++ } ++ ++} ++ ++static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs) ++{ ++ struct recv_buf *precvbuf = (struct recv_buf *)purb->context; ++ _adapter *padapter =(_adapter *)precvbuf->adapter; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port_complete!!!\n")); ++ ++ precvpriv->rx_pending_cnt --; ++ ++ if(padapter->bSurpriseRemoved || padapter->bDriverStopped||padapter->bReadPortCancel) ++ { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)\n", padapter->bDriverStopped, padapter->bSurpriseRemoved)); ++ DBG_8192C("%s() RX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bReadPortCancel(%d)\n", ++ __FUNCTION__,padapter->bDriverStopped, padapter->bSurpriseRemoved,padapter->bReadPortCancel); ++ goto exit; ++ } ++ ++ if(purb->status==0)//SUCCESS ++ { ++ if ((purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)) ++ { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port_complete: (purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)\n")); ++ ++ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf); ++ } ++ else ++ { ++ rtw_reset_continual_io_error(adapter_to_dvobj(padapter)); ++ ++ precvbuf->transfer_len = purb->actual_length; ++ ++ //rtw_enqueue_rx_transfer_buffer(precvpriv, rx_transfer_buf); ++ rtw_enqueue_recvbuf(precvbuf, &precvpriv->recv_buf_pending_queue); ++ ++ tasklet_schedule(&precvpriv->recv_tasklet); ++ } ++ } ++ else ++ { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port_complete : purb->status(%d) != 0 \n", purb->status)); ++ ++ DBG_8192C("###=> usb_read_port_complete => urb status(%d)\n", purb->status); ++ ++ if(rtw_inc_and_chk_continual_io_error(adapter_to_dvobj(padapter)) == _TRUE ){ ++ padapter->bSurpriseRemoved = _TRUE; ++ } ++ ++ switch(purb->status) { ++ case -EINVAL: ++ case -EPIPE: ++ case -ENODEV: ++ case -ESHUTDOWN: ++ //padapter->bSurpriseRemoved=_TRUE; ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port_complete:bSurpriseRemoved=TRUE\n")); ++ case -ENOENT: ++ padapter->bDriverStopped=_TRUE; ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port_complete:bDriverStopped=TRUE\n")); ++ break; ++ case -EPROTO: ++ case -EILSEQ: ++ case -ETIME: ++ case -ECOMM: ++ case -EOVERFLOW: ++ #ifdef DBG_CONFIG_ERROR_DETECT ++ { ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ pHalData->srestpriv.Wifi_Error_Status = USB_READ_PORT_FAIL; ++ } ++ #endif ++ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf); ++ break; ++ case -EINPROGRESS: ++ DBG_8192C("ERROR: URB IS IN PROGRESS!/n"); ++ break; ++ default: ++ break; ++ } ++ ++ } ++ ++exit: ++ ++_func_exit_; ++ ++} ++ ++static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) ++{ ++ int err; ++ unsigned int pipe; ++ u32 ret = _SUCCESS; ++ PURB purb = NULL; ++ struct recv_buf *precvbuf = (struct recv_buf *)rmem; ++ _adapter *adapter = pintfhdl->padapter; ++ struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter); ++ struct recv_priv *precvpriv = &adapter->recvpriv; ++ struct usb_device *pusbd = pdvobj->pusbdev; ++ ++_func_enter_; ++ ++ if(adapter->bDriverStopped || adapter->bSurpriseRemoved ||dvobj_to_pwrctl(pdvobj)->pnp_bstop_trx) ++ { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port:( padapter->bDriverStopped ||padapter->bSurpriseRemoved ||pwrctl->pnp_bstop_trx)!!!\n")); ++ return _FAIL; ++ } ++ ++ if(precvbuf !=NULL) ++ { ++ rtl8188eu_init_recvbuf(adapter, precvbuf); ++ ++ if(precvbuf->pbuf) ++ { ++ precvpriv->rx_pending_cnt++; ++ ++ purb = precvbuf->purb; ++ ++ //translate DMA FIFO addr to pipehandle ++ pipe = ffaddr2pipehdl(pdvobj, addr); ++ ++ usb_fill_bulk_urb(purb, pusbd, pipe, ++ precvbuf->pbuf, ++ MAX_RECVBUF_SZ, ++ usb_read_port_complete, ++ precvbuf);//context is precvbuf ++ ++ purb->transfer_dma = precvbuf->dma_transfer_addr; ++ purb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++ ++ err = usb_submit_urb(purb, GFP_ATOMIC); ++ if((err) && (err != (-EPERM))) ++ { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("cannot submit rx in-token(err=0x%.8x), URB_STATUS =0x%.8x", err, purb->status)); ++ DBG_8192C("cannot submit rx in-token(err = 0x%08x),urb_status = %d\n",err,purb->status); ++ ret = _FAIL; ++ } ++ ++ } ++ ++ } ++ else ++ { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port:precvbuf ==NULL\n")); ++ ret = _FAIL; ++ } ++ ++_func_exit_; ++ ++ return ret; ++} ++#else // CONFIG_USE_USB_BUFFER_ALLOC_RX ++static int recvbuf2recvframe(_adapter *padapter, _pkt *pskb) ++{ ++ u8 *pbuf; ++ u8 shift_sz = 0; ++ u16 pkt_cnt; ++ u32 pkt_offset, skb_len, alloc_sz; ++ s32 transfer_len; ++ struct recv_stat *prxstat; ++ struct phy_stat *pphy_status = NULL; ++ _pkt *pkt_copy = NULL; ++ union recv_frame *precvframe = NULL; ++ struct rx_pkt_attrib *pattrib = NULL; ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ _queue *pfree_recv_queue = &precvpriv->free_recv_queue; ++ ++ ++ transfer_len = (s32)pskb->len; ++ pbuf = pskb->data; ++ ++ prxstat = (struct recv_stat *)pbuf; ++ pkt_cnt = (le32_to_cpu(prxstat->rxdw2)>>16) & 0xff; ++ ++#if 0 //temp remove when disable usb rx aggregation ++ if((pkt_cnt > 10) || (pkt_cnt < 1) || (transfer_lenrxdw0, prxstat->rxdw1, prxstat->rxdw2, prxstat->rxdw4)); ++ ++ prxstat = (struct recv_stat *)pbuf; ++ ++ precvframe = rtw_alloc_recvframe(pfree_recv_queue); ++ if(precvframe==NULL) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_,("recvbuf2recvframe: precvframe==NULL\n")); ++ DBG_8192C("%s()-%d: rtw_alloc_recvframe() failed! RX Drop!\n", __FUNCTION__, __LINE__); ++ goto _exit_recvbuf2recvframe; ++ } ++ ++ _rtw_init_listhead(&precvframe->u.hdr.list); ++ precvframe->u.hdr.precvbuf = NULL; //can't access the precvbuf for new arch. ++ precvframe->u.hdr.len=0; ++ ++ //rtl8192c_query_rx_desc_status(precvframe, prxstat); ++ update_recvframe_attrib_88e(precvframe, prxstat); ++ ++ pattrib = &precvframe->u.hdr.attrib; ++ ++ if ((padapter->registrypriv.mp_mode == 0) &&((pattrib->crc_err) || (pattrib->icv_err))) ++ { ++ DBG_8192C("%s: RX Warning! crc_err=%d icv_err=%d, skip!\n", __FUNCTION__, pattrib->crc_err, pattrib->icv_err); ++ ++ rtw_free_recvframe(precvframe, pfree_recv_queue); ++ goto _exit_recvbuf2recvframe; ++ } ++ ++ if( (pattrib->physt) && (pattrib->pkt_rpt_type == NORMAL_RX)) ++ { ++ pphy_status = (struct phy_stat *)(pbuf + RXDESC_OFFSET); ++ } ++ ++ pkt_offset = RXDESC_SIZE + pattrib->drvinfo_sz + pattrib->shift_sz + pattrib->pkt_len; ++ ++ if((pattrib->pkt_len<=0) || (pkt_offset>transfer_len)) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_info_,("recvbuf2recvframe: pkt_len<=0\n")); ++ DBG_8192C("%s()-%d: RX Warning!,pkt_len<=0 or pkt_offset> transfoer_len \n", __FUNCTION__, __LINE__); ++ rtw_free_recvframe(precvframe, pfree_recv_queue); ++ goto _exit_recvbuf2recvframe; ++ } ++ ++ // Modified by Albert 20101213 ++ // For 8 bytes IP header alignment. ++ if (pattrib->qos) // Qos data, wireless lan header length is 26 ++ { ++ shift_sz = 6; ++ } ++ else ++ { ++ shift_sz = 0; ++ } ++ ++ skb_len = pattrib->pkt_len; ++ ++ // for first fragment packet, driver need allocate 1536+drvinfo_sz+RXDESC_SIZE to defrag packet. ++ // modify alloc_sz for recvive crc error packet by thomas 2011-06-02 ++ if((pattrib->mfrag == 1)&&(pattrib->frag_num == 0)){ ++ //alloc_sz = 1664; //1664 is 128 alignment. ++ if(skb_len <= 1650) ++ alloc_sz = 1664; ++ else ++ alloc_sz = skb_len + 14; ++ } ++ else { ++ alloc_sz = skb_len; ++ // 6 is for IP header 8 bytes alignment in QoS packet case. ++ // 8 is for skb->data 4 bytes alignment. ++ alloc_sz += 14; ++ } ++ ++ pkt_copy = rtw_skb_alloc(alloc_sz); ++ ++ if(pkt_copy) ++ { ++ pkt_copy->dev = padapter->pnetdev; ++ precvframe->u.hdr.pkt = pkt_copy; ++ precvframe->u.hdr.rx_head = pkt_copy->data; ++ precvframe->u.hdr.rx_end = pkt_copy->data + alloc_sz; ++ skb_reserve( pkt_copy, 8 - ((SIZE_PTR)( pkt_copy->data ) & 7 ));//force pkt_copy->data at 8-byte alignment address ++ skb_reserve( pkt_copy, shift_sz );//force ip_hdr at 8-byte alignment address according to shift_sz. ++ _rtw_memcpy(pkt_copy->data, (pbuf + pattrib->drvinfo_sz + RXDESC_SIZE), skb_len); ++ precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail = pkt_copy->data; ++ } ++ else ++ { ++ if((pattrib->mfrag == 1)&&(pattrib->frag_num == 0)) ++ { ++ DBG_8192C("recvbuf2recvframe: alloc_skb fail , drop frag frame \n"); ++ rtw_free_recvframe(precvframe, pfree_recv_queue); ++ goto _exit_recvbuf2recvframe; ++ } ++ ++ precvframe->u.hdr.pkt = rtw_skb_clone(pskb); ++ if(precvframe->u.hdr.pkt) ++ { ++ precvframe->u.hdr.rx_head = precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail ++ = pbuf+ pattrib->drvinfo_sz + RXDESC_SIZE; ++ precvframe->u.hdr.rx_end = pbuf +pattrib->drvinfo_sz + RXDESC_SIZE+ alloc_sz; ++ } ++ else ++ { ++ DBG_8192C("recvbuf2recvframe: rtw_skb_clone fail\n"); ++ rtw_free_recvframe(precvframe, pfree_recv_queue); ++ goto _exit_recvbuf2recvframe; ++ } ++ ++ } ++ ++ recvframe_put(precvframe, skb_len); ++ //recvframe_pull(precvframe, drvinfo_sz + RXDESC_SIZE); ++ ++#ifdef CONFIG_USB_RX_AGGREGATION ++ switch(pHalData->UsbRxAggMode) ++ { ++ case USB_RX_AGG_DMA: ++ case USB_RX_AGG_MIX: ++ pkt_offset = (u16)_RND128(pkt_offset); ++ break; ++ case USB_RX_AGG_USB: ++ pkt_offset = (u16)_RND4(pkt_offset); ++ break; ++ case USB_RX_AGG_DISABLE: ++ default: ++ break; ++ } ++#endif ++ ++ if(pattrib->pkt_rpt_type == NORMAL_RX)//Normal rx packet ++ { ++#ifdef CONFIG_CONCURRENT_MODE ++ if(rtw_buddy_adapter_up(padapter)) ++ { ++ if(pre_recv_entry(precvframe, prxstat, pphy_status) != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_, ++ ("recvbuf2recvframe: recv_entry(precvframe) != _SUCCESS\n")); ++ } ++ } ++ else ++#endif ++ { ++ if (pattrib->physt) ++ update_recvframe_phyinfo_88e(precvframe, (struct phy_stat*)pphy_status); ++ if(rtw_recv_entry(precvframe) != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_,_drv_err_, ++ ("recvbuf2recvframe: rtw_recv_entry(precvframe) != _SUCCESS\n")); ++ } ++ } ++ } ++ else{ // pkt_rpt_type == TX_REPORT1-CCX, TX_REPORT2-TX RTP,HIS_REPORT-USB HISR RTP ++ ++ //enqueue recvframe to txrtp queue ++ if(pattrib->pkt_rpt_type == TX_REPORT1){ ++ //DBG_8192C("rx CCX \n"); ++ //CCX-TXRPT ack for xmit mgmt frames. ++ handle_txrpt_ccx_88e(padapter, precvframe->u.hdr.rx_data); ++ } ++ else if(pattrib->pkt_rpt_type == TX_REPORT2){ ++ //DBG_8192C("rx TX RPT \n"); ++ ODM_RA_TxRPT2Handle_8188E( ++ &pHalData->odmpriv, ++ precvframe->u.hdr.rx_data, ++ pattrib->pkt_len, ++ pattrib->MacIDValidEntry[0], ++ pattrib->MacIDValidEntry[1] ++ ); ++ ++ } ++ else if(pattrib->pkt_rpt_type == HIS_REPORT) ++ { ++ //DBG_8192C("%s , rx USB HISR \n",__FUNCTION__); ++ #ifdef CONFIG_SUPPORT_USB_INT ++ interrupt_handler_8188eu(padapter,pattrib->pkt_len,precvframe->u.hdr.rx_data); ++ #endif ++ } ++ rtw_free_recvframe(precvframe, pfree_recv_queue); ++ ++ } ++ ++ pkt_cnt--; ++ transfer_len -= pkt_offset; ++ pbuf += pkt_offset; ++ precvframe = NULL; ++ pkt_copy = NULL; ++ ++ if(transfer_len>0 && pkt_cnt==0) ++ pkt_cnt = (le32_to_cpu(prxstat->rxdw2)>>16) & 0xff; ++ ++ }while((transfer_len>0) && (pkt_cnt>0)); ++ ++_exit_recvbuf2recvframe: ++ ++ return _SUCCESS; ++} ++ ++void rtl8188eu_recv_tasklet(void *priv) ++{ ++ _pkt *pskb; ++ _adapter *padapter = (_adapter*)priv; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++ while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue))) ++ { ++ if ((padapter->bDriverStopped == _TRUE)||(padapter->bSurpriseRemoved== _TRUE)) ++ { ++ DBG_8192C("recv_tasklet => bDriverStopped or bSurpriseRemoved \n"); ++ rtw_skb_free(pskb); ++ break; ++ } ++ ++ recvbuf2recvframe(padapter, pskb); ++ ++#ifdef CONFIG_PREALLOC_RECV_SKB ++ ++ skb_reset_tail_pointer(pskb); ++ ++ pskb->len = 0; ++ ++ skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); ++ ++#else ++ rtw_skb_free(pskb); ++#endif ++ ++ } ++ ++} ++ ++ ++static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs) ++{ ++ _irqL irqL; ++ uint isevt, *pbuf; ++ struct recv_buf *precvbuf = (struct recv_buf *)purb->context; ++ _adapter *padapter =(_adapter *)precvbuf->adapter; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port_complete!!!\n")); ++ ++ //_enter_critical(&precvpriv->lock, &irqL); ++ //precvbuf->irp_pending=_FALSE; ++ //precvpriv->rx_pending_cnt --; ++ //_exit_critical(&precvpriv->lock, &irqL); ++ ++ precvpriv->rx_pending_cnt --; ++ ++ //if(precvpriv->rx_pending_cnt== 0) ++ //{ ++ // RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port_complete: rx_pending_cnt== 0, set allrxreturnevt!\n")); ++ // _rtw_up_sema(&precvpriv->allrxreturnevt); ++ //} ++ ++ if(padapter->bSurpriseRemoved || padapter->bDriverStopped||padapter->bReadPortCancel) ++ { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)\n", padapter->bDriverStopped, padapter->bSurpriseRemoved)); ++ ++ #ifdef CONFIG_PREALLOC_RECV_SKB ++ precvbuf->reuse = _TRUE; ++ #else ++ if(precvbuf->pskb){ ++ DBG_8192C("==> free skb(%p)\n",precvbuf->pskb); ++ rtw_skb_free(precvbuf->pskb); ++ } ++ #endif ++ DBG_8192C("%s() RX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bReadPortCancel(%d)\n", ++ __FUNCTION__,padapter->bDriverStopped, padapter->bSurpriseRemoved,padapter->bReadPortCancel); ++ goto exit; ++ } ++ ++ if(purb->status==0)//SUCCESS ++ { ++ if ((purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)) ++ { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port_complete: (purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)\n")); ++ precvbuf->reuse = _TRUE; ++ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf); ++ DBG_8192C("%s()-%d: RX Warning!\n", __FUNCTION__, __LINE__); ++ } ++ else ++ { ++ rtw_reset_continual_io_error(adapter_to_dvobj(padapter)); ++ ++ precvbuf->transfer_len = purb->actual_length; ++ skb_put(precvbuf->pskb, purb->actual_length); ++ skb_queue_tail(&precvpriv->rx_skb_queue, precvbuf->pskb); ++ ++ if (skb_queue_len(&precvpriv->rx_skb_queue)<=1) ++ tasklet_schedule(&precvpriv->recv_tasklet); ++ ++ precvbuf->pskb = NULL; ++ precvbuf->reuse = _FALSE; ++ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf); ++ } ++ } ++ else ++ { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port_complete : purb->status(%d) != 0 \n", purb->status)); ++ ++ DBG_8192C("###=> usb_read_port_complete => urb status(%d)\n", purb->status); ++ ++ if(rtw_inc_and_chk_continual_io_error(adapter_to_dvobj(padapter)) == _TRUE ){ ++ padapter->bSurpriseRemoved = _TRUE; ++ } ++ ++ switch(purb->status) { ++ case -EINVAL: ++ case -EPIPE: ++ case -ENODEV: ++ case -ESHUTDOWN: ++ //padapter->bSurpriseRemoved=_TRUE; ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port_complete:bSurpriseRemoved=TRUE\n")); ++ case -ENOENT: ++ padapter->bDriverStopped=_TRUE; ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port_complete:bDriverStopped=TRUE\n")); ++ break; ++ case -EPROTO: ++ case -EILSEQ: ++ case -ETIME: ++ case -ECOMM: ++ case -EOVERFLOW: ++ #ifdef DBG_CONFIG_ERROR_DETECT ++ { ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ pHalData->srestpriv.Wifi_Error_Status = USB_READ_PORT_FAIL; ++ } ++ #endif ++ precvbuf->reuse = _TRUE; ++ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf); ++ break; ++ case -EINPROGRESS: ++ DBG_8192C("ERROR: URB IS IN PROGRESS!/n"); ++ break; ++ default: ++ break; ++ } ++ ++ } ++ ++exit: ++ ++_func_exit_; ++ ++} ++ ++static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) ++{ ++ _irqL irqL; ++ int err; ++ unsigned int pipe; ++ SIZE_PTR tmpaddr=0; ++ SIZE_PTR alignment=0; ++ u32 ret = _SUCCESS; ++ PURB purb = NULL; ++ struct recv_buf *precvbuf = (struct recv_buf *)rmem; ++ _adapter *adapter = pintfhdl->padapter; ++ struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter); ++ struct recv_priv *precvpriv = &adapter->recvpriv; ++ struct usb_device *pusbd = pdvobj->pusbdev; ++ ++ ++_func_enter_; ++ ++ if(adapter->bDriverStopped || adapter->bSurpriseRemoved ||dvobj_to_pwrctl(pdvobj)->pnp_bstop_trx) ++ { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port:( padapter->bDriverStopped ||padapter->bSurpriseRemoved ||pwrctl->pnp_bstop_trx)!!!\n")); ++ return _FAIL; ++ } ++ ++#ifdef CONFIG_PREALLOC_RECV_SKB ++ if((precvbuf->reuse == _FALSE) || (precvbuf->pskb == NULL)) ++ { ++ if (NULL != (precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue))) ++ { ++ precvbuf->reuse = _TRUE; ++ } ++ } ++#endif ++ ++ ++ if(precvbuf !=NULL) ++ { ++ rtl8188eu_init_recvbuf(adapter, precvbuf); ++ ++ //re-assign for linux based on skb ++ if((precvbuf->reuse == _FALSE) || (precvbuf->pskb == NULL)) ++ { ++ precvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); ++ ++ if(precvbuf->pskb == NULL) ++ { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("init_recvbuf(): alloc_skb fail!\n")); ++ DBG_8192C("#### usb_read_port() alloc_skb fail!#####\n"); ++ return _FAIL; ++ } ++ ++ tmpaddr = (SIZE_PTR)precvbuf->pskb->data; ++ alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); ++ skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment)); ++ ++ precvbuf->phead = precvbuf->pskb->head; ++ precvbuf->pdata = precvbuf->pskb->data; ++ precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); ++ precvbuf->pend = skb_end_pointer(precvbuf->pskb); ++ precvbuf->pbuf = precvbuf->pskb->data; ++ } ++ else//reuse skb ++ { ++ precvbuf->phead = precvbuf->pskb->head; ++ precvbuf->pdata = precvbuf->pskb->data; ++ precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); ++ precvbuf->pend = skb_end_pointer(precvbuf->pskb); ++ precvbuf->pbuf = precvbuf->pskb->data; ++ ++ precvbuf->reuse = _FALSE; ++ } ++ ++ //_enter_critical(&precvpriv->lock, &irqL); ++ //precvpriv->rx_pending_cnt++; ++ //precvbuf->irp_pending = _TRUE; ++ //_exit_critical(&precvpriv->lock, &irqL); ++ ++ precvpriv->rx_pending_cnt++; ++ ++ purb = precvbuf->purb; ++ ++ //translate DMA FIFO addr to pipehandle ++ pipe = ffaddr2pipehdl(pdvobj, addr); ++ ++ usb_fill_bulk_urb(purb, pusbd, pipe, ++ precvbuf->pbuf, ++ MAX_RECVBUF_SZ, ++ usb_read_port_complete, ++ precvbuf);//context is precvbuf ++ ++ err = usb_submit_urb(purb, GFP_ATOMIC); ++ if((err) && (err != (-EPERM))) ++ { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("cannot submit rx in-token(err=0x%.8x), URB_STATUS =0x%.8x", err, purb->status)); ++ DBG_8192C("cannot submit rx in-token(err = 0x%08x),urb_status = %d\n",err,purb->status); ++ ret = _FAIL; ++ } ++ } ++ else ++ { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_read_port:precvbuf ==NULL\n")); ++ ret = _FAIL; ++ } ++ ++_func_exit_; ++ ++ return ret; ++} ++#endif // CONFIG_USE_USB_BUFFER_ALLOC_RX ++ ++void rtl8188eu_xmit_tasklet(void *priv) ++{ ++ int ret = _FALSE; ++ _adapter *padapter = (_adapter*)priv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ if(check_fwstate(&padapter->mlmepriv, _FW_UNDER_SURVEY) == _TRUE) ++ return; ++ ++ while(1) ++ { ++ if ((padapter->bDriverStopped == _TRUE)||(padapter->bSurpriseRemoved== _TRUE) || (padapter->bWritePortCancel == _TRUE)) ++ { ++ DBG_8192C("xmit_tasklet => bDriverStopped or bSurpriseRemoved or bWritePortCancel\n"); ++ break; ++ } ++ ++ ret = rtl8188eu_xmitframe_complete(padapter, pxmitpriv, NULL); ++ ++ if(ret==_FALSE) ++ break; ++ ++ } ++ ++} ++ ++void rtl8188eu_set_intf_ops(struct _io_ops *pops) ++{ ++ _func_enter_; ++ ++ _rtw_memset((u8 *)pops, 0, sizeof(struct _io_ops)); ++ ++ pops->_read8 = &usb_read8; ++ pops->_read16 = &usb_read16; ++ pops->_read32 = &usb_read32; ++ pops->_read_mem = &usb_read_mem; ++ pops->_read_port = &usb_read_port; ++ ++ pops->_write8 = &usb_write8; ++ pops->_write16 = &usb_write16; ++ pops->_write32 = &usb_write32; ++ pops->_writeN = &usb_writeN; ++ ++#ifdef CONFIG_USB_SUPPORT_ASYNC_VDN_REQ ++ pops->_write8_async= &usb_async_write8; ++ pops->_write16_async = &usb_async_write16; ++ pops->_write32_async = &usb_async_write32; ++#endif ++ pops->_write_mem = &usb_write_mem; ++ pops->_write_port = &usb_write_port; ++ ++ pops->_read_port_cancel = &usb_read_port_cancel; ++ pops->_write_port_cancel = &usb_write_port_cancel; ++ ++#ifdef CONFIG_USB_INTERRUPT_IN_PIPE ++ pops->_read_interrupt = &usb_read_interrupt; ++#endif ++ ++ _func_exit_; ++ ++} ++ ++void rtl8188eu_set_hw_type(_adapter *padapter) ++{ ++ padapter->chip_type = RTL8188E; ++ padapter->HardwareType = HARDWARE_TYPE_RTL8188EU; ++ DBG_871X("CHIP TYPE: RTL8188E\n"); ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/ifcfg-wlan0 b/drivers/net/wireless/rtl818x/rtl8189/ifcfg-wlan0 +new file mode 100644 +index 00000000..20dcbec2 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/ifcfg-wlan0 +@@ -0,0 +1,4 @@ ++#DHCP client ++DEVICE=wlan0 ++BOOTPROTO=dhcp ++ONBOOT=yes +\ No newline at end of file +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/Hal8188EPhyCfg.h b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8188EPhyCfg.h +new file mode 100644 +index 00000000..e9b97cc1 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8188EPhyCfg.h +@@ -0,0 +1,429 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __INC_HAL8188EPHYCFG_H__ ++#define __INC_HAL8188EPHYCFG_H__ ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++#define LOOP_LIMIT 5 ++#define MAX_STALL_TIME 50 //us ++#define AntennaDiversityValue 0x80 //(Adapter->bSoftwareAntennaDiversity ? 0x00:0x80) ++#define MAX_TXPWR_IDX_NMODE_92S 63 ++#define Reset_Cnt_Limit 3 ++ ++#define IQK_MAC_REG_NUM 4 ++#define IQK_ADDA_REG_NUM 16 ++#define IQK_BB_REG_NUM 9 ++#define HP_THERMAL_NUM 8 ++ ++#ifdef CONFIG_PCI_HCI ++#define MAX_AGGR_NUM 0x0B ++#else ++#define MAX_AGGR_NUM 0x07 ++#endif // CONFIG_PCI_HCI ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++ ++/*------------------------------Define structure----------------------------*/ ++typedef enum _SwChnlCmdID{ ++ CmdID_End, ++ CmdID_SetTxPowerLevel, ++ CmdID_BBRegWrite10, ++ CmdID_WritePortUlong, ++ CmdID_WritePortUshort, ++ CmdID_WritePortUchar, ++ CmdID_RF_WriteReg, ++}SwChnlCmdID; ++ ++ ++/* 1. Switch channel related */ ++typedef struct _SwChnlCmd{ ++ SwChnlCmdID CmdID; ++ u32 Para1; ++ u32 Para2; ++ u32 msDelay; ++}SwChnlCmd; ++ ++typedef enum _HW90_BLOCK{ ++ HW90_BLOCK_MAC = 0, ++ HW90_BLOCK_PHY0 = 1, ++ HW90_BLOCK_PHY1 = 2, ++ HW90_BLOCK_RF = 3, ++ HW90_BLOCK_MAXIMUM = 4, // Never use this ++}HW90_BLOCK_E, *PHW90_BLOCK_E; ++ ++typedef enum _RF_RADIO_PATH{ ++ RF_PATH_A = 0, //Radio Path A ++ RF_PATH_B = 1, //Radio Path B ++ RF_PATH_C = 2, //Radio Path C ++ RF_PATH_D = 3, //Radio Path D ++ //RF_PATH_MAX //Max RF number 90 support ++}RF_RADIO_PATH_E, *PRF_RADIO_PATH_E; ++ ++#define MAX_PG_GROUP 13 ++ ++#define RF_PATH_MAX 2 ++#define MAX_RF_PATH RF_PATH_MAX ++#define MAX_TX_COUNT_88E 1 ++#define MAX_TX_COUNT MAX_TX_COUNT_88E // 4 //path numbers ++ ++#define CHANNEL_MAX_NUMBER 14 // 14 is the max channel number ++#define MAX_CHNL_GROUP_24G 6 // ch1~2, ch3~5, ch6~8,ch9~11,ch12~13,CH 14 total six groups ++#define CHANNEL_GROUP_MAX_88E 6 ++ ++typedef enum _WIRELESS_MODE { ++ WIRELESS_MODE_UNKNOWN = 0x00, ++ WIRELESS_MODE_A = BIT2, ++ WIRELESS_MODE_B = BIT0, ++ WIRELESS_MODE_G = BIT1, ++ WIRELESS_MODE_AUTO = BIT5, ++ WIRELESS_MODE_N_24G = BIT3, ++ WIRELESS_MODE_N_5G = BIT4, ++ WIRELESS_MODE_AC = BIT6 ++} WIRELESS_MODE; ++ ++ ++typedef enum _PHY_Rate_Tx_Power_Offset_Area{ ++ RA_OFFSET_LEGACY_OFDM1, ++ RA_OFFSET_LEGACY_OFDM2, ++ RA_OFFSET_HT_OFDM1, ++ RA_OFFSET_HT_OFDM2, ++ RA_OFFSET_HT_OFDM3, ++ RA_OFFSET_HT_OFDM4, ++ RA_OFFSET_HT_CCK, ++}RA_OFFSET_AREA,*PRA_OFFSET_AREA; ++ ++ ++/* BB/RF related */ ++typedef enum _RF_TYPE_8190P{ ++ RF_TYPE_MIN, // 0 ++ RF_8225=1, // 1 11b/g RF for verification only ++ RF_8256=2, // 2 11b/g/n ++ RF_8258=3, // 3 11a/b/g/n RF ++ RF_6052=4, // 4 11b/g/n RF ++ //RF_6052=5, // 4 11b/g/n RF ++ // TODO: We sholud remove this psudo PHY RF after we get new RF. ++ RF_PSEUDO_11N=5, // 5, It is a temporality RF. ++}RF_TYPE_8190P_E,*PRF_TYPE_8190P_E; ++ ++ ++typedef struct _BB_REGISTER_DEFINITION{ ++ u32 rfintfs; // set software control: ++ // 0x870~0x877[8 bytes] ++ ++ u32 rfintfi; // readback data: ++ // 0x8e0~0x8e7[8 bytes] ++ ++ u32 rfintfo; // output data: ++ // 0x860~0x86f [16 bytes] ++ ++ u32 rfintfe; // output enable: ++ // 0x860~0x86f [16 bytes] ++ ++ u32 rf3wireOffset; // LSSI data: ++ // 0x840~0x84f [16 bytes] ++ ++ u32 rfLSSI_Select; // BB Band Select: ++ // 0x878~0x87f [8 bytes] ++ ++ u32 rfTxGainStage; // Tx gain stage: ++ // 0x80c~0x80f [4 bytes] ++ ++ u32 rfHSSIPara1; // wire parameter control1 : ++ // 0x820~0x823,0x828~0x82b, 0x830~0x833, 0x838~0x83b [16 bytes] ++ ++ u32 rfHSSIPara2; // wire parameter control2 : ++ // 0x824~0x827,0x82c~0x82f, 0x834~0x837, 0x83c~0x83f [16 bytes] ++ ++ u32 rfSwitchControl; //Tx Rx antenna control : ++ // 0x858~0x85f [16 bytes] ++ ++ u32 rfAGCControl1; //AGC parameter control1 : ++ // 0xc50~0xc53,0xc58~0xc5b, 0xc60~0xc63, 0xc68~0xc6b [16 bytes] ++ ++ u32 rfAGCControl2; //AGC parameter control2 : ++ // 0xc54~0xc57,0xc5c~0xc5f, 0xc64~0xc67, 0xc6c~0xc6f [16 bytes] ++ ++ u32 rfRxIQImbalance; //OFDM Rx IQ imbalance matrix : ++ // 0xc14~0xc17,0xc1c~0xc1f, 0xc24~0xc27, 0xc2c~0xc2f [16 bytes] ++ ++ u32 rfRxAFE; //Rx IQ DC ofset and Rx digital filter, Rx DC notch filter : ++ // 0xc10~0xc13,0xc18~0xc1b, 0xc20~0xc23, 0xc28~0xc2b [16 bytes] ++ ++ u32 rfTxIQImbalance; //OFDM Tx IQ imbalance matrix ++ // 0xc80~0xc83,0xc88~0xc8b, 0xc90~0xc93, 0xc98~0xc9b [16 bytes] ++ ++ u32 rfTxAFE; //Tx IQ DC Offset and Tx DFIR type ++ // 0xc84~0xc87,0xc8c~0xc8f, 0xc94~0xc97, 0xc9c~0xc9f [16 bytes] ++ ++ u32 rfLSSIReadBack; //LSSI RF readback data SI mode ++ // 0x8a0~0x8af [16 bytes] ++ ++ u32 rfLSSIReadBackPi; //LSSI RF readback data PI mode 0x8b8-8bc for Path A and B ++ ++}BB_REGISTER_DEFINITION_T, *PBB_REGISTER_DEFINITION_T; ++ ++typedef struct _R_ANTENNA_SELECT_OFDM{ ++ u32 r_tx_antenna:4; ++ u32 r_ant_l:4; ++ u32 r_ant_non_ht:4; ++ u32 r_ant_ht1:4; ++ u32 r_ant_ht2:4; ++ u32 r_ant_ht_s1:4; ++ u32 r_ant_non_ht_s1:4; ++ u32 OFDM_TXSC:2; ++ u32 Reserved:2; ++}R_ANTENNA_SELECT_OFDM; ++ ++typedef struct _R_ANTENNA_SELECT_CCK{ ++ u8 r_cckrx_enable_2:2; ++ u8 r_cckrx_enable:2; ++ u8 r_ccktx_enable:4; ++}R_ANTENNA_SELECT_CCK; ++ ++/*------------------------------Define structure----------------------------*/ ++ ++ ++/*------------------------Export global variable----------------------------*/ ++/*------------------------Export global variable----------------------------*/ ++ ++ ++/*------------------------Export Marco Definition---------------------------*/ ++/*------------------------Export Marco Definition---------------------------*/ ++ ++ ++/*--------------------------Exported Function prototype---------------------*/ ++// ++// BB and RF register read/write ++// ++u32 rtl8188e_PHY_QueryBBReg( IN PADAPTER Adapter, ++ IN u32 RegAddr, ++ IN u32 BitMask ); ++void rtl8188e_PHY_SetBBReg( IN PADAPTER Adapter, ++ IN u32 RegAddr, ++ IN u32 BitMask, ++ IN u32 Data ); ++u32 rtl8188e_PHY_QueryRFReg( IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath, ++ IN u32 RegAddr, ++ IN u32 BitMask ); ++void rtl8188e_PHY_SetRFReg( IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath, ++ IN u32 RegAddr, ++ IN u32 BitMask, ++ IN u32 Data ); ++ ++// ++// Initialization related function ++// ++/* MAC/BB/RF HAL config */ ++int PHY_MACConfig8188E(IN PADAPTER Adapter ); ++int PHY_BBConfig8188E(IN PADAPTER Adapter ); ++int PHY_RFConfig8188E(IN PADAPTER Adapter ); ++ ++/* RF config */ ++int rtl8188e_PHY_ConfigRFWithParaFile(IN PADAPTER Adapter, IN u8 * pFileName, RF_RADIO_PATH_E eRFPath); ++int rtl8188e_PHY_ConfigRFWithHeaderFile( IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath); ++ ++/* Read initi reg value for tx power setting. */ ++void rtl8192c_PHY_GetHWRegOriginalValue( IN PADAPTER Adapter ); ++ ++// ++// RF Power setting ++// ++//extern BOOLEAN PHY_SetRFPowerState(IN PADAPTER Adapter, ++// IN RT_RF_POWER_STATE eRFPowerState); ++ ++// ++// BB TX Power R/W ++// ++void PHY_GetTxPowerLevel8188E( IN PADAPTER Adapter, ++ OUT u32* powerlevel ); ++void PHY_SetTxPowerLevel8188E( IN PADAPTER Adapter, ++ IN u8 channel ); ++BOOLEAN PHY_UpdateTxPowerDbm8188E( IN PADAPTER Adapter, ++ IN int powerInDbm ); ++ ++// ++VOID ++PHY_ScanOperationBackup8188E(IN PADAPTER Adapter, ++ IN u8 Operation ); ++ ++// ++// Switch bandwidth for 8192S ++// ++//extern void PHY_SetBWModeCallback8192C( IN PRT_TIMER pTimer ); ++void PHY_SetBWMode8188E( IN PADAPTER pAdapter, ++ IN HT_CHANNEL_WIDTH ChnlWidth, ++ IN unsigned char Offset ); ++ ++// ++// Set FW CMD IO for 8192S. ++// ++//extern BOOLEAN HalSetIO8192C( IN PADAPTER Adapter, ++// IN IO_TYPE IOType); ++ ++// ++// Set A2 entry to fw for 8192S ++// ++extern void FillA2Entry8192C( IN PADAPTER Adapter, ++ IN u8 index, ++ IN u8* val); ++ ++ ++// ++// channel switch related funciton ++// ++//extern void PHY_SwChnlCallback8192C( IN PRT_TIMER pTimer ); ++void PHY_SwChnl8188E( IN PADAPTER pAdapter, ++ IN u8 channel ); ++ // Call after initialization ++void PHY_SwChnlPhy8192C( IN PADAPTER pAdapter, ++ IN u8 channel ); ++ ++void ChkFwCmdIoDone( IN PADAPTER Adapter); ++ ++// ++// BB/MAC/RF other monitor API ++// ++void PHY_SetMonitorMode8192C(IN PADAPTER pAdapter, ++ IN BOOLEAN bEnableMonitorMode ); ++ ++BOOLEAN PHY_CheckIsLegalRfPath8192C(IN PADAPTER pAdapter, ++ IN u32 eRFPath ); ++ ++VOID PHY_SetRFPathSwitch_8188E(IN PADAPTER pAdapter, IN BOOLEAN bMain); ++ ++extern VOID ++PHY_SwitchEphyParameter( ++ IN PADAPTER Adapter ++ ); ++ ++extern VOID ++PHY_EnableHostClkReq( ++ IN PADAPTER Adapter ++ ); ++ ++BOOLEAN ++SetAntennaConfig92C( ++ IN PADAPTER Adapter, ++ IN u8 DefaultAnt ++ ); ++ ++#ifdef CONFIG_PHY_SETTING_WITH_ODM ++VOID ++storePwrIndexDiffRateOffset( ++ IN PADAPTER Adapter, ++ IN u32 RegAddr, ++ IN u32 BitMask, ++ IN u32 Data ++ ); ++#endif //CONFIG_PHY_SETTING_WITH_ODM ++/*--------------------------Exported Function prototype---------------------*/ ++ ++#define PHY_QueryBBReg(Adapter, RegAddr, BitMask) rtl8188e_PHY_QueryBBReg((Adapter), (RegAddr), (BitMask)) ++#define PHY_SetBBReg(Adapter, RegAddr, BitMask, Data) rtl8188e_PHY_SetBBReg((Adapter), (RegAddr), (BitMask), (Data)) ++#define PHY_QueryRFReg(Adapter, eRFPath, RegAddr, BitMask) rtl8188e_PHY_QueryRFReg((Adapter), (eRFPath), (RegAddr), (BitMask)) ++#define PHY_SetRFReg(Adapter, eRFPath, RegAddr, BitMask, Data) rtl8188e_PHY_SetRFReg((Adapter), (eRFPath), (RegAddr), (BitMask), (Data)) ++ ++#define PHY_SetMacReg PHY_SetBBReg ++#define PHY_QueryMacReg PHY_QueryBBReg ++ ++ ++// ++// Initialization related function ++// ++/* MAC/BB/RF HAL config */ ++//extern s32 PHY_MACConfig8723(PADAPTER padapter); ++//s32 PHY_BBConfig8723(PADAPTER padapter); ++//s32 PHY_RFConfig8723(PADAPTER padapter); ++ ++ ++ ++//================================================================== ++// Note: If SIC_ENABLE under PCIE, because of the slow operation ++// you should ++// 2) "#define RTL8723_FPGA_VERIFICATION 1" in Precomp.h.WlanE.Windows ++// 3) "#define RTL8190_Download_Firmware_From_Header 0" in Precomp.h.WlanE.Windows if needed. ++// ++#if (RTL8188E_SUPPORT == 1) && (RTL8188E_FPGA_TRUE_PHY_VERIFICATION == 1) ++#define SIC_ENABLE 1 ++#define SIC_HW_SUPPORT 1 ++#else ++#define SIC_ENABLE 0 ++#define SIC_HW_SUPPORT 0 ++#endif ++//================================================================== ++ ++ ++#define SIC_MAX_POLL_CNT 5 ++ ++#if(SIC_HW_SUPPORT == 1) ++#define SIC_CMD_READY 0 ++#define SIC_CMD_PREWRITE 0x1 ++#if(RTL8188E_SUPPORT == 1) ++#define SIC_CMD_WRITE 0x40 ++#define SIC_CMD_PREREAD 0x2 ++#define SIC_CMD_READ 0x80 ++#define SIC_CMD_INIT 0xf0 ++#define SIC_INIT_VAL 0xff ++ ++#define SIC_INIT_REG 0x1b7 ++#define SIC_CMD_REG 0x1EB // 1byte ++#define SIC_ADDR_REG 0x1E8 // 1b4~1b5, 2 bytes ++#define SIC_DATA_REG 0x1EC // 1b0~1b3 ++#else ++#define SIC_CMD_WRITE 0x11 ++#define SIC_CMD_PREREAD 0x2 ++#define SIC_CMD_READ 0x12 ++#define SIC_CMD_INIT 0x1f ++#define SIC_INIT_VAL 0xff ++ ++#define SIC_INIT_REG 0x1b7 ++#define SIC_CMD_REG 0x1b6 // 1byte ++#define SIC_ADDR_REG 0x1b4 // 1b4~1b5, 2 bytes ++#define SIC_DATA_REG 0x1b0 // 1b0~1b3 ++#endif ++#else ++#define SIC_CMD_READY 0 ++#define SIC_CMD_WRITE 1 ++#define SIC_CMD_READ 2 ++ ++#if(RTL8188E_SUPPORT == 1) ++#define SIC_CMD_REG 0x1EB // 1byte ++#define SIC_ADDR_REG 0x1E8 // 1b9~1ba, 2 bytes ++#define SIC_DATA_REG 0x1EC // 1bc~1bf ++#else ++#define SIC_CMD_REG 0x1b8 // 1byte ++#define SIC_ADDR_REG 0x1b9 // 1b9~1ba, 2 bytes ++#define SIC_DATA_REG 0x1bc // 1bc~1bf ++#endif ++#endif ++ ++#if(SIC_ENABLE == 1) ++VOID SIC_Init(IN PADAPTER Adapter); ++#endif ++ ++ ++#endif // __INC_HAL8192CPHYCFG_H ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/Hal8188EPhyReg.h b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8188EPhyReg.h +new file mode 100644 +index 00000000..f83e6096 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8188EPhyReg.h +@@ -0,0 +1,1112 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __INC_HAL8188EPHYREG_H__ ++#define __INC_HAL8188EPHYREG_H__ ++/*--------------------------Define Parameters-------------------------------*/ ++// ++// BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF ++// 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF ++// 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 ++// 3. RF register 0x00-2E ++// 4. Bit Mask for BB/RF register ++// 5. Other defintion for BB/RF R/W ++// ++ ++ ++// ++// 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF ++// 1. Page1(0x100) ++// ++#define rPMAC_Reset 0x100 ++#define rPMAC_TxStart 0x104 ++#define rPMAC_TxLegacySIG 0x108 ++#define rPMAC_TxHTSIG1 0x10c ++#define rPMAC_TxHTSIG2 0x110 ++#define rPMAC_PHYDebug 0x114 ++#define rPMAC_TxPacketNum 0x118 ++#define rPMAC_TxIdle 0x11c ++#define rPMAC_TxMACHeader0 0x120 ++#define rPMAC_TxMACHeader1 0x124 ++#define rPMAC_TxMACHeader2 0x128 ++#define rPMAC_TxMACHeader3 0x12c ++#define rPMAC_TxMACHeader4 0x130 ++#define rPMAC_TxMACHeader5 0x134 ++#define rPMAC_TxDataType 0x138 ++#define rPMAC_TxRandomSeed 0x13c ++#define rPMAC_CCKPLCPPreamble 0x140 ++#define rPMAC_CCKPLCPHeader 0x144 ++#define rPMAC_CCKCRC16 0x148 ++#define rPMAC_OFDMRxCRC32OK 0x170 ++#define rPMAC_OFDMRxCRC32Er 0x174 ++#define rPMAC_OFDMRxParityEr 0x178 ++#define rPMAC_OFDMRxCRC8Er 0x17c ++#define rPMAC_CCKCRxRC16Er 0x180 ++#define rPMAC_CCKCRxRC32Er 0x184 ++#define rPMAC_CCKCRxRC32OK 0x188 ++#define rPMAC_TxStatus 0x18c ++ ++// ++// 2. Page2(0x200) ++// ++// The following two definition are only used for USB interface. ++#define RF_BB_CMD_ADDR 0x02c0 // RF/BB read/write command address. ++#define RF_BB_CMD_DATA 0x02c4 // RF/BB read/write command data. ++ ++// ++// 3. Page8(0x800) ++// ++#define rFPGA0_RFMOD 0x800 //RF mode & CCK TxSC // RF BW Setting?? ++ ++#define rFPGA0_TxInfo 0x804 // Status report?? ++#define rFPGA0_PSDFunction 0x808 ++ ++#define rFPGA0_TxGainStage 0x80c // Set TX PWR init gain? ++ ++#define rFPGA0_RFTiming1 0x810 // Useless now ++#define rFPGA0_RFTiming2 0x814 ++ ++#define rFPGA0_XA_HSSIParameter1 0x820 // RF 3 wire register ++#define rFPGA0_XA_HSSIParameter2 0x824 ++#define rFPGA0_XB_HSSIParameter1 0x828 ++#define rFPGA0_XB_HSSIParameter2 0x82c ++ ++#define rFPGA0_XA_LSSIParameter 0x840 ++#define rFPGA0_XB_LSSIParameter 0x844 ++ ++#define rFPGA0_RFWakeUpParameter 0x850 // Useless now ++#define rFPGA0_RFSleepUpParameter 0x854 ++ ++#define rFPGA0_XAB_SwitchControl 0x858 // RF Channel switch ++#define rFPGA0_XCD_SwitchControl 0x85c ++ ++#define rFPGA0_XA_RFInterfaceOE 0x860 // RF Channel switch ++#define rFPGA0_XB_RFInterfaceOE 0x864 ++ ++#define rFPGA0_XAB_RFInterfaceSW 0x870 // RF Interface Software Control ++#define rFPGA0_XCD_RFInterfaceSW 0x874 ++ ++#define rFPGA0_XAB_RFParameter 0x878 // RF Parameter ++#define rFPGA0_XCD_RFParameter 0x87c ++ ++#define rFPGA0_AnalogParameter1 0x880 // Crystal cap setting RF-R/W protection for parameter4?? ++#define rFPGA0_AnalogParameter2 0x884 ++#define rFPGA0_AnalogParameter3 0x888 ++#define rFPGA0_AdDaClockEn 0x888 // enable ad/da clock1 for dual-phy ++#define rFPGA0_AnalogParameter4 0x88c ++ ++#define rFPGA0_XA_LSSIReadBack 0x8a0 // Tranceiver LSSI Readback ++#define rFPGA0_XB_LSSIReadBack 0x8a4 ++#define rFPGA0_XC_LSSIReadBack 0x8a8 ++#define rFPGA0_XD_LSSIReadBack 0x8ac ++ ++#define rFPGA0_PSDReport 0x8b4 // Useless now ++#define TransceiverA_HSPI_Readback 0x8b8 // Transceiver A HSPI Readback ++#define TransceiverB_HSPI_Readback 0x8bc // Transceiver B HSPI Readback ++#define rFPGA0_XAB_RFInterfaceRB 0x8e0 // Useless now // RF Interface Readback Value ++#define rFPGA0_XCD_RFInterfaceRB 0x8e4 // Useless now ++ ++// ++// 4. Page9(0x900) ++// ++#define rFPGA1_RFMOD 0x900 //RF mode & OFDM TxSC // RF BW Setting?? ++ ++#define rFPGA1_TxBlock 0x904 // Useless now ++#define rFPGA1_DebugSelect 0x908 // Useless now ++#define rFPGA1_TxInfo 0x90c // Useless now // Status report?? ++ ++// ++// 5. PageA(0xA00) ++// ++// Set Control channel to upper or lower. These settings are required only for 40MHz ++#define rCCK0_System 0xa00 ++ ++#define rCCK0_AFESetting 0xa04 // Disable init gain now // Select RX path by RSSI ++#define rCCK0_CCA 0xa08 // Disable init gain now // Init gain ++ ++#define rCCK0_RxAGC1 0xa0c //AGC default value, saturation level // Antenna Diversity, RX AGC, LNA Threshold, RX LNA Threshold useless now. Not the same as 90 series ++#define rCCK0_RxAGC2 0xa10 //AGC & DAGC ++ ++#define rCCK0_RxHP 0xa14 ++ ++#define rCCK0_DSPParameter1 0xa18 //Timing recovery & Channel estimation threshold ++#define rCCK0_DSPParameter2 0xa1c //SQ threshold ++ ++#define rCCK0_TxFilter1 0xa20 ++#define rCCK0_TxFilter2 0xa24 ++#define rCCK0_DebugPort 0xa28 //debug port and Tx filter3 ++#define rCCK0_FalseAlarmReport 0xa2c //0xa2d useless now 0xa30-a4f channel report ++#define rCCK0_TRSSIReport 0xa50 ++#define rCCK0_RxReport 0xa54 //0xa57 ++#define rCCK0_FACounterLower 0xa5c //0xa5b ++#define rCCK0_FACounterUpper 0xa58 //0xa5c ++ ++// ++// PageB(0xB00) ++// ++#define rPdp_AntA 0xb00 ++#define rPdp_AntA_4 0xb04 ++#define rConfig_Pmpd_AntA 0xb28 ++#define rConfig_AntA 0xb68 ++#define rConfig_AntB 0xb6c ++#define rPdp_AntB 0xb70 ++#define rPdp_AntB_4 0xb74 ++#define rConfig_Pmpd_AntB 0xb98 ++#define rAPK 0xbd8 ++ ++ ++ ++// ++// 6. PageC(0xC00) ++// ++#define rOFDM0_LSTF 0xc00 ++ ++#define rOFDM0_TRxPathEnable 0xc04 ++#define rOFDM0_TRMuxPar 0xc08 ++#define rOFDM0_TRSWIsolation 0xc0c ++ ++#define rOFDM0_XARxAFE 0xc10 //RxIQ DC offset, Rx digital filter, DC notch filter ++#define rOFDM0_XARxIQImbalance 0xc14 //RxIQ imblance matrix ++#define rOFDM0_XBRxAFE 0xc18 ++#define rOFDM0_XBRxIQImbalance 0xc1c ++#define rOFDM0_XCRxAFE 0xc20 ++#define rOFDM0_XCRxIQImbalance 0xc24 ++#define rOFDM0_XDRxAFE 0xc28 ++#define rOFDM0_XDRxIQImbalance 0xc2c ++ ++#define rOFDM0_RxDetector1 0xc30 //PD,BW & SBD // DM tune init gain ++#define rOFDM0_RxDetector2 0xc34 //SBD & Fame Sync. ++#define rOFDM0_RxDetector3 0xc38 //Frame Sync. ++#define rOFDM0_RxDetector4 0xc3c //PD, SBD, Frame Sync & Short-GI ++ ++#define rOFDM0_RxDSP 0xc40 //Rx Sync Path ++#define rOFDM0_CFOandDAGC 0xc44 //CFO & DAGC ++#define rOFDM0_CCADropThreshold 0xc48 //CCA Drop threshold ++#define rOFDM0_ECCAThreshold 0xc4c // energy CCA ++ ++#define rOFDM0_XAAGCCore1 0xc50 // DIG ++#define rOFDM0_XAAGCCore2 0xc54 ++#define rOFDM0_XBAGCCore1 0xc58 ++#define rOFDM0_XBAGCCore2 0xc5c ++#define rOFDM0_XCAGCCore1 0xc60 ++#define rOFDM0_XCAGCCore2 0xc64 ++#define rOFDM0_XDAGCCore1 0xc68 ++#define rOFDM0_XDAGCCore2 0xc6c ++ ++#define rOFDM0_AGCParameter1 0xc70 ++#define rOFDM0_AGCParameter2 0xc74 ++#define rOFDM0_AGCRSSITable 0xc78 ++#define rOFDM0_HTSTFAGC 0xc7c ++ ++#define rOFDM0_XATxIQImbalance 0xc80 // TX PWR TRACK and DIG ++#define rOFDM0_XATxAFE 0xc84 ++#define rOFDM0_XBTxIQImbalance 0xc88 ++#define rOFDM0_XBTxAFE 0xc8c ++#define rOFDM0_XCTxIQImbalance 0xc90 ++#define rOFDM0_XCTxAFE 0xc94 ++#define rOFDM0_XDTxIQImbalance 0xc98 ++#define rOFDM0_XDTxAFE 0xc9c ++ ++#define rOFDM0_RxIQExtAnta 0xca0 ++#define rOFDM0_TxCoeff1 0xca4 ++#define rOFDM0_TxCoeff2 0xca8 ++#define rOFDM0_TxCoeff3 0xcac ++#define rOFDM0_TxCoeff4 0xcb0 ++#define rOFDM0_TxCoeff5 0xcb4 ++#define rOFDM0_TxCoeff6 0xcb8 ++#define rOFDM0_RxHPParameter 0xce0 ++#define rOFDM0_TxPseudoNoiseWgt 0xce4 ++#define rOFDM0_FrameSync 0xcf0 ++#define rOFDM0_DFSReport 0xcf4 ++ ++ ++// ++// 7. PageD(0xD00) ++// ++#define rOFDM1_LSTF 0xd00 ++#define rOFDM1_TRxPathEnable 0xd04 ++ ++#define rOFDM1_CFO 0xd08 // No setting now ++#define rOFDM1_CSI1 0xd10 ++#define rOFDM1_SBD 0xd14 ++#define rOFDM1_CSI2 0xd18 ++#define rOFDM1_CFOTracking 0xd2c ++#define rOFDM1_TRxMesaure1 0xd34 ++#define rOFDM1_IntfDet 0xd3c ++#define rOFDM1_csi_fix_mask 0xd40 ++#define rOFDM1_PseudoNoiseStateAB 0xd50 ++#define rOFDM1_PseudoNoiseStateCD 0xd54 ++#define rOFDM1_RxPseudoNoiseWgt 0xd58 ++ ++#define rOFDM_PHYCounter1 0xda0 //cca, parity fail ++#define rOFDM_PHYCounter2 0xda4 //rate illegal, crc8 fail ++#define rOFDM_PHYCounter3 0xda8 //MCS not support ++ ++#define rOFDM_ShortCFOAB 0xdac // No setting now ++#define rOFDM_ShortCFOCD 0xdb0 ++#define rOFDM_LongCFOAB 0xdb4 ++#define rOFDM_LongCFOCD 0xdb8 ++#define rOFDM_TailCFOAB 0xdbc ++#define rOFDM_TailCFOCD 0xdc0 ++#define rOFDM_PWMeasure1 0xdc4 ++#define rOFDM_PWMeasure2 0xdc8 ++#define rOFDM_BWReport 0xdcc ++#define rOFDM_AGCReport 0xdd0 ++#define rOFDM_RxSNR 0xdd4 ++#define rOFDM_RxEVMCSI 0xdd8 ++#define rOFDM_SIGReport 0xddc ++ ++ ++// ++// 8. PageE(0xE00) ++// ++#define rTxAGC_A_Rate18_06 0xe00 ++#define rTxAGC_A_Rate54_24 0xe04 ++#define rTxAGC_A_CCK1_Mcs32 0xe08 ++#define rTxAGC_A_Mcs03_Mcs00 0xe10 ++#define rTxAGC_A_Mcs07_Mcs04 0xe14 ++#define rTxAGC_A_Mcs11_Mcs08 0xe18 ++#define rTxAGC_A_Mcs15_Mcs12 0xe1c ++ ++#define rTxAGC_B_Rate18_06 0x830 ++#define rTxAGC_B_Rate54_24 0x834 ++#define rTxAGC_B_CCK1_55_Mcs32 0x838 ++#define rTxAGC_B_Mcs03_Mcs00 0x83c ++#define rTxAGC_B_Mcs07_Mcs04 0x848 ++#define rTxAGC_B_Mcs11_Mcs08 0x84c ++#define rTxAGC_B_Mcs15_Mcs12 0x868 ++#define rTxAGC_B_CCK11_A_CCK2_11 0x86c ++ ++#define rFPGA0_IQK 0xe28 ++#define rTx_IQK_Tone_A 0xe30 ++#define rRx_IQK_Tone_A 0xe34 ++#define rTx_IQK_PI_A 0xe38 ++#define rRx_IQK_PI_A 0xe3c ++ ++#define rTx_IQK 0xe40 ++#define rRx_IQK 0xe44 ++#define rIQK_AGC_Pts 0xe48 ++#define rIQK_AGC_Rsp 0xe4c ++#define rTx_IQK_Tone_B 0xe50 ++#define rRx_IQK_Tone_B 0xe54 ++#define rTx_IQK_PI_B 0xe58 ++#define rRx_IQK_PI_B 0xe5c ++#define rIQK_AGC_Cont 0xe60 ++ ++#define rBlue_Tooth 0xe6c ++#define rRx_Wait_CCA 0xe70 ++#define rTx_CCK_RFON 0xe74 ++#define rTx_CCK_BBON 0xe78 ++#define rTx_OFDM_RFON 0xe7c ++#define rTx_OFDM_BBON 0xe80 ++#define rTx_To_Rx 0xe84 ++#define rTx_To_Tx 0xe88 ++#define rRx_CCK 0xe8c ++ ++#define rTx_Power_Before_IQK_A 0xe94 ++#define rTx_Power_After_IQK_A 0xe9c ++ ++#define rRx_Power_Before_IQK_A 0xea0 ++#define rRx_Power_Before_IQK_A_2 0xea4 ++#define rRx_Power_After_IQK_A 0xea8 ++#define rRx_Power_After_IQK_A_2 0xeac ++ ++#define rTx_Power_Before_IQK_B 0xeb4 ++#define rTx_Power_After_IQK_B 0xebc ++ ++#define rRx_Power_Before_IQK_B 0xec0 ++#define rRx_Power_Before_IQK_B_2 0xec4 ++#define rRx_Power_After_IQK_B 0xec8 ++#define rRx_Power_After_IQK_B_2 0xecc ++ ++#define rRx_OFDM 0xed0 ++#define rRx_Wait_RIFS 0xed4 ++#define rRx_TO_Rx 0xed8 ++#define rStandby 0xedc ++#define rSleep 0xee0 ++#define rPMPD_ANAEN 0xeec ++ ++// ++// 7. RF Register 0x00-0x2E (RF 8256) ++// RF-0222D 0x00-3F ++// ++//Zebra1 ++#define rZebra1_HSSIEnable 0x0 // Useless now ++#define rZebra1_TRxEnable1 0x1 ++#define rZebra1_TRxEnable2 0x2 ++#define rZebra1_AGC 0x4 ++#define rZebra1_ChargePump 0x5 ++#define rZebra1_Channel 0x7 // RF channel switch ++ ++//#endif ++#define rZebra1_TxGain 0x8 // Useless now ++#define rZebra1_TxLPF 0x9 ++#define rZebra1_RxLPF 0xb ++#define rZebra1_RxHPFCorner 0xc ++ ++//Zebra4 ++#define rGlobalCtrl 0 // Useless now ++#define rRTL8256_TxLPF 19 ++#define rRTL8256_RxLPF 11 ++ ++//RTL8258 ++#define rRTL8258_TxLPF 0x11 // Useless now ++#define rRTL8258_RxLPF 0x13 ++#define rRTL8258_RSSILPF 0xa ++ ++// ++// RL6052 Register definition ++// ++#define RF_AC 0x00 // ++ ++#define RF_IQADJ_G1 0x01 // ++#define RF_IQADJ_G2 0x02 // ++ ++#define RF_POW_TRSW 0x05 // ++ ++#define RF_GAIN_RX 0x06 // ++#define RF_GAIN_TX 0x07 // ++ ++#define RF_TXM_IDAC 0x08 // ++#define RF_IPA_G 0x09 // ++#define RF_TXBIAS_G 0x0A ++#define RF_TXPA_AG 0x0B ++#define RF_IPA_A 0x0C // ++#define RF_TXBIAS_A 0x0D ++#define RF_BS_PA_APSET_G9_G11 0x0E ++#define RF_BS_IQGEN 0x0F // ++ ++#define RF_MODE1 0x10 // ++#define RF_MODE2 0x11 // ++ ++#define RF_RX_AGC_HP 0x12 // ++#define RF_TX_AGC 0x13 // ++#define RF_BIAS 0x14 // ++#define RF_IPA 0x15 // ++#define RF_TXBIAS 0x16 ++#define RF_POW_ABILITY 0x17 // ++#define RF_CHNLBW 0x18 // RF channel and BW switch ++#define RF_TOP 0x19 // ++ ++#define RF_RX_G1 0x1A // ++#define RF_RX_G2 0x1B // ++ ++#define RF_RX_BB2 0x1C // ++#define RF_RX_BB1 0x1D // ++ ++#define RF_RCK1 0x1E // ++#define RF_RCK2 0x1F // ++ ++#define RF_TX_G1 0x20 // ++#define RF_TX_G2 0x21 // ++#define RF_TX_G3 0x22 // ++ ++#define RF_TX_BB1 0x23 // ++ ++//#if HARDWARE_TYPE_IS_RTL8192D == 1 ++#define RF_T_METER_92D 0x42 // ++//#else ++#define RF_T_METER_88E 0x42 // ++#define RF_T_METER 0x24 // ++ ++//#endif ++ ++#define RF_SYN_G1 0x25 // RF TX Power control ++#define RF_SYN_G2 0x26 // RF TX Power control ++#define RF_SYN_G3 0x27 // RF TX Power control ++#define RF_SYN_G4 0x28 // RF TX Power control ++#define RF_SYN_G5 0x29 // RF TX Power control ++#define RF_SYN_G6 0x2A // RF TX Power control ++#define RF_SYN_G7 0x2B // RF TX Power control ++#define RF_SYN_G8 0x2C // RF TX Power control ++ ++#define RF_RCK_OS 0x30 // RF TX PA control ++#define RF_TXPA_G1 0x31 // RF TX PA control ++#define RF_TXPA_G2 0x32 // RF TX PA control ++#define RF_TXPA_G3 0x33 // RF TX PA control ++#define RF_TX_BIAS_A 0x35 ++#define RF_TX_BIAS_D 0x36 ++#define RF_LOBF_9 0x38 ++#define RF_RXRF_A3 0x3C // ++#define RF_TRSW 0x3F ++ ++#define RF_TXRF_A2 0x41 ++#define RF_TXPA_G4 0x46 ++#define RF_TXPA_A4 0x4B ++#define RF_0x52 0x52 ++#define RF_WE_LUT 0xEF ++ ++ ++// ++//Bit Mask ++// ++// 1. Page1(0x100) ++#define bBBResetB 0x100 // Useless now? ++#define bGlobalResetB 0x200 ++#define bOFDMTxStart 0x4 ++#define bCCKTxStart 0x8 ++#define bCRC32Debug 0x100 ++#define bPMACLoopback 0x10 ++#define bTxLSIG 0xffffff ++#define bOFDMTxRate 0xf ++#define bOFDMTxReserved 0x10 ++#define bOFDMTxLength 0x1ffe0 ++#define bOFDMTxParity 0x20000 ++#define bTxHTSIG1 0xffffff ++#define bTxHTMCSRate 0x7f ++#define bTxHTBW 0x80 ++#define bTxHTLength 0xffff00 ++#define bTxHTSIG2 0xffffff ++#define bTxHTSmoothing 0x1 ++#define bTxHTSounding 0x2 ++#define bTxHTReserved 0x4 ++#define bTxHTAggreation 0x8 ++#define bTxHTSTBC 0x30 ++#define bTxHTAdvanceCoding 0x40 ++#define bTxHTShortGI 0x80 ++#define bTxHTNumberHT_LTF 0x300 ++#define bTxHTCRC8 0x3fc00 ++#define bCounterReset 0x10000 ++#define bNumOfOFDMTx 0xffff ++#define bNumOfCCKTx 0xffff0000 ++#define bTxIdleInterval 0xffff ++#define bOFDMService 0xffff0000 ++#define bTxMACHeader 0xffffffff ++#define bTxDataInit 0xff ++#define bTxHTMode 0x100 ++#define bTxDataType 0x30000 ++#define bTxRandomSeed 0xffffffff ++#define bCCKTxPreamble 0x1 ++#define bCCKTxSFD 0xffff0000 ++#define bCCKTxSIG 0xff ++#define bCCKTxService 0xff00 ++#define bCCKLengthExt 0x8000 ++#define bCCKTxLength 0xffff0000 ++#define bCCKTxCRC16 0xffff ++#define bCCKTxStatus 0x1 ++#define bOFDMTxStatus 0x2 ++ ++#define IS_BB_REG_OFFSET_92S(_Offset) ((_Offset >= 0x800) && (_Offset <= 0xfff)) ++ ++// 2. Page8(0x800) ++#define bRFMOD 0x1 // Reg 0x800 rFPGA0_RFMOD ++#define bJapanMode 0x2 ++#define bCCKTxSC 0x30 ++#define bCCKEn 0x1000000 ++#define bOFDMEn 0x2000000 ++ ++#define bOFDMRxADCPhase 0x10000 // Useless now ++#define bOFDMTxDACPhase 0x40000 ++#define bXATxAGC 0x3f ++ ++#define bAntennaSelect 0x0300 ++ ++#define bXBTxAGC 0xf00 // Reg 80c rFPGA0_TxGainStage ++#define bXCTxAGC 0xf000 ++#define bXDTxAGC 0xf0000 ++ ++#define bPAStart 0xf0000000 // Useless now ++#define bTRStart 0x00f00000 ++#define bRFStart 0x0000f000 ++#define bBBStart 0x000000f0 ++#define bBBCCKStart 0x0000000f ++#define bPAEnd 0xf //Reg0x814 ++#define bTREnd 0x0f000000 ++#define bRFEnd 0x000f0000 ++#define bCCAMask 0x000000f0 //T2R ++#define bR2RCCAMask 0x00000f00 ++#define bHSSI_R2TDelay 0xf8000000 ++#define bHSSI_T2RDelay 0xf80000 ++#define bContTxHSSI 0x400 //chane gain at continue Tx ++#define bIGFromCCK 0x200 ++#define bAGCAddress 0x3f ++#define bRxHPTx 0x7000 ++#define bRxHPT2R 0x38000 ++#define bRxHPCCKIni 0xc0000 ++#define bAGCTxCode 0xc00000 ++#define bAGCRxCode 0x300000 ++ ++#define b3WireDataLength 0x800 // Reg 0x820~84f rFPGA0_XA_HSSIParameter1 ++#define b3WireAddressLength 0x400 ++ ++#define b3WireRFPowerDown 0x1 // Useless now ++//#define bHWSISelect 0x8 ++#define b5GPAPEPolarity 0x40000000 ++#define b2GPAPEPolarity 0x80000000 ++#define bRFSW_TxDefaultAnt 0x3 ++#define bRFSW_TxOptionAnt 0x30 ++#define bRFSW_RxDefaultAnt 0x300 ++#define bRFSW_RxOptionAnt 0x3000 ++#define bRFSI_3WireData 0x1 ++#define bRFSI_3WireClock 0x2 ++#define bRFSI_3WireLoad 0x4 ++#define bRFSI_3WireRW 0x8 ++#define bRFSI_3Wire 0xf ++ ++#define bRFSI_RFENV 0x10 // Reg 0x870 rFPGA0_XAB_RFInterfaceSW ++ ++#define bRFSI_TRSW 0x20 // Useless now ++#define bRFSI_TRSWB 0x40 ++#define bRFSI_ANTSW 0x100 ++#define bRFSI_ANTSWB 0x200 ++#define bRFSI_PAPE 0x400 ++#define bRFSI_PAPE5G 0x800 ++#define bBandSelect 0x1 ++#define bHTSIG2_GI 0x80 ++#define bHTSIG2_Smoothing 0x01 ++#define bHTSIG2_Sounding 0x02 ++#define bHTSIG2_Aggreaton 0x08 ++#define bHTSIG2_STBC 0x30 ++#define bHTSIG2_AdvCoding 0x40 ++#define bHTSIG2_NumOfHTLTF 0x300 ++#define bHTSIG2_CRC8 0x3fc ++#define bHTSIG1_MCS 0x7f ++#define bHTSIG1_BandWidth 0x80 ++#define bHTSIG1_HTLength 0xffff ++#define bLSIG_Rate 0xf ++#define bLSIG_Reserved 0x10 ++#define bLSIG_Length 0x1fffe ++#define bLSIG_Parity 0x20 ++#define bCCKRxPhase 0x4 ++ ++#define bLSSIReadAddress 0x7f800000 // T65 RF ++ ++#define bLSSIReadEdge 0x80000000 //LSSI "Read" edge signal ++ ++#define bLSSIReadBackData 0xfffff // T65 RF ++ ++#define bLSSIReadOKFlag 0x1000 // Useless now ++#define bCCKSampleRate 0x8 //0: 44MHz, 1:88MHz ++#define bRegulator0Standby 0x1 ++#define bRegulatorPLLStandby 0x2 ++#define bRegulator1Standby 0x4 ++#define bPLLPowerUp 0x8 ++#define bDPLLPowerUp 0x10 ++#define bDA10PowerUp 0x20 ++#define bAD7PowerUp 0x200 ++#define bDA6PowerUp 0x2000 ++#define bXtalPowerUp 0x4000 ++#define b40MDClkPowerUP 0x8000 ++#define bDA6DebugMode 0x20000 ++#define bDA6Swing 0x380000 ++ ++#define bADClkPhase 0x4000000 // Reg 0x880 rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ ++ ++#define b80MClkDelay 0x18000000 // Useless ++#define bAFEWatchDogEnable 0x20000000 ++ ++#define bXtalCap01 0xc0000000 // Reg 0x884 rFPGA0_AnalogParameter2 Crystal cap ++#define bXtalCap23 0x3 ++#define bXtalCap92x 0x0f000000 ++#define bXtalCap 0x0f000000 ++ ++#define bIntDifClkEnable 0x400 // Useless ++#define bExtSigClkEnable 0x800 ++#define bBandgapMbiasPowerUp 0x10000 ++#define bAD11SHGain 0xc0000 ++#define bAD11InputRange 0x700000 ++#define bAD11OPCurrent 0x3800000 ++#define bIPathLoopback 0x4000000 ++#define bQPathLoopback 0x8000000 ++#define bAFELoopback 0x10000000 ++#define bDA10Swing 0x7e0 ++#define bDA10Reverse 0x800 ++#define bDAClkSource 0x1000 ++#define bAD7InputRange 0x6000 ++#define bAD7Gain 0x38000 ++#define bAD7OutputCMMode 0x40000 ++#define bAD7InputCMMode 0x380000 ++#define bAD7Current 0xc00000 ++#define bRegulatorAdjust 0x7000000 ++#define bAD11PowerUpAtTx 0x1 ++#define bDA10PSAtTx 0x10 ++#define bAD11PowerUpAtRx 0x100 ++#define bDA10PSAtRx 0x1000 ++#define bCCKRxAGCFormat 0x200 ++#define bPSDFFTSamplepPoint 0xc000 ++#define bPSDAverageNum 0x3000 ++#define bIQPathControl 0xc00 ++#define bPSDFreq 0x3ff ++#define bPSDAntennaPath 0x30 ++#define bPSDIQSwitch 0x40 ++#define bPSDRxTrigger 0x400000 ++#define bPSDTxTrigger 0x80000000 ++#define bPSDSineToneScale 0x7f000000 ++#define bPSDReport 0xffff ++ ++// 3. Page9(0x900) ++#define bOFDMTxSC 0x30000000 // Useless ++#define bCCKTxOn 0x1 ++#define bOFDMTxOn 0x2 ++#define bDebugPage 0xfff //reset debug page and also HWord, LWord ++#define bDebugItem 0xff //reset debug page and LWord ++#define bAntL 0x10 ++#define bAntNonHT 0x100 ++#define bAntHT1 0x1000 ++#define bAntHT2 0x10000 ++#define bAntHT1S1 0x100000 ++#define bAntNonHTS1 0x1000000 ++ ++// 4. PageA(0xA00) ++#define bCCKBBMode 0x3 // Useless ++#define bCCKTxPowerSaving 0x80 ++#define bCCKRxPowerSaving 0x40 ++ ++#define bCCKSideBand 0x10 // Reg 0xa00 rCCK0_System 20/40 switch ++ ++#define bCCKScramble 0x8 // Useless ++#define bCCKAntDiversity 0x8000 ++#define bCCKCarrierRecovery 0x4000 ++#define bCCKTxRate 0x3000 ++#define bCCKDCCancel 0x0800 ++#define bCCKISICancel 0x0400 ++#define bCCKMatchFilter 0x0200 ++#define bCCKEqualizer 0x0100 ++#define bCCKPreambleDetect 0x800000 ++#define bCCKFastFalseCCA 0x400000 ++#define bCCKChEstStart 0x300000 ++#define bCCKCCACount 0x080000 ++#define bCCKcs_lim 0x070000 ++#define bCCKBistMode 0x80000000 ++#define bCCKCCAMask 0x40000000 ++#define bCCKTxDACPhase 0x4 ++#define bCCKRxADCPhase 0x20000000 //r_rx_clk ++#define bCCKr_cp_mode0 0x0100 ++#define bCCKTxDCOffset 0xf0 ++#define bCCKRxDCOffset 0xf ++#define bCCKCCAMode 0xc000 ++#define bCCKFalseCS_lim 0x3f00 ++#define bCCKCS_ratio 0xc00000 ++#define bCCKCorgBit_sel 0x300000 ++#define bCCKPD_lim 0x0f0000 ++#define bCCKNewCCA 0x80000000 ++#define bCCKRxHPofIG 0x8000 ++#define bCCKRxIG 0x7f00 ++#define bCCKLNAPolarity 0x800000 ++#define bCCKRx1stGain 0x7f0000 ++#define bCCKRFExtend 0x20000000 //CCK Rx Iinital gain polarity ++#define bCCKRxAGCSatLevel 0x1f000000 ++#define bCCKRxAGCSatCount 0xe0 ++#define bCCKRxRFSettle 0x1f //AGCsamp_dly ++#define bCCKFixedRxAGC 0x8000 ++//#define bCCKRxAGCFormat 0x4000 //remove to HSSI register 0x824 ++#define bCCKAntennaPolarity 0x2000 ++#define bCCKTxFilterType 0x0c00 ++#define bCCKRxAGCReportType 0x0300 ++#define bCCKRxDAGCEn 0x80000000 ++#define bCCKRxDAGCPeriod 0x20000000 ++#define bCCKRxDAGCSatLevel 0x1f000000 ++#define bCCKTimingRecovery 0x800000 ++#define bCCKTxC0 0x3f0000 ++#define bCCKTxC1 0x3f000000 ++#define bCCKTxC2 0x3f ++#define bCCKTxC3 0x3f00 ++#define bCCKTxC4 0x3f0000 ++#define bCCKTxC5 0x3f000000 ++#define bCCKTxC6 0x3f ++#define bCCKTxC7 0x3f00 ++#define bCCKDebugPort 0xff0000 ++#define bCCKDACDebug 0x0f000000 ++#define bCCKFalseAlarmEnable 0x8000 ++#define bCCKFalseAlarmRead 0x4000 ++#define bCCKTRSSI 0x7f ++#define bCCKRxAGCReport 0xfe ++#define bCCKRxReport_AntSel 0x80000000 ++#define bCCKRxReport_MFOff 0x40000000 ++#define bCCKRxRxReport_SQLoss 0x20000000 ++#define bCCKRxReport_Pktloss 0x10000000 ++#define bCCKRxReport_Lockedbit 0x08000000 ++#define bCCKRxReport_RateError 0x04000000 ++#define bCCKRxReport_RxRate 0x03000000 ++#define bCCKRxFACounterLower 0xff ++#define bCCKRxFACounterUpper 0xff000000 ++#define bCCKRxHPAGCStart 0xe000 ++#define bCCKRxHPAGCFinal 0x1c00 ++#define bCCKRxFalseAlarmEnable 0x8000 ++#define bCCKFACounterFreeze 0x4000 ++#define bCCKTxPathSel 0x10000000 ++#define bCCKDefaultRxPath 0xc000000 ++#define bCCKOptionRxPath 0x3000000 ++ ++// 5. PageC(0xC00) ++#define bNumOfSTF 0x3 // Useless ++#define bShift_L 0xc0 ++#define bGI_TH 0xc ++#define bRxPathA 0x1 ++#define bRxPathB 0x2 ++#define bRxPathC 0x4 ++#define bRxPathD 0x8 ++#define bTxPathA 0x1 ++#define bTxPathB 0x2 ++#define bTxPathC 0x4 ++#define bTxPathD 0x8 ++#define bTRSSIFreq 0x200 ++#define bADCBackoff 0x3000 ++#define bDFIRBackoff 0xc000 ++#define bTRSSILatchPhase 0x10000 ++#define bRxIDCOffset 0xff ++#define bRxQDCOffset 0xff00 ++#define bRxDFIRMode 0x1800000 ++#define bRxDCNFType 0xe000000 ++#define bRXIQImb_A 0x3ff ++#define bRXIQImb_B 0xfc00 ++#define bRXIQImb_C 0x3f0000 ++#define bRXIQImb_D 0xffc00000 ++#define bDC_dc_Notch 0x60000 ++#define bRxNBINotch 0x1f000000 ++#define bPD_TH 0xf ++#define bPD_TH_Opt2 0xc000 ++#define bPWED_TH 0x700 ++#define bIfMF_Win_L 0x800 ++#define bPD_Option 0x1000 ++#define bMF_Win_L 0xe000 ++#define bBW_Search_L 0x30000 ++#define bwin_enh_L 0xc0000 ++#define bBW_TH 0x700000 ++#define bED_TH2 0x3800000 ++#define bBW_option 0x4000000 ++#define bRatio_TH 0x18000000 ++#define bWindow_L 0xe0000000 ++#define bSBD_Option 0x1 ++#define bFrame_TH 0x1c ++#define bFS_Option 0x60 ++#define bDC_Slope_check 0x80 ++#define bFGuard_Counter_DC_L 0xe00 ++#define bFrame_Weight_Short 0x7000 ++#define bSub_Tune 0xe00000 ++#define bFrame_DC_Length 0xe000000 ++#define bSBD_start_offset 0x30000000 ++#define bFrame_TH_2 0x7 ++#define bFrame_GI2_TH 0x38 ++#define bGI2_Sync_en 0x40 ++#define bSarch_Short_Early 0x300 ++#define bSarch_Short_Late 0xc00 ++#define bSarch_GI2_Late 0x70000 ++#define bCFOAntSum 0x1 ++#define bCFOAcc 0x2 ++#define bCFOStartOffset 0xc ++#define bCFOLookBack 0x70 ++#define bCFOSumWeight 0x80 ++#define bDAGCEnable 0x10000 ++#define bTXIQImb_A 0x3ff ++#define bTXIQImb_B 0xfc00 ++#define bTXIQImb_C 0x3f0000 ++#define bTXIQImb_D 0xffc00000 ++#define bTxIDCOffset 0xff ++#define bTxQDCOffset 0xff00 ++#define bTxDFIRMode 0x10000 ++#define bTxPesudoNoiseOn 0x4000000 ++#define bTxPesudoNoise_A 0xff ++#define bTxPesudoNoise_B 0xff00 ++#define bTxPesudoNoise_C 0xff0000 ++#define bTxPesudoNoise_D 0xff000000 ++#define bCCADropOption 0x20000 ++#define bCCADropThres 0xfff00000 ++#define bEDCCA_H 0xf ++#define bEDCCA_L 0xf0 ++#define bLambda_ED 0x300 ++#define bRxInitialGain 0x7f ++#define bRxAntDivEn 0x80 ++#define bRxAGCAddressForLNA 0x7f00 ++#define bRxHighPowerFlow 0x8000 ++#define bRxAGCFreezeThres 0xc0000 ++#define bRxFreezeStep_AGC1 0x300000 ++#define bRxFreezeStep_AGC2 0xc00000 ++#define bRxFreezeStep_AGC3 0x3000000 ++#define bRxFreezeStep_AGC0 0xc000000 ++#define bRxRssi_Cmp_En 0x10000000 ++#define bRxQuickAGCEn 0x20000000 ++#define bRxAGCFreezeThresMode 0x40000000 ++#define bRxOverFlowCheckType 0x80000000 ++#define bRxAGCShift 0x7f ++#define bTRSW_Tri_Only 0x80 ++#define bPowerThres 0x300 ++#define bRxAGCEn 0x1 ++#define bRxAGCTogetherEn 0x2 ++#define bRxAGCMin 0x4 ++#define bRxHP_Ini 0x7 ++#define bRxHP_TRLNA 0x70 ++#define bRxHP_RSSI 0x700 ++#define bRxHP_BBP1 0x7000 ++#define bRxHP_BBP2 0x70000 ++#define bRxHP_BBP3 0x700000 ++#define bRSSI_H 0x7f0000 //the threshold for high power ++#define bRSSI_Gen 0x7f000000 //the threshold for ant diversity ++#define bRxSettle_TRSW 0x7 ++#define bRxSettle_LNA 0x38 ++#define bRxSettle_RSSI 0x1c0 ++#define bRxSettle_BBP 0xe00 ++#define bRxSettle_RxHP 0x7000 ++#define bRxSettle_AntSW_RSSI 0x38000 ++#define bRxSettle_AntSW 0xc0000 ++#define bRxProcessTime_DAGC 0x300000 ++#define bRxSettle_HSSI 0x400000 ++#define bRxProcessTime_BBPPW 0x800000 ++#define bRxAntennaPowerShift 0x3000000 ++#define bRSSITableSelect 0xc000000 ++#define bRxHP_Final 0x7000000 ++#define bRxHTSettle_BBP 0x7 ++#define bRxHTSettle_HSSI 0x8 ++#define bRxHTSettle_RxHP 0x70 ++#define bRxHTSettle_BBPPW 0x80 ++#define bRxHTSettle_Idle 0x300 ++#define bRxHTSettle_Reserved 0x1c00 ++#define bRxHTRxHPEn 0x8000 ++#define bRxHTAGCFreezeThres 0x30000 ++#define bRxHTAGCTogetherEn 0x40000 ++#define bRxHTAGCMin 0x80000 ++#define bRxHTAGCEn 0x100000 ++#define bRxHTDAGCEn 0x200000 ++#define bRxHTRxHP_BBP 0x1c00000 ++#define bRxHTRxHP_Final 0xe0000000 ++#define bRxPWRatioTH 0x3 ++#define bRxPWRatioEn 0x4 ++#define bRxMFHold 0x3800 ++#define bRxPD_Delay_TH1 0x38 ++#define bRxPD_Delay_TH2 0x1c0 ++#define bRxPD_DC_COUNT_MAX 0x600 ++//#define bRxMF_Hold 0x3800 ++#define bRxPD_Delay_TH 0x8000 ++#define bRxProcess_Delay 0xf0000 ++#define bRxSearchrange_GI2_Early 0x700000 ++#define bRxFrame_Guard_Counter_L 0x3800000 ++#define bRxSGI_Guard_L 0xc000000 ++#define bRxSGI_Search_L 0x30000000 ++#define bRxSGI_TH 0xc0000000 ++#define bDFSCnt0 0xff ++#define bDFSCnt1 0xff00 ++#define bDFSFlag 0xf0000 ++#define bMFWeightSum 0x300000 ++#define bMinIdxTH 0x7f000000 ++#define bDAFormat 0x40000 ++#define bTxChEmuEnable 0x01000000 ++#define bTRSWIsolation_A 0x7f ++#define bTRSWIsolation_B 0x7f00 ++#define bTRSWIsolation_C 0x7f0000 ++#define bTRSWIsolation_D 0x7f000000 ++#define bExtLNAGain 0x7c00 ++ ++// 6. PageE(0xE00) ++#define bSTBCEn 0x4 // Useless ++#define bAntennaMapping 0x10 ++#define bNss 0x20 ++#define bCFOAntSumD 0x200 ++#define bPHYCounterReset 0x8000000 ++#define bCFOReportGet 0x4000000 ++#define bOFDMContinueTx 0x10000000 ++#define bOFDMSingleCarrier 0x20000000 ++#define bOFDMSingleTone 0x40000000 ++//#define bRxPath1 0x01 ++//#define bRxPath2 0x02 ++//#define bRxPath3 0x04 ++//#define bRxPath4 0x08 ++//#define bTxPath1 0x10 ++//#define bTxPath2 0x20 ++#define bHTDetect 0x100 ++#define bCFOEn 0x10000 ++#define bCFOValue 0xfff00000 ++#define bSigTone_Re 0x3f ++#define bSigTone_Im 0x7f00 ++#define bCounter_CCA 0xffff ++#define bCounter_ParityFail 0xffff0000 ++#define bCounter_RateIllegal 0xffff ++#define bCounter_CRC8Fail 0xffff0000 ++#define bCounter_MCSNoSupport 0xffff ++#define bCounter_FastSync 0xffff ++#define bShortCFO 0xfff ++#define bShortCFOTLength 12 //total ++#define bShortCFOFLength 11 //fraction ++#define bLongCFO 0x7ff ++#define bLongCFOTLength 11 ++#define bLongCFOFLength 11 ++#define bTailCFO 0x1fff ++#define bTailCFOTLength 13 ++#define bTailCFOFLength 12 ++#define bmax_en_pwdB 0xffff ++#define bCC_power_dB 0xffff0000 ++#define bnoise_pwdB 0xffff ++#define bPowerMeasTLength 10 ++#define bPowerMeasFLength 3 ++#define bRx_HT_BW 0x1 ++#define bRxSC 0x6 ++#define bRx_HT 0x8 ++#define bNB_intf_det_on 0x1 ++#define bIntf_win_len_cfg 0x30 ++#define bNB_Intf_TH_cfg 0x1c0 ++#define bRFGain 0x3f ++#define bTableSel 0x40 ++#define bTRSW 0x80 ++#define bRxSNR_A 0xff ++#define bRxSNR_B 0xff00 ++#define bRxSNR_C 0xff0000 ++#define bRxSNR_D 0xff000000 ++#define bSNREVMTLength 8 ++#define bSNREVMFLength 1 ++#define bCSI1st 0xff ++#define bCSI2nd 0xff00 ++#define bRxEVM1st 0xff0000 ++#define bRxEVM2nd 0xff000000 ++#define bSIGEVM 0xff ++#define bPWDB 0xff00 ++#define bSGIEN 0x10000 ++ ++#define bSFactorQAM1 0xf // Useless ++#define bSFactorQAM2 0xf0 ++#define bSFactorQAM3 0xf00 ++#define bSFactorQAM4 0xf000 ++#define bSFactorQAM5 0xf0000 ++#define bSFactorQAM6 0xf0000 ++#define bSFactorQAM7 0xf00000 ++#define bSFactorQAM8 0xf000000 ++#define bSFactorQAM9 0xf0000000 ++#define bCSIScheme 0x100000 ++ ++#define bNoiseLvlTopSet 0x3 // Useless ++#define bChSmooth 0x4 ++#define bChSmoothCfg1 0x38 ++#define bChSmoothCfg2 0x1c0 ++#define bChSmoothCfg3 0xe00 ++#define bChSmoothCfg4 0x7000 ++#define bMRCMode 0x800000 ++#define bTHEVMCfg 0x7000000 ++ ++#define bLoopFitType 0x1 // Useless ++#define bUpdCFO 0x40 ++#define bUpdCFOOffData 0x80 ++#define bAdvUpdCFO 0x100 ++#define bAdvTimeCtrl 0x800 ++#define bUpdClko 0x1000 ++#define bFC 0x6000 ++#define bTrackingMode 0x8000 ++#define bPhCmpEnable 0x10000 ++#define bUpdClkoLTF 0x20000 ++#define bComChCFO 0x40000 ++#define bCSIEstiMode 0x80000 ++#define bAdvUpdEqz 0x100000 ++#define bUChCfg 0x7000000 ++#define bUpdEqz 0x8000000 ++ ++//Rx Pseduo noise ++#define bRxPesudoNoiseOn 0x20000000 // Useless ++#define bRxPesudoNoise_A 0xff ++#define bRxPesudoNoise_B 0xff00 ++#define bRxPesudoNoise_C 0xff0000 ++#define bRxPesudoNoise_D 0xff000000 ++#define bPesudoNoiseState_A 0xffff ++#define bPesudoNoiseState_B 0xffff0000 ++#define bPesudoNoiseState_C 0xffff ++#define bPesudoNoiseState_D 0xffff0000 ++ ++//7. RF Register ++//Zebra1 ++#define bZebra1_HSSIEnable 0x8 // Useless ++#define bZebra1_TRxControl 0xc00 ++#define bZebra1_TRxGainSetting 0x07f ++#define bZebra1_RxCorner 0xc00 ++#define bZebra1_TxChargePump 0x38 ++#define bZebra1_RxChargePump 0x7 ++#define bZebra1_ChannelNum 0xf80 ++#define bZebra1_TxLPFBW 0x400 ++#define bZebra1_RxLPFBW 0x600 ++ ++//Zebra4 ++#define bRTL8256RegModeCtrl1 0x100 // Useless ++#define bRTL8256RegModeCtrl0 0x40 ++#define bRTL8256_TxLPFBW 0x18 ++#define bRTL8256_RxLPFBW 0x600 ++ ++//RTL8258 ++#define bRTL8258_TxLPFBW 0xc // Useless ++#define bRTL8258_RxLPFBW 0xc00 ++#define bRTL8258_RSSILPFBW 0xc0 ++ ++ ++// ++// Other Definition ++// ++ ++//byte endable for sb_write ++#define bByte0 0x1 // Useless ++#define bByte1 0x2 ++#define bByte2 0x4 ++#define bByte3 0x8 ++#define bWord0 0x3 ++#define bWord1 0xc ++#define bDWord 0xf ++ ++//for PutRegsetting & GetRegSetting BitMask ++#define bMaskByte0 0xff // Reg 0xc50 rOFDM0_XAAGCCore~0xC6f ++#define bMaskByte1 0xff00 ++#define bMaskByte2 0xff0000 ++#define bMaskByte3 0xff000000 ++#define bMaskHWord 0xffff0000 ++#define bMaskLWord 0x0000ffff ++#define bMaskDWord 0xffffffff ++#define bMask12Bits 0xfff ++#define bMaskH4Bits 0xf0000000 ++#define bMaskOFDM_D 0xffc00000 ++#define bMaskCCK 0x3f3f3f3f ++ ++//for PutRFRegsetting & GetRFRegSetting BitMask ++//#define bMask12Bits 0xfffff // RF Reg mask bits ++//#define bMask20Bits 0xfffff // RF Reg mask bits T65 RF ++#define bRFRegOffsetMask 0xfffff ++ ++#define bEnable 0x1 // Useless ++#define bDisable 0x0 ++ ++#define LeftAntenna 0x0 // Useless ++#define RightAntenna 0x1 ++ ++#define tCheckTxStatus 500 //500ms // Useless ++#define tUpdateRxCounter 100 //100ms ++ ++#define rateCCK 0 // Useless ++#define rateOFDM 1 ++#define rateHT 2 ++ ++//define Register-End ++#define bPMAC_End 0x1ff // Useless ++#define bFPGAPHY0_End 0x8ff ++#define bFPGAPHY1_End 0x9ff ++#define bCCKPHY0_End 0xaff ++#define bOFDMPHY0_End 0xcff ++#define bOFDMPHY1_End 0xdff ++ ++//define max debug item in each debug page ++//#define bMaxItem_FPGA_PHY0 0x9 ++//#define bMaxItem_FPGA_PHY1 0x3 ++//#define bMaxItem_PHY_11B 0x16 ++//#define bMaxItem_OFDM_PHY0 0x29 ++//#define bMaxItem_OFDM_PHY1 0x0 ++ ++#define bPMACControl 0x0 // Useless ++#define bWMACControl 0x1 ++#define bWNICControl 0x2 ++ ++#define PathA 0x0 // Useless ++#define PathB 0x1 ++#define PathC 0x2 ++#define PathD 0x3 ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/Hal8188EPwrSeq.h b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8188EPwrSeq.h +new file mode 100644 +index 00000000..915da604 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8188EPwrSeq.h +@@ -0,0 +1,177 @@ ++ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#ifndef __HAL8188EPWRSEQ_H__ ++#define __HAL8188EPWRSEQ_H__ ++ ++#include "HalPwrSeqCmd.h" ++ ++/* ++ Check document WM-20110607-Paul-RTL8188E_Power_Architecture-R02.vsd ++ There are 6 HW Power States: ++ 0: POFF--Power Off ++ 1: PDN--Power Down ++ 2: CARDEMU--Card Emulation ++ 3: ACT--Active Mode ++ 4: LPS--Low Power State ++ 5: SUS--Suspend ++ ++ The transision from different states are defined below ++ TRANS_CARDEMU_TO_ACT ++ TRANS_ACT_TO_CARDEMU ++ TRANS_CARDEMU_TO_SUS ++ TRANS_SUS_TO_CARDEMU ++ TRANS_CARDEMU_TO_PDN ++ TRANS_ACT_TO_LPS ++ TRANS_LPS_TO_ACT ++ ++ TRANS_END ++ ++ PWR SEQ Version: rtl8188E_PwrSeq_V09.h ++*/ ++#define RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS 10 ++#define RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS 10 ++#define RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS 10 ++#define RTL8188E_TRANS_SUS_TO_CARDEMU_STEPS 10 ++#define RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS 10 ++#define RTL8188E_TRANS_PDN_TO_CARDEMU_STEPS 10 ++#define RTL8188E_TRANS_ACT_TO_LPS_STEPS 15 ++#define RTL8188E_TRANS_LPS_TO_ACT_STEPS 15 ++#define RTL8188E_TRANS_END_STEPS 1 ++ ++ ++#define RTL8188E_TRANS_CARDEMU_TO_ACT \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, BIT1, BIT1},/* wait till 0x04[17] = 1 power ready*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0|BIT1, 0}, /* 0x02[1:0] = 0 reset BB*/ \ ++ {0x0026, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, BIT7}, /*0x24[23] = 2b'01 schmit trigger */ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, 0}, /* 0x04[15] = 0 disable HWPDN (control by DRV)*/\ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4|BIT3, 0}, /*0x04[12:11] = 2b'00 disable WL suspend*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, BIT0}, /*0x04[8] = 1 polling until return 0*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, BIT0, 0}, /*wait till 0x04[8] = 0*/ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, 0}, /*LDO normal mode*/ \ ++ {0x0074, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, BIT4}, /*SDIO Driving*/ \ ++ ++#define RTL8188E_TRANS_ACT_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0},/*0x1F[7:0] = 0 turn off RF*/ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, BIT4}, /*LDO Sleep mode*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, BIT1}, /*0x04[9] = 1 turn off MAC by HW state machine*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, BIT1, 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/ \ ++ ++#define RTL8188E_TRANS_CARDEMU_TO_SUS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3|BIT4, BIT3}, /*0x04[12:11] = 2b'01enable WL suspend*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3|BIT4, BIT3|BIT4}, /*0x04[12:11] = 2b'11enable WL suspend for PCIe*/ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, BIT7}, /* 0x04[31:30] = 2b'10 enable enable bandgap mbias in suspend */ \ ++ {0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, 0}, /*Clear SIC_EN register 0x40[12] = 1'b0 */ \ ++ {0xfe10, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, BIT4}, /*Set USB suspend enable local register 0xfe10[4]=1 */ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/ ++ ++#define RTL8188E_TRANS_SUS_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3|BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/ ++ ++#define RTL8188E_TRANS_CARDEMU_TO_CARDDIS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0026, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, BIT7}, /*0x24[23] = 2b'01 schmit trigger */ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3|BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0}, /* 0x04[31:30] = 2b'10 enable enable bandgap mbias in suspend */ \ ++ {0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, 0}, /*Clear SIC_EN register 0x40[12] = 1'b0 */ \ ++ {0xfe10, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, BIT4}, /*Set USB suspend enable local register 0xfe10[4]=1 */ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/ ++ ++#define RTL8188E_TRANS_CARDDIS_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3|BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/ ++ ++#define RTL8188E_TRANS_CARDEMU_TO_PDN \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, 0},/* 0x04[16] = 0*/\ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, BIT7},/* 0x04[15] = 1*/ ++ ++#define RTL8188E_TRANS_PDN_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, 0},/* 0x04[15] = 0*/ ++ ++//This is used by driver for LPSRadioOff Procedure, not for FW LPS Step ++#define RTL8188E_TRANS_ACT_TO_LPS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x7F},/*Tx Pause*/ \ ++ {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled,and clock are gated*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ ++ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x3F},/*Reset MAC TRX*/ \ ++ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, 0},/*check if removed later*/ \ ++ {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT5, BIT5},/*Respond TxOK to scheduler*/ \ ++ ++ ++#define RTL8188E_TRANS_LPS_TO_ACT \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/\ ++ {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/\ ++ {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/\ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/\ ++ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, 0}, /*. 0x08[4] = 0 switch TSF to 40M*/\ ++ {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, BIT7, 0}, /*Polling 0x109[7]=0 TSF in 40M*/\ ++ {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT6|BIT7, 0}, /*. 0x29[7:6] = 2b'00 enable BB clock*/\ ++ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, BIT1}, /*. 0x101[1] = 1*/\ ++ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0xFF}, /*. 0x100[7:0] = 0xFF enable WMAC TRX*/\ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1|BIT0, BIT1|BIT0}, /*. 0x02[1:0] = 2b'11 enable BB macro*/\ ++ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0}, /*. 0x522 = 0*/ ++ ++#define RTL8188E_TRANS_END \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,0,PWR_CMD_END, 0, 0}, // ++ ++ ++extern WLAN_PWR_CFG rtl8188E_power_on_flow[RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS+RTL8188E_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8188E_radio_off_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8188E_card_disable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS+RTL8188E_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8188E_card_enable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS+RTL8188E_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8188E_suspend_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS+RTL8188E_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8188E_resume_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS+RTL8188E_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8188E_hwpdn_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS+RTL8188E_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8188E_enter_lps_flow[RTL8188E_TRANS_ACT_TO_LPS_STEPS+RTL8188E_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8188E_leave_lps_flow[RTL8188E_TRANS_LPS_TO_ACT_STEPS+RTL8188E_TRANS_END_STEPS]; ++ ++#endif //__HAL8188EPWRSEQ_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/Hal8192CPhyCfg.h b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8192CPhyCfg.h +new file mode 100644 +index 00000000..b27642c7 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8192CPhyCfg.h +@@ -0,0 +1,396 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++/***************************************************************************** ++ * Module: __INC_HAL8192CPHYCFG_H ++ * ++ * ++ * Note: ++ * ++ * ++ * Export: Constants, macro, functions(API), global variables(None). ++ * ++ * Abbrev: ++ * ++ * History: ++ * Data Who Remark ++ * 08/07/2007 MHC 1. Porting from 9x series PHYCFG.h. ++ * 2. Reorganize code architecture. ++ * ++ *****************************************************************************/ ++ /* Check to see if the file has been included already. */ ++#ifndef __INC_HAL8192CPHYCFG_H ++#define __INC_HAL8192CPHYCFG_H ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++#define LOOP_LIMIT 5 ++#define MAX_STALL_TIME 50 //us ++#define AntennaDiversityValue 0x80 //(Adapter->bSoftwareAntennaDiversity ? 0x00:0x80) ++#define MAX_TXPWR_IDX_NMODE_92S 63 ++#define Reset_Cnt_Limit 3 ++ ++ ++#ifdef CONFIG_PCI_HCI ++#define MAX_AGGR_NUM 0x0A0A ++#else ++#define MAX_AGGR_NUM 0x0909 ++#endif ++ ++#ifdef CONFIG_PCI_HCI ++#define SET_RTL8192SE_RF_SLEEP(_pAdapter) \ ++{ \ ++ u1Byte u1bTmp; \ ++ u1bTmp = PlatformEFIORead1Byte(_pAdapter, REG_LDOV12D_CTRL); \ ++ u1bTmp |= BIT0; \ ++ PlatformEFIOWrite1Byte(_pAdapter, REG_LDOV12D_CTRL, u1bTmp); \ ++ PlatformEFIOWrite1Byte(_pAdapter, REG_SPS_OCP_CFG, 0x0); \ ++ PlatformEFIOWrite1Byte(_pAdapter, TXPAUSE, 0xFF); \ ++ PlatformEFIOWrite2Byte(_pAdapter, CMDR, 0x57FC); \ ++ delay_us(100); \ ++ PlatformEFIOWrite2Byte(_pAdapter, CMDR, 0x77FC); \ ++ PlatformEFIOWrite1Byte(_pAdapter, PHY_CCA, 0x0); \ ++ delay_us(10); \ ++ PlatformEFIOWrite2Byte(_pAdapter, CMDR, 0x37FC); \ ++ delay_us(10); \ ++ PlatformEFIOWrite2Byte(_pAdapter, CMDR, 0x77FC); \ ++ delay_us(10); \ ++ PlatformEFIOWrite2Byte(_pAdapter, CMDR, 0x57FC); \ ++} ++#endif ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++ ++/*------------------------------Define structure----------------------------*/ ++typedef enum _SwChnlCmdID{ ++ CmdID_End, ++ CmdID_SetTxPowerLevel, ++ CmdID_BBRegWrite10, ++ CmdID_WritePortUlong, ++ CmdID_WritePortUshort, ++ CmdID_WritePortUchar, ++ CmdID_RF_WriteReg, ++}SwChnlCmdID; ++ ++ ++/* 1. Switch channel related */ ++typedef struct _SwChnlCmd{ ++ SwChnlCmdID CmdID; ++ u32 Para1; ++ u32 Para2; ++ u32 msDelay; ++}SwChnlCmd; ++ ++typedef enum _HW90_BLOCK{ ++ HW90_BLOCK_MAC = 0, ++ HW90_BLOCK_PHY0 = 1, ++ HW90_BLOCK_PHY1 = 2, ++ HW90_BLOCK_RF = 3, ++ HW90_BLOCK_MAXIMUM = 4, // Never use this ++}HW90_BLOCK_E, *PHW90_BLOCK_E; ++ ++typedef enum _RF_RADIO_PATH{ ++ RF_PATH_A = 0, //Radio Path A ++ RF_PATH_B = 1, //Radio Path B ++ RF_PATH_C = 2, //Radio Path C ++ RF_PATH_D = 3, //Radio Path D ++ //RF_PATH_MAX //Max RF number 90 support ++}RF_RADIO_PATH_E, *PRF_RADIO_PATH_E; ++ ++#define RF_PATH_MAX 2 ++ ++#define CHANNEL_MAX_NUMBER 14 // 14 is the max channel number ++#define CHANNEL_GROUP_MAX 3 // ch1~3, ch4~9, ch10~14 total three groups ++ ++typedef enum _WIRELESS_MODE { ++ WIRELESS_MODE_UNKNOWN = 0x00, ++ WIRELESS_MODE_A = BIT2, ++ WIRELESS_MODE_B = BIT0, ++ WIRELESS_MODE_G = BIT1, ++ WIRELESS_MODE_AUTO = BIT5, ++ WIRELESS_MODE_N_24G = BIT3, ++ WIRELESS_MODE_N_5G = BIT4, ++ WIRELESS_MODE_AC = BIT6 ++} WIRELESS_MODE; ++ ++typedef enum _BaseBand_Config_Type{ ++ BaseBand_Config_PHY_REG = 0, //Radio Path A ++ BaseBand_Config_AGC_TAB = 1, //Radio Path B ++}BaseBand_Config_Type, *PBaseBand_Config_Type; ++ ++ ++typedef enum _PHY_Rate_Tx_Power_Offset_Area{ ++ RA_OFFSET_LEGACY_OFDM1, ++ RA_OFFSET_LEGACY_OFDM2, ++ RA_OFFSET_HT_OFDM1, ++ RA_OFFSET_HT_OFDM2, ++ RA_OFFSET_HT_OFDM3, ++ RA_OFFSET_HT_OFDM4, ++ RA_OFFSET_HT_CCK, ++}RA_OFFSET_AREA,*PRA_OFFSET_AREA; ++ ++ ++/* BB/RF related */ ++typedef enum _RF_TYPE_8190P{ ++ RF_TYPE_MIN, // 0 ++ RF_8225=1, // 1 11b/g RF for verification only ++ RF_8256=2, // 2 11b/g/n ++ RF_8258=3, // 3 11a/b/g/n RF ++ RF_6052=4, // 4 11b/g/n RF ++ //RF_6052=5, // 4 11b/g/n RF ++ // TODO: We sholud remove this psudo PHY RF after we get new RF. ++ RF_PSEUDO_11N=5, // 5, It is a temporality RF. ++}RF_TYPE_8190P_E,*PRF_TYPE_8190P_E; ++ ++ ++typedef struct _BB_REGISTER_DEFINITION{ ++ u32 rfintfs; // set software control: ++ // 0x870~0x877[8 bytes] ++ ++ u32 rfintfi; // readback data: ++ // 0x8e0~0x8e7[8 bytes] ++ ++ u32 rfintfo; // output data: ++ // 0x860~0x86f [16 bytes] ++ ++ u32 rfintfe; // output enable: ++ // 0x860~0x86f [16 bytes] ++ ++ u32 rf3wireOffset; // LSSI data: ++ // 0x840~0x84f [16 bytes] ++ ++ u32 rfLSSI_Select; // BB Band Select: ++ // 0x878~0x87f [8 bytes] ++ ++ u32 rfTxGainStage; // Tx gain stage: ++ // 0x80c~0x80f [4 bytes] ++ ++ u32 rfHSSIPara1; // wire parameter control1 : ++ // 0x820~0x823,0x828~0x82b, 0x830~0x833, 0x838~0x83b [16 bytes] ++ ++ u32 rfHSSIPara2; // wire parameter control2 : ++ // 0x824~0x827,0x82c~0x82f, 0x834~0x837, 0x83c~0x83f [16 bytes] ++ ++ u32 rfSwitchControl; //Tx Rx antenna control : ++ // 0x858~0x85f [16 bytes] ++ ++ u32 rfAGCControl1; //AGC parameter control1 : ++ // 0xc50~0xc53,0xc58~0xc5b, 0xc60~0xc63, 0xc68~0xc6b [16 bytes] ++ ++ u32 rfAGCControl2; //AGC parameter control2 : ++ // 0xc54~0xc57,0xc5c~0xc5f, 0xc64~0xc67, 0xc6c~0xc6f [16 bytes] ++ ++ u32 rfRxIQImbalance; //OFDM Rx IQ imbalance matrix : ++ // 0xc14~0xc17,0xc1c~0xc1f, 0xc24~0xc27, 0xc2c~0xc2f [16 bytes] ++ ++ u32 rfRxAFE; //Rx IQ DC ofset and Rx digital filter, Rx DC notch filter : ++ // 0xc10~0xc13,0xc18~0xc1b, 0xc20~0xc23, 0xc28~0xc2b [16 bytes] ++ ++ u32 rfTxIQImbalance; //OFDM Tx IQ imbalance matrix ++ // 0xc80~0xc83,0xc88~0xc8b, 0xc90~0xc93, 0xc98~0xc9b [16 bytes] ++ ++ u32 rfTxAFE; //Tx IQ DC Offset and Tx DFIR type ++ // 0xc84~0xc87,0xc8c~0xc8f, 0xc94~0xc97, 0xc9c~0xc9f [16 bytes] ++ ++ u32 rfLSSIReadBack; //LSSI RF readback data SI mode ++ // 0x8a0~0x8af [16 bytes] ++ ++ u32 rfLSSIReadBackPi; //LSSI RF readback data PI mode 0x8b8-8bc for Path A and B ++ ++}BB_REGISTER_DEFINITION_T, *PBB_REGISTER_DEFINITION_T; ++ ++typedef struct _R_ANTENNA_SELECT_OFDM{ ++ u32 r_tx_antenna:4; ++ u32 r_ant_l:4; ++ u32 r_ant_non_ht:4; ++ u32 r_ant_ht1:4; ++ u32 r_ant_ht2:4; ++ u32 r_ant_ht_s1:4; ++ u32 r_ant_non_ht_s1:4; ++ u32 OFDM_TXSC:2; ++ u32 Reserved:2; ++}R_ANTENNA_SELECT_OFDM; ++ ++typedef struct _R_ANTENNA_SELECT_CCK{ ++ u8 r_cckrx_enable_2:2; ++ u8 r_cckrx_enable:2; ++ u8 r_ccktx_enable:4; ++}R_ANTENNA_SELECT_CCK; ++ ++/*------------------------------Define structure----------------------------*/ ++ ++ ++/*------------------------Export global variable----------------------------*/ ++/*------------------------Export global variable----------------------------*/ ++ ++ ++/*------------------------Export Marco Definition---------------------------*/ ++/*------------------------Export Marco Definition---------------------------*/ ++ ++ ++/*--------------------------Exported Function prototype---------------------*/ ++// ++// BB and RF register read/write ++// ++u32 rtl8192c_PHY_QueryBBReg( IN PADAPTER Adapter, ++ IN u32 RegAddr, ++ IN u32 BitMask ); ++void rtl8192c_PHY_SetBBReg( IN PADAPTER Adapter, ++ IN u32 RegAddr, ++ IN u32 BitMask, ++ IN u32 Data ); ++u32 rtl8192c_PHY_QueryRFReg( IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath, ++ IN u32 RegAddr, ++ IN u32 BitMask ); ++void rtl8192c_PHY_SetRFReg( IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath, ++ IN u32 RegAddr, ++ IN u32 BitMask, ++ IN u32 Data ); ++ ++// ++// Initialization related function ++// ++/* MAC/BB/RF HAL config */ ++int PHY_MACConfig8192C( IN PADAPTER Adapter ); ++int PHY_BBConfig8192C( IN PADAPTER Adapter ); ++int PHY_RFConfig8192C( IN PADAPTER Adapter ); ++/* RF config */ ++int rtl8192c_PHY_ConfigRFWithParaFile( IN PADAPTER Adapter, ++ IN u8* pFileName, ++ IN RF_RADIO_PATH_E eRFPath); ++int rtl8192c_PHY_ConfigRFWithHeaderFile( IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath); ++ ++/* BB/RF readback check for making sure init OK */ ++int rtl8192c_PHY_CheckBBAndRFOK( IN PADAPTER Adapter, ++ IN HW90_BLOCK_E CheckBlock, ++ IN RF_RADIO_PATH_E eRFPath ); ++/* Read initi reg value for tx power setting. */ ++void rtl8192c_PHY_GetHWRegOriginalValue( IN PADAPTER Adapter ); ++ ++// ++// RF Power setting ++// ++//extern BOOLEAN PHY_SetRFPowerState(IN PADAPTER Adapter, ++// IN RT_RF_POWER_STATE eRFPowerState); ++ ++// ++// BB TX Power R/W ++// ++void PHY_GetTxPowerLevel8192C( IN PADAPTER Adapter, ++ OUT u32* powerlevel ); ++void PHY_SetTxPowerLevel8192C( IN PADAPTER Adapter, ++ IN u8 channel ); ++BOOLEAN PHY_UpdateTxPowerDbm8192C( IN PADAPTER Adapter, ++ IN int powerInDbm ); ++ ++// ++VOID ++PHY_ScanOperationBackup8192C(IN PADAPTER Adapter, ++ IN u8 Operation ); ++ ++// ++// Switch bandwidth for 8192S ++// ++//extern void PHY_SetBWModeCallback8192C( IN PRT_TIMER pTimer ); ++void PHY_SetBWMode8192C( IN PADAPTER pAdapter, ++ IN HT_CHANNEL_WIDTH ChnlWidth, ++ IN unsigned char Offset ); ++ ++// ++// Set FW CMD IO for 8192S. ++// ++//extern BOOLEAN HalSetIO8192C( IN PADAPTER Adapter, ++// IN IO_TYPE IOType); ++ ++// ++// Set A2 entry to fw for 8192S ++// ++extern void FillA2Entry8192C( IN PADAPTER Adapter, ++ IN u8 index, ++ IN u8* val); ++ ++ ++// ++// channel switch related funciton ++// ++//extern void PHY_SwChnlCallback8192C( IN PRT_TIMER pTimer ); ++void PHY_SwChnl8192C( IN PADAPTER pAdapter, ++ IN u8 channel ); ++ // Call after initialization ++void PHY_SwChnlPhy8192C( IN PADAPTER pAdapter, ++ IN u8 channel ); ++ ++void ChkFwCmdIoDone( IN PADAPTER Adapter); ++ ++// ++// BB/MAC/RF other monitor API ++// ++void PHY_SetMonitorMode8192C(IN PADAPTER pAdapter, ++ IN BOOLEAN bEnableMonitorMode ); ++ ++BOOLEAN PHY_CheckIsLegalRfPath8192C(IN PADAPTER pAdapter, ++ IN u32 eRFPath ); ++ ++ ++VOID rtl8192c_PHY_SetRFPathSwitch(IN PADAPTER pAdapter, IN BOOLEAN bMain); ++ ++// ++// Modify the value of the hw register when beacon interval be changed. ++// ++void ++rtl8192c_PHY_SetBeaconHwReg( IN PADAPTER Adapter, ++ IN u16 BeaconInterval ); ++ ++ ++extern VOID ++PHY_SwitchEphyParameter( ++ IN PADAPTER Adapter ++ ); ++ ++extern VOID ++PHY_EnableHostClkReq( ++ IN PADAPTER Adapter ++ ); ++ ++BOOLEAN ++SetAntennaConfig92C( ++ IN PADAPTER Adapter, ++ IN u8 DefaultAnt ++ ); ++ ++#ifdef RTL8192C_RECONFIG_TO_1T1R ++extern void PHY_Reconfig_To_1T1R(_adapter *padapter); ++#endif ++/*--------------------------Exported Function prototype---------------------*/ ++ ++#define PHY_QueryBBReg(Adapter, RegAddr, BitMask) rtl8192c_PHY_QueryBBReg((Adapter), (RegAddr), (BitMask)) ++#define PHY_SetBBReg(Adapter, RegAddr, BitMask, Data) rtl8192c_PHY_SetBBReg((Adapter), (RegAddr), (BitMask), (Data)) ++#define PHY_QueryRFReg(Adapter, eRFPath, RegAddr, BitMask) rtl8192c_PHY_QueryRFReg((Adapter), (eRFPath), (RegAddr), (BitMask)) ++#define PHY_SetRFReg(Adapter, eRFPath, RegAddr, BitMask, Data) rtl8192c_PHY_SetRFReg((Adapter), (eRFPath), (RegAddr), (BitMask), (Data)) ++ ++#define PHY_SetMacReg PHY_SetBBReg ++#define PHY_QueryMacReg PHY_QueryBBReg ++ ++#endif // __INC_HAL8192CPHYCFG_H ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/Hal8192CPhyReg.h b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8192CPhyReg.h +new file mode 100644 +index 00000000..49029956 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8192CPhyReg.h +@@ -0,0 +1,1123 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++/***************************************************************************** ++ * ++ * Module: __INC_HAL8192CPHYREG_H ++ * ++ * ++ * Note: 1. Define PMAC/BB register map ++ * 2. Define RF register map ++ * 3. PMAC/BB register bit mask. ++ * 4. RF reg bit mask. ++ * 5. Other BB/RF relative definition. ++ * ++ * ++ * Export: Constants, macro, functions(API), global variables(None). ++ * ++ * Abbrev: ++ * ++ * History: ++ * Data Who Remark ++ * 08/07/2007 MHC 1. Porting from 9x series PHYCFG.h. ++ * 2. Reorganize code architecture. ++ * 09/25/2008 MH 1. Add RL6052 register definition ++ * ++ *****************************************************************************/ ++#ifndef __INC_HAL8192CPHYREG_H ++#define __INC_HAL8192CPHYREG_H ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++//============================================================ ++// 8192S Regsiter offset definition ++//============================================================ ++ ++// ++// BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF ++// 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF ++// 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 ++// 3. RF register 0x00-2E ++// 4. Bit Mask for BB/RF register ++// 5. Other defintion for BB/RF R/W ++// ++ ++ ++// ++// 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF ++// 1. Page1(0x100) ++// ++#define rPMAC_Reset 0x100 ++#define rPMAC_TxStart 0x104 ++#define rPMAC_TxLegacySIG 0x108 ++#define rPMAC_TxHTSIG1 0x10c ++#define rPMAC_TxHTSIG2 0x110 ++#define rPMAC_PHYDebug 0x114 ++#define rPMAC_TxPacketNum 0x118 ++#define rPMAC_TxIdle 0x11c ++#define rPMAC_TxMACHeader0 0x120 ++#define rPMAC_TxMACHeader1 0x124 ++#define rPMAC_TxMACHeader2 0x128 ++#define rPMAC_TxMACHeader3 0x12c ++#define rPMAC_TxMACHeader4 0x130 ++#define rPMAC_TxMACHeader5 0x134 ++#define rPMAC_TxDataType 0x138 ++#define rPMAC_TxRandomSeed 0x13c ++#define rPMAC_CCKPLCPPreamble 0x140 ++#define rPMAC_CCKPLCPHeader 0x144 ++#define rPMAC_CCKCRC16 0x148 ++#define rPMAC_OFDMRxCRC32OK 0x170 ++#define rPMAC_OFDMRxCRC32Er 0x174 ++#define rPMAC_OFDMRxParityEr 0x178 ++#define rPMAC_OFDMRxCRC8Er 0x17c ++#define rPMAC_CCKCRxRC16Er 0x180 ++#define rPMAC_CCKCRxRC32Er 0x184 ++#define rPMAC_CCKCRxRC32OK 0x188 ++#define rPMAC_TxStatus 0x18c ++ ++// ++// 2. Page2(0x200) ++// ++// The following two definition are only used for USB interface. ++#define RF_BB_CMD_ADDR 0x02c0 // RF/BB read/write command address. ++#define RF_BB_CMD_DATA 0x02c4 // RF/BB read/write command data. ++ ++// ++// 3. Page8(0x800) ++// ++#define rFPGA0_RFMOD 0x800 //RF mode & CCK TxSC // RF BW Setting?? ++ ++#define rFPGA0_TxInfo 0x804 // Status report?? ++#define rFPGA0_PSDFunction 0x808 ++ ++#define rFPGA0_TxGainStage 0x80c // Set TX PWR init gain? ++ ++#define rFPGA0_RFTiming1 0x810 // Useless now ++#define rFPGA0_RFTiming2 0x814 ++ ++#define rFPGA0_XA_HSSIParameter1 0x820 // RF 3 wire register ++#define rFPGA0_XA_HSSIParameter2 0x824 ++#define rFPGA0_XB_HSSIParameter1 0x828 ++#define rFPGA0_XB_HSSIParameter2 0x82c ++#define rTxAGC_B_Rate18_06 0x830 ++#define rTxAGC_B_Rate54_24 0x834 ++#define rTxAGC_B_CCK1_55_Mcs32 0x838 ++#define rTxAGC_B_Mcs03_Mcs00 0x83c ++ ++#define rTxAGC_B_Mcs07_Mcs04 0x848 ++#define rTxAGC_B_Mcs11_Mcs08 0x84c ++ ++#define rFPGA0_XA_LSSIParameter 0x840 ++#define rFPGA0_XB_LSSIParameter 0x844 ++ ++#define rFPGA0_RFWakeUpParameter 0x850 // Useless now ++#define rFPGA0_RFSleepUpParameter 0x854 ++ ++#define rFPGA0_XAB_SwitchControl 0x858 // RF Channel switch ++#define rFPGA0_XCD_SwitchControl 0x85c ++ ++#define rFPGA0_XA_RFInterfaceOE 0x860 // RF Channel switch ++#define rFPGA0_XB_RFInterfaceOE 0x864 ++ ++#define rTxAGC_B_Mcs15_Mcs12 0x868 ++#define rTxAGC_B_CCK11_A_CCK2_11 0x86c ++ ++#define rFPGA0_XAB_RFInterfaceSW 0x870 // RF Interface Software Control ++#define rFPGA0_XCD_RFInterfaceSW 0x874 ++ ++#define rFPGA0_XAB_RFParameter 0x878 // RF Parameter ++#define rFPGA0_XCD_RFParameter 0x87c ++ ++#define rFPGA0_AnalogParameter1 0x880 // Crystal cap setting RF-R/W protection for parameter4?? ++#define rFPGA0_AnalogParameter2 0x884 ++#define rFPGA0_AnalogParameter3 0x888 // Useless now ++#define rFPGA0_AnalogParameter4 0x88c ++ ++#define rFPGA0_XA_LSSIReadBack 0x8a0 // Tranceiver LSSI Readback ++#define rFPGA0_XB_LSSIReadBack 0x8a4 ++#define rFPGA0_XC_LSSIReadBack 0x8a8 ++#define rFPGA0_XD_LSSIReadBack 0x8ac ++ ++#define rFPGA0_PSDReport 0x8b4 // Useless now ++#define TransceiverA_HSPI_Readback 0x8b8 // Transceiver A HSPI Readback ++#define TransceiverB_HSPI_Readback 0x8bc // Transceiver B HSPI Readback ++#define rFPGA0_XAB_RFInterfaceRB 0x8e0 // Useless now // RF Interface Readback Value ++#define rFPGA0_XCD_RFInterfaceRB 0x8e4 // Useless now ++ ++// ++// 4. Page9(0x900) ++// ++#define rFPGA1_RFMOD 0x900 //RF mode & OFDM TxSC // RF BW Setting?? ++ ++#define rFPGA1_TxBlock 0x904 // Useless now ++#define rFPGA1_DebugSelect 0x908 // Useless now ++#define rFPGA1_TxInfo 0x90c // Useless now // Status report?? ++ ++// ++// 5. PageA(0xA00) ++// ++// Set Control channel to upper or lower. These settings are required only for 40MHz ++#define rCCK0_System 0xa00 ++ ++#define rCCK0_AFESetting 0xa04 // Disable init gain now // Select RX path by RSSI ++#define rCCK0_CCA 0xa08 // Disable init gain now // Init gain ++ ++#define rCCK0_RxAGC1 0xa0c //AGC default value, saturation level // Antenna Diversity, RX AGC, LNA Threshold, RX LNA Threshold useless now. Not the same as 90 series ++#define rCCK0_RxAGC2 0xa10 //AGC & DAGC ++ ++#define rCCK0_RxHP 0xa14 ++ ++#define rCCK0_DSPParameter1 0xa18 //Timing recovery & Channel estimation threshold ++#define rCCK0_DSPParameter2 0xa1c //SQ threshold ++ ++#define rCCK0_TxFilter1 0xa20 ++#define rCCK0_TxFilter2 0xa24 ++#define rCCK0_DebugPort 0xa28 //debug port and Tx filter3 ++#define rCCK0_FalseAlarmReport 0xa2c //0xa2d useless now 0xa30-a4f channel report ++#define rCCK0_TRSSIReport 0xa50 ++#define rCCK0_RxReport 0xa54 //0xa57 ++#define rCCK0_FACounterLower 0xa5c //0xa5b ++#define rCCK0_FACounterUpper 0xa58 //0xa5c ++// ++// PageB(0xB00) ++// ++#define rPdp_AntA 0xb00 ++#define rPdp_AntA_4 0xb04 ++#define rConfig_Pmpd_AntA 0xb28 ++#define rConfig_AntA 0xb68 ++#define rConfig_AntB 0xb6c ++#define rPdp_AntB 0xb70 ++#define rPdp_AntB_4 0xb74 ++#define rConfig_Pmpd_AntB 0xb98 ++#define rAPK 0xbd8 ++ ++// ++// 6. PageC(0xC00) ++// ++#define rOFDM0_LSTF 0xc00 ++ ++#define rOFDM0_TRxPathEnable 0xc04 ++#define rOFDM0_TRMuxPar 0xc08 ++#define rOFDM0_TRSWIsolation 0xc0c ++ ++#define rOFDM0_XARxAFE 0xc10 //RxIQ DC offset, Rx digital filter, DC notch filter ++#define rOFDM0_XARxIQImbalance 0xc14 //RxIQ imblance matrix ++#define rOFDM0_XBRxAFE 0xc18 ++#define rOFDM0_XBRxIQImbalance 0xc1c ++#define rOFDM0_XCRxAFE 0xc20 ++#define rOFDM0_XCRxIQImbalance 0xc24 ++#define rOFDM0_XDRxAFE 0xc28 ++#define rOFDM0_XDRxIQImbalance 0xc2c ++ ++#define rOFDM0_RxDetector1 0xc30 //PD,BW & SBD // DM tune init gain ++#define rOFDM0_RxDetector2 0xc34 //SBD & Fame Sync. ++#define rOFDM0_RxDetector3 0xc38 //Frame Sync. ++#define rOFDM0_RxDetector4 0xc3c //PD, SBD, Frame Sync & Short-GI ++ ++#define rOFDM0_RxDSP 0xc40 //Rx Sync Path ++#define rOFDM0_CFOandDAGC 0xc44 //CFO & DAGC ++#define rOFDM0_CCADropThreshold 0xc48 //CCA Drop threshold ++#define rOFDM0_ECCAThreshold 0xc4c // energy CCA ++ ++#define rOFDM0_XAAGCCore1 0xc50 // DIG ++#define rOFDM0_XAAGCCore2 0xc54 ++#define rOFDM0_XBAGCCore1 0xc58 ++#define rOFDM0_XBAGCCore2 0xc5c ++#define rOFDM0_XCAGCCore1 0xc60 ++#define rOFDM0_XCAGCCore2 0xc64 ++#define rOFDM0_XDAGCCore1 0xc68 ++#define rOFDM0_XDAGCCore2 0xc6c ++ ++#define rOFDM0_AGCParameter1 0xc70 ++#define rOFDM0_AGCParameter2 0xc74 ++#define rOFDM0_AGCRSSITable 0xc78 ++#define rOFDM0_HTSTFAGC 0xc7c ++ ++#define rOFDM0_XATxIQImbalance 0xc80 // TX PWR TRACK and DIG ++#define rOFDM0_XATxAFE 0xc84 ++#define rOFDM0_XBTxIQImbalance 0xc88 ++#define rOFDM0_XBTxAFE 0xc8c ++#define rOFDM0_XCTxIQImbalance 0xc90 ++#define rOFDM0_XCTxAFE 0xc94 ++#define rOFDM0_XDTxIQImbalance 0xc98 ++#define rOFDM0_XDTxAFE 0xc9c ++ ++#define rOFDM0_RxIQExtAnta 0xca0 ++#define rOFDM0_TxCoeff1 0xca4 ++#define rOFDM0_TxCoeff2 0xca8 ++#define rOFDM0_TxCoeff3 0xcac ++#define rOFDM0_TxCoeff4 0xcb0 ++#define rOFDM0_TxCoeff5 0xcb4 ++#define rOFDM0_TxCoeff6 0xcb8 ++#define rOFDM0_RxHPParameter 0xce0 ++#define rOFDM0_TxPseudoNoiseWgt 0xce4 ++#define rOFDM0_FrameSync 0xcf0 ++#define rOFDM0_DFSReport 0xcf4 ++ ++// ++// 7. PageD(0xD00) ++// ++#define rOFDM1_LSTF 0xd00 ++#define rOFDM1_TRxPathEnable 0xd04 ++ ++#define rOFDM1_CFO 0xd08 // No setting now ++#define rOFDM1_CSI1 0xd10 ++#define rOFDM1_SBD 0xd14 ++#define rOFDM1_CSI2 0xd18 ++#define rOFDM1_CFOTracking 0xd2c ++#define rOFDM1_TRxMesaure1 0xd34 ++#define rOFDM1_IntfDet 0xd3c ++#define rOFDM1_PseudoNoiseStateAB 0xd50 ++#define rOFDM1_PseudoNoiseStateCD 0xd54 ++#define rOFDM1_RxPseudoNoiseWgt 0xd58 ++ ++#define rOFDM_PHYCounter1 0xda0 //cca, parity fail ++#define rOFDM_PHYCounter2 0xda4 //rate illegal, crc8 fail ++#define rOFDM_PHYCounter3 0xda8 //MCS not support ++ ++#define rOFDM_ShortCFOAB 0xdac // No setting now ++#define rOFDM_ShortCFOCD 0xdb0 ++#define rOFDM_LongCFOAB 0xdb4 ++#define rOFDM_LongCFOCD 0xdb8 ++#define rOFDM_TailCFOAB 0xdbc ++#define rOFDM_TailCFOCD 0xdc0 ++#define rOFDM_PWMeasure1 0xdc4 ++#define rOFDM_PWMeasure2 0xdc8 ++#define rOFDM_BWReport 0xdcc ++#define rOFDM_AGCReport 0xdd0 ++#define rOFDM_RxSNR 0xdd4 ++#define rOFDM_RxEVMCSI 0xdd8 ++#define rOFDM_SIGReport 0xddc ++ ++ ++// ++// 8. PageE(0xE00) ++// ++#define rTxAGC_A_Rate18_06 0xe00 ++#define rTxAGC_A_Rate54_24 0xe04 ++#define rTxAGC_A_CCK1_Mcs32 0xe08 ++#define rTxAGC_A_Mcs03_Mcs00 0xe10 ++#define rTxAGC_A_Mcs07_Mcs04 0xe14 ++#define rTxAGC_A_Mcs11_Mcs08 0xe18 ++#define rTxAGC_A_Mcs15_Mcs12 0xe1c ++ ++#define rFPGA0_IQK 0xe28 ++#define rTx_IQK_Tone_A 0xe30 ++#define rRx_IQK_Tone_A 0xe34 ++#define rTx_IQK_PI_A 0xe38 ++#define rRx_IQK_PI_A 0xe3c ++ ++#define rTx_IQK 0xe40 ++#define rRx_IQK 0xe44 ++#define rIQK_AGC_Pts 0xe48 ++#define rIQK_AGC_Rsp 0xe4c ++#define rTx_IQK_Tone_B 0xe50 ++#define rRx_IQK_Tone_B 0xe54 ++#define rTx_IQK_PI_B 0xe58 ++#define rRx_IQK_PI_B 0xe5c ++#define rIQK_AGC_Cont 0xe60 ++ ++#define rBlue_Tooth 0xe6c ++#define rRx_Wait_CCA 0xe70 ++#define rTx_CCK_RFON 0xe74 ++#define rTx_CCK_BBON 0xe78 ++#define rTx_OFDM_RFON 0xe7c ++#define rTx_OFDM_BBON 0xe80 ++#define rTx_To_Rx 0xe84 ++#define rTx_To_Tx 0xe88 ++#define rRx_CCK 0xe8c ++ ++#define rTx_Power_Before_IQK_A 0xe94 ++#define rTx_Power_After_IQK_A 0xe9c ++ ++#define rRx_Power_Before_IQK_A 0xea0 ++#define rRx_Power_Before_IQK_A_2 0xea4 ++#define rRx_Power_After_IQK_A 0xea8 ++#define rRx_Power_After_IQK_A_2 0xeac ++ ++#define rTx_Power_Before_IQK_B 0xeb4 ++#define rTx_Power_After_IQK_B 0xebc ++ ++#define rRx_Power_Before_IQK_B 0xec0 ++#define rRx_Power_Before_IQK_B_2 0xec4 ++#define rRx_Power_After_IQK_B 0xec8 ++#define rRx_Power_After_IQK_B_2 0xecc ++ ++#define rRx_OFDM 0xed0 ++#define rRx_Wait_RIFS 0xed4 ++#define rRx_TO_Rx 0xed8 ++#define rStandby 0xedc ++#define rSleep 0xee0 ++#define rPMPD_ANAEN 0xeec ++ ++// ++// 7. RF Register 0x00-0x2E (RF 8256) ++// RF-0222D 0x00-3F ++// ++//Zebra1 ++#define rZebra1_HSSIEnable 0x0 // Useless now ++#define rZebra1_TRxEnable1 0x1 ++#define rZebra1_TRxEnable2 0x2 ++#define rZebra1_AGC 0x4 ++#define rZebra1_ChargePump 0x5 ++#define rZebra1_Channel 0x7 // RF channel switch ++ ++//#endif ++#define rZebra1_TxGain 0x8 // Useless now ++#define rZebra1_TxLPF 0x9 ++#define rZebra1_RxLPF 0xb ++#define rZebra1_RxHPFCorner 0xc ++ ++//Zebra4 ++#define rGlobalCtrl 0 // Useless now ++#define rRTL8256_TxLPF 19 ++#define rRTL8256_RxLPF 11 ++ ++//RTL8258 ++#define rRTL8258_TxLPF 0x11 // Useless now ++#define rRTL8258_RxLPF 0x13 ++#define rRTL8258_RSSILPF 0xa ++ ++// ++// RL6052 Register definition ++// ++#define RF_AC 0x00 // ++ ++#define RF_IQADJ_G1 0x01 // ++#define RF_IQADJ_G2 0x02 // ++#define RF_BS_PA_APSET_G1_G4 0x03 ++#define RF_BS_PA_APSET_G5_G8 0x04 ++#define RF_POW_TRSW 0x05 // ++ ++#define RF_GAIN_RX 0x06 // ++#define RF_GAIN_TX 0x07 // ++ ++#define RF_TXM_IDAC 0x08 // ++#define RF_IPA_G 0x09 // ++#define RF_TXBIAS_G 0x0A ++#define RF_TXPA_AG 0x0B ++#define RF_IPA_A 0x0C // ++#define RF_TXBIAS_A 0x0D ++#define RF_BS_PA_APSET_G9_G11 0x0E ++#define RF_BS_IQGEN 0x0F // ++ ++#define RF_MODE1 0x10 // ++#define RF_MODE2 0x11 // ++ ++#define RF_RX_AGC_HP 0x12 // ++#define RF_TX_AGC 0x13 // ++#define RF_BIAS 0x14 // ++#define RF_IPA 0x15 // ++#define RF_TXBIAS 0x16 // ++#define RF_POW_ABILITY 0x17 // ++#define RF_MODE_AG 0x18 // ++#define rRfChannel 0x18 // RF channel and BW switch ++#define RF_CHNLBW 0x18 // RF channel and BW switch ++#define RF_TOP 0x19 // ++ ++#define RF_RX_G1 0x1A // ++#define RF_RX_G2 0x1B // ++ ++#define RF_RX_BB2 0x1C // ++#define RF_RX_BB1 0x1D // ++ ++#define RF_RCK1 0x1E // ++#define RF_RCK2 0x1F // ++ ++#define RF_TX_G1 0x20 // ++#define RF_TX_G2 0x21 // ++#define RF_TX_G3 0x22 // ++ ++#define RF_TX_BB1 0x23 // ++ ++#define RF_T_METER 0x24 // ++ ++#define RF_SYN_G1 0x25 // RF TX Power control ++#define RF_SYN_G2 0x26 // RF TX Power control ++#define RF_SYN_G3 0x27 // RF TX Power control ++#define RF_SYN_G4 0x28 // RF TX Power control ++#define RF_SYN_G5 0x29 // RF TX Power control ++#define RF_SYN_G6 0x2A // RF TX Power control ++#define RF_SYN_G7 0x2B // RF TX Power control ++#define RF_SYN_G8 0x2C // RF TX Power control ++ ++#define RF_RCK_OS 0x30 // RF TX PA control ++ ++#define RF_TXPA_G1 0x31 // RF TX PA control ++#define RF_TXPA_G2 0x32 // RF TX PA control ++#define RF_TXPA_G3 0x33 // RF TX PA control ++ ++// ++//Bit Mask ++// ++// 1. Page1(0x100) ++#define bBBResetB 0x100 // Useless now? ++#define bGlobalResetB 0x200 ++#define bOFDMTxStart 0x4 ++#define bCCKTxStart 0x8 ++#define bCRC32Debug 0x100 ++#define bPMACLoopback 0x10 ++#define bTxLSIG 0xffffff ++#define bOFDMTxRate 0xf ++#define bOFDMTxReserved 0x10 ++#define bOFDMTxLength 0x1ffe0 ++#define bOFDMTxParity 0x20000 ++#define bTxHTSIG1 0xffffff ++#define bTxHTMCSRate 0x7f ++#define bTxHTBW 0x80 ++#define bTxHTLength 0xffff00 ++#define bTxHTSIG2 0xffffff ++#define bTxHTSmoothing 0x1 ++#define bTxHTSounding 0x2 ++#define bTxHTReserved 0x4 ++#define bTxHTAggreation 0x8 ++#define bTxHTSTBC 0x30 ++#define bTxHTAdvanceCoding 0x40 ++#define bTxHTShortGI 0x80 ++#define bTxHTNumberHT_LTF 0x300 ++#define bTxHTCRC8 0x3fc00 ++#define bCounterReset 0x10000 ++#define bNumOfOFDMTx 0xffff ++#define bNumOfCCKTx 0xffff0000 ++#define bTxIdleInterval 0xffff ++#define bOFDMService 0xffff0000 ++#define bTxMACHeader 0xffffffff ++#define bTxDataInit 0xff ++#define bTxHTMode 0x100 ++#define bTxDataType 0x30000 ++#define bTxRandomSeed 0xffffffff ++#define bCCKTxPreamble 0x1 ++#define bCCKTxSFD 0xffff0000 ++#define bCCKTxSIG 0xff ++#define bCCKTxService 0xff00 ++#define bCCKLengthExt 0x8000 ++#define bCCKTxLength 0xffff0000 ++#define bCCKTxCRC16 0xffff ++#define bCCKTxStatus 0x1 ++#define bOFDMTxStatus 0x2 ++ ++#define IS_BB_REG_OFFSET_92S(_Offset) ((_Offset >= 0x800) && (_Offset <= 0xfff)) ++ ++// 2. Page8(0x800) ++#define bRFMOD 0x1 // Reg 0x800 rFPGA0_RFMOD ++#define bJapanMode 0x2 ++#define bCCKTxSC 0x30 ++#define bCCKEn 0x1000000 ++#define bOFDMEn 0x2000000 ++ ++#define bOFDMRxADCPhase 0x10000 // Useless now ++#define bOFDMTxDACPhase 0x40000 ++#define bXATxAGC 0x3f ++ ++#define bAntennaSelect 0x0300 ++ ++#define bXBTxAGC 0xf00 // Reg 80c rFPGA0_TxGainStage ++#define bXCTxAGC 0xf000 ++#define bXDTxAGC 0xf0000 ++ ++#define bPAStart 0xf0000000 // Useless now ++#define bTRStart 0x00f00000 ++#define bRFStart 0x0000f000 ++#define bBBStart 0x000000f0 ++#define bBBCCKStart 0x0000000f ++#define bPAEnd 0xf //Reg0x814 ++#define bTREnd 0x0f000000 ++#define bRFEnd 0x000f0000 ++#define bCCAMask 0x000000f0 //T2R ++#define bR2RCCAMask 0x00000f00 ++#define bHSSI_R2TDelay 0xf8000000 ++#define bHSSI_T2RDelay 0xf80000 ++#define bContTxHSSI 0x400 //chane gain at continue Tx ++#define bIGFromCCK 0x200 ++#define bAGCAddress 0x3f ++#define bRxHPTx 0x7000 ++#define bRxHPT2R 0x38000 ++#define bRxHPCCKIni 0xc0000 ++#define bAGCTxCode 0xc00000 ++#define bAGCRxCode 0x300000 ++ ++#define b3WireDataLength 0x800 // Reg 0x820~84f rFPGA0_XA_HSSIParameter1 ++#define b3WireAddressLength 0x400 ++ ++#define b3WireRFPowerDown 0x1 // Useless now ++//#define bHWSISelect 0x8 ++#define b5GPAPEPolarity 0x40000000 ++#define b2GPAPEPolarity 0x80000000 ++#define bRFSW_TxDefaultAnt 0x3 ++#define bRFSW_TxOptionAnt 0x30 ++#define bRFSW_RxDefaultAnt 0x300 ++#define bRFSW_RxOptionAnt 0x3000 ++#define bRFSI_3WireData 0x1 ++#define bRFSI_3WireClock 0x2 ++#define bRFSI_3WireLoad 0x4 ++#define bRFSI_3WireRW 0x8 ++#define bRFSI_3Wire 0xf ++ ++#define bRFSI_RFENV 0x10 // Reg 0x870 rFPGA0_XAB_RFInterfaceSW ++ ++#define bRFSI_TRSW 0x20 // Useless now ++#define bRFSI_TRSWB 0x40 ++#define bRFSI_ANTSW 0x100 ++#define bRFSI_ANTSWB 0x200 ++#define bRFSI_PAPE 0x400 ++#define bRFSI_PAPE5G 0x800 ++#define bBandSelect 0x1 ++#define bHTSIG2_GI 0x80 ++#define bHTSIG2_Smoothing 0x01 ++#define bHTSIG2_Sounding 0x02 ++#define bHTSIG2_Aggreaton 0x08 ++#define bHTSIG2_STBC 0x30 ++#define bHTSIG2_AdvCoding 0x40 ++#define bHTSIG2_NumOfHTLTF 0x300 ++#define bHTSIG2_CRC8 0x3fc ++#define bHTSIG1_MCS 0x7f ++#define bHTSIG1_BandWidth 0x80 ++#define bHTSIG1_HTLength 0xffff ++#define bLSIG_Rate 0xf ++#define bLSIG_Reserved 0x10 ++#define bLSIG_Length 0x1fffe ++#define bLSIG_Parity 0x20 ++#define bCCKRxPhase 0x4 ++ ++#define bLSSIReadAddress 0x7f800000 // T65 RF ++ ++#define bLSSIReadEdge 0x80000000 //LSSI "Read" edge signal ++ ++#define bLSSIReadBackData 0xfffff // T65 RF ++ ++#define bLSSIReadOKFlag 0x1000 // Useless now ++#define bCCKSampleRate 0x8 //0: 44MHz, 1:88MHz ++#define bRegulator0Standby 0x1 ++#define bRegulatorPLLStandby 0x2 ++#define bRegulator1Standby 0x4 ++#define bPLLPowerUp 0x8 ++#define bDPLLPowerUp 0x10 ++#define bDA10PowerUp 0x20 ++#define bAD7PowerUp 0x200 ++#define bDA6PowerUp 0x2000 ++#define bXtalPowerUp 0x4000 ++#define b40MDClkPowerUP 0x8000 ++#define bDA6DebugMode 0x20000 ++#define bDA6Swing 0x380000 ++ ++#define bADClkPhase 0x4000000 // Reg 0x880 rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ ++ ++#define b80MClkDelay 0x18000000 // Useless ++#define bAFEWatchDogEnable 0x20000000 ++ ++#define bXtalCap01 0xc0000000 // Reg 0x884 rFPGA0_AnalogParameter2 Crystal cap ++#define bXtalCap23 0x3 ++#define bXtalCap92x 0x0f000000 ++#define bXtalCap 0x0f000000 ++ ++#define bIntDifClkEnable 0x400 // Useless ++#define bExtSigClkEnable 0x800 ++#define bBandgapMbiasPowerUp 0x10000 ++#define bAD11SHGain 0xc0000 ++#define bAD11InputRange 0x700000 ++#define bAD11OPCurrent 0x3800000 ++#define bIPathLoopback 0x4000000 ++#define bQPathLoopback 0x8000000 ++#define bAFELoopback 0x10000000 ++#define bDA10Swing 0x7e0 ++#define bDA10Reverse 0x800 ++#define bDAClkSource 0x1000 ++#define bAD7InputRange 0x6000 ++#define bAD7Gain 0x38000 ++#define bAD7OutputCMMode 0x40000 ++#define bAD7InputCMMode 0x380000 ++#define bAD7Current 0xc00000 ++#define bRegulatorAdjust 0x7000000 ++#define bAD11PowerUpAtTx 0x1 ++#define bDA10PSAtTx 0x10 ++#define bAD11PowerUpAtRx 0x100 ++#define bDA10PSAtRx 0x1000 ++#define bCCKRxAGCFormat 0x200 ++#define bPSDFFTSamplepPoint 0xc000 ++#define bPSDAverageNum 0x3000 ++#define bIQPathControl 0xc00 ++#define bPSDFreq 0x3ff ++#define bPSDAntennaPath 0x30 ++#define bPSDIQSwitch 0x40 ++#define bPSDRxTrigger 0x400000 ++#define bPSDTxTrigger 0x80000000 ++#define bPSDSineToneScale 0x7f000000 ++#define bPSDReport 0xffff ++ ++// 3. Page9(0x900) ++#define bOFDMTxSC 0x30000000 // Useless ++#define bCCKTxOn 0x1 ++#define bOFDMTxOn 0x2 ++#define bDebugPage 0xfff //reset debug page and also HWord, LWord ++#define bDebugItem 0xff //reset debug page and LWord ++#define bAntL 0x10 ++#define bAntNonHT 0x100 ++#define bAntHT1 0x1000 ++#define bAntHT2 0x10000 ++#define bAntHT1S1 0x100000 ++#define bAntNonHTS1 0x1000000 ++ ++// 4. PageA(0xA00) ++#define bCCKBBMode 0x3 // Useless ++#define bCCKTxPowerSaving 0x80 ++#define bCCKRxPowerSaving 0x40 ++ ++#define bCCKSideBand 0x10 // Reg 0xa00 rCCK0_System 20/40 switch ++ ++#define bCCKScramble 0x8 // Useless ++#define bCCKAntDiversity 0x8000 ++#define bCCKCarrierRecovery 0x4000 ++#define bCCKTxRate 0x3000 ++#define bCCKDCCancel 0x0800 ++#define bCCKISICancel 0x0400 ++#define bCCKMatchFilter 0x0200 ++#define bCCKEqualizer 0x0100 ++#define bCCKPreambleDetect 0x800000 ++#define bCCKFastFalseCCA 0x400000 ++#define bCCKChEstStart 0x300000 ++#define bCCKCCACount 0x080000 ++#define bCCKcs_lim 0x070000 ++#define bCCKBistMode 0x80000000 ++#define bCCKCCAMask 0x40000000 ++#define bCCKTxDACPhase 0x4 ++#define bCCKRxADCPhase 0x20000000 //r_rx_clk ++#define bCCKr_cp_mode0 0x0100 ++#define bCCKTxDCOffset 0xf0 ++#define bCCKRxDCOffset 0xf ++#define bCCKCCAMode 0xc000 ++#define bCCKFalseCS_lim 0x3f00 ++#define bCCKCS_ratio 0xc00000 ++#define bCCKCorgBit_sel 0x300000 ++#define bCCKPD_lim 0x0f0000 ++#define bCCKNewCCA 0x80000000 ++#define bCCKRxHPofIG 0x8000 ++#define bCCKRxIG 0x7f00 ++#define bCCKLNAPolarity 0x800000 ++#define bCCKRx1stGain 0x7f0000 ++#define bCCKRFExtend 0x20000000 //CCK Rx Iinital gain polarity ++#define bCCKRxAGCSatLevel 0x1f000000 ++#define bCCKRxAGCSatCount 0xe0 ++#define bCCKRxRFSettle 0x1f //AGCsamp_dly ++#define bCCKFixedRxAGC 0x8000 ++//#define bCCKRxAGCFormat 0x4000 //remove to HSSI register 0x824 ++#define bCCKAntennaPolarity 0x2000 ++#define bCCKTxFilterType 0x0c00 ++#define bCCKRxAGCReportType 0x0300 ++#define bCCKRxDAGCEn 0x80000000 ++#define bCCKRxDAGCPeriod 0x20000000 ++#define bCCKRxDAGCSatLevel 0x1f000000 ++#define bCCKTimingRecovery 0x800000 ++#define bCCKTxC0 0x3f0000 ++#define bCCKTxC1 0x3f000000 ++#define bCCKTxC2 0x3f ++#define bCCKTxC3 0x3f00 ++#define bCCKTxC4 0x3f0000 ++#define bCCKTxC5 0x3f000000 ++#define bCCKTxC6 0x3f ++#define bCCKTxC7 0x3f00 ++#define bCCKDebugPort 0xff0000 ++#define bCCKDACDebug 0x0f000000 ++#define bCCKFalseAlarmEnable 0x8000 ++#define bCCKFalseAlarmRead 0x4000 ++#define bCCKTRSSI 0x7f ++#define bCCKRxAGCReport 0xfe ++#define bCCKRxReport_AntSel 0x80000000 ++#define bCCKRxReport_MFOff 0x40000000 ++#define bCCKRxRxReport_SQLoss 0x20000000 ++#define bCCKRxReport_Pktloss 0x10000000 ++#define bCCKRxReport_Lockedbit 0x08000000 ++#define bCCKRxReport_RateError 0x04000000 ++#define bCCKRxReport_RxRate 0x03000000 ++#define bCCKRxFACounterLower 0xff ++#define bCCKRxFACounterUpper 0xff000000 ++#define bCCKRxHPAGCStart 0xe000 ++#define bCCKRxHPAGCFinal 0x1c00 ++#define bCCKRxFalseAlarmEnable 0x8000 ++#define bCCKFACounterFreeze 0x4000 ++#define bCCKTxPathSel 0x10000000 ++#define bCCKDefaultRxPath 0xc000000 ++#define bCCKOptionRxPath 0x3000000 ++ ++// 5. PageC(0xC00) ++#define bNumOfSTF 0x3 // Useless ++#define bShift_L 0xc0 ++#define bGI_TH 0xc ++#define bRxPathA 0x1 ++#define bRxPathB 0x2 ++#define bRxPathC 0x4 ++#define bRxPathD 0x8 ++#define bTxPathA 0x1 ++#define bTxPathB 0x2 ++#define bTxPathC 0x4 ++#define bTxPathD 0x8 ++#define bTRSSIFreq 0x200 ++#define bADCBackoff 0x3000 ++#define bDFIRBackoff 0xc000 ++#define bTRSSILatchPhase 0x10000 ++#define bRxIDCOffset 0xff ++#define bRxQDCOffset 0xff00 ++#define bRxDFIRMode 0x1800000 ++#define bRxDCNFType 0xe000000 ++#define bRXIQImb_A 0x3ff ++#define bRXIQImb_B 0xfc00 ++#define bRXIQImb_C 0x3f0000 ++#define bRXIQImb_D 0xffc00000 ++#define bDC_dc_Notch 0x60000 ++#define bRxNBINotch 0x1f000000 ++#define bPD_TH 0xf ++#define bPD_TH_Opt2 0xc000 ++#define bPWED_TH 0x700 ++#define bIfMF_Win_L 0x800 ++#define bPD_Option 0x1000 ++#define bMF_Win_L 0xe000 ++#define bBW_Search_L 0x30000 ++#define bwin_enh_L 0xc0000 ++#define bBW_TH 0x700000 ++#define bED_TH2 0x3800000 ++#define bBW_option 0x4000000 ++#define bRatio_TH 0x18000000 ++#define bWindow_L 0xe0000000 ++#define bSBD_Option 0x1 ++#define bFrame_TH 0x1c ++#define bFS_Option 0x60 ++#define bDC_Slope_check 0x80 ++#define bFGuard_Counter_DC_L 0xe00 ++#define bFrame_Weight_Short 0x7000 ++#define bSub_Tune 0xe00000 ++#define bFrame_DC_Length 0xe000000 ++#define bSBD_start_offset 0x30000000 ++#define bFrame_TH_2 0x7 ++#define bFrame_GI2_TH 0x38 ++#define bGI2_Sync_en 0x40 ++#define bSarch_Short_Early 0x300 ++#define bSarch_Short_Late 0xc00 ++#define bSarch_GI2_Late 0x70000 ++#define bCFOAntSum 0x1 ++#define bCFOAcc 0x2 ++#define bCFOStartOffset 0xc ++#define bCFOLookBack 0x70 ++#define bCFOSumWeight 0x80 ++#define bDAGCEnable 0x10000 ++#define bTXIQImb_A 0x3ff ++#define bTXIQImb_B 0xfc00 ++#define bTXIQImb_C 0x3f0000 ++#define bTXIQImb_D 0xffc00000 ++#define bTxIDCOffset 0xff ++#define bTxQDCOffset 0xff00 ++#define bTxDFIRMode 0x10000 ++#define bTxPesudoNoiseOn 0x4000000 ++#define bTxPesudoNoise_A 0xff ++#define bTxPesudoNoise_B 0xff00 ++#define bTxPesudoNoise_C 0xff0000 ++#define bTxPesudoNoise_D 0xff000000 ++#define bCCADropOption 0x20000 ++#define bCCADropThres 0xfff00000 ++#define bEDCCA_H 0xf ++#define bEDCCA_L 0xf0 ++#define bLambda_ED 0x300 ++#define bRxInitialGain 0x7f ++#define bRxAntDivEn 0x80 ++#define bRxAGCAddressForLNA 0x7f00 ++#define bRxHighPowerFlow 0x8000 ++#define bRxAGCFreezeThres 0xc0000 ++#define bRxFreezeStep_AGC1 0x300000 ++#define bRxFreezeStep_AGC2 0xc00000 ++#define bRxFreezeStep_AGC3 0x3000000 ++#define bRxFreezeStep_AGC0 0xc000000 ++#define bRxRssi_Cmp_En 0x10000000 ++#define bRxQuickAGCEn 0x20000000 ++#define bRxAGCFreezeThresMode 0x40000000 ++#define bRxOverFlowCheckType 0x80000000 ++#define bRxAGCShift 0x7f ++#define bTRSW_Tri_Only 0x80 ++#define bPowerThres 0x300 ++#define bRxAGCEn 0x1 ++#define bRxAGCTogetherEn 0x2 ++#define bRxAGCMin 0x4 ++#define bRxHP_Ini 0x7 ++#define bRxHP_TRLNA 0x70 ++#define bRxHP_RSSI 0x700 ++#define bRxHP_BBP1 0x7000 ++#define bRxHP_BBP2 0x70000 ++#define bRxHP_BBP3 0x700000 ++#define bRSSI_H 0x7f0000 //the threshold for high power ++#define bRSSI_Gen 0x7f000000 //the threshold for ant diversity ++#define bRxSettle_TRSW 0x7 ++#define bRxSettle_LNA 0x38 ++#define bRxSettle_RSSI 0x1c0 ++#define bRxSettle_BBP 0xe00 ++#define bRxSettle_RxHP 0x7000 ++#define bRxSettle_AntSW_RSSI 0x38000 ++#define bRxSettle_AntSW 0xc0000 ++#define bRxProcessTime_DAGC 0x300000 ++#define bRxSettle_HSSI 0x400000 ++#define bRxProcessTime_BBPPW 0x800000 ++#define bRxAntennaPowerShift 0x3000000 ++#define bRSSITableSelect 0xc000000 ++#define bRxHP_Final 0x7000000 ++#define bRxHTSettle_BBP 0x7 ++#define bRxHTSettle_HSSI 0x8 ++#define bRxHTSettle_RxHP 0x70 ++#define bRxHTSettle_BBPPW 0x80 ++#define bRxHTSettle_Idle 0x300 ++#define bRxHTSettle_Reserved 0x1c00 ++#define bRxHTRxHPEn 0x8000 ++#define bRxHTAGCFreezeThres 0x30000 ++#define bRxHTAGCTogetherEn 0x40000 ++#define bRxHTAGCMin 0x80000 ++#define bRxHTAGCEn 0x100000 ++#define bRxHTDAGCEn 0x200000 ++#define bRxHTRxHP_BBP 0x1c00000 ++#define bRxHTRxHP_Final 0xe0000000 ++#define bRxPWRatioTH 0x3 ++#define bRxPWRatioEn 0x4 ++#define bRxMFHold 0x3800 ++#define bRxPD_Delay_TH1 0x38 ++#define bRxPD_Delay_TH2 0x1c0 ++#define bRxPD_DC_COUNT_MAX 0x600 ++//#define bRxMF_Hold 0x3800 ++#define bRxPD_Delay_TH 0x8000 ++#define bRxProcess_Delay 0xf0000 ++#define bRxSearchrange_GI2_Early 0x700000 ++#define bRxFrame_Guard_Counter_L 0x3800000 ++#define bRxSGI_Guard_L 0xc000000 ++#define bRxSGI_Search_L 0x30000000 ++#define bRxSGI_TH 0xc0000000 ++#define bDFSCnt0 0xff ++#define bDFSCnt1 0xff00 ++#define bDFSFlag 0xf0000 ++#define bMFWeightSum 0x300000 ++#define bMinIdxTH 0x7f000000 ++#define bDAFormat 0x40000 ++#define bTxChEmuEnable 0x01000000 ++#define bTRSWIsolation_A 0x7f ++#define bTRSWIsolation_B 0x7f00 ++#define bTRSWIsolation_C 0x7f0000 ++#define bTRSWIsolation_D 0x7f000000 ++#define bExtLNAGain 0x7c00 ++ ++// 6. PageE(0xE00) ++#define bSTBCEn 0x4 // Useless ++#define bAntennaMapping 0x10 ++#define bNss 0x20 ++#define bCFOAntSumD 0x200 ++#define bPHYCounterReset 0x8000000 ++#define bCFOReportGet 0x4000000 ++#define bOFDMContinueTx 0x10000000 ++#define bOFDMSingleCarrier 0x20000000 ++#define bOFDMSingleTone 0x40000000 ++//#define bRxPath1 0x01 ++//#define bRxPath2 0x02 ++//#define bRxPath3 0x04 ++//#define bRxPath4 0x08 ++//#define bTxPath1 0x10 ++//#define bTxPath2 0x20 ++#define bHTDetect 0x100 ++#define bCFOEn 0x10000 ++#define bCFOValue 0xfff00000 ++#define bSigTone_Re 0x3f ++#define bSigTone_Im 0x7f00 ++#define bCounter_CCA 0xffff ++#define bCounter_ParityFail 0xffff0000 ++#define bCounter_RateIllegal 0xffff ++#define bCounter_CRC8Fail 0xffff0000 ++#define bCounter_MCSNoSupport 0xffff ++#define bCounter_FastSync 0xffff ++#define bShortCFO 0xfff ++#define bShortCFOTLength 12 //total ++#define bShortCFOFLength 11 //fraction ++#define bLongCFO 0x7ff ++#define bLongCFOTLength 11 ++#define bLongCFOFLength 11 ++#define bTailCFO 0x1fff ++#define bTailCFOTLength 13 ++#define bTailCFOFLength 12 ++#define bmax_en_pwdB 0xffff ++#define bCC_power_dB 0xffff0000 ++#define bnoise_pwdB 0xffff ++#define bPowerMeasTLength 10 ++#define bPowerMeasFLength 3 ++#define bRx_HT_BW 0x1 ++#define bRxSC 0x6 ++#define bRx_HT 0x8 ++#define bNB_intf_det_on 0x1 ++#define bIntf_win_len_cfg 0x30 ++#define bNB_Intf_TH_cfg 0x1c0 ++#define bRFGain 0x3f ++#define bTableSel 0x40 ++#define bTRSW 0x80 ++#define bRxSNR_A 0xff ++#define bRxSNR_B 0xff00 ++#define bRxSNR_C 0xff0000 ++#define bRxSNR_D 0xff000000 ++#define bSNREVMTLength 8 ++#define bSNREVMFLength 1 ++#define bCSI1st 0xff ++#define bCSI2nd 0xff00 ++#define bRxEVM1st 0xff0000 ++#define bRxEVM2nd 0xff000000 ++#define bSIGEVM 0xff ++#define bPWDB 0xff00 ++#define bSGIEN 0x10000 ++ ++#define bSFactorQAM1 0xf // Useless ++#define bSFactorQAM2 0xf0 ++#define bSFactorQAM3 0xf00 ++#define bSFactorQAM4 0xf000 ++#define bSFactorQAM5 0xf0000 ++#define bSFactorQAM6 0xf0000 ++#define bSFactorQAM7 0xf00000 ++#define bSFactorQAM8 0xf000000 ++#define bSFactorQAM9 0xf0000000 ++#define bCSIScheme 0x100000 ++ ++#define bNoiseLvlTopSet 0x3 // Useless ++#define bChSmooth 0x4 ++#define bChSmoothCfg1 0x38 ++#define bChSmoothCfg2 0x1c0 ++#define bChSmoothCfg3 0xe00 ++#define bChSmoothCfg4 0x7000 ++#define bMRCMode 0x800000 ++#define bTHEVMCfg 0x7000000 ++ ++#define bLoopFitType 0x1 // Useless ++#define bUpdCFO 0x40 ++#define bUpdCFOOffData 0x80 ++#define bAdvUpdCFO 0x100 ++#define bAdvTimeCtrl 0x800 ++#define bUpdClko 0x1000 ++#define bFC 0x6000 ++#define bTrackingMode 0x8000 ++#define bPhCmpEnable 0x10000 ++#define bUpdClkoLTF 0x20000 ++#define bComChCFO 0x40000 ++#define bCSIEstiMode 0x80000 ++#define bAdvUpdEqz 0x100000 ++#define bUChCfg 0x7000000 ++#define bUpdEqz 0x8000000 ++ ++//Rx Pseduo noise ++#define bRxPesudoNoiseOn 0x20000000 // Useless ++#define bRxPesudoNoise_A 0xff ++#define bRxPesudoNoise_B 0xff00 ++#define bRxPesudoNoise_C 0xff0000 ++#define bRxPesudoNoise_D 0xff000000 ++#define bPesudoNoiseState_A 0xffff ++#define bPesudoNoiseState_B 0xffff0000 ++#define bPesudoNoiseState_C 0xffff ++#define bPesudoNoiseState_D 0xffff0000 ++ ++//7. RF Register ++//Zebra1 ++#define bZebra1_HSSIEnable 0x8 // Useless ++#define bZebra1_TRxControl 0xc00 ++#define bZebra1_TRxGainSetting 0x07f ++#define bZebra1_RxCorner 0xc00 ++#define bZebra1_TxChargePump 0x38 ++#define bZebra1_RxChargePump 0x7 ++#define bZebra1_ChannelNum 0xf80 ++#define bZebra1_TxLPFBW 0x400 ++#define bZebra1_RxLPFBW 0x600 ++ ++//Zebra4 ++#define bRTL8256RegModeCtrl1 0x100 // Useless ++#define bRTL8256RegModeCtrl0 0x40 ++#define bRTL8256_TxLPFBW 0x18 ++#define bRTL8256_RxLPFBW 0x600 ++ ++//RTL8258 ++#define bRTL8258_TxLPFBW 0xc // Useless ++#define bRTL8258_RxLPFBW 0xc00 ++#define bRTL8258_RSSILPFBW 0xc0 ++ ++ ++// ++// Other Definition ++// ++ ++//byte endable for sb_write ++#define bByte0 0x1 // Useless ++#define bByte1 0x2 ++#define bByte2 0x4 ++#define bByte3 0x8 ++#define bWord0 0x3 ++#define bWord1 0xc ++#define bDWord 0xf ++ ++//for PutRegsetting & GetRegSetting BitMask ++#define bMaskByte0 0xff // Reg 0xc50 rOFDM0_XAAGCCore~0xC6f ++#define bMaskByte1 0xff00 ++#define bMaskByte2 0xff0000 ++#define bMaskByte3 0xff000000 ++#define bMaskHWord 0xffff0000 ++#define bMaskLWord 0x0000ffff ++#define bMaskDWord 0xffffffff ++#define bMask12Bits 0xfff ++#define bMaskH4Bits 0xf0000000 ++#define bMaskOFDM_D 0xffc00000 ++#define bMaskCCK 0x3f3f3f3f ++ ++//for PutRFRegsetting & GetRFRegSetting BitMask ++//#define bMask12Bits 0xfffff // RF Reg mask bits ++//#define bMask20Bits 0xfffff // RF Reg mask bits T65 RF ++#define bRFRegOffsetMask 0xfffff ++ ++#define bEnable 0x1 // Useless ++#define bDisable 0x0 ++ ++#define LeftAntenna 0x0 // Useless ++#define RightAntenna 0x1 ++ ++#define tCheckTxStatus 500 //500ms // Useless ++#define tUpdateRxCounter 100 //100ms ++ ++#define rateCCK 0 // Useless ++#define rateOFDM 1 ++#define rateHT 2 ++ ++//define Register-End ++#define bPMAC_End 0x1ff // Useless ++#define bFPGAPHY0_End 0x8ff ++#define bFPGAPHY1_End 0x9ff ++#define bCCKPHY0_End 0xaff ++#define bOFDMPHY0_End 0xcff ++#define bOFDMPHY1_End 0xdff ++ ++//define max debug item in each debug page ++//#define bMaxItem_FPGA_PHY0 0x9 ++//#define bMaxItem_FPGA_PHY1 0x3 ++//#define bMaxItem_PHY_11B 0x16 ++//#define bMaxItem_OFDM_PHY0 0x29 ++//#define bMaxItem_OFDM_PHY1 0x0 ++ ++#define bPMACControl 0x0 // Useless ++#define bWMACControl 0x1 ++#define bWNICControl 0x2 ++ ++#define PathA 0x0 // Useless ++#define PathB 0x1 ++#define PathC 0x2 ++#define PathD 0x3 ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++ ++#endif //__INC_HAL8192SPHYREG_H ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/Hal8192DPhyCfg.h b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8192DPhyCfg.h +new file mode 100644 +index 00000000..f2e55df8 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8192DPhyCfg.h +@@ -0,0 +1,487 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++/***************************************************************************** ++ * ++ * Module: __INC_HAL8192DPHYCFG_H ++ * ++ * ++ * Note: ++ * ++ * ++ * Export: Constants, macro, functions(API), global variables(None). ++ * ++ * Abbrev: ++ * ++ * History: ++ * Data Who Remark ++ * 08/07/2007 MHC 1. Porting from 9x series PHYCFG.h. ++ * 2. Reorganize code architecture. ++ * ++ *****************************************************************************/ ++ /* Check to see if the file has been included already. */ ++#ifndef __INC_HAL8192DPHYCFG_H ++#define __INC_HAL8192DPHYCFG_H ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++#define LOOP_LIMIT 5 ++#define MAX_STALL_TIME 50 //us ++#define AntennaDiversityValue 0x80 //(Adapter->bSoftwareAntennaDiversity ? 0x00:0x80) ++#define MAX_TXPWR_IDX_NMODE_92S 63 ++#define Reset_Cnt_Limit 3 ++ ++ ++#ifdef CONFIG_PCI_HCI ++#define SET_RTL8192SE_RF_SLEEP(_pAdapter) \ ++{ \ ++ u1Byte u1bTmp; \ ++ u1bTmp = PlatformEFIORead1Byte(_pAdapter, REG_LDOV12D_CTRL); \ ++ u1bTmp |= BIT0; \ ++ PlatformEFIOWrite1Byte(_pAdapter, REG_LDOV12D_CTRL, u1bTmp); \ ++ PlatformEFIOWrite1Byte(_pAdapter, REG_SPS_OCP_CFG, 0x0); \ ++ PlatformEFIOWrite1Byte(_pAdapter, TXPAUSE, 0xFF); \ ++ PlatformEFIOWrite2Byte(_pAdapter, CMDR, 0x57FC); \ ++ delay_us(100); \ ++ PlatformEFIOWrite2Byte(_pAdapter, CMDR, 0x77FC); \ ++ PlatformEFIOWrite1Byte(_pAdapter, PHY_CCA, 0x0); \ ++ delay_us(10); \ ++ PlatformEFIOWrite2Byte(_pAdapter, CMDR, 0x37FC); \ ++ delay_us(10); \ ++ PlatformEFIOWrite2Byte(_pAdapter, CMDR, 0x77FC); \ ++ delay_us(10); \ ++ PlatformEFIOWrite2Byte(_pAdapter, CMDR, 0x57FC); \ ++} ++#endif ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++ ++/*------------------------------Define structure----------------------------*/ ++typedef enum _SwChnlCmdID{ ++ CmdID_End, ++ CmdID_SetTxPowerLevel, ++ CmdID_BBRegWrite10, ++ CmdID_WritePortUlong, ++ CmdID_WritePortUshort, ++ CmdID_WritePortUchar, ++ CmdID_RF_WriteReg, ++}SwChnlCmdID; ++ ++ ++/* 1. Switch channel related */ ++typedef struct _SwChnlCmd{ ++ SwChnlCmdID CmdID; ++ u32 Para1; ++ u32 Para2; ++ u32 msDelay; ++}SwChnlCmd; ++ ++typedef enum _HW90_BLOCK{ ++ HW90_BLOCK_MAC = 0, ++ HW90_BLOCK_PHY0 = 1, ++ HW90_BLOCK_PHY1 = 2, ++ HW90_BLOCK_RF = 3, ++ HW90_BLOCK_MAXIMUM = 4, // Never use this ++}HW90_BLOCK_E, *PHW90_BLOCK_E; ++ ++//vivi added this for read parameter from header, 20100908 ++typedef enum _RF_CONTENT{ ++ radioa_txt = 0x1000, ++ radiob_txt = 0x1001, ++ radioc_txt = 0x1002, ++ radiod_txt = 0x1003 ++} RF_CONTENT; ++ ++typedef enum _RF_RADIO_PATH{ ++ RF_PATH_A = 0, //Radio Path A ++ RF_PATH_B = 1, //Radio Path B ++ RF_PATH_C = 2, //Radio Path C ++ RF_PATH_D = 3, //Radio Path D ++ //RF_PATH_MAX //Max RF number 90 support ++}RF_RADIO_PATH_E, *PRF_RADIO_PATH_E; ++ ++#define RF_PATH_MAX 2 ++ ++ ++typedef enum _WIRELESS_MODE { ++ WIRELESS_MODE_UNKNOWN = 0x00, ++ WIRELESS_MODE_A = 0x01, ++ WIRELESS_MODE_B = 0x02, ++ WIRELESS_MODE_G = 0x04, ++ WIRELESS_MODE_AUTO = 0x08, ++ WIRELESS_MODE_N_24G = 0x10, ++ WIRELESS_MODE_N_5G = 0x20 ++} WIRELESS_MODE; ++ ++ ++#if(TX_POWER_FOR_5G_BAND == 1) ++#define CHANNEL_MAX_NUMBER 14+24+21 // 14 is the max channel number ++#define CHANNEL_GROUP_MAX 3+9 // ch1~3, ch4~9, ch10~14 total three groups ++#define MAX_PG_GROUP 13 ++#else ++#define CHANNEL_MAX_NUMBER 14 // 14 is the max channel number ++#define CHANNEL_GROUP_MAX 3 // ch1~3, ch4~9, ch10~14 total three groups ++#define MAX_PG_GROUP 7 ++#endif ++#define CHANNEL_GROUP_MAX_2G 3 ++#define CHANNEL_GROUP_IDX_5GL 3 ++#define CHANNEL_GROUP_IDX_5GM 6 ++#define CHANNEL_GROUP_IDX_5GH 9 ++#define CHANNEL_GROUP_MAX_5G 9 ++#define CHANNEL_MAX_NUMBER_2G 14 ++ ++#if (RTL8192D_DUAL_MAC_MODE_SWITCH == 1) ++typedef enum _BaseBand_Config_Type{ ++ BaseBand_Config_PHY_REG = 0, ++ BaseBand_Config_AGC_TAB = 1, ++ BaseBand_Config_AGC_TAB_2G = 2, ++ BaseBand_Config_AGC_TAB_5G = 3, ++}BaseBand_Config_Type, *PBaseBand_Config_Type; ++#else ++typedef enum _BaseBand_Config_Type{ ++ BaseBand_Config_PHY_REG = 0, //Radio Path A ++ BaseBand_Config_AGC_TAB = 1, //Radio Path B ++}BaseBand_Config_Type, *PBaseBand_Config_Type; ++#endif ++ ++ ++typedef enum _MACPHY_MODE_8192D{ ++ SINGLEMAC_SINGLEPHY, //SMSP ++ DUALMAC_DUALPHY, //DMDP ++ DUALMAC_SINGLEPHY, //DMSP ++}MACPHY_MODE_8192D,*PMACPHY_MODE_8192D; ++ ++typedef enum _MACPHY_MODE_CHANGE_ACTION{ ++ DMDP2DMSP = 0, ++ DMSP2DMDP = 1, ++ DMDP2SMSP = 2, ++ SMSP2DMDP = 3, ++ DMSP2SMSP = 4, ++ SMSP2DMSP = 5, ++ MAXACTION ++}MACPHY_MODE_CHANGE_ACTION,*PMACPHY_MODE_CHANGE_ACTION; ++ ++typedef enum _BAND_TYPE{ ++ BAND_ON_2_4G = 1, ++ BAND_ON_5G = 2, ++ BAND_ON_BOTH, ++ BANDMAX ++}BAND_TYPE,*PBAND_TYPE; ++ ++typedef enum _PHY_Rate_Tx_Power_Offset_Area{ ++ RA_OFFSET_LEGACY_OFDM1, ++ RA_OFFSET_LEGACY_OFDM2, ++ RA_OFFSET_HT_OFDM1, ++ RA_OFFSET_HT_OFDM2, ++ RA_OFFSET_HT_OFDM3, ++ RA_OFFSET_HT_OFDM4, ++ RA_OFFSET_HT_CCK, ++}RA_OFFSET_AREA,*PRA_OFFSET_AREA; ++ ++ ++/* BB/RF related */ ++typedef enum _RF_TYPE_8190P{ ++ RF_TYPE_MIN, // 0 ++ RF_8225=1, // 1 11b/g RF for verification only ++ RF_8256=2, // 2 11b/g/n ++ RF_8258=3, // 3 11a/b/g/n RF ++ RF_6052=4, // 4 11b/g/n RF ++ //RF_6052=5, // 4 11b/g/n RF ++ // TODO: We sholud remove this psudo PHY RF after we get new RF. ++ RF_PSEUDO_11N=5, // 5, It is a temporality RF. ++}RF_TYPE_8190P_E,*PRF_TYPE_8190P_E; ++ ++ ++ ++typedef struct _BB_REGISTER_DEFINITION{ ++ u32 rfintfs; // set software control: ++ // 0x870~0x877[8 bytes] ++ ++ u32 rfintfi; // readback data: ++ // 0x8e0~0x8e7[8 bytes] ++ ++ u32 rfintfo; // output data: ++ // 0x860~0x86f [16 bytes] ++ ++ u32 rfintfe; // output enable: ++ // 0x860~0x86f [16 bytes] ++ ++ u32 rf3wireOffset; // LSSI data: ++ // 0x840~0x84f [16 bytes] ++ ++ u32 rfLSSI_Select; // BB Band Select: ++ // 0x878~0x87f [8 bytes] ++ ++ u32 rfTxGainStage; // Tx gain stage: ++ // 0x80c~0x80f [4 bytes] ++ ++ u32 rfHSSIPara1; // wire parameter control1 : ++ // 0x820~0x823,0x828~0x82b, 0x830~0x833, 0x838~0x83b [16 bytes] ++ ++ u32 rfHSSIPara2; // wire parameter control2 : ++ // 0x824~0x827,0x82c~0x82f, 0x834~0x837, 0x83c~0x83f [16 bytes] ++ ++ u32 rfSwitchControl; //Tx Rx antenna control : ++ // 0x858~0x85f [16 bytes] ++ ++ u32 rfAGCControl1; //AGC parameter control1 : ++ // 0xc50~0xc53,0xc58~0xc5b, 0xc60~0xc63, 0xc68~0xc6b [16 bytes] ++ ++ u32 rfAGCControl2; //AGC parameter control2 : ++ // 0xc54~0xc57,0xc5c~0xc5f, 0xc64~0xc67, 0xc6c~0xc6f [16 bytes] ++ ++ u32 rfRxIQImbalance; //OFDM Rx IQ imbalance matrix : ++ // 0xc14~0xc17,0xc1c~0xc1f, 0xc24~0xc27, 0xc2c~0xc2f [16 bytes] ++ ++ u32 rfRxAFE; //Rx IQ DC ofset and Rx digital filter, Rx DC notch filter : ++ // 0xc10~0xc13,0xc18~0xc1b, 0xc20~0xc23, 0xc28~0xc2b [16 bytes] ++ ++ u32 rfTxIQImbalance; //OFDM Tx IQ imbalance matrix ++ // 0xc80~0xc83,0xc88~0xc8b, 0xc90~0xc93, 0xc98~0xc9b [16 bytes] ++ ++ u32 rfTxAFE; //Tx IQ DC Offset and Tx DFIR type ++ // 0xc84~0xc87,0xc8c~0xc8f, 0xc94~0xc97, 0xc9c~0xc9f [16 bytes] ++ ++ u32 rfLSSIReadBack; //LSSI RF readback data SI mode ++ // 0x8a0~0x8af [16 bytes] ++ ++ u32 rfLSSIReadBackPi; //LSSI RF readback data PI mode 0x8b8-8bc for Path A and B ++ ++}BB_REGISTER_DEFINITION_T, *PBB_REGISTER_DEFINITION_T; ++ ++ ++typedef struct _R_ANTENNA_SELECT_OFDM{ ++ u32 r_tx_antenna:4; ++ u32 r_ant_l:4; ++ u32 r_ant_non_ht:4; ++ u32 r_ant_ht1:4; ++ u32 r_ant_ht2:4; ++ u32 r_ant_ht_s1:4; ++ u32 r_ant_non_ht_s1:4; ++ u32 OFDM_TXSC:2; ++ u32 Reserved:2; ++}R_ANTENNA_SELECT_OFDM; ++ ++typedef struct _R_ANTENNA_SELECT_CCK{ ++ u8 r_cckrx_enable_2:2; ++ u8 r_cckrx_enable:2; ++ u8 r_ccktx_enable:4; ++}R_ANTENNA_SELECT_CCK; ++ ++/*------------------------------Define structure----------------------------*/ ++ ++ ++/*------------------------Export global variable----------------------------*/ ++/*------------------------Export global variable----------------------------*/ ++ ++ ++/*------------------------Export Marco Definition---------------------------*/ ++ ++/*--------------------------Exported Function prototype---------------------*/ ++// ++// BB and RF register read/write ++// ++void rtl8192d_PHY_SetBBReg1Byte( IN PADAPTER Adapter, ++ IN u32 RegAddr, ++ IN u32 BitMask, ++ IN u32 Data ); ++u32 rtl8192d_PHY_QueryBBReg( IN PADAPTER Adapter, ++ IN u32 RegAddr, ++ IN u32 BitMask ); ++void rtl8192d_PHY_SetBBReg( IN PADAPTER Adapter, ++ IN u32 RegAddr, ++ IN u32 BitMask, ++ IN u32 Data ); ++u32 rtl8192d_PHY_QueryRFReg( IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath, ++ IN u32 RegAddr, ++ IN u32 BitMask ); ++void rtl8192d_PHY_SetRFReg( IN PADAPTER Adapter, ++ IN RF_RADIO_PATH_E eRFPath, ++ IN u32 RegAddr, ++ IN u32 BitMask, ++ IN u32 Data ); ++ ++// ++// Initialization related function ++// ++/* MAC/BB/RF HAL config */ ++extern int PHY_MACConfig8192D( IN PADAPTER Adapter ); ++extern int PHY_BBConfig8192D( IN PADAPTER Adapter ); ++extern int PHY_RFConfig8192D( IN PADAPTER Adapter ); ++/* RF config */ ++int rtl8192d_PHY_ConfigRFWithParaFile( IN PADAPTER Adapter, ++ IN u8* pFileName, ++ IN RF_RADIO_PATH_E eRFPath); ++int rtl8192d_PHY_ConfigRFWithHeaderFile( IN PADAPTER Adapter, ++ IN RF_CONTENT Content, ++ IN RF_RADIO_PATH_E eRFPath); ++/* BB/RF readback check for making sure init OK */ ++int rtl8192d_PHY_CheckBBAndRFOK( IN PADAPTER Adapter, ++ IN HW90_BLOCK_E CheckBlock, ++ IN RF_RADIO_PATH_E eRFPath ); ++/* Read initi reg value for tx power setting. */ ++void rtl8192d_PHY_GetHWRegOriginalValue( IN PADAPTER Adapter ); ++ ++// ++// RF Power setting ++// ++//extern BOOLEAN PHY_SetRFPowerState(IN PADAPTER Adapter, ++// IN RT_RF_POWER_STATE eRFPowerState); ++ ++// ++// BB TX Power R/W ++// ++void PHY_GetTxPowerLevel8192D( IN PADAPTER Adapter, ++ OUT u32* powerlevel ); ++void PHY_SetTxPowerLevel8192D( IN PADAPTER Adapter, ++ IN u8 channel ); ++BOOLEAN PHY_UpdateTxPowerDbm8192D( IN PADAPTER Adapter, ++ IN int powerInDbm ); ++ ++// ++VOID ++PHY_ScanOperationBackup8192D(IN PADAPTER Adapter, ++ IN u8 Operation ); ++ ++// ++// Switch bandwidth for 8192S ++// ++//void PHY_SetBWModeCallback8192C( IN PRT_TIMER pTimer ); ++void PHY_SetBWMode8192D( IN PADAPTER pAdapter, ++ IN HT_CHANNEL_WIDTH ChnlWidth, ++ IN unsigned char Offset ); ++ ++// ++// Set FW CMD IO for 8192S. ++// ++//extern BOOLEAN HalSetIO8192C( IN PADAPTER Adapter, ++// IN IO_TYPE IOType); ++ ++// ++// Set A2 entry to fw for 8192S ++// ++extern void FillA2Entry8192C( IN PADAPTER Adapter, ++ IN u8 index, ++ IN u8* val); ++ ++ ++// ++// channel switch related funciton ++// ++//extern void PHY_SwChnlCallback8192C( IN PRT_TIMER pTimer ); ++void PHY_SwChnl8192D( IN PADAPTER pAdapter, ++ IN u8 channel ); ++ // Call after initialization ++void PHY_SwChnlPhy8192D( IN PADAPTER pAdapter, ++ IN u8 channel ); ++ ++extern void ChkFwCmdIoDone( IN PADAPTER Adapter); ++ ++ ++// ++// BB/MAC/RF other monitor API ++// ++void PHY_SetMonitorMode8192D(IN PADAPTER pAdapter, ++ IN BOOLEAN bEnableMonitorMode ); ++ ++BOOLEAN PHY_CheckIsLegalRfPath8192D(IN PADAPTER pAdapter, ++ IN u32 eRFPath ); ++ ++ ++// ++// Modify the value of the hw register when beacon interval be changed. ++// ++void ++rtl8192d_PHY_SetBeaconHwReg( IN PADAPTER Adapter, ++ IN u16 BeaconInterval ); ++ ++ ++extern VOID ++PHY_SwitchEphyParameter( ++ IN PADAPTER Adapter ++ ); ++ ++extern VOID ++PHY_EnableHostClkReq( ++ IN PADAPTER Adapter ++ ); ++ ++BOOLEAN ++SetAntennaConfig92C( ++ IN PADAPTER Adapter, ++ IN u8 DefaultAnt ++ ); ++ ++VOID ++PHY_UpdateBBRFConfiguration8192D( ++ IN PADAPTER Adapter, ++ IN BOOLEAN bisBandSwitch ++); ++ ++VOID PHY_ReadMacPhyMode92D( ++ IN PADAPTER Adapter, ++ IN BOOLEAN AutoloadFail ++); ++ ++VOID PHY_ConfigMacPhyMode92D( ++ IN PADAPTER Adapter ++); ++ ++VOID PHY_ConfigMacPhyModeInfo92D( ++ IN PADAPTER Adapter ++); ++ ++VOID PHY_ConfigMacCoexist_RFPage92D( ++ IN PADAPTER Adapter ++); ++ ++VOID ++rtl8192d_PHY_InitRxSetting( ++ IN PADAPTER Adapter ++); ++ ++ ++VOID ++rtl8192d_PHY_SetRFPathSwitch(IN PADAPTER pAdapter, IN BOOLEAN bMain); ++ ++VOID ++HalChangeCCKStatus8192D( ++ IN PADAPTER Adapter, ++ IN BOOLEAN bCCKDisable ++); ++ ++VOID ++PHY_InitPABias92D(IN PADAPTER Adapter); ++ ++/*--------------------------Exported Function prototype---------------------*/ ++ ++#define PHY_SetBBReg1Byte(Adapter, RegAddr, BitMask, Data) rtl8192d_PHY_SetBBReg1Byte((Adapter), (RegAddr), (BitMask), (Data)) ++#define PHY_QueryBBReg(Adapter, RegAddr, BitMask) rtl8192d_PHY_QueryBBReg((Adapter), (RegAddr), (BitMask)) ++#define PHY_SetBBReg(Adapter, RegAddr, BitMask, Data) rtl8192d_PHY_SetBBReg((Adapter), (RegAddr), (BitMask), (Data)) ++#define PHY_QueryRFReg(Adapter, eRFPath, RegAddr, BitMask) rtl8192d_PHY_QueryRFReg((Adapter), (eRFPath), (RegAddr), (BitMask)) ++#define PHY_SetRFReg(Adapter, eRFPath, RegAddr, BitMask, Data) rtl8192d_PHY_SetRFReg((Adapter), (eRFPath), (RegAddr), (BitMask), (Data)) ++ ++#define PHY_SetMacReg PHY_SetBBReg ++#define PHY_QueryMacReg PHY_QueryBBReg ++ ++#endif // __INC_HAL8192SPHYCFG_H ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/Hal8192DPhyReg.h b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8192DPhyReg.h +new file mode 100644 +index 00000000..de23a415 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8192DPhyReg.h +@@ -0,0 +1,1172 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++/***************************************************************************** ++ * ++ * Module: __INC_HAL8192DPHYREG_H ++ * ++ * ++ * Note: 1. Define PMAC/BB register map ++ * 2. Define RF register map ++ * 3. PMAC/BB register bit mask. ++ * 4. RF reg bit mask. ++ * 5. Other BB/RF relative definition. ++ * ++ * ++ * Export: Constants, macro, functions(API), global variables(None). ++ * ++ * Abbrev: ++ * ++ * History: ++ * Data Who Remark ++ * 08/07/2007 MHC 1. Porting from 9x series PHYCFG.h. ++ * 2. Reorganize code architecture. ++ * 09/25/2008 MH 1. Add RL6052 register definition ++ * ++ *****************************************************************************/ ++#ifndef __INC_HAL8192DPHYREG_H ++#define __INC_HAL8192DPHYREG_H ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++//============================================================ ++// 8192S Regsiter offset definition ++//============================================================ ++ ++// ++// BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF ++// 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF ++// 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 ++// 3. RF register 0x00-2E ++// 4. Bit Mask for BB/RF register ++// 5. Other defintion for BB/RF R/W ++// ++ ++ ++// ++// 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF ++// 1. Page1(0x100) ++// ++#define rPMAC_Reset 0x100 ++#define rPMAC_TxStart 0x104 ++#define rPMAC_TxLegacySIG 0x108 ++#define rPMAC_TxHTSIG1 0x10c ++#define rPMAC_TxHTSIG2 0x110 ++#define rPMAC_PHYDebug 0x114 ++#define rPMAC_TxPacketNum 0x118 ++#define rPMAC_TxIdle 0x11c ++#define rPMAC_TxMACHeader0 0x120 ++#define rPMAC_TxMACHeader1 0x124 ++#define rPMAC_TxMACHeader2 0x128 ++#define rPMAC_TxMACHeader3 0x12c ++#define rPMAC_TxMACHeader4 0x130 ++#define rPMAC_TxMACHeader5 0x134 ++#define rPMAC_TxDataType 0x138 ++#define rPMAC_TxRandomSeed 0x13c ++#define rPMAC_CCKPLCPPreamble 0x140 ++#define rPMAC_CCKPLCPHeader 0x144 ++#define rPMAC_CCKCRC16 0x148 ++#define rPMAC_OFDMRxCRC32OK 0x170 ++#define rPMAC_OFDMRxCRC32Er 0x174 ++#define rPMAC_OFDMRxParityEr 0x178 ++#define rPMAC_OFDMRxCRC8Er 0x17c ++#define rPMAC_CCKCRxRC16Er 0x180 ++#define rPMAC_CCKCRxRC32Er 0x184 ++#define rPMAC_CCKCRxRC32OK 0x188 ++#define rPMAC_TxStatus 0x18c ++ ++// ++// 2. Page2(0x200) ++// ++// The following two definition are only used for USB interface. ++#define RF_BB_CMD_ADDR 0x02c0 // RF/BB read/write command address. ++#define RF_BB_CMD_DATA 0x02c4 // RF/BB read/write command data. ++ ++// ++// 3. Page8(0x800) ++// ++#define rFPGA0_RFMOD 0x800 //RF mode & CCK TxSC // RF BW Setting?? ++ ++#define rFPGA0_TxInfo 0x804 // Status report?? ++#define rFPGA0_PSDFunction 0x808 ++ ++#define rFPGA0_TxGainStage 0x80c // Set TX PWR init gain? ++ ++#define rFPGA0_RFTiming1 0x810 // Useless now ++#define rFPGA0_RFTiming2 0x814 ++ ++#define rFPGA0_XA_HSSIParameter1 0x820 // RF 3 wire register ++#define rFPGA0_XA_HSSIParameter2 0x824 ++#define rFPGA0_XB_HSSIParameter1 0x828 ++#define rFPGA0_XB_HSSIParameter2 0x82c ++ ++#define rFPGA0_XA_LSSIParameter 0x840 ++#define rFPGA0_XB_LSSIParameter 0x844 ++ ++#define rFPGA0_RFWakeUpParameter 0x850 // Useless now ++#define rFPGA0_RFSleepUpParameter 0x854 ++ ++#define rFPGA0_XAB_SwitchControl 0x858 // RF Channel switch ++#define rFPGA0_XCD_SwitchControl 0x85c ++ ++#define rFPGA0_XA_RFInterfaceOE 0x860 // RF Channel switch ++#define rFPGA0_XB_RFInterfaceOE 0x864 ++ ++#define rFPGA0_XAB_RFInterfaceSW 0x870 // RF Interface Software Control ++#define rFPGA0_XCD_RFInterfaceSW 0x874 ++ ++#define rFPGA0_XAB_RFParameter 0x878 // RF Parameter ++#define rFPGA0_XCD_RFParameter 0x87c ++ ++#define rFPGA0_AnalogParameter1 0x880 // Crystal cap setting RF-R/W protection for parameter4?? ++#define rFPGA0_AnalogParameter2 0x884 ++#define rFPGA0_AnalogParameter3 0x888 ++#define rFPGA0_AdDaClockEn 0x888 // enable ad/da clock1 for dual-phy ++#define rFPGA0_AnalogParameter4 0x88c ++ ++#define rFPGA0_XA_LSSIReadBack 0x8a0 // Tranceiver LSSI Readback ++#define rFPGA0_XB_LSSIReadBack 0x8a4 ++#define rFPGA0_XC_LSSIReadBack 0x8a8 ++#define rFPGA0_XD_LSSIReadBack 0x8ac ++ ++#define rFPGA0_PSDReport 0x8b4 // Useless now ++#define TransceiverA_HSPI_Readback 0x8b8 // Transceiver A HSPI Readback ++#define TransceiverB_HSPI_Readback 0x8bc // Transceiver B HSPI Readback ++#define rFPGA0_XAB_RFInterfaceRB 0x8e0 // Useless now // RF Interface Readback Value ++#define rFPGA0_XCD_RFInterfaceRB 0x8e4 // Useless now ++ ++// ++// 4. Page9(0x900) ++// ++#define rFPGA1_RFMOD 0x900 //RF mode & OFDM TxSC // RF BW Setting?? ++ ++#define rFPGA1_TxBlock 0x904 // Useless now ++#define rFPGA1_DebugSelect 0x908 // Useless now ++#define rFPGA1_TxInfo 0x90c // Useless now // Status report?? ++ ++// ++// 5. PageA(0xA00) ++// ++// Set Control channel to upper or lower. These settings are required only for 40MHz ++#define rCCK0_System 0xa00 ++ ++#define rCCK0_AFESetting 0xa04 // Disable init gain now // Select RX path by RSSI ++#define rCCK0_CCA 0xa08 // Disable init gain now // Init gain ++ ++#define rCCK0_RxAGC1 0xa0c //AGC default value, saturation level // Antenna Diversity, RX AGC, LNA Threshold, RX LNA Threshold useless now. Not the same as 90 series ++#define rCCK0_RxAGC2 0xa10 //AGC & DAGC ++ ++#define rCCK0_RxHP 0xa14 ++ ++#define rCCK0_DSPParameter1 0xa18 //Timing recovery & Channel estimation threshold ++#define rCCK0_DSPParameter2 0xa1c //SQ threshold ++ ++#define rCCK0_TxFilter1 0xa20 ++#define rCCK0_TxFilter2 0xa24 ++#define rCCK0_DebugPort 0xa28 //debug port and Tx filter3 ++#define rCCK0_FalseAlarmReport 0xa2c //0xa2d useless now 0xa30-a4f channel report ++#define rCCK0_TRSSIReport 0xa50 ++#define rCCK0_RxReport 0xa54 //0xa57 ++#define rCCK0_FACounterLower 0xa5c //0xa5b ++#define rCCK0_FACounterUpper 0xa58 //0xa5c ++ ++// ++// PageB(0xB00) ++// ++#define rPdp_AntA 0xb00 ++#define rPdp_AntA_4 0xb04 ++#define rPdp_AntA_8 0xb08 ++#define rPdp_AntA_C 0xb0c ++#define rPdp_AntA_10 0xb10 ++#define rPdp_AntA_14 0xb14 ++#define rPdp_AntA_18 0xb18 ++#define rPdp_AntA_1C 0xb1c ++#define rPdp_AntA_20 0xb20 ++#define rPdp_AntA_24 0xb24 ++ ++#define rConfig_Pmpd_AntA 0xb28 ++#define rConfig_ram64x16 0xb2c ++ ++#define rBndA 0xb30 ++#define rHssiPar 0xb34 ++ ++#define rConfig_AntA 0xb68 ++#define rConfig_AntB 0xb6c ++ ++#define rPdp_AntB 0xb70 ++#define rPdp_AntB_4 0xb74 ++#define rPdp_AntB_8 0xb78 ++#define rPdp_AntB_C 0xb7c ++#define rPdp_AntB_10 0xb80 ++#define rPdp_AntB_14 0xb84 ++#define rPdp_AntB_18 0xb88 ++#define rPdp_AntB_1C 0xb8c ++#define rPdp_AntB_20 0xb90 ++#define rPdp_AntB_24 0xb94 ++ ++#define rConfig_Pmpd_AntB 0xb98 ++ ++#define rBndB 0xba0 ++ ++#define rAPK 0xbd8 ++#define rPm_Rx0_AntA 0xbdc ++#define rPm_Rx1_AntA 0xbe0 ++#define rPm_Rx2_AntA 0xbe4 ++#define rPm_Rx3_AntA 0xbe8 ++#define rPm_Rx0_AntB 0xbec ++#define rPm_Rx1_AntB 0xbf0 ++#define rPm_Rx2_AntB 0xbf4 ++#define rPm_Rx3_AntB 0xbf8 ++ ++// ++// 6. PageC(0xC00) ++// ++#define rOFDM0_LSTF 0xc00 ++ ++#define rOFDM0_TRxPathEnable 0xc04 ++#define rOFDM0_TRMuxPar 0xc08 ++#define rOFDM0_TRSWIsolation 0xc0c ++ ++#define rOFDM0_XARxAFE 0xc10 //RxIQ DC offset, Rx digital filter, DC notch filter ++#define rOFDM0_XARxIQImbalance 0xc14 //RxIQ imblance matrix ++#define rOFDM0_XBRxAFE 0xc18 ++#define rOFDM0_XBRxIQImbalance 0xc1c ++#define rOFDM0_XCRxAFE 0xc20 ++#define rOFDM0_XCRxIQImbalance 0xc24 ++#define rOFDM0_XDRxAFE 0xc28 ++#define rOFDM0_XDRxIQImbalance 0xc2c ++ ++#define rOFDM0_RxDetector1 0xc30 //PD,BW & SBD // DM tune init gain ++#define rOFDM0_RxDetector2 0xc34 //SBD & Fame Sync. ++#define rOFDM0_RxDetector3 0xc38 //Frame Sync. ++#define rOFDM0_RxDetector4 0xc3c //PD, SBD, Frame Sync & Short-GI ++ ++#define rOFDM0_RxDSP 0xc40 //Rx Sync Path ++#define rOFDM0_CFOandDAGC 0xc44 //CFO & DAGC ++#define rOFDM0_CCADropThreshold 0xc48 //CCA Drop threshold ++#define rOFDM0_ECCAThreshold 0xc4c // energy CCA ++ ++#define rOFDM0_XAAGCCore1 0xc50 // DIG ++#define rOFDM0_XAAGCCore2 0xc54 ++#define rOFDM0_XBAGCCore1 0xc58 ++#define rOFDM0_XBAGCCore2 0xc5c ++#define rOFDM0_XCAGCCore1 0xc60 ++#define rOFDM0_XCAGCCore2 0xc64 ++#define rOFDM0_XDAGCCore1 0xc68 ++#define rOFDM0_XDAGCCore2 0xc6c ++ ++#define rOFDM0_AGCParameter1 0xc70 ++#define rOFDM0_AGCParameter2 0xc74 ++#define rOFDM0_AGCRSSITable 0xc78 ++#define rOFDM0_HTSTFAGC 0xc7c ++ ++#define rOFDM0_XATxIQImbalance 0xc80 // TX PWR TRACK and DIG ++#define rOFDM0_XATxAFE 0xc84 ++#define rOFDM0_XBTxIQImbalance 0xc88 ++#define rOFDM0_XBTxAFE 0xc8c ++#define rOFDM0_XCTxIQImbalance 0xc90 ++#define rOFDM0_XCTxAFE 0xc94 ++#define rOFDM0_XDTxIQImbalance 0xc98 ++#define rOFDM0_XDTxAFE 0xc9c ++ ++#define rOFDM0_RxIQExtAnta 0xca0 ++#define rOFDM0_TxCoeff1 0xca4 ++#define rOFDM0_TxCoeff2 0xca8 ++#define rOFDM0_TxCoeff3 0xcac ++#define rOFDM0_TxCoeff4 0xcb0 ++#define rOFDM0_TxCoeff5 0xcb4 ++#define rOFDM0_TxCoeff6 0xcb8 ++#define rOFDM0_RxHPParameter 0xce0 ++#define rOFDM0_TxPseudoNoiseWgt 0xce4 ++#define rOFDM0_FrameSync 0xcf0 ++#define rOFDM0_DFSReport 0xcf4 ++ ++// ++// 7. PageD(0xD00) ++// ++#define rOFDM1_LSTF 0xd00 ++#define rOFDM1_TRxPathEnable 0xd04 ++ ++#define rOFDM1_CFO 0xd08 // No setting now ++#define rOFDM1_CSI1 0xd10 ++#define rOFDM1_SBD 0xd14 ++#define rOFDM1_CSI2 0xd18 ++#define rOFDM1_CFOTracking 0xd2c ++#define rOFDM1_TRxMesaure1 0xd34 ++#define rOFDM1_IntfDet 0xd3c ++#define rOFDM1_PseudoNoiseStateAB 0xd50 ++#define rOFDM1_PseudoNoiseStateCD 0xd54 ++#define rOFDM1_RxPseudoNoiseWgt 0xd58 ++ ++#define rOFDM_PHYCounter1 0xda0 //cca, parity fail ++#define rOFDM_PHYCounter2 0xda4 //rate illegal, crc8 fail ++#define rOFDM_PHYCounter3 0xda8 //MCS not support ++ ++#define rOFDM_ShortCFOAB 0xdac // No setting now ++#define rOFDM_ShortCFOCD 0xdb0 ++#define rOFDM_LongCFOAB 0xdb4 ++#define rOFDM_LongCFOCD 0xdb8 ++#define rOFDM_TailCFOAB 0xdbc ++#define rOFDM_TailCFOCD 0xdc0 ++#define rOFDM_PWMeasure1 0xdc4 ++#define rOFDM_PWMeasure2 0xdc8 ++#define rOFDM_BWReport 0xdcc ++#define rOFDM_AGCReport 0xdd0 ++#define rOFDM_RxSNR 0xdd4 ++#define rOFDM_RxEVMCSI 0xdd8 ++#define rOFDM_SIGReport 0xddc ++ ++ ++// ++// 8. PageE(0xE00) ++// ++#define rTxAGC_A_Rate18_06 0xe00 ++#define rTxAGC_A_Rate54_24 0xe04 ++#define rTxAGC_A_CCK1_Mcs32 0xe08 ++#define rTxAGC_A_Mcs03_Mcs00 0xe10 ++#define rTxAGC_A_Mcs07_Mcs04 0xe14 ++#define rTxAGC_A_Mcs11_Mcs08 0xe18 ++#define rTxAGC_A_Mcs15_Mcs12 0xe1c ++ ++#define rTxAGC_B_Rate18_06 0x830 ++#define rTxAGC_B_Rate54_24 0x834 ++#define rTxAGC_B_CCK1_55_Mcs32 0x838 ++#define rTxAGC_B_Mcs03_Mcs00 0x83c ++#define rTxAGC_B_Mcs07_Mcs04 0x848 ++#define rTxAGC_B_Mcs11_Mcs08 0x84c ++#define rTxAGC_B_Mcs15_Mcs12 0x868 ++#define rTxAGC_B_CCK11_A_CCK2_11 0x86c ++ ++#define rFPGA0_IQK 0xe28 ++#define rTx_IQK_Tone_A 0xe30 ++#define rRx_IQK_Tone_A 0xe34 ++#define rTx_IQK_PI_A 0xe38 ++#define rRx_IQK_PI_A 0xe3c ++ ++#define rTx_IQK 0xe40 ++#define rRx_IQK 0xe44 ++#define rIQK_AGC_Pts 0xe48 ++#define rIQK_AGC_Rsp 0xe4c ++#define rTx_IQK_Tone_B 0xe50 ++#define rRx_IQK_Tone_B 0xe54 ++#define rTx_IQK_PI_B 0xe58 ++#define rRx_IQK_PI_B 0xe5c ++#define rIQK_AGC_Cont 0xe60 ++ ++#define rBlue_Tooth 0xe6c ++#define rRx_Wait_CCA 0xe70 ++#define rTx_CCK_RFON 0xe74 ++#define rTx_CCK_BBON 0xe78 ++#define rTx_OFDM_RFON 0xe7c ++#define rTx_OFDM_BBON 0xe80 ++#define rTx_To_Rx 0xe84 ++#define rTx_To_Tx 0xe88 ++#define rRx_CCK 0xe8c ++ ++#define rTx_Power_Before_IQK_A 0xe94 ++#define rTx_Power_After_IQK_A 0xe9c ++ ++#define rRx_Power_Before_IQK_A 0xea0 ++#define rRx_Power_Before_IQK_A_2 0xea4 ++#define rRx_Power_After_IQK_A 0xea8 ++#define rRx_Power_After_IQK_A_2 0xeac ++ ++#define rTx_Power_Before_IQK_B 0xeb4 ++#define rTx_Power_After_IQK_B 0xebc ++ ++#define rRx_Power_Before_IQK_B 0xec0 ++#define rRx_Power_Before_IQK_B_2 0xec4 ++#define rRx_Power_After_IQK_B 0xec8 ++#define rRx_Power_After_IQK_B_2 0xecc ++ ++#define rRx_OFDM 0xed0 ++#define rRx_Wait_RIFS 0xed4 ++#define rRx_TO_Rx 0xed8 ++#define rStandby 0xedc ++#define rSleep 0xee0 ++#define rPMPD_ANAEN 0xeec ++ ++// ++// 7. RF Register 0x00-0x2E (RF 8256) ++// RF-0222D 0x00-3F ++// ++//Zebra1 ++#define rZebra1_HSSIEnable 0x0 // Useless now ++#define rZebra1_TRxEnable1 0x1 ++#define rZebra1_TRxEnable2 0x2 ++#define rZebra1_AGC 0x4 ++#define rZebra1_ChargePump 0x5 ++#define rZebra1_Channel 0x7 // RF channel switch ++ ++//#endif ++#define rZebra1_TxGain 0x8 // Useless now ++#define rZebra1_TxLPF 0x9 ++#define rZebra1_RxLPF 0xb ++#define rZebra1_RxHPFCorner 0xc ++ ++//Zebra4 ++#define rGlobalCtrl 0 // Useless now ++#define rRTL8256_TxLPF 19 ++#define rRTL8256_RxLPF 11 ++ ++//RTL8258 ++#define rRTL8258_TxLPF 0x11 // Useless now ++#define rRTL8258_RxLPF 0x13 ++#define rRTL8258_RSSILPF 0xa ++ ++// ++// RL6052 Register definition ++// ++#define RF_AC 0x00 // ++ ++#define RF_IQADJ_G1 0x01 // ++#define RF_IQADJ_G2 0x02 // ++#define RF_BS_PA_APSET_G1_G4 0x03 ++#define RF_BS_PA_APSET_G5_G8 0x04 ++#define RF_POW_TRSW 0x05 // ++ ++#define RF_GAIN_RX 0x06 // ++#define RF_GAIN_TX 0x07 // ++ ++#define RF_TXM_IDAC 0x08 // ++#define RF_IPA_G 0x09 // ++#define RF_TXBIAS_G 0x0A ++#define RF_TXPA_AG 0x0B ++#define RF_IPA_A 0x0C // ++#define RF_TXBIAS_A 0x0D ++#define RF_BS_PA_APSET_G9_G11 0x0E ++#define RF_BS_IQGEN 0x0F // ++ ++#define RF_MODE1 0x10 // ++#define RF_MODE2 0x11 // ++ ++#define RF_RX_AGC_HP 0x12 // ++#define RF_TX_AGC 0x13 // ++#define RF_BIAS 0x14 // ++#define RF_IPA 0x15 // ++#define RF_TXBIAS 0x16 // ++#define RF_POW_ABILITY 0x17 // ++#define RF_MODE_AG 0x18 // ++#define rRfChannel 0x18 // RF channel and BW switch ++#define RF_CHNLBW 0x18 // RF channel and BW switch ++#define RF_TOP 0x19 // ++ ++#define RF_RX_G1 0x1A // ++#define RF_RX_G2 0x1B // ++ ++#define RF_RX_BB2 0x1C // ++#define RF_RX_BB1 0x1D // ++ ++#define RF_RCK1 0x1E // ++#define RF_RCK2 0x1F // ++ ++#define RF_TX_G1 0x20 // ++#define RF_TX_G2 0x21 // ++#define RF_TX_G3 0x22 // ++ ++#define RF_TX_BB1 0x23 // ++ ++#define RF_T_METER 0x42 // ++ ++#define RF_SYN_G1 0x25 // RF TX Power control ++#define RF_SYN_G2 0x26 // RF TX Power control ++#define RF_SYN_G3 0x27 // RF TX Power control ++#define RF_SYN_G4 0x28 // RF TX Power control ++#define RF_SYN_G5 0x29 // RF TX Power control ++#define RF_SYN_G6 0x2A // RF TX Power control ++#define RF_SYN_G7 0x2B // RF TX Power control ++#define RF_SYN_G8 0x2C // RF TX Power control ++ ++#define RF_RCK_OS 0x30 // RF TX PA control ++ ++#define RF_TXPA_G1 0x31 // RF TX PA control ++#define RF_TXPA_G2 0x32 // RF TX PA control ++#define RF_TXPA_G3 0x33 // RF TX PA control ++#define RF_LOBF_9 0x38 ++#define RF_RXRF_A3 0x3C // ++#define RF_TRSW 0x3F ++ ++#define RF_TXRF_A2 0x41 ++#define RF_TXPA_G4 0x46 ++#define RF_TXPA_A4 0x4B ++ ++// ++//Bit Mask ++// ++// 1. Page1(0x100) ++#define bBBResetB 0x100 // Useless now? ++#define bGlobalResetB 0x200 ++#define bOFDMTxStart 0x4 ++#define bCCKTxStart 0x8 ++#define bCRC32Debug 0x100 ++#define bPMACLoopback 0x10 ++#define bTxLSIG 0xffffff ++#define bOFDMTxRate 0xf ++#define bOFDMTxReserved 0x10 ++#define bOFDMTxLength 0x1ffe0 ++#define bOFDMTxParity 0x20000 ++#define bTxHTSIG1 0xffffff ++#define bTxHTMCSRate 0x7f ++#define bTxHTBW 0x80 ++#define bTxHTLength 0xffff00 ++#define bTxHTSIG2 0xffffff ++#define bTxHTSmoothing 0x1 ++#define bTxHTSounding 0x2 ++#define bTxHTReserved 0x4 ++#define bTxHTAggreation 0x8 ++#define bTxHTSTBC 0x30 ++#define bTxHTAdvanceCoding 0x40 ++#define bTxHTShortGI 0x80 ++#define bTxHTNumberHT_LTF 0x300 ++#define bTxHTCRC8 0x3fc00 ++#define bCounterReset 0x10000 ++#define bNumOfOFDMTx 0xffff ++#define bNumOfCCKTx 0xffff0000 ++#define bTxIdleInterval 0xffff ++#define bOFDMService 0xffff0000 ++#define bTxMACHeader 0xffffffff ++#define bTxDataInit 0xff ++#define bTxHTMode 0x100 ++#define bTxDataType 0x30000 ++#define bTxRandomSeed 0xffffffff ++#define bCCKTxPreamble 0x1 ++#define bCCKTxSFD 0xffff0000 ++#define bCCKTxSIG 0xff ++#define bCCKTxService 0xff00 ++#define bCCKLengthExt 0x8000 ++#define bCCKTxLength 0xffff0000 ++#define bCCKTxCRC16 0xffff ++#define bCCKTxStatus 0x1 ++#define bOFDMTxStatus 0x2 ++ ++#define IS_BB_REG_OFFSET_92S(_Offset) ((_Offset >= 0x800) && (_Offset <= 0xfff)) ++ ++// 2. Page8(0x800) ++#define bRFMOD 0x1 // Reg 0x800 rFPGA0_RFMOD ++#define bJapanMode 0x2 ++#define bCCKTxSC 0x30 ++#define bCCKEn 0x1000000 ++#define bOFDMEn 0x2000000 ++ ++#define bOFDMRxADCPhase 0x10000 // Useless now ++#define bOFDMTxDACPhase 0x40000 ++#define bXATxAGC 0x3f ++ ++#define bAntennaSelect 0x0300 ++ ++#define bXBTxAGC 0xf00 // Reg 80c rFPGA0_TxGainStage ++#define bXCTxAGC 0xf000 ++#define bXDTxAGC 0xf0000 ++ ++#define bPAStart 0xf0000000 // Useless now ++#define bTRStart 0x00f00000 ++#define bRFStart 0x0000f000 ++#define bBBStart 0x000000f0 ++#define bBBCCKStart 0x0000000f ++#define bPAEnd 0xf //Reg0x814 ++#define bTREnd 0x0f000000 ++#define bRFEnd 0x000f0000 ++#define bCCAMask 0x000000f0 //T2R ++#define bR2RCCAMask 0x00000f00 ++#define bHSSI_R2TDelay 0xf8000000 ++#define bHSSI_T2RDelay 0xf80000 ++#define bContTxHSSI 0x400 //chane gain at continue Tx ++#define bIGFromCCK 0x200 ++#define bAGCAddress 0x3f ++#define bRxHPTx 0x7000 ++#define bRxHPT2R 0x38000 ++#define bRxHPCCKIni 0xc0000 ++#define bAGCTxCode 0xc00000 ++#define bAGCRxCode 0x300000 ++ ++#define b3WireDataLength 0x800 // Reg 0x820~84f rFPGA0_XA_HSSIParameter1 ++#define b3WireAddressLength 0x400 ++ ++#define b3WireRFPowerDown 0x1 // Useless now ++//#define bHWSISelect 0x8 ++#define b5GPAPEPolarity 0x40000000 ++#define b2GPAPEPolarity 0x80000000 ++#define bRFSW_TxDefaultAnt 0x3 ++#define bRFSW_TxOptionAnt 0x30 ++#define bRFSW_RxDefaultAnt 0x300 ++#define bRFSW_RxOptionAnt 0x3000 ++#define bRFSI_3WireData 0x1 ++#define bRFSI_3WireClock 0x2 ++#define bRFSI_3WireLoad 0x4 ++#define bRFSI_3WireRW 0x8 ++#define bRFSI_3Wire 0xf ++ ++#define bRFSI_RFENV 0x10 // Reg 0x870 rFPGA0_XAB_RFInterfaceSW ++ ++#define bRFSI_TRSW 0x20 // Useless now ++#define bRFSI_TRSWB 0x40 ++#define bRFSI_ANTSW 0x100 ++#define bRFSI_ANTSWB 0x200 ++#define bRFSI_PAPE 0x400 ++#define bRFSI_PAPE5G 0x800 ++#define bBandSelect 0x1 ++#define bHTSIG2_GI 0x80 ++#define bHTSIG2_Smoothing 0x01 ++#define bHTSIG2_Sounding 0x02 ++#define bHTSIG2_Aggreaton 0x08 ++#define bHTSIG2_STBC 0x30 ++#define bHTSIG2_AdvCoding 0x40 ++#define bHTSIG2_NumOfHTLTF 0x300 ++#define bHTSIG2_CRC8 0x3fc ++#define bHTSIG1_MCS 0x7f ++#define bHTSIG1_BandWidth 0x80 ++#define bHTSIG1_HTLength 0xffff ++#define bLSIG_Rate 0xf ++#define bLSIG_Reserved 0x10 ++#define bLSIG_Length 0x1fffe ++#define bLSIG_Parity 0x20 ++#define bCCKRxPhase 0x4 ++ ++#define bLSSIReadAddress 0x7f800000 // T65 RF ++ ++#define bLSSIReadEdge 0x80000000 //LSSI "Read" edge signal ++ ++#define bLSSIReadBackData 0xfffff // T65 RF ++ ++#define bLSSIReadOKFlag 0x1000 // Useless now ++#define bCCKSampleRate 0x8 //0: 44MHz, 1:88MHz ++#define bRegulator0Standby 0x1 ++#define bRegulatorPLLStandby 0x2 ++#define bRegulator1Standby 0x4 ++#define bPLLPowerUp 0x8 ++#define bDPLLPowerUp 0x10 ++#define bDA10PowerUp 0x20 ++#define bAD7PowerUp 0x200 ++#define bDA6PowerUp 0x2000 ++#define bXtalPowerUp 0x4000 ++#define b40MDClkPowerUP 0x8000 ++#define bDA6DebugMode 0x20000 ++#define bDA6Swing 0x380000 ++ ++#define bADClkPhase 0x4000000 // Reg 0x880 rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ ++ ++#define b80MClkDelay 0x18000000 // Useless ++#define bAFEWatchDogEnable 0x20000000 ++ ++#define bXtalCap01 0xc0000000 // Reg 0x884 rFPGA0_AnalogParameter2 Crystal cap ++#define bXtalCap23 0x3 ++#define bXtalCap92x 0x0f000000 ++#define bXtalCap 0x0f000000 ++ ++#define bIntDifClkEnable 0x400 // Useless ++#define bExtSigClkEnable 0x800 ++#define bBandgapMbiasPowerUp 0x10000 ++#define bAD11SHGain 0xc0000 ++#define bAD11InputRange 0x700000 ++#define bAD11OPCurrent 0x3800000 ++#define bIPathLoopback 0x4000000 ++#define bQPathLoopback 0x8000000 ++#define bAFELoopback 0x10000000 ++#define bDA10Swing 0x7e0 ++#define bDA10Reverse 0x800 ++#define bDAClkSource 0x1000 ++#define bAD7InputRange 0x6000 ++#define bAD7Gain 0x38000 ++#define bAD7OutputCMMode 0x40000 ++#define bAD7InputCMMode 0x380000 ++#define bAD7Current 0xc00000 ++#define bRegulatorAdjust 0x7000000 ++#define bAD11PowerUpAtTx 0x1 ++#define bDA10PSAtTx 0x10 ++#define bAD11PowerUpAtRx 0x100 ++#define bDA10PSAtRx 0x1000 ++#define bCCKRxAGCFormat 0x200 ++#define bPSDFFTSamplepPoint 0xc000 ++#define bPSDAverageNum 0x3000 ++#define bIQPathControl 0xc00 ++#define bPSDFreq 0x3ff ++#define bPSDAntennaPath 0x30 ++#define bPSDIQSwitch 0x40 ++#define bPSDRxTrigger 0x400000 ++#define bPSDTxTrigger 0x80000000 ++#define bPSDSineToneScale 0x7f000000 ++#define bPSDReport 0xffff ++ ++// 3. Page9(0x900) ++#define bOFDMTxSC 0x30000000 // Useless ++#define bCCKTxOn 0x1 ++#define bOFDMTxOn 0x2 ++#define bDebugPage 0xfff //reset debug page and also HWord, LWord ++#define bDebugItem 0xff //reset debug page and LWord ++#define bAntL 0x10 ++#define bAntNonHT 0x100 ++#define bAntHT1 0x1000 ++#define bAntHT2 0x10000 ++#define bAntHT1S1 0x100000 ++#define bAntNonHTS1 0x1000000 ++ ++// 4. PageA(0xA00) ++#define bCCKBBMode 0x3 // Useless ++#define bCCKTxPowerSaving 0x80 ++#define bCCKRxPowerSaving 0x40 ++ ++#define bCCKSideBand 0x10 // Reg 0xa00 rCCK0_System 20/40 switch ++ ++#define bCCKScramble 0x8 // Useless ++#define bCCKAntDiversity 0x8000 ++#define bCCKCarrierRecovery 0x4000 ++#define bCCKTxRate 0x3000 ++#define bCCKDCCancel 0x0800 ++#define bCCKISICancel 0x0400 ++#define bCCKMatchFilter 0x0200 ++#define bCCKEqualizer 0x0100 ++#define bCCKPreambleDetect 0x800000 ++#define bCCKFastFalseCCA 0x400000 ++#define bCCKChEstStart 0x300000 ++#define bCCKCCACount 0x080000 ++#define bCCKcs_lim 0x070000 ++#define bCCKBistMode 0x80000000 ++#define bCCKCCAMask 0x40000000 ++#define bCCKTxDACPhase 0x4 ++#define bCCKRxADCPhase 0x20000000 //r_rx_clk ++#define bCCKr_cp_mode0 0x0100 ++#define bCCKTxDCOffset 0xf0 ++#define bCCKRxDCOffset 0xf ++#define bCCKCCAMode 0xc000 ++#define bCCKFalseCS_lim 0x3f00 ++#define bCCKCS_ratio 0xc00000 ++#define bCCKCorgBit_sel 0x300000 ++#define bCCKPD_lim 0x0f0000 ++#define bCCKNewCCA 0x80000000 ++#define bCCKRxHPofIG 0x8000 ++#define bCCKRxIG 0x7f00 ++#define bCCKLNAPolarity 0x800000 ++#define bCCKRx1stGain 0x7f0000 ++#define bCCKRFExtend 0x20000000 //CCK Rx Iinital gain polarity ++#define bCCKRxAGCSatLevel 0x1f000000 ++#define bCCKRxAGCSatCount 0xe0 ++#define bCCKRxRFSettle 0x1f //AGCsamp_dly ++#define bCCKFixedRxAGC 0x8000 ++//#define bCCKRxAGCFormat 0x4000 //remove to HSSI register 0x824 ++#define bCCKAntennaPolarity 0x2000 ++#define bCCKTxFilterType 0x0c00 ++#define bCCKRxAGCReportType 0x0300 ++#define bCCKRxDAGCEn 0x80000000 ++#define bCCKRxDAGCPeriod 0x20000000 ++#define bCCKRxDAGCSatLevel 0x1f000000 ++#define bCCKTimingRecovery 0x800000 ++#define bCCKTxC0 0x3f0000 ++#define bCCKTxC1 0x3f000000 ++#define bCCKTxC2 0x3f ++#define bCCKTxC3 0x3f00 ++#define bCCKTxC4 0x3f0000 ++#define bCCKTxC5 0x3f000000 ++#define bCCKTxC6 0x3f ++#define bCCKTxC7 0x3f00 ++#define bCCKDebugPort 0xff0000 ++#define bCCKDACDebug 0x0f000000 ++#define bCCKFalseAlarmEnable 0x8000 ++#define bCCKFalseAlarmRead 0x4000 ++#define bCCKTRSSI 0x7f ++#define bCCKRxAGCReport 0xfe ++#define bCCKRxReport_AntSel 0x80000000 ++#define bCCKRxReport_MFOff 0x40000000 ++#define bCCKRxRxReport_SQLoss 0x20000000 ++#define bCCKRxReport_Pktloss 0x10000000 ++#define bCCKRxReport_Lockedbit 0x08000000 ++#define bCCKRxReport_RateError 0x04000000 ++#define bCCKRxReport_RxRate 0x03000000 ++#define bCCKRxFACounterLower 0xff ++#define bCCKRxFACounterUpper 0xff000000 ++#define bCCKRxHPAGCStart 0xe000 ++#define bCCKRxHPAGCFinal 0x1c00 ++#define bCCKRxFalseAlarmEnable 0x8000 ++#define bCCKFACounterFreeze 0x4000 ++#define bCCKTxPathSel 0x10000000 ++#define bCCKDefaultRxPath 0xc000000 ++#define bCCKOptionRxPath 0x3000000 ++ ++// 5. PageC(0xC00) ++#define bNumOfSTF 0x3 // Useless ++#define bShift_L 0xc0 ++#define bGI_TH 0xc ++#define bRxPathA 0x1 ++#define bRxPathB 0x2 ++#define bRxPathC 0x4 ++#define bRxPathD 0x8 ++#define bTxPathA 0x1 ++#define bTxPathB 0x2 ++#define bTxPathC 0x4 ++#define bTxPathD 0x8 ++#define bTRSSIFreq 0x200 ++#define bADCBackoff 0x3000 ++#define bDFIRBackoff 0xc000 ++#define bTRSSILatchPhase 0x10000 ++#define bRxIDCOffset 0xff ++#define bRxQDCOffset 0xff00 ++#define bRxDFIRMode 0x1800000 ++#define bRxDCNFType 0xe000000 ++#define bRXIQImb_A 0x3ff ++#define bRXIQImb_B 0xfc00 ++#define bRXIQImb_C 0x3f0000 ++#define bRXIQImb_D 0xffc00000 ++#define bDC_dc_Notch 0x60000 ++#define bRxNBINotch 0x1f000000 ++#define bPD_TH 0xf ++#define bPD_TH_Opt2 0xc000 ++#define bPWED_TH 0x700 ++#define bIfMF_Win_L 0x800 ++#define bPD_Option 0x1000 ++#define bMF_Win_L 0xe000 ++#define bBW_Search_L 0x30000 ++#define bwin_enh_L 0xc0000 ++#define bBW_TH 0x700000 ++#define bED_TH2 0x3800000 ++#define bBW_option 0x4000000 ++#define bRatio_TH 0x18000000 ++#define bWindow_L 0xe0000000 ++#define bSBD_Option 0x1 ++#define bFrame_TH 0x1c ++#define bFS_Option 0x60 ++#define bDC_Slope_check 0x80 ++#define bFGuard_Counter_DC_L 0xe00 ++#define bFrame_Weight_Short 0x7000 ++#define bSub_Tune 0xe00000 ++#define bFrame_DC_Length 0xe000000 ++#define bSBD_start_offset 0x30000000 ++#define bFrame_TH_2 0x7 ++#define bFrame_GI2_TH 0x38 ++#define bGI2_Sync_en 0x40 ++#define bSarch_Short_Early 0x300 ++#define bSarch_Short_Late 0xc00 ++#define bSarch_GI2_Late 0x70000 ++#define bCFOAntSum 0x1 ++#define bCFOAcc 0x2 ++#define bCFOStartOffset 0xc ++#define bCFOLookBack 0x70 ++#define bCFOSumWeight 0x80 ++#define bDAGCEnable 0x10000 ++#define bTXIQImb_A 0x3ff ++#define bTXIQImb_B 0xfc00 ++#define bTXIQImb_C 0x3f0000 ++#define bTXIQImb_D 0xffc00000 ++#define bTxIDCOffset 0xff ++#define bTxQDCOffset 0xff00 ++#define bTxDFIRMode 0x10000 ++#define bTxPesudoNoiseOn 0x4000000 ++#define bTxPesudoNoise_A 0xff ++#define bTxPesudoNoise_B 0xff00 ++#define bTxPesudoNoise_C 0xff0000 ++#define bTxPesudoNoise_D 0xff000000 ++#define bCCADropOption 0x20000 ++#define bCCADropThres 0xfff00000 ++#define bEDCCA_H 0xf ++#define bEDCCA_L 0xf0 ++#define bLambda_ED 0x300 ++#define bRxInitialGain 0x7f ++#define bRxAntDivEn 0x80 ++#define bRxAGCAddressForLNA 0x7f00 ++#define bRxHighPowerFlow 0x8000 ++#define bRxAGCFreezeThres 0xc0000 ++#define bRxFreezeStep_AGC1 0x300000 ++#define bRxFreezeStep_AGC2 0xc00000 ++#define bRxFreezeStep_AGC3 0x3000000 ++#define bRxFreezeStep_AGC0 0xc000000 ++#define bRxRssi_Cmp_En 0x10000000 ++#define bRxQuickAGCEn 0x20000000 ++#define bRxAGCFreezeThresMode 0x40000000 ++#define bRxOverFlowCheckType 0x80000000 ++#define bRxAGCShift 0x7f ++#define bTRSW_Tri_Only 0x80 ++#define bPowerThres 0x300 ++#define bRxAGCEn 0x1 ++#define bRxAGCTogetherEn 0x2 ++#define bRxAGCMin 0x4 ++#define bRxHP_Ini 0x7 ++#define bRxHP_TRLNA 0x70 ++#define bRxHP_RSSI 0x700 ++#define bRxHP_BBP1 0x7000 ++#define bRxHP_BBP2 0x70000 ++#define bRxHP_BBP3 0x700000 ++#define bRSSI_H 0x7f0000 //the threshold for high power ++#define bRSSI_Gen 0x7f000000 //the threshold for ant diversity ++#define bRxSettle_TRSW 0x7 ++#define bRxSettle_LNA 0x38 ++#define bRxSettle_RSSI 0x1c0 ++#define bRxSettle_BBP 0xe00 ++#define bRxSettle_RxHP 0x7000 ++#define bRxSettle_AntSW_RSSI 0x38000 ++#define bRxSettle_AntSW 0xc0000 ++#define bRxProcessTime_DAGC 0x300000 ++#define bRxSettle_HSSI 0x400000 ++#define bRxProcessTime_BBPPW 0x800000 ++#define bRxAntennaPowerShift 0x3000000 ++#define bRSSITableSelect 0xc000000 ++#define bRxHP_Final 0x7000000 ++#define bRxHTSettle_BBP 0x7 ++#define bRxHTSettle_HSSI 0x8 ++#define bRxHTSettle_RxHP 0x70 ++#define bRxHTSettle_BBPPW 0x80 ++#define bRxHTSettle_Idle 0x300 ++#define bRxHTSettle_Reserved 0x1c00 ++#define bRxHTRxHPEn 0x8000 ++#define bRxHTAGCFreezeThres 0x30000 ++#define bRxHTAGCTogetherEn 0x40000 ++#define bRxHTAGCMin 0x80000 ++#define bRxHTAGCEn 0x100000 ++#define bRxHTDAGCEn 0x200000 ++#define bRxHTRxHP_BBP 0x1c00000 ++#define bRxHTRxHP_Final 0xe0000000 ++#define bRxPWRatioTH 0x3 ++#define bRxPWRatioEn 0x4 ++#define bRxMFHold 0x3800 ++#define bRxPD_Delay_TH1 0x38 ++#define bRxPD_Delay_TH2 0x1c0 ++#define bRxPD_DC_COUNT_MAX 0x600 ++//#define bRxMF_Hold 0x3800 ++#define bRxPD_Delay_TH 0x8000 ++#define bRxProcess_Delay 0xf0000 ++#define bRxSearchrange_GI2_Early 0x700000 ++#define bRxFrame_Guard_Counter_L 0x3800000 ++#define bRxSGI_Guard_L 0xc000000 ++#define bRxSGI_Search_L 0x30000000 ++#define bRxSGI_TH 0xc0000000 ++#define bDFSCnt0 0xff ++#define bDFSCnt1 0xff00 ++#define bDFSFlag 0xf0000 ++#define bMFWeightSum 0x300000 ++#define bMinIdxTH 0x7f000000 ++#define bDAFormat 0x40000 ++#define bTxChEmuEnable 0x01000000 ++#define bTRSWIsolation_A 0x7f ++#define bTRSWIsolation_B 0x7f00 ++#define bTRSWIsolation_C 0x7f0000 ++#define bTRSWIsolation_D 0x7f000000 ++#define bExtLNAGain 0x7c00 ++ ++// 6. PageE(0xE00) ++#define bSTBCEn 0x4 // Useless ++#define bAntennaMapping 0x10 ++#define bNss 0x20 ++#define bCFOAntSumD 0x200 ++#define bPHYCounterReset 0x8000000 ++#define bCFOReportGet 0x4000000 ++#define bOFDMContinueTx 0x10000000 ++#define bOFDMSingleCarrier 0x20000000 ++#define bOFDMSingleTone 0x40000000 ++//#define bRxPath1 0x01 ++//#define bRxPath2 0x02 ++//#define bRxPath3 0x04 ++//#define bRxPath4 0x08 ++//#define bTxPath1 0x10 ++//#define bTxPath2 0x20 ++#define bHTDetect 0x100 ++#define bCFOEn 0x10000 ++#define bCFOValue 0xfff00000 ++#define bSigTone_Re 0x3f ++#define bSigTone_Im 0x7f00 ++#define bCounter_CCA 0xffff ++#define bCounter_ParityFail 0xffff0000 ++#define bCounter_RateIllegal 0xffff ++#define bCounter_CRC8Fail 0xffff0000 ++#define bCounter_MCSNoSupport 0xffff ++#define bCounter_FastSync 0xffff ++#define bShortCFO 0xfff ++#define bShortCFOTLength 12 //total ++#define bShortCFOFLength 11 //fraction ++#define bLongCFO 0x7ff ++#define bLongCFOTLength 11 ++#define bLongCFOFLength 11 ++#define bTailCFO 0x1fff ++#define bTailCFOTLength 13 ++#define bTailCFOFLength 12 ++#define bmax_en_pwdB 0xffff ++#define bCC_power_dB 0xffff0000 ++#define bnoise_pwdB 0xffff ++#define bPowerMeasTLength 10 ++#define bPowerMeasFLength 3 ++#define bRx_HT_BW 0x1 ++#define bRxSC 0x6 ++#define bRx_HT 0x8 ++#define bNB_intf_det_on 0x1 ++#define bIntf_win_len_cfg 0x30 ++#define bNB_Intf_TH_cfg 0x1c0 ++#define bRFGain 0x3f ++#define bTableSel 0x40 ++#define bTRSW 0x80 ++#define bRxSNR_A 0xff ++#define bRxSNR_B 0xff00 ++#define bRxSNR_C 0xff0000 ++#define bRxSNR_D 0xff000000 ++#define bSNREVMTLength 8 ++#define bSNREVMFLength 1 ++#define bCSI1st 0xff ++#define bCSI2nd 0xff00 ++#define bRxEVM1st 0xff0000 ++#define bRxEVM2nd 0xff000000 ++#define bSIGEVM 0xff ++#define bPWDB 0xff00 ++#define bSGIEN 0x10000 ++ ++#define bSFactorQAM1 0xf // Useless ++#define bSFactorQAM2 0xf0 ++#define bSFactorQAM3 0xf00 ++#define bSFactorQAM4 0xf000 ++#define bSFactorQAM5 0xf0000 ++#define bSFactorQAM6 0xf0000 ++#define bSFactorQAM7 0xf00000 ++#define bSFactorQAM8 0xf000000 ++#define bSFactorQAM9 0xf0000000 ++#define bCSIScheme 0x100000 ++ ++#define bNoiseLvlTopSet 0x3 // Useless ++#define bChSmooth 0x4 ++#define bChSmoothCfg1 0x38 ++#define bChSmoothCfg2 0x1c0 ++#define bChSmoothCfg3 0xe00 ++#define bChSmoothCfg4 0x7000 ++#define bMRCMode 0x800000 ++#define bTHEVMCfg 0x7000000 ++ ++#define bLoopFitType 0x1 // Useless ++#define bUpdCFO 0x40 ++#define bUpdCFOOffData 0x80 ++#define bAdvUpdCFO 0x100 ++#define bAdvTimeCtrl 0x800 ++#define bUpdClko 0x1000 ++#define bFC 0x6000 ++#define bTrackingMode 0x8000 ++#define bPhCmpEnable 0x10000 ++#define bUpdClkoLTF 0x20000 ++#define bComChCFO 0x40000 ++#define bCSIEstiMode 0x80000 ++#define bAdvUpdEqz 0x100000 ++#define bUChCfg 0x7000000 ++#define bUpdEqz 0x8000000 ++ ++//Rx Pseduo noise ++#define bRxPesudoNoiseOn 0x20000000 // Useless ++#define bRxPesudoNoise_A 0xff ++#define bRxPesudoNoise_B 0xff00 ++#define bRxPesudoNoise_C 0xff0000 ++#define bRxPesudoNoise_D 0xff000000 ++#define bPesudoNoiseState_A 0xffff ++#define bPesudoNoiseState_B 0xffff0000 ++#define bPesudoNoiseState_C 0xffff ++#define bPesudoNoiseState_D 0xffff0000 ++ ++//7. RF Register ++//Zebra1 ++#define bZebra1_HSSIEnable 0x8 // Useless ++#define bZebra1_TRxControl 0xc00 ++#define bZebra1_TRxGainSetting 0x07f ++#define bZebra1_RxCorner 0xc00 ++#define bZebra1_TxChargePump 0x38 ++#define bZebra1_RxChargePump 0x7 ++#define bZebra1_ChannelNum 0xf80 ++#define bZebra1_TxLPFBW 0x400 ++#define bZebra1_RxLPFBW 0x600 ++ ++//Zebra4 ++#define bRTL8256RegModeCtrl1 0x100 // Useless ++#define bRTL8256RegModeCtrl0 0x40 ++#define bRTL8256_TxLPFBW 0x18 ++#define bRTL8256_RxLPFBW 0x600 ++ ++//RTL8258 ++#define bRTL8258_TxLPFBW 0xc // Useless ++#define bRTL8258_RxLPFBW 0xc00 ++#define bRTL8258_RSSILPFBW 0xc0 ++ ++ ++// ++// Other Definition ++// ++ ++//byte endable for sb_write ++#define bByte0 0x1 // Useless ++#define bByte1 0x2 ++#define bByte2 0x4 ++#define bByte3 0x8 ++#define bWord0 0x3 ++#define bWord1 0xc ++#define bDWord 0xf ++ ++//for PutRegsetting & GetRegSetting BitMask ++#define bMaskByte0 0xff // Reg 0xc50 rOFDM0_XAAGCCore~0xC6f ++#define bMaskByte1 0xff00 ++#define bMaskByte2 0xff0000 ++#define bMaskByte3 0xff000000 ++#define bMaskHWord 0xffff0000 ++#define bMaskLWord 0x0000ffff ++#define bMaskDWord 0xffffffff ++#define bMask12Bits 0xfff ++#define bMaskH4Bits 0xf0000000 ++#define bMaskOFDM_D 0xffc00000 ++#define bMaskCCK 0x3f3f3f3f ++ ++//for PutRFRegsetting & GetRFRegSetting BitMask ++//#define bMask12Bits 0xfffff // RF Reg mask bits ++//#define bMask20Bits 0xfffff // RF Reg mask bits T65 RF ++#define bRFRegOffsetMask 0xfffff ++//#define bRFRegOffsetMask 0xfff ++ ++//MAC0 will wirte PHY1 ++#define MAC0_ACCESS_PHY1 0x4000 ++//MAC1 will wirte PHY0 ++#define MAC1_ACCESS_PHY0 0x2000 ++ ++#define bEnable 0x1 // Useless ++#define bDisable 0x0 ++ ++#define LeftAntenna 0x0 // Useless ++#define RightAntenna 0x1 ++ ++#define tCheckTxStatus 500 //500ms // Useless ++#define tUpdateRxCounter 100 //100ms ++ ++#define rateCCK 0 // Useless ++#define rateOFDM 1 ++#define rateHT 2 ++ ++//define Register-End ++#define bPMAC_End 0x1ff // Useless ++#define bFPGAPHY0_End 0x8ff ++#define bFPGAPHY1_End 0x9ff ++#define bCCKPHY0_End 0xaff ++#define bOFDMPHY0_End 0xcff ++#define bOFDMPHY1_End 0xdff ++ ++//define max debug item in each debug page ++//#define bMaxItem_FPGA_PHY0 0x9 ++//#define bMaxItem_FPGA_PHY1 0x3 ++//#define bMaxItem_PHY_11B 0x16 ++//#define bMaxItem_OFDM_PHY0 0x29 ++//#define bMaxItem_OFDM_PHY1 0x0 ++ ++#define bPMACControl 0x0 // Useless ++#define bWMACControl 0x1 ++#define bWNICControl 0x2 ++ ++#define PathA 0x0 // Useless ++#define PathB 0x1 ++#define PathC 0x2 ++#define PathD 0x3 ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++ ++#endif //__INC_HAL8192SPHYREG_H ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/Hal8723APhyCfg.h b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8723APhyCfg.h +new file mode 100644 +index 00000000..3ec89725 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8723APhyCfg.h +@@ -0,0 +1,30 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __INC_HAL8723PHYCFG_H__ ++#define __INC_HAL8723PHYCFG_H__ ++ ++#include ++/* MAC/BB/RF HAL config */ ++int PHY_BBConfig8723A( IN PADAPTER Adapter ); ++int PHY_RFConfig8723A( IN PADAPTER Adapter ); ++s32 PHY_MACConfig8723A(PADAPTER padapter); ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/Hal8723APhyReg.h b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8723APhyReg.h +new file mode 100644 +index 00000000..7b244b4d +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8723APhyReg.h +@@ -0,0 +1,74 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __INC_HAL8723APHYREG_H__ ++#define __INC_HAL8723APHYREG_H__ ++ ++#include ++ ++// ++// PageB(0xB00) ++// ++#define rPdp_AntA 0xb00 ++#define rPdp_AntA_4 0xb04 ++#define rPdp_AntA_8 0xb08 ++#define rPdp_AntA_C 0xb0c ++#define rPdp_AntA_10 0xb10 ++#define rPdp_AntA_14 0xb14 ++#define rPdp_AntA_18 0xb18 ++#define rPdp_AntA_1C 0xb1c ++#define rPdp_AntA_20 0xb20 ++#define rPdp_AntA_24 0xb24 ++ ++#define rConfig_Pmpd_AntA 0xb28 ++#define rConfig_ram64x16 0xb2c ++ ++#define rBndA 0xb30 ++#define rHssiPar 0xb34 ++ ++#define rConfig_AntA 0xb68 ++#define rConfig_AntB 0xb6c ++ ++#define rPdp_AntB 0xb70 ++#define rPdp_AntB_4 0xb74 ++#define rPdp_AntB_8 0xb78 ++#define rPdp_AntB_C 0xb7c ++#define rPdp_AntB_10 0xb80 ++#define rPdp_AntB_14 0xb84 ++#define rPdp_AntB_18 0xb88 ++#define rPdp_AntB_1C 0xb8c ++#define rPdp_AntB_20 0xb90 ++#define rPdp_AntB_24 0xb94 ++ ++#define rConfig_Pmpd_AntB 0xb98 ++ ++#define rBndB 0xba0 ++ ++#define rAPK 0xbd8 ++#define rPm_Rx0_AntA 0xbdc ++#define rPm_Rx1_AntA 0xbe0 ++#define rPm_Rx2_AntA 0xbe4 ++#define rPm_Rx3_AntA 0xbe8 ++#define rPm_Rx0_AntB 0xbec ++#define rPm_Rx1_AntB 0xbf0 ++#define rPm_Rx2_AntB 0xbf4 ++#define rPm_Rx3_AntB 0xbf8 ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/Hal8723PwrSeq.h b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8723PwrSeq.h +new file mode 100644 +index 00000000..ab1c32a0 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/Hal8723PwrSeq.h +@@ -0,0 +1,171 @@ ++#ifndef __HAL8723PWRSEQ_H__ ++#define __HAL8723PWRSEQ_H__ ++/* ++ Check document WM-20110607-Paul-RTL8723A_Power_Architecture-R02.vsd ++ There are 6 HW Power States: ++ 0: POFF--Power Off ++ 1: PDN--Power Down ++ 2: CARDEMU--Card Emulation ++ 3: ACT--Active Mode ++ 4: LPS--Low Power State ++ 5: SUS--Suspend ++ ++ The transision from different states are defined below ++ TRANS_CARDEMU_TO_ACT ++ TRANS_ACT_TO_CARDEMU ++ TRANS_CARDEMU_TO_SUS ++ TRANS_SUS_TO_CARDEMU ++ TRANS_CARDEMU_TO_PDN ++ TRANS_ACT_TO_LPS ++ TRANS_LPS_TO_ACT ++ ++ TRANS_END ++*/ ++#include "HalPwrSeqCmd.h" ++#include "rtl8723a_spec.h" ++ ++#define RTL8723A_TRANS_CARDEMU_TO_ACT_STEPS 15 ++#define RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS 15 ++#define RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS 15 ++#define RTL8723A_TRANS_SUS_TO_CARDEMU_STEPS 15 ++#define RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS 15 ++#define RTL8723A_TRANS_PDN_TO_CARDEMU_STEPS 15 ++#define RTL8723A_TRANS_ACT_TO_LPS_STEPS 15 ++#define RTL8723A_TRANS_LPS_TO_ACT_STEPS 15 ++#define RTL8723A_TRANS_END_STEPS 1 ++ ++ ++#define RTL8723A_TRANS_CARDEMU_TO_ACT \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, BIT0}, /*0x20[0] = 1b'1 enable LDOA12 MACRO block for all interface*/ \ ++ {0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, 0}, /*0x67[0] = 0 to disable BT_GPS_SEL pins*/ \ ++ {0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS},/*Delay 1ms*/ \ ++ {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT5, 0}, /*0x00[5] = 1b'0 release analog Ips to digital ,1:isolation*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT2, 0},/* disable SW LPS 0x04[10]=0*/ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, BIT1, BIT1},/* wait till 0x04[17] = 1 power ready*/ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, BIT0},/* release WLON reset 0x04[16]=1*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, 0},/* disable HWPDN 0x04[15]=0*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, (BIT4|BIT3), 0},/* disable WL suspend*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, BIT0},/* polling until return 0*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, BIT0, 0},/**/ \ ++ {0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, 1},/*0x4C[23] = 0x4E[7] = 1, switch DPDT_SEL_P output from WL BB */\ ++ ++#define RTL8723A_TRANS_ACT_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0},/*0x1F[7:0] = 0 turn off RF*/ \ ++ {0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, 0},/*0x4C[23] = 0x4E[7] = 0, switch DPDT_SEL_P output from register 0x65[2] */\ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, BIT1}, /*0x04[9] = 1 turn off MAC by HW state machine*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, BIT1, 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/ \ ++ {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT5, BIT5}, /*0x00[5] = 1b'1 analog Ips to digital ,1:isolation*/ \ ++ {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, 0}, /*0x20[0] = 1b'0 disable LDOA12 MACRO block*/ \ ++ ++ ++#define RTL8723A_TRANS_CARDEMU_TO_SUS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4|BIT3, (BIT4|BIT3)}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3|BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SDIO SOP option to disable BG/MB/ACK/SWR*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3|BIT4, BIT3|BIT4}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/ ++ ++#define RTL8723A_TRANS_SUS_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3 | BIT7, 0}, /*clear suspend enable and power down enable*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3|BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/ ++ ++#define RTL8723A_TRANS_CARDEMU_TO_CARDDIS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07=0x20 , SOP option to disable BG/MB*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3|BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT2, BIT2}, /*0x04[10] = 1, enable SW LPS*/ \ ++ {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, 1}, /*0x48[16] = 1 to enable GPIO9 as EXT WAKEUP*/ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/ ++ ++#define RTL8723A_TRANS_CARDDIS_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3 | BIT7, 0}, /*clear suspend enable and power down enable*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\ ++ {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, 0}, /*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3|BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/\ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/ \ ++ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0},/*PCIe DMA start*/ ++ ++ ++#define RTL8723A_TRANS_CARDEMU_TO_PDN \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK|PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SOP option to disable BG/MB/ACK/SWR*/ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, 0},/* 0x04[16] = 0*/\ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, BIT7},/* 0x04[15] = 1*/ ++ ++#define RTL8723A_TRANS_PDN_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT7, 0},/* 0x04[15] = 0*/ ++ ++#define RTL8723A_TRANS_ACT_TO_LPS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0xFF},/*PCIe DMA stop*/ \ ++ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0xFF},/*Tx Pause*/ \ ++ {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled,and clock are gated*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, 0},/*Whole BB is reset*/ \ ++ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x03},/*Reset MAC TRX*/ \ ++ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, 0},/*check if removed later*/ \ ++ {0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x00},/*When driver enter Sus/ Disable, enable LOP for BT*/ \ ++ {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT5, BIT5},/*Respond TxOK to scheduler*/ \ ++ ++ ++#define RTL8723A_TRANS_LPS_TO_ACT \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,PWR_BASEADDR_SDIO,PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/\ ++ {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/\ ++ {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/\ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/\ ++ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT4, 0}, /*. 0x08[4] = 0 switch TSF to 40M*/\ ++ {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_POLLING, BIT7, 0}, /*Polling 0x109[7]=0 TSF in 40M*/\ ++ {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT6|BIT7, 0}, /*. 0x29[7:6] = 2b'00 enable BB clock*/\ ++ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1, BIT1}, /*. 0x101[1] = 1*/\ ++ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0xFF}, /*. 0x100[7:0] = 0xFF enable WMAC TRX*/\ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT1|BIT0, BIT1|BIT0}, /*. 0x02[1:0] = 2b'11 enable BB macro*/\ ++ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0}, /*. 0x522 = 0*/ ++ ++#define RTL8723A_TRANS_END \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ ++ {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,0,PWR_CMD_END, 0, 0}, // ++ ++ ++extern WLAN_PWR_CFG rtl8723A_power_on_flow[RTL8723A_TRANS_CARDEMU_TO_ACT_STEPS+RTL8723A_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723A_radio_off_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723A_card_disable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723A_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723A_card_enable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723A_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723A_suspend_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723A_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723A_resume_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723A_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723A_hwpdn_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723A_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723A_enter_lps_flow[RTL8723A_TRANS_ACT_TO_LPS_STEPS+RTL8723A_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723A_leave_lps_flow[RTL8723A_TRANS_LPS_TO_ACT_STEPS+RTL8723A_TRANS_END_STEPS]; ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/HalPwrSeqCmd.h b/drivers/net/wireless/rtl818x/rtl8189/include/HalPwrSeqCmd.h +new file mode 100644 +index 00000000..5cf122fb +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/HalPwrSeqCmd.h +@@ -0,0 +1,138 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __HALPWRSEQCMD_H__ ++#define __HALPWRSEQCMD_H__ ++ ++#include ++ ++/*---------------------------------------------*/ ++//3 The value of cmd: 4 bits ++/*---------------------------------------------*/ ++#define PWR_CMD_READ 0x00 ++ // offset: the read register offset ++ // msk: the mask of the read value ++ // value: N/A, left by 0 ++ // note: dirver shall implement this function by read & msk ++ ++#define PWR_CMD_WRITE 0x01 ++ // offset: the read register offset ++ // msk: the mask of the write bits ++ // value: write value ++ // note: driver shall implement this cmd by read & msk after write ++ ++#define PWR_CMD_POLLING 0x02 ++ // offset: the read register offset ++ // msk: the mask of the polled value ++ // value: the value to be polled, masked by the msd field. ++ // note: driver shall implement this cmd by ++ // do{ ++ // if( (Read(offset) & msk) == (value & msk) ) ++ // break; ++ // } while(not timeout); ++ ++#define PWR_CMD_DELAY 0x03 ++ // offset: the value to delay ++ // msk: N/A ++ // value: the unit of delay, 0: us, 1: ms ++ ++#define PWR_CMD_END 0x04 ++ // offset: N/A ++ // msk: N/A ++ // value: N/A ++ ++/*---------------------------------------------*/ ++//3 The value of base: 4 bits ++/*---------------------------------------------*/ ++ // define the base address of each block ++#define PWR_BASEADDR_MAC 0x00 ++#define PWR_BASEADDR_USB 0x01 ++#define PWR_BASEADDR_PCIE 0x02 ++#define PWR_BASEADDR_SDIO 0x03 ++ ++/*---------------------------------------------*/ ++//3 The value of interface_msk: 4 bits ++/*---------------------------------------------*/ ++#define PWR_INTF_SDIO_MSK BIT(0) ++#define PWR_INTF_USB_MSK BIT(1) ++#define PWR_INTF_PCI_MSK BIT(2) ++#define PWR_INTF_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3)) ++ ++/*---------------------------------------------*/ ++//3 The value of fab_msk: 4 bits ++/*---------------------------------------------*/ ++#define PWR_FAB_TSMC_MSK BIT(0) ++#define PWR_FAB_UMC_MSK BIT(1) ++#define PWR_FAB_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3)) ++ ++/*---------------------------------------------*/ ++//3 The value of cut_msk: 8 bits ++/*---------------------------------------------*/ ++#define PWR_CUT_TESTCHIP_MSK BIT(0) ++#define PWR_CUT_A_MSK BIT(1) ++#define PWR_CUT_B_MSK BIT(2) ++#define PWR_CUT_C_MSK BIT(3) ++#define PWR_CUT_D_MSK BIT(4) ++#define PWR_CUT_E_MSK BIT(5) ++#define PWR_CUT_F_MSK BIT(6) ++#define PWR_CUT_G_MSK BIT(7) ++#define PWR_CUT_ALL_MSK 0xFF ++ ++ ++typedef enum _PWRSEQ_CMD_DELAY_UNIT_ ++{ ++ PWRSEQ_DELAY_US, ++ PWRSEQ_DELAY_MS, ++} PWRSEQ_DELAY_UNIT; ++ ++typedef struct _WL_PWR_CFG_ ++{ ++ u16 offset; ++ u8 cut_msk; ++ u8 fab_msk:4; ++ u8 interface_msk:4; ++ u8 base:4; ++ u8 cmd:4; ++ u8 msk; ++ u8 value; ++} WLAN_PWR_CFG, *PWLAN_PWR_CFG; ++ ++ ++#define GET_PWR_CFG_OFFSET(__PWR_CMD) __PWR_CMD.offset ++#define GET_PWR_CFG_CUT_MASK(__PWR_CMD) __PWR_CMD.cut_msk ++#define GET_PWR_CFG_FAB_MASK(__PWR_CMD) __PWR_CMD.fab_msk ++#define GET_PWR_CFG_INTF_MASK(__PWR_CMD) __PWR_CMD.interface_msk ++#define GET_PWR_CFG_BASE(__PWR_CMD) __PWR_CMD.base ++#define GET_PWR_CFG_CMD(__PWR_CMD) __PWR_CMD.cmd ++#define GET_PWR_CFG_MASK(__PWR_CMD) __PWR_CMD.msk ++#define GET_PWR_CFG_VALUE(__PWR_CMD) __PWR_CMD.value ++ ++ ++//================================================================================ ++// Prototype of protected function. ++//================================================================================ ++u8 HalPwrSeqCmdParsing( ++ PADAPTER padapter, ++ u8 CutVersion, ++ u8 FabVersion, ++ u8 InterfaceType, ++ WLAN_PWR_CFG PwrCfgCmd[]); ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/HalVerDef.h b/drivers/net/wireless/rtl818x/rtl8189/include/HalVerDef.h +new file mode 100644 +index 00000000..204c3ac8 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/HalVerDef.h +@@ -0,0 +1,164 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __HAL_VERSION_DEF_H__ ++#define __HAL_VERSION_DEF_H__ ++ ++#define TRUE _TRUE ++#define FALSE _FALSE ++ ++// HAL_IC_TYPE_E ++typedef enum tag_HAL_IC_Type_Definition ++{ ++ CHIP_8192S = 0, ++ CHIP_8188C = 1, ++ CHIP_8192C = 2, ++ CHIP_8192D = 3, ++ CHIP_8723A = 4, ++ CHIP_8188E = 5, ++ CHIP_8881A = 6, ++ CHIP_8812A = 7, ++ CHIP_8821A = 8, ++ CHIP_8723B = 9, ++ CHIP_8192E = 10, ++}HAL_IC_TYPE_E; ++ ++//HAL_CHIP_TYPE_E ++typedef enum tag_HAL_CHIP_Type_Definition ++{ ++ TEST_CHIP = 0, ++ NORMAL_CHIP = 1, ++ FPGA = 2, ++}HAL_CHIP_TYPE_E; ++ ++//HAL_CUT_VERSION_E ++typedef enum tag_HAL_Cut_Version_Definition ++{ ++ A_CUT_VERSION = 0, ++ B_CUT_VERSION = 1, ++ C_CUT_VERSION = 2, ++ D_CUT_VERSION = 3, ++ E_CUT_VERSION = 4, ++ F_CUT_VERSION = 5, ++ G_CUT_VERSION = 6, ++ H_CUT_VERSION = 7, ++ I_CUT_VERSION = 8, ++ J_CUT_VERSION = 9, ++ K_CUT_VERSION = 10, ++}HAL_CUT_VERSION_E; ++ ++// HAL_Manufacturer ++typedef enum tag_HAL_Manufacturer_Version_Definition ++{ ++ CHIP_VENDOR_TSMC = 0, ++ CHIP_VENDOR_UMC = 1, ++}HAL_VENDOR_E; ++ ++typedef enum tag_HAL_RF_Type_Definition ++{ ++ RF_TYPE_1T1R = 0, ++ RF_TYPE_1T2R = 1, ++ RF_TYPE_2T2R = 2, ++ RF_TYPE_2T3R = 3, ++ RF_TYPE_2T4R = 4, ++ RF_TYPE_3T3R = 5, ++ RF_TYPE_3T4R = 6, ++ RF_TYPE_4T4R = 7, ++}HAL_RF_TYPE_E; ++ ++typedef struct tag_HAL_VERSION ++{ ++ HAL_IC_TYPE_E ICType; ++ HAL_CHIP_TYPE_E ChipType; ++ HAL_CUT_VERSION_E CUTVersion; ++ HAL_VENDOR_E VendorType; ++ HAL_RF_TYPE_E RFType; ++ u8 ROMVer; ++}HAL_VERSION,*PHAL_VERSION; ++ ++//VERSION_8192C VersionID; ++//HAL_VERSION VersionID; ++ ++// Get element ++#define GET_CVID_IC_TYPE(version) ((HAL_IC_TYPE_E)(((HAL_VERSION)version).ICType) ) ++#define GET_CVID_CHIP_TYPE(version) ((HAL_CHIP_TYPE_E)(((HAL_VERSION)version).ChipType) ) ++#define GET_CVID_RF_TYPE(version) ((HAL_RF_TYPE_E)(((HAL_VERSION)version).RFType)) ++#define GET_CVID_MANUFACTUER(version) ((HAL_VENDOR_E)(((HAL_VERSION)version).VendorType)) ++#define GET_CVID_CUT_VERSION(version) ((HAL_CUT_VERSION_E)(((HAL_VERSION)version).CUTVersion)) ++#define GET_CVID_ROM_VERSION(version) ((((HAL_VERSION)version).ROMVer) & ROM_VERSION_MASK) ++ ++//---------------------------------------------------------------------------- ++//Common Macro. -- ++//---------------------------------------------------------------------------- ++//HAL_VERSION VersionID ++ ++// HAL_IC_TYPE_E ++#define IS_81XXC(version) (((GET_CVID_IC_TYPE(version) == CHIP_8192C)||(GET_CVID_IC_TYPE(version) == CHIP_8188C))? TRUE : FALSE) ++#define IS_8723_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8723A)? TRUE : FALSE) ++#define IS_92D(version) ((GET_CVID_IC_TYPE(version) == CHIP_8192D)? TRUE : FALSE) ++#define IS_8188E(version) ((GET_CVID_IC_TYPE(version) == CHIP_8188E)? TRUE : FALSE) ++ ++//HAL_CHIP_TYPE_E ++#define IS_TEST_CHIP(version) ((GET_CVID_CHIP_TYPE(version)==TEST_CHIP)? TRUE: FALSE) ++#define IS_NORMAL_CHIP(version) ((GET_CVID_CHIP_TYPE(version)==NORMAL_CHIP)? TRUE: FALSE) ++ ++//HAL_CUT_VERSION_E ++#define IS_A_CUT(version) ((GET_CVID_CUT_VERSION(version) == A_CUT_VERSION) ? TRUE : FALSE) ++#define IS_B_CUT(version) ((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? TRUE : FALSE) ++#define IS_C_CUT(version) ((GET_CVID_CUT_VERSION(version) == C_CUT_VERSION) ? TRUE : FALSE) ++#define IS_D_CUT(version) ((GET_CVID_CUT_VERSION(version) == D_CUT_VERSION) ? TRUE : FALSE) ++#define IS_E_CUT(version) ((GET_CVID_CUT_VERSION(version) == E_CUT_VERSION) ? TRUE : FALSE) ++#define IS_I_CUT(version) ((GET_CVID_CUT_VERSION(version) == I_CUT_VERSION) ? TRUE : FALSE) ++#define IS_J_CUT(version) ((GET_CVID_CUT_VERSION(version) == J_CUT_VERSION) ? TRUE : FALSE) ++#define IS_K_CUT(version) ((GET_CVID_CUT_VERSION(version) == K_CUT_VERSION) ? TRUE : FALSE) ++ ++#define IS_VENDOR_8188E_I_CUT_SERIES(_Adapter) ((IS_8188E(GET_HAL_DATA(_Adapter)->VersionID)) ? ((GET_CVID_CUT_VERSION(GET_HAL_DATA(_Adapter)->VersionID) >= I_CUT_VERSION) ? TRUE : FALSE) : FALSE) ++ ++//HAL_VENDOR_E ++#define IS_CHIP_VENDOR_TSMC(version) ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_TSMC)? TRUE: FALSE) ++#define IS_CHIP_VENDOR_UMC(version) ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_UMC)? TRUE: FALSE) ++ ++//HAL_RF_TYPE_E ++#define IS_1T1R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T1R)? TRUE : FALSE ) ++#define IS_1T2R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R)? TRUE : FALSE) ++#define IS_2T2R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R)? TRUE : FALSE) ++ ++ ++//---------------------------------------------------------------------------- ++//Chip version Macro. -- ++//---------------------------------------------------------------------------- ++#define IS_81XXC_TEST_CHIP(version) ((IS_81XXC(version) && (!IS_NORMAL_CHIP(version)))? TRUE: FALSE) ++ ++#define IS_92C_SERIAL(version) ((IS_81XXC(version) && IS_2T2R(version)) ? TRUE : FALSE) ++#define IS_81xxC_VENDOR_UMC_A_CUT(version) (IS_81XXC(version)?(IS_CHIP_VENDOR_UMC(version) ? (IS_A_CUT(version) ? TRUE : FALSE) : FALSE): FALSE) ++#define IS_81xxC_VENDOR_UMC_B_CUT(version) (IS_81XXC(version)?(IS_CHIP_VENDOR_UMC(version) ? (IS_B_CUT(version) ? TRUE : FALSE) : FALSE): FALSE) ++#define IS_81xxC_VENDOR_UMC_C_CUT(version) (IS_81XXC(version)?(IS_CHIP_VENDOR_UMC(version) ? (IS_C_CUT(version) ? TRUE : FALSE) : FALSE): FALSE) ++ ++#define IS_NORMAL_CHIP92D(version) (( IS_92D(version))?((GET_CVID_CHIP_TYPE(version)==NORMAL_CHIP)? TRUE: FALSE):FALSE) ++ ++#define IS_92D_SINGLEPHY(version) ((IS_92D(version)) ? (IS_2T2R(version) ? TRUE: FALSE) : FALSE) ++#define IS_92D_C_CUT(version) ((IS_92D(version)) ? (IS_C_CUT(version) ? TRUE : FALSE) : FALSE) ++#define IS_92D_D_CUT(version) ((IS_92D(version)) ? (IS_D_CUT(version) ? TRUE : FALSE) : FALSE) ++#define IS_92D_E_CUT(version) ((IS_92D(version)) ? (IS_E_CUT(version) ? TRUE : FALSE) : FALSE) ++ ++#define IS_8723A_A_CUT(version) ((IS_8723_SERIES(version)) ? ( IS_A_CUT(version)?TRUE : FALSE) : FALSE) ++#define IS_8723A_B_CUT(version) ((IS_8723_SERIES(version)) ? ( IS_B_CUT(version)?TRUE : FALSE) : FALSE) ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/autoconf.h b/drivers/net/wireless/rtl818x/rtl8189/include/autoconf.h +new file mode 100644 +index 00000000..620c115c +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/autoconf.h +@@ -0,0 +1,26 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#ifdef CONFIG_RTL8189ES ++#include "autoconf_rtl8189e_sdio_linux.h" ++#else ++#include "autoconf_rtl8189e_usb_linux.h" ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/autoconf_rtl8189e_sdio_linux.h b/drivers/net/wireless/rtl818x/rtl8189/include/autoconf_rtl8189e_sdio_linux.h +new file mode 100644 +index 00000000..6d605fe9 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/autoconf_rtl8189e_sdio_linux.h +@@ -0,0 +1,311 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2010 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++/* ++ * Automatically generated C config: don't edit ++ */ ++ ++//***** temporarily flag ******* ++#define CONFIG_ODM_REFRESH_RAMASK ++#define CONFIG_PHY_SETTING_WITH_ODM ++//***** temporarily flag ******* ++ ++ ++#define AUTOCONF_INCLUDED ++#define RTL871X_MODULE_NAME "8189ES" ++#define DRV_NAME "rtl8189es" ++ ++#define CONFIG_RTL8188E ++#define CONFIG_SDIO_HCI ++#define PLATFORM_LINUX ++ ++//#define CONFIG_IOCTL_CFG80211 ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ //#define RTW_USE_CFG80211_STA_EVENT /* Indecate new sta asoc through cfg80211_new_sta */ ++ #define CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER ++ //#define CONFIG_DEBUG_CFG80211 ++ #define CONFIG_SET_SCAN_DENY_TIMER ++#endif ++ ++#define CONFIG_EMBEDDED_FWIMG ++ ++#define CONFIG_XMIT_ACK ++#ifdef CONFIG_XMIT_ACK ++ #define CONFIG_ACTIVE_KEEP_ALIVE_CHECK ++#endif ++#define CONFIG_80211N_HT ++#define CONFIG_RECV_REORDERING_CTRL ++ ++#define CONFIG_CONCURRENT_MODE ++#ifdef CONFIG_CONCURRENT_MODE ++ #define CONFIG_TSF_RESET_OFFLOAD // For 2 PORT TSF SYNC. ++ //#define CONFIG_HWPORT_SWAP //Port0->Sec , Port1 -> Pri ++ //#define CONFIG_STA_MODE_SCAN_UNDER_AP_MODE ++#endif ++ ++#define CONFIG_AP_MODE ++#ifdef CONFIG_AP_MODE ++ ++ #define CONFIG_INTERRUPT_BASED_TXBCN // Tx Beacon when driver early interrupt occurs ++ #if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_INTERRUPT_BASED_TXBCN) ++ #undef CONFIG_INTERRUPT_BASED_TXBCN ++ #endif ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN ++ //#define CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ #define CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ #endif ++ ++ #define CONFIG_NATIVEAP_MLME ++ #ifndef CONFIG_NATIVEAP_MLME ++ #define CONFIG_HOSTAPD_MLME ++ #endif ++ //#define CONFIG_FIND_BEST_CHANNEL ++ //#define CONFIG_NO_WIRELESS_HANDLERS ++#endif ++ ++#define CONFIG_TX_MCAST2UNI // Support IP multicast->unicast ++//#define CONFIG_CHECK_AC_LIFETIME // Check packet lifetime of 4 ACs. ++ ++#define CONFIG_P2P ++#ifdef CONFIG_P2P ++ //The CONFIG_WFD is for supporting the Wi-Fi display ++ #define CONFIG_WFD ++ ++ #ifndef CONFIG_WIFI_TEST ++ #define CONFIG_P2P_REMOVE_GROUP_INFO ++ #endif ++ //#define CONFIG_DBG_P2P ++ ++ #define CONFIG_P2P_PS ++ //#define CONFIG_P2P_IPS ++ #define P2P_OP_CHECK_SOCIAL_CH ++#endif ++ ++// Added by Kurt 20110511 ++//#define CONFIG_TDLS ++#ifdef CONFIG_TDLS ++// #ifndef CONFIG_WFD ++// #define CONFIG_WFD ++// #endif ++// #define CONFIG_TDLS_AUTOSETUP ++// #define CONFIG_TDLS_AUTOCHECKALIVE ++#endif ++ ++#define CONFIG_SKB_COPY //for amsdu ++ ++#define CONFIG_LAYER2_ROAMING ++#define CONFIG_LAYER2_ROAMING_RESUME ++ ++#define CONFIG_LONG_DELAY_ISSUE ++#define CONFIG_NEW_SIGNAL_STAT_PROCESS ++#define RTW_NOTCH_FILTER 0 /* 0:Disable, 1:Enable, */ ++#define CONFIG_DEAUTH_BEFORE_CONNECT ++ ++//#define CONFIG_ARP_KEEP_ALIVE ++ ++/* ++ * Hardware Related Config ++ */ ++ ++//#define SUPPORT_HW_RFOFF_DETECTED ++ ++//#define CONFIG_SW_LED ++#define CONFIG_REGULATORY_CTRL ++ ++/* ++ * Interface Related Config ++ */ ++//#define CONFIG_SDIO_TX_TASKLET ++#define CONFIG_SDIO_RX_COPY ++//#define CONFIG_SDIO_REDUCE_TX_POLLING ++ ++ ++/* ++ * Others ++ */ ++//#define CONFIG_MAC_LOOPBACK_DRIVER ++ ++ ++/* ++ * Auto Config Section ++ */ ++#if defined(CONFIG_RTL8188E) && defined(CONFIG_SDIO_HCI) ++#define CONFIG_RTL8188E_SDIO ++#define CONFIG_XMIT_THREAD_MODE ++#endif ++ ++#define CONFIG_IPS ++ ++#define CONFIG_LPS ++#if defined(CONFIG_LPS) && defined(CONFIG_SDIO_HCI) ++#define CONFIG_LPS_LCLK ++ ++ #define CONFIG_LPS_RPWM_TIMER ++ #ifdef CONFIG_LPS_RPWM_TIMER ++ #define LPS_RPWM_WAIT_MS 300 ++ #endif ++#endif ++ ++#ifdef CONFIG_LPS_LCLK ++//#define CONFIG_DETECT_CPWM_BY_POLLING ++#endif ++ ++#ifdef CONFIG_DETECT_CPWM_BY_POLLING ++#define CONFIG_USING_CMD52_READ_INT /*for cmd53 I/O fail issue,read 0x18 only*/ ++#endif ++ ++ ++#ifdef CONFIG_MAC_LOOPBACK_DRIVER ++#undef CONFIG_AP_MODE ++#undef CONFIG_NATIVEAP_MLME ++#undef CONFIG_POWER_SAVING ++#undef SUPPORT_HW_RFOFF_DETECTED ++#endif ++ ++#ifdef CONFIG_MP_INCLUDED ++ ++ #define MP_DRIVER 1 ++ #define CONFIG_MP_IWPRIV_SUPPORT ++ ++ // disable unnecessary functions for MP ++ //#undef CONFIG_IPS ++ //#undef CONFIG_LPS ++ //#undef CONFIG_LPS_LCLK ++ //#undef SUPPORT_HW_RFOFF_DETECTED ++ ++#else// #ifdef CONFIG_MP_INCLUDED ++ ++ #define MP_DRIVER 0 ++ ++#endif // #ifdef CONFIG_MP_INCLUDED ++ ++#define CONFIG_IOL ++#ifdef CONFIG_IOL ++ #define CONFIG_IOL_NEW_GENERATION ++ #define CONFIG_IOL_READ_EFUSE_MAP ++ //#define DBG_IOL_READ_EFUSE_MAP ++ //#define CONFIG_IOL_LLT ++ #define CONFIG_IOL_EFUSE_PATCH ++ //#define CONFIG_IOL_IOREG_CFG ++ //#define CONFIG_IOL_IOREG_CFG_DBG ++#endif ++ ++ ++#define CONFIG_TX_AGGREGATION ++ ++#ifdef CONFIG_PLATFORM_ACTIONS_ATV5201 ++#define CONFIG_SDIO_DISABLE_RXFIFO_POLLING_LOOP ++#endif ++ ++/* ++ * Outsource Related Config ++ */ ++ ++#define RTL8192CE_SUPPORT 0 ++#define RTL8192CU_SUPPORT 0 ++#define RTL8192C_SUPPORT (RTL8192CE_SUPPORT|RTL8192CU_SUPPORT) ++ ++#define RTL8192DE_SUPPORT 0 ++#define RTL8192DU_SUPPORT 0 ++#define RTL8192D_SUPPORT (RTL8192DE_SUPPORT|RTL8192DU_SUPPORT) ++ ++#define RTL8723_FPGA_VERIFICATION 0 ++#define RTL8723AU_SUPPORT 0 ++#define RTL8723AS_SUPPORT 0 ++#define RTL8723AE_SUPPORT 0 ++#define RTL8723A_SUPPORT (RTL8723AU_SUPPORT|RTL8723AS_SUPPORT|RTL8723AE_SUPPORT) ++ ++#define RTL8188EE_SUPPORT 0 ++#define RTL8188EU_SUPPORT 0 ++#define RTL8188ES_SUPPORT 1 ++#define RTL8188E_SUPPORT (RTL8188EE_SUPPORT|RTL8188EU_SUPPORT|RTL8188ES_SUPPORT) ++#define RTL8188E_FOR_TEST_CHIP 0 ++//#if (RTL8188E_SUPPORT==1) ++#define RATE_ADAPTIVE_SUPPORT 1 ++#define POWER_TRAINING_ACTIVE 1 ++//#define CONFIG_TX_EARLY_MODE ++ ++#ifdef CONFIG_TX_EARLY_MODE ++#define RTL8188E_EARLY_MODE_PKT_NUM_10 0 ++#endif ++//#endif ++ ++#define CONFIG_ATTEMPT_TO_FIX_AP_BEACON_ERROR ++ ++/* ++ * HAL Related Config ++ */ ++ ++//for FPGA VERIFICATION config ++#define RTL8188E_FPGA_TRUE_PHY_VERIFICATION 0 ++ ++#define DISABLE_BB_RF 0 ++ ++#if DISABLE_BB_RF ++ #define HAL_MAC_ENABLE 1 ++ #define HAL_BB_ENABLE 0 ++ #define HAL_RF_ENABLE 0 ++#else ++ #define HAL_MAC_ENABLE 1 ++ #define HAL_BB_ENABLE 1 ++ #define HAL_RF_ENABLE 1 ++#endif ++ ++#define CONFIG_80211D ++ ++ ++ ++/* ++ * Debug Related Config ++ */ ++#define DBG 0 ++ ++//#define CONFIG_DEBUG /* DBG_871X, etc... */ ++//#define CONFIG_DEBUG_RTL871X /* RT_TRACE, RT_PRINT_DATA, _func_enter_, _func_exit_ */ ++ ++//#define CONFIG_PROC_DEBUG ++ ++//#define DBG_CONFIG_ERROR_DETECT ++//#define DBG_CONFIG_ERROR_RESET ++ ++//#define DBG_IO ++//#define DBG_DELAY_OS ++//#define DBG_MEM_ALLOC ++//#define DBG_IOCTL ++ ++//#define DBG_TX ++//#define DBG_XMIT_BUF ++//#define DBG_XMIT_BUF_EXT ++//#define DBG_TX_DROP_FRAME ++ ++//#define DBG_RX_DROP_FRAME ++//#define DBG_RX_SEQ ++//#define DBG_RX_SIGNAL_DISPLAY_PROCESSING ++//#define DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED "jeff-ap" ++ ++ ++//#define HAL_8195A_USB 0 ++ ++//#define RTL8188E_FOR_MP_TEST 1 ++ ++//#define DOWNLOAD_FW_TO_TXPKT_BUF 0 ++ ++//#define DBG_HAL_INIT_PROFILING ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/autoconf_rtl8189e_usb_linux.h b/drivers/net/wireless/rtl818x/rtl8189/include/autoconf_rtl8189e_usb_linux.h +new file mode 100644 +index 00000000..f87ab3a8 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/autoconf_rtl8189e_usb_linux.h +@@ -0,0 +1,406 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++//***** temporarily flag ******* ++ ++//#define CONFIG_DISABLE_ODM ++//#define CONFIG_ATMEL_RC_PATCH ++ ++#define CONFIG_ODM_REFRESH_RAMASK ++#define CONFIG_PHY_SETTING_WITH_ODM ++//for FPGA VERIFICATION config ++#define RTL8188E_FPGA_TRUE_PHY_VERIFICATION 0 ++ ++//***** temporarily flag ******* ++/* ++ * Public General Config ++ */ ++#define AUTOCONF_INCLUDED ++#define RTL871X_MODULE_NAME "88EU" ++#define DRV_NAME "rtl8188eu" ++ ++#define CONFIG_USB_HCI ++ ++#define CONFIG_RTL8188E ++ ++#define PLATFORM_LINUX ++ ++//#define CONFIG_IOCTL_CFG80211 ++//#define CONFIG_IEEE80211W ++ ++#if defined(CONFIG_PLATFORM_ACTIONS_ATM702X) ++ #ifndef CONFIG_IOCTL_CFG80211 ++ #define CONFIG_IOCTL_CFG80211 ++ #endif ++#endif ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ //#define RTW_USE_CFG80211_STA_EVENT /* Indecate new sta asoc through cfg80211_new_sta */ ++ #define CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER ++ //#define CONFIG_DEBUG_CFG80211 ++ //#define CONFIG_DRV_ISSUE_PROV_REQ // IOT FOR S2 ++ #define CONFIG_SET_SCAN_DENY_TIMER ++ ++#endif ++ ++/* ++ * Internal General Config ++ */ ++ ++//#define CONFIG_H2CLBK ++ ++#define CONFIG_EMBEDDED_FWIMG ++//#define CONFIG_FILE_FWIMG ++ ++#define CONFIG_XMIT_ACK ++#ifdef CONFIG_XMIT_ACK ++ #define CONFIG_ACTIVE_KEEP_ALIVE_CHECK ++#endif ++#define CONFIG_80211N_HT ++ ++#define CONFIG_RECV_REORDERING_CTRL ++ ++//#define CONFIG_TCP_CSUM_OFFLOAD_RX ++ ++//#define CONFIG_DRVEXT_MODULE ++ ++ #define CONFIG_SUPPORT_USB_INT ++ #ifdef CONFIG_SUPPORT_USB_INT ++//#define CONFIG_USB_INTERRUPT_IN_PIPE ++#endif ++ ++//#ifndef CONFIG_MP_INCLUDED ++ #define CONFIG_IPS ++ #ifdef CONFIG_IPS ++ //#define CONFIG_IPS_LEVEL_2 //enable this to set default IPS mode to IPS_LEVEL_2 ++ #endif ++ #define SUPPORT_HW_RFOFF_DETECTED ++ ++ #define CONFIG_LPS ++ #if defined(CONFIG_LPS) && defined(CONFIG_SUPPORT_USB_INT) ++ ++ ++ //#define CONFIG_LPS_LCLK ++ #endif ++ ++ #ifdef CONFIG_LPS_LCLK ++ #define CONFIG_XMIT_THREAD_MODE ++ #endif ++ ++ //befor link ++ #define CONFIG_ANTENNA_DIVERSITY ++ ++ //after link ++ #ifdef CONFIG_ANTENNA_DIVERSITY ++ #define CONFIG_HW_ANTENNA_DIVERSITY ++ #endif ++ ++ ++ #define CONFIG_CONCURRENT_MODE ++ #ifdef CONFIG_CONCURRENT_MODE ++ //#define CONFIG_HWPORT_SWAP //Port0->Sec , Port1 -> Pri ++ //#define CONFIG_STA_MODE_SCAN_UNDER_AP_MODE ++ #define CONFIG_TSF_RESET_OFFLOAD // For 2 PORT TSF SYNC. ++ #endif ++ ++ #define CONFIG_IOL ++//#else //#ifndef CONFIG_MP_INCLUDED ++ ++//#endif //#ifndef CONFIG_MP_INCLUDED ++ ++#define CONFIG_AP_MODE ++#ifdef CONFIG_AP_MODE ++ //#define CONFIG_INTERRUPT_BASED_TXBCN // Tx Beacon when driver BCN_OK ,BCN_ERR interrupt occurs ++ #if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_INTERRUPT_BASED_TXBCN) ++ #undef CONFIG_INTERRUPT_BASED_TXBCN ++ #endif ++ #ifdef CONFIG_INTERRUPT_BASED_TXBCN ++ //#define CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ #define CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ #endif ++ ++ #define CONFIG_NATIVEAP_MLME ++ #ifndef CONFIG_NATIVEAP_MLME ++ #define CONFIG_HOSTAPD_MLME ++ #endif ++ #define CONFIG_FIND_BEST_CHANNEL ++ //#define CONFIG_NO_WIRELESS_HANDLERS ++#endif ++ ++#define CONFIG_P2P ++#ifdef CONFIG_P2P ++ //The CONFIG_WFD is for supporting the Wi-Fi display ++ #define CONFIG_WFD ++ ++ #ifndef CONFIG_WIFI_TEST ++ #define CONFIG_P2P_REMOVE_GROUP_INFO ++ #endif ++ //#define CONFIG_DBG_P2P ++ ++ #define CONFIG_P2P_PS ++ //#define CONFIG_P2P_IPS ++ #define P2P_OP_CHECK_SOCIAL_CH ++#endif ++ ++// Added by Kurt 20110511 ++//#define CONFIG_TDLS ++#ifdef CONFIG_TDLS ++// #ifndef CONFIG_WFD ++// #define CONFIG_WFD ++// #endif ++// #define CONFIG_TDLS_AUTOSETUP ++// #define CONFIG_TDLS_AUTOCHECKALIVE ++#endif ++ ++ ++#define CONFIG_SKB_COPY //for amsdu ++ ++//#define CONFIG_LED ++#ifdef CONFIG_LED ++ #define CONFIG_SW_LED ++ #ifdef CONFIG_SW_LED ++ //#define CONFIG_LED_HANDLED_BY_CMD_THREAD ++ #endif ++#endif // CONFIG_LED ++ ++#ifdef CONFIG_IOL ++ #define CONFIG_IOL_NEW_GENERATION ++ #define CONFIG_IOL_READ_EFUSE_MAP ++ //#define DBG_IOL_READ_EFUSE_MAP ++ //#define CONFIG_IOL_LLT ++ #define CONFIG_IOL_EFUSE_PATCH ++ //#define CONFIG_IOL_IOREG_CFG ++ //#define CONFIG_IOL_IOREG_CFG_DBG ++#endif ++ ++ ++#define USB_INTERFERENCE_ISSUE // this should be checked in all usb interface ++#define CONFIG_GLOBAL_UI_PID ++ ++#define CONFIG_LAYER2_ROAMING ++#define CONFIG_LAYER2_ROAMING_RESUME ++//#define CONFIG_ADAPTOR_INFO_CACHING_FILE // now just applied on 8192cu only, should make it general... ++//#define CONFIG_RESUME_IN_WORKQUEUE ++//#define CONFIG_SET_SCAN_DENY_TIMER ++#define CONFIG_LONG_DELAY_ISSUE ++#define CONFIG_NEW_SIGNAL_STAT_PROCESS ++//#define CONFIG_SIGNAL_DISPLAY_DBM //display RX signal with dbm ++#define RTW_NOTCH_FILTER 0 /* 0:Disable, 1:Enable, */ ++#define CONFIG_DEAUTH_BEFORE_CONNECT ++ ++#define CONFIG_BR_EXT // Enable NAT2.5 support for STA mode interface with a L2 Bridge ++#ifdef CONFIG_BR_EXT ++#define CONFIG_BR_EXT_BRNAME "br0" ++#endif // CONFIG_BR_EXT ++ ++#define CONFIG_TX_MCAST2UNI // Support IP multicast->unicast ++//#define CONFIG_CHECK_AC_LIFETIME // Check packet lifetime of 4 ACs. ++ ++/* ++ * Interface Related Config ++ */ ++ ++#ifndef CONFIG_MINIMAL_MEMORY_USAGE ++ #define CONFIG_USB_TX_AGGREGATION ++ #define CONFIG_USB_RX_AGGREGATION ++#endif ++ ++#define CONFIG_PREALLOC_RECV_SKB ++//#define CONFIG_REDUCE_USB_TX_INT // Trade-off: Improve performance, but may cause TX URBs blocked by USB Host/Bus driver on few platforms. ++//#define CONFIG_EASY_REPLACEMENT ++ ++/* ++ * CONFIG_USE_USB_BUFFER_ALLOC_XX uses Linux USB Buffer alloc API and is for Linux platform only now! ++ */ ++//#define CONFIG_USE_USB_BUFFER_ALLOC_TX // Trade-off: For TX path, improve stability on some platforms, but may cause performance degrade on other platforms. ++//#define CONFIG_USE_USB_BUFFER_ALLOC_RX // For RX path ++#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX ++#undef CONFIG_PREALLOC_RECV_SKB ++#endif ++ ++/* ++ * USB VENDOR REQ BUFFER ALLOCATION METHOD ++ * if not set we'll use function local variable (stack memory) ++ */ ++//#define CONFIG_USB_VENDOR_REQ_BUFFER_DYNAMIC_ALLOCATE ++#define CONFIG_USB_VENDOR_REQ_BUFFER_PREALLOC ++ ++#define CONFIG_USB_VENDOR_REQ_MUTEX ++#define CONFIG_VENDOR_REQ_RETRY ++ ++//#define CONFIG_USB_SUPPORT_ASYNC_VDN_REQ ++ ++ ++/* ++ * HAL Related Config ++ */ ++ ++#define RTL8188E_RX_PACKET_INCLUDE_CRC 0 ++ ++#define SUPPORTED_BLOCK_IO ++#define CONFIG_REGULATORY_CTRL ++ ++//#define CONFIG_ONLY_ONE_OUT_EP_TO_LOW 0 ++ ++#define CONFIG_OUT_EP_WIFI_MODE 0 ++ ++#define ENABLE_USB_DROP_INCORRECT_OUT ++ ++ ++//#define RTL8192CU_ADHOC_WORKAROUND_SETTING ++ ++#define DISABLE_BB_RF 0 ++ ++//#define RTL8191C_FPGA_NETWORKTYPE_ADHOC 0 ++ ++#ifdef CONFIG_MP_INCLUDED ++ #define MP_DRIVER 1 ++ #define CONFIG_MP_IWPRIV_SUPPORT ++ //#undef CONFIG_USB_TX_AGGREGATION ++ //#undef CONFIG_USB_RX_AGGREGATION ++#else ++ #define MP_DRIVER 0 ++#endif ++ ++ ++/* ++ * Platform Related Config ++ */ ++#ifdef CONFIG_PLATFORM_MN10300 ++ #define CONFIG_SPECIAL_SETTING_FOR_FUNAI_TV ++ #define CONFIG_USE_USB_BUFFER_ALLOC_RX ++ ++ #if defined (CONFIG_SW_ANTENNA_DIVERSITY) ++ #undef CONFIG_SW_ANTENNA_DIVERSITY ++ #define CONFIG_HW_ANTENNA_DIVERSITY ++ #endif ++ ++ #if defined (CONFIG_POWER_SAVING) ++ #undef CONFIG_POWER_SAVING ++ #endif ++ ++#endif//CONFIG_PLATFORM_MN10300 ++ ++ ++ ++#ifdef CONFIG_PLATFORM_TI_DM365 ++#define CONFIG_USE_USB_BUFFER_ALLOC_RX ++#endif ++ ++ ++#if defined(CONFIG_PLATFORM_ACTIONS_ATM702X) ++ #ifdef CONFIG_USB_TX_AGGREGATION ++ #undef CONFIG_USB_TX_AGGREGATION ++ #endif ++ #ifndef CONFIG_USE_USB_BUFFER_ALLOC_TX ++ #define CONFIG_USE_USB_BUFFER_ALLOC_TX ++ #endif ++ #ifndef CONFIG_USE_USB_BUFFER_ALLOC_RX ++ #define CONFIG_USE_USB_BUFFER_ALLOC_RX ++ #endif ++#endif ++ ++ ++/* ++ * Outsource Related Config ++ */ ++ ++#define RTL8192CE_SUPPORT 0 ++#define RTL8192CU_SUPPORT 0 ++#define RTL8192C_SUPPORT (RTL8192CE_SUPPORT|RTL8192CU_SUPPORT) ++ ++#define RTL8192DE_SUPPORT 0 ++#define RTL8192DU_SUPPORT 0 ++#define RTL8192D_SUPPORT (RTL8192DE_SUPPORT|RTL8192DU_SUPPORT) ++ ++#define RTL8723AU_SUPPORT 0 ++#define RTL8723AS_SUPPORT 0 ++#define RTL8723AE_SUPPORT 0 ++#define RTL8723A_SUPPORT (RTL8723AU_SUPPORT|RTL8723AS_SUPPORT|RTL8723AE_SUPPORT) ++ ++#define RTL8723_FPGA_VERIFICATION 0 ++ ++#define RTL8188EE_SUPPORT 0 ++#define RTL8188EU_SUPPORT 1 ++#define RTL8188ES_SUPPORT 0 ++#define RTL8188E_SUPPORT (RTL8188EE_SUPPORT|RTL8188EU_SUPPORT|RTL8188ES_SUPPORT) ++#define RTL8188E_FOR_TEST_CHIP 0 ++//#if (RTL8188E_SUPPORT==1) ++#define RATE_ADAPTIVE_SUPPORT 1 ++#define POWER_TRAINING_ACTIVE 1 ++ ++//#endif ++ ++#ifdef CONFIG_USB_TX_AGGREGATION ++//#define CONFIG_TX_EARLY_MODE ++#endif ++ ++#ifdef CONFIG_TX_EARLY_MODE ++#define RTL8188E_EARLY_MODE_PKT_NUM_10 0 ++#endif ++ ++#define CONFIG_80211D ++ ++#define CONFIG_ATTEMPT_TO_FIX_AP_BEACON_ERROR ++ ++/* ++ * Debug Related Config ++ */ ++#define DBG 0 ++ ++//#define CONFIG_DEBUG /* DBG_871X, etc... */ ++//#define CONFIG_DEBUG_RTL871X /* RT_TRACE, RT_PRINT_DATA, _func_enter_, _func_exit_ */ ++ ++//#define CONFIG_PROC_DEBUG ++ ++//#define DBG_CONFIG_ERROR_DETECT ++//#define DBG_CONFIG_ERROR_DETECT_INT ++//#define DBG_CONFIG_ERROR_RESET ++ ++//#define DBG_IO ++//#define DBG_DELAY_OS ++//#define DBG_MEM_ALLOC ++//#define DBG_IOCTL ++ ++//#define DBG_TX ++//#define DBG_XMIT_BUF ++//#define DBG_XMIT_BUF_EXT ++//#define DBG_TX_DROP_FRAME ++ ++//#define DBG_TRX_STA_PKTS ++ ++//#define DBG_RX_DROP_FRAME ++//#define DBG_RX_SEQ ++//#define DBG_RX_SIGNAL_DISPLAY_PROCESSING ++//#define DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED "jeff-ap" ++ ++ ++ ++//#define DBG_SHOW_MCUFWDL_BEFORE_51_ENABLE ++//#define DBG_ROAMING_TEST ++ ++//#define DBG_HAL_INIT_PROFILING ++ ++//#define DBG_MEMORY_LEAK ++ ++//TX use 1 urb ++//#define CONFIG_SINGLE_XMIT_BUF ++//RX use 1 urb ++//#define CONFIG_SINGLE_RECV_BUF ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/basic_types.h b/drivers/net/wireless/rtl818x/rtl8189/include/basic_types.h +new file mode 100644 +index 00000000..9532f2aa +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/basic_types.h +@@ -0,0 +1,338 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __BASIC_TYPES_H__ ++#define __BASIC_TYPES_H__ ++ ++#include ++ ++ ++#define SUCCESS 0 ++#define FAIL (-1) ++ ++#ifndef TRUE ++ #define _TRUE 1 ++#else ++ #define _TRUE TRUE ++#endif ++ ++#ifndef FALSE ++ #define _FALSE 0 ++#else ++ #define _FALSE FALSE ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++ ++ typedef signed char s8; ++ typedef unsigned char u8; ++ ++ typedef signed short s16; ++ typedef unsigned short u16; ++ ++ typedef signed long s32; ++ typedef unsigned long u32; ++ ++ typedef unsigned int uint; ++ typedef signed int sint; ++ ++ ++ typedef signed long long s64; ++ typedef unsigned long long u64; ++ ++ #ifdef NDIS50_MINIPORT ++ ++ #define NDIS_MAJOR_VERSION 5 ++ #define NDIS_MINOR_VERSION 0 ++ ++ #endif ++ ++ #ifdef NDIS51_MINIPORT ++ ++ #define NDIS_MAJOR_VERSION 5 ++ #define NDIS_MINOR_VERSION 1 ++ ++ #endif ++ ++ typedef NDIS_PROC proc_t; ++ ++ typedef LONG atomic_t; ++ ++#endif ++ ++ ++#ifdef PLATFORM_LINUX ++ ++ #include ++ #define IN ++ #define OUT ++ #define VOID void ++ #define NDIS_OID uint ++ #define NDIS_STATUS uint ++ ++ typedef signed int sint; ++ ++ #ifndef PVOID ++ typedef void * PVOID; ++ //#define PVOID (void *) ++ #endif ++ ++ #define UCHAR u8 ++ #define USHORT u16 ++ #define UINT u32 ++ #define ULONG u32 ++ ++ typedef void (*proc_t)(void*); ++ ++ typedef __kernel_size_t SIZE_T; ++ typedef __kernel_ssize_t SSIZE_T; ++ #define FIELD_OFFSET(s,field) ((SSIZE_T)&((s*)(0))->field) ++ ++#endif ++ ++ ++#ifdef PLATFORM_FREEBSD ++ ++ typedef signed char s8; ++ typedef unsigned char u8; ++ ++ typedef signed short s16; ++ typedef unsigned short u16; ++ ++ typedef signed int s32; ++ typedef unsigned int u32; ++ ++ typedef unsigned int uint; ++ typedef signed int sint; ++ typedef long atomic_t; ++ ++ typedef signed long long s64; ++ typedef unsigned long long u64; ++ #define IN ++ #define OUT ++ #define VOID void ++ #define NDIS_OID uint ++ #define NDIS_STATUS uint ++ ++ #ifndef PVOID ++ typedef void * PVOID; ++ //#define PVOID (void *) ++ #endif ++ typedef u32 dma_addr_t; ++ #define UCHAR u8 ++ #define USHORT u16 ++ #define UINT u32 ++ #define ULONG u32 ++ ++ typedef void (*proc_t)(void*); ++ ++ typedef unsigned int __kernel_size_t; ++ typedef int __kernel_ssize_t; ++ ++ typedef __kernel_size_t SIZE_T; ++ typedef __kernel_ssize_t SSIZE_T; ++ #define FIELD_OFFSET(s,field) ((SSIZE_T)&((s*)(0))->field) ++ ++#endif ++ ++#define MEM_ALIGNMENT_OFFSET (sizeof (SIZE_T)) ++#define MEM_ALIGNMENT_PADDING (sizeof(SIZE_T) - 1) ++ ++#define SIZE_PTR SIZE_T ++#define SSIZE_PTR SSIZE_T ++ ++//port from fw by thomas ++// TODO: Belows are Sync from SD7-Driver. It is necessary to check correctness ++ ++/* ++ * Call endian free function when ++ * 1. Read/write packet content. ++ * 2. Before write integer to IO. ++ * 3. After read integer from IO. ++*/ ++ ++// ++// Byte Swapping routine. ++// ++#define EF1Byte ++#define EF2Byte le16_to_cpu ++#define EF4Byte le32_to_cpu ++ ++// ++// Read LE format data from memory ++// ++#define ReadEF1Byte(_ptr) EF1Byte(*((u8 *)(_ptr))) ++#define ReadEF2Byte(_ptr) EF2Byte(*((u16 *)(_ptr))) ++#define ReadEF4Byte(_ptr) EF4Byte(*((u32 *)(_ptr))) ++ ++// ++// Write LE data to memory ++// ++#define WriteEF1Byte(_ptr, _val) (*((u8 *)(_ptr)))=EF1Byte(_val) ++#define WriteEF2Byte(_ptr, _val) (*((u16 *)(_ptr)))=EF2Byte(_val) ++#define WriteEF4Byte(_ptr, _val) (*((u32 *)(_ptr)))=EF4Byte(_val) ++ ++// ++// Example: ++// BIT_LEN_MASK_32(0) => 0x00000000 ++// BIT_LEN_MASK_32(1) => 0x00000001 ++// BIT_LEN_MASK_32(2) => 0x00000003 ++// BIT_LEN_MASK_32(32) => 0xFFFFFFFF ++// ++#define BIT_LEN_MASK_32(__BitLen) \ ++ (0xFFFFFFFF >> (32 - (__BitLen))) ++// ++// Example: ++// BIT_OFFSET_LEN_MASK_32(0, 2) => 0x00000003 ++// BIT_OFFSET_LEN_MASK_32(16, 2) => 0x00030000 ++// ++#define BIT_OFFSET_LEN_MASK_32(__BitOffset, __BitLen) \ ++ (BIT_LEN_MASK_32(__BitLen) << (__BitOffset)) ++ ++// ++// Description: ++// Return 4-byte value in host byte ordering from ++// 4-byte pointer in litten-endian system. ++// ++#define LE_P4BYTE_TO_HOST_4BYTE(__pStart) \ ++ (EF4Byte(*((u32 *)(__pStart)))) ++ ++// ++// Description: ++// Translate subfield (continuous bits in little-endian) of 4-byte value in litten byte to ++// 4-byte value in host byte ordering. ++// ++#define LE_BITS_TO_4BYTE(__pStart, __BitOffset, __BitLen) \ ++ ( \ ++ ( LE_P4BYTE_TO_HOST_4BYTE(__pStart) >> (__BitOffset) ) \ ++ & \ ++ BIT_LEN_MASK_32(__BitLen) \ ++ ) ++ ++// ++// Description: ++// Mask subfield (continuous bits in little-endian) of 4-byte value in litten byte oredering ++// and return the result in 4-byte value in host byte ordering. ++// ++#define LE_BITS_CLEARED_TO_4BYTE(__pStart, __BitOffset, __BitLen) \ ++ ( \ ++ LE_P4BYTE_TO_HOST_4BYTE(__pStart) \ ++ & \ ++ ( ~BIT_OFFSET_LEN_MASK_32(__BitOffset, __BitLen) ) \ ++ ) ++ ++// ++// Description: ++// Set subfield of little-endian 4-byte value to specified value. ++// ++#define SET_BITS_TO_LE_4BYTE(__pStart, __BitOffset, __BitLen, __Value) \ ++ *((u32 *)(__pStart)) = \ ++ EF4Byte( \ ++ LE_BITS_CLEARED_TO_4BYTE(__pStart, __BitOffset, __BitLen) \ ++ | \ ++ ( (((u32)__Value) & BIT_LEN_MASK_32(__BitLen)) << (__BitOffset) ) \ ++ ); ++ ++ ++#define BIT_LEN_MASK_16(__BitLen) \ ++ (0xFFFF >> (16 - (__BitLen))) ++ ++#define BIT_OFFSET_LEN_MASK_16(__BitOffset, __BitLen) \ ++ (BIT_LEN_MASK_16(__BitLen) << (__BitOffset)) ++ ++#define LE_P2BYTE_TO_HOST_2BYTE(__pStart) \ ++ (EF2Byte(*((u16 *)(__pStart)))) ++ ++#define LE_BITS_TO_2BYTE(__pStart, __BitOffset, __BitLen) \ ++ ( \ ++ ( LE_P2BYTE_TO_HOST_2BYTE(__pStart) >> (__BitOffset) ) \ ++ & \ ++ BIT_LEN_MASK_16(__BitLen) \ ++ ) ++ ++#define LE_BITS_CLEARED_TO_2BYTE(__pStart, __BitOffset, __BitLen) \ ++ ( \ ++ LE_P2BYTE_TO_HOST_2BYTE(__pStart) \ ++ & \ ++ ( ~BIT_OFFSET_LEN_MASK_16(__BitOffset, __BitLen) ) \ ++ ) ++ ++#define SET_BITS_TO_LE_2BYTE(__pStart, __BitOffset, __BitLen, __Value) \ ++ *((u16 *)(__pStart)) = \ ++ EF2Byte( \ ++ LE_BITS_CLEARED_TO_2BYTE(__pStart, __BitOffset, __BitLen) \ ++ | \ ++ ( (((u16)__Value) & BIT_LEN_MASK_16(__BitLen)) << (__BitOffset) ) \ ++ ); ++ ++#define BIT_LEN_MASK_8(__BitLen) \ ++ (0xFF >> (8 - (__BitLen))) ++ ++#define BIT_OFFSET_LEN_MASK_8(__BitOffset, __BitLen) \ ++ (BIT_LEN_MASK_8(__BitLen) << (__BitOffset)) ++ ++#define LE_P1BYTE_TO_HOST_1BYTE(__pStart) \ ++ (EF1Byte(*((u8 *)(__pStart)))) ++ ++#define LE_BITS_TO_1BYTE(__pStart, __BitOffset, __BitLen) \ ++ ( \ ++ ( LE_P1BYTE_TO_HOST_1BYTE(__pStart) >> (__BitOffset) ) \ ++ & \ ++ BIT_LEN_MASK_8(__BitLen) \ ++ ) ++ ++#define LE_BITS_CLEARED_TO_1BYTE(__pStart, __BitOffset, __BitLen) \ ++ ( \ ++ LE_P1BYTE_TO_HOST_1BYTE(__pStart) \ ++ & \ ++ ( ~BIT_OFFSET_LEN_MASK_8(__BitOffset, __BitLen) ) \ ++ ) ++ ++#define SET_BITS_TO_LE_1BYTE(__pStart, __BitOffset, __BitLen, __Value) \ ++ *((u8 *)(__pStart)) = \ ++ EF1Byte( \ ++ LE_BITS_CLEARED_TO_1BYTE(__pStart, __BitOffset, __BitLen) \ ++ | \ ++ ( (((u8)__Value) & BIT_LEN_MASK_8(__BitLen)) << (__BitOffset) ) \ ++ ); ++ ++//pclint ++#define LE_BITS_CLEARED_TO_1BYTE_8BIT(__pStart, __BitOffset, __BitLen) \ ++ ( \ ++ LE_P1BYTE_TO_HOST_1BYTE(__pStart) \ ++ ) ++ ++//pclint ++#define SET_BITS_TO_LE_1BYTE_8BIT(__pStart, __BitOffset, __BitLen, __Value) \ ++{ \ ++ *((pu1Byte)(__pStart)) = \ ++ EF1Byte( \ ++ LE_BITS_CLEARED_TO_1BYTE_8BIT(__pStart, __BitOffset, __BitLen) \ ++ | \ ++ ((u1Byte)__Value) \ ++ ); \ ++} ++ ++// Get the N-bytes aligment offset from the current length ++#define N_BYTE_ALIGMENT(__Value, __Aligment) ((__Aligment == 1) ? (__Value) : (((__Value + __Aligment - 1) / __Aligment) * __Aligment)) ++ ++typedef unsigned char BOOLEAN,*PBOOLEAN; ++ ++#endif //__BASIC_TYPES_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/byteorder/big_endian.h b/drivers/net/wireless/rtl818x/rtl8189/include/byteorder/big_endian.h +new file mode 100644 +index 00000000..ccb31328 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/byteorder/big_endian.h +@@ -0,0 +1,88 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _LINUX_BYTEORDER_BIG_ENDIAN_H ++#define _LINUX_BYTEORDER_BIG_ENDIAN_H ++ ++#ifndef __BIG_ENDIAN ++#define __BIG_ENDIAN 4321 ++#endif ++#ifndef __BIG_ENDIAN_BITFIELD ++#define __BIG_ENDIAN_BITFIELD ++#endif ++ ++#include ++ ++#define __constant_htonl(x) ((__u32)(x)) ++#define __constant_ntohl(x) ((__u32)(x)) ++#define __constant_htons(x) ((__u16)(x)) ++#define __constant_ntohs(x) ((__u16)(x)) ++#define __constant_cpu_to_le64(x) ___constant_swab64((x)) ++#define __constant_le64_to_cpu(x) ___constant_swab64((x)) ++#define __constant_cpu_to_le32(x) ___constant_swab32((x)) ++#define __constant_le32_to_cpu(x) ___constant_swab32((x)) ++#define __constant_cpu_to_le16(x) ___constant_swab16((x)) ++#define __constant_le16_to_cpu(x) ___constant_swab16((x)) ++#define __constant_cpu_to_be64(x) ((__u64)(x)) ++#define __constant_be64_to_cpu(x) ((__u64)(x)) ++#define __constant_cpu_to_be32(x) ((__u32)(x)) ++#define __constant_be32_to_cpu(x) ((__u32)(x)) ++#define __constant_cpu_to_be16(x) ((__u16)(x)) ++#define __constant_be16_to_cpu(x) ((__u16)(x)) ++#define __cpu_to_le64(x) __swab64((x)) ++#define __le64_to_cpu(x) __swab64((x)) ++#define __cpu_to_le32(x) __swab32((x)) ++#define __le32_to_cpu(x) __swab32((x)) ++#define __cpu_to_le16(x) __swab16((x)) ++#define __le16_to_cpu(x) __swab16((x)) ++#define __cpu_to_be64(x) ((__u64)(x)) ++#define __be64_to_cpu(x) ((__u64)(x)) ++#define __cpu_to_be32(x) ((__u32)(x)) ++#define __be32_to_cpu(x) ((__u32)(x)) ++#define __cpu_to_be16(x) ((__u16)(x)) ++#define __be16_to_cpu(x) ((__u16)(x)) ++#define __cpu_to_le64p(x) __swab64p((x)) ++#define __le64_to_cpup(x) __swab64p((x)) ++#define __cpu_to_le32p(x) __swab32p((x)) ++#define __le32_to_cpup(x) __swab32p((x)) ++#define __cpu_to_le16p(x) __swab16p((x)) ++#define __le16_to_cpup(x) __swab16p((x)) ++#define __cpu_to_be64p(x) (*(__u64*)(x)) ++#define __be64_to_cpup(x) (*(__u64*)(x)) ++#define __cpu_to_be32p(x) (*(__u32*)(x)) ++#define __be32_to_cpup(x) (*(__u32*)(x)) ++#define __cpu_to_be16p(x) (*(__u16*)(x)) ++#define __be16_to_cpup(x) (*(__u16*)(x)) ++#define __cpu_to_le64s(x) __swab64s((x)) ++#define __le64_to_cpus(x) __swab64s((x)) ++#define __cpu_to_le32s(x) __swab32s((x)) ++#define __le32_to_cpus(x) __swab32s((x)) ++#define __cpu_to_le16s(x) __swab16s((x)) ++#define __le16_to_cpus(x) __swab16s((x)) ++#define __cpu_to_be64s(x) do {} while (0) ++#define __be64_to_cpus(x) do {} while (0) ++#define __cpu_to_be32s(x) do {} while (0) ++#define __be32_to_cpus(x) do {} while (0) ++#define __cpu_to_be16s(x) do {} while (0) ++#define __be16_to_cpus(x) do {} while (0) ++ ++#include ++ ++#endif /* _LINUX_BYTEORDER_BIG_ENDIAN_H */ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/byteorder/generic.h b/drivers/net/wireless/rtl818x/rtl8189/include/byteorder/generic.h +new file mode 100644 +index 00000000..759b0c47 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/byteorder/generic.h +@@ -0,0 +1,213 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _LINUX_BYTEORDER_GENERIC_H ++#define _LINUX_BYTEORDER_GENERIC_H ++ ++/* ++ * linux/byteorder_generic.h ++ * Generic Byte-reordering support ++ * ++ * Francois-Rene Rideau 19970707 ++ * gathered all the good ideas from all asm-foo/byteorder.h into one file, ++ * cleaned them up. ++ * I hope it is compliant with non-GCC compilers. ++ * I decided to put __BYTEORDER_HAS_U64__ in byteorder.h, ++ * because I wasn't sure it would be ok to put it in types.h ++ * Upgraded it to 2.1.43 ++ * Francois-Rene Rideau 19971012 ++ * Upgraded it to 2.1.57 ++ * to please Linus T., replaced huge #ifdef's between little/big endian ++ * by nestedly #include'd files. ++ * Francois-Rene Rideau 19971205 ++ * Made it to 2.1.71; now a facelift: ++ * Put files under include/linux/byteorder/ ++ * Split swab from generic support. ++ * ++ * TODO: ++ * = Regular kernel maintainers could also replace all these manual ++ * byteswap macros that remain, disseminated among drivers, ++ * after some grep or the sources... ++ * = Linus might want to rename all these macros and files to fit his taste, ++ * to fit his personal naming scheme. ++ * = it seems that a few drivers would also appreciate ++ * nybble swapping support... ++ * = every architecture could add their byteswap macro in asm/byteorder.h ++ * see how some architectures already do (i386, alpha, ppc, etc) ++ * = cpu_to_beXX and beXX_to_cpu might some day need to be well ++ * distinguished throughout the kernel. This is not the case currently, ++ * since little endian, big endian, and pdp endian machines needn't it. ++ * But this might be the case for, say, a port of Linux to 20/21 bit ++ * architectures (and F21 Linux addict around?). ++ */ ++ ++/* ++ * The following macros are to be defined by : ++ * ++ * Conversion of long and short int between network and host format ++ * ntohl(__u32 x) ++ * ntohs(__u16 x) ++ * htonl(__u32 x) ++ * htons(__u16 x) ++ * It seems that some programs (which? where? or perhaps a standard? POSIX?) ++ * might like the above to be functions, not macros (why?). ++ * if that's true, then detect them, and take measures. ++ * Anyway, the measure is: define only ___ntohl as a macro instead, ++ * and in a separate file, have ++ * unsigned long inline ntohl(x){return ___ntohl(x);} ++ * ++ * The same for constant arguments ++ * __constant_ntohl(__u32 x) ++ * __constant_ntohs(__u16 x) ++ * __constant_htonl(__u32 x) ++ * __constant_htons(__u16 x) ++ * ++ * Conversion of XX-bit integers (16- 32- or 64-) ++ * between native CPU format and little/big endian format ++ * 64-bit stuff only defined for proper architectures ++ * cpu_to_[bl]eXX(__uXX x) ++ * [bl]eXX_to_cpu(__uXX x) ++ * ++ * The same, but takes a pointer to the value to convert ++ * cpu_to_[bl]eXXp(__uXX x) ++ * [bl]eXX_to_cpup(__uXX x) ++ * ++ * The same, but change in situ ++ * cpu_to_[bl]eXXs(__uXX x) ++ * [bl]eXX_to_cpus(__uXX x) ++ * ++ * See asm-foo/byteorder.h for examples of how to provide ++ * architecture-optimized versions ++ * ++ */ ++ ++ ++#if defined(PLATFORM_LINUX) || defined(PLATFORM_WINDOWS) || defined(PLATFORM_MPIXEL) || defined(PLATFORM_FREEBSD) ++/* ++ * inside the kernel, we can use nicknames; ++ * outside of it, we must avoid POSIX namespace pollution... ++ */ ++#define cpu_to_le64 __cpu_to_le64 ++#define le64_to_cpu __le64_to_cpu ++#define cpu_to_le32 __cpu_to_le32 ++#define le32_to_cpu __le32_to_cpu ++#define cpu_to_le16 __cpu_to_le16 ++#define le16_to_cpu __le16_to_cpu ++#define cpu_to_be64 __cpu_to_be64 ++#define be64_to_cpu __be64_to_cpu ++#define cpu_to_be32 __cpu_to_be32 ++#define be32_to_cpu __be32_to_cpu ++#define cpu_to_be16 __cpu_to_be16 ++#define be16_to_cpu __be16_to_cpu ++#define cpu_to_le64p __cpu_to_le64p ++#define le64_to_cpup __le64_to_cpup ++#define cpu_to_le32p __cpu_to_le32p ++#define le32_to_cpup __le32_to_cpup ++#define cpu_to_le16p __cpu_to_le16p ++#define le16_to_cpup __le16_to_cpup ++#define cpu_to_be64p __cpu_to_be64p ++#define be64_to_cpup __be64_to_cpup ++#define cpu_to_be32p __cpu_to_be32p ++#define be32_to_cpup __be32_to_cpup ++#define cpu_to_be16p __cpu_to_be16p ++#define be16_to_cpup __be16_to_cpup ++#define cpu_to_le64s __cpu_to_le64s ++#define le64_to_cpus __le64_to_cpus ++#define cpu_to_le32s __cpu_to_le32s ++#define le32_to_cpus __le32_to_cpus ++#define cpu_to_le16s __cpu_to_le16s ++#define le16_to_cpus __le16_to_cpus ++#define cpu_to_be64s __cpu_to_be64s ++#define be64_to_cpus __be64_to_cpus ++#define cpu_to_be32s __cpu_to_be32s ++#define be32_to_cpus __be32_to_cpus ++#define cpu_to_be16s __cpu_to_be16s ++#define be16_to_cpus __be16_to_cpus ++#endif ++ ++ ++/* ++ * Handle ntohl and suches. These have various compatibility ++ * issues - like we want to give the prototype even though we ++ * also have a macro for them in case some strange program ++ * wants to take the address of the thing or something.. ++ * ++ * Note that these used to return a "long" in libc5, even though ++ * long is often 64-bit these days.. Thus the casts. ++ * ++ * They have to be macros in order to do the constant folding ++ * correctly - if the argument passed into a inline function ++ * it is no longer constant according to gcc.. ++ */ ++ ++#undef ntohl ++#undef ntohs ++#undef htonl ++#undef htons ++ ++/* ++ * Do the prototypes. Somebody might want to take the ++ * address or some such sick thing.. ++ */ ++#if defined(PLATFORM_LINUX) || (defined (__GLIBC__) && __GLIBC__ >= 2) ++extern __u32 ntohl(__u32); ++extern __u32 htonl(__u32); ++#else //defined(PLATFORM_LINUX) || (defined (__GLIBC__) && __GLIBC__ >= 2) ++#ifndef PLATFORM_FREEBSD ++extern unsigned long int ntohl(unsigned long int); ++extern unsigned long int htonl(unsigned long int); ++#endif ++#endif ++#ifndef PLATFORM_FREEBSD ++extern unsigned short int ntohs(unsigned short int); ++extern unsigned short int htons(unsigned short int); ++#endif ++ ++#if defined(__GNUC__) && (__GNUC__ >= 2) && defined(__OPTIMIZE__) || defined(PLATFORM_MPIXEL) ++ ++#define ___htonl(x) __cpu_to_be32(x) ++#define ___htons(x) __cpu_to_be16(x) ++#define ___ntohl(x) __be32_to_cpu(x) ++#define ___ntohs(x) __be16_to_cpu(x) ++ ++#if defined(PLATFORM_LINUX) || (defined (__GLIBC__) && __GLIBC__ >= 2) ++#define htonl(x) ___htonl(x) ++#define ntohl(x) ___ntohl(x) ++#else ++#define htonl(x) ((unsigned long)___htonl(x)) ++#define ntohl(x) ((unsigned long)___ntohl(x)) ++#endif ++#define htons(x) ___htons(x) ++#define ntohs(x) ___ntohs(x) ++ ++#endif /* OPTIMIZE */ ++ ++ ++#if defined (PLATFORM_WINDOWS) ++ ++#define htonl(x) __cpu_to_be32(x) ++#define ntohl(x) __be32_to_cpu(x) ++#define htons(x) __cpu_to_be16(x) ++#define ntohs(x) __be16_to_cpu(x) ++ ++ ++#endif ++ ++#endif /* _LINUX_BYTEORDER_GENERIC_H */ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/byteorder/little_endian.h b/drivers/net/wireless/rtl818x/rtl8189/include/byteorder/little_endian.h +new file mode 100644 +index 00000000..5a3c8ab4 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/byteorder/little_endian.h +@@ -0,0 +1,90 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _LINUX_BYTEORDER_LITTLE_ENDIAN_H ++#define _LINUX_BYTEORDER_LITTLE_ENDIAN_H ++ ++#ifndef __LITTLE_ENDIAN ++#define __LITTLE_ENDIAN 1234 ++#endif ++#ifndef __LITTLE_ENDIAN_BITFIELD ++#define __LITTLE_ENDIAN_BITFIELD ++#endif ++ ++#include ++ ++#ifndef __constant_htonl ++#define __constant_htonl(x) ___constant_swab32((x)) ++#define __constant_ntohl(x) ___constant_swab32((x)) ++#define __constant_htons(x) ___constant_swab16((x)) ++#define __constant_ntohs(x) ___constant_swab16((x)) ++#define __constant_cpu_to_le64(x) ((__u64)(x)) ++#define __constant_le64_to_cpu(x) ((__u64)(x)) ++#define __constant_cpu_to_le32(x) ((__u32)(x)) ++#define __constant_le32_to_cpu(x) ((__u32)(x)) ++#define __constant_cpu_to_le16(x) ((__u16)(x)) ++#define __constant_le16_to_cpu(x) ((__u16)(x)) ++#define __constant_cpu_to_be64(x) ___constant_swab64((x)) ++#define __constant_be64_to_cpu(x) ___constant_swab64((x)) ++#define __constant_cpu_to_be32(x) ___constant_swab32((x)) ++#define __constant_be32_to_cpu(x) ___constant_swab32((x)) ++#define __constant_cpu_to_be16(x) ___constant_swab16((x)) ++#define __constant_be16_to_cpu(x) ___constant_swab16((x)) ++#define __cpu_to_le64(x) ((__u64)(x)) ++#define __le64_to_cpu(x) ((__u64)(x)) ++#define __cpu_to_le32(x) ((__u32)(x)) ++#define __le32_to_cpu(x) ((__u32)(x)) ++#define __cpu_to_le16(x) ((__u16)(x)) ++#define __le16_to_cpu(x) ((__u16)(x)) ++#define __cpu_to_be64(x) __swab64((x)) ++#define __be64_to_cpu(x) __swab64((x)) ++#define __cpu_to_be32(x) __swab32((x)) ++#define __be32_to_cpu(x) __swab32((x)) ++#define __cpu_to_be16(x) __swab16((x)) ++#define __be16_to_cpu(x) __swab16((x)) ++#define __cpu_to_le64p(x) (*(__u64*)(x)) ++#define __le64_to_cpup(x) (*(__u64*)(x)) ++#define __cpu_to_le32p(x) (*(__u32*)(x)) ++#define __le32_to_cpup(x) (*(__u32*)(x)) ++#define __cpu_to_le16p(x) (*(__u16*)(x)) ++#define __le16_to_cpup(x) (*(__u16*)(x)) ++#define __cpu_to_be64p(x) __swab64p((x)) ++#define __be64_to_cpup(x) __swab64p((x)) ++#define __cpu_to_be32p(x) __swab32p((x)) ++#define __be32_to_cpup(x) __swab32p((x)) ++#define __cpu_to_be16p(x) __swab16p((x)) ++#define __be16_to_cpup(x) __swab16p((x)) ++#define __cpu_to_le64s(x) do {} while (0) ++#define __le64_to_cpus(x) do {} while (0) ++#define __cpu_to_le32s(x) do {} while (0) ++#define __le32_to_cpus(x) do {} while (0) ++#define __cpu_to_le16s(x) do {} while (0) ++#define __le16_to_cpus(x) do {} while (0) ++#define __cpu_to_be64s(x) __swab64s((x)) ++#define __be64_to_cpus(x) __swab64s((x)) ++#define __cpu_to_be32s(x) __swab32s((x)) ++#define __be32_to_cpus(x) __swab32s((x)) ++#define __cpu_to_be16s(x) __swab16s((x)) ++#define __be16_to_cpus(x) __swab16s((x)) ++#endif // __constant_htonl ++ ++#include ++ ++#endif /* _LINUX_BYTEORDER_LITTLE_ENDIAN_H */ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/byteorder/swab.h b/drivers/net/wireless/rtl818x/rtl8189/include/byteorder/swab.h +new file mode 100644 +index 00000000..067c8e43 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/byteorder/swab.h +@@ -0,0 +1,141 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _LINUX_BYTEORDER_SWAB_H ++#define _LINUX_BYTEORDER_SWAB_H ++ ++#if !defined(CONFIG_PLATFORM_MSTAR) ++#ifndef __u16 ++typedef unsigned short __u16; ++#endif ++ ++#ifndef __u32 ++typedef unsigned int __u32; ++#endif ++ ++#ifndef __u8 ++typedef unsigned char __u8; ++#endif ++ ++#ifndef __u64 ++typedef unsigned long long __u64; ++#endif ++ ++ ++__inline static __u16 ___swab16(__u16 x) ++{ ++ __u16 __x = x; ++ return ++ ((__u16)( ++ (((__u16)(__x) & (__u16)0x00ffU) << 8) | ++ (((__u16)(__x) & (__u16)0xff00U) >> 8) )); ++ ++} ++ ++__inline static __u32 ___swab32(__u32 x) ++{ ++ __u32 __x = (x); ++ return ((__u32)( ++ (((__u32)(__x) & (__u32)0x000000ffUL) << 24) | ++ (((__u32)(__x) & (__u32)0x0000ff00UL) << 8) | ++ (((__u32)(__x) & (__u32)0x00ff0000UL) >> 8) | ++ (((__u32)(__x) & (__u32)0xff000000UL) >> 24) )); ++} ++ ++__inline static __u64 ___swab64(__u64 x) ++{ ++ __u64 __x = (x); ++ ++ return ++ ((__u64)( \ ++ (__u64)(((__u64)(__x) & (__u64)0x00000000000000ffULL) << 56) | \ ++ (__u64)(((__u64)(__x) & (__u64)0x000000000000ff00ULL) << 40) | \ ++ (__u64)(((__u64)(__x) & (__u64)0x0000000000ff0000ULL) << 24) | \ ++ (__u64)(((__u64)(__x) & (__u64)0x00000000ff000000ULL) << 8) | \ ++ (__u64)(((__u64)(__x) & (__u64)0x000000ff00000000ULL) >> 8) | \ ++ (__u64)(((__u64)(__x) & (__u64)0x0000ff0000000000ULL) >> 24) | \ ++ (__u64)(((__u64)(__x) & (__u64)0x00ff000000000000ULL) >> 40) | \ ++ (__u64)(((__u64)(__x) & (__u64)0xff00000000000000ULL) >> 56) )); \ ++} ++#endif // CONFIG_PLATFORM_MSTAR ++ ++#ifndef __arch__swab16 ++__inline static __u16 __arch__swab16(__u16 x) ++{ ++ return ___swab16(x); ++} ++ ++#endif ++ ++#ifndef __arch__swab32 ++__inline static __u32 __arch__swab32(__u32 x) ++{ ++ __u32 __tmp = (x) ; ++ return ___swab32(__tmp); ++} ++#endif ++ ++#ifndef __arch__swab64 ++ ++__inline static __u64 __arch__swab64(__u64 x) ++{ ++ __u64 __tmp = (x) ; ++ return ___swab64(__tmp); ++} ++ ++ ++#endif ++ ++#ifndef __swab16 ++#define __swab16(x) __fswab16(x) ++#define __swab32(x) __fswab32(x) ++#define __swab64(x) __fswab64(x) ++#endif // __swab16 ++ ++#ifdef PLATFORM_FREEBSD ++__inline static __u16 __fswab16(__u16 x) ++#else ++__inline static const __u16 __fswab16(__u16 x) ++#endif //PLATFORM_FREEBSD ++{ ++ return __arch__swab16(x); ++} ++#ifdef PLATFORM_FREEBSD ++__inline static __u32 __fswab32(__u32 x) ++#else ++__inline static const __u32 __fswab32(__u32 x) ++#endif //PLATFORM_FREEBSD ++{ ++ return __arch__swab32(x); ++} ++ ++#if defined(PLATFORM_LINUX) || defined(PLATFORM_WINDOWS) ++#define swab16 __swab16 ++#define swab32 __swab32 ++#define swab64 __swab64 ++#define swab16p __swab16p ++#define swab32p __swab32p ++#define swab64p __swab64p ++#define swab16s __swab16s ++#define swab32s __swab32s ++#define swab64s __swab64s ++#endif ++ ++#endif /* _LINUX_BYTEORDER_SWAB_H */ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/byteorder/swabb.h b/drivers/net/wireless/rtl818x/rtl8189/include/byteorder/swabb.h +new file mode 100644 +index 00000000..dbbd50f8 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/byteorder/swabb.h +@@ -0,0 +1,157 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _LINUX_BYTEORDER_SWABB_H ++#define _LINUX_BYTEORDER_SWABB_H ++ ++/* ++ * linux/byteorder/swabb.h ++ * SWAp Bytes Bizarrely ++ * swaHHXX[ps]?(foo) ++ * ++ * Support for obNUXIous pdp-endian and other bizarre architectures. ++ * Will Linux ever run on such ancient beasts? if not, this file ++ * will be but a programming pearl. Still, it's a reminder that we ++ * shouldn't be making too many assumptions when trying to be portable. ++ * ++ */ ++ ++/* ++ * Meaning of the names I chose (vaxlinux people feel free to correct them): ++ * swahw32 swap 16-bit half-words in a 32-bit word ++ * swahb32 swap 8-bit halves of each 16-bit half-word in a 32-bit word ++ * ++ * No 64-bit support yet. I don't know NUXI conventions for long longs. ++ * I guarantee it will be a mess when it's there, though :-> ++ * It will be even worse if there are conflicting 64-bit conventions. ++ * Hopefully, no one ever used 64-bit objects on NUXI machines. ++ * ++ */ ++ ++#define ___swahw32(x) \ ++({ \ ++ __u32 __x = (x); \ ++ ((__u32)( \ ++ (((__u32)(__x) & (__u32)0x0000ffffUL) << 16) | \ ++ (((__u32)(__x) & (__u32)0xffff0000UL) >> 16) )); \ ++}) ++#define ___swahb32(x) \ ++({ \ ++ __u32 __x = (x); \ ++ ((__u32)( \ ++ (((__u32)(__x) & (__u32)0x00ff00ffUL) << 8) | \ ++ (((__u32)(__x) & (__u32)0xff00ff00UL) >> 8) )); \ ++}) ++ ++#define ___constant_swahw32(x) \ ++ ((__u32)( \ ++ (((__u32)(x) & (__u32)0x0000ffffUL) << 16) | \ ++ (((__u32)(x) & (__u32)0xffff0000UL) >> 16) )) ++#define ___constant_swahb32(x) \ ++ ((__u32)( \ ++ (((__u32)(x) & (__u32)0x00ff00ffUL) << 8) | \ ++ (((__u32)(x) & (__u32)0xff00ff00UL) >> 8) )) ++ ++/* ++ * provide defaults when no architecture-specific optimization is detected ++ */ ++#ifndef __arch__swahw32 ++# define __arch__swahw32(x) ___swahw32(x) ++#endif ++#ifndef __arch__swahb32 ++# define __arch__swahb32(x) ___swahb32(x) ++#endif ++ ++#ifndef __arch__swahw32p ++# define __arch__swahw32p(x) __swahw32(*(x)) ++#endif ++#ifndef __arch__swahb32p ++# define __arch__swahb32p(x) __swahb32(*(x)) ++#endif ++ ++#ifndef __arch__swahw32s ++# define __arch__swahw32s(x) do { *(x) = __swahw32p((x)); } while (0) ++#endif ++#ifndef __arch__swahb32s ++# define __arch__swahb32s(x) do { *(x) = __swahb32p((x)); } while (0) ++#endif ++ ++ ++/* ++ * Allow constant folding ++ */ ++#if defined(__GNUC__) && (__GNUC__ >= 2) && defined(__OPTIMIZE__) ++# define __swahw32(x) \ ++(__builtin_constant_p((__u32)(x)) ? \ ++ ___swahw32((x)) : \ ++ __fswahw32((x))) ++# define __swahb32(x) \ ++(__builtin_constant_p((__u32)(x)) ? \ ++ ___swahb32((x)) : \ ++ __fswahb32((x))) ++#else ++# define __swahw32(x) __fswahw32(x) ++# define __swahb32(x) __fswahb32(x) ++#endif /* OPTIMIZE */ ++ ++ ++__inline static__ __const__ __u32 __fswahw32(__u32 x) ++{ ++ return __arch__swahw32(x); ++} ++__inline static__ __u32 __swahw32p(__u32 *x) ++{ ++ return __arch__swahw32p(x); ++} ++__inline static__ void __swahw32s(__u32 *addr) ++{ ++ __arch__swahw32s(addr); ++} ++ ++ ++__inline static__ __const__ __u32 __fswahb32(__u32 x) ++{ ++ return __arch__swahb32(x); ++} ++__inline static__ __u32 __swahb32p(__u32 *x) ++{ ++ return __arch__swahb32p(x); ++} ++__inline static__ void __swahb32s(__u32 *addr) ++{ ++ __arch__swahb32s(addr); ++} ++ ++#ifdef __BYTEORDER_HAS_U64__ ++/* ++ * Not supported yet ++ */ ++#endif /* __BYTEORDER_HAS_U64__ */ ++ ++#if defined(PLATFORM_LINUX) ++#define swahw32 __swahw32 ++#define swahb32 __swahb32 ++#define swahw32p __swahw32p ++#define swahb32p __swahb32p ++#define swahw32s __swahw32s ++#define swahb32s __swahb32s ++#endif ++ ++#endif /* _LINUX_BYTEORDER_SWABB_H */ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/circ_buf.h b/drivers/net/wireless/rtl818x/rtl8189/include/circ_buf.h +new file mode 100644 +index 00000000..23523164 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/circ_buf.h +@@ -0,0 +1,28 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __CIRC_BUF_H_ ++#define __CIRC_BUF_H_ 1 ++ ++#define CIRC_CNT(head,tail,size) (((head) - (tail)) & ((size)-1)) ++ ++#define CIRC_SPACE(head,tail,size) CIRC_CNT((tail),((head)+1),(size)) ++ ++#endif //_CIRC_BUF_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/cmd_osdep.h b/drivers/net/wireless/rtl818x/rtl8189/include/cmd_osdep.h +new file mode 100644 +index 00000000..077efa73 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/cmd_osdep.h +@@ -0,0 +1,36 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __CMD_OSDEP_H_ ++#define __CMD_OSDEP_H_ ++ ++ ++#include ++#include ++#include ++ ++extern sint _rtw_init_cmd_priv (struct cmd_priv *pcmdpriv); ++extern sint _rtw_init_evt_priv(struct evt_priv *pevtpriv); ++extern void _rtw_free_evt_priv (struct evt_priv *pevtpriv); ++extern void _rtw_free_cmd_priv (struct cmd_priv *pcmdpriv); ++extern sint _rtw_enqueue_cmd(_queue *queue, struct cmd_obj *obj); ++extern struct cmd_obj *_rtw_dequeue_cmd(_queue *queue); ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/custom_gpio.h b/drivers/net/wireless/rtl818x/rtl8189/include/custom_gpio.h +new file mode 100644 +index 00000000..c76b340f +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/custom_gpio.h +@@ -0,0 +1,32 @@ ++#ifndef __CUSTOM_GPIO_H__ ++#define __CUSTOM_GPIO_H___ ++ ++#include ++#include ++ ++#ifdef PLATFORM_OS_XP ++#include ++#endif ++ ++#ifdef PLATFORM_OS_CE ++#include ++#endif ++ ++#ifdef PLATFORM_LINUX ++#include ++#endif ++ ++typedef enum cust_gpio_modes { ++ WLAN_PWDN_ON, ++ WLAN_PWDN_OFF, ++ WLAN_POWER_ON, ++ WLAN_POWER_OFF, ++ WLAN_BT_PWDN_ON, ++ WLAN_BT_PWDN_OFF ++} cust_gpio_modes_t; ++ ++extern int rtw_wifi_gpio_init(void); ++extern int rtw_wifi_gpio_deinit(void); ++extern void rtw_wifi_gpio_wlan_ctrl(int onoff); ++ ++#endif +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/drv_conf.h b/drivers/net/wireless/rtl818x/rtl8189/include/drv_conf.h +new file mode 100644 +index 00000000..13176879 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/drv_conf.h +@@ -0,0 +1,78 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __DRV_CONF_H__ ++#define __DRV_CONF_H__ ++#include "autoconf.h" ++ ++#if defined (PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) ++ ++#error "Shall be Linux or Windows, but not both!\n" ++ ++#endif ++ ++//Older Android kernel doesn't has CONFIG_ANDROID defined, ++//add this to force CONFIG_ANDROID defined ++#ifdef CONFIG_PLATFORM_ANDROID ++#define CONFIG_ANDROID ++#endif ++ ++#ifdef CONFIG_ANDROID ++//Some Android build will restart the UI while non-printable ascii is passed ++//between java and c/c++ layer (JNI). We force CONFIG_VALIDATE_SSID ++//for Android here. If you are sure there is no risk on your system about this, ++//mask this macro define to support non-printable ascii ssid. ++//#define CONFIG_VALIDATE_SSID ++ ++//Android expect dbm as the rx signal strength unit ++#define CONFIG_SIGNAL_DISPLAY_DBM ++#endif ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined (CONFIG_RESUME_IN_WORKQUEUE) ++ #warning "You have CONFIG_HAS_EARLYSUSPEND enabled in your system, we disable CONFIG_RESUME_IN_WORKQUEUE automatically" ++ #undef CONFIG_RESUME_IN_WORKQUEUE ++#endif ++ ++#if defined(CONFIG_ANDROID_POWER) && defined (CONFIG_RESUME_IN_WORKQUEUE) ++ #warning "You have CONFIG_ANDROID_POWER enabled in your system, we disable CONFIG_RESUME_IN_WORKQUEUE automatically" ++ #undef CONFIG_RESUME_IN_WORKQUEUE ++#endif ++ ++#ifdef CONFIG_RESUME_IN_WORKQUEUE //this can be removed, because there is no case for this... ++ #if !defined( CONFIG_WAKELOCK) && !defined(CONFIG_ANDROID_POWER) ++ #error "enable CONFIG_RESUME_IN_WORKQUEUE without CONFIG_WAKELOCK or CONFIG_ANDROID_POWER will suffer from the danger of wifi's unfunctionality..." ++ #error "If you still want to enable CONFIG_RESUME_IN_WORKQUEUE in this case, mask this preprossor checking and GOOD LUCK..." ++ #endif ++#endif ++ ++//About USB VENDOR REQ ++#if defined(CONFIG_USB_VENDOR_REQ_BUFFER_PREALLOC) && !defined(CONFIG_USB_VENDOR_REQ_MUTEX) ++ #warning "define CONFIG_USB_VENDOR_REQ_MUTEX for CONFIG_USB_VENDOR_REQ_BUFFER_PREALLOC automatically" ++ #define CONFIG_USB_VENDOR_REQ_MUTEX ++#endif ++#if defined(CONFIG_VENDOR_REQ_RETRY) && !defined(CONFIG_USB_VENDOR_REQ_MUTEX) ++ #warning "define CONFIG_USB_VENDOR_REQ_MUTEX for CONFIG_VENDOR_REQ_RETRY automatically" ++ #define CONFIG_USB_VENDOR_REQ_MUTEX ++#endif ++ ++ ++//#include ++ ++#endif // __DRV_CONF_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/drv_types.h b/drivers/net/wireless/rtl818x/rtl8189/include/drv_types.h +new file mode 100644 +index 00000000..57bd5172 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/drv_types.h +@@ -0,0 +1,695 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++/*------------------------------------------------------------------------------- ++ ++ For type defines and data structure defines ++ ++--------------------------------------------------------------------------------*/ ++ ++ ++#ifndef __DRV_TYPES_H__ ++#define __DRV_TYPES_H__ ++ ++#include ++#include ++#include ++ ++ ++#ifdef PLATFORM_OS_XP ++#include ++#endif ++ ++#ifdef PLATFORM_OS_CE ++#include ++#endif ++ ++#ifdef PLATFORM_LINUX ++#include ++#endif ++ ++enum _NIC_VERSION { ++ ++ RTL8711_NIC, ++ RTL8712_NIC, ++ RTL8713_NIC, ++ RTL8716_NIC ++ ++}; ++ ++ ++typedef struct _ADAPTER _adapter, ADAPTER,*PADAPTER; ++ ++#ifdef CONFIG_80211N_HT ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_WAPI_SUPPORT ++#include ++#endif ++ ++#ifdef CONFIG_DRVEXT_MODULE ++#include ++#endif ++ ++#ifdef CONFIG_MP_INCLUDED ++#include ++#endif ++ ++#ifdef CONFIG_BR_EXT ++#include ++#endif // CONFIG_BR_EXT ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ #include "ioctl_cfg80211.h" ++#endif //CONFIG_IOCTL_CFG80211 ++ ++#define SPEC_DEV_ID_NONE BIT(0) ++#define SPEC_DEV_ID_DISABLE_HT BIT(1) ++#define SPEC_DEV_ID_ENABLE_PS BIT(2) ++#define SPEC_DEV_ID_RF_CONFIG_1T1R BIT(3) ++#define SPEC_DEV_ID_RF_CONFIG_2T2R BIT(4) ++#define SPEC_DEV_ID_ASSIGN_IFNAME BIT(5) ++ ++struct specific_device_id{ ++ ++ u32 flags; ++ ++ u16 idVendor; ++ u16 idProduct; ++ ++}; ++ ++struct registry_priv ++{ ++ u8 chip_version; ++ u8 rfintfs; ++ u8 lbkmode; ++ u8 hci; ++ NDIS_802_11_SSID ssid; ++ u8 network_mode; //infra, ad-hoc, auto ++ u8 channel;//ad-hoc support requirement ++ u8 wireless_mode;//A, B, G, auto ++ u8 scan_mode;//active, passive ++ u8 radio_enable; ++ u8 preamble;//long, short, auto ++ u8 vrtl_carrier_sense;//Enable, Disable, Auto ++ u8 vcs_type;//RTS/CTS, CTS-to-self ++ u16 rts_thresh; ++ u16 frag_thresh; ++ u8 adhoc_tx_pwr; ++ u8 soft_ap; ++ u8 power_mgnt; ++ u8 ips_mode; ++ u8 smart_ps; ++ u8 long_retry_lmt; ++ u8 short_retry_lmt; ++ u16 busy_thresh; ++ u8 ack_policy; ++ u8 mp_mode; ++ u8 software_encrypt; ++ u8 software_decrypt; ++ #ifdef CONFIG_TX_EARLY_MODE ++ u8 early_mode; ++ #endif ++ u8 acm_method; ++ //UAPSD ++ u8 wmm_enable; ++ u8 uapsd_enable; ++ u8 uapsd_max_sp; ++ u8 uapsd_acbk_en; ++ u8 uapsd_acbe_en; ++ u8 uapsd_acvi_en; ++ u8 uapsd_acvo_en; ++ ++ WLAN_BSSID_EX dev_network; ++ ++#ifdef CONFIG_80211N_HT ++ u8 ht_enable; ++ u8 cbw40_enable; ++ u8 ampdu_enable;//for tx ++ u8 rx_stbc; ++ u8 ampdu_amsdu;//A-MPDU Supports A-MSDU is permitted ++#endif ++ u8 lowrate_two_xmit; ++ ++ u8 rf_config ; ++ u8 low_power ; ++ ++ u8 wifi_spec;// !turbo_mode ++ ++ u8 channel_plan; ++#ifdef CONFIG_BT_COEXIST ++ u8 btcoex; ++ u8 bt_iso; ++ u8 bt_sco; ++ u8 bt_ampdu; ++#endif ++ BOOLEAN bAcceptAddbaReq; ++ ++ u8 antdiv_cfg; ++ u8 antdiv_type; ++ ++ u8 usbss_enable;//0:disable,1:enable ++ u8 hwpdn_mode;//0:disable,1:enable,2:decide by EFUSE config ++ u8 hwpwrp_detect;//0:disable,1:enable ++ ++ u8 hw_wps_pbc;//0:disable,1:enable ++ ++#ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE ++ char adaptor_info_caching_file_path[PATH_LENGTH_MAX]; ++#endif ++ ++#ifdef CONFIG_LAYER2_ROAMING ++ u8 max_roaming_times; // the max number driver will try to roaming ++#endif ++ ++#ifdef CONFIG_IOL ++ u8 fw_iol; //enable iol without other concern ++#endif ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ u8 dmsp;//0:disable,1:enable ++#endif ++ ++#ifdef CONFIG_80211D ++ u8 enable80211d; ++#endif ++ ++ u8 ifname[16]; ++ u8 if2name[16]; ++ ++ u8 notch_filter; ++ ++#ifdef CONFIG_SPECIAL_SETTING_FOR_FUNAI_TV ++ u8 force_ant;//0 normal,1 main,2 aux ++ u8 force_igi;//0 normal ++#endif ++ u8 regulatory_tid; ++ u8 qos_opt_enable; ++}; ++ ++ ++//For registry parameters ++#define RGTRY_OFT(field) ((ULONG)FIELD_OFFSET(struct registry_priv,field)) ++#define RGTRY_SZ(field) sizeof(((struct registry_priv*) 0)->field) ++#define BSSID_OFT(field) ((ULONG)FIELD_OFFSET(WLAN_BSSID_EX,field)) ++#define BSSID_SZ(field) sizeof(((PWLAN_BSSID_EX) 0)->field) ++ ++ ++ ++#ifdef CONFIG_SDIO_HCI ++#include ++#define INTF_DATA SDIO_DATA ++#elif defined(CONFIG_GSPI_HCI) ++#include ++#define INTF_DATA GSPI_DATA ++#endif ++ ++#ifdef CONFIG_CONCURRENT_MODE ++#define is_primary_adapter(adapter) (adapter->adapter_type == PRIMARY_ADAPTER) ++#else ++#define is_primary_adapter(adapter) (1) ++#endif ++#define GET_PRIMARY_ADAPTER(padapter) (((_adapter *)padapter)->dvobj->if1) ++ ++#define GET_IFACE_NUMS(padapter) (((_adapter *)padapter)->dvobj->iface_nums) ++#define GET_ADAPTER(padapter, iface_id) (((_adapter *)padapter)->dvobj->padapters[iface_id]) ++ ++enum _IFACE_ID { ++ IFACE_ID0, //maping to PRIMARY_ADAPTER ++ IFACE_ID1, //maping to SECONDARY_ADAPTER ++ IFACE_ID2, ++ IFACE_ID3, ++ IFACE_ID_MAX, ++}; ++ ++struct dvobj_priv ++{ ++ _adapter *if1; //PRIMARY_ADAPTER ++ _adapter *if2; //SECONDARY_ADAPTER ++ ++ s32 processing_dev_remove; ++ ++ //for local/global synchronization ++ _mutex hw_init_mutex; ++ _mutex h2c_fwcmd_mutex; ++ _mutex setch_mutex; ++ _mutex setbw_mutex; ++ ++ unsigned char oper_channel; //saved channel info when call set_channel_bw ++ unsigned char oper_bwmode; ++ unsigned char oper_ch_offset;//PRIME_CHNL_OFFSET ++ u32 on_oper_ch_time; ++ ++ _adapter *padapters[IFACE_ID_MAX]; ++ u8 iface_nums; // total number of ifaces used runtime ++ ++ //For 92D, DMDP have 2 interface. ++ u8 InterfaceNumber; ++ u8 NumInterfaces; ++ ++ //In /Out Pipe information ++ int RtInPipe[2]; ++ int RtOutPipe[3]; ++ u8 Queue2Pipe[HW_QUEUE_ENTRY];//for out pipe mapping ++ ++ u8 irq_alloc; ++ ATOMIC_T continual_io_error; ++ ++ struct pwrctrl_priv pwrctl_priv; ++ ++/*-------- below is for SDIO INTERFACE --------*/ ++ ++#ifdef INTF_DATA ++ INTF_DATA intf_data; ++#endif ++ ++/*-------- below is for USB INTERFACE --------*/ ++ ++#ifdef CONFIG_USB_HCI ++ ++ u8 nr_endpoint; ++ u8 ishighspeed; ++ u8 RtNumInPipes; ++ u8 RtNumOutPipes; ++ int ep_num[5]; //endpoint number ++ ++ int RegUsbSS; ++ ++ _sema usb_suspend_sema; ++ ++#ifdef CONFIG_USB_VENDOR_REQ_MUTEX ++ _mutex usb_vendor_req_mutex; ++#endif ++ ++#ifdef CONFIG_USB_VENDOR_REQ_BUFFER_PREALLOC ++ u8 * usb_alloc_vendor_req_buf; ++ u8 * usb_vendor_req_buf; ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++ //related device objects ++ PDEVICE_OBJECT pphysdevobj;//pPhysDevObj; ++ PDEVICE_OBJECT pfuncdevobj;//pFuncDevObj; ++ PDEVICE_OBJECT pnextdevobj;//pNextDevObj; ++ ++ u8 nextdevstacksz;//unsigned char NextDeviceStackSize; //= (CHAR)CEdevice->pUsbDevObj->StackSize + 1; ++ ++ //urb for control diescriptor request ++ ++#ifdef PLATFORM_OS_XP ++ struct _URB_CONTROL_DESCRIPTOR_REQUEST descriptor_urb; ++ PUSB_CONFIGURATION_DESCRIPTOR pconfig_descriptor;//UsbConfigurationDescriptor; ++#endif ++ ++#ifdef PLATFORM_OS_CE ++ WCHAR active_path[MAX_ACTIVE_REG_PATH]; // adapter regpath ++ USB_EXTENSION usb_extension; ++ ++ _nic_hdl pipehdls_r8192c[0x10]; ++#endif ++ ++ u32 config_descriptor_len;//ULONG UsbConfigurationDescriptorLength; ++#endif//PLATFORM_WINDOWS ++ ++#ifdef PLATFORM_LINUX ++ struct usb_interface *pusbintf; ++ struct usb_device *pusbdev; ++#endif//PLATFORM_LINUX ++ ++#ifdef PLATFORM_FREEBSD ++ struct usb_interface *pusbintf; ++ struct usb_device *pusbdev; ++#endif//PLATFORM_FREEBSD ++ ++#endif//CONFIG_USB_HCI ++ ++/*-------- below is for PCIE INTERFACE --------*/ ++ ++#ifdef CONFIG_PCI_HCI ++ ++#ifdef PLATFORM_LINUX ++ struct pci_dev *ppcidev; ++ ++ //PCI MEM map ++ unsigned long pci_mem_end; /* shared mem end */ ++ unsigned long pci_mem_start; /* shared mem start */ ++ ++ //PCI IO map ++ unsigned long pci_base_addr; /* device I/O address */ ++ ++ //PciBridge ++ struct pci_priv pcipriv; ++ ++ u16 irqline; ++ u8 irq_enabled; ++ RT_ISR_CONTENT isr_content; ++ _lock irq_th_lock; ++ ++ //ASPM ++ u8 const_pci_aspm; ++ u8 const_amdpci_aspm; ++ u8 const_hwsw_rfoff_d3; ++ u8 const_support_pciaspm; ++ // pci-e bridge */ ++ u8 const_hostpci_aspm_setting; ++ // pci-e device */ ++ u8 const_devicepci_aspm_setting; ++ u8 b_support_aspm; // If it supports ASPM, Offset[560h] = 0x40, otherwise Offset[560h] = 0x00. ++ u8 b_support_backdoor; ++ u8 bdma64; ++#endif//PLATFORM_LINUX ++ ++#endif//CONFIG_PCI_HCI ++}; ++ ++#define dvobj_to_pwrctl(dvobj) (&(dvobj->pwrctl_priv)) ++#define pwrctl_to_dvobj(pwrctl) container_of(pwrctl, struct dvobj_priv, pwrctl_priv) ++ ++#ifdef PLATFORM_LINUX ++static struct device *dvobj_to_dev(struct dvobj_priv *dvobj) ++{ ++ /* todo: get interface type from dvobj and the return the dev accordingly */ ++#ifdef RTW_DVOBJ_CHIP_HW_TYPE ++#endif ++ ++#ifdef CONFIG_USB_HCI ++ return &dvobj->pusbintf->dev; ++#endif ++#ifdef CONFIG_SDIO_HCI ++ return &dvobj->intf_data.func->dev; ++#endif ++#ifdef CONFIG_GSPI_HCI ++ return &dvobj->intf_data.func->dev; ++#endif ++#ifdef CONFIG_PCI_HCI ++ return &dvobj->ppcidev->dev; ++#endif ++} ++#endif ++ ++enum _IFACE_TYPE { ++ IFACE_PORT0, //mapping to port0 for C/D series chips ++ IFACE_PORT1, //mapping to port1 for C/D series chip ++ MAX_IFACE_PORT, ++}; ++ ++enum _ADAPTER_TYPE { ++ PRIMARY_ADAPTER, ++ SECONDARY_ADAPTER, ++ MAX_ADAPTER, ++}; ++ ++typedef enum _DRIVER_STATE{ ++ DRIVER_NORMAL = 0, ++ DRIVER_DISAPPEAR = 1, ++ DRIVER_REPLACE_DONGLE = 2, ++}DRIVER_STATE; ++ ++#ifdef CONFIG_INTEL_PROXIM ++struct proxim { ++ bool proxim_support; ++ bool proxim_on; ++ ++ void *proximity_priv; ++ int (*proxim_rx)(_adapter *padapter, ++ union recv_frame *precv_frame); ++ u8 (*proxim_get_var)(_adapter* padapter, u8 type); ++}; ++#endif //CONFIG_INTEL_PROXIM ++ ++#ifdef CONFIG_MAC_LOOPBACK_DRIVER ++typedef struct loopbackdata ++{ ++ _sema sema; ++ _thread_hdl_ lbkthread; ++ u8 bstop; ++ u32 cnt; ++ u16 size; ++ u16 txsize; ++ u8 txbuf[0x8000]; ++ u16 rxsize; ++ u8 rxbuf[0x8000]; ++ u8 msg[100]; ++ ++}LOOPBACKDATA, *PLOOPBACKDATA; ++#endif ++ ++struct _ADAPTER{ ++ int DriverState;// for disable driver using module, use dongle to replace module. ++ int pid[3];//process id from UI, 0:wps, 1:hostapd, 2:dhcpcd ++ int bDongle;//build-in module or external dongle ++ u16 chip_type; ++ u16 HardwareType; ++ u16 interface_type;//USB,SDIO,SPI,PCI ++ ++ struct dvobj_priv *dvobj; ++ struct mlme_priv mlmepriv; ++ struct mlme_ext_priv mlmeextpriv; ++ struct cmd_priv cmdpriv; ++ struct evt_priv evtpriv; ++ //struct io_queue *pio_queue; ++ struct io_priv iopriv; ++ struct xmit_priv xmitpriv; ++ struct recv_priv recvpriv; ++ struct sta_priv stapriv; ++ struct security_priv securitypriv; ++ _lock security_key_mutex; // add for CONFIG_IEEE80211W, none 11w also can use ++ struct registry_priv registrypriv; ++ struct eeprom_priv eeprompriv; ++ struct led_priv ledpriv; ++#if defined(CONFIG_CHECK_BT_HANG) && defined(CONFIG_BT_COEXIST) ++ //Check BT status for BT Hung. ++ struct workqueue_struct *priv_checkbt_wq; ++ struct delayed_work checkbt_work; ++#endif ++#ifdef CONFIG_MP_INCLUDED ++ struct mp_priv mppriv; ++#endif ++ ++#ifdef CONFIG_DRVEXT_MODULE ++ struct drvext_priv drvextpriv; ++#endif ++ ++#ifdef CONFIG_AP_MODE ++ struct hostapd_priv *phostapdpriv; ++#endif ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++#ifdef CONFIG_P2P ++ struct cfg80211_wifidirect_info cfg80211_wdinfo; ++#endif //CONFIG_P2P ++#endif //CONFIG_IOCTL_CFG80211 ++ u32 setband; ++#ifdef CONFIG_P2P ++ struct wifidirect_info wdinfo; ++#endif //CONFIG_P2P ++ ++#ifdef CONFIG_TDLS ++ struct tdls_info tdlsinfo; ++#endif //CONFIG_TDLS ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ u8 WapiSupport; ++ RT_WAPI_T wapiInfo; ++#endif ++ ++ ++#ifdef CONFIG_WFD ++ struct wifi_display_info wfd_info; ++#endif //CONFIG_WFD ++ ++ PVOID HalData; ++ u32 hal_data_sz; ++ struct hal_ops HalFunc; ++ ++ s32 bDriverStopped; ++ s32 bSurpriseRemoved; ++ s32 bCardDisableWOHSM; ++ ++ u32 IsrContent; ++ u32 ImrContent; ++ ++ u8 EepromAddressSize; ++ u8 hw_init_completed; ++ u8 bDriverIsGoingToUnload; ++ u8 init_adpt_in_progress; ++ u8 bHaltInProgress; ++ ++ _thread_hdl_ cmdThread; ++ _thread_hdl_ evtThread; ++ _thread_hdl_ xmitThread; ++ _thread_hdl_ recvThread; ++ ++#ifndef PLATFORM_LINUX ++ NDIS_STATUS (*dvobj_init)(struct dvobj_priv *dvobj); ++ void (*dvobj_deinit)(struct dvobj_priv *dvobj); ++#endif ++ ++ void (*intf_start)(_adapter * adapter); ++ void (*intf_stop)(_adapter * adapter); ++ ++#ifdef PLATFORM_WINDOWS ++ _nic_hdl hndis_adapter;//hNdisAdapter(NDISMiniportAdapterHandle); ++ _nic_hdl hndis_config;//hNdisConfiguration; ++ NDIS_STRING fw_img; ++ ++ u32 NdisPacketFilter; ++ u8 MCList[MAX_MCAST_LIST_NUM][6]; ++ u32 MCAddrCount; ++#endif //end of PLATFORM_WINDOWS ++ ++ ++#ifdef PLATFORM_LINUX ++ _nic_hdl pnetdev; ++ ++ // used by rtw_rereg_nd_name related function ++ struct rereg_nd_name_data { ++ _nic_hdl old_pnetdev; ++ char old_ifname[IFNAMSIZ]; ++ u8 old_ips_mode; ++ u8 old_bRegUseLed; ++ } rereg_nd_name_priv; ++ ++ int bup; ++ struct net_device_stats stats; ++ struct iw_statistics iwstats; ++ struct proc_dir_entry *dir_dev;// for proc directory ++ struct proc_dir_entry *dir_odm; ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ struct wireless_dev *rtw_wdev; ++#endif //CONFIG_IOCTL_CFG80211 ++ ++#endif //end of PLATFORM_LINUX ++ ++#ifdef PLATFORM_FREEBSD ++ _nic_hdl pifp; ++ int bup; ++ _lock glock; ++#endif //PLATFORM_FREEBSD ++ int net_closed; ++ ++ u8 bFWReady; ++ u8 bBTFWReady; ++ u8 bReadPortCancel; ++ u8 bWritePortCancel; ++ u8 bRxRSSIDisplay; ++ // Added by Albert 2012/10/26 ++ // The driver will show up the desired channel number when this flag is 1. ++ u8 bNotifyChannelChange; ++#ifdef CONFIG_P2P ++ // Added by Albert 2012/12/06 ++ // The driver will show the current P2P status when the upper application reads it. ++ u8 bShowGetP2PState; ++#endif ++#ifdef CONFIG_AUTOSUSPEND ++ u8 bDisableAutosuspend; ++#endif ++ ++ _adapter *pbuddy_adapter; ++ ++#if defined(CONFIG_CONCURRENT_MODE) || defined(CONFIG_DUALMAC_CONCURRENT) ++ u8 isprimary; //is primary adapter or not ++ //notes: ++ // if isprimary is true, the adapter_type value is 0, iface_id is IFACE_ID0 for PRIMARY_ADAPTER ++ // if isprimary is false, the adapter_type value is 1, iface_id is IFACE_ID1 for SECONDARY_ADAPTER ++ // refer to iface_id if iface_nums>2 and isprimary is false and the adapter_type value is 0xff. ++ u8 adapter_type;//used only in two inteface case(PRIMARY_ADAPTER and SECONDARY_ADAPTER) . ++ u8 iface_type; //interface port type, it depends on HW port ++#endif ++ ++ //extend to support multi interface ++ //IFACE_ID0 is equals to PRIMARY_ADAPTER ++ //IFACE_ID1 is equals to SECONDARY_ADAPTER ++ u8 iface_id; ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ u8 DualMacConcurrent; // 1: DMSP 0:DMDP ++#endif ++ ++#ifdef CONFIG_BR_EXT ++ _lock br_ext_lock; ++ //unsigned int macclone_completed; ++ struct nat25_network_db_entry *nethash[NAT25_HASH_SIZE]; ++ int pppoe_connection_in_progress; ++ unsigned char pppoe_addr[MACADDRLEN]; ++ unsigned char scdb_mac[MACADDRLEN]; ++ unsigned char scdb_ip[4]; ++ struct nat25_network_db_entry *scdb_entry; ++ unsigned char br_mac[MACADDRLEN]; ++ unsigned char br_ip[4]; ++ ++ struct br_ext_info ethBrExtInfo; ++#endif // CONFIG_BR_EXT ++ ++#ifdef CONFIG_INTEL_PROXIM ++ /* intel Proximity, should be alloc mem ++ * in intel Proximity module and can only ++ * be used in intel Proximity mode */ ++ struct proxim proximity; ++#endif //CONFIG_INTEL_PROXIM ++ ++#ifdef CONFIG_MAC_LOOPBACK_DRIVER ++ PLOOPBACKDATA ploopback; ++#endif ++ ++ u8 fix_rate; ++ ++ unsigned char in_cta_test; ++ ++}; ++ ++#define adapter_to_dvobj(adapter) (adapter->dvobj) ++#define adapter_to_pwrctl(adapter) (&(adapter->dvobj->pwrctl_priv)) ++ ++int rtw_handle_dualmac(_adapter *adapter, bool init); ++ ++__inline static u8 *myid(struct eeprom_priv *peepriv) ++{ ++ return (peepriv->mac_addr); ++} ++ ++ ++#endif //__DRV_TYPES_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/drv_types_ce.h b/drivers/net/wireless/rtl818x/rtl8189/include/drv_types_ce.h +new file mode 100644 +index 00000000..b3d35235 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/drv_types_ce.h +@@ -0,0 +1,93 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __DRV_TYPES_CE_H__ ++#define __DRV_TYPES_CE_H__ ++ ++#include ++#include ++ ++#include ++ ++#define MAX_ACTIVE_REG_PATH 256 ++ ++#define MAX_MCAST_LIST_NUM 32 ++ ++ ++ ++//for ioctl ++#define MAKE_DRIVER_VERSION(_MainVer,_MinorVer) ((((u32)(_MainVer))<<16)+_MinorVer) ++ ++#define NIC_HEADER_SIZE 14 //!< can be moved to typedef.h ++#define NIC_MAX_PACKET_SIZE 1514 //!< can be moved to typedef.h ++#define NIC_MAX_SEND_PACKETS 10 // max number of send packets the MiniportSendPackets function can accept, can be moved to typedef.h ++#define NIC_VENDOR_DRIVER_VERSION MAKE_DRIVER_VERSION(0,001) //!< can be moved to typedef.h ++#define NIC_MAX_PACKET_SIZE 1514 //!< can be moved to typedef.h ++ ++typedef struct _MP_REG_ENTRY ++{ ++ ++ NDIS_STRING RegName; // variable name text ++ BOOLEAN bRequired; // 1 -> required, 0 -> optional ++ ++ u8 Type; // NdisParameterInteger/NdisParameterHexInteger/NdisParameterStringle/NdisParameterMultiString ++ uint FieldOffset; // offset to MP_ADAPTER field ++ uint FieldSize; // size (in bytes) of the field ++ ++#ifdef UNDER_AMD64 ++ u64 Default; ++#else ++ u32 Default; // default value to use ++#endif ++ ++ u32 Min; // minimum value allowed ++ u32 Max; // maximum value allowed ++} MP_REG_ENTRY, *PMP_REG_ENTRY; ++ ++#ifdef CONFIG_USB_HCI ++typedef struct _USB_EXTENSION { ++ LPCUSB_FUNCS _lpUsbFuncs; ++ USB_HANDLE _hDevice; ++ PVOID pAdapter; ++ ++#if 0 ++ USB_ENDPOINT_DESCRIPTOR _endpACLIn; ++ USB_ENDPOINT_DESCRIPTOR _endpACLOutHigh; ++ USB_ENDPOINT_DESCRIPTOR _endpACLOutNormal; ++ ++ USB_PIPE pPipeIn; ++ USB_PIPE pPipeOutNormal; ++ USB_PIPE pPipeOutHigh; ++#endif ++ ++} USB_EXTENSION, *PUSB_EXTENSION; ++#endif ++ ++ ++typedef struct _OCTET_STRING{ ++ u8 *Octet; ++ u16 Length; ++} OCTET_STRING, *POCTET_STRING; ++ ++ ++ ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/drv_types_gspi.h b/drivers/net/wireless/rtl818x/rtl8189/include/drv_types_gspi.h +new file mode 100644 +index 00000000..4d42c9cc +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/drv_types_gspi.h +@@ -0,0 +1,49 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __DRV_TYPES_GSPI_H__ ++#define __DRV_TYPES_GSPI_H__ ++ ++#include ++#include ++ ++// SPI Header Files ++#ifdef PLATFORM_LINUX ++#include ++#endif ++ ++ ++typedef struct gspi_data ++{ ++ u8 func_number; ++ ++ u8 tx_block_mode; ++ u8 rx_block_mode; ++ u32 block_transfer_len; ++ ++#ifdef PLATFORM_LINUX ++ struct spi_device *func; ++ ++ struct workqueue_struct *priv_wq; ++ struct delayed_work irq_work; ++#endif ++} GSPI_DATA, *PGSPI_DATA; ++ ++#endif // #ifndef __DRV_TYPES_GSPI_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/drv_types_linux.h b/drivers/net/wireless/rtl818x/rtl8189/include/drv_types_linux.h +new file mode 100644 +index 00000000..db1c5856 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/drv_types_linux.h +@@ -0,0 +1,25 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __DRV_TYPES_LINUX_H__ ++#define __DRV_TYPES_LINUX_H__ ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/drv_types_sdio.h b/drivers/net/wireless/rtl818x/rtl8189/include/drv_types_sdio.h +new file mode 100644 +index 00000000..7e2b9ed2 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/drv_types_sdio.h +@@ -0,0 +1,71 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __DRV_TYPES_SDIO_H__ ++#define __DRV_TYPES_SDIO_H__ ++ ++#include ++#include ++ ++// SDIO Header Files ++#ifdef PLATFORM_LINUX ++#include ++#endif ++#ifdef PLATFORM_OS_XP ++#include ++#include ++#endif ++#ifdef PLATFORM_OS_CE ++#include ++#endif ++ ++ ++typedef struct sdio_data ++{ ++ u8 func_number; ++ ++ u8 tx_block_mode; ++ u8 rx_block_mode; ++ u32 block_transfer_len; ++ ++#ifdef PLATFORM_LINUX ++ struct sdio_func *func; ++ _thread_hdl_ sys_sdio_irq_thd; ++#endif ++ ++#ifdef PLATFORM_OS_XP ++ PDEVICE_OBJECT pphysdevobj; ++ PDEVICE_OBJECT pfuncdevobj; ++ PDEVICE_OBJECT pnextdevobj; ++ SDBUS_INTERFACE_STANDARD sdbusinft; ++ u8 nextdevstacksz; ++#endif ++ ++#ifdef PLATFORM_OS_CE ++ SD_DEVICE_HANDLE hDevice; ++ SD_CARD_RCA sd_rca; ++ SD_CARD_INTERFACE card_intf; ++ BOOLEAN enableIsarWithStatus; ++ WCHAR active_path[MAX_ACTIVE_REG_PATH]; ++ SD_HOST_BLOCK_CAPABILITY sd_host_blk_cap; ++#endif ++} SDIO_DATA, *PSDIO_DATA; ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/drv_types_xp.h b/drivers/net/wireless/rtl818x/rtl8189/include/drv_types_xp.h +new file mode 100644 +index 00000000..2d51b1db +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/drv_types_xp.h +@@ -0,0 +1,95 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __DRV_TYPES_XP_H__ ++#define __DRV_TYPES_XP_H__ ++ ++#include ++#include ++ ++ ++ ++#define MAX_MCAST_LIST_NUM 32 ++ ++ ++ ++//for ioctl ++#define MAKE_DRIVER_VERSION(_MainVer,_MinorVer) ((((u32)(_MainVer))<<16)+_MinorVer) ++ ++#define NIC_HEADER_SIZE 14 //!< can be moved to typedef.h ++#define NIC_MAX_PACKET_SIZE 1514 //!< can be moved to typedef.h ++#define NIC_MAX_SEND_PACKETS 10 // max number of send packets the MiniportSendPackets function can accept, can be moved to typedef.h ++#define NIC_VENDOR_DRIVER_VERSION MAKE_DRIVER_VERSION(0,001) //!< can be moved to typedef.h ++#define NIC_MAX_PACKET_SIZE 1514 //!< can be moved to typedef.h ++ ++ ++#undef ON_VISTA ++//added by Jackson ++#ifndef ON_VISTA ++// ++// Bus driver versions ++// ++ ++#define SDBUS_DRIVER_VERSION_1 0x100 ++#define SDBUS_DRIVER_VERSION_2 0x200 ++ ++#define SDP_FUNCTION_TYPE 4 ++#define SDP_BUS_DRIVER_VERSION 5 ++#define SDP_BUS_WIDTH 6 ++#define SDP_BUS_CLOCK 7 ++#define SDP_BUS_INTERFACE_CONTROL 8 ++#define SDP_HOST_BLOCK_LENGTH 9 ++#define SDP_FUNCTION_BLOCK_LENGTH 10 ++#define SDP_FN0_BLOCK_LENGTH 11 ++#define SDP_FUNCTION_INT_ENABLE 12 ++#endif ++ ++ ++typedef struct _MP_REG_ENTRY ++{ ++ ++ NDIS_STRING RegName; // variable name text ++ BOOLEAN bRequired; // 1 -> required, 0 -> optional ++ ++ u8 Type; // NdisParameterInteger/NdisParameterHexInteger/NdisParameterStringle/NdisParameterMultiString ++ uint FieldOffset; // offset to MP_ADAPTER field ++ uint FieldSize; // size (in bytes) of the field ++ ++#ifdef UNDER_AMD64 ++ u64 Default; ++#else ++ u32 Default; // default value to use ++#endif ++ ++ u32 Min; // minimum value allowed ++ u32 Max; // maximum value allowed ++} MP_REG_ENTRY, *PMP_REG_ENTRY; ++ ++ ++typedef struct _OCTET_STRING{ ++ u8 *Octet; ++ u16 Length; ++} OCTET_STRING, *POCTET_STRING; ++ ++ ++ ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/ethernet.h b/drivers/net/wireless/rtl818x/rtl8189/include/ethernet.h +new file mode 100644 +index 00000000..cadc8c1d +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/ethernet.h +@@ -0,0 +1,42 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++/*! \file */ ++#ifndef __INC_ETHERNET_H ++#define __INC_ETHERNET_H ++ ++#define ETHERNET_ADDRESS_LENGTH 6 //!< Ethernet Address Length ++#define ETHERNET_HEADER_SIZE 14 //!< Ethernet Header Length ++#define LLC_HEADER_SIZE 6 //!< LLC Header Length ++#define TYPE_LENGTH_FIELD_SIZE 2 //!< Type/Length Size ++#define MINIMUM_ETHERNET_PACKET_SIZE 60 //!< Minimum Ethernet Packet Size ++#define MAXIMUM_ETHERNET_PACKET_SIZE 1514 //!< Maximum Ethernet Packet Size ++ ++#define RT_ETH_IS_MULTICAST(_pAddr) ((((UCHAR *)(_pAddr))[0]&0x01)!=0) //!< Is Multicast Address? ++#define RT_ETH_IS_BROADCAST(_pAddr) ( \ ++ ((UCHAR *)(_pAddr))[0]==0xff && \ ++ ((UCHAR *)(_pAddr))[1]==0xff && \ ++ ((UCHAR *)(_pAddr))[2]==0xff && \ ++ ((UCHAR *)(_pAddr))[3]==0xff && \ ++ ((UCHAR *)(_pAddr))[4]==0xff && \ ++ ((UCHAR *)(_pAddr))[5]==0xff ) //!< Is Broadcast Address? ++ ++ ++#endif // #ifndef __INC_ETHERNET_H ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/gspi_hal.h b/drivers/net/wireless/rtl818x/rtl8189/include/gspi_hal.h +new file mode 100644 +index 00000000..8146d6a5 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/gspi_hal.h +@@ -0,0 +1,37 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __GSPI_HAL_H__ ++#define __GSPI_HAL_H__ ++ ++ ++void spi_int_dpc(PADAPTER padapter); ++ ++#ifdef CONFIG_RTL8723A ++void rtl8723as_set_hal_ops(PADAPTER padapter); ++#define hal_set_hal_ops rtl8723as_set_hal_ops ++#endif ++ ++#ifdef CONFIG_RTL8188E ++void rtl8188es_set_hal_ops(PADAPTER padapter); ++#define hal_set_hal_ops rtl8188es_set_hal_ops ++#endif ++ ++#endif //__GSPI_HAL_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/gspi_ops.h b/drivers/net/wireless/rtl818x/rtl8189/include/gspi_ops.h +new file mode 100644 +index 00000000..ffd98c5a +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/gspi_ops.h +@@ -0,0 +1,171 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __GSPI_OPS_H__ ++#define __GSPI_OPS_H__ ++ ++/* follwing defination is based on ++ * GSPI spec of RTL8723, we temp ++ * suppose that it will be the same ++ * for diff chips of GSPI, if not ++ * we should move it to HAL folder */ ++#define SPI_LOCAL_DOMAIN 0x0 ++#define WLAN_IOREG_DOMAIN 0x8 ++#define FW_FIFO_DOMAIN 0x4 ++#define TX_HIQ_DOMAIN 0xc ++#define TX_MIQ_DOMAIN 0xd ++#define TX_LOQ_DOMAIN 0xe ++#define RX_RXFIFO_DOMAIN 0x1f ++ ++//IO Bus domain address mapping ++#define DEFUALT_OFFSET 0x0 ++#define SPI_LOCAL_OFFSET 0x10250000 ++#define WLAN_IOREG_OFFSET 0x10260000 ++#define FW_FIFO_OFFSET 0x10270000 ++#define TX_HIQ_OFFSET 0x10310000 ++#define TX_MIQ_OFFSET 0x1032000 ++#define TX_LOQ_OFFSET 0x10330000 ++#define RX_RXOFF_OFFSET 0x10340000 ++ ++//SPI Local registers ++#define SPI_REG_TX_CTRL 0x0000 // SPI Tx Control ++#define SPI_REG_STATUS_RECOVERY 0x0004 ++#define SPI_REG_INT_TIMEOUT 0x0006 ++#define SPI_REG_HIMR 0x0014 // SPI Host Interrupt Mask ++#define SPI_REG_HISR 0x0018 // SPI Host Interrupt Service Routine ++#define SPI_REG_RX0_REQ_LEN 0x001C // RXDMA Request Length ++#define SPI_REG_FREE_TXPG 0x0020 // Free Tx Buffer Page ++#define SPI_REG_HCPWM1 0x0024 // HCI Current Power Mode 1 ++#define SPI_REG_HCPWM2 0x0026 // HCI Current Power Mode 2 ++#define SPI_REG_HTSFR_INFO 0x0030 // HTSF Informaion ++#define SPI_REG_HRPWM1 0x0080 // HCI Request Power Mode 1 ++#define SPI_REG_HRPWM2 0x0082 // HCI Request Power Mode 2 ++#define SPI_REG_HPS_CLKR 0x0084 // HCI Power Save Clock ++#define SPI_REG_HSUS_CTRL 0x0086 // SPI HCI Suspend Control ++#define SPI_REG_HIMR_ON 0x0090 //SPI Host Extension Interrupt Mask Always ++#define SPI_REG_HISR_ON 0x0091 //SPI Host Extension Interrupt Status Always ++#define SPI_REG_CFG 0x00F0 //SPI Configuration Register ++ ++#define SPI_TX_CTRL (SPI_REG_TX_CTRL |SPI_LOCAL_OFFSET) ++#define SPI_STATUS_RECOVERY (SPI_REG_STATUS_RECOVERY |SPI_LOCAL_OFFSET) ++#define SPI_INT_TIMEOUT (SPI_REG_INT_TIMEOUT |SPI_LOCAL_OFFSET) ++#define SPI_HIMR (SPI_REG_HIMR |SPI_LOCAL_OFFSET) ++#define SPI_HISR (SPI_REG_HISR |SPI_LOCAL_OFFSET) ++#define SPI_RX0_REQ_LEN_1_BYTE (SPI_REG_RX0_REQ_LEN |SPI_LOCAL_OFFSET) ++#define SPI_FREE_TXPG (SPI_REG_FREE_TXPG |SPI_LOCAL_OFFSET) ++ ++#define SPI_HIMR_DISABLED 0 ++ ++//SPI HIMR MASK diff with SDIO ++#define SPI_HISR_RX_REQUEST BIT(0) ++#define SPI_HISR_AVAL BIT(1) ++#define SPI_HISR_TXERR BIT(2) ++#define SPI_HISR_RXERR BIT(3) ++#define SPI_HISR_TXFOVW BIT(4) ++#define SPI_HISR_RXFOVW BIT(5) ++#define SPI_HISR_TXBCNOK BIT(6) ++#define SPI_HISR_TXBCNERR BIT(7) ++#define SPI_HISR_BCNERLY_INT BIT(16) ++#define SPI_HISR_ATIMEND BIT(17) ++#define SPI_HISR_ATIMEND_E BIT(18) ++#define SPI_HISR_CTWEND BIT(19) ++#define SPI_HISR_C2HCMD BIT(20) ++#define SPI_HISR_CPWM1 BIT(21) ++#define SPI_HISR_CPWM2 BIT(22) ++#define SPI_HISR_HSISR_IND BIT(23) ++#define SPI_HISR_GTINT3_IND BIT(24) ++#define SPI_HISR_GTINT4_IND BIT(25) ++#define SPI_HISR_PSTIMEOUT BIT(26) ++#define SPI_HISR_OCPINT BIT(27) ++#define SPI_HISR_TSF_BIT32_TOGGLE BIT(29) ++ ++#define MASK_SPI_HISR_CLEAR (SPI_HISR_TXERR |\ ++ SPI_HISR_RXERR |\ ++ SPI_HISR_TXFOVW |\ ++ SPI_HISR_RXFOVW |\ ++ SPI_HISR_TXBCNOK |\ ++ SPI_HISR_TXBCNERR |\ ++ SPI_HISR_C2HCMD |\ ++ SPI_HISR_CPWM1 |\ ++ SPI_HISR_CPWM2 |\ ++ SPI_HISR_HSISR_IND |\ ++ SPI_HISR_GTINT3_IND |\ ++ SPI_HISR_GTINT4_IND |\ ++ SPI_HISR_PSTIMEOUT |\ ++ SPI_HISR_OCPINT) ++ ++#define REG_LEN_FORMAT(pcmd, x) SET_BITS_TO_LE_4BYTE(pcmd, 0, 8, x)//(x<<(unsigned int)24) ++#define REG_ADDR_FORMAT(pcmd,x) SET_BITS_TO_LE_4BYTE(pcmd, 8, 16, x)//(x<<(unsigned int)16) ++#define REG_DOMAIN_ID_FORMAT(pcmd,x) SET_BITS_TO_LE_4BYTE(pcmd, 24, 5, x)//(x<<(unsigned int)0) ++#define REG_FUN_FORMAT(pcmd,x) SET_BITS_TO_LE_4BYTE(pcmd, 29, 2, x)//(x<<(unsigned int)5) ++#define REG_RW_FORMAT(pcmd,x) SET_BITS_TO_LE_4BYTE(pcmd, 31, 1, x)//(x<<(unsigned int)7) ++ ++#define FIFO_LEN_FORMAT(pcmd, x) SET_BITS_TO_LE_4BYTE(pcmd, 0, 16, x)//(x<<(unsigned int)24) ++//#define FIFO_ADDR_FORMAT(pcmd,x) SET_BITS_TO_LE_4BYTE(pcmd, 8, 16, x)//(x<<(unsigned int)16) ++#define FIFO_DOMAIN_ID_FORMAT(pcmd,x) SET_BITS_TO_LE_4BYTE(pcmd, 24, 5, x)//(x<<(unsigned int)0) ++#define FIFO_FUN_FORMAT(pcmd,x) SET_BITS_TO_LE_4BYTE(pcmd, 29, 2, x)//(x<<(unsigned int)5) ++#define FIFO_RW_FORMAT(pcmd,x) SET_BITS_TO_LE_4BYTE(pcmd, 31, 1, x)//(x<<(unsigned int)7) ++ ++ ++//get status dword0 ++#define GET_STATUS_PUB_PAGE_NUM(status) LE_BITS_TO_4BYTE(status, 24, 8) ++#define GET_STATUS_HI_PAGE_NUM(status) LE_BITS_TO_4BYTE(status, 18, 6) ++#define GET_STATUS_MID_PAGE_NUM(status) LE_BITS_TO_4BYTE(status, 12, 6) ++#define GET_STATUS_LOW_PAGE_NUM(status) LE_BITS_TO_4BYTE(status, 6, 6) ++#define GET_STATUS_HISR_HI6BIT(status) LE_BITS_TO_4BYTE(status, 0, 6) ++ ++//get status dword1 ++#define GET_STATUS_HISR_MID8BIT(status) LE_BITS_TO_4BYTE(status + 4, 24, 8) ++#define GET_STATUS_HISR_LOW8BIT(status) LE_BITS_TO_4BYTE(status + 4, 16, 8) ++#define GET_STATUS_ERROR(status) LE_BITS_TO_4BYTE(status + 4, 17, 1) ++#define GET_STATUS_INT(status) LE_BITS_TO_4BYTE(status + 4, 16, 1) ++#define GET_STATUS_RX_LENGTH(status) LE_BITS_TO_4BYTE(status + 4, 0, 16) ++ ++ ++#define RXDESC_SIZE 24 ++ ++ ++struct spi_more_data { ++ unsigned long more_data; ++ unsigned long len; ++}; ++ ++#ifdef CONFIG_RTL8723A ++void rtl8723as_set_hal_ops(PADAPTER padapter); ++#define set_hal_ops rtl8723as_set_hal_ops ++#endif ++ ++#ifdef CONFIG_RTL8188E ++void rtl8188es_set_hal_ops(PADAPTER padapter); ++#define set_hal_ops rtl8188es_set_hal_ops ++#endif ++extern void spi_set_chip_endian(PADAPTER padapter); ++extern void spi_set_intf_ops(struct _io_ops *pops); ++extern void spi_set_chip_endian(PADAPTER padapter); ++extern void InitInterrupt8723ASdio(PADAPTER padapter); ++extern void InitSysInterrupt8723ASdio(PADAPTER padapter); ++extern void EnableInterrupt8723ASdio(PADAPTER padapter); ++extern void DisableInterrupt8723ASdio(PADAPTER padapter); ++extern void spi_int_hdl(PADAPTER padapter); ++extern u8 HalQueryTxBufferStatus8723ASdio(PADAPTER padapter); ++extern void InitInterrupt8188ESdio(PADAPTER padapter); ++extern void EnableInterrupt8188ESdio(PADAPTER padapter); ++extern void DisableInterrupt8188ESdio(PADAPTER padapter); ++ ++#endif //__GSPI_OPS_H__ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/gspi_ops_linux.h b/drivers/net/wireless/rtl818x/rtl8189/include/gspi_ops_linux.h +new file mode 100644 +index 00000000..6358a0fa +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/gspi_ops_linux.h +@@ -0,0 +1,24 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __SDIO_OPS_LINUX_H__ ++#define __SDIO_OPS_LINUX_H__ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/gspi_osintf.h b/drivers/net/wireless/rtl818x/rtl8189/include/gspi_osintf.h +new file mode 100644 +index 00000000..f00da10d +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/gspi_osintf.h +@@ -0,0 +1,35 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __SDIO_OSINTF_H__ ++#define __SDIO_OSINTF_H__ ++ ++ ++#include ++#include ++#include ++ ++#ifdef PLATFORM_OS_CE ++extern NDIS_STATUS ce_sd_get_dev_hdl(PADAPTER padapter); ++SD_API_STATUS ce_sd_int_callback(SD_DEVICE_HANDLE hDevice, PADAPTER padapter); ++extern void sd_setup_irs(PADAPTER padapter); ++#endif ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/h2clbk.h b/drivers/net/wireless/rtl818x/rtl8189/include/h2clbk.h +new file mode 100644 +index 00000000..6034a026 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/h2clbk.h +@@ -0,0 +1,36 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++ ++#define _H2CLBK_H_ ++ ++ ++#include ++#include ++ ++ ++void _lbk_cmd(PADAPTER Adapter); ++ ++void _lbk_rsp(PADAPTER Adapter); ++ ++void _lbk_evt(IN PADAPTER Adapter); ++ ++void h2c_event_callback(unsigned char *dev, unsigned char *pbuf); ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/hal_com.h b/drivers/net/wireless/rtl818x/rtl8189/include/hal_com.h +new file mode 100644 +index 00000000..e1542783 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/hal_com.h +@@ -0,0 +1,185 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __HAL_COMMON_H__ ++#define __HAL_COMMON_H__ ++ ++//---------------------------------------------------------------------------- ++// Rate Definition ++//---------------------------------------------------------------------------- ++//CCK ++#define RATR_1M 0x00000001 ++#define RATR_2M 0x00000002 ++#define RATR_55M 0x00000004 ++#define RATR_11M 0x00000008 ++//OFDM ++#define RATR_6M 0x00000010 ++#define RATR_9M 0x00000020 ++#define RATR_12M 0x00000040 ++#define RATR_18M 0x00000080 ++#define RATR_24M 0x00000100 ++#define RATR_36M 0x00000200 ++#define RATR_48M 0x00000400 ++#define RATR_54M 0x00000800 ++//MCS 1 Spatial Stream ++#define RATR_MCS0 0x00001000 ++#define RATR_MCS1 0x00002000 ++#define RATR_MCS2 0x00004000 ++#define RATR_MCS3 0x00008000 ++#define RATR_MCS4 0x00010000 ++#define RATR_MCS5 0x00020000 ++#define RATR_MCS6 0x00040000 ++#define RATR_MCS7 0x00080000 ++//MCS 2 Spatial Stream ++#define RATR_MCS8 0x00100000 ++#define RATR_MCS9 0x00200000 ++#define RATR_MCS10 0x00400000 ++#define RATR_MCS11 0x00800000 ++#define RATR_MCS12 0x01000000 ++#define RATR_MCS13 0x02000000 ++#define RATR_MCS14 0x04000000 ++#define RATR_MCS15 0x08000000 ++ ++//CCK ++#define RATE_1M BIT(0) ++#define RATE_2M BIT(1) ++#define RATE_5_5M BIT(2) ++#define RATE_11M BIT(3) ++//OFDM ++#define RATE_6M BIT(4) ++#define RATE_9M BIT(5) ++#define RATE_12M BIT(6) ++#define RATE_18M BIT(7) ++#define RATE_24M BIT(8) ++#define RATE_36M BIT(9) ++#define RATE_48M BIT(10) ++#define RATE_54M BIT(11) ++//MCS 1 Spatial Stream ++#define RATE_MCS0 BIT(12) ++#define RATE_MCS1 BIT(13) ++#define RATE_MCS2 BIT(14) ++#define RATE_MCS3 BIT(15) ++#define RATE_MCS4 BIT(16) ++#define RATE_MCS5 BIT(17) ++#define RATE_MCS6 BIT(18) ++#define RATE_MCS7 BIT(19) ++//MCS 2 Spatial Stream ++#define RATE_MCS8 BIT(20) ++#define RATE_MCS9 BIT(21) ++#define RATE_MCS10 BIT(22) ++#define RATE_MCS11 BIT(23) ++#define RATE_MCS12 BIT(24) ++#define RATE_MCS13 BIT(25) ++#define RATE_MCS14 BIT(26) ++#define RATE_MCS15 BIT(27) ++ ++// ALL CCK Rate ++#define RATE_ALL_CCK RATR_1M|RATR_2M|RATR_55M|RATR_11M ++#define RATE_ALL_OFDM_AG RATR_6M|RATR_9M|RATR_12M|RATR_18M|RATR_24M|\ ++ RATR_36M|RATR_48M|RATR_54M ++#define RATE_ALL_OFDM_1SS RATR_MCS0|RATR_MCS1|RATR_MCS2|RATR_MCS3 |\ ++ RATR_MCS4|RATR_MCS5|RATR_MCS6 |RATR_MCS7 ++#define RATE_ALL_OFDM_2SS RATR_MCS8|RATR_MCS9 |RATR_MCS10|RATR_MCS11|\ ++ RATR_MCS12|RATR_MCS13|RATR_MCS14|RATR_MCS15 ++ ++/*------------------------------ Tx Desc definition Macro ------------------------*/ ++//#pragma mark -- Tx Desc related definition. -- ++//---------------------------------------------------------------------------- ++//----------------------------------------------------------- ++// Rate ++//----------------------------------------------------------- ++// CCK Rates, TxHT = 0 ++#define DESC_RATE1M 0x00 ++#define DESC_RATE2M 0x01 ++#define DESC_RATE5_5M 0x02 ++#define DESC_RATE11M 0x03 ++ ++// OFDM Rates, TxHT = 0 ++#define DESC_RATE6M 0x04 ++#define DESC_RATE9M 0x05 ++#define DESC_RATE12M 0x06 ++#define DESC_RATE18M 0x07 ++#define DESC_RATE24M 0x08 ++#define DESC_RATE36M 0x09 ++#define DESC_RATE48M 0x0a ++#define DESC_RATE54M 0x0b ++ ++// MCS Rates, TxHT = 1 ++#define DESC_RATEMCS0 0x0c ++#define DESC_RATEMCS1 0x0d ++#define DESC_RATEMCS2 0x0e ++#define DESC_RATEMCS3 0x0f ++#define DESC_RATEMCS4 0x10 ++#define DESC_RATEMCS5 0x11 ++#define DESC_RATEMCS6 0x12 ++#define DESC_RATEMCS7 0x13 ++#define DESC_RATEMCS8 0x14 ++#define DESC_RATEMCS9 0x15 ++#define DESC_RATEMCS10 0x16 ++#define DESC_RATEMCS11 0x17 ++#define DESC_RATEMCS12 0x18 ++#define DESC_RATEMCS13 0x19 ++#define DESC_RATEMCS14 0x1a ++#define DESC_RATEMCS15 0x1b ++#define DESC_RATEMCS15_SG 0x1c ++#define DESC_RATEMCS32 0x20 ++ ++#define REG_P2P_CTWIN 0x0572 // 1 Byte long (in unit of TU) ++#define REG_NOA_DESC_SEL 0x05CF ++#define REG_NOA_DESC_DURATION 0x05E0 ++#define REG_NOA_DESC_INTERVAL 0x05E4 ++#define REG_NOA_DESC_START 0x05E8 ++#define REG_NOA_DESC_COUNT 0x05EC ++ ++#include "HalVerDef.h" ++void dump_chip_info(HAL_VERSION ChipVersion); ++ ++ ++u8 //return the final channel plan decision ++hal_com_get_channel_plan( ++ IN PADAPTER padapter, ++ IN u8 hw_channel_plan, //channel plan from HW (efuse/eeprom) ++ IN u8 sw_channel_plan, //channel plan from SW (registry/module param) ++ IN u8 def_channel_plan, //channel plan used when the former two is invalid ++ IN BOOLEAN AutoLoadFail ++ ); ++ ++u8 MRateToHwRate(u8 rate); ++ ++void HalSetBrateCfg( ++ IN PADAPTER Adapter, ++ IN u8 *mBratesOS, ++ OUT u16 *pBrateCfg); ++ ++BOOLEAN ++Hal_MappingOutPipe( ++ IN PADAPTER pAdapter, ++ IN u8 NumOutPipe ++ ); ++ ++void hal_init_macaddr(_adapter *adapter); ++ ++void c2h_evt_clear(_adapter *adapter); ++s32 c2h_evt_read(_adapter *adapter, u8 *buf); ++ ++u8 SetHalDefVar(_adapter *adapter, HAL_DEF_VARIABLE variable, void *value); ++u8 GetHalDefVar(_adapter *adapter, HAL_DEF_VARIABLE variable, void *value); ++ ++#endif //__HAL_COMMON_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/hal_intf.h b/drivers/net/wireless/rtl818x/rtl8189/include/hal_intf.h +new file mode 100644 +index 00000000..2048321a +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/hal_intf.h +@@ -0,0 +1,487 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __HAL_INTF_H__ ++#define __HAL_INTF_H__ ++ ++#include ++#include ++#include ++ ++#ifdef CONFIG_PCI_HCI ++#include ++#endif ++ ++ ++enum RTL871X_HCI_TYPE { ++ RTW_PCIE = BIT0, ++ RTW_USB = BIT1, ++ RTW_SDIO = BIT2, ++ RTW_GSPI = BIT3, ++}; ++ ++enum _CHIP_TYPE { ++ ++ NULL_CHIP_TYPE, ++ RTL8712_8188S_8191S_8192S, ++ RTL8188C_8192C, ++ RTL8192D, ++ RTL8723A, ++ RTL8188E, ++ MAX_CHIP_TYPE ++}; ++ ++ ++typedef enum _HW_VARIABLES{ ++ HW_VAR_MEDIA_STATUS, ++ HW_VAR_MEDIA_STATUS1, ++ HW_VAR_SET_OPMODE, ++ HW_VAR_MAC_ADDR, ++ HW_VAR_BSSID, ++ HW_VAR_INIT_RTS_RATE, ++ HW_VAR_BASIC_RATE, ++ HW_VAR_TXPAUSE, ++ HW_VAR_BCN_FUNC, ++ HW_VAR_CORRECT_TSF, ++ HW_VAR_CHECK_BSSID, ++ HW_VAR_MLME_DISCONNECT, ++ HW_VAR_MLME_SITESURVEY, ++ HW_VAR_MLME_JOIN, ++ HW_VAR_ON_RCR_AM, ++ HW_VAR_OFF_RCR_AM, ++ HW_VAR_BEACON_INTERVAL, ++ HW_VAR_SLOT_TIME, ++ HW_VAR_RESP_SIFS, ++ HW_VAR_ACK_PREAMBLE, ++ HW_VAR_SEC_CFG, ++ HW_VAR_BCN_VALID, ++ HW_VAR_RF_TYPE, ++ HW_VAR_DM_FLAG, ++ HW_VAR_DM_FUNC_OP, ++ HW_VAR_DM_FUNC_SET, ++ HW_VAR_DM_FUNC_CLR, ++ HW_VAR_CAM_EMPTY_ENTRY, ++ HW_VAR_CAM_INVALID_ALL, ++ HW_VAR_CAM_WRITE, ++ HW_VAR_CAM_READ, ++ HW_VAR_AC_PARAM_VO, ++ HW_VAR_AC_PARAM_VI, ++ HW_VAR_AC_PARAM_BE, ++ HW_VAR_AC_PARAM_BK, ++ HW_VAR_ACM_CTRL, ++ HW_VAR_AMPDU_MIN_SPACE, ++ HW_VAR_AMPDU_FACTOR, ++ HW_VAR_RXDMA_AGG_PG_TH, ++ HW_VAR_SET_RPWM, ++ HW_VAR_GET_CPWM, ++ HW_VAR_H2C_FW_PWRMODE, ++ HW_VAR_H2C_FW_JOINBSSRPT, ++ HW_VAR_FWLPS_RF_ON, ++ HW_VAR_H2C_FW_P2P_PS_OFFLOAD, ++ HW_VAR_TDLS_WRCR, ++ HW_VAR_TDLS_INIT_CH_SEN, ++ HW_VAR_TDLS_RS_RCR, ++ HW_VAR_TDLS_DONE_CH_SEN, ++ HW_VAR_INITIAL_GAIN, ++ HW_VAR_TRIGGER_GPIO_0, ++ HW_VAR_BT_SET_COEXIST, ++ HW_VAR_BT_ISSUE_DELBA, ++ HW_VAR_CURRENT_ANTENNA, ++ HW_VAR_ANTENNA_DIVERSITY_LINK, ++ HW_VAR_ANTENNA_DIVERSITY_SELECT, ++ HW_VAR_SWITCH_EPHY_WoWLAN, ++ HW_VAR_EFUSE_USAGE, ++ HW_VAR_EFUSE_BYTES, ++ HW_VAR_EFUSE_BT_USAGE, ++ HW_VAR_EFUSE_BT_BYTES, ++ HW_VAR_FIFO_CLEARN_UP, ++ HW_VAR_CHECK_TXBUF, ++ HW_VAR_APFM_ON_MAC, //Auto FSM to Turn On, include clock, isolation, power control for MAC only ++ // The valid upper nav range for the HW updating, if the true value is larger than the upper range, the HW won't update it. ++ // Unit in microsecond. 0 means disable this function. ++#ifdef CONFIG_WOWLAN ++ HW_VAR_WOWLAN, ++#endif ++ HW_VAR_SYS_CLKR, ++ HW_VAR_NAV_UPPER, ++ HW_VAR_RPT_TIMER_SETTING, ++ HW_VAR_TX_RPT_MAX_MACID, ++ HW_VAR_H2C_MEDIA_STATUS_RPT, ++ HW_VAR_CHK_HI_QUEUE_EMPTY, ++ HW_VAR_READ_LLT_TAB, ++ HW_VAR_C2HEVT_CLEAR, ++ HW_VAR_C2HEVT_MSG_NORMAL, ++}HW_VARIABLES; ++ ++typedef enum _HAL_DEF_VARIABLE{ ++ HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, ++ HAL_DEF_IS_SUPPORT_ANT_DIV, ++ HAL_DEF_CURRENT_ANTENNA, ++ HAL_DEF_DRVINFO_SZ, ++ HAL_DEF_MAX_RECVBUF_SZ, ++ HAL_DEF_RX_PACKET_OFFSET, ++ HAL_DEF_DBG_DUMP_RXPKT,//for dbg ++ HAL_DEF_DBG_DM_FUNC,//for dbg ++ HAL_DEF_RA_DECISION_RATE, ++ HAL_DEF_RA_SGI, ++ HAL_DEF_PT_PWR_STATUS, ++ HW_VAR_MAX_RX_AMPDU_FACTOR, ++ HW_DEF_RA_INFO_DUMP, ++ HAL_DEF_DBG_DUMP_TXPKT, ++ HW_DEF_FA_CNT_DUMP, ++ HW_DEF_ODM_DBG_FLAG, ++ HW_DEF_ODM_DBG_LEVEL, ++}HAL_DEF_VARIABLE; ++ ++typedef enum _HAL_ODM_VARIABLE{ ++ HAL_ODM_STA_INFO, ++ HAL_ODM_P2P_STATE, ++ HAL_ODM_WIFI_DISPLAY_STATE, ++}HAL_ODM_VARIABLE; ++ ++typedef enum _HAL_INTF_PS_FUNC{ ++ HAL_USB_SELECT_SUSPEND, ++ HAL_MAX_ID, ++}HAL_INTF_PS_FUNC; ++ ++typedef s32 (*c2h_id_filter)(u8 id); ++ ++struct hal_ops { ++ u32 (*hal_power_on)(_adapter *padapter); ++ void (*hal_power_off)(_adapter *padapter); ++ u32 (*hal_init)(_adapter *padapter); ++ u32 (*hal_deinit)(_adapter *padapter); ++ ++ void (*free_hal_data)(_adapter *padapter); ++ ++ u32 (*inirp_init)(_adapter *padapter); ++ u32 (*inirp_deinit)(_adapter *padapter); ++ ++ s32 (*init_xmit_priv)(_adapter *padapter); ++ void (*free_xmit_priv)(_adapter *padapter); ++ ++ s32 (*init_recv_priv)(_adapter *padapter); ++ void (*free_recv_priv)(_adapter *padapter); ++ ++ void (*InitSwLeds)(_adapter *padapter); ++ void (*DeInitSwLeds)(_adapter *padapter); ++ ++ void (*dm_init)(_adapter *padapter); ++ void (*dm_deinit)(_adapter *padapter); ++ void (*read_chip_version)(_adapter *padapter); ++ ++ void (*init_default_value)(_adapter *padapter); ++ ++ void (*intf_chip_configure)(_adapter *padapter); ++ ++ void (*read_adapter_info)(_adapter *padapter); ++ ++ void (*enable_interrupt)(_adapter *padapter); ++ void (*disable_interrupt)(_adapter *padapter); ++ s32 (*interrupt_handler)(_adapter *padapter); ++#ifdef CONFIG_WOWLAN ++ void (*clear_interrupt)(_adapter *padapter); ++#endif ++ void (*set_bwmode_handler)(_adapter *padapter, HT_CHANNEL_WIDTH Bandwidth, u8 Offset); ++ void (*set_channel_handler)(_adapter *padapter, u8 channel); ++ ++ void (*hal_dm_watchdog)(_adapter *padapter); ++ ++ void (*SetHwRegHandler)(_adapter *padapter, u8 variable,u8* val); ++ void (*GetHwRegHandler)(_adapter *padapter, u8 variable,u8* val); ++ ++ u8 (*GetHalDefVarHandler)(_adapter *padapter, HAL_DEF_VARIABLE eVariable, PVOID pValue); ++ u8 (*SetHalDefVarHandler)(_adapter *padapter, HAL_DEF_VARIABLE eVariable, PVOID pValue); ++ ++ void (*GetHalODMVarHandler)(_adapter *padapter, HAL_ODM_VARIABLE eVariable, PVOID pValue1,BOOLEAN bSet); ++ void (*SetHalODMVarHandler)(_adapter *padapter, HAL_ODM_VARIABLE eVariable, PVOID pValue1,BOOLEAN bSet); ++ ++ void (*UpdateRAMaskHandler)(_adapter *padapter, u32 mac_id, u8 rssi_level); ++ void (*SetBeaconRelatedRegistersHandler)(_adapter *padapter); ++ ++ void (*Add_RateATid)(_adapter *padapter, u32 bitmap, u8 arg, u8 rssi_level); ++ ++ void (*run_thread)(_adapter *padapter); ++ void (*cancel_thread)(_adapter *padapter); ++ ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ u8 (*AntDivBeforeLinkHandler)(_adapter *padapter); ++ void (*AntDivCompareHandler)(_adapter *padapter, WLAN_BSSID_EX *dst, WLAN_BSSID_EX *src); ++#endif ++ u8 (*interface_ps_func)(_adapter *padapter,HAL_INTF_PS_FUNC efunc_id, u8* val); ++ ++ s32 (*hal_xmit)(_adapter *padapter, struct xmit_frame *pxmitframe); ++ s32 (*mgnt_xmit)(_adapter *padapter, struct xmit_frame *pmgntframe); ++ s32 (*hal_xmitframe_enqueue)(_adapter *padapter, struct xmit_frame *pxmitframe); ++ ++ u32 (*read_bbreg)(_adapter *padapter, u32 RegAddr, u32 BitMask); ++ void (*write_bbreg)(_adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data); ++ u32 (*read_rfreg)(_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask); ++ void (*write_rfreg)(_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask, u32 Data); ++ ++#ifdef CONFIG_HOSTAPD_MLME ++ s32 (*hostap_mgnt_xmit_entry)(_adapter *padapter, _pkt *pkt); ++#endif ++ ++ void (*EfusePowerSwitch)(_adapter *padapter, u8 bWrite, u8 PwrState); ++ void (*ReadEFuse)(_adapter *padapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, BOOLEAN bPseudoTest); ++ void (*EFUSEGetEfuseDefinition)(_adapter *padapter, u8 efuseType, u8 type, void *pOut, BOOLEAN bPseudoTest); ++ u16 (*EfuseGetCurrentSize)(_adapter *padapter, u8 efuseType, BOOLEAN bPseudoTest); ++ int (*Efuse_PgPacketRead)(_adapter *padapter, u8 offset, u8 *data, BOOLEAN bPseudoTest); ++ int (*Efuse_PgPacketWrite)(_adapter *padapter, u8 offset, u8 word_en, u8 *data, BOOLEAN bPseudoTest); ++ u8 (*Efuse_WordEnableDataWrite)(_adapter *padapter, u16 efuse_addr, u8 word_en, u8 *data, BOOLEAN bPseudoTest); ++ BOOLEAN (*Efuse_PgPacketWrite_BT)(_adapter *padapter, u8 offset, u8 word_en, u8 *data, BOOLEAN bPseudoTest); ++ ++#ifdef DBG_CONFIG_ERROR_DETECT ++ void (*sreset_init_value)(_adapter *padapter); ++ void (*sreset_reset_value)(_adapter *padapter); ++ void (*silentreset)(_adapter *padapter); ++ void (*sreset_xmit_status_check)(_adapter *padapter); ++ void (*sreset_linked_status_check) (_adapter *padapter); ++ u8 (*sreset_get_wifi_status)(_adapter *padapter); ++ bool (*sreset_inprogress)(_adapter *padapter); ++#endif ++ ++#ifdef CONFIG_IOL ++ int (*IOL_exec_cmds_sync)(_adapter *padapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt); ++#endif ++ ++#ifdef CONFIG_XMIT_THREAD_MODE ++ s32 (*xmit_thread_handler)(_adapter *padapter); ++#endif ++ void (*hal_notch_filter)(_adapter * adapter, bool enable); ++ void (*hal_reset_security_engine)(_adapter * adapter); ++ s32 (*c2h_handler)(_adapter *padapter, struct c2h_evt_hdr *c2h_evt); ++ c2h_id_filter c2h_id_filter_ccx; ++#if defined(CONFIG_CHECK_BT_HANG) && defined(CONFIG_BT_COEXIST) ++ void (*hal_init_checkbthang_workqueue)(_adapter * padapter); ++ void (*hal_free_checkbthang_workqueue)(_adapter * padapter); ++ void (*hal_cancel_checkbthang_workqueue)(_adapter * padapter); ++ void (*hal_checke_bt_hang)(_adapter * padapter); ++#endif ++}; ++ ++typedef enum _RT_EEPROM_TYPE{ ++ EEPROM_93C46, ++ EEPROM_93C56, ++ EEPROM_BOOT_EFUSE, ++}RT_EEPROM_TYPE,*PRT_EEPROM_TYPE; ++ ++ ++ ++#define RF_CHANGE_BY_INIT 0 ++#define RF_CHANGE_BY_IPS BIT28 ++#define RF_CHANGE_BY_PS BIT29 ++#define RF_CHANGE_BY_HW BIT30 ++#define RF_CHANGE_BY_SW BIT31 ++ ++typedef enum _HARDWARE_TYPE{ ++ HARDWARE_TYPE_RTL8180, ++ HARDWARE_TYPE_RTL8185, ++ HARDWARE_TYPE_RTL8187, ++ HARDWARE_TYPE_RTL8188, ++ HARDWARE_TYPE_RTL8190P, ++ HARDWARE_TYPE_RTL8192E, ++ HARDWARE_TYPE_RTL819xU, ++ HARDWARE_TYPE_RTL8192SE, ++ HARDWARE_TYPE_RTL8192SU, ++ HARDWARE_TYPE_RTL8192CE, ++ HARDWARE_TYPE_RTL8192CU, ++ HARDWARE_TYPE_RTL8192DE, ++ HARDWARE_TYPE_RTL8192DU, ++ HARDWARE_TYPE_RTL8723AE, ++ HARDWARE_TYPE_RTL8723AU, ++ HARDWARE_TYPE_RTL8723AS, ++ HARDWARE_TYPE_RTL8188EE, ++ HARDWARE_TYPE_RTL8188EU, ++ HARDWARE_TYPE_RTL8188ES, ++ HARDWARE_TYPE_MAX, ++}HARDWARE_TYPE; ++ ++// ++// RTL8192C Series ++// ++#define IS_HARDWARE_TYPE_8192CE(_Adapter) (((PADAPTER)_Adapter)->HardwareType==HARDWARE_TYPE_RTL8192CE) ++#define IS_HARDWARE_TYPE_8192CU(_Adapter) (((PADAPTER)_Adapter)->HardwareType==HARDWARE_TYPE_RTL8192CU) ++#define IS_HARDWARE_TYPE_8192C(_Adapter) \ ++(IS_HARDWARE_TYPE_8192CE(_Adapter) || IS_HARDWARE_TYPE_8192CU(_Adapter)) ++ ++// ++// RTL8192D Series ++// ++#define IS_HARDWARE_TYPE_8192DE(_Adapter) (((PADAPTER)_Adapter)->HardwareType==HARDWARE_TYPE_RTL8192DE) ++#define IS_HARDWARE_TYPE_8192DU(_Adapter) (((PADAPTER)_Adapter)->HardwareType==HARDWARE_TYPE_RTL8192DU) ++#define IS_HARDWARE_TYPE_8192D(_Adapter) \ ++(IS_HARDWARE_TYPE_8192DE(_Adapter) || IS_HARDWARE_TYPE_8192DU(_Adapter)) ++ ++// ++// RTL8723A Series ++// ++#define IS_HARDWARE_TYPE_8723AE(_Adapter) (((PADAPTER)_Adapter)->HardwareType==HARDWARE_TYPE_RTL8723AE) ++#define IS_HARDWARE_TYPE_8723AU(_Adapter) (((PADAPTER)_Adapter)->HardwareType==HARDWARE_TYPE_RTL8723AU) ++#define IS_HARDWARE_TYPE_8723AS(_Adapter) (((PADAPTER)_Adapter)->HardwareType==HARDWARE_TYPE_RTL8723AS) ++#define IS_HARDWARE_TYPE_8723A(_Adapter) \ ++(IS_HARDWARE_TYPE_8723AE(_Adapter) || IS_HARDWARE_TYPE_8723AU(_Adapter) || IS_HARDWARE_TYPE_8723AS(_Adapter)) ++ ++// ++// RTL8188E Series ++// ++#define IS_HARDWARE_TYPE_8188EE(_Adapter) (((PADAPTER)_Adapter)->HardwareType==HARDWARE_TYPE_RTL8188EE) ++#define IS_HARDWARE_TYPE_8188EU(_Adapter) (((PADAPTER)_Adapter)->HardwareType==HARDWARE_TYPE_RTL8188EU) ++#define IS_HARDWARE_TYPE_8188ES(_Adapter) (((PADAPTER)_Adapter)->HardwareType==HARDWARE_TYPE_RTL8188ES) ++#define IS_HARDWARE_TYPE_8188E(_Adapter) \ ++(IS_HARDWARE_TYPE_8188EE(_Adapter) || IS_HARDWARE_TYPE_8188EU(_Adapter) || IS_HARDWARE_TYPE_8188ES(_Adapter)) ++ ++ ++typedef struct eeprom_priv EEPROM_EFUSE_PRIV, *PEEPROM_EFUSE_PRIV; ++#define GET_EEPROM_EFUSE_PRIV(adapter) (&adapter->eeprompriv) ++#define is_boot_from_eeprom(adapter) (adapter->eeprompriv.EepromOrEfuse) ++ ++#ifdef CONFIG_WOWLAN ++typedef enum _wowlan_subcode{ ++ WOWLAN_PATTERN_MATCH = 1, ++ WOWLAN_MAGIC_PACKET = 2, ++ WOWLAN_UNICAST = 3, ++ WOWLAN_SET_PATTERN = 4, ++ WOWLAN_DUMP_REG = 5, ++ WOWLAN_ENABLE = 6, ++ WOWLAN_DISABLE = 7, ++ WOWLAN_STATUS = 8, ++ WOWLAN_DEBUG_RELOAD_FW = 9, ++ WOWLAN_DEBUG_1 =10, ++ WOWLAN_DEBUG_2 =11 ++}wowlan_subcode; ++ ++struct wowlan_ioctl_param{ ++ unsigned int subcode; ++ unsigned int subcode_value; ++ unsigned int wakeup_reason; ++ unsigned int len; ++ unsigned char pattern[0]; ++}; ++ ++#define Rx_Pairwisekey 0x01 ++#define Rx_GTK 0x02 ++#define Rx_DisAssoc 0x04 ++#define Rx_DeAuth 0x08 ++#define FWDecisionDisconnect 0x10 ++#define Rx_MagicPkt 0x21 ++#define Rx_UnicastPkt 0x22 ++#define Rx_PatternPkt 0x23 ++#endif // CONFIG_WOWLAN ++ ++void rtw_hal_def_value_init(_adapter *padapter); ++ ++void rtw_hal_free_data(_adapter *padapter); ++ ++void rtw_hal_dm_init(_adapter *padapter); ++void rtw_hal_dm_deinit(_adapter *padapter); ++void rtw_hal_sw_led_init(_adapter *padapter); ++void rtw_hal_sw_led_deinit(_adapter *padapter); ++ ++u32 rtw_hal_power_on(_adapter *padapter); ++void rtw_hal_power_off(_adapter *padapter); ++uint rtw_hal_init(_adapter *padapter); ++uint rtw_hal_deinit(_adapter *padapter); ++void rtw_hal_stop(_adapter *padapter); ++void rtw_hal_set_hwreg(PADAPTER padapter, u8 variable, u8 *val); ++void rtw_hal_get_hwreg(PADAPTER padapter, u8 variable, u8 *val); ++ ++void rtw_hal_chip_configure(_adapter *padapter); ++void rtw_hal_read_chip_info(_adapter *padapter); ++void rtw_hal_read_chip_version(_adapter *padapter); ++ ++u8 rtw_hal_set_def_var(_adapter *padapter, HAL_DEF_VARIABLE eVariable, PVOID pValue); ++u8 rtw_hal_get_def_var(_adapter *padapter, HAL_DEF_VARIABLE eVariable, PVOID pValue); ++ ++void rtw_hal_set_odm_var(_adapter *padapter, HAL_ODM_VARIABLE eVariable, PVOID pValue1,BOOLEAN bSet); ++void rtw_hal_get_odm_var(_adapter *padapter, HAL_ODM_VARIABLE eVariable, PVOID pValue1,BOOLEAN bSet); ++ ++void rtw_hal_enable_interrupt(_adapter *padapter); ++void rtw_hal_disable_interrupt(_adapter *padapter); ++ ++u32 rtw_hal_inirp_init(_adapter *padapter); ++u32 rtw_hal_inirp_deinit(_adapter *padapter); ++ ++u8 rtw_hal_intf_ps_func(_adapter *padapter,HAL_INTF_PS_FUNC efunc_id, u8* val); ++ ++s32 rtw_hal_xmitframe_enqueue(_adapter *padapter, struct xmit_frame *pxmitframe); ++s32 rtw_hal_xmit(_adapter *padapter, struct xmit_frame *pxmitframe); ++s32 rtw_hal_mgnt_xmit(_adapter *padapter, struct xmit_frame *pmgntframe); ++ ++s32 rtw_hal_init_xmit_priv(_adapter *padapter); ++void rtw_hal_free_xmit_priv(_adapter *padapter); ++ ++s32 rtw_hal_init_recv_priv(_adapter *padapter); ++void rtw_hal_free_recv_priv(_adapter *padapter); ++ ++void rtw_hal_update_ra_mask(struct sta_info *psta, u8 rssi_level); ++void rtw_hal_add_ra_tid(_adapter *padapter, u32 bitmap, u8 arg, u8 rssi_level); ++ ++void rtw_hal_start_thread(_adapter *padapter); ++void rtw_hal_stop_thread(_adapter *padapter); ++ ++void rtw_hal_bcn_related_reg_setting(_adapter *padapter); ++ ++u32 rtw_hal_read_bbreg(_adapter *padapter, u32 RegAddr, u32 BitMask); ++void rtw_hal_write_bbreg(_adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data); ++u32 rtw_hal_read_rfreg(_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask); ++void rtw_hal_write_rfreg(_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask, u32 Data); ++ ++s32 rtw_hal_interrupt_handler(_adapter *padapter); ++ ++void rtw_hal_set_bwmode(_adapter *padapter, HT_CHANNEL_WIDTH Bandwidth, u8 Offset); ++void rtw_hal_set_chan(_adapter *padapter, u8 channel); ++void rtw_hal_dm_watchdog(_adapter *padapter); ++ ++#ifdef CONFIG_ANTENNA_DIVERSITY ++u8 rtw_hal_antdiv_before_linked(_adapter *padapter); ++void rtw_hal_antdiv_rssi_compared(_adapter *padapter, WLAN_BSSID_EX *dst, WLAN_BSSID_EX *src); ++#endif ++ ++#ifdef CONFIG_HOSTAPD_MLME ++s32 rtw_hal_hostap_mgnt_xmit_entry(_adapter *padapter, _pkt *pkt); ++#endif ++ ++#ifdef DBG_CONFIG_ERROR_DETECT ++void rtw_hal_sreset_init(_adapter *padapter); ++void rtw_hal_sreset_reset(_adapter *padapter); ++void rtw_hal_sreset_reset_value(_adapter *padapter); ++void rtw_hal_sreset_xmit_status_check(_adapter *padapter); ++void rtw_hal_sreset_linked_status_check (_adapter *padapter); ++u8 rtw_hal_sreset_get_wifi_status(_adapter *padapter); ++bool rtw_hal_sreset_inprogress(_adapter *padapter); ++#endif ++ ++#ifdef CONFIG_IOL ++int rtw_hal_iol_cmd(ADAPTER *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt); ++#endif ++ ++#ifdef CONFIG_XMIT_THREAD_MODE ++s32 rtw_hal_xmit_thread_handler(_adapter *padapter); ++#endif ++ ++void rtw_hal_notch_filter(_adapter * adapter, bool enable); ++void rtw_hal_reset_security_engine(_adapter * adapter); ++ ++s32 rtw_hal_c2h_handler(_adapter *adapter, struct c2h_evt_hdr *c2h_evt); ++c2h_id_filter rtw_hal_c2h_id_filter_ccx(_adapter *adapter); ++ ++#endif //__HAL_INTF_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/ieee80211.h b/drivers/net/wireless/rtl818x/rtl8189/include/ieee80211.h +new file mode 100644 +index 00000000..422c47ab +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/ieee80211.h +@@ -0,0 +1,1589 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __IEEE80211_H ++#define __IEEE80211_H ++ ++ ++#ifndef CONFIG_RTL8711FW ++ ++ #include ++ #include ++ #include ++ #include "wifi.h" ++ ++ #if defined PLATFORM_OS_XP ++ #include ++ #endif ++ #if defined PLATFORM_LINUX ++ #include ++ #endif ++#else ++ ++ #include ++ ++#endif ++ ++#define MGMT_QUEUE_NUM 5 ++ ++#define ETH_ALEN 6 ++#define ETH_TYPE_LEN 2 ++#define PAYLOAD_TYPE_LEN 1 ++ ++#ifdef CONFIG_AP_MODE ++ ++#define RTL_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 28) ++ ++/* RTL871X_IOCTL_HOSTAPD ioctl() cmd: */ ++enum { ++ RTL871X_HOSTAPD_FLUSH = 1, ++ RTL871X_HOSTAPD_ADD_STA = 2, ++ RTL871X_HOSTAPD_REMOVE_STA = 3, ++ RTL871X_HOSTAPD_GET_INFO_STA = 4, ++ /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */ ++ RTL871X_HOSTAPD_GET_WPAIE_STA = 5, ++ RTL871X_SET_ENCRYPTION = 6, ++ RTL871X_GET_ENCRYPTION = 7, ++ RTL871X_HOSTAPD_SET_FLAGS_STA = 8, ++ RTL871X_HOSTAPD_GET_RID = 9, ++ RTL871X_HOSTAPD_SET_RID = 10, ++ RTL871X_HOSTAPD_SET_ASSOC_AP_ADDR = 11, ++ RTL871X_HOSTAPD_SET_GENERIC_ELEMENT = 12, ++ RTL871X_HOSTAPD_MLME = 13, ++ RTL871X_HOSTAPD_SCAN_REQ = 14, ++ RTL871X_HOSTAPD_STA_CLEAR_STATS = 15, ++ RTL871X_HOSTAPD_SET_BEACON=16, ++ RTL871X_HOSTAPD_SET_WPS_BEACON = 17, ++ RTL871X_HOSTAPD_SET_WPS_PROBE_RESP = 18, ++ RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP = 19, ++ RTL871X_HOSTAPD_SET_HIDDEN_SSID = 20, ++ RTL871X_HOSTAPD_SET_MACADDR_ACL = 21, ++ RTL871X_HOSTAPD_ACL_ADD_STA = 22, ++ RTL871X_HOSTAPD_ACL_REMOVE_STA = 23, ++}; ++ ++/* STA flags */ ++#define WLAN_STA_AUTH BIT(0) ++#define WLAN_STA_ASSOC BIT(1) ++#define WLAN_STA_PS BIT(2) ++#define WLAN_STA_TIM BIT(3) ++#define WLAN_STA_PERM BIT(4) ++#define WLAN_STA_AUTHORIZED BIT(5) ++#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ ++#define WLAN_STA_SHORT_PREAMBLE BIT(7) ++#define WLAN_STA_PREAUTH BIT(8) ++#define WLAN_STA_WME BIT(9) ++#define WLAN_STA_MFP BIT(10) ++#define WLAN_STA_HT BIT(11) ++#define WLAN_STA_WPS BIT(12) ++#define WLAN_STA_MAYBE_WPS BIT(13) ++#define WLAN_STA_NONERP BIT(31) ++ ++#endif ++ ++#define IEEE_CMD_SET_WPA_PARAM 1 ++#define IEEE_CMD_SET_WPA_IE 2 ++#define IEEE_CMD_SET_ENCRYPTION 3 ++#define IEEE_CMD_MLME 4 ++ ++#define IEEE_PARAM_WPA_ENABLED 1 ++#define IEEE_PARAM_TKIP_COUNTERMEASURES 2 ++#define IEEE_PARAM_DROP_UNENCRYPTED 3 ++#define IEEE_PARAM_PRIVACY_INVOKED 4 ++#define IEEE_PARAM_AUTH_ALGS 5 ++#define IEEE_PARAM_IEEE_802_1X 6 ++#define IEEE_PARAM_WPAX_SELECT 7 ++ ++#define AUTH_ALG_OPEN_SYSTEM 0x1 ++#define AUTH_ALG_SHARED_KEY 0x2 ++#define AUTH_ALG_LEAP 0x00000004 ++ ++#define IEEE_MLME_STA_DEAUTH 1 ++#define IEEE_MLME_STA_DISASSOC 2 ++ ++#define IEEE_CRYPT_ERR_UNKNOWN_ALG 2 ++#define IEEE_CRYPT_ERR_UNKNOWN_ADDR 3 ++#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED 4 ++#define IEEE_CRYPT_ERR_KEY_SET_FAILED 5 ++#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED 6 ++#define IEEE_CRYPT_ERR_CARD_CONF_FAILED 7 ++ ++ ++#define IEEE_CRYPT_ALG_NAME_LEN 16 ++ ++#define WPA_CIPHER_NONE BIT(0) ++#define WPA_CIPHER_WEP40 BIT(1) ++#define WPA_CIPHER_WEP104 BIT(2) ++#define WPA_CIPHER_TKIP BIT(3) ++#define WPA_CIPHER_CCMP BIT(4) ++ ++ ++ ++#define WPA_SELECTOR_LEN 4 ++extern u8 RTW_WPA_OUI_TYPE[] ; ++extern u16 RTW_WPA_VERSION ; ++extern u8 WPA_AUTH_KEY_MGMT_NONE[]; ++extern u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[]; ++extern u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[]; ++extern u8 WPA_CIPHER_SUITE_NONE[]; ++extern u8 WPA_CIPHER_SUITE_WEP40[]; ++extern u8 WPA_CIPHER_SUITE_TKIP[]; ++extern u8 WPA_CIPHER_SUITE_WRAP[]; ++extern u8 WPA_CIPHER_SUITE_CCMP[]; ++extern u8 WPA_CIPHER_SUITE_WEP104[]; ++ ++ ++#define RSN_HEADER_LEN 4 ++#define RSN_SELECTOR_LEN 4 ++ ++extern u16 RSN_VERSION_BSD; ++extern u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[]; ++extern u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[]; ++extern u8 RSN_CIPHER_SUITE_NONE[]; ++extern u8 RSN_CIPHER_SUITE_WEP40[]; ++extern u8 RSN_CIPHER_SUITE_TKIP[]; ++extern u8 RSN_CIPHER_SUITE_WRAP[]; ++extern u8 RSN_CIPHER_SUITE_CCMP[]; ++extern u8 RSN_CIPHER_SUITE_WEP104[]; ++ ++typedef enum _RATR_TABLE_MODE{ ++ RATR_INX_WIRELESS_NGB = 0, // BGN 40 Mhz 2SS 1SS ++ RATR_INX_WIRELESS_NG = 1, // GN or N ++ RATR_INX_WIRELESS_NB = 2, // BGN 20 Mhz 2SS 1SS or BN ++ RATR_INX_WIRELESS_N = 3, ++ RATR_INX_WIRELESS_GB = 4, ++ RATR_INX_WIRELESS_G = 5, ++ RATR_INX_WIRELESS_B = 6, ++ RATR_INX_WIRELESS_MC = 7, ++ RATR_INX_WIRELESS_AC_N = 8, ++}RATR_TABLE_MODE, *PRATR_TABLE_MODE; ++ ++enum NETWORK_TYPE ++{ ++ WIRELESS_INVALID = 0, ++ //Sub-Element ++ WIRELESS_11B = BIT(0), // tx: cck only , rx: cck only, hw: cck ++ WIRELESS_11G = BIT(1), // tx: ofdm only, rx: ofdm & cck, hw: cck & ofdm ++ WIRELESS_11A = BIT(2), // tx: ofdm only, rx: ofdm only, hw: ofdm only ++ WIRELESS_11_24N = BIT(3), // tx: MCS only, rx: MCS & cck, hw: MCS & cck ++ WIRELESS_11_5N = BIT(4), // tx: MCS only, rx: MCS & ofdm, hw: ofdm only ++ //WIRELESS_AUTO = BIT(5), ++ WIRELESS_AC = BIT(6), ++ ++ //Combination ++ WIRELESS_11BG = (WIRELESS_11B|WIRELESS_11G), // tx: cck & ofdm, rx: cck & ofdm & MCS, hw: cck & ofdm ++ WIRELESS_11G_24N = (WIRELESS_11G|WIRELESS_11_24N), // tx: ofdm & MCS, rx: ofdm & cck & MCS, hw: cck & ofdm ++ WIRELESS_11A_5N = (WIRELESS_11A|WIRELESS_11_5N), // tx: ofdm & MCS, rx: ofdm & MCS, hw: ofdm only ++ WIRELESS_11BG_24N = (WIRELESS_11B|WIRELESS_11G|WIRELESS_11_24N), // tx: ofdm & cck & MCS, rx: ofdm & cck & MCS, hw: ofdm & cck ++ WIRELESS_11AGN = (WIRELESS_11A|WIRELESS_11G|WIRELESS_11_24N|WIRELESS_11_5N), // tx: ofdm & MCS, rx: ofdm & MCS, hw: ofdm only ++ WIRELESS_11ABGN = (WIRELESS_11A|WIRELESS_11B|WIRELESS_11G|WIRELESS_11_24N|WIRELESS_11_5N), ++}; ++ ++#define SUPPORTED_24G_NETTYPE_MSK (WIRELESS_11B | WIRELESS_11G | WIRELESS_11_24N) ++#define SUPPORTED_5G_NETTYPE_MSK (WIRELESS_11A | WIRELESS_11_5N) ++ ++#define IsSupported24G(NetType) ((NetType) & SUPPORTED_24G_NETTYPE_MSK ? _TRUE : _FALSE) ++#define IsSupported5G(NetType) ((NetType) & SUPPORTED_5G_NETTYPE_MSK ? _TRUE : _FALSE) ++ ++#define IsEnableHWCCK(NetType) IsSupported24G(NetType) ++#define IsEnableHWOFDM(NetType) ((NetType) & (WIRELESS_11G|WIRELESS_11_24N|SUPPORTED_5G_NETTYPE_MSK) ? _TRUE : _FALSE) ++ ++#define IsSupportedRxCCK(NetType) IsEnableHWCCK(NetType) ++#define IsSupportedRxOFDM(NetType) IsEnableHWOFDM(NetType) ++#define IsSupportedRxMCS(NetType) IsEnableHWOFDM(NetType) ++ ++#define IsSupportedTxCCK(NetType) ((NetType) & (WIRELESS_11B) ? _TRUE : _FALSE) ++#define IsSupportedTxOFDM(NetType) ((NetType) & (WIRELESS_11G|WIRELESS_11A) ? _TRUE : _FALSE) ++#define IsSupportedTxMCS(NetType) ((NetType) & (WIRELESS_11_24N|WIRELESS_11_5N) ? _TRUE : _FALSE) ++ ++ ++typedef struct ieee_param { ++ u32 cmd; ++ u8 sta_addr[ETH_ALEN]; ++ union { ++ struct { ++ u8 name; ++ u32 value; ++ } wpa_param; ++ struct { ++ u32 len; ++ u8 reserved[32]; ++ u8 data[0]; ++ } wpa_ie; ++ struct{ ++ int command; ++ int reason_code; ++ } mlme; ++ struct { ++ u8 alg[IEEE_CRYPT_ALG_NAME_LEN]; ++ u8 set_tx; ++ u32 err; ++ u8 idx; ++ u8 seq[8]; /* sequence counter (set: RX, get: TX) */ ++ u16 key_len; ++ u8 key[0]; ++ } crypt; ++#ifdef CONFIG_AP_MODE ++ struct { ++ u16 aid; ++ u16 capability; ++ int flags; ++ u8 tx_supp_rates[16]; ++ struct rtw_ieee80211_ht_cap ht_cap; ++ } add_sta; ++ struct { ++ u8 reserved[2];//for set max_num_sta ++ u8 buf[0]; ++ } bcn_ie; ++#endif ++ ++ } u; ++}ieee_param; ++ ++#ifdef CONFIG_AP_MODE ++typedef struct ieee_param_ex { ++ u32 cmd; ++ u8 sta_addr[ETH_ALEN]; ++ u8 data[0]; ++}ieee_param_ex; ++ ++struct sta_data{ ++ u16 aid; ++ u16 capability; ++ int flags; ++ u32 sta_set; ++ u8 tx_supp_rates[16]; ++ u32 tx_supp_rates_len; ++ struct rtw_ieee80211_ht_cap ht_cap; ++ u64 rx_pkts; ++ u64 rx_bytes; ++ u64 rx_drops; ++ u64 tx_pkts; ++ u64 tx_bytes; ++ u64 tx_drops; ++}; ++#endif ++ ++ ++#if WIRELESS_EXT < 17 ++#define IW_QUAL_QUAL_INVALID 0x10 ++#define IW_QUAL_LEVEL_INVALID 0x20 ++#define IW_QUAL_NOISE_INVALID 0x40 ++#define IW_QUAL_QUAL_UPDATED 0x1 ++#define IW_QUAL_LEVEL_UPDATED 0x2 ++#define IW_QUAL_NOISE_UPDATED 0x4 ++#endif ++ ++#define IEEE80211_DATA_LEN 2304 ++/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section ++ 6.2.1.1.2. ++ ++ The figure in section 7.1.2 suggests a body size of up to 2312 ++ bytes is allowed, which is a bit confusing, I suspect this ++ represents the 2304 bytes of real data, plus a possible 8 bytes of ++ WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ ++ ++ ++#define IEEE80211_HLEN 30 ++#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) ++ ++ ++/* this is stolen from ipw2200 driver */ ++#define IEEE_IBSS_MAC_HASH_SIZE 31 ++ ++struct ieee_ibss_seq { ++ u8 mac[ETH_ALEN]; ++ u16 seq_num; ++ u16 frag_num; ++ unsigned long packet_time; ++ _list list; ++}; ++ ++#if defined(PLATFORM_LINUX) || defined(CONFIG_RTL8711FW)||defined(PLATFORM_FREEBSD) ++ ++struct rtw_ieee80211_hdr { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++ u8 addr4[ETH_ALEN]; ++} __attribute__ ((packed)); ++ ++struct rtw_ieee80211_hdr_3addr { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++} __attribute__ ((packed)); ++ ++ ++struct rtw_ieee80211_hdr_qos { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++ u8 addr4[ETH_ALEN]; ++ u16 qc; ++} __attribute__ ((packed)); ++ ++struct rtw_ieee80211_hdr_3addr_qos { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++ u16 qc; ++} __attribute__ ((packed)); ++ ++struct eapol { ++ u8 snap[6]; ++ u16 ethertype; ++ u8 version; ++ u8 type; ++ u16 length; ++} __attribute__ ((packed)); ++ ++#endif ++ ++ ++ ++#ifdef PLATFORM_WINDOWS ++ ++#pragma pack(1) ++struct rtw_ieee80211_hdr { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++ u8 addr4[ETH_ALEN]; ++}; ++ ++struct rtw_ieee80211_hdr_3addr { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++}; ++ ++ ++struct rtw_ieee80211_hdr_qos { ++ struct rtw_ieee80211_hdr wlan_hdr; ++ u16 qc; ++}; ++ ++struct rtw_ieee80211_hdr_3addr_qos { ++ struct rtw_ieee80211_hdr_3addr wlan_hdr; ++ u16 qc; ++}; ++ ++struct eapol { ++ u8 snap[6]; ++ u16 ethertype; ++ u8 version; ++ u8 type; ++ u16 length; ++}; ++#pragma pack() ++ ++#endif ++ ++ ++ ++enum eap_type { ++ EAP_PACKET = 0, ++ EAPOL_START, ++ EAPOL_LOGOFF, ++ EAPOL_KEY, ++ EAPOL_ENCAP_ASF_ALERT ++}; ++ ++#define IEEE80211_3ADDR_LEN 24 ++#define IEEE80211_4ADDR_LEN 30 ++#define IEEE80211_FCS_LEN 4 ++ ++#define MIN_FRAG_THRESHOLD 256U ++#define MAX_FRAG_THRESHOLD 2346U ++ ++/* Frame control field constants */ ++#define RTW_IEEE80211_FCTL_VERS 0x0003 ++#define RTW_IEEE80211_FCTL_FTYPE 0x000c ++#define RTW_IEEE80211_FCTL_STYPE 0x00f0 ++#define RTW_IEEE80211_FCTL_TODS 0x0100 ++#define RTW_IEEE80211_FCTL_FROMDS 0x0200 ++#define RTW_IEEE80211_FCTL_MOREFRAGS 0x0400 ++#define RTW_IEEE80211_FCTL_RETRY 0x0800 ++#define RTW_IEEE80211_FCTL_PM 0x1000 ++#define RTW_IEEE80211_FCTL_MOREDATA 0x2000 ++#define RTW_IEEE80211_FCTL_PROTECTED 0x4000 ++#define RTW_IEEE80211_FCTL_ORDER 0x8000 ++#define RTW_IEEE80211_FCTL_CTL_EXT 0x0f00 ++ ++#define RTW_IEEE80211_FTYPE_MGMT 0x0000 ++#define RTW_IEEE80211_FTYPE_CTL 0x0004 ++#define RTW_IEEE80211_FTYPE_DATA 0x0008 ++#define RTW_IEEE80211_FTYPE_EXT 0x000c ++ ++/* management */ ++#define RTW_IEEE80211_STYPE_ASSOC_REQ 0x0000 ++#define RTW_IEEE80211_STYPE_ASSOC_RESP 0x0010 ++#define RTW_IEEE80211_STYPE_REASSOC_REQ 0x0020 ++#define RTW_IEEE80211_STYPE_REASSOC_RESP 0x0030 ++#define RTW_IEEE80211_STYPE_PROBE_REQ 0x0040 ++#define RTW_IEEE80211_STYPE_PROBE_RESP 0x0050 ++#define RTW_IEEE80211_STYPE_BEACON 0x0080 ++#define RTW_IEEE80211_STYPE_ATIM 0x0090 ++#define RTW_IEEE80211_STYPE_DISASSOC 0x00A0 ++#define RTW_IEEE80211_STYPE_AUTH 0x00B0 ++#define RTW_IEEE80211_STYPE_DEAUTH 0x00C0 ++#define RTW_IEEE80211_STYPE_ACTION 0x00D0 ++ ++/* control */ ++#define RTW_IEEE80211_STYPE_CTL_EXT 0x0060 ++#define RTW_IEEE80211_STYPE_BACK_REQ 0x0080 ++#define RTW_IEEE80211_STYPE_BACK 0x0090 ++#define RTW_IEEE80211_STYPE_PSPOLL 0x00A0 ++#define RTW_IEEE80211_STYPE_RTS 0x00B0 ++#define RTW_IEEE80211_STYPE_CTS 0x00C0 ++#define RTW_IEEE80211_STYPE_ACK 0x00D0 ++#define RTW_IEEE80211_STYPE_CFEND 0x00E0 ++#define RTW_IEEE80211_STYPE_CFENDACK 0x00F0 ++ ++/* data */ ++#define RTW_IEEE80211_STYPE_DATA 0x0000 ++#define RTW_IEEE80211_STYPE_DATA_CFACK 0x0010 ++#define RTW_IEEE80211_STYPE_DATA_CFPOLL 0x0020 ++#define RTW_IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 ++#define RTW_IEEE80211_STYPE_NULLFUNC 0x0040 ++#define RTW_IEEE80211_STYPE_CFACK 0x0050 ++#define RTW_IEEE80211_STYPE_CFPOLL 0x0060 ++#define RTW_IEEE80211_STYPE_CFACKPOLL 0x0070 ++#define RTW_IEEE80211_STYPE_QOS_DATA 0x0080 ++#define RTW_IEEE80211_STYPE_QOS_DATA_CFACK 0x0090 ++#define RTW_IEEE80211_STYPE_QOS_DATA_CFPOLL 0x00A0 ++#define RTW_IEEE80211_STYPE_QOS_DATA_CFACKPOLL 0x00B0 ++#define RTW_IEEE80211_STYPE_QOS_NULLFUNC 0x00C0 ++#define RTW_IEEE80211_STYPE_QOS_CFACK 0x00D0 ++#define RTW_IEEE80211_STYPE_QOS_CFPOLL 0x00E0 ++#define RTW_IEEE80211_STYPE_QOS_CFACKPOLL 0x00F0 ++ ++/* sequence control field */ ++#define RTW_IEEE80211_SCTL_FRAG 0x000F ++#define RTW_IEEE80211_SCTL_SEQ 0xFFF0 ++ ++ ++#define RTW_ERP_INFO_NON_ERP_PRESENT BIT(0) ++#define RTW_ERP_INFO_USE_PROTECTION BIT(1) ++#define RTW_ERP_INFO_BARKER_PREAMBLE_MODE BIT(2) ++ ++/* QoS,QOS */ ++#define NORMAL_ACK 0 ++#define NO_ACK 1 ++#define NON_EXPLICIT_ACK 2 ++#define BLOCK_ACK 3 ++ ++#ifndef ETH_P_PAE ++#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ ++#endif /* ETH_P_PAE */ ++ ++#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ ++ ++#define ETH_P_ECONET 0x0018 ++ ++#ifndef ETH_P_80211_RAW ++#define ETH_P_80211_RAW (ETH_P_ECONET + 1) ++#endif ++ ++/* IEEE 802.11 defines */ ++ ++#define P80211_OUI_LEN 3 ++ ++#if defined(PLATFORM_LINUX) || defined(CONFIG_RTL8711FW) || defined(PLATFORM_FREEBSD) ++ ++struct ieee80211_snap_hdr { ++ ++ u8 dsap; /* always 0xAA */ ++ u8 ssap; /* always 0xAA */ ++ u8 ctrl; /* always 0x03 */ ++ u8 oui[P80211_OUI_LEN]; /* organizational universal id */ ++ ++} __attribute__ ((packed)); ++ ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++ ++#pragma pack(1) ++struct ieee80211_snap_hdr { ++ ++ u8 dsap; /* always 0xAA */ ++ u8 ssap; /* always 0xAA */ ++ u8 ctrl; /* always 0x03 */ ++ u8 oui[P80211_OUI_LEN]; /* organizational universal id */ ++ ++}; ++#pragma pack() ++ ++#endif ++ ++ ++#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) ++ ++#define WLAN_FC_GET_TYPE(fc) ((fc) & RTW_IEEE80211_FCTL_FTYPE) ++#define WLAN_FC_GET_STYPE(fc) ((fc) & RTW_IEEE80211_FCTL_STYPE) ++ ++#define WLAN_QC_GET_TID(qc) ((qc) & 0x0f) ++ ++#define WLAN_GET_SEQ_FRAG(seq) ((seq) & RTW_IEEE80211_SCTL_FRAG) ++#define WLAN_GET_SEQ_SEQ(seq) ((seq) & RTW_IEEE80211_SCTL_SEQ) ++ ++/* Authentication algorithms */ ++#define WLAN_AUTH_OPEN 0 ++#define WLAN_AUTH_SHARED_KEY 1 ++ ++#define WLAN_AUTH_CHALLENGE_LEN 128 ++ ++#define WLAN_CAPABILITY_BSS (1<<0) ++#define WLAN_CAPABILITY_IBSS (1<<1) ++#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) ++#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) ++#define WLAN_CAPABILITY_PRIVACY (1<<4) ++#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) ++#define WLAN_CAPABILITY_PBCC (1<<6) ++#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) ++#define WLAN_CAPABILITY_SHORT_SLOT (1<<10) ++ ++/* Status codes */ ++#define WLAN_STATUS_SUCCESS 0 ++#define WLAN_STATUS_UNSPECIFIED_FAILURE 1 ++#define WLAN_STATUS_CAPS_UNSUPPORTED 10 ++#define WLAN_STATUS_REASSOC_NO_ASSOC 11 ++#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 ++#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 ++#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 ++#define WLAN_STATUS_CHALLENGE_FAIL 15 ++#define WLAN_STATUS_AUTH_TIMEOUT 16 ++#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 ++#define WLAN_STATUS_ASSOC_DENIED_RATES 18 ++/* 802.11b */ ++#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 ++#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 ++#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 ++ ++/* Reason codes */ ++#define WLAN_REASON_UNSPECIFIED 1 ++#define WLAN_REASON_PREV_AUTH_NOT_VALID 2 ++#define WLAN_REASON_DEAUTH_LEAVING 3 ++#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 ++#define WLAN_REASON_DISASSOC_AP_BUSY 5 ++#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 ++#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 ++#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 ++#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 ++#define WLAN_REASON_JOIN_WRONG_CHANNEL 65534 ++#define WLAN_REASON_EXPIRATION_CHK 65535 ++ ++/* Information Element IDs */ ++#define WLAN_EID_SSID 0 ++#define WLAN_EID_SUPP_RATES 1 ++#define WLAN_EID_FH_PARAMS 2 ++#define WLAN_EID_DS_PARAMS 3 ++#define WLAN_EID_CF_PARAMS 4 ++#define WLAN_EID_TIM 5 ++#define WLAN_EID_IBSS_PARAMS 6 ++#define WLAN_EID_CHALLENGE 16 ++/* EIDs defined by IEEE 802.11h - START */ ++#define WLAN_EID_PWR_CONSTRAINT 32 ++#define WLAN_EID_PWR_CAPABILITY 33 ++#define WLAN_EID_TPC_REQUEST 34 ++#define WLAN_EID_TPC_REPORT 35 ++#define WLAN_EID_SUPPORTED_CHANNELS 36 ++#define WLAN_EID_CHANNEL_SWITCH 37 ++#define WLAN_EID_MEASURE_REQUEST 38 ++#define WLAN_EID_MEASURE_REPORT 39 ++#define WLAN_EID_QUITE 40 ++#define WLAN_EID_IBSS_DFS 41 ++/* EIDs defined by IEEE 802.11h - END */ ++#define WLAN_EID_ERP_INFO 42 ++#define WLAN_EID_HT_CAP 45 ++#define WLAN_EID_RSN 48 ++#define WLAN_EID_EXT_SUPP_RATES 50 ++#define WLAN_EID_MOBILITY_DOMAIN 54 ++#define WLAN_EID_FAST_BSS_TRANSITION 55 ++#define WLAN_EID_TIMEOUT_INTERVAL 56 ++#define WLAN_EID_RIC_DATA 57 ++#define WLAN_EID_HT_OPERATION 61 ++#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 ++#define WLAN_EID_20_40_BSS_COEXISTENCE 72 ++#define WLAN_EID_20_40_BSS_INTOLERANT 73 ++#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74 ++#define WLAN_EID_MMIE 76 ++#define WLAN_EID_VENDOR_SPECIFIC 221 ++#define WLAN_EID_GENERIC (WLAN_EID_VENDOR_SPECIFIC) ++ ++#define IEEE80211_MGMT_HDR_LEN 24 ++#define IEEE80211_DATA_HDR3_LEN 24 ++#define IEEE80211_DATA_HDR4_LEN 30 ++ ++ ++#define IEEE80211_STATMASK_SIGNAL (1<<0) ++#define IEEE80211_STATMASK_RSSI (1<<1) ++#define IEEE80211_STATMASK_NOISE (1<<2) ++#define IEEE80211_STATMASK_RATE (1<<3) ++#define IEEE80211_STATMASK_WEMASK 0x7 ++ ++ ++#define IEEE80211_CCK_MODULATION (1<<0) ++#define IEEE80211_OFDM_MODULATION (1<<1) ++ ++#define IEEE80211_24GHZ_BAND (1<<0) ++#define IEEE80211_52GHZ_BAND (1<<1) ++ ++#define IEEE80211_CCK_RATE_LEN 4 ++#define IEEE80211_NUM_OFDM_RATESLEN 8 ++ ++ ++#define IEEE80211_CCK_RATE_1MB 0x02 ++#define IEEE80211_CCK_RATE_2MB 0x04 ++#define IEEE80211_CCK_RATE_5MB 0x0B ++#define IEEE80211_CCK_RATE_11MB 0x16 ++#define IEEE80211_OFDM_RATE_LEN 8 ++#define IEEE80211_OFDM_RATE_6MB 0x0C ++#define IEEE80211_OFDM_RATE_9MB 0x12 ++#define IEEE80211_OFDM_RATE_12MB 0x18 ++#define IEEE80211_OFDM_RATE_18MB 0x24 ++#define IEEE80211_OFDM_RATE_24MB 0x30 ++#define IEEE80211_OFDM_RATE_36MB 0x48 ++#define IEEE80211_OFDM_RATE_48MB 0x60 ++#define IEEE80211_OFDM_RATE_54MB 0x6C ++#define IEEE80211_BASIC_RATE_MASK 0x80 ++ ++#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) ++#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) ++#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) ++#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) ++#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) ++#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) ++#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) ++#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) ++#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) ++#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) ++#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) ++#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) ++ ++#define IEEE80211_CCK_RATES_MASK 0x0000000F ++#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ ++ IEEE80211_CCK_RATE_2MB_MASK) ++#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ ++ IEEE80211_CCK_RATE_5MB_MASK | \ ++ IEEE80211_CCK_RATE_11MB_MASK) ++ ++#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 ++#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ ++ IEEE80211_OFDM_RATE_12MB_MASK | \ ++ IEEE80211_OFDM_RATE_24MB_MASK) ++#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ ++ IEEE80211_OFDM_RATE_9MB_MASK | \ ++ IEEE80211_OFDM_RATE_18MB_MASK | \ ++ IEEE80211_OFDM_RATE_36MB_MASK | \ ++ IEEE80211_OFDM_RATE_48MB_MASK | \ ++ IEEE80211_OFDM_RATE_54MB_MASK) ++#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ ++ IEEE80211_CCK_DEFAULT_RATES_MASK) ++ ++#define IEEE80211_NUM_OFDM_RATES 8 ++#define IEEE80211_NUM_CCK_RATES 4 ++#define IEEE80211_OFDM_SHIFT_MASK_A 4 ++ ++ ++ ++ ++/* NOTE: This data is for statistical purposes; not all hardware provides this ++ * information for frames received. Not setting these will not cause ++ * any adverse affects. */ ++struct ieee80211_rx_stats { ++ //u32 mac_time[2]; ++ s8 rssi; ++ u8 signal; ++ u8 noise; ++ u8 received_channel; ++ u16 rate; /* in 100 kbps */ ++ //u8 control; ++ u8 mask; ++ u8 freq; ++ u16 len; ++}; ++ ++/* IEEE 802.11 requires that STA supports concurrent reception of at least ++ * three fragmented frames. This define can be increased to support more ++ * concurrent frames, but it should be noted that each entry can consume about ++ * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ ++#define IEEE80211_FRAG_CACHE_LEN 4 ++ ++struct ieee80211_frag_entry { ++ u32 first_frag_time; ++ uint seq; ++ uint last_frag; ++ uint qos; //jackson ++ uint tid; //jackson ++ struct sk_buff *skb; ++ u8 src_addr[ETH_ALEN]; ++ u8 dst_addr[ETH_ALEN]; ++}; ++ ++#ifndef PLATFORM_FREEBSD //Baron BSD has already defined ++struct ieee80211_stats { ++ uint tx_unicast_frames; ++ uint tx_multicast_frames; ++ uint tx_fragments; ++ uint tx_unicast_octets; ++ uint tx_multicast_octets; ++ uint tx_deferred_transmissions; ++ uint tx_single_retry_frames; ++ uint tx_multiple_retry_frames; ++ uint tx_retry_limit_exceeded; ++ uint tx_discards; ++ uint rx_unicast_frames; ++ uint rx_multicast_frames; ++ uint rx_fragments; ++ uint rx_unicast_octets; ++ uint rx_multicast_octets; ++ uint rx_fcs_errors; ++ uint rx_discards_no_buffer; ++ uint tx_discards_wrong_sa; ++ uint rx_discards_undecryptable; ++ uint rx_message_in_msg_fragments; ++ uint rx_message_in_bad_msg_fragments; ++}; ++#endif //PLATFORM_FREEBSD ++struct ieee80211_softmac_stats{ ++ uint rx_ass_ok; ++ uint rx_ass_err; ++ uint rx_probe_rq; ++ uint tx_probe_rs; ++ uint tx_beacons; ++ uint rx_auth_rq; ++ uint rx_auth_rs_ok; ++ uint rx_auth_rs_err; ++ uint tx_auth_rq; ++ uint no_auth_rs; ++ uint no_ass_rs; ++ uint tx_ass_rq; ++ uint rx_ass_rq; ++ uint tx_probe_rq; ++ uint reassoc; ++ uint swtxstop; ++ uint swtxawake; ++}; ++ ++#define SEC_KEY_1 (1<<0) ++#define SEC_KEY_2 (1<<1) ++#define SEC_KEY_3 (1<<2) ++#define SEC_KEY_4 (1<<3) ++#define SEC_ACTIVE_KEY (1<<4) ++#define SEC_AUTH_MODE (1<<5) ++#define SEC_UNICAST_GROUP (1<<6) ++#define SEC_LEVEL (1<<7) ++#define SEC_ENABLED (1<<8) ++ ++#define SEC_LEVEL_0 0 /* None */ ++#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ ++#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ ++#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ ++#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ ++ ++#define WEP_KEYS 4 ++#define WEP_KEY_LEN 13 ++ ++#ifdef CONFIG_IEEE80211W ++#define BIP_MAX_KEYID 5 ++#define BIP_AAD_SIZE 20 ++#endif //CONFIG_IEEE80211W ++ ++#if defined(PLATFORM_LINUX) || defined(CONFIG_RTL8711FW) ++ ++struct ieee80211_security { ++ u16 active_key:2, ++ enabled:1, ++ auth_mode:2, ++ auth_algo:4, ++ unicast_uses_group:1; ++ u8 key_sizes[WEP_KEYS]; ++ u8 keys[WEP_KEYS][WEP_KEY_LEN]; ++ u8 level; ++ u16 flags; ++} __attribute__ ((packed)); ++ ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++ ++#pragma pack(1) ++struct ieee80211_security { ++ u16 active_key:2, ++ enabled:1, ++ auth_mode:2, ++ auth_algo:4, ++ unicast_uses_group:1; ++ u8 key_sizes[WEP_KEYS]; ++ u8 keys[WEP_KEYS][WEP_KEY_LEN]; ++ u8 level; ++ u16 flags; ++} ; ++#pragma pack() ++ ++#endif ++ ++/* ++ ++ 802.11 data frame from AP ++ ++ ,-------------------------------------------------------------------. ++Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | ++ |------|------|---------|---------|---------|------|---------|------| ++Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | ++ | | tion | (BSSID) | | | ence | data | | ++ `-------------------------------------------------------------------' ++ ++Total: 28-2340 bytes ++ ++*/ ++ ++struct ieee80211_header_data { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[6]; ++ u8 addr2[6]; ++ u8 addr3[6]; ++ u16 seq_ctrl; ++}; ++ ++#define BEACON_PROBE_SSID_ID_POSITION 12 ++ ++/* Management Frame Information Element Types */ ++#define MFIE_TYPE_SSID 0 ++#define MFIE_TYPE_RATES 1 ++#define MFIE_TYPE_FH_SET 2 ++#define MFIE_TYPE_DS_SET 3 ++#define MFIE_TYPE_CF_SET 4 ++#define MFIE_TYPE_TIM 5 ++#define MFIE_TYPE_IBSS_SET 6 ++#define MFIE_TYPE_CHALLENGE 16 ++#define MFIE_TYPE_ERP 42 ++#define MFIE_TYPE_RSN 48 ++#define MFIE_TYPE_RATES_EX 50 ++#define MFIE_TYPE_GENERIC 221 ++ ++#if defined(PLATFORM_LINUX) || defined(CONFIG_RTL8711FW) ++ ++struct ieee80211_info_element_hdr { ++ u8 id; ++ u8 len; ++} __attribute__ ((packed)); ++ ++struct ieee80211_info_element { ++ u8 id; ++ u8 len; ++ u8 data[0]; ++} __attribute__ ((packed)); ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++ ++#pragma pack(1) ++struct ieee80211_info_element_hdr { ++ u8 id; ++ u8 len; ++} ; ++ ++struct ieee80211_info_element { ++ u8 id; ++ u8 len; ++ u8 data[0]; ++} ; ++#pragma pack() ++ ++#endif ++ ++ ++/* ++ * These are the data types that can make up management packets ++ * ++ u16 auth_algorithm; ++ u16 auth_sequence; ++ u16 beacon_interval; ++ u16 capability; ++ u8 current_ap[ETH_ALEN]; ++ u16 listen_interval; ++ struct { ++ u16 association_id:14, reserved:2; ++ } __attribute__ ((packed)); ++ u32 time_stamp[2]; ++ u16 reason; ++ u16 status; ++*/ ++ ++#define IEEE80211_DEFAULT_TX_ESSID "Penguin" ++#define IEEE80211_DEFAULT_BASIC_RATE 10 ++ ++ ++#if defined(PLATFORM_LINUX) || defined(CONFIG_RTL8711FW) ++ ++ ++struct ieee80211_authentication { ++ struct ieee80211_header_data header; ++ u16 algorithm; ++ u16 transaction; ++ u16 status; ++ //struct ieee80211_info_element_hdr info_element; ++} __attribute__ ((packed)); ++ ++ ++struct ieee80211_probe_response { ++ struct ieee80211_header_data header; ++ u32 time_stamp[2]; ++ u16 beacon_interval; ++ u16 capability; ++ struct ieee80211_info_element info_element; ++} __attribute__ ((packed)); ++ ++struct ieee80211_probe_request { ++ struct ieee80211_header_data header; ++ /*struct ieee80211_info_element info_element;*/ ++} __attribute__ ((packed)); ++ ++struct ieee80211_assoc_request_frame { ++ struct rtw_ieee80211_hdr_3addr header; ++ u16 capability; ++ u16 listen_interval; ++ //u8 current_ap[ETH_ALEN]; ++ struct ieee80211_info_element_hdr info_element; ++} __attribute__ ((packed)); ++ ++struct ieee80211_assoc_response_frame { ++ struct rtw_ieee80211_hdr_3addr header; ++ u16 capability; ++ u16 status; ++ u16 aid; ++// struct ieee80211_info_element info_element; /* supported rates */ ++} __attribute__ ((packed)); ++#endif ++ ++ ++ ++#ifdef PLATFORM_WINDOWS ++ ++#pragma pack(1) ++ ++struct ieee80211_authentication { ++ struct ieee80211_header_data header; ++ u16 algorithm; ++ u16 transaction; ++ u16 status; ++ //struct ieee80211_info_element_hdr info_element; ++} ; ++ ++ ++struct ieee80211_probe_response { ++ struct ieee80211_header_data header; ++ u32 time_stamp[2]; ++ u16 beacon_interval; ++ u16 capability; ++ struct ieee80211_info_element info_element; ++} ; ++ ++struct ieee80211_probe_request { ++ struct ieee80211_header_data header; ++ /*struct ieee80211_info_element info_element;*/ ++} ; ++ ++struct ieee80211_assoc_request_frame { ++ struct rtw_ieee80211_hdr_3addr header; ++ u16 capability; ++ u16 listen_interval; ++ //u8 current_ap[ETH_ALEN]; ++ struct ieee80211_info_element_hdr info_element; ++} ; ++ ++struct ieee80211_assoc_response_frame { ++ struct rtw_ieee80211_hdr_3addr header; ++ u16 capability; ++ u16 status; ++ u16 aid; ++// struct ieee80211_info_element info_element; /* supported rates */ ++}; ++ ++#pragma pack() ++ ++#endif ++ ++ ++ ++ ++struct ieee80211_txb { ++ u8 nr_frags; ++ u8 encrypted; ++ u16 reserved; ++ u16 frag_size; ++ u16 payload_size; ++ struct sk_buff *fragments[0]; ++}; ++ ++ ++/* SWEEP TABLE ENTRIES NUMBER*/ ++#define MAX_SWEEP_TAB_ENTRIES 42 ++#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 ++/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs ++ * only use 8, and then use extended rates for the remaining supported ++ * rates. Other APs, however, stick all of their supported rates on the ++ * main rates information element... */ ++#define MAX_RATES_LENGTH ((u8)12) ++#define MAX_RATES_EX_LENGTH ((u8)16) ++#define MAX_NETWORK_COUNT 128 ++#define MAX_CHANNEL_NUMBER 161 ++#define IEEE80211_SOFTMAC_SCAN_TIME 400 ++//(HZ / 2) ++#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2) ++ ++#define CRC_LENGTH 4U ++ ++#define MAX_WPA_IE_LEN (256) ++#define MAX_WPS_IE_LEN (512) ++#define MAX_P2P_IE_LEN (256) ++#define MAX_WFD_IE_LEN (128) ++ ++#define NETWORK_EMPTY_ESSID (1<<0) ++#define NETWORK_HAS_OFDM (1<<1) ++#define NETWORK_HAS_CCK (1<<2) ++ ++#define IEEE80211_DTIM_MBCAST 4 ++#define IEEE80211_DTIM_UCAST 2 ++#define IEEE80211_DTIM_VALID 1 ++#define IEEE80211_DTIM_INVALID 0 ++ ++#define IEEE80211_PS_DISABLED 0 ++#define IEEE80211_PS_UNICAST IEEE80211_DTIM_UCAST ++#define IEEE80211_PS_MBCAST IEEE80211_DTIM_MBCAST ++#define IW_ESSID_MAX_SIZE 32 ++#if 0 ++struct ieee80211_network { ++ /* These entries are used to identify a unique network */ ++ u8 bssid[ETH_ALEN]; ++ u8 channel; ++ /* Ensure null-terminated for any debug msgs */ ++ u8 ssid[IW_ESSID_MAX_SIZE + 1]; ++ u8 ssid_len; ++ u8 rssi; //relative signal strength ++ u8 sq; //signal quality ++ ++ /* These are network statistics */ ++ //struct ieee80211_rx_stats stats; ++ u16 capability; ++ u16 aid; ++ u8 rates[MAX_RATES_LENGTH]; ++ u8 rates_len; ++ u8 rates_ex[MAX_RATES_EX_LENGTH]; ++ u8 rates_ex_len; ++ ++ u8 edca_parmsets[18]; ++ ++ u8 mode; ++ u8 flags; ++ u8 time_stamp[8]; ++ u16 beacon_interval; ++ u16 listen_interval; ++ u16 atim_window; ++ u8 wpa_ie[MAX_WPA_IE_LEN]; ++ size_t wpa_ie_len; ++ u8 rsn_ie[MAX_WPA_IE_LEN]; ++ size_t rsn_ie_len; ++ u8 country[6]; ++ u8 dtim_period; ++ u8 dtim_data; ++ u8 power_constraint; ++ u8 qosinfo; ++ u8 qbssload[5]; ++ u8 network_type; ++ int join_res; ++ unsigned long last_scanned; ++}; ++#endif ++/* ++join_res: ++-1: authentication fail ++-2: association fail ++> 0: TID ++*/ ++ ++#ifndef PLATFORM_FREEBSD //Baron BSD has already defined ++ ++enum ieee80211_state { ++ ++ /* the card is not linked at all */ ++ IEEE80211_NOLINK = 0, ++ ++ /* IEEE80211_ASSOCIATING* are for BSS client mode ++ * the driver shall not perform RX filtering unless ++ * the state is LINKED. ++ * The driver shall just check for the state LINKED and ++ * defaults to NOLINK for ALL the other states (including ++ * LINKED_SCANNING) ++ */ ++ ++ /* the association procedure will start (wq scheduling)*/ ++ IEEE80211_ASSOCIATING, ++ IEEE80211_ASSOCIATING_RETRY, ++ ++ /* the association procedure is sending AUTH request*/ ++ IEEE80211_ASSOCIATING_AUTHENTICATING, ++ ++ /* the association procedure has successfully authentcated ++ * and is sending association request ++ */ ++ IEEE80211_ASSOCIATING_AUTHENTICATED, ++ ++ /* the link is ok. the card associated to a BSS or linked ++ * to a ibss cell or acting as an AP and creating the bss ++ */ ++ IEEE80211_LINKED, ++ ++ /* same as LINKED, but the driver shall apply RX filter ++ * rules as we are in NO_LINK mode. As the card is still ++ * logically linked, but it is doing a syncro site survey ++ * then it will be back to LINKED state. ++ */ ++ IEEE80211_LINKED_SCANNING, ++ ++}; ++#endif //PLATFORM_FREEBSD ++ ++#define DEFAULT_MAX_SCAN_AGE (15 * HZ) ++#define DEFAULT_FTS 2346 ++#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" ++#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5] ++#define IP_FMT "%d.%d.%d.%d" ++#define IP_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3] ++ ++#ifdef PLATFORM_FREEBSD //Baron change func to macro ++#define is_multicast_mac_addr(Addr) ((((Addr[0]) & 0x01) == 0x01) && ((Addr[0]) != 0xff)) ++#define is_broadcast_mac_addr(Addr) ((((Addr[0]) & 0xff) == 0xff) && (((Addr[1]) & 0xff) == 0xff) && \ ++(((Addr[2]) & 0xff) == 0xff) && (((Addr[3]) & 0xff) == 0xff) && (((Addr[4]) & 0xff) == 0xff) && \ ++(((Addr[5]) & 0xff) == 0xff)) ++#else ++extern __inline int is_multicast_mac_addr(const u8 *addr) ++{ ++ return ((addr[0] != 0xff) && (0x01 & addr[0])); ++} ++ ++extern __inline int is_broadcast_mac_addr(const u8 *addr) ++{ ++ return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \ ++ (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)); ++} ++ ++extern __inline int is_zero_mac_addr(const u8 *addr) ++{ ++ return ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && \ ++ (addr[3] == 0x00) && (addr[4] == 0x00) && (addr[5] == 0x00)); ++} ++#endif //PLATFORM_FREEBSD ++ ++#define CFG_IEEE80211_RESERVE_FCS (1<<0) ++#define CFG_IEEE80211_COMPUTE_FCS (1<<1) ++ ++typedef struct tx_pending_t{ ++ int frag; ++ struct ieee80211_txb *txb; ++}tx_pending_t; ++ ++ ++ ++#define MAXTID 16 ++ ++#define IEEE_A (1<<0) ++#define IEEE_B (1<<1) ++#define IEEE_G (1<<2) ++#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) ++ ++//Baron move to ieee80211.c ++int ieee80211_is_empty_essid(const char *essid, int essid_len); ++int ieee80211_get_hdrlen(u16 fc); ++ ++#if 0 ++/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */ ++#define WLAN_ACTION_SPECTRUM_MGMT 0 ++#define WLAN_ACTION_QOS 1 ++#define WLAN_ACTION_DLS 2 ++#define WLAN_ACTION_BLOCK_ACK 3 ++#define WLAN_ACTION_RADIO_MEASUREMENT 5 ++#define WLAN_ACTION_FT 6 ++#define WLAN_ACTION_SA_QUERY 8 ++#define WLAN_ACTION_WMM 17 ++#endif ++ ++ ++/* Action category code */ ++enum rtw_ieee80211_category { ++ RTW_WLAN_CATEGORY_SPECTRUM_MGMT = 0, ++ RTW_WLAN_CATEGORY_QOS = 1, ++ RTW_WLAN_CATEGORY_DLS = 2, ++ RTW_WLAN_CATEGORY_BACK = 3, ++ RTW_WLAN_CATEGORY_PUBLIC = 4, //IEEE 802.11 public action frames ++ RTW_WLAN_CATEGORY_RADIO_MEASUREMENT = 5, ++ RTW_WLAN_CATEGORY_FT = 6, ++ RTW_WLAN_CATEGORY_HT = 7, ++ RTW_WLAN_CATEGORY_SA_QUERY = 8, ++ RTW_WLAN_CATEGORY_UNPROTECTED_WNM = 11, // add for CONFIG_IEEE80211W, none 11w also can use ++ RTW_WLAN_CATEGORY_TDLS = 12, ++ RTW_WLAN_CATEGORY_SELF_PROTECTED = 15, // add for CONFIG_IEEE80211W, none 11w also can use ++ RTW_WLAN_CATEGORY_WMM = 17, ++ RTW_WLAN_CATEGORY_P2P = 0x7f,//P2P action frames ++}; ++ ++/* SPECTRUM_MGMT action code */ ++enum rtw_ieee80211_spectrum_mgmt_actioncode { ++ RTW_WLAN_ACTION_SPCT_MSR_REQ = 0, ++ RTW_WLAN_ACTION_SPCT_MSR_RPRT = 1, ++ RTW_WLAN_ACTION_SPCT_TPC_REQ = 2, ++ RTW_WLAN_ACTION_SPCT_TPC_RPRT = 3, ++ RTW_WLAN_ACTION_SPCT_CHL_SWITCH = 4, ++ RTW_WLAN_ACTION_SPCT_EXT_CHL_SWITCH = 5, ++}; ++ ++enum _PUBLIC_ACTION{ ++ ACT_PUBLIC_BSSCOEXIST = 0, // 20/40 BSS Coexistence ++ ACT_PUBLIC_DSE_ENABLE = 1, ++ ACT_PUBLIC_DSE_DEENABLE = 2, ++ ACT_PUBLIC_DSE_REG_LOCATION = 3, ++ ACT_PUBLIC_EXT_CHL_SWITCH = 4, ++ ACT_PUBLIC_DSE_MSR_REQ = 5, ++ ACT_PUBLIC_DSE_MSR_RPRT = 6, ++ ACT_PUBLIC_MP = 7, // Measurement Pilot ++ ACT_PUBLIC_DSE_PWR_CONSTRAINT = 8, ++ ACT_PUBLIC_VENDOR = 9, // for WIFI_DIRECT ++ ACT_PUBLIC_GAS_INITIAL_REQ = 10, ++ ACT_PUBLIC_GAS_INITIAL_RSP = 11, ++ ACT_PUBLIC_GAS_COMEBACK_REQ = 12, ++ ACT_PUBLIC_GAS_COMEBACK_RSP = 13, ++ ACT_PUBLIC_TDLS_DISCOVERY_RSP = 14, ++ ACT_PUBLIC_LOCATION_TRACK = 15, ++ ACT_PUBLIC_MAX ++}; ++ ++#ifdef CONFIG_TDLS ++enum TDLS_ACTION_FIELD{ ++ TDLS_SETUP_REQUEST = 0, ++ TDLS_SETUP_RESPONSE = 1, ++ TDLS_SETUP_CONFIRM = 2, ++ TDLS_TEARDOWN = 3, ++ TDLS_PEER_TRAFFIC_INDICATION = 4, ++ TDLS_CHANNEL_SWITCH_REQUEST = 5, ++ TDLS_CHANNEL_SWITCH_RESPONSE = 6, ++ TDLS_PEER_PSM_REQUEST = 7, ++ TDLS_PEER_PSM_RESPONSE = 8, ++ TDLS_PEER_TRAFFIC_RESPONSE = 9, ++ TDLS_DISCOVERY_REQUEST = 10, ++ TDLS_DISCOVERY_RESPONSE = 14, //it's used in public action frame ++}; ++ ++#define TUNNELED_PROBE_REQ 15 ++#define TUNNELED_PROBE_RSP 16 ++#endif //CONFIG_TDLS ++ ++/* BACK action code */ ++enum rtw_ieee80211_back_actioncode { ++ RTW_WLAN_ACTION_ADDBA_REQ = 0, ++ RTW_WLAN_ACTION_ADDBA_RESP = 1, ++ RTW_WLAN_ACTION_DELBA = 2, ++}; ++ ++/* HT features action code */ ++enum rtw_ieee80211_ht_actioncode { ++ RTW_WLAN_ACTION_NOTIFY_CH_WIDTH = 0, ++ RTW_WLAN_ACTION_SM_PS = 1, ++ RTW_WLAN_ACTION_PSPM = 2, ++ RTW_WLAN_ACTION_PCO_PHASE = 3, ++ RTW_WLAN_ACTION_MIMO_CSI_MX = 4, ++ RTW_WLAN_ACTION_MIMO_NONCP_BF = 5, ++ RTW_WLAN_ACTION_MIMP_CP_BF = 6, ++ RTW_WLAN_ACTION_ASEL_INDICATES_FB = 7, ++ RTW_WLAN_ACTION_HI_INFO_EXCHG = 8, ++}; ++ ++/* BACK (block-ack) parties */ ++enum rtw_ieee80211_back_parties { ++ RTW_WLAN_BACK_RECIPIENT = 0, ++ RTW_WLAN_BACK_INITIATOR = 1, ++ RTW_WLAN_BACK_TIMER = 2, ++}; ++ ++ ++#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs) ++ * 00:50:F2 */ ++#ifndef PLATFORM_FREEBSD //Baron BSD has defined ++#define WME_OUI_TYPE 2 ++#endif //PLATFORM_FREEBSD ++#define WME_OUI_SUBTYPE_INFORMATION_ELEMENT 0 ++#define WME_OUI_SUBTYPE_PARAMETER_ELEMENT 1 ++#define WME_OUI_SUBTYPE_TSPEC_ELEMENT 2 ++#define WME_VERSION 1 ++ ++#define WME_ACTION_CODE_SETUP_REQUEST 0 ++#define WME_ACTION_CODE_SETUP_RESPONSE 1 ++#define WME_ACTION_CODE_TEARDOWN 2 ++ ++#define WME_SETUP_RESPONSE_STATUS_ADMISSION_ACCEPTED 0 ++#define WME_SETUP_RESPONSE_STATUS_INVALID_PARAMETERS 1 ++#define WME_SETUP_RESPONSE_STATUS_REFUSED 3 ++ ++#define WME_TSPEC_DIRECTION_UPLINK 0 ++#define WME_TSPEC_DIRECTION_DOWNLINK 1 ++#define WME_TSPEC_DIRECTION_BI_DIRECTIONAL 3 ++ ++ ++#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */ ++ ++#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */ ++ ++/** ++ * enum rtw_ieee80211_channel_flags - channel flags ++ * ++ * Channel flags set by the regulatory control code. ++ * ++ * @RTW_IEEE80211_CHAN_DISABLED: This channel is disabled. ++ * @RTW_IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted ++ * on this channel. ++ * @RTW_IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel. ++ * @RTW_IEEE80211_CHAN_RADAR: Radar detection is required on this channel. ++ * @RTW_IEEE80211_CHAN_NO_HT40PLUS: extension channel above this channel ++ * is not permitted. ++ * @RTW_IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel ++ * is not permitted. ++ */ ++ enum rtw_ieee80211_channel_flags { ++ RTW_IEEE80211_CHAN_DISABLED = 1<<0, ++ RTW_IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, ++ RTW_IEEE80211_CHAN_NO_IBSS = 1<<2, ++ RTW_IEEE80211_CHAN_RADAR = 1<<3, ++ RTW_IEEE80211_CHAN_NO_HT40PLUS = 1<<4, ++ RTW_IEEE80211_CHAN_NO_HT40MINUS = 1<<5, ++ }; ++ ++ #define RTW_IEEE80211_CHAN_NO_HT40 \ ++ (RTW_IEEE80211_CHAN_NO_HT40PLUS | RTW_IEEE80211_CHAN_NO_HT40MINUS) ++ ++/* Represent channel details, subset of ieee80211_channel */ ++struct rtw_ieee80211_channel { ++ //enum ieee80211_band band; ++ //u16 center_freq; ++ u16 hw_value; ++ u32 flags; ++ //int max_antenna_gain; ++ //int max_power; ++ //int max_reg_power; ++ //bool beacon_found; ++ //u32 orig_flags; ++ //int orig_mag; ++ //int orig_mpwr; ++}; ++ ++#define CHAN_FMT \ ++ /*"band:%d, "*/ \ ++ /*"center_freq:%u, "*/ \ ++ "hw_value:%u, " \ ++ "flags:0x%08x" \ ++ /*"max_antenna_gain:%d\n"*/ \ ++ /*"max_power:%d\n"*/ \ ++ /*"max_reg_power:%d\n"*/ \ ++ /*"beacon_found:%u\n"*/ \ ++ /*"orig_flags:0x%08x\n"*/ \ ++ /*"orig_mag:%d\n"*/ \ ++ /*"orig_mpwr:%d\n"*/ ++ ++#define CHAN_ARG(channel) \ ++ /*(channel)->band*/ \ ++ /*, (channel)->center_freq*/ \ ++ (channel)->hw_value \ ++ , (channel)->flags \ ++ /*, (channel)->max_antenna_gain*/ \ ++ /*, (channel)->max_power*/ \ ++ /*, (channel)->max_reg_power*/ \ ++ /*, (channel)->beacon_found*/ \ ++ /*, (channel)->orig_flags*/ \ ++ /*, (channel)->orig_mag*/ \ ++ /*, (channel)->orig_mpwr*/ \ ++ ++/* Parsed Information Elements */ ++struct rtw_ieee802_11_elems { ++ u8 *ssid; ++ u8 ssid_len; ++ u8 *supp_rates; ++ u8 supp_rates_len; ++ u8 *fh_params; ++ u8 fh_params_len; ++ u8 *ds_params; ++ u8 ds_params_len; ++ u8 *cf_params; ++ u8 cf_params_len; ++ u8 *tim; ++ u8 tim_len; ++ u8 *ibss_params; ++ u8 ibss_params_len; ++ u8 *challenge; ++ u8 challenge_len; ++ u8 *erp_info; ++ u8 erp_info_len; ++ u8 *ext_supp_rates; ++ u8 ext_supp_rates_len; ++ u8 *wpa_ie; ++ u8 wpa_ie_len; ++ u8 *rsn_ie; ++ u8 rsn_ie_len; ++ u8 *wme; ++ u8 wme_len; ++ u8 *wme_tspec; ++ u8 wme_tspec_len; ++ u8 *wps_ie; ++ u8 wps_ie_len; ++ u8 *power_cap; ++ u8 power_cap_len; ++ u8 *supp_channels; ++ u8 supp_channels_len; ++ u8 *mdie; ++ u8 mdie_len; ++ u8 *ftie; ++ u8 ftie_len; ++ u8 *timeout_int; ++ u8 timeout_int_len; ++ u8 *ht_capabilities; ++ u8 ht_capabilities_len; ++ u8 *ht_operation; ++ u8 ht_operation_len; ++ u8 *vendor_ht_cap; ++ u8 vendor_ht_cap_len; ++}; ++ ++typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; ++ ++ParseRes rtw_ieee802_11_parse_elems(u8 *start, uint len, ++ struct rtw_ieee802_11_elems *elems, ++ int show_errors); ++ ++u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len, unsigned char *source, unsigned int *frlen); ++u8 *rtw_set_ie(u8 *pbuf, sint index, uint len, u8 *source, uint *frlen); ++ ++enum secondary_ch_offset { ++ SCN = 0, /* no secondary channel */ ++ SCA = 1, /* secondary channel above */ ++ SCB = 3, /* secondary channel below */ ++}; ++u8 secondary_ch_offset_to_hal_ch_offset(u8 ch_offset); ++u8 hal_ch_offset_to_secondary_ch_offset(u8 ch_offset); ++u8 *rtw_set_ie_ch_switch(u8 *buf, u32 *buf_len, u8 ch_switch_mode, u8 new_ch, u8 ch_switch_cnt); ++u8 *rtw_set_ie_secondary_ch_offset(u8 *buf, u32 *buf_len, u8 secondary_ch_offset); ++u8 *rtw_set_ie_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl, u8 flags, u16 reason, u16 precedence); ++ ++u8 *rtw_get_ie(u8*pbuf, sint index, sint *len, sint limit); ++u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen); ++int rtw_ies_remove_ie(u8 *ies, uint *ies_len, uint offset, u8 eid, u8 *oui, u8 oui_len); ++ ++void rtw_set_supported_rate(u8* SupportedRates, uint mode) ; ++ ++unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit); ++unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit); ++int rtw_get_wpa_cipher_suite(u8 *s); ++int rtw_get_wpa2_cipher_suite(u8 *s); ++int rtw_get_wapi_ie(u8 *in_ie,uint in_len,u8 *wapi_ie,u16 *wapi_len); ++int rtw_parse_wpa_ie(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x); ++int rtw_parse_wpa2_ie(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x); ++ ++int rtw_get_sec_ie(u8 *in_ie,uint in_len,u8 *rsn_ie,u16 *rsn_len,u8 *wpa_ie,u16 *wpa_len); ++ ++u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen); ++u8 *rtw_get_wps_ie_from_scan_queue(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen, u8 frame_type); ++u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen); ++u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id ,u8 *buf_attr, u32 *len_attr); ++u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id ,u8 *buf_content, uint *len_content); ++ ++/** ++ * for_each_ie - iterate over continuous IEs ++ * @ie: ++ * @buf: ++ * @buf_len: ++ */ ++#define for_each_ie(ie, buf, buf_len) \ ++ for (ie = (void*)buf; (((u8*)ie) - ((u8*)buf) + 1) < buf_len; ie = (void*)(((u8*)ie) + *(((u8*)ie)+1) + 2)) ++ ++void dump_ies(u8 *buf, u32 buf_len); ++void dump_wps_ie(u8 *ie, u32 ie_len); ++ ++#ifdef CONFIG_P2P ++u32 rtw_get_p2p_merged_ies_len(u8 *in_ie, u32 in_len); ++int rtw_p2p_merge_ies(u8 *in_ie, u32 in_len, u8 *merge_ie); ++void dump_p2p_ie(u8 *ie, u32 ie_len); ++u8 *rtw_get_p2p_ie(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen); ++u8 *rtw_get_p2p_ie_from_scan_queue(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen, u8 frame_type); ++u8 *rtw_get_p2p_attr(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id ,u8 *buf_attr, u32 *len_attr); ++u8 *rtw_get_p2p_attr_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id ,u8 *buf_content, uint *len_content); ++u32 rtw_set_p2p_attr_content(u8 *pbuf, u8 attr_id, u16 attr_len, u8 *pdata_attr); ++void rtw_WLAN_BSSID_EX_remove_p2p_attr(WLAN_BSSID_EX *bss_ex, u8 attr_id); ++#endif ++ ++#ifdef CONFIG_WFD ++void dump_wfd_ie(u8 *ie, u32 ie_len); ++int rtw_get_wfd_ie(u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen); ++int rtw_get_wfd_ie_from_scan_queue(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen, u8 frame_type); ++int rtw_get_wfd_attr_content(u8 *wfd_ie, uint wfd_ielen, u8 target_attr_id ,u8 *attr_content, uint *attr_contentlen); ++#endif // CONFIG_WFD ++ ++uint rtw_get_rateset_len(u8 *rateset); ++ ++struct registry_priv; ++int rtw_generate_ie(struct registry_priv *pregistrypriv); ++ ++ ++int rtw_get_bit_value_from_ieee_value(u8 val); ++ ++uint rtw_is_cckrates_included(u8 *rate); ++ ++uint rtw_is_cckratesonly_included(u8 *rate); ++ ++int rtw_check_network_type(unsigned char *rate, int ratelen, int channel); ++ ++void rtw_get_bcn_info(struct wlan_network *pnetwork); ++ ++void rtw_macaddr_cfg(u8 *mac_addr); ++ ++u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI_20, u8 short_GI_40, unsigned char * MCS_rate); ++ ++int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8* category, u8 *action); ++const char *action_public_str(u8 action); ++ ++#endif /* IEEE80211_H */ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/ieee80211_ext.h b/drivers/net/wireless/rtl818x/rtl8189/include/ieee80211_ext.h +new file mode 100644 +index 00000000..14f1b239 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/ieee80211_ext.h +@@ -0,0 +1,477 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __IEEE80211_EXT_H ++#define __IEEE80211_EXT_H ++ ++#include ++#include ++#include ++ ++#define WMM_OUI_TYPE 2 ++#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0 ++#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1 ++#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2 ++#define WMM_VERSION 1 ++ ++#define WPA_PROTO_WPA BIT(0) ++#define WPA_PROTO_RSN BIT(1) ++ ++#define WPA_KEY_MGMT_IEEE8021X BIT(0) ++#define WPA_KEY_MGMT_PSK BIT(1) ++#define WPA_KEY_MGMT_NONE BIT(2) ++#define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3) ++#define WPA_KEY_MGMT_WPA_NONE BIT(4) ++ ++ ++#define WPA_CAPABILITY_PREAUTH BIT(0) ++#define WPA_CAPABILITY_MGMT_FRAME_PROTECTION BIT(6) ++#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9) ++ ++ ++#define PMKID_LEN 16 ++ ++ ++#ifdef PLATFORM_LINUX ++struct wpa_ie_hdr { ++ u8 elem_id; ++ u8 len; ++ u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */ ++ u8 version[2]; /* little endian */ ++}__attribute__ ((packed)); ++ ++struct rsn_ie_hdr { ++ u8 elem_id; /* WLAN_EID_RSN */ ++ u8 len; ++ u8 version[2]; /* little endian */ ++}__attribute__ ((packed)); ++ ++struct wme_ac_parameter { ++#if defined(CONFIG_LITTLE_ENDIAN) ++ /* byte 1 */ ++ u8 aifsn:4, ++ acm:1, ++ aci:2, ++ reserved:1; ++ ++ /* byte 2 */ ++ u8 eCWmin:4, ++ eCWmax:4; ++#elif defined(CONFIG_BIG_ENDIAN) ++ /* byte 1 */ ++ u8 reserved:1, ++ aci:2, ++ acm:1, ++ aifsn:4; ++ ++ /* byte 2 */ ++ u8 eCWmax:4, ++ eCWmin:4; ++#else ++#error "Please fix " ++#endif ++ ++ /* bytes 3 & 4 */ ++ u16 txopLimit; ++} __attribute__ ((packed)); ++ ++struct wme_parameter_element { ++ /* required fields for WME version 1 */ ++ u8 oui[3]; ++ u8 oui_type; ++ u8 oui_subtype; ++ u8 version; ++ u8 acInfo; ++ u8 reserved; ++ struct wme_ac_parameter ac[4]; ++ ++} __attribute__ ((packed)); ++ ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++ ++#pragma pack(1) ++ ++struct wpa_ie_hdr { ++ u8 elem_id; ++ u8 len; ++ u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */ ++ u8 version[2]; /* little endian */ ++}; ++ ++struct rsn_ie_hdr { ++ u8 elem_id; /* WLAN_EID_RSN */ ++ u8 len; ++ u8 version[2]; /* little endian */ ++}; ++ ++#pragma pack() ++ ++#endif ++ ++#define WPA_PUT_LE16(a, val) \ ++ do { \ ++ (a)[1] = ((u16) (val)) >> 8; \ ++ (a)[0] = ((u16) (val)) & 0xff; \ ++ } while (0) ++ ++#define WPA_PUT_BE32(a, val) \ ++ do { \ ++ (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ ++ (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ ++ (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ ++ (a)[3] = (u8) (((u32) (val)) & 0xff); \ ++ } while (0) ++ ++#define WPA_PUT_LE32(a, val) \ ++ do { \ ++ (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ ++ (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ ++ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ ++ (a)[0] = (u8) (((u32) (val)) & 0xff); \ ++ } while (0) ++ ++#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val)) ++//#define RSN_SELECTOR_PUT(a, val) WPA_PUT_LE32((u8 *) (a), (val)) ++ ++ ++ ++/* Action category code */ ++enum ieee80211_category { ++ WLAN_CATEGORY_SPECTRUM_MGMT = 0, ++ WLAN_CATEGORY_QOS = 1, ++ WLAN_CATEGORY_DLS = 2, ++ WLAN_CATEGORY_BACK = 3, ++ WLAN_CATEGORY_HT = 7, ++ WLAN_CATEGORY_WMM = 17, ++}; ++ ++/* SPECTRUM_MGMT action code */ ++enum ieee80211_spectrum_mgmt_actioncode { ++ WLAN_ACTION_SPCT_MSR_REQ = 0, ++ WLAN_ACTION_SPCT_MSR_RPRT = 1, ++ WLAN_ACTION_SPCT_TPC_REQ = 2, ++ WLAN_ACTION_SPCT_TPC_RPRT = 3, ++ WLAN_ACTION_SPCT_CHL_SWITCH = 4, ++ WLAN_ACTION_SPCT_EXT_CHL_SWITCH = 5, ++}; ++ ++/* BACK action code */ ++enum ieee80211_back_actioncode { ++ WLAN_ACTION_ADDBA_REQ = 0, ++ WLAN_ACTION_ADDBA_RESP = 1, ++ WLAN_ACTION_DELBA = 2, ++}; ++ ++/* HT features action code */ ++enum ieee80211_ht_actioncode { ++ WLAN_ACTION_NOTIFY_CH_WIDTH = 0, ++ WLAN_ACTION_SM_PS = 1, ++ WLAN_ACTION_PSPM = 2, ++ WLAN_ACTION_PCO_PHASE = 3, ++ WLAN_ACTION_MIMO_CSI_MX = 4, ++ WLAN_ACTION_MIMO_NONCP_BF = 5, ++ WLAN_ACTION_MIMP_CP_BF = 6, ++ WLAN_ACTION_ASEL_INDICATES_FB = 7, ++ WLAN_ACTION_HI_INFO_EXCHG = 8, ++}; ++ ++/* BACK (block-ack) parties */ ++enum ieee80211_back_parties { ++ WLAN_BACK_RECIPIENT = 0, ++ WLAN_BACK_INITIATOR = 1, ++ WLAN_BACK_TIMER = 2, ++}; ++ ++#ifdef PLATFORM_LINUX ++ ++struct ieee80211_mgmt { ++ u16 frame_control; ++ u16 duration; ++ u8 da[6]; ++ u8 sa[6]; ++ u8 bssid[6]; ++ u16 seq_ctrl; ++ union { ++ struct { ++ u16 auth_alg; ++ u16 auth_transaction; ++ u16 status_code; ++ /* possibly followed by Challenge text */ ++ u8 variable[0]; ++ } __attribute__ ((packed)) auth; ++ struct { ++ u16 reason_code; ++ } __attribute__ ((packed)) deauth; ++ struct { ++ u16 capab_info; ++ u16 listen_interval; ++ /* followed by SSID and Supported rates */ ++ u8 variable[0]; ++ } __attribute__ ((packed)) assoc_req; ++ struct { ++ u16 capab_info; ++ u16 status_code; ++ u16 aid; ++ /* followed by Supported rates */ ++ u8 variable[0]; ++ } __attribute__ ((packed)) assoc_resp, reassoc_resp; ++ struct { ++ u16 capab_info; ++ u16 listen_interval; ++ u8 current_ap[6]; ++ /* followed by SSID and Supported rates */ ++ u8 variable[0]; ++ } __attribute__ ((packed)) reassoc_req; ++ struct { ++ u16 reason_code; ++ } __attribute__ ((packed)) disassoc; ++ struct { ++ __le64 timestamp; ++ u16 beacon_int; ++ u16 capab_info; ++ /* followed by some of SSID, Supported rates, ++ * FH Params, DS Params, CF Params, IBSS Params, TIM */ ++ u8 variable[0]; ++ } __attribute__ ((packed)) beacon; ++ struct { ++ /* only variable items: SSID, Supported rates */ ++ u8 variable[0]; ++ } __attribute__ ((packed)) probe_req; ++ struct { ++ __le64 timestamp; ++ u16 beacon_int; ++ u16 capab_info; ++ /* followed by some of SSID, Supported rates, ++ * FH Params, DS Params, CF Params, IBSS Params */ ++ u8 variable[0]; ++ } __attribute__ ((packed)) probe_resp; ++ struct { ++ u8 category; ++ union { ++ struct { ++ u8 action_code; ++ u8 dialog_token; ++ u8 status_code; ++ u8 variable[0]; ++ } __attribute__ ((packed)) wme_action; ++#if 0 ++ struct{ ++ u8 action_code; ++ u8 element_id; ++ u8 length; ++ struct ieee80211_channel_sw_ie sw_elem; ++ } __attribute__ ((packed)) chan_switch; ++ struct{ ++ u8 action_code; ++ u8 dialog_token; ++ u8 element_id; ++ u8 length; ++ struct ieee80211_msrment_ie msr_elem; ++ } __attribute__ ((packed)) measurement; ++#endif ++ struct{ ++ u8 action_code; ++ u8 dialog_token; ++ u16 capab; ++ u16 timeout; ++ u16 start_seq_num; ++ } __attribute__ ((packed)) addba_req; ++ struct{ ++ u8 action_code; ++ u8 dialog_token; ++ u16 status; ++ u16 capab; ++ u16 timeout; ++ } __attribute__ ((packed)) addba_resp; ++ struct{ ++ u8 action_code; ++ u16 params; ++ u16 reason_code; ++ } __attribute__ ((packed)) delba; ++ struct{ ++ u8 action_code; ++ /* capab_info for open and confirm, ++ * reason for close ++ */ ++ u16 aux; ++ /* Followed in plink_confirm by status ++ * code, AID and supported rates, ++ * and directly by supported rates in ++ * plink_open and plink_close ++ */ ++ u8 variable[0]; ++ } __attribute__ ((packed)) plink_action; ++ struct{ ++ u8 action_code; ++ u8 variable[0]; ++ } __attribute__ ((packed)) mesh_action; ++ } __attribute__ ((packed)) u; ++ } __attribute__ ((packed)) action; ++ } __attribute__ ((packed)) u; ++}__attribute__ ((packed)); ++ ++#endif ++ ++ ++#ifdef PLATFORM_WINDOWS ++ ++#pragma pack(1) ++ ++struct ieee80211_mgmt { ++ u16 frame_control; ++ u16 duration; ++ u8 da[6]; ++ u8 sa[6]; ++ u8 bssid[6]; ++ u16 seq_ctrl; ++ union { ++ struct { ++ u16 auth_alg; ++ u16 auth_transaction; ++ u16 status_code; ++ /* possibly followed by Challenge text */ ++ u8 variable[0]; ++ } auth; ++ struct { ++ u16 reason_code; ++ } deauth; ++ struct { ++ u16 capab_info; ++ u16 listen_interval; ++ /* followed by SSID and Supported rates */ ++ u8 variable[0]; ++ } assoc_req; ++ struct { ++ u16 capab_info; ++ u16 status_code; ++ u16 aid; ++ /* followed by Supported rates */ ++ u8 variable[0]; ++ } assoc_resp, reassoc_resp; ++ struct { ++ u16 capab_info; ++ u16 listen_interval; ++ u8 current_ap[6]; ++ /* followed by SSID and Supported rates */ ++ u8 variable[0]; ++ } reassoc_req; ++ struct { ++ u16 reason_code; ++ } disassoc; ++#if 0 ++ struct { ++ __le64 timestamp; ++ u16 beacon_int; ++ u16 capab_info; ++ /* followed by some of SSID, Supported rates, ++ * FH Params, DS Params, CF Params, IBSS Params, TIM */ ++ u8 variable[0]; ++ } beacon; ++ struct { ++ /* only variable items: SSID, Supported rates */ ++ u8 variable[0]; ++ } probe_req; ++ ++ struct { ++ __le64 timestamp; ++ u16 beacon_int; ++ u16 capab_info; ++ /* followed by some of SSID, Supported rates, ++ * FH Params, DS Params, CF Params, IBSS Params */ ++ u8 variable[0]; ++ } probe_resp; ++#endif ++ struct { ++ u8 category; ++ union { ++ struct { ++ u8 action_code; ++ u8 dialog_token; ++ u8 status_code; ++ u8 variable[0]; ++ } wme_action; ++/* ++ struct{ ++ u8 action_code; ++ u8 element_id; ++ u8 length; ++ struct ieee80211_channel_sw_ie sw_elem; ++ } chan_switch; ++ struct{ ++ u8 action_code; ++ u8 dialog_token; ++ u8 element_id; ++ u8 length; ++ struct ieee80211_msrment_ie msr_elem; ++ } measurement; ++*/ ++ struct{ ++ u8 action_code; ++ u8 dialog_token; ++ u16 capab; ++ u16 timeout; ++ u16 start_seq_num; ++ } addba_req; ++ struct{ ++ u8 action_code; ++ u8 dialog_token; ++ u16 status; ++ u16 capab; ++ u16 timeout; ++ } addba_resp; ++ struct{ ++ u8 action_code; ++ u16 params; ++ u16 reason_code; ++ } delba; ++ struct{ ++ u8 action_code; ++ /* capab_info for open and confirm, ++ * reason for close ++ */ ++ u16 aux; ++ /* Followed in plink_confirm by status ++ * code, AID and supported rates, ++ * and directly by supported rates in ++ * plink_open and plink_close ++ */ ++ u8 variable[0]; ++ } plink_action; ++ struct{ ++ u8 action_code; ++ u8 variable[0]; ++ } mesh_action; ++ } u; ++ } action; ++ } u; ++} ; ++ ++#pragma pack() ++ ++#endif ++ ++/* mgmt header + 1 byte category code */ ++#define IEEE80211_MIN_ACTION_SIZE FIELD_OFFSET(struct ieee80211_mgmt, u.action.u) ++ ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/if_ether.h b/drivers/net/wireless/rtl818x/rtl8189/include/if_ether.h +new file mode 100644 +index 00000000..93ed096d +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/if_ether.h +@@ -0,0 +1,113 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#ifndef _LINUX_IF_ETHER_H ++#define _LINUX_IF_ETHER_H ++ ++/* ++ * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble ++ * and FCS/CRC (frame check sequence). ++ */ ++ ++#define ETH_ALEN 6 /* Octets in one ethernet addr */ ++#define ETH_HLEN 14 /* Total octets in header. */ ++#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ ++#define ETH_DATA_LEN 1500 /* Max. octets in payload */ ++#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ ++ ++/* ++ * These are the defined Ethernet Protocol ID's. ++ */ ++ ++#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */ ++#define ETH_P_PUP 0x0200 /* Xerox PUP packet */ ++#define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */ ++#define ETH_P_IP 0x0800 /* Internet Protocol packet */ ++#define ETH_P_X25 0x0805 /* CCITT X.25 */ ++#define ETH_P_ARP 0x0806 /* Address Resolution packet */ ++#define ETH_P_BPQ 0x08FF /* G8BPQ AX.25 Ethernet Packet [ NOT AN OFFICIALLY REGISTERED ID ] */ ++#define ETH_P_IEEEPUP 0x0a00 /* Xerox IEEE802.3 PUP packet */ ++#define ETH_P_IEEEPUPAT 0x0a01 /* Xerox IEEE802.3 PUP Addr Trans packet */ ++#define ETH_P_DEC 0x6000 /* DEC Assigned proto */ ++#define ETH_P_DNA_DL 0x6001 /* DEC DNA Dump/Load */ ++#define ETH_P_DNA_RC 0x6002 /* DEC DNA Remote Console */ ++#define ETH_P_DNA_RT 0x6003 /* DEC DNA Routing */ ++#define ETH_P_LAT 0x6004 /* DEC LAT */ ++#define ETH_P_DIAG 0x6005 /* DEC Diagnostics */ ++#define ETH_P_CUST 0x6006 /* DEC Customer use */ ++#define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */ ++#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ ++#define ETH_P_ATALK 0x809B /* Appletalk DDP */ ++#define ETH_P_AARP 0x80F3 /* Appletalk AARP */ ++#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */ ++#define ETH_P_IPX 0x8137 /* IPX over DIX */ ++#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ ++#define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */ ++#define ETH_P_PPP_SES 0x8864 /* PPPoE session messages */ ++#define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */ ++#define ETH_P_ATMFATE 0x8884 /* Frame-based ATM Transport ++ * over Ethernet ++ */ ++ ++/* ++ * Non DIX types. Won't clash for 1500 types. ++ */ ++ ++#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */ ++#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ ++#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ ++#define ETH_P_802_2 0x0004 /* 802.2 frames */ ++#define ETH_P_SNAP 0x0005 /* Internal only */ ++#define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */ ++#define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/ ++#define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */ ++#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */ ++#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/ ++#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */ ++#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */ ++#define ETH_P_CONTROL 0x0016 /* Card specific control frames */ ++#define ETH_P_IRDA 0x0017 /* Linux-IrDA */ ++#define ETH_P_ECONET 0x0018 /* Acorn Econet */ ++ ++/* ++ * This is an Ethernet frame header. ++ */ ++ ++struct ethhdr ++{ ++ unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ ++ unsigned char h_source[ETH_ALEN]; /* source ether addr */ ++ unsigned short h_proto; /* packet type ID field */ ++}; ++ ++struct _vlan { ++ unsigned short h_vlan_TCI; // Encapsulates priority and VLAN ID ++ unsigned short h_vlan_encapsulated_proto; ++}; ++ ++ ++ ++#define get_vlan_id(pvlan) ((ntohs((unsigned short )pvlan->h_vlan_TCI)) & 0xfff) ++#define get_vlan_priority(pvlan) ((ntohs((unsigned short )pvlan->h_vlan_TCI))>>13) ++#define get_vlan_encap_proto(pvlan) (ntohs((unsigned short )pvlan->h_vlan_encapsulated_proto)) ++ ++ ++#endif /* _LINUX_IF_ETHER_H */ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/ioctl_cfg80211.h b/drivers/net/wireless/rtl818x/rtl8189/include/ioctl_cfg80211.h +new file mode 100644 +index 00000000..88647e84 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/ioctl_cfg80211.h +@@ -0,0 +1,176 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __IOCTL_CFG80211_H__ ++#define __IOCTL_CFG80211_H__ ++ ++ ++#if defined(RTW_USE_CFG80211_STA_EVENT) ++ #undef CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER ++#endif ++ ++struct rtw_wdev_invit_info { ++ u8 state; /* 0: req, 1:rep */ ++ u8 peer_mac[ETH_ALEN]; ++ u8 active; ++ u8 token; ++ u8 flags; ++ u8 status; ++ u8 req_op_ch; ++ u8 rsp_op_ch; ++}; ++ ++#define rtw_wdev_invit_info_init(invit_info) \ ++ do { \ ++ (invit_info)->state = 0xff; \ ++ _rtw_memset((invit_info)->peer_mac, 0, ETH_ALEN); \ ++ (invit_info)->active = 0xff; \ ++ (invit_info)->token = 0; \ ++ (invit_info)->flags = 0x00; \ ++ (invit_info)->status = 0xff; \ ++ (invit_info)->req_op_ch = 0; \ ++ (invit_info)->rsp_op_ch = 0; \ ++ } while (0) ++ ++struct rtw_wdev_nego_info { ++ u8 state; /* 0: req, 1:rep, 3:conf */ ++ u8 peer_mac[ETH_ALEN]; ++ u8 active; ++ u8 token; ++ u8 status; ++ u8 req_intent; ++ u8 req_op_ch; ++ u8 req_listen_ch; ++ u8 rsp_intent; ++ u8 rsp_op_ch; ++ u8 conf_op_ch; ++}; ++ ++#define rtw_wdev_nego_info_init(nego_info) \ ++ do { \ ++ (nego_info)->state = 0xff; \ ++ _rtw_memset((nego_info)->peer_mac, 0, ETH_ALEN); \ ++ (nego_info)->active = 0xff; \ ++ (nego_info)->token = 0; \ ++ (nego_info)->status = 0xff; \ ++ (nego_info)->req_intent = 0xff; \ ++ (nego_info)->req_op_ch = 0; \ ++ (nego_info)->req_listen_ch = 0; \ ++ (nego_info)->rsp_intent = 0xff; \ ++ (nego_info)->rsp_op_ch = 0; \ ++ (nego_info)->conf_op_ch = 0; \ ++ } while (0) ++ ++struct rtw_wdev_priv ++{ ++ struct wireless_dev *rtw_wdev; ++ ++ _adapter *padapter; ++ ++ struct cfg80211_scan_request *scan_request; ++ _lock scan_req_lock; ++ ++ struct net_device *pmon_ndev;//for monitor interface ++ char ifname_mon[IFNAMSIZ + 1]; //interface name for monitor interface ++ ++ u8 p2p_enabled; ++ ++ u8 provdisc_req_issued; ++ ++ struct rtw_wdev_invit_info invit_info; ++ struct rtw_wdev_nego_info nego_info; ++ ++ u8 bandroid_scan; ++ bool block; ++ bool power_mgmt; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ ATOMIC_T ro_ch_to; ++ ATOMIC_T switch_ch_to; ++#endif ++ ++}; ++ ++#define wdev_to_priv(w) ((struct rtw_wdev_priv *)(wdev_priv(w))) ++ ++#define wiphy_to_adapter(x) (_adapter *)(((struct rtw_wdev_priv*)wiphy_priv(x))->padapter) ++ ++#define wiphy_to_wdev(x) (struct wireless_dev *)(((struct rtw_wdev_priv*)wiphy_priv(x))->rtw_wdev) ++ ++int rtw_wdev_alloc(_adapter *padapter, struct device *dev); ++void rtw_wdev_free(struct wireless_dev *wdev); ++void rtw_wdev_unregister(struct wireless_dev *wdev); ++ ++void rtw_cfg80211_init_wiphy(_adapter *padapter); ++ ++void rtw_cfg80211_surveydone_event_callback(_adapter *padapter); ++struct cfg80211_bss *rtw_cfg80211_inform_bss(_adapter *padapter, struct wlan_network *pnetwork); ++int rtw_cfg80211_check_bss(_adapter *padapter); ++void rtw_cfg80211_ibss_indicate_connect(_adapter *padapter); ++void rtw_cfg80211_indicate_connect(_adapter *padapter); ++void rtw_cfg80211_indicate_disconnect(_adapter *padapter); ++void rtw_cfg80211_indicate_scan_done(struct rtw_wdev_priv *pwdev_priv, bool aborted); ++ ++#ifdef CONFIG_AP_MODE ++void rtw_cfg80211_indicate_sta_assoc(_adapter *padapter, u8 *pmgmt_frame, uint frame_len); ++void rtw_cfg80211_indicate_sta_disassoc(_adapter *padapter, unsigned char *da, unsigned short reason); ++#endif //CONFIG_AP_MODE ++ ++void rtw_cfg80211_issue_p2p_provision_request(_adapter *padapter, const u8 *buf, size_t len); ++void rtw_cfg80211_rx_p2p_action_public(_adapter *padapter, u8 *pmgmt_frame, uint frame_len); ++void rtw_cfg80211_rx_action_p2p(_adapter *padapter, u8 *pmgmt_frame, uint frame_len); ++void rtw_cfg80211_rx_action(_adapter *adapter, u8 *frame, uint frame_len, const char*msg); ++ ++int rtw_cfg80211_set_mgnt_wpsp2pie(struct net_device *net, char *buf, int len, int type); ++ ++bool rtw_cfg80211_pwr_mgmt(_adapter *adapter); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) && !defined(COMPAT_KERNEL_RELEASE) ++#define rtw_cfg80211_rx_mgmt(adapter, freq, sig_dbm, buf, len, gfp) cfg80211_rx_mgmt((adapter)->pnetdev, freq, buf, len, gfp) ++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) ++#define rtw_cfg80211_rx_mgmt(adapter, freq, sig_dbm, buf, len, gfp) cfg80211_rx_mgmt((adapter)->pnetdev, freq, sig_dbm, buf, len, gfp) ++#else ++#define rtw_cfg80211_rx_mgmt(adapter, freq, sig_dbm, buf, len, gfp) cfg80211_rx_mgmt((adapter)->rtw_wdev, freq, sig_dbm, buf, len, gfp) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) && !defined(COMPAT_KERNEL_RELEASE) ++#define rtw_cfg80211_send_rx_assoc(adapter, bss, buf, len) cfg80211_send_rx_assoc((adapter)->pnetdev, buf, len) ++#else ++#define rtw_cfg80211_send_rx_assoc(adapter, bss, buf, len) cfg80211_send_rx_assoc((adapter)->pnetdev, bss, buf, len) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) ++#define rtw_cfg80211_mgmt_tx_status(adapter, cookie, buf, len, ack, gfp) cfg80211_mgmt_tx_status((adapter)->pnetdev, cookie, buf, len, ack, gfp) ++#else ++#define rtw_cfg80211_mgmt_tx_status(adapter, cookie, buf, len, ack, gfp) cfg80211_mgmt_tx_status((adapter)->rtw_wdev, cookie, buf, len, ack, gfp) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) ++#define rtw_cfg80211_ready_on_channel(adapter, cookie, chan, channel_type, duration, gfp) cfg80211_ready_on_channel((adapter)->pnetdev, cookie, chan, channel_type, duration, gfp) ++#define rtw_cfg80211_remain_on_channel_expired(adapter, cookie, chan, chan_type, gfp) cfg80211_remain_on_channel_expired((adapter)->pnetdev, cookie, chan, chan_type, gfp) ++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)) ++#define rtw_cfg80211_ready_on_channel(adapter, cookie, chan, channel_type, duration, gfp) cfg80211_ready_on_channel((adapter)->rtw_wdev, cookie, chan, channel_type, duration, gfp) ++#define rtw_cfg80211_remain_on_channel_expired(adapter, cookie, chan, chan_type, gfp) cfg80211_remain_on_channel_expired((adapter)->rtw_wdev, cookie, chan, chan_type, gfp) ++#else ++#define rtw_cfg80211_ready_on_channel(adapter, cookie, chan, channel_type, duration, gfp) cfg80211_ready_on_channel((adapter)->rtw_wdev, cookie, chan, duration, gfp) ++#define rtw_cfg80211_remain_on_channel_expired(adapter, cookie, chan, chan_type, gfp) cfg80211_remain_on_channel_expired((adapter)->rtw_wdev, cookie, chan, gfp) ++#endif ++ ++#endif //__IOCTL_CFG80211_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/ip.h b/drivers/net/wireless/rtl818x/rtl8189/include/ip.h +new file mode 100644 +index 00000000..db079bc7 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/ip.h +@@ -0,0 +1,142 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _LINUX_IP_H ++#define _LINUX_IP_H ++#include ++ ++/* SOL_IP socket options */ ++ ++#define IPTOS_TOS_MASK 0x1E ++#define IPTOS_TOS(tos) ((tos)&IPTOS_TOS_MASK) ++#define IPTOS_LOWDELAY 0x10 ++#define IPTOS_THROUGHPUT 0x08 ++#define IPTOS_RELIABILITY 0x04 ++#define IPTOS_MINCOST 0x02 ++ ++#define IPTOS_PREC_MASK 0xE0 ++#define IPTOS_PREC(tos) ((tos)&IPTOS_PREC_MASK) ++#define IPTOS_PREC_NETCONTROL 0xe0 ++#define IPTOS_PREC_INTERNETCONTROL 0xc0 ++#define IPTOS_PREC_CRITIC_ECP 0xa0 ++#define IPTOS_PREC_FLASHOVERRIDE 0x80 ++#define IPTOS_PREC_FLASH 0x60 ++#define IPTOS_PREC_IMMEDIATE 0x40 ++#define IPTOS_PREC_PRIORITY 0x20 ++#define IPTOS_PREC_ROUTINE 0x00 ++ ++ ++/* IP options */ ++#define IPOPT_COPY 0x80 ++#define IPOPT_CLASS_MASK 0x60 ++#define IPOPT_NUMBER_MASK 0x1f ++ ++#define IPOPT_COPIED(o) ((o)&IPOPT_COPY) ++#define IPOPT_CLASS(o) ((o)&IPOPT_CLASS_MASK) ++#define IPOPT_NUMBER(o) ((o)&IPOPT_NUMBER_MASK) ++ ++#define IPOPT_CONTROL 0x00 ++#define IPOPT_RESERVED1 0x20 ++#define IPOPT_MEASUREMENT 0x40 ++#define IPOPT_RESERVED2 0x60 ++ ++#define IPOPT_END (0 |IPOPT_CONTROL) ++#define IPOPT_NOOP (1 |IPOPT_CONTROL) ++#define IPOPT_SEC (2 |IPOPT_CONTROL|IPOPT_COPY) ++#define IPOPT_LSRR (3 |IPOPT_CONTROL|IPOPT_COPY) ++#define IPOPT_TIMESTAMP (4 |IPOPT_MEASUREMENT) ++#define IPOPT_RR (7 |IPOPT_CONTROL) ++#define IPOPT_SID (8 |IPOPT_CONTROL|IPOPT_COPY) ++#define IPOPT_SSRR (9 |IPOPT_CONTROL|IPOPT_COPY) ++#define IPOPT_RA (20|IPOPT_CONTROL|IPOPT_COPY) ++ ++#define IPVERSION 4 ++#define MAXTTL 255 ++#define IPDEFTTL 64 ++ ++/* struct timestamp, struct route and MAX_ROUTES are removed. ++ ++ REASONS: it is clear that nobody used them because: ++ - MAX_ROUTES value was wrong. ++ - "struct route" was wrong. ++ - "struct timestamp" had fatally misaligned bitfields and was completely unusable. ++ */ ++ ++#define IPOPT_OPTVAL 0 ++#define IPOPT_OLEN 1 ++#define IPOPT_OFFSET 2 ++#define IPOPT_MINOFF 4 ++#define MAX_IPOPTLEN 40 ++#define IPOPT_NOP IPOPT_NOOP ++#define IPOPT_EOL IPOPT_END ++#define IPOPT_TS IPOPT_TIMESTAMP ++ ++#define IPOPT_TS_TSONLY 0 /* timestamps only */ ++#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ ++#define IPOPT_TS_PRESPEC 3 /* specified modules only */ ++ ++#ifdef PLATFORM_LINUX ++ ++struct ip_options { ++ __u32 faddr; /* Saved first hop address */ ++ unsigned char optlen; ++ unsigned char srr; ++ unsigned char rr; ++ unsigned char ts; ++ unsigned char is_setbyuser:1, /* Set by setsockopt? */ ++ is_data:1, /* Options in __data, rather than skb */ ++ is_strictroute:1, /* Strict source route */ ++ srr_is_hit:1, /* Packet destination addr was our one */ ++ is_changed:1, /* IP checksum more not valid */ ++ rr_needaddr:1, /* Need to record addr of outgoing dev */ ++ ts_needtime:1, /* Need to record timestamp */ ++ ts_needaddr:1; /* Need to record addr of outgoing dev */ ++ unsigned char router_alert; ++ unsigned char __pad1; ++ unsigned char __pad2; ++ unsigned char __data[0]; ++}; ++ ++#define optlength(opt) (sizeof(struct ip_options) + opt->optlen) ++#endif ++ ++struct iphdr { ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u8 ihl:4, ++ version:4; ++#elif defined (__BIG_ENDIAN_BITFIELD) ++ __u8 version:4, ++ ihl:4; ++#else ++#error "Please fix " ++#endif ++ __u8 tos; ++ __u16 tot_len; ++ __u16 id; ++ __u16 frag_off; ++ __u8 ttl; ++ __u8 protocol; ++ __u16 check; ++ __u32 saddr; ++ __u32 daddr; ++ /*The options start here. */ ++}; ++ ++#endif /* _LINUX_IP_H */ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/linux/wireless.h b/drivers/net/wireless/rtl818x/rtl8189/include/linux/wireless.h +new file mode 100644 +index 00000000..955ea8d3 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/linux/wireless.h +@@ -0,0 +1,91 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#ifndef _LINUX_WIRELESS_H ++#define _LINUX_WIRELESS_H ++ ++/***************************** INCLUDES *****************************/ ++ ++#if 0 ++#include /* for __u* and __s* typedefs */ ++#include /* for "struct sockaddr" et al */ ++#include /* for IFNAMSIZ and co... */ ++#else ++#define __user ++//typedef uint16_t __u16; ++#include /* for "struct sockaddr" et al */ ++#include /* for IFNAMSIZ and co... */ ++#endif ++ ++/****************************** TYPES ******************************/ ++ ++/* --------------------------- SUBTYPES --------------------------- */ ++/* ++ * For all data larger than 16 octets, we need to use a ++ * pointer to memory allocated in user space. ++ */ ++struct iw_point ++{ ++ void __user *pointer; /* Pointer to the data (in user space) */ ++ __u16 length; /* number of fields or size in bytes */ ++ __u16 flags; /* Optional params */ ++}; ++ ++ ++/* ------------------------ IOCTL REQUEST ------------------------ */ ++/* ++ * This structure defines the payload of an ioctl, and is used ++ * below. ++ * ++ * Note that this structure should fit on the memory footprint ++ * of iwreq (which is the same as ifreq), which mean a max size of ++ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... ++ * You should check this when increasing the structures defined ++ * above in this file... ++ */ ++union iwreq_data ++{ ++ /* Config - generic */ ++ char name[IFNAMSIZ]; ++ /* Name : used to verify the presence of wireless extensions. ++ * Name of the protocol/provider... */ ++ ++ struct iw_point data; /* Other large parameters */ ++}; ++ ++/* ++ * The structure to exchange data for ioctl. ++ * This structure is the same as 'struct ifreq', but (re)defined for ++ * convenience... ++ * Do I need to remind you about structure size (32 octets) ? ++ */ ++struct iwreq ++{ ++ union ++ { ++ char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */ ++ } ifr_ifrn; ++ ++ /* Data part (defined just above) */ ++ union iwreq_data u; ++}; ++ ++#endif /* _LINUX_WIRELESS_H */ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/mlme_osdep.h b/drivers/net/wireless/rtl818x/rtl8189/include/mlme_osdep.h +new file mode 100644 +index 00000000..75754db1 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/mlme_osdep.h +@@ -0,0 +1,40 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __MLME_OSDEP_H_ ++#define __MLME_OSDEP_H_ ++ ++#include ++#include ++#include ++ ++#if defined(PLATFORM_WINDOWS) || defined(PLATFORM_MPIXEL) ++extern int time_after(u32 now, u32 old); ++#endif ++ ++extern void rtw_init_mlme_timer(_adapter *padapter); ++extern void rtw_os_indicate_disconnect( _adapter *adapter ); ++extern void rtw_os_indicate_connect( _adapter *adapter ); ++void rtw_os_indicate_scan_done( _adapter *padapter, bool aborted); ++extern void rtw_report_sec_ie(_adapter *adapter,u8 authmode,u8 *sec_ie); ++ ++void rtw_reset_securitypriv( _adapter *adapter ); ++ ++#endif //_MLME_OSDEP_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/mp_custom_oid.h b/drivers/net/wireless/rtl818x/rtl8189/include/mp_custom_oid.h +new file mode 100644 +index 00000000..9cf1c827 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/mp_custom_oid.h +@@ -0,0 +1,354 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __CUSTOM_OID_H ++#define __CUSTOM_OID_H ++ ++// by Owen ++// 0xFF818000 - 0xFF81802F RTL8180 Mass Production Kit ++// 0xFF818500 - 0xFF81850F RTL8185 Setup Utility ++// 0xFF818580 - 0xFF81858F RTL8185 Phy Status Utility ++ ++// ++ ++// by Owen for Production Kit ++// For Production Kit with Agilent Equipments ++// in order to make our custom oids hopefully somewhat unique ++// we will use 0xFF (indicating implementation specific OID) ++// 81(first byte of non zero Realtek unique identifier) ++// 80 (second byte of non zero Realtek unique identifier) ++// XX (the custom OID number - providing 255 possible custom oids) ++ ++#define OID_RT_PRO_RESET_DUT 0xFF818000 ++#define OID_RT_PRO_SET_DATA_RATE 0xFF818001 ++#define OID_RT_PRO_START_TEST 0xFF818002 ++#define OID_RT_PRO_STOP_TEST 0xFF818003 ++#define OID_RT_PRO_SET_PREAMBLE 0xFF818004 ++#define OID_RT_PRO_SET_SCRAMBLER 0xFF818005 ++#define OID_RT_PRO_SET_FILTER_BB 0xFF818006 ++#define OID_RT_PRO_SET_MANUAL_DIVERSITY_BB 0xFF818007 ++#define OID_RT_PRO_SET_CHANNEL_DIRECT_CALL 0xFF818008 ++#define OID_RT_PRO_SET_SLEEP_MODE_DIRECT_CALL 0xFF818009 ++#define OID_RT_PRO_SET_WAKE_MODE_DIRECT_CALL 0xFF81800A ++ ++#define OID_RT_PRO_SET_TX_ANTENNA_BB 0xFF81800D ++#define OID_RT_PRO_SET_ANTENNA_BB 0xFF81800E ++#define OID_RT_PRO_SET_CR_SCRAMBLER 0xFF81800F ++#define OID_RT_PRO_SET_CR_NEW_FILTER 0xFF818010 ++#define OID_RT_PRO_SET_TX_POWER_CONTROL 0xFF818011 ++#define OID_RT_PRO_SET_CR_TX_CONFIG 0xFF818012 ++#define OID_RT_PRO_GET_TX_POWER_CONTROL 0xFF818013 ++#define OID_RT_PRO_GET_CR_SIGNAL_QUALITY 0xFF818014 ++#define OID_RT_PRO_SET_CR_SETPOINT 0xFF818015 ++#define OID_RT_PRO_SET_INTEGRATOR 0xFF818016 ++#define OID_RT_PRO_SET_SIGNAL_QUALITY 0xFF818017 ++#define OID_RT_PRO_GET_INTEGRATOR 0xFF818018 ++#define OID_RT_PRO_GET_SIGNAL_QUALITY 0xFF818019 ++#define OID_RT_PRO_QUERY_EEPROM_TYPE 0xFF81801A ++#define OID_RT_PRO_WRITE_MAC_ADDRESS 0xFF81801B ++#define OID_RT_PRO_READ_MAC_ADDRESS 0xFF81801C ++#define OID_RT_PRO_WRITE_CIS_DATA 0xFF81801D ++#define OID_RT_PRO_READ_CIS_DATA 0xFF81801E ++#define OID_RT_PRO_WRITE_POWER_CONTROL 0xFF81801F ++#define OID_RT_PRO_READ_POWER_CONTROL 0xFF818020 ++#define OID_RT_PRO_WRITE_EEPROM 0xFF818021 ++#define OID_RT_PRO_READ_EEPROM 0xFF818022 ++#define OID_RT_PRO_RESET_TX_PACKET_SENT 0xFF818023 ++#define OID_RT_PRO_QUERY_TX_PACKET_SENT 0xFF818024 ++#define OID_RT_PRO_RESET_RX_PACKET_RECEIVED 0xFF818025 ++#define OID_RT_PRO_QUERY_RX_PACKET_RECEIVED 0xFF818026 ++#define OID_RT_PRO_QUERY_RX_PACKET_CRC32_ERROR 0xFF818027 ++#define OID_RT_PRO_QUERY_CURRENT_ADDRESS 0xFF818028 ++#define OID_RT_PRO_QUERY_PERMANENT_ADDRESS 0xFF818029 ++#define OID_RT_PRO_SET_PHILIPS_RF_PARAMETERS 0xFF81802A ++#define OID_RT_PRO_RECEIVE_PACKET 0xFF81802C ++// added by Owen on 04/08/03 for Cameo's request ++#define OID_RT_PRO_WRITE_EEPROM_BYTE 0xFF81802D ++#define OID_RT_PRO_READ_EEPROM_BYTE 0xFF81802E ++#define OID_RT_PRO_SET_MODULATION 0xFF81802F ++// ++ ++//Sean ++#define OID_RT_DRIVER_OPTION 0xFF818080 ++#define OID_RT_RF_OFF 0xFF818081 ++#define OID_RT_AUTH_STATUS 0xFF818082 ++ ++//======================================================================== ++#define OID_RT_PRO_SET_CONTINUOUS_TX 0xFF81800B ++#define OID_RT_PRO_SET_SINGLE_CARRIER_TX 0xFF81800C ++#define OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX 0xFF81802B ++#define OID_RT_PRO_SET_SINGLE_TONE_TX 0xFF818043 ++//======================================================================== ++ ++ ++// by Owen for RTL8185 Phy Status Report Utility ++#define OID_RT_UTILITY_FALSE_ALARM_COUNTERS 0xFF818580 ++#define OID_RT_UTILITY_SELECT_DEBUG_MODE 0xFF818581 ++#define OID_RT_UTILITY_SELECT_SUBCARRIER_NUMBER 0xFF818582 ++#define OID_RT_UTILITY_GET_RSSI_STATUS 0xFF818583 ++#define OID_RT_UTILITY_GET_FRAME_DETECTION_STATUS 0xFF818584 ++#define OID_RT_UTILITY_GET_AGC_AND_FREQUENCY_OFFSET_ESTIMATION_STATUS 0xFF818585 ++#define OID_RT_UTILITY_GET_CHANNEL_ESTIMATION_STATUS 0xFF818586 ++// ++ ++// by Owen on 03/09/19-03/09/22 for RTL8185 ++#define OID_RT_WIRELESS_MODE 0xFF818500 ++#define OID_RT_SUPPORTED_RATES 0xFF818501 ++#define OID_RT_DESIRED_RATES 0xFF818502 ++#define OID_RT_WIRELESS_MODE_STARTING_ADHOC 0xFF818503 ++// ++ ++#define OID_RT_GET_CONNECT_STATE 0xFF030001 ++#define OID_RT_RESCAN 0xFF030002 ++#define OID_RT_SET_KEY_LENGTH 0xFF030003 ++#define OID_RT_SET_DEFAULT_KEY_ID 0xFF030004 ++ ++#define OID_RT_SET_CHANNEL 0xFF010182 ++#define OID_RT_SET_SNIFFER_MODE 0xFF010183 ++#define OID_RT_GET_SIGNAL_QUALITY 0xFF010184 ++#define OID_RT_GET_SMALL_PACKET_CRC 0xFF010185 ++#define OID_RT_GET_MIDDLE_PACKET_CRC 0xFF010186 ++#define OID_RT_GET_LARGE_PACKET_CRC 0xFF010187 ++#define OID_RT_GET_TX_RETRY 0xFF010188 ++#define OID_RT_GET_RX_RETRY 0xFF010189 ++#define OID_RT_PRO_SET_FW_DIG_STATE 0xFF01018A//S ++#define OID_RT_PRO_SET_FW_RA_STATE 0xFF01018B//S ++ ++#define OID_RT_GET_RX_TOTAL_PACKET 0xFF010190 ++#define OID_RT_GET_TX_BEACON_OK 0xFF010191 ++#define OID_RT_GET_TX_BEACON_ERR 0xFF010192 ++#define OID_RT_GET_RX_ICV_ERR 0xFF010193 ++#define OID_RT_SET_ENCRYPTION_ALGORITHM 0xFF010194 ++#define OID_RT_SET_NO_AUTO_RESCAN 0xFF010195 ++#define OID_RT_GET_PREAMBLE_MODE 0xFF010196 ++#define OID_RT_GET_DRIVER_UP_DELTA_TIME 0xFF010197 ++#define OID_RT_GET_AP_IP 0xFF010198 ++#define OID_RT_GET_CHANNELPLAN 0xFF010199 ++#define OID_RT_SET_PREAMBLE_MODE 0xFF01019A ++#define OID_RT_SET_BCN_INTVL 0xFF01019B ++#define OID_RT_GET_RF_VENDER 0xFF01019C ++#define OID_RT_DEDICATE_PROBE 0xFF01019D ++#define OID_RT_PRO_RX_FILTER_PATTERN 0xFF01019E ++ ++#define OID_RT_GET_DCST_CURRENT_THRESHOLD 0xFF01019F ++ ++#define OID_RT_GET_CCA_ERR 0xFF0101A0 ++#define OID_RT_GET_CCA_UPGRADE_THRESHOLD 0xFF0101A1 ++#define OID_RT_GET_CCA_FALLBACK_THRESHOLD 0xFF0101A2 ++ ++#define OID_RT_GET_CCA_UPGRADE_EVALUATE_TIMES 0xFF0101A3 ++#define OID_RT_GET_CCA_FALLBACK_EVALUATE_TIMES 0xFF0101A4 ++ ++// by Owen on 03/31/03 for Cameo's request ++#define OID_RT_SET_RATE_ADAPTIVE 0xFF0101A5 ++// ++#define OID_RT_GET_DCST_EVALUATE_PERIOD 0xFF0101A5 ++#define OID_RT_GET_DCST_TIME_UNIT_INDEX 0xFF0101A6 ++#define OID_RT_GET_TOTAL_TX_BYTES 0xFF0101A7 ++#define OID_RT_GET_TOTAL_RX_BYTES 0xFF0101A8 ++#define OID_RT_CURRENT_TX_POWER_LEVEL 0xFF0101A9 ++#define OID_RT_GET_ENC_KEY_MISMATCH_COUNT 0xFF0101AA ++#define OID_RT_GET_ENC_KEY_MATCH_COUNT 0xFF0101AB ++#define OID_RT_GET_CHANNEL 0xFF0101AC ++ ++#define OID_RT_SET_CHANNELPLAN 0xFF0101AD ++#define OID_RT_GET_HARDWARE_RADIO_OFF 0xFF0101AE ++#define OID_RT_CHANNELPLAN_BY_COUNTRY 0xFF0101AF ++#define OID_RT_SCAN_AVAILABLE_BSSID 0xFF0101B0 ++#define OID_RT_GET_HARDWARE_VERSION 0xFF0101B1 ++#define OID_RT_GET_IS_ROAMING 0xFF0101B2 ++#define OID_RT_GET_IS_PRIVACY 0xFF0101B3 ++#define OID_RT_GET_KEY_MISMATCH 0xFF0101B4 ++#define OID_RT_SET_RSSI_ROAM_TRAFFIC_TH 0xFF0101B5 ++#define OID_RT_SET_RSSI_ROAM_SIGNAL_TH 0xFF0101B6 ++#define OID_RT_RESET_LOG 0xFF0101B7 ++#define OID_RT_GET_LOG 0xFF0101B8 ++#define OID_RT_SET_INDICATE_HIDDEN_AP 0xFF0101B9 ++#define OID_RT_GET_HEADER_FAIL 0xFF0101BA ++#define OID_RT_SUPPORTED_WIRELESS_MODE 0xFF0101BB ++#define OID_RT_GET_CHANNEL_LIST 0xFF0101BC ++#define OID_RT_GET_SCAN_IN_PROGRESS 0xFF0101BD ++#define OID_RT_GET_TX_INFO 0xFF0101BE ++#define OID_RT_RF_READ_WRITE_OFFSET 0xFF0101BF ++#define OID_RT_RF_READ_WRITE 0xFF0101C0 ++ ++// For Netgear request. 2005.01.13, by rcnjko. ++#define OID_RT_FORCED_DATA_RATE 0xFF0101C1 ++#define OID_RT_WIRELESS_MODE_FOR_SCAN_LIST 0xFF0101C2 ++// For Netgear request. 2005.02.17, by rcnjko. ++#define OID_RT_GET_BSS_WIRELESS_MODE 0xFF0101C3 ++// For AZ project. 2005.06.27, by rcnjko. ++#define OID_RT_SCAN_WITH_MAGIC_PACKET 0xFF0101C4 ++ ++// Vincent 8185MP ++#define OID_RT_PRO_RX_FILTER 0xFF0111C0 ++ ++//Andy TEST ++//#define OID_RT_PRO_WRITE_REGISTRY 0xFF0111C1 ++//#define OID_RT_PRO_READ_REGISTRY 0xFF0111C2 ++#define OID_CE_USB_WRITE_REGISTRY 0xFF0111C1 ++#define OID_CE_USB_READ_REGISTRY 0xFF0111C2 ++ ++ ++#define OID_RT_PRO_SET_INITIAL_GAIN 0xFF0111C3 ++#define OID_RT_PRO_SET_BB_RF_STANDBY_MODE 0xFF0111C4 ++#define OID_RT_PRO_SET_BB_RF_SHUTDOWN_MODE 0xFF0111C5 ++#define OID_RT_PRO_SET_TX_CHARGE_PUMP 0xFF0111C6 ++#define OID_RT_PRO_SET_RX_CHARGE_PUMP 0xFF0111C7 ++#define OID_RT_PRO_RF_WRITE_REGISTRY 0xFF0111C8 ++#define OID_RT_PRO_RF_READ_REGISTRY 0xFF0111C9 ++#define OID_RT_PRO_QUERY_RF_TYPE 0xFF0111CA ++ ++// AP OID ++#define OID_RT_AP_GET_ASSOCIATED_STATION_LIST 0xFF010300 ++#define OID_RT_AP_GET_CURRENT_TIME_STAMP 0xFF010301 ++#define OID_RT_AP_SWITCH_INTO_AP_MODE 0xFF010302 ++#define OID_RT_AP_SET_DTIM_PERIOD 0xFF010303 ++#define OID_RT_AP_SUPPORTED 0xFF010304 // Determine if driver supports AP mode. 2004.08.27, by rcnjko. ++#define OID_RT_AP_SET_PASSPHRASE 0xFF010305 // Set WPA-PSK passphrase into authenticator. 2005.07.08, byrcnjko. ++ ++// 8187MP. 2004.09.06, by rcnjko. ++#define OID_RT_PRO8187_WI_POLL 0xFF818780 ++#define OID_RT_PRO_WRITE_BB_REG 0xFF818781 ++#define OID_RT_PRO_READ_BB_REG 0xFF818782 ++#define OID_RT_PRO_WRITE_RF_REG 0xFF818783 ++#define OID_RT_PRO_READ_RF_REG 0xFF818784 ++ ++// Meeting House. added by Annie, 2005-07-20. ++#define OID_RT_MH_VENDER_ID 0xFFEDC100 ++ ++//8711 MP OID added 20051230. ++#define OID_RT_PRO8711_JOIN_BSS 0xFF871100//S ++ ++#define OID_RT_PRO_READ_REGISTER 0xFF871101 //Q ++#define OID_RT_PRO_WRITE_REGISTER 0xFF871102 //S ++ ++#define OID_RT_PRO_BURST_READ_REGISTER 0xFF871103 //Q ++#define OID_RT_PRO_BURST_WRITE_REGISTER 0xFF871104 //S ++ ++#define OID_RT_PRO_WRITE_TXCMD 0xFF871105 //S ++ ++#define OID_RT_PRO_READ16_EEPROM 0xFF871106 //Q ++#define OID_RT_PRO_WRITE16_EEPROM 0xFF871107 //S ++ ++#define OID_RT_PRO_H2C_SET_COMMAND 0xFF871108 //S ++#define OID_RT_PRO_H2C_QUERY_RESULT 0xFF871109 //Q ++ ++#define OID_RT_PRO8711_WI_POLL 0xFF87110A //Q ++#define OID_RT_PRO8711_PKT_LOSS 0xFF87110B //Q ++#define OID_RT_RD_ATTRIB_MEM 0xFF87110C//Q ++#define OID_RT_WR_ATTRIB_MEM 0xFF87110D//S ++ ++ ++//Method 2 for H2C/C2H ++#define OID_RT_PRO_H2C_CMD_MODE 0xFF871110 //S ++#define OID_RT_PRO_H2C_CMD_RSP_MODE 0xFF871111 //Q ++#define OID_RT_PRO_H2C_CMD_EVENT_MODE 0xFF871112 //S ++#define OID_RT_PRO_WAIT_C2H_EVENT 0xFF871113 //Q ++#define OID_RT_PRO_RW_ACCESS_PROTOCOL_TEST 0xFF871114//Q ++ ++#define OID_RT_PRO_SCSI_ACCESS_TEST 0xFF871115 //Q, S ++ ++#define OID_RT_PRO_SCSI_TCPIPOFFLOAD_OUT 0xFF871116 //S ++#define OID_RT_PRO_SCSI_TCPIPOFFLOAD_IN 0xFF871117 //Q,S ++#define OID_RT_RRO_RX_PKT_VIA_IOCTRL 0xFF871118 //Q ++#define OID_RT_RRO_RX_PKTARRAY_VIA_IOCTRL 0xFF871119 //Q ++ ++#define OID_RT_RPO_SET_PWRMGT_TEST 0xFF87111A //S ++#define OID_RT_PRO_QRY_PWRMGT_TEST 0XFF87111B //Q ++#define OID_RT_RPO_ASYNC_RWIO_TEST 0xFF87111C //S ++#define OID_RT_RPO_ASYNC_RWIO_POLL 0xFF87111D //Q ++#define OID_RT_PRO_SET_RF_INTFS 0xFF87111E //S ++#define OID_RT_POLL_RX_STATUS 0xFF87111F //Q ++ ++#define OID_RT_PRO_CFG_DEBUG_MESSAGE 0xFF871120 //Q,S ++#define OID_RT_PRO_SET_DATA_RATE_EX 0xFF871121//S ++#define OID_RT_PRO_SET_BASIC_RATE 0xFF871122//S ++#define OID_RT_PRO_READ_TSSI 0xFF871123//S ++#define OID_RT_PRO_SET_POWER_TRACKING 0xFF871124//S ++ ++ ++#define OID_RT_PRO_QRY_PWRSTATE 0xFF871150 //Q ++#define OID_RT_PRO_SET_PWRSTATE 0xFF871151 //S ++ ++//Method 2 , using workitem ++#define OID_RT_SET_READ_REG 0xFF871181 //S ++#define OID_RT_SET_WRITE_REG 0xFF871182 //S ++#define OID_RT_SET_BURST_READ_REG 0xFF871183 //S ++#define OID_RT_SET_BURST_WRITE_REG 0xFF871184 //S ++#define OID_RT_SET_WRITE_TXCMD 0xFF871185 //S ++#define OID_RT_SET_READ16_EEPROM 0xFF871186 //S ++#define OID_RT_SET_WRITE16_EEPROM 0xFF871187 //S ++#define OID_RT_QRY_POLL_WKITEM 0xFF871188 //Q ++ ++//For SDIO INTERFACE only ++#define OID_RT_PRO_SYNCPAGERW_SRAM 0xFF8711A0 //Q, S ++#define OID_RT_PRO_871X_DRV_EXT 0xFF8711A1 ++ ++//For USB INTERFACE only ++#define OID_RT_PRO_USB_VENDOR_REQ 0xFF8711B0 //Q, S ++#define OID_RT_PRO_SCSI_AUTO_TEST 0xFF8711B1 //S ++#define OID_RT_PRO_USB_MAC_AC_FIFO_WRITE 0xFF8711B2 //S ++#define OID_RT_PRO_USB_MAC_RX_FIFO_READ 0xFF8711B3 //Q ++#define OID_RT_PRO_USB_MAC_RX_FIFO_POLLING 0xFF8711B4 //Q ++ ++#define OID_RT_PRO_H2C_SET_RATE_TABLE 0xFF8711FB //S ++#define OID_RT_PRO_H2C_GET_RATE_TABLE 0xFF8711FC //S ++#define OID_RT_PRO_H2C_C2H_LBK_TEST 0xFF8711FE ++ ++#define OID_RT_PRO_ENCRYPTION_CTRL 0xFF871200 //Q, S ++#define OID_RT_PRO_ADD_STA_INFO 0xFF871201 //S ++#define OID_RT_PRO_DELE_STA_INFO 0xFF871202 //S ++#define OID_RT_PRO_QUERY_DR_VARIABLE 0xFF871203 //Q ++ ++#define OID_RT_PRO_RX_PACKET_TYPE 0xFF871204 //Q, S ++ ++#define OID_RT_PRO_READ_EFUSE 0xFF871205 //Q ++#define OID_RT_PRO_WRITE_EFUSE 0xFF871206 //S ++#define OID_RT_PRO_RW_EFUSE_PGPKT 0xFF871207 //Q, S ++#define OID_RT_GET_EFUSE_CURRENT_SIZE 0xFF871208 //Q ++ ++#define OID_RT_SET_BANDWIDTH 0xFF871209 //S ++#define OID_RT_SET_CRYSTAL_CAP 0xFF87120A //S ++ ++#define OID_RT_SET_RX_PACKET_TYPE 0xFF87120B //S ++ ++#define OID_RT_GET_EFUSE_MAX_SIZE 0xFF87120C //Q ++ ++#define OID_RT_PRO_SET_TX_AGC_OFFSET 0xFF87120D //S ++ ++#define OID_RT_PRO_SET_PKT_TEST_MODE 0xFF87120E //S ++ ++#define OID_RT_PRO_FOR_EVM_TEST_SETTING 0xFF87120F //S ++ ++#define OID_RT_PRO_GET_THERMAL_METER 0xFF871210 //Q ++ ++#define OID_RT_RESET_PHY_RX_PACKET_COUNT 0xFF871211 //S ++#define OID_RT_GET_PHY_RX_PACKET_RECEIVED 0xFF871212 //Q ++#define OID_RT_GET_PHY_RX_PACKET_CRC32_ERROR 0xFF871213 //Q ++ ++#define OID_RT_SET_POWER_DOWN 0xFF871214 //S ++ ++#define OID_RT_GET_POWER_MODE 0xFF871215 //Q ++ ++#define OID_RT_PRO_EFUSE 0xFF871216 //Q, S ++#define OID_RT_PRO_EFUSE_MAP 0xFF871217 //Q, S ++ ++#endif //#ifndef __CUSTOM_OID_H ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/nic_spec.h b/drivers/net/wireless/rtl818x/rtl8189/include/nic_spec.h +new file mode 100644 +index 00000000..18e7b2c0 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/nic_spec.h +@@ -0,0 +1,47 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++ ++#ifndef __NIC_SPEC_H__ ++#define __NIC_SPEC_H__ ++ ++#include ++ ++#define RTL8711_MCTRL_ (0x20000) ++#define RTL8711_UART_ (0x30000) ++#define RTL8711_TIMER_ (0x40000) ++#define RTL8711_FINT_ (0x50000) ++#define RTL8711_HINT_ (0x50000) ++#define RTL8711_GPIO_ (0x60000) ++#define RTL8711_WLANCTRL_ (0x200000) ++#define RTL8711_WLANFF_ (0xe00000) ++#define RTL8711_HCICTRL_ (0x600000) ++#define RTL8711_SYSCFG_ (0x620000) ++#define RTL8711_SYSCTRL_ (0x620000) ++#define RTL8711_MCCTRL_ (0x020000) ++ ++ ++#include ++ ++#include ++ ++ ++#endif // __RTL8711_SPEC_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/osdep_ce_service.h b/drivers/net/wireless/rtl818x/rtl8189/include/osdep_ce_service.h +new file mode 100644 +index 00000000..6d2cc48f +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/osdep_ce_service.h +@@ -0,0 +1,171 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#ifndef __OSDEP_CE_SERVICE_H_ ++#define __OSDEP_CE_SERVICE_H_ ++ ++ ++#include ++#include ++ ++#ifdef CONFIG_SDIO_HCI ++#include "SDCardDDK.h" ++#endif ++ ++#ifdef CONFIG_USB_HCI ++#include ++#endif ++ ++typedef HANDLE _sema; ++typedef LIST_ENTRY _list; ++typedef NDIS_STATUS _OS_STATUS; ++ ++typedef NDIS_SPIN_LOCK _lock; ++ ++typedef HANDLE _rwlock; //Mutex ++ ++typedef u32 _irqL; ++ ++typedef NDIS_HANDLE _nic_hdl; ++ ++ ++typedef NDIS_MINIPORT_TIMER _timer; ++ ++struct __queue { ++ LIST_ENTRY queue; ++ _lock lock; ++}; ++ ++typedef NDIS_PACKET _pkt; ++typedef NDIS_BUFFER _buffer; ++typedef struct __queue _queue; ++ ++typedef HANDLE _thread_hdl_; ++typedef DWORD thread_return; ++typedef void* thread_context; ++typedef NDIS_WORK_ITEM _workitem; ++ ++#define thread_exit() ExitThread(STATUS_SUCCESS); return 0; ++ ++ ++#define SEMA_UPBND (0x7FFFFFFF) //8192 ++ ++__inline static _list *get_prev(_list *list) ++{ ++ return list->Blink; ++} ++ ++__inline static _list *get_next(_list *list) ++{ ++ return list->Flink; ++} ++ ++__inline static _list *get_list_head(_queue *queue) ++{ ++ return (&(queue->queue)); ++} ++ ++#define LIST_CONTAINOR(ptr, type, member) CONTAINING_RECORD(ptr, type, member) ++ ++__inline static void _enter_critical(_lock *plock, _irqL *pirqL) ++{ ++ NdisAcquireSpinLock(plock); ++} ++ ++__inline static void _exit_critical(_lock *plock, _irqL *pirqL) ++{ ++ NdisReleaseSpinLock(plock); ++} ++ ++__inline static _enter_critical_ex(_lock *plock, _irqL *pirqL) ++{ ++ NdisDprAcquireSpinLock(plock); ++} ++ ++__inline static _exit_critical_ex(_lock *plock, _irqL *pirqL) ++{ ++ NdisDprReleaseSpinLock(plock); ++} ++ ++ ++__inline static void _enter_hwio_critical(_rwlock *prwlock, _irqL *pirqL) ++{ ++ WaitForSingleObject(*prwlock, INFINITE ); ++ ++} ++ ++__inline static void _exit_hwio_critical(_rwlock *prwlock, _irqL *pirqL) ++{ ++ ReleaseMutex(*prwlock); ++} ++ ++__inline static void rtw_list_delete(_list *plist) ++{ ++ RemoveEntryList(plist); ++ InitializeListHead(plist); ++} ++ ++__inline static void _init_timer(_timer *ptimer,_nic_hdl nic_hdl,void *pfunc,PVOID cntx) ++{ ++ NdisMInitializeTimer(ptimer, nic_hdl, pfunc, cntx); ++} ++ ++__inline static void _set_timer(_timer *ptimer,u32 delay_time) ++{ ++ NdisMSetTimer(ptimer,delay_time); ++} ++ ++__inline static void _cancel_timer(_timer *ptimer,u8 *bcancelled) ++{ ++ NdisMCancelTimer(ptimer,bcancelled); ++} ++ ++__inline static void _init_workitem(_workitem *pwork, void *pfunc, PVOID cntx) ++{ ++ ++ NdisInitializeWorkItem(pwork, pfunc, cntx); ++} ++ ++__inline static void _set_workitem(_workitem *pwork) ++{ ++ NdisScheduleWorkItem(pwork); ++} ++ ++#define ATOMIC_INIT(i) { (i) } ++ ++// ++// Global Mutex: can only be used at PASSIVE level. ++// ++ ++#define ACQUIRE_GLOBAL_MUTEX(_MutexCounter) \ ++{ \ ++ while (NdisInterlockedIncrement((PULONG)&(_MutexCounter)) != 1)\ ++ { \ ++ NdisInterlockedDecrement((PULONG)&(_MutexCounter)); \ ++ NdisMSleep(10000); \ ++ } \ ++} ++ ++#define RELEASE_GLOBAL_MUTEX(_MutexCounter) \ ++{ \ ++ NdisInterlockedDecrement((PULONG)&(_MutexCounter)); \ ++} ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/osdep_intf.h b/drivers/net/wireless/rtl818x/rtl8189/include/osdep_intf.h +new file mode 100644 +index 00000000..6a4f1cde +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/osdep_intf.h +@@ -0,0 +1,160 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#ifndef __OSDEP_INTF_H_ ++#define __OSDEP_INTF_H_ ++ ++#include ++#include ++#include ++ ++struct intf_priv { ++ ++ u8 *intf_dev; ++ u32 max_iosz; //USB2.0: 128, USB1.1: 64, SDIO:64 ++ u32 max_xmitsz; //USB2.0: unlimited, SDIO:512 ++ u32 max_recvsz; //USB2.0: unlimited, SDIO:512 ++ ++ volatile u8 *io_rwmem; ++ volatile u8 *allocated_io_rwmem; ++ u32 io_wsz; //unit: 4bytes ++ u32 io_rsz;//unit: 4bytes ++ u8 intf_status; ++ ++ void (*_bus_io)(u8 *priv); ++ ++/* ++Under Sync. IRP (SDIO/USB) ++A protection mechanism is necessary for the io_rwmem(read/write protocol) ++ ++Under Async. IRP (SDIO/USB) ++The protection mechanism is through the pending queue. ++*/ ++ ++ _mutex ioctl_mutex; ++ ++ ++#ifdef PLATFORM_LINUX ++ #ifdef CONFIG_USB_HCI ++ // when in USB, IO is through interrupt in/out endpoints ++ struct usb_device *udev; ++ PURB piorw_urb; ++ u8 io_irp_cnt; ++ u8 bio_irp_pending; ++ _sema io_retevt; ++ _timer io_timer; ++ u8 bio_irp_timeout; ++ u8 bio_timer_cancel; ++ #endif ++#endif ++ ++#ifdef PLATFORM_OS_XP ++ #ifdef CONFIG_SDIO_HCI ++ // below is for io_rwmem... ++ PMDL pmdl; ++ PSDBUS_REQUEST_PACKET sdrp; ++ PSDBUS_REQUEST_PACKET recv_sdrp; ++ PSDBUS_REQUEST_PACKET xmit_sdrp; ++ ++ PIRP piorw_irp; ++ ++ #endif ++ #ifdef CONFIG_USB_HCI ++ PURB piorw_urb; ++ PIRP piorw_irp; ++ u8 io_irp_cnt; ++ u8 bio_irp_pending; ++ _sema io_retevt; ++ #endif ++#endif ++ ++}; ++ ++ ++#ifdef CONFIG_R871X_TEST ++int rtw_start_pseudo_adhoc(_adapter *padapter); ++int rtw_stop_pseudo_adhoc(_adapter *padapter); ++#endif ++ ++u8 rtw_init_drv_sw(_adapter *padapter); ++u8 rtw_free_drv_sw(_adapter *padapter); ++u8 rtw_reset_drv_sw(_adapter *padapter); ++ ++u32 rtw_start_drv_threads(_adapter *padapter); ++void rtw_stop_drv_threads (_adapter *padapter); ++#ifdef CONFIG_WOWLAN ++void rtw_cancel_dynamic_chk_timer(_adapter *padapter); ++#endif ++void rtw_cancel_all_timer(_adapter *padapter); ++ ++#ifdef PLATFORM_LINUX ++int rtw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); ++ ++int rtw_init_netdev_name(struct net_device *pnetdev, const char *ifname); ++struct net_device *rtw_init_netdev(_adapter *padapter); ++ ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)) ++u16 rtw_recv_select_queue(struct sk_buff *skb); ++#endif //LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35) ++ ++#ifdef CONFIG_PROC_DEBUG ++void rtw_proc_init_one(struct net_device *dev); ++void rtw_proc_remove_one(struct net_device *dev); ++#else //!CONFIG_PROC_DEBUG ++static void rtw_proc_init_one(struct net_device *dev){} ++static void rtw_proc_remove_one(struct net_device *dev){} ++#endif //!CONFIG_PROC_DEBUG ++#endif //PLATFORM_LINUX ++ ++ ++#ifdef PLATFORM_FREEBSD ++extern int rtw_ioctl(struct ifnet * ifp, u_long cmd, caddr_t data); ++#endif ++ ++void rtw_ips_dev_unload(_adapter *padapter); ++ ++#ifdef CONFIG_RF_GAIN_OFFSET ++void rtw_bb_rf_gain_offset(_adapter *padapter); ++#endif //CONFIG_RF_GAIN_OFFSET ++ ++#ifdef CONFIG_IPS ++int rtw_ips_pwr_up(_adapter *padapter); ++void rtw_ips_pwr_down(_adapter *padapter); ++#endif ++ ++#ifdef CONFIG_CONCURRENT_MODE ++struct _io_ops; ++_adapter *rtw_drv_if2_init(_adapter *primary_padapter, void (*set_intf_ops)(struct _io_ops *pops)); ++void rtw_drv_if2_free(_adapter *if2); ++void rtw_drv_if2_stop(_adapter *if2); ++#endif ++ ++int rtw_drv_register_netdev(_adapter *padapter); ++void rtw_ndev_destructor(_nic_hdl ndev); ++ ++int rtw_suspend_common(_adapter *padapter); ++int rtw_resume_common(_adapter *padapter); ++ ++#ifdef CONFIG_ARP_KEEP_ALIVE ++int rtw_gw_addr_query(_adapter *padapter); ++#endif ++ ++#endif //_OSDEP_INTF_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/osdep_service.h b/drivers/net/wireless/rtl818x/rtl8189/include/osdep_service.h +new file mode 100644 +index 00000000..683a2808 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/osdep_service.h +@@ -0,0 +1,1854 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __OSDEP_SERVICE_H_ ++#define __OSDEP_SERVICE_H_ ++ ++#include ++#include ++//#include ++ ++#define _FAIL 0 ++#define _SUCCESS 1 ++#define RTW_RX_HANDLED 2 ++//#define RTW_STATUS_TIMEDOUT -110 ++ ++#undef _TRUE ++#define _TRUE 1 ++ ++#undef _FALSE ++#define _FALSE 0 ++ ++ ++#ifdef PLATFORM_FREEBSD ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include "usbdevs.h" ++ ++#define USB_DEBUG_VAR rum_debug ++#include ++ ++#if 1 //Baron porting from linux, it's all temp solution, needs to check again ++#include ++#include /* XXX for PCPU_GET */ ++// typedef struct semaphore _sema; ++ typedef struct sema _sema; ++// typedef spinlock_t _lock; ++ typedef struct mtx _lock; ++ typedef struct mtx _mutex; ++ typedef struct timer_list _timer; ++ struct list_head { ++ struct list_head *next, *prev; ++ }; ++ struct __queue { ++ struct list_head queue; ++ _lock lock; ++ }; ++ ++ //typedef struct sk_buff _pkt; ++ typedef struct mbuf _pkt; ++ typedef struct mbuf _buffer; ++ ++ typedef struct __queue _queue; ++ typedef struct list_head _list; ++ typedef int _OS_STATUS; ++ //typedef u32 _irqL; ++ typedef unsigned long _irqL; ++ typedef struct ifnet * _nic_hdl; ++ ++ typedef pid_t _thread_hdl_; ++// typedef struct thread _thread_hdl_; ++ typedef void thread_return; ++ typedef void* thread_context; ++ ++ //#define thread_exit() complete_and_exit(NULL, 0) ++ ++ typedef void timer_hdl_return; ++ typedef void* timer_hdl_context; ++ typedef struct work_struct _workitem; ++ ++#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) ++/* emulate a modern version */ ++#define LINUX_VERSION_CODE KERNEL_VERSION(2, 6, 35) ++ ++#define WIRELESS_EXT -1 ++#define HZ hz ++#define spin_lock_irqsave mtx_lock_irqsave ++#define spin_lock_bh mtx_lock_irqsave ++#define mtx_lock_irqsave(lock, x) mtx_lock(lock)//{local_irq_save((x)); mtx_lock_spin((lock));} ++//#define IFT_RTW 0xf9 //ifnet allocate type for RTW ++#define free_netdev if_free ++#define LIST_CONTAINOR(ptr, type, member) \ ++ ((type *)((char *)(ptr)-(SIZE_T)(&((type *)0)->member))) ++#define container_of(p,t,n) (t*)((p)-&(((t*)0)->n)) ++/* ++ * Linux timers are emulated using FreeBSD callout functions ++ * (and taskqueue functionality). ++ * ++ * Currently no timer stats functionality. ++ * ++ * See (linux_compat) processes.c ++ * ++ */ ++struct timer_list { ++ ++ /* FreeBSD callout related fields */ ++ struct callout callout; ++ ++ //timeout function ++ void (*function)(void*); ++ //argument ++ void *arg; ++ ++}; ++struct workqueue_struct; ++struct work_struct; ++typedef void (*work_func_t)(struct work_struct *work); ++/* Values for the state of an item of work (work_struct) */ ++typedef enum work_state { ++ WORK_STATE_UNSET = 0, ++ WORK_STATE_CALLOUT_PENDING = 1, ++ WORK_STATE_TASK_PENDING = 2, ++ WORK_STATE_WORK_CANCELLED = 3 ++} work_state_t; ++ ++struct work_struct { ++ struct task task; /* FreeBSD task */ ++ work_state_t state; /* the pending or otherwise state of work. */ ++ work_func_t func; ++}; ++#define spin_unlock_irqrestore mtx_unlock_irqrestore ++#define spin_unlock_bh mtx_unlock_irqrestore ++#define mtx_unlock_irqrestore(lock,x) mtx_unlock(lock); ++extern void _rtw_spinlock_init(_lock *plock); ++ ++//modify private structure to match freebsd ++#define BITS_PER_LONG 32 ++union ktime { ++ s64 tv64; ++#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR) ++ struct { ++#ifdef __BIG_ENDIAN ++ s32 sec, nsec; ++#else ++ s32 nsec, sec; ++#endif ++ } tv; ++#endif ++}; ++#define kmemcheck_bitfield_begin(name) ++#define kmemcheck_bitfield_end(name) ++#define CHECKSUM_NONE 0 ++typedef unsigned char *sk_buff_data_t; ++typedef union ktime ktime_t; /* Kill this */ ++ ++void rtw_mtx_lock(_lock *plock); ++ ++void rtw_mtx_unlock(_lock *plock); ++ ++/** ++ * struct sk_buff - socket buffer ++ * @next: Next buffer in list ++ * @prev: Previous buffer in list ++ * @sk: Socket we are owned by ++ * @tstamp: Time we arrived ++ * @dev: Device we arrived on/are leaving by ++ * @transport_header: Transport layer header ++ * @network_header: Network layer header ++ * @mac_header: Link layer header ++ * @_skb_refdst: destination entry (with norefcount bit) ++ * @sp: the security path, used for xfrm ++ * @cb: Control buffer. Free for use by every layer. Put private vars here ++ * @len: Length of actual data ++ * @data_len: Data length ++ * @mac_len: Length of link layer header ++ * @hdr_len: writable header length of cloned skb ++ * @csum: Checksum (must include start/offset pair) ++ * @csum_start: Offset from skb->head where checksumming should start ++ * @csum_offset: Offset from csum_start where checksum should be stored ++ * @local_df: allow local fragmentation ++ * @cloned: Head may be cloned (check refcnt to be sure) ++ * @nohdr: Payload reference only, must not modify header ++ * @pkt_type: Packet class ++ * @fclone: skbuff clone status ++ * @ip_summed: Driver fed us an IP checksum ++ * @priority: Packet queueing priority ++ * @users: User count - see {datagram,tcp}.c ++ * @protocol: Packet protocol from driver ++ * @truesize: Buffer size ++ * @head: Head of buffer ++ * @data: Data head pointer ++ * @tail: Tail pointer ++ * @end: End pointer ++ * @destructor: Destruct function ++ * @mark: Generic packet mark ++ * @nfct: Associated connection, if any ++ * @ipvs_property: skbuff is owned by ipvs ++ * @peeked: this packet has been seen already, so stats have been ++ * done for it, don't do them again ++ * @nf_trace: netfilter packet trace flag ++ * @nfctinfo: Relationship of this skb to the connection ++ * @nfct_reasm: netfilter conntrack re-assembly pointer ++ * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c ++ * @skb_iif: ifindex of device we arrived on ++ * @rxhash: the packet hash computed on receive ++ * @queue_mapping: Queue mapping for multiqueue devices ++ * @tc_index: Traffic control index ++ * @tc_verd: traffic control verdict ++ * @ndisc_nodetype: router type (from link layer) ++ * @dma_cookie: a cookie to one of several possible DMA operations ++ * done by skb DMA functions ++ * @secmark: security marking ++ * @vlan_tci: vlan tag control information ++ */ ++ ++struct sk_buff { ++ /* These two members must be first. */ ++ struct sk_buff *next; ++ struct sk_buff *prev; ++ ++ ktime_t tstamp; ++ ++ struct sock *sk; ++ //struct net_device *dev; ++ struct ifnet *dev; ++ ++ /* ++ * This is the control buffer. It is free to use for every ++ * layer. Please put your private variables there. If you ++ * want to keep them across layers you have to do a skb_clone() ++ * first. This is owned by whoever has the skb queued ATM. ++ */ ++ char cb[48] __aligned(8); ++ ++ unsigned long _skb_refdst; ++#ifdef CONFIG_XFRM ++ struct sec_path *sp; ++#endif ++ unsigned int len, ++ data_len; ++ u16 mac_len, ++ hdr_len; ++ union { ++ u32 csum; ++ struct { ++ u16 csum_start; ++ u16 csum_offset; ++ }smbol2; ++ }smbol1; ++ u32 priority; ++ kmemcheck_bitfield_begin(flags1); ++ u8 local_df:1, ++ cloned:1, ++ ip_summed:2, ++ nohdr:1, ++ nfctinfo:3; ++ u8 pkt_type:3, ++ fclone:2, ++ ipvs_property:1, ++ peeked:1, ++ nf_trace:1; ++ kmemcheck_bitfield_end(flags1); ++ u16 protocol; ++ ++ void (*destructor)(struct sk_buff *skb); ++#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) ++ struct nf_conntrack *nfct; ++ struct sk_buff *nfct_reasm; ++#endif ++#ifdef CONFIG_BRIDGE_NETFILTER ++ struct nf_bridge_info *nf_bridge; ++#endif ++ ++ int skb_iif; ++#ifdef CONFIG_NET_SCHED ++ u16 tc_index; /* traffic control index */ ++#ifdef CONFIG_NET_CLS_ACT ++ u16 tc_verd; /* traffic control verdict */ ++#endif ++#endif ++ ++ u32 rxhash; ++ ++ kmemcheck_bitfield_begin(flags2); ++ u16 queue_mapping:16; ++#ifdef CONFIG_IPV6_NDISC_NODETYPE ++ u8 ndisc_nodetype:2, ++ deliver_no_wcard:1; ++#else ++ u8 deliver_no_wcard:1; ++#endif ++ kmemcheck_bitfield_end(flags2); ++ ++ /* 0/14 bit hole */ ++ ++#ifdef CONFIG_NET_DMA ++ dma_cookie_t dma_cookie; ++#endif ++#ifdef CONFIG_NETWORK_SECMARK ++ u32 secmark; ++#endif ++ union { ++ u32 mark; ++ u32 dropcount; ++ }symbol3; ++ ++ u16 vlan_tci; ++ ++ sk_buff_data_t transport_header; ++ sk_buff_data_t network_header; ++ sk_buff_data_t mac_header; ++ /* These elements must be at the end, see alloc_skb() for details. */ ++ sk_buff_data_t tail; ++ sk_buff_data_t end; ++ unsigned char *head, ++ *data; ++ unsigned int truesize; ++ atomic_t users; ++}; ++struct sk_buff_head { ++ /* These two members must be first. */ ++ struct sk_buff *next; ++ struct sk_buff *prev; ++ ++ u32 qlen; ++ _lock lock; ++}; ++#define skb_tail_pointer(skb) skb->tail ++static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len) ++{ ++ unsigned char *tmp = skb_tail_pointer(skb); ++ //SKB_LINEAR_ASSERT(skb); ++ skb->tail += len; ++ skb->len += len; ++ return tmp; ++} ++ ++static inline unsigned char *__skb_pull(struct sk_buff *skb, unsigned int len) ++{ ++ skb->len -= len; ++ if(skb->len < skb->data_len) ++ printf("%s(),%d,error!\n",__FUNCTION__,__LINE__); ++ return skb->data += len; ++} ++static inline unsigned char *skb_pull(struct sk_buff *skb, unsigned int len) ++{ ++ #ifdef PLATFORM_FREEBSD ++ return __skb_pull(skb, len); ++ #else ++ return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len); ++ #endif //PLATFORM_FREEBSD ++} ++static inline u32 skb_queue_len(const struct sk_buff_head *list_) ++{ ++ return list_->qlen; ++} ++static inline void __skb_insert(struct sk_buff *newsk, ++ struct sk_buff *prev, struct sk_buff *next, ++ struct sk_buff_head *list) ++{ ++ newsk->next = next; ++ newsk->prev = prev; ++ next->prev = prev->next = newsk; ++ list->qlen++; ++} ++static inline void __skb_queue_before(struct sk_buff_head *list, ++ struct sk_buff *next, ++ struct sk_buff *newsk) ++{ ++ __skb_insert(newsk, next->prev, next, list); ++} ++static inline void skb_queue_tail(struct sk_buff_head *list, ++ struct sk_buff *newsk) ++{ ++ mtx_lock(&list->lock); ++ __skb_queue_before(list, (struct sk_buff *)list, newsk); ++ mtx_unlock(&list->lock); ++} ++static inline struct sk_buff *skb_peek(struct sk_buff_head *list_) ++{ ++ struct sk_buff *list = ((struct sk_buff *)list_)->next; ++ if (list == (struct sk_buff *)list_) ++ list = NULL; ++ return list; ++} ++static inline void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list) ++{ ++ struct sk_buff *next, *prev; ++ ++ list->qlen--; ++ next = skb->next; ++ prev = skb->prev; ++ skb->next = skb->prev = NULL; ++ next->prev = prev; ++ prev->next = next; ++} ++ ++static inline struct sk_buff *skb_dequeue(struct sk_buff_head *list) ++{ ++ mtx_lock(&list->lock); ++ ++ struct sk_buff *skb = skb_peek(list); ++ if (skb) ++ __skb_unlink(skb, list); ++ ++ mtx_unlock(&list->lock); ++ ++ return skb; ++} ++static inline void skb_reserve(struct sk_buff *skb, int len) ++{ ++ skb->data += len; ++ skb->tail += len; ++} ++static inline void __skb_queue_head_init(struct sk_buff_head *list) ++{ ++ list->prev = list->next = (struct sk_buff *)list; ++ list->qlen = 0; ++} ++/* ++ * This function creates a split out lock class for each invocation; ++ * this is needed for now since a whole lot of users of the skb-queue ++ * infrastructure in drivers have different locking usage (in hardirq) ++ * than the networking core (in softirq only). In the long run either the ++ * network layer or drivers should need annotation to consolidate the ++ * main types of usage into 3 classes. ++ */ ++static inline void skb_queue_head_init(struct sk_buff_head *list) ++{ ++ _rtw_spinlock_init(&list->lock); ++ __skb_queue_head_init(list); ++} ++unsigned long copy_from_user(void *to, const void *from, unsigned long n); ++unsigned long copy_to_user(void *to, const void *from, unsigned long n); ++struct sk_buff * dev_alloc_skb(unsigned int size); ++struct sk_buff *skb_clone(const struct sk_buff *skb); ++void dev_kfree_skb_any(struct sk_buff *skb); ++#endif //Baron porting from linux, it's all temp solution, needs to check again ++ ++ ++#if 1 // kenny add Linux compatibility code for Linux USB driver ++#include ++ ++#define __init // __attribute ((constructor)) ++#define __exit // __attribute ((destructor)) ++ ++/* ++ * Definitions for module_init and module_exit macros. ++ * ++ * These macros will use the SYSINIT framework to call a specified ++ * function (with no arguments) on module loading or unloading. ++ * ++ */ ++ ++void module_init_exit_wrapper(void *arg); ++ ++#define module_init(initfn) \ ++ SYSINIT(mod_init_ ## initfn, \ ++ SI_SUB_KLD, SI_ORDER_FIRST, \ ++ module_init_exit_wrapper, initfn) ++ ++#define module_exit(exitfn) \ ++ SYSUNINIT(mod_exit_ ## exitfn, \ ++ SI_SUB_KLD, SI_ORDER_ANY, \ ++ module_init_exit_wrapper, exitfn) ++ ++/* ++ * The usb_register and usb_deregister functions are used to register ++ * usb drivers with the usb subsystem. ++ */ ++int usb_register(struct usb_driver *driver); ++int usb_deregister(struct usb_driver *driver); ++ ++/* ++ * usb_get_dev and usb_put_dev - increment/decrement the reference count ++ * of the usb device structure. ++ * ++ * Original body of usb_get_dev: ++ * ++ * if (dev) ++ * get_device(&dev->dev); ++ * return dev; ++ * ++ * Reference counts are not currently used in this compatibility ++ * layer. So these functions will do nothing. ++ */ ++static inline struct usb_device * ++usb_get_dev(struct usb_device *dev) ++{ ++ return dev; ++} ++ ++static inline void ++usb_put_dev(struct usb_device *dev) ++{ ++ return; ++} ++ ++ ++// rtw_usb_compat_linux ++int rtw_usb_submit_urb(struct urb *urb, uint16_t mem_flags); ++int rtw_usb_unlink_urb(struct urb *urb); ++int rtw_usb_clear_halt(struct usb_device *dev, struct usb_host_endpoint *uhe); ++int rtw_usb_control_msg(struct usb_device *dev, struct usb_host_endpoint *uhe, ++ uint8_t request, uint8_t requesttype, ++ uint16_t value, uint16_t index, void *data, ++ uint16_t size, usb_timeout_t timeout); ++int rtw_usb_set_interface(struct usb_device *dev, uint8_t iface_no, uint8_t alt_index); ++int rtw_usb_setup_endpoint(struct usb_device *dev, ++ struct usb_host_endpoint *uhe, usb_size_t bufsize); ++struct urb *rtw_usb_alloc_urb(uint16_t iso_packets, uint16_t mem_flags); ++struct usb_host_endpoint *rtw_usb_find_host_endpoint(struct usb_device *dev, uint8_t type, uint8_t ep); ++struct usb_host_interface *rtw_usb_altnum_to_altsetting(const struct usb_interface *intf, uint8_t alt_index); ++struct usb_interface *rtw_usb_ifnum_to_if(struct usb_device *dev, uint8_t iface_no); ++void *rtw_usb_buffer_alloc(struct usb_device *dev, usb_size_t size, uint8_t *dma_addr); ++void *rtw_usbd_get_intfdata(struct usb_interface *intf); ++void rtw_usb_linux_register(void *arg); ++void rtw_usb_linux_deregister(void *arg); ++void rtw_usb_linux_free_device(struct usb_device *dev); ++void rtw_usb_buffer_free(struct usb_device *dev, usb_size_t size, ++ void *addr, uint8_t dma_addr); ++void rtw_usb_free_urb(struct urb *urb); ++void rtw_usb_init_urb(struct urb *urb); ++void rtw_usb_kill_urb(struct urb *urb); ++void rtw_usb_set_intfdata(struct usb_interface *intf, void *data); ++void rtw_usb_fill_bulk_urb(struct urb *urb, struct usb_device *udev, ++ struct usb_host_endpoint *uhe, void *buf, ++ int length, usb_complete_t callback, void *arg); ++int rtw_usb_bulk_msg(struct usb_device *udev, struct usb_host_endpoint *uhe, ++ void *data, int len, uint16_t *pactlen, usb_timeout_t timeout); ++void *usb_get_intfdata(struct usb_interface *intf); ++int usb_linux_init_endpoints(struct usb_device *udev); ++ ++ ++ ++typedef struct urb * PURB; ++ ++typedef unsigned gfp_t; ++#define __GFP_WAIT ((gfp_t)0x10u) /* Can wait and reschedule? */ ++#define __GFP_HIGH ((gfp_t)0x20u) /* Should access emergency pools? */ ++#define __GFP_IO ((gfp_t)0x40u) /* Can start physical IO? */ ++#define __GFP_FS ((gfp_t)0x80u) /* Can call down to low-level FS? */ ++#define __GFP_COLD ((gfp_t)0x100u) /* Cache-cold page required */ ++#define __GFP_NOWARN ((gfp_t)0x200u) /* Suppress page allocation failure warning */ ++#define __GFP_REPEAT ((gfp_t)0x400u) /* Retry the allocation. Might fail */ ++#define __GFP_NOFAIL ((gfp_t)0x800u) /* Retry for ever. Cannot fail */ ++#define __GFP_NORETRY ((gfp_t)0x1000u)/* Do not retry. Might fail */ ++#define __GFP_NO_GROW ((gfp_t)0x2000u)/* Slab internal usage */ ++#define __GFP_COMP ((gfp_t)0x4000u)/* Add compound page metadata */ ++#define __GFP_ZERO ((gfp_t)0x8000u)/* Return zeroed page on success */ ++#define __GFP_NOMEMALLOC ((gfp_t)0x10000u) /* Don't use emergency reserves */ ++#define __GFP_HARDWALL ((gfp_t)0x20000u) /* Enforce hardwall cpuset memory allocs */ ++ ++/* This equals 0, but use constants in case they ever change */ ++#define GFP_NOWAIT (GFP_ATOMIC & ~__GFP_HIGH) ++/* GFP_ATOMIC means both !wait (__GFP_WAIT not set) and use emergency pool */ ++#define GFP_ATOMIC (__GFP_HIGH) ++#define GFP_NOIO (__GFP_WAIT) ++#define GFP_NOFS (__GFP_WAIT | __GFP_IO) ++#define GFP_KERNEL (__GFP_WAIT | __GFP_IO | __GFP_FS) ++#define GFP_USER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL) ++#define GFP_HIGHUSER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL | \ ++ __GFP_HIGHMEM) ++ ++ ++#endif // kenny add Linux compatibility code for Linux USB ++ ++__inline static _list *get_next(_list *list) ++{ ++ return list->next; ++} ++ ++__inline static _list *get_list_head(_queue *queue) ++{ ++ return (&(queue->queue)); ++} ++ ++ ++#define LIST_CONTAINOR(ptr, type, member) \ ++ ((type *)((char *)(ptr)-(SIZE_T)(&((type *)0)->member))) ++ ++ ++__inline static void _enter_critical(_lock *plock, _irqL *pirqL) ++{ ++ spin_lock_irqsave(plock, *pirqL); ++} ++ ++__inline static void _exit_critical(_lock *plock, _irqL *pirqL) ++{ ++ spin_unlock_irqrestore(plock, *pirqL); ++} ++ ++__inline static void _enter_critical_ex(_lock *plock, _irqL *pirqL) ++{ ++ spin_lock_irqsave(plock, *pirqL); ++} ++ ++__inline static void _exit_critical_ex(_lock *plock, _irqL *pirqL) ++{ ++ spin_unlock_irqrestore(plock, *pirqL); ++} ++ ++__inline static void _enter_critical_bh(_lock *plock, _irqL *pirqL) ++{ ++ spin_lock_bh(plock, *pirqL); ++} ++ ++__inline static void _exit_critical_bh(_lock *plock, _irqL *pirqL) ++{ ++ spin_unlock_bh(plock, *pirqL); ++} ++ ++__inline static void _enter_critical_mutex(_mutex *pmutex, _irqL *pirqL) ++{ ++ ++ mtx_lock(pmutex); ++ ++} ++ ++ ++__inline static void _exit_critical_mutex(_mutex *pmutex, _irqL *pirqL) ++{ ++ ++ mtx_unlock(pmutex); ++ ++} ++static inline void __list_del(struct list_head * prev, struct list_head * next) ++{ ++ next->prev = prev; ++ prev->next = next; ++} ++static inline void INIT_LIST_HEAD(struct list_head *list) ++{ ++ list->next = list; ++ list->prev = list; ++} ++__inline static void rtw_list_delete(_list *plist) ++{ ++ __list_del(plist->prev, plist->next); ++ INIT_LIST_HEAD(plist); ++} ++ ++__inline static void _init_timer(_timer *ptimer,_nic_hdl padapter,void *pfunc,void* cntx) ++{ ++ ptimer->function = pfunc; ++ ptimer->arg = cntx; ++ callout_init(&ptimer->callout, CALLOUT_MPSAFE); ++} ++ ++__inline static void _set_timer(_timer *ptimer,u32 delay_time) ++{ ++ // mod_timer(ptimer , (jiffies+(delay_time*HZ/1000))); ++ if(ptimer->function && ptimer->arg){ ++ rtw_mtx_lock(NULL); ++ callout_reset(&ptimer->callout, delay_time,ptimer->function, ptimer->arg); ++ rtw_mtx_unlock(NULL); ++ } ++} ++ ++__inline static void _cancel_timer(_timer *ptimer,u8 *bcancelled) ++{ ++ // del_timer_sync(ptimer); ++ // *bcancelled= _TRUE;//TRUE ==1; FALSE==0 ++ rtw_mtx_lock(NULL); ++ callout_drain(&ptimer->callout); ++ rtw_mtx_unlock(NULL); ++} ++ ++__inline static void _init_workitem(_workitem *pwork, void *pfunc, PVOID cntx) ++{ ++ printf("%s Not implement yet! \n",__FUNCTION__); ++} ++ ++__inline static void _set_workitem(_workitem *pwork) ++{ ++ printf("%s Not implement yet! \n",__FUNCTION__); ++// schedule_work(pwork); ++} ++ ++// ++// Global Mutex: can only be used at PASSIVE level. ++// ++ ++#define ACQUIRE_GLOBAL_MUTEX(_MutexCounter) \ ++{ \ ++} ++ ++#define RELEASE_GLOBAL_MUTEX(_MutexCounter) \ ++{ \ ++} ++ ++#define ATOMIC_INIT(i) { (i) } ++ ++#endif //PLATFORM_FREEBSD ++ ++ ++#ifdef PLATFORM_LINUX ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,5)) ++ #include ++#endif ++ //#include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) ++ #include ++#else ++ #include ++#endif ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include // Necessary because we use the proc fs ++ #include // for struct tasklet_struct ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++// #include ++ #include ++ #include ++#endif //CONFIG_IOCTL_CFG80211 ++ ++#ifdef CONFIG_TCP_CSUM_OFFLOAD_TX ++ #include ++ #include ++#endif ++ ++#ifdef CONFIG_USB_HCI ++ #include ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ #include ++#else ++ #include ++#endif ++#endif ++ ++#ifdef CONFIG_PCI_HCI ++ #include ++#endif ++ ++ ++#ifdef CONFIG_USB_HCI ++ typedef struct urb * PURB; ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,22)) ++#ifdef CONFIG_USB_SUSPEND ++#define CONFIG_AUTOSUSPEND 1 ++#endif ++#endif ++#endif ++ ++ typedef struct semaphore _sema; ++ typedef spinlock_t _lock; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ typedef struct mutex _mutex; ++#else ++ typedef struct semaphore _mutex; ++#endif ++ typedef struct timer_list _timer; ++ ++ struct __queue { ++ struct list_head queue; ++ _lock lock; ++ }; ++ ++ typedef struct sk_buff _pkt; ++ typedef unsigned char _buffer; ++ ++ typedef struct __queue _queue; ++ typedef struct list_head _list; ++ typedef int _OS_STATUS; ++ //typedef u32 _irqL; ++ typedef unsigned long _irqL; ++ typedef struct net_device * _nic_hdl; ++ ++ typedef void* _thread_hdl_; ++ typedef int thread_return; ++ typedef void* thread_context; ++ ++ #define thread_exit() complete_and_exit(NULL, 0) ++ ++ typedef void timer_hdl_return; ++ typedef void* timer_hdl_context; ++ typedef struct work_struct _workitem; ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)) ++// Porting from linux kernel, for compatible with old kernel. ++static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb) ++{ ++ return skb->tail; ++} ++ ++static inline void skb_reset_tail_pointer(struct sk_buff *skb) ++{ ++ skb->tail = skb->data; ++} ++ ++static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset) ++{ ++ skb->tail = skb->data + offset; ++} ++ ++static inline unsigned char *skb_end_pointer(const struct sk_buff *skb) ++{ ++ return skb->end; ++} ++#endif ++ ++__inline static _list *get_next(_list *list) ++{ ++ return list->next; ++} ++ ++__inline static _list *get_list_head(_queue *queue) ++{ ++ return (&(queue->queue)); ++} ++ ++ ++#define LIST_CONTAINOR(ptr, type, member) \ ++ ((type *)((char *)(ptr)-(SIZE_T)(&((type *)0)->member))) ++ ++ ++__inline static void _enter_critical(_lock *plock, _irqL *pirqL) ++{ ++ spin_lock_irqsave(plock, *pirqL); ++} ++ ++__inline static void _exit_critical(_lock *plock, _irqL *pirqL) ++{ ++ spin_unlock_irqrestore(plock, *pirqL); ++} ++ ++__inline static void _enter_critical_ex(_lock *plock, _irqL *pirqL) ++{ ++ spin_lock_irqsave(plock, *pirqL); ++} ++ ++__inline static void _exit_critical_ex(_lock *plock, _irqL *pirqL) ++{ ++ spin_unlock_irqrestore(plock, *pirqL); ++} ++ ++__inline static void _enter_critical_bh(_lock *plock, _irqL *pirqL) ++{ ++ spin_lock_bh(plock); ++} ++ ++__inline static void _exit_critical_bh(_lock *plock, _irqL *pirqL) ++{ ++ spin_unlock_bh(plock); ++} ++ ++__inline static int _enter_critical_mutex(_mutex *pmutex, _irqL *pirqL) ++{ ++ int ret = 0; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ //mutex_lock(pmutex); ++ ret = mutex_lock_interruptible(pmutex); ++#else ++ ret = down_interruptible(pmutex); ++#endif ++ return ret; ++} ++ ++ ++__inline static void _exit_critical_mutex(_mutex *pmutex, _irqL *pirqL) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ mutex_unlock(pmutex); ++#else ++ up(pmutex); ++#endif ++} ++ ++__inline static void rtw_list_delete(_list *plist) ++{ ++ list_del_init(plist); ++} ++ ++__inline static void _init_timer(_timer *ptimer,_nic_hdl nic_hdl,void *pfunc,void* cntx) ++{ ++ //setup_timer(ptimer, pfunc,(u32)cntx); ++ ptimer->function = pfunc; ++ ptimer->data = (unsigned long)cntx; ++ init_timer(ptimer); ++} ++ ++__inline static void _set_timer(_timer *ptimer,u32 delay_time) ++{ ++ mod_timer(ptimer , (jiffies+(delay_time*HZ/1000))); ++} ++ ++__inline static void _cancel_timer(_timer *ptimer,u8 *bcancelled) ++{ ++ del_timer_sync(ptimer); ++ *bcancelled= _TRUE;//TRUE ==1; FALSE==0 ++} ++ ++#ifdef PLATFORM_LINUX ++#define RTW_TIMER_HDL_ARGS void *FunctionContext ++#elif defined(PLATFORM_OS_CE) || defined(PLATFORM_WINDOWS) ++#define RTW_TIMER_HDL_ARGS IN PVOID SystemSpecific1, IN PVOID FunctionContext, IN PVOID SystemSpecific2, IN PVOID SystemSpecific3 ++#endif ++ ++#define RTW_TIMER_HDL_NAME(name) rtw_##name##_timer_hdl ++#define RTW_DECLARE_TIMER_HDL(name) void RTW_TIMER_HDL_NAME(name)(RTW_TIMER_HDL_ARGS) ++ ++ ++__inline static void _init_workitem(_workitem *pwork, void *pfunc, PVOID cntx) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++ INIT_WORK(pwork, pfunc); ++#else ++ INIT_WORK(pwork, pfunc,pwork); ++#endif ++} ++ ++__inline static void _set_workitem(_workitem *pwork) ++{ ++ schedule_work(pwork); ++} ++ ++__inline static void _cancel_workitem_sync(_workitem *pwork) ++{ ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,22)) ++ cancel_work_sync(pwork); ++#else ++ flush_scheduled_work(); ++#endif ++} ++// ++// Global Mutex: can only be used at PASSIVE level. ++// ++ ++#define ACQUIRE_GLOBAL_MUTEX(_MutexCounter) \ ++{ \ ++ while (atomic_inc_return((atomic_t *)&(_MutexCounter)) != 1)\ ++ { \ ++ atomic_dec((atomic_t *)&(_MutexCounter)); \ ++ msleep(10); \ ++ } \ ++} ++ ++#define RELEASE_GLOBAL_MUTEX(_MutexCounter) \ ++{ \ ++ atomic_dec((atomic_t *)&(_MutexCounter)); \ ++} ++ ++static inline int rtw_netif_queue_stopped(struct net_device *pnetdev) ++{ ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)) ++ return (netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 0)) && ++ netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 1)) && ++ netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 2)) && ++ netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 3)) ); ++#else ++ return netif_queue_stopped(pnetdev); ++#endif ++} ++ ++static inline void rtw_netif_wake_queue(struct net_device *pnetdev) ++{ ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)) ++ netif_tx_wake_all_queues(pnetdev); ++#else ++ netif_wake_queue(pnetdev); ++#endif ++} ++ ++static inline void rtw_netif_start_queue(struct net_device *pnetdev) ++{ ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)) ++ netif_tx_start_all_queues(pnetdev); ++#else ++ netif_start_queue(pnetdev); ++#endif ++} ++ ++static inline void rtw_netif_stop_queue(struct net_device *pnetdev) ++{ ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)) ++ netif_tx_stop_all_queues(pnetdev); ++#else ++ netif_stop_queue(pnetdev); ++#endif ++} ++ ++#endif // PLATFORM_LINUX ++ ++ ++#ifdef PLATFORM_OS_XP ++ ++ #include ++ #include ++ #include ++ #include ++ ++#ifdef CONFIG_USB_HCI ++ #include ++ #include ++ #include ++#endif ++ ++ typedef KSEMAPHORE _sema; ++ typedef LIST_ENTRY _list; ++ typedef NDIS_STATUS _OS_STATUS; ++ ++ ++ typedef NDIS_SPIN_LOCK _lock; ++ ++ typedef KMUTEX _mutex; ++ ++ typedef KIRQL _irqL; ++ ++ // USB_PIPE for WINCE , but handle can be use just integer under windows ++ typedef NDIS_HANDLE _nic_hdl; ++ ++ ++ typedef NDIS_MINIPORT_TIMER _timer; ++ ++ struct __queue { ++ LIST_ENTRY queue; ++ _lock lock; ++ }; ++ ++ typedef NDIS_PACKET _pkt; ++ typedef NDIS_BUFFER _buffer; ++ typedef struct __queue _queue; ++ ++ typedef PKTHREAD _thread_hdl_; ++ typedef void thread_return; ++ typedef void* thread_context; ++ ++ typedef NDIS_WORK_ITEM _workitem; ++ ++ #define thread_exit() PsTerminateSystemThread(STATUS_SUCCESS); ++ ++ #define HZ 10000000 ++ #define SEMA_UPBND (0x7FFFFFFF) //8192 ++ ++__inline static _list *get_next(_list *list) ++{ ++ return list->Flink; ++} ++ ++__inline static _list *get_list_head(_queue *queue) ++{ ++ return (&(queue->queue)); ++} ++ ++ ++#define LIST_CONTAINOR(ptr, type, member) CONTAINING_RECORD(ptr, type, member) ++ ++ ++__inline static _enter_critical(_lock *plock, _irqL *pirqL) ++{ ++ NdisAcquireSpinLock(plock); ++} ++ ++__inline static _exit_critical(_lock *plock, _irqL *pirqL) ++{ ++ NdisReleaseSpinLock(plock); ++} ++ ++ ++__inline static _enter_critical_ex(_lock *plock, _irqL *pirqL) ++{ ++ NdisDprAcquireSpinLock(plock); ++} ++ ++__inline static _exit_critical_ex(_lock *plock, _irqL *pirqL) ++{ ++ NdisDprReleaseSpinLock(plock); ++} ++ ++__inline static void _enter_critical_bh(_lock *plock, _irqL *pirqL) ++{ ++ NdisDprAcquireSpinLock(plock); ++} ++ ++__inline static void _exit_critical_bh(_lock *plock, _irqL *pirqL) ++{ ++ NdisDprReleaseSpinLock(plock); ++} ++ ++__inline static _enter_critical_mutex(_mutex *pmutex, _irqL *pirqL) ++{ ++ KeWaitForSingleObject(pmutex, Executive, KernelMode, FALSE, NULL); ++} ++ ++ ++__inline static _exit_critical_mutex(_mutex *pmutex, _irqL *pirqL) ++{ ++ KeReleaseMutex(pmutex, FALSE); ++} ++ ++ ++__inline static void rtw_list_delete(_list *plist) ++{ ++ RemoveEntryList(plist); ++ InitializeListHead(plist); ++} ++ ++__inline static void _init_timer(_timer *ptimer,_nic_hdl nic_hdl,void *pfunc,PVOID cntx) ++{ ++ NdisMInitializeTimer(ptimer, nic_hdl, pfunc, cntx); ++} ++ ++__inline static void _set_timer(_timer *ptimer,u32 delay_time) ++{ ++ NdisMSetTimer(ptimer,delay_time); ++} ++ ++__inline static void _cancel_timer(_timer *ptimer,u8 *bcancelled) ++{ ++ NdisMCancelTimer(ptimer,bcancelled); ++} ++ ++__inline static void _init_workitem(_workitem *pwork, void *pfunc, PVOID cntx) ++{ ++ ++ NdisInitializeWorkItem(pwork, pfunc, cntx); ++} ++ ++__inline static void _set_workitem(_workitem *pwork) ++{ ++ NdisScheduleWorkItem(pwork); ++} ++ ++ ++#define ATOMIC_INIT(i) { (i) } ++ ++// ++// Global Mutex: can only be used at PASSIVE level. ++// ++ ++#define ACQUIRE_GLOBAL_MUTEX(_MutexCounter) \ ++{ \ ++ while (NdisInterlockedIncrement((PULONG)&(_MutexCounter)) != 1)\ ++ { \ ++ NdisInterlockedDecrement((PULONG)&(_MutexCounter)); \ ++ NdisMSleep(10000); \ ++ } \ ++} ++ ++#define RELEASE_GLOBAL_MUTEX(_MutexCounter) \ ++{ \ ++ NdisInterlockedDecrement((PULONG)&(_MutexCounter)); \ ++} ++ ++#endif // PLATFORM_OS_XP ++ ++ ++#ifdef PLATFORM_OS_CE ++#include ++#endif ++ ++#include ++ ++#ifndef BIT ++ #define BIT(x) ( 1 << (x)) ++#endif ++ ++#define BIT0 0x00000001 ++#define BIT1 0x00000002 ++#define BIT2 0x00000004 ++#define BIT3 0x00000008 ++#define BIT4 0x00000010 ++#define BIT5 0x00000020 ++#define BIT6 0x00000040 ++#define BIT7 0x00000080 ++#define BIT8 0x00000100 ++#define BIT9 0x00000200 ++#define BIT10 0x00000400 ++#define BIT11 0x00000800 ++#define BIT12 0x00001000 ++#define BIT13 0x00002000 ++#define BIT14 0x00004000 ++#define BIT15 0x00008000 ++#define BIT16 0x00010000 ++#define BIT17 0x00020000 ++#define BIT18 0x00040000 ++#define BIT19 0x00080000 ++#define BIT20 0x00100000 ++#define BIT21 0x00200000 ++#define BIT22 0x00400000 ++#define BIT23 0x00800000 ++#define BIT24 0x01000000 ++#define BIT25 0x02000000 ++#define BIT26 0x04000000 ++#define BIT27 0x08000000 ++#define BIT28 0x10000000 ++#define BIT29 0x20000000 ++#define BIT30 0x40000000 ++#define BIT31 0x80000000 ++#define BIT32 0x0100000000 ++#define BIT33 0x0200000000 ++#define BIT34 0x0400000000 ++#define BIT35 0x0800000000 ++#define BIT36 0x1000000000 ++ ++extern int RTW_STATUS_CODE(int error_code); ++ ++//#define CONFIG_USE_VMALLOC ++ ++/* flags used for rtw_mstat_update() */ ++enum mstat_f { ++ /* type: 0x00ff */ ++ MSTAT_TYPE_VIR = 0x00, ++ MSTAT_TYPE_PHY= 0x01, ++ MSTAT_TYPE_SKB = 0x02, ++ MSTAT_TYPE_USB = 0x03, ++ MSTAT_TYPE_MAX = 0x04, ++ ++ /* func: 0xff00 */ ++ MSTAT_FUNC_UNSPECIFIED = 0x00<<8, ++ MSTAT_FUNC_IO = 0x01<<8, ++ MSTAT_FUNC_TX_IO = 0x02<<8, ++ MSTAT_FUNC_RX_IO = 0x03<<8, ++ MSTAT_FUNC_TX = 0x04<<8, ++ MSTAT_FUNC_RX = 0x05<<8, ++ MSTAT_FUNC_MAX = 0x06<<8, ++}; ++ ++#define mstat_tf_idx(flags) ((flags)&0xff) ++#define mstat_ff_idx(flags) (((flags)&0xff00) >> 8) ++ ++typedef enum mstat_status{ ++ MSTAT_ALLOC_SUCCESS = 0, ++ MSTAT_ALLOC_FAIL, ++ MSTAT_FREE ++} MSTAT_STATUS; ++ ++#ifdef DBG_MEM_ALLOC ++void rtw_mstat_update(const enum mstat_f flags, const MSTAT_STATUS status, u32 sz); ++int _rtw_mstat_dump(char *buf, int len); ++void rtw_mstat_dump (void); ++u8* dbg_rtw_vmalloc(u32 sz, const enum mstat_f flags, const char *func, const int line); ++u8* dbg_rtw_zvmalloc(u32 sz, const enum mstat_f flags, const char *func, const int line); ++void dbg_rtw_vmfree(u8 *pbuf, const enum mstat_f flags, u32 sz, const char *func, const int line); ++u8* dbg_rtw_malloc(u32 sz, const enum mstat_f flags, const char *func, const int line); ++u8* dbg_rtw_zmalloc(u32 sz, const enum mstat_f flags, const char *func, const int line); ++void dbg_rtw_mfree(u8 *pbuf, const enum mstat_f flags, u32 sz, const char *func, const int line); ++ ++struct sk_buff * dbg_rtw_skb_alloc(unsigned int size, const enum mstat_f flags, const char *func, const int line); ++void dbg_rtw_skb_free(struct sk_buff *skb, const enum mstat_f flags, const char *func, const int line); ++struct sk_buff *dbg_rtw_skb_copy(const struct sk_buff *skb, const enum mstat_f flags, const char *func, const int line); ++struct sk_buff *dbg_rtw_skb_clone(struct sk_buff *skb, const enum mstat_f flags, const char *func, const int line); ++int dbg_rtw_netif_rx(_nic_hdl ndev, struct sk_buff *skb, const enum mstat_f flags, const char *func, int line); ++void dbg_rtw_skb_queue_purge(struct sk_buff_head *list, enum mstat_f flags, const char *func, int line); ++ ++#ifdef CONFIG_USB_HCI ++void *dbg_rtw_usb_buffer_alloc(struct usb_device *dev, size_t size, dma_addr_t *dma, const enum mstat_f flags, const char *func, const int line); ++void dbg_rtw_usb_buffer_free(struct usb_device *dev, size_t size, void *addr, dma_addr_t dma, const enum mstat_f flags, const char *func, const int line); ++#endif /* CONFIG_USB_HCI */ ++ ++#ifdef CONFIG_USE_VMALLOC ++#define rtw_vmalloc(sz) dbg_rtw_vmalloc((sz), MSTAT_TYPE_VIR, __FUNCTION__, __LINE__) ++#define rtw_zvmalloc(sz) dbg_rtw_zvmalloc((sz), MSTAT_TYPE_VIR, __FUNCTION__, __LINE__) ++#define rtw_vmfree(pbuf, sz) dbg_rtw_vmfree((pbuf), (sz), MSTAT_TYPE_VIR, __FUNCTION__, __LINE__) ++#define rtw_vmalloc_f(sz, mstat_f) dbg_rtw_vmalloc((sz), ((mstat_f)&0xff00)|MSTAT_TYPE_VIR, __FUNCTION__, __LINE__) ++#define rtw_zvmalloc_f(sz, mstat_f) dbg_rtw_zvmalloc((sz), ((mstat_f)&0xff00)|MSTAT_TYPE_VIR, __FUNCTION__, __LINE__) ++#define rtw_vmfree_f(pbuf, sz, mstat_f) dbg_rtw_vmfree((pbuf), (sz), ((mstat_f)&0xff00)|MSTAT_TYPE_VIR, __FUNCTION__, __LINE__) ++#else /* CONFIG_USE_VMALLOC */ ++#define rtw_vmalloc(sz) dbg_rtw_malloc((sz), MSTAT_TYPE_PHY, __FUNCTION__, __LINE__) ++#define rtw_zvmalloc(sz) dbg_rtw_zmalloc((sz), MSTAT_TYPE_PHY, __FUNCTION__, __LINE__) ++#define rtw_vmfree(pbuf, sz) dbg_rtw_mfree((pbuf), (sz), MSTAT_TYPE_PHY, __FUNCTION__, __LINE__) ++#define rtw_vmalloc_f(sz, mstat_f) dbg_rtw_malloc((sz), ((mstat_f)&0xff00)|MSTAT_TYPE_PHY, __FUNCTION__, __LINE__) ++#define rtw_zvmalloc_f(sz, mstat_f) dbg_rtw_zmalloc((sz), ((mstat_f)&0xff00)|MSTAT_TYPE_PHY, __FUNCTION__, __LINE__) ++#define rtw_vmfree_f(pbuf, sz, mstat_f) dbg_rtw_mfree((pbuf), (sz), ((mstat_f)&0xff00)|MSTAT_TYPE_PHY, __FUNCTION__, __LINE__) ++#endif /* CONFIG_USE_VMALLOC */ ++#define rtw_malloc(sz) dbg_rtw_malloc((sz), MSTAT_TYPE_PHY, __FUNCTION__, __LINE__) ++#define rtw_zmalloc(sz) dbg_rtw_zmalloc((sz), MSTAT_TYPE_PHY, __FUNCTION__, __LINE__) ++#define rtw_mfree(pbuf, sz) dbg_rtw_mfree((pbuf), (sz), MSTAT_TYPE_PHY, __FUNCTION__, __LINE__) ++#define rtw_malloc_f(sz, mstat_f) dbg_rtw_malloc((sz), ((mstat_f)&0xff00)|MSTAT_TYPE_PHY, __FUNCTION__, __LINE__) ++#define rtw_zmalloc_f(sz, mstat_f) dbg_rtw_zmalloc((sz), ((mstat_f)&0xff00)|MSTAT_TYPE_PHY, __FUNCTION__, __LINE__) ++#define rtw_mfree_f(pbuf, sz, mstat_f) dbg_rtw_mfree((pbuf), (sz), ((mstat_f)&0xff00)|MSTAT_TYPE_PHY, __FUNCTION__, __LINE__) ++ ++#define rtw_skb_alloc(size) dbg_rtw_skb_alloc((size), MSTAT_TYPE_SKB, __FUNCTION__, __LINE__) ++#define rtw_skb_free(skb) dbg_rtw_skb_free((skb), MSTAT_TYPE_SKB, __FUNCTION__, __LINE__) ++#define rtw_skb_alloc_f(size, mstat_f) dbg_rtw_skb_alloc((size), ((mstat_f)&0xff00)|MSTAT_TYPE_SKB, __FUNCTION__, __LINE__) ++#define rtw_skb_free_f(skb, mstat_f) dbg_rtw_skb_free((skb), ((mstat_f)&0xff00)|MSTAT_TYPE_SKB, __FUNCTION__, __LINE__) ++#define rtw_skb_copy(skb) dbg_rtw_skb_copy((skb), MSTAT_TYPE_SKB, __FUNCTION__, __LINE__) ++#define rtw_skb_clone(skb) dbg_rtw_skb_clone((skb), MSTAT_TYPE_SKB, __FUNCTION__, __LINE__) ++#define rtw_skb_copy_f(skb, mstat_f) dbg_rtw_skb_copy((skb), ((mstat_f)&0xff00)|MSTAT_TYPE_SKB, __FUNCTION__, __LINE__) ++#define rtw_skb_clone_f(skb, mstat_f) dbg_rtw_skb_clone((skb), ((mstat_f)&0xff00)|MSTAT_TYPE_SKB, __FUNCTION__, __LINE__) ++#define rtw_netif_rx(ndev, skb) dbg_rtw_netif_rx(ndev, skb, MSTAT_TYPE_SKB, __FUNCTION__, __LINE__) ++#define rtw_skb_queue_purge(sk_buff_head) dbg_rtw_skb_queue_purge(sk_buff_head, MSTAT_TYPE_SKB, __FUNCTION__, __LINE__) ++#ifdef CONFIG_USB_HCI ++#define rtw_usb_buffer_alloc(dev, size, dma) dbg_rtw_usb_buffer_alloc((dev), (size), (dma), MSTAT_TYPE_USB, __FUNCTION__, __LINE__) ++#define rtw_usb_buffer_free(dev, size, addr, dma) dbg_rtw_usb_buffer_free((dev), (size), (addr), (dma), MSTAT_TYPE_USB, __FUNCTION__, __LINE__) ++#define rtw_usb_buffer_alloc_f(dev, size, dma, mstat_f) dbg_rtw_usb_buffer_alloc((dev), (size), (dma), ((mstat_f)&0xff00)|MSTAT_TYPE_USB, __FUNCTION__, __LINE__) ++#define rtw_usb_buffer_free_f(dev, size, addr, dma, mstat_f) dbg_rtw_usb_buffer_free((dev), (size), (addr), (dma), ((mstat_f)&0xff00)|MSTAT_TYPE_USB, __FUNCTION__, __LINE__) ++#endif /* CONFIG_USB_HCI */ ++ ++#else /* DBG_MEM_ALLOC */ ++#define rtw_mstat_update(flag, status, sz) do {} while(0) ++#define rtw_mstat_dump() do {} while(0) ++u8* _rtw_vmalloc(u32 sz); ++u8* _rtw_zvmalloc(u32 sz); ++void _rtw_vmfree(u8 *pbuf, u32 sz); ++u8* _rtw_zmalloc(u32 sz); ++u8* _rtw_malloc(u32 sz); ++void _rtw_mfree(u8 *pbuf, u32 sz); ++ ++struct sk_buff *_rtw_skb_alloc(u32 sz); ++void _rtw_skb_free(struct sk_buff *skb); ++struct sk_buff *_rtw_skb_copy(const struct sk_buff *skb); ++struct sk_buff *_rtw_skb_clone(struct sk_buff *skb); ++int _rtw_netif_rx(_nic_hdl ndev, struct sk_buff *skb); ++void _rtw_skb_queue_purge(struct sk_buff_head *list); ++ ++#ifdef CONFIG_USB_HCI ++void *_rtw_usb_buffer_alloc(struct usb_device *dev, size_t size, dma_addr_t *dma); ++void _rtw_usb_buffer_free(struct usb_device *dev, size_t size, void *addr, dma_addr_t dma); ++#endif /* CONFIG_USB_HCI */ ++ ++#ifdef CONFIG_USE_VMALLOC ++#define rtw_vmalloc(sz) _rtw_vmalloc((sz)) ++#define rtw_zvmalloc(sz) _rtw_zvmalloc((sz)) ++#define rtw_vmfree(pbuf, sz) _rtw_vmfree((pbuf), (sz)) ++#define rtw_vmalloc_f(sz, mstat_f) _rtw_vmalloc((sz)) ++#define rtw_zvmalloc_f(sz, mstat_f) _rtw_zvmalloc((sz)) ++#define rtw_vmfree_f(pbuf, sz, mstat_f) _rtw_vmfree((pbuf), (sz)) ++#else /* CONFIG_USE_VMALLOC */ ++#define rtw_vmalloc(sz) _rtw_malloc((sz)) ++#define rtw_zvmalloc(sz) _rtw_zmalloc((sz)) ++#define rtw_vmfree(pbuf, sz) _rtw_mfree((pbuf), (sz)) ++#define rtw_vmalloc_f(sz, mstat_f) _rtw_malloc((sz)) ++#define rtw_zvmalloc_f(sz, mstat_f) _rtw_zmalloc((sz)) ++#define rtw_vmfree_f(pbuf, sz, mstat_f) _rtw_mfree((pbuf), (sz)) ++#endif /* CONFIG_USE_VMALLOC */ ++#define rtw_malloc(sz) _rtw_malloc((sz)) ++#define rtw_zmalloc(sz) _rtw_zmalloc((sz)) ++#define rtw_mfree(pbuf, sz) _rtw_mfree((pbuf), (sz)) ++#define rtw_malloc_f(sz, mstat_f) _rtw_malloc((sz)) ++#define rtw_zmalloc_f(sz, mstat_f) _rtw_zmalloc((sz)) ++#define rtw_mfree_f(pbuf, sz, mstat_f) _rtw_mfree((pbuf), (sz)) ++ ++#define rtw_skb_alloc(size) _rtw_skb_alloc((size)) ++#define rtw_skb_free(skb) _rtw_skb_free((skb)) ++#define rtw_skb_alloc_f(size, mstat_f) _rtw_skb_alloc((size)) ++#define rtw_skb_free_f(skb, mstat_f) _rtw_skb_free((skb)) ++#define rtw_skb_copy(skb) _rtw_skb_copy((skb)) ++#define rtw_skb_clone(skb) _rtw_skb_clone((skb)) ++#define rtw_skb_copy_f(skb, mstat_f) _rtw_skb_copy((skb)) ++#define rtw_skb_clone_f(skb, mstat_f) _rtw_skb_clone((skb)) ++#define rtw_netif_rx(ndev, skb) _rtw_netif_rx(ndev, skb) ++#define rtw_skb_queue_purge(sk_buff_head) _rtw_skb_queue_purge(sk_buff_head) ++#ifdef CONFIG_USB_HCI ++#define rtw_usb_buffer_alloc(dev, size, dma) _rtw_usb_buffer_alloc((dev), (size), (dma)) ++#define rtw_usb_buffer_free(dev, size, addr, dma) _rtw_usb_buffer_free((dev), (size), (addr), (dma)) ++#define rtw_usb_buffer_alloc_f(dev, size, dma, mstat_f) _rtw_usb_buffer_alloc((dev), (size), (dma)) ++#define rtw_usb_buffer_free_f(dev, size, addr, dma, mstat_f) _rtw_usb_buffer_free((dev), (size), (addr), (dma)) ++#endif /* CONFIG_USB_HCI */ ++#endif /* DBG_MEM_ALLOC */ ++ ++extern void* rtw_malloc2d(int h, int w, int size); ++extern void rtw_mfree2d(void *pbuf, int h, int w, int size); ++ ++extern void _rtw_memcpy(void* dec, void* sour, u32 sz); ++extern int _rtw_memcmp(void *dst, void *src, u32 sz); ++extern void _rtw_memset(void *pbuf, int c, u32 sz); ++ ++extern void _rtw_init_listhead(_list *list); ++extern u32 rtw_is_list_empty(_list *phead); ++extern void rtw_list_insert_head(_list *plist, _list *phead); ++extern void rtw_list_insert_tail(_list *plist, _list *phead); ++#ifndef PLATFORM_FREEBSD ++extern void rtw_list_delete(_list *plist); ++#endif //PLATFORM_FREEBSD ++ ++extern void _rtw_init_sema(_sema *sema, int init_val); ++extern void _rtw_free_sema(_sema *sema); ++extern void _rtw_up_sema(_sema *sema); ++extern u32 _rtw_down_sema(_sema *sema); ++extern void _rtw_mutex_init(_mutex *pmutex); ++extern void _rtw_mutex_free(_mutex *pmutex); ++#ifndef PLATFORM_FREEBSD ++extern void _rtw_spinlock_init(_lock *plock); ++#endif //PLATFORM_FREEBSD ++extern void _rtw_spinlock_free(_lock *plock); ++extern void _rtw_spinlock(_lock *plock); ++extern void _rtw_spinunlock(_lock *plock); ++extern void _rtw_spinlock_ex(_lock *plock); ++extern void _rtw_spinunlock_ex(_lock *plock); ++ ++extern void _rtw_init_queue(_queue *pqueue); ++extern u32 _rtw_queue_empty(_queue *pqueue); ++extern u32 rtw_end_of_queue_search(_list *queue, _list *pelement); ++ ++extern u32 rtw_get_current_time(void); ++extern u32 rtw_systime_to_ms(u32 systime); ++extern u32 rtw_ms_to_systime(u32 ms); ++extern s32 rtw_get_passing_time_ms(u32 start); ++extern s32 rtw_get_time_interval_ms(u32 start, u32 end); ++ ++extern void rtw_sleep_schedulable(int ms); ++ ++extern void rtw_msleep_os(int ms); ++extern void rtw_usleep_os(int us); ++ ++extern u32 rtw_atoi(u8* s); ++ ++#ifdef DBG_DELAY_OS ++#define rtw_mdelay_os(ms) _rtw_mdelay_os((ms), __FUNCTION__, __LINE__) ++#define rtw_udelay_os(ms) _rtw_udelay_os((ms), __FUNCTION__, __LINE__) ++extern void _rtw_mdelay_os(int ms, const char *func, const int line); ++extern void _rtw_udelay_os(int us, const char *func, const int line); ++#else ++extern void rtw_mdelay_os(int ms); ++extern void rtw_udelay_os(int us); ++#endif ++ ++extern void rtw_yield_os(void); ++ ++ ++__inline static unsigned char _cancel_timer_ex(_timer *ptimer) ++{ ++#ifdef PLATFORM_LINUX ++ return del_timer_sync(ptimer); ++#endif ++#ifdef PLATFORM_FREEBSD ++ _cancel_timer(ptimer,0); ++ return 0; ++#endif ++#ifdef PLATFORM_WINDOWS ++ u8 bcancelled; ++ ++ _cancel_timer(ptimer, &bcancelled); ++ ++ return bcancelled; ++#endif ++} ++ ++#ifdef PLATFORM_FREEBSD ++static __inline void thread_enter(char *name); ++#endif //PLATFORM_FREEBSD ++static __inline void thread_enter(char *name) ++{ ++#ifdef PLATFORM_LINUX ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) ++ daemonize("%s", name); ++ #endif ++ allow_signal(SIGTERM); ++#endif ++#ifdef PLATFORM_FREEBSD ++ printf("%s", "RTKTHREAD_enter"); ++#endif ++} ++ ++#ifdef PLATFORM_FREEBSD ++#define thread_exit() do{printf("%s", "RTKTHREAD_exit");}while(0) ++#endif //PLATFORM_FREEBSD ++__inline static void flush_signals_thread(void) ++{ ++#ifdef PLATFORM_LINUX ++ if (signal_pending (current)) ++ { ++ flush_signals(current); ++ } ++#endif ++} ++ ++__inline static _OS_STATUS res_to_status(sint res) ++{ ++ ++ ++#if defined (PLATFORM_LINUX) || defined (PLATFORM_MPIXEL) || defined (PLATFORM_FREEBSD) ++ return res; ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++ ++ if (res == _SUCCESS) ++ return NDIS_STATUS_SUCCESS; ++ else ++ return NDIS_STATUS_FAILURE; ++ ++#endif ++ ++} ++ ++__inline static void rtw_dump_stack(void) ++{ ++#ifdef PLATFORM_LINUX ++ dump_stack(); ++#endif ++} ++ ++#ifdef PLATFORM_LINUX ++#define rtw_warn_on(condition) WARN_ON(condition) ++#else ++#define rtw_warn_on(condition) do {} while (0) ++#endif ++ ++#define _RND(sz, r) ((((sz)+((r)-1))/(r))*(r)) ++#define RND4(x) (((x >> 2) + (((x & 3) == 0) ? 0: 1)) << 2) ++ ++__inline static u32 _RND4(u32 sz) ++{ ++ ++ u32 val; ++ ++ val = ((sz >> 2) + ((sz & 3) ? 1: 0)) << 2; ++ ++ return val; ++ ++} ++ ++__inline static u32 _RND8(u32 sz) ++{ ++ ++ u32 val; ++ ++ val = ((sz >> 3) + ((sz & 7) ? 1: 0)) << 3; ++ ++ return val; ++ ++} ++ ++__inline static u32 _RND128(u32 sz) ++{ ++ ++ u32 val; ++ ++ val = ((sz >> 7) + ((sz & 127) ? 1: 0)) << 7; ++ ++ return val; ++ ++} ++ ++__inline static u32 _RND256(u32 sz) ++{ ++ ++ u32 val; ++ ++ val = ((sz >> 8) + ((sz & 255) ? 1: 0)) << 8; ++ ++ return val; ++ ++} ++ ++__inline static u32 _RND512(u32 sz) ++{ ++ ++ u32 val; ++ ++ val = ((sz >> 9) + ((sz & 511) ? 1: 0)) << 9; ++ ++ return val; ++ ++} ++ ++__inline static u32 bitshift(u32 bitmask) ++{ ++ u32 i; ++ ++ for (i = 0; i <= 31; i++) ++ if (((bitmask>>i) & 0x1) == 1) break; ++ ++ return i; ++} ++ ++#ifndef MAC_FMT ++#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" ++#endif ++#ifndef MAC_ARG ++#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5] ++#endif ++ ++//#ifdef __GNUC__ ++#ifdef PLATFORM_LINUX ++#define STRUCT_PACKED __attribute__ ((packed)) ++#else ++#define STRUCT_PACKED ++#endif ++ ++ ++// limitation of path length ++#ifdef PLATFORM_LINUX ++ #define PATH_LENGTH_MAX PATH_MAX ++#elif defined(PLATFORM_WINDOWS) ++ #define PATH_LENGTH_MAX MAX_PATH ++#endif ++ ++ ++// Suspend lock prevent system from going suspend ++#ifdef CONFIG_WAKELOCK ++#include ++#elif defined(CONFIG_ANDROID_POWER) ++#include ++#endif ++ ++extern void rtw_suspend_lock_init(void); ++extern void rtw_suspend_lock_uninit(void); ++extern void rtw_lock_suspend(void); ++extern void rtw_unlock_suspend(void); ++extern void rtw_lock_suspend_timeout(u32 timeout_ms); ++extern void rtw_lock_ext_suspend_timeout(u32 timeout_ms); ++ ++ ++//Atomic integer operations ++#ifdef PLATFORM_LINUX ++ #define ATOMIC_T atomic_t ++#elif defined(PLATFORM_WINDOWS) ++ #define ATOMIC_T LONG ++#elif defined(PLATFORM_FREEBSD) ++ typedef uint32_t ATOMIC_T ; ++#endif ++ ++extern void ATOMIC_SET(ATOMIC_T *v, int i); ++extern int ATOMIC_READ(ATOMIC_T *v); ++extern void ATOMIC_ADD(ATOMIC_T *v, int i); ++extern void ATOMIC_SUB(ATOMIC_T *v, int i); ++extern void ATOMIC_INC(ATOMIC_T *v); ++extern void ATOMIC_DEC(ATOMIC_T *v); ++extern int ATOMIC_ADD_RETURN(ATOMIC_T *v, int i); ++extern int ATOMIC_SUB_RETURN(ATOMIC_T *v, int i); ++extern int ATOMIC_INC_RETURN(ATOMIC_T *v); ++extern int ATOMIC_DEC_RETURN(ATOMIC_T *v); ++ ++//File operation APIs, just for linux now ++extern int rtw_is_file_readable(char *path); ++extern int rtw_retrive_from_file(char *path, u8* buf, u32 sz); ++extern int rtw_store_to_file(char *path, u8* buf, u32 sz); ++ ++ ++#if 1 //#ifdef MEM_ALLOC_REFINE_ADAPTOR ++struct rtw_netdev_priv_indicator { ++ void *priv; ++ u32 sizeof_priv; ++}; ++struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv, void *old_priv); ++extern struct net_device * rtw_alloc_etherdev(int sizeof_priv); ++ ++#ifndef PLATFORM_FREEBSD ++#define rtw_netdev_priv(netdev) ( ((struct rtw_netdev_priv_indicator *)netdev_priv(netdev))->priv ) ++#else //PLATFORM_FREEBSD ++#define rtw_netdev_priv(netdev) (((struct ifnet *)netdev)->if_softc) ++#endif //PLATFORM_FREEBSD ++ ++#ifndef PLATFORM_FREEBSD ++extern void rtw_free_netdev(struct net_device * netdev); ++#else //PLATFORM_FREEBSD ++#define rtw_free_netdev(netdev) if_free((netdev)) ++#endif //PLATFORM_FREEBSD ++ ++#else //MEM_ALLOC_REFINE_ADAPTOR ++ ++#define rtw_alloc_etherdev(sizeof_priv) alloc_etherdev((sizeof_priv)) ++ ++#ifndef PLATFORM_FREEBSD ++#define rtw_netdev_priv(netdev) netdev_priv((netdev)) ++#define rtw_free_netdev(netdev) free_netdev((netdev)) ++#else //PLATFORM_FREEBSD ++#define rtw_netdev_priv(netdev) (((struct ifnet *)netdev)->if_softc) ++#define rtw_free_netdev(netdev) if_free((netdev)) ++#endif //PLATFORM_FREEBSD ++#endif ++ ++#ifdef PLATFORM_LINUX ++#define NDEV_FMT "%s" ++#define NDEV_ARG(ndev) ndev->name ++#define ADPT_FMT "%s" ++#define ADPT_ARG(adapter) adapter->pnetdev->name ++#define FUNC_NDEV_FMT "%s(%s)" ++#define FUNC_NDEV_ARG(ndev) __func__, ndev->name ++#define FUNC_ADPT_FMT "%s(%s)" ++#define FUNC_ADPT_ARG(adapter) __func__, adapter->pnetdev->name ++#else ++#define NDEV_FMT "%s" ++#define NDEV_ARG(ndev) "" ++#define ADPT_FMT "%s" ++#define ADPT_ARG(adapter) "" ++#define FUNC_NDEV_FMT "%s" ++#define FUNC_NDEV_ARG(ndev) __func__ ++#define FUNC_ADPT_FMT "%s" ++#define FUNC_ADPT_ARG(adapter) __func__ ++#endif ++ ++#ifdef PLATFORM_LINUX ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) ++#define rtw_signal_process(pid, sig) kill_pid(find_vpid((pid)),(sig), 1) ++#else //(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) ++#define rtw_signal_process(pid, sig) kill_proc((pid), (sig), 1) ++#endif //(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) ++#endif //PLATFORM_LINUX ++ ++extern u64 rtw_modular64(u64 x, u64 y); ++extern u64 rtw_division64(u64 x, u64 y); ++ ++ ++/* Macros for handling unaligned memory accesses */ ++ ++#define RTW_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1])) ++#define RTW_PUT_BE16(a, val) \ ++ do { \ ++ (a)[0] = ((u16) (val)) >> 8; \ ++ (a)[1] = ((u16) (val)) & 0xff; \ ++ } while (0) ++ ++#define RTW_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) ++#define RTW_PUT_LE16(a, val) \ ++ do { \ ++ (a)[1] = ((u16) (val)) >> 8; \ ++ (a)[0] = ((u16) (val)) & 0xff; \ ++ } while (0) ++ ++#define RTW_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ ++ ((u32) (a)[2])) ++#define RTW_PUT_BE24(a, val) \ ++ do { \ ++ (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \ ++ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ ++ (a)[2] = (u8) (((u32) (val)) & 0xff); \ ++ } while (0) ++ ++#define RTW_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ ++ (((u32) (a)[2]) << 8) | ((u32) (a)[3])) ++#define RTW_PUT_BE32(a, val) \ ++ do { \ ++ (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ ++ (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ ++ (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ ++ (a)[3] = (u8) (((u32) (val)) & 0xff); \ ++ } while (0) ++ ++#define RTW_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \ ++ (((u32) (a)[1]) << 8) | ((u32) (a)[0])) ++#define RTW_PUT_LE32(a, val) \ ++ do { \ ++ (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ ++ (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ ++ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ ++ (a)[0] = (u8) (((u32) (val)) & 0xff); \ ++ } while (0) ++ ++#define RTW_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \ ++ (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \ ++ (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \ ++ (((u64) (a)[6]) << 8) | ((u64) (a)[7])) ++#define RTW_PUT_BE64(a, val) \ ++ do { \ ++ (a)[0] = (u8) (((u64) (val)) >> 56); \ ++ (a)[1] = (u8) (((u64) (val)) >> 48); \ ++ (a)[2] = (u8) (((u64) (val)) >> 40); \ ++ (a)[3] = (u8) (((u64) (val)) >> 32); \ ++ (a)[4] = (u8) (((u64) (val)) >> 24); \ ++ (a)[5] = (u8) (((u64) (val)) >> 16); \ ++ (a)[6] = (u8) (((u64) (val)) >> 8); \ ++ (a)[7] = (u8) (((u64) (val)) & 0xff); \ ++ } while (0) ++ ++#define RTW_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \ ++ (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \ ++ (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \ ++ (((u64) (a)[1]) << 8) | ((u64) (a)[0])) ++ ++void rtw_buf_free(u8 **buf, u32 *buf_len); ++void rtw_buf_update(u8 **buf, u32 *buf_len, u8 *src, u32 src_len); ++ ++struct rtw_cbuf { ++ u32 write; ++ u32 read; ++ u32 size; ++ void *bufs[0]; ++}; ++ ++bool rtw_cbuf_full(struct rtw_cbuf *cbuf); ++bool rtw_cbuf_empty(struct rtw_cbuf *cbuf); ++bool rtw_cbuf_push(struct rtw_cbuf *cbuf, void *buf); ++void *rtw_cbuf_pop(struct rtw_cbuf *cbuf); ++struct rtw_cbuf *rtw_cbuf_alloc(u32 size); ++void rtw_cbuf_free(struct rtw_cbuf *cbuf); ++ ++#endif ++ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/pci_hal.h b/drivers/net/wireless/rtl818x/rtl8189/include/pci_hal.h +new file mode 100644 +index 00000000..b6c95c2f +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/pci_hal.h +@@ -0,0 +1,177 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __PCI_HAL_H__ ++#define __PCI_HAL_H__ ++ ++ ++#define INTEL_VENDOR_ID 0x8086 ++#define SIS_VENDOR_ID 0x1039 ++#define ATI_VENDOR_ID 0x1002 ++#define ATI_DEVICE_ID 0x7914 ++#define AMD_VENDOR_ID 0x1022 ++ ++#define PCI_MAX_BRIDGE_NUMBER 255 ++#define PCI_MAX_DEVICES 32 ++#define PCI_MAX_FUNCTION 8 ++ ++#define PCI_CONF_ADDRESS 0x0CF8 // PCI Configuration Space Address ++#define PCI_CONF_DATA 0x0CFC // PCI Configuration Space Data ++ ++#define PCI_CLASS_BRIDGE_DEV 0x06 ++#define PCI_SUBCLASS_BR_PCI_TO_PCI 0x04 ++ ++#define PCI_CAPABILITY_ID_PCI_EXPRESS 0x10 ++ ++#define U1DONTCARE 0xFF ++#define U2DONTCARE 0xFFFF ++#define U4DONTCARE 0xFFFFFFFF ++ ++#define PCI_VENDER_ID_REALTEK 0x10ec ++ ++#define HAL_HW_PCI_8180_DEVICE_ID 0x8180 ++#define HAL_HW_PCI_8185_DEVICE_ID 0x8185 //8185 or 8185b ++#define HAL_HW_PCI_8188_DEVICE_ID 0x8188 //8185b ++#define HAL_HW_PCI_8198_DEVICE_ID 0x8198 //8185b ++#define HAL_HW_PCI_8190_DEVICE_ID 0x8190 //8190 ++#define HAL_HW_PCI_8723E_DEVICE_ID 0x8723 //8723E ++#define HAL_HW_PCI_8192_DEVICE_ID 0x8192 //8192 PCI-E ++#define HAL_HW_PCI_8192SE_DEVICE_ID 0x8192 //8192 SE ++#define HAL_HW_PCI_8174_DEVICE_ID 0x8174 //8192 SE ++#define HAL_HW_PCI_8173_DEVICE_ID 0x8173 //8191 SE Crab ++#define HAL_HW_PCI_8172_DEVICE_ID 0x8172 //8191 SE RE ++#define HAL_HW_PCI_8171_DEVICE_ID 0x8171 //8191 SE Unicron ++#define HAL_HW_PCI_0045_DEVICE_ID 0x0045 //8190 PCI for Ceraga ++#define HAL_HW_PCI_0046_DEVICE_ID 0x0046 //8190 Cardbus for Ceraga ++#define HAL_HW_PCI_0044_DEVICE_ID 0x0044 //8192e PCIE for Ceraga ++#define HAL_HW_PCI_0047_DEVICE_ID 0x0047 //8192e Express Card for Ceraga ++#define HAL_HW_PCI_700F_DEVICE_ID 0x700F ++#define HAL_HW_PCI_701F_DEVICE_ID 0x701F ++#define HAL_HW_PCI_DLINK_DEVICE_ID 0x3304 ++#define HAL_HW_PCI_8192CET_DEVICE_ID 0x8191 //8192ce ++#define HAL_HW_PCI_8192CE_DEVICE_ID 0x8178 //8192ce ++#define HAL_HW_PCI_8191CE_DEVICE_ID 0x8177 //8192ce ++#define HAL_HW_PCI_8188CE_DEVICE_ID 0x8176 //8192ce ++#define HAL_HW_PCI_8192CU_DEVICE_ID 0x8191 //8192ce ++#define HAL_HW_PCI_8192DE_DEVICE_ID 0x8193 //8192de ++#define HAL_HW_PCI_002B_DEVICE_ID 0x002B //8192de, provided by HW SD ++#define HAL_HW_PCI_8188EE_DEVICE_ID 0x8179 ++ ++#define HAL_MEMORY_MAPPED_IO_RANGE_8190PCI 0x1000 //8190 support 16 pages of IO registers ++#define HAL_HW_PCI_REVISION_ID_8190PCI 0x00 ++#define HAL_MEMORY_MAPPED_IO_RANGE_8192PCIE 0x4000 //8192 support 16 pages of IO registers ++#define HAL_HW_PCI_REVISION_ID_8192PCIE 0x01 ++#define HAL_MEMORY_MAPPED_IO_RANGE_8192SE 0x4000 //8192 support 16 pages of IO registers ++#define HAL_HW_PCI_REVISION_ID_8192SE 0x10 ++#define HAL_HW_PCI_REVISION_ID_8192CE 0x1 ++#define HAL_MEMORY_MAPPED_IO_RANGE_8192CE 0x4000 //8192 support 16 pages of IO registers ++#define HAL_HW_PCI_REVISION_ID_8192DE 0x0 ++#define HAL_MEMORY_MAPPED_IO_RANGE_8192DE 0x4000 //8192 support 16 pages of IO registers ++ ++enum pci_bridge_vendor { ++ PCI_BRIDGE_VENDOR_INTEL = 0x0,//0b'0000,0001 ++ PCI_BRIDGE_VENDOR_ATI, //= 0x02,//0b'0000,0010 ++ PCI_BRIDGE_VENDOR_AMD, //= 0x04,//0b'0000,0100 ++ PCI_BRIDGE_VENDOR_SIS ,//= 0x08,//0b'0000,1000 ++ PCI_BRIDGE_VENDOR_UNKNOWN, //= 0x40,//0b'0100,0000 ++ PCI_BRIDGE_VENDOR_MAX ,//= 0x80 ++} ; ++ ++struct rt_pci_capabilities_header { ++ u8 capability_id; ++ u8 next; ++}; ++ ++struct pci_priv{ ++ u8 linkctrl_reg; ++ ++ u8 busnumber; ++ u8 devnumber; ++ u8 funcnumber; ++ ++ u8 pcibridge_busnum; ++ u8 pcibridge_devnum; ++ u8 pcibridge_funcnum; ++ u8 pcibridge_vendor; ++ u16 pcibridge_vendorid; ++ u16 pcibridge_deviceid; ++ u8 pcibridge_pciehdr_offset; ++ u8 pcibridge_linkctrlreg; ++ ++ u8 amd_l1_patch; ++}; ++ ++typedef struct _RT_ISR_CONTENT ++{ ++ union{ ++ u32 IntArray[2]; ++ u32 IntReg4Byte; ++ u16 IntReg2Byte; ++ }; ++}RT_ISR_CONTENT, *PRT_ISR_CONTENT; ++ ++//#define RegAddr(addr) (addr + 0xB2000000UL) ++//some platform macros will def here ++static inline void NdisRawWritePortUlong(u32 port, u32 val) ++{ ++ outl(val, port); ++ //writel(val, (u8 *)RegAddr(port)); ++} ++ ++static inline void NdisRawWritePortUchar(u32 port, u8 val) ++{ ++ outb(val, port); ++ //writeb(val, (u8 *)RegAddr(port)); ++} ++ ++static inline void NdisRawReadPortUchar(u32 port, u8 *pval) ++{ ++ *pval = inb(port); ++ //*pval = readb((u8 *)RegAddr(port)); ++} ++ ++static inline void NdisRawReadPortUshort(u32 port, u16 *pval) ++{ ++ *pval = inw(port); ++ //*pval = readw((u8 *)RegAddr(port)); ++} ++ ++static inline void NdisRawReadPortUlong(u32 port, u32 *pval) ++{ ++ *pval = inl(port); ++ //*pval = readl((u8 *)RegAddr(port)); ++} ++ ++#ifdef CONFIG_RTL8192C ++void rtl8192ce_set_hal_ops(_adapter * padapter); ++#define hal_set_hal_ops rtl8192ce_set_hal_ops ++#endif ++#ifdef CONFIG_RTL8192D ++void rtl8192de_set_hal_ops(_adapter * padapter); ++#define hal_set_hal_ops rtl8192de_set_hal_ops ++#endif ++ ++ ++#ifdef CONFIG_RTL8188E ++void rtl8188ee_set_hal_ops(_adapter * padapter); ++#define hal_set_hal_ops rtl8188ee_set_hal_ops ++#endif ++ ++#endif //__PCIE_HAL_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/pci_ops.h b/drivers/net/wireless/rtl818x/rtl8189/include/pci_ops.h +new file mode 100644 +index 00000000..be8cad5e +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/pci_ops.h +@@ -0,0 +1,78 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __PCI_OPS_H_ ++#define __PCI_OPS_H_ ++ ++#include ++#include ++#include ++#include ++ ++ ++#ifdef CONFIG_RTL8188E ++u32 rtl8188ee_init_desc_ring(_adapter * padapter); ++u32 rtl8188ee_free_desc_ring(_adapter * padapter); ++void rtl8188ee_reset_desc_ring(_adapter * padapter); ++#ifdef CONFIG_64BIT_DMA ++u8 PlatformEnable88EEDMA64(PADAPTER Adapter); ++#endif ++int rtl8188ee_interrupt(PADAPTER Adapter); ++void rtl8188ee_xmit_tasklet(void *priv); ++void rtl8188ee_recv_tasklet(void *priv); ++void rtl8188ee_prepare_bcn_tasklet(void *priv); ++void rtl8188ee_set_intf_ops(struct _io_ops *pops); ++#define pci_set_intf_ops rtl8188ee_set_intf_ops ++#endif ++ ++ ++#ifdef CONFIG_RTL8192C ++u32 rtl8192ce_init_desc_ring(_adapter * padapter); ++u32 rtl8192ce_free_desc_ring(_adapter * padapter); ++void rtl8192ce_reset_desc_ring(_adapter * padapter); ++#ifdef CONFIG_64BIT_DMA ++u8 PlatformEnable92CEDMA64(PADAPTER Adapter); ++#endif ++int rtl8192ce_interrupt(PADAPTER Adapter); ++void rtl8192ce_xmit_tasklet(void *priv); ++void rtl8192ce_recv_tasklet(void *priv); ++void rtl8192ce_prepare_bcn_tasklet(void *priv); ++void rtl8192ce_set_intf_ops(struct _io_ops *pops); ++#define pci_set_intf_ops rtl8192ce_set_intf_ops ++#endif ++ ++#ifdef CONFIG_RTL8192D ++u32 rtl8192de_init_desc_ring(_adapter * padapter); ++u32 rtl8192de_free_desc_ring(_adapter * padapter); ++void rtl8192de_reset_desc_ring(_adapter * padapter); ++#ifdef CONFIG_64BIT_DMA ++u8 PlatformEnable92DEDMA64(PADAPTER Adapter); ++#endif ++int rtl8192de_interrupt(PADAPTER Adapter); ++void rtl8192de_xmit_tasklet(void *priv); ++void rtl8192de_recv_tasklet(void *priv); ++void rtl8192de_prepare_bcn_tasklet(void *priv); ++void rtl8192de_set_intf_ops(struct _io_ops *pops); ++#define pci_set_intf_ops rtl8192de_set_intf_ops ++u32 MpReadPCIDwordDBI8192D(IN PADAPTER Adapter, IN u16 Offset, IN u8 Direct); ++void MpWritePCIDwordDBI8192D(IN PADAPTER Adapter, IN u16 Offset, IN u32 Value, IN u8 Direct); ++#endif ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/pci_osintf.h b/drivers/net/wireless/rtl818x/rtl8189/include/pci_osintf.h +new file mode 100644 +index 00000000..09715af4 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/pci_osintf.h +@@ -0,0 +1,33 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __PCI_OSINTF_H ++#define __PCI_OSINTF_H ++ ++#include ++#include ++#include ++ ++ ++void rtw_pci_disable_aspm(_adapter *padapter); ++void rtw_pci_enable_aspm(_adapter *padapter); ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/recv_osdep.h b/drivers/net/wireless/rtl818x/rtl8189/include/recv_osdep.h +new file mode 100644 +index 00000000..536ed310 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/recv_osdep.h +@@ -0,0 +1,58 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RECV_OSDEP_H_ ++#define __RECV_OSDEP_H_ ++ ++#include ++#include ++#include ++ ++ ++extern sint _rtw_init_recv_priv(struct recv_priv *precvpriv, _adapter *padapter); ++extern void _rtw_free_recv_priv (struct recv_priv *precvpriv); ++ ++ ++extern s32 rtw_recv_entry(union recv_frame *precv_frame); ++extern int rtw_recv_indicatepkt(_adapter *adapter, union recv_frame *precv_frame); ++extern void rtw_recv_returnpacket(IN _nic_hdl cnxt, IN _pkt *preturnedpkt); ++ ++extern void rtw_hostapd_mlme_rx(_adapter *padapter, union recv_frame *precv_frame); ++extern void rtw_handle_tkip_mic_err(_adapter *padapter,u8 bgroup); ++ ++ ++int rtw_init_recv_priv(struct recv_priv *precvpriv, _adapter *padapter); ++void rtw_free_recv_priv (struct recv_priv *precvpriv); ++ ++ ++int rtw_os_recv_resource_init(struct recv_priv *precvpriv, _adapter *padapter); ++int rtw_os_recv_resource_alloc(_adapter *padapter, union recv_frame *precvframe); ++void rtw_os_recv_resource_free(struct recv_priv *precvpriv); ++ ++ ++int rtw_os_recvbuf_resource_alloc(_adapter *padapter, struct recv_buf *precvbuf); ++int rtw_os_recvbuf_resource_free(_adapter *padapter, struct recv_buf *precvbuf); ++ ++void rtw_os_read_port(_adapter *padapter, struct recv_buf *precvbuf); ++ ++void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl); ++ ++ ++#endif // ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_cmd.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_cmd.h +new file mode 100644 +index 00000000..9899f67b +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_cmd.h +@@ -0,0 +1,258 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8188E_CMD_H__ ++#define __RTL8188E_CMD_H__ ++ ++#if 0 ++enum cmd_msg_element_id ++{ ++ NONE_CMDMSG_EID, ++ AP_OFFLOAD_EID = 0, ++ SET_PWRMODE_EID = 1, ++ JOINBSS_RPT_EID = 2, ++ RSVD_PAGE_EID = 3, ++ RSSI_4_EID = 4, ++ RSSI_SETTING_EID = 5, ++ MACID_CONFIG_EID = 6, ++ MACID_PS_MODE_EID = 7, ++ P2P_PS_OFFLOAD_EID = 8, ++ SELECTIVE_SUSPEND_ROF_CMD = 9, ++ P2P_PS_CTW_CMD_EID = 32, ++ MAX_CMDMSG_EID ++}; ++#else ++typedef enum _RTL8188E_H2C_CMD_ID ++{ ++ //Class Common ++ H2C_COM_RSVD_PAGE =0x00, ++ H2C_COM_MEDIA_STATUS_RPT =0x01, ++ H2C_COM_SCAN =0x02, ++ H2C_COM_KEEP_ALIVE =0x03, ++ H2C_COM_DISCNT_DECISION =0x04, ++#ifndef CONFIG_WOWLAN ++ H2C_COM_WWLAN =0x05, ++#endif ++ H2C_COM_INIT_OFFLOAD =0x06, ++ H2C_COM_REMOTE_WAKE_CTL =0x07, ++ H2C_COM_AP_OFFLOAD =0x08, ++ H2C_COM_BCN_RSVD_PAGE =0x09, ++ H2C_COM_PROB_RSP_RSVD_PAGE =0x0A, ++ ++ //Class PS ++ H2C_PS_PWR_MODE =0x20, ++ H2C_PS_TUNE_PARA =0x21, ++ H2C_PS_TUNE_PARA_2 =0x22, ++ H2C_PS_LPS_PARA =0x23, ++ H2C_PS_P2P_OFFLOAD =0x24, ++ ++ //Class DM ++ H2C_DM_MACID_CFG =0x40, ++ H2C_DM_TXBF =0x41, ++ ++ //Class BT ++ H2C_BT_COEX_MASK =0x60, ++ H2C_BT_COEX_GPIO_MODE =0x61, ++ H2C_BT_DAC_SWING_VAL =0x62, ++ H2C_BT_PSD_RST =0x63, ++ ++ //Class Remote WakeUp ++#ifdef CONFIG_WOWLAN ++ H2C_COM_WWLAN =0x80, ++ H2C_COM_REMOTE_WAKE_CTRL =0x81, ++ H2C_COM_AOAC_GLOBAL_INFO =0x82, ++ H2C_COM_AOAC_RSVD_PAGE =0x83, ++#endif ++ ++ //Class ++ H2C_RESET_TSF =0xc0, ++}RTL8188E_H2C_CMD_ID; ++ ++#endif ++ ++ ++struct cmd_msg_parm { ++ u8 eid; //element id ++ u8 sz; // sz ++ u8 buf[6]; ++}; ++ ++enum{ ++ PWRS ++}; ++ ++typedef struct _SETPWRMODE_PARM { ++ u8 Mode;//0:Active,1:LPS,2:WMMPS ++ //u8 RLBM:4;//0:Min,1:Max,2: User define ++ u8 SmartPS_RLBM;//LPS=0:PS_Poll,1:PS_Poll,2:NullData,WMM=0:PS_Poll,1:NullData ++ u8 AwakeInterval; // unit: beacon interval ++ u8 bAllQueueUAPSD; ++ u8 PwrState;//AllON(0x0c),RFON(0x04),RFOFF(0x00) ++} SETPWRMODE_PARM, *PSETPWRMODE_PARM; ++ ++struct H2C_SS_RFOFF_PARAM{ ++ u8 ROFOn; // 1: on, 0:off ++ u16 gpio_period; // unit: 1024 us ++}__attribute__ ((packed)); ++ ++ ++typedef struct JOINBSSRPT_PARM{ ++ u8 OpMode; // RT_MEDIA_STATUS ++#ifdef CONFIG_WOWLAN ++ u8 MacID; // MACID ++#endif //CONFIG_WOWLAN ++}JOINBSSRPT_PARM, *PJOINBSSRPT_PARM; ++ ++typedef struct _RSVDPAGE_LOC { ++ u8 LocProbeRsp; ++ u8 LocPsPoll; ++ u8 LocNullData; ++ u8 LocQosNull; ++ u8 LocBTQosNull; ++#ifdef CONFIG_WOWLAN ++ u8 LocRemoteCtrlInfo; ++ u8 LocArpRsp; ++ u8 LocNbrAdv; ++ u8 LocGTKRsp; ++ u8 LocGTKInfo; ++ u8 LocProbeReq; ++ u8 LocNetList; ++#endif //CONFIG_WOWLAN ++} RSVDPAGE_LOC, *PRSVDPAGE_LOC; ++ ++struct P2P_PS_Offload_t { ++ u8 Offload_En:1; ++ u8 role:1; // 1: Owner, 0: Client ++ u8 CTWindow_En:1; ++ u8 NoA0_En:1; ++ u8 NoA1_En:1; ++ u8 AllStaSleep:1; // Only valid in Owner ++ u8 discovery:1; ++ u8 rsvd:1; ++}; ++ ++struct P2P_PS_CTWPeriod_t { ++ u8 CTWPeriod; //TU ++}; ++ ++ ++// host message to firmware cmd ++void rtl8188e_set_FwPwrMode_cmd(PADAPTER padapter, u8 Mode); ++void rtl8188e_set_FwJoinBssReport_cmd(PADAPTER padapter, u8 mstatus); ++u8 rtl8188e_set_rssi_cmd(PADAPTER padapter, u8 *param); ++u8 rtl8188e_set_raid_cmd(PADAPTER padapter, u32 mask); ++void rtl8188e_Add_RateATid(PADAPTER padapter, u32 bitmap, u8 arg, u8 rssi_level); ++//u8 rtl8192c_set_FwSelectSuspend_cmd(PADAPTER padapter, u8 bfwpoll, u16 period); ++ ++ ++#ifdef CONFIG_P2P ++void rtl8188e_set_p2p_ps_offload_cmd(PADAPTER padapter, u8 p2p_ps_state); ++#endif //CONFIG_P2P ++ ++void CheckFwRsvdPageContent(PADAPTER padapter); ++void rtl8188e_set_FwMediaStatus_cmd(PADAPTER padapter, u16 mstatus_rpt ); ++ ++#ifdef CONFIG_TSF_RESET_OFFLOAD ++//u8 rtl8188e_reset_tsf(_adapter *padapter, u8 reset_port); ++int reset_tsf(PADAPTER Adapter, u8 reset_port ); ++#endif // CONFIG_TSF_RESET_OFFLOAD ++ ++#define H2C_8188E_RSVDPAGE_LOC_LEN 5 ++#define H2C_8188E_AOAC_RSVDPAGE_LOC_LEN 7 ++ ++#ifdef CONFIG_WOWLAN ++typedef struct _SETWOWLAN_PARM{ ++ u8 mode; ++ u8 gpio_index; ++ u8 gpio_duration; ++ u8 second_mode; ++ u8 reserve; ++}SETWOWLAN_PARM, *PSETWOWLAN_PARM; ++ ++typedef struct _SETAOAC_GLOBAL_INFO{ ++ u8 pairwiseEncAlg; ++ u8 groupEncAlg; ++}SETAOAC_GLOBAL_INFO, *PSETAOAC_GLOBAL_INFO; ++ ++#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 ) ++#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5]) ++#define cpIpAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3]) ++ ++// ++// ARP packet ++// ++// LLC Header ++#define GET_ARP_PKT_LLC_TYPE(__pHeader) ReadEF2Byte( ((u8*)(__pHeader)) + 6) ++ ++//ARP element ++#define GET_ARP_PKT_OPERATION(__pHeader) ReadEF2Byte( ((u8*)(__pHeader)) + 6) ++#define GET_ARP_PKT_SENDER_MAC_ADDR(__pHeader, _val) cpMacAddr((u8*)(_val), ((u8*)(__pHeader))+8) ++#define GET_ARP_PKT_SENDER_IP_ADDR(__pHeader, _val) cpIpAddr((u8*)(_val), ((u8*)(__pHeader))+14) ++#define GET_ARP_PKT_TARGET_MAC_ADDR(__pHeader, _val) cpMacAddr((u8*)(_val), ((u8*)(__pHeader))+18) ++#define SET_ARP_PKT_HW(__pHeader, __Value) WriteEF2Byte( ((u8*)(__pHeader)) + 0, __Value) ++#define SET_ARP_PKT_PROTOCOL(__pHeader, __Value) WriteEF2Byte( ((u8*)(__pHeader)) + 2, __Value) ++#define SET_ARP_PKT_HW_ADDR_LEN(__pHeader, __Value) WriteEF1Byte( ((u8*)(__pHeader)) + 4, __Value) ++#define SET_ARP_PKT_PROTOCOL_ADDR_LEN(__pHeader, __Value) WriteEF1Byte( ((u8*)(__pHeader)) + 5, __Value) ++#define SET_ARP_PKT_OPERATION(__pHeader, __Value) WriteEF2Byte( ((u8*)(__pHeader)) + 6, __Value) ++#define SET_ARP_PKT_SENDER_MAC_ADDR(__pHeader, _val) cpMacAddr(((u8*)(__pHeader))+8, (u8*)(_val)) ++#define SET_ARP_PKT_SENDER_IP_ADDR(__pHeader, _val) cpIpAddr(((u8*)(__pHeader))+14, (u8*)(_val)) ++#define SET_ARP_PKT_TARGET_MAC_ADDR(__pHeader, _val) cpMacAddr(((u8*)(__pHeader))+18, (u8*)(_val)) ++#define SET_ARP_PKT_TARGET_IP_ADDR(__pHeader, _val) cpIpAddr(((u8*)(__pHeader))+24, (u8*)(_val)) ++ ++#define FW_WOWLAN_FUN_EN BIT(0) ++#define FW_WOWLAN_PATTERN_MATCH BIT(1) ++#define FW_WOWLAN_MAGIC_PKT BIT(2) ++#define FW_WOWLAN_UNICAST BIT(3) ++#define FW_WOWLAN_ALL_PKT_DROP BIT(4) ++#define FW_WOWLAN_GPIO_ACTIVE BIT(5) ++#define FW_WOWLAN_REKEY_WAKEUP BIT(6) ++#define FW_WOWLAN_DEAUTH_WAKEUP BIT(7) ++ ++#define FW_WOWLAN_GPIO_WAKEUP_EN BIT(0) ++#define FW_FW_PARSE_MAGIC_PKT BIT(1) ++ ++#define FW_WOWLAN_KEEP_ALIVE_EN BIT(0) ++#define FW_WOWLAN_KEEP_ALIVE_PKT_TYPE BIT(2) ++ ++#define FW_REMOTE_WAKE_CTRL_EN BIT(0) ++#define FW_ARP_EN BIT(1) ++#define FW_REALWOWLAN_EN BIT(5) ++#define FW_WOW_FW_UNICAST_EN BIT(7) ++ ++#define FW_ADOPT_USER BIT(1) ++void rtl8188es_set_wowlan_cmd(_adapter* padapter, u8 enable); ++void SetFwRelatedForWoWLAN8188ES(_adapter* padapter, u8 bHostIsGoingtoSleep); ++#endif//CONFIG_WOWLAN ++ ++//---------------------------------------------------------------------------------------------------------// ++//---------------------------------- H2C CMD CONTENT --------------------------------------------------// ++//---------------------------------------------------------------------------------------------------------// ++//_RSVDPAGE_LOC_CMD_0x00 ++#define SET_8188E_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 8, __Value) ++#define SET_8188E_H2CCMD_RSVDPAGE_LOC_PSPOLL(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 0, 8, __Value) ++#define SET_8188E_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+2, 0, 8, __Value) ++#define SET_8188E_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+3, 0, 8, __Value) ++ ++// AOAC_RSVDPAGE_LOC_0x83 ++#define SET_8188E_H2CCMD_AOAC_RSVDPAGE_LOC_REMOTE_WAKE_CTRL_INFO(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd), 0, 8, __Value) ++#define SET_8188E_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 0, 8, __Value) ++ ++#endif//__RTL8188E_CMD_H__ ++ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_dm.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_dm.h +new file mode 100644 +index 00000000..d35d27fa +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_dm.h +@@ -0,0 +1,179 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8188E_DM_H__ ++#define __RTL8188E_DM_H__ ++enum{ ++ UP_LINK, ++ DOWN_LINK, ++}; ++//###### duplicate code,will move to ODM ######### ++#define IQK_MAC_REG_NUM 4 ++#define IQK_ADDA_REG_NUM 16 ++#define IQK_BB_REG_NUM 9 ++#define HP_THERMAL_NUM 8 ++//###### duplicate code,will move to ODM ######### ++struct dm_priv ++{ ++ u8 DM_Type; ++ u8 DMFlag; ++ u8 InitDMFlag; ++ u32 InitODMFlag; ++ ++ //* Upper and Lower Signal threshold for Rate Adaptive*/ ++ int UndecoratedSmoothedPWDB; ++ int UndecoratedSmoothedCCK; ++ int EntryMinUndecoratedSmoothedPWDB; ++ int EntryMaxUndecoratedSmoothedPWDB; ++ int MinUndecoratedPWDBForDM; ++ int LastMinUndecoratedPWDBForDM; ++ ++//###### duplicate code,will move to ODM ######### ++/* ++ //for DIG ++ u8 bDMInitialGainEnable; ++ u8 binitialized; // for dm_initial_gain_Multi_STA use. ++ DIG_T DM_DigTable; ++ ++ PS_T DM_PSTable; ++ ++ FALSE_ALARM_STATISTICS FalseAlmCnt; ++ ++ //for rate adaptive, in fact, 88c/92c fw will handle this ++ u8 bUseRAMask; ++ RATE_ADAPTIVE RateAdaptive; ++*/ ++ //for High Power ++ u8 bDynamicTxPowerEnable; ++ u8 LastDTPLvl; ++ u8 DynamicTxHighPowerLvl;//Add by Jacken Tx Power Control for Near/Far Range 2008/03/06 ++ u8 PowerIndex_backup[6]; ++ u8 TxPowerTrackControl; //for mp mode, turn off txpwrtracking as default ++#if 0 ++ //for tx power tracking ++ u8 bTXPowerTracking; ++ u8 TXPowercount; ++ u8 bTXPowerTrackingInit; ++ ++ ++ u8 TM_Trigger; ++ ++ u8 ThermalMeter[2]; // ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 ++ u8 ThermalValue; ++ u8 ThermalValue_LCK; ++ u8 ThermalValue_IQK; ++ u8 ThermalValue_DPK; ++ ++ u8 bRfPiEnable; ++ ++ //for APK ++ u32 APKoutput[2][2]; //path A/B; output1_1a/output1_2a ++ u8 bAPKdone; ++ u8 bAPKThermalMeterIgnore; ++ u8 bDPdone; ++ u8 bDPPathAOK; ++ u8 bDPPathBOK; ++ ++ //for IQK ++ u32 RegC04; ++ u32 Reg874; ++ u32 RegC08; ++ u32 RegB68; ++ u32 RegB6C; ++ u32 Reg870; ++ u32 Reg860; ++ u32 Reg864; ++ u32 ADDA_backup[IQK_ADDA_REG_NUM]; ++ u32 IQK_MAC_backup[IQK_MAC_REG_NUM]; ++ u32 IQK_BB_backup_recover[9]; ++ u32 IQK_BB_backup[IQK_BB_REG_NUM]; ++ ++ ++ u8 bCCKinCH14; ++ ++ u8 CCK_index; ++ u8 OFDM_index[2]; ++ ++ u8 bDoneTxpower; ++ u8 CCK_index_HP; ++ u8 OFDM_index_HP[2]; ++ u8 ThermalValue_HP[HP_THERMAL_NUM]; ++ u8 ThermalValue_HP_index; ++ ++ //for TxPwrTracking ++ s32 RegE94; ++ s32 RegE9C; ++ s32 RegEB4; ++ s32 RegEBC; ++ ++ u32 TXPowerTrackingCallbackCnt; //cosa add for debug ++ ++ u32 prv_traffic_idx; // edca turbo ++ ++/* ++ // for dm_RF_Saving ++ u8 initialize; ++ u32 rf_saving_Reg874; ++ u32 rf_saving_RegC70; ++ u32 rf_saving_Reg85C; ++ u32 rf_saving_RegA74; ++*/ ++ //for Antenna diversity ++#ifdef CONFIG_ANTENNA_DIVERSITY ++// SWAT_T DM_SWAT_Table; ++#endif ++#ifdef CONFIG_SW_ANTENNA_DIVERSITY ++// _timer SwAntennaSwitchTimer; ++/* ++ u64 lastTxOkCnt; ++ u64 lastRxOkCnt; ++ u64 TXByteCnt_A; ++ u64 TXByteCnt_B; ++ u64 RXByteCnt_A; ++ u64 RXByteCnt_B; ++ u8 DoubleComfirm; ++ u8 TrafficLoad; ++*/ ++#endif ++ ++ s32 OFDM_Pkt_Cnt; ++ u8 RSSI_Select; ++// u8 DIG_Dynamic_MIN ; ++//###### duplicate code,will move to ODM ######### ++#endif ++ // Add for Reading Initial Data Rate SEL Register 0x484 during watchdog. Using for fill tx desc. 2011.3.21 by Thomas ++ //u8 INIDATA_RATE[32]; ++}; ++ ++ ++void rtl8188e_init_dm_priv(IN PADAPTER Adapter); ++void rtl8188e_deinit_dm_priv(IN PADAPTER Adapter); ++void rtl8188e_InitHalDm(IN PADAPTER Adapter); ++void rtl8188e_HalDmWatchDog(IN PADAPTER Adapter); ++ ++//VOID rtl8192c_dm_CheckTXPowerTracking(IN PADAPTER Adapter); ++ ++//void rtl8192c_dm_RF_Saving(IN PADAPTER pAdapter, IN u8 bForceInNormal); ++ ++#ifdef CONFIG_ANTENNA_DIVERSITY ++void AntDivCompare8188E(PADAPTER Adapter, WLAN_BSSID_EX *dst, WLAN_BSSID_EX *src); ++u8 AntDivBeforeLink8188E(PADAPTER Adapter ); ++#endif ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_hal.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_hal.h +new file mode 100644 +index 00000000..3c7d574b +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_hal.h +@@ -0,0 +1,715 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8188E_HAL_H__ ++#define __RTL8188E_HAL_H__ ++ ++ ++//include HAL Related header after HAL Related compiling flags ++#include "rtl8188e_spec.h" ++#include "Hal8188EPhyReg.h" ++#include "Hal8188EPhyCfg.h" ++#include "rtl8188e_rf.h" ++#include "rtl8188e_dm.h" ++#include "rtl8188e_recv.h" ++#include "rtl8188e_xmit.h" ++#include "rtl8188e_cmd.h" ++#include "Hal8188EPwrSeq.h" ++#ifdef DBG_CONFIG_ERROR_DETECT ++#include "rtl8188e_sreset.h" ++#endif ++#include "rtw_efuse.h" ++ ++#include "../hal/OUTSRC/odm_precomp.h" ++ ++ // Fw Array ++ #define Rtl8188E_FwImageArray Rtl8188EFwImgArray ++ #define Rtl8188E_FWImgArrayLength Rtl8188EFWImgArrayLength ++#ifdef CONFIG_WOWLAN ++ #define Rtl8188E_FwWoWImageArray Array_8188E_FW_WoWLAN ++ #define Rtl8188E_FwWoWImgArrayLength ArrayLength_8188E_FW_WoWLAN ++#endif //CONFIG_WOWLAN ++ ++ ++#ifdef CONFIG_SDIO_HCI ++ ++ //TODO: We should define 8188ES firmware related macro settings here!! ++ //TODO: The following need to check!! ++ #define RTL8188E_FW_UMC_IMG "rtl8188E\\rtl8188efw.bin" ++ #define RTL8188E_PHY_REG "rtl8188E\\PHY_REG_1T.txt" ++ #define RTL8188E_PHY_RADIO_A "rtl8188E\\radio_a_1T.txt" ++ #define RTL8188E_PHY_RADIO_B "rtl8188E\\radio_b_1T.txt" ++ #define RTL8188E_AGC_TAB "rtl8188E\\AGC_TAB_1T.txt" ++ #define RTL8188E_PHY_MACREG "rtl8188E\\MAC_REG.txt" ++ #define RTL8188E_PHY_REG_PG "rtl8188E\\PHY_REG_PG.txt" ++ #define RTL8188E_PHY_REG_MP "rtl8188E\\PHY_REG_MP.txt" ++ ++//--------------------------------------------------------------------- ++// RTL8188E From header ++//--------------------------------------------------------------------- ++#if 0 ++ #define Rtl8188E_PHY_REG_Array_PG Rtl8188ESPHY_REG_Array_PG ++ #define Rtl8188E_PHY_REG_Array_PGLength Rtl8188ESPHY_REG_Array_PGLength ++ ++#endif ++ ++ //--------------------------------------------------------------------- ++ // RTL8188E Power Configuration CMDs for USB/SDIO interfaces ++ //--------------------------------------------------------------------- ++ #define Rtl8188E_NIC_PWR_ON_FLOW rtl8188E_power_on_flow ++ #define Rtl8188E_NIC_RF_OFF_FLOW rtl8188E_radio_off_flow ++ #define Rtl8188E_NIC_DISABLE_FLOW rtl8188E_card_disable_flow ++ #define Rtl8188E_NIC_ENABLE_FLOW rtl8188E_card_enable_flow ++ #define Rtl8188E_NIC_SUSPEND_FLOW rtl8188E_suspend_flow ++ #define Rtl8188E_NIC_RESUME_FLOW rtl8188E_resume_flow ++ #define Rtl8188E_NIC_PDN_FLOW rtl8188E_hwpdn_flow ++ #define Rtl8188E_NIC_LPS_ENTER_FLOW rtl8188E_enter_lps_flow ++ #define Rtl8188E_NIC_LPS_LEAVE_FLOW rtl8188E_leave_lps_flow ++ ++#elif defined(CONFIG_USB_HCI) ++ #define RTL8188E_FW_UMC_IMG "rtl8188E\\rtl8188efw.bin" ++ #define RTL8188E_PHY_REG "rtl8188E\\PHY_REG_1T.txt" ++ #define RTL8188E_PHY_RADIO_A "rtl8188E\\radio_a_1T.txt" ++ #define RTL8188E_PHY_RADIO_B "rtl8188E\\radio_b_1T.txt" ++ #define RTL8188E_AGC_TAB "rtl8188E\\AGC_TAB_1T.txt" ++ #define RTL8188E_PHY_MACREG "rtl8188E\\MAC_REG.txt" ++ #define RTL8188E_PHY_REG_PG "rtl8188E\\PHY_REG_PG.txt" ++ #define RTL8188E_PHY_REG_MP "rtl8188E\\PHY_REG_MP.txt" ++ ++#if 0 ++ #define Rtl8188E_PHY_REG_Array_PG Rtl8188EUPHY_REG_Array_PG ++ #define Rtl8188E_PHY_REG_Array_PGLength Rtl8188EUPHY_REG_Array_PGLength ++ ++#endif ++ ++ //--------------------------------------------------------------------- ++ // RTL8188E Power Configuration CMDs for USB/SDIO interfaces ++ //--------------------------------------------------------------------- ++ #define Rtl8188E_NIC_PWR_ON_FLOW rtl8188E_power_on_flow ++ #define Rtl8188E_NIC_RF_OFF_FLOW rtl8188E_radio_off_flow ++ #define Rtl8188E_NIC_DISABLE_FLOW rtl8188E_card_disable_flow ++ #define Rtl8188E_NIC_ENABLE_FLOW rtl8188E_card_enable_flow ++ #define Rtl8188E_NIC_SUSPEND_FLOW rtl8188E_suspend_flow ++ #define Rtl8188E_NIC_RESUME_FLOW rtl8188E_resume_flow ++ #define Rtl8188E_NIC_PDN_FLOW rtl8188E_hwpdn_flow ++ #define Rtl8188E_NIC_LPS_ENTER_FLOW rtl8188E_enter_lps_flow ++ #define Rtl8188E_NIC_LPS_LEAVE_FLOW rtl8188E_leave_lps_flow ++ ++#elif defined(CONFIG_PCI_HCI) ++ #define RTL8188E_FW_UMC_IMG "rtl8188E\\rtl8188efw.bin" ++ #define RTL8188E_PHY_REG "rtl8188E\\PHY_REG_1T.txt" ++ #define RTL8188E_PHY_RADIO_A "rtl8188E\\radio_a_1T.txt" ++ #define RTL8188E_PHY_RADIO_B "rtl8188E\\radio_b_1T.txt" ++ #define RTL8188E_AGC_TAB "rtl8188E\\AGC_TAB_1T.txt" ++ #define RTL8188E_PHY_MACREG "rtl8188E\\MAC_REG.txt" ++ #define RTL8188E_PHY_REG_PG "rtl8188E\\PHY_REG_PG.txt" ++ #define RTL8188E_PHY_REG_MP "rtl8188E\\PHY_REG_MP.txt" ++ ++ #define Rtl8188E_PHY_REG_Array_PG Rtl8188EEPHY_REG_Array_PG ++ #define Rtl8188E_PHY_REG_Array_PGLength Rtl8188EEPHY_REG_Array_PGLength ++ ++ ++ #ifndef CONFIG_PHY_SETTING_WITH_ODM ++ #if MP_DRIVER == 1 ++ #define Rtl8188ES_PHY_REG_Array_MP Rtl8188ESPHY_REG_Array_MP ++ #endif ++ #endif ++ ++ //--------------------------------------------------------------------- ++ // RTL8188E Power Configuration CMDs for USB/SDIO/PCIE interfaces ++ //--------------------------------------------------------------------- ++ #define Rtl8188E_NIC_PWR_ON_FLOW rtl8188E_power_on_flow ++ #define Rtl8188E_NIC_RF_OFF_FLOW rtl8188E_radio_off_flow ++ #define Rtl8188E_NIC_DISABLE_FLOW rtl8188E_card_disable_flow ++ #define Rtl8188E_NIC_ENABLE_FLOW rtl8188E_card_enable_flow ++ #define Rtl8188E_NIC_SUSPEND_FLOW rtl8188E_suspend_flow ++ #define Rtl8188E_NIC_RESUME_FLOW rtl8188E_resume_flow ++ #define Rtl8188E_NIC_PDN_FLOW rtl8188E_hwpdn_flow ++ #define Rtl8188E_NIC_LPS_ENTER_FLOW rtl8188E_enter_lps_flow ++ #define Rtl8188E_NIC_LPS_LEAVE_FLOW rtl8188E_leave_lps_flow ++#endif //CONFIG_***_HCI ++ ++ ++#define DRVINFO_SZ 4 // unit is 8bytes ++#define PageNum_128(_Len) (u32)(((_Len)>>7) + ((_Len)&0x7F ? 1:0)) ++ ++ ++#if 1 // download firmware related data structure ++#define FW_8188E_SIZE 0x4000 //16384,16k ++#define FW_8188E_START_ADDRESS 0x1000 ++#define FW_8188E_END_ADDRESS 0x1FFF //0x5FFF ++ ++#define MAX_PAGE_SIZE 4096 // @ page : 4k bytes ++ ++#define IS_FW_HEADER_EXIST(_pFwHdr) ((le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x92C0 ||\ ++ (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x88C0 ||\ ++ (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x2300 ||\ ++ (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x88E0) ++ ++typedef enum _FIRMWARE_SOURCE { ++ FW_SOURCE_IMG_FILE = 0, ++ FW_SOURCE_HEADER_FILE = 1, //from header file ++} FIRMWARE_SOURCE, *PFIRMWARE_SOURCE; ++ ++typedef struct _RT_FIRMWARE { ++ FIRMWARE_SOURCE eFWSource; ++#ifdef CONFIG_EMBEDDED_FWIMG ++ u8* szFwBuffer; ++#else ++ u8 szFwBuffer[FW_8188E_SIZE]; ++#endif ++ u32 ulFwLength; ++ ++#ifdef CONFIG_WOWLAN ++ u8* szWoWLANFwBuffer; ++ u32 ulWoWLANFwLength; ++#endif //CONFIG_WOWLAN ++} RT_FIRMWARE, *PRT_FIRMWARE, RT_FIRMWARE_8188E, *PRT_FIRMWARE_8188E; ++ ++// ++// This structure must be cared byte-ordering ++// ++ ++typedef struct _RT_8188E_FIRMWARE_HDR ++{ ++ // 8-byte alinment required ++ ++ //--- LONG WORD 0 ---- ++ u16 Signature; // 92C0: test chip; 92C, 88C0: test chip; 88C1: MP A-cut; 92C1: MP A-cut ++ u8 Category; // AP/NIC and USB/PCI ++ u8 Function; // Reserved for different FW function indcation, for further use when driver needs to download different FW in different conditions ++ u16 Version; // FW Version ++ u8 Subversion; // FW Subversion, default 0x00 ++ u16 Rsvd1; ++ ++ ++ //--- LONG WORD 1 ---- ++ u8 Month; // Release time Month field ++ u8 Date; // Release time Date field ++ u8 Hour; // Release time Hour field ++ u8 Minute; // Release time Minute field ++ u16 RamCodeSize; // The size of RAM code ++ u8 Foundry; ++ u8 Rsvd2; ++ ++ //--- LONG WORD 2 ---- ++ u32 SvnIdx; // The SVN entry index ++ u32 Rsvd3; ++ ++ //--- LONG WORD 3 ---- ++ u32 Rsvd4; ++ u32 Rsvd5; ++}RT_8188E_FIRMWARE_HDR, *PRT_8188E_FIRMWARE_HDR; ++#endif // download firmware related data structure ++ ++ ++#define DRIVER_EARLY_INT_TIME 0x05 ++#define BCN_DMA_ATIME_INT_TIME 0x02 ++ ++#ifdef CONFIG_USB_RX_AGGREGATION ++ ++typedef enum _USB_RX_AGG_MODE{ ++ USB_RX_AGG_DISABLE, ++ USB_RX_AGG_DMA, ++ USB_RX_AGG_USB, ++ USB_RX_AGG_MIX ++}USB_RX_AGG_MODE; ++ ++//#define MAX_RX_DMA_BUFFER_SIZE 10240 // 10K for 8192C RX DMA buffer ++ ++#endif ++ ++ ++#define MAX_RX_DMA_BUFFER_SIZE_88E (1024*256) //9k for 88E nornal chip , //MaxRxBuff=10k-max(TxReportSize(64*8), WOLPattern(16*24)) ++ ++//modify by liming 1k --> 16k ++#define MAX_TX_REPORT_BUFFER_SIZE (1024*32) // 1k ++ ++//modify by liming 9 --> 300 ++// BK, BE, VI, VO, HCCA, MANAGEMENT, COMMAND, HIGH, BEACON. ++#define MAX_TX_QUEUE 800 ++ ++#define TX_SELE_HQ BIT(0) // High Queue ++#define TX_SELE_LQ BIT(1) // Low Queue ++#define TX_SELE_NQ BIT(2) // Normal Queue ++ ++// Note: We will divide number of page equally for each queue other than public queue! ++// 22k = 22528 bytes = 176 pages (@page = 128 bytes) ++// must reserved about 7 pages for LPS => 176-7 = 169 (0xA9) ++// 2*BCN / 1*ps-poll / 1*null-data /1*prob_rsp /1*QOS null-data /1*BT QOS null-data ++ ++#define TX_TOTAL_PAGE_NUMBER_88E 0xA9// 169 (21632=> 21k) ++ ++#ifdef RTL8188ES_MAC_LOOPBACK ++#define TX_PAGE_BOUNDARY_88E 0x48 //72 ++#else //TX_PAGE_BOUNDARY_LOOPBACK_MODE ++#define TX_PAGE_BOUNDARY_88E (TX_TOTAL_PAGE_NUMBER_88E + 1) ++#endif ++ ++ ++//Note: For Normal Chip Setting ,modify later ++#define WMM_NORMAL_TX_TOTAL_PAGE_NUMBER TX_TOTAL_PAGE_NUMBER_88E //0xA9 , 0xb0=>176=>22k ++#define WMM_NORMAL_TX_PAGE_BOUNDARY_88E (WMM_NORMAL_TX_TOTAL_PAGE_NUMBER + 1) //0xA9 ++ ++ ++ ++//------------------------------------------------------------------------- ++// Chip specific ++//------------------------------------------------------------------------- ++#define CHIP_BONDING_IDENTIFIER(_value) (((_value)>>22)&0x3) ++#define CHIP_BONDING_92C_1T2R 0x1 ++#define CHIP_BONDING_88C_USB_MCARD 0x2 ++#define CHIP_BONDING_88C_USB_HP 0x1 ++#include "HalVerDef.h" ++#include "hal_com.h" ++ ++//------------------------------------------------------------------------- ++// Channel Plan ++//------------------------------------------------------------------------- ++enum ChannelPlan ++{ ++ CHPL_FCC = 0, ++ CHPL_IC = 1, ++ CHPL_ETSI = 2, ++ CHPL_SPAIN = 3, ++ CHPL_FRANCE = 4, ++ CHPL_MKK = 5, ++ CHPL_MKK1 = 6, ++ CHPL_ISRAEL = 7, ++ CHPL_TELEC = 8, ++ CHPL_GLOBAL = 9, ++ CHPL_WORLD = 10, ++}; ++ ++typedef struct _TxPowerInfo ++{ ++ u8 CCKIndex[RF_PATH_MAX][CHANNEL_GROUP_MAX_88E]; ++ u8 HT40_1SIndex[RF_PATH_MAX][CHANNEL_GROUP_MAX_88E]; ++ u8 HT40_2SIndexDiff[RF_PATH_MAX][CHANNEL_GROUP_MAX_88E]; ++ u8 HT20IndexDiff[RF_PATH_MAX][CHANNEL_GROUP_MAX_88E]; ++ u8 OFDMIndexDiff[RF_PATH_MAX][CHANNEL_GROUP_MAX_88E]; ++ u8 HT40MaxOffset[RF_PATH_MAX][CHANNEL_GROUP_MAX_88E]; ++ u8 HT20MaxOffset[RF_PATH_MAX][CHANNEL_GROUP_MAX_88E]; ++ u8 TSSI_A[3]; ++ u8 TSSI_B[3]; ++ u8 TSSI_A_5G[3]; //5GL/5GM/5GH ++ u8 TSSI_B_5G[3]; ++} TxPowerInfo, *PTxPowerInfo; ++ ++typedef struct _TxPowerInfo24G{ ++ u1Byte IndexCCK_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; ++ u1Byte IndexBW40_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G-1]; ++ //If only one tx, only BW20 and OFDM are used. ++ s1Byte CCK_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s1Byte OFDM_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s1Byte BW20_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s1Byte BW40_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++}TxPowerInfo24G, *PTxPowerInfo24G; ++ ++#define EFUSE_REAL_CONTENT_LEN 512 ++#define EFUSE_MAP_LEN 128 ++#define EFUSE_MAX_SECTION 16 ++#define EFUSE_IC_ID_OFFSET 506 //For some inferiority IC purpose. added by Roger, 2009.09.02. ++#define AVAILABLE_EFUSE_ADDR(addr) (addr < EFUSE_REAL_CONTENT_LEN) ++// ++// ++// To prevent out of boundary programming case, ++// leave 1byte and program full section ++// 9bytes + 1byt + 5bytes and pre 1byte. ++// For worst case: ++// | 1byte|----8bytes----|1byte|--5bytes--| ++// | | Reserved(14bytes) | ++// ++#define EFUSE_OOB_PROTECT_BYTES 15 // PG data exclude header, dummy 6 bytes frome CP test and reserved 1byte. ++ ++#define HWSET_MAX_SIZE_88E 512 ++ ++#define EFUSE_REAL_CONTENT_LEN_88E 256 ++#define EFUSE_MAP_LEN_88E 512 ++#define EFUSE_MAX_SECTION_88E 64 ++#define EFUSE_MAX_WORD_UNIT_88E 4 ++#define EFUSE_IC_ID_OFFSET_88E 506 //For some inferiority IC purpose. added by Roger, 2009.09.02. ++#define AVAILABLE_EFUSE_ADDR_88E(addr) (addr < EFUSE_REAL_CONTENT_LEN_88E) ++// To prevent out of boundary programming case, leave 1byte and program full section ++// 9bytes + 1byt + 5bytes and pre 1byte. ++// For worst case: ++// | 2byte|----8bytes----|1byte|--7bytes--| //92D ++#define EFUSE_OOB_PROTECT_BYTES_88E 18 // PG data exclude header, dummy 7 bytes frome CP test and reserved 1byte. ++#define EFUSE_PROTECT_BYTES_BANK_88E 16 ++ ++ ++//======================================================== ++// EFUSE for BT definition ++//======================================================== ++#define EFUSE_BT_REAL_CONTENT_LEN 1536 // 512*3 ++#define EFUSE_BT_MAP_LEN 1024 // 1k bytes ++#define EFUSE_BT_MAX_SECTION 128 // 1024/8 ++ ++#define EFUSE_PROTECT_BYTES_BANK 16 ++ ++// ++// For RTL8723 WiFi/BT/GPS multi-function configuration. 2010.10.06. ++// ++typedef enum _RT_MULTI_FUNC { ++ RT_MULTI_FUNC_NONE = 0x00, ++ RT_MULTI_FUNC_WIFI = 0x01, ++ RT_MULTI_FUNC_BT = 0x02, ++ RT_MULTI_FUNC_GPS = 0x04, ++} RT_MULTI_FUNC, *PRT_MULTI_FUNC; ++ ++// ++// For RTL8723 WiFi PDn/GPIO polarity control configuration. 2010.10.08. ++// ++typedef enum _RT_POLARITY_CTL { ++ RT_POLARITY_LOW_ACT = 0, ++ RT_POLARITY_HIGH_ACT = 1, ++} RT_POLARITY_CTL, *PRT_POLARITY_CTL; ++ ++// For RTL8723 regulator mode. by tynli. 2011.01.14. ++typedef enum _RT_REGULATOR_MODE { ++ RT_SWITCHING_REGULATOR = 0, ++ RT_LDO_REGULATOR = 1, ++} RT_REGULATOR_MODE, *PRT_REGULATOR_MODE; ++ ++ ++typedef struct hal_data_8188e ++{ ++ HAL_VERSION VersionID; ++ RT_MULTI_FUNC MultiFunc; // For multi-function consideration. ++ RT_POLARITY_CTL PolarityCtl; // For Wifi PDn Polarity control. ++ RT_REGULATOR_MODE RegulatorMode; // switching regulator or LDO ++ u16 CustomerID; ++ ++ u16 FirmwareVersion; ++ u16 FirmwareVersionRev; ++ u16 FirmwareSubVersion; ++ u16 FirmwareSignature; ++ u8 PGMaxGroup; ++ //current WIFI_PHY values ++ u32 ReceiveConfig; ++ WIRELESS_MODE CurrentWirelessMode; ++ HT_CHANNEL_WIDTH CurrentChannelBW; ++ u8 CurrentChannel; ++ u8 nCur40MhzPrimeSC;// Control channel sub-carrier ++ ++ u16 BasicRateSet; ++ ++ //rf_ctrl ++ u8 rf_chip; ++ u8 rf_type; ++ u8 NumTotalRFPath; ++ ++ u8 BoardType; ++ ++ // ++ // EEPROM setting. ++ // ++ u16 EEPROMVID; ++ u16 EEPROMPID; ++ u16 EEPROMSVID; ++ u16 EEPROMSDID; ++ u8 EEPROMCustomerID; ++ u8 EEPROMSubCustomerID; ++ u8 EEPROMVersion; ++ u8 EEPROMRegulatory; ++ ++ u8 bTXPowerDataReadFromEEPORM; ++ u8 EEPROMThermalMeter; ++ u8 bAPKThermalMeterIgnore; ++ ++ BOOLEAN EepromOrEfuse; ++ u8 EfuseMap[2][HWSET_MAX_SIZE_512]; //92C:256bytes, 88E:512bytes, we use union set (512bytes) ++ u8 EfuseUsedPercentage; ++ EFUSE_HAL EfuseHal; ++ ++ //u8 bIQKInitialized; ++ ++ ++ u8 Index24G_CCK_Base[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; ++ u8 Index24G_BW40_Base[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; ++ //If only one tx, only BW20 and OFDM are used. ++ s8 CCK_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 OFDM_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 BW20_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 BW40_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ ++ u8 TxPwrLevelCck[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ u8 TxPwrLevelHT40_1S[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; // For HT 40MHZ pwr ++ u8 TxPwrLevelHT40_2S[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; // For HT 40MHZ pwr ++ u8 TxPwrHt20Diff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];// HT 20<->40 Pwr diff ++ u8 TxPwrLegacyHtDiff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];// For HT<->legacy pwr diff ++ // For power group ++ u8 PwrGroupHT20[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ u8 PwrGroupHT40[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ ++ u8 LegacyHTTxPowerDiff;// Legacy to HT rate power diff ++ // The current Tx Power Level ++ u8 CurrentCckTxPwrIdx; ++ u8 CurrentOfdm24GTxPwrIdx; ++ u8 CurrentBW2024GTxPwrIdx; ++ u8 CurrentBW4024GTxPwrIdx; ++ ++ ++ // Read/write are allow for following hardware information variables ++ u8 framesync; ++ u32 framesyncC34; ++ u8 framesyncMonitor; ++ u8 DefaultInitialGain[4]; ++ u8 pwrGroupCnt; ++ u32 MCSTxPowerLevelOriginalOffset[MAX_PG_GROUP][16]; ++ u32 CCKTxPowerLevelOriginalOffset; ++ ++ u8 CrystalCap; ++ u32 AntennaTxPath; // Antenna path Tx ++ u32 AntennaRxPath; // Antenna path Rx ++ u8 BluetoothCoexist; ++ u8 ExternalPA; ++ ++ u8 bLedOpenDrain; // Support Open-drain arrangement for controlling the LED. Added by Roger, 2009.10.16. ++ ++ //u32 LedControlNum; ++ //u32 LedControlMode; ++ //u32 TxPowerTrackControl; ++ u8 b1x1RecvCombine; // for 1T1R receive combining ++ ++ //u8 bCurrentTurboEDCA; ++ u32 AcParam_BE; //Original parameter for BE, use for EDCA turbo. ++ ++ BB_REGISTER_DEFINITION_T PHYRegDef[4]; //Radio A/B/C/D ++ ++ u32 RfRegChnlVal[2]; ++ ++ //RDG enable ++ BOOLEAN bRDGEnable; ++ ++ //for host message to fw ++ u8 LastHMEBoxNum; ++ ++ u8 fw_ractrl; ++ u8 RegTxPause; ++ // Beacon function related global variable. ++ u32 RegBcnCtrlVal; ++ u8 RegFwHwTxQCtrl; ++ u8 RegReg542; ++ u8 RegCR_1; ++ ++ struct dm_priv dmpriv; ++ DM_ODM_T odmpriv; ++ //_lock odm_stainfo_lock; ++#ifdef DBG_CONFIG_ERROR_DETECT ++ struct sreset_priv srestpriv; ++#endif ++ ++#ifdef CONFIG_BT_COEXIST ++ struct btcoexist_priv bt_coexist; ++#endif ++ ++ u8 CurAntenna; ++ u8 AntDivCfg; ++ u8 TRxAntDivType; ++ ++ ++ u8 bDumpRxPkt;//for debug ++ u8 bDumpTxPkt;//for debug ++ u8 FwRsvdPageStartOffset; //2010.06.23. Added by tynli. Reserve page start offset except beacon in TxQ. ++ ++ // 2010/08/09 MH Add CU power down mode. ++ BOOLEAN pwrdown; ++ ++ // Add for dual MAC 0--Mac0 1--Mac1 ++ u32 interfaceIndex; ++ ++ u8 OutEpQueueSel; ++ u8 OutEpNumber; ++ ++ // 2010/12/10 MH Add for USB aggreation mode dynamic shceme. ++ BOOLEAN UsbRxHighSpeedMode; ++ ++ // 2010/11/22 MH Add for slim combo debug mode selective. ++ // This is used for fix the drawback of CU TSMC-A/UMC-A cut. HW auto suspend ability. Close BT clock. ++ BOOLEAN SlimComboDbg; ++ ++ u16 EfuseUsedBytes; ++ ++#ifdef CONFIG_P2P ++ struct P2P_PS_Offload_t p2p_ps_offload; ++#endif ++ ++ // Auto FSM to Turn On, include clock, isolation, power control for MAC only ++ u8 bMacPwrCtrlOn; ++ ++#ifdef CONFIG_SDIO_HCI ++ // ++ // For SDIO Interface HAL related ++ // ++ ++ // ++ // SDIO ISR Related ++ // ++// u32 IntrMask[1]; ++// u32 IntrMaskToSet[1]; ++// LOG_INTERRUPT InterruptLog; ++ u32 sdio_himr; ++ u32 sdio_hisr; ++ ++ // ++ // SDIO Tx FIFO related. ++ // ++ // HIQ, MID, LOW, PUB free pages; padapter->xmitpriv.free_txpg ++ u8 SdioTxFIFOFreePage[SDIO_TX_FREE_PG_QUEUE]; ++ _lock SdioTxFIFOFreePageLock; ++ ++ // ++ // SDIO Rx FIFO related. ++ // ++ u8 SdioRxFIFOCnt; ++ u16 SdioRxFIFOSize; ++#endif //CONFIG_SDIO_HCI ++ ++#ifdef CONFIG_USB_HCI ++ u32 UsbBulkOutSize; ++ ++ // Interrupt relatd register information. ++ u32 IntArray[3];//HISR0,HISR1,HSISR ++ u32 IntrMask[3]; ++ u8 C2hArray[16]; ++#ifdef CONFIG_USB_TX_AGGREGATION ++ u8 UsbTxAggMode; ++ u8 UsbTxAggDescNum; ++#endif ++#ifdef CONFIG_USB_RX_AGGREGATION ++ u16 HwRxPageSize; // Hardware setting ++ u32 MaxUsbRxAggBlock; ++ ++ USB_RX_AGG_MODE UsbRxAggMode; ++ u8 UsbRxAggBlockCount; // USB Block count. Block size is 512-byte in hight speed and 64-byte in full speed ++ u8 UsbRxAggBlockTimeout; ++ u8 UsbRxAggPageCount; // 8192C DMA page count ++ u8 UsbRxAggPageTimeout; ++#endif ++#endif //CONFIG_USB_HCI ++ ++ ++#ifdef CONFIG_PCI_HCI ++ ++ // ++ // EEPROM setting. ++ // ++ ++ u16 EEPROMDID; ++ u16 EEPROMSMID; ++ u16 EEPROMChannelPlan; ++ ++ u8 EEPROMTSSI[2]; ++ u8 EEPROMBoardType; ++ u32 TransmitConfig; ++ ++ u32 IntrMask[2]; ++ u32 IntrMaskToSet[2]; ++ ++ u8 bDefaultAntenna; ++ u8 bIQKInitialized; ++ ++ u8 bInterruptMigration; ++ u8 bDisableTxInt; ++ u8 bGpioHwWpsPbc; ++#endif //CONFIG_PCI_HCI ++ ++ ++#ifdef CONFIG_TX_EARLY_MODE ++ u8 bEarlyModeEnable; ++#endif ++} HAL_DATA_8188E, *PHAL_DATA_8188E; ++ ++typedef struct hal_data_8188e HAL_DATA_TYPE, *PHAL_DATA_TYPE; ++ ++ ++#define GET_HAL_DATA(__pAdapter) ((HAL_DATA_TYPE *)((__pAdapter)->HalData)) ++#define GET_RF_TYPE(priv) (GET_HAL_DATA(priv)->rf_type) ++ ++#define INCLUDE_MULTI_FUNC_BT(_Adapter) (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_BT) ++#define INCLUDE_MULTI_FUNC_GPS(_Adapter) (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_GPS) ++ ++//#define IS_MULTI_FUNC_CHIP(_Adapter) (((((PHAL_DATA_TYPE)(_Adapter->HalData))->MultiFunc) & (RT_MULTI_FUNC_BT|RT_MULTI_FUNC_GPS)) ? _TRUE : _FALSE) ++ ++//#define RT_IS_FUNC_DISABLED(__pAdapter, __FuncBits) ( (__pAdapter)->DisabledFunctions & (__FuncBits) ) ++ ++#ifdef CONFIG_PCI_HCI ++void InterruptRecognized8188EE(PADAPTER Adapter, PRT_ISR_CONTENT pIsrContent); ++void UpdateInterruptMask8188EE(PADAPTER Adapter, u32 AddMSR, u32 AddMSR1, u32 RemoveMSR, u32 RemoveMSR1); ++#endif //CONFIG_PCI_HCI ++ ++// rtl8188e_hal_init.c ++#ifdef CONFIG_WOWLAN ++s32 rtl8188e_FirmwareDownload(PADAPTER padapter, BOOLEAN bUsedWoWLANFw); ++#else ++s32 rtl8188e_FirmwareDownload(PADAPTER padapter); ++#endif ++void _8051Reset88E(PADAPTER padapter); ++void rtl8188e_InitializeFirmwareVars(PADAPTER padapter); ++ ++ ++s32 InitLLTTable(PADAPTER padapter, u8 txpktbuf_bndy); ++void Read_LLT_Tab(PADAPTER padapter); ++ ++// EFuse ++u8 GetEEPROMSize8188E(PADAPTER padapter); ++void Hal_InitPGData88E(PADAPTER padapter); ++void Hal_EfuseParseIDCode88E(PADAPTER padapter, u8 *hwinfo); ++void Hal_ReadTxPowerInfo88E(PADAPTER padapter,u8* hwinfo,BOOLEAN AutoLoadFail); ++ ++void Hal_EfuseParseEEPROMVer88E(PADAPTER padapter, u8 *hwinfo, BOOLEAN AutoLoadFail); ++void rtl8188e_EfuseParseChnlPlan(PADAPTER padapter, u8 *hwinfo, BOOLEAN AutoLoadFail); ++void Hal_EfuseParseCustomerID88E(PADAPTER padapter, u8 *hwinfo, BOOLEAN AutoLoadFail); ++void Hal_ReadAntennaDiversity88E (PADAPTER pAdapter,u8*PROMContent,BOOLEAN AutoLoadFail); ++void Hal_ReadThermalMeter_88E(PADAPTER Adapter,u8* PROMContent,BOOLEAN AutoloadFail); ++void Hal_EfuseParseXtal_8188E(PADAPTER pAdapter,u8* hwinfo,BOOLEAN AutoLoadFail); ++void Hal_EfuseParseBoardType88E(PADAPTER pAdapter,u8* hwinfo,BOOLEAN AutoLoadFail); ++void Hal_ReadPowerSavingMode88E(PADAPTER pAdapter,u8* hwinfo,BOOLEAN AutoLoadFail); ++ ++BOOLEAN HalDetectPwrDownMode88E(PADAPTER Adapter); ++ ++#ifdef CONFIG_WOWLAN ++void Hal_DetectWoWMode(PADAPTER pAdapter); ++#endif //CONFIG_WOWLAN ++ ++#ifdef CONFIG_RF_GAIN_OFFSET ++void Hal_ReadRFGainOffset(PADAPTER pAdapter,u8* hwinfo,BOOLEAN AutoLoadFail); ++#endif //CONFIG_RF_GAIN_OFFSET ++ ++//RT_CHANNEL_DOMAIN rtl8723a_HalMapChannelPlan(PADAPTER padapter, u8 HalChannelPlan); ++//VERSION_8192C rtl8723a_ReadChipVersion(PADAPTER padapter); ++//void rtl8723a_ReadBluetoothCoexistInfo(PADAPTER padapter, u8 *PROMContent, BOOLEAN AutoloadFail); ++void Hal_InitChannelPlan(PADAPTER padapter); ++ ++void rtl8188e_set_hal_ops(struct hal_ops *pHalFunc); ++ ++// register ++void SetBcnCtrlReg(PADAPTER padapter, u8 SetBits, u8 ClearBits); ++ ++void rtl8188e_start_thread(_adapter *padapter); ++void rtl8188e_stop_thread(_adapter *padapter); ++ ++void rtw_IOL_cmd_tx_pkt_buf_dump(ADAPTER *Adapter,int data_len); ++#ifdef CONFIG_IOL_EFUSE_PATCH ++s32 rtl8188e_iol_efuse_patch(PADAPTER padapter); ++#endif//CONFIG_IOL_EFUSE_PATCH ++ ++#endif //__RTL8188E_HAL_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_led.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_led.h +new file mode 100644 +index 00000000..2bafb83f +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_led.h +@@ -0,0 +1,46 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8188E_LED_H__ ++#define __RTL8188E_LED_H__ ++ ++#include ++#include ++#include ++ ++ ++//================================================================================ ++// Interface to manipulate LED objects. ++//================================================================================ ++#ifdef CONFIG_USB_HCI ++void rtl8188eu_InitSwLeds(PADAPTER padapter); ++void rtl8188eu_DeInitSwLeds(PADAPTER padapter); ++#endif ++#ifdef CONFIG_PCI_HCI ++void rtl8188ee_gen_RefreshLedState(PADAPTER Adapter); ++void rtl8188ee_InitSwLeds(PADAPTER padapter); ++void rtl8188ee_DeInitSwLeds(PADAPTER padapter); ++#endif ++#ifdef CONFIG_SDIO_HCI ++void rtl8188es_InitSwLeds(PADAPTER padapter); ++void rtl8188es_DeInitSwLeds(PADAPTER padapter); ++#endif ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_recv.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_recv.h +new file mode 100644 +index 00000000..2c190d05 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_recv.h +@@ -0,0 +1,146 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8188E_RECV_H__ ++#define __RTL8188E_RECV_H__ ++ ++#include ++ ++#define TX_RPT1_PKT_LEN 8 ++ ++typedef enum _RX_PACKET_TYPE{ ++ NORMAL_RX,//Normal rx packet ++ TX_REPORT1,//CCX ++ TX_REPORT2,//TX RPT ++ HIS_REPORT,// USB HISR RPT ++}RX_PACKET_TYPE, *PRX_PACKET_TYPE; ++ ++typedef struct rxreport_8188e ++{ ++ //Offset 0 ++ u32 pktlen:14; ++ u32 crc32:1; ++ u32 icverr:1; ++ u32 drvinfosize:4; ++ u32 security:3; ++ u32 qos:1; ++ u32 shift:2; ++ u32 physt:1; ++ u32 swdec:1; ++ u32 ls:1; ++ u32 fs:1; ++ u32 eor:1; ++ u32 own:1; ++ ++ //Offset 4 ++ u32 macid:5; ++ u32 tid:4; ++ u32 hwrsvd:4; ++ u32 amsdu:1; ++ u32 paggr:1; ++ u32 faggr:1; ++ u32 a1fit:4; ++ u32 a2fit:4; ++ u32 pam:1; ++ u32 pwr:1; ++ u32 md:1; ++ u32 mf:1; ++ u32 type:2; ++ u32 mc:1; ++ u32 bc:1; ++ ++ //Offset 8 ++ u32 seq:12; ++ u32 frag:4; ++ u32 nextpktlen:14; ++ u32 nextind:1; ++ u32 rsvd0831:1; ++ ++ //Offset 12 ++ u32 rxmcs:6; ++ u32 rxht:1; ++ u32 gf:1; ++ u32 splcp:1; ++ u32 bw:1; ++ u32 htc:1; ++ u32 eosp:1; ++ u32 bssidfit:2; ++ u32 rpt_sel:2; ++ u32 rsvd1216:13; ++ u32 pattern_match:1; ++ u32 unicastwake:1; ++ u32 magicwake:1; ++ ++ //Offset 16 ++ /* ++ u32 pattern0match:1; ++ u32 pattern1match:1; ++ u32 pattern2match:1; ++ u32 pattern3match:1; ++ u32 pattern4match:1; ++ u32 pattern5match:1; ++ u32 pattern6match:1; ++ u32 pattern7match:1; ++ u32 pattern8match:1; ++ u32 pattern9match:1; ++ u32 patternamatch:1; ++ u32 patternbmatch:1; ++ u32 patterncmatch:1; ++ u32 rsvd1613:19; ++ */ ++ u32 rsvd16; ++ ++ //Offset 20 ++ u32 tsfl; ++ ++ //Offset 24 ++ u32 bassn:12; ++ u32 bavld:1; ++ u32 rsvd2413:19; ++} RXREPORT, *PRXREPORT; ++ ++ ++#ifdef CONFIG_SDIO_HCI ++s32 rtl8188es_init_recv_priv(PADAPTER padapter); ++void rtl8188es_free_recv_priv(PADAPTER padapter); ++void rtl8188es_recv_hdl(PADAPTER padapter, struct recv_buf *precvbuf); ++#endif ++ ++#ifdef CONFIG_USB_HCI ++#define INTERRUPT_MSG_FORMAT_LEN 60 ++void rtl8188eu_init_recvbuf(_adapter *padapter, struct recv_buf *precvbuf); ++s32 rtl8188eu_init_recv_priv(PADAPTER padapter); ++void rtl8188eu_free_recv_priv(PADAPTER padapter); ++void rtl8188eu_recv_hdl(PADAPTER padapter, struct recv_buf *precvbuf); ++void rtl8188eu_recv_tasklet(void *priv); ++ ++#endif ++ ++#ifdef CONFIG_PCI_HCI ++s32 rtl8188ee_init_recv_priv(PADAPTER padapter); ++void rtl8188ee_free_recv_priv(PADAPTER padapter); ++#endif ++ ++void rtl8188e_query_rx_phy_status(union recv_frame *prframe, struct phy_stat *pphy_stat); ++void rtl8188e_process_phy_info(PADAPTER padapter, void *prframe); ++void update_recvframe_phyinfo_88e(union recv_frame *precvframe,struct phy_stat *pphy_status); ++void update_recvframe_attrib_88e( union recv_frame *precvframe, struct recv_stat *prxstat); ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_rf.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_rf.h +new file mode 100644 +index 00000000..bafa6ad7 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_rf.h +@@ -0,0 +1,45 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8188E_RF_H__ ++#define __RTL8188E_RF_H__ ++ ++#define RF6052_MAX_TX_PWR 0x3F ++#define RF6052_MAX_REG 0x3F ++#define RF6052_MAX_PATH 2 ++ ++ ++int PHY_RF6052_Config8188E( IN PADAPTER Adapter ); ++void rtl8188e_RF_ChangeTxPath( IN PADAPTER Adapter, ++ IN u16 DataRate); ++void rtl8188e_PHY_RF6052SetBandwidth( ++ IN PADAPTER Adapter, ++ IN HT_CHANNEL_WIDTH Bandwidth); ++VOID rtl8188e_PHY_RF6052SetCckTxPower( ++ IN PADAPTER Adapter, ++ IN u8* pPowerlevel); ++VOID rtl8188e_PHY_RF6052SetOFDMTxPower( ++ IN PADAPTER Adapter, ++ IN u8* pPowerLevelOFDM, ++ IN u8* pPowerLevelBW20, ++ IN u8* pPowerLevelBW40, ++ IN u8 Channel); ++ ++#endif//__RTL8188E_RF_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_spec.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_spec.h +new file mode 100644 +index 00000000..0421da90 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_spec.h +@@ -0,0 +1,1741 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ *******************************************************************************/ ++#ifndef __RTL8188E_SPEC_H__ ++#define __RTL8188E_SPEC_H__ ++ ++#include ++ ++#ifndef BIT ++#define BIT(x) (1 << (x)) ++#endif ++ ++#define BIT0 0x00000001 ++#define BIT1 0x00000002 ++#define BIT2 0x00000004 ++#define BIT3 0x00000008 ++#define BIT4 0x00000010 ++#define BIT5 0x00000020 ++#define BIT6 0x00000040 ++#define BIT7 0x00000080 ++#define BIT8 0x00000100 ++#define BIT9 0x00000200 ++#define BIT10 0x00000400 ++#define BIT11 0x00000800 ++#define BIT12 0x00001000 ++#define BIT13 0x00002000 ++#define BIT14 0x00004000 ++#define BIT15 0x00008000 ++#define BIT16 0x00010000 ++#define BIT17 0x00020000 ++#define BIT18 0x00040000 ++#define BIT19 0x00080000 ++#define BIT20 0x00100000 ++#define BIT21 0x00200000 ++#define BIT22 0x00400000 ++#define BIT23 0x00800000 ++#define BIT24 0x01000000 ++#define BIT25 0x02000000 ++#define BIT26 0x04000000 ++#define BIT27 0x08000000 ++#define BIT28 0x10000000 ++#define BIT29 0x20000000 ++#define BIT30 0x40000000 ++#define BIT31 0x80000000 ++ ++//============================================================ ++// 8192C Regsiter offset definition ++//============================================================ ++ ++#define HAL_PS_TIMER_INT_DELAY 50 // 50 microseconds ++#define HAL_92C_NAV_UPPER_UNIT 128 // micro-second ++ ++#define MAC_ADDR_LEN 6 ++// 8188E PKT_BUFF_ACCESS_CTRL value ++#define TXPKT_BUF_SELECT 0x69 ++#define RXPKT_BUF_SELECT 0xA5 ++#define DISABLE_TRXPKT_BUF_ACCESS 0x0 ++ ++//============================================================ ++// ++//============================================================ ++ ++//----------------------------------------------------- ++// ++// 0x0000h ~ 0x00FFh System Configuration ++// ++//----------------------------------------------------- ++#define REG_SYS_ISO_CTRL 0x0000 ++#define REG_SYS_FUNC_EN 0x0002 ++#define REG_APS_FSMCO 0x0004 ++#define REG_SYS_CLKR 0x0008 ++#define REG_9346CR 0x000A ++#define REG_EE_VPD 0x000C ++#define REG_AFE_MISC 0x0010 ++#define REG_SPS0_CTRL 0x0011 ++#define REG_SPS_OCP_CFG 0x0018 ++#define REG_RSV_CTRL 0x001C ++#define REG_RF_CTRL 0x001F ++#define REG_LDOA15_CTRL 0x0020 ++#define REG_LDOV12D_CTRL 0x0021 ++#define REG_LDOHCI12_CTRL 0x0022 ++#define REG_LPLDO_CTRL 0x0023 ++#define REG_AFE_XTAL_CTRL 0x0024 ++#define REG_AFE_PLL_CTRL 0x0028 ++#define REG_APE_PLL_CTRL_EXT 0x002c ++#define REG_EFUSE_CTRL 0x0030 ++#define REG_EFUSE_TEST 0x0034 ++#define REG_GPIO_MUXCFG 0x0040 ++#define REG_GPIO_IO_SEL 0x0042 ++#define REG_MAC_PINMUX_CFG 0x0043 ++#define REG_GPIO_PIN_CTRL 0x0044 ++#define REG_GPIO_INTM 0x0048 ++#define REG_LEDCFG0 0x004C ++#define REG_LEDCFG1 0x004D ++#define REG_LEDCFG2 0x004E ++#define REG_LEDCFG3 0x004F ++#define REG_FSIMR 0x0050 ++#define REG_FSISR 0x0054 ++#define REG_HSIMR 0x0058 ++#define REG_HSISR 0x005c ++#define REG_GPIO_PIN_CTRL_2 0x0060 // RTL8723 WIFI/BT/GPS Multi-Function GPIO Pin Control. ++#define REG_GPIO_IO_SEL_2 0x0062 // RTL8723 WIFI/BT/GPS Multi-Function GPIO Select. ++#define REG_BB_PAD_CTRL 0x0064 ++#define REG_MULTI_FUNC_CTRL 0x0068 // RTL8723 WIFI/BT/GPS Multi-Function control source. ++#define REG_GPIO_OUTPUT 0x006c ++#define REG_AFE_XTAL_CTRL_EXT 0x0078 //RTL8188E ++#define REG_XCK_OUT_CTRL 0x007c //RTL8188E ++#define REG_MCUFWDL 0x0080 ++#define REG_WOL_EVENT 0x0081 //RTL8188E ++#define REG_MCUTSTCFG 0x0084 ++#define REG_HMEBOX_E0 0x0088 ++#define REG_HMEBOX_E1 0x008A ++#define REG_HMEBOX_E2 0x008C ++#define REG_HMEBOX_E3 0x008E ++#define REG_HMEBOX_EXT_0 0x01F0 ++#define REG_HMEBOX_EXT_1 0x01F4 ++#define REG_HMEBOX_EXT_2 0x01F8 ++#define REG_HMEBOX_EXT_3 0x01FC ++#define REG_HIMR_88E 0x00B0 ++#define REG_HISR_88E 0x00B4 ++#define REG_HIMRE_88E 0x00B8 ++#define REG_HISRE_88E 0x00BC ++#define REG_EFUSE_ACCESS 0x00CF // Efuse access protection for RTL8723 ++#define REG_BIST_SCAN 0x00D0 ++#define REG_BIST_RPT 0x00D4 ++#define REG_BIST_ROM_RPT 0x00D8 ++#define REG_USB_SIE_INTF 0x00E0 ++#define REG_PCIE_MIO_INTF 0x00E4 ++#define REG_PCIE_MIO_INTD 0x00E8 ++#define REG_HPON_FSM 0x00EC ++#define REG_SYS_CFG 0x00F0 ++#define REG_GPIO_OUTSTS 0x00F4 // For RTL8723 only. ++#define REG_TYPE_ID 0x00FC ++ ++#define REG_MAC_PHY_CTRL_NORMAL 0x00f8 ++ ++//----------------------------------------------------- ++// ++// 0x0100h ~ 0x01FFh MACTOP General Configuration ++// ++//----------------------------------------------------- ++#define REG_CR 0x0100 ++#define REG_PBP 0x0104 ++#define REG_PKT_BUFF_ACCESS_CTRL 0x0106 ++#define REG_TRXDMA_CTRL 0x010C ++#define REG_TRXFF_BNDY 0x0114 ++#define REG_TRXFF_STATUS 0x0118 ++#define REG_RXFF_PTR 0x011C ++//#define REG_HIMR 0x0120 ++//#define REG_HISR 0x0124 ++#define REG_HIMRE 0x0128 ++#define REG_HISRE 0x012C ++#define REG_CPWM 0x012F ++#define REG_FWIMR 0x0130 ++#define REG_FTIMR 0x0138 ++#define REG_FWISR 0x0134 ++#define REG_PKTBUF_DBG_CTRL 0x0140 ++#define REG_PKTBUF_DBG_ADDR (REG_PKTBUF_DBG_CTRL) ++#define REG_RXPKTBUF_DBG (REG_PKTBUF_DBG_CTRL+2) ++#define REG_TXPKTBUF_DBG (REG_PKTBUF_DBG_CTRL+3) ++#define REG_RXPKTBUF_CTRL (REG_PKTBUF_DBG_CTRL+2) ++#define REG_PKTBUF_DBG_DATA_L 0x0144 ++#define REG_PKTBUF_DBG_DATA_H 0x0148 ++ ++#define REG_TC0_CTRL 0x0150 ++#define REG_TC1_CTRL 0x0154 ++#define REG_TC2_CTRL 0x0158 ++#define REG_TC3_CTRL 0x015C ++#define REG_TC4_CTRL 0x0160 ++#define REG_TCUNIT_BASE 0x0164 ++#define REG_MBIST_START 0x0174 ++#define REG_MBIST_DONE 0x0178 ++#define REG_MBIST_FAIL 0x017C ++#define REG_32K_CTRL 0x0194 //RTL8188E ++#define REG_C2HEVT_MSG_NORMAL 0x01A0 ++#define REG_C2HEVT_CLEAR 0x01AF ++#define REG_MCUTST_1 0x01c0 ++#ifdef CONFIG_WOWLAN ++#define REG_WOWLAN_WAKE_REASON 0x01c7 ++#endif ++#define REG_FMETHR 0x01C8 ++#define REG_HMETFR 0x01CC ++#define REG_HMEBOX_0 0x01D0 ++#define REG_HMEBOX_1 0x01D4 ++#define REG_HMEBOX_2 0x01D8 ++#define REG_HMEBOX_3 0x01DC ++ ++#define REG_LLT_INIT 0x01E0 ++ ++ ++//----------------------------------------------------- ++// ++// 0x0200h ~ 0x027Fh TXDMA Configuration ++// ++//----------------------------------------------------- ++#define REG_RQPN 0x0200 ++#define REG_FIFOPAGE 0x0204 ++#define REG_TDECTRL 0x0208 ++#define REG_TXDMA_OFFSET_CHK 0x020C ++#define REG_TXDMA_STATUS 0x0210 ++#define REG_RQPN_NPQ 0x0214 ++ ++//----------------------------------------------------- ++// ++// 0x0280h ~ 0x02FFh RXDMA Configuration ++// ++//----------------------------------------------------- ++#define REG_RXDMA_AGG_PG_TH 0x0280 ++#define REG_RXPKT_NUM 0x0284 ++#define REG_RXDMA_STATUS 0x0288 ++ ++//----------------------------------------------------- ++// ++// 0x0300h ~ 0x03FFh PCIe ++// ++//----------------------------------------------------- ++#define REG_PCIE_CTRL_REG 0x0300 ++#define REG_INT_MIG 0x0304 // Interrupt Migration ++#define REG_BCNQ_DESA 0x0308 // TX Beacon Descriptor Address ++#define REG_HQ_DESA 0x0310 // TX High Queue Descriptor Address ++#define REG_MGQ_DESA 0x0318 // TX Manage Queue Descriptor Address ++#define REG_VOQ_DESA 0x0320 // TX VO Queue Descriptor Address ++#define REG_VIQ_DESA 0x0328 // TX VI Queue Descriptor Address ++#define REG_BEQ_DESA 0x0330 // TX BE Queue Descriptor Address ++#define REG_BKQ_DESA 0x0338 // TX BK Queue Descriptor Address ++#define REG_RX_DESA 0x0340 // RX Queue Descriptor Address ++#define REG_MDIO 0x0354 // MDIO for Access PCIE PHY ++#define REG_DBG_SEL 0x0360 // Debug Selection Register ++#define REG_PCIE_HRPWM 0x0361 //PCIe RPWM ++#define REG_PCIE_HCPWM 0x0363 //PCIe CPWM ++#define REG_WATCH_DOG 0x0368 ++ ++// RTL8723 series ------------------------------- ++#define REG_PCIE_HISR 0x03A0 ++ ++// spec version 11 ++//----------------------------------------------------- ++// ++// 0x0400h ~ 0x047Fh Protocol Configuration ++// ++//----------------------------------------------------- ++#define REG_VOQ_INFORMATION 0x0400 ++#define REG_VIQ_INFORMATION 0x0404 ++#define REG_BEQ_INFORMATION 0x0408 ++#define REG_BKQ_INFORMATION 0x040C ++#define REG_MGQ_INFORMATION 0x0410 ++#define REG_HGQ_INFORMATION 0x0414 ++#define REG_BCNQ_INFORMATION 0x0418 ++#define REG_TXPKT_EMPTY 0x041A ++ ++#define REG_CPU_MGQ_INFORMATION 0x041C ++#define REG_FWHW_TXQ_CTRL 0x0420 ++#define REG_HWSEQ_CTRL 0x0423 ++#define REG_TXPKTBUF_BCNQ_BDNY 0x0424 ++#define REG_TXPKTBUF_MGQ_BDNY 0x0425 ++#define REG_LIFETIME_EN 0x0426 ++#define REG_MULTI_BCNQ_OFFSET 0x0427 ++#define REG_SPEC_SIFS 0x0428 ++#define REG_RL 0x042A ++#define REG_DARFRC 0x0430 ++#define REG_RARFRC 0x0438 ++#define REG_RRSR 0x0440 ++#define REG_ARFR0 0x0444 ++#define REG_ARFR1 0x0448 ++#define REG_ARFR2 0x044C ++#define REG_ARFR3 0x0450 ++#define REG_AGGLEN_LMT 0x0458 ++#define REG_AMPDU_MIN_SPACE 0x045C ++#define REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045D ++#define REG_FAST_EDCA_CTRL 0x0460 ++#define REG_RD_RESP_PKT_TH 0x0463 ++#define REG_INIRTS_RATE_SEL 0x0480 ++//#define REG_INIDATA_RATE_SEL 0x0484 ++#define REG_MACID_NO_LINK_0 0x0484 ++#define REG_MACID_NO_LINK_1 0x0488 ++ ++#define REG_POWER_STATUS 0x04A4 ++#define REG_POWER_STAGE1 0x04B4 ++#define REG_POWER_STAGE2 0x04B8 ++#define REG_PKT_VO_VI_LIFE_TIME 0x04C0 ++#define REG_PKT_BE_BK_LIFE_TIME 0x04C2 ++#define REG_STBC_SETTING 0x04C4 ++#define REG_PROT_MODE_CTRL 0x04C8 ++#define REG_MAX_AGGR_NUM 0x04CA ++#define REG_RTS_MAX_AGGR_NUM 0x04CB ++#define REG_BAR_MODE_CTRL 0x04CC ++#define REG_RA_TRY_RATE_AGG_LMT 0x04CF ++#define REG_EARLY_MODE_CONTROL 0x4D0 ++#define REG_NQOS_SEQ 0x04DC ++#define REG_QOS_SEQ 0x04DE ++#define REG_NEED_CPU_HANDLE 0x04E0 ++#define REG_PKT_LOSE_RPT 0x04E1 ++#define REG_PTCL_ERR_STATUS 0x04E2 ++#define REG_TX_RPT_CTRL 0x04EC ++#define REG_TX_RPT_TIME 0x04F0 // 2 byte ++#define REG_DUMMY 0x04FC ++ ++#ifdef CONFIG_WOWLAN ++#define REG_TXPKTBUF_IV_LOW 0x0484 ++#define REG_TXPKTBUF_IV_HIGH 0x0488 ++#endif ++ ++//----------------------------------------------------- ++// ++// 0x0500h ~ 0x05FFh EDCA Configuration ++// ++//----------------------------------------------------- ++#define REG_EDCA_VO_PARAM 0x0500 ++#define REG_EDCA_VI_PARAM 0x0504 ++#define REG_EDCA_BE_PARAM 0x0508 ++#define REG_EDCA_BK_PARAM 0x050C ++#define REG_BCNTCFG 0x0510 ++#define REG_PIFS 0x0512 ++#define REG_RDG_PIFS 0x0513 ++#define REG_SIFS_CTX 0x0514 ++#define REG_SIFS_TRX 0x0516 ++#define REG_TSFTR_SYN_OFFSET 0x0518 ++#define REG_AGGR_BREAK_TIME 0x051A ++#define REG_SLOT 0x051B ++#define REG_TX_PTCL_CTRL 0x0520 ++#define REG_TXPAUSE 0x0522 ++#define REG_DIS_TXREQ_CLR 0x0523 ++#define REG_RD_CTRL 0x0524 ++// ++// Format for offset 540h-542h: ++// [3:0]: TBTT prohibit setup in unit of 32us. The time for HW getting beacon content before TBTT. ++// [7:4]: Reserved. ++// [19:8]: TBTT prohibit hold in unit of 32us. The time for HW holding to send the beacon packet. ++// [23:20]: Reserved ++// Description: ++// | ++// |<--Setup--|--Hold------------>| ++// --------------|---------------------- ++// | ++// TBTT ++// Note: We cannot update beacon content to HW or send any AC packets during the time between Setup and Hold. ++// Described by Designer Tim and Bruce, 2011-01-14. ++// ++#define REG_TBTT_PROHIBIT 0x0540 ++#define REG_RD_NAV_NXT 0x0544 ++#define REG_NAV_PROT_LEN 0x0546 ++#define REG_BCN_CTRL 0x0550 ++#define REG_BCN_CTRL_1 0x0551 ++#define REG_MBID_NUM 0x0552 ++#define REG_DUAL_TSF_RST 0x0553 ++#define REG_BCN_INTERVAL 0x0554 // The same as REG_MBSSID_BCN_SPACE ++#define REG_DRVERLYINT 0x0558 ++#define REG_BCNDMATIM 0x0559 ++#define REG_ATIMWND 0x055A ++#define REG_BCN_MAX_ERR 0x055D ++#define REG_RXTSF_OFFSET_CCK 0x055E ++#define REG_RXTSF_OFFSET_OFDM 0x055F ++#define REG_TSFTR 0x0560 ++#define REG_TSFTR1 0x0568 ++#define REG_ATIMWND_1 0x0570 ++#define REG_PSTIMER 0x0580 ++#define REG_TIMER0 0x0584 ++#define REG_TIMER1 0x0588 ++#define REG_ACMHWCTRL 0x05C0 ++ ++//#define REG_FW_TSF_SYNC_CNT 0x04A0 ++#define REG_FW_RESET_TSF_CNT_1 0x05FC ++#define REG_FW_RESET_TSF_CNT_0 0x05FD ++#define REG_FW_BCN_DIS_CNT 0x05FE ++ ++//----------------------------------------------------- ++// ++// 0x0600h ~ 0x07FFh WMAC Configuration ++// ++//----------------------------------------------------- ++#define REG_APSD_CTRL 0x0600 ++#define REG_BWOPMODE 0x0603 ++#define REG_TCR 0x0604 ++#define REG_RCR 0x0608 ++#define REG_RX_PKT_LIMIT 0x060C ++#define REG_RX_DLK_TIME 0x060D ++#define REG_RX_DRVINFO_SZ 0x060F ++ ++#define REG_MACID 0x0610 ++#define REG_BSSID 0x0618 ++#define REG_MAR 0x0620 ++#define REG_MBIDCAMCFG 0x0628 ++ ++#define REG_USTIME_EDCA 0x0638 ++#define REG_MAC_SPEC_SIFS 0x063A ++ ++// 20100719 Joseph: Hardware register definition change. (HW datasheet v54) ++#define REG_R2T_SIFS 0x063C // [15:8]SIFS_R2T_OFDM, [7:0]SIFS_R2T_CCK ++#define REG_T2T_SIFS 0x063E // [15:8]SIFS_T2T_OFDM, [7:0]SIFS_T2T_CCK ++#define REG_ACKTO 0x0640 ++#define REG_CTS2TO 0x0641 ++#define REG_EIFS 0x0642 ++ ++ ++//RXERR_RPT ++#define RXERR_TYPE_OFDM_PPDU 0 ++#define RXERR_TYPE_OFDM_FALSE_ALARM 1 ++#define RXERR_TYPE_OFDM_MPDU_OK 2 ++#define RXERR_TYPE_OFDM_MPDU_FAIL 3 ++#define RXERR_TYPE_CCK_PPDU 4 ++#define RXERR_TYPE_CCK_FALSE_ALARM 5 ++#define RXERR_TYPE_CCK_MPDU_OK 6 ++#define RXERR_TYPE_CCK_MPDU_FAIL 7 ++#define RXERR_TYPE_HT_PPDU 8 ++#define RXERR_TYPE_HT_FALSE_ALARM 9 ++#define RXERR_TYPE_HT_MPDU_TOTAL 10 ++#define RXERR_TYPE_HT_MPDU_OK 11 ++#define RXERR_TYPE_HT_MPDU_FAIL 12 ++#define RXERR_TYPE_RX_FULL_DROP 15 ++ ++#define RXERR_COUNTER_MASK 0xFFFFF ++#define RXERR_RPT_RST BIT(27) ++#define _RXERR_RPT_SEL(type) ((type) << 28) ++ ++ ++// ++// Note: ++// The NAV upper value is very important to WiFi 11n 5.2.3 NAV test. The default value is ++// always too small, but the WiFi TestPlan test by 25,000 microseconds of NAV through sending ++// CTS in the air. We must update this value greater than 25,000 microseconds to pass the item. ++// The offset of NAV_UPPER in 8192C Spec is incorrect, and the offset should be 0x0652. Commented ++// by SD1 Scott. ++// By Bruce, 2011-07-18. ++// ++#define REG_NAV_UPPER 0x0652 // unit of 128 ++ ++//WMA, BA, CCX ++//#define REG_NAV_CTRL 0x0650 ++#define REG_BACAMCMD 0x0654 ++#define REG_BACAMCONTENT 0x0658 ++#define REG_LBDLY 0x0660 ++#define REG_FWDLY 0x0661 ++#define REG_RXERR_RPT 0x0664 ++#define REG_WMAC_TRXPTCL_CTL 0x0668 ++ ++// Security ++#define REG_CAMCMD 0x0670 ++#define REG_CAMWRITE 0x0674 ++#define REG_CAMREAD 0x0678 ++#define REG_CAMDBG 0x067C ++#define REG_SECCFG 0x0680 ++ ++// Power ++#define REG_WOW_CTRL 0x0690 ++#define REG_PS_RX_INFO 0x0692 ++#define REG_UAPSD_TID 0x0693 ++#define REG_WKFMCAM_CMD 0x0698 ++#define REG_WKFMCAM_NUM_88E 0x698 ++#define REG_RXFLTMAP0 0x06A0 ++#define REG_RXFLTMAP1 0x06A2 ++#define REG_RXFLTMAP2 0x06A4 ++#define REG_BCN_PSR_RPT 0x06A8 ++#define REG_BT_COEX_TABLE 0x06C0 ++ ++ ++// Hardware Port 2 ++#define REG_MACID1 0x0700 ++#define REG_BSSID1 0x0708 ++ ++ ++//----------------------------------------------------- ++// ++// 0xFE00h ~ 0xFE55h USB Configuration ++// ++//----------------------------------------------------- ++#define REG_USB_INFO 0xFE17 ++#define REG_USB_SPECIAL_OPTION 0xFE55 ++#define REG_USB_DMA_AGG_TO 0xFE5B ++#define REG_USB_AGG_TO 0xFE5C ++#define REG_USB_AGG_TH 0xFE5D ++ ++ ++// For normal chip ++#define REG_NORMAL_SIE_VID 0xFE60 // 0xFE60~0xFE61 ++#define REG_NORMAL_SIE_PID 0xFE62 // 0xFE62~0xFE63 ++#define REG_NORMAL_SIE_OPTIONAL 0xFE64 ++#define REG_NORMAL_SIE_EP 0xFE65 // 0xFE65~0xFE67 ++#define REG_NORMAL_SIE_PHY 0xFE68 // 0xFE68~0xFE6B ++#define REG_NORMAL_SIE_OPTIONAL2 0xFE6C ++#define REG_NORMAL_SIE_GPS_EP 0xFE6D // 0xFE6D, for RTL8723 only. ++#define REG_NORMAL_SIE_MAC_ADDR 0xFE70 // 0xFE70~0xFE75 ++#define REG_NORMAL_SIE_STRING 0xFE80 // 0xFE80~0xFEDF ++ ++ ++//----------------------------------------------------- ++// ++// Redifine 8192C register definition for compatibility ++// ++//----------------------------------------------------- ++ ++// TODO: use these definition when using REG_xxx naming rule. ++// NOTE: DO NOT Remove these definition. Use later. ++ ++#define EFUSE_CTRL REG_EFUSE_CTRL // E-Fuse Control. ++#define EFUSE_TEST REG_EFUSE_TEST // E-Fuse Test. ++#define MSR (REG_CR + 2) // Media Status register ++#define ISR REG_HISR_88E ++#define TSFR REG_TSFTR // Timing Sync Function Timer Register. ++ ++#define PBP REG_PBP ++ ++// Redifine MACID register, to compatible prior ICs. ++#define IDR0 REG_MACID // MAC ID Register, Offset 0x0050-0x0053 ++#define IDR4 (REG_MACID + 4) // MAC ID Register, Offset 0x0054-0x0055 ++ ++ ++// ++// 9. Security Control Registers (Offset: ) ++// ++#define RWCAM REG_CAMCMD //IN 8190 Data Sheet is called CAMcmd ++#define WCAMI REG_CAMWRITE // Software write CAM input content ++#define RCAMO REG_CAMREAD // Software read/write CAM config ++#define CAMDBG REG_CAMDBG ++#define SECR REG_SECCFG //Security Configuration Register ++ ++// Unused register ++#define UnusedRegister 0x1BF ++#define DCAM UnusedRegister ++#define PSR UnusedRegister ++#define BBAddr UnusedRegister ++#define PhyDataR UnusedRegister ++ ++// Min Spacing related settings. ++#define MAX_MSS_DENSITY_2T 0x13 ++#define MAX_MSS_DENSITY_1T 0x0A ++ ++//---------------------------------------------------------------------------- ++// 8192C Cmd9346CR bits (Offset 0xA, 16bit) ++//---------------------------------------------------------------------------- ++#define CmdEEPROM_En BIT5 // EEPROM enable when set 1 ++#define CmdEERPOMSEL BIT4 // System EEPROM select, 0: boot from E-FUSE, 1: The EEPROM used is 9346 ++#define Cmd9346CR_9356SEL BIT4 ++ ++//---------------------------------------------------------------------------- ++// 8192C GPIO MUX Configuration Register (offset 0x40, 4 byte) ++//---------------------------------------------------------------------------- ++#define GPIOSEL_GPIO 0 ++#define GPIOSEL_ENBT BIT5 ++ ++//---------------------------------------------------------------------------- ++// 8192C GPIO PIN Control Register (offset 0x44, 4 byte) ++//---------------------------------------------------------------------------- ++#define GPIO_IN REG_GPIO_PIN_CTRL // GPIO pins input value ++#define GPIO_OUT (REG_GPIO_PIN_CTRL+1) // GPIO pins output value ++#define GPIO_IO_SEL (REG_GPIO_PIN_CTRL+2) // GPIO pins output enable when a bit is set to "1"; otherwise, input is configured. ++#define GPIO_MOD (REG_GPIO_PIN_CTRL+3) ++ ++//---------------------------------------------------------------------------- ++// 8723/8188E Host System Interrupt Mask Register (offset 0x58, 32 byte) ++//---------------------------------------------------------------------------- ++#define HSIMR_GPIO12_0_INT_EN BIT0 ++#define HSIMR_SPS_OCP_INT_EN BIT5 ++#define HSIMR_RON_INT_EN BIT6 ++#define HSIMR_PDN_INT_EN BIT7 ++#define HSIMR_GPIO9_INT_EN BIT25 ++ ++ ++//---------------------------------------------------------------------------- ++// 8723/8188E Host System Interrupt Status Register (offset 0x5C, 32 byte) ++//---------------------------------------------------------------------------- ++#define HSISR_GPIO12_0_INT BIT0 ++#define HSISR_SPS_OCP_INT BIT5 ++#define HSISR_RON_INT_EN BIT6 ++#define HSISR_PDNINT BIT7 ++#define HSISR_GPIO9_INT BIT25 ++ ++//---------------------------------------------------------------------------- ++// 8192C (MSR) Media Status Register (Offset 0x4C, 8 bits) ++//---------------------------------------------------------------------------- ++/* ++Network Type ++00: No link ++01: Link in ad hoc network ++10: Link in infrastructure network ++11: AP mode ++Default: 00b. ++*/ ++#define MSR_NOLINK 0x00 ++#define MSR_ADHOC 0x01 ++#define MSR_INFRA 0x02 ++#define MSR_AP 0x03 ++ ++//---------------------------------------------------------------------------- ++// 88EU (MSR) Media Status Register (Offset 0x4C, 8 bits) ++//---------------------------------------------------------------------------- ++#define USB_INTR_CONTENT_C2H_OFFSET 0 ++#define USB_INTR_CONTENT_CPWM1_OFFSET 16 ++#define USB_INTR_CONTENT_CPWM2_OFFSET 20 ++#define USB_INTR_CONTENT_HISR_OFFSET 48 ++#define USB_INTR_CONTENT_HISRE_OFFSET 52 ++ ++ ++//---------------------------------------------------------------------------- ++// 88E Driver Initialization Offload REG_FDHM0(Offset 0x88, 8 bits) ++//---------------------------------------------------------------------------- ++//IOL config for REG_FDHM0(Reg0x88) ++#define CMD_INIT_LLT BIT0 ++#define CMD_READ_EFUSE_MAP BIT1 ++#define CMD_EFUSE_PATCH BIT2 ++#define CMD_IOCONFIG BIT3 ++#define CMD_INIT_LLT_ERR BIT4 ++#define CMD_READ_EFUSE_MAP_ERR BIT5 ++#define CMD_EFUSE_PATCH_ERR BIT6 ++#define CMD_IOCONFIG_ERR BIT7 ++ ++// ++// 6. Adaptive Control Registers (Offset: 0x0160 - 0x01CF) ++// ++//---------------------------------------------------------------------------- ++// 8192C Response Rate Set Register (offset 0x181, 24bits) ++//---------------------------------------------------------------------------- ++#define RRSR_1M BIT0 ++#define RRSR_2M BIT1 ++#define RRSR_5_5M BIT2 ++#define RRSR_11M BIT3 ++#define RRSR_6M BIT4 ++#define RRSR_9M BIT5 ++#define RRSR_12M BIT6 ++#define RRSR_18M BIT7 ++#define RRSR_24M BIT8 ++#define RRSR_36M BIT9 ++#define RRSR_48M BIT10 ++#define RRSR_54M BIT11 ++#define RRSR_MCS0 BIT12 ++#define RRSR_MCS1 BIT13 ++#define RRSR_MCS2 BIT14 ++#define RRSR_MCS3 BIT15 ++#define RRSR_MCS4 BIT16 ++#define RRSR_MCS5 BIT17 ++#define RRSR_MCS6 BIT18 ++#define RRSR_MCS7 BIT19 ++ ++//---------------------------------------------------------------------------- ++// 8192C Response Rate Set Register (offset 0x1BF, 8bits) ++//---------------------------------------------------------------------------- ++// WOL bit information ++#define HAL92C_WOL_PTK_UPDATE_EVENT BIT0 ++#define HAL92C_WOL_GTK_UPDATE_EVENT BIT1 ++ ++//---------------------------------------------------------------------------- ++// 8192C BW_OPMODE bits (Offset 0x203, 8bit) ++//---------------------------------------------------------------------------- ++#define BW_OPMODE_20MHZ BIT2 ++#define BW_OPMODE_5G BIT1 ++ ++ ++//---------------------------------------------------------------------------- ++// 8192C CAM Config Setting (offset 0x250, 1 byte) ++//---------------------------------------------------------------------------- ++#define CAM_VALID BIT15 ++#define CAM_NOTVALID 0x0000 ++#define CAM_USEDK BIT5 ++ ++#define CAM_CONTENT_COUNT 8 ++ ++#define CAM_NONE 0x0 ++#define CAM_WEP40 0x01 ++#define CAM_TKIP 0x02 ++#define CAM_AES 0x04 ++#define CAM_WEP104 0x05 ++#define CAM_SMS4 0x6 ++ ++#define TOTAL_CAM_ENTRY 32 ++#define HALF_CAM_ENTRY 16 ++ ++#define CAM_CONFIG_USEDK _TRUE ++#define CAM_CONFIG_NO_USEDK _FALSE ++ ++#define CAM_WRITE BIT16 ++#define CAM_READ 0x00000000 ++#define CAM_POLLINIG BIT31 ++ ++#define SCR_UseDK 0x01 ++#define SCR_TxSecEnable 0x02 ++#define SCR_RxSecEnable 0x04 ++ ++// ++// 10. Power Save Control Registers (Offset: 0x0260 - 0x02DF) ++// ++#define WOW_PMEN BIT0 // Power management Enable. ++#define WOW_WOMEN BIT1 // WoW function on or off. ++#define WOW_MAGIC BIT2 // Magic packet ++#define WOW_UWF BIT3 // Unicast Wakeup frame. ++ ++// ++// 12. Host Interrupt Status Registers (Offset: 0x0300 - 0x030F) ++// ++//---------------------------------------------------------------------------- ++//---------------------------------------------------------------------------- ++// 8188 IMR/ISR bits ++//---------------------------------------------------------------------------- ++#define IMR_DISABLED_88E 0x0 ++// IMR DW0(0x0060-0063) Bit 0-31 ++#define IMR_TXCCK_88E BIT30 // TXRPT interrupt when CCX bit of the packet is set ++#define IMR_PSTIMEOUT_88E BIT29 // Power Save Time Out Interrupt ++#define IMR_GTINT4_88E BIT28 // When GTIMER4 expires, this bit is set to 1 ++#define IMR_GTINT3_88E BIT27 // When GTIMER3 expires, this bit is set to 1 ++#define IMR_TBDER_88E BIT26 // Transmit Beacon0 Error ++#define IMR_TBDOK_88E BIT25 // Transmit Beacon0 OK ++#define IMR_TSF_BIT32_TOGGLE_88E BIT24 // TSF Timer BIT32 toggle indication interrupt ++#define IMR_BCNDMAINT0_88E BIT20 // Beacon DMA Interrupt 0 ++#define IMR_BCNDERR0_88E BIT16 // Beacon Queue DMA Error 0 ++#define IMR_HSISR_IND_ON_INT_88E BIT15 // HSISR Indicator (HSIMR & HSISR is true, this bit is set to 1) ++#define IMR_BCNDMAINT_E_88E BIT14 // Beacon DMA Interrupt Extension for Win7 ++#define IMR_ATIMEND_88E BIT12 // CTWidnow End or ATIM Window End ++#define IMR_HISR1_IND_INT_88E BIT11 // HISR1 Indicator (HISR1 & HIMR1 is true, this bit is set to 1) ++#define IMR_C2HCMD_88E BIT10 // CPU to Host Command INT Status, Write 1 clear ++#define IMR_CPWM2_88E BIT9 // CPU power Mode exchange INT Status, Write 1 clear ++#define IMR_CPWM_88E BIT8 // CPU power Mode exchange INT Status, Write 1 clear ++#define IMR_HIGHDOK_88E BIT7 // High Queue DMA OK ++#define IMR_MGNTDOK_88E BIT6 // Management Queue DMA OK ++#define IMR_BKDOK_88E BIT5 // AC_BK DMA OK ++#define IMR_BEDOK_88E BIT4 // AC_BE DMA OK ++#define IMR_VIDOK_88E BIT3 // AC_VI DMA OK ++#define IMR_VODOK_88E BIT2 // AC_VO DMA OK ++#define IMR_RDU_88E BIT1 // Rx Descriptor Unavailable ++#define IMR_ROK_88E BIT0 // Receive DMA OK ++ ++// IMR DW1(0x00B4-00B7) Bit 0-31 ++#define IMR_BCNDMAINT7_88E BIT27 // Beacon DMA Interrupt 7 ++#define IMR_BCNDMAINT6_88E BIT26 // Beacon DMA Interrupt 6 ++#define IMR_BCNDMAINT5_88E BIT25 // Beacon DMA Interrupt 5 ++#define IMR_BCNDMAINT4_88E BIT24 // Beacon DMA Interrupt 4 ++#define IMR_BCNDMAINT3_88E BIT23 // Beacon DMA Interrupt 3 ++#define IMR_BCNDMAINT2_88E BIT22 // Beacon DMA Interrupt 2 ++#define IMR_BCNDMAINT1_88E BIT21 // Beacon DMA Interrupt 1 ++#define IMR_BCNDERR7_88E BIT20 // Beacon Queue DMA Error Interrup 7 ++#define IMR_BCNDERR6_88E BIT19 // Beacon Queue DMA Error Interrup 6 ++#define IMR_BCNDERR5_88E BIT18 // Beacon Queue DMA Error Interrup 5 ++#define IMR_BCNDERR4_88E BIT17 // Beacon Queue DMA Error Interrup 4 ++#define IMR_BCNDERR3_88E BIT16 // Beacon Queue DMA Error Interrup 3 ++#define IMR_BCNDERR2_88E BIT15 // Beacon Queue DMA Error Interrup 2 ++#define IMR_BCNDERR1_88E BIT14 // Beacon Queue DMA Error Interrup 1 ++#define IMR_ATIMEND_E_88E BIT13 // ATIM Window End Extension for Win7 ++#define IMR_TXERR_88E BIT11 // Tx Error Flag Interrupt Status, write 1 clear. ++#define IMR_RXERR_88E BIT10 // Rx Error Flag INT Status, Write 1 clear ++#define IMR_TXFOVW_88E BIT9 // Transmit FIFO Overflow ++#define IMR_RXFOVW_88E BIT8 // Receive FIFO Overflow ++ ++#define HAL_NIC_UNPLUG_ISR 0xFFFFFFFF // The value when the NIC is unplugged for PCI. ++ ++ ++#ifdef CONFIG_PCI_HCI ++//#define IMR_RX_MASK (IMR_ROK_88E|IMR_RDU_88E|IMR_RXFOVW_88E) ++#define IMR_TX_MASK (IMR_VODOK_88E|IMR_VIDOK_88E|IMR_BEDOK_88E|IMR_BKDOK_88E|IMR_MGNTDOK_88E|IMR_HIGHDOK_88E|IMR_BCNDERR0_88E) ++ ++#ifdef CONFIG_CONCURRENT_MODE ++#define RT_IBSS_INT_MASKS (IMR_BCNDMAINT0_88E | IMR_TBDOK_88E | IMR_TBDER_88E | IMR_BCNDMAINT_E_88E) ++#else ++#define RT_IBSS_INT_MASKS (IMR_BCNDMAINT0_88E | IMR_TBDOK_88E | IMR_TBDER_88E) ++#endif ++ ++#define RT_AC_INT_MASKS (IMR_VIDOK_88E | IMR_VODOK_88E | IMR_BEDOK_88E|IMR_BKDOK_88E) ++#define RT_BSS_INT_MASKS (RT_IBSS_INT_MASKS) ++#endif ++ ++ ++// 8192C EFUSE ++//---------------------------------------------------------------------------- ++#define HWSET_MAX_SIZE 256 ++#define HWSET_MAX_SIZE_88E 512 ++ ++ ++ ++/*=================================================================== ++===================================================================== ++Here the register defines are for 92C. When the define is as same with 92C, ++we will use the 92C's define for the consistency ++So the following defines for 92C is not entire!!!!!! ++===================================================================== ++=====================================================================*/ ++/* ++Based on Datasheet V33---090401 ++Register Summary ++Current IOREG MAP ++0x0000h ~ 0x00FFh System Configuration (256 Bytes) ++0x0100h ~ 0x01FFh MACTOP General Configuration (256 Bytes) ++0x0200h ~ 0x027Fh TXDMA Configuration (128 Bytes) ++0x0280h ~ 0x02FFh RXDMA Configuration (128 Bytes) ++0x0300h ~ 0x03FFh PCIE EMAC Reserved Region (256 Bytes) ++0x0400h ~ 0x04FFh Protocol Configuration (256 Bytes) ++0x0500h ~ 0x05FFh EDCA Configuration (256 Bytes) ++0x0600h ~ 0x07FFh WMAC Configuration (512 Bytes) ++0x2000h ~ 0x3FFFh 8051 FW Download Region (8196 Bytes) ++*/ ++ //---------------------------------------------------------------------------- ++ // 8192C (TXPAUSE) transmission pause (Offset 0x522, 8 bits) ++ //---------------------------------------------------------------------------- ++// Note: ++// The the bits of stoping AC(VO/VI/BE/BK) queue in datasheet RTL8192S/RTL8192C are wrong, ++// the correct arragement is VO - Bit0, VI - Bit1, BE - Bit2, and BK - Bit3. ++// 8723 and 88E may be not correct either in the eralier version. Confirmed with DD Tim. ++// By Bruce, 2011-09-22. ++#define StopBecon BIT6 ++#define StopHigh BIT5 ++#define StopMgt BIT4 ++#define StopBK BIT3 ++#define StopBE BIT2 ++#define StopVI BIT1 ++#define StopVO BIT0 ++ ++//---------------------------------------------------------------------------- ++// 8192C (RCR) Receive Configuration Register (Offset 0x608, 32 bits) ++//---------------------------------------------------------------------------- ++#define RCR_APPFCS BIT31 //WMAC append FCS after pauload ++#define RCR_APP_MIC BIT30 // ++#define RCR_APP_PHYSTS BIT28// ++#define RCR_APP_ICV BIT29 // ++#define RCR_APP_PHYST_RXFF BIT28 // ++#define RCR_APP_BA_SSN BIT27 //Accept BA SSN ++#define RCR_ENMBID BIT24 //Enable Multiple BssId. ++#define RCR_LSIGEN BIT23 ++#define RCR_MFBEN BIT22 ++#define RCR_HTC_LOC_CTRL BIT14 //MFC<--HTC=1 MFC-->HTC=0 ++#define RCR_AMF BIT13 //Accept management type frame ++#define RCR_ACF BIT12 //Accept control type frame ++#define RCR_ADF BIT11 //Accept data type frame ++#define RCR_AICV BIT9 //Accept ICV error packet ++#define RCR_ACRC32 BIT8 //Accept CRC32 error packet ++#define RCR_CBSSID_BCN BIT7 //Accept BSSID match packet (Rx beacon, probe rsp) ++#define RCR_CBSSID_DATA BIT6 //Accept BSSID match packet (Data) ++#define RCR_CBSSID RCR_CBSSID_DATA //Accept BSSID match packet ++#define RCR_APWRMGT BIT5 //Accept power management packet ++#define RCR_ADD3 BIT4 //Accept address 3 match packet ++#define RCR_AB BIT3 //Accept broadcast packet ++#define RCR_AM BIT2 //Accept multicast packet ++#define RCR_APM BIT1 //Accept physical match packet ++#define RCR_AAP BIT0 //Accept all unicast packet ++#define RCR_MXDMA_OFFSET 8 ++#define RCR_FIFO_OFFSET 13 ++ ++//----------------------------------------------------- ++// ++// 0xFE00h ~ 0xFE55h USB Configuration ++// ++//----------------------------------------------------- ++#define REG_USB_INFO 0xFE17 ++#define REG_USB_SPECIAL_OPTION 0xFE55 ++#define REG_USB_DMA_AGG_TO 0xFE5B ++#define REG_USB_AGG_TO 0xFE5C ++#define REG_USB_AGG_TH 0xFE5D ++ ++#define REG_USB_HRPWM 0xFE58 ++#define REG_USB_HCPWM 0xFE57 ++ ++//============================================================================ ++// 8192C Regsiter Bit and Content definition ++//============================================================================ ++//----------------------------------------------------- ++// ++// 0x0000h ~ 0x00FFh System Configuration ++// ++//----------------------------------------------------- ++ ++//2 SYS_ISO_CTRL ++#define ISO_MD2PP BIT(0) ++#define ISO_UA2USB BIT(1) ++#define ISO_UD2CORE BIT(2) ++#define ISO_PA2PCIE BIT(3) ++#define ISO_PD2CORE BIT(4) ++#define ISO_IP2MAC BIT(5) ++#define ISO_DIOP BIT(6) ++#define ISO_DIOE BIT(7) ++#define ISO_EB2CORE BIT(8) ++#define ISO_DIOR BIT(9) ++#define PWC_EV12V BIT(15) ++ ++ ++//2 SYS_FUNC_EN ++#define FEN_BBRSTB BIT(0) ++#define FEN_BB_GLB_RSTn BIT(1) ++#define FEN_USBA BIT(2) ++#define FEN_UPLL BIT(3) ++#define FEN_USBD BIT(4) ++#define FEN_DIO_PCIE BIT(5) ++#define FEN_PCIEA BIT(6) ++#define FEN_PPLL BIT(7) ++#define FEN_PCIED BIT(8) ++#define FEN_DIOE BIT(9) ++#define FEN_CPUEN BIT(10) ++#define FEN_DCORE BIT(11) ++#define FEN_ELDR BIT(12) ++#define FEN_DIO_RF BIT(13) ++#define FEN_HWPDN BIT(14) ++#define FEN_MREGEN BIT(15) ++ ++//2 APS_FSMCO ++#define PFM_LDALL BIT(0) ++#define PFM_ALDN BIT(1) ++#define PFM_LDKP BIT(2) ++#define PFM_WOWL BIT(3) ++#define EnPDN BIT(4) ++#define PDN_PL BIT(5) ++#define APFM_ONMAC BIT(8) ++#define APFM_OFF BIT(9) ++#define APFM_RSM BIT(10) ++#define AFSM_HSUS BIT(11) ++#define AFSM_PCIE BIT(12) ++#define APDM_MAC BIT(13) ++#define APDM_HOST BIT(14) ++#define APDM_HPDN BIT(15) ++#define RDY_MACON BIT(16) ++#define SUS_HOST BIT(17) ++#define ROP_ALD BIT(20) ++#define ROP_PWR BIT(21) ++#define ROP_SPS BIT(22) ++#define SOP_MRST BIT(25) ++#define SOP_FUSE BIT(26) ++#define SOP_ABG BIT(27) ++#define SOP_AMB BIT(28) ++#define SOP_RCK BIT(29) ++#define SOP_A8M BIT(30) ++#define XOP_BTCK BIT(31) ++ ++//2 SYS_CLKR ++#define ANAD16V_EN BIT(0) ++#define ANA8M BIT(1) ++#define MACSLP BIT(4) ++#define LOADER_CLK_EN BIT(5) ++ ++ ++//2 9346CR ++ ++#define BOOT_FROM_EEPROM BIT(4) ++#define EEPROM_EN BIT(5) ++ ++ ++//2 SPS0_CTRL ++ ++ ++//2 SPS_OCP_CFG ++ ++ ++//2 RF_CTRL ++#define RF_EN BIT(0) ++#define RF_RSTB BIT(1) ++#define RF_SDMRSTB BIT(2) ++ ++ ++ ++//2 LDOV12D_CTRL ++#define LDV12_EN BIT(0) ++#define LDV12_SDBY BIT(1) ++#define LPLDO_HSM BIT(2) ++#define LPLDO_LSM_DIS BIT(3) ++#define _LDV12_VADJ(x) (((x) & 0xF) << 4) ++ ++ ++//2EFUSE_CTRL ++#define ALD_EN BIT(18) ++#define EF_PD BIT(19) ++#define EF_FLAG BIT(31) ++ ++//2 EFUSE_TEST (For RTL8723 partially) ++#define EF_TRPT BIT(7) ++#define EF_CELL_SEL (BIT(8)|BIT(9)) // 00: Wifi Efuse, 01: BT Efuse0, 10: BT Efuse1, 11: BT Efuse2 ++#define LDOE25_EN BIT(31) ++#define EFUSE_SEL(x) (((x) & 0x3) << 8) ++#define EFUSE_SEL_MASK 0x300 ++#define EFUSE_WIFI_SEL_0 0x0 ++#define EFUSE_BT_SEL_0 0x1 ++#define EFUSE_BT_SEL_1 0x2 ++#define EFUSE_BT_SEL_2 0x3 ++ ++#define EFUSE_ACCESS_ON 0x69 // For RTL8723 only. ++#define EFUSE_ACCESS_OFF 0x00 // For RTL8723 only. ++ ++ ++//2 8051FWDL ++//2 MCUFWDL ++#define MCUFWDL_EN BIT(0) ++#define MCUFWDL_RDY BIT(1) ++#define FWDL_ChkSum_rpt BIT(2) ++#define MACINI_RDY BIT(3) ++#define BBINI_RDY BIT(4) ++#define RFINI_RDY BIT(5) ++#define WINTINI_RDY BIT(6) ++#define RAM_DL_SEL BIT(7) // 1:RAM, 0:ROM ++#define ROM_DLEN BIT(19) ++#define CPRST BIT(23) ++ ++ ++ ++//2 REG_SYS_CFG ++#define XCLK_VLD BIT(0) ++#define ACLK_VLD BIT(1) ++#define UCLK_VLD BIT(2) ++#define PCLK_VLD BIT(3) ++#define PCIRSTB BIT(4) ++#define V15_VLD BIT(5) ++#define SW_OFFLOAD_EN BIT(7) ++#define SIC_IDLE BIT(8) ++#define BD_MAC2 BIT(9) ++#define BD_MAC1 BIT(10) ++#define IC_MACPHY_MODE BIT(11) ++#define CHIP_VER (BIT(12)|BIT(13)|BIT(14)|BIT(15)) ++#define BT_FUNC BIT(16) ++#define VENDOR_ID BIT(19) ++#define PAD_HWPD_IDN BIT(22) ++#define TRP_VAUX_EN BIT(23) // RTL ID ++#define TRP_BT_EN BIT(24) ++#define BD_PKG_SEL BIT(25) ++#define BD_HCI_SEL BIT(26) ++#define TYPE_ID BIT(27) ++ ++#define CHIP_VER_RTL_MASK 0xF000 //Bit 12 ~ 15 ++#define CHIP_VER_RTL_SHIFT 12 ++ ++ ++//2REG_GPIO_OUTSTS (For RTL8723 only) ++#define EFS_HCI_SEL (BIT(0)|BIT(1)) ++#define PAD_HCI_SEL (BIT(2)|BIT(3)) ++#define HCI_SEL (BIT(4)|BIT(5)) ++#define PKG_SEL_HCI BIT(6) ++#define FEN_GPS BIT(7) ++#define FEN_BT BIT(8) ++#define FEN_WL BIT(9) ++#define FEN_PCI BIT(10) ++#define FEN_USB BIT(11) ++#define BTRF_HWPDN_N BIT(12) ++#define WLRF_HWPDN_N BIT(13) ++#define PDN_BT_N BIT(14) ++#define PDN_GPS_N BIT(15) ++#define BT_CTL_HWPDN BIT(16) ++#define GPS_CTL_HWPDN BIT(17) ++#define PPHY_SUSB BIT(20) ++#define UPHY_SUSB BIT(21) ++#define PCI_SUSEN BIT(22) ++#define USB_SUSEN BIT(23) ++#define RF_RL_ID (BIT(31)|BIT(30)|BIT(29)|BIT(28)) ++ ++ ++//2SYS_CFG ++#define RTL_ID BIT(23) // TestChip ID, 1:Test(RLE); 0:MP(RL) ++ ++//----------------------------------------------------- ++// ++// 0x0100h ~ 0x01FFh MACTOP General Configuration ++// ++//----------------------------------------------------- ++ ++ ++//2 Function Enable Registers ++//2 CR ++ ++ ++ ++#define HCI_TXDMA_EN BIT(0) ++#define HCI_RXDMA_EN BIT(1) ++#define TXDMA_EN BIT(2) ++#define RXDMA_EN BIT(3) ++#define PROTOCOL_EN BIT(4) ++#define SCHEDULE_EN BIT(5) ++#define MACTXEN BIT(6) ++#define MACRXEN BIT(7) ++#define ENSWBCN BIT(8) ++#define ENSEC BIT(9) ++#define CALTMR_EN BIT(10) // 32k CAL TMR enable ++ ++// Network type ++#define _NETTYPE(x) (((x) & 0x3) << 16) ++#define MASK_NETTYPE 0x30000 ++#define NT_NO_LINK 0x0 ++#define NT_LINK_AD_HOC 0x1 ++#define NT_LINK_AP 0x2 ++#define NT_AS_AP 0x3 ++ ++ ++ ++//2 PBP - Page Size Register ++#define GET_RX_PAGE_SIZE(value) ((value) & 0xF) ++#define GET_TX_PAGE_SIZE(value) (((value) & 0xF0) >> 4) ++#define _PSRX_MASK 0xF ++#define _PSTX_MASK 0xF0 ++#define _PSRX(x) (x) ++#define _PSTX(x) ((x) << 4) ++ ++#define PBP_64 0x0 ++#define PBP_128 0x1 ++#define PBP_256 0x2 ++#define PBP_512 0x3 ++#define PBP_1024 0x4 ++ ++ ++//2 TX/RXDMA ++#define RXDMA_ARBBW_EN BIT(0) ++#define RXSHFT_EN BIT(1) ++#define RXDMA_AGG_EN BIT(2) ++#define QS_VO_QUEUE BIT(8) ++#define QS_VI_QUEUE BIT(9) ++#define QS_BE_QUEUE BIT(10) ++#define QS_BK_QUEUE BIT(11) ++#define QS_MANAGER_QUEUE BIT(12) ++#define QS_HIGH_QUEUE BIT(13) ++ ++#define HQSEL_VOQ BIT(0) ++#define HQSEL_VIQ BIT(1) ++#define HQSEL_BEQ BIT(2) ++#define HQSEL_BKQ BIT(3) ++#define HQSEL_MGTQ BIT(4) ++#define HQSEL_HIQ BIT(5) ++ ++// For normal driver, 0x10C ++#define _TXDMA_HIQ_MAP(x) (((x)&0x3) << 14) ++#define _TXDMA_MGQ_MAP(x) (((x)&0x3) << 12) ++#define _TXDMA_BKQ_MAP(x) (((x)&0x3) << 10) ++#define _TXDMA_BEQ_MAP(x) (((x)&0x3) << 8 ) ++#define _TXDMA_VIQ_MAP(x) (((x)&0x3) << 6 ) ++#define _TXDMA_VOQ_MAP(x) (((x)&0x3) << 4 ) ++ ++#define QUEUE_LOW 1 ++#define QUEUE_NORMAL 2 ++#define QUEUE_HIGH 3 ++ ++ ++ ++//2 TRXFF_BNDY ++ ++ ++//2 LLT_INIT ++#define _LLT_NO_ACTIVE 0x0 ++#define _LLT_WRITE_ACCESS 0x1 ++#define _LLT_READ_ACCESS 0x2 ++ ++#define _LLT_INIT_DATA(x) ((x) & 0xFF) ++#define _LLT_INIT_ADDR(x) (((x) & 0xFF) << 8) ++#define _LLT_OP(x) (((x) & 0x3) << 30) ++#define _LLT_OP_VALUE(x) (((x) >> 30) & 0x3) ++ ++ ++//----------------------------------------------------- ++// ++// 0x0200h ~ 0x027Fh TXDMA Configuration ++// ++//----------------------------------------------------- ++//2RQPN ++#define _HPQ(x) ((x) & 0xFF) ++#define _LPQ(x) (((x) & 0xFF) << 8) ++#define _PUBQ(x) (((x) & 0xFF) << 16) ++#define _NPQ(x) ((x) & 0xFF) // NOTE: in RQPN_NPQ register ++ ++ ++#define HPQ_PUBLIC_DIS BIT(24) ++#define LPQ_PUBLIC_DIS BIT(25) ++#define LD_RQPN BIT(31) ++ ++ ++//2TDECTRL ++#define BCN_VALID BIT(16) ++#define BCN_HEAD(x) (((x) & 0xFF) << 8) ++#define BCN_HEAD_MASK 0xFF00 ++ ++ ++//2 TDECTL ++#define BLK_DESC_NUM_SHIFT 4 ++#define BLK_DESC_NUM_MASK 0xF ++ ++ ++//2 TXDMA_OFFSET_CHK ++#define DROP_DATA_EN BIT(9) ++ ++ ++ ++ ++//----------------------------------------------------- ++// ++// 0x0280h ~ 0x028Bh RX DMA Configuration ++// ++//----------------------------------------------------- ++ ++// REG_RXDMA_CONTROL, 0x0286h ++// Write only. When this bit is set, RXDMA will decrease RX PKT counter by one. Before ++// this bit is polled, FW shall update RXFF_RD_PTR first. This register is write pulse and auto clear. ++//#define RXPKT_RELEASE_POLL BIT(0) ++// Read only. When RXMA finishes on-going DMA operation, RXMDA will report idle state in ++// this bit. FW can start releasing packets after RXDMA entering idle mode. ++//#define RXDMA_IDLE BIT(1) ++// When this bit is set, RXDMA will enter this mode after on-going RXDMA packet to host ++// completed, and stop DMA packet to host. RXDMA will then report Default: 0; ++//#define RW_RELEASE_EN BIT(2) ++ ++//2 REG_RXPKT_NUM, 0x0284 ++#define RXPKT_RELEASE_POLL BIT(16) ++#define RXDMA_IDLE BIT(17) ++#define RW_RELEASE_EN BIT(18) ++ ++//----------------------------------------------------- ++// ++// 0x0400h ~ 0x047Fh Protocol Configuration ++// ++//----------------------------------------------------- ++//2 FWHW_TXQ_CTRL ++#define EN_AMPDU_RTY_NEW BIT(7) ++ ++ ++//2 SPEC SIFS ++#define _SPEC_SIFS_CCK(x) ((x) & 0xFF) ++#define _SPEC_SIFS_OFDM(x) (((x) & 0xFF) << 8) ++ ++//2 RL ++#define RETRY_LIMIT_SHORT_SHIFT 8 ++#define RETRY_LIMIT_LONG_SHIFT 0 ++ ++ ++ ++ ++ ++//----------------------------------------------------- ++// ++// 0x0500h ~ 0x05FFh EDCA Configuration ++// ++//----------------------------------------------------- ++ ++ ++ ++//2 EDCA setting ++#define AC_PARAM_TXOP_LIMIT_OFFSET 16 ++#define AC_PARAM_ECW_MAX_OFFSET 12 ++#define AC_PARAM_ECW_MIN_OFFSET 8 ++#define AC_PARAM_AIFS_OFFSET 0 ++ ++ ++ ++#define _LRL(x) ((x) & 0x3F) ++#define _SRL(x) (((x) & 0x3F) << 8) ++ ++ ++//2 BCN_CTRL ++#define EN_MBSSID BIT(1) ++#define EN_TXBCN_RPT BIT(2) ++#define EN_BCN_FUNCTION BIT(3) ++#define DIS_TSF_UPDATE BIT(3) ++ ++// The same function but different bit field. ++#define DIS_TSF_UDT0_NORMAL_CHIP BIT(4) ++#define DIS_TSF_UDT0_TEST_CHIP BIT(5) ++#define STOP_BCNQ BIT(6) ++ ++ ++//2 ACMHWCTRL ++#define AcmHw_HwEn BIT(0) ++#define AcmHw_BeqEn BIT(1) ++#define AcmHw_ViqEn BIT(2) ++#define AcmHw_VoqEn BIT(3) ++#define AcmHw_BeqStatus BIT(4) ++#define AcmHw_ViqStatus BIT(5) ++#define AcmHw_VoqStatus BIT(6) ++ ++ ++ ++//----------------------------------------------------- ++// ++// 0x0600h ~ 0x07FFh WMAC Configuration ++// ++//----------------------------------------------------- ++//2APSD_CTRL ++#define APSDOFF BIT(6) ++#define APSDOFF_STATUS BIT(7) ++ ++ ++#define RATE_BITMAP_ALL 0xFFFFF ++ ++// Only use CCK 1M rate for ACK ++#define RATE_RRSR_CCK_ONLY_1M 0xFFFF1 ++ ++//2 TCR ++#define TSFRST BIT(0) ++#define DIS_GCLK BIT(1) ++#define PAD_SEL BIT(2) ++#define PWR_ST BIT(6) ++#define PWRBIT_OW_EN BIT(7) ++#define ACRC BIT(8) ++#define CFENDFORM BIT(9) ++#define ICV BIT(10) ++ ++ ++ ++//2 RCR ++#define AAP BIT(0) ++#define APM BIT(1) ++#define AM BIT(2) ++#define AB BIT(3) ++#define ADD3 BIT(4) ++#define APWRMGT BIT(5) ++#define CBSSID BIT(6) ++#define CBSSID_DATA BIT(6) ++#define CBSSID_BCN BIT(7) ++#define ACRC32 BIT(8) ++#define AICV BIT(9) ++#define ADF BIT(11) ++#define ACF BIT(12) ++#define AMF BIT(13) ++#define HTC_LOC_CTRL BIT(14) ++#define UC_DATA_EN BIT(16) ++#define BM_DATA_EN BIT(17) ++#define MFBEN BIT(22) ++#define LSIGEN BIT(23) ++#define EnMBID BIT(24) ++#define APP_BASSN BIT(27) ++#define APP_PHYSTS BIT(28) ++#define APP_ICV BIT(29) ++#define APP_MIC BIT(30) ++#define APP_FCS BIT(31) ++ ++ ++//2 SECCFG ++#define SCR_TxUseDK BIT(0) //Force Tx Use Default Key ++#define SCR_RxUseDK BIT(1) //Force Rx Use Default Key ++#define SCR_TxEncEnable BIT(2) //Enable Tx Encryption ++#define SCR_RxDecEnable BIT(3) //Enable Rx Decryption ++#define SCR_SKByA2 BIT(4) //Search kEY BY A2 ++#define SCR_NoSKMC BIT(5) //No Key Search Multicast ++#define SCR_TXBCUSEDK BIT(6) // Force Tx Broadcast packets Use Default Key ++#define SCR_RXBCUSEDK BIT(7) // Force Rx Broadcast packets Use Default Key ++ ++ ++//----------------------------------------------------- ++// ++// RTL8188E SDIO Configuration ++// ++//----------------------------------------------------- ++ ++// I/O bus domain address mapping ++#define SDIO_LOCAL_BASE 0x10250000 ++#define WLAN_IOREG_BASE 0x10260000 ++#define FIRMWARE_FIFO_BASE 0x10270000 ++#define TX_HIQ_BASE 0x10310000 ++#define TX_MIQ_BASE 0x10320000 ++#define TX_LOQ_BASE 0x10330000 ++#define RX_RX0FF_BASE 0x10340000 ++ ++// SDIO host local register space mapping. ++#define SDIO_LOCAL_MSK 0x0FFF ++#define WLAN_IOREG_MSK 0x7FFF ++#define WLAN_FIFO_MSK 0x1FFF // Aggregation Length[12:0] ++#define WLAN_RX0FF_MSK 0x0003 ++ ++#define SDIO_WITHOUT_REF_DEVICE_ID 0 // Without reference to the SDIO Device ID ++#define SDIO_LOCAL_DEVICE_ID 0 // 0b[16], 000b[15:13] ++#define WLAN_TX_HIQ_DEVICE_ID 4 // 0b[16], 100b[15:13] ++#define WLAN_TX_MIQ_DEVICE_ID 5 // 0b[16], 101b[15:13] ++#define WLAN_TX_LOQ_DEVICE_ID 6 // 0b[16], 110b[15:13] ++#define WLAN_RX0FF_DEVICE_ID 7 // 0b[16], 111b[15:13] ++#define WLAN_IOREG_DEVICE_ID 8 // 1b[16] ++ ++// SDIO Tx Free Page Index ++#define HI_QUEUE_IDX 0 ++#define MID_QUEUE_IDX 1 ++#define LOW_QUEUE_IDX 2 ++#define PUBLIC_QUEUE_IDX 3 ++ ++#define SDIO_MAX_TX_QUEUE 3 // HIQ, MIQ and LOQ ++#define SDIO_MAX_RX_QUEUE 1 ++ ++#define SDIO_REG_TX_CTRL 0x0000 // SDIO Tx Control ++#define SDIO_REG_HIMR 0x0014 // SDIO Host Interrupt Mask ++#define SDIO_REG_HISR 0x0018 // SDIO Host Interrupt Service Routine ++#define SDIO_REG_HCPWM 0x0019 // HCI Current Power Mode ++#define SDIO_REG_RX0_REQ_LEN 0x001C // RXDMA Request Length ++#define SDIO_REG_FREE_TXPG 0x0020 // Free Tx Buffer Page ++#define SDIO_REG_HCPWM1 0x0024 // HCI Current Power Mode 1 ++#define SDIO_REG_HCPWM2 0x0026 // HCI Current Power Mode 2 ++#define SDIO_REG_HTSFR_INFO 0x0030 // HTSF Informaion ++#define SDIO_REG_HRPWM1 0x0080 // HCI Request Power Mode 1 ++#define SDIO_REG_HRPWM2 0x0082 // HCI Request Power Mode 2 ++#define SDIO_REG_HPS_CLKR 0x0084 // HCI Power Save Clock ++#define SDIO_REG_HSUS_CTRL 0x0086 // SDIO HCI Suspend Control ++#define SDIO_REG_HIMR_ON 0x0090 // SDIO Host Extension Interrupt Mask Always ++#define SDIO_REG_HISR_ON 0x0091 // SDIO Host Extension Interrupt Status Always ++ ++#define SDIO_HIMR_DISABLED 0 ++ ++// RTL8188E SDIO Host Interrupt Mask Register ++#define SDIO_HIMR_RX_REQUEST_MSK BIT0 ++#define SDIO_HIMR_AVAL_MSK BIT1 ++#define SDIO_HIMR_TXERR_MSK BIT2 ++#define SDIO_HIMR_RXERR_MSK BIT3 ++#define SDIO_HIMR_TXFOVW_MSK BIT4 ++#define SDIO_HIMR_RXFOVW_MSK BIT5 ++#define SDIO_HIMR_TXBCNOK_MSK BIT6 ++#define SDIO_HIMR_TXBCNERR_MSK BIT7 ++#define SDIO_HIMR_BCNERLY_INT_MSK BIT16 ++#define SDIO_HIMR_C2HCMD_MSK BIT17 ++#define SDIO_HIMR_CPWM1_MSK BIT18 ++#define SDIO_HIMR_CPWM2_MSK BIT19 ++#define SDIO_HIMR_HSISR_IND_MSK BIT20 ++#define SDIO_HIMR_GTINT3_IND_MSK BIT21 ++#define SDIO_HIMR_GTINT4_IND_MSK BIT22 ++#define SDIO_HIMR_PSTIMEOUT_MSK BIT23 ++#define SDIO_HIMR_OCPINT_MSK BIT24 ++#define SDIO_HIMR_ATIMEND_MSK BIT25 ++#define SDIO_HIMR_ATIMEND_E_MSK BIT26 ++#define SDIO_HIMR_CTWEND_MSK BIT27 ++ ++//RTL8188E SDIO Specific ++#define SDIO_HIMR_MCU_ERR_MSK BIT28 ++#define SDIO_HIMR_TSF_BIT32_TOGGLE_MSK BIT29 ++ ++// SDIO Host Interrupt Service Routine ++#define SDIO_HISR_RX_REQUEST BIT0 ++#define SDIO_HISR_AVAL BIT1 ++#define SDIO_HISR_TXERR BIT2 ++#define SDIO_HISR_RXERR BIT3 ++#define SDIO_HISR_TXFOVW BIT4 ++#define SDIO_HISR_RXFOVW BIT5 ++#define SDIO_HISR_TXBCNOK BIT6 ++#define SDIO_HISR_TXBCNERR BIT7 ++#define SDIO_HISR_BCNERLY_INT BIT16 ++#define SDIO_HISR_C2HCMD BIT17 ++#define SDIO_HISR_CPWM1 BIT18 ++#define SDIO_HISR_CPWM2 BIT19 ++#define SDIO_HISR_HSISR_IND BIT20 ++#define SDIO_HISR_GTINT3_IND BIT21 ++#define SDIO_HISR_GTINT4_IND BIT22 ++#define SDIO_HISR_PSTIMEOUT BIT23 ++#define SDIO_HISR_OCPINT BIT24 ++#define SDIO_HISR_ATIMEND BIT25 ++#define SDIO_HISR_ATIMEND_E BIT26 ++#define SDIO_HISR_CTWEND BIT27 ++ ++//RTL8188E SDIO Specific ++#define SDIO_HISR_MCU_ERR BIT28 ++#define SDIO_HISR_TSF_BIT32_TOGGLE BIT29 ++ ++#define MASK_SDIO_HISR_CLEAR (SDIO_HISR_TXERR |\ ++ SDIO_HISR_RXERR |\ ++ SDIO_HISR_TXFOVW |\ ++ SDIO_HISR_RXFOVW |\ ++ SDIO_HISR_TXBCNOK |\ ++ SDIO_HISR_TXBCNERR |\ ++ SDIO_HISR_C2HCMD |\ ++ SDIO_HISR_CPWM1 |\ ++ SDIO_HISR_CPWM2 |\ ++ SDIO_HISR_HSISR_IND |\ ++ SDIO_HISR_GTINT3_IND |\ ++ SDIO_HISR_GTINT4_IND |\ ++ SDIO_HISR_PSTIMEOUT |\ ++ SDIO_HISR_OCPINT) ++ ++// SDIO HCI Suspend Control Register ++#define HCI_RESUME_PWR_RDY BIT1 ++#define HCI_SUS_CTRL BIT0 ++ ++// SDIO Tx FIFO related ++#define SDIO_TX_FREE_PG_QUEUE 4 // The number of Tx FIFO free page ++#define SDIO_TX_FIFO_PAGE_SZ 128 ++ ++/* move to rtl8188e_xmit.h ++#if DEV_BUS_TYPE == RT_SDIO_INTERFACE ++ #define MAX_TX_AGG_PACKET_NUMBER 0x8 ++#else ++ #define MAX_TX_AGG_PACKET_NUMBER 0xFF ++#endif ++*/ ++ ++// vivi added for new cam search flow, 20091028 ++//#define SCR_TxUseBroadcastDK BIT6 // Force Tx Use Broadcast Default Key ++//#define SCR_RxUseBroadcastDK BIT7 // Force Rx Use Broadcast Default Key ++ ++//----------------------------------------------------- ++// ++// 0xFE00h ~ 0xFE55h USB Configuration ++// ++//----------------------------------------------------- ++ ++//2 USB Information (0xFE17) ++#define USB_IS_HIGH_SPEED 0 ++#define USB_IS_FULL_SPEED 1 ++#define USB_SPEED_MASK BIT(5) ++ ++#define USB_NORMAL_SIE_EP_MASK 0xF ++#define USB_NORMAL_SIE_EP_SHIFT 4 ++ ++ ++//2 Special Option ++#define USB_AGG_EN BIT(3) ++ ++// 0; Use interrupt endpoint to upload interrupt pkt ++// 1; Use bulk endpoint to upload interrupt pkt, ++#define INT_BULK_SEL BIT(4) ++ ++ ++ ++//2REG_C2HEVT_CLEAR ++#define C2H_EVT_HOST_CLOSE 0x00 // Set by driver and notify FW that the driver has read the C2H command message ++#define C2H_EVT_FW_CLOSE 0xFF // Set by FW indicating that FW had set the C2H command message and it's not yet read by driver. ++ ++ ++//2REG_MULTI_FUNC_CTRL(For RTL8723 Only) ++#define WL_HWPDN_EN BIT0 // Enable GPIO[9] as WiFi HW PDn source ++#define WL_HWPDN_SL BIT1 // WiFi HW PDn polarity control ++#define WL_FUNC_EN BIT2 // WiFi function enable ++#define WL_HWROF_EN BIT3 // Enable GPIO[9] as WiFi RF HW PDn source ++#define BT_HWPDN_EN BIT16 // Enable GPIO[11] as BT HW PDn source ++#define BT_HWPDN_SL BIT17 // BT HW PDn polarity control ++#define BT_FUNC_EN BIT18 // BT function enable ++#define BT_HWROF_EN BIT19 // Enable GPIO[11] as BT/GPS RF HW PDn source ++#define GPS_HWPDN_EN BIT20 // Enable GPIO[10] as GPS HW PDn source ++#define GPS_HWPDN_SL BIT21 // GPS HW PDn polarity control ++#define GPS_FUNC_EN BIT22 // GPS function enable ++ ++ ++//3 REG_LIFECTRL_CTRL ++#define HAL92C_EN_PKT_LIFE_TIME_BK BIT3 ++#define HAL92C_EN_PKT_LIFE_TIME_BE BIT2 ++#define HAL92C_EN_PKT_LIFE_TIME_VI BIT1 ++#define HAL92C_EN_PKT_LIFE_TIME_VO BIT0 ++ ++#define HAL92C_MSDU_LIFE_TIME_UNIT 128 // in us, said by Tim. ++ ++//======================================================== ++// General definitions ++//======================================================== ++//#if (HAL_8195A_USB == 1) ++//#define LAST_ENTRY_OF_TX_PKT_BUFFER 255 ++//#else ++#define LAST_ENTRY_OF_TX_PKT_BUFFER 176 // 22k 22528 bytes ++//#endif ++ ++#define POLLING_LLT_THRESHOLD 20 ++//#if RTL8188E_FOR_MP_TEST == 1 ++//#define POLLING_READY_TIMEOUT_COUNT 3000 ++//#else ++#define POLLING_READY_TIMEOUT_COUNT 1000 ++//#endif ++// GPIO BIT ++#define HAL_8188E_HW_GPIO_WPS_BIT BIT7 ++ ++#if 0//(RTL8188E_SUPPORT == 1) ++////////////////////////////////ONLY for 88EE///////////////////////////////// ++// ++// Host Interrupt Status Registers (Offset: 0x00B4-00B7, 0x00BC-00BF) ++// Host Interrupt Mask Registers (Offset: 0x00B0-00B3, 0x00B8-00BB) ++// ++//---------------------------------------------------------------------------- ++// 8188 IMR/ISR bits ++//---------------------------------------------------------------------------- ++#define IMR_DISABLED_88E 0x0 ++// IMR DW0(0x00B0-00B3) Bit 0-31 ++#define IMR_TXCCK_88E BIT30 // TXRPT interrupt when CCX bit of the packet is set ++#define IMR_PSTIMEOUT_88E BIT29 // Power Save Time Out Interrupt ++#define IMR_GTINT4_88E BIT28 // When GTIMER4 expires, this bit is set to 1 ++#define IMR_GTINT3_88E BIT27 // When GTIMER3 expires, this bit is set to 1 ++#define IMR_TBDER_88E BIT26 // Transmit Beacon0 Error ++#define IMR_TBDOK_88E BIT25 // Transmit Beacon0 OK ++#define IMR_TSF_BIT32_TOGGLE_88E BIT24 // TSF Timer BIT32 toggle indication interrupt ++#define IMR_BcnInt_88E BIT20 // Beacon DMA Interrupt 0 ++#define IMR_BDOK_88E BIT16 // Beacon Queue DMA OK0 ++#define IMR_HSISR_IND_ON_INT_88E BIT15 // HSISR Indicator (HSIMR & HSISR is true, this bit is set to 1) ++#define IMR_BCNDMAINT_E_88E BIT14 // Beacon DMA Interrupt Extension for Win7 ++#define IMR_ATIMEND_88E BIT12 // CTWidnow End or ATIM Window End ++#define IMR_HISR1_IND_INT_88E BIT11 // HISR1 Indicator (HISR1 & HIMR1 is true, this bit is set to 1) ++#define IMR_C2HCMD_88E BIT10 // CPU to Host Command INT Status, Write 1 clear ++#define IMR_CPWM2_88E BIT9 // CPU power Mode exchange INT Status, Write 1 clear ++#define IMR_CPWM_88E BIT8 // CPU power Mode exchange INT Status, Write 1 clear ++#define IMR_HIGHDOK_88E BIT7 // High Queue DMA OK ++#define IMR_MGNTDOK_88E BIT6 // Management Queue DMA OK ++#define IMR_BKDOK_88E BIT5 // AC_BK DMA OK ++#define IMR_BEDOK_88E BIT4 // AC_BE DMA OK ++#define IMR_VIDOK_88E BIT3 // AC_VI DMA OK ++#define IMR_VODOK_88E BIT2 // AC_VO DMA OK ++#define IMR_RDU_88E BIT1 // Rx Descriptor Unavailable ++#define IMR_ROK_88E BIT0 // Receive DMA OK ++ ++// IMR DW1(0x00B8-00BB) Bit 0-31 ++#define IMR_BCNDMAINT7_88E BIT27 // Beacon DMA Interrupt 7 ++#define IMR_BCNDMAINT6_88E BIT26 // Beacon DMA Interrupt 6 ++#define IMR_BCNDMAINT5_88E BIT25 // Beacon DMA Interrupt 5 ++#define IMR_BCNDMAINT4_88E BIT24 // Beacon DMA Interrupt 4 ++#define IMR_BCNDMAINT3_88E BIT23 // Beacon DMA Interrupt 3 ++#define IMR_BCNDMAINT2_88E BIT22 // Beacon DMA Interrupt 2 ++#define IMR_BCNDMAINT1_88E BIT21 // Beacon DMA Interrupt 1 ++#define IMR_BCNDOK7_88E BIT20 // Beacon Queue DMA OK Interrup 7 ++#define IMR_BCNDOK6_88E BIT19 // Beacon Queue DMA OK Interrup 6 ++#define IMR_BCNDOK5_88E BIT18 // Beacon Queue DMA OK Interrup 5 ++#define IMR_BCNDOK4_88E BIT17 // Beacon Queue DMA OK Interrup 4 ++#define IMR_BCNDOK3_88E BIT16 // Beacon Queue DMA OK Interrup 3 ++#define IMR_BCNDOK2_88E BIT15 // Beacon Queue DMA OK Interrup 2 ++#define IMR_BCNDOK1_88E BIT14 // Beacon Queue DMA OK Interrup 1 ++#define IMR_ATIMEND_E_88E BIT13 // ATIM Window End Extension for Win7 ++#define IMR_TXERR_88E BIT11 // Tx Error Flag Interrupt Status, write 1 clear. ++#define IMR_RXERR_88E BIT10 // Rx Error Flag INT Status, Write 1 clear ++#define IMR_TXFOVW_88E BIT9 // Transmit FIFO Overflow ++#define IMR_RXFOVW_88E BIT8 // Receive FIFO Overflow ++ ++ ++ ++////////////////////////////////ONLY for 88EE///////////////////////////////// ++#endif //(RTL8188E_SUPPORT == 1) ++ ++ ++//---------------------------------------------------------------------------- ++// 8192C EEPROM/EFUSE share register definition. ++//---------------------------------------------------------------------------- ++ ++//==================================================== ++// EEPROM/Efuse PG Offset for 88EE/88EU/88ES ++//==================================================== ++#define EEPROM_TX_PWR_INX_88E 0x10 ++ ++#define EEPROM_ChannelPlan_88E 0xB8 ++#define EEPROM_XTAL_88E 0xB9 ++#define EEPROM_THERMAL_METER_88E 0xBA ++#define EEPROM_IQK_LCK_88E 0xBB ++ ++#define EEPROM_RF_BOARD_OPTION_88E 0xC1 ++#define EEPROM_RF_FEATURE_OPTION_88E 0xC2 ++#define EEPROM_RF_BT_SETTING_88E 0xC3 ++#define EEPROM_VERSION_88E 0xC4 ++#define EEPROM_CUSTOMERID_88E 0xC5 ++#define EEPROM_RF_ANTENNA_OPT_88E 0xC9 ++ ++#ifdef CONFIG_RF_GAIN_OFFSET ++#define EEPROM_RF_GAIN_OFFSET_88E 0xC1 ++#define EEPROM_RF_GAIN_VAL_88E 0xF6 //Physical address which is the BB gain offset value ++#endif //CONFIG_RF_GAIN_OFFSET ++ ++// RTL88EE ++#define EEPROM_MAC_ADDR_88EE 0xD0 ++#define EEPROM_VID_88EE 0xD6 ++#define EEPROM_DID_88EE 0xD8 ++#define EEPROM_SVID_88EE 0xDA ++#define EEPROM_SMID_88EE 0xDC ++ ++//RTL88EU ++#define EEPROM_MAC_ADDR_88EU 0xD7 ++#define EEPROM_VID_88EU 0xD0 ++#define EEPROM_PID_88EU 0xD2 ++#define EEPROM_USB_OPTIONAL_FUNCTION0 0xD4 ++ ++// RTL88ES ++#define EEPROM_MAC_ADDR_88ES 0x11A ++ ++ ++ ++ ++//==================================================== ++// EEPROM/Efuse Value Type ++//==================================================== ++#define EETYPE_TX_PWR 0x0 ++ ++// ++// Default Value for EEPROM or EFUSE!!! ++// ++#define EEPROM_Default_TSSI 0x0 ++#define EEPROM_Default_TxPowerDiff 0x0 ++#define EEPROM_Default_CrystalCap 0x5 ++#define EEPROM_Default_BoardType 0x02 // Default: 2X2, RTL8192CE(QFPN68) ++#define EEPROM_Default_TxPower 0x1010 ++#define EEPROM_Default_HT2T_TxPwr 0x10 ++ ++#define EEPROM_Default_LegacyHTTxPowerDiff 0x3 ++#define EEPROM_Default_ThermalMeter 0x12 ++ ++#define EEPROM_Default_AntTxPowerDiff 0x0 ++#define EEPROM_Default_TxPwDiff_CrystalCap 0x5 ++#if (RTL8188ES_SUPPORT==1) //for SDIO ++#define EEPROM_Default_TxPowerLevel 0x25 ++#else //for USB/PCIE ++#define EEPROM_Default_TxPowerLevel 0x2A ++#endif ++ ++#define EEPROM_Default_HT40_2SDiff 0x0 ++#define EEPROM_Default_HT20_Diff 2 // HT20<->40 default Tx Power Index Difference ++#define EEPROM_Default_LegacyHTTxPowerDiff 0x3 ++#define EEPROM_Default_HT40_PwrMaxOffset 0 ++#define EEPROM_Default_HT20_PwrMaxOffset 0 ++ ++#define EEPROM_Default_CrystalCap_88E 0x20 ++#define EEPROM_Default_ThermalMeter_88E 0x18 ++ ++#ifdef CONFIG_RF_GAIN_OFFSET ++#define EEPROM_Default_RFGainOffset 0xff ++#endif //CONFIG_RF_GAIN_OFFSET ++ ++//New EFUSE deafult value ++#define EEPROM_DEFAULT_24G_INDEX 0x2D ++#define EEPROM_DEFAULT_24G_HT20_DIFF 0X02 ++#define EEPROM_DEFAULT_24G_OFDM_DIFF 0X04 ++ ++#define EEPROM_DEFAULT_5G_INDEX 0X2A ++#define EEPROM_DEFAULT_5G_HT20_DIFF 0X00 ++#define EEPROM_DEFAULT_5G_OFDM_DIFF 0X04 ++ ++#define EEPROM_DEFAULT_DIFF 0XFE ++#define EEPROM_DEFAULT_CHANNEL_PLAN 0x7F ++#define EEPROM_DEFAULT_BOARD_OPTION 0x00 ++#define EEPROM_DEFAULT_FEATURE_OPTION 0x00 ++#define EEPROM_DEFAULT_BT_OPTION 0x10 ++ ++ ++// For debug ++#define EEPROM_Default_PID 0x1234 ++#define EEPROM_Default_VID 0x5678 ++#define EEPROM_Default_CustomerID 0xAB ++#define EEPROM_Default_CustomerID_8188E 0x00 ++#define EEPROM_Default_SubCustomerID 0xCD ++#define EEPROM_Default_Version 0 ++ ++#define EEPROM_CHANNEL_PLAN_FCC 0x0 ++#define EEPROM_CHANNEL_PLAN_IC 0x1 ++#define EEPROM_CHANNEL_PLAN_ETSI 0x2 ++#define EEPROM_CHANNEL_PLAN_SPAIN 0x3 ++#define EEPROM_CHANNEL_PLAN_FRANCE 0x4 ++#define EEPROM_CHANNEL_PLAN_MKK 0x5 ++#define EEPROM_CHANNEL_PLAN_MKK1 0x6 ++#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7 ++#define EEPROM_CHANNEL_PLAN_TELEC 0x8 ++#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9 ++#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA ++#define EEPROM_CHANNEL_PLAN_NCC 0xB ++#define EEPROM_USB_OPTIONAL1 0xE ++#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 ++ ++ ++#define EEPROM_CID_DEFAULT 0x0 ++#define EEPROM_CID_TOSHIBA 0x4 ++#define EEPROM_CID_CCX 0x10 // CCX test. By Bruce, 2009-02-25. ++#define EEPROM_CID_QMI 0x0D ++#define EEPROM_CID_WHQL 0xFE // added by chiyoko for dtm, 20090108 ++ ++ ++#define RTL_EEPROM_ID 0x8129 ++ ++#endif //__RTL8188E_SPEC_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_sreset.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_sreset.h +new file mode 100644 +index 00000000..67ae34c4 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_sreset.h +@@ -0,0 +1,33 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTL8188E_SRESET_H_ ++#define _RTL8188E_SRESET_H_ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef DBG_CONFIG_ERROR_DETECT ++extern void rtl8188e_sreset_xmit_status_check(_adapter *padapter); ++extern void rtl8188e_sreset_linked_status_check(_adapter *padapter); ++#endif ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_xmit.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_xmit.h +new file mode 100644 +index 00000000..842afc1a +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8188e_xmit.h +@@ -0,0 +1,311 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8188E_XMIT_H__ ++#define __RTL8188E_XMIT_H__ ++ ++#define MAX_TX_AGG_PACKET_NUMBER 0xFF ++// ++// Queue Select Value in TxDesc ++// ++#define QSLT_BK 0x2//0x01 ++#define QSLT_BE 0x0 ++#define QSLT_VI 0x5//0x4 ++#define QSLT_VO 0x7//0x6 ++#define QSLT_BEACON 0x10 ++#define QSLT_HIGH 0x11 ++#define QSLT_MGNT 0x12 ++#define QSLT_CMD 0x13 ++ ++//For 88e early mode ++#define SET_EARLYMODE_PKTNUM(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr, 0, 3, __Value) ++#define SET_EARLYMODE_LEN0(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr, 4, 12, __Value) ++#define SET_EARLYMODE_LEN1(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr, 16, 12, __Value) ++#define SET_EARLYMODE_LEN2_1(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr, 28, 4, __Value) ++#define SET_EARLYMODE_LEN2_2(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr+4, 0, 8, __Value) ++#define SET_EARLYMODE_LEN3(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr+4, 8, 12, __Value) ++#define SET_EARLYMODE_LEN4(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr+4, 20, 12, __Value) ++ ++// ++//defined for TX DESC Operation ++// ++ ++#define MAX_TID (15) ++ ++//OFFSET 0 ++#define OFFSET_SZ 0 ++#define OFFSET_SHT 16 ++#define BMC BIT(24) ++#define LSG BIT(26) ++#define FSG BIT(27) ++#define OWN BIT(31) ++ ++ ++//OFFSET 4 ++#define PKT_OFFSET_SZ 0 ++#define QSEL_SHT 8 ++#define RATE_ID_SHT 16 ++#define NAVUSEHDR BIT(20) ++#define SEC_TYPE_SHT 22 ++#define PKT_OFFSET_SHT 26 ++ ++//OFFSET 8 ++#define AGG_EN BIT(12) ++#define AGG_BK BIT(16) ++#define AMPDU_DENSITY_SHT 20 ++#define ANTSEL_A BIT(24) ++#define ANTSEL_B BIT(25) ++#define TX_ANT_CCK_SHT 26 ++#define TX_ANTL_SHT 28 ++#define TX_ANT_HT_SHT 30 ++ ++//OFFSET 12 ++#define SEQ_SHT 16 ++#define EN_HWSEQ BIT(31) ++ ++//OFFSET 16 ++#define QOS BIT(6) ++#define HW_SSN BIT(7) ++#define USERATE BIT(8) ++#define DISDATAFB BIT(10) ++#define CTS_2_SELF BIT(11) ++#define RTS_EN BIT(12) ++#define HW_RTS_EN BIT(13) ++#define DATA_SHORT BIT(24) ++#define PWR_STATUS_SHT 15 ++#define DATA_SC_SHT 20 ++#define DATA_BW BIT(25) ++ ++//OFFSET 20 ++#define RTY_LMT_EN BIT(17) ++ ++enum TXDESC_SC{ ++ SC_DONT_CARE = 0x00, ++ SC_UPPER= 0x01, ++ SC_LOWER=0x02, ++ SC_DUPLICATE=0x03 ++}; ++//OFFSET 20 ++#define SGI BIT(6) ++#define USB_TXAGG_NUM_SHT 24 ++ ++typedef struct txdesc_88e ++{ ++ //Offset 0 ++ u32 pktlen:16; ++ u32 offset:8; ++ u32 bmc:1; ++ u32 htc:1; ++ u32 ls:1; ++ u32 fs:1; ++ u32 linip:1; ++ u32 noacm:1; ++ u32 gf:1; ++ u32 own:1; ++ ++ //Offset 4 ++ u32 macid:6; ++ u32 rsvd0406:2; ++ u32 qsel:5; ++ u32 rd_nav_ext:1; ++ u32 lsig_txop_en:1; ++ u32 pifs:1; ++ u32 rate_id:4; ++ u32 navusehdr:1; ++ u32 en_desc_id:1; ++ u32 sectype:2; ++ u32 rsvd0424:2; ++ u32 pkt_offset:5; // unit: 8 bytes ++ u32 rsvd0431:1; ++ ++ //Offset 8 ++ u32 rts_rc:6; ++ u32 data_rc:6; ++ u32 agg_en:1; ++ u32 rd_en:1; ++ u32 bar_rty_th:2; ++ u32 bk:1; ++ u32 morefrag:1; ++ u32 raw:1; ++ u32 ccx:1; ++ u32 ampdu_density:3; ++ u32 bt_null:1; ++ u32 ant_sel_a:1; ++ u32 ant_sel_b:1; ++ u32 tx_ant_cck:2; ++ u32 tx_antl:2; ++ u32 tx_ant_ht:2; ++ ++ //Offset 12 ++ u32 nextheadpage:8; ++ u32 tailpage:8; ++ u32 seq:12; ++ u32 cpu_handle:1; ++ u32 tag1:1; ++ u32 trigger_int:1; ++ u32 hwseq_en:1; ++ ++ //Offset 16 ++ u32 rtsrate:5; ++ u32 ap_dcfe:1; ++ u32 hwseq_sel:2; ++ u32 userate:1; ++ u32 disrtsfb:1; ++ u32 disdatafb:1; ++ u32 cts2self:1; ++ u32 rtsen:1; ++ u32 hw_rts_en:1; ++ u32 port_id:1; ++ u32 pwr_status:3; ++ u32 wait_dcts:1; ++ u32 cts2ap_en:1; ++ u32 data_sc:2; ++ u32 data_stbc:2; ++ u32 data_short:1; ++ u32 data_bw:1; ++ u32 rts_short:1; ++ u32 rts_bw:1; ++ u32 rts_sc:2; ++ u32 vcs_stbc:2; ++ ++ //Offset 20 ++ u32 datarate:6; ++ u32 sgi:1; ++ u32 try_rate:1; ++ u32 data_ratefb_lmt:5; ++ u32 rts_ratefb_lmt:4; ++ u32 rty_lmt_en:1; ++ u32 data_rt_lmt:6; ++ u32 usb_txagg_num:8; ++ ++ //Offset 24 ++ u32 txagg_a:5; ++ u32 txagg_b:5; ++ u32 use_max_len:1; ++ u32 max_agg_num:5; ++ u32 mcsg1_max_len:4; ++ u32 mcsg2_max_len:4; ++ u32 mcsg3_max_len:4; ++ u32 mcs7_sgi_max_len:4; ++ ++ //Offset 28 ++ u32 checksum:16; // TxBuffSize(PCIe)/CheckSum(USB) ++ u32 sw0:8; /* offset 30 */ ++ u32 sw1:4; ++ u32 mcs15_sgi_max_len:4; ++}TXDESC, *PTXDESC; ++ ++#define txdesc_set_ccx_sw_88e(txdesc, value) \ ++ do { \ ++ ((struct txdesc_88e *)(txdesc))->sw1 = (((value)>>8) & 0x0f); \ ++ ((struct txdesc_88e *)(txdesc))->sw0 = ((value) & 0xff); \ ++ } while (0) ++ ++struct txrpt_ccx_88e { ++ /* offset 0 */ ++ u8 tag1:1; ++ u8 pkt_num:3; ++ u8 txdma_underflow:1; ++ u8 int_bt:1; ++ u8 int_tri:1; ++ u8 int_ccx:1; ++ ++ /* offset 1 */ ++ u8 mac_id:6; ++ u8 pkt_ok:1; ++ u8 bmc:1; ++ ++ /* offset 2 */ ++ u8 retry_cnt:6; ++ u8 lifetime_over:1; ++ u8 retry_over:1; ++ ++ /* offset 3 */ ++ u8 ccx_qtime0; ++ u8 ccx_qtime1; ++ ++ /* offset 5 */ ++ u8 final_data_rate; ++ ++ /* offset 6 */ ++ u8 sw1:4; ++ u8 qsel:4; ++ ++ /* offset 7 */ ++ u8 sw0; ++}; ++ ++#define txrpt_ccx_sw_88e(txrpt_ccx) ((txrpt_ccx)->sw0 + ((txrpt_ccx)->sw1<<8)) ++#define txrpt_ccx_qtime_88e(txrpt_ccx) ((txrpt_ccx)->ccx_qtime0+((txrpt_ccx)->ccx_qtime1<<8)) ++ ++void rtl8188e_fill_fake_txdesc(PADAPTER padapter,u8*pDesc,u32 BufferLen,u8 IsPsPoll,u8 IsBTQosNull); ++#ifdef CONFIG_SDIO_HCI ++s32 rtl8188es_init_xmit_priv(PADAPTER padapter); ++void rtl8188es_free_xmit_priv(PADAPTER padapter); ++s32 rtl8188es_hal_xmit(PADAPTER padapter, struct xmit_frame *pxmitframe); ++s32 rtl8188es_mgnt_xmit(PADAPTER padapter, struct xmit_frame *pmgntframe); ++s32 rtl8188es_hal_xmitframe_enqueue(_adapter *padapter, struct xmit_frame *pxmitframe); ++thread_return rtl8188es_xmit_thread(thread_context context); ++s32 rtl8188es_xmit_buf_handler(PADAPTER padapter); ++#define hal_xmit_handler rtl8188es_xmit_buf_handler ++ ++#ifdef CONFIG_SDIO_TX_TASKLET ++void rtl8188es_xmit_tasklet(void *priv); ++#endif ++#endif ++ ++#ifdef CONFIG_USB_HCI ++s32 rtl8188eu_init_xmit_priv(PADAPTER padapter); ++void rtl8188eu_free_xmit_priv(PADAPTER padapter); ++s32 rtl8188eu_hal_xmit(PADAPTER padapter, struct xmit_frame *pxmitframe); ++s32 rtl8188eu_mgnt_xmit(PADAPTER padapter, struct xmit_frame *pmgntframe); ++s32 rtl8188eu_hal_xmitframe_enqueue(_adapter *padapter, struct xmit_frame *pxmitframe); ++s32 rtl8188eu_xmit_buf_handler(PADAPTER padapter); ++#define hal_xmit_handler rtl8188eu_xmit_buf_handler ++void rtl8188eu_xmit_tasklet(void *priv); ++s32 rtl8188eu_xmitframe_complete(_adapter *padapter, struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf); ++#endif ++ ++#ifdef CONFIG_PCI_HCI ++s32 rtl8188ee_init_xmit_priv(PADAPTER padapter); ++void rtl8188ee_free_xmit_priv(PADAPTER padapter); ++struct xmit_buf *rtl8188ee_dequeue_xmitbuf(struct rtw_tx_ring *ring); ++void rtl8188ee_xmitframe_resume(_adapter *padapter); ++s32 rtl8188ee_hal_xmit(PADAPTER padapter, struct xmit_frame *pxmitframe); ++s32 rtl8188ee_mgnt_xmit(PADAPTER padapter, struct xmit_frame *pmgntframe); ++void rtl8188ee_xmit_tasklet(void *priv); ++#endif ++ ++ ++ ++#ifdef CONFIG_TX_EARLY_MODE ++void UpdateEarlyModeInfo8188E(struct xmit_priv *pxmitpriv,struct xmit_buf *pxmitbuf ); ++#endif ++ ++#ifdef CONFIG_XMIT_ACK ++void dump_txrpt_ccx_88e(void *buf); ++void handle_txrpt_ccx_88e(_adapter *adapter, u8 *buf); ++#else ++#define dump_txrpt_ccx_88e(buf) do {} while(0) ++#define handle_txrpt_ccx_88e(adapter, buf) do {} while(0) ++#endif //CONFIG_XMIT_ACK ++ ++void _dbg_dump_tx_info(_adapter *padapter,int frame_tag,struct tx_desc *ptxdesc); ++#endif //__RTL8188E_XMIT_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_cmd.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_cmd.h +new file mode 100644 +index 00000000..de1be78a +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_cmd.h +@@ -0,0 +1,116 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8192C_CMD_H_ ++#define __RTL8192C_CMD_H_ ++ ++ ++enum cmd_msg_element_id ++{ ++ NONE_CMDMSG_EID, ++ AP_OFFLOAD_EID=0, ++ SET_PWRMODE_EID=1, ++ JOINBSS_RPT_EID=2, ++ RSVD_PAGE_EID=3, ++ RSSI_4_EID = 4, ++ RSSI_SETTING_EID=5, ++ MACID_CONFIG_EID=6, ++ MACID_PS_MODE_EID=7, ++ P2P_PS_OFFLOAD_EID=8, ++ SELECTIVE_SUSPEND_ROF_CMD=9, ++ P2P_PS_CTW_CMD_EID=32, ++ H2C_92C_IO_OFFLOAD=44, ++ H2C_92C_TSF_SYNC=67, ++ H2C_92C_DISABLE_BCN_FUNC=68, ++ H2C_92C_RESET_TSF = 75, ++ H2C_92C_CMD_MAX ++}; ++ ++struct cmd_msg_parm { ++ u8 eid; //element id ++ u8 sz; // sz ++ u8 buf[6]; ++}; ++ ++typedef struct _SETPWRMODE_PARM{ ++ u8 Mode; ++ u8 SmartPS; ++ u8 BcnPassTime; // unit: 100ms ++}SETPWRMODE_PARM, *PSETPWRMODE_PARM; ++ ++struct H2C_SS_RFOFF_PARAM{ ++ u8 ROFOn; // 1: on, 0:off ++ u16 gpio_period; // unit: 1024 us ++}__attribute__ ((packed)); ++ ++ ++typedef struct JOINBSSRPT_PARM{ ++ u8 OpMode; // RT_MEDIA_STATUS ++}JOINBSSRPT_PARM, *PJOINBSSRPT_PARM; ++ ++typedef struct _RSVDPAGE_LOC{ ++ u8 LocProbeRsp; ++ u8 LocPsPoll; ++ u8 LocNullData; ++}RSVDPAGE_LOC, *PRSVDPAGE_LOC; ++ ++struct P2P_PS_Offload_t { ++ unsigned char Offload_En:1; ++ unsigned char role:1; // 1: Owner, 0: Client ++ unsigned char CTWindow_En:1; ++ unsigned char NoA0_En:1; ++ unsigned char NoA1_En:1; ++ unsigned char AllStaSleep:1; // Only valid in Owner ++ unsigned char discovery:1; ++ unsigned char rsvd:1; ++}; ++ ++struct P2P_PS_CTWPeriod_t { ++ unsigned char CTWPeriod; //TU ++}; ++ ++// host message to firmware cmd ++void rtl8192c_set_FwPwrMode_cmd(_adapter*padapter, u8 Mode); ++void rtl8192c_set_FwJoinBssReport_cmd(_adapter* padapter, u8 mstatus); ++u8 rtl8192c_set_rssi_cmd(_adapter*padapter, u8 *param); ++u8 rtl8192c_set_raid_cmd(_adapter*padapter, u32 mask, u8 arg); ++void rtl8192c_Add_RateATid(PADAPTER pAdapter, u32 bitmap, u8 arg, u8 rssi_level); ++u8 rtl8192c_set_FwSelectSuspend_cmd(_adapter*padapter,u8 bfwpoll, u16 period); ++#ifdef CONFIG_P2P ++void rtl8192c_set_p2p_ps_offload_cmd(_adapter* padapter, u8 p2p_ps_state); ++#endif //CONFIG_P2P ++ ++#ifdef CONFIG_IOL ++typedef struct _IO_OFFLOAD_LOC{ ++ u8 LocCmd; ++}IO_OFFLOAD_LOC, *PIO_OFFLOAD_LOC; ++int rtl8192c_IOL_exec_cmds_sync(ADAPTER *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt); ++#endif //CONFIG_IOL ++ ++#ifdef CONFIG_BEACON_DISABLE_OFFLOAD ++u8 rtl8192c_dis_beacon_fun_cmd(_adapter* padapter); ++#endif // CONFIG_BEACON_DISABLE_OFFLOAD ++ ++ ++#ifdef CONFIG_TSF_RESET_OFFLOAD ++u8 rtl8192c_reset_tsf(_adapter *padapter, u8 reset_port); ++#endif // CONFIG_TSF_RESET_OFFLOAD ++ ++#endif // __RTL8192C_CMD_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_dm.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_dm.h +new file mode 100644 +index 00000000..b017fb22 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_dm.h +@@ -0,0 +1,263 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8192C_DM_H__ ++#define __RTL8192C_DM_H__ ++//============================================================ ++// Description: ++// ++// This file is for 92CE/92CU dynamic mechanism only ++// ++// ++//============================================================ ++ ++//============================================================ ++// function prototype ++//============================================================ ++#define DYNAMIC_FUNC_BT BIT(0) ++ ++enum{ ++ UP_LINK, ++ DOWN_LINK, ++}; ++typedef enum _BT_Ant_NUM{ ++ Ant_x2 = 0, ++ Ant_x1 = 1 ++} BT_Ant_NUM, *PBT_Ant_NUM; ++ ++typedef enum _BT_CoType{ ++ BT_2Wire = 0, ++ BT_ISSC_3Wire = 1, ++ BT_Accel = 2, ++ BT_CSR_BC4 = 3, ++ BT_CSR_BC8 = 4, ++ BT_RTL8756 = 5, ++} BT_CoType, *PBT_CoType; ++ ++typedef enum _BT_CurState{ ++ BT_OFF = 0, ++ BT_ON = 1, ++} BT_CurState, *PBT_CurState; ++ ++typedef enum _BT_ServiceType{ ++ BT_SCO = 0, ++ BT_A2DP = 1, ++ BT_HID = 2, ++ BT_HID_Idle = 3, ++ BT_Scan = 4, ++ BT_Idle = 5, ++ BT_OtherAction = 6, ++ BT_Busy = 7, ++ BT_OtherBusy = 8, ++ BT_PAN = 9, ++} BT_ServiceType, *PBT_ServiceType; ++ ++typedef enum _BT_RadioShared{ ++ BT_Radio_Shared = 0, ++ BT_Radio_Individual = 1, ++} BT_RadioShared, *PBT_RadioShared; ++ ++struct btcoexist_priv { ++ u8 BT_Coexist; ++ u8 BT_Ant_Num; ++ u8 BT_CoexistType; ++ u8 BT_State; ++ u8 BT_CUR_State; //0:on, 1:off ++ u8 BT_Ant_isolation; //0:good, 1:bad ++ u8 BT_PapeCtrl; //0:SW, 1:SW/HW dynamic ++ u8 BT_Service; ++ u8 BT_Ampdu; // 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. ++ u8 BT_RadioSharedType; ++ u32 Ratio_Tx; ++ u32 Ratio_PRI; ++ u8 BtRfRegOrigin1E; ++ u8 BtRfRegOrigin1F; ++ u8 BtRssiState; ++ u32 BtEdcaUL; ++ u32 BtEdcaDL; ++ u32 BT_EDCA[2]; ++ u8 bCOBT; ++ ++ u8 bInitSet; ++ u8 bBTBusyTraffic; ++ u8 bBTTrafficModeSet; ++ u8 bBTNonTrafficModeSet; ++ //BTTraffic BT21TrafficStatistics; ++ u32 CurrentState; ++ u32 PreviousState; ++ u8 BtPreRssiState; ++ u8 bFWCoexistAllOff; ++ u8 bSWCoexistAllOff; ++}; ++ ++//============================================================ ++// structure and define ++//============================================================ ++ ++//###### duplicate code,will move to ODM ######### ++#define IQK_MAC_REG_NUM 4 ++#define IQK_ADDA_REG_NUM 16 ++#define IQK_BB_REG_NUM 9 ++#define HP_THERMAL_NUM 8 ++//###### duplicate code,will move to ODM ######### ++struct dm_priv ++{ ++ u8 DM_Type; ++ u8 DMFlag; ++ u8 InitDMFlag; ++ u32 InitODMFlag; ++ ++ //* Upper and Lower Signal threshold for Rate Adaptive*/ ++ int UndecoratedSmoothedPWDB; ++ int UndecoratedSmoothedCCK; ++ int EntryMinUndecoratedSmoothedPWDB; ++ int EntryMaxUndecoratedSmoothedPWDB; ++ int MinUndecoratedPWDBForDM; ++ int LastMinUndecoratedPWDBForDM; ++ ++//###### duplicate code,will move to ODM ######### ++/* ++ //for DIG ++ u8 bDMInitialGainEnable; ++ u8 binitialized; // for dm_initial_gain_Multi_STA use. ++ DIG_T DM_DigTable; ++ ++ PS_T DM_PSTable; ++ ++ FALSE_ALARM_STATISTICS FalseAlmCnt; ++ ++ //for rate adaptive, in fact, 88c/92c fw will handle this ++ u8 bUseRAMask; ++ RATE_ADAPTIVE RateAdaptive; ++*/ ++ //for High Power ++ u8 bDynamicTxPowerEnable; ++ u8 LastDTPLvl; ++ u8 DynamicTxHighPowerLvl;//Add by Jacken Tx Power Control for Near/Far Range 2008/03/06 ++ ++ //for tx power tracking ++ u8 bTXPowerTracking; ++ u8 TXPowercount; ++ u8 bTXPowerTrackingInit; ++ u8 TxPowerTrackControl; //for mp mode, turn off txpwrtracking as default ++ u8 TM_Trigger; ++ ++ u8 ThermalMeter[2]; // ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 ++ u8 ThermalValue; ++ u8 ThermalValue_LCK; ++ u8 ThermalValue_IQK; ++ u8 ThermalValue_DPK; ++ ++ u8 bRfPiEnable; ++ ++ //for APK ++ u32 APKoutput[2][2]; //path A/B; output1_1a/output1_2a ++ u8 bAPKdone; ++ u8 bAPKThermalMeterIgnore; ++ u8 bDPdone; ++ u8 bDPPathAOK; ++ u8 bDPPathBOK; ++ ++ //for IQK ++ u32 RegC04; ++ u32 Reg874; ++ u32 RegC08; ++ u32 RegB68; ++ u32 RegB6C; ++ u32 Reg870; ++ u32 Reg860; ++ u32 Reg864; ++ u32 ADDA_backup[IQK_ADDA_REG_NUM]; ++ u32 IQK_MAC_backup[IQK_MAC_REG_NUM]; ++ u32 IQK_BB_backup_recover[9]; ++ u32 IQK_BB_backup[IQK_BB_REG_NUM]; ++ u8 PowerIndex_backup[6]; ++ ++ u8 bCCKinCH14; ++ ++ u8 CCK_index; ++ u8 OFDM_index[2]; ++ ++ u8 bDoneTxpower; ++ u8 CCK_index_HP; ++ u8 OFDM_index_HP[2]; ++ u8 ThermalValue_HP[HP_THERMAL_NUM]; ++ u8 ThermalValue_HP_index; ++ ++ //for TxPwrTracking ++ s32 RegE94; ++ s32 RegE9C; ++ s32 RegEB4; ++ s32 RegEBC; ++ ++ u32 TXPowerTrackingCallbackCnt; //cosa add for debug ++ ++ u32 prv_traffic_idx; // edca turbo ++ ++/* ++ // for dm_RF_Saving ++ u8 initialize; ++ u32 rf_saving_Reg874; ++ u32 rf_saving_RegC70; ++ u32 rf_saving_Reg85C; ++ u32 rf_saving_RegA74; ++*/ ++ //for Antenna diversity ++#ifdef CONFIG_ANTENNA_DIVERSITY ++// SWAT_T DM_SWAT_Table; ++#endif ++#ifdef CONFIG_SW_ANTENNA_DIVERSITY ++// _timer SwAntennaSwitchTimer; ++/* ++ u64 lastTxOkCnt; ++ u64 lastRxOkCnt; ++ u64 TXByteCnt_A; ++ u64 TXByteCnt_B; ++ u64 RXByteCnt_A; ++ u64 RXByteCnt_B; ++ u8 DoubleComfirm; ++ u8 TrafficLoad; ++*/ ++#endif ++ ++ s32 OFDM_Pkt_Cnt; ++ u8 RSSI_Select; ++// u8 DIG_Dynamic_MIN ; ++//###### duplicate code,will move to ODM ######### ++ // Add for Reading Initial Data Rate SEL Register 0x484 during watchdog. Using for fill tx desc. 2011.3.21 by Thomas ++ u8 INIDATA_RATE[32]; ++}; ++ ++ ++//============================================================ ++// function prototype ++//============================================================ ++#ifdef CONFIG_BT_COEXIST ++void rtl8192c_set_dm_bt_coexist(_adapter *padapter, u8 bStart); ++void rtl8192c_issue_delete_ba(_adapter *padapter, u8 dir); ++#endif ++ ++void rtl8192c_init_dm_priv(IN PADAPTER Adapter); ++void rtl8192c_deinit_dm_priv(IN PADAPTER Adapter); ++ ++void rtl8192c_InitHalDm( IN PADAPTER Adapter); ++void rtl8192c_HalDmWatchDog(IN PADAPTER Adapter); ++ ++#endif //__HAL8190PCIDM_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_event.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_event.h +new file mode 100644 +index 00000000..7596531f +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_event.h +@@ -0,0 +1,28 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTL8192C_EVENT_H_ ++#define _RTL8192C_EVENT_H_ ++ ++ ++ ++ ++#endif ++ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_hal.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_hal.h +new file mode 100644 +index 00000000..2d54a198 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_hal.h +@@ -0,0 +1,849 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8192C_HAL_H__ ++#define __RTL8192C_HAL_H__ ++ ++#include "rtl8192c_spec.h" ++#include "Hal8192CPhyReg.h" ++#include "Hal8192CPhyCfg.h" ++#include "rtl8192c_rf.h" ++#include "rtl8192c_dm.h" ++#include "rtl8192c_recv.h" ++#include "rtl8192c_xmit.h" ++#include "rtl8192c_cmd.h" ++ ++#ifdef DBG_CONFIG_ERROR_DETECT ++#include "rtl8192c_sreset.h" ++#endif ++#include "rtw_efuse.h" ++ ++#include "../hal/OUTSRC/odm_precomp.h" ++ ++ ++#ifdef CONFIG_PCI_HCI ++ ++ #define RTL819X_DEFAULT_RF_TYPE RF_2T2R ++ //#define RTL819X_DEFAULT_RF_TYPE RF_1T2R ++ #define RTL819X_TOTAL_RF_PATH 2 ++ ++ //2TODO: The following need to check!! ++ #define RTL8192C_FW_TSMC_IMG "rtl8192CE\\rtl8192cfwT.bin" ++ #define RTL8192C_FW_UMC_IMG "rtl8192CE\\rtl8192cfwU.bin" ++ #define RTL8192C_FW_UMC_B_IMG "rtl8192CE\\rtl8192cfwU_B.bin" ++ ++ #define RTL8188C_PHY_REG "rtl8192CE\\PHY_REG_1T.txt" ++ #define RTL8188C_PHY_RADIO_A "rtl8192CE\\radio_a_1T.txt" ++ #define RTL8188C_PHY_RADIO_B "rtl8192CE\\radio_b_1T.txt" ++ #define RTL8188C_AGC_TAB "rtl8192CE\\AGC_TAB_1T.txt" ++ #define RTL8188C_PHY_MACREG "rtl8192CE\\MACREG_1T.txt" ++ ++ #define RTL8192C_PHY_REG "rtl8192CE\\PHY_REG_2T.txt" ++ #define RTL8192C_PHY_RADIO_A "rtl8192CE\\radio_a_2T.txt" ++ #define RTL8192C_PHY_RADIO_B "rtl8192CE\\radio_b_2T.txt" ++ #define RTL8192C_AGC_TAB "rtl8192CE\\AGC_TAB_2T.txt" ++ #define RTL8192C_PHY_MACREG "rtl8192CE\\MACREG_2T.txt" ++ ++ #define RTL819X_PHY_MACPHY_REG "rtl8192CE\\MACPHY_reg.txt" ++ #define RTL819X_PHY_MACPHY_REG_PG "rtl8192CE\\MACPHY_reg_PG.txt" ++ #define RTL819X_PHY_MACREG "rtl8192CE\\MAC_REG.txt" ++ #define RTL819X_PHY_REG "rtl8192CE\\PHY_REG.txt" ++ #define RTL819X_PHY_REG_1T2R "rtl8192CE\\PHY_REG_1T2R.txt" ++ #define RTL819X_PHY_REG_to1T1R "rtl8192CE\\phy_to1T1R_a.txt" ++ #define RTL819X_PHY_REG_to1T2R "rtl8192CE\\phy_to1T2R.txt" ++ #define RTL819X_PHY_REG_to2T2R "rtl8192CE\\phy_to2T2R.txt" ++ #define RTL819X_PHY_REG_PG "rtl8192CE\\PHY_REG_PG.txt" ++ #define RTL819X_AGC_TAB "rtl8192CE\\AGC_TAB.txt" ++ #define RTL819X_PHY_RADIO_A "rtl8192CE\\radio_a.txt" ++ #define RTL819X_PHY_RADIO_A_1T "rtl8192CE\\radio_a_1t.txt" ++ #define RTL819X_PHY_RADIO_A_2T "rtl8192CE\\radio_a_2t.txt" ++ #define RTL819X_PHY_RADIO_B "rtl8192CE\\radio_b.txt" ++ #define RTL819X_PHY_RADIO_B_GM "rtl8192CE\\radio_b_gm.txt" ++ #define RTL819X_PHY_RADIO_C "rtl8192CE\\radio_c.txt" ++ #define RTL819X_PHY_RADIO_D "rtl8192CE\\radio_d.txt" ++ #define RTL819X_EEPROM_MAP "rtl8192CE\\8192ce.map" ++ #define RTL819X_EFUSE_MAP "rtl8192CE\\8192ce.map" ++ ++//--------------------------------------------------------------------- ++// RTL8723E From file ++//--------------------------------------------------------------------- ++ ++ // The file name "_2T" is for 92CE, "_1T" is for 88CE. Modified by tynli. 2009.11.24. ++ #define Rtl819XFwTSMCImageArray Rtl8192CEFwTSMCImgArray ++ #define Rtl819XFwUMCACutImageArray Rtl8192CEFwUMCACutImgArray ++ #define Rtl819XFwUMCBCutImageArray Rtl8192CEFwUMCBCutImgArray ++ ++// #define Rtl8723FwUMCImageArray Rtl8192CEFwUMC8723ImgArray ++ #define Rtl819XMAC_Array Rtl8192CEMAC_2T_Array ++ #define Rtl819XAGCTAB_2TArray Rtl8192CEAGCTAB_2TArray ++ #define Rtl819XAGCTAB_1TArray Rtl8192CEAGCTAB_1TArray ++ #define Rtl819XPHY_REG_2TArray Rtl8192CEPHY_REG_2TArray ++ #define Rtl819XPHY_REG_1TArray Rtl8192CEPHY_REG_1TArray ++ #define Rtl819XRadioA_2TArray Rtl8192CERadioA_2TArray ++ #define Rtl819XRadioA_1TArray Rtl8192CERadioA_1TArray ++ #define Rtl819XRadioB_2TArray Rtl8192CERadioB_2TArray ++ #define Rtl819XRadioB_1TArray Rtl8192CERadioB_1TArray ++ #define Rtl819XPHY_REG_Array_PG Rtl8192CEPHY_REG_Array_PG ++ #define Rtl819XPHY_REG_Array_MP Rtl8192CEPHY_REG_Array_MP ++ ++ #define PHY_REG_2TArrayLength Rtl8192CEPHY_REG_2TArrayLength ++ #define PHY_REG_1TArrayLength Rtl8192CEPHY_REG_1TArrayLength ++ #define PHY_ChangeTo_1T1RArrayLength Rtl8192CEPHY_ChangeTo_1T1RArrayLength ++ #define PHY_ChangeTo_1T2RArrayLength Rtl8192CEPHY_ChangeTo_1T2RArrayLength ++ #define PHY_ChangeTo_2T2RArrayLength Rtl8192CEPHY_ChangeTo_2T2RArrayLength ++ #define PHY_REG_Array_PGLength Rtl8192CEPHY_REG_Array_PGLength ++ //#define PHY_REG_Array_PG_mCardLength Rtl8192CEPHY_REG_Array_PG_mCardLength ++ #define PHY_REG_Array_MPLength Rtl8192CEPHY_REG_Array_MPLength ++ #define PHY_REG_Array_MPLength Rtl8192CEPHY_REG_Array_MPLength ++ //#define PHY_REG_1T_mCardArrayLength Rtl8192CEPHY_REG_1T_mCardArrayLength ++ //#define PHY_REG_2T_mCardArrayLength Rtl8192CEPHY_REG_2T_mCardArrayLength ++ //#define PHY_REG_Array_PG_HPLength Rtl8192CEPHY_REG_Array_PG_HPLength ++ #define RadioA_2TArrayLength Rtl8192CERadioA_2TArrayLength ++ #define RadioB_2TArrayLength Rtl8192CERadioB_2TArrayLength ++ #define RadioA_1TArrayLength Rtl8192CERadioA_1TArrayLength ++ #define RadioB_1TArrayLength Rtl8192CERadioB_1TArrayLength ++ //#define RadioA_1T_mCardArrayLength Rtl8192CERadioA_1T_mCardArrayLength ++ //#define RadioB_1T_mCardArrayLength Rtl8192CERadioB_1T_mCardArrayLength ++ //#define RadioA_1T_HPArrayLength Rtl8192CERadioA_1T_HPArrayLength ++ #define RadioB_GM_ArrayLength Rtl8192CERadioB_GM_ArrayLength ++ #define MAC_2T_ArrayLength Rtl8192CEMAC_2T_ArrayLength ++ #define MACPHY_Array_PGLength Rtl8192CEMACPHY_Array_PGLength ++ #define AGCTAB_2TArrayLength Rtl8192CEAGCTAB_2TArrayLength ++ #define AGCTAB_1TArrayLength Rtl8192CEAGCTAB_1TArrayLength ++ //#define AGCTAB_1T_HPArrayLength Rtl8192CEAGCTAB_1T_HPArrayLength ++ ++#elif defined(CONFIG_USB_HCI) ++ ++ ++ //2TODO: We should define 8192S firmware related macro settings here!! ++ #define RTL819X_DEFAULT_RF_TYPE RF_1T2R ++ #define RTL819X_TOTAL_RF_PATH 2 ++ ++ //TODO: The following need to check!! ++ #define RTL8192C_FW_TSMC_IMG "rtl8192CU\\rtl8192cfwT.bin" ++ #define RTL8192C_FW_UMC_IMG "rtl8192CU\\rtl8192cfwU.bin" ++ #define RTL8192C_FW_UMC_B_IMG "rtl8192CU\\rtl8192cfwU_B.bin" ++ ++ //#define RTL819X_FW_BOOT_IMG "rtl8192CU\\boot.img" ++ //#define RTL819X_FW_MAIN_IMG "rtl8192CU\\main.img" ++ //#define RTL819X_FW_DATA_IMG "rtl8192CU\\data.img" ++ ++ #define RTL8188C_PHY_REG "rtl8188CU\\PHY_REG.txt" ++ #define RTL8188C_PHY_RADIO_A "rtl8188CU\\radio_a.txt" ++ #define RTL8188C_PHY_RADIO_B "rtl8188CU\\radio_b.txt" ++ #define RTL8188C_PHY_RADIO_A_mCard "rtl8192CU\\radio_a_1T_mCard.txt" ++ #define RTL8188C_PHY_RADIO_B_mCard "rtl8192CU\\radio_b_1T_mCard.txt" ++ #define RTL8188C_PHY_RADIO_A_HP "rtl8192CU\\radio_a_1T_HP.txt" ++ #define RTL8188C_AGC_TAB "rtl8188CU\\AGC_TAB.txt" ++ #define RTL8188C_PHY_MACREG "rtl8188CU\\MACREG.txt" ++ ++ #define RTL8192C_PHY_REG "rtl8192CU\\PHY_REG.txt" ++ #define RTL8192C_PHY_RADIO_A "rtl8192CU\\radio_a.txt" ++ #define RTL8192C_PHY_RADIO_B "rtl8192CU\\radio_b.txt" ++ #define RTL8192C_AGC_TAB "rtl8192CU\\AGC_TAB.txt" ++ #define RTL8192C_PHY_MACREG "rtl8192CU\\MACREG.txt" ++ ++ #define RTL819X_PHY_REG_PG "rtl8192CU\\PHY_REG_PG.txt" ++ ++//--------------------------------------------------------------------- ++// RTL8723U From file ++//--------------------------------------------------------------------- ++ ++ // The file name "_2T" is for 92CU, "_1T" is for 88CU. Modified by tynli. 2009.11.24. ++ #define Rtl819XFwImageArray Rtl8192CUFwTSMCImgArray ++ #define Rtl819XFwTSMCImageArray Rtl8192CUFwTSMCImgArray ++ #define Rtl819XFwUMCACutImageArray Rtl8192CUFwUMCACutImgArray ++ #define Rtl819XFwUMCBCutImageArray Rtl8192CUFwUMCBCutImgArray ++ ++ #define Rtl819XMAC_Array Rtl8192CUMAC_2T_Array ++ #define Rtl819XAGCTAB_2TArray Rtl8192CUAGCTAB_2TArray ++ #define Rtl819XAGCTAB_1TArray Rtl8192CUAGCTAB_1TArray ++ #define Rtl819XAGCTAB_1T_HPArray Rtl8192CUAGCTAB_1T_HPArray ++ #define Rtl819XPHY_REG_2TArray Rtl8192CUPHY_REG_2TArray ++ #define Rtl819XPHY_REG_1TArray Rtl8192CUPHY_REG_1TArray ++ #define Rtl819XPHY_REG_1T_mCardArray Rtl8192CUPHY_REG_1T_mCardArray ++ #define Rtl819XPHY_REG_2T_mCardArray Rtl8192CUPHY_REG_2T_mCardArray ++ #define Rtl819XPHY_REG_1T_HPArray Rtl8192CUPHY_REG_1T_HPArray ++ #define Rtl819XRadioA_2TArray Rtl8192CURadioA_2TArray ++ #define Rtl819XRadioA_1TArray Rtl8192CURadioA_1TArray ++ #define Rtl819XRadioA_1T_mCardArray Rtl8192CURadioA_1T_mCardArray ++ #define Rtl819XRadioB_2TArray Rtl8192CURadioB_2TArray ++ #define Rtl819XRadioB_1TArray Rtl8192CURadioB_1TArray ++ #define Rtl819XRadioB_1T_mCardArray Rtl8192CURadioB_1T_mCardArray ++ #define Rtl819XRadioA_1T_HPArray Rtl8192CURadioA_1T_HPArray ++ #define Rtl819XPHY_REG_Array_PG Rtl8192CUPHY_REG_Array_PG ++ #define Rtl819XPHY_REG_Array_PG_mCard Rtl8192CUPHY_REG_Array_PG_mCard ++ #define Rtl819XPHY_REG_Array_PG_HP Rtl8192CUPHY_REG_Array_PG_HP ++ #define Rtl819XPHY_REG_Array_MP Rtl8192CUPHY_REG_Array_MP ++ ++ #define PHY_REG_2TArrayLength Rtl8192CUPHY_REG_2TArrayLength ++ #define PHY_REG_1TArrayLength Rtl8192CUPHY_REG_1TArrayLength ++ #define PHY_ChangeTo_1T1RArrayLength Rtl8192CUPHY_ChangeTo_1T1RArrayLength ++ #define PHY_ChangeTo_1T2RArrayLength Rtl8192CUPHY_ChangeTo_1T2RArrayLength ++ #define PHY_ChangeTo_2T2RArrayLength Rtl8192CUPHY_ChangeTo_2T2RArrayLength ++ #define PHY_REG_Array_PGLength Rtl8192CUPHY_REG_Array_PGLength ++ #define PHY_REG_Array_PG_mCardLength Rtl8192CUPHY_REG_Array_PG_mCardLength ++ #define PHY_REG_Array_MPLength Rtl8192CUPHY_REG_Array_MPLength ++ #define PHY_REG_Array_MPLength Rtl8192CUPHY_REG_Array_MPLength ++ #define PHY_REG_1T_mCardArrayLength Rtl8192CUPHY_REG_1T_mCardArrayLength ++ #define PHY_REG_2T_mCardArrayLength Rtl8192CUPHY_REG_2T_mCardArrayLength ++ #define PHY_REG_Array_PG_HPLength Rtl8192CUPHY_REG_Array_PG_HPLength ++ #define RadioA_2TArrayLength Rtl8192CURadioA_2TArrayLength ++ #define RadioB_2TArrayLength Rtl8192CURadioB_2TArrayLength ++ #define RadioA_1TArrayLength Rtl8192CURadioA_1TArrayLength ++ #define RadioB_1TArrayLength Rtl8192CURadioB_1TArrayLength ++ #define RadioA_1T_mCardArrayLength Rtl8192CURadioA_1T_mCardArrayLength ++ #define RadioB_1T_mCardArrayLength Rtl8192CURadioB_1T_mCardArrayLength ++ #define RadioA_1T_HPArrayLength Rtl8192CURadioA_1T_HPArrayLength ++ #define RadioB_GM_ArrayLength Rtl8192CURadioB_GM_ArrayLength ++ #define MAC_2T_ArrayLength Rtl8192CUMAC_2T_ArrayLength ++ #define MACPHY_Array_PGLength Rtl8192CUMACPHY_Array_PGLength ++ #define AGCTAB_2TArrayLength Rtl8192CUAGCTAB_2TArrayLength ++ #define AGCTAB_1TArrayLength Rtl8192CUAGCTAB_1TArrayLength ++ #define AGCTAB_1T_HPArrayLength Rtl8192CUAGCTAB_1T_HPArrayLength ++ #define PHY_REG_1T_HPArrayLength Rtl8192CUPHY_REG_1T_HPArrayLength ++ ++#endif ++ ++#define DRVINFO_SZ 4 // unit is 8bytes ++#define PageNum_128(_Len) (u32)(((_Len)>>7) + ((_Len)&0x7F ? 1:0)) ++ ++#define FW_8192C_SIZE 16384+32//16k ++#define FW_8192C_START_ADDRESS 0x1000 ++//#define FW_8192C_END_ADDRESS 0x3FFF //Filen said this is for test chip ++#define FW_8192C_END_ADDRESS 0x1FFF ++ ++#define MAX_PAGE_SIZE 4096 // @ page : 4k bytes ++ ++#define IS_FW_HEADER_EXIST(_pFwHdr) ((le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x92C0 ||\ ++ (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x88C0 ||\ ++ (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x2300) ++ ++typedef enum _FIRMWARE_SOURCE{ ++ FW_SOURCE_IMG_FILE = 0, ++ FW_SOURCE_HEADER_FILE = 1, //from header file ++}FIRMWARE_SOURCE, *PFIRMWARE_SOURCE; ++ ++typedef struct _RT_FIRMWARE{ ++ FIRMWARE_SOURCE eFWSource; ++ u8* szFwBuffer; ++ u32 ulFwLength; ++}RT_FIRMWARE, *PRT_FIRMWARE, RT_FIRMWARE_92C, *PRT_FIRMWARE_92C; ++ ++// ++// This structure must be cared byte-ordering ++// ++// Added by tynli. 2009.12.04. ++typedef struct _RT_8192C_FIRMWARE_HDR {//8-byte alinment required ++ ++ //--- LONG WORD 0 ---- ++ u16 Signature; // 92C0: test chip; 92C, 88C0: test chip; 88C1: MP A-cut; 92C1: MP A-cut ++ u8 Category; // AP/NIC and USB/PCI ++ u8 Function; // Reserved for different FW function indcation, for further use when driver needs to download different FW in different conditions ++ u16 Version; // FW Version ++ u8 Subversion; // FW Subversion, default 0x00 ++ u16 Rsvd1; ++ ++ ++ //--- LONG WORD 1 ---- ++ u8 Month; // Release time Month field ++ u8 Date; // Release time Date field ++ u8 Hour; // Release time Hour field ++ u8 Minute; // Release time Minute field ++ u16 RamCodeSize; // The size of RAM code ++ u16 Rsvd2; ++ ++ //--- LONG WORD 2 ---- ++ u32 SvnIdx; // The SVN entry index ++ u32 Rsvd3; ++ ++ //--- LONG WORD 3 ---- ++ u32 Rsvd4; ++ u32 Rsvd5; ++ ++}RT_8192C_FIRMWARE_HDR, *PRT_8192C_FIRMWARE_HDR; ++ ++#define DRIVER_EARLY_INT_TIME 0x05 ++#define BCN_DMA_ATIME_INT_TIME 0x02 ++ ++#ifdef CONFIG_USB_RX_AGGREGATION ++ ++typedef enum _USB_RX_AGG_MODE{ ++ USB_RX_AGG_DISABLE, ++ USB_RX_AGG_DMA, ++ USB_RX_AGG_USB, ++ USB_RX_AGG_MIX ++}USB_RX_AGG_MODE; ++ ++#define MAX_RX_DMA_BUFFER_SIZE 10240 // 10K for 8192C RX DMA buffer ++ ++#endif ++ ++ ++#define TX_SELE_HQ BIT(0) // High Queue ++#define TX_SELE_LQ BIT(1) // Low Queue ++#define TX_SELE_NQ BIT(2) // Normal Queue ++ ++ ++// Note: We will divide number of page equally for each queue other than public queue! ++ ++#define TX_TOTAL_PAGE_NUMBER 0xF8 ++#define TX_PAGE_BOUNDARY (TX_TOTAL_PAGE_NUMBER + 1) ++ ++// For Normal Chip Setting ++// (HPQ + LPQ + NPQ + PUBQ) shall be TX_TOTAL_PAGE_NUMBER ++#define NORMAL_PAGE_NUM_PUBQ 0xE7 ++#define NORMAL_PAGE_NUM_HPQ 0x0C ++#define NORMAL_PAGE_NUM_LPQ 0x02 ++#define NORMAL_PAGE_NUM_NPQ 0x02 ++ ++ ++// For Test Chip Setting ++// (HPQ + LPQ + PUBQ) shall be TX_TOTAL_PAGE_NUMBER ++#define TEST_PAGE_NUM_PUBQ 0x7E ++ ++ ++// For Test Chip Setting ++#define WMM_TEST_TX_TOTAL_PAGE_NUMBER 0xF5 ++#define WMM_TEST_TX_PAGE_BOUNDARY (WMM_TEST_TX_TOTAL_PAGE_NUMBER + 1) //F6 ++ ++#define WMM_TEST_PAGE_NUM_PUBQ 0xA3 ++#define WMM_TEST_PAGE_NUM_HPQ 0x29 ++#define WMM_TEST_PAGE_NUM_LPQ 0x29 ++ ++ ++//Note: For Normal Chip Setting ,modify later ++#define WMM_NORMAL_TX_TOTAL_PAGE_NUMBER 0xF5 ++#define WMM_NORMAL_TX_PAGE_BOUNDARY (WMM_TEST_TX_TOTAL_PAGE_NUMBER + 1) //F6 ++ ++#define WMM_NORMAL_PAGE_NUM_PUBQ 0xB0 ++#define WMM_NORMAL_PAGE_NUM_HPQ 0x29 ++#define WMM_NORMAL_PAGE_NUM_LPQ 0x1C ++#define WMM_NORMAL_PAGE_NUM_NPQ 0x1C ++ ++//------------------------------------------------------------------------- ++// Chip specific ++//------------------------------------------------------------------------- ++#define CHIP_BONDING_IDENTIFIER(_value) (((_value)>>22)&0x3) ++#define CHIP_BONDING_92C_1T2R 0x1 ++#define CHIP_BONDING_88C_USB_MCARD 0x2 ++#define CHIP_BONDING_88C_USB_HP 0x1 ++ ++#include "HalVerDef.h" ++#include "hal_com.h" ++ ++//------------------------------------------------------------------------- ++// Channel Plan ++//------------------------------------------------------------------------- ++enum ChannelPlan{ ++ CHPL_FCC = 0, ++ CHPL_IC = 1, ++ CHPL_ETSI = 2, ++ CHPL_SPAIN = 3, ++ CHPL_FRANCE = 4, ++ CHPL_MKK = 5, ++ CHPL_MKK1 = 6, ++ CHPL_ISRAEL = 7, ++ CHPL_TELEC = 8, ++ CHPL_GLOBAL = 9, ++ CHPL_WORLD = 10, ++}; ++ ++typedef struct _TxPowerInfo{ ++ u8 CCKIndex[RF_PATH_MAX][CHANNEL_GROUP_MAX]; ++ u8 HT40_1SIndex[RF_PATH_MAX][CHANNEL_GROUP_MAX]; ++ u8 HT40_2SIndexDiff[RF_PATH_MAX][CHANNEL_GROUP_MAX]; ++ u8 HT20IndexDiff[RF_PATH_MAX][CHANNEL_GROUP_MAX]; ++ u8 OFDMIndexDiff[RF_PATH_MAX][CHANNEL_GROUP_MAX]; ++ u8 HT40MaxOffset[RF_PATH_MAX][CHANNEL_GROUP_MAX]; ++ u8 HT20MaxOffset[RF_PATH_MAX][CHANNEL_GROUP_MAX]; ++ u8 TSSI_A; ++ u8 TSSI_B; ++}TxPowerInfo, *PTxPowerInfo; ++ ++#define EFUSE_REAL_CONTENT_LEN 512 ++#define EFUSE_MAP_LEN 128 ++#define EFUSE_MAX_SECTION 16 ++#define EFUSE_IC_ID_OFFSET 506 //For some inferiority IC purpose. added by Roger, 2009.09.02. ++#define AVAILABLE_EFUSE_ADDR(addr) (addr < EFUSE_REAL_CONTENT_LEN) ++// ++// To prevent out of boundary programming case, leave 1byte and program full section ++// 9bytes + 1byt + 5bytes and pre 1byte. ++// For worst case: ++// | 1byte|----8bytes----|1byte|--5bytes--| ++// | | Reserved(14bytes) | ++// ++#define EFUSE_OOB_PROTECT_BYTES 15 // PG data exclude header, dummy 6 bytes frome CP test and reserved 1byte. ++ ++ ++#define EFUSE_MAP_LEN_8723 256 ++#define EFUSE_MAX_SECTION_8723 32 ++ ++//======================================================== ++// EFUSE for BT definition ++//======================================================== ++#define EFUSE_BT_REAL_CONTENT_LEN 1536 // 512*3 ++#define EFUSE_BT_MAP_LEN 1024 // 1k bytes ++#define EFUSE_BT_MAX_SECTION 128 // 1024/8 ++ ++#define EFUSE_PROTECT_BYTES_BANK 16 ++ ++// ++// For RTL8723 WiFi/BT/GPS multi-function configuration. 2010.10.06. ++// ++typedef enum _RT_MULTI_FUNC{ ++ RT_MULTI_FUNC_NONE = 0x00, ++ RT_MULTI_FUNC_WIFI = 0x01, ++ RT_MULTI_FUNC_BT = 0x02, ++ RT_MULTI_FUNC_GPS = 0x04, ++}RT_MULTI_FUNC,*PRT_MULTI_FUNC; ++ ++// ++// For RTL8723 WiFi PDn/GPIO polarity control configuration. 2010.10.08. ++// ++typedef enum _RT_POLARITY_CTL{ ++ RT_POLARITY_LOW_ACT = 0, ++ RT_POLARITY_HIGH_ACT = 1, ++}RT_POLARITY_CTL,*PRT_POLARITY_CTL; ++ ++// For RTL8723 regulator mode. by tynli. 2011.01.14. ++typedef enum _RT_REGULATOR_MODE{ ++ RT_SWITCHING_REGULATOR = 0, ++ RT_LDO_REGULATOR = 1, ++}RT_REGULATOR_MODE,*PRT_REGULATOR_MODE; ++ ++enum c2h_id_8192c { ++ C2H_DBG = 0, ++ C2H_TSF = 1, ++ C2H_AP_RPT_RSP = 2, ++ C2H_CCX_TX_RPT = 3, ++ C2H_BT_RSSI = 4, ++ C2H_BT_OP_MODE = 5, ++ C2H_EXT_RA_RPT = 6, ++ C2H_HW_INFO_EXCH = 10, ++ C2H_C2H_H2C_TEST = 11, ++ C2H_BT_INFO = 12, ++ C2H_BT_MP_INFO = 15, ++ MAX_C2HEVENT ++}; ++ ++#ifdef CONFIG_PCI_HCI ++struct hal_data_8192ce ++{ ++ HAL_VERSION VersionID; ++ RT_MULTI_FUNC MultiFunc; // For multi-function consideration. ++ RT_POLARITY_CTL PolarityCtl; // For Wifi PDn Polarity control. ++ RT_REGULATOR_MODE RegulatorMode; // switching regulator or LDO ++ u16 CustomerID; ++ ++ u16 FirmwareVersion; ++ u16 FirmwareVersionRev; ++ u16 FirmwareSubVersion; ++ ++ u32 IntrMask[2]; ++ u32 IntrMaskToSet[2]; ++ ++ u32 DisabledFunctions; ++ ++ //current WIFI_PHY values ++ u32 ReceiveConfig; ++ u32 TransmitConfig; ++ WIRELESS_MODE CurrentWirelessMode; ++ HT_CHANNEL_WIDTH CurrentChannelBW; ++ u8 CurrentChannel; ++ u8 nCur40MhzPrimeSC;// Control channel sub-carrier ++ ++ u16 BasicRateSet; ++ ++ //rf_ctrl ++ _lock rf_lock; ++ u8 rf_chip; ++ u8 rf_type; ++ u8 NumTotalRFPath; ++ ++ INTERFACE_SELECT_8192CPCIe InterfaceSel; ++ ++ // ++ // EEPROM setting. ++ // ++ u16 EEPROMVID; ++ u16 EEPROMDID; ++ u16 EEPROMSVID; ++ u16 EEPROMSMID; ++ u16 EEPROMChannelPlan; ++ u16 EEPROMVersion; ++ ++ u8 EEPROMChnlAreaTxPwrCCK[2][3]; ++ u8 EEPROMChnlAreaTxPwrHT40_1S[2][3]; ++ u8 EEPROMChnlAreaTxPwrHT40_2SDiff[2][3]; ++ u8 EEPROMPwrLimitHT20[3]; ++ u8 EEPROMPwrLimitHT40[3]; ++ ++ u8 bTXPowerDataReadFromEEPORM; ++ u8 EEPROMThermalMeter; ++ u8 EEPROMTSSI[2]; ++ ++ u8 EEPROMCustomerID; ++ u8 EEPROMBoardType; ++ u8 EEPROMRegulatory; ++ ++ u8 bDefaultAntenna; ++ u8 bIQKInitialized; ++ ++ u8 TxPwrLevelCck[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ u8 TxPwrLevelHT40_1S[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; // For HT 40MHZ pwr ++ u8 TxPwrLevelHT40_2S[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; // For HT 40MHZ pwr ++ u8 TxPwrHt20Diff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];// HT 20<->40 Pwr diff ++ u8 TxPwrLegacyHtDiff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];// For HT<->legacy pwr diff ++ // For power group ++ u8 PwrGroupHT20[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ u8 PwrGroupHT40[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ ++ u8 LegacyHTTxPowerDiff;// Legacy to HT rate power diff ++ ++ BOOLEAN EepromOrEfuse; ++ u8 EfuseMap[2][HWSET_MAX_SIZE_512]; //92C:256bytes, 88E:512bytes, we use union set (512bytes) ++ u8 EfuseUsedPercentage; ++ EFUSE_HAL EfuseHal; ++ ++#ifdef CONFIG_BT_COEXIST ++ struct btcoexist_priv bt_coexist; ++#endif ++ ++ // Read/write are allow for following hardware information variables ++ u8 framesync; ++ u32 framesyncC34; ++ u8 framesyncMonitor; ++ u8 DefaultInitialGain[4]; ++ u8 pwrGroupCnt; ++ u32 MCSTxPowerLevelOriginalOffset[7][16]; ++ u32 CCKTxPowerLevelOriginalOffset; ++ ++ u32 AntennaTxPath; // Antenna path Tx ++ u32 AntennaRxPath; // Antenna path Rx ++ u8 BluetoothCoexist; ++ u8 ExternalPA; ++ ++ //u32 LedControlNum; ++ //u32 LedControlMode; ++ u8 bLedOpenDrain; // Support Open-drain arrangement for controlling the LED. Added by Roger, 2009.10.16. ++ //u32 TxPowerTrackControl; ++ u8 b1x1RecvCombine; // for 1T1R receive combining ++ ++ u32 AcParam_BE; //Original parameter for BE, use for EDCA turbo. ++ ++ //vivi, for tx power tracking, 20080407 ++ //u16 TSSI_13dBm; ++ //u32 Pwr_Track; ++ // The current Tx Power Level ++ u8 CurrentCckTxPwrIdx; ++ u8 CurrentOfdm24GTxPwrIdx; ++ ++ BB_REGISTER_DEFINITION_T PHYRegDef[4]; //Radio A/B/C/D ++ ++ u32 RfRegChnlVal[2]; ++ ++ //RDG enable ++ BOOLEAN bRDGEnable; ++ ++ //for host message to fw ++ u8 LastHMEBoxNum; ++ ++ u8 fw_ractrl; ++ u8 RegTxPause; ++ // Beacon function related global variable. ++ u32 RegBcnCtrlVal; ++ u8 RegFwHwTxQCtrl; ++ u8 RegReg542; ++ u8 CurAntenna; ++ ++//### ODM-DUPLICATE CODE ### ++ u8 AntDivCfg; ++/* ++#ifdef CONFIG_SW_ANTENNA_DIVERSITY ++ //SW Antenna Switch ++ s32 RSSI_sum_A; ++ s32 RSSI_sum_B; ++ s32 RSSI_cnt_A; ++ s32 RSSI_cnt_B; ++ BOOLEAN RSSI_test; ++#endif ++#ifdef CONFIG_HW_ANTENNA_DIVERSITY ++ //Hybrid Antenna Diversity ++ u32 CCK_Ant1_Cnt; ++ u32 CCK_Ant2_Cnt; ++ u32 OFDM_Ant1_Cnt; ++ u32 OFDM_Ant2_Cnt; ++#endif ++*/ ++//### ODM-DUPLICATE CODE ### ++ struct dm_priv dmpriv; ++ DM_ODM_T odmpriv; ++ //_lock odm_stainfo_lock; ++ u8 bDumpRxPkt;//for debug ++#ifdef DBG_CONFIG_ERROR_DETECT ++ struct sreset_priv srestpriv; ++#endif ++ u8 bInterruptMigration; ++ u8 bDisableTxInt; ++ u8 bGpioHwWpsPbc; ++ ++ u8 FwRsvdPageStartOffset; //2010.06.23. Added by tynli. Reserve page start offset except beacon in TxQ. ++ ++ u16 EfuseUsedBytes; ++ ++#ifdef CONFIG_P2P ++ struct P2P_PS_Offload_t p2p_ps_offload; ++#endif //CONFIG_P2P ++}; ++ ++typedef struct hal_data_8192ce HAL_DATA_TYPE, *PHAL_DATA_TYPE; ++ ++// ++// Function disabled. ++// ++#define DF_TX_BIT BIT0 ++#define DF_RX_BIT BIT1 ++#define DF_IO_BIT BIT2 ++#define DF_IO_D3_BIT BIT3 ++ ++#define RT_DF_TYPE u32 ++#define RT_DISABLE_FUNC(__pAdapter, __FuncBits) ((__pAdapter)->DisabledFunctions |= ((RT_DF_TYPE)(__FuncBits))) ++#define RT_ENABLE_FUNC(__pAdapter, __FuncBits) ((__pAdapter)->DisabledFunctions &= (~((RT_DF_TYPE)(__FuncBits)))) ++#define RT_IS_FUNC_DISABLED(__pAdapter, __FuncBits) ( (__pAdapter)->DisabledFunctions & (__FuncBits) ) ++#define IS_MULTI_FUNC_CHIP(_Adapter) (((((PHAL_DATA_TYPE)(_Adapter->HalData))->MultiFunc) & (RT_MULTI_FUNC_BT|RT_MULTI_FUNC_GPS)) ? _TRUE : _FALSE) ++ ++void InterruptRecognized8192CE(PADAPTER Adapter, PRT_ISR_CONTENT pIsrContent); ++VOID UpdateInterruptMask8192CE(PADAPTER Adapter, u32 AddMSR, u32 AddMSR1, u32 RemoveMSR, u32 RemoveMSR1); ++#endif ++ ++#ifdef CONFIG_USB_HCI ++struct hal_data_8192cu ++{ ++ HAL_VERSION VersionID; ++ RT_MULTI_FUNC MultiFunc; // For multi-function consideration. ++ RT_POLARITY_CTL PolarityCtl; // For Wifi PDn Polarity control. ++ RT_REGULATOR_MODE RegulatorMode; // switching regulator or LDO ++ u16 CustomerID; ++ ++ u16 FirmwareVersion; ++ u16 FirmwareVersionRev; ++ u16 FirmwareSubVersion; ++ ++ //current WIFI_PHY values ++ u32 ReceiveConfig; ++ WIRELESS_MODE CurrentWirelessMode; ++ HT_CHANNEL_WIDTH CurrentChannelBW; ++ u8 CurrentChannel; ++ u8 nCur40MhzPrimeSC;// Control channel sub-carrier ++ ++ u16 BasicRateSet; ++ ++ //rf_ctrl ++ u8 rf_chip; ++ u8 rf_type; ++ u8 NumTotalRFPath; ++ ++ u8 BoardType; ++ //INTERFACE_SELECT_8192CUSB InterfaceSel; ++ ++ // ++ // EEPROM setting. ++ // ++ u16 EEPROMVID; ++ u16 EEPROMPID; ++ u16 EEPROMSVID; ++ u16 EEPROMSDID; ++ u8 EEPROMCustomerID; ++ u8 EEPROMSubCustomerID; ++ u8 EEPROMVersion; ++ u8 EEPROMRegulatory; ++ ++ u8 bTXPowerDataReadFromEEPORM; ++ u8 EEPROMThermalMeter; ++ ++ u8 bIQKInitialized; ++ ++ u8 TxPwrLevelCck[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ u8 TxPwrLevelHT40_1S[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; // For HT 40MHZ pwr ++ u8 TxPwrLevelHT40_2S[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; // For HT 40MHZ pwr ++ s8 TxPwrHt20Diff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];// HT 20<->40 Pwr diff ++ u8 TxPwrLegacyHtDiff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];// For HT<->legacy pwr diff ++ // For power group ++ u8 PwrGroupHT20[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ u8 PwrGroupHT40[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ ++ u8 LegacyHTTxPowerDiff;// Legacy to HT rate power diff ++ ++ // Read/write are allow for following hardware information variables ++ u8 framesync; ++ u32 framesyncC34; ++ u8 framesyncMonitor; ++ u8 DefaultInitialGain[4]; ++ u8 pwrGroupCnt; ++ u32 MCSTxPowerLevelOriginalOffset[7][16]; ++ u32 CCKTxPowerLevelOriginalOffset; ++ ++ u32 AntennaTxPath; // Antenna path Tx ++ u32 AntennaRxPath; // Antenna path Rx ++ u8 BluetoothCoexist; ++ u8 ExternalPA; ++ ++ u8 bLedOpenDrain; // Support Open-drain arrangement for controlling the LED. Added by Roger, 2009.10.16. ++ ++ //u32 LedControlNum; ++ //u32 LedControlMode; ++ //u32 TxPowerTrackControl; ++ u8 b1x1RecvCombine; // for 1T1R receive combining ++ ++ u32 AcParam_BE; //Original parameter for BE, use for EDCA turbo. ++ ++ //vivi, for tx power tracking, 20080407 ++ //u16 TSSI_13dBm; ++ //u32 Pwr_Track; ++ // The current Tx Power Level ++ u8 CurrentCckTxPwrIdx; ++ u8 CurrentOfdm24GTxPwrIdx; ++ ++ BB_REGISTER_DEFINITION_T PHYRegDef[4]; //Radio A/B/C/D ++ ++ u32 RfRegChnlVal[2]; ++ ++ //RDG enable ++ BOOLEAN bRDGEnable; ++ ++ //for host message to fw ++ u8 LastHMEBoxNum; ++ ++ u8 fw_ractrl; ++ u8 RegTxPause; ++ // Beacon function related global variable. ++ u32 RegBcnCtrlVal; ++ u8 RegFwHwTxQCtrl; ++ u8 RegReg542; ++ ++ struct dm_priv dmpriv; ++ DM_ODM_T odmpriv; ++ //_lock odm_stainfo_lock; ++#ifdef DBG_CONFIG_ERROR_DETECT ++ struct sreset_priv srestpriv; ++#endif ++ ++#ifdef CONFIG_BT_COEXIST ++ struct btcoexist_priv bt_coexist; ++#endif ++ u8 CurAntenna; ++ ++/*****ODM duplicate data********/ ++ u8 AntDivCfg; ++/* ++#ifdef CONFIG_SW_ANTENNA_DIVERSITY ++ ++ //SW Antenna Switch ++ s32 RSSI_sum_A; ++ s32 RSSI_sum_B; ++ s32 RSSI_cnt_A; ++ s32 RSSI_cnt_B; ++ BOOLEAN RSSI_test; ++#endif ++ ++#ifdef CONFIG_HW_ANTENNA_DIVERSITY ++ //Hybrid Antenna Diversity ++ u32 CCK_Ant1_Cnt; ++ u32 CCK_Ant2_Cnt; ++ u32 OFDM_Ant1_Cnt; ++ u32 OFDM_Ant2_Cnt; ++#endif ++*/ ++ u8 bDumpRxPkt;//for debug ++ u8 FwRsvdPageStartOffset; //2010.06.23. Added by tynli. Reserve page start offset except beacon in TxQ. ++ ++ // 2010/08/09 MH Add CU power down mode. ++ BOOLEAN pwrdown; ++ ++ // For 92C USB endpoint setting ++ // ++ ++ u32 UsbBulkOutSize; ++ ++ // Add for dual MAC 0--Mac0 1--Mac1 ++ u32 interfaceIndex; ++ ++ u8 OutEpQueueSel; ++ u8 OutEpNumber; ++ ++#ifdef CONFIG_USB_TX_AGGREGATION ++ u8 UsbTxAggMode; ++ u8 UsbTxAggDescNum; ++#endif ++#ifdef CONFIG_USB_RX_AGGREGATION ++ u16 HwRxPageSize; // Hardware setting ++ u32 MaxUsbRxAggBlock; ++ ++ USB_RX_AGG_MODE UsbRxAggMode; ++ u8 UsbRxAggBlockCount; // USB Block count. Block size is 512-byte in hight speed and 64-byte in full speed ++ u8 UsbRxAggBlockTimeout; ++ u8 UsbRxAggPageCount; // 8192C DMA page count ++ u8 UsbRxAggPageTimeout; ++#endif ++ ++ // 2010/12/10 MH Add for USB aggreation mode dynamic shceme. ++ BOOLEAN UsbRxHighSpeedMode; ++ ++ // 2010/11/22 MH Add for slim combo debug mode selective. ++ // This is used for fix the drawback of CU TSMC-A/UMC-A cut. HW auto suspend ability. Close BT clock. ++ BOOLEAN SlimComboDbg; ++ ++ u16 EfuseUsedBytes; ++ ++ BOOLEAN EepromOrEfuse; ++ u8 EfuseMap[2][HWSET_MAX_SIZE_512]; //92C:256bytes, 88E:512bytes, we use union set (512bytes) ++ u8 EfuseUsedPercentage; ++ EFUSE_HAL EfuseHal; ++ ++ ++#ifdef CONFIG_P2P ++ struct P2P_PS_Offload_t p2p_ps_offload; ++#endif //CONFIG_P2P ++}; ++ ++typedef struct hal_data_8192cu HAL_DATA_TYPE, *PHAL_DATA_TYPE; ++#endif ++ ++#define GET_HAL_DATA(__pAdapter) ((HAL_DATA_TYPE *)((__pAdapter)->HalData)) ++#define GET_RF_TYPE(priv) (GET_HAL_DATA(priv)->rf_type) ++ ++#define INCLUDE_MULTI_FUNC_BT(_Adapter) (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_BT) ++#define INCLUDE_MULTI_FUNC_GPS(_Adapter) (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_GPS) ++ ++VOID rtl8192c_FirmwareSelfReset(IN PADAPTER Adapter); ++int FirmwareDownload92C(IN PADAPTER Adapter); ++VOID InitializeFirmwareVars92C(PADAPTER Adapter); ++u8 GetEEPROMSize8192C(PADAPTER Adapter); ++void rtl8192c_EfuseParseChnlPlan(PADAPTER padapter, u8 *hwinfo, BOOLEAN AutoLoadFail); ++ ++HAL_VERSION rtl8192c_ReadChipVersion(IN PADAPTER Adapter); ++void rtl8192c_ReadBluetoothCoexistInfo(PADAPTER Adapter, u8 *PROMContent, BOOLEAN AutoloadFail); ++//void rtl8192c_free_hal_data(_adapter * padapter); ++VOID rtl8192c_EfuseParseIDCode(PADAPTER pAdapter, u8 *hwinfo); ++void rtl8192c_set_hal_ops(struct hal_ops *pHalFunc); ++ ++s32 c2h_id_filter_ccx_8192c(u8 id); ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_led.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_led.h +new file mode 100644 +index 00000000..df2a9998 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_led.h +@@ -0,0 +1,42 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8192C_LED_H_ ++#define __RTL8192C_LED_H_ ++ ++#include ++#include ++#include ++ ++ ++//================================================================================ ++// Interface to manipulate LED objects. ++//================================================================================ ++#ifdef CONFIG_USB_HCI ++void rtl8192cu_InitSwLeds(_adapter *padapter); ++void rtl8192cu_DeInitSwLeds(_adapter *padapter); ++#endif ++#ifdef CONFIG_PCI_HCI ++void rtl8192ce_gen_RefreshLedState(PADAPTER Adapter); ++void rtl8192ce_InitSwLeds(_adapter *padapter); ++void rtl8192ce_DeInitSwLeds(_adapter *padapter); ++#endif ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_recv.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_recv.h +new file mode 100644 +index 00000000..0a237dc1 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_recv.h +@@ -0,0 +1,147 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTL8192C_RECV_H_ ++#define _RTL8192C_RECV_H_ ++ ++#include ++#include ++#include ++ ++ ++#ifdef PLATFORM_OS_XP ++ #define NR_RECVBUFF (16) ++#elif defined(PLATFORM_OS_CE) ++ #define NR_RECVBUFF (4) ++#else ++ ++ #if defined(CONFIG_GSPI_HCI) ++ #define NR_RECVBUFF (32) ++ #elif defined(CONFIG_SDIO_HCI) ++ #define NR_RECVBUFF (8) ++ #else ++ #ifdef CONFIG_SINGLE_RECV_BUF ++ #define NR_RECVBUFF (1) ++ #else ++ #define NR_RECVBUFF (4) ++ #endif //CONFIG_SINGLE_RECV_BUF ++ #endif ++ ++ #define NR_PREALLOC_RECV_SKB (8) ++#endif ++ ++ ++#define RECV_BLK_SZ 512 ++#define RECV_BLK_CNT 16 ++#define RECV_BLK_TH RECV_BLK_CNT ++ ++#if defined(CONFIG_USB_HCI) ++ ++#ifdef PLATFORM_OS_CE ++#define MAX_RECVBUF_SZ (8192+1024) // 8K+1k ++#else ++ #ifndef CONFIG_MINIMAL_MEMORY_USAGE ++ //#define MAX_RECVBUF_SZ (32768) // 32k ++ //#define MAX_RECVBUF_SZ (16384) //16K ++ //#define MAX_RECVBUF_SZ (10240) //10K ++ #ifdef CONFIG_PLATFORM_MSTAR ++ #define MAX_RECVBUF_SZ (8192) // 8K ++ #else ++ #define MAX_RECVBUF_SZ (15360) // 15k < 16k ++ #endif ++ //#define MAX_RECVBUF_SZ (8192+1024) // 8K+1k ++ #else ++ #define MAX_RECVBUF_SZ (4000) // about 4K ++ #endif ++#endif ++ ++#elif defined(CONFIG_PCI_HCI) ++//#ifndef CONFIG_MINIMAL_MEMORY_USAGE ++// #define MAX_RECVBUF_SZ (9100) ++//#else ++ #define MAX_RECVBUF_SZ (4000) // about 4K ++//#endif ++ ++#define RX_MPDU_QUEUE 0 ++#define RX_CMD_QUEUE 1 ++#define RX_MAX_QUEUE 2 ++ ++#elif defined(CONFIG_SDIO_HCI) ++ ++#define MAX_RECVBUF_SZ (10240) ++ ++#endif ++ ++ ++#define RECV_BULK_IN_ADDR 0x80 ++#define RECV_INT_IN_ADDR 0x81 ++ ++#define PHY_RSSI_SLID_WIN_MAX 100 ++#define PHY_LINKQUALITY_SLID_WIN_MAX 20 ++ ++ ++struct phy_stat ++{ ++ unsigned int phydw0; ++ ++ unsigned int phydw1; ++ ++ unsigned int phydw2; ++ ++ unsigned int phydw3; ++ ++ unsigned int phydw4; ++ ++ unsigned int phydw5; ++ ++ unsigned int phydw6; ++ ++ unsigned int phydw7; ++}; ++ ++// Rx smooth factor ++#define Rx_Smooth_Factor (20) ++ ++ ++#ifdef CONFIG_USB_HCI ++typedef struct _INTERRUPT_MSG_FORMAT_EX{ ++ unsigned int C2H_MSG0; ++ unsigned int C2H_MSG1; ++ unsigned int C2H_MSG2; ++ unsigned int C2H_MSG3; ++ unsigned int HISR; // from HISR Reg0x124, read to clear ++ unsigned int HISRE;// from HISRE Reg0x12c, read to clear ++ unsigned int MSG_EX; ++}INTERRUPT_MSG_FORMAT_EX,*PINTERRUPT_MSG_FORMAT_EX; ++ ++void rtl8192cu_init_recvbuf(_adapter *padapter, struct recv_buf *precvbuf); ++int rtl8192cu_init_recv_priv(_adapter * padapter); ++void rtl8192cu_free_recv_priv(_adapter * padapter); ++#endif ++ ++#ifdef CONFIG_PCI_HCI ++int rtl8192ce_init_recv_priv(_adapter * padapter); ++void rtl8192ce_free_recv_priv(_adapter * padapter); ++#endif ++ ++void rtl8192c_translate_rx_signal_stuff(union recv_frame *precvframe, struct phy_stat *pphy_status); ++void rtl8192c_query_rx_desc_status(union recv_frame *precvframe, struct recv_stat *pdesc); ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_rf.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_rf.h +new file mode 100644 +index 00000000..2d6bd8cf +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_rf.h +@@ -0,0 +1,92 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++/****************************************************************************** ++ * ++ * ++ * Module: rtl8192c_rf.h ( Header File) ++ * ++ * Note: Collect every HAL RF type exter API or constant. ++ * ++ * Function: ++ * ++ * Export: ++ * ++ * Abbrev: ++ * ++ * History: ++ * Data Who Remark ++ * ++ * 09/25/2008 MHC Create initial version. ++ * ++ * ++******************************************************************************/ ++#ifndef _RTL8192C_RF_H_ ++#define _RTL8192C_RF_H_ ++/* Check to see if the file has been included already. */ ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++// ++// For RF 6052 Series ++// ++#define RF6052_MAX_TX_PWR 0x3F ++#define RF6052_MAX_REG 0x3F ++#define RF6052_MAX_PATH 2 ++/*--------------------------Define Parameters-------------------------------*/ ++ ++ ++/*------------------------------Define structure----------------------------*/ ++ ++/*------------------------------Define structure----------------------------*/ ++ ++ ++/*------------------------Export global variable----------------------------*/ ++/*------------------------Export global variable----------------------------*/ ++ ++/*------------------------Export Marco Definition---------------------------*/ ++ ++/*------------------------Export Marco Definition---------------------------*/ ++ ++ ++/*--------------------------Exported Function prototype---------------------*/ ++ ++// ++// RF RL6052 Series API ++// ++void rtl8192c_RF_ChangeTxPath( IN PADAPTER Adapter, ++ IN u16 DataRate); ++void rtl8192c_PHY_RF6052SetBandwidth( ++ IN PADAPTER Adapter, ++ IN HT_CHANNEL_WIDTH Bandwidth); ++VOID rtl8192c_PHY_RF6052SetCckTxPower( ++ IN PADAPTER Adapter, ++ IN u8* pPowerlevel); ++VOID rtl8192c_PHY_RF6052SetOFDMTxPower( ++ IN PADAPTER Adapter, ++ IN u8* pPowerLevel, ++ IN u8 Channel); ++int PHY_RF6052_Config8192C( IN PADAPTER Adapter ); ++ ++/*--------------------------Exported Function prototype---------------------*/ ++ ++ ++#endif/* End of HalRf.h */ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_spec.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_spec.h +new file mode 100644 +index 00000000..ce88b022 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_spec.h +@@ -0,0 +1,1790 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8192C_SPEC_H__ ++#define __RTL8192C_SPEC_H__ ++ ++#include ++ ++//============================================================ ++// 8192C Regsiter offset definition ++//============================================================ ++ ++ ++//============================================================ ++// ++//============================================================ ++ ++//----------------------------------------------------- ++// ++// 0x0000h ~ 0x00FFh System Configuration ++// ++//----------------------------------------------------- ++#define REG_SYS_ISO_CTRL 0x0000 ++#define REG_SYS_FUNC_EN 0x0002 ++#define REG_APS_FSMCO 0x0004 ++#define REG_SYS_CLKR 0x0008 ++#define REG_9346CR 0x000A ++#define REG_EE_VPD 0x000C ++#define REG_AFE_MISC 0x0010 ++#define REG_SPS0_CTRL 0x0011 ++#define REG_SPS_OCP_CFG 0x0018 ++#define REG_RSV_CTRL 0x001C ++#define REG_RF_CTRL 0x001F ++#define REG_LDOA15_CTRL 0x0020 ++#define REG_LDOV12D_CTRL 0x0021 ++#define REG_LDOHCI12_CTRL 0x0022 ++#define REG_LPLDO_CTRL 0x0023 ++#define REG_AFE_XTAL_CTRL 0x0024 ++#define REG_AFE_PLL_CTRL 0x0028 ++#define REG_MAC_PHY_CTRL 0x002c ++#define REG_EFUSE_CTRL 0x0030 ++#define REG_EFUSE_TEST 0x0034 ++#define REG_PWR_DATA 0x0038 ++#define REG_CAL_TIMER 0x003C ++#define REG_ACLK_MON 0x003E ++#define REG_GPIO_MUXCFG 0x0040 ++#define REG_GPIO_IO_SEL 0x0042 ++#define REG_MAC_PINMUX_CFG 0x0043 ++#define REG_GPIO_PIN_CTRL 0x0044 ++#define REG_GPIO_INTM 0x0048 ++#define REG_LEDCFG0 0x004C ++#define REG_LEDCFG1 0x004D ++#define REG_LEDCFG2 0x004E ++#define REG_LEDCFG3 0x004F ++#define REG_LEDCFG REG_LEDCFG2 ++#define REG_FSIMR 0x0050 ++#define REG_FSISR 0x0054 ++#define REG_HSIMR 0x0058 ++#define REG_HSISR 0x005c ++#define REG_GPIO_PIN_CTRL_2 0x0060 // RTL8723 WIFI/BT/GPS Multi-Function GPIO Pin Control. ++#define REG_GPIO_IO_SEL_2 0x0062 // RTL8723 WIFI/BT/GPS Multi-Function GPIO Select. ++#define REG_MULTI_FUNC_CTRL 0x0068 // RTL8723 WIFI/BT/GPS Multi-Function control source. ++#define REG_MCUFWDL 0x0080 ++#define REG_HMEBOX_EXT_0 0x0088 ++#define REG_HMEBOX_EXT_1 0x008A ++#define REG_HMEBOX_EXT_2 0x008C ++#define REG_HMEBOX_EXT_3 0x008E ++#define REG_HOST_SUSP_CNT 0x00BC // Host suspend counter on FPGA platform ++#define REG_EFUSE_ACCESS 0x00CF // Efuse access protection for RTL8723 ++#define REG_BIST_SCAN 0x00D0 ++#define REG_BIST_RPT 0x00D4 ++#define REG_BIST_ROM_RPT 0x00D8 ++#define REG_USB_SIE_INTF 0x00E0 ++#define REG_PCIE_MIO_INTF 0x00E4 ++#define REG_PCIE_MIO_INTD 0x00E8 ++#define REG_HPON_FSM 0x00EC ++#define REG_SYS_CFG 0x00F0 ++#define REG_GPIO_OUTSTS 0x00F4 // For RTL8723 only. ++ ++//----------------------------------------------------- ++// ++// 0x0100h ~ 0x01FFh MACTOP General Configuration ++// ++//----------------------------------------------------- ++#define REG_CR 0x0100 ++#define REG_PBP 0x0104 ++#define REG_TRXDMA_CTRL 0x010C ++#define REG_TRXFF_BNDY 0x0114 ++#define REG_TRXFF_STATUS 0x0118 ++#define REG_RXFF_PTR 0x011C ++#define REG_HIMR 0x0120 ++#define REG_HISR 0x0124 ++#define REG_HIMRE 0x0128 ++#define REG_HISRE 0x012C ++#define REG_CPWM 0x012F ++#define REG_FWIMR 0x0130 ++#define REG_FWISR 0x0134 ++#define REG_PKTBUF_DBG_CTRL 0x0140 ++#define REG_PKTBUF_DBG_DATA_L 0x0144 ++#define REG_PKTBUF_DBG_DATA_H 0x0148 ++ ++#define REG_TC0_CTRL 0x0150 ++#define REG_TC1_CTRL 0x0154 ++#define REG_TC2_CTRL 0x0158 ++#define REG_TC3_CTRL 0x015C ++#define REG_TC4_CTRL 0x0160 ++#define REG_TCUNIT_BASE 0x0164 ++#define REG_MBIST_START 0x0174 ++#define REG_MBIST_DONE 0x0178 ++#define REG_MBIST_FAIL 0x017C ++#define REG_C2HEVT_MSG_NORMAL 0x01A0 ++#define REG_C2HEVT_CLEAR 0x01AF ++#define REG_C2HEVT_MSG_TEST 0x01B8 ++#define REG_MCUTST_1 0x01c0 ++#define REG_FMETHR 0x01C8 ++#define REG_HMETFR 0x01CC ++#define REG_HMEBOX_0 0x01D0 ++#define REG_HMEBOX_1 0x01D4 ++#define REG_HMEBOX_2 0x01D8 ++#define REG_HMEBOX_3 0x01DC ++ ++#define REG_LLT_INIT 0x01E0 ++#define REG_BB_ACCEESS_CTRL 0x01E8 ++#define REG_BB_ACCESS_DATA 0x01EC ++ ++ ++//----------------------------------------------------- ++// ++// 0x0200h ~ 0x027Fh TXDMA Configuration ++// ++//----------------------------------------------------- ++#define REG_RQPN 0x0200 ++#define REG_FIFOPAGE 0x0204 ++#define REG_TDECTRL 0x0208 ++#define REG_TXDMA_OFFSET_CHK 0x020C ++#define REG_TXDMA_STATUS 0x0210 ++#define REG_RQPN_NPQ 0x0214 ++ ++//----------------------------------------------------- ++// ++// 0x0280h ~ 0x02FFh RXDMA Configuration ++// ++//----------------------------------------------------- ++#define REG_RXDMA_AGG_PG_TH 0x0280 ++#define REG_RXPKT_NUM 0x0284 ++#define REG_RXDMA_STATUS 0x0288 ++ ++ ++//----------------------------------------------------- ++// ++// 0x0300h ~ 0x03FFh PCIe ++// ++//----------------------------------------------------- ++#define REG_PCIE_CTRL_REG 0x0300 ++#define REG_INT_MIG 0x0304 // Interrupt Migration ++#define REG_BCNQ_DESA 0x0308 // TX Beacon Descriptor Address ++#define REG_HQ_DESA 0x0310 // TX High Queue Descriptor Address ++#define REG_MGQ_DESA 0x0318 // TX Manage Queue Descriptor Address ++#define REG_VOQ_DESA 0x0320 // TX VO Queue Descriptor Address ++#define REG_VIQ_DESA 0x0328 // TX VI Queue Descriptor Address ++#define REG_BEQ_DESA 0x0330 // TX BE Queue Descriptor Address ++#define REG_BKQ_DESA 0x0338 // TX BK Queue Descriptor Address ++#define REG_RX_DESA 0x0340 // RX Queue Descriptor Address ++#define REG_DBI 0x0348 // Backdoor REG for Access Configuration ++#define REG_MDIO 0x0354 // MDIO for Access PCIE PHY ++#define REG_DBG_SEL 0x0360 // Debug Selection Register ++#define REG_PCIE_HRPWM 0x0361 //PCIe RPWM ++#define REG_PCIE_HCPWM 0x0363 //PCIe CPWM ++#define REG_UART_CTRL 0x0364 // UART Control ++#define REG_UART_TX_DESA 0x0370 // UART TX Descriptor Address ++#define REG_UART_RX_DESA 0x0378 // UART Rx Descriptor Address ++ ++ ++// spec version 11 ++//----------------------------------------------------- ++// ++// 0x0400h ~ 0x047Fh Protocol Configuration ++// ++//----------------------------------------------------- ++#define REG_VOQ_INFORMATION 0x0400 ++#define REG_VIQ_INFORMATION 0x0404 ++#define REG_BEQ_INFORMATION 0x0408 ++#define REG_BKQ_INFORMATION 0x040C ++#define REG_MGQ_INFORMATION 0x0410 ++#define REG_HGQ_INFORMATION 0x0414 ++#define REG_BCNQ_INFORMATION 0x0418 ++ ++ ++#define REG_CPU_MGQ_INFORMATION 0x041C ++#define REG_FWHW_TXQ_CTRL 0x0420 ++#define REG_HWSEQ_CTRL 0x0423 ++#define REG_TXPKTBUF_BCNQ_BDNY 0x0424 ++#define REG_TXPKTBUF_MGQ_BDNY 0x0425 ++#define REG_LIFETIME_EN 0x0426 ++#define REG_MULTI_BCNQ_OFFSET 0x0427 ++#define REG_SPEC_SIFS 0x0428 ++#define REG_RL 0x042A ++#define REG_DARFRC 0x0430 ++#define REG_RARFRC 0x0438 ++#define REG_RRSR 0x0440 ++#define REG_ARFR0 0x0444 ++#define REG_ARFR1 0x0448 ++#define REG_ARFR2 0x044C ++#define REG_ARFR3 0x0450 ++#define REG_AGGLEN_LMT 0x0458 ++#define REG_AMPDU_MIN_SPACE 0x045C ++#define REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045D ++#define REG_FAST_EDCA_CTRL 0x0460 ++#define REG_RD_RESP_PKT_TH 0x0463 ++#define REG_INIRTS_RATE_SEL 0x0480 ++#define REG_INIDATA_RATE_SEL 0x0484 ++ ++ ++#define REG_POWER_STATUS 0x04A4 ++#define REG_POWER_STAGE1 0x04B4 ++#define REG_POWER_STAGE2 0x04B8 ++#define REG_PKT_VO_VI_LIFE_TIME 0x04C0 ++#define REG_PKT_BE_BK_LIFE_TIME 0x04C2 ++#define REG_STBC_SETTING 0x04C4 ++#define REG_PROT_MODE_CTRL 0x04C8 ++#define REG_MAX_AGGR_NUM 0x04CA ++#define REG_RTS_MAX_AGGR_NUM 0x04CB ++#define REG_BAR_MODE_CTRL 0x04CC ++#define REG_RA_TRY_RATE_AGG_LMT 0x04CF ++#define REG_NQOS_SEQ 0x04DC ++#define REG_QOS_SEQ 0x04DE ++#define REG_NEED_CPU_HANDLE 0x04E0 ++#define REG_PKT_LOSE_RPT 0x04E1 ++#define REG_PTCL_ERR_STATUS 0x04E2 ++#define REG_DUMMY 0x04FC ++ ++ ++ ++//----------------------------------------------------- ++// ++// 0x0500h ~ 0x05FFh EDCA Configuration ++// ++//----------------------------------------------------- ++#define REG_EDCA_VO_PARAM 0x0500 ++#define REG_EDCA_VI_PARAM 0x0504 ++#define REG_EDCA_BE_PARAM 0x0508 ++#define REG_EDCA_BK_PARAM 0x050C ++#define REG_BCNTCFG 0x0510 ++#define REG_PIFS 0x0512 ++#define REG_RDG_PIFS 0x0513 ++#define REG_SIFS_CCK 0x0514 ++#define REG_SIFS_OFDM 0x0516 ++#define REG_SIFS_CTX 0x0514 ++#define REG_SIFS_TRX 0x0516 ++#define REG_TSFTR_SYN_OFFSET 0x0518 ++#define REG_AGGR_BREAK_TIME 0x051A ++#define REG_SLOT 0x051B ++#define REG_TX_PTCL_CTRL 0x0520 ++#define REG_TXPAUSE 0x0522 ++#define REG_DIS_TXREQ_CLR 0x0523 ++#define REG_RD_CTRL 0x0524 ++#define REG_TBTT_PROHIBIT 0x0540 ++#define REG_RD_NAV_NXT 0x0544 ++#define REG_NAV_PROT_LEN 0x0546 ++#define REG_BCN_CTRL 0x0550 ++#define REG_BCN_CTRL_1 0x0551 ++#define REG_MBID_NUM 0x0552 ++#define REG_DUAL_TSF_RST 0x0553 ++#define REG_BCN_INTERVAL 0x0554 // The same as REG_MBSSID_BCN_SPACE ++#define REG_MBSSID_BCN_SPACE 0x0554 ++#define REG_DRVERLYINT 0x0558 ++#define REG_BCNDMATIM 0x0559 ++#define REG_ATIMWND 0x055A ++#define REG_BCN_MAX_ERR 0x055D ++#define REG_RXTSF_OFFSET_CCK 0x055E ++#define REG_RXTSF_OFFSET_OFDM 0x055F ++#define REG_TSFTR 0x0560 ++#define REG_TSFTR1 0x0568 ++#define REG_INIT_TSFTR 0x0564 ++#define REG_ATIMWND_1 0x0570 ++#define REG_PSTIMER 0x0580 ++#define REG_TIMER0 0x0584 ++#define REG_TIMER1 0x0588 ++#define REG_ACMHWCTRL 0x05C0 ++#define REG_ACMRSTCTRL 0x05C1 ++#define REG_ACMAVG 0x05C2 ++#define REG_VO_ADMTIME 0x05C4 ++#define REG_VI_ADMTIME 0x05C6 ++#define REG_BE_ADMTIME 0x05C8 ++#define REG_EDCA_RANDOM_GEN 0x05CC ++#define REG_SCH_TXCMD 0x05D0 ++ ++//#define REG_FW_TSF_SYNC_CNT 0x04A0 ++#define REG_FW_RESET_TSF_CNT_1 0x05FC ++#define REG_FW_RESET_TSF_CNT_0 0x05FD ++#define REG_FW_BCN_DIS_CNT 0x05FE ++ ++//----------------------------------------------------- ++// ++// 0x0600h ~ 0x07FFh WMAC Configuration ++// ++//----------------------------------------------------- ++#define REG_APSD_CTRL 0x0600 ++#define REG_BWOPMODE 0x0603 ++#define REG_TCR 0x0604 ++#define REG_RCR 0x0608 ++#define REG_RX_PKT_LIMIT 0x060C ++#define REG_RX_DLK_TIME 0x060D ++#define REG_RX_DRVINFO_SZ 0x060F ++ ++#define REG_MACID 0x0610 ++#define REG_BSSID 0x0618 ++#define REG_MAR 0x0620 ++#define REG_MBIDCAMCFG 0x0628 ++ ++#define REG_USTIME_EDCA 0x0638 ++#define REG_MAC_SPEC_SIFS 0x063A ++ ++// 20100719 Joseph: Hardware register definition change. (HW datasheet v54) ++#define REG_R2T_SIFS 0x063C // [15:8]SIFS_R2T_OFDM, [7:0]SIFS_R2T_CCK ++#define REG_T2T_SIFS 0x063E // [15:8]SIFS_T2T_OFDM, [7:0]SIFS_T2T_CCK ++#define REG_ACKTO 0x0640 ++#define REG_CTS2TO 0x0641 ++#define REG_EIFS 0x0642 ++ ++//WMA, BA, CCX ++#define REG_NAV_CTRL 0x0650 ++#define REG_BACAMCMD 0x0654 ++#define REG_BACAMCONTENT 0x0658 ++#define REG_LBDLY 0x0660 ++#define REG_FWDLY 0x0661 ++#define REG_RXERR_RPT 0x0664 ++#define REG_WMAC_TRXPTCL_CTL 0x0668 ++ ++ ++// Security ++#define REG_CAMCMD 0x0670 ++#define REG_CAMWRITE 0x0674 ++#define REG_CAMREAD 0x0678 ++#define REG_CAMDBG 0x067C ++#define REG_SECCFG 0x0680 ++ ++// Power ++#define REG_WOW_CTRL 0x0690 ++#define REG_PSSTATUS 0x0691 ++#define REG_PS_RX_INFO 0x0692 ++#define REG_LPNAV_CTRL 0x0694 ++#define REG_WKFMCAM_CMD 0x0698 ++#define REG_WKFMCAM_RWD 0x069C ++#define REG_RXFLTMAP0 0x06A0 ++#define REG_RXFLTMAP1 0x06A2 ++#define REG_RXFLTMAP2 0x06A4 ++#define REG_BCN_PSR_RPT 0x06A8 ++#define REG_CALB32K_CTRL 0x06AC ++#define REG_PKT_MON_CTRL 0x06B4 ++#define REG_BT_COEX_TABLE 0x06C0 ++#define REG_WMAC_RESP_TXINFO 0x06D8 ++ ++#define REG_MACID1 0x0700 ++#define REG_BSSID1 0x0708 ++ ++ ++//----------------------------------------------------- ++// ++// 0xFE00h ~ 0xFE55h USB Configuration ++// ++//----------------------------------------------------- ++#define REG_USB_INFO 0xFE17 ++#define REG_USB_SPECIAL_OPTION 0xFE55 ++#define REG_USB_DMA_AGG_TO 0xFE5B ++#define REG_USB_AGG_TO 0xFE5C ++#define REG_USB_AGG_TH 0xFE5D ++ ++// For test chip ++#define REG_TEST_USB_TXQS 0xFE48 ++#define REG_TEST_SIE_VID 0xFE60 // 0xFE60~0xFE61 ++#define REG_TEST_SIE_PID 0xFE62 // 0xFE62~0xFE63 ++#define REG_TEST_SIE_OPTIONAL 0xFE64 ++#define REG_TEST_SIE_CHIRP_K 0xFE65 ++#define REG_TEST_SIE_PHY 0xFE66 // 0xFE66~0xFE6B ++#define REG_TEST_SIE_MAC_ADDR 0xFE70 // 0xFE70~0xFE75 ++#define REG_TEST_SIE_STRING 0xFE80 // 0xFE80~0xFEB9 ++ ++ ++// For normal chip ++#define REG_NORMAL_SIE_VID 0xFE60 // 0xFE60~0xFE61 ++#define REG_NORMAL_SIE_PID 0xFE62 // 0xFE62~0xFE63 ++#define REG_NORMAL_SIE_OPTIONAL 0xFE64 ++#define REG_NORMAL_SIE_EP 0xFE65 // 0xFE65~0xFE67 ++#define REG_NORMAL_SIE_PHY 0xFE68 // 0xFE68~0xFE6B ++#define REG_NORMAL_SIE_OPTIONAL2 0xFE6C ++#define REG_NORMAL_SIE_GPS_EP 0xFE6D // 0xFE6D, for RTL8723 only. ++#define REG_NORMAL_SIE_MAC_ADDR 0xFE70 // 0xFE70~0xFE75 ++#define REG_NORMAL_SIE_STRING 0xFE80 // 0xFE80~0xFEDF ++ ++ ++//----------------------------------------------------- ++// ++// Redifine 8192C register definition for compatibility ++// ++//----------------------------------------------------- ++ ++// TODO: use these definition when using REG_xxx naming rule. ++// NOTE: DO NOT Remove these definition. Use later. ++ ++#define SYS_ISO_CTRL REG_SYS_ISO_CTRL // System Isolation Interface Control. ++#define SYS_FUNC_EN REG_SYS_FUNC_EN // System Function Enable. ++#define SYS_CLK REG_SYS_CLKR ++#define CR9346 REG_9346CR // 93C46/93C56 Command Register. ++#define EFUSE_CTRL REG_EFUSE_CTRL // E-Fuse Control. ++#define EFUSE_TEST REG_EFUSE_TEST // E-Fuse Test. ++#define MSR (REG_CR + 2) // Media Status register ++#define ISR REG_HISR ++#define TSFR REG_TSFTR // Timing Sync Function Timer Register. ++ ++#define MACIDR0 REG_MACID // MAC ID Register, Offset 0x0050-0x0053 ++#define MACIDR4 (REG_MACID + 4) // MAC ID Register, Offset 0x0054-0x0055 ++ ++#define PBP REG_PBP ++ ++// Redifine MACID register, to compatible prior ICs. ++#define IDR0 MACIDR0 ++#define IDR4 MACIDR4 ++ ++ ++// ++// 9. Security Control Registers (Offset: ) ++// ++#define RWCAM REG_CAMCMD //IN 8190 Data Sheet is called CAMcmd ++#define WCAMI REG_CAMWRITE // Software write CAM input content ++#define RCAMO REG_CAMREAD // Software read/write CAM config ++#define CAMDBG REG_CAMDBG ++#define SECR REG_SECCFG //Security Configuration Register ++ ++// Unused register ++#define UnusedRegister 0x1BF ++#define DCAM UnusedRegister ++#define PSR UnusedRegister ++#define BBAddr UnusedRegister ++#define PhyDataR UnusedRegister ++ ++#define InvalidBBRFValue 0x12345678 ++ ++// Min Spacing related settings. ++#define MAX_MSS_DENSITY_2T 0x13 ++#define MAX_MSS_DENSITY_1T 0x0A ++ ++//---------------------------------------------------------------------------- ++// 8192C Cmd9346CR bits (Offset 0xA, 16bit) ++//---------------------------------------------------------------------------- ++#define CmdEEPROM_En BIT5 // EEPROM enable when set 1 ++#define CmdEERPOMSEL BIT4 // System EEPROM select, 0: boot from E-FUSE, 1: The EEPROM used is 9346 ++#define Cmd9346CR_9356SEL BIT4 ++#define AutoLoadEEPROM (CmdEEPROM_En|CmdEERPOMSEL) ++#define AutoLoadEFUSE CmdEEPROM_En ++ ++//---------------------------------------------------------------------------- ++// 8192C GPIO MUX Configuration Register (offset 0x40, 4 byte) ++//---------------------------------------------------------------------------- ++#define GPIOSEL_GPIO 0 ++#define GPIOSEL_ENBT BIT5 ++ ++//---------------------------------------------------------------------------- ++// 8192C GPIO PIN Control Register (offset 0x44, 4 byte) ++//---------------------------------------------------------------------------- ++#define GPIO_IN REG_GPIO_PIN_CTRL // GPIO pins input value ++#define GPIO_OUT (REG_GPIO_PIN_CTRL+1) // GPIO pins output value ++#define GPIO_IO_SEL (REG_GPIO_PIN_CTRL+2) // GPIO pins output enable when a bit is set to "1"; otherwise, input is configured. ++#define GPIO_MOD (REG_GPIO_PIN_CTRL+3) ++ ++//---------------------------------------------------------------------------- ++// 8192C (MSR) Media Status Register (Offset 0x4C, 8 bits) ++//---------------------------------------------------------------------------- ++/* ++Network Type ++00: No link ++01: Link in ad hoc network ++10: Link in infrastructure network ++11: AP mode ++Default: 00b. ++*/ ++#define MSR_NOLINK 0x00 ++#define MSR_ADHOC 0x01 ++#define MSR_INFRA 0x02 ++#define MSR_AP 0x03 ++ ++// ++// 6. Adaptive Control Registers (Offset: 0x0160 - 0x01CF) ++// ++//---------------------------------------------------------------------------- ++// 8192C Response Rate Set Register (offset 0x181, 24bits) ++//---------------------------------------------------------------------------- ++#define RRSR_RSC_OFFSET 21 ++#define RRSR_SHORT_OFFSET 23 ++#define RRSR_RSC_BW_40M 0x600000 ++#define RRSR_RSC_UPSUBCHNL 0x400000 ++#define RRSR_RSC_LOWSUBCHNL 0x200000 ++#define RRSR_SHORT 0x800000 ++#define RRSR_1M BIT0 ++#define RRSR_2M BIT1 ++#define RRSR_5_5M BIT2 ++#define RRSR_11M BIT3 ++#define RRSR_6M BIT4 ++#define RRSR_9M BIT5 ++#define RRSR_12M BIT6 ++#define RRSR_18M BIT7 ++#define RRSR_24M BIT8 ++#define RRSR_36M BIT9 ++#define RRSR_48M BIT10 ++#define RRSR_54M BIT11 ++#define RRSR_MCS0 BIT12 ++#define RRSR_MCS1 BIT13 ++#define RRSR_MCS2 BIT14 ++#define RRSR_MCS3 BIT15 ++#define RRSR_MCS4 BIT16 ++#define RRSR_MCS5 BIT17 ++#define RRSR_MCS6 BIT18 ++#define RRSR_MCS7 BIT19 ++#define BRSR_AckShortPmb BIT23 ++// CCK ACK: use Short Preamble or not ++ ++//---------------------------------------------------------------------------- ++// 8192C BW_OPMODE bits (Offset 0x203, 8bit) ++//---------------------------------------------------------------------------- ++#define BW_OPMODE_20MHZ BIT2 ++#define BW_OPMODE_5G BIT1 ++#define BW_OPMODE_11J BIT0 ++ ++ ++//---------------------------------------------------------------------------- ++// 8192C CAM Config Setting (offset 0x250, 1 byte) ++//---------------------------------------------------------------------------- ++#define CAM_VALID BIT15 ++#define CAM_NOTVALID 0x0000 ++#define CAM_USEDK BIT5 ++ ++#define CAM_CONTENT_COUNT 8 ++ ++#define CAM_NONE 0x0 ++#define CAM_WEP40 0x01 ++#define CAM_TKIP 0x02 ++#define CAM_AES 0x04 ++#define CAM_WEP104 0x05 ++ ++#define TOTAL_CAM_ENTRY 32 ++#define HALF_CAM_ENTRY 16 ++ ++#define CAM_CONFIG_USEDK _TRUE ++#define CAM_CONFIG_NO_USEDK _FALSE ++ ++#define CAM_WRITE BIT16 ++#define CAM_READ 0x00000000 ++#define CAM_POLLINIG BIT31 ++ ++#define SCR_UseDK 0x01 ++#define SCR_TxSecEnable 0x02 ++#define SCR_RxSecEnable 0x04 ++ ++ ++// ++// 12. Host Interrupt Status Registers (Offset: 0x0300 - 0x030F) ++// ++//---------------------------------------------------------------------------- ++// 8190 IMR/ISR bits (offset 0xfd, 8bits) ++//---------------------------------------------------------------------------- ++#define IMR8190_DISABLED 0x0 ++// IMR DW0 Bit 0-31 ++#define IMR_BCNDMAINT6 BIT31 // Beacon DMA Interrupt 6 ++#define IMR_BCNDMAINT5 BIT30 // Beacon DMA Interrupt 5 ++#define IMR_BCNDMAINT4 BIT29 // Beacon DMA Interrupt 4 ++#define IMR_BCNDMAINT3 BIT28 // Beacon DMA Interrupt 3 ++#define IMR_BCNDMAINT2 BIT27 // Beacon DMA Interrupt 2 ++#define IMR_BCNDMAINT1 BIT26 // Beacon DMA Interrupt 1 ++#define IMR_BCNDOK8 BIT25 // Beacon Queue DMA OK Interrup 8 ++#define IMR_BCNDOK7 BIT24 // Beacon Queue DMA OK Interrup 7 ++#define IMR_BCNDOK6 BIT23 // Beacon Queue DMA OK Interrup 6 ++#define IMR_BCNDOK5 BIT22 // Beacon Queue DMA OK Interrup 5 ++#define IMR_BCNDOK4 BIT21 // Beacon Queue DMA OK Interrup 4 ++#define IMR_BCNDOK3 BIT20 // Beacon Queue DMA OK Interrup 3 ++#define IMR_BCNDOK2 BIT19 // Beacon Queue DMA OK Interrup 2 ++#define IMR_BCNDOK1 BIT18 // Beacon Queue DMA OK Interrup 1 ++#define IMR_TIMEOUT2 BIT17 // Timeout interrupt 2 ++#define IMR_TIMEOUT1 BIT16 // Timeout interrupt 1 ++#define IMR_TXFOVW BIT15 // Transmit FIFO Overflow ++#define IMR_PSTIMEOUT BIT14 // Power save time out interrupt ++#define IMR_BcnInt BIT13 // Beacon DMA Interrupt 0 ++#define IMR_RXFOVW BIT12 // Receive FIFO Overflow ++#define IMR_RDU BIT11 // Receive Descriptor Unavailable ++#define IMR_ATIMEND BIT10 // For 92C,ATIM Window End Interrupt ++#define IMR_BDOK BIT9 // Beacon Queue DMA OK Interrup ++#define IMR_HIGHDOK BIT8 // High Queue DMA OK Interrupt ++#define IMR_TBDOK BIT7 // Transmit Beacon OK interrup ++#define IMR_MGNTDOK BIT6 // Management Queue DMA OK Interrupt ++#define IMR_TBDER BIT5 // For 92C,Transmit Beacon Error Interrupt ++#define IMR_BKDOK BIT4 // AC_BK DMA OK Interrupt ++#define IMR_BEDOK BIT3 // AC_BE DMA OK Interrupt ++#define IMR_VIDOK BIT2 // AC_VI DMA OK Interrupt ++#define IMR_VODOK BIT1 // AC_VO DMA Interrupt ++#define IMR_ROK BIT0 // Receive DMA OK Interrupt ++ ++#define IMR_RX_MASK (IMR_ROK|IMR_RDU|IMR_RXFOVW) ++#define IMR_TX_MASK (IMR_VODOK|IMR_VIDOK|IMR_BEDOK|IMR_BKDOK|IMR_MGNTDOK|IMR_HIGHDOK|IMR_BDOK) ++ ++// 13. Host Interrupt Status Extension Register (Offset: 0x012C-012Eh) ++#define IMR_BcnInt_E BIT12 ++#define IMR_TXERR BIT11 ++#define IMR_RXERR BIT10 ++#define IMR_C2HCMD BIT9 ++#define IMR_CPWM BIT8 ++//RSVD [2-7] ++#define IMR_OCPINT BIT1 ++#define IMR_WLANOFF BIT0 ++ ++ ++ ++//---------------------------------------------------------------------------- ++// 8192C EFUSE ++//---------------------------------------------------------------------------- ++#define HWSET_MAX_SIZE 128 ++ ++ ++//---------------------------------------------------------------------------- ++// 8192C EEPROM/EFUSE share register definition. ++//---------------------------------------------------------------------------- ++ ++// ++// Default Value for EEPROM or EFUSE!!! ++// ++#define EEPROM_Default_TSSI 0x0 ++#define EEPROM_Default_TxPowerDiff 0x0 ++#define EEPROM_Default_CrystalCap 0x5 ++#define EEPROM_Default_BoardType 0x02 // Default: 2X2, RTL8192CE(QFPN68) ++#define EEPROM_Default_TxPower 0x1010 ++#define EEPROM_Default_HT2T_TxPwr 0x10 ++ ++#define EEPROM_Default_LegacyHTTxPowerDiff 0x3 ++#define EEPROM_Default_ThermalMeter 0x12 ++ ++#define EEPROM_Default_AntTxPowerDiff 0x0 ++#define EEPROM_Default_TxPwDiff_CrystalCap 0x5 ++#define EEPROM_Default_TxPowerLevel 0x22 ++#define EEPROM_Default_HT40_2SDiff 0x0 ++#define EEPROM_Default_HT20_Diff 2 // HT20<->40 default Tx Power Index Difference ++#define EEPROM_Default_LegacyHTTxPowerDiff 0x3 ++#define EEPROM_Default_HT40_PwrMaxOffset 0 ++#define EEPROM_Default_HT20_PwrMaxOffset 0 ++ ++// For debug ++#define EEPROM_Default_PID 0x1234 ++#define EEPROM_Default_VID 0x5678 ++#define EEPROM_Default_CustomerID 0xAB ++#define EEPROM_Default_SubCustomerID 0xCD ++#define EEPROM_Default_Version 0 ++ ++#define EEPROM_CHANNEL_PLAN_FCC 0x0 ++#define EEPROM_CHANNEL_PLAN_IC 0x1 ++#define EEPROM_CHANNEL_PLAN_ETSI 0x2 ++#define EEPROM_CHANNEL_PLAN_SPAIN 0x3 ++#define EEPROM_CHANNEL_PLAN_FRANCE 0x4 ++#define EEPROM_CHANNEL_PLAN_MKK 0x5 ++#define EEPROM_CHANNEL_PLAN_MKK1 0x6 ++#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7 ++#define EEPROM_CHANNEL_PLAN_TELEC 0x8 ++#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9 ++#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA ++#define EEPROM_CHANNEL_PLAN_NCC 0xB ++#define EEPROM_USB_OPTIONAL1 0xE ++#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 ++ ++ ++#define EEPROM_CID_DEFAULT 0x0 ++#define EEPROM_CID_TOSHIBA 0x4 ++#define EEPROM_CID_CCX 0x10 // CCX test. By Bruce, 2009-02-25. ++#define EEPROM_CID_QMI 0x0D ++#define EEPROM_CID_WHQL 0xFE // added by chiyoko for dtm, 20090108 ++ ++ ++#define RTL_EEPROM_ID 0x8129 ++ ++ ++#ifdef CONFIG_PCI_HCI ++#define RT_IBSS_INT_MASKS (IMR_BcnInt | IMR_TBDOK | IMR_TBDER) ++#define RT_AC_INT_MASKS (IMR_VIDOK | IMR_VODOK | IMR_BEDOK|IMR_BKDOK) ++#define RT_BSS_INT_MASKS (RT_IBSS_INT_MASKS) ++ ++// ++// Interface type. ++// ++typedef enum _INTERFACE_SELECT_8192CPCIe{ ++ INTF_SEL0_SOLO_MINICARD = 0, // WiFi solo-mCard ++ INTF_SEL1_BT_COMBO_MINICARD = 1, // WiFi+BT combo-mCard ++ INTF_SEL2_PCIe = 2, // PCIe Card ++} INTERFACE_SELECT_8192CPCIe, *PINTERFACE_SELECT_8192CPCIe; ++ ++#define RTL8190_EEPROM_ID 0x8129 // 0-1 ++#define EEPROM_HPON 0x02 // LDO settings.2-5 ++#define EEPROM_CLK 0x06 // Clock settings.6-7 ++#define EEPROM_TESTR 0x08 // SE Test mode.8 ++ ++#define EEPROM_VID 0x0A // SE Vendor ID.A-B ++#define EEPROM_DID 0x0C // SE Device ID. C-D ++#define EEPROM_SVID 0x0E // SE Vendor ID.E-F ++#define EEPROM_SMID 0x10 // SE PCI Subsystem ID. 10-11 ++ ++#define EEPROM_MAC_ADDR 0x16 // SEMAC Address. 12-17 ++ ++//---------------------------------------------------------------- ++// Ziv - Let PCIe and USB use the same define. Modify address mapping later. ++#define EEPROM_CCK_TX_PWR_INX 0x5A ++#define EEPROM_HT40_1S_TX_PWR_INX 0x60 ++#define EEPROM_HT40_2S_TX_PWR_INX_DIFF 0x66 ++#define EEPROM_HT20_TX_PWR_INX_DIFF 0x69 ++#define EEPROM_OFDM_TX_PWR_INX_DIFF 0x6C ++#define EEPROM_HT40_MAX_PWR_OFFSET 0x6F ++#define EEPROM_HT20_MAX_PWR_OFFSET 0x72 ++ ++#define EEPROM_CHANNEL_PLAN 0x75 ++#define EEPROM_TSSI_A 0x76 ++#define EEPROM_TSSI_B 0x77 ++#define EEPROM_THERMAL_METER 0x78 ++#define EEPROM_RF_OPT1 0x79 ++#define EEPROM_RF_OPT2 0x7A ++#define EEPROM_RF_OPT3 0x7B ++#define EEPROM_RF_OPT4 0x7C ++#define EEPROM_VERSION 0x7E ++#define EEPROM_CUSTOMER_ID 0x7F ++ ++#define EEPROM_NORMAL_BoardType EEPROM_RF_OPT1 //[7:5] ++ ++#endif ++ ++#ifdef CONFIG_USB_HCI ++ ++//should be renamed and moved to another file ++typedef enum _BOARD_TYPE_8192CUSB{ ++ BOARD_USB_DONGLE = 0, // USB dongle ++ BOARD_USB_High_PA = 1, // USB dongle with high power PA ++ BOARD_MINICARD = 2, // Minicard ++ BOARD_USB_SOLO = 3, // USB solo-Slim module ++ BOARD_USB_COMBO = 4, // USB Combo-Slim module ++} BOARD_TYPE_8192CUSB, *PBOARD_TYPE_8192CUSB; ++ ++#define SUPPORT_HW_RADIO_DETECT(pHalData) (pHalData->BoardType == BOARD_MINICARD||\ ++ pHalData->BoardType == BOARD_USB_SOLO||\ ++ pHalData->BoardType == BOARD_USB_COMBO) ++ ++//--------------------------------------------------------------- ++// EEPROM address for Test chip ++//--------------------------------------------------------------- ++#define EEPROM_TEST_USB_OPT 0x0E ++#define EEPROM_TEST_CHIRP_K 0x0F ++#define EEPROM_TEST_EP_SETTING 0x0E ++#define EEPROM_TEST_USB_PHY 0x10 ++ ++ ++//--------------------------------------------------------------- ++// EEPROM address for Normal chip ++//--------------------------------------------------------------- ++#define EEPROM_NORMAL_USB_OPT 0x0E ++#define EEPROM_NORMAL_CHIRP_K 0x0E // Changed ++#define EEPROM_NORMAL_EP_SETTING 0x0F // Changed ++#define EEPROM_NORMAL_USB_PHY 0x12 // Changed ++ ++ ++// Test chip and normal chip common define ++//--------------------------------------------------------------- ++// EEPROM address for both ++//--------------------------------------------------------------- ++#define EEPROM_ID0 0x00 ++#define EEPROM_ID1 0x01 ++#define EEPROM_RTK_RSV1 0x02 ++#define EEPROM_RTK_RSV2 0x03 ++#define EEPROM_RTK_RSV3 0x04 ++#define EEPROM_RTK_RSV4 0x05 ++#define EEPROM_RTK_RSV5 0x06 ++#define EEPROM_DBG_SEL 0x07 ++#define EEPROM_RTK_RSV6 0x08 ++#define EEPROM_VID 0x0A ++#define EEPROM_PID 0x0C ++ ++#define EEPROM_MAC_ADDR 0x16 ++#define EEPROM_STRING 0x1C ++#define EEPROM_SUBCUSTOMER_ID 0x59 ++#define EEPROM_CCK_TX_PWR_INX 0x5A ++#define EEPROM_HT40_1S_TX_PWR_INX 0x60 ++#define EEPROM_HT40_2S_TX_PWR_INX_DIFF 0x66 ++#define EEPROM_HT20_TX_PWR_INX_DIFF 0x69 ++#define EEPROM_OFDM_TX_PWR_INX_DIFF 0x6C ++#define EEPROM_HT40_MAX_PWR_OFFSET 0x6F ++#define EEPROM_HT20_MAX_PWR_OFFSET 0x72 ++ ++#define EEPROM_CHANNEL_PLAN 0x75 ++#define EEPROM_TSSI_A 0x76 ++#define EEPROM_TSSI_B 0x77 ++#define EEPROM_THERMAL_METER 0x78 ++#define EEPROM_RF_OPT1 0x79 ++#define EEPROM_RF_OPT2 0x7A ++#define EEPROM_RF_OPT3 0x7B ++#define EEPROM_RF_OPT4 0x7C ++#define EEPROM_VERSION 0x7E ++#define EEPROM_CUSTOMER_ID 0x7F ++ ++#define EEPROM_BoardType 0x54 //0x0: RTL8188SU, 0x1: RTL8191SU, 0x2: RTL8192SU, 0x3: RTL8191GU ++#define EEPROM_TxPwIndex 0x5C //0x5C-0x76, Tx Power index. ++#define EEPROM_PwDiff 0x67 // Difference of gain index between legacy and high throughput OFDM. ++ ++#define EEPROM_TxPowerCCK 0x5A // CCK Tx Power ++ ++// 2009/02/09 Cosa Add for SD3 requirement ++#define EEPROM_TX_PWR_HT20_DIFF 0x6e// HT20 Tx Power Index Difference ++#define DEFAULT_HT20_TXPWR_DIFF 2 // HT20<->40 default Tx Power Index Difference ++#define EEPROM_TX_PWR_OFDM_DIFF 0x71// OFDM Tx Power Index Difference ++ ++#define EEPROM_TxPWRGroup 0x73// Power diff for channel group ++#define EEPROM_Regulatory 0x79// Check if power safety is need ++ ++#define EEPROM_BLUETOOTH_COEXIST 0x7E // 92cu, 0x7E[4] ++#define EEPROM_NORMAL_BoardType EEPROM_RF_OPT1 //[7:5] ++#define BOARD_TYPE_NORMAL_MASK 0xE0 ++#define BOARD_TYPE_TEST_MASK 0x0F ++#define EEPROM_EASY_REPLACEMENT 0x50//BIT0 1 for build-in module, 0 for external dongle ++//------------------------------------------------------------- ++// EEPROM content definitions ++//------------------------------------------------------------- ++#define OS_LINK_SPEED BIT(5) ++ ++#define BOARD_TYPE_MASK 0xF ++ ++#define BT_COEXISTENCE BIT(4) ++#define BT_CO_SHIFT 4 ++ ++#define EP_NUMBER_MASK 0x30 //bit 4:5 0Eh ++#define EP_NUMBER_SHIFT 4 ++ ++ ++#define USB_PHY_PARA_SIZE 5 ++ ++ ++//------------------------------------------------------------- ++// EEPROM default value definitions ++//------------------------------------------------------------- ++// Use 0xABCD instead of 0x8192 for debug ++#define EEPROM_DEF_ID_0 0xCD // Byte 0x00 ++#define EEPROM_DEF_ID_1 0xAB // Byte 0x01 ++ ++#define EEPROM_DEF_RTK_RSV_A3 0x74 // Byte 0x03 ++#define EEPROM_DEF_RTK_RSV_A4 0x6D // Byte 0x04 ++#define EEPROM_DEF_RTK_RSV_A8 0xFF // Byte 0x08 ++ ++#define EEPROM_DEF_VID_0 0x0A // Byte 0x0A ++#define EEPROM_DEF_VID_1 0x0B ++ ++#define EEPROM_DEF_PID_0 0x92 // Byte 0x0C ++#define EEPROM_DEF_PID_1 0x81 ++ ++ ++#define EEPROM_TEST_DEF_USB_OPT 0x80 // Byte 0x0E ++#define EEPROM_NORMAL_DEF_USB_OPT 0x00 // Byte 0x0E ++ ++#define EEPROM_DEF_CHIRPK 0x15 // Byte 0x0F ++ ++#define EEPROM_DEF_USB_PHY_0 0x85 // Byte 0x10 ++#define EEPROM_DEF_USB_PHY_1 0x62 // Byte 0x11 ++#define EEPROM_DEF_USB_PHY_2 0x9E // Byte 0x12 ++#define EEPROM_DEF_USB_PHY_3 0x06 // Byte 0x13 ++ ++#define EEPROM_DEF_TSSI_A 0x09 // Byte 0x78 ++#define EEPROM_DEF_TSSI_B 0x09 // Byte 0x79 ++ ++ ++#define EEPROM_DEF_THERMAL_METER 0x12 // Byte 0x7A ++ ++#define RF_OPTION1 0x79// Check if power safety spec is need ++#define RF_OPTION2 0x7A ++#define RF_OPTION3 0x7B ++#define RF_OPTION4 0x7C ++ ++ ++#define EEPROM_USB_SN BIT(0) ++#define EEPROM_USB_REMOTE_WAKEUP BIT(1) ++#define EEPROM_USB_DEVICE_PWR BIT(2) ++#define EEPROM_EP_NUMBER (BIT(3)|BIT(4)) ++ ++#if 0 ++#define EEPROM_CHANNEL_PLAN_FCC 0x0 ++#define EEPROM_CHANNEL_PLAN_IC 0x1 ++#define EEPROM_CHANNEL_PLAN_ETSI 0x2 ++#define EEPROM_CHANNEL_PLAN_SPAIN 0x3 ++#define EEPROM_CHANNEL_PLAN_FRANCE 0x4 ++#define EEPROM_CHANNEL_PLAN_MKK 0x5 ++#define EEPROM_CHANNEL_PLAN_MKK1 0x6 ++#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7 ++#define EEPROM_CHANNEL_PLAN_TELEC 0x8 ++#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9 ++#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA ++#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 ++ ++#define EEPROM_CID_DEFAULT 0x0 ++ ++#define EEPROM_CID_WHQL 0xFE // added by chiyoko for dtm, 20090108 ++ ++ ++#define EEPROM_CID_CCX 0x10 // CCX test. By Bruce, 2009-02-25. ++#endif ++ ++#endif ++ ++ ++/*=================================================================== ++===================================================================== ++Here the register defines are for 92C. When the define is as same with 92C, ++we will use the 92C's define for the consistency ++So the following defines for 92C is not entire!!!!!! ++===================================================================== ++=====================================================================*/ ++/* ++Based on Datasheet V33---090401 ++Register Summary ++Current IOREG MAP ++0x0000h ~ 0x00FFh System Configuration (256 Bytes) ++0x0100h ~ 0x01FFh MACTOP General Configuration (256 Bytes) ++0x0200h ~ 0x027Fh TXDMA Configuration (128 Bytes) ++0x0280h ~ 0x02FFh RXDMA Configuration (128 Bytes) ++0x0300h ~ 0x03FFh PCIE EMAC Reserved Region (256 Bytes) ++0x0400h ~ 0x04FFh Protocol Configuration (256 Bytes) ++0x0500h ~ 0x05FFh EDCA Configuration (256 Bytes) ++0x0600h ~ 0x07FFh WMAC Configuration (512 Bytes) ++0x2000h ~ 0x3FFFh 8051 FW Download Region (8196 Bytes) ++*/ ++ ++//---------------------------------------------------------------------------- ++// 8192C (RCR) Receive Configuration Register (Offset 0x608, 32 bits) ++//---------------------------------------------------------------------------- ++#define RCR_APPFCS BIT31 //WMAC append FCS after pauload ++#define RCR_APP_MIC BIT30 // ++#define RCR_APP_PHYSTS BIT28// ++#define RCR_APP_ICV BIT29 // ++#define RCR_APP_PHYST_RXFF BIT28 // ++#define RCR_APP_BA_SSN BIT27 //Accept BA SSN ++#define RCR_ENMBID BIT24 //Enable Multiple BssId. ++#define RCR_LSIGEN BIT23 ++#define RCR_MFBEN BIT22 ++#define RCR_HTC_LOC_CTRL BIT14 //MFC<--HTC=1 MFC-->HTC=0 ++#define RCR_AMF BIT13 //Accept management type frame ++#define RCR_ACF BIT12 //Accept control type frame ++#define RCR_ADF BIT11 //Accept data type frame ++#define RCR_AICV BIT9 //Accept ICV error packet ++#define RCR_ACRC32 BIT8 //Accept CRC32 error packet ++#define RCR_CBSSID_BCN BIT7 //Accept BSSID match packet (Rx beacon, probe rsp) ++#define RCR_CBSSID_DATA BIT6 //Accept BSSID match packet (Data) ++#define RCR_CBSSID RCR_CBSSID_DATA //Accept BSSID match packet ++#define RCR_APWRMGT BIT5 //Accept power management packet ++#define RCR_ADD3 BIT4 //Accept address 3 match packet ++#define RCR_AB BIT3 //Accept broadcast packet ++#define RCR_AM BIT2 //Accept multicast packet ++#define RCR_APM BIT1 //Accept physical match packet ++#define RCR_AAP BIT0 //Accept all unicast packet ++#define RCR_MXDMA_OFFSET 8 ++#define RCR_FIFO_OFFSET 13 ++ ++ ++ ++//============================================================================ ++// 8192c USB specific Regsiter Offset and Content definition, ++// 2009.08.18, added by vivi. for merge 92c and 92C into one driver ++//============================================================================ ++//#define APS_FSMCO 0x0004 same with 92Ce ++#define RSV_CTRL 0x001C ++#define RD_CTRL 0x0524 ++ ++//----------------------------------------------------- ++// ++// 0xFE00h ~ 0xFE55h USB Configuration ++// ++//----------------------------------------------------- ++#define REG_USB_INFO 0xFE17 ++#define REG_USB_SPECIAL_OPTION 0xFE55 ++#define REG_USB_DMA_AGG_TO 0xFE5B ++#define REG_USB_AGG_TO 0xFE5C ++#define REG_USB_AGG_TH 0xFE5D ++ ++#define REG_USB_VID 0xFE60 ++#define REG_USB_PID 0xFE62 ++#define REG_USB_OPTIONAL 0xFE64 ++#define REG_USB_CHIRP_K 0xFE65 ++#define REG_USB_PHY 0xFE66 ++#define REG_USB_MAC_ADDR 0xFE70 ++ ++#define REG_USB_HRPWM 0xFE58 ++#define REG_USB_HCPWM 0xFE57 ++ ++#define InvalidBBRFValue 0x12345678 ++ ++//============================================================================ ++// 8192C Regsiter Bit and Content definition ++//============================================================================ ++//----------------------------------------------------- ++// ++// 0x0000h ~ 0x00FFh System Configuration ++// ++//----------------------------------------------------- ++ ++//2 SPS0_CTRL ++#define SW18_FPWM BIT(3) ++ ++ ++//2 SYS_ISO_CTRL ++#define ISO_MD2PP BIT(0) ++#define ISO_UA2USB BIT(1) ++#define ISO_UD2CORE BIT(2) ++#define ISO_PA2PCIE BIT(3) ++#define ISO_PD2CORE BIT(4) ++#define ISO_IP2MAC BIT(5) ++#define ISO_DIOP BIT(6) ++#define ISO_DIOE BIT(7) ++#define ISO_EB2CORE BIT(8) ++#define ISO_DIOR BIT(9) ++ ++#define PWC_EV25V BIT(14) ++#define PWC_EV12V BIT(15) ++ ++ ++//2 SYS_FUNC_EN ++#define FEN_BBRSTB BIT(0) ++#define FEN_BB_GLB_RSTn BIT(1) ++#define FEN_USBA BIT(2) ++#define FEN_UPLL BIT(3) ++#define FEN_USBD BIT(4) ++#define FEN_DIO_PCIE BIT(5) ++#define FEN_PCIEA BIT(6) ++#define FEN_PPLL BIT(7) ++#define FEN_PCIED BIT(8) ++#define FEN_DIOE BIT(9) ++#define FEN_CPUEN BIT(10) ++#define FEN_DCORE BIT(11) ++#define FEN_ELDR BIT(12) ++#define FEN_DIO_RF BIT(13) ++#define FEN_HWPDN BIT(14) ++#define FEN_MREGEN BIT(15) ++ ++//2 APS_FSMCO ++#define PFM_LDALL BIT(0) ++#define PFM_ALDN BIT(1) ++#define PFM_LDKP BIT(2) ++#define PFM_WOWL BIT(3) ++#define EnPDN BIT(4) ++#define PDN_PL BIT(5) ++#define APFM_ONMAC BIT(8) ++#define APFM_OFF BIT(9) ++#define APFM_RSM BIT(10) ++#define AFSM_HSUS BIT(11) ++#define AFSM_PCIE BIT(12) ++#define APDM_MAC BIT(13) ++#define APDM_HOST BIT(14) ++#define APDM_HPDN BIT(15) ++#define RDY_MACON BIT(16) ++#define SUS_HOST BIT(17) ++#define ROP_ALD BIT(20) ++#define ROP_PWR BIT(21) ++#define ROP_SPS BIT(22) ++#define SOP_MRST BIT(25) ++#define SOP_FUSE BIT(26) ++#define SOP_ABG BIT(27) ++#define SOP_AMB BIT(28) ++#define SOP_RCK BIT(29) ++#define SOP_A8M BIT(30) ++#define XOP_BTCK BIT(31) ++ ++//2 SYS_CLKR ++#define ANAD16V_EN BIT(0) ++#define ANA8M BIT(1) ++#define MACSLP BIT(4) ++#define LOADER_CLK_EN BIT(5) ++#define _80M_SSC_DIS BIT(7) ++#define _80M_SSC_EN_HO BIT(8) ++#define PHY_SSC_RSTB BIT(9) ++#define SEC_CLK_EN BIT(10) ++#define MAC_CLK_EN BIT(11) ++#define SYS_CLK_EN BIT(12) ++#define RING_CLK_EN BIT(13) ++ ++ ++//2 9346CR ++ ++ ++#define EEDO BIT(0) ++#define EEDI BIT(1) ++#define EESK BIT(2) ++#define EECS BIT(3) ++//#define EERPROMSEL BIT(4) ++//#define EEPROM_EN BIT(5) ++#define BOOT_FROM_EEPROM BIT(4) ++#define EEPROM_EN BIT(5) ++#define EEM0 BIT(6) ++#define EEM1 BIT(7) ++ ++ ++//2 AFE_MISC ++#define AFE_BGEN BIT(0) ++#define AFE_MBEN BIT(1) ++#define MAC_ID_EN BIT(7) ++ ++ ++//2 SPS0_CTRL ++ ++ ++//2 SPS_OCP_CFG ++ ++ ++//2 RSV_CTRL ++#define WLOCK_ALL BIT(0) ++#define WLOCK_00 BIT(1) ++#define WLOCK_04 BIT(2) ++#define WLOCK_08 BIT(3) ++#define WLOCK_40 BIT(4) ++#define R_DIS_PRST_0 BIT(5) ++#define R_DIS_PRST_1 BIT(6) ++#define LOCK_ALL_EN BIT(7) ++ ++//2 RF_CTRL ++#define RF_EN BIT(0) ++#define RF_RSTB BIT(1) ++#define RF_SDMRSTB BIT(2) ++ ++ ++ ++//2 LDOA15_CTRL ++#define LDA15_EN BIT(0) ++#define LDA15_STBY BIT(1) ++#define LDA15_OBUF BIT(2) ++#define LDA15_REG_VOS BIT(3) ++#define _LDA15_VOADJ(x) (((x) & 0x7) << 4) ++ ++ ++ ++//2 LDOV12D_CTRL ++#define LDV12_EN BIT(0) ++#define LDV12_SDBY BIT(1) ++#define LPLDO_HSM BIT(2) ++#define LPLDO_LSM_DIS BIT(3) ++#define _LDV12_VADJ(x) (((x) & 0xF) << 4) ++ ++ ++//2 AFE_XTAL_CTRL ++#define XTAL_EN BIT(0) ++#define XTAL_BSEL BIT(1) ++#define _XTAL_BOSC(x) (((x) & 0x3) << 2) ++#define _XTAL_CADJ(x) (((x) & 0xF) << 4) ++#define XTAL_GATE_USB BIT(8) ++#define _XTAL_USB_DRV(x) (((x) & 0x3) << 9) ++#define XTAL_GATE_AFE BIT(11) ++#define _XTAL_AFE_DRV(x) (((x) & 0x3) << 12) ++#define XTAL_RF_GATE BIT(14) ++#define _XTAL_RF_DRV(x) (((x) & 0x3) << 15) ++#define XTAL_GATE_DIG BIT(17) ++#define _XTAL_DIG_DRV(x) (((x) & 0x3) << 18) ++#define XTAL_BT_GATE BIT(20) ++#define _XTAL_BT_DRV(x) (((x) & 0x3) << 21) ++#define _XTAL_GPIO(x) (((x) & 0x7) << 23) ++ ++ ++#define CKDLY_AFE BIT(26) ++#define CKDLY_USB BIT(27) ++#define CKDLY_DIG BIT(28) ++#define CKDLY_BT BIT(29) ++ ++ ++//2 AFE_PLL_CTRL ++#define APLL_EN BIT(0) ++#define APLL_320_EN BIT(1) ++#define APLL_FREF_SEL BIT(2) ++#define APLL_EDGE_SEL BIT(3) ++#define APLL_WDOGB BIT(4) ++#define APLL_LPFEN BIT(5) ++ ++#define APLL_REF_CLK_13MHZ 0x1 ++#define APLL_REF_CLK_19_2MHZ 0x2 ++#define APLL_REF_CLK_20MHZ 0x3 ++#define APLL_REF_CLK_25MHZ 0x4 ++#define APLL_REF_CLK_26MHZ 0x5 ++#define APLL_REF_CLK_38_4MHZ 0x6 ++#define APLL_REF_CLK_40MHZ 0x7 ++ ++#define APLL_320EN BIT(14) ++#define APLL_80EN BIT(15) ++#define APLL_1MEN BIT(24) ++ ++ ++//2 EFUSE_CTRL ++#define ALD_EN BIT(18) ++#define EF_PD BIT(19) ++#define EF_FLAG BIT(31) ++ ++//2 EFUSE_TEST (For RTL8723 partially) ++#define EF_TRPT BIT(7) ++#define EF_CELL_SEL (BIT(8)|BIT(9)) // 00: Wifi Efuse, 01: BT Efuse0, 10: BT Efuse1, 11: BT Efuse2 ++#define LDOE25_EN BIT(31) ++#define EFUSE_SEL(x) (((x) & 0x3) << 8) ++#define EFUSE_SEL_MASK 0x300 ++#define EFUSE_WIFI_SEL_0 0x0 ++#define EFUSE_BT_SEL_0 0x1 ++#define EFUSE_BT_SEL_1 0x2 ++#define EFUSE_BT_SEL_2 0x3 ++ ++#define EFUSE_ACCESS_ON 0x69 // For RTL8723 only. ++#define EFUSE_ACCESS_OFF 0x00 // For RTL8723 only. ++ ++//2 PWR_DATA ++ ++//2 CAL_TIMER ++ ++//2 ACLK_MON ++#define RSM_EN BIT(0) ++#define Timer_EN BIT(4) ++ ++ ++//2 GPIO_MUXCFG ++#define TRSW0EN BIT(2) ++#define TRSW1EN BIT(3) ++#define EROM_EN BIT(4) ++#define EnBT BIT(5) ++#define EnUart BIT(8) ++#define Uart_910 BIT(9) ++#define EnPMAC BIT(10) ++#define SIC_SWRST BIT(11) ++#define EnSIC BIT(12) ++#define SIC_23 BIT(13) ++#define EnHDP BIT(14) ++#define SIC_LBK BIT(15) ++ ++//2 GPIO_PIN_CTRL ++ ++// GPIO BIT ++#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2) ++ ++//2 GPIO_INTM ++ ++//2 LEDCFG ++#define LED0PL BIT(4) ++#define LED0DIS BIT(7) ++#define LED1DIS BIT(15) ++#define LED1PL BIT(12) ++ ++#define SECCAM_CLR BIT(30) ++ ++ ++//2 FSIMR ++ ++//2 FSISR ++ ++ ++//2 8051FWDL ++//2 MCUFWDL ++#define MCUFWDL_EN BIT(0) ++#define MCUFWDL_RDY BIT(1) ++#define FWDL_ChkSum_rpt BIT(2) ++#define MACINI_RDY BIT(3) ++#define BBINI_RDY BIT(4) ++#define RFINI_RDY BIT(5) ++#define WINTINI_RDY BIT(6) ++#define CPRST BIT(23) ++ ++//2REG_HPON_FSM ++#define BOND92CE_1T2R_CFG BIT(22) ++ ++ ++//2 REG_SYS_CFG ++#define XCLK_VLD BIT(0) ++#define ACLK_VLD BIT(1) ++#define UCLK_VLD BIT(2) ++#define PCLK_VLD BIT(3) ++#define PCIRSTB BIT(4) ++#define V15_VLD BIT(5) ++#define TRP_B15V_EN BIT(7) ++#define SIC_IDLE BIT(8) ++#define BD_MAC2 BIT(9) ++#define BD_MAC1 BIT(10) ++#define IC_MACPHY_MODE BIT(11) ++#define CHIP_VER (BIT(12)|BIT(13)|BIT(14)|BIT(15)) ++#define BT_FUNC BIT(16) ++#define VENDOR_ID BIT(19) ++#define PAD_HWPD_IDN BIT(22) ++#define TRP_VAUX_EN BIT(23) ++#define TRP_BT_EN BIT(24) ++#define BD_PKG_SEL BIT(25) ++#define BD_HCI_SEL BIT(26) ++#define TYPE_ID BIT(27) ++ ++#define CHIP_VER_RTL_MASK 0xF000 //Bit 12 ~ 15 ++#define CHIP_VER_RTL_SHIFT 12 ++ ++//2REG_GPIO_OUTSTS (For RTL8723 only) ++#define EFS_HCI_SEL (BIT(0)|BIT(1)) ++#define PAD_HCI_SEL (BIT(2)|BIT(3)) ++#define HCI_SEL (BIT(4)|BIT(5)) ++#define PKG_SEL_HCI BIT(6) ++#define FEN_GPS BIT(7) ++#define FEN_BT BIT(8) ++#define FEN_WL BIT(9) ++#define FEN_PCI BIT(10) ++#define FEN_USB BIT(11) ++#define BTRF_HWPDN_N BIT(12) ++#define WLRF_HWPDN_N BIT(13) ++#define PDN_BT_N BIT(14) ++#define PDN_GPS_N BIT(15) ++#define BT_CTL_HWPDN BIT(16) ++#define GPS_CTL_HWPDN BIT(17) ++#define PPHY_SUSB BIT(20) ++#define UPHY_SUSB BIT(21) ++#define PCI_SUSEN BIT(22) ++#define USB_SUSEN BIT(23) ++#define RF_RL_ID (BIT(31)|BIT(30)|BIT(29)|BIT(28)) ++ ++//----------------------------------------------------- ++// ++// 0x0100h ~ 0x01FFh MACTOP General Configuration ++// ++//----------------------------------------------------- ++ ++ ++//2 Function Enable Registers ++//2 CR ++ ++#define REG_LBMODE (REG_CR + 3) ++ ++ ++#define HCI_TXDMA_EN BIT(0) ++#define HCI_RXDMA_EN BIT(1) ++#define TXDMA_EN BIT(2) ++#define RXDMA_EN BIT(3) ++#define PROTOCOL_EN BIT(4) ++#define SCHEDULE_EN BIT(5) ++#define MACTXEN BIT(6) ++#define MACRXEN BIT(7) ++#define ENSWBCN BIT(8) ++#define ENSEC BIT(9) ++ ++// Network type ++#define _NETTYPE(x) (((x) & 0x3) << 16) ++#define MASK_NETTYPE 0x30000 ++#define NT_NO_LINK 0x0 ++#define NT_LINK_AD_HOC 0x1 ++#define NT_LINK_AP 0x2 ++#define NT_AS_AP 0x3 ++ ++#define _LBMODE(x) (((x) & 0xF) << 24) ++#define MASK_LBMODE 0xF000000 ++#define LOOPBACK_NORMAL 0x0 ++#define LOOPBACK_IMMEDIATELY 0xB ++#define LOOPBACK_MAC_DELAY 0x3 ++#define LOOPBACK_PHY 0x1 ++#define LOOPBACK_DMA 0x7 ++ ++ ++//2 PBP - Page Size Register ++#define GET_RX_PAGE_SIZE(value) ((value) & 0xF) ++#define GET_TX_PAGE_SIZE(value) (((value) & 0xF0) >> 4) ++#define _PSRX_MASK 0xF ++#define _PSTX_MASK 0xF0 ++#define _PSRX(x) (x) ++#define _PSTX(x) ((x) << 4) ++ ++#define PBP_64 0x0 ++#define PBP_128 0x1 ++#define PBP_256 0x2 ++#define PBP_512 0x3 ++#define PBP_1024 0x4 ++ ++ ++//2 TX/RXDMA ++#define RXDMA_ARBBW_EN BIT(0) ++#define RXSHFT_EN BIT(1) ++#define RXDMA_AGG_EN BIT(2) ++#define QS_VO_QUEUE BIT(8) ++#define QS_VI_QUEUE BIT(9) ++#define QS_BE_QUEUE BIT(10) ++#define QS_BK_QUEUE BIT(11) ++#define QS_MANAGER_QUEUE BIT(12) ++#define QS_HIGH_QUEUE BIT(13) ++ ++#define HQSEL_VOQ BIT(0) ++#define HQSEL_VIQ BIT(1) ++#define HQSEL_BEQ BIT(2) ++#define HQSEL_BKQ BIT(3) ++#define HQSEL_MGTQ BIT(4) ++#define HQSEL_HIQ BIT(5) ++ ++// For normal driver, 0x10C ++#define _TXDMA_HIQ_MAP(x) (((x)&0x3) << 14) ++#define _TXDMA_MGQ_MAP(x) (((x)&0x3) << 12) ++#define _TXDMA_BKQ_MAP(x) (((x)&0x3) << 10) ++#define _TXDMA_BEQ_MAP(x) (((x)&0x3) << 8 ) ++#define _TXDMA_VIQ_MAP(x) (((x)&0x3) << 6 ) ++#define _TXDMA_VOQ_MAP(x) (((x)&0x3) << 4 ) ++ ++#define QUEUE_LOW 1 ++#define QUEUE_NORMAL 2 ++#define QUEUE_HIGH 3 ++ ++ ++ ++//2 TRXFF_BNDY ++ ++ ++//2 LLT_INIT ++#define _LLT_NO_ACTIVE 0x0 ++#define _LLT_WRITE_ACCESS 0x1 ++#define _LLT_READ_ACCESS 0x2 ++ ++#define _LLT_INIT_DATA(x) ((x) & 0xFF) ++#define _LLT_INIT_ADDR(x) (((x) & 0xFF) << 8) ++#define _LLT_OP(x) (((x) & 0x3) << 30) ++#define _LLT_OP_VALUE(x) (((x) >> 30) & 0x3) ++ ++ ++//2 BB_ACCESS_CTRL ++#define BB_WRITE_READ_MASK (BIT(31) | BIT(30)) ++#define BB_WRITE_EN BIT(30) ++#define BB_READ_EN BIT(31) ++//#define BB_ADDR_MASK 0xFFF ++//#define _BB_ADDR(x) ((x) & BB_ADDR_MASK) ++ ++//----------------------------------------------------- ++// ++// 0x0200h ~ 0x027Fh TXDMA Configuration ++// ++//----------------------------------------------------- ++//2 RQPN ++#define _HPQ(x) ((x) & 0xFF) ++#define _LPQ(x) (((x) & 0xFF) << 8) ++#define _PUBQ(x) (((x) & 0xFF) << 16) ++#define _NPQ(x) ((x) & 0xFF) // NOTE: in RQPN_NPQ register ++ ++ ++#define HPQ_PUBLIC_DIS BIT(24) ++#define LPQ_PUBLIC_DIS BIT(25) ++#define LD_RQPN BIT(31) ++ ++ ++//2 TDECTRL ++#define BCN_VALID BIT(16) ++#define BCN_HEAD(x) (((x) & 0xFF) << 8) ++#define BCN_HEAD_MASK 0xFF00 ++ ++//2 TDECTL ++#define BLK_DESC_NUM_SHIFT 4 ++#define BLK_DESC_NUM_MASK 0xF ++ ++ ++//2 TXDMA_OFFSET_CHK ++#define DROP_DATA_EN BIT(9) ++ ++//----------------------------------------------------- ++// ++// 0x0400h ~ 0x047Fh Protocol Configuration ++// ++//----------------------------------------------------- ++//2 FWHW_TXQ_CTRL ++#define EN_AMPDU_RTY_NEW BIT(7) ++ ++//2 INIRTSMCS_SEL ++#define _INIRTSMCS_SEL(x) ((x) & 0x3F) ++ ++ ++//2 SPEC SIFS ++#define _SPEC_SIFS_CCK(x) ((x) & 0xFF) ++#define _SPEC_SIFS_OFDM(x) (((x) & 0xFF) << 8) ++ ++ ++//2 RRSR ++ ++#define RATE_REG_BITMAP_ALL 0xFFFFF ++ ++#define _RRSC_BITMAP(x) ((x) & 0xFFFFF) ++ ++#define _RRSR_RSC(x) (((x) & 0x3) << 21) ++#define RRSR_RSC_RESERVED 0x0 ++#define RRSR_RSC_UPPER_SUBCHANNEL 0x1 ++#define RRSR_RSC_LOWER_SUBCHANNEL 0x2 ++#define RRSR_RSC_DUPLICATE_MODE 0x3 ++ ++ ++//2 ARFR ++#define USE_SHORT_G1 BIT(20) ++ ++//2 AGGLEN_LMT_L ++#define _AGGLMT_MCS0(x) ((x) & 0xF) ++#define _AGGLMT_MCS1(x) (((x) & 0xF) << 4) ++#define _AGGLMT_MCS2(x) (((x) & 0xF) << 8) ++#define _AGGLMT_MCS3(x) (((x) & 0xF) << 12) ++#define _AGGLMT_MCS4(x) (((x) & 0xF) << 16) ++#define _AGGLMT_MCS5(x) (((x) & 0xF) << 20) ++#define _AGGLMT_MCS6(x) (((x) & 0xF) << 24) ++#define _AGGLMT_MCS7(x) (((x) & 0xF) << 28) ++ ++ ++//2 RL ++#define RETRY_LIMIT_SHORT_SHIFT 8 ++#define RETRY_LIMIT_LONG_SHIFT 0 ++ ++ ++//2 DARFRC ++#define _DARF_RC1(x) ((x) & 0x1F) ++#define _DARF_RC2(x) (((x) & 0x1F) << 8) ++#define _DARF_RC3(x) (((x) & 0x1F) << 16) ++#define _DARF_RC4(x) (((x) & 0x1F) << 24) ++// NOTE: shift starting from address (DARFRC + 4) ++#define _DARF_RC5(x) ((x) & 0x1F) ++#define _DARF_RC6(x) (((x) & 0x1F) << 8) ++#define _DARF_RC7(x) (((x) & 0x1F) << 16) ++#define _DARF_RC8(x) (((x) & 0x1F) << 24) ++ ++ ++//2 RARFRC ++#define _RARF_RC1(x) ((x) & 0x1F) ++#define _RARF_RC2(x) (((x) & 0x1F) << 8) ++#define _RARF_RC3(x) (((x) & 0x1F) << 16) ++#define _RARF_RC4(x) (((x) & 0x1F) << 24) ++// NOTE: shift starting from address (RARFRC + 4) ++#define _RARF_RC5(x) ((x) & 0x1F) ++#define _RARF_RC6(x) (((x) & 0x1F) << 8) ++#define _RARF_RC7(x) (((x) & 0x1F) << 16) ++#define _RARF_RC8(x) (((x) & 0x1F) << 24) ++ ++ ++ ++ ++//----------------------------------------------------- ++// ++// 0x0500h ~ 0x05FFh EDCA Configuration ++// ++//----------------------------------------------------- ++ ++ ++ ++//2 EDCA setting ++#define AC_PARAM_TXOP_LIMIT_OFFSET 16 ++#define AC_PARAM_ECW_MAX_OFFSET 12 ++#define AC_PARAM_ECW_MIN_OFFSET 8 ++#define AC_PARAM_AIFS_OFFSET 0 ++ ++ ++//2 EDCA_VO_PARAM ++#define _AIFS(x) (x) ++#define _ECW_MAX_MIN(x) ((x) << 8) ++#define _TXOP_LIMIT(x) ((x) << 16) ++ ++ ++#define _BCNIFS(x) ((x) & 0xFF) ++#define _BCNECW(x) (((x) & 0xF))<< 8) ++ ++ ++#define _LRL(x) ((x) & 0x3F) ++#define _SRL(x) (((x) & 0x3F) << 8) ++ ++ ++//2 SIFS_CCK ++#define _SIFS_CCK_CTX(x) ((x) & 0xFF) ++#define _SIFS_CCK_TRX(x) (((x) & 0xFF) << 8); ++ ++ ++//2 SIFS_OFDM ++#define _SIFS_OFDM_CTX(x) ((x) & 0xFF) ++#define _SIFS_OFDM_TRX(x) (((x) & 0xFF) << 8); ++ ++ ++//2 TBTT PROHIBIT ++#define _TBTT_PROHIBIT_HOLD(x) (((x) & 0xFF) << 8) ++ ++ ++//2 REG_RD_CTRL ++#define DIS_EDCA_CNT_DWN BIT(11) ++ ++ ++//2 BCN_CTRL ++#define EN_MBSSID BIT(1) ++#define EN_TXBCN_RPT BIT(2) ++#define EN_BCN_FUNCTION BIT(3) ++#define DIS_TSF_UPDATE BIT(3) ++ ++// The same function but different bit field. ++#define DIS_TSF_UDT0_NORMAL_CHIP BIT(4) ++#define DIS_TSF_UDT0_TEST_CHIP BIT(5) ++ ++//2 ACMHWCTRL ++#define AcmHw_HwEn BIT(0) ++#define AcmHw_BeqEn BIT(1) ++#define AcmHw_ViqEn BIT(2) ++#define AcmHw_VoqEn BIT(3) ++#define AcmHw_BeqStatus BIT(4) ++#define AcmHw_ViqStatus BIT(5) ++#define AcmHw_VoqStatus BIT(6) ++ ++ ++ ++//----------------------------------------------------- ++// ++// 0x0600h ~ 0x07FFh WMAC Configuration ++// ++//----------------------------------------------------- ++ ++//2 APSD_CTRL ++#define APSDOFF BIT(6) ++#define APSDOFF_STATUS BIT(7) ++ ++ ++//2 BWOPMODE ++#define BW_20MHZ BIT(2) ++//#define BW_OPMODE_20MHZ BIT(2) // For compability ++ ++ ++#define RATE_BITMAP_ALL 0xFFFFF ++ ++// Only use CCK 1M rate for ACK ++#define RATE_RRSR_CCK_ONLY_1M 0xFFFF1 ++ ++//2 TCR ++#define TSFRST BIT(0) ++#define DIS_GCLK BIT(1) ++#define PAD_SEL BIT(2) ++#define PWR_ST BIT(6) ++#define PWRBIT_OW_EN BIT(7) ++#define ACRC BIT(8) ++#define CFENDFORM BIT(9) ++#define ICV BIT(10) ++ ++ ++ ++//2 RCR ++#define AAP BIT(0) ++#define APM BIT(1) ++#define AM BIT(2) ++#define AB BIT(3) ++#define ADD3 BIT(4) ++#define APWRMGT BIT(5) ++#define CBSSID BIT(6) ++#define CBSSID_BCN BIT(7) ++#define ACRC32 BIT(8) ++#define AICV BIT(9) ++#define ADF BIT(11) ++#define ACF BIT(12) ++#define AMF BIT(13) ++#define HTC_LOC_CTRL BIT(14) ++#define UC_DATA_EN BIT(16) ++#define BM_DATA_EN BIT(17) ++#define MFBEN BIT(22) ++#define LSIGEN BIT(23) ++#define EnMBID BIT(24) ++#define APP_BASSN BIT(27) ++#define APP_PHYSTS BIT(28) ++#define APP_ICV BIT(29) ++#define APP_MIC BIT(30) ++#define APP_FCS BIT(31) ++ ++//2 RX_PKT_LIMIT ++ ++//2 RX_DLK_TIME ++ ++//2 MBIDCAMCFG ++ ++ ++ ++//2 AMPDU_MIN_SPACE ++#define _MIN_SPACE(x) ((x) & 0x7) ++#define _SHORT_GI_PADDING(x) (((x) & 0x1F) << 3) ++ ++ ++//2 RXERR_RPT ++#define RXERR_TYPE_OFDM_PPDU 0 ++#define RXERR_TYPE_OFDM_FALSE_ALARM 1 ++#define RXERR_TYPE_OFDM_MPDU_OK 2 ++#define RXERR_TYPE_OFDM_MPDU_FAIL 3 ++#define RXERR_TYPE_CCK_PPDU 4 ++#define RXERR_TYPE_CCK_FALSE_ALARM 5 ++#define RXERR_TYPE_CCK_MPDU_OK 6 ++#define RXERR_TYPE_CCK_MPDU_FAIL 7 ++#define RXERR_TYPE_HT_PPDU 8 ++#define RXERR_TYPE_HT_FALSE_ALARM 9 ++#define RXERR_TYPE_HT_MPDU_TOTAL 10 ++#define RXERR_TYPE_HT_MPDU_OK 11 ++#define RXERR_TYPE_HT_MPDU_FAIL 12 ++#define RXERR_TYPE_RX_FULL_DROP 15 ++ ++#define RXERR_COUNTER_MASK 0xFFFFF ++#define RXERR_RPT_RST BIT(27) ++#define _RXERR_RPT_SEL(type) ((type) << 28) ++ ++ ++//2 SECCFG ++#define SCR_TxUseDK BIT(0) //Force Tx Use Default Key ++#define SCR_RxUseDK BIT(1) //Force Rx Use Default Key ++#define SCR_TxEncEnable BIT(2) //Enable Tx Encryption ++#define SCR_RxDecEnable BIT(3) //Enable Rx Decryption ++#define SCR_SKByA2 BIT(4) //Search kEY BY A2 ++#define SCR_NoSKMC BIT(5) //No Key Search Multicast ++ ++ ++ ++//----------------------------------------------------- ++// ++// 0xFE00h ~ 0xFE55h USB Configuration ++// ++//----------------------------------------------------- ++ ++//2 USB Information (0xFE17) ++#define USB_IS_HIGH_SPEED 0 ++#define USB_IS_FULL_SPEED 1 ++#define USB_SPEED_MASK BIT(5) ++ ++#define USB_NORMAL_SIE_EP_MASK 0xF ++#define USB_NORMAL_SIE_EP_SHIFT 4 ++ ++#define USB_TEST_EP_MASK 0x30 ++#define USB_TEST_EP_SHIFT 4 ++ ++//2 Special Option ++#define USB_AGG_EN BIT(3) ++ ++ ++//2REG_C2HEVT_CLEAR ++#define C2H_EVT_HOST_CLOSE 0x00 // Set by driver and notify FW that the driver has read the C2H command message ++#define C2H_EVT_FW_CLOSE 0xFF // Set by FW indicating that FW had set the C2H command message and it's not yet read by driver. ++ ++ ++//2REG_MULTI_FUNC_CTRL(For RTL8723 Only) ++#define WL_HWPDN_EN BIT0 // Enable GPIO[9] as WiFi HW PDn source ++#define WL_HWPDN_SL BIT1 // WiFi HW PDn polarity control ++#define WL_FUNC_EN BIT2 // WiFi function enable ++#define WL_HWROF_EN BIT3 // Enable GPIO[9] as WiFi RF HW PDn source ++#define BT_HWPDN_EN BIT16 // Enable GPIO[11] as BT HW PDn source ++#define BT_HWPDN_SL BIT17 // BT HW PDn polarity control ++#define BT_FUNC_EN BIT18 // BT function enable ++#define BT_HWROF_EN BIT19 // Enable GPIO[11] as BT/GPS RF HW PDn source ++#define GPS_HWPDN_EN BIT20 // Enable GPIO[10] as GPS HW PDn source ++#define GPS_HWPDN_SL BIT21 // GPS HW PDn polarity control ++#define GPS_FUNC_EN BIT22 // GPS function enable ++ ++//3 REG_LIFECTRL_CTRL ++#define HAL92C_EN_PKT_LIFE_TIME_BK BIT3 ++#define HAL92C_EN_PKT_LIFE_TIME_BE BIT2 ++#define HAL92C_EN_PKT_LIFE_TIME_VI BIT1 ++#define HAL92C_EN_PKT_LIFE_TIME_VO BIT0 ++ ++#define HAL92C_MSDU_LIFE_TIME_UNIT 128 // in us, said by Tim. ++ ++//======================================================== ++// General definitions ++//======================================================== ++ ++#define MAC_ADDR_LEN 6 ++#define LAST_ENTRY_OF_TX_PKT_BUFFER 255 ++ ++#define POLLING_LLT_THRESHOLD 20 ++#define POLLING_READY_TIMEOUT_COUNT 1000 ++ ++// Min Spacing related settings. ++#define MAX_MSS_DENSITY_2T 0x13 ++#define MAX_MSS_DENSITY_1T 0x0A ++ ++//---------------------------------------------------------------------------- ++// 8192C GPIO MUX Configuration Register (offset 0x40, 4 byte) ++//---------------------------------------------------------------------------- ++#define GPIOSEL_GPIO 0 ++#define GPIOSEL_ENBT BIT5 ++ ++//---------------------------------------------------------------------------- ++// 8192C GPIO PIN Control Register (offset 0x44, 4 byte) ++//---------------------------------------------------------------------------- ++#define GPIO_IN REG_GPIO_PIN_CTRL // GPIO pins input value ++#define GPIO_OUT (REG_GPIO_PIN_CTRL+1) // GPIO pins output value ++#define GPIO_IO_SEL (REG_GPIO_PIN_CTRL+2) // GPIO pins output enable when a bit is set to "1"; otherwise, input is configured. ++#define GPIO_MOD (REG_GPIO_PIN_CTRL+3) ++ ++ ++ ++#include "basic_types.h" ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_sreset.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_sreset.h +new file mode 100644 +index 00000000..93c36282 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_sreset.h +@@ -0,0 +1,33 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTL8192C_SRESET_C_ ++#define _RTL8192C_SRESET_C_ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef DBG_CONFIG_ERROR_DETECT ++extern void rtl8192c_sreset_xmit_status_check(_adapter *padapter); ++extern void rtl8192c_sreset_linked_status_check(_adapter *padapter); ++#endif ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_xmit.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_xmit.h +new file mode 100644 +index 00000000..332856c5 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192c_xmit.h +@@ -0,0 +1,165 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTL8192C_XMIT_H_ ++#define _RTL8192C_XMIT_H_ ++ ++// ++//defined for TX DESC Operation ++// ++ ++#define MAX_TID (15) ++ ++//OFFSET 0 ++#define OFFSET_SZ 0 ++#define OFFSET_SHT 16 ++#define BMC BIT(24) ++#define LSG BIT(26) ++#define FSG BIT(27) ++#define OWN BIT(31) ++ ++ ++//OFFSET 4 ++#define PKT_OFFSET_SZ 0 ++#define BK BIT(6) ++#define QSEL_SHT 8 ++#define Rate_ID_SHT 16 ++#define NAVUSEHDR BIT(20) ++#define PKT_OFFSET_SHT 26 ++#define HWPC BIT(31) ++ ++//OFFSET 8 ++#define AGG_EN BIT(29) ++ ++//OFFSET 12 ++#define SEQ_SHT 16 ++ ++//OFFSET 16 ++#define QoS BIT(6) ++#define HW_SEQ_EN BIT(7) ++#define USERATE BIT(8) ++#define DISDATAFB BIT(10) ++#define DATA_SHORT BIT(24) ++#define DATA_BW BIT(25) ++ ++//OFFSET 20 ++#define SGI BIT(6) ++ ++// ++// Queue Select Value in TxDesc ++// ++#define QSLT_BK 0x2//0x01 ++#define QSLT_BE 0x0 ++#define QSLT_VI 0x5//0x4 ++#define QSLT_VO 0x7//0x6 ++#define QSLT_BEACON 0x10 ++#define QSLT_HIGH 0x11 ++#define QSLT_MGNT 0x12 ++#define QSLT_CMD 0x13 ++ ++struct txrpt_ccx_8192c { ++ /* offset 0 */ ++ u8 retry_cnt:6; ++ u8 rsvd_0:2; ++ ++ /* offset 1 */ ++ u8 rts_retry_cnt:6; ++ u8 rsvd_1:2; ++ ++ /* offset 2 */ ++ u8 ccx_qtime0; ++ u8 ccx_qtime1; ++ ++ /* offset 4 */ ++ u8 missed_pkt_num:5; ++ u8 rsvd_4:3; ++ ++ /* offset 5 */ ++ u8 mac_id:5; ++ u8 des1_fragssn:3; ++ ++ /* offset 6 */ ++ u8 rpt_pkt_num:5; ++ u8 pkt_drop:1; ++ u8 lifetime_over:1; ++ u8 retry_over:1; ++ ++ /* offset 7*/ ++ u8 edca_tx_queue:4; ++ u8 rsvd_7:1; ++ u8 bmc:1; ++ u8 pkt_ok:1; ++ u8 int_ccx:1; ++}; ++ ++#define txrpt_ccx_qtime_8192c(txrpt_ccx) ((txrpt_ccx)->ccx_qtime0+((txrpt_ccx)->ccx_qtime1<<8)) ++ ++#ifdef CONFIG_XMIT_ACK ++void dump_txrpt_ccx_8192c(void *buf); ++void handle_txrpt_ccx_8192c(_adapter *adapter, void *buf); ++#else ++#define dump_txrpt_ccx_8192c(buf) do {} while(0) ++#define handle_txrpt_ccx_8192c(adapter, buf) do {} while(0) ++#endif ++ ++#ifdef CONFIG_USB_HCI ++ ++#ifdef CONFIG_USB_TX_AGGREGATION ++#define MAX_TX_AGG_PACKET_NUMBER 0xFF ++#endif ++ ++s32 rtl8192cu_init_xmit_priv(_adapter * padapter); ++ ++void rtl8192cu_free_xmit_priv(_adapter * padapter); ++ ++void rtl8192cu_cal_txdesc_chksum(struct tx_desc *ptxdesc); ++ ++s32 rtl8192cu_xmitframe_complete(_adapter *padapter, struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf); ++ ++s32 rtl8192cu_mgnt_xmit(_adapter *padapter, struct xmit_frame *pmgntframe); ++ ++s32 rtl8192cu_hal_xmit(_adapter *padapter, struct xmit_frame *pxmitframe); ++ ++#ifdef CONFIG_HOSTAPD_MLME ++s32 rtl8192cu_hostap_mgnt_xmit_entry(_adapter *padapter, _pkt *pkt); ++#endif ++ ++#endif ++ ++#ifdef CONFIG_PCI_HCI ++s32 rtl8192ce_init_xmit_priv(_adapter * padapter); ++void rtl8192ce_free_xmit_priv(_adapter * padapter); ++ ++s32 rtl8192ce_enqueue_xmitbuf(struct rtw_tx_ring *ring, struct xmit_buf *pxmitbuf); ++struct xmit_buf *rtl8192ce_dequeue_xmitbuf(struct rtw_tx_ring *ring); ++ ++void rtl8192ce_xmitframe_resume(_adapter *padapter); ++ ++s32 rtl8192ce_mgnt_xmit(_adapter *padapter, struct xmit_frame *pmgntframe); ++ ++s32 rtl8192ce_hal_xmit(_adapter *padapter, struct xmit_frame *pxmitframe); ++ ++#ifdef CONFIG_HOSTAPD_MLME ++s32 rtl8192ce_hostap_mgnt_xmit_entry(_adapter *padapter, _pkt *pkt); ++#endif ++ ++#endif ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_cmd.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_cmd.h +new file mode 100644 +index 00000000..ef571f1d +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_cmd.h +@@ -0,0 +1,103 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8192D_CMD_H_ ++#define __RTL8192D_CMD_H_ ++ ++ ++//-------------------------------------------- ++//3 Host Message Box ++//-------------------------------------------- ++ ++// User Define Message [31:8] ++ ++//_SETPWRMODE_PARM ++#define SET_H2CCMD_PWRMODE_PARM_MODE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 8, __Value) ++#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 0, 8, __Value) ++#define SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+2, 0, 8, __Value) ++ ++//JOINBSSRPT_PARM ++#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 8, __Value) ++ ++//_RSVDPAGE_LOC ++#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 8, __Value) ++#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 0, 8, __Value) ++#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+2, 0, 8, __Value) ++ ++//P2P_PS_OFFLOAD ++ ++struct P2P_PS_Offload_t { ++ unsigned char Offload_En:1; ++ unsigned char role:1; // 1: Owner, 0: Client ++ unsigned char CTWindow_En:1; ++ unsigned char NoA0_En:1; ++ unsigned char NoA1_En:1; ++ unsigned char AllStaSleep:1; // Only valid in Owner ++ unsigned char discovery:1; ++ unsigned char rsvd:1; ++}; ++ ++#define SET_H2CCMD_P2P_PS_OFFLOAD_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 1, __Value) ++#define SET_H2CCMD_P2P_PS_OFFLOAD_ROLE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 1, 1, __Value) ++#define SET_H2CCMD_P2P_PS_OFFLOAD_CTW(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 2, 1, __Value) ++#define SET_H2CCMD_P2P_PS_OFFLOAD_NOA0(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 3, 1, __Value) ++#define SET_H2CCMD_P2P_PS_OFFLOAD_NOA1(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 4, 1, __Value) ++#define SET_H2CCMD_P2P_PS_OFFLOAD_ALLSTASLEEP(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 5, 1, __Value) ++#define SET_H2CCMD_P2P_PS_OFFLOAD_DISCOVERY(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 6, 1, __Value) ++ ++// Description: Determine the types of H2C commands that are the same in driver and Fw. ++// Fisrt constructed by tynli. 2009.10.09. ++typedef enum _RTL8192D_H2C_CMD ++{ ++ H2C_AP_OFFLOAD = 0, /*0*/ ++ H2C_SETPWRMODE = 1, /*1*/ ++ H2C_JOINBSSRPT = 2, /*2*/ ++ H2C_RSVDPAGE = 3, ++ H2C_RSSI_REPORT = 5, ++ H2C_RA_MASK = 6, ++ H2C_P2P_PS_OFFLOAD = 8, ++ H2C_MAC_MODE_SEL = 9, ++ H2C_PWRM=15, ++ H2C_P2P_PS_CTW_CMD = 24, ++ H2C_PathDiv = 26, //PathDiv--NeilChen--2011.07.15 ++ H2C_CMD_MAX ++}RTL8192D_H2C_CMD; ++ ++struct cmd_msg_parm { ++ u8 eid; //element id ++ u8 sz; // sz ++ u8 buf[6]; ++}; ++ ++ ++void FillH2CCmd92D(_adapter* padapter, u8 ElementID, u32 CmdLen, u8* pCmdBuffer); ++ ++// host message to firmware cmd ++void rtl8192d_set_FwPwrMode_cmd(_adapter*padapter, u8 Mode); ++void rtl8192d_set_FwJoinBssReport_cmd(_adapter* padapter, u8 mstatus); ++u8 rtl8192d_set_rssi_cmd(_adapter*padapter, u8 *param); ++u8 rtl8192d_set_raid_cmd(_adapter*padapter, u32 mask, u8 arg); ++void rtl8192d_Add_RateATid(PADAPTER pAdapter, u32 bitmap, u8 arg, u8 rssi_level); ++#ifdef CONFIG_P2P ++void rtl8192d_set_p2p_ps_offload_cmd(_adapter* padapter, u8 p2p_ps_state); ++#endif //CONFIG_P2P ++ ++#endif ++ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_dm.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_dm.h +new file mode 100644 +index 00000000..b7b91b60 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_dm.h +@@ -0,0 +1,183 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8192D_DM_H__ ++#define __RTL8192D_DM_H__ ++//============================================================ ++// Description: ++// ++// This file is for 92CE/92CU dynamic mechanism only ++// ++// ++//============================================================ ++enum{ ++ UP_LINK, ++ DOWN_LINK, ++}; ++/*------------------------Export global variable----------------------------*/ ++/*------------------------Export global variable----------------------------*/ ++/*------------------------Export Marco Definition---------------------------*/ ++//#define DM_MultiSTA_InitGainChangeNotify(Event) {DM_DigTable.CurMultiSTAConnectState = Event;} ++//============================================================ ++// structure and define ++//============================================================ ++ ++//###### duplicate code,will move to ODM ######### ++#define IQK_MAC_REG_NUM 4 ++#define IQK_ADDA_REG_NUM 16 ++#define IQK_BB_REG_NUM 10 ++#define IQK_BB_REG_NUM_92C 9 ++#define IQK_BB_REG_NUM_92D 10 ++#define IQK_BB_REG_NUM_test 6 ++#define index_mapping_NUM 13 ++#define Rx_index_mapping_NUM 15 ++#define AVG_THERMAL_NUM 8 ++#define IQK_Matrix_REG_NUM 8 ++#define IQK_Matrix_Settings_NUM 1+24+21 ++//###### duplicate code,will move to ODM ######### ++struct dm_priv ++{ ++ u8 DM_Type; ++ u8 DMFlag; ++ u8 InitDMFlag; ++ u32 InitODMFlag; ++ ++ //* Upper and Lower Signal threshold for Rate Adaptive*/ ++ int UndecoratedSmoothedPWDB; ++ int EntryMinUndecoratedSmoothedPWDB; ++ int EntryMaxUndecoratedSmoothedPWDB; ++ int MinUndecoratedPWDBForDM; ++ int LastMinUndecoratedPWDBForDM; ++//###### duplicate code,will move to ODM ######### ++/* ++ //for DIG ++ u8 bDMInitialGainEnable; ++ //u8 binitialized; // for dm_initial_gain_Multi_STA use. ++ DIG_T DM_DigTable; ++ ++ PS_T DM_PSTable; ++ ++ FALSE_ALARM_STATISTICS FalseAlmCnt; ++ ++ //for rate adaptive, in fact, 88c/92c fw will handle this ++ u8 bUseRAMask; ++ RATE_ADAPTIVE RateAdaptive; ++*/ ++ ++ //for High Power ++ u8 bDynamicTxPowerEnable; ++ u8 LastDTPLvl; ++ u8 DynamicTxHighPowerLvl;//Add by Jacken Tx Power Control for Near/Far Range 2008/03/06 ++ ++ //for tx power tracking ++ u8 bTXPowerTracking; ++ u8 TXPowercount; ++ u8 bTXPowerTrackingInit; ++ u8 TxPowerTrackControl; //for mp mode, turn off txpwrtracking as default ++ u8 TM_Trigger; ++ ++ u8 ThermalMeter[2]; // ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 ++ u8 ThermalValue; ++ u8 ThermalValue_LCK; ++ u8 ThermalValue_IQK; ++ u8 ThermalValue_AVG[AVG_THERMAL_NUM]; ++ u8 ThermalValue_AVG_index; ++ u8 ThermalValue_RxGain; ++ u8 ThermalValue_Crystal; ++ u8 Delta_IQK; ++ u8 Delta_LCK; ++ u8 bRfPiEnable; ++ u8 bReloadtxpowerindex; ++ u8 bDoneTxpower; ++ ++ //for APK ++ u32 APKoutput[2][2]; //path A/B; output1_1a/output1_2a ++ u8 bAPKdone; ++ u8 bAPKThermalMeterIgnore; ++ u32 RegA24; ++ ++ //for IQK ++ u32 Reg874; ++ u32 RegC08; ++ u32 Reg88C; ++ u8 Reg522; ++ u8 Reg550; ++ u8 Reg551; ++ u32 Reg870; ++ u32 ADDA_backup[IQK_ADDA_REG_NUM]; ++ u32 IQK_MAC_backup[IQK_MAC_REG_NUM]; ++ u32 IQK_BB_backup[IQK_BB_REG_NUM]; ++ ++ u8 bCCKinCH14; ++ ++ char CCK_index; ++ //u8 Record_CCK_20Mindex; ++ //u8 Record_CCK_40Mindex; ++ char OFDM_index[2]; ++ ++ BOOLEAN bDPKdone[2]; ++ ++ u8 PowerIndex_backup[6]; ++ ++ //for Antenna diversity ++//#ifdef CONFIG_ANTENNA_DIVERSITY ++ //SWAT_T DM_SWAT_Table; ++//#endif ++ //Neil Chen----2011--06--23----- ++ //3 Path Diversity ++ BOOLEAN bPathDiv_Enable; //For 92D Non-interrupt Antenna Diversity by Neil ,add by wl.2011.07.19 ++ BOOLEAN RSSI_test; ++ s32 RSSI_sum_A; ++ s32 RSSI_cnt_A; ++ s32 RSSI_sum_B; ++ s32 RSSI_cnt_B; ++ struct sta_info *RSSI_target; ++ _timer PathDivSwitchTimer; ++ ++ //for TxPwrTracking ++ int RegE94; ++ int RegE9C; ++ int RegEB4; ++ int RegEBC; ++#if MP_DRIVER == 1 ++ u8 RegC04_MP; ++ u32 RegD04_MP; ++#endif ++ u32 TXPowerTrackingCallbackCnt; //cosa add for debug ++ ++ u32 prv_traffic_idx; // edca turbo ++ ++ u32 RegRF3C[2]; //pathA / pathB ++//###### duplicate code,will move to ODM ######### ++ // Add for Reading Initial Data Rate SEL Register 0x484 during watchdog. Using for fill tx desc. 2011.3.21 by Thomas ++ u8 INIDATA_RATE[32]; ++}; ++ ++ ++//============================================================ ++// function prototype ++//============================================================ ++void rtl8192d_init_dm_priv(IN PADAPTER Adapter); ++void rtl8192d_deinit_dm_priv(IN PADAPTER Adapter); ++ ++void rtl8192d_InitHalDm(IN PADAPTER Adapter); ++void rtl8192d_HalDmWatchDog(IN PADAPTER Adapter); ++ ++#endif //__HAL8190PCIDM_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_hal.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_hal.h +new file mode 100644 +index 00000000..97083f0a +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_hal.h +@@ -0,0 +1,854 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8192D_HAL_H__ ++#define __RTL8192D_HAL_H__ ++ ++#include "rtl8192d_spec.h" ++#include "Hal8192DPhyReg.h" ++#include "Hal8192DPhyCfg.h" ++#include "rtl8192d_rf.h" ++#include "rtl8192d_dm.h" ++#include "rtl8192d_recv.h" ++#include "rtl8192d_xmit.h" ++#include "rtl8192d_cmd.h" ++#include "rtw_efuse.h" ++ ++#include "../hal/OUTSRC/odm_precomp.h" ++ ++#ifdef CONFIG_PCI_HCI ++ #include ++ ++ #define RTL819X_DEFAULT_RF_TYPE RF_2T2R ++ ++//--------------------------------------------------------------------- ++// RTL8192DE From file ++//--------------------------------------------------------------------- ++ #define RTL8192D_FW_IMG "rtl8192DE\\rtl8192dfw.bin" ++ ++ #define RTL8192D_PHY_REG "rtl8192DE\\PHY_REG.txt" ++ #define RTL8192D_PHY_REG_PG "rtl8192DE\\PHY_REG_PG.txt" ++ #define RTL8192D_PHY_REG_MP "rtl8192DE\\PHY_REG_MP.txt" ++ ++ #define RTL8192D_AGC_TAB "rtl8192DE\\AGC_TAB.txt" ++ #define RTL8192D_AGC_TAB_2G "rtl8192DE\\AGC_TAB_2G.txt" ++ #define RTL8192D_AGC_TAB_5G "rtl8192DE\\AGC_TAB_5G.txt" ++ #define RTL8192D_PHY_RADIO_A "rtl8192DE\\radio_a.txt" ++ #define RTL8192D_PHY_RADIO_B "rtl8192DE\\radio_b.txt" ++ #define RTL8192D_PHY_RADIO_A_intPA "rtl8192DE\\radio_a_intPA.txt" ++ #define RTL8192D_PHY_RADIO_B_intPA "rtl8192DE\\radio_b_intPA.txt" ++ #define RTL8192D_PHY_MACREG "rtl8192DE\\MAC_REG.txt" ++ ++//--------------------------------------------------------------------- ++// RTL8192DE From header ++//--------------------------------------------------------------------- ++ // Fw Array ++ #define Rtl8192D_FwImageArray Rtl8192DEFwImgArray ++ ++ // MAC/BB/PHY Array ++ #define Rtl8192D_MAC_Array Rtl8192DEMAC_2T_Array ++ #define Rtl8192D_AGCTAB_Array Rtl8192DEAGCTAB_Array ++ #define Rtl8192D_AGCTAB_5GArray Rtl8192DEAGCTAB_5GArray ++ #define Rtl8192D_AGCTAB_2GArray Rtl8192DEAGCTAB_2GArray ++ #define Rtl8192D_AGCTAB_2TArray Rtl8192DEAGCTAB_2TArray ++ #define Rtl8192D_AGCTAB_1TArray Rtl8192DEAGCTAB_1TArray ++ #define Rtl8192D_PHY_REG_2TArray Rtl8192DEPHY_REG_2TArray ++ #define Rtl8192D_PHY_REG_1TArray Rtl8192DEPHY_REG_1TArray ++ #define Rtl8192D_PHY_REG_Array_PG Rtl8192DEPHY_REG_Array_PG ++ #define Rtl8192D_PHY_REG_Array_MP Rtl8192DEPHY_REG_Array_MP ++ #define Rtl8192D_RadioA_2TArray Rtl8192DERadioA_2TArray ++ #define Rtl8192D_RadioA_1TArray Rtl8192DERadioA_1TArray ++ #define Rtl8192D_RadioB_2TArray Rtl8192DERadioB_2TArray ++ #define Rtl8192D_RadioB_1TArray Rtl8192DERadioB_1TArray ++ #define Rtl8192D_RadioA_2T_intPAArray Rtl8192DERadioA_2T_intPAArray ++ #define Rtl8192D_RadioB_2T_intPAArray Rtl8192DERadioB_2T_intPAArray ++ ++ // Array length ++ #define Rtl8192D_FwImageArrayLength Rtl8192DEImgArrayLength ++ #define Rtl8192D_MAC_ArrayLength Rtl8192DEMAC_2T_ArrayLength ++ #define Rtl8192D_AGCTAB_5GArrayLength Rtl8192DEAGCTAB_5GArrayLength ++ #define Rtl8192D_AGCTAB_2GArrayLength Rtl8192DEAGCTAB_2GArrayLength ++ #define Rtl8192D_AGCTAB_2TArrayLength Rtl8192DEAGCTAB_2TArrayLength ++ #define Rtl8192D_AGCTAB_1TArrayLength Rtl8192DEAGCTAB_1TArrayLength ++ #define Rtl8192D_AGCTAB_ArrayLength Rtl8192DEAGCTAB_ArrayLength ++ #define Rtl8192D_PHY_REG_2TArrayLength Rtl8192DEPHY_REG_2TArrayLength ++ #define Rtl8192D_PHY_REG_1TArrayLength Rtl8192DEPHY_REG_1TArrayLength ++ #define Rtl8192D_PHY_REG_Array_PGLength Rtl8192DEPHY_REG_Array_PGLength ++ #define Rtl8192D_PHY_REG_Array_MPLength Rtl8192DEPHY_REG_Array_MPLength ++ #define Rtl8192D_RadioA_2TArrayLength Rtl8192DERadioA_2TArrayLength ++ #define Rtl8192D_RadioB_2TArrayLength Rtl8192DERadioB_2TArrayLength ++ #define Rtl8192D_RadioA_2T_intPAArrayLength Rtl8192DERadioA_2T_intPAArrayLength ++ #define Rtl8192D_RadioB_2T_intPAArrayLength Rtl8192DERadioB_2T_intPAArrayLength ++ ++#elif defined(CONFIG_USB_HCI) ++ ++ ++ #define RTL819X_DEFAULT_RF_TYPE RF_1T2R ++ ++//--------------------------------------------------------------------- ++// RTL8192DU From file ++//--------------------------------------------------------------------- ++ #define RTL8192D_FW_IMG "rtl8192DU\\rtl8192dfw.bin" ++ ++ #define RTL8192D_PHY_REG "rtl8192DU\\PHY_REG.txt" ++ #define RTL8192D_PHY_REG_PG "rtl8192DU\\PHY_REG_PG.txt" ++ #define RTL8192D_PHY_REG_MP "rtl8192DU\\PHY_REG_MP.txt" ++ ++ #define RTL8192D_AGC_TAB "rtl8192DU\\AGC_TAB.txt" ++ #define RTL8192D_AGC_TAB_2G "rtl8192DU\\AGC_TAB_2G.txt" ++ #define RTL8192D_AGC_TAB_5G "rtl8192DU\\AGC_TAB_5G.txt" ++ #define RTL8192D_PHY_RADIO_A "rtl8192DU\\radio_a.txt" ++ #define RTL8192D_PHY_RADIO_B "rtl8192DU\\radio_b.txt" ++ #define RTL8192D_PHY_RADIO_A_intPA "rtl8192DU\\radio_a_intPA.txt" ++ #define RTL8192D_PHY_RADIO_B_intPA "rtl8192DU\\radio_b_intPA.txt" ++ #define RTL8192D_PHY_MACREG "rtl8192DU\\MAC_REG.txt" ++ ++//--------------------------------------------------------------------- ++// RTL8192DU From header ++//--------------------------------------------------------------------- ++ ++ // Fw Array ++ #define Rtl8192D_FwImageArray Rtl8192DUFwImgArray ++ ++ // MAC/BB/PHY Array ++ #define Rtl8192D_MAC_Array Rtl8192DUMAC_2T_Array ++ #define Rtl8192D_AGCTAB_Array Rtl8192DUAGCTAB_Array ++ #define Rtl8192D_AGCTAB_5GArray Rtl8192DUAGCTAB_5GArray ++ #define Rtl8192D_AGCTAB_2GArray Rtl8192DUAGCTAB_2GArray ++ #define Rtl8192D_AGCTAB_2TArray Rtl8192DUAGCTAB_2TArray ++ #define Rtl8192D_AGCTAB_1TArray Rtl8192DUAGCTAB_1TArray ++ #define Rtl8192D_PHY_REG_2TArray Rtl8192DUPHY_REG_2TArray ++ #define Rtl8192D_PHY_REG_1TArray Rtl8192DUPHY_REG_1TArray ++ #define Rtl8192D_PHY_REG_Array_PG Rtl8192DUPHY_REG_Array_PG ++ #define Rtl8192D_PHY_REG_Array_MP Rtl8192DUPHY_REG_Array_MP ++ #define Rtl8192D_RadioA_2TArray Rtl8192DURadioA_2TArray ++ #define Rtl8192D_RadioA_1TArray Rtl8192DURadioA_1TArray ++ #define Rtl8192D_RadioB_2TArray Rtl8192DURadioB_2TArray ++ #define Rtl8192D_RadioB_1TArray Rtl8192DURadioB_1TArray ++ #define Rtl8192D_RadioA_2T_intPAArray Rtl8192DURadioA_2T_intPAArray ++ #define Rtl8192D_RadioB_2T_intPAArray Rtl8192DURadioB_2T_intPAArray ++ ++ // Array length ++ #define Rtl8192D_FwImageArrayLength Rtl8192DUImgArrayLength ++ #define Rtl8192D_MAC_ArrayLength Rtl8192DUMAC_2T_ArrayLength ++ #define Rtl8192D_AGCTAB_5GArrayLength Rtl8192DUAGCTAB_5GArrayLength ++ #define Rtl8192D_AGCTAB_2GArrayLength Rtl8192DUAGCTAB_2GArrayLength ++ #define Rtl8192D_AGCTAB_2TArrayLength Rtl8192DUAGCTAB_2TArrayLength ++ #define Rtl8192D_AGCTAB_1TArrayLength Rtl8192DUAGCTAB_1TArrayLength ++ #define Rtl8192D_AGCTAB_ArrayLength Rtl8192DUAGCTAB_ArrayLength ++ #define Rtl8192D_PHY_REG_2TArrayLength Rtl8192DUPHY_REG_2TArrayLength ++ #define Rtl8192D_PHY_REG_1TArrayLength Rtl8192DUPHY_REG_1TArrayLength ++ #define Rtl8192D_PHY_REG_Array_PGLength Rtl8192DUPHY_REG_Array_PGLength ++ #define Rtl8192D_PHY_REG_Array_MPLength Rtl8192DUPHY_REG_Array_MPLength ++ #define Rtl8192D_RadioA_2TArrayLength Rtl8192DURadioA_2TArrayLength ++ #define Rtl8192D_RadioB_2TArrayLength Rtl8192DURadioB_2TArrayLength ++ #define Rtl8192D_RadioA_2T_intPAArrayLength Rtl8192DURadioA_2T_intPAArrayLength ++ #define Rtl8192D_RadioB_2T_intPAArrayLength Rtl8192DURadioB_2T_intPAArrayLength ++ ++ // The file name "_2T" is for 92CU, "_1T" is for 88CU. Modified by tynli. 2009.11.24. ++/* #define Rtl819XFwImageArray Rtl8192DUFwImgArray ++ #define Rtl819XMAC_Array Rtl8192DUMAC_2TArray ++ #define Rtl819XAGCTAB_Array Rtl8192DUAGCTAB_Array ++ #define Rtl819XAGCTAB_5GArray Rtl8192DUAGCTAB_5GArray ++ #define Rtl819XAGCTAB_2GArray Rtl8192DUAGCTAB_2GArray ++ #define Rtl819XPHY_REG_2TArray Rtl8192DUPHY_REG_2TArray ++ #define Rtl819XPHY_REG_1TArray Rtl8192DUPHY_REG_1TArray ++ #define Rtl819XRadioA_2TArray Rtl8192DURadioA_2TArray ++ #define Rtl819XRadioA_1TArray Rtl8192DURadioA_1TArray ++ #define Rtl819XRadioA_2T_intPAArray Rtl8192DURadioA_2T_intPAArray ++ #define Rtl819XRadioB_2TArray Rtl8192DURadioB_2TArray ++ #define Rtl819XRadioB_1TArray Rtl8192DURadioB_1TArray ++ #define Rtl819XRadioB_2T_intPAArray Rtl8192DURadioB_2T_intPAArray ++ #define Rtl819XPHY_REG_Array_PG Rtl8192DUPHY_REG_Array_PG ++ #define Rtl819XPHY_REG_Array_MP Rtl8192DUPHY_REG_Array_MP ++ ++ #define Rtl819XAGCTAB_2TArray Rtl8192DUAGCTAB_2TArray ++ #define Rtl819XAGCTAB_1TArray Rtl8192DUAGCTAB_1TArray*/ ++ ++#endif ++ ++#define DRVINFO_SZ 4 // unit is 8bytes ++#define PageNum_128(_Len) (u32)(((_Len)>>7) + ((_Len)&0x7F ? 1:0)) ++ ++// ++// Check if FW header exists. We do not consider the lower 4 bits in this case. ++// By tynli. 2009.12.04. ++// ++#define IS_FW_HEADER_EXIST(_pFwHdr) ((le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x92C0 ||\ ++ (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x88C0 ||\ ++ (le16_to_cpu(_pFwHdr->Signature)&0xFFFF) == 0x92D0 ||\ ++ (le16_to_cpu(_pFwHdr->Signature)&0xFFFF) == 0x92D1 ||\ ++ (le16_to_cpu(_pFwHdr->Signature)&0xFFFF) == 0x92D2 ||\ ++ (le16_to_cpu(_pFwHdr->Signature)&0xFFFF) == 0x92D3 ) ++ ++#define FW_8192D_SIZE 0x8020 // Max FW len = 32k + 32(FW header length). ++#define FW_8192D_START_ADDRESS 0x1000 ++#define FW_8192D_END_ADDRESS 0x1FFF ++ ++#define MAX_PAGE_SIZE 4096 // @ page : 4k bytes ++ ++typedef enum _FIRMWARE_SOURCE{ ++ FW_SOURCE_IMG_FILE = 0, ++ FW_SOURCE_HEADER_FILE = 1, //from header file ++}FIRMWARE_SOURCE, *PFIRMWARE_SOURCE; ++ ++typedef struct _RT_FIRMWARE{ ++ FIRMWARE_SOURCE eFWSource; ++ u8* szFwBuffer; ++ u32 ulFwLength; ++}RT_FIRMWARE, *PRT_FIRMWARE, RT_FIRMWARE_92D, *PRT_FIRMWARE_92D; ++ ++// ++// This structure must be cared byte-ordering ++// ++// Added by tynli. 2009.12.04. ++typedef struct _RT_8192D_FIRMWARE_HDR {//8-byte alinment required ++ ++ //--- LONG WORD 0 ---- ++ u16 Signature; // 92C0: test chip; 92C, 88C0: test chip; 88C1: MP A-cut; 92C1: MP A-cut ++ u8 Category; // AP/NIC and USB/PCI ++ u8 Function; // Reserved for different FW function indcation, for further use when driver needs to download different FW in different conditions ++ u16 Version; // FW Version ++ u8 Subversion; // FW Subversion, default 0x00 ++ u8 Rsvd1; ++ ++ ++ //--- LONG WORD 1 ---- ++ u8 Month; // Release time Month field ++ u8 Date; // Release time Date field ++ u8 Hour; // Release time Hour field ++ u8 Minute; // Release time Minute field ++ u16 RamCodeSize; // The size of RAM code ++ u16 Rsvd2; ++ ++ //--- LONG WORD 2 ---- ++ u32 SvnIdx; // The SVN entry index ++ u32 Rsvd3; ++ ++ //--- LONG WORD 3 ---- ++ u32 Rsvd4; ++ u32 Rsvd5; ++ ++}RT_8192D_FIRMWARE_HDR, *PRT_8192D_FIRMWARE_HDR; ++ ++#define DRIVER_EARLY_INT_TIME 0x05 ++#define BCN_DMA_ATIME_INT_TIME 0x02 ++ ++typedef enum _BT_CoType{ ++ BT_2Wire = 0, ++ BT_ISSC_3Wire = 1, ++ BT_Accel = 2, ++ BT_CSR = 3, ++ BT_CSR_ENHAN = 4, ++ BT_RTL8756 = 5, ++} BT_CoType, *PBT_CoType; ++ ++typedef enum _BT_CurState{ ++ BT_OFF = 0, ++ BT_ON = 1, ++} BT_CurState, *PBT_CurState; ++ ++typedef enum _BT_ServiceType{ ++ BT_SCO = 0, ++ BT_A2DP = 1, ++ BT_HID = 2, ++ BT_HID_Idle = 3, ++ BT_Scan = 4, ++ BT_Idle = 5, ++ BT_OtherAction = 6, ++ BT_Busy = 7, ++ BT_OtherBusy = 8, ++} BT_ServiceType, *PBT_ServiceType; ++ ++typedef enum _BT_RadioShared{ ++ BT_Radio_Shared = 0, ++ BT_Radio_Individual = 1, ++} BT_RadioShared, *PBT_RadioShared; ++ ++typedef struct _BT_COEXIST_STR{ ++ u8 BluetoothCoexist; ++ u8 BT_Ant_Num; ++ u8 BT_CoexistType; ++ u8 BT_State; ++ u8 BT_CUR_State; //0:on, 1:off ++ u8 BT_Ant_isolation; //0:good, 1:bad ++ u8 BT_PapeCtrl; //0:SW, 1:SW/HW dynamic ++ u8 BT_Service; ++ u8 BT_RadioSharedType; ++ u8 Ratio_Tx; ++ u8 Ratio_PRI; ++}BT_COEXIST_STR, *PBT_COEXIST_STR; ++ ++ ++#ifdef CONFIG_USB_RX_AGGREGATION ++ ++typedef enum _USB_RX_AGG_MODE{ ++ USB_RX_AGG_DISABLE, ++ USB_RX_AGG_DMA, ++ USB_RX_AGG_USB, ++ USB_RX_AGG_DMA_USB ++}USB_RX_AGG_MODE; ++ ++#define MAX_RX_DMA_BUFFER_SIZE 10240 // 10K for 8192C RX DMA buffer ++ ++#endif ++ ++ ++#define TX_SELE_HQ BIT(0) // High Queue ++#define TX_SELE_LQ BIT(1) // Low Queue ++#define TX_SELE_NQ BIT(2) // Normal Queue ++ ++ ++// Note: We will divide number of page equally for each queue other than public queue! ++ ++#define TX_TOTAL_PAGE_NUMBER 0xF8 ++#define TX_PAGE_BOUNDARY (TX_TOTAL_PAGE_NUMBER + 1) ++ ++// For Normal Chip Setting ++// (HPQ + LPQ + NPQ + PUBQ) shall be TX_TOTAL_PAGE_NUMBER ++#define NORMAL_PAGE_NUM_PUBQ 0x56 ++ ++ ++// For Test Chip Setting ++// (HPQ + LPQ + PUBQ) shall be TX_TOTAL_PAGE_NUMBER ++#define TEST_PAGE_NUM_PUBQ 0x89 ++#define TX_TOTAL_PAGE_NUMBER_92D_DUAL_MAC 0x7A ++#define NORMAL_PAGE_NUM_PUBQ_92D_DUAL_MAC 0x5A ++#define NORMAL_PAGE_NUM_HPQ_92D_DUAL_MAC 0x10 ++#define NORMAL_PAGE_NUM_LPQ_92D_DUAL_MAC 0x10 ++#define NORMAL_PAGE_NUM_NORMALQ_92D_DUAL_MAC 0 ++ ++#define TX_PAGE_BOUNDARY_DUAL_MAC (TX_TOTAL_PAGE_NUMBER_92D_DUAL_MAC + 1) ++ ++// For Test Chip Setting ++#define WMM_TEST_TX_TOTAL_PAGE_NUMBER 0xF5 ++#define WMM_TEST_TX_PAGE_BOUNDARY (WMM_TEST_TX_TOTAL_PAGE_NUMBER + 1) //F6 ++ ++#define WMM_TEST_PAGE_NUM_PUBQ 0xA3 ++#define WMM_TEST_PAGE_NUM_HPQ 0x29 ++#define WMM_TEST_PAGE_NUM_LPQ 0x29 ++ ++ ++//Note: For Normal Chip Setting ,modify later ++#define WMM_NORMAL_TX_TOTAL_PAGE_NUMBER 0xF5 ++#define WMM_NORMAL_TX_PAGE_BOUNDARY (WMM_TEST_TX_TOTAL_PAGE_NUMBER + 1) //F6 ++ ++#define WMM_NORMAL_PAGE_NUM_PUBQ 0xB0 ++#define WMM_NORMAL_PAGE_NUM_HPQ 0x29 ++#define WMM_NORMAL_PAGE_NUM_LPQ 0x1C ++#define WMM_NORMAL_PAGE_NUM_NPQ 0x1C ++ ++#define WMM_NORMAL_PAGE_NUM_PUBQ_92D 0X65//0x82 ++#define WMM_NORMAL_PAGE_NUM_HPQ_92D 0X30//0x29 ++#define WMM_NORMAL_PAGE_NUM_LPQ_92D 0X30 ++#define WMM_NORMAL_PAGE_NUM_NPQ_92D 0X30 ++ ++//------------------------------------------------------------------------- ++// Chip specific ++//------------------------------------------------------------------------- ++ ++#define CHIP_BONDING_IDENTIFIER(_value) (((_value)>>22)&0x3) ++#define CHIP_BONDING_92C_1T2R 0x1 ++#define CHIP_BONDING_88C_USB_MCARD 0x2 ++#define CHIP_BONDING_88C_USB_HP 0x1 ++ ++#include "HalVerDef.h" ++#include "hal_com.h" ++ ++//------------------------------------------------------------------------- ++// Channel Plan ++//------------------------------------------------------------------------- ++enum ChannelPlan{ ++ CHPL_FCC = 0, ++ CHPL_IC = 1, ++ CHPL_ETSI = 2, ++ CHPL_SPAIN = 3, ++ CHPL_FRANCE = 4, ++ CHPL_MKK = 5, ++ CHPL_MKK1 = 6, ++ CHPL_ISRAEL = 7, ++ CHPL_TELEC = 8, ++ CHPL_GLOBAL = 9, ++ CHPL_WORLD = 10, ++}; ++ ++typedef struct _TxPowerInfo{ ++ u8 CCKIndex[RF_PATH_MAX][CHANNEL_GROUP_MAX]; ++ u8 HT40_1SIndex[RF_PATH_MAX][CHANNEL_GROUP_MAX]; ++ u8 HT40_2SIndexDiff[RF_PATH_MAX][CHANNEL_GROUP_MAX]; ++ s8 HT20IndexDiff[RF_PATH_MAX][CHANNEL_GROUP_MAX]; ++ u8 OFDMIndexDiff[RF_PATH_MAX][CHANNEL_GROUP_MAX]; ++ u8 HT40MaxOffset[RF_PATH_MAX][CHANNEL_GROUP_MAX]; ++ u8 HT20MaxOffset[RF_PATH_MAX][CHANNEL_GROUP_MAX]; ++ u8 TSSI_A[3]; ++ u8 TSSI_B[3]; ++ u8 TSSI_A_5G[3]; //5GL/5GM/5GH ++ u8 TSSI_B_5G[3]; ++}TxPowerInfo, *PTxPowerInfo; ++ ++#define EFUSE_REAL_CONTENT_LEN 1024 ++#define EFUSE_MAP_LEN 256 ++#define EFUSE_MAX_SECTION 32 ++#define EFUSE_MAX_SECTION_BASE 16 ++// To prevent out of boundary programming case, leave 1byte and program full section ++// 9bytes + 1byt + 5bytes and pre 1byte. ++// For worst case: ++// | 2byte|----8bytes----|1byte|--7bytes--| //92D ++#define EFUSE_OOB_PROTECT_BYTES 18 // PG data exclude header, dummy 7 bytes frome CP test and reserved 1byte. ++ ++typedef enum _PA_MODE { ++ PA_MODE_EXTERNAL = 0x00, ++ PA_MODE_INTERNAL_SP3T = 0x01, ++ PA_MODE_INTERNAL_SPDT = 0x02 ++} PA_MODE; ++ ++/* Copy from rtl8192c */ ++enum c2h_id_8192d { ++ C2H_DBG = 0, ++ C2H_TSF = 1, ++ C2H_AP_RPT_RSP = 2, ++ C2H_CCX_TX_RPT = 3, ++ C2H_BT_RSSI = 4, ++ C2H_BT_OP_MODE = 5, ++ C2H_EXT_RA_RPT = 6, ++ C2H_HW_INFO_EXCH = 10, ++ C2H_C2H_H2C_TEST = 11, ++ C2H_BT_INFO = 12, ++ C2H_BT_MP_INFO = 15, ++ MAX_C2HEVENT ++}; ++ ++#ifdef CONFIG_PCI_HCI ++struct hal_data_8192de ++{ ++ HAL_VERSION VersionID; ++ // add for 92D Phy mode/mac/Band mode ++ MACPHY_MODE_8192D MacPhyMode92D; ++ BAND_TYPE CurrentBandType92D; //0:2.4G, 1:5G ++ BAND_TYPE BandSet92D; ++ BOOLEAN bIsVS; ++ BOOLEAN bSupportRemoteWakeUp; ++ u8 AutoLoadStatusFor8192D; ++ ++ BOOLEAN bNOPG; ++ ++ BOOLEAN bMasterOfDMSP; ++ BOOLEAN bSlaveOfDMSP; ++ ++ u16 CustomerID; ++ ++ u16 FirmwareVersion; ++ u16 FirmwareVersionRev; ++ u16 FirmwareSubVersion; ++ ++ u32 IntrMask[2]; ++ u32 IntrMaskToSet[2]; ++ ++ u32 DisabledFunctions; ++ ++ //current WIFI_PHY values ++ u32 ReceiveConfig; ++ u32 TransmitConfig; ++ WIRELESS_MODE CurrentWirelessMode; ++ HT_CHANNEL_WIDTH CurrentChannelBW; ++ u8 CurrentChannel; ++ u8 nCur40MhzPrimeSC;// Control channel sub-carrier ++ u16 BasicRateSet; ++ ++ //rf_ctrl ++ u8 rf_chip; ++ u8 rf_type; ++ u8 NumTotalRFPath; ++ ++ // ++ // EEPROM setting. ++ // ++ u16 EEPROMVID; ++ u16 EEPROMDID; ++ u16 EEPROMSVID; ++ u16 EEPROMSMID; ++ u16 EEPROMChannelPlan; ++ u16 EEPROMVersion; ++ ++ u8 EEPROMCustomerID; ++ u8 EEPROMBoardType; ++ u8 EEPROMRegulatory; ++ ++ u8 EEPROMThermalMeter; ++ ++ u8 EEPROMC9; ++ u8 EEPROMCC; ++ u8 PAMode; ++ ++ u8 TxPwrLevelCck[RF_PATH_MAX][CHANNEL_MAX_NUMBER_2G]; ++ u8 TxPwrLevelHT40_1S[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; // For HT 40MHZ pwr ++ u8 TxPwrLevelHT40_2S[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; // For HT 40MHZ pwr ++ s8 TxPwrHt20Diff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];// HT 20<->40 Pwr diff ++ u8 TxPwrLegacyHtDiff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];// For HT<->legacy pwr diff ++ // For power group ++ u8 PwrGroupHT20[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ u8 PwrGroupHT40[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ ++ u8 LegacyHTTxPowerDiff;// Legacy to HT rate power diff ++ ++ u8 CrystalCap; // CrystalCap. ++ ++#ifdef CONFIG_BT_COEXIST ++ struct btcoexist_priv bt_coexist; ++#endif ++ ++ // Read/write are allow for following hardware information variables ++ u8 framesync; ++ u32 framesyncC34; ++ u8 framesyncMonitor; ++ u8 DefaultInitialGain[4]; ++ u8 pwrGroupCnt; ++ u32 MCSTxPowerLevelOriginalOffset[MAX_PG_GROUP][16]; ++ u32 CCKTxPowerLevelOriginalOffset; ++ ++ u32 AntennaTxPath; // Antenna path Tx ++ u32 AntennaRxPath; // Antenna path Rx ++ u8 BluetoothCoexist; ++ u8 ExternalPA; ++ u8 InternalPA5G[2]; //pathA / pathB ++ ++ //u32 LedControlNum; ++ //u32 LedControlMode; ++ //u32 TxPowerTrackControl; ++ u8 b1x1RecvCombine; // for 1T1R receive combining ++ ++ u32 AcParam_BE; //Original parameter for BE, use for EDCA turbo. ++ ++ //vivi, for tx power tracking, 20080407 ++ //u16 TSSI_13dBm; ++ //u32 Pwr_Track; ++ // The current Tx Power Level ++ u8 CurrentCckTxPwrIdx; ++ u8 CurrentOfdm24GTxPwrIdx; ++ ++ BB_REGISTER_DEFINITION_T PHYRegDef[4]; //Radio A/B/C/D ++ ++ u32 RfRegChnlVal[2]; ++ ++ ++ BOOLEAN bPhyValueInitReady; ++ ++ BOOLEAN bTXPowerDataReadFromEEPORM; ++ ++ BOOLEAN bInSetPower; ++ ++ //RDG enable ++ BOOLEAN bRDGEnable; ++ ++ BOOLEAN bLoadIMRandIQKSettingFor2G;// True if IMR or IQK have done for 2.4G in scan progress ++ BOOLEAN bNeedIQK; ++ ++ BOOLEAN bLCKInProgress; ++ ++ BOOLEAN bEarlyModeEnable; ++ ++#if 1 ++ IQK_MATRIX_REGS_SETTING IQKMatrixRegSetting[IQK_Matrix_Settings_NUM]; ++#else ++ //regc80¡¢regc94¡¢regc4c¡¢regc88¡¢regc9c¡¢regc14¡¢regca0¡¢regc1c¡¢regc78 ++ u4Byte IQKMatrixReg[IQK_Matrix_REG_NUM]; ++ IQK_MATRIX_REGS_SETTING IQKMatrixRegSetting[IQK_Matrix_Settings_NUM]; // 1->2G,24->5G 20M channel,21->5G 40M channel. ++#endif ++ ++ //for host message to fw ++ u8 LastHMEBoxNum; ++ ++ u8 fw_ractrl; ++ // Beacon function related global variable. ++ u32 RegBcnCtrlVal; ++ u8 RegTxPause; ++ u8 RegFwHwTxQCtrl; ++ u8 RegReg542; ++ u8 RegCR_1; ++ ++ struct dm_priv dmpriv; ++ DM_ODM_T odmpriv; ++ //_lock odm_stainfo_lock; ++ u8 bInterruptMigration; ++ ++ u8 FwRsvdPageStartOffset; //2010.06.23. Added by tynli. Reserve page start offset except beacon in TxQ. ++ ++ // Add for dual MAC 0--Mac0 1--Mac1 ++ u32 interfaceIndex; ++ ++ u16 RegRRSR; ++ ++ u16 EfuseUsedBytes; ++ ++ BOOLEAN EepromOrEfuse; ++ u8 EfuseMap[2][HWSET_MAX_SIZE_512]; //92C:256bytes, 88E:512bytes, we use union set (512bytes) ++ u8 EfuseUsedPercentage; ++ EFUSE_HAL EfuseHal; ++ ++ u8 RTSInitRate; // 2010.11.24.by tynli. ++#ifdef CONFIG_P2P ++ struct P2P_PS_Offload_t p2p_ps_offload; ++#endif //CONFIG_P2P ++}; ++ ++typedef struct hal_data_8192de HAL_DATA_TYPE, *PHAL_DATA_TYPE; ++ ++// ++// Function disabled. ++// ++#define DF_TX_BIT BIT0 ++#define DF_RX_BIT BIT1 ++#define DF_IO_BIT BIT2 ++#define DF_IO_D3_BIT BIT3 ++ ++#define RT_DF_TYPE u32 ++#define RT_DISABLE_FUNC(__pAdapter, __FuncBits) ((__pAdapter)->DisabledFunctions |= ((RT_DF_TYPE)(__FuncBits))) ++#define RT_ENABLE_FUNC(__pAdapter, __FuncBits) ((__pAdapter)->DisabledFunctions &= (~((RT_DF_TYPE)(__FuncBits)))) ++#define RT_IS_FUNC_DISABLED(__pAdapter, __FuncBits) ( (__pAdapter)->DisabledFunctions & (__FuncBits) ) ++ ++void InterruptRecognized8192DE(PADAPTER Adapter, PRT_ISR_CONTENT pIsrContent); ++VOID UpdateInterruptMask8192DE(PADAPTER Adapter, u32 AddMSR, u32 RemoveMSR); ++#endif ++ ++#ifdef CONFIG_USB_HCI ++ ++//should be renamed and moved to another file ++typedef enum _INTERFACE_SELECT_8192DUSB{ ++ INTF_SEL0_USB = 0, // USB ++ INTF_SEL1_MINICARD = 1, // Minicard ++ INTF_SEL2_EKB_PRO = 2, // Eee keyboard proprietary ++ INTF_SEL3_PRO = 3, // Customized proprietary ++} INTERFACE_SELECT_8192DUSB, *PINTERFACE_SELECT_8192DUSB; ++ ++typedef INTERFACE_SELECT_8192DUSB INTERFACE_SELECT_USB; ++ ++struct hal_data_8192du ++{ ++ HAL_VERSION VersionID; ++ ++ // add for 92D Phy mode/mac/Band mode ++ MACPHY_MODE_8192D MacPhyMode92D; ++ BAND_TYPE CurrentBandType92D; //0:2.4G, 1:5G ++ BAND_TYPE BandSet92D; ++ BOOLEAN bIsVS; ++ ++ BOOLEAN bNOPG; ++ ++ BOOLEAN bSupportRemoteWakeUp; ++ BOOLEAN bMasterOfDMSP; ++ BOOLEAN bSlaveOfDMSP; ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ BOOLEAN bInModeSwitchProcess; ++#endif ++ ++ u16 CustomerID; ++ ++ u16 FirmwareVersion; ++ u16 FirmwareVersionRev; ++ u16 FirmwareSubVersion; ++ ++ //current WIFI_PHY values ++ u32 ReceiveConfig; ++ WIRELESS_MODE CurrentWirelessMode; ++ HT_CHANNEL_WIDTH CurrentChannelBW; ++ u8 CurrentChannel; ++ u8 nCur40MhzPrimeSC;// Control channel sub-carrier ++ u16 BasicRateSet; ++ ++ INTERFACE_SELECT_8192DUSB InterfaceSel; ++ ++ //rf_ctrl ++ u8 rf_chip; ++ u8 rf_type; ++ u8 NumTotalRFPath; ++ ++ // ++ // EEPROM setting. ++ // ++ u8 EEPROMVersion; ++ u16 EEPROMVID; ++ u16 EEPROMPID; ++ u16 EEPROMSVID; ++ u16 EEPROMSDID; ++ u8 EEPROMCustomerID; ++ u8 EEPROMSubCustomerID; ++ u8 EEPROMRegulatory; ++ ++ u8 EEPROMThermalMeter; ++ ++ u8 EEPROMC9; ++ u8 EEPROMCC; ++ u8 PAMode; ++ ++ u8 TxPwrLevelCck[RF_PATH_MAX][CHANNEL_MAX_NUMBER_2G]; ++ u8 TxPwrLevelHT40_1S[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; // For HT 40MHZ pwr ++ u8 TxPwrLevelHT40_2S[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; // For HT 40MHZ pwr ++ s8 TxPwrHt20Diff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];// HT 20<->40 Pwr diff ++ u8 TxPwrLegacyHtDiff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];// For HT<->legacy pwr diff ++ // For power group ++ u8 PwrGroupHT20[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ u8 PwrGroupHT40[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ ++ u8 LegacyHTTxPowerDiff;// Legacy to HT rate power diff ++ ++ u8 CrystalCap; // CrystalCap. ++ ++#ifdef CONFIG_BT_COEXIST ++ struct btcoexist_priv bt_coexist; ++#endif ++ ++ // Read/write are allow for following hardware information variables ++ u8 framesync; ++ u32 framesyncC34; ++ u8 framesyncMonitor; ++ u8 DefaultInitialGain[4]; ++ u8 pwrGroupCnt; ++ u32 MCSTxPowerLevelOriginalOffset[MAX_PG_GROUP][16]; ++ u32 CCKTxPowerLevelOriginalOffset; ++ ++ u32 AntennaTxPath; // Antenna path Tx ++ u32 AntennaRxPath; // Antenna path Rx ++ u8 BluetoothCoexist; ++ u8 ExternalPA; ++ u8 InternalPA5G[2]; //pathA / pathB ++ ++ //u32 LedControlNum; ++ //u32 LedControlMode; ++ //u32 TxPowerTrackControl; ++ u8 b1x1RecvCombine; // for 1T1R receive combining ++ ++ u32 AcParam_BE; //Original parameter for BE, use for EDCA turbo. ++ ++ //vivi, for tx power tracking, 20080407 ++ //u16 TSSI_13dBm; ++ //u32 Pwr_Track; ++ // The current Tx Power Level ++ u8 CurrentCckTxPwrIdx; ++ u8 CurrentOfdm24GTxPwrIdx; ++ ++ BB_REGISTER_DEFINITION_T PHYRegDef[4]; //Radio A/B/C/D ++ ++ ++ u32 RfRegChnlVal[2]; ++ ++ ++ BOOLEAN bPhyValueInitReady; ++ ++ BOOLEAN bTXPowerDataReadFromEEPORM; ++ ++ BOOLEAN bInSetPower; ++ ++ //RDG enable ++ BOOLEAN bRDGEnable; ++ ++ BOOLEAN bLoadIMRandIQKSettingFor2G;// True if IMR or IQK have done for 2.4G in scan progress ++ BOOLEAN bNeedIQK; ++ ++ BOOLEAN bLCKInProgress; ++ ++ BOOLEAN bEarlyModeEnable; ++ ++#if 1 ++ IQK_MATRIX_REGS_SETTING IQKMatrixRegSetting[IQK_Matrix_Settings_NUM]; ++#else ++ //regc80¡¢regc94¡¢regc4c¡¢regc88¡¢regc9c¡¢regc14¡¢regca0¡¢regc1c¡¢regc78 ++ u4Byte IQKMatrixReg[IQK_Matrix_REG_NUM]; ++ IQK_MATRIX_REGS_SETTING IQKMatrixRegSetting[IQK_Matrix_Settings_NUM]; // 1->2G,24->5G 20M channel,21->5G 40M channel. ++#endif ++ ++ //for host message to fw ++ u8 LastHMEBoxNum; ++ ++ u8 fw_ractrl; ++ // Beacon function related global variable. ++ u32 RegBcnCtrlVal; ++ u8 RegTxPause; ++ u8 RegFwHwTxQCtrl; ++ u8 RegReg542; ++ u8 RegCR_1; ++ ++ struct dm_priv dmpriv; ++ DM_ODM_T odmpriv; ++ //_lock odm_stainfo_lock; ++ u8 FwRsvdPageStartOffset; //2010.06.23. Added by tynli. Reserve page start offset except beacon in TxQ. ++ ++ //Query RF by FW ++ BOOLEAN bReadRFbyFW; ++ ++ // For 92C USB endpoint setting ++ // ++ ++ u32 UsbBulkOutSize; ++ ++ // Add for dual MAC 0--Mac0 1--Mac1 ++ u32 interfaceIndex; ++ ++ u8 OutEpQueueSel; ++ u8 OutEpNumber; ++ ++#ifdef CONFIG_USB_TX_AGGREGATION ++ u8 UsbTxAggMode; ++ u8 UsbTxAggDescNum; ++#endif ++#ifdef CONFIG_USB_RX_AGGREGATION ++ u16 HwRxPageSize; // Hardware setting ++ u32 MaxUsbRxAggBlock; ++ ++ USB_RX_AGG_MODE UsbRxAggMode; ++ u8 UsbRxAggBlockCount; // USB Block count. Block size is 512-byte in hight speed and 64-byte in full speed ++ u8 UsbRxAggBlockTimeout; ++ u8 UsbRxAggPageCount; // 8192C DMA page count ++ u8 UsbRxAggPageTimeout; ++#endif ++ ++ u16 RegRRSR; ++ ++ u16 EfuseUsedBytes; ++ ++ BOOLEAN EepromOrEfuse; ++ u8 EfuseMap[2][HWSET_MAX_SIZE_512]; //92C:256bytes, 88E:512bytes, we use union set (512bytes) ++ u8 EfuseUsedPercentage; ++ EFUSE_HAL EfuseHal; ++ ++ u8 RTSInitRate; // 2010.11.24.by tynli. ++#ifdef CONFIG_P2P ++ struct P2P_PS_Offload_t p2p_ps_offload; ++#endif //CONFIG_P2P ++}; ++ ++typedef struct hal_data_8192du HAL_DATA_TYPE, *PHAL_DATA_TYPE; ++#endif ++ ++#define GET_HAL_DATA(__pAdapter) ((HAL_DATA_TYPE *)((__pAdapter)->HalData)) ++#define GET_RF_TYPE(priv) (GET_HAL_DATA(priv)->rf_type) ++ ++int FirmwareDownload92D(IN PADAPTER Adapter); ++VOID rtl8192d_FirmwareSelfReset(IN PADAPTER Adapter); ++void rtl8192d_ReadChipVersion(IN PADAPTER Adapter); ++VOID rtl8192d_EfuseParseChnlPlan(PADAPTER Adapter, u8 *hwinfo, BOOLEAN AutoLoadFail); ++VOID rtl8192d_ReadTxPowerInfo(PADAPTER Adapter, u8* PROMContent, BOOLEAN AutoLoadFail); ++VOID rtl8192d_ResetDualMacSwitchVariables(IN PADAPTER Adapter); ++u8 GetEEPROMSize8192D(PADAPTER Adapter); ++BOOLEAN PHY_CheckPowerOffFor8192D(PADAPTER Adapter); ++VOID PHY_SetPowerOnFor8192D(PADAPTER Adapter); ++//void PHY_ConfigMacPhyMode92D(PADAPTER Adapter); ++void rtl8192d_free_hal_data(_adapter * padapter); ++void rtl8192d_set_hal_ops(struct hal_ops *pHalFunc); ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_led.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_led.h +new file mode 100644 +index 00000000..c75df2ef +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_led.h +@@ -0,0 +1,43 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8192D_LED_H_ ++#define __RTL8192D_LED_H_ ++ ++#include ++#include ++#include ++ ++ ++//================================================================================ ++// Interface to manipulate LED objects. ++//================================================================================ ++#ifdef CONFIG_USB_HCI ++void rtl8192du_InitSwLeds(_adapter *padapter); ++void rtl8192du_DeInitSwLeds(_adapter *padapter); ++#endif ++ ++#ifdef CONFIG_PCI_HCI ++void rtl8192de_gen_RefreshLedState(PADAPTER Adapter); ++void rtl8192de_InitSwLeds(_adapter *padapter); ++void rtl8192de_DeInitSwLeds(_adapter *padapter); ++#endif ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_recv.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_recv.h +new file mode 100644 +index 00000000..5ffec395 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_recv.h +@@ -0,0 +1,139 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTL8192D_RECV_H_ ++#define _RTL8192D_RECV_H_ ++ ++#include ++#include ++#include ++ ++ ++#ifdef PLATFORM_OS_XP ++ #ifdef CONFIG_SDIO_HCI ++ #define NR_RECVBUFF 1024//512//128 ++ #else ++ #define NR_RECVBUFF (16) ++ #endif ++#elif defined(PLATFORM_OS_CE) ++ #ifdef CONFIG_SDIO_HCI ++ #define NR_RECVBUFF (128) ++ #else ++ #define NR_RECVBUFF (4) ++ #endif ++#else ++#ifdef CONFIG_SINGLE_RECV_BUF ++ #define NR_RECVBUFF (1) ++#else ++ #define NR_RECVBUFF (4) ++#endif //CONFIG_SINGLE_RECV_BUF ++ #define NR_PREALLOC_RECV_SKB (8) ++#endif ++ ++ ++ ++#define RECV_BLK_SZ 512 ++#define RECV_BLK_CNT 16 ++#define RECV_BLK_TH RECV_BLK_CNT ++ ++#if defined(CONFIG_USB_HCI) ++ ++#ifdef PLATFORM_OS_CE ++#define MAX_RECVBUF_SZ (8192+1024) // 8K+1k ++#else ++ #ifndef CONFIG_MINIMAL_MEMORY_USAGE ++ //#define MAX_RECVBUF_SZ (32768) // 32k ++ //#define MAX_RECVBUF_SZ (16384) //16K ++ //#define MAX_RECVBUF_SZ (10240) //10K ++ #ifdef CONFIG_PLATFORM_MSTAR ++ #define MAX_RECVBUF_SZ (8192) // 8K ++ #else ++ #define MAX_RECVBUF_SZ (15360) // 15k < 16k ++ #endif ++ #else ++ #define MAX_RECVBUF_SZ (4000) // about 4K ++ #endif ++#endif ++ ++#elif defined(CONFIG_PCI_HCI) ++//#ifndef CONFIG_MINIMAL_MEMORY_USAGE ++// #define MAX_RECVBUF_SZ (9100) ++//#else ++ #define MAX_RECVBUF_SZ (4000) // about 4K ++//#endif ++ ++#define RX_MPDU_QUEUE 0 ++#define RX_CMD_QUEUE 1 ++#define RX_MAX_QUEUE 2 ++#endif ++ ++#define RECV_BULK_IN_ADDR 0x80 ++#define RECV_INT_IN_ADDR 0x81 ++ ++#define PHY_RSSI_SLID_WIN_MAX 100 ++#define PHY_LINKQUALITY_SLID_WIN_MAX 20 ++ ++struct phy_stat ++{ ++ unsigned int phydw0; ++ ++ unsigned int phydw1; ++ ++ unsigned int phydw2; ++ ++ unsigned int phydw3; ++ ++ unsigned int phydw4; ++ ++ unsigned int phydw5; ++ ++ unsigned int phydw6; ++ ++ unsigned int phydw7; ++}; ++ ++// Rx smooth factor ++#define Rx_Smooth_Factor (20) ++ ++#ifdef CONFIG_USB_HCI ++typedef struct _INTERRUPT_MSG_FORMAT_EX{ ++ unsigned int C2H_MSG0; ++ unsigned int C2H_MSG1; ++ unsigned int C2H_MSG2; ++ unsigned int C2H_MSG3; ++ unsigned int HISR; // from HISR Reg0x124, read to clear ++ unsigned int HISRE;// from HISRE Reg0x12c, read to clear ++ unsigned int MSG_EX; ++}INTERRUPT_MSG_FORMAT_EX,*PINTERRUPT_MSG_FORMAT_EX; ++ ++void rtl8192du_init_recvbuf(_adapter *padapter, struct recv_buf *precvbuf); ++int rtl8192du_init_recv_priv(_adapter * padapter); ++void rtl8192du_free_recv_priv(_adapter * padapter); ++#endif ++ ++#ifdef CONFIG_PCI_HCI ++int rtl8192de_init_recv_priv(_adapter * padapter); ++void rtl8192de_free_recv_priv(_adapter * padapter); ++#endif ++ ++void rtl8192d_translate_rx_signal_stuff(union recv_frame *precvframe, struct phy_stat *pphy_status); ++void rtl8192d_query_rx_desc_status(union recv_frame *precvframe, struct recv_stat *pdesc); ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_rf.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_rf.h +new file mode 100644 +index 00000000..8fc17e25 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_rf.h +@@ -0,0 +1,97 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++/****************************************************************************** ++ * ++ * ++ * Module: rtl8192d_rf.h ( Header File) ++ * ++ * Note: Collect every HAL RF type exter API or constant. ++ * ++ * Function: ++ * ++ * Export: ++ * ++ * Abbrev: ++ * ++ * History: ++ * Data Who Remark ++ * ++ * 09/25/2008 MHC Create initial version. ++ * ++ * ++******************************************************************************/ ++#ifndef _RTL8192D_RF_H_ ++#define _RTL8192D_RF_H_ ++/* Check to see if the file has been included already. */ ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++// ++// For RF 6052 Series ++// ++#define RF6052_MAX_TX_PWR 0x3F ++#define RF6052_MAX_REG 0x3F ++#define RF6052_MAX_PATH 2 ++/*--------------------------Define Parameters-------------------------------*/ ++ ++ ++/*------------------------------Define structure----------------------------*/ ++ ++/*------------------------------Define structure----------------------------*/ ++ ++ ++/*------------------------Export global variable----------------------------*/ ++/*------------------------Export global variable----------------------------*/ ++ ++/*------------------------Export Marco Definition---------------------------*/ ++ ++/*------------------------Export Marco Definition---------------------------*/ ++ ++ ++/*--------------------------Exported Function prototype---------------------*/ ++ ++// ++// RF RL6052 Series API ++// ++void rtl8192d_RF_ChangeTxPath( IN PADAPTER Adapter, ++ IN u16 DataRate); ++void rtl8192d_PHY_RF6052SetBandwidth( ++ IN PADAPTER Adapter, ++ IN HT_CHANNEL_WIDTH Bandwidth); ++VOID rtl8192d_PHY_RF6052SetCckTxPower( ++ IN PADAPTER Adapter, ++ IN u8* pPowerlevel); ++VOID rtl8192d_PHY_RF6052SetOFDMTxPower( ++ IN PADAPTER Adapter, ++ IN u8* pPowerLevel, ++ IN u8 Channel); ++int PHY_RF6052_Config8192D( IN PADAPTER Adapter ); ++ ++BOOLEAN rtl8192d_PHY_EnableAnotherPHY(IN PADAPTER Adapter, IN BOOLEAN bMac0); ++ ++void rtl8192d_PHY_PowerDownAnotherPHY(IN PADAPTER Adapter, IN BOOLEAN bMac0); ++ ++ ++/*--------------------------Exported Function prototype---------------------*/ ++ ++ ++#endif/* End of HalRf.h */ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_spec.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_spec.h +new file mode 100644 +index 00000000..74e11d5a +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_spec.h +@@ -0,0 +1,1761 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#ifndef __RTL8192D_SPEC_H__ ++#define __RTL8192D_SPEC_H__ ++ ++#include ++ ++//============================================================ ++// 8192D Regsiter offset definition ++//============================================================ ++ ++ ++//============================================================ ++// ++//============================================================ ++ ++//----------------------------------------------------- ++// ++// 0x0000h ~ 0x00FFh System Configuration ++// ++//----------------------------------------------------- ++#define REG_SYS_ISO_CTRL 0x0000 ++#define REG_SYS_FUNC_EN 0x0002 ++#define REG_APS_FSMCO 0x0004 ++#define REG_SYS_CLKR 0x0008 ++#define REG_9346CR 0x000A ++#define REG_EE_VPD 0x000C ++#define REG_AFE_MISC 0x0010 ++#define REG_SPS0_CTRL 0x0011 ++#define REG_POWER_OFF_IN_PROCESS 0x0017 ++#define REG_SPS_OCP_CFG 0x0018 ++#define REG_RSV_CTRL 0x001C ++#define REG_RF_CTRL 0x001F ++#define REG_LDOA15_CTRL 0x0020 ++#define REG_LDOV12D_CTRL 0x0021 ++#define REG_LDOHCI12_CTRL 0x0022 ++#define REG_LPLDO_CTRL 0x0023 ++#define REG_AFE_XTAL_CTRL 0x0024 ++#define REG_AFE_PLL_CTRL 0x0028 ++#define REG_MAC_PHY_CTRL 0x002c //for 92d, DMDP,SMSP,DMSP contrl ++#define REG_EFUSE_CTRL 0x0030 ++#define REG_EFUSE_TEST 0x0034 ++#define REG_PWR_DATA 0x0038 ++#define REG_CAL_TIMER 0x003C ++#define REG_ACLK_MON 0x003E ++#define REG_GPIO_MUXCFG 0x0040 ++//#define REG_GPIO_MUXCFG 0x0041 ++#define REG_GPIO_IO_SEL 0x0042 ++#define REG_MAC_PINMUX_CFG 0x0043 ++#define REG_GPIO_PIN_CTRL 0x0044 ++#define REG_GPIO_INTM 0x0048 ++#define REG_LEDCFG0 0x004C ++#define REG_LEDCFG1 0x004D ++#define REG_LEDCFG2 0x004E ++#define REG_LEDCFG3 0x004F ++#define REG_FSIMR 0x0050 ++#define REG_FSISR 0x0054 ++ ++#define REG_MCUFWDL 0x0080 ++ ++#define REG_HMEBOX_EXT_0 0x0088 ++#define REG_HMEBOX_EXT_1 0x008A ++#define REG_HMEBOX_EXT_2 0x008C ++#define REG_HMEBOX_EXT_3 0x008E ++ ++#define REG_BIST_SCAN 0x00D0 ++#define REG_BIST_RPT 0x00D4 ++#define REG_BIST_ROM_RPT 0x00D8 ++#define REG_USB_SIE_INTF 0x00E0 ++#define REG_PCIE_MIO_INTF 0x00E4 ++#define REG_PCIE_MIO_INTD 0x00E8 ++#define REG_HPON_FSM 0x00EC ++#define REG_SYS_CFG 0x00F0 ++#define REG_MAC_PHY_CTRL_NORMAL 0x00f8 ++ ++#define REG_MAC0 0x0081 ++#define REG_MAC1 0x0053 ++#define FW_MAC0_ready 0x18 ++#define FW_MAC1_ready 0x1A ++#define MAC0_ON BIT7 ++#define MAC1_ON BIT0 ++#define mac0_ready BIT0 ++#define mac1_ready BIT0 ++ ++ ++//----------------------------------------------------- ++// ++// 0x0100h ~ 0x01FFh MACTOP General Configuration ++// ++//----------------------------------------------------- ++#define REG_CR 0x0100 ++#define REG_PBP 0x0104 ++#define REG_TRXDMA_CTRL 0x010C ++#define REG_TRXFF_BNDY 0x0114 ++#define REG_TRXFF_STATUS 0x0118 ++#define REG_RXFF_PTR 0x011C ++#define REG_HIMR 0x0120 ++#define REG_HISR 0x0124 ++#define REG_HIMRE 0x0128 ++#define REG_HISRE 0x012C ++#define REG_CPWM 0x012F ++#define REG_FWIMR 0x0130 ++#define REG_FWISR 0x0134 ++#define REG_FTIMR 0x0138 ++#define REG_PKTBUF_DBG_CTRL 0x0140 ++#define REG_PKTBUF_DBG_DATA_L 0x0144 ++#define REG_PKTBUF_DBG_DATA_H 0x0148 ++ ++#define REG_TC0_CTRL 0x0150 ++#define REG_TC1_CTRL 0x0154 ++#define REG_TC2_CTRL 0x0158 ++#define REG_TC3_CTRL 0x015C ++#define REG_TC4_CTRL 0x0160 ++#define REG_TCUNIT_BASE 0x0164 ++#define REG_MBIST_START 0x0174 ++#define REG_MBIST_DONE 0x0178 ++#define REG_MBIST_FAIL 0x017C ++#define REG_C2HEVT_MSG_NORMAL 0x01A0 ++#define REG_C2HEVT_CLEAR 0x01AF ++#define REG_C2HEVT_MSG_TEST 0x01B8 ++#define REG_MCUTST_1 0x01c0 ++#define REG_FMETHR 0x01C8 ++#define REG_HMETFR 0x01CC ++#define REG_HMEBOX_0 0x01D0 ++#define REG_HMEBOX_1 0x01D4 ++#define REG_HMEBOX_2 0x01D8 ++#define REG_HMEBOX_3 0x01DC ++ ++#define REG_LLT_INIT 0x01E0 ++#define REG_BB_ACCEESS_CTRL 0x01E8 ++#define REG_BB_ACCESS_DATA 0x01EC ++ ++ ++//----------------------------------------------------- ++// ++// 0x0200h ~ 0x027Fh TXDMA Configuration ++// ++//----------------------------------------------------- ++#define REG_RQPN 0x0200 ++#define REG_FIFOPAGE 0x0204 ++#define REG_TDECTRL 0x0208 ++#define REG_TXDMA_OFFSET_CHK 0x020C ++#define REG_TXDMA_STATUS 0x0210 ++#define REG_RQPN_NPQ 0x0214 ++ ++//----------------------------------------------------- ++// ++// 0x0280h ~ 0x02FFh RXDMA Configuration ++// ++//----------------------------------------------------- ++#define REG_RXDMA_AGG_PG_TH 0x0280 ++#define REG_RXPKT_NUM 0x0284 ++#define REG_RXDMA_STATUS 0x0288 ++ ++ ++//----------------------------------------------------- ++// ++// 0x0300h ~ 0x03FFh PCIe ++// ++//----------------------------------------------------- ++#define REG_PCIE_CTRL_REG 0x0300 ++#define REG_INT_MIG 0x0304 // Interrupt Migration ++#define REG_BCNQ_DESA 0x0308 // TX Beacon Descriptor Address ++#define REG_HQ_DESA 0x0310 // TX High Queue Descriptor Address ++#define REG_MGQ_DESA 0x0318 // TX Manage Queue Descriptor Address ++#define REG_VOQ_DESA 0x0320 // TX VO Queue Descriptor Address ++#define REG_VIQ_DESA 0x0328 // TX VI Queue Descriptor Address ++#define REG_BEQ_DESA 0x0330 // TX BE Queue Descriptor Address ++#define REG_BKQ_DESA 0x0338 // TX BK Queue Descriptor Address ++#define REG_RX_DESA 0x0340 // RX Queue Descriptor Address ++#define REG_DBI 0x0348 // Backdoor REG for Access Configuration ++//sherry added for DBI Read/Write 20091126 ++#define REG_DBI_WDATA 0x0348 // Backdoor REG for Access Configuration ++#define REG_DBI_RDATA 0x034C //Backdoor REG for Access Configuration ++#define REG_DBI_CTRL 0x0350 //Backdoor REG for Access Configuration ++#define REG_DBI_FLAG 0x0352 //Backdoor REG for Access Configuration#define REG_MDIO 0x0354 // MDIO for Access PCIE PHY ++#define REG_MDIO 0x0354 // MDIO for Access PCIE PHY ++#define REG_DBG_SEL 0x0360 // Debug Selection Register ++#define REG_PCIE_HRPWM 0x0361 //PCIe RPWM ++#define REG_PCIE_HCPWM 0x0363 //PCIe CPWM ++#define REG_UART_CTRL 0x0364 // UART Control ++#define REG_UART_TX_DESA 0x0370 // UART TX Descriptor Address ++#define REG_UART_RX_DESA 0x0378 // UART Rx Descriptor Address ++ ++ ++// spec version 11 ++//----------------------------------------------------- ++// ++// 0x0400h ~ 0x047Fh Protocol Configuration ++// ++//----------------------------------------------------- ++#define REG_VOQ_INFORMATION 0x0400 ++#define REG_VIQ_INFORMATION 0x0404 ++#define REG_BEQ_INFORMATION 0x0408 ++#define REG_BKQ_INFORMATION 0x040C ++#define REG_MGQ_INFORMATION 0x0410 ++#define REG_HGQ_INFORMATION 0x0414 ++#define REG_BCNQ_INFORMATION 0x0418 ++ ++ ++#define REG_CPU_MGQ_INFORMATION 0x041C ++#define REG_FWHW_TXQ_CTRL 0x0420 ++#define REG_HWSEQ_CTRL 0x0423 ++#define REG_TXPKTBUF_BCNQ_BDNY 0x0424 ++#define REG_TXPKTBUF_MGQ_BDNY 0x0425 ++#define REG_LIFETIME_EN 0x0426 ++#define REG_MULTI_BCNQ_OFFSET 0x0427 ++#define REG_SPEC_SIFS 0x0428 ++#define REG_RL 0x042A ++#define REG_DARFRC 0x0430 ++#define REG_RARFRC 0x0438 ++#define REG_RRSR 0x0440 ++#define REG_ARFR0 0x0444 ++#define REG_ARFR1 0x0448 ++#define REG_ARFR2 0x044C ++#define REG_ARFR3 0x0450 ++#define REG_AGGLEN_LMT 0x0458 ++#define REG_AMPDU_MIN_SPACE 0x045C ++#define REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045D ++#define REG_FAST_EDCA_CTRL 0x0460 ++#define REG_RD_RESP_PKT_TH 0x0463 ++#define REG_INIRTS_RATE_SEL 0x0480 ++#define REG_INIDATA_RATE_SEL 0x0484 ++ ++#define REG_FW_TSF_SYNC_CNT 0x04A0 ++#define REG_FW_BCN_DIS_CNT 0x04A1 ++ ++#define REG_POWER_STATUS 0x04A4 ++#define REG_POWER_STAGE1 0x04B4 ++#define REG_POWER_STAGE2 0x04B8 ++#define REG_PKT_VO_VI_LIFE_TIME 0x04C0 ++#define REG_PKT_BE_BK_LIFE_TIME 0x04C2 ++#define REG_STBC_SETTING 0x04C4 ++#define REG_PROT_MODE_CTRL 0x04C8 ++#define REG_MAX_AGGR_NUM 0x04CA ++#define REG_RTS_MAX_AGGR_NUM 0x04CB ++#define REG_BAR_MODE_CTRL 0x04CC ++#define REG_RA_TRY_RATE_AGG_LMT 0x04CF ++#define REG_EARLY_MODE_CONTROL 0x04D0 ++#define REG_NQOS_SEQ 0x04DC ++#define REG_QOS_SEQ 0x04DE ++#define REG_NEED_CPU_HANDLE 0x04E0 ++#define REG_PKT_LOSE_RPT 0x04E1 ++#define REG_PTCL_ERR_STATUS 0x04E2 ++#define REG_DUMMY 0x04FC ++ ++ ++ ++//----------------------------------------------------- ++// ++// 0x0500h ~ 0x05FFh EDCA Configuration ++// ++//----------------------------------------------------- ++#define REG_EDCA_VO_PARAM 0x0500 ++#define REG_EDCA_VI_PARAM 0x0504 ++#define REG_EDCA_BE_PARAM 0x0508 ++#define REG_EDCA_BK_PARAM 0x050C ++#define REG_BCNTCFG 0x0510 ++#define REG_PIFS 0x0512 ++#define REG_RDG_PIFS 0x0513 ++#define REG_SIFS_CTX 0x0514 ++#define REG_SIFS_TRX 0x0516 ++#define REG_TSFTR_SYN_OFFSET 0x0518 ++#define REG_AGGR_BREAK_TIME 0x051A ++#define REG_SLOT 0x051B ++#define REG_TX_PTCL_CTRL 0x0520 ++#define REG_TXPAUSE 0x0522 ++#define REG_DIS_TXREQ_CLR 0x0523 ++#define REG_RD_CTRL 0x0524 ++#define REG_TBTT_PROHIBIT 0x0540 ++#define REG_RD_NAV_NXT 0x0544 ++#define REG_NAV_PROT_LEN 0x0546 ++#define REG_BCN_CTRL 0x0550 ++#define REG_BCN_CTRL_1 0x0551 ++#define REG_MBID_NUM 0x0552 ++#define REG_DUAL_TSF_RST 0x0553 ++#define REG_BCN_INTERVAL 0x0554 // The same as REG_MBSSID_BCN_SPACE ++#define REG_MBSSID_BCN_SPACE 0x0554 ++#define REG_DRVERLYINT 0x0558 ++#define REG_BCNDMATIM 0x0559 ++#define REG_ATIMWND 0x055A ++#define REG_USTIME_TSF 0x055C ++#define REG_BCN_MAX_ERR 0x055D ++#define REG_RXTSF_OFFSET_CCK 0x055E ++#define REG_RXTSF_OFFSET_OFDM 0x055F ++#define REG_TSFTR 0x0560 ++#define REG_TSFTR1 0x0568 ++#define REG_INIT_TSFTR 0x0564 ++#define REG_ATIMWND_1 0x0570 ++#define REG_PSTIMER 0x0580 ++#define REG_TIMER0 0x0584 ++#define REG_TIMER1 0x0588 ++#define REG_ACMHWCTRL 0x05C0 ++#define REG_ACMRSTCTRL 0x05C1 ++#define REG_ACMAVG 0x05C2 ++#define REG_VO_ADMTIME 0x05C4 ++#define REG_VI_ADMTIME 0x05C6 ++#define REG_BE_ADMTIME 0x05C8 ++#define REG_EDCA_RANDOM_GEN 0x05CC ++#define REG_SCH_TXCMD 0x05D0 ++ ++#define REG_DMC 0x05F0 //Dual MAC Co-Existence Register ++ ++ ++//----------------------------------------------------- ++// ++// 0x0600h ~ 0x07FFh WMAC Configuration ++// ++//----------------------------------------------------- ++#define REG_APSD_CTRL 0x0600 ++#define REG_BWOPMODE 0x0603 ++#define REG_TCR 0x0604 ++#define REG_RCR 0x0608 ++#define REG_RX_PKT_LIMIT 0x060C ++#define REG_RX_DLK_TIME 0x060D ++#define REG_RX_DRVINFO_SZ 0x060F ++ ++#define REG_MACID 0x0610 ++#define REG_BSSID 0x0618 ++#define REG_MAR 0x0620 ++#define REG_MBIDCAMCFG 0x0628 ++ ++#define REG_USTIME_EDCA 0x0638 ++#define REG_MAC_SPEC_SIFS 0x063A ++#define REG_RESP_SIFS_CCK 0x063C ++#define REG_RESP_SIFS_OFDM 0x063E ++#define REG_ACKTO 0x0640 ++#define REG_CTS2TO 0x0641 ++#define REG_EIFS 0x0642 ++ ++ ++//WMA, BA, CCX ++#define REG_NAV_CTRL 0x0650 ++#define REG_BACAMCMD 0x0654 ++#define REG_BACAMCONTENT 0x0658 ++#define REG_LBDLY 0x0660 ++#define REG_FWDLY 0x0661 ++#define REG_RXERR_RPT 0x0664 ++#define REG_WMAC_TRXPTCL_CTL 0x0668 ++ ++ ++// Security ++#define REG_CAMCMD 0x0670 ++#define REG_CAMWRITE 0x0674 ++#define REG_CAMREAD 0x0678 ++#define REG_CAMDBG 0x067C ++#define REG_SECCFG 0x0680 ++ ++// Power ++#define REG_WOW_CTRL 0x0690 ++#define REG_PSSTATUS 0x0691 ++#define REG_PS_RX_INFO 0x0692 ++#define REG_LPNAV_CTRL 0x0694 ++#define REG_WKFMCAM_CMD 0x0698 ++#define REG_WKFMCAM_RWD 0x069C ++#define REG_RXFLTMAP0 0x06A0 ++#define REG_RXFLTMAP1 0x06A2 ++#define REG_RXFLTMAP2 0x06A4 ++#define REG_BCN_PSR_RPT 0x06A8 ++#define REG_CALB32K_CTRL 0x06AC ++#define REG_PKT_MON_CTRL 0x06B4 ++#define REG_BT_COEX_TABLE 0x06C0 ++#define REG_WMAC_RESP_TXINFO 0x06D8 ++ ++#define REG_MACID1 0x0700 ++#define REG_BSSID1 0x0708 ++ ++//----------------------------------------------------- ++// ++// 0xFE00h ~ 0xFE55h USB Configuration ++// ++//----------------------------------------------------- ++#define REG_USB_INFO 0xFE17 ++#define REG_USB_SPECIAL_OPTION 0xFE55 ++#define REG_USB_DMA_AGG_TO 0xFE5B ++#define REG_USB_AGG_TO 0xFE5C ++#define REG_USB_AGG_TH 0xFE5D ++ ++// for 92DU high_Queue low_Queue Normal_Queue select ++#define REG_USB_High_NORMAL_Queue_Select_MAC0 0xFE44 ++//#define REG_USB_LOW_Queue_Select_MAC0 0xFE45 ++#define REG_USB_High_NORMAL_Queue_Select_MAC1 0xFE47 ++//#define REG_USB_LOW_Queue_Select_MAC1 0xFE48 ++ ++// For test chip ++#define REG_TEST_USB_TXQS 0xFE48 ++#define REG_TEST_SIE_VID 0xFE60 // 0xFE60~0xFE61 ++#define REG_TEST_SIE_PID 0xFE62 // 0xFE62~0xFE63 ++#define REG_TEST_SIE_OPTIONAL 0xFE64 ++#define REG_TEST_SIE_CHIRP_K 0xFE65 ++#define REG_TEST_SIE_PHY 0xFE66 // 0xFE66~0xFE6B ++#define REG_TEST_SIE_MAC_ADDR 0xFE70 // 0xFE70~0xFE75 ++#define REG_TEST_SIE_STRING 0xFE80 // 0xFE80~0xFEB9 ++ ++ ++// For normal chip ++#define REG_NORMAL_SIE_VID 0xFE60 // 0xFE60~0xFE61 ++#define REG_NORMAL_SIE_PID 0xFE62 // 0xFE62~0xFE63 ++#define REG_NORMAL_SIE_OPTIONAL 0xFE64 ++#define REG_NORMAL_SIE_EP 0xFE65 // 0xFE65~0xFE67 ++#define REG_NORMAL_SIE_PHY 0xFE68 // 0xFE68~0xFE6B ++#define REG_NORMAL_SIE_MAC_ADDR 0xFE70 // 0xFE70~0xFE75 ++#define REG_NORMAL_SIE_STRING 0xFE80 // 0xFE80~0xFEDF ++ ++ ++//----------------------------------------------------- ++// ++// Redifine 8192C register definition for compatibility ++// ++//----------------------------------------------------- ++ ++// TODO: use these definition when using REG_xxx naming rule. ++// NOTE: DO NOT Remove these definition. Use later. ++ ++#define SYS_ISO_CTRL REG_SYS_ISO_CTRL // System Isolation Interface Control. ++#define SYS_FUNC_EN REG_SYS_FUNC_EN // System Function Enable. ++#define SYS_CLK REG_SYS_CLKR ++#define CR9346 REG_9346CR // 93C46/93C56 Command Register. ++#define EFUSE_CTRL REG_EFUSE_CTRL // E-Fuse Control. ++#define EFUSE_TEST REG_EFUSE_TEST // E-Fuse Test. ++#define MSR (REG_CR + 2) // Media Status register ++#define ISR REG_HISR ++#define TSFR REG_TSFTR // Timing Sync Function Timer Register. ++ ++#define MACIDR0 REG_MACID // MAC ID Register, Offset 0x0050-0x0053 ++#define MACIDR4 (REG_MACID + 4) // MAC ID Register, Offset 0x0054-0x0055 ++ ++#define PBP REG_PBP ++ ++// Redifine MACID register, to compatible prior ICs. ++#define IDR0 MACIDR0 ++#define IDR4 MACIDR4 ++ ++ ++// ++// 9. Security Control Registers (Offset: ) ++// ++#define RWCAM REG_CAMCMD //IN 8190 Data Sheet is called CAMcmd ++#define WCAMI REG_CAMWRITE // Software write CAM input content ++#define RCAMO REG_CAMREAD // Software read/write CAM config ++#define CAMDBG REG_CAMDBG ++#define SECR REG_SECCFG //Security Configuration Register ++ ++// Unused register ++#define UnusedRegister 0x1BF ++#define DCAM UnusedRegister ++#define PSR UnusedRegister ++#define BBAddr UnusedRegister ++#define PhyDataR UnusedRegister ++ ++#define InvalidBBRFValue 0x12345678 ++ ++// Min Spacing related settings. ++#define MAX_MSS_DENSITY_2T 0x13 ++#define MAX_MSS_DENSITY_1T 0x0A ++ ++//---------------------------------------------------------------------------- ++// 8192C Cmd9346CR bits (Offset 0xA, 16bit) ++//---------------------------------------------------------------------------- ++#define CmdEEPROM_En BIT5 // EEPROM enable when set 1 ++#define CmdEERPOMSEL BIT4 // System EEPROM select, 0: boot from E-FUSE, 1: The EEPROM used is 9346 ++#define Cmd9346CR_9356SEL BIT4 ++#define AutoLoadEEPROM (CmdEEPROM_En|CmdEERPOMSEL) ++#define AutoLoadEFUSE CmdEEPROM_En ++ ++// 8192C GPIO MUX Configuration Register (offset 0x40, 4 byte) ++//---------------------------------------------------------------------------- ++#define GPIOSEL_GPIO 0 ++#define GPIOSEL_ENBT BIT5 ++ ++//---------------------------------------------------------------------------- ++// 8192C GPIO PIN Control Register (offset 0x44, 4 byte) ++//---------------------------------------------------------------------------- ++#define GPIO_IN REG_GPIO_PIN_CTRL // GPIO pins input value ++#define GPIO_OUT (REG_GPIO_PIN_CTRL+1) // GPIO pins output value ++#define GPIO_IO_SEL (REG_GPIO_PIN_CTRL+2) // GPIO pins output enable when a bit is set to "1"; otherwise, input is configured. ++#define GPIO_MOD (REG_GPIO_PIN_CTRL+3) ++ ++ ++//---------------------------------------------------------------------------- ++// 8192C (MSR) Media Status Register (Offset 0x4C, 8 bits) ++//---------------------------------------------------------------------------- ++/* ++Network Type ++00: No link ++01: Link in ad hoc network ++10: Link in infrastructure network ++11: AP mode ++Default: 00b. ++*/ ++#define MSR_NOLINK 0x00 ++#define MSR_ADHOC 0x01 ++#define MSR_INFRA 0x02 ++#define MSR_AP 0x03 ++ ++// ++// 6. Adaptive Control Registers (Offset: 0x0160 - 0x01CF) ++// ++//---------------------------------------------------------------------------- ++// 8192C Response Rate Set Register (offset 0x181, 24bits) ++//---------------------------------------------------------------------------- ++#define RRSR_RSC_OFFSET 21 ++#define RRSR_SHORT_OFFSET 23 ++#define RRSR_RSC_BW_40M 0x600000 ++#define RRSR_RSC_UPSUBCHNL 0x400000 ++#define RRSR_RSC_LOWSUBCHNL 0x200000 ++#define RRSR_SHORT 0x800000 ++#define RRSR_1M BIT0 ++#define RRSR_2M BIT1 ++#define RRSR_5_5M BIT2 ++#define RRSR_11M BIT3 ++#define RRSR_6M BIT4 ++#define RRSR_9M BIT5 ++#define RRSR_12M BIT6 ++#define RRSR_18M BIT7 ++#define RRSR_24M BIT8 ++#define RRSR_36M BIT9 ++#define RRSR_48M BIT10 ++#define RRSR_54M BIT11 ++#define RRSR_MCS0 BIT12 ++#define RRSR_MCS1 BIT13 ++#define RRSR_MCS2 BIT14 ++#define RRSR_MCS3 BIT15 ++#define RRSR_MCS4 BIT16 ++#define RRSR_MCS5 BIT17 ++#define RRSR_MCS6 BIT18 ++#define RRSR_MCS7 BIT19 ++#define BRSR_AckShortPmb BIT23 ++// CCK ACK: use Short Preamble or not ++ ++//---------------------------------------------------------------------------- ++// 8192C BW_OPMODE bits (Offset 0x203, 8bit) ++//---------------------------------------------------------------------------- ++#define BW_OPMODE_20MHZ BIT2 ++#define BW_OPMODE_5G BIT1 ++#define BW_OPMODE_11J BIT0 ++ ++ ++//---------------------------------------------------------------------------- ++// 8192C CAM Config Setting (offset 0x250, 1 byte) ++//---------------------------------------------------------------------------- ++#define CAM_VALID BIT15 ++#define CAM_NOTVALID 0x0000 ++#define CAM_USEDK BIT5 ++ ++#define CAM_CONTENT_COUNT 8 ++ ++#define CAM_NONE 0x0 ++#define CAM_WEP40 0x01 ++#define CAM_TKIP 0x02 ++#define CAM_AES 0x04 ++#define CAM_WEP104 0x05 ++#define CAM_SMS4 0x6 ++ ++ ++#define TOTAL_CAM_ENTRY 32 ++#define HALF_CAM_ENTRY 16 ++ ++#define CAM_CONFIG_USEDK _TRUE ++#define CAM_CONFIG_NO_USEDK _FALSE ++ ++#define CAM_WRITE BIT16 ++#define CAM_READ 0x00000000 ++#define CAM_POLLINIG BIT31 ++ ++#define SCR_UseDK 0x01 ++#define SCR_TxSecEnable 0x02 ++#define SCR_RxSecEnable 0x04 ++ ++ ++// ++// 12. Host Interrupt Status Registers (Offset: 0x0300 - 0x030F) ++// ++//---------------------------------------------------------------------------- ++// 8190 IMR/ISR bits (offset 0xfd, 8bits) ++//---------------------------------------------------------------------------- ++#define IMR8190_DISABLED 0x0 ++// IMR DW0 Bit 0-31 ++#define IMR_BCNDMAINT6 BIT31 // Beacon DMA Interrupt 6 ++#define IMR_BCNDMAINT5 BIT30 // Beacon DMA Interrupt 5 ++#define IMR_BCNDMAINT4 BIT29 // Beacon DMA Interrupt 4 ++#define IMR_BCNDMAINT3 BIT28 // Beacon DMA Interrupt 3 ++#define IMR_BCNDMAINT2 BIT27 // Beacon DMA Interrupt 2 ++#define IMR_BCNDMAINT1 BIT26 // Beacon DMA Interrupt 1 ++#define IMR_BCNDOK8 BIT25 // Beacon Queue DMA OK Interrup 8 ++#define IMR_BCNDOK7 BIT24 // Beacon Queue DMA OK Interrup 7 ++#define IMR_BCNDOK6 BIT23 // Beacon Queue DMA OK Interrup 6 ++#define IMR_BCNDOK5 BIT22 // Beacon Queue DMA OK Interrup 5 ++#define IMR_BCNDOK4 BIT21 // Beacon Queue DMA OK Interrup 4 ++#define IMR_BCNDOK3 BIT20 // Beacon Queue DMA OK Interrup 3 ++#define IMR_BCNDOK2 BIT19 // Beacon Queue DMA OK Interrup 2 ++#define IMR_BCNDOK1 BIT18 // Beacon Queue DMA OK Interrup 1 ++#define IMR_TIMEOUT2 BIT17 // Timeout interrupt 2 ++#define IMR_TIMEOUT1 BIT16 // Timeout interrupt 1 ++#define IMR_TXFOVW BIT15 // Transmit FIFO Overflow ++#define IMR_PSTIMEOUT BIT14 // Power save time out interrupt ++#define IMR_BcnInt BIT13 // Beacon DMA Interrupt 0 ++#define IMR_RXFOVW BIT12 // Receive FIFO Overflow ++#define IMR_RDU BIT11 // Receive Descriptor Unavailable ++#define IMR_ATIMEND BIT10 // For 92C,ATIM Window End Interrupt ++#define IMR_BDOK BIT9 // Beacon Queue DMA OK Interrup ++#define IMR_HIGHDOK BIT8 // High Queue DMA OK Interrupt ++#define IMR_TBDOK BIT7 // Transmit Beacon OK interrup ++#define IMR_MGNTDOK BIT6 // Management Queue DMA OK Interrupt ++#define IMR_TBDER BIT5 // For 92C,Transmit Beacon Error Interrupt ++#define IMR_BKDOK BIT4 // AC_BK DMA OK Interrupt ++#define IMR_BEDOK BIT3 // AC_BE DMA OK Interrupt ++#define IMR_VIDOK BIT2 // AC_VI DMA OK Interrupt ++#define IMR_VODOK BIT1 // AC_VO DMA Interrupt ++#define IMR_ROK BIT0 // Receive DMA OK Interrupt ++ ++// 13. Host Interrupt Status Extension Register (Offset: 0x012C-012Eh) ++#define IMR_TXERR BIT11 ++#define IMR_RXERR BIT10 ++#define IMR_C2HCMD BIT9 ++#define IMR_CPWM BIT8 ++//RSVD [2-7] ++#define IMR_OCPINT BIT1 ++#define IMR_WLANOFF BIT0 ++ ++ ++ ++//---------------------------------------------------------------------------- ++// 8192D EFUSE ++//---------------------------------------------------------------------------- ++#define HWSET_MAX_SIZE 256 ++ ++//---------------------------------------------------------------------------- ++// 8192C EEPROM/EFUSE share register definition. ++//---------------------------------------------------------------------------- ++ ++// ++// Default Value for EEPROM or EFUSE!!! ++// ++#define EEPROM_Default_TSSI 0x0 ++#define EEPROM_Default_TxPowerDiff 0x0 ++#define EEPROM_Default_CrystalCap 0x0 //92D default 0x0 ++#define EEPROM_Default_BoardType 0x02 // Default: 2X2, RTL8192CE(QFPN68) ++#define EEPROM_Default_TxPower 0x1010 ++#define EEPROM_Default_HT2T_TxPwr 0x10 ++ ++#define EEPROM_Default_LegacyHTTxPowerDiff 0x4 ++#define EEPROM_Default_ThermalMeter 0x12 ++ ++#define EEPROM_Default_AntTxPowerDiff 0x0 ++//#define EEPROM_Default_TxPwDiff_CrystalCap 0x5 ++#define EEPROM_Default_TxPowerLevel_2G 0x2C ++#define EEPROM_Default_TxPowerLevel_5G 0x22 ++ ++#define EEPROM_Default_HT40_2SDiff 0x0 ++#define EEPROM_Default_HT20_Diff 2 // HT20<->40 default Tx Power Index Difference ++#define EEPROM_Default_LegacyHTTxPowerDiff 0x4 //OFDM Tx Power index diff ++#define EEPROM_Default_HT40_PwrMaxOffset 0 ++#define EEPROM_Default_HT20_PwrMaxOffset 0 ++ ++// For debug ++#define EEPROM_Default_PID 0x1234 ++#define EEPROM_Default_VID 0x5678 ++#define EEPROM_Default_CustomerID 0xAB ++#define EEPROM_Default_SubCustomerID 0xCD ++#define EEPROM_Default_Version 0 ++ ++#define EEPROM_Default_externalPA_C9 0x00 ++#define EEPROM_Default_externalPA_CC 0xFF ++#define EEPROM_Default_internalPA_SP3T_C9 0xAA ++#define EEPROM_Default_internalPA_SP3T_CC 0xAF ++#define EEPROM_Default_internalPA_SPDT_C9 0xAA ++#ifdef CONFIG_PCI_HCI ++#define EEPROM_Default_internalPA_SPDT_CC 0xA0 ++#else ++#define EEPROM_Default_internalPA_SPDT_CC 0xFA ++#endif ++ ++#define EEPROM_CHANNEL_PLAN_FCC 0x0 ++#define EEPROM_CHANNEL_PLAN_IC 0x1 ++#define EEPROM_CHANNEL_PLAN_ETSI 0x2 ++#define EEPROM_CHANNEL_PLAN_SPAIN 0x3 ++#define EEPROM_CHANNEL_PLAN_FRANCE 0x4 ++#define EEPROM_CHANNEL_PLAN_MKK 0x5 ++#define EEPROM_CHANNEL_PLAN_MKK1 0x6 ++#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7 ++#define EEPROM_CHANNEL_PLAN_TELEC 0x8 ++#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9 ++#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA ++#define EEPROM_CHANNEL_PLAN_NCC 0xB ++#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 ++ ++ ++#define EEPROM_CID_DEFAULT 0x0 ++#define EEPROM_CID_TOSHIBA 0x4 ++#define EEPROM_CID_CCX 0x10 // CCX test. By Bruce, 2009-02-25. ++#define EEPROM_CID_QMI 0x0D ++#define EEPROM_CID_WHQL 0xFE // added by chiyoko for dtm, 20090108 ++ ++ ++#define RTL8192_EEPROM_ID 0x8129 ++#define EEPROM_WAPI_SUPPORT 0x78 ++ ++ ++#ifdef CONFIG_PCI_HCI ++#define RT_IBSS_INT_MASKS (IMR_BcnInt | IMR_TBDOK | IMR_TBDER) ++#define RT_AC_INT_MASKS (IMR_VIDOK | IMR_VODOK | IMR_BEDOK|IMR_BKDOK) ++#define RT_BSS_INT_MASKS (RT_IBSS_INT_MASKS) ++ ++#define RTL8190_EEPROM_ID 0x8129 // 0-1 ++#define EEPROM_HPON 0x02 // LDO settings.2-5 ++#define EEPROM_CLK 0x06 // Clock settings.6-7 ++#define EEPROM_MAC_FUNCTION 0x08 // SE Test mode.8 ++ ++#define EEPROM_VID 0x28 // SE Vendor ID.A-B ++#define EEPROM_DID 0x2A // SE Device ID. C-D ++#define EEPROM_SVID 0x2C // SE Vendor ID.E-F ++#define EEPROM_SMID 0x2E // SE PCI Subsystem ID. 10-11 ++ ++#define EEPROM_MAC_ADDR 0x16 // SEMAC Address. 12-17 ++#define EEPROM_MAC_ADDR_MAC0_92D 0x55 ++#define EEPROM_MAC_ADDR_MAC1_92D 0x5B ++//---------------------------------------------------------------- ++// 2.4G band Tx power index setting ++#define EEPROM_CCK_TX_PWR_INX_2G 0x61 ++#define EEPROM_HT40_1S_TX_PWR_INX_2G 0x67 ++#define EEPROM_HT40_2S_TX_PWR_INX_DIFF_2G 0x6D ++#define EEPROM_HT20_TX_PWR_INX_DIFF_2G 0x70 ++#define EEPROM_OFDM_TX_PWR_INX_DIFF_2G 0x73 ++#define EEPROM_HT40_MAX_PWR_OFFSET_2G 0x76 ++#define EEPROM_HT20_MAX_PWR_OFFSET_2G 0x79 ++ ++//5GL channel 32-64 ++#define EEPROM_HT40_1S_TX_PWR_INX_5GL 0x7C ++#define EEPROM_HT40_2S_TX_PWR_INX_DIFF_5GL 0x82 ++#define EEPROM_HT20_TX_PWR_INX_DIFF_5GL 0x85 ++#define EEPROM_OFDM_TX_PWR_INX_DIFF_5GL 0x88 ++#define EEPROM_HT40_MAX_PWR_OFFSET_5GL 0x8B ++#define EEPROM_HT20_MAX_PWR_OFFSET_5GL 0x8E ++ ++//5GM channel 100-140 ++#define EEPROM_HT40_1S_TX_PWR_INX_5GM 0x91 ++#define EEPROM_HT40_2S_TX_PWR_INX_DIFF_5GM 0x97 ++#define EEPROM_HT20_TX_PWR_INX_DIFF_5GM 0x9A ++#define EEPROM_OFDM_TX_PWR_INX_DIFF_5GM 0x9D ++#define EEPROM_HT40_MAX_PWR_OFFSET_5GM 0xA0 ++#define EEPROM_HT20_MAX_PWR_OFFSET_5GM 0xA3 ++ ++//5GH channel 149-165 ++#define EEPROM_HT40_1S_TX_PWR_INX_5GH 0xA6 ++#define EEPROM_HT40_2S_TX_PWR_INX_DIFF_5GH 0xAC ++#define EEPROM_HT20_TX_PWR_INX_DIFF_5GH 0xAF ++#define EEPROM_OFDM_TX_PWR_INX_DIFF_5GH 0xB2 ++#define EEPROM_HT40_MAX_PWR_OFFSET_5GH 0xB5 ++#define EEPROM_HT20_MAX_PWR_OFFSET_5GH 0xB8 ++ ++#define EEPROM_CHANNEL_PLAN 0xBB // Map of supported channels. ++#define EEPROM_IQK_DELTA 0xBC ++#define EEPROM_LCK_DELTA 0xBC ++#define EEPROM_XTAL_K 0xBD //[7:5] ++#define EEPROM_TSSI_A_5G 0xBE ++#define EEPROM_TSSI_B_5G 0xBF ++#define EEPROM_TSSI_AB_5G 0xC0 ++#define EEPROM_THERMAL_METER 0xC3 //[4:0] ++#define EEPROM_PATHDIV 0xC4 ++#define EEPROM_RF_OPT1 0xC4 ++#define EEPROM_RF_OPT2 0xC5 ++#define EEPROM_RF_OPT3 0xC6 ++#define EEPROM_RF_OPT4 0xC7 ++#define EEPROM_RF_OPT5 0xC8 ++#define EEPROM_RF_OPT6 0xC9 ++#define EEPROM_VERSION 0xCA ++#define EEPROM_CUSTOMER_ID 0xCB ++#define EEPROM_RF_OPT7 0xCC ++ ++#define EEPROM_WIDIPAIRING_ADDR 0xF0 ++#define EEPROM_WIDIPAIRING_KEY 0xF6 ++ ++#define EEPROM_DEF_PART_NO 0x3FD //Byte ++#define EEPROME_CHIP_VERSION_L 0x3FF ++#define EEPROME_CHIP_VERSION_H 0x3FE ++#endif ++ ++#ifdef CONFIG_USB_HCI ++#define RTL8190_EEPROM_ID 0x8129 // 0-1 ++#define EEPROM_HPON 0x02 // LDO settings.2-5 ++#define EEPROM_CLK 0x06 // Clock settings.6-7 ++#define EEPROM_MAC_FUNCTION 0x08 // SE Test mode.8 ++ ++#define EEPROM_VID 0xC // SE Vendor ID.A-B ++#define EEPROM_PID 0xE // SE Device ID. C-D ++#define EEPROM_ENDPOINT_SETTING 0x10 ++#define EEPROM_CHIRP_K 0x12 // Changed ++#define EEPROM_USB_PHY 0x13 // Changed ++#define EEPROM_NORMAL_BoardType EEPROM_RF_OPT1 //[7:5] ++#define EEPROM_MAC_ADDR 0x16 // SEMAC Address. 12-17 ++#define EEPROM_STRING 0x1F ++#define EEPROM_SUBCUSTOMER_ID 0x59 ++ ++#define EEPROM_MAC_ADDR_MAC0_92D 0x19 ++#define EEPROM_MAC_ADDR_MAC1_92D 0x5B ++//---------------------------------------------------------------- ++// 2.4G band Tx power index setting ++#define EEPROM_CCK_TX_PWR_INX_2G 0x61 ++#define EEPROM_HT40_1S_TX_PWR_INX_2G 0x67 ++#define EEPROM_HT40_2S_TX_PWR_INX_DIFF_2G 0x6D ++#define EEPROM_HT20_TX_PWR_INX_DIFF_2G 0x70 ++#define EEPROM_OFDM_TX_PWR_INX_DIFF_2G 0x73 ++#define EEPROM_HT40_MAX_PWR_OFFSET_2G 0x76 ++#define EEPROM_HT20_MAX_PWR_OFFSET_2G 0x79 ++ ++//5GL channel 32-64 ++#define EEPROM_HT40_1S_TX_PWR_INX_5GL 0x7C ++#define EEPROM_HT40_2S_TX_PWR_INX_DIFF_5GL 0x82 ++#define EEPROM_HT20_TX_PWR_INX_DIFF_5GL 0x85 ++#define EEPROM_OFDM_TX_PWR_INX_DIFF_5GL 0x88 ++#define EEPROM_HT40_MAX_PWR_OFFSET_5GL 0x8B ++#define EEPROM_HT20_MAX_PWR_OFFSET_5GL 0x8E ++ ++//5GM channel 100-140 ++#define EEPROM_HT40_1S_TX_PWR_INX_5GM 0x91 ++#define EEPROM_HT40_2S_TX_PWR_INX_DIFF_5GM 0x97 ++#define EEPROM_HT20_TX_PWR_INX_DIFF_5GM 0x9A ++#define EEPROM_OFDM_TX_PWR_INX_DIFF_5GM 0x9D ++#define EEPROM_HT40_MAX_PWR_OFFSET_5GM 0xA0 ++#define EEPROM_HT20_MAX_PWR_OFFSET_5GM 0xA3 ++ ++//5GH channel 149-165 ++#define EEPROM_HT40_1S_TX_PWR_INX_5GH 0xA6 ++#define EEPROM_HT40_2S_TX_PWR_INX_DIFF_5GH 0xAC ++#define EEPROM_HT20_TX_PWR_INX_DIFF_5GH 0xAF ++#define EEPROM_OFDM_TX_PWR_INX_DIFF_5GH 0xB2 ++#define EEPROM_HT40_MAX_PWR_OFFSET_5GH 0xB5 ++#define EEPROM_HT20_MAX_PWR_OFFSET_5GH 0xB8 ++ ++#define EEPROM_CHANNEL_PLAN 0xBB // Map of supported channels. ++#define EEPROM_TEST_CHANNEL_PLAN 0xBB ++#define EEPROM_IQK_DELTA 0xBC ++#define EEPROM_LCK_DELTA 0xBC ++#define EEPROM_XTAL_K 0xBD //[7:5] ++#define EEPROM_TSSI_A_5G 0xBE ++#define EEPROM_TSSI_B_5G 0xBF ++#define EEPROM_TSSI_AB_5G 0xC0 ++#define EEPROM_THERMAL_METER 0xC3 //[4:0] ++#define EEPROM_RF_OPT1 0xC4 ++#define EEPROM_RF_OPT2 0xC5 ++#define EEPROM_RF_OPT3 0xC6 ++#define EEPROM_RF_OPT4 0xC7 ++#define EEPROM_RF_OPT5 0xC8 ++#define EEPROM_RF_OPT6 0xC9 ++#define EEPROM_VERSION 0xCA ++#define EEPROM_CUSTOMER_ID 0xCB ++#define EEPROM_RF_OPT7 0xCC ++ ++#define EEPROM_DEF_PART_NO 0x3FD //Byte ++#define EEPROME_CHIP_VERSION_L 0x3FF ++#define EEPROME_CHIP_VERSION_H 0x3FE ++ ++//------------------------------------------------------------- ++// EEPROM content definitions ++//------------------------------------------------------------- ++#define OS_LINK_SPEED_NORMAL_MASK BIT3 | BIT2 ++#define OS_LINK_SPEED_TEST_MASK BIT3 | BIT4 ++ ++#define BOARD_TYPE_NORMAL_MASK 0xE0 ++#define BOARD_TYPE_TEST_MASK 0xF ++ ++#define BT_COEXISTENCE_TEST BIT4 ++#define BT_COEXISTENCE_NORMAL BIT5 ++ ++#define BT_CO_SHIFT_TEST 4 ++#define BT_CO_SHIFT_NORMAL 5 ++ ++#define EP_NUMBER_MASK_TEST 0x30 //bit 4:5 0Eh ++#define EP_NUMBER_SHIFT_TEST 4 ++ ++#define USB_PHY_PARA_SIZE_TEST 6 ++#define USB_PHY_PARA_SIZE_NORMAL 4 ++ ++//------------------------------------------------------------- ++// EEPROM default value definitions ++//------------------------------------------------------------- ++// Use 0xABCD instead of 0x8192 for debug ++#define EEPROM_DEF_ID_0 0xCD // Byte 0x00 ++#define EEPROM_DEF_ID_1 0xAB // Byte 0x01 ++ ++#define EEPROM_DEF_RTK_RSV_A3 0x74 // Byte 0x03 ++#define EEPROM_DEF_RTK_RSV_A4 0x6D // Byte 0x04 ++#define EEPROM_DEF_RTK_RSV_A8 0xFF // Byte 0x08 ++ ++#define EEPROM_DEF_VID_0 0x0A // Byte 0x0A ++#define EEPROM_DEF_VID_1 0x0B ++ ++#define EEPROM_DEF_PID_0 0x92 // Byte 0x0C ++#define EEPROM_DEF_PID_1 0x81 ++ ++ ++#define EEPROM_TEST_DEF_USB_OPT 0x80 // Byte 0x0E ++#define EEPROM_NORMAL_DEF_USB_OPT 0x00 // Byte 0x0E ++ ++#define EEPROM_DEF_CHIRPK 0x15 // Byte 0x0F ++ ++#define EEPROM_DEF_USB_PHY_0 0x85 // Byte 0x10 ++#define EEPROM_DEF_USB_PHY_1 0x62 // Byte 0x11 ++#define EEPROM_DEF_USB_PHY_2 0x9E // Byte 0x12 ++#define EEPROM_DEF_USB_PHY_3 0x06 // Byte 0x13 ++ ++#define EEPROM_DEF_TSSI_A 0x09 // Byte 0x78 ++#define EEPROM_DEF_TSSI_B 0x09 // Byte 0x79 ++ ++ ++#define EEPROM_DEF_THERMAL_METER 0x12 // Byte 0x7A ++ ++ ++#define EEPROM_USB_SN BIT(0) ++#define EEPROM_USB_REMOTE_WAKEUP BIT(1) ++#define EEPROM_USB_DEVICE_PWR BIT(2) ++#define EEPROM_EP_NUMBER (BIT(3)|BIT(4)) ++ ++#if 0 ++#define EEPROM_CHANNEL_PLAN_FCC 0x0 ++#define EEPROM_CHANNEL_PLAN_IC 0x1 ++#define EEPROM_CHANNEL_PLAN_ETSI 0x2 ++#define EEPROM_CHANNEL_PLAN_SPAIN 0x3 ++#define EEPROM_CHANNEL_PLAN_FRANCE 0x4 ++#define EEPROM_CHANNEL_PLAN_MKK 0x5 ++#define EEPROM_CHANNEL_PLAN_MKK1 0x6 ++#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7 ++#define EEPROM_CHANNEL_PLAN_TELEC 0x8 ++#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9 ++#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA ++#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 ++ ++#define EEPROM_CID_DEFAULT 0x0 ++ ++#define EEPROM_CID_WHQL 0xFE // added by chiyoko for dtm, 20090108 ++ ++ ++#define EEPROM_CID_CCX 0x10 // CCX test. By Bruce, 2009-02-25. ++ ++#endif ++#endif ++ ++ ++/*=================================================================== ++===================================================================== ++Here the register defines are for 92C. When the define is as same with 92C, ++we will use the 92C's define for the consistency ++So the following defines for 92C is not entire!!!!!! ++===================================================================== ++=====================================================================*/ ++/* ++Based on Datasheet V33---090401 ++Register Summary ++Current IOREG MAP ++0x0000h ~ 0x00FFh System Configuration (256 Bytes) ++0x0100h ~ 0x01FFh MACTOP General Configuration (256 Bytes) ++0x0200h ~ 0x027Fh TXDMA Configuration (128 Bytes) ++0x0280h ~ 0x02FFh RXDMA Configuration (128 Bytes) ++0x0300h ~ 0x03FFh PCIE EMAC Reserved Region (256 Bytes) ++0x0400h ~ 0x04FFh Protocol Configuration (256 Bytes) ++0x0500h ~ 0x05FFh EDCA Configuration (256 Bytes) ++0x0600h ~ 0x07FFh WMAC Configuration (512 Bytes) ++0x2000h ~ 0x3FFFh 8051 FW Download Region (8196 Bytes) ++*/ ++ ++//---------------------------------------------------------------------------- ++// 8192C (RCR) Receive Configuration Register (Offset 0x608, 32 bits) ++//---------------------------------------------------------------------------- ++#define RCR_APPFCS BIT31 //WMAC append FCS after pauload ++#define RCR_APP_MIC BIT30 // ++#define RCR_APP_ICV BIT29 // ++#define RCR_APP_PHYST_RXFF BIT28 // ++#define RCR_APP_BA_SSN BIT27 //Accept BA SSN ++#define RCR_ENMBID BIT24 //Enable Multiple BssId. ++#define RCR_LSIGEN BIT23 ++#define RCR_MFBEN BIT22 ++#define RCR_HTC_LOC_CTRL BIT14 //MFC<--HTC=1 MFC-->HTC=0 ++#define RCR_AMF BIT13 //Accept management type frame ++#define RCR_ACF BIT12 //Accept control type frame ++#define RCR_ADF BIT11 //Accept data type frame ++#define RCR_AICV BIT9 //Accept ICV error packet ++#define RCR_ACRC32 BIT8 //Accept CRC32 error packet ++#define RCR_CBSSID_BCN BIT7 //Accept BSSID match packet (Rx beacon, probe rsp) ++#define RCR_CBSSID_DATA BIT6 //Accept BSSID match packet (Data) ++#define RCR_CBSSID RCR_CBSSID_DATA //Accept BSSID match packet ++#define RCR_APWRMGT BIT5 //Accept power management packet ++#define RCR_ADD3 BIT4 //Accept address 3 match packet ++#define RCR_AB BIT3 //Accept broadcast packet ++#define RCR_AM BIT2 //Accept multicast packet ++#define RCR_APM BIT1 //Accept physical match packet ++#define RCR_AAP BIT0 //Accept all unicast packet ++#define RCR_MXDMA_OFFSET 8 ++#define RCR_FIFO_OFFSET 13 ++ ++ ++ ++//============================================================================ ++// 8192c USB specific Regsiter Offset and Content definition, ++// 2009.08.18, added by vivi. for merge 92c and 92C into one driver ++//============================================================================ ++//#define APS_FSMCO 0x0004 same with 92Ce ++#define RSV_CTRL 0x001C ++#define RD_CTRL 0x0524 ++ ++//----------------------------------------------------- ++// ++// 0xFE00h ~ 0xFE55h USB Configuration ++// ++//----------------------------------------------------- ++#define REG_USB_INFO 0xFE17 ++#define REG_USB_SPECIAL_OPTION 0xFE55 ++#define REG_USB_DMA_AGG_TO 0xFE5B ++#define REG_USB_AGG_TO 0xFE5C ++#define REG_USB_AGG_TH 0xFE5D ++ ++#define REG_USB_VID 0xFE60 ++#define REG_USB_PID 0xFE62 ++#define REG_USB_OPTIONAL 0xFE64 ++#define REG_USB_CHIRP_K 0xFE65 ++#define REG_USB_PHY 0xFE66 ++#define REG_USB_MAC_ADDR 0xFE70 ++ ++#define REG_USB_HRPWM 0xFE58 ++#define REG_USB_HCPWM 0xFE57 ++ ++#define InvalidBBRFValue 0x12345678 ++ ++//============================================================================ ++// 8192C Regsiter Bit and Content definition ++//============================================================================ ++//----------------------------------------------------- ++// ++// 0x0000h ~ 0x00FFh System Configuration ++// ++//----------------------------------------------------- ++ ++//2 SPS0_CTRL ++#define SW18_FPWM BIT(3) ++ ++ ++//2 SYS_ISO_CTRL ++#define ISO_MD2PP BIT(0) ++#define ISO_UA2USB BIT(1) ++#define ISO_UD2CORE BIT(2) ++#define ISO_PA2PCIE BIT(3) ++#define ISO_PD2CORE BIT(4) ++#define ISO_IP2MAC BIT(5) ++#define ISO_DIOP BIT(6) ++#define ISO_DIOE BIT(7) ++#define ISO_EB2CORE BIT(8) ++#define ISO_DIOR BIT(9) ++ ++#define PWC_EV25V BIT(14) ++#define PWC_EV12V BIT(15) ++ ++ ++//2 SYS_FUNC_EN ++#define FEN_BBRSTB BIT(0) ++#define FEN_BB_GLB_RSTn BIT(1) ++#define FEN_USBA BIT(2) ++#define FEN_UPLL BIT(3) ++#define FEN_USBD BIT(4) ++#define FEN_DIO_PCIE BIT(5) ++#define FEN_PCIEA BIT(6) ++#define FEN_PPLL BIT(7) ++#define FEN_PCIED BIT(8) ++#define FEN_DIOE BIT(9) ++#define FEN_CPUEN BIT(10) ++#define FEN_DCORE BIT(11) ++#define FEN_ELDR BIT(12) ++#define FEN_DIO_RF BIT(13) ++#define FEN_HWPDN BIT(14) ++#define FEN_MREGEN BIT(15) ++ ++//2 APS_FSMCO ++#define PFM_LDALL BIT(0) ++#define PFM_ALDN BIT(1) ++#define PFM_LDKP BIT(2) ++#define PFM_WOWL BIT(3) ++#define EnPDN BIT(4) ++#define PDN_PL BIT(5) ++#define APFM_ONMAC BIT(8) ++#define APFM_OFF BIT(9) ++#define APFM_RSM BIT(10) ++#define AFSM_HSUS BIT(11) ++#define AFSM_PCIE BIT(12) ++#define APDM_MAC BIT(13) ++#define APDM_HOST BIT(14) ++#define APDM_HPDN BIT(15) ++#define RDY_MACON BIT(16) ++#define SUS_HOST BIT(17) ++#define ROP_ALD BIT(20) ++#define ROP_PWR BIT(21) ++#define ROP_SPS BIT(22) ++#define SOP_MRST BIT(25) ++#define SOP_FUSE BIT(26) ++#define SOP_ABG BIT(27) ++#define SOP_AMB BIT(28) ++#define SOP_RCK BIT(29) ++#define SOP_A8M BIT(30) ++#define XOP_BTCK BIT(31) ++ ++//2 SYS_CLKR ++#define ANAD16V_EN BIT(0) ++#define ANA8M BIT(1) ++#define MACSLP BIT(4) ++#define LOADER_CLK_EN BIT(5) ++#define _80M_SSC_DIS BIT(7) ++#define _80M_SSC_EN_HO BIT(8) ++#define PHY_SSC_RSTB BIT(9) ++#define SEC_CLK_EN BIT(10) ++#define MAC_CLK_EN BIT(11) ++#define SYS_CLK_EN BIT(12) ++#define RING_CLK_EN BIT(13) ++ ++ ++//2 9346CR ++ ++#define BOOT_FROM_EEPROM BIT(4) ++#define EEPROM_EN BIT(5) ++ ++ ++//2 AFE_MISC ++#define AFE_BGEN BIT(0) ++#define AFE_MBEN BIT(1) ++#define MAC_ID_EN BIT(7) ++ ++ ++//2 SPS0_CTRL ++ ++ ++//2 SPS_OCP_CFG ++ ++ ++//2 RSV_CTRL ++#define WLOCK_ALL BIT(0) ++#define WLOCK_00 BIT(1) ++#define WLOCK_04 BIT(2) ++#define WLOCK_08 BIT(3) ++#define WLOCK_40 BIT(4) ++#define R_DIS_PRST_0 BIT(5) ++#define R_DIS_PRST_1 BIT(6) ++#define LOCK_ALL_EN BIT(7) ++ ++//2 RF_CTRL ++#define RF_EN BIT(0) ++#define RF_RSTB BIT(1) ++#define RF_SDMRSTB BIT(2) ++ ++ ++ ++//2 LDOA15_CTRL ++#define LDA15_EN BIT(0) ++#define LDA15_STBY BIT(1) ++#define LDA15_OBUF BIT(2) ++#define LDA15_REG_VOS BIT(3) ++#define _LDA15_VOADJ(x) (((x) & 0x7) << 4) ++ ++ ++ ++//2 LDOV12D_CTRL ++#define LDV12_EN BIT(0) ++#define LDV12_SDBY BIT(1) ++#define LPLDO_HSM BIT(2) ++#define LPLDO_LSM_DIS BIT(3) ++#define _LDV12_VADJ(x) (((x) & 0xF) << 4) ++ ++ ++//2 AFE_XTAL_CTRL ++#define XTAL_EN BIT(0) ++#define XTAL_BSEL BIT(1) ++#define _XTAL_BOSC(x) (((x) & 0x3) << 2) ++#define _XTAL_CADJ(x) (((x) & 0xF) << 4) ++#define XTAL_GATE_USB BIT(8) ++#define _XTAL_USB_DRV(x) (((x) & 0x3) << 9) ++#define XTAL_GATE_AFE BIT(11) ++#define _XTAL_AFE_DRV(x) (((x) & 0x3) << 12) ++#define XTAL_RF_GATE BIT(14) ++#define _XTAL_RF_DRV(x) (((x) & 0x3) << 15) ++#define XTAL_GATE_DIG BIT(17) ++#define _XTAL_DIG_DRV(x) (((x) & 0x3) << 18) ++#define XTAL_BT_GATE BIT(20) ++#define _XTAL_BT_DRV(x) (((x) & 0x3) << 21) ++#define _XTAL_GPIO(x) (((x) & 0x7) << 23) ++ ++ ++#define CKDLY_AFE BIT(26) ++#define CKDLY_USB BIT(27) ++#define CKDLY_DIG BIT(28) ++#define CKDLY_BT BIT(29) ++ ++ ++//2 AFE_PLL_CTRL ++#define APLL_EN BIT(0) ++#define APLL_320_EN BIT(1) ++#define APLL_FREF_SEL BIT(2) ++#define APLL_EDGE_SEL BIT(3) ++#define APLL_WDOGB BIT(4) ++#define APLL_LPFEN BIT(5) ++ ++#define APLL_REF_CLK_13MHZ 0x1 ++#define APLL_REF_CLK_19_2MHZ 0x2 ++#define APLL_REF_CLK_20MHZ 0x3 ++#define APLL_REF_CLK_25MHZ 0x4 ++#define APLL_REF_CLK_26MHZ 0x5 ++#define APLL_REF_CLK_38_4MHZ 0x6 ++#define APLL_REF_CLK_40MHZ 0x7 ++ ++#define APLL_320EN BIT(14) ++#define APLL_80EN BIT(15) ++#define APLL_1MEN BIT(24) ++ ++ ++//2 EFUSE_CTRL ++#define ALD_EN BIT(18) ++#define EF_PD BIT(19) ++#define EF_FLAG BIT(31) ++ ++//2 EFUSE_TEST ++#define EF_TRPT BIT(7) ++#define LDOE25_EN BIT(31) ++ ++//2 PWR_DATA ++ ++//2 CAL_TIMER ++ ++//2 ACLK_MON ++#define RSM_EN BIT(0) ++#define Timer_EN BIT(4) ++ ++ ++//2 GPIO_MUXCFG ++#define TRSW0EN BIT(2) ++#define TRSW1EN BIT(3) ++#define EROM_EN BIT(4) ++#define EnBT BIT(5) ++#define EnUart BIT(8) ++#define Uart_910 BIT(9) ++#define EnPMAC BIT(10) ++#define SIC_SWRST BIT(11) ++#define EnSIC BIT(12) ++#define SIC_23 BIT(13) ++#define EnHDP BIT(14) ++#define SIC_LBK BIT(15) ++ ++//2 GPIO_PIN_CTRL ++ ++ ++ ++//2 GPIO_INTM ++ ++//2 LEDCFG ++#define LED0PL BIT(4) ++#define LED1PL BIT(12) ++#define LED0DIS BIT(7) ++ ++#define SECCAM_CLR BIT(30) ++ ++//2 FSIMR ++ ++//2 FSISR ++ ++ ++//2 8051FWDL ++//2 MCUFWDL ++#define MCUFWDL_EN BIT(0) ++#define MCUFWDL_RDY BIT(1) ++#define FWDL_ChkSum_rpt BIT(2) ++#define MACINI_RDY BIT(3) ++#define BBINI_RDY BIT(4) ++#define RFINI_RDY BIT(5) ++#define WINTINI_RDY BIT(6) ++#define MAC1_WINTINI_RDY BIT(11)// 0X81 BIT3 ++#define CPRST BIT(23) ++ ++ ++ ++ ++//2 REG_SYS_CFG ++#define XCLK_VLD BIT(0) ++#define ACLK_VLD BIT(1) ++#define UCLK_VLD BIT(2) ++#define PCLK_VLD BIT(3) ++#define PCIRSTB BIT(4) ++#define V15_VLD BIT(5) ++#define TRP_B15V_EN BIT(7) ++#define SIC_IDLE BIT(8) ++#define BD_MAC2 BIT(9) ++#define BD_MAC1 BIT(10) ++#define IC_MACPHY_MODE BIT(11) ++#define PAD_HWPD_IDN BIT(22) ++#define TRP_VAUX_EN BIT(23) ++#define TRP_BT_EN BIT(24) ++#define BD_PKG_SEL BIT(25) ++#define BD_HCI_SEL BIT(26) ++#define TYPE_ID BIT(27) ++ ++#define CHIP_VER_RTL_MASK 0xF000 //Bit 12 ~ 15 ++#define CHIP_VER_RTL_SHIFT 12 ++ ++//----------------------------------------------------- ++// ++// 0x0100h ~ 0x01FFh MACTOP General Configuration ++// ++//----------------------------------------------------- ++ ++ ++//2 Function Enable Registers ++//2 CR ++ ++#define REG_LBMODE (REG_CR + 3) ++ ++ ++#define HCI_TXDMA_EN BIT(0) ++#define HCI_RXDMA_EN BIT(1) ++#define TXDMA_EN BIT(2) ++#define RXDMA_EN BIT(3) ++#define PROTOCOL_EN BIT(4) ++#define SCHEDULE_EN BIT(5) ++#define MACTXEN BIT(6) ++#define MACRXEN BIT(7) ++#define ENSWBCN BIT(8) ++#define ENSEC BIT(9) ++ ++// Network type ++#define _NETTYPE(x) (((x) & 0x3) << 16) ++#define MASK_NETTYPE 0x30000 ++#define NT_NO_LINK 0x0 ++#define NT_LINK_AD_HOC 0x1 ++#define NT_LINK_AP 0x2 ++#define NT_AS_AP 0x3 ++ ++#define _LBMODE(x) (((x) & 0xF) << 24) ++#define MASK_LBMODE 0xF000000 ++#define LOOPBACK_NORMAL 0x0 ++#define LOOPBACK_IMMEDIATELY 0xB ++#define LOOPBACK_MAC_DELAY 0x3 ++#define LOOPBACK_PHY 0x1 ++#define LOOPBACK_DMA 0x7 ++ ++ ++//2 PBP - Page Size Register ++#define GET_RX_PAGE_SIZE(value) ((value) & 0xF) ++#define GET_TX_PAGE_SIZE(value) (((value) & 0xF0) >> 4) ++#define _PSRX_MASK 0xF ++#define _PSTX_MASK 0xF0 ++#define _PSRX(x) (x) ++#define _PSTX(x) ((x) << 4) ++ ++#define PBP_64 0x0 ++#define PBP_128 0x1 ++#define PBP_256 0x2 ++#define PBP_512 0x3 ++#define PBP_1024 0x4 ++ ++ ++//2 TX/RXDMA ++#define RXDMA_ARBBW_EN BIT(0) ++#define RXSHFT_EN BIT(1) ++#define RXDMA_AGG_EN BIT(2) ++#define QS_VO_QUEUE BIT(8) ++#define QS_VI_QUEUE BIT(9) ++#define QS_BE_QUEUE BIT(10) ++#define QS_BK_QUEUE BIT(11) ++#define QS_MANAGER_QUEUE BIT(12) ++#define QS_HIGH_QUEUE BIT(13) ++ ++#define HQSEL_VOQ BIT(0) ++#define HQSEL_VIQ BIT(1) ++#define HQSEL_BEQ BIT(2) ++#define HQSEL_BKQ BIT(3) ++#define HQSEL_MGTQ BIT(4) ++#define HQSEL_HIQ BIT(5) ++ ++// For normal driver, 0x10C ++#define _TXDMA_HIQ_MAP(x) (((x)&0x3) << 14) ++#define _TXDMA_MGQ_MAP(x) (((x)&0x3) << 12) ++#define _TXDMA_BKQ_MAP(x) (((x)&0x3) << 10) ++#define _TXDMA_BEQ_MAP(x) (((x)&0x3) << 8 ) ++#define _TXDMA_VIQ_MAP(x) (((x)&0x3) << 6 ) ++#define _TXDMA_VOQ_MAP(x) (((x)&0x3) << 4 ) ++ ++#define QUEUE_LOW 1 ++#define QUEUE_NORMAL 2 ++#define QUEUE_HIGH 3 ++ ++ ++ ++//2 TRXFF_BNDY ++ ++ ++//2 LLT_INIT ++#define _LLT_NO_ACTIVE 0x0 ++#define _LLT_WRITE_ACCESS 0x1 ++#define _LLT_READ_ACCESS 0x2 ++ ++#define _LLT_INIT_DATA(x) ((x) & 0xFF) ++#define _LLT_INIT_ADDR(x) (((x) & 0xFF) << 8) ++#define _LLT_OP(x) (((x) & 0x3) << 30) ++#define _LLT_OP_VALUE(x) (((x) >> 30) & 0x3) ++ ++ ++//2 BB_ACCESS_CTRL ++#define BB_WRITE_READ_MASK (BIT(31) | BIT(30)) ++#define BB_WRITE_EN BIT(30) ++#define BB_READ_EN BIT(31) ++//#define BB_ADDR_MASK 0xFFF ++//#define _BB_ADDR(x) ((x) & BB_ADDR_MASK) ++ ++//----------------------------------------------------- ++// ++// 0x0200h ~ 0x027Fh TXDMA Configuration ++// ++//----------------------------------------------------- ++//2 RQPN ++#define _HPQ(x) ((x) & 0xFF) ++#define _LPQ(x) (((x) & 0xFF) << 8) ++#define _PUBQ(x) (((x) & 0xFF) << 16) ++#define _NPQ(x) ((x) & 0xFF) // NOTE: in RQPN_NPQ register ++ ++ ++#define HPQ_PUBLIC_DIS BIT(24) ++#define LPQ_PUBLIC_DIS BIT(25) ++#define LD_RQPN BIT(31) ++ ++ ++//2 TDECTRL ++#define BCN_VALID BIT(16) ++#define BCN_HEAD(x) (((x) & 0xFF) << 8) ++#define BCN_HEAD_MASK 0xFF00 ++ ++//2 TDECTL ++#define BLK_DESC_NUM_SHIFT 4 ++#define BLK_DESC_NUM_MASK 0xF ++ ++ ++//2 TXDMA_OFFSET_CHK ++#define DROP_DATA_EN BIT(9) ++ ++//----------------------------------------------------- ++// ++// 0x0400h ~ 0x047Fh Protocol Configuration ++// ++//----------------------------------------------------- ++//2 FWHW_TXQ_CTRL ++#define EN_AMPDU_RTY_NEW BIT(7) ++ ++//2 INIRTSMCS_SEL ++#define _INIRTSMCS_SEL(x) ((x) & 0x3F) ++ ++ ++//2 SPEC SIFS ++#define _SPEC_SIFS_CCK(x) ((x) & 0xFF) ++#define _SPEC_SIFS_OFDM(x) (((x) & 0xFF) << 8) ++ ++ ++//2 RRSR ++ ++#define RATE_REG_BITMAP_ALL 0xFFFFF ++ ++#define _RRSC_BITMAP(x) ((x) & 0xFFFFF) ++ ++#define _RRSR_RSC(x) (((x) & 0x3) << 21) ++#define RRSR_RSC_RESERVED 0x0 ++#define RRSR_RSC_UPPER_SUBCHANNEL 0x1 ++#define RRSR_RSC_LOWER_SUBCHANNEL 0x2 ++#define RRSR_RSC_DUPLICATE_MODE 0x3 ++ ++ ++//2 ARFR ++#define USE_SHORT_G1 BIT(20) ++ ++//2 AGGLEN_LMT_L ++#define _AGGLMT_MCS0(x) ((x) & 0xF) ++#define _AGGLMT_MCS1(x) (((x) & 0xF) << 4) ++#define _AGGLMT_MCS2(x) (((x) & 0xF) << 8) ++#define _AGGLMT_MCS3(x) (((x) & 0xF) << 12) ++#define _AGGLMT_MCS4(x) (((x) & 0xF) << 16) ++#define _AGGLMT_MCS5(x) (((x) & 0xF) << 20) ++#define _AGGLMT_MCS6(x) (((x) & 0xF) << 24) ++#define _AGGLMT_MCS7(x) (((x) & 0xF) << 28) ++ ++ ++//2 RL ++#define RETRY_LIMIT_SHORT_SHIFT 8 ++#define RETRY_LIMIT_LONG_SHIFT 0 ++ ++ ++//2 DARFRC ++#define _DARF_RC1(x) ((x) & 0x1F) ++#define _DARF_RC2(x) (((x) & 0x1F) << 8) ++#define _DARF_RC3(x) (((x) & 0x1F) << 16) ++#define _DARF_RC4(x) (((x) & 0x1F) << 24) ++// NOTE: shift starting from address (DARFRC + 4) ++#define _DARF_RC5(x) ((x) & 0x1F) ++#define _DARF_RC6(x) (((x) & 0x1F) << 8) ++#define _DARF_RC7(x) (((x) & 0x1F) << 16) ++#define _DARF_RC8(x) (((x) & 0x1F) << 24) ++ ++ ++//2 RARFRC ++#define _RARF_RC1(x) ((x) & 0x1F) ++#define _RARF_RC2(x) (((x) & 0x1F) << 8) ++#define _RARF_RC3(x) (((x) & 0x1F) << 16) ++#define _RARF_RC4(x) (((x) & 0x1F) << 24) ++// NOTE: shift starting from address (RARFRC + 4) ++#define _RARF_RC5(x) ((x) & 0x1F) ++#define _RARF_RC6(x) (((x) & 0x1F) << 8) ++#define _RARF_RC7(x) (((x) & 0x1F) << 16) ++#define _RARF_RC8(x) (((x) & 0x1F) << 24) ++ ++ ++ ++ ++//----------------------------------------------------- ++// ++// 0x0500h ~ 0x05FFh EDCA Configuration ++// ++//----------------------------------------------------- ++ ++ ++ ++//2 EDCA setting ++#define AC_PARAM_TXOP_LIMIT_OFFSET 16 ++#define AC_PARAM_ECW_MAX_OFFSET 12 ++#define AC_PARAM_ECW_MIN_OFFSET 8 ++#define AC_PARAM_AIFS_OFFSET 0 ++ ++ ++//2 EDCA_VO_PARAM ++#define _AIFS(x) (x) ++#define _ECW_MAX_MIN(x) ((x) << 8) ++#define _TXOP_LIMIT(x) ((x) << 16) ++ ++ ++#define _BCNIFS(x) ((x) & 0xFF) ++#define _BCNECW(x) (((x) & 0xF))<< 8) ++ ++ ++#define _LRL(x) ((x) & 0x3F) ++#define _SRL(x) (((x) & 0x3F) << 8) ++ ++ ++//2 SIFS_CCK ++#define _SIFS_CCK_CTX(x) ((x) & 0xFF) ++#define _SIFS_CCK_TRX(x) (((x) & 0xFF) << 8); ++ ++ ++//2 SIFS_OFDM ++#define _SIFS_OFDM_CTX(x) ((x) & 0xFF) ++#define _SIFS_OFDM_TRX(x) (((x) & 0xFF) << 8); ++ ++ ++//2 TBTT PROHIBIT ++#define _TBTT_PROHIBIT_HOLD(x) (((x) & 0xFF) << 8) ++ ++ ++//2 REG_RD_CTRL ++#define DIS_EDCA_CNT_DWN BIT(11) ++ ++ ++//2 BCN_CTRL ++#define EN_MBSSID BIT(1) ++#define EN_TXBCN_RPT BIT(2) ++#define EN_BCN_FUNCTION BIT(3) ++#define DIS_TSF_UPDATE BIT(3) ++ ++// The same function but different bit field. ++#define DIS_TSF_UDT0_NORMAL_CHIP BIT(4) ++#define DIS_TSF_UDT0_TEST_CHIP BIT(5) ++ ++//2 ACMHWCTRL ++#define AcmHw_HwEn BIT(0) ++#define AcmHw_BeqEn BIT(1) ++#define AcmHw_ViqEn BIT(2) ++#define AcmHw_VoqEn BIT(3) ++#define AcmHw_BeqStatus BIT(4) ++#define AcmHw_ViqStatus BIT(5) ++#define AcmHw_VoqStatus BIT(6) ++ ++ ++ ++//----------------------------------------------------- ++// ++// 0x0600h ~ 0x07FFh WMAC Configuration ++// ++//----------------------------------------------------- ++ ++//2 APSD_CTRL ++#define APSDOFF BIT(6) ++#define APSDOFF_STATUS BIT(7) ++ ++ ++//2 BWOPMODE ++#define BW_20MHZ BIT(2) ++//#define BW_OPMODE_20MHZ BIT(2) // For compability ++ ++ ++#define RATE_BITMAP_ALL 0xFFFFF ++ ++// Only use CCK 1M rate for ACK ++#define RATE_RRSR_CCK_ONLY_1M 0xFFFF1 ++#define RATE_RRSR_WITHOUT_CCK 0xFFFF0 ++ ++//2 TCR ++#define TSFRST BIT(0) ++#define DIS_GCLK BIT(1) ++#define PAD_SEL BIT(2) ++#define PWR_ST BIT(6) ++#define PWRBIT_OW_EN BIT(7) ++#define ACRC BIT(8) ++#define CFENDFORM BIT(9) ++#define ICV BIT(10) ++ ++ ++ ++//2 RCR ++#define AAP BIT(0) ++#define APM BIT(1) ++#define AM BIT(2) ++#define AB BIT(3) ++#define ADD3 BIT(4) ++#define APWRMGT BIT(5) ++#define CBSSID BIT(6) ++#define CBSSID_BCN BIT(7) ++#define ACRC32 BIT(8) ++#define AICV BIT(9) ++#define ADF BIT(11) ++#define ACF BIT(12) ++#define AMF BIT(13) ++#define HTC_LOC_CTRL BIT(14) ++#define UC_DATA_EN BIT(16) ++#define BM_DATA_EN BIT(17) ++#define MFBEN BIT(22) ++#define LSIGEN BIT(23) ++#define EnMBID BIT(24) ++#define APP_BASSN BIT(27) ++#define APP_PHYSTS BIT(28) ++#define APP_ICV BIT(29) ++#define APP_MIC BIT(30) ++#define APP_FCS BIT(31) ++ ++//2 RX_PKT_LIMIT ++ ++//2 RX_DLK_TIME ++ ++//2 MBIDCAMCFG ++ ++ ++ ++//2 AMPDU_MIN_SPACE ++#define _MIN_SPACE(x) ((x) & 0x7) ++#define _SHORT_GI_PADDING(x) (((x) & 0x1F) << 3) ++ ++ ++//2 RXERR_RPT ++#define RXERR_TYPE_OFDM_PPDU 0 ++#define RXERR_TYPE_OFDM_FALSE_ALARM 1 ++#define RXERR_TYPE_OFDM_MPDU_OK 2 ++#define RXERR_TYPE_OFDM_MPDU_FAIL 3 ++#define RXERR_TYPE_CCK_PPDU 4 ++#define RXERR_TYPE_CCK_FALSE_ALARM 5 ++#define RXERR_TYPE_CCK_MPDU_OK 6 ++#define RXERR_TYPE_CCK_MPDU_FAIL 7 ++#define RXERR_TYPE_HT_PPDU 8 ++#define RXERR_TYPE_HT_FALSE_ALARM 9 ++#define RXERR_TYPE_HT_MPDU_TOTAL 10 ++#define RXERR_TYPE_HT_MPDU_OK 11 ++#define RXERR_TYPE_HT_MPDU_FAIL 12 ++#define RXERR_TYPE_RX_FULL_DROP 15 ++ ++#define RXERR_COUNTER_MASK 0xFFFFF ++#define RXERR_RPT_RST BIT(27) ++#define _RXERR_RPT_SEL(type) ((type) << 28) ++ ++ ++//2 SECCFG ++#define SCR_TxUseDK BIT(0) //Force Tx Use Default Key ++#define SCR_RxUseDK BIT(1) //Force Rx Use Default Key ++#define SCR_TxEncEnable BIT(2) //Enable Tx Encryption ++#define SCR_RxDecEnable BIT(3) //Enable Rx Decryption ++#define SCR_SKByA2 BIT(4) //Search kEY BY A2 ++#define SCR_NoSKMC BIT(5) //No Key Search Multicast ++#define SCR_TXBCUSEDK BIT(6) // Force Tx Broadcast packets Use Default Key ++#define SCR_RXBCUSEDK BIT(7) // Force Rx Broadcast packets Use Default Key ++ ++//vivi added for new cam search flow, 20091028 ++#ifdef HW_EN_DE_CRYPTION_FOR_NEW_CAM_SEARCH_FLOW ++#define SCR_TxUseBroadcastDK BIT6 //Force Tx Use Broadcast Default Key ++#define SCR_RxUseBroadcastDK BIT7 //Force Rx Use Broadcast Default Key ++#endif ++ ++ ++//----------------------------------------------------- ++// ++// 0xFE00h ~ 0xFE55h USB Configuration ++// ++//----------------------------------------------------- ++ ++//2 USB Information (0xFE17) ++#define USB_IS_HIGH_SPEED 0 ++#define USB_IS_FULL_SPEED 1 ++#define USB_SPEED_MASK BIT(5) ++ ++#define USB_NORMAL_SIE_EP_MASK 0xF ++#define USB_NORMAL_SIE_EP_SHIFT 4 ++ ++#define USB_TEST_EP_MASK 0x30 ++#define USB_TEST_EP_SHIFT 4 ++ ++//2 Special Option ++#define USB_AGG_EN BIT(3) ++ ++ ++//2REG_C2HEVT_CLEAR ++#define C2H_EVT_HOST_CLOSE 0x00 // Set by driver and notify FW that the driver has read the C2H command message ++#define C2H_EVT_FW_CLOSE 0xFF // Set by FW indicating that FW had set the C2H command message and it's not yet read by driver. ++ ++//2 8192D PartNo. ++#define PARTNO_92D_NIC (BIT7|BIT6) ++#define PARTNO_92D_NIC_REMARK (BIT5|BIT4) ++#define PARTNO_SINGLE_BAND_VS BIT3 ++#define PARTNO_SINGLE_BAND_VS_REMARK BIT1 ++#define PARTNO_CONCURRENT_BAND_VC (BIT3|BIT2) ++#define PARTNO_CONCURRENT_BAND_VC_REMARK (BIT1|BIT0) ++//======================================================== ++// General definitions ++//======================================================== ++ ++#define MAC_ADDR_LEN 6 ++#define LAST_ENTRY_OF_TX_PKT_BUFFER 255 ++#define LAST_ENTRY_OF_TX_PKT_BUFFER_DUAL_MAC 127 ++ ++#define POLLING_LLT_THRESHOLD 20 ++#define POLLING_READY_TIMEOUT_COUNT 1000 ++ ++// Min Spacing related settings. ++#define MAX_MSS_DENSITY_2T 0x13 ++#define MAX_MSS_DENSITY_1T 0x0A ++// GPIO BIT ++#define HAL_8192C_HW_GPIO_WPS_BIT BIT2 ++ ++ ++#include "basic_types.h" ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_xmit.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_xmit.h +new file mode 100644 +index 00000000..54f0511c +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8192d_xmit.h +@@ -0,0 +1,181 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTL8192D_XMIT_H_ ++#define _RTL8192D_XMIT_H_ ++ ++// ++//defined for TX DESC Operation ++// ++ ++#define MAX_TID (15) ++ ++//OFFSET 0 ++#define OFFSET_SZ 0 ++#define OFFSET_SHT 16 ++#define BMC BIT(24) ++#define LSG BIT(26) ++#define FSG BIT(27) ++#define OWN BIT(31) ++ ++ ++//OFFSET 4 ++#define PKT_OFFSET_SZ 0 ++#define BK BIT(6) ++#define QSEL_SHT 8 ++#define Rate_ID_SHT 16 ++#define NAVUSEHDR BIT(20) ++#define PKT_OFFSET_SHT 26 ++#define HWPC BIT(31) ++ ++//OFFSET 8 ++#define AGG_EN BIT(29) ++ ++//OFFSET 12 ++#define SEQ_SHT 16 ++ ++//OFFSET 16 ++#define QoS BIT(6) ++#define HW_SEQ_EN BIT(7) ++#define USERATE BIT(8) ++#define DISDATAFB BIT(10) ++#define DATA_SHORT BIT(24) ++#define DATA_BW BIT(25) ++ ++//OFFSET 20 ++#define SGI BIT(6) ++ ++// ++// Queue Select Value in TxDesc ++// ++#define QSLT_BK 0x2//0x01 ++#define QSLT_BE 0x0 ++#define QSLT_VI 0x5//0x4 ++#define QSLT_VO 0x7//0x6 ++#define QSLT_BEACON 0x10 ++#define QSLT_HIGH 0x11 ++#define QSLT_MGNT 0x12 ++#define QSLT_CMD 0x13 ++ ++//Because we open EM for normal case, we just always insert 2*8 bytes.by wl ++#define USB_92D_DUMMY_OFFSET 2 ++#define USB_92D_DUMMY_LENGTH (USB_92D_DUMMY_OFFSET * PACKET_OFFSET_SZ) ++#define USB_HWDESC_HEADER_LEN (TXDESC_SIZE + USB_92D_DUMMY_LENGTH) ++ ++//For 92D early mode ++#define SET_EARLYMODE_PKTNUM(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr, 0, 3, __Value) ++#define SET_EARLYMODE_LEN0(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr, 4, 12, __Value) ++#define SET_EARLYMODE_LEN1(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr, 16, 12, __Value) ++#define SET_EARLYMODE_LEN2_1(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr, 28, 4, __Value) ++#define SET_EARLYMODE_LEN2_2(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr+4, 0, 8, __Value) ++#define SET_EARLYMODE_LEN3(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr+4, 8, 12, __Value) ++#define SET_EARLYMODE_LEN4(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr+4, 20, 12, __Value) ++ ++/* Copy from rtl8192c */ ++struct txrpt_ccx_8192d { ++ /* offset 0 */ ++ u8 retry_cnt:6; ++ u8 rsvd_0:2; ++ ++ /* offset 1 */ ++ u8 rts_retry_cnt:6; ++ u8 rsvd_1:2; ++ ++ /* offset 2 */ ++ u8 ccx_qtime0; ++ u8 ccx_qtime1; ++ ++ /* offset 4 */ ++ u8 missed_pkt_num:5; ++ u8 rsvd_4:3; ++ ++ /* offset 5 */ ++ u8 mac_id:5; ++ u8 des1_fragssn:3; ++ ++ /* offset 6 */ ++ u8 rpt_pkt_num:5; ++ u8 pkt_drop:1; ++ u8 lifetime_over:1; ++ u8 retry_over:1; ++ ++ /* offset 7*/ ++ u8 edca_tx_queue:4; ++ u8 rsvd_7:1; ++ u8 bmc:1; ++ u8 pkt_ok:1; ++ u8 int_ccx:1; ++}; ++ ++#define txrpt_ccx_qtime_8192d(txrpt_ccx) ((txrpt_ccx)->ccx_qtime0+((txrpt_ccx)->ccx_qtime1<<8)) ++ ++#ifdef CONFIG_XMIT_ACK ++void dump_txrpt_ccx_8192d(void *buf); ++void handle_txrpt_ccx_8192d(_adapter *adapter, void *buf); ++#else ++#define dump_txrpt_ccx_8192d(buf) do {} while(0) ++#define handle_txrpt_ccx_8192d(adapter, buf) do {} while(0) ++#endif ++ ++#ifdef CONFIG_USB_HCI ++ ++#ifdef CONFIG_USB_TX_AGGREGATION ++#define MAX_TX_AGG_PACKET_NUMBER 0xFF ++#endif ++ ++s32 rtl8192du_init_xmit_priv(_adapter * padapter); ++ ++void rtl8192du_free_xmit_priv(_adapter * padapter); ++ ++void rtl8192du_cal_txdesc_chksum(struct tx_desc *ptxdesc); ++ ++s32 rtl8192du_xmitframe_complete(_adapter *padapter, struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf); ++ ++s32 rtl8192du_mgnt_xmit(_adapter *padapter, struct xmit_frame *pmgntframe); ++ ++s32 rtl8192du_hal_xmit(_adapter *padapter, struct xmit_frame *pxmitframe); ++ ++#ifdef CONFIG_HOSTAPD_MLME ++s32 rtl8192du_hostap_mgnt_xmit_entry(_adapter *padapter, _pkt *pkt); ++#endif ++ ++#endif ++ ++#ifdef CONFIG_PCI_HCI ++s32 rtl8192de_init_xmit_priv(_adapter * padapter); ++void rtl8192de_free_xmit_priv(_adapter * padapter); ++ ++s32 rtl8192de_enqueue_xmitbuf(struct rtw_tx_ring *ring, struct xmit_buf *pxmitbuf); ++struct xmit_buf *rtl8192de_dequeue_xmitbuf(struct rtw_tx_ring *ring); ++ ++void rtl8192de_xmitframe_resume(_adapter *padapter); ++ ++s32 rtl8192de_mgnt_xmit(_adapter *padapter, struct xmit_frame *pmgntframe); ++ ++s32 rtl8192de_hal_xmit(_adapter *padapter, struct xmit_frame *pxmitframe); ++ ++#ifdef CONFIG_HOSTAPD_MLME ++s32 rtl8192de_hostap_mgnt_xmit_entry(_adapter *padapter, _pkt *pkt); ++#endif ++ ++#endif ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_bt-coexist.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_bt-coexist.h +new file mode 100644 +index 00000000..78d64b8d +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_bt-coexist.h +@@ -0,0 +1,1816 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8723A_BT_COEXIST_H__ ++#define __RTL8723A_BT_COEXIST_H__ ++ ++#include ++#include "../hal/OUTSRC/odm_precomp.h" ++ ++ ++#define __BT_C__ 1 ++#define __BT_HANDLEPACKET_C__ 1 ++#define __BT_HCI_C__ 1 ++#define __HALBTC87231ANT_C__ 1 ++#define __HALBTC87232ANT_C__ 1 ++#define __HALBTC8723_C__ 1 ++#define __HALBTCCSR1ANT_C__ 1 ++#define __HALBTCCSR2ANT_C__ 1 ++#define __HALBTCOEXIST_C__ 1 ++#define __HALBT_C__ 1 ++ ++#ifdef __BT_C__ // COMMON/BT.h ++ ++// HEADER/PlatformDef.h ++typedef enum _RT_MEDIA_STATUS { ++ RT_MEDIA_DISCONNECT = 0, ++ RT_MEDIA_CONNECT = 1 ++} RT_MEDIA_STATUS; ++ ++// ===== Below this line is sync from SD7 driver COMMON/BT.h ===== ++ ++#define BT_TMP_BUF_SIZE 100 ++ ++void BT_SignalCompensation(PADAPTER padapter, u8 *rssi_wifi, u8 *rssi_bt); ++void BT_WifiScanNotify(PADAPTER padapter, u8 scanType); ++void BT_WifiAssociateNotify(PADAPTER padapter, u8 action); ++void BT_WifiMediaStatusNotify(PADAPTER padapter, RT_MEDIA_STATUS mstatus); ++void BT_SpecialPacketNotify(PADAPTER padapter); ++void BT_HaltProcess(PADAPTER padapter); ++void BT_LpsLeave(PADAPTER padapter); ++ ++ ++#define BT_HsConnectionEstablished(Adapter) _FALSE ++// ===== End of sync from SD7 driver COMMON/BT.h ===== ++#endif // __BT_C__ ++ ++#ifdef __BT_HCI_C__ // COMMON/bt_hci.h ++ ++// HEADER/SecurityType.h ++#define TKIP_ENC_KEY_POS 32 //(KEK_LEN+KEK_LEN) ++#define MAXRSNIELEN 256 ++ ++// HEADER/QoSType.h ++#if 0 ++// ++// BSS QOS data. ++// Ref: BssDscr in 8185 code. [def. in BssDscr.h] ++// ++typedef struct _BSS_QOS ++{ ++ // Part 0. Ref. 8185 QoS code (From Emily) ++ QOS_MODE bdQoSMode; ++ u8 bdWMMIEBuf[MAX_WMMELE_LENGTH]; ++ OCTET_STRING bdWMMIE; ++ ++ QOS_ELE_SUBTYPE EleSubType; ++ ++ // Part 2. EDCA Parameter (perAC) ++ u8 *pWMMInfoEle; ++ u8 *pWMMParamEle; ++ ++ // QBSS Load. ++ u8 QBssLoad[QBSS_LOAD_SIZE]; ++ u8 bQBssLoadValid; ++} BSS_QOS, *PBSS_QOS; ++#endif ++ ++// COMMON/Protocol802_11.h ++//---------------------------------------------------------------------------- ++// 802.11 Management frame Status Code field ++//---------------------------------------------------------------------------- ++typedef struct _OCTET_STRING{ ++ u8 *Octet; ++ u16 Length; ++} OCTET_STRING, *POCTET_STRING; ++ ++ ++//====================================================================================== ++// AES_CCMP specific ++//====================================================================================== ++enum ++{ ++ AESCCMP_BLK_SIZE = 16, // # octets in an AES block ++ AESCCMP_MAX_PACKET = 4*512, // largest packet size ++ AESCCMP_N_RESERVED = 0, // reserved nonce octet value ++ AESCCMP_A_DATA = 0x40, // the Adata bit in the flags ++ AESCCMP_M_SHIFT = 3, // how much to shift the 3-bit M field ++ AESCCMP_L_SHIFT = 0, // how much to shift the 3-bit L field ++ AESCCMP_L_SIZE = 2, // size of the l(m) length field (in octets) ++ AESCCMP_OFFSET_SC = 22, ++ AESCCMP_OFFSET_DURATION = 4, ++ AESCCMP_OFFSET_A2 = 10, ++ AESCCMP_OFFSET_A4 = 24, ++ AESCCMP_QC_TID_MASK = 0x0f, ++ AESCCMP_BLK_SIZE_TOTAL = 16*16, // Added by Annie for CKIP AES MIC BSOD, 2006-08-17. ++ // 16*8 < 4*60 Resove to 16*16 ++}; ++ ++// ++// Key Length ++// ++#define PMK_LEN 32 ++#define PTK_LEN_TKIP 64 ++#define GTK_LEN 32 ++#define KEY_NONCE_LEN 32 ++ ++ ++// COMMON/Dot11d.h ++typedef struct _CHNL_TXPOWER_TRIPLE ++{ ++ u8 FirstChnl; ++ u8 NumChnls; ++ s8 MaxTxPowerInDbm; ++} CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE; ++ ++ ++// ===== Below this line is sync from SD7 driver COMMON/bt_hci.h ===== ++#define BT_THREAD 0 ++#if(BT_THREAD == 1) ++#define SENDTXMEHTOD 2 ++#else ++#define SENDTXMEHTOD 1 // 0=workitem, 1= SendDirectily, 2=thread ++#endif ++ ++//============================================= ++// The following is for BT 3.0 + HS HCI COMMAND ERRORS CODES ++//============================================= ++ ++#define Max80211PALPDUSize 1492 ++#define Max80211AMPASSOCLen 672 ++#define MinGUserPrio 4 ++#define MaxGUserPrio 7 ++#define BEUserPrio0 0 ++#define BEUserPrio1 3 ++#define Max80211BeaconPeriod 2000 ++#define ShortRangeModePowerMax 4 ++ ++#define BT_Default_Chnl 10 ++#define ACLDataHeaderLen 4 ++ ++#define BTTotalDataBlockNum 0x100 ++#define BTLocalBufNum 0x200 ++#define BTMaxDataBlockLen 0x800 ++#define BTTOTALBANDWIDTH 0x7530 ++#define BTMAXBANDGUBANDWIDTH 0x4e20 ++#define TmpLocalBufSize 0x100 ++#define BTSynDataPacketLength 0xff ++//============================================= ++ ++#define BTMaxAuthCount 5 ++#define BTMaxAsocCount 5 ++ ++#define MAX_LOGICAL_LINK_NUM 2 //temporarily define ++#define MAX_BT_ASOC_ENTRY_NUM 2 //temporarily define ++ ++#define INVALID_PL_HANDLE 0xff ++#define INVALID_ENTRY_NUM 0xff ++//============================================= ++ ++#define CAM_BT_START_INDEX (HALF_CAM_ENTRY - 4) // MAX_BT_ASOC_ENTRY_NUM : 4 !!! ++#define BT_HWCAM_STAR CAM_BT_START_INDEX // We used HALF_CAM_ENTRY ~ HALF_CAM_ENTRY -MAX_BT_ASOC_ENTRY_NUM ++ ++typedef enum _HCI_STATUS ++{ ++ HCI_STATUS_SUCCESS =0x00, //Success ++ HCI_STATUS_UNKNOW_HCI_CMD =0x01, //Unknown HCI Command ++ HCI_STATUS_UNKNOW_CONNECT_ID =0X02, //Unknown Connection Identifier ++ HCI_STATUS_HW_FAIL =0X03, //Hardware Failure ++ HCI_STATUS_PAGE_TIMEOUT =0X04, //Page Timeout ++ HCI_STATUS_AUTH_FAIL =0X05, //Authentication Failure ++ HCI_STATUS_PIN_OR_KEY_MISSING =0X06, //PIN or Key Missing ++ HCI_STATUS_MEM_CAP_EXCEED =0X07, //Memory Capacity Exceeded ++ HCI_STATUS_CONNECT_TIMEOUT =0X08, //Connection Timeout ++ HCI_STATUS_CONNECT_LIMIT =0X09, //Connection Limit Exceeded ++ HCI_STATUS_SYN_CONNECT_LIMIT =0X0a, //Synchronous Connection Limit To A Device Exceeded ++ HCI_STATUS_ACL_CONNECT_EXISTS =0X0b, //ACL Connection Already Exists ++ HCI_STATUS_CMD_DISALLOW =0X0c, //Command Disallowed ++ HCI_STATUS_CONNECT_RJT_LIMIT_RESOURCE =0X0d, //Connection Rejected due to Limited Resources ++ HCI_STATUS_CONNECT_RJT_SEC_REASON =0X0e, //Connection Rejected Due To Security Reasons ++ HCI_STATUS_CONNECT_RJT_UNACCEPT_BD_ADDR =0X0f, //Connection Rejected due to Unacceptable BD_ADDR ++ HCI_STATUS_CONNECT_ACCEPT_TIMEOUT =0X10, //Connection Accept Timeout Exceeded ++ HCI_STATUS_UNSUPPORT_FEATURE_PARA_VALUE =0X11, //Unsupported Feature or Parameter Value ++ HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE =0X12, //Invalid HCI Command Parameters ++ HCI_STATUS_REMOTE_USER_TERMINATE_CONNECT =0X13, //Remote User Terminated Connection ++ HCI_STATUS_REMOTE_DEV_TERMINATE_LOW_RESOURCE =0X14, //Remote Device Terminated Connection due to Low Resources ++ HCI_STATUS_REMOTE_DEV_TERMINATE_CONNECT_POWER_OFF =0X15, //Remote Device Terminated Connection due to Power Off ++ HCI_STATUS_CONNECT_TERMINATE_LOCAL_HOST =0X16, //Connection Terminated By Local Host ++ HCI_STATUS_REPEATE_ATTEMPT =0X17, //Repeated Attempts ++ HCI_STATUS_PAIR_NOT_ALLOW =0X18, //Pairing Not Allowed ++ HCI_STATUS_UNKNOW_LMP_PDU =0X19, //Unknown LMP PDU ++ HCI_STATUS_UNSUPPORT_REMOTE_LMP_FEATURE =0X1a, //Unsupported Remote Feature / Unsupported LMP Feature ++ HCI_STATUS_SOC_OFFSET_REJECT =0X1b, //SCO Offset Rejected ++ HCI_STATUS_SOC_INTERVAL_REJECT =0X1c, //SCO Interval Rejected ++ HCI_STATUS_SOC_AIR_MODE_REJECT =0X1d,//SCO Air Mode Rejected ++ HCI_STATUS_INVALID_LMP_PARA =0X1e, //Invalid LMP Parameters ++ HCI_STATUS_UNSPECIFIC_ERROR =0X1f, //Unspecified Error ++ HCI_STATUS_UNSUPPORT_LMP_PARA_VALUE =0X20, //Unsupported LMP Parameter Value ++ HCI_STATUS_ROLE_CHANGE_NOT_ALLOW =0X21, //Role Change Not Allowed ++ HCI_STATUS_LMP_RESPONSE_TIMEOUT =0X22, //LMP Response Timeout ++ HCI_STATUS_LMP_ERROR_TRANSACTION_COLLISION =0X23, //LMP Error Transaction Collision ++ HCI_STATUS_LMP_PDU_NOT_ALLOW =0X24, //LMP PDU Not Allowed ++ HCI_STATUS_ENCRYPTION_MODE_NOT_ALLOW =0X25, //Encryption Mode Not Acceptable ++ HCI_STATUS_LINK_KEY_CAN_NOT_CHANGE =0X26, //Link Key Can Not be Changed ++ HCI_STATUS_REQUEST_QOS_NOT_SUPPORT =0X27, //Requested QoS Not Supported ++ HCI_STATUS_INSTANT_PASSED =0X28, //Instant Passed ++ HCI_STATUS_PAIRING_UNIT_KEY_NOT_SUPPORT =0X29, //Pairing With Unit Key Not Supported ++ HCI_STATUS_DIFFERENT_TRANSACTION_COLLISION =0X2a, //Different Transaction Collision ++ HCI_STATUS_RESERVE_1 =0X2b, //Reserved ++ HCI_STATUS_QOS_UNACCEPT_PARA =0X2c, //QoS Unacceptable Parameter ++ HCI_STATUS_QOS_REJECT =0X2d, //QoS Rejected ++ HCI_STATUS_CHNL_CLASSIFICATION_NOT_SUPPORT =0X2e, //Channel Classification Not Supported ++ HCI_STATUS_INSUFFICIENT_SECURITY =0X2f, //Insufficient Security ++ HCI_STATUS_PARA_OUT_OF_RANGE =0x30, //Parameter Out Of Mandatory Range ++ HCI_STATUS_RESERVE_2 =0X31, //Reserved ++ HCI_STATUS_ROLE_SWITCH_PENDING =0X32, //Role Switch Pending ++ HCI_STATUS_RESERVE_3 =0X33, //Reserved ++ HCI_STATUS_RESERVE_SOLT_VIOLATION =0X34, //Reserved Slot Violation ++ HCI_STATUS_ROLE_SWITCH_FAIL =0X35, //Role Switch Failed ++ HCI_STATUS_EXTEND_INQUIRY_RSP_TOO_LARGE =0X36, //Extended Inquiry Response Too Large ++ HCI_STATUS_SEC_SIMPLE_PAIRING_NOT_SUPPORT =0X37, //Secure Simple Pairing Not Supported By Host. ++ HCI_STATUS_HOST_BUSY_PAIRING =0X38, //Host Busy - Pairing ++ HCI_STATUS_CONNECT_REJ_NOT_SUIT_CHNL_FOUND =0X39, //Connection Rejected due to No Suitable Channel Found ++ HCI_STATUS_CONTROLLER_BUSY =0X3a //CONTROLLER BUSY ++} HCI_STATUS,*PHCI_STATUS; ++ ++//============================================= ++// The following is for BT 3.0 + HS HCI COMMAND ++//============================================= ++ ++//bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ++// | OCF | OGF | ++// ++ ++//OGF 0x01 ++#define OGF_LINK_CONTROL_COMMANDS 0x01 ++typedef enum _LINK_CONTROL_COMMANDS ++{ ++ HCI_INQUIRY =0x0001, ++ HCI_INQUIRY_CANCEL =0x0002, ++ HCI_PERIODIC_INQUIRY_MODE =0x0003, ++ HCI_EXIT_PERIODIC_INQUIRY_MODE =0x0004, ++ HCI_CREATE_CONNECTION =0x0005, ++ HCI_DISCONNECT =0x0006, ++ HCI_CREATE_CONNECTION_CANCEL =0x0008, ++ HCI_ACCEPT_CONNECTIONREQUEST =0x0009, ++ HCI_REJECT_CONNECTION_REQUEST =0x000a, ++ HCI_LINK_KEY_REQUEST_REPLY =0x000b, ++ HCI_LINK_KEY_REQUEST_NEGATIVE_REPLY =0x000c, ++ HCI_PIN_CODE_REQUEST_REPLY =0x000d, ++ HCI_PIN_CODE_REQUEST_NEGATIVE_REPLY =0x000e, ++ HCI_CHANGE_CONNECTION_PACKET_TYPE =0x000f, ++ HCI_AUTHENTICATION_REQUESTED =0x0011, ++ HCI_SET_CONNECTION_ENCRYPTION =0x0013, ++ HCI_CHANGE_CONNECTION_LINK_KEY =0x0015, ++ HCI_MASTER_LINK_KEY =0x0017, ++ HCI_REMOTE_NAME_REQUEST =0x0019, ++ HCI_REMOTE_NAME_REQUEST_CANCEL =0x001a, ++ HCI_READ_REMOTE_SUPPORTED_FEATURES =0x001b, ++ HCI_READ_REMOTE_EXTENDED_FEATURES =0x001c, ++ HCI_READ_REMOTE_VERSION_INFORMATION =0x001d, ++ HCI_READ_CLOCK_OFFSET =0x001f, ++ HCI_READ_LMP_HANDLE =0x0020, ++ HCI_SETUP_SYNCHRONOUS_CONNECTION =0x0028, ++ HCI_ACCEPT_SYNCHRONOUS_CONNECTION_REQUEST =0x0029, ++ HCI_REJECT_SYNCHRONOUS_CONNECTION_REQUEST =0x002a, ++ HCI_IO_CAPABILITY_REQUEST_REPLY =0x002b, ++ HCI_USER_CONFIRMATION_REQUEST_REPLY =0x002c, ++ HCI_USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY =0x002d, ++ HCI_USER_PASSKEY_REQUEST_REPLY =0x002e, ++ HCI_USER_PASSKEY_REQUESTNEGATIVE_REPLY =0x002f, ++ HCI_REMOTE_OOB_DATA_REQUEST_REPLY =0x0030, ++ HCI_REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY =0x0033, ++ HCI_IO_CAPABILITY_REQUEST_NEGATIVE_REPLY =0x0034, ++ HCI_CREATE_PHYSICAL_LINK =0x0035, ++ HCI_ACCEPT_PHYSICAL_LINK =0x0036, ++ HCI_DISCONNECT_PHYSICAL_LINK =0x0037, ++ HCI_CREATE_LOGICAL_LINK =0x0038, ++ HCI_ACCEPT_LOGICAL_LINK =0x0039, ++ HCI_DISCONNECT_LOGICAL_LINK =0x003a, ++ HCI_LOGICAL_LINK_CANCEL =0x003b, ++ HCI_FLOW_SPEC_MODIFY =0x003c ++} LINK_CONTROL_COMMANDS,*PLINK_CONTROL_COMMANDS; ++ ++//OGF 0x02 ++#define OGF_HOLD_MODE_COMMAND 0x02 ++typedef enum _HOLD_MODE_COMMAND ++{ ++ HCI_HOLD_MODE =0x0001, ++ HCI_SNIFF_MODE =0x0002, ++ HCI_EXIT_SNIFF_MODE =0x0003, ++ HCI_PARK_STATE =0x0005, ++ HCI_EXIT_PARK_STATE =0x0006, ++ HCI_QOS_SETUP =0x0007, ++ HCI_ROLE_DISCOVERY =0x0009, ++ HCI_SWITCH_ROLE =0x000b, ++ HCI_READ_LINK_POLICY_SETTINGS =0x000c, ++ HCI_WRITE_LINK_POLICY_SETTINGS =0x000d, ++ HCI_READ_DEFAULT_LINK_POLICY_SETTINGS =0x000e, ++ HCI_WRITE_DEFAULT_LINK_POLICY_SETTINGS =0x000f, ++ HCI_FLOW_SPECIFICATION =0x0010, ++ HCI_SNIFF_SUBRATING =0x0011 ++} HOLD_MODE_COMMAND,*PHOLD_MODE_COMMAND; ++ ++//OGF 0x03 ++#define OGF_SET_EVENT_MASK_COMMAND 0x03 ++typedef enum _SET_EVENT_MASK_COMMAND ++{ ++ HCI_SET_EVENT_MASK =0x0001, ++ HCI_RESET =0x0003, ++ HCI_SET_EVENT_FILTER =0x0005, ++ HCI_FLUSH =0x0008, ++ HCI_READ_PIN_TYPE =0x0009, ++ HCI_WRITE_PIN_TYPE =0x000a, ++ HCI_CREATE_NEW_UNIT_KEY =0x000b, ++ HCI_READ_STORED_LINK_KEY =0x000d, ++ HCI_WRITE_STORED_LINK_KEY =0x0011, ++ HCI_DELETE_STORED_LINK_KEY =0x0012, ++ HCI_WRITE_LOCAL_NAME =0x0013, ++ HCI_READ_LOCAL_NAME =0x0014, ++ HCI_READ_CONNECTION_ACCEPT_TIMEOUT =0x0015, ++ HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT =0x0016, ++ HCI_READ_PAGE_TIMEOUT =0x0017, ++ HCI_WRITE_PAGE_TIMEOUT =0x0018, ++ HCI_READ_SCAN_ENABLE =0x0019, ++ HCI_WRITE_SCAN_ENABLE =0x001a, ++ HCI_READ_PAGE_SCAN_ACTIVITY =0x001b, ++ HCI_WRITE_PAGE_SCAN_ACTIVITY =0x001c, ++ HCI_READ_INQUIRY_SCAN_ACTIVITY =0x001d, ++ HCI_WRITE_INQUIRY_SCAN_ACTIVITY =0x001e, ++ HCI_READ_AUTHENTICATION_ENABLE =0x001f, ++ HCI_WRITE_AUTHENTICATION_ENABLE =0x0020, ++ HCI_READ_CLASS_OF_DEVICE =0x0023, ++ HCI_WRITE_CLASS_OF_DEVICE =0x0024, ++ HCI_READ_VOICE_SETTING =0x0025, ++ HCI_WRITE_VOICE_SETTING =0x0026, ++ HCI_READ_AUTOMATIC_FLUSH_TIMEOUT =0x0027, ++ HCI_WRITE_AUTOMATIC_FLUSH_TIMEOUT =0x0028, ++ HCI_READ_NUM_BROADCAST_RETRANSMISSIONS =0x0029, ++ HCI_WRITE_NUM_BROADCAST_RETRANSMISSIONS =0x002a, ++ HCI_READ_HOLD_MODE_ACTIVITY =0x002b, ++ HCI_WRITE_HOLD_MODE_ACTIVITY =0x002c, ++ HCI_READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE =0x002e, ++ HCI_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE =0x002f, ++ HCI_SET_CONTROLLER_TO_HOST_FLOW_CONTROL =0x0031, ++ HCI_HOST_BUFFER_SIZE =0x0033, ++ HCI_HOST_NUMBER_OF_COMPLETED_PACKETS =0x0035, ++ HCI_READ_LINK_SUPERVISION_TIMEOUT =0x0036, ++ HCI_WRITE_LINK_SUPERVISION_TIMEOUT =0x0037, ++ HCI_READ_NUMBER_OF_SUPPORTED_IAC =0x0038, ++ HCI_READ_CURRENT_IAC_LAP =0x0039, ++ HCI_WRITE_CURRENT_IAC_LAP =0x003a, ++ HCI_READ_PAGE_SCAN_MODE =0x003d, ++ HCI_WRITE_PAGE_SCAN_MODE =0x003e, ++ HCI_SET_AFH_HOST_CHANNEL_CLASSIFICATION =0x003f, ++ HCI_READ_INQUIRY_SCAN_TYPE =0x0042, ++ HCI_WRITE_INQUIRY_SCAN_TYPE =0x0043, ++ HCI_READ_INQUIRY_MODE =0x0044, ++ HCI_WRITE_INQUIRY_MODE =0x0045, ++ HCI_READ_PAGE_SCAN_TYPE =0x0046, ++ HCI_WRITE_PAGE_SCAN_TYPE =0x0047, ++ HCI_READ_AFH_CHANNEL_ASSESSMENT_MODE =0x0048, ++ HCI_WRITE_AFH_CHANNEL_ASSESSMENT_MODE =0x0049, ++ HCI_READ_EXTENDED_INQUIRY_RESPONSE =0x0051, ++ HCI_WRITE_EXTENDED_INQUIRY_RESPONSE =0x0052, ++ HCI_REFRESH_ENCRYPTION_KEY =0x0053, ++ HCI_READ_SIMPLE_PAIRING_MODE =0x0055, ++ HCI_WRITE_SIMPLE_PAIRING_MODE =0x0056, ++ HCI_READ_LOCAL_OOB_DATA =0x0057, ++ HCI_READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL =0x0058, ++ HCI_WRITE_INQUIRY_TRANSMIT_POWER_LEVEL =0x0059, ++ HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING =0x005a, ++ HCI_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING =0x005b, ++ HCI_ENHANCED_FLUSH =0x005f, ++ HCI_SEND_KEYPRESS_NOTIFICATION =0x0060, ++ HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT =0x0061, ++ HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT =0x0062, ++ HCI_SET_EVENT_MASK_PAGE_2 =0x0063, ++ HCI_READ_LOCATION_DATA =0x0064, ++ HCI_WRITE_LOCATION_DATA =0x0065, ++ HCI_READ_FLOW_CONTROL_MODE =0x0066, ++ HCI_WRITE_FLOW_CONTROL_MODE =0x0067, ++ HCI_READ_ENHANCE_TRANSMIT_POWER_LEVEL =0x0068, ++ HCI_READ_BEST_EFFORT_FLUSH_TIMEOUT =0x0069, ++ HCI_WRITE_BEST_EFFORT_FLUSH_TIMEOUT =0x006a, ++ HCI_SHORT_RANGE_MODE =0x006b ++}SET_EVENT_MASK_COMMAND,*PSET_EVENT_MASK_COMMAND; ++ ++//OGF 0x04 ++#define OGF_INFORMATIONAL_PARAMETERS 0x04 ++typedef enum _INFORMATIONAL_PARAMETERS ++{ ++ HCI_READ_LOCAL_VERSION_INFORMATION =0x0001, ++ HCI_READ_LOCAL_SUPPORTED_COMMANDS =0x0002, ++ HCI_READ_LOCAL_SUPPORTED_FEATURES =0x0003, ++ HCI_READ_LOCAL_EXTENDED_FEATURES =0x0004, ++ HCI_READ_BUFFER_SIZE =0x0005, ++ HCI_READ_BD_ADDR =0x0009, ++ HCI_READ_DATA_BLOCK_SIZE =0x000a ++} INFORMATIONAL_PARAMETERS,*PINFORMATIONAL_PARAMETERS; ++ ++//OGF 0x05 ++#define OGF_STATUS_PARAMETERS 0x05 ++typedef enum _STATUS_PARAMETERS ++{ ++ HCI_READ_FAILED_CONTACT_COUNTER =0x0001, ++ HCI_RESET_FAILED_CONTACT_COUNTER =0x0002, ++ HCI_READ_LINK_QUALITY =0x0003, ++ HCI_READ_RSSI =0x0005, ++ HCI_READ_AFH_CHANNEL_MAP =0x0006, ++ HCI_READ_CLOCK =0x0007, ++ HCI_READ_ENCRYPTION_KEY_SIZE =0x0008, ++ HCI_READ_LOCAL_AMP_INFO =0x0009, ++ HCI_READ_LOCAL_AMP_ASSOC =0x000a, ++ HCI_WRITE_REMOTE_AMP_ASSOC =0x000b ++} STATUS_PARAMETERS,*PSTATUS_PARAMETERS; ++ ++//OGF 0x06 ++#define OGF_TESTING_COMMANDS 0x06 ++typedef enum _TESTING_COMMANDS ++{ ++ HCI_READ_LOOPBACK_MODE =0x0001, ++ HCI_WRITE_LOOPBACK_MODE =0x0002, ++ HCI_ENABLE_DEVICE_UNDER_TEST_MODE =0x0003, ++ HCI_WRITE_SIMPLE_PAIRING_DEBUG_MODE =0x0004, ++ HCI_ENABLE_AMP_RECEIVER_REPORTS =0x0007, ++ HCI_AMP_TEST_END =0x0008, ++ HCI_AMP_TEST_COMMAND =0x0009 ++} TESTING_COMMANDS,*PTESTING_COMMANDS; ++ ++//OGF 0x3f ++#define OGF_EXTENSION 0X3f ++typedef enum _HCI_EXTENSION_COMMANDS ++{ ++ HCI_SET_ACL_LINK_DATA_FLOW_MODE =0x0010, ++ HCI_SET_ACL_LINK_STATUS =0x0020, ++ HCI_SET_SCO_LINK_STATUS =0x0030, ++ HCI_SET_RSSI_VALUE =0x0040, ++ HCI_SET_CURRENT_BLUETOOTH_STATUS =0x0041, ++ ++ //The following is for RTK8723 ++ HCI_EXTENSION_VERSION_NOTIFY =0x0100, ++ HCI_LINK_STATUS_NOTIFY =0x0101, ++ HCI_BT_OPERATION_NOTIFY =0x0102, ++ HCI_ENABLE_WIFI_SCAN_NOTIFY =0x0103, ++ ++ ++ //The following is for IVT ++ HCI_WIFI_CURRENT_CHANNEL =0x0300, ++ HCI_WIFI_CURRENT_BANDWIDTH =0x0301, ++ HCI_WIFI_CONNECTION_STATUS =0x0302, ++} HCI_EXTENSION_COMMANDS,*PHCI_EXTENSION_COMMANDS; ++ ++typedef enum _BT_SPEC ++{ ++ BT_SPEC_1_0_b =0x00, ++ BT_SPEC_1_1 =0x01, ++ BT_SPEC_1_2 =0x02, ++ BT_SPEC_2_0_EDR =0x03, ++ BT_SPEC_2_1_EDR =0x04, ++ BT_SPEC_3_0_HS =0x05, ++ BT_SPEC_4_0 =0x06 ++} BT_SPEC,*PBT_SPEC; ++ ++//============================================= ++// The following is for BT 3.0 + HS EVENTS ++//============================================= ++typedef enum _HCI_EVENT ++{ ++ HCI_EVENT_INQUIRY_COMPLETE =0x01, ++ HCI_EVENT_INQUIRY_RESULT =0x02, ++ HCI_EVENT_CONNECTION_COMPLETE =0x03, ++ HCI_EVENT_CONNECTION_REQUEST =0x04, ++ HCI_EVENT_DISCONNECTION_COMPLETE =0x05, ++ HCI_EVENT_AUTHENTICATION_COMPLETE =0x06, ++ HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE =0x07, ++ HCI_EVENT_ENCRYPTION_CHANGE =0x08, ++ HCI_EVENT_CHANGE_LINK_KEY_COMPLETE =0x09, ++ HCI_EVENT_MASTER_LINK_KEY_COMPLETE =0x0a, ++ HCI_EVENT_READ_REMOTE_SUPPORT_FEATURES_COMPLETE =0x0b, ++ HCI_EVENT_READ_REMOTE_VER_INFO_COMPLETE =0x0c, ++ HCI_EVENT_QOS_SETUP_COMPLETE =0x0d, ++ HCI_EVENT_COMMAND_COMPLETE =0x0e, ++ HCI_EVENT_COMMAND_STATUS =0x0f, ++ HCI_EVENT_HARDWARE_ERROR =0x10, ++ HCI_EVENT_FLUSH_OCCRUED =0x11, ++ HCI_EVENT_ROLE_CHANGE =0x12, ++ HCI_EVENT_NUMBER_OF_COMPLETE_PACKETS =0x13, ++ HCI_EVENT_MODE_CHANGE =0x14, ++ HCI_EVENT_RETURN_LINK_KEYS =0x15, ++ HCI_EVENT_PIN_CODE_REQUEST =0x16, ++ HCI_EVENT_LINK_KEY_REQUEST =0x17, ++ HCI_EVENT_LINK_KEY_NOTIFICATION =0x18, ++ HCI_EVENT_LOOPBACK_COMMAND =0x19, ++ HCI_EVENT_DATA_BUFFER_OVERFLOW =0x1a, ++ HCI_EVENT_MAX_SLOTS_CHANGE =0x1b, ++ HCI_EVENT_READ_CLOCK_OFFSET_COMPLETE =0x1c, ++ HCI_EVENT_CONNECT_PACKET_TYPE_CHANGE =0x1d, ++ HCI_EVENT_QOS_VIOLATION =0x1e, ++ HCI_EVENT_PAGE_SCAN_REPETITION_MODE_CHANGE =0x20, ++ HCI_EVENT_FLOW_SEPC_COMPLETE =0x21, ++ HCI_EVENT_INQUIRY_RESULT_WITH_RSSI =0x22, ++ HCI_EVENT_READ_REMOTE_EXT_FEATURES_COMPLETE =0x23, ++ HCI_EVENT_SYNC_CONNECT_COMPLETE =0x2c, ++ HCI_EVENT_SYNC_CONNECT_CHANGE =0x2d, ++ HCI_EVENT_SNIFFER_SUBRATING =0x2e, ++ HCI_EVENT_EXTENTED_INQUIRY_RESULT =0x2f, ++ HCI_EVENT_ENCRYPTION_KEY_REFLASH_COMPLETE =0x30, ++ HCI_EVENT_IO_CAPIBILITY_COMPLETE =0x31, ++ HCI_EVENT_IO_CAPIBILITY_RESPONSE =0x32, ++ HCI_EVENT_USER_CONFIRMTION_REQUEST =0x33, ++ HCI_EVENT_USER_PASSKEY_REQUEST =0x34, ++ HCI_EVENT_REMOTE_OOB_DATA_REQUEST =0x35, ++ HCI_EVENT_SIMPLE_PAIRING_COMPLETE =0x36, ++ HCI_EVENT_LINK_SUPERVISION_TIMEOUT_CHANGE =0x38, ++ HCI_EVENT_ENHANCED_FLUSH_COMPLETE =0x39, ++ HCI_EVENT_USER_PASSKEY_NOTIFICATION =0x3b, ++ HCI_EVENT_KEYPRESS_NOTIFICATION =0x3c, ++ HCI_EVENT_REMOTE_HOST_SUPPORT_FEATURES_NOTIFICATION =0x3d, ++ HCI_EVENT_PHY_LINK_COMPLETE =0x40, ++ HCI_EVENT_CHANNEL_SELECT =0x41, ++ HCI_EVENT_DISCONNECT_PHY_LINK_COMPLETE =0x42, ++ HCI_EVENT_PHY_LINK_LOSS_EARLY_WARNING =0x43, ++ HCI_EVENT_PHY_LINK_RECOVER =0x44, ++ HCI_EVENT_LOGICAL_LINK_COMPLETE =0x45, ++ HCI_EVENT_DISCONNECT_LOGICAL_LINK_COMPLETE =0x46, ++ HCI_EVENT_FLOW_SPEC_MODIFY_COMPLETE =0x47, ++ HCI_EVENT_NUM_OF_COMPLETE_DATA_BLOCKS =0x48, ++ HCI_EVENT_AMP_START_TEST =0x49, ++ HCI_EVENT_AMP_TEST_END =0x4a, ++ HCI_EVENT_AMP_RECEIVER_REPORT =0x4b, ++ HCI_EVENT_SHORT_RANGE_MODE_CHANGE_COMPLETE =0x4c, ++ HCI_EVENT_AMP_STATUS_CHANGE =0x4d, ++ HCI_EVENT_EXTENSION_RTK =0xfe, ++ HCI_EVENT_EXTENSION_MOTO =0xff, ++}HCI_EVENT, *PHCI_EVENT; ++ ++typedef enum _HCI_EXTENSION_EVENT_MOTO ++{ ++ HCI_EVENT_GET_BT_RSSI =0x01, ++} HCI_EXTENSION_EVENT_MOTO, *PHCI_EXTENSION_EVENT_MOTO; ++ ++typedef enum _HCI_EXTENSION_EVENT_RTK ++{ ++ HCI_EVENT_EXT_WIFI_SCAN_NOTIFY =0x01, ++} HCI_EXTENSION_EVENT_RTK, *PHCI_EXTENSION_EVENT_RTK; ++ ++typedef enum _HCI_EVENT_MASK_PAGE_2 ++{ ++ EMP2_HCI_EVENT_PHY_LINK_COMPLETE =0x0000000000000001, ++ EMP2_HCI_EVENT_CHANNEL_SELECT =0x0000000000000002, ++ EMP2_HCI_EVENT_DISCONNECT_PHY_LINK_COMPLETE =0x0000000000000004, ++ EMP2_HCI_EVENT_PHY_LINK_LOSS_EARLY_WARNING =0x0000000000000008, ++ EMP2_HCI_EVENT_PHY_LINK_RECOVER =0x0000000000000010, ++ EMP2_HCI_EVENT_LOGICAL_LINK_COMPLETE =0x0000000000000020, ++ EMP2_HCI_EVENT_DISCONNECT_LOGICAL_LINK_COMPLETE =0x0000000000000040, ++ EMP2_HCI_EVENT_FLOW_SPEC_MODIFY_COMPLETE =0x0000000000000080, ++ EMP2_HCI_EVENT_NUM_OF_COMPLETE_DATA_BLOCKS =0x0000000000000100, ++ EMP2_HCI_EVENT_AMP_START_TEST =0x0000000000000200, ++ EMP2_HCI_EVENT_AMP_TEST_END =0x0000000000000400, ++ EMP2_HCI_EVENT_AMP_RECEIVER_REPORT =0x0000000000000800, ++ EMP2_HCI_EVENT_SHORT_RANGE_MODE_CHANGE_COMPLETE =0x0000000000001000, ++ EMP2_HCI_EVENT_AMP_STATUS_CHANGE =0x0000000000002000, ++} HCI_EVENT_MASK_PAGE_2, *PHCI_EVENT_MASK_PAGE_2; ++ ++typedef enum _HCI_STATE_MACHINE ++{ ++ HCI_STATE_STARTING =0x01, ++ HCI_STATE_CONNECTING =0x02, ++ HCI_STATE_AUTHENTICATING =0x04, ++ HCI_STATE_CONNECTED =0x08, ++ HCI_STATE_DISCONNECTING =0x10, ++ HCI_STATE_DISCONNECTED =0x20 ++} HCI_STATE_MACHINE, *PHCI_STATE_MACHINE; ++ ++typedef enum _AMP_ASSOC_STRUCTURE_TYPE ++{ ++ AMP_MAC_ADDR =0x01, ++ AMP_PREFERRED_CHANNEL_LIST =0x02, ++ AMP_CONNECTED_CHANNEL =0x03, ++ AMP_80211_PAL_CAP_LIST =0x04, ++ AMP_80211_PAL_VISION =0x05, ++ AMP_RESERVED_FOR_TESTING =0x33 ++} AMP_ASSOC_STRUCTURE_TYPE, *PAMP_ASSOC_STRUCTURE_TYPE; ++ ++typedef enum _AMP_BTAP_TYPE ++{ ++ AMP_BTAP_NONE, ++ AMP_BTAP_CREATOR, ++ AMP_BTAP_JOINER ++} AMP_BTAP_TYPE, *PAMP_BTAP_TYPE; ++ ++typedef enum _HCI_STATE_WITH_CMD ++{ ++ STATE_CMD_CREATE_PHY_LINK, ++ STATE_CMD_ACCEPT_PHY_LINK, ++ STATE_CMD_DISCONNECT_PHY_LINK, ++ STATE_CMD_CONNECT_ACCEPT_TIMEOUT, ++ STATE_CMD_MAC_START_COMPLETE, ++ STATE_CMD_MAC_START_FAILED, ++ STATE_CMD_MAC_CONNECT_COMPLETE, ++ STATE_CMD_MAC_CONNECT_FAILED, ++ STATE_CMD_MAC_DISCONNECT_INDICATE, ++ STATE_CMD_MAC_CONNECT_CANCEL_INDICATE, ++ STATE_CMD_4WAY_FAILED, ++ STATE_CMD_4WAY_SUCCESSED, ++ STATE_CMD_ENTER_STATE, ++ STATE_CMD_NO_SUCH_CMD, ++} HCI_STATE_WITH_CMD, *PHCI_STATE_WITH_CMD; ++ ++typedef enum _HCI_SERVICE_TYPE ++{ ++ SERVICE_NO_TRAFFIC, ++ SERVICE_BEST_EFFORT, ++ SERVICE_GUARANTEE ++} HCI_SERVICE_TYPE, *PHCI_SERVICE_TYPE; ++ ++typedef enum _HCI_TRAFFIC_MODE ++{ ++ TRAFFIC_MODE_BEST_EFFORT =0x00, ++ TRAFFIC_MODE_GUARANTEED_LATENCY =0x01, ++ TRAFFIC_MODE_GUARANTEED_BANDWIDTH =0x02, ++ TRAFFIC_MODE_GUARANTEED_LATENCY_AND_BANDWIDTH =0x03 ++} HCI_TRAFFIC_MODE, *PHCI_TRAFFIC_MODE; ++ ++#define HCIOPCODE(_OCF, _OGF) (_OGF<<10|_OCF) ++#define HCIOPCODELOW(_OCF, _OGF) (u8)(HCIOPCODE(_OCF, _OGF)&0x00ff) ++#define HCIOPCODEHIGHT(_OCF, _OGF) (u8)(HCIOPCODE(_OCF, _OGF)>>8) ++ ++#define TWOBYTE_HIGHTBYTE(_DATA) (u8)(_DATA>>8) ++#define TWOBYTE_LOWBYTE(_DATA) (u8)(_DATA) ++ ++typedef enum _AMP_STATUS ++{ ++ AMP_STATUS_AVA_PHY_PWR_DWN = 0x0, ++ AMP_STATUS_BT_USE_ONLY = 0x1, ++ AMP_STATUS_NO_CAPACITY_FOR_BT = 0x2, ++ AMP_STATUS_LOW_CAPACITY_FOR_BT = 0x3, ++ AMP_STATUS_MEDIUM_CAPACITY_FOR_BT = 0x4, ++ AMP_STATUS_HIGH_CAPACITY_FOR_BT = 0x5, ++ AMP_STATUS_FULL_CAPACITY_FOR_BT = 0x6 ++} AMP_STATUS, *PAMP_STATUS; ++ ++typedef enum ++{ ++ Type_BT_4way1st = 0, ++ Type_BT_4way2nd = 1, ++ Type_BT_4way3rd = 2, ++ Type_BT_4way4th = 3, ++ Type_BT_unknow = 4 ++} BT_WPAMsgType; ++ ++typedef enum _BT_CONNECT_TYPE ++{ ++ BT_CONNECT_AUTH_REQ =0x00, ++ BT_CONNECT_AUTH_RSP =0x01, ++ BT_CONNECT_ASOC_REQ =0x02, ++ BT_CONNECT_ASOC_RSP =0x03, ++ BT_DISCONNECT =0x04 ++} BT_CONNECT_TYPE, *PBT_CONNECT_TYPE; ++ ++typedef enum _BT_LL_SERVICE_TYPE ++{ ++ BT_LL_BE = 0x01, ++ BT_LL_GU = 0x02 ++} BT_LL_SERVICE_TYPE; ++ ++typedef enum _BT_LL_FLOWSPEC ++{ ++ BT_TX_BE_FS, //TX best effort flowspec ++ BT_RX_BE_FS, //RX best effort flowspec ++ BT_TX_GU_FS, //TX guaranteed latency flowspec ++ BT_RX_GU_FS, //RX guaranteed latency flowspec ++ BT_TX_BE_AGG_FS, //TX aggregated best effort flowspec ++ BT_RX_BE_AGG_FS, //RX aggregated best effort flowspec ++ BT_TX_GU_BW_FS, //TX guaranteed bandwidth flowspec ++ BT_RX_GU_BW_FS, //RX guaranteed bandwidth flowspec ++ BT_TX_GU_LARGE_FS, //TX guaranteed latency flowspec, for testing only ++ BT_RX_GU_LARGE_FS, //RX guaranteed latency flowspec, for testing only ++} BT_LL_FLOWSPEC; ++ ++typedef enum _BT_TRAFFIC_MODE ++{ ++ BT_MOTOR_EXT_BE = 0x00, //Best Effort. Default. for HCRP, PAN, SDP, RFCOMM-based profiles like FTP,OPP, SPP, DUN, etc. ++ BT_MOTOR_EXT_GUL = 0x01, //Guaranteed Latency. This type of traffic is used e.g. for HID and AVRCP. ++ BT_MOTOR_EXT_GUB = 0X02, //Guaranteed Bandwidth. ++ BT_MOTOR_EXT_GULB = 0X03 //Guaranteed Latency and Bandwidth. for A2DP and VDP. ++} BT_TRAFFIC_MODE; ++ ++typedef enum _BT_TRAFFIC_MODE_PROFILE ++{ ++ BT_PROFILE_NONE, ++ BT_PROFILE_A2DP, ++ BT_PROFILE_PAN, ++ BT_PROFILE_HID, ++ BT_PROFILE_SCO ++} BT_TRAFFIC_MODE_PROFILE; ++ ++typedef enum _BT_LINK_ROLE ++{ ++ BT_LINK_MASTER = 0, ++ BT_LINK_SLAVE = 1 ++} BT_LINK_ROLE; ++ ++typedef enum _BT_STATE_WPA_AUTH ++{ ++ STATE_WPA_AUTH_UNINITIALIZED, ++ STATE_WPA_AUTH_WAIT_PACKET_1, // Join ++ STATE_WPA_AUTH_WAIT_PACKET_2, // Creat ++ STATE_WPA_AUTH_WAIT_PACKET_3, ++ STATE_WPA_AUTH_WAIT_PACKET_4, ++ STATE_WPA_AUTH_SUCCESSED ++} BT_STATE_WPA_AUTH, *PBT_STATE_WPA_AUTH; ++ ++#define BT_WPA_AUTH_TIMEOUT_PERIOD 1000 ++#define BTMaxWPAAuthReTransmitCoun 5 ++ ++#define MAX_AMP_ASSOC_FRAG_LEN 248 ++#define TOTAL_ALLOCIATE_ASSOC_LEN 1000 ++ ++typedef struct _HCI_FLOW_SPEC ++{ ++ u8 Identifier; ++ u8 ServiceType; ++ u16 MaximumSDUSize; ++ u32 SDUInterArrivalTime; ++ u32 AccessLatency; ++ u32 FlushTimeout; ++} HCI_FLOW_SPEC, *PHCI_FLOW_SPEC; ++ ++typedef struct _HCI_LOG_LINK_CMD_DATA ++{ ++ u8 BtPhyLinkhandle; ++ u16 BtLogLinkhandle; ++ u8 BtTxFlowSpecID; ++ HCI_FLOW_SPEC Tx_Flow_Spec; ++ HCI_FLOW_SPEC Rx_Flow_Spec; ++ u32 TxPacketCount; ++ u32 BestEffortFlushTimeout; ++ ++ u8 bLLCompleteEventIsSet; ++ ++ u8 bLLCancelCMDIsSetandComplete; ++} HCI_LOG_LINK_CMD_DATA, *PHCI_LOG_LINK_CMD_DATA; ++ ++typedef struct _HCI_PHY_LINK_CMD_DATA ++{ ++ //Physical_Link_Handle ++ u8 BtPhyLinkhandle; ++ ++ u16 LinkSuperversionTimeout; ++ ++ //u16 SuperTimeOutCnt; ++ ++ //Dedicated_AMP_Key_Length ++ u8 BtAMPKeyLen; ++ //Dedicated_AMP_Key_Type ++ u8 BtAMPKeyType; ++ //Dedicated_AMP_Key ++ u8 BtAMPKey[PMK_LEN]; ++} HCI_PHY_LINK_CMD_DATA, *PHCI_PHY_LINK_CMD_DATA; ++ ++typedef struct _AMP_ASSOC_STRUCTURE ++{ ++ //TYPE ID ++ u8 TypeID; ++ //Length ++ u16 Length; ++ //Value ++ u8 Data[1]; ++} AMP_ASSOC_STRUCTURE, *PAMP_ASSOC_STRUCTURE; ++ ++typedef struct _AMP_PREF_CHNL_REGULATORY ++{ ++ u8 reXId; ++ u8 regulatoryClass; ++ u8 coverageClass; ++} AMP_PREF_CHNL_REGULATORY, *PAMP_PREF_CHNL_REGULATORY; ++ ++typedef struct _AMP_ASSOC_CMD_DATA ++{ ++ //Physical_Link_Handle ++ u8 BtPhyLinkhandle; ++ //Length_So_Far ++ u16 LenSoFar; ++ ++ u16 MaxRemoteASSOCLen; ++ //AMP_ASSOC_Remaining_Length ++ u16 AMPAssocRemLen; ++ //AMP_ASSOC_fragment ++ void *AMPAssocfragment; ++} AMP_ASSOC_CMD_DATA, *PAMP_ASSOC_CMD_DATA; ++ ++typedef struct _HCI_LINK_INFO ++{ ++ u16 ConnectHandle; ++ u8 IncomingTrafficMode; ++ u8 OutgoingTrafficMode; ++ u8 BTProfile; ++ u8 BTCoreSpec; ++ s8 BT_RSSI; ++ u8 TrafficProfile; ++ u8 linkRole; ++} HCI_LINK_INFO, *PHCI_LINK_INFO; ++ ++typedef struct _HCI_EXT_CONFIG ++{ ++ HCI_LINK_INFO linkInfo[MAX_BT_ASOC_ENTRY_NUM]; ++ u8 btOperationCode; ++ u16 CurrentConnectHandle; ++ u8 CurrentIncomingTrafficMode; ++ u8 CurrentOutgoingTrafficMode; ++ s8 MIN_BT_RSSI; ++ u8 NumberOfHandle; ++ u8 NumberOfSCO; ++ u8 CurrentBTStatus; ++ u16 HCIExtensionVer; ++ ++ //Bt coexist related ++ u8 btProfileCase; ++ u8 btProfileAction; ++ u8 bManualControl; ++ u8 bBTBusy; ++ u8 bBTA2DPBusy; ++ u8 bEnableWifiScanNotify; ++ ++ u8 bHoldForBtOperation; ++ u32 bHoldPeriodCnt; ++ ++}HCI_EXT_CONFIG, *PHCI_EXT_CONFIG; ++ ++typedef struct _HCI_ACL_PACKET_DATA ++{ ++ u16 ACLDataPacketLen; ++ u8 SyncDataPacketLen; ++ u16 TotalNumACLDataPackets; ++ u16 TotalSyncNumDataPackets; ++} HCI_ACL_PACKET_DATA, *PHCI_ACL_PACKET_DATA; ++ ++typedef struct _HCI_PHY_LINK_BSS_INFO ++{ ++ u16 bdCap; // capability information ++ ++ // Qos related. Added by Annie, 2005-11-01. ++// BSS_QOS BssQos; // not implement yet ++ ++} HCI_PHY_LINK_BSS_INFO, *PHCI_PHY_LINK_BSS_INFO; ++ ++typedef struct _PACKET_IRP_HCICMD_DATA ++{ ++ u16 OCF:10; ++ u16 OGF:6; ++ u8 Length; ++ u8 Data[1]; ++} PACKET_IRP_HCICMD_DATA, *PPACKET_IRP_HCICMD_DATA; ++ ++typedef struct _BT_ASOC_ENTRY ++{ ++ u8 bUsed; ++ u8 mAssoc; ++ u8 b4waySuccess; ++ u8 Bssid[6]; ++ HCI_PHY_LINK_CMD_DATA PhyLinkCmdData; ++ ++ HCI_LOG_LINK_CMD_DATA LogLinkCmdData[MAX_LOGICAL_LINK_NUM]; ++ ++ HCI_ACL_PACKET_DATA ACLPacketsData; ++ ++ AMP_ASSOC_CMD_DATA AmpAsocCmdData; ++ OCTET_STRING BTSsid; ++ u8 BTSsidBuf[33]; ++ ++ HCI_STATUS PhyLinkDisconnectReason; ++ ++ u8 bSendSupervisionPacket; ++ //u8 CurrentSuervisionPacketSendNum; ++ //u8 LastSuervisionPacketSendNum; ++ u32 NoRxPktCnt; ++ //Is Creator or Joiner ++ AMP_BTAP_TYPE AMPRole; ++ ++ //BT current state ++ u8 BtCurrentState; ++ //BT next state ++ u8 BtNextState; ++ ++ u8 bNeedPhysLinkCompleteEvent; ++ ++ HCI_STATUS PhysLinkCompleteStatus; ++ ++ u8 BTRemoteMACAddr[6]; ++ ++ u32 BTCapability; ++ ++ u8 SyncDataPacketLen; ++ ++ u16 TotalSyncNumDataPackets; ++ u16 TotalNumACLDataPackets; ++ ++ u8 ShortRangeMode; ++ ++ u8 PTK[PTK_LEN_TKIP]; ++ u8 GTK[GTK_LEN]; ++ u8 ANonce[KEY_NONCE_LEN]; ++ u8 SNonce[KEY_NONCE_LEN]; ++ u64 KeyReplayCounter; ++ u8 WPAAuthReplayCount; ++ u8 AESKeyBuf[AESCCMP_BLK_SIZE_TOTAL]; ++ u8 PMK[PMK_LEN]; ++ BT_STATE_WPA_AUTH BTWPAAuthState; ++ s32 UndecoratedSmoothedPWDB; ++ ++ // Add for HW security !! ++ u8 HwCAMIndex; // Cam index ++ u8 bPeerQosSta; ++ ++ u32 rxSuvpPktCnt; ++}BT_ASOC_ENTRY, *PBT_ASOC_ENTRY; ++ ++typedef struct _BT_TRAFFIC_STATISTICS ++{ ++ u8 bTxBusyTraffic; ++ u8 bRxBusyTraffic; ++ u8 bIdle; ++ u32 TxPktCntInPeriod; ++ u32 RxPktCntInPeriod; ++ u64 TxPktLenInPeriod; ++ u64 RxPktLenInPeriod; ++} BT_TRAFFIC_STATISTICS, *PBT_TRAFFIC_STATISTICS; ++ ++typedef struct _BT_MGNT ++{ ++ u8 bBTConnectInProgress; ++ u8 bLogLinkInProgress; ++ u8 bPhyLinkInProgress; ++ u8 bPhyLinkInProgressStartLL; ++ u8 BtCurrentPhyLinkhandle; ++ u16 BtCurrentLogLinkhandle; ++ u8 CurrentConnectEntryNum; ++ u8 DisconnectEntryNum; ++ u8 CurrentBTConnectionCnt; ++ BT_CONNECT_TYPE BTCurrentConnectType; ++ BT_CONNECT_TYPE BTReceiveConnectPkt; ++ u8 BTAuthCount; ++ u8 BTAsocCount; ++ u8 bStartSendSupervisionPkt; ++ u8 BtOperationOn; ++ u8 BTNeedAMPStatusChg; ++ u8 JoinerNeedSendAuth; ++ HCI_PHY_LINK_BSS_INFO bssDesc; ++ HCI_EXT_CONFIG ExtConfig; ++ u8 bNeedNotifyAMPNoCap; ++ u8 bCreateSpportQos; ++ u8 bSupportProfile; ++ u8 BTChannel; ++ u8 CheckChnlIsSuit; ++ u8 bBtScan; ++ u8 btLogoTest; ++} BT_MGNT, *PBT_MGNT; ++ ++typedef struct _BT_HCI_DBG_INFO ++{ ++ u32 hciCmdCnt; ++ u32 hciCmdCntUnknown; ++ u32 hciCmdCntCreatePhyLink; ++ u32 hciCmdCntAcceptPhyLink; ++ u32 hciCmdCntDisconnectPhyLink; ++ u32 hciCmdPhyLinkStatus; ++ u32 hciCmdCntCreateLogLink; ++ u32 hciCmdCntAcceptLogLink; ++ u32 hciCmdCntDisconnectLogLink; ++ u32 hciCmdCntReadLocalAmpAssoc; ++ u32 hciCmdCntWriteRemoteAmpAssoc; ++ u32 hciCmdCntSetAclLinkStatus; ++ u32 hciCmdCntSetScoLinkStatus; ++ u32 hciCmdCntExtensionVersionNotify; ++ u32 hciCmdCntLinkStatusNotify; ++} BT_HCI_DBG_INFO, *PBT_HCI_DBG_INFO; ++ ++typedef struct _BT_IRP_DBG_INFO ++{ ++ u32 irpMJCreate; ++ // Io Control ++ u32 irpIoControl; ++ u32 irpIoCtrlHciCmd; ++ u32 irpIoCtrlHciEvent; ++ u32 irpIoCtrlHciTxData; ++ u32 irpIoCtrlHciRxData; ++ u32 irpIoCtrlUnknown; ++ ++ u32 irpIoCtrlHciTxData1s; ++} BT_IRP_DBG_INFO, *PBT_IRP_DBG_INFO; ++ ++typedef struct _BT_PACKET_DBG_INFO ++{ ++ u32 btPktTxProbReq; ++ u32 btPktRxProbReq; ++ u32 btPktRxProbReqFail; ++ u32 btPktTxProbRsp; ++ u32 btPktRxProbRsp; ++ u32 btPktTxAuth; ++ u32 btPktRxAuth; ++ u32 btPktRxAuthButDrop; ++ u32 btPktTxAssocReq; ++ u32 btPktRxAssocReq; ++ u32 btPktRxAssocReqButDrop; ++ u32 btPktTxAssocRsp; ++ u32 btPktRxAssocRsp; ++ u32 btPktTxDisassoc; ++ u32 btPktRxDisassoc; ++ u32 btPktRxDeauth; ++ u32 btPktTx4way1st; ++ u32 btPktRx4way1st; ++ u32 btPktTx4way2nd; ++ u32 btPktRx4way2nd; ++ u32 btPktTx4way3rd; ++ u32 btPktRx4way3rd; ++ u32 btPktTx4way4th; ++ u32 btPktRx4way4th; ++ u32 btPktTxLinkSuperReq; ++ u32 btPktRxLinkSuperReq; ++ u32 btPktTxLinkSuperRsp; ++ u32 btPktRxLinkSuperRsp; ++ u32 btPktTxData; ++ u32 btPktRxData; ++} BT_PACKET_DBG_INFO, *PBT_PACKET_DBG_INFO; ++ ++typedef struct _BT_DBG ++{ ++ u8 dbgCtrl; ++ u32 dbgProfile; ++ BT_HCI_DBG_INFO dbgHciInfo; ++ BT_IRP_DBG_INFO dbgIrpInfo; ++ BT_PACKET_DBG_INFO dbgBtPkt; ++} BT_DBG, *PBT_DBG; ++ ++typedef struct _BT_HCI_INFO ++{ ++ //802.11 Pal version specifier ++ u8 BTPalVersion; ++ u16 BTPalCompanyID; ++ u16 BTPalsubversion; ++ ++ //Connected channel list ++ u16 BTConnectChnlListLen; ++ u8 BTConnectChnllist[64]; ++ ++ //Fail contact counter ++ u16 FailContactCount; ++ ++ //Event mask ++ u64 BTEventMask; ++ u64 BTEventMaskPage2; ++ ++ //timeout var ++ u16 ConnAcceptTimeout; ++ u16 LogicalAcceptTimeout; ++ u16 PageTimeout; ++ ++ u8 LocationDomainAware; ++ u16 LocationDomain; ++ u8 LocationDomainOptions; ++ u8 LocationOptions; ++ ++ u8 FlowControlMode; ++ ++ //Preferred channel list ++ u16 BtPreChnlListLen; ++ u8 BTPreChnllist[64]; ++ ++ u16 enFlush_LLH; //enhanced flush handle ++ u16 FLTO_LLH; //enhanced flush handle ++ ++ //========================================== ++ //Test command only. ++ u8 bInTestMode; ++ u8 bTestIsEnd; ++ u8 bTestNeedReport; ++ u8 TestScenario; ++ u8 TestReportInterval; ++ u8 TestCtrType; ++ u32 TestEventType; ++ u16 TestNumOfFrame; ++ u16 TestNumOfErrFrame; ++ u16 TestNumOfBits; ++ u16 TestNumOfErrBits; ++ //========================================== ++} BT_HCI_INFO, *PBT_HCI_INFO; ++ ++typedef struct _BT_TRAFFIC ++{ ++ // Add for check replay data ++ u8 LastRxUniFragNum; ++ u16 LastRxUniSeqNum; ++ ++ //s32 EntryMaxUndecoratedSmoothedPWDB; ++ //s32 EntryMinUndecoratedSmoothedPWDB; ++ ++ BT_TRAFFIC_STATISTICS Bt30TrafficStatistics; ++} BT_TRAFFIC, *PBT_TRAFFIC; ++ ++#define RT_WORK_ITEM _workitem ++#define RT_THREAD _thread_hdl_ ++ ++typedef struct _BT_SECURITY ++{ ++ // WPA auth state ++ // May need to remove to BTSecInfo ... ++ //BT_STATE_WPA_AUTH BTWPAAuthState; ++ //u8 PMK[PMK_LEN]; ++ RT_TIMER BTWPAAuthTimer; ++ OCTET_STRING RSNIE; ++ u8 RSNIEBuf[MAXRSNIELEN]; ++ u8 bRegNoEncrypt; ++ u8 bUsedHwEncrypt; // It is define by OS version !! ++} BT_SECURITY, *PBT_SECURITY; ++ ++typedef struct _BT30Info ++{ ++ PADAPTER padapter; ++ BT_ASOC_ENTRY BtAsocEntry[MAX_BT_ASOC_ENTRY_NUM]; ++ BT_MGNT BtMgnt; ++ BT_DBG BtDbg; ++ BT_HCI_INFO BtHciInfo; ++ BT_TRAFFIC BtTraffic; ++ BT_SECURITY BtSec; ++ ++#if(BT_THREAD == 0) ++ RT_WORK_ITEM HCICmdWorkItem; ++ RT_TIMER BTHCICmdTimer; ++#endif ++#if (SENDTXMEHTOD==0) ++ RT_WORK_ITEM HCISendACLDataWorkItem; ++ RT_TIMER BTHCISendAclDataTimer; ++#elif(SENDTXMEHTOD==2) ++ RT_THREAD BTTxThread; ++#endif ++ RT_WORK_ITEM BTPsDisableWorkItem; ++ RT_WORK_ITEM BTConnectWorkItem; ++ RT_TIMER BTHCIDiscardAclDataTimer; ++ RT_TIMER BTHCIJoinTimeoutTimer; ++ RT_TIMER BTTestSendPacketTimer; ++ RT_TIMER BTSupervisionPktTimer; ++ RT_TIMER BTDisconnectPhyLinkTimer; ++ RT_TIMER BTBeaconTimer; ++ u8 BTBeaconTmrOn; ++ ++ RT_TIMER BTPsDisableTimer; ++ RT_TIMER BTAuthTimeoutTimer; ++ RT_TIMER BTAsocTimeoutTimer; ++ ++ PVOID pBtChnlList; ++}BT30Info, *PBT30Info; ++ ++typedef struct _PACKET_IRP_ACL_DATA ++{ ++ u16 Handle:12; ++ u16 PB_Flag:2; ++ u16 BC_Flag:2; ++ u16 Length; ++ u8 Data[1]; ++} PACKET_IRP_ACL_DATA, *PPACKET_IRP_ACL_DATA; ++ ++typedef struct _PACKET_IRP_HCIEVENT_DATA ++{ ++ u8 EventCode; ++ u8 Length; ++ u8 Data[1]; ++} PACKET_IRP_HCIEVENT_DATA, *PPACKET_IRP_HCIEVENT_DATA; ++ ++typedef struct _COMMON_TRIPLE ++{ ++ u8 byte_1st; ++ u8 byte_2nd; ++ u8 byte_3rd; ++} COMMON_TRIPLE, *PCOMMON_TRIPLE; ++ ++#define COUNTRY_STR_LEN 3 // country string len=3 ++ ++#define LOCAL_PMK 0 ++ ++typedef enum _HCI_WIFI_CONNECT_STATUS ++{ ++ HCI_WIFI_NOT_CONNECTED =0x0, ++ HCI_WIFI_CONNECTED =0x1, ++ HCI_WIFI_CONNECT_IN_PROGRESS =0x2, ++} HCI_WIFI_CONNECT_STATUS, *PHCI_WIFI_CONNECT_STATUS; ++ ++typedef enum _HCI_EXT_BT_OPERATION ++{ ++ HCI_BT_OP_NONE = 0x0, ++ HCI_BT_OP_INQUIRY_START = 0x1, ++ HCI_BT_OP_INQUIRY_FINISH = 0x2, ++ HCI_BT_OP_PAGING_START = 0x3, ++ HCI_BT_OP_PAGING_SUCCESS = 0x4, ++ HCI_BT_OP_PAGING_UNSUCCESS = 0x5, ++ HCI_BT_OP_PAIRING_START = 0x6, ++ HCI_BT_OP_PAIRING_FINISH = 0x7, ++ HCI_BT_OP_BT_DEV_ENABLE = 0x8, ++ HCI_BT_OP_BT_DEV_DISABLE = 0x9, ++ HCI_BT_OP_MAX ++} HCI_EXT_BT_OPERATION, *PHCI_EXT_BT_OPERATION; ++ ++//====================================== ++// Function proto type ++//====================================== ++#define RT_LIST_ENTRY _list ++typedef struct _BTData_ENTRY ++{ ++ RT_LIST_ENTRY List; ++ void *pDataBlock; ++} BTData_ENTRY, *PBTData_ENTRY; ++ ++#define BTHCI_SM_WITH_INFO(_Adapter, _StateToEnter, _StateCmd, _EntryNum) \ ++{ \ ++ RTPRINT(FIOCTL, IOCTL_STATE, ("[BT state change] caused by ""%s"", line=%d\n", __FUNCTION__, __LINE__)); \ ++ BTHCI_StateMachine(_Adapter, _StateToEnter, _StateCmd, _EntryNum);\ ++} ++ ++void BTHCI_EventParse(PADAPTER padapter, void *pEvntData, u32 dataLen); ++#define BT_EventParse BTHCI_EventParse ++u8 BTHCI_HsConnectionEstablished(PADAPTER padapter); ++void BTHCI_UpdateBTProfileRTKToMoto(PADAPTER padapter); ++void BTHCI_WifiScanNotify(PADAPTER padapter, u8 scanType); ++void BTHCI_StateMachine(PADAPTER padapter, u8 StateToEnter, HCI_STATE_WITH_CMD StateCmd, u8 EntryNum); ++void BTHCI_DisconnectPeer(PADAPTER padapter, u8 EntryNum); ++void BTHCI_EventNumOfCompletedDataBlocks(PADAPTER padapter); ++void BTHCI_EventAMPStatusChange(PADAPTER padapter, u8 AMP_Status); ++void BTHCI_DisconnectAll(PADAPTER padapter); ++HCI_STATUS BTHCI_HandleHCICMD(PADAPTER padapter, PPACKET_IRP_HCICMD_DATA pHciCmd); ++ ++// ===== End of sync from SD7 driver COMMON/bt_hci.h ===== ++#endif // __BT_HCI_C__ ++ ++#ifdef __HALBTC87231ANT_C__ // HAL/BTCoexist/HalBtc87231Ant.h ++// ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc87231Ant.h ===== ++#define GET_BT_INFO(padapter) (&GET_HAL_DATA(padapter)->BtInfo) ++ ++#define BTC_FOR_SCAN_START 1 ++#define BTC_FOR_SCAN_FINISH 0 ++ ++#define BT_TXRX_CNT_THRES_1 1200 ++#define BT_TXRX_CNT_THRES_2 1400 ++#define BT_TXRX_CNT_THRES_3 3000 ++#define BT_TXRX_CNT_LEVEL_0 0 // < 1200 ++#define BT_TXRX_CNT_LEVEL_1 1 // >= 1200 && < 1400 ++#define BT_TXRX_CNT_LEVEL_2 2 // >= 1400 ++#define BT_TXRX_CNT_LEVEL_3 3 // >= 3000 ++ ++typedef enum _BT_STATE_1ANT{ ++ BT_INFO_STATE_DISABLED = 0, ++ BT_INFO_STATE_NO_CONNECTION = 1, ++ BT_INFO_STATE_CONNECT_IDLE = 2, ++ BT_INFO_STATE_INQ_OR_PAG = 3, ++ BT_INFO_STATE_ACL_ONLY_BUSY = 4, ++ BT_INFO_STATE_SCO_ONLY_BUSY = 5, ++ BT_INFO_STATE_ACL_SCO_BUSY = 6, ++ BT_INFO_STATE_ACL_INQ_OR_PAG = 7, ++ BT_INFO_STATE_MAX = 8 ++} BT_STATE_1ANT, *PBT_STATE_1ANT; ++ ++typedef struct _BTDM_8723A_1ANT ++{ ++ u8 prePsTdma; ++ u8 curPsTdma; ++ u8 psTdmaDuAdjType; ++ u8 bPrePsTdmaOn; ++ u8 bCurPsTdmaOn; ++ u8 preWifiPara; ++ u8 curWifiPara; ++ u8 preCoexWifiCon; ++ u8 curCoexWifiCon; ++ u8 wifiRssiThresh; ++ ++ u32 psTdmaMonitorCnt; ++ u32 psTdmaGlobalCnt; ++ ++ //DurationAdjust For SCO ++ u32 psTdmaMonitorCntForSCO; ++ u8 psTdmaDuAdjTypeForSCO; ++ u8 RSSI_WiFi_Last; ++ u8 RSSI_BT_Last; ++ ++ u8 bWiFiHalt; ++ u8 bRAChanged; ++} BTDM_8723A_1ANT, *PBTDM_8723A_1ANT; ++ ++void BTDM_1AntSignalCompensation(PADAPTER padapter, u8 *rssi_wifi, u8 *rssi_bt); ++void BTDM_1AntForDhcp(PADAPTER padapter); ++void BTDM_1AntBtCoexist8723A(PADAPTER padapter); ++ ++// ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc87231Ant.h ===== ++#endif // __HALBTC87231ANT_C__ ++ ++#ifdef __HALBTC87232ANT_C__ // HAL/BTCoexist/HalBtc87232Ant.h ++// ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc87232Ant.h ===== ++typedef enum _BT_2ANT_BT_STATUS{ ++ BT_2ANT_BT_STATUS_IDLE = 0x0, ++ BT_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, ++ BT_2ANT_BT_STATUS_NON_IDLE = 0x2, ++ BT_2ANT_BT_STATUS_MAX ++}BT_2ANT_BT_STATUS,*PBT_2ANT_BT_STATUS; ++ ++typedef enum _BT_2ANT_COEX_ALGO{ ++ BT_2ANT_COEX_ALGO_UNDEFINED = 0x0, ++ BT_2ANT_COEX_ALGO_SCO = 0x1, ++ BT_2ANT_COEX_ALGO_HID = 0x2, ++ BT_2ANT_COEX_ALGO_A2DP = 0x3, ++ BT_2ANT_COEX_ALGO_PANEDR = 0x4, ++ BT_2ANT_COEX_ALGO_PANHS = 0x5, ++ BT_2ANT_COEX_ALGO_PANEDR_A2DP = 0x6, ++ BT_2ANT_COEX_ALGO_PANEDR_HID = 0x7, ++ BT_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x8, ++ BT_2ANT_COEX_ALGO_HID_A2DP = 0x9, ++ BT_2ANT_COEX_ALGO_HID_A2DP_PANHS = 0xA, ++ BT_2ANT_COEX_ALGO_MAX = 0xB, ++}BT_2ANT_COEX_ALGO,*PBT_2ANT_COEX_ALGO; ++ ++typedef struct _BTDM_8723A_2ANT ++{ ++ u8 bPreDecBtPwr; ++ u8 bCurDecBtPwr; ++ ++ u8 preWlanActHi; ++ u8 curWlanActHi; ++ u8 preWlanActLo; ++ u8 curWlanActLo; ++ ++ u8 preFwDacSwingLvl; ++ u8 curFwDacSwingLvl; ++ ++ u8 bPreRfRxLpfShrink; ++ u8 bCurRfRxLpfShrink; ++ ++ u8 bPreLowPenaltyRa; ++ u8 bCurLowPenaltyRa; ++ ++ u8 preBtRetryIndex; ++ u8 curBtRetryIndex; ++ ++ u8 bPreDacSwingOn; ++ u32 preDacSwingLvl; ++ u8 bCurDacSwingOn; ++ u32 curDacSwingLvl; ++ ++ u8 bPreAdcBackOff; ++ u8 bCurAdcBackOff; ++ ++ u8 bPreAgcTableEn; ++ u8 bCurAgcTableEn; ++ ++ u32 preVal0x6c0; ++ u32 curVal0x6c0; ++ u32 preVal0x6c8; ++ u32 curVal0x6c8; ++ u8 preVal0x6cc; ++ u8 curVal0x6cc; ++ ++ u8 bCurIgnoreWlanAct; ++ u8 bPreIgnoreWlanAct; ++ ++ u8 prePsTdma; ++ u8 curPsTdma; ++ u8 psTdmaDuAdjType; ++ u8 bPrePsTdmaOn; ++ u8 bCurPsTdmaOn; ++ ++ u8 preAlgorithm; ++ u8 curAlgorithm; ++ u8 bResetTdmaAdjust; ++ ++ ++ u8 btStatus; ++} BTDM_8723A_2ANT, *PBTDM_8723A_2ANT; ++void BTDM_2AntBtCoexist8723A(PADAPTER padapter); ++// ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc87232Ant.h ===== ++#endif // __HALBTC87232ANT_C__ ++ ++#ifdef __HALBTC8723_C__ // HAL/BTCoexist/HalBtc8723.h ++// ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc8723.h ===== ++ ++#define BT_Q_PKT_OFF 0 ++#define BT_Q_PKT_ON 1 ++ ++#define BT_TX_PWR_OFF 0 ++#define BT_TX_PWR_ON 1 ++ ++// TDMA mode definition ++#define TDMA_2ANT 0 ++#define TDMA_1ANT 1 ++#define TDMA_NAV_OFF 0 ++#define TDMA_NAV_ON 1 ++#define TDMA_DAC_SWING_OFF 0 ++#define TDMA_DAC_SWING_ON 1 ++ ++#define BT_RSSI_LEVEL_H 0 ++#define BT_RSSI_LEVEL_M 1 ++#define BT_RSSI_LEVEL_L 2 ++ ++// PTA mode related definition ++#define BT_PTA_MODE_OFF 0 ++#define BT_PTA_MODE_ON 1 ++ ++// Penalty Tx Rate Adaptive ++#define BT_TX_RATE_ADAPTIVE_NORMAL 0 ++#define BT_TX_RATE_ADAPTIVE_LOW_PENALTY 1 ++ ++// RF Corner ++#define BT_RF_RX_LPF_CORNER_RESUME 0 ++#define BT_RF_RX_LPF_CORNER_SHRINK 1 ++ ++#define BT_INFO_ACL BIT(0) ++#define BT_INFO_SCO BIT(1) ++#define BT_INFO_INQ_PAG BIT(2) ++#define BT_INFO_ACL_BUSY BIT(3) ++#define BT_INFO_SCO_BUSY BIT(4) ++#define BT_INFO_HID BIT(5) ++#define BT_INFO_A2DP BIT(6) ++#define BT_INFO_FTP BIT(7) ++ ++ ++ ++typedef struct _BT_COEXIST_8723A ++{ ++ u32 highPriorityTx; ++ u32 highPriorityRx; ++ u32 lowPriorityTx; ++ u32 lowPriorityRx; ++ u8 btRssi; ++ u8 TotalAntNum; ++ u8 bC2hBtInfoSupport; ++ u8 c2hBtInfo; ++ u8 c2hBtInfoOriginal; ++ u8 prec2hBtInfo; // for 1Ant ++ u8 bC2hBtInquiryPage; ++ u64 btInqPageStartTime; // for 2Ant ++ u8 c2hBtProfile; // for 1Ant ++ u8 btRetryCnt; ++ u16 AclTp; ++ u8 btInfoExt; ++ u8 bC2hBtInfoReqSent; ++ u8 bForceFwBtInfo; ++ u8 bForceA2dpSink; ++// u8 bForceLps; ++// u8 bBtPwrSaveMode; ++ BTDM_8723A_2ANT btdm2Ant; ++ BTDM_8723A_1ANT btdm1Ant; ++} BT_COEXIST_8723A, *PBT_COEXIST_8723A; ++ ++void BTDM_SetFwChnlInfo(PADAPTER padapter, RT_MEDIA_STATUS mstatus); ++u8 BTDM_IsWifiConnectionExist(PADAPTER padapter); ++void BTDM_SetFw3a(PADAPTER padapter, u8 byte1, u8 byte2, u8 byte3, u8 byte4, u8 byte5); ++void BTDM_QueryBtInformation(PADAPTER padapter); ++void BTDM_SetSwRfRxLpfCorner(PADAPTER padapter, u8 type); ++void BTDM_SetSwPenaltyTxRateAdaptive(PADAPTER padapter, u8 raType); ++void BTDM_SetFwDecBtPwr(PADAPTER padapter, u8 bDecBtPwr); ++u8 BTDM_BtProfileSupport(PADAPTER padapter); ++void BTDM_LpsLeave(PADAPTER padapter); ++u8 BTDM_1Ant8723A(PADAPTER padapter); ++u8 BTDM_GetBtState8723A(PADAPTER padapter); ++u8 BTDM_IsBtInquiryPage8723A(PADAPTER padapter); ++#define BT_1Ant BTDM_1Ant8723A ++#define BT_GetBtState BTDM_GetBtState8723A ++#define BT_IsBtInquiryPage BTDM_IsBtInquiryPage8723A ++ ++// ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc8723.h ===== ++#endif // __HALBTC8723_C__ ++ ++#ifdef __HALBTCCSR1ANT_C__ // HAL/BTCoexist/HalBtcCsr1Ant.h ++// ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtcCsr1Ant.h ===== ++ ++enum BT_A2DP_INDEX{ ++ BT_A2DP_INDEX0 =0, // 32,12; the most critical for BT ++ BT_A2DP_INDEX1, // 12,24 ++ BT_A2DP_INDEX2, // 0,0 ++ BT_A2DP_INDEX_MAX ++}; ++ ++#define BT_A2DP_STATE_NOT_ENTERED 0 ++#define BT_A2DP_STATE_DETECTING 1 ++#define BT_A2DP_STATE_DETECTED 2 ++ ++#define BTDM_ANT_BT_IDLE 0 ++#define BTDM_ANT_WIFI 1 ++#define BTDM_ANT_BT 2 ++ ++ ++void BTDM_SingleAnt(PADAPTER padapter, u8 bSingleAntOn, u8 bInterruptOn, u8 bMultiNAVOn); ++void BTDM_CheckBTIdleChange1Ant(PADAPTER padapter); ++ ++// ===== End of sync from SD7 driver HAL/BTCoexist/HalBtcCsr1Ant.h ===== ++#endif // __HALBTCCSR1ANT_C__ ++ ++#ifdef __HALBTCCSR2ANT_C__ // HAL/BTCoexist/HalBtcCsr2Ant.h ++// ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtcCsr2Ant.h ===== ++ ++//=========================================== ++// For old core stack before v251 ++//=========================================== ++#define BT_RSSI_STATE_NORMAL_POWER BIT0 ++#define BT_RSSI_STATE_AMDPU_OFF BIT1 ++#define BT_RSSI_STATE_SPECIAL_LOW BIT2 ++#define BT_RSSI_STATE_BG_EDCA_LOW BIT3 ++#define BT_RSSI_STATE_TXPOWER_LOW BIT4 ++ ++#define BT_DACSWING_OFF 0 ++#define BT_DACSWING_M4 1 ++#define BT_DACSWING_M7 2 ++#define BT_DACSWING_M10 3 ++ ++void BTDM_DiminishWiFi(PADAPTER Adapter, u8 bDACOn, u8 bInterruptOn, u8 DACSwingLevel, u8 bNAVOn); ++ ++// ===== End of sync from SD7 driver HAL/BTCoexist/HalBtcCsr2Ant.h ===== ++#endif // __HALBTCCSR2ANT_C__ ++ ++#ifdef __HALBTCOEXIST_C__ // HAL/BTCoexist/HalBtCoexist.h ++ ++// HEADER/TypeDef.h ++#define MAX_FW_SUPPORT_MACID_NUM 64 ++#define WIFI_BUSY_TRAFFIC_TH 25 ++ ++// ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtCoexist.h ===== ++ ++#define FW_VER_BT_REG 62 ++#define FW_VER_BT_REG1 74 ++#define REG_BT_ACTIVE 0x444 ++#define REG_BT_STATE 0x448 ++#define REG_BT_POLLING1 0x44c ++#define REG_BT_POLLING 0x700 ++ ++#define REG_BT_ACTIVE_OLD 0x488 ++#define REG_BT_STATE_OLD 0x48c ++#define REG_BT_POLLING_OLD 0x490 ++ ++// The reg define is for 8723 ++#define REG_HIGH_PRIORITY_TXRX 0x770 ++#define REG_LOW_PRIORITY_TXRX 0x774 ++ ++#define BT_FW_COEX_THRESH_TOL 6 ++#define BT_FW_COEX_THRESH_20 20 ++#define BT_FW_COEX_THRESH_23 23 ++#define BT_FW_COEX_THRESH_25 25 ++#define BT_FW_COEX_THRESH_30 30 ++#define BT_FW_COEX_THRESH_35 35 ++#define BT_FW_COEX_THRESH_40 40 ++#define BT_FW_COEX_THRESH_45 45 ++#define BT_FW_COEX_THRESH_47 47 ++#define BT_FW_COEX_THRESH_50 50 ++#define BT_FW_COEX_THRESH_55 55 ++#define BT_FW_COEX_THRESH_65 65 ++ ++#define BT_COEX_STATE_BT30 BIT(0) ++#define BT_COEX_STATE_WIFI_HT20 BIT(1) ++#define BT_COEX_STATE_WIFI_HT40 BIT(2) ++#define BT_COEX_STATE_WIFI_LEGACY BIT(3) ++ ++#define BT_COEX_STATE_WIFI_RSSI_LOW BIT(4) ++#define BT_COEX_STATE_WIFI_RSSI_MEDIUM BIT(5) ++#define BT_COEX_STATE_WIFI_RSSI_HIGH BIT(6) ++#define BT_COEX_STATE_DEC_BT_POWER BIT(7) ++ ++#define BT_COEX_STATE_WIFI_IDLE BIT(8) ++#define BT_COEX_STATE_WIFI_UPLINK BIT(9) ++#define BT_COEX_STATE_WIFI_DOWNLINK BIT(10) ++ ++#define BT_COEX_STATE_BT_INQ_PAGE BIT(11) ++#define BT_COEX_STATE_BT_IDLE BIT(12) ++#define BT_COEX_STATE_BT_UPLINK BIT(13) ++#define BT_COEX_STATE_BT_DOWNLINK BIT(14) ++//=========================================== ++// Todo: Remove these definitions ++#define BT_COEX_STATE_BT_PAN_IDLE BIT(15) ++#define BT_COEX_STATE_BT_PAN_UPLINK BIT(16) ++#define BT_COEX_STATE_BT_PAN_DOWNLINK BIT(17) ++#define BT_COEX_STATE_BT_A2DP_IDLE BIT(18) ++//=========================================== ++#define BT_COEX_STATE_BT_RSSI_LOW BIT(19) ++ ++#define BT_COEX_STATE_PROFILE_HID BIT(20) ++#define BT_COEX_STATE_PROFILE_A2DP BIT(21) ++#define BT_COEX_STATE_PROFILE_PAN BIT(22) ++#define BT_COEX_STATE_PROFILE_SCO BIT(23) ++ ++#define BT_COEX_STATE_WIFI_RSSI_1_LOW BIT(24) ++#define BT_COEX_STATE_WIFI_RSSI_1_MEDIUM BIT(25) ++#define BT_COEX_STATE_WIFI_RSSI_1_HIGH BIT(26) ++ ++#define BT_COEX_STATE_WIFI_RSSI_BEACON_LOW BIT(27) ++#define BT_COEX_STATE_WIFI_RSSI_BEACON_MEDIUM BIT(28) ++#define BT_COEX_STATE_WIFI_RSSI_BEACON_HIGH BIT(29) ++ ++ ++#define BT_COEX_STATE_BTINFO_COMMON BIT30 ++#define BT_COEX_STATE_BTINFO_B_HID_SCOESCO BIT31 ++#define BT_COEX_STATE_BTINFO_B_FTP_A2DP BIT32 ++ ++#define BT_COEX_STATE_BT_CNT_LEVEL_0 BIT33 ++#define BT_COEX_STATE_BT_CNT_LEVEL_1 BIT34 ++#define BT_COEX_STATE_BT_CNT_LEVEL_2 BIT35 ++#define BT_COEX_STATE_BT_CNT_LEVEL_3 BIT36 ++ ++#define BT_RSSI_STATE_HIGH 0 ++#define BT_RSSI_STATE_MEDIUM 1 ++#define BT_RSSI_STATE_LOW 2 ++#define BT_RSSI_STATE_STAY_HIGH 3 ++#define BT_RSSI_STATE_STAY_MEDIUM 4 ++#define BT_RSSI_STATE_STAY_LOW 5 ++ ++ ++ ++#define BT_AGCTABLE_OFF 0 ++#define BT_AGCTABLE_ON 1 ++ ++#define BT_BB_BACKOFF_OFF 0 ++#define BT_BB_BACKOFF_ON 1 ++ ++#define BT_FW_NAV_OFF 0 ++#define BT_FW_NAV_ON 1 ++ ++ ++#define BT_COEX_MECH_NONE 0 ++#define BT_COEX_MECH_SCO 1 ++#define BT_COEX_MECH_HID 2 ++#define BT_COEX_MECH_A2DP 3 ++#define BT_COEX_MECH_PAN 4 ++#define BT_COEX_MECH_HID_A2DP 5 ++#define BT_COEX_MECH_HID_PAN 6 ++#define BT_COEX_MECH_PAN_A2DP 7 ++#define BT_COEX_MECH_HID_SCO_ESCO 8 ++#define BT_COEX_MECH_FTP_A2DP 9 ++#define BT_COEX_MECH_COMMON 10 ++#define BT_COEX_MECH_MAX 11 ++//=========================================== ++// BT Dbg Ctrl ++//=========================================== ++#define BT_DBG_PROFILE_NONE 0 ++#define BT_DBG_PROFILE_SCO 1 ++#define BT_DBG_PROFILE_HID 2 ++#define BT_DBG_PROFILE_A2DP 3 ++#define BT_DBG_PROFILE_PAN 4 ++#define BT_DBG_PROFILE_HID_A2DP 5 ++#define BT_DBG_PROFILE_HID_PAN 6 ++#define BT_DBG_PROFILE_PAN_A2DP 7 ++#define BT_DBG_PROFILE_MAX 9 ++//=========================================== ++ ++typedef struct _BT_COEXIST_STR ++{ ++ u8 BluetoothCoexist; ++ u8 BT_Ant_Num; ++ u8 BT_CoexistType; ++ u8 BT_Ant_isolation; //0:good, 1:bad ++ u8 BT_RadioSharedType; ++ u32 Ratio_Tx; ++ u32 Ratio_PRI; ++ u8 bInitlized; ++ u32 BtRfRegOrigin1E; ++ u32 BtRfRegOrigin1F; ++ u8 bBTBusyTraffic; ++ u8 bBTTrafficModeSet; ++ u8 bBTNonTrafficModeSet; ++ BT_TRAFFIC_STATISTICS BT21TrafficStatistics; ++ u64 CurrentState; ++ u64 PreviousState; ++ u8 preRssiState; ++ u8 preRssiState1; ++ u8 preRssiStateBeacon; ++ u8 bFWCoexistAllOff; ++ u8 bSWCoexistAllOff; ++ u8 bHWCoexistAllOff; ++ u8 bBalanceOn; ++ u8 bSingleAntOn; ++ u8 bInterruptOn; ++ u8 bMultiNAVOn; ++ u8 PreWLANActH; ++ u8 PreWLANActL; ++ u8 WLANActH; ++ u8 WLANActL; ++ u8 A2DPState; ++ u8 AntennaState; ++ u32 lastBtEdca; ++ u16 last_aggr_num; ++ u8 bEDCAInitialized; ++ u8 exec_cnt; ++ u8 b8723aAgcTableOn; ++ u8 b92DAgcTableOn; ++ BT_COEXIST_8723A halCoex8723; ++ u8 btActiveZeroCnt; ++ u8 bCurBtDisabled; ++ u8 bPreBtDisabled; ++ u8 bNeedToRoamForBtDisableEnable; ++ u8 fw3aVal[5]; ++}BT_COEXIST_STR, *PBT_COEXIST_STR; ++ ++ ++void BTDM_CheckAntSelMode(PADAPTER padapter); ++void BTDM_FwC2hBtRssi(PADAPTER padapter, u8 *tmpBuf); ++#define BT_FwC2hBtRssi BTDM_FwC2hBtRssi ++void BTDM_FwC2hBtInfo(PADAPTER padapter, u8 *tmpBuf, u8 length); ++#define BT_FwC2hBtInfo BTDM_FwC2hBtInfo ++void BTDM_DisplayBtCoexInfo(PADAPTER padapter); ++#define BT_DisplayBtCoexInfo BTDM_DisplayBtCoexInfo ++void BTDM_RejectAPAggregatedPacket(PADAPTER padapter, u8 bReject); ++u8 BTDM_IsHT40(PADAPTER padapter); ++u8 BTDM_Legacy(PADAPTER padapter); ++void BTDM_CheckWiFiState(PADAPTER padapter); ++s32 BTDM_GetRxSS(PADAPTER padapter); ++u8 BTDM_CheckCoexBcnRssiState(PADAPTER padapter, u8 levelNum, u8 RssiThresh, u8 RssiThresh1); ++u8 BTDM_CheckCoexRSSIState1(PADAPTER padapter, u8 levelNum, u8 RssiThresh, u8 RssiThresh1); ++u8 BTDM_CheckCoexRSSIState(PADAPTER padapter, u8 levelNum, u8 RssiThresh, u8 RssiThresh1); ++u8 BTDM_DisableEDCATurbo(PADAPTER padapter); ++#define BT_DisableEDCATurbo BTDM_DisableEDCATurbo ++void BTDM_Balance(PADAPTER padapter, u8 bBalanceOn, u8 ms0, u8 ms1); ++void BTDM_AGCTable(PADAPTER padapter, u8 type); ++void BTDM_BBBackOffLevel(PADAPTER padapter, u8 type); ++void BTDM_FWCoexAllOff(PADAPTER padapter); ++void BTDM_SWCoexAllOff(PADAPTER padapter); ++void BTDM_HWCoexAllOff(PADAPTER padapter); ++void BTDM_CoexAllOff(PADAPTER padapter); ++void BTDM_TurnOffBtCoexistBeforeEnterIPS(PADAPTER padapter); ++void BTDM_SignalCompensation(PADAPTER padapter, u8 *rssi_wifi, u8 *rssi_bt); ++void BTDM_Coexist(PADAPTER padapter); ++#define BT_CoexistMechanism BTDM_Coexist ++void BTDM_UpdateCoexState(PADAPTER padapter); ++u8 BTDM_IsSameCoexistState(PADAPTER padapter); ++void BTDM_PWDBMonitor(PADAPTER padapter); ++u8 BTDM_IsBTBusy(PADAPTER padapter); ++#define BT_IsBtBusy BTDM_IsBTBusy ++u8 BTDM_IsWifiBusy(PADAPTER padapter); ++u8 BTDM_IsCoexistStateChanged(PADAPTER padapter); ++u8 BTDM_IsWifiUplink(PADAPTER padapter); ++u8 BTDM_IsWifiDownlink(PADAPTER padapter); ++u8 BTDM_IsBTHSMode(PADAPTER padapter); ++u8 BTDM_IsBTUplink(PADAPTER padapter); ++u8 BTDM_IsBTDownlink(PADAPTER padapter); ++void BTDM_AdjustForBtOperation(PADAPTER padapter); ++void BTDM_ForHalt(PADAPTER padapter); ++void BTDM_WifiScanNotify(PADAPTER padapter, u8 scanType); ++void BTDM_WifiAssociateNotify(PADAPTER padapter, u8 action); ++void BTDM_MediaStatusNotify(PADAPTER padapter, RT_MEDIA_STATUS mstatus); ++void BTDM_ForDhcp(PADAPTER padapter); ++void BTDM_ResetActionProfileState(PADAPTER padapter); ++void BTDM_SetBtCoexCurrAntNum(PADAPTER padapter, u8 antNum); ++#define BT_SetBtCoexCurrAntNum BTDM_SetBtCoexCurrAntNum ++u8 BTDM_IsActionSCO(PADAPTER padapter); ++u8 BTDM_IsActionHID(PADAPTER padapter); ++u8 BTDM_IsActionA2DP(PADAPTER padapter); ++u8 BTDM_IsActionPAN(PADAPTER padapter); ++u8 BTDM_IsActionHIDA2DP(PADAPTER padapter); ++u8 BTDM_IsActionHIDPAN(PADAPTER padapter); ++u8 BTDM_IsActionPANA2DP(PADAPTER padapter); ++u8 BTDM_IsBtDisabled(PADAPTER padapter); ++#define BT_IsBtDisabled BTDM_IsBtDisabled ++sint BTDM_CheckFWState(PADAPTER padapter, sint state); ++u32 BTDM_BtTxRxCounterH(PADAPTER padapter); ++u32 BTDM_BtTxRxCounterL(PADAPTER padapter); ++ ++// ===== End of sync from SD7 driver HAL/BTCoexist/HalBtCoexist.h ===== ++#endif // __HALBTCOEXIST_C__ ++ ++#ifdef __HALBT_C__ // HAL/HalBT.h ++// ===== Below this line is sync from SD7 driver HAL/HalBT.h ===== ++ ++#define RTS_CTS_NO_LEN_LIMIT 0 ++ ++u8 HALBT_GetPGAntNum(PADAPTER padapter); ++#define BT_GetPGAntNum HALBT_GetPGAntNum ++void HALBT_SetKey(PADAPTER padapter, u8 EntryNum); ++void HALBT_RemoveKey(PADAPTER padapter, u8 EntryNum); ++void HALBT_InitBTVars8723A(PADAPTER padapter); ++#define HALBT_InitHalVars HALBT_InitBTVars8723A ++#define BT_InitHalVars HALBT_InitHalVars ++u8 HALBT_IsBTExist(PADAPTER padapter); ++#define BT_IsBtExist HALBT_IsBTExist ++u8 HALBT_BTChipType(PADAPTER padapter); ++void HALBT_InitHwConfig(PADAPTER padapter); ++#define BT_InitHwConfig HALBT_InitHwConfig ++void HALBT_SetRtsCtsNoLenLimit(PADAPTER padapter); ++ ++// ===== End of sync from SD7 driver HAL/HalBT.c ===== ++#endif // __HALBT_C__ ++ ++#define _bt_dbg_off_ 0 ++#define _bt_dbg_on_ 1 ++ ++extern u32 BTCoexDbgLevel; ++ ++ ++ ++#endif // __RTL8723A_BT_COEXIST_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_cmd.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_cmd.h +new file mode 100644 +index 00000000..91202dc2 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_cmd.h +@@ -0,0 +1,229 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8723A_CMD_H__ ++#define __RTL8723A_CMD_H__ ++ ++ ++#define H2C_BT_FW_PATCH_LEN 3 ++#define H2C_BT_PWR_FORCE_LEN 3 ++ ++enum cmd_msg_element_id ++{ ++ NONE_CMDMSG_EID, ++ AP_OFFLOAD_EID = 0, ++ SET_PWRMODE_EID = 1, ++ JOINBSS_RPT_EID = 2, ++ RSVD_PAGE_EID = 3, ++ RSSI_4_EID = 4, ++ RSSI_SETTING_EID = 5, ++ MACID_CONFIG_EID = 6, ++ MACID_PS_MODE_EID = 7, ++ P2P_PS_OFFLOAD_EID = 8, ++ SELECTIVE_SUSPEND_ROF_CMD = 9, ++ BT_QUEUE_PKT_EID = 17, ++ BT_ANT_TDMA_EID = 20, ++ BT_2ANT_HID_EID = 21, ++ P2P_PS_CTW_CMD_EID = 32, ++ FORCE_BT_TX_PWR_EID = 33, ++ SET_TDMA_WLAN_ACT_TIME_EID = 34, ++ SET_BT_TX_RETRY_INDEX_EID = 35, ++ HID_PROFILE_ENABLE_EID = 36, ++ BT_IGNORE_WLAN_ACT_EID = 37, ++ BT_PTA_MANAGER_UPDATE_ENABLE_EID = 38, ++ DAC_SWING_VALUE_EID = 41, ++ TRADITIONAL_TDMA_EN_EID = 51, ++ H2C_BT_FW_PATCH = 54, ++ B_TYPE_TDMA_EID = 58, ++ SCAN_EN_EID = 59, ++ LOWPWR_LPS_EID = 71, ++ H2C_RESET_TSF = 75, ++ MAX_CMDMSG_EID ++}; ++ ++struct cmd_msg_parm { ++ u8 eid; //element id ++ u8 sz; // sz ++ u8 buf[6]; ++}; ++ ++typedef struct _SETPWRMODE_PARM ++{ ++ u8 Mode; ++ u8 SmartPS; ++ u8 AwakeInterval; // unit: beacon interval ++ u8 bAllQueueUAPSD; ++ ++#if 0 ++ u8 LowRxBCN:1; ++ u8 AutoAntSwitch:1; ++ u8 PSAllowBTHighPriority:1; ++ u8 rsvd43:5; ++#else ++#define SETPM_LOWRXBCN BIT(0) ++#define SETPM_AUTOANTSWITCH BIT(1) ++#define SETPM_PSALLOWBTHIGHPRI BIT(2) ++ u8 BcnAntMode; ++#endif ++}__attribute__((__packed__)) SETPWRMODE_PARM, *PSETPWRMODE_PARM; ++ ++struct H2C_SS_RFOFF_PARAM{ ++ u8 ROFOn; // 1: on, 0:off ++ u16 gpio_period; // unit: 1024 us ++}__attribute__ ((packed)); ++ ++ ++typedef struct JOINBSSRPT_PARM{ ++ u8 OpMode; // RT_MEDIA_STATUS ++}JOINBSSRPT_PARM, *PJOINBSSRPT_PARM; ++ ++typedef struct _RSVDPAGE_LOC { ++ u8 LocProbeRsp; ++ u8 LocPsPoll; ++ u8 LocNullData; ++ u8 LocQosNull; ++ u8 LocBTQosNull; ++} RSVDPAGE_LOC, *PRSVDPAGE_LOC; ++ ++struct P2P_PS_Offload_t { ++ u8 Offload_En:1; ++ u8 role:1; // 1: Owner, 0: Client ++ u8 CTWindow_En:1; ++ u8 NoA0_En:1; ++ u8 NoA1_En:1; ++ u8 AllStaSleep:1; // Only valid in Owner ++ u8 discovery:1; ++ u8 rsvd:1; ++}; ++ ++struct P2P_PS_CTWPeriod_t { ++ u8 CTWPeriod; //TU ++}; ++ ++ ++typedef struct _B_TYPE_TDMA_PARM ++{ ++#if 0 ++ u8 En:1; ++ u8 FixAntennaInBTSide:1; ++ u8 TxPspoll:1; ++ u8 val870:1; // value of 870, when disable ++ u8 AutoWakeUp:1; ++ u8 NoPS:1; ++ u8 WlanHighPriority:1; ++ u8 rsvd07:1; ++#else ++#define B_TDMA_EN BIT(0) ++#define B_TDMA_FIXANTINBT BIT(1) ++#define B_TDMA_TXPSPOLL BIT(2) ++#define B_TDMA_VAL870 BIT(3) ++#define B_TDMA_AUTOWAKEUP BIT(4) ++#define B_TDMA_NOPS BIT(5) ++#define B_TDMA_WLANHIGHPRI BIT(6) ++ u8 option; ++#endif ++ ++ u8 TBTTOnPeriod; ++ u8 MedPeriod; ++ u8 rsvd30; ++}__attribute__((__packed__)) B_TYPE_TDMA_PARM, *PB_TYPE_TDMA_PARM; ++ ++typedef struct _SCAN_EN_PARM { ++#if 0 ++ u8 En:1; ++ u8 rsvd01:7; ++#else ++ u8 En; ++#endif ++}__attribute__((__packed__)) SCAN_EN_PARM, *PSCAN_EN_PARM; ++ ++// BT_PWR ++#define SET_H2CCMD_BT_PWR_IDX(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd, 0, 8, __Value) ++ ++// BT_FW_PATCH ++#if 0 ++#define SET_H2CCMD_BT_FW_PATCH_ENABLE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 8, __Value) ++#define SET_H2CCMD_BT_FW_PATCH_SIZE(__pH2CCmd, __Value) SET_BITS_TO_LE_2BYTE((__pH2CCmd)+1, 0, 16, __Value) ++#else ++#define SET_H2CCMD_BT_FW_PATCH_ENABLE(__pH2CCmd, __Value) SET_BITS_TO_LE_4BYTE(__pH2CCmd, 0, 8, __Value) // SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 8, __Value) ++#define SET_H2CCMD_BT_FW_PATCH_SIZE(__pH2CCmd, __Value) SET_BITS_TO_LE_4BYTE(__pH2CCmd, 8, 16, __Value) // SET_BITS_TO_LE_2BYTE((__pH2CCmd)+1, 0, 16, __Value) ++#endif ++ ++#if 0 ++/* ++ * H2C_LOWPWR_LPS ++ * h2c cmd = 71 ++ * byte1[6:0]= bcn count : how many bcn not recevied should return to old mechanism ++ * byte1[7] = enable : enable mechanism ++ * byte2=bcn period : bcn recv time of this AP, unit 32 us ++ * byte3= drop threshold : how many pkts be droped, rx dma should be release ++ * byte4 = max early period ++ * byte5 = max bcn timeout period ++ */ ++#define SET_H2CCMD_LOWPWR_LPS_BCN_COUNT(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 4, __Value) ++#define SET_H2CCMD_LOWPWR_LPS_TB_BCN_THRESH(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 4, 3, __Value) ++#define SET_H2CCMD_LOWPWR_LPS_ENABLE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 7, 1, __Value) ++#define SET_H2CCMD_LOWPWR_LPS_BCN_PERIOD(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+1, 0, 8, __Value) ++#define SET_H2CCMD_LOWPWR_LPS_BCN_DROP_THRESH(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+2, 0, 8, __Value) ++#define SET_H2CCMD_LOWPWR_LPS_MAX_EARLY_PERIOD(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+3, 0, 8, __Value) ++#define SET_H2CCMD_LOWPWR_LPS_MAX_BCN_TO_PERIOD(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+4, 0, 8, __Value) ++#else ++typedef struct _LOWPWR_LPS_PARM ++{ ++ u8 bcn_count:4; ++ u8 tb_bcn_threshold:3; ++ u8 enable:1; ++ u8 bcn_interval; ++ u8 drop_threshold; ++ u8 max_early_period; ++ u8 max_bcn_timeout_period; ++}__attribute__((__packed__)) LOWPWR_LPS_PARM, *PLOWPWR_LPS_PARM; ++#endif ++ ++ ++// host message to firmware cmd ++void rtl8723a_set_FwPwrMode_cmd(PADAPTER padapter, u8 Mode); ++void rtl8723a_set_FwJoinBssReport_cmd(PADAPTER padapter, u8 mstatus); ++#ifdef CONFIG_BT_COEXIST ++void rtl8723a_set_BTCoex_AP_mode_FwRsvdPkt_cmd(PADAPTER padapter); ++#endif ++u8 rtl8192c_set_rssi_cmd(PADAPTER padapter, u8 *param); ++//u8 rtl8723a_set_rssi_cmd(PADAPTER padapter, u8 *param); ++u8 rtl8192c_set_raid_cmd(PADAPTER padapter, u32 mask, u8 arg); ++//u8 rtl8723a_set_raid_cmd(PADAPTER padapter, u32 mask, u8 arg); ++void rtl8192c_Add_RateATid(PADAPTER padapter, u32 bitmap, u8 arg, u8 rssi_level); ++//void rtl8723a_Add_RateATid(PADAPTER padapter, u32 bitmap, u8 arg); ++u8 rtl8192c_set_FwSelectSuspend_cmd(PADAPTER padapter, u8 bfwpoll, u16 period); ++//u8 rtl8723a_set_FwSelectSuspend_cmd(PADAPTER padapter, u8 bfwpoll, u16 period); ++ ++#ifdef CONFIG_P2P ++void rtl8192c_set_p2p_ps_offload_cmd(PADAPTER padapter, u8 p2p_ps_state); ++//void rtl8723a_set_p2p_ps_offload_cmd(PADAPTER padapter, u8 p2p_ps_state); ++#endif //CONFIG_P2P ++ ++void CheckFwRsvdPageContent(PADAPTER padapter); ++ ++void rtl8723a_set_FwMediaStatus_cmd(PADAPTER padapter, u16 mstatus_rpt ); ++ ++#endif ++ ++#ifdef CONFIG_TSF_RESET_OFFLOAD ++u8 rtl8723c_reset_tsf(_adapter *padapter, u8 reset_port); ++#endif // CONFIG_TSF_RESET_OFFLOAD ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_dm.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_dm.h +new file mode 100644 +index 00000000..7b5da5ad +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_dm.h +@@ -0,0 +1,194 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8723A_DM_H__ ++#define __RTL8723A_DM_H__ ++//============================================================ ++// Description: ++// ++// This file is for 8723A dynamic mechanism only ++// ++// ++//============================================================ ++#define DYNAMIC_FUNC_BT BIT(0) ++ ++enum{ ++ UP_LINK, ++ DOWN_LINK, ++}; ++//============================================================ ++// structure and define ++//============================================================ ++ ++//###### duplicate code,will move to ODM ######### ++#define IQK_MAC_REG_NUM 4 ++#define IQK_ADDA_REG_NUM 16 ++#define IQK_BB_REG_NUM 9 ++#define HP_THERMAL_NUM 8 ++//###### duplicate code,will move to ODM ######### ++struct dm_priv ++{ ++ u8 DM_Type; ++ u8 DMFlag; ++ u8 InitDMFlag; ++ u32 InitODMFlag; ++ ++ //* Upper and Lower Signal threshold for Rate Adaptive*/ ++ int UndecoratedSmoothedPWDB; ++ int UndecoratedSmoothedCCK; ++ int EntryMinUndecoratedSmoothedPWDB; ++ int EntryMaxUndecoratedSmoothedPWDB; ++ int MinUndecoratedPWDBForDM; ++ int LastMinUndecoratedPWDBForDM; ++ ++ s32 UndecoratedSmoothedBeacon; ++ #ifdef CONFIG_BT_COEXIST ++ s32 BT_EntryMinUndecoratedSmoothedPWDB; ++ s32 BT_EntryMaxUndecoratedSmoothedPWDB; ++ #endif ++ ++//###### duplicate code,will move to ODM ######### ++/* ++ //for DIG ++ u8 bDMInitialGainEnable; ++ u8 binitialized; // for dm_initial_gain_Multi_STA use. ++ DIG_T DM_DigTable; ++ ++ PS_T DM_PSTable; ++ ++ FALSE_ALARM_STATISTICS FalseAlmCnt; ++ ++ //for rate adaptive, in fact, 88c/92c fw will handle this ++ u8 bUseRAMask; ++ RATE_ADAPTIVE RateAdaptive; ++*/ ++ //for High Power ++ u8 bDynamicTxPowerEnable; ++ u8 LastDTPLvl; ++ u8 DynamicTxHighPowerLvl;//Add by Jacken Tx Power Control for Near/Far Range 2008/03/06 ++ ++ //for tx power tracking ++ u8 bTXPowerTracking; ++ u8 TXPowercount; ++ u8 bTXPowerTrackingInit; ++ u8 TxPowerTrackControl; //for mp mode, turn off txpwrtracking as default ++ u8 TM_Trigger; ++ ++ u8 ThermalMeter[2]; // ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 ++ u8 ThermalValue; ++ u8 ThermalValue_LCK; ++ u8 ThermalValue_IQK; ++ u8 ThermalValue_DPK; ++ ++ u8 bRfPiEnable; ++ ++ //for APK ++ u32 APKoutput[2][2]; //path A/B; output1_1a/output1_2a ++ u8 bAPKdone; ++ u8 bAPKThermalMeterIgnore; ++ u8 bDPdone; ++ u8 bDPPathAOK; ++ u8 bDPPathBOK; ++ ++ //for IQK ++ u32 RegC04; ++ u32 Reg874; ++ u32 RegC08; ++ u32 RegB68; ++ u32 RegB6C; ++ u32 Reg870; ++ u32 Reg860; ++ u32 Reg864; ++ u32 ADDA_backup[IQK_ADDA_REG_NUM]; ++ u32 IQK_MAC_backup[IQK_MAC_REG_NUM]; ++ u32 IQK_BB_backup_recover[9]; ++ u32 IQK_BB_backup[IQK_BB_REG_NUM]; ++ u8 PowerIndex_backup[6]; ++ ++ u8 bCCKinCH14; ++ ++ u8 CCK_index; ++ u8 OFDM_index[2]; ++ ++ u8 bDoneTxpower; ++ u8 CCK_index_HP; ++ u8 OFDM_index_HP[2]; ++ u8 ThermalValue_HP[HP_THERMAL_NUM]; ++ u8 ThermalValue_HP_index; ++ ++ //for TxPwrTracking ++ s32 RegE94; ++ s32 RegE9C; ++ s32 RegEB4; ++ s32 RegEBC; ++ ++ u32 TXPowerTrackingCallbackCnt; //cosa add for debug ++ ++ u32 prv_traffic_idx; // edca turbo ++ ++/* ++ // for dm_RF_Saving ++ u8 initialize; ++ u32 rf_saving_Reg874; ++ u32 rf_saving_RegC70; ++ u32 rf_saving_Reg85C; ++ u32 rf_saving_RegA74; ++*/ ++ //for Antenna diversity ++#ifdef CONFIG_ANTENNA_DIVERSITY ++// SWAT_T DM_SWAT_Table; ++#endif ++ ++#ifdef CONFIG_SW_ANTENNA_DIVERSITY ++// _timer SwAntennaSwitchTimer; ++/* ++ u64 lastTxOkCnt; ++ u64 lastRxOkCnt; ++ u64 TXByteCnt_A; ++ u64 TXByteCnt_B; ++ u64 RXByteCnt_A; ++ u64 RXByteCnt_B; ++ u8 DoubleComfirm; ++ u8 TrafficLoad; ++*/ ++#endif ++ ++ s32 OFDM_Pkt_Cnt; ++ u8 RSSI_Select; ++// u8 DIG_Dynamic_MIN ; ++//###### duplicate code,will move to ODM ######### ++ // Add for Reading Initial Data Rate SEL Register 0x484 during watchdog. Using for fill tx desc. 2011.3.21 by Thomas ++ u8 INIDATA_RATE[32]; ++}; ++ ++ ++//============================================================ ++// function prototype ++//============================================================ ++ ++void rtl8723a_init_dm_priv(PADAPTER padapter); ++void rtl8723a_deinit_dm_priv(PADAPTER padapter); ++ ++void rtl8723a_InitHalDm(PADAPTER padapter); ++void rtl8723a_HalDmWatchDog(PADAPTER padapter); ++ ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_hal.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_hal.h +new file mode 100644 +index 00000000..2111999b +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_hal.h +@@ -0,0 +1,849 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8723A_HAL_H__ ++#define __RTL8723A_HAL_H__ ++ ++#include "rtl8723a_spec.h" ++#include "rtl8723a_pg.h" ++#include "Hal8723APhyReg.h" ++#include "Hal8723APhyCfg.h" ++#include "rtl8723a_rf.h" ++#ifdef CONFIG_BT_COEXIST ++#include "rtl8723a_bt-coexist.h" ++#endif ++#include "rtl8723a_dm.h" ++#include "rtl8723a_recv.h" ++#include "rtl8723a_xmit.h" ++#include "rtl8723a_cmd.h" ++#ifdef DBG_CONFIG_ERROR_DETECT ++#include "rtl8723a_sreset.h" ++#endif ++#include "rtw_efuse.h" ++ ++#include "../hal/OUTSRC/odm_precomp.h" ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ ++ //2TODO: We should define 8192S firmware related macro settings here!! ++ #define RTL819X_DEFAULT_RF_TYPE RF_1T2R ++ #define RTL819X_TOTAL_RF_PATH 2 ++ ++//--------------------------------------------------------------------- ++// RTL8723S From file ++//--------------------------------------------------------------------- ++ #define RTL8723_FW_UMC_IMG "rtl8723S\\rtl8723fw.bin" ++ #define RTL8723_FW_UMC_B_IMG "rtl8723S\\rtl8723fw_B.bin" ++ #define RTL8723_PHY_REG "rtl8723S\\PHY_REG_1T.txt" ++ #define RTL8723_PHY_RADIO_A "rtl8723S\\radio_a_1T.txt" ++ #define RTL8723_PHY_RADIO_B "rtl8723S\\radio_b_1T.txt" ++ #define RTL8723_AGC_TAB "rtl8723S\\AGC_TAB_1T.txt" ++ #define RTL8723_PHY_MACREG "rtl8723S\\MAC_REG.txt" ++ #define RTL8723_PHY_REG_PG "rtl8723S\\PHY_REG_PG.txt" ++ #define RTL8723_PHY_REG_MP "rtl8723S\\PHY_REG_MP.txt" ++ ++//--------------------------------------------------------------------- ++// RTL8723S From header ++//--------------------------------------------------------------------- ++ ++ // Fw Array ++ #define Rtl8723_FwImageArray Rtl8723SFwImgArray ++ #define Rtl8723_FwUMCBCutImageArrayWithBT Rtl8723SFwUMCBCutImgArrayWithBT ++ #define Rtl8723_FwUMCBCutImageArrayWithoutBT Rtl8723SFwUMCBCutImgArrayWithoutBT ++ ++ #define Rtl8723_ImgArrayLength Rtl8723SImgArrayLength ++ #define Rtl8723_UMCBCutImgArrayWithBTLength Rtl8723SUMCBCutImgArrayWithBTLength ++ #define Rtl8723_UMCBCutImgArrayWithoutBTLength Rtl8723SUMCBCutImgArrayWithoutBTLength ++ ++ #define Rtl8723_PHY_REG_Array_PG Rtl8723SPHY_REG_Array_PG ++ #define Rtl8723_PHY_REG_Array_PGLength Rtl8723SPHY_REG_Array_PGLength ++#if MP_DRIVER == 1 ++ #define Rtl8723E_FwBTImgArray Rtl8723EFwBTImgArray ++ #define Rtl8723E_FwBTImgArrayLength Rtl8723EBTImgArrayLength ++ ++ #define Rtl8723_FwUMCBCutMPImageArray Rtl8723SFwUMCBCutMPImgArray ++ #define Rtl8723_UMCBCutMPImgArrayLength Rtl8723SUMCBCutMPImgArrayLength ++ ++ #define Rtl8723_PHY_REG_Array_MP Rtl8723SPHY_REG_Array_MP ++ #define Rtl8723_PHY_REG_Array_MPLength Rtl8723SPHY_REG_Array_MPLength ++#endif ++ ++#ifndef CONFIG_PHY_SETTING_WITH_ODM ++ // MAC/BB/PHY Array ++ #define Rtl8723_MAC_Array Rtl8723SMAC_2T_Array ++ //#define Rtl8723_AGCTAB_2TArray Rtl8723SAGCTAB_2TArray ++ #define Rtl8723_AGCTAB_1TArray Rtl8723SAGCTAB_1TArray ++ //#define Rtl8723_PHY_REG_2TArray Rtl8723SPHY_REG_2TArray ++ #define Rtl8723_PHY_REG_1TArray Rtl8723SPHY_REG_1TArray ++ //#define Rtl8723_RadioA_2TArray Rtl8723SRadioA_2TArray ++ #define Rtl8723_RadioA_1TArray Rtl8723SRadioA_1TArray ++ //#define Rtl8723_RadioB_2TArray Rtl8723SRadioB_2TArray ++ #define Rtl8723_RadioB_1TArray Rtl8723SRadioB_1TArray ++ ++ // Array length ++ #define Rtl8723_MAC_ArrayLength Rtl8723SMAC_2T_ArrayLength ++ #define Rtl8723_AGCTAB_1TArrayLength Rtl8723SAGCTAB_1TArrayLength ++ #define Rtl8723_PHY_REG_1TArrayLength Rtl8723SPHY_REG_1TArrayLength ++ ++ #define Rtl8723_RadioA_1TArrayLength Rtl8723SRadioA_1TArrayLength ++ #define Rtl8723_RadioB_1TArrayLength Rtl8723SRadioB_1TArrayLength ++#endif // CONFIG_PHY_SETTING_WITH_ODM ++#endif // CONFIG_SDIO_HCI ++ ++#ifdef CONFIG_USB_HCI ++ ++ //2TODO: We should define 8192S firmware related macro settings here!! ++ #define RTL819X_DEFAULT_RF_TYPE RF_1T2R ++ #define RTL819X_TOTAL_RF_PATH 2 ++ ++ //TODO: The following need to check!! ++ #define RTL8723_FW_UMC_IMG "rtl8192CU\\rtl8723fw.bin" ++ #define RTL8723_FW_UMC_B_IMG "rtl8192CU\\rtl8723fw_B.bin" ++ #define RTL8723_PHY_REG "rtl8723S\\PHY_REG_1T.txt" ++ #define RTL8723_PHY_RADIO_A "rtl8723S\\radio_a_1T.txt" ++ #define RTL8723_PHY_RADIO_B "rtl8723S\\radio_b_1T.txt" ++ #define RTL8723_AGC_TAB "rtl8723S\\AGC_TAB_1T.txt" ++ #define RTL8723_PHY_MACREG "rtl8723S\\MAC_REG.txt" ++ #define RTL8723_PHY_REG_PG "rtl8723S\\PHY_REG_PG.txt" ++ #define RTL8723_PHY_REG_MP "rtl8723S\\PHY_REG_MP.txt" ++ ++//--------------------------------------------------------------------- ++// RTL8723S From header ++//--------------------------------------------------------------------- ++ ++ // Fw Array ++ #define Rtl8723_FwImageArray Rtl8723UFwImgArray ++ #define Rtl8723_FwUMCBCutImageArrayWithBT Rtl8723UFwUMCBCutImgArrayWithBT ++ #define Rtl8723_FwUMCBCutImageArrayWithoutBT Rtl8723UFwUMCBCutImgArrayWithoutBT ++ ++ #define Rtl8723_ImgArrayLength Rtl8723UImgArrayLength ++ #define Rtl8723_UMCBCutImgArrayWithBTLength Rtl8723UUMCBCutImgArrayWithBTLength ++ #define Rtl8723_UMCBCutImgArrayWithoutBTLength Rtl8723UUMCBCutImgArrayWithoutBTLength ++ ++ #define Rtl8723_PHY_REG_Array_PG Rtl8723UPHY_REG_Array_PG ++ #define Rtl8723_PHY_REG_Array_PGLength Rtl8723UPHY_REG_Array_PGLength ++ ++#if MP_DRIVER == 1 ++ #define Rtl8723E_FwBTImgArray Rtl8723EFwBTImgArray ++ #define Rtl8723E_FwBTImgArrayLength Rtl8723EBTImgArrayLength ++ ++ #define Rtl8723_FwUMCBCutMPImageArray Rtl8723SFwUMCBCutMPImgArray ++ #define Rtl8723_UMCBCutMPImgArrayLength Rtl8723SUMCBCutMPImgArrayLength ++ ++ #define Rtl8723_PHY_REG_Array_MP Rtl8723UPHY_REG_Array_MP ++ #define Rtl8723_PHY_REG_Array_MPLength Rtl8723UPHY_REG_Array_MPLength ++#endif ++#ifndef CONFIG_PHY_SETTING_WITH_ODM ++ // MAC/BB/PHY Array ++ #define Rtl8723_MAC_Array Rtl8723UMAC_2T_Array ++ //#define Rtl8723_AGCTAB_2TArray Rtl8723UAGCTAB_2TArray ++ #define Rtl8723_AGCTAB_1TArray Rtl8723UAGCTAB_1TArray ++ //#define Rtl8723_PHY_REG_2TArray Rtl8723UPHY_REG_2TArray ++ #define Rtl8723_PHY_REG_1TArray Rtl8723UPHY_REG_1TArray ++ //#define Rtl8723_RadioA_2TArray Rtl8723URadioA_2TArray ++ #define Rtl8723_RadioA_1TArray Rtl8723URadioA_1TArray ++ //#define Rtl8723_RadioB_2TArray Rtl8723URadioB_2TArray ++ #define Rtl8723_RadioB_1TArray Rtl8723URadioB_1TArray ++ ++ ++ ++ // Array length ++ ++ #define Rtl8723_MAC_ArrayLength Rtl8723UMAC_2T_ArrayLength ++ #define Rtl8723_AGCTAB_1TArrayLength Rtl8723UAGCTAB_1TArrayLength ++ #define Rtl8723_PHY_REG_1TArrayLength Rtl8723UPHY_REG_1TArrayLength ++ ++ ++ #define Rtl8723_RadioA_1TArrayLength Rtl8723URadioA_1TArrayLength ++ #define Rtl8723_RadioB_1TArrayLength Rtl8723URadioB_1TArrayLength ++#endif ++#endif ++ ++#define DRVINFO_SZ 4 // unit is 8bytes ++#define PageNum_128(_Len) (u32)(((_Len)>>7) + ((_Len)&0x7F ? 1:0)) ++ ++#define FW_8723A_SIZE 0x8000 ++#define FW_8723A_START_ADDRESS 0x1000 ++#define FW_8723A_END_ADDRESS 0x1FFF //0x5FFF ++ ++#define MAX_PAGE_SIZE 4096 // @ page : 4k bytes ++ ++#define IS_FW_HEADER_EXIST(_pFwHdr) ((le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x92C0 ||\ ++ (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x88C0 ||\ ++ (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x2300) ++ ++typedef enum _FIRMWARE_SOURCE { ++ FW_SOURCE_IMG_FILE = 0, ++ FW_SOURCE_HEADER_FILE = 1, //from header file ++} FIRMWARE_SOURCE, *PFIRMWARE_SOURCE; ++ ++typedef struct _RT_FIRMWARE { ++ FIRMWARE_SOURCE eFWSource; ++#ifdef CONFIG_EMBEDDED_FWIMG ++ u8* szFwBuffer; ++#else ++ u8 szFwBuffer[FW_8723A_SIZE]; ++#endif ++ u32 ulFwLength; ++ ++#ifdef CONFIG_EMBEDDED_FWIMG ++ u8* szBTFwBuffer; ++#else ++ u8 szBTFwBuffer[FW_8723A_SIZE]; ++#endif ++ u32 ulBTFwLength; ++} RT_FIRMWARE, *PRT_FIRMWARE, RT_FIRMWARE_8723A, *PRT_FIRMWARE_8723A; ++ ++// ++// This structure must be cared byte-ordering ++// ++// Added by tynli. 2009.12.04. ++typedef struct _RT_8723A_FIRMWARE_HDR ++{ ++ // 8-byte alinment required ++ ++ //--- LONG WORD 0 ---- ++ u16 Signature; // 92C0: test chip; 92C, 88C0: test chip; 88C1: MP A-cut; 92C1: MP A-cut ++ u8 Category; // AP/NIC and USB/PCI ++ u8 Function; // Reserved for different FW function indcation, for further use when driver needs to download different FW in different conditions ++ u16 Version; // FW Version ++ u8 Subversion; // FW Subversion, default 0x00 ++ u16 Rsvd1; ++ ++ ++ //--- LONG WORD 1 ---- ++ u8 Month; // Release time Month field ++ u8 Date; // Release time Date field ++ u8 Hour; // Release time Hour field ++ u8 Minute; // Release time Minute field ++ u16 RamCodeSize; // The size of RAM code ++ u16 Rsvd2; ++ ++ //--- LONG WORD 2 ---- ++ u32 SvnIdx; // The SVN entry index ++ u32 Rsvd3; ++ ++ //--- LONG WORD 3 ---- ++ u32 Rsvd4; ++ u32 Rsvd5; ++}RT_8723A_FIRMWARE_HDR, *PRT_8723A_FIRMWARE_HDR; ++ ++#define DRIVER_EARLY_INT_TIME 0x05 ++#define BCN_DMA_ATIME_INT_TIME 0x02 ++ ++#ifdef CONFIG_USB_RX_AGGREGATION ++ ++typedef enum _USB_RX_AGG_MODE{ ++ USB_RX_AGG_DISABLE, ++ USB_RX_AGG_DMA, ++ USB_RX_AGG_USB, ++ USB_RX_AGG_MIX ++}USB_RX_AGG_MODE; ++ ++#define MAX_RX_DMA_BUFFER_SIZE 10240 // 10K for 8192C RX DMA buffer ++ ++#endif ++ ++ ++// BK, BE, VI, VO, HCCA, MANAGEMENT, COMMAND, HIGH, BEACON. ++#define MAX_TX_QUEUE 9 ++ ++#define TX_SELE_HQ BIT(0) // High Queue ++#define TX_SELE_LQ BIT(1) // Low Queue ++#define TX_SELE_NQ BIT(2) // Normal Queue ++ ++// Note: We will divide number of page equally for each queue other than public queue! ++#define TX_TOTAL_PAGE_NUMBER 0xF8 ++#define TX_PAGE_BOUNDARY (TX_TOTAL_PAGE_NUMBER + 1) ++ ++// For Normal Chip Setting ++// (HPQ + LPQ + NPQ + PUBQ) shall be TX_TOTAL_PAGE_NUMBER ++#define NORMAL_PAGE_NUM_PUBQ 0xE7 ++#define NORMAL_PAGE_NUM_HPQ 0x0C ++#define NORMAL_PAGE_NUM_LPQ 0x02 ++#define NORMAL_PAGE_NUM_NPQ 0x02 ++ ++// For Test Chip Setting ++// (HPQ + LPQ + PUBQ) shall be TX_TOTAL_PAGE_NUMBER ++#define TEST_PAGE_NUM_PUBQ 0x7E ++ ++// For Test Chip Setting ++#define WMM_TEST_TX_TOTAL_PAGE_NUMBER 0xF5 ++#define WMM_TEST_TX_PAGE_BOUNDARY (WMM_TEST_TX_TOTAL_PAGE_NUMBER + 1) //F6 ++ ++#define WMM_TEST_PAGE_NUM_PUBQ 0xA3 ++#define WMM_TEST_PAGE_NUM_HPQ 0x29 ++#define WMM_TEST_PAGE_NUM_LPQ 0x29 ++ ++// Note: For Normal Chip Setting, modify later ++#define WMM_NORMAL_TX_TOTAL_PAGE_NUMBER 0xF5 ++#define WMM_NORMAL_TX_PAGE_BOUNDARY (WMM_TEST_TX_TOTAL_PAGE_NUMBER + 1) //F6 ++ ++#define WMM_NORMAL_PAGE_NUM_PUBQ 0xB0 ++#define WMM_NORMAL_PAGE_NUM_HPQ 0x29 ++#define WMM_NORMAL_PAGE_NUM_LPQ 0x1C ++#define WMM_NORMAL_PAGE_NUM_NPQ 0x1C ++ ++ ++//------------------------------------------------------------------------- ++// Chip specific ++//------------------------------------------------------------------------- ++#define CHIP_BONDING_IDENTIFIER(_value) (((_value)>>22)&0x3) ++#define CHIP_BONDING_92C_1T2R 0x1 ++#define CHIP_BONDING_88C_USB_MCARD 0x2 ++#define CHIP_BONDING_88C_USB_HP 0x1 ++ ++#include "HalVerDef.h" ++#include "hal_com.h" ++ ++//------------------------------------------------------------------------- ++// Channel Plan ++//------------------------------------------------------------------------- ++enum ChannelPlan ++{ ++ CHPL_FCC = 0, ++ CHPL_IC = 1, ++ CHPL_ETSI = 2, ++ CHPL_SPAIN = 3, ++ CHPL_FRANCE = 4, ++ CHPL_MKK = 5, ++ CHPL_MKK1 = 6, ++ CHPL_ISRAEL = 7, ++ CHPL_TELEC = 8, ++ CHPL_GLOBAL = 9, ++ CHPL_WORLD = 10, ++}; ++ ++#define HAL_EFUSE_MEMORY ++ ++#define EFUSE_REAL_CONTENT_LEN 512 ++#define EFUSE_MAP_LEN 128 ++#define EFUSE_MAX_SECTION 16 ++#define EFUSE_IC_ID_OFFSET 506 //For some inferiority IC purpose. added by Roger, 2009.09.02. ++#define AVAILABLE_EFUSE_ADDR(addr) (addr < EFUSE_REAL_CONTENT_LEN) ++// ++// ++// To prevent out of boundary programming case, ++// leave 1byte and program full section ++// 9bytes + 1byt + 5bytes and pre 1byte. ++// For worst case: ++// | 1byte|----8bytes----|1byte|--5bytes--| ++// | | Reserved(14bytes) | ++// ++ ++// PG data exclude header, dummy 6 bytes frome CP test and reserved 1byte. ++#define EFUSE_OOB_PROTECT_BYTES 15 ++ ++#define EFUSE_REAL_CONTENT_LEN_8723A 512 ++#define EFUSE_MAP_LEN_8723A 256 ++#define EFUSE_MAX_SECTION_8723A 32 ++ ++//======================================================== ++// EFUSE for BT definition ++//======================================================== ++#define EFUSE_BT_REAL_BANK_CONTENT_LEN 512 ++#define EFUSE_BT_REAL_CONTENT_LEN 1536 // 512*3 ++#define EFUSE_BT_MAP_LEN 1024 // 1k bytes ++#define EFUSE_BT_MAX_SECTION 128 // 1024/8 ++ ++#define EFUSE_PROTECT_BYTES_BANK 16 ++ ++// ++// For RTL8723 WiFi/BT/GPS multi-function configuration. 2010.10.06. ++// ++typedef enum _RT_MULTI_FUNC { ++ RT_MULTI_FUNC_NONE = 0x00, ++ RT_MULTI_FUNC_WIFI = 0x01, ++ RT_MULTI_FUNC_BT = 0x02, ++ RT_MULTI_FUNC_GPS = 0x04, ++} RT_MULTI_FUNC, *PRT_MULTI_FUNC; ++ ++// ++// For RTL8723 WiFi PDn/GPIO polarity control configuration. 2010.10.08. ++// ++typedef enum _RT_POLARITY_CTL { ++ RT_POLARITY_LOW_ACT = 0, ++ RT_POLARITY_HIGH_ACT = 1, ++} RT_POLARITY_CTL, *PRT_POLARITY_CTL; ++ ++// For RTL8723 regulator mode. by tynli. 2011.01.14. ++typedef enum _RT_REGULATOR_MODE { ++ RT_SWITCHING_REGULATOR = 0, ++ RT_LDO_REGULATOR = 1, ++} RT_REGULATOR_MODE, *PRT_REGULATOR_MODE; ++ ++// Description: Determine the types of C2H events that are the same in driver and Fw. ++// Fisrt constructed by tynli. 2009.10.09. ++typedef enum _RTL8192C_C2H_EVT ++{ ++ C2H_DBG = 0, ++ C2H_TSF = 1, ++ C2H_AP_RPT_RSP = 2, ++ C2H_CCX_TX_RPT = 3, // The FW notify the report of the specific tx packet. ++ C2H_BT_RSSI = 4, ++ C2H_BT_OP_MODE = 5, ++ C2H_EXT_RA_RPT = 6, ++ C2H_HW_INFO_EXCH = 10, ++ C2H_C2H_H2C_TEST = 11, ++ C2H_BT_INFO = 12, ++ C2H_BT_MP_INFO = 15, ++ MAX_C2HEVENT ++} RTL8192C_C2H_EVT; ++ ++typedef struct hal_data_8723a ++{ ++ HAL_VERSION VersionID; ++ RT_CUSTOMER_ID CustomerID; ++ ++ u16 FirmwareVersion; ++ u16 FirmwareVersionRev; ++ u16 FirmwareSubVersion; ++ u16 FirmwareSignature; ++ ++ //current WIFI_PHY values ++ u32 ReceiveConfig; ++ WIRELESS_MODE CurrentWirelessMode; ++ HT_CHANNEL_WIDTH CurrentChannelBW; ++ u8 CurrentChannel; ++ u8 nCur40MhzPrimeSC;// Control channel sub-carrier ++ ++ u16 BasicRateSet; ++ ++ //rf_ctrl ++ u8 rf_chip; ++ u8 rf_type; ++ u8 NumTotalRFPath; ++ ++ u8 BoardType; ++ u8 CrystalCap; ++ // ++ // EEPROM setting. ++ // ++ u8 EEPROMVersion; ++ u16 EEPROMVID; ++ u16 EEPROMPID; ++ u16 EEPROMSVID; ++ u16 EEPROMSDID; ++ u8 EEPROMCustomerID; ++ u8 EEPROMSubCustomerID; ++ u8 EEPROMRegulatory; ++ u8 EEPROMThermalMeter; ++ u8 EEPROMBluetoothCoexist; ++ u8 EEPROMBluetoothType; ++ u8 EEPROMBluetoothAntNum; ++ u8 EEPROMBluetoothAntIsolation; ++ u8 EEPROMBluetoothRadioShared; ++ ++ u8 bTXPowerDataReadFromEEPORM; ++ u8 bAPKThermalMeterIgnore; ++ ++ u8 bIQKInitialized; ++ u8 bAntennaDetected; ++ ++ u8 TxPwrLevelCck[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ u8 TxPwrLevelHT40_1S[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; // For HT 40MHZ pwr ++ u8 TxPwrLevelHT40_2S[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; // For HT 40MHZ pwr ++ u8 TxPwrHt20Diff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];// HT 20<->40 Pwr diff ++ u8 TxPwrLegacyHtDiff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];// For HT<->legacy pwr diff ++ // For power group ++ u8 PwrGroupHT20[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ u8 PwrGroupHT40[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ ++ u8 LegacyHTTxPowerDiff;// Legacy to HT rate power diff ++ ++ // Read/write are allow for following hardware information variables ++ u8 framesync; ++ u32 framesyncC34; ++ u8 framesyncMonitor; ++ u8 DefaultInitialGain[4]; ++ u8 pwrGroupCnt; ++ u32 MCSTxPowerLevelOriginalOffset[7][16]; ++ u32 CCKTxPowerLevelOriginalOffset; ++ ++ u32 AntennaTxPath; // Antenna path Tx ++ u32 AntennaRxPath; // Antenna path Rx ++ u8 ExternalPA; ++ ++ u8 bLedOpenDrain; // Support Open-drain arrangement for controlling the LED. Added by Roger, 2009.10.16. ++ ++ //u32 LedControlNum; ++ //u32 LedControlMode; ++ //u32 TxPowerTrackControl; ++ u8 b1x1RecvCombine; // for 1T1R receive combining ++ ++ // For EDCA Turbo mode ++// u8 bIsAnyNonBEPkts; // Adapter->recvpriv.bIsAnyNonBEPkts ++// u8 bCurrentTurboEDCA; ++// u8 bForcedDisableTurboEDCA; ++// u8 bIsCurRDLState; // pdmpriv->prv_traffic_idx ++ ++ u32 AcParam_BE; //Original parameter for BE, use for EDCA turbo. ++ ++ //vivi, for tx power tracking, 20080407 ++ //u16 TSSI_13dBm; ++ //u32 Pwr_Track; ++ // The current Tx Power Level ++ u8 CurrentCckTxPwrIdx; ++ u8 CurrentOfdm24GTxPwrIdx; ++ ++ BB_REGISTER_DEFINITION_T PHYRegDef[4]; //Radio A/B/C/D ++ ++ BOOLEAN bRFPathRxEnable[4]; // We support 4 RF path now. ++ ++ u32 RfRegChnlVal[2]; ++ ++ u8 bCckHighPower; ++ ++ //RDG enable ++ BOOLEAN bRDGEnable; ++ ++ //for host message to fw ++ u8 LastHMEBoxNum; ++ ++ u8 fw_ractrl; ++ u8 RegTxPause; ++ // Beacon function related global variable. ++ u32 RegBcnCtrlVal; ++ u8 RegFwHwTxQCtrl; ++ u8 RegReg542; ++ ++ struct dm_priv dmpriv; ++ DM_ODM_T odmpriv; ++ //_lock odm_stainfo_lock; ++#ifdef DBG_CONFIG_ERROR_DETECT ++ struct sreset_priv srestpriv; ++#endif ++ ++#ifdef CONFIG_BT_COEXIST ++ u8 bBTMode; ++ // BT only. ++ BT30Info BtInfo; ++ // For bluetooth co-existance ++ BT_COEXIST_STR bt_coexist; ++#endif ++ ++#ifdef CONFIG_ANTENNA_DIVERSITY ++ u8 CurAntenna; ++ ++ // SW Antenna Switch ++ s32 RSSI_sum_A; ++ s32 RSSI_sum_B; ++ s32 RSSI_cnt_A; ++ s32 RSSI_cnt_B; ++ u8 RSSI_test; ++ u8 AntDivCfg; ++#endif ++ ++ u8 bDumpRxPkt;//for debug ++ u8 FwRsvdPageStartOffset; //2010.06.23. Added by tynli. Reserve page start offset except beacon in TxQ. ++ ++ // 2010/08/09 MH Add CU power down mode. ++ u8 pwrdown; ++ ++ // Add for dual MAC 0--Mac0 1--Mac1 ++ u32 interfaceIndex; ++ ++ u8 OutEpQueueSel; ++ u8 OutEpNumber; ++ ++ // 2010/12/10 MH Add for USB aggreation mode dynamic shceme. ++ BOOLEAN UsbRxHighSpeedMode; ++ ++ // 2010/11/22 MH Add for slim combo debug mode selective. ++ // This is used for fix the drawback of CU TSMC-A/UMC-A cut. HW auto suspend ability. Close BT clock. ++ BOOLEAN SlimComboDbg; ++ ++ // ++ // Add For EEPROM Efuse switch and Efuse Shadow map Setting ++ // ++ u8 EepromOrEfuse; ++// u8 EfuseMap[2][HWSET_MAX_SIZE_512]; //92C:256bytes, 88E:512bytes, we use union set (512bytes) ++ u16 EfuseUsedBytes; ++ u8 EfuseUsedPercentage; ++#ifdef HAL_EFUSE_MEMORY ++ EFUSE_HAL EfuseHal; ++#endif ++ ++ // Interrupt relatd register information. ++ u32 SysIntrStatus; ++ u32 SysIntrMask; ++ ++ // ++ // 2011/02/23 MH Add for 8723 mylti function definition. The define should be moved to an ++ // independent file in the future. ++ // ++ //------------------------8723-----------------------------------------// ++ RT_MULTI_FUNC MultiFunc; // For multi-function consideration. ++ RT_POLARITY_CTL PolarityCtl; // For Wifi PDn Polarity control. ++ RT_REGULATOR_MODE RegulatorMode; // switching regulator or LDO ++ //------------------------8723-----------------------------------------// ++ // ++ // 2011/02/23 MH Add for 8723 mylti function definition. The define should be moved to an ++ // independent file in the future. ++ ++ BOOLEAN bMACFuncEnable; ++ ++#ifdef CONFIG_P2P ++ struct P2P_PS_Offload_t p2p_ps_offload; ++#endif ++ ++ ++ // ++ // For USB Interface HAL related ++ // ++#ifdef CONFIG_USB_HCI ++ u32 UsbBulkOutSize; ++ ++ // Interrupt relatd register information. ++ u32 IntArray[2]; ++ u32 IntrMask[2]; ++#endif ++ ++ ++ // ++ // For SDIO Interface HAL related ++ // ++ ++ // Auto FSM to Turn On, include clock, isolation, power control for MAC only ++ u8 bMacPwrCtrlOn; ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ // ++ // SDIO ISR Related ++ // ++// u32 IntrMask[1]; ++// u32 IntrMaskToSet[1]; ++// LOG_INTERRUPT InterruptLog; ++ u32 sdio_himr; ++ u32 sdio_hisr; ++ ++ // ++ // SDIO Tx FIFO related. ++ // ++ // HIQ, MID, LOW, PUB free pages; padapter->xmitpriv.free_txpg ++ u8 SdioTxFIFOFreePage[SDIO_TX_FREE_PG_QUEUE]; ++ _lock SdioTxFIFOFreePageLock; ++ ++ // ++ // SDIO Rx FIFO related. ++ // ++ u8 SdioRxFIFOCnt; ++ u16 SdioRxFIFOSize; ++#endif ++} HAL_DATA_8723A, *PHAL_DATA_8723A; ++ ++#if 0 ++#define HAL_DATA_TYPE HAL_DATA_8723A ++#define PHAL_DATA_TYPE PHAL_DATA_8723A ++#else ++typedef struct hal_data_8723a HAL_DATA_TYPE, *PHAL_DATA_TYPE; ++#endif ++ ++#define GET_HAL_DATA(__pAdapter) ((HAL_DATA_TYPE *)((__pAdapter)->HalData)) ++#define GET_RF_TYPE(priv) (GET_HAL_DATA(priv)->rf_type) ++ ++#define INCLUDE_MULTI_FUNC_BT(_Adapter) (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_BT) ++#define INCLUDE_MULTI_FUNC_GPS(_Adapter) (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_GPS) ++ ++typedef struct rxreport_8723a ++{ ++ u32 pktlen:14; ++ u32 crc32:1; ++ u32 icverr:1; ++ u32 drvinfosize:4; ++ u32 security:3; ++ u32 qos:1; ++ u32 shift:2; ++ u32 physt:1; ++ u32 swdec:1; ++ u32 ls:1; ++ u32 fs:1; ++ u32 eor:1; ++ u32 own:1; ++ ++ u32 macid:5; ++ u32 tid:4; ++ u32 hwrsvd:4; ++ u32 amsdu:1; ++ u32 paggr:1; ++ u32 faggr:1; ++ u32 a1fit:4; ++ u32 a2fit:4; ++ u32 pam:1; ++ u32 pwr:1; ++ u32 md:1; ++ u32 mf:1; ++ u32 type:2; ++ u32 mc:1; ++ u32 bc:1; ++ ++ u32 seq:12; ++ u32 frag:4; ++ u32 nextpktlen:14; ++ u32 nextind:1; ++ u32 rsvd0831:1; ++ ++ u32 rxmcs:6; ++ u32 rxht:1; ++ u32 gf:1; ++ u32 splcp:1; ++ u32 bw:1; ++ u32 htc:1; ++ u32 eosp:1; ++ u32 bssidfit:2; ++ u32 rsvd1214:16; ++ u32 unicastwake:1; ++ u32 magicwake:1; ++ ++ u32 pattern0match:1; ++ u32 pattern1match:1; ++ u32 pattern2match:1; ++ u32 pattern3match:1; ++ u32 pattern4match:1; ++ u32 pattern5match:1; ++ u32 pattern6match:1; ++ u32 pattern7match:1; ++ u32 pattern8match:1; ++ u32 pattern9match:1; ++ u32 patternamatch:1; ++ u32 patternbmatch:1; ++ u32 patterncmatch:1; ++ u32 rsvd1613:19; ++ ++ u32 tsfl; ++ ++ u32 bassn:12; ++ u32 bavld:1; ++ u32 rsvd2413:19; ++} RXREPORT, *PRXREPORT; ++ ++typedef struct phystatus_8723a ++{ ++ u32 rxgain_a:7; ++ u32 trsw_a:1; ++ u32 rxgain_b:7; ++ u32 trsw_b:1; ++ u32 chcorr_l:16; ++ ++ u32 sigqualcck:8; ++ u32 cfo_a:8; ++ u32 cfo_b:8; ++ u32 chcorr_h:8; ++ ++ u32 noisepwrdb_h:8; ++ u32 cfo_tail_a:8; ++ u32 cfo_tail_b:8; ++ u32 rsvd0824:8; ++ ++ u32 rsvd1200:8; ++ u32 rxevm_a:8; ++ u32 rxevm_b:8; ++ u32 rxsnr_a:8; ++ ++ u32 rxsnr_b:8; ++ u32 noisepwrdb_l:8; ++ u32 rsvd1616:8; ++ u32 postsnr_a:8; ++ ++ u32 postsnr_b:8; ++ u32 csi_a:8; ++ u32 csi_b:8; ++ u32 targetcsi_a:8; ++ ++ u32 targetcsi_b:8; ++ u32 sigevm:8; ++ u32 maxexpwr:8; ++ u32 exintflag:1; ++ u32 sgien:1; ++ u32 rxsc:2; ++ u32 idlelong:1; ++ u32 anttrainen:1; ++ u32 antselb:1; ++ u32 antsel:1; ++} PHYSTATUS, *PPHYSTATUS; ++ ++ ++// rtl8723a_hal_init.c ++int FirmwareDownloadBT(IN PADAPTER Adapter, PRT_FIRMWARE_8723A pFirmware); ++s32 rtl8723a_FirmwareDownload(PADAPTER padapter); ++void rtl8723a_FirmwareSelfReset(PADAPTER padapter); ++void rtl8723a_InitializeFirmwareVars(PADAPTER padapter); ++void _8051Reset8723A(PADAPTER padapter); ++ ++void rtl8723a_InitAntenna_Selection(PADAPTER padapter); ++void rtl8723a_DeinitAntenna_Selection(PADAPTER padapter); ++void rtl8723a_CheckAntenna_Selection(PADAPTER padapter); ++void rtl8723a_init_default_value(PADAPTER padapter); ++ ++s32 InitLLTTable(PADAPTER padapter, u32 boundary); ++ ++s32 CardDisableHWSM(PADAPTER padapter, u8 resetMCU); ++s32 CardDisableWithoutHWSM(PADAPTER padapter); ++ ++// EFuse ++u8 GetEEPROMSize8723A(PADAPTER padapter); ++void Hal_InitPGData(PADAPTER padapter, u8 *PROMContent); ++void Hal_EfuseParseIDCode(PADAPTER padapter, u8 *hwinfo); ++void Hal_EfuseParseTxPowerInfo_8723A(PADAPTER padapter, u8 *PROMContent, BOOLEAN AutoLoadFail); ++void Hal_EfuseParseBTCoexistInfo_8723A(PADAPTER padapter, u8 *hwinfo, BOOLEAN AutoLoadFail); ++void Hal_EfuseParseEEPROMVer(PADAPTER padapter, u8 *hwinfo, BOOLEAN AutoLoadFail); ++void rtl8723a_EfuseParseChnlPlan(PADAPTER padapter, u8 *hwinfo, BOOLEAN AutoLoadFail); ++void Hal_EfuseParseCustomerID(PADAPTER padapter, u8 *hwinfo, BOOLEAN AutoLoadFail); ++void Hal_EfuseParseAntennaDiversity(PADAPTER padapter, u8 *hwinfo, BOOLEAN AutoLoadFail); ++void Hal_EfuseParseRateIndicationOption(PADAPTER padapter, u8 *hwinfo, BOOLEAN AutoLoadFail); ++void Hal_EfuseParseXtal_8723A(PADAPTER pAdapter, u8 *hwinfo, u8 AutoLoadFail); ++void Hal_EfuseParseThermalMeter_8723A(PADAPTER padapter, u8 *hwinfo, u8 AutoLoadFail); ++ ++//RT_CHANNEL_DOMAIN rtl8723a_HalMapChannelPlan(PADAPTER padapter, u8 HalChannelPlan); ++//VERSION_8192C rtl8723a_ReadChipVersion(PADAPTER padapter); ++//void rtl8723a_ReadBluetoothCoexistInfo(PADAPTER padapter, u8 *PROMContent, BOOLEAN AutoloadFail); ++void Hal_InitChannelPlan(PADAPTER padapter); ++ ++void rtl8723a_set_hal_ops(struct hal_ops *pHalFunc); ++void SetHwReg8723A(PADAPTER padapter, u8 variable, u8 *val); ++void GetHwReg8723A(PADAPTER padapter, u8 variable, u8 *val); ++#ifdef CONFIG_BT_COEXIST ++void rtl8723a_SingleDualAntennaDetection(PADAPTER padapter); ++#endif ++ ++// register ++void SetBcnCtrlReg(PADAPTER padapter, u8 SetBits, u8 ClearBits); ++void rtl8723a_InitBeaconParameters(PADAPTER padapter); ++void rtl8723a_InitBeaconMaxError(PADAPTER padapter, u8 InfraMode); ++ ++void rtl8723a_start_thread(_adapter *padapter); ++void rtl8723a_stop_thread(_adapter *padapter); ++ ++s32 c2h_id_filter_ccx_8723a(u8 id); ++ ++ ++#if defined(CONFIG_CHECK_BT_HANG) && defined(CONFIG_BT_COEXIST) ++void rtl8723a_init_checkbthang_workqueue(_adapter * padapter); ++void rtl8723a_free_checkbthang_workqueue(_adapter * padapter); ++void rtl8723a_cancel_checkbthang_workqueue(_adapter * padapter); ++void rtl8723a_hal_check_bt_hang(_adapter * padapter); ++#endif ++ ++ ++#ifdef CONFIG_RF_GAIN_OFFSET ++void Hal_ReadRFGainOffset(PADAPTER pAdapter,u8* hwinfo,BOOLEAN AutoLoadFail); ++#endif //CONFIG_RF_GAIN_OFFSET ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_led.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_led.h +new file mode 100644 +index 00000000..1af41993 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_led.h +@@ -0,0 +1,50 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8723A_LED_H__ ++#define __RTL8723A_LED_H__ ++ ++#include ++#include ++#include ++ ++ ++//================================================================================ ++// Interface to manipulate LED objects. ++//================================================================================ ++#ifdef CONFIG_USB_HCI ++void rtl8723au_InitSwLeds(PADAPTER padapter); ++void rtl8723au_DeInitSwLeds(PADAPTER padapter); ++#endif ++#ifdef CONFIG_PCI_HCI ++void rtl8723ae_gen_RefreshLedState(PADAPTER Adapter); ++void rtl8723ae_InitSwLeds(PADAPTER padapter); ++void rtl8723ae_DeInitSwLeds(PADAPTER padapter); ++#endif ++#ifdef CONFIG_SDIO_HCI ++void rtl8723as_InitSwLeds(PADAPTER padapter); ++void rtl8723as_DeInitSwLeds(PADAPTER padapter); ++#endif ++#ifdef CONFIG_GSPI_HCI ++void rtl8723as_InitSwLeds(PADAPTER padapter); ++void rtl8723as_DeInitSwLeds(PADAPTER padapter); ++#endif ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_pg.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_pg.h +new file mode 100644 +index 00000000..68cc0985 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_pg.h +@@ -0,0 +1,146 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8723A_PG_H__ ++#define __RTL8723A_PG_H__ ++ ++//==================================================== ++// EEPROM/Efuse PG Offset for 8723E/8723U/8723S ++//==================================================== ++#define EEPROM_CCK_TX_PWR_INX_8723A 0x10 ++#define EEPROM_HT40_1S_TX_PWR_INX_8723A 0x16 ++#define EEPROM_HT20_TX_PWR_INX_DIFF_8723A 0x1C ++#define EEPROM_OFDM_TX_PWR_INX_DIFF_8723A 0x1F ++#define EEPROM_HT40_MAX_PWR_OFFSET_8723A 0x22 ++#define EEPROM_HT20_MAX_PWR_OFFSET_8723A 0x25 ++ ++#define EEPROM_ChannelPlan_8723A 0x28 ++#define EEPROM_TSSI_A_8723A 0x29 ++#define EEPROM_THERMAL_METER_8723A 0x2A ++#define RF_OPTION1_8723A 0x2B ++#define RF_OPTION2_8723A 0x2C ++#define RF_OPTION3_8723A 0x2D ++#define RF_OPTION4_8723A 0x2E ++#define EEPROM_VERSION_8723A 0x30 ++#define EEPROM_CustomID_8723A 0x31 ++#define EEPROM_SubCustomID_8723A 0x32 ++#define EEPROM_XTAL_K_8723A 0x33 ++#define EEPROM_Chipset_8723A 0x34 ++ ++// RTL8723AE ++#define EEPROM_VID_8723AE 0x49 ++#define EEPROM_DID_8723AE 0x4B ++#define EEPROM_SVID_8723AE 0x4D ++#define EEPROM_SMID_8723AE 0x4F ++#define EEPROM_MAC_ADDR_8723AE 0x67 ++ ++// RTL8723AU ++#define EEPROM_MAC_ADDR_8723AU 0xC6 ++#define EEPROM_VID_8723AU 0xB7 ++#define EEPROM_PID_8723AU 0xB9 ++ ++// RTL8723AS ++#define EEPROM_MAC_ADDR_8723AS 0xAA ++ ++//==================================================== ++// EEPROM/Efuse Value Type ++//==================================================== ++#define EETYPE_TX_PWR 0x0 ++ ++//==================================================== ++// EEPROM/Efuse Default Value ++//==================================================== ++#define EEPROM_Default_CrystalCap_8723A 0x20 ++ ++ ++//---------------------------------------------------------------------------- ++// EEPROM/EFUSE data structure definition. ++//---------------------------------------------------------------------------- ++#define MAX_RF_PATH_NUM 2 ++#define MAX_CHNL_GROUP 3+9 ++typedef struct _TxPowerInfo ++{ ++ u8 CCKIndex[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; ++ u8 HT40_1SIndex[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; ++ u8 HT40_2SIndexDiff[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; ++ u8 HT20IndexDiff[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; ++ u8 OFDMIndexDiff[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; ++ u8 HT40MaxOffset[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; ++ u8 HT20MaxOffset[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; ++ u8 TSSI_A[3]; ++ u8 TSSI_B[3]; ++ u8 TSSI_A_5G[3]; //5GL/5GM/5GH ++ u8 TSSI_B_5G[3]; ++} TxPowerInfo, *PTxPowerInfo; ++ ++#if 0 ++#define MAX_RF_PATH 4 ++#define MAX_CHNL_GROUP_24G 6 ++#define MAX_CHNL_GROUP_5G 14 ++ ++// It must always set to 4, otherwise read efuse table secquence will be wrong. ++#define MAX_TX_COUNT 4 ++ ++typedef struct _TxPowerInfo24G ++{ ++ u8 IndexCCK_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; ++ u8 IndexBW40_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G-1]; ++ //If only one tx, only BW20 and OFDM are used. ++ s8 CCK_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 OFDM_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 BW20_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 BW40_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++} TxPowerInfo24G, *PTxPowerInfo24G; ++ ++typedef struct _TxPowerInfo5G ++{ ++ u8 IndexBW40_Base[MAX_RF_PATH][MAX_CHNL_GROUP_5G]; ++ //If only one tx, only BW20, OFDM, BW80 and BW160 are used. ++ s8 OFDM_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 BW20_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 BW40_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 BW80_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 BW160_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++} TxPowerInfo5G, *PTxPowerInfo5G; ++#endif ++ ++typedef enum _BT_Ant_NUM ++{ ++ Ant_x2 = 0, ++ Ant_x1 = 1 ++} BT_Ant_NUM, *PBT_Ant_NUM; ++ ++typedef enum _BT_CoType ++{ ++ BT_2Wire = 0, ++ BT_ISSC_3Wire = 1, ++ BT_Accel = 2, ++ BT_CSR_BC4 = 3, ++ BT_CSR_BC8 = 4, ++ BT_RTL8756 = 5, ++ BT_RTL8723A = 6 ++} BT_CoType, *PBT_CoType; ++ ++typedef enum _BT_RadioShared ++{ ++ BT_Radio_Shared = 0, ++ BT_Radio_Individual = 1, ++} BT_RadioShared, *PBT_RadioShared; ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_recv.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_recv.h +new file mode 100644 +index 00000000..98831678 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_recv.h +@@ -0,0 +1,41 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8723A_RECV_H__ ++#define __RTL8723A_RECV_H__ ++ ++#include ++ ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++#ifdef CONFIG_DIRECT_RECV ++void rtl8723as_recv(PADAPTER padapter, struct recv_buf *precvbuf); ++#endif ++s32 rtl8723as_init_recv_priv(PADAPTER padapter); ++void rtl8723as_free_recv_priv(PADAPTER padapter); ++#endif ++ ++void rtl8192c_query_rx_phy_status(union recv_frame *prframe, struct phy_stat *pphy_stat); ++void rtl8192c_process_phy_info(PADAPTER padapter, void *prframe); ++#ifdef CONFIG_USB_HCI ++void update_recvframe_attrib(union recv_frame *precvframe, struct recv_stat *prxstat); ++void update_recvframe_phyinfo(union recv_frame *precvframe, struct phy_stat *pphy_info); ++#endif ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_rf.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_rf.h +new file mode 100644 +index 00000000..187702f7 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_rf.h +@@ -0,0 +1,27 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8723A_RF_H__ ++#define __RTL8723A_RF_H__ ++ ++#include "rtl8192c_rf.h" ++int PHY_RF6052_Config8723A( IN PADAPTER Adapter ); ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_spec.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_spec.h +new file mode 100644 +index 00000000..a51bc5a0 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_spec.h +@@ -0,0 +1,538 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ *******************************************************************************/ ++#ifndef __RTL8723A_SPEC_H__ ++#define __RTL8723A_SPEC_H__ ++ ++#include ++ ++ ++//============================================================================ ++// 8723A Regsiter offset definition ++//============================================================================ ++#define HAL_8723A_NAV_UPPER_UNIT 128 // micro-second ++ ++//----------------------------------------------------- ++// ++// 0x0000h ~ 0x00FFh System Configuration ++// ++//----------------------------------------------------- ++#define REG_SYSON_REG_LOCK 0x001C ++ ++ ++//----------------------------------------------------- ++// ++// 0x0100h ~ 0x01FFh MACTOP General Configuration ++// ++//----------------------------------------------------- ++#define REG_FTIMR 0x0138 ++ ++ ++//----------------------------------------------------- ++// ++// 0x0200h ~ 0x027Fh TXDMA Configuration ++// ++//----------------------------------------------------- ++ ++ ++//----------------------------------------------------- ++// ++// 0x0280h ~ 0x02FFh RXDMA Configuration ++// ++//----------------------------------------------------- ++ ++ ++//----------------------------------------------------- ++// ++// 0x0300h ~ 0x03FFh PCIe ++// ++//----------------------------------------------------- ++ ++ ++//----------------------------------------------------- ++// ++// 0x0400h ~ 0x047Fh Protocol Configuration ++// ++//----------------------------------------------------- ++//#define REG_EARLY_MODE_CONTROL 0x4D0 ++#define REG_MACID_NO_LINK 0x4D0 ++ ++//----------------------------------------------------- ++// ++// 0x0500h ~ 0x05FFh EDCA Configuration ++// ++//----------------------------------------------------- ++ ++//2 BCN_CTRL ++#define DIS_ATIM BIT(0) ++#define DIS_BCNQ_SUB BIT(1) ++#define DIS_TSF_UDT BIT(4) ++ ++ ++//----------------------------------------------------- ++// ++// 0x0600h ~ 0x07FFh WMAC Configuration ++// ++//----------------------------------------------------- ++// ++// Note: ++// The NAV upper value is very important to WiFi 11n 5.2.3 NAV test. The default value is ++// always too small, but the WiFi TestPlan test by 25,000 microseconds of NAV through sending ++// CTS in the air. We must update this value greater than 25,000 microseconds to pass the item. ++// The offset of NAV_UPPER in 8192C Spec is incorrect, and the offset should be 0x0652. Commented ++// by SD1 Scott. ++// By Bruce, 2011-07-18. ++// ++#define REG_NAV_UPPER 0x0652 // unit of 128 ++ ++#define REG_BT_COEX_TABLE_1 0x06C0 ++#define REG_BT_COEX_TABLE_2 0x06C4 ++ ++//============================================================================ ++// 8723 Regsiter Bit and Content definition ++//============================================================================ ++ ++//----------------------------------------------------- ++// ++// 0x0000h ~ 0x00FFh System Configuration ++// ++//----------------------------------------------------- ++ ++//2 SPS0_CTRL ++ ++//2 SYS_ISO_CTRL ++ ++//2 SYS_FUNC_EN ++ ++//2 APS_FSMCO ++#define EN_WLON BIT(16) ++ ++//2 SYS_CLKR ++ ++//2 9346CR ++ ++//2 AFE_MISC ++ ++//2 SPS0_CTRL ++ ++//2 SPS_OCP_CFG ++ ++//2 SYSON_REG_LOCK ++#define WLOCK_ALL BIT(0) ++#define WLOCK_00 BIT(1) ++#define WLOCK_04 BIT(2) ++#define WLOCK_08 BIT(3) ++#define WLOCK_40 BIT(4) ++#define WLOCK_1C_B6 BIT(5) ++#define R_DIS_PRST_1 BIT(6) ++#define LOCK_ALL_EN BIT(7) ++ ++//2 RF_CTRL ++ ++//2 LDOA15_CTRL ++ ++//2 LDOV12D_CTRL ++ ++//2 AFE_XTAL_CTRL ++ ++//2 AFE_PLL_CTRL ++ ++//2 EFUSE_CTRL ++ ++//2 EFUSE_TEST (For RTL8723 partially) ++ ++//2 PWR_DATA ++ ++//2 CAL_TIMER ++ ++//2 ACLK_MON ++ ++//2 GPIO_MUXCFG ++ ++//2 GPIO_PIN_CTRL ++ ++//2 GPIO_INTM ++ ++//2 LEDCFG ++ ++//2 FSIMR ++ ++//2 FSISR ++ ++//2 HSIMR ++// 8723 Host System Interrupt Mask Register (offset 0x58, 32 byte) ++#define HSIMR_GPIO12_0_INT_EN BIT(0) ++#define HSIMR_SPS_OCP_INT_EN BIT(5) ++#define HSIMR_RON_INT_EN BIT(6) ++#define HSIMR_PDNINT_EN BIT(7) ++#define HSIMR_GPIO9_INT_EN BIT(25) ++ ++//2 HSISR ++// 8723 Host System Interrupt Status Register (offset 0x5C, 32 byte) ++#define HSISR_GPIO12_0_INT BIT(0) ++#define HSISR_SPS_OCP_INT BIT(5) ++#define HSISR_RON_INT BIT(6) ++#define HSISR_PDNINT BIT(7) ++#define HSISR_GPIO9_INT BIT(25) ++ ++// interrupt mask which needs to clear ++#define MASK_HSISR_CLEAR (HSISR_GPIO12_0_INT |\ ++ HSISR_SPS_OCP_INT |\ ++ HSISR_RON_INT |\ ++ HSISR_PDNINT |\ ++ HSISR_GPIO9_INT) ++ ++//2 MCUFWDL ++#define RAM_DL_SEL BIT7 // 1:RAM, 0:ROM ++ ++//2 HPON_FSM ++ ++//2 SYS_CFG ++#define RTL_ID BIT(23) // TestChip ID, 1:Test(RLE); 0:MP(RL) ++#define SPS_SEL BIT(24) // 1:LDO regulator mode; 0:Switching regulator mode ++ ++ ++//----------------------------------------------------- ++// ++// 0x0100h ~ 0x01FFh MACTOP General Configuration ++// ++//----------------------------------------------------- ++ ++//2 Function Enable Registers ++ ++//2 CR ++#define CALTMR_EN BIT(10) ++ ++//2 PBP - Page Size Register ++ ++//2 TX/RXDMA ++ ++//2 TRXFF_BNDY ++ ++//2 LLT_INIT ++ ++//2 BB_ACCESS_CTRL ++ ++ ++//----------------------------------------------------- ++// ++// 0x0200h ~ 0x027Fh TXDMA Configuration ++// ++//----------------------------------------------------- ++ ++//2 RQPN ++ ++//2 TDECTRL ++ ++//2 TDECTL ++ ++//2 TXDMA_OFFSET_CHK ++ ++ ++//----------------------------------------------------- ++// ++// 0x0400h ~ 0x047Fh Protocol Configuration ++// ++//----------------------------------------------------- ++ ++//2 FWHW_TXQ_CTRL ++ ++//2 INIRTSMCS_SEL ++ ++//2 SPEC SIFS ++ ++//2 RRSR ++ ++//2 ARFR ++ ++//2 AGGLEN_LMT_L ++ ++//2 RL ++ ++//2 DARFRC ++ ++//2 RARFRC ++ ++ ++//----------------------------------------------------- ++// ++// 0x0500h ~ 0x05FFh EDCA Configuration ++// ++//----------------------------------------------------- ++ ++//2 EDCA setting ++ ++//2 EDCA_VO_PARAM ++ ++//2 SIFS_CCK ++ ++//2 SIFS_OFDM ++ ++//2 TBTT PROHIBIT ++ ++//2 REG_RD_CTRL ++ ++//2 BCN_CTRL ++ ++//2 ACMHWCTRL ++ ++ ++//----------------------------------------------------- ++// ++// 0x0600h ~ 0x07FFh WMAC Configuration ++// ++//----------------------------------------------------- ++ ++//2 APSD_CTRL ++ ++//2 BWOPMODE ++ ++//2 TCR ++ ++//2 RCR ++ ++//2 RX_PKT_LIMIT ++ ++//2 RX_DLK_TIME ++ ++//2 MBIDCAMCFG ++ ++//2 AMPDU_MIN_SPACE ++ ++//2 RXERR_RPT ++ ++//2 SECCFG ++ ++ ++//----------------------------------------------------- ++// ++// 0xFE00h ~ 0xFE55h RTL8723 SDIO Configuration ++// ++//----------------------------------------------------- ++ ++// I/O bus domain address mapping ++#define SDIO_LOCAL_BASE 0x10250000 ++#define WLAN_IOREG_BASE 0x10260000 ++#define FIRMWARE_FIFO_BASE 0x10270000 ++#define TX_HIQ_BASE 0x10310000 ++#define TX_MIQ_BASE 0x10320000 ++#define TX_LOQ_BASE 0x10330000 ++#define RX_RX0FF_BASE 0x10340000 ++ ++// SDIO host local register space mapping. ++#define SDIO_LOCAL_MSK 0x0FFF ++#define WLAN_IOREG_MSK 0x7FFF ++#define WLAN_FIFO_MSK 0x1FFF // Aggregation Length[12:0] ++#define WLAN_RX0FF_MSK 0x0003 ++ ++#define SDIO_WITHOUT_REF_DEVICE_ID 0 // Without reference to the SDIO Device ID ++#define SDIO_LOCAL_DEVICE_ID 0 // 0b[16], 000b[15:13] ++#define WLAN_TX_HIQ_DEVICE_ID 4 // 0b[16], 100b[15:13] ++#define WLAN_TX_MIQ_DEVICE_ID 5 // 0b[16], 101b[15:13] ++#define WLAN_TX_LOQ_DEVICE_ID 6 // 0b[16], 110b[15:13] ++#define WLAN_RX0FF_DEVICE_ID 7 // 0b[16], 111b[15:13] ++#define WLAN_IOREG_DEVICE_ID 8 // 1b[16] ++ ++// SDIO Tx Free Page Index ++#define HI_QUEUE_IDX 0 ++#define MID_QUEUE_IDX 1 ++#define LOW_QUEUE_IDX 2 ++#define PUBLIC_QUEUE_IDX 3 ++ ++#define SDIO_MAX_TX_QUEUE 3 // HIQ, MIQ and LOQ ++#define SDIO_MAX_RX_QUEUE 1 ++ ++#define SDIO_REG_TX_CTRL 0x0000 // SDIO Tx Control ++#define SDIO_REG_HIMR 0x0014 // SDIO Host Interrupt Mask ++#define SDIO_REG_HISR 0x0018 // SDIO Host Interrupt Service Routine ++#define SDIO_REG_HCPWM 0x0019 // HCI Current Power Mode ++#define SDIO_REG_RX0_REQ_LEN 0x001C // RXDMA Request Length ++#define SDIO_REG_FREE_TXPG 0x0020 // Free Tx Buffer Page ++#define SDIO_REG_HCPWM1 0x0024 // HCI Current Power Mode 1 ++#define SDIO_REG_HCPWM2 0x0026 // HCI Current Power Mode 2 ++#define SDIO_REG_HTSFR_INFO 0x0030 // HTSF Informaion ++#define SDIO_REG_HRPWM1 0x0080 // HCI Request Power Mode 1 ++#define SDIO_REG_HRPWM2 0x0082 // HCI Request Power Mode 2 ++#define SDIO_REG_HPS_CLKR 0x0084 // HCI Power Save Clock ++#define SDIO_REG_HSUS_CTRL 0x0086 // SDIO HCI Suspend Control ++#define SDIO_REG_HIMR_ON 0x0090 // SDIO Host Extension Interrupt Mask Always ++#define SDIO_REG_HISR_ON 0x0091 // SDIO Host Extension Interrupt Status Always ++ ++#define SDIO_HIMR_DISABLED 0 ++ ++// SDIO Host Interrupt Mask Register ++#define SDIO_HIMR_RX_REQUEST_MSK BIT0 ++#define SDIO_HIMR_AVAL_MSK BIT1 ++#define SDIO_HIMR_TXERR_MSK BIT2 ++#define SDIO_HIMR_RXERR_MSK BIT3 ++#define SDIO_HIMR_TXFOVW_MSK BIT4 ++#define SDIO_HIMR_RXFOVW_MSK BIT5 ++#define SDIO_HIMR_TXBCNOK_MSK BIT6 ++#define SDIO_HIMR_TXBCNERR_MSK BIT7 ++#define SDIO_HIMR_BCNERLY_INT_MSK BIT16 ++#define SDIO_HIMR_C2HCMD_MSK BIT17 ++#define SDIO_HIMR_CPWM1_MSK BIT18 ++#define SDIO_HIMR_CPWM2_MSK BIT19 ++#define SDIO_HIMR_HSISR_IND_MSK BIT20 ++#define SDIO_HIMR_GTINT3_IND_MSK BIT21 ++#define SDIO_HIMR_GTINT4_IND_MSK BIT22 ++#define SDIO_HIMR_PSTIMEOUT_MSK BIT23 ++#define SDIO_HIMR_OCPINT_MSK BIT24 ++#define SDIO_HIMR_ATIMEND_MSK BIT25 ++#define SDIO_HIMR_ATIMEND_E_MSK BIT26 ++#define SDIO_HIMR_CTWEND_MSK BIT27 ++ ++// SDIO Host Interrupt Service Routine ++#define SDIO_HISR_RX_REQUEST BIT0 ++#define SDIO_HISR_AVAL BIT1 ++#define SDIO_HISR_TXERR BIT2 ++#define SDIO_HISR_RXERR BIT3 ++#define SDIO_HISR_TXFOVW BIT4 ++#define SDIO_HISR_RXFOVW BIT5 ++#define SDIO_HISR_TXBCNOK BIT6 ++#define SDIO_HISR_TXBCNERR BIT7 ++#define SDIO_HISR_BCNERLY_INT BIT16 ++#define SDIO_HISR_C2HCMD BIT17 ++#define SDIO_HISR_CPWM1 BIT18 ++#define SDIO_HISR_CPWM2 BIT19 ++#define SDIO_HISR_HSISR_IND BIT20 ++#define SDIO_HISR_GTINT3_IND BIT21 ++#define SDIO_HISR_GTINT4_IND BIT22 ++#define SDIO_HISR_PSTIMEOUT BIT23 ++#define SDIO_HISR_OCPINT BIT24 ++#define SDIO_HISR_ATIMEND BIT25 ++#define SDIO_HISR_ATIMEND_E BIT26 ++#define SDIO_HISR_CTWEND BIT27 ++ ++#define MASK_SDIO_HISR_CLEAR (SDIO_HISR_TXERR |\ ++ SDIO_HISR_RXERR |\ ++ SDIO_HISR_TXFOVW |\ ++ SDIO_HISR_RXFOVW |\ ++ SDIO_HISR_TXBCNOK |\ ++ SDIO_HISR_TXBCNERR |\ ++ SDIO_HISR_C2HCMD |\ ++ SDIO_HISR_CPWM1 |\ ++ SDIO_HISR_CPWM2 |\ ++ SDIO_HISR_HSISR_IND |\ ++ SDIO_HISR_GTINT3_IND |\ ++ SDIO_HISR_GTINT4_IND |\ ++ SDIO_HISR_PSTIMEOUT |\ ++ SDIO_HISR_OCPINT) ++ ++// SDIO HCI Suspend Control Register ++#define HCI_RESUME_PWR_RDY BIT1 ++#define HCI_SUS_CTRL BIT0 ++ ++// SDIO Tx FIFO related ++#define SDIO_TX_FREE_PG_QUEUE 4 // The number of Tx FIFO free page ++#define SDIO_TX_FIFO_PAGE_SZ 128 ++ ++// vivi added for new cam search flow, 20091028 ++#define SCR_TxUseBroadcastDK BIT6 // Force Tx Use Broadcast Default Key ++#define SCR_RxUseBroadcastDK BIT7 // Force Rx Use Broadcast Default Key ++ ++ ++//---------------------------------------------------------------------------- ++// 8723 EFUSE ++//---------------------------------------------------------------------------- ++#ifdef HWSET_MAX_SIZE ++#undef HWSET_MAX_SIZE ++#endif ++#define HWSET_MAX_SIZE 256 ++ ++ ++//----------------------------------------------------------------------------- ++//USB interrupt ++//----------------------------------------------------------------------------- ++#define UHIMR_TIMEOUT2 BIT31 ++#define UHIMR_TIMEOUT1 BIT30 ++#define UHIMR_PSTIMEOUT BIT29 ++#define UHIMR_GTINT4 BIT28 ++#define UHIMR_GTINT3 BIT27 ++#define UHIMR_TXBCNERR BIT26 ++#define UHIMR_TXBCNOK BIT25 ++#define UHIMR_TSF_BIT32_TOGGLE BIT24 ++#define UHIMR_BCNDMAINT3 BIT23 ++#define UHIMR_BCNDMAINT2 BIT22 ++#define UHIMR_BCNDMAINT1 BIT21 ++#define UHIMR_BCNDMAINT0 BIT20 ++#define UHIMR_BCNDOK3 BIT19 ++#define UHIMR_BCNDOK2 BIT18 ++#define UHIMR_BCNDOK1 BIT17 ++#define UHIMR_BCNDOK0 BIT16 ++#define UHIMR_HSISR_IND BIT15 ++#define UHIMR_BCNDMAINT_E BIT14 ++//RSVD BIT13 ++#define UHIMR_CTW_END BIT12 ++//RSVD BIT11 ++#define UHIMR_C2HCMD BIT10 ++#define UHIMR_CPWM2 BIT9 ++#define UHIMR_CPWM BIT8 ++#define UHIMR_HIGHDOK BIT7 // High Queue DMA OK Interrupt ++#define UHIMR_MGNTDOK BIT6 // Management Queue DMA OK Interrupt ++#define UHIMR_BKDOK BIT5 // AC_BK DMA OK Interrupt ++#define UHIMR_BEDOK BIT4 // AC_BE DMA OK Interrupt ++#define UHIMR_VIDOK BIT3 // AC_VI DMA OK Interrupt ++#define UHIMR_VODOK BIT2 // AC_VO DMA Interrupt ++#define UHIMR_RDU BIT1 // Receive Descriptor Unavailable ++#define UHIMR_ROK BIT0 // Receive DMA OK Interrupt ++ ++// USB Host Interrupt Status Extension bit ++#define UHIMR_BCNDMAINT7 BIT23 ++#define UHIMR_BCNDMAINT6 BIT22 ++#define UHIMR_BCNDMAINT5 BIT21 ++#define UHIMR_BCNDMAINT4 BIT20 ++#define UHIMR_BCNDOK7 BIT19 ++#define UHIMR_BCNDOK6 BIT18 ++#define UHIMR_BCNDOK5 BIT17 ++#define UHIMR_BCNDOK4 BIT16 ++// bit14-15: RSVD ++#define UHIMR_ATIMEND_E BIT13 ++#define UHIMR_ATIMEND BIT12 ++#define UHIMR_TXERR BIT11 ++#define UHIMR_RXERR BIT10 ++#define UHIMR_TXFOVW BIT9 ++#define UHIMR_RXFOVW BIT8 ++// bit2-7: RSVD ++#define UHIMR_OCPINT BIT1 ++// bit0: RSVD ++ ++#define REG_USB_HIMR 0xFE38 ++#define REG_USB_HIMRE 0xFE3C ++#define REG_USB_HISR 0xFE78 ++#define REG_USB_HISRE 0xFE7C ++ ++#define USB_INTR_CPWM_OFFSET 16 ++#define USB_INTR_CONTENT_HISR_OFFSET 48 ++#define USB_INTR_CONTENT_HISRE_OFFSET 52 ++#define USB_INTR_CONTENT_LENGTH 56 ++#define USB_C2H_CMDID_OFFSET 0 ++#define USB_C2H_SEQ_OFFSET 1 ++#define USB_C2H_EVENT_OFFSET 2 ++//============================================================================ ++// General definitions ++//============================================================================ ++ ++#ifdef CONFIG_RF_GAIN_OFFSET ++#define EEPROM_RF_GAIN_OFFSET 0x2F ++#define EEPROM_RF_GAIN_VAL 0x1F6 ++#endif //CONFIG_RF_GAIN_OFFSET ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_sreset.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_sreset.h +new file mode 100644 +index 00000000..c6ca4dca +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_sreset.h +@@ -0,0 +1,33 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTL8188E_SRESET_H_ ++#define _RTL8188E_SRESET_H_ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef DBG_CONFIG_ERROR_DETECT ++extern void rtl8723a_sreset_xmit_status_check(_adapter *padapter); ++extern void rtl8723a_sreset_linked_status_check(_adapter *padapter); ++#endif ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_xmit.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_xmit.h +new file mode 100644 +index 00000000..c3658435 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtl8723a_xmit.h +@@ -0,0 +1,238 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTL8723A_XMIT_H__ ++#define __RTL8723A_XMIT_H__ ++ ++#include ++ ++// ++//defined for TX DESC Operation ++// ++ ++#define MAX_TID (15) ++ ++//OFFSET 0 ++#define OFFSET_SZ 0 ++#define OFFSET_SHT 16 ++#define BMC BIT(24) ++#define LSG BIT(26) ++#define FSG BIT(27) ++#define OWN BIT(31) ++ ++ ++//OFFSET 4 ++#define PKT_OFFSET_SZ 0 ++#define BK BIT(6) ++#define QSEL_SHT 8 ++#define Rate_ID_SHT 16 ++#define NAVUSEHDR BIT(20) ++#define PKT_OFFSET_SHT 26 ++#define HWPC BIT(31) ++ ++//OFFSET 8 ++#define AGG_EN BIT(29) ++ ++//OFFSET 12 ++#define SEQ_SHT 16 ++ ++//OFFSET 16 ++#define QoS BIT(6) ++#define HW_SEQ_EN BIT(7) ++#define USERATE BIT(8) ++#define DISDATAFB BIT(10) ++#define DATA_SHORT BIT(24) ++#define DATA_BW BIT(25) ++ ++//OFFSET 20 ++#define SGI BIT(6) ++ ++typedef struct txdesc_8723a ++{ ++ u32 pktlen:16; ++ u32 offset:8; ++ u32 bmc:1; ++ u32 htc:1; ++ u32 ls:1; ++ u32 fs:1; ++ u32 linip:1; ++ u32 noacm:1; ++ u32 gf:1; ++ u32 own:1; ++ ++ u32 macid:5; ++ u32 agg_en:1; ++ u32 bk:1; ++ u32 rd_en:1; ++ u32 qsel:5; ++ u32 rd_nav_ext:1; ++ u32 lsig_txop_en:1; ++ u32 pifs:1; ++ u32 rate_id:4; ++ u32 navusehdr:1; ++ u32 en_desc_id:1; ++ u32 sectype:2; ++ u32 rsvd0424:2; ++ u32 pkt_offset:5; // unit: 8 bytes ++ u32 rsvd0431:1; ++ ++ u32 rts_rc:6; ++ u32 data_rc:6; ++ u32 rsvd0812:2; ++ u32 bar_rty_th:2; ++ u32 rsvd0816:1; ++ u32 morefrag:1; ++ u32 raw:1; ++ u32 ccx:1; ++ u32 ampdu_density:3; ++ u32 bt_null:1; ++ u32 ant_sel_a:1; ++ u32 ant_sel_b:1; ++ u32 tx_ant_cck:2; ++ u32 tx_antl:2; ++ u32 tx_ant_ht:2; ++ ++ u32 nextheadpage:8; ++ u32 tailpage:8; ++ u32 seq:12; ++ u32 cpu_handle:1; ++ u32 tag1:1; ++ u32 trigger_int:1; ++ u32 hwseq_en:1; ++ ++ u32 rtsrate:5; ++ u32 ap_dcfe:1; ++ u32 hwseq_sel:2; ++ u32 userate:1; ++ u32 disrtsfb:1; ++ u32 disdatafb:1; ++ u32 cts2self:1; ++ u32 rtsen:1; ++ u32 hw_rts_en:1; ++ u32 port_id:1; ++ u32 rsvd1615:3; ++ u32 wait_dcts:1; ++ u32 cts2ap_en:1; ++ u32 data_sc:2; ++ u32 data_stbc:2; ++ u32 data_short:1; ++ u32 data_bw:1; ++ u32 rts_short:1; ++ u32 rts_bw:1; ++ u32 rts_sc:2; ++ u32 vcs_stbc:2; ++ ++ u32 datarate:6; ++ u32 sgi:1; ++ u32 try_rate:1; ++ u32 data_ratefb_lmt:5; ++ u32 rts_ratefb_lmt:4; ++ u32 rty_lmt_en:1; ++ u32 data_rt_lmt:6; ++ u32 usb_txagg_num:8; ++ ++ u32 txagg_a:5; ++ u32 txagg_b:5; ++ u32 use_max_len:1; ++ u32 max_agg_num:5; ++ u32 mcsg1_max_len:4; ++ u32 mcsg2_max_len:4; ++ u32 mcsg3_max_len:4; ++ u32 mcs7_sgi_max_len:4; ++ ++ u32 checksum:16; // TxBuffSize(PCIe)/CheckSum(USB) ++ u32 mcsg4_max_len:4; ++ u32 mcsg5_max_len:4; ++ u32 mcsg6_max_len:4; ++ u32 mcs15_sgi_max_len:4; ++}TXDESC, *PTXDESC; ++ ++#define txdesc_set_ccx_sw_8723a(txdesc, value) \ ++ do { \ ++ ((struct txdesc_8723a *)(txdesc))->mcsg4_max_len = (((value)>>8) & 0x0f); \ ++ ((struct txdesc_8723a *)(txdesc))->mcs15_sgi_max_len= (((value)>>4) & 0x0f); \ ++ ((struct txdesc_8723a *)(txdesc))->mcsg6_max_len = ((value) & 0x0f); \ ++ } while (0) ++ ++struct txrpt_ccx_8723a { ++ /* offset 0 */ ++ u8 tag1:1; ++ u8 rsvd:4; ++ u8 int_bt:1; ++ u8 int_tri:1; ++ u8 int_ccx:1; ++ ++ /* offset 1 */ ++ u8 mac_id:5; ++ u8 pkt_drop:1; ++ u8 pkt_ok:1; ++ u8 bmc:1; ++ ++ /* offset 2 */ ++ u8 retry_cnt:6; ++ u8 lifetime_over:1; ++ u8 retry_over:1; ++ ++ /* offset 3 */ ++ u8 ccx_qtime0; ++ u8 ccx_qtime1; ++ ++ /* offset 5 */ ++ u8 final_data_rate; ++ ++ /* offset 6 */ ++ u8 sw1:4; ++ u8 qsel:4; ++ ++ /* offset 7 */ ++ u8 sw0; ++}; ++ ++#define txrpt_ccx_sw_8723a(txrpt_ccx) ((txrpt_ccx)->sw0 + ((txrpt_ccx)->sw1<<8)) ++#define txrpt_ccx_qtime_8723a(txrpt_ccx) ((txrpt_ccx)->ccx_qtime0+((txrpt_ccx)->ccx_qtime1<<8)) ++ ++#ifdef CONFIG_XMIT_ACK ++void dump_txrpt_ccx_8723a(void *buf); ++void handle_txrpt_ccx_8723a(_adapter *adapter, void *buf); ++#else ++#define dump_txrpt_ccx_8723a(buf) do {} while(0) ++#define handle_txrpt_ccx_8723a(adapter, buf) do {} while(0) ++#endif //CONFIG_XMIT_ACK ++ ++void rtl8723a_update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem); ++void rtl8723a_fill_fake_txdesc(PADAPTER padapter, u8 *pDesc, u32 BufferLen, u8 IsPsPoll, u8 IsBTQosNull); ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++s32 rtl8723as_init_xmit_priv(PADAPTER padapter); ++void rtl8723as_free_xmit_priv(PADAPTER padapter); ++s32 rtl8723as_hal_xmit(PADAPTER padapter, struct xmit_frame *pxmitframe); ++s32 rtl8723as_mgnt_xmit(PADAPTER padapter, struct xmit_frame *pmgntframe); ++s32 rtl8723as_hal_xmitframe_enqueue(_adapter *padapter, struct xmit_frame *pxmitframe); ++s32 rtl8723as_xmit_buf_handler(PADAPTER padapter); ++thread_return rtl8723as_xmit_thread(thread_context context); ++#define hal_xmit_handler rtl8723as_xmit_buf_handler ++#endif ++ ++#ifdef CONFIG_USB_HCI ++s32 rtl8723au_hal_xmitframe_enqueue(_adapter *padapter, struct xmit_frame *pxmitframe); ++s32 rtl8723au_xmit_buf_handler(PADAPTER padapter); ++#define hal_xmit_handler rtl8723au_xmit_buf_handler ++#endif ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_android.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_android.h +new file mode 100644 +index 00000000..f9214c2d +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_android.h +@@ -0,0 +1,90 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#ifndef __RTW_ANDROID_H__ ++#define __RTW_ANDROID_H__ ++ ++#include ++#include ++ ++enum ANDROID_WIFI_CMD { ++ ANDROID_WIFI_CMD_START, ++ ANDROID_WIFI_CMD_STOP, ++ ANDROID_WIFI_CMD_SCAN_ACTIVE, ++ ANDROID_WIFI_CMD_SCAN_PASSIVE, ++ ANDROID_WIFI_CMD_RSSI, ++ ANDROID_WIFI_CMD_LINKSPEED, ++ ANDROID_WIFI_CMD_RXFILTER_START, ++ ANDROID_WIFI_CMD_RXFILTER_STOP, ++ ANDROID_WIFI_CMD_RXFILTER_ADD, ++ ANDROID_WIFI_CMD_RXFILTER_REMOVE, ++ ANDROID_WIFI_CMD_BTCOEXSCAN_START, ++ ANDROID_WIFI_CMD_BTCOEXSCAN_STOP, ++ ANDROID_WIFI_CMD_BTCOEXMODE, ++ ANDROID_WIFI_CMD_SETSUSPENDOPT, ++ ANDROID_WIFI_CMD_P2P_DEV_ADDR, ++ ANDROID_WIFI_CMD_SETFWPATH, ++ ANDROID_WIFI_CMD_SETBAND, ++ ANDROID_WIFI_CMD_GETBAND, ++ ANDROID_WIFI_CMD_COUNTRY, ++ ANDROID_WIFI_CMD_P2P_SET_NOA, ++ ANDROID_WIFI_CMD_P2P_GET_NOA, ++ ANDROID_WIFI_CMD_P2P_SET_PS, ++ ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE, ++#ifdef PNO_SUPPORT ++ ANDROID_WIFI_CMD_PNOSSIDCLR_SET, ++ ANDROID_WIFI_CMD_PNOSETUP_SET, ++ ANDROID_WIFI_CMD_PNOENABLE_SET, ++ ANDROID_WIFI_CMD_PNODEBUG_SET, ++#endif ++ ++ ANDROID_WIFI_CMD_MACADDR, ++ ++ ANDROID_WIFI_CMD_BLOCK, ++ ++ ANDROID_WIFI_CMD_WFD_ENABLE, ++ ANDROID_WIFI_CMD_WFD_DISABLE, ++ ++ ANDROID_WIFI_CMD_WFD_SET_TCPPORT, ++ ANDROID_WIFI_CMD_WFD_SET_MAX_TPUT, ++ ANDROID_WIFI_CMD_WFD_SET_DEVTYPE, ++ ++ ANDROID_WIFI_CMD_MAX ++}; ++ ++int rtw_android_cmdstr_to_num(char *cmdstr); ++int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd); ++ ++#if defined(RTW_ENABLE_WIFI_CONTROL_FUNC) ++int rtw_android_wifictrl_func_add(void); ++void rtw_android_wifictrl_func_del(void); ++void* wl_android_prealloc(int section, unsigned long size); ++ ++int wifi_get_irq_number(unsigned long *irq_flags_ptr); ++int wifi_set_power(int on, unsigned long msec); ++int wifi_get_mac_addr(unsigned char *buf); ++void *wifi_get_country_code(char *ccode); ++#else ++static int rtw_android_wifictrl_func_add(void) { return 0; } ++static void rtw_android_wifictrl_func_del(void) {} ++#endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */ ++ ++#endif //__RTW_ANDROID_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ap.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ap.h +new file mode 100644 +index 00000000..a93e1e8d +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ap.h +@@ -0,0 +1,65 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTW_AP_H_ ++#define __RTW_AP_H_ ++ ++#include ++#include ++#include ++ ++ ++#ifdef CONFIG_AP_MODE ++ ++//external function ++extern void rtw_indicate_sta_assoc_event(_adapter *padapter, struct sta_info *psta); ++extern void rtw_indicate_sta_disassoc_event(_adapter *padapter, struct sta_info *psta); ++ ++ ++void init_mlme_ap_info(_adapter *padapter); ++void free_mlme_ap_info(_adapter *padapter); ++//void update_BCNTIM(_adapter *padapter); ++void rtw_add_bcn_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 index, u8 *data, u8 len); ++void rtw_remove_bcn_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 index); ++void update_beacon(_adapter *padapter, u8 ie_id, u8 *oui, u8 tx); ++void add_RATid(_adapter *padapter, struct sta_info *psta, u8 rssi_level); ++void expire_timeout_chk(_adapter *padapter); ++void update_sta_info_apmode(_adapter *padapter, struct sta_info *psta); ++int rtw_check_beacon_data(_adapter *padapter, u8 *pbuf, int len); ++void rtw_ap_restore_network(_adapter *padapter); ++void rtw_set_macaddr_acl(_adapter *padapter, int mode); ++int rtw_acl_add_sta(_adapter *padapter, u8 *addr); ++int rtw_acl_remove_sta(_adapter *padapter, u8 *addr); ++ ++#ifdef CONFIG_NATIVEAP_MLME ++void associated_clients_update(_adapter *padapter, u8 updated); ++void bss_cap_update_on_sta_join(_adapter *padapter, struct sta_info *psta); ++u8 bss_cap_update_on_sta_leave(_adapter *padapter, struct sta_info *psta); ++void sta_info_update(_adapter *padapter, struct sta_info *psta); ++void ap_sta_info_defer_update(_adapter *padapter, struct sta_info *psta); ++u8 ap_free_sta(_adapter *padapter, struct sta_info *psta, bool active, u16 reason); ++int rtw_sta_flush(_adapter *padapter); ++int rtw_ap_inform_ch_switch(_adapter *padapter, u8 new_ch, u8 ch_offset); ++void start_ap_mode(_adapter *padapter); ++void stop_ap_mode(_adapter *padapter); ++#endif ++#endif //end of CONFIG_AP_MODE ++ ++#endif ++void update_bmc_sta(_adapter *padapter); +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_br_ext.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_br_ext.h +new file mode 100644 +index 00000000..c8d78016 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_br_ext.h +@@ -0,0 +1,76 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTW_BR_EXT_H_ ++#define _RTW_BR_EXT_H_ ++ ++#if 1 // rtw_wifi_driver ++#define CL_IPV6_PASS 1 ++#define MACADDRLEN 6 ++#define _DEBUG_ERR DBG_8192C ++#define _DEBUG_INFO //DBG_8192C ++#define DEBUG_WARN DBG_8192C ++#define DEBUG_INFO //DBG_8192C ++#define DEBUG_ERR DBG_8192C ++//#define GET_MY_HWADDR ((GET_MIB(priv))->dot11OperationEntry.hwaddr) ++#define GET_MY_HWADDR(padapter) ((padapter)->eeprompriv.mac_addr) ++#endif // rtw_wifi_driver ++ ++#define NAT25_HASH_BITS 4 ++#define NAT25_HASH_SIZE (1 << NAT25_HASH_BITS) ++#define NAT25_AGEING_TIME 300 ++ ++#ifdef CL_IPV6_PASS ++#define MAX_NETWORK_ADDR_LEN 17 ++#else ++#define MAX_NETWORK_ADDR_LEN 11 ++#endif ++ ++struct nat25_network_db_entry ++{ ++ struct nat25_network_db_entry *next_hash; ++ struct nat25_network_db_entry **pprev_hash; ++ atomic_t use_count; ++ unsigned char macAddr[6]; ++ unsigned long ageing_timer; ++ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; ++}; ++ ++enum NAT25_METHOD { ++ NAT25_MIN, ++ NAT25_CHECK, ++ NAT25_INSERT, ++ NAT25_LOOKUP, ++ NAT25_PARSE, ++ NAT25_MAX ++}; ++ ++struct br_ext_info { ++ unsigned int nat25_disable; ++ unsigned int macclone_enable; ++ unsigned int dhcp_bcst_disable; ++ int addPPPoETag; // 1: Add PPPoE relay-SID, 0: disable ++ unsigned char nat25_dmzMac[MACADDRLEN]; ++ unsigned int nat25sc_disable; ++}; ++ ++void nat25_db_cleanup(_adapter *priv); ++ ++#endif // _RTW_BR_EXT_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_bt_mp.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_bt_mp.h +new file mode 100644 +index 00000000..15746616 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_bt_mp.h +@@ -0,0 +1,318 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#ifndef __RTW_BT_MP_H ++#define __RTW_BT_MP_H ++ ++#include ++#include ++#include ++ ++ ++#if(MP_DRIVER == 1) ++ ++#pragma pack(1) ++ ++// definition for BT_UP_OP_BT_READY ++#define MP_BT_NOT_READY 0 ++#define MP_BT_READY 1 ++ ++// definition for BT_UP_OP_BT_SET_MODE ++typedef enum _MP_BT_MODE{ ++ MP_BT_MODE_RF_TXRX_TEST_MODE = 0, ++ MP_BT_MODE_BT20_DUT_TEST_MODE = 1, ++ MP_BT_MODE_BT40_DIRECT_TEST_MODE = 2, ++ MP_BT_MODE_CONNECT_TEST_MODE = 3, ++ MP_BT_MODE_MAX ++}MP_BT_MODE,*PMP_BT_MODE; ++ ++ ++// definition for BT_UP_OP_BT_SET_TX_RX_PARAMETER ++typedef struct _BT_TXRX_PARAMETERS{ ++ u1Byte txrxChannel; ++ u4Byte txrxTxPktCnt; ++ u1Byte txrxTxPktInterval; ++ u1Byte txrxPayloadType; ++ u1Byte txrxPktType; ++ u2Byte txrxPayloadLen; ++ u4Byte txrxPktHeader; ++ u1Byte txrxWhitenCoeff; ++ u1Byte txrxBdaddr[6]; ++ u1Byte txrxTxGainIndex; ++} BT_TXRX_PARAMETERS, *PBT_TXRX_PARAMETERS; ++ ++// txrxPktType ++typedef enum _MP_BT_PKT_TYPE{ ++ MP_BT_PKT_DH1 = 0, ++ MP_BT_PKT_DH3 = 1, ++ MP_BT_PKT_DH5 = 2, ++ MP_BT_PKT_2DH1 = 3, ++ MP_BT_PKT_2DH3 = 4, ++ MP_BT_PKT_2DH5 = 5, ++ MP_BT_PKT_3DH1 = 6, ++ MP_BT_PKT_3DH3 = 7, ++ MP_BT_PKT_3DH5 = 8, ++ MP_BT_PKT_LE = 9, ++ MP_BT_PKT_MAX ++}MP_BT_PKT_TYPE,*PMP_BT_PKT_TYPE; ++// txrxPayloadType ++typedef enum _MP_BT_PAYLOAD_TYPE{ ++ MP_BT_PAYLOAD_01010101 = 0, ++ MP_BT_PAYLOAD_ALL_1 = 1, ++ MP_BT_PAYLOAD_ALL_0 = 2, ++ MP_BT_PAYLOAD_11110000 = 3, ++ MP_BT_PAYLOAD_PRBS9 = 4, ++ MP_BT_PAYLOAD_MAX ++}MP_BT_PAYLOAD_TYPE,*PMP_BT_PAYLOAD_TYPE; ++ ++ ++// definition for BT_UP_OP_BT_TEST_CTRL ++typedef enum _MP_BT_TEST_CTRL{ ++ MP_BT_TEST_STOP_ALL_TESTS = 0, ++ MP_BT_TEST_START_RX_TEST = 1, ++ MP_BT_TEST_START_PACKET_TX_TEST = 2, ++ MP_BT_TEST_START_CONTINUOUS_TX_TEST = 3, ++ MP_BT_TEST_START_INQUIRY_SCAN_TEST = 4, ++ MP_BT_TEST_START_PAGE_SCAN_TEST = 5, ++ MP_BT_TEST_START_INQUIRY_PAGE_SCAN_TEST = 6, ++ MP_BT_TEST_START_LEGACY_CONNECT_TEST = 7, ++ MP_BT_TEST_START_LE_CONNECT_TEST_INITIATOR = 8, ++ MP_BT_TEST_START_LE_CONNECT_TEST_ADVERTISER = 9, ++ MP_BT_TEST_MAX ++}MP_BT_TEST_CTRL,*PMP_BT_TEST_CTRL; ++ ++ ++typedef enum _RTL_EXT_C2H_EVT ++{ ++ EXT_C2H_WIFI_FW_ACTIVE_RSP = 0, ++ EXT_C2H_TRIG_BY_BT_FW = 1, ++ MAX_EXT_C2HEVENT ++}RTL_EXT_C2H_EVT; ++ ++ ++// return status definition to the user layer ++typedef enum _BT_CTRL_STATUS{ ++ BT_STATUS_SUCCESS = 0x00, // Success ++ BT_STATUS_BT_OP_SUCCESS = 0x01, // bt fw op execution success ++ BT_STATUS_H2C_SUCCESS = 0x02, // H2c success ++ BT_STATUS_H2C_TIMTOUT = 0x03, // H2c timeout ++ BT_STATUS_H2C_BT_NO_RSP = 0x04, // H2c sent, bt no rsp ++ BT_STATUS_C2H_SUCCESS = 0x05, // C2h success ++ BT_STATUS_C2H_REQNUM_MISMATCH = 0x06, // bt fw wrong rsp ++ BT_STATUS_OPCODE_U_VERSION_MISMATCH = 0x07, // Upper layer OP code version mismatch. ++ BT_STATUS_OPCODE_L_VERSION_MISMATCH = 0x08, // Lower layer OP code version mismatch. ++ BT_STATUS_UNKNOWN_OPCODE_U = 0x09, // Unknown Upper layer OP code ++ BT_STATUS_UNKNOWN_OPCODE_L = 0x0a, // Unknown Lower layer OP code ++ BT_STATUS_PARAMETER_FORMAT_ERROR_U = 0x0b, // Wrong parameters sent by upper layer. ++ BT_STATUS_PARAMETER_FORMAT_ERROR_L = 0x0c, // bt fw parameter format is not consistency ++ BT_STATUS_PARAMETER_OUT_OF_RANGE_U = 0x0d, // uppery layer parameter value is out of range ++ BT_STATUS_PARAMETER_OUT_OF_RANGE_L = 0x0e, // bt fw parameter value is out of range ++ BT_STATUS_UNKNOWN_STATUS_L = 0x0f, // bt returned an defined status code ++ BT_STATUS_UNKNOWN_STATUS_H = 0x10, // driver need to do error handle or not handle-well. ++ BT_STATUS_WRONG_LEVEL = 0x11, // should be under passive level ++ BT_STATUS_MAX ++}BT_CTRL_STATUS,*PBT_CTRL_STATUS; ++ ++// OP codes definition between the user layer and driver ++typedef enum _BT_CTRL_OPCODE_UPPER{ ++ BT_UP_OP_BT_READY = 0x00, ++ BT_UP_OP_BT_SET_MODE = 0x01, ++ BT_UP_OP_BT_SET_TX_RX_PARAMETER = 0x02, ++ BT_UP_OP_BT_SET_GENERAL = 0x03, ++ BT_UP_OP_BT_GET_GENERAL = 0x04, ++ BT_UP_OP_BT_TEST_CTRL = 0x05, ++ BT_UP_OP_TEST_BT = 0x06, ++ BT_UP_OP_MAX ++}BT_CTRL_OPCODE_UPPER,*PBT_CTRL_OPCODE_UPPER; ++ ++ ++typedef enum _BT_SET_GENERAL{ ++ BT_GSET_REG = 0x00, ++ BT_GSET_RESET = 0x01, ++ BT_GSET_TARGET_BD_ADDR = 0x02, ++ BT_GSET_TX_PWR_FINETUNE = 0x03, ++ BT_SET_TRACKING_INTERVAL = 0x04, ++ BT_SET_THERMAL_METER = 0x05, ++ BT_ENABLE_CFO_TRACKING = 0x06, ++ BT_GSET_UPDATE_BT_PATCH = 0x07, ++ BT_GSET_MAX ++}BT_SET_GENERAL,*PBT_SET_GENERAL; ++ ++typedef enum _BT_GET_GENERAL{ ++ BT_GGET_REG = 0x00, ++ BT_GGET_STATUS = 0x01, ++ BT_GGET_REPORT = 0x02, ++ BT_GGET_AFH_MAP = 0x03, ++ BT_GGET_AFH_STATUS = 0x04, ++ BT_GGET_MAX ++}BT_GET_GENERAL,*PBT_GET_GENERAL; ++ ++// definition for BT_UP_OP_BT_SET_GENERAL ++typedef enum _BT_REG_TYPE{ ++ BT_REG_RF = 0, ++ BT_REG_MODEM = 1, ++ BT_REG_BLUEWIZE = 2, ++ BT_REG_VENDOR = 3, ++ BT_REG_LE = 4, ++ BT_REG_MAX ++}BT_REG_TYPE,*PBT_REG_TYPE; ++ ++// definition for BT_LO_OP_GET_AFH_MAP ++typedef enum _BT_AFH_MAP_TYPE{ ++ BT_AFH_MAP_RESULT = 0, ++ BT_AFH_MAP_WIFI_PSD_ONLY = 1, ++ BT_AFH_MAP_WIFI_CH_BW_ONLY = 2, ++ BT_AFH_MAP_BT_PSD_ONLY = 3, ++ BT_AFH_MAP_HOST_CLASSIFICATION_ONLY = 4, ++ BT_AFH_MAP_MAX ++}BT_AFH_MAP_TYPE,*PBT_AFH_MAP_TYPE; ++ ++// definition for BT_UP_OP_BT_GET_GENERAL ++typedef enum _BT_REPORT_TYPE{ ++ BT_REPORT_RX_PACKET_CNT = 0, ++ BT_REPORT_RX_ERROR_BITS = 1, ++ BT_REPORT_RSSI = 2, ++ BT_REPORT_CFO_HDR_QUALITY = 3, ++ BT_REPORT_CONNECT_TARGET_BD_ADDR = 4, ++ BT_REPORT_MAX ++}BT_REPORT_TYPE,*PBT_REPORT_TYPE; ++ ++VOID ++MPTBT_Test( ++ IN PADAPTER Adapter, ++ IN u1Byte opCode, ++ IN u1Byte byte1, ++ IN u1Byte byte2, ++ IN u1Byte byte3 ++ ); ++ ++NDIS_STATUS ++MPTBT_SendOidBT( ++ IN PADAPTER pAdapter, ++ IN PVOID InformationBuffer, ++ IN ULONG InformationBufferLength, ++ OUT PULONG BytesRead, ++ OUT PULONG BytesNeeded ++ ); ++ ++VOID ++MPTBT_FwC2hBtMpCtrl( ++ PADAPTER Adapter, ++ pu1Byte tmpBuf, ++ u1Byte length ++ ); ++ ++void MPh2c_timeout_handle(void *FunctionContext); ++ ++VOID mptbt_BtControlProcess( ++ PADAPTER Adapter, ++ PVOID pInBuf ++ ); ++ ++#define BT_H2C_MAX_RETRY 1 ++#define BT_MAX_C2H_LEN 20 ++ ++typedef struct _BT_REQ_CMD{ ++ UCHAR opCodeVer; ++ UCHAR OpCode; ++ USHORT paraLength; ++ UCHAR pParamStart[100]; ++} BT_REQ_CMD, *PBT_REQ_CMD; ++ ++typedef struct _BT_RSP_CMD{ ++ USHORT status; ++ USHORT paraLength; ++ UCHAR pParamStart[100]; ++} BT_RSP_CMD, *PBT_RSP_CMD; ++ ++ ++typedef struct _BT_H2C{ ++ u1Byte opCodeVer:4; ++ u1Byte reqNum:4; ++ u1Byte opCode; ++ u1Byte buf[100]; ++}BT_H2C, *PBT_H2C; ++ ++ ++ ++typedef struct _BT_EXT_C2H{ ++ u1Byte extendId; ++ u1Byte statusCode:4; ++ u1Byte retLen:4; ++ u1Byte opCodeVer:4; ++ u1Byte reqNum:4; ++ u1Byte buf[100]; ++}BT_EXT_C2H, *PBT_EXT_C2H; ++ ++typedef enum _BT_OPCODE_STATUS{ ++ BT_OP_STATUS_SUCCESS = 0x00, // Success ++ BT_OP_STATUS_VERSION_MISMATCH = 0x01, ++ BT_OP_STATUS_UNKNOWN_OPCODE = 0x02, ++ BT_OP_STATUS_ERROR_PARAMETER = 0x03, ++ BT_OP_STATUS_MAX ++}BT_OPCODE_STATUS,*PBT_OPCODE_STATUS; ++ ++ ++//OP codes definition between driver and bt fw ++typedef enum _BT_CTRL_OPCODE_LOWER{ ++ BT_LO_OP_GET_BT_VERSION = 0x00, ++ BT_LO_OP_RESET = 0x01, ++ BT_LO_OP_TEST_CTRL = 0x02, ++ BT_LO_OP_SET_BT_MODE = 0x03, ++ BT_LO_OP_SET_CHNL_TX_GAIN = 0x04, ++ BT_LO_OP_SET_PKT_TYPE_LEN = 0x05, ++ BT_LO_OP_SET_PKT_CNT_L_PL_TYPE = 0x06, ++ BT_LO_OP_SET_PKT_CNT_H_PKT_INTV = 0x07, ++ BT_LO_OP_SET_PKT_HEADER = 0x08, ++ BT_LO_OP_SET_WHITENCOEFF = 0x09, ++ BT_LO_OP_SET_BD_ADDR_L = 0x0a, ++ BT_LO_OP_SET_BD_ADDR_H = 0x0b, ++ BT_LO_OP_WRITE_REG_ADDR = 0x0c, ++ BT_LO_OP_WRITE_REG_VALUE = 0x0d, ++ BT_LO_OP_GET_BT_STATUS = 0x0e, ++ BT_LO_OP_GET_BD_ADDR_L = 0x0f, ++ BT_LO_OP_GET_BD_ADDR_H = 0x10, ++ BT_LO_OP_READ_REG = 0x11, ++ BT_LO_OP_SET_TARGET_BD_ADDR_L = 0x12, ++ BT_LO_OP_SET_TARGET_BD_ADDR_H = 0x13, ++ BT_LO_OP_SET_TX_POWER_CALIBRATION = 0x14, ++ BT_LO_OP_GET_RX_PKT_CNT_L = 0x15, ++ BT_LO_OP_GET_RX_PKT_CNT_H = 0x16, ++ BT_LO_OP_GET_RX_ERROR_BITS_L = 0x17, ++ BT_LO_OP_GET_RX_ERROR_BITS_H = 0x18, ++ BT_LO_OP_GET_RSSI = 0x19, ++ BT_LO_OP_GET_CFO_HDR_QUALITY_L = 0x1a, ++ BT_LO_OP_GET_CFO_HDR_QUALITY_H = 0x1b, ++ BT_LO_OP_GET_TARGET_BD_ADDR_L = 0x1c, ++ BT_LO_OP_GET_TARGET_BD_ADDR_H = 0x1d, ++ BT_LO_OP_GET_AFH_MAP_L = 0x1e, ++ BT_LO_OP_GET_AFH_MAP_M = 0x1f, ++ BT_LO_OP_GET_AFH_MAP_H = 0x20, ++ BT_LO_OP_GET_AFH_STATUS = 0x21, ++ BT_LO_OP_SET_TRACKING_INTERVAL = 0x22, ++ BT_LO_OP_SET_THERMAL_METER = 0x23, ++ BT_LO_OP_ENABLE_CFO_TRACKING = 0x24, ++ BT_LO_OP_MAX ++}BT_CTRL_OPCODE_LOWER,*PBT_CTRL_OPCODE_LOWER; ++ ++#endif /* #if(MP_DRIVER == 1) */ ++ ++#endif // #ifndef __INC_MPT_BT_H ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_byteorder.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_byteorder.h +new file mode 100644 +index 00000000..ad72188e +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_byteorder.h +@@ -0,0 +1,40 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTL871X_BYTEORDER_H_ ++#define _RTL871X_BYTEORDER_H_ ++ ++#include ++ ++#if defined (CONFIG_LITTLE_ENDIAN) && defined (CONFIG_BIG_ENDIAN) ++#error "Shall be CONFIG_LITTLE_ENDIAN or CONFIG_BIG_ENDIAN, but not both!\n" ++#endif ++ ++#if defined (CONFIG_LITTLE_ENDIAN) ++#ifndef CONFIG_PLATFORM_MSTAR ++# include ++#endif ++#elif defined (CONFIG_BIG_ENDIAN) ++# include ++#else ++# error "Must be LITTLE/BIG Endian Host" ++#endif ++ ++#endif /* _RTL871X_BYTEORDER_H_ */ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_cmd.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_cmd.h +new file mode 100644 +index 00000000..97a468c0 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_cmd.h +@@ -0,0 +1,1178 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTW_CMD_H_ ++#define __RTW_CMD_H_ ++ ++#include ++#include ++#include ++#include ++ ++#define C2H_MEM_SZ (16*1024) ++ ++#ifndef CONFIG_RTL8711FW ++ ++ #include ++ #include // ++ ++ ++ #define FREE_CMDOBJ_SZ 128 ++ ++ #define MAX_CMDSZ 1024 ++ #define MAX_RSPSZ 512 ++ #define MAX_EVTSZ 1024 ++ ++#ifdef PLATFORM_OS_CE ++ #define CMDBUFF_ALIGN_SZ 4 ++#else ++ #define CMDBUFF_ALIGN_SZ 512 ++#endif ++ ++ struct cmd_obj { ++ _adapter *padapter; ++ u16 cmdcode; ++ u8 res; ++ u8 *parmbuf; ++ u32 cmdsz; ++ u8 *rsp; ++ u32 rspsz; ++ //_sema cmd_sem; ++ _list list; ++ }; ++ ++ struct cmd_priv { ++ _sema cmd_queue_sema; ++ //_sema cmd_done_sema; ++ _sema terminate_cmdthread_sema; ++ _queue cmd_queue; ++ u8 cmd_seq; ++ u8 *cmd_buf; //shall be non-paged, and 4 bytes aligned ++ u8 *cmd_allocated_buf; ++ u8 *rsp_buf; //shall be non-paged, and 4 bytes aligned ++ u8 *rsp_allocated_buf; ++ u32 cmd_issued_cnt; ++ u32 cmd_done_cnt; ++ u32 rsp_cnt; ++ u8 cmdthd_running; ++ u8 stop_req; ++ _adapter *padapter; ++ }; ++ ++#ifdef CONFIG_EVENT_THREAD_MODE ++ struct evt_obj { ++ u16 evtcode; ++ u8 res; ++ u8 *parmbuf; ++ u32 evtsz; ++ _list list; ++ }; ++#endif ++ ++ struct evt_priv { ++#ifdef CONFIG_EVENT_THREAD_MODE ++ _sema evt_notify; ++ _sema terminate_evtthread_sema; ++ _queue evt_queue; ++#endif ++ ++#define CONFIG_C2H_WK ++#ifdef CONFIG_C2H_WK ++ _workitem c2h_wk; ++ bool c2h_wk_alive; ++ struct rtw_cbuf *c2h_queue; ++ #define C2H_QUEUE_MAX_LEN 10 ++#endif ++ ++#ifdef CONFIG_H2CLBK ++ _sema lbkevt_done; ++ u8 lbkevt_limit; ++ u8 lbkevt_num; ++ u8 *cmdevt_parm; ++#endif ++ ATOMIC_T event_seq; ++ u8 *evt_buf; //shall be non-paged, and 4 bytes aligned ++ u8 *evt_allocated_buf; ++ u32 evt_done_cnt; ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ u8 *c2h_mem; ++ u8 *allocated_c2h_mem; ++#ifdef PLATFORM_OS_XP ++ PMDL pc2h_mdl; ++#endif ++#endif ++ ++ }; ++ ++#define init_h2fwcmd_w_parm_no_rsp(pcmd, pparm, code) \ ++do {\ ++ _rtw_init_listhead(&pcmd->list);\ ++ pcmd->cmdcode = code;\ ++ pcmd->parmbuf = (u8 *)(pparm);\ ++ pcmd->cmdsz = sizeof (*pparm);\ ++ pcmd->rsp = NULL;\ ++ pcmd->rspsz = 0;\ ++} while(0) ++ ++struct c2h_evt_hdr { ++ u8 id:4; ++ u8 plen:4; ++ u8 seq; ++ u8 payload[0]; ++}; ++ ++#define c2h_evt_exist(c2h_evt) ((c2h_evt)->id || (c2h_evt)->plen) ++ ++extern u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj); ++extern struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv); ++extern void rtw_free_cmd_obj(struct cmd_obj *pcmd); ++ ++#ifdef CONFIG_EVENT_THREAD_MODE ++extern u32 rtw_enqueue_evt(struct evt_priv *pevtpriv, struct evt_obj *obj); ++extern struct evt_obj *rtw_dequeue_evt(_queue *queue); ++extern void rtw_free_evt_obj(struct evt_obj *pcmd); ++#endif ++ ++void rtw_stop_cmd_thread(_adapter *adapter); ++thread_return rtw_cmd_thread(thread_context context); ++ ++extern u32 rtw_init_cmd_priv (struct cmd_priv *pcmdpriv); ++extern void rtw_free_cmd_priv (struct cmd_priv *pcmdpriv); ++ ++extern u32 rtw_init_evt_priv (struct evt_priv *pevtpriv); ++extern void rtw_free_evt_priv (struct evt_priv *pevtpriv); ++extern void rtw_cmd_clr_isr(struct cmd_priv *pcmdpriv); ++extern void rtw_evt_notify_isr(struct evt_priv *pevtpriv); ++#ifdef CONFIG_P2P ++u8 p2p_protocol_wk_cmd(_adapter*padapter, int intCmdType ); ++#endif //CONFIG_P2P ++ ++#else ++ #include ++#endif /* CONFIG_RTL8711FW */ ++ ++enum rtw_drvextra_cmd_id ++{ ++ NONE_WK_CID, ++ DYNAMIC_CHK_WK_CID, ++ DM_CTRL_WK_CID, ++ PBC_POLLING_WK_CID, ++ POWER_SAVING_CTRL_WK_CID,//IPS,AUTOSuspend ++ LPS_CTRL_WK_CID, ++ ANT_SELECT_WK_CID, ++ P2P_PS_WK_CID, ++ P2P_PROTO_WK_CID, ++ CHECK_HIQ_WK_CID,//for softap mode, check hi queue if empty ++ INTEl_WIDI_WK_CID, ++ C2H_WK_CID, ++ RTP_TIMER_CFG_WK_CID, ++ RESET_SECURITYPRIV, // add for CONFIG_IEEE80211W, none 11w also can use ++ FREE_ASSOC_RESOURCES, // add for CONFIG_IEEE80211W, none 11w also can use ++#ifdef CONFIG_DETECT_C2H_BY_POLLING ++ EVENT_POLLING_CID, ++#endif ++ MAX_WK_CID ++}; ++ ++enum LPS_CTRL_TYPE ++{ ++ LPS_CTRL_SCAN=0, ++ LPS_CTRL_JOINBSS=1, ++ LPS_CTRL_CONNECT=2, ++ LPS_CTRL_DISCONNECT=3, ++ LPS_CTRL_SPECIAL_PACKET=4, ++ LPS_CTRL_LEAVE=5, ++}; ++ ++enum RFINTFS { ++ SWSI, ++ HWSI, ++ HWPI, ++}; ++ ++/* ++Caller Mode: Infra, Ad-HoC(C) ++ ++Notes: To enter USB suspend mode ++ ++Command Mode ++ ++*/ ++struct usb_suspend_parm { ++ u32 action;// 1: sleep, 0:resume ++}; ++ ++/* ++Caller Mode: Infra, Ad-HoC ++ ++Notes: To join a known BSS. ++ ++Command-Event Mode ++ ++*/ ++ ++/* ++Caller Mode: Infra, Ad-Hoc ++ ++Notes: To join the specified bss ++ ++Command Event Mode ++ ++*/ ++struct joinbss_parm { ++ WLAN_BSSID_EX network; ++}; ++ ++/* ++Caller Mode: Infra, Ad-HoC(C) ++ ++Notes: To disconnect the current associated BSS ++ ++Command Mode ++ ++*/ ++struct disconnect_parm { ++ u32 deauth_timeout_ms; ++}; ++ ++/* ++Caller Mode: AP, Ad-HoC(M) ++ ++Notes: To create a BSS ++ ++Command Mode ++*/ ++struct createbss_parm { ++ WLAN_BSSID_EX network; ++}; ++ ++/* ++Caller Mode: AP, Ad-HoC, Infra ++ ++Notes: To set the NIC mode of RTL8711 ++ ++Command Mode ++ ++The definition of mode: ++ ++#define IW_MODE_AUTO 0 // Let the driver decides which AP to join ++#define IW_MODE_ADHOC 1 // Single cell network (Ad-Hoc Clients) ++#define IW_MODE_INFRA 2 // Multi cell network, roaming, .. ++#define IW_MODE_MASTER 3 // Synchronisation master or Access Point ++#define IW_MODE_REPEAT 4 // Wireless Repeater (forwarder) ++#define IW_MODE_SECOND 5 // Secondary master/repeater (backup) ++#define IW_MODE_MONITOR 6 // Passive monitor (listen only) ++ ++*/ ++struct setopmode_parm { ++ u8 mode; ++ u8 rsvd[3]; ++}; ++ ++/* ++Caller Mode: AP, Ad-HoC, Infra ++ ++Notes: To ask RTL8711 performing site-survey ++ ++Command-Event Mode ++ ++*/ ++ ++#define RTW_SSID_SCAN_AMOUNT 9 // for WEXT_CSCAN_AMOUNT 9 ++#define RTW_CHANNEL_SCAN_AMOUNT (14+37) ++struct sitesurvey_parm { ++ sint scan_mode; //active: 1, passive: 0 ++ /* sint bsslimit; // 1 ~ 48 */ ++ u8 ssid_num; ++ u8 ch_num; ++ NDIS_802_11_SSID ssid[RTW_SSID_SCAN_AMOUNT]; ++ struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT]; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To set the auth type of RTL8711. open/shared/802.1x ++ ++Command Mode ++ ++*/ ++struct setauth_parm { ++ u8 mode; //0: legacy open, 1: legacy shared 2: 802.1x ++ u8 _1x; //0: PSK, 1: TLS ++ u8 rsvd[2]; ++}; ++ ++/* ++Caller Mode: Infra ++ ++a. algorithm: wep40, wep104, tkip & aes ++b. keytype: grp key/unicast key ++c. key contents ++ ++when shared key ==> keyid is the camid ++when 802.1x ==> keyid [0:1] ==> grp key ++when 802.1x ==> keyid > 2 ==> unicast key ++ ++*/ ++struct setkey_parm { ++ u8 algorithm; // encryption algorithm, could be none, wep40, TKIP, CCMP, wep104 ++ u8 keyid; ++ u8 grpkey; // 1: this is the grpkey for 802.1x. 0: this is the unicast key for 802.1x ++ u8 set_tx; // 1: main tx key for wep. 0: other key. ++ u8 key[16]; // this could be 40 or 104 ++}; ++ ++/* ++When in AP or Ad-Hoc mode, this is used to ++allocate an sw/hw entry for a newly associated sta. ++ ++Command ++ ++when shared key ==> algorithm/keyid ++ ++*/ ++struct set_stakey_parm { ++ u8 addr[ETH_ALEN]; ++ u8 algorithm; ++ u8 id;// currently for erasing cam entry if algorithm == _NO_PRIVACY_ ++ u8 key[16]; ++}; ++ ++struct set_stakey_rsp { ++ u8 addr[ETH_ALEN]; ++ u8 keyid; ++ u8 rsvd; ++}; ++ ++/* ++Caller Ad-Hoc/AP ++ ++Command -Rsp(AID == CAMID) mode ++ ++This is to force fw to add an sta_data entry per driver's request. ++ ++FW will write an cam entry associated with it. ++ ++*/ ++struct set_assocsta_parm { ++ u8 addr[ETH_ALEN]; ++}; ++ ++struct set_assocsta_rsp { ++ u8 cam_id; ++ u8 rsvd[3]; ++}; ++ ++/* ++ Caller Ad-Hoc/AP ++ ++ Command mode ++ ++ This is to force fw to del an sta_data entry per driver's request ++ ++ FW will invalidate the cam entry associated with it. ++ ++*/ ++struct del_assocsta_parm { ++ u8 addr[ETH_ALEN]; ++}; ++ ++/* ++Caller Mode: AP/Ad-HoC(M) ++ ++Notes: To notify fw that given staid has changed its power state ++ ++Command Mode ++ ++*/ ++struct setstapwrstate_parm { ++ u8 staid; ++ u8 status; ++ u8 hwaddr[6]; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To setup the basic rate of RTL8711 ++ ++Command Mode ++ ++*/ ++struct setbasicrate_parm { ++ u8 basicrates[NumRates]; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To read the current basic rate ++ ++Command-Rsp Mode ++ ++*/ ++struct getbasicrate_parm { ++ u32 rsvd; ++}; ++ ++struct getbasicrate_rsp { ++ u8 basicrates[NumRates]; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To setup the data rate of RTL8711 ++ ++Command Mode ++ ++*/ ++struct setdatarate_parm { ++#ifdef MP_FIRMWARE_OFFLOAD ++ u32 curr_rateidx; ++#else ++ u8 mac_id; ++ u8 datarates[NumRates]; ++#endif ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To read the current data rate ++ ++Command-Rsp Mode ++ ++*/ ++struct getdatarate_parm { ++ u32 rsvd; ++ ++}; ++struct getdatarate_rsp { ++ u8 datarates[NumRates]; ++}; ++ ++ ++/* ++Caller Mode: Any ++AP: AP can use the info for the contents of beacon frame ++Infra: STA can use the info when sitesurveying ++Ad-HoC(M): Like AP ++Ad-HoC(C): Like STA ++ ++ ++Notes: To set the phy capability of the NIC ++ ++Command Mode ++ ++*/ ++ ++struct setphyinfo_parm { ++ struct regulatory_class class_sets[NUM_REGULATORYS]; ++ u8 status; ++}; ++ ++struct getphyinfo_parm { ++ u32 rsvd; ++}; ++ ++struct getphyinfo_rsp { ++ struct regulatory_class class_sets[NUM_REGULATORYS]; ++ u8 status; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To set the channel/modem/band ++This command will be used when channel/modem/band is changed. ++ ++Command Mode ++ ++*/ ++struct setphy_parm { ++ u8 rfchannel; ++ u8 modem; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To get the current setting of channel/modem/band ++ ++Command-Rsp Mode ++ ++*/ ++struct getphy_parm { ++ u32 rsvd; ++ ++}; ++struct getphy_rsp { ++ u8 rfchannel; ++ u8 modem; ++}; ++ ++struct readBB_parm { ++ u8 offset; ++}; ++struct readBB_rsp { ++ u8 value; ++}; ++ ++struct readTSSI_parm { ++ u8 offset; ++}; ++struct readTSSI_rsp { ++ u8 value; ++}; ++ ++struct writeBB_parm { ++ u8 offset; ++ u8 value; ++}; ++ ++struct readRF_parm { ++ u8 offset; ++}; ++struct readRF_rsp { ++ u32 value; ++}; ++ ++struct writeRF_parm { ++ u32 offset; ++ u32 value; ++}; ++ ++struct getrfintfs_parm { ++ u8 rfintfs; ++}; ++ ++ ++struct Tx_Beacon_param ++{ ++ WLAN_BSSID_EX network; ++}; ++ ++/* ++ Notes: This command is used for H2C/C2H loopback testing ++ ++ mac[0] == 0 ++ ==> CMD mode, return H2C_SUCCESS. ++ The following condition must be ture under CMD mode ++ mac[1] == mac[4], mac[2] == mac[3], mac[0]=mac[5]= 0; ++ s0 == 0x1234, s1 == 0xabcd, w0 == 0x78563412, w1 == 0x5aa5def7; ++ s2 == (b1 << 8 | b0); ++ ++ mac[0] == 1 ++ ==> CMD_RSP mode, return H2C_SUCCESS_RSP ++ ++ The rsp layout shall be: ++ rsp: parm: ++ mac[0] = mac[5]; ++ mac[1] = mac[4]; ++ mac[2] = mac[3]; ++ mac[3] = mac[2]; ++ mac[4] = mac[1]; ++ mac[5] = mac[0]; ++ s0 = s1; ++ s1 = swap16(s0); ++ w0 = swap32(w1); ++ b0 = b1 ++ s2 = s0 + s1 ++ b1 = b0 ++ w1 = w0 ++ ++ mac[0] == 2 ++ ==> CMD_EVENT mode, return H2C_SUCCESS ++ The event layout shall be: ++ event: parm: ++ mac[0] = mac[5]; ++ mac[1] = mac[4]; ++ mac[2] = event's sequence number, starting from 1 to parm's marc[3] ++ mac[3] = mac[2]; ++ mac[4] = mac[1]; ++ mac[5] = mac[0]; ++ s0 = swap16(s0) - event.mac[2]; ++ s1 = s1 + event.mac[2]; ++ w0 = swap32(w0); ++ b0 = b1 ++ s2 = s0 + event.mac[2] ++ b1 = b0 ++ w1 = swap32(w1) - event.mac[2]; ++ ++ parm->mac[3] is the total event counts that host requested. ++ ++ ++ event will be the same with the cmd's param. ++ ++*/ ++ ++#ifdef CONFIG_H2CLBK ++ ++struct seth2clbk_parm { ++ u8 mac[6]; ++ u16 s0; ++ u16 s1; ++ u32 w0; ++ u8 b0; ++ u16 s2; ++ u8 b1; ++ u32 w1; ++}; ++ ++struct geth2clbk_parm { ++ u32 rsv; ++}; ++ ++struct geth2clbk_rsp { ++ u8 mac[6]; ++ u16 s0; ++ u16 s1; ++ u32 w0; ++ u8 b0; ++ u16 s2; ++ u8 b1; ++ u32 w1; ++}; ++ ++#endif /* CONFIG_H2CLBK */ ++ ++// CMD param Formart for driver extra cmd handler ++struct drvextra_cmd_parm { ++ int ec_id; //extra cmd id ++ int type_size; // Can use this field as the type id or command size ++ unsigned char *pbuf; ++}; ++ ++/*------------------- Below are used for RF/BB tunning ---------------------*/ ++ ++struct setantenna_parm { ++ u8 tx_antset; ++ u8 rx_antset; ++ u8 tx_antenna; ++ u8 rx_antenna; ++}; ++ ++struct enrateadaptive_parm { ++ u32 en; ++}; ++ ++struct settxagctbl_parm { ++ u32 txagc[MAX_RATES_LENGTH]; ++}; ++ ++struct gettxagctbl_parm { ++ u32 rsvd; ++}; ++struct gettxagctbl_rsp { ++ u32 txagc[MAX_RATES_LENGTH]; ++}; ++ ++struct setagcctrl_parm { ++ u32 agcctrl; // 0: pure hw, 1: fw ++}; ++ ++ ++struct setssup_parm { ++ u32 ss_ForceUp[MAX_RATES_LENGTH]; ++}; ++ ++struct getssup_parm { ++ u32 rsvd; ++}; ++struct getssup_rsp { ++ u8 ss_ForceUp[MAX_RATES_LENGTH]; ++}; ++ ++ ++struct setssdlevel_parm { ++ u8 ss_DLevel[MAX_RATES_LENGTH]; ++}; ++ ++struct getssdlevel_parm { ++ u32 rsvd; ++}; ++struct getssdlevel_rsp { ++ u8 ss_DLevel[MAX_RATES_LENGTH]; ++}; ++ ++struct setssulevel_parm { ++ u8 ss_ULevel[MAX_RATES_LENGTH]; ++}; ++ ++struct getssulevel_parm { ++ u32 rsvd; ++}; ++struct getssulevel_rsp { ++ u8 ss_ULevel[MAX_RATES_LENGTH]; ++}; ++ ++ ++struct setcountjudge_parm { ++ u8 count_judge[MAX_RATES_LENGTH]; ++}; ++ ++struct getcountjudge_parm { ++ u32 rsvd; ++}; ++struct getcountjudge_rsp { ++ u8 count_judge[MAX_RATES_LENGTH]; ++}; ++ ++ ++struct setratable_parm { ++ u8 ss_ForceUp[NumRates]; ++ u8 ss_ULevel[NumRates]; ++ u8 ss_DLevel[NumRates]; ++ u8 count_judge[NumRates]; ++}; ++ ++struct getratable_parm { ++ uint rsvd; ++}; ++struct getratable_rsp { ++ u8 ss_ForceUp[NumRates]; ++ u8 ss_ULevel[NumRates]; ++ u8 ss_DLevel[NumRates]; ++ u8 count_judge[NumRates]; ++}; ++ ++ ++//to get TX,RX retry count ++struct gettxretrycnt_parm{ ++ unsigned int rsvd; ++}; ++struct gettxretrycnt_rsp{ ++ unsigned long tx_retrycnt; ++}; ++ ++struct getrxretrycnt_parm{ ++ unsigned int rsvd; ++}; ++struct getrxretrycnt_rsp{ ++ unsigned long rx_retrycnt; ++}; ++ ++//to get BCNOK,BCNERR count ++struct getbcnokcnt_parm{ ++ unsigned int rsvd; ++}; ++struct getbcnokcnt_rsp{ ++ unsigned long bcnokcnt; ++}; ++ ++struct getbcnerrcnt_parm{ ++ unsigned int rsvd; ++}; ++struct getbcnerrcnt_rsp{ ++ unsigned long bcnerrcnt; ++}; ++ ++// to get current TX power level ++struct getcurtxpwrlevel_parm{ ++ unsigned int rsvd; ++}; ++struct getcurtxpwrlevel_rsp{ ++ unsigned short tx_power; ++}; ++ ++struct setprobereqextraie_parm { ++ unsigned char e_id; ++ unsigned char ie_len; ++ unsigned char ie[0]; ++}; ++ ++struct setassocreqextraie_parm { ++ unsigned char e_id; ++ unsigned char ie_len; ++ unsigned char ie[0]; ++}; ++ ++struct setproberspextraie_parm { ++ unsigned char e_id; ++ unsigned char ie_len; ++ unsigned char ie[0]; ++}; ++ ++struct setassocrspextraie_parm { ++ unsigned char e_id; ++ unsigned char ie_len; ++ unsigned char ie[0]; ++}; ++ ++ ++struct addBaReq_parm ++{ ++ unsigned int tid; ++ u8 addr[ETH_ALEN]; ++}; ++ ++/*H2C Handler index: 46 */ ++struct set_ch_parm { ++ u8 ch; ++ u8 bw; ++ u8 ch_offset; ++}; ++ ++#ifdef MP_FIRMWARE_OFFLOAD ++/*H2C Handler index: 47 */ ++struct SetTxPower_parm ++{ ++ u8 TxPower; ++}; ++ ++/*H2C Handler index: 48 */ ++struct SwitchAntenna_parm ++{ ++ u16 antenna_tx; ++ u16 antenna_rx; ++// R_ANTENNA_SELECT_CCK cck_txrx; ++ u8 cck_txrx; ++}; ++ ++/*H2C Handler index: 49 */ ++struct SetCrystalCap_parm ++{ ++ u32 curr_crystalcap; ++}; ++ ++/*H2C Handler index: 50 */ ++struct SetSingleCarrierTx_parm ++{ ++ u8 bStart; ++}; ++ ++/*H2C Handler index: 51 */ ++struct SetSingleToneTx_parm ++{ ++ u8 bStart; ++ u8 curr_rfpath; ++}; ++ ++/*H2C Handler index: 52 */ ++struct SetCarrierSuppressionTx_parm ++{ ++ u8 bStart; ++ u32 curr_rateidx; ++}; ++ ++/*H2C Handler index: 53 */ ++struct SetContinuousTx_parm ++{ ++ u8 bStart; ++ u8 CCK_flag; /*1:CCK 2:OFDM*/ ++ u32 curr_rateidx; ++}; ++ ++/*H2C Handler index: 54 */ ++struct SwitchBandwidth_parm ++{ ++ u8 curr_bandwidth; ++}; ++ ++#endif /* MP_FIRMWARE_OFFLOAD */ ++ ++/*H2C Handler index: 59 */ ++struct SetChannelPlan_param ++{ ++ u8 channel_plan; ++}; ++ ++/*H2C Handler index: 60 */ ++struct LedBlink_param ++{ ++ PLED_871x pLed; ++}; ++ ++/*H2C Handler index: 61 */ ++struct SetChannelSwitch_param ++{ ++ u8 new_ch_no; ++}; ++ ++/*H2C Handler index: 62 */ ++struct TDLSoption_param ++{ ++ u8 addr[ETH_ALEN]; ++ u8 option; ++}; ++ ++#define GEN_CMD_CODE(cmd) cmd ## _CMD_ ++ ++ ++/* ++ ++Result: ++0x00: success ++0x01: sucess, and check Response. ++0x02: cmd ignored due to duplicated sequcne number ++0x03: cmd dropped due to invalid cmd code ++0x04: reserved. ++ ++*/ ++ ++#define H2C_RSP_OFFSET 512 ++ ++#define H2C_SUCCESS 0x00 ++#define H2C_SUCCESS_RSP 0x01 ++#define H2C_DUPLICATED 0x02 ++#define H2C_DROPPED 0x03 ++#define H2C_PARAMETERS_ERROR 0x04 ++#define H2C_REJECTED 0x05 ++#define H2C_CMD_OVERFLOW 0x06 ++#define H2C_RESERVED 0x07 ++ ++extern u8 rtw_setassocsta_cmd(_adapter *padapter, u8 *mac_addr); ++extern u8 rtw_setstandby_cmd(_adapter *padapter, uint action); ++u8 rtw_sitesurvey_cmd(_adapter *padapter, NDIS_802_11_SSID *ssid, int ssid_num, struct rtw_ieee80211_channel *ch, int ch_num); ++extern u8 rtw_createbss_cmd(_adapter *padapter); ++extern u8 rtw_createbss_cmd_ex(_adapter *padapter, unsigned char *pbss, unsigned int sz); ++extern u8 rtw_setphy_cmd(_adapter *padapter, u8 modem, u8 ch); ++extern u8 rtw_setstakey_cmd(_adapter *padapter, u8 *psta, u8 unicast_key, bool enqueue); ++extern u8 rtw_clearstakey_cmd(_adapter *padapter, u8 *psta, u8 entry, u8 enqueue); ++extern u8 rtw_joinbss_cmd(_adapter *padapter, struct wlan_network* pnetwork); ++u8 rtw_disassoc_cmd(_adapter *padapter, u32 deauth_timeout_ms, bool enqueue); ++extern u8 rtw_setopmode_cmd(_adapter *padapter, NDIS_802_11_NETWORK_INFRASTRUCTURE networktype, bool enqueue); ++extern u8 rtw_setdatarate_cmd(_adapter *padapter, u8 *rateset); ++extern u8 rtw_setbasicrate_cmd(_adapter *padapter, u8 *rateset); ++extern u8 rtw_setbbreg_cmd(_adapter * padapter, u8 offset, u8 val); ++extern u8 rtw_setrfreg_cmd(_adapter * padapter, u8 offset, u32 val); ++extern u8 rtw_getbbreg_cmd(_adapter * padapter, u8 offset, u8 * pval); ++extern u8 rtw_getrfreg_cmd(_adapter * padapter, u8 offset, u8 * pval); ++extern u8 rtw_setrfintfs_cmd(_adapter *padapter, u8 mode); ++extern u8 rtw_setrttbl_cmd(_adapter *padapter, struct setratable_parm *prate_table); ++extern u8 rtw_getrttbl_cmd(_adapter *padapter, struct getratable_rsp *pval); ++ ++extern u8 rtw_gettssi_cmd(_adapter *padapter, u8 offset,u8 *pval); ++extern u8 rtw_setfwdig_cmd(_adapter*padapter, u8 type); ++extern u8 rtw_setfwra_cmd(_adapter*padapter, u8 type); ++ ++extern u8 rtw_addbareq_cmd(_adapter*padapter, u8 tid, u8 *addr); ++// add for CONFIG_IEEE80211W, none 11w also can use ++extern u8 rtw_reset_securitypriv_cmd(_adapter*padapter); ++extern u8 rtw_free_assoc_resources_cmd(_adapter *padapter); ++extern u8 rtw_dynamic_chk_wk_cmd(_adapter *adapter); ++ ++u8 rtw_lps_ctrl_wk_cmd(_adapter*padapter, u8 lps_ctrl_type, u8 enqueue); ++#if (RATE_ADAPTIVE_SUPPORT==1) ++u8 rtw_rpt_timer_cfg_cmd(_adapter*padapter, u16 minRptTime); ++#endif ++ ++#ifdef CONFIG_ANTENNA_DIVERSITY ++extern u8 rtw_antenna_select_cmd(_adapter*padapter, u8 antenna,u8 enqueue); ++#endif ++ ++extern u8 rtw_ps_cmd(_adapter*padapter); ++ ++#ifdef CONFIG_AP_MODE ++u8 rtw_chk_hi_queue_cmd(_adapter*padapter); ++#endif ++ ++u8 rtw_set_ch_cmd(_adapter*padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue); ++extern u8 rtw_set_chplan_cmd(_adapter*padapter, u8 chplan, u8 enqueue); ++extern u8 rtw_led_blink_cmd(_adapter*padapter, PLED_871x pLed); ++extern u8 rtw_set_csa_cmd(_adapter*padapter, u8 new_ch_no); ++extern u8 rtw_tdls_cmd(_adapter*padapter, u8 *addr, u8 option); ++ ++extern u8 rtw_c2h_wk_cmd(PADAPTER padapter, u8 *c2h_evt); ++ ++#ifdef CONFIG_DETECT_C2H_BY_POLLING ++extern u8 rtw_event_polling_cmd(_adapter*padapter); ++#endif ++ ++u8 rtw_drvextra_cmd_hdl(_adapter *padapter, unsigned char *pbuf); ++ ++extern void rtw_survey_cmd_callback(_adapter *padapter, struct cmd_obj *pcmd); ++extern void rtw_disassoc_cmd_callback(_adapter *padapter, struct cmd_obj *pcmd); ++extern void rtw_joinbss_cmd_callback(_adapter *padapter, struct cmd_obj *pcmd); ++extern void rtw_createbss_cmd_callback(_adapter *padapter, struct cmd_obj *pcmd); ++extern void rtw_getbbrfreg_cmdrsp_callback(_adapter *padapter, struct cmd_obj *pcmd); ++extern void rtw_readtssi_cmdrsp_callback(_adapter* padapter, struct cmd_obj *pcmd); ++ ++extern void rtw_setstaKey_cmdrsp_callback(_adapter *padapter, struct cmd_obj *pcmd); ++extern void rtw_setassocsta_cmdrsp_callback(_adapter *padapter, struct cmd_obj *pcmd); ++extern void rtw_getrttbl_cmdrsp_callback(_adapter *padapter, struct cmd_obj *pcmd); ++ ++ ++struct _cmd_callback { ++ u32 cmd_code; ++ void (*callback)(_adapter *padapter, struct cmd_obj *cmd); ++}; ++ ++enum rtw_h2c_cmd ++{ ++ GEN_CMD_CODE(_Read_MACREG) , /*0*/ ++ GEN_CMD_CODE(_Write_MACREG) , ++ GEN_CMD_CODE(_Read_BBREG) , ++ GEN_CMD_CODE(_Write_BBREG) , ++ GEN_CMD_CODE(_Read_RFREG) , ++ GEN_CMD_CODE(_Write_RFREG) , /*5*/ ++ GEN_CMD_CODE(_Read_EEPROM) , ++ GEN_CMD_CODE(_Write_EEPROM) , ++ GEN_CMD_CODE(_Read_EFUSE) , ++ GEN_CMD_CODE(_Write_EFUSE) , ++ ++ GEN_CMD_CODE(_Read_CAM) , /*10*/ ++ GEN_CMD_CODE(_Write_CAM) , ++ GEN_CMD_CODE(_setBCNITV), ++ GEN_CMD_CODE(_setMBIDCFG), ++ GEN_CMD_CODE(_JoinBss), /*14*/ ++ GEN_CMD_CODE(_DisConnect) , /*15*/ ++ GEN_CMD_CODE(_CreateBss) , ++ GEN_CMD_CODE(_SetOpMode) , ++ GEN_CMD_CODE(_SiteSurvey), /*18*/ ++ GEN_CMD_CODE(_SetAuth) , ++ ++ GEN_CMD_CODE(_SetKey) , /*20*/ ++ GEN_CMD_CODE(_SetStaKey) , ++ GEN_CMD_CODE(_SetAssocSta) , ++ GEN_CMD_CODE(_DelAssocSta) , ++ GEN_CMD_CODE(_SetStaPwrState) , ++ GEN_CMD_CODE(_SetBasicRate) , /*25*/ ++ GEN_CMD_CODE(_GetBasicRate) , ++ GEN_CMD_CODE(_SetDataRate) , ++ GEN_CMD_CODE(_GetDataRate) , ++ GEN_CMD_CODE(_SetPhyInfo) , ++ ++ GEN_CMD_CODE(_GetPhyInfo) , /*30*/ ++ GEN_CMD_CODE(_SetPhy) , ++ GEN_CMD_CODE(_GetPhy) , ++ GEN_CMD_CODE(_readRssi) , ++ GEN_CMD_CODE(_readGain) , ++ GEN_CMD_CODE(_SetAtim) , /*35*/ ++ GEN_CMD_CODE(_SetPwrMode) , ++ GEN_CMD_CODE(_JoinbssRpt), ++ GEN_CMD_CODE(_SetRaTable) , ++ GEN_CMD_CODE(_GetRaTable) , ++ ++ GEN_CMD_CODE(_GetCCXReport), /*40*/ ++ GEN_CMD_CODE(_GetDTMReport), ++ GEN_CMD_CODE(_GetTXRateStatistics), ++ GEN_CMD_CODE(_SetUsbSuspend), ++ GEN_CMD_CODE(_SetH2cLbk), ++ GEN_CMD_CODE(_AddBAReq) , /*45*/ ++ GEN_CMD_CODE(_SetChannel), /*46*/ ++ GEN_CMD_CODE(_SetTxPower), ++ GEN_CMD_CODE(_SwitchAntenna), ++ GEN_CMD_CODE(_SetCrystalCap), ++ GEN_CMD_CODE(_SetSingleCarrierTx), /*50*/ ++ ++ GEN_CMD_CODE(_SetSingleToneTx),/*51*/ ++ GEN_CMD_CODE(_SetCarrierSuppressionTx), ++ GEN_CMD_CODE(_SetContinuousTx), ++ GEN_CMD_CODE(_SwitchBandwidth), /*54*/ ++ GEN_CMD_CODE(_TX_Beacon), /*55*/ ++ ++ GEN_CMD_CODE(_Set_MLME_EVT), /*56*/ ++ GEN_CMD_CODE(_Set_Drv_Extra), /*57*/ ++ GEN_CMD_CODE(_Set_H2C_MSG), /*58*/ ++ ++ GEN_CMD_CODE(_SetChannelPlan), /*59*/ ++ GEN_CMD_CODE(_LedBlink), /*60*/ ++ ++ GEN_CMD_CODE(_SetChannelSwitch), /*61*/ ++ GEN_CMD_CODE(_TDLS), /*62*/ ++ ++ MAX_H2CCMD ++}; ++ ++#define _GetBBReg_CMD_ _Read_BBREG_CMD_ ++#define _SetBBReg_CMD_ _Write_BBREG_CMD_ ++#define _GetRFReg_CMD_ _Read_RFREG_CMD_ ++#define _SetRFReg_CMD_ _Write_RFREG_CMD_ ++ ++#ifdef _RTW_CMD_C_ ++struct _cmd_callback rtw_cmd_callback[] = ++{ ++ {GEN_CMD_CODE(_Read_MACREG), NULL}, /*0*/ ++ {GEN_CMD_CODE(_Write_MACREG), NULL}, ++ {GEN_CMD_CODE(_Read_BBREG), &rtw_getbbrfreg_cmdrsp_callback}, ++ {GEN_CMD_CODE(_Write_BBREG), NULL}, ++ {GEN_CMD_CODE(_Read_RFREG), &rtw_getbbrfreg_cmdrsp_callback}, ++ {GEN_CMD_CODE(_Write_RFREG), NULL}, /*5*/ ++ {GEN_CMD_CODE(_Read_EEPROM), NULL}, ++ {GEN_CMD_CODE(_Write_EEPROM), NULL}, ++ {GEN_CMD_CODE(_Read_EFUSE), NULL}, ++ {GEN_CMD_CODE(_Write_EFUSE), NULL}, ++ ++ {GEN_CMD_CODE(_Read_CAM), NULL}, /*10*/ ++ {GEN_CMD_CODE(_Write_CAM), NULL}, ++ {GEN_CMD_CODE(_setBCNITV), NULL}, ++ {GEN_CMD_CODE(_setMBIDCFG), NULL}, ++ {GEN_CMD_CODE(_JoinBss), &rtw_joinbss_cmd_callback}, /*14*/ ++ {GEN_CMD_CODE(_DisConnect), &rtw_disassoc_cmd_callback}, /*15*/ ++ {GEN_CMD_CODE(_CreateBss), &rtw_createbss_cmd_callback}, ++ {GEN_CMD_CODE(_SetOpMode), NULL}, ++ {GEN_CMD_CODE(_SiteSurvey), &rtw_survey_cmd_callback}, /*18*/ ++ {GEN_CMD_CODE(_SetAuth), NULL}, ++ ++ {GEN_CMD_CODE(_SetKey), NULL}, /*20*/ ++ {GEN_CMD_CODE(_SetStaKey), &rtw_setstaKey_cmdrsp_callback}, ++ {GEN_CMD_CODE(_SetAssocSta), &rtw_setassocsta_cmdrsp_callback}, ++ {GEN_CMD_CODE(_DelAssocSta), NULL}, ++ {GEN_CMD_CODE(_SetStaPwrState), NULL}, ++ {GEN_CMD_CODE(_SetBasicRate), NULL}, /*25*/ ++ {GEN_CMD_CODE(_GetBasicRate), NULL}, ++ {GEN_CMD_CODE(_SetDataRate), NULL}, ++ {GEN_CMD_CODE(_GetDataRate), NULL}, ++ {GEN_CMD_CODE(_SetPhyInfo), NULL}, ++ ++ {GEN_CMD_CODE(_GetPhyInfo), NULL}, /*30*/ ++ {GEN_CMD_CODE(_SetPhy), NULL}, ++ {GEN_CMD_CODE(_GetPhy), NULL}, ++ {GEN_CMD_CODE(_readRssi), NULL}, ++ {GEN_CMD_CODE(_readGain), NULL}, ++ {GEN_CMD_CODE(_SetAtim), NULL}, /*35*/ ++ {GEN_CMD_CODE(_SetPwrMode), NULL}, ++ {GEN_CMD_CODE(_JoinbssRpt), NULL}, ++ {GEN_CMD_CODE(_SetRaTable), NULL}, ++ {GEN_CMD_CODE(_GetRaTable) , NULL}, ++ ++ {GEN_CMD_CODE(_GetCCXReport), NULL}, /*40*/ ++ {GEN_CMD_CODE(_GetDTMReport), NULL}, ++ {GEN_CMD_CODE(_GetTXRateStatistics), NULL}, ++ {GEN_CMD_CODE(_SetUsbSuspend), NULL}, ++ {GEN_CMD_CODE(_SetH2cLbk), NULL}, ++ {GEN_CMD_CODE(_AddBAReq), NULL}, /*45*/ ++ {GEN_CMD_CODE(_SetChannel), NULL}, /*46*/ ++ {GEN_CMD_CODE(_SetTxPower), NULL}, ++ {GEN_CMD_CODE(_SwitchAntenna), NULL}, ++ {GEN_CMD_CODE(_SetCrystalCap), NULL}, ++ {GEN_CMD_CODE(_SetSingleCarrierTx), NULL}, /*50*/ ++ ++ {GEN_CMD_CODE(_SetSingleToneTx), NULL}, /*51*/ ++ {GEN_CMD_CODE(_SetCarrierSuppressionTx), NULL}, ++ {GEN_CMD_CODE(_SetContinuousTx), NULL}, ++ {GEN_CMD_CODE(_SwitchBandwidth), NULL}, /*54*/ ++ {GEN_CMD_CODE(_TX_Beacon), NULL},/*55*/ ++ ++ {GEN_CMD_CODE(_Set_MLME_EVT), NULL},/*56*/ ++ {GEN_CMD_CODE(_Set_Drv_Extra), NULL},/*57*/ ++ {GEN_CMD_CODE(_Set_H2C_MSG), NULL},/*58*/ ++ {GEN_CMD_CODE(_SetChannelPlan), NULL},/*59*/ ++ {GEN_CMD_CODE(_LedBlink), NULL},/*60*/ ++ ++ {GEN_CMD_CODE(_SetChannelSwitch), NULL},/*61*/ ++ {GEN_CMD_CODE(_TDLS), NULL},/*62*/ ++}; ++#endif ++ ++#endif // _CMD_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_debug.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_debug.h +new file mode 100644 +index 00000000..f9f69416 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_debug.h +@@ -0,0 +1,482 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTW_DEBUG_H__ ++#define __RTW_DEBUG_H__ ++ ++#include ++#include ++#include ++ ++ ++#define _drv_always_ 1 ++#define _drv_emerg_ 2 ++#define _drv_alert_ 3 ++#define _drv_crit_ 4 ++#define _drv_err_ 5 ++#define _drv_warning_ 6 ++#define _drv_notice_ 7 ++#define _drv_info_ 8 ++#define _drv_dump_ 9 ++#define _drv_debug_ 10 ++ ++ ++#define _module_rtl871x_xmit_c_ BIT(0) ++#define _module_xmit_osdep_c_ BIT(1) ++#define _module_rtl871x_recv_c_ BIT(2) ++#define _module_recv_osdep_c_ BIT(3) ++#define _module_rtl871x_mlme_c_ BIT(4) ++#define _module_mlme_osdep_c_ BIT(5) ++#define _module_rtl871x_sta_mgt_c_ BIT(6) ++#define _module_rtl871x_cmd_c_ BIT(7) ++#define _module_cmd_osdep_c_ BIT(8) ++#define _module_rtl871x_io_c_ BIT(9) ++#define _module_io_osdep_c_ BIT(10) ++#define _module_os_intfs_c_ BIT(11) ++#define _module_rtl871x_security_c_ BIT(12) ++#define _module_rtl871x_eeprom_c_ BIT(13) ++#define _module_hal_init_c_ BIT(14) ++#define _module_hci_hal_init_c_ BIT(15) ++#define _module_rtl871x_ioctl_c_ BIT(16) ++#define _module_rtl871x_ioctl_set_c_ BIT(17) ++#define _module_rtl871x_ioctl_query_c_ BIT(18) ++#define _module_rtl871x_pwrctrl_c_ BIT(19) ++#define _module_hci_intfs_c_ BIT(20) ++#define _module_hci_ops_c_ BIT(21) ++#define _module_osdep_service_c_ BIT(22) ++#define _module_mp_ BIT(23) ++#define _module_hci_ops_os_c_ BIT(24) ++#define _module_rtl871x_ioctl_os_c BIT(25) ++#define _module_rtl8712_cmd_c_ BIT(26) ++//#define _module_efuse_ BIT(27) ++#define _module_rtl8192c_xmit_c_ BIT(28) ++#define _module_hal_xmit_c_ BIT(28) ++#define _module_efuse_ BIT(29) ++#define _module_rtl8712_recv_c_ BIT(30) ++#define _module_rtl8712_led_c_ BIT(31) ++ ++#undef _MODULE_DEFINE_ ++ ++#if defined _RTW_XMIT_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_xmit_c_ ++#elif defined _XMIT_OSDEP_C_ ++ #define _MODULE_DEFINE_ _module_xmit_osdep_c_ ++#elif defined _RTW_RECV_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_recv_c_ ++#elif defined _RECV_OSDEP_C_ ++ #define _MODULE_DEFINE_ _module_recv_osdep_c_ ++#elif defined _RTW_MLME_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_mlme_c_ ++#elif defined _MLME_OSDEP_C_ ++ #define _MODULE_DEFINE_ _module_mlme_osdep_c_ ++#elif defined _RTW_MLME_EXT_C_ ++ #define _MODULE_DEFINE_ 1 ++#elif defined _RTW_STA_MGT_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_sta_mgt_c_ ++#elif defined _RTW_CMD_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_cmd_c_ ++#elif defined _CMD_OSDEP_C_ ++ #define _MODULE_DEFINE_ _module_cmd_osdep_c_ ++#elif defined _RTW_IO_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_io_c_ ++#elif defined _IO_OSDEP_C_ ++ #define _MODULE_DEFINE_ _module_io_osdep_c_ ++#elif defined _OS_INTFS_C_ ++ #define _MODULE_DEFINE_ _module_os_intfs_c_ ++#elif defined _RTW_SECURITY_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_security_c_ ++#elif defined _RTW_EEPROM_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_eeprom_c_ ++#elif defined _HAL_INTF_C_ ++ #define _MODULE_DEFINE_ _module_hal_init_c_ ++#elif (defined _HCI_HAL_INIT_C_) || (defined _SDIO_HALINIT_C_) ++ #define _MODULE_DEFINE_ _module_hci_hal_init_c_ ++#elif defined _RTL871X_IOCTL_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_ioctl_c_ ++#elif defined _RTL871X_IOCTL_SET_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_ioctl_set_c_ ++#elif defined _RTL871X_IOCTL_QUERY_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_ioctl_query_c_ ++#elif defined _RTL871X_PWRCTRL_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_pwrctrl_c_ ++#elif defined _RTW_PWRCTRL_C_ ++ #define _MODULE_DEFINE_ 1 ++#elif defined _HCI_INTF_C_ ++ #define _MODULE_DEFINE_ _module_hci_intfs_c_ ++#elif defined _HCI_OPS_C_ ++ #define _MODULE_DEFINE_ _module_hci_ops_c_ ++#elif defined _SDIO_OPS_C_ ++ #define _MODULE_DEFINE_ 1 ++#elif defined _OSDEP_HCI_INTF_C_ ++ #define _MODULE_DEFINE_ _module_hci_intfs_c_ ++#elif defined _OSDEP_SERVICE_C_ ++ #define _MODULE_DEFINE_ _module_osdep_service_c_ ++#elif defined _HCI_OPS_OS_C_ ++ #define _MODULE_DEFINE_ _module_hci_ops_os_c_ ++#elif defined _RTL871X_IOCTL_LINUX_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_ioctl_os_c ++#elif defined _RTL8712_CMD_C_ ++ #define _MODULE_DEFINE_ _module_rtl8712_cmd_c_ ++#elif defined _RTL8192C_XMIT_C_ ++ #define _MODULE_DEFINE_ 1 ++#elif defined _RTL8723AS_XMIT_C_ ++ #define _MODULE_DEFINE_ 1 ++#elif defined _RTL8712_RECV_C_ ++ #define _MODULE_DEFINE_ _module_rtl8712_recv_c_ ++#elif defined _RTL8192CU_RECV_C_ ++ #define _MODULE_DEFINE_ _module_rtl8712_recv_c_ ++#elif defined _RTL871X_MLME_EXT_C_ ++ #define _MODULE_DEFINE_ _module_mlme_osdep_c_ ++#elif defined _RTW_MP_C_ ++ #define _MODULE_DEFINE_ _module_mp_ ++#elif defined _RTW_MP_IOCTL_C_ ++ #define _MODULE_DEFINE_ _module_mp_ ++#elif defined _RTW_EFUSE_C_ ++ #define _MODULE_DEFINE_ _module_efuse_ ++#endif ++ ++#ifdef PLATFORM_OS_CE ++extern void rtl871x_cedbg(const char *fmt, ...); ++#endif ++ ++#define RT_TRACE(_Comp, _Level, Fmt) do{}while(0) ++#define _func_enter_ do{}while(0) ++#define _func_exit_ do{}while(0) ++#define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData, _HexDataLen) do{}while(0) ++ ++#ifdef PLATFORM_WINDOWS ++ #define DBG_871X do {} while(0) ++ #define MSG_8192C do {} while(0) ++ #define DBG_8192C do {} while(0) ++ #define DBG_871X_LEVEL do {} while(0) ++#else ++ #define DBG_871X(x, ...) do {} while(0) ++ #define MSG_8192C(x, ...) do {} while(0) ++ #define DBG_8192C(x,...) do {} while(0) ++ #define DBG_871X_LEVEL(x,...) do {} while(0) ++#endif ++ ++#undef _dbgdump ++#ifdef PLATFORM_WINDOWS ++ ++ #ifdef PLATFORM_OS_XP ++ #define _dbgdump DbgPrint ++ #elif defined PLATFORM_OS_CE ++ #define _dbgdump rtl871x_cedbg ++ #endif ++ ++#elif defined PLATFORM_LINUX ++ #define _dbgdump printk ++#elif defined PLATFORM_FREEBSD ++ #define _dbgdump printf ++#endif ++ ++#define DRIVER_PREFIX "RTL871X: " ++#define DEBUG_LEVEL (_drv_err_) ++#if defined (_dbgdump) ++ #undef DBG_871X_LEVEL ++ #define DBG_871X_LEVEL(level, fmt, arg...) \ ++ do {\ ++ if (level <= DEBUG_LEVEL) {\ ++ if (level <= _drv_err_ && level > _drv_always_) \ ++ _dbgdump(DRIVER_PREFIX"ERROR " fmt, ##arg);\ ++ else \ ++ _dbgdump(DRIVER_PREFIX fmt, ##arg);\ ++ }\ ++ }while(0) ++#endif ++ ++#ifdef CONFIG_DEBUG ++#if defined (_dbgdump) ++ #undef DBG_871X ++ #define DBG_871X(...) do {\ ++ _dbgdump(DRIVER_PREFIX __VA_ARGS__);\ ++ }while(0) ++ ++ #undef MSG_8192C ++ #define MSG_8192C(...) do {\ ++ _dbgdump(DRIVER_PREFIX __VA_ARGS__);\ ++ }while(0) ++ ++ #undef DBG_8192C ++ #define DBG_8192C(...) do {\ ++ _dbgdump(DRIVER_PREFIX __VA_ARGS__);\ ++ }while(0) ++#endif ++#endif /* CONFIG_DEBUG */ ++ ++#ifdef CONFIG_DEBUG_RTL871X ++#ifndef _RTL871X_DEBUG_C_ ++ extern u32 GlobalDebugLevel; ++ extern u64 GlobalDebugComponents; ++#endif ++ ++#if defined (_dbgdump) && defined (_MODULE_DEFINE_) ++ ++ #undef RT_TRACE ++ #define RT_TRACE(_Comp, _Level, Fmt)\ ++ do {\ ++ if((_Comp & GlobalDebugComponents) && (_Level <= GlobalDebugLevel)) {\ ++ _dbgdump("%s [0x%08x,%d]", DRIVER_PREFIX, (unsigned int)_Comp, _Level);\ ++ _dbgdump Fmt;\ ++ }\ ++ }while(0) ++ ++#endif ++ ++ ++#if defined (_dbgdump) ++ ++ #undef _func_enter_ ++ #define _func_enter_ \ ++ do { \ ++ if (GlobalDebugLevel >= _drv_debug_) \ ++ { \ ++ _dbgdump("\n %s : %s enters at %d\n", DRIVER_PREFIX, __FUNCTION__, __LINE__);\ ++ } \ ++ } while(0) ++ ++ #undef _func_exit_ ++ #define _func_exit_ \ ++ do { \ ++ if (GlobalDebugLevel >= _drv_debug_) \ ++ { \ ++ _dbgdump("\n %s : %s exits at %d\n", DRIVER_PREFIX, __FUNCTION__, __LINE__); \ ++ } \ ++ } while(0) ++ ++ #undef RT_PRINT_DATA ++ #define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData, _HexDataLen) \ ++ if(((_Comp) & GlobalDebugComponents) && (_Level <= GlobalDebugLevel)) \ ++ { \ ++ int __i; \ ++ u8 *ptr = (u8 *)_HexData; \ ++ _dbgdump("%s", DRIVER_PREFIX); \ ++ _dbgdump(_TitleString); \ ++ for( __i=0; __i<(int)_HexDataLen; __i++ ) \ ++ { \ ++ _dbgdump("%02X%s", ptr[__i], (((__i + 1) % 4) == 0)?" ":" "); \ ++ if (((__i + 1) % 16) == 0) _dbgdump("\n"); \ ++ } \ ++ _dbgdump("\n"); \ ++ } ++#endif ++#endif /* CONFIG_DEBUG_RTL871X */ ++ ++ ++#ifdef CONFIG_PROC_DEBUG ++ ++ int proc_get_drv_version(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++#ifdef DBG_MEM_ALLOC ++ int proc_get_mstat(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++#endif /* DBG_MEM_ALLOC */ ++ ++ int proc_get_write_reg(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_set_write_reg(struct file *file, const char *buffer, ++ unsigned long count, void *data); ++ ++ int proc_get_read_reg(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_set_read_reg(struct file *file, const char *buffer, ++ unsigned long count, void *data); ++ ++ ++ int proc_get_fwstate(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_sec_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_mlmext_state(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_qos_option(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_ht_option(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_rf_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_ap_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_adapter_state(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_trx_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_mac_reg_dump1(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_mac_reg_dump2(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_mac_reg_dump3(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_bb_reg_dump1(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_bb_reg_dump2(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_bb_reg_dump3(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_rf_reg_dump1(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_rf_reg_dump2(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_rf_reg_dump3(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_rf_reg_dump4(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++#ifdef CONFIG_AP_MODE ++ ++ int proc_get_all_sta_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++#endif ++ ++#ifdef DBG_MEMORY_LEAK ++ int proc_get_malloc_cnt(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++#endif ++ ++#ifdef CONFIG_FIND_BEST_CHANNEL ++ int proc_get_best_channel(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ int proc_set_best_channel(struct file *file, const char *buffer, ++ unsigned long count, void *data); ++#endif ++ ++ int proc_get_rx_signal(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_set_rx_signal(struct file *file, const char *buffer, ++ unsigned long count, void *data); ++#ifdef CONFIG_80211N_HT ++ ++ int proc_get_ht_enable(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_set_ht_enable(struct file *file, const char *buffer, ++ unsigned long count, void *data); ++ ++ int proc_get_cbw40_enable(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_set_cbw40_enable(struct file *file, const char *buffer, ++ unsigned long count, void *data); ++ ++ int proc_get_ampdu_enable(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_set_ampdu_enable(struct file *file, const char *buffer, ++ unsigned long count, void *data); ++ ++ int proc_get_rx_stbc(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_set_rx_stbc(struct file *file, const char *buffer, ++ unsigned long count, void *data); ++#endif //CONFIG_80211N_HT ++ ++ int proc_get_two_path_rssi(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_get_rssi_disp(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_set_rssi_disp(struct file *file, const char *buffer, ++ unsigned long count, void *data); ++ ++#ifdef CONFIG_BT_COEXIST ++ int proc_get_btcoex_dbg(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++ int proc_set_btcoex_dbg(struct file *file, const char *buffer, ++ unsigned long count, void *data); ++ ++#endif //CONFIG_BT_COEXIST ++ ++#if defined(DBG_CONFIG_ERROR_DETECT) ++int proc_get_sreset(char *page, char **start, off_t offset, int count, int *eof, void *data); ++int proc_set_sreset(struct file *file, const char *buffer, unsigned long count, void *data); ++#endif /* DBG_CONFIG_ERROR_DETECT */ ++ ++int proc_get_odm_dbg_comp(char *page, char **start, off_t offset, int count, int *eof, void *data); ++int proc_set_odm_dbg_comp(struct file *file, const char *buffer, unsigned long count, void *data); ++int proc_get_odm_dbg_level(char *page, char **start, off_t offset, int count, int *eof, void *data); ++int proc_set_odm_dbg_level(struct file *file, const char *buffer, unsigned long count, void *data); ++ ++int proc_get_odm_adaptivity(char *page, char **start, off_t offset, int count, int *eof, void *data); ++int proc_set_odm_adaptivity(struct file *file, const char *buffer, unsigned long count, void *data); ++ ++#endif //CONFIG_PROC_DEBUG ++ ++#endif //__RTW_DEBUG_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_eeprom.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_eeprom.h +new file mode 100644 +index 00000000..564f5cd2 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_eeprom.h +@@ -0,0 +1,169 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTW_EEPROM_H__ ++#define __RTW_EEPROM_H__ ++ ++#include ++#include ++#include ++ ++#define RTL8712_EEPROM_ID 0x8712 ++//#define EEPROM_MAX_SIZE 256 ++ ++#define HWSET_MAX_SIZE_512 512 ++#define EEPROM_MAX_SIZE HWSET_MAX_SIZE_512 ++ ++#define CLOCK_RATE 50 //100us ++ ++//- EEPROM opcodes ++#define EEPROM_READ_OPCODE 06 ++#define EEPROM_WRITE_OPCODE 05 ++#define EEPROM_ERASE_OPCODE 07 ++#define EEPROM_EWEN_OPCODE 19 // Erase/write enable ++#define EEPROM_EWDS_OPCODE 16 // Erase/write disable ++ ++//Country codes ++#define USA 0x555320 ++#define EUROPE 0x1 //temp, should be provided later ++#define JAPAN 0x2 //temp, should be provided later ++ ++#ifdef CONFIG_SDIO_HCI ++#define eeprom_cis0_sz 17 ++#define eeprom_cis1_sz 50 ++#endif ++ ++#define EEPROM_CID_DEFAULT 0x0 ++#define EEPROM_CID_ALPHA 0x1 ++#define EEPROM_CID_Senao 0x3 ++#define EEPROM_CID_NetCore 0x5 ++#define EEPROM_CID_CAMEO 0X8 ++#define EEPROM_CID_SITECOM 0x9 ++#define EEPROM_CID_COREGA 0xB ++#define EEPROM_CID_EDIMAX_BELKIN 0xC ++#define EEPROM_CID_SERCOMM_BELKIN 0xE ++#define EEPROM_CID_CAMEO1 0xF ++#define EEPROM_CID_WNC_COREGA 0x12 ++#define EEPROM_CID_CLEVO 0x13 ++#define EEPROM_CID_WHQL 0xFE // added by chiyoko for dtm, 20090108 ++ ++// ++// Customer ID, note that: ++// This variable is initiailzed through EEPROM or registry, ++// however, its definition may be different with that in EEPROM for ++// EEPROM size consideration. So, we have to perform proper translation between them. ++// Besides, CustomerID of registry has precedence of that of EEPROM. ++// defined below. 060703, by rcnjko. ++// ++typedef enum _RT_CUSTOMER_ID ++{ ++ RT_CID_DEFAULT = 0, ++ RT_CID_8187_ALPHA0 = 1, ++ RT_CID_8187_SERCOMM_PS = 2, ++ RT_CID_8187_HW_LED = 3, ++ RT_CID_8187_NETGEAR = 4, ++ RT_CID_WHQL = 5, ++ RT_CID_819x_CAMEO = 6, ++ RT_CID_819x_RUNTOP = 7, ++ RT_CID_819x_Senao = 8, ++ RT_CID_TOSHIBA = 9, // Merge by Jacken, 2008/01/31. ++ RT_CID_819x_Netcore = 10, ++ RT_CID_Nettronix = 11, ++ RT_CID_DLINK = 12, ++ RT_CID_PRONET = 13, ++ RT_CID_COREGA = 14, ++ RT_CID_CHINA_MOBILE = 15, ++ RT_CID_819x_ALPHA = 16, ++ RT_CID_819x_Sitecom = 17, ++ RT_CID_CCX = 18, // It's set under CCX logo test and isn't demanded for CCX functions, but for test behavior like retry limit and tx report. By Bruce, 2009-02-17. ++ RT_CID_819x_Lenovo = 19, ++ RT_CID_819x_QMI = 20, ++ RT_CID_819x_Edimax_Belkin = 21, ++ RT_CID_819x_Sercomm_Belkin = 22, ++ RT_CID_819x_CAMEO1 = 23, ++ RT_CID_819x_MSI = 24, ++ RT_CID_819x_Acer = 25, ++ RT_CID_819x_AzWave_ASUS = 26, ++ RT_CID_819x_AzWave = 27, // For AzWave in PCIe, The ID is AzWave use and not only Asus ++ RT_CID_819x_HP = 28, ++ RT_CID_819x_WNC_COREGA = 29, ++ RT_CID_819x_Arcadyan_Belkin = 30, ++ RT_CID_819x_SAMSUNG = 31, ++ RT_CID_819x_CLEVO = 32, ++ RT_CID_819x_DELL = 33, ++ RT_CID_819x_PRONETS = 34, ++ RT_CID_819x_Edimax_ASUS = 35, ++ RT_CID_819x_CAMEO_NETGEAR = 36, ++ RT_CID_PLANEX = 37, ++ RT_CID_CC_C = 38, ++ RT_CID_819x_Xavi = 39, ++ RT_CID_819x_FUNAI_TV = 40, ++ RT_CID_819x_ALPHA_WD=41, ++}RT_CUSTOMER_ID, *PRT_CUSTOMER_ID; ++ ++struct eeprom_priv ++{ ++ u8 bautoload_fail_flag; ++ u8 bloadfile_fail_flag; ++ u8 bloadmac_fail_flag; ++ //u8 bempty; ++ //u8 sys_config; ++ u8 mac_addr[6]; //PermanentAddress ++ //u8 config0; ++ u16 channel_plan; ++ //u8 country_string[3]; ++ //u8 tx_power_b[15]; ++ //u8 tx_power_g[15]; ++ //u8 tx_power_a[201]; ++ ++ u8 EepromOrEfuse; ++ ++ u8 efuse_eeprom_data[HWSET_MAX_SIZE_512]; //92C:256bytes, 88E:512bytes, we use union set (512bytes) ++ ++#ifdef CONFIG_RF_GAIN_OFFSET ++ u8 EEPROMRFGainOffset; ++ u8 EEPROMRFGainVal; ++#endif //CONFIG_RF_GAIN_OFFSET ++ ++#ifdef CONFIG_SDIO_HCI ++ u8 sdio_setting; ++ u32 ocr; ++ u8 cis0[eeprom_cis0_sz]; ++ u8 cis1[eeprom_cis1_sz]; ++#endif ++}; ++ ++ ++extern void eeprom_write16(_adapter *padapter, u16 reg, u16 data); ++extern u16 eeprom_read16(_adapter *padapter, u16 reg); ++extern void read_eeprom_content(_adapter *padapter); ++extern void eeprom_read_sz(_adapter * padapter, u16 reg,u8* data, u32 sz); ++ ++extern void read_eeprom_content_by_attrib(_adapter * padapter ); ++ ++#ifdef PLATFORM_LINUX ++#ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE ++extern int isAdaptorInfoFileValid(void); ++extern int storeAdaptorInfoFile(char *path, struct eeprom_priv * eeprom_priv); ++extern int retriveAdaptorInfoFile(char *path, struct eeprom_priv * eeprom_priv); ++#endif //CONFIG_ADAPTOR_INFO_CACHING_FILE ++#endif //PLATFORM_LINUX ++ ++#endif //__RTL871X_EEPROM_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_efuse.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_efuse.h +new file mode 100644 +index 00000000..41a6ef96 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_efuse.h +@@ -0,0 +1,167 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTW_EFUSE_H__ ++#define __RTW_EFUSE_H__ ++ ++#include ++#include ++ ++#define EFUSE_ERROE_HANDLE 1 ++ ++#define PG_STATE_HEADER 0x01 ++#define PG_STATE_WORD_0 0x02 ++#define PG_STATE_WORD_1 0x04 ++#define PG_STATE_WORD_2 0x08 ++#define PG_STATE_WORD_3 0x10 ++#define PG_STATE_DATA 0x20 ++ ++#define PG_SWBYTE_H 0x01 ++#define PG_SWBYTE_L 0x02 ++ ++#define PGPKT_DATA_SIZE 8 ++ ++#define EFUSE_WIFI 0 ++#define EFUSE_BT 1 ++ ++enum _EFUSE_DEF_TYPE { ++ TYPE_EFUSE_MAX_SECTION = 0, ++ TYPE_EFUSE_REAL_CONTENT_LEN = 1, ++ TYPE_AVAILABLE_EFUSE_BYTES_BANK = 2, ++ TYPE_AVAILABLE_EFUSE_BYTES_TOTAL = 3, ++ TYPE_EFUSE_MAP_LEN = 4, ++ TYPE_EFUSE_PROTECT_BYTES_BANK = 5, ++ TYPE_EFUSE_CONTENT_LEN_BANK = 6, ++}; ++ ++/* E-Fuse */ ++#ifdef CONFIG_RTL8192D ++#define EFUSE_MAP_SIZE 256 ++#endif ++#ifdef CONFIG_RTL8192C ++#define EFUSE_MAP_SIZE 128 ++#endif ++#ifdef CONFIG_RTL8723A ++#define EFUSE_MAP_SIZE 256 ++#endif ++#ifdef CONFIG_RTL8188E ++#define EFUSE_MAP_SIZE 512 ++#endif ++ ++#ifdef CONFIG_RTL8188E ++#define EFUSE_MAX_SIZE 256 ++#else ++#define EFUSE_MAX_SIZE 512 ++#endif ++/* end of E-Fuse */ ++ ++#define EFUSE_MAX_MAP_LEN 256 ++#define EFUSE_MAX_HW_SIZE 512 ++#define EFUSE_MAX_SECTION_BASE 16 ++ ++#define EXT_HEADER(header) ((header & 0x1F ) == 0x0F) ++#define ALL_WORDS_DISABLED(wde) ((wde & 0x0F) == 0x0F) ++#define GET_HDR_OFFSET_2_0(header) ( (header & 0xE0) >> 5) ++ ++#define EFUSE_REPEAT_THRESHOLD_ 3 ++ ++//============================================= ++// The following is for BT Efuse definition ++//============================================= ++#define EFUSE_BT_MAX_MAP_LEN 1024 ++#define EFUSE_MAX_BANK 4 ++#define EFUSE_MAX_BT_BANK (EFUSE_MAX_BANK-1) ++//============================================= ++/*--------------------------Define Parameters-------------------------------*/ ++#define EFUSE_MAX_WORD_UNIT 4 ++ ++/*------------------------------Define structure----------------------------*/ ++typedef struct PG_PKT_STRUCT_A{ ++ u8 offset; ++ u8 word_en; ++ u8 data[8]; ++ u8 word_cnts; ++}PGPKT_STRUCT,*PPGPKT_STRUCT; ++ ++/*------------------------------Define structure----------------------------*/ ++typedef struct _EFUSE_HAL{ ++ u8 fakeEfuseBank; ++ u32 fakeEfuseUsedBytes; ++ u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE]; ++ u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN]; ++ u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN]; ++ ++ u16 BTEfuseUsedBytes; ++ u8 BTEfuseUsedPercentage; ++ u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++ u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN]; ++ u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN]; ++ ++ u16 fakeBTEfuseUsedBytes; ++ u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++ u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN]; ++ u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN]; ++}EFUSE_HAL, *PEFUSE_HAL; ++ ++ ++/*------------------------Export global variable----------------------------*/ ++extern u8 fakeEfuseBank; ++extern u32 fakeEfuseUsedBytes; ++extern u8 fakeEfuseContent[]; ++extern u8 fakeEfuseInitMap[]; ++extern u8 fakeEfuseModifiedMap[]; ++ ++extern u32 BTEfuseUsedBytes; ++extern u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++extern u8 BTEfuseInitMap[]; ++extern u8 BTEfuseModifiedMap[]; ++ ++extern u32 fakeBTEfuseUsedBytes; ++extern u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++extern u8 fakeBTEfuseInitMap[]; ++extern u8 fakeBTEfuseModifiedMap[]; ++/*------------------------Export global variable----------------------------*/ ++ ++u8 efuse_GetCurrentSize(PADAPTER padapter, u16 *size); ++u16 efuse_GetMaxSize(PADAPTER padapter); ++u8 rtw_efuse_access(PADAPTER padapter, u8 bRead, u16 start_addr, u16 cnts, u8 *data); ++u8 rtw_efuse_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data); ++u8 rtw_efuse_map_write(PADAPTER padapter, u16 addr, u16 cnts, u8 *data); ++u8 rtw_BT_efuse_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data); ++u8 rtw_BT_efuse_map_write(PADAPTER padapter, u16 addr, u16 cnts, u8 *data); ++ ++u16 Efuse_GetCurrentSize(PADAPTER pAdapter, u8 efuseType, BOOLEAN bPseudoTest); ++u8 Efuse_CalculateWordCnts(u8 word_en); ++void ReadEFuseByte(PADAPTER Adapter, u16 _offset, u8 *pbuf, BOOLEAN bPseudoTest) ; ++void EFUSE_GetEfuseDefinition(PADAPTER pAdapter, u8 efuseType, u8 type, void *pOut, BOOLEAN bPseudoTest); ++u8 efuse_OneByteRead(PADAPTER pAdapter, u16 addr, u8 *data, BOOLEAN bPseudoTest); ++u8 efuse_OneByteWrite(PADAPTER pAdapter, u16 addr, u8 data, BOOLEAN bPseudoTest); ++ ++void Efuse_PowerSwitch(PADAPTER pAdapter,u8 bWrite,u8 PwrState); ++int Efuse_PgPacketRead(PADAPTER pAdapter, u8 offset, u8 *data, BOOLEAN bPseudoTest); ++int Efuse_PgPacketWrite(PADAPTER pAdapter, u8 offset, u8 word_en, u8 *data, BOOLEAN bPseudoTest); ++void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata); ++u8 Efuse_WordEnableDataWrite(PADAPTER pAdapter, u16 efuse_addr, u8 word_en, u8 *data, BOOLEAN bPseudoTest); ++ ++u8 EFUSE_Read1Byte(PADAPTER pAdapter, u16 Address); ++void EFUSE_ShadowMapUpdate(PADAPTER pAdapter, u8 efuseType, BOOLEAN bPseudoTest); ++void EFUSE_ShadowRead(PADAPTER pAdapter, u8 Type, u16 Offset, u32 *Value); ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_event.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_event.h +new file mode 100644 +index 00000000..4299ddcf +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_event.h +@@ -0,0 +1,154 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTW_EVENT_H_ ++#define _RTW_EVENT_H_ ++#include ++#include ++ ++#ifndef CONFIG_RTL8711FW ++#ifdef PLATFORM_LINUX ++#include ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) ++#include ++#else ++#include ++#endif ++#include ++#endif ++#else ++#include ++#endif//CONFIG_RTL8711FW ++ ++ ++ ++#ifdef CONFIG_H2CLBK ++#include ++#endif ++ ++/* ++Used to report a bss has been scanned ++ ++*/ ++struct survey_event { ++ WLAN_BSSID_EX bss; ++}; ++ ++/* ++Used to report that the requested site survey has been done. ++ ++bss_cnt indicates the number of bss that has been reported. ++ ++ ++*/ ++struct surveydone_event { ++ unsigned int bss_cnt; ++ ++}; ++ ++/* ++Used to report the link result of joinning the given bss ++ ++ ++join_res: ++-1: authentication fail ++-2: association fail ++> 0: TID ++ ++*/ ++struct joinbss_event { ++ struct wlan_network network; ++}; ++ ++/* ++Used to report a given STA has joinned the created BSS. ++It is used in AP/Ad-HoC(M) mode. ++ ++ ++*/ ++struct stassoc_event { ++ unsigned char macaddr[6]; ++ unsigned char rsvd[2]; ++ int cam_id; ++ ++}; ++ ++struct stadel_event { ++ unsigned char macaddr[6]; ++ unsigned char rsvd[2]; //for reason ++ int mac_id; ++}; ++ ++struct addba_event ++{ ++ unsigned int tid; ++}; ++ ++ ++#ifdef CONFIG_H2CLBK ++struct c2hlbk_event{ ++ unsigned char mac[6]; ++ unsigned short s0; ++ unsigned short s1; ++ unsigned int w0; ++ unsigned char b0; ++ unsigned short s2; ++ unsigned char b1; ++ unsigned int w1; ++}; ++#endif//CONFIG_H2CLBK ++ ++#define GEN_EVT_CODE(event) event ## _EVT_ ++ ++ ++ ++struct fwevent { ++ u32 parmsize; ++ void (*event_callback)(_adapter *dev, u8 *pbuf); ++}; ++ ++ ++#define C2HEVENT_SZ 32 ++ ++struct event_node{ ++ unsigned char *node; ++ unsigned char evt_code; ++ unsigned short evt_sz; ++ volatile int *caller_ff_tail; ++ int caller_ff_sz; ++}; ++ ++struct c2hevent_queue { ++ volatile int head; ++ volatile int tail; ++ struct event_node nodes[C2HEVENT_SZ]; ++ unsigned char seq; ++}; ++ ++#define NETWORK_QUEUE_SZ 4 ++ ++struct network_queue { ++ volatile int head; ++ volatile int tail; ++ WLAN_BSSID_EX networks[NETWORK_QUEUE_SZ]; ++}; ++ ++ ++#endif // _WLANEVENT_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ht.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ht.h +new file mode 100644 +index 00000000..3cd904df +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ht.h +@@ -0,0 +1,50 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTW_HT_H_ ++#define _RTW_HT_H_ ++ ++#include ++#include ++#include "wifi.h" ++ ++struct ht_priv ++{ ++ u32 ht_option; ++ u32 ampdu_enable;//for enable Tx A-MPDU ++ //u8 baddbareq_issued[16]; ++ u32 tx_amsdu_enable;//for enable Tx A-MSDU ++ u32 tx_amdsu_maxlen; // 1: 8k, 0:4k ; default:8k, for tx ++ u32 rx_ampdu_maxlen; //for rx reordering ctrl win_sz, updated when join_callback. ++ ++ u8 bwmode;// ++ u8 ch_offset;//PRIME_CHNL_OFFSET ++ u8 sgi;//short GI ++ ++ //for processing Tx A-MPDU ++ u8 agg_enable_bitmap; ++ //u8 ADDBA_retry_count; ++ u8 candidate_tid_bitmap; ++ ++ struct rtw_ieee80211_ht_cap ht_cap; ++ ++}; ++ ++#endif //_RTL871X_HT_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_io.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_io.h +new file mode 100644 +index 00000000..bc09b0d8 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_io.h +@@ -0,0 +1,534 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#ifndef _RTW_IO_H_ ++#define _RTW_IO_H_ ++ ++#include ++#include ++#include ++ ++#ifdef PLATFORM_LINUX ++#include ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) ++#include ++#else ++#include ++#endif ++#include ++//#include ++#include ++#include ++ ++#ifdef CONFIG_USB_HCI ++#include ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++#include ++#else ++#include ++#endif ++ ++#endif //CONFIG_USB_HCI ++ ++#endif //PLATFORM_LINUX ++ ++ ++#define NUM_IOREQ 8 ++ ++#ifdef PLATFORM_WINDOWS ++#define MAX_PROT_SZ 64 ++#endif ++#ifdef PLATFORM_LINUX ++#define MAX_PROT_SZ (64-16) ++#endif ++ ++#define _IOREADY 0 ++#define _IO_WAIT_COMPLETE 1 ++#define _IO_WAIT_RSP 2 ++ ++// IO COMMAND TYPE ++#define _IOSZ_MASK_ (0x7F) ++#define _IO_WRITE_ BIT(7) ++#define _IO_FIXED_ BIT(8) ++#define _IO_BURST_ BIT(9) ++#define _IO_BYTE_ BIT(10) ++#define _IO_HW_ BIT(11) ++#define _IO_WORD_ BIT(12) ++#define _IO_SYNC_ BIT(13) ++#define _IO_CMDMASK_ (0x1F80) ++ ++ ++/* ++ For prompt mode accessing, caller shall free io_req ++ Otherwise, io_handler will free io_req ++*/ ++ ++ ++ ++// IO STATUS TYPE ++#define _IO_ERR_ BIT(2) ++#define _IO_SUCCESS_ BIT(1) ++#define _IO_DONE_ BIT(0) ++ ++ ++#define IO_RD32 (_IO_SYNC_ | _IO_WORD_) ++#define IO_RD16 (_IO_SYNC_ | _IO_HW_) ++#define IO_RD8 (_IO_SYNC_ | _IO_BYTE_) ++ ++#define IO_RD32_ASYNC (_IO_WORD_) ++#define IO_RD16_ASYNC (_IO_HW_) ++#define IO_RD8_ASYNC (_IO_BYTE_) ++ ++#define IO_WR32 (_IO_WRITE_ | _IO_SYNC_ | _IO_WORD_) ++#define IO_WR16 (_IO_WRITE_ | _IO_SYNC_ | _IO_HW_) ++#define IO_WR8 (_IO_WRITE_ | _IO_SYNC_ | _IO_BYTE_) ++ ++#define IO_WR32_ASYNC (_IO_WRITE_ | _IO_WORD_) ++#define IO_WR16_ASYNC (_IO_WRITE_ | _IO_HW_) ++#define IO_WR8_ASYNC (_IO_WRITE_ | _IO_BYTE_) ++ ++/* ++ ++ Only Sync. burst accessing is provided. ++ ++*/ ++ ++#define IO_WR_BURST(x) (_IO_WRITE_ | _IO_SYNC_ | _IO_BURST_ | ( (x) & _IOSZ_MASK_)) ++#define IO_RD_BURST(x) (_IO_SYNC_ | _IO_BURST_ | ( (x) & _IOSZ_MASK_)) ++ ++ ++ ++//below is for the intf_option bit defition... ++ ++#define _INTF_ASYNC_ BIT(0) //support async io ++ ++struct intf_priv; ++struct intf_hdl; ++struct io_queue; ++ ++struct _io_ops ++{ ++ u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr); ++ u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr); ++ u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr); ++ ++ int (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val); ++ int (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val); ++ int (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val); ++ int (*_writeN)(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata); ++ ++ int (*_write8_async)(struct intf_hdl *pintfhdl, u32 addr, u8 val); ++ int (*_write16_async)(struct intf_hdl *pintfhdl, u32 addr, u16 val); ++ int (*_write32_async)(struct intf_hdl *pintfhdl, u32 addr, u32 val); ++ ++ void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ ++ void (*_sync_irp_protocol_rw)(struct io_queue *pio_q); ++ ++ u32 (*_read_interrupt)(struct intf_hdl *pintfhdl, u32 addr); ++ ++ u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ ++ u32 (*_write_scsi)(struct intf_hdl *pintfhdl,u32 cnt, u8 *pmem); ++ ++ void (*_read_port_cancel)(struct intf_hdl *pintfhdl); ++ void (*_write_port_cancel)(struct intf_hdl *pintfhdl); ++ ++}; ++ ++struct io_req { ++ _list list; ++ u32 addr; ++ volatile u32 val; ++ u32 command; ++ u32 status; ++ u8 *pbuf; ++ _sema sema; ++ ++#ifdef PLATFORM_OS_CE ++#ifdef CONFIG_USB_HCI ++ // URB handler for rtw_write_mem ++ USB_TRANSFER usb_transfer_write_mem; ++#endif ++#endif ++ ++ void (*_async_io_callback)(_adapter *padater, struct io_req *pio_req, u8 *cnxt); ++ u8 *cnxt; ++ ++#ifdef PLATFORM_OS_XP ++ PMDL pmdl; ++ PIRP pirp; ++ ++#ifdef CONFIG_SDIO_HCI ++ PSDBUS_REQUEST_PACKET sdrp; ++#endif ++ ++#endif ++ ++ ++}; ++ ++struct intf_hdl { ++ ++/* ++ u32 intf_option; ++ u32 bus_status; ++ u32 do_flush; ++ u8 *adapter; ++ u8 *intf_dev; ++ struct intf_priv *pintfpriv; ++ u8 cnt; ++ void (*intf_hdl_init)(u8 *priv); ++ void (*intf_hdl_unload)(u8 *priv); ++ void (*intf_hdl_open)(u8 *priv); ++ void (*intf_hdl_close)(u8 *priv); ++ struct _io_ops io_ops; ++ //u8 intf_status;//moved to struct intf_priv ++ u16 len; ++ u16 done_len; ++*/ ++ _adapter *padapter; ++ struct dvobj_priv *pintf_dev;// pointer to &(padapter->dvobjpriv); ++ ++ struct _io_ops io_ops; ++ ++}; ++ ++struct reg_protocol_rd { ++ ++#ifdef CONFIG_LITTLE_ENDIAN ++ ++ //DW1 ++ u32 NumOfTrans:4; ++ u32 Reserved1:4; ++ u32 Reserved2:24; ++ //DW2 ++ u32 ByteCount:7; ++ u32 WriteEnable:1; //0:read, 1:write ++ u32 FixOrContinuous:1; //0:continuous, 1: Fix ++ u32 BurstMode:1; ++ u32 Byte1Access:1; ++ u32 Byte2Access:1; ++ u32 Byte4Access:1; ++ u32 Reserved3:3; ++ u32 Reserved4:16; ++ //DW3 ++ u32 BusAddress; ++ //DW4 ++ //u32 Value; ++#else ++ ++ ++//DW1 ++ u32 Reserved1 :4; ++ u32 NumOfTrans :4; ++ ++ u32 Reserved2 :24; ++ ++ //DW2 ++ u32 WriteEnable : 1; ++ u32 ByteCount :7; ++ ++ ++ u32 Reserved3 : 3; ++ u32 Byte4Access : 1; ++ ++ u32 Byte2Access : 1; ++ u32 Byte1Access : 1; ++ u32 BurstMode :1 ; ++ u32 FixOrContinuous : 1; ++ ++ u32 Reserved4 : 16; ++ ++ //DW3 ++ u32 BusAddress; ++ ++ //DW4 ++ //u32 Value; ++ ++#endif ++ ++}; ++ ++ ++struct reg_protocol_wt { ++ ++ ++#ifdef CONFIG_LITTLE_ENDIAN ++ ++ //DW1 ++ u32 NumOfTrans:4; ++ u32 Reserved1:4; ++ u32 Reserved2:24; ++ //DW2 ++ u32 ByteCount:7; ++ u32 WriteEnable:1; //0:read, 1:write ++ u32 FixOrContinuous:1; //0:continuous, 1: Fix ++ u32 BurstMode:1; ++ u32 Byte1Access:1; ++ u32 Byte2Access:1; ++ u32 Byte4Access:1; ++ u32 Reserved3:3; ++ u32 Reserved4:16; ++ //DW3 ++ u32 BusAddress; ++ //DW4 ++ u32 Value; ++ ++#else ++ //DW1 ++ u32 Reserved1 :4; ++ u32 NumOfTrans :4; ++ ++ u32 Reserved2 :24; ++ ++ //DW2 ++ u32 WriteEnable : 1; ++ u32 ByteCount :7; ++ ++ u32 Reserved3 : 3; ++ u32 Byte4Access : 1; ++ ++ u32 Byte2Access : 1; ++ u32 Byte1Access : 1; ++ u32 BurstMode :1 ; ++ u32 FixOrContinuous : 1; ++ ++ u32 Reserved4 : 16; ++ ++ //DW3 ++ u32 BusAddress; ++ ++ //DW4 ++ u32 Value; ++ ++#endif ++ ++}; ++#ifdef CONFIG_PCI_HCI ++#define MAX_CONTINUAL_IO_ERR 4 ++#endif ++ ++#ifdef CONFIG_USB_HCI ++#define MAX_CONTINUAL_IO_ERR 4 ++#endif ++ ++#ifdef CONFIG_SDIO_HCI ++#define SD_IO_TRY_CNT (8) ++#define MAX_CONTINUAL_IO_ERR SD_IO_TRY_CNT ++#endif ++ ++ ++int rtw_inc_and_chk_continual_io_error(struct dvobj_priv *dvobj); ++void rtw_reset_continual_io_error(struct dvobj_priv *dvobj); ++ ++/* ++Below is the data structure used by _io_handler ++ ++*/ ++ ++struct io_queue { ++ _lock lock; ++ _list free_ioreqs; ++ _list pending; //The io_req list that will be served in the single protocol read/write. ++ _list processing; ++ u8 *free_ioreqs_buf; // 4-byte aligned ++ u8 *pallocated_free_ioreqs_buf; ++ struct intf_hdl intf; ++}; ++ ++struct io_priv{ ++ ++ _adapter *padapter; ++ ++ struct intf_hdl intf; ++ ++}; ++ ++extern uint ioreq_flush(_adapter *adapter, struct io_queue *ioqueue); ++extern void sync_ioreq_enqueue(struct io_req *preq,struct io_queue *ioqueue); ++extern uint sync_ioreq_flush(_adapter *adapter, struct io_queue *ioqueue); ++ ++ ++extern uint free_ioreq(struct io_req *preq, struct io_queue *pio_queue); ++extern struct io_req *alloc_ioreq(struct io_queue *pio_q); ++ ++extern uint register_intf_hdl(u8 *dev, struct intf_hdl *pintfhdl); ++extern void unregister_intf_hdl(struct intf_hdl *pintfhdl); ++ ++extern void _rtw_attrib_read(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++extern void _rtw_attrib_write(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++ ++extern u8 _rtw_read8(_adapter *adapter, u32 addr); ++extern u16 _rtw_read16(_adapter *adapter, u32 addr); ++extern u32 _rtw_read32(_adapter *adapter, u32 addr); ++extern void _rtw_read_mem(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++extern void _rtw_read_port(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++extern void _rtw_read_port_cancel(_adapter *adapter); ++ ++ ++extern int _rtw_write8(_adapter *adapter, u32 addr, u8 val); ++extern int _rtw_write16(_adapter *adapter, u32 addr, u16 val); ++extern int _rtw_write32(_adapter *adapter, u32 addr, u32 val); ++extern int _rtw_writeN(_adapter *adapter, u32 addr, u32 length, u8 *pdata); ++ ++extern int _rtw_write8_async(_adapter *adapter, u32 addr, u8 val); ++extern int _rtw_write16_async(_adapter *adapter, u32 addr, u16 val); ++extern int _rtw_write32_async(_adapter *adapter, u32 addr, u32 val); ++ ++extern void _rtw_write_mem(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++extern u32 _rtw_write_port(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++u32 _rtw_write_port_and_wait(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem, int timeout_ms); ++extern void _rtw_write_port_cancel(_adapter *adapter); ++ ++#ifdef DBG_IO ++bool match_read_sniff_ranges(u16 addr, u16 len); ++bool match_write_sniff_ranges(u16 addr, u16 len); ++ ++extern u8 dbg_rtw_read8(_adapter *adapter, u32 addr, const char *caller, const int line); ++extern u16 dbg_rtw_read16(_adapter *adapter, u32 addr, const char *caller, const int line); ++extern u32 dbg_rtw_read32(_adapter *adapter, u32 addr, const char *caller, const int line); ++ ++extern int dbg_rtw_write8(_adapter *adapter, u32 addr, u8 val, const char *caller, const int line); ++extern int dbg_rtw_write16(_adapter *adapter, u32 addr, u16 val, const char *caller, const int line); ++extern int dbg_rtw_write32(_adapter *adapter, u32 addr, u32 val, const char *caller, const int line); ++extern int dbg_rtw_writeN(_adapter *adapter, u32 addr ,u32 length , u8 *data, const char *caller, const int line); ++ ++#define rtw_read8(adapter, addr) dbg_rtw_read8((adapter), (addr), __FUNCTION__, __LINE__) ++#define rtw_read16(adapter, addr) dbg_rtw_read16((adapter), (addr), __FUNCTION__, __LINE__) ++#define rtw_read32(adapter, addr) dbg_rtw_read32((adapter), (addr), __FUNCTION__, __LINE__) ++#define rtw_read_mem(adapter, addr, cnt, mem) _rtw_read_mem((adapter), (addr), (cnt), (mem)) ++#define rtw_read_port(adapter, addr, cnt, mem) _rtw_read_port((adapter), (addr), (cnt), (mem)) ++#define rtw_read_port_cancel(adapter) _rtw_read_port_cancel((adapter)) ++ ++#define rtw_write8(adapter, addr, val) dbg_rtw_write8((adapter), (addr), (val), __FUNCTION__, __LINE__) ++#define rtw_write16(adapter, addr, val) dbg_rtw_write16((adapter), (addr), (val), __FUNCTION__, __LINE__) ++#define rtw_write32(adapter, addr, val) dbg_rtw_write32((adapter), (addr), (val), __FUNCTION__, __LINE__) ++#define rtw_writeN(adapter, addr, length, data) dbg_rtw_writeN((adapter), (addr), (length), (data), __FUNCTION__, __LINE__) ++ ++#define rtw_write8_async(adapter, addr, val) _rtw_write8_async((adapter), (addr), (val)) ++#define rtw_write16_async(adapter, addr, val) _rtw_write16_async((adapter), (addr), (val)) ++#define rtw_write32_async(adapter, addr, val) _rtw_write32_async((adapter), (addr), (val)) ++ ++#define rtw_write_mem(adapter, addr, cnt, mem) _rtw_write_mem((adapter), addr, cnt, mem) ++#define rtw_write_port(adapter, addr, cnt, mem) _rtw_write_port(adapter, addr, cnt, mem) ++#define rtw_write_port_and_wait(adapter, addr, cnt, mem, timeout_ms) _rtw_write_port_and_wait((adapter), (addr), (cnt), (mem), (timeout_ms)) ++#define rtw_write_port_cancel(adapter) _rtw_write_port_cancel(adapter) ++#else //DBG_IO ++#define rtw_read8(adapter, addr) _rtw_read8((adapter), (addr)) ++#define rtw_read16(adapter, addr) _rtw_read16((adapter), (addr)) ++#define rtw_read32(adapter, addr) _rtw_read32((adapter), (addr)) ++#define rtw_read_mem(adapter, addr, cnt, mem) _rtw_read_mem((adapter), (addr), (cnt), (mem)) ++#define rtw_read_port(adapter, addr, cnt, mem) _rtw_read_port((adapter), (addr), (cnt), (mem)) ++#define rtw_read_port_cancel(adapter) _rtw_read_port_cancel((adapter)) ++ ++#define rtw_write8(adapter, addr, val) _rtw_write8((adapter), (addr), (val)) ++#define rtw_write16(adapter, addr, val) _rtw_write16((adapter), (addr), (val)) ++#define rtw_write32(adapter, addr, val) _rtw_write32((adapter), (addr), (val)) ++#define rtw_writeN(adapter, addr, length, data) _rtw_writeN((adapter), (addr), (length), (data)) ++ ++#define rtw_write8_async(adapter, addr, val) _rtw_write8_async((adapter), (addr), (val)) ++#define rtw_write16_async(adapter, addr, val) _rtw_write16_async((adapter), (addr), (val)) ++#define rtw_write32_async(adapter, addr, val) _rtw_write32_async((adapter), (addr), (val)) ++ ++#define rtw_write_mem(adapter, addr, cnt, mem) _rtw_write_mem((adapter), (addr), (cnt), (mem)) ++#define rtw_write_port(adapter, addr, cnt, mem) _rtw_write_port((adapter), (addr), (cnt), (mem)) ++#define rtw_write_port_and_wait(adapter, addr, cnt, mem, timeout_ms) _rtw_write_port_and_wait((adapter), (addr), (cnt), (mem), (timeout_ms)) ++#define rtw_write_port_cancel(adapter) _rtw_write_port_cancel((adapter)) ++#endif //DBG_IO ++ ++extern void rtw_write_scsi(_adapter *adapter, u32 cnt, u8 *pmem); ++ ++//ioreq ++extern void ioreq_read8(_adapter *adapter, u32 addr, u8 *pval); ++extern void ioreq_read16(_adapter *adapter, u32 addr, u16 *pval); ++extern void ioreq_read32(_adapter *adapter, u32 addr, u32 *pval); ++extern void ioreq_write8(_adapter *adapter, u32 addr, u8 val); ++extern void ioreq_write16(_adapter *adapter, u32 addr, u16 val); ++extern void ioreq_write32(_adapter *adapter, u32 addr, u32 val); ++ ++ ++extern uint async_read8(_adapter *adapter, u32 addr, u8 *pbuff, ++ void (*_async_io_callback)(_adapter *padater, struct io_req *pio_req, u8 *cnxt), u8 *cnxt); ++extern uint async_read16(_adapter *adapter, u32 addr, u8 *pbuff, ++ void (*_async_io_callback)(_adapter *padater, struct io_req *pio_req, u8 *cnxt), u8 *cnxt); ++extern uint async_read32(_adapter *adapter, u32 addr, u8 *pbuff, ++ void (*_async_io_callback)(_adapter *padater, struct io_req *pio_req, u8 *cnxt), u8 *cnxt); ++ ++extern void async_read_mem(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++extern void async_read_port(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++ ++extern void async_write8(_adapter *adapter, u32 addr, u8 val, ++ void (*_async_io_callback)(_adapter *padater, struct io_req *pio_req, u8 *cnxt), u8 *cnxt); ++extern void async_write16(_adapter *adapter, u32 addr, u16 val, ++ void (*_async_io_callback)(_adapter *padater, struct io_req *pio_req, u8 *cnxt), u8 *cnxt); ++extern void async_write32(_adapter *adapter, u32 addr, u32 val, ++ void (*_async_io_callback)(_adapter *padater, struct io_req *pio_req, u8 *cnxt), u8 *cnxt); ++ ++extern void async_write_mem(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++extern void async_write_port(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++ ++ ++int rtw_init_io_priv(_adapter *padapter, void (*set_intf_ops)(struct _io_ops *pops)); ++ ++ ++extern uint alloc_io_queue(_adapter *adapter); ++extern void free_io_queue(_adapter *adapter); ++extern void async_bus_io(struct io_queue *pio_q); ++extern void bus_sync_io(struct io_queue *pio_q); ++extern u32 _ioreq2rwmem(struct io_queue *pio_q); ++extern void dev_power_down(_adapter * Adapter, u8 bpwrup); ++ ++/* ++#define RTL_R8(reg) rtw_read8(padapter, reg) ++#define RTL_R16(reg) rtw_read16(padapter, reg) ++#define RTL_R32(reg) rtw_read32(padapter, reg) ++#define RTL_W8(reg, val8) rtw_write8(padapter, reg, val8) ++#define RTL_W16(reg, val16) rtw_write16(padapter, reg, val16) ++#define RTL_W32(reg, val32) rtw_write32(padapter, reg, val32) ++*/ ++ ++/* ++#define RTL_W8_ASYNC(reg, val8) rtw_write32_async(padapter, reg, val8) ++#define RTL_W16_ASYNC(reg, val16) rtw_write32_async(padapter, reg, val16) ++#define RTL_W32_ASYNC(reg, val32) rtw_write32_async(padapter, reg, val32) ++ ++#define RTL_WRITE_BB(reg, val32) phy_SetUsbBBReg(padapter, reg, val32) ++#define RTL_READ_BB(reg) phy_QueryUsbBBReg(padapter, reg) ++*/ ++ ++#define PlatformEFIOWrite1Byte(_a,_b,_c) \ ++ rtw_write8(_a,_b,_c) ++#define PlatformEFIOWrite2Byte(_a,_b,_c) \ ++ rtw_write16(_a,_b,_c) ++#define PlatformEFIOWrite4Byte(_a,_b,_c) \ ++ rtw_write32(_a,_b,_c) ++ ++#define PlatformEFIORead1Byte(_a,_b) \ ++ rtw_read8(_a,_b) ++#define PlatformEFIORead2Byte(_a,_b) \ ++ rtw_read16(_a,_b) ++#define PlatformEFIORead4Byte(_a,_b) \ ++ rtw_read32(_a,_b) ++ ++#endif //_RTL8711_IO_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ioctl.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ioctl.h +new file mode 100644 +index 00000000..ad6ac5d3 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ioctl.h +@@ -0,0 +1,269 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTW_IOCTL_H_ ++#define _RTW_IOCTL_H_ ++ ++#include ++#include ++#include ++ ++ ++#ifndef OID_802_11_CAPABILITY ++ #define OID_802_11_CAPABILITY 0x0d010122 ++#endif ++ ++#ifndef OID_802_11_PMKID ++ #define OID_802_11_PMKID 0x0d010123 ++#endif ++ ++ ++// For DDK-defined OIDs ++#define OID_NDIS_SEG1 0x00010100 ++#define OID_NDIS_SEG2 0x00010200 ++#define OID_NDIS_SEG3 0x00020100 ++#define OID_NDIS_SEG4 0x01010100 ++#define OID_NDIS_SEG5 0x01020100 ++#define OID_NDIS_SEG6 0x01020200 ++#define OID_NDIS_SEG7 0xFD010100 ++#define OID_NDIS_SEG8 0x0D010100 ++#define OID_NDIS_SEG9 0x0D010200 ++#define OID_NDIS_SEG10 0x0D020200 ++ ++#define SZ_OID_NDIS_SEG1 23 ++#define SZ_OID_NDIS_SEG2 3 ++#define SZ_OID_NDIS_SEG3 6 ++#define SZ_OID_NDIS_SEG4 6 ++#define SZ_OID_NDIS_SEG5 4 ++#define SZ_OID_NDIS_SEG6 8 ++#define SZ_OID_NDIS_SEG7 7 ++#define SZ_OID_NDIS_SEG8 36 ++#define SZ_OID_NDIS_SEG9 24 ++#define SZ_OID_NDIS_SEG10 19 ++ ++// For Realtek-defined OIDs ++#define OID_MP_SEG1 0xFF871100 ++#define OID_MP_SEG2 0xFF818000 ++ ++#define OID_MP_SEG3 0xFF818700 ++#define OID_MP_SEG4 0xFF011100 ++ ++#define DEBUG_OID(dbg, str) \ ++ if((!dbg)) \ ++ { \ ++ RT_TRACE(_module_rtl871x_ioctl_c_,_drv_info_,("%s(%d): %s", __FUNCTION__, __LINE__, str)); \ ++ } ++ ++ ++enum oid_type ++{ ++ QUERY_OID, ++ SET_OID ++}; ++ ++struct oid_funs_node { ++ unsigned int oid_start; //the starting number for OID ++ unsigned int oid_end; //the ending number for OID ++ struct oid_obj_priv *node_array; ++ unsigned int array_sz; //the size of node_array ++ int query_counter; //count the number of query hits for this segment ++ int set_counter; //count the number of set hits for this segment ++}; ++ ++struct oid_par_priv ++{ ++ void *adapter_context; ++ NDIS_OID oid; ++ void *information_buf; ++ u32 information_buf_len; ++ u32 *bytes_rw; ++ u32 *bytes_needed; ++ enum oid_type type_of_oid; ++ u32 dbg; ++}; ++ ++struct oid_obj_priv { ++ unsigned char dbg; // 0: without OID debug message 1: with OID debug message ++ NDIS_STATUS (*oidfuns)(struct oid_par_priv *poid_par_priv); ++}; ++ ++#if (defined(CONFIG_MP_INCLUDED) && defined(_RTW_MP_IOCTL_C_)) || \ ++ (defined(PLATFORM_WINDOWS) && defined(_RTW_IOCTL_RTL_C_)) ++static NDIS_STATUS oid_null_function(struct oid_par_priv* poid_par_priv) ++{ ++ _func_enter_; ++ _func_exit_; ++ return NDIS_STATUS_SUCCESS; ++} ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++ ++int TranslateNdisPsToRtPs(IN NDIS_802_11_POWER_MODE ndisPsMode); ++ ++//OID Handler for Segment 1 ++NDIS_STATUS oid_gen_supported_list_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_hardware_status_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_media_supported_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_media_in_use_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_maximum_lookahead_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_maximum_frame_size_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_link_speed_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_transmit_buffer_space_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_receive_buffer_space_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_transmit_block_size_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_receive_block_size_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_vendor_id_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_vendor_description_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_current_packet_filter_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_current_lookahead_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_driver_version_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_maximum_total_size_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_protocol_options_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_mac_options_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_media_connect_status_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_maximum_send_packets_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_vendor_driver_version_hdl(struct oid_par_priv* poid_par_priv); ++ ++ ++//OID Handler for Segment 2 ++NDIS_STATUS oid_gen_physical_medium_hdl(struct oid_par_priv* poid_par_priv); ++ ++//OID Handler for Segment 3 ++NDIS_STATUS oid_gen_xmit_ok_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_rcv_ok_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_xmit_error_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_rcv_error_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_gen_rcv_no_buffer_hdl(struct oid_par_priv* poid_par_priv); ++ ++ ++//OID Handler for Segment 4 ++NDIS_STATUS oid_802_3_permanent_address_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_3_current_address_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_3_multicast_list_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_3_maximum_list_size_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_3_mac_options_hdl(struct oid_par_priv* poid_par_priv); ++ ++ ++ ++//OID Handler for Segment 5 ++NDIS_STATUS oid_802_3_rcv_error_alignment_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_3_xmit_one_collision_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_3_xmit_more_collisions_hdl(struct oid_par_priv* poid_par_priv); ++ ++ ++//OID Handler for Segment 6 ++NDIS_STATUS oid_802_3_xmit_deferred_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_3_xmit_max_collisions_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_3_rcv_overrun_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_3_xmit_underrun_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_3_xmit_heartbeat_failure_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_3_xmit_times_crs_lost_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_3_xmit_late_collisions_hdl(struct oid_par_priv* poid_par_priv); ++ ++ ++ ++//OID Handler for Segment 7 ++NDIS_STATUS oid_pnp_capabilities_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_pnp_set_power_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_pnp_query_power_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_pnp_add_wake_up_pattern_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_pnp_remove_wake_up_pattern_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_pnp_wake_up_pattern_list_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_pnp_enable_wake_up_hdl(struct oid_par_priv* poid_par_priv); ++ ++ ++ ++//OID Handler for Segment 8 ++NDIS_STATUS oid_802_11_bssid_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_ssid_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_infrastructure_mode_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_add_wep_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_remove_wep_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_disassociate_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_authentication_mode_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_privacy_filter_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_bssid_list_scan_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_encryption_status_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_reload_defaults_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_add_key_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_remove_key_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_association_information_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_test_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_media_stream_mode_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_capability_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_pmkid_hdl(struct oid_par_priv* poid_par_priv); ++ ++ ++ ++ ++ ++//OID Handler for Segment 9 ++NDIS_STATUS oid_802_11_network_types_supported_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_network_type_in_use_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_tx_power_level_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_rssi_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_rssi_trigger_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_fragmentation_threshold_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_rts_threshold_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_number_of_antennas_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_rx_antenna_selected_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_tx_antenna_selected_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_supported_rates_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_desired_rates_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_configuration_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_power_mode_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_802_11_bssid_list_hdl(struct oid_par_priv* poid_par_priv); ++ ++ ++//OID Handler for Segment 10 ++NDIS_STATUS oid_802_11_statistics_hdl(struct oid_par_priv* poid_par_priv); ++ ++ ++//OID Handler for Segment ED ++NDIS_STATUS oid_rt_mh_vender_id_hdl(struct oid_par_priv* poid_par_priv); ++ ++void Set_802_3_MULTICAST_LIST(ADAPTER *pAdapter, UCHAR *MCListbuf, ULONG MCListlen, BOOLEAN bAcceptAllMulticast); ++ ++#endif// end of PLATFORM_WINDOWS ++ ++#if defined(PLATFORM_LINUX) && defined(CONFIG_WIRELESS_EXT) ++extern struct iw_handler_def rtw_handlers_def; ++#endif ++ ++extern NDIS_STATUS drv_query_info( ++ IN _nic_hdl MiniportAdapterContext, ++ IN NDIS_OID Oid, ++ IN void * InformationBuffer, ++ IN u32 InformationBufferLength, ++ OUT u32* BytesWritten, ++ OUT u32* BytesNeeded ++ ); ++ ++extern NDIS_STATUS drv_set_info( ++ IN _nic_hdl MiniportAdapterContext, ++ IN NDIS_OID Oid, ++ IN void * InformationBuffer, ++ IN u32 InformationBufferLength, ++ OUT u32* BytesRead, ++ OUT u32* BytesNeeded ++ ); ++ ++#endif // #ifndef __INC_CEINFO_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ioctl_query.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ioctl_query.h +new file mode 100644 +index 00000000..5b6018af +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ioctl_query.h +@@ -0,0 +1,36 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTW_IOCTL_QUERY_H_ ++#define _RTW_IOCTL_QUERY_H_ ++ ++#include ++#include ++ ++ ++#ifdef PLATFORM_WINDOWS ++ ++u8 query_802_11_capability(_adapter* padapter,u8* pucBuf,u32 * pulOutLen); ++u8 query_802_11_association_information (_adapter * padapter, PNDIS_802_11_ASSOCIATION_INFORMATION pAssocInfo); ++ ++#endif ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ioctl_rtl.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ioctl_rtl.h +new file mode 100644 +index 00000000..9a43c280 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ioctl_rtl.h +@@ -0,0 +1,84 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTW_IOCTL_RTL_H_ ++#define _RTW_IOCTL_RTL_H_ ++ ++#include ++#include ++#include ++ ++//************** oid_rtl_seg_01_01 ************** ++NDIS_STATUS oid_rt_get_signal_quality_hdl(struct oid_par_priv* poid_par_priv);//84 ++NDIS_STATUS oid_rt_get_small_packet_crc_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_middle_packet_crc_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_large_packet_crc_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_tx_retry_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_rx_retry_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_rx_total_packet_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_tx_beacon_ok_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_tx_beacon_err_hdl(struct oid_par_priv* poid_par_priv); ++ ++NDIS_STATUS oid_rt_pro_set_fw_dig_state_hdl(struct oid_par_priv* poid_par_priv); //8a ++NDIS_STATUS oid_rt_pro_set_fw_ra_state_hdl(struct oid_par_priv* poid_par_priv); //8b ++ ++NDIS_STATUS oid_rt_get_rx_icv_err_hdl(struct oid_par_priv* poid_par_priv);//93 ++NDIS_STATUS oid_rt_set_encryption_algorithm_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_preamble_mode_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_ap_ip_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_channelplan_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_set_channelplan_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_set_preamble_mode_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_set_bcn_intvl_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_dedicate_probe_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_total_tx_bytes_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_total_rx_bytes_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_current_tx_power_level_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_enc_key_mismatch_count_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_enc_key_match_count_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_channel_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_hardware_radio_off_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_key_mismatch_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_supported_wireless_mode_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_channel_list_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_scan_in_progress_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_forced_data_rate_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_wireless_mode_for_scan_list_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_bss_wireless_mode_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_scan_with_magic_packet_hdl(struct oid_par_priv* poid_par_priv); ++ ++//************** oid_rtl_seg_01_03 section start ************** ++NDIS_STATUS oid_rt_ap_get_associated_station_list_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_ap_switch_into_ap_mode_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_ap_supported_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_ap_set_passphrase_hdl(struct oid_par_priv* poid_par_priv); ++ ++// oid_rtl_seg_01_11 ++NDIS_STATUS oid_rt_pro_rf_write_registry_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_rf_read_registry_hdl(struct oid_par_priv* poid_par_priv); ++ ++//************** oid_rtl_seg_03_00 section start ************** ++NDIS_STATUS oid_rt_get_connect_state_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_set_default_key_id_hdl(struct oid_par_priv* poid_par_priv); ++ ++ ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ioctl_set.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ioctl_set.h +new file mode 100644 +index 00000000..5f755bd2 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_ioctl_set.h +@@ -0,0 +1,78 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTW_IOCTL_SET_H_ ++#define __RTW_IOCTL_SET_H_ ++ ++#include ++#include ++ ++ ++typedef u8 NDIS_802_11_PMKID_VALUE[16]; ++ ++typedef struct _BSSIDInfo { ++ NDIS_802_11_MAC_ADDRESS BSSID; ++ NDIS_802_11_PMKID_VALUE PMKID; ++} BSSIDInfo, *PBSSIDInfo; ++ ++ ++#ifdef PLATFORM_OS_XP ++typedef struct _NDIS_802_11_PMKID { ++ u32 Length; ++ u32 BSSIDInfoCount; ++ BSSIDInfo BSSIDInfo[1]; ++} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID; ++#endif ++ ++ ++#ifdef PLATFORM_WINDOWS ++u8 rtw_set_802_11_reload_defaults(_adapter * padapter, NDIS_802_11_RELOAD_DEFAULTS reloadDefaults); ++u8 rtw_set_802_11_test(_adapter * padapter, NDIS_802_11_TEST * test); ++u8 rtw_set_802_11_pmkid(_adapter *pdapter, NDIS_802_11_PMKID *pmkid); ++ ++u8 rtw_pnp_set_power_sleep(_adapter* padapter); ++u8 rtw_pnp_set_power_wakeup(_adapter* padapter); ++ ++void rtw_pnp_resume_wk(void *context); ++void rtw_pnp_sleep_wk(void * context); ++ ++#endif ++ ++u8 rtw_set_802_11_add_key(_adapter * padapter, NDIS_802_11_KEY * key); ++u8 rtw_set_802_11_authentication_mode(_adapter *pdapter, NDIS_802_11_AUTHENTICATION_MODE authmode); ++u8 rtw_set_802_11_bssid(_adapter* padapter, u8 *bssid); ++u8 rtw_set_802_11_add_wep(_adapter * padapter, NDIS_802_11_WEP * wep); ++u8 rtw_set_802_11_disassociate(_adapter * padapter); ++u8 rtw_set_802_11_bssid_list_scan(_adapter* padapter, NDIS_802_11_SSID *pssid, int ssid_max_num); ++u8 rtw_set_802_11_infrastructure_mode(_adapter * padapter, NDIS_802_11_NETWORK_INFRASTRUCTURE networktype); ++u8 rtw_set_802_11_remove_wep(_adapter * padapter, u32 keyindex); ++u8 rtw_set_802_11_ssid(_adapter * padapter, NDIS_802_11_SSID * ssid); ++u8 rtw_set_802_11_connect(_adapter* padapter, u8 *bssid, NDIS_802_11_SSID *ssid); ++u8 rtw_set_802_11_remove_key(_adapter * padapter, NDIS_802_11_REMOVE_KEY * key); ++ ++u8 rtw_validate_bssid(u8 *bssid); ++u8 rtw_validate_ssid(NDIS_802_11_SSID *ssid); ++ ++u16 rtw_get_cur_max_rate(_adapter *adapter); ++int rtw_set_scan_mode(_adapter *adapter, RT_SCAN_TYPE scan_mode); ++int rtw_set_channel_plan(_adapter *adapter, u8 channel_plan); ++int rtw_set_country(_adapter *adapter, const char *country_code); ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_iol.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_iol.h +new file mode 100644 +index 00000000..0b0672a1 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_iol.h +@@ -0,0 +1,139 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTW_IOL_H_ ++#define __RTW_IOL_H_ ++ ++#include ++#include ++#include ++struct xmit_frame *rtw_IOL_accquire_xmit_frame(ADAPTER *adapter); ++int rtw_IOL_append_cmds(struct xmit_frame *xmit_frame, u8 *IOL_cmds, u32 cmd_len); ++int rtw_IOL_append_LLT_cmd(struct xmit_frame *xmit_frame, u8 page_boundary); ++int rtw_IOL_exec_cmds_sync(ADAPTER *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt); ++bool rtw_IOL_applied(ADAPTER *adapter); ++int rtw_IOL_append_DELAY_US_cmd(struct xmit_frame *xmit_frame, u16 us); ++int rtw_IOL_append_DELAY_MS_cmd(struct xmit_frame *xmit_frame, u16 ms); ++int rtw_IOL_append_END_cmd(struct xmit_frame *xmit_frame); ++ ++ ++#ifdef CONFIG_IOL_NEW_GENERATION ++#define IOREG_CMD_END_LEN 4 ++ ++struct ioreg_cfg{ ++ u8 length; ++ u8 cmd_id; ++ u16 address; ++ u32 data; ++ u32 mask; ++}; ++enum ioreg_cmd{ ++ IOREG_CMD_LLT = 0x01, ++ IOREG_CMD_REFUSE = 0x02, ++ IOREG_CMD_EFUSE_PATH = 0x03, ++ IOREG_CMD_WB_REG = 0x04, ++ IOREG_CMD_WW_REG = 0x05, ++ IOREG_CMD_WD_REG = 0x06, ++ IOREG_CMD_W_RF = 0x07, ++ IOREG_CMD_DELAY_US = 0x10, ++ IOREG_CMD_DELAY_MS = 0x11, ++ IOREG_CMD_END = 0xFF, ++}; ++void read_efuse_from_txpktbuf(ADAPTER *adapter, int bcnhead, u8 *content, u16 *size); ++ ++int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, u8 mask); ++int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, u16 mask); ++int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, u32 mask); ++int _rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path, u16 addr, u32 value, u32 mask); ++#define rtw_IOL_append_WB_cmd(xmit_frame, addr, value,mask) _rtw_IOL_append_WB_cmd((xmit_frame), (addr), (value) ,(mask)) ++#define rtw_IOL_append_WW_cmd(xmit_frame, addr, value,mask) _rtw_IOL_append_WW_cmd((xmit_frame), (addr), (value),(mask)) ++#define rtw_IOL_append_WD_cmd(xmit_frame, addr, value,mask) _rtw_IOL_append_WD_cmd((xmit_frame), (addr), (value),(mask)) ++#define rtw_IOL_append_WRF_cmd(xmit_frame, rf_path, addr, value,mask) _rtw_IOL_append_WRF_cmd((xmit_frame),(rf_path), (addr), (value),(mask)) ++ ++u8 rtw_IOL_cmd_boundary_handle(struct xmit_frame *pxmit_frame); ++void rtw_IOL_cmd_buf_dump(ADAPTER *Adapter,int buf_len,u8 *pbuf); ++ ++#ifdef CONFIG_IOL_IOREG_CFG_DBG ++ struct cmd_cmp{ ++ u16 addr; ++ u32 value; ++ }; ++#endif ++ ++#else //CONFIG_IOL_NEW_GENERATION ++ ++typedef struct _io_offload_cmd { ++ u8 rsvd0; ++ u8 cmd; ++ u16 address; ++ u32 value; ++} IO_OFFLOAD_CMD, IOL_CMD; ++ ++#define IOL_CMD_LLT 0x00 ++//#define IOL_CMD_R_EFUSE 0x01 ++#define IOL_CMD_WB_REG 0x02 ++#define IOL_CMD_WW_REG 0x03 ++#define IOL_CMD_WD_REG 0x04 ++//#define IOL_CMD_W_RF 0x05 ++#define IOL_CMD_DELAY_US 0x80 ++#define IOL_CMD_DELAY_MS 0x81 ++//#define IOL_CMD_DELAY_S 0x82 ++#define IOL_CMD_END 0x83 ++ ++/***************************************************** ++CMD Address Value ++(B1) (B2/B3:H/L addr) (B4:B7 : MSB:LSB) ++****************************************************** ++IOL_CMD_LLT - B7: PGBNDY ++//IOL_CMD_R_EFUSE - - ++IOL_CMD_WB_REG 0x0~0xFFFF B7 ++IOL_CMD_WW_REG 0x0~0xFFFF B6~B7 ++IOL_CMD_WD_REG 0x0~0xFFFF B4~B7 ++//IOL_CMD_W_RF RF Reg B5~B7 ++IOL_CMD_DELAY_US - B6~B7 ++IOL_CMD_DELAY_MS - B6~B7 ++//IOL_CMD_DELAY_S - B6~B7 ++IOL_CMD_END - - ++******************************************************/ ++int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value); ++int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value); ++int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value); ++ ++ ++int rtw_IOL_exec_cmd_array_sync(PADAPTER adapter, u8 *IOL_cmds, u32 cmd_num, u32 max_wating_ms); ++int rtw_IOL_exec_empty_cmds_sync(ADAPTER *adapter, u32 max_wating_ms); ++ ++#ifdef DBG_IO ++int dbg_rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, const char *caller, const int line); ++int dbg_rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, const char *caller, const int line); ++int dbg_rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, const char *caller, const int line); ++#define rtw_IOL_append_WB_cmd(xmit_frame, addr, value) dbg_rtw_IOL_append_WB_cmd((xmit_frame), (addr), (value), __FUNCTION__, __LINE__) ++#define rtw_IOL_append_WW_cmd(xmit_frame, addr, value) dbg_rtw_IOL_append_WW_cmd((xmit_frame), (addr), (value), __FUNCTION__, __LINE__) ++#define rtw_IOL_append_WD_cmd(xmit_frame, addr, value) dbg_rtw_IOL_append_WD_cmd((xmit_frame), (addr), (value), __FUNCTION__, __LINE__) ++#else ++#define rtw_IOL_append_WB_cmd(xmit_frame, addr, value) _rtw_IOL_append_WB_cmd((xmit_frame), (addr), (value)) ++#define rtw_IOL_append_WW_cmd(xmit_frame, addr, value) _rtw_IOL_append_WW_cmd((xmit_frame), (addr), (value)) ++#define rtw_IOL_append_WD_cmd(xmit_frame, addr, value) _rtw_IOL_append_WD_cmd((xmit_frame), (addr), (value)) ++#endif // DBG_IO ++#endif // CONFIG_IOL_NEW_GENERATION ++ ++ ++ ++#endif //__RTW_IOL_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_led.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_led.h +new file mode 100644 +index 00000000..2bba754c +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_led.h +@@ -0,0 +1,237 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTW_LED_H_ ++#define __RTW_LED_H_ ++ ++#include ++#include ++#include ++ ++#define MSECS(t) (HZ * ((t) / 1000) + (HZ * ((t) % 1000)) / 1000) ++ ++#define LED_BLINK_NORMAL_INTERVAL 100 ++#define LED_BLINK_SLOWLY_INTERVAL 200 ++#define LED_BLINK_LONG_INTERVAL 400 ++ ++#define LED_BLINK_NO_LINK_INTERVAL_ALPHA 1000 ++#define LED_BLINK_LINK_INTERVAL_ALPHA 500 //500 ++#define LED_BLINK_SCAN_INTERVAL_ALPHA 180 //150 ++#define LED_BLINK_FASTER_INTERVAL_ALPHA 50 ++#define LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA 5000 ++ ++#define LED_BLINK_NORMAL_INTERVAL_NETTRONIX 100 ++#define LED_BLINK_SLOWLY_INTERVAL_NETTRONIX 2000 ++ ++#define LED_BLINK_SLOWLY_INTERVAL_PORNET 1000 ++#define LED_BLINK_NORMAL_INTERVAL_PORNET 100 ++ ++#define LED_BLINK_FAST_INTERVAL_BITLAND 30 ++ ++// 060403, rcnjko: Customized for AzWave. ++#define LED_CM2_BLINK_ON_INTERVAL 250 ++#define LED_CM2_BLINK_OFF_INTERVAL 4750 ++ ++#define LED_CM8_BLINK_INTERVAL 500 //for QMI ++#define LED_CM8_BLINK_OFF_INTERVAL 3750 //for QMI ++ ++// 080124, lanhsin: Customized for RunTop ++#define LED_RunTop_BLINK_INTERVAL 300 ++ ++// 060421, rcnjko: Customized for Sercomm Printer Server case. ++#define LED_CM3_BLINK_INTERVAL 1500 ++ ++typedef enum _LED_CTL_MODE{ ++ LED_CTL_POWER_ON = 1, ++ LED_CTL_LINK = 2, ++ LED_CTL_NO_LINK = 3, ++ LED_CTL_TX = 4, ++ LED_CTL_RX = 5, ++ LED_CTL_SITE_SURVEY = 6, ++ LED_CTL_POWER_OFF = 7, ++ LED_CTL_START_TO_LINK = 8, ++ LED_CTL_START_WPS = 9, ++ LED_CTL_STOP_WPS = 10, ++ LED_CTL_START_WPS_BOTTON = 11, //added for runtop ++ LED_CTL_STOP_WPS_FAIL = 12, //added for ALPHA ++ LED_CTL_STOP_WPS_FAIL_OVERLAP = 13, //added for BELKIN ++ LED_CTL_CONNECTION_NO_TRANSFER = 14, ++}LED_CTL_MODE; ++ ++typedef enum _LED_STATE_871x{ ++ LED_UNKNOWN = 0, ++ RTW_LED_ON = 1, ++ RTW_LED_OFF = 2, ++ LED_BLINK_NORMAL = 3, ++ LED_BLINK_SLOWLY = 4, ++ LED_BLINK_POWER_ON = 5, ++ LED_BLINK_SCAN = 6, // LED is blinking during scanning period, the # of times to blink is depend on time for scanning. ++ LED_BLINK_NO_LINK = 7, // LED is blinking during no link state. ++ LED_BLINK_StartToBlink = 8,// Customzied for Sercomm Printer Server case ++ LED_BLINK_TXRX = 9, ++ LED_BLINK_WPS = 10, // LED is blinkg during WPS communication ++ LED_BLINK_WPS_STOP = 11, //for ALPHA ++ LED_BLINK_WPS_STOP_OVERLAP = 12, //for BELKIN ++ LED_BLINK_RUNTOP = 13, // Customized for RunTop ++ LED_BLINK_CAMEO = 14, ++ LED_BLINK_XAVI = 15, ++ LED_BLINK_ALWAYS_ON = 16, ++}LED_STATE_871x; ++ ++typedef enum _LED_PIN_871x{ ++ LED_PIN_NULL = 0, ++ LED_PIN_LED0 = 1, ++ LED_PIN_LED1 = 2, ++ LED_PIN_LED2 = 3, ++ LED_PIN_GPIO0 = 4, ++}LED_PIN_871x; ++ ++typedef struct _LED_871x{ ++ _adapter *padapter; ++ ++ LED_PIN_871x LedPin; // Identify how to implement this SW led. ++ LED_STATE_871x CurrLedState; // Current LED state. ++ LED_STATE_871x BlinkingLedState; // Next state for blinking, either RTW_LED_ON or RTW_LED_OFF are. ++ ++ u8 bLedOn; // true if LED is ON, false if LED is OFF. ++ ++ u8 bLedBlinkInProgress; // true if it is blinking, false o.w.. ++ ++ u8 bLedWPSBlinkInProgress; ++ ++ u32 BlinkTimes; // Number of times to toggle led state for blinking. ++ ++ _timer BlinkTimer; // Timer object for led blinking. ++ ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ u8 bSWLedCtrl; ++ ++ // ALPHA, added by chiyoko, 20090106 ++ u8 bLedNoLinkBlinkInProgress; ++ u8 bLedLinkBlinkInProgress; ++ u8 bLedStartToLinkBlinkInProgress; ++ u8 bLedScanBlinkInProgress; ++ ++ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)|| defined PLATFORM_FREEBSD ++ _workitem BlinkWorkItem; // Workitem used by BlinkTimer to manipulate H/W to blink LED. ++ #endif ++#endif //defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ ++#if defined(CONFIG_PCI_HCI) ++ u8 bLedSlowBlinkInProgress;//added by vivi, for led new mode ++#endif ++ ++} LED_871x, *PLED_871x; ++ ++#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ ++#define IS_LED_WPS_BLINKING(_LED_871x) (((PLED_871x)_LED_871x)->CurrLedState==LED_BLINK_WPS \ ++ || ((PLED_871x)_LED_871x)->CurrLedState==LED_BLINK_WPS_STOP \ ++ || ((PLED_871x)_LED_871x)->bLedWPSBlinkInProgress) ++ ++#define IS_LED_BLINKING(_LED_871x) (((PLED_871x)_LED_871x)->bLedWPSBlinkInProgress \ ++ ||((PLED_871x)_LED_871x)->bLedScanBlinkInProgress) ++ ++//================================================================================ ++// LED customization. ++//================================================================================ ++ ++typedef enum _LED_STRATEGY_871x{ ++ SW_LED_MODE0 = 0, // SW control 1 LED via GPIO0. It is default option. ++ SW_LED_MODE1= 1, // 2 LEDs, through LED0 and LED1. For ALPHA. ++ SW_LED_MODE2 = 2, // SW control 1 LED via GPIO0, customized for AzWave 8187 minicard. ++ SW_LED_MODE3 = 3, // SW control 1 LED via GPIO0, customized for Sercomm Printer Server case. ++ SW_LED_MODE4 = 4, //for Edimax / Belkin ++ SW_LED_MODE5 = 5, //for Sercomm / Belkin ++ SW_LED_MODE6 = 6, //for 88CU minicard, porting from ce SW_LED_MODE7 ++ HW_LED = 50, // HW control 2 LEDs, LED0 and LED1 (there are 4 different control modes, see MAC.CONFIG1 for details.) ++ LED_ST_NONE = 99, ++}LED_STRATEGY_871x, *PLED_STRATEGY_871x; ++ ++void ++LedControl871x( ++ _adapter *padapter, ++ LED_CTL_MODE LedAction ++ ); ++#endif //defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ ++#if defined(CONFIG_PCI_HCI) ++//================================================================================ ++// LED customization. ++//================================================================================ ++ ++typedef enum _LED_STRATEGY_871x{ ++ SW_LED_MODE0 = 0, // SW control 1 LED via GPIO0. It is default option. ++ SW_LED_MODE1 = 1, // SW control for PCI Express ++ SW_LED_MODE2 = 2, // SW control for Cameo. ++ SW_LED_MODE3 = 3, // SW contorl for RunTop. ++ SW_LED_MODE4 = 4, // SW control for Netcore ++ SW_LED_MODE5 = 5, //added by vivi, for led new mode, DLINK ++ SW_LED_MODE6 = 6, //added by vivi, for led new mode, PRONET ++ SW_LED_MODE7 = 7, //added by chiyokolin, for Lenovo, PCI Express Minicard Spec Rev.1.2 spec ++ SW_LED_MODE8 = 8, //added by chiyokolin, for QMI ++ SW_LED_MODE9 = 9, //added by chiyokolin, for BITLAND, PCI Express Minicard Spec Rev.1.1 ++ SW_LED_MODE10 = 10, //added by chiyokolin, for Edimax-ASUS ++ HW_LED = 50, // HW control 2 LEDs, LED0 and LED1 (there are 4 different control modes) ++ LED_ST_NONE = 99, ++}LED_STRATEGY_871x, *PLED_STRATEGY_871x; ++#endif //defined(CONFIG_PCI_HCI) ++ ++struct led_priv{ ++ /* add for led controll */ ++ LED_871x SwLed0; ++ LED_871x SwLed1; ++ LED_STRATEGY_871x LedStrategy; ++ u8 bRegUseLed; ++ void (*LedControlHandler)(_adapter *padapter, LED_CTL_MODE LedAction); ++ /* add for led controll */ ++}; ++ ++#ifdef CONFIG_SW_LED ++#define rtw_led_control(adapter, LedAction) \ ++ do { \ ++ if((adapter)->ledpriv.LedControlHandler) \ ++ (adapter)->ledpriv.LedControlHandler((adapter), (LedAction)); \ ++ } while(0) ++#else //CONFIG_SW_LED ++#define rtw_led_control(adapter, LedAction) ++#endif //CONFIG_SW_LED ++ ++void BlinkTimerCallback(void *data); ++void BlinkWorkItemCallback(struct work_struct *work); ++ ++void ResetLedStatus(PLED_871x pLed); ++ ++void ++InitLed871x( ++ _adapter *padapter, ++ PLED_871x pLed, ++ LED_PIN_871x LedPin ++ ); ++ ++void ++DeInitLed871x( ++ PLED_871x pLed ++ ); ++ ++//hal... ++extern void BlinkHandler(PLED_871x pLed); ++ ++#endif //__RTW_LED_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_mlme.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_mlme.h +new file mode 100644 +index 00000000..98738c8d +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_mlme.h +@@ -0,0 +1,870 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTW_MLME_H_ ++#define __RTW_MLME_H_ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_INTEL_WIDI ++#include ++#endif ++ ++#define MAX_BSS_CNT 128 ++//#define MAX_JOIN_TIMEOUT 2000 ++//#define MAX_JOIN_TIMEOUT 2500 ++#define MAX_JOIN_TIMEOUT 6500 ++ ++// Commented by Albert 20101105 ++// Increase the scanning timeout because of increasing the SURVEY_TO value. ++ ++#define SCANNING_TIMEOUT 8000 ++ ++#define SCAN_INTERVAL (30) // unit:2sec, 30*2=60sec ++ ++#ifdef PALTFORM_OS_WINCE ++#define SCANQUEUE_LIFETIME 12000000 // unit:us ++#else ++#define SCANQUEUE_LIFETIME 20 // unit:sec ++#endif ++ ++#define WIFI_NULL_STATE 0x00000000 ++ ++#define WIFI_ASOC_STATE 0x00000001 // Under Linked state... ++#define WIFI_REASOC_STATE 0x00000002 ++#define WIFI_SLEEP_STATE 0x00000004 ++#define WIFI_STATION_STATE 0x00000008 ++ ++#define WIFI_AP_STATE 0x00000010 ++#define WIFI_ADHOC_STATE 0x00000020 ++#define WIFI_ADHOC_MASTER_STATE 0x00000040 ++#define WIFI_UNDER_LINKING 0x00000080 ++ ++#define WIFI_UNDER_WPS 0x00000100 ++//#define WIFI_UNDER_CMD 0x00000200 ++//#define WIFI_UNDER_P2P 0x00000400 ++#define WIFI_STA_ALIVE_CHK_STATE 0x00000400 ++#define WIFI_SITE_MONITOR 0x00000800 //to indicate the station is under site surveying ++ ++#ifdef WDS ++#define WIFI_WDS 0x00001000 ++#define WIFI_WDS_RX_BEACON 0x00002000 // already rx WDS AP beacon ++#endif ++#ifdef AUTO_CONFIG ++#define WIFI_AUTOCONF 0x00004000 ++#define WIFI_AUTOCONF_IND 0x00008000 ++#endif ++ ++/* ++// ========== P2P Section Start =============== ++#define WIFI_P2P_LISTEN_STATE 0x00010000 ++#define WIFI_P2P_GROUP_FORMATION_STATE 0x00020000 ++// ========== P2P Section End =============== ++*/ ++ ++//#ifdef UNDER_MPTEST ++#define WIFI_MP_STATE 0x00010000 ++#define WIFI_MP_CTX_BACKGROUND 0x00020000 // in continous tx background ++#define WIFI_MP_CTX_ST 0x00040000 // in continous tx with single-tone ++#define WIFI_MP_CTX_BACKGROUND_PENDING 0x00080000 // pending in continous tx background due to out of skb ++#define WIFI_MP_CTX_CCK_HW 0x00100000 // in continous tx ++#define WIFI_MP_CTX_CCK_CS 0x00200000 // in continous tx with carrier suppression ++#define WIFI_MP_LPBK_STATE 0x00400000 ++//#endif ++ ++//#define _FW_UNDER_CMD WIFI_UNDER_CMD ++#define _FW_UNDER_LINKING WIFI_UNDER_LINKING ++#define _FW_LINKED WIFI_ASOC_STATE ++#define _FW_UNDER_SURVEY WIFI_SITE_MONITOR ++ ++ ++enum dot11AuthAlgrthmNum { ++ dot11AuthAlgrthm_Open = 0, ++ dot11AuthAlgrthm_Shared, ++ dot11AuthAlgrthm_8021X, ++ dot11AuthAlgrthm_Auto, ++ dot11AuthAlgrthm_WAPI, ++ dot11AuthAlgrthm_MaxNum ++}; ++ ++// Scan type including active and passive scan. ++typedef enum _RT_SCAN_TYPE ++{ ++ SCAN_PASSIVE, ++ SCAN_ACTIVE, ++ SCAN_MIX, ++}RT_SCAN_TYPE, *PRT_SCAN_TYPE; ++ ++enum _BAND ++{ ++ GHZ24_50 = 0, ++ GHZ_50, ++ GHZ_24, ++}; ++ ++enum DriverInterface { ++ DRIVER_WEXT = 1, ++ DRIVER_CFG80211 = 2 ++}; ++ ++enum SCAN_RESULT_TYPE ++{ ++ SCAN_RESULT_P2P_ONLY = 0, // Will return all the P2P devices. ++ SCAN_RESULT_ALL = 1, // Will return all the scanned device, include AP. ++ SCAN_RESULT_WFD_TYPE = 2 // Will just return the correct WFD device. ++ // If this device is Miracast sink device, it will just return all the Miracast source devices. ++}; ++ ++/* ++ ++there are several "locks" in mlme_priv, ++since mlme_priv is a shared resource between many threads, ++like ISR/Call-Back functions, the OID handlers, and even timer functions. ++ ++ ++Each _queue has its own locks, already. ++Other items are protected by mlme_priv.lock. ++ ++To avoid possible dead lock, any thread trying to modifiying mlme_priv ++SHALL not lock up more than one locks at a time! ++ ++*/ ++ ++ ++#define traffic_threshold 10 ++#define traffic_scan_period 500 ++ ++struct sitesurvey_ctrl { ++ u64 last_tx_pkts; ++ uint last_rx_pkts; ++ sint traffic_busy; ++ _timer sitesurvey_ctrl_timer; ++}; ++ ++typedef struct _RT_LINK_DETECT_T{ ++ u32 NumTxOkInPeriod; ++ u32 NumRxOkInPeriod; ++ u32 NumRxUnicastOkInPeriod; ++ BOOLEAN bBusyTraffic; ++ BOOLEAN bTxBusyTraffic; ++ BOOLEAN bRxBusyTraffic; ++ BOOLEAN bHigherBusyTraffic; // For interrupt migration purpose. ++ BOOLEAN bHigherBusyRxTraffic; // We may disable Tx interrupt according as Rx traffic. ++ BOOLEAN bHigherBusyTxTraffic; // We may disable Tx interrupt according as Tx traffic. ++}RT_LINK_DETECT_T, *PRT_LINK_DETECT_T; ++ ++struct profile_info { ++ u8 ssidlen; ++ u8 ssid[ WLAN_SSID_MAXLEN ]; ++ u8 peermac[ ETH_ALEN ]; ++}; ++ ++struct tx_invite_req_info{ ++ u8 token; ++ u8 benable; ++ u8 go_ssid[ WLAN_SSID_MAXLEN ]; ++ u8 ssidlen; ++ u8 go_bssid[ ETH_ALEN ]; ++ u8 peer_macaddr[ ETH_ALEN ]; ++ u8 operating_ch; // This information will be set by using the p2p_set op_ch=x ++ u8 peer_ch; // The listen channel for peer P2P device ++ ++}; ++ ++struct tx_invite_resp_info{ ++ u8 token; // Used to record the dialog token of p2p invitation request frame. ++}; ++ ++#ifdef CONFIG_WFD ++ ++struct wifi_display_info{ ++ u16 wfd_enable; // Eanble/Disable the WFD function. ++ u16 rtsp_ctrlport; // TCP port number at which the this WFD device listens for RTSP messages ++ u16 peer_rtsp_ctrlport; // TCP port number at which the peer WFD device listens for RTSP messages ++ // This filed should be filled when receiving the gropu negotiation request ++ ++ u8 peer_session_avail; // WFD session is available or not for the peer wfd device. ++ // This variable will be set when sending the provisioning discovery request to peer WFD device. ++ // And this variable will be reset when it is read by using the iwpriv p2p_get wfd_sa command. ++ u8 ip_address[4]; ++ u8 peer_ip_address[4]; ++ u8 wfd_pc; // WFD preferred connection ++ // 0 -> Prefer to use the P2P for WFD connection on peer side. ++ // 1 -> Prefer to use the TDLS for WFD connection on peer side. ++ ++ u8 wfd_device_type; // WFD Device Type ++ // 0 -> WFD Source Device ++ // 1 -> WFD Primary Sink Device ++ enum SCAN_RESULT_TYPE scan_result_type; // Used when P2P is enable. This parameter will impact the scan result. ++}; ++#endif //CONFIG_WFD ++ ++struct tx_provdisc_req_info{ ++ u16 wps_config_method_request; // Used when sending the provisioning request frame ++ u16 peer_channel_num[2]; // The channel number which the receiver stands. ++ NDIS_802_11_SSID ssid; ++ u8 peerDevAddr[ ETH_ALEN ]; // Peer device address ++ u8 peerIFAddr[ ETH_ALEN ]; // Peer interface address ++ u8 benable; // This provision discovery request frame is trigger to send or not ++}; ++ ++struct rx_provdisc_req_info{ //When peer device issue prov_disc_req first, we should store the following informations ++ u8 peerDevAddr[ ETH_ALEN ]; // Peer device address ++ u8 strconfig_method_desc_of_prov_disc_req[4]; // description for the config method located in the provisioning discovery request frame. ++ // The UI must know this information to know which config method the remote p2p device is requiring. ++}; ++ ++struct tx_nego_req_info{ ++ u16 peer_channel_num[2]; // The channel number which the receiver stands. ++ u8 peerDevAddr[ ETH_ALEN ]; // Peer device address ++ u8 benable; // This negoitation request frame is trigger to send or not ++}; ++ ++struct group_id_info{ ++ u8 go_device_addr[ ETH_ALEN ]; // The GO's device address of this P2P group ++ u8 ssid[ WLAN_SSID_MAXLEN ]; // The SSID of this P2P group ++}; ++ ++struct scan_limit_info{ ++ u8 scan_op_ch_only; // When this flag is set, the driver should just scan the operation channel ++#ifndef P2P_OP_CHECK_SOCIAL_CH ++ u8 operation_ch[2]; // Store the operation channel of invitation request frame ++#else ++ u8 operation_ch[5]; // Store additional channel 1,6,11 for Android 4.2 IOT & Nexus 4 ++#endif //P2P_OP_CHECK_SOCIAL_CH ++}; ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++struct cfg80211_wifidirect_info{ ++ _timer remain_on_ch_timer; ++ u8 restore_channel; ++ struct ieee80211_channel remain_on_ch_channel; ++ enum nl80211_channel_type remain_on_ch_type; ++ u64 remain_on_ch_cookie; ++ bool is_ro_ch; ++}; ++#endif //CONFIG_IOCTL_CFG80211 ++ ++struct wifidirect_info{ ++ _adapter* padapter; ++ _timer find_phase_timer; ++ _timer restore_p2p_state_timer; ++ ++ // Used to do the scanning. After confirming the peer is availalble, the driver transmits the P2P frame to peer. ++ _timer pre_tx_scan_timer; ++ _timer reset_ch_sitesurvey; ++ _timer reset_ch_sitesurvey2; // Just for resetting the scan limit function by using p2p nego ++#ifdef CONFIG_CONCURRENT_MODE ++ // Used to switch the channel between legacy AP and listen state. ++ _timer ap_p2p_switch_timer; ++#endif ++ struct tx_provdisc_req_info tx_prov_disc_info; ++ struct rx_provdisc_req_info rx_prov_disc_info; ++ struct tx_invite_req_info invitereq_info; ++ struct profile_info profileinfo[ P2P_MAX_PERSISTENT_GROUP_NUM ]; // Store the profile information of persistent group ++ struct tx_invite_resp_info inviteresp_info; ++ struct tx_nego_req_info nego_req_info; ++ struct group_id_info groupid_info; // Store the group id information when doing the group negotiation handshake. ++ struct scan_limit_info rx_invitereq_info; // Used for get the limit scan channel from the Invitation procedure ++ struct scan_limit_info p2p_info; // Used for get the limit scan channel from the P2P negotiation handshake ++#ifdef CONFIG_WFD ++ struct wifi_display_info *wfd_info; ++#endif ++ enum P2P_ROLE role; ++ enum P2P_STATE pre_p2p_state; ++ enum P2P_STATE p2p_state; ++ u8 device_addr[ETH_ALEN]; // The device address should be the mac address of this device. ++ u8 interface_addr[ETH_ALEN]; ++ u8 social_chan[4]; ++ u8 listen_channel; ++ u8 operating_channel; ++ u8 listen_dwell; // This value should be between 1 and 3 ++ u8 support_rate[8]; ++ u8 p2p_wildcard_ssid[P2P_WILDCARD_SSID_LEN]; ++ u8 intent; // should only include the intent value. ++ u8 p2p_peer_interface_addr[ ETH_ALEN ]; ++ u8 p2p_peer_device_addr[ ETH_ALEN ]; ++ u8 peer_intent; // Included the intent value and tie breaker value. ++ u8 device_name[ WPS_MAX_DEVICE_NAME_LEN ]; // Device name for displaying on searching device screen ++ u8 device_name_len; ++ u8 profileindex; // Used to point to the index of profileinfo array ++ u8 peer_operating_ch; ++ u8 find_phase_state_exchange_cnt; ++ u16 device_password_id_for_nego; // The device password ID for group negotation ++ u8 negotiation_dialog_token; ++ u8 nego_ssid[ WLAN_SSID_MAXLEN ]; // SSID information for group negotitation ++ u8 nego_ssidlen; ++ u8 p2p_group_ssid[WLAN_SSID_MAXLEN]; ++ u8 p2p_group_ssid_len; ++ u8 persistent_supported; // Flag to know the persistent function should be supported or not. ++ // In the Sigma test, the Sigma will provide this enable from the sta_set_p2p CAPI. ++ // 0: disable ++ // 1: enable ++ u8 session_available; // Flag to set the WFD session available to enable or disable "by Sigma" ++ // In the Sigma test, the Sigma will disable the session available by using the sta_preset CAPI. ++ // 0: disable ++ // 1: enable ++ ++ u8 wfd_tdls_enable; // Flag to enable or disable the TDLS by WFD Sigma ++ // 0: disable ++ // 1: enable ++ u8 wfd_tdls_weaksec; // Flag to enable or disable the weak security function for TDLS by WFD Sigma ++ // 0: disable ++ // In this case, the driver can't issue the tdsl setup request frame. ++ // 1: enable ++ // In this case, the driver can issue the tdls setup request frame ++ // even the current security is weak security. ++ ++ enum P2P_WPSINFO ui_got_wps_info; // This field will store the WPS value (PIN value or PBC) that UI had got from the user. ++ u16 supported_wps_cm; // This field describes the WPS config method which this driver supported. ++ // The value should be the combination of config method defined in page104 of WPS v2.0 spec. ++ u8 external_uuid; // UUID flag ++ u8 uuid[16]; // UUID ++ uint channel_list_attr_len; // This field will contain the length of body of P2P Channel List attribute of group negotitation response frame. ++ u8 channel_list_attr[100]; // This field will contain the body of P2P Channel List attribute of group negotitation response frame. ++ // We will use the channel_cnt and channel_list fields when constructing the group negotitation confirm frame. ++ u8 driver_interface; // Indicate DRIVER_WEXT or DRIVER_CFG80211 ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ u16 ext_listen_interval; // The interval to be available with legacy AP (ms) ++ u16 ext_listen_period; // The time period to be available for P2P listen state (ms) ++#endif ++#ifdef CONFIG_P2P_PS ++ enum P2P_PS_MODE p2p_ps_mode; // indicate p2p ps mode ++ enum P2P_PS_STATE p2p_ps_state; // indicate p2p ps state ++ u8 noa_index; // Identifies and instance of Notice of Absence timing. ++ u8 ctwindow; // Client traffic window. A period of time in TU after TBTT. ++ u8 opp_ps; // opportunistic power save. ++ u8 noa_num; // number of NoA descriptor in P2P IE. ++ u8 noa_count[P2P_MAX_NOA_NUM]; // Count for owner, Type of client. ++ u32 noa_duration[P2P_MAX_NOA_NUM]; // Max duration for owner, preferred or min acceptable duration for client. ++ u32 noa_interval[P2P_MAX_NOA_NUM]; // Length of interval for owner, preferred or max acceptable interval of client. ++ u32 noa_start_time[P2P_MAX_NOA_NUM]; // schedule expressed in terms of the lower 4 bytes of the TSF timer. ++#endif // CONFIG_P2P_PS ++}; ++ ++struct tdls_ss_record{ //signal strength record ++ u8 macaddr[ETH_ALEN]; ++ u8 RxPWDBAll; ++ u8 is_tdls_sta; // _TRUE: direct link sta, _FALSE: else ++}; ++ ++struct tdls_info{ ++ u8 ap_prohibited; ++ uint setup_state; ++ u8 sta_cnt; ++ u8 sta_maximum; // 1:tdls sta is equal (NUM_STA-1), reach max direct link number; 0: else; ++ struct tdls_ss_record ss_record; ++ u8 macid_index; //macid entry that is ready to write ++ u8 clear_cam; //cam entry that is trying to clear, using it in direct link teardown ++ u8 ch_sensing; ++ u8 cur_channel; ++ u8 candidate_ch; ++ u8 collect_pkt_num[MAX_CHANNEL_NUM]; ++ _lock cmd_lock; ++ _lock hdl_lock; ++ u8 watchdog_count; ++ u8 dev_discovered; //WFD_TDLS: for sigma test ++ u8 enable; ++#ifdef CONFIG_WFD ++ struct wifi_display_info *wfd_info; ++#endif ++}; ++ ++struct mlme_priv { ++ ++ _lock lock; ++ sint fw_state; //shall we protect this variable? maybe not necessarily... ++ u8 bScanInProcess; ++ u8 to_join; //flag ++ #ifdef CONFIG_LAYER2_ROAMING ++ u8 to_roaming; // roaming trying times ++ #endif ++ ++ u8 *nic_hdl; ++ ++ u8 not_indic_disco; ++ _list *pscanned; ++ _queue free_bss_pool; ++ _queue scanned_queue; ++ u8 *free_bss_buf; ++ u32 num_of_scanned; ++ ++ NDIS_802_11_SSID assoc_ssid; ++ u8 assoc_bssid[6]; ++ ++ struct wlan_network cur_network; ++ struct wlan_network *cur_network_scanned; ++#ifdef CONFIG_ARP_KEEP_ALIVE ++ // for arp offload keep alive ++ u8 gw_mac_addr[6]; ++ u8 gw_ip[4]; ++#endif ++ ++ //uint wireless_mode; no used, remove it ++ ++ u32 scan_interval; ++ ++ _timer assoc_timer; ++ ++ uint assoc_by_bssid; ++ uint assoc_by_rssi; ++ ++ _timer scan_to_timer; // driver itself handles scan_timeout status. ++ u32 scan_start_time; // used to evaluate the time spent in scanning ++ ++ #ifdef CONFIG_SET_SCAN_DENY_TIMER ++ _timer set_scan_deny_timer; ++ ATOMIC_T set_scan_deny; //0: allowed, 1: deny ++ #endif ++ ++ #ifdef CONFIG_DETECT_C2H_BY_POLLING ++ _timer event_polling_timer; ++ #endif ++ ++ struct qos_priv qospriv; ++ ++#ifdef CONFIG_80211N_HT ++ ++ /* Number of non-HT AP/stations */ ++ int num_sta_no_ht; ++ ++ /* Number of HT AP/stations 20 MHz */ ++ //int num_sta_ht_20mhz; ++ ++ ++ int num_FortyMHzIntolerant; ++ ++ struct ht_priv htpriv; ++ ++#endif ++ ++ RT_LINK_DETECT_T LinkDetectInfo; ++ _timer dynamic_chk_timer; //dynamic/periodic check timer ++ ++ u8 acm_mask; // for wmm acm mask ++ u8 ChannelPlan; ++ RT_SCAN_TYPE scan_mode; // active: 1, passive: 0 ++ ++ //u8 probereq_wpsie[MAX_WPS_IE_LEN];//added in probe req ++ //int probereq_wpsie_len; ++ u8 *wps_probe_req_ie; ++ u32 wps_probe_req_ie_len; ++ ++#if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) ++ /* Number of associated Non-ERP stations (i.e., stations using 802.11b ++ * in 802.11g BSS) */ ++ int num_sta_non_erp; ++ ++ /* Number of associated stations that do not support Short Slot Time */ ++ int num_sta_no_short_slot_time; ++ ++ /* Number of associated stations that do not support Short Preamble */ ++ int num_sta_no_short_preamble; ++ ++ int olbc; /* Overlapping Legacy BSS Condition */ ++ ++ /* Number of HT associated stations that do not support greenfield */ ++ int num_sta_ht_no_gf; ++ ++ /* Number of associated non-HT stations */ ++ //int num_sta_no_ht; ++ ++ /* Number of HT associated stations 20 MHz */ ++ int num_sta_ht_20mhz; ++ ++ /* Overlapping BSS information */ ++ int olbc_ht; ++ ++#ifdef CONFIG_80211N_HT ++ u16 ht_op_mode; ++#endif /* CONFIG_80211N_HT */ ++ ++ u8 *assoc_req; ++ u32 assoc_req_len; ++ u8 *assoc_rsp; ++ u32 assoc_rsp_len; ++ ++ u8 *wps_beacon_ie; ++ //u8 *wps_probe_req_ie; ++ u8 *wps_probe_resp_ie; ++ u8 *wps_assoc_resp_ie; // for CONFIG_IOCTL_CFG80211, this IE could include p2p ie / wfd ie ++ ++ u32 wps_beacon_ie_len; ++ //u32 wps_probe_req_ie_len; ++ u32 wps_probe_resp_ie_len; ++ u32 wps_assoc_resp_ie_len; // for CONFIG_IOCTL_CFG80211, this IE len could include p2p ie / wfd ie ++ ++ u8 *p2p_beacon_ie; ++ u8 *p2p_probe_req_ie; ++ u8 *p2p_probe_resp_ie; ++ u8 *p2p_go_probe_resp_ie; //for GO ++ u8 *p2p_assoc_req_ie; ++ ++ u32 p2p_beacon_ie_len; ++ u32 p2p_probe_req_ie_len; ++ u32 p2p_probe_resp_ie_len; ++ u32 p2p_go_probe_resp_ie_len; //for GO ++ u32 p2p_assoc_req_ie_len; ++/* ++#if defined(CONFIG_P2P) && defined(CONFIG_IOCTL_CFG80211) ++ //u8 *wps_p2p_beacon_ie; ++ u8 *p2p_beacon_ie; ++ u8 *wps_p2p_probe_resp_ie; ++ u8 *wps_p2p_assoc_resp_ie; ++ //u32 wps_p2p_beacon_ie_len; ++ u32 p2p_beacon_ie_len; ++ u32 wps_p2p_probe_resp_ie_len; ++ u32 wps_p2p_assoc_resp_ie_len; ++#endif ++*/ ++ ++ _lock bcn_update_lock; ++ u8 update_bcn; ++ ++ ++#endif //#if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) ++ ++#if defined(CONFIG_WFD) && defined(CONFIG_IOCTL_CFG80211) ++ ++ u8 *wfd_beacon_ie; ++ u8 *wfd_probe_req_ie; ++ u8 *wfd_probe_resp_ie; ++ u8 *wfd_go_probe_resp_ie; //for GO ++ u8 *wfd_assoc_req_ie; ++ ++ u32 wfd_beacon_ie_len; ++ u32 wfd_probe_req_ie_len; ++ u32 wfd_probe_resp_ie_len; ++ u32 wfd_go_probe_resp_ie_len; //for GO ++ u32 wfd_assoc_req_ie_len; ++ ++#endif ++ ++#ifdef RTK_DMP_PLATFORM ++ // DMP kobject_hotplug function signal need in passive level ++ _workitem Linkup_workitem; ++ _workitem Linkdown_workitem; ++#endif ++ ++#ifdef CONFIG_INTEL_WIDI ++ int widi_state; ++ int listen_state; ++ _timer listen_timer; ++ ATOMIC_T rx_probe_rsp; // 1:receive probe respone from RDS source. ++ u8 *l2sdTaBuffer; ++ u8 channel_idx; ++ u8 group_cnt; //In WiDi 3.5, they specified another scan algo. for WFD/RDS co-existed ++ u8 sa_ext[L2SDTA_SERVICE_VE_LEN]; ++ ++ u8 widi_enable; ++ /** ++ * For WiDi 4; upper layer would set ++ * p2p_primary_device_type_category_id ++ * p2p_primary_device_type_sub_category_id ++ * p2p_secondary_device_type_category_id ++ * p2p_secondary_device_type_sub_category_id ++ */ ++ u16 p2p_pdt_cid; ++ u16 p2p_pdt_scid; ++ u8 num_p2p_sdt; ++ u16 p2p_sdt_cid[MAX_NUM_P2P_SDT]; ++ u16 p2p_sdt_scid[MAX_NUM_P2P_SDT]; ++ u8 p2p_reject_disable; //When starting NL80211 wpa_supplicant/hostapd, it will call netdev_close ++ //such that it will cause p2p disabled. Use this flag to reject. ++#endif // CONFIG_INTEL_WIDI ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ u8 scanning_via_buddy_intf; ++#endif ++ ++#ifdef CONFIG_FTP_PROTECT ++ u8 ftp_lock_flag; ++#endif //CONFIG_FTP_PROTECT ++}; ++ ++#ifdef CONFIG_AP_MODE ++ ++struct hostapd_priv ++{ ++ _adapter *padapter; ++ ++#ifdef CONFIG_HOSTAPD_MLME ++ struct net_device *pmgnt_netdev; ++ struct usb_anchor anchored; ++#endif ++ ++}; ++ ++extern int hostapd_mode_init(_adapter *padapter); ++extern void hostapd_mode_unload(_adapter *padapter); ++#endif ++ ++ ++extern void rtw_joinbss_event_prehandle(_adapter *adapter, u8 *pbuf); ++extern void rtw_survey_event_callback(_adapter *adapter, u8 *pbuf); ++extern void rtw_surveydone_event_callback(_adapter *adapter, u8 *pbuf); ++extern void rtw_joinbss_event_callback(_adapter *adapter, u8 *pbuf); ++extern void rtw_stassoc_event_callback(_adapter *adapter, u8 *pbuf); ++extern void rtw_stadel_event_callback(_adapter *adapter, u8 *pbuf); ++extern void rtw_atimdone_event_callback(_adapter *adapter, u8 *pbuf); ++extern void rtw_cpwm_event_callback(_adapter *adapter, u8 *pbuf); ++ ++#ifdef PLATFORM_WINDOWS ++extern thread_return event_thread(void *context); ++ ++extern void rtw_join_timeout_handler ( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3 ++ ); ++ ++extern void _rtw_scan_timeout_handler ( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3 ++ ); ++ ++#endif ++ ++#if defined (PLATFORM_LINUX)|| defined (PLATFORM_FREEBSD) ++extern int event_thread(void *context); ++extern void rtw_join_timeout_handler(void* FunctionContext); ++extern void _rtw_scan_timeout_handler(void* FunctionContext); ++#endif ++ ++extern void rtw_free_network_queue(_adapter *adapter,u8 isfreeall); ++extern int rtw_init_mlme_priv(_adapter *adapter);// (struct mlme_priv *pmlmepriv); ++ ++extern void rtw_free_mlme_priv (struct mlme_priv *pmlmepriv); ++ ++ ++extern sint rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv); ++extern sint rtw_set_key(_adapter *adapter,struct security_priv *psecuritypriv,sint keyid, u8 set_tx, bool enqueue); ++extern sint rtw_set_auth(_adapter *adapter,struct security_priv *psecuritypriv); ++ ++__inline static u8 *get_bssid(struct mlme_priv *pmlmepriv) ++{ //if sta_mode:pmlmepriv->cur_network.network.MacAddress=> bssid ++ // if adhoc_mode:pmlmepriv->cur_network.network.MacAddress=> ibss mac address ++ return pmlmepriv->cur_network.network.MacAddress; ++} ++ ++__inline static sint check_fwstate(struct mlme_priv *pmlmepriv, sint state) ++{ ++ if (pmlmepriv->fw_state & state) ++ return _TRUE; ++ ++ return _FALSE; ++} ++ ++__inline static sint get_fwstate(struct mlme_priv *pmlmepriv) ++{ ++ return pmlmepriv->fw_state; ++} ++ ++/* ++ * No Limit on the calling context, ++ * therefore set it to be the critical section... ++ * ++ * ### NOTE:#### (!!!!) ++ * MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock ++ */ ++__inline static void set_fwstate(struct mlme_priv *pmlmepriv, sint state) ++{ ++ pmlmepriv->fw_state |= state; ++ //FOR HW integration ++ if(_FW_UNDER_SURVEY==state){ ++ pmlmepriv->bScanInProcess = _TRUE; ++ } ++} ++ ++__inline static void _clr_fwstate_(struct mlme_priv *pmlmepriv, sint state) ++{ ++ pmlmepriv->fw_state &= ~state; ++ //FOR HW integration ++ if(_FW_UNDER_SURVEY==state){ ++ pmlmepriv->bScanInProcess = _FALSE; ++ } ++} ++ ++/* ++ * No Limit on the calling context, ++ * therefore set it to be the critical section... ++ */ ++__inline static void clr_fwstate(struct mlme_priv *pmlmepriv, sint state) ++{ ++ _irqL irqL; ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ if (check_fwstate(pmlmepriv, state) == _TRUE) ++ pmlmepriv->fw_state ^= state; ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++} ++ ++__inline static void clr_fwstate_ex(struct mlme_priv *pmlmepriv, sint state) ++{ ++ _irqL irqL; ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ _clr_fwstate_(pmlmepriv, state); ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++} ++ ++__inline static void up_scanned_network(struct mlme_priv *pmlmepriv) ++{ ++ _irqL irqL; ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ pmlmepriv->num_of_scanned++; ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++} ++ ++#ifdef CONFIG_CONCURRENT_MODE ++sint rtw_buddy_adapter_up(_adapter *padapter); ++sint check_buddy_fwstate(_adapter *padapter, sint state); ++u8 rtw_get_buddy_bBusyTraffic(_adapter *padapter); ++#endif //CONFIG_CONCURRENT_MODE ++ ++__inline static void down_scanned_network(struct mlme_priv *pmlmepriv) ++{ ++ _irqL irqL; ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ pmlmepriv->num_of_scanned--; ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++} ++ ++__inline static void set_scanned_network_val(struct mlme_priv *pmlmepriv, sint val) ++{ ++ _irqL irqL; ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ pmlmepriv->num_of_scanned = val; ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++} ++ ++extern u16 rtw_get_capability(WLAN_BSSID_EX *bss); ++extern void rtw_update_scanned_network(_adapter *adapter, WLAN_BSSID_EX *target); ++extern void rtw_disconnect_hdl_under_linked(_adapter* adapter, struct sta_info *psta, u8 free_assoc); ++extern void rtw_generate_random_ibss(u8 *pibss); ++extern struct wlan_network* rtw_find_network(_queue *scanned_queue, u8 *addr); ++extern struct wlan_network* rtw_get_oldest_wlan_network(_queue *scanned_queue); ++ ++extern void rtw_free_assoc_resources(_adapter* adapter, int lock_scanned_queue); ++extern void rtw_indicate_disconnect(_adapter* adapter); ++extern void rtw_indicate_connect(_adapter* adapter); ++void rtw_indicate_scan_done( _adapter *padapter, bool aborted); ++void rtw_scan_abort(_adapter *adapter); ++ ++extern int rtw_restruct_sec_ie(_adapter *adapter,u8 *in_ie,u8 *out_ie,uint in_len); ++extern int rtw_restruct_wmm_ie(_adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len, uint initial_out_len); ++extern void rtw_init_registrypriv_dev_network(_adapter *adapter); ++ ++extern void rtw_update_registrypriv_dev_network(_adapter *adapter); ++ ++extern void rtw_get_encrypt_decrypt_from_registrypriv(_adapter *adapter); ++ ++extern void _rtw_join_timeout_handler(_adapter *adapter); ++extern void rtw_scan_timeout_handler(_adapter *adapter); ++ ++extern void rtw_dynamic_check_timer_handlder(_adapter *adapter); ++#ifdef CONFIG_SET_SCAN_DENY_TIMER ++bool rtw_is_scan_deny(_adapter *adapter); ++void rtw_clear_scan_deny(_adapter *adapter); ++void rtw_set_scan_deny_timer_hdl(_adapter *adapter); ++void rtw_set_scan_deny(_adapter *adapter, u32 ms); ++#else ++#define rtw_is_scan_deny(adapter) _FALSE ++#define rtw_clear_scan_deny(adapter) do {} while (0) ++#define rtw_set_scan_deny_timer_hdl(adapter) do {} while (0) ++#define rtw_set_scan_deny(adapter, ms) do {} while (0) ++#endif ++ ++#ifdef CONFIG_DETECT_C2H_BY_POLLING ++extern void rtw_event_polling_timer_hdl(_adapter *adapter); ++#endif ++ ++extern int _rtw_init_mlme_priv(_adapter *padapter); ++ ++void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv); ++ ++extern void _rtw_free_mlme_priv(struct mlme_priv *pmlmepriv); ++ ++extern int _rtw_enqueue_network(_queue *queue, struct wlan_network *pnetwork); ++ ++extern struct wlan_network* _rtw_dequeue_network(_queue *queue); ++ ++extern struct wlan_network* _rtw_alloc_network(struct mlme_priv *pmlmepriv); ++ ++ ++extern void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork, u8 isfreeall); ++extern void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork); ++ ++ ++extern struct wlan_network* _rtw_find_network(_queue *scanned_queue, u8 *addr); ++ ++extern void _rtw_free_network_queue(_adapter* padapter, u8 isfreeall); ++ ++extern sint rtw_if_up(_adapter *padapter); ++ ++sint rtw_linked_check(_adapter *padapter); ++ ++u8 *rtw_get_capability_from_ie(u8 *ie); ++u8 *rtw_get_timestampe_from_ie(u8 *ie); ++u8 *rtw_get_beacon_interval_from_ie(u8 *ie); ++ ++ ++void rtw_joinbss_reset(_adapter *padapter); ++ ++#ifdef CONFIG_80211N_HT ++unsigned int rtw_restructure_ht_ie(_adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len); ++void rtw_update_ht_cap(_adapter *padapter, u8 *pie, uint ie_len); ++void rtw_issue_addbareq_cmd(_adapter *padapter, struct xmit_frame *pxmitframe); ++#endif ++ ++int rtw_is_same_ibss(_adapter *adapter, struct wlan_network *pnetwork); ++int is_same_network(WLAN_BSSID_EX *src, WLAN_BSSID_EX *dst, u8 feature); ++ ++#ifdef CONFIG_LAYER2_ROAMING ++void _rtw_roaming(_adapter *adapter, struct wlan_network *tgt_network); ++void rtw_roaming(_adapter *adapter, struct wlan_network *tgt_network); ++void rtw_set_roaming(_adapter *adapter, u8 to_roaming); ++u8 rtw_to_roaming(_adapter *adapter); ++#else ++#define _rtw_roaming(adapter, tgt_network) do {} while(0) ++#define rtw_roaming(adapter, tgt_network) do {} while(0) ++#define rtw_set_roaming(adapter, to_roaming) do {} while(0) ++#define rtw_to_roaming(adapter) 0 ++#endif ++ ++void rtw_sta_media_status_rpt(_adapter *adapter,struct sta_info *psta, u32 mstatus); ++ ++#ifdef CONFIG_INTEL_PROXIM ++void rtw_proxim_enable(_adapter *padapter); ++void rtw_proxim_disable(_adapter *padapter); ++void rtw_proxim_send_packet(_adapter *padapter,u8 *pbuf,u16 len,u8 hw_rate); ++#endif //CONFIG_INTEL_PROXIM ++#endif //__RTL871X_MLME_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_mlme_ext.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_mlme_ext.h +new file mode 100644 +index 00000000..a4757732 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_mlme_ext.h +@@ -0,0 +1,1021 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTW_MLME_EXT_H_ ++#define __RTW_MLME_EXT_H_ ++ ++#include ++#include ++#include ++#include ++ ++ ++// Commented by Albert 20101105 ++// Increase the SURVEY_TO value from 100 to 150 ( 100ms to 150ms ) ++// The Realtek 8188CE SoftAP will spend around 100ms to send the probe response after receiving the probe request. ++// So, this driver tried to extend the dwell time for each scanning channel. ++// This will increase the chance to receive the probe response from SoftAP. ++ ++#define SURVEY_TO (100) ++#define REAUTH_TO (300) //(50) ++#define REASSOC_TO (300) //(50) ++//#define DISCONNECT_TO (3000) ++#define ADDBA_TO (2000) ++ ++#define LINKED_TO (1) //unit:2 sec, 1x2=2 sec ++ ++#define REAUTH_LIMIT (4) ++#define REASSOC_LIMIT (4) ++#define READDBA_LIMIT (2) ++ ++#ifdef CONFIG_GSPI_HCI ++ #define ROAMING_LIMIT 5 ++#else ++ #define ROAMING_LIMIT 8 ++#endif ++//#define IOCMD_REG0 0x10250370 ++//#define IOCMD_REG1 0x10250374 ++//#define IOCMD_REG2 0x10250378 ++ ++//#define FW_DYNAMIC_FUN_SWITCH 0x10250364 ++ ++//#define WRITE_BB_CMD 0xF0000001 ++//#define SET_CHANNEL_CMD 0xF3000000 ++//#define UPDATE_RA_CMD 0xFD0000A2 ++ ++#define DYNAMIC_FUNC_DISABLE (0x0) ++ ++// ====== ODM_ABILITY_E ======== ++// BB ODM section BIT 0-15 ++#define DYNAMIC_BB_DIG BIT(0) ++#define DYNAMIC_BB_RA_MASK BIT(1) ++#define DYNAMIC_BB_DYNAMIC_TXPWR BIT(2) ++#define DYNAMIC_BB_BB_FA_CNT BIT(3) ++ ++#define DYNAMIC_BB_RSSI_MONITOR BIT(4) ++#define DYNAMIC_BB_CCK_PD BIT(5) ++#define DYNAMIC_BB_ANT_DIV BIT(6) ++#define DYNAMIC_BB_PWR_SAVE BIT(7) ++#define DYNAMIC_BB_PWR_TRAIN BIT(8) ++#define DYNAMIC_BB_RATE_ADAPTIVE BIT(9) ++#define DYNAMIC_BB_PATH_DIV BIT(10) ++#define DYNAMIC_BB_PSD BIT(11) ++ ++// MAC DM section BIT 16-23 ++#define DYNAMIC_MAC_EDCA_TURBO BIT(16) ++#define DYNAMIC_MAC_EARLY_MODE BIT(17) ++ ++// RF ODM section BIT 24-31 ++#define DYNAMIC_RF_TX_PWR_TRACK BIT(24) ++#define DYNAMIC_RF_RX_GAIN_TRACK BIT(25) ++#define DYNAMIC_RF_CALIBRATION BIT(26) ++ ++#define DYNAMIC_ALL_FUNC_ENABLE 0xFFFFFFF ++ ++#define _HW_STATE_NOLINK_ 0x00 ++#define _HW_STATE_ADHOC_ 0x01 ++#define _HW_STATE_STATION_ 0x02 ++#define _HW_STATE_AP_ 0x03 ++ ++ ++#define _1M_RATE_ 0 ++#define _2M_RATE_ 1 ++#define _5M_RATE_ 2 ++#define _11M_RATE_ 3 ++#define _6M_RATE_ 4 ++#define _9M_RATE_ 5 ++#define _12M_RATE_ 6 ++#define _18M_RATE_ 7 ++#define _24M_RATE_ 8 ++#define _36M_RATE_ 9 ++#define _48M_RATE_ 10 ++#define _54M_RATE_ 11 ++ ++ ++extern unsigned char RTW_WPA_OUI[]; ++extern unsigned char WMM_OUI[]; ++extern unsigned char WPS_OUI[]; ++extern unsigned char WFD_OUI[]; ++extern unsigned char P2P_OUI[]; ++ ++extern unsigned char WMM_INFO_OUI[]; ++extern unsigned char WMM_PARA_OUI[]; ++ ++ ++// ++// Channel Plan Type. ++// Note: ++// We just add new channel plan when the new channel plan is different from any of the following ++// channel plan. ++// If you just wnat to customize the acitions(scan period or join actions) about one of the channel plan, ++// customize them in RT_CHANNEL_INFO in the RT_CHANNEL_LIST. ++// ++typedef enum _RT_CHANNEL_DOMAIN ++{ ++ //===== old channel plan mapping =====// ++ RT_CHANNEL_DOMAIN_FCC = 0x00, ++ RT_CHANNEL_DOMAIN_IC = 0x01, ++ RT_CHANNEL_DOMAIN_ETSI = 0x02, ++ RT_CHANNEL_DOMAIN_SPAIN = 0x03, ++ RT_CHANNEL_DOMAIN_FRANCE = 0x04, ++ RT_CHANNEL_DOMAIN_MKK = 0x05, ++ RT_CHANNEL_DOMAIN_MKK1 = 0x06, ++ RT_CHANNEL_DOMAIN_ISRAEL = 0x07, ++ RT_CHANNEL_DOMAIN_TELEC = 0x08, ++ RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN = 0x09, ++ RT_CHANNEL_DOMAIN_WORLD_WIDE_13 = 0x0A, ++ RT_CHANNEL_DOMAIN_TAIWAN = 0x0B, ++ RT_CHANNEL_DOMAIN_CHINA = 0x0C, ++ RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO = 0x0D, ++ RT_CHANNEL_DOMAIN_KOREA = 0x0E, ++ RT_CHANNEL_DOMAIN_TURKEY = 0x0F, ++ RT_CHANNEL_DOMAIN_JAPAN = 0x10, ++ RT_CHANNEL_DOMAIN_FCC_NO_DFS = 0x11, ++ RT_CHANNEL_DOMAIN_JAPAN_NO_DFS = 0x12, ++ RT_CHANNEL_DOMAIN_WORLD_WIDE_5G = 0x13, ++ RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS = 0x14, ++ ++ //===== new channel plan mapping, (2GDOMAIN_5GDOMAIN) =====// ++ RT_CHANNEL_DOMAIN_WORLD_NULL = 0x20, ++ RT_CHANNEL_DOMAIN_ETSI1_NULL = 0x21, ++ RT_CHANNEL_DOMAIN_FCC1_NULL = 0x22, ++ RT_CHANNEL_DOMAIN_MKK1_NULL = 0x23, ++ RT_CHANNEL_DOMAIN_ETSI2_NULL = 0x24, ++ RT_CHANNEL_DOMAIN_FCC1_FCC1 = 0x25, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI1 = 0x26, ++ RT_CHANNEL_DOMAIN_MKK1_MKK1 = 0x27, ++ RT_CHANNEL_DOMAIN_WORLD_KCC1 = 0x28, ++ RT_CHANNEL_DOMAIN_WORLD_FCC2 = 0x29, ++ RT_CHANNEL_DOMAIN_WORLD_FCC3 = 0x30, ++ RT_CHANNEL_DOMAIN_WORLD_FCC4 = 0x31, ++ RT_CHANNEL_DOMAIN_WORLD_FCC5 = 0x32, ++ RT_CHANNEL_DOMAIN_WORLD_FCC6 = 0x33, ++ RT_CHANNEL_DOMAIN_FCC1_FCC7 = 0x34, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI2 = 0x35, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI3 = 0x36, ++ RT_CHANNEL_DOMAIN_MKK1_MKK2 = 0x37, ++ RT_CHANNEL_DOMAIN_MKK1_MKK3 = 0x38, ++ RT_CHANNEL_DOMAIN_FCC1_NCC1 = 0x39, ++ RT_CHANNEL_DOMAIN_FCC1_NCC2 = 0x40, ++ RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G = 0x41, ++ //===== Add new channel plan above this line===============// ++ RT_CHANNEL_DOMAIN_MAX, ++ RT_CHANNEL_DOMAIN_REALTEK_DEFINE = 0x7F, ++}RT_CHANNEL_DOMAIN, *PRT_CHANNEL_DOMAIN; ++ ++typedef enum _RT_CHANNEL_DOMAIN_2G ++{ ++ RT_CHANNEL_DOMAIN_2G_WORLD = 0x00, //Worldwird 13 ++ RT_CHANNEL_DOMAIN_2G_ETSI1 = 0x01, //Europe ++ RT_CHANNEL_DOMAIN_2G_FCC1 = 0x02, //US ++ RT_CHANNEL_DOMAIN_2G_MKK1 = 0x03, //Japan ++ RT_CHANNEL_DOMAIN_2G_ETSI2 = 0x04, //France ++ RT_CHANNEL_DOMAIN_2G_NULL = 0x05, ++ //===== Add new channel plan above this line===============// ++ RT_CHANNEL_DOMAIN_2G_MAX, ++}RT_CHANNEL_DOMAIN_2G, *PRT_CHANNEL_DOMAIN_2G; ++ ++typedef enum _RT_CHANNEL_DOMAIN_5G ++{ ++ RT_CHANNEL_DOMAIN_5G_NULL = 0x00, ++ RT_CHANNEL_DOMAIN_5G_ETSI1 = 0x01, //Europe ++ RT_CHANNEL_DOMAIN_5G_ETSI2 = 0x02, //Australia, New Zealand ++ RT_CHANNEL_DOMAIN_5G_ETSI3 = 0x03, //Russia ++ RT_CHANNEL_DOMAIN_5G_FCC1 = 0x04, //US ++ RT_CHANNEL_DOMAIN_5G_FCC2 = 0x05, //FCC o/w DFS Channels ++ RT_CHANNEL_DOMAIN_5G_FCC3 = 0x06, //India, Mexico ++ RT_CHANNEL_DOMAIN_5G_FCC4 = 0x07, //Venezuela ++ RT_CHANNEL_DOMAIN_5G_FCC5 = 0x08, //China ++ RT_CHANNEL_DOMAIN_5G_FCC6 = 0x09, //Israel ++ RT_CHANNEL_DOMAIN_5G_FCC7_IC1 = 0x0A, //US, Canada ++ RT_CHANNEL_DOMAIN_5G_KCC1 = 0x0B, //Korea ++ RT_CHANNEL_DOMAIN_5G_MKK1 = 0x0C, //Japan ++ RT_CHANNEL_DOMAIN_5G_MKK2 = 0x0D, //Japan (W52, W53) ++ RT_CHANNEL_DOMAIN_5G_MKK3 = 0x0E, //Japan (W56) ++ RT_CHANNEL_DOMAIN_5G_NCC1 = 0x0F, //Taiwan ++ RT_CHANNEL_DOMAIN_5G_NCC2 = 0x10, //Taiwan o/w DFS ++ //===== Add new channel plan above this line===============// ++ //===== Driver Self Defined =====// ++ RT_CHANNEL_DOMAIN_5G_FCC = 0x11, ++ RT_CHANNEL_DOMAIN_5G_JAPAN_NO_DFS = 0x12, ++ RT_CHANNEL_DOMAIN_5G_FCC4_NO_DFS = 0x13, ++ RT_CHANNEL_DOMAIN_5G_MAX, ++}RT_CHANNEL_DOMAIN_5G, *PRT_CHANNEL_DOMAIN_5G; ++ ++#define rtw_is_channel_plan_valid(chplan) (chplansurvey_timer, (ms)); \ ++ } while(0) ++ ++#define set_link_timer(mlmeext, ms) \ ++ do { \ ++ /*DBG_871X("%s set_link_timer(%p, %d)\n", __FUNCTION__, (mlmeext), (ms));*/ \ ++ _set_timer(&(mlmeext)->link_timer, (ms)); \ ++ } while(0) ++#ifdef CONFIG_IEEE80211W ++#define set_sa_query_timer(mlmeext, ms) \ ++ do { \ ++ DBG_871X("%s set_sa_query_timer(%p, %d)\n", __FUNCTION__, (mlmeext), (ms)); \ ++ _set_timer(&(mlmeext)->sa_query_timer, (ms)); \ ++ } while(0) ++#endif //CONFIG_IEEE80211W ++extern int cckrates_included(unsigned char *rate, int ratelen); ++extern int cckratesonly_included(unsigned char *rate, int ratelen); ++ ++extern void process_addba_req(_adapter *padapter, u8 *paddba_req, u8 *addr); ++ ++extern void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len); ++extern void correct_TSF(_adapter *padapter, struct mlme_ext_priv *pmlmeext); ++ ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ sint check_buddy_mlmeinfo_state(_adapter *padapter, u32 state); ++void concurrent_chk_joinbss_done(_adapter *padapter, int join_res); ++#endif //CONFIG_CONCURRENT_MODE ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++void dc_SelectChannel(_adapter *padapter, unsigned char channel); ++void dc_SetBWMode(_adapter *padapter, unsigned short bwmode, unsigned char channel_offset); ++void dc_set_channel_bwmode_disconnect(_adapter *padapter); ++u8 dc_handle_join_request(_adapter *padapter, u8 *ch, u8 *bw, u8 *offset); ++void dc_handle_join_done(_adapter *padapter, u8 join_res); ++sint dc_check_fwstate(_adapter *padapter, sint fw_state); ++u8 dc_handle_site_survey(_adapter *padapter); ++void dc_report_survey_event(_adapter *padapter, union recv_frame *precv_frame); ++void dc_set_channel_bwmode_survey_done(_adapter *padapter); ++void dc_set_ap_channel_bandwidth(_adapter *padapter, u8 channel, u8 channel_offset, u8 bwmode); ++void dc_resume_xmit(_adapter *padapter); ++u8 dc_check_xmit(_adapter *padapter); ++#endif ++ ++int rtw_chk_start_clnt_join(_adapter *padapter, u8 *ch, u8 *bw, u8 *offset); ++int rtw_get_ch_setting_union(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset); ++ ++struct cmd_hdl { ++ uint parmsize; ++ u8 (*h2cfuns)(struct _ADAPTER *padapter, u8 *pbuf); ++}; ++ ++ ++u8 read_macreg_hdl(_adapter *padapter, u8 *pbuf); ++u8 write_macreg_hdl(_adapter *padapter, u8 *pbuf); ++u8 read_bbreg_hdl(_adapter *padapter, u8 *pbuf); ++u8 write_bbreg_hdl(_adapter *padapter, u8 *pbuf); ++u8 read_rfreg_hdl(_adapter *padapter, u8 *pbuf); ++u8 write_rfreg_hdl(_adapter *padapter, u8 *pbuf); ++ ++ ++u8 NULL_hdl(_adapter *padapter, u8 *pbuf); ++u8 join_cmd_hdl(_adapter *padapter, u8 *pbuf); ++u8 disconnect_hdl(_adapter *padapter, u8 *pbuf); ++u8 createbss_hdl(_adapter *padapter, u8 *pbuf); ++u8 setopmode_hdl(_adapter *padapter, u8 *pbuf); ++u8 sitesurvey_cmd_hdl(_adapter *padapter, u8 *pbuf); ++u8 setauth_hdl(_adapter *padapter, u8 *pbuf); ++u8 setkey_hdl(_adapter *padapter, u8 *pbuf); ++u8 set_stakey_hdl(_adapter *padapter, u8 *pbuf); ++u8 set_assocsta_hdl(_adapter *padapter, u8 *pbuf); ++u8 del_assocsta_hdl(_adapter *padapter, u8 *pbuf); ++u8 add_ba_hdl(_adapter *padapter, unsigned char *pbuf); ++ ++u8 mlme_evt_hdl(_adapter *padapter, unsigned char *pbuf); ++u8 h2c_msg_hdl(_adapter *padapter, unsigned char *pbuf); ++u8 tx_beacon_hdl(_adapter *padapter, unsigned char *pbuf); ++u8 set_ch_hdl(_adapter *padapter, u8 *pbuf); ++u8 set_chplan_hdl(_adapter *padapter, unsigned char *pbuf); ++u8 led_blink_hdl(_adapter *padapter, unsigned char *pbuf); ++u8 set_csa_hdl(_adapter *padapter, unsigned char *pbuf); //Kurt: Handling DFS channel switch announcement ie. ++u8 tdls_hdl(_adapter *padapter, unsigned char *pbuf); ++ ++ ++#define GEN_DRV_CMD_HANDLER(size, cmd) {size, &cmd ## _hdl}, ++#define GEN_MLME_EXT_HANDLER(size, cmd) {size, cmd}, ++ ++#ifdef _RTW_CMD_C_ ++ ++struct cmd_hdl wlancmds[] = ++{ ++ GEN_DRV_CMD_HANDLER(0, NULL) /*0*/ ++ GEN_DRV_CMD_HANDLER(0, NULL) ++ GEN_DRV_CMD_HANDLER(0, NULL) ++ GEN_DRV_CMD_HANDLER(0, NULL) ++ GEN_DRV_CMD_HANDLER(0, NULL) ++ GEN_DRV_CMD_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) /*10*/ ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct joinbss_parm), join_cmd_hdl) /*14*/ ++ GEN_MLME_EXT_HANDLER(sizeof (struct disconnect_parm), disconnect_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof (struct createbss_parm), createbss_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof (struct setopmode_parm), setopmode_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof (struct sitesurvey_parm), sitesurvey_cmd_hdl) /*18*/ ++ GEN_MLME_EXT_HANDLER(sizeof (struct setauth_parm), setauth_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof (struct setkey_parm), setkey_hdl) /*20*/ ++ GEN_MLME_EXT_HANDLER(sizeof (struct set_stakey_parm), set_stakey_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof (struct set_assocsta_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct del_assocsta_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct setstapwrstate_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct setbasicrate_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct getbasicrate_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct setdatarate_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct getdatarate_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct setphyinfo_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct getphyinfo_parm), NULL) /*30*/ ++ GEN_MLME_EXT_HANDLER(sizeof (struct setphy_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct getphy_parm), NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) /*40*/ ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(sizeof(struct addBaReq_parm), add_ba_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof(struct set_ch_parm), set_ch_hdl) /* 46 */ ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) /*50*/ ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(sizeof(struct Tx_Beacon_param), tx_beacon_hdl) /*55*/ ++ ++ GEN_MLME_EXT_HANDLER(0, mlme_evt_hdl) /*56*/ ++ GEN_MLME_EXT_HANDLER(0, rtw_drvextra_cmd_hdl) /*57*/ ++ ++ GEN_MLME_EXT_HANDLER(0, h2c_msg_hdl) /*58*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelPlan_param), set_chplan_hdl) /*59*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct LedBlink_param), led_blink_hdl) /*60*/ ++ ++ GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelSwitch_param), set_csa_hdl) /*61*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct TDLSoption_param), tdls_hdl) /*62*/ ++}; ++ ++#endif ++ ++struct C2HEvent_Header ++{ ++ ++#ifdef CONFIG_LITTLE_ENDIAN ++ ++ unsigned int len:16; ++ unsigned int ID:8; ++ unsigned int seq:8; ++ ++#elif defined(CONFIG_BIG_ENDIAN) ++ ++ unsigned int seq:8; ++ unsigned int ID:8; ++ unsigned int len:16; ++ ++#else ++ ++# error "Must be LITTLE or BIG Endian" ++ ++#endif ++ ++ unsigned int rsvd; ++ ++}; ++ ++void rtw_dummy_event_callback(_adapter *adapter , u8 *pbuf); ++void rtw_fwdbg_event_callback(_adapter *adapter , u8 *pbuf); ++ ++enum rtw_c2h_event ++{ ++ GEN_EVT_CODE(_Read_MACREG)=0, /*0*/ ++ GEN_EVT_CODE(_Read_BBREG), ++ GEN_EVT_CODE(_Read_RFREG), ++ GEN_EVT_CODE(_Read_EEPROM), ++ GEN_EVT_CODE(_Read_EFUSE), ++ GEN_EVT_CODE(_Read_CAM), /*5*/ ++ GEN_EVT_CODE(_Get_BasicRate), ++ GEN_EVT_CODE(_Get_DataRate), ++ GEN_EVT_CODE(_Survey), /*8*/ ++ GEN_EVT_CODE(_SurveyDone), /*9*/ ++ ++ GEN_EVT_CODE(_JoinBss) , /*10*/ ++ GEN_EVT_CODE(_AddSTA), ++ GEN_EVT_CODE(_DelSTA), ++ GEN_EVT_CODE(_AtimDone) , ++ GEN_EVT_CODE(_TX_Report), ++ GEN_EVT_CODE(_CCX_Report), /*15*/ ++ GEN_EVT_CODE(_DTM_Report), ++ GEN_EVT_CODE(_TX_Rate_Statistics), ++ GEN_EVT_CODE(_C2HLBK), ++ GEN_EVT_CODE(_FWDBG), ++ GEN_EVT_CODE(_C2HFEEDBACK), /*20*/ ++ GEN_EVT_CODE(_ADDBA), ++ GEN_EVT_CODE(_C2HBCN), ++ GEN_EVT_CODE(_ReportPwrState), //filen: only for PCIE, USB ++ GEN_EVT_CODE(_CloseRF), //filen: only for PCIE, work around ASPM ++ MAX_C2HEVT ++}; ++ ++ ++#ifdef _RTW_MLME_EXT_C_ ++ ++static struct fwevent wlanevents[] = ++{ ++ {0, rtw_dummy_event_callback}, /*0*/ ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, &rtw_survey_event_callback}, /*8*/ ++ {sizeof (struct surveydone_event), &rtw_surveydone_event_callback}, /*9*/ ++ ++ {0, &rtw_joinbss_event_callback}, /*10*/ ++ {sizeof(struct stassoc_event), &rtw_stassoc_event_callback}, ++ {sizeof(struct stadel_event), &rtw_stadel_event_callback}, ++ {0, &rtw_atimdone_event_callback}, ++ {0, rtw_dummy_event_callback}, ++ {0, NULL}, /*15*/ ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, rtw_fwdbg_event_callback}, ++ {0, NULL}, /*20*/ ++ {0, NULL}, ++ {0, NULL}, ++ {0, &rtw_cpwm_event_callback}, ++}; ++ ++#endif//_RTL8192C_CMD_C_ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_mp.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_mp.h +new file mode 100644 +index 00000000..9a017a46 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_mp.h +@@ -0,0 +1,771 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTW_MP_H_ ++#define _RTW_MP_H_ ++ ++#ifndef PLATFORM_WINDOWS ++// 00 - Success ++// 11 - Error ++#define STATUS_SUCCESS (0x00000000L) ++#define STATUS_PENDING (0x00000103L) ++ ++#define STATUS_UNSUCCESSFUL (0xC0000001L) ++#define STATUS_INSUFFICIENT_RESOURCES (0xC000009AL) ++#define STATUS_NOT_SUPPORTED (0xC00000BBL) ++ ++#define NDIS_STATUS_SUCCESS ((NDIS_STATUS)STATUS_SUCCESS) ++#define NDIS_STATUS_PENDING ((NDIS_STATUS)STATUS_PENDING) ++#define NDIS_STATUS_NOT_RECOGNIZED ((NDIS_STATUS)0x00010001L) ++#define NDIS_STATUS_NOT_COPIED ((NDIS_STATUS)0x00010002L) ++#define NDIS_STATUS_NOT_ACCEPTED ((NDIS_STATUS)0x00010003L) ++#define NDIS_STATUS_CALL_ACTIVE ((NDIS_STATUS)0x00010007L) ++ ++#define NDIS_STATUS_FAILURE ((NDIS_STATUS)STATUS_UNSUCCESSFUL) ++#define NDIS_STATUS_RESOURCES ((NDIS_STATUS)STATUS_INSUFFICIENT_RESOURCES) ++#define NDIS_STATUS_CLOSING ((NDIS_STATUS)0xC0010002L) ++#define NDIS_STATUS_BAD_VERSION ((NDIS_STATUS)0xC0010004L) ++#define NDIS_STATUS_BAD_CHARACTERISTICS ((NDIS_STATUS)0xC0010005L) ++#define NDIS_STATUS_ADAPTER_NOT_FOUND ((NDIS_STATUS)0xC0010006L) ++#define NDIS_STATUS_OPEN_FAILED ((NDIS_STATUS)0xC0010007L) ++#define NDIS_STATUS_DEVICE_FAILED ((NDIS_STATUS)0xC0010008L) ++#define NDIS_STATUS_MULTICAST_FULL ((NDIS_STATUS)0xC0010009L) ++#define NDIS_STATUS_MULTICAST_EXISTS ((NDIS_STATUS)0xC001000AL) ++#define NDIS_STATUS_MULTICAST_NOT_FOUND ((NDIS_STATUS)0xC001000BL) ++#define NDIS_STATUS_REQUEST_ABORTED ((NDIS_STATUS)0xC001000CL) ++#define NDIS_STATUS_RESET_IN_PROGRESS ((NDIS_STATUS)0xC001000DL) ++#define NDIS_STATUS_CLOSING_INDICATING ((NDIS_STATUS)0xC001000EL) ++#define NDIS_STATUS_NOT_SUPPORTED ((NDIS_STATUS)STATUS_NOT_SUPPORTED) ++#define NDIS_STATUS_INVALID_PACKET ((NDIS_STATUS)0xC001000FL) ++#define NDIS_STATUS_OPEN_LIST_FULL ((NDIS_STATUS)0xC0010010L) ++#define NDIS_STATUS_ADAPTER_NOT_READY ((NDIS_STATUS)0xC0010011L) ++#define NDIS_STATUS_ADAPTER_NOT_OPEN ((NDIS_STATUS)0xC0010012L) ++#define NDIS_STATUS_NOT_INDICATING ((NDIS_STATUS)0xC0010013L) ++#define NDIS_STATUS_INVALID_LENGTH ((NDIS_STATUS)0xC0010014L) ++#define NDIS_STATUS_INVALID_DATA ((NDIS_STATUS)0xC0010015L) ++#define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L) ++#define NDIS_STATUS_INVALID_OID ((NDIS_STATUS)0xC0010017L) ++#define NDIS_STATUS_ADAPTER_REMOVED ((NDIS_STATUS)0xC0010018L) ++#define NDIS_STATUS_UNSUPPORTED_MEDIA ((NDIS_STATUS)0xC0010019L) ++#define NDIS_STATUS_GROUP_ADDRESS_IN_USE ((NDIS_STATUS)0xC001001AL) ++#define NDIS_STATUS_FILE_NOT_FOUND ((NDIS_STATUS)0xC001001BL) ++#define NDIS_STATUS_ERROR_READING_FILE ((NDIS_STATUS)0xC001001CL) ++#define NDIS_STATUS_ALREADY_MAPPED ((NDIS_STATUS)0xC001001DL) ++#define NDIS_STATUS_RESOURCE_CONFLICT ((NDIS_STATUS)0xC001001EL) ++#define NDIS_STATUS_NO_CABLE ((NDIS_STATUS)0xC001001FL) ++ ++#define NDIS_STATUS_INVALID_SAP ((NDIS_STATUS)0xC0010020L) ++#define NDIS_STATUS_SAP_IN_USE ((NDIS_STATUS)0xC0010021L) ++#define NDIS_STATUS_INVALID_ADDRESS ((NDIS_STATUS)0xC0010022L) ++#define NDIS_STATUS_VC_NOT_ACTIVATED ((NDIS_STATUS)0xC0010023L) ++#define NDIS_STATUS_DEST_OUT_OF_ORDER ((NDIS_STATUS)0xC0010024L) // cause 27 ++#define NDIS_STATUS_VC_NOT_AVAILABLE ((NDIS_STATUS)0xC0010025L) // cause 35,45 ++#define NDIS_STATUS_CELLRATE_NOT_AVAILABLE ((NDIS_STATUS)0xC0010026L) // cause 37 ++#define NDIS_STATUS_INCOMPATABLE_QOS ((NDIS_STATUS)0xC0010027L) // cause 49 ++#define NDIS_STATUS_AAL_PARAMS_UNSUPPORTED ((NDIS_STATUS)0xC0010028L) // cause 93 ++#define NDIS_STATUS_NO_ROUTE_TO_DESTINATION ((NDIS_STATUS)0xC0010029L) // cause 3 ++#endif /* #ifndef PLATFORM_WINDOWS */ ++ ++#if 0 ++#define MPT_NOOP 0 ++#define MPT_READ_MAC_1BYTE 1 ++#define MPT_READ_MAC_2BYTE 2 ++#define MPT_READ_MAC_4BYTE 3 ++#define MPT_WRITE_MAC_1BYTE 4 ++#define MPT_WRITE_MAC_2BYTE 5 ++#define MPT_WRITE_MAC_4BYTE 6 ++#define MPT_READ_BB_CCK 7 ++#define MPT_WRITE_BB_CCK 8 ++#define MPT_READ_BB_OFDM 9 ++#define MPT_WRITE_BB_OFDM 10 ++#define MPT_READ_RF 11 ++#define MPT_WRITE_RF 12 ++#define MPT_READ_EEPROM_1BYTE 13 ++#define MPT_WRITE_EEPROM_1BYTE 14 ++#define MPT_READ_EEPROM_2BYTE 15 ++#define MPT_WRITE_EEPROM_2BYTE 16 ++#define MPT_SET_CSTHRESHOLD 21 ++#define MPT_SET_INITGAIN 22 ++#define MPT_SWITCH_BAND 23 ++#define MPT_SWITCH_CHANNEL 24 ++#define MPT_SET_DATARATE 25 ++#define MPT_SWITCH_ANTENNA 26 ++#define MPT_SET_TX_POWER 27 ++#define MPT_SET_CONT_TX 28 ++#define MPT_SET_SINGLE_CARRIER 29 ++#define MPT_SET_CARRIER_SUPPRESSION 30 ++#define MPT_GET_RATE_TABLE 31 ++#define MPT_READ_TSSI 32 ++#define MPT_GET_THERMAL_METER 33 ++#endif ++ ++typedef enum _ANTENNA_PATH{ ++ ANTENNA_NONE = 0x00, ++ ANTENNA_D , ++ ANTENNA_C , ++ ANTENNA_CD , ++ ANTENNA_B , ++ ANTENNA_BD , ++ ANTENNA_BC , ++ ANTENNA_BCD , ++ ANTENNA_A , ++ ANTENNA_AD , ++ ANTENNA_AC , ++ ANTENNA_ACD , ++ ANTENNA_AB , ++ ANTENNA_ABD , ++ ANTENNA_ABC , ++ ANTENNA_ABCD ++} ANTENNA_PATH; ++ ++ ++#define MAX_MP_XMITBUF_SZ 2048 ++#define NR_MP_XMITFRAME 8 ++ ++struct mp_xmit_frame ++{ ++ _list list; ++ ++ struct pkt_attrib attrib; ++ ++ _pkt *pkt; ++ ++ int frame_tag; ++ ++ _adapter *padapter; ++ ++#ifdef CONFIG_USB_HCI ++ ++ //insert urb, irp, and irpcnt info below... ++ //max frag_cnt = 8 ++ ++ u8 *mem_addr; ++ u32 sz[8]; ++ ++#if defined(PLATFORM_OS_XP) || defined(PLATFORM_LINUX) ++ PURB pxmit_urb[8]; ++#endif ++ ++#ifdef PLATFORM_OS_XP ++ PIRP pxmit_irp[8]; ++#endif ++ ++ u8 bpending[8]; ++ sint ac_tag[8]; ++ sint last[8]; ++ uint irpcnt; ++ uint fragcnt; ++#endif /* CONFIG_USB_HCI */ ++ ++ uint mem[(MAX_MP_XMITBUF_SZ >> 2)]; ++}; ++ ++struct mp_wiparam ++{ ++ u32 bcompleted; ++ u32 act_type; ++ u32 io_offset; ++ u32 io_value; ++}; ++ ++typedef void(*wi_act_func)(void* padapter); ++ ++#ifdef PLATFORM_WINDOWS ++struct mp_wi_cntx ++{ ++ u8 bmpdrv_unload; ++ ++ // Work Item ++ NDIS_WORK_ITEM mp_wi; ++ NDIS_EVENT mp_wi_evt; ++ _lock mp_wi_lock; ++ u8 bmp_wi_progress; ++ wi_act_func curractfunc; ++ // Variable needed in each implementation of CurrActFunc. ++ struct mp_wiparam param; ++}; ++#endif ++ ++struct mp_tx ++{ ++ u8 stop; ++ u32 count, sended; ++ u8 payload; ++ struct pkt_attrib attrib; ++ struct tx_desc desc; ++ u8 *pallocated_buf; ++ u8 *buf; ++ u32 buf_size, write_size; ++ _thread_hdl_ PktTxThread; ++}; ++ ++#if defined(CONFIG_RTL8192C) || defined(CONFIG_RTL8192D) || defined(CONFIG_RTL8723A) || defined(CONFIG_RTL8188E) ++#ifdef CONFIG_RTL8192C ++#include ++#endif ++#ifdef CONFIG_RTL8192D ++#include ++#endif ++#ifdef CONFIG_RTL8723A ++#include ++#endif ++#ifdef CONFIG_RTL8188E ++#include ++#endif ++ ++#define MP_MAX_LINES 1000 ++#define MP_MAX_LINES_BYTES 256 ++#define u1Byte u8 ++#define s1Byte s8 ++#define u4Byte u32 ++#define s4Byte s32 ++#define u1Byte u8 ++#define pu1Byte u8* ++ ++#define u2Byte u16 ++#define pu2Byte u16* ++ ++#define u4Byte u32 ++#define pu4Byte u32* ++ ++#define u8Byte u64 ++#define pu8Byte u64* ++ ++#define s1Byte s8 ++#define ps1Byte s8* ++ ++#define s2Byte s16 ++#define ps2Byte s16* ++ ++#define s4Byte s32 ++#define ps4Byte s32* ++ ++#define s8Byte s64 ++#define ps8Byte s64* ++ ++#define UCHAR u8 ++#define USHORT u16 ++#define UINT u32 ++#define ULONG u32 ++#define PULONG u32* ++ ++ ++ ++typedef VOID (*MPT_WORK_ITEM_HANDLER)(IN PVOID Adapter); ++typedef struct _MPT_CONTEXT ++{ ++ // Indicate if we have started Mass Production Test. ++ BOOLEAN bMassProdTest; ++ ++ // Indicate if the driver is unloading or unloaded. ++ BOOLEAN bMptDrvUnload; ++ ++ _sema MPh2c_Sema; ++ _timer MPh2c_timeout_timer; ++// Event used to sync H2c for BT control ++ ++ BOOLEAN MptH2cRspEvent; ++ BOOLEAN MptBtC2hEvent; ++ BOOLEAN bMPh2c_timeout; ++ ++ /* 8190 PCI does not support NDIS_WORK_ITEM. */ ++ // Work Item for Mass Production Test. ++ //NDIS_WORK_ITEM MptWorkItem; ++// RT_WORK_ITEM MptWorkItem; ++ // Event used to sync the case unloading driver and MptWorkItem is still in progress. ++// NDIS_EVENT MptWorkItemEvent; ++ // To protect the following variables. ++// NDIS_SPIN_LOCK MptWorkItemSpinLock; ++ // Indicate a MptWorkItem is scheduled and not yet finished. ++ BOOLEAN bMptWorkItemInProgress; ++ // An instance which implements function and context of MptWorkItem. ++ MPT_WORK_ITEM_HANDLER CurrMptAct; ++ ++ // 1=Start, 0=Stop from UI. ++ ULONG MptTestStart; ++ // _TEST_MODE, defined in MPT_Req2.h ++ ULONG MptTestItem; ++ // Variable needed in each implementation of CurrMptAct. ++ ULONG MptActType; // Type of action performed in CurrMptAct. ++ // The Offset of IO operation is depend of MptActType. ++ ULONG MptIoOffset; ++ // The Value of IO operation is depend of MptActType. ++ ULONG MptIoValue; ++ // The RfPath of IO operation is depend of MptActType. ++ ULONG MptRfPath; ++ ++ WIRELESS_MODE MptWirelessModeToSw; // Wireless mode to switch. ++ u8 MptChannelToSw; // Channel to switch. ++ u8 MptInitGainToSet; // Initial gain to set. ++ //ULONG bMptAntennaA; // TRUE if we want to use antenna A. ++ ULONG MptBandWidth; // bandwidth to switch. ++ ULONG MptRateIndex; // rate index. ++ // Register value kept for Single Carrier Tx test. ++ u8 btMpCckTxPower; ++ // Register value kept for Single Carrier Tx test. ++ u8 btMpOfdmTxPower; ++ // For MP Tx Power index ++ u8 TxPwrLevel[2]; // rf-A, rf-B ++ ++ // Content of RCR Regsiter for Mass Production Test. ++ ULONG MptRCR; ++ // TRUE if we only receive packets with specific pattern. ++ BOOLEAN bMptFilterPattern; ++ // Rx OK count, statistics used in Mass Production Test. ++ ULONG MptRxOkCnt; ++ // Rx CRC32 error count, statistics used in Mass Production Test. ++ ULONG MptRxCrcErrCnt; ++ ++ BOOLEAN bCckContTx; // TRUE if we are in CCK Continuous Tx test. ++ BOOLEAN bOfdmContTx; // TRUE if we are in OFDM Continuous Tx test. ++ BOOLEAN bStartContTx; // TRUE if we have start Continuous Tx test. ++ // TRUE if we are in Single Carrier Tx test. ++ BOOLEAN bSingleCarrier; ++ // TRUE if we are in Carrier Suppression Tx Test. ++ BOOLEAN bCarrierSuppression; ++ //TRUE if we are in Single Tone Tx test. ++ BOOLEAN bSingleTone; ++ ++ // ACK counter asked by K.Y.. ++ BOOLEAN bMptEnableAckCounter; ++ ULONG MptAckCounter; ++ ++ // SD3 Willis For 8192S to save 1T/2T RF table for ACUT Only fro ACUT delete later ~~~! ++ //s1Byte BufOfLines[2][MAX_LINES_HWCONFIG_TXT][MAX_BYTES_LINE_HWCONFIG_TXT]; ++ //s1Byte BufOfLines[2][MP_MAX_LINES][MP_MAX_LINES_BYTES]; ++ //s4Byte RfReadLine[2]; ++ ++ u8 APK_bound[2]; //for APK path A/path B ++ BOOLEAN bMptIndexEven; ++ ++ u8 backup0xc50; ++ u8 backup0xc58; ++ u8 backup0xc30; ++ u8 backup0x52_RF_A; ++ u8 backup0x52_RF_B; ++ ++ u1Byte h2cReqNum; ++ u1Byte c2hBuf[20]; ++ ++ u1Byte btInBuf[100]; ++ ULONG mptOutLen; ++ u1Byte mptOutBuf[100]; ++ ++}MPT_CONTEXT, *PMPT_CONTEXT; ++#endif ++//#endif ++ ++//#define RTPRIV_IOCTL_MP ( SIOCIWFIRSTPRIV + 0x17) ++enum { ++ WRITE_REG = 1, ++ READ_REG, ++ WRITE_RF, ++ READ_RF, ++ MP_START, ++ MP_STOP, ++ MP_RATE, ++ MP_CHANNEL, ++ MP_BANDWIDTH, ++ MP_TXPOWER, ++ MP_ANT_TX, ++ MP_ANT_RX, ++ MP_CTX, ++ MP_QUERY, ++ MP_ARX, ++ MP_PSD, ++ MP_PWRTRK, ++ MP_THER, ++ MP_IOCTL, ++ EFUSE_GET, ++ EFUSE_SET, ++ MP_RESET_STATS, ++ MP_DUMP, ++ MP_PHYPARA, ++ MP_SetRFPathSwh, ++ MP_QueryDrvStats, ++ MP_SetBT, ++ CTA_TEST, ++ MP_DISABLE_BT_COEXIST, ++ MP_PwrCtlDM, ++#ifdef CONFIG_WOWLAN ++ MP_WOW_ENABLE, ++#endif ++ MP_NULL, ++}; ++ ++struct mp_priv ++{ ++ _adapter *papdater; ++ ++ //Testing Flag ++ u32 mode;//0 for normal type packet, 1 for loopback packet (16bytes TXCMD) ++ ++ u32 prev_fw_state; ++ ++ //OID cmd handler ++ struct mp_wiparam workparam; ++// u8 act_in_progress; ++ ++ //Tx Section ++ u8 TID; ++ u32 tx_pktcount; ++ struct mp_tx tx; ++ ++ //Rx Section ++ u32 rx_pktcount; ++ u32 rx_crcerrpktcount; ++ u32 rx_pktloss; ++ ++ struct recv_stat rxstat; ++ ++ //RF/BB relative ++ u8 channel; ++ u8 bandwidth; ++ u8 prime_channel_offset; ++ u8 txpoweridx; ++ u8 txpoweridx_b; ++ u8 rateidx; ++ u32 preamble; ++// u8 modem; ++ u32 CrystalCap; ++// u32 curr_crystalcap; ++ ++ u16 antenna_tx; ++ u16 antenna_rx; ++// u8 curr_rfpath; ++ ++ u8 check_mp_pkt; ++ ++ u8 bSetTxPower; ++// uint ForcedDataRate; ++ ++ struct wlan_network mp_network; ++ NDIS_802_11_MAC_ADDRESS network_macaddr; ++ ++#ifdef PLATFORM_WINDOWS ++ u32 rx_testcnt; ++ u32 rx_testcnt1; ++ u32 rx_testcnt2; ++ u32 tx_testcnt; ++ u32 tx_testcnt1; ++ ++ struct mp_wi_cntx wi_cntx; ++ ++ u8 h2c_result; ++ u8 h2c_seqnum; ++ u16 h2c_cmdcode; ++ u8 h2c_resp_parambuf[512]; ++ _lock h2c_lock; ++ _lock wkitm_lock; ++ u32 h2c_cmdcnt; ++ NDIS_EVENT h2c_cmd_evt; ++ NDIS_EVENT c2h_set; ++ NDIS_EVENT h2c_clr; ++ NDIS_EVENT cpwm_int; ++ ++ NDIS_EVENT scsir_full_evt; ++ NDIS_EVENT scsiw_empty_evt; ++#endif ++ ++ u8 *pallocated_mp_xmitframe_buf; ++ u8 *pmp_xmtframe_buf; ++ _queue free_mp_xmitqueue; ++ u32 free_mp_xmitframe_cnt; ++ ++ MPT_CONTEXT MptCtx; ++}; ++ ++typedef struct _IOCMD_STRUCT_ { ++ u8 cmdclass; ++ u16 value; ++ u8 index; ++}IOCMD_STRUCT; ++ ++struct rf_reg_param { ++ u32 path; ++ u32 offset; ++ u32 value; ++}; ++ ++struct bb_reg_param { ++ u32 offset; ++ u32 value; ++}; ++//======================================================================= ++ ++#define LOWER _TRUE ++#define RAISE _FALSE ++ ++/* Hardware Registers */ ++#if 0 ++#if 0 ++#define IOCMD_CTRL_REG 0x102502C0 ++#define IOCMD_DATA_REG 0x102502C4 ++#else ++#define IOCMD_CTRL_REG 0x10250370 ++#define IOCMD_DATA_REG 0x10250374 ++#endif ++ ++#define IOCMD_GET_THERMAL_METER 0xFD000028 ++ ++#define IOCMD_CLASS_BB_RF 0xF0 ++#define IOCMD_BB_READ_IDX 0x00 ++#define IOCMD_BB_WRITE_IDX 0x01 ++#define IOCMD_RF_READ_IDX 0x02 ++#define IOCMD_RF_WRIT_IDX 0x03 ++#endif ++#define BB_REG_BASE_ADDR 0x800 ++ ++/* MP variables */ ++#if 0 ++#define _2MAC_MODE_ 0 ++#define _LOOPBOOK_MODE_ 1 ++#endif ++typedef enum _MP_MODE_ { ++ MP_OFF, ++ MP_ON, ++ MP_ERR, ++ MP_CONTINUOUS_TX, ++ MP_SINGLE_CARRIER_TX, ++ MP_CARRIER_SUPPRISSION_TX, ++ MP_SINGLE_TONE_TX, ++ MP_PACKET_TX, ++ MP_PACKET_RX ++} MP_MODE; ++ ++ ++#define MAX_RF_PATH_NUMS RF_PATH_MAX ++ ++ ++extern u8 mpdatarate[NumRates]; ++ ++/* MP set force data rate base on the definition. */ ++typedef enum _MPT_RATE_INDEX ++{ ++ /* CCK rate. */ ++ MPT_RATE_1M, /* 0 */ ++ MPT_RATE_2M, ++ MPT_RATE_55M, ++ MPT_RATE_11M, /* 3 */ ++ ++ /* OFDM rate. */ ++ MPT_RATE_6M, /* 4 */ ++ MPT_RATE_9M, ++ MPT_RATE_12M, ++ MPT_RATE_18M, ++ MPT_RATE_24M, ++ MPT_RATE_36M, ++ MPT_RATE_48M, ++ MPT_RATE_54M, /* 11 */ ++ ++ /* HT rate. */ ++ MPT_RATE_MCS0, /* 12 */ ++ MPT_RATE_MCS1, ++ MPT_RATE_MCS2, ++ MPT_RATE_MCS3, ++ MPT_RATE_MCS4, ++ MPT_RATE_MCS5, ++ MPT_RATE_MCS6, ++ MPT_RATE_MCS7, /* 19 */ ++ MPT_RATE_MCS8, ++ MPT_RATE_MCS9, ++ MPT_RATE_MCS10, ++ MPT_RATE_MCS11, ++ MPT_RATE_MCS12, ++ MPT_RATE_MCS13, ++ MPT_RATE_MCS14, ++ MPT_RATE_MCS15, /* 27 */ ++ MPT_RATE_LAST ++}MPT_RATE_E, *PMPT_RATE_E; ++ ++#if 0 ++// Represent Channel Width in HT Capabilities ++typedef enum _HT_CHANNEL_WIDTH { ++ HT_CHANNEL_WIDTH_20 = 0, ++ HT_CHANNEL_WIDTH_40 = 1, ++}HT_CHANNEL_WIDTH, *PHT_CHANNEL_WIDTH; ++#endif ++ ++#define MAX_TX_PWR_INDEX_N_MODE 64 // 0x3F ++ ++typedef enum _POWER_MODE_ { ++ POWER_LOW = 0, ++ POWER_NORMAL ++}POWER_MODE; ++ ++ ++#define RX_PKT_BROADCAST 1 ++#define RX_PKT_DEST_ADDR 2 ++#define RX_PKT_PHY_MATCH 3 ++ ++#if 0 ++#define RPTMaxCount 0x000FFFFF; ++ ++// parameter 1 : BitMask ++// bit 0 : OFDM PPDU ++// bit 1 : OFDM False Alarm ++// bit 2 : OFDM MPDU OK ++// bit 3 : OFDM MPDU Fail ++// bit 4 : CCK PPDU ++// bit 5 : CCK False Alarm ++// bit 6 : CCK MPDU ok ++// bit 7 : CCK MPDU fail ++// bit 8 : HT PPDU counter ++// bit 9 : HT false alarm ++// bit 10 : HT MPDU total ++// bit 11 : HT MPDU OK ++// bit 12 : HT MPDU fail ++// bit 15 : RX full drop ++typedef enum _RXPHY_BITMASK_ ++{ ++ OFDM_PPDU_BIT = 0, ++ OFDM_FALSE_BIT, ++ OFDM_MPDU_OK_BIT, ++ OFDM_MPDU_FAIL_BIT, ++ CCK_PPDU_BIT, ++ CCK_FALSE_BIT, ++ CCK_MPDU_OK_BIT, ++ CCK_MPDU_FAIL_BIT, ++ HT_PPDU_BIT, ++ HT_FALSE_BIT, ++ HT_MPDU_BIT, ++ HT_MPDU_OK_BIT, ++ HT_MPDU_FAIL_BIT, ++} RXPHY_BITMASK; ++#endif ++ ++typedef enum _ENCRY_CTRL_STATE_ { ++ HW_CONTROL, //hw encryption& decryption ++ SW_CONTROL, //sw encryption& decryption ++ HW_ENCRY_SW_DECRY, //hw encryption & sw decryption ++ SW_ENCRY_HW_DECRY //sw encryption & hw decryption ++}ENCRY_CTRL_STATE; ++ ++#define Mac_OFDM_OK 0x00000000 ++#define Mac_OFDM_Fail 0x10000000 ++#define Mac_OFDM_FasleAlarm 0x20000000 ++#define Mac_CCK_OK 0x30000000 ++#define Mac_CCK_Fail 0x40000000 ++#define Mac_CCK_FasleAlarm 0x50000000 ++#define Mac_HT_OK 0x60000000 ++#define Mac_HT_Fail 0x70000000 ++#define Mac_HT_FasleAlarm 0x90000000 ++#define Mac_DropPacket 0xA0000000 ++ ++//======================================================================= ++//extern struct mp_xmit_frame *alloc_mp_xmitframe(struct mp_priv *pmp_priv); ++//extern int free_mp_xmitframe(struct xmit_priv *pxmitpriv, struct mp_xmit_frame *pmp_xmitframe); ++ ++extern s32 init_mp_priv(PADAPTER padapter); ++extern void free_mp_priv(struct mp_priv *pmp_priv); ++extern s32 MPT_InitializeAdapter(PADAPTER padapter, u8 Channel); ++extern void MPT_DeInitAdapter(PADAPTER padapter); ++extern s32 mp_start_test(PADAPTER padapter); ++extern void mp_stop_test(PADAPTER padapter); ++ ++//======================================================================= ++//extern void IQCalibrateBcut(PADAPTER pAdapter); ++ ++//extern u32 bb_reg_read(PADAPTER Adapter, u16 offset); ++//extern u8 bb_reg_write(PADAPTER Adapter, u16 offset, u32 value); ++//extern u32 rf_reg_read(PADAPTER Adapter, u8 path, u8 offset); ++//extern u8 rf_reg_write(PADAPTER Adapter, u8 path, u8 offset, u32 value); ++ ++//extern u32 get_bb_reg(PADAPTER Adapter, u16 offset, u32 bitmask); ++//extern u8 set_bb_reg(PADAPTER Adapter, u16 offset, u32 bitmask, u32 value); ++//extern u32 get_rf_reg(PADAPTER Adapter, u8 path, u8 offset, u32 bitmask); ++//extern u8 set_rf_reg(PADAPTER Adapter, u8 path, u8 offset, u32 bitmask, u32 value); ++ ++extern u32 _read_rfreg(PADAPTER padapter, u8 rfpath, u32 addr, u32 bitmask); ++extern void _write_rfreg(PADAPTER padapter, u8 rfpath, u32 addr, u32 bitmask, u32 val); ++ ++extern u32 read_macreg(_adapter *padapter, u32 addr, u32 sz); ++extern void write_macreg(_adapter *padapter, u32 addr, u32 val, u32 sz); ++extern u32 read_bbreg(_adapter *padapter, u32 addr, u32 bitmask); ++extern void write_bbreg(_adapter *padapter, u32 addr, u32 bitmask, u32 val); ++extern u32 read_rfreg(PADAPTER padapter, u8 rfpath, u32 addr); ++extern void write_rfreg(PADAPTER padapter, u8 rfpath, u32 addr, u32 val); ++ ++extern void SetChannel(PADAPTER pAdapter); ++extern void SetBandwidth(PADAPTER pAdapter); ++extern void SetTxPower(PADAPTER pAdapter); ++extern void SetAntennaPathPower(PADAPTER pAdapter); ++//extern void SetTxAGCOffset(PADAPTER pAdapter, u32 ulTxAGCOffset); ++extern void SetDataRate(PADAPTER pAdapter); ++ ++extern void SetAntenna(PADAPTER pAdapter); ++ ++//extern void SetCrystalCap(PADAPTER pAdapter); ++ ++extern s32 SetThermalMeter(PADAPTER pAdapter, u8 target_ther); ++extern void GetThermalMeter(PADAPTER pAdapter, u8 *value); ++ ++extern void SetContinuousTx(PADAPTER pAdapter, u8 bStart); ++extern void SetSingleCarrierTx(PADAPTER pAdapter, u8 bStart); ++extern void SetSingleToneTx(PADAPTER pAdapter, u8 bStart); ++extern void SetCarrierSuppressionTx(PADAPTER pAdapter, u8 bStart); ++extern void PhySetTxPowerLevel(PADAPTER pAdapter); ++ ++extern void fill_txdesc_for_mp(PADAPTER padapter, struct tx_desc *ptxdesc); ++extern void SetPacketTx(PADAPTER padapter); ++extern void SetPacketRx(PADAPTER pAdapter, u8 bStartRx); ++ ++extern void ResetPhyRxPktCount(PADAPTER pAdapter); ++extern u32 GetPhyRxPktReceived(PADAPTER pAdapter); ++extern u32 GetPhyRxPktCRC32Error(PADAPTER pAdapter); ++ ++extern s32 SetPowerTracking(PADAPTER padapter, u8 enable); ++extern void GetPowerTracking(PADAPTER padapter, u8 *enable); ++ ++extern u32 mp_query_psd(PADAPTER pAdapter, u8 *data); ++ ++ ++extern void Hal_SetAntenna(PADAPTER pAdapter); ++extern void Hal_SetBandwidth(PADAPTER pAdapter); ++ ++extern void Hal_SetTxPower(PADAPTER pAdapter); ++extern void Hal_SetCarrierSuppressionTx(PADAPTER pAdapter, u8 bStart); ++extern void Hal_SetSingleToneTx ( PADAPTER pAdapter , u8 bStart ); ++extern void Hal_SetSingleCarrierTx (PADAPTER pAdapter, u8 bStart); ++extern void Hal_SetContinuousTx (PADAPTER pAdapter, u8 bStart); ++extern void Hal_SetBandwidth(PADAPTER pAdapter); ++ ++extern void Hal_SetDataRate(PADAPTER pAdapter); ++extern void Hal_SetChannel(PADAPTER pAdapter); ++extern void Hal_SetAntennaPathPower(PADAPTER pAdapter); ++extern s32 Hal_SetThermalMeter(PADAPTER pAdapter, u8 target_ther); ++extern s32 Hal_SetPowerTracking(PADAPTER padapter, u8 enable); ++extern void Hal_GetPowerTracking(PADAPTER padapter, u8 * enable); ++extern void Hal_GetThermalMeter(PADAPTER pAdapter, u8 *value); ++extern void Hal_mpt_SwitchRfSetting(PADAPTER pAdapter); ++extern void Hal_MPT_CCKTxPowerAdjust(PADAPTER Adapter, BOOLEAN bInCH14); ++extern void Hal_MPT_CCKTxPowerAdjustbyIndex(PADAPTER pAdapter, BOOLEAN beven); ++extern void Hal_SetCCKTxPower(PADAPTER pAdapter, u8 * TxPower); ++extern void Hal_SetOFDMTxPower(PADAPTER pAdapter, u8 * TxPower); ++extern void Hal_TriggerRFThermalMeter(PADAPTER pAdapter); ++extern u8 Hal_ReadRFThermalMeter(PADAPTER pAdapter); ++extern void Hal_SetCCKContinuousTx(PADAPTER pAdapter, u8 bStart); ++extern void Hal_SetOFDMContinuousTx(PADAPTER pAdapter, u8 bStart); ++extern void Hal_ProSetCrystalCap (PADAPTER pAdapter , u32 CrystalCapVal); ++extern void _rtw_mp_xmit_priv(struct xmit_priv *pxmitpriv); ++extern void MP_PHY_SetRFPathSwitch(PADAPTER pAdapter ,BOOLEAN bMain); ++extern void MPT_PwrCtlDM(PADAPTER padapter, u32 bstart); ++ ++#endif //_RTW_MP_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_mp_ioctl.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_mp_ioctl.h +new file mode 100644 +index 00000000..962bc38e +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_mp_ioctl.h +@@ -0,0 +1,596 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTW_MP_IOCTL_H_ ++#define _RTW_MP_IOCTL_H_ ++ ++//#include ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if 0 ++#define TESTFWCMDNUMBER 1000000 ++#define TEST_H2CINT_WAIT_TIME 500 ++#define TEST_C2HINT_WAIT_TIME 500 ++#define HCI_TEST_SYSCFG_HWMASK 1 ++#define _BUSCLK_40M (4 << 2) ++#endif ++//------------------------------------------------------------------------------ ++typedef struct CFG_DBG_MSG_STRUCT { ++ u32 DebugLevel; ++ u32 DebugComponent_H32; ++ u32 DebugComponent_L32; ++}CFG_DBG_MSG_STRUCT,*PCFG_DBG_MSG_STRUCT; ++ ++typedef struct _RW_REG { ++ u32 offset; ++ u32 width; ++ u32 value; ++}mp_rw_reg,RW_Reg, *pRW_Reg; ++ ++//for OID_RT_PRO_READ16_EEPROM & OID_RT_PRO_WRITE16_EEPROM ++typedef struct _EEPROM_RW_PARAM { ++ u32 offset; ++ u16 value; ++}eeprom_rw_param,EEPROM_RWParam, *pEEPROM_RWParam; ++ ++typedef struct _EFUSE_ACCESS_STRUCT_ { ++ u16 start_addr; ++ u16 cnts; ++ u8 data[0]; ++}EFUSE_ACCESS_STRUCT, *PEFUSE_ACCESS_STRUCT; ++ ++typedef struct _BURST_RW_REG { ++ u32 offset; ++ u32 len; ++ u8 Data[256]; ++}burst_rw_reg,Burst_RW_Reg, *pBurst_RW_Reg; ++ ++typedef struct _USB_VendorReq{ ++ u8 bRequest; ++ u16 wValue; ++ u16 wIndex; ++ u16 wLength; ++ u8 u8Dir;//0:OUT, 1:IN ++ u8 u8InData; ++}usb_vendor_req, USB_VendorReq, *pUSB_VendorReq; ++ ++typedef struct _DR_VARIABLE_STRUCT_ { ++ u8 offset; ++ u32 variable; ++}DR_VARIABLE_STRUCT; ++ ++//int mp_start_joinbss(_adapter *padapter, NDIS_802_11_SSID *pssid); ++ ++//void _irqlevel_changed_(_irqL *irqlevel, /*BOOLEAN*/unsigned char bLower); ++#ifdef PLATFORM_OS_XP ++static void _irqlevel_changed_(_irqL *irqlevel, u8 bLower) ++{ ++ ++ if (bLower == LOWER) { ++ *irqlevel = KeGetCurrentIrql(); ++ ++ if (*irqlevel > PASSIVE_LEVEL) { ++ KeLowerIrql(PASSIVE_LEVEL); ++ } ++ } else { ++ if (KeGetCurrentIrql() == PASSIVE_LEVEL) { ++ KeRaiseIrql(DISPATCH_LEVEL, irqlevel); ++ } ++ } ++ ++} ++#else ++#define _irqlevel_changed_(a,b) ++#endif ++ ++//oid_rtl_seg_81_80_00 ++NDIS_STATUS oid_rt_pro_set_data_rate_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_start_test_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_stop_test_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_set_channel_direct_call_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_set_antenna_bb_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_set_tx_power_control_hdl(struct oid_par_priv* poid_par_priv); ++//oid_rtl_seg_81_80_20 ++NDIS_STATUS oid_rt_pro_query_tx_packet_sent_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_query_rx_packet_received_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_query_rx_packet_crc32_error_hdl(struct oid_par_priv* poid_par_priv); ++ ++NDIS_STATUS oid_rt_pro_reset_tx_packet_sent_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_reset_rx_packet_received_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_set_modulation_hdl(struct oid_par_priv* poid_par_priv); ++ ++NDIS_STATUS oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv* poid_par_priv); ++ ++ ++//oid_rtl_seg_81_87 ++NDIS_STATUS oid_rt_pro_write_bb_reg_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_read_bb_reg_hdl(struct oid_par_priv* poid_par_priv); ++ ++NDIS_STATUS oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv* poid_par_priv); ++ ++ ++//oid_rtl_seg_81_85 ++NDIS_STATUS oid_rt_wireless_mode_hdl(struct oid_par_priv* poid_par_priv); ++ ++ ++// oid_rtl_seg_87_11_00 ++NDIS_STATUS oid_rt_pro8711_join_bss_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_read_register_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_write_register_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_burst_read_register_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_burst_write_register_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_write_txcmd_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_read16_eeprom_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_write16_eeprom_hdl (struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro8711_wi_poll_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro8711_pkt_loss_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_rd_attrib_mem_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_wr_attrib_mem_hdl (struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_set_rf_intfs_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_poll_rx_status_hdl(struct oid_par_priv* poid_par_priv); ++// oid_rtl_seg_87_11_20 ++NDIS_STATUS oid_rt_pro_cfg_debug_message_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_set_data_rate_ex_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_set_basic_rate_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_read_tssi_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_set_power_tracking_hdl(struct oid_par_priv* poid_par_priv); ++//oid_rtl_seg_87_11_50 ++NDIS_STATUS oid_rt_pro_qry_pwrstate_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_set_pwrstate_hdl(struct oid_par_priv* poid_par_priv); ++//oid_rtl_seg_87_11_F0 ++NDIS_STATUS oid_rt_pro_h2c_set_rate_table_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_h2c_get_rate_table_hdl(struct oid_par_priv* poid_par_priv); ++ ++ ++//oid_rtl_seg_87_12_00 ++NDIS_STATUS oid_rt_pro_encryption_ctrl_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_add_sta_info_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_dele_sta_info_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_query_dr_variable_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_rx_packet_type_hdl(struct oid_par_priv* poid_par_priv); ++ ++NDIS_STATUS oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_pro_rw_efuse_pgpkt_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_get_efuse_current_size_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv); ++NDIS_STATUS oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv); ++ ++NDIS_STATUS oid_rt_set_bandwidth_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_set_crystal_cap_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_set_rx_packet_type_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_efuse_max_size_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_pro_set_tx_agc_offset_hdl(struct oid_par_priv* poid_par_priv); ++ ++NDIS_STATUS oid_rt_pro_set_pkt_test_mode_hdl(struct oid_par_priv* poid_par_priv); ++ ++NDIS_STATUS oid_rt_get_thermal_meter_hdl(struct oid_par_priv* poid_par_priv); ++ ++NDIS_STATUS oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv* poid_par_priv); ++NDIS_STATUS oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv* poid_par_priv); ++ ++NDIS_STATUS oid_rt_set_power_down_hdl(struct oid_par_priv* poid_par_priv); ++ ++NDIS_STATUS oid_rt_get_power_mode_hdl(struct oid_par_priv* poid_par_priv); ++ ++NDIS_STATUS oid_rt_pro_trigger_gpio_hdl(struct oid_par_priv *poid_par_priv); ++ ++#ifdef _RTW_MP_IOCTL_C_ ++ ++const struct oid_obj_priv oid_rtl_seg_81_80_00[] = ++{ ++ {1, &oid_null_function}, //0x00 OID_RT_PRO_RESET_DUT ++ {1, &oid_rt_pro_set_data_rate_hdl}, //0x01 ++ {1, &oid_rt_pro_start_test_hdl}, //0x02 ++ {1, &oid_rt_pro_stop_test_hdl}, //0x03 ++ {1, &oid_null_function}, //0x04 OID_RT_PRO_SET_PREAMBLE ++ {1, &oid_null_function}, //0x05 OID_RT_PRO_SET_SCRAMBLER ++ {1, &oid_null_function}, //0x06 OID_RT_PRO_SET_FILTER_BB ++ {1, &oid_null_function}, //0x07 OID_RT_PRO_SET_MANUAL_DIVERSITY_BB ++ {1, &oid_rt_pro_set_channel_direct_call_hdl}, //0x08 ++ {1, &oid_null_function}, //0x09 OID_RT_PRO_SET_SLEEP_MODE_DIRECT_CALL ++ {1, &oid_null_function}, //0x0A OID_RT_PRO_SET_WAKE_MODE_DIRECT_CALL ++ {1, &oid_rt_pro_set_continuous_tx_hdl}, //0x0B OID_RT_PRO_SET_TX_CONTINUOUS_DIRECT_CALL ++ {1, &oid_rt_pro_set_single_carrier_tx_hdl}, //0x0C OID_RT_PRO_SET_SINGLE_CARRIER_TX_CONTINUOUS ++ {1, &oid_null_function}, //0x0D OID_RT_PRO_SET_TX_ANTENNA_BB ++ {1, &oid_rt_pro_set_antenna_bb_hdl}, //0x0E ++ {1, &oid_null_function}, //0x0F OID_RT_PRO_SET_CR_SCRAMBLER ++ {1, &oid_null_function}, //0x10 OID_RT_PRO_SET_CR_NEW_FILTER ++ {1, &oid_rt_pro_set_tx_power_control_hdl}, //0x11 OID_RT_PRO_SET_TX_POWER_CONTROL ++ {1, &oid_null_function}, //0x12 OID_RT_PRO_SET_CR_TX_CONFIG ++ {1, &oid_null_function}, //0x13 OID_RT_PRO_GET_TX_POWER_CONTROL ++ {1, &oid_null_function}, //0x14 OID_RT_PRO_GET_CR_SIGNAL_QUALITY ++ {1, &oid_null_function}, //0x15 OID_RT_PRO_SET_CR_SETPOINT ++ {1, &oid_null_function}, //0x16 OID_RT_PRO_SET_INTEGRATOR ++ {1, &oid_null_function}, //0x17 OID_RT_PRO_SET_SIGNAL_QUALITY ++ {1, &oid_null_function}, //0x18 OID_RT_PRO_GET_INTEGRATOR ++ {1, &oid_null_function}, //0x19 OID_RT_PRO_GET_SIGNAL_QUALITY ++ {1, &oid_null_function}, //0x1A OID_RT_PRO_QUERY_EEPROM_TYPE ++ {1, &oid_null_function}, //0x1B OID_RT_PRO_WRITE_MAC_ADDRESS ++ {1, &oid_null_function}, //0x1C OID_RT_PRO_READ_MAC_ADDRESS ++ {1, &oid_null_function}, //0x1D OID_RT_PRO_WRITE_CIS_DATA ++ {1, &oid_null_function}, //0x1E OID_RT_PRO_READ_CIS_DATA ++ {1, &oid_null_function} //0x1F OID_RT_PRO_WRITE_POWER_CONTROL ++ ++}; ++ ++const struct oid_obj_priv oid_rtl_seg_81_80_20[] = ++{ ++ {1, &oid_null_function}, //0x20 OID_RT_PRO_READ_POWER_CONTROL ++ {1, &oid_null_function}, //0x21 OID_RT_PRO_WRITE_EEPROM ++ {1, &oid_null_function}, //0x22 OID_RT_PRO_READ_EEPROM ++ {1, &oid_rt_pro_reset_tx_packet_sent_hdl}, //0x23 ++ {1, &oid_rt_pro_query_tx_packet_sent_hdl}, //0x24 ++ {1, &oid_rt_pro_reset_rx_packet_received_hdl}, //0x25 ++ {1, &oid_rt_pro_query_rx_packet_received_hdl}, //0x26 ++ {1, &oid_rt_pro_query_rx_packet_crc32_error_hdl}, //0x27 ++ {1, &oid_null_function}, //0x28 OID_RT_PRO_QUERY_CURRENT_ADDRESS ++ {1, &oid_null_function}, //0x29 OID_RT_PRO_QUERY_PERMANENT_ADDRESS ++ {1, &oid_null_function}, //0x2A OID_RT_PRO_SET_PHILIPS_RF_PARAMETERS ++ {1, &oid_rt_pro_set_carrier_suppression_tx_hdl},//0x2B OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX ++ {1, &oid_null_function}, //0x2C OID_RT_PRO_RECEIVE_PACKET ++ {1, &oid_null_function}, //0x2D OID_RT_PRO_WRITE_EEPROM_BYTE ++ {1, &oid_null_function}, //0x2E OID_RT_PRO_READ_EEPROM_BYTE ++ {1, &oid_rt_pro_set_modulation_hdl} //0x2F ++ ++}; ++ ++const struct oid_obj_priv oid_rtl_seg_81_80_40[] = ++{ ++ {1, &oid_null_function}, //0x40 ++ {1, &oid_null_function}, //0x41 ++ {1, &oid_null_function}, //0x42 ++ {1, &oid_rt_pro_set_single_tone_tx_hdl}, //0x43 ++ {1, &oid_null_function}, //0x44 ++ {1, &oid_null_function} //0x45 ++}; ++ ++const struct oid_obj_priv oid_rtl_seg_81_80_80[] = ++{ ++ {1, &oid_null_function}, //0x80 OID_RT_DRIVER_OPTION ++ {1, &oid_null_function}, //0x81 OID_RT_RF_OFF ++ {1, &oid_null_function} //0x82 OID_RT_AUTH_STATUS ++ ++}; ++ ++const struct oid_obj_priv oid_rtl_seg_81_85[] = ++{ ++ {1, &oid_rt_wireless_mode_hdl} //0x00 OID_RT_WIRELESS_MODE ++}; ++ ++struct oid_obj_priv oid_rtl_seg_81_87[] = ++{ ++ {1, &oid_null_function}, //0x80 OID_RT_PRO8187_WI_POLL ++ {1, &oid_rt_pro_write_bb_reg_hdl}, //0x81 ++ {1, &oid_rt_pro_read_bb_reg_hdl}, //0x82 ++ {1, &oid_rt_pro_write_rf_reg_hdl}, //0x82 ++ {1, &oid_rt_pro_read_rf_reg_hdl} //0x83 ++}; ++ ++struct oid_obj_priv oid_rtl_seg_87_11_00[] = ++{ ++ {1, &oid_rt_pro8711_join_bss_hdl}, //0x00 //S ++ {1, &oid_rt_pro_read_register_hdl}, //0x01 ++ {1, &oid_rt_pro_write_register_hdl}, //0x02 ++ {1, &oid_rt_pro_burst_read_register_hdl}, //0x03 ++ {1, &oid_rt_pro_burst_write_register_hdl}, //0x04 ++ {1, &oid_rt_pro_write_txcmd_hdl}, //0x05 ++ {1, &oid_rt_pro_read16_eeprom_hdl}, //0x06 ++ {1, &oid_rt_pro_write16_eeprom_hdl}, //0x07 ++ {1, &oid_null_function}, //0x08 OID_RT_PRO_H2C_SET_COMMAND ++ {1, &oid_null_function}, //0x09 OID_RT_PRO_H2C_QUERY_RESULT ++ {1, &oid_rt_pro8711_wi_poll_hdl}, //0x0A ++ {1, &oid_rt_pro8711_pkt_loss_hdl}, //0x0B ++ {1, &oid_rt_rd_attrib_mem_hdl}, //0x0C ++ {1, &oid_rt_wr_attrib_mem_hdl}, //0x0D ++ {1, &oid_null_function}, //0x0E ++ {1, &oid_null_function}, //0x0F ++ {1, &oid_null_function}, //0x10 OID_RT_PRO_H2C_CMD_MODE ++ {1, &oid_null_function}, //0x11 OID_RT_PRO_H2C_CMD_RSP_MODE ++ {1, &oid_null_function}, //0X12 OID_RT_PRO_WAIT_C2H_EVENT ++ {1, &oid_null_function}, //0X13 OID_RT_PRO_RW_ACCESS_PROTOCOL_TEST ++ {1, &oid_null_function}, //0X14 OID_RT_PRO_SCSI_ACCESS_TEST ++ {1, &oid_null_function}, //0X15 OID_RT_PRO_SCSI_TCPIPOFFLOAD_OUT ++ {1, &oid_null_function}, //0X16 OID_RT_PRO_SCSI_TCPIPOFFLOAD_IN ++ {1, &oid_null_function}, //0X17 OID_RT_RRO_RX_PKT_VIA_IOCTRL ++ {1, &oid_null_function}, //0X18 OID_RT_RRO_RX_PKTARRAY_VIA_IOCTRL ++ {1, &oid_null_function}, //0X19 OID_RT_RPO_SET_PWRMGT_TEST ++ {1, &oid_null_function}, //0X1A ++ {1, &oid_null_function}, //0X1B OID_RT_PRO_QRY_PWRMGT_TEST ++ {1, &oid_null_function}, //0X1C OID_RT_RPO_ASYNC_RWIO_TEST ++ {1, &oid_null_function}, //0X1D OID_RT_RPO_ASYNC_RWIO_POLL ++ {1, &oid_rt_pro_set_rf_intfs_hdl}, //0X1E ++ {1, &oid_rt_poll_rx_status_hdl} //0X1F ++}; ++ ++struct oid_obj_priv oid_rtl_seg_87_11_20[] = ++{ ++ {1, &oid_rt_pro_cfg_debug_message_hdl}, //0x20 ++ {1, &oid_rt_pro_set_data_rate_ex_hdl}, //0x21 ++ {1, &oid_rt_pro_set_basic_rate_hdl}, //0x22 ++ {1, &oid_rt_pro_read_tssi_hdl}, //0x23 ++ {1, &oid_rt_pro_set_power_tracking_hdl} //0x24 ++}; ++ ++ ++struct oid_obj_priv oid_rtl_seg_87_11_50[] = ++{ ++ {1, &oid_rt_pro_qry_pwrstate_hdl}, //0x50 ++ {1, &oid_rt_pro_set_pwrstate_hdl} //0x51 ++}; ++ ++struct oid_obj_priv oid_rtl_seg_87_11_80[] = ++{ ++ {1, &oid_null_function} //0x80 ++}; ++ ++struct oid_obj_priv oid_rtl_seg_87_11_B0[] = ++{ ++ {1, &oid_null_function} //0xB0 ++}; ++ ++struct oid_obj_priv oid_rtl_seg_87_11_F0[] = ++{ ++ {1, &oid_null_function}, //0xF0 ++ {1, &oid_null_function}, //0xF1 ++ {1, &oid_null_function}, //0xF2 ++ {1, &oid_null_function}, //0xF3 ++ {1, &oid_null_function}, //0xF4 ++ {1, &oid_null_function}, //0xF5 ++ {1, &oid_null_function}, //0xF6 ++ {1, &oid_null_function}, //0xF7 ++ {1, &oid_null_function}, //0xF8 ++ {1, &oid_null_function}, //0xF9 ++ {1, &oid_null_function}, //0xFA ++ {1, &oid_rt_pro_h2c_set_rate_table_hdl}, //0xFB ++ {1, &oid_rt_pro_h2c_get_rate_table_hdl}, //0xFC ++ {1, &oid_null_function}, //0xFD ++ {1, &oid_null_function}, //0xFE OID_RT_PRO_H2C_C2H_LBK_TEST ++ {1, &oid_null_function} //0xFF ++ ++}; ++ ++struct oid_obj_priv oid_rtl_seg_87_12_00[]= ++{ ++ {1, &oid_rt_pro_encryption_ctrl_hdl}, //0x00 Q&S ++ {1, &oid_rt_pro_add_sta_info_hdl}, //0x01 S ++ {1, &oid_rt_pro_dele_sta_info_hdl}, //0x02 S ++ {1, &oid_rt_pro_query_dr_variable_hdl}, //0x03 Q ++ {1, &oid_rt_pro_rx_packet_type_hdl}, //0x04 Q,S ++ {1, &oid_rt_pro_read_efuse_hdl}, //0x05 Q OID_RT_PRO_READ_EFUSE ++ {1, &oid_rt_pro_write_efuse_hdl}, //0x06 S OID_RT_PRO_WRITE_EFUSE ++ {1, &oid_rt_pro_rw_efuse_pgpkt_hdl}, //0x07 Q,S ++ {1, &oid_rt_get_efuse_current_size_hdl}, //0x08 Q ++ {1, &oid_rt_set_bandwidth_hdl}, //0x09 ++ {1, &oid_rt_set_crystal_cap_hdl}, //0x0a ++ {1, &oid_rt_set_rx_packet_type_hdl}, //0x0b S ++ {1, &oid_rt_get_efuse_max_size_hdl}, //0x0c ++ {1, &oid_rt_pro_set_tx_agc_offset_hdl}, //0x0d ++ {1, &oid_rt_pro_set_pkt_test_mode_hdl}, //0x0e ++ {1, &oid_null_function}, //0x0f OID_RT_PRO_FOR_EVM_TEST_SETTING ++ {1, &oid_rt_get_thermal_meter_hdl}, //0x10 Q OID_RT_PRO_GET_THERMAL_METER ++ {1, &oid_rt_reset_phy_rx_packet_count_hdl}, //0x11 S OID_RT_RESET_PHY_RX_PACKET_COUNT ++ {1, &oid_rt_get_phy_rx_packet_received_hdl}, //0x12 Q OID_RT_GET_PHY_RX_PACKET_RECEIVED ++ {1, &oid_rt_get_phy_rx_packet_crc32_error_hdl}, //0x13 Q OID_RT_GET_PHY_RX_PACKET_CRC32_ERROR ++ {1, &oid_rt_set_power_down_hdl}, //0x14 Q OID_RT_SET_POWER_DOWN ++ {1, &oid_rt_get_power_mode_hdl} //0x15 Q OID_RT_GET_POWER_MODE ++}; ++ ++#else /* _RTL871X_MP_IOCTL_C_ */ ++ ++extern struct oid_obj_priv oid_rtl_seg_81_80_00[32]; ++extern struct oid_obj_priv oid_rtl_seg_81_80_20[16]; ++extern struct oid_obj_priv oid_rtl_seg_81_80_40[6]; ++extern struct oid_obj_priv oid_rtl_seg_81_80_80[3]; ++ ++extern struct oid_obj_priv oid_rtl_seg_81_85[1]; ++extern struct oid_obj_priv oid_rtl_seg_81_87[5]; ++ ++extern struct oid_obj_priv oid_rtl_seg_87_11_00[32]; ++extern struct oid_obj_priv oid_rtl_seg_87_11_20[5]; ++extern struct oid_obj_priv oid_rtl_seg_87_11_50[2]; ++extern struct oid_obj_priv oid_rtl_seg_87_11_80[1]; ++extern struct oid_obj_priv oid_rtl_seg_87_11_B0[1]; ++extern struct oid_obj_priv oid_rtl_seg_87_11_F0[16]; ++ ++extern struct oid_obj_priv oid_rtl_seg_87_12_00[32]; ++ ++#endif /* _RTL871X_MP_IOCTL_C_ */ ++ ++struct rwreg_param{ ++ u32 offset; ++ u32 width; ++ u32 value; ++}; ++ ++struct bbreg_param{ ++ u32 offset; ++ u32 phymask; ++ u32 value; ++}; ++/* ++struct rfchannel_param{ ++ u32 ch; ++ u32 modem; ++}; ++*/ ++struct txpower_param{ ++ u32 pwr_index; ++}; ++ ++ ++struct datarate_param{ ++ u32 rate_index; ++}; ++ ++ ++struct rfintfs_parm { ++ u32 rfintfs; ++}; ++ ++typedef struct _mp_xmit_parm_ { ++ u8 enable; ++ u32 count; ++ u16 length; ++ u8 payload_type; ++ u8 da[ETH_ALEN]; ++}MP_XMIT_PARM, *PMP_XMIT_PARM; ++ ++struct mp_xmit_packet { ++ u32 len; ++ u32 mem[MAX_MP_XMITBUF_SZ >> 2]; ++}; ++ ++struct psmode_param { ++ u32 ps_mode; ++ u32 smart_ps; ++}; ++ ++//for OID_RT_PRO_READ16_EEPROM & OID_RT_PRO_WRITE16_EEPROM ++struct eeprom_rw_param { ++ u32 offset; ++ u16 value; ++}; ++ ++struct mp_ioctl_handler { ++ u32 paramsize; ++ u32 (*handler)(struct oid_par_priv* poid_par_priv); ++ u32 oid; ++}; ++ ++struct mp_ioctl_param{ ++ u32 subcode; ++ u32 len; ++ u8 data[0]; ++}; ++ ++#define GEN_MP_IOCTL_SUBCODE(code) _MP_IOCTL_ ## code ## _CMD_ ++ ++enum RTL871X_MP_IOCTL_SUBCODE { ++ GEN_MP_IOCTL_SUBCODE(MP_START), /*0*/ ++ GEN_MP_IOCTL_SUBCODE(MP_STOP), ++ GEN_MP_IOCTL_SUBCODE(READ_REG), ++ GEN_MP_IOCTL_SUBCODE(WRITE_REG), ++ GEN_MP_IOCTL_SUBCODE(READ_BB_REG), ++ GEN_MP_IOCTL_SUBCODE(WRITE_BB_REG), /*5*/ ++ GEN_MP_IOCTL_SUBCODE(READ_RF_REG), ++ GEN_MP_IOCTL_SUBCODE(WRITE_RF_REG), ++ GEN_MP_IOCTL_SUBCODE(SET_CHANNEL), ++ GEN_MP_IOCTL_SUBCODE(SET_TXPOWER), ++ GEN_MP_IOCTL_SUBCODE(SET_DATARATE), /*10*/ ++ GEN_MP_IOCTL_SUBCODE(SET_BANDWIDTH), ++ GEN_MP_IOCTL_SUBCODE(SET_ANTENNA), ++ GEN_MP_IOCTL_SUBCODE(CNTU_TX), ++ GEN_MP_IOCTL_SUBCODE(SC_TX), ++ GEN_MP_IOCTL_SUBCODE(CS_TX), /*15*/ ++ GEN_MP_IOCTL_SUBCODE(ST_TX), ++ GEN_MP_IOCTL_SUBCODE(IOCTL_XMIT_PACKET), ++ GEN_MP_IOCTL_SUBCODE(SET_RX_PKT_TYPE), ++ GEN_MP_IOCTL_SUBCODE(RESET_PHY_RX_PKT_CNT), ++ GEN_MP_IOCTL_SUBCODE(GET_PHY_RX_PKT_RECV), /*20*/ ++ GEN_MP_IOCTL_SUBCODE(GET_PHY_RX_PKT_ERROR), ++ GEN_MP_IOCTL_SUBCODE(READ16_EEPROM), ++ GEN_MP_IOCTL_SUBCODE(WRITE16_EEPROM), ++ GEN_MP_IOCTL_SUBCODE(EFUSE), ++ GEN_MP_IOCTL_SUBCODE(EFUSE_MAP), /*25*/ ++ GEN_MP_IOCTL_SUBCODE(GET_EFUSE_MAX_SIZE), ++ GEN_MP_IOCTL_SUBCODE(GET_EFUSE_CURRENT_SIZE), ++ GEN_MP_IOCTL_SUBCODE(GET_THERMAL_METER), ++ GEN_MP_IOCTL_SUBCODE(SET_PTM), ++ GEN_MP_IOCTL_SUBCODE(SET_POWER_DOWN), /*30*/ ++ GEN_MP_IOCTL_SUBCODE(TRIGGER_GPIO), ++ GEN_MP_IOCTL_SUBCODE(SET_DM_BT), /*35*/ ++ GEN_MP_IOCTL_SUBCODE(DEL_BA), /*36*/ ++ GEN_MP_IOCTL_SUBCODE(GET_WIFI_STATUS), /*37*/ ++ MAX_MP_IOCTL_SUBCODE, ++}; ++ ++u32 mp_ioctl_xmit_packet_hdl(struct oid_par_priv* poid_par_priv); ++ ++#ifdef _RTW_MP_IOCTL_C_ ++ ++#define GEN_MP_IOCTL_HANDLER(sz, hdl, oid) {sz, hdl, oid}, ++ ++#define EXT_MP_IOCTL_HANDLER(sz, subcode, oid) {sz, mp_ioctl_ ## subcode ## _hdl, oid}, ++ ++ ++struct mp_ioctl_handler mp_ioctl_hdl[] = { ++ ++/*0*/ GEN_MP_IOCTL_HANDLER(sizeof(u32), oid_rt_pro_start_test_hdl, OID_RT_PRO_START_TEST) ++ GEN_MP_IOCTL_HANDLER(sizeof(u32), oid_rt_pro_stop_test_hdl, OID_RT_PRO_STOP_TEST) ++ ++ GEN_MP_IOCTL_HANDLER(sizeof(struct rwreg_param), oid_rt_pro_read_register_hdl, OID_RT_PRO_READ_REGISTER) ++ GEN_MP_IOCTL_HANDLER(sizeof(struct rwreg_param), oid_rt_pro_write_register_hdl, OID_RT_PRO_WRITE_REGISTER) ++ GEN_MP_IOCTL_HANDLER(sizeof(struct bb_reg_param), oid_rt_pro_read_bb_reg_hdl, OID_RT_PRO_READ_BB_REG) ++/*5*/ GEN_MP_IOCTL_HANDLER(sizeof(struct bb_reg_param), oid_rt_pro_write_bb_reg_hdl, OID_RT_PRO_WRITE_BB_REG) ++ GEN_MP_IOCTL_HANDLER(sizeof(struct rf_reg_param), oid_rt_pro_read_rf_reg_hdl, OID_RT_PRO_RF_READ_REGISTRY) ++ GEN_MP_IOCTL_HANDLER(sizeof(struct rf_reg_param), oid_rt_pro_write_rf_reg_hdl, OID_RT_PRO_RF_WRITE_REGISTRY) ++ ++ GEN_MP_IOCTL_HANDLER(sizeof(u32), oid_rt_pro_set_channel_direct_call_hdl, OID_RT_PRO_SET_CHANNEL_DIRECT_CALL) ++ GEN_MP_IOCTL_HANDLER(sizeof(struct txpower_param), oid_rt_pro_set_tx_power_control_hdl, OID_RT_PRO_SET_TX_POWER_CONTROL) ++/*10*/ GEN_MP_IOCTL_HANDLER(sizeof(u32), oid_rt_pro_set_data_rate_hdl, OID_RT_PRO_SET_DATA_RATE) ++ GEN_MP_IOCTL_HANDLER(sizeof(u32), oid_rt_set_bandwidth_hdl, OID_RT_SET_BANDWIDTH) ++ GEN_MP_IOCTL_HANDLER(sizeof(u32), oid_rt_pro_set_antenna_bb_hdl, OID_RT_PRO_SET_ANTENNA_BB) ++ ++ GEN_MP_IOCTL_HANDLER(sizeof(u32), oid_rt_pro_set_continuous_tx_hdl, OID_RT_PRO_SET_CONTINUOUS_TX) ++ GEN_MP_IOCTL_HANDLER(sizeof(u32), oid_rt_pro_set_single_carrier_tx_hdl, OID_RT_PRO_SET_SINGLE_CARRIER_TX) ++/*15*/ GEN_MP_IOCTL_HANDLER(sizeof(u32), oid_rt_pro_set_carrier_suppression_tx_hdl, OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX) ++ GEN_MP_IOCTL_HANDLER(sizeof(u32), oid_rt_pro_set_single_tone_tx_hdl, OID_RT_PRO_SET_SINGLE_TONE_TX) ++ ++ EXT_MP_IOCTL_HANDLER(0, xmit_packet, 0) ++ ++ GEN_MP_IOCTL_HANDLER(sizeof(u32), oid_rt_set_rx_packet_type_hdl, OID_RT_SET_RX_PACKET_TYPE) ++ GEN_MP_IOCTL_HANDLER(0, oid_rt_reset_phy_rx_packet_count_hdl, OID_RT_RESET_PHY_RX_PACKET_COUNT) ++/*20*/ GEN_MP_IOCTL_HANDLER(sizeof(u32), oid_rt_get_phy_rx_packet_received_hdl, OID_RT_GET_PHY_RX_PACKET_RECEIVED) ++ GEN_MP_IOCTL_HANDLER(sizeof(u32), oid_rt_get_phy_rx_packet_crc32_error_hdl, OID_RT_GET_PHY_RX_PACKET_CRC32_ERROR) ++ ++ GEN_MP_IOCTL_HANDLER(sizeof(struct eeprom_rw_param), NULL, 0) ++ GEN_MP_IOCTL_HANDLER(sizeof(struct eeprom_rw_param), NULL, 0) ++ GEN_MP_IOCTL_HANDLER(sizeof(EFUSE_ACCESS_STRUCT), oid_rt_pro_efuse_hdl, OID_RT_PRO_EFUSE) ++/*25*/ GEN_MP_IOCTL_HANDLER(0, oid_rt_pro_efuse_map_hdl, OID_RT_PRO_EFUSE_MAP) ++ GEN_MP_IOCTL_HANDLER(sizeof(u32), oid_rt_get_efuse_max_size_hdl, OID_RT_GET_EFUSE_MAX_SIZE) ++ GEN_MP_IOCTL_HANDLER(sizeof(u32), oid_rt_get_efuse_current_size_hdl, OID_RT_GET_EFUSE_CURRENT_SIZE) ++ ++ GEN_MP_IOCTL_HANDLER(sizeof(u32), oid_rt_get_thermal_meter_hdl, OID_RT_PRO_GET_THERMAL_METER) ++ GEN_MP_IOCTL_HANDLER(sizeof(u8), oid_rt_pro_set_power_tracking_hdl, OID_RT_PRO_SET_POWER_TRACKING) ++/*30*/ GEN_MP_IOCTL_HANDLER(sizeof(u8), oid_rt_set_power_down_hdl, OID_RT_SET_POWER_DOWN) ++/*31*/ GEN_MP_IOCTL_HANDLER(0, oid_rt_pro_trigger_gpio_hdl, 0) ++ ++ ++}; ++ ++#else /* _RTW_MP_IOCTL_C_ */ ++ ++extern struct mp_ioctl_handler mp_ioctl_hdl[]; ++ ++#endif /* _RTW_MP_IOCTL_C_ */ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_mp_phy_regdef.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_mp_phy_regdef.h +new file mode 100644 +index 00000000..0f8df412 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_mp_phy_regdef.h +@@ -0,0 +1,1099 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++/***************************************************************************** ++ * ++ * Module: __RTW_MP_PHY_REGDEF_H_ ++ * ++ * ++ * Note: 1. Define PMAC/BB register map ++ * 2. Define RF register map ++ * 3. PMAC/BB register bit mask. ++ * 4. RF reg bit mask. ++ * 5. Other BB/RF relative definition. ++ * ++ * ++ * Export: Constants, macro, functions(API), global variables(None). ++ * ++ * Abbrev: ++ * ++ * History: ++ * Data Who Remark ++ * 08/07/2007 MHC 1. Porting from 9x series PHYCFG.h. ++ * 2. Reorganize code architecture. ++ * 09/25/2008 MH 1. Add RL6052 register definition ++ * ++ *****************************************************************************/ ++#ifndef __RTW_MP_PHY_REGDEF_H_ ++#define __RTW_MP_PHY_REGDEF_H_ ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++//============================================================ ++// 8192S Regsiter offset definition ++//============================================================ ++ ++// ++// BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF ++// 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF ++// 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 ++// 3. RF register 0x00-2E ++// 4. Bit Mask for BB/RF register ++// 5. Other defintion for BB/RF R/W ++// ++ ++ ++// ++// 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF ++// 1. Page1(0x100) ++// ++#define rPMAC_Reset 0x100 ++#define rPMAC_TxStart 0x104 ++#define rPMAC_TxLegacySIG 0x108 ++#define rPMAC_TxHTSIG1 0x10c ++#define rPMAC_TxHTSIG2 0x110 ++#define rPMAC_PHYDebug 0x114 ++#define rPMAC_TxPacketNum 0x118 ++#define rPMAC_TxIdle 0x11c ++#define rPMAC_TxMACHeader0 0x120 ++#define rPMAC_TxMACHeader1 0x124 ++#define rPMAC_TxMACHeader2 0x128 ++#define rPMAC_TxMACHeader3 0x12c ++#define rPMAC_TxMACHeader4 0x130 ++#define rPMAC_TxMACHeader5 0x134 ++#define rPMAC_TxDataType 0x138 ++#define rPMAC_TxRandomSeed 0x13c ++#define rPMAC_CCKPLCPPreamble 0x140 ++#define rPMAC_CCKPLCPHeader 0x144 ++#define rPMAC_CCKCRC16 0x148 ++#define rPMAC_OFDMRxCRC32OK 0x170 ++#define rPMAC_OFDMRxCRC32Er 0x174 ++#define rPMAC_OFDMRxParityEr 0x178 ++#define rPMAC_OFDMRxCRC8Er 0x17c ++#define rPMAC_CCKCRxRC16Er 0x180 ++#define rPMAC_CCKCRxRC32Er 0x184 ++#define rPMAC_CCKCRxRC32OK 0x188 ++#define rPMAC_TxStatus 0x18c ++ ++// ++// 2. Page2(0x200) ++// ++// The following two definition are only used for USB interface. ++//#define RF_BB_CMD_ADDR 0x02c0 // RF/BB read/write command address. ++//#define RF_BB_CMD_DATA 0x02c4 // RF/BB read/write command data. ++ ++// ++// 3. Page8(0x800) ++// ++#define rFPGA0_RFMOD 0x800 //RF mode & CCK TxSC // RF BW Setting?? ++ ++#define rFPGA0_TxInfo 0x804 // Status report?? ++#define rFPGA0_PSDFunction 0x808 ++ ++#define rFPGA0_TxGainStage 0x80c // Set TX PWR init gain? ++ ++#define rFPGA0_RFTiming1 0x810 // Useless now ++#define rFPGA0_RFTiming2 0x814 ++//#define rFPGA0_XC_RFTiming 0x818 ++//#define rFPGA0_XD_RFTiming 0x81c ++ ++#define rFPGA0_XA_HSSIParameter1 0x820 // RF 3 wire register ++#define rFPGA0_XA_HSSIParameter2 0x824 ++#define rFPGA0_XB_HSSIParameter1 0x828 ++#define rFPGA0_XB_HSSIParameter2 0x82c ++#define rFPGA0_XC_HSSIParameter1 0x830 ++#define rFPGA0_XC_HSSIParameter2 0x834 ++#define rFPGA0_XD_HSSIParameter1 0x838 ++#define rFPGA0_XD_HSSIParameter2 0x83c ++#define rFPGA0_XA_LSSIParameter 0x840 ++#define rFPGA0_XB_LSSIParameter 0x844 ++#define rFPGA0_XC_LSSIParameter 0x848 ++#define rFPGA0_XD_LSSIParameter 0x84c ++ ++#define rFPGA0_RFWakeUpParameter 0x850 // Useless now ++#define rFPGA0_RFSleepUpParameter 0x854 ++ ++#define rFPGA0_XAB_SwitchControl 0x858 // RF Channel switch ++#define rFPGA0_XCD_SwitchControl 0x85c ++ ++#define rFPGA0_XA_RFInterfaceOE 0x860 // RF Channel switch ++#define rFPGA0_XB_RFInterfaceOE 0x864 ++#define rFPGA0_XC_RFInterfaceOE 0x868 ++#define rFPGA0_XD_RFInterfaceOE 0x86c ++ ++#define rFPGA0_XAB_RFInterfaceSW 0x870 // RF Interface Software Control ++#define rFPGA0_XCD_RFInterfaceSW 0x874 ++ ++#define rFPGA0_XAB_RFParameter 0x878 // RF Parameter ++#define rFPGA0_XCD_RFParameter 0x87c ++ ++#define rFPGA0_AnalogParameter1 0x880 // Crystal cap setting RF-R/W protection for parameter4?? ++#define rFPGA0_AnalogParameter2 0x884 ++#define rFPGA0_AnalogParameter3 0x888 // Useless now ++#define rFPGA0_AnalogParameter4 0x88c ++ ++#define rFPGA0_XA_LSSIReadBack 0x8a0 // Tranceiver LSSI Readback ++#define rFPGA0_XB_LSSIReadBack 0x8a4 ++#define rFPGA0_XC_LSSIReadBack 0x8a8 ++#define rFPGA0_XD_LSSIReadBack 0x8ac ++ ++#define rFPGA0_PSDReport 0x8b4 // Useless now ++#define rFPGA0_XAB_RFInterfaceRB 0x8e0 // Useless now // RF Interface Readback Value ++#define rFPGA0_XCD_RFInterfaceRB 0x8e4 // Useless now ++ ++// ++// 4. Page9(0x900) ++// ++#define rFPGA1_RFMOD 0x900 //RF mode & OFDM TxSC // RF BW Setting?? ++ ++#define rFPGA1_TxBlock 0x904 // Useless now ++#define rFPGA1_DebugSelect 0x908 // Useless now ++#define rFPGA1_TxInfo 0x90c // Useless now // Status report?? ++ ++// ++// 5. PageA(0xA00) ++// ++// Set Control channel to upper or lower. These settings are required only for 40MHz ++#define rCCK0_System 0xa00 ++ ++#define rCCK0_AFESetting 0xa04 // Disable init gain now // Select RX path by RSSI ++#define rCCK0_CCA 0xa08 // Disable init gain now // Init gain ++ ++#define rCCK0_RxAGC1 0xa0c //AGC default value, saturation level // Antenna Diversity, RX AGC, LNA Threshold, RX LNA Threshold useless now. Not the same as 90 series ++#define rCCK0_RxAGC2 0xa10 //AGC & DAGC ++ ++#define rCCK0_RxHP 0xa14 ++ ++#define rCCK0_DSPParameter1 0xa18 //Timing recovery & Channel estimation threshold ++#define rCCK0_DSPParameter2 0xa1c //SQ threshold ++ ++#define rCCK0_TxFilter1 0xa20 ++#define rCCK0_TxFilter2 0xa24 ++#define rCCK0_DebugPort 0xa28 //debug port and Tx filter3 ++#define rCCK0_FalseAlarmReport 0xa2c //0xa2d useless now 0xa30-a4f channel report ++#define rCCK0_TRSSIReport 0xa50 ++#define rCCK0_RxReport 0xa54 //0xa57 ++#define rCCK0_FACounterLower 0xa5c //0xa5b ++#define rCCK0_FACounterUpper 0xa58 //0xa5c ++ ++// ++// 6. PageC(0xC00) ++// ++#define rOFDM0_LSTF 0xc00 ++ ++#define rOFDM0_TRxPathEnable 0xc04 ++#define rOFDM0_TRMuxPar 0xc08 ++#define rOFDM0_TRSWIsolation 0xc0c ++ ++#define rOFDM0_XARxAFE 0xc10 //RxIQ DC offset, Rx digital filter, DC notch filter ++#define rOFDM0_XARxIQImbalance 0xc14 //RxIQ imblance matrix ++#define rOFDM0_XBRxAFE 0xc18 ++#define rOFDM0_XBRxIQImbalance 0xc1c ++#define rOFDM0_XCRxAFE 0xc20 ++#define rOFDM0_XCRxIQImbalance 0xc24 ++#define rOFDM0_XDRxAFE 0xc28 ++#define rOFDM0_XDRxIQImbalance 0xc2c ++ ++#define rOFDM0_RxDetector1 0xc30 //PD,BW & SBD // DM tune init gain ++#define rOFDM0_RxDetector2 0xc34 //SBD & Fame Sync. ++#define rOFDM0_RxDetector3 0xc38 //Frame Sync. ++#define rOFDM0_RxDetector4 0xc3c //PD, SBD, Frame Sync & Short-GI ++ ++#define rOFDM0_RxDSP 0xc40 //Rx Sync Path ++#define rOFDM0_CFOandDAGC 0xc44 //CFO & DAGC ++#define rOFDM0_CCADropThreshold 0xc48 //CCA Drop threshold ++#define rOFDM0_ECCAThreshold 0xc4c // energy CCA ++ ++#define rOFDM0_XAAGCCore1 0xc50 // DIG ++#define rOFDM0_XAAGCCore2 0xc54 ++#define rOFDM0_XBAGCCore1 0xc58 ++#define rOFDM0_XBAGCCore2 0xc5c ++#define rOFDM0_XCAGCCore1 0xc60 ++#define rOFDM0_XCAGCCore2 0xc64 ++#define rOFDM0_XDAGCCore1 0xc68 ++#define rOFDM0_XDAGCCore2 0xc6c ++ ++#define rOFDM0_AGCParameter1 0xc70 ++#define rOFDM0_AGCParameter2 0xc74 ++#define rOFDM0_AGCRSSITable 0xc78 ++#define rOFDM0_HTSTFAGC 0xc7c ++ ++#define rOFDM0_XATxIQImbalance 0xc80 // TX PWR TRACK and DIG ++#define rOFDM0_XATxAFE 0xc84 ++#define rOFDM0_XBTxIQImbalance 0xc88 ++#define rOFDM0_XBTxAFE 0xc8c ++#define rOFDM0_XCTxIQImbalance 0xc90 ++#define rOFDM0_XCTxAFE 0xc94 ++#define rOFDM0_XDTxIQImbalance 0xc98 ++#define rOFDM0_XDTxAFE 0xc9c ++#define rOFDM0_RxIQExtAnta 0xca0 ++ ++#define rOFDM0_RxHPParameter 0xce0 ++#define rOFDM0_TxPseudoNoiseWgt 0xce4 ++#define rOFDM0_FrameSync 0xcf0 ++#define rOFDM0_DFSReport 0xcf4 ++#define rOFDM0_TxCoeff1 0xca4 ++#define rOFDM0_TxCoeff2 0xca8 ++#define rOFDM0_TxCoeff3 0xcac ++#define rOFDM0_TxCoeff4 0xcb0 ++#define rOFDM0_TxCoeff5 0xcb4 ++#define rOFDM0_TxCoeff6 0xcb8 ++ ++ ++// ++// 7. PageD(0xD00) ++// ++#define rOFDM1_LSTF 0xd00 ++#define rOFDM1_TRxPathEnable 0xd04 ++ ++#define rOFDM1_CFO 0xd08 // No setting now ++#define rOFDM1_CSI1 0xd10 ++#define rOFDM1_SBD 0xd14 ++#define rOFDM1_CSI2 0xd18 ++#define rOFDM1_CFOTracking 0xd2c ++#define rOFDM1_TRxMesaure1 0xd34 ++#define rOFDM1_IntfDet 0xd3c ++#define rOFDM1_csi_fix_mask 0xd40 ++#define rOFDM1_PseudoNoiseStateAB 0xd50 ++#define rOFDM1_PseudoNoiseStateCD 0xd54 ++#define rOFDM1_RxPseudoNoiseWgt 0xd58 ++ ++#define rOFDM_PHYCounter1 0xda0 //cca, parity fail ++#define rOFDM_PHYCounter2 0xda4 //rate illegal, crc8 fail ++#define rOFDM_PHYCounter3 0xda8 //MCS not support ++ ++#define rOFDM_ShortCFOAB 0xdac // No setting now ++#define rOFDM_ShortCFOCD 0xdb0 ++#define rOFDM_LongCFOAB 0xdb4 ++#define rOFDM_LongCFOCD 0xdb8 ++#define rOFDM_TailCFOAB 0xdbc ++#define rOFDM_TailCFOCD 0xdc0 ++#define rOFDM_PWMeasure1 0xdc4 ++#define rOFDM_PWMeasure2 0xdc8 ++#define rOFDM_BWReport 0xdcc ++#define rOFDM_AGCReport 0xdd0 ++#define rOFDM_RxSNR 0xdd4 ++#define rOFDM_RxEVMCSI 0xdd8 ++#define rOFDM_SIGReport 0xddc ++ ++ ++// ++// 8. PageE(0xE00) ++// ++#define rTxAGC_Rate18_06 0xe00 ++#define rTxAGC_Rate54_24 0xe04 ++#define rTxAGC_CCK_Mcs32 0xe08 ++#define rTxAGC_Mcs03_Mcs00 0xe10 ++#define rTxAGC_Mcs07_Mcs04 0xe14 ++#define rTxAGC_Mcs11_Mcs08 0xe18 ++#define rTxAGC_Mcs15_Mcs12 0xe1c ++ ++// Analog- control in RX_WAIT_CCA : REG: EE0 [Analog- Power & Control Register] ++#define rRx_Wait_CCCA 0xe70 ++#define rAnapar_Ctrl_BB 0xee0 ++ ++// ++// 7. RF Register 0x00-0x2E (RF 8256) ++// RF-0222D 0x00-3F ++// ++//Zebra1 ++#define RTL92SE_FPGA_VERIFY 0 ++#define rZebra1_HSSIEnable 0x0 // Useless now ++#define rZebra1_TRxEnable1 0x1 ++#define rZebra1_TRxEnable2 0x2 ++#define rZebra1_AGC 0x4 ++#define rZebra1_ChargePump 0x5 ++//#if (RTL92SE_FPGA_VERIFY == 1) ++#define rZebra1_Channel 0x7 // RF channel switch ++//#else ++ ++//#endif ++#define rZebra1_TxGain 0x8 // Useless now ++#define rZebra1_TxLPF 0x9 ++#define rZebra1_RxLPF 0xb ++#define rZebra1_RxHPFCorner 0xc ++ ++//Zebra4 ++#define rGlobalCtrl 0 // Useless now ++#define rRTL8256_TxLPF 19 ++#define rRTL8256_RxLPF 11 ++ ++//RTL8258 ++#define rRTL8258_TxLPF 0x11 // Useless now ++#define rRTL8258_RxLPF 0x13 ++#define rRTL8258_RSSILPF 0xa ++ ++// ++// RL6052 Register definition ++// ++#define RF_AC 0x00 // ++ ++#define RF_IQADJ_G1 0x01 // ++#define RF_IQADJ_G2 0x02 // ++#define RF_POW_TRSW 0x05 // ++ ++#define RF_GAIN_RX 0x06 // ++#define RF_GAIN_TX 0x07 // ++ ++#define RF_TXM_IDAC 0x08 // ++#define RF_BS_IQGEN 0x0F // ++ ++#define RF_MODE1 0x10 // ++#define RF_MODE2 0x11 // ++ ++#define RF_RX_AGC_HP 0x12 // ++#define RF_TX_AGC 0x13 // ++#define RF_BIAS 0x14 // ++#define RF_IPA 0x15 // ++#define RF_TXBIAS 0x16 // ++#define RF_POW_ABILITY 0x17 // ++#define RF_MODE_AG 0x18 // ++#define rRfChannel 0x18 // RF channel and BW switch ++#define RF_CHNLBW 0x18 // RF channel and BW switch ++#define RF_TOP 0x19 // ++ ++#define RF_RX_G1 0x1A // ++#define RF_RX_G2 0x1B // ++ ++#define RF_RX_BB2 0x1C // ++#define RF_RX_BB1 0x1D // ++ ++#define RF_RCK1 0x1E // ++#define RF_RCK2 0x1F // ++ ++#define RF_TX_G1 0x20 // ++#define RF_TX_G2 0x21 // ++#define RF_TX_G3 0x22 // ++ ++#define RF_TX_BB1 0x23 // ++ ++#define RF_T_METER 0x24 // ++ ++#define RF_SYN_G1 0x25 // RF TX Power control ++#define RF_SYN_G2 0x26 // RF TX Power control ++#define RF_SYN_G3 0x27 // RF TX Power control ++#define RF_SYN_G4 0x28 // RF TX Power control ++#define RF_SYN_G5 0x29 // RF TX Power control ++#define RF_SYN_G6 0x2A // RF TX Power control ++#define RF_SYN_G7 0x2B // RF TX Power control ++#define RF_SYN_G8 0x2C // RF TX Power control ++ ++#define RF_RCK_OS 0x30 // RF TX PA control ++ ++#define RF_TXPA_G1 0x31 // RF TX PA control ++#define RF_TXPA_G2 0x32 // RF TX PA control ++#define RF_TXPA_G3 0x33 // RF TX PA control ++ ++// ++//Bit Mask ++// ++// 1. Page1(0x100) ++#define bBBResetB 0x100 // Useless now? ++#define bGlobalResetB 0x200 ++#define bOFDMTxStart 0x4 ++#define bCCKTxStart 0x8 ++#define bCRC32Debug 0x100 ++#define bPMACLoopback 0x10 ++#define bTxLSIG 0xffffff ++#define bOFDMTxRate 0xf ++#define bOFDMTxReserved 0x10 ++#define bOFDMTxLength 0x1ffe0 ++#define bOFDMTxParity 0x20000 ++#define bTxHTSIG1 0xffffff ++#define bTxHTMCSRate 0x7f ++#define bTxHTBW 0x80 ++#define bTxHTLength 0xffff00 ++#define bTxHTSIG2 0xffffff ++#define bTxHTSmoothing 0x1 ++#define bTxHTSounding 0x2 ++#define bTxHTReserved 0x4 ++#define bTxHTAggreation 0x8 ++#define bTxHTSTBC 0x30 ++#define bTxHTAdvanceCoding 0x40 ++#define bTxHTShortGI 0x80 ++#define bTxHTNumberHT_LTF 0x300 ++#define bTxHTCRC8 0x3fc00 ++#define bCounterReset 0x10000 ++#define bNumOfOFDMTx 0xffff ++#define bNumOfCCKTx 0xffff0000 ++#define bTxIdleInterval 0xffff ++#define bOFDMService 0xffff0000 ++#define bTxMACHeader 0xffffffff ++#define bTxDataInit 0xff ++#define bTxHTMode 0x100 ++#define bTxDataType 0x30000 ++#define bTxRandomSeed 0xffffffff ++#define bCCKTxPreamble 0x1 ++#define bCCKTxSFD 0xffff0000 ++#define bCCKTxSIG 0xff ++#define bCCKTxService 0xff00 ++#define bCCKLengthExt 0x8000 ++#define bCCKTxLength 0xffff0000 ++#define bCCKTxCRC16 0xffff ++#define bCCKTxStatus 0x1 ++#define bOFDMTxStatus 0x2 ++ ++#define IS_BB_REG_OFFSET_92S(_Offset) ((_Offset >= 0x800) && (_Offset <= 0xfff)) ++ ++// 2. Page8(0x800) ++#define bRFMOD 0x1 // Reg 0x800 rFPGA0_RFMOD ++#define bJapanMode 0x2 ++#define bCCKTxSC 0x30 ++#define bCCKEn 0x1000000 ++#define bOFDMEn 0x2000000 ++ ++#define bOFDMRxADCPhase 0x10000 // Useless now ++#define bOFDMTxDACPhase 0x40000 ++#define bXATxAGC 0x3f ++ ++#define bXBTxAGC 0xf00 // Reg 80c rFPGA0_TxGainStage ++#define bXCTxAGC 0xf000 ++#define bXDTxAGC 0xf0000 ++ ++#define bPAStart 0xf0000000 // Useless now ++#define bTRStart 0x00f00000 ++#define bRFStart 0x0000f000 ++#define bBBStart 0x000000f0 ++#define bBBCCKStart 0x0000000f ++#define bPAEnd 0xf //Reg0x814 ++#define bTREnd 0x0f000000 ++#define bRFEnd 0x000f0000 ++#define bCCAMask 0x000000f0 //T2R ++#define bR2RCCAMask 0x00000f00 ++#define bHSSI_R2TDelay 0xf8000000 ++#define bHSSI_T2RDelay 0xf80000 ++#define bContTxHSSI 0x400 //chane gain at continue Tx ++#define bIGFromCCK 0x200 ++#define bAGCAddress 0x3f ++#define bRxHPTx 0x7000 ++#define bRxHPT2R 0x38000 ++#define bRxHPCCKIni 0xc0000 ++#define bAGCTxCode 0xc00000 ++#define bAGCRxCode 0x300000 ++ ++#define b3WireDataLength 0x800 // Reg 0x820~84f rFPGA0_XA_HSSIParameter1 ++#define b3WireAddressLength 0x400 ++ ++#define b3WireRFPowerDown 0x1 // Useless now ++//#define bHWSISelect 0x8 ++#define b5GPAPEPolarity 0x40000000 ++#define b2GPAPEPolarity 0x80000000 ++#define bRFSW_TxDefaultAnt 0x3 ++#define bRFSW_TxOptionAnt 0x30 ++#define bRFSW_RxDefaultAnt 0x300 ++#define bRFSW_RxOptionAnt 0x3000 ++#define bRFSI_3WireData 0x1 ++#define bRFSI_3WireClock 0x2 ++#define bRFSI_3WireLoad 0x4 ++#define bRFSI_3WireRW 0x8 ++#define bRFSI_3Wire 0xf ++ ++#define bRFSI_RFENV 0x10 // Reg 0x870 rFPGA0_XAB_RFInterfaceSW ++ ++#define bRFSI_TRSW 0x20 // Useless now ++#define bRFSI_TRSWB 0x40 ++#define bRFSI_ANTSW 0x100 ++#define bRFSI_ANTSWB 0x200 ++#define bRFSI_PAPE 0x400 ++#define bRFSI_PAPE5G 0x800 ++#define bBandSelect 0x1 ++#define bHTSIG2_GI 0x80 ++#define bHTSIG2_Smoothing 0x01 ++#define bHTSIG2_Sounding 0x02 ++#define bHTSIG2_Aggreaton 0x08 ++#define bHTSIG2_STBC 0x30 ++#define bHTSIG2_AdvCoding 0x40 ++#define bHTSIG2_NumOfHTLTF 0x300 ++#define bHTSIG2_CRC8 0x3fc ++#define bHTSIG1_MCS 0x7f ++#define bHTSIG1_BandWidth 0x80 ++#define bHTSIG1_HTLength 0xffff ++#define bLSIG_Rate 0xf ++#define bLSIG_Reserved 0x10 ++#define bLSIG_Length 0x1fffe ++#define bLSIG_Parity 0x20 ++#define bCCKRxPhase 0x4 ++#if (RTL92SE_FPGA_VERIFY == 1) ++#define bLSSIReadAddress 0x3f000000 //LSSI "Read" Address // Reg 0x824 rFPGA0_XA_HSSIParameter2 ++#else ++#define bLSSIReadAddress 0x7f800000 // T65 RF ++#endif ++#define bLSSIReadEdge 0x80000000 //LSSI "Read" edge signal ++#if (RTL92SE_FPGA_VERIFY == 1) ++#define bLSSIReadBackData 0xfff // Reg 0x8a0 rFPGA0_XA_LSSIReadBack ++#else ++#define bLSSIReadBackData 0xfffff // T65 RF ++#endif ++#define bLSSIReadOKFlag 0x1000 // Useless now ++#define bCCKSampleRate 0x8 //0: 44MHz, 1:88MHz ++#define bRegulator0Standby 0x1 ++#define bRegulatorPLLStandby 0x2 ++#define bRegulator1Standby 0x4 ++#define bPLLPowerUp 0x8 ++#define bDPLLPowerUp 0x10 ++#define bDA10PowerUp 0x20 ++#define bAD7PowerUp 0x200 ++#define bDA6PowerUp 0x2000 ++#define bXtalPowerUp 0x4000 ++#define b40MDClkPowerUP 0x8000 ++#define bDA6DebugMode 0x20000 ++#define bDA6Swing 0x380000 ++ ++#define bADClkPhase 0x4000000 // Reg 0x880 rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ ++ ++#define b80MClkDelay 0x18000000 // Useless ++#define bAFEWatchDogEnable 0x20000000 ++ ++#define bXtalCap01 0xc0000000 // Reg 0x884 rFPGA0_AnalogParameter2 Crystal cap ++#define bXtalCap23 0x3 ++#define bXtalCap92x 0x0f000000 ++#define bXtalCap 0x0f000000 ++ ++#define bIntDifClkEnable 0x400 // Useless ++#define bExtSigClkEnable 0x800 ++#define bBandgapMbiasPowerUp 0x10000 ++#define bAD11SHGain 0xc0000 ++#define bAD11InputRange 0x700000 ++#define bAD11OPCurrent 0x3800000 ++#define bIPathLoopback 0x4000000 ++#define bQPathLoopback 0x8000000 ++#define bAFELoopback 0x10000000 ++#define bDA10Swing 0x7e0 ++#define bDA10Reverse 0x800 ++#define bDAClkSource 0x1000 ++#define bAD7InputRange 0x6000 ++#define bAD7Gain 0x38000 ++#define bAD7OutputCMMode 0x40000 ++#define bAD7InputCMMode 0x380000 ++#define bAD7Current 0xc00000 ++#define bRegulatorAdjust 0x7000000 ++#define bAD11PowerUpAtTx 0x1 ++#define bDA10PSAtTx 0x10 ++#define bAD11PowerUpAtRx 0x100 ++#define bDA10PSAtRx 0x1000 ++#define bCCKRxAGCFormat 0x200 ++#define bPSDFFTSamplepPoint 0xc000 ++#define bPSDAverageNum 0x3000 ++#define bIQPathControl 0xc00 ++#define bPSDFreq 0x3ff ++#define bPSDAntennaPath 0x30 ++#define bPSDIQSwitch 0x40 ++#define bPSDRxTrigger 0x400000 ++#define bPSDTxTrigger 0x80000000 ++#define bPSDSineToneScale 0x7f000000 ++#define bPSDReport 0xffff ++ ++// 3. Page9(0x900) ++#define bOFDMTxSC 0x30000000 // Useless ++#define bCCKTxOn 0x1 ++#define bOFDMTxOn 0x2 ++#define bDebugPage 0xfff //reset debug page and also HWord, LWord ++#define bDebugItem 0xff //reset debug page and LWord ++#define bAntL 0x10 ++#define bAntNonHT 0x100 ++#define bAntHT1 0x1000 ++#define bAntHT2 0x10000 ++#define bAntHT1S1 0x100000 ++#define bAntNonHTS1 0x1000000 ++ ++// 4. PageA(0xA00) ++#define bCCKBBMode 0x3 // Useless ++#define bCCKTxPowerSaving 0x80 ++#define bCCKRxPowerSaving 0x40 ++ ++#define bCCKSideBand 0x10 // Reg 0xa00 rCCK0_System 20/40 switch ++ ++#define bCCKScramble 0x8 // Useless ++#define bCCKAntDiversity 0x8000 ++#define bCCKCarrierRecovery 0x4000 ++#define bCCKTxRate 0x3000 ++#define bCCKDCCancel 0x0800 ++#define bCCKISICancel 0x0400 ++#define bCCKMatchFilter 0x0200 ++#define bCCKEqualizer 0x0100 ++#define bCCKPreambleDetect 0x800000 ++#define bCCKFastFalseCCA 0x400000 ++#define bCCKChEstStart 0x300000 ++#define bCCKCCACount 0x080000 ++#define bCCKcs_lim 0x070000 ++#define bCCKBistMode 0x80000000 ++#define bCCKCCAMask 0x40000000 ++#define bCCKTxDACPhase 0x4 ++#define bCCKRxADCPhase 0x20000000 //r_rx_clk ++#define bCCKr_cp_mode0 0x0100 ++#define bCCKTxDCOffset 0xf0 ++#define bCCKRxDCOffset 0xf ++#define bCCKCCAMode 0xc000 ++#define bCCKFalseCS_lim 0x3f00 ++#define bCCKCS_ratio 0xc00000 ++#define bCCKCorgBit_sel 0x300000 ++#define bCCKPD_lim 0x0f0000 ++#define bCCKNewCCA 0x80000000 ++#define bCCKRxHPofIG 0x8000 ++#define bCCKRxIG 0x7f00 ++#define bCCKLNAPolarity 0x800000 ++#define bCCKRx1stGain 0x7f0000 ++#define bCCKRFExtend 0x20000000 //CCK Rx Iinital gain polarity ++#define bCCKRxAGCSatLevel 0x1f000000 ++#define bCCKRxAGCSatCount 0xe0 ++#define bCCKRxRFSettle 0x1f //AGCsamp_dly ++#define bCCKFixedRxAGC 0x8000 ++//#define bCCKRxAGCFormat 0x4000 //remove to HSSI register 0x824 ++#define bCCKAntennaPolarity 0x2000 ++#define bCCKTxFilterType 0x0c00 ++#define bCCKRxAGCReportType 0x0300 ++#define bCCKRxDAGCEn 0x80000000 ++#define bCCKRxDAGCPeriod 0x20000000 ++#define bCCKRxDAGCSatLevel 0x1f000000 ++#define bCCKTimingRecovery 0x800000 ++#define bCCKTxC0 0x3f0000 ++#define bCCKTxC1 0x3f000000 ++#define bCCKTxC2 0x3f ++#define bCCKTxC3 0x3f00 ++#define bCCKTxC4 0x3f0000 ++#define bCCKTxC5 0x3f000000 ++#define bCCKTxC6 0x3f ++#define bCCKTxC7 0x3f00 ++#define bCCKDebugPort 0xff0000 ++#define bCCKDACDebug 0x0f000000 ++#define bCCKFalseAlarmEnable 0x8000 ++#define bCCKFalseAlarmRead 0x4000 ++#define bCCKTRSSI 0x7f ++#define bCCKRxAGCReport 0xfe ++#define bCCKRxReport_AntSel 0x80000000 ++#define bCCKRxReport_MFOff 0x40000000 ++#define bCCKRxRxReport_SQLoss 0x20000000 ++#define bCCKRxReport_Pktloss 0x10000000 ++#define bCCKRxReport_Lockedbit 0x08000000 ++#define bCCKRxReport_RateError 0x04000000 ++#define bCCKRxReport_RxRate 0x03000000 ++#define bCCKRxFACounterLower 0xff ++#define bCCKRxFACounterUpper 0xff000000 ++#define bCCKRxHPAGCStart 0xe000 ++#define bCCKRxHPAGCFinal 0x1c00 ++#define bCCKRxFalseAlarmEnable 0x8000 ++#define bCCKFACounterFreeze 0x4000 ++#define bCCKTxPathSel 0x10000000 ++#define bCCKDefaultRxPath 0xc000000 ++#define bCCKOptionRxPath 0x3000000 ++ ++// 5. PageC(0xC00) ++#define bNumOfSTF 0x3 // Useless ++#define bShift_L 0xc0 ++#define bGI_TH 0xc ++#define bRxPathA 0x1 ++#define bRxPathB 0x2 ++#define bRxPathC 0x4 ++#define bRxPathD 0x8 ++#define bTxPathA 0x1 ++#define bTxPathB 0x2 ++#define bTxPathC 0x4 ++#define bTxPathD 0x8 ++#define bTRSSIFreq 0x200 ++#define bADCBackoff 0x3000 ++#define bDFIRBackoff 0xc000 ++#define bTRSSILatchPhase 0x10000 ++#define bRxIDCOffset 0xff ++#define bRxQDCOffset 0xff00 ++#define bRxDFIRMode 0x1800000 ++#define bRxDCNFType 0xe000000 ++#define bRXIQImb_A 0x3ff ++#define bRXIQImb_B 0xfc00 ++#define bRXIQImb_C 0x3f0000 ++#define bRXIQImb_D 0xffc00000 ++#define bDC_dc_Notch 0x60000 ++#define bRxNBINotch 0x1f000000 ++#define bPD_TH 0xf ++#define bPD_TH_Opt2 0xc000 ++#define bPWED_TH 0x700 ++#define bIfMF_Win_L 0x800 ++#define bPD_Option 0x1000 ++#define bMF_Win_L 0xe000 ++#define bBW_Search_L 0x30000 ++#define bwin_enh_L 0xc0000 ++#define bBW_TH 0x700000 ++#define bED_TH2 0x3800000 ++#define bBW_option 0x4000000 ++#define bRatio_TH 0x18000000 ++#define bWindow_L 0xe0000000 ++#define bSBD_Option 0x1 ++#define bFrame_TH 0x1c ++#define bFS_Option 0x60 ++#define bDC_Slope_check 0x80 ++#define bFGuard_Counter_DC_L 0xe00 ++#define bFrame_Weight_Short 0x7000 ++#define bSub_Tune 0xe00000 ++#define bFrame_DC_Length 0xe000000 ++#define bSBD_start_offset 0x30000000 ++#define bFrame_TH_2 0x7 ++#define bFrame_GI2_TH 0x38 ++#define bGI2_Sync_en 0x40 ++#define bSarch_Short_Early 0x300 ++#define bSarch_Short_Late 0xc00 ++#define bSarch_GI2_Late 0x70000 ++#define bCFOAntSum 0x1 ++#define bCFOAcc 0x2 ++#define bCFOStartOffset 0xc ++#define bCFOLookBack 0x70 ++#define bCFOSumWeight 0x80 ++#define bDAGCEnable 0x10000 ++#define bTXIQImb_A 0x3ff ++#define bTXIQImb_B 0xfc00 ++#define bTXIQImb_C 0x3f0000 ++#define bTXIQImb_D 0xffc00000 ++#define bTxIDCOffset 0xff ++#define bTxQDCOffset 0xff00 ++#define bTxDFIRMode 0x10000 ++#define bTxPesudoNoiseOn 0x4000000 ++#define bTxPesudoNoise_A 0xff ++#define bTxPesudoNoise_B 0xff00 ++#define bTxPesudoNoise_C 0xff0000 ++#define bTxPesudoNoise_D 0xff000000 ++#define bCCADropOption 0x20000 ++#define bCCADropThres 0xfff00000 ++#define bEDCCA_H 0xf ++#define bEDCCA_L 0xf0 ++#define bLambda_ED 0x300 ++#define bRxInitialGain 0x7f ++#define bRxAntDivEn 0x80 ++#define bRxAGCAddressForLNA 0x7f00 ++#define bRxHighPowerFlow 0x8000 ++#define bRxAGCFreezeThres 0xc0000 ++#define bRxFreezeStep_AGC1 0x300000 ++#define bRxFreezeStep_AGC2 0xc00000 ++#define bRxFreezeStep_AGC3 0x3000000 ++#define bRxFreezeStep_AGC0 0xc000000 ++#define bRxRssi_Cmp_En 0x10000000 ++#define bRxQuickAGCEn 0x20000000 ++#define bRxAGCFreezeThresMode 0x40000000 ++#define bRxOverFlowCheckType 0x80000000 ++#define bRxAGCShift 0x7f ++#define bTRSW_Tri_Only 0x80 ++#define bPowerThres 0x300 ++#define bRxAGCEn 0x1 ++#define bRxAGCTogetherEn 0x2 ++#define bRxAGCMin 0x4 ++#define bRxHP_Ini 0x7 ++#define bRxHP_TRLNA 0x70 ++#define bRxHP_RSSI 0x700 ++#define bRxHP_BBP1 0x7000 ++#define bRxHP_BBP2 0x70000 ++#define bRxHP_BBP3 0x700000 ++#define bRSSI_H 0x7f0000 //the threshold for high power ++#define bRSSI_Gen 0x7f000000 //the threshold for ant diversity ++#define bRxSettle_TRSW 0x7 ++#define bRxSettle_LNA 0x38 ++#define bRxSettle_RSSI 0x1c0 ++#define bRxSettle_BBP 0xe00 ++#define bRxSettle_RxHP 0x7000 ++#define bRxSettle_AntSW_RSSI 0x38000 ++#define bRxSettle_AntSW 0xc0000 ++#define bRxProcessTime_DAGC 0x300000 ++#define bRxSettle_HSSI 0x400000 ++#define bRxProcessTime_BBPPW 0x800000 ++#define bRxAntennaPowerShift 0x3000000 ++#define bRSSITableSelect 0xc000000 ++#define bRxHP_Final 0x7000000 ++#define bRxHTSettle_BBP 0x7 ++#define bRxHTSettle_HSSI 0x8 ++#define bRxHTSettle_RxHP 0x70 ++#define bRxHTSettle_BBPPW 0x80 ++#define bRxHTSettle_Idle 0x300 ++#define bRxHTSettle_Reserved 0x1c00 ++#define bRxHTRxHPEn 0x8000 ++#define bRxHTAGCFreezeThres 0x30000 ++#define bRxHTAGCTogetherEn 0x40000 ++#define bRxHTAGCMin 0x80000 ++#define bRxHTAGCEn 0x100000 ++#define bRxHTDAGCEn 0x200000 ++#define bRxHTRxHP_BBP 0x1c00000 ++#define bRxHTRxHP_Final 0xe0000000 ++#define bRxPWRatioTH 0x3 ++#define bRxPWRatioEn 0x4 ++#define bRxMFHold 0x3800 ++#define bRxPD_Delay_TH1 0x38 ++#define bRxPD_Delay_TH2 0x1c0 ++#define bRxPD_DC_COUNT_MAX 0x600 ++//#define bRxMF_Hold 0x3800 ++#define bRxPD_Delay_TH 0x8000 ++#define bRxProcess_Delay 0xf0000 ++#define bRxSearchrange_GI2_Early 0x700000 ++#define bRxFrame_Guard_Counter_L 0x3800000 ++#define bRxSGI_Guard_L 0xc000000 ++#define bRxSGI_Search_L 0x30000000 ++#define bRxSGI_TH 0xc0000000 ++#define bDFSCnt0 0xff ++#define bDFSCnt1 0xff00 ++#define bDFSFlag 0xf0000 ++#define bMFWeightSum 0x300000 ++#define bMinIdxTH 0x7f000000 ++#define bDAFormat 0x40000 ++#define bTxChEmuEnable 0x01000000 ++#define bTRSWIsolation_A 0x7f ++#define bTRSWIsolation_B 0x7f00 ++#define bTRSWIsolation_C 0x7f0000 ++#define bTRSWIsolation_D 0x7f000000 ++#define bExtLNAGain 0x7c00 ++ ++// 6. PageE(0xE00) ++#define bSTBCEn 0x4 // Useless ++#define bAntennaMapping 0x10 ++#define bNss 0x20 ++#define bCFOAntSumD 0x200 ++#define bPHYCounterReset 0x8000000 ++#define bCFOReportGet 0x4000000 ++#define bOFDMContinueTx 0x10000000 ++#define bOFDMSingleCarrier 0x20000000 ++#define bOFDMSingleTone 0x40000000 ++//#define bRxPath1 0x01 ++//#define bRxPath2 0x02 ++//#define bRxPath3 0x04 ++//#define bRxPath4 0x08 ++//#define bTxPath1 0x10 ++//#define bTxPath2 0x20 ++#define bHTDetect 0x100 ++#define bCFOEn 0x10000 ++#define bCFOValue 0xfff00000 ++#define bSigTone_Re 0x3f ++#define bSigTone_Im 0x7f00 ++#define bCounter_CCA 0xffff ++#define bCounter_ParityFail 0xffff0000 ++#define bCounter_RateIllegal 0xffff ++#define bCounter_CRC8Fail 0xffff0000 ++#define bCounter_MCSNoSupport 0xffff ++#define bCounter_FastSync 0xffff ++#define bShortCFO 0xfff ++#define bShortCFOTLength 12 //total ++#define bShortCFOFLength 11 //fraction ++#define bLongCFO 0x7ff ++#define bLongCFOTLength 11 ++#define bLongCFOFLength 11 ++#define bTailCFO 0x1fff ++#define bTailCFOTLength 13 ++#define bTailCFOFLength 12 ++#define bmax_en_pwdB 0xffff ++#define bCC_power_dB 0xffff0000 ++#define bnoise_pwdB 0xffff ++#define bPowerMeasTLength 10 ++#define bPowerMeasFLength 3 ++#define bRx_HT_BW 0x1 ++#define bRxSC 0x6 ++#define bRx_HT 0x8 ++#define bNB_intf_det_on 0x1 ++#define bIntf_win_len_cfg 0x30 ++#define bNB_Intf_TH_cfg 0x1c0 ++#define bRFGain 0x3f ++#define bTableSel 0x40 ++#define bTRSW 0x80 ++#define bRxSNR_A 0xff ++#define bRxSNR_B 0xff00 ++#define bRxSNR_C 0xff0000 ++#define bRxSNR_D 0xff000000 ++#define bSNREVMTLength 8 ++#define bSNREVMFLength 1 ++#define bCSI1st 0xff ++#define bCSI2nd 0xff00 ++#define bRxEVM1st 0xff0000 ++#define bRxEVM2nd 0xff000000 ++#define bSIGEVM 0xff ++#define bPWDB 0xff00 ++#define bSGIEN 0x10000 ++ ++#define bSFactorQAM1 0xf // Useless ++#define bSFactorQAM2 0xf0 ++#define bSFactorQAM3 0xf00 ++#define bSFactorQAM4 0xf000 ++#define bSFactorQAM5 0xf0000 ++#define bSFactorQAM6 0xf0000 ++#define bSFactorQAM7 0xf00000 ++#define bSFactorQAM8 0xf000000 ++#define bSFactorQAM9 0xf0000000 ++#define bCSIScheme 0x100000 ++ ++#define bNoiseLvlTopSet 0x3 // Useless ++#define bChSmooth 0x4 ++#define bChSmoothCfg1 0x38 ++#define bChSmoothCfg2 0x1c0 ++#define bChSmoothCfg3 0xe00 ++#define bChSmoothCfg4 0x7000 ++#define bMRCMode 0x800000 ++#define bTHEVMCfg 0x7000000 ++ ++#define bLoopFitType 0x1 // Useless ++#define bUpdCFO 0x40 ++#define bUpdCFOOffData 0x80 ++#define bAdvUpdCFO 0x100 ++#define bAdvTimeCtrl 0x800 ++#define bUpdClko 0x1000 ++#define bFC 0x6000 ++#define bTrackingMode 0x8000 ++#define bPhCmpEnable 0x10000 ++#define bUpdClkoLTF 0x20000 ++#define bComChCFO 0x40000 ++#define bCSIEstiMode 0x80000 ++#define bAdvUpdEqz 0x100000 ++#define bUChCfg 0x7000000 ++#define bUpdEqz 0x8000000 ++ ++#define bTxAGCRate18_06 0x7f7f7f7f // Useless ++#define bTxAGCRate54_24 0x7f7f7f7f ++#define bTxAGCRateMCS32 0x7f ++#define bTxAGCRateCCK 0x7f00 ++#define bTxAGCRateMCS3_MCS0 0x7f7f7f7f ++#define bTxAGCRateMCS7_MCS4 0x7f7f7f7f ++#define bTxAGCRateMCS11_MCS8 0x7f7f7f7f ++#define bTxAGCRateMCS15_MCS12 0x7f7f7f7f ++ ++//Rx Pseduo noise ++#define bRxPesudoNoiseOn 0x20000000 // Useless ++#define bRxPesudoNoise_A 0xff ++#define bRxPesudoNoise_B 0xff00 ++#define bRxPesudoNoise_C 0xff0000 ++#define bRxPesudoNoise_D 0xff000000 ++#define bPesudoNoiseState_A 0xffff ++#define bPesudoNoiseState_B 0xffff0000 ++#define bPesudoNoiseState_C 0xffff ++#define bPesudoNoiseState_D 0xffff0000 ++ ++//7. RF Register ++//Zebra1 ++#define bZebra1_HSSIEnable 0x8 // Useless ++#define bZebra1_TRxControl 0xc00 ++#define bZebra1_TRxGainSetting 0x07f ++#define bZebra1_RxCorner 0xc00 ++#define bZebra1_TxChargePump 0x38 ++#define bZebra1_RxChargePump 0x7 ++#define bZebra1_ChannelNum 0xf80 ++#define bZebra1_TxLPFBW 0x400 ++#define bZebra1_RxLPFBW 0x600 ++ ++//Zebra4 ++#define bRTL8256RegModeCtrl1 0x100 // Useless ++#define bRTL8256RegModeCtrl0 0x40 ++#define bRTL8256_TxLPFBW 0x18 ++#define bRTL8256_RxLPFBW 0x600 ++ ++//RTL8258 ++#define bRTL8258_TxLPFBW 0xc // Useless ++#define bRTL8258_RxLPFBW 0xc00 ++#define bRTL8258_RSSILPFBW 0xc0 ++ ++ ++// ++// Other Definition ++// ++ ++//byte endable for sb_write ++#define bByte0 0x1 // Useless ++#define bByte1 0x2 ++#define bByte2 0x4 ++#define bByte3 0x8 ++#define bWord0 0x3 ++#define bWord1 0xc ++#define bDWord 0xf ++ ++//for PutRegsetting & GetRegSetting BitMask ++#define bMaskByte0 0xff // Reg 0xc50 rOFDM0_XAAGCCore~0xC6f ++#define bMaskByte1 0xff00 ++#define bMaskByte2 0xff0000 ++#define bMaskByte3 0xff000000 ++#define bMaskHWord 0xffff0000 ++#define bMaskLWord 0x0000ffff ++#define bMaskDWord 0xffffffff ++#define bMaskH4Bits 0xf0000000 ++#define bMaskOFDM_D 0xffc00000 ++#define bMaskCCK 0x3f3f3f3f ++#define bMask12Bits 0xfff ++ ++//for PutRFRegsetting & GetRFRegSetting BitMask ++#if (RTL92SE_FPGA_VERIFY == 1) ++//#define bMask12Bits 0xfff // RF Reg mask bits ++//#define bMask20Bits 0xfff // RF Reg mask bits T65 RF ++#define bRFRegOffsetMask 0xfff ++#else ++//#define bMask12Bits 0xfffff // RF Reg mask bits ++//#define bMask20Bits 0xfffff // RF Reg mask bits T65 RF ++#define bRFRegOffsetMask 0xfffff ++#endif ++#define bEnable 0x1 // Useless ++#define bDisable 0x0 ++ ++#define LeftAntenna 0x0 // Useless ++#define RightAntenna 0x1 ++ ++#define tCheckTxStatus 500 //500ms // Useless ++#define tUpdateRxCounter 100 //100ms ++ ++#define rateCCK 0 // Useless ++#define rateOFDM 1 ++#define rateHT 2 ++ ++//define Register-End ++#define bPMAC_End 0x1ff // Useless ++#define bFPGAPHY0_End 0x8ff ++#define bFPGAPHY1_End 0x9ff ++#define bCCKPHY0_End 0xaff ++#define bOFDMPHY0_End 0xcff ++#define bOFDMPHY1_End 0xdff ++ ++//define max debug item in each debug page ++//#define bMaxItem_FPGA_PHY0 0x9 ++//#define bMaxItem_FPGA_PHY1 0x3 ++//#define bMaxItem_PHY_11B 0x16 ++//#define bMaxItem_OFDM_PHY0 0x29 ++//#define bMaxItem_OFDM_PHY1 0x0 ++ ++#define bPMACControl 0x0 // Useless ++#define bWMACControl 0x1 ++#define bWNICControl 0x2 ++ ++#if 0 ++#define ANTENNA_A 0x1 // Useless ++#define ANTENNA_B 0x2 ++#define ANTENNA_AB 0x3 // ANTENNA_A|ANTENNA_B ++ ++#define ANTENNA_C 0x4 ++#define ANTENNA_D 0x8 ++#endif ++ ++#define RCR_AAP BIT(0) // accept all physical address ++#define RCR_APM BIT(1) // accept physical match ++#define RCR_AM BIT(2) // accept multicast ++#define RCR_AB BIT(3) // accept broadcast ++#define RCR_ACRC32 BIT(5) // accept error packet ++#define RCR_9356SEL BIT(6) ++#define RCR_AICV BIT(12) // Accept ICV error packet ++#define RCR_RXFTH0 (BIT(13)|BIT(14)|BIT(15)) // Rx FIFO threshold ++#define RCR_ADF BIT(18) // Accept Data(frame type) frame ++#define RCR_ACF BIT(19) // Accept control frame ++#define RCR_AMF BIT(20) // Accept management frame ++#define RCR_ADD3 BIT(21) ++#define RCR_APWRMGT BIT(22) // Accept power management packet ++#define RCR_CBSSID BIT(23) // Accept BSSID match packet ++#define RCR_ENMARP BIT(28) // enable mac auto reset phy ++#define RCR_EnCS1 BIT(29) // enable carrier sense method 1 ++#define RCR_EnCS2 BIT(30) // enable carrier sense method 2 ++#define RCR_OnlyErlPkt BIT(31) // Rx Early mode is performed for packet size greater than 1536 ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++ ++#endif //__INC_HAL8192SPHYREG_H ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_odm.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_odm.h +new file mode 100644 +index 00000000..d01acd64 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_odm.h +@@ -0,0 +1,42 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2013 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTW_ODM_H__ ++#define __RTW_ODM_H__ ++ ++#include ++ ++/* ++* This file provides utilities/wrappers for rtw driver to use ODM ++*/ ++ ++int _rtw_odm_dbg_comp_msg(_adapter *adapter, char *buf, int len); ++void rtw_odm_dbg_comp_msg(_adapter *adapter); ++void rtw_odm_dbg_comp_set(_adapter *adapter, u64 comps); ++int _rtw_odm_dbg_level_msg(_adapter *adapter, char *buf, int len); ++void rtw_odm_dbg_level_msg(_adapter *adapter); ++void rtw_odm_dbg_level_set(_adapter *adapter, u32 level); ++ ++int _rtw_odm_adaptivity_parm_msg(_adapter *adapter, char *buf, int len); ++void rtw_odm_adaptivity_parm_msg(_adapter *adapter); ++void rtw_odm_adaptivity_parm_set(_adapter *adapter, s8 TH_L2H_ini, s8 TH_EDCCA_HL_diff, ++ s8 IGI_Base, bool ForceEDCCA, u8 AdapEn_RSSI, u8 IGI_LowerBound); ++ ++#endif // __RTW_ODM_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_p2p.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_p2p.h +new file mode 100644 +index 00000000..4249bc96 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_p2p.h +@@ -0,0 +1,161 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTW_P2P_H_ ++#define __RTW_P2P_H_ ++ ++#include ++ ++u32 build_beacon_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++u32 build_probe_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++u32 build_prov_disc_request_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8* pssid, u8 ussidlen, u8* pdev_raddr ); ++u32 build_assoc_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 status_code); ++u32 build_deauth_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++#ifdef CONFIG_WFD ++u32 build_probe_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunneled); ++u32 build_beacon_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++u32 build_nego_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++u32 build_nego_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++u32 build_nego_confirm_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++u32 build_invitation_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++u32 build_invitation_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++u32 build_assoc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++u32 build_assoc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++u32 build_provdisc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++u32 build_provdisc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++#endif //CONFIG_WFD ++ ++u32 process_probe_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint len); ++u32 process_assoc_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint len, struct sta_info *psta); ++u32 process_p2p_devdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len); ++u32 process_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe, uint len); ++u8 process_p2p_provdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len); ++u8 process_p2p_provdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe); ++u8 process_p2p_group_negotation_req( struct wifidirect_info *pwdinfo, u8 *pframe, uint len ); ++u8 process_p2p_group_negotation_resp( struct wifidirect_info *pwdinfo, u8 *pframe, uint len ); ++u8 process_p2p_group_negotation_confirm( struct wifidirect_info *pwdinfo, u8 *pframe, uint len ); ++u8 process_p2p_presence_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len); ++ ++void p2p_protocol_wk_hdl(_adapter *padapter, int intCmdType); ++ ++#ifdef CONFIG_P2P_PS ++void process_p2p_ps_ie(PADAPTER padapter, u8 *IEs, u32 IELength); ++void p2p_ps_wk_hdl(_adapter *padapter, u8 p2p_ps_state); ++u8 p2p_ps_wk_cmd(_adapter*padapter, u8 p2p_ps_state, u8 enqueue); ++#endif // CONFIG_P2P_PS ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++void rtw_init_cfg80211_wifidirect_info( _adapter* padapter); ++int rtw_p2p_check_frames(_adapter *padapter, const u8 *buf, u32 len, u8 tx); ++void rtw_append_wfd_ie(_adapter *padapter, u8 *buf, u32 *len); ++#endif //CONFIG_IOCTL_CFG80211 ++ ++void reset_global_wifidirect_info( _adapter* padapter ); ++int rtw_init_wifi_display_info(_adapter* padapter); ++void rtw_init_wifidirect_timers(_adapter* padapter); ++void rtw_init_wifidirect_addrs(_adapter* padapter, u8 *dev_addr, u8 *iface_addr); ++void init_wifidirect_info( _adapter* padapter, enum P2P_ROLE role); ++int rtw_p2p_enable(_adapter *padapter, enum P2P_ROLE role); ++ ++static inline void _rtw_p2p_set_state(struct wifidirect_info *wdinfo, enum P2P_STATE state) ++{ ++ if(wdinfo->p2p_state != state) { ++ //wdinfo->pre_p2p_state = wdinfo->p2p_state; ++ wdinfo->p2p_state = state; ++ } ++} ++static inline void _rtw_p2p_set_pre_state(struct wifidirect_info *wdinfo, enum P2P_STATE state) ++{ ++ if(wdinfo->pre_p2p_state != state) { ++ wdinfo->pre_p2p_state = state; ++ } ++} ++#if 0 ++static inline void _rtw_p2p_restore_state(struct wifidirect_info *wdinfo) ++{ ++ if(wdinfo->pre_p2p_state != -1) { ++ wdinfo->p2p_state = wdinfo->pre_p2p_state; ++ wdinfo->pre_p2p_state = -1; ++ } ++} ++#endif ++static inline void _rtw_p2p_set_role(struct wifidirect_info *wdinfo, enum P2P_ROLE role) ++{ ++ if(wdinfo->role != role) { ++ wdinfo->role = role; ++ } ++} ++static inline int _rtw_p2p_state(struct wifidirect_info *wdinfo) ++{ ++ return wdinfo->p2p_state; ++} ++static inline int _rtw_p2p_pre_state(struct wifidirect_info *wdinfo) ++{ ++ return wdinfo->pre_p2p_state; ++} ++static inline int _rtw_p2p_role(struct wifidirect_info *wdinfo) ++{ ++ return wdinfo->role; ++} ++static inline bool _rtw_p2p_chk_state(struct wifidirect_info *wdinfo, enum P2P_STATE state) ++{ ++ return wdinfo->p2p_state == state; ++} ++static inline bool _rtw_p2p_chk_role(struct wifidirect_info *wdinfo, enum P2P_ROLE role) ++{ ++ return wdinfo->role == role; ++} ++ ++#ifdef CONFIG_DBG_P2P ++void dbg_rtw_p2p_set_state(struct wifidirect_info *wdinfo, enum P2P_STATE state, const char *caller, int line); ++void dbg_rtw_p2p_set_pre_state(struct wifidirect_info *wdinfo, enum P2P_STATE state, const char *caller, int line); ++//void dbg_rtw_p2p_restore_state(struct wifidirect_info *wdinfo, const char *caller, int line); ++void dbg_rtw_p2p_set_role(struct wifidirect_info *wdinfo, enum P2P_ROLE role, const char *caller, int line); ++#define rtw_p2p_set_state(wdinfo, state) dbg_rtw_p2p_set_state(wdinfo, state, __FUNCTION__, __LINE__) ++#define rtw_p2p_set_pre_state(wdinfo, state) dbg_rtw_p2p_set_pre_state(wdinfo, state, __FUNCTION__, __LINE__) ++#define rtw_p2p_set_role(wdinfo, role) dbg_rtw_p2p_set_role(wdinfo, role, __FUNCTION__, __LINE__) ++//#define rtw_p2p_restore_state(wdinfo) dbg_rtw_p2p_restore_state(wdinfo, __FUNCTION__, __LINE__) ++#else //CONFIG_DBG_P2P ++#define rtw_p2p_set_state(wdinfo, state) _rtw_p2p_set_state(wdinfo, state) ++#define rtw_p2p_set_pre_state(wdinfo, state) _rtw_p2p_set_pre_state(wdinfo, state) ++#define rtw_p2p_set_role(wdinfo, role) _rtw_p2p_set_role(wdinfo, role) ++//#define rtw_p2p_restore_state(wdinfo) _rtw_p2p_restore_state(wdinfo) ++#endif //CONFIG_DBG_P2P ++ ++#define rtw_p2p_state(wdinfo) _rtw_p2p_state(wdinfo) ++#define rtw_p2p_pre_state(wdinfo) _rtw_p2p_pre_state(wdinfo) ++#define rtw_p2p_role(wdinfo) _rtw_p2p_role(wdinfo) ++#define rtw_p2p_chk_state(wdinfo, state) _rtw_p2p_chk_state(wdinfo, state) ++#define rtw_p2p_chk_role(wdinfo, role) _rtw_p2p_chk_role(wdinfo, role) ++ ++#define rtw_p2p_findphase_ex_set(wdinfo, value) \ ++ (wdinfo)->find_phase_state_exchange_cnt = (value) ++ ++//is this find phase exchange for social channel scan? ++#define rtw_p2p_findphase_ex_is_social(wdinfo) \ ++ (wdinfo)->find_phase_state_exchange_cnt >= P2P_FINDPHASE_EX_SOCIAL_FIRST ++ ++//should we need find phase exchange anymore? ++#define rtw_p2p_findphase_ex_is_needed(wdinfo) \ ++ ((wdinfo)->find_phase_state_exchange_cnt < P2P_FINDPHASE_EX_MAX && \ ++ (wdinfo)->find_phase_state_exchange_cnt != P2P_FINDPHASE_EX_NONE) ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_pwrctrl.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_pwrctrl.h +new file mode 100644 +index 00000000..4b63a1e0 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_pwrctrl.h +@@ -0,0 +1,384 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTW_PWRCTRL_H_ ++#define __RTW_PWRCTRL_H_ ++ ++#include ++#include ++#include ++ ++#ifdef CONFIG_HAS_EARLYSUSPEND ++#include ++#endif //CONFIG_HAS_EARLYSUSPEND ++ ++ ++#define FW_PWR0 0 ++#define FW_PWR1 1 ++#define FW_PWR2 2 ++#define FW_PWR3 3 ++ ++ ++#define HW_PWR0 7 ++#define HW_PWR1 6 ++#define HW_PWR2 2 ++#define HW_PWR3 0 ++#define HW_PWR4 8 ++ ++#define FW_PWRMSK 0x7 ++ ++ ++#define XMIT_ALIVE BIT(0) ++#define RECV_ALIVE BIT(1) ++#define CMD_ALIVE BIT(2) ++#define EVT_ALIVE BIT(3) ++ ++ ++enum Power_Mgnt ++{ ++ PS_MODE_ACTIVE = 0 , ++ PS_MODE_MIN , ++ PS_MODE_MAX , ++ PS_MODE_DTIM , ++ PS_MODE_VOIP , ++ PS_MODE_UAPSD_WMM , ++ PS_MODE_UAPSD , ++ PS_MODE_IBSS , ++ PS_MODE_WWLAN , ++ PM_Radio_Off , ++ PM_Card_Disable , ++ PS_MODE_NUM ++}; ++ ++ ++/* ++ BIT[2:0] = HW state ++ BIT[3] = Protocol PS state, 0: register active state , 1: register sleep state ++ BIT[4] = sub-state ++*/ ++ ++#define PS_DPS BIT(0) ++#define PS_LCLK (PS_DPS) ++#define PS_RF_OFF BIT(1) ++#define PS_ALL_ON BIT(2) ++#define PS_ST_ACTIVE BIT(3) ++ ++#define PS_ISR_ENABLE BIT(4) ++#define PS_IMR_ENABLE BIT(5) ++#define PS_ACK BIT(6) ++#define PS_TOGGLE BIT(7) ++ ++#define PS_STATE_MASK (0x0F) ++#define PS_STATE_HW_MASK (0x07) ++#define PS_SEQ_MASK (0xc0) ++ ++#define PS_STATE(x) (PS_STATE_MASK & (x)) ++#define PS_STATE_HW(x) (PS_STATE_HW_MASK & (x)) ++#define PS_SEQ(x) (PS_SEQ_MASK & (x)) ++ ++#define PS_STATE_S0 (PS_DPS) ++#define PS_STATE_S1 (PS_LCLK) ++#define PS_STATE_S2 (PS_RF_OFF) ++#define PS_STATE_S3 (PS_ALL_ON) ++#define PS_STATE_S4 ((PS_ST_ACTIVE) | (PS_ALL_ON)) ++ ++ ++#define PS_IS_RF_ON(x) ((x) & (PS_ALL_ON)) ++#define PS_IS_ACTIVE(x) ((x) & (PS_ST_ACTIVE)) ++#define CLR_PS_STATE(x) ((x) = ((x) & (0xF0))) ++ ++ ++struct reportpwrstate_parm { ++ unsigned char mode; ++ unsigned char state; //the CPWM value ++ unsigned short rsvd; ++}; ++ ++ ++typedef _sema _pwrlock; ++ ++ ++__inline static void _init_pwrlock(_pwrlock *plock) ++{ ++ _rtw_init_sema(plock, 1); ++} ++ ++__inline static void _free_pwrlock(_pwrlock *plock) ++{ ++ _rtw_free_sema(plock); ++} ++ ++ ++__inline static void _enter_pwrlock(_pwrlock *plock) ++{ ++ _rtw_down_sema(plock); ++} ++ ++ ++__inline static void _exit_pwrlock(_pwrlock *plock) ++{ ++ _rtw_up_sema(plock); ++} ++ ++#define LPS_DELAY_TIME 1*HZ // 1 sec ++ ++#define EXE_PWR_NONE 0x01 ++#define EXE_PWR_IPS 0x02 ++#define EXE_PWR_LPS 0x04 ++ ++// RF state. ++typedef enum _rt_rf_power_state ++{ ++ rf_on, // RF is on after RFSleep or RFOff ++ rf_sleep, // 802.11 Power Save mode ++ rf_off, // HW/SW Radio OFF or Inactive Power Save ++ //=====Add the new RF state above this line=====// ++ rf_max ++}rt_rf_power_state; ++ ++// RF Off Level for IPS or HW/SW radio off ++#define RT_RF_OFF_LEVL_ASPM BIT(0) // PCI ASPM ++#define RT_RF_OFF_LEVL_CLK_REQ BIT(1) // PCI clock request ++#define RT_RF_OFF_LEVL_PCI_D3 BIT(2) // PCI D3 mode ++#define RT_RF_OFF_LEVL_HALT_NIC BIT(3) // NIC halt, re-initialize hw parameters ++#define RT_RF_OFF_LEVL_FREE_FW BIT(4) // FW free, re-download the FW ++#define RT_RF_OFF_LEVL_FW_32K BIT(5) // FW in 32k ++#define RT_RF_PS_LEVEL_ALWAYS_ASPM BIT(6) // Always enable ASPM and Clock Req in initialization. ++#define RT_RF_LPS_DISALBE_2R BIT(30) // When LPS is on, disable 2R if no packet is received or transmittd. ++#define RT_RF_LPS_LEVEL_ASPM BIT(31) // LPS with ASPM ++ ++#define RT_IN_PS_LEVEL(ppsc, _PS_FLAG) ((ppsc->cur_ps_level & _PS_FLAG) ? _TRUE : _FALSE) ++#define RT_CLEAR_PS_LEVEL(ppsc, _PS_FLAG) (ppsc->cur_ps_level &= (~(_PS_FLAG))) ++#define RT_SET_PS_LEVEL(ppsc, _PS_FLAG) (ppsc->cur_ps_level |= _PS_FLAG) ++ ++ ++enum _PS_BBRegBackup_ { ++ PSBBREG_RF0 = 0, ++ PSBBREG_RF1, ++ PSBBREG_RF2, ++ PSBBREG_AFE0, ++ PSBBREG_TOTALCNT ++}; ++ ++enum { // for ips_mode ++ IPS_NONE=0, ++ IPS_NORMAL, ++ IPS_LEVEL_2, ++}; ++ ++struct pwrctrl_priv ++{ ++ _pwrlock lock; ++ volatile u8 rpwm; // requested power state for fw ++ volatile u8 cpwm; // fw current power state. updated when 1. read from HCPWM 2. driver lowers power level ++ volatile u8 tog; // toggling ++ volatile u8 cpwm_tog; // toggling ++ ++ u8 pwr_mode; ++ u8 smart_ps; ++ u8 bcn_ant_mode; ++ ++ u32 alives; ++ _workitem cpwm_event; ++#ifdef CONFIG_LPS_RPWM_TIMER ++ u8 brpwmtimeout; ++ _workitem rpwmtimeoutwi; ++ _timer pwr_rpwm_timer; ++#endif // CONFIG_LPS_RPWM_TIMER ++ u8 bpower_saving; ++ ++ u8 b_hw_radio_off; ++ u8 reg_rfoff; ++ u8 reg_pdnmode; //powerdown mode ++ u32 rfoff_reason; ++ ++ //RF OFF Level ++ u32 cur_ps_level; ++ u32 reg_rfps_level; ++ ++ ++ ++#ifdef CONFIG_PCI_HCI ++ //just for PCIE ASPM ++ u8 b_support_aspm; // If it supports ASPM, Offset[560h] = 0x40, otherwise Offset[560h] = 0x00. ++ u8 b_support_backdoor; ++ ++ //just for PCIE ASPM ++ u8 const_amdpci_aspm; ++#endif ++ ++ uint ips_enter_cnts; ++ uint ips_leave_cnts; ++ ++ u8 ips_mode; ++ u8 ips_mode_req; // used to accept the mode setting request, will update to ipsmode later ++ uint bips_processing; ++ u32 ips_deny_time; /* will deny IPS when system time is smaller than this */ ++ u8 ps_processing; /* temporarily used to mark whether in rtw_ps_processor */ ++ ++ u8 bLeisurePs; ++ u8 LpsIdleCount; ++ u8 power_mgnt; ++ u8 bFwCurrentInPSMode; ++ u32 DelayLPSLastTimeStamp; ++ u8 btcoex_rfon; ++ s32 pnp_current_pwr_state; ++ u8 pnp_bstop_trx; ++ ++ ++ u8 bInternalAutoSuspend; ++ u8 bInSuspend; ++#ifdef CONFIG_BT_COEXIST ++ u8 bAutoResume; ++ u8 autopm_cnt; ++#endif ++ u8 bSupportRemoteWakeup; ++#ifdef CONFIG_WOWLAN ++ u8 wowlan_mode; ++ u8 wowlan_pattern; ++ u8 wowlan_magic; ++ u8 wowlan_unicast; ++ u8 wowlan_pattern_idx; ++ u8 wowlan_wake_reason; ++ u32 wowlan_pattern_context[8][5]; ++ u64 wowlan_fw_iv; ++#endif // CONFIG_WOWLAN ++ _timer pwr_state_check_timer; ++ int pwr_state_check_interval; ++ u8 pwr_state_check_cnts; ++ ++ int ps_flag; ++ ++ rt_rf_power_state rf_pwrstate;//cur power state ++ //rt_rf_power_state current_rfpwrstate; ++ rt_rf_power_state change_rfpwrstate; ++ ++ u8 bHWPowerdown;//if support hw power down ++ u8 bHWPwrPindetect; ++ u8 bkeepfwalive; ++ u8 brfoffbyhw; ++ unsigned long PS_BBRegBackup[PSBBREG_TOTALCNT]; ++ ++ #ifdef CONFIG_RESUME_IN_WORKQUEUE ++ struct workqueue_struct *rtw_workqueue; ++ _workitem resume_work; ++ #endif ++ ++ #ifdef CONFIG_HAS_EARLYSUSPEND ++ struct early_suspend early_suspend; ++ u8 do_late_resume; ++ #endif //CONFIG_HAS_EARLYSUSPEND ++ ++ #ifdef CONFIG_ANDROID_POWER ++ android_early_suspend_t early_suspend; ++ u8 do_late_resume; ++ #endif ++ ++ #ifdef CONFIG_INTEL_PROXIM ++ u8 stored_power_mgnt; ++ #endif ++}; ++ ++#define rtw_get_ips_mode_req(pwrctl) \ ++ (pwrctl)->ips_mode_req ++ ++#define rtw_ips_mode_req(pwrctl, ips_mode) \ ++ (pwrctl)->ips_mode_req = (ips_mode) ++ ++#define RTW_PWR_STATE_CHK_INTERVAL 2000 ++ ++#define _rtw_set_pwr_state_check_timer(pwrctl, ms) \ ++ do { \ ++ /*DBG_871X("%s _rtw_set_pwr_state_check_timer(%p, %d)\n", __FUNCTION__, (pwrctl), (ms));*/ \ ++ _set_timer(&(pwrctl)->pwr_state_check_timer, (ms)); \ ++ } while(0) ++ ++#define rtw_set_pwr_state_check_timer(pwrctl) \ ++ _rtw_set_pwr_state_check_timer((pwrctl), (pwrctl)->pwr_state_check_interval) ++ ++extern void rtw_init_pwrctrl_priv(_adapter *adapter); ++extern void rtw_free_pwrctrl_priv(_adapter * adapter); ++ ++#ifdef CONFIG_LPS_LCLK ++extern s32 rtw_register_tx_alive(PADAPTER padapter); ++extern void rtw_unregister_tx_alive(PADAPTER padapter); ++extern s32 rtw_register_rx_alive(PADAPTER padapter); ++extern void rtw_unregister_rx_alive(PADAPTER padapter); ++extern s32 rtw_register_cmd_alive(PADAPTER padapter); ++extern void rtw_unregister_cmd_alive(PADAPTER padapter); ++extern s32 rtw_register_evt_alive(PADAPTER padapter); ++extern void rtw_unregister_evt_alive(PADAPTER padapter); ++extern void cpwm_int_hdl(PADAPTER padapter, struct reportpwrstate_parm *preportpwrstate); ++extern void LPS_Leave_check(PADAPTER padapter); ++#endif ++ ++extern void rtw_set_ps_mode(PADAPTER padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode); ++extern void rtw_set_rpwm(_adapter * padapter, u8 val8); ++extern void LeaveAllPowerSaveMode(PADAPTER Adapter); ++#ifdef CONFIG_IPS ++void _ips_enter(_adapter * padapter); ++void ips_enter(_adapter * padapter); ++int _ips_leave(_adapter * padapter); ++int ips_leave(_adapter * padapter); ++#endif ++ ++void rtw_ps_processor(_adapter*padapter); ++ ++#ifdef CONFIG_AUTOSUSPEND ++int autoresume_enter(_adapter* padapter); ++#endif ++#ifdef SUPPORT_HW_RFOFF_DETECTED ++rt_rf_power_state RfOnOffDetect(IN PADAPTER pAdapter ); ++#endif ++ ++ ++#ifdef CONFIG_LPS ++s32 LPS_RF_ON_check(PADAPTER padapter, u32 delay_ms); ++void LPS_Enter(PADAPTER padapter); ++void LPS_Leave(PADAPTER padapter); ++#endif ++ ++#ifdef CONFIG_RESUME_IN_WORKQUEUE ++void rtw_resume_in_workqueue(struct pwrctrl_priv *pwrpriv); ++#endif //CONFIG_RESUME_IN_WORKQUEUE ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND ) || defined(CONFIG_ANDROID_POWER) ++bool rtw_is_earlysuspend_registered(struct pwrctrl_priv *pwrpriv); ++bool rtw_is_do_late_resume(struct pwrctrl_priv *pwrpriv); ++void rtw_set_do_late_resume(struct pwrctrl_priv *pwrpriv, bool enable); ++void rtw_register_early_suspend(struct pwrctrl_priv *pwrpriv); ++void rtw_unregister_early_suspend(struct pwrctrl_priv *pwrpriv); ++#else ++#define rtw_is_earlysuspend_registered(pwrpriv) _FALSE ++#define rtw_is_do_late_resume(pwrpriv) _FALSE ++#define rtw_set_do_late_resume(pwrpriv, enable) do {} while (0) ++#define rtw_register_early_suspend(pwrpriv) do {} while (0) ++#define rtw_unregister_early_suspend(pwrpriv) do {} while (0) ++#endif /* CONFIG_HAS_EARLYSUSPEND || CONFIG_ANDROID_POWER */ ++ ++u8 rtw_interface_ps_func(_adapter *padapter,HAL_INTF_PS_FUNC efunc_id,u8* val); ++void rtw_set_ips_deny(_adapter *padapter, u32 ms); ++int _rtw_pwr_wakeup(_adapter *padapter, u32 ips_deffer_ms, const char *caller); ++#define rtw_pwr_wakeup(adapter) _rtw_pwr_wakeup(adapter, RTW_PWR_STATE_CHK_INTERVAL, __FUNCTION__) ++#define rtw_pwr_wakeup_ex(adapter, ips_deffer_ms) _rtw_pwr_wakeup(adapter, ips_deffer_ms, __FUNCTION__) ++int rtw_pm_set_ips(_adapter *padapter, u8 mode); ++int rtw_pm_set_lps(_adapter *padapter, u8 mode); ++ ++#endif //__RTL871X_PWRCTRL_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_qos.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_qos.h +new file mode 100644 +index 00000000..a359c5fe +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_qos.h +@@ -0,0 +1,40 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++ ++#ifndef _RTW_QOS_H_ ++#define _RTW_QOS_H_ ++#include ++#include ++ ++ ++ ++ ++ ++ ++struct qos_priv { ++ ++ unsigned int qos_option; //bit mask option: u-apsd, s-apsd, ts, block ack... ++ ++}; ++ ++ ++#endif //_RTL871X_QOS_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_recv.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_recv.h +new file mode 100644 +index 00000000..97ffea34 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_recv.h +@@ -0,0 +1,758 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTW_RECV_H_ ++#define _RTW_RECV_H_ ++ ++#include ++#include ++#include ++ ++ ++#define NR_RECVFRAME 256 ++ ++#define RXFRAME_ALIGN 8 ++#define RXFRAME_ALIGN_SZ (1<signal_stat_timer, (recvpriv)->signal_stat_sampling_interval) ++#endif //CONFIG_NEW_SIGNAL_STAT_PROCESS ++ ++struct sta_recv_priv { ++ ++ _lock lock; ++ sint option; ++ ++ //_queue blk_strms[MAX_RX_NUMBLKS]; ++ _queue defrag_q; //keeping the fragment frame until defrag ++ ++ struct stainfo_rxcache rxcache; ++ ++ //uint sta_rx_bytes; ++ //uint sta_rx_pkts; ++ //uint sta_rx_fail; ++ ++}; ++ ++ ++struct recv_buf ++{ ++ _list list; ++ ++ _lock recvbuf_lock; ++ ++ u32 ref_cnt; ++ ++ PADAPTER adapter; ++ ++ u8 *pbuf; ++ u8 *pallocated_buf; ++ ++ u32 len; ++ u8 *phead; ++ u8 *pdata; ++ u8 *ptail; ++ u8 *pend; ++ ++#ifdef CONFIG_USB_HCI ++ ++ #if defined(PLATFORM_OS_XP)||defined(PLATFORM_LINUX)||defined(PLATFORM_FREEBSD) ++ PURB purb; ++ dma_addr_t dma_transfer_addr; /* (in) dma addr for transfer_buffer */ ++ u32 alloc_sz; ++ #endif ++ ++ #ifdef PLATFORM_OS_XP ++ PIRP pirp; ++ #endif ++ ++ #ifdef PLATFORM_OS_CE ++ USB_TRANSFER usb_transfer_read_port; ++ #endif ++ ++ u8 irp_pending; ++ int transfer_len; ++ ++#endif ++ ++#ifdef PLATFORM_LINUX ++ _pkt *pskb; ++ u8 reuse; ++#endif ++#ifdef PLATFORM_FREEBSD //skb solution ++ struct sk_buff *pskb; ++ u8 reuse; ++#endif //PLATFORM_FREEBSD //skb solution ++}; ++ ++ ++/* ++ head -----> ++ ++ data -----> ++ ++ payload ++ ++ tail -----> ++ ++ ++ end -----> ++ ++ len = (unsigned int )(tail - data); ++ ++*/ ++struct recv_frame_hdr ++{ ++ _list list; ++#ifndef CONFIG_BSD_RX_USE_MBUF ++ struct sk_buff *pkt; ++ struct sk_buff *pkt_newalloc; ++#else // CONFIG_BSD_RX_USE_MBUF ++ _pkt *pkt; ++ _pkt *pkt_newalloc; ++#endif // CONFIG_BSD_RX_USE_MBUF ++ ++ _adapter *adapter; ++ ++ u8 fragcnt; ++ ++ int frame_tag; ++ ++ struct rx_pkt_attrib attrib; ++ ++ uint len; ++ u8 *rx_head; ++ u8 *rx_data; ++ u8 *rx_tail; ++ u8 *rx_end; ++ ++ void *precvbuf; ++ ++ ++ // ++ struct sta_info *psta; ++ ++ //for A-MPDU Rx reordering buffer control ++ struct recv_reorder_ctrl *preorder_ctrl; ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ u8 UserPriority; ++ u8 WapiTempPN[16]; ++ u8 WapiSrcAddr[6]; ++ u8 bWapiCheckPNInDecrypt; ++ u8 bIsWaiPacket; ++#endif ++ ++}; ++ ++ ++union recv_frame{ ++ ++ union{ ++ _list list; ++ struct recv_frame_hdr hdr; ++ uint mem[RECVFRAME_HDR_ALIGN>>2]; ++ }u; ++ ++ //uint mem[MAX_RXSZ>>2]; ++ ++}; ++ ++ ++extern union recv_frame *_rtw_alloc_recvframe (_queue *pfree_recv_queue); //get a free recv_frame from pfree_recv_queue ++extern union recv_frame *rtw_alloc_recvframe (_queue *pfree_recv_queue); //get a free recv_frame from pfree_recv_queue ++extern void rtw_init_recvframe(union recv_frame *precvframe ,struct recv_priv *precvpriv); ++extern int rtw_free_recvframe(union recv_frame *precvframe, _queue *pfree_recv_queue); ++ ++#define rtw_dequeue_recvframe(queue) rtw_alloc_recvframe(queue) ++extern int _rtw_enqueue_recvframe(union recv_frame *precvframe, _queue *queue); ++extern int rtw_enqueue_recvframe(union recv_frame *precvframe, _queue *queue); ++ ++extern void rtw_free_recvframe_queue(_queue *pframequeue, _queue *pfree_recv_queue); ++u32 rtw_free_uc_swdec_pending_queue(_adapter *adapter); ++ ++sint rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, _queue *queue); ++sint rtw_enqueue_recvbuf(struct recv_buf *precvbuf, _queue *queue); ++struct recv_buf *rtw_dequeue_recvbuf (_queue *queue); ++ ++void rtw_reordering_ctrl_timeout_handler(void *pcontext); ++ ++__inline static u8 *get_rxmem(union recv_frame *precvframe) ++{ ++ //always return rx_head... ++ if(precvframe==NULL) ++ return NULL; ++ ++ return precvframe->u.hdr.rx_head; ++} ++ ++__inline static u8 *get_rx_status(union recv_frame *precvframe) ++{ ++ ++ return get_rxmem(precvframe); ++ ++} ++ ++__inline static u8 *get_recvframe_data(union recv_frame *precvframe) ++{ ++ ++ //alwasy return rx_data ++ if(precvframe==NULL) ++ return NULL; ++ ++ return precvframe->u.hdr.rx_data; ++ ++} ++ ++__inline static u8 *recvframe_push(union recv_frame *precvframe, sint sz) ++{ ++ // append data before rx_data ++ ++ /* add data to the start of recv_frame ++ * ++ * This function extends the used data area of the recv_frame at the buffer ++ * start. rx_data must be still larger than rx_head, after pushing. ++ */ ++ ++ if(precvframe==NULL) ++ return NULL; ++ ++ ++ precvframe->u.hdr.rx_data -= sz ; ++ if( precvframe->u.hdr.rx_data < precvframe->u.hdr.rx_head ) ++ { ++ precvframe->u.hdr.rx_data += sz ; ++ return NULL; ++ } ++ ++ precvframe->u.hdr.len +=sz; ++ ++ return precvframe->u.hdr.rx_data; ++ ++} ++ ++ ++__inline static u8 *recvframe_pull(union recv_frame *precvframe, sint sz) ++{ ++ // rx_data += sz; move rx_data sz bytes hereafter ++ ++ //used for extract sz bytes from rx_data, update rx_data and return the updated rx_data to the caller ++ ++ ++ if(precvframe==NULL) ++ return NULL; ++ ++ ++ precvframe->u.hdr.rx_data += sz; ++ ++ if(precvframe->u.hdr.rx_data > precvframe->u.hdr.rx_tail) ++ { ++ precvframe->u.hdr.rx_data -= sz; ++ return NULL; ++ } ++ ++ precvframe->u.hdr.len -=sz; ++ ++ return precvframe->u.hdr.rx_data; ++ ++} ++ ++__inline static u8 *recvframe_put(union recv_frame *precvframe, sint sz) ++{ ++ // rx_tai += sz; move rx_tail sz bytes hereafter ++ ++ //used for append sz bytes from ptr to rx_tail, update rx_tail and return the updated rx_tail to the caller ++ //after putting, rx_tail must be still larger than rx_end. ++ unsigned char * prev_rx_tail; ++ ++ if(precvframe==NULL) ++ return NULL; ++ ++ prev_rx_tail = precvframe->u.hdr.rx_tail; ++ ++ precvframe->u.hdr.rx_tail += sz; ++ ++ if(precvframe->u.hdr.rx_tail > precvframe->u.hdr.rx_end) ++ { ++ precvframe->u.hdr.rx_tail -= sz; ++ return NULL; ++ } ++ ++ precvframe->u.hdr.len +=sz; ++ ++ return precvframe->u.hdr.rx_tail; ++ ++} ++ ++ ++ ++__inline static u8 *recvframe_pull_tail(union recv_frame *precvframe, sint sz) ++{ ++ // rmv data from rx_tail (by yitsen) ++ ++ //used for extract sz bytes from rx_end, update rx_end and return the updated rx_end to the caller ++ //after pulling, rx_end must be still larger than rx_data. ++ ++ if(precvframe==NULL) ++ return NULL; ++ ++ precvframe->u.hdr.rx_tail -= sz; ++ ++ if(precvframe->u.hdr.rx_tail < precvframe->u.hdr.rx_data) ++ { ++ precvframe->u.hdr.rx_tail += sz; ++ return NULL; ++ } ++ ++ precvframe->u.hdr.len -=sz; ++ ++ return precvframe->u.hdr.rx_tail; ++ ++} ++ ++ ++ ++__inline static _buffer * get_rxbuf_desc(union recv_frame *precvframe) ++{ ++ _buffer * buf_desc; ++ ++ if(precvframe==NULL) ++ return NULL; ++#ifdef PLATFORM_WINDOWS ++ NdisQueryPacket(precvframe->u.hdr.pkt, NULL, NULL, &buf_desc, NULL); ++#endif ++ ++ return buf_desc; ++} ++ ++ ++__inline static union recv_frame *rxmem_to_recvframe(u8 *rxmem) ++{ ++ //due to the design of 2048 bytes alignment of recv_frame, we can reference the union recv_frame ++ //from any given member of recv_frame. ++ // rxmem indicates the any member/address in recv_frame ++ ++ return (union recv_frame*)(((SIZE_PTR)rxmem >> RXFRAME_ALIGN) << RXFRAME_ALIGN); ++ ++} ++ ++__inline static union recv_frame *pkt_to_recvframe(_pkt *pkt) ++{ ++ ++ u8 * buf_star; ++ union recv_frame * precv_frame; ++#ifdef PLATFORM_WINDOWS ++ _buffer * buf_desc; ++ uint len; ++ ++ NdisQueryPacket(pkt, NULL, NULL, &buf_desc, &len); ++ NdisQueryBufferSafe(buf_desc, &buf_star, &len, HighPagePriority); ++#endif ++ precv_frame = rxmem_to_recvframe((unsigned char*)buf_star); ++ ++ return precv_frame; ++} ++ ++__inline static u8 *pkt_to_recvmem(_pkt *pkt) ++{ ++ // return the rx_head ++ ++ union recv_frame * precv_frame = pkt_to_recvframe(pkt); ++ ++ return precv_frame->u.hdr.rx_head; ++ ++} ++ ++__inline static u8 *pkt_to_recvdata(_pkt *pkt) ++{ ++ // return the rx_data ++ ++ union recv_frame * precv_frame =pkt_to_recvframe(pkt); ++ ++ return precv_frame->u.hdr.rx_data; ++ ++} ++ ++ ++__inline static sint get_recvframe_len(union recv_frame *precvframe) ++{ ++ return precvframe->u.hdr.len; ++} ++ ++ ++__inline static s32 translate_percentage_to_dbm(u32 SignalStrengthIndex) ++{ ++ s32 SignalPower; // in dBm. ++ ++ // Translate to dBm (x=0.5y-95). ++ SignalPower = (s32)((SignalStrengthIndex + 1) >> 1); ++ SignalPower -= 95; ++ ++ return SignalPower; ++} ++ ++ ++struct sta_info; ++ ++extern void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv); ++ ++extern void mgt_dispatcher(_adapter *padapter, union recv_frame *precv_frame); ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_rf.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_rf.h +new file mode 100644 +index 00000000..6ca44004 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_rf.h +@@ -0,0 +1,158 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTW_RF_H_ ++#define __RTW_RF_H_ ++ ++#include ++#include ++ ++#define OFDM_PHY 1 ++#define MIXED_PHY 2 ++#define CCK_PHY 3 ++ ++#define NumRates (13) ++ ++// slot time for 11g ++#define SHORT_SLOT_TIME 9 ++#define NON_SHORT_SLOT_TIME 20 ++ ++#define RTL8711_RF_MAX_SENS 6 ++#define RTL8711_RF_DEF_SENS 4 ++ ++// ++// We now define the following channels as the max channels in each channel plan. ++// 2G, total 14 chnls ++// {1,2,3,4,5,6,7,8,9,10,11,12,13,14} ++// 5G, total 24 chnls ++// {36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140,149,153,157,161,165} ++#define MAX_CHANNEL_NUM_2G 14 ++#define MAX_CHANNEL_NUM_5G 24 ++#define MAX_CHANNEL_NUM 38//14+24 ++ ++//#define NUM_REGULATORYS 21 ++#define NUM_REGULATORYS 1 ++ ++//Country codes ++#define USA 0x555320 ++#define EUROPE 0x1 //temp, should be provided later ++#define JAPAN 0x2 //temp, should be provided later ++ ++struct regulatory_class { ++ u32 starting_freq; //MHz, ++ u8 channel_set[MAX_CHANNEL_NUM]; ++ u8 channel_cck_power[MAX_CHANNEL_NUM];//dbm ++ u8 channel_ofdm_power[MAX_CHANNEL_NUM];//dbm ++ u8 txpower_limit; //dbm ++ u8 channel_spacing; //MHz ++ u8 modem; ++}; ++ ++typedef enum _CAPABILITY{ ++ cESS = 0x0001, ++ cIBSS = 0x0002, ++ cPollable = 0x0004, ++ cPollReq = 0x0008, ++ cPrivacy = 0x0010, ++ cShortPreamble = 0x0020, ++ cPBCC = 0x0040, ++ cChannelAgility = 0x0080, ++ cSpectrumMgnt = 0x0100, ++ cQos = 0x0200, // For HCCA, use with CF-Pollable and CF-PollReq ++ cShortSlotTime = 0x0400, ++ cAPSD = 0x0800, ++ cRM = 0x1000, // RRM (Radio Request Measurement) ++ cDSSS_OFDM = 0x2000, ++ cDelayedBA = 0x4000, ++ cImmediateBA = 0x8000, ++}CAPABILITY, *PCAPABILITY; ++ ++enum _REG_PREAMBLE_MODE{ ++ PREAMBLE_LONG = 1, ++ PREAMBLE_AUTO = 2, ++ PREAMBLE_SHORT = 3, ++}; ++ ++ ++enum _RTL8712_RF_MIMO_CONFIG_{ ++ RTL8712_RFCONFIG_1T=0x10, ++ RTL8712_RFCONFIG_2T=0x20, ++ RTL8712_RFCONFIG_1R=0x01, ++ RTL8712_RFCONFIG_2R=0x02, ++ RTL8712_RFCONFIG_1T1R=0x11, ++ RTL8712_RFCONFIG_1T2R=0x12, ++ RTL8712_RFCONFIG_TURBO=0x92, ++ RTL8712_RFCONFIG_2T2R=0x22 ++}; ++ ++ ++typedef enum _RF90_RADIO_PATH{ ++ RF90_PATH_A = 0, //Radio Path A ++ RF90_PATH_B = 1, //Radio Path B ++ RF90_PATH_C = 2, //Radio Path C ++ RF90_PATH_D = 3 //Radio Path D ++ //RF90_PATH_MAX //Max RF number 90 support ++}RF90_RADIO_PATH_E, *PRF90_RADIO_PATH_E; ++ ++// Bandwidth Offset ++#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 ++#define HAL_PRIME_CHNL_OFFSET_LOWER 1 ++#define HAL_PRIME_CHNL_OFFSET_UPPER 2 ++ ++// Represent Channel Width in HT Capabilities ++// ++typedef enum _HT_CHANNEL_WIDTH { ++ ++ HT_CHANNEL_WIDTH_20 = 0, ++ HT_CHANNEL_WIDTH_40 = 1, ++ HT_CHANNEL_WIDTH_80 = 2, ++ HT_CHANNEL_WIDTH_160 = 3, ++ HT_CHANNEL_WIDTH_10 = 4, ++ ++}HT_CHANNEL_WIDTH, *PHT_CHANNEL_WIDTH; ++ ++// ++// Represent Extention Channel Offset in HT Capabilities ++// This is available only in 40Mhz mode. ++// ++typedef enum _HT_EXTCHNL_OFFSET{ ++ HT_EXTCHNL_OFFSET_NO_EXT = 0, ++ HT_EXTCHNL_OFFSET_UPPER = 1, ++ HT_EXTCHNL_OFFSET_NO_DEF = 2, ++ HT_EXTCHNL_OFFSET_LOWER = 3, ++}HT_EXTCHNL_OFFSET, *PHT_EXTCHNL_OFFSET; ++ ++/* 2007/11/15 MH Define different RF type. */ ++typedef enum _RT_RF_TYPE_DEFINITION ++{ ++ RF_1T2R = 0, ++ RF_2T4R = 1, ++ RF_2T2R = 2, ++ RF_1T1R = 3, ++ RF_2T2R_GREEN = 4, ++ RF_819X_MAX_TYPE = 5, ++}RT_RF_TYPE_DEF_E; ++ ++ ++u32 rtw_ch2freq(u32 ch); ++u32 rtw_freq2ch(u32 freq); ++ ++ ++#endif //_RTL8711_RF_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_security.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_security.h +new file mode 100644 +index 00000000..730857c2 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_security.h +@@ -0,0 +1,466 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTW_SECURITY_H_ ++#define __RTW_SECURITY_H_ ++ ++ ++#include ++#include ++#include ++ ++ ++#define _NO_PRIVACY_ 0x0 ++#define _WEP40_ 0x1 ++#define _TKIP_ 0x2 ++#define _TKIP_WTMIC_ 0x3 ++#define _AES_ 0x4 ++#define _WEP104_ 0x5 ++#define _WEP_WPA_MIXED_ 0x07 // WEP + WPA ++#define _SMS4_ 0x06 ++#ifdef CONFIG_IEEE80211W ++#define _BIP_ 0x8 ++#endif //CONFIG_IEEE80211W ++#define is_wep_enc(alg) (((alg) == _WEP40_) || ((alg) == _WEP104_)) ++ ++#define _WPA_IE_ID_ 0xdd ++#define _WPA2_IE_ID_ 0x30 ++ ++#define SHA256_MAC_LEN 32 ++#define AES_BLOCK_SIZE 16 ++#define AES_PRIV_SIZE (4 * 44) ++ ++typedef enum { ++ ENCRYP_PROTOCOL_OPENSYS, //open system ++ ENCRYP_PROTOCOL_WEP, //WEP ++ ENCRYP_PROTOCOL_WPA, //WPA ++ ENCRYP_PROTOCOL_WPA2, //WPA2 ++ ENCRYP_PROTOCOL_WAPI, //WAPI: Not support in this version ++ ENCRYP_PROTOCOL_MAX ++}ENCRYP_PROTOCOL_E; ++ ++ ++#ifndef Ndis802_11AuthModeWPA2 ++#define Ndis802_11AuthModeWPA2 (Ndis802_11AuthModeWPANone + 1) ++#endif ++ ++#ifndef Ndis802_11AuthModeWPA2PSK ++#define Ndis802_11AuthModeWPA2PSK (Ndis802_11AuthModeWPANone + 2) ++#endif ++ ++union pn48 { ++ ++ u64 val; ++ ++#ifdef CONFIG_LITTLE_ENDIAN ++ ++struct { ++ u8 TSC0; ++ u8 TSC1; ++ u8 TSC2; ++ u8 TSC3; ++ u8 TSC4; ++ u8 TSC5; ++ u8 TSC6; ++ u8 TSC7; ++} _byte_; ++ ++#elif defined(CONFIG_BIG_ENDIAN) ++ ++struct { ++ u8 TSC7; ++ u8 TSC6; ++ u8 TSC5; ++ u8 TSC4; ++ u8 TSC3; ++ u8 TSC2; ++ u8 TSC1; ++ u8 TSC0; ++} _byte_; ++ ++#endif ++ ++}; ++ ++union Keytype { ++ u8 skey[16]; ++ u32 lkey[4]; ++}; ++ ++ ++typedef struct _RT_PMKID_LIST ++{ ++ u8 bUsed; ++ u8 Bssid[6]; ++ u8 PMKID[16]; ++ u8 SsidBuf[33]; ++ u8* ssid_octet; ++ u16 ssid_length; ++} RT_PMKID_LIST, *PRT_PMKID_LIST; ++ ++ ++struct security_priv ++{ ++ u32 dot11AuthAlgrthm; // 802.11 auth, could be open, shared, 8021x and authswitch ++ u32 dot11PrivacyAlgrthm; // This specify the privacy for shared auth. algorithm. ++ ++ /* WEP */ ++ u32 dot11PrivacyKeyIndex; // this is only valid for legendary wep, 0~3 for key id. (tx key index) ++ union Keytype dot11DefKey[4]; // this is only valid for def. key ++ u32 dot11DefKeylen[4]; ++ u8 key_mask; /* use to restore wep key after hal_init */ ++ ++ u32 dot118021XGrpPrivacy; // This specify the privacy algthm. used for Grp key ++ u32 dot118021XGrpKeyid; // key id used for Grp Key ( tx key index) ++ union Keytype dot118021XGrpKey[4]; // 802.1x Group Key, for inx0 and inx1 ++ union Keytype dot118021XGrptxmickey[4]; ++ union Keytype dot118021XGrprxmickey[4]; ++ union pn48 dot11Grptxpn; // PN48 used for Grp Key xmit. ++ union pn48 dot11Grprxpn; // PN48 used for Grp Key recv. ++#ifdef CONFIG_IEEE80211W ++ u32 dot11wBIPKeyid; // key id used for BIP Key ( tx key index) ++ union Keytype dot11wBIPKey[6]; // BIP Key, for index4 and index5 ++ union pn48 dot11wBIPtxpn; // PN48 used for Grp Key xmit. ++ union pn48 dot11wBIPrxpn; // PN48 used for Grp Key recv. ++#endif //CONFIG_IEEE80211W ++#ifdef CONFIG_AP_MODE ++ //extend security capabilities for AP_MODE ++ unsigned int dot8021xalg;//0:disable, 1:psk, 2:802.1x ++ unsigned int wpa_psk;//0:disable, bit(0): WPA, bit(1):WPA2 ++ unsigned int wpa_group_cipher; ++ unsigned int wpa2_group_cipher; ++ unsigned int wpa_pairwise_cipher; ++ unsigned int wpa2_pairwise_cipher; ++#endif ++ ++ u8 wps_ie[MAX_WPS_IE_LEN];//added in assoc req ++ int wps_ie_len; ++ ++ ++ u8 binstallGrpkey; ++#ifdef CONFIG_IEEE80211W ++ u8 binstallBIPkey; ++#endif //CONFIG_IEEE80211W ++ u8 busetkipkey; ++ //_timer tkip_timer; ++ u8 bcheck_grpkey; ++ u8 bgrpkey_handshake; ++ ++ //u8 packet_cnt;//unused, removed ++ ++ s32 sw_encrypt;//from registry_priv ++ s32 sw_decrypt;//from registry_priv ++ ++ s32 hw_decrypted;//if the rx packets is hw_decrypted==_FALSE, it means the hw has not been ready. ++ ++ ++ //keeps the auth_type & enc_status from upper layer ioctl(wpa_supplicant or wzc) ++ u32 ndisauthtype; // NDIS_802_11_AUTHENTICATION_MODE ++ u32 ndisencryptstatus; // NDIS_802_11_ENCRYPTION_STATUS ++ ++ WLAN_BSSID_EX sec_bss; //for joinbss (h2c buffer) usage ++ ++ NDIS_802_11_WEP ndiswep; ++#ifdef PLATFORM_WINDOWS ++ u8 KeyMaterial[16];// variable length depending on above field. ++#endif ++ ++ u8 assoc_info[600]; ++ u8 szofcapability[256]; //for wpa2 usage ++ u8 oidassociation[512]; //for wpa/wpa2 usage ++ u8 authenticator_ie[256]; //store ap security information element ++ u8 supplicant_ie[256]; //store sta security information element ++ ++ ++ //for tkip countermeasure ++ u32 last_mic_err_time; ++ u8 btkip_countermeasure; ++ u8 btkip_wait_report; ++ u32 btkip_countermeasure_time; ++ ++ //--------------------------------------------------------------------------- ++ // For WPA2 Pre-Authentication. ++ //--------------------------------------------------------------------------- ++ //u8 RegEnablePreAuth; // Default value: Pre-Authentication enabled or not, from registry "EnablePreAuth". Added by Annie, 2005-11-01. ++ //u8 EnablePreAuthentication; // Current Value: Pre-Authentication enabled or not. ++ RT_PMKID_LIST PMKIDList[NUM_PMKID_CACHE]; // Renamed from PreAuthKey[NUM_PRE_AUTH_KEY]. Annie, 2006-10-13. ++ u8 PMKIDIndex; ++ //u32 PMKIDCount; // Added by Annie, 2006-10-13. ++ //u8 szCapability[256]; // For WPA2-PSK using zero-config, by Annie, 2005-09-20. ++ ++ u8 bWepDefaultKeyIdxSet; ++}; ++ ++struct sha256_state { ++ u64 length; ++ u32 state[8], curlen; ++ u8 buf[64]; ++}; ++ ++#define GET_ENCRY_ALGO(psecuritypriv, psta, encry_algo, bmcst)\ ++do{\ ++ switch(psecuritypriv->dot11AuthAlgrthm)\ ++ {\ ++ case dot11AuthAlgrthm_Open:\ ++ case dot11AuthAlgrthm_Shared:\ ++ case dot11AuthAlgrthm_Auto:\ ++ encry_algo = (u8)psecuritypriv->dot11PrivacyAlgrthm;\ ++ break;\ ++ case dot11AuthAlgrthm_8021X:\ ++ if(bmcst)\ ++ encry_algo = (u8)psecuritypriv->dot118021XGrpPrivacy;\ ++ else\ ++ encry_algo =(u8) psta->dot118021XPrivacy;\ ++ break;\ ++ case dot11AuthAlgrthm_WAPI:\ ++ encry_algo = (u8)psecuritypriv->dot11PrivacyAlgrthm;\ ++ break;\ ++ }\ ++}while(0) ++ ++ ++#define SET_ICE_IV_LEN( iv_len, icv_len, encrypt)\ ++do{\ ++ switch(encrypt)\ ++ {\ ++ case _WEP40_:\ ++ case _WEP104_:\ ++ iv_len = 4;\ ++ icv_len = 4;\ ++ break;\ ++ case _TKIP_:\ ++ iv_len = 8;\ ++ icv_len = 4;\ ++ break;\ ++ case _AES_:\ ++ iv_len = 8;\ ++ icv_len = 8;\ ++ break;\ ++ case _SMS4_:\ ++ iv_len = 18;\ ++ icv_len = 16;\ ++ break;\ ++ default:\ ++ iv_len = 0;\ ++ icv_len = 0;\ ++ break;\ ++ }\ ++}while(0) ++ ++ ++#define GET_TKIP_PN(iv,dot11txpn)\ ++do{\ ++ dot11txpn._byte_.TSC0=iv[2];\ ++ dot11txpn._byte_.TSC1=iv[0];\ ++ dot11txpn._byte_.TSC2=iv[4];\ ++ dot11txpn._byte_.TSC3=iv[5];\ ++ dot11txpn._byte_.TSC4=iv[6];\ ++ dot11txpn._byte_.TSC5=iv[7];\ ++}while(0) ++ ++ ++#define ROL32( A, n ) ( ((A) << (n)) | ( ((A)>>(32-(n))) & ( (1UL << (n)) - 1 ) ) ) ++#define ROR32( A, n ) ROL32( (A), 32-(n) ) ++ ++struct mic_data ++{ ++ u32 K0, K1; // Key ++ u32 L, R; // Current state ++ u32 M; // Message accumulator (single word) ++ u32 nBytesInM; // # bytes in M ++}; ++ ++extern const u32 Te0[256]; ++extern const u32 Te1[256]; ++extern const u32 Te2[256]; ++extern const u32 Te3[256]; ++extern const u32 Te4[256]; ++extern const u32 Td0[256]; ++extern const u32 Td1[256]; ++extern const u32 Td2[256]; ++extern const u32 Td3[256]; ++extern const u32 Td4[256]; ++extern const u32 rcon[10]; ++extern const u8 Td4s[256]; ++extern const u8 rcons[10]; ++ ++#define RCON(i) (rcons[(i)] << 24) ++ ++static inline u32 rotr(u32 val, int bits) ++{ ++ return (val >> bits) | (val << (32 - bits)); ++} ++ ++#define TE0(i) Te0[((i) >> 24) & 0xff] ++#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8) ++#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16) ++#define TE3(i) rotr(Te0[(i) & 0xff], 24) ++#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000) ++#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000) ++#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00) ++#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff) ++#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000) ++#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000) ++#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00) ++#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff) ++#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff) ++ ++#define TD0(i) Td0[((i) >> 24) & 0xff] ++#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8) ++#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16) ++#define TD3(i) rotr(Td0[(i) & 0xff], 24) ++#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24) ++#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16) ++#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8) ++#define TD44(i) (Td4s[(i) & 0xff]) ++#define TD0_(i) Td0[(i) & 0xff] ++#define TD1_(i) rotr(Td0[(i) & 0xff], 8) ++#define TD2_(i) rotr(Td0[(i) & 0xff], 16) ++#define TD3_(i) rotr(Td0[(i) & 0xff], 24) ++ ++#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \ ++ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) ++ ++#define PUTU32(ct, st) { \ ++(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \ ++(ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } ++ ++#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ ++ (((u32) (a)[2]) << 8) | ((u32) (a)[3])) ++ ++#define WPA_PUT_LE16(a, val) \ ++ do { \ ++ (a)[1] = ((u16) (val)) >> 8; \ ++ (a)[0] = ((u16) (val)) & 0xff; \ ++ } while (0) ++ ++#define WPA_PUT_BE32(a, val) \ ++ do { \ ++ (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ ++ (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ ++ (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ ++ (a)[3] = (u8) (((u32) (val)) & 0xff); \ ++ } while (0) ++ ++#define WPA_PUT_BE64(a, val) \ ++ do { \ ++ (a)[0] = (u8) (((u64) (val)) >> 56); \ ++ (a)[1] = (u8) (((u64) (val)) >> 48); \ ++ (a)[2] = (u8) (((u64) (val)) >> 40); \ ++ (a)[3] = (u8) (((u64) (val)) >> 32); \ ++ (a)[4] = (u8) (((u64) (val)) >> 24); \ ++ (a)[5] = (u8) (((u64) (val)) >> 16); \ ++ (a)[6] = (u8) (((u64) (val)) >> 8); \ ++ (a)[7] = (u8) (((u64) (val)) & 0xff); \ ++ } while (0) ++ ++/* ===== start - public domain SHA256 implementation ===== */ ++ ++/* This is based on SHA256 implementation in LibTomCrypt that was released into ++ * public domain by Tom St Denis. */ ++ ++/* the K array */ ++static const unsigned long K[64] = { ++ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, ++ 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, ++ 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, ++ 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, ++ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, ++ 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, ++ 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, ++ 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, ++ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, ++ 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, ++ 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, ++ 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, ++ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL ++}; ++ ++ ++/* Various logical functions */ ++#define RORc(x, y) \ ++( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \ ++ ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) ++#define Ch(x,y,z) (z ^ (x & (y ^ z))) ++#define Maj(x,y,z) (((x | y) & z) | (x & y)) ++#define S(x, n) RORc((x), (n)) ++#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) ++#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) ++#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) ++#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) ++#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) ++#ifndef MIN ++#define MIN(x, y) (((x) < (y)) ? (x) : (y)) ++#endif ++#ifdef CONFIG_IEEE80211W ++int omac1_aes_128(u8 *key, u8 *data, size_t data_len, u8 *mac); ++#endif //CONFIG_IEEE80211W ++void rtw_secmicsetkey(struct mic_data *pmicdata, u8 * key ); ++void rtw_secmicappendbyte(struct mic_data *pmicdata, u8 b ); ++void rtw_secmicappend(struct mic_data *pmicdata, u8 * src, u32 nBytes ); ++void rtw_secgetmic(struct mic_data *pmicdata, u8 * dst ); ++ ++void rtw_seccalctkipmic( ++ u8 * key, ++ u8 *header, ++ u8 *data, ++ u32 data_len, ++ u8 *Miccode, ++ u8 priority); ++ ++u32 rtw_aes_encrypt(_adapter *padapter, u8 *pxmitframe); ++u32 rtw_tkip_encrypt(_adapter *padapter, u8 *pxmitframe); ++void rtw_wep_encrypt(_adapter *padapter, u8 *pxmitframe); ++ ++u32 rtw_aes_decrypt(_adapter *padapter, u8 *precvframe); ++u32 rtw_tkip_decrypt(_adapter *padapter, u8 *precvframe); ++void rtw_wep_decrypt(_adapter *padapter, u8 *precvframe); ++#ifdef CONFIG_IEEE80211W ++u32 rtw_BIP_verify(_adapter *padapter, u8 *precvframe); ++#endif //CONFIG_IEEE80211W ++#ifdef CONFIG_TDLS ++void wpa_tdls_generate_tpk(_adapter *padapter, struct sta_info *psta); ++int wpa_tdls_ftie_mic(u8 *kck, u8 trans_seq, ++ u8 *lnkid, u8 *rsnie, u8 *timeoutie, u8 *ftie, ++ u8 *mic); ++int tdls_verify_mic(u8 *kck, u8 trans_seq, ++ u8 *lnkid, u8 *rsnie, u8 *timeoutie, u8 *ftie); ++#endif //CONFIG_TDLS ++ ++#ifdef PLATFORM_WINDOWS ++void rtw_use_tkipkey_handler ( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3 ++ ); ++#endif ++#ifdef PLATFORM_LINUX ++void rtw_use_tkipkey_handler(void* FunctionContext); ++#endif ++ ++#ifdef PLATFORM_FREEBSD ++void rtw_use_tkipkey_handler(void* FunctionContext); ++#endif //PLATFORM_FREEBSD ++ ++void rtw_sec_restore_wep_key(_adapter *adapter); ++u8 rtw_handle_tkip_countermeasure(_adapter* adapter, const char *caller); ++ ++#endif //__RTL871X_SECURITY_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_sreset.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_sreset.h +new file mode 100644 +index 00000000..45dd2bfb +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_sreset.h +@@ -0,0 +1,74 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _RTW_SRESET_C_ ++#define _RTW_SRESET_C_ ++ ++#include ++#include ++#include ++ ++enum { ++ SRESET_TGP_NULL = 0, ++ SRESET_TGP_XMIT_STATUS = 1, ++ SRESET_TGP_LINK_STATUS = 2, ++}; ++ ++struct sreset_priv { ++ _mutex silentreset_mutex; ++ u8 silent_reset_inprogress; ++ u8 Wifi_Error_Status; ++ unsigned long last_tx_time; ++ unsigned long last_tx_complete_time; ++ ++ s32 dbg_trigger_point; ++}; ++ ++#ifdef CONFIG_RTL8192C ++#include ++#endif ++#ifdef CONFIG_RTL8192D ++#include ++#endif ++#ifdef CONFIG_RTL8723A ++#include ++#endif ++#ifdef CONFIG_RTL8188E ++#include ++#endif ++ ++#define WIFI_STATUS_SUCCESS 0 ++#define USB_VEN_REQ_CMD_FAIL BIT0 ++#define USB_READ_PORT_FAIL BIT1 ++#define USB_WRITE_PORT_FAIL BIT2 ++#define WIFI_MAC_TXDMA_ERROR BIT3 ++#define WIFI_TX_HANG BIT4 ++#define WIFI_RX_HANG BIT5 ++#define WIFI_IF_NOT_EXIST BIT6 ++ ++void sreset_init_value(_adapter *padapter); ++void sreset_reset_value(_adapter *padapter); ++u8 sreset_get_wifi_status(_adapter *padapter); ++void sreset_set_wifi_error_status(_adapter *padapter, u32 status); ++void sreset_set_trigger_point(_adapter *padapter, s32 tgp); ++bool sreset_inprogress(_adapter *padapter); ++void sreset_reset(_adapter *padapter); ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_tdls.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_tdls.h +new file mode 100644 +index 00000000..bc22cfee +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_tdls.h +@@ -0,0 +1,143 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __RTW_TDLS_H_ ++#define __RTW_TDLS_H_ ++ ++#include ++ ++#ifdef CONFIG_TDLS ++/* TDLS STA state */ ++#define TDLS_STATE_NONE 0x00000000 //default state ++#define TDLS_INITIATOR_STATE 0x10000000 ++#define TDLS_RESPONDER_STATE 0x20000000 ++#define TDLS_LINKED_STATE 0x40000000 ++#define TDLS_CH_SWITCH_ON_STATE 0x01000000 ++#define TDLS_PEER_AT_OFF_STATE 0x02000000 //could send pkt on target ch ++#define TDLS_AT_OFF_CH_STATE 0x04000000 ++#define TDLS_CH_SW_INITIATOR_STATE 0x08000000 //avoiding duplicated or unconditional ch. switch rsp. ++#define TDLS_APSD_CHSW_STATE 0x00100000 //in APSD and want to setup channel switch ++#define TDLS_PEER_SLEEP_STATE 0x00200000 //peer sta is sleeping ++#define TDLS_SW_OFF_STATE 0x00400000 //terminate channel swithcing ++#define TDLS_ALIVE_STATE 0x00010000 //Check if peer sta is alived. ++ ++#define TPK_RESEND_COUNT 301 ++#define CH_SWITCH_TIME 10 ++#define CH_SWITCH_TIMEOUT 30 ++#define TDLS_STAY_TIME 500 ++#define TDLS_SIGNAL_THRESH 0x20 ++#define TDLS_WATCHDOG_PERIOD 10 //Periodically sending tdls discovery request in TDLS_WATCHDOG_PERIOD * 2 sec ++#define TDLS_ALIVE_TIMER_PH1 5000 ++#define TDLS_ALIVE_TIMER_PH2 2000 ++#define TDLS_STAY_TIME 500 ++#define TDLS_HANDSHAKE_TIME 8000 ++#define TDLS_ALIVE_COUNT 3 ++#define TDLS_INI_MACID_ENTRY 6 ++ ++/* TDLS */ ++#define TDLS_MIC_LEN 16 ++#define WPA_NONCE_LEN 32 ++#define TDLS_TIMEOUT_LEN 4 ++ ++struct wpa_tdls_ftie { ++ u8 ie_type; /* FTIE */ ++ u8 ie_len; ++ u8 mic_ctrl[2]; ++ u8 mic[TDLS_MIC_LEN]; ++ u8 Anonce[WPA_NONCE_LEN]; /* Responder Nonce in TDLS */ ++ u8 Snonce[WPA_NONCE_LEN]; /* Initiator Nonce in TDLS */ ++ /* followed by optional elements */ ++} ; ++ ++struct wpa_tdls_lnkid { ++ u8 ie_type; /* Link Identifier IE */ ++ u8 ie_len; ++ u8 bssid[ETH_ALEN]; ++ u8 init_sta[ETH_ALEN]; ++ u8 resp_sta[ETH_ALEN]; ++} ; ++ ++static u8 TDLS_RSNIE[]={ 0x01, 0x00, //version shall be set to 1 ++ 0x00, 0x0f, 0xac, 0x07, //group sipher suite ++ 0x01, 0x00, //pairwise cipher suite count ++ 0x00, 0x0f, 0xac, 0x04, //pairwise cipher suite list; CCMP only ++ 0x01, 0x00, //AKM suite count ++ 0x00, 0x0f, 0xac, 0x07, //TPK Handshake ++ 0x00, 0x02, ++ //PMKID shall not be present ++ }; ++ ++static u8 TDLS_WMMIE[]={0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; //Qos info all set zero ++ ++static u8 TDLS_EXT_CAPIE[] = {0x00, 0x00, 0x00, 0x50, 0x20}; //bit(28), bit(30), bit(37) ++ ++// SRC: Supported Regulatory Classes ++static u8 TDLS_SRC[] = { 0x01, 0x01, 0x02, 0x03, 0x04, 0x0c, 0x16, 0x17, 0x18, 0x19, 0x1b, 0x1c, 0x1d, 0x1e, 0x20, 0x21 }; ++ ++void rtw_reset_tdls_info(_adapter* padapter); ++int rtw_init_tdls_info(_adapter* padapter); ++void rtw_free_tdls_info(struct tdls_info *ptdlsinfo); ++void issue_nulldata_to_TDLS_peer_STA(_adapter *padapter, struct sta_info *ptdls_sta, unsigned int power_mode); ++void init_TPK_timer(_adapter *padapter, struct sta_info *psta); ++void init_ch_switch_timer(_adapter *padapter, struct sta_info *psta); ++void init_base_ch_timer(_adapter *padapter, struct sta_info *psta); ++void init_off_ch_timer(_adapter *padapter, struct sta_info *psta); ++void init_tdls_alive_timer(_adapter *padapter, struct sta_info *psta); ++void init_handshake_timer(_adapter *padapter, struct sta_info *psta); ++void free_tdls_sta(_adapter *padapter, struct sta_info *ptdls_sta); ++#ifdef CONFIG_WFD ++void issue_tunneled_probe_req(_adapter *padapter); ++void issue_tunneled_probe_rsp(_adapter *padapter, union recv_frame *precv_frame); ++#endif //CONFIG_WFD ++void issue_tdls_dis_req(_adapter *padapter, u8 *mac_addr); ++void issue_tdls_setup_req(_adapter *padapter, u8 *mac_addr); ++void issue_tdls_setup_rsp(_adapter *padapter, union recv_frame *precv_frame); ++void issue_tdls_setup_cfm(_adapter *padapter, union recv_frame *precv_frame); ++void issue_tdls_dis_rsp(_adapter * padapter, union recv_frame * precv_frame, u8 dialog); ++void issue_tdls_teardown(_adapter *padapter, u8 *mac_addr); ++void issue_tdls_peer_traffic_indication(_adapter *padapter, struct sta_info *psta); ++void issue_tdls_ch_switch_req(_adapter *padapter, u8 *mac_addr); ++void issue_tdls_ch_switch_rsp(_adapter *padapter, u8 *mac_addr); ++sint On_TDLS_Dis_Rsp(_adapter *adapter, union recv_frame *precv_frame); ++sint On_TDLS_Setup_Req(_adapter *adapter, union recv_frame *precv_frame); ++sint On_TDLS_Setup_Rsp(_adapter *adapter, union recv_frame *precv_frame); ++sint On_TDLS_Setup_Cfm(_adapter *adapter, union recv_frame *precv_frame); ++sint On_TDLS_Dis_Req(_adapter *adapter, union recv_frame *precv_frame); ++sint On_TDLS_Teardown(_adapter *adapter, union recv_frame *precv_frame); ++sint On_TDLS_Peer_Traffic_Rsp(_adapter *adapter, union recv_frame *precv_frame); ++sint On_TDLS_Ch_Switch_Req(_adapter *adapter, union recv_frame *precv_frame); ++sint On_TDLS_Ch_Switch_Rsp(_adapter *adapter, union recv_frame *precv_frame); ++void rtw_build_tdls_setup_req_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe); ++void rtw_build_tdls_setup_rsp_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe); ++void rtw_build_tdls_setup_cfm_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe); ++void rtw_build_tdls_teardown_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe); ++void rtw_build_tdls_dis_req_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe); ++void rtw_build_tdls_dis_rsp_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe, u8 dialog); ++void rtw_build_tdls_peer_traffic_indication_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe); ++void rtw_build_tdls_ch_switch_req_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe); ++void rtw_build_tdls_ch_switch_rsp_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe); ++void rtw_build_tunneled_probe_req_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe); ++void rtw_build_tunneled_probe_rsp_ies(_adapter * padapter, struct xmit_frame * pxmitframe, u8 *pframe); ++ ++int update_sgi_tdls(_adapter *padapter, struct sta_info *psta); ++u32 update_mask_tdls(_adapter *padapter, struct sta_info *psta); ++#endif //CONFIG_TDLS ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_version.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_version.h +new file mode 100644 +index 00000000..15d14e01 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_version.h +@@ -0,0 +1 @@ ++#define DRIVERVERSION "v4.1.8_9499.20131104" +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/rtw_wapi.h b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_wapi.h +new file mode 100644 +index 00000000..f72c666d +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/rtw_wapi.h +@@ -0,0 +1,229 @@ ++#ifndef __INC_WAPI_H ++#define __INC_WAPI_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++//#include "rtl819x_Qos.h" ++ ++#define CONFIG_WAPI_SW_SMS4 ++#define WAPI_DEBUG ++ ++#define SMS4_MIC_LEN 16 ++#define WAPI_EXT_LEN 18 ++#define MAX_WAPI_IE_LEN 256 ++#define sMacHdrLng 24 // octets in data header, no WEP ++ ++#ifdef WAPI_DEBUG ++ ++/* WAPI trace debug */ ++extern u32 wapi_debug_component; ++ ++static inline void dump_buf(u8 *buf, u32 len) ++{ ++ u32 i; ++ printk("-----------------Len %d----------------\n", len); ++ for(i=0; i ++#include ++#include ++#ifdef PLATFORM_FREEBSD ++#include ++#endif //PLATFORM_FREEBSD ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++//#define MAX_XMITBUF_SZ (30720)// (2048) ++#ifdef CONFIG_TX_AGGREGATION ++#define MAX_XMITBUF_SZ (20480) // 20k ++#else ++#define MAX_XMITBUF_SZ (12288) //12k 1536*8 ++#endif ++ ++#if defined CONFIG_SDIO_HCI ++#define NR_XMITBUFF (16) ++#endif ++#if defined(CONFIG_GSPI_HCI) ++#define NR_XMITBUFF (128) ++#endif ++ ++#elif defined (CONFIG_USB_HCI) ++ ++#ifdef CONFIG_USB_TX_AGGREGATION ++ #if defined(CONFIG_PLATFORM_ARM_SUNxI) || defined(CONFIG_PLATFORM_ARM_SUN6I) || defined(CONFIG_PLATFORM_ARM_SUN7I) ++ #define MAX_XMITBUF_SZ (12288) //12k 1536*8 ++ #elif defined (CONFIG_PLATFORM_MSTAR) ++ #define MAX_XMITBUF_SZ 7680 // 7.5k ++ #else ++ #define MAX_XMITBUF_SZ (20480) // 20k ++ #endif ++#else ++#define MAX_XMITBUF_SZ (2048) ++#endif ++#ifdef CONFIG_SINGLE_XMIT_BUF ++#define NR_XMITBUFF (1) ++#else ++#define NR_XMITBUFF (4) ++#endif //CONFIG_SINGLE_XMIT_BUF ++#elif defined (CONFIG_PCI_HCI) ++#define MAX_XMITBUF_SZ (1664) ++#define NR_XMITBUFF (128) ++#endif ++ ++#ifdef PLATFORM_OS_CE ++#define XMITBUF_ALIGN_SZ 4 ++#else ++#ifdef CONFIG_PCI_HCI ++#define XMITBUF_ALIGN_SZ 4 ++#else ++#define XMITBUF_ALIGN_SZ 512 ++#endif ++#endif ++ ++// xmit extension buff defination ++#define MAX_XMIT_EXTBUF_SZ (1536) ++#define NR_XMIT_EXTBUFF (32) ++ ++#define MAX_NUMBLKS (1) ++ ++#define XMIT_VO_QUEUE (0) ++#define XMIT_VI_QUEUE (1) ++#define XMIT_BE_QUEUE (2) ++#define XMIT_BK_QUEUE (3) ++ ++#define VO_QUEUE_INX 0 ++#define VI_QUEUE_INX 1 ++#define BE_QUEUE_INX 2 ++#define BK_QUEUE_INX 3 ++#define BCN_QUEUE_INX 4 ++#define MGT_QUEUE_INX 5 ++#define HIGH_QUEUE_INX 6 ++#define TXCMD_QUEUE_INX 7 ++ ++#define HW_QUEUE_ENTRY 8 ++ ++#ifdef CONFIG_PCI_HCI ++//#define TXDESC_NUM 64 ++#define TXDESC_NUM 128 ++#define TXDESC_NUM_BE_QUEUE 128 ++#endif ++ ++#define WEP_IV(pattrib_iv, dot11txpn, keyidx)\ ++do{\ ++ pattrib_iv[0] = dot11txpn._byte_.TSC0;\ ++ pattrib_iv[1] = dot11txpn._byte_.TSC1;\ ++ pattrib_iv[2] = dot11txpn._byte_.TSC2;\ ++ pattrib_iv[3] = ((keyidx & 0x3)<<6);\ ++ dot11txpn.val = (dot11txpn.val == 0xffffff) ? 0: (dot11txpn.val+1);\ ++}while(0) ++ ++ ++#define TKIP_IV(pattrib_iv, dot11txpn, keyidx)\ ++do{\ ++ pattrib_iv[0] = dot11txpn._byte_.TSC1;\ ++ pattrib_iv[1] = (dot11txpn._byte_.TSC1 | 0x20) & 0x7f;\ ++ pattrib_iv[2] = dot11txpn._byte_.TSC0;\ ++ pattrib_iv[3] = BIT(5) | ((keyidx & 0x3)<<6);\ ++ pattrib_iv[4] = dot11txpn._byte_.TSC2;\ ++ pattrib_iv[5] = dot11txpn._byte_.TSC3;\ ++ pattrib_iv[6] = dot11txpn._byte_.TSC4;\ ++ pattrib_iv[7] = dot11txpn._byte_.TSC5;\ ++ dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0: (dot11txpn.val+1);\ ++}while(0) ++ ++#define AES_IV(pattrib_iv, dot11txpn, keyidx)\ ++do{\ ++ pattrib_iv[0] = dot11txpn._byte_.TSC0;\ ++ pattrib_iv[1] = dot11txpn._byte_.TSC1;\ ++ pattrib_iv[2] = 0;\ ++ pattrib_iv[3] = BIT(5) | ((keyidx & 0x3)<<6);\ ++ pattrib_iv[4] = dot11txpn._byte_.TSC2;\ ++ pattrib_iv[5] = dot11txpn._byte_.TSC3;\ ++ pattrib_iv[6] = dot11txpn._byte_.TSC4;\ ++ pattrib_iv[7] = dot11txpn._byte_.TSC5;\ ++ dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0: (dot11txpn.val+1);\ ++}while(0) ++ ++ ++#define HWXMIT_ENTRY 4 ++ ++ ++#define TXDESC_SIZE 32 ++ ++#ifdef CONFIG_TX_EARLY_MODE ++#define EARLY_MODE_INFO_SIZE 8 ++#endif ++ ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++#define TXDESC_OFFSET TXDESC_SIZE ++ ++#endif ++ ++#ifdef CONFIG_USB_HCI ++#define PACKET_OFFSET_SZ (8) ++#define TXDESC_OFFSET (TXDESC_SIZE + PACKET_OFFSET_SZ) ++#endif ++ ++#ifdef CONFIG_PCI_HCI ++#define TXDESC_OFFSET 0 ++#define TX_DESC_NEXT_DESC_OFFSET 40 ++#endif ++ ++ ++ ++struct tx_desc{ ++ ++ //DWORD 0 ++ unsigned int txdw0; ++ ++ unsigned int txdw1; ++ ++ unsigned int txdw2; ++ ++ unsigned int txdw3; ++ ++ unsigned int txdw4; ++ ++ unsigned int txdw5; ++ ++ unsigned int txdw6; ++ ++ unsigned int txdw7; ++#ifdef CONFIG_PCI_HCI ++ unsigned int txdw8; ++ ++ unsigned int txdw9; ++ ++ unsigned int txdw10; ++ ++ unsigned int txdw11; ++ ++ // 2008/05/15 MH Because PCIE HW memory R/W 4K limit. And now, our descriptor ++ // size is 40 bytes. If you use more than 102 descriptor( 103*40>4096), HW will execute ++ // memoryR/W CRC error. And then all DMA fetch will fail. We must decrease descriptor ++ // number or enlarge descriptor size as 64 bytes. ++ unsigned int txdw12; ++ ++ unsigned int txdw13; ++ ++ unsigned int txdw14; ++ ++ unsigned int txdw15; ++#endif ++}; ++ ++ ++union txdesc { ++ struct tx_desc txdesc; ++ unsigned int value[TXDESC_SIZE>>2]; ++}; ++ ++#ifdef CONFIG_PCI_HCI ++#define PCI_MAX_TX_QUEUE_COUNT 8 ++ ++struct rtw_tx_ring { ++ struct tx_desc *desc; ++ dma_addr_t dma; ++ unsigned int idx; ++ unsigned int entries; ++ _queue queue; ++ u32 qlen; ++}; ++#endif ++ ++struct hw_xmit { ++ //_lock xmit_lock; ++ //_list pending; ++ _queue *sta_queue; ++ //struct hw_txqueue *phwtxqueue; ++ //sint txcmdcnt; ++ int accnt; ++}; ++ ++#if 0 ++struct pkt_attrib ++{ ++ u8 type; ++ u8 subtype; ++ u8 bswenc; ++ u8 dhcp_pkt; ++ u16 ether_type; ++ int pktlen; //the original 802.3 pkt raw_data len (not include ether_hdr data) ++ int pkt_hdrlen; //the original 802.3 pkt header len ++ int hdrlen; //the WLAN Header Len ++ int nr_frags; ++ int last_txcmdsz; ++ int encrypt; //when 0 indicate no encrypt. when non-zero, indicate the encrypt algorith ++ u8 iv[8]; ++ int iv_len; ++ u8 icv[8]; ++ int icv_len; ++ int priority; ++ int ack_policy; ++ int mac_id; ++ int vcs_mode; //virtual carrier sense method ++ ++ u8 dst[ETH_ALEN]; ++ u8 src[ETH_ALEN]; ++ u8 ta[ETH_ALEN]; ++ u8 ra[ETH_ALEN]; ++ ++ u8 key_idx; ++ ++ u8 qos_en; ++ u8 ht_en; ++ u8 raid;//rate adpative id ++ u8 bwmode; ++ u8 ch_offset;//PRIME_CHNL_OFFSET ++ u8 sgi;//short GI ++ u8 ampdu_en;//tx ampdu enable ++ u8 mdata;//more data bit ++ u8 eosp; ++ ++ u8 pctrl;//per packet txdesc control enable ++ u8 triggered;//for ap mode handling Power Saving sta ++ ++ u32 qsel; ++ u16 seqnum; ++ ++ struct sta_info * psta; ++#ifdef CONFIG_TCP_CSUM_OFFLOAD_TX ++ u8 hw_tcp_csum; ++#endif ++}; ++#else ++//reduce size ++struct pkt_attrib ++{ ++ u8 type; ++ u8 subtype; ++ u8 bswenc; ++ u8 dhcp_pkt; ++ u16 ether_type; ++ u16 seqnum; ++ u16 pkt_hdrlen; //the original 802.3 pkt header len ++ u16 hdrlen; //the WLAN Header Len ++ u32 pktlen; //the original 802.3 pkt raw_data len (not include ether_hdr data) ++ u32 last_txcmdsz; ++ u8 nr_frags; ++ u8 encrypt; //when 0 indicate no encrypt. when non-zero, indicate the encrypt algorith ++ u8 iv_len; ++ u8 icv_len; ++ u8 iv[18]; ++ u8 icv[16]; ++ u8 priority; ++ u8 ack_policy; ++ u8 mac_id; ++ u8 vcs_mode; //virtual carrier sense method ++ u8 dst[ETH_ALEN]; ++ u8 src[ETH_ALEN]; ++ u8 ta[ETH_ALEN]; ++ u8 ra[ETH_ALEN]; ++ u8 key_idx; ++ u8 qos_en; ++ u8 ht_en; ++ u8 raid;//rate adpative id ++ u8 bwmode; ++ u8 ch_offset;//PRIME_CHNL_OFFSET ++ u8 sgi;//short GI ++ u8 ampdu_en;//tx ampdu enable ++ u8 mdata;//more data bit ++ u8 pctrl;//per packet txdesc control enable ++ u8 triggered;//for ap mode handling Power Saving sta ++ u8 qsel; ++ u8 eosp; ++ u8 rate; ++ u8 intel_proxim; ++ u8 retry_ctrl; ++ struct sta_info * psta; ++#ifdef CONFIG_TCP_CSUM_OFFLOAD_TX ++ u8 hw_tcp_csum; ++#endif ++}; ++#endif ++ ++#ifdef PLATFORM_FREEBSD ++#define ETH_ALEN 6 /* Octets in one ethernet addr */ ++#define ETH_HLEN 14 /* Total octets in header. */ ++#define ETH_P_IP 0x0800 /* Internet Protocol packet */ ++ ++/*struct rtw_ieee80211_hdr { ++ uint16_t frame_control; ++ uint16_t duration_id; ++ u8 addr1[6]; ++ u8 addr2[6]; ++ u8 addr3[6]; ++ uint16_t seq_ctrl; ++ u8 addr4[6]; ++} ;*/ ++#endif //PLATFORM_FREEBSD ++ ++#define WLANHDR_OFFSET 64 ++ ++#define NULL_FRAMETAG (0x0) ++#define DATA_FRAMETAG 0x01 ++#define L2_FRAMETAG 0x02 ++#define MGNT_FRAMETAG 0x03 ++#define AMSDU_FRAMETAG 0x04 ++ ++#define EII_FRAMETAG 0x05 ++#define IEEE8023_FRAMETAG 0x06 ++ ++#define MP_FRAMETAG 0x07 ++ ++#define TXAGG_FRAMETAG 0x08 ++ ++struct submit_ctx{ ++ u32 submit_time; /* */ ++ u32 timeout_ms; /* <0: not synchronous, 0: wait forever, >0: up to ms waiting */ ++ int status; /* status for operation */ ++#ifdef PLATFORM_LINUX ++ struct completion done; ++#endif ++}; ++ ++enum { ++ RTW_SCTX_SUBMITTED = -1, ++ RTW_SCTX_DONE_SUCCESS = 0, ++ RTW_SCTX_DONE_UNKNOWN, ++ RTW_SCTX_DONE_TIMEOUT, ++ RTW_SCTX_DONE_BUF_ALLOC, ++ RTW_SCTX_DONE_BUF_FREE, ++ RTW_SCTX_DONE_WRITE_PORT_ERR, ++ RTW_SCTX_DONE_TX_DESC_NA, ++ RTW_SCTX_DONE_TX_DENY, ++ RTW_SCTX_DONE_CCX_PKT_FAIL, ++ RTW_SCTX_DONE_DRV_STOP, ++ RTW_SCTX_DONE_DEV_REMOVE, ++}; ++ ++ ++void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms); ++int rtw_sctx_wait(struct submit_ctx *sctx); ++void rtw_sctx_done_err(struct submit_ctx **sctx, int status); ++void rtw_sctx_done(struct submit_ctx **sctx); ++ ++struct xmit_buf ++{ ++ _list list; ++ ++ _adapter *padapter; ++ ++ u8 *pallocated_buf; ++ ++ u8 *pbuf; ++ ++ void *priv_data; ++ ++ u16 ext_tag; // 0: Normal xmitbuf, 1: extension xmitbuf. ++ u16 flags; ++ u32 alloc_sz; ++ ++ u32 len; ++ ++ struct submit_ctx *sctx; ++ ++#ifdef CONFIG_USB_HCI ++ ++ //u32 sz[8]; ++ u32 ff_hwaddr; ++ ++#if defined(PLATFORM_OS_XP)||defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD) ++ PURB pxmit_urb[8]; ++ dma_addr_t dma_transfer_addr; /* (in) dma addr for transfer_buffer */ ++#endif ++ ++#ifdef PLATFORM_OS_XP ++ PIRP pxmit_irp[8]; ++#endif ++ ++#ifdef PLATFORM_OS_CE ++ USB_TRANSFER usb_transfer_write_port; ++#endif ++ ++ u8 bpending[8]; ++ ++ sint last[8]; ++ ++#endif ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ u8 *phead; ++ u8 *pdata; ++ u8 *ptail; ++ u8 *pend; ++ u32 ff_hwaddr; ++ u8 pg_num; ++ u8 agg_num; ++#ifdef PLATFORM_OS_XP ++ PMDL pxmitbuf_mdl; ++ PIRP pxmitbuf_irp; ++ PSDBUS_REQUEST_PACKET pxmitbuf_sdrp; ++#endif ++#endif ++ ++#if defined(DBG_XMIT_BUF )|| defined(DBG_XMIT_BUF_EXT) ++ u8 no; ++#endif ++ ++}; ++ ++ ++struct xmit_frame ++{ ++ _list list; ++ ++ struct pkt_attrib attrib; ++ ++ _pkt *pkt; ++ ++ int frame_tag; ++ ++ _adapter *padapter; ++ ++ u8 *buf_addr; ++ ++ struct xmit_buf *pxmitbuf; ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ u8 pg_num; ++ u8 agg_num; ++#endif ++ ++#ifdef CONFIG_USB_HCI ++#ifdef CONFIG_USB_TX_AGGREGATION ++ u8 agg_num; ++#endif ++ s8 pkt_offset; ++#ifdef CONFIG_RTL8192D ++ u8 EMPktNum; ++ u16 EMPktLen[5];//The max value by HW ++#endif ++#endif ++ ++#ifdef CONFIG_XMIT_ACK ++ u8 ack_report; ++#endif ++ ++ u8 *alloc_addr; /* the actual address this xmitframe allocated */ ++ u8 ext_tag; /* 0:data, 1:mgmt */ ++ ++}; ++ ++struct tx_servq { ++ _list tx_pending; ++ _queue sta_pending; ++ int qcnt; ++}; ++ ++ ++struct sta_xmit_priv ++{ ++ _lock lock; ++ sint option; ++ sint apsd_setting; //When bit mask is on, the associated edca queue supports APSD. ++ ++ ++ //struct tx_servq blk_q[MAX_NUMBLKS]; ++ struct tx_servq be_q; //priority == 0,3 ++ struct tx_servq bk_q; //priority == 1,2 ++ struct tx_servq vi_q; //priority == 4,5 ++ struct tx_servq vo_q; //priority == 6,7 ++ _list legacy_dz; ++ _list apsd; ++ ++ u16 txseq_tid[16]; ++ ++ //uint sta_tx_bytes; ++ //u64 sta_tx_pkts; ++ //uint sta_tx_fail; ++ ++ ++}; ++ ++ ++struct hw_txqueue { ++ volatile sint head; ++ volatile sint tail; ++ volatile sint free_sz; //in units of 64 bytes ++ volatile sint free_cmdsz; ++ volatile sint txsz[8]; ++ uint ff_hwaddr; ++ uint cmd_hwaddr; ++ sint ac_tag; ++}; ++ ++struct agg_pkt_info{ ++ u16 offset; ++ u16 pkt_len; ++}; ++ ++struct xmit_priv { ++ ++ _lock lock; ++ ++ _sema xmit_sema; ++ _sema terminate_xmitthread_sema; ++ ++ //_queue blk_strms[MAX_NUMBLKS]; ++ _queue be_pending; ++ _queue bk_pending; ++ _queue vi_pending; ++ _queue vo_pending; ++ _queue bm_pending; ++ ++ //_queue legacy_dz_queue; ++ //_queue apsd_queue; ++ ++ u8 *pallocated_frame_buf; ++ u8 *pxmit_frame_buf; ++ uint free_xmitframe_cnt; ++ _queue free_xmit_queue; ++ ++ //uint mapping_addr; ++ //uint pkt_sz; ++ ++ u8 *xframe_ext_alloc_addr; ++ u8 *xframe_ext; ++ uint free_xframe_ext_cnt; ++ _queue free_xframe_ext_queue; ++ ++ //struct hw_txqueue be_txqueue; ++ //struct hw_txqueue bk_txqueue; ++ //struct hw_txqueue vi_txqueue; ++ //struct hw_txqueue vo_txqueue; ++ //struct hw_txqueue bmc_txqueue; ++ ++ uint frag_len; ++ ++ _adapter *adapter; ++ ++ u8 vcs_setting; ++ u8 vcs; ++ u8 vcs_type; ++ //u16 rts_thresh; ++ ++ u64 tx_bytes; ++ u64 tx_pkts; ++ u64 tx_drop; ++ u64 last_tx_bytes; ++ u64 last_tx_pkts; ++ ++ struct hw_xmit *hwxmits; ++ u8 hwxmit_entry; ++ ++ u8 wmm_para_seq[4];//sequence for wmm ac parameter strength from large to small. it's value is 0->vo, 1->vi, 2->be, 3->bk. ++ ++#ifdef CONFIG_USB_HCI ++ _sema tx_retevt;//all tx return event; ++ u8 txirp_cnt;// ++ ++#ifdef PLATFORM_OS_CE ++ USB_TRANSFER usb_transfer_write_port; ++// USB_TRANSFER usb_transfer_write_mem; ++#endif ++#ifdef PLATFORM_LINUX ++ struct tasklet_struct xmit_tasklet; ++#endif ++#ifdef PLATFORM_FREEBSD ++ struct task xmit_tasklet; ++#endif ++ //per AC pending irp ++ int beq_cnt; ++ int bkq_cnt; ++ int viq_cnt; ++ int voq_cnt; ++ ++#endif ++ ++#ifdef CONFIG_PCI_HCI ++ // Tx ++ struct rtw_tx_ring tx_ring[PCI_MAX_TX_QUEUE_COUNT]; ++ int txringcount[PCI_MAX_TX_QUEUE_COUNT]; ++ u8 beaconDMAing; //flag of indicating beacon is transmiting to HW by DMA ++#ifdef PLATFORM_LINUX ++ struct tasklet_struct xmit_tasklet; ++#endif ++#endif ++ ++#ifdef CONFIG_SDIO_HCI ++#ifdef CONFIG_SDIO_TX_TASKLET ++ #ifdef PLATFORM_LINUX ++ struct tasklet_struct xmit_tasklet; ++ #endif /* PLATFORM_LINUX */ ++#else ++ _thread_hdl_ SdioXmitThread; ++ _sema SdioXmitSema; ++ _sema SdioXmitTerminateSema; ++#endif /* CONFIG_SDIO_TX_TASKLET */ ++#endif /* CONFIG_SDIO_HCI */ ++ ++ _queue free_xmitbuf_queue; ++ _queue pending_xmitbuf_queue; ++ u8 *pallocated_xmitbuf; ++ u8 *pxmitbuf; ++ uint free_xmitbuf_cnt; ++ ++ _queue free_xmit_extbuf_queue; ++ u8 *pallocated_xmit_extbuf; ++ u8 *pxmit_extbuf; ++ uint free_xmit_extbuf_cnt; ++ ++ u16 nqos_ssn; ++ #ifdef CONFIG_TX_EARLY_MODE ++ ++ #ifdef CONFIG_SDIO_HCI ++ #define MAX_AGG_PKT_NUM 20 ++ #else ++ #define MAX_AGG_PKT_NUM 256 //Max tx ampdu coounts ++ #endif ++ ++ struct agg_pkt_info agg_pkt[MAX_AGG_PKT_NUM]; ++ #endif ++ ++#ifdef CONFIG_XMIT_ACK ++ int ack_tx; ++ _mutex ack_tx_mutex; ++ struct submit_ctx ack_tx_ops; ++#endif ++ _lock lock_sctx; ++}; ++ ++extern struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv); ++extern s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf); ++ ++extern struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv); ++extern s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf); ++ ++void rtw_count_tx_stats(_adapter *padapter, struct xmit_frame *pxmitframe, int sz); ++extern void rtw_update_protection(_adapter *padapter, u8 *ie, uint ie_len); ++extern s32 rtw_make_wlanhdr(_adapter *padapter, u8 *hdr, struct pkt_attrib *pattrib); ++extern s32 rtw_put_snap(u8 *data, u16 h_proto); ++ ++extern struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv); ++struct xmit_frame *rtw_alloc_xmitframe_ext(struct xmit_priv *pxmitpriv); ++struct xmit_frame *rtw_alloc_xmitframe_once(struct xmit_priv *pxmitpriv); ++extern s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitframe); ++extern void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, _queue *pframequeue); ++struct tx_servq *rtw_get_sta_pending(_adapter *padapter, struct sta_info *psta, sint up, u8 *ac); ++extern s32 rtw_xmitframe_enqueue(_adapter *padapter, struct xmit_frame *pxmitframe); ++extern struct xmit_frame* rtw_dequeue_xframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit_i, sint entry); ++ ++extern s32 rtw_xmit_classifier(_adapter *padapter, struct xmit_frame *pxmitframe); ++extern u32 rtw_calculate_wlan_pkt_size_by_attribue(struct pkt_attrib *pattrib); ++#define rtw_wlan_pkt_size(f) rtw_calculate_wlan_pkt_size_by_attribue(&f->attrib) ++extern s32 rtw_xmitframe_coalesce(_adapter *padapter, _pkt *pkt, struct xmit_frame *pxmitframe); ++#ifdef CONFIG_IEEE80211W ++extern s32 rtw_mgmt_xmitframe_coalesce(_adapter *padapter, _pkt *pkt, struct xmit_frame *pxmitframe); ++#endif //CONFIG_IEEE80211W ++#ifdef CONFIG_TDLS ++s32 rtw_xmit_tdls_coalesce(_adapter *padapter, struct xmit_frame *pxmitframe, u8 action); ++#endif ++s32 _rtw_init_hw_txqueue(struct hw_txqueue* phw_txqueue, u8 ac_tag); ++void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv); ++ ++ ++s32 rtw_txframes_pending(_adapter *padapter); ++s32 rtw_txframes_sta_ac_pending(_adapter *padapter, struct pkt_attrib *pattrib); ++void rtw_init_hwxmits(struct hw_xmit *phwxmit, sint entry); ++ ++ ++s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, _adapter *padapter); ++void _rtw_free_xmit_priv (struct xmit_priv *pxmitpriv); ++ ++ ++void rtw_alloc_hwxmits(_adapter *padapter); ++void rtw_free_hwxmits(_adapter *padapter); ++ ++ ++s32 rtw_xmit(_adapter *padapter, _pkt **pkt); ++ ++#if defined(CONFIG_AP_MODE) || defined(CONFIG_TDLS) ++sint xmitframe_enqueue_for_sleeping_sta(_adapter *padapter, struct xmit_frame *pxmitframe); ++void stop_sta_xmit(_adapter *padapter, struct sta_info *psta); ++void wakeup_sta_to_xmit(_adapter *padapter, struct sta_info *psta); ++void xmit_delivery_enabled_frames(_adapter *padapter, struct sta_info *psta); ++#endif ++ ++u8 qos_acm(u8 acm_mask, u8 priority); ++ ++#ifdef CONFIG_XMIT_THREAD_MODE ++void enqueue_pending_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf); ++struct xmit_buf* dequeue_pending_xmitbuf(struct xmit_priv *pxmitpriv); ++struct xmit_buf* dequeue_pending_xmitbuf_under_survey(struct xmit_priv *pxmitpriv); ++sint check_pending_xmitbuf(struct xmit_priv *pxmitpriv); ++thread_return rtw_xmit_thread(thread_context context); ++#endif ++ ++u32 rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe); ++ ++#ifdef CONFIG_XMIT_ACK ++int rtw_ack_tx_wait(struct xmit_priv *pxmitpriv, u32 timeout_ms); ++void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status); ++#endif //CONFIG_XMIT_ACK ++ ++ ++//include after declaring struct xmit_buf, in order to avoid warning ++#include ++ ++#endif //_RTL871X_XMIT_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/sdio_hal.h b/drivers/net/wireless/rtl818x/rtl8189/include/sdio_hal.h +new file mode 100644 +index 00000000..60e261bc +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/sdio_hal.h +@@ -0,0 +1,41 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __SDIO_HAL_H__ ++#define __SDIO_HAL_H__ ++ ++ ++extern u8 sd_hal_bus_init(PADAPTER padapter); ++extern u8 sd_hal_bus_deinit(PADAPTER padapter); ++ ++u8 sd_int_isr(PADAPTER padapter); ++void sd_int_dpc(PADAPTER padapter); ++ ++#ifdef CONFIG_RTL8723A ++void rtl8723as_set_hal_ops(PADAPTER padapter); ++#define hal_set_hal_ops rtl8723as_set_hal_ops ++#endif ++ ++#ifdef CONFIG_RTL8188E ++void rtl8188es_set_hal_ops(PADAPTER padapter); ++#define hal_set_hal_ops rtl8188es_set_hal_ops ++#endif ++ ++#endif //__SDIO_HAL_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/sdio_ops.h b/drivers/net/wireless/rtl818x/rtl8189/include/sdio_ops.h +new file mode 100644 +index 00000000..e79b0fc8 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/sdio_ops.h +@@ -0,0 +1,84 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __SDIO_OPS_H__ ++#define __SDIO_OPS_H__ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef PLATFORM_LINUX ++#include ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++#ifdef PLATFORM_OS_XP ++#include ++struct async_context ++{ ++ PMDL pmdl; ++ PSDBUS_REQUEST_PACKET sdrp; ++ unsigned char* r_buf; ++ unsigned char* padapter; ++}; ++#endif ++#ifdef PLATFORM_OS_CE ++#include ++#endif ++#endif ++ ++ ++extern void sdio_set_intf_ops(struct _io_ops *pops); ++ ++//extern void sdio_func1cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem); ++//extern void sdio_func1cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem); ++extern u8 SdioLocalCmd52Read1Byte(PADAPTER padapter, u32 addr); ++extern void SdioLocalCmd52Write1Byte(PADAPTER padapter, u32 addr, u8 v); ++extern s32 _sdio_local_read(PADAPTER padapter, u32 addr, u32 cnt, u8 *pbuf); ++extern s32 sdio_local_read(PADAPTER padapter, u32 addr, u32 cnt, u8 *pbuf); ++extern s32 _sdio_local_write(PADAPTER padapter, u32 addr, u32 cnt, u8 *pbuf); ++extern s32 sdio_local_write(PADAPTER padapter, u32 addr, u32 cnt, u8 *pbuf); ++ ++u32 _sdio_read32(PADAPTER padapter, u32 addr); ++s32 _sdio_write32(PADAPTER padapter, u32 addr, u32 val); ++ ++extern void InitInterrupt8723ASdio(PADAPTER padapter); ++extern void InitSysInterrupt8723ASdio(PADAPTER padapter); ++extern void EnableInterrupt8723ASdio(PADAPTER padapter); ++extern void DisableInterrupt8723ASdio(PADAPTER padapter); ++extern void sd_int_hdl(PADAPTER padapter); ++#ifdef CONFIG_RTL8723A ++extern u8 HalQueryTxBufferStatus8723ASdio(PADAPTER padapter); ++#endif //CONFIG_RTL8723A ++#ifdef CONFIG_RTL8188E ++extern u8 HalQueryTxBufferStatus8189ESdio(PADAPTER padapter); ++#endif //CONFIG_RTL8188E ++extern void InitInterrupt8188ESdio(PADAPTER padapter); ++extern void EnableInterrupt8188ESdio(PADAPTER padapter); ++extern void DisableInterrupt8188ESdio(PADAPTER padapter); ++extern void UpdateInterruptMask8188ESdio(PADAPTER padapter, u32 AddMSR, u32 RemoveMSR); ++ ++#ifdef CONFIG_WOWLAN ++extern u8 RecvOnePkt(PADAPTER padapter, u32 size); ++extern void ClearInterrupt8189ESdio(PADAPTER padapter); ++#endif //CONFIG_WOWLAN ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/sdio_ops_ce.h b/drivers/net/wireless/rtl818x/rtl8189/include/sdio_ops_ce.h +new file mode 100644 +index 00000000..d2da2933 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/sdio_ops_ce.h +@@ -0,0 +1,55 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _SDIO_OPS_WINCE_H_ ++#define _SDIO_OPS_WINCE_H_ ++ ++#include ++#include ++#include ++#include ++ ++ ++#ifdef PLATFORM_OS_CE ++ ++ ++extern u8 sdbus_cmd52r_ce(struct intf_priv *pintfpriv, u32 addr); ++ ++ ++extern void sdbus_cmd52w_ce(struct intf_priv *pintfpriv, u32 addr,u8 val8); ++ ++ ++uint sdbus_read_blocks_to_membuf_ce(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf); ++ ++extern uint sdbus_read_bytes_to_membuf_ce(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf); ++ ++ ++extern uint sdbus_write_blocks_from_membuf_ce(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf,u8 async); ++ ++extern uint sdbus_write_bytes_from_membuf_ce(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf); ++extern u8 sdbus_func1cmd52r_ce(struct intf_priv *pintfpriv, u32 addr); ++extern void sdbus_func1cmd52w_ce(struct intf_priv *pintfpriv, u32 addr, u8 val8); ++extern uint sdbus_read_reg(struct intf_priv *pintfpriv, u32 addr, u32 cnt,void *pdata); ++extern uint sdbus_write_reg(struct intf_priv *pintfpriv, u32 addr, u32 cnt,void *pdata); ++extern void sdio_read_int(_adapter *padapter, u32 addr,u8 sz,void *pdata); ++ ++#endif ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/sdio_ops_linux.h b/drivers/net/wireless/rtl818x/rtl8189/include/sdio_ops_linux.h +new file mode 100644 +index 00000000..008c5bf0 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/sdio_ops_linux.h +@@ -0,0 +1,52 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __SDIO_OPS_LINUX_H__ ++#define __SDIO_OPS_LINUX_H__ ++ ++#define SDIO_ERR_VAL8 0xEA ++#define SDIO_ERR_VAL16 0xEAEA ++#define SDIO_ERR_VAL32 0xEAEAEAEA ++ ++u8 sd_f0_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err); ++void sd_f0_write8(struct intf_hdl *pintfhdl, u32 addr, u8 v, s32 *err); ++ ++s32 _sd_cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata); ++s32 _sd_cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata); ++s32 sd_cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata); ++s32 sd_cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata); ++ ++u8 _sd_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err); ++u8 sd_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err); ++u16 sd_read16(struct intf_hdl *pintfhdl, u32 addr, s32 *err); ++u32 _sd_read32(struct intf_hdl *pintfhdl, u32 addr, s32 *err); ++u32 sd_read32(struct intf_hdl *pintfhdl, u32 addr, s32 *err); ++s32 _sd_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata); ++s32 sd_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata); ++void sd_write8(struct intf_hdl *pintfhdl, u32 addr, u8 v, s32 *err); ++void sd_write16(struct intf_hdl *pintfhdl, u32 addr, u16 v, s32 *err); ++void _sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err); ++void sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err); ++s32 _sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata); ++s32 sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata); ++ ++ ++void rtw_sdio_set_irq_thd(struct dvobj_priv *dvobj, _thread_hdl_ thd_hdl); ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/sdio_ops_xp.h b/drivers/net/wireless/rtl818x/rtl8189/include/sdio_ops_xp.h +new file mode 100644 +index 00000000..757b35d4 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/sdio_ops_xp.h +@@ -0,0 +1,55 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _SDIO_OPS_XP_H_ ++#define _SDIO_OPS_XP_H_ ++ ++#include ++#include ++#include ++#include ++ ++ ++#ifdef PLATFORM_OS_XP ++ ++ ++extern u8 sdbus_cmd52r_xp(struct intf_priv *pintfpriv, u32 addr); ++ ++ ++extern void sdbus_cmd52w_xp(struct intf_priv *pintfpriv, u32 addr,u8 val8); ++ ++ ++uint sdbus_read_blocks_to_membuf_xp(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf); ++ ++extern uint sdbus_read_bytes_to_membuf_xp(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf); ++ ++ ++extern uint sdbus_write_blocks_from_membuf_xp(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf,u8 async); ++ ++extern uint sdbus_write_bytes_from_membuf_xp(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf); ++extern u8 sdbus_func1cmd52r_xp(struct intf_priv *pintfpriv, u32 addr); ++extern void sdbus_func1cmd52w_xp(struct intf_priv *pintfpriv, u32 addr, u8 val8); ++extern uint sdbus_read_reg(struct intf_priv *pintfpriv, u32 addr, u32 cnt,void *pdata); ++extern uint sdbus_write_reg(struct intf_priv *pintfpriv, u32 addr, u32 cnt,void *pdata); ++extern void sdio_read_int(_adapter *padapter, u32 addr,u8 sz,void *pdata); ++ ++#endif ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/sdio_osintf.h b/drivers/net/wireless/rtl818x/rtl8189/include/sdio_osintf.h +new file mode 100644 +index 00000000..51ec5b75 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/sdio_osintf.h +@@ -0,0 +1,40 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __SDIO_OSINTF_H__ ++#define __SDIO_OSINTF_H__ ++ ++ ++#include ++#include ++#include ++ ++ ++u8 sd_hal_bus_init(PADAPTER padapter); ++u8 sd_hal_bus_deinit(PADAPTER padapter); ++void sd_c2h_hdl(PADAPTER padapter); ++ ++#ifdef PLATFORM_OS_CE ++extern NDIS_STATUS ce_sd_get_dev_hdl(PADAPTER padapter); ++SD_API_STATUS ce_sd_int_callback(SD_DEVICE_HANDLE hDevice, PADAPTER padapter); ++extern void sd_setup_irs(PADAPTER padapter); ++#endif ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/sta_info.h b/drivers/net/wireless/rtl818x/rtl8189/include/sta_info.h +new file mode 100644 +index 00000000..3b8ed787 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/sta_info.h +@@ -0,0 +1,479 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __STA_INFO_H_ ++#define __STA_INFO_H_ ++ ++#include ++#include ++#include ++#include ++ ++#define IBSS_START_MAC_ID 2 ++#define NUM_STA 32 ++#define NUM_ACL 16 ++ ++ ++//if mode ==0, then the sta is allowed once the addr is hit. ++//if mode ==1, then the sta is rejected once the addr is non-hit. ++struct rtw_wlan_acl_node { ++ _list list; ++ u8 addr[ETH_ALEN]; ++ u8 valid; ++}; ++ ++//mode=0, disable ++//mode=1, accept unless in deny list ++//mode=2, deny unless in accept list ++struct wlan_acl_pool { ++ int mode; ++ int num; ++ struct rtw_wlan_acl_node aclnode[NUM_ACL]; ++ _queue acl_node_q; ++}; ++ ++typedef struct _RSSI_STA{ ++ s32 UndecoratedSmoothedPWDB; ++ s32 UndecoratedSmoothedCCK; ++ s32 UndecoratedSmoothedOFDM; ++ u64 PacketMap; ++ u8 ValidBit; ++}RSSI_STA, *PRSSI_STA; ++ ++struct stainfo_stats { ++ ++ u64 rx_mgnt_pkts; ++ u64 rx_beacon_pkts; ++ u64 rx_probereq_pkts; ++ u64 rx_probersp_pkts; ++ u64 rx_probersp_bm_pkts; ++ u64 rx_probersp_uo_pkts; ++ u64 rx_ctrl_pkts; ++ u64 rx_data_pkts; ++ ++ u64 last_rx_mgnt_pkts; ++ u64 last_rx_beacon_pkts; ++ u64 last_rx_probereq_pkts; ++ u64 last_rx_probersp_pkts; ++ u64 last_rx_probersp_bm_pkts; ++ u64 last_rx_probersp_uo_pkts; ++ u64 last_rx_ctrl_pkts; ++ u64 last_rx_data_pkts; ++ ++ u64 rx_bytes; ++ u64 rx_drops; ++ ++ u64 tx_pkts; ++ u64 tx_bytes; ++ u64 tx_drops; ++ ++}; ++ ++#ifdef CONFIG_TDLS ++struct TDLS_PeerKey { ++ u8 kck[16]; /* TPK-KCK */ ++ u8 tk[16]; /* TPK-TK; only CCMP will be used */ ++} ; ++#endif //CONFIG_TDLS ++ ++struct sta_info { ++ ++ _lock lock; ++ _list list; //free_sta_queue ++ _list hash_list; //sta_hash ++ //_list asoc_list; //20061114 ++ //_list sleep_list;//sleep_q ++ //_list wakeup_list;//wakeup_q ++ _adapter *padapter; ++ ++ struct sta_xmit_priv sta_xmitpriv; ++ struct sta_recv_priv sta_recvpriv; ++ ++ _queue sleep_q; ++ unsigned int sleepq_len; ++ ++ uint state; ++ uint aid; ++ uint mac_id; ++ uint qos_option; ++ u8 hwaddr[ETH_ALEN]; ++ ++ uint ieee8021x_blocked; //0: allowed, 1:blocked ++ uint dot118021XPrivacy; //aes, tkip... ++ union Keytype dot11tkiptxmickey; ++ union Keytype dot11tkiprxmickey; ++ union Keytype dot118021x_UncstKey; ++ union pn48 dot11txpn; // PN48 used for Unicast xmit. ++#ifdef CONFIG_IEEE80211W ++ union pn48 dot11wtxpn; // PN48 used for Unicast mgmt xmit. ++#endif //CONFIG_IEEE80211W ++ union pn48 dot11rxpn; // PN48 used for Unicast recv. ++ ++ ++ u8 bssrateset[16]; ++ u32 bssratelen; ++ s32 rssi; ++ s32 signal_quality; ++ ++ u8 cts2self; ++ u8 rtsen; ++ ++ u8 raid; ++ u8 init_rate; ++ u32 ra_mask; ++ u8 wireless_mode; // NETWORK_TYPE ++ struct stainfo_stats sta_stats; ++ ++#ifdef CONFIG_TDLS ++ u32 tdls_sta_state; ++ u8 dialog; ++ u8 SNonce[32]; ++ u8 ANonce[32]; ++ u32 TDLS_PeerKey_Lifetime; ++ u16 TPK_count; ++ _timer TPK_timer; ++ struct TDLS_PeerKey tpk; ++ u16 stat_code; ++ u8 off_ch; ++ u16 ch_switch_time; ++ u16 ch_switch_timeout; ++ u8 option; ++ _timer option_timer; ++ _timer base_ch_timer; ++ _timer off_ch_timer; ++ ++ _timer handshake_timer; ++ _timer alive_timer1; ++ _timer alive_timer2; ++ u8 timer_flag; ++ u8 alive_count; ++#endif //CONFIG_TDLS ++ ++ //for A-MPDU TX, ADDBA timeout check ++ _timer addba_retry_timer; ++ ++ //for A-MPDU Rx reordering buffer control ++ struct recv_reorder_ctrl recvreorder_ctrl[16]; ++ ++ //for A-MPDU Tx ++ //unsigned char ampdu_txen_bitmap; ++ u16 BA_starting_seqctrl[16]; ++ ++ ++#ifdef CONFIG_80211N_HT ++ struct ht_priv htpriv; ++#endif ++ ++ //Notes: ++ //STA_Mode: ++ //curr_network(mlme_priv/security_priv/qos/ht) + sta_info: (STA & AP) CAP/INFO ++ //scan_q: AP CAP/INFO ++ ++ //AP_Mode: ++ //curr_network(mlme_priv/security_priv/qos/ht) : AP CAP/INFO ++ //sta_info: (AP & STA) CAP/INFO ++ ++#ifdef CONFIG_AP_MODE ++ ++ _list asoc_list; ++ _list auth_list; ++ ++ unsigned int expire_to; ++ unsigned int auth_seq; ++ unsigned int authalg; ++ unsigned char chg_txt[128]; ++ ++ u16 capability; ++ int flags; ++ ++ int dot8021xalg;//0:disable, 1:psk, 2:802.1x ++ int wpa_psk;//0:disable, bit(0): WPA, bit(1):WPA2 ++ int wpa_group_cipher; ++ int wpa2_group_cipher; ++ int wpa_pairwise_cipher; ++ int wpa2_pairwise_cipher; ++ ++ u8 bpairwise_key_installed; ++ ++#ifdef CONFIG_NATIVEAP_MLME ++ u8 wpa_ie[32]; ++ ++ u8 nonerp_set; ++ u8 no_short_slot_time_set; ++ u8 no_short_preamble_set; ++ u8 no_ht_gf_set; ++ u8 no_ht_set; ++ u8 ht_20mhz_set; ++#endif // CONFIG_NATIVEAP_MLME ++ ++#ifdef CONFIG_ATMEL_RC_PATCH ++ u8 flag_atmel_rc; ++#endif ++ ++ unsigned int tx_ra_bitmap; ++ u8 qos_info; ++ ++ u8 max_sp_len; ++ u8 uapsd_bk;//BIT(0): Delivery enabled, BIT(1): Trigger enabled ++ u8 uapsd_be; ++ u8 uapsd_vi; ++ u8 uapsd_vo; ++ ++ u8 has_legacy_ac; ++ unsigned int sleepq_ac_len; ++ ++#ifdef CONFIG_P2P ++ //p2p priv data ++ u8 is_p2p_device; ++ u8 p2p_status_code; ++ ++ //p2p client info ++ u8 dev_addr[ETH_ALEN]; ++ //u8 iface_addr[ETH_ALEN];//= hwaddr[ETH_ALEN] ++ u8 dev_cap; ++ u16 config_methods; ++ u8 primary_dev_type[8]; ++ u8 num_of_secdev_type; ++ u8 secdev_types_list[32];// 32/8 == 4; ++ u16 dev_name_len; ++ u8 dev_name[32]; ++#endif //CONFIG_P2P ++ ++#ifdef CONFIG_TX_MCAST2UNI ++ u8 under_exist_checking; ++#endif // CONFIG_TX_MCAST2UNI ++ ++ u8 keep_alive_trycnt; ++ ++#endif // CONFIG_AP_MODE ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ u8 *passoc_req; ++ u32 assoc_req_len; ++#endif ++ ++#ifdef DBG_TRX_STA_PKTS ++ //per AC dbg irp cnts ++ int rx_be_cnt; ++ int rx_bk_cnt; ++ int rx_vi_cnt; ++ int rx_vo_cnt; ++ //per AC dbg irp cnts ++ int tx_be_cnt; ++ int tx_bk_cnt; ++ int tx_vi_cnt; ++ int tx_vo_cnt; ++#endif ++ //for DM ++ RSSI_STA rssi_stat; ++ ++ //ODM_STA_INFO_T ++ // ================ODM Relative Info======================= ++ // Please be care, dont declare too much structure here. It will cost memory * STA support num. ++ // ++ // ++ // 2011/10/20 MH Add for ODM STA info. ++ // ++ // Driver Write ++ u8 bValid; // record the sta status link or not? ++ //u8 WirelessMode; // ++ u8 IOTPeer; // Enum value. HT_IOT_PEER_E ++ // ODM Write ++ //1 PHY_STATUS_INFO ++ u8 RSSI_Path[4]; // ++ u8 RSSI_Ave; ++ u8 RXEVM[4]; ++ u8 RXSNR[4]; ++ ++ u8 rssi_level; //for Refresh RA mask ++ // ODM Write ++ //1 TX_INFO (may changed by IC) ++ //TX_INFO_T pTxInfo; // Define in IC folder. Move lower layer. ++ // ++ // ================ODM Relative Info======================= ++ // ++ ++ /* To store the sequence number of received management frame */ ++ u16 RxMgmtFrameSeqNum; ++}; ++ ++#define sta_rx_pkts(sta) \ ++ (sta->sta_stats.rx_mgnt_pkts \ ++ + sta->sta_stats.rx_ctrl_pkts \ ++ + sta->sta_stats.rx_data_pkts) ++ ++#define sta_last_rx_pkts(sta) \ ++ (sta->sta_stats.last_rx_mgnt_pkts \ ++ + sta->sta_stats.last_rx_ctrl_pkts \ ++ + sta->sta_stats.last_rx_data_pkts) ++ ++#define sta_rx_data_pkts(sta) \ ++ (sta->sta_stats.rx_data_pkts) ++ ++#define sta_last_rx_data_pkts(sta) \ ++ (sta->sta_stats.last_rx_data_pkts) ++ ++#define sta_rx_mgnt_pkts(sta) \ ++ (sta->sta_stats.rx_mgnt_pkts) ++ ++#define sta_last_rx_mgnt_pkts(sta) \ ++ (sta->sta_stats.last_rx_mgnt_pkts) ++ ++#define sta_rx_beacon_pkts(sta) \ ++ (sta->sta_stats.rx_beacon_pkts) ++ ++#define sta_last_rx_beacon_pkts(sta) \ ++ (sta->sta_stats.last_rx_beacon_pkts) ++ ++#define sta_rx_probereq_pkts(sta) \ ++ (sta->sta_stats.rx_probereq_pkts) ++ ++#define sta_last_rx_probereq_pkts(sta) \ ++ (sta->sta_stats.last_rx_probereq_pkts) ++ ++#define sta_rx_probersp_pkts(sta) \ ++ (sta->sta_stats.rx_probersp_pkts) ++ ++#define sta_last_rx_probersp_pkts(sta) \ ++ (sta->sta_stats.last_rx_probersp_pkts) ++ ++#define sta_rx_probersp_bm_pkts(sta) \ ++ (sta->sta_stats.rx_probersp_bm_pkts) ++ ++#define sta_last_rx_probersp_bm_pkts(sta) \ ++ (sta->sta_stats.last_rx_probersp_bm_pkts) ++ ++#define sta_rx_probersp_uo_pkts(sta) \ ++ (sta->sta_stats.rx_probersp_uo_pkts) ++ ++#define sta_last_rx_probersp_uo_pkts(sta) \ ++ (sta->sta_stats.last_rx_probersp_uo_pkts) ++ ++#define sta_update_last_rx_pkts(sta) \ ++ do { \ ++ sta->sta_stats.last_rx_mgnt_pkts = sta->sta_stats.rx_mgnt_pkts; \ ++ sta->sta_stats.last_rx_beacon_pkts = sta->sta_stats.rx_beacon_pkts; \ ++ sta->sta_stats.last_rx_probereq_pkts = sta->sta_stats.rx_probereq_pkts; \ ++ sta->sta_stats.last_rx_probersp_pkts = sta->sta_stats.rx_probersp_pkts; \ ++ sta->sta_stats.last_rx_probersp_bm_pkts = sta->sta_stats.rx_probersp_bm_pkts; \ ++ sta->sta_stats.last_rx_probersp_uo_pkts = sta->sta_stats.rx_probersp_uo_pkts; \ ++ sta->sta_stats.last_rx_ctrl_pkts = sta->sta_stats.rx_ctrl_pkts; \ ++ sta->sta_stats.last_rx_data_pkts = sta->sta_stats.rx_data_pkts; \ ++ } while(0) ++ ++#define STA_RX_PKTS_ARG(sta) \ ++ sta->sta_stats.rx_mgnt_pkts \ ++ , sta->sta_stats.rx_ctrl_pkts \ ++ , sta->sta_stats.rx_data_pkts ++ ++#define STA_LAST_RX_PKTS_ARG(sta) \ ++ sta->sta_stats.last_rx_mgnt_pkts \ ++ , sta->sta_stats.last_rx_ctrl_pkts \ ++ , sta->sta_stats.last_rx_data_pkts ++ ++#define STA_RX_PKTS_DIFF_ARG(sta) \ ++ sta->sta_stats.rx_mgnt_pkts - sta->sta_stats.last_rx_mgnt_pkts \ ++ , sta->sta_stats.rx_ctrl_pkts - sta->sta_stats.last_rx_ctrl_pkts \ ++ , sta->sta_stats.rx_data_pkts -sta->sta_stats.last_rx_data_pkts ++ ++#define STA_PKTS_FMT "(m:%llu, c:%llu, d:%llu)" ++ ++struct sta_priv { ++ ++ u8 *pallocated_stainfo_buf; ++ u8 *pstainfo_buf; ++ _queue free_sta_queue; ++ ++ _lock sta_hash_lock; ++ _list sta_hash[NUM_STA]; ++ int asoc_sta_count; ++ _queue sleep_q; ++ _queue wakeup_q; ++ ++ _adapter *padapter; ++ ++ ++#ifdef CONFIG_AP_MODE ++ _list asoc_list; ++ _list auth_list; ++ _lock asoc_list_lock; ++ _lock auth_list_lock; ++ u8 asoc_list_cnt; ++ u8 auth_list_cnt; ++ ++ unsigned int auth_to; //sec, time to expire in authenticating. ++ unsigned int assoc_to; //sec, time to expire before associating. ++ unsigned int expire_to; //sec , time to expire after associated. ++ ++ /* pointers to STA info; based on allocated AID or NULL if AID free ++ * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1 ++ * and so on ++ */ ++ struct sta_info *sta_aid[NUM_STA]; ++ ++ u16 sta_dz_bitmap;//only support 15 stations, staion aid bitmap for sleeping sta. ++ u16 tim_bitmap;//only support 15 stations, aid=0~15 mapping bit0~bit15 ++ ++ u16 max_num_sta; ++ ++ struct wlan_acl_pool acl_list; ++#endif ++ ++#ifdef CONFIG_ATMEL_RC_PATCH ++ u8 atmel_rc_pattern [6]; ++#endif ++ ++}; ++ ++ ++__inline static u32 wifi_mac_hash(u8 *mac) ++{ ++ u32 x; ++ ++ x = mac[0]; ++ x = (x << 2) ^ mac[1]; ++ x = (x << 2) ^ mac[2]; ++ x = (x << 2) ^ mac[3]; ++ x = (x << 2) ^ mac[4]; ++ x = (x << 2) ^ mac[5]; ++ ++ x ^= x >> 8; ++ x = x & (NUM_STA - 1); ++ ++ return x; ++} ++ ++ ++extern u32 _rtw_init_sta_priv(struct sta_priv *pstapriv); ++extern u32 _rtw_free_sta_priv(struct sta_priv *pstapriv); ++ ++#define stainfo_offset_valid(offset) (offset < NUM_STA && offset >= 0) ++int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta); ++struct sta_info *rtw_get_stainfo_by_offset(struct sta_priv *stapriv, int offset); ++ ++extern struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr); ++extern u32 rtw_free_stainfo(_adapter *padapter , struct sta_info *psta); ++extern void rtw_free_all_stainfo(_adapter *padapter); ++extern struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr); ++extern u32 rtw_init_bcmc_stainfo(_adapter* padapter); ++extern struct sta_info* rtw_get_bcmc_stainfo(_adapter* padapter); ++extern u8 rtw_access_ctrl(_adapter *padapter, u8 *mac_addr); ++ ++#endif //_STA_INFO_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/usb_hal.h b/drivers/net/wireless/rtl818x/rtl8189/include/usb_hal.h +new file mode 100644 +index 00000000..c3ac5e97 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/usb_hal.h +@@ -0,0 +1,47 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __USB_HAL_H__ ++#define __USB_HAL_H__ ++ ++#ifdef CONFIG_RTL8192C ++void rtl8192cu_set_hal_ops(_adapter * padapter); ++#define hal_set_hal_ops rtl8192cu_set_hal_ops ++#endif ++ ++#ifdef CONFIG_RTL8192D ++void rtl8192du_set_hal_ops(_adapter * padapter); ++#define hal_set_hal_ops rtl8192du_set_hal_ops ++#endif ++ ++#ifdef CONFIG_RTL8723A ++void rtl8723au_set_hal_ops(_adapter * padapter); ++#define hal_set_hal_ops rtl8723au_set_hal_ops ++#endif ++ ++#ifdef CONFIG_RTL8188E ++void rtl8188eu_set_hal_ops(_adapter * padapter); ++#define hal_set_hal_ops rtl8188eu_set_hal_ops ++#endif ++ ++#ifdef CONFIG_INTEL_PROXIM ++extern _adapter *rtw_usb_get_sw_pointer(void); ++#endif //CONFIG_INTEL_PROXIM ++#endif //__USB_HAL_H__ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/usb_ops.h b/drivers/net/wireless/rtl818x/rtl8189/include/usb_ops.h +new file mode 100644 +index 00000000..bb0a2b6d +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/usb_ops.h +@@ -0,0 +1,123 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __USB_OPS_H_ ++#define __USB_OPS_H_ ++ ++#include ++#include ++#include ++#include ++ ++#define REALTEK_USB_VENQT_READ 0xC0 ++#define REALTEK_USB_VENQT_WRITE 0x40 ++#define REALTEK_USB_VENQT_CMD_REQ 0x05 ++#define REALTEK_USB_VENQT_CMD_IDX 0x00 ++ ++enum{ ++ VENDOR_WRITE = 0x00, ++ VENDOR_READ = 0x01, ++}; ++#define ALIGNMENT_UNIT 16 ++#define MAX_VENDOR_REQ_CMD_SIZE 254 //8188cu SIE Support ++#define MAX_USB_IO_CTL_SIZE (MAX_VENDOR_REQ_CMD_SIZE +ALIGNMENT_UNIT) ++ ++#ifdef PLATFORM_LINUX ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)) ++#define rtw_usb_control_msg(dev, pipe, request, requesttype, value, index, data, size, timeout_ms) \ ++ usb_control_msg((dev), (pipe), (request), (requesttype), (value), (index), (data), (size), (timeout_ms)) ++#define rtw_usb_bulk_msg(usb_dev, pipe, data, len, actual_length, timeout_ms) \ ++ usb_bulk_msg((usb_dev), (pipe), (data), (len), (actual_length), (timeout_ms)) ++#else ++#define rtw_usb_control_msg(dev, pipe, request, requesttype, value, index, data, size,timeout_ms) \ ++ usb_control_msg((dev), (pipe), (request), (requesttype), (value), (index), (data), (size), \ ++ ((timeout_ms) == 0) ||((timeout_ms)*HZ/1000>0)?((timeout_ms)*HZ/1000):1) ++#define rtw_usb_bulk_msg(usb_dev, pipe, data, len, actual_length, timeout_ms) \ ++ usb_bulk_msg((usb_dev), (pipe), (data), (len), (actual_length), \ ++ ((timeout_ms) == 0) ||((timeout_ms)*HZ/1000>0)?((timeout_ms)*HZ/1000):1) ++#endif ++#include ++#endif //PLATFORM_LINUX ++ ++#ifdef CONFIG_RTL8192C ++void rtl8192cu_set_hw_type(_adapter *padapter); ++#define hal_set_hw_type rtl8192cu_set_hw_type ++ ++void rtl8192cu_set_intf_ops(struct _io_ops *pops); ++#define usb_set_intf_ops rtl8192cu_set_intf_ops ++ ++void rtl8192cu_recv_tasklet(void *priv); ++ ++void rtl8192cu_xmit_tasklet(void *priv); ++#endif ++ ++#ifdef CONFIG_RTL8723A ++void rtl8723au_set_hw_type(_adapter *padapter); ++#define hal_set_hw_type rtl8723au_set_hw_type ++ ++void rtl8723au_set_intf_ops(struct _io_ops *pops); ++#define usb_set_intf_ops rtl8723au_set_intf_ops ++ ++void rtl8192cu_recv_tasklet(void *priv); ++ ++void rtl8192cu_xmit_tasklet(void *priv); ++#endif ++ ++#ifdef CONFIG_RTL8192D ++void rtl8192du_set_hw_type(_adapter *padapter); ++#define hal_set_hw_type rtl8192du_set_hw_type ++void rtl8192du_set_intf_ops(struct _io_ops *pops); ++#define usb_set_intf_ops rtl8192du_set_intf_ops ++#ifndef PLATFORM_FREEBSD ++void rtl8192du_recv_tasklet(void *priv); ++#else // PLATFORM_FREEBSD ++void rtl8192du_recv_tasklet(void *priv, int npending); ++#ifdef CONFIG_RX_INDICATE_QUEUE ++void rtw_rx_indicate_tasklet(void *priv, int npending); ++#endif // CONFIG_RX_INDICATE_QUEUE ++#endif // PLATFORM_FREEBSD ++ ++void rtl8192du_xmit_tasklet(void *priv); ++#endif ++ ++#ifdef CONFIG_RTL8188E ++void rtl8188eu_set_hw_type(_adapter *padapter); ++#define hal_set_hw_type rtl8188eu_set_hw_type ++void rtl8188eu_set_intf_ops(struct _io_ops *pops); ++#define usb_set_intf_ops rtl8188eu_set_intf_ops ++#endif ++ ++#define USB_HIGH_SPEED_BULK_SIZE 512 ++#define USB_FULL_SPEED_BULK_SIZE 64 ++ ++static inline u8 rtw_usb_bulk_size_boundary(_adapter * padapter,int buf_len) ++{ ++ u8 rst = _TRUE; ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ ++ if (pdvobjpriv->ishighspeed == _TRUE) ++ rst = (0 == (buf_len) % USB_HIGH_SPEED_BULK_SIZE)?_TRUE:_FALSE; ++ else ++ rst = (0 == (buf_len) % USB_FULL_SPEED_BULK_SIZE)?_TRUE:_FALSE; ++ return rst; ++} ++ ++ ++#endif //__USB_OPS_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/usb_ops_linux.h b/drivers/net/wireless/rtl818x/rtl8189/include/usb_ops_linux.h +new file mode 100644 +index 00000000..d418ba26 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/usb_ops_linux.h +@@ -0,0 +1,63 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __USB_OPS_LINUX_H__ ++#define __USB_OPS_LINUX_H__ ++ ++#define VENDOR_CMD_MAX_DATA_LEN 254 ++ ++#define RTW_USB_CONTROL_MSG_TIMEOUT_TEST 10//ms ++#define RTW_USB_CONTROL_MSG_TIMEOUT 500//ms ++ ++#if defined(CONFIG_VENDOR_REQ_RETRY) && defined(CONFIG_USB_VENDOR_REQ_MUTEX) ++/* vendor req retry should be in the situation when each vendor req is atomically submitted from others */ ++#define MAX_USBCTRL_VENDORREQ_TIMES 10 ++#else ++#define MAX_USBCTRL_VENDORREQ_TIMES 1 ++#endif ++ ++#define RTW_USB_BULKOUT_TIMEOUT 5000//ms ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) || (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) ++#define _usbctrl_vendorreq_async_callback(urb, regs) _usbctrl_vendorreq_async_callback(urb) ++#define usb_bulkout_zero_complete(purb, regs) usb_bulkout_zero_complete(purb) ++#define usb_write_mem_complete(purb, regs) usb_write_mem_complete(purb) ++#define usb_write_port_complete(purb, regs) usb_write_port_complete(purb) ++#define usb_read_port_complete(purb, regs) usb_read_port_complete(purb) ++#define usb_read_interrupt_complete(purb, regs) usb_read_interrupt_complete(purb) ++#endif ++ ++#ifdef CONFIG_USB_SUPPORT_ASYNC_VDN_REQ ++int usb_async_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val); ++int usb_async_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val); ++int usb_async_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val); ++#endif /* CONFIG_USB_SUPPORT_ASYNC_VDN_REQ */ ++ ++unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr); ++ ++void usb_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem); ++void usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem); ++ ++void usb_read_port_cancel(struct intf_hdl *pintfhdl); ++ ++u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem); ++void usb_write_port_cancel(struct intf_hdl *pintfhdl); ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/usb_osintf.h b/drivers/net/wireless/rtl818x/rtl8189/include/usb_osintf.h +new file mode 100644 +index 00000000..753013dd +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/usb_osintf.h +@@ -0,0 +1,38 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __USB_OSINTF_H ++#define __USB_OSINTF_H ++ ++#include ++#include ++#include ++#include ++ ++#define USBD_HALTED(Status) ((ULONG)(Status) >> 30 == 3) ++ ++ ++//uint usb_dvobj_init(_adapter * adapter); ++//void usb_dvobj_deinit(_adapter * adapter); ++ ++u8 usbvendorrequest(struct dvobj_priv *pdvobjpriv, RT_USB_BREQUEST brequest, RT_USB_WVALUE wvalue, u8 windex, void* data, u8 datalen, u8 isdirectionin); ++ ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/usb_vendor_req.h b/drivers/net/wireless/rtl818x/rtl8189/include/usb_vendor_req.h +new file mode 100644 +index 00000000..b60eefac +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/usb_vendor_req.h +@@ -0,0 +1,60 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _USB_VENDOR_REQUEST_H_ ++#define _USB_VENDOR_REQUEST_H_ ++ ++//4 Set/Get Register related wIndex/Data ++#define RT_USB_RESET_MASK_OFF 0 ++#define RT_USB_RESET_MASK_ON 1 ++#define RT_USB_SLEEP_MASK_OFF 0 ++#define RT_USB_SLEEP_MASK_ON 1 ++#define RT_USB_LDO_ON 1 ++#define RT_USB_LDO_OFF 0 ++ ++//4 Set/Get SYSCLK related wValue or Data ++#define RT_USB_SYSCLK_32KHZ 0 ++#define RT_USB_SYSCLK_40MHZ 1 ++#define RT_USB_SYSCLK_60MHZ 2 ++ ++ ++typedef enum _RT_USB_BREQUEST { ++ RT_USB_SET_REGISTER = 1, ++ RT_USB_SET_SYSCLK = 2, ++ RT_USB_GET_SYSCLK = 3, ++ RT_USB_GET_REGISTER = 4 ++} RT_USB_BREQUEST; ++ ++ ++typedef enum _RT_USB_WVALUE { ++ RT_USB_RESET_MASK = 1, ++ RT_USB_SLEEP_MASK = 2, ++ RT_USB_USB_HRCPWM = 3, ++ RT_USB_LDO = 4, ++ RT_USB_BOOT_TYPE = 5 ++} RT_USB_WVALUE; ++ ++ ++//BOOLEAN usbvendorrequest(PCE_USB_DEVICE CEdevice, RT_USB_BREQUEST bRequest, RT_USB_WVALUE wValue, UCHAR wIndex, PVOID Data, UCHAR DataLength, BOOLEAN isDirectionIn); ++//BOOLEAN CEusbGetStatusRequest(PCE_USB_DEVICE CEdevice, IN USHORT Op, IN USHORT Index, PVOID Data); ++//BOOLEAN CEusbFeatureRequest(PCE_USB_DEVICE CEdevice, IN USHORT Op, IN USHORT FeatureSelector, IN USHORT Index); ++//BOOLEAN CEusbGetDescriptorRequest(PCE_USB_DEVICE CEdevice, IN short urbLength, IN UCHAR DescriptorType, IN UCHAR Index, IN USHORT LanguageId, IN PVOID TransferBuffer, IN ULONG TransferBufferLength); ++ ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/wifi.h b/drivers/net/wireless/rtl818x/rtl8189/include/wifi.h +new file mode 100644 +index 00000000..39f46186 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/wifi.h +@@ -0,0 +1,1263 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef _WIFI_H_ ++#define _WIFI_H_ ++ ++#include ++ ++#ifdef BIT ++//#error "BIT define occurred earlier elsewhere!\n" ++#undef BIT ++#endif ++#define BIT(x) (1 << (x)) ++ ++ ++#define WLAN_ETHHDR_LEN 14 ++#define WLAN_ETHADDR_LEN 6 ++#define WLAN_IEEE_OUI_LEN 3 ++#define WLAN_ADDR_LEN 6 ++#define WLAN_CRC_LEN 4 ++#define WLAN_BSSID_LEN 6 ++#define WLAN_BSS_TS_LEN 8 ++#define WLAN_HDR_A3_LEN 24 ++#define WLAN_HDR_A4_LEN 30 ++#define WLAN_HDR_A3_QOS_LEN 26 ++#define WLAN_HDR_A4_QOS_LEN 32 ++#define WLAN_SSID_MAXLEN 32 ++#define WLAN_DATA_MAXLEN 2312 ++ ++#define WLAN_A3_PN_OFFSET 24 ++#define WLAN_A4_PN_OFFSET 30 ++ ++#define WLAN_MIN_ETHFRM_LEN 60 ++#define WLAN_MAX_ETHFRM_LEN 1514 ++#define WLAN_ETHHDR_LEN 14 ++ ++#define P80211CAPTURE_VERSION 0x80211001 ++ ++// This value is tested by WiFi 11n Test Plan 5.2.3. ++// This test verifies the WLAN NIC can update the NAV through sending the CTS with large duration. ++#define WiFiNavUpperUs 30000 // 30 ms ++ ++#ifdef GREEN_HILL ++#pragma pack(1) ++#endif ++ ++enum WIFI_FRAME_TYPE { ++ WIFI_MGT_TYPE = (0), ++ WIFI_CTRL_TYPE = (BIT(2)), ++ WIFI_DATA_TYPE = (BIT(3)), ++ WIFI_QOS_DATA_TYPE = (BIT(7)|BIT(3)), //!< QoS Data ++}; ++ ++enum WIFI_FRAME_SUBTYPE { ++ ++ // below is for mgt frame ++ WIFI_ASSOCREQ = (0 | WIFI_MGT_TYPE), ++ WIFI_ASSOCRSP = (BIT(4) | WIFI_MGT_TYPE), ++ WIFI_REASSOCREQ = (BIT(5) | WIFI_MGT_TYPE), ++ WIFI_REASSOCRSP = (BIT(5) | BIT(4) | WIFI_MGT_TYPE), ++ WIFI_PROBEREQ = (BIT(6) | WIFI_MGT_TYPE), ++ WIFI_PROBERSP = (BIT(6) | BIT(4) | WIFI_MGT_TYPE), ++ WIFI_BEACON = (BIT(7) | WIFI_MGT_TYPE), ++ WIFI_ATIM = (BIT(7) | BIT(4) | WIFI_MGT_TYPE), ++ WIFI_DISASSOC = (BIT(7) | BIT(5) | WIFI_MGT_TYPE), ++ WIFI_AUTH = (BIT(7) | BIT(5) | BIT(4) | WIFI_MGT_TYPE), ++ WIFI_DEAUTH = (BIT(7) | BIT(6) | WIFI_MGT_TYPE), ++ WIFI_ACTION = (BIT(7) | BIT(6) | BIT(4) | WIFI_MGT_TYPE), ++ ++ // below is for control frame ++ WIFI_PSPOLL = (BIT(7) | BIT(5) | WIFI_CTRL_TYPE), ++ WIFI_RTS = (BIT(7) | BIT(5) | BIT(4) | WIFI_CTRL_TYPE), ++ WIFI_CTS = (BIT(7) | BIT(6) | WIFI_CTRL_TYPE), ++ WIFI_ACK = (BIT(7) | BIT(6) | BIT(4) | WIFI_CTRL_TYPE), ++ WIFI_CFEND = (BIT(7) | BIT(6) | BIT(5) | WIFI_CTRL_TYPE), ++ WIFI_CFEND_CFACK = (BIT(7) | BIT(6) | BIT(5) | BIT(4) | WIFI_CTRL_TYPE), ++ ++ // below is for data frame ++ WIFI_DATA = (0 | WIFI_DATA_TYPE), ++ WIFI_DATA_CFACK = (BIT(4) | WIFI_DATA_TYPE), ++ WIFI_DATA_CFPOLL = (BIT(5) | WIFI_DATA_TYPE), ++ WIFI_DATA_CFACKPOLL = (BIT(5) | BIT(4) | WIFI_DATA_TYPE), ++ WIFI_DATA_NULL = (BIT(6) | WIFI_DATA_TYPE), ++ WIFI_CF_ACK = (BIT(6) | BIT(4) | WIFI_DATA_TYPE), ++ WIFI_CF_POLL = (BIT(6) | BIT(5) | WIFI_DATA_TYPE), ++ WIFI_CF_ACKPOLL = (BIT(6) | BIT(5) | BIT(4) | WIFI_DATA_TYPE), ++ WIFI_QOS_DATA_NULL = (BIT(6) | WIFI_QOS_DATA_TYPE), ++}; ++ ++enum WIFI_REASON_CODE { ++ _RSON_RESERVED_ = 0, ++ _RSON_UNSPECIFIED_ = 1, ++ _RSON_AUTH_NO_LONGER_VALID_ = 2, ++ _RSON_DEAUTH_STA_LEAVING_ = 3, ++ _RSON_INACTIVITY_ = 4, ++ _RSON_UNABLE_HANDLE_ = 5, ++ _RSON_CLS2_ = 6, ++ _RSON_CLS3_ = 7, ++ _RSON_DISAOC_STA_LEAVING_ = 8, ++ _RSON_ASOC_NOT_AUTH_ = 9, ++ ++ // WPA reason ++ _RSON_INVALID_IE_ = 13, ++ _RSON_MIC_FAILURE_ = 14, ++ _RSON_4WAY_HNDSHK_TIMEOUT_ = 15, ++ _RSON_GROUP_KEY_UPDATE_TIMEOUT_ = 16, ++ _RSON_DIFF_IE_ = 17, ++ _RSON_MLTCST_CIPHER_NOT_VALID_ = 18, ++ _RSON_UNICST_CIPHER_NOT_VALID_ = 19, ++ _RSON_AKMP_NOT_VALID_ = 20, ++ _RSON_UNSUPPORT_RSNE_VER_ = 21, ++ _RSON_INVALID_RSNE_CAP_ = 22, ++ _RSON_IEEE_802DOT1X_AUTH_FAIL_ = 23, ++ ++ //belowing are Realtek definition ++ _RSON_PMK_NOT_AVAILABLE_ = 24, ++ _RSON_TDLS_TEAR_TOOFAR_ = 25, ++ _RSON_TDLS_TEAR_UN_RSN_ = 26, ++}; ++ ++/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */ ++#if 0 ++#define WLAN_REASON_UNSPECIFIED 1 ++#define WLAN_REASON_PREV_AUTH_NOT_VALID 2 ++#define WLAN_REASON_DEAUTH_LEAVING 3 ++#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 ++#define WLAN_REASON_DISASSOC_AP_BUSY 5 ++#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 ++#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 ++#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 ++#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 ++#endif ++/* IEEE 802.11h */ ++#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10 ++#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11 ++#if 0 ++/* IEEE 802.11i */ ++#define WLAN_REASON_INVALID_IE 13 ++#define WLAN_REASON_MICHAEL_MIC_FAILURE 14 ++#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15 ++#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16 ++#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17 ++#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18 ++#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19 ++#define WLAN_REASON_AKMP_NOT_VALID 20 ++#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21 ++#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22 ++#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23 ++#define WLAN_REASON_CIPHER_SUITE_REJECTED 24 ++#endif ++ ++enum WIFI_STATUS_CODE { ++ _STATS_SUCCESSFUL_ = 0, ++ _STATS_FAILURE_ = 1, ++ _STATS_CAP_FAIL_ = 10, ++ _STATS_NO_ASOC_ = 11, ++ _STATS_OTHER_ = 12, ++ _STATS_NO_SUPP_ALG_ = 13, ++ _STATS_OUT_OF_AUTH_SEQ_ = 14, ++ _STATS_CHALLENGE_FAIL_ = 15, ++ _STATS_AUTH_TIMEOUT_ = 16, ++ _STATS_UNABLE_HANDLE_STA_ = 17, ++ _STATS_RATE_FAIL_ = 18, ++}; ++ ++/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */ ++#if 0 ++#define WLAN_STATUS_SUCCESS 0 ++#define WLAN_STATUS_UNSPECIFIED_FAILURE 1 ++#define WLAN_STATUS_CAPS_UNSUPPORTED 10 ++#define WLAN_STATUS_REASSOC_NO_ASSOC 11 ++#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 ++#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 ++#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 ++#define WLAN_STATUS_CHALLENGE_FAIL 15 ++#define WLAN_STATUS_AUTH_TIMEOUT 16 ++#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 ++#define WLAN_STATUS_ASSOC_DENIED_RATES 18 ++#endif ++//entended ++/* IEEE 802.11b */ ++#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 ++#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 ++#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 ++/* IEEE 802.11h */ ++#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22 ++#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23 ++#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24 ++/* IEEE 802.11g */ ++#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25 ++#define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26 ++#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27 ++/* IEEE 802.11w */ ++#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30 ++#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 ++/* IEEE 802.11i */ ++#define WLAN_STATUS_INVALID_IE 40 ++#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41 ++#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42 ++#define WLAN_STATUS_AKMP_NOT_VALID 43 ++#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44 ++#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45 ++#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46 ++#define WLAN_STATUS_TS_NOT_CREATED 47 ++#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48 ++#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49 ++#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50 ++#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51 ++/* IEEE 802.11r */ ++#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52 ++#define WLAN_STATUS_INVALID_PMKID 53 ++#define WLAN_STATUS_INVALID_MDIE 54 ++#define WLAN_STATUS_INVALID_FTIE 55 ++ ++ ++enum WIFI_REG_DOMAIN { ++ DOMAIN_FCC = 1, ++ DOMAIN_IC = 2, ++ DOMAIN_ETSI = 3, ++ DOMAIN_SPAIN = 4, ++ DOMAIN_FRANCE = 5, ++ DOMAIN_MKK = 6, ++ DOMAIN_ISRAEL = 7, ++ DOMAIN_MKK1 = 8, ++ DOMAIN_MKK2 = 9, ++ DOMAIN_MKK3 = 10, ++ DOMAIN_MAX ++}; ++ ++#define _TO_DS_ BIT(8) ++#define _FROM_DS_ BIT(9) ++#define _MORE_FRAG_ BIT(10) ++#define _RETRY_ BIT(11) ++#define _PWRMGT_ BIT(12) ++#define _MORE_DATA_ BIT(13) ++#define _PRIVACY_ BIT(14) ++#define _ORDER_ BIT(15) ++ ++#define SetToDs(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) |= cpu_to_le16(_TO_DS_); \ ++ } while(0) ++ ++#define GetToDs(pbuf) (((*(unsigned short *)(pbuf)) & le16_to_cpu(_TO_DS_)) != 0) ++ ++#define ClearToDs(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) &= (~cpu_to_le16(_TO_DS_)); \ ++ } while(0) ++ ++#define SetFrDs(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) |= cpu_to_le16(_FROM_DS_); \ ++ } while(0) ++ ++#define GetFrDs(pbuf) (((*(unsigned short *)(pbuf)) & le16_to_cpu(_FROM_DS_)) != 0) ++ ++#define ClearFrDs(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) &= (~cpu_to_le16(_FROM_DS_)); \ ++ } while(0) ++ ++#define get_tofr_ds(pframe) ((GetToDs(pframe) << 1) | GetFrDs(pframe)) ++ ++ ++#define SetMFrag(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) |= cpu_to_le16(_MORE_FRAG_); \ ++ } while(0) ++ ++#define GetMFrag(pbuf) (((*(unsigned short *)(pbuf)) & le16_to_cpu(_MORE_FRAG_)) != 0) ++ ++#define ClearMFrag(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) &= (~cpu_to_le16(_MORE_FRAG_)); \ ++ } while(0) ++ ++#define SetRetry(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) |= cpu_to_le16(_RETRY_); \ ++ } while(0) ++ ++#define GetRetry(pbuf) (((*(unsigned short *)(pbuf)) & le16_to_cpu(_RETRY_)) != 0) ++ ++#define ClearRetry(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) &= (~cpu_to_le16(_RETRY_)); \ ++ } while(0) ++ ++#define SetPwrMgt(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) |= cpu_to_le16(_PWRMGT_); \ ++ } while(0) ++ ++#define GetPwrMgt(pbuf) (((*(unsigned short *)(pbuf)) & le16_to_cpu(_PWRMGT_)) != 0) ++ ++#define ClearPwrMgt(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) &= (~cpu_to_le16(_PWRMGT_)); \ ++ } while(0) ++ ++#define SetMData(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) |= cpu_to_le16(_MORE_DATA_); \ ++ } while(0) ++ ++#define GetMData(pbuf) (((*(unsigned short *)(pbuf)) & le16_to_cpu(_MORE_DATA_)) != 0) ++ ++#define ClearMData(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) &= (~cpu_to_le16(_MORE_DATA_)); \ ++ } while(0) ++ ++#define SetPrivacy(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) |= cpu_to_le16(_PRIVACY_); \ ++ } while(0) ++ ++#define GetPrivacy(pbuf) (((*(unsigned short *)(pbuf)) & le16_to_cpu(_PRIVACY_)) != 0) ++ ++#define ClearPrivacy(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) &= (~cpu_to_le16(_PRIVACY_)); \ ++ } while(0) ++ ++ ++#define GetOrder(pbuf) (((*(unsigned short *)(pbuf)) & le16_to_cpu(_ORDER_)) != 0) ++ ++#define GetFrameType(pbuf) (le16_to_cpu(*(unsigned short *)(pbuf)) & (BIT(3) | BIT(2))) ++ ++#define SetFrameType(pbuf,type) \ ++ do { \ ++ *(unsigned short *)(pbuf) &= __constant_cpu_to_le16(~(BIT(3) | BIT(2))); \ ++ *(unsigned short *)(pbuf) |= __constant_cpu_to_le16(type); \ ++ } while(0) ++ ++#define GetFrameSubType(pbuf) (cpu_to_le16(*(unsigned short *)(pbuf)) & (BIT(7) | BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2))) ++ ++#define SetFrameSubType(pbuf,type) \ ++ do { \ ++ *(unsigned short *)(pbuf) &= cpu_to_le16(~(BIT(7) | BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2))); \ ++ *(unsigned short *)(pbuf) |= cpu_to_le16(type); \ ++ } while(0) ++ ++#define GetSequence(pbuf) (cpu_to_le16(*(unsigned short *)((SIZE_PTR)(pbuf) + 22)) >> 4) ++ ++#define GetFragNum(pbuf) (cpu_to_le16(*(unsigned short *)((SIZE_PTR)(pbuf) + 22)) & 0x0f) ++ ++#define GetTupleCache(pbuf) (cpu_to_le16(*(unsigned short *)((SIZE_PTR)(pbuf) + 22))) ++ ++#define SetFragNum(pbuf, num) \ ++ do { \ ++ *(unsigned short *)((SIZE_PTR)(pbuf) + 22) = \ ++ ((*(unsigned short *)((SIZE_PTR)(pbuf) + 22)) & le16_to_cpu(~(0x000f))) | \ ++ cpu_to_le16(0x0f & (num)); \ ++ } while(0) ++ ++#define SetSeqNum(pbuf, num) \ ++ do { \ ++ *(unsigned short *)((SIZE_PTR)(pbuf) + 22) = \ ++ ((*(unsigned short *)((SIZE_PTR)(pbuf) + 22)) & le16_to_cpu((unsigned short)~0xfff0)) | \ ++ le16_to_cpu((unsigned short)(0xfff0 & (num << 4))); \ ++ } while(0) ++ ++#define SetDuration(pbuf, dur) \ ++ do { \ ++ *(unsigned short *)((SIZE_PTR)(pbuf) + 2) = cpu_to_le16(0xffff & (dur)); \ ++ } while(0) ++ ++ ++#define SetPriority(pbuf, tid) \ ++ do { \ ++ *(unsigned short *)(pbuf) |= cpu_to_le16(tid & 0xf); \ ++ } while(0) ++ ++#define GetPriority(pbuf) ((le16_to_cpu(*(unsigned short *)(pbuf))) & 0xf) ++ ++#define SetEOSP(pbuf, eosp) \ ++ do { \ ++ *(unsigned short *)(pbuf) |= cpu_to_le16( (eosp & 1) << 4); \ ++ } while(0) ++ ++#define SetAckpolicy(pbuf, ack) \ ++ do { \ ++ *(unsigned short *)(pbuf) |= cpu_to_le16( (ack & 3) << 5); \ ++ } while(0) ++ ++#define GetAckpolicy(pbuf) (((le16_to_cpu(*(unsigned short *)pbuf)) >> 5) & 0x3) ++ ++#define GetAMsdu(pbuf) (((le16_to_cpu(*(unsigned short *)pbuf)) >> 7) & 0x1) ++ ++#define SetAMsdu(pbuf, amsdu) \ ++ do { \ ++ *(unsigned short *)(pbuf) |= cpu_to_le16( (amsdu & 1) << 7); \ ++ } while(0) ++ ++#define GetAid(pbuf) (cpu_to_le16(*(unsigned short *)((SIZE_PTR)(pbuf) + 2)) & 0x3fff) ++ ++#define GetTid(pbuf) (cpu_to_le16(*(unsigned short *)((SIZE_PTR)(pbuf) + (((GetToDs(pbuf)<<1)|GetFrDs(pbuf))==3?30:24))) & 0x000f) ++ ++#define GetAddr1Ptr(pbuf) ((unsigned char *)((SIZE_PTR)(pbuf) + 4)) ++ ++#define GetAddr2Ptr(pbuf) ((unsigned char *)((SIZE_PTR)(pbuf) + 10)) ++ ++#define GetAddr3Ptr(pbuf) ((unsigned char *)((SIZE_PTR)(pbuf) + 16)) ++ ++#define GetAddr4Ptr(pbuf) ((unsigned char *)((SIZE_PTR)(pbuf) + 24)) ++ ++#define MacAddr_isBcst(addr) \ ++( \ ++ ( (addr[0] == 0xff) && (addr[1] == 0xff) && \ ++ (addr[2] == 0xff) && (addr[3] == 0xff) && \ ++ (addr[4] == 0xff) && (addr[5] == 0xff) ) ? _TRUE : _FALSE \ ++) ++ ++__inline static int IS_MCAST(unsigned char *da) ++{ ++ if ((*da) & 0x01) ++ return _TRUE; ++ else ++ return _FALSE; ++} ++ ++ ++__inline static unsigned char * get_da(unsigned char *pframe) ++{ ++ unsigned char *da; ++ unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); ++ ++ switch (to_fr_ds) { ++ case 0x00: // ToDs=0, FromDs=0 ++ da = GetAddr1Ptr(pframe); ++ break; ++ case 0x01: // ToDs=0, FromDs=1 ++ da = GetAddr1Ptr(pframe); ++ break; ++ case 0x02: // ToDs=1, FromDs=0 ++ da = GetAddr3Ptr(pframe); ++ break; ++ default: // ToDs=1, FromDs=1 ++ da = GetAddr3Ptr(pframe); ++ break; ++ } ++ ++ return da; ++} ++ ++ ++__inline static unsigned char * get_sa(unsigned char *pframe) ++{ ++ unsigned char *sa; ++ unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); ++ ++ switch (to_fr_ds) { ++ case 0x00: // ToDs=0, FromDs=0 ++ sa = GetAddr2Ptr(pframe); ++ break; ++ case 0x01: // ToDs=0, FromDs=1 ++ sa = GetAddr3Ptr(pframe); ++ break; ++ case 0x02: // ToDs=1, FromDs=0 ++ sa = GetAddr2Ptr(pframe); ++ break; ++ default: // ToDs=1, FromDs=1 ++ sa = GetAddr4Ptr(pframe); ++ break; ++ } ++ ++ return sa; ++} ++ ++__inline static unsigned char * get_hdr_bssid(unsigned char *pframe) ++{ ++ unsigned char *sa; ++ unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); ++ ++ switch (to_fr_ds) { ++ case 0x00: // ToDs=0, FromDs=0 ++ sa = GetAddr3Ptr(pframe); ++ break; ++ case 0x01: // ToDs=0, FromDs=1 ++ sa = GetAddr2Ptr(pframe); ++ break; ++ case 0x02: // ToDs=1, FromDs=0 ++ sa = GetAddr1Ptr(pframe); ++ break; ++ case 0x03: // ToDs=1, FromDs=1 ++ sa = GetAddr1Ptr(pframe); ++ break; ++ default: ++ sa =NULL; //??????? ++ break; ++ } ++ ++ return sa; ++} ++ ++ ++__inline static int IsFrameTypeCtrl(unsigned char *pframe) ++{ ++ if(WIFI_CTRL_TYPE == GetFrameType(pframe)) ++ return _TRUE; ++ else ++ return _FALSE; ++} ++/*----------------------------------------------------------------------------- ++ Below is for the security related definition ++------------------------------------------------------------------------------*/ ++#define _RESERVED_FRAME_TYPE_ 0 ++#define _SKB_FRAME_TYPE_ 2 ++#define _PRE_ALLOCMEM_ 1 ++#define _PRE_ALLOCHDR_ 3 ++#define _PRE_ALLOCLLCHDR_ 4 ++#define _PRE_ALLOCICVHDR_ 5 ++#define _PRE_ALLOCMICHDR_ 6 ++ ++#define _SIFSTIME_ ((priv->pmib->dot11BssType.net_work_type&WIRELESS_11A)?16:10) ++#define _ACKCTSLNG_ 14 //14 bytes long, including crclng ++#define _CRCLNG_ 4 ++ ++#define _ASOCREQ_IE_OFFSET_ 4 // excluding wlan_hdr ++#define _ASOCRSP_IE_OFFSET_ 6 ++#define _REASOCREQ_IE_OFFSET_ 10 ++#define _REASOCRSP_IE_OFFSET_ 6 ++#define _PROBEREQ_IE_OFFSET_ 0 ++#define _PROBERSP_IE_OFFSET_ 12 ++#define _AUTH_IE_OFFSET_ 6 ++#define _DEAUTH_IE_OFFSET_ 0 ++#define _BEACON_IE_OFFSET_ 12 ++#define _PUBLIC_ACTION_IE_OFFSET_ 8 ++ ++#define _FIXED_IE_LENGTH_ _BEACON_IE_OFFSET_ ++ ++#define _SSID_IE_ 0 ++#define _SUPPORTEDRATES_IE_ 1 ++#define _DSSET_IE_ 3 ++#define _TIM_IE_ 5 ++#define _IBSS_PARA_IE_ 6 ++#define _COUNTRY_IE_ 7 ++#define _CHLGETXT_IE_ 16 ++#define _SUPPORTED_CH_IE_ 36 ++#define _CH_SWTICH_ANNOUNCE_ 37 //Secondary Channel Offset ++#define _RSN_IE_2_ 48 ++#define _SSN_IE_1_ 221 ++#define _ERPINFO_IE_ 42 ++#define _EXT_SUPPORTEDRATES_IE_ 50 ++ ++#define _HT_CAPABILITY_IE_ 45 ++#define _FTIE_ 55 ++#define _TIMEOUT_ITVL_IE_ 56 ++#define _SRC_IE_ 59 ++#define _HT_EXTRA_INFO_IE_ 61 ++#define _HT_ADD_INFO_IE_ 61 //_HT_EXTRA_INFO_IE_ ++#define _WAPI_IE_ 68 ++ ++ ++#define EID_BSSCoexistence 72 // 20/40 BSS Coexistence ++#define EID_BSSIntolerantChlReport 73 ++#define _RIC_Descriptor_IE_ 75 ++#ifdef CONFIG_IEEE80211W ++#define _MME_IE_ 76 //802.11w Management MIC element ++#endif //CONFIG_IEEE80211W ++#define _LINK_ID_IE_ 101 ++#define _CH_SWITCH_TIMING_ 104 ++#define _PTI_BUFFER_STATUS_ 106 ++#define _EXT_CAP_IE_ 127 ++#define _VENDOR_SPECIFIC_IE_ 221 ++ ++#define _RESERVED47_ 47 ++ ++/* --------------------------------------------------------------------------- ++ Below is the fixed elements... ++-----------------------------------------------------------------------------*/ ++#define _AUTH_ALGM_NUM_ 2 ++#define _AUTH_SEQ_NUM_ 2 ++#define _BEACON_ITERVAL_ 2 ++#define _CAPABILITY_ 2 ++#define _CURRENT_APADDR_ 6 ++#define _LISTEN_INTERVAL_ 2 ++#define _RSON_CODE_ 2 ++#define _ASOC_ID_ 2 ++#define _STATUS_CODE_ 2 ++#define _TIMESTAMP_ 8 ++ ++#define AUTH_ODD_TO 0 ++#define AUTH_EVEN_TO 1 ++ ++#define WLAN_ETHCONV_ENCAP 1 ++#define WLAN_ETHCONV_RFC1042 2 ++#define WLAN_ETHCONV_8021h 3 ++ ++#define cap_ESS BIT(0) ++#define cap_IBSS BIT(1) ++#define cap_CFPollable BIT(2) ++#define cap_CFRequest BIT(3) ++#define cap_Privacy BIT(4) ++#define cap_ShortPremble BIT(5) ++#define cap_PBCC BIT(6) ++#define cap_ChAgility BIT(7) ++#define cap_SpecMgmt BIT(8) ++#define cap_QoS BIT(9) ++#define cap_ShortSlot BIT(10) ++ ++/*----------------------------------------------------------------------------- ++ Below is the definition for 802.11i / 802.1x ++------------------------------------------------------------------------------*/ ++#define _IEEE8021X_MGT_ 1 // WPA ++#define _IEEE8021X_PSK_ 2 // WPA with pre-shared key ++ ++/* ++#define _NO_PRIVACY_ 0 ++#define _WEP_40_PRIVACY_ 1 ++#define _TKIP_PRIVACY_ 2 ++#define _WRAP_PRIVACY_ 3 ++#define _CCMP_PRIVACY_ 4 ++#define _WEP_104_PRIVACY_ 5 ++#define _WEP_WPA_MIXED_PRIVACY_ 6 // WEP + WPA ++*/ ++ ++#ifdef CONFIG_IEEE80211W ++#define _MME_IE_LENGTH_ 18 ++#endif //CONFIG_IEEE80211W ++/*----------------------------------------------------------------------------- ++ Below is the definition for WMM ++------------------------------------------------------------------------------*/ ++#define _WMM_IE_Length_ 7 // for WMM STA ++#define _WMM_Para_Element_Length_ 24 ++ ++ ++/*----------------------------------------------------------------------------- ++ Below is the definition for 802.11n ++------------------------------------------------------------------------------*/ ++ ++//#ifdef CONFIG_80211N_HT ++ ++#define SetOrderBit(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) |= cpu_to_le16(_ORDER_); \ ++ } while(0) ++ ++#define GetOrderBit(pbuf) (((*(unsigned short *)(pbuf)) & le16_to_cpu(_ORDER_)) != 0) ++ ++ ++/** ++ * struct rtw_ieee80211_bar - HT Block Ack Request ++ * ++ * This structure refers to "HT BlockAckReq" as ++ * described in 802.11n draft section 7.2.1.7.1 ++ */ ++ #if defined(PLATFORM_LINUX) || defined(CONFIG_RTL8712FW) ++struct rtw_ieee80211_bar { ++ unsigned short frame_control; ++ unsigned short duration; ++ unsigned char ra[6]; ++ unsigned char ta[6]; ++ unsigned short control; ++ unsigned short start_seq_num; ++} __attribute__((packed)); ++ #endif ++ ++/* 802.11 BAR control masks */ ++#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL 0x0000 ++#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA 0x0004 ++ ++ ++ #if defined(PLATFORM_LINUX) || defined(CONFIG_RTL8712FW) || defined(PLATFORM_FREEBSD) ++ ++ ++ ++ /** ++ * struct rtw_ieee80211_ht_cap - HT capabilities ++ * ++ * This structure refers to "HT capabilities element" as ++ * described in 802.11n draft section 7.3.2.52 ++ */ ++ ++struct rtw_ieee80211_ht_cap { ++ unsigned short cap_info; ++ unsigned char ampdu_params_info; ++ unsigned char supp_mcs_set[16]; ++ unsigned short extended_ht_cap_info; ++ unsigned int tx_BF_cap_info; ++ unsigned char antenna_selection_info; ++} __attribute__ ((packed)); ++ ++/** ++ * struct rtw_ieee80211_ht_cap - HT additional information ++ * ++ * This structure refers to "HT information element" as ++ * described in 802.11n draft section 7.3.2.53 ++ */ ++struct ieee80211_ht_addt_info { ++ unsigned char control_chan; ++ unsigned char ht_param; ++ unsigned short operation_mode; ++ unsigned short stbc_param; ++ unsigned char basic_set[16]; ++} __attribute__ ((packed)); ++ ++ ++struct HT_caps_element ++{ ++ union ++ { ++ struct ++ { ++ unsigned short HT_caps_info; ++ unsigned char AMPDU_para; ++ unsigned char MCS_rate[16]; ++ unsigned short HT_ext_caps; ++ unsigned int Beamforming_caps; ++ unsigned char ASEL_caps; ++ } HT_cap_element; ++ unsigned char HT_cap[26]; ++ }u; ++} __attribute__ ((packed)); ++ ++struct HT_info_element ++{ ++ unsigned char primary_channel; ++ unsigned char infos[5]; ++ unsigned char MCS_rate[16]; ++} __attribute__ ((packed)); ++ ++struct AC_param ++{ ++ unsigned char ACI_AIFSN; ++ unsigned char CW; ++ unsigned short TXOP_limit; ++} __attribute__ ((packed)); ++ ++struct WMM_para_element ++{ ++ unsigned char QoS_info; ++ unsigned char reserved; ++ struct AC_param ac_param[4]; ++} __attribute__ ((packed)); ++ ++struct ADDBA_request ++{ ++ unsigned char dialog_token; ++ unsigned short BA_para_set; ++ unsigned short BA_timeout_value; ++ unsigned short BA_starting_seqctrl; ++} __attribute__ ((packed)); ++ ++ ++ ++#endif ++ ++ ++#ifdef PLATFORM_WINDOWS ++ ++#pragma pack(1) ++ ++struct rtw_ieee80211_ht_cap { ++ unsigned short cap_info; ++ unsigned char ampdu_params_info; ++ unsigned char supp_mcs_set[16]; ++ unsigned short extended_ht_cap_info; ++ unsigned int tx_BF_cap_info; ++ unsigned char antenna_selection_info; ++}; ++ ++ ++struct ieee80211_ht_addt_info { ++ unsigned char control_chan; ++ unsigned char ht_param; ++ unsigned short operation_mode; ++ unsigned short stbc_param; ++ unsigned char basic_set[16]; ++}; ++ ++struct HT_caps_element ++{ ++ union ++ { ++ struct ++ { ++ unsigned short HT_caps_info; ++ unsigned char AMPDU_para; ++ unsigned char MCS_rate[16]; ++ unsigned short HT_ext_caps; ++ unsigned int Beamforming_caps; ++ unsigned char ASEL_caps; ++ } HT_cap_element; ++ unsigned char HT_cap[26]; ++ }; ++}; ++ ++struct HT_info_element ++{ ++ unsigned char primary_channel; ++ unsigned char infos[5]; ++ unsigned char MCS_rate[16]; ++}; ++ ++struct AC_param ++{ ++ unsigned char ACI_AIFSN; ++ unsigned char CW; ++ unsigned short TXOP_limit; ++}; ++ ++struct WMM_para_element ++{ ++ unsigned char QoS_info; ++ unsigned char reserved; ++ struct AC_param ac_param[4]; ++}; ++ ++struct ADDBA_request ++{ ++ unsigned char dialog_token; ++ unsigned short BA_para_set; ++ unsigned short BA_timeout_value; ++ unsigned short BA_starting_seqctrl; ++}; ++ ++ ++#pragma pack() ++ ++#endif ++ ++typedef enum _HT_CAP_AMPDU_FACTOR { ++ MAX_AMPDU_FACTOR_8K = 0, ++ MAX_AMPDU_FACTOR_16K = 1, ++ MAX_AMPDU_FACTOR_32K = 2, ++ MAX_AMPDU_FACTOR_64K = 3, ++}HT_CAP_AMPDU_FACTOR; ++ ++/* 802.11n HT capabilities masks */ ++#define IEEE80211_HT_CAP_SUP_WIDTH 0x0002 ++#define IEEE80211_HT_CAP_SM_PS 0x000C ++#define IEEE80211_HT_CAP_GRN_FLD 0x0010 ++#define IEEE80211_HT_CAP_SGI_20 0x0020 ++#define IEEE80211_HT_CAP_SGI_40 0x0040 ++#define IEEE80211_HT_CAP_TX_STBC 0x0080 ++#define IEEE80211_HT_CAP_RX_STBC 0x0300 ++#define IEEE80211_HT_CAP_DELAY_BA 0x0400 ++#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 ++#define IEEE80211_HT_CAP_DSSSCCK40 0x1000 ++/* 802.11n HT capability AMPDU settings */ ++#define IEEE80211_HT_CAP_AMPDU_FACTOR 0x03 ++#define IEEE80211_HT_CAP_AMPDU_DENSITY 0x1C ++/* 802.11n HT capability MSC set */ ++#define IEEE80211_SUPP_MCS_SET_UEQM 4 ++#define IEEE80211_HT_CAP_MAX_STREAMS 4 ++#define IEEE80211_SUPP_MCS_SET_LEN 10 ++/* maximum streams the spec allows */ ++#define IEEE80211_HT_CAP_MCS_TX_DEFINED 0x01 ++#define IEEE80211_HT_CAP_MCS_TX_RX_DIFF 0x02 ++#define IEEE80211_HT_CAP_MCS_TX_STREAMS 0x0C ++#define IEEE80211_HT_CAP_MCS_TX_UEQM 0x10 ++/* 802.11n HT IE masks */ ++#define IEEE80211_HT_IE_CHA_SEC_OFFSET 0x03 ++#define IEEE80211_HT_IE_CHA_SEC_NONE 0x00 ++#define IEEE80211_HT_IE_CHA_SEC_ABOVE 0x01 ++#define IEEE80211_HT_IE_CHA_SEC_BELOW 0x03 ++#define IEEE80211_HT_IE_CHA_WIDTH 0x04 ++#define IEEE80211_HT_IE_HT_PROTECTION 0x0003 ++#define IEEE80211_HT_IE_NON_GF_STA_PRSNT 0x0004 ++#define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010 ++ ++/* block-ack parameters */ ++#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002 ++#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C ++#define RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFC0 ++#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000 ++#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800 ++ ++/* ++ * A-PMDU buffer sizes ++ * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) ++ */ ++#define IEEE80211_MIN_AMPDU_BUF 0x8 ++#define IEEE80211_MAX_AMPDU_BUF 0x40 ++ ++ ++/* Spatial Multiplexing Power Save Modes */ ++#define WLAN_HT_CAP_SM_PS_STATIC 0 ++#define WLAN_HT_CAP_SM_PS_DYNAMIC 1 ++#define WLAN_HT_CAP_SM_PS_INVALID 2 ++#define WLAN_HT_CAP_SM_PS_DISABLED 3 ++ ++ ++#define OP_MODE_PURE 0 ++#define OP_MODE_MAY_BE_LEGACY_STAS 1 ++#define OP_MODE_20MHZ_HT_STA_ASSOCED 2 ++#define OP_MODE_MIXED 3 ++ ++#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1)) ++#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0)) ++#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1)) ++#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH ((u8) BIT(2)) ++#define HT_INFO_HT_PARAM_RIFS_MODE ((u8) BIT(3)) ++#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4)) ++#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5)) ++ ++#define HT_INFO_OPERATION_MODE_OP_MODE_MASK \ ++ ((u16) (0x0001 | 0x0002)) ++#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0 ++#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2)) ++#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3)) ++#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8) BIT(4)) ++ ++#define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16) BIT(6)) ++#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16) BIT(7)) ++#define HT_INFO_STBC_PARAM_SECONDARY_BCN ((u16) BIT(8)) ++#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16) BIT(9)) ++#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10)) ++#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11)) ++ ++ ++ ++//#endif ++ ++// ===============WPS Section=============== ++// For WPSv1.0 ++#define WPSOUI 0x0050f204 ++// WPS attribute ID ++#define WPS_ATTR_VER1 0x104A ++#define WPS_ATTR_SIMPLE_CONF_STATE 0x1044 ++#define WPS_ATTR_RESP_TYPE 0x103B ++#define WPS_ATTR_UUID_E 0x1047 ++#define WPS_ATTR_MANUFACTURER 0x1021 ++#define WPS_ATTR_MODEL_NAME 0x1023 ++#define WPS_ATTR_MODEL_NUMBER 0x1024 ++#define WPS_ATTR_SERIAL_NUMBER 0x1042 ++#define WPS_ATTR_PRIMARY_DEV_TYPE 0x1054 ++#define WPS_ATTR_SEC_DEV_TYPE_LIST 0x1055 ++#define WPS_ATTR_DEVICE_NAME 0x1011 ++#define WPS_ATTR_CONF_METHOD 0x1008 ++#define WPS_ATTR_RF_BANDS 0x103C ++#define WPS_ATTR_DEVICE_PWID 0x1012 ++#define WPS_ATTR_REQUEST_TYPE 0x103A ++#define WPS_ATTR_ASSOCIATION_STATE 0x1002 ++#define WPS_ATTR_CONFIG_ERROR 0x1009 ++#define WPS_ATTR_VENDOR_EXT 0x1049 ++#define WPS_ATTR_SELECTED_REGISTRAR 0x1041 ++ ++// Value of WPS attribute "WPS_ATTR_DEVICE_NAME ++#define WPS_MAX_DEVICE_NAME_LEN 32 ++ ++// Value of WPS Request Type Attribute ++#define WPS_REQ_TYPE_ENROLLEE_INFO_ONLY 0x00 ++#define WPS_REQ_TYPE_ENROLLEE_OPEN_8021X 0x01 ++#define WPS_REQ_TYPE_REGISTRAR 0x02 ++#define WPS_REQ_TYPE_WLAN_MANAGER_REGISTRAR 0x03 ++ ++// Value of WPS Response Type Attribute ++#define WPS_RESPONSE_TYPE_INFO_ONLY 0x00 ++#define WPS_RESPONSE_TYPE_8021X 0x01 ++#define WPS_RESPONSE_TYPE_REGISTRAR 0x02 ++#define WPS_RESPONSE_TYPE_AP 0x03 ++ ++// Value of WPS WiFi Simple Configuration State Attribute ++#define WPS_WSC_STATE_NOT_CONFIG 0x01 ++#define WPS_WSC_STATE_CONFIG 0x02 ++ ++// Value of WPS Version Attribute ++#define WPS_VERSION_1 0x10 ++ ++// Value of WPS Configuration Method Attribute ++#define WPS_CONFIG_METHOD_FLASH 0x0001 ++#define WPS_CONFIG_METHOD_ETHERNET 0x0002 ++#define WPS_CONFIG_METHOD_LABEL 0x0004 ++#define WPS_CONFIG_METHOD_DISPLAY 0x0008 ++#define WPS_CONFIG_METHOD_E_NFC 0x0010 ++#define WPS_CONFIG_METHOD_I_NFC 0x0020 ++#define WPS_CONFIG_METHOD_NFC 0x0040 ++#define WPS_CONFIG_METHOD_PBC 0x0080 ++#define WPS_CONFIG_METHOD_KEYPAD 0x0100 ++#define WPS_CONFIG_METHOD_VPBC 0x0280 ++#define WPS_CONFIG_METHOD_PPBC 0x0480 ++#define WPS_CONFIG_METHOD_VDISPLAY 0x2008 ++#define WPS_CONFIG_METHOD_PDISPLAY 0x4008 ++ ++// Value of Category ID of WPS Primary Device Type Attribute ++#define WPS_PDT_CID_DISPLAYS 0x0007 ++#define WPS_PDT_CID_MULIT_MEDIA 0x0008 ++#define WPS_PDT_CID_RTK_WIDI WPS_PDT_CID_MULIT_MEDIA ++ ++// Value of Sub Category ID of WPS Primary Device Type Attribute ++#define WPS_PDT_SCID_MEDIA_SERVER 0x0005 ++#define WPS_PDT_SCID_RTK_DMP WPS_PDT_SCID_MEDIA_SERVER ++ ++// Value of Device Password ID ++#define WPS_DPID_PIN 0x0000 ++#define WPS_DPID_USER_SPEC 0x0001 ++#define WPS_DPID_MACHINE_SPEC 0x0002 ++#define WPS_DPID_REKEY 0x0003 ++#define WPS_DPID_PBC 0x0004 ++#define WPS_DPID_REGISTRAR_SPEC 0x0005 ++ ++// Value of WPS RF Bands Attribute ++#define WPS_RF_BANDS_2_4_GHZ 0x01 ++#define WPS_RF_BANDS_5_GHZ 0x02 ++ ++// Value of WPS Association State Attribute ++#define WPS_ASSOC_STATE_NOT_ASSOCIATED 0x00 ++#define WPS_ASSOC_STATE_CONNECTION_SUCCESS 0x01 ++#define WPS_ASSOC_STATE_CONFIGURATION_FAILURE 0x02 ++#define WPS_ASSOC_STATE_ASSOCIATION_FAILURE 0x03 ++#define WPS_ASSOC_STATE_IP_FAILURE 0x04 ++ ++// =====================P2P Section===================== ++// For P2P ++#define P2POUI 0x506F9A09 ++ ++// P2P Attribute ID ++#define P2P_ATTR_STATUS 0x00 ++#define P2P_ATTR_MINOR_REASON_CODE 0x01 ++#define P2P_ATTR_CAPABILITY 0x02 ++#define P2P_ATTR_DEVICE_ID 0x03 ++#define P2P_ATTR_GO_INTENT 0x04 ++#define P2P_ATTR_CONF_TIMEOUT 0x05 ++#define P2P_ATTR_LISTEN_CH 0x06 ++#define P2P_ATTR_GROUP_BSSID 0x07 ++#define P2P_ATTR_EX_LISTEN_TIMING 0x08 ++#define P2P_ATTR_INTENTED_IF_ADDR 0x09 ++#define P2P_ATTR_MANAGEABILITY 0x0A ++#define P2P_ATTR_CH_LIST 0x0B ++#define P2P_ATTR_NOA 0x0C ++#define P2P_ATTR_DEVICE_INFO 0x0D ++#define P2P_ATTR_GROUP_INFO 0x0E ++#define P2P_ATTR_GROUP_ID 0x0F ++#define P2P_ATTR_INTERFACE 0x10 ++#define P2P_ATTR_OPERATING_CH 0x11 ++#define P2P_ATTR_INVITATION_FLAGS 0x12 ++ ++// Value of Status Attribute ++#define P2P_STATUS_SUCCESS 0x00 ++#define P2P_STATUS_FAIL_INFO_UNAVAILABLE 0x01 ++#define P2P_STATUS_FAIL_INCOMPATIBLE_PARAM 0x02 ++#define P2P_STATUS_FAIL_LIMIT_REACHED 0x03 ++#define P2P_STATUS_FAIL_INVALID_PARAM 0x04 ++#define P2P_STATUS_FAIL_REQUEST_UNABLE 0x05 ++#define P2P_STATUS_FAIL_PREVOUS_PROTO_ERR 0x06 ++#define P2P_STATUS_FAIL_NO_COMMON_CH 0x07 ++#define P2P_STATUS_FAIL_UNKNOWN_P2PGROUP 0x08 ++#define P2P_STATUS_FAIL_BOTH_GOINTENT_15 0x09 ++#define P2P_STATUS_FAIL_INCOMPATIBLE_PROVSION 0x0A ++#define P2P_STATUS_FAIL_USER_REJECT 0x0B ++ ++// Value of Inviation Flags Attribute ++#define P2P_INVITATION_FLAGS_PERSISTENT BIT(0) ++ ++#define DMP_P2P_DEVCAP_SUPPORT (P2P_DEVCAP_SERVICE_DISCOVERY | \ ++ P2P_DEVCAP_CLIENT_DISCOVERABILITY | \ ++ P2P_DEVCAP_CONCURRENT_OPERATION | \ ++ P2P_DEVCAP_INVITATION_PROC) ++ ++#define DMP_P2P_GRPCAP_SUPPORT (P2P_GRPCAP_INTRABSS) ++ ++// Value of Device Capability Bitmap ++#define P2P_DEVCAP_SERVICE_DISCOVERY BIT(0) ++#define P2P_DEVCAP_CLIENT_DISCOVERABILITY BIT(1) ++#define P2P_DEVCAP_CONCURRENT_OPERATION BIT(2) ++#define P2P_DEVCAP_INFRA_MANAGED BIT(3) ++#define P2P_DEVCAP_DEVICE_LIMIT BIT(4) ++#define P2P_DEVCAP_INVITATION_PROC BIT(5) ++ ++// Value of Group Capability Bitmap ++#define P2P_GRPCAP_GO BIT(0) ++#define P2P_GRPCAP_PERSISTENT_GROUP BIT(1) ++#define P2P_GRPCAP_GROUP_LIMIT BIT(2) ++#define P2P_GRPCAP_INTRABSS BIT(3) ++#define P2P_GRPCAP_CROSS_CONN BIT(4) ++#define P2P_GRPCAP_PERSISTENT_RECONN BIT(5) ++#define P2P_GRPCAP_GROUP_FORMATION BIT(6) ++ ++// P2P Public Action Frame ( Management Frame ) ++#define P2P_PUB_ACTION_ACTION 0x09 ++ ++// P2P Public Action Frame Type ++#define P2P_GO_NEGO_REQ 0 ++#define P2P_GO_NEGO_RESP 1 ++#define P2P_GO_NEGO_CONF 2 ++#define P2P_INVIT_REQ 3 ++#define P2P_INVIT_RESP 4 ++#define P2P_DEVDISC_REQ 5 ++#define P2P_DEVDISC_RESP 6 ++#define P2P_PROVISION_DISC_REQ 7 ++#define P2P_PROVISION_DISC_RESP 8 ++ ++// P2P Action Frame Type ++#define P2P_NOTICE_OF_ABSENCE 0 ++#define P2P_PRESENCE_REQUEST 1 ++#define P2P_PRESENCE_RESPONSE 2 ++#define P2P_GO_DISC_REQUEST 3 ++ ++ ++#define P2P_MAX_PERSISTENT_GROUP_NUM 10 ++ ++#define P2P_PROVISIONING_SCAN_CNT 3 ++ ++#define P2P_WILDCARD_SSID_LEN 7 ++ ++#define P2P_FINDPHASE_EX_NONE 0 // default value, used when: (1)p2p disabed or (2)p2p enabled but only do 1 scan phase ++#define P2P_FINDPHASE_EX_FULL 1 // used when p2p enabled and want to do 1 scan phase and P2P_FINDPHASE_EX_MAX-1 find phase ++#define P2P_FINDPHASE_EX_SOCIAL_FIRST (P2P_FINDPHASE_EX_FULL+1) ++#define P2P_FINDPHASE_EX_MAX 4 ++#define P2P_FINDPHASE_EX_SOCIAL_LAST P2P_FINDPHASE_EX_MAX ++ ++#define P2P_PROVISION_TIMEOUT 5000 // 5 seconds timeout for sending the provision discovery request ++#define P2P_CONCURRENT_PROVISION_TIMEOUT 3000 // 3 seconds timeout for sending the provision discovery request under concurrent mode ++#define P2P_GO_NEGO_TIMEOUT 5000 // 5 seconds timeout for receiving the group negotation response ++#define P2P_CONCURRENT_GO_NEGO_TIMEOUT 3000 // 3 seconds timeout for sending the negotiation request under concurrent mode ++#define P2P_TX_PRESCAN_TIMEOUT 100 // 100ms ++#define P2P_INVITE_TIMEOUT 5000 // 5 seconds timeout for sending the invitation request ++#define P2P_CONCURRENT_INVITE_TIMEOUT 3000 // 3 seconds timeout for sending the invitation request under concurrent mode ++#define P2P_RESET_SCAN_CH 25000 // 25 seconds timeout to reset the scan channel ( based on channel plan ) ++#define P2P_MAX_INTENT 15 ++ ++#define P2P_MAX_NOA_NUM 2 ++ ++// WPS Configuration Method ++#define WPS_CM_NONE 0x0000 ++#define WPS_CM_LABEL 0x0004 ++#define WPS_CM_DISPLYA 0x0008 ++#define WPS_CM_EXTERNAL_NFC_TOKEN 0x0010 ++#define WPS_CM_INTEGRATED_NFC_TOKEN 0x0020 ++#define WPS_CM_NFC_INTERFACE 0x0040 ++#define WPS_CM_PUSH_BUTTON 0x0080 ++#define WPS_CM_KEYPAD 0x0100 ++#define WPS_CM_SW_PUHS_BUTTON 0x0280 ++#define WPS_CM_HW_PUHS_BUTTON 0x0480 ++#define WPS_CM_SW_DISPLAY_PIN 0x2008 ++#define WPS_CM_LCD_DISPLAY_PIN 0x4008 ++ ++enum P2P_ROLE { ++ P2P_ROLE_DISABLE = 0, ++ P2P_ROLE_DEVICE = 1, ++ P2P_ROLE_CLIENT = 2, ++ P2P_ROLE_GO = 3 ++}; ++ ++enum P2P_STATE { ++ P2P_STATE_NONE = 0, // P2P disable ++ P2P_STATE_IDLE = 1, // P2P had enabled and do nothing ++ P2P_STATE_LISTEN = 2, // In pure listen state ++ P2P_STATE_SCAN = 3, // In scan phase ++ P2P_STATE_FIND_PHASE_LISTEN = 4, // In the listen state of find phase ++ P2P_STATE_FIND_PHASE_SEARCH = 5, // In the search state of find phase ++ P2P_STATE_TX_PROVISION_DIS_REQ = 6, // In P2P provisioning discovery ++ P2P_STATE_RX_PROVISION_DIS_RSP = 7, ++ P2P_STATE_RX_PROVISION_DIS_REQ = 8, ++ P2P_STATE_GONEGO_ING = 9, // Doing the group owner negoitation handshake ++ P2P_STATE_GONEGO_OK = 10, // finish the group negoitation handshake with success ++ P2P_STATE_GONEGO_FAIL = 11, // finish the group negoitation handshake with failure ++ P2P_STATE_RECV_INVITE_REQ_MATCH = 12, // receiving the P2P Inviation request and match with the profile. ++ P2P_STATE_PROVISIONING_ING = 13, // Doing the P2P WPS ++ P2P_STATE_PROVISIONING_DONE = 14, // Finish the P2P WPS ++ P2P_STATE_TX_INVITE_REQ = 15, // Transmit the P2P Invitation request ++ P2P_STATE_RX_INVITE_RESP_OK = 16, // Receiving the P2P Invitation response ++ P2P_STATE_RECV_INVITE_REQ_DISMATCH = 17, // receiving the P2P Inviation request and dismatch with the profile. ++ P2P_STATE_RECV_INVITE_REQ_GO = 18, // receiving the P2P Inviation request and this wifi is GO. ++ P2P_STATE_RECV_INVITE_REQ_JOIN = 19, // receiving the P2P Inviation request to join an existing P2P Group. ++ P2P_STATE_RX_INVITE_RESP_FAIL = 20, // recveing the P2P Inviation response with failure ++ P2P_STATE_RX_INFOR_NOREADY = 21, // receiving p2p negoitation response with information is not available ++ P2P_STATE_TX_INFOR_NOREADY = 22, // sending p2p negoitation response with information is not available ++}; ++ ++enum P2P_WPSINFO { ++ P2P_NO_WPSINFO = 0, ++ P2P_GOT_WPSINFO_PEER_DISPLAY_PIN = 1, ++ P2P_GOT_WPSINFO_SELF_DISPLAY_PIN = 2, ++ P2P_GOT_WPSINFO_PBC = 3, ++}; ++ ++#define P2P_PRIVATE_IOCTL_SET_LEN 64 ++ ++enum P2P_PROTO_WK_ID ++{ ++ P2P_FIND_PHASE_WK = 0, ++ P2P_RESTORE_STATE_WK = 1, ++ P2P_PRE_TX_PROVDISC_PROCESS_WK = 2, ++ P2P_PRE_TX_NEGOREQ_PROCESS_WK = 3, ++ P2P_PRE_TX_INVITEREQ_PROCESS_WK = 4, ++ P2P_AP_P2P_CH_SWITCH_PROCESS_WK =5, ++ P2P_RO_CH_WK = 6, ++}; ++ ++#ifdef CONFIG_P2P_PS ++enum P2P_PS_STATE ++{ ++ P2P_PS_DISABLE = 0, ++ P2P_PS_ENABLE = 1, ++ P2P_PS_SCAN = 2, ++ P2P_PS_SCAN_DONE = 3, ++ P2P_PS_ALLSTASLEEP = 4, // for P2P GO ++}; ++ ++enum P2P_PS_MODE ++{ ++ P2P_PS_NONE = 0, ++ P2P_PS_CTWINDOW = 1, ++ P2P_PS_NOA = 2, ++ P2P_PS_MIX = 3, // CTWindow and NoA ++}; ++#endif // CONFIG_P2P_PS ++ ++// =====================WFD Section===================== ++// For Wi-Fi Display ++#define WFD_ATTR_DEVICE_INFO 0x00 ++#define WFD_ATTR_ASSOC_BSSID 0x01 ++#define WFD_ATTR_COUPLED_SINK_INFO 0x06 ++#define WFD_ATTR_LOCAL_IP_ADDR 0x08 ++#define WFD_ATTR_SESSION_INFO 0x09 ++#define WFD_ATTR_ALTER_MAC 0x0a ++ ++// For WFD Device Information Attribute ++#define WFD_DEVINFO_SOURCE 0x0000 ++#define WFD_DEVINFO_PSINK 0x0001 ++#define WFD_DEVINFO_SSINK 0x0002 ++#define WFD_DEVINFO_DUAL 0x0003 ++ ++#define WFD_DEVINFO_SESSION_AVAIL 0x0010 ++#define WFD_DEVINFO_WSD 0x0040 ++#define WFD_DEVINFO_PC_TDLS 0x0080 ++#define WFD_DEVINFO_HDCP_SUPPORT 0x0100 ++ ++#ifdef CONFIG_TX_MCAST2UNI ++#define IP_MCAST_MAC(mac) ((mac[0]==0x01)&&(mac[1]==0x00)&&(mac[2]==0x5e)) ++#define ICMPV6_MCAST_MAC(mac) ((mac[0]==0x33)&&(mac[1]==0x33)&&(mac[2]!=0xff)) ++#endif // CONFIG_TX_MCAST2UNI ++ ++ ++ ++#ifdef CONFIG_WAPI_SUPPORT ++#ifndef IW_AUTH_WAPI_VERSION_1 ++#define IW_AUTH_WAPI_VERSION_1 0x00000008 ++#endif ++#ifndef IW_AUTH_KEY_MGMT_WAPI_PSK ++#define IW_AUTH_KEY_MGMT_WAPI_PSK 0x04 ++#endif ++#ifndef IW_AUTH_WAPI_ENABLED ++#define IW_AUTH_WAPI_ENABLED 0x20 ++#endif ++#ifndef IW_ENCODE_ALG_SM4 ++#define IW_ENCODE_ALG_SM4 0x20 ++#endif ++#endif ++ ++#endif // _WIFI_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/wlan_bssdef.h b/drivers/net/wireless/rtl818x/rtl8189/include/wlan_bssdef.h +new file mode 100644 +index 00000000..dac17a05 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/wlan_bssdef.h +@@ -0,0 +1,741 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __WLAN_BSSDEF_H__ ++#define __WLAN_BSSDEF_H__ ++ ++ ++#define MAX_IE_SZ 768 ++ ++ ++#ifdef PLATFORM_LINUX ++ ++#define NDIS_802_11_LENGTH_SSID 32 ++#define NDIS_802_11_LENGTH_RATES 8 ++#define NDIS_802_11_LENGTH_RATES_EX 16 ++ ++typedef unsigned char NDIS_802_11_MAC_ADDRESS[6]; ++typedef long NDIS_802_11_RSSI; // in dBm ++typedef unsigned char NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; // Set of 8 data rates ++typedef unsigned char NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; // Set of 16 data rates ++ ++ ++typedef ULONG NDIS_802_11_KEY_INDEX; ++typedef unsigned long long NDIS_802_11_KEY_RSC; ++ ++ ++typedef struct _NDIS_802_11_SSID ++{ ++ ULONG SsidLength; ++ UCHAR Ssid[32]; ++} NDIS_802_11_SSID, *PNDIS_802_11_SSID; ++ ++typedef enum _NDIS_802_11_NETWORK_TYPE ++{ ++ Ndis802_11FH, ++ Ndis802_11DS, ++ Ndis802_11OFDM5, ++ Ndis802_11OFDM24, ++ Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound ++} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE; ++ ++typedef struct _NDIS_802_11_CONFIGURATION_FH ++{ ++ ULONG Length; // Length of structure ++ ULONG HopPattern; // As defined by 802.11, MSB set ++ ULONG HopSet; // to one if non-802.11 ++ ULONG DwellTime; // units are Kusec ++} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH; ++ ++ ++/* ++ FW will only save the channel number in DSConfig. ++ ODI Handler will convert the channel number to freq. number. ++*/ ++typedef struct _NDIS_802_11_CONFIGURATION ++{ ++ ULONG Length; // Length of structure ++ ULONG BeaconPeriod; // units are Kusec ++ ULONG ATIMWindow; // units are Kusec ++ ULONG DSConfig; // Frequency, units are kHz ++ NDIS_802_11_CONFIGURATION_FH FHConfig; ++} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION; ++ ++ ++ ++typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE ++{ ++ Ndis802_11IBSS, ++ Ndis802_11Infrastructure, ++ Ndis802_11AutoUnknown, ++ Ndis802_11InfrastructureMax, // Not a real value, defined as upper bound ++ Ndis802_11APMode ++} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE; ++ ++ ++ ++ ++ ++typedef struct _NDIS_802_11_FIXED_IEs ++{ ++ UCHAR Timestamp[8]; ++ USHORT BeaconInterval; ++ USHORT Capabilities; ++} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs; ++ ++ ++ ++typedef struct _NDIS_802_11_VARIABLE_IEs ++{ ++ UCHAR ElementID; ++ UCHAR Length; ++ UCHAR data[1]; ++} NDIS_802_11_VARIABLE_IEs, *PNDIS_802_11_VARIABLE_IEs; ++ ++ ++ ++/* ++ ++ ++ ++Length is the 4 bytes multiples of the sume of ++ sizeof (NDIS_802_11_MAC_ADDRESS) + 2 + sizeof (NDIS_802_11_SSID) + sizeof (ULONG) +++ sizeof (NDIS_802_11_RSSI) + sizeof (NDIS_802_11_NETWORK_TYPE) + sizeof (NDIS_802_11_CONFIGURATION) +++ sizeof (NDIS_802_11_RATES_EX) + IELength ++ ++Except the IELength, all other fields are fixed length. Therefore, we can define a marco to present the ++partial sum. ++ ++*/ ++#if 0 ++typedef struct _NDIS_WLAN_BSSID_EX ++{ ++ ULONG Length; ++ NDIS_802_11_MAC_ADDRESS MacAddress; ++ UCHAR Reserved[2];//[0]: IS beacon frame, [1]:optimum_antenna=>For antenna diversity; ++ NDIS_802_11_SSID Ssid; ++ ULONG Privacy; ++ NDIS_802_11_RSSI Rssi; ++ NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; ++ NDIS_802_11_CONFIGURATION Configuration; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; ++ NDIS_802_11_RATES_EX SupportedRates; ++ ULONG IELength; ++ UCHAR IEs[MAX_IE_SZ]; //(timestamp, beacon interval, and capability information) ++} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX; ++ ++ ++typedef struct _NDIS_802_11_BSSID_LIST_EX ++{ ++ ULONG NumberOfItems; ++ NDIS_WLAN_BSSID_EX Bssid[1]; ++} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX; ++#endif ++ ++typedef enum _NDIS_802_11_AUTHENTICATION_MODE ++{ ++ Ndis802_11AuthModeOpen, ++ Ndis802_11AuthModeShared, ++ Ndis802_11AuthModeAutoSwitch, ++ Ndis802_11AuthModeWPA, ++ Ndis802_11AuthModeWPAPSK, ++ Ndis802_11AuthModeWPANone, ++ Ndis802_11AuthModeWAPI, ++ Ndis802_11AuthModeMax // Not a real mode, defined as upper bound ++} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE; ++ ++typedef enum _NDIS_802_11_WEP_STATUS ++{ ++ Ndis802_11WEPEnabled, ++ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, ++ Ndis802_11WEPDisabled, ++ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, ++ Ndis802_11WEPKeyAbsent, ++ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, ++ Ndis802_11WEPNotSupported, ++ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, ++ Ndis802_11Encryption2Enabled, ++ Ndis802_11Encryption2KeyAbsent, ++ Ndis802_11Encryption3Enabled, ++ Ndis802_11Encryption3KeyAbsent, ++ Ndis802_11_EncrypteionWAPI ++} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS, ++ NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS; ++ ++ ++#define NDIS_802_11_AI_REQFI_CAPABILITIES 1 ++#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2 ++#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4 ++ ++#define NDIS_802_11_AI_RESFI_CAPABILITIES 1 ++#define NDIS_802_11_AI_RESFI_STATUSCODE 2 ++#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4 ++ ++typedef struct _NDIS_802_11_AI_REQFI ++{ ++ USHORT Capabilities; ++ USHORT ListenInterval; ++ NDIS_802_11_MAC_ADDRESS CurrentAPAddress; ++} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI; ++ ++typedef struct _NDIS_802_11_AI_RESFI ++{ ++ USHORT Capabilities; ++ USHORT StatusCode; ++ USHORT AssociationId; ++} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI; ++ ++typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION ++{ ++ ULONG Length; ++ USHORT AvailableRequestFixedIEs; ++ NDIS_802_11_AI_REQFI RequestFixedIEs; ++ ULONG RequestIELength; ++ ULONG OffsetRequestIEs; ++ USHORT AvailableResponseFixedIEs; ++ NDIS_802_11_AI_RESFI ResponseFixedIEs; ++ ULONG ResponseIELength; ++ ULONG OffsetResponseIEs; ++} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION; ++ ++typedef enum _NDIS_802_11_RELOAD_DEFAULTS ++{ ++ Ndis802_11ReloadWEPKeys ++} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS; ++ ++ ++// Key mapping keys require a BSSID ++typedef struct _NDIS_802_11_KEY ++{ ++ ULONG Length; // Length of this structure ++ ULONG KeyIndex; ++ ULONG KeyLength; // length of key in bytes ++ NDIS_802_11_MAC_ADDRESS BSSID; ++ NDIS_802_11_KEY_RSC KeyRSC; ++ UCHAR KeyMaterial[32]; // variable length depending on above field ++} NDIS_802_11_KEY, *PNDIS_802_11_KEY; ++ ++typedef struct _NDIS_802_11_REMOVE_KEY ++{ ++ ULONG Length; // Length of this structure ++ ULONG KeyIndex; ++ NDIS_802_11_MAC_ADDRESS BSSID; ++} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY; ++ ++typedef struct _NDIS_802_11_WEP ++{ ++ ULONG Length; // Length of this structure ++ ULONG KeyIndex; // 0 is the per-client key, 1-N are the global keys ++ ULONG KeyLength; // length of key in bytes ++ UCHAR KeyMaterial[16];// variable length depending on above field ++} NDIS_802_11_WEP, *PNDIS_802_11_WEP; ++ ++typedef struct _NDIS_802_11_AUTHENTICATION_REQUEST ++{ ++ ULONG Length; // Length of structure ++ NDIS_802_11_MAC_ADDRESS Bssid; ++ ULONG Flags; ++} NDIS_802_11_AUTHENTICATION_REQUEST, *PNDIS_802_11_AUTHENTICATION_REQUEST; ++ ++typedef enum _NDIS_802_11_STATUS_TYPE ++{ ++ Ndis802_11StatusType_Authentication, ++ Ndis802_11StatusType_MediaStreamMode, ++ Ndis802_11StatusType_PMKID_CandidateList, ++ Ndis802_11StatusTypeMax // not a real type, defined as an upper bound ++} NDIS_802_11_STATUS_TYPE, *PNDIS_802_11_STATUS_TYPE; ++ ++typedef struct _NDIS_802_11_STATUS_INDICATION ++{ ++ NDIS_802_11_STATUS_TYPE StatusType; ++} NDIS_802_11_STATUS_INDICATION, *PNDIS_802_11_STATUS_INDICATION; ++ ++// mask for authentication/integrity fields ++#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f ++#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 ++#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 ++#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 ++#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E ++ ++// MIC check time, 60 seconds. ++#define MIC_CHECK_TIME 60000000 ++ ++typedef struct _NDIS_802_11_AUTHENTICATION_EVENT ++{ ++ NDIS_802_11_STATUS_INDICATION Status; ++ NDIS_802_11_AUTHENTICATION_REQUEST Request[1]; ++} NDIS_802_11_AUTHENTICATION_EVENT, *PNDIS_802_11_AUTHENTICATION_EVENT; ++ ++typedef struct _NDIS_802_11_TEST ++{ ++ ULONG Length; ++ ULONG Type; ++ union ++ { ++ NDIS_802_11_AUTHENTICATION_EVENT AuthenticationEvent; ++ NDIS_802_11_RSSI RssiTrigger; ++ }tt; ++} NDIS_802_11_TEST, *PNDIS_802_11_TEST; ++ ++ ++#endif //end of #ifdef PLATFORM_LINUX ++ ++#ifdef PLATFORM_FREEBSD ++ ++#define NDIS_802_11_LENGTH_SSID 32 ++#define NDIS_802_11_LENGTH_RATES 8 ++#define NDIS_802_11_LENGTH_RATES_EX 16 ++ ++typedef unsigned char NDIS_802_11_MAC_ADDRESS[6]; ++typedef long NDIS_802_11_RSSI; // in dBm ++typedef unsigned char NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; // Set of 8 data rates ++typedef unsigned char NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; // Set of 16 data rates ++ ++ ++typedef ULONG NDIS_802_11_KEY_INDEX; ++typedef unsigned long long NDIS_802_11_KEY_RSC; ++ ++ ++typedef struct _NDIS_802_11_SSID ++{ ++ ULONG SsidLength; ++ UCHAR Ssid[32]; ++} NDIS_802_11_SSID, *PNDIS_802_11_SSID; ++ ++typedef enum _NDIS_802_11_NETWORK_TYPE ++{ ++ Ndis802_11FH, ++ Ndis802_11DS, ++ Ndis802_11OFDM5, ++ Ndis802_11OFDM24, ++ Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound ++} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE; ++ ++typedef struct _NDIS_802_11_CONFIGURATION_FH ++{ ++ ULONG Length; // Length of structure ++ ULONG HopPattern; // As defined by 802.11, MSB set ++ ULONG HopSet; // to one if non-802.11 ++ ULONG DwellTime; // units are Kusec ++} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH; ++ ++ ++/* ++ FW will only save the channel number in DSConfig. ++ ODI Handler will convert the channel number to freq. number. ++*/ ++typedef struct _NDIS_802_11_CONFIGURATION ++{ ++ ULONG Length; // Length of structure ++ ULONG BeaconPeriod; // units are Kusec ++ ULONG ATIMWindow; // units are Kusec ++ ULONG DSConfig; // Frequency, units are kHz ++ NDIS_802_11_CONFIGURATION_FH FHConfig; ++} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION; ++ ++ ++ ++typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE ++{ ++ Ndis802_11IBSS, ++ Ndis802_11Infrastructure, ++ Ndis802_11AutoUnknown, ++ Ndis802_11InfrastructureMax, // Not a real value, defined as upper bound ++ Ndis802_11APMode ++} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE; ++ ++ ++ ++ ++ ++typedef struct _NDIS_802_11_FIXED_IEs ++{ ++ UCHAR Timestamp[8]; ++ USHORT BeaconInterval; ++ USHORT Capabilities; ++} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs; ++ ++ ++ ++typedef struct _NDIS_802_11_VARIABLE_IEs ++{ ++ UCHAR ElementID; ++ UCHAR Length; ++ UCHAR data[1]; ++} NDIS_802_11_VARIABLE_IEs, *PNDIS_802_11_VARIABLE_IEs; ++ ++ ++ ++/* ++ ++ ++ ++Length is the 4 bytes multiples of the sume of ++ sizeof (NDIS_802_11_MAC_ADDRESS) + 2 + sizeof (NDIS_802_11_SSID) + sizeof (ULONG) +++ sizeof (NDIS_802_11_RSSI) + sizeof (NDIS_802_11_NETWORK_TYPE) + sizeof (NDIS_802_11_CONFIGURATION) +++ sizeof (NDIS_802_11_RATES_EX) + IELength ++ ++Except the IELength, all other fields are fixed length. Therefore, we can define a marco to present the ++partial sum. ++ ++*/ ++#if 0 ++typedef struct _NDIS_WLAN_BSSID_EX ++{ ++ ULONG Length; ++ NDIS_802_11_MAC_ADDRESS MacAddress; ++ UCHAR Reserved[2];//[0]: IS beacon frame, [1]:optimum_antenna=>For antenna diversity; ++ NDIS_802_11_SSID Ssid; ++ ULONG Privacy; ++ NDIS_802_11_RSSI Rssi; ++ NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; ++ NDIS_802_11_CONFIGURATION Configuration; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; ++ NDIS_802_11_RATES_EX SupportedRates; ++ ULONG IELength; ++ UCHAR IEs[MAX_IE_SZ]; //(timestamp, beacon interval, and capability information) ++} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX; ++ ++ ++typedef struct _NDIS_802_11_BSSID_LIST_EX ++{ ++ ULONG NumberOfItems; ++ NDIS_WLAN_BSSID_EX Bssid[1]; ++} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX; ++#endif ++ ++typedef enum _NDIS_802_11_AUTHENTICATION_MODE ++{ ++ Ndis802_11AuthModeOpen, ++ Ndis802_11AuthModeShared, ++ Ndis802_11AuthModeAutoSwitch, ++ Ndis802_11AuthModeWPA, ++ Ndis802_11AuthModeWPAPSK, ++ Ndis802_11AuthModeWPANone, ++ Ndis802_11AuthModeMax // Not a real mode, defined as upper bound ++} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE; ++ ++typedef enum _NDIS_802_11_WEP_STATUS ++{ ++ Ndis802_11WEPEnabled, ++ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, ++ Ndis802_11WEPDisabled, ++ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, ++ Ndis802_11WEPKeyAbsent, ++ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, ++ Ndis802_11WEPNotSupported, ++ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, ++ Ndis802_11Encryption2Enabled, ++ Ndis802_11Encryption2KeyAbsent, ++ Ndis802_11Encryption3Enabled, ++ Ndis802_11Encryption3KeyAbsent ++} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS, ++ NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS; ++ ++ ++#define NDIS_802_11_AI_REQFI_CAPABILITIES 1 ++#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2 ++#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4 ++ ++#define NDIS_802_11_AI_RESFI_CAPABILITIES 1 ++#define NDIS_802_11_AI_RESFI_STATUSCODE 2 ++#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4 ++ ++typedef struct _NDIS_802_11_AI_REQFI ++{ ++ USHORT Capabilities; ++ USHORT ListenInterval; ++ NDIS_802_11_MAC_ADDRESS CurrentAPAddress; ++} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI; ++ ++typedef struct _NDIS_802_11_AI_RESFI ++{ ++ USHORT Capabilities; ++ USHORT StatusCode; ++ USHORT AssociationId; ++} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI; ++ ++typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION ++{ ++ ULONG Length; ++ USHORT AvailableRequestFixedIEs; ++ NDIS_802_11_AI_REQFI RequestFixedIEs; ++ ULONG RequestIELength; ++ ULONG OffsetRequestIEs; ++ USHORT AvailableResponseFixedIEs; ++ NDIS_802_11_AI_RESFI ResponseFixedIEs; ++ ULONG ResponseIELength; ++ ULONG OffsetResponseIEs; ++} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION; ++ ++typedef enum _NDIS_802_11_RELOAD_DEFAULTS ++{ ++ Ndis802_11ReloadWEPKeys ++} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS; ++ ++ ++// Key mapping keys require a BSSID ++typedef struct _NDIS_802_11_KEY ++{ ++ ULONG Length; // Length of this structure ++ ULONG KeyIndex; ++ ULONG KeyLength; // length of key in bytes ++ NDIS_802_11_MAC_ADDRESS BSSID; ++ NDIS_802_11_KEY_RSC KeyRSC; ++ UCHAR KeyMaterial[32]; // variable length depending on above field ++} NDIS_802_11_KEY, *PNDIS_802_11_KEY; ++ ++typedef struct _NDIS_802_11_REMOVE_KEY ++{ ++ ULONG Length; // Length of this structure ++ ULONG KeyIndex; ++ NDIS_802_11_MAC_ADDRESS BSSID; ++} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY; ++ ++typedef struct _NDIS_802_11_WEP ++{ ++ ULONG Length; // Length of this structure ++ ULONG KeyIndex; // 0 is the per-client key, 1-N are the global keys ++ ULONG KeyLength; // length of key in bytes ++ UCHAR KeyMaterial[16];// variable length depending on above field ++} NDIS_802_11_WEP, *PNDIS_802_11_WEP; ++ ++typedef struct _NDIS_802_11_AUTHENTICATION_REQUEST ++{ ++ ULONG Length; // Length of structure ++ NDIS_802_11_MAC_ADDRESS Bssid; ++ ULONG Flags; ++} NDIS_802_11_AUTHENTICATION_REQUEST, *PNDIS_802_11_AUTHENTICATION_REQUEST; ++ ++typedef enum _NDIS_802_11_STATUS_TYPE ++{ ++ Ndis802_11StatusType_Authentication, ++ Ndis802_11StatusType_MediaStreamMode, ++ Ndis802_11StatusType_PMKID_CandidateList, ++ Ndis802_11StatusTypeMax // not a real type, defined as an upper bound ++} NDIS_802_11_STATUS_TYPE, *PNDIS_802_11_STATUS_TYPE; ++ ++typedef struct _NDIS_802_11_STATUS_INDICATION ++{ ++ NDIS_802_11_STATUS_TYPE StatusType; ++} NDIS_802_11_STATUS_INDICATION, *PNDIS_802_11_STATUS_INDICATION; ++ ++// mask for authentication/integrity fields ++#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f ++#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 ++#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 ++#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 ++#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E ++ ++// MIC check time, 60 seconds. ++#define MIC_CHECK_TIME 60000000 ++ ++typedef struct _NDIS_802_11_AUTHENTICATION_EVENT ++{ ++ NDIS_802_11_STATUS_INDICATION Status; ++ NDIS_802_11_AUTHENTICATION_REQUEST Request[1]; ++} NDIS_802_11_AUTHENTICATION_EVENT, *PNDIS_802_11_AUTHENTICATION_EVENT; ++ ++typedef struct _NDIS_802_11_TEST ++{ ++ ULONG Length; ++ ULONG Type; ++ union ++ { ++ NDIS_802_11_AUTHENTICATION_EVENT AuthenticationEvent; ++ NDIS_802_11_RSSI RssiTrigger; ++ }tt; ++} NDIS_802_11_TEST, *PNDIS_802_11_TEST; ++ ++ ++#endif //PLATFORM_FREEBSD ++#ifndef Ndis802_11APMode ++#define Ndis802_11APMode (Ndis802_11InfrastructureMax+1) ++#endif ++ ++typedef struct _WLAN_PHY_INFO ++{ ++ u8 SignalStrength;//(in percentage) ++ u8 SignalQuality;//(in percentage) ++ u8 Optimum_antenna; //for Antenna diversity ++ u8 Reserved_0; ++}WLAN_PHY_INFO,*PWLAN_PHY_INFO; ++ ++typedef struct _WLAN_BCN_INFO ++{ ++ /* these infor get from rtw_get_encrypt_info when ++ * * translate scan to UI */ ++ u8 encryp_protocol;//ENCRYP_PROTOCOL_E: OPEN/WEP/WPA/WPA2/WAPI ++ int group_cipher; //WPA/WPA2 group cipher ++ int pairwise_cipher;////WPA/WPA2/WEP pairwise cipher ++ int is_8021x; ++ ++ /* bwmode 20/40 and ch_offset UP/LOW */ ++ unsigned short ht_cap_info; ++ unsigned char ht_info_infos_0; ++}WLAN_BCN_INFO,*PWLAN_BCN_INFO; ++ ++/* temporally add #pragma pack for structure alignment issue of ++* WLAN_BSSID_EX and get_WLAN_BSSID_EX_sz() ++*/ ++#ifdef PLATFORM_WINDOWS ++#pragma pack(push) ++#pragma pack(1) ++#endif ++typedef struct _WLAN_BSSID_EX ++{ ++ ULONG Length; ++ NDIS_802_11_MAC_ADDRESS MacAddress; ++ UCHAR Reserved[2];//[0]: IS beacon frame ++ NDIS_802_11_SSID Ssid; ++ ULONG Privacy; ++ NDIS_802_11_RSSI Rssi;//(in dBM,raw data ,get from PHY) ++ NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; ++ NDIS_802_11_CONFIGURATION Configuration; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; ++ NDIS_802_11_RATES_EX SupportedRates; ++ WLAN_PHY_INFO PhyInfo; ++ ULONG IELength; ++ UCHAR IEs[MAX_IE_SZ]; //(timestamp, beacon interval, and capability information) ++} ++#ifndef PLATFORM_WINDOWS ++__attribute__((packed)) ++#endif ++WLAN_BSSID_EX, *PWLAN_BSSID_EX; ++#ifdef PLATFORM_WINDOWS ++#pragma pack(pop) ++#endif ++ ++__inline static uint get_WLAN_BSSID_EX_sz(WLAN_BSSID_EX *bss) ++{ ++#if 0 ++ uint t_len; ++ ++ t_len = sizeof (ULONG) ++ + sizeof (NDIS_802_11_MAC_ADDRESS) ++ + 2 ++ + sizeof (NDIS_802_11_SSID) ++ + sizeof (ULONG) ++ + sizeof (NDIS_802_11_RSSI) ++ + sizeof (NDIS_802_11_NETWORK_TYPE) ++ + sizeof (NDIS_802_11_CONFIGURATION) ++ + sizeof (NDIS_802_11_NETWORK_INFRASTRUCTURE) ++ + sizeof (NDIS_802_11_RATES_EX) ++ //all new member add here ++ + sizeof(WLAN_PHY_INFO) ++ //all new member add here ++ + sizeof (ULONG) ++ + bss->IELength; ++ return t_len; ++#else ++ return (sizeof(WLAN_BSSID_EX) -MAX_IE_SZ + bss->IELength); ++#endif ++} ++ ++struct wlan_network { ++ _list list; ++ int network_type; //refer to ieee80211.h for WIRELESS_11A/B/G ++ int fixed; // set to fixed when not to be removed as site-surveying ++ unsigned long last_scanned; //timestamp for the network ++ int aid; //will only be valid when a BSS is joinned. ++ int join_res; ++ WLAN_BSSID_EX network; //must be the last item ++ WLAN_BCN_INFO BcnInfo; ++#ifdef PLATFORM_WINDOWS ++ unsigned char iebuf[MAX_IE_SZ]; ++#endif ++ ++}; ++ ++enum VRTL_CARRIER_SENSE ++{ ++ DISABLE_VCS, ++ ENABLE_VCS, ++ AUTO_VCS ++}; ++ ++enum VCS_TYPE ++{ ++ NONE_VCS, ++ RTS_CTS, ++ CTS_TO_SELF ++}; ++ ++ ++ ++ ++#define PWR_CAM 0 ++#define PWR_MINPS 1 ++#define PWR_MAXPS 2 ++#define PWR_UAPSD 3 ++#define PWR_VOIP 4 ++ ++ ++enum UAPSD_MAX_SP ++{ ++ NO_LIMIT, ++ TWO_MSDU, ++ FOUR_MSDU, ++ SIX_MSDU ++}; ++ ++ ++//john ++#define NUM_PRE_AUTH_KEY 16 ++#define NUM_PMKID_CACHE NUM_PRE_AUTH_KEY ++ ++/* ++* WPA2 ++*/ ++ ++#ifndef PLATFORM_OS_CE ++typedef struct _PMKID_CANDIDATE { ++ NDIS_802_11_MAC_ADDRESS BSSID; ++ ULONG Flags; ++} PMKID_CANDIDATE, *PPMKID_CANDIDATE; ++ ++typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST ++{ ++ ULONG Version; // Version of the structure ++ ULONG NumCandidates; // No. of pmkid candidates ++ PMKID_CANDIDATE CandidateList[1]; ++} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST; ++ ++ ++typedef struct _NDIS_802_11_AUTHENTICATION_ENCRYPTION ++{ ++ NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported; ++ NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported; ++ ++} NDIS_802_11_AUTHENTICATION_ENCRYPTION, *PNDIS_802_11_AUTHENTICATION_ENCRYPTION; ++ ++typedef struct _NDIS_802_11_CAPABILITY ++{ ++ ULONG Length; ++ ULONG Version; ++ ULONG NoOfPMKIDs; ++ ULONG NoOfAuthEncryptPairsSupported; ++ NDIS_802_11_AUTHENTICATION_ENCRYPTION AuthenticationEncryptionSupported[1]; ++ ++} NDIS_802_11_CAPABILITY, *PNDIS_802_11_CAPABILITY; ++#endif ++ ++ ++#endif //#ifndef WLAN_BSSDEF_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/include/xmit_osdep.h b/drivers/net/wireless/rtl818x/rtl8189/include/xmit_osdep.h +new file mode 100644 +index 00000000..090a4475 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/include/xmit_osdep.h +@@ -0,0 +1,99 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#ifndef __XMIT_OSDEP_H_ ++#define __XMIT_OSDEP_H_ ++ ++#include ++#include ++#include ++ ++struct pkt_file { ++ _pkt *pkt; ++ SIZE_T pkt_len; //the remainder length of the open_file ++ _buffer *cur_buffer; ++ u8 *buf_start; ++ u8 *cur_addr; ++ SIZE_T buf_len; ++}; ++ ++#ifdef PLATFORM_WINDOWS ++ ++#ifdef PLATFORM_OS_XP ++#ifdef CONFIG_USB_HCI ++#include ++#include ++#include ++#endif ++#endif ++ ++#ifdef CONFIG_GSPI_HCI ++#define NR_XMITFRAME 64 ++#else ++#define NR_XMITFRAME 128 ++#endif ++ ++#define ETH_ALEN 6 ++ ++extern NDIS_STATUS rtw_xmit_entry( ++IN _nic_hdl cnxt, ++IN NDIS_PACKET *pkt, ++IN UINT flags ++); ++ ++#endif ++ ++#ifdef PLATFORM_FREEBSD ++#define NR_XMITFRAME 256 ++extern int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev); ++extern void rtw_xmit_entry_wrap (struct ifnet * pifp); ++#endif //PLATFORM_FREEBSD ++ ++#ifdef PLATFORM_LINUX ++ ++#define NR_XMITFRAME 256 ++ ++struct xmit_priv; ++struct pkt_attrib; ++struct sta_xmit_priv; ++struct xmit_frame; ++struct xmit_buf; ++ ++extern int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev); ++extern int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev); ++ ++#endif ++ ++void rtw_os_xmit_schedule(_adapter *padapter); ++ ++int rtw_os_xmit_resource_alloc(_adapter *padapter, struct xmit_buf *pxmitbuf,u32 alloc_sz); ++void rtw_os_xmit_resource_free(_adapter *padapter, struct xmit_buf *pxmitbuf,u32 free_sz); ++ ++extern void rtw_set_tx_chksum_offload(_pkt *pkt, struct pkt_attrib *pattrib); ++ ++extern uint rtw_remainder_len(struct pkt_file *pfile); ++extern void _rtw_open_pktfile(_pkt *pkt, struct pkt_file *pfile); ++extern uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen); ++extern sint rtw_endofpktfile (struct pkt_file *pfile); ++ ++extern void rtw_os_pkt_complete(_adapter *padapter, _pkt *pkt); ++extern void rtw_os_xmit_complete(_adapter *padapter, struct xmit_frame *pxframe); ++ ++#endif //__XMIT_OSDEP_H_ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/make_drv b/drivers/net/wireless/rtl818x/rtl8189/make_drv +new file mode 100644 +index 00000000..c61ef0b7 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/make_drv +@@ -0,0 +1,238 @@ ++#!/bin/bash ++#======================================== ++# Common functions ++#======================================== ++intf_usb() ++{ ++ sed -i '/CONFIG_USB_HCI = /c\CONFIG_USB_HCI = y' Makefile ++ sed -i '/CONFIG_PCI_HCI = /c\CONFIG_PCI_HCI = n' Makefile ++ sed -i '/CONFIG_SDIO_HCI = /c\CONFIG_SDIO_HCI = n' Makefile ++ sed -i '/CONFIG_GSPI_HCI = /c\CONFIG_GSPI_HCI = n' Makefile ++} ++intf_pcie() ++{ ++ sed -i '/CONFIG_USB_HCI = /c\CONFIG_USB_HCI = n' Makefile ++ sed -i '/CONFIG_PCI_HCI = /c\CONFIG_PCI_HCI = y' Makefile ++ sed -i '/CONFIG_SDIO_HCI = /c\CONFIG_SDIO_HCI = n' Makefile ++ sed -i '/CONFIG_GSPI_HCI = /c\CONFIG_GSPI_HCI = n' Makefile ++} ++intf_sdio() ++{ ++ sed -i '/CONFIG_USB_HCI = /c\CONFIG_USB_HCI = n' Makefile ++ sed -i '/CONFIG_PCI_HCI = /c\CONFIG_PCI_HCI = n' Makefile ++ sed -i '/CONFIG_SDIO_HCI = /c\CONFIG_SDIO_HCI = y' Makefile ++ sed -i '/CONFIG_GSPI_HCI = /c\CONFIG_GSPI_HCI = n' Makefile ++} ++ ++nic_8192c() ++{ ++ sed -i '/CONFIG_RTL8192C = /c\CONFIG_RTL8192C = y' Makefile ++ sed -i '/CONFIG_RTL8192D = /c\CONFIG_RTL8192D = n' Makefile ++ sed -i '/CONFIG_RTL8723A = /c\CONFIG_RTL8723A = n' Makefile ++ sed -i '/CONFIG_RTL8188E = /c\CONFIG_RTL8188E = n' Makefile ++} ++nic_8192d() ++{ ++ sed -i '/CONFIG_RTL8192C = /c\CONFIG_RTL8192C = n' Makefile ++ sed -i '/CONFIG_RTL8192D = /c\CONFIG_RTL8192D = y' Makefile ++ sed -i '/CONFIG_RTL8723A = /c\CONFIG_RTL8723A = n' Makefile ++ sed -i '/CONFIG_RTL8188E = /c\CONFIG_RTL8188E = n' Makefile ++} ++nic_8723a(){ ++ sed -i '/CONFIG_RTL8192C = /c\CONFIG_RTL8192C = n' Makefile ++ sed -i '/CONFIG_RTL8192D = /c\CONFIG_RTL8192D = n' Makefile ++ sed -i '/CONFIG_RTL8723A = /c\CONFIG_RTL8723A = y' Makefile ++ sed -i '/CONFIG_RTL8188E = /c\CONFIG_RTL8188E = n' Makefile ++} ++nic_8188e(){ ++ sed -i '/CONFIG_RTL8192C = /c\CONFIG_RTL8192C = n' Makefile ++ sed -i '/CONFIG_RTL8192D = /c\CONFIG_RTL8192D = n' Makefile ++ sed -i '/CONFIG_RTL8723A = /c\CONFIG_RTL8723A = n' Makefile ++ sed -i '/CONFIG_RTL8188E = /c\CONFIG_RTL8188E = y' Makefile ++} ++ch_obj_cu() ++{ ++ sed -i '/obj-$(CONFIG_RTL/c\obj-$(CONFIG_RTL8192CU) := $(MODULE_NAME).o' Makefile ++ sed -i '/export CONFIG_RTL/c\export CONFIG_RTL8192CU = m' Makefile ++ ++ cp -f Kconfig_rtl8192c_usb_linux Kconfig ++} ++ ++ch_obj_ce() ++{ ++ sed -i '/obj-$(CONFIG_RTL/c\obj-$(CONFIG_RTL8192CE) := $(MODULE_NAME).o' Makefile ++ sed -i '/export CONFIG_RTL/c\export CONFIG_RTL8192CE = m' Makefile ++ ++ cp -f Kconfig_rtl8192c_pci_linux Kconfig ++} ++ ++ch_obj_du() ++{ ++ sed -i '/obj-$(CONFIG_RTL/c\obj-$(CONFIG_RTL8192DU) := $(MODULE_NAME).o' Makefile ++ sed -i '/export CONFIG_RTL/c\export CONFIG_RTL8192DU = m' Makefile ++ ++ cp -f Kconfig_rtl8192d_usb_linux Kconfig ++} ++ ++ch_obj_de() ++{ ++ sed -i '/obj-$(CONFIG_RTL/c\obj-$(CONFIG_RTL8192DE) := $(MODULE_NAME).o' Makefile ++ sed -i '/export CONFIG_RTL/c\export CONFIG_RTL8192DE = m' Makefile ++ ++ cp -f Kconfig_rtl8192d_pci_linux Kconfig ++} ++ ++ch_obj_as() ++{ ++ sed -i '/obj-$(CONFIG_RTL/c\obj-$(CONFIG_RTL8723AS) := $(MODULE_NAME).o' Makefile ++ sed -i '/export CONFIG_RTL/c\export CONFIG_RTL8723AS = m' Makefile ++ ++# sed -i '/CONFIG_POWER_SAVING = /c\CONFIG_POWER_SAVING = y' Makefile ++ ++ cp -f Kconfig_rtl8723a_sdio_linux Kconfig ++} ++ ++ch_obj_au() ++{ ++ sed -i '/obj-$(CONFIG_RTL/ c obj-$(CONFIG_RTL8723AS-VAU) := $(MODULE_NAME).o' Makefile ++ sed -i '/export CONFIG_RTL/ c export CONFIG_RTL8723AS-VAU = m' Makefile ++ ++# sed -i '/CONFIG_POWER_SAVING = /c\CONFIG_POWER_SAVING = n' Makefile ++ ++ cp -f Kconfig_rtl8723a_usb_linux Kconfig ++} ++ ++ch_obj_es() ++{ ++ sed -i '/obj-$(CONFIG_RTL/c\obj-$(CONFIG_RTL8189ES) := $(MODULE_NAME).o' Makefile ++ sed -i '/export CONFIG_RTL/c\export CONFIG_RTL8189ES = m' Makefile ++ ++ cp -f Kconfig_rtl8189e_sdio_linux Kconfig ++} ++ ++ch_obj_eu() ++{ ++ sed -i '/obj-$(CONFIG_RTL/c\obj-$(CONFIG_RTL8188EU) := $(MODULE_NAME).o' Makefile ++ sed -i '/export CONFIG_RTL/c\export CONFIG_RTL8188EU = m' Makefile ++ ++ cp -f Kconfig_rtl8188e_usb_linux Kconfig ++} ++ ++ch_obj_ee() ++{ ++ sed -i '/obj-$(CONFIG_RTL/c\obj-$(CONFIG_RTL8188EE) := $(MODULE_NAME).o' Makefile ++ sed -i '/export CONFIG_RTL/c\export CONFIG_RTL8188EE = m' Makefile ++ ++ cp -f Kconfig_rtl8188e_pci_linux Kconfig ++} ++ ++get_svn_revision() ++{ ++ if [ -z "$svn_rev" ] && [ -f .svn/entries ]; then ++ svn_rev=`sed -n '11 s/^\([0-9][0-9]*\)$/\1/p' .svn/entries` ++ fi ++ if [ -z "$svn_rev" ]; then ++ svn_rev="xxxx" ++ fi ++} ++ ++#======================================== ++# Sub functions ++#======================================== ++ ++add_version_file() ++{ ++ defversion="#define DRIVERVERSION\t\"$postfix\"" ++ echo -e $defversion > include/rtw_version.h ++} ++ ++conf_driver() ++{ ++ sed -i '/CONFIG_AUTOCFG_CP = /c\CONFIG_AUTOCFG_CP = y' Makefile ++ if [ -f include/rtw_version.h ]; then ++ echo "rtw_version.h has existed!" ++ else ++ add_version_file ++ fi ++} ++ ++#======================================== ++# Main Script Start From Here ++#======================================== ++ ++if [ ! -f include/rtw_version.h ]; then ++ # Make Version string ++ if [ -z "$2" ]; then ++ get_svn_revision ++ version="v4.1.3_"$svn_rev ++ datestr=$(date +%Y%m%d) ++ postfix=$version.$datestr ++ else ++ postfix=$2 ++ fi ++fi ++ ++if [ $# -eq 1 ]; then ++ card=$1 ++ echo "You have selected $card" ++else ++ # Select NIC type ++ echo "Please select card type(1/2):" ++ select card in RTL8188eus RTL8189es; ++ do ++ echo "You have selected $card" ++ break ++ done ++fi ++ ++# Make ++case "$card" in ++ [Rr][Tt][Ll]8192[Cc][Uu]) ++ conf_driver; ++ nic_8192c; ++ intf_usb; ++ ch_obj_cu;; ++ [Rr][Tt][Ll]8192[Cc][Ee]) ++ conf_driver; ++ nic_8192c; ++ intf_pcie; ++ ch_obj_ce;; ++ [Rr][Tt][Ll]8192[Dd][Uu]) ++ conf_driver; ++ nic_8192d; ++ intf_usb; ++ ch_obj_du;; ++ [Rr][Tt][Ll]8192[Dd][Ee]) ++ conf_driver; ++ nic_8192d; ++ intf_pcie; ++ ch_obj_de;; ++ [Rr][Tt][Ll]8723[Aa][Ss]) ++ conf_driver; ++ nic_8723a; ++ intf_sdio; ++ ch_obj_as;; ++ [Rr][Tt][Ll]8723[Aa][Ss]-[Vv][Aa][Uu]) ++ conf_driver; ++ nic_8723a; ++ intf_usb; ++ ch_obj_au;; ++ [Rr][Tt][Ll]8189[Ee][Ss]) ++ conf_driver; ++ nic_8188e; ++ intf_sdio; ++ ch_obj_es;; ++ [Rr][Tt][Ll]8188[Ee][Uu][Ss]) ++ conf_driver; ++ nic_8188e; ++ intf_usb; ++ ch_obj_eu;; ++ [Rr][Tt][Ll]8188[Ee][Ee]) ++ conf_driver; ++ nic_8188e; ++ intf_pcie; ++ ch_obj_ee;; ++ *) ++ echo "Unknown NIC type" ++ ;; ++esac +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/custom_gpio_linux.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/custom_gpio_linux.c +new file mode 100644 +index 00000000..eaf2e14e +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/custom_gpio_linux.c +@@ -0,0 +1,210 @@ ++/****************************************************************************** ++ * Customer code to add GPIO control during WLAN start/stop ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#include "osdep_service.h" ++#include "drv_types.h" ++#include "custom_gpio.h" ++ ++#ifdef CONFIG_PLATFORM_SPRD ++ ++//gspi func & GPIO define ++#include //0915 ++#include ++ ++#if !(defined ANDROID_2X) ++ ++#ifdef CONFIG_RTL8188E ++#include ++#include ++#endif // CONFIG_RTL8188E ++ ++#ifndef GPIO_WIFI_POWER ++#define GPIO_WIFI_POWER -1 ++#endif // !GPIO_WIFI_POWER ++ ++#ifndef GPIO_WIFI_RESET ++#define GPIO_WIFI_RESET -1 ++#endif // !GPIO_WIFI_RESET ++ ++#ifndef GPIO_WIFI_PWDN ++#define GPIO_WIFI_PWDN -1 ++#endif // !GPIO_WIFI_RESET ++#ifdef CONFIG_GSPI_HCI ++extern unsigned int oob_irq; ++#endif // CONFIG_GSPI_HCI ++ ++#ifdef CONFIG_SDIO_HCI ++extern int rtw_mp_mode; ++#else // !CONFIG_SDIO_HCI ++#endif // !CONFIG_SDIO_HCI ++ ++int rtw_wifi_gpio_init(void) ++{ ++#ifdef CONFIG_GSPI_HCI ++ if (GPIO_WIFI_IRQ > 0) { ++ gpio_request(GPIO_WIFI_IRQ, "oob_irq"); ++ gpio_direction_input(GPIO_WIFI_IRQ); ++ ++ oob_irq = gpio_to_irq(GPIO_WIFI_IRQ); ++ ++ DBG_8192C("%s oob_irq:%d\n", __func__, oob_irq); ++ } ++#endif ++ ++ if (GPIO_WIFI_RESET > 0) ++ gpio_request(GPIO_WIFI_RESET , "wifi_rst"); ++ ++ return 0; ++} ++ ++int rtw_wifi_gpio_deinit(void) ++{ ++#ifdef CONFIG_GSPI_HCI ++ if (GPIO_WIFI_IRQ > 0) { ++ gpio_free(GPIO_WIFI_IRQ); ++#endif ++ if (GPIO_WIFI_RESET > 0) ++ gpio_free(GPIO_WIFI_RESET ); ++ ++ return 0; ++} ++ ++/* Customer function to control hw specific wlan gpios */ ++void rtw_wifi_gpio_wlan_ctrl(int onoff) ++{ ++ switch (onoff) { ++ case WLAN_PWDN_OFF: ++ DBG_8192C("%s: call customer specific GPIO(%d) to set wifi power down pin to 0\n", ++ __FUNCTION__, GPIO_WIFI_RESET); ++ ++ if (GPIO_WIFI_RESET > 0) ++ gpio_direction_output(GPIO_WIFI_RESET , 0); ++ break; ++ ++ case WLAN_PWDN_ON: ++ DBG_8192C("%s: callc customer specific GPIO(%d) to set wifi power down pin to 1\n", ++ __FUNCTION__, GPIO_WIFI_RESET); ++ ++ if (GPIO_WIFI_RESET > 0) ++ gpio_direction_output(GPIO_WIFI_RESET , 1); ++ break; ++ ++ case WLAN_POWER_OFF: ++ DBG_8192C("%s: call customer specific GPIO to turn off wifi power\n", ++ __FUNCTION__); ++ break; ++ case WLAN_POWER_ON: ++ DBG_8192C("%s: call customer specific GPIO to turn on wifi power\n", ++ __FUNCTION__); ++ break; ++ } ++} ++#else //ANDROID_2X ++//gspi func & GPIO define ++#include //0915 ++#include ++#ifdef CONFIG_RTL8188E ++extern int sprd_3rdparty_gpio_wifi_power; ++#endif ++extern int sprd_3rdparty_gpio_wifi_pwd; ++#ifdef CONFIG_RTL8723A ++extern int sprd_3rdparty_gpio_bt_reset; ++#endif ++ ++int rtw_wifi_gpio_init(void) ++{ ++#ifdef CONFIG_RTL8723A ++ if (sprd_3rdparty_gpio_bt_reset > 0) ++ gpio_direction_output(sprd_3rdparty_gpio_bt_reset, 1); ++#endif ++ ++ return 0; ++} ++ ++int rtw_wifi_gpio_deinit(void) ++{ ++ return 0; ++} ++ ++/* Customer function to control hw specific wlan gpios */ ++void rtw_wifi_gpio_wlan_ctrl(int onoff) ++{ ++ switch (onoff) { ++ case WLAN_PWDN_OFF: ++ DBG_8192C("%s: call customer specific GPIO to set wifi power down pin to 0\n", ++ __FUNCTION__); ++ if (sprd_3rdparty_gpio_wifi_pwd > 0) ++ gpio_set_value(sprd_3rdparty_gpio_wifi_pwd, 0); ++ break; ++ ++ case WLAN_PWDN_ON: ++ DBG_8192C("%s: callc customer specific GPIO to set wifi power down pin to 1\n", ++ __FUNCTION__); ++ if (sprd_3rdparty_gpio_wifi_pwd > 0) ++ gpio_set_value(sprd_3rdparty_gpio_wifi_pwd, 1); ++ break; ++ ++ case WLAN_POWER_OFF: ++ DBG_8192C("%s: call customer specific GPIO to turn off wifi power\n", ++ __FUNCTION__); ++#ifdef CONFIG_RTL8188E ++ if (sprd_3rdparty_gpio_wifi_power > 0) ++ gpio_set_value(sprd_3rdparty_gpio_wifi_power, 0); ++#endif ++ break; ++ case WLAN_POWER_ON: ++ DBG_8192C("%s: call customer specific GPIO to turn on wifi power\n", ++ __FUNCTION__); ++#ifdef CONFIG_RTL8188E ++ if (sprd_3rdparty_gpio_wifi_power > 0) ++ gpio_set_value(sprd_3rdparty_gpio_wifi_power, 1); ++#endif ++ ++ case WLAN_BT_PWDN_OFF: ++ DBG_8192C("%s: call customer specific GPIO to set bt power down pin to 0\n", ++ __FUNCTION__); ++#ifdef CONFIG_RTL8723A ++ if (sprd_3rdparty_gpio_bt_reset > 0) ++ gpio_set_value(sprd_3rdparty_gpio_bt_reset, 0); ++#endif ++ break; ++ ++ case WLAN_BT_PWDN_ON: ++ DBG_8192C("%s: callc customer specific GPIO to set bt power down pin to 1\n", ++ __FUNCTION__); ++#ifdef CONFIG_RTL8723A ++ if (sprd_3rdparty_gpio_bt_reset > 0) ++ gpio_set_value(sprd_3rdparty_gpio_bt_reset, 1); ++#endif ++ break; ++ break; ++ } ++} ++#endif //ANDROID_2X ++#else //CONFIG_PLATFORM_SPRD ++int rtw_wifi_gpio_init(void) ++{ ++ return 0; ++} ++ ++void rtw_wifi_gpio_wlan_ctrl(int onoff) ++{ ++} ++#endif //CONFIG_PLATFORM_SPRD +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/gspi_intf.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/gspi_intf.c +new file mode 100644 +index 00000000..aa08f2b1 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/gspi_intf.c +@@ -0,0 +1,945 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _HCI_INTF_C_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef CONFIG_GSPI_HCI ++#error "CONFIG_GSPI_HCI should be on!\n" ++#endif ++ ++#include ++#include ++#include ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_RTL8723A ++#include ++#include ++#include ++#endif ++ ++#ifdef CONFIG_RTL8188E ++#include ++#endif ++ ++#include ++#include ++#include ++ ++#include ++ ++ ++extern char* ifname; ++ ++typedef struct _driver_priv { ++ int drv_registered; ++} drv_priv, *pdrv_priv; ++ ++unsigned int oob_irq; ++static drv_priv drvpriv = { ++ ++}; ++ ++static void decide_chip_type_by_device_id(PADAPTER padapter) ++{ ++ padapter->chip_type = NULL_CHIP_TYPE; ++ ++#if defined(CONFIG_RTL8723A) ++ padapter->chip_type = RTL8723A; ++ padapter->HardwareType = HARDWARE_TYPE_RTL8723AS; ++#elif defined(CONFIG_RTL8188E) ++ padapter->chip_type = RTL8188E; ++ padapter->HardwareType = HARDWARE_TYPE_RTL8188ES; ++#endif ++} ++ ++static irqreturn_t spi_interrupt_thread(int irq, void *data) ++{ ++ struct dvobj_priv *dvobj; ++ PGSPI_DATA pgspi_data; ++ ++ ++ dvobj = (struct dvobj_priv*)data; ++ pgspi_data = &dvobj->intf_data; ++ ++ //spi_int_hdl(padapter); ++ if (pgspi_data->priv_wq) ++ queue_delayed_work(pgspi_data->priv_wq, &pgspi_data->irq_work, 0); ++ ++ return IRQ_HANDLED; ++} ++ ++static u8 gspi_alloc_irq(struct dvobj_priv *dvobj) ++{ ++ PGSPI_DATA pgspi_data; ++ struct spi_device *spi; ++ int err; ++ ++ ++ pgspi_data = &dvobj->intf_data; ++ spi = pgspi_data->func; ++ ++ err = request_irq(oob_irq, spi_interrupt_thread, ++ IRQF_TRIGGER_FALLING,//IRQF_TRIGGER_HIGH;//|IRQF_ONESHOT, ++ DRV_NAME, dvobj); ++ //err = request_threaded_irq(oob_irq, NULL, spi_interrupt_thread, ++ // IRQF_TRIGGER_FALLING, ++ // DRV_NAME, dvobj); ++ if (err < 0) { ++ DBG_871X("Oops: can't allocate irq %d err:%d\n", oob_irq, err); ++ goto exit; ++ } ++ enable_irq_wake(oob_irq); ++ disable_irq(oob_irq); ++ ++exit: ++ return err?_FAIL:_SUCCESS; ++} ++ ++static u8 gspi_init(struct dvobj_priv *dvobj) ++{ ++ PGSPI_DATA pgspi_data; ++ int err = 0; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+gspi_init\n")); ++ ++ if (NULL == dvobj) { ++ DBG_8192C(KERN_ERR "%s: driver object is NULL!\n", __func__); ++ err = -1; ++ goto exit; ++ } ++ ++ pgspi_data = &dvobj->intf_data; ++ ++ pgspi_data->block_transfer_len = 512; ++ pgspi_data->tx_block_mode = 0; ++ pgspi_data->rx_block_mode = 0; ++ ++exit: ++ _func_exit_; ++ ++ if (err) return _FAIL; ++ return _SUCCESS; ++} ++ ++static void gspi_deinit(struct dvobj_priv *dvobj) ++{ ++ PGSPI_DATA pgspi_data; ++ struct spi_device *spi; ++ int err; ++ ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+gspi_deinit\n")); ++ ++ if (NULL == dvobj) { ++ DBG_8192C(KERN_ERR "%s: driver object is NULL!\n", __FUNCTION__); ++ return; ++ } ++ ++ pgspi_data = &dvobj->intf_data; ++ spi = pgspi_data->func; ++ ++ if (spi) { ++ free_irq(oob_irq, dvobj); ++ } ++} ++ ++static struct dvobj_priv *gspi_dvobj_init(struct spi_device *spi) ++{ ++ int status = _FAIL; ++ struct dvobj_priv *dvobj = NULL; ++ PGSPI_DATA pgspi; ++ ++_func_enter_; ++ ++ dvobj = (struct dvobj_priv*)rtw_zmalloc(sizeof(*dvobj)); ++ if (NULL == dvobj) { ++ goto exit; ++ } ++ ++ _rtw_mutex_init(&dvobj->hw_init_mutex); ++ _rtw_mutex_init(&dvobj->h2c_fwcmd_mutex); ++ _rtw_mutex_init(&dvobj->setch_mutex); ++ _rtw_mutex_init(&dvobj->setbw_mutex); ++ dvobj->processing_dev_remove = _FALSE; ++ //spi init ++ /* This is the only SPI value that we need to set here, the rest ++ * comes from the board-peripherals file */ ++ spi->bits_per_word = 32; ++ spi->max_speed_hz = 48 * 1000 * 1000; ++ //here mode 0 and 3 all ok, ++ //3 can run under 48M clock when SPI_CTL4 bit14 IS_FST set to 1 ++ //0 can run under 24M clock, but can run under 48M when SPI_CTL4 bit14 IS_FST set to 1 and Ctl0_reg[1:0] set to 3. ++ spi->mode = SPI_MODE_3; ++ spi_setup(spi); ++ ++#if 1 ++ //DBG_8192C("set spi ==========================%d \n", spi_setup(spi)); ++ ++ DBG_871X("%s, mode = %d \n", __func__, spi->mode); ++ DBG_871X("%s, bit_per_word = %d \n", __func__, spi->bits_per_word); ++ DBG_871X("%s, speed = %d \n", __func__, spi->max_speed_hz); ++ DBG_871X("%s, chip_select = %d \n", __func__, spi->chip_select); ++ DBG_871X("%s, controller_data = %d \n", __func__, *(int *)spi->controller_data); ++ DBG_871X("%s, irq= %d \n", __func__, oob_irq); ++#endif ++ ++ spi_set_drvdata(spi, dvobj); ++ pgspi = &dvobj->intf_data; ++ pgspi->func = spi; ++ ++ if (gspi_init(dvobj) != _SUCCESS) { ++ DBG_871X("%s: initialize GSPI Failed!\n", __FUNCTION__); ++ goto free_dvobj; ++ } ++ rtw_reset_continual_io_error(dvobj); ++ status = _SUCCESS; ++ ++free_dvobj: ++ if (status != _SUCCESS && dvobj) { ++ spi_set_drvdata(spi, NULL); ++ _rtw_mutex_free(&dvobj->hw_init_mutex); ++ _rtw_mutex_free(&dvobj->h2c_fwcmd_mutex); ++ _rtw_mutex_free(&dvobj->setch_mutex); ++ _rtw_mutex_free(&dvobj->setbw_mutex); ++ rtw_mfree((u8*)dvobj, sizeof(*dvobj)); ++ dvobj = NULL; ++ } ++ ++exit: ++_func_exit_; ++ ++ return dvobj; ++} ++ ++static void gspi_dvobj_deinit(struct spi_device *spi) ++{ ++ struct dvobj_priv *dvobj = spi_get_drvdata(spi); ++ ++_func_enter_; ++ ++ spi_set_drvdata(spi, NULL); ++ if (dvobj) { ++ gspi_deinit(dvobj); ++ _rtw_mutex_free(&dvobj->hw_init_mutex); ++ _rtw_mutex_free(&dvobj->h2c_fwcmd_mutex); ++ _rtw_mutex_free(&dvobj->setch_mutex); ++ _rtw_mutex_free(&dvobj->setbw_mutex); ++ rtw_mfree((u8*)dvobj, sizeof(*dvobj)); ++ } ++ ++_func_exit_; ++} ++ ++static void spi_irq_work(void *data) ++{ ++ struct delayed_work *dwork; ++ PGSPI_DATA pgspi; ++ struct dvobj_priv *dvobj; ++ ++ ++ dwork = container_of(data, struct delayed_work, work); ++ pgspi = container_of(dwork, GSPI_DATA, irq_work); ++ ++ dvobj = spi_get_drvdata(pgspi->func); ++ if (!dvobj->if1) { ++ DBG_871X("%s if1 == NULL !!\n", __FUNCTION__); ++ return; ++ } ++ spi_int_hdl(dvobj->if1); ++} ++ ++static void gspi_intf_start(PADAPTER padapter) ++{ ++ PGSPI_DATA pgspi; ++ ++ ++ if (padapter == NULL) { ++ DBG_871X(KERN_ERR "%s: padapter is NULL!\n", __FUNCTION__); ++ return; ++ } ++ ++ pgspi = &adapter_to_dvobj(padapter)->intf_data; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ pgspi->priv_wq = alloc_workqueue("spi_wq", 0, 0); ++#else ++ pgspi->priv_wq = create_workqueue("spi_wq"); ++#endif ++ INIT_DELAYED_WORK(&pgspi->irq_work, (void*)spi_irq_work); ++ ++ enable_irq(oob_irq); ++ //hal dep ++ rtw_hal_enable_interrupt(padapter); ++} ++ ++static void gspi_intf_stop(PADAPTER padapter) ++{ ++ PGSPI_DATA pgspi; ++ ++ ++ if (padapter == NULL) { ++ DBG_871X(KERN_ERR "%s: padapter is NULL!\n", __FUNCTION__); ++ return; ++ } ++ ++ pgspi = &adapter_to_dvobj(padapter)->intf_data; ++ ++ if (pgspi->priv_wq) { ++ cancel_delayed_work_sync(&pgspi->irq_work); ++ flush_workqueue(pgspi->priv_wq); ++ destroy_workqueue(pgspi->priv_wq); ++ pgspi->priv_wq = NULL; ++ } ++ ++ //hal dep ++ rtw_hal_disable_interrupt(padapter); ++ disable_irq(oob_irq); ++} ++ ++/* ++ * Do deinit job corresponding to netdev_open() ++ */ ++void rtw_dev_unload(PADAPTER padapter) ++{ ++ struct net_device *pnetdev = (struct net_device*)padapter->pnetdev; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+rtw_dev_unload\n")); ++ ++ padapter->bDriverStopped = _TRUE; ++ #ifdef CONFIG_XMIT_ACK ++ if (padapter->xmitpriv.ack_tx) ++ rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_DRV_STOP); ++ #endif ++ ++ if (padapter->bup == _TRUE) ++ { ++#if 0 ++ if (padapter->intf_stop) ++ padapter->intf_stop(padapter); ++#else ++ gspi_intf_stop(padapter); ++#endif ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("@ rtw_dev_unload: stop intf complete!\n")); ++ ++ if (!adapter_to_pwrctl(padapter)->bInternalAutoSuspend) ++ rtw_stop_drv_threads(padapter); ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("@ rtw_dev_unload: stop thread complete!\n")); ++ ++ if (padapter->bSurpriseRemoved == _FALSE) ++ { ++#ifdef CONFIG_WOWLAN ++ if (adapter_to_pwrctl(padapter)->bSupportRemoteWakeup == _TRUE) { ++ DBG_871X("%s bSupportRemoteWakeup==_TRUE do not run rtw_hal_deinit()\n",__FUNCTION__); ++ } ++ else ++#endif ++ { ++ rtw_hal_deinit(padapter); ++ } ++ padapter->bSurpriseRemoved = _TRUE; ++ } ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("@ rtw_dev_unload: deinit hal complelt!\n")); ++ ++ padapter->bup = _FALSE; ++ } ++ else { ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("rtw_dev_unload: bup==_FALSE\n")); ++ } ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("-rtw_dev_unload\n")); ++} ++ ++static PADAPTER rtw_gspi_if1_init(struct dvobj_priv *dvobj) ++{ ++ int status = _FAIL; ++ struct net_device *pnetdev; ++ PADAPTER padapter = NULL; ++ ++ ++ padapter = (PADAPTER)rtw_zvmalloc(sizeof(*padapter)); ++ if (NULL == padapter) { ++ goto exit; ++ } ++ ++ padapter->dvobj = dvobj; ++ dvobj->if1 = padapter; ++ ++ padapter->bDriverStopped = _TRUE; ++ ++ dvobj->padapters[dvobj->iface_nums++] = padapter; ++ padapter->iface_id = IFACE_ID0; ++ ++#if defined(CONFIG_CONCURRENT_MODE) || defined(CONFIG_DUALMAC_CONCURRENT) ++ //set adapter_type/iface type for primary padapter ++ padapter->isprimary = _TRUE; ++ padapter->adapter_type = PRIMARY_ADAPTER; ++ #ifndef CONFIG_HWPORT_SWAP ++ padapter->iface_type = IFACE_PORT0; ++ #else ++ padapter->iface_type = IFACE_PORT1; ++ #endif ++#endif ++ ++ padapter->interface_type = RTW_GSPI; ++ decide_chip_type_by_device_id(padapter); ++ ++ //3 1. init network device data ++ pnetdev = rtw_init_netdev(padapter); ++ if (!pnetdev) ++ goto free_adapter; ++ ++ SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj)); ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ rtw_wdev_alloc(padapter, dvobj_to_dev(dvobj)); ++#endif ++ ++ ++ //3 3. init driver special setting, interface, OS and hardware relative ++ //4 3.1 set hardware operation functions ++ hal_set_hal_ops(padapter); ++ ++ ++ //3 5. initialize Chip version ++ padapter->intf_start = &gspi_intf_start; ++ padapter->intf_stop = &gspi_intf_stop; ++ ++ if (rtw_init_io_priv(padapter, spi_set_intf_ops) == _FAIL) ++ { ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ++ ("rtw_drv_init: Can't init io_priv\n")); ++ goto free_hal_data; ++ } ++ ++ { ++ u32 ret = 0; ++ DBG_8192C("read start:\n"); ++ //spi_write8_endian(padapter, SPI_LOCAL_OFFSET | 0xF0, 0x01, 1); ++ rtw_write8(padapter, SPI_LOCAL_OFFSET | 0xF0, 0x03); ++ ret = rtw_read32(padapter, SPI_LOCAL_OFFSET | 0xF0); ++ DBG_8192C("read end 0xF0 read32:%x:\n", ret); ++ DBG_8192C("read end 0xF0 read8:%x:\n", rtw_read8(padapter, SPI_LOCAL_OFFSET | 0xF0)); ++ ++ } ++ ++ rtw_hal_read_chip_version(padapter); ++ ++ rtw_hal_chip_configure(padapter); ++ ++ ++ //3 6. read efuse/eeprom data ++ rtw_hal_read_chip_info(padapter); ++ ++ ++ //3 7. init driver common data ++ if (rtw_init_drv_sw(padapter) == _FAIL) { ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ++ ("rtw_drv_init: Initialize driver software resource Failed!\n")); ++ goto free_hal_data; ++ } ++ ++ ++ //3 8. get WLan MAC address ++ // set mac addr ++ rtw_macaddr_cfg(padapter->eeprompriv.mac_addr); ++ rtw_init_wifidirect_addrs(padapter, padapter->eeprompriv.mac_addr, padapter->eeprompriv.mac_addr); ++ ++ rtw_hal_disable_interrupt(padapter); ++ ++ DBG_871X("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n" ++ ,padapter->bDriverStopped ++ ,padapter->bSurpriseRemoved ++ ,padapter->bup ++ ,padapter->hw_init_completed ++ ); ++ ++ status = _SUCCESS; ++ ++free_hal_data: ++ if (status != _SUCCESS && padapter->HalData) ++ rtw_mfree(padapter->HalData, sizeof(*(padapter->HalData))); ++ ++free_wdev: ++ if (status != _SUCCESS) { ++ #ifdef CONFIG_IOCTL_CFG80211 ++ rtw_wdev_unregister(padapter->rtw_wdev); ++ rtw_wdev_free(padapter->rtw_wdev); ++ #endif ++ } ++ ++free_adapter: ++ if (status != _SUCCESS) { ++ if (pnetdev) ++ rtw_free_netdev(pnetdev); ++ else if (padapter) ++ rtw_vmfree((u8*)padapter, sizeof(*padapter)); ++ padapter = NULL; ++ } ++ ++exit: ++ return padapter; ++} ++ ++static void rtw_gspi_if1_deinit(PADAPTER if1) ++{ ++ struct net_device *pnetdev = if1->pnetdev; ++ struct mlme_priv *pmlmepriv = &if1->mlmepriv; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) ++ rtw_disassoc_cmd(if1, 0, _FALSE); ++ ++#ifdef CONFIG_AP_MODE ++ free_mlme_ap_info(if1); ++ #ifdef CONFIG_HOSTAPD_MLME ++ hostapd_mode_unload(if1); ++#endif ++#endif ++/* ++ if(if1->DriverState != DRIVER_DISAPPEAR) { ++ if(pnetdev) { ++ unregister_netdev(pnetdev); //will call netdev_close() ++ rtw_proc_remove_one(pnetdev); ++ } ++ } ++*/ ++ rtw_cancel_all_timer(if1); ++ ++ rtw_dev_unload(if1); ++ DBG_871X("+r871xu_dev_remove, hw_init_completed=%d\n", if1->hw_init_completed); ++ ++ rtw_handle_dualmac(if1, 0); ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if (if1->rtw_wdev) ++ { ++ //rtw_wdev_unregister(if1->rtw_wdev); ++ rtw_wdev_free(if1->rtw_wdev); ++ } ++#endif ++ ++ rtw_free_drv_sw(if1); ++ ++ if(pnetdev) ++ rtw_free_netdev(pnetdev); ++} ++ ++/* ++ * drv_init() - a device potentially for us ++ * ++ * notes: drv_init() is called when the bus driver has located a card for us to support. ++ * We accept the new device by returning 0. ++ */ ++static int /*__devinit*/ rtw_drv_probe(struct spi_device *spi) ++{ ++ int status = _FAIL; ++ struct dvobj_priv *dvobj; ++ struct net_device *pnetdev; ++ PADAPTER if1 = NULL, if2 = NULL; ++ ++ ++ DBG_8192C("RTW: %s line:%d", __FUNCTION__, __LINE__); ++ ++ if ((dvobj = gspi_dvobj_init(spi)) == NULL) { ++ DBG_871X("%s: Initialize device object priv Failed!\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ if ((if1 = rtw_gspi_if1_init(dvobj)) == NULL) { ++ DBG_871X("rtw_init_primary_adapter Failed!\n"); ++ goto free_dvobj; ++ } ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ((if2 = rtw_drv_if2_init(if1, NULL, spi_set_intf_ops)) == NULL) { ++ goto free_if1; ++ } ++#endif ++ ++ //dev_alloc_name && register_netdev ++ if((status = rtw_drv_register_netdev(if1)) != _SUCCESS) { ++ goto free_if2; ++ } ++ ++#ifdef CONFIG_HOSTAPD_MLME ++ hostapd_mode_init(if1); ++#endif ++ ++#ifdef CONFIG_PLATFORM_RTD2880B ++ DBG_871X("wlan link up\n"); ++ rtd2885_wlan_netlink_sendMsg("linkup", "8712"); ++#endif ++ ++#ifdef RTK_DMP_PLATFORM ++ rtw_proc_init_one(if1->pnetdev); ++#endif ++ ++ if (gspi_alloc_irq(dvobj) != _SUCCESS) ++ goto free_if2; ++ ++#ifdef CONFIG_GLOBAL_UI_PID ++ if(ui_pid[1]!=0) { ++ DBG_871X("ui_pid[1]:%d\n",ui_pid[1]); ++ rtw_signal_process(ui_pid[1], SIGUSR2); ++ } ++#endif ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("-871x_drv - drv_init, success!\n")); ++ ++ status = _SUCCESS; ++ ++free_if2: ++ if (status != _SUCCESS && if2) { ++ #ifdef CONFIG_CONCURRENT_MODE ++ rtw_drv_if2_stop(if2); ++ rtw_drv_if2_free(if2); ++ #endif ++ } ++ ++free_if1: ++ if (status != _SUCCESS && if1) { ++ rtw_gspi_if1_deinit(if1); ++ } ++ ++free_dvobj: ++ if (status != _SUCCESS) ++ gspi_dvobj_deinit(spi); ++ ++exit: ++ return status == _SUCCESS?0:-ENODEV; ++} ++extern void rtw_unregister_netdevs(struct dvobj_priv *dvobj); ++static int /*__devexit*/ rtw_dev_remove(struct spi_device *spi) ++{ ++ struct dvobj_priv *dvobj = spi_get_drvdata(spi); ++ PADAPTER padapter = dvobj->if1; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+rtw_dev_remove\n")); ++ ++ dvobj->processing_dev_remove = _TRUE; ++ rtw_unregister_netdevs(dvobj); ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_ANDROID_POWER) ++ rtw_unregister_early_suspend(dvobj_to_pwrctl(dvobj)); ++#endif ++ ++ rtw_pm_set_ips(padapter, IPS_NONE); ++ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE); ++ ++ LeaveAllPowerSaveMode(padapter); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ rtw_drv_if2_stop(dvobj->if2); ++#endif ++ ++ rtw_gspi_if1_deinit(padapter); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ rtw_drv_if2_free(dvobj->if2); ++#endif ++ ++ gspi_dvobj_deinit(spi); ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("-rtw_dev_remove\n")); ++ ++_func_exit_; ++ ++ return 0; ++} ++ ++static int rtw_gspi_suspend(struct spi_device *spi, pm_message_t mesg) ++{ ++ struct dvobj_priv *dvobj = spi_get_drvdata(spi); ++ PADAPTER padapter = dvobj->if1; ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct net_device *pnetdev = padapter->pnetdev; ++ int ret = 0; ++ ++ u32 start_time = rtw_get_current_time(); ++ ++ _func_enter_; ++ ++ DBG_871X("==> %s (%s:%d)\n",__FUNCTION__, current->comm, current->pid); ++ ++ pwrpriv->bInSuspend = _TRUE; ++ ++ while (pwrpriv->bips_processing == _TRUE) ++ rtw_msleep_os(1); ++ ++ if((!padapter->bup) || (padapter->bDriverStopped)||(padapter->bSurpriseRemoved)) ++ { ++ DBG_871X("%s bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n", __FUNCTION__ ++ ,padapter->bup, padapter->bDriverStopped,padapter->bSurpriseRemoved); ++ goto exit; ++ } ++ ++ rtw_cancel_all_timer(padapter); ++ LeaveAllPowerSaveMode(padapter); ++ ++ //padapter->net_closed = _TRUE; ++ //s1. ++ if(pnetdev) ++ { ++ netif_carrier_off(pnetdev); ++ rtw_netif_stop_queue(pnetdev); ++ } ++#ifdef CONFIG_WOWLAN ++ pwrpriv->bSupportRemoteWakeup=_TRUE; ++#else ++ //s2. ++ rtw_disassoc_cmd(padapter, 0, _FALSE); ++#endif ++ ++#ifdef CONFIG_LAYER2_ROAMING_RESUME ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED) ) ++ { ++ DBG_871X("%s %s(" MAC_FMT "), length:%d assoc_ssid.length:%d\n",__FUNCTION__, ++ pmlmepriv->cur_network.network.Ssid.Ssid, ++ MAC_ARG(pmlmepriv->cur_network.network.MacAddress), ++ pmlmepriv->cur_network.network.Ssid.SsidLength, ++ pmlmepriv->assoc_ssid.SsidLength); ++ ++ rtw_set_roaming(padapter, 1); ++ } ++#endif ++ ++ //s2-2. indicate disconnect to os ++ rtw_indicate_disconnect(padapter); ++ //s2-3. ++ rtw_free_assoc_resources(padapter, 1); ++ ++ //s2-4. ++ rtw_free_network_queue(padapter, _TRUE); ++ ++ rtw_led_control(padapter, LED_CTL_POWER_OFF); ++ ++ rtw_dev_unload(padapter); ++ ++ if(check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) ++ rtw_indicate_scan_done(padapter, 1); ++ ++ if(check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) ++ rtw_indicate_disconnect(padapter); ++ ++ // interface deinit ++ gspi_deinit(dvobj); ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("%s: deinit GSPI complete!\n", __FUNCTION__)); ++ ++ rtw_wifi_gpio_wlan_ctrl(WLAN_PWDN_OFF); ++ rtw_mdelay_os(1); ++exit: ++ DBG_871X("<=== %s return %d.............. in %dms\n", __FUNCTION__ ++ , ret, rtw_get_passing_time_ms(start_time)); ++ ++ _func_exit_; ++ return ret; ++} ++ ++extern int pm_netdev_open(struct net_device *pnetdev,u8 bnormal); ++int rtw_resume_process(_adapter *padapter) ++{ ++ struct net_device *pnetdev; ++ struct pwrctrl_priv *pwrpriv; ++ u8 is_pwrlock_hold_by_caller; ++ u8 is_directly_called_by_auto_resume; ++ int ret = 0; ++ u32 start_time = rtw_get_current_time(); ++ ++ _func_enter_; ++ ++ DBG_871X("==> %s (%s:%d)\n",__FUNCTION__, current->comm, current->pid); ++ ++ rtw_wifi_gpio_wlan_ctrl(WLAN_PWDN_ON); ++ rtw_mdelay_os(1); ++ ++ { ++ u32 ret = 0; ++ DBG_8192C("read start:\n"); ++ //spi_write8_endian(padapter, SPI_LOCAL_OFFSET | 0xF0, 0x01, 1); ++ rtw_write8(padapter, SPI_LOCAL_OFFSET | 0xF0, 0x03); ++ ret = rtw_read32(padapter, SPI_LOCAL_OFFSET | 0xF0); ++ DBG_8192C("read end 0xF0 read32:%x:\n", ret); ++ DBG_8192C("read end 0xF0 read8:%x:\n", rtw_read8(padapter, SPI_LOCAL_OFFSET | 0xF0)); ++ ++ } ++ ++ if (padapter) { ++ pnetdev = padapter->pnetdev; ++ pwrpriv = adapter_to_pwrctl(padapter); ++ } else { ++ ret = -1; ++ goto exit; ++ } ++ ++ // interface init ++ if (gspi_init(adapter_to_dvobj(padapter)) != _SUCCESS) ++ { ++ ret = -1; ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: initialize SDIO Failed!!\n", __FUNCTION__)); ++ goto exit; ++ } ++ rtw_hal_disable_interrupt(padapter); ++ if (gspi_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) ++ { ++ ret = -1; ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: gspi_alloc_irq Failed!!\n", __FUNCTION__)); ++ goto exit; ++ } ++ ++ rtw_reset_drv_sw(padapter); ++ pwrpriv->bkeepfwalive = _FALSE; ++ ++ DBG_871X("bkeepfwalive(%x)\n",pwrpriv->bkeepfwalive); ++ if(pm_netdev_open(pnetdev,_TRUE) != 0) { ++ ret = -1; ++ goto exit; ++ } ++ ++ netif_device_attach(pnetdev); ++ netif_carrier_on(pnetdev); ++ ++ if( padapter->pid[1]!=0) { ++ DBG_871X("pid[1]:%d\n",padapter->pid[1]); ++ rtw_signal_process(padapter->pid[1], SIGUSR2); ++ } ++ ++ #ifdef CONFIG_LAYER2_ROAMING_RESUME ++ rtw_roaming(padapter, NULL); ++ #endif ++ ++ #ifdef CONFIG_RESUME_IN_WORKQUEUE ++ rtw_unlock_suspend(); ++ #endif //CONFIG_RESUME_IN_WORKQUEUE ++ ++exit: ++ pwrpriv->bInSuspend = _FALSE; ++ DBG_871X("<=== %s return %d.............. in %dms\n", __FUNCTION__ ++ , ret, rtw_get_passing_time_ms(start_time)); ++ ++ _func_exit_; ++ ++ return ret; ++} ++ ++static int rtw_gspi_resume(struct spi_device *spi) ++{ ++ struct dvobj_priv *dvobj = spi_get_drvdata(spi); ++ PADAPTER padapter = dvobj->if1; ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj); ++ int ret = 0; ++ ++ ++ DBG_871X("==> %s (%s:%d)\n",__FUNCTION__, current->comm, current->pid); ++ ++ if(pwrpriv->bInternalAutoSuspend ){ ++ ret = rtw_resume_process(padapter); ++ } else { ++#ifdef CONFIG_RESUME_IN_WORKQUEUE ++ rtw_resume_in_workqueue(pwrpriv); ++#else ++ if(rtw_is_earlysuspend_registered(pwrpriv)) { ++ /* jeff: bypass resume here, do in late_resume */ ++ rtw_set_do_late_resume(pwrpriv, _TRUE); ++ } else { ++ ret = rtw_resume_process(padapter); ++ } ++#endif /* CONFIG_RESUME_IN_WORKQUEUE */ ++ } ++ ++ DBG_871X("<======== %s return %d\n", __FUNCTION__, ret); ++ return ret; ++ ++} ++ ++ ++static struct spi_driver rtw_spi_drv = { ++ .probe = rtw_drv_probe, ++ .remove = rtw_dev_remove, ++ .suspend = rtw_gspi_suspend, ++ .resume = rtw_gspi_resume, ++ .driver = { ++ .name = "wlan_spi", ++ .bus = &spi_bus_type, ++ .owner = THIS_MODULE, ++ } ++ ++}; ++ ++static int __init rtw_drv_entry(void) ++{ ++ int ret; ++ ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+rtw_drv_entry\n")); ++ DBG_8192C("RTW: rtw_drv_entry enter\n"); ++ ++ rtw_suspend_lock_init(); ++ ++ drvpriv.drv_registered = _TRUE; ++ ++ rtw_wifi_gpio_init(); ++ rtw_wifi_gpio_wlan_ctrl(WLAN_PWDN_ON); ++ ret = spi_register_driver(&rtw_spi_drv); ++ ++ DBG_8192C("RTW: rtw_drv_entry exit %d\n", ret); ++ ++ return 0; ++} ++ ++static void __exit rtw_drv_halt(void) ++{ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+rtw_drv_halt\n")); ++ DBG_8192C("RTW: rtw_drv_halt enter\n"); ++ ++ drvpriv.drv_registered = _FALSE; ++ ++ spi_unregister_driver(&rtw_spi_drv); ++ ++ ++ rtw_wifi_gpio_wlan_ctrl(WLAN_PWDN_OFF); ++ rtw_wifi_gpio_deinit(); ++ ++ rtw_suspend_lock_uninit(); ++ DBG_8192C("RTW: rtw_drv_halt enter\n"); ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("-rtw_drv_halt\n")); ++ ++ rtw_mstat_dump(); ++} ++module_init(rtw_drv_entry); ++module_exit(rtw_drv_halt); +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/gspi_ops_linux.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/gspi_ops_linux.c +new file mode 100644 +index 00000000..8600f059 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/gspi_ops_linux.c +@@ -0,0 +1,432 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ *******************************************************************************/ ++#define _GSPI_OPS_LINUX_C_ ++ ++#include ++#include ++ ++#include "rtl8723a_hal.h" ++#include "rtl8723a_spec.h" ++#include "gspi_ops.h" ++ ++int spi_send_msg(PADAPTER Adapter, struct spi_transfer xfers[], u32 IoAction) ++{ ++ struct dvobj_priv *psddev; ++ struct spi_device *spi; ++ struct spi_message msg; ++ int ret = 1; ++ ++ if (Adapter == NULL) { ++ DBG_8192C(KERN_ERR "%s: padapter is NULL!\n", __func__); ++ return 1; ++ } ++ ++ psddev = adapter_to_dvobj(Adapter); ++ spi = psddev->intf_data.func; ++ ++ spi_message_init(&msg); ++ spi_message_add_tail(&xfers[0], &msg); ++ spi_message_add_tail(&xfers[1], &msg); ++ spi_message_add_tail(&xfers[2], &msg); ++ ret = spi_sync(spi, &msg); ++ if (ret) { ++ DBG_8192C("%s: FAIL!\n", __func__); ++ } ++ ++ return ret; ++} ++ ++int addr_convert(u32 addr) ++{ ++ u32 domain_id = 0 ; ++ u32 temp_addr = addr&0xffff0000; ++ ++ if (temp_addr == 0 ) { ++ domain_id = WLAN_IOREG_DOMAIN; ++ return domain_id; ++ } ++ ++ switch (temp_addr) { ++ case SPI_LOCAL_OFFSET: ++ domain_id = SPI_LOCAL_DOMAIN; ++ break; ++ case WLAN_IOREG_OFFSET: ++ domain_id = WLAN_IOREG_DOMAIN; ++ break; ++ case FW_FIFO_OFFSET: ++ domain_id = FW_FIFO_DOMAIN; ++ break; ++ case TX_HIQ_OFFSET: ++ domain_id = TX_HIQ_DOMAIN; ++ break; ++ case TX_MIQ_OFFSET: ++ domain_id = TX_MIQ_DOMAIN; ++ break; ++ case TX_LOQ_OFFSET: ++ domain_id = TX_LOQ_DOMAIN; ++ break; ++ case RX_RXOFF_OFFSET: ++ domain_id = RX_RXFIFO_DOMAIN; ++ break; ++ default: ++ break; ++ } ++ //sys_mib.Spi_Transation_record.domain_id =domain_id; ++ return domain_id; ++} ++ ++static u32 buf_endian_reverse(u32 src) ++{ ++ return (((src&0x000000ff)<<24)|((src&0x0000ff00)<<8)| ++ ((src&0x00ff0000)>>8)|((src&0xff000000)>>24)); ++} ++ ++void spi_get_status_info(ADAPTER* Adapter, unsigned char *status) ++{ ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ ++ pHalData->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX] = GET_STATUS_PUB_PAGE_NUM(status); ++ pHalData->SdioTxFIFOFreePage[HI_QUEUE_IDX] = GET_STATUS_HI_PAGE_NUM(status); ++ pHalData->SdioTxFIFOFreePage[MID_QUEUE_IDX] = GET_STATUS_MID_PAGE_NUM(status); ++ pHalData->SdioTxFIFOFreePage[LOW_QUEUE_IDX] = GET_STATUS_LOW_PAGE_NUM(status); ++ ++ //DBG_8192C("%s: Free page for HIQ(%#x),MIDQ(%#x),LOWQ(%#x),PUBQ(%#x)\n", ++ // __FUNCTION__, ++ // pHalData->SdioTxFIFOFreePage[HI_QUEUE_IDX], ++ // pHalData->SdioTxFIFOFreePage[MID_QUEUE_IDX], ++ // pHalData->SdioTxFIFOFreePage[LOW_QUEUE_IDX], ++ // pHalData->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX]); ++} ++ ++int spi_read_write_reg(PADAPTER pAdapter, int write_flag, u32 addr, char * buf, int len, u32 eddien) ++{ ++ int fun = 1, domain_id = 0x0; //LOCAL ++ unsigned int cmd = 0 ; ++ int byte_en = 0 ;//,i = 0 ; ++ int ret = 0; ++ unsigned char status[8] = {0}; ++ unsigned int data_tmp = 0; ++ //u32 force_bigendian = !eddien; ++ u32 force_bigendian = eddien; ++ ++ if (len!=1 && len!=2 && len != 4) { ++ return -1; ++ } ++ ++ domain_id = addr_convert(addr); ++ ++ addr &= 0x7fff; ++ len &= 0xff; ++ if (write_flag) //write register ++ { ++ int remainder = addr % 4; ++ u32 val32 = *(u32 *)buf; ++ switch(len) { ++ case 1: ++ byte_en = (0x1 << remainder); ++ data_tmp = (val32& 0xff)<< (remainder*8); ++ break; ++ case 2: ++ byte_en = (0x3 << remainder); ++ data_tmp = (val32 & 0xffff)<< (remainder*8); ++ break; ++ case 4: ++ byte_en = 0xf; ++ data_tmp = val32 & 0xffffffff; ++ break; ++ default: ++ byte_en = 0xf; ++ data_tmp = val32 & 0xffffffff; ++ break; ++ } ++ } ++ else //read register ++ { ++ switch(len) { ++ case 1: ++ byte_en = 0x1; ++ break; ++ case 2: ++ byte_en = 0x3; ++ break; ++ case 4: ++ byte_en = 0xf; ++ break; ++ default: ++ byte_en = 0xf; ++ break; ++ } ++ } ++ ++ //addr = 0xF0 4byte: 0x2800f00f ++ REG_LEN_FORMAT(&cmd, byte_en); ++ REG_ADDR_FORMAT(&cmd, (addr&0xfffffffc)); ++ REG_DOMAIN_ID_FORMAT(&cmd, domain_id); ++ REG_FUN_FORMAT(&cmd, fun); ++ REG_RW_FORMAT(&cmd, write_flag); ++ ++ //DBG_8192C("spi_read_write_reg cmd1: %x, data_tmp is %x\n",cmd, data_tmp); ++ ++ if (force_bigendian) { ++ cmd = buf_endian_reverse(cmd); ++ } ++ ++ //io is one by one, so we do not need fwps_lock here ++ //rtw_spin_lock(&padapter->halpriv.fwps_lock); ++ //padapter->io_fifo_processing = _TRUE; ++ if (!write_flag && (domain_id!= RX_RXFIFO_DOMAIN)) { ++ u32 read_data = 0; ++ struct spi_transfer xfers[3]; ++ _rtw_memset(xfers, 0x00, 3*sizeof(struct spi_transfer)); ++ _rtw_memset(buf, 0x0, len); ++ ++ xfers[0].tx_buf = &cmd; ++ xfers[0].len = 4; ++ ++ xfers[1].rx_buf = status; ++ xfers[1].len = 8; ++ ++ xfers[2].rx_buf = &read_data; ++ xfers[2].len = 4; ++ ++ //DBG_8192C("spi_read_write_reg: read_data is %x\n", read_data); ++ ret = spi_send_msg(pAdapter, xfers, 0); ++ if (ret) { ++ DBG_8192C(KERN_ERR "%s: FAIL!(%d) addr=0x%05x\n", __func__, ret, addr); ++ read_data = 0; ++ _rtw_memset(status, 0, 8); ++ } ++ ++ //DBG_8192C("spi_read_write_reg: read_data is %x\n", read_data); ++ read_data = EF4Byte(read_data); ++ //add for 8810 ++#ifdef CONFIG_BIG_ENDIAN ++ if (!force_bigendian) ++ read_data = buf_endian_reverse(read_data); ++#else ++ if (force_bigendian) ++ read_data = buf_endian_reverse(read_data); ++#endif ++ *(u32*)buf = read_data; ++ //DBG_8192C("spi_read_write_reg: read: buf is %x %x %x %x\n", buf[0], buf[1], buf[2], buf[3]); ++ } else if (write_flag ) { ++ struct spi_transfer xfers[3]; ++ _rtw_memset(xfers, 0x00, 3*sizeof(struct spi_transfer)); ++ ++ xfers[0].tx_buf = &cmd; ++ xfers[0].len = 4; ++ ++ xfers[1].tx_buf = &data_tmp; ++ xfers[1].len = 4; ++ ++ xfers[2].rx_buf = status; ++ xfers[2].len = 8; ++ ++ //DBG_8192C("spi_read_write_reg data_tmp 111: %x\n",data_tmp); ++#ifdef CONFIG_BIG_ENDIAN ++ if (!force_bigendian) ++ data_tmp = buf_endian_reverse(data_tmp); ++#else ++ if (force_bigendian) ++ data_tmp = buf_endian_reverse(data_tmp); ++#endif ++ ret = spi_send_msg(pAdapter, xfers, 0); ++ if (ret) { ++ DBG_8192C(KERN_ERR "%s: FAIL!(%d) addr=0x%05x\n", __func__, ret, addr); ++ _rtw_memset(status, 0, 8); ++ } ++ } ++ ++ //padapter->io_fifo_processing = _FALSE; ++ ++ spi_get_status_info(pAdapter, (unsigned char*)status); ++ ++ return ret; ++} ++ ++u8 spi_read8(ADAPTER *Adapter, unsigned int addr, s32 *err) ++{ ++ unsigned int ret = 0; ++ int val32 = 0 , remainder = 0 ; ++ s32 _err = 0; ++ ++ _err = spi_read_write_reg(Adapter,0,addr&0xFFFFFFFC,(char *)&ret,4,0); ++ remainder = addr % 4; ++ val32 = ret; ++ val32 = (val32& (0xff<< (remainder<<3)))>>(remainder<<3); ++ ++ if (err) ++ *err = _err; ++ ++ return (u8)val32; ++ ++} ++ ++u16 spi_read16(ADAPTER *Adapter, u32 addr, s32 *err) ++{ ++ unsigned int ret = 0; ++ int val32 = 0 , remainder = 0 ; ++ s32 _err = 0; ++ ++ _err = spi_read_write_reg(Adapter,0,addr&0xFFFFFFFC,(char *)&ret,4,0); ++ remainder = addr % 4; ++ val32 = ret; ++ val32 = (val32& (0xffff<< (remainder<<3)))>>(remainder<<3); ++ ++ if (err) ++ *err = _err; ++ ++ return (u16)val32; ++} ++ ++u32 spi_read32(ADAPTER *Adapter, u32 addr, s32 *err) ++{ ++ unsigned int ret = 0; ++ s32 _err = 0; ++ ++ _err = spi_read_write_reg(Adapter,0,addr&0xFFFFFFFC,(char *)&ret,4,0); ++ if (err) ++ *err = _err; ++ ++ return ret; ++} ++ ++void spi_write8(ADAPTER *Adapter, u32 addr, u8 buf, s32 *err) ++{ ++ int ret = 0; ++ ++ ret = spi_read_write_reg(Adapter,1,addr,(char *)&buf,1,0); ++ if (err) ++ *err = ret; ++} ++ ++void spi_write16(ADAPTER *Adapter, u32 addr, u16 buf, s32 *err) ++{ ++ int ret = 0; ++ ++ ret = spi_read_write_reg(Adapter,1,addr,(char *)&buf,2,0); ++ if (err) ++ *err = ret; ++} ++ ++void spi_write32(ADAPTER *Adapter, u32 addr, u32 buf, s32 *err) ++{ ++ int ret = 0; ++ ++ ret = spi_read_write_reg(Adapter, 1,addr,(char *)&buf,4,0); ++ if (err) ++ *err = ret; ++} ++ ++unsigned int spi_write8_endian(ADAPTER *Adapter, unsigned int addr, unsigned int buf, u32 big) ++{ ++ int ret = 0; ++ ++ ret = spi_read_write_reg(Adapter,1,addr,(char *)&buf,1, big); ++ return ret; ++} ++ ++void spi_write_tx_fifo(ADAPTER *Adapter, u8 *buf, int len, u32 fifo) ++{ ++ int fun =1; //TX_HIQ_FIFO ++ unsigned int cmd = 0; ++ unsigned char status[8]; ++ u8 more_data = 0; ++ int ret = 0; ++ ++ struct spi_transfer xfers[3]; ++ _rtw_memset(xfers, 0x00, 3*sizeof(struct spi_transfer)); ++ ++ xfers[0].tx_buf = &cmd; ++ xfers[0].len = 4; ++ ++ xfers[1].tx_buf = buf; ++ xfers[1].len = len;//len/4; ++ ++ xfers[2].rx_buf = status; ++ xfers[2].len = 8; ++ ++_func_enter_; ++ ++ FIFO_LEN_FORMAT(&cmd, len); //TX Agg len ++ FIFO_DOMAIN_ID_FORMAT(&cmd, fifo); ++ FIFO_FUN_FORMAT(&cmd, fun); ++ FIFO_RW_FORMAT(&cmd, (unsigned int)1); //write ++ ++ _rtw_memset(status, 0x00, 8); ++ ++ ret = spi_send_msg(Adapter, xfers, 1); ++ if (ret) { ++ DBG_8192C("%s: FAIL!(%d)\n", __func__, ret); ++ _rtw_memset(status, 0, 8); ++ } ++ ++ spi_get_status_info(Adapter, status); ++ ++ more_data = GET_STATUS_HISR_LOW8BIT(status) & BIT(0); ++ //if(more_data) { ++ // rtw_queue_delayed_work(Adapter->recv_wq, &Adapter->recv_work, 0, (void*)Adapter); ++ //} ++ ++_func_exit_; ++ ++ return; ++} ++ ++int spi_read_rx_fifo(ADAPTER *Adapter, unsigned char *buf, int len, struct spi_more_data *pmore_data) ++{ ++ int fun =1, domain_id = 0x1f; //RX_FIFO ++ unsigned int cmd = 0; ++ unsigned char status[8]; ++ int ret = 0; ++ struct spi_transfer xfers[3]; ++ ++ _rtw_memset(xfers, 0x00, 3*sizeof(struct spi_transfer)); ++ ++ xfers[0].tx_buf = &cmd; ++ xfers[0].len = 4; ++ ++ xfers[1].rx_buf = buf; ++ xfers[1].len = len; ++ ++ xfers[2].rx_buf = status; ++ xfers[2].len = 8; ++ ++ FIFO_LEN_FORMAT(&cmd, len); //TX Agg len ++ FIFO_DOMAIN_ID_FORMAT(&cmd, domain_id); ++ FIFO_FUN_FORMAT(&cmd, fun); ++ FIFO_RW_FORMAT(&cmd, 0); //read ++ ++ _rtw_memset(status, 0x00, 8); ++ _rtw_memset(buf, 0x0, len); ++ ++ ret = spi_send_msg(Adapter, xfers, 1); ++ if (ret) { ++ DBG_8192C(KERN_ERR "%s: FAIL!(%d)\n", __func__, ret); ++ _rtw_memset(status, 0x00, 8); ++ _rtw_memset(buf, 0x0, len); ++ return _FAIL; ++ } ++ ++ spi_get_status_info(Adapter, (unsigned char*)status); ++ pmore_data->more_data = GET_STATUS_HISR_LOW8BIT(status) & BIT(0); ++ pmore_data->len = GET_STATUS_RX_LENGTH(status); ++ ++ return _SUCCESS; ++} +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/ioctl_cfg80211.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/ioctl_cfg80211.c +new file mode 100644 +index 00000000..da7c494c +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/ioctl_cfg80211.c +@@ -0,0 +1,5776 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _IOCTL_CFG80211_C_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ ++#include "ioctl_cfg80211.h" ++ ++#define RTW_MAX_MGMT_TX_CNT (8) ++ ++#define RTW_SCAN_IE_LEN_MAX 2304 ++#define RTW_MAX_REMAIN_ON_CHANNEL_DURATION 65535 //ms ++#define RTW_MAX_NUM_PMKIDS 4 ++ ++#define RTW_CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */ ++ ++ ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ ++#ifndef WLAN_CIPHER_SUITE_SMS4 ++#define WLAN_CIPHER_SUITE_SMS4 0x00147201 ++#endif ++ ++#ifndef WLAN_AKM_SUITE_WAPI_PSK ++#define WLAN_AKM_SUITE_WAPI_PSK 0x000FAC04 ++#endif ++ ++#ifndef WLAN_AKM_SUITE_WAPI_CERT ++#define WLAN_AKM_SUITE_WAPI_CERT 0x000FAC12 ++#endif ++ ++#ifndef NL80211_WAPI_VERSION_1 ++#define NL80211_WAPI_VERSION_1 (1 << 2) ++#endif ++ ++#endif ++ ++ ++ ++static const u32 rtw_cipher_suites[] = { ++ WLAN_CIPHER_SUITE_WEP40, ++ WLAN_CIPHER_SUITE_WEP104, ++ WLAN_CIPHER_SUITE_TKIP, ++ WLAN_CIPHER_SUITE_CCMP, ++#ifdef CONFIG_IEEE80211W ++ WLAN_CIPHER_SUITE_AES_CMAC, ++#endif //CONFIG_IEEE80211W ++}; ++ ++#define RATETAB_ENT(_rate, _rateid, _flags) \ ++ { \ ++ .bitrate = (_rate), \ ++ .hw_value = (_rateid), \ ++ .flags = (_flags), \ ++ } ++ ++#define CHAN2G(_channel, _freq, _flags) { \ ++ .band = IEEE80211_BAND_2GHZ, \ ++ .center_freq = (_freq), \ ++ .hw_value = (_channel), \ ++ .flags = (_flags), \ ++ .max_antenna_gain = 0, \ ++ .max_power = 30, \ ++} ++ ++#define CHAN5G(_channel, _flags) { \ ++ .band = IEEE80211_BAND_5GHZ, \ ++ .center_freq = 5000 + (5 * (_channel)), \ ++ .hw_value = (_channel), \ ++ .flags = (_flags), \ ++ .max_antenna_gain = 0, \ ++ .max_power = 30, \ ++} ++ ++static struct ieee80211_rate rtw_rates[] = { ++ RATETAB_ENT(10, 0x1, 0), ++ RATETAB_ENT(20, 0x2, 0), ++ RATETAB_ENT(55, 0x4, 0), ++ RATETAB_ENT(110, 0x8, 0), ++ RATETAB_ENT(60, 0x10, 0), ++ RATETAB_ENT(90, 0x20, 0), ++ RATETAB_ENT(120, 0x40, 0), ++ RATETAB_ENT(180, 0x80, 0), ++ RATETAB_ENT(240, 0x100, 0), ++ RATETAB_ENT(360, 0x200, 0), ++ RATETAB_ENT(480, 0x400, 0), ++ RATETAB_ENT(540, 0x800, 0), ++}; ++ ++#define rtw_a_rates (rtw_rates + 4) ++#define RTW_A_RATES_NUM 8 ++#define rtw_g_rates (rtw_rates + 0) ++#define RTW_G_RATES_NUM 12 ++ ++#define RTW_2G_CHANNELS_NUM 14 ++#define RTW_5G_CHANNELS_NUM 37 ++ ++static struct ieee80211_channel rtw_2ghz_channels[] = { ++ CHAN2G(1, 2412, 0), ++ CHAN2G(2, 2417, 0), ++ CHAN2G(3, 2422, 0), ++ CHAN2G(4, 2427, 0), ++ CHAN2G(5, 2432, 0), ++ CHAN2G(6, 2437, 0), ++ CHAN2G(7, 2442, 0), ++ CHAN2G(8, 2447, 0), ++ CHAN2G(9, 2452, 0), ++ CHAN2G(10, 2457, 0), ++ CHAN2G(11, 2462, 0), ++ CHAN2G(12, 2467, 0), ++ CHAN2G(13, 2472, 0), ++ CHAN2G(14, 2484, 0), ++}; ++ ++static struct ieee80211_channel rtw_5ghz_a_channels[] = { ++ CHAN5G(34, 0), CHAN5G(36, 0), ++ CHAN5G(38, 0), CHAN5G(40, 0), ++ CHAN5G(42, 0), CHAN5G(44, 0), ++ CHAN5G(46, 0), CHAN5G(48, 0), ++ CHAN5G(52, 0), CHAN5G(56, 0), ++ CHAN5G(60, 0), CHAN5G(64, 0), ++ CHAN5G(100, 0), CHAN5G(104, 0), ++ CHAN5G(108, 0), CHAN5G(112, 0), ++ CHAN5G(116, 0), CHAN5G(120, 0), ++ CHAN5G(124, 0), CHAN5G(128, 0), ++ CHAN5G(132, 0), CHAN5G(136, 0), ++ CHAN5G(140, 0), CHAN5G(149, 0), ++ CHAN5G(153, 0), CHAN5G(157, 0), ++ CHAN5G(161, 0), CHAN5G(165, 0), ++ CHAN5G(184, 0), CHAN5G(188, 0), ++ CHAN5G(192, 0), CHAN5G(196, 0), ++ CHAN5G(200, 0), CHAN5G(204, 0), ++ CHAN5G(208, 0), CHAN5G(212, 0), ++ CHAN5G(216, 0), ++}; ++ ++ ++void rtw_2g_channels_init(struct ieee80211_channel *channels) ++{ ++ _rtw_memcpy((void*)channels, (void*)rtw_2ghz_channels, ++ sizeof(struct ieee80211_channel)*RTW_2G_CHANNELS_NUM ++ ); ++} ++ ++void rtw_5g_channels_init(struct ieee80211_channel *channels) ++{ ++ _rtw_memcpy((void*)channels, (void*)rtw_5ghz_a_channels, ++ sizeof(struct ieee80211_channel)*RTW_5G_CHANNELS_NUM ++ ); ++} ++ ++void rtw_2g_rates_init(struct ieee80211_rate *rates) ++{ ++ _rtw_memcpy(rates, rtw_g_rates, ++ sizeof(struct ieee80211_rate)*RTW_G_RATES_NUM ++ ); ++} ++ ++void rtw_5g_rates_init(struct ieee80211_rate *rates) ++{ ++ _rtw_memcpy(rates, rtw_a_rates, ++ sizeof(struct ieee80211_rate)*RTW_A_RATES_NUM ++ ); ++} ++ ++struct ieee80211_supported_band *rtw_spt_band_alloc( ++ enum ieee80211_band band ++ ) ++{ ++ struct ieee80211_supported_band *spt_band = NULL; ++ int n_channels, n_bitrates; ++ ++ if(band == IEEE80211_BAND_2GHZ) ++ { ++ n_channels = RTW_2G_CHANNELS_NUM; ++ n_bitrates = RTW_G_RATES_NUM; ++ } ++ else if(band == IEEE80211_BAND_5GHZ) ++ { ++ n_channels = RTW_5G_CHANNELS_NUM; ++ n_bitrates = RTW_A_RATES_NUM; ++ } ++ else ++ { ++ goto exit; ++ } ++ ++ spt_band = (struct ieee80211_supported_band *)rtw_zmalloc( ++ sizeof(struct ieee80211_supported_band) ++ + sizeof(struct ieee80211_channel)*n_channels ++ + sizeof(struct ieee80211_rate)*n_bitrates ++ ); ++ if(!spt_band) ++ goto exit; ++ ++ spt_band->channels = (struct ieee80211_channel*)(((u8*)spt_band)+sizeof(struct ieee80211_supported_band)); ++ spt_band->bitrates= (struct ieee80211_rate*)(((u8*)spt_band->channels)+sizeof(struct ieee80211_channel)*n_channels); ++ spt_band->band = band; ++ spt_band->n_channels = n_channels; ++ spt_band->n_bitrates = n_bitrates; ++ ++ if(band == IEEE80211_BAND_2GHZ) ++ { ++ rtw_2g_channels_init(spt_band->channels); ++ rtw_2g_rates_init(spt_band->bitrates); ++ } ++ else if(band == IEEE80211_BAND_5GHZ) ++ { ++ rtw_5g_channels_init(spt_band->channels); ++ rtw_5g_rates_init(spt_band->bitrates); ++ } ++ ++ //spt_band.ht_cap ++ ++exit: ++ ++ return spt_band; ++} ++ ++void rtw_spt_band_free(struct ieee80211_supported_band *spt_band) ++{ ++ u32 size; ++ ++ if(!spt_band) ++ return; ++ ++ if(spt_band->band == IEEE80211_BAND_2GHZ) ++ { ++ size = sizeof(struct ieee80211_supported_band) ++ + sizeof(struct ieee80211_channel)*RTW_2G_CHANNELS_NUM ++ + sizeof(struct ieee80211_rate)*RTW_G_RATES_NUM; ++ } ++ else if(spt_band->band == IEEE80211_BAND_5GHZ) ++ { ++ size = sizeof(struct ieee80211_supported_band) ++ + sizeof(struct ieee80211_channel)*RTW_5G_CHANNELS_NUM ++ + sizeof(struct ieee80211_rate)*RTW_A_RATES_NUM; ++ } ++ else ++ { ++ ++ } ++ rtw_mfree((u8*)spt_band, size); ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++static const struct ieee80211_txrx_stypes ++rtw_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { ++ [NL80211_IFTYPE_ADHOC] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_STATION] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) ++ }, ++ [NL80211_IFTYPE_AP] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_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] = { ++ /* copy AP */ ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | ++ BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_P2P_CLIENT] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) ++ }, ++ [NL80211_IFTYPE_P2P_GO] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_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) ++ }, ++}; ++#endif ++ ++static int rtw_ieee80211_channel_to_frequency(int chan, int band) ++{ ++ /* see 802.11 17.3.8.3.2 and Annex J ++ * there are overlapping channel numbers in 5GHz and 2GHz bands */ ++ ++ if (band == IEEE80211_BAND_5GHZ) { ++ if (chan >= 182 && chan <= 196) ++ return 4000 + chan * 5; ++ else ++ return 5000 + chan * 5; ++ } else { /* IEEE80211_BAND_2GHZ */ ++ if (chan == 14) ++ return 2484; ++ else if (chan < 14) ++ return 2407 + chan * 5; ++ else ++ return 0; /* not supported */ ++ } ++} ++ ++#define MAX_BSSINFO_LEN 1000 ++struct cfg80211_bss *rtw_cfg80211_inform_bss(_adapter *padapter, struct wlan_network *pnetwork) ++{ ++ struct ieee80211_channel *notify_channel; ++ struct cfg80211_bss *bss = NULL; ++ //struct ieee80211_supported_band *band; ++ u16 channel; ++ u32 freq; ++ u64 notify_timestamp; ++ u16 notify_capability; ++ u16 notify_interval; ++ u8 *notify_ie; ++ size_t notify_ielen; ++ s32 notify_signal; ++ u8 buf[MAX_BSSINFO_LEN], *pbuf; ++ size_t len,bssinf_len=0; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ struct wireless_dev *wdev = padapter->rtw_wdev; ++ struct wiphy *wiphy = wdev->wiphy; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ ++ //DBG_8192C("%s\n", __func__); ++ ++ bssinf_len = pnetwork->network.IELength+sizeof (struct rtw_ieee80211_hdr_3addr); ++ if(bssinf_len > MAX_BSSINFO_LEN){ ++ DBG_871X("%s IE Length too long > %d byte \n",__FUNCTION__,MAX_BSSINFO_LEN); ++ goto exit; ++ } ++ ++ //To reduce PBC Overlap rate ++ //_enter_critical_bh(&pwdev_priv->scan_req_lock, &irqL); ++ if(wdev_to_priv(wdev)->scan_request != NULL) ++ { ++ u8 *psr=NULL, sr = 0; ++ NDIS_802_11_SSID *pssid = &pnetwork->network.Ssid; ++ struct cfg80211_scan_request *request = wdev_to_priv(wdev)->scan_request; ++ struct cfg80211_ssid *ssids = request->ssids; ++ u32 wpsielen=0; ++ u8 *wpsie=NULL; ++ ++ wpsie = rtw_get_wps_ie(pnetwork->network.IEs+_FIXED_IE_LENGTH_, pnetwork->network.IELength-_FIXED_IE_LENGTH_, NULL, &wpsielen); ++ ++ if(wpsie && wpsielen>0) ++ psr = rtw_get_wps_attr_content(wpsie, wpsielen, WPS_ATTR_SELECTED_REGISTRAR, (u8*)(&sr), NULL); ++ ++ if (sr != 0) ++ { ++ if(request->n_ssids == 1 && request->n_channels == 1) // it means under processing WPS ++ { ++ DBG_8192C("ssid=%s, len=%d\n", pssid->Ssid, pssid->SsidLength); ++ ++ if (ssids[0].ssid_len == 0) { ++ } ++ else if(pssid->SsidLength == ssids[0].ssid_len && ++ _rtw_memcmp(pssid->Ssid, ssids[0].ssid, ssids[0].ssid_len)) ++ { ++ DBG_871X("%s, got sr and ssid match!\n", __func__); ++ } ++ else ++ { ++ if(psr !=NULL) ++ *psr = 0; //clear sr ++ ++#if 0 ++ WLAN_BSSID_EX *pselect_network = &pnetwork->network; ++ struct cfg80211_bss *pselect_bss = NULL; ++ struct ieee80211_channel *notify_channel = NULL; ++ u32 freq; ++ ++ DBG_871X("%s, got sr, but ssid mismatch, to remove this bss\n", __func__); ++ ++ if (pselect_network->Configuration.DSConfig <= RTW_CH_MAX_2G_CHANNEL) ++ freq = rtw_ieee80211_channel_to_frequency(pselect_network->Configuration.DSConfig, IEEE80211_BAND_2GHZ); ++ else ++ freq = rtw_ieee80211_channel_to_frequency(pselect_network->Configuration.DSConfig, IEEE80211_BAND_5GHZ); ++ ++ notify_channel = ieee80211_get_channel(wiphy, freq); ++ pselect_bss = cfg80211_get_bss(wiphy, NULL/*notify_channel*/, ++ pselect_network->MacAddress, pselect_network->Ssid.Ssid, ++ pselect_network->Ssid.SsidLength, 0/*WLAN_CAPABILITY_ESS*/, ++ 0/*WLAN_CAPABILITY_ESS*/); ++ ++ if(pselect_bss) ++ { ++ DBG_871X("%s, got bss for cfg80211 for unlinking bss\n", __func__); ++ ++ cfg80211_unlink_bss(wiphy, pselect_bss); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) ++ cfg80211_put_bss(wiphy, pselect_bss); ++#else ++ cfg80211_put_bss(pselect_bss); ++#endif ++ ++ } ++ ++ goto exit; ++#endif ++ } ++ } ++ } ++ } ++ //_exit_critical_bh(&pwdev_priv->scan_req_lock, &irqL); ++ ++ channel = pnetwork->network.Configuration.DSConfig; ++ if (channel <= RTW_CH_MAX_2G_CHANNEL) ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); ++ else ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); ++ ++ notify_channel = ieee80211_get_channel(wiphy, freq); ++ ++ //rtw_get_timestampe_from_ie() ++ notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */ ++ ++ notify_interval = le16_to_cpu(*(u16*)rtw_get_beacon_interval_from_ie(pnetwork->network.IEs)); ++ notify_capability = le16_to_cpu(*(u16*)rtw_get_capability_from_ie(pnetwork->network.IEs)); ++ ++ ++ notify_ie = pnetwork->network.IEs+_FIXED_IE_LENGTH_; ++ notify_ielen = pnetwork->network.IELength-_FIXED_IE_LENGTH_; ++ ++ //We've set wiphy's signal_type as CFG80211_SIGNAL_TYPE_MBM: signal strength in mBm (100*dBm) ++ if ( check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE && ++ is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network, 0)) { ++ notify_signal = 100*translate_percentage_to_dbm(padapter->recvpriv.signal_strength);//dbm ++ } else { ++ notify_signal = 100*translate_percentage_to_dbm(pnetwork->network.PhyInfo.SignalStrength);//dbm ++ } ++ ++ #if 0 ++ DBG_8192C("bssid: "MAC_FMT"\n", MAC_ARG(pnetwork->network.MacAddress)); ++ DBG_8192C("Channel: %d(%d)\n", channel, freq); ++ DBG_8192C("Capability: %X\n", notify_capability); ++ DBG_8192C("Beacon interval: %d\n", notify_interval); ++ DBG_8192C("Signal: %d\n", notify_signal); ++ DBG_8192C("notify_timestamp: %#018llx\n", notify_timestamp); ++ #endif ++ ++ pbuf = buf; ++ ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pbuf; ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); ++ //pmlmeext->mgnt_seq++; ++ ++ if (pnetwork->network.Reserved[0] == 1) { // WIFI_BEACON ++ _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); ++ SetFrameSubType(pbuf, WIFI_BEACON); ++ } else { ++ _rtw_memcpy(pwlanhdr->addr1, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ SetFrameSubType(pbuf, WIFI_PROBERSP); ++ } ++ ++ _rtw_memcpy(pwlanhdr->addr2, pnetwork->network.MacAddress, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, pnetwork->network.MacAddress, ETH_ALEN); ++ ++ ++ pbuf += sizeof(struct rtw_ieee80211_hdr_3addr); ++ len = sizeof (struct rtw_ieee80211_hdr_3addr); ++ ++ _rtw_memcpy(pbuf, pnetwork->network.IEs, pnetwork->network.IELength); ++ len += pnetwork->network.IELength; ++ ++ //#ifdef CONFIG_P2P ++ //if(rtw_get_p2p_ie(pnetwork->network.IEs+12, pnetwork->network.IELength-12, NULL, NULL)) ++ //{ ++ // DBG_8192C("%s, got p2p_ie\n", __func__); ++ //} ++ //#endif ++ ++ ++#if 1 ++ bss = cfg80211_inform_bss_frame(wiphy, notify_channel, (struct ieee80211_mgmt *)buf, ++ len, notify_signal, GFP_ATOMIC); ++#else ++ ++ bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)pnetwork->network.MacAddress, ++ notify_timestamp, notify_capability, notify_interval, notify_ie, ++ notify_ielen, notify_signal, GFP_ATOMIC/*GFP_KERNEL*/); ++#endif ++ ++ if (unlikely(!bss)) { ++ DBG_8192C(FUNC_ADPT_FMT" bss NULL\n", FUNC_ADPT_ARG(padapter)); ++ goto exit; ++ } ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)) ++#ifndef COMPAT_KERNEL_RELEASE ++ //patch for cfg80211, update beacon ies to information_elements ++ if (pnetwork->network.Reserved[0] == 1) { // WIFI_BEACON ++ ++ if(bss->len_information_elements != bss->len_beacon_ies) ++ { ++ bss->information_elements = bss->beacon_ies; ++ bss->len_information_elements = bss->len_beacon_ies; ++ } ++ } ++#endif //COMPAT_KERNEL_RELEASE ++#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) ++ ++/* ++ { ++ if( bss->information_elements == bss->proberesp_ies) ++ { ++ if( bss->len_information_elements != bss->len_proberesp_ies) ++ { ++ DBG_8192C("error!, len_information_elements != bss->len_proberesp_ies\n"); ++ } ++ ++ } ++ else if(bss->len_information_elements < bss->len_beacon_ies) ++ { ++ bss->information_elements = bss->beacon_ies; ++ bss->len_information_elements = bss->len_beacon_ies; ++ } ++ } ++*/ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) ++ cfg80211_put_bss(wiphy, bss); ++#else ++ cfg80211_put_bss(bss); ++#endif ++ ++exit: ++ return bss; ++ ++} ++ ++/* ++ Check the given bss is valid by kernel API cfg80211_get_bss() ++ @padapter : the given adapter ++ ++ return _TRUE if bss is valid, _FALSE for not found. ++*/ ++int rtw_cfg80211_check_bss(_adapter *padapter) ++{ ++ WLAN_BSSID_EX *pnetwork = &(padapter->mlmeextpriv.mlmext_info.network); ++ struct cfg80211_bss *bss = NULL; ++ struct ieee80211_channel *notify_channel = NULL; ++ u32 freq; ++ ++ if (!(pnetwork) || !(padapter->rtw_wdev)) ++ return _FALSE; ++ ++ if (pnetwork->Configuration.DSConfig <= RTW_CH_MAX_2G_CHANNEL) ++ freq = rtw_ieee80211_channel_to_frequency(pnetwork->Configuration.DSConfig, IEEE80211_BAND_2GHZ); ++ else ++ freq = rtw_ieee80211_channel_to_frequency(pnetwork->Configuration.DSConfig, IEEE80211_BAND_5GHZ); ++ ++ notify_channel = ieee80211_get_channel(padapter->rtw_wdev->wiphy, freq); ++ bss = cfg80211_get_bss(padapter->rtw_wdev->wiphy, notify_channel, ++ pnetwork->MacAddress, pnetwork->Ssid.Ssid, ++ pnetwork->Ssid.SsidLength, ++ WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); ++ ++ return (bss!=NULL); ++} ++ ++void rtw_cfg80211_ibss_indicate_connect(_adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *cur_network = &(pmlmepriv->cur_network); ++ struct wireless_dev *pwdev = padapter->rtw_wdev; ++ struct cfg80211_bss *bss = NULL; ++ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++ if (pwdev->iftype != NL80211_IFTYPE_ADHOC) ++ { ++ return; ++ } ++ ++ if (!rtw_cfg80211_check_bss(padapter)) { ++ WLAN_BSSID_EX *pnetwork = &(padapter->mlmeextpriv.mlmext_info.network); ++ struct wlan_network *scanned = pmlmepriv->cur_network_scanned; ++ ++ if(check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)==_TRUE) ++ { ++ ++ _rtw_memcpy(&cur_network->network, pnetwork, sizeof(WLAN_BSSID_EX)); ++ if(cur_network) ++ { ++ if (!rtw_cfg80211_inform_bss(padapter,cur_network)) ++ DBG_871X(FUNC_ADPT_FMT" inform fail !!\n", FUNC_ADPT_ARG(padapter)); ++ else ++ DBG_871X(FUNC_ADPT_FMT" inform success !!\n", FUNC_ADPT_ARG(padapter)); ++ } ++ else ++ { ++ DBG_871X("cur_network is not exist!!!\n"); ++ return ; ++ } ++ } ++ else ++ { ++ if(scanned == NULL) ++ rtw_warn_on(1); ++ ++ if (_rtw_memcmp(&(scanned->network.Ssid), &(pnetwork->Ssid), sizeof(NDIS_802_11_SSID)) == _TRUE ++ && _rtw_memcmp(scanned->network.MacAddress, pnetwork->MacAddress, sizeof(NDIS_802_11_MAC_ADDRESS)) == _TRUE ++ ) { ++ if (!rtw_cfg80211_inform_bss(padapter,scanned)) { ++ DBG_871X(FUNC_ADPT_FMT" inform fail !!\n", FUNC_ADPT_ARG(padapter)); ++ } else { ++ //DBG_871X(FUNC_ADPT_FMT" inform success !!\n", FUNC_ADPT_ARG(padapter)); ++ } ++ } else { ++ DBG_871X("scanned & pnetwork compare fail\n"); ++ rtw_warn_on(1); ++ } ++ } ++ ++ if (!rtw_cfg80211_check_bss(padapter)) ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" BSS not found !!\n", FUNC_ADPT_ARG(padapter)); ++ } ++ //notify cfg80211 that device joined an IBSS ++ cfg80211_ibss_joined(padapter->pnetdev, cur_network->network.MacAddress, GFP_ATOMIC); ++} ++ ++void rtw_cfg80211_indicate_connect(_adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *cur_network = &(pmlmepriv->cur_network); ++ struct wireless_dev *pwdev = padapter->rtw_wdev; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++#endif ++ struct cfg80211_bss *bss = NULL; ++ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++ if (pwdev->iftype != NL80211_IFTYPE_STATION ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++ && pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT ++ #endif ++ ) { ++ return; ++ } ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ return; ++ ++#ifdef CONFIG_P2P ++ if(pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ { ++ if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ DBG_8192C("%s, role=%d, p2p_state=%d, pre_p2p_state=%d\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo), rtw_p2p_pre_state(pwdinfo)); ++ } ++ } ++#endif //CONFIG_P2P ++ ++ { ++ WLAN_BSSID_EX *pnetwork = &(padapter->mlmeextpriv.mlmext_info.network); ++ struct wlan_network *scanned = pmlmepriv->cur_network_scanned; ++ ++ //DBG_871X(FUNC_ADPT_FMT" BSS not found\n", FUNC_ADPT_ARG(padapter)); ++ ++ if(scanned == NULL) { ++ rtw_warn_on(1); ++ goto check_bss; ++ } ++ ++ if (_rtw_memcmp(scanned->network.MacAddress, pnetwork->MacAddress, sizeof(NDIS_802_11_MAC_ADDRESS)) == _TRUE ++ && _rtw_memcmp(&(scanned->network.Ssid), &(pnetwork->Ssid), sizeof(NDIS_802_11_SSID)) == _TRUE ++ ) { ++ if (!rtw_cfg80211_inform_bss(padapter,scanned)) { ++ DBG_871X(FUNC_ADPT_FMT" inform fail !!\n", FUNC_ADPT_ARG(padapter)); ++ } else { ++ //DBG_871X(FUNC_ADPT_FMT" inform success !!\n", FUNC_ADPT_ARG(padapter)); ++ } ++ } else { ++ DBG_871X("scanned: %s("MAC_FMT"), cur: %s("MAC_FMT")\n", ++ scanned->network.Ssid.Ssid, MAC_ARG(scanned->network.MacAddress), ++ pnetwork->Ssid.Ssid, MAC_ARG(pnetwork->MacAddress) ++ ); ++ rtw_warn_on(1); ++ } ++ } ++ ++check_bss: ++ if (!rtw_cfg80211_check_bss(padapter)) ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" BSS not found !!\n", FUNC_ADPT_ARG(padapter)); ++ ++ #ifdef CONFIG_LAYER2_ROAMING ++ if (rtw_to_roaming(padapter) > 0) { ++ #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) || defined(COMPAT_KERNEL_RELEASE) ++ struct wiphy *wiphy = pwdev->wiphy; ++ struct ieee80211_channel *notify_channel; ++ u32 freq; ++ u16 channel = cur_network->network.Configuration.DSConfig; ++ ++ if (channel <= RTW_CH_MAX_2G_CHANNEL) ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); ++ else ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); ++ ++ notify_channel = ieee80211_get_channel(wiphy, freq); ++ #endif ++ ++ DBG_871X(FUNC_ADPT_FMT" call cfg80211_roamed\n", FUNC_ADPT_ARG(padapter)); ++ cfg80211_roamed(padapter->pnetdev ++ #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) || defined(COMPAT_KERNEL_RELEASE) ++ , notify_channel ++ #endif ++ , cur_network->network.MacAddress ++ , pmlmepriv->assoc_req+sizeof(struct rtw_ieee80211_hdr_3addr)+2 ++ , pmlmepriv->assoc_req_len-sizeof(struct rtw_ieee80211_hdr_3addr)-2 ++ , pmlmepriv->assoc_rsp+sizeof(struct rtw_ieee80211_hdr_3addr)+6 ++ , pmlmepriv->assoc_rsp_len-sizeof(struct rtw_ieee80211_hdr_3addr)-6 ++ , GFP_ATOMIC); ++ } ++ else ++ #endif ++ { ++ DBG_8192C("pwdev->sme_state(b)=%d\n", pwdev->sme_state); ++ cfg80211_connect_result(padapter->pnetdev, cur_network->network.MacAddress ++ , pmlmepriv->assoc_req+sizeof(struct rtw_ieee80211_hdr_3addr)+2 ++ , pmlmepriv->assoc_req_len-sizeof(struct rtw_ieee80211_hdr_3addr)-2 ++ , pmlmepriv->assoc_rsp+sizeof(struct rtw_ieee80211_hdr_3addr)+6 ++ , pmlmepriv->assoc_rsp_len-sizeof(struct rtw_ieee80211_hdr_3addr)-6 ++ , WLAN_STATUS_SUCCESS, GFP_ATOMIC); ++ DBG_8192C("pwdev->sme_state(a)=%d\n", pwdev->sme_state); ++ } ++} ++ ++void rtw_cfg80211_indicate_disconnect(_adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wireless_dev *pwdev = padapter->rtw_wdev; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++#endif ++ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++ ++ if (pwdev->iftype != NL80211_IFTYPE_STATION ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++ && pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT ++ #endif ++ ) { ++ return; ++ } ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ return; ++ ++#ifdef CONFIG_P2P ++ if( pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ { ++ if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ ++ DBG_8192C("%s, role=%d, p2p_state=%d, pre_p2p_state=%d\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo), rtw_p2p_pre_state(pwdinfo)); ++ } ++ } ++#endif //CONFIG_P2P ++ ++ if (!padapter->mlmepriv.not_indic_disco) { ++ DBG_8192C("pwdev->sme_state(b)=%d\n", pwdev->sme_state); ++ ++ if(pwdev->sme_state==CFG80211_SME_CONNECTING) ++ cfg80211_connect_result(padapter->pnetdev, NULL, NULL, 0, NULL, 0, ++ WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_ATOMIC/*GFP_KERNEL*/); ++ else if(pwdev->sme_state==CFG80211_SME_CONNECTED) ++ cfg80211_disconnected(padapter->pnetdev, 0, NULL, 0, GFP_ATOMIC); ++ //else ++ //DBG_8192C("pwdev->sme_state=%d\n", pwdev->sme_state); ++ ++ DBG_8192C("pwdev->sme_state(a)=%d\n", pwdev->sme_state); ++ } ++} ++ ++ ++#ifdef CONFIG_AP_MODE ++static u8 set_pairwise_key(_adapter *padapter, struct sta_info *psta) ++{ ++ struct cmd_obj* ph2c; ++ struct set_stakey_parm *psetstakey_para; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ u8 res=_SUCCESS; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if ( ph2c == NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ psetstakey_para = (struct set_stakey_parm*)rtw_zmalloc(sizeof(struct set_stakey_parm)); ++ if(psetstakey_para==NULL){ ++ rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); ++ res=_FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); ++ ++ ++ psetstakey_para->algorithm = (u8)psta->dot118021XPrivacy; ++ ++ _rtw_memcpy(psetstakey_para->addr, psta->hwaddr, ETH_ALEN); ++ ++ _rtw_memcpy(psetstakey_para->key, &psta->dot118021x_UncstKey, 16); ++ ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ return res; ++ ++} ++ ++static int set_group_key(_adapter *padapter, u8 *key, u8 alg, int keyid) ++{ ++ u8 keylen; ++ struct cmd_obj* pcmd; ++ struct setkey_parm *psetkeyparm; ++ struct cmd_priv *pcmdpriv=&(padapter->cmdpriv); ++ int res=_SUCCESS; ++ ++ DBG_8192C("%s\n", __FUNCTION__); ++ ++ pcmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(pcmd==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ psetkeyparm=(struct setkey_parm*)rtw_zmalloc(sizeof(struct setkey_parm)); ++ if(psetkeyparm==NULL){ ++ rtw_mfree((unsigned char *)pcmd, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ _rtw_memset(psetkeyparm, 0, sizeof(struct setkey_parm)); ++ ++ psetkeyparm->keyid=(u8)keyid; ++ if (is_wep_enc(alg)) ++ padapter->securitypriv.key_mask |= BIT(psetkeyparm->keyid); ++ ++ psetkeyparm->algorithm = alg; ++ ++ psetkeyparm->set_tx = 1; ++ ++ switch(alg) ++ { ++ case _WEP40_: ++ keylen = 5; ++ break; ++ case _WEP104_: ++ keylen = 13; ++ break; ++ case _TKIP_: ++ case _TKIP_WTMIC_: ++ case _AES_: ++ keylen = 16; ++ default: ++ keylen = 16; ++ } ++ ++ _rtw_memcpy(&(psetkeyparm->key[0]), key, keylen); ++ ++ pcmd->cmdcode = _SetKey_CMD_; ++ pcmd->parmbuf = (u8 *)psetkeyparm; ++ pcmd->cmdsz = (sizeof(struct setkey_parm)); ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ ++ ++ _rtw_init_listhead(&pcmd->list); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++ ++exit: ++ ++ return res; ++ ++ ++} ++ ++static int set_wep_key(_adapter *padapter, u8 *key, u8 keylen, int keyid) ++{ ++ u8 alg; ++ ++ switch(keylen) ++ { ++ case 5: ++ alg =_WEP40_; ++ break; ++ case 13: ++ alg =_WEP104_; ++ break; ++ default: ++ alg =_NO_PRIVACY_; ++ } ++ ++ return set_group_key(padapter, key, alg, keyid); ++ ++} ++ ++static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len) ++{ ++ int ret = 0; ++ u32 wep_key_idx, wep_key_len,wep_total_len; ++ struct sta_info *psta = NULL, *pbcmc_sta = NULL; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv* psecuritypriv=&(padapter->securitypriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_8192C("%s\n", __FUNCTION__); ++ ++ param->u.crypt.err = 0; ++ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; ++ ++ //sizeof(struct ieee_param) = 64 bytes; ++ //if (param_len != (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) ++ if (param_len != sizeof(struct ieee_param) + param->u.crypt.key_len) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && ++ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && ++ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) ++ { ++ if (param->u.crypt.idx >= WEP_KEYS) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } ++ else ++ { ++ psta = rtw_get_stainfo(pstapriv, param->sta_addr); ++ if(!psta) ++ { ++ //ret = -EINVAL; ++ DBG_8192C("rtw_set_encryption(), sta has already been removed or never been added\n"); ++ goto exit; ++ } ++ } ++ ++ if (strcmp(param->u.crypt.alg, "none") == 0 && (psta==NULL)) ++ { ++ //todo:clear default encryption keys ++ ++ DBG_8192C("clear default encryption keys, keyid=%d\n", param->u.crypt.idx); ++ ++ goto exit; ++ } ++ ++ ++ if (strcmp(param->u.crypt.alg, "WEP") == 0 && (psta==NULL)) ++ { ++ DBG_8192C("r871x_set_encryption, crypt.alg = WEP\n"); ++ ++ wep_key_idx = param->u.crypt.idx; ++ wep_key_len = param->u.crypt.key_len; ++ ++ DBG_8192C("r871x_set_encryption, wep_key_idx=%d, len=%d\n", wep_key_idx, wep_key_len); ++ ++ if((wep_key_idx >= WEP_KEYS) || (wep_key_len<=0)) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (wep_key_len > 0) ++ { ++ wep_key_len = wep_key_len <= 5 ? 5 : 13; ++ } ++ ++ if (psecuritypriv->bWepDefaultKeyIdxSet == 0) ++ { ++ //wep default key has not been set, so use this key index as default key. ++ ++ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ psecuritypriv->dot11PrivacyAlgrthm=_WEP40_; ++ psecuritypriv->dot118021XGrpPrivacy=_WEP40_; ++ ++ if(wep_key_len == 13) ++ { ++ psecuritypriv->dot11PrivacyAlgrthm=_WEP104_; ++ psecuritypriv->dot118021XGrpPrivacy=_WEP104_; ++ } ++ ++ psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx; ++ } ++ ++ _rtw_memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), param->u.crypt.key, wep_key_len); ++ ++ psecuritypriv->dot11DefKeylen[wep_key_idx] = wep_key_len; ++ ++ set_wep_key(padapter, param->u.crypt.key, wep_key_len, wep_key_idx); ++ ++ goto exit; ++ ++ } ++ ++ ++ if(!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) // //group key ++ { ++ if(param->u.crypt.set_tx == 0) //group key ++ { ++ if(strcmp(param->u.crypt.alg, "WEP") == 0) ++ { ++ DBG_8192C("%s, set group_key, WEP\n", __FUNCTION__); ++ ++ _rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _WEP40_; ++ if(param->u.crypt.key_len==13) ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _WEP104_; ++ } ++ ++ } ++ else if(strcmp(param->u.crypt.alg, "TKIP") == 0) ++ { ++ DBG_8192C("%s, set group_key, TKIP\n", __FUNCTION__); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _TKIP_; ++ ++ _rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ //DEBUG_ERR("set key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len); ++ //set mic key ++ _rtw_memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8); ++ _rtw_memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8); ++ ++ psecuritypriv->busetkipkey = _TRUE; ++ ++ } ++ else if(strcmp(param->u.crypt.alg, "CCMP") == 0) ++ { ++ DBG_8192C("%s, set group_key, CCMP\n", __FUNCTION__); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _AES_; ++ ++ _rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ } ++ else ++ { ++ DBG_8192C("%s, set group_key, none\n", __FUNCTION__); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ } ++ ++ psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx; ++ ++ psecuritypriv->binstallGrpkey = _TRUE; ++ ++ psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;//!!! ++ ++ set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx); ++ ++ pbcmc_sta=rtw_get_bcmc_stainfo(padapter); ++ if(pbcmc_sta) ++ { ++ pbcmc_sta->ieee8021x_blocked = _FALSE; ++ pbcmc_sta->dot118021XPrivacy= psecuritypriv->dot118021XGrpPrivacy;//rx will use bmc_sta's dot118021XPrivacy ++ } ++ ++ } ++ ++ goto exit; ++ ++ } ++ ++ if(psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) // psk/802_1x ++ { ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ { ++ if(param->u.crypt.set_tx ==1) //pairwise key ++ { ++ _rtw_memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ if(strcmp(param->u.crypt.alg, "WEP") == 0) ++ { ++ DBG_8192C("%s, set pairwise key, WEP\n", __FUNCTION__); ++ ++ psta->dot118021XPrivacy = _WEP40_; ++ if(param->u.crypt.key_len==13) ++ { ++ psta->dot118021XPrivacy = _WEP104_; ++ } ++ } ++ else if(strcmp(param->u.crypt.alg, "TKIP") == 0) ++ { ++ DBG_8192C("%s, set pairwise key, TKIP\n", __FUNCTION__); ++ ++ psta->dot118021XPrivacy = _TKIP_; ++ ++ //DEBUG_ERR("set key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len); ++ //set mic key ++ _rtw_memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8); ++ _rtw_memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8); ++ ++ psecuritypriv->busetkipkey = _TRUE; ++ ++ } ++ else if(strcmp(param->u.crypt.alg, "CCMP") == 0) ++ { ++ ++ DBG_8192C("%s, set pairwise key, CCMP\n", __FUNCTION__); ++ ++ psta->dot118021XPrivacy = _AES_; ++ } ++ else ++ { ++ DBG_8192C("%s, set pairwise key, none\n", __FUNCTION__); ++ ++ psta->dot118021XPrivacy = _NO_PRIVACY_; ++ } ++ ++ set_pairwise_key(padapter, psta); ++ ++ psta->ieee8021x_blocked = _FALSE; ++ ++ psta->bpairwise_key_installed = _TRUE; ++ ++ } ++ else//group key??? ++ { ++ if(strcmp(param->u.crypt.alg, "WEP") == 0) ++ { ++ _rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _WEP40_; ++ if(param->u.crypt.key_len==13) ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _WEP104_; ++ } ++ } ++ else if(strcmp(param->u.crypt.alg, "TKIP") == 0) ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _TKIP_; ++ ++ _rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ //DEBUG_ERR("set key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len); ++ //set mic key ++ _rtw_memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8); ++ _rtw_memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8); ++ ++ psecuritypriv->busetkipkey = _TRUE; ++ ++ } ++ else if(strcmp(param->u.crypt.alg, "CCMP") == 0) ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _AES_; ++ ++ _rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ } ++ else ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ } ++ ++ psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx; ++ ++ psecuritypriv->binstallGrpkey = _TRUE; ++ ++ psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;//!!! ++ ++ set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx); ++ ++ pbcmc_sta=rtw_get_bcmc_stainfo(padapter); ++ if(pbcmc_sta) ++ { ++ pbcmc_sta->ieee8021x_blocked = _FALSE; ++ pbcmc_sta->dot118021XPrivacy= psecuritypriv->dot118021XGrpPrivacy;//rx will use bmc_sta's dot118021XPrivacy ++ } ++ ++ } ++ ++ } ++ ++ } ++ ++exit: ++ ++ return ret; ++ ++} ++#endif ++ ++static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len) ++{ ++ int ret = 0; ++ u32 wep_key_idx, wep_key_len,wep_total_len; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++#ifdef CONFIG_P2P ++ struct wifidirect_info* pwdinfo = &padapter->wdinfo; ++#endif //CONFIG_P2P ++ ++_func_enter_; ++ ++ DBG_8192C("%s\n", __func__); ++ ++ param->u.crypt.err = 0; ++ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; ++ ++ if (param_len < (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && ++ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && ++ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) ++ { ++ if (param->u.crypt.idx >= WEP_KEYS ++#ifdef CONFIG_IEEE80211W ++ && param->u.crypt.idx > BIP_MAX_KEYID ++#endif //CONFIG_IEEE80211W ++ ) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } else { ++#ifdef CONFIG_WAPI_SUPPORT ++ if (strcmp(param->u.crypt.alg, "SMS4")) ++#endif ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } ++ ++ if (strcmp(param->u.crypt.alg, "WEP") == 0) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_os_c,_drv_err_,("wpa_set_encryption, crypt.alg = WEP\n")); ++ DBG_8192C("wpa_set_encryption, crypt.alg = WEP\n"); ++ ++ wep_key_idx = param->u.crypt.idx; ++ wep_key_len = param->u.crypt.key_len; ++ ++ if ((wep_key_idx > WEP_KEYS) || (wep_key_len <= 0)) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (psecuritypriv->bWepDefaultKeyIdxSet == 0) ++ { ++ //wep default key has not been set, so use this key index as default key. ++ ++ wep_key_len = wep_key_len <= 5 ? 5 : 13; ++ ++ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; ++ psecuritypriv->dot118021XGrpPrivacy = _WEP40_; ++ ++ if(wep_key_len==13) ++ { ++ psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; ++ psecuritypriv->dot118021XGrpPrivacy = _WEP104_; ++ } ++ ++ psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx; ++ } ++ ++ _rtw_memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), param->u.crypt.key, wep_key_len); ++ ++ psecuritypriv->dot11DefKeylen[wep_key_idx] = wep_key_len; ++ ++ rtw_set_key(padapter, psecuritypriv, wep_key_idx, 0,_TRUE); ++ ++ goto exit; ++ } ++ ++ if(padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) // 802_1x ++ { ++ struct sta_info * psta,*pbcmc_sta; ++ struct sta_priv * pstapriv = &padapter->stapriv; ++ ++ //DBG_8192C("%s, : dot11AuthAlgrthm == dot11AuthAlgrthm_8021X \n", __func__); ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE) == _TRUE) //sta mode ++ { ++ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); ++ if (psta == NULL) { ++ //DEBUG_ERR( ("Set wpa_set_encryption: Obtain Sta_info fail \n")); ++ DBG_8192C("%s, : Obtain Sta_info fail \n", __func__); ++ } ++ else ++ { ++ //Jeff: don't disable ieee8021x_blocked while clearing key ++ if (strcmp(param->u.crypt.alg, "none") != 0) ++ psta->ieee8021x_blocked = _FALSE; ++ ++ ++ if((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled)|| ++ (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) ++ { ++ psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; ++ } ++ ++ if(param->u.crypt.set_tx ==1)//pairwise key ++ { ++ ++ DBG_8192C("%s, : param->u.crypt.set_tx ==1 \n", __func__); ++ ++ _rtw_memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ if(strcmp(param->u.crypt.alg, "TKIP") == 0)//set mic key ++ { ++ //DEBUG_ERR(("\nset key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len)); ++ _rtw_memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8); ++ _rtw_memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8); ++ ++ padapter->securitypriv.busetkipkey=_FALSE; ++ //_set_timer(&padapter->securitypriv.tkip_timer, 50); ++ } ++ ++ //DEBUG_ERR((" param->u.crypt.key_len=%d\n",param->u.crypt.key_len)); ++ DBG_871X(" ~~~~set sta key:unicastkey\n"); ++ ++ rtw_setstakey_cmd(padapter, (unsigned char *)psta, _TRUE, _TRUE); ++ } ++ else//group key ++ { ++ if(strcmp(param->u.crypt.alg, "TKIP") == 0 || strcmp(param->u.crypt.alg, "CCMP") == 0) ++ { ++ _rtw_memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key,(param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ _rtw_memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey,&(param->u.crypt.key[16]),8); ++ _rtw_memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey,&(param->u.crypt.key[24]),8); ++ padapter->securitypriv.binstallGrpkey = _TRUE; ++ //DEBUG_ERR((" param->u.crypt.key_len=%d\n", param->u.crypt.key_len)); ++ DBG_871X(" ~~~~set sta key:groupkey\n"); ++ ++ padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx; ++#ifdef CONFIG_CONCURRENT_MODE ++ if (padapter->adapter_type == PRIMARY_ADAPTER) ++ rtw_set_key(padapter,&padapter->securitypriv,param->u.crypt.idx, 1,_TRUE); ++ else ++ DBG_871X_LEVEL(_drv_always_, "second interface do not set cam.\n"); ++#else ++ rtw_set_key(padapter,&padapter->securitypriv,param->u.crypt.idx, 1,_TRUE); ++#endif ++ } ++#ifdef CONFIG_IEEE80211W ++ else if(strcmp(param->u.crypt.alg, "BIP") == 0) ++ { ++ int no; ++ //DBG_871X("BIP key_len=%d , index=%d @@@@@@@@@@@@@@@@@@\n", param->u.crypt.key_len, param->u.crypt.idx); ++ //save the IGTK key, length 16 bytes ++ _rtw_memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey, param->u.crypt.key,(param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ /*DBG_871X("IGTK key below:\n"); ++ for(no=0;no<16;no++) ++ printk(" %02x ", padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey[no]); ++ DBG_871X("\n");*/ ++ padapter->securitypriv.dot11wBIPKeyid = param->u.crypt.idx; ++ padapter->securitypriv.binstallBIPkey = _TRUE; ++ DBG_871X(" ~~~~set sta key:IGKT\n"); ++ } ++#endif //CONFIG_IEEE80211W ++ ++#ifdef CONFIG_P2P ++ if(pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ { ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING)) ++ { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_PROVISIONING_DONE); ++ } ++ } ++#endif //CONFIG_P2P ++ ++ } ++ } ++ ++ pbcmc_sta=rtw_get_bcmc_stainfo(padapter); ++ if(pbcmc_sta==NULL) ++ { ++ //DEBUG_ERR( ("Set OID_802_11_ADD_KEY: bcmc stainfo is null \n")); ++ } ++ else ++ { ++ //Jeff: don't disable ieee8021x_blocked while clearing key ++ if (strcmp(param->u.crypt.alg, "none") != 0) ++ pbcmc_sta->ieee8021x_blocked = _FALSE; ++ ++ if((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled)|| ++ (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) ++ { ++ pbcmc_sta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; ++ } ++ } ++ } ++ else if(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) //adhoc mode ++ { ++ } ++ } ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ if (strcmp(param->u.crypt.alg, "SMS4") == 0) ++ { ++ PRT_WAPI_T pWapiInfo = &padapter->wapiInfo; ++ PRT_WAPI_STA_INFO pWapiSta; ++ u8 WapiASUEPNInitialValueSrc[16] = {0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ; ++ u8 WapiAEPNInitialValueSrc[16] = {0x37,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ; ++ u8 WapiAEMultiCastPNInitialValueSrc[16] = {0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ; ++ ++ if(param->u.crypt.set_tx == 1) ++ { ++ list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { ++ if(_rtw_memcmp(pWapiSta->PeerMacAddr,param->sta_addr,6)) ++ { ++ _rtw_memcpy(pWapiSta->lastTxUnicastPN,WapiASUEPNInitialValueSrc,16); ++ ++ pWapiSta->wapiUsk.bSet = true; ++ _rtw_memcpy(pWapiSta->wapiUsk.dataKey,param->u.crypt.key,16); ++ _rtw_memcpy(pWapiSta->wapiUsk.micKey,param->u.crypt.key+16,16); ++ pWapiSta->wapiUsk.keyId = param->u.crypt.idx ; ++ pWapiSta->wapiUsk.bTxEnable = true; ++ ++ _rtw_memcpy(pWapiSta->lastRxUnicastPNBEQueue,WapiAEPNInitialValueSrc,16); ++ _rtw_memcpy(pWapiSta->lastRxUnicastPNBKQueue,WapiAEPNInitialValueSrc,16); ++ _rtw_memcpy(pWapiSta->lastRxUnicastPNVIQueue,WapiAEPNInitialValueSrc,16); ++ _rtw_memcpy(pWapiSta->lastRxUnicastPNVOQueue,WapiAEPNInitialValueSrc,16); ++ _rtw_memcpy(pWapiSta->lastRxUnicastPN,WapiAEPNInitialValueSrc,16); ++ pWapiSta->wapiUskUpdate.bTxEnable = false; ++ pWapiSta->wapiUskUpdate.bSet = false; ++ ++ if (psecuritypriv->sw_encrypt== false || psecuritypriv->sw_decrypt == false) ++ { ++ //set unicast key for ASUE ++ rtw_wapi_set_key(padapter, &pWapiSta->wapiUsk, pWapiSta, false, false); ++ } ++ } ++ } ++ } ++ else ++ { ++ list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { ++ if(_rtw_memcmp(pWapiSta->PeerMacAddr,get_bssid(pmlmepriv),6)) ++ { ++ pWapiSta->wapiMsk.bSet = true; ++ _rtw_memcpy(pWapiSta->wapiMsk.dataKey,param->u.crypt.key,16); ++ _rtw_memcpy(pWapiSta->wapiMsk.micKey,param->u.crypt.key+16,16); ++ pWapiSta->wapiMsk.keyId = param->u.crypt.idx ; ++ pWapiSta->wapiMsk.bTxEnable = false; ++ if(!pWapiSta->bSetkeyOk) ++ pWapiSta->bSetkeyOk = true; ++ pWapiSta->bAuthenticateInProgress = false; ++ ++ _rtw_memcpy(pWapiSta->lastRxMulticastPN, WapiAEMultiCastPNInitialValueSrc, 16); ++ ++ if (psecuritypriv->sw_decrypt == false) ++ { ++ //set rx broadcast key for ASUE ++ rtw_wapi_set_key(padapter, &pWapiSta->wapiMsk, pWapiSta, true, false); ++ } ++ } ++ ++ } ++ } ++ } ++#endif ++ ++ ++exit: ++ ++ DBG_8192C("%s, ret=%d\n", __func__, ret); ++ ++ _func_exit_; ++ ++ return ret; ++} ++ ++static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct net_device *ndev, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++ u8 key_index, bool pairwise, const u8 *mac_addr, ++#else // (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ u8 key_index, const u8 *mac_addr, ++#endif // (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ struct key_params *params) ++{ ++ char *alg_name; ++ u32 param_len; ++ struct ieee_param *param = NULL; ++ int ret=0; ++ struct wireless_dev *rtw_wdev = wiphy_to_wdev(wiphy); ++ _adapter *padapter = wiphy_to_adapter(wiphy); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ DBG_871X(FUNC_NDEV_FMT" adding key for %pM\n", FUNC_NDEV_ARG(ndev), mac_addr); ++ DBG_871X("cipher=0x%x\n", params->cipher); ++ DBG_871X("key_len=0x%x\n", params->key_len); ++ DBG_871X("seq_len=0x%x\n", params->seq_len); ++ DBG_871X("key_index=%d\n", key_index); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++ DBG_871X("pairwise=%d\n", pairwise); ++#endif // (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ ++ param_len = sizeof(struct ieee_param) + params->key_len; ++ param = (struct ieee_param *)rtw_malloc(param_len); ++ if (param == NULL) ++ return -1; ++ ++ _rtw_memset(param, 0, param_len); ++ ++ param->cmd = IEEE_CMD_SET_ENCRYPTION; ++ _rtw_memset(param->sta_addr, 0xff, ETH_ALEN); ++ ++ switch (params->cipher) { ++ case IW_AUTH_CIPHER_NONE: ++ //todo: remove key ++ //remove = 1; ++ alg_name = "none"; ++ break; ++ case WLAN_CIPHER_SUITE_WEP40: ++ case WLAN_CIPHER_SUITE_WEP104: ++ alg_name = "WEP"; ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ alg_name = "TKIP"; ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ alg_name = "CCMP"; ++ break; ++#ifdef CONFIG_IEEE80211W ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ alg_name = "BIP"; ++ break; ++#endif //CONFIG_IEEE80211W ++#ifdef CONFIG_WAPI_SUPPORT ++ case WLAN_CIPHER_SUITE_SMS4: ++ alg_name= "SMS4"; ++ if(pairwise == NL80211_KEYTYPE_PAIRWISE) { ++ if (key_index != 0 && key_index != 1) { ++ ret = -ENOTSUPP; ++ goto addkey_end; ++ } ++ _rtw_memcpy((void*)param->sta_addr, (void*)mac_addr, ETH_ALEN); ++ } else { ++ DBG_871X("mac_addr is null \n"); ++ } ++ DBG_871X("rtw_wx_set_enc_ext: SMS4 case \n"); ++ break; ++#endif ++ ++ default: ++ ret = -ENOTSUPP; ++ goto addkey_end; ++ } ++ ++ strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN); ++ ++ ++ if (!mac_addr || is_broadcast_ether_addr(mac_addr)) ++ { ++ param->u.crypt.set_tx = 0; //for wpa/wpa2 group key ++ } else { ++ param->u.crypt.set_tx = 1; //for wpa/wpa2 pairwise key ++ } ++ ++ ++ //param->u.crypt.idx = key_index - 1; ++ param->u.crypt.idx = key_index; ++ ++ if (params->seq_len && params->seq) ++ { ++ _rtw_memcpy(param->u.crypt.seq, params->seq, params->seq_len); ++ } ++ ++ if(params->key_len && params->key) ++ { ++ param->u.crypt.key_len = params->key_len; ++ _rtw_memcpy(param->u.crypt.key, params->key, params->key_len); ++ } ++ ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) ++ { ++ ret = rtw_cfg80211_set_encryption(ndev, param, param_len); ++ } ++ else if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ { ++#ifdef CONFIG_AP_MODE ++ if(mac_addr) ++ _rtw_memcpy(param->sta_addr, (void*)mac_addr, ETH_ALEN); ++ ++ ret = rtw_cfg80211_ap_set_encryption(ndev, param, param_len); ++#endif ++ } ++ else ++ { ++ DBG_8192C("error! fw_state=0x%x, iftype=%d\n", pmlmepriv->fw_state, rtw_wdev->iftype); ++ ++ } ++ ++addkey_end: ++ if(param) ++ { ++ rtw_mfree((u8*)param, param_len); ++ } ++ ++ return ret; ++ ++} ++ ++static int cfg80211_rtw_get_key(struct wiphy *wiphy, struct net_device *ndev, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++ u8 key_index, bool pairwise, const u8 *mac_addr, ++#else // (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ u8 key_index, const u8 *mac_addr, ++#endif // (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ void *cookie, ++ void (*callback)(void *cookie, ++ struct key_params*)) ++{ ++#if 0 ++ struct iwm_priv *iwm = ndev_to_iwm(ndev); ++ struct iwm_key *key = &iwm->keys[key_index]; ++ struct key_params params; ++ ++ IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index); ++ ++ memset(¶ms, 0, sizeof(params)); ++ ++ params.cipher = key->cipher; ++ params.key_len = key->key_len; ++ params.seq_len = key->seq_len; ++ params.seq = key->seq; ++ params.key = key->key; ++ ++ callback(cookie, ¶ms); ++ ++ return key->key_len ? 0 : -ENOENT; ++#endif ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ return 0; ++} ++ ++static int cfg80211_rtw_del_key(struct wiphy *wiphy, struct net_device *ndev, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++ u8 key_index, bool pairwise, const u8 *mac_addr) ++#else // (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ u8 key_index, const u8 *mac_addr) ++#endif // (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ DBG_871X(FUNC_NDEV_FMT" key_index=%d\n", FUNC_NDEV_ARG(ndev), key_index); ++ ++ if (key_index == psecuritypriv->dot11PrivacyKeyIndex) ++ { ++ //clear the flag of wep default key set. ++ psecuritypriv->bWepDefaultKeyIdxSet = 0; ++ } ++ ++ return 0; ++} ++ ++static int cfg80211_rtw_set_default_key(struct wiphy *wiphy, ++ struct net_device *ndev, u8 key_index ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) || defined(COMPAT_KERNEL_RELEASE) ++ , bool unicast, bool multicast ++ #endif ++ ) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ DBG_871X(FUNC_NDEV_FMT" key_index=%d" ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) || defined(COMPAT_KERNEL_RELEASE) ++ ", unicast=%d, multicast=%d" ++ #endif ++ ".\n", FUNC_NDEV_ARG(ndev), key_index ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) || defined(COMPAT_KERNEL_RELEASE) ++ , unicast, multicast ++ #endif ++ ); ++ ++ if ((key_index < WEP_KEYS) && ((psecuritypriv->dot11PrivacyAlgrthm == _WEP40_) || (psecuritypriv->dot11PrivacyAlgrthm == _WEP104_))) //set wep default key ++ { ++ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ ++ psecuritypriv->dot11PrivacyKeyIndex = key_index; ++ ++ psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; ++ psecuritypriv->dot118021XGrpPrivacy = _WEP40_; ++ if (psecuritypriv->dot11DefKeylen[key_index] == 13) ++ { ++ psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; ++ psecuritypriv->dot118021XGrpPrivacy = _WEP104_; ++ } ++ ++ psecuritypriv->bWepDefaultKeyIdxSet = 1; //set the flag to represent that wep default key has been set ++ } ++ ++ return 0; ++ ++} ++ ++static int cfg80211_rtw_get_station(struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8 *mac, struct station_info *sinfo) ++{ ++ int ret = 0; ++ _adapter *padapter = wiphy_to_adapter(wiphy); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ sinfo->filled = 0; ++ ++ if (!mac) { ++ DBG_871X(FUNC_NDEV_FMT" mac==%p\n", FUNC_NDEV_ARG(ndev), mac); ++ ret = -ENOENT; ++ goto exit; ++ } ++ ++ psta = rtw_get_stainfo(pstapriv, mac); ++ if (psta == NULL) { ++ DBG_8192C("%s, sta_info is null\n", __func__); ++ ret = -ENOENT; ++ goto exit; ++ } ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X(FUNC_NDEV_FMT" mac="MAC_FMT"\n", FUNC_NDEV_ARG(ndev), MAC_ARG(mac)); ++#endif ++ ++ //for infra./P2PClient mode ++ if( check_fwstate(pmlmepriv, WIFI_STATION_STATE) ++ && check_fwstate(pmlmepriv, _FW_LINKED) ++ ) ++ { ++ struct wlan_network *cur_network = &(pmlmepriv->cur_network); ++ ++ if (_rtw_memcmp(mac, cur_network->network.MacAddress, ETH_ALEN) == _FALSE) { ++ DBG_871X("%s, mismatch bssid="MAC_FMT"\n", __func__, MAC_ARG(cur_network->network.MacAddress)); ++ ret = -ENOENT; ++ goto exit; ++ } ++ ++ sinfo->filled |= STATION_INFO_SIGNAL; ++ sinfo->signal = translate_percentage_to_dbm(padapter->recvpriv.signal_strength); ++ ++ sinfo->filled |= STATION_INFO_TX_BITRATE; ++ sinfo->txrate.legacy = rtw_get_cur_max_rate(padapter); ++ ++ sinfo->filled |= STATION_INFO_RX_PACKETS; ++ sinfo->rx_packets = sta_rx_data_pkts(psta); ++ ++ sinfo->filled |= STATION_INFO_TX_PACKETS; ++ sinfo->tx_packets = psta->sta_stats.tx_pkts; ++ ++ } ++ ++ //for Ad-Hoc/AP mode ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ++ ||check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ++ ||check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ && check_fwstate(pmlmepriv, _FW_LINKED) ++ ) ++ { ++ //TODO: should acquire station info... ++ } ++ ++exit: ++ return ret; ++} ++ ++extern int netdev_open(struct net_device *pnetdev); ++#ifdef CONFIG_CONCURRENT_MODE ++extern int netdev_if2_open(struct net_device *pnetdev); ++#endif ++ ++/* ++enum nl80211_iftype { ++ NL80211_IFTYPE_UNSPECIFIED, ++ NL80211_IFTYPE_ADHOC, //1 ++ NL80211_IFTYPE_STATION, //2 ++ NL80211_IFTYPE_AP, //3 ++ NL80211_IFTYPE_AP_VLAN, ++ NL80211_IFTYPE_WDS, ++ NL80211_IFTYPE_MONITOR, //6 ++ NL80211_IFTYPE_MESH_POINT, ++ NL80211_IFTYPE_P2P_CLIENT, //8 ++ NL80211_IFTYPE_P2P_GO, //9 ++ //keep last ++ NUM_NL80211_IFTYPES, ++ NL80211_IFTYPE_MAX = NUM_NL80211_IFTYPES - 1 ++}; ++*/ ++static int cfg80211_rtw_change_iface(struct wiphy *wiphy, ++ struct net_device *ndev, ++ enum nl80211_iftype type, u32 *flags, ++ struct vif_params *params) ++{ ++ enum nl80211_iftype old_type; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE networkType ; ++ _adapter *padapter = wiphy_to_adapter(wiphy); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct wireless_dev *rtw_wdev = wiphy_to_wdev(wiphy); ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++#endif ++ int ret = 0; ++ u8 change = _FALSE; ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ if(adapter_to_dvobj(padapter)->processing_dev_remove == _TRUE) ++ { ++ ret= -EPERM; ++ goto exit; ++ } ++ ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(padapter->adapter_type == SECONDARY_ADAPTER) ++ { ++ DBG_871X(FUNC_NDEV_FMT" call netdev_if2_open\n", FUNC_NDEV_ARG(ndev)); ++ if(netdev_if2_open(ndev) != 0) { ++ ret= -EPERM; ++ goto exit; ++ } ++ } ++ else if(padapter->adapter_type == PRIMARY_ADAPTER) ++#endif //CONFIG_CONCURRENT_MODE ++ { ++ DBG_871X(FUNC_NDEV_FMT" call netdev_open\n", FUNC_NDEV_ARG(ndev)); ++ if(netdev_open(ndev) != 0) { ++ ret= -EPERM; ++ goto exit; ++ } ++ } ++ ++ if(_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret= -EPERM; ++ goto exit; ++ } ++ ++ old_type = rtw_wdev->iftype; ++ DBG_871X(FUNC_NDEV_FMT" old_iftype=%d, new_iftype=%d\n", ++ FUNC_NDEV_ARG(ndev), old_type, type); ++ ++ if(old_type != type) ++ { ++ change = _TRUE; ++ pmlmeext->action_public_rxseq = 0xffff; ++ pmlmeext->action_public_dialog_token = 0xff; ++ } ++ ++ switch (type) { ++ case NL80211_IFTYPE_ADHOC: ++ networkType = Ndis802_11IBSS; ++ break; ++#if defined(CONFIG_P2P) && ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE)) ++ case NL80211_IFTYPE_P2P_CLIENT: ++#endif ++ case NL80211_IFTYPE_STATION: ++ networkType = Ndis802_11Infrastructure; ++ #ifdef CONFIG_P2P ++ if(pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ { ++ if(change && rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ { ++ //it means remove GO and change mode from AP(GO) to station(P2P DEVICE) ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); ++ ++ DBG_8192C("%s, role=%d, p2p_state=%d, pre_p2p_state=%d\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo), rtw_p2p_pre_state(pwdinfo)); ++ } ++ } ++ #endif //CONFIG_P2P ++ break; ++#if defined(CONFIG_P2P) && ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE)) ++ case NL80211_IFTYPE_P2P_GO: ++#endif ++ case NL80211_IFTYPE_AP: ++ networkType = Ndis802_11APMode; ++ #ifdef CONFIG_P2P ++ if(pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ { ++ if(change && !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ //it means P2P Group created, we will be GO and change mode from P2P DEVICE to AP(GO) ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ } ++ } ++ #endif //CONFIG_P2P ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ rtw_wdev->iftype = type; ++ ++ if (rtw_set_802_11_infrastructure_mode(padapter, networkType) ==_FALSE) ++ { ++ rtw_wdev->iftype = old_type; ++ ret = -EPERM; ++ goto exit; ++ } ++ ++ rtw_setopmode_cmd(padapter, networkType,_TRUE); ++ ++exit: ++ ++ return ret; ++} ++ ++void rtw_cfg80211_indicate_scan_done(struct rtw_wdev_priv *pwdev_priv, bool aborted) ++{ ++ _irqL irqL; ++ ++ _enter_critical_bh(&pwdev_priv->scan_req_lock, &irqL); ++ if(pwdev_priv->scan_request != NULL) ++ { ++ //struct cfg80211_scan_request *scan_request = pwdev_priv->scan_request; ++ ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X("%s with scan req\n", __FUNCTION__); ++ #endif ++ ++ //avoid WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); ++ //if(scan_request == wiphy_to_dev(scan_request->wiphy)->scan_req) ++ if(pwdev_priv->scan_request->wiphy != pwdev_priv->rtw_wdev->wiphy) ++ { ++ DBG_8192C("error wiphy compare\n"); ++ } ++ else ++ { ++ cfg80211_scan_done(pwdev_priv->scan_request, aborted); ++ } ++ ++ pwdev_priv->scan_request = NULL; ++ ++ } else { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X("%s without scan req\n", __FUNCTION__); ++ #endif ++ } ++ _exit_critical_bh(&pwdev_priv->scan_req_lock, &irqL); ++} ++ ++void rtw_cfg80211_surveydone_event_callback(_adapter *padapter) ++{ ++ _irqL irqL; ++ _list *plist, *phead; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ u32 cnt=0; ++ u32 wait_for_surveydone; ++ sint wait_status; ++#ifdef CONFIG_P2P ++ struct wifidirect_info* pwdinfo = &padapter->wdinfo; ++#endif //CONFIG_P2P ++ struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s\n", __func__); ++#endif ++ ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while(1) ++ { ++ if (rtw_end_of_queue_search(phead,plist)== _TRUE) ++ break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ //report network only if the current channel set contains the channel to which this network belongs ++ if(rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0 ++ && _TRUE == rtw_validate_ssid(&(pnetwork->network.Ssid)) ++ ) ++ { ++ //ev=translate_scan(padapter, a, pnetwork, ev, stop); ++ rtw_cfg80211_inform_bss(padapter, pnetwork); ++ } ++ ++ plist = get_next(plist); ++ ++ } ++ ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ //call this after other things have been done ++ rtw_cfg80211_indicate_scan_done(wdev_to_priv(padapter->rtw_wdev), _FALSE); ++} ++ ++static int rtw_cfg80211_set_probe_req_wpsp2pie(_adapter *padapter, char *buf, int len) ++{ ++ int ret = 0; ++ uint wps_ielen = 0; ++ u8 *wps_ie; ++ u32 p2p_ielen = 0; ++ u8 *p2p_ie; ++ u32 wfd_ielen = 0; ++ u8 *wfd_ie; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s, ielen=%d\n", __func__, len); ++#endif ++ ++ if(len>0) ++ { ++ if((wps_ie = rtw_get_wps_ie(buf, len, NULL, &wps_ielen))) ++ { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("probe_req_wps_ielen=%d\n", wps_ielen); ++ #endif ++ ++ if(pmlmepriv->wps_probe_req_ie) ++ { ++ u32 free_len = pmlmepriv->wps_probe_req_ie_len; ++ pmlmepriv->wps_probe_req_ie_len = 0; ++ rtw_mfree(pmlmepriv->wps_probe_req_ie, free_len); ++ pmlmepriv->wps_probe_req_ie = NULL; ++ } ++ ++ pmlmepriv->wps_probe_req_ie = rtw_malloc(wps_ielen); ++ if ( pmlmepriv->wps_probe_req_ie == NULL) { ++ DBG_8192C("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ return -EINVAL; ++ ++ } ++ _rtw_memcpy(pmlmepriv->wps_probe_req_ie, wps_ie, wps_ielen); ++ pmlmepriv->wps_probe_req_ie_len = wps_ielen; ++ } ++ ++ //buf += wps_ielen; ++ //len -= wps_ielen; ++ ++ #ifdef CONFIG_P2P ++ if((p2p_ie=rtw_get_p2p_ie(buf, len, NULL, &p2p_ielen))) ++ { ++ struct wifidirect_info *wdinfo = &padapter->wdinfo; ++ u32 attr_contentlen = 0; ++ u8 listen_ch_attr[5]; ++ ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("probe_req_p2p_ielen=%d\n", p2p_ielen); ++ #endif ++ ++ if(pmlmepriv->p2p_probe_req_ie) ++ { ++ u32 free_len = pmlmepriv->p2p_probe_req_ie_len; ++ pmlmepriv->p2p_probe_req_ie_len = 0; ++ rtw_mfree(pmlmepriv->p2p_probe_req_ie, free_len); ++ pmlmepriv->p2p_probe_req_ie = NULL; ++ } ++ ++ pmlmepriv->p2p_probe_req_ie = rtw_malloc(p2p_ielen); ++ if ( pmlmepriv->p2p_probe_req_ie == NULL) { ++ DBG_8192C("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ return -EINVAL; ++ ++ } ++ _rtw_memcpy(pmlmepriv->p2p_probe_req_ie, p2p_ie, p2p_ielen); ++ pmlmepriv->p2p_probe_req_ie_len = p2p_ielen; ++ ++ if(rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_LISTEN_CH, (u8*)listen_ch_attr, (uint*) &attr_contentlen) ++ && attr_contentlen == 5) ++ { ++ if (wdinfo->listen_channel != listen_ch_attr[4]) { ++ DBG_871X(FUNC_ADPT_FMT" listen channel - country:%c%c%c, class:%u, ch:%u\n", ++ FUNC_ADPT_ARG(padapter), listen_ch_attr[0], listen_ch_attr[1], listen_ch_attr[2], ++ listen_ch_attr[3], listen_ch_attr[4]); ++ wdinfo->listen_channel = listen_ch_attr[4]; ++ } ++ } ++ } ++ #endif //CONFIG_P2P ++ ++ //buf += p2p_ielen; ++ //len -= p2p_ielen; ++ ++ #ifdef CONFIG_WFD ++ if(rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen)) ++ { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("probe_req_wfd_ielen=%d\n", wfd_ielen); ++ #endif ++ ++ if(pmlmepriv->wfd_probe_req_ie) ++ { ++ u32 free_len = pmlmepriv->wfd_probe_req_ie_len; ++ pmlmepriv->wfd_probe_req_ie_len = 0; ++ rtw_mfree(pmlmepriv->wfd_probe_req_ie, free_len); ++ pmlmepriv->wfd_probe_req_ie = NULL; ++ } ++ ++ pmlmepriv->wfd_probe_req_ie = rtw_malloc(wfd_ielen); ++ if ( pmlmepriv->wfd_probe_req_ie == NULL) { ++ DBG_8192C("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ return -EINVAL; ++ ++ } ++ rtw_get_wfd_ie(buf, len, pmlmepriv->wfd_probe_req_ie, &pmlmepriv->wfd_probe_req_ie_len); ++ } ++ #endif //CONFIG_WFD ++ ++ } ++ ++ return ret; ++ ++} ++ ++static int cfg80211_rtw_scan(struct wiphy *wiphy ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) ++ , struct net_device *ndev ++ #endif ++ , struct cfg80211_scan_request *request) ++{ ++ int i; ++ u8 _status = _FALSE; ++ int ret = 0; ++ _adapter *padapter = wiphy_to_adapter(wiphy); ++ struct mlme_priv *pmlmepriv= &padapter->mlmepriv; ++ NDIS_802_11_SSID ssid[RTW_SSID_SCAN_AMOUNT]; ++ struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT]; ++ _irqL irqL; ++ u8 *wps_ie=NULL; ++ uint wps_ielen=0; ++ u8 *p2p_ie=NULL; ++ uint p2p_ielen=0; ++ u8 survey_times=3; ++ u8 survey_times_for_one_ch=6; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++#endif //CONFIG_P2P ++ struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); ++ struct cfg80211_ssid *ssids = request->ssids; ++ int social_channel = 0, j = 0; ++ bool need_indicate_scan_done = _FALSE; ++#ifdef CONFIG_CONCURRENT_MODE ++ PADAPTER pbuddy_adapter = NULL; ++ struct mlme_priv *pbuddy_mlmepriv = NULL; ++#endif //CONFIG_CONCURRENT_MODE ++ ++//#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++//#endif ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (padapter->pbuddy_adapter) { ++ pbuddy_adapter = padapter->pbuddy_adapter; ++ pbuddy_mlmepriv = &(pbuddy_adapter->mlmepriv); ++ } ++#endif //CONFIG_CONCURRENT_MODE ++ ++#ifdef CONFIG_MP_INCLUDED ++if (padapter->registrypriv.mp_mode == 1) ++{ ++ if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) ++ { ++ ret = -EPERM; ++ goto exit; ++ } ++} ++#endif ++ ++ _enter_critical_bh(&pwdev_priv->scan_req_lock, &irqL); ++ pwdev_priv->scan_request = request; ++ _exit_critical_bh(&pwdev_priv->scan_req_lock, &irqL); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ { ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X("%s under WIFI_AP_STATE\n", __FUNCTION__); ++#endif ++ ++ if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS|_FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE) ++ { ++ DBG_8192C("%s, fwstate=0x%x\n", __func__, pmlmepriv->fw_state); ++ ++ if(check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) ++ { ++ DBG_8192C("AP mode process WPS \n"); ++ } ++ ++ need_indicate_scan_done = _TRUE; ++ goto check_need_indicate_scan_done; ++ } ++ } ++ ++ if(_FAIL == rtw_pwr_wakeup(padapter)) { ++ need_indicate_scan_done = _TRUE; ++ goto check_need_indicate_scan_done; ++ } ++ ++ #ifdef CONFIG_P2P ++ if( pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ { ++ if(ssids->ssid != NULL ++ && _rtw_memcmp(ssids->ssid, "DIRECT-", 7) ++ && rtw_get_p2p_ie((u8 *)request->ie, request->ie_len, NULL, NULL) ++ ) ++ { ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ rtw_p2p_enable(padapter, P2P_ROLE_DEVICE); ++ wdev_to_priv(padapter->rtw_wdev)->p2p_enabled = _TRUE; ++ } ++ else ++ { ++ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s, role=%d, p2p_state=%d\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo)); ++ #endif ++ } ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); ++ ++ if(request->n_channels == 3 && ++ request->channels[0]->hw_value == 1 && ++ request->channels[1]->hw_value == 6 && ++ request->channels[2]->hw_value == 11 ++ ) ++ { ++ social_channel = 1; ++ } ++ } ++ } ++ #endif //CONFIG_P2P ++ ++ if(request->ie && request->ie_len>0) ++ { ++ rtw_cfg80211_set_probe_req_wpsp2pie(padapter, (u8 *)request->ie, request->ie_len ); ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) { ++ DBG_8192C("%s, fwstate=0x%x\n", __func__, pmlmepriv->fw_state); ++ need_indicate_scan_done = _TRUE; ++ goto check_need_indicate_scan_done; ++ } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE) { ++ DBG_8192C("%s, fwstate=0x%x\n", __func__, pmlmepriv->fw_state); ++ ret = -EBUSY; ++ goto check_need_indicate_scan_done; ++ } ++ ++ if (pmlmepriv->LinkDetectInfo.bBusyTraffic == _TRUE) ++ { ++ DBG_8192C("%s, bBusyTraffic == _TRUE\n", __func__); ++ need_indicate_scan_done = _TRUE; ++ goto check_need_indicate_scan_done; ++ } ++ ++ if (rtw_is_scan_deny(padapter)){ ++ DBG_871X(FUNC_ADPT_FMT ": scan deny\n", FUNC_ADPT_ARG(padapter)); ++ need_indicate_scan_done = _TRUE; ++ goto check_need_indicate_scan_done; ++ } ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(pbuddy_mlmepriv && (pbuddy_mlmepriv->LinkDetectInfo.bBusyTraffic == _TRUE)) ++ { ++ DBG_8192C("%s, bBusyTraffic == _TRUE at buddy_intf\n", __func__); ++ need_indicate_scan_done = _TRUE; ++ goto check_need_indicate_scan_done; ++ } ++ ++ if (check_buddy_fwstate(padapter, ++ _FW_UNDER_SURVEY|_FW_UNDER_LINKING|WIFI_UNDER_WPS) == _TRUE) ++ { ++ if(check_buddy_fwstate(padapter, _FW_UNDER_SURVEY)) ++ { ++ DBG_8192C("scanning_via_buddy_intf\n"); ++ pmlmepriv->scanning_via_buddy_intf = _TRUE; ++ } ++ ++ DBG_8192C("buddy_intf's mlme state:0x%x\n", pbuddy_mlmepriv->fw_state); ++ ++ need_indicate_scan_done = _TRUE; ++ goto check_need_indicate_scan_done; ++ } ++#endif ++ ++ ++#ifdef CONFIG_P2P ++ if( pwdinfo->driver_interface == DRIVER_CFG80211 ) ++ { ++ if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) ++ { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH); ++ rtw_free_network_queue(padapter, _TRUE); ++ ++ if(social_channel == 0) ++ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE); ++ else ++ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_SOCIAL_LAST); ++ } ++ } ++#endif //CONFIG_P2P ++ ++ ++ _rtw_memset(ssid, 0, sizeof(NDIS_802_11_SSID)*RTW_SSID_SCAN_AMOUNT); ++ //parsing request ssids, n_ssids ++ for (i = 0; i < request->n_ssids && i < RTW_SSID_SCAN_AMOUNT; i++) { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("ssid=%s, len=%d\n", ssids[i].ssid, ssids[i].ssid_len); ++ #endif ++ _rtw_memcpy(ssid[i].Ssid, ssids[i].ssid, ssids[i].ssid_len); ++ ssid[i].SsidLength = ssids[i].ssid_len; ++ } ++ ++ /* parsing channels, n_channels */ ++ _rtw_memset(ch, 0, sizeof(struct rtw_ieee80211_channel)*RTW_CHANNEL_SCAN_AMOUNT); ++ for (i=0;in_channels && ichannels[i])); ++ #endif ++ ch[i].hw_value = request->channels[i]->hw_value; ++ ch[i].flags = request->channels[i]->flags; ++ } ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ if (request->n_channels == 1) { ++ for(i=1;in_channels <= 4) { ++ for(j=request->n_channels-1;j>=0;j--) ++ for(i=0;in_channels); ++ } else { ++ _status = rtw_sitesurvey_cmd(padapter, ssid, RTW_SSID_SCAN_AMOUNT, NULL, 0); ++ } ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ ++ if(_status == _FALSE) ++ { ++ ret = -1; ++ } ++ ++check_need_indicate_scan_done: ++ if(need_indicate_scan_done) ++ rtw_cfg80211_surveydone_event_callback(padapter); ++ ++exit: ++ ++ return ret; ++ ++} ++ ++static int cfg80211_rtw_set_wiphy_params(struct wiphy *wiphy, u32 changed) ++{ ++#if 0 ++ struct iwm_priv *iwm = wiphy_to_iwm(wiphy); ++ ++ if (changed & WIPHY_PARAM_RTS_THRESHOLD && ++ (iwm->conf.rts_threshold != wiphy->rts_threshold)) { ++ int ret; ++ ++ iwm->conf.rts_threshold = wiphy->rts_threshold; ++ ++ ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, ++ CFG_RTS_THRESHOLD, ++ iwm->conf.rts_threshold); ++ if (ret < 0) ++ return ret; ++ } ++ ++ if (changed & WIPHY_PARAM_FRAG_THRESHOLD && ++ (iwm->conf.frag_threshold != wiphy->frag_threshold)) { ++ int ret; ++ ++ iwm->conf.frag_threshold = wiphy->frag_threshold; ++ ++ ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX, ++ CFG_FRAG_THRESHOLD, ++ iwm->conf.frag_threshold); ++ if (ret < 0) ++ return ret; ++ } ++#endif ++ DBG_8192C("%s\n", __func__); ++ return 0; ++} ++ ++ ++ ++static int rtw_cfg80211_set_wpa_version(struct security_priv *psecuritypriv, u32 wpa_version) ++{ ++ DBG_8192C("%s, wpa_version=%d\n", __func__, wpa_version); ++ ++ if (!wpa_version) { ++ psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen; ++ return 0; ++ } ++ ++ ++ if (wpa_version & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) ++ { ++ psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPAPSK; ++ } ++ ++/* ++ if (wpa_version & NL80211_WPA_VERSION_2) ++ { ++ psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPA2PSK; ++ } ++*/ ++ ++ return 0; ++ ++} ++ ++static int rtw_cfg80211_set_auth_type(struct security_priv *psecuritypriv, ++ enum nl80211_auth_type sme_auth_type) ++{ ++ DBG_8192C("%s, nl80211_auth_type=%d\n", __func__, sme_auth_type); ++ ++ ++ switch (sme_auth_type) { ++ case NL80211_AUTHTYPE_AUTOMATIC: ++ ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; ++ ++ break; ++ case NL80211_AUTHTYPE_OPEN_SYSTEM: ++ ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; ++ ++ if(psecuritypriv->ndisauthtype>Ndis802_11AuthModeWPA) ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ if(psecuritypriv->ndisauthtype == Ndis802_11AuthModeWAPI) ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_WAPI; ++#endif ++ ++ break; ++ case NL80211_AUTHTYPE_SHARED_KEY: ++ ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Shared; ++ ++ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ ++ ++ break; ++ default: ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; ++ //return -ENOTSUPP; ++ } ++ ++ return 0; ++ ++} ++ ++static int rtw_cfg80211_set_cipher(struct security_priv *psecuritypriv, u32 cipher, bool ucast) ++{ ++ u32 ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ ++ u32 *profile_cipher = ucast ? &psecuritypriv->dot11PrivacyAlgrthm : ++ &psecuritypriv->dot118021XGrpPrivacy; ++ ++ DBG_8192C("%s, ucast=%d, cipher=0x%x\n", __func__, ucast, cipher); ++ ++ ++ if (!cipher) { ++ *profile_cipher = _NO_PRIVACY_; ++ psecuritypriv->ndisencryptstatus = ndisencryptstatus; ++ return 0; ++ } ++ ++ switch (cipher) { ++ case IW_AUTH_CIPHER_NONE: ++ *profile_cipher = _NO_PRIVACY_; ++ ndisencryptstatus = Ndis802_11EncryptionDisabled; ++#ifdef CONFIG_WAPI_SUPPORT ++ if(psecuritypriv->dot11PrivacyAlgrthm ==_SMS4_ ) ++ { ++ *profile_cipher = _SMS4_; ++ } ++#endif ++ break; ++ case WLAN_CIPHER_SUITE_WEP40: ++ *profile_cipher = _WEP40_; ++ ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ case WLAN_CIPHER_SUITE_WEP104: ++ *profile_cipher = _WEP104_; ++ ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ *profile_cipher = _TKIP_; ++ ndisencryptstatus = Ndis802_11Encryption2Enabled; ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ *profile_cipher = _AES_; ++ ndisencryptstatus = Ndis802_11Encryption3Enabled; ++ break; ++#ifdef CONFIG_WAPI_SUPPORT ++ case WLAN_CIPHER_SUITE_SMS4: ++ *profile_cipher = _SMS4_; ++ ndisencryptstatus = Ndis802_11_EncrypteionWAPI; ++ break; ++#endif ++ default: ++ DBG_8192C("Unsupported cipher: 0x%x\n", cipher); ++ return -ENOTSUPP; ++ } ++ ++ if(ucast) ++ { ++ psecuritypriv->ndisencryptstatus = ndisencryptstatus; ++ ++ //if(psecuritypriv->dot11PrivacyAlgrthm >= _AES_) ++ // psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPA2PSK; ++ } ++ ++ return 0; ++} ++ ++static int rtw_cfg80211_set_key_mgt(struct security_priv *psecuritypriv, u32 key_mgt) ++{ ++ DBG_8192C("%s, key_mgt=0x%x\n", __func__, key_mgt); ++ ++ if (key_mgt == WLAN_AKM_SUITE_8021X) ++ //*auth_type = UMAC_AUTH_TYPE_8021X; ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ else if (key_mgt == WLAN_AKM_SUITE_PSK) { ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ } ++#ifdef CONFIG_WAPI_SUPPORT ++ else if(key_mgt ==WLAN_AKM_SUITE_WAPI_PSK){ ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_WAPI; ++ } ++ else if(key_mgt ==WLAN_AKM_SUITE_WAPI_CERT){ ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_WAPI; ++ } ++#endif ++ ++ ++ else { ++ DBG_8192C("Invalid key mgt: 0x%x\n", key_mgt); ++ //return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int rtw_cfg80211_set_wpa_ie(_adapter *padapter, u8 *pie, size_t ielen) ++{ ++ u8 *buf=NULL, *pos=NULL; ++ u32 left; ++ int group_cipher = 0, pairwise_cipher = 0; ++ int ret = 0; ++ int wpa_ielen=0; ++ int wpa2_ielen=0; ++ u8 *pwpa, *pwpa2; ++ u8 null_addr[]= {0,0,0,0,0,0}; ++ ++ if (pie == NULL || !ielen) { ++ /* Treat this as normal case, but need to clear WIFI_UNDER_WPS */ ++ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); ++ goto exit; ++ } ++ ++ if (ielen > MAX_WPA_IE_LEN+MAX_WPS_IE_LEN+MAX_P2P_IE_LEN) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ buf = rtw_zmalloc(ielen); ++ if (buf == NULL){ ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ++ _rtw_memcpy(buf, pie , ielen); ++ ++ //dump ++ { ++ int i; ++ DBG_8192C("set wpa_ie(length:%zu):\n", ielen); ++ for(i=0;i0) ++ { ++ if(rtw_parse_wpa_ie(pwpa, wpa_ielen+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) ++ { ++ padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_8021X; ++ padapter->securitypriv.ndisauthtype=Ndis802_11AuthModeWPAPSK; ++ _rtw_memcpy(padapter->securitypriv.supplicant_ie, &pwpa[0], wpa_ielen+2); ++ ++ DBG_8192C("got wpa_ie, wpa_ielen:%u\n", wpa_ielen); ++ } ++ } ++ ++ pwpa2 = rtw_get_wpa2_ie(buf, &wpa2_ielen, ielen); ++ if(pwpa2 && wpa2_ielen>0) ++ { ++ if(rtw_parse_wpa2_ie(pwpa2, wpa2_ielen+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) ++ { ++ padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_8021X; ++ padapter->securitypriv.ndisauthtype=Ndis802_11AuthModeWPA2PSK; ++ _rtw_memcpy(padapter->securitypriv.supplicant_ie, &pwpa2[0], wpa2_ielen+2); ++ ++ DBG_8192C("got wpa2_ie, wpa2_ielen:%u\n", wpa2_ielen); ++ } ++ } ++ ++ if (group_cipher == 0) ++ { ++ group_cipher = WPA_CIPHER_NONE; ++ } ++ if (pairwise_cipher == 0) ++ { ++ pairwise_cipher = WPA_CIPHER_NONE; ++ } ++ ++ switch(group_cipher) ++ { ++ case WPA_CIPHER_NONE: ++ padapter->securitypriv.dot118021XGrpPrivacy=_NO_PRIVACY_; ++ padapter->securitypriv.ndisencryptstatus=Ndis802_11EncryptionDisabled; ++ break; ++ case WPA_CIPHER_WEP40: ++ padapter->securitypriv.dot118021XGrpPrivacy=_WEP40_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ case WPA_CIPHER_TKIP: ++ padapter->securitypriv.dot118021XGrpPrivacy=_TKIP_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; ++ break; ++ case WPA_CIPHER_CCMP: ++ padapter->securitypriv.dot118021XGrpPrivacy=_AES_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; ++ break; ++ case WPA_CIPHER_WEP104: ++ padapter->securitypriv.dot118021XGrpPrivacy=_WEP104_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ } ++ ++ switch(pairwise_cipher) ++ { ++ case WPA_CIPHER_NONE: ++ padapter->securitypriv.dot11PrivacyAlgrthm=_NO_PRIVACY_; ++ padapter->securitypriv.ndisencryptstatus=Ndis802_11EncryptionDisabled; ++ break; ++ case WPA_CIPHER_WEP40: ++ padapter->securitypriv.dot11PrivacyAlgrthm=_WEP40_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ case WPA_CIPHER_TKIP: ++ padapter->securitypriv.dot11PrivacyAlgrthm=_TKIP_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; ++ break; ++ case WPA_CIPHER_CCMP: ++ padapter->securitypriv.dot11PrivacyAlgrthm=_AES_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; ++ break; ++ case WPA_CIPHER_WEP104: ++ padapter->securitypriv.dot11PrivacyAlgrthm=_WEP104_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ } ++ ++ {/* handle wps_ie */ ++ uint wps_ielen; ++ u8 *wps_ie; ++ ++ wps_ie = rtw_get_wps_ie(buf, ielen, NULL, &wps_ielen); ++ if (wps_ie && wps_ielen > 0) { ++ DBG_8192C("got wps_ie, wps_ielen:%u\n", wps_ielen); ++ padapter->securitypriv.wps_ie_len = wps_ielensecuritypriv.wps_ie, wps_ie, padapter->securitypriv.wps_ie_len); ++ set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS); ++ } else { ++ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); ++ } ++ } ++ ++ #ifdef CONFIG_P2P ++ {//check p2p_ie for assoc req; ++ uint p2p_ielen=0; ++ u8 *p2p_ie; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ if((p2p_ie=rtw_get_p2p_ie(buf, ielen, NULL, &p2p_ielen))) ++ { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s p2p_assoc_req_ielen=%d\n", __FUNCTION__, p2p_ielen); ++ #endif ++ ++ if(pmlmepriv->p2p_assoc_req_ie) ++ { ++ u32 free_len = pmlmepriv->p2p_assoc_req_ie_len; ++ pmlmepriv->p2p_assoc_req_ie_len = 0; ++ rtw_mfree(pmlmepriv->p2p_assoc_req_ie, free_len); ++ pmlmepriv->p2p_assoc_req_ie = NULL; ++ } ++ ++ pmlmepriv->p2p_assoc_req_ie = rtw_malloc(p2p_ielen); ++ if ( pmlmepriv->p2p_assoc_req_ie == NULL) { ++ DBG_8192C("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ goto exit; ++ } ++ _rtw_memcpy(pmlmepriv->p2p_assoc_req_ie, p2p_ie, p2p_ielen); ++ pmlmepriv->p2p_assoc_req_ie_len = p2p_ielen; ++ } ++ } ++ #endif //CONFIG_P2P ++ ++ #ifdef CONFIG_WFD ++ {//check wfd_ie for assoc req; ++ uint wfd_ielen=0; ++ u8 *wfd_ie; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ if(rtw_get_wfd_ie(buf, ielen, NULL, &wfd_ielen)) ++ { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s wfd_assoc_req_ielen=%d\n", __FUNCTION__, wfd_ielen); ++ #endif ++ ++ if(pmlmepriv->wfd_assoc_req_ie) ++ { ++ u32 free_len = pmlmepriv->wfd_assoc_req_ie_len; ++ pmlmepriv->wfd_assoc_req_ie_len = 0; ++ rtw_mfree(pmlmepriv->wfd_assoc_req_ie, free_len); ++ pmlmepriv->wfd_assoc_req_ie = NULL; ++ } ++ ++ pmlmepriv->wfd_assoc_req_ie = rtw_malloc(wfd_ielen); ++ if ( pmlmepriv->wfd_assoc_req_ie == NULL) { ++ DBG_8192C("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ goto exit; ++ } ++ rtw_get_wfd_ie(buf, ielen, pmlmepriv->wfd_assoc_req_ie, &pmlmepriv->wfd_assoc_req_ie_len); ++ } ++ } ++ #endif //CONFIG_WFD ++ ++ //TKIP and AES disallow multicast packets until installing group key ++ if(padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_ ++ || padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_WTMIC_ ++ || padapter->securitypriv.dot11PrivacyAlgrthm == _AES_) ++ //WPS open need to enable multicast ++ //|| check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) == _TRUE) ++ rtw_hal_set_hwreg(padapter, HW_VAR_OFF_RCR_AM, null_addr); ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ++ ("rtw_set_wpa_ie: pairwise_cipher=0x%08x padapter->securitypriv.ndisencryptstatus=%d padapter->securitypriv.ndisauthtype=%d\n", ++ pairwise_cipher, padapter->securitypriv.ndisencryptstatus, padapter->securitypriv.ndisauthtype)); ++ ++exit: ++ if (buf) ++ rtw_mfree(buf, ielen); ++ if (ret) ++ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); ++ return ret; ++} ++ ++static int cfg80211_rtw_join_ibss(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_ibss_params *params) ++{ ++ _adapter *padapter = wiphy_to_adapter(wiphy); ++ NDIS_802_11_SSID ndis_ssid; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ int ret=0; ++ ++ if(_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret= -EPERM; ++ goto exit; ++ } ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ ret = -EPERM; ++ goto exit; ++ } ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (check_buddy_fwstate(padapter, _FW_UNDER_LINKING) == _TRUE) { ++ DBG_8192C("%s, but buddy_intf is under linking\n", __FUNCTION__); ++ ret = -EINVAL; ++ goto exit; ++ } ++ if (check_buddy_fwstate(padapter, _FW_UNDER_SURVEY) == _TRUE) { ++ rtw_scan_abort(padapter->pbuddy_adapter); ++ } ++#endif //CONFIG_CONCURRENT_MODE ++ ++ if (!params->ssid || !params->ssid_len) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (params->ssid_len > IW_ESSID_MAX_SIZE){ ++ ++ ret= -E2BIG; ++ goto exit; ++ } ++ ++ _rtw_memset(&ndis_ssid, 0, sizeof(NDIS_802_11_SSID)); ++ ndis_ssid.SsidLength = params->ssid_len; ++ _rtw_memcpy(ndis_ssid.Ssid, params->ssid, params->ssid_len); ++ ++ //DBG_8192C("ssid=%s, len=%zu\n", ndis_ssid.Ssid, params->ssid_len); ++ ++ psecuritypriv->ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; //open system ++ psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen; ++ ++ ret = rtw_cfg80211_set_auth_type(psecuritypriv, NL80211_AUTHTYPE_OPEN_SYSTEM); ++ rtw_set_802_11_authentication_mode(padapter, psecuritypriv->ndisauthtype); ++ ++ if (rtw_set_802_11_ssid(padapter, &ndis_ssid) == _FALSE) ++ { ++ ret = -1; ++ goto exit; ++ } ++ ++exit: ++ return ret; ++} ++ ++static int cfg80211_rtw_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) ++{ ++#if 0 ++ struct iwm_priv *iwm = wiphy_to_iwm(wiphy); ++ ++ if (iwm->umac_profile_active) ++ return iwm_invalidate_mlme_profile(iwm); ++#endif ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ return 0; ++} ++ ++static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_connect_params *sme) ++{ ++ int ret=0; ++ _irqL irqL; ++ _list *phead; ++ struct wlan_network *pnetwork = NULL; ++ NDIS_802_11_AUTHENTICATION_MODE authmode; ++ NDIS_802_11_SSID ndis_ssid; ++ u8 *dst_ssid, *src_ssid; ++ u8 *dst_bssid, *src_bssid; ++ //u8 matched_by_bssid=_FALSE; ++ //u8 matched_by_ssid=_FALSE; ++ u8 matched=_FALSE; ++ _adapter *padapter = wiphy_to_adapter(wiphy); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ _queue *queue = &pmlmepriv->scanned_queue; ++ ++ padapter->mlmepriv.not_indic_disco = _TRUE; ++ ++ DBG_871X("=>"FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ DBG_871X("privacy=%d, key=%p, key_len=%d, key_idx=%d\n", ++ sme->privacy, sme->key, sme->key_len, sme->key_idx); ++ ++ ++ if(wdev_to_priv(padapter->rtw_wdev)->block == _TRUE) ++ { ++ ret = -EBUSY; ++ DBG_871X("%s wdev_priv.block is set\n", __FUNCTION__); ++ goto exit; ++ } ++ ++#ifdef CONFIG_PLATFORM_MSTAR ++ printk("MStar Android!\n"); ++ if((wdev_to_priv(padapter->rtw_wdev))->bandroid_scan == _FALSE) ++ { ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++#endif //CONFIG_P2P ++ { ++ ret = -EBUSY; ++ printk("Android hasn't attached yet!\n"); ++ goto exit; ++ } ++ } ++#endif ++ ++ if(_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret= -EPERM; ++ goto exit; ++ } ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ ret = -EPERM; ++ goto exit; ++ } ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (check_buddy_fwstate(padapter, _FW_UNDER_LINKING) == _TRUE) { ++ DBG_8192C("%s, but buddy_intf is under linking\n", __FUNCTION__); ++ ret = -EINVAL; ++ goto exit; ++ } ++ if (check_buddy_fwstate(padapter, _FW_UNDER_SURVEY) == _TRUE) { ++ rtw_scan_abort(padapter->pbuddy_adapter); ++ } ++#endif ++ ++ if (!sme->ssid || !sme->ssid_len) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (sme->ssid_len > IW_ESSID_MAX_SIZE){ ++ ++ ret= -E2BIG; ++ goto exit; ++ } ++ ++ _rtw_memset(&ndis_ssid, 0, sizeof(NDIS_802_11_SSID)); ++ ndis_ssid.SsidLength = sme->ssid_len; ++ _rtw_memcpy(ndis_ssid.Ssid, sme->ssid, sme->ssid_len); ++ ++ DBG_8192C("ssid=%s, len=%zu\n", ndis_ssid.Ssid, sme->ssid_len); ++ ++ ++ if (sme->bssid) ++ DBG_8192C("bssid="MAC_FMT"\n", MAC_ARG(sme->bssid)); ++ ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE) { ++ ret = -EBUSY; ++ DBG_8192C("%s, fw_state=0x%x, goto exit\n", __FUNCTION__, pmlmepriv->fw_state); ++ goto exit; ++ } ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) { ++ rtw_scan_abort(padapter); ++ } ++ ++ psecuritypriv->ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; //open system ++ psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen; ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ padapter->wapiInfo.bWapiEnable = false; ++#endif ++ ++ ret = rtw_cfg80211_set_wpa_version(psecuritypriv, sme->crypto.wpa_versions); ++ if (ret < 0) ++ goto exit; ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ if(sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) ++ { ++ padapter->wapiInfo.bWapiEnable = true; ++ padapter->wapiInfo.extra_prefix_len = WAPI_EXT_LEN; ++ padapter->wapiInfo.extra_postfix_len = SMS4_MIC_LEN; ++ } ++#endif ++ ++ ret = rtw_cfg80211_set_auth_type(psecuritypriv, sme->auth_type); ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ if(psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_WAPI) ++ padapter->mlmeextpriv.mlmext_info.auth_algo = psecuritypriv->dot11AuthAlgrthm; ++#endif ++ ++ ++ if (ret < 0) ++ goto exit; ++ ++ DBG_8192C("%s, ie_len=%zu\n", __func__, sme->ie_len); ++ ++ ret = rtw_cfg80211_set_wpa_ie(padapter, sme->ie, sme->ie_len); ++ if (ret < 0) ++ goto exit; ++ ++ if (sme->crypto.n_ciphers_pairwise) { ++ ret = rtw_cfg80211_set_cipher(psecuritypriv, sme->crypto.ciphers_pairwise[0], _TRUE); ++ if (ret < 0) ++ goto exit; ++ } ++ ++ //For WEP Shared auth ++ if((psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Shared ++ || psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Auto) && sme->key ++ ) ++ { ++ u32 wep_key_idx, wep_key_len,wep_total_len; ++ NDIS_802_11_WEP *pwep = NULL; ++ DBG_871X("%s(): Shared/Auto WEP\n",__FUNCTION__); ++ ++ wep_key_idx = sme->key_idx; ++ wep_key_len = sme->key_len; ++ ++ if (sme->key_idx > WEP_KEYS) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (wep_key_len > 0) ++ { ++ wep_key_len = wep_key_len <= 5 ? 5 : 13; ++ wep_total_len = wep_key_len + FIELD_OFFSET(NDIS_802_11_WEP, KeyMaterial); ++ pwep =(NDIS_802_11_WEP *) rtw_malloc(wep_total_len); ++ if(pwep == NULL){ ++ DBG_871X(" wpa_set_encryption: pwep allocate fail !!!\n"); ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ++ _rtw_memset(pwep, 0, wep_total_len); ++ ++ pwep->KeyLength = wep_key_len; ++ pwep->Length = wep_total_len; ++ ++ if(wep_key_len==13) ++ { ++ padapter->securitypriv.dot11PrivacyAlgrthm=_WEP104_; ++ padapter->securitypriv.dot118021XGrpPrivacy=_WEP104_; ++ } ++ } ++ else { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ pwep->KeyIndex = wep_key_idx; ++ pwep->KeyIndex |= 0x80000000; ++ ++ _rtw_memcpy(pwep->KeyMaterial, (void *)sme->key, pwep->KeyLength); ++ ++ if(rtw_set_802_11_add_wep(padapter, pwep) == (u8)_FAIL) ++ { ++ ret = -EOPNOTSUPP ; ++ } ++ ++ if (pwep) { ++ rtw_mfree((u8 *)pwep,wep_total_len); ++ } ++ ++ if(ret < 0) ++ goto exit; ++ } ++ ++ ret = rtw_cfg80211_set_cipher(psecuritypriv, sme->crypto.cipher_group, _FALSE); ++ if (ret < 0) ++ return ret; ++ ++ if (sme->crypto.n_akm_suites) { ++ ret = rtw_cfg80211_set_key_mgt(psecuritypriv, sme->crypto.akm_suites[0]); ++ if (ret < 0) ++ goto exit; ++ } ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ if(sme->crypto.akm_suites[0] ==WLAN_AKM_SUITE_WAPI_PSK){ ++ padapter->wapiInfo.bWapiPSK = true; ++ } ++ else if(sme->crypto.akm_suites[0] ==WLAN_AKM_SUITE_WAPI_CERT){ ++ padapter->wapiInfo.bWapiPSK = false; ++ } ++#endif ++ ++ authmode = psecuritypriv->ndisauthtype; ++ rtw_set_802_11_authentication_mode(padapter, authmode); ++ ++ //rtw_set_802_11_encryption_mode(padapter, padapter->securitypriv.ndisencryptstatus); ++ ++ if (rtw_set_802_11_connect(padapter, sme->bssid, &ndis_ssid) == _FALSE) { ++ ret = -1; ++ goto exit; ++ } ++ ++ DBG_8192C("set ssid:dot11AuthAlgrthm=%d, dot11PrivacyAlgrthm=%d, dot118021XGrpPrivacy=%d\n", psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm, psecuritypriv->dot118021XGrpPrivacy); ++ ++exit: ++ ++ DBG_8192C("<=%s, ret %d\n",__FUNCTION__, ret); ++ ++ padapter->mlmepriv.not_indic_disco = _FALSE; ++ ++ return ret; ++} ++ ++static int cfg80211_rtw_disconnect(struct wiphy *wiphy, struct net_device *ndev, ++ u16 reason_code) ++{ ++ _adapter *padapter = wiphy_to_adapter(wiphy); ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ padapter->mlmepriv.not_indic_disco = _TRUE; ++ ++ rtw_set_roaming(padapter, 0); ++ ++ if(check_fwstate(&padapter->mlmepriv, _FW_LINKED)) ++ { ++ rtw_scan_abort(padapter); ++ LeaveAllPowerSaveMode(padapter); ++ rtw_disassoc_cmd(padapter, 500, _FALSE); ++ ++ DBG_871X("%s...call rtw_indicate_disconnect\n", __FUNCTION__); ++ ++ rtw_indicate_disconnect(padapter); ++ ++ rtw_free_assoc_resources(padapter, 1); ++ } ++ ++ padapter->mlmepriv.not_indic_disco = _FALSE; ++ ++ return 0; ++} ++ ++static int cfg80211_rtw_set_txpower(struct wiphy *wiphy, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)) ++ struct wireless_dev *wdev, ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) || defined(COMPAT_KERNEL_RELEASE) ++ enum nl80211_tx_power_setting type, int mbm) ++#else ++ enum tx_power_setting type, int dbm) ++#endif ++{ ++#if 0 ++ struct iwm_priv *iwm = wiphy_to_iwm(wiphy); ++ int ret; ++ ++ switch (type) { ++ case NL80211_TX_POWER_AUTOMATIC: ++ return 0; ++ case NL80211_TX_POWER_FIXED: ++ if (mbm < 0 || (mbm % 100)) ++ return -EOPNOTSUPP; ++ ++ if (!test_bit(IWM_STATUS_READY, &iwm->status)) ++ return 0; ++ ++ ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, ++ CFG_TX_PWR_LIMIT_USR, ++ MBM_TO_DBM(mbm) * 2); ++ if (ret < 0) ++ return ret; ++ ++ return iwm_tx_power_trigger(iwm); ++ default: ++ IWM_ERR(iwm, "Unsupported power type: %d\n", type); ++ return -EOPNOTSUPP; ++ } ++#endif ++ DBG_8192C("%s\n", __func__); ++ return 0; ++} ++ ++static int cfg80211_rtw_get_txpower(struct wiphy *wiphy, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)) ++ struct wireless_dev *wdev, ++#endif ++ int *dbm) ++{ ++ //_adapter *padapter = wiphy_to_adapter(wiphy); ++ ++ DBG_8192C("%s\n", __func__); ++ ++ *dbm = (12); ++ ++ return 0; ++} ++ ++inline bool rtw_cfg80211_pwr_mgmt(_adapter *adapter) ++{ ++ struct rtw_wdev_priv *rtw_wdev_priv = wdev_to_priv(adapter->rtw_wdev); ++ return rtw_wdev_priv->power_mgmt; ++} ++ ++static int cfg80211_rtw_set_power_mgmt(struct wiphy *wiphy, ++ struct net_device *ndev, ++ bool enabled, int timeout) ++{ ++ _adapter *padapter = wiphy_to_adapter(wiphy); ++ struct rtw_wdev_priv *rtw_wdev_priv = wdev_to_priv(padapter->rtw_wdev); ++ ++ DBG_871X(FUNC_NDEV_FMT" enabled:%u, timeout:%d\n", FUNC_NDEV_ARG(ndev), ++ enabled, timeout); ++ ++ rtw_wdev_priv->power_mgmt = enabled; ++ ++ #ifdef CONFIG_LPS ++ if (!enabled) ++ LPS_Leave(padapter); ++ #endif ++ ++ return 0; ++} ++ ++static int cfg80211_rtw_set_pmksa(struct wiphy *wiphy, ++ struct net_device *netdev, ++ struct cfg80211_pmksa *pmksa) ++{ ++ u8 index,blInserted = _FALSE; ++ _adapter *padapter = wiphy_to_adapter(wiphy); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ u8 strZeroMacAddress[ ETH_ALEN ] = { 0x00 }; ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(netdev)); ++ ++ if ( _rtw_memcmp( pmksa->bssid, strZeroMacAddress, ETH_ALEN ) == _TRUE ) ++ { ++ return -EINVAL; ++ } ++ ++ blInserted = _FALSE; ++ ++ //overwrite PMKID ++ for(index=0 ; indexPMKIDList[index].Bssid, pmksa->bssid, ETH_ALEN) ==_TRUE ) ++ { // BSSID is matched, the same AP => rewrite with new PMKID. ++ DBG_871X(FUNC_NDEV_FMT" BSSID exists in the PMKList.\n", FUNC_NDEV_ARG(netdev)); ++ ++ _rtw_memcpy( psecuritypriv->PMKIDList[index].PMKID, pmksa->pmkid, WLAN_PMKID_LEN); ++ psecuritypriv->PMKIDList[index].bUsed = _TRUE; ++ psecuritypriv->PMKIDIndex = index+1; ++ blInserted = _TRUE; ++ break; ++ } ++ } ++ ++ if(!blInserted) ++ { ++ // Find a new entry ++ DBG_871X(FUNC_NDEV_FMT" Use the new entry index = %d for this PMKID.\n", ++ FUNC_NDEV_ARG(netdev), psecuritypriv->PMKIDIndex ); ++ ++ _rtw_memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].Bssid, pmksa->bssid, ETH_ALEN); ++ _rtw_memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].PMKID, pmksa->pmkid, WLAN_PMKID_LEN); ++ ++ psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].bUsed = _TRUE; ++ psecuritypriv->PMKIDIndex++ ; ++ if(psecuritypriv->PMKIDIndex==16) ++ { ++ psecuritypriv->PMKIDIndex =0; ++ } ++ } ++ ++ return 0; ++} ++ ++static int cfg80211_rtw_del_pmksa(struct wiphy *wiphy, ++ struct net_device *netdev, ++ struct cfg80211_pmksa *pmksa) ++{ ++ u8 index, bMatched = _FALSE; ++ _adapter *padapter = wiphy_to_adapter(wiphy); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(netdev)); ++ ++ for(index=0 ; indexPMKIDList[index].Bssid, pmksa->bssid, ETH_ALEN) ==_TRUE ) ++ { // BSSID is matched, the same AP => Remove this PMKID information and reset it. ++ _rtw_memset( psecuritypriv->PMKIDList[index].Bssid, 0x00, ETH_ALEN ); ++ _rtw_memset( psecuritypriv->PMKIDList[index].PMKID, 0x00, WLAN_PMKID_LEN ); ++ psecuritypriv->PMKIDList[index].bUsed = _FALSE; ++ bMatched = _TRUE; ++ break; ++ } ++ } ++ ++ if(_FALSE == bMatched) ++ { ++ DBG_871X(FUNC_NDEV_FMT" do not have matched BSSID\n" ++ , FUNC_NDEV_ARG(netdev)); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int cfg80211_rtw_flush_pmksa(struct wiphy *wiphy, ++ struct net_device *netdev) ++{ ++ _adapter *padapter = wiphy_to_adapter(wiphy); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(netdev)); ++ ++ _rtw_memset( &psecuritypriv->PMKIDList[ 0 ], 0x00, sizeof( RT_PMKID_LIST ) * NUM_PMKID_CACHE ); ++ psecuritypriv->PMKIDIndex = 0; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_AP_MODE ++void rtw_cfg80211_indicate_sta_assoc(_adapter *padapter, u8 *pmgmt_frame, uint frame_len) ++{ ++ s32 freq; ++ int channel; ++ struct wireless_dev *pwdev = padapter->rtw_wdev; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct net_device *ndev = padapter->pnetdev; ++ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++ ++#if defined(RTW_USE_CFG80211_STA_EVENT) || defined(COMPAT_KERNEL_RELEASE) ++ { ++ struct station_info sinfo; ++ u8 ie_offset; ++ if (GetFrameSubType(pmgmt_frame) == WIFI_ASSOCREQ) ++ ie_offset = _ASOCREQ_IE_OFFSET_; ++ else // WIFI_REASSOCREQ ++ ie_offset = _REASOCREQ_IE_OFFSET_; ++ ++ sinfo.filled = 0; ++ sinfo.filled = STATION_INFO_ASSOC_REQ_IES; ++ sinfo.assoc_req_ies = pmgmt_frame + WLAN_HDR_A3_LEN + ie_offset; ++ sinfo.assoc_req_ies_len = frame_len - WLAN_HDR_A3_LEN - ie_offset; ++ cfg80211_new_sta(ndev, GetAddr2Ptr(pmgmt_frame), &sinfo, GFP_ATOMIC); ++ } ++#else /* defined(RTW_USE_CFG80211_STA_EVENT) */ ++ channel = pmlmeext->cur_channel; ++ if (channel <= RTW_CH_MAX_2G_CHANNEL) ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); ++ else ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); ++ ++ #ifdef COMPAT_KERNEL_RELEASE ++ rtw_cfg80211_rx_mgmt(padapter, freq, 0, pmgmt_frame, frame_len, GFP_ATOMIC); ++ #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) && !defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER) ++ rtw_cfg80211_rx_mgmt(padapter, freq, 0, pmgmt_frame, frame_len, GFP_ATOMIC); ++ #else //COMPAT_KERNEL_RELEASE ++ { ++ //to avoid WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION) when calling cfg80211_send_rx_assoc() ++ #ifndef CONFIG_PLATFORM_MSTAR ++ pwdev->iftype = NL80211_IFTYPE_STATION; ++ #endif //CONFIG_PLATFORM_MSTAR ++ DBG_8192C("iftype=%d before call cfg80211_send_rx_assoc()\n", pwdev->iftype); ++ rtw_cfg80211_send_rx_assoc(padapter, NULL, pmgmt_frame, frame_len); ++ DBG_8192C("iftype=%d after call cfg80211_send_rx_assoc()\n", pwdev->iftype); ++ pwdev->iftype = NL80211_IFTYPE_AP; ++ //cfg80211_rx_action(padapter->pnetdev, freq, pmgmt_frame, frame_len, GFP_ATOMIC); ++ } ++ #endif //COMPAT_KERNEL_RELEASE ++#endif /* defined(RTW_USE_CFG80211_STA_EVENT) */ ++ ++} ++ ++void rtw_cfg80211_indicate_sta_disassoc(_adapter *padapter, unsigned char *da, unsigned short reason) ++{ ++ s32 freq; ++ int channel; ++ u8 *pmgmt_frame; ++ uint frame_len; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ u8 mgmt_buf[128] = {0}; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct net_device *ndev = padapter->pnetdev; ++ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++ ++#if defined(RTW_USE_CFG80211_STA_EVENT) || defined(COMPAT_KERNEL_RELEASE) ++ cfg80211_del_sta(ndev, da, GFP_ATOMIC); ++#else /* defined(RTW_USE_CFG80211_STA_EVENT) */ ++ channel = pmlmeext->cur_channel; ++ if (channel <= RTW_CH_MAX_2G_CHANNEL) ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); ++ else ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); ++ ++ pmgmt_frame = mgmt_buf; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pmgmt_frame; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ //_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ //_rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr1, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, da, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pmgmt_frame, WIFI_DEAUTH); ++ ++ pmgmt_frame += sizeof(struct rtw_ieee80211_hdr_3addr); ++ frame_len = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ reason = cpu_to_le16(reason); ++ pmgmt_frame = rtw_set_fixed_ie(pmgmt_frame, _RSON_CODE_ , (unsigned char *)&reason, &frame_len); ++ ++ #ifdef COMPAT_KERNEL_RELEASE ++ rtw_cfg80211_rx_mgmt(padapter, freq, 0, mgmt_buf, frame_len, GFP_ATOMIC); ++ #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) && !defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER) ++ rtw_cfg80211_rx_mgmt(padapter, freq, 0, mgmt_buf, frame_len, GFP_ATOMIC); ++ #else //COMPAT_KERNEL_RELEASE ++ cfg80211_send_disassoc(padapter->pnetdev, mgmt_buf, frame_len); ++ //cfg80211_rx_action(padapter->pnetdev, freq, mgmt_buf, frame_len, GFP_ATOMIC); ++ #endif //COMPAT_KERNEL_RELEASE ++#endif /* defined(RTW_USE_CFG80211_STA_EVENT) */ ++} ++ ++static int rtw_cfg80211_monitor_if_open(struct net_device *ndev) ++{ ++ int ret = 0; ++ ++ DBG_8192C("%s\n", __func__); ++ ++ return ret; ++} ++ ++static int rtw_cfg80211_monitor_if_close(struct net_device *ndev) ++{ ++ int ret = 0; ++ ++ DBG_8192C("%s\n", __func__); ++ ++ return ret; ++} ++ ++static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struct net_device *ndev) ++{ ++ int ret = 0; ++ int rtap_len; ++ int qos_len = 0; ++ int dot11_hdr_len = 24; ++ int snap_len = 6; ++ unsigned char *pdata; ++ u16 frame_ctl; ++ unsigned char src_mac_addr[6]; ++ unsigned char dst_mac_addr[6]; ++ struct ieee80211_hdr *dot11_hdr; ++ struct ieee80211_radiotap_header *rtap_hdr; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev); ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ if (skb) ++ rtw_mstat_update(MSTAT_TYPE_SKB, MSTAT_ALLOC_SUCCESS, skb->truesize); ++ ++ if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) ++ goto fail; ++ ++ rtap_hdr = (struct ieee80211_radiotap_header *)skb->data; ++ if (unlikely(rtap_hdr->it_version)) ++ goto fail; ++ ++ rtap_len = ieee80211_get_radiotap_len(skb->data); ++ if (unlikely(skb->len < rtap_len)) ++ goto fail; ++ ++ if(rtap_len != 14) ++ { ++ DBG_8192C("radiotap len (should be 14): %d\n", rtap_len); ++ goto fail; ++ } ++ ++ /* Skip the ratio tap header */ ++ skb_pull(skb, rtap_len); ++ ++ dot11_hdr = (struct ieee80211_hdr *)skb->data; ++ frame_ctl = le16_to_cpu(dot11_hdr->frame_control); ++ /* Check if the QoS bit is set */ ++ if ((frame_ctl & RTW_IEEE80211_FCTL_FTYPE) == RTW_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)); ++ ++ DBG_8192C("should be eapol packet\n"); ++ ++ /* Use the real net device to transmit the packet */ ++ ret = _rtw_xmit_entry(skb, padapter->pnetdev); ++ ++ return ret; ++ ++ } ++ else if ((frame_ctl & (RTW_IEEE80211_FCTL_FTYPE|RTW_IEEE80211_FCTL_STYPE)) ++ == (RTW_IEEE80211_FTYPE_MGMT|RTW_IEEE80211_STYPE_ACTION) ++ ) ++ { ++ //only for action frames ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ //u8 category, action, OUI_Subtype, dialogToken=0; ++ //unsigned char *frame_body; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ u8 *buf = skb->data; ++ u32 len = skb->len; ++ u8 category, action; ++ int type = -1; ++ ++ if (rtw_action_frame_parse(buf, len, &category, &action) == _FALSE) { ++ DBG_8192C(FUNC_NDEV_FMT" frame_control:0x%x\n", FUNC_NDEV_ARG(ndev), ++ le16_to_cpu(((struct rtw_ieee80211_hdr_3addr *)buf)->frame_ctl)); ++ goto fail; ++ } ++ ++ DBG_8192C("RTW_Tx:da="MAC_FMT" via "FUNC_NDEV_FMT"\n", ++ MAC_ARG(GetAddr1Ptr(buf)), FUNC_NDEV_ARG(ndev)); ++ #ifdef CONFIG_P2P ++ if((type = rtw_p2p_check_frames(padapter, buf, len, _TRUE)) >= 0) ++ goto dump; ++ #endif ++ if (category == RTW_WLAN_CATEGORY_PUBLIC) ++ DBG_871X("RTW_Tx:%s\n", action_public_str(action)); ++ else ++ DBG_871X("RTW_Tx:category(%u), action(%u)\n", category, action); ++ ++dump: ++ //starting alloc mgmt frame to dump it ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ goto fail; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->retry_ctrl = _FALSE; ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ ++ _rtw_memcpy(pframe, (void*)buf, len); ++ #ifdef CONFIG_WFD ++ if (type >= 0) ++ { ++ struct wifi_display_info *pwfd_info; ++ ++ pwfd_info = padapter->wdinfo.wfd_info; ++ ++ if ( _TRUE == pwfd_info->wfd_enable ) ++ { ++ rtw_append_wfd_ie( padapter, pframe, &len ); ++ } ++ } ++ #endif // CONFIG_WFD ++ pattrib->pktlen = len; ++ ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ //update seq number ++ pmlmeext->mgnt_seq = GetSequence(pwlanhdr); ++ pattrib->seqnum = pmlmeext->mgnt_seq; ++ pmlmeext->mgnt_seq++; ++ ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++ } ++ else ++ { ++ DBG_8192C("frame_ctl=0x%x\n", frame_ctl & (RTW_IEEE80211_FCTL_FTYPE|RTW_IEEE80211_FCTL_STYPE)); ++ } ++ ++ ++fail: ++ ++ dev_kfree_skb(skb); ++ ++ return 0; ++ ++} ++ ++static void rtw_cfg80211_monitor_if_set_multicast_list(struct net_device *ndev) ++{ ++ DBG_8192C("%s\n", __func__); ++} ++ ++static int rtw_cfg80211_monitor_if_set_mac_address(struct net_device *ndev, void *addr) ++{ ++ int ret = 0; ++ ++ DBG_8192C("%s\n", __func__); ++ ++ return ret; ++} ++ ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,29)) ++static const struct net_device_ops rtw_cfg80211_monitor_if_ops = { ++ .ndo_open = rtw_cfg80211_monitor_if_open, ++ .ndo_stop = rtw_cfg80211_monitor_if_close, ++ .ndo_start_xmit = rtw_cfg80211_monitor_if_xmit_entry, ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0)) ++ .ndo_set_multicast_list = rtw_cfg80211_monitor_if_set_multicast_list, ++ #endif ++ .ndo_set_mac_address = rtw_cfg80211_monitor_if_set_mac_address, ++}; ++#endif ++ ++static int rtw_cfg80211_add_monitor_if(_adapter *padapter, char *name, struct net_device **ndev) ++{ ++ int ret = 0; ++ struct net_device* mon_ndev = NULL; ++ struct wireless_dev* mon_wdev = NULL; ++ struct rtw_netdev_priv_indicator *pnpi; ++ struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); ++ ++ if (!name ) { ++ DBG_871X(FUNC_ADPT_FMT" without specific name\n", FUNC_ADPT_ARG(padapter)); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (pwdev_priv->pmon_ndev) { ++ DBG_871X(FUNC_ADPT_FMT" monitor interface exist: "NDEV_FMT"\n", ++ FUNC_ADPT_ARG(padapter), NDEV_ARG(pwdev_priv->pmon_ndev)); ++ ret = -EBUSY; ++ goto out; ++ } ++ ++ mon_ndev = alloc_etherdev(sizeof(struct rtw_netdev_priv_indicator)); ++ if (!mon_ndev) { ++ DBG_871X(FUNC_ADPT_FMT" allocate ndev fail\n", FUNC_ADPT_ARG(padapter)); ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ mon_ndev->type = ARPHRD_IEEE80211_RADIOTAP; ++ strncpy(mon_ndev->name, name, IFNAMSIZ); ++ mon_ndev->name[IFNAMSIZ - 1] = 0; ++ mon_ndev->destructor = rtw_ndev_destructor; ++ ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,29)) ++ mon_ndev->netdev_ops = &rtw_cfg80211_monitor_if_ops; ++#else ++ mon_ndev->open = rtw_cfg80211_monitor_if_open; ++ mon_ndev->stop = rtw_cfg80211_monitor_if_close; ++ mon_ndev->hard_start_xmit = rtw_cfg80211_monitor_if_xmit_entry; ++ mon_ndev->set_mac_address = rtw_cfg80211_monitor_if_set_mac_address; ++#endif ++ ++ pnpi = netdev_priv(mon_ndev); ++ pnpi->priv = padapter; ++ pnpi->sizeof_priv = sizeof(_adapter); ++ ++ /* wdev */ ++ mon_wdev = (struct wireless_dev *)rtw_zmalloc(sizeof(struct wireless_dev)); ++ if (!mon_wdev) { ++ DBG_871X(FUNC_ADPT_FMT" allocate mon_wdev fail\n", FUNC_ADPT_ARG(padapter)); ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ mon_wdev->wiphy = padapter->rtw_wdev->wiphy; ++ mon_wdev->netdev = mon_ndev; ++ mon_wdev->iftype = NL80211_IFTYPE_MONITOR; ++ mon_ndev->ieee80211_ptr = mon_wdev; ++ ++ ret = register_netdevice(mon_ndev); ++ if (ret) { ++ goto out; ++ } ++ ++ *ndev = pwdev_priv->pmon_ndev = mon_ndev; ++ _rtw_memcpy(pwdev_priv->ifname_mon, name, IFNAMSIZ+1); ++ ++out: ++ if (ret && mon_wdev) { ++ rtw_mfree((u8*)mon_wdev, sizeof(struct wireless_dev)); ++ mon_wdev = NULL; ++ } ++ ++ if (ret && mon_ndev) { ++ free_netdev(mon_ndev); ++ *ndev = mon_ndev = NULL; ++ } ++ ++ return ret; ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)) ++static struct wireless_dev * ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) || defined(COMPAT_KERNEL_RELEASE) ++static struct net_device * ++#else ++static int ++#endif ++ cfg80211_rtw_add_virtual_intf( ++ struct wiphy *wiphy, ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)) ++ const char *name, ++ #else ++ char *name, ++ #endif ++ enum nl80211_iftype type, u32 *flags, struct vif_params *params) ++{ ++ int ret = 0; ++ struct net_device* ndev = NULL; ++ _adapter *padapter = wiphy_to_adapter(wiphy); ++ ++ DBG_871X(FUNC_ADPT_FMT " wiphy:%s, name:%s, type:%d\n", ++ FUNC_ADPT_ARG(padapter), wiphy_name(wiphy), name, type); ++ ++ switch (type) { ++ case NL80211_IFTYPE_ADHOC: ++ case NL80211_IFTYPE_AP_VLAN: ++ case NL80211_IFTYPE_WDS: ++ case NL80211_IFTYPE_MESH_POINT: ++ ret = -ENODEV; ++ break; ++ case NL80211_IFTYPE_MONITOR: ++ ret = rtw_cfg80211_add_monitor_if(padapter, (char *)name, &ndev); ++ break; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++ case NL80211_IFTYPE_P2P_CLIENT: ++#endif ++ case NL80211_IFTYPE_STATION: ++ ret = -ENODEV; ++ break; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++ case NL80211_IFTYPE_P2P_GO: ++#endif ++ case NL80211_IFTYPE_AP: ++ ret = -ENODEV; ++ break; ++ default: ++ ret = -ENODEV; ++ DBG_871X("Unsupported interface type\n"); ++ break; ++ } ++ ++ DBG_871X(FUNC_ADPT_FMT" ndev:%p, ret:%d\n", FUNC_ADPT_ARG(padapter), ndev, ret); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)) ++ return ndev ? ndev->ieee80211_ptr : ERR_PTR(ret); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) || defined(COMPAT_KERNEL_RELEASE) ++ return ndev ? ndev : ERR_PTR(ret); ++#else ++ return ret; ++#endif ++} ++ ++static int cfg80211_rtw_del_virtual_intf(struct wiphy *wiphy, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)) ++ struct wireless_dev *wdev ++#else ++ struct net_device *ndev ++#endif ++) ++{ ++ struct rtw_wdev_priv *pwdev_priv = (struct rtw_wdev_priv *)wiphy_priv(wiphy); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)) ++ struct net_device *ndev; ++ ndev = wdev ? wdev->netdev : NULL; ++#endif ++ ++ if (!ndev) ++ goto exit; ++ ++ unregister_netdevice(ndev); ++ ++ if (ndev == pwdev_priv->pmon_ndev) { ++ pwdev_priv->pmon_ndev = NULL; ++ pwdev_priv->ifname_mon[0] = '\0'; ++ DBG_871X(FUNC_NDEV_FMT" remove monitor interface\n", FUNC_NDEV_ARG(ndev)); ++ } ++ ++exit: ++ return 0; ++} ++ ++static int rtw_add_beacon(_adapter *adapter, const u8 *head, size_t head_len, const u8 *tail, size_t tail_len) ++{ ++ int ret=0; ++ u8 *pbuf = NULL; ++ uint len, wps_ielen=0; ++ uint p2p_ielen=0; ++ u8 *p2p_ie; ++ u8 got_p2p_ie = _FALSE; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ //struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ ++ DBG_8192C("%s beacon_head_len=%zu, beacon_tail_len=%zu\n", __FUNCTION__, head_len, tail_len); ++ ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE) ++ return -EINVAL; ++ ++ if(head_len<24) ++ return -EINVAL; ++ ++ ++ pbuf = rtw_zmalloc(head_len+tail_len); ++ if(!pbuf) ++ return -ENOMEM; ++ ++ ++ //_rtw_memcpy(&pstapriv->max_num_sta, param->u.bcn_ie.reserved, 2); ++ ++ //if((pstapriv->max_num_sta>NUM_STA) || (pstapriv->max_num_sta<=0)) ++ // pstapriv->max_num_sta = NUM_STA; ++ ++ ++ _rtw_memcpy(pbuf, (void *)head+24, head_len-24);// 24=beacon header len. ++ _rtw_memcpy(pbuf+head_len-24, (void *)tail, tail_len); ++ ++ len = head_len+tail_len-24; ++ ++ //check wps ie if inclued ++ if(rtw_get_wps_ie(pbuf+_FIXED_IE_LENGTH_, len-_FIXED_IE_LENGTH_, NULL, &wps_ielen)) ++ DBG_8192C("add bcn, wps_ielen=%d\n", wps_ielen); ++ ++#ifdef CONFIG_P2P ++ //check p2p ie if inclued ++ if( adapter->wdinfo.driver_interface == DRIVER_CFG80211 ) ++ { ++ //check p2p if enable ++ if(rtw_get_p2p_ie(pbuf+_FIXED_IE_LENGTH_, len-_FIXED_IE_LENGTH_, NULL, &p2p_ielen)) ++ { ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ struct wifidirect_info *pwdinfo= &(adapter->wdinfo); ++ ++ DBG_8192C("got p2p_ie, len=%d\n", p2p_ielen); ++ got_p2p_ie = _TRUE; ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ DBG_8192C("Enable P2P function for the first time\n"); ++ rtw_p2p_enable(adapter, P2P_ROLE_GO); ++ wdev_to_priv(adapter->rtw_wdev)->p2p_enabled = _TRUE; ++ } ++ else ++ { ++ DBG_8192C("enter GO Mode, p2p_ielen=%d\n", p2p_ielen); ++ ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ pwdinfo->intent = 15; ++ } ++ } ++ } ++#endif // CONFIG_P2P ++ ++ /* pbss_network->IEs will not include p2p_ie, wfd ie */ ++ rtw_ies_remove_ie(pbuf, &len, _BEACON_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, P2P_OUI, 4); ++ rtw_ies_remove_ie(pbuf, &len, _BEACON_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, WFD_OUI, 4); ++ ++ if (rtw_check_beacon_data(adapter, pbuf, len) == _SUCCESS) ++ { ++#ifdef CONFIG_P2P ++ //check p2p if enable ++ if(got_p2p_ie == _TRUE) ++ { ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ struct wifidirect_info *pwdinfo= &(adapter->wdinfo); ++ pwdinfo->operating_channel = pmlmeext->cur_channel; ++ } ++#endif //CONFIG_P2P ++ ret = 0; ++ } ++ else ++ { ++ ret = -EINVAL; ++ } ++ ++ ++ rtw_mfree(pbuf, head_len+tail_len); ++ ++ return ret; ++} ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) && !defined(COMPAT_KERNEL_RELEASE) ++static int cfg80211_rtw_add_beacon(struct wiphy *wiphy, struct net_device *ndev, ++ struct beacon_parameters *info) ++{ ++ int ret=0; ++ _adapter *adapter = wiphy_to_adapter(wiphy); ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ret = rtw_add_beacon(adapter, info->head, info->head_len, info->tail, info->tail_len); ++ ++ return ret; ++} ++ ++static int cfg80211_rtw_set_beacon(struct wiphy *wiphy, struct net_device *ndev, ++ struct beacon_parameters *info) ++{ ++ _adapter *padapter = wiphy_to_adapter(wiphy); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ pmlmeext->bstart_bss = _TRUE; ++ ++ cfg80211_rtw_add_beacon(wiphy, ndev, info); ++ ++ return 0; ++} ++ ++static int cfg80211_rtw_del_beacon(struct wiphy *wiphy, struct net_device *ndev) ++{ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ return 0; ++} ++#else ++static int cfg80211_rtw_start_ap(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_ap_settings *settings) ++{ ++ int ret = 0; ++ _adapter *adapter = wiphy_to_adapter(wiphy); ++ ++ DBG_871X(FUNC_NDEV_FMT" hidden_ssid:%d, auth_type:%d\n", FUNC_NDEV_ARG(ndev), ++ settings->hidden_ssid, settings->auth_type); ++ ++ ret = rtw_add_beacon(adapter, settings->beacon.head, settings->beacon.head_len, ++ settings->beacon.tail, settings->beacon.tail_len); ++ ++ adapter->mlmeextpriv.mlmext_info.hidden_ssid_mode = settings->hidden_ssid; ++ ++ if (settings->ssid && settings->ssid_len) { ++ WLAN_BSSID_EX *pbss_network = &adapter->mlmepriv.cur_network.network; ++ WLAN_BSSID_EX *pbss_network_ext = &adapter->mlmeextpriv.mlmext_info.network; ++ ++ if(0) ++ DBG_871X(FUNC_ADPT_FMT" ssid:(%s,%d), from ie:(%s,%d)\n", FUNC_ADPT_ARG(adapter), ++ settings->ssid, settings->ssid_len, ++ pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength); ++ ++ _rtw_memcpy(pbss_network->Ssid.Ssid, (void *)settings->ssid, settings->ssid_len); ++ pbss_network->Ssid.SsidLength = settings->ssid_len; ++ _rtw_memcpy(pbss_network_ext->Ssid.Ssid, (void *)settings->ssid, settings->ssid_len); ++ pbss_network_ext->Ssid.SsidLength = settings->ssid_len; ++ ++ if(0) ++ DBG_871X(FUNC_ADPT_FMT" after ssid:(%s,%d), (%s,%d)\n", FUNC_ADPT_ARG(adapter), ++ pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength, ++ pbss_network_ext->Ssid.Ssid, pbss_network_ext->Ssid.SsidLength); ++ } ++ ++ return ret; ++} ++ ++static int cfg80211_rtw_change_beacon(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_beacon_data *info) ++{ ++ int ret = 0; ++ _adapter *adapter = wiphy_to_adapter(wiphy); ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ ret = rtw_add_beacon(adapter, info->head, info->head_len, info->tail, info->tail_len); ++ ++ return ret; ++} ++ ++static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev) ++{ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ return 0; ++} ++ ++#endif //(LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) ++ ++static int cfg80211_rtw_add_station(struct wiphy *wiphy, struct net_device *ndev, ++ u8 *mac, struct station_parameters *params) ++{ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ return 0; ++} ++ ++static int cfg80211_rtw_del_station(struct wiphy *wiphy, struct net_device *ndev, ++ u8 *mac) ++{ ++ int ret=0; ++ _irqL irqL; ++ _list *phead, *plist; ++ u8 updated; ++ struct sta_info *psta = NULL; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_871X("+"FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ if(check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != _TRUE) ++ { ++ DBG_8192C("%s, fw_state != FW_LINKED|WIFI_AP_STATE\n", __func__); ++ return -EINVAL; ++ } ++ ++ ++ if(!mac) ++ { ++ DBG_8192C("flush all sta, and cam_entry\n"); ++ ++ flush_all_cam_entry(padapter); //clear CAM ++ ++ ret = rtw_sta_flush(padapter); ++ ++ return ret; ++ } ++ ++ ++ DBG_8192C("free sta macaddr =" MAC_FMT "\n", MAC_ARG(mac)); ++ ++ if (mac[0] == 0xff && mac[1] == 0xff && ++ mac[2] == 0xff && mac[3] == 0xff && ++ mac[4] == 0xff && mac[5] == 0xff) ++ { ++ return -EINVAL; ++ } ++ ++ ++ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ ++ //check asoc_queue ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ ++ plist = get_next(plist); ++ ++ if(_rtw_memcmp(mac, psta->hwaddr, ETH_ALEN)) ++ { ++ if(psta->dot8021xalg == 1 && psta->bpairwise_key_installed == _FALSE) ++ { ++ DBG_8192C("%s, sta's dot8021xalg = 1 and key_installed = _FALSE\n", __func__); ++ } ++ else ++ { ++ DBG_8192C("free psta=%p, aid=%d\n", psta, psta->aid); ++ ++ rtw_list_delete(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ ++ //_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ updated = ap_free_sta(padapter, psta, _TRUE, WLAN_REASON_DEAUTH_LEAVING); ++ //_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ psta = NULL; ++ ++ break; ++ } ++ ++ } ++ ++ } ++ ++ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ associated_clients_update(padapter, updated); ++ ++ DBG_871X("-"FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ return ret; ++ ++} ++ ++static int cfg80211_rtw_change_station(struct wiphy *wiphy, struct net_device *ndev, ++ u8 *mac, struct station_parameters *params) ++{ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ return 0; ++} ++ ++static int cfg80211_rtw_dump_station(struct wiphy *wiphy, struct net_device *ndev, ++ int idx, u8 *mac, struct station_info *sinfo) ++{ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ //TODO: dump scanned queue ++ ++ return -ENOENT; ++} ++ ++static int cfg80211_rtw_change_bss(struct wiphy *wiphy, struct net_device *ndev, ++ struct bss_parameters *params) ++{ ++ u8 i; ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++/* ++ DBG_8192C("use_cts_prot=%d\n", params->use_cts_prot); ++ DBG_8192C("use_short_preamble=%d\n", params->use_short_preamble); ++ DBG_8192C("use_short_slot_time=%d\n", params->use_short_slot_time); ++ DBG_8192C("ap_isolate=%d\n", params->ap_isolate); ++ ++ DBG_8192C("basic_rates_len=%d\n", params->basic_rates_len); ++ for(i=0; ibasic_rates_len; i++) ++ { ++ DBG_8192C("basic_rates=%d\n", params->basic_rates[i]); ++ ++ } ++*/ ++ return 0; ++ ++} ++ ++static int cfg80211_rtw_set_channel(struct wiphy *wiphy ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) ++ , struct net_device *ndev ++ #endif ++ , struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) ++{ ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ #endif ++ ++ return 0; ++} ++ ++static int cfg80211_rtw_auth(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_auth_request *req) ++{ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ return 0; ++} ++ ++static int cfg80211_rtw_assoc(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_assoc_request *req) ++{ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ return 0; ++} ++#endif //CONFIG_AP_MODE ++ ++void rtw_cfg80211_rx_action_p2p(_adapter *padapter, u8 *pmgmt_frame, uint frame_len) ++{ ++ int type; ++ s32 freq; ++ int channel; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ u8 category, action; ++ ++ channel = rtw_get_oper_ch(padapter); ++ ++ DBG_8192C("RTW_Rx:cur_ch=%d\n", channel); ++ #ifdef CONFIG_P2P ++ type = rtw_p2p_check_frames(padapter, pmgmt_frame, frame_len, _FALSE); ++ if (type >= 0) ++ goto indicate; ++ #endif ++ rtw_action_frame_parse(pmgmt_frame, frame_len, &category, &action); ++ DBG_871X("RTW_Rx:category(%u), action(%u)\n", category, action); ++ ++indicate: ++ if (channel <= RTW_CH_MAX_2G_CHANNEL) ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); ++ else ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++ rtw_cfg80211_rx_mgmt(padapter, freq, 0, pmgmt_frame, frame_len, GFP_ATOMIC); ++#else ++ cfg80211_rx_action(padapter->pnetdev, freq, pmgmt_frame, frame_len, GFP_ATOMIC); ++#endif ++} ++ ++void rtw_cfg80211_rx_p2p_action_public(_adapter *padapter, u8 *pmgmt_frame, uint frame_len) ++{ ++ int type; ++ s32 freq; ++ int channel; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ u8 category, action; ++ ++ channel = rtw_get_oper_ch(padapter); ++ ++ DBG_8192C("RTW_Rx:cur_ch=%d\n", channel); ++ #ifdef CONFIG_P2P ++ type = rtw_p2p_check_frames(padapter, pmgmt_frame, frame_len, _FALSE); ++ if (type >= 0) { ++ switch (type) { ++ case P2P_GO_NEGO_CONF: ++ case P2P_PROVISION_DISC_RESP: ++ case P2P_INVIT_RESP: ++ rtw_set_scan_deny(padapter, 2000); ++ rtw_clear_scan_deny(padapter); ++ } ++ goto indicate; ++ } ++ #endif ++ rtw_action_frame_parse(pmgmt_frame, frame_len, &category, &action); ++ DBG_871X("RTW_Rx:category(%u), action(%u)\n", category, action); ++ ++indicate: ++ if (channel <= RTW_CH_MAX_2G_CHANNEL) ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); ++ else ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++ rtw_cfg80211_rx_mgmt(padapter, freq, 0, pmgmt_frame, frame_len, GFP_ATOMIC); ++#else ++ cfg80211_rx_action(padapter->pnetdev, freq, pmgmt_frame, frame_len, GFP_ATOMIC); ++#endif ++} ++ ++void rtw_cfg80211_rx_action(_adapter *adapter, u8 *frame, uint frame_len, const char*msg) ++{ ++ s32 freq; ++ int channel; ++ struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv); ++ struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(adapter->rtw_wdev); ++ u8 category, action; ++ ++ channel = rtw_get_oper_ch(adapter); ++ ++ rtw_action_frame_parse(frame, frame_len, &category, &action); ++ ++ DBG_8192C("RTW_Rx:cur_ch=%d\n", channel); ++ if (msg) ++ DBG_871X("RTW_Rx:%s\n", msg); ++ else ++ DBG_871X("RTW_Rx:category(%u), action(%u)\n", category, action); ++ ++ if (channel <= RTW_CH_MAX_2G_CHANNEL) ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); ++ else ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++ rtw_cfg80211_rx_mgmt(adapter, freq, 0, frame, frame_len, GFP_ATOMIC); ++#else ++ cfg80211_rx_action(adapter->pnetdev, freq, frame, frame_len, GFP_ATOMIC); ++#endif ++ ++} ++ ++#ifdef CONFIG_P2P ++void rtw_cfg80211_issue_p2p_provision_request(_adapter *padapter, const u8 *buf, size_t len) ++{ ++ u16 wps_devicepassword_id = 0x0000; ++ uint wps_devicepassword_id_len = 0; ++ u8 wpsie[ 255 ] = { 0x00 }, p2p_ie[ 255 ] = { 0x00 }; ++ uint p2p_ielen = 0; ++ uint wpsielen = 0; ++ u32 devinfo_contentlen = 0; ++ u8 devinfo_content[64] = { 0x00 }; ++ u16 capability = 0; ++ uint capability_len = 0; ++ ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ u8 dialogToken = 1; ++ u32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_PROVISION_DISC_REQ; ++ u32 p2pielen = 0; ++#ifdef CONFIG_WFD ++ u32 wfdielen = 0; ++#endif //CONFIG_WFD ++ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ unsigned short *fctrl; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); ++ u8 *frame_body = (unsigned char *)(buf + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ size_t frame_body_len = len - sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ ++ DBG_871X( "[%s] In\n", __FUNCTION__ ); ++ ++ //prepare for building provision_request frame ++ _rtw_memcpy(pwdinfo->tx_prov_disc_info.peerIFAddr, GetAddr1Ptr(buf), ETH_ALEN); ++ _rtw_memcpy(pwdinfo->tx_prov_disc_info.peerDevAddr, GetAddr1Ptr(buf), ETH_ALEN); ++ ++ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_PUSH_BUTTON; ++ ++ rtw_get_wps_ie( frame_body + _PUBLIC_ACTION_IE_OFFSET_, frame_body_len - _PUBLIC_ACTION_IE_OFFSET_, wpsie, &wpsielen); ++ rtw_get_wps_attr_content( wpsie, wpsielen, WPS_ATTR_DEVICE_PWID, (u8*) &wps_devicepassword_id, &wps_devicepassword_id_len); ++ wps_devicepassword_id = be16_to_cpu( wps_devicepassword_id ); ++ ++ switch(wps_devicepassword_id) ++ { ++ case WPS_DPID_PIN: ++ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_LABEL; ++ break; ++ case WPS_DPID_USER_SPEC: ++ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_DISPLYA; ++ break; ++ case WPS_DPID_MACHINE_SPEC: ++ break; ++ case WPS_DPID_REKEY: ++ break; ++ case WPS_DPID_PBC: ++ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_PUSH_BUTTON; ++ break; ++ case WPS_DPID_REGISTRAR_SPEC: ++ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_KEYPAD; ++ break; ++ default: ++ break; ++ } ++ ++ ++ if ( rtw_get_p2p_ie( frame_body + _PUBLIC_ACTION_IE_OFFSET_, frame_body_len - _PUBLIC_ACTION_IE_OFFSET_, p2p_ie, &p2p_ielen ) ) ++ { ++ ++ rtw_get_p2p_attr_content( p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO, devinfo_content, &devinfo_contentlen); ++ rtw_get_p2p_attr_content( p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8*)&capability, &capability_len); ++ ++ } ++ ++ ++ //start to build provision_request frame ++ _rtw_memset(wpsie, 0, sizeof(wpsie)); ++ _rtw_memset(p2p_ie, 0, sizeof(p2p_ie)); ++ p2p_ielen = 0; ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_ctl); ++ *(fctrl) = 0; ++ ++ _rtw_memcpy(pwlanhdr->addr1, pwdinfo->tx_prov_disc_info.peerDevAddr, ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ _rtw_memcpy(pwlanhdr->addr3, pwdinfo->tx_prov_disc_info.peerDevAddr, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); ++ ++ ++ //build_prov_disc_request_p2p_ie ++ // P2P OUI ++ p2pielen = 0; ++ p2p_ie[ p2pielen++ ] = 0x50; ++ p2p_ie[ p2pielen++ ] = 0x6F; ++ p2p_ie[ p2pielen++ ] = 0x9A; ++ p2p_ie[ p2pielen++ ] = 0x09; // WFA P2P v1.0 ++ ++ // Commented by Albert 20110301 ++ // According to the P2P Specification, the provision discovery request frame should contain 3 P2P attributes ++ // 1. P2P Capability ++ // 2. Device Info ++ // 3. Group ID ( When joining an operating P2P Group ) ++ ++ // P2P Capability ATTR ++ // Type: ++ p2p_ie[ p2pielen++ ] = P2P_ATTR_CAPABILITY; ++ ++ // Length: ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); ++ RTW_PUT_LE16(p2p_ie + p2pielen, 0x0002); ++ p2pielen += 2; ++ ++ // Value: ++ // Device Capability Bitmap, 1 byte ++ // Group Capability Bitmap, 1 byte ++ _rtw_memcpy(p2p_ie + p2pielen, &capability, 2); ++ p2pielen += 2; ++ ++ ++ // Device Info ATTR ++ // Type: ++ p2p_ie[ p2pielen++ ] = P2P_ATTR_DEVICE_INFO; ++ ++ // Length: ++ // 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) ++ // + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) ++ //*(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 21 + pwdinfo->device_name_len ); ++ RTW_PUT_LE16(p2p_ie + p2pielen, devinfo_contentlen); ++ p2pielen += 2; ++ ++ // Value: ++ _rtw_memcpy(p2p_ie + p2pielen, devinfo_content, devinfo_contentlen); ++ p2pielen += devinfo_contentlen; ++ ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2p_ie, &p2p_ielen); ++ //p2pielen = build_prov_disc_request_p2p_ie( pwdinfo, pframe, NULL, 0, pwdinfo->tx_prov_disc_info.peerDevAddr); ++ //pframe += p2pielen; ++ pattrib->pktlen += p2p_ielen; ++ ++ wpsielen = 0; ++ // WPS OUI ++ *(u32*) ( wpsie ) = cpu_to_be32( WPSOUI ); ++ wpsielen += 4; ++ ++ // WPS version ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_VER1 ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0001 ); ++ wpsielen += 2; ++ ++ // Value: ++ wpsie[wpsielen++] = WPS_VERSION_1; // Version 1.0 ++ ++ // Config Method ++ // Type: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_CONF_METHOD ); ++ wpsielen += 2; ++ ++ // Length: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0002 ); ++ wpsielen += 2; ++ ++ // Value: ++ *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( pwdinfo->tx_prov_disc_info.wps_config_method_request ); ++ wpsielen += 2; ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen ); ++ ++ ++#ifdef CONFIG_WFD ++ wfdielen = build_provdisc_req_wfd_ie(pwdinfo, pframe); ++ pframe += wfdielen; ++ pattrib->pktlen += wfdielen; ++#endif //CONFIG_WFD ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ //dump_mgntframe(padapter, pmgntframe); ++ if (dump_mgntframe_and_wait_ack(padapter, pmgntframe) != _SUCCESS) ++ DBG_8192C("%s, ack to\n", __func__); ++ ++ //if(wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) ++ //{ ++ // DBG_8192C("waiting for p2p peer key-in PIN CODE\n"); ++ // rtw_msleep_os(15000); // 15 sec for key in PIN CODE, workaround for GS2 before issuing Nego Req. ++ //} ++ ++} ++ ++static s32 cfg80211_rtw_remain_on_channel(struct wiphy *wiphy, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)) ++ struct wireless_dev *wdev, ++#else ++ struct net_device *ndev, ++#endif ++ struct ieee80211_channel * channel, ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)) ++ enum nl80211_channel_type channel_type, ++#endif ++ unsigned int duration, u64 *cookie) ++{ ++ s32 err = 0; ++ _adapter *padapter = wiphy_to_adapter(wiphy); ++ struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; ++ u8 remain_ch = (u8) ieee80211_frequency_to_channel(channel->center_freq); ++ u8 ready_on_channel = _FALSE; ++ ++ DBG_871X(FUNC_ADPT_FMT" ch:%u duration:%d\n", FUNC_ADPT_ARG(padapter), remain_ch, duration); ++ ++ if(pcfg80211_wdinfo->is_ro_ch == _TRUE) ++ { ++ DBG_8192C("%s, cancel ro ch timer\n", __func__); ++ ++ _cancel_timer_ex(&padapter->cfg80211_wdinfo.remain_on_ch_timer); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ ATOMIC_SET(&pwdev_priv->ro_ch_to, 1); ++#endif //CONFIG_CONCURRENT_MODE ++ ++ p2p_protocol_wk_hdl(padapter, P2P_RO_CH_WK); ++ } ++ ++ pcfg80211_wdinfo->is_ro_ch = _TRUE; ++ ++ if(_FAIL == rtw_pwr_wakeup(padapter)) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ _rtw_memcpy(&pcfg80211_wdinfo->remain_on_ch_channel, channel, sizeof(struct ieee80211_channel)); ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)) ++ pcfg80211_wdinfo->remain_on_ch_type= channel_type; ++ #endif ++ pcfg80211_wdinfo->remain_on_ch_cookie= *cookie; ++ ++ rtw_scan_abort(padapter); ++#ifdef CONFIG_CONCURRENT_MODE ++ if(rtw_buddy_adapter_up(padapter)) ++ rtw_scan_abort(padapter->pbuddy_adapter); ++#endif //CONFIG_CONCURRENT_MODE ++ ++ //if(!rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) && !rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ rtw_p2p_enable(padapter, P2P_ROLE_DEVICE); ++ wdev_to_priv(padapter->rtw_wdev)->p2p_enabled = _TRUE; ++ padapter->wdinfo.listen_channel = remain_ch; ++ } ++ else ++ { ++ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s, role=%d, p2p_state=%d\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo)); ++#endif ++ } ++ ++ ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); ++ ++ ++ if(duration < 400) ++ duration = duration*3;//extend from exper. ++ ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(check_buddy_fwstate(padapter, _FW_LINKED) && ++ (durationext_listen_interval)) ++ { ++ duration = duration + pwdinfo->ext_listen_interval; ++ } ++#endif ++ ++ pcfg80211_wdinfo->restore_channel = rtw_get_oper_ch(padapter); ++ ++ if(rtw_ch_set_search_ch(pmlmeext->channel_set, remain_ch) >= 0) { ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_buddy_fwstate(padapter, _FW_LINKED ) ) ++ { ++ PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ ++ if(remain_ch != pbuddy_mlmeext->cur_channel) ++ { ++ if(ATOMIC_READ(&pwdev_priv->switch_ch_to)==1 || ++ (remain_ch != pmlmeext->cur_channel)) ++ { ++ DBG_8192C("%s, issue nulldata pwrbit=1\n", __func__); ++ issue_nulldata(padapter->pbuddy_adapter, NULL, 1, 3, 500); ++ ++ ATOMIC_SET(&pwdev_priv->switch_ch_to, 0); ++ ++ DBG_8192C("%s, set switch ch timer, duration=%d\n", __func__, duration-pwdinfo->ext_listen_interval); ++ _set_timer(&pwdinfo->ap_p2p_switch_timer, duration-pwdinfo->ext_listen_interval); ++ } ++ } ++ ++ ready_on_channel = _TRUE; ++ //pmlmeext->cur_channel = remain_ch; ++ //set_channel_bwmode(padapter, remain_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ }else ++#endif //CONFIG_CONCURRENT_MODE ++ if(remain_ch != rtw_get_oper_ch(padapter) ) ++ { ++ ready_on_channel = _TRUE; ++ //pmlmeext->cur_channel = remain_ch; ++ //set_channel_bwmode(padapter, remain_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ } ++ } else { ++ DBG_871X("%s remain_ch:%u not in channel plan!!!!\n", __FUNCTION__, remain_ch); ++ } ++ ++ ++ //call this after other things have been done ++#ifdef CONFIG_CONCURRENT_MODE ++ if(ATOMIC_READ(&pwdev_priv->ro_ch_to)==1 || ++ (remain_ch != rtw_get_oper_ch(padapter))) ++ { ++ u8 co_channel = 0xff; ++ ATOMIC_SET(&pwdev_priv->ro_ch_to, 0); ++#endif ++ ++ if(ready_on_channel == _TRUE) ++ { ++ if ( !check_fwstate(&padapter->mlmepriv, _FW_LINKED ) ) ++ { ++ pmlmeext->cur_channel = remain_ch; ++ ++ ++ set_channel_bwmode(padapter, remain_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ } ++ } ++ DBG_8192C("%s, set ro ch timer, duration=%d\n", __func__, duration); ++ _set_timer( &pcfg80211_wdinfo->remain_on_ch_timer, duration); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ } ++#endif ++ ++ rtw_cfg80211_ready_on_channel(padapter, *cookie, channel, channel_type, duration, GFP_KERNEL); ++ ++exit: ++ if (err) ++ pcfg80211_wdinfo->is_ro_ch = _FALSE; ++ ++ return err; ++} ++ ++static s32 cfg80211_rtw_cancel_remain_on_channel(struct wiphy *wiphy, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)) ++ struct wireless_dev *wdev, ++#else ++ struct net_device *ndev, ++#endif ++ u64 cookie) ++{ ++ s32 err = 0; ++ _adapter *padapter = wiphy_to_adapter(wiphy); ++ struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; ++ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++ ++ if (pcfg80211_wdinfo->is_ro_ch == _TRUE) { ++ DBG_8192C("%s, cancel ro ch timer\n", __func__); ++ _cancel_timer_ex(&padapter->cfg80211_wdinfo.remain_on_ch_timer); ++ #ifdef CONFIG_CONCURRENT_MODE ++ ATOMIC_SET(&pwdev_priv->ro_ch_to, 1); ++ #endif ++ p2p_protocol_wk_hdl(padapter, P2P_RO_CH_WK); ++ } ++ ++ #if 0 ++ // Disable P2P Listen State ++ if(!rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) && !rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ { ++ if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE); ++ _rtw_memset(pwdinfo, 0x00, sizeof(struct wifidirect_info)); ++ } ++ } ++ else ++ #endif ++ { ++ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s, role=%d, p2p_state=%d\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo)); ++#endif ++ } ++ pcfg80211_wdinfo->is_ro_ch = _FALSE; ++ ++ return err; ++} ++ ++#endif //CONFIG_P2P ++ ++static int _cfg80211_rtw_mgmt_tx(_adapter *padapter, u8 tx_ch, const u8 *buf, size_t len) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ int ret = _FAIL; ++ bool ack = _TRUE; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ //struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; ++ ++ if(_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret = -EFAULT; ++ goto exit; ++ } ++ ++ rtw_set_scan_deny(padapter, 1000); ++ ++ rtw_scan_abort(padapter); ++ #ifdef CONFIG_CONCURRENT_MODE ++ if(rtw_buddy_adapter_up(padapter)) ++ rtw_scan_abort(padapter->pbuddy_adapter); ++ #endif /* CONFIG_CONCURRENT_MODE */ ++ ++ if (padapter->cfg80211_wdinfo.is_ro_ch == _TRUE) { ++ //DBG_8192C("%s, cancel ro ch timer\n", __func__); ++ //_cancel_timer_ex(&padapter->cfg80211_wdinfo.remain_on_ch_timer); ++ //padapter->cfg80211_wdinfo.is_ro_ch = _FALSE; ++ #ifdef CONFIG_CONCURRENT_MODE ++ if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED )) ++ { ++ DBG_8192C("%s, extend ro ch time\n", __func__); ++ _set_timer( &padapter->cfg80211_wdinfo.remain_on_ch_timer, pwdinfo->ext_listen_period); ++ } ++ #endif //CONFIG_CONCURRENT_MODE ++ } ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (check_buddy_fwstate(padapter, _FW_LINKED )) { ++ u8 co_channel=0xff; ++ PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ ++ co_channel = rtw_get_oper_ch(padapter); ++ ++ if (tx_ch != pbuddy_mlmeext->cur_channel) { ++ ++ u16 ext_listen_period; ++ ++ if (ATOMIC_READ(&pwdev_priv->switch_ch_to)==1) { ++ DBG_8192C("%s, issue nulldata pwrbit=1\n", __func__); ++ issue_nulldata(padapter->pbuddy_adapter, NULL, 1, 3, 500); ++ ++ ATOMIC_SET(&pwdev_priv->switch_ch_to, 0); ++ ++ //DBG_8192C("%s, set switch ch timer, period=%d\n", __func__, pwdinfo->ext_listen_period); ++ //_set_timer(&pwdinfo->ap_p2p_switch_timer, pwdinfo->ext_listen_period); ++ } ++ ++ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED )) ++ { ++ ext_listen_period = 500;// 500ms ++ } ++ else ++ { ++ ext_listen_period = pwdinfo->ext_listen_period; ++ } ++ ++ DBG_8192C("%s, set switch ch timer, period=%d\n", __func__, ext_listen_period); ++ _set_timer(&pwdinfo->ap_p2p_switch_timer, ext_listen_period); ++ ++ } ++ ++ if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED )) ++ pmlmeext->cur_channel = tx_ch; ++ ++ if (tx_ch != co_channel) ++ set_channel_bwmode(padapter, tx_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ }else ++#endif //CONFIG_CONCURRENT_MODE ++ //if (tx_ch != pmlmeext->cur_channel) { ++ if(tx_ch != rtw_get_oper_ch(padapter)) { ++ if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED )) ++ pmlmeext->cur_channel = tx_ch; ++ set_channel_bwmode(padapter, tx_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ } ++ ++ //starting alloc mgmt frame to dump it ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ //ret = -ENOMEM; ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ //update attribute ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->retry_ctrl = _FALSE; ++ ++ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ ++ _rtw_memcpy(pframe, (void*)buf, len); ++ pattrib->pktlen = len; ++ ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ //update seq number ++ pmlmeext->mgnt_seq = GetSequence(pwlanhdr); ++ pattrib->seqnum = pmlmeext->mgnt_seq; ++ pmlmeext->mgnt_seq++; ++ ++#ifdef CONFIG_WFD ++ { ++ struct wifi_display_info *pwfd_info; ++ ++ pwfd_info = padapter->wdinfo.wfd_info; ++ ++ if ( _TRUE == pwfd_info->wfd_enable ) ++ { ++ rtw_append_wfd_ie( padapter, pframe, &pattrib->pktlen ); ++ } ++ } ++#endif // CONFIG_WFD ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ if (dump_mgntframe_and_wait_ack(padapter, pmgntframe) != _SUCCESS) ++ { ++ ack = _FALSE; ++ ret = _FAIL; ++ ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s, ack == _FAIL\n", __func__); ++ #endif ++ } ++ else ++ { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s, ack=%d, ok!\n", __func__, ack); ++ #endif ++ ret = _SUCCESS; ++ } ++ ++exit: ++ ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s, ret=%d\n", __func__, ret); ++ #endif ++ ++ return ret; ++ ++} ++ ++static int cfg80211_rtw_mgmt_tx(struct wiphy *wiphy, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)) ++ struct wireless_dev *wdev, ++#else ++ struct net_device *ndev, ++#endif ++ struct ieee80211_channel *chan, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) || defined(COMPAT_KERNEL_RELEASE) ++ bool offchan, ++#endif ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)) ++ enum nl80211_channel_type channel_type, ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++ bool channel_type_valid, ++ #endif ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) || defined(COMPAT_KERNEL_RELEASE) ++ unsigned int wait, ++#endif ++ const u8 *buf, size_t len, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) ++ bool no_cck, ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)) ++ bool dont_wait_for_ack, ++#endif ++ u64 *cookie) ++{ ++ _adapter *padapter = (_adapter *)wiphy_to_adapter(wiphy); ++ struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); ++ int ret = 0; ++ int tx_ret; ++ u32 dump_limit = RTW_MAX_MGMT_TX_CNT; ++ u32 dump_cnt = 0; ++ bool ack = _TRUE; ++ u8 tx_ch = (u8)ieee80211_frequency_to_channel(chan->center_freq); ++ u8 category, action; ++ int type = (-1); ++ u32 start = rtw_get_current_time(); ++ ++ /* cookie generation */ ++ *cookie = (unsigned long) buf; ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X(FUNC_ADPT_FMT" len=%zu, ch=%d" ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)) ++ ", ch_type=%d" ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++ ", channel_type_valid=%d" ++ #endif ++ #endif ++ "\n", FUNC_ADPT_ARG(padapter), ++ len, tx_ch ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)) ++ , channel_type ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++ , channel_type_valid ++ #endif ++ #endif ++ ); ++#endif /* CONFIG_DEBUG_CFG80211 */ ++ ++ /* indicate ack before issue frame to avoid racing with rsp frame */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++ rtw_cfg80211_mgmt_tx_status(padapter, *cookie, buf, len, ack, GFP_KERNEL); ++#elif (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,34) && LINUX_VERSION_CODE<=KERNEL_VERSION(2,6,35)) ++ cfg80211_action_tx_status(ndev, *cookie, buf, len, ack, GFP_KERNEL); ++#endif ++ ++ if (rtw_action_frame_parse(buf, len, &category, &action) == _FALSE) { ++ DBG_8192C(FUNC_ADPT_FMT" frame_control:0x%x\n", FUNC_ADPT_ARG(padapter), ++ le16_to_cpu(((struct rtw_ieee80211_hdr_3addr *)buf)->frame_ctl)); ++ goto exit; ++ } ++ ++ DBG_8192C("RTW_Tx:tx_ch=%d, da="MAC_FMT"\n", tx_ch, MAC_ARG(GetAddr1Ptr(buf))); ++ #ifdef CONFIG_P2P ++ if((type = rtw_p2p_check_frames(padapter, buf, len, _TRUE)) >= 0) { ++ goto dump; ++ } ++ #endif ++ if (category == RTW_WLAN_CATEGORY_PUBLIC) ++ DBG_871X("RTW_Tx:%s\n", action_public_str(action)); ++ else ++ DBG_871X("RTW_Tx:category(%u), action(%u)\n", category, action); ++ ++dump: ++ do { ++ dump_cnt++; ++ tx_ret = _cfg80211_rtw_mgmt_tx(padapter, tx_ch, buf, len); ++ } while (dump_cnt < dump_limit && tx_ret != _SUCCESS); ++ ++ if (tx_ret != _SUCCESS || dump_cnt > 1) { ++ DBG_871X(FUNC_ADPT_FMT" %s (%d/%d) in %d ms\n", FUNC_ADPT_ARG(padapter), ++ tx_ret==_SUCCESS?"OK":"FAIL", dump_cnt, dump_limit, rtw_get_passing_time_ms(start)); ++ } ++ ++ switch (type) { ++ case P2P_GO_NEGO_CONF: ++ rtw_clear_scan_deny(padapter); ++ break; ++ case P2P_INVIT_RESP: ++ if (pwdev_priv->invit_info.flags & BIT(0) ++ && pwdev_priv->invit_info.status == 0) ++ { ++ DBG_871X(FUNC_ADPT_FMT" agree with invitation of persistent group\n", ++ FUNC_ADPT_ARG(padapter)); ++ rtw_set_scan_deny(padapter, 5000); ++ rtw_pwr_wakeup_ex(padapter, 5000); ++ rtw_clear_scan_deny(padapter); ++ } ++ break; ++ } ++ ++exit: ++ return ret; ++} ++ ++static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) ++ struct wireless_dev *wdev, ++#else ++ struct net_device *ndev, ++#endif ++ u16 frame_type, bool reg) ++{ ++ _adapter *adapter = wiphy_to_adapter(wiphy); ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X(FUNC_ADPT_FMT" frame_type:%x, reg:%d\n", FUNC_ADPT_ARG(adapter), ++ frame_type, reg); ++#endif ++ ++ if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) ++ return; ++ ++ return; ++} ++ ++static int rtw_cfg80211_set_beacon_wpsp2pie(struct net_device *ndev, char *buf, int len) ++{ ++ int ret = 0; ++ uint wps_ielen = 0; ++ u8 *wps_ie; ++ u32 p2p_ielen = 0; ++ u8 wps_oui[8]={0x0,0x50,0xf2,0x04}; ++ u8 *p2p_ie; ++ u32 wfd_ielen = 0; ++ u8 *wfd_ie; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ ++ DBG_871X(FUNC_NDEV_FMT" ielen=%d\n", FUNC_NDEV_ARG(ndev), len); ++ ++ if(len>0) ++ { ++ if((wps_ie = rtw_get_wps_ie(buf, len, NULL, &wps_ielen))) ++ { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("bcn_wps_ielen=%d\n", wps_ielen); ++ #endif ++ ++ if(pmlmepriv->wps_beacon_ie) ++ { ++ u32 free_len = pmlmepriv->wps_beacon_ie_len; ++ pmlmepriv->wps_beacon_ie_len = 0; ++ rtw_mfree(pmlmepriv->wps_beacon_ie, free_len); ++ pmlmepriv->wps_beacon_ie = NULL; ++ } ++ ++ pmlmepriv->wps_beacon_ie = rtw_malloc(wps_ielen); ++ if ( pmlmepriv->wps_beacon_ie == NULL) { ++ DBG_8192C("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ return -EINVAL; ++ ++ } ++ ++ _rtw_memcpy(pmlmepriv->wps_beacon_ie, wps_ie, wps_ielen); ++ pmlmepriv->wps_beacon_ie_len = wps_ielen; ++ ++ update_beacon(padapter, _VENDOR_SPECIFIC_IE_, wps_oui, _TRUE); ++ ++ } ++ ++ //buf += wps_ielen; ++ //len -= wps_ielen; ++ ++ #ifdef CONFIG_P2P ++ if((p2p_ie=rtw_get_p2p_ie(buf, len, NULL, &p2p_ielen))) ++ { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("bcn_p2p_ielen=%d\n", p2p_ielen); ++ #endif ++ ++ if(pmlmepriv->p2p_beacon_ie) ++ { ++ u32 free_len = pmlmepriv->p2p_beacon_ie_len; ++ pmlmepriv->p2p_beacon_ie_len = 0; ++ rtw_mfree(pmlmepriv->p2p_beacon_ie, free_len); ++ pmlmepriv->p2p_beacon_ie = NULL; ++ } ++ ++ pmlmepriv->p2p_beacon_ie = rtw_malloc(p2p_ielen); ++ if ( pmlmepriv->p2p_beacon_ie == NULL) { ++ DBG_8192C("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ return -EINVAL; ++ ++ } ++ ++ _rtw_memcpy(pmlmepriv->p2p_beacon_ie, p2p_ie, p2p_ielen); ++ pmlmepriv->p2p_beacon_ie_len = p2p_ielen; ++ ++ } ++ #endif //CONFIG_P2P ++ ++ //buf += p2p_ielen; ++ //len -= p2p_ielen; ++ ++ #ifdef CONFIG_WFD ++ if(rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen)) ++ { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("bcn_wfd_ielen=%d\n", wfd_ielen); ++ #endif ++ ++ if(pmlmepriv->wfd_beacon_ie) ++ { ++ u32 free_len = pmlmepriv->wfd_beacon_ie_len; ++ pmlmepriv->wfd_beacon_ie_len = 0; ++ rtw_mfree(pmlmepriv->wfd_beacon_ie, free_len); ++ pmlmepriv->wfd_beacon_ie = NULL; ++ } ++ ++ pmlmepriv->wfd_beacon_ie = rtw_malloc(wfd_ielen); ++ if ( pmlmepriv->wfd_beacon_ie == NULL) { ++ DBG_8192C("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ return -EINVAL; ++ ++ } ++ rtw_get_wfd_ie(buf, len, pmlmepriv->wfd_beacon_ie, &pmlmepriv->wfd_beacon_ie_len); ++ } ++ #endif //CONFIG_WFD ++ ++ pmlmeext->bstart_bss = _TRUE; ++ ++ } ++ ++ return ret; ++ ++} ++ ++static int rtw_cfg80211_set_probe_resp_wpsp2pie(struct net_device *net, char *buf, int len) ++{ ++ int ret = 0; ++ uint wps_ielen = 0; ++ u8 *wps_ie; ++ u32 p2p_ielen = 0; ++ u8 *p2p_ie; ++ u32 wfd_ielen = 0; ++ u8 *wfd_ie; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(net); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s, ielen=%d\n", __func__, len); ++#endif ++ ++ if(len>0) ++ { ++ if((wps_ie = rtw_get_wps_ie(buf, len, NULL, &wps_ielen))) ++ { ++ uint attr_contentlen = 0; ++ u16 uconfig_method, *puconfig_method = NULL; ++ ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("probe_resp_wps_ielen=%d\n", wps_ielen); ++ #endif ++ ++ if(check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) ++ { ++ u8 sr = 0; ++ rtw_get_wps_attr_content(wps_ie, wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8*)(&sr), NULL); ++ ++ if (sr != 0) ++ { ++ DBG_871X("%s, got sr\n", __func__); ++ } ++ else ++ { ++ DBG_8192C("GO mode process WPS under site-survey, sr no set\n"); ++ return ret; ++ } ++ } ++ ++ if(pmlmepriv->wps_probe_resp_ie) ++ { ++ u32 free_len = pmlmepriv->wps_probe_resp_ie_len; ++ pmlmepriv->wps_probe_resp_ie_len = 0; ++ rtw_mfree(pmlmepriv->wps_probe_resp_ie, free_len); ++ pmlmepriv->wps_probe_resp_ie = NULL; ++ } ++ ++ pmlmepriv->wps_probe_resp_ie = rtw_malloc(wps_ielen); ++ if ( pmlmepriv->wps_probe_resp_ie == NULL) { ++ DBG_8192C("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ return -EINVAL; ++ ++ } ++ ++ //add PUSH_BUTTON config_method by driver self in wpsie of probe_resp at GO Mode ++ if ( (puconfig_method = (u16*)rtw_get_wps_attr_content( wps_ie, wps_ielen, WPS_ATTR_CONF_METHOD , NULL, &attr_contentlen)) != NULL ) ++ { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ //printk("config_method in wpsie of probe_resp = 0x%x\n", be16_to_cpu(*puconfig_method)); ++ #endif ++ ++ uconfig_method = WPS_CM_PUSH_BUTTON; ++ uconfig_method = cpu_to_be16( uconfig_method ); ++ ++ *puconfig_method |= uconfig_method; ++ } ++ ++ _rtw_memcpy(pmlmepriv->wps_probe_resp_ie, wps_ie, wps_ielen); ++ pmlmepriv->wps_probe_resp_ie_len = wps_ielen; ++ ++ } ++ ++ //buf += wps_ielen; ++ //len -= wps_ielen; ++ ++ #ifdef CONFIG_P2P ++ if((p2p_ie=rtw_get_p2p_ie(buf, len, NULL, &p2p_ielen))) ++ { ++ u8 is_GO = _FALSE; ++ u32 attr_contentlen = 0; ++ u16 cap_attr=0; ++ ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("probe_resp_p2p_ielen=%d\n", p2p_ielen); ++ #endif ++ ++ //Check P2P Capability ATTR ++ if( rtw_get_p2p_attr_content( p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8*)&cap_attr, (uint*) &attr_contentlen) ) ++ { ++ u8 grp_cap=0; ++ //DBG_8192C( "[%s] Got P2P Capability Attr!!\n", __FUNCTION__ ); ++ cap_attr = le16_to_cpu(cap_attr); ++ grp_cap = (u8)((cap_attr >> 8)&0xff); ++ ++ is_GO = (grp_cap&BIT(0)) ? _TRUE:_FALSE; ++ ++ if(is_GO) ++ DBG_8192C("Got P2P Capability Attr, grp_cap=0x%x, is_GO\n", grp_cap); ++ } ++ ++ ++ if(is_GO == _FALSE) ++ { ++ if(pmlmepriv->p2p_probe_resp_ie) ++ { ++ u32 free_len = pmlmepriv->p2p_probe_resp_ie_len; ++ pmlmepriv->p2p_probe_resp_ie_len = 0; ++ rtw_mfree(pmlmepriv->p2p_probe_resp_ie, free_len); ++ pmlmepriv->p2p_probe_resp_ie = NULL; ++ } ++ ++ pmlmepriv->p2p_probe_resp_ie = rtw_malloc(p2p_ielen); ++ if ( pmlmepriv->p2p_probe_resp_ie == NULL) { ++ DBG_8192C("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ return -EINVAL; ++ ++ } ++ _rtw_memcpy(pmlmepriv->p2p_probe_resp_ie, p2p_ie, p2p_ielen); ++ pmlmepriv->p2p_probe_resp_ie_len = p2p_ielen; ++ } ++ else ++ { ++ if(pmlmepriv->p2p_go_probe_resp_ie) ++ { ++ u32 free_len = pmlmepriv->p2p_go_probe_resp_ie_len; ++ pmlmepriv->p2p_go_probe_resp_ie_len = 0; ++ rtw_mfree(pmlmepriv->p2p_go_probe_resp_ie, free_len); ++ pmlmepriv->p2p_go_probe_resp_ie = NULL; ++ } ++ ++ pmlmepriv->p2p_go_probe_resp_ie = rtw_malloc(p2p_ielen); ++ if ( pmlmepriv->p2p_go_probe_resp_ie == NULL) { ++ DBG_8192C("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ return -EINVAL; ++ ++ } ++ _rtw_memcpy(pmlmepriv->p2p_go_probe_resp_ie, p2p_ie, p2p_ielen); ++ pmlmepriv->p2p_go_probe_resp_ie_len = p2p_ielen; ++ } ++ ++ } ++ #endif //CONFIG_P2P ++ ++ //buf += p2p_ielen; ++ //len -= p2p_ielen; ++ ++ #ifdef CONFIG_WFD ++ if(rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen)) ++ { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("probe_resp_wfd_ielen=%d\n", wfd_ielen); ++ #endif ++ ++ if(pmlmepriv->wfd_probe_resp_ie) ++ { ++ u32 free_len = pmlmepriv->wfd_probe_resp_ie_len; ++ pmlmepriv->wfd_probe_resp_ie_len = 0; ++ rtw_mfree(pmlmepriv->wfd_probe_resp_ie, free_len); ++ pmlmepriv->wfd_probe_resp_ie = NULL; ++ } ++ ++ pmlmepriv->wfd_probe_resp_ie = rtw_malloc(wfd_ielen); ++ if ( pmlmepriv->wfd_probe_resp_ie == NULL) { ++ DBG_8192C("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ return -EINVAL; ++ ++ } ++ rtw_get_wfd_ie(buf, len, pmlmepriv->wfd_probe_resp_ie, &pmlmepriv->wfd_probe_resp_ie_len); ++ } ++ #endif //CONFIG_WFD ++ ++ } ++ ++ return ret; ++ ++} ++ ++static int rtw_cfg80211_set_assoc_resp_wpsp2pie(struct net_device *net, char *buf, int len) ++{ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(net); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ DBG_8192C("%s, ielen=%d\n", __func__, len); ++ ++ if(len>0) ++ { ++ if(pmlmepriv->wps_assoc_resp_ie) ++ { ++ u32 free_len = pmlmepriv->wps_assoc_resp_ie_len; ++ pmlmepriv->wps_assoc_resp_ie_len = 0; ++ rtw_mfree(pmlmepriv->wps_assoc_resp_ie, free_len); ++ pmlmepriv->wps_assoc_resp_ie = NULL; ++ } ++ ++ pmlmepriv->wps_assoc_resp_ie = rtw_malloc(len); ++ if ( pmlmepriv->wps_assoc_resp_ie == NULL) { ++ DBG_8192C("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ return -EINVAL; ++ ++ } ++ _rtw_memcpy(pmlmepriv->wps_assoc_resp_ie, buf, len); ++ pmlmepriv->wps_assoc_resp_ie_len = len; ++ } ++ ++ return ret; ++ ++} ++ ++int rtw_cfg80211_set_mgnt_wpsp2pie(struct net_device *net, char *buf, int len, ++ int type) ++{ ++ int ret = 0; ++ uint wps_ielen = 0; ++ u32 p2p_ielen = 0; ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s, ielen=%d\n", __func__, len); ++#endif ++ ++ if( (rtw_get_wps_ie(buf, len, NULL, &wps_ielen) && (wps_ielen>0)) ++ #ifdef CONFIG_P2P ++ || (rtw_get_p2p_ie(buf, len, NULL, &p2p_ielen) && (p2p_ielen>0)) ++ #endif ++ ) ++ { ++ if (net != NULL) ++ { ++ switch (type) ++ { ++ case 0x1: //BEACON ++ ret = rtw_cfg80211_set_beacon_wpsp2pie(net, buf, len); ++ break; ++ case 0x2: //PROBE_RESP ++ ret = rtw_cfg80211_set_probe_resp_wpsp2pie(net, buf, len); ++ break; ++ case 0x4: //ASSOC_RESP ++ ret = rtw_cfg80211_set_assoc_resp_wpsp2pie(net, buf, len); ++ break; ++ } ++ } ++ } ++ ++ return ret; ++ ++} ++ ++static struct cfg80211_ops rtw_cfg80211_ops = { ++ .change_virtual_intf = cfg80211_rtw_change_iface, ++ .add_key = cfg80211_rtw_add_key, ++ .get_key = cfg80211_rtw_get_key, ++ .del_key = cfg80211_rtw_del_key, ++ .set_default_key = cfg80211_rtw_set_default_key, ++ .get_station = cfg80211_rtw_get_station, ++ .scan = cfg80211_rtw_scan, ++ .set_wiphy_params = cfg80211_rtw_set_wiphy_params, ++ .connect = cfg80211_rtw_connect, ++ .disconnect = cfg80211_rtw_disconnect, ++ .join_ibss = cfg80211_rtw_join_ibss, ++ .leave_ibss = cfg80211_rtw_leave_ibss, ++ .set_tx_power = cfg80211_rtw_set_txpower, ++ .get_tx_power = cfg80211_rtw_get_txpower, ++ .set_power_mgmt = cfg80211_rtw_set_power_mgmt, ++ .set_pmksa = cfg80211_rtw_set_pmksa, ++ .del_pmksa = cfg80211_rtw_del_pmksa, ++ .flush_pmksa = cfg80211_rtw_flush_pmksa, ++ ++#ifdef CONFIG_AP_MODE ++ .add_virtual_intf = cfg80211_rtw_add_virtual_intf, ++ .del_virtual_intf = cfg80211_rtw_del_virtual_intf, ++ ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(COMPAT_KERNEL_RELEASE) ++ .add_beacon = cfg80211_rtw_add_beacon, ++ .set_beacon = cfg80211_rtw_set_beacon, ++ .del_beacon = cfg80211_rtw_del_beacon, ++ #else ++ .start_ap = cfg80211_rtw_start_ap, ++ .change_beacon = cfg80211_rtw_change_beacon, ++ .stop_ap = cfg80211_rtw_stop_ap, ++ #endif ++ ++ .add_station = cfg80211_rtw_add_station, ++ .del_station = cfg80211_rtw_del_station, ++ .change_station = cfg80211_rtw_change_station, ++ .dump_station = cfg80211_rtw_dump_station, ++ .change_bss = cfg80211_rtw_change_bss, ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) ++ .set_channel = cfg80211_rtw_set_channel, ++ #endif ++ //.auth = cfg80211_rtw_auth, ++ //.assoc = cfg80211_rtw_assoc, ++#endif //CONFIG_AP_MODE ++ ++#ifdef CONFIG_P2P ++ .remain_on_channel = cfg80211_rtw_remain_on_channel, ++ .cancel_remain_on_channel = cfg80211_rtw_cancel_remain_on_channel, ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++ .mgmt_tx = cfg80211_rtw_mgmt_tx, ++ .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, ++#elif (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,34) && LINUX_VERSION_CODE<=KERNEL_VERSION(2,6,35)) ++ .action = cfg80211_rtw_mgmt_tx, ++#endif ++}; ++ ++static void rtw_cfg80211_init_ht_capab(struct ieee80211_sta_ht_cap *ht_cap, enum ieee80211_band band, u8 rf_type) ++{ ++ ++#define MAX_BIT_RATE_40MHZ_MCS15 300 /* Mbps */ ++#define MAX_BIT_RATE_40MHZ_MCS7 150 /* Mbps */ ++ ++ ht_cap->ht_supported = _TRUE; ++ ++ ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | ++ IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20 | ++ IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU; ++ ++ /* ++ *Maximum length of AMPDU that the STA can receive. ++ *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) ++ */ ++ ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; ++ ++ /*Minimum MPDU start spacing , */ ++ ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; ++ ++ ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; ++ ++ /* ++ *hw->wiphy->bands[IEEE80211_BAND_2GHZ] ++ *base on ant_num ++ *rx_mask: RX mask ++ *if rx_ant =1 rx_mask[0]=0xff;==>MCS0-MCS7 ++ *if rx_ant =2 rx_mask[1]=0xff;==>MCS8-MCS15 ++ *if rx_ant >=3 rx_mask[2]=0xff; ++ *if BW_40 rx_mask[4]=0x01; ++ *highest supported RX rate ++ */ ++ if(rf_type == RF_1T1R) ++ { ++ ht_cap->mcs.rx_mask[0] = 0xFF; ++ ht_cap->mcs.rx_mask[1] = 0x00; ++ ht_cap->mcs.rx_mask[4] = 0x01; ++ ++ ht_cap->mcs.rx_highest = MAX_BIT_RATE_40MHZ_MCS7; ++ } ++ else if((rf_type == RF_1T2R) || (rf_type==RF_2T2R)) ++ { ++ ht_cap->mcs.rx_mask[0] = 0xFF; ++ ht_cap->mcs.rx_mask[1] = 0xFF; ++ ht_cap->mcs.rx_mask[4] = 0x01; ++ ++ ht_cap->mcs.rx_highest = MAX_BIT_RATE_40MHZ_MCS15; ++ } ++ else ++ { ++ DBG_8192C("%s, error rf_type=%d\n", __func__, rf_type); ++ } ++ ++} ++ ++void rtw_cfg80211_init_wiphy(_adapter *padapter) ++{ ++ u8 rf_type; ++ struct ieee80211_supported_band *bands; ++ struct wireless_dev *pwdev = padapter->rtw_wdev; ++ struct wiphy *wiphy = pwdev->wiphy; ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ ++ DBG_8192C("%s:rf_type=%d\n", __func__, rf_type); ++ ++ /* if (padapter->registrypriv.wireless_mode & WIRELESS_11G) */ ++ { ++ bands = wiphy->bands[IEEE80211_BAND_2GHZ]; ++ if(bands) ++ rtw_cfg80211_init_ht_capab(&bands->ht_cap, IEEE80211_BAND_2GHZ, rf_type); ++ } ++ ++ /* if (padapter->registrypriv.wireless_mode & WIRELESS_11A) */ ++ { ++ bands = wiphy->bands[IEEE80211_BAND_5GHZ]; ++ if(bands) ++ rtw_cfg80211_init_ht_capab(&bands->ht_cap, IEEE80211_BAND_5GHZ, rf_type); ++ } ++} ++ ++/* ++struct ieee80211_iface_limit rtw_limits[] = { ++ { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) ++ | BIT(NL80211_IFTYPE_ADHOC) ++#ifdef CONFIG_AP_MODE ++ | BIT(NL80211_IFTYPE_AP) ++#endif ++#if defined(CONFIG_P2P) && ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE)) ++ | BIT(NL80211_IFTYPE_P2P_CLIENT) ++ | BIT(NL80211_IFTYPE_P2P_GO) ++#endif ++ }, ++ {.max = 1, .types = BIT(NL80211_IFTYPE_MONITOR)}, ++}; ++ ++struct ieee80211_iface_combination rtw_combinations = { ++ .limits = rtw_limits, ++ .n_limits = ARRAY_SIZE(rtw_limits), ++ .max_interfaces = 2, ++ .num_different_channels = 1, ++}; ++*/ ++ ++static void rtw_cfg80211_preinit_wiphy(_adapter *padapter, struct wiphy *wiphy) ++{ ++ ++ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; ++ ++ wiphy->max_scan_ssids = RTW_SSID_SCAN_AMOUNT; ++ wiphy->max_scan_ie_len = RTW_SCAN_IE_LEN_MAX; ++ wiphy->max_num_pmkids = RTW_MAX_NUM_PMKIDS; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) || defined(COMPAT_KERNEL_RELEASE) ++ wiphy->max_remain_on_channel_duration = RTW_MAX_REMAIN_ON_CHANNEL_DURATION; ++#endif ++ ++ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) ++ | BIT(NL80211_IFTYPE_ADHOC) ++#ifdef CONFIG_AP_MODE ++ | BIT(NL80211_IFTYPE_AP) ++ | BIT(NL80211_IFTYPE_MONITOR) ++#endif ++#if defined(CONFIG_P2P) && ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE)) ++ | BIT(NL80211_IFTYPE_P2P_CLIENT) ++ | BIT(NL80211_IFTYPE_P2P_GO) ++#endif ++ ; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) ++#ifdef CONFIG_AP_MODE ++ wiphy->mgmt_stypes = rtw_cfg80211_default_mgmt_stypes; ++#endif //CONFIG_AP_MODE ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)) ++ wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); ++#endif ++ ++ /* ++ wiphy->iface_combinations = &rtw_combinations; ++ wiphy->n_iface_combinations = 1; ++ */ ++ ++ wiphy->cipher_suites = rtw_cipher_suites; ++ wiphy->n_cipher_suites = ARRAY_SIZE(rtw_cipher_suites); ++ ++ /* if (padapter->registrypriv.wireless_mode & WIRELESS_11G) */ ++ wiphy->bands[IEEE80211_BAND_2GHZ] = rtw_spt_band_alloc(IEEE80211_BAND_2GHZ); ++ /* if (padapter->registrypriv.wireless_mode & WIRELESS_11A) */ ++ wiphy->bands[IEEE80211_BAND_5GHZ] = rtw_spt_band_alloc(IEEE80211_BAND_5GHZ); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38) && LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ wiphy->flags |= WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS; ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)) ++ wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; ++ wiphy->flags |= WIPHY_FLAG_OFFCHAN_TX | WIPHY_FLAG_HAVE_AP_SME; ++#endif ++ ++ if(padapter->registrypriv.power_mgnt != PS_MODE_ACTIVE) ++ wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; ++ else ++ wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; ++} ++ ++int rtw_wdev_alloc(_adapter *padapter, struct device *dev) ++{ ++ int ret = 0; ++ struct wiphy *wiphy; ++ struct wireless_dev *wdev; ++ struct rtw_wdev_priv *pwdev_priv; ++ struct net_device *pnetdev = padapter->pnetdev; ++ ++ DBG_8192C("%s(padapter=%p)\n", __func__, padapter); ++ ++ /* wiphy */ ++ wiphy = wiphy_new(&rtw_cfg80211_ops, sizeof(struct rtw_wdev_priv)); ++ if (!wiphy) { ++ DBG_8192C("Couldn't allocate wiphy device\n"); ++ ret = -ENOMEM; ++ goto exit; ++ } ++ set_wiphy_dev(wiphy, dev); ++ rtw_cfg80211_preinit_wiphy(padapter, wiphy); ++ ++ ret = wiphy_register(wiphy); ++ if (ret < 0) { ++ DBG_8192C("Couldn't register wiphy device\n"); ++ goto free_wiphy; ++ } ++ ++ /* wdev */ ++ wdev = (struct wireless_dev *)rtw_zmalloc(sizeof(struct wireless_dev)); ++ if (!wdev) { ++ DBG_8192C("Couldn't allocate wireless device\n"); ++ ret = -ENOMEM; ++ goto unregister_wiphy; ++ } ++ wdev->wiphy = wiphy; ++ wdev->netdev = pnetdev; ++ //wdev->iftype = NL80211_IFTYPE_STATION; ++ wdev->iftype = NL80211_IFTYPE_MONITOR; // for rtw_setopmode_cmd() in cfg80211_rtw_change_iface() ++ padapter->rtw_wdev = wdev; ++ pnetdev->ieee80211_ptr = wdev; ++ ++ //init pwdev_priv ++ pwdev_priv = wdev_to_priv(wdev); ++ pwdev_priv->rtw_wdev = wdev; ++ pwdev_priv->pmon_ndev = NULL; ++ pwdev_priv->ifname_mon[0] = '\0'; ++ pwdev_priv->padapter = padapter; ++ pwdev_priv->scan_request = NULL; ++ _rtw_spinlock_init(&pwdev_priv->scan_req_lock); ++ ++ pwdev_priv->p2p_enabled = _FALSE; ++ pwdev_priv->provdisc_req_issued = _FALSE; ++ rtw_wdev_invit_info_init(&pwdev_priv->invit_info); ++ rtw_wdev_nego_info_init(&pwdev_priv->nego_info); ++ ++ pwdev_priv->bandroid_scan = _FALSE; ++ ++ if(padapter->registrypriv.power_mgnt != PS_MODE_ACTIVE) ++ pwdev_priv->power_mgmt = _TRUE; ++ else ++ pwdev_priv->power_mgmt = _FALSE; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ ATOMIC_SET(&pwdev_priv->switch_ch_to, 1); ++ ATOMIC_SET(&pwdev_priv->ro_ch_to, 1); ++#endif ++ ++ return ret; ++ ++ rtw_mfree((u8*)wdev, sizeof(struct wireless_dev)); ++unregister_wiphy: ++ wiphy_unregister(wiphy); ++ free_wiphy: ++ wiphy_free(wiphy); ++exit: ++ return ret; ++ ++} ++ ++void rtw_wdev_free(struct wireless_dev *wdev) ++{ ++ struct rtw_wdev_priv *pwdev_priv; ++ ++ DBG_8192C("%s(wdev=%p)\n", __func__, wdev); ++ ++ if (!wdev) ++ return; ++ ++ pwdev_priv = wdev_to_priv(wdev); ++ ++ rtw_spt_band_free(wdev->wiphy->bands[IEEE80211_BAND_2GHZ]); ++ rtw_spt_band_free(wdev->wiphy->bands[IEEE80211_BAND_5GHZ]); ++ ++ wiphy_free(wdev->wiphy); ++ ++ rtw_mfree((u8*)wdev, sizeof(struct wireless_dev)); ++} ++ ++void rtw_wdev_unregister(struct wireless_dev *wdev) ++{ ++ struct rtw_wdev_priv *pwdev_priv; ++ ++ DBG_8192C("%s(wdev=%p)\n", __func__, wdev); ++ ++ if (!wdev) ++ return; ++ ++ pwdev_priv = wdev_to_priv(wdev); ++ ++ rtw_cfg80211_indicate_scan_done(pwdev_priv, _TRUE); ++ ++ if (pwdev_priv->pmon_ndev) { ++ DBG_8192C("%s, unregister monitor interface\n", __func__); ++ unregister_netdev(pwdev_priv->pmon_ndev); ++ } ++ ++ wiphy_unregister(wdev->wiphy); ++} ++ ++#endif //CONFIG_IOCTL_CFG80211 ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/ioctl_linux.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/ioctl_linux.c +new file mode 100644 +index 00000000..d76facb6 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/ioctl_linux.c +@@ -0,0 +1,14216 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _IOCTL_LINUX_C_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++//#ifdef CONFIG_MP_INCLUDED ++#include ++//#endif ++ ++#ifdef CONFIG_USB_HCI ++#include ++#endif //CONFIG_USB_HCI ++#include ++ ++#ifdef CONFIG_MP_INCLUDED ++#include ++#endif //#ifdef CONFIG_MP_INCLUDED ++#ifdef CONFIG_RTL8192C ++#include ++#endif ++#ifdef CONFIG_RTL8192D ++#include ++#endif ++#ifdef CONFIG_RTL8723A ++#include ++#include ++#include ++#endif ++#ifdef CONFIG_RTL8188E ++#include ++#endif ++#ifdef CONFIG_GSPI_HCI ++#include ++#endif ++ ++#ifdef CONFIG_RTL8723A ++//extern u8 _InitPowerOn(PADAPTER padapter); ++//extern s32 rtl8723a_FirmwareDownload(PADAPTER padapter); ++extern s32 FillH2CCmd(PADAPTER padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer); ++#endif ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)) ++#define iwe_stream_add_event(a, b, c, d, e) iwe_stream_add_event(b, c, d, e) ++#define iwe_stream_add_point(a, b, c, d, e) iwe_stream_add_point(b, c, d, e) ++#endif ++ ++ ++#define RTL_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30 ++ ++#define SCAN_ITEM_SIZE 768 ++#define MAX_CUSTOM_LEN 64 ++#define RATE_COUNT 4 ++ ++#ifdef CONFIG_GLOBAL_UI_PID ++extern int ui_pid[3]; ++#endif ++ ++// combo scan ++#define WEXT_CSCAN_AMOUNT 9 ++#define WEXT_CSCAN_BUF_LEN 360 ++#define WEXT_CSCAN_HEADER "CSCAN S\x01\x00\x00S\x00" ++#define WEXT_CSCAN_HEADER_SIZE 12 ++#define WEXT_CSCAN_SSID_SECTION 'S' ++#define WEXT_CSCAN_CHANNEL_SECTION 'C' ++#define WEXT_CSCAN_NPROBE_SECTION 'N' ++#define WEXT_CSCAN_ACTV_DWELL_SECTION 'A' ++#define WEXT_CSCAN_PASV_DWELL_SECTION 'P' ++#define WEXT_CSCAN_HOME_DWELL_SECTION 'H' ++#define WEXT_CSCAN_TYPE_SECTION 'T' ++ ++ ++extern u8 key_2char2num(u8 hch, u8 lch); ++extern u8 str_2char2num(u8 hch, u8 lch); ++extern u8 convert_ip_addr(u8 hch, u8 mch, u8 lch); ++ ++u32 rtw_rates[] = {1000000,2000000,5500000,11000000, ++ 6000000,9000000,12000000,18000000,24000000,36000000,48000000,54000000}; ++ ++static const char * const iw_operation_mode[] = ++{ ++ "Auto", "Ad-Hoc", "Managed", "Master", "Repeater", "Secondary", "Monitor" ++}; ++ ++static int hex2num_i(char c) ++{ ++ if (c >= '0' && c <= '9') ++ return c - '0'; ++ if (c >= 'a' && c <= 'f') ++ return c - 'a' + 10; ++ if (c >= 'A' && c <= 'F') ++ return c - 'A' + 10; ++ return -1; ++} ++ ++static int hex2byte_i(const char *hex) ++{ ++ int a, b; ++ a = hex2num_i(*hex++); ++ if (a < 0) ++ return -1; ++ b = hex2num_i(*hex++); ++ if (b < 0) ++ return -1; ++ return (a << 4) | b; ++} ++ ++/** ++ * hwaddr_aton - Convert ASCII string to MAC address ++ * @txt: MAC address as a string (e.g., "00:11:22:33:44:55") ++ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) ++ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) ++ */ ++static int hwaddr_aton_i(const char *txt, u8 *addr) ++{ ++ int i; ++ ++ for (i = 0; i < 6; i++) { ++ int a, b; ++ ++ a = hex2num_i(*txt++); ++ if (a < 0) ++ return -1; ++ b = hex2num_i(*txt++); ++ if (b < 0) ++ return -1; ++ *addr++ = (a << 4) | b; ++ if (i < 5 && *txt++ != ':') ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static void indicate_wx_custom_event(_adapter *padapter, char *msg) ++{ ++ u8 *buff, *p; ++ union iwreq_data wrqu; ++ ++ if (strlen(msg) > IW_CUSTOM_MAX) { ++ DBG_871X("%s strlen(msg):%zu > IW_CUSTOM_MAX:%u\n", __FUNCTION__ , strlen(msg), IW_CUSTOM_MAX); ++ return; ++ } ++ ++ buff = rtw_zmalloc(IW_CUSTOM_MAX+1); ++ if(!buff) ++ return; ++ ++ _rtw_memcpy(buff, msg, strlen(msg)); ++ ++ _rtw_memset(&wrqu,0,sizeof(wrqu)); ++ wrqu.data.length = strlen(msg); ++ ++ DBG_871X("%s %s\n", __FUNCTION__, buff); ++#ifndef CONFIG_IOCTL_CFG80211 ++ wireless_send_event(padapter->pnetdev, IWEVCUSTOM, &wrqu, buff); ++#endif ++ ++ rtw_mfree(buff, IW_CUSTOM_MAX+1); ++ ++} ++ ++ ++static void request_wps_pbc_event(_adapter *padapter) ++{ ++ u8 *buff, *p; ++ union iwreq_data wrqu; ++ ++ ++ buff = rtw_malloc(IW_CUSTOM_MAX); ++ if(!buff) ++ return; ++ ++ _rtw_memset(buff, 0, IW_CUSTOM_MAX); ++ ++ p=buff; ++ ++ p+=sprintf(p, "WPS_PBC_START.request=TRUE"); ++ ++ _rtw_memset(&wrqu,0,sizeof(wrqu)); ++ ++ wrqu.data.length = p-buff; ++ ++ wrqu.data.length = (wrqu.data.lengthpnetdev, IWEVCUSTOM, &wrqu, buff); ++#endif ++ ++ if(buff) ++ { ++ rtw_mfree(buff, IW_CUSTOM_MAX); ++ } ++ ++} ++ ++ ++void indicate_wx_scan_complete_event(_adapter *padapter) ++{ ++ union iwreq_data wrqu; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ _rtw_memset(&wrqu, 0, sizeof(union iwreq_data)); ++ ++ //DBG_871X("+rtw_indicate_wx_scan_complete_event\n"); ++#ifndef CONFIG_IOCTL_CFG80211 ++ wireless_send_event(padapter->pnetdev, SIOCGIWSCAN, &wrqu, NULL); ++#endif ++} ++ ++ ++void rtw_indicate_wx_assoc_event(_adapter *padapter) ++{ ++ union iwreq_data wrqu; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX*)(&(pmlmeinfo->network)); ++ ++ _rtw_memset(&wrqu, 0, sizeof(union iwreq_data)); ++ ++ wrqu.ap_addr.sa_family = ARPHRD_ETHER; ++ ++ if(check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)==_TRUE ) ++ _rtw_memcpy(wrqu.ap_addr.sa_data, pnetwork->MacAddress, ETH_ALEN); ++ else ++ _rtw_memcpy(wrqu.ap_addr.sa_data, pmlmepriv->cur_network.network.MacAddress, ETH_ALEN); ++ ++ DBG_871X_LEVEL(_drv_always_, "assoc success\n"); ++#ifndef CONFIG_IOCTL_CFG80211 ++ wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL); ++#endif ++} ++ ++void rtw_indicate_wx_disassoc_event(_adapter *padapter) ++{ ++ union iwreq_data wrqu; ++ ++ _rtw_memset(&wrqu, 0, sizeof(union iwreq_data)); ++ ++ wrqu.ap_addr.sa_family = ARPHRD_ETHER; ++ _rtw_memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); ++ ++#ifndef CONFIG_IOCTL_CFG80211 ++ DBG_871X_LEVEL(_drv_always_, "indicate disassoc\n"); ++ wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL); ++#endif ++} ++ ++/* ++uint rtw_is_cckrates_included(u8 *rate) ++{ ++ u32 i = 0; ++ ++ while(rate[i]!=0) ++ { ++ if ( (((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || ++ (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22) ) ++ return _TRUE; ++ i++; ++ } ++ ++ return _FALSE; ++} ++ ++uint rtw_is_cckratesonly_included(u8 *rate) ++{ ++ u32 i = 0; ++ ++ while(rate[i]!=0) ++ { ++ if ( (((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && ++ (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22) ) ++ return _FALSE; ++ i++; ++ } ++ ++ return _TRUE; ++} ++*/ ++ ++static char *translate_scan(_adapter *padapter, ++ struct iw_request_info* info, struct wlan_network *pnetwork, ++ char *start, char *stop) ++{ ++ struct iw_event iwe; ++ u16 cap; ++ u32 ht_ielen = 0; ++ char custom[MAX_CUSTOM_LEN]; ++ char *p; ++ u16 max_rate=0, rate, ht_cap=_FALSE; ++ u32 i = 0; ++ char *current_val; ++ long rssi; ++ u8 bw_40MHz=0, short_GI=0; ++ u16 mcs_rate=0; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++#endif //CONFIG_P2P ++ ++#ifdef CONFIG_P2P ++#ifdef CONFIG_WFD ++ if ( SCAN_RESULT_ALL == pwdinfo->wfd_info->scan_result_type ) ++ { ++ ++ } ++ else if ( ( SCAN_RESULT_P2P_ONLY == pwdinfo->wfd_info->scan_result_type ) || ++ ( SCAN_RESULT_WFD_TYPE == pwdinfo->wfd_info->scan_result_type ) ) ++#endif // CONFIG_WFD ++ { ++ if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ u32 blnGotP2PIE = _FALSE; ++ ++ // User is doing the P2P device discovery ++ // The prefix of SSID should be "DIRECT-" and the IE should contains the P2P IE. ++ // If not, the driver should ignore this AP and go to the next AP. ++ ++ // Verifying the SSID ++ if ( _rtw_memcmp( pnetwork->network.Ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN ) ) ++ { ++ u32 p2pielen = 0; ++ ++ if (pnetwork->network.Reserved[0] == 2) { // Probe Request ++ // Verifying the P2P IE ++ if ( rtw_get_p2p_ie( pnetwork->network.IEs, pnetwork->network.IELength, NULL, &p2pielen) ) ++ { ++ blnGotP2PIE = _TRUE; ++ } ++ } else { // Beacon or Probe Respones ++ // Verifying the P2P IE ++ if ( rtw_get_p2p_ie( &pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen) ) ++ { ++ blnGotP2PIE = _TRUE; ++ } ++ } ++ } ++ ++ if ( blnGotP2PIE == _FALSE ) ++ { ++ return start; ++ } ++ ++ } ++ } ++ ++#ifdef CONFIG_WFD ++ if ( SCAN_RESULT_WFD_TYPE == pwdinfo->wfd_info->scan_result_type ) ++ { ++ u32 blnGotWFD = _FALSE; ++ u8 wfd_ie[ 128 ] = { 0x00 }; ++ uint wfd_ielen = 0; ++ ++ if ( rtw_get_wfd_ie_from_scan_queue( &pnetwork->network.IEs[0], pnetwork->network.IELength, wfd_ie, &wfd_ielen, pnetwork->network.Reserved[0]) ) ++ { ++ u8 wfd_devinfo[ 6 ] = { 0x00 }; ++ uint wfd_devlen = 6; ++ ++ if ( rtw_get_wfd_attr_content( wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, wfd_devinfo, &wfd_devlen) ) ++ { ++ if ( pwdinfo->wfd_info->wfd_device_type == WFD_DEVINFO_PSINK ) ++ { ++ // the first two bits will indicate the WFD device type ++ if ( ( wfd_devinfo[ 1 ] & 0x03 ) == WFD_DEVINFO_SOURCE ) ++ { ++ // If this device is Miracast PSink device, the scan reuslt should just provide the Miracast source. ++ blnGotWFD = _TRUE; ++ } ++ } ++ else if ( pwdinfo->wfd_info->wfd_device_type == WFD_DEVINFO_SOURCE ) ++ { ++ // the first two bits will indicate the WFD device type ++ if ( ( wfd_devinfo[ 1 ] & 0x03 ) == WFD_DEVINFO_PSINK ) ++ { ++ // If this device is Miracast source device, the scan reuslt should just provide the Miracast PSink. ++ // Todo: How about the SSink?! ++ blnGotWFD = _TRUE; ++ } ++ } ++ } ++ } ++ ++ if ( blnGotWFD == _FALSE ) ++ { ++ return start; ++ } ++ } ++#endif // CONFIG_WFD ++ ++#endif //CONFIG_P2P ++ ++ /* AP MAC address */ ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ ++ _rtw_memcpy(iwe.u.ap_addr.sa_data, pnetwork->network.MacAddress, ETH_ALEN); ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); ++ ++ /* Add the ESSID */ ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.flags = 1; ++ iwe.u.data.length = min((u16)pnetwork->network.Ssid.SsidLength, (u16)32); ++ start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.Ssid.Ssid); ++ ++ //parsing HT_CAP_IE ++ p = rtw_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pnetwork->network.IELength-12); ++ ++ if(p && ht_ielen>0) ++ { ++ struct rtw_ieee80211_ht_cap *pht_capie; ++ ht_cap = _TRUE; ++ pht_capie = (struct rtw_ieee80211_ht_cap *)(p+2); ++ _rtw_memcpy(&mcs_rate , pht_capie->supp_mcs_set, 2); ++ bw_40MHz = (pht_capie->cap_info&IEEE80211_HT_CAP_SUP_WIDTH) ? 1:0; ++ short_GI = (pht_capie->cap_info&(IEEE80211_HT_CAP_SGI_20|IEEE80211_HT_CAP_SGI_40)) ? 1:0; ++ } ++ ++ /* Add the protocol name */ ++ iwe.cmd = SIOCGIWNAME; ++ if ((rtw_is_cckratesonly_included((u8*)&pnetwork->network.SupportedRates)) == _TRUE) ++ { ++ if(ht_cap == _TRUE) ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bn"); ++ else ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11b"); ++ } ++ else if ((rtw_is_cckrates_included((u8*)&pnetwork->network.SupportedRates)) == _TRUE) ++ { ++ if(ht_cap == _TRUE) ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bgn"); ++ else ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bg"); ++ } ++ else ++ { ++ if(pnetwork->network.Configuration.DSConfig > 14) ++ { ++ if(ht_cap == _TRUE) ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11an"); ++ else ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11a"); ++ } ++ else ++ { ++ if(ht_cap == _TRUE) ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11gn"); ++ else ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11g"); ++ } ++ } ++ ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); ++ ++ /* Add mode */ ++ iwe.cmd = SIOCGIWMODE; ++ _rtw_memcpy((u8 *)&cap, rtw_get_capability_from_ie(pnetwork->network.IEs), 2); ++ ++ ++ cap = le16_to_cpu(cap); ++ ++ if(cap & (WLAN_CAPABILITY_IBSS |WLAN_CAPABILITY_BSS)){ ++ if (cap & WLAN_CAPABILITY_BSS) ++ iwe.u.mode = IW_MODE_MASTER; ++ else ++ iwe.u.mode = IW_MODE_ADHOC; ++ ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN); ++ } ++ ++ if(pnetwork->network.Configuration.DSConfig<1 /*|| pnetwork->network.Configuration.DSConfig>14*/) ++ pnetwork->network.Configuration.DSConfig = 1; ++ ++ /* Add frequency/channel */ ++ iwe.cmd = SIOCGIWFREQ; ++ iwe.u.freq.m = rtw_ch2freq(pnetwork->network.Configuration.DSConfig) * 100000; ++ iwe.u.freq.e = 1; ++ iwe.u.freq.i = pnetwork->network.Configuration.DSConfig; ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); ++ ++ /* Add encryption capability */ ++ iwe.cmd = SIOCGIWENCODE; ++ if (cap & WLAN_CAPABILITY_PRIVACY) ++ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ iwe.u.data.length = 0; ++ start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.Ssid.Ssid); ++ ++ /*Add basic and extended rates */ ++ max_rate = 0; ++ p = custom; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); ++ while(pnetwork->network.SupportedRates[i]!=0) ++ { ++ rate = pnetwork->network.SupportedRates[i]&0x7F; ++ if (rate > max_rate) ++ max_rate = rate; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), ++ "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); ++ i++; ++ } ++ ++ if(ht_cap == _TRUE) ++ { ++ if(mcs_rate&0x8000)//MCS15 ++ { ++ max_rate = (bw_40MHz) ? ((short_GI)?300:270):((short_GI)?144:130); ++ ++ } ++ else if(mcs_rate&0x0080)//MCS7 ++ { ++ max_rate = (bw_40MHz) ? ((short_GI)?150:135):((short_GI)?72:65); ++ } ++ else//default MCS7 ++ { ++ //DBG_871X("wx_get_scan, mcs_rate_bitmap=0x%x\n", mcs_rate); ++ max_rate = (bw_40MHz) ? ((short_GI)?150:135):((short_GI)?72:65); ++ } ++ ++ max_rate = max_rate*2;//Mbps/2; ++ } ++ ++ iwe.cmd = SIOCGIWRATE; ++ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; ++ iwe.u.bitrate.value = max_rate * 500000; ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_PARAM_LEN); ++ ++ //parsing WPA/WPA2 IE ++ { ++ u8 buf[MAX_WPA_IE_LEN]; ++ u8 wpa_ie[255],rsn_ie[255]; ++ u16 wpa_len=0,rsn_len=0; ++ u8 *p; ++ sint out_len=0; ++ out_len=rtw_get_sec_ie(pnetwork->network.IEs ,pnetwork->network.IELength,rsn_ie,&rsn_len,wpa_ie,&wpa_len); ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_wx_get_scan: ssid=%s\n",pnetwork->network.Ssid.Ssid)); ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_wx_get_scan: wpa_len=%d rsn_len=%d\n",wpa_len,rsn_len)); ++ ++ if (wpa_len > 0) ++ { ++ p=buf; ++ _rtw_memset(buf, 0, MAX_WPA_IE_LEN); ++ p += sprintf(p, "wpa_ie="); ++ for (i = 0; i < wpa_len; i++) { ++ p += sprintf(p, "%02x", wpa_ie[i]); ++ } ++ ++ _rtw_memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = strlen(buf); ++ start = iwe_stream_add_point(info, start, stop, &iwe,buf); ++ ++ _rtw_memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd =IWEVGENIE; ++ iwe.u.data.length = wpa_len; ++ start = iwe_stream_add_point(info, start, stop, &iwe, wpa_ie); ++ } ++ if (rsn_len > 0) ++ { ++ p = buf; ++ _rtw_memset(buf, 0, MAX_WPA_IE_LEN); ++ p += sprintf(p, "rsn_ie="); ++ for (i = 0; i < rsn_len; i++) { ++ p += sprintf(p, "%02x", rsn_ie[i]); ++ } ++ _rtw_memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = strlen(buf); ++ start = iwe_stream_add_point(info, start, stop, &iwe,buf); ++ ++ _rtw_memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd =IWEVGENIE; ++ iwe.u.data.length = rsn_len; ++ start = iwe_stream_add_point(info, start, stop, &iwe, rsn_ie); ++ } ++ } ++ ++ { //parsing WPS IE ++ uint cnt = 0,total_ielen; ++ u8 *wpsie_ptr=NULL; ++ uint wps_ielen = 0; ++ ++ u8 *ie_ptr = pnetwork->network.IEs +_FIXED_IE_LENGTH_; ++ total_ielen= pnetwork->network.IELength - _FIXED_IE_LENGTH_; ++ ++ if (pnetwork->network.Reserved[0] == 2) // Probe Request ++ { ++ ie_ptr = pnetwork->network.IEs; ++ total_ielen = pnetwork->network.IELength; ++ } ++ else // Beacon or Probe Respones ++ { ++ ie_ptr = pnetwork->network.IEs + _FIXED_IE_LENGTH_; ++ total_ielen = pnetwork->network.IELength - _FIXED_IE_LENGTH_; ++ } ++ ++ while(cnt < total_ielen) ++ { ++ if(rtw_is_wps_ie(&ie_ptr[cnt], &wps_ielen) && (wps_ielen>2)) ++ { ++ wpsie_ptr = &ie_ptr[cnt]; ++ iwe.cmd =IWEVGENIE; ++ iwe.u.data.length = (u16)wps_ielen; ++ start = iwe_stream_add_point(info, start, stop, &iwe, wpsie_ptr); ++ } ++ cnt+=ie_ptr[cnt+1]+2; //goto next ++ } ++ } ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ { ++ sint out_len_wapi=0; ++ /* here use static for stack size */ ++ static u8 buf_wapi[MAX_WAPI_IE_LEN]; ++ static u8 wapi_ie[MAX_WAPI_IE_LEN]; ++ u16 wapi_len=0; ++ u16 i; ++ ++ _rtw_memset(buf_wapi, 0, MAX_WAPI_IE_LEN); ++ _rtw_memset(wapi_ie, 0, MAX_WAPI_IE_LEN); ++ ++ out_len_wapi=rtw_get_wapi_ie(pnetwork->network.IEs ,pnetwork->network.IELength,wapi_ie,&wapi_len); ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_wx_get_scan: ssid=%s\n",pnetwork->network.Ssid.Ssid)); ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_wx_get_scan: wapi_len=%d \n",wapi_len)); ++ ++ DBG_871X("rtw_wx_get_scan: %s ",pnetwork->network.Ssid.Ssid); ++ DBG_871X("rtw_wx_get_scan: ssid = %d ",wapi_len); ++ ++ ++ if (wapi_len > 0) ++ { ++ p=buf_wapi; ++ _rtw_memset(buf_wapi, 0, MAX_WAPI_IE_LEN); ++ p += sprintf(p, "wapi_ie="); ++ for (i = 0; i < wapi_len; i++) { ++ p += sprintf(p, "%02x", wapi_ie[i]); ++ } ++ ++ _rtw_memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = strlen(buf_wapi); ++ start = iwe_stream_add_point(info, start, stop, &iwe,buf_wapi); ++ ++ _rtw_memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd =IWEVGENIE; ++ iwe.u.data.length = wapi_len; ++ start = iwe_stream_add_point(info, start, stop, &iwe, wapi_ie); ++ } ++ } ++#endif //CONFIG_WAPI_SUPPORT ++ ++{ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ u8 ss, sq; ++ ++ /* Add quality statistics */ ++ iwe.cmd = IWEVQUAL; ++ iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID ++ #ifdef CONFIG_SIGNAL_DISPLAY_DBM ++ | IW_QUAL_DBM ++ #endif ++ ; ++ ++ if ( check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE && ++ is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network, 0)) { ++ ss = padapter->recvpriv.signal_strength; ++ sq = padapter->recvpriv.signal_qual; ++ } else { ++ ss = pnetwork->network.PhyInfo.SignalStrength; ++ sq = pnetwork->network.PhyInfo.SignalQuality; ++ } ++ ++ ++ #ifdef CONFIG_SIGNAL_DISPLAY_DBM ++ iwe.u.qual.level = (u8) translate_percentage_to_dbm(ss);//dbm ++ #else ++ iwe.u.qual.level = (u8)ss;//% ++ #ifdef CONFIG_BT_COEXIST ++ BT_SignalCompensation(padapter, &iwe.u.qual.level, NULL); ++ #endif // CONFIG_BT_COEXIST ++ #endif ++ ++ iwe.u.qual.qual = (u8)sq; // signal quality ++ ++ #ifdef CONFIG_PLATFORM_ROCKCHIPS ++ iwe.u.qual.noise = -100; // noise level suggest by zhf@rockchips ++ #else ++ iwe.u.qual.noise = 0; // noise level ++ #endif //CONFIG_PLATFORM_ROCKCHIPS ++ ++ //DBG_871X("iqual=%d, ilevel=%d, inoise=%d, iupdated=%d\n", iwe.u.qual.qual, iwe.u.qual.level , iwe.u.qual.noise, iwe.u.qual.updated); ++ ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); ++} ++ ++ { ++ u8 buf[MAX_WPA_IE_LEN]; ++ u8 * p,*pos; ++ int len; ++ p = buf; ++ pos = pnetwork->network.Reserved; ++ _rtw_memset(buf, 0, MAX_WPA_IE_LEN); ++ p += sprintf(p, "fm=%02X%02X", pos[1], pos[0]); ++ _rtw_memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = strlen(buf); ++ start = iwe_stream_add_point(info, start, stop, &iwe, buf); ++ } ++ ++ return start; ++} ++ ++static int wpa_set_auth_algs(struct net_device *dev, u32 value) ++{ ++ _adapter *padapter = (_adapter *) rtw_netdev_priv(dev); ++ int ret = 0; ++ ++ if ((value & AUTH_ALG_SHARED_KEY)&&(value & AUTH_ALG_OPEN_SYSTEM)) ++ { ++ DBG_871X("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY and AUTH_ALG_OPEN_SYSTEM [value:0x%x]\n",value); ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch; ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; ++ } ++ else if (value & AUTH_ALG_SHARED_KEY) ++ { ++ DBG_871X("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY [value:0x%x]\n",value); ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ ++#ifdef CONFIG_PLATFORM_MT53XX ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch; ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; ++#else ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared; ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared; ++#endif ++ } ++ else if(value & AUTH_ALG_OPEN_SYSTEM) ++ { ++ DBG_871X("wpa_set_auth_algs, AUTH_ALG_OPEN_SYSTEM\n"); ++ //padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ if(padapter->securitypriv.ndisauthtype < Ndis802_11AuthModeWPAPSK) ++ { ++#ifdef CONFIG_PLATFORM_MT53XX ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch; ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; ++#else ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; ++#endif ++ } ++ ++ } ++ else if(value & AUTH_ALG_LEAP) ++ { ++ DBG_871X("wpa_set_auth_algs, AUTH_ALG_LEAP\n"); ++ } ++ else ++ { ++ DBG_871X("wpa_set_auth_algs, error!\n"); ++ ret = -EINVAL; ++ } ++ ++ return ret; ++ ++} ++ ++static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len) ++{ ++ int ret = 0; ++ u32 wep_key_idx, wep_key_len,wep_total_len; ++ NDIS_802_11_WEP *pwep = NULL; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++#ifdef CONFIG_P2P ++ struct wifidirect_info* pwdinfo = &padapter->wdinfo; ++#endif //CONFIG_P2P ++ ++_func_enter_; ++ ++ param->u.crypt.err = 0; ++ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; ++ ++ if (param_len < (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && ++ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && ++ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) ++ { ++ ++ if (param->u.crypt.idx >= WEP_KEYS ++#ifdef CONFIG_IEEE80211W ++ && param->u.crypt.idx > BIP_MAX_KEYID ++#endif //CONFIG_IEEE80211W ++ ) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } ++ else ++ { ++#ifdef CONFIG_WAPI_SUPPORT ++ if (strcmp(param->u.crypt.alg, "SMS4")) ++#endif ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } ++ ++ if (strcmp(param->u.crypt.alg, "WEP") == 0) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_os_c,_drv_err_,("wpa_set_encryption, crypt.alg = WEP\n")); ++ DBG_871X("wpa_set_encryption, crypt.alg = WEP\n"); ++ ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ padapter->securitypriv.dot11PrivacyAlgrthm=_WEP40_; ++ padapter->securitypriv.dot118021XGrpPrivacy=_WEP40_; ++ ++ wep_key_idx = param->u.crypt.idx; ++ wep_key_len = param->u.crypt.key_len; ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c,_drv_info_,("(1)wep_key_idx=%d\n", wep_key_idx)); ++ DBG_871X("(1)wep_key_idx=%d\n", wep_key_idx); ++ ++ if (wep_key_idx > WEP_KEYS) ++ return -EINVAL; ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c,_drv_info_,("(2)wep_key_idx=%d\n", wep_key_idx)); ++ ++ if (wep_key_len > 0) ++ { ++ wep_key_len = wep_key_len <= 5 ? 5 : 13; ++ wep_total_len = wep_key_len + FIELD_OFFSET(NDIS_802_11_WEP, KeyMaterial); ++ pwep =(NDIS_802_11_WEP *) rtw_malloc(wep_total_len); ++ if(pwep == NULL){ ++ RT_TRACE(_module_rtl871x_ioctl_os_c,_drv_err_,(" wpa_set_encryption: pwep allocate fail !!!\n")); ++ goto exit; ++ } ++ ++ _rtw_memset(pwep, 0, wep_total_len); ++ ++ pwep->KeyLength = wep_key_len; ++ pwep->Length = wep_total_len; ++ ++ if(wep_key_len==13) ++ { ++ padapter->securitypriv.dot11PrivacyAlgrthm=_WEP104_; ++ padapter->securitypriv.dot118021XGrpPrivacy=_WEP104_; ++ } ++ } ++ else { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ pwep->KeyIndex = wep_key_idx; ++ pwep->KeyIndex |= 0x80000000; ++ ++ _rtw_memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength); ++ ++ if(param->u.crypt.set_tx) ++ { ++ DBG_871X("wep, set_tx=1\n"); ++ ++ if(rtw_set_802_11_add_wep(padapter, pwep) == (u8)_FAIL) ++ { ++ ret = -EOPNOTSUPP ; ++ } ++ } ++ else ++ { ++ DBG_871X("wep, set_tx=0\n"); ++ ++ //don't update "psecuritypriv->dot11PrivacyAlgrthm" and ++ //"psecuritypriv->dot11PrivacyKeyIndex=keyid", but can rtw_set_key to fw/cam ++ ++ if (wep_key_idx >= WEP_KEYS) { ++ ret = -EOPNOTSUPP ; ++ goto exit; ++ } ++ ++ _rtw_memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength); ++ psecuritypriv->dot11DefKeylen[wep_key_idx]=pwep->KeyLength; ++ rtw_set_key(padapter, psecuritypriv, wep_key_idx, 0,_TRUE); ++ } ++ ++ goto exit; ++ } ++ ++ if(padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) // 802_1x ++ { ++ struct sta_info * psta,*pbcmc_sta; ++ struct sta_priv * pstapriv = &padapter->stapriv; ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE) == _TRUE) //sta mode ++ { ++ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); ++ if (psta == NULL) { ++ //DEBUG_ERR( ("Set wpa_set_encryption: Obtain Sta_info fail \n")); ++ } ++ else ++ { ++ //Jeff: don't disable ieee8021x_blocked while clearing key ++ if (strcmp(param->u.crypt.alg, "none") != 0) ++ psta->ieee8021x_blocked = _FALSE; ++ ++ if((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled)|| ++ (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) ++ { ++ psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; ++ } ++ ++ if(param->u.crypt.set_tx ==1)//pairwise key ++ { ++ _rtw_memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ if(strcmp(param->u.crypt.alg, "TKIP") == 0)//set mic key ++ { ++ //DEBUG_ERR(("\nset key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len)); ++ _rtw_memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8); ++ _rtw_memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8); ++ ++ padapter->securitypriv.busetkipkey=_FALSE; ++ //_set_timer(&padapter->securitypriv.tkip_timer, 50); ++ } ++ ++ //DEBUG_ERR((" param->u.crypt.key_len=%d\n",param->u.crypt.key_len)); ++ DBG_871X(" ~~~~set sta key:unicastkey\n"); ++ ++ rtw_setstakey_cmd(padapter, (unsigned char *)psta, _TRUE, _TRUE); ++ } ++ else//group key ++ { ++ if(strcmp(param->u.crypt.alg, "TKIP") == 0 || strcmp(param->u.crypt.alg, "CCMP") == 0) ++ { ++ printk("[%s] GTK key_len=%d @@@@@@@@@@@@@@@@@@\n", param->u.crypt.alg, param->u.crypt.key_len); ++ _rtw_memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key,(param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ //only TKIP group key need to install this ++ if(param->u.crypt.key_len > 16) ++ { ++ _rtw_memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey,&(param->u.crypt.key[16]),8); ++ _rtw_memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey,&(param->u.crypt.key[24]),8); ++ } ++ padapter->securitypriv.binstallGrpkey = _TRUE; ++ //DEBUG_ERR((" param->u.crypt.key_len=%d\n", param->u.crypt.key_len)); ++ DBG_871X(" ~~~~set sta key:groupkey\n"); ++ ++ padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx; ++ ++ rtw_set_key(padapter,&padapter->securitypriv,param->u.crypt.idx, 1,_TRUE); ++ } ++#ifdef CONFIG_IEEE80211W ++ else if(strcmp(param->u.crypt.alg, "BIP") == 0) ++ { ++ int no; ++ //printk("BIP key_len=%d , index=%d @@@@@@@@@@@@@@@@@@\n", param->u.crypt.key_len, param->u.crypt.idx); ++ //save the IGTK key, length 16 bytes ++ _rtw_memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey, param->u.crypt.key,(param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ /*printk("IGTK key below:\n"); ++ for(no=0;no<16;no++) ++ printk(" %02x ", padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey[no]); ++ printk("\n");*/ ++ padapter->securitypriv.dot11wBIPKeyid = param->u.crypt.idx; ++ padapter->securitypriv.binstallBIPkey = _TRUE; ++ DBG_871X(" ~~~~set sta key:IGKT\n"); ++ } ++#endif //CONFIG_IEEE80211W ++ ++#ifdef CONFIG_P2P ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING)) ++ { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_PROVISIONING_DONE); ++ } ++#endif //CONFIG_P2P ++ ++ } ++ } ++ ++ pbcmc_sta=rtw_get_bcmc_stainfo(padapter); ++ if(pbcmc_sta==NULL) ++ { ++ //DEBUG_ERR( ("Set OID_802_11_ADD_KEY: bcmc stainfo is null \n")); ++ } ++ else ++ { ++ //Jeff: don't disable ieee8021x_blocked while clearing key ++ if (strcmp(param->u.crypt.alg, "none") != 0) ++ pbcmc_sta->ieee8021x_blocked = _FALSE; ++ ++ if((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled)|| ++ (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) ++ { ++ pbcmc_sta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; ++ } ++ } ++ } ++ else if(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) //adhoc mode ++ { ++ } ++ } ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ if (strcmp(param->u.crypt.alg, "SMS4") == 0) ++ { ++ PRT_WAPI_T pWapiInfo = &padapter->wapiInfo; ++ PRT_WAPI_STA_INFO pWapiSta; ++ u8 WapiASUEPNInitialValueSrc[16] = {0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ; ++ u8 WapiAEPNInitialValueSrc[16] = {0x37,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ; ++ u8 WapiAEMultiCastPNInitialValueSrc[16] = {0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ; ++ ++ if(param->u.crypt.set_tx == 1) ++ { ++ list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { ++ if(_rtw_memcmp(pWapiSta->PeerMacAddr,param->sta_addr,6)) ++ { ++ _rtw_memcpy(pWapiSta->lastTxUnicastPN,WapiASUEPNInitialValueSrc,16); ++ ++ pWapiSta->wapiUsk.bSet = true; ++ _rtw_memcpy(pWapiSta->wapiUsk.dataKey,param->u.crypt.key,16); ++ _rtw_memcpy(pWapiSta->wapiUsk.micKey,param->u.crypt.key+16,16); ++ pWapiSta->wapiUsk.keyId = param->u.crypt.idx ; ++ pWapiSta->wapiUsk.bTxEnable = true; ++ ++ _rtw_memcpy(pWapiSta->lastRxUnicastPNBEQueue,WapiAEPNInitialValueSrc,16); ++ _rtw_memcpy(pWapiSta->lastRxUnicastPNBKQueue,WapiAEPNInitialValueSrc,16); ++ _rtw_memcpy(pWapiSta->lastRxUnicastPNVIQueue,WapiAEPNInitialValueSrc,16); ++ _rtw_memcpy(pWapiSta->lastRxUnicastPNVOQueue,WapiAEPNInitialValueSrc,16); ++ _rtw_memcpy(pWapiSta->lastRxUnicastPN,WapiAEPNInitialValueSrc,16); ++ pWapiSta->wapiUskUpdate.bTxEnable = false; ++ pWapiSta->wapiUskUpdate.bSet = false; ++ ++ if (psecuritypriv->sw_encrypt== false || psecuritypriv->sw_decrypt == false) ++ { ++ //set unicast key for ASUE ++ rtw_wapi_set_key(padapter, &pWapiSta->wapiUsk, pWapiSta, false, false); ++ } ++ } ++ } ++ } ++ else ++ { ++ list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { ++ if(_rtw_memcmp(pWapiSta->PeerMacAddr,get_bssid(pmlmepriv),6)) ++ { ++ pWapiSta->wapiMsk.bSet = true; ++ _rtw_memcpy(pWapiSta->wapiMsk.dataKey,param->u.crypt.key,16); ++ _rtw_memcpy(pWapiSta->wapiMsk.micKey,param->u.crypt.key+16,16); ++ pWapiSta->wapiMsk.keyId = param->u.crypt.idx ; ++ pWapiSta->wapiMsk.bTxEnable = false; ++ if(!pWapiSta->bSetkeyOk) ++ pWapiSta->bSetkeyOk = true; ++ pWapiSta->bAuthenticateInProgress = false; ++ ++ _rtw_memcpy(pWapiSta->lastRxMulticastPN, WapiAEMultiCastPNInitialValueSrc, 16); ++ ++ if (psecuritypriv->sw_decrypt == false) ++ { ++ //set rx broadcast key for ASUE ++ rtw_wapi_set_key(padapter, &pWapiSta->wapiMsk, pWapiSta, true, false); ++ } ++ } ++ ++ } ++ } ++ } ++#endif ++ ++exit: ++ ++ if (pwep) { ++ rtw_mfree((u8 *)pwep, wep_total_len); ++ } ++ ++_func_exit_; ++ ++ return ret; ++} ++ ++static int rtw_set_wpa_ie(_adapter *padapter, char *pie, unsigned short ielen) ++{ ++ u8 *buf=NULL, *pos=NULL; ++ u32 left; ++ int group_cipher = 0, pairwise_cipher = 0; ++ int ret = 0; ++ u8 null_addr[]= {0,0,0,0,0,0}; ++#ifdef CONFIG_P2P ++ struct wifidirect_info* pwdinfo = &padapter->wdinfo; ++#endif //CONFIG_P2P ++ ++ if((ielen > MAX_WPA_IE_LEN) || (pie == NULL)){ ++ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); ++ if(pie == NULL) ++ return ret; ++ else ++ return -EINVAL; ++ } ++ ++ if(ielen) ++ { ++ buf = rtw_zmalloc(ielen); ++ if (buf == NULL){ ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ++ _rtw_memcpy(buf, pie , ielen); ++ ++ //dump ++ { ++ int i; ++ DBG_871X("\n wpa_ie(length:%d):\n", ielen); ++ for(i=0;i= RSN_SELECTOR_LEN){ ++ pos += RSN_SELECTOR_LEN; ++ left -= RSN_SELECTOR_LEN; ++ } ++ else if (left > 0){ ++ RT_TRACE(_module_rtl871x_ioctl_os_c,_drv_err_,("Ie length mismatch, %u too much \n", left)); ++ ret =-1; ++ goto exit; ++ } ++#endif ++ ++ if(rtw_parse_wpa_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) ++ { ++ padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_8021X; ++ padapter->securitypriv.ndisauthtype=Ndis802_11AuthModeWPAPSK; ++ _rtw_memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen); ++ } ++ ++ if(rtw_parse_wpa2_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) ++ { ++ padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_8021X; ++ padapter->securitypriv.ndisauthtype=Ndis802_11AuthModeWPA2PSK; ++ _rtw_memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen); ++ } ++ ++ if (group_cipher == 0) ++ { ++ group_cipher = WPA_CIPHER_NONE; ++ } ++ if (pairwise_cipher == 0) ++ { ++ pairwise_cipher = WPA_CIPHER_NONE; ++ } ++ ++ switch(group_cipher) ++ { ++ case WPA_CIPHER_NONE: ++ padapter->securitypriv.dot118021XGrpPrivacy=_NO_PRIVACY_; ++ padapter->securitypriv.ndisencryptstatus=Ndis802_11EncryptionDisabled; ++ break; ++ case WPA_CIPHER_WEP40: ++ padapter->securitypriv.dot118021XGrpPrivacy=_WEP40_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ case WPA_CIPHER_TKIP: ++ padapter->securitypriv.dot118021XGrpPrivacy=_TKIP_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; ++ break; ++ case WPA_CIPHER_CCMP: ++ padapter->securitypriv.dot118021XGrpPrivacy=_AES_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; ++ break; ++ case WPA_CIPHER_WEP104: ++ padapter->securitypriv.dot118021XGrpPrivacy=_WEP104_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ } ++ ++ switch(pairwise_cipher) ++ { ++ case WPA_CIPHER_NONE: ++ padapter->securitypriv.dot11PrivacyAlgrthm=_NO_PRIVACY_; ++ padapter->securitypriv.ndisencryptstatus=Ndis802_11EncryptionDisabled; ++ break; ++ case WPA_CIPHER_WEP40: ++ padapter->securitypriv.dot11PrivacyAlgrthm=_WEP40_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ case WPA_CIPHER_TKIP: ++ padapter->securitypriv.dot11PrivacyAlgrthm=_TKIP_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; ++ break; ++ case WPA_CIPHER_CCMP: ++ padapter->securitypriv.dot11PrivacyAlgrthm=_AES_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; ++ break; ++ case WPA_CIPHER_WEP104: ++ padapter->securitypriv.dot11PrivacyAlgrthm=_WEP104_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ } ++ ++ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); ++ {//set wps_ie ++ u16 cnt = 0; ++ u8 eid, wps_oui[4]={0x0,0x50,0xf2,0x04}; ++ ++ while( cnt < ielen ) ++ { ++ eid = buf[cnt]; ++ ++ if((eid==_VENDOR_SPECIFIC_IE_)&&(_rtw_memcmp(&buf[cnt+2], wps_oui, 4)==_TRUE)) ++ { ++ DBG_871X("SET WPS_IE\n"); ++ ++ padapter->securitypriv.wps_ie_len = ( (buf[cnt+1]+2) < (MAX_WPA_IE_LEN<<2)) ? (buf[cnt+1]+2):(MAX_WPA_IE_LEN<<2); ++ ++ _rtw_memcpy(padapter->securitypriv.wps_ie, &buf[cnt], padapter->securitypriv.wps_ie_len); ++ ++ set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS); ++ ++#ifdef CONFIG_P2P ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_OK)) ++ { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_PROVISIONING_ING); ++ } ++#endif //CONFIG_P2P ++ cnt += buf[cnt+1]+2; ++ ++ break; ++ } else { ++ cnt += buf[cnt+1]+2; //goto next ++ } ++ } ++ } ++ } ++ ++ //TKIP and AES disallow multicast packets until installing group key ++ if(padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_ ++ || padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_WTMIC_ ++ || padapter->securitypriv.dot11PrivacyAlgrthm == _AES_) ++ //WPS open need to enable multicast ++ //|| check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) == _TRUE) ++ rtw_hal_set_hwreg(padapter, HW_VAR_OFF_RCR_AM, null_addr); ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ++ ("rtw_set_wpa_ie: pairwise_cipher=0x%08x padapter->securitypriv.ndisencryptstatus=%d padapter->securitypriv.ndisauthtype=%d\n", ++ pairwise_cipher, padapter->securitypriv.ndisencryptstatus, padapter->securitypriv.ndisauthtype)); ++ ++exit: ++ ++ if (buf) rtw_mfree(buf, ielen); ++ ++ return ret; ++} ++ ++static int rtw_wx_get_name(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ u16 cap; ++ u32 ht_ielen = 0; ++ char *p; ++ u8 ht_cap=_FALSE; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ WLAN_BSSID_EX *pcur_bss = &pmlmepriv->cur_network.network; ++ NDIS_802_11_RATES_EX* prates = NULL; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("cmd_code=%x\n", info->cmd)); ++ ++ _func_enter_; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == _TRUE) ++ { ++ //parsing HT_CAP_IE ++ p = rtw_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pcur_bss->IELength-12); ++ if(p && ht_ielen>0) ++ { ++ ht_cap = _TRUE; ++ } ++ ++ prates = &pcur_bss->SupportedRates; ++ ++ if (rtw_is_cckratesonly_included((u8*)prates) == _TRUE) ++ { ++ if(ht_cap == _TRUE) ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bn"); ++ else ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b"); ++ } ++ else if ((rtw_is_cckrates_included((u8*)prates)) == _TRUE) ++ { ++ if(ht_cap == _TRUE) ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bgn"); ++ else ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bg"); ++ } ++ else ++ { ++ if(pcur_bss->Configuration.DSConfig > 14) ++ { ++ if(ht_cap == _TRUE) ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11an"); ++ else ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11a"); ++ } ++ else ++ { ++ if(ht_cap == _TRUE) ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11gn"); ++ else ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11g"); ++ } ++ } ++ } ++ else ++ { ++ //prates = &padapter->registrypriv.dev_network.SupportedRates; ++ //snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11g"); ++ snprintf(wrqu->name, IFNAMSIZ, "unassociated"); ++ } ++ ++ _func_exit_; ++ ++ return 0; ++} ++ ++static int rtw_wx_set_freq(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ _func_enter_; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_wx_set_freq\n")); ++ ++ _func_exit_; ++ ++ return 0; ++} ++ ++static int rtw_wx_get_freq(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ WLAN_BSSID_EX *pcur_bss = &pmlmepriv->cur_network.network; ++ ++ if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ++ { ++ //wrqu->freq.m = ieee80211_wlan_frequencies[pcur_bss->Configuration.DSConfig-1] * 100000; ++ wrqu->freq.m = rtw_ch2freq(pcur_bss->Configuration.DSConfig) * 100000; ++ wrqu->freq.e = 1; ++ wrqu->freq.i = pcur_bss->Configuration.DSConfig; ++ ++ } ++ else{ ++ wrqu->freq.m = rtw_ch2freq(padapter->mlmeextpriv.cur_channel) * 100000; ++ wrqu->freq.e = 1; ++ wrqu->freq.i = padapter->mlmeextpriv.cur_channel; ++ } ++ ++ return 0; ++} ++ ++static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ NDIS_802_11_NETWORK_INFRASTRUCTURE networkType ; ++ int ret = 0; ++ ++ _func_enter_; ++ ++ if(_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret= -EPERM; ++ goto exit; ++ } ++ ++ if (padapter->hw_init_completed==_FALSE){ ++ ret = -EPERM; ++ goto exit; ++ } ++ ++ switch(wrqu->mode) ++ { ++ case IW_MODE_AUTO: ++ networkType = Ndis802_11AutoUnknown; ++ DBG_871X("set_mode = IW_MODE_AUTO\n"); ++ break; ++ case IW_MODE_ADHOC: ++ networkType = Ndis802_11IBSS; ++ DBG_871X("set_mode = IW_MODE_ADHOC\n"); ++ break; ++ case IW_MODE_MASTER: ++ networkType = Ndis802_11APMode; ++ DBG_871X("set_mode = IW_MODE_MASTER\n"); ++ //rtw_setopmode_cmd(padapter, networkType,_TRUE); ++ break; ++ case IW_MODE_INFRA: ++ networkType = Ndis802_11Infrastructure; ++ DBG_871X("set_mode = IW_MODE_INFRA\n"); ++ break; ++ ++ default : ++ ret = -EINVAL;; ++ RT_TRACE(_module_rtl871x_ioctl_os_c,_drv_err_,("\n Mode: %s is not supported \n", iw_operation_mode[wrqu->mode])); ++ goto exit; ++ } ++ ++/* ++ if(Ndis802_11APMode == networkType) ++ { ++ rtw_setopmode_cmd(padapter, networkType,_TRUE); ++ } ++ else ++ { ++ rtw_setopmode_cmd(padapter, Ndis802_11AutoUnknown,_TRUE); ++ } ++*/ ++ ++ if (rtw_set_802_11_infrastructure_mode(padapter, networkType) ==_FALSE){ ++ ++ ret = -EPERM; ++ goto exit; ++ ++ } ++ ++ rtw_setopmode_cmd(padapter, networkType,_TRUE); ++ ++exit: ++ ++ _func_exit_; ++ ++ return ret; ++ ++} ++ ++static int rtw_wx_get_mode(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,(" rtw_wx_get_mode \n")); ++ ++ _func_enter_; ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) ++ { ++ wrqu->mode = IW_MODE_INFRA; ++ } ++ else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE)) ++ ++ { ++ wrqu->mode = IW_MODE_ADHOC; ++ } ++ else if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ { ++ wrqu->mode = IW_MODE_MASTER; ++ } ++ else ++ { ++ wrqu->mode = IW_MODE_AUTO; ++ } ++ ++ _func_exit_; ++ ++ return 0; ++ ++} ++ ++ ++static int rtw_wx_set_pmkid(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ u8 j,blInserted = _FALSE; ++ int intReturn = _FALSE; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct iw_pmksa* pPMK = ( struct iw_pmksa* ) extra; ++ u8 strZeroMacAddress[ ETH_ALEN ] = { 0x00 }; ++ u8 strIssueBssid[ ETH_ALEN ] = { 0x00 }; ++ ++/* ++ struct iw_pmksa ++ { ++ __u32 cmd; ++ struct sockaddr bssid; ++ __u8 pmkid[IW_PMKID_LEN]; //IW_PMKID_LEN=16 ++ } ++ There are the BSSID information in the bssid.sa_data array. ++ If cmd is IW_PMKSA_FLUSH, it means the wpa_suppplicant wants to clear all the PMKID information. ++ If cmd is IW_PMKSA_ADD, it means the wpa_supplicant wants to add a PMKID/BSSID to driver. ++ If cmd is IW_PMKSA_REMOVE, it means the wpa_supplicant wants to remove a PMKID/BSSID from driver. ++ */ ++ ++ _rtw_memcpy( strIssueBssid, pPMK->bssid.sa_data, ETH_ALEN); ++ if ( pPMK->cmd == IW_PMKSA_ADD ) ++ { ++ DBG_871X( "[rtw_wx_set_pmkid] IW_PMKSA_ADD!\n" ); ++ if ( _rtw_memcmp( strIssueBssid, strZeroMacAddress, ETH_ALEN ) == _TRUE ) ++ { ++ return( intReturn ); ++ } ++ else ++ { ++ intReturn = _TRUE; ++ } ++ blInserted = _FALSE; ++ ++ //overwrite PMKID ++ for(j=0 ; jPMKIDList[j].Bssid, strIssueBssid, ETH_ALEN) ==_TRUE ) ++ { // BSSID is matched, the same AP => rewrite with new PMKID. ++ ++ DBG_871X( "[rtw_wx_set_pmkid] BSSID exists in the PMKList.\n" ); ++ ++ _rtw_memcpy( psecuritypriv->PMKIDList[j].PMKID, pPMK->pmkid, IW_PMKID_LEN); ++ psecuritypriv->PMKIDList[ j ].bUsed = _TRUE; ++ psecuritypriv->PMKIDIndex = j+1; ++ blInserted = _TRUE; ++ break; ++ } ++ } ++ ++ if(!blInserted) ++ { ++ // Find a new entry ++ DBG_871X( "[rtw_wx_set_pmkid] Use the new entry index = %d for this PMKID.\n", ++ psecuritypriv->PMKIDIndex ); ++ ++ _rtw_memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].Bssid, strIssueBssid, ETH_ALEN); ++ _rtw_memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].PMKID, pPMK->pmkid, IW_PMKID_LEN); ++ ++ psecuritypriv->PMKIDList[ psecuritypriv->PMKIDIndex ].bUsed = _TRUE; ++ psecuritypriv->PMKIDIndex++ ; ++ if(psecuritypriv->PMKIDIndex==16) ++ { ++ psecuritypriv->PMKIDIndex =0; ++ } ++ } ++ } ++ else if ( pPMK->cmd == IW_PMKSA_REMOVE ) ++ { ++ DBG_871X( "[rtw_wx_set_pmkid] IW_PMKSA_REMOVE!\n" ); ++ intReturn = _TRUE; ++ for(j=0 ; jPMKIDList[j].Bssid, strIssueBssid, ETH_ALEN) ==_TRUE ) ++ { // BSSID is matched, the same AP => Remove this PMKID information and reset it. ++ _rtw_memset( psecuritypriv->PMKIDList[ j ].Bssid, 0x00, ETH_ALEN ); ++ psecuritypriv->PMKIDList[ j ].bUsed = _FALSE; ++ break; ++ } ++ } ++ } ++ else if ( pPMK->cmd == IW_PMKSA_FLUSH ) ++ { ++ DBG_871X( "[rtw_wx_set_pmkid] IW_PMKSA_FLUSH!\n" ); ++ _rtw_memset( &psecuritypriv->PMKIDList[ 0 ], 0x00, sizeof( RT_PMKID_LIST ) * NUM_PMKID_CACHE ); ++ psecuritypriv->PMKIDIndex = 0; ++ intReturn = _TRUE; ++ } ++ return( intReturn ); ++} ++ ++static int rtw_wx_get_sens(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ #ifdef CONFIG_PLATFORM_ROCKCHIPS ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ /* ++ * 20110311 Commented by Jeff ++ * For rockchip platform's wpa_driver_wext_get_rssi ++ */ ++ if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { ++ //wrqu->sens.value=-padapter->recvpriv.signal_strength; ++ wrqu->sens.value=-padapter->recvpriv.rssi; ++ //DBG_871X("%s: %d\n", __FUNCTION__, wrqu->sens.value); ++ wrqu->sens.fixed = 0; /* no auto select */ ++ } else ++ #endif ++ { ++ wrqu->sens.value = 0; ++ wrqu->sens.fixed = 0; /* no auto select */ ++ wrqu->sens.disabled = 1; ++ } ++ return 0; ++} ++ ++static int rtw_wx_get_range(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct iw_range *range = (struct iw_range *)extra; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ u16 val; ++ int i; ++ ++ _func_enter_; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_wx_get_range. cmd_code=%x\n", info->cmd)); ++ ++ wrqu->data.length = sizeof(*range); ++ _rtw_memset(range, 0, sizeof(*range)); ++ ++ /* Let's try to keep this struct in the same order as in ++ * linux/include/wireless.h ++ */ ++ ++ /* TODO: See what values we can set, and remove the ones we can't ++ * set, or fill them with some default data. ++ */ ++ ++ /* ~5 Mb/s real (802.11b) */ ++ range->throughput = 5 * 1000 * 1000; ++ ++ // TODO: Not used in 802.11b? ++// range->min_nwid; /* Minimal NWID we are able to set */ ++ // TODO: Not used in 802.11b? ++// range->max_nwid; /* Maximal NWID we are able to set */ ++ ++ /* Old Frequency (backward compat - moved lower ) */ ++// range->old_num_channels; ++// range->old_num_frequency; ++// range->old_freq[6]; /* Filler to keep "version" at the same offset */ ++ ++ /* signal level threshold range */ ++ ++ //percent values between 0 and 100. ++ range->max_qual.qual = 100; ++ range->max_qual.level = 100; ++ range->max_qual.noise = 100; ++ range->max_qual.updated = 7; /* Updated all three */ ++ ++ ++ range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */ ++ /* TODO: Find real 'good' to 'bad' threshol value for RSSI */ ++ range->avg_qual.level = 20 + -98; ++ range->avg_qual.noise = 0; ++ range->avg_qual.updated = 7; /* Updated all three */ ++ ++ range->num_bitrates = RATE_COUNT; ++ ++ for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) { ++ range->bitrate[i] = rtw_rates[i]; ++ } ++ ++ range->min_frag = MIN_FRAG_THRESHOLD; ++ range->max_frag = MAX_FRAG_THRESHOLD; ++ ++ range->pm_capa = 0; ++ ++ range->we_version_compiled = WIRELESS_EXT; ++ range->we_version_source = 16; ++ ++// range->retry_capa; /* What retry options are supported */ ++// range->retry_flags; /* How to decode max/min retry limit */ ++// range->r_time_flags; /* How to decode max/min retry life */ ++// range->min_retry; /* Minimal number of retries */ ++// range->max_retry; /* Maximal number of retries */ ++// range->min_r_time; /* Minimal retry lifetime */ ++// range->max_r_time; /* Maximal retry lifetime */ ++ ++ for (i = 0, val = 0; i < MAX_CHANNEL_NUM; i++) { ++ ++ // Include only legal frequencies for some countries ++ if(pmlmeext->channel_set[i].ChannelNum != 0) ++ { ++ range->freq[val].i = pmlmeext->channel_set[i].ChannelNum; ++ range->freq[val].m = rtw_ch2freq(pmlmeext->channel_set[i].ChannelNum) * 100000; ++ range->freq[val].e = 1; ++ val++; ++ } ++ ++ if (val == IW_MAX_FREQUENCIES) ++ break; ++ } ++ ++ range->num_channels = val; ++ range->num_frequency = val; ++ ++// Commented by Albert 2009/10/13 ++// The following code will proivde the security capability to network manager. ++// If the driver doesn't provide this capability to network manager, ++// the WPA/WPA2 routers can't be choosen in the network manager. ++ ++/* ++#define IW_SCAN_CAPA_NONE 0x00 ++#define IW_SCAN_CAPA_ESSID 0x01 ++#define IW_SCAN_CAPA_BSSID 0x02 ++#define IW_SCAN_CAPA_CHANNEL 0x04 ++#define IW_SCAN_CAPA_MODE 0x08 ++#define IW_SCAN_CAPA_RATE 0x10 ++#define IW_SCAN_CAPA_TYPE 0x20 ++#define IW_SCAN_CAPA_TIME 0x40 ++*/ ++ ++#if WIRELESS_EXT > 17 ++ range->enc_capa = IW_ENC_CAPA_WPA|IW_ENC_CAPA_WPA2| ++ IW_ENC_CAPA_CIPHER_TKIP|IW_ENC_CAPA_CIPHER_CCMP; ++#endif ++ ++#ifdef IW_SCAN_CAPA_ESSID //WIRELESS_EXT > 21 ++ range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE |IW_SCAN_CAPA_BSSID| ++ IW_SCAN_CAPA_CHANNEL|IW_SCAN_CAPA_MODE|IW_SCAN_CAPA_RATE; ++#endif ++ ++ ++ _func_exit_; ++ ++ return 0; ++ ++} ++ ++//set bssid flow ++//s1. rtw_set_802_11_infrastructure_mode() ++//s2. rtw_set_802_11_authentication_mode() ++//s3. set_802_11_encryption_mode() ++//s4. rtw_set_802_11_bssid() ++static int rtw_wx_set_wap(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra) ++{ ++ _irqL irqL; ++ uint ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct sockaddr *temp = (struct sockaddr *)awrq; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ _list *phead; ++ u8 *dst_bssid, *src_bssid; ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ NDIS_802_11_AUTHENTICATION_MODE authmode; ++ ++ _func_enter_; ++/* ++#ifdef CONFIG_CONCURRENT_MODE ++ if(padapter->iface_type > PRIMARY_IFACE) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++#endif ++*/ ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (check_buddy_fwstate(padapter, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE) ++ { ++ DBG_871X("set bssid, but buddy_intf is under scanning or linking\n"); ++ ++ ret = -EINVAL; ++ ++ goto exit; ++ } ++#endif ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ if (dc_check_fwstate(padapter, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)== _TRUE) ++ { ++ DBG_871X("set bssid, but buddy_intf is under scanning or linking\n"); ++ ret = -EINVAL; ++ goto exit; ++ } ++#endif ++ ++ if(_FAIL == rtw_pwr_wakeup(padapter)) ++ { ++ ret= -1; ++ goto exit; ++ } ++ ++ if(!padapter->bup){ ++ ret = -1; ++ goto exit; ++ } ++ ++ ++ if (temp->sa_family != ARPHRD_ETHER){ ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ authmode = padapter->securitypriv.ndisauthtype; ++ _enter_critical_bh(&queue->lock, &irqL); ++ phead = get_list_head(queue); ++ pmlmepriv->pscanned = get_next(phead); ++ ++ while (1) ++ { ++ ++ if ((rtw_end_of_queue_search(phead, pmlmepriv->pscanned)) == _TRUE) ++ { ++#if 0 ++ ret = -EINVAL; ++ goto exit; ++ ++ if(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) ++ { ++ rtw_set_802_11_bssid(padapter, temp->sa_data); ++ goto exit; ++ } ++ else ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++#endif ++ ++ break; ++ } ++ ++ pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list); ++ ++ pmlmepriv->pscanned = get_next(pmlmepriv->pscanned); ++ ++ dst_bssid = pnetwork->network.MacAddress; ++ ++ src_bssid = temp->sa_data; ++ ++ if ((_rtw_memcmp(dst_bssid, src_bssid, ETH_ALEN)) == _TRUE) ++ { ++ if(!rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode)) ++ { ++ ret = -1; ++ _exit_critical_bh(&queue->lock, &irqL); ++ goto exit; ++ } ++ ++ break; ++ } ++ ++ } ++ _exit_critical_bh(&queue->lock, &irqL); ++ ++ rtw_set_802_11_authentication_mode(padapter, authmode); ++ //set_802_11_encryption_mode(padapter, padapter->securitypriv.ndisencryptstatus); ++ if (rtw_set_802_11_bssid(padapter, temp->sa_data) == _FALSE) { ++ ret = -1; ++ goto exit; ++ } ++ ++exit: ++ ++ _func_exit_; ++ ++ return ret; ++} ++ ++static int rtw_wx_get_wap(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ WLAN_BSSID_EX *pcur_bss = &pmlmepriv->cur_network.network; ++ ++ wrqu->ap_addr.sa_family = ARPHRD_ETHER; ++ ++ _rtw_memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_wx_get_wap\n")); ++ ++ _func_enter_; ++ ++ if ( ((check_fwstate(pmlmepriv, _FW_LINKED)) == _TRUE) || ++ ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == _TRUE) || ++ ((check_fwstate(pmlmepriv, WIFI_AP_STATE)) == _TRUE) ) ++ { ++ ++ _rtw_memcpy(wrqu->ap_addr.sa_data, pcur_bss->MacAddress, ETH_ALEN); ++ } ++ else ++ { ++ _rtw_memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); ++ } ++ ++ _func_exit_; ++ ++ return 0; ++ ++} ++ ++static int rtw_wx_set_mlme(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++#if 0 ++/* SIOCSIWMLME data */ ++struct iw_mlme ++{ ++ __u16 cmd; /* IW_MLME_* */ ++ __u16 reason_code; ++ struct sockaddr addr; ++}; ++#endif ++ ++ int ret=0; ++ u16 reason; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_mlme *mlme = (struct iw_mlme *) extra; ++ ++ ++ if(mlme==NULL) ++ return -1; ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ reason = cpu_to_le16(mlme->reason_code); ++ ++ ++ DBG_871X("%s, cmd=%d, reason=%d\n", __FUNCTION__, mlme->cmd, reason); ++ ++ ++ switch (mlme->cmd) ++ { ++ case IW_MLME_DEAUTH: ++ if(!rtw_set_802_11_disassociate(padapter)) ++ ret = -1; ++ break; ++ ++ case IW_MLME_DISASSOC: ++ if(!rtw_set_802_11_disassociate(padapter)) ++ ret = -1; ++ ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ u8 _status = _FALSE; ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv= &padapter->mlmepriv; ++ NDIS_802_11_SSID ssid[RTW_SSID_SCAN_AMOUNT]; ++ _irqL irqL; ++#ifdef CONFIG_P2P ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++#endif //CONFIG_P2P ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_wx_set_scan\n")); ++ ++_func_enter_; ++ ++ #ifdef DBG_IOCTL ++ DBG_871X("DBG_IOCTL %s:%d\n",__FUNCTION__, __LINE__); ++ #endif ++/* ++#ifdef CONFIG_CONCURRENT_MODE ++ if(padapter->iface_type > PRIMARY_IFACE) ++ { ++ ret = -1; ++ goto exit; ++ } ++#endif ++*/ ++ ++#ifdef CONFIG_MP_INCLUDED ++if (padapter->registrypriv.mp_mode == 1) ++{ ++ if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) ++ { ++ ret = -1; ++ goto exit; ++ } ++} ++#endif ++ if(_FAIL == rtw_pwr_wakeup(padapter)) ++ { ++ ret= -1; ++ goto exit; ++ } ++ ++ if(padapter->bDriverStopped){ ++ DBG_871X("bDriverStopped=%d\n", padapter->bDriverStopped); ++ ret= -1; ++ goto exit; ++ } ++ ++ if(!padapter->bup){ ++ ret = -1; ++ goto exit; ++ } ++ ++ if (padapter->hw_init_completed==_FALSE){ ++ ret = -1; ++ goto exit; ++ } ++ ++ // When Busy Traffic, driver do not site survey. So driver return success. ++ // wpa_supplicant will not issue SIOCSIWSCAN cmd again after scan timeout. ++ // modify by thomas 2011-02-22. ++ if (pmlmepriv->LinkDetectInfo.bBusyTraffic == _TRUE ++#ifdef CONFIG_CONCURRENT_MODE ++ || rtw_get_buddy_bBusyTraffic(padapter) == _TRUE ++#endif //CONFIG_CONCURRENT_MODE ++ ) ++ { ++ indicate_wx_scan_complete_event(padapter); ++ goto exit; ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE) ++ { ++ indicate_wx_scan_complete_event(padapter); ++ goto exit; ++ } ++ ++#ifdef CONFIG_BT_COEXIST ++ { ++ u32 curr_time, delta_time; ++ ++ // under DHCP(Special packet) ++ curr_time = rtw_get_current_time(); ++ delta_time = curr_time - adapter_to_pwrctl(padapter)->DelayLPSLastTimeStamp; ++ delta_time = rtw_systime_to_ms(delta_time); ++ if (delta_time < 500) // 500ms ++ { ++ DBG_871X("%s: send DHCP pkt before %d ms, Skip scan\n", __FUNCTION__, delta_time); ++ ret = -1; ++ goto exit; ++ } ++ } ++#endif ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (check_buddy_fwstate(padapter, ++ _FW_UNDER_SURVEY|_FW_UNDER_LINKING|WIFI_UNDER_WPS) == _TRUE) ++ { ++ if(check_buddy_fwstate(padapter, _FW_UNDER_SURVEY)) ++ { ++ DBG_871X("scanning_via_buddy_intf\n"); ++ pmlmepriv->scanning_via_buddy_intf = _TRUE; ++ } ++ ++ indicate_wx_scan_complete_event(padapter); ++ ++ goto exit; ++ } ++#endif ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ if (dc_check_fwstate(padapter, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)== _TRUE) ++ { ++ indicate_wx_scan_complete_event(padapter); ++ goto exit; ++ } ++#endif ++ ++// Mareded by Albert 20101103 ++// For the DMP WiFi Display project, the driver won't to scan because ++// the pmlmepriv->scan_interval is always equal to 3. ++// So, the wpa_supplicant won't find out the WPS SoftAP. ++ ++/* ++ if(pmlmepriv->scan_interval>10) ++ pmlmepriv->scan_interval = 0; ++ ++ if(pmlmepriv->scan_interval > 0) ++ { ++ DBG_871X("scan done\n"); ++ ret = 0; ++ goto exit; ++ } ++ ++*/ ++#ifdef CONFIG_P2P ++ if ( pwdinfo->p2p_state != P2P_STATE_NONE ) ++ { ++ rtw_p2p_set_pre_state( pwdinfo, rtw_p2p_state( pwdinfo ) ); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH); ++ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_FULL); ++ rtw_free_network_queue(padapter, _TRUE); ++ } ++#endif //CONFIG_P2P ++ ++ _rtw_memset(ssid, 0, sizeof(NDIS_802_11_SSID)*RTW_SSID_SCAN_AMOUNT); ++ ++#if WIRELESS_EXT >= 17 ++ if (wrqu->data.length == sizeof(struct iw_scan_req)) ++ { ++ struct iw_scan_req *req = (struct iw_scan_req *)extra; ++ ++ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) ++ { ++ int len = min((int)req->essid_len, IW_ESSID_MAX_SIZE); ++ ++ _rtw_memcpy(ssid[0].Ssid, req->essid, len); ++ ssid[0].SsidLength = len; ++ ++ DBG_871X("IW_SCAN_THIS_ESSID, ssid=%s, len=%d\n", req->essid, req->essid_len); ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ _status = rtw_sitesurvey_cmd(padapter, ssid, 1, NULL, 0); ++ ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++ } ++ else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) ++ { ++ DBG_871X("rtw_wx_set_scan, req->scan_type == IW_SCAN_TYPE_PASSIVE\n"); ++ } ++ ++ } ++ else ++#endif ++ ++ if( wrqu->data.length >= WEXT_CSCAN_HEADER_SIZE ++ && _rtw_memcmp(extra, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) == _TRUE ++ ) ++ { ++ int len = wrqu->data.length -WEXT_CSCAN_HEADER_SIZE; ++ char *pos = extra+WEXT_CSCAN_HEADER_SIZE; ++ char section; ++ char sec_len; ++ int ssid_index = 0; ++ ++ //DBG_871X("%s COMBO_SCAN header is recognized\n", __FUNCTION__); ++ ++ while(len >= 1) { ++ section = *(pos++); len-=1; ++ ++ switch(section) { ++ case WEXT_CSCAN_SSID_SECTION: ++ //DBG_871X("WEXT_CSCAN_SSID_SECTION\n"); ++ if(len < 1) { ++ len = 0; ++ break; ++ } ++ ++ sec_len = *(pos++); len-=1; ++ ++ if(sec_len>0 && sec_len<=len) { ++ ssid[ssid_index].SsidLength = sec_len; ++ _rtw_memcpy(ssid[ssid_index].Ssid, pos, ssid[ssid_index].SsidLength); ++ //DBG_871X("%s COMBO_SCAN with specific ssid:%s, %d\n", __FUNCTION__ ++ // , ssid[ssid_index].Ssid, ssid[ssid_index].SsidLength); ++ ssid_index++; ++ } ++ ++ pos+=sec_len; len-=sec_len; ++ break; ++ ++ ++ case WEXT_CSCAN_CHANNEL_SECTION: ++ //DBG_871X("WEXT_CSCAN_CHANNEL_SECTION\n"); ++ pos+=1; len-=1; ++ break; ++ case WEXT_CSCAN_ACTV_DWELL_SECTION: ++ //DBG_871X("WEXT_CSCAN_ACTV_DWELL_SECTION\n"); ++ pos+=2; len-=2; ++ break; ++ case WEXT_CSCAN_PASV_DWELL_SECTION: ++ //DBG_871X("WEXT_CSCAN_PASV_DWELL_SECTION\n"); ++ pos+=2; len-=2; ++ break; ++ case WEXT_CSCAN_HOME_DWELL_SECTION: ++ //DBG_871X("WEXT_CSCAN_HOME_DWELL_SECTION\n"); ++ pos+=2; len-=2; ++ break; ++ case WEXT_CSCAN_TYPE_SECTION: ++ //DBG_871X("WEXT_CSCAN_TYPE_SECTION\n"); ++ pos+=1; len-=1; ++ break; ++ #if 0 ++ case WEXT_CSCAN_NPROBE_SECTION: ++ DBG_871X("WEXT_CSCAN_NPROBE_SECTION\n"); ++ break; ++ #endif ++ ++ default: ++ //DBG_871X("Unknown CSCAN section %c\n", section); ++ len = 0; // stop parsing ++ } ++ //DBG_871X("len:%d\n", len); ++ ++ } ++ ++ //jeff: it has still some scan paramater to parse, we only do this now... ++ _status = rtw_set_802_11_bssid_list_scan(padapter, ssid, RTW_SSID_SCAN_AMOUNT); ++ ++ } else ++ ++ { ++ _status = rtw_set_802_11_bssid_list_scan(padapter, NULL, 0); ++ } ++ ++ if(_status == _FALSE) ++ ret = -1; ++ ++exit: ++ #ifdef DBG_IOCTL ++ DBG_871X("DBG_IOCTL %s:%d return %d\n",__FUNCTION__, __LINE__, ret); ++ #endif ++ ++_func_exit_; ++ ++ return ret; ++} ++ ++static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ _irqL irqL; ++ _list *plist, *phead; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ char *ev = extra; ++ char *stop = ev + wrqu->data.length; ++ u32 ret = 0; ++ u32 cnt=0; ++ u32 wait_for_surveydone; ++ sint wait_status; ++#ifdef CONFIG_CONCURRENT_MODE ++ //PADAPTER pbuddy_adapter = padapter->pbuddy_adapter; ++ //struct mlme_priv *pbuddy_mlmepriv = &(pbuddy_adapter->mlmepriv); ++#endif ++#ifdef CONFIG_P2P ++ struct wifidirect_info* pwdinfo = &padapter->wdinfo; ++#endif //CONFIG_P2P ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_wx_get_scan\n")); ++ RT_TRACE(_module_rtl871x_ioctl_os_c,_drv_info_, (" Start of Query SIOCGIWSCAN .\n")); ++ ++ _func_enter_; ++ ++ #ifdef DBG_IOCTL ++ DBG_871X("DBG_IOCTL %s:%d\n",__FUNCTION__, __LINE__); ++ #endif ++ ++/* ++#ifdef CONFIG_CONCURRENT_MODE ++ if(padapter->iface_type > PRIMARY_IFACE) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++#endif ++*/ ++ if(adapter_to_pwrctl(padapter)->brfoffbyhw && padapter->bDriverStopped) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++#ifdef CONFIG_P2P ++ if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ // P2P is enabled ++ if ( padapter->chip_type == RTL8192D ) ++ wait_for_surveydone = 300; // Because the 8192du supports more channels. ++ else ++ wait_for_surveydone = 200; ++ } ++ else ++ { ++ // P2P is disabled ++ wait_for_surveydone = 100; ++ } ++#else ++ { ++ wait_for_surveydone = 100; ++ } ++#endif //CONFIG_P2P ++ ++/* ++#ifdef CONFIG_CONCURRENT_MODE ++ if(pmlmepriv->scanning_via_buddy_intf == _TRUE) ++ { ++ pmlmepriv->scanning_via_buddy_intf = _FALSE;//reset ++ ++ // change pointers to buddy interface ++ padapter = pbuddy_adapter; ++ pmlmepriv = pbuddy_mlmepriv; ++ queue = &(pbuddy_mlmepriv->scanned_queue); ++ ++ } ++#endif // CONFIG_CONCURRENT_MODE ++*/ ++#if 1 // Wireless Extension use EAGAIN to try ++ wait_status = _FW_UNDER_SURVEY ++#ifndef CONFIG_ANDROID ++ | _FW_UNDER_LINKING ++#endif ++ ; ++ ++ while (check_fwstate(pmlmepriv, wait_status) == _TRUE) ++ { ++ return -EAGAIN; ++ } ++#else ++ wait_status = _FW_UNDER_SURVEY ++ #ifndef CONFIG_ANDROID ++ |_FW_UNDER_LINKING ++ #endif ++ ; ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ while(dc_check_fwstate(padapter, wait_status)== _TRUE) ++ { ++ rtw_msleep_os(30); ++ cnt++; ++ if(cnt > wait_for_surveydone ) ++ break; ++ } ++#endif // CONFIG_DUALMAC_CONCURRENT ++ ++ while(check_fwstate(pmlmepriv, wait_status) == _TRUE) ++ { ++ rtw_msleep_os(30); ++ cnt++; ++ if(cnt > wait_for_surveydone ) ++ break; ++ } ++#endif ++ ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while(1) ++ { ++ if (rtw_end_of_queue_search(phead,plist)== _TRUE) ++ break; ++ ++ if((stop - ev) < SCAN_ITEM_SIZE) { ++ ret = -E2BIG; ++ break; ++ } ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ //report network only if the current channel set contains the channel to which this network belongs ++ if(rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0 ++ && _TRUE == rtw_validate_ssid(&(pnetwork->network.Ssid)) ++ ) ++ { ++ ev=translate_scan(padapter, a, pnetwork, ev, stop); ++ } ++ ++ plist = get_next(plist); ++ ++ } ++ ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ wrqu->data.length = ev-extra; ++ wrqu->data.flags = 0; ++ ++exit: ++ ++ _func_exit_; ++ ++ #ifdef DBG_IOCTL ++ DBG_871X("DBG_IOCTL %s:%d return %d\n",__FUNCTION__, __LINE__, ret); ++ #endif ++ ++ return ret ; ++ ++} ++ ++//set ssid flow ++//s1. rtw_set_802_11_infrastructure_mode() ++//s2. set_802_11_authenticaion_mode() ++//s3. set_802_11_encryption_mode() ++//s4. rtw_set_802_11_ssid() ++static int rtw_wx_set_essid(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ _irqL irqL; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ _queue *queue = &pmlmepriv->scanned_queue; ++ _list *phead; ++ s8 status = _TRUE; ++ struct wlan_network *pnetwork = NULL; ++ NDIS_802_11_AUTHENTICATION_MODE authmode; ++ NDIS_802_11_SSID ndis_ssid; ++ u8 *dst_ssid, *src_ssid; ++ ++ uint ret = 0, len; ++ ++ _func_enter_; ++ ++ #ifdef DBG_IOCTL ++ DBG_871X("DBG_IOCTL %s:%d\n",__FUNCTION__, __LINE__); ++ #endif ++ ++/* ++#ifdef CONFIG_CONCURRENT_MODE ++ if(padapter->iface_type > PRIMARY_IFACE) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++#endif ++*/ ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if (check_buddy_fwstate(padapter, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE) ++ { ++ DBG_871X("set ssid, but buddy_intf is under scanning or linking\n"); ++ ++ ret = -EINVAL; ++ ++ goto exit; ++ } ++#endif ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ if (dc_check_fwstate(padapter, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)== _TRUE) ++ { ++ DBG_871X("set bssid, but buddy_intf is under scanning or linking\n"); ++ ret = -EINVAL; ++ goto exit; ++ } ++#endif ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ++ ("+rtw_wx_set_essid: fw_state=0x%08x\n", get_fwstate(pmlmepriv))); ++ if(_FAIL == rtw_pwr_wakeup(padapter)) ++ { ++ ret = -1; ++ goto exit; ++ } ++ ++ if(!padapter->bup){ ++ ret = -1; ++ goto exit; ++ } ++ ++#if WIRELESS_EXT <= 20 ++ if ((wrqu->essid.length-1) > IW_ESSID_MAX_SIZE){ ++#else ++ if (wrqu->essid.length > IW_ESSID_MAX_SIZE){ ++#endif ++ ret= -E2BIG; ++ goto exit; ++ } ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ ret = -1; ++ goto exit; ++ } ++ ++ authmode = padapter->securitypriv.ndisauthtype; ++ DBG_871X("=>%s\n",__FUNCTION__); ++ if (wrqu->essid.flags && wrqu->essid.length) ++ { ++ // Commented by Albert 20100519 ++ // We got the codes in "set_info" function of iwconfig source code. ++ // ========================================= ++ // wrq.u.essid.length = strlen(essid) + 1; ++ // if(we_kernel_version > 20) ++ // wrq.u.essid.length--; ++ // ========================================= ++ // That means, if the WIRELESS_EXT less than or equal to 20, the correct ssid len should subtract 1. ++#if WIRELESS_EXT <= 20 ++ len = ((wrqu->essid.length-1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length-1) : IW_ESSID_MAX_SIZE; ++#else ++ len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? wrqu->essid.length : IW_ESSID_MAX_SIZE; ++#endif ++ ++ if( wrqu->essid.length != 33 ) ++ DBG_871X("ssid=%s, len=%d\n", extra, wrqu->essid.length); ++ ++ _rtw_memset(&ndis_ssid, 0, sizeof(NDIS_802_11_SSID)); ++ ndis_ssid.SsidLength = len; ++ _rtw_memcpy(ndis_ssid.Ssid, extra, len); ++ src_ssid = ndis_ssid.Ssid; ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("rtw_wx_set_essid: ssid=[%s]\n", src_ssid)); ++ _enter_critical_bh(&queue->lock, &irqL); ++ phead = get_list_head(queue); ++ pmlmepriv->pscanned = get_next(phead); ++ ++ while (1) ++ { ++ if (rtw_end_of_queue_search(phead, pmlmepriv->pscanned) == _TRUE) ++ { ++#if 0 ++ if(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) ++ { ++ rtw_set_802_11_ssid(padapter, &ndis_ssid); ++ ++ goto exit; ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_ioctl_os_c,_drv_info_,("rtw_wx_set_ssid(): scanned_queue is empty\n")); ++ ret = -EINVAL; ++ goto exit; ++ } ++#endif ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_warning_, ++ ("rtw_wx_set_essid: scan_q is empty, set ssid to check if scanning again!\n")); ++ ++ break; ++ } ++ ++ pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list); ++ ++ pmlmepriv->pscanned = get_next(pmlmepriv->pscanned); ++ ++ dst_ssid = pnetwork->network.Ssid.Ssid; ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ++ ("rtw_wx_set_essid: dst_ssid=%s\n", ++ pnetwork->network.Ssid.Ssid)); ++ ++ if ((_rtw_memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength) == _TRUE) && ++ (pnetwork->network.Ssid.SsidLength==ndis_ssid.SsidLength)) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ++ ("rtw_wx_set_essid: find match, set infra mode\n")); ++ ++ if(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) ++ { ++ if(pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode) ++ continue; ++ } ++ ++ if (rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode) == _FALSE) ++ { ++ ret = -1; ++ _exit_critical_bh(&queue->lock, &irqL); ++ goto exit; ++ } ++ ++ break; ++ } ++ } ++ _exit_critical_bh(&queue->lock, &irqL); ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ++ ("set ssid: set_802_11_auth. mode=%d\n", authmode)); ++ rtw_set_802_11_authentication_mode(padapter, authmode); ++ //set_802_11_encryption_mode(padapter, padapter->securitypriv.ndisencryptstatus); ++ if (rtw_set_802_11_ssid(padapter, &ndis_ssid) == _FALSE) { ++ ret = -1; ++ goto exit; ++ } ++ } ++ ++exit: ++ ++ DBG_871X("<=%s, ret %d\n",__FUNCTION__, ret); ++ ++ #ifdef DBG_IOCTL ++ DBG_871X("DBG_IOCTL %s:%d return %d\n",__FUNCTION__, __LINE__, ret); ++ #endif ++ ++ _func_exit_; ++ ++ return ret; ++} ++ ++static int rtw_wx_get_essid(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ u32 len,ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ WLAN_BSSID_EX *pcur_bss = &pmlmepriv->cur_network.network; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_wx_get_essid\n")); ++ ++ _func_enter_; ++ ++ if ( (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE)) ++ { ++ len = pcur_bss->Ssid.SsidLength; ++ ++ wrqu->essid.length = len; ++ ++ _rtw_memcpy(extra, pcur_bss->Ssid.Ssid, len); ++ ++ wrqu->essid.flags = 1; ++ } ++ else ++ { ++ ret = -1; ++ goto exit; ++ } ++ ++exit: ++ ++ _func_exit_; ++ ++ return ret; ++ ++} ++ ++static int rtw_wx_set_rate(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int i, ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ u8 datarates[NumRates]; ++ u32 target_rate = wrqu->bitrate.value; ++ u32 fixed = wrqu->bitrate.fixed; ++ u32 ratevalue = 0; ++ u8 mpdatarate[NumRates]={11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff}; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,(" rtw_wx_set_rate \n")); ++ RT_TRACE(_module_rtl871x_ioctl_os_c,_drv_info_,("target_rate = %d, fixed = %d\n",target_rate,fixed)); ++ ++ if(target_rate == -1){ ++ ratevalue = 11; ++ goto set_rate; ++ } ++ target_rate = target_rate/100000; ++ ++ switch(target_rate){ ++ case 10: ++ ratevalue = 0; ++ break; ++ case 20: ++ ratevalue = 1; ++ break; ++ case 55: ++ ratevalue = 2; ++ break; ++ case 60: ++ ratevalue = 3; ++ break; ++ case 90: ++ ratevalue = 4; ++ break; ++ case 110: ++ ratevalue = 5; ++ break; ++ case 120: ++ ratevalue = 6; ++ break; ++ case 180: ++ ratevalue = 7; ++ break; ++ case 240: ++ ratevalue = 8; ++ break; ++ case 360: ++ ratevalue = 9; ++ break; ++ case 480: ++ ratevalue = 10; ++ break; ++ case 540: ++ ratevalue = 11; ++ break; ++ default: ++ ratevalue = 11; ++ break; ++ } ++ ++set_rate: ++ ++ for(i=0; ibitrate.fixed = 0; /* no auto select */ ++ wrqu->bitrate.value = max_rate * 100000; ++ ++ return 0; ++} ++ ++static int rtw_wx_set_rts(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ _func_enter_; ++ ++ if (wrqu->rts.disabled) ++ padapter->registrypriv.rts_thresh = 2347; ++ else { ++ if (wrqu->rts.value < 0 || ++ wrqu->rts.value > 2347) ++ return -EINVAL; ++ ++ padapter->registrypriv.rts_thresh = wrqu->rts.value; ++ } ++ ++ DBG_871X("%s, rts_thresh=%d\n", __func__, padapter->registrypriv.rts_thresh); ++ ++ _func_exit_; ++ ++ return 0; ++ ++} ++ ++static int rtw_wx_get_rts(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ _func_enter_; ++ ++ DBG_871X("%s, rts_thresh=%d\n", __func__, padapter->registrypriv.rts_thresh); ++ ++ wrqu->rts.value = padapter->registrypriv.rts_thresh; ++ wrqu->rts.fixed = 0; /* no auto select */ ++ //wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); ++ ++ _func_exit_; ++ ++ return 0; ++} ++ ++static int rtw_wx_set_frag(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ _func_enter_; ++ ++ if (wrqu->frag.disabled) ++ padapter->xmitpriv.frag_len = MAX_FRAG_THRESHOLD; ++ else { ++ if (wrqu->frag.value < MIN_FRAG_THRESHOLD || ++ wrqu->frag.value > MAX_FRAG_THRESHOLD) ++ return -EINVAL; ++ ++ padapter->xmitpriv.frag_len = wrqu->frag.value & ~0x1; ++ } ++ ++ DBG_871X("%s, frag_len=%d\n", __func__, padapter->xmitpriv.frag_len); ++ ++ _func_exit_; ++ ++ return 0; ++ ++} ++ ++static int rtw_wx_get_frag(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ _func_enter_; ++ ++ DBG_871X("%s, frag_len=%d\n", __func__, padapter->xmitpriv.frag_len); ++ ++ wrqu->frag.value = padapter->xmitpriv.frag_len; ++ wrqu->frag.fixed = 0; /* no auto select */ ++ //wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD); ++ ++ _func_exit_; ++ ++ return 0; ++} ++ ++static int rtw_wx_get_retry(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ //_adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ ++ wrqu->retry.value = 7; ++ wrqu->retry.fixed = 0; /* no auto select */ ++ wrqu->retry.disabled = 1; ++ ++ return 0; ++ ++} ++ ++#if 0 ++#define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */ ++#define IW_ENCODE_FLAGS 0xFF00 /* Flags defined below */ ++#define IW_ENCODE_MODE 0xF000 /* Modes defined below */ ++#define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */ ++#define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */ ++#define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */ ++#define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */ ++#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ ++#define IW_ENCODE_TEMP 0x0400 /* Temporary key */ ++/* ++iwconfig wlan0 key on -> flags = 0x6001 -> maybe it means auto ++iwconfig wlan0 key off -> flags = 0x8800 ++iwconfig wlan0 key open -> flags = 0x2800 ++iwconfig wlan0 key open 1234567890 -> flags = 0x2000 ++iwconfig wlan0 key restricted -> flags = 0x4800 ++iwconfig wlan0 key open [3] 1234567890 -> flags = 0x2003 ++iwconfig wlan0 key restricted [2] 1234567890 -> flags = 0x4002 ++iwconfig wlan0 key open [3] -> flags = 0x2803 ++iwconfig wlan0 key restricted [2] -> flags = 0x4802 ++*/ ++#endif ++ ++static int rtw_wx_set_enc(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *keybuf) ++{ ++ u32 key, ret = 0; ++ u32 keyindex_provided; ++ NDIS_802_11_WEP wep; ++ NDIS_802_11_AUTHENTICATION_MODE authmode; ++ ++ struct iw_point *erq = &(wrqu->encoding); ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ DBG_871X("+rtw_wx_set_enc, flags=0x%x\n", erq->flags); ++ ++ _rtw_memset(&wep, 0, sizeof(NDIS_802_11_WEP)); ++ ++ key = erq->flags & IW_ENCODE_INDEX; ++ ++ _func_enter_; ++ ++ if (erq->flags & IW_ENCODE_DISABLED) ++ { ++ DBG_871X("EncryptionDisabled\n"); ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ padapter->securitypriv.dot11PrivacyAlgrthm=_NO_PRIVACY_; ++ padapter->securitypriv.dot118021XGrpPrivacy=_NO_PRIVACY_; ++ padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_Open; //open system ++ authmode = Ndis802_11AuthModeOpen; ++ padapter->securitypriv.ndisauthtype=authmode; ++ ++ goto exit; ++ } ++ ++ if (key) { ++ if (key > WEP_KEYS) ++ return -EINVAL; ++ key--; ++ keyindex_provided = 1; ++ } ++ else ++ { ++ keyindex_provided = 0; ++ key = padapter->securitypriv.dot11PrivacyKeyIndex; ++ DBG_871X("rtw_wx_set_enc, key=%d\n", key); ++ } ++ ++ //set authentication mode ++ if(erq->flags & IW_ENCODE_OPEN) ++ { ++ DBG_871X("rtw_wx_set_enc():IW_ENCODE_OPEN\n"); ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;//Ndis802_11EncryptionDisabled; ++ ++#ifdef CONFIG_PLATFORM_MT53XX ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; ++#else ++ padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_Open; ++#endif ++ ++ padapter->securitypriv.dot11PrivacyAlgrthm=_NO_PRIVACY_; ++ padapter->securitypriv.dot118021XGrpPrivacy=_NO_PRIVACY_; ++ authmode = Ndis802_11AuthModeOpen; ++ padapter->securitypriv.ndisauthtype=authmode; ++ } ++ else if(erq->flags & IW_ENCODE_RESTRICTED) ++ { ++ DBG_871X("rtw_wx_set_enc():IW_ENCODE_RESTRICTED\n"); ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ ++#ifdef CONFIG_PLATFORM_MT53XX ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; ++#else ++ padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_Shared; ++#endif ++ ++ padapter->securitypriv.dot11PrivacyAlgrthm=_WEP40_; ++ padapter->securitypriv.dot118021XGrpPrivacy=_WEP40_; ++ authmode = Ndis802_11AuthModeShared; ++ padapter->securitypriv.ndisauthtype=authmode; ++ } ++ else ++ { ++ DBG_871X("rtw_wx_set_enc():erq->flags=0x%x\n", erq->flags); ++ ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;//Ndis802_11EncryptionDisabled; ++ padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_Open; //open system ++ padapter->securitypriv.dot11PrivacyAlgrthm=_NO_PRIVACY_; ++ padapter->securitypriv.dot118021XGrpPrivacy=_NO_PRIVACY_; ++ authmode = Ndis802_11AuthModeOpen; ++ padapter->securitypriv.ndisauthtype=authmode; ++ } ++ ++ wep.KeyIndex = key; ++ if (erq->length > 0) ++ { ++ wep.KeyLength = erq->length <= 5 ? 5 : 13; ++ ++ wep.Length = wep.KeyLength + FIELD_OFFSET(NDIS_802_11_WEP, KeyMaterial); ++ } ++ else ++ { ++ wep.KeyLength = 0 ; ++ ++ if(keyindex_provided == 1)// set key_id only, no given KeyMaterial(erq->length==0). ++ { ++ padapter->securitypriv.dot11PrivacyKeyIndex = key; ++ ++ DBG_871X("(keyindex_provided == 1), keyid=%d, key_len=%d\n", key, padapter->securitypriv.dot11DefKeylen[key]); ++ ++ switch(padapter->securitypriv.dot11DefKeylen[key]) ++ { ++ case 5: ++ padapter->securitypriv.dot11PrivacyAlgrthm=_WEP40_; ++ break; ++ case 13: ++ padapter->securitypriv.dot11PrivacyAlgrthm=_WEP104_; ++ break; ++ default: ++ padapter->securitypriv.dot11PrivacyAlgrthm=_NO_PRIVACY_; ++ break; ++ } ++ ++ goto exit; ++ ++ } ++ ++ } ++ ++ wep.KeyIndex |= 0x80000000; ++ ++ _rtw_memcpy(wep.KeyMaterial, keybuf, wep.KeyLength); ++ ++ if (rtw_set_802_11_add_wep(padapter, &wep) == _FALSE) { ++ if(rf_on == pwrpriv->rf_pwrstate ) ++ ret = -EOPNOTSUPP; ++ goto exit; ++ } ++ ++exit: ++ ++ _func_exit_; ++ ++ return ret; ++ ++} ++ ++static int rtw_wx_get_enc(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *keybuf) ++{ ++ uint key, ret =0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *erq = &(wrqu->encoding); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ _func_enter_; ++ ++ if(check_fwstate(pmlmepriv, _FW_LINKED) != _TRUE) ++ { ++ if(check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) != _TRUE) ++ { ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_DISABLED; ++ return 0; ++ } ++ } ++ ++ ++ key = erq->flags & IW_ENCODE_INDEX; ++ ++ if (key) { ++ if (key > WEP_KEYS) ++ return -EINVAL; ++ key--; ++ } else ++ { ++ key = padapter->securitypriv.dot11PrivacyKeyIndex; ++ } ++ ++ erq->flags = key + 1; ++ ++ //if(padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeOpen) ++ //{ ++ // erq->flags |= IW_ENCODE_OPEN; ++ //} ++ ++ switch(padapter->securitypriv.ndisencryptstatus) ++ { ++ case Ndis802_11EncryptionNotSupported: ++ case Ndis802_11EncryptionDisabled: ++ ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_DISABLED; ++ ++ break; ++ ++ case Ndis802_11Encryption1Enabled: ++ ++ erq->length = padapter->securitypriv.dot11DefKeylen[key]; ++ ++ if(erq->length) ++ { ++ _rtw_memcpy(keybuf, padapter->securitypriv.dot11DefKey[key].skey, padapter->securitypriv.dot11DefKeylen[key]); ++ ++ erq->flags |= IW_ENCODE_ENABLED; ++ ++ if(padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeOpen) ++ { ++ erq->flags |= IW_ENCODE_OPEN; ++ } ++ else if(padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeShared) ++ { ++ erq->flags |= IW_ENCODE_RESTRICTED; ++ } ++ } ++ else ++ { ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_DISABLED; ++ } ++ ++ break; ++ ++ case Ndis802_11Encryption2Enabled: ++ case Ndis802_11Encryption3Enabled: ++ ++ erq->length = 16; ++ erq->flags |= (IW_ENCODE_ENABLED | IW_ENCODE_OPEN | IW_ENCODE_NOKEY); ++ ++ break; ++ ++ default: ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_DISABLED; ++ ++ break; ++ ++ } ++ ++ _func_exit_; ++ ++ return ret; ++ ++} ++ ++static int rtw_wx_get_power(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ //_adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ wrqu->power.value = 0; ++ wrqu->power.fixed = 0; /* no auto select */ ++ wrqu->power.disabled = 1; ++ ++ return 0; ++ ++} ++ ++static int rtw_wx_set_gen_ie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ ret = rtw_set_wpa_ie(padapter, extra, wrqu->data.length); ++ ++ return ret; ++} ++ ++static int rtw_wx_set_auth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_param *param = (struct iw_param*)&(wrqu->param); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u32 value = param->value; ++ int ret = 0; ++ ++ switch (param->flags & IW_AUTH_INDEX) { ++ ++ case IW_AUTH_WPA_VERSION: ++#ifdef CONFIG_WAPI_SUPPORT ++#ifndef CONFIG_IOCTL_CFG80211 ++ padapter->wapiInfo.bWapiEnable = false; ++ if(value == IW_AUTH_WAPI_VERSION_1) ++ { ++ padapter->wapiInfo.bWapiEnable = true; ++ psecuritypriv->dot11PrivacyAlgrthm = _SMS4_; ++ psecuritypriv->dot118021XGrpPrivacy = _SMS4_; ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_WAPI; ++ pmlmeinfo->auth_algo = psecuritypriv->dot11AuthAlgrthm; ++ padapter->wapiInfo.extra_prefix_len = WAPI_EXT_LEN; ++ padapter->wapiInfo.extra_postfix_len = SMS4_MIC_LEN; ++ } ++#endif ++#endif ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ ++ break; ++ case IW_AUTH_CIPHER_GROUP: ++ ++ break; ++ case IW_AUTH_KEY_MGMT: ++#ifdef CONFIG_WAPI_SUPPORT ++#ifndef CONFIG_IOCTL_CFG80211 ++ DBG_871X("rtw_wx_set_auth: IW_AUTH_KEY_MGMT case \n"); ++ if(value == IW_AUTH_KEY_MGMT_WAPI_PSK) ++ padapter->wapiInfo.bWapiPSK = true; ++ else ++ padapter->wapiInfo.bWapiPSK = false; ++ DBG_871X("rtw_wx_set_auth: IW_AUTH_KEY_MGMT bwapipsk %d \n",padapter->wapiInfo.bWapiPSK); ++#endif ++#endif ++ /* ++ * ??? does not use these parameters ++ */ ++ break; ++ ++ case IW_AUTH_TKIP_COUNTERMEASURES: ++ { ++ if ( param->value ) ++ { // wpa_supplicant is enabling the tkip countermeasure. ++ padapter->securitypriv.btkip_countermeasure = _TRUE; ++ } ++ else ++ { // wpa_supplicant is disabling the tkip countermeasure. ++ padapter->securitypriv.btkip_countermeasure = _FALSE; ++ } ++ break; ++ } ++ case IW_AUTH_DROP_UNENCRYPTED: ++ { ++ /* HACK: ++ * ++ * wpa_supplicant calls set_wpa_enabled when the driver ++ * is loaded and unloaded, regardless of if WPA is being ++ * used. No other calls are made which can be used to ++ * determine if encryption will be used or not prior to ++ * association being expected. If encryption is not being ++ * used, drop_unencrypted is set to false, else true -- we ++ * can use this to determine if the CAP_PRIVACY_ON bit should ++ * be set. ++ */ ++ ++ if(padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption1Enabled) ++ { ++ break;//it means init value, or using wep, ndisencryptstatus = Ndis802_11Encryption1Enabled, ++ // then it needn't reset it; ++ } ++ ++ if(param->value){ ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ padapter->securitypriv.dot11PrivacyAlgrthm=_NO_PRIVACY_; ++ padapter->securitypriv.dot118021XGrpPrivacy=_NO_PRIVACY_; ++ padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_Open; //open system ++ padapter->securitypriv.ndisauthtype=Ndis802_11AuthModeOpen; ++ } ++ ++ break; ++ } ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ ++ #if defined(CONFIG_ANDROID) || 1 ++ /* ++ * It's the starting point of a link layer connection using wpa_supplicant ++ */ ++ if(check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { ++ LeaveAllPowerSaveMode(padapter); ++ rtw_disassoc_cmd(padapter, 500, _FALSE); ++ DBG_871X("%s...call rtw_indicate_disconnect\n ",__FUNCTION__); ++ rtw_indicate_disconnect(padapter); ++ rtw_free_assoc_resources(padapter, 1); ++ } ++ #endif ++ ++ ++ ret = wpa_set_auth_algs(dev, (u32)param->value); ++ ++ break; ++ ++ case IW_AUTH_WPA_ENABLED: ++ ++ //if(param->value) ++ // padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; //802.1x ++ //else ++ // padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open;//open system ++ ++ //_disassociate(priv); ++ ++ break; ++ ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ //ieee->ieee802_1x = param->value; ++ break; ++ ++ case IW_AUTH_PRIVACY_INVOKED: ++ //ieee->privacy_invoked = param->value; ++ break; ++ ++#ifdef CONFIG_WAPI_SUPPORT ++#ifndef CONFIG_IOCTL_CFG80211 ++ case IW_AUTH_WAPI_ENABLED: ++ break; ++#endif ++#endif ++ ++ default: ++ return -EOPNOTSUPP; ++ ++ } ++ ++ return ret; ++ ++} ++ ++static int rtw_wx_set_enc_ext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ char *alg_name; ++ u32 param_len; ++ struct ieee_param *param = NULL; ++ struct iw_point *pencoding = &wrqu->encoding; ++ struct iw_encode_ext *pext = (struct iw_encode_ext *)extra; ++ int ret=0; ++ ++ param_len = sizeof(struct ieee_param) + pext->key_len; ++ param = (struct ieee_param *)rtw_malloc(param_len); ++ if (param == NULL) ++ return -1; ++ ++ _rtw_memset(param, 0, param_len); ++ ++ param->cmd = IEEE_CMD_SET_ENCRYPTION; ++ _rtw_memset(param->sta_addr, 0xff, ETH_ALEN); ++ ++ ++ switch (pext->alg) { ++ case IW_ENCODE_ALG_NONE: ++ //todo: remove key ++ //remove = 1; ++ alg_name = "none"; ++ break; ++ case IW_ENCODE_ALG_WEP: ++ alg_name = "WEP"; ++ break; ++ case IW_ENCODE_ALG_TKIP: ++ alg_name = "TKIP"; ++ break; ++ case IW_ENCODE_ALG_CCMP: ++ alg_name = "CCMP"; ++ break; ++#ifdef CONFIG_IEEE80211W ++ case IW_ENCODE_ALG_AES_CMAC: ++ alg_name = "BIP"; ++ break; ++#endif //CONFIG_IEEE80211W ++#ifdef CONFIG_WAPI_SUPPORT ++#ifndef CONFIG_IOCTL_CFG80211 ++ case IW_ENCODE_ALG_SM4: ++ alg_name= "SMS4"; ++ _rtw_memcpy(param->sta_addr, pext->addr.sa_data, ETH_ALEN); ++ DBG_871X("rtw_wx_set_enc_ext: SMS4 case \n"); ++ break; ++#endif ++#endif ++ default: ++ return -1; ++ } ++ ++ strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN); ++ ++ if (pext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ param->u.crypt.set_tx = 1; ++ } ++ ++ /* cliW: WEP does not have group key ++ * just not checking GROUP key setting ++ */ ++ if ((pext->alg != IW_ENCODE_ALG_WEP) && ++ ((pext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) ++#ifdef CONFIG_IEEE80211W ++ || (pext->ext_flags & IW_ENCODE_ALG_AES_CMAC) ++#endif //CONFIG_IEEE80211W ++ )) ++ { ++ param->u.crypt.set_tx = 0; ++ } ++ ++ param->u.crypt.idx = (pencoding->flags&0x00FF) -1 ; ++ ++ if (pext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) ++ { ++#ifdef CONFIG_WAPI_SUPPORT ++#ifndef CONFIG_IOCTL_CFG80211 ++ if(pext->alg == IW_ENCODE_ALG_SM4) ++ _rtw_memcpy(param->u.crypt.seq, pext->rx_seq, 16); ++ else ++#endif //CONFIG_IOCTL_CFG80211 ++#endif //CONFIG_WAPI_SUPPORT ++ _rtw_memcpy(param->u.crypt.seq, pext->rx_seq, 8); ++ } ++ ++ if(pext->key_len) ++ { ++ param->u.crypt.key_len = pext->key_len; ++ //_rtw_memcpy(param + 1, pext + 1, pext->key_len); ++ _rtw_memcpy(param->u.crypt.key, pext + 1, pext->key_len); ++ } ++ ++ if (pencoding->flags & IW_ENCODE_DISABLED) ++ { ++ //todo: remove key ++ //remove = 1; ++ } ++ ++ ret = wpa_set_encryption(dev, param, param_len); ++ ++ if(param) ++ { ++ rtw_mfree((u8*)param, param_len); ++ } ++ ++ return ret; ++} ++ ++ ++static int rtw_wx_get_nick(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ //_adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ //struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ //struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ if(extra) ++ { ++ wrqu->data.length = 14; ++ wrqu->data.flags = 1; ++ _rtw_memcpy(extra, "", 14); ++ } ++ ++ //rtw_signal_process(pid, SIGUSR1); //for test ++ ++ //dump debug info here ++/* ++ u32 dot11AuthAlgrthm; // 802.11 auth, could be open, shared, and 8021x ++ u32 dot11PrivacyAlgrthm; // This specify the privacy for shared auth. algorithm. ++ u32 dot118021XGrpPrivacy; // This specify the privacy algthm. used for Grp key ++ u32 ndisauthtype; ++ u32 ndisencryptstatus; ++*/ ++ ++ //DBG_871X("auth_alg=0x%x, enc_alg=0x%x, auth_type=0x%x, enc_type=0x%x\n", ++ // psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm, ++ // psecuritypriv->ndisauthtype, psecuritypriv->ndisencryptstatus); ++ ++ //DBG_871X("enc_alg=0x%x\n", psecuritypriv->dot11PrivacyAlgrthm); ++ //DBG_871X("auth_type=0x%x\n", psecuritypriv->ndisauthtype); ++ //DBG_871X("enc_type=0x%x\n", psecuritypriv->ndisencryptstatus); ++ ++#if 0 ++ DBG_871X("dbg(0x210)=0x%x\n", rtw_read32(padapter, 0x210)); ++ DBG_871X("dbg(0x608)=0x%x\n", rtw_read32(padapter, 0x608)); ++ DBG_871X("dbg(0x280)=0x%x\n", rtw_read32(padapter, 0x280)); ++ DBG_871X("dbg(0x284)=0x%x\n", rtw_read32(padapter, 0x284)); ++ DBG_871X("dbg(0x288)=0x%x\n", rtw_read32(padapter, 0x288)); ++ ++ DBG_871X("dbg(0x664)=0x%x\n", rtw_read32(padapter, 0x664)); ++ ++ ++ DBG_871X("\n"); ++ ++ DBG_871X("dbg(0x430)=0x%x\n", rtw_read32(padapter, 0x430)); ++ DBG_871X("dbg(0x438)=0x%x\n", rtw_read32(padapter, 0x438)); ++ ++ DBG_871X("dbg(0x440)=0x%x\n", rtw_read32(padapter, 0x440)); ++ ++ DBG_871X("dbg(0x458)=0x%x\n", rtw_read32(padapter, 0x458)); ++ ++ DBG_871X("dbg(0x484)=0x%x\n", rtw_read32(padapter, 0x484)); ++ DBG_871X("dbg(0x488)=0x%x\n", rtw_read32(padapter, 0x488)); ++ ++ DBG_871X("dbg(0x444)=0x%x\n", rtw_read32(padapter, 0x444)); ++ DBG_871X("dbg(0x448)=0x%x\n", rtw_read32(padapter, 0x448)); ++ DBG_871X("dbg(0x44c)=0x%x\n", rtw_read32(padapter, 0x44c)); ++ DBG_871X("dbg(0x450)=0x%x\n", rtw_read32(padapter, 0x450)); ++#endif ++ ++ return 0; ++ ++} ++ ++static int rtw_wx_read32(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PADAPTER padapter; ++ struct iw_point *p; ++ u16 len; ++ u32 addr; ++ u32 data32; ++ u32 bytes; ++ u8 *ptmp; ++ ++ ++ padapter = (PADAPTER)rtw_netdev_priv(dev); ++ p = &wrqu->data; ++ len = p->length; ++ ptmp = (u8*)rtw_malloc(len); ++ if (NULL == ptmp) ++ return -ENOMEM; ++ ++ if (copy_from_user(ptmp, p->pointer, len)) { ++ rtw_mfree(ptmp, len); ++ return -EFAULT; ++ } ++ ++ bytes = 0; ++ addr = 0; ++ sscanf(ptmp, "%d,%x", &bytes, &addr); ++ ++ switch (bytes) { ++ case 1: ++ data32 = rtw_read8(padapter, addr); ++ sprintf(extra, "0x%02X", data32); ++ break; ++ case 2: ++ data32 = rtw_read16(padapter, addr); ++ sprintf(extra, "0x%04X", data32); ++ break; ++ case 4: ++ data32 = rtw_read32(padapter, addr); ++ sprintf(extra, "0x%08X", data32); ++ break; ++ default: ++ DBG_871X(KERN_INFO "%s: usage> read [bytes],[address(hex)]\n", __func__); ++ return -EINVAL; ++ } ++ DBG_871X(KERN_INFO "%s: addr=0x%08X data=%s\n", __func__, addr, extra); ++ ++ rtw_mfree(ptmp, len); ++ ++ return 0; ++} ++ ++static int rtw_wx_write32(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PADAPTER padapter = (PADAPTER)rtw_netdev_priv(dev); ++ ++ u32 addr; ++ u32 data32; ++ u32 bytes; ++ ++ ++ bytes = 0; ++ addr = 0; ++ data32 = 0; ++ sscanf(extra, "%d,%x,%x", &bytes, &addr, &data32); ++ ++ switch (bytes) { ++ case 1: ++ rtw_write8(padapter, addr, (u8)data32); ++ DBG_871X(KERN_INFO "%s: addr=0x%08X data=0x%02X\n", __func__, addr, (u8)data32); ++ break; ++ case 2: ++ rtw_write16(padapter, addr, (u16)data32); ++ DBG_871X(KERN_INFO "%s: addr=0x%08X data=0x%04X\n", __func__, addr, (u16)data32); ++ break; ++ case 4: ++ rtw_write32(padapter, addr, data32); ++ DBG_871X(KERN_INFO "%s: addr=0x%08X data=0x%08X\n", __func__, addr, data32); ++ break; ++ default: ++ DBG_871X(KERN_INFO "%s: usage> write [bytes],[address(hex)],[data(hex)]\n", __func__); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int rtw_wx_read_rf(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ u32 path, addr, data32; ++ ++ ++ path = *(u32*)extra; ++ addr = *((u32*)extra + 1); ++ data32 = rtw_hal_read_rfreg(padapter, path, addr, 0xFFFFF); ++// DBG_871X("%s: path=%d addr=0x%02x data=0x%05x\n", __func__, path, addr, data32); ++ /* ++ * IMPORTANT!! ++ * Only when wireless private ioctl is at odd order, ++ * "extra" would be copied to user space. ++ */ ++ sprintf(extra, "0x%05x", data32); ++ ++ return 0; ++} ++ ++static int rtw_wx_write_rf(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ u32 path, addr, data32; ++ ++ ++ path = *(u32*)extra; ++ addr = *((u32*)extra + 1); ++ data32 = *((u32*)extra + 2); ++// DBG_871X("%s: path=%d addr=0x%02x data=0x%05x\n", __func__, path, addr, data32); ++ rtw_hal_write_rfreg(padapter, path, addr, 0xFFFFF, data32); ++ ++ return 0; ++} ++ ++static int rtw_wx_priv_null(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ return -1; ++} ++ ++static int dummy(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ //_adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ //struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ //DBG_871X("cmd_code=%x, fwstate=0x%x\n", a->cmd, get_fwstate(pmlmepriv)); ++ ++ return -1; ++ ++} ++ ++static int rtw_wx_set_channel_plan(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ extern int rtw_channel_plan; ++ u8 channel_plan_req = (u8) (*((int *)wrqu)); ++ ++ #if 0 ++ rtw_channel_plan = (int)wrqu->data.pointer; ++ pregistrypriv->channel_plan = rtw_channel_plan; ++ pmlmepriv->ChannelPlan = pregistrypriv->channel_plan; ++ #endif ++ ++ if( _SUCCESS == rtw_set_chplan_cmd(padapter, channel_plan_req, 1) ) { ++ DBG_871X("%s set channel_plan = 0x%02X\n", __func__, pmlmepriv->ChannelPlan); ++ } else ++ return -EPERM; ++ ++ return 0; ++} ++ ++static int rtw_wx_set_mtk_wps_probe_ie(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++#ifdef CONFIG_PLATFORM_MT53XX ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_notice_, ++ ("WLAN IOCTL: cmd_code=%x, fwstate=0x%x\n", ++ a->cmd, get_fwstate(pmlmepriv))); ++#endif ++ return 0; ++} ++ ++static int rtw_wx_get_sensitivity(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *buf) ++{ ++#ifdef CONFIG_PLATFORM_MT53XX ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ // Modified by Albert 20110914 ++ // This is in dbm format for MTK platform. ++ wrqu->qual.level = padapter->recvpriv.rssi; ++ DBG_871X(" level = %u\n", wrqu->qual.level ); ++#endif ++ return 0; ++} ++ ++static int rtw_wx_set_mtk_wps_ie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++#ifdef CONFIG_PLATFORM_MT53XX ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ return rtw_set_wpa_ie(padapter, wrqu->data.pointer, wrqu->data.length); ++#else ++ return 0; ++#endif ++} ++ ++/* ++typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++*/ ++/* ++ * For all data larger than 16 octets, we need to use a ++ * pointer to memory allocated in user space. ++ */ ++static int rtw_drvext_hdl(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ #if 0 ++struct iw_point ++{ ++ void __user *pointer; /* Pointer to the data (in user space) */ ++ __u16 length; /* number of fields or size in bytes */ ++ __u16 flags; /* Optional params */ ++}; ++ #endif ++ ++#ifdef CONFIG_DRVEXT_MODULE ++ u8 res; ++ struct drvext_handler *phandler; ++ struct drvext_oidparam *poidparam; ++ int ret; ++ u16 len; ++ u8 *pparmbuf, bset; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *p = &wrqu->data; ++ ++ if( (!p->length) || (!p->pointer)){ ++ ret = -EINVAL; ++ goto _rtw_drvext_hdl_exit; ++ } ++ ++ ++ bset = (u8)(p->flags&0xFFFF); ++ len = p->length; ++ pparmbuf = (u8*)rtw_malloc(len); ++ if (pparmbuf == NULL){ ++ ret = -ENOMEM; ++ goto _rtw_drvext_hdl_exit; ++ } ++ ++ if(bset)//set info ++ { ++ if (copy_from_user(pparmbuf, p->pointer,len)) { ++ rtw_mfree(pparmbuf, len); ++ ret = -EFAULT; ++ goto _rtw_drvext_hdl_exit; ++ } ++ } ++ else//query info ++ { ++ ++ } ++ ++ ++ // ++ poidparam = (struct drvext_oidparam *)pparmbuf; ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c,_drv_info_,("drvext set oid subcode [%d], len[%d], InformationBufferLength[%d]\r\n", ++ poidparam->subcode, poidparam->len, len)); ++ ++ ++ //check subcode ++ if ( poidparam->subcode >= MAX_DRVEXT_HANDLERS) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_os_c,_drv_err_,("no matching drvext handlers\r\n")); ++ ret = -EINVAL; ++ goto _rtw_drvext_hdl_exit; ++ } ++ ++ ++ if ( poidparam->subcode >= MAX_DRVEXT_OID_SUBCODES) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_os_c,_drv_err_,("no matching drvext subcodes\r\n")); ++ ret = -EINVAL; ++ goto _rtw_drvext_hdl_exit; ++ } ++ ++ ++ phandler = drvextoidhandlers + poidparam->subcode; ++ ++ if (poidparam->len != phandler->parmsize) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_os_c,_drv_err_,("no matching drvext param size %d vs %d\r\n", ++ poidparam->len , phandler->parmsize)); ++ ret = -EINVAL; ++ goto _rtw_drvext_hdl_exit; ++ } ++ ++ ++ res = phandler->handler(&padapter->drvextpriv, bset, poidparam->data); ++ ++ if(res==0) ++ { ++ ret = 0; ++ ++ if (bset == 0x00) {//query info ++ //_rtw_memcpy(p->pointer, pparmbuf, len); ++ if (copy_to_user(p->pointer, pparmbuf, len)) ++ ret = -EFAULT; ++ } ++ } ++ else ++ ret = -EFAULT; ++ ++ ++_rtw_drvext_hdl_exit: ++ ++ return ret; ++ ++#endif ++ ++ return 0; ++ ++} ++ ++static void rtw_dbg_mode_hdl(_adapter *padapter, u32 id, u8 *pdata, u32 len) ++{ ++ pRW_Reg RegRWStruct; ++ struct rf_reg_param *prfreg; ++ u8 path; ++ u8 offset; ++ u32 value; ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ switch(id) ++ { ++ case GEN_MP_IOCTL_SUBCODE(MP_START): ++ DBG_871X("871x_driver is only for normal mode, can't enter mp mode\n"); ++ break; ++ case GEN_MP_IOCTL_SUBCODE(READ_REG): ++ RegRWStruct = (pRW_Reg)pdata; ++ switch (RegRWStruct->width) ++ { ++ case 1: ++ RegRWStruct->value = rtw_read8(padapter, RegRWStruct->offset); ++ break; ++ case 2: ++ RegRWStruct->value = rtw_read16(padapter, RegRWStruct->offset); ++ break; ++ case 4: ++ RegRWStruct->value = rtw_read32(padapter, RegRWStruct->offset); ++ break; ++ default: ++ break; ++ } ++ ++ break; ++ case GEN_MP_IOCTL_SUBCODE(WRITE_REG): ++ RegRWStruct = (pRW_Reg)pdata; ++ switch (RegRWStruct->width) ++ { ++ case 1: ++ rtw_write8(padapter, RegRWStruct->offset, (u8)RegRWStruct->value); ++ break; ++ case 2: ++ rtw_write16(padapter, RegRWStruct->offset, (u16)RegRWStruct->value); ++ break; ++ case 4: ++ rtw_write32(padapter, RegRWStruct->offset, (u32)RegRWStruct->value); ++ break; ++ default: ++ break; ++ } ++ ++ break; ++ case GEN_MP_IOCTL_SUBCODE(READ_RF_REG): ++ ++ prfreg = (struct rf_reg_param *)pdata; ++ ++ path = (u8)prfreg->path; ++ offset = (u8)prfreg->offset; ++ ++ value = rtw_hal_read_rfreg(padapter, path, offset, 0xffffffff); ++ ++ prfreg->value = value; ++ ++ break; ++ case GEN_MP_IOCTL_SUBCODE(WRITE_RF_REG): ++ ++ prfreg = (struct rf_reg_param *)pdata; ++ ++ path = (u8)prfreg->path; ++ offset = (u8)prfreg->offset; ++ value = prfreg->value; ++ ++ rtw_hal_write_rfreg(padapter, path, offset, 0xffffffff, value); ++ ++ break; ++ case GEN_MP_IOCTL_SUBCODE(TRIGGER_GPIO): ++ DBG_871X("==> trigger gpio 0\n"); ++ rtw_hal_set_hwreg(padapter, HW_VAR_TRIGGER_GPIO_0, 0); ++ break; ++#ifdef CONFIG_BT_COEXIST ++ case GEN_MP_IOCTL_SUBCODE(SET_DM_BT): ++ DBG_871X("==> set dm_bt_coexist:%x\n",*(u8 *)pdata); ++ rtw_hal_set_hwreg(padapter, HW_VAR_BT_SET_COEXIST, pdata); ++ break; ++ case GEN_MP_IOCTL_SUBCODE(DEL_BA): ++ DBG_871X("==> delete ba:%x\n",*(u8 *)pdata); ++ rtw_hal_set_hwreg(padapter, HW_VAR_BT_ISSUE_DELBA, pdata); ++ break; ++#endif ++#ifdef DBG_CONFIG_ERROR_DETECT ++ case GEN_MP_IOCTL_SUBCODE(GET_WIFI_STATUS): ++ *pdata = rtw_hal_sreset_get_wifi_status(padapter); ++ break; ++#endif ++ ++ default: ++ break; ++ } ++ ++} ++ ++static int rtw_mp_ioctl_hdl(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ u32 BytesRead, BytesWritten, BytesNeeded; ++ struct oid_par_priv oid_par; ++ struct mp_ioctl_handler *phandler; ++ struct mp_ioctl_param *poidparam; ++ uint status=0; ++ u16 len; ++ u8 *pparmbuf = NULL, bset; ++ PADAPTER padapter = (PADAPTER)rtw_netdev_priv(dev); ++ struct iw_point *p = &wrqu->data; ++ ++ //DBG_871X("+rtw_mp_ioctl_hdl\n"); ++ ++ //mutex_lock(&ioctl_mutex); ++ ++ if ((!p->length) || (!p->pointer)) { ++ ret = -EINVAL; ++ goto _rtw_mp_ioctl_hdl_exit; ++ } ++ ++ pparmbuf = NULL; ++ bset = (u8)(p->flags & 0xFFFF); ++ len = p->length; ++ pparmbuf = (u8*)rtw_malloc(len); ++ if (pparmbuf == NULL){ ++ ret = -ENOMEM; ++ goto _rtw_mp_ioctl_hdl_exit; ++ } ++ ++ if (copy_from_user(pparmbuf, p->pointer, len)) { ++ ret = -EFAULT; ++ goto _rtw_mp_ioctl_hdl_exit; ++ } ++ ++ poidparam = (struct mp_ioctl_param *)pparmbuf; ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ++ ("rtw_mp_ioctl_hdl: subcode [%d], len[%d], buffer_len[%d]\r\n", ++ poidparam->subcode, poidparam->len, len)); ++ ++ if (poidparam->subcode >= MAX_MP_IOCTL_SUBCODE) { ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("no matching drvext subcodes\r\n")); ++ ret = -EINVAL; ++ goto _rtw_mp_ioctl_hdl_exit; ++ } ++ ++ //DBG_871X("%s: %d\n", __func__, poidparam->subcode); ++#ifdef CONFIG_MP_INCLUDED ++if (padapter->registrypriv.mp_mode == 1) ++{ ++ phandler = mp_ioctl_hdl + poidparam->subcode; ++ ++ if ((phandler->paramsize != 0) && (poidparam->len < phandler->paramsize)) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ++ ("no matching drvext param size %d vs %d\r\n", ++ poidparam->len, phandler->paramsize)); ++ ret = -EINVAL; ++ goto _rtw_mp_ioctl_hdl_exit; ++ } ++ ++ if (phandler->handler) ++ { ++ oid_par.adapter_context = padapter; ++ oid_par.oid = phandler->oid; ++ oid_par.information_buf = poidparam->data; ++ oid_par.information_buf_len = poidparam->len; ++ oid_par.dbg = 0; ++ ++ BytesWritten = 0; ++ BytesNeeded = 0; ++ ++ if (bset) { ++ oid_par.bytes_rw = &BytesRead; ++ oid_par.bytes_needed = &BytesNeeded; ++ oid_par.type_of_oid = SET_OID; ++ } else { ++ oid_par.bytes_rw = &BytesWritten; ++ oid_par.bytes_needed = &BytesNeeded; ++ oid_par.type_of_oid = QUERY_OID; ++ } ++ ++ status = phandler->handler(&oid_par); ++ ++ //todo:check status, BytesNeeded, etc. ++ } ++ else { ++ DBG_871X("rtw_mp_ioctl_hdl(): err!, subcode=%d, oid=%d, handler=%p\n", ++ poidparam->subcode, phandler->oid, phandler->handler); ++ ret = -EFAULT; ++ goto _rtw_mp_ioctl_hdl_exit; ++ } ++} ++else ++#endif ++{ ++ rtw_dbg_mode_hdl(padapter, poidparam->subcode, poidparam->data, poidparam->len); ++} ++ ++ if (bset == 0x00) {//query info ++ if (copy_to_user(p->pointer, pparmbuf, len)) ++ ret = -EFAULT; ++ } ++ ++ if (status) { ++ ret = -EFAULT; ++ goto _rtw_mp_ioctl_hdl_exit; ++ } ++ ++_rtw_mp_ioctl_hdl_exit: ++ ++ if (pparmbuf) ++ rtw_mfree(pparmbuf, len); ++ ++ //mutex_unlock(&ioctl_mutex); ++ ++ return ret; ++} ++ ++static int rtw_get_ap_info(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int bssid_match, ret = 0; ++ u32 cnt=0, wpa_ielen; ++ _irqL irqL; ++ _list *plist, *phead; ++ unsigned char *pbuf; ++ u8 bssid[ETH_ALEN]; ++ char data[32]; ++ struct wlan_network *pnetwork = NULL; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct iw_point *pdata = &wrqu->data; ++ ++ DBG_871X("+rtw_get_aplist_info\n"); ++ ++ if((padapter->bDriverStopped) || (pdata==NULL)) ++ { ++ ret= -EINVAL; ++ goto exit; ++ } ++ ++ while((check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING))) == _TRUE) ++ { ++ rtw_msleep_os(30); ++ cnt++; ++ if(cnt > 100) ++ break; ++ } ++ ++ ++ //pdata->length = 0;//? ++ pdata->flags = 0; ++ if(pdata->length>=32) ++ { ++ if(copy_from_user(data, pdata->pointer, 32)) ++ { ++ ret= -EINVAL; ++ goto exit; ++ } ++ } ++ else ++ { ++ ret= -EINVAL; ++ goto exit; ++ } ++ ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while(1) ++ { ++ if (rtw_end_of_queue_search(phead,plist)== _TRUE) ++ break; ++ ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ //if(hwaddr_aton_i(pdata->pointer, bssid)) ++ if(hwaddr_aton_i(data, bssid)) ++ { ++ DBG_871X("Invalid BSSID '%s'.\n", (u8*)data); ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ return -EINVAL; ++ } ++ ++ ++ if(_rtw_memcmp(bssid, pnetwork->network.MacAddress, ETH_ALEN) == _TRUE)//BSSID match, then check if supporting wpa/wpa2 ++ { ++ DBG_871X("BSSID:" MAC_FMT "\n", MAC_ARG(bssid)); ++ ++ pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12); ++ if(pbuf && (wpa_ielen>0)) ++ { ++ pdata->flags = 1; ++ break; ++ } ++ ++ pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12); ++ if(pbuf && (wpa_ielen>0)) ++ { ++ pdata->flags = 2; ++ break; ++ } ++ ++ } ++ ++ plist = get_next(plist); ++ ++ } ++ ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ if(pdata->length>=34) ++ { ++ if(copy_to_user((u8*)pdata->pointer+32, (u8*)&pdata->flags, 1)) ++ { ++ ret= -EINVAL; ++ goto exit; ++ } ++ } ++ ++exit: ++ ++ return ret; ++ ++} ++ ++static int rtw_set_pid(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = rtw_netdev_priv(dev); ++ int *pdata = (int *)wrqu; ++ int selector; ++ ++ if((padapter->bDriverStopped) || (pdata==NULL)) ++ { ++ ret= -EINVAL; ++ goto exit; ++ } ++ ++ selector = *pdata; ++ if(selector < 3 && selector >=0) { ++ padapter->pid[selector] = *(pdata+1); ++ #ifdef CONFIG_GLOBAL_UI_PID ++ ui_pid[selector] = *(pdata+1); ++ #endif ++ DBG_871X("%s set pid[%d]=%d\n", __FUNCTION__, selector ,padapter->pid[selector]); ++ } ++ else ++ DBG_871X("%s selector %d error\n", __FUNCTION__, selector); ++ ++exit: ++ ++ return ret; ++ ++} ++ ++static int rtw_wps_start(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ u32 u32wps_start = 0; ++ unsigned int uintRet = 0; ++ ++ uintRet = copy_from_user( ( void* ) &u32wps_start, pdata->pointer, 4 ); ++ ++ if((padapter->bDriverStopped) || (pdata==NULL)) ++ { ++ ret= -EINVAL; ++ goto exit; ++ } ++ ++ if ( u32wps_start == 0 ) ++ { ++ u32wps_start = *extra; ++ } ++ ++ DBG_871X( "[%s] wps_start = %d\n", __FUNCTION__, u32wps_start ); ++ ++ if ( u32wps_start == 1 ) // WPS Start ++ { ++ rtw_led_control(padapter, LED_CTL_START_WPS); ++ } ++ else if ( u32wps_start == 2 ) // WPS Stop because of wps success ++ { ++ rtw_led_control(padapter, LED_CTL_STOP_WPS); ++ } ++ else if ( u32wps_start == 3 ) // WPS Stop because of wps fail ++ { ++ rtw_led_control(padapter, LED_CTL_STOP_WPS_FAIL); ++ } ++ ++#ifdef CONFIG_INTEL_WIDI ++ process_intel_widi_wps_status(padapter, u32wps_start); ++#endif //CONFIG_INTEL_WIDI ++ ++exit: ++ ++ return ret; ++ ++} ++ ++#ifdef CONFIG_P2P ++static int rtw_wext_p2p_enable(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ enum P2P_ROLE init_role = P2P_ROLE_DISABLE; ++ ++ if(*extra == '0' ) ++ init_role = P2P_ROLE_DISABLE; ++ else if(*extra == '1') ++ init_role = P2P_ROLE_DEVICE; ++ else if(*extra == '2') ++ init_role = P2P_ROLE_CLIENT; ++ else if(*extra == '3') ++ init_role = P2P_ROLE_GO; ++ ++ if(_FAIL == rtw_p2p_enable(padapter, init_role)) ++ { ++ ret = -EFAULT; ++ goto exit; ++ } ++ ++ //set channel/bandwidth ++ if(init_role != P2P_ROLE_DISABLE) ++ { ++ u8 channel, ch_offset; ++ u16 bwmode; ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_LISTEN)) ++ { ++ // Stay at the listen state and wait for discovery. ++ channel = pwdinfo->listen_channel; ++ pwdinfo->operating_channel = pwdinfo->listen_channel; ++ ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ bwmode = HT_CHANNEL_WIDTH_20; ++ } ++#ifdef CONFIG_CONCURRENT_MODE ++ else if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) ++ { ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ //struct wifidirect_info *pbuddy_wdinfo = &pbuddy_adapter->wdinfo; ++ struct mlme_priv *pbuddy_mlmepriv = &pbuddy_adapter->mlmepriv; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++ ++ _set_timer( &pwdinfo->ap_p2p_switch_timer, pwdinfo->ext_listen_interval ); ++ if ( check_fwstate( pbuddy_mlmepriv, _FW_LINKED ) ) ++ { ++ pwdinfo->operating_channel = pbuddy_mlmeext->cur_channel; ++ // How about the ch_offset and bwmode ?? ++ } ++ else ++ { ++ pwdinfo->operating_channel = pwdinfo->listen_channel; ++ } ++ ++ channel = pbuddy_mlmeext->cur_channel; ++ ch_offset = pbuddy_mlmeext->cur_ch_offset; ++ bwmode = pbuddy_mlmeext->cur_bwmode; ++ } ++#endif ++ else ++ { ++ pwdinfo->operating_channel = pmlmeext->cur_channel; ++ ++ channel = pwdinfo->operating_channel; ++ ch_offset = pmlmeext->cur_ch_offset; ++ bwmode = pmlmeext->cur_bwmode; ++ } ++ ++ set_channel_bwmode(padapter, channel, ch_offset, bwmode); ++ } ++ ++exit: ++ return ret; ++ ++} ++ ++static int rtw_p2p_set_go_nego_ssid(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ ++ DBG_871X( "[%s] ssid = %s, len = %zu\n", __FUNCTION__, extra, strlen( extra ) ); ++ _rtw_memcpy( pwdinfo->nego_ssid, extra, strlen( extra ) ); ++ pwdinfo->nego_ssidlen = strlen( extra ); ++ ++ return ret; ++ ++} ++ ++ ++static int rtw_p2p_set_intent(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ u8 intent = pwdinfo->intent; ++ ++ extra[ wrqu->data.length ] = 0x00; ++ ++ intent = rtw_atoi( extra ); ++ ++ if ( intent <= 15 ) ++ { ++ pwdinfo->intent= intent; ++ } ++ else ++ { ++ ret = -1; ++ } ++ ++ DBG_871X( "[%s] intent = %d\n", __FUNCTION__, intent); ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_set_listen_ch(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ u8 listen_ch = pwdinfo->listen_channel; // Listen channel number ++ ++ extra[ wrqu->data.length ] = 0x00; ++ listen_ch = rtw_atoi( extra ); ++ ++ if ( ( listen_ch == 1 ) || ( listen_ch == 6 ) || ( listen_ch == 11 ) ) ++ { ++ pwdinfo->listen_channel = listen_ch; ++ set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ } ++ else ++ { ++ ret = -1; ++ } ++ ++ DBG_871X( "[%s] listen_ch = %d\n", __FUNCTION__, pwdinfo->listen_channel ); ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_set_op_ch(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++// Commented by Albert 20110524 ++// This function is used to set the operating channel if the driver will become the group owner ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ u8 op_ch = pwdinfo->operating_channel; // Operating channel number ++ ++ extra[ wrqu->data.length ] = 0x00; ++ ++ op_ch = ( u8 ) rtw_atoi( extra ); ++ if ( op_ch > 0 ) ++ { ++ pwdinfo->operating_channel = op_ch; ++ } ++ else ++ { ++ ret = -1; ++ } ++ ++ DBG_871X( "[%s] op_ch = %d\n", __FUNCTION__, pwdinfo->operating_channel ); ++ ++ return ret; ++ ++} ++ ++ ++static int rtw_p2p_profilefound(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ ++ // Comment by Albert 2010/10/13 ++ // Input data format: ++ // Ex: 0 ++ // Ex: 1XX:XX:XX:XX:XX:XXYYSSID ++ // 0 => Reflush the profile record list. ++ // 1 => Add the profile list ++ // XX:XX:XX:XX:XX:XX => peer's MAC Address ( ex: 00:E0:4C:00:00:01 ) ++ // YY => SSID Length ++ // SSID => SSID for persistence group ++ ++ DBG_871X( "[%s] In value = %s, len = %d \n", __FUNCTION__, extra, wrqu->data.length -1); ++ ++ ++ // The upper application should pass the SSID to driver by using this rtw_p2p_profilefound function. ++ if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ if ( extra[ 0 ] == '0' ) ++ { ++ // Remove all the profile information of wifidirect_info structure. ++ _rtw_memset( &pwdinfo->profileinfo[ 0 ], 0x00, sizeof( struct profile_info ) * P2P_MAX_PERSISTENT_GROUP_NUM ); ++ pwdinfo->profileindex = 0; ++ } ++ else ++ { ++ if ( pwdinfo->profileindex >= P2P_MAX_PERSISTENT_GROUP_NUM ) ++ { ++ ret = -1; ++ } ++ else ++ { ++ int jj, kk; ++ ++ // Add this profile information into pwdinfo->profileinfo ++ // Ex: 1XX:XX:XX:XX:XX:XXYYSSID ++ for( jj = 0, kk = 1; jj < ETH_ALEN; jj++, kk += 3 ) ++ { ++ pwdinfo->profileinfo[ pwdinfo->profileindex ].peermac[ jj ] = key_2char2num(extra[ kk ], extra[ kk+ 1 ]); ++ } ++ ++ //pwdinfo->profileinfo[ pwdinfo->profileindex ].ssidlen = ( extra[18] - '0' ) * 10 + ( extra[ 19 ] - '0' ); ++ //_rtw_memcpy( pwdinfo->profileinfo[ pwdinfo->profileindex ].ssid, &extra[ 20 ], pwdinfo->profileinfo[ pwdinfo->profileindex ].ssidlen ); ++ pwdinfo->profileindex++; ++ } ++ } ++ } ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_setDN(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ ++ ++ DBG_871X( "[%s] %s %d\n", __FUNCTION__, extra, wrqu->data.length -1 ); ++ _rtw_memset( pwdinfo->device_name, 0x00, WPS_MAX_DEVICE_NAME_LEN ); ++ _rtw_memcpy( pwdinfo->device_name, extra, wrqu->data.length - 1 ); ++ pwdinfo->device_name_len = wrqu->data.length - 1; ++ ++ return ret; ++ ++} ++ ++ ++static int rtw_p2p_get_status(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++#ifdef CONFIG_CONCURRENT_MODE ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct wifidirect_info *pbuddy_wdinfo = &pbuddy_adapter->wdinfo; ++ struct mlme_priv *pbuddy_mlmepriv = &pbuddy_adapter->mlmepriv; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++#endif ++ ++ if ( padapter->bShowGetP2PState ) ++ { ++ DBG_871X( "[%s] Role = %d, Status = %d, peer addr = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", __FUNCTION__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo), ++ pwdinfo->p2p_peer_interface_addr[ 0 ], pwdinfo->p2p_peer_interface_addr[ 1 ], pwdinfo->p2p_peer_interface_addr[ 2 ], ++ pwdinfo->p2p_peer_interface_addr[ 3 ], pwdinfo->p2p_peer_interface_addr[ 4 ], pwdinfo->p2p_peer_interface_addr[ 5 ]); ++ } ++ ++ // Commented by Albert 2010/10/12 ++ // Because of the output size limitation, I had removed the "Role" information. ++ // About the "Role" information, we will use the new private IOCTL to get the "Role" information. ++ sprintf( extra, "\n\nStatus=%.2d\n", rtw_p2p_state(pwdinfo) ); ++ wrqu->data.length = strlen( extra ); ++ ++ return ret; ++ ++} ++ ++// Commented by Albert 20110520 ++// This function will return the config method description ++// This config method description will show us which config method the remote P2P device is intented to use ++// by sending the provisioning discovery request frame. ++ ++static int rtw_p2p_get_req_cm(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ ++ sprintf( extra, "\n\nCM=%s\n", pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req ); ++ wrqu->data.length = strlen( extra ); ++ return ret; ++ ++} ++ ++ ++static int rtw_p2p_get_role(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ ++ ++ DBG_871X( "[%s] Role = %d, Status = %d, peer addr = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", __FUNCTION__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo), ++ pwdinfo->p2p_peer_interface_addr[ 0 ], pwdinfo->p2p_peer_interface_addr[ 1 ], pwdinfo->p2p_peer_interface_addr[ 2 ], ++ pwdinfo->p2p_peer_interface_addr[ 3 ], pwdinfo->p2p_peer_interface_addr[ 4 ], pwdinfo->p2p_peer_interface_addr[ 5 ]); ++ ++ sprintf( extra, "\n\nRole=%.2d\n", rtw_p2p_role(pwdinfo) ); ++ wrqu->data.length = strlen( extra ); ++ return ret; ++ ++} ++ ++ ++static int rtw_p2p_get_peer_ifaddr(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ ++ ++ DBG_871X( "[%s] Role = %d, Status = %d, peer addr = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", __FUNCTION__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo), ++ pwdinfo->p2p_peer_interface_addr[ 0 ], pwdinfo->p2p_peer_interface_addr[ 1 ], pwdinfo->p2p_peer_interface_addr[ 2 ], ++ pwdinfo->p2p_peer_interface_addr[ 3 ], pwdinfo->p2p_peer_interface_addr[ 4 ], pwdinfo->p2p_peer_interface_addr[ 5 ]); ++ ++ sprintf( extra, "\nMAC %.2X:%.2X:%.2X:%.2X:%.2X:%.2X", ++ pwdinfo->p2p_peer_interface_addr[ 0 ], pwdinfo->p2p_peer_interface_addr[ 1 ], pwdinfo->p2p_peer_interface_addr[ 2 ], ++ pwdinfo->p2p_peer_interface_addr[ 3 ], pwdinfo->p2p_peer_interface_addr[ 4 ], pwdinfo->p2p_peer_interface_addr[ 5 ]); ++ wrqu->data.length = strlen( extra ); ++ return ret; ++ ++} ++ ++static int rtw_p2p_get_peer_devaddr(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++ ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ ++ DBG_871X( "[%s] Role = %d, Status = %d, peer addr = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", __FUNCTION__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo), ++ pwdinfo->rx_prov_disc_info.peerDevAddr[ 0 ], pwdinfo->rx_prov_disc_info.peerDevAddr[ 1 ], ++ pwdinfo->rx_prov_disc_info.peerDevAddr[ 2 ], pwdinfo->rx_prov_disc_info.peerDevAddr[ 3 ], ++ pwdinfo->rx_prov_disc_info.peerDevAddr[ 4 ], pwdinfo->rx_prov_disc_info.peerDevAddr[ 5 ]); ++ sprintf( extra, "\n%.2X%.2X%.2X%.2X%.2X%.2X", ++ pwdinfo->rx_prov_disc_info.peerDevAddr[ 0 ], pwdinfo->rx_prov_disc_info.peerDevAddr[ 1 ], ++ pwdinfo->rx_prov_disc_info.peerDevAddr[ 2 ], pwdinfo->rx_prov_disc_info.peerDevAddr[ 3 ], ++ pwdinfo->rx_prov_disc_info.peerDevAddr[ 4 ], pwdinfo->rx_prov_disc_info.peerDevAddr[ 5 ]); ++ wrqu->data.length = strlen( extra ); ++ return ret; ++ ++} ++ ++static int rtw_p2p_get_peer_devaddr_by_invitation(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++ ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ ++ DBG_871X( "[%s] Role = %d, Status = %d, peer addr = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", __FUNCTION__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo), ++ pwdinfo->p2p_peer_device_addr[ 0 ], pwdinfo->p2p_peer_device_addr[ 1 ], ++ pwdinfo->p2p_peer_device_addr[ 2 ], pwdinfo->p2p_peer_device_addr[ 3 ], ++ pwdinfo->p2p_peer_device_addr[ 4 ], pwdinfo->p2p_peer_device_addr[ 5 ]); ++ sprintf( extra, "\nMAC %.2X:%.2X:%.2X:%.2X:%.2X:%.2X", ++ pwdinfo->p2p_peer_device_addr[ 0 ], pwdinfo->p2p_peer_device_addr[ 1 ], ++ pwdinfo->p2p_peer_device_addr[ 2 ], pwdinfo->p2p_peer_device_addr[ 3 ], ++ pwdinfo->p2p_peer_device_addr[ 4 ], pwdinfo->p2p_peer_device_addr[ 5 ]); ++ wrqu->data.length = strlen( extra ); ++ return ret; ++ ++} ++ ++static int rtw_p2p_get_groupid(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++ ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ ++ sprintf( extra, "\n%.2X:%.2X:%.2X:%.2X:%.2X:%.2X %s", ++ pwdinfo->groupid_info.go_device_addr[ 0 ], pwdinfo->groupid_info.go_device_addr[ 1 ], ++ pwdinfo->groupid_info.go_device_addr[ 2 ], pwdinfo->groupid_info.go_device_addr[ 3 ], ++ pwdinfo->groupid_info.go_device_addr[ 4 ], pwdinfo->groupid_info.go_device_addr[ 5 ], ++ pwdinfo->groupid_info.ssid); ++ wrqu->data.length = strlen( extra ); ++ return ret; ++ ++} ++ ++static int rtw_p2p_get_op_ch(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++ ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ ++ ++ DBG_871X( "[%s] Op_ch = %02x\n", __FUNCTION__, pwdinfo->operating_channel); ++ ++ sprintf( extra, "\n\nOp_ch=%.2d\n", pwdinfo->operating_channel ); ++ wrqu->data.length = strlen( extra ); ++ return ret; ++ ++} ++ ++inline static void macstr2num(u8 *dst, u8 *src) ++{ ++ int jj, kk; ++ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3) ++ { ++ dst[jj] = key_2char2num(src[kk], src[kk + 1]); ++ } ++} ++ ++static int rtw_p2p_get_wps_configmethod(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra, char *subcmd) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ u8 peerMAC[ETH_ALEN] = { 0x00 }; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ _irqL irqL; ++ _list * plist,*phead; ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ u8 blnMatch = 0; ++ u16 attr_content = 0; ++ uint attr_contentlen = 0; ++ u8 attr_content_str[P2P_PRIVATE_IOCTL_SET_LEN] = { 0x00 }; ++ ++ // Commented by Albert 20110727 ++ // The input data is the MAC address which the application wants to know its WPS config method. ++ // After knowing its WPS config method, the application can decide the config method for provisioning discovery. ++ // Format: iwpriv wlanx p2p_get_wpsCM 00:E0:4C:00:00:05 ++ ++ DBG_871X("[%s] data = %s\n", __FUNCTION__, subcmd); ++ ++ macstr2num(peerMAC, subcmd); ++ ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while (1) ++ { ++ if (rtw_end_of_queue_search(phead, plist) == _TRUE) break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ if (_rtw_memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) ++ { ++ u8 *wpsie; ++ uint wpsie_len = 0; ++ ++ // The mac address is matched. ++ ++ if ( (wpsie=rtw_get_wps_ie_from_scan_queue( &pnetwork->network.IEs[0], pnetwork->network.IELength, NULL, &wpsie_len, pnetwork->network.Reserved[0])) ) ++ { ++ rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_CONF_METHOD, (u8 *)&attr_content, &attr_contentlen); ++ if (attr_contentlen) ++ { ++ attr_content = be16_to_cpu(attr_content); ++ sprintf(attr_content_str, "\n\nM=%.4d", attr_content); ++ blnMatch = 1; ++ } ++ } ++ ++ break; ++ } ++ ++ plist = get_next(plist); ++ ++ } ++ ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ if (!blnMatch) ++ { ++ sprintf(attr_content_str, "\n\nM=0000"); ++ } ++ ++ wrqu->data.length = strlen(attr_content_str); ++ _rtw_memcpy(extra, attr_content_str, wrqu->data.length); ++ ++ return ret; ++ ++} ++ ++#ifdef CONFIG_WFD ++static int rtw_p2p_get_peer_wfd_port(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ ++ DBG_871X( "[%s] p2p_state = %d\n", __FUNCTION__, rtw_p2p_state(pwdinfo) ); ++ ++ sprintf( extra, "\n\nPort=%d\n", pwdinfo->wfd_info->peer_rtsp_ctrlport ); ++ DBG_871X( "[%s] remote port = %d\n", __FUNCTION__, pwdinfo->wfd_info->peer_rtsp_ctrlport ); ++ ++ wrqu->data.length = strlen( extra ); ++ return ret; ++ ++} ++ ++static int rtw_p2p_get_peer_wfd_preferred_connection(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ ++ sprintf( extra, "\n\nwfd_pc=%d\n", pwdinfo->wfd_info->wfd_pc ); ++ DBG_871X( "[%s] wfd_pc = %d\n", __FUNCTION__, pwdinfo->wfd_info->wfd_pc ); ++ ++ wrqu->data.length = strlen( extra ); ++ pwdinfo->wfd_info->wfd_pc = _FALSE; // Reset the WFD preferred connection to P2P ++ return ret; ++ ++} ++ ++static int rtw_p2p_get_peer_wfd_session_available(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ ++ sprintf( extra, "\n\nwfd_sa=%d\n", pwdinfo->wfd_info->peer_session_avail ); ++ DBG_871X( "[%s] wfd_sa = %d\n", __FUNCTION__, pwdinfo->wfd_info->peer_session_avail ); ++ ++ wrqu->data.length = strlen( extra ); ++ pwdinfo->wfd_info->peer_session_avail = _TRUE; // Reset the WFD session available ++ return ret; ++ ++} ++ ++#endif // CONFIG_WFD ++ ++static int rtw_p2p_get_go_device_address(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra, char *subcmd) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ u8 peerMAC[ETH_ALEN] = { 0x00 }; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ _irqL irqL; ++ _list *plist, *phead; ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ u8 blnMatch = 0; ++ u8 *p2pie; ++ uint p2pielen = 0, attr_contentlen = 0; ++ u8 attr_content[100] = { 0x00 }; ++ u8 go_devadd_str[P2P_PRIVATE_IOCTL_SET_LEN] = { 0x00 }; ++ ++ // Commented by Albert 20121209 ++ // The input data is the GO's interface address which the application wants to know its device address. ++ // Format: iwpriv wlanx p2p_get2 go_devadd=00:E0:4C:00:00:05 ++ ++ DBG_871X("[%s] data = %s\n", __FUNCTION__, subcmd); ++ ++ macstr2num(peerMAC, subcmd); ++ ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while (1) ++ { ++ if (rtw_end_of_queue_search(phead, plist) == _TRUE) break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ if (_rtw_memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) ++ { ++ // Commented by Albert 2011/05/18 ++ // Match the device address located in the P2P IE ++ // This is for the case that the P2P device address is not the same as the P2P interface address. ++ ++ if ((p2pie = rtw_get_p2p_ie_from_scan_queue( &pnetwork->network.IEs[0], pnetwork->network.IELength, NULL, &p2pielen, pnetwork->network.Reserved[0]))) ++ { ++ while (p2pie) ++ { ++ // The P2P Device ID attribute is included in the Beacon frame. ++ // The P2P Device Info attribute is included in the probe response frame. ++ ++ _rtw_memset(attr_content, 0x00, 100); ++ if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen)) ++ { ++ // Handle the P2P Device ID attribute of Beacon first ++ blnMatch = 1; ++ break; ++ ++ } else if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen)) ++ { ++ // Handle the P2P Device Info attribute of probe response ++ blnMatch = 1; ++ break; ++ } ++ ++ //Get the next P2P IE ++ p2pie = rtw_get_p2p_ie(p2pie + p2pielen, pnetwork->network.IELength - 12 - (p2pie - &pnetwork->network.IEs[12] + p2pielen), NULL, &p2pielen); ++ } ++ } ++ } ++ ++ plist = get_next(plist); ++ ++ } ++ ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ if (!blnMatch) ++ { ++ sprintf(go_devadd_str, "\n\ndev_add=NULL"); ++ } else ++ { ++ sprintf(go_devadd_str, "\n\ndev_add=%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", ++ attr_content[0], attr_content[1], attr_content[2], attr_content[3], attr_content[4], attr_content[5]); ++ } ++ ++ wrqu->data.length = strlen(go_devadd_str); ++ _rtw_memcpy(extra, go_devadd_str, wrqu->data.length); ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_get_device_type(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra, char *subcmd) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ u8 peerMAC[ETH_ALEN] = { 0x00 }; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ _irqL irqL; ++ _list *plist, *phead; ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ u8 blnMatch = 0; ++ u8 dev_type[8] = { 0x00 }; ++ uint dev_type_len = 0; ++ u8 dev_type_str[P2P_PRIVATE_IOCTL_SET_LEN] = { 0x00 }; // +9 is for the str "dev_type=", we have to clear it at wrqu->data.pointer ++ ++ // Commented by Albert 20121209 ++ // The input data is the MAC address which the application wants to know its device type. ++ // Such user interface could know the device type. ++ // Format: iwpriv wlanx p2p_get2 dev_type=00:E0:4C:00:00:05 ++ ++ DBG_871X("[%s] data = %s\n", __FUNCTION__, subcmd); ++ ++ macstr2num(peerMAC, subcmd); ++ ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while (1) ++ { ++ if (rtw_end_of_queue_search(phead, plist) == _TRUE) break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ if (_rtw_memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) ++ { ++ u8 *wpsie; ++ uint wpsie_len = 0; ++ ++ // The mac address is matched. ++ ++ if ( (wpsie=rtw_get_wps_ie_from_scan_queue( &pnetwork->network.IEs[0], pnetwork->network.IELength, NULL, &wpsie_len, pnetwork->network.Reserved[0])) ) ++ { ++ rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_PRIMARY_DEV_TYPE, dev_type, &dev_type_len); ++ if (dev_type_len) ++ { ++ u16 type = 0; ++ ++ _rtw_memcpy(&type, dev_type, 2); ++ type = be16_to_cpu(type); ++ sprintf(dev_type_str, "\n\nN=%.2d", type); ++ blnMatch = 1; ++ } ++ } ++ break; ++ } ++ ++ plist = get_next(plist); ++ ++ } ++ ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ if (!blnMatch) ++ { ++ sprintf(dev_type_str, "\n\nN=00"); ++ } ++ ++ wrqu->data.length = strlen(dev_type_str); ++ _rtw_memcpy(extra, dev_type_str, wrqu->data.length); ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_get_device_name(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra, char *subcmd) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ u8 peerMAC[ETH_ALEN] = { 0x00 }; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ _irqL irqL; ++ _list *plist, *phead; ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ u8 blnMatch = 0; ++ u8 dev_name[WPS_MAX_DEVICE_NAME_LEN] = { 0x00 }; ++ uint dev_len = 0; ++ u8 dev_name_str[P2P_PRIVATE_IOCTL_SET_LEN] = { 0x00 }; ++ ++ // Commented by Albert 20121225 ++ // The input data is the MAC address which the application wants to know its device name. ++ // Such user interface could show peer device's device name instead of ssid. ++ // Format: iwpriv wlanx p2p_get2 devN=00:E0:4C:00:00:05 ++ ++ DBG_871X("[%s] data = %s\n", __FUNCTION__, subcmd); ++ ++ macstr2num(peerMAC, subcmd); ++ ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while (1) ++ { ++ if (rtw_end_of_queue_search(phead, plist) == _TRUE) break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ if (_rtw_memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) ++ { ++ u8 *wpsie; ++ uint wpsie_len = 0; ++ ++ // The mac address is matched. ++ ++ if ( (wpsie=rtw_get_wps_ie_from_scan_queue( &pnetwork->network.IEs[0], pnetwork->network.IELength, NULL, &wpsie_len, pnetwork->network.Reserved[0])) ) ++ { ++ rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_DEVICE_NAME, dev_name, &dev_len); ++ if (dev_len) ++ { ++ sprintf(dev_name_str, "\n\nN=%s", dev_name); ++ blnMatch = 1; ++ } ++ } ++ break; ++ } ++ ++ plist = get_next(plist); ++ ++ } ++ ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ if (!blnMatch) ++ { ++ sprintf(dev_name_str, "\n\nN=0000"); ++ } ++ ++ wrqu->data.length = strlen(dev_name_str); ++ _rtw_memcpy(extra, dev_name_str, wrqu->data.length); ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_get_invitation_procedure(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra, char *subcmd) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ u8 peerMAC[ETH_ALEN] = { 0x00 }; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ _irqL irqL; ++ _list *plist, *phead; ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ u8 blnMatch = 0; ++ u8 *p2pie; ++ uint p2pielen = 0, attr_contentlen = 0; ++ u8 attr_content[2] = { 0x00 }; ++ u8 inv_proc_str[P2P_PRIVATE_IOCTL_SET_LEN] = { 0x00 }; ++ ++ // Commented by Ouden 20121226 ++ // The application wants to know P2P initation procedure is support or not. ++ // Format: iwpriv wlanx p2p_get2 InvProc=00:E0:4C:00:00:05 ++ ++ DBG_871X("[%s] data = %s\n", __FUNCTION__, subcmd); ++ ++ macstr2num(peerMAC, subcmd); ++ ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while (1) ++ { ++ if (rtw_end_of_queue_search(phead, plist) == _TRUE) break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ if (_rtw_memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) ++ { ++ // Commented by Albert 20121226 ++ // Match the device address located in the P2P IE ++ // This is for the case that the P2P device address is not the same as the P2P interface address. ++ ++ if ((p2pie = rtw_get_p2p_ie_from_scan_queue( &pnetwork->network.IEs[0], pnetwork->network.IELength, NULL, &p2pielen, pnetwork->network.Reserved[0]))) ++ { ++ while (p2pie) ++ { ++ //_rtw_memset( attr_content, 0x00, 2); ++ if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_CAPABILITY, attr_content, &attr_contentlen)) ++ { ++ // Handle the P2P capability attribute ++ blnMatch = 1; ++ break; ++ ++ } ++ ++ //Get the next P2P IE ++ p2pie = rtw_get_p2p_ie(p2pie + p2pielen, pnetwork->network.IELength - 12 - (p2pie - &pnetwork->network.IEs[12] + p2pielen), NULL, &p2pielen); ++ } ++ } ++ } ++ ++ plist = get_next(plist); ++ ++ } ++ ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ if (!blnMatch) ++ { ++ sprintf(inv_proc_str, "\nIP=-1"); ++ } else ++ { ++ if (attr_content[0] && 0x20) ++ { ++ sprintf(inv_proc_str, "\nIP=1"); ++ } else ++ { ++ sprintf(inv_proc_str, "\nIP=0"); ++ } ++ } ++ ++ wrqu->data.length = strlen(inv_proc_str); ++ _rtw_memcpy(extra, inv_proc_str, wrqu->data.length); ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_connect(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ u8 peerMAC[ ETH_ALEN ] = { 0x00 }; ++ int jj,kk; ++ u8 peerMACStr[ ETH_ALEN * 2 ] = { 0x00 }; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ _irqL irqL; ++ _list *plist, *phead; ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ uint uintPeerChannel = 0; ++#ifdef CONFIG_CONCURRENT_MODE ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_priv *pbuddy_mlmepriv = &pbuddy_adapter->mlmepriv; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++#endif // CONFIG_CONCURRENT_MODE ++ ++ // Commented by Albert 20110304 ++ // The input data contains two informations. ++ // 1. First information is the MAC address which wants to formate with ++ // 2. Second information is the WPS PINCode or "pbc" string for push button method ++ // Format: 00:E0:4C:00:00:05 ++ // Format: 00:E0:4C:00:00:05 ++ ++ DBG_871X( "[%s] data = %s\n", __FUNCTION__, extra ); ++ ++ if ( pwdinfo->p2p_state == P2P_STATE_NONE ) ++ { ++ DBG_871X( "[%s] WiFi Direct is disable!\n", __FUNCTION__ ); ++ return ret; ++ } ++ ++ if ( pwdinfo->ui_got_wps_info == P2P_NO_WPSINFO ) ++ { ++ return -1; ++ } ++ ++ for( jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3 ) ++ { ++ peerMAC[ jj ] = key_2char2num( extra[kk], extra[kk+ 1] ); ++ } ++ ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while(1) ++ { ++ if (rtw_end_of_queue_search(phead,plist)== _TRUE) ++ break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ if ( _rtw_memcmp( pnetwork->network.MacAddress, peerMAC, ETH_ALEN ) ) ++ { ++ uintPeerChannel = pnetwork->network.Configuration.DSConfig; ++ break; ++ } ++ ++ plist = get_next(plist); ++ ++ } ++ ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ if ( uintPeerChannel ) ++ { ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_fwstate( pbuddy_mlmepriv, _FW_LINKED ) ) ++ { ++ _cancel_timer_ex( &pwdinfo->ap_p2p_switch_timer ); ++ } ++#endif // CONFIG_CONCURRENT_MODE ++ ++ _rtw_memset( &pwdinfo->nego_req_info, 0x00, sizeof( struct tx_nego_req_info ) ); ++ _rtw_memset( &pwdinfo->groupid_info, 0x00, sizeof( struct group_id_info ) ); ++ ++ pwdinfo->nego_req_info.peer_channel_num[ 0 ] = uintPeerChannel; ++ _rtw_memcpy( pwdinfo->nego_req_info.peerDevAddr, pnetwork->network.MacAddress, ETH_ALEN ); ++ pwdinfo->nego_req_info.benable = _TRUE; ++ ++ _cancel_timer_ex( &pwdinfo->restore_p2p_state_timer ); ++ if ( rtw_p2p_state(pwdinfo) != P2P_STATE_GONEGO_OK ) ++ { ++ // Restore to the listen state if the current p2p state is not nego OK ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN ); ++ } ++ ++ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_ING); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_fwstate( pbuddy_mlmepriv, _FW_LINKED ) ) ++ { ++ // Have to enter the power saving with the AP ++ set_channel_bwmode(padapter, pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_ch_offset, pbuddy_mlmeext->cur_bwmode); ++ ++ issue_nulldata(pbuddy_adapter, NULL, 1, 3, 500); ++ } ++#endif // CONFIG_CONCURRENT_MODE ++ ++ DBG_871X( "[%s] Start PreTx Procedure!\n", __FUNCTION__ ); ++ _set_timer( &pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT ); ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_fwstate( pbuddy_mlmepriv, _FW_LINKED ) ) ++ { ++ _set_timer( &pwdinfo->restore_p2p_state_timer, P2P_CONCURRENT_GO_NEGO_TIMEOUT ); ++ } ++ else ++ { ++ _set_timer( &pwdinfo->restore_p2p_state_timer, P2P_GO_NEGO_TIMEOUT ); ++ } ++#else ++ _set_timer( &pwdinfo->restore_p2p_state_timer, P2P_GO_NEGO_TIMEOUT ); ++#endif // CONFIG_CONCURRENT_MODE ++ ++ } ++ else ++ { ++ DBG_871X( "[%s] Not Found in Scanning Queue~\n", __FUNCTION__ ); ++ ret = -1; ++ } ++exit: ++ return ret; ++} ++ ++static int rtw_p2p_invite_req(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ int jj,kk; ++ u8 peerMACStr[ ETH_ALEN * 2 ] = { 0x00 }; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ _list *plist, *phead; ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ uint uintPeerChannel = 0; ++ u8 attr_content[50] = { 0x00 }, _status = 0; ++ u8 *p2pie; ++ uint p2pielen = 0, attr_contentlen = 0; ++ _irqL irqL; ++ struct tx_invite_req_info* pinvite_req_info = &pwdinfo->invitereq_info; ++#ifdef CONFIG_CONCURRENT_MODE ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_priv *pbuddy_mlmepriv = &pbuddy_adapter->mlmepriv; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++#endif // CONFIG_CONCURRENT_MODE ++ ++#ifdef CONFIG_WFD ++ struct wifi_display_info* pwfd_info = pwdinfo->wfd_info; ++#endif // CONFIG_WFD ++ ++ // Commented by Albert 20120321 ++ // The input data contains two informations. ++ // 1. First information is the P2P device address which you want to send to. ++ // 2. Second information is the group id which combines with GO's mac address, space and GO's ssid. ++ // Command line sample: iwpriv wlan0 p2p_set invite="00:11:22:33:44:55 00:E0:4C:00:00:05 DIRECT-xy" ++ // Format: 00:11:22:33:44:55 00:E0:4C:00:00:05 DIRECT-xy ++ ++ DBG_871X( "[%s] data = %s\n", __FUNCTION__, extra ); ++ ++ if ( wrqu->data.length <= 37 ) ++ { ++ DBG_871X( "[%s] Wrong format!\n", __FUNCTION__ ); ++ return ret; ++ } ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ DBG_871X( "[%s] WiFi Direct is disable!\n", __FUNCTION__ ); ++ return ret; ++ } ++ else ++ { ++ // Reset the content of struct tx_invite_req_info ++ pinvite_req_info->benable = _FALSE; ++ _rtw_memset( pinvite_req_info->go_bssid, 0x00, ETH_ALEN ); ++ _rtw_memset( pinvite_req_info->go_ssid, 0x00, WLAN_SSID_MAXLEN ); ++ pinvite_req_info->ssidlen = 0x00; ++ pinvite_req_info->operating_ch = pwdinfo->operating_channel; ++ _rtw_memset( pinvite_req_info->peer_macaddr, 0x00, ETH_ALEN ); ++ pinvite_req_info->token = 3; ++ } ++ ++ for( jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3 ) ++ { ++ pinvite_req_info->peer_macaddr[ jj ] = key_2char2num( extra[kk], extra[kk+ 1] ); ++ } ++ ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while(1) ++ { ++ if (rtw_end_of_queue_search(phead,plist)== _TRUE) ++ break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ // Commented by Albert 2011/05/18 ++ // Match the device address located in the P2P IE ++ // This is for the case that the P2P device address is not the same as the P2P interface address. ++ ++ if ( (p2pie=rtw_get_p2p_ie_from_scan_queue( &pnetwork->network.IEs[0], pnetwork->network.IELength, NULL, &p2pielen, pnetwork->network.Reserved[0]))) ++ { ++ // The P2P Device ID attribute is included in the Beacon frame. ++ // The P2P Device Info attribute is included in the probe response frame. ++ ++ if ( rtw_get_p2p_attr_content( p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen) ) ++ { ++ // Handle the P2P Device ID attribute of Beacon first ++ if ( _rtw_memcmp( attr_content, pinvite_req_info->peer_macaddr, ETH_ALEN ) ) ++ { ++ uintPeerChannel = pnetwork->network.Configuration.DSConfig; ++ break; ++ } ++ } ++ else if ( rtw_get_p2p_attr_content( p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen) ) ++ { ++ // Handle the P2P Device Info attribute of probe response ++ if ( _rtw_memcmp( attr_content, pinvite_req_info->peer_macaddr, ETH_ALEN ) ) ++ { ++ uintPeerChannel = pnetwork->network.Configuration.DSConfig; ++ break; ++ } ++ } ++ ++ } ++ ++ plist = get_next(plist); ++ ++ } ++ ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++#ifdef CONFIG_WFD ++ if ( uintPeerChannel ) ++ { ++ u8 wfd_ie[ 128 ] = { 0x00 }; ++ uint wfd_ielen = 0; ++ ++ if ( rtw_get_wfd_ie_from_scan_queue( &pnetwork->network.IEs[0], pnetwork->network.IELength, wfd_ie, &wfd_ielen, pnetwork->network.Reserved[0]) ) ++ { ++ u8 wfd_devinfo[ 6 ] = { 0x00 }; ++ uint wfd_devlen = 6; ++ ++ DBG_871X( "[%s] Found WFD IE!\n", __FUNCTION__ ); ++ if ( rtw_get_wfd_attr_content( wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, wfd_devinfo, &wfd_devlen ) ) ++ { ++ u16 wfd_devinfo_field = 0; ++ ++ // Commented by Albert 20120319 ++ // The first two bytes are the WFD device information field of WFD device information subelement. ++ // In big endian format. ++ wfd_devinfo_field = RTW_GET_BE16(wfd_devinfo); ++ if ( wfd_devinfo_field & WFD_DEVINFO_SESSION_AVAIL ) ++ { ++ pwfd_info->peer_session_avail = _TRUE; ++ } ++ else ++ { ++ pwfd_info->peer_session_avail = _FALSE; ++ } ++ } ++ } ++ ++ if ( _FALSE == pwfd_info->peer_session_avail ) ++ { ++ DBG_871X( "[%s] WFD Session not avaiable!\n", __FUNCTION__ ); ++ goto exit; ++ } ++ } ++#endif // CONFIG_WFD ++ ++ if ( uintPeerChannel ) ++ { ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_fwstate( pbuddy_mlmepriv, _FW_LINKED ) ) ++ { ++ _cancel_timer_ex( &pwdinfo->ap_p2p_switch_timer ); ++ } ++#endif // CONFIG_CONCURRENT_MODE ++ ++ // Store the GO's bssid ++ for( jj = 0, kk = 18; jj < ETH_ALEN; jj++, kk += 3 ) ++ { ++ pinvite_req_info->go_bssid[ jj ] = key_2char2num( extra[kk], extra[kk+ 1] ); ++ } ++ ++ // Store the GO's ssid ++ pinvite_req_info->ssidlen = wrqu->data.length - 36; ++ _rtw_memcpy( pinvite_req_info->go_ssid, &extra[ 36 ], (u32) pinvite_req_info->ssidlen ); ++ pinvite_req_info->benable = _TRUE; ++ pinvite_req_info->peer_ch = uintPeerChannel; ++ ++ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_INVITE_REQ); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_fwstate( pbuddy_mlmepriv, _FW_LINKED ) ) ++ { ++ // Have to enter the power saving with the AP ++ set_channel_bwmode(padapter, pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_ch_offset, pbuddy_mlmeext->cur_bwmode); ++ ++ issue_nulldata(pbuddy_adapter, NULL, 1, 3, 500); ++ } ++ else ++ { ++ set_channel_bwmode(padapter, uintPeerChannel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ } ++#else ++ set_channel_bwmode(padapter, uintPeerChannel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++#endif ++ ++ _set_timer( &pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT ); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_fwstate( pbuddy_mlmepriv, _FW_LINKED ) ) ++ { ++ _set_timer( &pwdinfo->restore_p2p_state_timer, P2P_CONCURRENT_INVITE_TIMEOUT ); ++ } ++ else ++ { ++ _set_timer( &pwdinfo->restore_p2p_state_timer, P2P_INVITE_TIMEOUT ); ++ } ++#else ++ _set_timer( &pwdinfo->restore_p2p_state_timer, P2P_INVITE_TIMEOUT ); ++#endif // CONFIG_CONCURRENT_MODE ++ ++ ++ } ++ else ++ { ++ DBG_871X( "[%s] NOT Found in the Scanning Queue!\n", __FUNCTION__ ); ++ } ++exit: ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_set_persistent(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ int jj,kk; ++ u8 peerMACStr[ ETH_ALEN * 2 ] = { 0x00 }; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ _list *plist, *phead; ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ uint uintPeerChannel = 0; ++ u8 attr_content[50] = { 0x00 }, _status = 0; ++ u8 *p2pie; ++ uint p2pielen = 0, attr_contentlen = 0; ++ _irqL irqL; ++ struct tx_invite_req_info* pinvite_req_info = &pwdinfo->invitereq_info; ++#ifdef CONFIG_CONCURRENT_MODE ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_priv *pbuddy_mlmepriv = &pbuddy_adapter->mlmepriv; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++#endif // CONFIG_CONCURRENT_MODE ++ ++#ifdef CONFIG_WFD ++ struct wifi_display_info* pwfd_info = pwdinfo->wfd_info; ++#endif // CONFIG_WFD ++ ++ // Commented by Albert 20120328 ++ // The input data is 0 or 1 ++ // 0: disable persistent group functionality ++ // 1: enable persistent group founctionality ++ ++ DBG_871X( "[%s] data = %s\n", __FUNCTION__, extra ); ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ DBG_871X( "[%s] WiFi Direct is disable!\n", __FUNCTION__ ); ++ return ret; ++ } ++ else ++ { ++ if ( extra[ 0 ] == '0' ) // Disable the persistent group function. ++ { ++ pwdinfo->persistent_supported = _FALSE; ++ } ++ else if ( extra[ 0 ] == '1' ) // Enable the persistent group function. ++ { ++ pwdinfo->persistent_supported = _TRUE; ++ } ++ else ++ { ++ pwdinfo->persistent_supported = _FALSE; ++ } ++ } ++ printk( "[%s] persistent_supported = %d\n", __FUNCTION__, pwdinfo->persistent_supported ); ++ ++exit: ++ ++ return ret; ++ ++} ++ ++static int hexstr2bin(const char *hex, u8 *buf, size_t len) ++{ ++ size_t i; ++ int a; ++ const char *ipos = hex; ++ u8 *opos = buf; ++ ++ for (i = 0; i < len; i++) { ++ a = hex2byte_i(ipos); ++ if (a < 0) ++ return -1; ++ *opos++ = a; ++ ipos += 2; ++ } ++ return 0; ++} ++ ++static int uuid_str2bin(const char *str, u8 *bin) ++{ ++ const char *pos; ++ u8 *opos; ++ ++ pos = str; ++ opos = bin; ++ ++ if (hexstr2bin(pos, opos, 4)) ++ return -1; ++ pos += 8; ++ opos += 4; ++ ++ if (*pos++ != '-' || hexstr2bin(pos, opos, 2)) ++ return -1; ++ pos += 4; ++ opos += 2; ++ ++ if (*pos++ != '-' || hexstr2bin(pos, opos, 2)) ++ return -1; ++ pos += 4; ++ opos += 2; ++ ++ if (*pos++ != '-' || hexstr2bin(pos, opos, 2)) ++ return -1; ++ pos += 4; ++ opos += 2; ++ ++ if (*pos++ != '-' || hexstr2bin(pos, opos, 6)) ++ return -1; ++ ++ return 0; ++} ++ ++static int rtw_p2p_set_wps_uuid(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); ++ ++ DBG_871X("[%s] data = %s\n", __FUNCTION__, extra); ++ ++ if ((36 == strlen(extra)) && (uuid_str2bin(extra, pwdinfo->uuid) == 0)) ++ { ++ pwdinfo->external_uuid = 1; ++ } else { ++ pwdinfo->external_uuid = 0; ++ ret = -EINVAL; ++ } ++ ++ return ret; ++ ++} ++#ifdef CONFIG_WFD ++static int rtw_p2p_set_pc(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ u8 peerMAC[ ETH_ALEN ] = { 0x00 }; ++ int jj,kk; ++ u8 peerMACStr[ ETH_ALEN * 2 ] = { 0x00 }; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ _list *plist, *phead; ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ u8 attr_content[50] = { 0x00 }, _status = 0; ++ u8 *p2pie; ++ uint p2pielen = 0, attr_contentlen = 0; ++ _irqL irqL; ++ uint uintPeerChannel = 0; ++#ifdef CONFIG_CONCURRENT_MODE ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++#endif // CONFIG_CONCURRENT_MODE ++ struct wifi_display_info* pwfd_info = pwdinfo->wfd_info; ++ ++ // Commented by Albert 20120512 ++ // 1. Input information is the MAC address which wants to know the Preferred Connection bit (PC bit) ++ // Format: 00:E0:4C:00:00:05 ++ ++ DBG_871X( "[%s] data = %s\n", __FUNCTION__, extra ); ++ ++ if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ DBG_871X( "[%s] WiFi Direct is disable!\n", __FUNCTION__ ); ++ return ret; ++ } ++ ++ for( jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3 ) ++ { ++ peerMAC[ jj ] = key_2char2num( extra[kk], extra[kk+ 1] ); ++ } ++ ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while(1) ++ { ++ if (rtw_end_of_queue_search(phead,plist)== _TRUE) ++ break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ // Commented by Albert 2011/05/18 ++ // Match the device address located in the P2P IE ++ // This is for the case that the P2P device address is not the same as the P2P interface address. ++ ++ if ( (p2pie=rtw_get_p2p_ie_from_scan_queue( &pnetwork->network.IEs[0], pnetwork->network.IELength, NULL, &p2pielen, pnetwork->network.Reserved[0]))) ++ { ++ // The P2P Device ID attribute is included in the Beacon frame. ++ // The P2P Device Info attribute is included in the probe response frame. ++ printk( "[%s] Got P2P IE\n", __FUNCTION__ ); ++ if ( rtw_get_p2p_attr_content( p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen) ) ++ { ++ // Handle the P2P Device ID attribute of Beacon first ++ printk( "[%s] P2P_ATTR_DEVICE_ID \n", __FUNCTION__ ); ++ if ( _rtw_memcmp( attr_content, peerMAC, ETH_ALEN ) ) ++ { ++ uintPeerChannel = pnetwork->network.Configuration.DSConfig; ++ break; ++ } ++ } ++ else if ( rtw_get_p2p_attr_content( p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen) ) ++ { ++ // Handle the P2P Device Info attribute of probe response ++ printk( "[%s] P2P_ATTR_DEVICE_INFO \n", __FUNCTION__ ); ++ if ( _rtw_memcmp( attr_content, peerMAC, ETH_ALEN ) ) ++ { ++ uintPeerChannel = pnetwork->network.Configuration.DSConfig; ++ break; ++ } ++ } ++ ++ } ++ ++ plist = get_next(plist); ++ ++ } ++ ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ printk( "[%s] channel = %d\n", __FUNCTION__, uintPeerChannel ); ++ ++ if ( uintPeerChannel ) ++ { ++ u8 wfd_ie[ 128 ] = { 0x00 }; ++ uint wfd_ielen = 0; ++ ++ if ( rtw_get_wfd_ie_from_scan_queue( &pnetwork->network.IEs[0], pnetwork->network.IELength, wfd_ie, &wfd_ielen, pnetwork->network.Reserved[0]) ) ++ { ++ u8 wfd_devinfo[ 6 ] = { 0x00 }; ++ uint wfd_devlen = 6; ++ ++ DBG_871X( "[%s] Found WFD IE!\n", __FUNCTION__ ); ++ if ( rtw_get_wfd_attr_content( wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, wfd_devinfo, &wfd_devlen ) ) ++ { ++ u16 wfd_devinfo_field = 0; ++ ++ // Commented by Albert 20120319 ++ // The first two bytes are the WFD device information field of WFD device information subelement. ++ // In big endian format. ++ wfd_devinfo_field = RTW_GET_BE16(wfd_devinfo); ++ if ( wfd_devinfo_field & WFD_DEVINFO_PC_TDLS ) ++ { ++ pwfd_info->wfd_pc = _TRUE; ++ } ++ else ++ { ++ pwfd_info->wfd_pc = _FALSE; ++ } ++ } ++ } ++ } ++ else ++ { ++ DBG_871X( "[%s] NOT Found in the Scanning Queue!\n", __FUNCTION__ ); ++ } ++ ++exit: ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_set_wfd_device_type(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ struct wifi_display_info* pwfd_info = pwdinfo->wfd_info; ++ ++ // Commented by Albert 20120328 ++ // The input data is 0 or 1 ++ // 0: specify to Miracast source device ++ // 1 or others: specify to Miracast sink device (display device) ++ ++ DBG_871X( "[%s] data = %s\n", __FUNCTION__, extra ); ++ ++ if ( extra[ 0 ] == '0' ) // Set to Miracast source device. ++ { ++ pwfd_info->wfd_device_type = WFD_DEVINFO_SOURCE; ++ } ++ else // Set to Miracast sink device. ++ { ++ pwfd_info->wfd_device_type = WFD_DEVINFO_PSINK; ++ } ++ ++exit: ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_set_scan_result_type(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ struct wifi_display_info *pwfd_info = pwdinfo->wfd_info; ++ ++ // Commented by Albert 20120328 ++ // The input data is 0 , 1 , 2 ++ // 0: when the P2P is enabled, the scan result will return all the found P2P device. ++ // 1: when the P2P is enabled, the scan result will return all the found P2P device and AP. ++ // 2: when the P2P is enabled, the scan result will show up the found Miracast devices base on... ++ // It will show up all the Miracast source device if this device is sink. ++ // It will show up all the Miracast sink device if this device is source. ++ ++ DBG_871X( "[%s] data = %s\n", __FUNCTION__, extra ); ++ ++ if ( extra[ 0 ] == '0' ) ++ { ++ pwfd_info->scan_result_type = SCAN_RESULT_P2P_ONLY; ++ } ++ else if ( extra[ 0 ] == '1' ) ++ { ++ pwfd_info->scan_result_type = SCAN_RESULT_ALL; ++ } ++ else if ( extra[ 0 ] == '2' ) ++ { ++ pwfd_info->scan_result_type = SCAN_RESULT_WFD_TYPE; ++ } ++ else ++ { ++ pwfd_info->scan_result_type = SCAN_RESULT_P2P_ONLY; ++ } ++ ++exit: ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_set_wfd_enable(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++// Commented by Kurt 20121206 ++// This function is used to set wfd enabled ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ ++ if(*extra == '0' ) ++ pwdinfo->wfd_info->wfd_enable = _FALSE; ++ else if(*extra == '1') ++ pwdinfo->wfd_info->wfd_enable = _TRUE; ++ ++ DBG_871X( "[%s] wfd_enable = %d\n", __FUNCTION__, pwdinfo->wfd_info->wfd_enable ); ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_set_driver_iface(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++// Commented by Kurt 20121206 ++// This function is used to set driver iface is WEXT or CFG80211 ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ ++ if(*extra == '1' ) ++ { ++ pwdinfo->driver_interface = DRIVER_WEXT; ++ DBG_871X( "[%s] driver_interface = WEXT\n", __FUNCTION__); ++ } ++ else if(*extra == '2') ++ { ++ pwdinfo->driver_interface = DRIVER_CFG80211; ++ DBG_871X( "[%s] driver_interface = CFG80211\n", __FUNCTION__); ++ } ++ ++ return ret; ++ ++} ++ ++// To set the WFD session available to enable or disable ++static int rtw_p2p_set_sa(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ struct wifi_display_info *pwfd_info = pwdinfo->wfd_info; ++ ++ DBG_871X( "[%s] data = %s\n", __FUNCTION__, extra ); ++ ++ if( 0 ) ++ { ++ DBG_871X( "[%s] WiFi Direct is disable!\n", __FUNCTION__ ); ++ return ret; ++ } ++ else ++ { ++ if ( extra[ 0 ] == '0' ) // Disable the session available. ++ { ++ pwdinfo->session_available = _FALSE; ++ } ++ else if ( extra[ 0 ] == '1' ) // Enable the session available. ++ { ++ pwdinfo->session_available = _TRUE; ++ } ++ else ++ { ++ pwdinfo->session_available = _FALSE; ++ } ++ } ++ printk( "[%s] session available = %d\n", __FUNCTION__, pwdinfo->session_available ); ++ ++exit: ++ ++ return ret; ++ ++} ++#endif // CONFIG_WFD ++ ++static int rtw_p2p_prov_disc(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ u8 peerMAC[ ETH_ALEN ] = { 0x00 }; ++ int jj,kk; ++ u8 peerMACStr[ ETH_ALEN * 2 ] = { 0x00 }; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ _list *plist, *phead; ++ _queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ uint uintPeerChannel = 0; ++ u8 attr_content[100] = { 0x00 }, _status = 0; ++ u8 *p2pie; ++ uint p2pielen = 0, attr_contentlen = 0; ++ _irqL irqL; ++ u8 ie_offset; ++#ifdef CONFIG_CONCURRENT_MODE ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ struct mlme_priv *pbuddy_mlmepriv = &pbuddy_adapter->mlmepriv; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddy_adapter->mlmeextpriv; ++#endif // CONFIG_CONCURRENT_MODE ++ ++#ifdef CONFIG_WFD ++ struct wifi_display_info* pwfd_info = pwdinfo->wfd_info; ++#endif // CONFIG_WFD ++ ++ // Commented by Albert 20110301 ++ // The input data contains two informations. ++ // 1. First information is the MAC address which wants to issue the provisioning discovery request frame. ++ // 2. Second information is the WPS configuration method which wants to discovery ++ // Format: 00:E0:4C:00:00:05_display ++ // Format: 00:E0:4C:00:00:05_keypad ++ // Format: 00:E0:4C:00:00:05_pbc ++ // Format: 00:E0:4C:00:00:05_label ++ ++ DBG_871X( "[%s] data = %s\n", __FUNCTION__, extra ); ++ ++ if ( pwdinfo->p2p_state == P2P_STATE_NONE ) ++ { ++ DBG_871X( "[%s] WiFi Direct is disable!\n", __FUNCTION__ ); ++ return ret; ++ } ++ else ++ { ++#ifdef CONFIG_INTEL_WIDI ++ if(check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE){ ++ DBG_871X( "[%s] WiFi is under survey!\n", __FUNCTION__ ); ++ return ret; ++ } ++#endif //CONFIG_INTEL_WIDI ++ ++ // Reset the content of struct tx_provdisc_req_info excluded the wps_config_method_request. ++ _rtw_memset( pwdinfo->tx_prov_disc_info.peerDevAddr, 0x00, ETH_ALEN ); ++ _rtw_memset( pwdinfo->tx_prov_disc_info.peerIFAddr, 0x00, ETH_ALEN ); ++ _rtw_memset( &pwdinfo->tx_prov_disc_info.ssid, 0x00, sizeof( NDIS_802_11_SSID ) ); ++ pwdinfo->tx_prov_disc_info.peer_channel_num[ 0 ] = 0; ++ pwdinfo->tx_prov_disc_info.peer_channel_num[ 1 ] = 0; ++ pwdinfo->tx_prov_disc_info.benable = _FALSE; ++ } ++ ++ for( jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3 ) ++ { ++ peerMAC[ jj ] = key_2char2num( extra[kk], extra[kk+ 1] ); ++ } ++ ++ if ( _rtw_memcmp( &extra[ 18 ], "display", 7 ) ) ++ { ++ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_DISPLYA; ++ } ++ else if ( _rtw_memcmp( &extra[ 18 ], "keypad", 7 ) ) ++ { ++ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_KEYPAD; ++ } ++ else if ( _rtw_memcmp( &extra[ 18 ], "pbc", 3 ) ) ++ { ++ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_PUSH_BUTTON; ++ } ++ else if ( _rtw_memcmp( &extra[ 18 ], "label", 5 ) ) ++ { ++ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_LABEL; ++ } ++ else ++ { ++ DBG_871X( "[%s] Unknown WPS config methodn", __FUNCTION__ ); ++ return( ret ); ++ } ++ ++ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while(1) ++ { ++ if (rtw_end_of_queue_search(phead,plist)== _TRUE) ++ break; ++ ++ if( uintPeerChannel != 0 ) ++ break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ // Commented by Albert 2011/05/18 ++ // Match the device address located in the P2P IE ++ // This is for the case that the P2P device address is not the same as the P2P interface address. ++ ++ if (pnetwork->network.Reserved[0] == 2) { // Probe Request ++ ie_offset = 0; ++ } else { // Beacon or Probe Respones ++ ie_offset = 12; ++ } ++ if ( (p2pie=rtw_get_p2p_ie_from_scan_queue( &pnetwork->network.IEs[0], pnetwork->network.IELength, NULL, &p2pielen, pnetwork->network.Reserved[0]))) ++ { ++ while ( p2pie ) ++ { ++ // The P2P Device ID attribute is included in the Beacon frame. ++ // The P2P Device Info attribute is included in the probe response frame. ++ ++ if ( rtw_get_p2p_attr_content( p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen) ) ++ { ++ // Handle the P2P Device ID attribute of Beacon first ++ if ( _rtw_memcmp( attr_content, peerMAC, ETH_ALEN ) ) ++ { ++ uintPeerChannel = pnetwork->network.Configuration.DSConfig; ++ break; ++ } ++ } ++ else if ( rtw_get_p2p_attr_content( p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen) ) ++ { ++ // Handle the P2P Device Info attribute of probe response ++ if ( _rtw_memcmp( attr_content, peerMAC, ETH_ALEN ) ) ++ { ++ uintPeerChannel = pnetwork->network.Configuration.DSConfig; ++ break; ++ } ++ } ++ ++ //Get the next P2P IE ++ p2pie = rtw_get_p2p_ie(p2pie+p2pielen, pnetwork->network.IELength - ie_offset -(p2pie -&pnetwork->network.IEs[ie_offset] + p2pielen), NULL, &p2pielen); ++ } ++ } ++ ++#ifdef CONFIG_INTEL_WIDI ++ // Some Intel WiDi source may not provide P2P IE, ++ // so we could only compare mac addr by 802.11 Source Address ++ if( pmlmepriv->widi_state == INTEL_WIDI_STATE_WFD_CONNECTION ++ && uintPeerChannel == 0 ) ++ { ++ if ( _rtw_memcmp( pnetwork->network.MacAddress, peerMAC, ETH_ALEN ) ) ++ { ++ uintPeerChannel = pnetwork->network.Configuration.DSConfig; ++ break; ++ } ++ } ++#endif //CONFIG_INTEL_WIDI ++ ++ plist = get_next(plist); ++ ++ } ++ ++ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ ++ if ( uintPeerChannel ) ++ { ++#ifdef CONFIG_WFD ++ { ++ u8 wfd_ie[ 128 ] = { 0x00 }; ++ uint wfd_ielen = 0; ++ ++ if ( rtw_get_wfd_ie_from_scan_queue( &pnetwork->network.IEs[0], pnetwork->network.IELength, wfd_ie, &wfd_ielen, pnetwork->network.Reserved[0]) ) ++ { ++ u8 wfd_devinfo[ 6 ] = { 0x00 }; ++ uint wfd_devlen = 6; ++ ++ DBG_871X( "[%s] Found WFD IE!\n", __FUNCTION__ ); ++ if ( rtw_get_wfd_attr_content( wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, wfd_devinfo, &wfd_devlen ) ) ++ { ++ u16 wfd_devinfo_field = 0; ++ ++ // Commented by Albert 20120319 ++ // The first two bytes are the WFD device information field of WFD device information subelement. ++ // In big endian format. ++ wfd_devinfo_field = RTW_GET_BE16(wfd_devinfo); ++ if ( wfd_devinfo_field & WFD_DEVINFO_SESSION_AVAIL ) ++ { ++ pwfd_info->peer_session_avail = _TRUE; ++ } ++ else ++ { ++ pwfd_info->peer_session_avail = _FALSE; ++ } ++ } ++ } ++ ++ if ( _FALSE == pwfd_info->peer_session_avail ) ++ { ++ DBG_871X( "[%s] WFD Session not avaiable!\n", __FUNCTION__ ); ++ goto exit; ++ } ++ } ++#endif // CONFIG_WFD ++ ++ DBG_871X( "[%s] peer channel: %d!\n", __FUNCTION__, uintPeerChannel ); ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_fwstate( pbuddy_mlmepriv, _FW_LINKED ) ) ++ { ++ _cancel_timer_ex( &pwdinfo->ap_p2p_switch_timer ); ++ } ++#endif // CONFIG_CONCURRENT_MODE ++ _rtw_memcpy( pwdinfo->tx_prov_disc_info.peerIFAddr, pnetwork->network.MacAddress, ETH_ALEN ); ++ _rtw_memcpy( pwdinfo->tx_prov_disc_info.peerDevAddr, peerMAC, ETH_ALEN ); ++ pwdinfo->tx_prov_disc_info.peer_channel_num[0] = ( u16 ) uintPeerChannel; ++ pwdinfo->tx_prov_disc_info.benable = _TRUE; ++ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ); ++ ++ if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) ++ { ++ _rtw_memcpy( &pwdinfo->tx_prov_disc_info.ssid, &pnetwork->network.Ssid, sizeof( NDIS_802_11_SSID ) ); ++ } ++ else if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ { ++ _rtw_memcpy( pwdinfo->tx_prov_disc_info.ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN ); ++ pwdinfo->tx_prov_disc_info.ssid.SsidLength= P2P_WILDCARD_SSID_LEN; ++ } ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_fwstate( pbuddy_mlmepriv, _FW_LINKED ) ) ++ { ++ // Have to enter the power saving with the AP ++ set_channel_bwmode(padapter, pbuddy_mlmeext->cur_channel, pbuddy_mlmeext->cur_ch_offset, pbuddy_mlmeext->cur_bwmode); ++ ++ issue_nulldata(pbuddy_adapter, NULL, 1, 3, 500); ++ } ++ else ++ { ++ set_channel_bwmode(padapter, uintPeerChannel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ } ++#else ++ set_channel_bwmode(padapter, uintPeerChannel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++#endif ++ ++ _set_timer( &pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT ); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ( check_fwstate( pbuddy_mlmepriv, _FW_LINKED ) ) ++ { ++ _set_timer( &pwdinfo->restore_p2p_state_timer, P2P_CONCURRENT_PROVISION_TIMEOUT ); ++ } ++ else ++ { ++ _set_timer( &pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT ); ++ } ++#else ++ _set_timer( &pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT ); ++#endif // CONFIG_CONCURRENT_MODE ++ ++ } ++ else ++ { ++ DBG_871X( "[%s] NOT Found in the Scanning Queue!\n", __FUNCTION__ ); ++#ifdef CONFIG_INTEL_WIDI ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH); ++ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE); ++ rtw_free_network_queue(padapter, _TRUE); ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ rtw_sitesurvey_cmd(padapter, NULL, 0, NULL, 0); ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++#endif //CONFIG_INTEL_WIDI ++ } ++exit: ++ ++ return ret; ++ ++} ++ ++// Added by Albert 20110328 ++// This function is used to inform the driver the user had specified the pin code value or pbc ++// to application. ++ ++static int rtw_p2p_got_wpsinfo(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &( padapter->wdinfo ); ++ ++ ++ DBG_871X( "[%s] data = %s\n", __FUNCTION__, extra ); ++ // Added by Albert 20110328 ++ // if the input data is P2P_NO_WPSINFO -> reset the wpsinfo ++ // if the input data is P2P_GOT_WPSINFO_PEER_DISPLAY_PIN -> the utility just input the PIN code got from the peer P2P device. ++ // if the input data is P2P_GOT_WPSINFO_SELF_DISPLAY_PIN -> the utility just got the PIN code from itself. ++ // if the input data is P2P_GOT_WPSINFO_PBC -> the utility just determine to use the PBC ++ ++ if ( *extra == '0' ) ++ { ++ pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO; ++ } ++ else if ( *extra == '1' ) ++ { ++ pwdinfo->ui_got_wps_info = P2P_GOT_WPSINFO_PEER_DISPLAY_PIN; ++ } ++ else if ( *extra == '2' ) ++ { ++ pwdinfo->ui_got_wps_info = P2P_GOT_WPSINFO_SELF_DISPLAY_PIN; ++ } ++ else if ( *extra == '3' ) ++ { ++ pwdinfo->ui_got_wps_info = P2P_GOT_WPSINFO_PBC; ++ } ++ else ++ { ++ pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO; ++ } ++ ++ return ret; ++ ++} ++ ++#endif //CONFIG_P2P ++ ++static int rtw_p2p_set(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++#ifdef CONFIG_P2P ++ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ DBG_871X( "[%s] extra = %s\n", __FUNCTION__, extra ); ++ ++ if ( _rtw_memcmp( extra, "enable=", 7 ) ) ++ { ++ rtw_wext_p2p_enable( dev, info, wrqu, &extra[7] ); ++ } ++ else if ( _rtw_memcmp( extra, "setDN=", 6 ) ) ++ { ++ wrqu->data.length -= 6; ++ rtw_p2p_setDN( dev, info, wrqu, &extra[6] ); ++ } ++ else if ( _rtw_memcmp( extra, "profilefound=", 13 ) ) ++ { ++ wrqu->data.length -= 13; ++ rtw_p2p_profilefound( dev, info, wrqu, &extra[13] ); ++ } ++ else if ( _rtw_memcmp( extra, "prov_disc=", 10 ) ) ++ { ++ wrqu->data.length -= 10; ++ rtw_p2p_prov_disc( dev, info, wrqu, &extra[10] ); ++ } ++ else if ( _rtw_memcmp( extra, "nego=", 5 ) ) ++ { ++ wrqu->data.length -= 5; ++ rtw_p2p_connect( dev, info, wrqu, &extra[5] ); ++ } ++ else if ( _rtw_memcmp( extra, "intent=", 7 ) ) ++ { ++ // Commented by Albert 2011/03/23 ++ // The wrqu->data.length will include the null character ++ // So, we will decrease 7 + 1 ++ wrqu->data.length -= 8; ++ rtw_p2p_set_intent( dev, info, wrqu, &extra[7] ); ++ } ++ else if ( _rtw_memcmp( extra, "ssid=", 5 ) ) ++ { ++ wrqu->data.length -= 5; ++ rtw_p2p_set_go_nego_ssid( dev, info, wrqu, &extra[5] ); ++ } ++ else if ( _rtw_memcmp( extra, "got_wpsinfo=", 12 ) ) ++ { ++ wrqu->data.length -= 12; ++ rtw_p2p_got_wpsinfo( dev, info, wrqu, &extra[12] ); ++ } ++ else if ( _rtw_memcmp( extra, "listen_ch=", 10 ) ) ++ { ++ // Commented by Albert 2011/05/24 ++ // The wrqu->data.length will include the null character ++ // So, we will decrease (10 + 1) ++ wrqu->data.length -= 11; ++ rtw_p2p_set_listen_ch( dev, info, wrqu, &extra[10] ); ++ } ++ else if ( _rtw_memcmp( extra, "op_ch=", 6 ) ) ++ { ++ // Commented by Albert 2011/05/24 ++ // The wrqu->data.length will include the null character ++ // So, we will decrease (6 + 1) ++ wrqu->data.length -= 7; ++ rtw_p2p_set_op_ch( dev, info, wrqu, &extra[6] ); ++ } ++ else if ( _rtw_memcmp( extra, "invite=", 7 ) ) ++ { ++ wrqu->data.length -= 8; ++ rtw_p2p_invite_req( dev, info, wrqu, &extra[7] ); ++ } ++ else if ( _rtw_memcmp( extra, "persistent=", 11 ) ) ++ { ++ wrqu->data.length -= 11; ++ rtw_p2p_set_persistent( dev, info, wrqu, &extra[11] ); ++ } ++ else if ( _rtw_memcmp ( extra, "uuid=", 5) ) ++ { ++ wrqu->data.length -= 5; ++ ret = rtw_p2p_set_wps_uuid( dev, info, wrqu, &extra[5] ); ++ } ++#ifdef CONFIG_WFD ++ else if ( _rtw_memcmp( extra, "sa=", 3 ) ) ++ { ++ // sa: WFD Session Available information ++ wrqu->data.length -= 3; ++ rtw_p2p_set_sa( dev, info, wrqu, &extra[3] ); ++ } ++ else if ( _rtw_memcmp( extra, "pc=", 3 ) ) ++ { ++ // pc: WFD Preferred Connection ++ wrqu->data.length -= 3; ++ rtw_p2p_set_pc( dev, info, wrqu, &extra[3] ); ++ } ++ else if ( _rtw_memcmp( extra, "wfd_type=", 9 ) ) ++ { ++ // Specify this device is Mircast source or sink ++ wrqu->data.length -= 9; ++ rtw_p2p_set_wfd_device_type( dev, info, wrqu, &extra[9] ); ++ } ++ else if ( _rtw_memcmp( extra, "scan_type=", 10 ) ) ++ { ++ wrqu->data.length -= 10; ++ rtw_p2p_set_scan_result_type( dev, info, wrqu, &extra[10] ); ++ } ++ else if ( _rtw_memcmp( extra, "wfd_enable=", 11 ) ) ++ { ++ wrqu->data.length -= 11; ++ rtw_p2p_set_wfd_enable( dev, info, wrqu, &extra[11] ); ++ } ++ else if ( _rtw_memcmp( extra, "driver_iface=", 13 ) ) ++ { ++ wrqu->data.length -= 13; ++ rtw_p2p_set_driver_iface( dev, info, wrqu, &extra[13] ); ++ } ++#endif //CONFIG_WFD ++#endif //CONFIG_P2P ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_get(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ ++#ifdef CONFIG_P2P ++ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct iw_point *pdata = &wrqu->data; ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ if ( padapter->bShowGetP2PState ) ++ { ++ DBG_871X( "[%s] extra = %s\n", __FUNCTION__, (char*) wrqu->data.pointer ); ++ } ++ ++ if ( _rtw_memcmp( wrqu->data.pointer, "status", 6 ) ) ++ { ++ rtw_p2p_get_status( dev, info, wrqu, extra ); ++ } ++ else if ( _rtw_memcmp( wrqu->data.pointer, "role", 4 ) ) ++ { ++ rtw_p2p_get_role( dev, info, wrqu, extra); ++ } ++ else if ( _rtw_memcmp( wrqu->data.pointer, "peer_ifa", 8 ) ) ++ { ++ rtw_p2p_get_peer_ifaddr( dev, info, wrqu, extra); ++ } ++ else if ( _rtw_memcmp( wrqu->data.pointer, "req_cm", 6 ) ) ++ { ++ rtw_p2p_get_req_cm( dev, info, wrqu, extra); ++ } ++ else if ( _rtw_memcmp( wrqu->data.pointer, "peer_deva", 9 ) ) ++ { ++ // Get the P2P device address when receiving the provision discovery request frame. ++ rtw_p2p_get_peer_devaddr( dev, info, wrqu, extra); ++ } ++ else if ( _rtw_memcmp( wrqu->data.pointer, "group_id", 8 ) ) ++ { ++ rtw_p2p_get_groupid( dev, info, wrqu, extra); ++ } ++ else if ( _rtw_memcmp( wrqu->data.pointer, "inv_peer_deva", 13 ) ) ++ { ++ // Get the P2P device address when receiving the P2P Invitation request frame. ++ rtw_p2p_get_peer_devaddr_by_invitation( dev, info, wrqu, extra); ++ } ++ else if ( _rtw_memcmp( wrqu->data.pointer, "op_ch", 5 ) ) ++ { ++ rtw_p2p_get_op_ch( dev, info, wrqu, extra); ++ } ++#ifdef CONFIG_WFD ++ else if ( _rtw_memcmp( wrqu->data.pointer, "peer_port", 9 ) ) ++ { ++ rtw_p2p_get_peer_wfd_port( dev, info, wrqu, extra ); ++ } ++ else if ( _rtw_memcmp( wrqu->data.pointer, "wfd_sa", 6 ) ) ++ { ++ rtw_p2p_get_peer_wfd_session_available( dev, info, wrqu, extra ); ++ } ++ else if ( _rtw_memcmp( wrqu->data.pointer, "wfd_pc", 6 ) ) ++ { ++ rtw_p2p_get_peer_wfd_preferred_connection( dev, info, wrqu, extra ); ++ } ++#endif // CONFIG_WFD ++ ++#endif //CONFIG_P2P ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_get2(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ ++#ifdef CONFIG_P2P ++ ++ int length = wrqu->data.length; ++ char *buffer = (u8 *)rtw_malloc(length); ++ ++ if (buffer == NULL) ++ { ++ ret = -ENOMEM; ++ goto bad; ++ } ++ ++ if (copy_from_user(buffer, wrqu->data.pointer, wrqu->data.length)) ++ { ++ ret - EFAULT; ++ goto bad; ++ } ++ ++ DBG_871X("[%s] buffer = %s\n", __FUNCTION__, buffer); ++ ++ if (_rtw_memcmp(buffer, "wpsCM=", 6)) ++ { ++ ret = rtw_p2p_get_wps_configmethod(dev, info, wrqu, extra, &buffer[6]); ++ } else if (_rtw_memcmp(buffer, "devN=", 5)) ++ { ++ ret = rtw_p2p_get_device_name(dev, info, wrqu, extra, &buffer[5]); ++ } else if (_rtw_memcmp(buffer, "dev_type=", 9)) ++ { ++ ret = rtw_p2p_get_device_type(dev, info, wrqu, extra, &buffer[9]); ++ } else if (_rtw_memcmp(buffer, "go_devadd=", 10)) ++ { ++ ret = rtw_p2p_get_go_device_address(dev, info, wrqu, extra, &buffer[10]); ++ } else if (_rtw_memcmp(buffer, "InvProc=", 8)) ++ { ++ ret = rtw_p2p_get_invitation_procedure(dev, info, wrqu, extra, &buffer[8]); ++ } else ++ { ++ snprintf(extra, sizeof("Command not found."), "Command not found."); ++ wrqu->data.length = strlen(extra); ++ } ++ ++bad: ++ if (buffer) ++ { ++ rtw_mfree(buffer, length); ++ } ++ ++#endif //CONFIG_P2P ++ ++ return ret; ++ ++} ++ ++static int rtw_cta_test_start(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ DBG_871X("%s %s\n", __func__, extra); ++ if (!strcmp(extra, "1")) ++ padapter->in_cta_test = 1; ++ else ++ padapter->in_cta_test = 0; ++ ++ if(padapter->in_cta_test) ++ { ++ u32 v = rtw_read32(padapter, REG_RCR); ++ v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN );//| RCR_ADF ++ rtw_write32(padapter, REG_RCR, v); ++ DBG_871X("enable RCR_ADF\n"); ++ } ++ else ++ { ++ u32 v = rtw_read32(padapter, REG_RCR); ++ v |= RCR_CBSSID_DATA | RCR_CBSSID_BCN ;//| RCR_ADF ++ rtw_write32(padapter, REG_RCR, v); ++ DBG_871X("disable RCR_ADF\n"); ++ } ++ return ret; ++} ++ ++ ++extern int rtw_change_ifname(_adapter *padapter, const char *ifname); ++static int rtw_rereg_nd_name(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ _adapter *padapter = rtw_netdev_priv(dev); ++ struct rereg_nd_name_data *rereg_priv = &padapter->rereg_nd_name_priv; ++ char new_ifname[IFNAMSIZ]; ++ ++ if(rereg_priv->old_ifname[0] == 0) { ++ char *reg_ifname; ++#ifdef CONFIG_CONCURRENT_MODE ++ if (padapter->isprimary) ++ reg_ifname = padapter->registrypriv.ifname; ++ else ++#endif ++ reg_ifname = padapter->registrypriv.if2name; ++ ++ strncpy(rereg_priv->old_ifname, reg_ifname, IFNAMSIZ); ++ rereg_priv->old_ifname[IFNAMSIZ-1] = 0; ++ } ++ ++ //DBG_871X("%s wrqu->data.length:%d\n", __FUNCTION__, wrqu->data.length); ++ if(wrqu->data.length > IFNAMSIZ) ++ return -EFAULT; ++ ++ if ( copy_from_user(new_ifname, wrqu->data.pointer, IFNAMSIZ) ) { ++ return -EFAULT; ++ } ++ ++ if( 0 == strcmp(rereg_priv->old_ifname, new_ifname) ) { ++ return ret; ++ } ++ ++ DBG_871X("%s new_ifname:%s\n", __FUNCTION__, new_ifname); ++ if( 0 != (ret = rtw_change_ifname(padapter, new_ifname)) ) { ++ goto exit; ++ } ++ ++ if(_rtw_memcmp(rereg_priv->old_ifname, "disable%d", 9) == _TRUE) { ++ padapter->ledpriv.bRegUseLed= rereg_priv->old_bRegUseLed; ++ rtw_hal_sw_led_init(padapter); ++ /* rtw_ips_mode_req(&padapter->pwrctrlpriv, rereg_priv->old_ips_mode); */ ++ } ++ ++ strncpy(rereg_priv->old_ifname, new_ifname, IFNAMSIZ); ++ rereg_priv->old_ifname[IFNAMSIZ-1] = 0; ++ ++ if(_rtw_memcmp(new_ifname, "disable%d", 9) == _TRUE) { ++ ++ DBG_871X("%s disable\n", __FUNCTION__); ++ // free network queue for Android's timming issue ++ rtw_free_network_queue(padapter, _TRUE); ++ ++ // close led ++ rtw_led_control(padapter, LED_CTL_POWER_OFF); ++ rereg_priv->old_bRegUseLed = padapter->ledpriv.bRegUseLed; ++ padapter->ledpriv.bRegUseLed= _FALSE; ++ rtw_hal_sw_led_deinit(padapter); ++ ++ /* ++ // the interface is being "disabled", we can do deeper IPS ++ rereg_priv->old_ips_mode = rtw_get_ips_mode_req(&padapter->pwrctrlpriv); ++ rtw_ips_mode_req(&padapter->pwrctrlpriv, IPS_NORMAL); ++ */ ++ } ++exit: ++ return ret; ++ ++} ++ ++#if 0 ++void mac_reg_dump(_adapter *padapter) ++{ ++ int i,j=1; ++ DBG_871X("\n======= MAC REG =======\n"); ++ for(i=0x0;i<0x300;i+=4) ++ { ++ if(j%4==1) DBG_871X("0x%02x",i); ++ DBG_871X(" 0x%08x ",rtw_read32(padapter,i)); ++ if((j++)%4 == 0) DBG_871X("\n"); ++ } ++ for(i=0x400;i<0x800;i+=4) ++ { ++ if(j%4==1) DBG_871X("0x%02x",i); ++ DBG_871X(" 0x%08x ",rtw_read32(padapter,i)); ++ if((j++)%4 == 0) DBG_871X("\n"); ++ } ++} ++void bb_reg_dump(_adapter *padapter) ++{ ++ int i,j=1; ++ DBG_871X("\n======= BB REG =======\n"); ++ for(i=0x800;i<0x1000;i+=4) ++ { ++ if(j%4==1) DBG_871X("0x%02x",i); ++ ++ DBG_871X(" 0x%08x ",rtw_read32(padapter,i)); ++ if((j++)%4 == 0) DBG_871X("\n"); ++ } ++} ++void rf_reg_dump(_adapter *padapter) ++{ ++ int i,j=1,path; ++ u32 value; ++ DBG_871X("\n======= RF REG =======\n"); ++ for(path=0;path<2;path++) ++ { ++ DBG_871X("\nRF_Path(%x)\n",path); ++ for(i=0;i<0x100;i++) ++ { ++ value = PHY_QueryRFReg(padapter, (RF_RADIO_PATH_E)path,i, bMaskDWord); ++ if(j%4==1) DBG_871X("0x%02x ",i); ++ DBG_871X(" 0x%08x ",value); ++ if((j++)%4==0) DBG_871X("\n"); ++ } ++ } ++} ++ ++#endif ++ ++void mac_reg_dump(_adapter *padapter) ++{ ++ int i,j=1; ++ printk("\n======= MAC REG =======\n"); ++ for(i=0x0;i<0x300;i+=4) ++ { ++ if(j%4==1) printk("0x%02x",i); ++ printk(" 0x%08x ",rtw_read32(padapter,i)); ++ if((j++)%4 == 0) printk("\n"); ++ } ++ for(i=0x400;i<0x800;i+=4) ++ { ++ if(j%4==1) printk("0x%02x",i); ++ printk(" 0x%08x ",rtw_read32(padapter,i)); ++ if((j++)%4 == 0) printk("\n"); ++ } ++} ++void bb_reg_dump(_adapter *padapter) ++{ ++ int i,j=1; ++ printk("\n======= BB REG =======\n"); ++ for(i=0x800;i<0x1000;i+=4) ++ { ++ if(j%4==1) printk("0x%02x",i); ++ ++ printk(" 0x%08x ",rtw_read32(padapter,i)); ++ if((j++)%4 == 0) printk("\n"); ++ } ++} ++void rf_reg_dump(_adapter *padapter) ++{ ++ int i,j=1,path; ++ u32 value; ++ u8 rf_type,path_nums = 0; ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ ++ printk("\n======= RF REG =======\n"); ++ if((RF_1T2R == rf_type) ||(RF_1T1R ==rf_type )) ++ path_nums = 1; ++ else ++ path_nums = 2; ++ ++ for(path=0;path ++#endif ++static int rtw_dbg_port(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ _irqL irqL; ++ int ret = 0; ++ u8 major_cmd, minor_cmd; ++ u16 arg; ++ u32 extra_arg, *pdata, val32; ++ struct sta_info *psta; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct wlan_network *cur_network = &(pmlmepriv->cur_network); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ ++ pdata = (u32*)&wrqu->data; ++ ++ val32 = *pdata; ++ arg = (u16)(val32&0x0000ffff); ++ major_cmd = (u8)(val32>>24); ++ minor_cmd = (u8)((val32>>16)&0x00ff); ++ ++ extra_arg = *(pdata+1); ++ ++ switch(major_cmd) ++ { ++ case 0x70://read_reg ++ switch(minor_cmd) ++ { ++ case 1: ++ DBG_871X("rtw_read8(0x%x)=0x%02x\n", arg, rtw_read8(padapter, arg)); ++ break; ++ case 2: ++ DBG_871X("rtw_read16(0x%x)=0x%04x\n", arg, rtw_read16(padapter, arg)); ++ break; ++ case 4: ++ DBG_871X("rtw_read32(0x%x)=0x%08x\n", arg, rtw_read32(padapter, arg)); ++ break; ++ } ++ break; ++ case 0x71://write_reg ++ switch(minor_cmd) ++ { ++ case 1: ++ rtw_write8(padapter, arg, extra_arg); ++ DBG_871X("rtw_write8(0x%x)=0x%02x\n", arg, rtw_read8(padapter, arg)); ++ break; ++ case 2: ++ rtw_write16(padapter, arg, extra_arg); ++ DBG_871X("rtw_write16(0x%x)=0x%04x\n", arg, rtw_read16(padapter, arg)); ++ break; ++ case 4: ++ rtw_write32(padapter, arg, extra_arg); ++ DBG_871X("rtw_write32(0x%x)=0x%08x\n", arg, rtw_read32(padapter, arg)); ++ break; ++ } ++ break; ++ case 0x72://read_bb ++ DBG_871X("read_bbreg(0x%x)=0x%x\n", arg, rtw_hal_read_bbreg(padapter, arg, 0xffffffff)); ++ break; ++ case 0x73://write_bb ++ rtw_hal_write_bbreg(padapter, arg, 0xffffffff, extra_arg); ++ DBG_871X("write_bbreg(0x%x)=0x%x\n", arg, rtw_hal_read_bbreg(padapter, arg, 0xffffffff)); ++ break; ++ case 0x74://read_rf ++ DBG_871X("read RF_reg path(0x%02x),offset(0x%x),value(0x%08x)\n",minor_cmd,arg,rtw_hal_read_rfreg(padapter, minor_cmd, arg, 0xffffffff)); ++ break; ++ case 0x75://write_rf ++ rtw_hal_write_rfreg(padapter, minor_cmd, arg, 0xffffffff, extra_arg); ++ DBG_871X("write RF_reg path(0x%02x),offset(0x%x),value(0x%08x)\n",minor_cmd,arg, rtw_hal_read_rfreg(padapter, minor_cmd, arg, 0xffffffff)); ++ break; ++ ++ case 0x76: ++ switch(minor_cmd) ++ { ++ case 0x00: //normal mode, ++ padapter->recvpriv.is_signal_dbg = 0; ++ break; ++ case 0x01: //dbg mode ++ padapter->recvpriv.is_signal_dbg = 1; ++ extra_arg = extra_arg>100?100:extra_arg; ++ extra_arg = extra_arg<0?0:extra_arg; ++ padapter->recvpriv.signal_strength_dbg=extra_arg; ++ break; ++ } ++ break; ++ case 0x78: //IOL test ++ switch(minor_cmd) ++ { ++ #ifdef CONFIG_IOL ++ case 0x04: //LLT table initialization test ++ { ++ u8 page_boundary = 0xf9; ++ { ++ struct xmit_frame *xmit_frame; ++ ++ if((xmit_frame=rtw_IOL_accquire_xmit_frame(padapter)) == NULL) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ rtw_IOL_append_LLT_cmd(xmit_frame, page_boundary); ++ ++ ++ if(_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 500,0) ) ++ ret = -EPERM; ++ } ++ } ++ break; ++ case 0x05: //blink LED test ++ { ++ u16 reg = 0x4c; ++ u32 blink_num = 50; ++ u32 blink_delay_ms = 200; ++ int i; ++ ++ { ++ struct xmit_frame *xmit_frame; ++ ++ if((xmit_frame=rtw_IOL_accquire_xmit_frame(padapter)) == NULL) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ for(i=0;inetwork.MacAddress ++ , WLAN_REASON_EXPIRATION_CHK); ++ break; ++ case 0x7F: ++ switch(minor_cmd) ++ { ++ case 0x0: ++ DBG_871X("fwstate=0x%x\n", get_fwstate(pmlmepriv)); ++ break; ++ case 0x01: ++ DBG_871X("auth_alg=0x%x, enc_alg=0x%x, auth_type=0x%x, enc_type=0x%x\n", ++ psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm, ++ psecuritypriv->ndisauthtype, psecuritypriv->ndisencryptstatus); ++ break; ++ case 0x02: ++ DBG_871X("pmlmeinfo->state=0x%x\n", pmlmeinfo->state); ++ break; ++ case 0x03: ++ DBG_871X("qos_option=%d\n", pmlmepriv->qospriv.qos_option); ++#ifdef CONFIG_80211N_HT ++ DBG_871X("ht_option=%d\n", pmlmepriv->htpriv.ht_option); ++#endif //CONFIG_80211N_HT ++ break; ++ case 0x04: ++ DBG_871X("cur_ch=%d\n", pmlmeext->cur_channel); ++ DBG_871X("cur_bw=%d\n", pmlmeext->cur_bwmode); ++ DBG_871X("cur_ch_off=%d\n", pmlmeext->cur_ch_offset); ++ break; ++ case 0x05: ++ psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress); ++ if(psta) ++ { ++ int i; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ ++ DBG_871X("SSID=%s\n", cur_network->network.Ssid.Ssid); ++ DBG_871X("sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr)); ++ DBG_871X("cur_channel=%d, cur_bwmode=%d, cur_ch_offset=%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); ++ DBG_871X("rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self); ++ DBG_871X("state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); ++#ifdef CONFIG_80211N_HT ++ DBG_871X("qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); ++ DBG_871X("bwmode=%d, ch_offset=%d, sgi=%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi); ++ DBG_871X("ampdu_enable = %d\n", psta->htpriv.ampdu_enable); ++ DBG_871X("agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); ++#endif //CONFIG_80211N_HT ++ ++ for(i=0;i<16;i++) ++ { ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ if(preorder_ctrl->enable) ++ { ++ DBG_871X("tid=%d, indicate_seq=%d\n", i, preorder_ctrl->indicate_seq); ++ } ++ } ++ ++ } ++ else ++ { ++ DBG_871X("can't get sta's macaddr, cur_network's macaddr:" MAC_FMT "\n", MAC_ARG(cur_network->network.MacAddress)); ++ } ++ break; ++ case 0x06: ++ { ++ u32 ODMFlag; ++ rtw_hal_get_hwreg(padapter, HW_VAR_DM_FLAG, (u8*)(&ODMFlag)); ++ DBG_871X("(B)DMFlag=0x%x, arg=0x%x\n", ODMFlag, arg); ++ ODMFlag = (u32)(0x0f&arg); ++ DBG_871X("(A)DMFlag=0x%x\n", ODMFlag); ++ rtw_hal_set_hwreg(padapter, HW_VAR_DM_FLAG, (u8 *)(&ODMFlag)); ++ } ++ break; ++ case 0x07: ++ DBG_871X("bSurpriseRemoved=%d, bDriverStopped=%d\n", ++ padapter->bSurpriseRemoved, padapter->bDriverStopped); ++ break; ++ case 0x08: ++ { ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++ DBG_871X("free_xmitbuf_cnt=%d, free_xmitframe_cnt=%d" ++ ", free_xmit_extbuf_cnt=%d, free_xframe_ext_cnt=%d" ++ ", free_recvframe_cnt=%d\n", ++ pxmitpriv->free_xmitbuf_cnt, pxmitpriv->free_xmitframe_cnt, ++ pxmitpriv->free_xmit_extbuf_cnt, pxmitpriv->free_xframe_ext_cnt, ++ precvpriv->free_recvframe_cnt); ++ #ifdef CONFIG_USB_HCI ++ DBG_871X("rx_urb_pending_cn=%d\n", precvpriv->rx_pending_cnt); ++ #endif ++ } ++ break; ++ case 0x09: ++ { ++ int i, j; ++ _list *plist, *phead; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ ++#ifdef CONFIG_AP_MODE ++ DBG_871X("sta_dz_bitmap=0x%x, tim_bitmap=0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap); ++#endif ++ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ ++ for(i=0; i< NUM_STA; i++) ++ { ++ phead = &(pstapriv->sta_hash[i]); ++ plist = get_next(phead); ++ ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); ++ ++ plist = get_next(plist); ++ ++ if(extra_arg == psta->aid) ++ { ++ DBG_871X("sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr)); ++ DBG_871X("rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self); ++ DBG_871X("state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); ++#ifdef CONFIG_80211N_HT ++ DBG_871X("qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); ++ DBG_871X("bwmode=%d, ch_offset=%d, sgi=%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi); ++ DBG_871X("ampdu_enable = %d\n", psta->htpriv.ampdu_enable); ++ DBG_871X("agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); ++#endif //CONFIG_80211N_HT ++ ++#ifdef CONFIG_AP_MODE ++ DBG_871X("capability=0x%x\n", psta->capability); ++ DBG_871X("flags=0x%x\n", psta->flags); ++ DBG_871X("wpa_psk=0x%x\n", psta->wpa_psk); ++ DBG_871X("wpa2_group_cipher=0x%x\n", psta->wpa2_group_cipher); ++ DBG_871X("wpa2_pairwise_cipher=0x%x\n", psta->wpa2_pairwise_cipher); ++ DBG_871X("qos_info=0x%x\n", psta->qos_info); ++#endif ++ DBG_871X("dot118021XPrivacy=0x%x\n", psta->dot118021XPrivacy); ++ ++ ++ ++ for(j=0;j<16;j++) ++ { ++ preorder_ctrl = &psta->recvreorder_ctrl[j]; ++ if(preorder_ctrl->enable) ++ { ++ DBG_871X("tid=%d, indicate_seq=%d\n", j, preorder_ctrl->indicate_seq); ++ } ++ } ++ ++ } ++ ++ } ++ } ++ ++ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ ++ } ++ break; ++ case 0x0a: ++ { ++ #ifdef DBG_TRX_STA_PKTS ++ int i, j; ++ _list *plist, *phead; ++ ++ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ ++ for(i=0; i< NUM_STA; i++) ++ { ++ phead = &(pstapriv->sta_hash[i]); ++ plist = get_next(phead); ++ ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); ++ ++ plist = get_next(plist); ++ if(arg == 0xff){ ++ psta->rx_bk_cnt =0; ++ psta->rx_be_cnt =0; ++ psta->rx_vo_cnt =0; ++ psta->rx_vi_cnt =0; ++ psta->tx_bk_cnt =0; ++ psta->tx_be_cnt =0; ++ psta->tx_vo_cnt =0; ++ psta->tx_vi_cnt =0; ++ } ++ else{ ++ if(extra_arg == psta->mac_id) ++ { ++ DBG_871X("=== sta's macaddr:" MAC_FMT "===\n", MAC_ARG(psta->hwaddr)); ++ DBG_871X("rx_bk_cnt =%d\n", psta->rx_bk_cnt); ++ DBG_871X("rx_be_cnt =%d\n", psta->rx_be_cnt); ++ DBG_871X("rx_vo_cnt =%d\n", psta->rx_vo_cnt); ++ DBG_871X("rx_vi_cnt =%d\n\n", psta->rx_vi_cnt); ++ ++ DBG_871X("tx_bk_cnt =%d\n", psta->tx_bk_cnt); ++ DBG_871X("tx_be_cnt =%d\n", psta->tx_be_cnt); ++ DBG_871X("tx_vo_cnt =%d\n", psta->tx_vo_cnt); ++ DBG_871X("tx_vi_cnt =%dn\n", psta->tx_vi_cnt); ++ } ++ } ++ ++ } ++ } ++ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ #endif ++ } ++ break; ++ ++ case 0x0c://dump rx/tx packet ++ { ++ if(arg == 0){ ++ DBG_871X("dump rx packet (%d)\n",extra_arg); ++ //pHalData->bDumpRxPkt =extra_arg; ++ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DUMP_RXPKT, &(extra_arg)); ++ } ++ else if(arg==1){ ++ DBG_871X("dump tx packet (%d)\n",extra_arg); ++ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DUMP_TXPKT, &(extra_arg)); ++ } ++ } ++ break; ++#if 0 ++ case 0x0d://dump cam ++ { ++ //u8 entry = (u8) extra_arg; ++ u8 entry=0; ++ //dump cam ++ for(entry=0;entry<32;entry++) ++ read_cam(padapter,entry); ++ } ++ break; ++#endif ++ #ifdef DBG_CONFIG_ERROR_DETECT ++ case 0x0f: ++ { ++ if(extra_arg == 0){ ++ DBG_871X("###### silent reset test.......#####\n"); ++ rtw_hal_sreset_reset(padapter); ++ } else { ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct sreset_priv *psrtpriv = &pHalData->srestpriv; ++ psrtpriv->dbg_trigger_point = extra_arg; ++ } ++ ++ } ++ break; ++ case 0x15: ++ { ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ DBG_871X("==>silent resete cnts:%d\n",pwrpriv->ips_enter_cnts); ++ } ++ break; ++ ++ #endif ++ ++ case 0x10:// driver version display ++ DBG_871X("rtw driver version=%s\n", DRIVERVERSION); ++ break; ++ case 0x11: ++ { ++ DBG_871X("turn %s Rx RSSI display function\n",(extra_arg==1)?"on":"off"); ++ padapter->bRxRSSIDisplay = extra_arg; ++ rtw_hal_set_def_var(padapter, HW_DEF_FA_CNT_DUMP, &(padapter->bRxRSSIDisplay)); ++ } ++ break; ++ case 0x12: //set rx_stbc ++ { ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ // 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, 0x3: enable both 2.4g and 5g ++ //default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ ++ if( pregpriv && (extra_arg == 0 || extra_arg == 1|| extra_arg == 2 || extra_arg == 3)) ++ { ++ pregpriv->rx_stbc= extra_arg; ++ DBG_871X("set rx_stbc=%d\n",pregpriv->rx_stbc); ++ } ++ else ++ DBG_871X("get rx_stbc=%d\n",pregpriv->rx_stbc); ++ ++ } ++ break; ++ case 0x13: //set ampdu_enable ++ { ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ // 0: disable, 0x1:enable (but wifi_spec should be 0), 0x2: force enable (don't care wifi_spec) ++ if( pregpriv && extra_arg >= 0 && extra_arg < 3 ) ++ { ++ pregpriv->ampdu_enable= extra_arg; ++ DBG_871X("set ampdu_enable=%d\n",pregpriv->ampdu_enable); ++ } ++ else ++ DBG_871X("get ampdu_enable=%d\n",pregpriv->ampdu_enable); ++ ++ } ++ break; ++ case 0x14: //get wifi_spec ++ { ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ DBG_871X("get wifi_spec=%d\n",pregpriv->wifi_spec); ++ ++ } ++ break; ++ case 0x16: ++ { ++ if(arg == 0xff){ ++ rtw_odm_dbg_comp_msg(padapter); ++ } ++ else{ ++ u64 dbg_comp = (u64)extra_arg; ++ rtw_odm_dbg_comp_set(padapter, dbg_comp); ++ } ++ } ++ break; ++#ifdef DBG_FIXED_CHAN ++ case 0x17: ++ { ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ printk("===> Fixed channel to %d \n",extra_arg); ++ pmlmeext->fixed_chan = extra_arg; ++ ++ } ++ break; ++#endif ++ case 0x20: ++ { ++ rtw_hal_get_hwreg(padapter, HW_VAR_READ_LLT_TAB,(u8 *)&extra_arg); ++ } ++ break; ++ case 0x23: ++ { ++ DBG_871X("turn %s the bNotifyChannelChange Variable\n",(extra_arg==1)?"on":"off"); ++ padapter->bNotifyChannelChange = extra_arg; ++ break; ++ } ++ case 0x24: ++ { ++#ifdef CONFIG_P2P ++ DBG_871X("turn %s the bShowGetP2PState Variable\n",(extra_arg==1)?"on":"off"); ++ padapter->bShowGetP2PState = extra_arg; ++#endif // CONFIG_P2P ++ break; ++ } ++ case 0xaa: ++ { ++ if(extra_arg> 0x13) extra_arg = 0xFF; ++ DBG_871X("chang data rate to :0x%02x\n",extra_arg); ++ padapter->fix_rate = extra_arg; ++ } ++ break; ++ case 0xdd://registers dump , 0 for mac reg,1 for bb reg, 2 for rf reg ++ { ++ if(extra_arg==0){ ++ mac_reg_dump(padapter); ++ } ++ else if(extra_arg==1){ ++ bb_reg_dump(padapter); ++ } ++ else if(extra_arg==2){ ++ rf_reg_dump(padapter); ++ } ++ ++ } ++ break; ++ ++ case 0xee://turn on/off dynamic funcs ++ { ++ u32 odm_flag; ++ ++ if(0xf==extra_arg){ ++ rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC,&odm_flag); ++ DBG_871X(" === DMFlag(0x%08x) === \n",odm_flag); ++ DBG_871X("extra_arg = 0 - disable all dynamic func \n"); ++ DBG_871X("extra_arg = 1 - disable DIG- BIT(0)\n"); ++ DBG_871X("extra_arg = 2 - disable High power - BIT(1)\n"); ++ DBG_871X("extra_arg = 3 - disable tx power tracking - BIT(2)\n"); ++ DBG_871X("extra_arg = 4 - disable BT coexistence - BIT(3)\n"); ++ DBG_871X("extra_arg = 5 - disable antenna diversity - BIT(4)\n"); ++ DBG_871X("extra_arg = 6 - enable all dynamic func \n"); ++ } ++ else{ ++ /* extra_arg = 0 - disable all dynamic func ++ extra_arg = 1 - disable DIG ++ extra_arg = 2 - disable tx power tracking ++ extra_arg = 3 - turn on all dynamic func ++ */ ++ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &(extra_arg)); ++ rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC,&odm_flag); ++ DBG_871X(" === DMFlag(0x%08x) === \n",odm_flag); ++ } ++ } ++ break; ++ ++ case 0xfd: ++ rtw_write8(padapter, 0xc50, arg); ++ DBG_871X("wr(0xc50)=0x%x\n", rtw_read8(padapter, 0xc50)); ++ rtw_write8(padapter, 0xc58, arg); ++ DBG_871X("wr(0xc58)=0x%x\n", rtw_read8(padapter, 0xc58)); ++ break; ++ case 0xfe: ++ DBG_871X("rd(0xc50)=0x%x\n", rtw_read8(padapter, 0xc50)); ++ DBG_871X("rd(0xc58)=0x%x\n", rtw_read8(padapter, 0xc58)); ++ break; ++ case 0xff: ++ { ++ DBG_871X("dbg(0x210)=0x%x\n", rtw_read32(padapter, 0x210)); ++ DBG_871X("dbg(0x608)=0x%x\n", rtw_read32(padapter, 0x608)); ++ DBG_871X("dbg(0x280)=0x%x\n", rtw_read32(padapter, 0x280)); ++ DBG_871X("dbg(0x284)=0x%x\n", rtw_read32(padapter, 0x284)); ++ DBG_871X("dbg(0x288)=0x%x\n", rtw_read32(padapter, 0x288)); ++ ++ DBG_871X("dbg(0x664)=0x%x\n", rtw_read32(padapter, 0x664)); ++ ++ ++ DBG_871X("\n"); ++ ++ DBG_871X("dbg(0x430)=0x%x\n", rtw_read32(padapter, 0x430)); ++ DBG_871X("dbg(0x438)=0x%x\n", rtw_read32(padapter, 0x438)); ++ ++ DBG_871X("dbg(0x440)=0x%x\n", rtw_read32(padapter, 0x440)); ++ ++ DBG_871X("dbg(0x458)=0x%x\n", rtw_read32(padapter, 0x458)); ++ ++ DBG_871X("dbg(0x484)=0x%x\n", rtw_read32(padapter, 0x484)); ++ DBG_871X("dbg(0x488)=0x%x\n", rtw_read32(padapter, 0x488)); ++ ++ DBG_871X("dbg(0x444)=0x%x\n", rtw_read32(padapter, 0x444)); ++ DBG_871X("dbg(0x448)=0x%x\n", rtw_read32(padapter, 0x448)); ++ DBG_871X("dbg(0x44c)=0x%x\n", rtw_read32(padapter, 0x44c)); ++ DBG_871X("dbg(0x450)=0x%x\n", rtw_read32(padapter, 0x450)); ++ } ++ break; ++ } ++ break; ++ default: ++ DBG_871X("error dbg cmd!\n"); ++ break; ++ } ++ ++ ++ return ret; ++ ++} ++ ++static int wpa_set_param(struct net_device *dev, u8 name, u32 value) ++{ ++ uint ret=0; ++ u32 flags; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ switch (name){ ++ case IEEE_PARAM_WPA_ENABLED: ++ ++ padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_8021X; //802.1x ++ ++ //ret = ieee80211_wpa_enable(ieee, value); ++ ++ switch((value)&0xff) ++ { ++ case 1 : //WPA ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK; //WPA_PSK ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; ++ break; ++ case 2: //WPA2 ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK; //WPA2_PSK ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; ++ break; ++ } ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c,_drv_info_,("wpa_set_param:padapter->securitypriv.ndisauthtype=%d\n", padapter->securitypriv.ndisauthtype)); ++ ++ break; ++ ++ case IEEE_PARAM_TKIP_COUNTERMEASURES: ++ //ieee->tkip_countermeasures=value; ++ break; ++ ++ case IEEE_PARAM_DROP_UNENCRYPTED: ++ { ++ /* HACK: ++ * ++ * wpa_supplicant calls set_wpa_enabled when the driver ++ * is loaded and unloaded, regardless of if WPA is being ++ * used. No other calls are made which can be used to ++ * determine if encryption will be used or not prior to ++ * association being expected. If encryption is not being ++ * used, drop_unencrypted is set to false, else true -- we ++ * can use this to determine if the CAP_PRIVACY_ON bit should ++ * be set. ++ */ ++ ++#if 0 ++ struct ieee80211_security sec = { ++ .flags = SEC_ENABLED, ++ .enabled = value, ++ }; ++ ieee->drop_unencrypted = value; ++ /* We only change SEC_LEVEL for open mode. Others ++ * are set by ipw_wpa_set_encryption. ++ */ ++ if (!value) { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_0; ++ } ++ else { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_1; ++ } ++ if (ieee->set_security) ++ ieee->set_security(ieee->dev, &sec); ++#endif ++ break; ++ ++ } ++ case IEEE_PARAM_PRIVACY_INVOKED: ++ ++ //ieee->privacy_invoked=value; ++ ++ break; ++ ++ case IEEE_PARAM_AUTH_ALGS: ++ ++ ret = wpa_set_auth_algs(dev, value); ++ ++ break; ++ ++ case IEEE_PARAM_IEEE_802_1X: ++ ++ //ieee->ieee802_1x=value; ++ ++ break; ++ ++ case IEEE_PARAM_WPAX_SELECT: ++ ++ // added for WPA2 mixed mode ++ //DBG_871X(KERN_WARNING "------------------------>wpax value = %x\n", value); ++ /* ++ spin_lock_irqsave(&ieee->wpax_suitlist_lock,flags); ++ ieee->wpax_type_set = 1; ++ ieee->wpax_type_notify = value; ++ spin_unlock_irqrestore(&ieee->wpax_suitlist_lock,flags); ++ */ ++ ++ break; ++ ++ default: ++ ++ ++ ++ ret = -EOPNOTSUPP; ++ ++ ++ break; ++ ++ } ++ ++ return ret; ++ ++} ++ ++static int wpa_mlme(struct net_device *dev, u32 command, u32 reason) ++{ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ switch (command) ++ { ++ case IEEE_MLME_STA_DEAUTH: ++ ++ if(!rtw_set_802_11_disassociate(padapter)) ++ ret = -1; ++ ++ break; ++ ++ case IEEE_MLME_STA_DISASSOC: ++ ++ if(!rtw_set_802_11_disassociate(padapter)) ++ ret = -1; ++ ++ break; ++ ++ default: ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ return ret; ++ ++} ++ ++static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p) ++{ ++ struct ieee_param *param; ++ uint ret=0; ++ ++ //down(&ieee->wx_sem); ++ ++ if (p->length < sizeof(struct ieee_param) || !p->pointer){ ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ param = (struct ieee_param *)rtw_malloc(p->length); ++ if (param == NULL) ++ { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ if (copy_from_user(param, p->pointer, p->length)) ++ { ++ rtw_mfree((u8*)param, p->length); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ switch (param->cmd) { ++ ++ case IEEE_CMD_SET_WPA_PARAM: ++ ret = wpa_set_param(dev, param->u.wpa_param.name, param->u.wpa_param.value); ++ break; ++ ++ case IEEE_CMD_SET_WPA_IE: ++ //ret = wpa_set_wpa_ie(dev, param, p->length); ++ ret = rtw_set_wpa_ie((_adapter *)rtw_netdev_priv(dev), (char*)param->u.wpa_ie.data, (u16)param->u.wpa_ie.len); ++ break; ++ ++ case IEEE_CMD_SET_ENCRYPTION: ++ ret = wpa_set_encryption(dev, param, p->length); ++ break; ++ ++ case IEEE_CMD_MLME: ++ ret = wpa_mlme(dev, param->u.mlme.command, param->u.mlme.reason_code); ++ break; ++ ++ default: ++ DBG_871X("Unknown WPA supplicant request: %d\n", param->cmd); ++ ret = -EOPNOTSUPP; ++ break; ++ ++ } ++ ++ if (ret == 0 && copy_to_user(p->pointer, param, p->length)) ++ ret = -EFAULT; ++ ++ rtw_mfree((u8 *)param, p->length); ++ ++out: ++ ++ //up(&ieee->wx_sem); ++ ++ return ret; ++ ++} ++ ++#ifdef CONFIG_AP_MODE ++static u8 set_pairwise_key(_adapter *padapter, struct sta_info *psta) ++{ ++ struct cmd_obj* ph2c; ++ struct set_stakey_parm *psetstakey_para; ++ struct cmd_priv *pcmdpriv=&padapter->cmdpriv; ++ u8 res=_SUCCESS; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if ( ph2c == NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ ++ psetstakey_para = (struct set_stakey_parm*)rtw_zmalloc(sizeof(struct set_stakey_parm)); ++ if(psetstakey_para==NULL){ ++ rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); ++ res=_FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); ++ ++ ++ psetstakey_para->algorithm = (u8)psta->dot118021XPrivacy; ++ ++ _rtw_memcpy(psetstakey_para->addr, psta->hwaddr, ETH_ALEN); ++ ++ _rtw_memcpy(psetstakey_para->key, &psta->dot118021x_UncstKey, 16); ++ ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ return res; ++ ++} ++ ++static int set_group_key(_adapter *padapter, u8 *key, u8 alg, int keyid) ++{ ++ u8 keylen; ++ struct cmd_obj* pcmd; ++ struct setkey_parm *psetkeyparm; ++ struct cmd_priv *pcmdpriv=&(padapter->cmdpriv); ++ int res=_SUCCESS; ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ pcmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if(pcmd==NULL){ ++ res= _FAIL; ++ goto exit; ++ } ++ psetkeyparm=(struct setkey_parm*)rtw_zmalloc(sizeof(struct setkey_parm)); ++ if(psetkeyparm==NULL){ ++ rtw_mfree((unsigned char *)pcmd, sizeof(struct cmd_obj)); ++ res= _FAIL; ++ goto exit; ++ } ++ ++ _rtw_memset(psetkeyparm, 0, sizeof(struct setkey_parm)); ++ ++ psetkeyparm->keyid=(u8)keyid; ++ if (is_wep_enc(alg)) ++ padapter->securitypriv.key_mask |= BIT(psetkeyparm->keyid); ++ psetkeyparm->algorithm = alg; ++ ++ psetkeyparm->set_tx = 1; ++ ++ switch(alg) ++ { ++ case _WEP40_: ++ keylen = 5; ++ break; ++ case _WEP104_: ++ keylen = 13; ++ break; ++ case _TKIP_: ++ case _TKIP_WTMIC_: ++ case _AES_: ++ keylen = 16; ++ default: ++ keylen = 16; ++ } ++ ++ _rtw_memcpy(&(psetkeyparm->key[0]), key, keylen); ++ ++ pcmd->cmdcode = _SetKey_CMD_; ++ pcmd->parmbuf = (u8 *)psetkeyparm; ++ pcmd->cmdsz = (sizeof(struct setkey_parm)); ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ ++ ++ _rtw_init_listhead(&pcmd->list); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++ ++exit: ++ ++ return res; ++ ++ ++} ++ ++static int set_wep_key(_adapter *padapter, u8 *key, u8 keylen, int keyid) ++{ ++ u8 alg; ++ ++ switch(keylen) ++ { ++ case 5: ++ alg =_WEP40_; ++ break; ++ case 13: ++ alg =_WEP104_; ++ break; ++ default: ++ alg =_NO_PRIVACY_; ++ } ++ ++ return set_group_key(padapter, key, alg, keyid); ++ ++} ++ ++ ++static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len) ++{ ++ int ret = 0; ++ u32 wep_key_idx, wep_key_len,wep_total_len; ++ NDIS_802_11_WEP *pwep = NULL; ++ struct sta_info *psta = NULL, *pbcmc_sta = NULL; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv* psecuritypriv=&(padapter->securitypriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ param->u.crypt.err = 0; ++ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; ++ ++ //sizeof(struct ieee_param) = 64 bytes; ++ //if (param_len != (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) ++ if (param_len != sizeof(struct ieee_param) + param->u.crypt.key_len) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && ++ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && ++ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) ++ { ++ if (param->u.crypt.idx >= WEP_KEYS) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } ++ else ++ { ++ psta = rtw_get_stainfo(pstapriv, param->sta_addr); ++ if(!psta) ++ { ++ //ret = -EINVAL; ++ DBG_871X("rtw_set_encryption(), sta has already been removed or never been added\n"); ++ goto exit; ++ } ++ } ++ ++ if (strcmp(param->u.crypt.alg, "none") == 0 && (psta==NULL)) ++ { ++ //todo:clear default encryption keys ++ ++ DBG_871X("clear default encryption keys, keyid=%d\n", param->u.crypt.idx); ++ ++ goto exit; ++ } ++ ++ ++ if (strcmp(param->u.crypt.alg, "WEP") == 0 && (psta==NULL)) ++ { ++ DBG_871X("r871x_set_encryption, crypt.alg = WEP\n"); ++ ++ wep_key_idx = param->u.crypt.idx; ++ wep_key_len = param->u.crypt.key_len; ++ ++ DBG_871X("r871x_set_encryption, wep_key_idx=%d, len=%d\n", wep_key_idx, wep_key_len); ++ ++ if((wep_key_idx >= WEP_KEYS) || (wep_key_len<=0)) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ ++ if (wep_key_len > 0) ++ { ++ wep_key_len = wep_key_len <= 5 ? 5 : 13; ++ wep_total_len = wep_key_len + FIELD_OFFSET(NDIS_802_11_WEP, KeyMaterial); ++ pwep =(NDIS_802_11_WEP *)rtw_malloc(wep_total_len); ++ if(pwep == NULL){ ++ DBG_871X(" r871x_set_encryption: pwep allocate fail !!!\n"); ++ goto exit; ++ } ++ ++ _rtw_memset(pwep, 0, wep_total_len); ++ ++ pwep->KeyLength = wep_key_len; ++ pwep->Length = wep_total_len; ++ ++ } ++ ++ pwep->KeyIndex = wep_key_idx; ++ ++ _rtw_memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength); ++ ++ if(param->u.crypt.set_tx) ++ { ++ DBG_871X("wep, set_tx=1\n"); ++ ++ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ psecuritypriv->dot11PrivacyAlgrthm=_WEP40_; ++ psecuritypriv->dot118021XGrpPrivacy=_WEP40_; ++ ++ if(pwep->KeyLength==13) ++ { ++ psecuritypriv->dot11PrivacyAlgrthm=_WEP104_; ++ psecuritypriv->dot118021XGrpPrivacy=_WEP104_; ++ } ++ ++ ++ psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx; ++ ++ _rtw_memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength); ++ ++ psecuritypriv->dot11DefKeylen[wep_key_idx]=pwep->KeyLength; ++ ++ set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx); ++ ++ ++ } ++ else ++ { ++ DBG_871X("wep, set_tx=0\n"); ++ ++ //don't update "psecuritypriv->dot11PrivacyAlgrthm" and ++ //"psecuritypriv->dot11PrivacyKeyIndex=keyid", but can rtw_set_key to cam ++ ++ _rtw_memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength); ++ ++ psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength; ++ ++ set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx); ++ ++ } ++ ++ goto exit; ++ ++ } ++ ++ ++ if(!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) // //group key ++ { ++ if(param->u.crypt.set_tx ==1) ++ { ++ if(strcmp(param->u.crypt.alg, "WEP") == 0) ++ { ++ DBG_871X("%s, set group_key, WEP\n", __FUNCTION__); ++ ++ _rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _WEP40_; ++ if(param->u.crypt.key_len==13) ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _WEP104_; ++ } ++ ++ } ++ else if(strcmp(param->u.crypt.alg, "TKIP") == 0) ++ { ++ DBG_871X("%s, set group_key, TKIP\n", __FUNCTION__); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _TKIP_; ++ ++ _rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ //DEBUG_ERR("set key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len); ++ //set mic key ++ _rtw_memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8); ++ _rtw_memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8); ++ ++ psecuritypriv->busetkipkey = _TRUE; ++ ++ } ++ else if(strcmp(param->u.crypt.alg, "CCMP") == 0) ++ { ++ DBG_871X("%s, set group_key, CCMP\n", __FUNCTION__); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _AES_; ++ ++ _rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ } ++ else ++ { ++ DBG_871X("%s, set group_key, none\n", __FUNCTION__); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ } ++ ++ psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx; ++ ++ psecuritypriv->binstallGrpkey = _TRUE; ++ ++ psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;//!!! ++ ++ set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx); ++ ++ pbcmc_sta=rtw_get_bcmc_stainfo(padapter); ++ if(pbcmc_sta) ++ { ++ pbcmc_sta->ieee8021x_blocked = _FALSE; ++ pbcmc_sta->dot118021XPrivacy= psecuritypriv->dot118021XGrpPrivacy;//rx will use bmc_sta's dot118021XPrivacy ++ } ++ ++ } ++ ++ goto exit; ++ ++ } ++ ++ if(psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) // psk/802_1x ++ { ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ { ++ if(param->u.crypt.set_tx ==1) ++ { ++ _rtw_memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ if(strcmp(param->u.crypt.alg, "WEP") == 0) ++ { ++ DBG_871X("%s, set pairwise key, WEP\n", __FUNCTION__); ++ ++ psta->dot118021XPrivacy = _WEP40_; ++ if(param->u.crypt.key_len==13) ++ { ++ psta->dot118021XPrivacy = _WEP104_; ++ } ++ } ++ else if(strcmp(param->u.crypt.alg, "TKIP") == 0) ++ { ++ DBG_871X("%s, set pairwise key, TKIP\n", __FUNCTION__); ++ ++ psta->dot118021XPrivacy = _TKIP_; ++ ++ //DEBUG_ERR("set key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len); ++ //set mic key ++ _rtw_memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8); ++ _rtw_memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8); ++ ++ psecuritypriv->busetkipkey = _TRUE; ++ ++ } ++ else if(strcmp(param->u.crypt.alg, "CCMP") == 0) ++ { ++ ++ DBG_871X("%s, set pairwise key, CCMP\n", __FUNCTION__); ++ ++ psta->dot118021XPrivacy = _AES_; ++ } ++ else ++ { ++ DBG_871X("%s, set pairwise key, none\n", __FUNCTION__); ++ ++ psta->dot118021XPrivacy = _NO_PRIVACY_; ++ } ++ ++ set_pairwise_key(padapter, psta); ++ ++ psta->ieee8021x_blocked = _FALSE; ++ ++ } ++ else//group key??? ++ { ++ if(strcmp(param->u.crypt.alg, "WEP") == 0) ++ { ++ _rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _WEP40_; ++ if(param->u.crypt.key_len==13) ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _WEP104_; ++ } ++ } ++ else if(strcmp(param->u.crypt.alg, "TKIP") == 0) ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _TKIP_; ++ ++ _rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ //DEBUG_ERR("set key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len); ++ //set mic key ++ _rtw_memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8); ++ _rtw_memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8); ++ ++ psecuritypriv->busetkipkey = _TRUE; ++ ++ } ++ else if(strcmp(param->u.crypt.alg, "CCMP") == 0) ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _AES_; ++ ++ _rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ } ++ else ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ } ++ ++ psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx; ++ ++ psecuritypriv->binstallGrpkey = _TRUE; ++ ++ psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;//!!! ++ ++ set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx); ++ ++ pbcmc_sta=rtw_get_bcmc_stainfo(padapter); ++ if(pbcmc_sta) ++ { ++ pbcmc_sta->ieee8021x_blocked = _FALSE; ++ pbcmc_sta->dot118021XPrivacy= psecuritypriv->dot118021XGrpPrivacy;//rx will use bmc_sta's dot118021XPrivacy ++ } ++ ++ } ++ ++ } ++ ++ } ++ ++exit: ++ ++ if(pwep) ++ { ++ rtw_mfree((u8 *)pwep, wep_total_len); ++ } ++ ++ return ret; ++ ++} ++ ++static int rtw_set_beacon(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret=0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ unsigned char *pbuf = param->u.bcn_ie.buf; ++ ++ ++ DBG_871X("%s, len=%d\n", __FUNCTION__, len); ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE) ++ return -EINVAL; ++ ++ _rtw_memcpy(&pstapriv->max_num_sta, param->u.bcn_ie.reserved, 2); ++ ++ if((pstapriv->max_num_sta>NUM_STA) || (pstapriv->max_num_sta<=0)) ++ pstapriv->max_num_sta = NUM_STA; ++ ++ ++ if(rtw_check_beacon_data(padapter, pbuf, (len-12-2)) == _SUCCESS)// 12 = param header, 2:no packed ++ ret = 0; ++ else ++ ret = -EINVAL; ++ ++ ++ return ret; ++ ++} ++ ++static int rtw_hostapd_sta_flush(struct net_device *dev) ++{ ++ //_irqL irqL; ++ //_list *phead, *plist; ++ int ret=0; ++ //struct sta_info *psta = NULL; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ //struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ flush_all_cam_entry(padapter); //clear CAM ++ ++ ret = rtw_sta_flush(padapter); ++ ++ return ret; ++ ++} ++ ++static int rtw_add_sta(struct net_device *dev, struct ieee_param *param) ++{ ++ _irqL irqL; ++ int ret=0; ++ struct sta_info *psta = NULL; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_871X("rtw_add_sta(aid=%d)=" MAC_FMT "\n", param->u.add_sta.aid, MAC_ARG(param->sta_addr)); ++ ++ if(check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != _TRUE) ++ { ++ return -EINVAL; ++ } ++ ++ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && ++ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && ++ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) ++ { ++ return -EINVAL; ++ } ++ ++/* ++ psta = rtw_get_stainfo(pstapriv, param->sta_addr); ++ if(psta) ++ { ++ DBG_871X("rtw_add_sta(), free has been added psta=%p\n", psta); ++ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ rtw_free_stainfo(padapter, psta); ++ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ ++ psta = NULL; ++ } ++*/ ++ //psta = rtw_alloc_stainfo(pstapriv, param->sta_addr); ++ psta = rtw_get_stainfo(pstapriv, param->sta_addr); ++ if(psta) ++ { ++ int flags = param->u.add_sta.flags; ++ ++ //DBG_871X("rtw_add_sta(), init sta's variables, psta=%p\n", psta); ++ ++ psta->aid = param->u.add_sta.aid;//aid=1~2007 ++ ++ _rtw_memcpy(psta->bssrateset, param->u.add_sta.tx_supp_rates, 16); ++ ++ ++ //check wmm cap. ++ if(WLAN_STA_WME&flags) ++ psta->qos_option = 1; ++ else ++ psta->qos_option = 0; ++ ++ if(pmlmepriv->qospriv.qos_option == 0) ++ psta->qos_option = 0; ++ ++ ++#ifdef CONFIG_80211N_HT ++ //chec 802.11n ht cap. ++ if(WLAN_STA_HT&flags) ++ { ++ psta->htpriv.ht_option = _TRUE; ++ psta->qos_option = 1; ++ _rtw_memcpy((void*)&psta->htpriv.ht_cap, (void*)¶m->u.add_sta.ht_cap, sizeof(struct rtw_ieee80211_ht_cap)); ++ } ++ else ++ { ++ psta->htpriv.ht_option = _FALSE; ++ } ++ ++ if(pmlmepriv->htpriv.ht_option == _FALSE) ++ psta->htpriv.ht_option = _FALSE; ++#endif ++ ++ ++ update_sta_info_apmode(padapter, psta); ++ ++ ++ } ++ else ++ { ++ ret = -ENOMEM; ++ } ++ ++ return ret; ++ ++} ++ ++static int rtw_del_sta(struct net_device *dev, struct ieee_param *param) ++{ ++ _irqL irqL; ++ int ret=0; ++ struct sta_info *psta = NULL; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_871X("rtw_del_sta=" MAC_FMT "\n", MAC_ARG(param->sta_addr)); ++ ++ if(check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != _TRUE) ++ { ++ return -EINVAL; ++ } ++ ++ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && ++ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && ++ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) ++ { ++ return -EINVAL; ++ } ++ ++ psta = rtw_get_stainfo(pstapriv, param->sta_addr); ++ if(psta) ++ { ++ u8 updated; ++ ++ //DBG_871X("free psta=%p, aid=%d\n", psta, psta->aid); ++ ++ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ if(rtw_is_list_empty(&psta->asoc_list)==_FALSE) ++ { ++ rtw_list_delete(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ updated = ap_free_sta(padapter, psta, _TRUE, WLAN_REASON_DEAUTH_LEAVING); ++ ++ } ++ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ associated_clients_update(padapter, updated); ++ ++ psta = NULL; ++ ++ } ++ else ++ { ++ DBG_871X("rtw_del_sta(), sta has already been removed or never been added\n"); ++ ++ //ret = -1; ++ } ++ ++ ++ return ret; ++ ++} ++ ++static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret=0; ++ struct sta_info *psta = NULL; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct ieee_param_ex *param_ex = (struct ieee_param_ex *)param; ++ struct sta_data *psta_data = (struct sta_data *)param_ex->data; ++ ++ DBG_871X("rtw_ioctl_get_sta_info, sta_addr: " MAC_FMT "\n", MAC_ARG(param_ex->sta_addr)); ++ ++ if(check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != _TRUE) ++ { ++ return -EINVAL; ++ } ++ ++ if (param_ex->sta_addr[0] == 0xff && param_ex->sta_addr[1] == 0xff && ++ param_ex->sta_addr[2] == 0xff && param_ex->sta_addr[3] == 0xff && ++ param_ex->sta_addr[4] == 0xff && param_ex->sta_addr[5] == 0xff) ++ { ++ return -EINVAL; ++ } ++ ++ psta = rtw_get_stainfo(pstapriv, param_ex->sta_addr); ++ if(psta) ++ { ++#if 0 ++ struct { ++ u16 aid; ++ u16 capability; ++ int flags; ++ u32 sta_set; ++ u8 tx_supp_rates[16]; ++ u32 tx_supp_rates_len; ++ struct rtw_ieee80211_ht_cap ht_cap; ++ u64 rx_pkts; ++ u64 rx_bytes; ++ u64 rx_drops; ++ u64 tx_pkts; ++ u64 tx_bytes; ++ u64 tx_drops; ++ } get_sta; ++#endif ++ psta_data->aid = (u16)psta->aid; ++ psta_data->capability = psta->capability; ++ psta_data->flags = psta->flags; ++ ++/* ++ nonerp_set : BIT(0) ++ no_short_slot_time_set : BIT(1) ++ no_short_preamble_set : BIT(2) ++ no_ht_gf_set : BIT(3) ++ no_ht_set : BIT(4) ++ ht_20mhz_set : BIT(5) ++*/ ++ ++ psta_data->sta_set =((psta->nonerp_set) | ++ (psta->no_short_slot_time_set <<1) | ++ (psta->no_short_preamble_set <<2) | ++ (psta->no_ht_gf_set <<3) | ++ (psta->no_ht_set <<4) | ++ (psta->ht_20mhz_set <<5)); ++ ++ psta_data->tx_supp_rates_len = psta->bssratelen; ++ _rtw_memcpy(psta_data->tx_supp_rates, psta->bssrateset, psta->bssratelen); ++#ifdef CONFIG_80211N_HT ++ _rtw_memcpy(&psta_data->ht_cap, &psta->htpriv.ht_cap, sizeof(struct rtw_ieee80211_ht_cap)); ++#endif //CONFIG_80211N_HT ++ psta_data->rx_pkts = psta->sta_stats.rx_data_pkts; ++ psta_data->rx_bytes = psta->sta_stats.rx_bytes; ++ psta_data->rx_drops = psta->sta_stats.rx_drops; ++ ++ psta_data->tx_pkts = psta->sta_stats.tx_pkts; ++ psta_data->tx_bytes = psta->sta_stats.tx_bytes; ++ psta_data->tx_drops = psta->sta_stats.tx_drops; ++ ++ ++ } ++ else ++ { ++ ret = -1; ++ } ++ ++ return ret; ++ ++} ++ ++static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param) ++{ ++ int ret=0; ++ struct sta_info *psta = NULL; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_871X("rtw_get_sta_wpaie, sta_addr: " MAC_FMT "\n", MAC_ARG(param->sta_addr)); ++ ++ if(check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != _TRUE) ++ { ++ return -EINVAL; ++ } ++ ++ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && ++ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && ++ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) ++ { ++ return -EINVAL; ++ } ++ ++ psta = rtw_get_stainfo(pstapriv, param->sta_addr); ++ if(psta) ++ { ++ if((psta->wpa_ie[0] == WLAN_EID_RSN) || (psta->wpa_ie[0] == WLAN_EID_GENERIC)) ++ { ++ int wpa_ie_len; ++ int copy_len; ++ ++ wpa_ie_len = psta->wpa_ie[1]; ++ ++ copy_len = ((wpa_ie_len+2) > sizeof(psta->wpa_ie)) ? (sizeof(psta->wpa_ie)):(wpa_ie_len+2); ++ ++ param->u.wpa_ie.len = copy_len; ++ ++ _rtw_memcpy(param->u.wpa_ie.reserved, psta->wpa_ie, copy_len); ++ } ++ else ++ { ++ //ret = -1; ++ DBG_871X("sta's wpa_ie is NONE\n"); ++ } ++ } ++ else ++ { ++ ret = -1; ++ } ++ ++ return ret; ++ ++} ++ ++static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret=0; ++ unsigned char wps_oui[4]={0x0,0x50,0xf2,0x04}; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ int ie_len; ++ ++ DBG_871X("%s, len=%d\n", __FUNCTION__, len); ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE) ++ return -EINVAL; ++ ++ ie_len = len-12-2;// 12 = param header, 2:no packed ++ ++ ++ if(pmlmepriv->wps_beacon_ie) ++ { ++ rtw_mfree(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len); ++ pmlmepriv->wps_beacon_ie = NULL; ++ } ++ ++ if(ie_len>0) ++ { ++ pmlmepriv->wps_beacon_ie = rtw_malloc(ie_len); ++ pmlmepriv->wps_beacon_ie_len = ie_len; ++ if ( pmlmepriv->wps_beacon_ie == NULL) { ++ DBG_871X("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ return -EINVAL; ++ } ++ ++ _rtw_memcpy(pmlmepriv->wps_beacon_ie, param->u.bcn_ie.buf, ie_len); ++ ++ update_beacon(padapter, _VENDOR_SPECIFIC_IE_, wps_oui, _TRUE); ++ ++ pmlmeext->bstart_bss = _TRUE; ++ ++ } ++ ++ ++ return ret; ++ ++} ++ ++static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret=0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ int ie_len; ++ ++ DBG_871X("%s, len=%d\n", __FUNCTION__, len); ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE) ++ return -EINVAL; ++ ++ ie_len = len-12-2;// 12 = param header, 2:no packed ++ ++ ++ if(pmlmepriv->wps_probe_resp_ie) ++ { ++ rtw_mfree(pmlmepriv->wps_probe_resp_ie, pmlmepriv->wps_probe_resp_ie_len); ++ pmlmepriv->wps_probe_resp_ie = NULL; ++ } ++ ++ if(ie_len>0) ++ { ++ pmlmepriv->wps_probe_resp_ie = rtw_malloc(ie_len); ++ pmlmepriv->wps_probe_resp_ie_len = ie_len; ++ if ( pmlmepriv->wps_probe_resp_ie == NULL) { ++ DBG_871X("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ return -EINVAL; ++ } ++ _rtw_memcpy(pmlmepriv->wps_probe_resp_ie, param->u.bcn_ie.buf, ie_len); ++ } ++ ++ ++ return ret; ++ ++} ++ ++static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret=0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ int ie_len; ++ ++ DBG_871X("%s, len=%d\n", __FUNCTION__, len); ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE) ++ return -EINVAL; ++ ++ ie_len = len-12-2;// 12 = param header, 2:no packed ++ ++ ++ if(pmlmepriv->wps_assoc_resp_ie) ++ { ++ rtw_mfree(pmlmepriv->wps_assoc_resp_ie, pmlmepriv->wps_assoc_resp_ie_len); ++ pmlmepriv->wps_assoc_resp_ie = NULL; ++ } ++ ++ if(ie_len>0) ++ { ++ pmlmepriv->wps_assoc_resp_ie = rtw_malloc(ie_len); ++ pmlmepriv->wps_assoc_resp_ie_len = ie_len; ++ if ( pmlmepriv->wps_assoc_resp_ie == NULL) { ++ DBG_871X("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ return -EINVAL; ++ } ++ ++ _rtw_memcpy(pmlmepriv->wps_assoc_resp_ie, param->u.bcn_ie.buf, ie_len); ++ } ++ ++ ++ return ret; ++ ++} ++ ++static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret=0; ++ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *mlmepriv = &(adapter->mlmepriv); ++ struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv); ++ struct mlme_ext_info *mlmeinfo = &(mlmeext->mlmext_info); ++ int ie_len; ++ u8 *ssid_ie; ++ char ssid[NDIS_802_11_LENGTH_SSID + 1]; ++ sint ssid_len; ++ u8 ignore_broadcast_ssid; ++ ++ if(check_fwstate(mlmepriv, WIFI_AP_STATE) != _TRUE) ++ return -EPERM; ++ ++ if (param->u.bcn_ie.reserved[0] != 0xea) ++ return -EINVAL; ++ ++ mlmeinfo->hidden_ssid_mode = ignore_broadcast_ssid = param->u.bcn_ie.reserved[1]; ++ ++ ie_len = len-12-2;// 12 = param header, 2:no packed ++ ssid_ie = rtw_get_ie(param->u.bcn_ie.buf, WLAN_EID_SSID, &ssid_len, ie_len); ++ ++ if (ssid_ie && ssid_len) { ++ WLAN_BSSID_EX *pbss_network = &mlmepriv->cur_network.network; ++ WLAN_BSSID_EX *pbss_network_ext = &mlmeinfo->network; ++ ++ _rtw_memcpy(ssid, ssid_ie+2, ssid_len); ++ ssid[ssid_len>NDIS_802_11_LENGTH_SSID?NDIS_802_11_LENGTH_SSID:ssid_len] = 0x0; ++ ++ if(0) ++ DBG_871X(FUNC_ADPT_FMT" ssid:(%s,%d), from ie:(%s,%d), (%s,%d)\n", FUNC_ADPT_ARG(adapter), ++ ssid, ssid_len, ++ pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength, ++ pbss_network_ext->Ssid.Ssid, pbss_network_ext->Ssid.SsidLength); ++ ++ _rtw_memcpy(pbss_network->Ssid.Ssid, (void *)ssid, ssid_len); ++ pbss_network->Ssid.SsidLength = ssid_len; ++ _rtw_memcpy(pbss_network_ext->Ssid.Ssid, (void *)ssid, ssid_len); ++ pbss_network_ext->Ssid.SsidLength = ssid_len; ++ ++ if(0) ++ DBG_871X(FUNC_ADPT_FMT" after ssid:(%s,%d), (%s,%d)\n", FUNC_ADPT_ARG(adapter), ++ pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength, ++ pbss_network_ext->Ssid.Ssid, pbss_network_ext->Ssid.SsidLength); ++ } ++ ++ DBG_871X(FUNC_ADPT_FMT" ignore_broadcast_ssid:%d, %s,%d\n", FUNC_ADPT_ARG(adapter), ++ ignore_broadcast_ssid, ssid, ssid_len); ++ ++ return ret; ++} ++ ++static int rtw_ioctl_acl_remove_sta(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret=0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE) ++ return -EINVAL; ++ ++ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && ++ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && ++ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) ++ { ++ return -EINVAL; ++ } ++ ++ ret = rtw_acl_remove_sta(padapter, param->sta_addr); ++ ++ return ret; ++ ++} ++ ++static int rtw_ioctl_acl_add_sta(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret=0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE) ++ return -EINVAL; ++ ++ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && ++ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && ++ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) ++ { ++ return -EINVAL; ++ } ++ ++ ret = rtw_acl_add_sta(padapter, param->sta_addr); ++ ++ return ret; ++ ++} ++ ++static int rtw_ioctl_set_macaddr_acl(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret=0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE) ++ return -EINVAL; ++ ++ rtw_set_macaddr_acl(padapter, param->u.mlme.command); ++ ++ return ret; ++} ++ ++static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p) ++{ ++ struct ieee_param *param; ++ int ret=0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ //DBG_871X("%s\n", __FUNCTION__); ++ ++ /* ++ * this function is expect to call in master mode, which allows no power saving ++ * so, we just check hw_init_completed ++ */ ++ ++ if (padapter->hw_init_completed==_FALSE){ ++ ret = -EPERM; ++ goto out; ++ } ++ ++ ++ //if (p->length < sizeof(struct ieee_param) || !p->pointer){ ++ if(!p->pointer){ ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ param = (struct ieee_param *)rtw_malloc(p->length); ++ if (param == NULL) ++ { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ if (copy_from_user(param, p->pointer, p->length)) ++ { ++ rtw_mfree((u8*)param, p->length); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ //DBG_871X("%s, cmd=%d\n", __FUNCTION__, param->cmd); ++ ++ switch (param->cmd) ++ { ++ case RTL871X_HOSTAPD_FLUSH: ++ ++ ret = rtw_hostapd_sta_flush(dev); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_ADD_STA: ++ ++ ret = rtw_add_sta(dev, param); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_REMOVE_STA: ++ ++ ret = rtw_del_sta(dev, param); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_SET_BEACON: ++ ++ ret = rtw_set_beacon(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_SET_ENCRYPTION: ++ ++ ret = rtw_set_encryption(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_GET_WPAIE_STA: ++ ++ ret = rtw_get_sta_wpaie(dev, param); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_SET_WPS_BEACON: ++ ++ ret = rtw_set_wps_beacon(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_SET_WPS_PROBE_RESP: ++ ++ ret = rtw_set_wps_probe_resp(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP: ++ ++ ret = rtw_set_wps_assoc_resp(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_SET_HIDDEN_SSID: ++ ++ ret = rtw_set_hidden_ssid(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_GET_INFO_STA: ++ ++ ret = rtw_ioctl_get_sta_data(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_SET_MACADDR_ACL: ++ ++ ret = rtw_ioctl_set_macaddr_acl(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_ACL_ADD_STA: ++ ++ ret = rtw_ioctl_acl_add_sta(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_ACL_REMOVE_STA: ++ ++ ret = rtw_ioctl_acl_remove_sta(dev, param, p->length); ++ ++ break; ++ ++ default: ++ DBG_871X("Unknown hostapd request: %d\n", param->cmd); ++ ret = -EOPNOTSUPP; ++ break; ++ ++ } ++ ++ if (ret == 0 && copy_to_user(p->pointer, param, p->length)) ++ ret = -EFAULT; ++ ++ ++ rtw_mfree((u8 *)param, p->length); ++ ++out: ++ ++ return ret; ++ ++} ++#endif ++ ++#include ++static int rtw_wx_set_priv(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra) ++{ ++ ++#ifdef CONFIG_DEBUG_RTW_WX_SET_PRIV ++ char *ext_dbg; ++#endif ++ ++ int ret = 0; ++ int len = 0; ++ char *ext; ++ int i; ++ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_point *dwrq = (struct iw_point*)awrq; ++ ++ //RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_notice_, ("+rtw_wx_set_priv\n")); ++ if(dwrq->length == 0) ++ return -EFAULT; ++ ++ len = dwrq->length; ++ if (!(ext = rtw_vmalloc(len))) ++ return -ENOMEM; ++ ++ if (copy_from_user(ext, dwrq->pointer, len)) { ++ rtw_vmfree(ext, len); ++ return -EFAULT; ++ } ++ ++ ++ //RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_notice_, ++ // ("rtw_wx_set_priv: %s req=%s\n", ++ // dev->name, ext)); ++ ++ #ifdef CONFIG_DEBUG_RTW_WX_SET_PRIV ++ if (!(ext_dbg = rtw_vmalloc(len))) ++ { ++ rtw_vmfree(ext, len); ++ return -ENOMEM; ++ } ++ ++ _rtw_memcpy(ext_dbg, ext, len); ++ #endif ++ ++ //added for wps2.0 @20110524 ++ if(dwrq->flags == 0x8766 && len > 8) ++ { ++ u32 cp_sz; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ u8 *probereq_wpsie = ext; ++ int probereq_wpsie_len = len; ++ u8 wps_oui[4]={0x0,0x50,0xf2,0x04}; ++ ++ if((_VENDOR_SPECIFIC_IE_ == probereq_wpsie[0]) && ++ (_rtw_memcmp(&probereq_wpsie[2], wps_oui, 4) ==_TRUE)) ++ { ++ cp_sz = probereq_wpsie_len>MAX_WPS_IE_LEN ? MAX_WPS_IE_LEN:probereq_wpsie_len; ++ ++ //_rtw_memcpy(pmlmepriv->probereq_wpsie, probereq_wpsie, cp_sz); ++ //pmlmepriv->probereq_wpsie_len = cp_sz; ++ if(pmlmepriv->wps_probe_req_ie) ++ { ++ u32 free_len = pmlmepriv->wps_probe_req_ie_len; ++ pmlmepriv->wps_probe_req_ie_len = 0; ++ rtw_mfree(pmlmepriv->wps_probe_req_ie, free_len); ++ pmlmepriv->wps_probe_req_ie = NULL; ++ } ++ ++ pmlmepriv->wps_probe_req_ie = rtw_malloc(cp_sz); ++ if ( pmlmepriv->wps_probe_req_ie == NULL) { ++ printk("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__); ++ ret = -EINVAL; ++ goto FREE_EXT; ++ ++ } ++ ++ _rtw_memcpy(pmlmepriv->wps_probe_req_ie, probereq_wpsie, cp_sz); ++ pmlmepriv->wps_probe_req_ie_len = cp_sz; ++ ++ } ++ ++ goto FREE_EXT; ++ ++ } ++ ++ if( len >= WEXT_CSCAN_HEADER_SIZE ++ && _rtw_memcmp(ext, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) == _TRUE ++ ){ ++ ret = rtw_wx_set_scan(dev, info, awrq, ext); ++ goto FREE_EXT; ++ } ++ ++#ifdef CONFIG_ANDROID ++ //DBG_871X("rtw_wx_set_priv: %s req=%s\n", dev->name, ext); ++ ++ i = rtw_android_cmdstr_to_num(ext); ++ ++ switch(i) { ++ case ANDROID_WIFI_CMD_START : ++ indicate_wx_custom_event(padapter, "START"); ++ break; ++ case ANDROID_WIFI_CMD_STOP : ++ indicate_wx_custom_event(padapter, "STOP"); ++ break; ++ case ANDROID_WIFI_CMD_RSSI : ++ { ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct wlan_network *pcur_network = &pmlmepriv->cur_network; ++ ++ if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { ++ sprintf(ext, "%s rssi %d", pcur_network->network.Ssid.Ssid, padapter->recvpriv.rssi); ++ } else { ++ sprintf(ext, "OK"); ++ } ++ } ++ break; ++ case ANDROID_WIFI_CMD_LINKSPEED : ++ { ++ u16 mbps = rtw_get_cur_max_rate(padapter)/10; ++ sprintf(ext, "LINKSPEED %d", mbps); ++ } ++ break; ++ case ANDROID_WIFI_CMD_MACADDR : ++ sprintf(ext, "MACADDR = " MAC_FMT, MAC_ARG(dev->dev_addr)); ++ break; ++ case ANDROID_WIFI_CMD_SCAN_ACTIVE : ++ { ++ //rtw_set_scan_mode(padapter, SCAN_ACTIVE); ++ sprintf(ext, "OK"); ++ } ++ break; ++ case ANDROID_WIFI_CMD_SCAN_PASSIVE : ++ { ++ //rtw_set_scan_mode(padapter, SCAN_PASSIVE); ++ sprintf(ext, "OK"); ++ } ++ break; ++ ++ case ANDROID_WIFI_CMD_COUNTRY : ++ { ++ char country_code[10]; ++ sscanf(ext, "%*s %s", country_code); ++ rtw_set_country(padapter, country_code); ++ sprintf(ext, "OK"); ++ } ++ break; ++ default : ++ #ifdef CONFIG_DEBUG_RTW_WX_SET_PRIV ++ DBG_871X("%s: %s unknowned req=%s\n", __FUNCTION__, ++ dev->name, ext_dbg); ++ #endif ++ ++ sprintf(ext, "OK"); ++ ++ } ++ ++ if (copy_to_user(dwrq->pointer, ext, min(dwrq->length, (u16)(strlen(ext)+1)) ) ) ++ ret = -EFAULT; ++ ++ #ifdef CONFIG_DEBUG_RTW_WX_SET_PRIV ++ DBG_871X("%s: %s req=%s rep=%s dwrq->length=%d, strlen(ext)+1=%d\n", __FUNCTION__, ++ dev->name, ext_dbg ,ext, dwrq->length, (u16)(strlen(ext)+1)); ++ #endif ++#endif //end of CONFIG_ANDROID ++ ++ ++FREE_EXT: ++ ++ rtw_vmfree(ext, len); ++ #ifdef CONFIG_DEBUG_RTW_WX_SET_PRIV ++ rtw_vmfree(ext_dbg, len); ++ #endif ++ ++ //DBG_871X("rtw_wx_set_priv: (SIOCSIWPRIV) %s ret=%d\n", ++ // dev->name, ret); ++ ++ return ret; ++ ++} ++ ++#ifdef CONFIG_WOWLAN ++static int rtw_wowlan_ctrl(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct wowlan_ioctl_param poidparam; ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct sta_info *psta = NULL; ++ int ret = 0; ++ u32 start_time = rtw_get_current_time(); ++ poidparam.subcode = 0; ++ ++ DBG_871X("+rtw_wowlan_ctrl: %s\n", extra); ++ ++ if(pwrctrlpriv->bSupportRemoteWakeup==_FALSE){ ++ ret = -EPERM; ++ DBG_871X("+rtw_wowlan_ctrl: Device didn't support the remote wakeup!!\n"); ++ goto _rtw_wowlan_ctrl_exit_free; ++ } ++ ++ if (!check_fwstate(pmlmepriv, _FW_LINKED) && ++ check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { ++ DBG_871X("[%s] WARNING: Please Connect With AP First!!\n", __func__); ++ goto _rtw_wowlan_ctrl_exit_free; ++ } ++ ++ if (_rtw_memcmp( extra, "enable", 6 )) { ++ ++ while (pwrctrlpriv->bips_processing == _TRUE) ++ rtw_msleep_os(1); ++ ++ rtw_cancel_all_timer(padapter); ++ ++ padapter->bDriverStopped = _TRUE; //for stop thread ++ rtw_stop_drv_threads(padapter); ++ padapter->bDriverStopped = _FALSE; //for 32k command ++ ++#ifdef CONFIG_LPS ++ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0); ++#endif ++ rtw_hal_disable_interrupt(padapter); // It need wait for leaving 32K. ++ ++ // 2.1 clean interupt ++ if (padapter->HalFunc.clear_interrupt) ++ padapter->HalFunc.clear_interrupt(padapter); ++ ++ poidparam.subcode = WOWLAN_ENABLE; ++ ++ rtw_hal_set_hwreg(padapter,HW_VAR_WOWLAN,(u8 *)&poidparam); ++ } else if (_rtw_memcmp( extra, "disable", 6 )) { ++#ifdef CONFIG_LPS ++ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0); ++#endif //CONFIG_LPS ++ pwrctrlpriv->bFwCurrentInPSMode = _FALSE; ++ ++ rtw_hal_disable_interrupt(padapter); ++ ++ if (padapter->HalFunc.clear_interrupt) ++ padapter->HalFunc.clear_interrupt(padapter); ++ ++ poidparam.subcode = WOWLAN_DISABLE; ++ ++ rtw_hal_set_hwreg(padapter,HW_VAR_WOWLAN,(u8 *)&poidparam); ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv)); ++ if (psta) { ++ set_sta_rate(padapter, psta); ++ } ++ ++ padapter->bDriverStopped = _FALSE; ++ DBG_871X("%s: wowmode resuming, DriverStopped:%d\n", __func__, padapter->bDriverStopped); ++ rtw_start_drv_threads(padapter); ++ ++ rtw_hal_enable_interrupt(padapter); ++ ++ _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 2000); ++ pwrctrlpriv->bips_processing = _FALSE; ++ rtw_set_pwr_state_check_timer(pwrctrlpriv); ++ ++ } else { ++ DBG_871X("[%s] Invalid Parameter.\n", __func__); ++ goto _rtw_wowlan_ctrl_exit_free; ++ } ++ //mutex_lock(&ioctl_mutex); ++_rtw_wowlan_ctrl_exit_free: ++ DBG_871X("-rtw_wowlan_ctrl( subcode = %d)\n", poidparam.subcode); ++ DBG_871X_LEVEL(_drv_always_, "%s in %d ms\n", __func__, ++ rtw_get_passing_time_ms(start_time)); ++_rtw_wowlan_ctrl_exit: ++ return ret; ++} ++#endif //CONFIG_WOWLAN ++ ++static int rtw_pm_set(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ unsigned mode = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ DBG_871X( "[%s] extra = %s\n", __FUNCTION__, extra ); ++ ++ if ( _rtw_memcmp( extra, "lps=", 4 ) ) ++ { ++ sscanf(extra+4, "%u", &mode); ++ ret = rtw_pm_set_lps(padapter,mode); ++ } ++ else if ( _rtw_memcmp( extra, "ips=", 4 ) ) ++ { ++ sscanf(extra+4, "%u", &mode); ++ ret = rtw_pm_set_ips(padapter,mode); ++ } ++ else{ ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int rtw_mp_efuse_get(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wdata, char *extra) ++{ ++ ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); ++ PEFUSE_HAL pEfuseHal; ++ struct iw_point *wrqu; ++ ++ u8 *PROMContent = pEEPROM->efuse_eeprom_data; ++ struct pwrctrl_priv *pwrctrlpriv ; ++ ++ u8 *data = NULL; ++ u8 *rawdata = NULL; ++ char *pch, *ptmp, *token, *tmp[3]={0x00,0x00,0x00}; ++ u8 ips_mode,lps_mode; ++ u16 i=0, j=0, mapLen=0, addr=0, cnts=0; ++ u16 max_available_size=0, raw_cursize=0, raw_maxsize=0; ++ int err; ++ #ifdef CONFIG_IOL ++ u8 org_fw_iol = padapter->registrypriv.fw_iol;// 0:Disable, 1:enable, 2:by usb speed ++ #endif ++ ++ wrqu = (struct iw_point*)wdata; ++ pwrctrlpriv = adapter_to_pwrctl(padapter); ++ pEfuseHal = &pHalData->EfuseHal; ++ ++ err = 0; ++ data = rtw_zmalloc(EFUSE_BT_MAX_MAP_LEN); ++ if (data == NULL) ++ { ++ err = -ENOMEM; ++ goto exit; ++ } ++ rawdata = rtw_zmalloc(EFUSE_BT_MAX_MAP_LEN); ++ if (rawdata == NULL) ++ { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ if (copy_from_user(extra, wrqu->pointer, wrqu->length)) ++ { ++ err = -EFAULT; ++ goto exit; ++ } ++ #ifdef CONFIG_LPS ++ lps_mode = pwrctrlpriv->power_mgnt;//keep org value ++ rtw_pm_set_lps(padapter,PS_MODE_ACTIVE); ++ #endif ++ ++ #ifdef CONFIG_IPS ++ ips_mode = pwrctrlpriv->ips_mode;//keep org value ++ rtw_pm_set_ips(padapter,IPS_NONE); ++ #endif ++ ++ pch = extra; ++ DBG_871X("%s: in=%s\n", __FUNCTION__, extra); ++ ++ i = 0; ++ //mac 16 "00e04c871200" rmap,00,2 ++ while ((token = strsep(&pch, ",")) != NULL) ++ { ++ if (i > 2) break; ++ tmp[i] = token; ++ i++; ++ } ++ #ifdef CONFIG_IOL ++ padapter->registrypriv.fw_iol = 0;// 0:Disable, 1:enable, 2:by usb speed ++ #endif ++ ++ if(strcmp(tmp[0], "status") == 0){ ++ sprintf(extra, "Load File efuse=%s,Load File MAC=%s",(pEEPROM->bloadfile_fail_flag? "FAIL" : "OK"),(pEEPROM->bloadmac_fail_flag? "FAIL" : "OK")); ++ ++ goto exit; ++ } ++ else if (strcmp(tmp[0], "drvmap") == 0) ++ { ++ mapLen = EFUSE_MAP_SIZE; ++ ++ sprintf(extra, "\n"); ++ for (i = 0; i < EFUSE_MAP_SIZE; i += 16) ++ { ++// DBG_871X("0x%02x\t", i); ++ sprintf(extra, "%s0x%02x\t", extra, i); ++ for (j=0; j<8; j++) { ++// DBG_871X("%02X ", data[i+j]); ++ sprintf(extra, "%s%02X ", extra, PROMContent[i+j]); ++ } ++// DBG_871X("\t"); ++ sprintf(extra, "%s\t", extra); ++ for (; j<16; j++) { ++// DBG_871X("%02X ", data[i+j]); ++ sprintf(extra, "%s%02X ", extra, PROMContent[i+j]); ++ } ++// DBG_871X("\n"); ++ sprintf(extra,"%s\n",extra); ++ } ++// DBG_871X("\n"); ++ } ++ else if (strcmp(tmp[0], "realmap") == 0) ++ { ++ mapLen = EFUSE_MAP_SIZE; ++ if (rtw_efuse_map_read(padapter, 0, mapLen, pEfuseHal->fakeEfuseInitMap) == _FAIL) ++ { ++ DBG_871X("%s: read realmap Fail!!\n", __FUNCTION__); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++// DBG_871X("OFFSET\tVALUE(hex)\n"); ++ sprintf(extra, "\n"); ++ for (i = 0; i < EFUSE_MAP_SIZE; i += 16) ++ { ++// DBG_871X("0x%02x\t", i); ++ sprintf(extra, "%s0x%02x\t", extra, i); ++ for (j=0; j<8; j++) { ++// DBG_871X("%02X ", data[i+j]); ++ sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeEfuseInitMap[i+j]); ++ } ++// DBG_871X("\t"); ++ sprintf(extra, "%s\t", extra); ++ for (; j<16; j++) { ++// DBG_871X("%02X ", data[i+j]); ++ sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeEfuseInitMap[i+j]); ++ } ++// DBG_871X("\n"); ++ sprintf(extra,"%s\n",extra); ++ } ++// DBG_871X("\n"); ++ } ++ else if (strcmp(tmp[0], "rmap") == 0) ++ { ++ if ((tmp[1]==NULL) || (tmp[2]==NULL)) ++ { ++ DBG_871X("%s: rmap Fail!! Parameters error!\n", __FUNCTION__); ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ // rmap addr cnts ++ addr = simple_strtoul(tmp[1], &ptmp, 16); ++ DBG_871X("%s: addr=%x\n", __FUNCTION__, addr); ++ ++ cnts = simple_strtoul(tmp[2], &ptmp, 10); ++ if (cnts == 0) ++ { ++ DBG_871X("%s: rmap Fail!! cnts error!\n", __FUNCTION__); ++ err = -EINVAL; ++ goto exit; ++ } ++ DBG_871X("%s: cnts=%d\n", __FUNCTION__, cnts); ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_available_size, _FALSE); ++ if ((addr + cnts) > max_available_size) ++ { ++ DBG_871X("%s: addr(0x%X)+cnts(%d) parameter error!\n", __FUNCTION__, addr, cnts); ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ if (rtw_efuse_map_read(padapter, addr, cnts, data) == _FAIL) ++ { ++ DBG_871X("%s: rtw_efuse_map_read error!\n", __FUNCTION__); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++// DBG_871X("%s: data={", __FUNCTION__); ++ *extra = 0; ++ for (i=0; i max_available_size) { ++ DBG_871X("%s: addr(0x%02x)+cnts(%d) parameter error!\n", __FUNCTION__, addr, cnts); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if (rtw_efuse_map_read(padapter, addr, cnts, data) == _FAIL) ++ { ++ DBG_871X("%s: rtw_efuse_map_read error!\n", __FUNCTION__); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++// DBG_871X("%s: MAC address={", __FUNCTION__); ++ *extra = 0; ++ for (i=0; i max_available_size) ++ { ++ DBG_871X("%s: addr(0x%02x)+cnts(%d) parameter error!\n", __FUNCTION__, addr, cnts); ++ err = -EFAULT; ++ goto exit; ++ } ++ if (rtw_efuse_map_read(padapter, addr, cnts, data) == _FAIL) ++ { ++ DBG_871X("%s: rtw_efuse_access error!!\n", __FUNCTION__); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++// DBG_871X("%s: {VID,PID}={", __FUNCTION__); ++ *extra = 0; ++ for (i=0; iBTEfuseInitMap) == _FAIL) ++ { ++ DBG_871X("%s: rtw_BT_efuse_map_read Fail!!\n", __FUNCTION__); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++// DBG_871X("OFFSET\tVALUE(hex)\n"); ++ sprintf(extra, "\n"); ++ for (i=0; i<512; i+=16) // set 512 because the iwpriv's extra size have limit 0x7FF ++ { ++// DBG_871X("0x%03x\t", i); ++ sprintf(extra, "%s0x%03x\t", extra, i); ++ for (j=0; j<8; j++) { ++// DBG_871X("%02X ", pEfuseHal->BTEfuseInitMap[i+j]); ++ sprintf(extra, "%s%02X ", extra, pEfuseHal->BTEfuseInitMap[i+j]); ++ } ++// DBG_871X("\t"); ++ sprintf(extra,"%s\t",extra); ++ for (; j<16; j++) { ++// DBG_871X("%02X ", pEfuseHal->BTEfuseInitMap[i+j]); ++ sprintf(extra, "%s%02X ", extra, pEfuseHal->BTEfuseInitMap[i+j]); ++ } ++// DBG_871X("\n"); ++ sprintf(extra, "%s\n", extra); ++ } ++// DBG_871X("\n"); ++ } ++ else if (strcmp(tmp[0],"btbmap") == 0) ++ { ++ mapLen = EFUSE_BT_MAX_MAP_LEN; ++ if (rtw_BT_efuse_map_read(padapter, 0, mapLen, pEfuseHal->BTEfuseInitMap) == _FAIL) ++ { ++ DBG_871X("%s: rtw_BT_efuse_map_read Fail!!\n", __FUNCTION__); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++// DBG_871X("OFFSET\tVALUE(hex)\n"); ++ sprintf(extra, "\n"); ++ for (i=512; i<1024 ; i+=16) ++ { ++// DBG_871X("0x%03x\t", i); ++ sprintf(extra, "%s0x%03x\t", extra, i); ++ for (j=0; j<8; j++) ++ { ++// DBG_871X("%02X ", data[i+j]); ++ sprintf(extra, "%s%02X ", extra, pEfuseHal->BTEfuseInitMap[i+j]); ++ } ++// DBG_871X("\t"); ++ sprintf(extra,"%s\t",extra); ++ for (; j<16; j++) { ++// DBG_871X("%02X ", data[i+j]); ++ sprintf(extra, "%s%02X ", extra, pEfuseHal->BTEfuseInitMap[i+j]); ++ } ++// DBG_871X("\n"); ++ sprintf(extra, "%s\n", extra); ++ } ++// DBG_871X("\n"); ++ } ++ else if (strcmp(tmp[0],"btrmap") == 0) ++ { ++ if ((tmp[1]==NULL) || (tmp[2]==NULL)) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ // rmap addr cnts ++ addr = simple_strtoul(tmp[1], &ptmp, 16); ++ DBG_871X("%s: addr=0x%X\n", __FUNCTION__, addr); ++ ++ cnts = simple_strtoul(tmp[2], &ptmp, 10); ++ if (cnts == 0) ++ { ++ DBG_871X("%s: btrmap Fail!! cnts error!\n", __FUNCTION__); ++ err = -EINVAL; ++ goto exit; ++ } ++ DBG_871X("%s: cnts=%d\n", __FUNCTION__, cnts); ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_available_size, _FALSE); ++ if ((addr + cnts) > max_available_size) ++ { ++ DBG_871X("%s: addr(0x%X)+cnts(%d) parameter error!\n", __FUNCTION__, addr, cnts); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if (rtw_BT_efuse_map_read(padapter, addr, cnts, data) == _FAIL) ++ { ++ DBG_871X("%s: rtw_BT_efuse_map_read error!!\n", __FUNCTION__); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ *extra = 0; ++// DBG_871X("%s: bt efuse data={", __FUNCTION__); ++ for (i=0; ifakeBTEfuseModifiedMap[i+j]); ++ sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeBTEfuseModifiedMap[i+j]); ++ } ++// DBG_871X("\t"); ++ sprintf(extra, "%s\t", extra); ++ for (; j<16; j++) { ++// DBG_871X("%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i+j]); ++ sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeBTEfuseModifiedMap[i+j]); ++ } ++// DBG_871X("\n"); ++ sprintf(extra, "%s\n", extra); ++ } ++// DBG_871X("\n"); ++ } ++ else if (strcmp(tmp[0],"btbfake") == 0) ++ { ++// DBG_871X("OFFSET\tVALUE(hex)\n"); ++ sprintf(extra, "\n"); ++ for (i=512; i<1024; i+=16) ++ { ++// DBG_871X("0x%03x\t", i); ++ sprintf(extra, "%s0x%03x\t", extra, i); ++ for (j=0; j<8; j++) { ++// DBG_871X("%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i+j]); ++ sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeBTEfuseModifiedMap[i+j]); ++ } ++// DBG_871X("\t"); ++ sprintf(extra, "%s\t", extra); ++ for (; j<16; j++) { ++// DBG_871X("%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i+j]); ++ sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeBTEfuseModifiedMap[i+j]); ++ } ++// DBG_871X("\n"); ++ sprintf(extra, "%s\n", extra); ++ } ++// DBG_871X("\n"); ++ } ++ else if (strcmp(tmp[0],"wlrfkmap")== 0) ++ { ++// DBG_871X("OFFSET\tVALUE(hex)\n"); ++ sprintf(extra, "\n"); ++ for (i=0; ifakeEfuseModifiedMap[i+j]); ++ sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeEfuseModifiedMap[i+j]); ++ } ++// DBG_871X("\t"); ++ sprintf(extra, "%s\t", extra); ++ for (; j<16; j++) { ++// DBG_871X("%02X ", pEfuseHal->fakeEfuseModifiedMap[i+j]); ++ sprintf(extra, "%s %02X", extra, pEfuseHal->fakeEfuseModifiedMap[i+j]); ++ } ++// DBG_871X("\n"); ++ sprintf(extra, "%s\n", extra); ++ } ++// DBG_871X("\n"); ++ ++ } ++ else if (strcmp(tmp[0],"wlrfkrmap")== 0) ++ { ++ if ((tmp[1]==NULL) || (tmp[2]==NULL)) ++ { ++ DBG_871X("%s: rmap Fail!! Parameters error!\n", __FUNCTION__); ++ err = -EINVAL; ++ goto exit; ++ } ++ // rmap addr cnts ++ addr = simple_strtoul(tmp[1], &ptmp, 16); ++ DBG_871X("%s: addr=%x\n", __FUNCTION__, addr); ++ ++ cnts = simple_strtoul(tmp[2], &ptmp, 10); ++ if (cnts == 0) ++ { ++ DBG_871X("%s: rmap Fail!! cnts error!\n", __FUNCTION__); ++ err = -EINVAL; ++ goto exit; ++ } ++ DBG_871X("%s: cnts=%d\n", __FUNCTION__, cnts); ++ ++ // DBG_871X("%s: data={", __FUNCTION__); ++ *extra = 0; ++ for (i=0; ifakeEfuseModifiedMap[addr+i]); ++ sprintf(extra, "%s0x%02X ", extra, pEfuseHal->fakeEfuseModifiedMap[addr+i]); ++ } ++ } ++ else if (strcmp(tmp[0],"btrfkrmap")== 0) ++ { ++ if ((tmp[1]==NULL) || (tmp[2]==NULL)) ++ { ++ DBG_871X("%s: rmap Fail!! Parameters error!\n", __FUNCTION__); ++ err = -EINVAL; ++ goto exit; ++ } ++ // rmap addr cnts ++ addr = simple_strtoul(tmp[1], &ptmp, 16); ++ DBG_871X("%s: addr=%x\n", __FUNCTION__, addr); ++ ++ cnts = simple_strtoul(tmp[2], &ptmp, 10); ++ if (cnts == 0) ++ { ++ DBG_871X("%s: rmap Fail!! cnts error!\n", __FUNCTION__); ++ err = -EINVAL; ++ goto exit; ++ } ++ DBG_871X("%s: cnts=%d\n", __FUNCTION__, cnts); ++ ++ // DBG_871X("%s: data={", __FUNCTION__); ++ *extra = 0; ++ for (i=0; ifakeBTEfuseModifiedMap[addr+i]); ++ sprintf(extra, "%s0x%02X ", extra, pEfuseHal->fakeBTEfuseModifiedMap[addr+i]); ++ } ++ } ++ else ++ { ++ sprintf(extra, "Command not found!"); ++ } ++ ++exit: ++ if (data) ++ rtw_mfree(data, EFUSE_BT_MAX_MAP_LEN); ++ if (rawdata) ++ rtw_mfree(rawdata, EFUSE_BT_MAX_MAP_LEN); ++ if (!err) ++ wrqu->length = strlen(extra); ++ ++ #ifdef CONFIG_IPS ++ rtw_pm_set_ips(padapter, ips_mode); ++ #endif ++ #ifdef CONFIG_LPS ++ rtw_pm_set_lps(padapter, lps_mode); ++ #endif ++ #ifdef CONFIG_IOL ++ padapter->registrypriv.fw_iol = org_fw_iol;// 0:Disable, 1:enable, 2:by usb speed ++ #endif ++ return err; ++} ++ ++static int rtw_mp_efuse_set(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wdata, char *extra) ++{ ++ struct iw_point *wrqu; ++ PADAPTER padapter; ++ struct pwrctrl_priv *pwrctrlpriv ; ++ PHAL_DATA_TYPE pHalData; ++ PEFUSE_HAL pEfuseHal; ++ ++ u8 ips_mode,lps_mode; ++ u32 i, jj, kk; ++ u8 *setdata = NULL; ++ u8 *ShadowMapBT = NULL; ++ u8 *ShadowMapWiFi = NULL; ++ u8 *setrawdata = NULL; ++ char *pch, *ptmp, *token, *tmp[3]={0x00,0x00,0x00}; ++ u16 addr=0, cnts=0, max_available_size=0; ++ int err; ++ ++ ++ wrqu = (struct iw_point*)wdata; ++ padapter = rtw_netdev_priv(dev); ++ pwrctrlpriv = adapter_to_pwrctl(padapter); ++ pHalData = GET_HAL_DATA(padapter); ++ pEfuseHal = &pHalData->EfuseHal; ++ err = 0; ++ setdata = rtw_zmalloc(1024); ++ if (setdata == NULL) ++ { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ShadowMapBT = rtw_malloc(EFUSE_BT_MAX_MAP_LEN); ++ if (ShadowMapBT == NULL) ++ { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ShadowMapWiFi = rtw_malloc(EFUSE_MAP_SIZE); ++ if (ShadowMapWiFi == NULL) ++ { ++ err = -ENOMEM; ++ goto exit; ++ } ++ setrawdata = rtw_malloc(EFUSE_MAX_SIZE); ++ if (setrawdata == NULL) ++ { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ #ifdef CONFIG_LPS ++ lps_mode = pwrctrlpriv->power_mgnt;//keep org value ++ rtw_pm_set_lps(padapter,PS_MODE_ACTIVE); ++ #endif ++ ++ #ifdef CONFIG_IPS ++ ips_mode = pwrctrlpriv->ips_mode;//keep org value ++ rtw_pm_set_ips(padapter,IPS_NONE); ++ #endif ++ ++ pch = extra; ++ DBG_871X("%s: in=%s\n", __FUNCTION__, extra); ++ ++ i = 0; ++ while ((token = strsep(&pch, ",")) != NULL) ++ { ++ if (i > 2) break; ++ tmp[i] = token; ++ i++; ++ } ++ ++ // tmp[0],[1],[2] ++ // wmap,addr,00e04c871200 ++ if (strcmp(tmp[0], "wmap") == 0) ++ { ++ if ((tmp[1]==NULL) || (tmp[2]==NULL)) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ addr = simple_strtoul(tmp[1], &ptmp, 16); ++ addr &= 0xFFF; ++ ++ cnts = strlen(tmp[2]); ++ if (cnts%2) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ cnts /= 2; ++ if (cnts == 0) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ DBG_871X("%s: addr=0x%X\n", __FUNCTION__, addr); ++ DBG_871X("%s: cnts=%d\n", __FUNCTION__, cnts); ++ DBG_871X("%s: map data=%s\n", __FUNCTION__, tmp[2]); ++ ++ for (jj=0, kk=0; jj max_available_size) ++ { ++ DBG_871X("%s: addr(0x%X)+cnts(%d) parameter error!\n", __FUNCTION__, addr, cnts); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if (rtw_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) ++ { ++ DBG_871X("%s: rtw_efuse_map_write error!!\n", __FUNCTION__); ++ err = -EFAULT; ++ goto exit; ++ } ++ } ++ else if (strcmp(tmp[0], "wraw") == 0) ++ { ++ if ((tmp[1]==NULL) || (tmp[2]==NULL)) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ addr = simple_strtoul( tmp[1], &ptmp, 16 ); ++ addr &= 0xFFF; ++ ++ cnts = strlen(tmp[2]); ++ if (cnts%2) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ cnts /= 2; ++ if (cnts == 0) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ DBG_871X("%s: addr=0x%X\n", __FUNCTION__, addr); ++ DBG_871X("%s: cnts=%d\n", __FUNCTION__, cnts); ++ DBG_871X("%s: raw data=%s\n", __FUNCTION__, tmp[2]); ++ ++ for (jj=0, kk=0; jj 6) ++ { ++ DBG_871X("%s: error data for mac addr=\"%s\"\n", __FUNCTION__, tmp[1]); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ DBG_871X("%s: addr=0x%X\n", __FUNCTION__, addr); ++ DBG_871X("%s: cnts=%d\n", __FUNCTION__, cnts); ++ DBG_871X("%s: MAC address=%s\n", __FUNCTION__, tmp[1]); ++ ++ for (jj=0, kk=0; jj max_available_size) ++ { ++ DBG_871X("%s: addr(0x%X)+cnts(%d) parameter error!\n", __FUNCTION__, addr, cnts); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if (rtw_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) ++ { ++ DBG_871X("%s: rtw_efuse_map_write error!!\n", __FUNCTION__); ++ err = -EFAULT; ++ goto exit; ++ } ++ } ++ else if (strcmp(tmp[0], "vidpid") == 0) ++ { ++ if (tmp[1]==NULL) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ // pidvid,da0b7881 ++ #ifdef CONFIG_RTL8192C ++ addr = 0x0a; ++ #endif ++ #ifdef CONFIG_RTL8192D ++ addr = 0x0c; ++ #endif ++ #ifdef CONFIG_RTL8723A ++ addr = EEPROM_VID_8723AU; ++ #endif ++ #ifdef CONFIG_RTL8188E ++ #ifdef CONFIG_USB_HCI ++ addr = EEPROM_VID_88EE; ++ #endif ++ #ifdef CONFIG_PCI_HCI ++ addr = EEPROM_VID_88EE; ++ #endif ++ #endif //#ifdef CONFIG_RTL8188E ++ cnts = strlen(tmp[1]); ++ if (cnts%2) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ cnts /= 2; ++ if (cnts == 0) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ DBG_871X("%s: addr=0x%X\n", __FUNCTION__, addr); ++ DBG_871X("%s: cnts=%d\n", __FUNCTION__, cnts); ++ DBG_871X("%s: VID/PID=%s\n", __FUNCTION__, tmp[1]); ++ ++ for (jj=0, kk=0; jj max_available_size) ++ { ++ DBG_871X("%s: addr(0x%X)+cnts(%d) parameter error!\n", __FUNCTION__, addr, cnts); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if (rtw_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) ++ { ++ DBG_871X("%s: rtw_efuse_map_write error!!\n", __FUNCTION__); ++ err = -EFAULT; ++ goto exit; ++ } ++ } ++ else if (strcmp(tmp[0], "wldumpfake") == 0) ++ { ++ if (rtw_efuse_map_read(padapter, 0, EFUSE_MAP_SIZE, pEfuseHal->fakeEfuseModifiedMap) == _SUCCESS) { ++ DBG_871X("%s: WiFi hw efuse dump to Fake map success \n", __FUNCTION__); ++ } else { ++ DBG_871X("%s: WiFi hw efuse dump to Fake map Fail \n", __FUNCTION__); ++ err = -EFAULT; ++ } ++ } ++ else if (strcmp(tmp[0], "btwmap") == 0) ++ { ++ if ((tmp[1]==NULL) || (tmp[2]==NULL)) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ addr = simple_strtoul(tmp[1], &ptmp, 16); ++ addr &= 0xFFF; ++ ++ cnts = strlen(tmp[2]); ++ if (cnts%2) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ cnts /= 2; ++ if (cnts == 0) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ DBG_871X("%s: addr=0x%X\n", __FUNCTION__, addr); ++ DBG_871X("%s: cnts=%d\n", __FUNCTION__, cnts); ++ DBG_871X("%s: BT data=%s\n", __FUNCTION__, tmp[2]); ++ ++ for (jj=0, kk=0; jj max_available_size) ++ { ++ DBG_871X("%s: addr(0x%X)+cnts(%d) parameter error!\n", __FUNCTION__, addr, cnts); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if (rtw_BT_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) ++ { ++ DBG_871X("%s: rtw_BT_efuse_map_write error!!\n", __FUNCTION__); ++ err = -EFAULT; ++ goto exit; ++ } ++ } ++ else if (strcmp(tmp[0], "btwfake") == 0) ++ { ++ if ((tmp[1]==NULL) || (tmp[2]==NULL)) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ addr = simple_strtoul(tmp[1], &ptmp, 16); ++ addr &= 0xFFF; ++ ++ cnts = strlen(tmp[2]); ++ if (cnts%2) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ cnts /= 2; ++ if (cnts == 0) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ DBG_871X("%s: addr=0x%X\n", __FUNCTION__, addr); ++ DBG_871X("%s: cnts=%d\n", __FUNCTION__, cnts); ++ DBG_871X("%s: BT tmp data=%s\n", __FUNCTION__, tmp[2]); ++ ++ for (jj=0, kk=0; jjfakeBTEfuseModifiedMap[addr+jj] = key_2char2num(tmp[2][kk], tmp[2][kk+1]); ++ } ++ } ++ else if (strcmp(tmp[0], "btdumpfake") == 0) ++ { ++ if (rtw_BT_efuse_map_read(padapter, 0, EFUSE_BT_MAX_MAP_LEN, pEfuseHal->fakeBTEfuseModifiedMap) == _SUCCESS) { ++ DBG_871X("%s: BT read all map success\n", __FUNCTION__); ++ } else { ++ DBG_871X("%s: BT read all map Fail!\n", __FUNCTION__); ++ err = -EFAULT; ++ } ++ } ++ else if (strcmp(tmp[0], "btfk2map") == 0) ++ { ++ _rtw_memcpy(pEfuseHal->BTEfuseModifiedMap, pEfuseHal->fakeBTEfuseModifiedMap, EFUSE_BT_MAX_MAP_LEN); ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_available_size, _FALSE); ++ if (max_available_size < 1) ++ { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if (rtw_BT_efuse_map_write(padapter, 0x00, EFUSE_BT_MAX_MAP_LEN, pEfuseHal->fakeBTEfuseModifiedMap) == _FAIL) ++ { ++ DBG_871X("%s: rtw_BT_efuse_map_write error!\n", __FUNCTION__); ++ err = -EFAULT; ++ goto exit; ++ } ++ } ++ else if (strcmp(tmp[0], "wlfk2map") == 0) ++ { ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_available_size, _FALSE); ++ if (max_available_size < 1) ++ { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if (rtw_efuse_map_write(padapter, 0x00, EFUSE_MAP_SIZE, pEfuseHal->fakeEfuseModifiedMap) == _FAIL) ++ { ++ DBG_871X("%s: rtw_efuse_map_write fakeEfuseModifiedMap error!\n", __FUNCTION__); ++ err = -EFAULT; ++ goto exit; ++ } ++ } ++ else if (strcmp(tmp[0], "wlwfake") == 0) ++ { ++ if ((tmp[1]==NULL) || (tmp[2]==NULL)) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ addr = simple_strtoul(tmp[1], &ptmp, 16); ++ addr &= 0xFFF; ++ ++ cnts = strlen(tmp[2]); ++ if (cnts%2) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ cnts /= 2; ++ if (cnts == 0) ++ { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ DBG_871X("%s: addr=0x%X\n", __FUNCTION__, addr); ++ DBG_871X("%s: cnts=%d\n", __FUNCTION__, cnts); ++ DBG_871X("%s: map tmp data=%s\n", __FUNCTION__, tmp[2]); ++ ++ for (jj=0, kk=0; jjfakeEfuseModifiedMap[addr+jj] = key_2char2num(tmp[2][kk], tmp[2][kk+1]); ++ } ++ } ++ ++exit: ++ if (setdata) ++ rtw_mfree(setdata, 1024); ++ if (ShadowMapBT) ++ rtw_mfree(ShadowMapBT, EFUSE_BT_MAX_MAP_LEN); ++ if (ShadowMapWiFi) ++ rtw_mfree(ShadowMapWiFi, EFUSE_MAP_SIZE); ++ if (setrawdata) ++ rtw_mfree(setrawdata, EFUSE_MAX_SIZE); ++ ++ #ifdef CONFIG_IPS ++ rtw_pm_set_ips(padapter, ips_mode); ++ #endif ++ #ifdef CONFIG_LPS ++ rtw_pm_set_lps(padapter, lps_mode); ++ #endif ++ ++ return err; ++} ++ ++#if defined(CONFIG_MP_INCLUDED) && defined(CONFIG_MP_IWPRIV_SUPPORT) ++/* ++ * Input Format: %s,%d,%d ++ * %s is width, could be ++ * "b" for 1 byte ++ * "w" for WORD (2 bytes) ++ * "dw" for DWORD (4 bytes) ++ * 1st %d is address(offset) ++ * 2st %d is data to write ++ */ ++static int rtw_mp_write_reg(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ char *pch, *pnext, *ptmp; ++ char *width_str; ++ char width; ++ u32 addr, data; ++ int ret; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ char input[wrqu->length]; ++ ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ _rtw_memset(extra, 0, wrqu->length); ++ ++ pch = input; ++ ++ pnext = strpbrk(pch, " ,.-"); ++ if (pnext == NULL) return -EINVAL; ++ *pnext = 0; ++ width_str = pch; ++ ++ pch = pnext + 1; ++ pnext = strpbrk(pch, " ,.-"); ++ if (pnext == NULL) return -EINVAL; ++ *pnext = 0; ++ addr = simple_strtoul(pch, &ptmp, 16); ++ if (addr > 0x3FFF) return -EINVAL; ++ ++ pch = pnext + 1; ++ if ((pch - extra) >= wrqu->length) return -EINVAL; ++ data = simple_strtoul(pch, &ptmp, 16); ++ ++ ret = 0; ++ width = width_str[0]; ++ switch (width) { ++ case 'b': ++ // 1 byte ++ if (data > 0xFF) { ++ ret = -EINVAL; ++ break; ++ } ++ rtw_write8(padapter, addr, data); ++ break; ++ case 'w': ++ // 2 bytes ++ if (data > 0xFFFF) { ++ ret = -EINVAL; ++ break; ++ } ++ rtw_write16(padapter, addr, data); ++ break; ++ case 'd': ++ // 4 bytes ++ rtw_write32(padapter, addr, data); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++/* ++ * Input Format: %s,%d ++ * %s is width, could be ++ * "b" for 1 byte ++ * "w" for WORD (2 bytes) ++ * "dw" for DWORD (4 bytes) ++ * %d is address(offset) ++ * ++ * Return: ++ * %d for data readed ++ */ ++static int rtw_mp_read_reg(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ char input[wrqu->length]; ++ char *pch, *pnext, *ptmp; ++ char *width_str; ++ char width; ++ char data[20],tmp[20]; ++ u32 addr; ++ //u32 *data = (u32*)extra; ++ u32 ret, i=0, j=0, strtout=0; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ ++ ++ if (wrqu->length > 128) ++ return -EFAULT; ++ ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ _rtw_memset(data, 0, 20); ++ _rtw_memset(tmp, 0, 20); ++ _rtw_memset(extra, 0, wrqu->length); ++ ++ pch = input; ++ pnext = strpbrk(pch, " ,.-"); ++ if (pnext == NULL) return -EINVAL; ++ *pnext = 0; ++ width_str = pch; ++ ++ pch = pnext + 1; ++ if ((pch - input) >= wrqu->length) return -EINVAL; ++ ++ addr = simple_strtoul(pch, &ptmp, 16); ++ if (addr > 0x3FFF) return -EINVAL; ++ ++ ret = 0; ++ width = width_str[0]; ++ switch (width) ++ { ++ case 'b': ++ // 1 byte ++ // *(u8*)data = rtw_read8(padapter, addr); ++ sprintf(extra, "%d\n", rtw_read8(padapter, addr)); ++ wrqu->length = strlen(extra); ++ break; ++ case 'w': ++ // 2 bytes ++ //*(u16*)data = rtw_read16(padapter, addr); ++ sprintf(data, "%04x\n", rtw_read16(padapter, addr)); ++ for( i=0 ; i <= strlen(data) ; i++) ++ { ++ if( i%2==0 ) ++ { ++ tmp[j]=' '; ++ j++; ++ } ++ if ( data[i] != '\0' ) ++ tmp[j] = data[i]; ++ ++ j++; ++ } ++ pch = tmp; ++ DBG_871X("pch=%s",pch); ++ ++ while( *pch != '\0' ) ++ { ++ pnext = strpbrk(pch, " "); ++ if (!pnext) ++ break; ++ ++ pnext++; ++ if ( *pnext != '\0' ) ++ { ++ strtout = simple_strtoul (pnext , &ptmp, 16); ++ sprintf( extra, "%s %d" ,extra ,strtout ); ++ } ++ else{ ++ break; ++ } ++ pch = pnext; ++ } ++ wrqu->length = 7; ++ break; ++ case 'd': ++ // 4 bytes ++ //*data = rtw_read32(padapter, addr); ++ sprintf(data, "%08x", rtw_read32(padapter, addr)); ++ //add read data format blank ++ for( i=0 ; i <= strlen(data) ; i++) ++ { ++ if( i%2==0 ) ++ { ++ tmp[j]=' '; ++ j++; ++ } ++ if ( data[i] != '\0' ) ++ tmp[j] = data[i]; ++ ++ j++; ++ } ++ pch = tmp; ++ DBG_871X("pch=%s",pch); ++ ++ while( *pch != '\0' ) ++ { ++ pnext = strpbrk(pch, " "); ++ if (!pnext) ++ break; ++ ++ pnext++; ++ if ( *pnext != '\0' ) ++ { ++ strtout = simple_strtoul (pnext , &ptmp, 16); ++ sprintf( extra, "%s %d" ,extra ,strtout ); ++ } ++ else{ ++ break; ++ } ++ pch = pnext; ++ } ++ wrqu->length = strlen(extra); ++ break; ++ ++ default: ++ wrqu->length = 0; ++ ret = -EINVAL; ++ break; ++ ++ } ++ ++ return ret; ++} ++ ++/* ++ * Input Format: %d,%x,%x ++ * %d is RF path, should be smaller than MAX_RF_PATH_NUMS ++ * 1st %x is address(offset) ++ * 2st %x is data to write ++ */ ++ static int rtw_mp_write_rf(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++/*static int rtw_mp_write_rf(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++*/ ++ u32 path, addr, data; ++ int ret; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ char input[wrqu->length]; ++ ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ ++ ret = sscanf(input, "%d,%x,%x", &path, &addr, &data); ++ if (ret < 3) return -EINVAL; ++ ++ if (path >= MAX_RF_PATH_NUMS) return -EINVAL; ++ if (addr > 0xFF) return -EINVAL; ++ if (data > 0xFFFFF) return -EINVAL; ++ ++ _rtw_memset(extra, 0, wrqu->length); ++ ++ write_rfreg(padapter, path, addr, data); ++ ++ sprintf(extra, "write_rf completed \n"); ++ wrqu->length = strlen(extra); ++ ++ return 0; ++} ++ ++/* ++ * Input Format: %d,%x ++ * %d is RF path, should be smaller than MAX_RF_PATH_NUMS ++ * %x is address(offset) ++ * ++ * Return: ++ * %d for data readed ++ */ ++static int rtw_mp_read_rf(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ char input[wrqu->length]; ++ char *pch, *pnext, *ptmp; ++ char data[20],tmp[20]; ++ //u32 *data = (u32*)extra; ++ u32 path, addr; ++ u32 ret,i=0 ,j=0,strtou=0; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ ++ ++ if (wrqu->length > 128) return -EFAULT; ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ ret = sscanf(input, "%d,%x", &path, &addr); ++ if (ret < 2) return -EINVAL; ++ ++ if (path >= MAX_RF_PATH_NUMS) return -EINVAL; ++ if (addr > 0xFF) return -EINVAL; ++ ++ _rtw_memset(extra, 0, wrqu->length); ++ ++ //*data = read_rfreg(padapter, path, addr); ++ sprintf(data, "%08x", read_rfreg(padapter, path, addr)); ++ //add read data format blank ++ for( i=0 ; i <= strlen(data) ; i++) ++ { ++ if( i%2==0 ) ++ { ++ tmp[j]=' '; ++ j++; ++ } ++ tmp[j] = data[i]; ++ j++; ++ } ++ pch = tmp; ++ DBG_871X("pch=%s",pch); ++ ++ while( *pch != '\0' ) ++ { ++ pnext = strpbrk(pch, " "); ++ pnext++; ++ if ( *pnext != '\0' ) ++ { ++ strtou = simple_strtoul (pnext , &ptmp, 16); ++ sprintf( extra, "%s %d" ,extra ,strtou ); ++ } ++ else{ ++ break; ++ } ++ pch = pnext; ++ } ++ wrqu->length = strlen(extra); ++ ++ return 0; ++} ++ ++static int rtw_mp_start(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u8 val8; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ struct hal_ops *pHalFunc = &padapter->HalFunc; ++#ifdef CONFIG_BT_COEXIST ++ PBT30Info pBTInfo; ++ PBT_MGNT pBtMgnt; ++ ++ pBTInfo = GET_BT_INFO(padapter); ++ pBtMgnt = &pBTInfo->BtMgnt; ++#endif ++ if(padapter->registrypriv.mp_mode ==0) ++ { ++ #ifdef CONFIG_RTL8723A ++ DBG_871X("_rtw_mp_xmit_priv for Download BT patch FW\n"); ++ _rtw_mp_xmit_priv(&padapter->xmitpriv); ++ #endif ++ ++ padapter->registrypriv.mp_mode =1; ++ rtw_pm_set_ips(padapter,IPS_NONE); ++ LeaveAllPowerSaveMode(padapter); ++ MPT_InitializeAdapter(padapter, 1); ++#ifdef CONFIG_BT_COEXIST ++ pHalData->bt_coexist.BluetoothCoexist = 0; ++ pBtMgnt->ExtConfig.bManualControl = _TRUE; ++ pdmpriv->DMFlag &= (~DYNAMIC_FUNC_BT); ++ BT_HaltProcess(padapter); ++ DBG_871X("Set disable BT_COEXIST\n"); ++ //padapter->registrypriv.mp_mode =0; ++ //pHalFunc->hal_init(padapter); ++ //padapter->registrypriv.mp_mode =1; ++ // Force to switch Antenna to WiFi ++ rtw_write16(padapter, 0x870, 0x300); ++ rtw_write16(padapter, 0x860, 0x110); ++#endif ++ } ++ ++ if (padapter->registrypriv.mp_mode == 0) ++ return -EPERM; ++ ++ if (padapter->mppriv.mode == MP_OFF) { ++ if (mp_start_test(padapter) == _FAIL) ++ return -EPERM; ++ padapter->mppriv.mode = MP_ON; ++ MPT_PwrCtlDM(padapter,0); ++ } ++ ++ return 0; ++} ++ ++static int rtw_mp_stop(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ ++ if(padapter->registrypriv.mp_mode ==1) ++ { ++ MPT_DeInitAdapter(padapter); ++ padapter->registrypriv.mp_mode=0; ++ DBG_871X("rtw_mp_stop -> registrypriv.mp_mode=%d ",padapter->registrypriv.mp_mode); ++ ++ if (padapter->mppriv.mode != MP_OFF) { ++ //mp_stop_test(padapter); ++ padapter->mppriv.mode = MP_OFF; ++ } ++ } ++ ++ return 0; ++} ++ ++extern int wifirate2_ratetbl_inx(unsigned char rate); ++ ++static int rtw_mp_rate(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u32 rate = MPT_RATE_1M; ++ u8 input[wrqu->length]; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ rate = rtw_atoi(input); ++ sprintf( extra, "Set data rate to %d" , rate ); ++ ++ if(rate <= 0x7f) ++ rate = wifirate2_ratetbl_inx( (u8)rate); ++ else ++ rate =(rate-0x80+MPT_RATE_MCS0); ++ ++ //DBG_871X("%s: rate=%d\n", __func__, rate); ++ ++ if (rate >= MPT_RATE_LAST ) ++ return -EINVAL; ++ ++ padapter->mppriv.rateidx = rate; ++ Hal_SetDataRate(padapter); ++ ++ wrqu->length = strlen(extra) + 1; ++ return 0; ++} ++ ++static int rtw_mp_channel(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ u8 input[wrqu->length]; ++ u32 channel = 1; ++ ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ channel = rtw_atoi(input); ++ //DBG_871X("%s: channel=%d\n", __func__, channel); ++ sprintf( extra, "Change channel %d to channel %d", padapter->mppriv.channel , channel ); ++ ++ padapter->mppriv.channel = channel; ++ Hal_SetChannel(padapter); ++ ++ wrqu->length = strlen(extra) + 1; ++ return 0; ++} ++ ++static int rtw_mp_bandwidth(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u32 bandwidth=0, sg=0; ++ //u8 buffer[40]; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ //if (copy_from_user(buffer, (void*)wrqu->data.pointer, wrqu->data.length)) ++ // return -EFAULT; ++ ++ //DBG_871X("%s:iwpriv in=%s\n", __func__, extra); ++ ++ sscanf(extra, "40M=%d,shortGI=%d", &bandwidth, &sg); ++ ++ if (bandwidth != HT_CHANNEL_WIDTH_40) ++ bandwidth = HT_CHANNEL_WIDTH_20; ++ ++ //DBG_871X("%s: bw=%d sg=%d \n", __func__, bandwidth , sg); ++ ++ padapter->mppriv.bandwidth = (u8)bandwidth; ++ padapter->mppriv.preamble = sg; ++ ++ SetBandwidth(padapter); ++ ++ return 0; ++} ++ ++static int rtw_mp_txpower(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u32 idx_a=0,idx_b=0,MsetPower=1; ++ u8 input[wrqu->length]; ++ ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ MsetPower = strncmp(input, "off", 3); ++ sscanf(input,"patha=%d,pathb=%d",&idx_a,&idx_b); ++ //DBG_871X("%s: tx_pwr_idx_a=%x b=%x\n", __func__, idx_a, idx_b); ++ if(MsetPower==0) ++ { ++ padapter->mppriv.bSetTxPower = 0; ++ sprintf( extra, "MP Set power off"); ++ } ++ else ++ { ++ sprintf( extra, "Set power level path_A:%d path_B:%d", idx_a , idx_b ); ++ padapter->mppriv.txpoweridx = (u8)idx_a; ++ padapter->mppriv.txpoweridx_b = (u8)idx_b; ++ padapter->mppriv.bSetTxPower = 1; ++ Hal_SetAntennaPathPower(padapter); ++ } ++ wrqu->length = strlen(extra) + 1; ++ return 0; ++} ++ ++static int rtw_mp_ant_tx(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u8 i; ++ u8 input[wrqu->length]; ++ u16 antenna = 0; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ //DBG_871X("%s: input=%s\n", __func__, input); ++ ++ sprintf( extra, "switch Tx antenna to %s", input ); ++ ++ for (i=0; i < strlen(input); i++) ++ { ++ switch(input[i]) ++ { ++ case 'a' : ++ antenna|=ANTENNA_A; ++ break; ++ case 'b': ++ antenna|=ANTENNA_B; ++ break; ++ } ++ } ++ //antenna |= BIT(extra[i]-'a'); ++ //DBG_871X("%s: antenna=0x%x\n", __func__, antenna); ++ padapter->mppriv.antenna_tx = antenna; ++ //DBG_871X("%s:mppriv.antenna_rx=%d\n", __func__, padapter->mppriv.antenna_tx); ++ ++ Hal_SetAntenna(padapter); ++ ++ wrqu->length = strlen(extra) + 1; ++ return 0; ++} ++ ++static int rtw_mp_ant_rx(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u8 i; ++ u16 antenna = 0; ++ u8 input[wrqu->length]; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ //DBG_871X("%s: input=%s\n", __func__, input); ++ _rtw_memset(extra, 0, wrqu->length); ++ ++ sprintf( extra, "switch Rx antenna to %s", input ); ++ ++ for (i=0; i < strlen(input); i++) { ++ ++ switch( input[i] ) ++ { ++ case 'a' : ++ antenna|=ANTENNA_A; ++ break; ++ case 'b': ++ antenna|=ANTENNA_B; ++ break; ++ } ++ } ++ ++ //DBG_871X("%s: antenna=0x%x\n", __func__, antenna); ++ padapter->mppriv.antenna_rx = antenna; ++ //DBG_871X("%s:mppriv.antenna_rx=%d\n", __func__, padapter->mppriv.antenna_rx); ++ Hal_SetAntenna(padapter); ++ wrqu->length = strlen(extra); ++ ++ return 0; ++} ++ ++static int rtw_mp_ctx(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u32 pkTx = 1, countPkTx = 1, cotuTx = 1, CarrSprTx = 1, scTx = 1, sgleTx = 1, stop = 1; ++ u32 bStartTest = 1; ++ u32 count = 0; ++ struct mp_priv *pmp_priv; ++ struct pkt_attrib *pattrib; ++ ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ ++ ++ pmp_priv = &padapter->mppriv; ++ ++ if (copy_from_user(extra, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ DBG_871X("%s: in=%s\n", __func__, extra); ++ ++ countPkTx = strncmp(extra, "count=", 5); // strncmp TRUE is 0 ++ cotuTx = strncmp(extra, "background", 20); ++ CarrSprTx = strncmp(extra, "background,cs", 20); ++ scTx = strncmp(extra, "background,sc", 20); ++ sgleTx = strncmp(extra, "background,stone", 20); ++ pkTx = strncmp(extra, "background,pkt", 20); ++ stop = strncmp(extra, "stop", 4); ++ sscanf(extra, "count=%d,pkt", &count); ++ ++ //DBG_871X("%s: count=%d countPkTx=%d cotuTx=%d CarrSprTx=%d scTx=%d sgleTx=%d pkTx=%d stop=%d\n", __func__, count, countPkTx, cotuTx, CarrSprTx, pkTx, sgleTx, scTx, stop); ++ _rtw_memset(extra, '\0', sizeof(extra)); ++ ++ if (stop == 0) { ++ bStartTest = 0; // To set Stop ++ pmp_priv->tx.stop = 1; ++ sprintf( extra, "Stop continuous Tx"); ++ } else { ++ bStartTest = 1; ++ if (pmp_priv->mode != MP_ON) { ++ if (pmp_priv->tx.stop != 1) { ++ DBG_871X("%s: MP_MODE != ON %d\n", __func__, pmp_priv->mode); ++ return -EFAULT; ++ } ++ } ++ } ++ ++ if (pkTx == 0 || countPkTx == 0) ++ pmp_priv->mode = MP_PACKET_TX; ++ if (sgleTx == 0) ++ pmp_priv->mode = MP_SINGLE_TONE_TX; ++ if (cotuTx == 0) ++ pmp_priv->mode = MP_CONTINUOUS_TX; ++ if (CarrSprTx == 0) ++ pmp_priv->mode = MP_CARRIER_SUPPRISSION_TX; ++ if (scTx == 0) ++ pmp_priv->mode = MP_SINGLE_CARRIER_TX; ++ ++ switch (pmp_priv->mode) ++ { ++ case MP_PACKET_TX: ++ ++ //DBG_871X("%s:pkTx %d\n", __func__,bStartTest); ++ if (bStartTest == 0) ++ { ++ pmp_priv->tx.stop = 1; ++ pmp_priv->mode = MP_ON; ++ sprintf( extra, "Stop continuous Tx"); ++ } ++ else if (pmp_priv->tx.stop == 1) ++ { ++ sprintf( extra, "Start continuous DA=ffffffffffff len=1500 count=%u,\n",count); ++ //DBG_871X("%s:countPkTx %d\n", __func__,count); ++ pmp_priv->tx.stop = 0; ++ pmp_priv->tx.count = count; ++ pmp_priv->tx.payload = 2; ++ pattrib = &pmp_priv->tx.attrib; ++ pattrib->pktlen = 1500; ++ _rtw_memset(pattrib->dst, 0xFF, ETH_ALEN); ++ SetPacketTx(padapter); ++ } ++ else { ++ //DBG_871X("%s: pkTx not stop\n", __func__); ++ return -EFAULT; ++ } ++ wrqu->length = strlen(extra); ++ return 0; ++ ++ case MP_SINGLE_TONE_TX: ++ //DBG_871X("%s: sgleTx %d \n", __func__, bStartTest); ++ if (bStartTest != 0){ ++ sprintf( extra, "Start continuous DA=ffffffffffff len=1500 \n infinite=yes."); ++ } ++ Hal_SetSingleToneTx(padapter, (u8)bStartTest); ++ break; ++ ++ case MP_CONTINUOUS_TX: ++ //DBG_871X("%s: cotuTx %d\n", __func__, bStartTest); ++ if (bStartTest != 0){ ++ sprintf( extra, "Start continuous DA=ffffffffffff len=1500 \n infinite=yes."); ++ } ++ Hal_SetContinuousTx(padapter, (u8)bStartTest); ++ break; ++ ++ case MP_CARRIER_SUPPRISSION_TX: ++ //DBG_871X("%s: CarrSprTx %d\n", __func__, bStartTest); ++ if (bStartTest != 0){ ++ if( pmp_priv->rateidx <= MPT_RATE_11M ) ++ { ++ sprintf( extra, "Start continuous DA=ffffffffffff len=1500 \n infinite=yes."); ++ Hal_SetCarrierSuppressionTx(padapter, (u8)bStartTest); ++ }else ++ sprintf( extra, "Specify carrier suppression but not CCK rate"); ++ } ++ break; ++ ++ case MP_SINGLE_CARRIER_TX: ++ //DBG_871X("%s: scTx %d\n", __func__, bStartTest); ++ if (bStartTest != 0){ ++ sprintf( extra, "Start continuous DA=ffffffffffff len=1500 \n infinite=yes."); ++ } ++ Hal_SetSingleCarrierTx(padapter, (u8)bStartTest); ++ break; ++ ++ default: ++ //DBG_871X("%s:No Match MP_MODE\n", __func__); ++ sprintf( extra, "Error! Continuous-Tx is not on-going."); ++ return -EFAULT; ++ } ++ ++ if ( bStartTest==1 && pmp_priv->mode != MP_ON) { ++ struct mp_priv *pmp_priv = &padapter->mppriv; ++ if (pmp_priv->tx.stop == 0) { ++ pmp_priv->tx.stop = 1; ++ //DBG_871X("%s: pkt tx is running...\n", __func__); ++ rtw_msleep_os(5); ++ } ++ pmp_priv->tx.stop = 0; ++ pmp_priv->tx.count = 1; ++ SetPacketTx(padapter); ++ } else { ++ pmp_priv->mode = MP_ON; ++ } ++ ++ wrqu->length = strlen(extra); ++ return 0; ++} ++ ++ ++static int rtw_mp_disable_bt_coexist(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PADAPTER padapter = (PADAPTER)rtw_netdev_priv(dev); ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ struct hal_ops *pHalFunc = &padapter->HalFunc; ++ ++ u8 input[wrqu->data.length]; ++ u32 bt_coexist; ++ ++#ifdef CONFIG_BT_COEXIST ++ PBT30Info pBTInfo; ++ PBT_MGNT pBtMgnt; ++ ++ pBTInfo = GET_BT_INFO(padapter); ++ pBtMgnt = &pBTInfo->BtMgnt; ++#endif ++ if (copy_from_user(input, wrqu->data.pointer, wrqu->data.length)) ++ return -EFAULT; ++ ++ bt_coexist = rtw_atoi(input); ++ ++ if( bt_coexist == 0 ) ++ { ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("Set OID_RT_SET_DISABLE_BT_COEXIST: disable BT_COEXIST\n")); ++ DBG_871X("Set OID_RT_SET_DISABLE_BT_COEXIST: disable BT_COEXIST\n"); ++#ifdef CONFIG_BT_COEXIST ++ pHalData->bt_coexist.BluetoothCoexist = 0; ++ pBtMgnt->ExtConfig.bManualControl = _TRUE; ++ pdmpriv->DMFlag &= (~DYNAMIC_FUNC_BT); ++ BT_HaltProcess(padapter); ++#if 1 ++ padapter->registrypriv.mp_mode=0; ++ pHalFunc->hal_init(padapter); ++ padapter->registrypriv.mp_mode=1; ++#endif ++ // Force to switch Antenna to WiFi ++ rtw_write16(padapter, 0x870, 0x300); ++ rtw_write16(padapter, 0x860, 0x110); ++#endif ++ //BT_SetManualControl(pAdapter, TRUE); ++ } ++ else ++ { ++ RT_TRACE(_module_mp_, _drv_info_, ++ ("Set OID_RT_SET_DISABLE_BT_COEXIST: enable BT_COEXIST\n")); ++#ifdef CONFIG_BT_COEXIST ++ pBtMgnt->ExtConfig.bManualControl = _FALSE; ++#endif ++ //BT_SetManualControl(pAdapter, FALSE); ++ } ++ ++ return 0; ++} ++ ++ ++static int rtw_mp_arx(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u8 bStartRx=0,bStopRx=0,bQueryPhy=0,bQueryMac=0; ++ u32 cckok=0,cckcrc=0,ofdmok=0,ofdmcrc=0,htok=0,htcrc=0,OFDM_FA=0,CCK_FA=0,DropPacket=0,vht_ok=0,vht_err=0; ++ u8 input[wrqu->length]; ++ u32 mac_cck_ok=0, mac_ofdm_ok=0, mac_ht_ok=0, mac_vht_ok=0; ++ u32 mac_cck_err=0, mac_ofdm_err=0, mac_ht_err=0, mac_vht_err=0; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ ++ ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ DBG_871X("%s: %s\n", __func__, input); ++ ++ bStartRx = (strncmp(input, "start", 5)==0)?1:0; // strncmp TRUE is 0 ++ bStopRx = (strncmp(input, "stop", 5)==0)?1:0; // strncmp TRUE is 0 ++ bQueryPhy = (strncmp(input, "phy", 3)==0)?1:0; // strncmp TRUE is 0 ++ bQueryMac = (strncmp(input, "mac", 3)==0)?1:0; // strncmp TRUE is 0 ++ ++ if(bStartRx) ++ { ++ sprintf( extra, "start"); ++ SetPacketRx(padapter, bStartRx); ++ } ++ else if(bStopRx) ++ { ++ SetPacketRx(padapter, 0); ++ sprintf( extra, "Received packet OK:%d CRC error:%d",padapter->mppriv.rx_pktcount,padapter->mppriv.rx_crcerrpktcount); ++ } ++ else if(bQueryPhy) ++ { ++ ++ //if (IS_HARDWARE_TYPE_JAGUAR(padapter)) ++ #ifdef CONFIG_RTL8188A ++ { ++ cckok = PHY_QueryBBReg(padapter, 0xF04, 0x3FFF); // [13:0] ++ ofdmok = PHY_QueryBBReg(padapter, 0xF14, 0x3FFF); // [13:0] ++ htok = PHY_QueryBBReg(padapter, 0xF10, 0x3FFF); // [13:0] ++ vht_ok = PHY_QueryBBReg(padapter, 0xF0C, 0x3FFF); // [13:0] ++ ++ cckcrc = PHY_QueryBBReg(padapter, 0xF04, 0x3FFF0000); // [29:16] ++ ofdmcrc = PHY_QueryBBReg(padapter, 0xF14, 0x3FFF0000); // [29:16] ++ htcrc = PHY_QueryBBReg(padapter, 0xF10, 0x3FFF0000); // [29:16] ++ vht_err = PHY_QueryBBReg(padapter, 0xF0C, 0x3FFF0000); // [29:16] ++ } ++ #else ++ { ++ cckok = PHY_QueryBBReg(padapter, 0xF88, bMaskDWord); ++ ofdmok = PHY_QueryBBReg(padapter, 0xF94, bMaskLWord); ++ htok = PHY_QueryBBReg(padapter, 0xF90, bMaskLWord); ++ vht_ok = 0; ++ ++ cckcrc = PHY_QueryBBReg(padapter, 0xF84, bMaskDWord); ++ ofdmcrc = PHY_QueryBBReg(padapter, 0xF94, bMaskHWord); ++ htcrc = PHY_QueryBBReg(padapter, 0xF90, bMaskHWord); ++ vht_err = 0; ++ } ++ #endif ++ CCK_FA=(rtw_read8(padapter, 0xa5b )<<8 ) | (rtw_read8(padapter, 0xa5c)); ++ sprintf( extra, "Phy Received packet OK:%d CRC error:%d FA Counter: %d",cckok+ofdmok+htok+vht_ok,cckcrc+ofdmcrc+htcrc+vht_err,OFDM_FA+CCK_FA); ++ } ++ else if(bQueryMac) ++ { ++ ++ // for 8723A ++ { ++ PHY_SetMacReg(padapter, 0x664, BIT28|BIT29|BIT30|BIT31, 0x3); ++ mac_cck_ok = PHY_QueryMacReg(padapter, 0x664, bMaskLWord); // [15:0] ++ PHY_SetMacReg(padapter, 0x664, BIT28|BIT29|BIT30|BIT31, 0x0); ++ mac_ofdm_ok = PHY_QueryMacReg(padapter, 0x664, bMaskLWord); // [15:0] ++ PHY_SetMacReg(padapter, 0x664, BIT28|BIT29|BIT30|BIT31, 0x6); ++ mac_ht_ok = PHY_QueryMacReg(padapter, 0x664, bMaskLWord); // [15:0] ++ mac_vht_ok = 0; ++ ++ PHY_SetMacReg(padapter, 0x664, BIT28|BIT29|BIT30|BIT31, 0x4); ++ mac_cck_err = PHY_QueryMacReg(padapter, 0x664, bMaskLWord); // [15:0] ++ PHY_SetMacReg(padapter, 0x664, BIT28|BIT29|BIT30|BIT31, 0x1); ++ mac_ofdm_err = PHY_QueryMacReg(padapter, 0x664, bMaskLWord); // [15:0] ++ PHY_SetMacReg(padapter, 0x664, BIT28|BIT29|BIT30|BIT31, 0x7); ++ mac_ht_err = PHY_QueryMacReg(padapter, 0x664, bMaskLWord); // [15:0] ++ mac_vht_err = 0; ++ //Mac_DropPacket ++ rtw_write32(padapter, 0x664, (rtw_read32(padapter, 0x0664)& 0x0FFFFFFF)| Mac_DropPacket); ++ DropPacket = rtw_read32(padapter, 0x664)& 0x0000FFFF; ++ } ++ ++ sprintf( extra, "Mac Received packet OK: %d , CRC error: %d , FA Counter: %d , Drop Packets: %d\n", ++ mac_cck_ok+mac_ofdm_ok+mac_ht_ok+mac_vht_ok,mac_cck_err+mac_ofdm_err+mac_ht_err+mac_vht_err,OFDM_FA+CCK_FA,DropPacket); ++ } ++ wrqu->length = strlen(extra) + 1; ++ return 0; ++} ++ ++static int rtw_mp_trx_query(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u32 txok,txfail,rxok,rxfail; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ //if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) ++ // return -EFAULT; ++ ++ txok=padapter->mppriv.tx.sended; ++ txfail=0; ++ rxok = padapter->mppriv.rx_pktcount; ++ rxfail = padapter->mppriv.rx_crcerrpktcount; ++ ++ _rtw_memset(extra, '\0', 128); ++ ++ sprintf(extra, "Tx OK:%d, Tx Fail:%d, Rx OK:%d, CRC error:%d ", txok, txfail,rxok,rxfail); ++ ++ wrqu->length=strlen(extra)+1; ++ ++ return 0; ++} ++ ++static int rtw_mp_pwrtrk(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u8 enable; ++ u32 thermal; ++ s32 ret; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ u8 input[wrqu->length]; ++ ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ _rtw_memset(extra, 0, wrqu->length); ++ ++ enable = 1; ++ if (wrqu->length > 1) { // not empty string ++ if (strncmp(input, "stop", 4) == 0) ++ { ++ enable = 0; ++ sprintf(extra, "mp tx power tracking stop"); ++ } ++ else if (sscanf(input, "ther=%d", &thermal)) { ++ ret = Hal_SetThermalMeter(padapter, (u8)thermal); ++ if (ret == _FAIL) return -EPERM; ++ sprintf(extra, "mp tx power tracking start,target value=%d ok ",thermal); ++ }else { ++ return -EINVAL; ++ } ++ } ++ ++ ret = Hal_SetPowerTracking(padapter, enable); ++ if (ret == _FAIL) return -EPERM; ++ ++ wrqu->length = strlen(extra); ++ ++ return 0; ++} ++ ++static int rtw_mp_psd(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ u8 input[wrqu->length]; ++ ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ strcpy(extra,input); ++ ++ wrqu->length = mp_query_psd(padapter, extra); ++ ++ return 0; ++} ++ ++static int rtw_mp_thermal(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u8 val; ++ u16 bwrite=1; ++ ++ #if defined(CONFIG_RTL8192C) || defined(CONFIG_RTL8192D) ++ u16 addr=EEPROM_THERMAL_METER; ++ #endif ++ #ifdef CONFIG_RTL8723A ++ u16 addr=EEPROM_THERMAL_METER_8723A; ++ #endif ++ #if defined(CONFIG_RTL8188E) ++ u16 addr=EEPROM_THERMAL_METER_88E; ++ #endif ++ ++ u16 cnt=1; ++ u16 max_available_size=0; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ ++ if (copy_from_user(extra, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ //DBG_871X("print extra %s \n",extra); ++ ++ bwrite = strncmp(extra, "write", 6); // strncmp TRUE is 0 ++ ++ Hal_GetThermalMeter(padapter, &val); ++ ++ if( bwrite == 0 ) ++ { ++ //DBG_871X("to write val:%d",val); ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_available_size, _FALSE); ++ if( 2 > max_available_size ) ++ { ++ DBG_871X("no available efuse!\n"); ++ return -EFAULT; ++ } ++ if ( rtw_efuse_map_write(padapter, addr, cnt, &val) == _FAIL ) ++ { ++ DBG_871X("rtw_efuse_map_write error \n"); ++ return -EFAULT; ++ } ++ else ++ { ++ sprintf(extra, " efuse write ok :%d", val); ++ } ++ } ++ else ++ { ++ sprintf(extra, "%d", val); ++ } ++ wrqu->length = strlen(extra); ++ ++ return 0; ++} ++ ++static int rtw_mp_reset_stats(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ struct mp_priv *pmp_priv; ++ struct pkt_attrib *pattrib; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ ++ pmp_priv = &padapter->mppriv; ++ ++ pmp_priv->tx.sended = 0; ++ pmp_priv->tx_pktcount = 0; ++ pmp_priv->rx_pktcount = 0; ++ pmp_priv->rx_crcerrpktcount = 0; ++ ++ //reset phy counter ++ write_bbreg(padapter,0xf14,BIT16,0x1); ++ rtw_msleep_os(10); ++ write_bbreg(padapter,0xf14,BIT16,0x0); ++ //reset mac counter ++ PHY_SetMacReg(padapter, 0x664, BIT27, 0x1); ++ PHY_SetMacReg(padapter, 0x664, BIT27, 0x0); ++ return 0; ++} ++ ++static int rtw_mp_dump(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u32 value,i,j=1,path; ++ u8 input[wrqu->length]; ++ u8 rf_type,path_nums = 0; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ struct mp_priv *pmp_priv; ++ struct pkt_attrib *pattrib; ++ ++ pmp_priv = &padapter->mppriv; ++ ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ if ( strncmp(input, "all", 4)==0 ) ++ { ++ printk("\n======= MAC REG =======\n"); ++ for ( i=0x0;i<0x300;i+=4 ) ++ { ++ if(j%4==1) printk("0x%02x ",i); ++ printk(" 0x%08x ",rtw_read32(padapter,i)); ++ if((j++)%4 == 0) printk("\n"); ++ } ++ for( i=0x400;i<0x1000;i+=4 ) ++ { ++ if(j%4==1) DBG_871X("0x%02x",i); ++ printk(" 0x%08x ",rtw_read32(padapter,i)); ++ if((j++)%4 == 0) printk("\n"); ++ } ++ ++ i,j=1; ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ bb_reg_dump(padapter); ++ rf_reg_dump(padapter); ++ /* ++ printk("\n======= RF REG =======\n"); ++ if(( RF_1T2R == rf_type ) ||( RF_1T1R ==rf_type )) ++ path_nums = 1; ++ else ++ path_nums = 2; ++ ++ for(path=0;pathlength]; ++ u32 valxcap; ++ ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ DBG_871X("%s:iwpriv in=%s\n", __func__, input); ++ ++ sscanf(input, "xcap=%d", &valxcap); ++ ++ Hal_ProSetCrystalCap( padapter , valxcap ); ++ ++ sprintf( extra, "Set xcap=%d",valxcap ); ++ wrqu->length = strlen(extra) + 1; ++ ++return 0; ++ ++} ++ ++static int rtw_mp_SetRFPath(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ char input[wrqu->data.length]; ++ u8 bMain=1,bTurnoff=1; ++ ++ if (copy_from_user(input, wrqu->data.pointer, wrqu->data.length)) ++ return -EFAULT; ++ DBG_871X("%s:iwpriv in=%s\n", __func__, input); ++ ++ bMain = strncmp(input, "1", 2); // strncmp TRUE is 0 ++ bTurnoff = strncmp(input, "0", 3); // strncmp TRUE is 0 ++ ++ if(bMain==0) ++ { ++ MP_PHY_SetRFPathSwitch(padapter,_TRUE); ++ DBG_871X("%s:PHY_SetRFPathSwitch=TRUE\n", __func__); ++ } ++ else if(bTurnoff==0) ++ { ++ MP_PHY_SetRFPathSwitch(padapter,_FALSE); ++ DBG_871X("%s:PHY_SetRFPathSwitch=FALSE\n", __func__); ++ } ++ ++ return 0; ++} ++ ++static int rtw_mp_QueryDrv(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ char input[wrqu->data.length]; ++ u8 qAutoLoad=1; ++ ++ EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ ++ if (copy_from_user(input, wrqu->data.pointer, wrqu->data.length)) ++ return -EFAULT; ++ DBG_871X("%s:iwpriv in=%s\n", __func__, input); ++ ++ qAutoLoad = strncmp(input, "autoload", 8); // strncmp TRUE is 0 ++ ++ if(qAutoLoad==0) ++ { ++ DBG_871X("%s:qAutoLoad\n", __func__); ++ ++ if(pEEPROM->bautoload_fail_flag) ++ sprintf(extra, "fail"); ++ else ++ sprintf(extra, "ok"); ++ } ++ wrqu->data.length = strlen(extra) + 1; ++ return 0; ++} ++ ++/* update Tx AGC offset */ ++static int rtw_mp_antBdiff(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ ++ ++ // MPT_ProSetTxAGCOffset ++ return 0; ++} ++ ++ ++static int rtw_mp_PwrCtlDM(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ u8 input[wrqu->length]; ++ u8 bstart=1; ++ ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ bstart = strncmp(input, "start", 5); // strncmp TRUE is 0 ++ if(bstart==0){ ++ sprintf(extra, "PwrCtlDM start \n"); ++ MPT_PwrCtlDM(padapter,1); ++ }else{ ++ sprintf(extra, "PwrCtlDM stop \n"); ++ MPT_PwrCtlDM(padapter,0); ++ } ++ wrqu->length = strlen(extra); ++ ++ return 0; ++} ++ ++ ++#ifdef CONFIG_RTL8723A ++ ++/* update Tx AGC offset */ ++static int rtw_mp_SetBT(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ struct hal_ops *pHalFunc = &padapter->HalFunc; ++ ++ BT_REQ_CMD BtReq; ++ PMPT_CONTEXT pMptCtx=&(padapter->mppriv.MptCtx); ++ PBT_RSP_CMD pBtRsp=(PBT_RSP_CMD)&pMptCtx->mptOutBuf[0]; ++ char input[128]; ++ char *pch, *ptmp, *token, *tmp[2]={0x00,0x00}; ++ u8 setdata[100]; ++ u8 resetbt=0x00; ++ u8 H2cSetbtmac[6]; ++ ++ u16 testmode=1,ready=1,trxparam=1,setgen=1,getgen=1,testctrl=1,testbt=1,readtherm=1,setbtmac=1; ++ u32 i,ii,jj,kk,cnts,status; ++ PRT_FIRMWARE_8723A pBTFirmware = NULL; ++ ++ if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) ++ return -EFAULT; ++ if(strlen(extra)<1) return -EFAULT; ++ ++ DBG_871X("%s:iwpriv in=%s\n", __func__, extra); ++ ready = strncmp(extra, "ready", 5); ++ testmode = strncmp(extra, "testmode", 8); // strncmp TRUE is 0 ++ trxparam = strncmp(extra, "trxparam", 8); ++ setgen = strncmp(extra, "setgen", 6); ++ getgen = strncmp(extra, "getgen", 6); ++ testctrl = strncmp(extra, "testctrl", 8); ++ testbt = strncmp(extra, "testbt", 6); ++ readtherm = strncmp(extra, "readtherm", 9); ++ setbtmac = strncmp(extra, "setbtmac", 8); ++ ++ if ( strncmp(extra, "dlfw", 4) == 0) ++ { ++ padapter->registrypriv.mp_mode =0; ++ pHalFunc->hal_init(padapter); ++ padapter->registrypriv.mp_mode =1; ++ MPT_PwrCtlDM(padapter,0); ++ rtw_write32(padapter, 0xcc, (rtw_read32(padapter, 0xcc)| 0x00000004)); ++ rtw_write32(padapter, 0x6b, (rtw_read32(padapter, 0x6b)& 0xFFFFFFEF)); ++ rtw_msleep_os(600); ++ //rtw_write32(padapter, 0x6a, (rtw_read32(padapter, 0x6a)& 0xFFFFFFFE)); ++ rtw_write32(padapter, 0x6b, (rtw_read32(padapter, 0x6b)| 0x00000010)); ++ rtw_write32(padapter, 0xcc, (rtw_read32(padapter, 0xcc)& 0xFFFFFFFB)); ++ rtw_msleep_os(1200); ++ ++ DBG_871X("padapter->bBTFWReady == _FALSE rtl8723a_FirmwareDownload !\n"); ++ status = rtl8723a_FirmwareDownload(padapter); ++ #if 0 ++ FillH2CCmd(padapter, 0x32, 1, &resetbt); ++ rtw_msleep_os(1000); ++ ++ if(padapter->bBTFWReady == _FALSE && padapter->registrypriv.mp_mode == 1) ++ { ++ //pMptCtx->h2cReqNum=0; ++ DBG_871X("padapter->bBTFWReady == _FALSE rtl8723a_FirmwareDownload !\n"); ++ status = rtl8723a_FirmwareDownload(padapter); ++ } ++ else ++ { ++ pBTFirmware = (PRT_FIRMWARE_8723A)rtw_zmalloc(sizeof(RT_FIRMWARE_8723A)); ++ DBG_871X("rtl8723a_FirmwareDownload go to FirmwareDownloadBT !\n"); ++ FirmwareDownloadBT(padapter, pBTFirmware); ++ if (pBTFirmware) ++ rtw_mfree((u8*)pBTFirmware, sizeof(RT_FIRMWARE_8723A)); ++ } ++ #endif ++ DBG_871X("Wait for FirmwareDownloadBT fw boot!\n"); ++ rtw_msleep_os(1000); ++ _rtw_memset(extra,'\0', wrqu->data.length); ++ BtReq.opCodeVer=1; ++ BtReq.OpCode=0; ++ BtReq.paraLength=0; ++ mptbt_BtControlProcess(padapter,&BtReq); ++ rtw_msleep_os(100); ++ for (i=4; imptOutLen; i++) ++ { ++ DBG_8192C("FirmwareDownloadBT ready = 0x%x ", pMptCtx->mptOutBuf[i]); ++ if( (pMptCtx->mptOutBuf[i]==0x00) && (pMptCtx->mptOutBuf[i+1]==0x00)) ++ { ++ sprintf(extra, "download FW Fail.\n"); ++ } ++ else ++ { ++ sprintf(extra, "download FW OK.\n"); ++ goto exit; ++ } ++ } ++ ++ goto exit; ++ } ++ ++ if ( strncmp(extra, "down", 4) == 0){ ++ DBG_871X("SetBT down for to hal_init !\n"); ++ mp_stop_test(padapter); ++ pHalFunc->hal_init(padapter); ++ mp_start_test(padapter); ++ MPT_PwrCtlDM(padapter,0); ++ rtw_write32(padapter, 0xcc, (rtw_read32(padapter, 0xcc)| 0x00000004)); ++ rtw_write32(padapter, 0x6b, (rtw_read32(padapter, 0x6b)& 0xFFFFFFEF)); ++ rtw_msleep_os(600); ++ //rtw_write32(padapter, 0x6a, (rtw_read32(padapter, 0x6a)& 0xFFFFFFFE)); ++ rtw_write32(padapter, 0x6b, (rtw_read32(padapter, 0x6b)| 0x00000010)); ++ rtw_write32(padapter, 0xcc, (rtw_read32(padapter, 0xcc)& 0xFFFFFFFB)); ++ rtw_msleep_os(1200); ++ goto exit; ++ } ++ if ( strncmp(extra, "disable", 4) == 0){ ++ DBG_871X("SetBT enable !\n"); ++ rtw_write32(padapter, 0x6a, (rtw_read32(padapter, 0x6a)& 0xFFFFFFFB)); ++ rtw_msleep_os(500); ++ goto exit; ++ } ++ if ( strncmp(extra, "enable", 4) == 0){ ++ DBG_871X("SetBT disable !\n"); ++ rtw_write32(padapter, 0x6a, (rtw_read32(padapter, 0x6a)| 0x00000004)); ++ rtw_msleep_os(500); ++ goto exit; ++ } ++ ++ if( ready!=0 && testmode!=0 && trxparam!=0 && setgen!=0 && getgen!=0 && testctrl!=0 && testbt!=0 && readtherm!=0 &&setbtmac!=0) ++ return -EFAULT; ++ ++ if( testbt==0 ) ++ { ++ BtReq.opCodeVer=1; ++ BtReq.OpCode=6; ++ BtReq.paraLength=cnts/2; ++ goto todo; ++ } ++ if( ready==0 ) ++ { ++ BtReq.opCodeVer=1; ++ BtReq.OpCode=0; ++ BtReq.paraLength=0; ++ goto todo; ++ } ++ ++ DBG_871X("%s:after strncmp\n", __func__); ++ pch = extra; ++ i = 0; ++ while ((token = strsep(&pch, ",")) != NULL) ++ { ++ if (i > 1) break; ++ tmp[i] = token; ++ i++; ++ } ++ ++ if ((tmp[0]==NULL) && (tmp[1]==NULL)) ++ { ++ return -EFAULT; ++ } ++ else ++ { ++ cnts = strlen(tmp[1]); ++ if (cnts<1) return -EFAULT; ++ ++ DBG_871X("%s: cnts=%d\n", __FUNCTION__, cnts); ++ DBG_871X("%s: data=%s\n", __FUNCTION__, tmp[1]); ++ ++ for (jj=0, kk=0; jjdata.length); ++ ++ mptbt_BtControlProcess(padapter,&BtReq); ++ ++ if(readtherm==0){ ++ sprintf(extra,"BT thermal="); ++ for (i=4; imptOutLen; i++) ++ { ++ if( (pMptCtx->mptOutBuf[i]==0x00) && (pMptCtx->mptOutBuf[i+1]==0x00)) ++ goto exit; ++ DBG_8192C("0x%x ", pMptCtx->mptOutBuf[i]); ++ sprintf(extra, "%s %d ", extra, pMptCtx->mptOutBuf[i]); ++ } ++ }else{ ++ for (i=4; imptOutLen; i++) ++ { ++ DBG_8192C("0x%x ", pMptCtx->mptOutBuf[i]); ++ sprintf(extra, "%s 0x%x ", extra, pMptCtx->mptOutBuf[i]); ++ } ++ } ++ ++exit: ++ wrqu->data.length = strlen(extra) + 1; ++ ++return status; ++ ++} ++ ++#endif //#ifdef CONFIG_RTL8723A ++ ++static int rtw_mp_set(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wdata, char *extra) ++{ ++ struct iw_point *wrqu = (struct iw_point *)wdata; ++ u32 subcmd = wrqu->flags; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ ++ if (padapter == NULL) ++ { ++ return -ENETDOWN; ++ } ++ ++ if((padapter->bup == _FALSE )||(padapter->hw_init_completed == _FALSE)) ++ { ++ DBG_871X(" %s fail =>(padapter->bup == _FALSE )||(padapter->hw_init_completed == _FALSE) \n",__FUNCTION__); ++ return -ENETDOWN; ++ } ++ ++ if( (padapter->bSurpriseRemoved == _TRUE) || ( padapter->bDriverStopped == _TRUE)) ++ { ++ DBG_871X("%s fail =>(padapter->bSurpriseRemoved == _TRUE) || ( padapter->bDriverStopped == _TRUE) \n",__FUNCTION__); ++ return -ENETDOWN; ++ } ++ ++ //_rtw_memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ ++ if (extra == NULL) ++ { ++ wrqu->length = 0; ++ return -EIO; ++ } ++ ++ switch(subcmd) ++ { ++ case MP_START: ++ DBG_871X("set case mp_start \n"); ++ rtw_mp_start (dev,info,wrqu,extra); ++ break; ++ ++ case MP_STOP: ++ DBG_871X("set case mp_stop \n"); ++ rtw_mp_stop (dev,info,wrqu,extra); ++ break; ++ ++ case MP_BANDWIDTH: ++ DBG_871X("set case mp_bandwidth \n"); ++ rtw_mp_bandwidth (dev,info,wrqu,extra); ++ break; ++ ++ case MP_RESET_STATS: ++ DBG_871X("set case MP_RESET_STATS \n"); ++ rtw_mp_reset_stats (dev,info,wrqu,extra); ++ break; ++ case MP_SetRFPathSwh: ++ DBG_871X("set MP_SetRFPathSwitch \n"); ++ rtw_mp_SetRFPath (dev,info,wdata,extra); ++ break; ++ case CTA_TEST: ++ DBG_871X("set CTA_TEST\n"); ++ rtw_cta_test_start (dev, info, wdata, extra); ++ break; ++ case MP_DISABLE_BT_COEXIST: ++ DBG_871X("set case MP_DISABLE_BT_COEXIST \n"); ++ rtw_mp_disable_bt_coexist(dev, info, wdata, extra); ++ break; ++#ifdef CONFIG_WOWLAN ++ case MP_WOW_ENABLE: ++ DBG_871X("set case MP_WOW_ENABLE: %s \n", extra); ++ rtw_wowlan_ctrl(dev, info, wdata, extra); ++ break; ++#endif ++ } ++ ++ ++ return 0; ++} ++ ++ ++static int rtw_mp_get(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wdata, char *extra) ++{ ++ struct iw_point *wrqu = (struct iw_point *)wdata; ++ u32 subcmd = wrqu->flags; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ ++ //DBG_871X("in mp_get extra= %s \n",extra); ++ ++ if (padapter == NULL) ++ { ++ return -ENETDOWN; ++ } ++ if (extra == NULL) ++ { ++ wrqu->length = 0; ++ return -EIO; ++ } ++ ++ switch(subcmd) ++ { ++ case WRITE_REG : ++ rtw_mp_write_reg (dev,info,wrqu,extra); ++ break; ++ ++ case WRITE_RF: ++ rtw_mp_write_rf (dev,info,wrqu,extra); ++ break; ++ ++ case MP_PHYPARA: ++ DBG_871X("mp_get MP_PHYPARA \n"); ++ rtw_mp_phypara(dev,info,wrqu,extra); ++ break; ++ ++ case MP_CHANNEL: ++ DBG_871X("set case mp_channel \n"); ++ rtw_mp_channel (dev,info,wrqu,extra); ++ break; ++ ++ case READ_REG: ++ DBG_871X("mp_get READ_REG \n"); ++ rtw_mp_read_reg (dev,info,wrqu,extra); ++ break; ++ case READ_RF: ++ DBG_871X("mp_get READ_RF \n"); ++ rtw_mp_read_rf (dev,info,wrqu,extra); ++ break; ++ ++ case MP_RATE: ++ DBG_871X("set case mp_rate \n"); ++ rtw_mp_rate (dev,info,wrqu,extra); ++ break; ++ ++ case MP_TXPOWER: ++ DBG_871X("set case MP_TXPOWER \n"); ++ rtw_mp_txpower (dev,info,wrqu,extra); ++ break; ++ ++ case MP_ANT_TX: ++ DBG_871X("set case MP_ANT_TX \n"); ++ rtw_mp_ant_tx (dev,info,wrqu,extra); ++ break; ++ ++ case MP_ANT_RX: ++ DBG_871X("set case MP_ANT_RX \n"); ++ rtw_mp_ant_rx (dev,info,wrqu,extra); ++ break; ++ ++ case MP_QUERY: ++ //DBG_871X("mp_get mp_query MP_QUERY \n"); ++ rtw_mp_trx_query(dev,info,wrqu,extra); ++ break; ++ ++ case MP_CTX: ++ DBG_871X("set case MP_CTX \n"); ++ rtw_mp_ctx (dev,info,wrqu,extra); ++ break; ++ ++ case MP_ARX: ++ DBG_871X("set case MP_ARX \n"); ++ rtw_mp_arx (dev,info,wrqu,extra); ++ break; ++ ++ case EFUSE_GET: ++ DBG_871X("efuse get EFUSE_GET \n"); ++ rtw_mp_efuse_get(dev,info,wdata,extra); ++ break; ++ ++ case MP_DUMP: ++ DBG_871X("set case MP_DUMP \n"); ++ rtw_mp_dump (dev,info,wrqu,extra); ++ break; ++ case MP_PSD: ++ DBG_871X("set case MP_PSD \n"); ++ rtw_mp_psd (dev,info,wrqu,extra); ++ break; ++ case MP_THER: ++ DBG_871X("set case MP_THER \n"); ++ rtw_mp_thermal (dev,info,wrqu,extra); ++ break; ++ case MP_PwrCtlDM: ++ DBG_871X("set MP_PwrCtlDM\n"); ++ rtw_mp_PwrCtlDM (dev,info,wrqu,extra); ++ break; ++ case MP_QueryDrvStats: ++ DBG_871X("mp_get MP_QueryDrvStats \n"); ++ rtw_mp_QueryDrv (dev,info,wdata,extra); ++ break; ++ case MP_PWRTRK: ++ DBG_871X("set case MP_PWRTRK \n"); ++ rtw_mp_pwrtrk (dev,info,wrqu,extra); ++ break; ++ case EFUSE_SET: ++ DBG_871X("set case efuse set \n"); ++ rtw_mp_efuse_set (dev,info,wdata,extra); ++ break; ++ ++#ifdef CONFIG_RTL8723A ++ case MP_SetBT: ++ DBG_871X("set MP_SetBT \n"); ++ rtw_mp_SetBT (dev,info,wdata,extra); ++ break; ++#endif ++ ++ } ++ ++ rtw_msleep_os(10); //delay 5ms for sending pkt before exit adb shell operation ++return 0; ++} ++ ++#endif //#if defined(CONFIG_MP_INCLUDED) && defined(CONFIG_MP_IWPRIV_SUPPORT) ++ ++static int rtw_wfd_tdls_enable(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_TDLS ++#ifdef CONFIG_WFD ++ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ printk( "[%s] %s %d\n", __FUNCTION__, extra, wrqu->data.length -1 ); ++ ++ if ( extra[ 0 ] == '0' ) ++ { ++ padapter->wdinfo.wfd_tdls_enable = 0; ++ } ++ else ++ { ++ padapter->wdinfo.wfd_tdls_enable = 1; ++ } ++ ++#endif //CONFIG_WFD ++#endif //CONFIG_TDLS ++ ++ return ret; ++} ++ ++static int rtw_tdls_weaksec(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_TDLS ++ ++ u8 i, j; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ DBG_871X( "[%s] %s %d\n", __FUNCTION__, extra, wrqu->data.length -1 ); ++ ++ if ( extra[ 0 ] == '0' ) ++ { ++ padapter->wdinfo.wfd_tdls_weaksec = 0; ++ } ++ else ++ { ++ padapter->wdinfo.wfd_tdls_weaksec = 1; ++ } ++#endif ++ ++ return ret; ++} ++ ++ ++static int rtw_tdls_enable(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_TDLS ++ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ _irqL irqL; ++ _list *plist, *phead; ++ s32 index; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 tdls_sta[NUM_STA][ETH_ALEN]; ++ u8 empty_hwaddr[ETH_ALEN] = { 0x00 }; ++ ++ printk( "[%s] %s %d\n", __FUNCTION__, extra, wrqu->data.length -1 ); ++ ++ _rtw_memset(tdls_sta, 0x00, sizeof(tdls_sta)); ++ ++ if ( extra[ 0 ] == '0' ) ++ { ++ ptdlsinfo->enable = 0; ++ ++ if(pstapriv->asoc_sta_count==1) ++ return ret; ++ ++ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ for(index=0; index< NUM_STA; index++) ++ { ++ phead = &(pstapriv->sta_hash[index]); ++ plist = get_next(phead); ++ ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info ,hash_list); ++ ++ plist = get_next(plist); ++ ++ if(psta->tdls_sta_state != TDLS_STATE_NONE) ++ { ++ _rtw_memcpy(tdls_sta[index], psta->hwaddr, ETH_ALEN); ++ } ++ } ++ } ++ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ ++ for(index=0; index< NUM_STA; index++) ++ { ++ if( !_rtw_memcmp(tdls_sta[index], empty_hwaddr, ETH_ALEN) ) ++ { ++ printk("issue tear down to "MAC_FMT"\n", MAC_ARG(tdls_sta[index])); ++ issue_tdls_teardown(padapter, tdls_sta[index]); ++ } ++ } ++ rtw_tdls_cmd(padapter, myid(&(padapter->eeprompriv)), TDLS_RS_RCR); ++ rtw_reset_tdls_info(padapter); ++ } ++ else if ( extra[ 0 ] == '1' ) ++ { ++ ptdlsinfo->enable = 1; ++ } ++#endif //CONFIG_TDLS ++ ++ return ret; ++} ++ ++static int rtw_tdls_setup(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_TDLS ++ ++ u8 i, j; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ u8 mac_addr[ETH_ALEN]; ++ ++#ifdef CONFIG_WFD ++ struct wifidirect_info *pwdinfo= &(padapter->wdinfo); ++#endif // CONFIG_WFD ++ ++ printk( "[%s] %s %d\n", __FUNCTION__, extra, wrqu->data.length -1 ); ++ ++ for( i=0, j=0 ; i < ETH_ALEN; i++, j+=3 ){ ++ mac_addr[i]=key_2char2num(*(extra+j), *(extra+j+1)); ++ } ++ ++#ifdef CONFIG_WFD ++ if ( _AES_ != padapter->securitypriv.dot11PrivacyAlgrthm ) ++ { ++ // Weak Security situation with AP. ++ if ( 0 == pwdinfo->wfd_tdls_weaksec ) ++ { ++ // Can't send the tdls setup request out!! ++ DBG_871X( "[%s] Current link is not AES, SKIP sending the tdls setup request!!\n", __FUNCTION__ ); ++ } ++ else ++ { ++ issue_tdls_setup_req(padapter, mac_addr); ++ } ++ } ++ else ++#endif // CONFIG_WFD ++ { ++ issue_tdls_setup_req(padapter, mac_addr); ++ } ++#endif ++ ++ return ret; ++} ++ ++static int rtw_tdls_teardown(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_TDLS ++ ++ u8 i,j; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct sta_info *ptdls_sta = NULL; ++ u8 mac_addr[ETH_ALEN]; ++ ++ DBG_871X( "[%s] %s %d\n", __FUNCTION__, extra, wrqu->data.length -1 ); ++ ++ for( i=0, j=0 ; i < ETH_ALEN; i++, j+=3 ){ ++ mac_addr[i]=key_2char2num(*(extra+j), *(extra+j+1)); ++ } ++ ++ ptdls_sta = rtw_get_stainfo( &(padapter->stapriv), mac_addr); ++ ++ if(ptdls_sta != NULL) ++ { ++ ptdls_sta->stat_code = _RSON_TDLS_TEAR_UN_RSN_; ++ issue_tdls_teardown(padapter, mac_addr); ++ } ++ ++#endif //CONFIG_TDLS ++ ++ return ret; ++} ++ ++static int rtw_tdls_discovery(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_TDLS ++ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ DBG_871X( "[%s] %s %d\n", __FUNCTION__, extra, wrqu->data.length -1 ); ++ ++ issue_tdls_dis_req(padapter, NULL); ++ ++#endif //CONFIG_TDLS ++ ++ return ret; ++} ++ ++static int rtw_tdls_ch_switch(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_TDLS ++ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ u8 i, j, mac_addr[ETH_ALEN]; ++ struct sta_info *ptdls_sta = NULL; ++ ++ DBG_8192C( "[%s] %s %d\n", __FUNCTION__, extra, wrqu->data.length -1 ); ++ ++ for( i=0, j=0 ; i < ETH_ALEN; i++, j+=3 ){ ++ mac_addr[i]=key_2char2num(*(extra+j), *(extra+j+1)); ++ } ++ ++ ptdls_sta = rtw_get_stainfo(&padapter->stapriv, mac_addr); ++ if( ptdls_sta == NULL ) ++ return ret; ++ ptdlsinfo->ch_sensing=1; ++ ++ rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_INIT_CH_SEN); ++ ++#endif //CONFIG_TDLS ++ ++ return ret; ++} ++ ++static int rtw_tdls_pson(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_TDLS ++ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 i, j, mac_addr[ETH_ALEN]; ++ struct sta_info *ptdls_sta = NULL; ++ ++ DBG_871X( "[%s] %s %d\n", __FUNCTION__, extra, wrqu->data.length -1 ); ++ ++ for( i=0, j=0 ; i < ETH_ALEN; i++, j+=3 ){ ++ mac_addr[i]=key_2char2num(*(extra+j), *(extra+j+1)); ++ } ++ ++ ptdls_sta = rtw_get_stainfo(&padapter->stapriv, mac_addr); ++ ++ issue_nulldata_to_TDLS_peer_STA(padapter, ptdls_sta, 1); ++ ++#endif //CONFIG_TDLS ++ ++ return ret; ++} ++ ++static int rtw_tdls_psoff(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_TDLS ++ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 i, j, mac_addr[ETH_ALEN]; ++ struct sta_info *ptdls_sta = NULL; ++ ++ DBG_8192C( "[%s] %s %d\n", __FUNCTION__, extra, wrqu->data.length -1 ); ++ ++ for( i=0, j=0 ; i < ETH_ALEN; i++, j+=3 ){ ++ mac_addr[i]=key_2char2num(*(extra+j), *(extra+j+1)); ++ } ++ ++ ptdls_sta = rtw_get_stainfo(&padapter->stapriv, mac_addr); ++ ++ issue_nulldata_to_TDLS_peer_STA(padapter, ptdls_sta, 0); ++ ++#endif //CONFIG_TDLS ++ ++ return ret; ++} ++ ++static int rtw_tdls_setip(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_TDLS ++#ifdef CONFIG_WFD ++ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ struct wifi_display_info *pwfd_info = ptdlsinfo->wfd_info; ++ u8 i=0, j=0, k=0, tag=0, ip[3] = { 0xff }, *ptr = extra; ++ ++ printk( "[%s] %s %d\n", __FUNCTION__, extra, wrqu->data.length - 1 ); ++ ++ ++ while( i < 4 ) ++ { ++ for( j=0; j < 4; j++) ++ { ++ if( *( extra + j + tag ) == '.' || *( extra + j + tag ) == '\0' ) ++ { ++ if( j == 1 ) ++ pwfd_info->ip_address[i]=convert_ip_addr( '0', '0', *(extra+(j-1)+tag)); ++ if( j == 2 ) ++ pwfd_info->ip_address[i]=convert_ip_addr( '0', *(extra+(j-2)+tag), *(extra+(j-1)+tag)); ++ if( j == 3 ) ++ pwfd_info->ip_address[i]=convert_ip_addr( *(extra+(j-3)+tag), *(extra+(j-2)+tag), *(extra+(j-1)+tag)); ++ ++ tag += j + 1; ++ break; ++ } ++ } ++ i++; ++ } ++ ++ printk( "[%s] Set IP = %u.%u.%u.%u \n", __FUNCTION__, ++ ptdlsinfo->wfd_info->ip_address[0], ptdlsinfo->wfd_info->ip_address[1], ++ ptdlsinfo->wfd_info->ip_address[2], ptdlsinfo->wfd_info->ip_address[3] ++ ); ++ ++#endif //CONFIG_WFD ++#endif //CONFIG_TDLS ++ ++ return ret; ++} ++ ++static int rtw_tdls_getip(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_TDLS ++#ifdef CONFIG_WFD ++ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ struct wifi_display_info *pwfd_info = ptdlsinfo->wfd_info; ++ ++ printk( "[%s]\n", __FUNCTION__); ++ ++ sprintf( extra, "\n\n%u.%u.%u.%u\n", ++ pwfd_info->peer_ip_address[0], pwfd_info->peer_ip_address[1], ++ pwfd_info->peer_ip_address[2], pwfd_info->peer_ip_address[3] ++ ); ++ ++ printk( "[%s] IP=%u.%u.%u.%u\n", __FUNCTION__, ++ pwfd_info->peer_ip_address[0], pwfd_info->peer_ip_address[1], ++ pwfd_info->peer_ip_address[2], pwfd_info->peer_ip_address[3] ++ ); ++ ++ wrqu->data.length = strlen( extra ); ++ ++#endif //CONFIG_WFD ++#endif //CONFIG_TDLS ++ ++ return ret; ++} ++ ++static int rtw_tdls_getport(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ ++#ifdef CONFIG_TDLS ++#ifdef CONFIG_WFD ++ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ struct wifi_display_info *pwfd_info = ptdlsinfo->wfd_info; ++ ++ printk( "[%s]\n", __FUNCTION__); ++ ++ sprintf( extra, "\n\n%d\n", pwfd_info->peer_rtsp_ctrlport ); ++ printk( "[%s] remote port = %d\n", __FUNCTION__, pwfd_info->peer_rtsp_ctrlport ); ++ ++ wrqu->data.length = strlen( extra ); ++ ++#endif //CONFIG_WFD ++#endif //CONFIG_TDLS ++ ++ return ret; ++ ++} ++ ++//WFDTDLS, for sigma test ++static int rtw_tdls_dis_result(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ ++#ifdef CONFIG_TDLS ++#ifdef CONFIG_WFD ++ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ struct wifi_display_info *pwfd_info = ptdlsinfo->wfd_info; ++ ++ printk( "[%s]\n", __FUNCTION__); ++ ++ if(ptdlsinfo->dev_discovered == 1 ) ++ { ++ sprintf( extra, "\n\nDis=1\n" ); ++ ptdlsinfo->dev_discovered = 0; ++ } ++ ++ wrqu->data.length = strlen( extra ); ++ ++#endif //CONFIG_WFD ++#endif //CONFIG_TDLS ++ ++ return ret; ++ ++} ++ ++//WFDTDLS, for sigma test ++static int rtw_wfd_tdls_status(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ ++#ifdef CONFIG_TDLS ++#ifdef CONFIG_WFD ++ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; ++ struct wifi_display_info *pwfd_info = ptdlsinfo->wfd_info; ++ ++ printk( "[%s]\n", __FUNCTION__); ++ ++ if(ptdlsinfo->setup_state == TDLS_LINKED_STATE ) ++ { ++ sprintf( extra, "\n\nStatus=1\n" ); ++ } ++ else ++ { ++ sprintf( extra, "\n\nStatus=0\n" ); ++ } ++ ++ wrqu->data.length = strlen( extra ); ++ ++#endif //CONFIG_WFD ++#endif //CONFIG_TDLS ++ ++ return ret; ++ ++} ++ ++static int rtw_tdls_ch_switch_off(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_TDLS ++ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ u8 i, j, mac_addr[ETH_ALEN]; ++ struct sta_info *ptdls_sta = NULL; ++ ++ DBG_871X( "[%s] %s %d\n", __FUNCTION__, extra, wrqu->data.length -1 ); ++ ++ for( i=0, j=0 ; i < ETH_ALEN; i++, j+=3 ){ ++ mac_addr[i]=key_2char2num(*(extra+j), *(extra+j+1)); ++ } ++ ++ ptdls_sta = rtw_get_stainfo(&padapter->stapriv, mac_addr); ++ ++ ptdls_sta->tdls_sta_state |= TDLS_SW_OFF_STATE; ++/* ++ if((ptdls_sta->tdls_sta_state & TDLS_AT_OFF_CH_STATE) && (ptdls_sta->tdls_sta_state & TDLS_PEER_AT_OFF_STATE)){ ++ pmlmeinfo->tdls_candidate_ch= pmlmeext->cur_channel; ++ issue_tdls_ch_switch_req(padapter, mac_addr); ++ DBG_871X("issue tdls ch switch req back to base channel\n"); ++ } ++*/ ++ ++#endif //CONFIG_TDLS ++ ++ return ret; ++} ++ ++static int rtw_tdls(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_TDLS ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ DBG_871X( "[%s] extra = %s\n", __FUNCTION__, extra ); ++ // WFD Sigma will use the tdls enable command to let the driver know we want to test the tdls now! ++ if ( _rtw_memcmp( extra, "wfdenable=", 10 ) ) ++ { ++ wrqu->data.length -=10; ++ rtw_wfd_tdls_enable( dev, info, wrqu, &extra[10] ); ++ return ret; ++ } ++ else if ( _rtw_memcmp( extra, "weaksec=", 8 ) ) ++ { ++ wrqu->data.length -=8; ++ rtw_tdls_weaksec( dev, info, wrqu, &extra[8] ); ++ return ret; ++ } ++ else if ( _rtw_memcmp( extra, "tdlsenable=", 11 ) ) ++ { ++ wrqu->data.length -=11; ++ rtw_tdls_enable( dev, info, wrqu, &extra[11] ); ++ return ret; ++ } ++ ++ if( padapter->tdlsinfo.enable == 0 ) ++ { ++ printk("tdls haven't enabled\n"); ++ return 0; ++ } ++ ++ if ( _rtw_memcmp( extra, "setup=", 6 ) ) ++ { ++ wrqu->data.length -=6; ++ rtw_tdls_setup( dev, info, wrqu, &extra[6] ); ++ } ++ else if (_rtw_memcmp( extra, "tear=", 5 ) ) ++ { ++ wrqu->data.length -= 5; ++ rtw_tdls_teardown( dev, info, wrqu, &extra[5] ); ++ } ++ else if (_rtw_memcmp( extra, "dis=", 4 ) ) ++ { ++ wrqu->data.length -= 4; ++ rtw_tdls_discovery( dev, info, wrqu, &extra[4] ); ++ } ++ else if (_rtw_memcmp( extra, "sw=", 3 ) ) ++ { ++ wrqu->data.length -= 3; ++ rtw_tdls_ch_switch( dev, info, wrqu, &extra[3] ); ++ } ++ else if (_rtw_memcmp( extra, "swoff=", 6 ) ) ++ { ++ wrqu->data.length -= 6; ++ rtw_tdls_ch_switch_off( dev, info, wrqu, &extra[6] ); ++ } ++ else if (_rtw_memcmp( extra, "pson=", 5 ) ) ++ { ++ wrqu->data.length -= 5; ++ rtw_tdls_pson( dev, info, wrqu, &extra[5] ); ++ } ++ else if (_rtw_memcmp( extra, "psoff=", 6 ) ) ++ { ++ wrqu->data.length -= 6; ++ rtw_tdls_psoff( dev, info, wrqu, &extra[6] ); ++ } ++#ifdef CONFIG_WFD ++ else if (_rtw_memcmp( extra, "setip=", 6 ) ) ++ { ++ wrqu->data.length -= 6; ++ rtw_tdls_setip( dev, info, wrqu, &extra[6] ); ++ } ++ else if (_rtw_memcmp( extra, "tprobe=", 6 ) ) ++ { ++ issue_tunneled_probe_req((_adapter *)rtw_netdev_priv(dev)); ++ } ++#endif //CONFIG_WFD ++ ++#endif //CONFIG_TDLS ++ ++ return ret; ++} ++ ++ ++static int rtw_tdls_get(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_WFD ++ ++ DBG_871X( "[%s] extra = %s\n", __FUNCTION__, (char*) wrqu->data.pointer ); ++ ++ if ( _rtw_memcmp( wrqu->data.pointer, "ip", 2 ) ) ++ { ++ rtw_tdls_getip( dev, info, wrqu, extra ); ++ } ++ if ( _rtw_memcmp( wrqu->data.pointer, "port", 4 ) ) ++ { ++ rtw_tdls_getport( dev, info, wrqu, extra ); ++ } ++ //WFDTDLS, for sigma test ++ if ( _rtw_memcmp( wrqu->data.pointer, "dis", 3 ) ) ++ { ++ rtw_tdls_dis_result( dev, info, wrqu, extra ); ++ } ++ if ( _rtw_memcmp( wrqu->data.pointer, "status", 6 ) ) ++ { ++ rtw_wfd_tdls_status( dev, info, wrqu, extra ); ++ } ++ ++#endif //CONFIG_WFD ++ ++ return ret; ++} ++ ++ ++ ++ ++ ++#ifdef CONFIG_INTEL_WIDI ++static int rtw_widi_set(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ process_intel_widi_cmd(padapter, extra); ++ ++ return ret; ++} ++ ++static int rtw_widi_set_probe_request(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ u8 *pbuf = NULL; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ ++ pbuf = rtw_malloc(sizeof(l2_msg_t)); ++ if(pbuf) ++ { ++ copy_from_user(pbuf, wrqu->data.pointer, wrqu->data.length); ++ //_rtw_memcpy(pbuf, wrqu->data.pointer, wrqu->data.length); ++ ++ if( wrqu->data.flags == 0 ) ++ intel_widi_wk_cmd(padapter, INTEL_WIDI_ISSUE_PROB_WK, pbuf); ++ else if( wrqu->data.flags == 1 ) ++ rtw_set_wfd_rds_sink_info( padapter, (l2_msg_t *)pbuf ); ++ } ++ return ret; ++} ++#endif // CONFIG_INTEL_WIDI ++ ++#ifdef CONFIG_MAC_LOOPBACK_DRIVER ++ ++#ifdef CONFIG_RTL8723A ++extern void rtl8723a_cal_txdesc_chksum(struct tx_desc *ptxdesc); ++#define cal_txdesc_chksum rtl8723a_cal_txdesc_chksum ++extern void rtl8723a_fill_default_txdesc(struct xmit_frame *pxmitframe, u8 *pbuf); ++#define fill_default_txdesc rtl8723a_fill_default_txdesc ++#elif defined(CONFIG_RTL8188E) ++#include ++extern void rtl8188e_cal_txdesc_chksum(struct tx_desc *ptxdesc); ++#define cal_txdesc_chksum rtl8188e_cal_txdesc_chksum ++#ifdef CONFIG_SDIO_HCI ++extern void rtl8188es_fill_default_txdesc(struct xmit_frame *pxmitframe, u8 *pbuf); ++#define fill_default_txdesc rtl8188es_fill_default_txdesc ++#endif // CONFIG_SDIO_HCI ++#endif // CONFIG_RTL8188E ++ ++static s32 initLoopback(PADAPTER padapter) ++{ ++ PLOOPBACKDATA ploopback; ++ ++ ++ if (padapter->ploopback == NULL) { ++ ploopback = (PLOOPBACKDATA)rtw_zmalloc(sizeof(LOOPBACKDATA)); ++ if (ploopback == NULL) return -ENOMEM; ++ ++ _rtw_init_sema(&ploopback->sema, 0); ++ ploopback->bstop = _TRUE; ++ ploopback->cnt = 0; ++ ploopback->size = 300; ++ _rtw_memset(ploopback->msg, 0, sizeof(ploopback->msg)); ++ ++ padapter->ploopback = ploopback; ++ } ++ ++ return 0; ++} ++ ++static void freeLoopback(PADAPTER padapter) ++{ ++ PLOOPBACKDATA ploopback; ++ ++ ++ ploopback = padapter->ploopback; ++ if (ploopback) { ++ rtw_mfree((u8*)ploopback, sizeof(LOOPBACKDATA)); ++ padapter->ploopback = NULL; ++ } ++} ++ ++static s32 initpseudoadhoc(PADAPTER padapter) ++{ ++ NDIS_802_11_NETWORK_INFRASTRUCTURE networkType; ++ s32 err; ++ ++ networkType = Ndis802_11IBSS; ++ err = rtw_set_802_11_infrastructure_mode(padapter, networkType); ++ if (err == _FALSE) return _FAIL; ++ ++ err = rtw_setopmode_cmd(padapter, networkType,_TRUE); ++ if (err == _FAIL) return _FAIL; ++ ++ return _SUCCESS; ++} ++ ++static s32 createpseudoadhoc(PADAPTER padapter) ++{ ++ NDIS_802_11_AUTHENTICATION_MODE authmode; ++ struct mlme_priv *pmlmepriv; ++ NDIS_802_11_SSID *passoc_ssid; ++ WLAN_BSSID_EX *pdev_network; ++ u8 *pibss; ++ u8 ssid[] = "pseduo_ad-hoc"; ++ s32 err; ++ _irqL irqL; ++ ++ ++ pmlmepriv = &padapter->mlmepriv; ++ ++ authmode = Ndis802_11AuthModeOpen; ++ err = rtw_set_802_11_authentication_mode(padapter, authmode); ++ if (err == _FALSE) return _FAIL; ++ ++ passoc_ssid = &pmlmepriv->assoc_ssid; ++ _rtw_memset(passoc_ssid, 0, sizeof(NDIS_802_11_SSID)); ++ passoc_ssid->SsidLength = sizeof(ssid) - 1; ++ _rtw_memcpy(passoc_ssid->Ssid, ssid, passoc_ssid->SsidLength); ++ ++ pdev_network = &padapter->registrypriv.dev_network; ++ pibss = padapter->registrypriv.dev_network.MacAddress; ++ _rtw_memcpy(&pdev_network->Ssid, passoc_ssid, sizeof(NDIS_802_11_SSID)); ++ ++ rtw_update_registrypriv_dev_network(padapter); ++ rtw_generate_random_ibss(pibss); ++ ++ _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; ++ _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ ++#if 0 ++ err = rtw_createbss_cmd(padapter); ++ if (err == _FAIL) return _FAIL; ++#else ++{ ++ struct wlan_network *pcur_network; ++ struct sta_info *psta; ++ ++ //3 create a new psta ++ pcur_network = &pmlmepriv->cur_network; ++ ++ //clear psta in the cur_network, if any ++ psta = rtw_get_stainfo(&padapter->stapriv, pcur_network->network.MacAddress); ++ if (psta) rtw_free_stainfo(padapter, psta); ++ ++ psta = rtw_alloc_stainfo(&padapter->stapriv, pibss); ++ if (psta == NULL) return _FAIL; ++ ++ //3 join psudo AdHoc ++ pcur_network->join_res = 1; ++ pcur_network->aid = psta->aid = 1; ++ _rtw_memcpy(&pcur_network->network, pdev_network, get_WLAN_BSSID_EX_sz(pdev_network)); ++ ++ // set msr to WIFI_FW_ADHOC_STATE ++#if 0 ++ Set_NETYPE0_MSR(padapter, WIFI_FW_ADHOC_STATE); ++#else ++ { ++ u8 val8; ++ ++ val8 = rtw_read8(padapter, MSR); ++ val8 &= 0xFC; // clear NETYPE0 ++ val8 |= WIFI_FW_ADHOC_STATE & 0x3; ++ rtw_write8(padapter, MSR, val8); ++ } ++#endif ++} ++#endif ++ ++ return _SUCCESS; ++} ++ ++static struct xmit_frame* createloopbackpkt(PADAPTER padapter, u32 size) ++{ ++ struct xmit_priv *pxmitpriv; ++ struct xmit_frame *pframe; ++ struct xmit_buf *pxmitbuf; ++ struct pkt_attrib *pattrib; ++ struct tx_desc *desc; ++ u8 *pkt_start, *pkt_end, *ptr; ++ struct rtw_ieee80211_hdr *hdr; ++ s32 bmcast; ++ _irqL irqL; ++ ++ ++ if ((TXDESC_SIZE + WLANHDR_OFFSET + size) > MAX_XMITBUF_SZ) return NULL; ++ ++ pxmitpriv = &padapter->xmitpriv; ++ pframe = NULL; ++ ++ //2 1. allocate xmit frame ++ pframe = rtw_alloc_xmitframe(pxmitpriv); ++ if (pframe == NULL) return NULL; ++ pframe->padapter = padapter; ++ ++ //2 2. allocate xmit buffer ++ _enter_critical_bh(&pxmitpriv->lock, &irqL); ++ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); ++ _exit_critical_bh(&pxmitpriv->lock, &irqL); ++ if (pxmitbuf == NULL) { ++ rtw_free_xmitframe(pxmitpriv, pframe); ++ return NULL; ++ } ++ ++ pframe->pxmitbuf = pxmitbuf; ++ pframe->buf_addr = pxmitbuf->pbuf; ++ pxmitbuf->priv_data = pframe; ++ ++ //2 3. update_attrib() ++ pattrib = &pframe->attrib; ++ ++ // init xmitframe attribute ++ _rtw_memset(pattrib, 0, sizeof(struct pkt_attrib)); ++ ++ pattrib->ether_type = 0x8723; ++ _rtw_memcpy(pattrib->src, padapter->eeprompriv.mac_addr, ETH_ALEN); ++ _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ _rtw_memset(pattrib->dst, 0xFF, ETH_ALEN); ++ _rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); ++// pattrib->pctrl = 0; ++// pattrib->dhcp_pkt = 0; ++// pattrib->pktlen = 0; ++ pattrib->ack_policy = 0; ++// pattrib->pkt_hdrlen = ETH_HLEN; ++ pattrib->hdrlen = WLAN_HDR_A3_LEN; ++ pattrib->subtype = WIFI_DATA; ++ pattrib->priority = 0; ++ pattrib->qsel = pattrib->priority; ++// do_queue_select(padapter, pattrib); ++ pattrib->nr_frags = 1; ++ pattrib->encrypt = 0; ++ pattrib->bswenc = _FALSE; ++ pattrib->qos_en = _FALSE; ++ ++ bmcast = IS_MCAST(pattrib->ra); ++ if (bmcast) { ++ pattrib->mac_id = 1; ++ pattrib->psta = rtw_get_bcmc_stainfo(padapter); ++ } else { ++ pattrib->mac_id = 0; ++ pattrib->psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv)); ++ } ++ ++ pattrib->pktlen = size; ++ pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->pktlen; ++ ++ //2 4. fill TX descriptor ++ desc = (struct tx_desc*)pframe->buf_addr; ++ _rtw_memset(desc, 0, TXDESC_SIZE); ++ ++ fill_default_txdesc(pframe, (u8*)desc); ++ ++ // Hw set sequence number ++ ((PTXDESC)desc)->hwseq_en = 0; // HWSEQ_EN, 0:disable, 1:enable ++// ((PTXDESC)desc)->hwseq_sel = 0; // HWSEQ_SEL ++ ++ ((PTXDESC)desc)->disdatafb = 1; ++ ++ // convert to little endian ++ desc->txdw0 = cpu_to_le32(desc->txdw0); ++ desc->txdw1 = cpu_to_le32(desc->txdw1); ++ desc->txdw2 = cpu_to_le32(desc->txdw2); ++ desc->txdw3 = cpu_to_le32(desc->txdw3); ++ desc->txdw4 = cpu_to_le32(desc->txdw4); ++ desc->txdw5 = cpu_to_le32(desc->txdw5); ++ desc->txdw6 = cpu_to_le32(desc->txdw6); ++ desc->txdw7 = cpu_to_le32(desc->txdw7); ++#ifdef CONFIG_PCI_HCI ++ desc->txdw8 = cpu_to_le32(desc->txdw8); ++ desc->txdw9 = cpu_to_le32(desc->txdw9); ++ desc->txdw10 = cpu_to_le32(desc->txdw10); ++ desc->txdw11 = cpu_to_le32(desc->txdw11); ++ desc->txdw12 = cpu_to_le32(desc->txdw12); ++ desc->txdw13 = cpu_to_le32(desc->txdw13); ++ desc->txdw14 = cpu_to_le32(desc->txdw14); ++ desc->txdw15 = cpu_to_le32(desc->txdw15); ++#endif ++ ++ cal_txdesc_chksum(desc); ++ ++ //2 5. coalesce ++ pkt_start = pframe->buf_addr + TXDESC_SIZE; ++ pkt_end = pkt_start + pattrib->last_txcmdsz; ++ ++ //3 5.1. make wlan header, make_wlanhdr() ++ hdr = (struct rtw_ieee80211_hdr *)pkt_start; ++ SetFrameSubType(&hdr->frame_ctl, pattrib->subtype); ++ _rtw_memcpy(hdr->addr1, pattrib->dst, ETH_ALEN); // DA ++ _rtw_memcpy(hdr->addr2, pattrib->src, ETH_ALEN); // SA ++ _rtw_memcpy(hdr->addr3, get_bssid(&padapter->mlmepriv), ETH_ALEN); // RA, BSSID ++ ++ //3 5.2. make payload ++ ptr = pkt_start + pattrib->hdrlen; ++ get_random_bytes(ptr, pkt_end - ptr); ++ ++ pxmitbuf->len = TXDESC_SIZE + pattrib->last_txcmdsz; ++ pxmitbuf->ptail += pxmitbuf->len; ++ ++ return pframe; ++} ++ ++static void freeloopbackpkt(PADAPTER padapter, struct xmit_frame *pframe) ++{ ++ struct xmit_priv *pxmitpriv; ++ struct xmit_buf *pxmitbuf; ++ ++ ++ pxmitpriv = &padapter->xmitpriv; ++ pxmitbuf = pframe->pxmitbuf; ++ ++ rtw_free_xmitframe(pxmitpriv, pframe); ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++} ++ ++static void printdata(u8 *pbuf, u32 len) ++{ ++ u32 i, val; ++ ++ ++ for (i = 0; (i+4) <= len; i+=4) { ++ printk("%08X", *(u32*)(pbuf + i)); ++ if ((i+4) & 0x1F) printk(" "); ++ else printk("\n"); ++ } ++ ++ if (i < len) ++ { ++#ifdef CONFIG_BIG_ENDIAN ++ for (; i < len, i++) ++ printk("%02X", pbuf+i); ++#else // CONFIG_LITTLE_ENDIAN ++#if 0 ++ val = 0; ++ _rtw_memcpy(&val, pbuf + i, len - i); ++ printk("%8X", val); ++#else ++ u8 str[9]; ++ u8 n; ++ val = 0; ++ n = len - i; ++ _rtw_memcpy(&val, pbuf+i, n); ++ sprintf(str, "%08X", val); ++ n = (4 - n) * 2; ++ printk("%8s", str+n); ++#endif ++#endif // CONFIG_LITTLE_ENDIAN ++ } ++ printk("\n"); ++} ++ ++static u8 pktcmp(PADAPTER padapter, u8 *txbuf, u32 txsz, u8 *rxbuf, u32 rxsz) ++{ ++ PHAL_DATA_TYPE phal; ++ struct recv_stat *prxstat; ++ struct recv_stat report; ++ PRXREPORT prxreport; ++ u32 drvinfosize; ++ u32 rxpktsize; ++ u8 fcssize; ++ u8 ret = _FALSE; ++ ++ prxstat = (struct recv_stat*)rxbuf; ++ report.rxdw0 = le32_to_cpu(prxstat->rxdw0); ++ report.rxdw1 = le32_to_cpu(prxstat->rxdw1); ++ report.rxdw2 = le32_to_cpu(prxstat->rxdw2); ++ report.rxdw3 = le32_to_cpu(prxstat->rxdw3); ++ report.rxdw4 = le32_to_cpu(prxstat->rxdw4); ++ report.rxdw5 = le32_to_cpu(prxstat->rxdw5); ++ ++ prxreport = (PRXREPORT)&report; ++ drvinfosize = prxreport->drvinfosize << 3; ++ rxpktsize = prxreport->pktlen; ++ ++ phal = GET_HAL_DATA(padapter); ++ if (phal->ReceiveConfig & RCR_APPFCS) fcssize = IEEE80211_FCS_LEN; ++ else fcssize = 0; ++ ++ if ((txsz - TXDESC_SIZE) != (rxpktsize - fcssize)) { ++ DBG_8192C("%s: ERROR! size not match tx/rx=%d/%d !\n", ++ __func__, txsz - TXDESC_SIZE, rxpktsize - fcssize); ++ ret = _FALSE; ++ } else { ++ ret = _rtw_memcmp(txbuf + TXDESC_SIZE,\ ++ rxbuf + RXDESC_SIZE + drvinfosize,\ ++ txsz - TXDESC_SIZE); ++ if (ret == _FALSE) { ++ DBG_8192C("%s: ERROR! pkt content mismatch!\n", __func__); ++ } ++ } ++ ++ if (ret == _FALSE) ++ { ++ DBG_8192C("\n%s: TX PKT total=%d, desc=%d, content=%d\n", ++ __func__, txsz, TXDESC_SIZE, txsz - TXDESC_SIZE); ++ DBG_8192C("%s: TX DESC size=%d\n", __func__, TXDESC_SIZE); ++ printdata(txbuf, TXDESC_SIZE); ++ DBG_8192C("%s: TX content size=%d\n", __func__, txsz - TXDESC_SIZE); ++ printdata(txbuf + TXDESC_SIZE, txsz - TXDESC_SIZE); ++ ++ DBG_8192C("\n%s: RX PKT read=%d offset=%d(%d,%d) content=%d\n", ++ __func__, rxsz, RXDESC_SIZE + drvinfosize, RXDESC_SIZE, drvinfosize, rxpktsize); ++ if (rxpktsize != 0) ++ { ++ DBG_8192C("%s: RX DESC size=%d\n", __func__, RXDESC_SIZE); ++ printdata(rxbuf, RXDESC_SIZE); ++ DBG_8192C("%s: RX drvinfo size=%d\n", __func__, drvinfosize); ++ printdata(rxbuf + RXDESC_SIZE, drvinfosize); ++ DBG_8192C("%s: RX content size=%d\n", __func__, rxpktsize); ++ printdata(rxbuf + RXDESC_SIZE + drvinfosize, rxpktsize); ++ } else { ++ DBG_8192C("%s: RX data size=%d\n", __func__, rxsz); ++ printdata(rxbuf, rxsz); ++ } ++ } ++ ++ return ret; ++} ++ ++thread_return lbk_thread(thread_context context) ++{ ++ s32 err; ++ PADAPTER padapter; ++ PLOOPBACKDATA ploopback; ++ struct xmit_frame *pxmitframe; ++ u32 cnt, ok, fail, headerlen; ++ u32 pktsize; ++ u32 ff_hwaddr; ++ ++ ++ padapter = (PADAPTER)context; ++ ploopback = padapter->ploopback; ++ if (ploopback == NULL) return -1; ++ cnt = 0; ++ ok = 0; ++ fail = 0; ++ ++ daemonize("%s", "RTW_LBK_THREAD"); ++ allow_signal(SIGTERM); ++ ++ do { ++ if (ploopback->size == 0) { ++ get_random_bytes(&pktsize, 4); ++ pktsize = (pktsize % 1535) + 1; // 1~1535 ++ } else ++ pktsize = ploopback->size; ++ ++ pxmitframe = createloopbackpkt(padapter, pktsize); ++ if (pxmitframe == NULL) { ++ sprintf(ploopback->msg, "loopback FAIL! 3. create Packet FAIL!"); ++ break; ++ } ++ ++ ploopback->txsize = TXDESC_SIZE + pxmitframe->attrib.last_txcmdsz; ++ _rtw_memcpy(ploopback->txbuf, pxmitframe->buf_addr, ploopback->txsize); ++ ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe); ++ cnt++; ++ DBG_8192C("%s: wirte port cnt=%d size=%d\n", __func__, cnt, ploopback->txsize); ++ pxmitframe->pxmitbuf->pdata = ploopback->txbuf; ++ rtw_write_port(padapter, ff_hwaddr, ploopback->txsize, (u8 *)pxmitframe->pxmitbuf); ++ ++ // wait for rx pkt ++ _rtw_down_sema(&ploopback->sema); ++ ++ err = pktcmp(padapter, ploopback->txbuf, ploopback->txsize, ploopback->rxbuf, ploopback->rxsize); ++ if (err == _TRUE) ++ ok++; ++ else ++ fail++; ++ ++ ploopback->txsize = 0; ++ _rtw_memset(ploopback->txbuf, 0, 0x8000); ++ ploopback->rxsize = 0; ++ _rtw_memset(ploopback->rxbuf, 0, 0x8000); ++ ++ freeloopbackpkt(padapter, pxmitframe); ++ pxmitframe = NULL; ++ ++ if (signal_pending(current)) { ++ flush_signals(current); ++ } ++ ++ if ((ploopback->bstop == _TRUE) || ++ ((ploopback->cnt != 0) && (ploopback->cnt == cnt))) ++ { ++ u32 ok_rate, fail_rate, all; ++ all = cnt; ++ ok_rate = (ok*100)/all; ++ fail_rate = (fail*100)/all; ++ sprintf(ploopback->msg,\ ++ "loopback result: ok=%d%%(%d/%d),error=%d%%(%d/%d)",\ ++ ok_rate, ok, all, fail_rate, fail, all); ++ break; ++ } ++ } while (1); ++ ++ ploopback->bstop = _TRUE; ++ ++ thread_exit(); ++} ++ ++static void loopbackTest(PADAPTER padapter, u32 cnt, u32 size, u8* pmsg) ++{ ++ PLOOPBACKDATA ploopback; ++ u32 len; ++ s32 err; ++ ++ ++ ploopback = padapter->ploopback; ++ ++ if (ploopback) ++ { ++ if (ploopback->bstop == _FALSE) { ++ ploopback->bstop = _TRUE; ++ _rtw_up_sema(&ploopback->sema); ++ } ++ len = 0; ++ do { ++ len = strlen(ploopback->msg); ++ if (len) break; ++ rtw_msleep_os(1); ++ } while (1); ++ _rtw_memcpy(pmsg, ploopback->msg, len+1); ++ freeLoopback(padapter); ++ ++ return; ++ } ++ ++ // disable dynamic algorithm ++ { ++ u32 DMFlag = DYNAMIC_FUNC_DISABLE; ++ rtw_hal_get_hwreg(padapter, HW_VAR_DM_FLAG, (u8*)&DMFlag); ++ } ++ ++ // create pseudo ad-hoc connection ++ err = initpseudoadhoc(padapter); ++ if (err == _FAIL) { ++ sprintf(pmsg, "loopback FAIL! 1.1 init ad-hoc FAIL!"); ++ return; ++ } ++ ++ err = createpseudoadhoc(padapter); ++ if (err == _FAIL) { ++ sprintf(pmsg, "loopback FAIL! 1.2 create ad-hoc master FAIL!"); ++ return; ++ } ++ ++ err = initLoopback(padapter); ++ if (err) { ++ sprintf(pmsg, "loopback FAIL! 2. init FAIL! error code=%d", err); ++ return; ++ } ++ ++ ploopback = padapter->ploopback; ++ ++ ploopback->bstop = _FALSE; ++ ploopback->cnt = cnt; ++ ploopback->size = size; ++ ploopback->lbkthread = kthread_run(lbk_thread, padapter, "RTW_LBK_THREAD"); ++ if (IS_ERR(padapter->lbkthread)) ++ { ++ freeLoopback(padapter); ++ sprintf(pmsg, "loopback start FAIL! cnt=%d", cnt); ++ return; ++ } ++ ++ sprintf(pmsg, "loopback start! cnt=%d", cnt); ++} ++#endif // CONFIG_MAC_LOOPBACK_DRIVER ++ ++static int rtw_test( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ u32 len; ++ u8 *pbuf, *pch; ++ char *ptmp; ++ u8 *delim = ","; ++ PADAPTER padapter = rtw_netdev_priv(dev); ++ ++ ++ DBG_871X("+%s\n", __func__); ++ len = wrqu->data.length; ++ ++ pbuf = (u8*)rtw_zmalloc(len); ++ if (pbuf == NULL) { ++ DBG_871X("%s: no memory!\n", __func__); ++ return -ENOMEM; ++ } ++ ++ if (copy_from_user(pbuf, wrqu->data.pointer, len)) { ++ rtw_mfree(pbuf, len); ++ DBG_871X("%s: copy from user fail!\n", __func__); ++ return -EFAULT; ++ } ++ DBG_871X("%s: string=\"%s\"\n", __func__, pbuf); ++ ++ ptmp = (char*)pbuf; ++ pch = strsep(&ptmp, delim); ++ if ((pch == NULL) || (strlen(pch) == 0)) { ++ rtw_mfree(pbuf, len); ++ DBG_871X("%s: parameter error(level 1)!\n", __func__); ++ return -EFAULT; ++ } ++ ++#ifdef CONFIG_MAC_LOOPBACK_DRIVER ++ if (strcmp(pch, "loopback") == 0) ++ { ++ s32 cnt = 0; ++ u32 size = 64; ++ ++ pch = strsep(&ptmp, delim); ++ if ((pch == NULL) || (strlen(pch) == 0)) { ++ rtw_mfree(pbuf, len); ++ DBG_871X("%s: parameter error(level 2)!\n", __func__); ++ return -EFAULT; ++ } ++ ++ sscanf(pch, "%d", &cnt); ++ DBG_871X("%s: loopback cnt=%d\n", __func__, cnt); ++ ++ pch = strsep(&ptmp, delim); ++ if ((pch == NULL) || (strlen(pch) == 0)) { ++ rtw_mfree(pbuf, len); ++ DBG_871X("%s: parameter error(level 2)!\n", __func__); ++ return -EFAULT; ++ } ++ ++ sscanf(pch, "%d", &size); ++ DBG_871X("%s: loopback size=%d\n", __func__, size); ++ ++ loopbackTest(padapter, cnt, size, extra); ++ wrqu->data.length = strlen(extra) + 1; ++ ++ rtw_mfree(pbuf, len); ++ return 0; ++ } ++#endif ++ ++#ifdef CONFIG_RTL8723A ++#if 0 ++ if (strcmp(pch, "poweron") == 0) ++ { ++ s32 ret; ++ ++ ret = _InitPowerOn(padapter); ++ DBG_871X("%s: power on %s\n", __func__, (_FAIL==ret) ? "FAIL!":"OK."); ++ sprintf(extra, "Power ON %s", (_FAIL==ret) ? "FAIL!":"OK."); ++ wrqu->data.length = strlen(extra) + 1; ++ ++ rtw_mfree(pbuf, len); ++ return 0; ++ } ++ ++ if (strcmp(pch, "dlfw") == 0) ++ { ++ s32 ret; ++ ++ ret = rtl8723a_FirmwareDownload(padapter); ++ DBG_871X("%s: download FW %s\n", __func__, (_FAIL==ret) ? "FAIL!":"OK."); ++ sprintf(extra, "download FW %s", (_FAIL==ret) ? "FAIL!":"OK."); ++ wrqu->data.length = strlen(extra) + 1; ++ ++ rtw_mfree(pbuf, len); ++ return 0; ++ } ++#endif ++ ++#ifdef CONFIG_BT_COEXIST ++#define GET_BT_INFO(padapter) (&GET_HAL_DATA(padapter)->BtInfo) ++ ++ if (strcmp(pch, "btdbg") == 0) ++ { ++ DBG_8192C("===== BT debug information Start =====\n"); ++ DBG_8192C("WIFI status=\n"); ++ DBG_8192C("BT status=\n"); ++ DBG_8192C("BT profile=\n"); ++ DBG_8192C("WIFI RSSI=%d\n", GET_HAL_DATA(padapter)->dmpriv.UndecoratedSmoothedPWDB); ++ DBG_8192C("BT RSSI=\n"); ++ DBG_8192C("coex mechanism=\n"); ++ DBG_8192C("BT counter TX/RX=/\n"); ++ DBG_8192C("0x880=0x%08x\n", rtw_read32(padapter, 0x880)); ++ DBG_8192C("0x6c0=0x%08x\n", rtw_read32(padapter, 0x6c0)); ++ DBG_8192C("0x6c4=0x%08x\n", rtw_read32(padapter, 0x6c4)); ++ DBG_8192C("0x6c8=0x%08x\n", rtw_read32(padapter, 0x6c8)); ++ DBG_8192C("0x6cc=0x%08x\n", rtw_read32(padapter, 0x6cc)); ++ DBG_8192C("0x778=0x%08x\n", rtw_read32(padapter, 0x778)); ++ DBG_8192C("0xc50=0x%08x\n", rtw_read32(padapter, 0xc50)); ++ BT_DisplayBtCoexInfo(padapter); ++ DBG_8192C("===== BT debug information End =====\n"); ++ } ++ ++ if (strcmp(pch, "bton") == 0) ++ { ++ PBT30Info pBTInfo = GET_BT_INFO(padapter); ++ PBT_MGNT pBtMgnt = &pBTInfo->BtMgnt; ++ ++ pBtMgnt->ExtConfig.bManualControl = _FALSE; ++ } ++ ++ if (strcmp(pch, "btoff") == 0) ++ { ++ PBT30Info pBTInfo = GET_BT_INFO(padapter); ++ PBT_MGNT pBtMgnt = &pBTInfo->BtMgnt; ++ ++ pBtMgnt->ExtConfig.bManualControl = _TRUE; ++ } ++#endif // CONFIG_BT_COEXIST ++ ++ if (strcmp(pch, "h2c") == 0) ++ { ++ u8 param[6]; ++ u8 count = 0; ++ u32 tmp; ++ u8 i; ++ u32 pos; ++ s32 ret; ++ ++ ++ do { ++ pch = strsep(&ptmp, delim); ++ if ((pch == NULL) || (strlen(pch) == 0)) ++ break; ++ ++ sscanf(pch, "%x", &tmp); ++ param[count++] = (u8)tmp; ++ } while (count < 6); ++ ++ if (count == 0) { ++ rtw_mfree(pbuf, len); ++ DBG_8192C("%s: parameter error(level 2)!\n", __func__); ++ return -EFAULT; ++ } ++ ++ ret = FillH2CCmd(padapter, param[0], count-1, ¶m[1]); ++ ++ pos = sprintf(extra, "H2C ID=%x content=", param[0]); ++ for (i=0; idata.length = strlen(extra) + 1; ++ } ++#endif // CONFIG_RTL8723A ++ ++ rtw_mfree(pbuf, len); ++ return 0; ++} ++ ++static iw_handler rtw_handlers[] = ++{ ++ NULL, /* SIOCSIWCOMMIT */ ++ rtw_wx_get_name, /* SIOCGIWNAME */ ++ dummy, /* SIOCSIWNWID */ ++ dummy, /* SIOCGIWNWID */ ++ rtw_wx_set_freq, /* SIOCSIWFREQ */ ++ rtw_wx_get_freq, /* SIOCGIWFREQ */ ++ rtw_wx_set_mode, /* SIOCSIWMODE */ ++ rtw_wx_get_mode, /* SIOCGIWMODE */ ++ dummy, /* SIOCSIWSENS */ ++ rtw_wx_get_sens, /* SIOCGIWSENS */ ++ NULL, /* SIOCSIWRANGE */ ++ rtw_wx_get_range, /* SIOCGIWRANGE */ ++ rtw_wx_set_priv, /* SIOCSIWPRIV */ ++ NULL, /* SIOCGIWPRIV */ ++ NULL, /* SIOCSIWSTATS */ ++ NULL, /* SIOCGIWSTATS */ ++ dummy, /* SIOCSIWSPY */ ++ dummy, /* SIOCGIWSPY */ ++ NULL, /* SIOCGIWTHRSPY */ ++ NULL, /* SIOCWIWTHRSPY */ ++ rtw_wx_set_wap, /* SIOCSIWAP */ ++ rtw_wx_get_wap, /* SIOCGIWAP */ ++ rtw_wx_set_mlme, /* request MLME operation; uses struct iw_mlme */ ++ dummy, /* SIOCGIWAPLIST -- depricated */ ++ rtw_wx_set_scan, /* SIOCSIWSCAN */ ++ rtw_wx_get_scan, /* SIOCGIWSCAN */ ++ rtw_wx_set_essid, /* SIOCSIWESSID */ ++ rtw_wx_get_essid, /* SIOCGIWESSID */ ++ dummy, /* SIOCSIWNICKN */ ++ rtw_wx_get_nick, /* SIOCGIWNICKN */ ++ NULL, /* -- hole -- */ ++ NULL, /* -- hole -- */ ++ rtw_wx_set_rate, /* SIOCSIWRATE */ ++ rtw_wx_get_rate, /* SIOCGIWRATE */ ++ rtw_wx_set_rts, /* SIOCSIWRTS */ ++ rtw_wx_get_rts, /* SIOCGIWRTS */ ++ rtw_wx_set_frag, /* SIOCSIWFRAG */ ++ rtw_wx_get_frag, /* SIOCGIWFRAG */ ++ dummy, /* SIOCSIWTXPOW */ ++ dummy, /* SIOCGIWTXPOW */ ++ dummy, /* SIOCSIWRETRY */ ++ rtw_wx_get_retry, /* SIOCGIWRETRY */ ++ rtw_wx_set_enc, /* SIOCSIWENCODE */ ++ rtw_wx_get_enc, /* SIOCGIWENCODE */ ++ dummy, /* SIOCSIWPOWER */ ++ rtw_wx_get_power, /* SIOCGIWPOWER */ ++ NULL, /*---hole---*/ ++ NULL, /*---hole---*/ ++ rtw_wx_set_gen_ie, /* SIOCSIWGENIE */ ++ NULL, /* SIOCGWGENIE */ ++ rtw_wx_set_auth, /* SIOCSIWAUTH */ ++ NULL, /* SIOCGIWAUTH */ ++ rtw_wx_set_enc_ext, /* SIOCSIWENCODEEXT */ ++ NULL, /* SIOCGIWENCODEEXT */ ++ rtw_wx_set_pmkid, /* SIOCSIWPMKSA */ ++ NULL, /*---hole---*/ ++}; ++ ++#if 0 ++//defined(CONFIG_MP_INCLUDED) && defined(CONFIG_MP_IWPRIV_SUPPORT) ++ ++static const struct iw_priv_args rtw_private_args[] = ++{ ++ { SIOCIWFIRSTPRIV + 0x00, IW_PRIV_TYPE_CHAR | 1024, 0 , ""}, //set ++ { SIOCIWFIRSTPRIV + 0x01, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK , ""},//get ++/* --- sub-ioctls definitions --- */ ++ { MP_START , IW_PRIV_TYPE_CHAR | 1024, 0, "mp_start" }, //set ++ { MP_PHYPARA, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_phypara" },//get ++ { MP_STOP , IW_PRIV_TYPE_CHAR | 1024, 0, "mp_stop" }, //set ++ { MP_CHANNEL , IW_PRIV_TYPE_CHAR | 1024 , IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_channel" },//get ++ { MP_BANDWIDTH , IW_PRIV_TYPE_CHAR | 1024, 0, "mp_bandwidth"}, //set ++ { MP_RATE , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_rate" },//get ++ { MP_RESET_STATS , IW_PRIV_TYPE_CHAR | 1024, 0, "mp_reset_stats"}, ++ { MP_QUERY , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK , "mp_query"}, //get ++ { MP_NULL, IW_PRIV_TYPE_CHAR | 128, 0,"NULL"},//set ++ { READ_REG , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "read_reg" }, ++ { MP_NULL, IW_PRIV_TYPE_CHAR | 128, 0,"NULL"},//set ++ { MP_RATE , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_rate" }, ++ { MP_NULL, IW_PRIV_TYPE_CHAR | 128, 0,"NULL"},//set ++ { READ_RF , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "read_rf" }, ++ { MP_NULL, IW_PRIV_TYPE_CHAR | 128, 0,"NULL"},//set ++ { MP_PSD , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_psd"}, ++ { MP_NULL, IW_PRIV_TYPE_CHAR | 128, 0,"NULL"},//set ++ { MP_DUMP, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_dump" }, ++ { MP_NULL, IW_PRIV_TYPE_CHAR | 128, 0,"NULL"},//set ++ { MP_TXPOWER , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_txpower"}, ++ { MP_NULL, IW_PRIV_TYPE_CHAR | 128, 0,"NULL"},//set ++ { MP_ANT_TX , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ant_tx"}, ++ { MP_NULL, IW_PRIV_TYPE_CHAR | 128, 0,"NULL"},//set ++ { MP_ANT_RX , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ant_rx"}, ++ { WRITE_REG, IW_PRIV_TYPE_CHAR | 1024, 0,"write_reg"},//set ++ { MP_NULL, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "NULL" }, ++ { WRITE_RF, IW_PRIV_TYPE_CHAR | 1024, 0,"write_rf"},//set ++ { MP_NULL, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "NULL" }, ++ { MP_NULL, IW_PRIV_TYPE_CHAR | 128, 0,"NULL"},//set ++ { MP_CTX , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ctx"}, ++ { MP_NULL, IW_PRIV_TYPE_CHAR | 128, 0,"NULL"},//set ++ { MP_ARX , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_arx"}, ++ { MP_NULL, IW_PRIV_TYPE_CHAR | 128, 0,"NULL"},//set ++ { MP_THER , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ther"}, ++ { EFUSE_SET, IW_PRIV_TYPE_CHAR | 1024, 0, "efuse_set" }, ++ { EFUSE_GET, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_get" }, ++ { MP_PWRTRK , IW_PRIV_TYPE_CHAR | 1024, 0, "mp_pwrtrk"}, ++ { MP_QueryDrvStats, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_drvquery" }, ++ { MP_IOCTL, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_ioctl"}, // mp_ioctl ++ { MP_SetRFPathSwh, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_setrfpath" }, ++ ++#ifdef CONFIG_RTL8723A ++ { MP_SetBT, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_setbt" }, ++#endif ++ ++ { SIOCIWFIRSTPRIV + 0x02, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK , "test"},//set ++}; ++ ++ ++static iw_handler rtw_private_handler[] = ++{ ++ rtw_mp_set, ++ rtw_mp_get, ++}; ++ ++#else // not inlucde MP ++ ++static const struct iw_priv_args rtw_private_args[] = { ++ { ++ SIOCIWFIRSTPRIV + 0x0, ++ IW_PRIV_TYPE_CHAR | 0x7FF, 0, "write" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x1, ++ IW_PRIV_TYPE_CHAR | 0x7FF, ++ IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "read" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x2, 0, 0, "driver_ext" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x3, 0, 0, "mp_ioctl" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x4, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "apinfo" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x5, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "setpid" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x6, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_start" ++ }, ++//for PLATFORM_MT53XX ++ { ++ SIOCIWFIRSTPRIV + 0x7, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "get_sensitivity" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x8, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_prob_req_ie" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x9, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_assoc_req_ie" ++ }, ++ ++//for RTK_DMP_PLATFORM ++ { ++ SIOCIWFIRSTPRIV + 0xA, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "channel_plan" ++ }, ++ ++ { ++ SIOCIWFIRSTPRIV + 0xB, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "dbg" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0xC, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "rfw" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0xD, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "rfr" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x10, ++ IW_PRIV_TYPE_CHAR | 1024, 0, "p2p_set" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x11, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK , "p2p_get" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x12, 0, 0, "NULL" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x13, ++ IW_PRIV_TYPE_CHAR | 64, IW_PRIV_TYPE_CHAR | 64 , "p2p_get2" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x14, ++ IW_PRIV_TYPE_CHAR | 64, 0, "tdls" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x15, ++ IW_PRIV_TYPE_CHAR | P2P_PRIVATE_IOCTL_SET_LEN, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | P2P_PRIVATE_IOCTL_SET_LEN , "tdls_get" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x16, ++ IW_PRIV_TYPE_CHAR | 64, 0, "pm_set" ++ }, ++ ++ {SIOCIWFIRSTPRIV + 0x18, IW_PRIV_TYPE_CHAR | IFNAMSIZ , 0 , "rereg_nd_name"}, ++ ++ {SIOCIWFIRSTPRIV + 0x1A, IW_PRIV_TYPE_CHAR | 1024, 0, "efuse_set"}, ++ {SIOCIWFIRSTPRIV + 0x1B, IW_PRIV_TYPE_CHAR | 128, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_get"}, ++ { ++ SIOCIWFIRSTPRIV + 0x1D, ++ IW_PRIV_TYPE_CHAR | 40, IW_PRIV_TYPE_CHAR | 0x7FF, "test" ++ }, ++ ++#ifdef CONFIG_INTEL_WIDI ++ { ++ SIOCIWFIRSTPRIV + 0x1E, ++ IW_PRIV_TYPE_CHAR | 1024, 0, "widi_set" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x1F, ++ IW_PRIV_TYPE_CHAR | 128, 0, "widi_prob_req" ++ }, ++#endif // CONFIG_INTEL_WIDI ++ ++#ifdef CONFIG_MP_INCLUDED ++ ++ { SIOCIWFIRSTPRIV + 0x0E, IW_PRIV_TYPE_CHAR | 1024, 0 , ""}, //set ++ { SIOCIWFIRSTPRIV + 0x0F, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK , ""},//get ++/* --- sub-ioctls definitions --- */ ++ ++ { MP_START , IW_PRIV_TYPE_CHAR | 1024, 0, "mp_start" }, //set ++ { MP_PHYPARA, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_phypara" },//get ++ { MP_STOP , IW_PRIV_TYPE_CHAR | 1024, 0, "mp_stop" }, //set ++ { MP_CHANNEL , IW_PRIV_TYPE_CHAR | 1024 , IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_channel" },//get ++ { MP_BANDWIDTH , IW_PRIV_TYPE_CHAR | 1024, 0, "mp_bandwidth"}, //set ++ { MP_RATE , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_rate" },//get ++ { MP_RESET_STATS , IW_PRIV_TYPE_CHAR | 1024, 0, "mp_reset_stats"}, ++ { MP_QUERY , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK , "mp_query"}, //get ++ { READ_REG , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "read_reg" }, ++ { MP_RATE , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_rate" }, ++ { READ_RF , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "read_rf" }, ++ { MP_PSD , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_psd"}, ++ { MP_DUMP, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_dump" }, ++ { MP_TXPOWER , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_txpower"}, ++ { MP_ANT_TX , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ant_tx"}, ++ { MP_ANT_RX , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ant_rx"}, ++ { WRITE_REG , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "write_reg" }, ++ { WRITE_RF , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "write_rf" }, ++ { MP_CTX , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ctx"}, ++ { MP_ARX , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_arx"}, ++ { MP_THER , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ther"}, ++ { EFUSE_SET, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_set" }, ++ { EFUSE_GET, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_get" }, ++ { MP_PWRTRK , IW_PRIV_TYPE_CHAR | 1024, 0, "mp_pwrtrk"}, ++ { MP_QueryDrvStats, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_drvquery" }, ++ { MP_IOCTL, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_ioctl"}, // mp_ioctl ++ { MP_SetRFPathSwh, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_setrfpath" }, ++ { MP_PwrCtlDM, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_pwrctldm" }, ++#ifdef CONFIG_RTL8723A ++ { MP_SetBT, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_setbt" }, ++ { MP_DISABLE_BT_COEXIST, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_disa_btcoex"}, ++#endif ++ { CTA_TEST, IW_PRIV_TYPE_CHAR | 1024, 0, "cta_test"}, ++#endif ++#ifdef CONFIG_WOWLAN ++ { MP_WOW_ENABLE , IW_PRIV_TYPE_CHAR | 1024, 0, "wow_enable" }, //set ++#endif ++}; ++ ++static iw_handler rtw_private_handler[] = ++{ ++ rtw_wx_write32, //0x00 ++ rtw_wx_read32, //0x01 ++ rtw_drvext_hdl, //0x02 ++ rtw_mp_ioctl_hdl, //0x03 ++ ++// for MM DTV platform ++ rtw_get_ap_info, //0x04 ++ ++ rtw_set_pid, //0x05 ++ rtw_wps_start, //0x06 ++ ++// for PLATFORM_MT53XX ++ rtw_wx_get_sensitivity, //0x07 ++ rtw_wx_set_mtk_wps_probe_ie, //0x08 ++ rtw_wx_set_mtk_wps_ie, //0x09 ++ ++// for RTK_DMP_PLATFORM ++// Set Channel depend on the country code ++ rtw_wx_set_channel_plan, //0x0A ++ ++ rtw_dbg_port, //0x0B ++ rtw_wx_write_rf, //0x0C ++ rtw_wx_read_rf, //0x0D ++ ++#ifndef CONFIG_MP_INCLUDED ++ rtw_wx_priv_null, //0x0E ++ rtw_wx_priv_null, //0x0F ++#else ++ rtw_mp_set, //0x0E ++ rtw_mp_get, //0x0F ++#endif ++ rtw_p2p_set, //0x10 ++ rtw_p2p_get, //0x11 ++ NULL, //0x12 ++ rtw_p2p_get2, //0x13 ++ ++ rtw_tdls, //0x14 ++ rtw_tdls_get, //0x15 ++ ++ rtw_pm_set, //0x16 ++ rtw_wx_priv_null, //0x17 ++ rtw_rereg_nd_name, //0x18 ++ rtw_wx_priv_null, //0x19 ++ ++ rtw_mp_efuse_set, //0x1A ++ rtw_mp_efuse_get, //0x1B ++ NULL, // 0x1C is reserved for hostapd ++ rtw_test, // 0x1D ++#ifdef CONFIG_INTEL_WIDI ++ rtw_widi_set, //0x1E ++ rtw_widi_set_probe_request, //0x1F ++#endif // CONFIG_INTEL_WIDI ++}; ++ ++#endif // #if defined(CONFIG_MP_INCLUDED) && defined(CONFIG_MP_IWPRIV_SUPPORT) ++ ++#if WIRELESS_EXT >= 17 ++static struct iw_statistics *rtw_get_wireless_stats(struct net_device *dev) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); ++ struct iw_statistics *piwstats=&padapter->iwstats; ++ int tmp_level = 0; ++ int tmp_qual = 0; ++ int tmp_noise = 0; ++ ++ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) != _TRUE) ++ { ++ piwstats->qual.qual = 0; ++ piwstats->qual.level = 0; ++ piwstats->qual.noise = 0; ++ //DBG_871X("No link level:%d, qual:%d, noise:%d\n", tmp_level, tmp_qual, tmp_noise); ++ } ++ else{ ++ #ifdef CONFIG_SIGNAL_DISPLAY_DBM ++ tmp_level = translate_percentage_to_dbm(padapter->recvpriv.signal_strength); ++ #else ++ tmp_level = padapter->recvpriv.signal_strength; ++ #ifdef CONFIG_BT_COEXIST ++ { ++ u8 signal = (u8)tmp_level; ++ BT_SignalCompensation(padapter, &signal, NULL); ++ tmp_level= signal; ++ } ++ #endif // CONFIG_BT_COEXIST ++ #endif ++ ++ tmp_qual = padapter->recvpriv.signal_qual; ++ tmp_noise =padapter->recvpriv.noise; ++ //DBG_871X("level:%d, qual:%d, noise:%d, rssi (%d)\n", tmp_level, tmp_qual, tmp_noise,padapter->recvpriv.rssi); ++ ++ piwstats->qual.level = tmp_level; ++ piwstats->qual.qual = tmp_qual; ++ piwstats->qual.noise = tmp_noise; ++ } ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)) ++ piwstats->qual.updated = IW_QUAL_ALL_UPDATED ;//|IW_QUAL_DBM; ++#else ++#ifdef RTK_DMP_PLATFORM ++ //IW_QUAL_DBM= 0x8, if driver use this flag, wireless extension will show value of dbm. ++ //remove this flag for show percentage 0~100 ++ piwstats->qual.updated = 0x07; ++#else ++ piwstats->qual.updated = 0x0f; ++#endif ++#endif ++ ++ #ifdef CONFIG_SIGNAL_DISPLAY_DBM ++ piwstats->qual.updated = piwstats->qual.updated | IW_QUAL_DBM; ++ #endif ++ ++ return &padapter->iwstats; ++} ++#endif ++ ++#ifdef CONFIG_WIRELESS_EXT ++struct iw_handler_def rtw_handlers_def = ++{ ++ .standard = rtw_handlers, ++ .num_standard = sizeof(rtw_handlers) / sizeof(iw_handler), ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) || defined(CONFIG_WEXT_PRIV) ++ .private = rtw_private_handler, ++ .private_args = (struct iw_priv_args *)rtw_private_args, ++ .num_private = sizeof(rtw_private_handler) / sizeof(iw_handler), ++ .num_private_args = sizeof(rtw_private_args) / sizeof(struct iw_priv_args), ++#endif ++#if WIRELESS_EXT >= 17 ++ .get_wireless_stats = rtw_get_wireless_stats, ++#endif ++}; ++#endif ++ ++// copy from net/wireless/wext.c start ++/* ---------------------------------------------------------------- */ ++/* ++ * Calculate size of private arguments ++ */ ++static const char iw_priv_type_size[] = { ++ 0, /* IW_PRIV_TYPE_NONE */ ++ 1, /* IW_PRIV_TYPE_BYTE */ ++ 1, /* IW_PRIV_TYPE_CHAR */ ++ 0, /* Not defined */ ++ sizeof(__u32), /* IW_PRIV_TYPE_INT */ ++ sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */ ++ sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */ ++ 0, /* Not defined */ ++}; ++ ++static int get_priv_size(__u16 args) ++{ ++ int num = args & IW_PRIV_SIZE_MASK; ++ int type = (args & IW_PRIV_TYPE_MASK) >> 12; ++ ++ return num * iw_priv_type_size[type]; ++} ++// copy from net/wireless/wext.c end ++ ++static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_data) ++{ ++ int err = 0; ++ u8 *input = NULL; ++ u32 input_len = 0; ++ const char delim[] = " "; ++ u8 *output = NULL; ++ u32 output_len = 0; ++ u32 count = 0; ++ u8 *buffer= NULL; ++ u32 buffer_len = 0; ++ char *ptr = NULL; ++ u8 cmdname[17] = {0}; // IFNAMSIZ+1 ++ u32 cmdlen; ++ s32 len; ++ u8 *extra = NULL; ++ u32 extra_size = 0; ++ ++ s32 k; ++ const iw_handler *priv; /* Private ioctl */ ++ const struct iw_priv_args *priv_args; /* Private ioctl description */ ++ u32 num_priv; /* Number of ioctl */ ++ u32 num_priv_args; /* Number of descriptions */ ++ iw_handler handler; ++ int temp; ++ int subcmd = 0; /* sub-ioctl index */ ++ int offset = 0; /* Space for sub-ioctl index */ ++ ++ union iwreq_data wdata; ++ ++ ++ _rtw_memcpy(&wdata, wrq_data, sizeof(wdata)); ++ ++ input_len = wdata.data.length; ++ input = rtw_zmalloc(input_len); ++ if (NULL == input) ++ return -ENOMEM; ++ if (copy_from_user(input, wdata.data.pointer, input_len)) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ptr = input; ++ len = input_len; ++ ++ sscanf(ptr, "%16s", cmdname); ++ cmdlen = strlen(cmdname); ++ DBG_8192C("%s: cmd=%s\n", __func__, cmdname); ++ ++ // skip command string ++ if (cmdlen > 0) ++ cmdlen += 1; // skip one space ++ ptr += cmdlen; ++ len -= cmdlen; ++ DBG_8192C("%s: parameters=%s\n", __func__, ptr); ++ ++ priv = rtw_private_handler; ++ priv_args = rtw_private_args; ++ num_priv = sizeof(rtw_private_handler) / sizeof(iw_handler); ++ num_priv_args = sizeof(rtw_private_args) / sizeof(struct iw_priv_args); ++ ++ if (num_priv_args == 0) { ++ err = -EOPNOTSUPP; ++ goto exit; ++ } ++ ++ /* Search the correct ioctl */ ++ k = -1; ++ while((++k < num_priv_args) && strcmp(priv_args[k].name, cmdname)); ++ ++ /* If not found... */ ++ if (k == num_priv_args) { ++ err = -EOPNOTSUPP; ++ goto exit; ++ } ++ ++ /* Watch out for sub-ioctls ! */ ++ if (priv_args[k].cmd < SIOCDEVPRIVATE) ++ { ++ int j = -1; ++ ++ /* Find the matching *real* ioctl */ ++ while ((++j < num_priv_args) && ((priv_args[j].name[0] != '\0') || ++ (priv_args[j].set_args != priv_args[k].set_args) || ++ (priv_args[j].get_args != priv_args[k].get_args))); ++ ++ /* If not found... */ ++ if (j == num_priv_args) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ /* Save sub-ioctl number */ ++ subcmd = priv_args[k].cmd; ++ /* Reserve one int (simplify alignment issues) */ ++ offset = sizeof(__u32); ++ /* Use real ioctl definition from now on */ ++ k = j; ++ } ++ ++ buffer = rtw_zmalloc(4096); ++ if (NULL == buffer) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ /* If we have to set some data */ ++ if ((priv_args[k].set_args & IW_PRIV_TYPE_MASK) && ++ (priv_args[k].set_args & IW_PRIV_SIZE_MASK)) ++ { ++ u8 *str; ++ ++ switch (priv_args[k].set_args & IW_PRIV_TYPE_MASK) ++ { ++ case IW_PRIV_TYPE_BYTE: ++ /* Fetch args */ ++ count = 0; ++ do { ++ str = strsep(&ptr, delim); ++ if (NULL == str) break; ++ sscanf(str, "%i", &temp); ++ buffer[count++] = (u8)temp; ++ } while (1); ++ buffer_len = count; ++ ++ /* Number of args to fetch */ ++ wdata.data.length = count; ++ if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK)) ++ wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK; ++ ++ break; ++ ++ case IW_PRIV_TYPE_INT: ++ /* Fetch args */ ++ count = 0; ++ do { ++ str = strsep(&ptr, delim); ++ if (NULL == str) break; ++ sscanf(str, "%i", &temp); ++ ((s32*)buffer)[count++] = (s32)temp; ++ } while (1); ++ buffer_len = count * sizeof(s32); ++ ++ /* Number of args to fetch */ ++ wdata.data.length = count; ++ if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK)) ++ wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK; ++ ++ break; ++ ++ case IW_PRIV_TYPE_CHAR: ++ if (len > 0) ++ { ++ /* Size of the string to fetch */ ++ wdata.data.length = len; ++ if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK)) ++ wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK; ++ ++ /* Fetch string */ ++ _rtw_memcpy(buffer, ptr, wdata.data.length); ++ } ++ else ++ { ++ wdata.data.length = 1; ++ buffer[0] = '\0'; ++ } ++ buffer_len = wdata.data.length; ++ break; ++ ++ default: ++ DBG_8192C("%s: Not yet implemented...\n", __func__); ++ err = -1; ++ goto exit; ++ } ++ ++ if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) && ++ (wdata.data.length != (priv_args[k].set_args & IW_PRIV_SIZE_MASK))) ++ { ++ DBG_8192C("%s: The command %s needs exactly %d argument(s)...\n", ++ __func__, cmdname, priv_args[k].set_args & IW_PRIV_SIZE_MASK); ++ err = -EINVAL; ++ goto exit; ++ } ++ } /* if args to set */ ++ else ++ { ++ wdata.data.length = 0L; ++ } ++ ++ /* Those two tests are important. They define how the driver ++ * will have to handle the data */ ++ if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) && ++ ((get_priv_size(priv_args[k].set_args) + offset) <= IFNAMSIZ)) ++ { ++ /* First case : all SET args fit within wrq */ ++ if (offset) ++ wdata.mode = subcmd; ++ _rtw_memcpy(wdata.name + offset, buffer, IFNAMSIZ - offset); ++ } ++ else ++ { ++ if ((priv_args[k].set_args == 0) && ++ (priv_args[k].get_args & IW_PRIV_SIZE_FIXED) && ++ (get_priv_size(priv_args[k].get_args) <= IFNAMSIZ)) ++ { ++ /* Second case : no SET args, GET args fit within wrq */ ++ if (offset) ++ wdata.mode = subcmd; ++ } ++ else ++ { ++ /* Third case : args won't fit in wrq, or variable number of args */ ++ if (copy_to_user(wdata.data.pointer, buffer, buffer_len)) { ++ err = -EFAULT; ++ goto exit; ++ } ++ wdata.data.flags = subcmd; ++ } ++ } ++ ++ rtw_mfree(input, input_len); ++ input = NULL; ++ ++ extra_size = 0; ++ if (IW_IS_SET(priv_args[k].cmd)) ++ { ++ /* Size of set arguments */ ++ extra_size = get_priv_size(priv_args[k].set_args); ++ ++ /* Does it fits in iwr ? */ ++ if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) && ++ ((extra_size + offset) <= IFNAMSIZ)) ++ extra_size = 0; ++ } else { ++ /* Size of get arguments */ ++ extra_size = get_priv_size(priv_args[k].get_args); ++ ++ /* Does it fits in iwr ? */ ++ if ((priv_args[k].get_args & IW_PRIV_SIZE_FIXED) && ++ (extra_size <= IFNAMSIZ)) ++ extra_size = 0; ++ } ++ ++ if (extra_size == 0) { ++ extra = (u8*)&wdata; ++ rtw_mfree(buffer, 4096); ++ buffer = NULL; ++ } else ++ extra = buffer; ++ ++ handler = priv[priv_args[k].cmd - SIOCIWFIRSTPRIV]; ++ err = handler(dev, NULL, &wdata, extra); ++ ++ /* If we have to get some data */ ++ if ((priv_args[k].get_args & IW_PRIV_TYPE_MASK) && ++ (priv_args[k].get_args & IW_PRIV_SIZE_MASK)) ++ { ++ int j; ++ int n = 0; /* number of args */ ++ u8 str[20] = {0}; ++ ++ /* Check where is the returned data */ ++ if ((priv_args[k].get_args & IW_PRIV_SIZE_FIXED) && ++ (get_priv_size(priv_args[k].get_args) <= IFNAMSIZ)) ++ n = priv_args[k].get_args & IW_PRIV_SIZE_MASK; ++ else ++ n = wdata.data.length; ++ ++ output = rtw_zmalloc(4096); ++ if (NULL == output) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ switch (priv_args[k].get_args & IW_PRIV_TYPE_MASK) ++ { ++ case IW_PRIV_TYPE_BYTE: ++ /* Display args */ ++ for (j = 0; j < n; j++) ++ { ++ sprintf(str, "%d ", extra[j]); ++ len = strlen(str); ++ output_len = strlen(output); ++ if ((output_len + len + 1) > 4096) { ++ err = -E2BIG; ++ goto exit; ++ } ++ _rtw_memcpy(output+output_len, str, len); ++ } ++ break; ++ ++ case IW_PRIV_TYPE_INT: ++ /* Display args */ ++ for (j = 0; j < n; j++) ++ { ++ sprintf(str, "%d ", ((__s32*)extra)[j]); ++ len = strlen(str); ++ output_len = strlen(output); ++ if ((output_len + len + 1) > 4096) { ++ err = -E2BIG; ++ goto exit; ++ } ++ _rtw_memcpy(output+output_len, str, len); ++ } ++ break; ++ ++ case IW_PRIV_TYPE_CHAR: ++ /* Display args */ ++ _rtw_memcpy(output, extra, n); ++ break; ++ ++ default: ++ DBG_8192C("%s: Not yet implemented...\n", __func__); ++ err = -1; ++ goto exit; ++ } ++ ++ output_len = strlen(output) + 1; ++ wrq_data->data.length = output_len; ++ if (copy_to_user(wrq_data->data.pointer, output, output_len)) { ++ err = -EFAULT; ++ goto exit; ++ } ++ } /* if args to set */ ++ else ++ { ++ wrq_data->data.length = 0; ++ } ++ ++exit: ++ if (input) ++ rtw_mfree(input, input_len); ++ if (buffer) ++ rtw_mfree(buffer, 4096); ++ if (output) ++ rtw_mfree(output, 4096); ++ ++ return err; ++} ++ ++#include ++int rtw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++ struct iwreq *wrq = (struct iwreq *)rq; ++ int ret=0; ++ ++ switch (cmd) ++ { ++ case RTL_IOCTL_WPA_SUPPLICANT: ++ ret = wpa_supplicant_ioctl(dev, &wrq->u.data); ++ break; ++#ifdef CONFIG_AP_MODE ++ case RTL_IOCTL_HOSTAPD: ++ ret = rtw_hostapd_ioctl(dev, &wrq->u.data); ++ break; ++#ifdef CONFIG_NO_WIRELESS_HANDLERS ++ case SIOCSIWMODE: ++ ret = rtw_wx_set_mode(dev, NULL, &wrq->u, NULL); ++ break; ++#endif ++#endif // CONFIG_AP_MODE ++ case SIOCDEVPRIVATE: ++ ret = rtw_ioctl_wext_private(dev, &wrq->u); ++ break; ++ case (SIOCDEVPRIVATE+1): ++ ret = rtw_android_priv_cmd(dev, rq, cmd); ++ break; ++ default: ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ return ret; ++} +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/mlme_linux.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/mlme_linux.c +new file mode 100644 +index 00000000..58c466bb +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/mlme_linux.c +@@ -0,0 +1,620 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++ ++#define _MLME_OSDEP_C_ ++ ++#include ++#include ++#include ++#include ++ ++ ++#ifdef RTK_DMP_PLATFORM ++void Linkup_workitem_callback(struct work_struct *work) ++{ ++ struct mlme_priv *pmlmepriv = container_of(work, struct mlme_priv, Linkup_workitem); ++ _adapter *padapter = container_of(pmlmepriv, _adapter, mlmepriv); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mlme_osdep_c_,_drv_info_,("+ Linkup_workitem_callback\n")); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12)) ++ kobject_uevent(&padapter->pnetdev->dev.kobj, KOBJ_LINKUP); ++#else ++ kobject_hotplug(&padapter->pnetdev->class_dev.kobj, KOBJ_LINKUP); ++#endif ++ ++_func_exit_; ++} ++ ++void Linkdown_workitem_callback(struct work_struct *work) ++{ ++ struct mlme_priv *pmlmepriv = container_of(work, struct mlme_priv, Linkdown_workitem); ++ _adapter *padapter = container_of(pmlmepriv, _adapter, mlmepriv); ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mlme_osdep_c_,_drv_info_,("+ Linkdown_workitem_callback\n")); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12)) ++ kobject_uevent(&padapter->pnetdev->dev.kobj, KOBJ_LINKDOWN); ++#else ++ kobject_hotplug(&padapter->pnetdev->class_dev.kobj, KOBJ_LINKDOWN); ++#endif ++ ++_func_exit_; ++} ++#endif ++ ++ ++/* ++void sitesurvey_ctrl_handler(void *FunctionContext) ++{ ++ _adapter *adapter = (_adapter *)FunctionContext; ++ ++ _sitesurvey_ctrl_handler(adapter); ++ ++ _set_timer(&adapter->mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer, 3000); ++} ++*/ ++ ++void rtw_join_timeout_handler (void *FunctionContext) ++{ ++ _adapter *adapter = (_adapter *)FunctionContext; ++ _rtw_join_timeout_handler(adapter); ++} ++ ++ ++void _rtw_scan_timeout_handler (void *FunctionContext) ++{ ++ _adapter *adapter = (_adapter *)FunctionContext; ++ rtw_scan_timeout_handler(adapter); ++} ++ ++ ++void _dynamic_check_timer_handlder (void *FunctionContext) ++{ ++ _adapter *adapter = (_adapter *)FunctionContext; ++/* remove for MP power tracking DM. ++#if (MP_DRIVER == 1) ++if (adapter->registrypriv.mp_mode == 1) ++ return; ++#endif ++*/ ++ rtw_dynamic_check_timer_handlder(adapter); ++ ++ _set_timer(&adapter->mlmepriv.dynamic_chk_timer, 2000); ++} ++ ++#ifdef CONFIG_SET_SCAN_DENY_TIMER ++void _rtw_set_scan_deny_timer_hdl(void *FunctionContext) ++{ ++ _adapter *adapter = (_adapter *)FunctionContext; ++ rtw_set_scan_deny_timer_hdl(adapter); ++} ++#endif ++ ++#ifdef CONFIG_DETECT_C2H_BY_POLLING ++void _rtw_event_polling_timer_hdl(void *FunctionContext) ++{ ++ _adapter *adapter = (_adapter *)FunctionContext; ++ ++ rtw_event_polling_timer_hdl(adapter); ++ ++ _set_timer(&adapter->mlmepriv.event_polling_timer, 200); ++} ++#endif ++ ++void rtw_init_mlme_timer(_adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ _init_timer(&(pmlmepriv->assoc_timer), padapter->pnetdev, rtw_join_timeout_handler, padapter); ++ //_init_timer(&(pmlmepriv->sitesurveyctrl.sitesurvey_ctrl_timer), padapter->pnetdev, sitesurvey_ctrl_handler, padapter); ++ _init_timer(&(pmlmepriv->scan_to_timer), padapter->pnetdev, _rtw_scan_timeout_handler, padapter); ++ ++ _init_timer(&(pmlmepriv->dynamic_chk_timer), padapter->pnetdev, _dynamic_check_timer_handlder, padapter); ++ ++ #ifdef CONFIG_SET_SCAN_DENY_TIMER ++ _init_timer(&(pmlmepriv->set_scan_deny_timer), padapter->pnetdev, _rtw_set_scan_deny_timer_hdl, padapter); ++ #endif ++ ++#ifdef CONFIG_DETECT_C2H_BY_POLLING ++ _init_timer(&(pmlmepriv->event_polling_timer), padapter->pnetdev, _rtw_event_polling_timer_hdl, padapter); ++#endif ++ ++#ifdef RTK_DMP_PLATFORM ++ _init_workitem(&(pmlmepriv->Linkup_workitem), Linkup_workitem_callback, padapter); ++ _init_workitem(&(pmlmepriv->Linkdown_workitem), Linkdown_workitem_callback, padapter); ++#endif ++#if defined(CONFIG_CHECK_BT_HANG) && defined(CONFIG_BT_COEXIST) ++ if (padapter->HalFunc.hal_init_checkbthang_workqueue) ++ padapter->HalFunc.hal_init_checkbthang_workqueue(padapter); ++#endif ++} ++ ++extern void rtw_indicate_wx_assoc_event(_adapter *padapter); ++extern void rtw_indicate_wx_disassoc_event(_adapter *padapter); ++ ++void rtw_os_indicate_connect(_adapter *adapter) ++{ ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++_func_enter_; ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if ( (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)==_TRUE ) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)==_TRUE ) ) ++ { ++ rtw_cfg80211_ibss_indicate_connect(adapter); ++ } ++ else ++ rtw_cfg80211_indicate_connect(adapter); ++#endif //CONFIG_IOCTL_CFG80211 ++ ++ rtw_indicate_wx_assoc_event(adapter); ++ netif_carrier_on(adapter->pnetdev); ++ ++ if(adapter->pid[2] !=0) ++ rtw_signal_process(adapter->pid[2], SIGALRM); ++ ++#ifdef RTK_DMP_PLATFORM ++ _set_workitem(&adapter->mlmepriv.Linkup_workitem); ++#endif ++ ++_func_exit_; ++ ++} ++ ++extern void indicate_wx_scan_complete_event(_adapter *padapter); ++void rtw_os_indicate_scan_done( _adapter *padapter, bool aborted) ++{ ++#ifdef CONFIG_IOCTL_CFG80211 ++ rtw_cfg80211_indicate_scan_done(wdev_to_priv(padapter->rtw_wdev), aborted); ++#endif ++ indicate_wx_scan_complete_event(padapter); ++} ++ ++static RT_PMKID_LIST backupPMKIDList[ NUM_PMKID_CACHE ]; ++void rtw_reset_securitypriv( _adapter *adapter ) ++{ ++ u8 backupPMKIDIndex = 0; ++ u8 backupTKIPCountermeasure = 0x00; ++ u32 backupTKIPcountermeasure_time = 0; ++ // add for CONFIG_IEEE80211W, none 11w also can use ++ _irqL irqL; ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ ++ _enter_critical_bh(&adapter->security_key_mutex, &irqL); ++ ++ if(adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)//802.1x ++ { ++ // Added by Albert 2009/02/18 ++ // We have to backup the PMK information for WiFi PMK Caching test item. ++ // ++ // Backup the btkip_countermeasure information. ++ // When the countermeasure is trigger, the driver have to disconnect with AP for 60 seconds. ++ ++ _rtw_memset( &backupPMKIDList[ 0 ], 0x00, sizeof( RT_PMKID_LIST ) * NUM_PMKID_CACHE ); ++ ++ _rtw_memcpy( &backupPMKIDList[ 0 ], &adapter->securitypriv.PMKIDList[ 0 ], sizeof( RT_PMKID_LIST ) * NUM_PMKID_CACHE ); ++ backupPMKIDIndex = adapter->securitypriv.PMKIDIndex; ++ backupTKIPCountermeasure = adapter->securitypriv.btkip_countermeasure; ++ backupTKIPcountermeasure_time = adapter->securitypriv.btkip_countermeasure_time; ++#ifdef CONFIG_IEEE80211W ++ //reset RX BIP packet number ++ pmlmeext->mgnt_80211w_IPN_rx = 0; ++#endif //CONFIG_IEEE80211W ++ _rtw_memset((unsigned char *)&adapter->securitypriv, 0, sizeof (struct security_priv)); ++ //_init_timer(&(adapter->securitypriv.tkip_timer),adapter->pnetdev, rtw_use_tkipkey_handler, adapter); ++ ++ // Added by Albert 2009/02/18 ++ // Restore the PMK information to securitypriv structure for the following connection. ++ _rtw_memcpy( &adapter->securitypriv.PMKIDList[ 0 ], &backupPMKIDList[ 0 ], sizeof( RT_PMKID_LIST ) * NUM_PMKID_CACHE ); ++ adapter->securitypriv.PMKIDIndex = backupPMKIDIndex; ++ adapter->securitypriv.btkip_countermeasure = backupTKIPCountermeasure; ++ adapter->securitypriv.btkip_countermeasure_time = backupTKIPcountermeasure_time; ++ ++ adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; ++ adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled; ++ ++ } ++ else //reset values in securitypriv ++ { ++ //if(adapter->mlmepriv.fw_state & WIFI_STATION_STATE) ++ //{ ++ struct security_priv *psec_priv=&adapter->securitypriv; ++ ++ psec_priv->dot11AuthAlgrthm =dot11AuthAlgrthm_Open; //open system ++ psec_priv->dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ psec_priv->dot11PrivacyKeyIndex = 0; ++ ++ psec_priv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ psec_priv->dot118021XGrpKeyid = 1; ++ ++ psec_priv->ndisauthtype = Ndis802_11AuthModeOpen; ++ psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled; ++ //} ++ } ++ // add for CONFIG_IEEE80211W, none 11w also can use ++ _exit_critical_bh(&adapter->security_key_mutex, &irqL); ++} ++ ++void rtw_os_indicate_disconnect( _adapter *adapter ) ++{ ++ //RT_PMKID_LIST backupPMKIDList[ NUM_PMKID_CACHE ]; ++ ++_func_enter_; ++ ++ netif_carrier_off(adapter->pnetdev); // Do it first for tx broadcast pkt after disconnection issue! ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ rtw_cfg80211_indicate_disconnect(adapter); ++#endif //CONFIG_IOCTL_CFG80211 ++ ++ rtw_indicate_wx_disassoc_event(adapter); ++ ++#ifdef RTK_DMP_PLATFORM ++ _set_workitem(&adapter->mlmepriv.Linkdown_workitem); ++#endif ++ //modify for CONFIG_IEEE80211W, none 11w also can use the same command ++ rtw_reset_securitypriv_cmd(adapter); ++ ++_func_exit_; ++ ++} ++ ++void rtw_report_sec_ie(_adapter *adapter,u8 authmode,u8 *sec_ie) ++{ ++ uint len; ++ u8 *buff,*p,i; ++ union iwreq_data wrqu; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_mlme_osdep_c_,_drv_info_,("+rtw_report_sec_ie, authmode=%d\n", authmode)); ++ ++ buff = NULL; ++ if(authmode==_WPA_IE_ID_) ++ { ++ RT_TRACE(_module_mlme_osdep_c_,_drv_info_,("rtw_report_sec_ie, authmode=%d\n", authmode)); ++ ++ buff = rtw_malloc(IW_CUSTOM_MAX); ++ ++ _rtw_memset(buff,0,IW_CUSTOM_MAX); ++ ++ p=buff; ++ ++ p+=sprintf(p,"ASSOCINFO(ReqIEs="); ++ ++ len = sec_ie[1]+2; ++ len = (len < IW_CUSTOM_MAX) ? len:IW_CUSTOM_MAX; ++ ++ for(i=0;ipnetdev,IWEVCUSTOM,&wrqu,buff); ++#endif ++ ++ if(buff) ++ rtw_mfree(buff, IW_CUSTOM_MAX); ++ ++ } ++ ++_func_exit_; ++ ++} ++ ++void _survey_timer_hdl (void *FunctionContext) ++{ ++ _adapter *padapter = (_adapter *)FunctionContext; ++ ++ survey_timer_hdl(padapter); ++} ++ ++void _link_timer_hdl (void *FunctionContext) ++{ ++ _adapter *padapter = (_adapter *)FunctionContext; ++ link_timer_hdl(padapter); ++} ++ ++void _addba_timer_hdl(void *FunctionContext) ++{ ++ struct sta_info *psta = (struct sta_info *)FunctionContext; ++ addba_timer_hdl(psta); ++} ++ ++#ifdef CONFIG_IEEE80211W ++void _sa_query_timer_hdl (void *FunctionContext) ++{ ++ _adapter *padapter = (_adapter *)FunctionContext; ++ sa_query_timer_hdl(padapter); ++} ++#endif //CONFIG_IEEE80211W ++ ++void init_addba_retry_timer(_adapter *padapter, struct sta_info *psta) ++{ ++ ++ _init_timer(&psta->addba_retry_timer, padapter->pnetdev, _addba_timer_hdl, psta); ++} ++ ++/* ++void _reauth_timer_hdl(void *FunctionContext) ++{ ++ _adapter *padapter = (_adapter *)FunctionContext; ++ reauth_timer_hdl(padapter); ++} ++ ++void _reassoc_timer_hdl(void *FunctionContext) ++{ ++ _adapter *padapter = (_adapter *)FunctionContext; ++ reassoc_timer_hdl(padapter); ++} ++*/ ++ ++void init_mlme_ext_timer(_adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ _init_timer(&pmlmeext->survey_timer, padapter->pnetdev, _survey_timer_hdl, padapter); ++ _init_timer(&pmlmeext->link_timer, padapter->pnetdev, _link_timer_hdl, padapter); ++#ifdef CONFIG_IEEE80211W ++ _init_timer(&pmlmeext->sa_query_timer, padapter->pnetdev, _sa_query_timer_hdl, padapter); ++#endif //CONFIG_IEEE80211W ++ //_init_timer(&pmlmeext->ADDBA_timer, padapter->pnetdev, _addba_timer_hdl, padapter); ++ ++ //_init_timer(&pmlmeext->reauth_timer, padapter->pnetdev, _reauth_timer_hdl, padapter); ++ //_init_timer(&pmlmeext->reassoc_timer, padapter->pnetdev, _reassoc_timer_hdl, padapter); ++} ++ ++#ifdef CONFIG_AP_MODE ++ ++void rtw_indicate_sta_assoc_event(_adapter *padapter, struct sta_info *psta) ++{ ++ union iwreq_data wrqu; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ if(psta==NULL) ++ return; ++ ++ if(psta->aid > NUM_STA) ++ return; ++ ++ if(pstapriv->sta_aid[psta->aid - 1] != psta) ++ return; ++ ++ ++ wrqu.addr.sa_family = ARPHRD_ETHER; ++ ++ _rtw_memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN); ++ ++ DBG_871X("+rtw_indicate_sta_assoc_event\n"); ++ ++#ifndef CONFIG_IOCTL_CFG80211 ++ wireless_send_event(padapter->pnetdev, IWEVREGISTERED, &wrqu, NULL); ++#endif ++ ++} ++ ++void rtw_indicate_sta_disassoc_event(_adapter *padapter, struct sta_info *psta) ++{ ++ union iwreq_data wrqu; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ if(psta==NULL) ++ return; ++ ++ if(psta->aid > NUM_STA) ++ return; ++ ++ if(pstapriv->sta_aid[psta->aid - 1] != psta) ++ return; ++ ++ ++ wrqu.addr.sa_family = ARPHRD_ETHER; ++ ++ _rtw_memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN); ++ ++ DBG_871X("+rtw_indicate_sta_disassoc_event\n"); ++ ++#ifndef CONFIG_IOCTL_CFG80211 ++ wireless_send_event(padapter->pnetdev, IWEVEXPIRED, &wrqu, NULL); ++#endif ++ ++} ++ ++ ++#ifdef CONFIG_HOSTAPD_MLME ++ ++static int mgnt_xmit_entry(struct sk_buff *skb, struct net_device *pnetdev) ++{ ++ struct hostapd_priv *phostapdpriv = rtw_netdev_priv(pnetdev); ++ _adapter *padapter = (_adapter *)phostapdpriv->padapter; ++ ++ //DBG_871X("%s\n", __FUNCTION__); ++ ++ return rtw_hal_hostap_mgnt_xmit_entry(padapter, skb); ++} ++ ++static int mgnt_netdev_open(struct net_device *pnetdev) ++{ ++ struct hostapd_priv *phostapdpriv = rtw_netdev_priv(pnetdev); ++ ++ DBG_871X("mgnt_netdev_open: MAC Address:" MAC_FMT "\n", MAC_ARG(pnetdev->dev_addr)); ++ ++ ++ init_usb_anchor(&phostapdpriv->anchored); ++ ++ if(!rtw_netif_queue_stopped(pnetdev)) ++ rtw_netif_start_queue(pnetdev); ++ else ++ rtw_netif_wake_queue(pnetdev); ++ ++ ++ netif_carrier_on(pnetdev); ++ ++ //rtw_write16(phostapdpriv->padapter, 0x0116, 0x0100);//only excluding beacon ++ ++ return 0; ++} ++static int mgnt_netdev_close(struct net_device *pnetdev) ++{ ++ struct hostapd_priv *phostapdpriv = rtw_netdev_priv(pnetdev); ++ ++ DBG_871X("%s\n", __FUNCTION__); ++ ++ usb_kill_anchored_urbs(&phostapdpriv->anchored); ++ ++ netif_carrier_off(pnetdev); ++ ++ if (!rtw_netif_queue_stopped(pnetdev)) ++ rtw_netif_stop_queue(pnetdev); ++ ++ //rtw_write16(phostapdpriv->padapter, 0x0116, 0x3f3f); ++ ++ return 0; ++} ++ ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,29)) ++static const struct net_device_ops rtl871x_mgnt_netdev_ops = { ++ .ndo_open = mgnt_netdev_open, ++ .ndo_stop = mgnt_netdev_close, ++ .ndo_start_xmit = mgnt_xmit_entry, ++ //.ndo_set_mac_address = r871x_net_set_mac_address, ++ //.ndo_get_stats = r871x_net_get_stats, ++ //.ndo_do_ioctl = r871x_mp_ioctl, ++}; ++#endif ++ ++int hostapd_mode_init(_adapter *padapter) ++{ ++ unsigned char mac[ETH_ALEN]; ++ struct hostapd_priv *phostapdpriv; ++ struct net_device *pnetdev; ++ ++ pnetdev = rtw_alloc_etherdev(sizeof(struct hostapd_priv)); ++ if (!pnetdev) ++ return -ENOMEM; ++ ++ //SET_MODULE_OWNER(pnetdev); ++ ether_setup(pnetdev); ++ ++ //pnetdev->type = ARPHRD_IEEE80211; ++ ++ phostapdpriv = rtw_netdev_priv(pnetdev); ++ phostapdpriv->pmgnt_netdev = pnetdev; ++ phostapdpriv->padapter= padapter; ++ padapter->phostapdpriv = phostapdpriv; ++ ++ //pnetdev->init = NULL; ++ ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,29)) ++ ++ DBG_871X("register rtl871x_mgnt_netdev_ops to netdev_ops\n"); ++ ++ pnetdev->netdev_ops = &rtl871x_mgnt_netdev_ops; ++ ++#else ++ ++ pnetdev->open = mgnt_netdev_open; ++ ++ pnetdev->stop = mgnt_netdev_close; ++ ++ pnetdev->hard_start_xmit = mgnt_xmit_entry; ++ ++ //pnetdev->set_mac_address = r871x_net_set_mac_address; ++ ++ //pnetdev->get_stats = r871x_net_get_stats; ++ ++ //pnetdev->do_ioctl = r871x_mp_ioctl; ++ ++#endif ++ ++ pnetdev->watchdog_timeo = HZ; /* 1 second timeout */ ++ ++ //pnetdev->wireless_handlers = NULL; ++ ++#ifdef CONFIG_TCP_CSUM_OFFLOAD_TX ++ pnetdev->features |= NETIF_F_IP_CSUM; ++#endif ++ ++ ++ ++ if(dev_alloc_name(pnetdev,"mgnt.wlan%d") < 0) ++ { ++ DBG_871X("hostapd_mode_init(): dev_alloc_name, fail! \n"); ++ } ++ ++ ++ //SET_NETDEV_DEV(pnetdev, pintfpriv->udev); ++ ++ ++ mac[0]=0x00; ++ mac[1]=0xe0; ++ mac[2]=0x4c; ++ mac[3]=0x87; ++ mac[4]=0x11; ++ mac[5]=0x12; ++ ++ _rtw_memcpy(pnetdev->dev_addr, mac, ETH_ALEN); ++ ++ ++ netif_carrier_off(pnetdev); ++ ++ ++ /* Tell the network stack we exist */ ++ if (register_netdev(pnetdev) != 0) ++ { ++ DBG_871X("hostapd_mode_init(): register_netdev fail!\n"); ++ ++ if(pnetdev) ++ { ++ rtw_free_netdev(pnetdev); ++ } ++ } ++ ++ return 0; ++ ++} ++ ++void hostapd_mode_unload(_adapter *padapter) ++{ ++ struct hostapd_priv *phostapdpriv = padapter->phostapdpriv; ++ struct net_device *pnetdev = phostapdpriv->pmgnt_netdev; ++ ++ unregister_netdev(pnetdev); ++ rtw_free_netdev(pnetdev); ++ ++} ++ ++#endif ++#endif ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/os_intfs.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/os_intfs.c +new file mode 100644 +index 00000000..255d2b8d +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/os_intfs.c +@@ -0,0 +1,2986 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _OS_INTFS_C_ ++ ++#include ++ ++#if defined (PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) ++ ++#error "Shall be Linux or Windows, but not both!\n" ++ ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_USB_HCI ++#include ++#endif ++ ++#ifdef CONFIG_PCI_HCI ++#include ++#endif ++ ++#ifdef CONFIG_BR_EXT ++#include ++#endif //CONFIG_BR_EXT ++ ++#ifdef CONFIG_RF_GAIN_OFFSET ++#ifdef CONFIG_RTL8723A ++#define RF_GAIN_OFFSET_ON BIT0 ++#define REG_RF_BB_GAIN_OFFSET 0x7f ++#define RF_GAIN_OFFSET_MASK 0xfffff ++#else ++#define RF_GAIN_OFFSET_ON BIT4 ++#define REG_RF_BB_GAIN_OFFSET 0x55 ++#define RF_GAIN_OFFSET_MASK 0xfffff ++#endif //CONFIG_RTL8723A ++#endif //CONFIG_RF_GAIN_OFFSET ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Realtek Wireless Lan Driver"); ++MODULE_AUTHOR("Realtek Semiconductor Corp."); ++MODULE_VERSION(DRIVERVERSION); ++ ++/* module param defaults */ ++int rtw_chip_version = 0x00; ++int rtw_rfintfs = HWPI; ++int rtw_lbkmode = 0;//RTL8712_AIR_TRX; ++ ++ ++int rtw_network_mode = Ndis802_11IBSS;//Ndis802_11Infrastructure;//infra, ad-hoc, auto ++//NDIS_802_11_SSID ssid; ++int rtw_channel = 1;//ad-hoc support requirement ++int rtw_wireless_mode = WIRELESS_11BG_24N; ++int rtw_vrtl_carrier_sense = AUTO_VCS; ++int rtw_vcs_type = RTS_CTS;//* ++int rtw_rts_thresh = 2347;//* ++int rtw_frag_thresh = 2346;//* ++int rtw_preamble = PREAMBLE_LONG;//long, short, auto ++int rtw_scan_mode = 1;//active, passive ++int rtw_adhoc_tx_pwr = 1; ++int rtw_soft_ap = 0; ++//int smart_ps = 1; ++#ifdef CONFIG_POWER_SAVING ++int rtw_power_mgnt = 1; ++#ifdef CONFIG_IPS_LEVEL_2 ++int rtw_ips_mode = IPS_LEVEL_2; ++#else ++int rtw_ips_mode = IPS_NORMAL; ++#endif ++#else ++int rtw_power_mgnt = PS_MODE_ACTIVE; ++int rtw_ips_mode = IPS_NONE; ++#endif ++ ++int rtw_smart_ps = 2; ++ ++#ifdef CONFIG_TX_EARLY_MODE ++int rtw_early_mode=1; ++#endif ++module_param(rtw_ips_mode, int, 0644); ++MODULE_PARM_DESC(rtw_ips_mode,"The default IPS mode"); ++ ++int rtw_radio_enable = 1; ++int rtw_long_retry_lmt = 7; ++int rtw_short_retry_lmt = 7; ++int rtw_busy_thresh = 40; ++//int qos_enable = 0; //* ++int rtw_ack_policy = NORMAL_ACK; ++ ++int rtw_mp_mode = 0; ++ ++int rtw_software_encrypt = 0; ++int rtw_software_decrypt = 0; ++ ++int rtw_acm_method = 0;// 0:By SW 1:By HW. ++ ++int rtw_wmm_enable = 1;// default is set to enable the wmm. ++int rtw_uapsd_enable = 0; ++int rtw_uapsd_max_sp = NO_LIMIT; ++int rtw_uapsd_acbk_en = 0; ++int rtw_uapsd_acbe_en = 0; ++int rtw_uapsd_acvi_en = 0; ++int rtw_uapsd_acvo_en = 0; ++ ++#ifdef CONFIG_80211N_HT ++int rtw_ht_enable = 1; ++int rtw_cbw40_enable = 3; // 0 :diable, bit(0): enable 2.4g, bit(1): enable 5g ++int rtw_ampdu_enable = 1;//for enable tx_ampdu ++int rtw_rx_stbc = 1;// 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ ++int rtw_ampdu_amsdu = 0;// 0: disabled, 1:enabled, 2:auto ++#endif ++ ++int rtw_lowrate_two_xmit = 1;//Use 2 path Tx to transmit MCS0~7 and legacy mode ++ ++//int rf_config = RF_1T2R; // 1T2R ++int rtw_rf_config = RF_819X_MAX_TYPE; //auto ++int rtw_low_power = 0; ++#ifdef CONFIG_WIFI_TEST ++int rtw_wifi_spec = 1;//for wifi test ++#else ++int rtw_wifi_spec = 0; ++#endif ++int rtw_channel_plan = RT_CHANNEL_DOMAIN_MAX; ++ ++#ifdef CONFIG_BT_COEXIST ++int rtw_btcoex_enable = 1; ++int rtw_bt_iso = 2;// 0:Low, 1:High, 2:From Efuse ++int rtw_bt_sco = 3;// 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter, 4.Busy, 5.OtherBusy ++int rtw_bt_ampdu =1 ;// 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. ++#endif ++ ++int rtw_AcceptAddbaReq = _TRUE;// 0:Reject AP's Add BA req, 1:Accept AP's Add BA req. ++ ++int rtw_antdiv_cfg = 2; // 0:OFF , 1:ON, 2:decide by Efuse config ++int rtw_antdiv_type = 0 ; //0:decide by efuse 1: for 88EE, 1Tx and 1RxCG are diversity.(2 Ant with SPDT), 2: for 88EE, 1Tx and 2Rx are diversity.( 2 Ant, Tx and RxCG are both on aux port, RxCS is on main port ), 3: for 88EE, 1Tx and 1RxCG are fixed.(1Ant, Tx and RxCG are both on aux port) ++ ++ ++#ifdef CONFIG_USB_AUTOSUSPEND ++int rtw_enusbss = 1;//0:disable,1:enable ++#else ++int rtw_enusbss = 0;//0:disable,1:enable ++#endif ++ ++int rtw_hwpdn_mode=2;//0:disable,1:enable,2: by EFUSE config ++ ++#ifdef CONFIG_HW_PWRP_DETECTION ++int rtw_hwpwrp_detect = 1; ++#else ++int rtw_hwpwrp_detect = 0; //HW power ping detect 0:disable , 1:enable ++#endif ++ ++#ifdef CONFIG_USB_HCI ++int rtw_hw_wps_pbc = 1; ++#else ++int rtw_hw_wps_pbc = 0; ++#endif ++ ++#ifdef CONFIG_TX_MCAST2UNI ++int rtw_mc2u_disable = 0; ++#endif // CONFIG_TX_MCAST2UNI ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++int rtw_dmsp = 0; ++#endif // CONFIG_DUALMAC_CONCURRENT ++ ++#ifdef CONFIG_80211D ++int rtw_80211d = 0; ++#endif ++ ++#ifdef CONFIG_REGULATORY_CTRL ++int rtw_regulatory_id =2; ++#else ++int rtw_regulatory_id = 0xff;// Regulatory tab id, 0xff = follow efuse's setting ++#endif ++module_param(rtw_regulatory_id, int, 0644); ++ ++ ++#ifdef CONFIG_SPECIAL_SETTING_FOR_FUNAI_TV ++int rtw_force_ant = 2;//0 :normal, 1:Main ant, 2:Aux ant ++int rtw_force_igi =0;//0 :normal ++module_param(rtw_force_ant, int, 0644); ++module_param(rtw_force_igi, int, 0644); ++#endif ++ ++#ifdef CONFIG_QOS_OPTIMIZATION ++int rtw_qos_opt_enable=1;//0: disable,1:enable ++#else ++int rtw_qos_opt_enable=0;//0: disable,1:enable ++#endif ++module_param(rtw_qos_opt_enable,int,0644); ++ ++char* ifname = "wlan%d"; ++module_param(ifname, charp, 0644); ++MODULE_PARM_DESC(ifname, "The default name to allocate for first interface"); ++ ++char* if2name = "wlan%d"; ++module_param(if2name, charp, 0644); ++MODULE_PARM_DESC(if2name, "The default name to allocate for second interface"); ++ ++char* rtw_initmac = 0; // temp mac address if users want to use instead of the mac address in Efuse ++ ++module_param(rtw_initmac, charp, 0644); ++module_param(rtw_channel_plan, int, 0644); ++module_param(rtw_chip_version, int, 0644); ++module_param(rtw_rfintfs, int, 0644); ++module_param(rtw_lbkmode, int, 0644); ++module_param(rtw_network_mode, int, 0644); ++module_param(rtw_channel, int, 0644); ++module_param(rtw_mp_mode, int, 0644); ++module_param(rtw_wmm_enable, int, 0644); ++module_param(rtw_vrtl_carrier_sense, int, 0644); ++module_param(rtw_vcs_type, int, 0644); ++module_param(rtw_busy_thresh, int, 0644); ++#ifdef CONFIG_80211N_HT ++module_param(rtw_ht_enable, int, 0644); ++module_param(rtw_cbw40_enable, int, 0644); ++module_param(rtw_ampdu_enable, int, 0644); ++module_param(rtw_rx_stbc, int, 0644); ++module_param(rtw_ampdu_amsdu, int, 0644); ++#endif ++ ++module_param(rtw_lowrate_two_xmit, int, 0644); ++ ++module_param(rtw_rf_config, int, 0644); ++module_param(rtw_power_mgnt, int, 0644); ++module_param(rtw_smart_ps, int, 0644); ++module_param(rtw_low_power, int, 0644); ++module_param(rtw_wifi_spec, int, 0644); ++ ++module_param(rtw_antdiv_cfg, int, 0644); ++module_param(rtw_antdiv_type, int, 0644); ++ ++module_param(rtw_enusbss, int, 0644); ++module_param(rtw_hwpdn_mode, int, 0644); ++module_param(rtw_hwpwrp_detect, int, 0644); ++ ++module_param(rtw_hw_wps_pbc, int, 0644); ++ ++#ifdef CONFIG_TX_EARLY_MODE ++module_param(rtw_early_mode, int, 0644); ++#endif ++#ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE ++char *rtw_adaptor_info_caching_file_path= "/data/misc/wifi/rtw_cache"; ++module_param(rtw_adaptor_info_caching_file_path, charp, 0644); ++MODULE_PARM_DESC(rtw_adaptor_info_caching_file_path, "The path of adapter info cache file"); ++#endif //CONFIG_ADAPTOR_INFO_CACHING_FILE ++ ++#ifdef CONFIG_LAYER2_ROAMING ++uint rtw_max_roaming_times=2; ++module_param(rtw_max_roaming_times, uint, 0644); ++MODULE_PARM_DESC(rtw_max_roaming_times,"The max roaming times to try"); ++#endif //CONFIG_LAYER2_ROAMING ++ ++#ifdef CONFIG_IOL ++int rtw_fw_iol=1;// 0:Disable, 1:enable, 2:by usb speed ++module_param(rtw_fw_iol, int, 0644); ++MODULE_PARM_DESC(rtw_fw_iol,"FW IOL"); ++#endif //CONFIG_IOL ++ ++#ifdef CONFIG_FILE_FWIMG ++char *rtw_fw_file_path= ""; ++module_param(rtw_fw_file_path, charp, 0644); ++MODULE_PARM_DESC(rtw_fw_file_path, "The path of fw image"); ++#endif //CONFIG_FILE_FWIMG ++ ++#ifdef CONFIG_TX_MCAST2UNI ++module_param(rtw_mc2u_disable, int, 0644); ++#endif // CONFIG_TX_MCAST2UNI ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++module_param(rtw_dmsp, int, 0644); ++#endif // CONFIG_DUALMAC_CONCURRENT ++ ++#ifdef CONFIG_80211D ++module_param(rtw_80211d, int, 0644); ++MODULE_PARM_DESC(rtw_80211d, "Enable 802.11d mechanism"); ++#endif ++ ++#ifdef CONFIG_BT_COEXIST ++module_param(rtw_btcoex_enable, int, 0644); ++MODULE_PARM_DESC(rtw_btcoex_enable, "Enable BT co-existence mechanism"); ++#endif ++ ++uint rtw_notch_filter = RTW_NOTCH_FILTER; ++module_param(rtw_notch_filter, uint, 0644); ++MODULE_PARM_DESC(rtw_notch_filter, "0:Disable, 1:Enable, 2:Enable only for P2P"); ++ ++static uint loadparam(PADAPTER padapter, _nic_hdl pnetdev); ++int _netdev_open(struct net_device *pnetdev); ++int netdev_open (struct net_device *pnetdev); ++static int netdev_close (struct net_device *pnetdev); ++ ++//#ifdef RTK_DMP_PLATFORM ++#ifdef CONFIG_PROC_DEBUG ++#define RTL8192C_PROC_NAME "rtl819xC" ++#define RTL8192D_PROC_NAME "rtl819xD" ++static char rtw_proc_name[IFNAMSIZ]; ++static struct proc_dir_entry *rtw_proc = NULL; ++static int rtw_proc_cnt = 0; ++ ++#define RTW_PROC_NAME DRV_NAME ++ ++void rtw_proc_init_one(struct net_device *dev) ++{ ++ struct proc_dir_entry *dir_dev = NULL; ++ struct proc_dir_entry *entry=NULL; ++ _adapter *padapter = rtw_netdev_priv(dev); ++ u8 rf_type; ++ ++ if(rtw_proc == NULL) ++ { ++ if(padapter->chip_type == RTL8188C_8192C) ++ { ++ _rtw_memcpy(rtw_proc_name, RTL8192C_PROC_NAME, sizeof(RTL8192C_PROC_NAME)); ++ } ++ else if(padapter->chip_type == RTL8192D) ++ { ++ _rtw_memcpy(rtw_proc_name, RTL8192D_PROC_NAME, sizeof(RTL8192D_PROC_NAME)); ++ } ++ else if(padapter->chip_type == RTL8723A) ++ { ++ _rtw_memcpy(rtw_proc_name, RTW_PROC_NAME, sizeof(RTW_PROC_NAME)); ++ } ++ else if(padapter->chip_type == RTL8188E) ++ { ++ _rtw_memcpy(rtw_proc_name, RTW_PROC_NAME, sizeof(RTW_PROC_NAME)); ++ } ++ else ++ { ++ _rtw_memcpy(rtw_proc_name, RTW_PROC_NAME, sizeof(RTW_PROC_NAME)); ++ } ++ ++#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ rtw_proc=create_proc_entry(rtw_proc_name, S_IFDIR, proc_net); ++#else ++ rtw_proc=create_proc_entry(rtw_proc_name, S_IFDIR, init_net.proc_net); ++#endif ++ if (rtw_proc == NULL) { ++ DBG_871X(KERN_ERR "Unable to create rtw_proc directory\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("ver_info", S_IFREG | S_IRUGO, rtw_proc, proc_get_drv_version, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++#ifdef DBG_MEM_ALLOC ++ entry = create_proc_read_entry("mstat", S_IFREG | S_IRUGO, ++ rtw_proc, proc_get_mstat, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++#endif /* DBG_MEM_ALLOC */ ++ } ++ ++ ++ ++ if(padapter->dir_dev == NULL) ++ { ++ padapter->dir_dev = create_proc_entry(dev->name, ++ S_IFDIR | S_IRUGO | S_IXUGO, ++ rtw_proc); ++ ++ dir_dev = padapter->dir_dev; ++ ++ if(dir_dev==NULL) ++ { ++ if(rtw_proc_cnt == 0) ++ { ++ if(rtw_proc){ ++#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ remove_proc_entry(rtw_proc_name, proc_net); ++#else ++ remove_proc_entry(rtw_proc_name, init_net.proc_net); ++#endif ++ rtw_proc = NULL; ++ } ++ } ++ ++ DBG_871X("Unable to create dir_dev directory\n"); ++ return; ++ } ++ } ++ else ++ { ++ return; ++ } ++ ++ rtw_proc_cnt++; ++ ++ entry = create_proc_read_entry("write_reg", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_write_reg, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_write_reg; ++ ++ entry = create_proc_read_entry("read_reg", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_read_reg, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_read_reg; ++ ++ ++ entry = create_proc_read_entry("fwstate", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_fwstate, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ ++ entry = create_proc_read_entry("sec_info", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_sec_info, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ ++ entry = create_proc_read_entry("mlmext_state", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_mlmext_state, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ ++ entry = create_proc_read_entry("qos_option", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_qos_option, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("ht_option", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_ht_option, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("rf_info", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_rf_info, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("ap_info", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_ap_info, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("adapter_state", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_adapter_state, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("trx_info", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_trx_info, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("mac_reg_dump1", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_mac_reg_dump1, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("mac_reg_dump2", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_mac_reg_dump2, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("mac_reg_dump3", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_mac_reg_dump3, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("bb_reg_dump1", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_bb_reg_dump1, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("bb_reg_dump2", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_bb_reg_dump2, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("bb_reg_dump3", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_bb_reg_dump3, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("rf_reg_dump1", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_rf_reg_dump1, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("rf_reg_dump2", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_rf_reg_dump2, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ if((RF_1T2R == rf_type) ||(RF_1T1R ==rf_type )) { ++ entry = create_proc_read_entry("rf_reg_dump3", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_rf_reg_dump3, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("rf_reg_dump4", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_rf_reg_dump4, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ } ++ ++#ifdef CONFIG_AP_MODE ++ ++ entry = create_proc_read_entry("all_sta_info", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_all_sta_info, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++#endif ++ ++#ifdef DBG_MEMORY_LEAK ++ entry = create_proc_read_entry("_malloc_cnt", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_malloc_cnt, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++#endif ++ ++#ifdef CONFIG_FIND_BEST_CHANNEL ++ entry = create_proc_read_entry("best_channel", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_best_channel, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_best_channel; ++#endif ++ ++ entry = create_proc_read_entry("rx_signal", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_rx_signal, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_rx_signal; ++#ifdef CONFIG_80211N_HT ++ entry = create_proc_read_entry("ht_enable", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_ht_enable, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_ht_enable; ++ ++ entry = create_proc_read_entry("cbw40_enable", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_cbw40_enable, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_cbw40_enable; ++ ++ entry = create_proc_read_entry("ampdu_enable", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_ampdu_enable, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_ampdu_enable; ++ ++ entry = create_proc_read_entry("rx_stbc", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_rx_stbc, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_rx_stbc; ++#endif //CONFIG_80211N_HT ++ ++ entry = create_proc_read_entry("path_rssi", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_two_path_rssi, dev); ++ ++ ++ entry = create_proc_read_entry("rssi_disp", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_rssi_disp, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_rssi_disp; ++#ifdef CONFIG_BT_COEXIST ++ entry = create_proc_read_entry("btcoex_dbg", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_btcoex_dbg, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_btcoex_dbg; ++#endif /*CONFIG_BT_COEXIST*/ ++ ++#if defined(DBG_CONFIG_ERROR_DETECT) ++ entry = create_proc_read_entry("sreset", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_sreset, dev); ++ if (!entry) { ++ DBG_871X("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_sreset; ++#endif /* DBG_CONFIG_ERROR_DETECT */ ++ ++ /* for odm */ ++ { ++ struct proc_dir_entry *dir_odm = NULL; ++ ++ if (padapter->dir_odm == NULL) { ++ padapter->dir_odm = create_proc_entry( ++ "odm", S_IFDIR | S_IRUGO | S_IXUGO, dir_dev); ++ ++ dir_odm = padapter->dir_odm; ++ ++ if(dir_odm==NULL) { ++ DBG_871X("Unable to create dir_odm directory\n"); ++ return; ++ } ++ } ++ else ++ { ++ return; ++ } ++ ++ entry = create_proc_read_entry("dbg_comp", S_IFREG | S_IRUGO, ++ dir_odm, proc_get_odm_dbg_comp, dev); ++ if (!entry) { ++ rtw_warn_on(1); ++ return; ++ } ++ entry->write_proc = proc_set_odm_dbg_comp; ++ ++ entry = create_proc_read_entry("dbg_level", S_IFREG | S_IRUGO, ++ dir_odm, proc_get_odm_dbg_level, dev); ++ if (!entry) { ++ rtw_warn_on(1); ++ return; ++ } ++ entry->write_proc = proc_set_odm_dbg_level; ++ ++ entry = create_proc_read_entry("adaptivity", S_IFREG | S_IRUGO, ++ dir_odm, proc_get_odm_adaptivity, dev); ++ if (!entry) { ++ rtw_warn_on(1); ++ return; ++ } ++ entry->write_proc = proc_set_odm_adaptivity; ++ } ++} ++ ++void rtw_proc_remove_one(struct net_device *dev) ++{ ++ struct proc_dir_entry *dir_dev = NULL; ++ _adapter *padapter = rtw_netdev_priv(dev); ++ u8 rf_type; ++ ++ dir_dev = padapter->dir_dev; ++ padapter->dir_dev = NULL; ++ ++ if (dir_dev) { ++ ++ remove_proc_entry("write_reg", dir_dev); ++ remove_proc_entry("read_reg", dir_dev); ++ remove_proc_entry("fwstate", dir_dev); ++ remove_proc_entry("sec_info", dir_dev); ++ remove_proc_entry("mlmext_state", dir_dev); ++ remove_proc_entry("qos_option", dir_dev); ++ remove_proc_entry("ht_option", dir_dev); ++ remove_proc_entry("rf_info", dir_dev); ++ remove_proc_entry("ap_info", dir_dev); ++ remove_proc_entry("adapter_state", dir_dev); ++ remove_proc_entry("trx_info", dir_dev); ++ ++ remove_proc_entry("mac_reg_dump1", dir_dev); ++ remove_proc_entry("mac_reg_dump2", dir_dev); ++ remove_proc_entry("mac_reg_dump3", dir_dev); ++ remove_proc_entry("bb_reg_dump1", dir_dev); ++ remove_proc_entry("bb_reg_dump2", dir_dev); ++ remove_proc_entry("bb_reg_dump3", dir_dev); ++ remove_proc_entry("rf_reg_dump1", dir_dev); ++ remove_proc_entry("rf_reg_dump2", dir_dev); ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ if((RF_1T2R == rf_type) ||(RF_1T1R ==rf_type )) { ++ remove_proc_entry("rf_reg_dump3", dir_dev); ++ remove_proc_entry("rf_reg_dump4", dir_dev); ++ } ++#ifdef CONFIG_AP_MODE ++ remove_proc_entry("all_sta_info", dir_dev); ++#endif ++ ++#ifdef DBG_MEMORY_LEAK ++ remove_proc_entry("_malloc_cnt", dir_dev); ++#endif ++ ++#ifdef CONFIG_FIND_BEST_CHANNEL ++ remove_proc_entry("best_channel", dir_dev); ++#endif ++ remove_proc_entry("rx_signal", dir_dev); ++#ifdef CONFIG_80211N_HT ++ remove_proc_entry("cbw40_enable", dir_dev); ++ ++ remove_proc_entry("ht_enable", dir_dev); ++ ++ remove_proc_entry("ampdu_enable", dir_dev); ++ ++ remove_proc_entry("rx_stbc", dir_dev); ++#endif //CONFIG_80211N_HT ++ remove_proc_entry("path_rssi", dir_dev); ++ ++ remove_proc_entry("rssi_disp", dir_dev); ++ ++#ifdef CONFIG_BT_COEXIST ++ remove_proc_entry("btcoex_dbg", dir_dev); ++#endif //CONFIG_BT_COEXIST ++ ++#if defined(DBG_CONFIG_ERROR_DETECT) ++ remove_proc_entry("sreset", dir_dev); ++#endif /* DBG_CONFIG_ERROR_DETECT */ ++ ++ /* for odm */ ++ { ++ struct proc_dir_entry *dir_odm = NULL; ++ dir_odm = padapter->dir_odm; ++ padapter->dir_odm = NULL; ++ ++ if (dir_odm) { ++ remove_proc_entry("dbg_comp", dir_odm); ++ remove_proc_entry("dbg_level", dir_odm); ++ remove_proc_entry("adaptivity", dir_odm); ++ ++ remove_proc_entry("odm", dir_dev); ++ } ++ } ++ ++ remove_proc_entry(dev->name, rtw_proc); ++ dir_dev = NULL; ++ ++ } ++ else ++ { ++ return; ++ } ++ ++ rtw_proc_cnt--; ++ ++ if(rtw_proc_cnt == 0) ++ { ++ if(rtw_proc){ ++ remove_proc_entry("ver_info", rtw_proc); ++ #ifdef DBG_MEM_ALLOC ++ remove_proc_entry("mstat", rtw_proc); ++ #endif /* DBG_MEM_ALLOC */ ++#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ remove_proc_entry(rtw_proc_name, proc_net); ++#else ++ remove_proc_entry(rtw_proc_name, init_net.proc_net); ++#endif ++ rtw_proc = NULL; ++ } ++ } ++} ++#endif ++ ++uint loadparam( _adapter *padapter, _nic_hdl pnetdev); ++uint loadparam( _adapter *padapter, _nic_hdl pnetdev) ++{ ++ ++ uint status = _SUCCESS; ++ struct registry_priv *registry_par = &padapter->registrypriv; ++ ++_func_enter_; ++ ++ registry_par->chip_version = (u8)rtw_chip_version; ++ registry_par->rfintfs = (u8)rtw_rfintfs; ++ registry_par->lbkmode = (u8)rtw_lbkmode; ++ //registry_par->hci = (u8)hci; ++ registry_par->network_mode = (u8)rtw_network_mode; ++ ++ _rtw_memcpy(registry_par->ssid.Ssid, "ANY", 3); ++ registry_par->ssid.SsidLength = 3; ++ ++ registry_par->channel = (u8)rtw_channel; ++ registry_par->wireless_mode = (u8)rtw_wireless_mode; ++ registry_par->vrtl_carrier_sense = (u8)rtw_vrtl_carrier_sense ; ++ registry_par->vcs_type = (u8)rtw_vcs_type; ++ registry_par->rts_thresh=(u16)rtw_rts_thresh; ++ registry_par->frag_thresh=(u16)rtw_frag_thresh; ++ registry_par->preamble = (u8)rtw_preamble; ++ registry_par->scan_mode = (u8)rtw_scan_mode; ++ registry_par->adhoc_tx_pwr = (u8)rtw_adhoc_tx_pwr; ++ registry_par->soft_ap= (u8)rtw_soft_ap; ++ registry_par->smart_ps = (u8)rtw_smart_ps; ++ registry_par->power_mgnt = (u8)rtw_power_mgnt; ++ registry_par->ips_mode = (u8)rtw_ips_mode; ++ registry_par->radio_enable = (u8)rtw_radio_enable; ++ registry_par->long_retry_lmt = (u8)rtw_long_retry_lmt; ++ registry_par->short_retry_lmt = (u8)rtw_short_retry_lmt; ++ registry_par->busy_thresh = (u16)rtw_busy_thresh; ++ //registry_par->qos_enable = (u8)rtw_qos_enable; ++ registry_par->ack_policy = (u8)rtw_ack_policy; ++ registry_par->mp_mode = (u8)rtw_mp_mode; ++ registry_par->software_encrypt = (u8)rtw_software_encrypt; ++ registry_par->software_decrypt = (u8)rtw_software_decrypt; ++ ++ registry_par->acm_method = (u8)rtw_acm_method; ++ ++ //UAPSD ++ registry_par->wmm_enable = (u8)rtw_wmm_enable; ++ registry_par->uapsd_enable = (u8)rtw_uapsd_enable; ++ registry_par->uapsd_max_sp = (u8)rtw_uapsd_max_sp; ++ registry_par->uapsd_acbk_en = (u8)rtw_uapsd_acbk_en; ++ registry_par->uapsd_acbe_en = (u8)rtw_uapsd_acbe_en; ++ registry_par->uapsd_acvi_en = (u8)rtw_uapsd_acvi_en; ++ registry_par->uapsd_acvo_en = (u8)rtw_uapsd_acvo_en; ++ ++#ifdef CONFIG_80211N_HT ++ registry_par->ht_enable = (u8)rtw_ht_enable; ++ registry_par->cbw40_enable = (u8)rtw_cbw40_enable; ++ registry_par->ampdu_enable = (u8)rtw_ampdu_enable; ++ registry_par->rx_stbc = (u8)rtw_rx_stbc; ++ registry_par->ampdu_amsdu = (u8)rtw_ampdu_amsdu; ++#endif ++#ifdef CONFIG_TX_EARLY_MODE ++ registry_par->early_mode = (u8)rtw_early_mode; ++#endif ++ registry_par->lowrate_two_xmit = (u8)rtw_lowrate_two_xmit; ++ registry_par->rf_config = (u8)rtw_rf_config; ++ registry_par->low_power = (u8)rtw_low_power; ++ ++ ++ registry_par->wifi_spec = (u8)rtw_wifi_spec; ++ ++ registry_par->channel_plan = (u8)rtw_channel_plan; ++ ++#ifdef CONFIG_BT_COEXIST ++ registry_par->btcoex = (u8)rtw_btcoex_enable; ++ registry_par->bt_iso = (u8)rtw_bt_iso; ++ registry_par->bt_sco = (u8)rtw_bt_sco; ++ registry_par->bt_ampdu = (u8)rtw_bt_ampdu; ++#endif ++ ++ registry_par->bAcceptAddbaReq = (u8)rtw_AcceptAddbaReq; ++ ++ registry_par->antdiv_cfg = (u8)rtw_antdiv_cfg; ++ registry_par->antdiv_type = (u8)rtw_antdiv_type; ++ ++#ifdef CONFIG_AUTOSUSPEND ++ registry_par->usbss_enable = (u8)rtw_enusbss;//0:disable,1:enable ++#endif ++#ifdef SUPPORT_HW_RFOFF_DETECTED ++ registry_par->hwpdn_mode = (u8)rtw_hwpdn_mode;//0:disable,1:enable,2:by EFUSE config ++ registry_par->hwpwrp_detect = (u8)rtw_hwpwrp_detect;//0:disable,1:enable ++#endif ++ ++ registry_par->qos_opt_enable = (u8)rtw_qos_opt_enable; ++ registry_par->hw_wps_pbc = (u8)rtw_hw_wps_pbc; ++ ++#ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE ++ snprintf(registry_par->adaptor_info_caching_file_path, PATH_LENGTH_MAX, "%s", rtw_adaptor_info_caching_file_path); ++ registry_par->adaptor_info_caching_file_path[PATH_LENGTH_MAX-1]=0; ++#endif ++ ++#ifdef CONFIG_LAYER2_ROAMING ++ registry_par->max_roaming_times = (u8)rtw_max_roaming_times; ++#ifdef CONFIG_INTEL_WIDI ++ registry_par->max_roaming_times = (u8)rtw_max_roaming_times + 2; ++#endif // CONFIG_INTEL_WIDI ++#endif ++ ++#ifdef CONFIG_IOL ++ registry_par->fw_iol = rtw_fw_iol; ++#endif ++ ++#ifdef CONFIG_DUALMAC_CONCURRENT ++ registry_par->dmsp= (u8)rtw_dmsp; ++#endif ++ ++#ifdef CONFIG_80211D ++ registry_par->enable80211d = (u8)rtw_80211d; ++#endif ++ ++ snprintf(registry_par->ifname, 16, "%s", ifname); ++ snprintf(registry_par->if2name, 16, "%s", if2name); ++ ++ registry_par->notch_filter = (u8)rtw_notch_filter; ++ ++#ifdef CONFIG_SPECIAL_SETTING_FOR_FUNAI_TV ++ registry_par->force_ant = (u8)rtw_force_ant; ++ registry_par->force_igi = (u8)rtw_force_igi; ++#endif ++ registry_par->regulatory_tid = (u8)rtw_regulatory_id; ++ ++ ++_func_exit_; ++ ++ return status; ++} ++ ++static int rtw_net_set_mac_address(struct net_device *pnetdev, void *p) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev); ++ struct sockaddr *addr = p; ++ ++ if(padapter->bup == _FALSE) ++ { ++ //DBG_871X("r8711_net_set_mac_address(), MAC=%x:%x:%x:%x:%x:%x\n", addr->sa_data[0], addr->sa_data[1], addr->sa_data[2], addr->sa_data[3], ++ //addr->sa_data[4], addr->sa_data[5]); ++ _rtw_memcpy(padapter->eeprompriv.mac_addr, addr->sa_data, ETH_ALEN); ++ //_rtw_memcpy(pnetdev->dev_addr, addr->sa_data, ETH_ALEN); ++ //padapter->bset_hwaddr = _TRUE; ++ } ++ ++ return 0; ++} ++ ++static struct net_device_stats *rtw_net_get_stats(struct net_device *pnetdev) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev); ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct recv_priv *precvpriv = &(padapter->recvpriv); ++ ++ padapter->stats.tx_packets = pxmitpriv->tx_pkts;//pxmitpriv->tx_pkts++; ++ padapter->stats.rx_packets = precvpriv->rx_pkts;//precvpriv->rx_pkts++; ++ padapter->stats.tx_dropped = pxmitpriv->tx_drop; ++ padapter->stats.rx_dropped = precvpriv->rx_drop; ++ padapter->stats.tx_bytes = pxmitpriv->tx_bytes; ++ padapter->stats.rx_bytes = precvpriv->rx_bytes; ++ ++ return &padapter->stats; ++} ++ ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)) ++/* ++ * AC to queue mapping ++ * ++ * AC_VO -> queue 0 ++ * AC_VI -> queue 1 ++ * AC_BE -> queue 2 ++ * AC_BK -> queue 3 ++ */ ++static const u16 rtw_1d_to_queue[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; ++ ++/* Given a data frame determine the 802.1p/1d tag to use. */ ++unsigned int rtw_classify8021d(struct sk_buff *skb) ++{ ++ unsigned int dscp; ++ ++ /* skb->priority values from 256->263 are magic values to ++ * directly indicate a specific 802.1d priority. This is used ++ * to allow 802.1d priority to be passed directly in from VLAN ++ * tags, etc. ++ */ ++ if (skb->priority >= 256 && skb->priority <= 263) ++ return skb->priority - 256; ++ ++ switch (skb->protocol) { ++ case htons(ETH_P_IP): ++ dscp = ip_hdr(skb)->tos & 0xfc; ++ break; ++ default: ++ return 0; ++ } ++ ++ return dscp >> 5; ++} ++ ++static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb) ++{ ++ _adapter *padapter = rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ skb->priority = rtw_classify8021d(skb); ++ ++ if(pmlmepriv->acm_mask != 0) ++ { ++ skb->priority = qos_acm(pmlmepriv->acm_mask, skb->priority); ++ } ++ ++ return rtw_1d_to_queue[skb->priority]; ++} ++ ++u16 rtw_recv_select_queue(struct sk_buff *skb) ++{ ++ struct iphdr *piphdr; ++ unsigned int dscp; ++ u16 eth_type; ++ u32 priority; ++ u8 *pdata = skb->data; ++ ++ _rtw_memcpy(ð_type, pdata+(ETH_ALEN<<1), 2); ++ ++ switch (eth_type) { ++ case htons(ETH_P_IP): ++ ++ piphdr = (struct iphdr *)(pdata+ETH_HLEN); ++ ++ dscp = piphdr->tos & 0xfc; ++ ++ priority = dscp >> 5; ++ ++ break; ++ default: ++ priority = 0; ++ } ++ ++ return rtw_1d_to_queue[priority]; ++ ++} ++ ++#endif ++ ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,29)) ++static const struct net_device_ops rtw_netdev_ops = { ++ .ndo_open = netdev_open, ++ .ndo_stop = netdev_close, ++ .ndo_start_xmit = rtw_xmit_entry, ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)) ++ .ndo_select_queue = rtw_select_queue, ++#endif ++ .ndo_set_mac_address = rtw_net_set_mac_address, ++ .ndo_get_stats = rtw_net_get_stats, ++ .ndo_do_ioctl = rtw_ioctl, ++}; ++#endif ++ ++int rtw_init_netdev_name(struct net_device *pnetdev, const char *ifname) ++{ ++ _adapter *padapter = rtw_netdev_priv(pnetdev); ++ ++#ifdef CONFIG_EASY_REPLACEMENT ++ struct net_device *TargetNetdev = NULL; ++ _adapter *TargetAdapter = NULL; ++ struct net *devnet = NULL; ++ ++ if(padapter->bDongle == 1) ++ { ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ TargetNetdev = dev_get_by_name("wlan0"); ++#else ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) ++ devnet = pnetdev->nd_net; ++ #else ++ devnet = dev_net(pnetdev); ++ #endif ++ TargetNetdev = dev_get_by_name(devnet, "wlan0"); ++#endif ++ if(TargetNetdev) { ++ DBG_871X("Force onboard module driver disappear !!!\n"); ++ TargetAdapter = rtw_netdev_priv(TargetNetdev); ++ TargetAdapter->DriverState = DRIVER_DISAPPEAR; ++ ++ padapter->pid[0] = TargetAdapter->pid[0]; ++ padapter->pid[1] = TargetAdapter->pid[1]; ++ padapter->pid[2] = TargetAdapter->pid[2]; ++ ++ dev_put(TargetNetdev); ++ unregister_netdev(TargetNetdev); ++ ++ if(TargetAdapter->chip_type == padapter->chip_type) ++ rtw_proc_remove_one(TargetNetdev); ++ ++ padapter->DriverState = DRIVER_REPLACE_DONGLE; ++ } ++ } ++#endif ++ ++ if(dev_alloc_name(pnetdev, ifname) < 0) ++ { ++ RT_TRACE(_module_os_intfs_c_,_drv_err_,("dev_alloc_name, fail! \n")); ++ } ++ ++ netif_carrier_off(pnetdev); ++ //rtw_netif_stop_queue(pnetdev); ++ ++ return 0; ++} ++ ++struct net_device *rtw_init_netdev(_adapter *old_padapter) ++{ ++ _adapter *padapter; ++ struct net_device *pnetdev; ++ ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("+init_net_dev\n")); ++ ++ if(old_padapter != NULL) ++ pnetdev = rtw_alloc_etherdev_with_old_priv(sizeof(_adapter), (void *)old_padapter); ++ else ++ pnetdev = rtw_alloc_etherdev(sizeof(_adapter)); ++ ++ if (!pnetdev) ++ return NULL; ++ ++ padapter = rtw_netdev_priv(pnetdev); ++ padapter->pnetdev = pnetdev; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++ SET_MODULE_OWNER(pnetdev); ++#endif ++ ++ //pnetdev->init = NULL; ++ ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,29)) ++ DBG_871X("register rtw_netdev_ops to netdev_ops\n"); ++ pnetdev->netdev_ops = &rtw_netdev_ops; ++#else ++ pnetdev->open = netdev_open; ++ pnetdev->stop = netdev_close; ++ pnetdev->hard_start_xmit = rtw_xmit_entry; ++ pnetdev->set_mac_address = rtw_net_set_mac_address; ++ pnetdev->get_stats = rtw_net_get_stats; ++ pnetdev->do_ioctl = rtw_ioctl; ++#endif ++ ++ ++#ifdef CONFIG_TCP_CSUM_OFFLOAD_TX ++ pnetdev->features |= NETIF_F_IP_CSUM; ++#endif ++ //pnetdev->tx_timeout = NULL; ++ pnetdev->watchdog_timeo = HZ*3; /* 3 second timeout */ ++#ifdef CONFIG_WIRELESS_EXT ++ pnetdev->wireless_handlers = (struct iw_handler_def *)&rtw_handlers_def; ++#endif ++ ++#ifdef WIRELESS_SPY ++ //priv->wireless_data.spy_data = &priv->spy_data; ++ //pnetdev->wireless_data = &priv->wireless_data; ++#endif ++ ++ //step 2. ++ loadparam(padapter, pnetdev); ++ ++ return pnetdev; ++ ++} ++ ++u32 rtw_start_drv_threads(_adapter *padapter) ++{ ++ u32 _status = _SUCCESS; ++ ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("+rtw_start_drv_threads\n")); ++#ifdef CONFIG_XMIT_THREAD_MODE ++#if defined(CONFIG_SDIO_HCI) && defined(CONFIG_CONCURRENT_MODE) ++ if(padapter->adapter_type == PRIMARY_ADAPTER){ ++#endif ++ padapter->xmitThread = kthread_run(rtw_xmit_thread, padapter, "RTW_XMIT_THREAD"); ++ if(IS_ERR(padapter->xmitThread)) ++ _status = _FAIL; ++#if defined(CONFIG_SDIO_HCI) && defined(CONFIG_CONCURRENT_MODE) ++ } ++#endif // CONFIG_SDIO_HCI+CONFIG_CONCURRENT_MODE ++#endif ++ ++#ifdef CONFIG_RECV_THREAD_MODE ++ padapter->recvThread = kthread_run(rtw_recv_thread, padapter, "RTW_RECV_THREAD"); ++ if(IS_ERR(padapter->recvThread)) ++ _status = _FAIL; ++#endif ++ ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(padapter->isprimary == _TRUE) ++#endif //CONFIG_CONCURRENT_MODE ++ { ++ padapter->cmdThread = kthread_run(rtw_cmd_thread, padapter, "RTW_CMD_THREAD"); ++ if(IS_ERR(padapter->cmdThread)) ++ _status = _FAIL; ++ else ++ _rtw_down_sema(&padapter->cmdpriv.terminate_cmdthread_sema); //wait for cmd_thread to run ++ } ++ ++ ++#ifdef CONFIG_EVENT_THREAD_MODE ++ padapter->evtThread = kthread_run(event_thread, padapter, "RTW_EVENT_THREAD"); ++ if(IS_ERR(padapter->evtThread)) ++ _status = _FAIL; ++#endif ++ ++ rtw_hal_start_thread(padapter); ++ return _status; ++ ++} ++ ++void rtw_unregister_netdevs(struct dvobj_priv *dvobj) ++{ ++ int i; ++ _adapter *padapter = NULL; ++ ++ for(i=0;iiface_nums;i++) ++ { ++ struct net_device *pnetdev = NULL; ++ ++ padapter = dvobj->padapters[i]; ++ ++ if (padapter == NULL) ++ continue; ++ ++ pnetdev = padapter->pnetdev; ++ ++ if((padapter->DriverState != DRIVER_DISAPPEAR) && pnetdev) { ++ ++ unregister_netdev(pnetdev); //will call netdev_close() ++ rtw_proc_remove_one(pnetdev); ++ } ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ rtw_wdev_unregister(padapter->rtw_wdev); ++#endif ++ ++ } ++ ++} ++ ++ ++void rtw_stop_drv_threads (_adapter *padapter) ++{ ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("+rtw_stop_drv_threads\n")); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(padapter->isprimary == _TRUE) ++#endif //CONFIG_CONCURRENT_MODE ++ { ++ rtw_stop_cmd_thread(padapter); ++ } ++ ++#ifdef CONFIG_EVENT_THREAD_MODE ++ _rtw_up_sema(&padapter->evtpriv.evt_notify); ++ if(padapter->evtThread){ ++ _rtw_down_sema(&padapter->evtpriv.terminate_evtthread_sema); ++ } ++#endif ++ ++#ifdef CONFIG_XMIT_THREAD_MODE ++ // Below is to termindate tx_thread... ++#if defined(CONFIG_SDIO_HCI) && defined(CONFIG_CONCURRENT_MODE) ++ // Only wake-up primary adapter ++ if(padapter->adapter_type == PRIMARY_ADAPTER) ++#endif //SDIO_HCI + CONCURRENT ++ { ++ _rtw_up_sema(&padapter->xmitpriv.xmit_sema); ++ _rtw_down_sema(&padapter->xmitpriv.terminate_xmitthread_sema); ++ } ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("\n drv_halt: rtw_xmit_thread can be terminated ! \n")); ++#endif ++ ++#ifdef CONFIG_RECV_THREAD_MODE ++ // Below is to termindate rx_thread... ++ _rtw_up_sema(&padapter->recvpriv.recv_sema); ++ _rtw_down_sema(&padapter->recvpriv.terminate_recvthread_sema); ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("\n drv_halt:recv_thread can be terminated! \n")); ++#endif ++ ++ rtw_hal_stop_thread(padapter); ++} ++ ++u8 rtw_init_default_value(_adapter *padapter); ++u8 rtw_init_default_value(_adapter *padapter) ++{ ++ u8 ret = _SUCCESS; ++ struct registry_priv* pregistrypriv = &padapter->registrypriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_priv *pmlmepriv= &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ //xmit_priv ++ pxmitpriv->vcs_setting = pregistrypriv->vrtl_carrier_sense; ++ pxmitpriv->vcs = pregistrypriv->vcs_type; ++ pxmitpriv->vcs_type = pregistrypriv->vcs_type; ++ //pxmitpriv->rts_thresh = pregistrypriv->rts_thresh; ++ pxmitpriv->frag_len = pregistrypriv->frag_thresh; ++ ++ ++ ++ //recv_priv ++ ++ ++ //mlme_priv ++ pmlmepriv->scan_interval = SCAN_INTERVAL;// 30*2 sec = 60sec ++ pmlmepriv->scan_mode = SCAN_ACTIVE; ++ ++ //qos_priv ++ //pmlmepriv->qospriv.qos_option = pregistrypriv->wmm_enable; ++ ++ //ht_priv ++#ifdef CONFIG_80211N_HT ++ pmlmepriv->htpriv.ampdu_enable = _FALSE;//set to disabled ++#endif ++ ++ //security_priv ++ //rtw_get_encrypt_decrypt_from_registrypriv(padapter); ++ psecuritypriv->binstallGrpkey = _FAIL; ++ psecuritypriv->sw_encrypt=pregistrypriv->software_encrypt; ++ psecuritypriv->sw_decrypt=pregistrypriv->software_decrypt; ++ ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; //open system ++ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ ++ psecuritypriv->dot11PrivacyKeyIndex = 0; ++ ++ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ psecuritypriv->dot118021XGrpKeyid = 1; ++ ++ psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen; ++ psecuritypriv->ndisencryptstatus = Ndis802_11WEPDisabled; ++ ++ ++ //pwrctrl_priv ++ ++ ++ //registry_priv ++ rtw_init_registrypriv_dev_network(padapter); ++ rtw_update_registrypriv_dev_network(padapter); ++ ++ ++ //hal_priv ++ rtw_hal_def_value_init(padapter); ++ ++ //misc. ++ padapter->bReadPortCancel = _FALSE; ++ padapter->bWritePortCancel = _FALSE; ++ padapter->bRxRSSIDisplay = 0; ++ padapter->bNotifyChannelChange = 0; ++#ifdef CONFIG_P2P ++ padapter->bShowGetP2PState = 1; ++#endif ++ ++ return ret; ++} ++ ++u8 rtw_reset_drv_sw(_adapter *padapter) ++{ ++ u8 ret8=_SUCCESS; ++ struct mlme_priv *pmlmepriv= &padapter->mlmepriv; ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); ++ ++ //hal_priv ++ rtw_hal_def_value_init(padapter); ++ padapter->bReadPortCancel = _FALSE; ++ padapter->bWritePortCancel = _FALSE; ++ padapter->bRxRSSIDisplay = 0; ++ pmlmepriv->scan_interval = SCAN_INTERVAL;// 30*2 sec = 60sec ++ ++ padapter->xmitpriv.tx_pkts = 0; ++ padapter->recvpriv.rx_pkts = 0; ++ ++ pmlmepriv->LinkDetectInfo.bBusyTraffic = _FALSE; ++ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY |_FW_UNDER_LINKING); ++ ++#ifdef CONFIG_AUTOSUSPEND ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,22) && LINUX_VERSION_CODE<=KERNEL_VERSION(2,6,34)) ++ adapter_to_dvobj(padapter)->pusbdev->autosuspend_disabled = 1;//autosuspend disabled by the user ++ #endif ++#endif ++ ++#ifdef DBG_CONFIG_ERROR_DETECT ++ rtw_hal_sreset_reset_value(padapter); ++#endif ++ pwrctrlpriv->pwr_state_check_cnts = 0; ++ ++ //mlmeextpriv ++ padapter->mlmeextpriv.sitesurvey_res.state= SCAN_DISABLE; ++ ++#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS ++ rtw_set_signal_stat_timer(&padapter->recvpriv); ++#endif ++ ++ return ret8; ++} ++ ++ ++u8 rtw_init_drv_sw(_adapter *padapter) ++{ ++ ++ u8 ret8=_SUCCESS; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("+rtw_init_drv_sw\n")); ++ ++ if ((rtw_init_cmd_priv(&padapter->cmdpriv)) == _FAIL) ++ { ++ RT_TRACE(_module_os_intfs_c_,_drv_err_,("\n Can't init cmd_priv\n")); ++ ret8=_FAIL; ++ goto exit; ++ } ++ ++ padapter->cmdpriv.padapter=padapter; ++ ++ if ((rtw_init_evt_priv(&padapter->evtpriv)) == _FAIL) ++ { ++ RT_TRACE(_module_os_intfs_c_,_drv_err_,("\n Can't init evt_priv\n")); ++ ret8=_FAIL; ++ goto exit; ++ } ++ ++ ++ if (rtw_init_mlme_priv(padapter) == _FAIL) ++ { ++ RT_TRACE(_module_os_intfs_c_,_drv_err_,("\n Can't init mlme_priv\n")); ++ ret8=_FAIL; ++ goto exit; ++ } ++ ++#ifdef CONFIG_P2P ++ rtw_init_wifidirect_timers(padapter); ++ init_wifidirect_info(padapter, P2P_ROLE_DISABLE); ++ reset_global_wifidirect_info(padapter); ++ #ifdef CONFIG_IOCTL_CFG80211 ++ rtw_init_cfg80211_wifidirect_info(padapter); ++ #endif ++#ifdef CONFIG_WFD ++ if(rtw_init_wifi_display_info(padapter) == _FAIL) ++ RT_TRACE(_module_os_intfs_c_,_drv_err_,("\n Can't init init_wifi_display_info\n")); ++#endif ++#endif /* CONFIG_P2P */ ++ ++ if(init_mlme_ext_priv(padapter) == _FAIL) ++ { ++ RT_TRACE(_module_os_intfs_c_,_drv_err_,("\n Can't init mlme_ext_priv\n")); ++ ret8=_FAIL; ++ goto exit; ++ } ++ ++#ifdef CONFIG_TDLS ++ if(rtw_init_tdls_info(padapter) == _FAIL) ++ { ++ DBG_871X("Can't rtw_init_tdls_info\n"); ++ ret8=_FAIL; ++ goto exit; ++ } ++#endif //CONFIG_TDLS ++ ++ if(_rtw_init_xmit_priv(&padapter->xmitpriv, padapter) == _FAIL) ++ { ++ DBG_871X("Can't _rtw_init_xmit_priv\n"); ++ ret8=_FAIL; ++ goto exit; ++ } ++ ++ if(_rtw_init_recv_priv(&padapter->recvpriv, padapter) == _FAIL) ++ { ++ DBG_871X("Can't _rtw_init_recv_priv\n"); ++ ret8=_FAIL; ++ goto exit; ++ } ++ // add for CONFIG_IEEE80211W, none 11w also can use ++ _rtw_spinlock_init(&padapter->security_key_mutex); ++ ++ // We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). ++ //_rtw_memset((unsigned char *)&padapter->securitypriv, 0, sizeof (struct security_priv)); ++ ++ //_init_timer(&(padapter->securitypriv.tkip_timer), padapter->pifp, rtw_use_tkipkey_handler, padapter); ++ ++ if(_rtw_init_sta_priv(&padapter->stapriv) == _FAIL) ++ { ++ DBG_871X("Can't _rtw_init_sta_priv\n"); ++ ret8=_FAIL; ++ goto exit; ++ } ++ ++ padapter->stapriv.padapter = padapter; ++ padapter->setband = GHZ24_50; ++ padapter->fix_rate = 0xFF; ++ rtw_init_bcmc_stainfo(padapter); ++ ++ rtw_init_pwrctrl_priv(padapter); ++ ++ //_rtw_memset((u8 *)&padapter->qospriv, 0, sizeof (struct qos_priv));//move to mlme_priv ++ ++#ifdef CONFIG_MP_INCLUDED ++ if (init_mp_priv(padapter) == _FAIL) { ++ DBG_871X("%s: initialize MP private data Fail!\n", __func__); ++ } ++#endif ++ ++ ret8 = rtw_init_default_value(padapter); ++ ++ rtw_hal_dm_init(padapter); ++ rtw_hal_sw_led_init(padapter); ++ ++#ifdef DBG_CONFIG_ERROR_DETECT ++ rtw_hal_sreset_init(padapter); ++#endif ++ ++#ifdef CONFIG_INTEL_WIDI ++ if(rtw_init_intel_widi(padapter) == _FAIL) ++ { ++ DBG_871X("Can't rtw_init_intel_widi\n"); ++ ret8=_FAIL; ++ goto exit; ++ } ++#endif //CONFIG_INTEL_WIDI ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ padapter->WapiSupport = true; //set true temp, will revise according to Efuse or Registry value later. ++ rtw_wapi_init(padapter); ++#endif ++ ++#ifdef CONFIG_BR_EXT ++ _rtw_spinlock_init(&padapter->br_ext_lock); ++#endif // CONFIG_BR_EXT ++ ++exit: ++ ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("-rtw_init_drv_sw\n")); ++ ++ _func_exit_; ++ ++ return ret8; ++ ++} ++ ++#ifdef CONFIG_WOWLAN ++void rtw_cancel_dynamic_chk_timer(_adapter *padapter) ++{ ++ _cancel_timer_ex(&padapter->mlmepriv.dynamic_chk_timer); ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("rtw_cancel_all_timer:cancel dynamic_chk_timer! \n")); ++} ++#endif ++ ++void rtw_cancel_all_timer(_adapter *padapter) ++{ ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("+rtw_cancel_all_timer\n")); ++ ++ _cancel_timer_ex(&padapter->mlmepriv.assoc_timer); ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("rtw_cancel_all_timer:cancel association timer complete! \n")); ++ ++ //_cancel_timer_ex(&padapter->securitypriv.tkip_timer); ++ //RT_TRACE(_module_os_intfs_c_,_drv_info_,("rtw_cancel_all_timer:cancel tkip_timer! \n")); ++ ++ _cancel_timer_ex(&padapter->mlmepriv.scan_to_timer); ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("rtw_cancel_all_timer:cancel scan_to_timer! \n")); ++ ++ _cancel_timer_ex(&padapter->mlmepriv.dynamic_chk_timer); ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("rtw_cancel_all_timer:cancel dynamic_chk_timer! \n")); ++ ++ // cancel sw led timer ++ rtw_hal_sw_led_deinit(padapter); ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("rtw_cancel_all_timer:cancel DeInitSwLeds! \n")); ++ ++ _cancel_timer_ex(&(adapter_to_pwrctl(padapter)->pwr_state_check_timer)); ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++#ifdef CONFIG_P2P ++ _cancel_timer_ex(&padapter->cfg80211_wdinfo.remain_on_ch_timer); ++#endif //CONFIG_P2P ++#endif //CONFIG_IOCTL_CFG80211 ++ ++#ifdef CONFIG_SET_SCAN_DENY_TIMER ++ _cancel_timer_ex(&padapter->mlmepriv.set_scan_deny_timer); ++ rtw_clear_scan_deny(padapter); ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("rtw_cancel_all_timer:cancel set_scan_deny_timer! \n")); ++#endif ++ ++#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS ++ _cancel_timer_ex(&padapter->recvpriv.signal_stat_timer); ++#endif ++ ++#ifdef CONFIG_DETECT_C2H_BY_POLLING ++ _cancel_timer_ex(&padapter->mlmepriv.event_polling_timer); ++#endif ++ ++#if defined(CONFIG_CHECK_BT_HANG) && defined(CONFIG_BT_COEXIST) ++ if (padapter->HalFunc.hal_cancel_checkbthang_workqueue) ++ padapter->HalFunc.hal_cancel_checkbthang_workqueue(padapter); ++#endif ++ //cancel dm timer ++ rtw_hal_dm_deinit(padapter); ++ ++} ++ ++u8 rtw_free_drv_sw(_adapter *padapter) ++{ ++ struct net_device *pnetdev = (struct net_device*)padapter->pnetdev; ++ ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("==>rtw_free_drv_sw")); ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ rtw_wapi_free(padapter); ++#endif ++ ++ //we can call rtw_p2p_enable here, but: ++ // 1. rtw_p2p_enable may have IO operation ++ // 2. rtw_p2p_enable is bundled with wext interface ++ #ifdef CONFIG_P2P ++ { ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ _cancel_timer_ex( &pwdinfo->find_phase_timer ); ++ _cancel_timer_ex( &pwdinfo->restore_p2p_state_timer ); ++ _cancel_timer_ex( &pwdinfo->pre_tx_scan_timer); ++#ifdef CONFIG_CONCURRENT_MODE ++ _cancel_timer_ex( &pwdinfo->ap_p2p_switch_timer ); ++#endif // CONFIG_CONCURRENT_MODE ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE); ++ } ++ } ++ #endif ++ // add for CONFIG_IEEE80211W, none 11w also can use ++ _rtw_spinlock_free(&padapter->security_key_mutex); ++ ++#ifdef CONFIG_BR_EXT ++ _rtw_spinlock_free(&padapter->br_ext_lock); ++#endif // CONFIG_BR_EXT ++ ++#ifdef CONFIG_INTEL_WIDI ++ rtw_free_intel_widi(padapter); ++#endif //CONFIG_INTEL_WIDI ++ ++ free_mlme_ext_priv(&padapter->mlmeextpriv); ++ ++#ifdef CONFIG_TDLS ++ //rtw_free_tdls_info(&padapter->tdlsinfo); ++#endif //CONFIG_TDLS ++ ++ rtw_free_cmd_priv(&padapter->cmdpriv); ++ ++ rtw_free_evt_priv(&padapter->evtpriv); ++ ++ rtw_free_mlme_priv(&padapter->mlmepriv); ++#if defined(CONFIG_CHECK_BT_HANG) && defined(CONFIG_BT_COEXIST) ++ if (padapter->HalFunc.hal_free_checkbthang_workqueue) ++ padapter->HalFunc.hal_free_checkbthang_workqueue(padapter); ++#endif ++ //free_io_queue(padapter); ++ ++ _rtw_free_xmit_priv(&padapter->xmitpriv); ++ ++ _rtw_free_sta_priv(&padapter->stapriv); //will free bcmc_stainfo here ++ ++ _rtw_free_recv_priv(&padapter->recvpriv); ++ ++ rtw_free_pwrctrl_priv(padapter); ++ ++ //rtw_mfree((void *)padapter, sizeof (padapter)); ++ ++#ifdef CONFIG_DRVEXT_MODULE ++ free_drvext(&padapter->drvextpriv); ++#endif ++ ++ rtw_hal_free_data(padapter); ++ ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("<==rtw_free_drv_sw\n")); ++ ++ //free the old_pnetdev ++ if(padapter->rereg_nd_name_priv.old_pnetdev) { ++ free_netdev(padapter->rereg_nd_name_priv.old_pnetdev); ++ padapter->rereg_nd_name_priv.old_pnetdev = NULL; ++ } ++ ++ // clear pbuddy_adapter to avoid access wrong pointer. ++ if(padapter->pbuddy_adapter != NULL) { ++ padapter->pbuddy_adapter->pbuddy_adapter = NULL; ++ } ++ ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("-rtw_free_drv_sw\n")); ++ ++ return _SUCCESS; ++ ++} ++ ++#ifdef CONFIG_CONCURRENT_MODE ++int _netdev_if2_open(struct net_device *pnetdev) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev); ++ _adapter *primary_padapter = padapter->pbuddy_adapter; ++ ++ DBG_871X("+871x_drv - if2_open, bup=%d\n", padapter->bup); ++ ++ if(primary_padapter->bup == _FALSE || primary_padapter->hw_init_completed == _FALSE) ++ { ++ _netdev_open(primary_padapter->pnetdev); ++ } ++ ++ if(padapter->bup == _FALSE && primary_padapter->bup == _TRUE && ++ primary_padapter->hw_init_completed == _TRUE) ++ { ++ int i; ++ ++ padapter->bDriverStopped = _FALSE; ++ padapter->bSurpriseRemoved = _FALSE; ++ padapter->bCardDisableWOHSM = _FALSE; ++ ++ padapter->bFWReady = primary_padapter->bFWReady; ++ ++ //if (init_mlme_ext_priv(padapter) == _FAIL) ++ // goto netdev_if2_open_error; ++ ++ ++ if(rtw_start_drv_threads(padapter) == _FAIL) ++ { ++ goto netdev_if2_open_error; ++ } ++ ++ ++ if(padapter->intf_start) ++ { ++ padapter->intf_start(padapter); ++ } ++ ++ rtw_proc_init_one(pnetdev); ++ ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ rtw_cfg80211_init_wiphy(padapter); ++#endif ++ ++ padapter->bup = _TRUE; ++ ++ } ++ ++ padapter->net_closed = _FALSE; ++ ++ _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 2000); ++ ++ if(!rtw_netif_queue_stopped(pnetdev)) ++ rtw_netif_start_queue(pnetdev); ++ else ++ rtw_netif_wake_queue(pnetdev); ++ ++ DBG_871X("-871x_drv - if2_open, bup=%d\n", padapter->bup); ++ return 0; ++ ++netdev_if2_open_error: ++ ++ padapter->bup = _FALSE; ++ ++ netif_carrier_off(pnetdev); ++ rtw_netif_stop_queue(pnetdev); ++ ++ return (-1); ++ ++} ++ ++int netdev_if2_open(struct net_device *pnetdev) ++{ ++ int ret; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev); ++ ++ _enter_critical_mutex(&(adapter_to_dvobj(padapter)->hw_init_mutex), NULL); ++ ret = _netdev_if2_open(pnetdev); ++ _exit_critical_mutex(&(adapter_to_dvobj(padapter)->hw_init_mutex), NULL); ++ return ret; ++} ++ ++static int netdev_if2_close(struct net_device *pnetdev) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev); ++ ++ padapter->net_closed = _TRUE; ++ ++ if(pnetdev) ++ { ++ if (!rtw_netif_queue_stopped(pnetdev)) ++ rtw_netif_stop_queue(pnetdev); ++ } ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ rtw_scan_abort(padapter); ++ wdev_to_priv(padapter->rtw_wdev)->bandroid_scan = _FALSE; ++#endif ++ ++ return 0; ++} ++ ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,29)) ++static const struct net_device_ops rtw_netdev_if2_ops = { ++ .ndo_open = netdev_if2_open, ++ .ndo_stop = netdev_if2_close, ++ .ndo_start_xmit = rtw_xmit_entry, ++ .ndo_set_mac_address = rtw_net_set_mac_address, ++ .ndo_get_stats = rtw_net_get_stats, ++ .ndo_do_ioctl = rtw_ioctl, ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)) ++ .ndo_select_queue = rtw_select_queue, ++#endif ++}; ++#endif ++ ++ ++#ifdef CONFIG_USB_HCI ++ #include ++#endif ++#ifdef CONFIG_SDIO_HCI ++ #include ++#endif ++_adapter *rtw_drv_if2_init(_adapter *primary_padapter, void (*set_intf_ops)(struct _io_ops *pops)) ++{ ++ int res = _FAIL; ++ struct net_device *pnetdev = NULL; ++ _adapter *padapter = NULL; ++ struct dvobj_priv *pdvobjpriv; ++ u8 mac[ETH_ALEN]; ++ ++ /****** init netdev ******/ ++ pnetdev = rtw_init_netdev(NULL); ++ if (!pnetdev) ++ goto error_rtw_drv_if2_init; ++ ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,29)) ++ DBG_871X("register rtw_netdev_if2_ops to netdev_ops\n"); ++ pnetdev->netdev_ops = &rtw_netdev_if2_ops; ++#else ++ pnetdev->open = netdev_if2_open; ++ pnetdev->stop = netdev_if2_close; ++#endif ++ ++#ifdef CONFIG_NO_WIRELESS_HANDLERS ++ pnetdev->wireless_handlers = NULL; ++#endif ++ ++ /****** init adapter ******/ ++ padapter = rtw_netdev_priv(pnetdev); ++ _rtw_memcpy(padapter, primary_padapter, sizeof(_adapter)); ++ ++ // ++ padapter->bup = _FALSE; ++ padapter->net_closed = _TRUE; ++ padapter->hw_init_completed = _FALSE; ++ padapter->dir_dev = NULL; ++ padapter->dir_odm = NULL; ++ ++ //set adapter_type/iface type ++ padapter->isprimary = _FALSE; ++ padapter->adapter_type = SECONDARY_ADAPTER; ++ padapter->pbuddy_adapter = primary_padapter; ++ padapter->iface_id = IFACE_ID1; ++#ifndef CONFIG_HWPORT_SWAP //Port0 -> Pri , Port1 -> Sec ++ padapter->iface_type = IFACE_PORT1; ++#else ++ padapter->iface_type = IFACE_PORT0; ++#endif //CONFIG_HWPORT_SWAP ++ // ++ padapter->pnetdev = pnetdev; ++ ++ /****** setup dvobj ******/ ++ pdvobjpriv = adapter_to_dvobj(padapter); ++ pdvobjpriv->if2 = padapter; ++ pdvobjpriv->padapters[pdvobjpriv->iface_nums++] = padapter; ++ ++ SET_NETDEV_DEV(pnetdev, dvobj_to_dev(pdvobjpriv)); ++ #ifdef CONFIG_IOCTL_CFG80211 ++ rtw_wdev_alloc(padapter, dvobj_to_dev(pdvobjpriv)); ++ #endif //CONFIG_IOCTL_CFG80211 ++ ++ //set interface_type/chip_type/HardwareType ++ padapter->interface_type = primary_padapter->interface_type; ++ padapter->chip_type = primary_padapter->chip_type; ++ padapter->HardwareType = primary_padapter->HardwareType; ++ ++ //step 2. hook HalFunc, allocate HalData ++ hal_set_hal_ops(padapter); ++ ++ padapter->HalFunc.inirp_init = NULL; ++ padapter->HalFunc.inirp_deinit = NULL; ++ ++ // ++ padapter->intf_start = primary_padapter->intf_start; ++ padapter->intf_stop = primary_padapter->intf_stop; ++ ++ //step init_io_priv ++ if ((rtw_init_io_priv(padapter, set_intf_ops)) == _FAIL) { ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,(" \n Can't init io_reqs\n")); ++ } ++ ++ //step read_chip_version ++ rtw_hal_read_chip_version(padapter); ++ ++ //step usb endpoint mapping ++ rtw_hal_chip_configure(padapter); ++ ++ ++ //init drv data ++ if(rtw_init_drv_sw(padapter)!= _SUCCESS) ++ goto error_rtw_drv_if2_init; ++ ++ //get mac address from primary_padapter ++ _rtw_memcpy(mac, primary_padapter->eeprompriv.mac_addr, ETH_ALEN); ++ ++ if (((mac[0]==0xff) &&(mac[1]==0xff) && (mac[2]==0xff) && ++ (mac[3]==0xff) && (mac[4]==0xff) &&(mac[5]==0xff)) || ++ ((mac[0]==0x0) && (mac[1]==0x0) && (mac[2]==0x0) && ++ (mac[3]==0x0) && (mac[4]==0x0) &&(mac[5]==0x0))) ++ { ++ mac[0] = 0x00; ++ mac[1] = 0xe0; ++ mac[2] = 0x4c; ++ mac[3] = 0x87; ++ mac[4] = 0x11; ++ mac[5] = 0x22; ++ } ++ else ++ { ++ //If the BIT1 is 0, the address is universally administered. ++ //If it is 1, the address is locally administered ++ mac[0] |= BIT(1); // locally administered ++ ++ } ++ ++ _rtw_memcpy(padapter->eeprompriv.mac_addr, mac, ETH_ALEN); ++#ifdef CONFIG_P2P ++ rtw_init_wifidirect_addrs(padapter, padapter->eeprompriv.mac_addr, padapter->eeprompriv.mac_addr); ++#endif ++ primary_padapter->pbuddy_adapter = padapter; ++ ++ res = _SUCCESS; ++ ++ return padapter; ++ ++ ++error_rtw_drv_if2_init: ++ ++ if(padapter) ++ rtw_free_drv_sw(padapter); ++ ++ if (pnetdev) ++ rtw_free_netdev(pnetdev); ++ ++ return NULL; ++ ++} ++ ++void rtw_drv_if2_free(_adapter *if2) ++{ ++ _adapter *padapter = if2; ++ struct net_device *pnetdev = NULL; ++ ++ if (padapter == NULL) ++ return; ++ ++ pnetdev = padapter->pnetdev; ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ rtw_wdev_free(padapter->rtw_wdev); ++#endif /* CONFIG_IOCTL_CFG80211 */ ++ ++ ++ rtw_free_drv_sw(padapter); ++ ++ rtw_free_netdev(pnetdev); ++ ++} ++ ++void rtw_drv_if2_stop(_adapter *if2) ++{ ++ _adapter *padapter = if2; ++ //struct net_device *pnetdev = NULL; ++ ++ if (padapter == NULL) ++ return; ++/* ++ pnetdev = padapter->pnetdev; ++ ++ if (pnetdev) { ++ unregister_netdev(pnetdev); //will call netdev_close() ++ rtw_proc_remove_one(pnetdev); ++ } ++*/ ++ rtw_cancel_all_timer(padapter); ++ ++ if (padapter->bup == _TRUE) { ++ padapter->bDriverStopped = _TRUE; ++ #ifdef CONFIG_XMIT_ACK ++ if (padapter->xmitpriv.ack_tx) ++ rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_DRV_STOP); ++ #endif ++ ++ if(padapter->intf_stop) ++ { ++ padapter->intf_stop(padapter); ++ } ++ ++ rtw_stop_drv_threads(padapter); ++ ++ padapter->bup = _FALSE; ++ } ++/* ++ #ifdef CONFIG_IOCTL_CFG80211 ++ rtw_wdev_unregister(padapter->rtw_wdev); ++ #endif ++*/ ++} ++#endif //end of CONFIG_CONCURRENT_MODE ++ ++#ifdef CONFIG_BR_EXT ++void netdev_br_init(struct net_device *netdev) ++{ ++ _adapter *adapter = (_adapter *)rtw_netdev_priv(netdev); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) ++ rcu_read_lock(); ++#endif // (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) ++ ++ //if(check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) == _TRUE) ++ { ++ //struct net_bridge *br = netdev->br_port->br;//->dev->dev_addr; ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ if (netdev->br_port) ++#else // (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ if (rcu_dereference(adapter->pnetdev->rx_handler_data)) ++#endif // (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ { ++ struct net_device *br_netdev; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ br_netdev = dev_get_by_name(CONFIG_BR_EXT_BRNAME); ++#else // (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ struct net *devnet = NULL; ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) ++ devnet = netdev->nd_net; ++#else // (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) ++ devnet = dev_net(netdev); ++#endif // (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) ++ ++ br_netdev = dev_get_by_name(devnet, CONFIG_BR_EXT_BRNAME); ++#endif // (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ ++ if (br_netdev) { ++ memcpy(adapter->br_mac, br_netdev->dev_addr, ETH_ALEN); ++ dev_put(br_netdev); ++ } else ++ DBG_871X("%s()-%d: dev_get_by_name(%s) failed!", __FUNCTION__, __LINE__, CONFIG_BR_EXT_BRNAME); ++ } ++ ++ adapter->ethBrExtInfo.addPPPoETag = 1; ++ } ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) ++ rcu_read_unlock(); ++#endif // (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) ++} ++#endif //CONFIG_BR_EXT ++ ++static int _rtw_drv_register_netdev(_adapter *padapter, char *name) ++{ ++ int ret = _SUCCESS; ++ struct net_device *pnetdev = padapter->pnetdev; ++ ++ /* alloc netdev name */ ++ rtw_init_netdev_name(pnetdev, name); ++ ++ _rtw_memcpy(pnetdev->dev_addr, padapter->eeprompriv.mac_addr, ETH_ALEN); ++ ++ /* Tell the network stack we exist */ ++ if (register_netdev(pnetdev) != 0) { ++ DBG_871X(FUNC_NDEV_FMT "Failed!\n", FUNC_NDEV_ARG(pnetdev)); ++ ret = _FAIL; ++ goto error_register_netdev; ++ } ++ ++ DBG_871X("%s, MAC Address (if%d) = " MAC_FMT "\n", __FUNCTION__, (padapter->iface_id+1), MAC_ARG(pnetdev->dev_addr)); ++ ++ return ret; ++ ++error_register_netdev: ++ ++ if(padapter->iface_id > IFACE_ID0) ++ { ++ rtw_free_drv_sw(padapter); ++ ++ rtw_free_netdev(pnetdev); ++ } ++ ++ return ret; ++} ++ ++int rtw_drv_register_netdev(_adapter *if1) ++{ ++ int i, status = _SUCCESS; ++ struct dvobj_priv *dvobj = if1->dvobj; ++ ++ if(dvobj->iface_nums < IFACE_ID_MAX) ++ { ++ for(i=0; iiface_nums; i++) ++ { ++ _adapter *padapter = dvobj->padapters[i]; ++ ++ if(padapter) ++ { ++ char *name; ++ ++ if(padapter->iface_id == IFACE_ID0) ++ name = if1->registrypriv.ifname; ++ else if(padapter->iface_id == IFACE_ID1) ++ name = if1->registrypriv.if2name; ++ else ++ name = "wlan%d"; ++ ++ if((status = _rtw_drv_register_netdev(padapter, name)) != _SUCCESS) { ++ break; ++ } ++ } ++ } ++ } ++ ++ return status; ++} ++ ++int _netdev_open(struct net_device *pnetdev) ++{ ++ uint status; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev); ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); ++ ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("+871x_drv - dev_open\n")); ++ DBG_871X("+871x_drv - drv_open, bup=%d\n", padapter->bup); ++ ++ if(pwrctrlpriv->ps_flag == _TRUE){ ++ padapter->net_closed = _FALSE; ++ goto netdev_open_normal_process; ++ } ++ ++ if(padapter->bup == _FALSE) ++ { ++ padapter->bDriverStopped = _FALSE; ++ padapter->bSurpriseRemoved = _FALSE; ++ padapter->bCardDisableWOHSM = _FALSE; ++ ++ status = rtw_hal_init(padapter); ++ if (status ==_FAIL) ++ { ++ RT_TRACE(_module_os_intfs_c_,_drv_err_,("rtl871x_hal_init(): Can't init h/w!\n")); ++ goto netdev_open_error; ++ } ++ ++ DBG_871X("MAC Address = "MAC_FMT"\n", MAC_ARG(pnetdev->dev_addr)); ++ ++#ifdef CONFIG_RF_GAIN_OFFSET ++ rtw_bb_rf_gain_offset(padapter); ++#endif //CONFIG_RF_GAIN_OFFSET ++ ++ status=rtw_start_drv_threads(padapter); ++ if(status ==_FAIL) ++ { ++ DBG_871X("Initialize driver software resource Failed!\n"); ++ goto netdev_open_error; ++ } ++ ++#ifdef CONFIG_DRVEXT_MODULE ++ init_drvext(padapter); ++#endif ++ ++ if(padapter->intf_start) ++ { ++ padapter->intf_start(padapter); ++ } ++ ++#ifndef RTK_DMP_PLATFORM ++ rtw_proc_init_one(pnetdev); ++#endif ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ rtw_cfg80211_init_wiphy(padapter); ++#endif ++ ++ rtw_led_control(padapter, LED_CTL_NO_LINK); ++ ++ padapter->bup = _TRUE; ++ ++ pwrctrlpriv->bips_processing = _FALSE; ++ } ++ padapter->net_closed = _FALSE; ++ ++ _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 2000); ++ ++#ifdef CONFIG_DETECT_C2H_BY_POLLING ++ _set_timer(&padapter->mlmepriv.event_polling_timer, 200); ++#endif ++ ++ rtw_set_pwr_state_check_timer(pwrctrlpriv); ++ ++ //netif_carrier_on(pnetdev);//call this func when rtw_joinbss_event_callback return success ++ if(!rtw_netif_queue_stopped(pnetdev)) ++ rtw_netif_start_queue(pnetdev); ++ else ++ rtw_netif_wake_queue(pnetdev); ++ ++#ifdef CONFIG_BR_EXT ++ netdev_br_init(pnetdev); ++#endif // CONFIG_BR_EXT ++ ++netdev_open_normal_process: ++ ++ #ifdef CONFIG_CONCURRENT_MODE ++ { ++ _adapter *sec_adapter = padapter->pbuddy_adapter; ++ if(sec_adapter && (sec_adapter->bup == _FALSE)) ++ _netdev_if2_open(sec_adapter->pnetdev); ++ } ++ #endif ++ ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("-871x_drv - dev_open\n")); ++ DBG_871X("-871x_drv - drv_open, bup=%d\n", padapter->bup); ++ ++ return 0; ++ ++netdev_open_error: ++ ++ padapter->bup = _FALSE; ++ ++ netif_carrier_off(pnetdev); ++ rtw_netif_stop_queue(pnetdev); ++ ++ RT_TRACE(_module_os_intfs_c_,_drv_err_,("-871x_drv - dev_open, fail!\n")); ++ DBG_871X("-871x_drv - drv_open fail, bup=%d\n", padapter->bup); ++ ++ return (-1); ++ ++} ++ ++int netdev_open(struct net_device *pnetdev) ++{ ++ int ret; ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev); ++ ++ _enter_critical_mutex(&(adapter_to_dvobj(padapter)->hw_init_mutex), NULL); ++ ret = _netdev_open(pnetdev); ++ _exit_critical_mutex(&(adapter_to_dvobj(padapter)->hw_init_mutex), NULL); ++ ++ return ret; ++} ++ ++#ifdef CONFIG_IPS ++int ips_netdrv_open(_adapter *padapter) ++{ ++ int status = _SUCCESS; ++ padapter->net_closed = _FALSE; ++ DBG_871X("===> %s.........\n",__FUNCTION__); ++ ++ ++ padapter->bDriverStopped = _FALSE; ++ padapter->bCardDisableWOHSM = _FALSE; ++ //padapter->bup = _TRUE; ++ ++ status = rtw_hal_init(padapter); ++ if (status ==_FAIL) ++ { ++ RT_TRACE(_module_os_intfs_c_,_drv_err_,("ips_netdrv_open(): Can't init h/w!\n")); ++ goto netdev_open_error; ++ } ++ ++#ifdef CONFIG_RF_GAIN_OFFSET ++ rtw_bb_rf_gain_offset(padapter); ++#endif //CONFIG_RF_GAIN_OFFSET ++ ++ if(padapter->intf_start) ++ { ++ padapter->intf_start(padapter); ++ } ++ ++ rtw_set_pwr_state_check_timer(adapter_to_pwrctl(padapter)); ++ _set_timer(&padapter->mlmepriv.dynamic_chk_timer,5000); ++ ++ return _SUCCESS; ++ ++netdev_open_error: ++ //padapter->bup = _FALSE; ++ DBG_871X("-ips_netdrv_open - drv_open failure, bup=%d\n", padapter->bup); ++ ++ return _FAIL; ++} ++ ++ ++int rtw_ips_pwr_up(_adapter *padapter) ++{ ++ int result; ++ u32 start_time = rtw_get_current_time(); ++ DBG_871X("===> rtw_ips_pwr_up..............\n"); ++ rtw_reset_drv_sw(padapter); ++ ++ result = ips_netdrv_open(padapter); ++ ++ rtw_led_control(padapter, LED_CTL_NO_LINK); ++ ++ DBG_871X("<=== rtw_ips_pwr_up.............. in %dms\n", rtw_get_passing_time_ms(start_time)); ++ return result; ++ ++} ++ ++void rtw_ips_pwr_down(_adapter *padapter) ++{ ++ u32 start_time = rtw_get_current_time(); ++ DBG_871X("===> rtw_ips_pwr_down...................\n"); ++ ++ padapter->bCardDisableWOHSM = _TRUE; ++ padapter->net_closed = _TRUE; ++ ++ rtw_led_control(padapter, LED_CTL_POWER_OFF); ++ ++ rtw_ips_dev_unload(padapter); ++ padapter->bCardDisableWOHSM = _FALSE; ++ DBG_871X("<=== rtw_ips_pwr_down..................... in %dms\n", rtw_get_passing_time_ms(start_time)); ++} ++#endif ++void rtw_ips_dev_unload(_adapter *padapter) ++{ ++ struct net_device *pnetdev= (struct net_device*)padapter->pnetdev; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ DBG_871X("====> %s...\n",__FUNCTION__); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_FIFO_CLEARN_UP, 0); ++ ++ if(padapter->intf_stop) ++ { ++ padapter->intf_stop(padapter); ++ } ++ ++ //s5. ++ if(padapter->bSurpriseRemoved == _FALSE) ++ { ++ rtw_hal_deinit(padapter); ++ } ++ ++} ++ ++#ifdef CONFIG_RF_GAIN_OFFSET ++void rtw_bb_rf_gain_offset(_adapter *padapter) ++{ ++ u8 value = padapter->eeprompriv.EEPROMRFGainOffset; ++ u8 tmp = 0x3e; ++ u32 res; ++ ++ DBG_871X("+%s value: 0x%02x+\n", __func__, value); ++ ++ if (value & RF_GAIN_OFFSET_ON) { ++ //DBG_871X("Offset RF Gain.\n"); ++ //DBG_871X("Offset RF Gain. padapter->eeprompriv.EEPROMRFGainVal=0x%x\n",padapter->eeprompriv.EEPROMRFGainVal); ++ if(padapter->eeprompriv.EEPROMRFGainVal != 0xff){ ++#ifdef CONFIG_RTL8723A ++ res = rtw_hal_read_rfreg(padapter, RF_PATH_A, 0xd, 0xffffffff); ++ //DBG_871X("Offset RF Gain. reg 0xd=0x%x\n",res); ++ res &= 0xfff87fff; ++ ++ res |= (padapter->eeprompriv.EEPROMRFGainVal & 0x0f)<< 15; ++ //DBG_871X("Offset RF Gain. reg 0xd=0x%x\n",res); ++ ++ rtw_hal_write_rfreg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, RF_GAIN_OFFSET_MASK, res); ++ ++ res = rtw_hal_read_rfreg(padapter, RF_PATH_A, 0xe, 0xffffffff); ++ DBG_871X("Offset RF Gain. reg 0xe=0x%x\n",res); ++ res &= 0xfffffff0; ++ ++ res |= (padapter->eeprompriv.EEPROMRFGainVal & 0x0f); ++ //DBG_871X("Offset RF Gain. reg 0xe=0x%x\n",res); ++ ++ rtw_hal_write_rfreg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, RF_GAIN_OFFSET_MASK, res); ++#else ++ res = rtw_hal_read_rfreg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, 0xffffffff); ++ DBG_871X("REG_RF_BB_GAIN_OFFSET=%x \n",res); ++ res &= 0xfff87fff; ++ res |= (padapter->eeprompriv.EEPROMRFGainVal & 0x0f)<< 15; ++ DBG_871X("write REG_RF_BB_GAIN_OFFSET=%x \n",res); ++ rtw_hal_write_rfreg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, RF_GAIN_OFFSET_MASK, res); ++#endif ++ } ++ else ++ { ++ //DBG_871X("Offset RF Gain. padapter->eeprompriv.EEPROMRFGainVal=0x%x != 0xff, didn't run Kfree\n",padapter->eeprompriv.EEPROMRFGainVal); ++ } ++ } else { ++ //DBG_871X("Using the default RF gain.\n"); ++ } ++ ++} ++#endif //CONFIG_RF_GAIN_OFFSET ++ ++int pm_netdev_open(struct net_device *pnetdev,u8 bnormal) ++{ ++ int status; ++ ++ ++ if (_TRUE == bnormal) ++ status = netdev_open(pnetdev); ++#ifdef CONFIG_IPS ++ else ++ status = (_SUCCESS == ips_netdrv_open((_adapter *)rtw_netdev_priv(pnetdev)))?(0):(-1); ++#endif ++ ++ return status; ++} ++ ++static int netdev_close(struct net_device *pnetdev) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev); ++ ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("+871x_drv - drv_close\n")); ++ ++ if(adapter_to_pwrctl(padapter)->bInternalAutoSuspend == _TRUE) ++ { ++ //rtw_pwr_wakeup(padapter); ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate == rf_off) ++ adapter_to_pwrctl(padapter)->ps_flag = _TRUE; ++ } ++ padapter->net_closed = _TRUE; ++ ++/* if(!padapter->hw_init_completed) ++ { ++ DBG_871X("(1)871x_drv - drv_close, bup=%d, hw_init_completed=%d\n", padapter->bup, padapter->hw_init_completed); ++ ++ padapter->bDriverStopped = _TRUE; ++ ++ rtw_dev_unload(padapter); ++ } ++ else*/ ++ if(adapter_to_pwrctl(padapter)->rf_pwrstate == rf_on){ ++ DBG_871X("(2)871x_drv - drv_close, bup=%d, hw_init_completed=%d\n", padapter->bup, padapter->hw_init_completed); ++ ++ //s1. ++ if(pnetdev) ++ { ++ if (!rtw_netif_queue_stopped(pnetdev)) ++ rtw_netif_stop_queue(pnetdev); ++ } ++ ++#ifndef CONFIG_ANDROID ++ //s2. ++ LeaveAllPowerSaveMode(padapter); ++ rtw_disassoc_cmd(padapter, 500, _FALSE); ++ //s2-2. indicate disconnect to os ++ rtw_indicate_disconnect(padapter); ++ //s2-3. ++ rtw_free_assoc_resources(padapter, 1); ++ //s2-4. ++ rtw_free_network_queue(padapter,_TRUE); ++#endif ++ // Close LED ++ rtw_led_control(padapter, LED_CTL_POWER_OFF); ++ } ++ ++#ifdef CONFIG_BR_EXT ++ //if (OPMODE & (WIFI_STATION_STATE | WIFI_ADHOC_STATE)) ++ { ++ //void nat25_db_cleanup(_adapter *priv); ++ nat25_db_cleanup(padapter); ++ } ++#endif // CONFIG_BR_EXT ++ ++#ifdef CONFIG_P2P ++ rtw_p2p_enable(padapter, P2P_ROLE_DISABLE); ++#endif //CONFIG_P2P ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ rtw_scan_abort(padapter); ++ wdev_to_priv(padapter->rtw_wdev)->bandroid_scan = _FALSE; ++ padapter->rtw_wdev->iftype = NL80211_IFTYPE_MONITOR; //set this at the end ++#endif //CONFIG_IOCTL_CFG80211 ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ rtw_wapi_disable_tx(padapter); ++#endif ++ ++ RT_TRACE(_module_os_intfs_c_,_drv_info_,("-871x_drv - drv_close\n")); ++ DBG_871X("-871x_drv - drv_close, bup=%d\n", padapter->bup); ++ ++ return 0; ++ ++} ++ ++void rtw_ndev_destructor(struct net_device *ndev) ++{ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if (ndev->ieee80211_ptr) ++ rtw_mfree((u8 *)ndev->ieee80211_ptr, sizeof(struct wireless_dev)); ++#endif ++ free_netdev(ndev); ++} ++ ++#ifdef CONFIG_ARP_KEEP_ALIVE ++struct route_info { ++ struct in_addr dst_addr; ++ struct in_addr src_addr; ++ struct in_addr gateway; ++ unsigned int dev_index; ++}; ++ ++static void parse_routes(struct nlmsghdr *nl_hdr, struct route_info *rt_info) ++{ ++ struct rtmsg *rt_msg; ++ struct rtattr *rt_attr; ++ int rt_len; ++ ++ rt_msg = (struct rtmsg *) NLMSG_DATA(nl_hdr); ++ if ((rt_msg->rtm_family != AF_INET) || (rt_msg->rtm_table != RT_TABLE_MAIN)) ++ return; ++ ++ rt_attr = (struct rtattr *) RTM_RTA(rt_msg); ++ rt_len = RTM_PAYLOAD(nl_hdr); ++ ++ for (; RTA_OK(rt_attr, rt_len); rt_attr = RTA_NEXT(rt_attr, rt_len)) ++ { ++ switch (rt_attr->rta_type) { ++ case RTA_OIF: ++ rt_info->dev_index = *(int *) RTA_DATA(rt_attr); ++ break; ++ case RTA_GATEWAY: ++ rt_info->gateway.s_addr = *(u_int *) RTA_DATA(rt_attr); ++ break; ++ case RTA_PREFSRC: ++ rt_info->src_addr.s_addr = *(u_int *) RTA_DATA(rt_attr); ++ break; ++ case RTA_DST: ++ rt_info->dst_addr.s_addr = *(u_int *) RTA_DATA(rt_attr); ++ break; ++ } ++ } ++} ++ ++static int route_dump(u32 *gw_addr ,int* gw_index) ++{ ++ int err = 0; ++ struct socket *sock; ++ struct { ++ struct nlmsghdr nlh; ++ struct rtgenmsg g; ++ } req; ++ struct msghdr msg; ++ struct iovec iov; ++ struct sockaddr_nl nladdr; ++ mm_segment_t oldfs; ++ char *pg; ++ int size = 0; ++ ++ err = sock_create(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, &sock); ++ if (err) ++ { ++ printk( ": Could not create a datagram socket, error = %d\n", -ENXIO); ++ return err; ++ } ++ ++ memset(&nladdr, 0, sizeof(nladdr)); ++ nladdr.nl_family = AF_NETLINK; ++ ++ req.nlh.nlmsg_len = sizeof(req); ++ req.nlh.nlmsg_type = RTM_GETROUTE; ++ req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; ++ req.nlh.nlmsg_pid = 0; ++ req.g.rtgen_family = AF_INET; ++ ++ iov.iov_base = &req; ++ iov.iov_len = sizeof(req); ++ ++ msg.msg_name = &nladdr; ++ msg.msg_namelen = sizeof(nladdr); ++ msg.msg_iov = &iov; ++ msg.msg_iovlen = 1; ++ msg.msg_control = NULL; ++ msg.msg_controllen = 0; ++ msg.msg_flags = MSG_DONTWAIT; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ err = sock_sendmsg(sock, &msg, sizeof(req)); ++ set_fs(oldfs); ++ ++ if (size < 0) ++ goto out_sock; ++ ++ pg = (char *) __get_free_page(GFP_KERNEL); ++ if (pg == NULL) { ++ err = -ENOMEM; ++ goto out_sock; ++ } ++ ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++restart: ++#endif ++ ++ for (;;) ++ { ++ struct nlmsghdr *h; ++ ++ iov.iov_base = pg; ++ iov.iov_len = PAGE_SIZE; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ err = sock_recvmsg(sock, &msg, PAGE_SIZE, MSG_DONTWAIT); ++ set_fs(oldfs); ++ ++ if (err < 0) ++ goto out_sock_pg; ++ ++ if (msg.msg_flags & MSG_TRUNC) { ++ err = -ENOBUFS; ++ goto out_sock_pg; ++ } ++ ++ h = (struct nlmsghdr*) pg; ++ ++ while (NLMSG_OK(h, err)) ++ { ++ struct route_info rt_info; ++ if (h->nlmsg_type == NLMSG_DONE) { ++ err = 0; ++ goto done; ++ } ++ ++ if (h->nlmsg_type == NLMSG_ERROR) { ++ struct nlmsgerr *errm = (struct nlmsgerr*) NLMSG_DATA(h); ++ err = errm->error; ++ printk( "NLMSG error: %d\n", errm->error); ++ goto done; ++ } ++ ++ if (h->nlmsg_type == RTM_GETROUTE) ++ { ++ printk( "RTM_GETROUTE: NLMSG: %d\n", h->nlmsg_type); ++ } ++ if (h->nlmsg_type != RTM_NEWROUTE) { ++ printk( "NLMSG: %d\n", h->nlmsg_type); ++ err = -EINVAL; ++ goto done; ++ } ++ ++ memset(&rt_info, 0, sizeof(struct route_info)); ++ parse_routes(h, &rt_info); ++ if(!rt_info.dst_addr.s_addr && rt_info.gateway.s_addr && rt_info.dev_index) ++ { ++ *gw_addr = rt_info.gateway.s_addr; ++ *gw_index = rt_info.dev_index; ++ ++ } ++ h = NLMSG_NEXT(h, err); ++ } ++ ++ if (err) ++ { ++ printk( "!!!Remnant of size %d %d %d\n", err, h->nlmsg_len, h->nlmsg_type); ++ err = -EINVAL; ++ break; ++ } ++ } ++ ++done: ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++ if (!err && req.g.rtgen_family == AF_INET) { ++ req.g.rtgen_family = AF_INET6; ++ ++ iov.iov_base = &req; ++ iov.iov_len = sizeof(req); ++ ++ msg.msg_name = &nladdr; ++ msg.msg_namelen = sizeof(nladdr); ++ msg.msg_iov = &iov; ++ msg.msg_iovlen = 1; ++ msg.msg_control = NULL; ++ msg.msg_controllen = 0; ++ msg.msg_flags=MSG_DONTWAIT; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ err = sock_sendmsg(sock, &msg, sizeof(req)); ++ set_fs(oldfs); ++ ++ if (err > 0) ++ goto restart; ++ } ++#endif ++ ++out_sock_pg: ++ free_page((unsigned long) pg); ++ ++out_sock: ++ sock_release(sock); ++ return err; ++} ++ ++static int arp_query(unsigned char *haddr, u32 paddr, ++ struct net_device *dev) ++{ ++ struct neighbour *neighbor_entry; ++ int ret = 0; ++ ++ neighbor_entry = neigh_lookup(&arp_tbl, &paddr, dev); ++ ++ if (neighbor_entry != NULL) { ++ neighbor_entry->used = jiffies; ++ if (neighbor_entry->nud_state & NUD_VALID) { ++ _rtw_memcpy(haddr, neighbor_entry->ha, dev->addr_len); ++ ret = 1; ++ } ++ neigh_release(neighbor_entry); ++ } ++ return ret; ++} ++ ++static int get_defaultgw(u32 *ip_addr ,char mac[]) ++{ ++ int gw_index = 0; // oif device index ++ struct net_device *gw_dev = NULL; //oif device ++ ++ route_dump(ip_addr, &gw_index); ++ ++ if( !(*ip_addr) || !gw_index ) ++ { ++ //DBG_871X("No default GW \n"); ++ return -1; ++ } ++ ++ gw_dev = dev_get_by_index(&init_net, gw_index); ++ ++ if(gw_dev == NULL) ++ { ++ //DBG_871X("get Oif Device Fail \n"); ++ return -1; ++ } ++ ++ if(!arp_query(mac, *ip_addr, gw_dev)) ++ { ++ //DBG_871X( "arp query failed\n"); ++ dev_put(gw_dev); ++ return -1; ++ ++ } ++ dev_put(gw_dev); ++ ++ return 0; ++} ++ ++int rtw_gw_addr_query(_adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u32 gw_addr = 0; // default gw address ++ unsigned char gw_mac[32] = {0}; // default gw mac ++ int i; ++ int res; ++ ++ res = get_defaultgw(&gw_addr, gw_mac); ++ if(!res) ++ { ++ pmlmepriv->gw_ip[0] = gw_addr&0xff; ++ pmlmepriv->gw_ip[1] = (gw_addr&0xff00)>>8; ++ pmlmepriv->gw_ip[2] = (gw_addr&0xff0000)>>16; ++ pmlmepriv->gw_ip[3] = (gw_addr&0xff000000)>>24; ++ _rtw_memcpy(pmlmepriv->gw_mac_addr, gw_mac, 6); ++ DBG_871X("%s Gateway Mac:\t" MAC_FMT "\n", __FUNCTION__, MAC_ARG(pmlmepriv->gw_mac_addr)); ++ DBG_871X("%s Gateway IP:\t" IP_FMT "\n", __FUNCTION__, IP_ARG(pmlmepriv->gw_ip)); ++ } ++ else ++ { ++ //DBG_871X("Get Gateway IP/MAC fail!\n"); ++ } ++ ++ return res; ++} ++#endif ++ ++int rtw_suspend_free_assoc_resource(_adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct net_device *pnetdev = padapter->pnetdev; ++#ifdef CONFIG_P2P ++ struct wifidirect_info* pwdinfo = &padapter->wdinfo; ++#endif ++ DBG_871X("==> "FUNC_ADPT_FMT" entry....\n", FUNC_ADPT_ARG(padapter)); ++ ++ rtw_cancel_all_timer(padapter); ++ if(pnetdev){ ++ netif_carrier_off(pnetdev); ++ rtw_netif_stop_queue(pnetdev); ++ } ++ ++ #ifdef CONFIG_LAYER2_ROAMING_RESUME ++#ifdef CONFIG_P2P ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED) && rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++#else ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED)) ++#endif ++ { ++ DBG_871X("%s %s(" MAC_FMT "), length:%d assoc_ssid.length:%d\n",__FUNCTION__, ++ pmlmepriv->cur_network.network.Ssid.Ssid, ++ MAC_ARG(pmlmepriv->cur_network.network.MacAddress), ++ pmlmepriv->cur_network.network.Ssid.SsidLength, ++ pmlmepriv->assoc_ssid.SsidLength); ++ rtw_set_roaming(padapter, 1); ++ } ++ #endif //CONFIG_LAYER2_ROAMING_RESUME ++ ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED)) ++ { ++ rtw_disassoc_cmd(padapter, 0, _FALSE); ++ } ++ #ifdef CONFIG_AP_MODE ++ else if(check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ { ++ rtw_sta_flush(padapter); ++ } ++ #endif ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) ){ ++ //s2-2. indicate disconnect to os ++ rtw_indicate_disconnect(padapter); ++ } ++ ++ //s2-3. ++ rtw_free_assoc_resources(padapter, 1); ++ ++ //s2-4. ++#ifdef CONFIG_AUTOSUSPEND ++ if(is_primary_adapter(padapter) && (!adapter_to_pwrctl(padapter)->bInternalAutoSuspend )) ++#endif ++ rtw_free_network_queue(padapter, _TRUE); ++ ++ if(check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) ++ rtw_indicate_scan_done(padapter, 1); ++ ++ DBG_871X("==> "FUNC_ADPT_FMT" exit....\n", FUNC_ADPT_ARG(padapter)); ++ return 0; ++} ++extern void rtw_dev_unload(_adapter *padapter); ++int rtw_suspend_common(_adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ int ret = 0; ++ _func_enter_; ++ LeaveAllPowerSaveMode(padapter); ++ ++ rtw_suspend_free_assoc_resource(padapter); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(rtw_buddy_adapter_up(padapter)){ ++ rtw_suspend_free_assoc_resource(padapter->pbuddy_adapter); ++ } ++#endif ++ rtw_led_control(padapter, LED_CTL_POWER_OFF); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(rtw_buddy_adapter_up(padapter)){ ++ rtw_dev_unload(padapter->pbuddy_adapter); ++ } ++#endif ++ rtw_dev_unload(padapter); ++ ++exit: ++ ++ _func_exit_; ++ return ret; ++} ++ ++int rtw_resume_common(_adapter *padapter) ++{ ++ int ret = 0; ++ struct net_device *pnetdev= padapter->pnetdev; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct mlme_priv *mlmepriv = &padapter->mlmepriv; ++ ++ _func_enter_; ++ ++ #ifdef CONFIG_CONCURRENT_MODE ++ rtw_reset_drv_sw(padapter->pbuddy_adapter); ++ #endif ++ ++ rtw_reset_drv_sw(padapter); ++ pwrpriv->bkeepfwalive = _FALSE; ++ ++ DBG_871X("bkeepfwalive(%x)\n",pwrpriv->bkeepfwalive); ++ if(pm_netdev_open(pnetdev,_TRUE) != 0) { ++ DBG_871X("%s ==> pm_netdev_open failed \n",__FUNCTION__); ++ ret = -1; ++ return ret; ++ } ++ ++ netif_device_attach(pnetdev); ++ netif_carrier_on(pnetdev); ++ ++ ++ #ifdef CONFIG_CONCURRENT_MODE ++ if(rtw_buddy_adapter_up(padapter)){ ++ pnetdev = padapter->pbuddy_adapter->pnetdev; ++ ++ netif_device_attach(pnetdev); ++ netif_carrier_on(pnetdev); ++ } ++ #endif ++ ++ if (check_fwstate(mlmepriv, WIFI_STATION_STATE)) { ++ DBG_871X(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_STATION_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); ++ ++ #ifdef CONFIG_LAYER2_ROAMING_RESUME ++ rtw_roaming(padapter, NULL); ++ #endif //CONFIG_LAYER2_ROAMING_RESUME ++ ++ } else if (check_fwstate(mlmepriv, WIFI_AP_STATE)) { ++ DBG_871X(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_AP_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); ++ rtw_ap_restore_network(padapter); ++ } else if (check_fwstate(mlmepriv, WIFI_ADHOC_STATE)) { ++ DBG_871X(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_ADHOC_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); ++ } else { ++ DBG_871X(FUNC_ADPT_FMT" fwstate:0x%08x - ???\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); ++ } ++ ++ #ifdef CONFIG_CONCURRENT_MODE ++ if(rtw_buddy_adapter_up(padapter)) ++ { ++ mlmepriv = &padapter->pbuddy_adapter->mlmepriv; ++ if (check_fwstate(mlmepriv, WIFI_STATION_STATE)) { ++ DBG_871X(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_STATION_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); ++ ++ #ifdef CONFIG_LAYER2_ROAMING_RESUME ++ rtw_roaming(padapter->pbuddy_adapter, NULL); ++ #endif //CONFIG_LAYER2_ROAMING_RESUME ++ ++ } else if (check_fwstate(mlmepriv, WIFI_AP_STATE)) { ++ DBG_871X(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_AP_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); ++ rtw_ap_restore_network(padapter->pbuddy_adapter); ++ } else if (check_fwstate(mlmepriv, WIFI_ADHOC_STATE)) { ++ DBG_871X(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_ADHOC_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); ++ } else { ++ DBG_871X(FUNC_ADPT_FMT" fwstate:0x%08x - ???\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); ++ } ++ } ++ #endif ++ ++ _func_exit_; ++ return ret; ++} +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/pci_intf.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/pci_intf.c +new file mode 100644 +index 00000000..4d00d304 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/pci_intf.c +@@ -0,0 +1,2001 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _HCI_INTF_C_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef CONFIG_PCI_HCI ++ ++#error "CONFIG_PCI_HCI shall be on!\n" ++ ++#endif ++ ++#include ++#include ++#include ++ ++#if defined (PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) ++ ++#error "Shall be Linux or Windows, but not both!\n" ++ ++#endif ++ ++#ifdef CONFIG_80211N_HT ++extern int rtw_ht_enable; ++extern int rtw_cbw40_enable; ++extern int rtw_ampdu_enable;//for enable tx_ampdu ++#endif ++ ++#ifdef CONFIG_PM ++extern int pm_netdev_open(struct net_device *pnetdev); ++static int rtw_suspend(struct pci_dev *pdev, pm_message_t state); ++static int rtw_resume(struct pci_dev *pdev); ++#endif ++ ++ ++static int rtw_drv_init(struct pci_dev *pdev, const struct pci_device_id *pdid); ++static void rtw_dev_remove(struct pci_dev *pdev); ++ ++static struct specific_device_id specific_device_id_tbl[] = { ++ {.idVendor=0x0b05, .idProduct=0x1791, .flags=SPEC_DEV_ID_DISABLE_HT}, ++ {.idVendor=0x13D3, .idProduct=0x3311, .flags=SPEC_DEV_ID_DISABLE_HT}, ++ {} ++}; ++ ++struct pci_device_id rtw_pci_id_tbl[] = { ++#ifdef CONFIG_RTL8188E ++ {PCI_DEVICE(PCI_VENDER_ID_REALTEK, 0x8179)}, ++#endif ++#ifdef CONFIG_RTL8192C ++ {PCI_DEVICE(PCI_VENDER_ID_REALTEK, 0x8191)}, ++ {PCI_DEVICE(PCI_VENDER_ID_REALTEK, 0x8178)}, ++ {PCI_DEVICE(PCI_VENDER_ID_REALTEK, 0x8177)}, ++ {PCI_DEVICE(PCI_VENDER_ID_REALTEK, 0x8176)}, ++#endif ++#ifdef CONFIG_RTL8192D ++ {PCI_DEVICE(PCI_VENDER_ID_REALTEK, 0x8193)}, ++ {PCI_DEVICE(PCI_VENDER_ID_REALTEK, 0x002B)}, ++#endif ++ {}, ++}; ++ ++struct pci_drv_priv { ++ struct pci_driver rtw_pci_drv; ++ int drv_registered; ++}; ++ ++ ++static struct pci_drv_priv pci_drvpriv = { ++ .rtw_pci_drv.name = (char*)DRV_NAME, ++ .rtw_pci_drv.probe = rtw_drv_init, ++ .rtw_pci_drv.remove = rtw_dev_remove, ++ .rtw_pci_drv.id_table = rtw_pci_id_tbl, ++#ifdef CONFIG_PM ++ .rtw_pci_drv.suspend = rtw_suspend, ++ .rtw_pci_drv.resume = rtw_resume, ++#else ++ .rtw_pci_drv.suspend = NULL, ++ .rtw_pci_drv.resume = NULL, ++#endif ++}; ++ ++ ++MODULE_DEVICE_TABLE(pci, rtw_pci_id_tbl); ++ ++ ++static u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { ++ INTEL_VENDOR_ID, ++ ATI_VENDOR_ID, ++ AMD_VENDOR_ID, ++ SIS_VENDOR_ID ++}; ++ ++static u8 rtw_pci_platform_switch_device_pci_aspm(_adapter *padapter, u8 value) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ u8 bresult = _SUCCESS; ++ int error; ++ ++ value |= 0x40; ++ ++ error = pci_write_config_byte(pdvobjpriv->ppcidev, 0x80, value); ++ ++ if(error != 0) ++ { ++ bresult = _FALSE; ++ DBG_871X("rtw_pci_platform_switch_device_pci_aspm error (%d)\n",error); ++ } ++ ++ return bresult; ++} ++ ++// ++// When we set 0x01 to enable clk request. Set 0x0 to disable clk req. ++// ++static u8 rtw_pci_switch_clk_req(_adapter *padapter, u8 value) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ u8 buffer, bresult = _SUCCESS; ++ int error; ++ ++ buffer = value; ++ ++ if(!padapter->hw_init_completed) ++ return bresult; ++ ++ error = pci_write_config_byte(pdvobjpriv->ppcidev, 0x81, value); ++ ++ if(error != 0) ++ { ++ bresult = _FALSE; ++ DBG_871X("rtw_pci_switch_clk_req error (%d)\n",error); ++ } ++ ++ return bresult; ++} ++ ++#if 0 ++//Description: ++//Disable RTL8192SE ASPM & Disable Pci Bridge ASPM ++void rtw_pci_disable_aspm(_adapter *padapter) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(pdvobjpriv); ++ struct pci_priv *pcipriv = &(pdvobjpriv->pcipriv); ++ u32 pcicfg_addrport = 0; ++ u8 num4bytes; ++ u8 linkctrl_reg; ++ u16 pcibridge_linkctrlreg, aspmlevel = 0; ++ ++ // When there exists anyone's busnum, devnum, and funcnum that are set to 0xff, ++ // we do not execute any action and return. ++ // if it is not intel bus then don't enable ASPM. ++ if ((pcipriv->busnumber == 0xff ++ && pcipriv->devnumber == 0xff ++ && pcipriv->funcnumber == 0xff) ++ || (pcipriv->pcibridge_busnum == 0xff ++ && pcipriv->pcibridge_devnum == 0xff ++ && pcipriv->pcibridge_funcnum == 0xff)) ++ { ++ DBG_871X("PlatformEnableASPM(): Fail to enable ASPM. Cannot find the Bus of PCI(Bridge).\n"); ++ return; ++ } ++ ++ if (pcipriv->pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { ++ DBG_871X("%s(): Disable ASPM. Recognize the Bus of PCI(Bridge) as UNKNOWN.\n", __func__); ++ } ++ ++ if (pwrpriv->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) { ++ RT_CLEAR_PS_LEVEL(pwrpriv, RT_RF_OFF_LEVL_CLK_REQ); ++ rtw_pci_switch_clk_req(padapter, 0x0); ++ } ++ ++ { ++ // Suggested by SD1 for promising device will in L0 state after an I/O. ++ u8 tmp_u1b; ++ ++ pci_read_config_byte(pdvobjpriv->ppcidev, 0x80, &tmp_u1b); ++ } ++ ++ // Retrieve original configuration settings. ++ linkctrl_reg = pcipriv->linkctrl_reg; ++ pcibridge_linkctrlreg = pcipriv->pcibridge_linkctrlreg; ++ ++ // Set corresponding value. ++ aspmlevel |= BIT(0) | BIT(1); ++ linkctrl_reg &= ~aspmlevel; ++ pcibridge_linkctrlreg &= ~(BIT(0) | BIT(1)); ++ ++ rtw_pci_platform_switch_device_pci_aspm(padapter, linkctrl_reg); ++ rtw_udelay_os(50); ++ ++ //When there exists anyone's busnum, devnum, and funcnum that are set to 0xff, ++ // we do not execute any action and return. ++ if ((pcipriv->busnumber == 0xff && ++ pcipriv->devnumber == 0xff && ++ pcipriv->funcnumber == 0xff) || ++ (pcipriv->pcibridge_busnum == 0xff && ++ pcipriv->pcibridge_devnum == 0xff ++ && pcipriv->pcibridge_funcnum == 0xff)) ++ { ++ //Do Nothing!! ++ } ++ else ++ { ++ //4 //Disable Pci Bridge ASPM ++ pcicfg_addrport = (pcipriv->pcibridge_busnum << 16) | ++ (pcipriv->pcibridge_devnum << 11) | ++ (pcipriv->pcibridge_funcnum << 8) | (1 << 31); ++ num4bytes = (pcipriv->pcibridge_pciehdr_offset + 0x10) / 4; ++ ++ // set up address port at 0xCF8 offset field= 0 (dev|vend) ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport + (num4bytes << 2)); ++ ++ // now grab data port with device|vendor 4 byte dword ++ NdisRawWritePortUchar(PCI_CONF_DATA, pcibridge_linkctrlreg); ++ ++ DBG_871X("rtw_pci_disable_aspm():PciBridge busnumber[%x], DevNumbe[%x], funcnumber[%x], Write reg[%x] = %x\n", ++ pcipriv->pcibridge_busnum, pcipriv->pcibridge_devnum, ++ pcipriv->pcibridge_funcnum, ++ (pcipriv->pcibridge_pciehdr_offset+0x10), pcibridge_linkctrlreg); ++ ++ rtw_udelay_os(50); ++ } ++} ++ ++//[ASPM] ++//Description: ++// Enable RTL8192SE ASPM & Enable Pci Bridge ASPM for power saving ++// We should follow the sequence to enable RTL8192SE first then enable Pci Bridge ASPM ++// or the system will show bluescreen. ++void rtw_pci_enable_aspm(_adapter *padapter) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(pdvobjpriv); ++ struct pci_priv *pcipriv = &(pdvobjpriv->pcipriv); ++ u16 aspmlevel = 0; ++ u32 pcicfg_addrport = 0; ++ u8 num4bytes; ++ u8 u_pcibridge_aspmsetting = 0; ++ u8 u_device_aspmsetting = 0; ++ ++ // When there exists anyone's busnum, devnum, and funcnum that are set to 0xff, ++ // we do not execute any action and return. ++ // if it is not intel bus then don't enable ASPM. ++ ++ if ((pcipriv->busnumber == 0xff ++ && pcipriv->devnumber == 0xff ++ && pcipriv->funcnumber == 0xff) ++ || (pcipriv->pcibridge_busnum == 0xff ++ && pcipriv->pcibridge_devnum == 0xff ++ && pcipriv->pcibridge_funcnum == 0xff)) ++ { ++ DBG_871X("PlatformEnableASPM(): Fail to enable ASPM. Cannot find the Bus of PCI(Bridge).\n"); ++ return; ++ } ++ ++ //4 Enable Pci Bridge ASPM ++ pcicfg_addrport = (pcipriv->pcibridge_busnum << 16) ++ | (pcipriv->pcibridge_devnum << 11) ++ | (pcipriv->pcibridge_funcnum << 8) | (1 << 31); ++ num4bytes = (pcipriv->pcibridge_pciehdr_offset + 0x10) / 4; ++ // set up address port at 0xCF8 offset field= 0 (dev|vend) ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport + (num4bytes << 2)); ++ // now grab data port with device|vendor 4 byte dword ++ ++ u_pcibridge_aspmsetting = pcipriv->pcibridge_linkctrlreg | pdvobjpriv->const_hostpci_aspm_setting; ++ ++ if (pcipriv->pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL || ++ pcipriv->pcibridge_vendor == PCI_BRIDGE_VENDOR_SIS) ++ u_pcibridge_aspmsetting &= ~BIT(0); ++ ++ NdisRawWritePortUchar(PCI_CONF_DATA, u_pcibridge_aspmsetting); ++ ++ DBG_871X("PlatformEnableASPM():PciBridge busnumber[%x], DevNumbe[%x], funcnumber[%x], Write reg[%x] = %x\n", ++ pcipriv->pcibridge_busnum, ++ pcipriv->pcibridge_devnum, ++ pcipriv->pcibridge_funcnum, ++ (pcipriv->pcibridge_pciehdr_offset+0x10), ++ u_pcibridge_aspmsetting); ++ ++ rtw_udelay_os(50); ++ ++ // Get ASPM level (with/without Clock Req) ++ aspmlevel |= pdvobjpriv->const_devicepci_aspm_setting; ++ u_device_aspmsetting = pcipriv->linkctrl_reg; ++ u_device_aspmsetting |= aspmlevel; ++ ++ rtw_pci_platform_switch_device_pci_aspm(padapter, u_device_aspmsetting); //(priv->linkctrl_reg | ASPMLevel)); ++ ++ if (pwrpriv->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) { ++ rtw_pci_switch_clk_req(padapter, (pwrpriv->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0); ++ RT_SET_PS_LEVEL(pwrpriv, RT_RF_OFF_LEVL_CLK_REQ); ++ } ++ ++ rtw_udelay_os(50); ++} ++ ++// ++//Description: ++//To get link control field by searching from PCIe capability lists. ++// ++static u8 ++rtw_get_link_control_field(_adapter *padapter, u8 busnum, u8 devnum, ++ u8 funcnum) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct pci_priv *pcipriv = &(pdvobjpriv->pcipriv); ++ struct rt_pci_capabilities_header capability_hdr; ++ u8 capability_offset, num4bytes; ++ u32 pcicfg_addrport = 0; ++ u8 linkctrl_reg; ++ u8 status = _FALSE; ++ ++ //If busnum, devnum, funcnum are set to 0xff. ++ if (busnum == 0xff && devnum == 0xff && funcnum == 0xff) { ++ DBG_871X("GetLinkControlField(): Fail to find PCIe Capability\n"); ++ return _FALSE; ++ } ++ ++ pcicfg_addrport = (busnum << 16) | (devnum << 11) | (funcnum << 8) | (1 << 31); ++ ++ //2PCIeCap ++ ++ // The device supports capability lists. Find the capabilities. ++ num4bytes = 0x34 / 4; ++ //get capability_offset ++ // set up address port at 0xCF8 offset field= 0 (dev|vend) ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport + (num4bytes << 2)); ++ // now grab data port with device|vendor 4 byte dword ++ NdisRawReadPortUchar(PCI_CONF_DATA, &capability_offset); ++ ++ // Loop through the capabilities in search of the power management capability. ++ // The list is NULL-terminated, so the last offset will always be zero. ++ ++ while (capability_offset != 0) { ++ // First find the number of 4 Byte. ++ num4bytes = capability_offset / 4; ++ ++ // Read the header of the capability at this offset. If the retrieved capability is not ++ // the power management capability that we are looking for, follow the link to the ++ // next capability and continue looping. ++ ++ //4 get capability_hdr ++ // set up address port at 0xCF8 offset field= 0 (dev|vend) ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport + (num4bytes << 2)); ++ // now grab data port with device|vendor 4 byte dword ++ NdisRawReadPortUshort(PCI_CONF_DATA, (u16 *) & capability_hdr); ++ ++ // Found the PCI express capability ++ if (capability_hdr.capability_id == PCI_CAPABILITY_ID_PCI_EXPRESS) ++ { ++ break; ++ } ++ else ++ { ++ // This is some other capability. Keep looking for the PCI express capability. ++ capability_offset = capability_hdr.next; ++ } ++ } ++ ++ if (capability_hdr.capability_id == PCI_CAPABILITY_ID_PCI_EXPRESS) // ++ { ++ num4bytes = (capability_offset + 0x10) / 4; ++ ++ //4 Read Link Control Register ++ // set up address port at 0xCF8 offset field= 0 (dev|vend) ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport + (num4bytes << 2)); ++ // now grab data port with device|vendor 4 byte dword ++ NdisRawReadPortUchar(PCI_CONF_DATA, &linkctrl_reg); ++ ++ pcipriv->pcibridge_pciehdr_offset = capability_offset; ++ pcipriv->pcibridge_linkctrlreg = linkctrl_reg; ++ ++ status = _TRUE; ++ } ++ else ++ { ++ // We didn't find a PCIe capability. ++ DBG_871X("GetLinkControlField(): Cannot Find PCIe Capability\n"); ++ } ++ ++ return status; ++} ++ ++// ++//Description: ++//To get PCI bus infomation and return busnum, devnum, and funcnum about ++//the bus(bridge) which the device binds. ++// ++static u8 ++rtw_get_pci_bus_info(_adapter *padapter, ++ u16 vendorid, ++ u16 deviceid, ++ u8 irql, u8 basecode, u8 subclass, u8 filed19val, ++ u8 * busnum, u8 * devnum, u8 * funcnum) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct pci_dev *pdev = pdvobjpriv->ppcidev; ++ u8 busnum_idx, devicenum_idx, functionnum_idx; ++ u32 pcicfg_addrport = 0; ++ u32 dev_venid = 0, classcode, field19, headertype; ++ u16 venId, devId; ++ u8 basec, subc, irqline; ++ u16 regoffset; ++ u8 b_singlefunc = _FALSE; ++ u8 b_bridgechk = _FALSE; ++ ++ *busnum = 0xFF; ++ *devnum = 0xFF; ++ *funcnum = 0xFF; ++ ++ //DBG_871X("==============>vendorid:%x,deviceid:%x,irql:%x\n", vendorid,deviceid,irql); ++ if ((basecode == PCI_CLASS_BRIDGE_DEV) && ++ (subclass == PCI_SUBCLASS_BR_PCI_TO_PCI) ++ && (filed19val == U1DONTCARE)) ++ b_bridgechk = _TRUE; ++ ++ // perform a complete pci bus scan operation ++ for (busnum_idx = 0; busnum_idx < PCI_MAX_BRIDGE_NUMBER; busnum_idx++) //255 ++ { ++ for (devicenum_idx = 0; devicenum_idx < PCI_MAX_DEVICES; devicenum_idx++) //32 ++ { ++ b_singlefunc = _FALSE; ++ for (functionnum_idx = 0; functionnum_idx < PCI_MAX_FUNCTION; functionnum_idx++) //8 ++ { ++ // ++ // We have to skip redundant Bus scan to prevent unexpected system hang ++ // if single function is present in this device. ++ // 2009.02.26. ++ // ++ if (functionnum_idx == 0) { ++ //4 get header type (DWORD #3) ++ pcicfg_addrport = (busnum_idx << 16) | (devicenum_idx << 11) | (functionnum_idx << 8) | (1 << 31); ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport + (3 << 2)); ++ NdisRawReadPortUlong(PCI_CONF_DATA, &headertype); ++ headertype = ((headertype >> 16) & 0x0080) >> 7; // address 0x0e[7]. ++ if (headertype == 0) //Single function ++ b_singlefunc = _TRUE; ++ } ++ else ++ {//By pass the following scan process. ++ if (b_singlefunc == _TRUE) ++ break; ++ } ++ ++ // Set access enable control. ++ pcicfg_addrport = (busnum_idx << 16) | (devicenum_idx << 11) | (functionnum_idx << 8) | (1 << 31); ++ ++ //4 // Get vendorid/ deviceid ++ // set up address port at 0xCF8 offset field= 0 (dev|vend) ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport); ++ // now grab data port with device|vendor 4 byte dword ++ NdisRawReadPortUlong(PCI_CONF_DATA, &dev_venid); ++ ++ // if data port is full of 1s, no device is present ++ // some broken boards return 0 if a slot is empty: ++ if (dev_venid == 0xFFFFFFFF || dev_venid == 0) ++ continue; //PCI_INVALID_VENDORID ++ ++ // 4 // Get irql ++ regoffset = 0x3C; ++ pcicfg_addrport = (busnum_idx << 16) | (devicenum_idx << 11) | (functionnum_idx << 8) | (1 << 31) | (regoffset & 0xFFFFFFFC); ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport); ++ NdisRawReadPortUchar((PCI_CONF_DATA +(regoffset & 0x3)), &irqline); ++ ++ venId = (u16) (dev_venid >> 0) & 0xFFFF; ++ devId = (u16) (dev_venid >> 16) & 0xFFFF; ++ ++ // Check Vendor ID ++ if (!b_bridgechk && (venId != vendorid) && (vendorid != U2DONTCARE)) ++ continue; ++ ++ // Check Device ID ++ if (!b_bridgechk && (devId != deviceid) && (deviceid != U2DONTCARE)) ++ continue; ++ ++ // Check irql ++ if (!b_bridgechk && (irqline != irql) && (irql != U1DONTCARE)) ++ continue; ++ ++ //4 get Class Code ++ pcicfg_addrport = (busnum_idx << 16) | (devicenum_idx << 11) | (functionnum_idx << 8) | (1 << 31); ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport + (2 << 2)); ++ NdisRawReadPortUlong(PCI_CONF_DATA, &classcode); ++ classcode = classcode >> 8; ++ ++ basec = (u8) (classcode >> 16) & 0xFF; ++ subc = (u8) (classcode >> 8) & 0xFF; ++ if (b_bridgechk && (venId != vendorid) && (basec == basecode) && (subc == subclass)) ++ return _TRUE; ++ ++ // Check Vendor ID ++ if (b_bridgechk && (venId != vendorid) && (vendorid != U2DONTCARE)) ++ continue; ++ ++ // Check Device ID ++ if (b_bridgechk && (devId != deviceid) && (deviceid != U2DONTCARE)) ++ continue; ++ ++ // Check irql ++ if (b_bridgechk && (irqline != irql) && (irql != U1DONTCARE)) ++ continue; ++ ++ //4 get field 0x19 value (DWORD #6) ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport + (6 << 2)); ++ NdisRawReadPortUlong(PCI_CONF_DATA, &field19); ++ field19 = (field19 >> 8) & 0xFF; ++ ++ //4 Matching Class Code and filed19. ++ if ((basec == basecode) && (subc == subclass) && ((field19 == filed19val) || (filed19val == U1DONTCARE))) { ++ *busnum = busnum_idx; ++ *devnum = devicenum_idx; ++ *funcnum = functionnum_idx; ++ ++ DBG_871X("GetPciBusInfo(): Find Device(%X:%X) bus=%d dev=%d, func=%d\n", ++ vendorid, deviceid, busnum_idx, devicenum_idx, functionnum_idx); ++ return _TRUE; ++ } ++ } ++ } ++ } ++ ++ DBG_871X("GetPciBusInfo(): Cannot Find Device(%X:%X:%X)\n", vendorid, deviceid, dev_venid); ++ ++ return _FALSE; ++} ++ ++static u8 ++rtw_get_pci_brideg_info(_adapter *padapter, ++ u8 basecode, ++ u8 subclass, ++ u8 filed19val, u8 * busnum, u8 * devnum, ++ u8 * funcnum, u16 * vendorid, u16 * deviceid) ++{ ++ u8 busnum_idx, devicenum_idx, functionnum_idx; ++ u32 pcicfg_addrport = 0; ++ u32 dev_venid, classcode, field19, headertype; ++ u16 venId, devId; ++ u8 basec, subc, irqline; ++ u16 regoffset; ++ u8 b_singlefunc = _FALSE; ++ ++ *busnum = 0xFF; ++ *devnum = 0xFF; ++ *funcnum = 0xFF; ++ ++ // perform a complete pci bus scan operation ++ for (busnum_idx = 0; busnum_idx < PCI_MAX_BRIDGE_NUMBER; busnum_idx++) //255 ++ { ++ for (devicenum_idx = 0; devicenum_idx < PCI_MAX_DEVICES; devicenum_idx++) //32 ++ { ++ b_singlefunc = _FALSE; ++ for (functionnum_idx = 0; functionnum_idx < PCI_MAX_FUNCTION; functionnum_idx++) //8 ++ { ++ // ++ // We have to skip redundant Bus scan to prevent unexpected system hang ++ // if single function is present in this device. ++ // 2009.02.26. ++ // ++ if (functionnum_idx == 0) ++ { ++ //4 get header type (DWORD #3) ++ pcicfg_addrport = (busnum_idx << 16) | (devicenum_idx << 11) | (functionnum_idx << 8) | (1 << 31); ++ //NdisRawWritePortUlong((ULONG_PTR)PCI_CONF_ADDRESS , pcicfg_addrport + (3 << 2)); ++ //NdisRawReadPortUlong((ULONG_PTR)PCI_CONF_DATA, &headertype); ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport + (3 << 2)); ++ NdisRawReadPortUlong(PCI_CONF_DATA, &headertype); ++ headertype = ((headertype >> 16) & 0x0080) >> 7; // address 0x0e[7]. ++ if (headertype == 0) //Single function ++ b_singlefunc = _TRUE; ++ } ++ else ++ {//By pass the following scan process. ++ if (b_singlefunc == _TRUE) ++ break; ++ } ++ ++ pcicfg_addrport = (busnum_idx << 16) | (devicenum_idx << 11) | (functionnum_idx << 8) | (1 << 31); ++ ++ //4 // Get vendorid/ deviceid ++ // set up address port at 0xCF8 offset field= 0 (dev|vend) ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport); ++ // now grab data port with device|vendor 4 byte dword ++ NdisRawReadPortUlong(PCI_CONF_DATA, &dev_venid); ++ ++ //4 Get irql ++ regoffset = 0x3C; ++ pcicfg_addrport = (busnum_idx << 16) | (devicenum_idx << 11) | (functionnum_idx << 8) | (1 << 31) | (regoffset & 0xFFFFFFFC); ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport); ++ NdisRawReadPortUchar((PCI_CONF_DATA + (regoffset & 0x3)), &irqline); ++ ++ venId = (u16) (dev_venid >> 0) & 0xFFFF; ++ devId = (u16) (dev_venid >> 16) & 0xFFFF; ++ ++ //4 get Class Code ++ pcicfg_addrport = (busnum_idx << 16) | (devicenum_idx << 11) | (functionnum_idx << 8) | (1 << 31); ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport + (2 << 2)); ++ NdisRawReadPortUlong(PCI_CONF_DATA, &classcode); ++ classcode = classcode >> 8; ++ ++ basec = (u8) (classcode >> 16) & 0xFF; ++ subc = (u8) (classcode >> 8) & 0xFF; ++ ++ //4 get field 0x19 value (DWORD #6) ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport + (6 << 2)); ++ NdisRawReadPortUlong(PCI_CONF_DATA, &field19); ++ field19 = (field19 >> 8) & 0xFF; ++ ++ //4 Matching Class Code and filed19. ++ if ((basec == basecode) && (subc == subclass) && ((field19 == filed19val) || (filed19val == U1DONTCARE))) { ++ *busnum = busnum_idx; ++ *devnum = devicenum_idx; ++ *funcnum = functionnum_idx; ++ *vendorid = venId; ++ *deviceid = devId; ++ ++ DBG_871X("GetPciBridegInfo : Find Device(%X:%X) bus=%d dev=%d, func=%d\n", ++ venId, devId, busnum_idx, devicenum_idx, functionnum_idx); ++ ++ return _TRUE; ++ } ++ } ++ } ++ } ++ ++ DBG_871X("GetPciBridegInfo(): Cannot Find PciBridge for Device\n"); ++ ++ return _FALSE; ++} // end of GetPciBridegInfo ++ ++// ++//Description: ++//To find specific bridge information. ++// ++static void rtw_find_bridge_info(_adapter *padapter) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct pci_priv *pcipriv = &(pdvobjpriv->pcipriv); ++ u8 pcibridge_busnum = 0xff; ++ u8 pcibridge_devnum = 0xff; ++ u8 pcibridge_funcnum = 0xff; ++ u16 pcibridge_vendorid = 0xff; ++ u16 pcibridge_deviceid = 0xff; ++ u8 tmp = 0; ++ ++ rtw_get_pci_brideg_info(padapter, ++ PCI_CLASS_BRIDGE_DEV, ++ PCI_SUBCLASS_BR_PCI_TO_PCI, ++ pcipriv->busnumber, ++ &pcibridge_busnum, ++ &pcibridge_devnum, &pcibridge_funcnum, ++ &pcibridge_vendorid, &pcibridge_deviceid); ++ ++ // match the array of vendor id and regonize which chipset is used. ++ pcipriv->pcibridge_vendor = PCI_BRIDGE_VENDOR_UNKNOWN; ++ ++ for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) { ++ if (pcibridge_vendorid == pcibridge_vendors[tmp]) { ++ pcipriv->pcibridge_vendor = tmp; ++ DBG_871X("Pci Bridge Vendor is found index: %d\n", tmp); ++ break; ++ } ++ } ++ DBG_871X("Pci Bridge Vendor is %x\n", pcibridge_vendors[tmp]); ++ ++ // Update corresponding PCI bus info. ++ pcipriv->pcibridge_busnum = pcibridge_busnum; ++ pcipriv->pcibridge_devnum = pcibridge_devnum; ++ pcipriv->pcibridge_funcnum = pcibridge_funcnum; ++ pcipriv->pcibridge_vendorid = pcibridge_vendorid; ++ pcipriv->pcibridge_deviceid = pcibridge_deviceid; ++ ++} ++ ++static u8 ++rtw_get_amd_l1_patch(_adapter *padapter, u8 busnum, u8 devnum, ++ u8 funcnum) ++{ ++ u8 status = _FALSE; ++ u8 offset_e0; ++ unsigned offset_e4; ++ u32 pcicfg_addrport = 0; ++ ++ pcicfg_addrport = (busnum << 16) | (devnum << 11) | (funcnum << 8) | (1 << 31); ++ ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport + 0xE0); ++ NdisRawWritePortUchar(PCI_CONF_DATA, 0xA0); ++ ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport + 0xE0); ++ NdisRawReadPortUchar(PCI_CONF_DATA, &offset_e0); ++ ++ if (offset_e0 == 0xA0) ++ { ++ NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport + 0xE4); ++ NdisRawReadPortUlong(PCI_CONF_DATA, &offset_e4); ++ //DbgPrint("Offset E4 %x\n", offset_e4); ++ if (offset_e4 & BIT(23)) ++ status = _TRUE; ++ } ++ ++ return status; ++} ++#else ++/*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/ ++void rtw_pci_disable_aspm(_adapter *padapter) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(pdvobjpriv); ++ struct pci_dev *pdev = pdvobjpriv->ppcidev; ++ struct pci_dev *bridge_pdev = pdev->bus->self; ++ struct pci_priv *pcipriv = &(pdvobjpriv->pcipriv); ++ u8 linkctrl_reg; ++ u16 pcibridge_linkctrlreg; ++ u16 aspmlevel = 0; ++ ++ // We do not diable/enable ASPM by driver, in the future, the BIOS will enable host and NIC ASPM. ++ // Advertised by SD1 victorh. Added by tynli. 2009.11.23. ++ if(pdvobjpriv->const_pci_aspm == 0) ++ return; ++ ++ if(!padapter->hw_init_completed) ++ return; ++ ++ if (pcipriv->pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s(): PCI(Bridge) UNKNOWN.\n", __FUNCTION__)); ++ return; ++ } ++ ++ linkctrl_reg = pcipriv->linkctrl_reg; ++ pcibridge_linkctrlreg = pcipriv->pcibridge_linkctrlreg; ++ ++ // Set corresponding value. ++ aspmlevel |= BIT(0) | BIT(1); ++ linkctrl_reg &=~aspmlevel; ++ pcibridge_linkctrlreg &=~aspmlevel; ++ ++ if (pwrpriv->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) { ++ RT_CLEAR_PS_LEVEL(pwrpriv, RT_RF_OFF_LEVL_CLK_REQ); ++ rtw_pci_switch_clk_req(padapter, 0x0); ++ } ++ ++ { ++ /*for promising device will in L0 state after an I/O.*/ ++ u8 tmp_u1b; ++ pci_read_config_byte(pdev, 0x80, &tmp_u1b); ++ } ++ ++ rtw_pci_platform_switch_device_pci_aspm(padapter, linkctrl_reg); ++ rtw_udelay_os(50); ++ ++ //When there exists anyone's BusNum, DevNum, and FuncNum that are set to 0xff, ++ // we do not execute any action and return. Added by tynli. ++ if( (pcipriv->busnumber == 0xff && pcipriv->devnumber == 0xff && pcipriv->funcnumber == 0xff) || ++ (pcipriv->pcibridge_busnum == 0xff && pcipriv->pcibridge_devnum == 0xff && pcipriv->pcibridge_funcnum == 0xff) ) ++ { ++ // Do Nothing!! ++ } ++ else ++ { ++ /*Disable Pci Bridge ASPM*/ ++ //NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport + (num4bytes << 2)); ++ //NdisRawWritePortUchar(PCI_CONF_DATA, pcibridge_linkctrlreg); ++ pci_write_config_byte(bridge_pdev, pcipriv->pcibridge_pciehdr_offset + 0x10, pcibridge_linkctrlreg); ++ ++ DBG_871X("rtw_pci_disable_aspm():PciBridge busnumber[%x], DevNumbe[%x], funcnumber[%x], Write reg[%x] = %x\n", ++ pcipriv->pcibridge_busnum, pcipriv->pcibridge_devnum, ++ pcipriv->pcibridge_funcnum, ++ (pcipriv->pcibridge_pciehdr_offset+0x10), pcibridge_linkctrlreg); ++ ++ rtw_udelay_os(50); ++ } ++ ++} ++ ++/*Enable RTL8192SE ASPM & Enable Pci Bridge ASPM for ++power saving We should follow the sequence to enable ++RTL8192SE first then enable Pci Bridge ASPM ++or the system will show bluescreen.*/ ++void rtw_pci_enable_aspm(_adapter *padapter) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(pdvobjpriv); ++ struct pci_dev *pdev = pdvobjpriv->ppcidev; ++ struct pci_dev *bridge_pdev = pdev->bus->self; ++ struct pci_priv *pcipriv = &(pdvobjpriv->pcipriv); ++ u16 aspmlevel = 0; ++ u8 u_pcibridge_aspmsetting = 0; ++ u8 u_device_aspmsetting = 0; ++ u32 u_device_aspmsupportsetting = 0; ++ ++ // We do not diable/enable ASPM by driver, in the future, the BIOS will enable host and NIC ASPM. ++ // Advertised by SD1 victorh. Added by tynli. 2009.11.23. ++ if(pdvobjpriv->const_pci_aspm == 0) ++ return; ++ ++ //When there exists anyone's BusNum, DevNum, and FuncNum that are set to 0xff, ++ // we do not execute any action and return. Added by tynli. ++ if( (pcipriv->busnumber == 0xff && pcipriv->devnumber == 0xff && pcipriv->funcnumber == 0xff) || ++ (pcipriv->pcibridge_busnum == 0xff && pcipriv->pcibridge_devnum == 0xff && pcipriv->pcibridge_funcnum == 0xff) ) ++ { ++ DBG_871X("rtw_pci_enable_aspm(): Fail to enable ASPM. Cannot find the Bus of PCI(Bridge).\n"); ++ return; ++ } ++ ++//Get Bridge ASPM Support ++//not to enable bridge aspm if bridge does not support ++//Added by sherry 20100803 ++ if (IS_HARDWARE_TYPE_8192DE(padapter)) ++ { ++ //PciCfgAddrPort = (pcipriv->pcibridge_busnum << 16)|(pcipriv->pcibridge_devnum<< 11)|(pcipriv->pcibridge_funcnum << 8)|(1 << 31); ++ //Num4Bytes = (pcipriv->pcibridge_pciehdr_offset+0x0C)/4; ++ //NdisRawWritePortUlong((ULONG_PTR)PCI_CONF_ADDRESS , PciCfgAddrPort+(Num4Bytes << 2)); ++ //NdisRawReadPortUlong((ULONG_PTR)PCI_CONF_DATA,&uDeviceASPMSupportSetting); ++ pci_read_config_dword(bridge_pdev, (pcipriv->pcibridge_pciehdr_offset+0x0C), &u_device_aspmsupportsetting); ++ DBG_871X("rtw_pci_enable_aspm(): Bridge ASPM support %x \n",u_device_aspmsupportsetting); ++ if(((u_device_aspmsupportsetting & BIT(11)) != BIT(11)) || ((u_device_aspmsupportsetting & BIT(10)) != BIT(10))) ++ { ++ if(pdvobjpriv->const_devicepci_aspm_setting == 3) ++ { ++ DBG_871X("rtw_pci_enable_aspm(): Bridge not support L0S or L1\n"); ++ return; ++ } ++ else if(pdvobjpriv->const_devicepci_aspm_setting == 2) ++ { ++ if((u_device_aspmsupportsetting & BIT(11)) != BIT(11)) ++ { ++ DBG_871X("rtw_pci_enable_aspm(): Bridge not support L1 \n"); ++ return; ++ } ++ } ++ else if(pdvobjpriv->const_devicepci_aspm_setting == 1) ++ { ++ if((u_device_aspmsupportsetting & BIT(10)) != BIT(10)) ++ { ++ DBG_871X("rtw_pci_enable_aspm(): Bridge not support L0s \n"); ++ return; ++ } ++ ++ } ++ } ++ else ++ { ++ DBG_871X("rtw_pci_enable_aspm(): Bridge support L0s and L1 \n"); ++ } ++ } ++ ++ ++ /*Enable Pci Bridge ASPM*/ ++ //PciCfgAddrPort = (pcipriv->pcibridge_busnum << 16)|(pcipriv->pcibridge_devnum<< 11) |(pcipriv->pcibridge_funcnum << 8)|(1 << 31); ++ //Num4Bytes = (pcipriv->pcibridge_pciehdr_offset+0x10)/4; ++ // set up address port at 0xCF8 offset field= 0 (dev|vend) ++ //NdisRawWritePortUlong(PCI_CONF_ADDRESS, PciCfgAddrPort + (Num4Bytes << 2)); ++ // now grab data port with device|vendor 4 byte dword ++ ++ u_pcibridge_aspmsetting = pcipriv->pcibridge_linkctrlreg; ++ u_pcibridge_aspmsetting |= pdvobjpriv->const_hostpci_aspm_setting; ++ ++ if (pcipriv->pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL || ++ pcipriv->pcibridge_vendor == PCI_BRIDGE_VENDOR_SIS ) ++ u_pcibridge_aspmsetting &= ~BIT(0); // for intel host 42 device 43 ++ ++ //NdisRawWritePortUchar(PCI_CONF_DATA, u_pcibridge_aspmsetting); ++ pci_write_config_byte(bridge_pdev, (pcipriv->pcibridge_pciehdr_offset+0x10), u_pcibridge_aspmsetting); ++ ++ DBG_871X("PlatformEnableASPM():PciBridge busnumber[%x], DevNumbe[%x], funcnumber[%x], Write reg[%x] = %x\n", ++ pcipriv->pcibridge_busnum, pcipriv->pcibridge_devnum, pcipriv->pcibridge_funcnum, ++ (pcipriv->pcibridge_pciehdr_offset+0x10), ++ u_pcibridge_aspmsetting); ++ ++ rtw_udelay_os(50); ++ ++ /*Get ASPM level (with/without Clock Req)*/ ++ aspmlevel |= pdvobjpriv->const_devicepci_aspm_setting; ++ u_device_aspmsetting = pcipriv->linkctrl_reg; ++ u_device_aspmsetting |= aspmlevel; // device 43 ++ ++ rtw_pci_platform_switch_device_pci_aspm(padapter, u_device_aspmsetting); ++ ++ if (pwrpriv->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) { ++ rtw_pci_switch_clk_req(padapter, (pwrpriv->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0); ++ RT_SET_PS_LEVEL(pwrpriv, RT_RF_OFF_LEVL_CLK_REQ); ++ } ++ ++ rtw_udelay_os(50); ++} ++ ++static u8 rtw_pci_get_amd_l1_patch(struct dvobj_priv *pdvobjpriv) ++{ ++ struct pci_dev *pdev = pdvobjpriv->ppcidev; ++ struct pci_dev *bridge_pdev = pdev->bus->self; ++ u8 status = _FALSE; ++ u8 offset_e0; ++ u32 offset_e4; ++ ++ //NdisRawWritePortUlong(PCI_CONF_ADDRESS,pcicfg_addrport + 0xE0); ++ //NdisRawWritePortUchar(PCI_CONF_DATA, 0xA0); ++ pci_write_config_byte(bridge_pdev, 0xE0, 0xA0); ++ ++ //NdisRawWritePortUlong(PCI_CONF_ADDRESS,pcicfg_addrport + 0xE0); ++ //NdisRawReadPortUchar(PCI_CONF_DATA, &offset_e0); ++ pci_read_config_byte(bridge_pdev, 0xE0, &offset_e0); ++ ++ if (offset_e0 == 0xA0) { ++ //NdisRawWritePortUlong(PCI_CONF_ADDRESS, pcicfg_addrport + 0xE4); ++ //NdisRawReadPortUlong(PCI_CONF_DATA, &offset_e4); ++ pci_read_config_dword(bridge_pdev, 0xE4, &offset_e4); ++ if (offset_e4 & BIT(23)) ++ status = _TRUE; ++ } ++ ++ return status; ++} ++ ++static void rtw_pci_get_linkcontrol_field(struct dvobj_priv *pdvobjpriv) ++{ ++ struct pci_priv *pcipriv = &(pdvobjpriv->pcipriv); ++ struct pci_dev *pdev = pdvobjpriv->ppcidev; ++ struct pci_dev *bridge_pdev = pdev->bus->self; ++ u8 capabilityoffset = pcipriv->pcibridge_pciehdr_offset; ++ u8 linkctrl_reg; ++ ++ /*Read Link Control Register*/ ++ pci_read_config_byte(bridge_pdev, capabilityoffset + PCI_EXP_LNKCTL, &linkctrl_reg); ++ ++ pcipriv->pcibridge_linkctrlreg = linkctrl_reg; ++} ++#endif ++ ++static void rtw_pci_parse_configuration(struct pci_dev *pdev, struct dvobj_priv *pdvobjpriv) ++{ ++ struct pci_priv *pcipriv = &(pdvobjpriv->pcipriv); ++ u8 tmp; ++ int pos; ++ u8 linkctrl_reg; ++ ++ //Link Control Register ++ pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); ++ pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &linkctrl_reg); ++ pcipriv->linkctrl_reg = linkctrl_reg; ++ ++ //DBG_871X("Link Control Register = %x\n", pcipriv->linkctrl_reg); ++ ++ pci_read_config_byte(pdev, 0x98, &tmp); ++ tmp |= BIT(4); ++ pci_write_config_byte(pdev, 0x98, tmp); ++ ++ //tmp = 0x17; ++ //pci_write_config_byte(pdev, 0x70f, tmp); ++} ++ ++// ++// Update PCI dependent default settings. ++// ++static void rtw_pci_update_default_setting(_adapter *padapter) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct pci_priv *pcipriv = &(pdvobjpriv->pcipriv); ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(pdvobjpriv); ++ ++ //reset pPSC->reg_rfps_level & priv->b_support_aspm ++ pwrpriv->reg_rfps_level = 0; ++ pwrpriv->b_support_aspm = 0; ++ ++ // Dynamic Mechanism, ++ //rtw_hal_set_def_var(pAdapter, HAL_DEF_INIT_GAIN, &(pDevice->InitGainState)); ++ ++ // Update PCI ASPM setting ++ pwrpriv->const_amdpci_aspm = pdvobjpriv->const_amdpci_aspm; ++ switch (pdvobjpriv->const_pci_aspm) { ++ case 0: // No ASPM ++ break; ++ ++ case 1: // ASPM dynamically enabled/disable. ++ pwrpriv->reg_rfps_level |= RT_RF_LPS_LEVEL_ASPM; ++ break; ++ ++ case 2: // ASPM with Clock Req dynamically enabled/disable. ++ pwrpriv->reg_rfps_level |= (RT_RF_LPS_LEVEL_ASPM | RT_RF_OFF_LEVL_CLK_REQ); ++ break; ++ ++ case 3: // Always enable ASPM and Clock Req from initialization to halt. ++ pwrpriv->reg_rfps_level &= ~(RT_RF_LPS_LEVEL_ASPM); ++ pwrpriv->reg_rfps_level |= (RT_RF_PS_LEVEL_ALWAYS_ASPM | RT_RF_OFF_LEVL_CLK_REQ); ++ break; ++ ++ case 4: // Always enable ASPM without Clock Req from initialization to halt. ++ pwrpriv->reg_rfps_level &= ~(RT_RF_LPS_LEVEL_ASPM | RT_RF_OFF_LEVL_CLK_REQ); ++ pwrpriv->reg_rfps_level |= RT_RF_PS_LEVEL_ALWAYS_ASPM; ++ break; ++ } ++ ++ pwrpriv->reg_rfps_level |= RT_RF_OFF_LEVL_HALT_NIC; ++ ++ // Update Radio OFF setting ++ switch (pdvobjpriv->const_hwsw_rfoff_d3) { ++ case 1: ++ if (pwrpriv->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM) ++ pwrpriv->reg_rfps_level |= RT_RF_OFF_LEVL_ASPM; ++ break; ++ ++ case 2: ++ if (pwrpriv->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM) ++ pwrpriv->reg_rfps_level |= RT_RF_OFF_LEVL_ASPM; ++ pwrpriv->reg_rfps_level |= RT_RF_OFF_LEVL_HALT_NIC; ++ break; ++ ++ case 3: ++ pwrpriv->reg_rfps_level |= RT_RF_OFF_LEVL_PCI_D3; ++ break; ++ } ++ ++ // Update Rx 2R setting ++ //pPSC->reg_rfps_level |= ((pDevice->RegLPS2RDisable) ? RT_RF_LPS_DISALBE_2R : 0); ++ ++ // ++ // Set HW definition to determine if it supports ASPM. ++ // ++ switch (pdvobjpriv->const_support_pciaspm) { ++ case 0: // Not support ASPM. ++ { ++ u8 b_support_aspm = _FALSE; ++ pwrpriv->b_support_aspm = b_support_aspm; ++ } ++ break; ++ ++ case 1: // Support ASPM. ++ { ++ u8 b_support_aspm = _TRUE; ++ u8 b_support_backdoor = _TRUE; ++ ++ pwrpriv->b_support_aspm = b_support_aspm; ++ ++ /*if(pAdapter->MgntInfo.CustomerID == RT_CID_TOSHIBA && ++ pcipriv->pcibridge_vendor == PCI_BRIDGE_VENDOR_AMD && ++ !pcipriv->amd_l1_patch) ++ b_support_backdoor = _FALSE;*/ ++ ++ pwrpriv->b_support_backdoor = b_support_backdoor; ++ } ++ break; ++ ++ case 2: // Set by Chipset. ++ // ASPM value set by chipset. ++ if (pcipriv->pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) { ++ u8 b_support_aspm = _TRUE; ++ pwrpriv->b_support_aspm = b_support_aspm; ++ } ++ break; ++ ++ default: ++ // Do nothing. Set when finding the chipset. ++ break; ++ } ++} ++ ++static void rtw_pci_initialize_adapter_common(_adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ ++ rtw_pci_update_default_setting(padapter); ++ ++ if (pwrpriv->reg_rfps_level & RT_RF_PS_LEVEL_ALWAYS_ASPM) { ++ // Always enable ASPM & Clock Req. ++ rtw_pci_enable_aspm(padapter); ++ RT_SET_PS_LEVEL(pwrpriv, RT_RF_PS_LEVEL_ALWAYS_ASPM); ++ } ++ ++} ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) || (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) ++#define rtw_pci_interrupt(x,y,z) rtw_pci_interrupt(x,y) ++#endif ++ ++static irqreturn_t rtw_pci_interrupt(int irq, void *priv, struct pt_regs *regs) ++{ ++ struct dvobj_priv *dvobj = (struct dvobj_priv *)priv; ++ _adapter *adapter = dvobj->if1; ++ ++ if (dvobj->irq_enabled == 0) { ++ return IRQ_HANDLED; ++ } ++ ++ if(rtw_hal_interrupt_handler(adapter) == _FAIL) ++ return IRQ_HANDLED; ++ //return IRQ_NONE; ++ ++ return IRQ_HANDLED; ++} ++ ++#ifdef RTK_DMP_PLATFORM ++#define pci_iounmap(x,y) iounmap(y) ++#endif ++ ++int pci_alloc_irq(struct dvobj_priv *dvobj) ++{ ++ int err; ++ struct pci_dev *pdev = dvobj->ppcidev; ++ ++#if defined(IRQF_SHARED) ++ err = request_irq(pdev->irq, &rtw_pci_interrupt, IRQF_SHARED, DRV_NAME, dvobj); ++#else ++ err = request_irq(pdev->irq, &rtw_pci_interrupt, SA_SHIRQ, DRV_NAME, dvobj); ++#endif ++ if (err) { ++ DBG_871X("Error allocating IRQ %d",pdev->irq); ++ } else { ++ dvobj->irq_alloc = 1; ++ DBG_871X("Request_irq OK, IRQ %d\n",pdev->irq); ++ } ++ ++ return err?_FAIL:_SUCCESS; ++} ++ ++static struct dvobj_priv *pci_dvobj_init(struct pci_dev *pdev) ++{ ++ int err; ++ u32 status = _FAIL; ++ struct dvobj_priv *dvobj = NULL; ++ struct pci_priv *pcipriv = NULL; ++ struct pci_dev *bridge_pdev = pdev->bus->self; ++ unsigned long pmem_start, pmem_len, pmem_flags; ++ u8 tmp; ++ ++_func_enter_; ++ ++ if ((dvobj = (struct dvobj_priv*)rtw_zmalloc(sizeof(*dvobj))) == NULL) { ++ goto exit; ++ } ++ dvobj->ppcidev = pdev; ++ pcipriv = &(dvobj->pcipriv); ++ pci_set_drvdata(pdev, dvobj); ++ ++ _rtw_mutex_init(&dvobj->hw_init_mutex); ++ _rtw_mutex_init(&dvobj->h2c_fwcmd_mutex); ++ _rtw_mutex_init(&dvobj->setch_mutex); ++ _rtw_mutex_init(&dvobj->setbw_mutex); ++ ++ dvobj->processing_dev_remove = _FALSE; ++ if ( (err = pci_enable_device(pdev)) != 0) { ++ DBG_871X(KERN_ERR "%s : Cannot enable new PCI device\n", pci_name(pdev)); ++ goto free_dvobj; ++ } ++ ++#ifdef CONFIG_64BIT_DMA ++ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { ++ DBG_871X("RTL819xCE: Using 64bit DMA\n"); ++ if ((err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) != 0) { ++ DBG_871X(KERN_ERR "Unable to obtain 64bit DMA for consistent allocations\n"); ++ goto disable_picdev; ++ } ++ dvobj->bdma64 = _TRUE; ++ } else ++#endif ++ { ++ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { ++ if ((err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) { ++ DBG_871X(KERN_ERR "Unable to obtain 32bit DMA for consistent allocations\n"); ++ goto disable_picdev; ++ } ++ } ++ } ++ ++ pci_set_master(pdev); ++ ++ if ((err = pci_request_regions(pdev, DRV_NAME)) != 0) { ++ DBG_871X(KERN_ERR "Can't obtain PCI resources\n"); ++ goto disable_picdev; ++ } ++ //MEM map ++ pmem_start = pci_resource_start(pdev, 2); ++ pmem_len = pci_resource_len(pdev, 2); ++ pmem_flags = pci_resource_flags(pdev, 2); ++ ++#ifdef RTK_DMP_PLATFORM ++ dvobj->pci_mem_start = (unsigned long)ioremap_nocache(pmem_start, pmem_len); ++#else ++ dvobj->pci_mem_start = (unsigned long)pci_iomap(pdev, 2, pmem_len); /* shared mem start */ ++#endif ++ if (dvobj->pci_mem_start == 0) { ++ DBG_871X(KERN_ERR "Can't map PCI mem\n"); ++ goto release_regions; ++ } ++ ++ DBG_871X("Memory mapped space start: 0x%08lx len:%08lx flags:%08lx, after map:0x%08lx\n", ++ pmem_start, pmem_len, pmem_flags, dvobj->pci_mem_start); ++ ++ // Disable Clk Request */ ++ pci_write_config_byte(pdev, 0x81, 0); ++ // leave D3 mode */ ++ pci_write_config_byte(pdev, 0x44, 0); ++ pci_write_config_byte(pdev, 0x04, 0x06); ++ pci_write_config_byte(pdev, 0x04, 0x07); ++ ++#if 1 ++ /*find bus info*/ ++ pcipriv->busnumber = pdev->bus->number; ++ pcipriv->devnumber = PCI_SLOT(pdev->devfn); ++ pcipriv->funcnumber = PCI_FUNC(pdev->devfn); ++ ++ /*find bridge info*/ ++ pcipriv->pcibridge_vendor = PCI_BRIDGE_VENDOR_UNKNOWN; ++ if(bridge_pdev){ ++ pcipriv->pcibridge_vendorid = bridge_pdev->vendor; ++ for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) { ++ if (bridge_pdev->vendor == pcibridge_vendors[tmp]) { ++ pcipriv->pcibridge_vendor = tmp; ++ DBG_871X("Pci Bridge Vendor is found index: %d, %x\n", tmp, pcibridge_vendors[tmp]); ++ break; ++ } ++ } ++ } ++ ++ //if (pcipriv->pcibridge_vendor != PCI_BRIDGE_VENDOR_UNKNOWN) { ++ if(bridge_pdev){ ++ pcipriv->pcibridge_busnum = bridge_pdev->bus->number; ++ pcipriv->pcibridge_devnum = PCI_SLOT(bridge_pdev->devfn); ++ pcipriv->pcibridge_funcnum = PCI_FUNC(bridge_pdev->devfn); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)) ++ pcipriv->pcibridge_pciehdr_offset = pci_find_capability(bridge_pdev, PCI_CAP_ID_EXP); ++#else ++ pcipriv->pcibridge_pciehdr_offset = bridge_pdev->pcie_cap; ++#endif ++ ++ rtw_pci_get_linkcontrol_field(dvobj); ++ ++ if (pcipriv->pcibridge_vendor == PCI_BRIDGE_VENDOR_AMD) { ++ pcipriv->amd_l1_patch = rtw_pci_get_amd_l1_patch(dvobj); ++ } ++ } ++#else ++ // ++ // Find bridge related info. ++ // ++ rtw_get_pci_bus_info(padapter, ++ pdev->vendor, ++ pdev->device, ++ (u8) pdvobjpriv->irqline, ++ 0x02, 0x80, U1DONTCARE, ++ &pcipriv->busnumber, ++ &pcipriv->devnumber, ++ &pcipriv->funcnumber); ++ ++ rtw_find_bridge_info(padapter); ++ ++ if (pcipriv->pcibridge_vendor != PCI_BRIDGE_VENDOR_UNKNOWN) { ++ rtw_get_link_control_field(padapter, ++ pcipriv->pcibridge_busnum, ++ pcipriv->pcibridge_devnum, ++ pcipriv->pcibridge_funcnum); ++ ++ if (pcipriv->pcibridge_vendor == PCI_BRIDGE_VENDOR_AMD) { ++ pcipriv->amd_l1_patch = ++ rtw_get_amd_l1_patch(padapter, ++ pcipriv->pcibridge_busnum, ++ pcipriv->pcibridge_devnum, ++ pcipriv->pcibridge_funcnum); ++ } ++ } ++#endif ++ ++ // ++ // Allow the hardware to look at PCI config information. ++ // ++ rtw_pci_parse_configuration(pdev, dvobj); ++ ++ DBG_871X("pcidev busnumber:devnumber:funcnumber:" ++ "vendor:link_ctl %d:%d:%d:%x:%x\n", ++ pcipriv->busnumber, ++ pcipriv->devnumber, ++ pcipriv->funcnumber, ++ pdev->vendor, ++ pcipriv->linkctrl_reg); ++ ++ DBG_871X("pci_bridge busnumber:devnumber:funcnumber:vendor:" ++ "pcie_cap:link_ctl_reg: %d:%d:%d:%x:%x:%x:%x\n", ++ pcipriv->pcibridge_busnum, ++ pcipriv->pcibridge_devnum, ++ pcipriv->pcibridge_funcnum, ++ pcibridge_vendors[pcipriv->pcibridge_vendor], ++ pcipriv->pcibridge_pciehdr_offset, ++ pcipriv->pcibridge_linkctrlreg, ++ pcipriv->amd_l1_patch); ++ ++ status = _SUCCESS; ++ ++iounmap: ++ if (status != _SUCCESS && dvobj->pci_mem_start != 0) { ++ pci_iounmap(pdev, (void *)dvobj->pci_mem_start); ++ dvobj->pci_mem_start = 0; ++ } ++release_regions: ++ if (status != _SUCCESS) ++ pci_release_regions(pdev); ++disable_picdev: ++ if (status != _SUCCESS) ++ pci_disable_device(pdev); ++free_dvobj: ++ if (status != _SUCCESS && dvobj) { ++ pci_set_drvdata(pdev, NULL); ++ _rtw_mutex_free(&dvobj->hw_init_mutex); ++ _rtw_mutex_free(&dvobj->h2c_fwcmd_mutex); ++ _rtw_mutex_free(&dvobj->setch_mutex); ++ _rtw_mutex_free(&dvobj->setbw_mutex); ++ rtw_mfree((u8*)dvobj, sizeof(*dvobj)); ++ dvobj = NULL; ++ } ++exit: ++_func_exit_; ++ return dvobj; ++} ++ ++ ++static void pci_dvobj_deinit(struct pci_dev *pdev) ++{ ++ struct dvobj_priv *dvobj = pci_get_drvdata(pdev); ++_func_enter_; ++ ++ pci_set_drvdata(pdev, NULL); ++ if (dvobj) { ++ if (dvobj->irq_alloc) { ++ free_irq(pdev->irq, dvobj); ++ dvobj->irq_alloc = 0; ++ } ++ ++ if (dvobj->pci_mem_start != 0) { ++ pci_iounmap(pdev, (void *)dvobj->pci_mem_start); ++ dvobj->pci_mem_start = 0; ++ } ++ ++ _rtw_mutex_free(&dvobj->hw_init_mutex); ++ _rtw_mutex_free(&dvobj->h2c_fwcmd_mutex); ++ _rtw_mutex_free(&dvobj->setch_mutex); ++ _rtw_mutex_free(&dvobj->setbw_mutex); ++ ++ rtw_mfree((u8*)dvobj, sizeof(*dvobj)); ++ } ++ ++ pci_release_regions(pdev); ++ pci_disable_device(pdev); ++ ++_func_exit_; ++} ++ ++ ++static void decide_chip_type_by_pci_device_id(_adapter *padapter, struct pci_dev *pdev) ++{ ++ u16 venderid, deviceid, irqline; ++ u8 revisionid; ++ struct dvobj_priv *pdvobjpriv=adapter_to_dvobj(padapter); ++ ++ ++ venderid = pdev->vendor; ++ deviceid = pdev->device; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) ++ pci_read_config_byte(pdev, PCI_REVISION_ID, &revisionid); // PCI_REVISION_ID 0x08 ++#else ++ revisionid = pdev->revision; ++#endif ++ pci_read_config_word(pdev, PCI_INTERRUPT_LINE, &irqline); // PCI_INTERRUPT_LINE 0x3c ++ pdvobjpriv->irqline = irqline; ++ ++ ++ // ++ // Decide hardware type here. ++ // ++ if( deviceid == HAL_HW_PCI_8185_DEVICE_ID || ++ deviceid == HAL_HW_PCI_8188_DEVICE_ID || ++ deviceid == HAL_HW_PCI_8198_DEVICE_ID) ++ { ++ DBG_871X("Adapter (8185/8185B) is found- VendorID/DeviceID=%x/%x\n", venderid, deviceid); ++ padapter->HardwareType=HARDWARE_TYPE_RTL8185; ++ } ++ else if (deviceid == HAL_HW_PCI_8190_DEVICE_ID || ++ deviceid == HAL_HW_PCI_0045_DEVICE_ID || ++ deviceid == HAL_HW_PCI_0046_DEVICE_ID || ++ deviceid == HAL_HW_PCI_DLINK_DEVICE_ID) ++ { ++ DBG_871X("Adapter(8190 PCI) is found - vendorid/deviceid=%x/%x\n", venderid, deviceid); ++ padapter->HardwareType = HARDWARE_TYPE_RTL8190P; ++ } ++ else if (deviceid == HAL_HW_PCI_8192_DEVICE_ID || ++ deviceid == HAL_HW_PCI_0044_DEVICE_ID || ++ deviceid == HAL_HW_PCI_0047_DEVICE_ID || ++ deviceid == HAL_HW_PCI_8192SE_DEVICE_ID || ++ deviceid == HAL_HW_PCI_8174_DEVICE_ID || ++ deviceid == HAL_HW_PCI_8173_DEVICE_ID || ++ deviceid == HAL_HW_PCI_8172_DEVICE_ID || ++ deviceid == HAL_HW_PCI_8171_DEVICE_ID) ++ { ++ // 8192e and and 8192se may have the same device ID 8192. However, their Revision ++ // ID is different ++ // Added for 92DE. We deferentiate it from SVID,SDID. ++ if( pdev->subsystem_vendor == 0x10EC && pdev->subsystem_device == 0xE020){ ++ padapter->HardwareType = HARDWARE_TYPE_RTL8192DE; ++ DBG_871X("Adapter(8192DE) is found - VendorID/DeviceID/RID=%X/%X/%X\n", venderid, deviceid, revisionid); ++ }else{ ++ switch (revisionid) { ++ case HAL_HW_PCI_REVISION_ID_8192PCIE: ++ DBG_871X("Adapter(8192 PCI-E) is found - vendorid/deviceid=%x/%x\n", venderid, deviceid); ++ padapter->HardwareType = HARDWARE_TYPE_RTL8192E; ++ break; ++ case HAL_HW_PCI_REVISION_ID_8192SE: ++ DBG_871X("Adapter(8192SE) is found - vendorid/deviceid=%x/%x\n", venderid, deviceid); ++ padapter->HardwareType = HARDWARE_TYPE_RTL8192SE; ++ break; ++ default: ++ DBG_871X("Err: Unknown device - vendorid/deviceid=%x/%x\n", venderid, deviceid); ++ padapter->HardwareType = HARDWARE_TYPE_RTL8192SE; ++ break; ++ } ++ } ++ } ++ else if(deviceid==HAL_HW_PCI_8723E_DEVICE_ID ) ++ {//RTL8723E may have the same device ID with RTL8192CET ++ padapter->HardwareType = HARDWARE_TYPE_RTL8723AE; ++ DBG_871X("Adapter(8723 PCI-E) is found - VendorID/DeviceID=%x/%x\n", venderid, deviceid); ++ } ++ else if (deviceid == HAL_HW_PCI_8192CET_DEVICE_ID || ++ deviceid == HAL_HW_PCI_8192CE_DEVICE_ID || ++ deviceid == HAL_HW_PCI_8191CE_DEVICE_ID || ++ deviceid == HAL_HW_PCI_8188CE_DEVICE_ID) ++ { ++ DBG_871X("Adapter(8192C PCI-E) is found - vendorid/deviceid=%x/%x\n", venderid, deviceid); ++ padapter->HardwareType = HARDWARE_TYPE_RTL8192CE; ++ } ++ else if (deviceid == HAL_HW_PCI_8192DE_DEVICE_ID || ++ deviceid == HAL_HW_PCI_002B_DEVICE_ID ){ ++ padapter->HardwareType = HARDWARE_TYPE_RTL8192DE; ++ DBG_871X("Adapter(8192DE) is found - VendorID/DeviceID/RID=%X/%X/%X\n", venderid, deviceid, revisionid); ++ } ++ else if (deviceid == HAL_HW_PCI_8188EE_DEVICE_ID){ ++ padapter->HardwareType = HARDWARE_TYPE_RTL8188EE; ++ padapter->chip_type = RTL8188E; ++ DBG_871X("Adapter(8188EE) is found - VendorID/DeviceID/RID=%X/%X/%X\n", venderid, deviceid, revisionid); ++ } ++ ++ else ++ { ++ DBG_871X("Err: Unknown device - vendorid/deviceid=%x/%x\n", venderid, deviceid); ++ //padapter->HardwareType = HAL_DEFAULT_HARDWARE_TYPE; ++ } ++ ++ ++ padapter->chip_type = NULL_CHIP_TYPE; ++ ++ //TODO: ++#ifdef CONFIG_RTL8192C ++ padapter->chip_type = RTL8188C_8192C; ++ padapter->HardwareType = HARDWARE_TYPE_RTL8192CE; ++#endif ++#ifdef CONFIG_RTL8192D ++ pdvobjpriv->InterfaceNumber = revisionid; ++ ++ padapter->chip_type = RTL8192D; ++ padapter->HardwareType = HARDWARE_TYPE_RTL8192DE; ++#endif ++ ++} ++ ++static void pci_intf_start(_adapter *padapter) ++{ ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("+pci_intf_start\n")); ++ DBG_871X("+pci_intf_start\n"); ++ ++ //Enable hw interrupt ++ rtw_hal_enable_interrupt(padapter); ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("-pci_intf_start\n")); ++ DBG_871X("-pci_intf_start\n"); ++} ++ ++static void pci_intf_stop(_adapter *padapter) ++{ ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("+pci_intf_stop\n")); ++ ++ //Disable hw interrupt ++ if(padapter->bSurpriseRemoved == _FALSE) ++ { ++ //device still exists, so driver can do i/o operation ++ rtw_hal_disable_interrupt(padapter); ++ tasklet_disable(&(padapter->recvpriv.recv_tasklet)); ++ tasklet_disable(&(padapter->recvpriv.irq_prepare_beacon_tasklet)); ++ tasklet_disable(&(padapter->xmitpriv.xmit_tasklet)); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ /* This function only be called at driver removing. disable buddy_adapter too ++ don't disable interrupt of buddy_adapter because it is same as primary. ++ */ ++ if (padapter->pbuddy_adapter){ ++ tasklet_disable(&(padapter->pbuddy_adapter->recvpriv.recv_tasklet)); ++ tasklet_disable(&(padapter->pbuddy_adapter->recvpriv.irq_prepare_beacon_tasklet)); ++ tasklet_disable(&(padapter->pbuddy_adapter->xmitpriv.xmit_tasklet)); ++ } ++#endif ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("pci_intf_stop: SurpriseRemoved==_FALSE\n")); ++ } ++ else ++ { ++ // Clear irq_enabled to prevent handle interrupt function. ++ adapter_to_dvobj(padapter)->irq_enabled = 0; ++ } ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("-pci_intf_stop\n")); ++ ++} ++ ++ ++void rtw_dev_unload(_adapter *padapter) ++{ ++ struct net_device *pnetdev= (struct net_device*)padapter->pnetdev; ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("+rtw_dev_unload\n")); ++ ++ if(padapter->bup == _TRUE) ++ { ++ DBG_871X("+rtw_dev_unload\n"); ++ ++ padapter->bDriverStopped = _TRUE; ++ #ifdef CONFIG_XMIT_ACK ++ if (padapter->xmitpriv.ack_tx) ++ rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_DRV_STOP); ++ #endif ++ ++ //s3. ++ if(padapter->intf_stop) ++ { ++ padapter->intf_stop(padapter); ++ } ++ ++ //s4. ++ rtw_stop_drv_threads(padapter); ++ ++ ++ //s5. ++ if(padapter->bSurpriseRemoved == _FALSE) ++ { ++ DBG_871X("r871x_dev_unload()->rtl871x_hal_deinit()\n"); ++ rtw_hal_deinit(padapter); ++ ++ padapter->bSurpriseRemoved = _TRUE; ++ } ++ ++ padapter->bup = _FALSE; ++ ++ } ++ else ++ { ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("r871x_dev_unload():padapter->bup == _FALSE\n" )); ++ } ++ ++ DBG_871X("-rtw_dev_unload\n"); ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("-rtw_dev_unload\n")); ++ ++} ++ ++static void disable_ht_for_spec_devid(const struct pci_device_id *pdid) ++{ ++#ifdef CONFIG_80211N_HT ++ u16 vid, pid; ++ u32 flags; ++ int i; ++ int num = sizeof(specific_device_id_tbl)/sizeof(struct specific_device_id); ++ ++ for(i=0; ivendor==vid) && (pdid->device==pid) && (flags&SPEC_DEV_ID_DISABLE_HT)) ++ { ++ rtw_ht_enable = 0; ++ rtw_cbw40_enable = 0; ++ rtw_ampdu_enable = 0; ++ } ++ ++ } ++#endif ++} ++ ++#ifdef CONFIG_PM ++static int rtw_suspend(struct pci_dev *pdev, pm_message_t state) ++{ ++ _func_enter_; ++ ++ ++ _func_exit_; ++ return 0; ++} ++ ++static int rtw_resume(struct pci_dev *pdev) ++{ ++ _func_enter_; ++ ++ ++ _func_exit_; ++ ++ return 0; ++} ++#endif ++ ++_adapter *rtw_pci_if1_init(struct dvobj_priv * dvobj, struct pci_dev *pdev, const struct pci_device_id *pdid) ++{ ++ _adapter *padapter = NULL; ++ struct net_device *pnetdev = NULL; ++ int status = _FAIL; ++ ++ if ((padapter = (_adapter *)rtw_zvmalloc(sizeof(*padapter))) == NULL) { ++ goto exit; ++ } ++ padapter->dvobj = dvobj; ++ dvobj->if1 = padapter; ++ ++ padapter->bDriverStopped=_TRUE; ++ ++ dvobj->padapters[dvobj->iface_nums++] = padapter; ++ padapter->iface_id = IFACE_ID0; ++ ++#if defined(CONFIG_CONCURRENT_MODE) || defined(CONFIG_DUALMAC_CONCURRENT) ++ //set adapter_type/iface type for primary padapter ++ padapter->isprimary = _TRUE; ++ padapter->adapter_type = PRIMARY_ADAPTER; ++ #ifndef CONFIG_HWPORT_SWAP ++ padapter->iface_type = IFACE_PORT0; ++ #else ++ padapter->iface_type = IFACE_PORT1; ++ #endif ++#endif ++ ++ #ifndef RTW_DVOBJ_CHIP_HW_TYPE ++ //step 1-1., decide the chip_type via vid/pid ++ padapter->interface_type = RTW_PCIE; ++ decide_chip_type_by_pci_device_id(padapter, pdev); ++ #endif ++ ++ if((pnetdev = rtw_init_netdev(padapter)) == NULL) { ++ goto free_adapter; ++ } ++ ++ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj)); ++ #endif ++ if (dvobj->bdma64) ++ pnetdev->features |= NETIF_F_HIGHDMA; ++ pnetdev->irq = pdev->irq; ++ ++ padapter = rtw_netdev_priv(pnetdev); ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if(rtw_wdev_alloc(padapter, dvobj_to_dev(dvobj)) != 0) { ++ goto free_adapter; ++ } ++#endif //CONFIG_IOCTL_CFG80211 ++ ++ ++ //step 2. hook HalFunc, allocate HalData ++ hal_set_hal_ops(padapter); ++ ++ ++ //step 3. ++ padapter->intf_start=&pci_intf_start; ++ padapter->intf_stop=&pci_intf_stop; ++ ++ ++ //.2 ++ rtw_init_io_priv(padapter, pci_set_intf_ops); ++ ++ //.3 ++ rtw_hal_read_chip_version(padapter); ++ ++ //.4 ++ rtw_hal_chip_configure(padapter); ++ ++ ++ //step 4. read efuse/eeprom data and get mac_addr ++ rtw_hal_read_chip_info(padapter); ++ ++ //step 5. ++ if(rtw_init_drv_sw(padapter) ==_FAIL) { ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("Initialize driver software resource Failed!\n")); ++ goto free_hal_data; ++ } ++ ++ if(rtw_hal_inirp_init(padapter) ==_FAIL) { ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("Initialize PCI desc ring Failed!\n")); ++ goto free_hal_data; ++ } ++ rtw_macaddr_cfg(padapter->eeprompriv.mac_addr); ++ rtw_init_wifidirect_addrs(padapter, padapter->eeprompriv.mac_addr, padapter->eeprompriv.mac_addr); ++ ++ rtw_hal_disable_interrupt(padapter); ++ ++ //step 6. Init pci related configuration ++ rtw_pci_initialize_adapter_common(padapter); ++ ++ DBG_871X("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n" ++ ,padapter->bDriverStopped ++ ,padapter->bSurpriseRemoved ++ ,padapter->bup ++ ,padapter->hw_init_completed ++ ); ++ ++ status = _SUCCESS; ++ ++free_hal_data: ++ if(status != _SUCCESS && padapter->HalData) ++ rtw_mfree(padapter->HalData, sizeof(*(padapter->HalData))); ++ ++free_wdev: ++ if(status != _SUCCESS) { ++ #ifdef CONFIG_IOCTL_CFG80211 ++ rtw_wdev_unregister(padapter->rtw_wdev); ++ rtw_wdev_free(padapter->rtw_wdev); ++ #endif ++ } ++ ++free_adapter: ++ if (status != _SUCCESS) { ++ if (pnetdev) ++ rtw_free_netdev(pnetdev); ++ else if (padapter) ++ rtw_vmfree((u8*)padapter, sizeof(*padapter)); ++ padapter = NULL; ++ } ++exit: ++ return padapter; ++} ++ ++static void rtw_pci_if1_deinit(_adapter *if1) ++{ ++ struct net_device *pnetdev = if1->pnetdev; ++ struct mlme_priv *pmlmepriv= &if1->mlmepriv; ++ ++ // padapter->intf_stop(padapter); ++ ++ if(check_fwstate(pmlmepriv, _FW_LINKED)) ++ rtw_disassoc_cmd(if1, 0, _FALSE); ++ ++#ifdef CONFIG_AP_MODE ++ free_mlme_ap_info(if1); ++ #ifdef CONFIG_HOSTAPD_MLME ++ hostapd_mode_unload(if1); ++ #endif ++#endif ++ ++ if (if1->DriverState != DRIVER_DISAPPEAR) { ++ if(pnetdev) { ++ unregister_netdev(pnetdev); //will call netdev_close() ++ rtw_proc_remove_one(pnetdev); ++ } ++ } ++ ++ rtw_cancel_all_timer(if1); ++#ifdef CONFIG_WOWLAN ++ adapter_to_pwrctl(if1)->wowlan_mode=_FALSE; ++#endif //CONFIG_WOWLAN ++ rtw_dev_unload(if1); ++ ++ DBG_871X("%s, hw_init_completed=%d\n", __func__, if1->hw_init_completed); ++ ++ //s6. ++ rtw_handle_dualmac(if1, 0); ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if(if1->rtw_wdev) ++ { ++ rtw_wdev_unregister(if1->rtw_wdev); ++ rtw_wdev_free(if1->rtw_wdev); ++ } ++#endif //CONFIG_IOCTL_CFG80211 ++ ++ rtw_hal_inirp_deinit(if1); ++ rtw_free_drv_sw(if1); ++ ++ if(pnetdev) ++ rtw_free_netdev(pnetdev); ++ ++#ifdef CONFIG_PLATFORM_RTD2880B ++ DBG_871X("wlan link down\n"); ++ rtd2885_wlan_netlink_sendMsg("linkdown", "8712"); ++#endif ++} ++ ++/* ++ * drv_init() - a device potentially for us ++ * ++ * notes: drv_init() is called when the bus driver has located a card for us to support. ++ * We accept the new device by returning 0. ++*/ ++static int rtw_drv_init(struct pci_dev *pdev, const struct pci_device_id *pdid) ++{ ++ int i, err = -ENODEV; ++ ++ int status; ++ _adapter *if1 = NULL, *if2 = NULL; ++ struct dvobj_priv *dvobj; ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_init\n")); ++ //DBG_871X("+rtw_drv_init\n"); ++ ++ //step 0. ++ disable_ht_for_spec_devid(pdid); ++ ++ /* Initialize dvobj_priv */ ++ if ((dvobj = pci_dvobj_init(pdev)) == NULL) { ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("initialize device object priv Failed!\n")); ++ goto exit; ++ } ++ ++ /* Initialize if1 */ ++ if ((if1 = rtw_pci_if1_init(dvobj, pdev, pdid)) == NULL) { ++ DBG_871X("rtw_pci_if1_init Failed!\n"); ++ goto free_dvobj; ++ } ++ ++ /* Initialize if2 */ ++#ifdef CONFIG_CONCURRENT_MODE ++ if((if2 = rtw_drv_if2_init(if1, pci_set_intf_ops)) == NULL) { ++ goto free_if1; ++ } ++#endif ++ ++ //dev_alloc_name && register_netdev ++ if((status = rtw_drv_register_netdev(if1)) != _SUCCESS) { ++ goto free_if2; ++ } ++ ++#ifdef CONFIG_HOSTAPD_MLME ++ hostapd_mode_init(if1); ++#endif ++ ++#ifdef CONFIG_PLATFORM_RTD2880B ++ DBG_871X("wlan link up\n"); ++ rtd2885_wlan_netlink_sendMsg("linkup", "8712"); ++#endif ++ ++#ifdef RTK_DMP_PLATFORM ++ rtw_proc_init_one(if1->pnetdev); ++#endif ++ ++ /* alloc irq */ ++ if (pci_alloc_irq(dvobj) != _SUCCESS) ++ goto free_if2; ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("-871x_drv - drv_init, success!\n")); ++ //DBG_871X("-871x_drv - drv_init, success!\n"); ++ ++ status = _SUCCESS; ++ ++free_if2: ++ if(status != _SUCCESS && if2) { ++ #ifdef CONFIG_CONCURRENT_MODE ++ rtw_drv_if2_stop(if2); ++ rtw_drv_if2_free(if2); ++ #endif ++ } ++free_if1: ++ if (status != _SUCCESS && if1) { ++ rtw_pci_if1_deinit(if1); ++ } ++free_dvobj: ++ if (status != _SUCCESS) ++ pci_dvobj_deinit(pdev); ++exit: ++ return status == _SUCCESS?0:-ENODEV; ++} ++ ++extern void rtw_unregister_netdevs(struct dvobj_priv *dvobj); ++/* ++ * dev_remove() - our device is being removed ++*/ ++//rmmod module & unplug(SurpriseRemoved) will call r871xu_dev_remove() => how to recognize both ++static void rtw_dev_remove(struct pci_dev *pdev) ++{ ++ struct dvobj_priv *pdvobjpriv = pci_get_drvdata(pdev); ++ _adapter *padapter = pdvobjpriv->if1; ++ struct net_device *pnetdev = padapter->pnetdev; ++ ++_func_exit_; ++ ++ DBG_871X("+rtw_dev_remove\n"); ++ ++ pdvobjpriv->processing_dev_remove = _TRUE; ++ rtw_unregister_netdevs(pdvobjpriv); ++ ++ if (unlikely(!padapter)) { ++ return; ++ } ++ ++ #if 0 ++#ifdef RTK_DMP_PLATFORM ++ padapter->bSurpriseRemoved = _FALSE; // always trate as device exists ++ // this will let the driver to disable it's interrupt ++#else ++ if(pci_drvpriv.drv_registered == _TRUE) ++ { ++ //DBG_871X("r871xu_dev_remove():padapter->bSurpriseRemoved == _TRUE\n"); ++ padapter->bSurpriseRemoved = _TRUE; ++ } ++ /*else ++ { ++ //DBG_871X("r871xu_dev_remove():module removed\n"); ++ padapter->hw_init_completed = _FALSE; ++ }*/ ++#endif ++ #endif ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_ANDROID_POWER) ++ rtw_unregister_early_suspend(dvobj_to_pwrctl(pdvobjpriv)); ++#endif ++ ++ rtw_pm_set_ips(padapter, IPS_NONE); ++ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE); ++ ++ LeaveAllPowerSaveMode(padapter); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ rtw_drv_if2_stop(pdvobjpriv->if2); ++#endif ++ ++ rtw_pci_if1_deinit(padapter); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ rtw_drv_if2_free(pdvobjpriv->if2); ++#endif ++ ++ pci_dvobj_deinit(pdev); ++ ++ DBG_871X("-r871xu_dev_remove, done\n"); ++ ++_func_exit_; ++ return; ++} ++ ++ ++static int __init rtw_drv_entry(void) ++{ ++ int ret = 0; ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("+rtw_drv_entry\n")); ++ DBG_871X("rtw driver version=%s\n", DRIVERVERSION); ++ DBG_871X("Build at: %s %s\n", __DATE__, __TIME__); ++ pci_drvpriv.drv_registered = _TRUE; ++ ++ rtw_suspend_lock_init(); ++ ++ ret = pci_register_driver(&pci_drvpriv.rtw_pci_drv); ++ if (ret) { ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, (": No device found\n")); ++ } ++ ++ return ret; ++} ++ ++static void __exit rtw_drv_halt(void) ++{ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("+rtw_drv_halt\n")); ++ DBG_871X("+rtw_drv_halt\n"); ++ ++ pci_drvpriv.drv_registered = _FALSE; ++ ++ pci_unregister_driver(&pci_drvpriv.rtw_pci_drv); ++ ++ rtw_suspend_lock_uninit(); ++ ++ DBG_871X("-rtw_drv_halt\n"); ++ ++ rtw_mstat_dump(); ++} ++ ++ ++module_init(rtw_drv_entry); ++module_exit(rtw_drv_halt); ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/pci_ops_linux.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/pci_ops_linux.c +new file mode 100644 +index 00000000..12c6c683 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/pci_ops_linux.c +@@ -0,0 +1,24 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ *******************************************************************************/ ++#define _PCI_OPS_LINUX_C_ ++ ++#include ++ ++ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/recv_linux.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/recv_linux.c +new file mode 100644 +index 00000000..bb6de8a9 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/recv_linux.c +@@ -0,0 +1,512 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _RECV_OSDEP_C_ ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#ifdef CONFIG_USB_HCI ++#include ++#endif ++ ++//init os related resource in struct recv_priv ++int rtw_os_recv_resource_init(struct recv_priv *precvpriv, _adapter *padapter) ++{ ++ int res=_SUCCESS; ++ ++ return res; ++} ++ ++//alloc os related resource in union recv_frame ++int rtw_os_recv_resource_alloc(_adapter *padapter, union recv_frame *precvframe) ++{ ++ int res=_SUCCESS; ++ ++ precvframe->u.hdr.pkt_newalloc = precvframe->u.hdr.pkt = NULL; ++ ++ return res; ++ ++} ++ ++//free os related resource in union recv_frame ++void rtw_os_recv_resource_free(struct recv_priv *precvpriv) ++{ ++ sint i; ++ union recv_frame *precvframe; ++ precvframe = (union recv_frame*) precvpriv->precv_frame_buf; ++ ++ for(i=0; i < NR_RECVFRAME; i++) ++ { ++ if(precvframe->u.hdr.pkt) ++ { ++ rtw_skb_free(precvframe->u.hdr.pkt);//free skb by driver ++ precvframe->u.hdr.pkt = NULL; ++ } ++ precvframe++; ++ } ++ ++} ++ ++ ++//alloc os related resource in struct recv_buf ++int rtw_os_recvbuf_resource_alloc(_adapter *padapter, struct recv_buf *precvbuf) ++{ ++ int res=_SUCCESS; ++ ++#ifdef CONFIG_USB_HCI ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct usb_device *pusbd = pdvobjpriv->pusbdev; ++ ++ precvbuf->irp_pending = _FALSE; ++ precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); ++ if(precvbuf->purb == NULL){ ++ res = _FAIL; ++ } ++ ++ precvbuf->pskb = NULL; ++ ++ precvbuf->reuse = _FALSE; ++ ++ precvbuf->pallocated_buf = precvbuf->pbuf = NULL; ++ ++ precvbuf->pdata = precvbuf->phead = precvbuf->ptail = precvbuf->pend = NULL; ++ ++ precvbuf->transfer_len = 0; ++ ++ precvbuf->len = 0; ++ ++ #ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX ++ precvbuf->pallocated_buf = rtw_usb_buffer_alloc(pusbd, (size_t)precvbuf->alloc_sz, &precvbuf->dma_transfer_addr); ++ precvbuf->pbuf = precvbuf->pallocated_buf; ++ if(precvbuf->pallocated_buf == NULL) ++ return _FAIL; ++ #endif //CONFIG_USE_USB_BUFFER_ALLOC_RX ++ ++#endif //CONFIG_USB_HCI ++ ++ return res; ++} ++ ++//free os related resource in struct recv_buf ++int rtw_os_recvbuf_resource_free(_adapter *padapter, struct recv_buf *precvbuf) ++{ ++ int ret = _SUCCESS; ++ ++#ifdef CONFIG_USB_HCI ++ ++#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX ++ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct usb_device *pusbd = pdvobjpriv->pusbdev; ++ ++ rtw_usb_buffer_free(pusbd, (size_t)precvbuf->alloc_sz, precvbuf->pallocated_buf, precvbuf->dma_transfer_addr); ++ precvbuf->pallocated_buf = NULL; ++ precvbuf->dma_transfer_addr = 0; ++ ++#endif //CONFIG_USE_USB_BUFFER_ALLOC_RX ++ ++ if(precvbuf->purb) ++ { ++ //usb_kill_urb(precvbuf->purb); ++ usb_free_urb(precvbuf->purb); ++ } ++ ++#endif //CONFIG_USB_HCI ++ ++ ++ if(precvbuf->pskb) ++ rtw_skb_free(precvbuf->pskb); ++ ++ ++ return ret; ++ ++} ++ ++void rtw_handle_tkip_mic_err(_adapter *padapter,u8 bgroup) ++{ ++#ifdef CONFIG_IOCTL_CFG80211 ++ enum nl80211_key_type key_type; ++#endif ++ union iwreq_data wrqu; ++ struct iw_michaelmicfailure ev; ++ struct mlme_priv* pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ u32 cur_time = 0; ++ ++ if( psecuritypriv->last_mic_err_time == 0 ) ++ { ++ psecuritypriv->last_mic_err_time = rtw_get_current_time(); ++ } ++ else ++ { ++ cur_time = rtw_get_current_time(); ++ ++ if( cur_time - psecuritypriv->last_mic_err_time < 60*HZ ) ++ { ++ psecuritypriv->btkip_countermeasure = _TRUE; ++ psecuritypriv->last_mic_err_time = 0; ++ psecuritypriv->btkip_countermeasure_time = cur_time; ++ } ++ else ++ { ++ psecuritypriv->last_mic_err_time = rtw_get_current_time(); ++ } ++ } ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if ( bgroup ) ++ { ++ key_type |= NL80211_KEYTYPE_GROUP; ++ } ++ else ++ { ++ key_type |= NL80211_KEYTYPE_PAIRWISE; ++ } ++ ++ cfg80211_michael_mic_failure(padapter->pnetdev, (u8 *)&pmlmepriv->assoc_bssid[ 0 ], key_type, -1, ++ NULL, GFP_ATOMIC); ++#endif ++ ++ _rtw_memset( &ev, 0x00, sizeof( ev ) ); ++ if ( bgroup ) ++ { ++ ev.flags |= IW_MICFAILURE_GROUP; ++ } ++ else ++ { ++ ev.flags |= IW_MICFAILURE_PAIRWISE; ++ } ++ ++ ev.src_addr.sa_family = ARPHRD_ETHER; ++ _rtw_memcpy( ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN ); ++ ++ _rtw_memset( &wrqu, 0x00, sizeof( wrqu ) ); ++ wrqu.data.length = sizeof( ev ); ++ ++#ifndef CONFIG_IOCTL_CFG80211 ++ wireless_send_event( padapter->pnetdev, IWEVMICHAELMICFAILURE, &wrqu, (char*) &ev ); ++#endif ++} ++ ++void rtw_hostapd_mlme_rx(_adapter *padapter, union recv_frame *precv_frame) ++{ ++#ifdef CONFIG_HOSTAPD_MLME ++ _pkt *skb; ++ struct hostapd_priv *phostapdpriv = padapter->phostapdpriv; ++ struct net_device *pmgnt_netdev = phostapdpriv->pmgnt_netdev; ++ ++ RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("+rtw_hostapd_mlme_rx\n")); ++ ++ skb = precv_frame->u.hdr.pkt; ++ ++ if (skb == NULL) ++ return; ++ ++ skb->data = precv_frame->u.hdr.rx_data; ++ skb->tail = precv_frame->u.hdr.rx_tail; ++ skb->len = precv_frame->u.hdr.len; ++ ++ //pskb_copy = rtw_skb_copy(skb); ++// if(skb == NULL) goto _exit; ++ ++ skb->dev = pmgnt_netdev; ++ skb->ip_summed = CHECKSUM_NONE; ++ skb->pkt_type = PACKET_OTHERHOST; ++ //skb->protocol = __constant_htons(0x0019); /*ETH_P_80211_RAW*/ ++ skb->protocol = __constant_htons(0x0003); /*ETH_P_80211_RAW*/ ++ ++ //DBG_871X("(1)data=0x%x, head=0x%x, tail=0x%x, mac_header=0x%x, len=%d\n", skb->data, skb->head, skb->tail, skb->mac_header, skb->len); ++ ++ //skb->mac.raw = skb->data; ++ skb_reset_mac_header(skb); ++ ++ //skb_pull(skb, 24); ++ _rtw_memset(skb->cb, 0, sizeof(skb->cb)); ++ ++ rtw_netif_rx(pmgnt_netdev, skb); ++ ++ precv_frame->u.hdr.pkt = NULL; // set pointer to NULL before rtw_free_recvframe() if call rtw_netif_rx() ++#endif ++} ++ ++int rtw_recv_indicatepkt(_adapter *padapter, union recv_frame *precv_frame) ++{ ++ struct recv_priv *precvpriv; ++ _queue *pfree_recv_queue; ++ _pkt *skb; ++ struct mlme_priv*pmlmepriv = &padapter->mlmepriv; ++#ifdef CONFIG_TCP_CSUM_OFFLOAD_RX ++ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; ++#endif ++ ++#ifdef CONFIG_BR_EXT ++ void *br_port = NULL; ++#endif ++ ++_func_enter_; ++ ++ precvpriv = &(padapter->recvpriv); ++ pfree_recv_queue = &(precvpriv->free_recv_queue); ++ ++#ifdef CONFIG_DRVEXT_MODULE ++ if (drvext_rx_handler(padapter, precv_frame->u.hdr.rx_data, precv_frame->u.hdr.len) == _SUCCESS) ++ { ++ goto _recv_indicatepkt_drop; ++ } ++#endif ++ ++#ifdef CONFIG_WAPI_SUPPORT ++ if (rtw_wapi_check_for_drop(padapter,precv_frame)) ++ { ++ WAPI_TRACE(WAPI_ERR, "%s(): Rx Reorder Drop case!!\n", __FUNCTION__); ++ goto _recv_indicatepkt_drop; ++ } ++#endif ++ ++ skb = precv_frame->u.hdr.pkt; ++ if(skb == NULL) ++ { ++ RT_TRACE(_module_recv_osdep_c_,_drv_err_,("rtw_recv_indicatepkt():skb==NULL something wrong!!!!\n")); ++ goto _recv_indicatepkt_drop; ++ } ++ ++ RT_TRACE(_module_recv_osdep_c_,_drv_info_,("rtw_recv_indicatepkt():skb != NULL !!!\n")); ++ RT_TRACE(_module_recv_osdep_c_,_drv_info_,("rtw_recv_indicatepkt():precv_frame->u.hdr.rx_head=%p precv_frame->hdr.rx_data=%p\n", precv_frame->u.hdr.rx_head, precv_frame->u.hdr.rx_data)); ++ RT_TRACE(_module_recv_osdep_c_,_drv_info_,("precv_frame->hdr.rx_tail=%p precv_frame->u.hdr.rx_end=%p precv_frame->hdr.len=%d \n", precv_frame->u.hdr.rx_tail, precv_frame->u.hdr.rx_end, precv_frame->u.hdr.len)); ++ ++ skb->data = precv_frame->u.hdr.rx_data; ++ ++ skb_set_tail_pointer(skb, precv_frame->u.hdr.len); ++ ++ skb->len = precv_frame->u.hdr.len; ++ ++ RT_TRACE(_module_recv_osdep_c_,_drv_info_,("\n skb->head=%p skb->data=%p skb->tail=%p skb->end=%p skb->len=%d\n", skb->head, skb->data, skb->tail, skb->end, skb->len)); ++ ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) ++ { ++ _pkt *pskb2=NULL; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; ++ int bmcast = IS_MCAST(pattrib->dst); ++ ++ //DBG_871X("bmcast=%d\n", bmcast); ++ ++ if(_rtw_memcmp(pattrib->dst, myid(&padapter->eeprompriv), ETH_ALEN)==_FALSE) ++ { ++ //DBG_871X("not ap psta=%p, addr=%pM\n", psta, pattrib->dst); ++ ++ if(bmcast) ++ { ++ psta = rtw_get_bcmc_stainfo(padapter); ++ pskb2 = rtw_skb_clone(skb); ++ } else { ++ psta = rtw_get_stainfo(pstapriv, pattrib->dst); ++ } ++ ++ if(psta) ++ { ++ struct net_device *pnetdev= (struct net_device*)padapter->pnetdev; ++ ++ //DBG_871X("directly forwarding to the rtw_xmit_entry\n"); ++ ++ //skb->ip_summed = CHECKSUM_NONE; ++ skb->dev = pnetdev; ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)) ++ skb_set_queue_mapping(skb, rtw_recv_select_queue(skb)); ++#endif //LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35) ++ ++ _rtw_xmit_entry(skb, pnetdev); ++ ++ if(bmcast) ++ skb = pskb2; ++ else ++ goto _recv_indicatepkt_end; ++ } ++ ++ ++ } ++ else// to APself ++ { ++ //DBG_871X("to APSelf\n"); ++ } ++ } ++ ++ ++#ifdef CONFIG_BR_EXT ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ br_port = padapter->pnetdev->br_port; ++#else // (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ rcu_read_lock(); ++ br_port = rcu_dereference(padapter->pnetdev->rx_handler_data); ++ rcu_read_unlock(); ++#endif // (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ ++ if( br_port && (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) == _TRUE) ) ++ { ++ int nat25_handle_frame(_adapter *priv, struct sk_buff *skb); ++ if (nat25_handle_frame(padapter, skb) == -1) { ++ //priv->ext_stats.rx_data_drops++; ++ //DEBUG_ERR("RX DROP: nat25_handle_frame fail!\n"); ++ //return FAIL; ++#if 1 ++ // bypass this frame to upper layer!! ++#else ++ goto _recv_indicatepkt_drop; ++#endif ++ } ++ } ++ ++#endif // CONFIG_BR_EXT ++ ++ ++#ifdef CONFIG_TCP_CSUM_OFFLOAD_RX ++ if ( (pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1) ) { ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ //DBG_871X("CHECKSUM_UNNECESSARY \n"); ++ } else { ++ skb->ip_summed = CHECKSUM_NONE; ++ //DBG_871X("CHECKSUM_NONE(%d, %d) \n", pattrib->tcpchk_valid, pattrib->tcp_chkrpt); ++ } ++#else /* !CONFIG_TCP_CSUM_OFFLOAD_RX */ ++ ++ skb->ip_summed = CHECKSUM_NONE; ++ ++#endif ++ ++ skb->dev = padapter->pnetdev; ++ skb->protocol = eth_type_trans(skb, padapter->pnetdev); ++ ++ #ifdef DBG_TRX_STA_PKTS ++ { ++ ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; ++ int bmcast = IS_MCAST(pattrib->dst); ++ ++ if(bmcast) ++ { ++ psta = rtw_get_bcmc_stainfo(padapter); ++ ++ } else { ++ psta = rtw_get_stainfo(pstapriv, pattrib->src); ++ } ++ if(psta) ++ { ++ switch(pattrib->priority) ++ { ++ case 1: ++ case 2: ++ psta->rx_bk_cnt++; ++ break; ++ case 4: ++ case 5: ++ psta->rx_vi_cnt++; ++ break; ++ case 6: ++ case 7: ++ psta->rx_vo_cnt++; ++ break; ++ case 0: ++ case 3: ++ default: ++ psta->rx_be_cnt++; ++ break; ++ } ++ } ++ } ++ #endif ++ ++ rtw_netif_rx(padapter->pnetdev, skb); ++ ++_recv_indicatepkt_end: ++ ++ precv_frame->u.hdr.pkt = NULL; // pointers to NULL before rtw_free_recvframe() ++ ++ rtw_free_recvframe(precv_frame, pfree_recv_queue); ++ ++ RT_TRACE(_module_recv_osdep_c_,_drv_info_,("\n rtw_recv_indicatepkt :after rtw_netif_rx!!!!\n")); ++ ++_func_exit_; ++ ++ return _SUCCESS; ++ ++_recv_indicatepkt_drop: ++ ++ //enqueue back to free_recv_queue ++ if(precv_frame) ++ rtw_free_recvframe(precv_frame, pfree_recv_queue); ++ ++ return _FAIL; ++ ++_func_exit_; ++ ++} ++ ++void rtw_os_read_port(_adapter *padapter, struct recv_buf *precvbuf) ++{ ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++#ifdef CONFIG_USB_HCI ++ ++ precvbuf->ref_cnt--; ++ ++ //free skb in recv_buf ++ rtw_skb_free(precvbuf->pskb); ++ ++ precvbuf->pskb = NULL; ++ precvbuf->reuse = _FALSE; ++ ++ if(precvbuf->irp_pending == _FALSE) ++ { ++ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf); ++ } ++ ++ ++#endif ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ precvbuf->pskb = NULL; ++#endif ++ ++} ++void _rtw_reordering_ctrl_timeout_handler (void *FunctionContext); ++void _rtw_reordering_ctrl_timeout_handler (void *FunctionContext) ++{ ++ struct recv_reorder_ctrl *preorder_ctrl = (struct recv_reorder_ctrl *)FunctionContext; ++ rtw_reordering_ctrl_timeout_handler(preorder_ctrl); ++} ++ ++void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl) ++{ ++ _adapter *padapter = preorder_ctrl->padapter; ++ ++ _init_timer(&(preorder_ctrl->reordering_ctrl_timer), padapter->pnetdev, _rtw_reordering_ctrl_timeout_handler, preorder_ctrl); ++ ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/rtw_android.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/rtw_android.c +new file mode 100644 +index 00000000..201aead2 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/rtw_android.c +@@ -0,0 +1,844 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_GPIO_WAKEUP ++#include ++#endif ++ ++#include ++ ++#if defined(RTW_ENABLE_WIFI_CONTROL_FUNC) ++#include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) ++#include ++#else ++#include ++#endif ++#endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */ ++ ++#ifdef CONFIG_GPIO_WAKEUP ++#include ++#include ++#endif ++ ++const char *android_wifi_cmd_str[ANDROID_WIFI_CMD_MAX] = { ++ "START", ++ "STOP", ++ "SCAN-ACTIVE", ++ "SCAN-PASSIVE", ++ "RSSI", ++ "LINKSPEED", ++ "RXFILTER-START", ++ "RXFILTER-STOP", ++ "RXFILTER-ADD", ++ "RXFILTER-REMOVE", ++ "BTCOEXSCAN-START", ++ "BTCOEXSCAN-STOP", ++ "BTCOEXMODE", ++ "SETSUSPENDOPT", ++ "P2P_DEV_ADDR", ++ "SETFWPATH", ++ "SETBAND", ++ "GETBAND", ++ "COUNTRY", ++ "P2P_SET_NOA", ++ "P2P_GET_NOA", ++ "P2P_SET_PS", ++ "SET_AP_WPS_P2P_IE", ++#ifdef PNO_SUPPORT ++ "PNOSSIDCLR", ++ "PNOSETUP ", ++ "PNOFORCE", ++ "PNODEBUG", ++#endif ++ ++ "MACADDR", ++ ++ "BLOCK", ++ "WFD-ENABLE", ++ "WFD-DISABLE", ++ "WFD-SET-TCPPORT", ++ "WFD-SET-MAXTPUT", ++ "WFD-SET-DEVTYPE", ++}; ++ ++#ifdef PNO_SUPPORT ++#define PNO_TLV_PREFIX 'S' ++#define PNO_TLV_VERSION '1' ++#define PNO_TLV_SUBVERSION '2' ++#define PNO_TLV_RESERVED '0' ++#define PNO_TLV_TYPE_SSID_IE 'S' ++#define PNO_TLV_TYPE_TIME 'T' ++#define PNO_TLV_FREQ_REPEAT 'R' ++#define PNO_TLV_FREQ_EXPO_MAX 'M' ++ ++typedef struct cmd_tlv { ++ char prefix; ++ char version; ++ char subver; ++ char reserved; ++} cmd_tlv_t; ++#endif /* PNO_SUPPORT */ ++ ++typedef struct android_wifi_priv_cmd { ++ ++#ifdef CONFIG_COMPAT ++ compat_uptr_t buf; ++#else ++ char *buf; ++#endif ++ ++ int used_len; ++ int total_len; ++} android_wifi_priv_cmd; ++ ++/** ++ * Local (static) functions and variables ++ */ ++ ++/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first ++ * time (only) in dhd_open, subsequential wifi on will be handled by ++ * wl_android_wifi_on ++ */ ++static int g_wifi_on = _TRUE; ++ ++unsigned int oob_irq; ++ ++#ifdef PNO_SUPPORT ++static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len) ++{ ++ wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; ++ int res = -1; ++ int nssid = 0; ++ cmd_tlv_t *cmd_tlv_temp; ++ char *str_ptr; ++ int tlv_size_left; ++ int pno_time = 0; ++ int pno_repeat = 0; ++ int pno_freq_expo_max = 0; ++ ++#ifdef PNO_SET_DEBUG ++ int i; ++ char pno_in_example[] = { ++ 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ', ++ 'S', '1', '2', '0', ++ 'S', ++ 0x05, ++ 'd', 'l', 'i', 'n', 'k', ++ 'S', ++ 0x04, ++ 'G', 'O', 'O', 'G', ++ 'T', ++ '0', 'B', ++ 'R', ++ '2', ++ 'M', ++ '2', ++ 0x00 ++ }; ++#endif /* PNO_SET_DEBUG */ ++ ++ DHD_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); ++ ++ if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) { ++ DBG_871X("%s argument=%d less min size\n", __FUNCTION__, total_len); ++ goto exit_proc; ++ } ++ ++#ifdef PNO_SET_DEBUG ++ memcpy(command, pno_in_example, sizeof(pno_in_example)); ++ for (i = 0; i < sizeof(pno_in_example); i++) ++ printf("%02X ", command[i]); ++ printf("\n"); ++ total_len = sizeof(pno_in_example); ++#endif ++ ++ str_ptr = command + strlen(CMD_PNOSETUP_SET); ++ tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET); ++ ++ cmd_tlv_temp = (cmd_tlv_t *)str_ptr; ++ memset(ssids_local, 0, sizeof(ssids_local)); ++ ++ if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && ++ (cmd_tlv_temp->version == PNO_TLV_VERSION) && ++ (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) { ++ ++ str_ptr += sizeof(cmd_tlv_t); ++ tlv_size_left -= sizeof(cmd_tlv_t); ++ ++ if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, ++ MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) { ++ DBG_871X("SSID is not presented or corrupted ret=%d\n", nssid); ++ goto exit_proc; ++ } else { ++ if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) { ++ DBG_871X("%s scan duration corrupted field size %d\n", ++ __FUNCTION__, tlv_size_left); ++ goto exit_proc; ++ } ++ str_ptr++; ++ pno_time = simple_strtoul(str_ptr, &str_ptr, 16); ++ DHD_INFO(("%s: pno_time=%d\n", __FUNCTION__, pno_time)); ++ ++ if (str_ptr[0] != 0) { ++ if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) { ++ DBG_871X("%s pno repeat : corrupted field\n", ++ __FUNCTION__); ++ goto exit_proc; ++ } ++ str_ptr++; ++ pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16); ++ DHD_INFO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat)); ++ if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) { ++ DBG_871X("%s FREQ_EXPO_MAX corrupted field size\n", ++ __FUNCTION__); ++ goto exit_proc; ++ } ++ str_ptr++; ++ pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16); ++ DHD_INFO(("%s: pno_freq_expo_max=%d\n", ++ __FUNCTION__, pno_freq_expo_max)); ++ } ++ } ++ } else { ++ DBG_871X("%s get wrong TLV command\n", __FUNCTION__); ++ goto exit_proc; ++ } ++ ++ res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max); ++ ++exit_proc: ++ return res; ++} ++#endif /* PNO_SUPPORT */ ++ ++int rtw_android_cmdstr_to_num(char *cmdstr) ++{ ++ int cmd_num; ++ for(cmd_num=0 ; cmd_nummlmepriv); ++ struct wlan_network *pcur_network = &pmlmepriv->cur_network; ++ int bytes_written = 0; ++ ++ if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { ++ bytes_written += snprintf(&command[bytes_written], total_len, "%s rssi %d", ++ pcur_network->network.Ssid.Ssid, padapter->recvpriv.rssi); ++ } ++ ++ return bytes_written; ++} ++ ++int rtw_android_get_link_speed(struct net_device *net, char *command, int total_len) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(net); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct wlan_network *pcur_network = &pmlmepriv->cur_network; ++ int bytes_written = 0; ++ u16 link_speed = 0; ++ ++ link_speed = rtw_get_cur_max_rate(padapter)/10; ++ bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed); ++ ++ return bytes_written; ++} ++ ++int rtw_android_get_macaddr(struct net_device *net, char *command, int total_len) ++{ ++ _adapter *adapter = (_adapter *)rtw_netdev_priv(net); ++ int bytes_written = 0; ++ ++ bytes_written = snprintf(command, total_len, "Macaddr = "MAC_FMT, MAC_ARG(net->dev_addr)); ++ return bytes_written; ++} ++ ++int rtw_android_set_country(struct net_device *net, char *command, int total_len) ++{ ++ _adapter *adapter = (_adapter *)rtw_netdev_priv(net); ++ char *country_code = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_COUNTRY]) + 1; ++ int ret = _FAIL; ++ ++ ret = rtw_set_country(adapter, country_code); ++ ++ return (ret==_SUCCESS)?0:-1; ++} ++ ++int rtw_android_get_p2p_dev_addr(struct net_device *net, char *command, int total_len) ++{ ++ int bytes_written = 0; ++ ++ //We use the same address as our HW MAC address ++ _rtw_memcpy(command, net->dev_addr, ETH_ALEN); ++ ++ bytes_written = ETH_ALEN; ++ return bytes_written; ++} ++ ++int rtw_android_set_block(struct net_device *net, char *command, int total_len) ++{ ++ _adapter *adapter = (_adapter *)rtw_netdev_priv(net); ++ char *block_value = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_BLOCK]) + 1; ++ ++ #ifdef CONFIG_IOCTL_CFG80211 ++ wdev_to_priv(adapter->rtw_wdev)->block = (*block_value=='0')?_FALSE:_TRUE; ++ #endif ++ ++ return 0; ++} ++ ++int get_int_from_command( char* pcmd ) ++{ ++ int i = 0; ++ ++ for( i = 0; i < strlen( pcmd ); i++ ) ++ { ++ if ( pcmd[ i ] == '=' ) ++ { ++ // Skip the '=' and space characters. ++ i += 2; ++ break; ++ } ++ } ++ return ( rtw_atoi( pcmd + i ) ); ++} ++ ++int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) ++{ ++ int ret = 0; ++ char *command = NULL; ++ int cmd_num; ++ int bytes_written = 0; ++ android_wifi_priv_cmd priv_cmd; ++ _adapter* padapter = ( _adapter * ) rtw_netdev_priv(net); ++#ifdef CONFIG_WFD ++ struct wifi_display_info *pwfd_info; ++#endif ++ ++ rtw_lock_suspend(); ++ ++ if (!ifr->ifr_data) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) { ++ ret = -EFAULT; ++ goto exit; ++ } ++ ++ //DBG_871X("%s priv_cmd.buf=%p priv_cmd.total_len=%d priv_cmd.used_len=%d\n",__func__,priv_cmd.buf,priv_cmd.total_len,priv_cmd.used_len); ++ command = rtw_zmalloc(priv_cmd.total_len); ++ if (!command) ++ { ++ DBG_871X("%s: failed to allocate memory\n", __FUNCTION__); ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ++ if (!access_ok(VERIFY_READ, priv_cmd.buf, priv_cmd.total_len)){ ++ DBG_871X("%s: failed to access memory\n", __FUNCTION__); ++ ret = -EFAULT; ++ goto exit; ++ } ++ if (copy_from_user(command, (void *)priv_cmd.buf, priv_cmd.total_len)) { ++ ret = -EFAULT; ++ goto exit; ++ } ++ ++ DBG_871X("%s: Android private cmd \"%s\" on %s\n" ++ , __FUNCTION__, command, ifr->ifr_name); ++ ++ cmd_num = rtw_android_cmdstr_to_num(command); ++ ++ switch(cmd_num) { ++ case ANDROID_WIFI_CMD_START: ++ //bytes_written = wl_android_wifi_on(net); ++ goto response; ++ case ANDROID_WIFI_CMD_SETFWPATH: ++ goto response; ++ } ++ ++ if (!g_wifi_on) { ++ DBG_871X("%s: Ignore private cmd \"%s\" - iface %s is down\n" ++ ,__FUNCTION__, command, ifr->ifr_name); ++ ret = 0; ++ goto exit; ++ } ++ ++ switch(cmd_num) { ++ ++ case ANDROID_WIFI_CMD_STOP: ++ //bytes_written = wl_android_wifi_off(net); ++ break; ++ ++ case ANDROID_WIFI_CMD_SCAN_ACTIVE: ++ //rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_ACTIVE); ++#ifdef CONFIG_PLATFORM_MSTAR ++#ifdef CONFIG_IOCTL_CFG80211 ++ (wdev_to_priv(net->ieee80211_ptr))->bandroid_scan = _TRUE; ++#endif //CONFIG_IOCTL_CFG80211 ++#endif //CONFIG_PLATFORM_MSTAR ++ break; ++ case ANDROID_WIFI_CMD_SCAN_PASSIVE: ++ //rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_PASSIVE); ++ break; ++ ++ case ANDROID_WIFI_CMD_RSSI: ++ bytes_written = rtw_android_get_rssi(net, command, priv_cmd.total_len); ++ break; ++ case ANDROID_WIFI_CMD_LINKSPEED: ++ bytes_written = rtw_android_get_link_speed(net, command, priv_cmd.total_len); ++ break; ++ ++ case ANDROID_WIFI_CMD_MACADDR: ++ bytes_written = rtw_android_get_macaddr(net, command, priv_cmd.total_len); ++ break; ++ ++ case ANDROID_WIFI_CMD_BLOCK: ++ bytes_written = rtw_android_set_block(net, command, priv_cmd.total_len); ++ break; ++ ++ case ANDROID_WIFI_CMD_RXFILTER_START: ++ //bytes_written = net_os_set_packet_filter(net, 1); ++ break; ++ case ANDROID_WIFI_CMD_RXFILTER_STOP: ++ //bytes_written = net_os_set_packet_filter(net, 0); ++ break; ++ case ANDROID_WIFI_CMD_RXFILTER_ADD: ++ //int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0'; ++ //bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num); ++ break; ++ case ANDROID_WIFI_CMD_RXFILTER_REMOVE: ++ //int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0'; ++ //bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num); ++ break; ++ ++ case ANDROID_WIFI_CMD_BTCOEXSCAN_START: ++ /* TBD: BTCOEXSCAN-START */ ++ break; ++ case ANDROID_WIFI_CMD_BTCOEXSCAN_STOP: ++ /* TBD: BTCOEXSCAN-STOP */ ++ break; ++ case ANDROID_WIFI_CMD_BTCOEXMODE: ++ #if 0 ++ uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0'; ++ if (mode == 1) ++ net_os_set_packet_filter(net, 0); /* DHCP starts */ ++ else ++ net_os_set_packet_filter(net, 1); /* DHCP ends */ ++#ifdef WL_CFG80211 ++ bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command); ++#endif ++ #endif ++ break; ++ ++ case ANDROID_WIFI_CMD_SETSUSPENDOPT: ++ //bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len); ++ break; ++ ++ case ANDROID_WIFI_CMD_SETBAND: ++ { ++ uint band = *(command + strlen("SETBAND") + 1) - '0'; ++ _adapter* padapter = ( _adapter * ) rtw_netdev_priv(net); ++ ++ if (padapter->chip_type == RTL8192D) ++ padapter->setband = band; ++ ++ break; ++ } ++ case ANDROID_WIFI_CMD_GETBAND: ++ //bytes_written = wl_android_get_band(net, command, priv_cmd.total_len); ++ break; ++ ++ case ANDROID_WIFI_CMD_COUNTRY: ++ bytes_written = rtw_android_set_country(net, command, priv_cmd.total_len); ++ break; ++ ++#ifdef PNO_SUPPORT ++ case ANDROID_WIFI_CMD_PNOSSIDCLR_SET: ++ //bytes_written = dhd_dev_pno_reset(net); ++ break; ++ case ANDROID_WIFI_CMD_PNOSETUP_SET: ++ //bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len); ++ break; ++ case ANDROID_WIFI_CMD_PNOENABLE_SET: ++ //uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0'; ++ //bytes_written = dhd_dev_pno_enable(net, pfn_enabled); ++ break; ++#endif ++ ++ case ANDROID_WIFI_CMD_P2P_DEV_ADDR: ++ bytes_written = rtw_android_get_p2p_dev_addr(net, command, priv_cmd.total_len); ++ break; ++ case ANDROID_WIFI_CMD_P2P_SET_NOA: ++ //int skip = strlen(CMD_P2P_SET_NOA) + 1; ++ //bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, priv_cmd.total_len - skip); ++ break; ++ case ANDROID_WIFI_CMD_P2P_GET_NOA: ++ //bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len); ++ break; ++ case ANDROID_WIFI_CMD_P2P_SET_PS: ++ //int skip = strlen(CMD_P2P_SET_PS) + 1; ++ //bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, priv_cmd.total_len - skip); ++ break; ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ case ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE: ++ { ++ int skip = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE]) + 3; ++ bytes_written = rtw_cfg80211_set_mgnt_wpsp2pie(net, command + skip, priv_cmd.total_len - skip, *(command + skip - 2) - '0'); ++ break; ++ } ++#endif //CONFIG_IOCTL_CFG80211 ++ ++#ifdef CONFIG_WFD ++ case ANDROID_WIFI_CMD_WFD_ENABLE: ++ { ++ // Commented by Albert 2012/07/24 ++ // We can enable the WFD function by using the following command: ++ // wpa_cli driver wfd-enable ++ ++ pwfd_info = &padapter->wfd_info; ++ if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 ) ++ pwfd_info->wfd_enable = _TRUE; ++ break; ++ } ++ ++ case ANDROID_WIFI_CMD_WFD_DISABLE: ++ { ++ // Commented by Albert 2012/07/24 ++ // We can disable the WFD function by using the following command: ++ // wpa_cli driver wfd-disable ++ ++ pwfd_info = &padapter->wfd_info; ++ if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 ) ++ pwfd_info->wfd_enable = _FALSE; ++ break; ++ } ++ case ANDROID_WIFI_CMD_WFD_SET_TCPPORT: ++ { ++ // Commented by Albert 2012/07/24 ++ // We can set the tcp port number by using the following command: ++ // wpa_cli driver wfd-set-tcpport = 554 ++ ++ pwfd_info = &padapter->wfd_info; ++ if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 ) ++ pwfd_info->rtsp_ctrlport = ( u16 ) get_int_from_command( priv_cmd.buf ); ++ break; ++ } ++ case ANDROID_WIFI_CMD_WFD_SET_MAX_TPUT: ++ { ++ break; ++ } ++ case ANDROID_WIFI_CMD_WFD_SET_DEVTYPE: ++ { ++ // Commented by Albert 2012/08/28 ++ // Specify the WFD device type ( WFD source/primary sink ) ++ ++ struct wifi_display_info *pwfd_info; ++ _adapter* padapter = ( _adapter * ) rtw_netdev_priv(net); ++ ++ pwfd_info = &padapter->wfd_info; ++ if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 ) ++ { ++ pwfd_info->wfd_device_type = ( u8 ) get_int_from_command( priv_cmd.buf ); ++ ++ pwfd_info->wfd_device_type &= WFD_DEVINFO_DUAL; ++ } ++ break; ++ } ++#endif ++ default: ++ DBG_871X("Unknown PRIVATE command %s - ignored\n", command); ++ snprintf(command, 3, "OK"); ++ bytes_written = strlen("OK"); ++ } ++ ++response: ++ if (bytes_written >= 0) { ++ if ((bytes_written == 0) && (priv_cmd.total_len > 0)) ++ command[0] = '\0'; ++ if (bytes_written >= priv_cmd.total_len) { ++ DBG_871X("%s: bytes_written = %d\n", __FUNCTION__, bytes_written); ++ bytes_written = priv_cmd.total_len; ++ } else { ++ bytes_written++; ++ } ++ priv_cmd.used_len = bytes_written; ++ if (copy_to_user((void *)priv_cmd.buf, command, bytes_written)) { ++ DBG_871X("%s: failed to copy data to user buffer\n", __FUNCTION__); ++ ret = -EFAULT; ++ } ++ } ++ else { ++ ret = bytes_written; ++ } ++ ++exit: ++ rtw_unlock_suspend(); ++ if (command) { ++ rtw_mfree(command, priv_cmd.total_len); ++ } ++ ++ return ret; ++} ++ ++ ++/** ++ * Functions for Android WiFi card detection ++ */ ++#if defined(RTW_ENABLE_WIFI_CONTROL_FUNC) ++ ++static int g_wifidev_registered = 0; ++static struct semaphore wifi_control_sem; ++static struct wifi_platform_data *wifi_control_data = NULL; ++static struct resource *wifi_irqres = NULL; ++ ++static int wifi_add_dev(void); ++static void wifi_del_dev(void); ++ ++int rtw_android_wifictrl_func_add(void) ++{ ++ int ret = 0; ++ sema_init(&wifi_control_sem, 0); ++ ++ ret = wifi_add_dev(); ++ if (ret) { ++ DBG_871X("%s: platform_driver_register failed\n", __FUNCTION__); ++ return ret; ++ } ++ g_wifidev_registered = 1; ++ ++ /* Waiting callback after platform_driver_register is done or exit with error */ ++ if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) { ++ ret = -EINVAL; ++ DBG_871X("%s: platform_driver_register timeout\n", __FUNCTION__); ++ } ++ ++ return ret; ++} ++ ++void rtw_android_wifictrl_func_del(void) ++{ ++ if (g_wifidev_registered) ++ { ++ wifi_del_dev(); ++ g_wifidev_registered = 0; ++ } ++} ++ ++void *wl_android_prealloc(int section, unsigned long size) ++{ ++ void *alloc_ptr = NULL; ++ if (wifi_control_data && wifi_control_data->mem_prealloc) { ++ alloc_ptr = wifi_control_data->mem_prealloc(section, size); ++ if (alloc_ptr) { ++ DBG_871X("success alloc section %d\n", section); ++ if (size != 0L) ++ memset(alloc_ptr, 0, size); ++ return alloc_ptr; ++ } ++ } ++ ++ DBG_871X("can't alloc section %d\n", section); ++ return NULL; ++} ++ ++int wifi_get_irq_number(unsigned long *irq_flags_ptr) ++{ ++ if (wifi_irqres) { ++ *irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK; ++ return (int)wifi_irqres->start; ++ } ++#ifdef CUSTOM_OOB_GPIO_NUM ++ return CUSTOM_OOB_GPIO_NUM; ++#else ++ return -1; ++#endif ++} ++ ++int wifi_set_power(int on, unsigned long msec) ++{ ++ DBG_871X("%s = %d\n", __FUNCTION__, on); ++ if (wifi_control_data && wifi_control_data->set_power) { ++ wifi_control_data->set_power(on); ++ } ++ if (msec) ++ msleep(msec); ++ return 0; ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) ++int wifi_get_mac_addr(unsigned char *buf) ++{ ++ DBG_871X("%s\n", __FUNCTION__); ++ if (!buf) ++ return -EINVAL; ++ if (wifi_control_data && wifi_control_data->get_mac_addr) { ++ return wifi_control_data->get_mac_addr(buf); ++ } ++ return -EOPNOTSUPP; ++} ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) || defined(COMPAT_KERNEL_RELEASE) ++void *wifi_get_country_code(char *ccode) ++{ ++ DBG_871X("%s\n", __FUNCTION__); ++ if (!ccode) ++ return NULL; ++ if (wifi_control_data && wifi_control_data->get_country_code) { ++ return wifi_control_data->get_country_code(ccode); ++ } ++ return NULL; ++} ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ ++ ++static int wifi_set_carddetect(int on) ++{ ++ DBG_871X("%s = %d\n", __FUNCTION__, on); ++ if (wifi_control_data && wifi_control_data->set_carddetect) { ++ wifi_control_data->set_carddetect(on); ++ } ++ return 0; ++} ++ ++static int wifi_probe(struct platform_device *pdev) ++{ ++ struct wifi_platform_data *wifi_ctrl = ++ (struct wifi_platform_data *)(pdev->dev.platform_data); ++ int wifi_wake_gpio = 0; ++ ++ DBG_871X("## %s\n", __FUNCTION__); ++ wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq"); ++ ++ if (wifi_irqres == NULL) ++ wifi_irqres = platform_get_resource_byname(pdev, ++ IORESOURCE_IRQ, "bcm4329_wlan_irq"); ++ else ++ wifi_wake_gpio = wifi_irqres->start; ++ ++#ifdef CONFIG_GPIO_WAKEUP ++ printk("%s: gpio:%d wifi_wake_gpio:%d\n", __func__, ++ wifi_irqres->start, wifi_wake_gpio); ++ ++ if (wifi_wake_gpio > 0) { ++ gpio_request(wifi_wake_gpio, "oob_irq"); ++ gpio_direction_input(wifi_wake_gpio); ++ oob_irq = gpio_to_irq(wifi_wake_gpio); ++ printk("%s oob_irq:%d\n", __func__, oob_irq); ++ } ++#endif ++ wifi_control_data = wifi_ctrl; ++ ++ wifi_set_power(1, 0); /* Power On */ ++ wifi_set_carddetect(1); /* CardDetect (0->1) */ ++ ++ up(&wifi_control_sem); ++ return 0; ++} ++ ++static int wifi_remove(struct platform_device *pdev) ++{ ++ struct wifi_platform_data *wifi_ctrl = ++ (struct wifi_platform_data *)(pdev->dev.platform_data); ++ ++ DBG_871X("## %s\n", __FUNCTION__); ++ wifi_control_data = wifi_ctrl; ++ ++ wifi_set_power(0, 0); /* Power Off */ ++ wifi_set_carddetect(0); /* CardDetect (1->0) */ ++ ++ up(&wifi_control_sem); ++ return 0; ++} ++ ++static int wifi_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ DBG_871X("##> %s\n", __FUNCTION__); ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) ++ bcmsdh_oob_intr_set(0); ++#endif ++ return 0; ++} ++ ++static int wifi_resume(struct platform_device *pdev) ++{ ++ DBG_871X("##> %s\n", __FUNCTION__); ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) ++ if (dhd_os_check_if_up(bcmsdh_get_drvdata())) ++ bcmsdh_oob_intr_set(1); ++#endif ++ return 0; ++} ++ ++/* temporarily use these two */ ++static struct platform_driver wifi_device = { ++ .probe = wifi_probe, ++ .remove = wifi_remove, ++ .suspend = wifi_suspend, ++ .resume = wifi_resume, ++ .driver = { ++ .name = "bcmdhd_wlan", ++ } ++}; ++ ++static struct platform_driver wifi_device_legacy = { ++ .probe = wifi_probe, ++ .remove = wifi_remove, ++ .suspend = wifi_suspend, ++ .resume = wifi_resume, ++ .driver = { ++ .name = "bcm4329_wlan", ++ } ++}; ++ ++static int wifi_add_dev(void) ++{ ++ DBG_871X("## Calling platform_driver_register\n"); ++ platform_driver_register(&wifi_device); ++ platform_driver_register(&wifi_device_legacy); ++ return 0; ++} ++ ++static void wifi_del_dev(void) ++{ ++ DBG_871X("## Unregister platform_driver_register\n"); ++ platform_driver_unregister(&wifi_device); ++ platform_driver_unregister(&wifi_device_legacy); ++} ++#endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/sdio_intf.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/sdio_intf.c +new file mode 100644 +index 00000000..d6a4698e +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/sdio_intf.c +@@ -0,0 +1,1972 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _HCI_INTF_C_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef CONFIG_SDIO_HCI ++#error "CONFIG_SDIO_HCI shall be on!\n" ++#endif ++ ++#include ++#include ++ ++#if defined(CONFIG_WOWLAN) || defined(CONFIG_PLATFORM_SPRD) ++#include ++#include ++#endif ++ ++#ifdef CONFIG_PLATFORM_SPRD ++#include ++#endif // CONFIG_PLATFORM_SPRD ++ ++#include ++#include ++#include ++ ++#include ++ ++#ifdef CONFIG_PLATFORM_SPRD ++#ifdef CONFIG_PM_RUNTIME ++#include ++#endif ++#endif ++ ++#ifdef CONFIG_PLATFORM_ARM_SUNxI ++#if defined(CONFIG_MMC_SUNXI_POWER_CONTROL) ++ ++#ifdef CONFIG_WITS_EVB_V13 ++#define SDIOID 0 ++#else ++#define SDIOID (CONFIG_CHIP_ID==1123 ? 3 : 1) ++#endif ++ ++#define SUNXI_SDIO_WIFI_NUM_RTL8189ES 10 ++extern void sunximmc_rescan_card(unsigned id, unsigned insert); ++extern int mmc_pm_get_mod_type(void); ++extern int mmc_pm_gpio_ctrl(char* name, int level); ++/* ++* rtl8189es_shdn = port:PH09<1><0> ++* rtl8189es_wakeup = port:PH10<1><1> ++* rtl8189es_vdd_en = port:PH11<1><0> ++* rtl8189es_vcc_en = port:PH12<1><0> ++*/ ++ ++int rtl8189es_sdio_powerup(void) ++{ ++ mmc_pm_gpio_ctrl("rtl8189es_vdd_en", 1); ++ udelay(100); ++ mmc_pm_gpio_ctrl("rtl8189es_vcc_en", 1); ++ udelay(50); ++ mmc_pm_gpio_ctrl("rtl8189es_shdn", 1); ++ return 0; ++} ++int rtl8189es_sdio_poweroff(void) ++{ ++ mmc_pm_gpio_ctrl("rtl8189es_shdn", 0); ++ mmc_pm_gpio_ctrl("rtl8189es_vcc_en", 0); ++ mmc_pm_gpio_ctrl("rtl8189es_vdd_en", 0); ++ return 0; ++} ++#endif //defined(CONFIG_MMC_SUNXI_POWER_CONTROL) ++#endif //CONFIG_PLATFORM_ARM_SUNxI ++ ++#if defined(CONFIG_PLATFORM_ARM_SUN6I) || defined(CONFIG_PLATFORM_ARM_SUN7I) ++#ifdef CONFIG_MMC ++#include ++static unsigned sdc_id = 0; ++extern void sw_mci_rescan_card(unsigned id, unsigned insert); ++extern int wifi_pm_get_mod_type(void); ++extern void wifi_pm_power(int on); ++#endif //CONFIG_MMC ++#endif //#if defined(CONFIG_PLATFORM_ARM_SUN6I) || defined(CONFIG_PLATFORM_ARM_SUN7I) ++ ++#ifndef dev_to_sdio_func ++#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) ++#endif ++ ++#ifdef CONFIG_WOWLAN ++static struct mmc_host *mmc_host = NULL; ++#endif ++ ++static const struct sdio_device_id sdio_ids[] = { ++#ifdef CONFIG_RTL8723A ++ { SDIO_DEVICE(0x024c, 0x8723) }, ++#endif //CONFIG_RTL8723A ++ ++#ifdef CONFIG_RTL8188E ++ { SDIO_DEVICE(0x024c, 0x8179) }, ++#endif //CONFIG_RTL8188E ++ ++#if defined(RTW_ENABLE_WIFI_CONTROL_FUNC) /* temporarily add this to accept all sdio wlan id */ ++ { SDIO_DEVICE_CLASS(SDIO_CLASS_WLAN) }, ++#endif ++// { /* end: all zeroes */ }, ++}; ++ ++static int rtw_drv_init(struct sdio_func *func, const struct sdio_device_id *id); ++static void rtw_dev_remove(struct sdio_func *func); ++static int rtw_sdio_resume(struct device *dev); ++static int rtw_sdio_suspend(struct device *dev); ++#ifdef CONFIG_PM_RUNTIME ++static void rtw_start_runtime(struct sdio_func *func); ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) ++static const struct dev_pm_ops rtw_sdio_pm_ops = { ++ .suspend = rtw_sdio_suspend, ++ .resume = rtw_sdio_resume, ++}; ++#endif ++ ++struct sdio_drv_priv { ++ struct sdio_driver r871xs_drv; ++ int drv_registered; ++}; ++ ++static struct sdio_drv_priv sdio_drvpriv = { ++ .r871xs_drv.probe = rtw_drv_init, ++ .r871xs_drv.remove = rtw_dev_remove, ++ .r871xs_drv.name = (char*)DRV_NAME, ++ .r871xs_drv.id_table = sdio_ids, ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) ++ .r871xs_drv.drv = { ++ .pm = &rtw_sdio_pm_ops, ++ } ++ #endif ++}; ++ ++static void sd_sync_int_hdl(struct sdio_func *func) ++{ ++ struct dvobj_priv *psdpriv; ++ ++ ++ psdpriv = sdio_get_drvdata(func); ++ ++ if (!psdpriv->if1) { ++ DBG_871X("%s if1 == NULL\n", __func__); ++ return; ++ } ++ ++ rtw_sdio_set_irq_thd(psdpriv, current); ++ sd_int_hdl(psdpriv->if1); ++ rtw_sdio_set_irq_thd(psdpriv, NULL); ++} ++ ++int sdio_alloc_irq(struct dvobj_priv *dvobj) ++{ ++ PSDIO_DATA psdio_data; ++ struct sdio_func *func; ++ int err; ++ ++ psdio_data = &dvobj->intf_data; ++ func = psdio_data->func; ++ ++ sdio_claim_host(func); ++ ++ err = sdio_claim_irq(func, &sd_sync_int_hdl); ++ if (err) ++ printk(KERN_CRIT "%s: sdio_claim_irq FAIL(%d)!\n", __func__, err); ++ else ++ dvobj->irq_alloc = 1; ++ ++ sdio_release_host(func); ++ ++ return err?_FAIL:_SUCCESS; ++} ++ ++void sdio_free_irq(struct dvobj_priv *dvobj) ++{ ++ PSDIO_DATA psdio_data; ++ struct sdio_func *func; ++ int err; ++ ++ if (dvobj->irq_alloc) { ++ psdio_data = &dvobj->intf_data; ++ func = psdio_data->func; ++ ++ if (func) { ++ sdio_claim_host(func); ++ err = sdio_release_irq(func); ++ if (err) ++ DBG_871X_LEVEL(_drv_err_,"%s: sdio_release_irq FAIL(%d)!\n", __func__, err); ++ sdio_release_host(func); ++ } ++ dvobj->irq_alloc = 0; ++ } ++} ++ ++#ifdef CONFIG_GPIO_WAKEUP ++extern unsigned int oob_irq; ++static irqreturn_t gpio_hostwakeup_irq_thread(int irq, void *data) ++{ ++ PADAPTER padapter = (PADAPTER)data; ++ DBG_871X_LEVEL(_drv_always_, "gpio_hostwakeup_irq_thread\n"); ++ /* Disable interrupt before calling handler */ ++ //disable_irq_nosync(oob_irq); ++ rtw_lock_suspend_timeout(HZ/2); ++ return IRQ_HANDLED; ++} ++ ++static u8 gpio_hostwakeup_alloc_irq(PADAPTER padapter) ++{ ++ int err; ++ if (oob_irq == 0) ++ return _FAIL; ++ /* dont set it IRQF_TRIGGER_LOW, or wowlan */ ++ /* power is high after suspend */ ++ /* and failing can prevent can not sleep issue if */ ++ /* wifi gpio12 pin is not linked with CPU */ ++ err = request_threaded_irq(oob_irq, gpio_hostwakeup_irq_thread, NULL, ++ //IRQF_TRIGGER_LOW | IRQF_ONESHOT, ++ IRQF_TRIGGER_FALLING, ++ "rtw_wifi_gpio_wakeup", padapter); ++ if (err < 0) { ++ DBG_871X("Oops: can't allocate gpio irq %d err:%d\n", oob_irq, err); ++ return _FALSE; ++ } else { ++ DBG_871X("allocate gpio irq %d ok\n", oob_irq); ++} ++ ++ enable_irq_wake(oob_irq); ++ return _SUCCESS; ++} ++ ++static void gpio_hostwakeup_free_irq(PADAPTER padapter) ++{ ++ if (oob_irq == 0) ++ return; ++ disable_irq_wake(oob_irq); ++ free_irq(oob_irq, padapter); ++} ++#endif ++ ++static u32 sdio_init(struct dvobj_priv *dvobj) ++{ ++ PSDIO_DATA psdio_data; ++ struct sdio_func *func; ++ int err; ++ ++_func_enter_; ++ ++ psdio_data = &dvobj->intf_data; ++ func = psdio_data->func; ++ ++ //3 1. init SDIO bus ++ sdio_claim_host(func); ++ ++ err = sdio_enable_func(func); ++ if (err) { ++ DBG_8192C(KERN_CRIT "%s: sdio_enable_func FAIL(%d)!\n", __func__, err); ++ goto release; ++ } ++ ++ err = sdio_set_block_size(func, 512); ++ if (err) { ++ DBG_8192C(KERN_CRIT "%s: sdio_set_block_size FAIL(%d)!\n", __func__, err); ++ goto release; ++ } ++ psdio_data->block_transfer_len = 512; ++ psdio_data->tx_block_mode = 1; ++ psdio_data->rx_block_mode = 1; ++ ++release: ++ sdio_release_host(func); ++ ++exit: ++_func_exit_; ++ ++ if (err) return _FAIL; ++ return _SUCCESS; ++} ++ ++static void sdio_deinit(struct dvobj_priv *dvobj) ++{ ++ struct sdio_func *func; ++ int err; ++ ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+sdio_deinit\n")); ++ ++ func = dvobj->intf_data.func; ++ ++ if (func) { ++ sdio_claim_host(func); ++ err = sdio_disable_func(func); ++ if (err) ++ DBG_8192C(KERN_ERR "%s: sdio_disable_func(%d)\n", __func__, err); ++ ++ if (dvobj->irq_alloc) { ++ err = sdio_release_irq(func); ++ if (err) ++ DBG_8192C(KERN_ERR "%s: sdio_release_irq(%d)\n", __func__, err); ++ } ++ ++ sdio_release_host(func); ++ } ++} ++static struct dvobj_priv *sdio_dvobj_init(struct sdio_func *func) ++{ ++ int status = _FAIL; ++ struct dvobj_priv *dvobj = NULL; ++ PSDIO_DATA psdio; ++_func_enter_; ++ ++ if ((dvobj = (struct dvobj_priv*)rtw_zmalloc(sizeof(*dvobj))) == NULL) { ++ goto exit; ++ } ++ ++ _rtw_mutex_init(&dvobj->hw_init_mutex); ++ _rtw_mutex_init(&dvobj->h2c_fwcmd_mutex); ++ _rtw_mutex_init(&dvobj->setch_mutex); ++ _rtw_mutex_init(&dvobj->setbw_mutex); ++ ++ sdio_set_drvdata(func, dvobj); ++ dvobj->processing_dev_remove = _FALSE; ++ ++#ifdef CONFIG_WOWLAN ++ sdio_claim_host(func); ++ mmc_host = func->card->host; ++ sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); ++ sdio_release_host(func); ++#endif ++ ++ psdio = &dvobj->intf_data; ++ psdio->func = func; ++ ++ if (sdio_init(dvobj) != _SUCCESS) { ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: initialize SDIO Failed!\n", __FUNCTION__)); ++ goto free_dvobj; ++ } ++ rtw_reset_continual_io_error(dvobj); ++ status = _SUCCESS; ++ ++free_dvobj: ++ if (status != _SUCCESS && dvobj) { ++ sdio_set_drvdata(func, NULL); ++ _rtw_mutex_free(&dvobj->hw_init_mutex); ++ _rtw_mutex_free(&dvobj->h2c_fwcmd_mutex); ++ _rtw_mutex_free(&dvobj->setch_mutex); ++ _rtw_mutex_free(&dvobj->setbw_mutex); ++ rtw_mfree((u8*)dvobj, sizeof(*dvobj)); ++ dvobj = NULL; ++ } ++exit: ++_func_exit_; ++ return dvobj; ++} ++ ++static void sdio_dvobj_deinit(struct sdio_func *func) ++{ ++ struct dvobj_priv *dvobj = sdio_get_drvdata(func); ++_func_enter_; ++ ++ sdio_set_drvdata(func, NULL); ++ if (dvobj) { ++ sdio_deinit(dvobj); ++ _rtw_mutex_free(&dvobj->hw_init_mutex); ++ _rtw_mutex_free(&dvobj->h2c_fwcmd_mutex); ++ _rtw_mutex_free(&dvobj->setch_mutex); ++ _rtw_mutex_free(&dvobj->setbw_mutex); ++ rtw_mfree((u8*)dvobj, sizeof(*dvobj)); ++ } ++ ++_func_exit_; ++ return; ++} ++static void decide_chip_type_by_device_id(PADAPTER padapter, u32 id) ++{ ++ padapter->chip_type = NULL_CHIP_TYPE; ++ ++#if 0 ++ switch (id) ++ { ++ case 0x8723: ++ padapter->chip_type = RTL8723A; ++ padapter->HardwareType = HARDWARE_TYPE_RTL8723AS; ++ break; ++ case 0x8179: ++ padapter->chip_type = RTL8188E; ++ padapter->HardwareType = HARDWARE_TYPE_RTL8188ES; ++ break; ++ } ++#else ++#if defined(CONFIG_RTL8723A) ++ padapter->chip_type = RTL8723A; ++ padapter->HardwareType = HARDWARE_TYPE_RTL8723AS; ++#elif defined(CONFIG_RTL8188E) ++ padapter->chip_type = RTL8188E; ++ padapter->HardwareType = HARDWARE_TYPE_RTL8188ES; ++#endif ++#endif ++} ++ ++static void sd_intf_start(PADAPTER padapter) ++{ ++ if (padapter == NULL) { ++ DBG_8192C(KERN_ERR "%s: padapter is NULL!\n", __func__); ++ return; ++ } ++ ++ // hal dep ++ rtw_hal_enable_interrupt(padapter); ++} ++ ++static void sd_intf_stop(PADAPTER padapter) ++{ ++ if (padapter == NULL) { ++ DBG_8192C(KERN_ERR "%s: padapter is NULL!\n", __func__); ++ return; ++ } ++ ++ // hal dep ++ rtw_hal_disable_interrupt(padapter); ++} ++ ++/* ++ * Do deinit job corresponding to netdev_open() ++ */ ++void rtw_dev_unload(PADAPTER padapter) ++{ ++ struct net_device *pnetdev = (struct net_device*)padapter->pnetdev; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+rtw_dev_unload\n")); ++ ++ padapter->bDriverStopped = _TRUE; ++ #ifdef CONFIG_XMIT_ACK ++ if (padapter->xmitpriv.ack_tx) ++ rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_DRV_STOP); ++ #endif ++ ++ if (padapter->bup == _TRUE) ++ { ++ // stop TX ++// val8 = 0xFF; ++// rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE,&val8); ++ ++#if 0 ++ if (padapter->intf_stop) ++ padapter->intf_stop(padapter); ++#else ++ sd_intf_stop(padapter); ++#endif ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("@ rtw_dev_unload: stop intf complete!\n")); ++ ++ if (!pwrctl->bInternalAutoSuspend) ++ rtw_stop_drv_threads(padapter); ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("@ rtw_dev_unload: stop thread complete!\n")); ++ ++ if (padapter->bSurpriseRemoved == _FALSE) ++ { ++#ifdef CONFIG_WOWLAN ++ if (pwrctl->bSupportRemoteWakeup == _TRUE && ++ pwrctl->wowlan_mode ==_TRUE) { ++ DBG_871X_LEVEL(_drv_always_, "%s bSupportRemoteWakeup==_TRUE do not run rtw_hal_deinit()\n",__FUNCTION__); ++ } ++ else ++#endif ++ { ++ //amy modify 20120221 for power seq is different between driver open and ips ++ rtw_hal_deinit(padapter); ++ } ++ padapter->bSurpriseRemoved = _TRUE; ++ } ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("@ rtw_dev_unload: deinit hal complelt!\n")); ++ ++ padapter->bup = _FALSE; ++ } ++ else { ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("rtw_dev_unload: bup==_FALSE\n")); ++ } ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("-rtw_dev_unload\n")); ++} ++ ++_adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct sdio_device_id *pdid) ++{ ++ int status = _FAIL; ++ struct net_device *pnetdev; ++ PADAPTER padapter = NULL; ++ ++ if ((padapter = (_adapter *)rtw_zvmalloc(sizeof(*padapter))) == NULL) { ++ goto exit; ++ } ++ padapter->dvobj = dvobj; ++ dvobj->if1 = padapter; ++ ++ padapter->bDriverStopped=_TRUE; ++ ++ dvobj->padapters[dvobj->iface_nums++] = padapter; ++ padapter->iface_id = IFACE_ID0; ++ ++#if defined(CONFIG_CONCURRENT_MODE) || defined(CONFIG_DUALMAC_CONCURRENT) ++ //set adapter_type/iface type for primary padapter ++ padapter->isprimary = _TRUE; ++ padapter->adapter_type = PRIMARY_ADAPTER; ++ #ifndef CONFIG_HWPORT_SWAP ++ padapter->iface_type = IFACE_PORT0; ++ #else ++ padapter->iface_type = IFACE_PORT1; ++ #endif ++#endif ++ ++ padapter->interface_type = RTW_SDIO; ++ decide_chip_type_by_device_id(padapter, (u32)pdid->device); ++ ++ //3 1. init network device data ++ pnetdev = rtw_init_netdev(padapter); ++ if (!pnetdev) ++ goto free_adapter; ++ ++ SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj)); ++ ++ padapter = rtw_netdev_priv(pnetdev); ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ rtw_wdev_alloc(padapter, dvobj_to_dev(dvobj)); ++#endif ++ ++ //3 3. init driver special setting, interface, OS and hardware relative ++ ++ //4 3.1 set hardware operation functions ++ hal_set_hal_ops(padapter); ++ ++ ++ //3 5. initialize Chip version ++ padapter->intf_start = &sd_intf_start; ++ padapter->intf_stop = &sd_intf_stop; ++ ++ if (rtw_init_io_priv(padapter, sdio_set_intf_ops) == _FAIL) ++ { ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ++ ("rtw_drv_init: Can't init io_priv\n")); ++ goto free_hal_data; ++ } ++ ++ rtw_hal_read_chip_version(padapter); ++ ++ rtw_hal_chip_configure(padapter); ++ ++ ++ //3 6. read efuse/eeprom data ++ rtw_hal_read_chip_info(padapter); ++ ++ //3 7. init driver common data ++ if (rtw_init_drv_sw(padapter) == _FAIL) { ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ++ ("rtw_drv_init: Initialize driver software resource Failed!\n")); ++ goto free_hal_data; ++ } ++ ++ //3 8. get WLan MAC address ++ // set mac addr ++ rtw_macaddr_cfg(padapter->eeprompriv.mac_addr); ++#ifdef CONFIG_P2P ++ rtw_init_wifidirect_addrs(padapter, padapter->eeprompriv.mac_addr, padapter->eeprompriv.mac_addr); ++#endif ++ rtw_hal_disable_interrupt(padapter); ++ ++ DBG_871X("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n" ++ ,padapter->bDriverStopped ++ ,padapter->bSurpriseRemoved ++ ,padapter->bup ++ ,padapter->hw_init_completed ++ ); ++ ++ status = _SUCCESS; ++ ++free_hal_data: ++ if(status != _SUCCESS && padapter->HalData) ++ rtw_mfree(padapter->HalData, sizeof(*(padapter->HalData))); ++ ++free_wdev: ++ if(status != _SUCCESS) { ++ #ifdef CONFIG_IOCTL_CFG80211 ++ rtw_wdev_unregister(padapter->rtw_wdev); ++ rtw_wdev_free(padapter->rtw_wdev); ++ #endif ++ } ++ ++free_adapter: ++ if (status != _SUCCESS) { ++ if (pnetdev) ++ rtw_free_netdev(pnetdev); ++ else if (padapter) ++ rtw_vmfree((u8*)padapter, sizeof(*padapter)); ++ padapter = NULL; ++ } ++exit: ++ return padapter; ++} ++ ++static void rtw_sdio_if1_deinit(_adapter *if1) ++{ ++ struct net_device *pnetdev = if1->pnetdev; ++ struct mlme_priv *pmlmepriv= &if1->mlmepriv; ++ ++ if(check_fwstate(pmlmepriv, _FW_LINKED)) ++ rtw_disassoc_cmd(if1, 0, _FALSE); ++ ++#ifdef CONFIG_AP_MODE ++ free_mlme_ap_info(if1); ++ #ifdef CONFIG_HOSTAPD_MLME ++ hostapd_mode_unload(if1); ++ #endif ++#endif ++ ++#ifdef CONFIG_GPIO_WAKEUP ++ gpio_hostwakeup_free_irq(if1); ++#endif ++/* ++ if(if1->DriverState != DRIVER_DISAPPEAR) { ++ if(pnetdev) { ++ unregister_netdev(pnetdev); //will call netdev_close() ++ rtw_proc_remove_one(pnetdev); ++ } ++ } ++*/ ++ rtw_cancel_all_timer(if1); ++ ++#ifdef CONFIG_WOWLAN ++ adapter_to_pwrctl(if1)->wowlan_mode=_FALSE; ++ DBG_871X_LEVEL(_drv_always_, "%s wowlan_mode:%d\n", __func__, adapter_to_pwrctl(if1)->wowlan_mode); ++#endif //CONFIG_WOWLAN ++ ++ rtw_dev_unload(if1); ++ DBG_871X("+r871xu_dev_remove, hw_init_completed=%d\n", if1->hw_init_completed); ++ ++ rtw_handle_dualmac(if1, 0); ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if (if1->rtw_wdev) ++ { ++ //rtw_wdev_unregister(if1->rtw_wdev); ++ rtw_wdev_free(if1->rtw_wdev); ++ } ++#endif ++ ++ rtw_free_drv_sw(if1); ++ ++ if(pnetdev) ++ rtw_free_netdev(pnetdev); ++ ++#ifdef CONFIG_PLATFORM_RTD2880B ++ DBG_871X("wlan link down\n"); ++ rtd2885_wlan_netlink_sendMsg("linkdown", "8712"); ++#endif ++ ++} ++ ++#ifdef CONFIG_PLATFORM_SPRD ++#ifdef CONFIG_PM_RUNTIME ++#include ++static void rtw_start_runtime(struct sdio_func *func) ++{ ++ unsigned long flags; ++ struct mmc_card *card = func->card; ++ struct mmc_host *host = card->host; ++ ++ DBG_871X("%s \n", __func__); ++ ++ pm_runtime_no_callbacks(&func->dev); ++ pm_suspend_ignore_children(&func->dev, true); ++ pm_runtime_set_autosuspend_delay(&func->dev, 50); ++ pm_runtime_use_autosuspend(&func->dev); ++ pm_runtime_put_autosuspend(&func->dev); ++} ++#endif ++#endif ++ ++/* ++ * drv_init() - a device potentially for us ++ * ++ * notes: drv_init() is called when the bus driver has located a card for us to support. ++ * We accept the new device by returning 0. ++ */ ++static int rtw_drv_init( ++ struct sdio_func *func, ++ const struct sdio_device_id *id) ++{ ++ int status = _FAIL; ++ struct net_device *pnetdev; ++ PADAPTER if1 = NULL, if2 = NULL; ++ struct dvobj_priv *dvobj; ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_info_, ++ ("+rtw_drv_init: vendor=0x%04x device=0x%04x class=0x%02x\n", ++ func->vendor, func->device, func->class)); ++ ++ if ((dvobj = sdio_dvobj_init(func)) == NULL) { ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("initialize device object priv Failed!\n")); ++ goto exit; ++ } ++ ++ if ((if1 = rtw_sdio_if1_init(dvobj, id)) == NULL) { ++ DBG_871X("rtw_init_primary_adapter Failed!\n"); ++ goto free_dvobj; ++ } ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if ((if2 = rtw_drv_if2_init(if1, sdio_set_intf_ops)) == NULL) { ++ goto free_if1; ++ } ++#endif ++ ++ //dev_alloc_name && register_netdev ++ if((status = rtw_drv_register_netdev(if1)) != _SUCCESS) { ++ goto free_if2; ++ } ++ ++#ifdef CONFIG_HOSTAPD_MLME ++ hostapd_mode_init(if1); ++#endif ++ ++#ifdef CONFIG_PLATFORM_RTD2880B ++ DBG_871X("wlan link up\n"); ++ rtd2885_wlan_netlink_sendMsg("linkup", "8712"); ++#endif ++ ++#ifdef RTK_DMP_PLATFORM ++ rtw_proc_init_one(if1->pnetdev); ++#endif ++ ++ if (sdio_alloc_irq(dvobj) != _SUCCESS) ++ goto free_if2; ++ ++#ifdef CONFIG_GPIO_WAKEUP ++ gpio_hostwakeup_alloc_irq(if1); ++#endif ++ ++#ifdef CONFIG_GLOBAL_UI_PID ++ if(ui_pid[1]!=0) { ++ DBG_871X("ui_pid[1]:%d\n",ui_pid[1]); ++ rtw_signal_process(ui_pid[1], SIGUSR2); ++ } ++#endif ++ ++#ifdef CONFIG_PLATFORM_SPRD ++#ifdef CONFIG_PM_RUNTIME ++ rtw_start_runtime(func); ++#endif ++#endif ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("-871x_drv - drv_init, success!\n")); ++ ++ status = _SUCCESS; ++ ++free_if2: ++ if(status != _SUCCESS && if2) { ++ #ifdef CONFIG_CONCURRENT_MODE ++ rtw_drv_if2_stop(if2); ++ rtw_drv_if2_free(if2); ++ #endif ++ } ++free_if1: ++ if (status != _SUCCESS && if1) { ++ rtw_sdio_if1_deinit(if1); ++ } ++free_dvobj: ++ if (status != _SUCCESS) ++ sdio_dvobj_deinit(func); ++exit: ++ return status == _SUCCESS?0:-ENODEV; ++} ++extern void rtw_unregister_netdevs(struct dvobj_priv *dvobj); ++static void rtw_dev_remove(struct sdio_func *func) ++{ ++ struct dvobj_priv *dvobj = sdio_get_drvdata(func); ++ PADAPTER padapter = dvobj->if1; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+rtw_dev_remove\n")); ++ ++ dvobj->processing_dev_remove = _TRUE; ++ rtw_unregister_netdevs(dvobj); ++ ++ if (padapter->bSurpriseRemoved == _FALSE) { ++ int err; ++ ++ /* test surprise remove */ ++ sdio_claim_host(func); ++ sdio_readb(func, 0, &err); ++ sdio_release_host(func); ++ if (err == -ENOMEDIUM) { ++ padapter->bSurpriseRemoved = _TRUE; ++ DBG_871X(KERN_NOTICE "%s: device had been removed!\n", __func__); ++ } ++ } ++#ifdef CONFIG_MP_INCLUDED ++ if (padapter->registrypriv.mp_mode == 1) ++ MPT_DeInitAdapter(padapter); ++#endif ++#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_ANDROID_POWER) ++ rtw_unregister_early_suspend(dvobj_to_pwrctl(dvobj)); ++#endif ++ ++ rtw_pm_set_ips(padapter, IPS_NONE); ++ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE); ++ ++ LeaveAllPowerSaveMode(padapter); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ rtw_drv_if2_stop(dvobj->if2); ++#endif ++ ++ rtw_sdio_if1_deinit(padapter); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ rtw_drv_if2_free(dvobj->if2); ++#endif ++ ++ sdio_dvobj_deinit(func); ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("-rtw_dev_remove\n")); ++ ++_func_exit_; ++} ++ ++#if 1 ++ ++#ifdef CONFIG_WOWLAN ++static int rtw_suspend_wow(_adapter *padapter) ++{ ++ _adapter *pbuddy_adapter = padapter->pbuddy_adapter; ++ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct net_device *pnetdev = padapter->pnetdev; ++ struct wifidirect_info* pwdinfo = &padapter->wdinfo; ++ int ret = 0; ++ ++ struct wowlan_ioctl_param poidparam; ++ u8 ps_mode; ++ ++ _func_enter_; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) ++ pwrpriv->wowlan_mode = _TRUE; ++ else ++ pwrpriv->wowlan_mode = _FALSE; ++ ++ rtw_cancel_all_timer(padapter); ++ ++ if (pwrpriv->wowlan_mode == _TRUE) { ++ // 1. stop thread ++ padapter->bDriverStopped = _TRUE; //for stop thread ++ rtw_stop_drv_threads(padapter); ++ padapter->bDriverStopped = _FALSE; //for 32k command ++#ifdef CONFIG_POWER_SAVING ++ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0); ++#endif ++ // 2. disable interrupt ++ rtw_hal_disable_interrupt(padapter); // It need wait for leaving 32K. ++ ++ // 2.1 clean interupt ++ if (padapter->HalFunc.clear_interrupt) ++ padapter->HalFunc.clear_interrupt(padapter); ++ ++ // 2.2 free irq ++ sdio_free_irq(adapter_to_dvobj(padapter)); ++ } ++ else { ++ LeaveAllPowerSaveMode(padapter); ++ } ++ ++ if(pnetdev){ ++ if(pwrpriv->wowlan_mode == _TRUE) { ++ rtw_netif_stop_queue(pnetdev); ++ } else { ++ netif_carrier_off(pnetdev); ++ rtw_netif_stop_queue(pnetdev); ++ } ++ } ++ ++ DBG_871X("wowlan_mode: %d\n", pwrpriv->wowlan_mode); ++ ++ if ((pwrpriv->bSupportRemoteWakeup == _TRUE) && ++ (pwrpriv->wowlan_mode == _TRUE)) { ++ poidparam.subcode = WOWLAN_ENABLE; ++ padapter->HalFunc.SetHwRegHandler(padapter,HW_VAR_WOWLAN,(u8 *)&poidparam); ++ } else { ++ //s2-1. issue rtw_disassoc_cmd to fw ++ rtw_disassoc_cmd(padapter, 0, _FALSE); ++ } ++ ++ ++#ifdef CONFIG_LAYER2_ROAMING_RESUME ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED) && rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) ) ++ { ++ DBG_871X("%s %s(" MAC_FMT "), length:%d assoc_ssid.length:%d\n",__FUNCTION__, ++ pmlmepriv->cur_network.network.Ssid.Ssid, ++ MAC_ARG(pmlmepriv->cur_network.network.MacAddress), ++ pmlmepriv->cur_network.network.Ssid.SsidLength, ++ pmlmepriv->assoc_ssid.SsidLength); ++ ++ if (pwrpriv->wowlan_mode != _TRUE) ++ rtw_set_roaming(padapter, 1); ++ else ++ rtw_set_roaming(padapter, 0); ++ } ++#endif //CONFIG_LAYER2_ROAMING_RESUME ++ ++ if (pwrpriv->wowlan_mode == _FALSE) ++ { ++ //s2-2. indicate disconnect to os ++ rtw_indicate_disconnect(padapter); ++ //s2-3. ++ rtw_free_assoc_resources(padapter, 1); ++ ++ //s2-4. ++ rtw_free_network_queue(padapter, _TRUE); ++ ++ rtw_led_control(padapter, LED_CTL_POWER_OFF); ++ ++ rtw_dev_unload(padapter); ++ ++ if(check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)){ ++ DBG_871X_LEVEL(_drv_always_, "%s: fw_under_survey\n", __func__); ++ rtw_indicate_scan_done(padapter, 1); ++ } ++ ++ if(check_fwstate(pmlmepriv, _FW_UNDER_LINKING)){ ++ DBG_871X_LEVEL(_drv_always_, "%s: fw_under_linking\n", __func__); ++ rtw_indicate_disconnect(padapter); ++ } ++ ++ sdio_deinit(adapter_to_dvobj(padapter)); ++ } ++ else ++ { ++ DBG_871X_LEVEL(_drv_always_, "%s: wowmode suspending\n", __func__); ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) ++ { ++ DBG_871X_LEVEL(_drv_always_, "%s: fw_under_survey\n", __func__); ++ rtw_indicate_scan_done(padapter, 1); ++ clr_fwstate(pmlmepriv, _FW_UNDER_SURVEY); ++ } ++#ifdef CONFIG_POWER_SAVING ++ rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, 0); ++#endif ++ } ++ ++exit: ++ ++ _func_exit_; ++ return ret; ++} ++#endif //#ifdef CONFIG_WOWLAN ++ ++static int rtw_sdio_suspend(struct device *dev) ++{ ++ struct sdio_func *func =dev_to_sdio_func(dev); ++ struct dvobj_priv *psdpriv = sdio_get_drvdata(func); ++ _adapter *padapter = psdpriv->if1; ++ ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(psdpriv); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct net_device *pnetdev = padapter->pnetdev; ++ int ret = 0; ++#ifdef CONFIG_PLATFORM_SPRD ++ u32 value; ++#endif // CONFIG_PLATFORM_SPRD ++ ++ u32 start_time = rtw_get_current_time(); ++ ++ _func_enter_; ++ ++ DBG_871X_LEVEL(_drv_always_, "sdio suspend start\n"); ++ DBG_871X("==> %s (%s:%d)\n",__FUNCTION__, current->comm, current->pid); ++ ++ pwrpriv->bInSuspend = _TRUE; ++ ++#if (!(defined ANDROID_2X) && (defined CONFIG_PLATFORM_SPRD)) ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) { ++ //we should not suspend softap, bcm also do like this ++ DBG_871X("%s should not suspend hw and system in AP mode\n",__FUNCTION__); ++ goto exit; ++ } ++#endif ++ ++ while (pwrpriv->bips_processing == _TRUE) ++ rtw_msleep_os(1); ++ ++#ifdef CONFIG_IOL_READ_EFUSE_MAP ++ if(!padapter->bup){ ++ u8 bMacPwrCtrlOn = _FALSE; ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if(bMacPwrCtrlOn) ++ rtw_hal_power_off(padapter); ++ } ++#endif ++ ++ if((!padapter->bup) || (padapter->bDriverStopped)||(padapter->bSurpriseRemoved)) ++ { ++ DBG_871X("%s bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n", __FUNCTION__ ++ ,padapter->bup, padapter->bDriverStopped,padapter->bSurpriseRemoved); ++ goto exit; ++ } ++ ++ ++#ifdef CONFIG_WOWLAN ++ rtw_suspend_wow(padapter); ++#else ++ rtw_suspend_common(padapter); ++#endif ++ ++ // interface deinit ++ sdio_deinit(adapter_to_dvobj(padapter)); ++ ++ DBG_871X_LEVEL(_drv_always_, "sdio suspend success in %d ms\n", ++ rtw_get_passing_time_ms(start_time)); ++ ++exit: ++ ++#ifdef CONFIG_MMC_PM_KEEP_POWER ++ //Android 4.0 don't support WIFI close power ++ //or power down or clock will close after wifi resume, ++ //this is sprd's bug in Android 4.0, but sprd don't ++ //want to fix it. ++ //we have test power under 8723as, power consumption is ok ++ if (func) { ++ mmc_pm_flag_t pm_flag = 0; ++ pm_flag = sdio_get_host_pm_caps(func); ++ DBG_871X("cmd: %s: suspend: PM flag = 0x%x\n", sdio_func_id(func), pm_flag); ++ if (!(pm_flag & MMC_PM_KEEP_POWER)) { ++ DBG_871X("%s: cannot remain alive while host is suspended\n", sdio_func_id(func)); ++ return -ENOSYS; ++ } else { ++ DBG_871X("cmd: suspend with MMC_PM_KEEP_POWER\n"); ++ sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); ++ } ++ } ++#endif ++ ++#ifdef CONFIG_PLATFORM_SPRD ++#ifndef CONFIG_WOWLAN ++#ifdef CONFIG_RTL8188E ++#ifdef ANDROID_2X ++ /* ++ * Pull down wifi power pin here ++ * Pull up wifi power pin before sdio resume. ++ */ ++ rtw_wifi_gpio_wlan_ctrl(WLAN_POWER_OFF); ++#endif // ANDROID_2X ++#endif // CONFIG_RTL8188E ++#endif // CONFIG_WOWLAN ++#endif // CONFIG_PLATFORM_SPRD ++ ++ DBG_871X("<=== %s return %d.............. in %dms\n", __FUNCTION__ ++ , ret, rtw_get_passing_time_ms(start_time)); ++ ++ _func_exit_; ++ return ret; ++} ++ ++ ++#else ++static int rtw_sdio_suspend(struct device *dev) ++{ ++ struct sdio_func *func =dev_to_sdio_func(dev); ++ struct dvobj_priv *psdpriv = sdio_get_drvdata(func); ++ _adapter *padapter = psdpriv->if1; ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(psdpriv); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct net_device *pnetdev = padapter->pnetdev; ++ int ret = 0; ++#ifdef CONFIG_PLATFORM_SPRD ++ u32 value; ++#endif // CONFIG_PLATFORM_SPRD ++ ++#ifdef CONFIG_WOWLAN ++ struct wowlan_ioctl_param poidparam; ++ u8 ps_mode; ++#endif //CONFIG_WOWLAN ++ ++ u32 start_time = rtw_get_current_time(); ++ ++ _func_enter_; ++ ++ DBG_871X_LEVEL(_drv_always_, "sdio suspend start\n"); ++ DBG_871X("==> %s (%s:%d)\n",__FUNCTION__, current->comm, current->pid); ++ ++ pwrpriv->bInSuspend = _TRUE; ++ ++#if (!(defined ANDROID_2X) && (defined CONFIG_PLATFORM_SPRD)) ++ if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) { ++ //we should not suspend softap, bcm also do like this ++ DBG_871X("%s should not suspend hw and system in AP mode\n",__FUNCTION__); ++ goto exit; ++ } ++#endif ++ ++#ifdef CONFIG_WOWLAN ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) ++ pwrpriv->wowlan_mode = _TRUE; ++ else ++ pwrpriv->wowlan_mode = _FALSE; ++#endif ++ ++ //pwrpriv->bInSuspend = _TRUE; ++ ++ while (pwrpriv->bips_processing == _TRUE) ++ rtw_msleep_os(1); ++ ++ if((!padapter->bup) || (padapter->bDriverStopped)||(padapter->bSurpriseRemoved)) ++ { ++ DBG_871X("%s bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n", __FUNCTION__ ++ ,padapter->bup, padapter->bDriverStopped,padapter->bSurpriseRemoved); ++ goto exit; ++ } ++ ++ rtw_cancel_all_timer(padapter); ++ ++#ifdef CONFIG_WOWLAN ++ if (pwrpriv->wowlan_mode == _TRUE) { ++ // 1. stop thread ++ padapter->bDriverStopped = _TRUE; //for stop thread ++ rtw_stop_drv_threads(padapter); ++ padapter->bDriverStopped = _FALSE; //for 32k command ++#ifdef CONFIG_POWER_SAVING ++ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0); ++#endif ++ // 2. disable interrupt ++ rtw_hal_disable_interrupt(padapter); // It need wait for leaving 32K. ++ ++ // 2.1 clean interupt ++ if (padapter->HalFunc.clear_interrupt) ++ padapter->HalFunc.clear_interrupt(padapter); ++ ++ // 2.2 free irq ++ sdio_free_irq(adapter_to_dvobj(padapter)); ++ } else { ++ LeaveAllPowerSaveMode(padapter); ++ } ++ ++ if(pnetdev){ ++ if(pwrpriv->wowlan_mode == _TRUE) { ++ rtw_netif_stop_queue(pnetdev); ++ } else { ++ netif_carrier_off(pnetdev); ++ rtw_netif_stop_queue(pnetdev); ++ } ++ } ++ ++ DBG_871X("wowlan_mode: %d\n", pwrpriv->wowlan_mode); ++ ++ if ((pwrpriv->bSupportRemoteWakeup == _TRUE) && ++ (pwrpriv->wowlan_mode == _TRUE)) { ++ poidparam.subcode = WOWLAN_ENABLE; ++ padapter->HalFunc.SetHwRegHandler(padapter,HW_VAR_WOWLAN,(u8 *)&poidparam); ++ } else { ++ //s2-1. issue rtw_disassoc_cmd to fw ++ rtw_disassoc_cmd(padapter, 0, _FALSE); ++ } ++#else // !CONFIG_WOWLAN ++ LeaveAllPowerSaveMode(padapter); ++ ++ if(pnetdev) ++ { ++ netif_carrier_off(pnetdev); ++ rtw_netif_stop_queue(pnetdev); ++ } ++ ++ rtw_disassoc_cmd(padapter, 0, _FALSE); ++#endif // !CONFIG_WOWLAN ++ ++ //for power down during suspend, need leave ips mode before entering power down. ++ //pwrpriv->bInSuspend = _TRUE; ++ ++ //padapter->net_closed = _TRUE; ++ //s1. ++ ++#ifdef CONFIG_LAYER2_ROAMING_RESUME ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED) ) ++ { ++ DBG_871X("%s %s(" MAC_FMT "), length:%d assoc_ssid.length:%d\n",__FUNCTION__, ++ pmlmepriv->cur_network.network.Ssid.Ssid, ++ MAC_ARG(pmlmepriv->cur_network.network.MacAddress), ++ pmlmepriv->cur_network.network.Ssid.SsidLength, ++ pmlmepriv->assoc_ssid.SsidLength); ++#ifdef CONFIG_WOWLAN ++ if (pwrpriv->wowlan_mode != _TRUE) ++ rtw_set_roaming(padapter, 1); ++ else ++ rtw_set_roaming(padapter, 0); ++#else //CONFIG_WOWLAN ++ rtw_set_roaming(padapter, 1); ++#endif // !CONFIG_WOWLAN ++ } ++#endif //CONFIG_LAYER2_ROAMING_RESUME ++ ++#ifdef CONFIG_WOWLAN ++ if (pwrpriv->wowlan_mode == _FALSE) ++ { ++ //s2-2. indicate disconnect to os ++ rtw_indicate_disconnect(padapter); ++ //s2-3. ++ rtw_free_assoc_resources(padapter, 1); ++ ++ //s2-4. ++ rtw_free_network_queue(padapter, _TRUE); ++ ++ rtw_led_control(padapter, LED_CTL_POWER_OFF); ++ ++ rtw_dev_unload(padapter); ++ ++ if(check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)){ ++ DBG_871X_LEVEL(_drv_always_, "%s: fw_under_survey\n", __func__); ++ rtw_indicate_scan_done(padapter, 1); ++ } ++ ++ if(check_fwstate(pmlmepriv, _FW_UNDER_LINKING)){ ++ DBG_871X_LEVEL(_drv_always_, "%s: fw_under_linking\n", __func__); ++ rtw_indicate_disconnect(padapter); ++ } ++ ++ sdio_deinit(adapter_to_dvobj(padapter)); ++ } ++ else ++ { ++ DBG_871X_LEVEL(_drv_always_, "%s: wowmode suspending\n", __func__); ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) ++ { ++ DBG_871X_LEVEL(_drv_always_, "%s: fw_under_survey\n", __func__); ++ rtw_indicate_scan_done(padapter, 1); ++ clr_fwstate(pmlmepriv, _FW_UNDER_SURVEY); ++ } ++#ifdef CONFIG_POWER_SAVING ++ rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, 0); ++#endif ++ } ++#else ++ //s2-2. indicate disconnect to os ++ rtw_indicate_disconnect(padapter); ++ //s2-3. ++ rtw_free_assoc_resources(padapter, 1); ++ ++ //s2-4. ++ rtw_free_network_queue(padapter, _TRUE); ++ ++ rtw_led_control(padapter, LED_CTL_POWER_OFF); ++ ++ rtw_dev_unload(padapter); ++ ++ if(check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) ++ rtw_indicate_scan_done(padapter, 1); ++ ++ if(check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) ++ rtw_indicate_disconnect(padapter); ++ ++ // interface deinit ++ sdio_deinit(adapter_to_dvobj(padapter)); ++#endif ++ DBG_871X_LEVEL(_drv_always_, "sdio suspend success in %d ms\n", ++ rtw_get_passing_time_ms(start_time)); ++ ++exit: ++ ++//#if (defined CONFIG_WOWLAN) || (!(defined ANDROID_2X) && (defined CONFIG_PLATFORM_SPRD)) ++#if (defined CONFIG_WOWLAN) ++#if (!(defined ANDROID_2X)) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) ++ //Android 4.0 don't support WIFI close power ++ //or power down or clock will close after wifi resume, ++ //this is sprd's bug in Android 4.0, but sprd don't ++ //want to fix it. ++ //we have test power under 8723as, power consumption is ok ++ if (func) { ++ mmc_pm_flag_t pm_flag = 0; ++ pm_flag = sdio_get_host_pm_caps(func); ++ DBG_871X("cmd: %s: suspend: PM flag = 0x%x\n", sdio_func_id(func), pm_flag); ++ if (!(pm_flag & MMC_PM_KEEP_POWER)) { ++ DBG_871X("%s: cannot remain alive while host is suspended\n", sdio_func_id(func)); ++ return -ENOSYS; ++ } else { ++ DBG_871X("cmd: suspend with MMC_PM_KEEP_POWER\n"); ++ sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); ++ } ++ } ++#endif ++#endif ++ ++#ifdef CONFIG_PLATFORM_SPRD ++#ifndef CONFIG_WOWLAN ++#ifdef CONFIG_RTL8188E ++#ifdef ANDROID_2X ++ /* ++ * Pull down wifi power pin here ++ * Pull up wifi power pin before sdio resume. ++ */ ++ rtw_wifi_gpio_wlan_ctrl(WLAN_POWER_OFF); ++#endif // ANDROID_2X ++#endif // CONFIG_RTL8188E ++#endif // CONFIG_WOWLAN ++#endif // CONFIG_PLATFORM_SPRD ++ ++ DBG_871X("<=== %s return %d.............. in %dms\n", __FUNCTION__ ++ , ret, rtw_get_passing_time_ms(start_time)); ++ ++ _func_exit_; ++ return ret; ++} ++#endif ++extern int pm_netdev_open(struct net_device *pnetdev,u8 bnormal); ++ ++#if 1 ++#ifdef CONFIG_WOWLAN ++int rtw_resume_process_wow(_adapter *padapter) ++{ ++ struct net_device *pnetdev = padapter->pnetdev; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ int ret = 0; ++ ++ u32 value = 0; ++ struct wowlan_ioctl_param poidparam; ++ struct sta_info *psta = NULL; ++ ++ _func_enter_; ++ ++ if (pwrpriv->wowlan_mode == _FALSE){ ++ ++ // interface init ++ if (sdio_init(adapter_to_dvobj(padapter)) != _SUCCESS) ++ { ++ ret = -1; ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: initialize SDIO Failed!!\n", __FUNCTION__)); ++ goto exit; ++ } ++ ++ rtw_hal_disable_interrupt(padapter); ++ ++ if (padapter->HalFunc.clear_interrupt) ++ padapter->HalFunc.clear_interrupt(padapter); ++ ++ if (sdio_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) ++ { ++ ret = -1; ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: sdio_alloc_irq Failed!!\n", __FUNCTION__)); ++ goto exit; ++ } ++ ++ rtw_reset_drv_sw(padapter); ++ pwrpriv->bkeepfwalive = _FALSE; ++ ++ DBG_871X("bkeepfwalive(%x)\n",pwrpriv->bkeepfwalive); ++ ++ if(pm_netdev_open(pnetdev,_TRUE) != 0) { ++ ret = -1; ++ goto exit; ++ } ++ ++ netif_device_attach(pnetdev); ++ netif_carrier_on(pnetdev); ++ } ++ else //pwrpriv->wowlan_mode == _TRUE ++ { ++ ++#ifdef CONFIG_POWER_SAVING ++#ifdef CONFIG_LPS ++ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0); ++#endif //CONFIG_LPS ++#endif ++ ++ pwrpriv->bFwCurrentInPSMode = _FALSE; ++ ++ rtw_hal_disable_interrupt(padapter); ++ ++ if (padapter->HalFunc.clear_interrupt) ++ padapter->HalFunc.clear_interrupt(padapter); ++ ++ if (sdio_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) { ++ ret = -1; ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: sdio_alloc_irq Failed!!\n", __FUNCTION__)); ++ goto exit; ++ } ++ ++ //Disable WOW, set H2C command ++ poidparam.subcode=WOWLAN_DISABLE; ++ padapter->HalFunc.SetHwRegHandler(padapter,HW_VAR_WOWLAN,(u8 *)&poidparam); ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv)); ++ if (psta) { ++ set_sta_rate(padapter, psta); ++ } ++ ++ padapter->bDriverStopped = _FALSE; ++ ++ DBG_871X("%s: wowmode resuming, DriverStopped:%d\n", __func__, padapter->bDriverStopped); ++ rtw_start_drv_threads(padapter); ++ ++ rtw_hal_enable_interrupt(padapter); ++ ++ // start netif queue ++ if(pnetdev) { ++ if(!rtw_netif_queue_stopped(pnetdev)) ++ rtw_netif_start_queue(pnetdev); ++ else ++ rtw_netif_wake_queue(pnetdev); ++ } ++ } ++ ++ ++#ifdef CONFIG_LAYER2_ROAMING_RESUME ++ ++ if (pwrpriv->wowlan_wake_reason == FWDecisionDisconnect || ++ pwrpriv->wowlan_wake_reason == Rx_DisAssoc || ++ pwrpriv->wowlan_wake_reason == Rx_DeAuth) { ++ ++ DBG_871X("%s: disconnect reason: %02x\n", __func__, ++ pwrpriv->wowlan_wake_reason); ++ rtw_indicate_disconnect(padapter); ++ rtw_sta_media_status_rpt(padapter, rtw_get_stainfo(&padapter->stapriv, ++ get_bssid(&padapter->mlmepriv)), 0); ++ rtw_free_assoc_resources(padapter, 1); ++ } else { ++ DBG_871X("%s: do roaming\n", __func__); ++ rtw_roaming(padapter, NULL); ++ } ++ ++#endif //CONFIG_LAYER2_ROAMING_RESUME ++ ++ if (pwrpriv->wowlan_wake_reason == Rx_GTK || ++ pwrpriv->wowlan_wake_reason == Rx_DisAssoc || ++ pwrpriv->wowlan_wake_reason == Rx_DeAuth) { ++ DBG_871X("%s: set ext wake lock\n", __func__); ++ rtw_lock_ext_suspend_timeout(1500); ++ } ++ ++ if (pwrpriv->wowlan_mode == _TRUE) { ++ pwrpriv->bips_processing = _FALSE; ++ _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 2000); ++ rtw_set_pwr_state_check_timer(pwrpriv); ++ pwrpriv->bips_processing = _FALSE; ++ rtw_unlock_suspend(); ++ } else { ++ DBG_871X_LEVEL(_drv_always_, "do not reset timer\n"); ++ } ++ ++ pwrpriv->wowlan_mode =_FALSE; ++ ++exit: ++ ++ _func_exit_; ++ ++ return ret; ++} ++#endif //CONFIG_WOWLAN ++ ++int rtw_resume_process_normal(_adapter *padapter) ++{ ++ struct net_device *pnetdev= padapter->pnetdev; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct mlme_priv *mlmepriv = &padapter->mlmepriv; ++ int ret = 0; ++ ++ _func_enter_; ++ // interface init ++ if (sdio_init(adapter_to_dvobj(padapter)) != _SUCCESS) ++ { ++ ret = -1; ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: initialize SDIO Failed!!\n", __FUNCTION__)); ++ goto exit; ++ } ++ rtw_hal_disable_interrupt(padapter); ++ if (sdio_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) ++ { ++ ret = -1; ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: sdio_alloc_irq Failed!!\n", __FUNCTION__)); ++ goto exit; ++ } ++ ++ if(rtw_resume_common(padapter)!= 0) { ++ DBG_871X("%s rtw_resume_common failed\n",__FUNCTION__); ++ goto exit; ++ } ++ _func_exit_; ++exit: ++ return ret; ++} ++ ++int rtw_resume_process(_adapter *padapter) ++{ ++ struct net_device *pnetdev; ++ struct pwrctrl_priv *pwrpriv = NULL; ++ ++ int ret = 0; ++ u32 start_time = rtw_get_current_time(); ++ ++ _func_enter_; ++ ++ DBG_871X_LEVEL(_drv_always_, "sdio resume start\n"); ++ DBG_871X("==> %s (%s:%d)\n",__FUNCTION__, current->comm, current->pid); ++ ++ if (padapter) { ++ pnetdev = padapter->pnetdev; ++ pwrpriv = adapter_to_pwrctl(padapter); ++ } else { ++ ret = -1; ++ goto exit; ++ } ++ ++#ifdef CONFIG_WOWLAN ++ rtw_resume_process_wow( padapter); ++#else //!CONFIG_WOWLAN ++ rtw_resume_process_normal( padapter); ++#endif ++ ++ if( padapter->pid[1]!=0) { ++ DBG_871X("pid[1]:%d\n",padapter->pid[1]); ++ rtw_signal_process(padapter->pid[1], SIGUSR2); ++ } ++ ++ #ifdef CONFIG_RESUME_IN_WORKQUEUE ++ rtw_unlock_suspend(); ++ #endif //CONFIG_RESUME_IN_WORKQUEUE ++ ++exit: ++ if (pwrpriv) ++ pwrpriv->bInSuspend = _FALSE; ++ DBG_871X_LEVEL(_drv_always_, "sdio resume ret:%d in %d ms\n", ret, ++ rtw_get_passing_time_ms(start_time)); ++ ++ _func_exit_; ++ ++ return ret; ++} ++#else ++int rtw_resume_process(_adapter *padapter) ++{ ++ struct net_device *pnetdev; ++ struct pwrctrl_priv *pwrpriv = NULL; ++ u8 is_pwrlock_hold_by_caller; ++ u8 is_directly_called_by_auto_resume; ++ int ret = 0; ++ u32 start_time = rtw_get_current_time(); ++#ifdef CONFIG_WOWLAN ++ u32 value = 0; ++ struct wowlan_ioctl_param poidparam; ++ struct sta_info *psta = NULL; ++#endif // CONFIG_WOWLAN ++ ++ _func_enter_; ++ ++ DBG_871X_LEVEL(_drv_always_, "sdio resume start\n"); ++ DBG_871X("==> %s (%s:%d)\n",__FUNCTION__, current->comm, current->pid); ++ ++ if (padapter) { ++ pnetdev = padapter->pnetdev; ++ pwrpriv = adapter_to_pwrctl(padapter); ++ } else { ++ ret = -1; ++ goto exit; ++ } ++ ++#ifdef CONFIG_WOWLAN ++ if (pwrpriv->wowlan_mode == _FALSE){ ++ ++ // interface init ++ if (sdio_init(adapter_to_dvobj(padapter)) != _SUCCESS) ++ { ++ ret = -1; ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: initialize SDIO Failed!!\n", __FUNCTION__)); ++ goto exit; ++ } ++ ++ rtw_hal_disable_interrupt(padapter); ++ ++ if (padapter->HalFunc.clear_interrupt) ++ padapter->HalFunc.clear_interrupt(padapter); ++ ++ if (sdio_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) ++ { ++ ret = -1; ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: sdio_alloc_irq Failed!!\n", __FUNCTION__)); ++ goto exit; ++ } ++ ++ rtw_reset_drv_sw(padapter); ++ pwrpriv->bkeepfwalive = _FALSE; ++ ++ DBG_871X("bkeepfwalive(%x)\n",pwrpriv->bkeepfwalive); ++ ++ if(pm_netdev_open(pnetdev,_TRUE) != 0) { ++ ret = -1; ++ goto exit; ++ } ++ ++ netif_device_attach(pnetdev); ++ netif_carrier_on(pnetdev); ++ } else { ++ ++#ifdef CONFIG_POWER_SAVING ++#ifdef CONFIG_LPS ++ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0); ++#endif //CONFIG_LPS ++#endif ++ ++ pwrpriv->bFwCurrentInPSMode = _FALSE; ++ ++ rtw_hal_disable_interrupt(padapter); ++ ++ if (padapter->HalFunc.clear_interrupt) ++ padapter->HalFunc.clear_interrupt(padapter); ++ ++ if (sdio_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) { ++ ret = -1; ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: sdio_alloc_irq Failed!!\n", __FUNCTION__)); ++ goto exit; ++ } ++ ++ //Disable WOW, set H2C command ++ poidparam.subcode=WOWLAN_DISABLE; ++ padapter->HalFunc.SetHwRegHandler(padapter,HW_VAR_WOWLAN,(u8 *)&poidparam); ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv)); ++ if (psta) { ++ set_sta_rate(padapter, psta); ++ } ++ ++ padapter->bDriverStopped = _FALSE; ++ ++ DBG_871X("%s: wowmode resuming, DriverStopped:%d\n", __func__, padapter->bDriverStopped); ++ rtw_start_drv_threads(padapter); ++ ++ rtw_hal_enable_interrupt(padapter); ++ ++ // start netif queue ++ if(pnetdev) { ++ if(!rtw_netif_queue_stopped(pnetdev)) ++ rtw_netif_start_queue(pnetdev); ++ else ++ rtw_netif_wake_queue(pnetdev); ++ } ++ } ++#else //!CONFIG_WOWLAN ++ ++ // interface init ++ if (sdio_init(adapter_to_dvobj(padapter)) != _SUCCESS) ++ { ++ ret = -1; ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: initialize SDIO Failed!!\n", __FUNCTION__)); ++ goto exit; ++ } ++ rtw_hal_disable_interrupt(padapter); ++ if (sdio_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) ++ { ++ ret = -1; ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: sdio_alloc_irq Failed!!\n", __FUNCTION__)); ++ goto exit; ++ } ++ ++ rtw_reset_drv_sw(padapter); ++ pwrpriv->bkeepfwalive = _FALSE; ++ ++ DBG_871X("bkeepfwalive(%x)\n",pwrpriv->bkeepfwalive); ++ if(pm_netdev_open(pnetdev,_TRUE) != 0) { ++ ret = -1; ++ goto exit; ++ } ++ ++ netif_device_attach(pnetdev); ++ netif_carrier_on(pnetdev); ++#endif ++ if( padapter->pid[1]!=0) { ++ DBG_871X("pid[1]:%d\n",padapter->pid[1]); ++ rtw_signal_process(padapter->pid[1], SIGUSR2); ++ } ++ ++#ifdef CONFIG_LAYER2_ROAMING_RESUME ++#ifdef CONFIG_WOWLAN ++ if (pwrpriv->wowlan_wake_reason == FWDecisionDisconnect || ++ pwrpriv->wowlan_wake_reason == Rx_DisAssoc || ++ pwrpriv->wowlan_wake_reason == Rx_DeAuth) { ++ ++ DBG_871X("%s: disconnect reason: %02x\n", __func__, ++ pwrpriv->wowlan_wake_reason); ++ rtw_indicate_disconnect(padapter); ++ rtw_sta_media_status_rpt(padapter, rtw_get_stainfo(&padapter->stapriv, ++ get_bssid(&padapter->mlmepriv)), 0); ++ rtw_free_assoc_resources(padapter, 1); ++ } else { ++ DBG_871X("%s: do roaming\n", __func__); ++ rtw_roaming(padapter, NULL); ++ } ++#else ++ rtw_roaming(padapter, NULL); ++#endif //CONFOG_WOWLAN ++#endif //CONFIG_LAYER2_ROAMING_RESUME ++ ++ #ifdef CONFIG_RESUME_IN_WORKQUEUE ++ rtw_unlock_suspend(); ++ #endif //CONFIG_RESUME_IN_WORKQUEUE ++ ++#ifdef CONFIG_WOWLAN ++ if (pwrpriv->wowlan_wake_reason == Rx_GTK || ++ pwrpriv->wowlan_wake_reason == Rx_DisAssoc || ++ pwrpriv->wowlan_wake_reason == Rx_DeAuth) { ++ DBG_871X("%s: set ext wake lock\n", __func__); ++ rtw_lock_ext_suspend_timeout(1500); ++ } ++ ++ if (pwrpriv->wowlan_mode == _TRUE) { ++ pwrpriv->bips_processing = _FALSE; ++ _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 2000); ++ rtw_set_pwr_state_check_timer(pwrpriv); ++ pwrpriv->bips_processing = _FALSE; ++ rtw_unlock_suspend(); ++ } else { ++ DBG_871X_LEVEL(_drv_always_, "do not reset timer\n"); ++ } ++ ++ pwrpriv->wowlan_mode =_FALSE; ++#endif //CONFIG_WOWLAN ++ ++exit: ++ if (pwrpriv) ++ pwrpriv->bInSuspend = _FALSE; ++ DBG_871X_LEVEL(_drv_always_, "sdio resume ret:%d in %d ms\n", ret, ++ rtw_get_passing_time_ms(start_time)); ++ ++ _func_exit_; ++ ++ return ret; ++} ++#endif ++ ++ ++static int rtw_sdio_resume(struct device *dev) ++{ ++ struct sdio_func *func =dev_to_sdio_func(dev); ++ struct dvobj_priv *psdpriv = sdio_get_drvdata(func); ++ _adapter *padapter = psdpriv->if1; ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(psdpriv); ++ int ret = 0; ++ ++ DBG_871X("==> %s (%s:%d)\n",__FUNCTION__, current->comm, current->pid); ++ ++ if(pwrpriv->bInternalAutoSuspend ){ ++ ret = rtw_resume_process(padapter); ++ } else { ++#ifdef CONFIG_RESUME_IN_WORKQUEUE ++ rtw_resume_in_workqueue(pwrpriv); ++#else ++ if (rtw_is_earlysuspend_registered(pwrpriv) ++ #ifdef CONFIG_WOWLAN ++ && !pwrpriv->wowlan_mode ++ #endif /* CONFIG_WOWLAN */ ++ ) { ++ /* jeff: bypass resume here, do in late_resume */ ++ rtw_set_do_late_resume(pwrpriv, _TRUE); ++ } else { ++ rtw_set_do_late_resume(pwrpriv, _FALSE); ++ #ifdef CONFIG_WOWLAN ++ //rtw_lock_suspend_timeout(4000); ++ rtw_lock_suspend(); ++ #endif ++ ret = rtw_resume_process(padapter); ++ } ++#endif /* CONFIG_RESUME_IN_WORKQUEUE */ ++ } ++ ++ DBG_871X("<======== %s return %d\n", __FUNCTION__, ret); ++ return ret; ++ ++} ++ ++ ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) ++extern int console_suspend_enabled; ++#endif ++ ++ ++#ifdef CONFIG_PLATFORM_SPRD ++extern void sdhci_bus_scan(void); ++#ifndef ANDROID_2X ++extern int sdhci_device_attached(void); ++#endif ++#endif // CONFIG_PLATFORM_SPRD ++ ++static int __init rtw_drv_entry(void) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_PLATFORM_ARM_SUNxI ++/*depends on sunxi power control */ ++#if defined CONFIG_MMC_SUNXI_POWER_CONTROL ++ unsigned int mod_sel = mmc_pm_get_mod_type(); ++ ++ if(mod_sel == SUNXI_SDIO_WIFI_NUM_RTL8189ES) ++ { ++ rtl8189es_sdio_powerup(); ++ sunximmc_rescan_card(SDIOID, 1); ++ DBG_8192C("[rtl8189es] %s: power up, rescan card.\n", __FUNCTION__); ++ } ++ else ++ { ++ ret = -1; ++ DBG_8192C("[rtl8189es] %s: mod_sel = %d is incorrect.\n", __FUNCTION__, mod_sel); ++ } ++#endif // defined CONFIG_MMC_SUNXI_POWER_CONTROL ++ if(ret != 0) ++ goto exit; ++ ++#endif //CONFIG_PLATFORM_ARM_SUNxI ++ ++#if defined(CONFIG_PLATFORM_ARM_SUN6I) || defined(CONFIG_PLATFORM_ARM_SUN7I) ++#ifdef CONFIG_MMC ++ script_item_value_type_e type; ++ script_item_u item; ++ ++ unsigned int mod_sel = wifi_pm_get_mod_type(); ++ ++ type = script_get_item("wifi_para", "wifi_sdc_id", &item); ++ if (SCIRPT_ITEM_VALUE_TYPE_INT != type) ++ { ++ DBG_871X("ERR: script_get_item wifi_sdc_id failed\n"); ++ ret = -1; ++ } ++ else ++ { ++ sdc_id = item.val; ++ DBG_871X("----- %s sdc_id: %d, mod_sel: %d\n", __FUNCTION__, sdc_id, mod_sel); ++ wifi_pm_power(1); ++ mdelay(10); ++ sw_mci_rescan_card(sdc_id, 1); ++ DBG_871X("[rtw_sdio] %s: power up, rescan card.\n", __FUNCTION__); ++ } ++#endif //CONFIG_MMC ++ if(ret != 0) ++ goto exit; ++ ++#endif //#if defined(CONFIG_PLATFORM_ARM_SUN6I) || defined(CONFIG_PLATFORM_ARM_SUN7I) ++ ++ DBG_871X_LEVEL(_drv_always_, "module init start version:"DRIVERVERSION"\n"); ++ ++// DBG_871X(KERN_INFO "+%s", __func__); ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+rtw_drv_entry\n")); ++ DBG_871X(DRV_NAME " driver version=%s\n", DRIVERVERSION); ++ DBG_871X("build time: %s %s\n", __DATE__, __TIME__); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) ++ //console_suspend_enabled=0; ++#endif ++ ++#ifdef CONFIG_PLATFORM_SPRD ++ rtw_wifi_gpio_init(); ++ ++#ifdef ANDROID_2X ++#ifdef CONFIG_RTL8188E ++ rtw_wifi_gpio_wlan_ctrl(WLAN_POWER_ON); ++#endif //CONFIG_RTL8188E ++#endif //ANDROID_2X ++ ++ /* Pull up pwd pin, make wifi leave power down mode. */ ++ rtw_wifi_gpio_wlan_ctrl(WLAN_PWDN_ON); ++ ++#if defined(CONFIG_RTL8723A) && (MP_DRIVER == 1) ++ // Pull up BT reset pin. ++ rtw_wifi_gpio_wlan_ctrl(WLAN_BT_PWDN_ON); ++#endif ++ rtw_mdelay_os(5); ++ ++ sdhci_bus_scan(); ++#if (defined ANDROID_2X) ++ rtw_mdelay_os(200); ++#endif //ANDROID_2X ++ ++#endif // CONFIG_PLATFORM_SPRD ++ ++ rtw_suspend_lock_init(); ++ ++ ++ sdio_drvpriv.drv_registered = _TRUE; ++ ++ ret = sdio_register_driver(&sdio_drvpriv.r871xs_drv); ++ ++exit: ++ DBG_871X_LEVEL(_drv_always_, "module init ret=%d\n", ret); ++ ++ rtw_android_wifictrl_func_add(); ++ ++ return ret; ++} ++ ++static void __exit rtw_drv_halt(void) ++{ ++ DBG_871X_LEVEL(_drv_always_, "module exit start\n"); ++ ++ rtw_android_wifictrl_func_del(); ++ sdio_drvpriv.drv_registered = _FALSE; ++ ++ sdio_unregister_driver(&sdio_drvpriv.r871xs_drv); ++ ++#ifdef CONFIG_PLATFORM_SPRD ++ /* Pull down pwd pin, make wifi enter power down mode. */ ++ rtw_wifi_gpio_wlan_ctrl(WLAN_PWDN_OFF); ++ rtw_mdelay_os(5); ++ rtw_wifi_gpio_deinit(); ++ ++#ifdef ANDROID_2X ++#ifdef CONFIG_RTL8188E ++ rtw_wifi_gpio_wlan_ctrl(WLAN_POWER_OFF); ++#endif // CONFIG_RTL8188E ++#endif // ANDROID_2X ++ ++#endif // CONFIG_PLATFORM_SPRD ++ ++#ifdef CONFIG_PLATFORM_ARM_SUNxI ++#if defined(CONFIG_MMC_SUNXI_POWER_CONTROL) ++ sunximmc_rescan_card(SDIOID, 0); ++#ifdef CONFIG_RTL8188E ++ rtl8189es_sdio_poweroff(); ++ DBG_8192C("[rtl8189es] %s: remove card, power off.\n", __FUNCTION__); ++#endif //CONFIG_RTL8188E ++#endif //defined(CONFIG_MMC_SUNXI_POWER_CONTROL) ++#endif //CONFIG_PLATFORM_ARM_SUNxI ++ ++#if defined(CONFIG_PLATFORM_ARM_SUN6I) || defined(CONFIG_PLATFORM_ARM_SUN7I) ++#ifdef CONFIG_MMC ++ wifi_pm_power(0); ++ sw_mci_rescan_card(sdc_id, 0); ++ printk("[rtl8723as] %s: remove card, power off.\n", __FUNCTION__); ++#endif //CONFIG_MMC ++#endif //#if defined(CONFIG_PLATFORM_ARM_SUN6I) || defined(CONFIG_PLATFORM_ARM_SUN7I) ++ rtw_suspend_lock_uninit(); ++ DBG_871X_LEVEL(_drv_always_, "module exit success\n"); ++ ++ rtw_mstat_dump(); ++} ++ ++ ++module_init(rtw_drv_entry); ++module_exit(rtw_drv_halt); ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/sdio_ops_linux.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/sdio_ops_linux.c +new file mode 100644 +index 00000000..4a107892 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/sdio_ops_linux.c +@@ -0,0 +1,912 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ *******************************************************************************/ ++#define _SDIO_OPS_LINUX_C_ ++ ++#include ++ ++#include ++ ++static bool rtw_sdio_claim_host_needed(struct sdio_func *func) ++{ ++ struct dvobj_priv *dvobj = sdio_get_drvdata(func); ++ PSDIO_DATA sdio_data = &dvobj->intf_data; ++ ++ if (sdio_data->sys_sdio_irq_thd && sdio_data->sys_sdio_irq_thd == current) ++ return _FALSE; ++ return _TRUE; ++} ++ ++inline void rtw_sdio_set_irq_thd(struct dvobj_priv *dvobj, _thread_hdl_ thd_hdl) ++{ ++ PSDIO_DATA sdio_data = &dvobj->intf_data; ++ ++ sdio_data->sys_sdio_irq_thd = thd_hdl; ++} ++ ++u8 sd_f0_read8(struct intf_hdl *pintfhdl,u32 addr, s32 *err) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ u8 v=0; ++ struct sdio_func *func; ++ bool claim_needed; ++ ++_func_enter_; ++ ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved )!!!\n",__FUNCTION__); ++ return v; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ v = sdio_f0_readb(func, addr, err); ++ if (claim_needed) ++ sdio_release_host(func); ++ if (err && *err) ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr=0x%05x\n", __func__, *err, addr); ++ ++_func_exit_; ++ ++ return v; ++} ++ ++void sd_f0_write8(struct intf_hdl *pintfhdl, u32 addr, u8 v, s32 *err) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ struct sdio_func *func; ++ bool claim_needed; ++ ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved )!!!\n",__FUNCTION__); ++ return; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ sdio_f0_writeb(func, v, addr, err); ++ if (claim_needed) ++ sdio_release_host(func); ++ if (err && *err) ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr=0x%05x val=0x%02x\n", __func__, *err, addr, v); ++ ++_func_exit_; ++} ++ ++/* ++ * Return: ++ * 0 Success ++ * others Fail ++ */ ++s32 _sd_cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ int err=0, i; ++ struct sdio_func *func; ++ ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved )!!!\n",__FUNCTION__); ++ return err; ++ } ++ ++ func = psdio->func; ++ ++ for (i = 0; i < cnt; i++) { ++ pdata[i] = sdio_readb(func, addr+i, &err); ++ if (err) { ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr=0x%05x\n", __func__, err, addr+i); ++ break; ++ } ++ } ++ ++_func_exit_; ++ ++ return err; ++} ++ ++/* ++ * Return: ++ * 0 Success ++ * others Fail ++ */ ++s32 sd_cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ int err=0, i; ++ struct sdio_func *func; ++ bool claim_needed; ++ ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved )!!!\n",__FUNCTION__); ++ return err; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ err = _sd_cmd52_read(pintfhdl, addr, cnt, pdata); ++ if (claim_needed) ++ sdio_release_host(func); ++ ++_func_exit_; ++ ++ return err; ++} ++ ++/* ++ * Return: ++ * 0 Success ++ * others Fail ++ */ ++s32 _sd_cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ int err=0, i; ++ struct sdio_func *func; ++ ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved)!!!\n",__FUNCTION__); ++ return err; ++ } ++ ++ func = psdio->func; ++ ++ for (i = 0; i < cnt; i++) { ++ sdio_writeb(func, pdata[i], addr+i, &err); ++ if (err) { ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr=0x%05x val=0x%02x\n", __func__, err, addr+i, pdata[i]); ++ break; ++ } ++ } ++ ++_func_exit_; ++ ++ return err; ++} ++ ++/* ++ * Return: ++ * 0 Success ++ * others Fail ++ */ ++s32 sd_cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ int err=0, i; ++ struct sdio_func *func; ++ bool claim_needed; ++ ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved )!!!\n",__FUNCTION__); ++ return err; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ err = _sd_cmd52_write(pintfhdl, addr, cnt, pdata); ++ if (claim_needed) ++ sdio_release_host(func); ++ ++_func_exit_; ++ ++ return err; ++} ++ ++u8 _sd_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ u8 v=0; ++ struct sdio_func *func; ++ ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved)!!!\n",__FUNCTION__); ++ return v; ++ } ++ ++ func = psdio->func; ++ ++ v = sdio_readb(func, addr, err); ++ ++ if (err && *err) ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr=0x%05x\n", __func__, *err, addr); ++ ++_func_exit_; ++ ++ return v; ++} ++ ++u8 sd_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ u8 v; ++ struct sdio_func *func; ++ bool claim_needed; ++ ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved )!!!\n",__FUNCTION__); ++ return v; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ v = sdio_readb(func, addr, err); ++ if (claim_needed) ++ sdio_release_host(func); ++ if (err && *err) ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr=0x%05x\n", __func__, *err, addr); ++ ++_func_exit_; ++ ++ return v; ++} ++ ++u16 sd_read16(struct intf_hdl *pintfhdl, u32 addr, s32 *err) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ u16 v=0; ++ struct sdio_func *func; ++ bool claim_needed; ++ ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved )!!!\n",__FUNCTION__); ++ return v; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ v = sdio_readw(func, addr, err); ++ if (claim_needed) ++ sdio_release_host(func); ++ if (err && *err) ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr=0x%05x\n", __func__, *err, addr); ++ ++_func_exit_; ++ ++ return v; ++} ++ ++u32 _sd_read32(struct intf_hdl *pintfhdl, u32 addr, s32 *err) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ u32 v=0; ++ struct sdio_func *func; ++ ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved )!!!\n",__FUNCTION__); ++ return v; ++ } ++ ++ func = psdio->func; ++ ++ v = sdio_readl(func, addr, err); ++ ++ if (err && *err) ++ { ++ int i; ++ ++ DBG_871X(KERN_ERR "%s: (%d) addr=0x%05x, val=0x%x\n", __func__, *err, addr, v); ++ ++ *err = 0; ++ for(i=0; ibSurpriseRemoved = _TRUE; ++ } ++ ++ if(rtw_inc_and_chk_continual_io_error(psdiodev) == _TRUE ){ ++ padapter->bSurpriseRemoved = _TRUE; ++ break; ++ } ++ ++ } ++ } ++ ++ if (i==SD_IO_TRY_CNT) ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr=0x%05x, val=0x%x, try_cnt=%d\n", __func__, *err, addr, v, i); ++ else ++ DBG_871X(KERN_ERR "%s: (%d) addr=0x%05x, val=0x%x, try_cnt=%d\n", __func__, *err, addr, v, i); ++ ++ } ++ ++_func_exit_; ++ ++ return v; ++} ++ ++u32 sd_read32(struct intf_hdl *pintfhdl, u32 addr, s32 *err) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ u32 v=0; ++ struct sdio_func *func; ++ bool claim_needed; ++ ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved )!!!\n",__FUNCTION__); ++ return v; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ v = sdio_readl(func, addr, err); ++ if (claim_needed) ++ sdio_release_host(func); ++ ++ if (err && *err) ++ { ++ int i; ++ ++ DBG_871X(KERN_ERR "%s: (%d) addr=0x%05x, val=0x%x\n", __func__, *err, addr, v); ++ ++ *err = 0; ++ for(i=0; ibSurpriseRemoved = _TRUE; ++ } ++ ++ if(rtw_inc_and_chk_continual_io_error(psdiodev) == _TRUE ){ ++ padapter->bSurpriseRemoved = _TRUE; ++ break; ++ } ++ } ++ } ++ ++ if (i==SD_IO_TRY_CNT) ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr=0x%05x, val=0x%x, try_cnt=%d\n", __func__, *err, addr, v, i); ++ else ++ DBG_871X(KERN_ERR "%s: (%d) addr=0x%05x, val=0x%x, try_cnt=%d\n", __func__, *err, addr, v, i); ++ ++ } ++ ++_func_exit_; ++ ++ return v; ++} ++ ++void sd_write8(struct intf_hdl *pintfhdl, u32 addr, u8 v, s32 *err) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ struct sdio_func *func; ++ bool claim_needed; ++ ++_func_enter_; ++ ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved )!!!\n",__FUNCTION__); ++ return ; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ sdio_writeb(func, v, addr, err); ++ if (claim_needed) ++ sdio_release_host(func); ++ if (err && *err) ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr=0x%05x val=0x%02x\n", __func__, *err, addr, v); ++ ++_func_exit_; ++} ++ ++void sd_write16(struct intf_hdl *pintfhdl, u32 addr, u16 v, s32 *err) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ struct sdio_func *func; ++ bool claim_needed; ++ ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved )!!!\n",__FUNCTION__); ++ return ; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ sdio_writew(func, v, addr, err); ++ if (claim_needed) ++ sdio_release_host(func); ++ if (err && *err) ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr=0x%05x val=0x%04x\n", __func__, *err, addr, v); ++ ++_func_exit_; ++} ++ ++void _sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ struct sdio_func *func; ++ ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved )!!!\n",__FUNCTION__); ++ return ; ++ } ++ ++ func = psdio->func; ++ ++ sdio_writel(func, v, addr, err); ++ ++ if (err && *err) ++ { ++ int i; ++ ++ DBG_871X(KERN_ERR "%s: (%d) addr=0x%05x val=0x%08x\n", __func__, *err, addr, v); ++ ++ *err = 0; ++ for(i=0; ibSurpriseRemoved = _TRUE; ++ } ++ ++ if(rtw_inc_and_chk_continual_io_error(psdiodev) == _TRUE ){ ++ padapter->bSurpriseRemoved = _TRUE; ++ break; ++ } ++ } ++ } ++ ++ if (i==SD_IO_TRY_CNT) ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr=0x%05x val=0x%08x, try_cnt=%d\n", __func__, *err, addr, v, i); ++ else ++ DBG_871X(KERN_ERR "%s: (%d) addr=0x%05x val=0x%08x, try_cnt=%d\n", __func__, *err, addr, v, i); ++ ++ } ++ ++_func_exit_; ++} ++ ++void sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ struct sdio_func *func; ++ bool claim_needed; ++ ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved)!!!\n",__FUNCTION__); ++ return ; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ sdio_writel(func, v, addr, err); ++ if (claim_needed) ++ sdio_release_host(func); ++ ++ if (err && *err) ++ { ++ int i; ++ ++ DBG_871X(KERN_ERR "%s: (%d) addr=0x%05x val=0x%08x\n", __func__, *err, addr, v); ++ ++ *err = 0; ++ for(i=0; ibSurpriseRemoved = _TRUE; ++ } ++ ++ if(rtw_inc_and_chk_continual_io_error(psdiodev) == _TRUE ){ ++ padapter->bSurpriseRemoved = _TRUE; ++ break; ++ } ++ } ++ } ++ ++ if (i==SD_IO_TRY_CNT) ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr=0x%05x val=0x%08x, try_cnt=%d\n", __func__, *err, addr, v, i); ++ else ++ DBG_871X(KERN_ERR "%s: (%d) addr=0x%05x val=0x%08x, try_cnt=%d\n", __func__, *err, addr, v, i); ++ } ++ ++_func_exit_; ++} ++ ++/* ++ * Use CMD53 to read data from SDIO device. ++ * This function MUST be called after sdio_claim_host() or ++ * in SDIO ISR(host had been claimed). ++ * ++ * Parameters: ++ * psdio pointer of SDIO_DATA ++ * addr address to read ++ * cnt amount to read ++ * pdata pointer to put data, this should be a "DMA:able scratch buffer"! ++ * ++ * Return: ++ * 0 Success ++ * others Fail ++ */ ++s32 _sd_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ int err= -EPERM; ++ struct sdio_func *func; ++ ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved )!!!\n",__FUNCTION__); ++ return err; ++ } ++ ++ func = psdio->func; ++ ++ if (unlikely((cnt==1) || (cnt==2))) ++ { ++ int i; ++ u8 *pbuf = (u8*)pdata; ++ ++ for (i = 0; i < cnt; i++) ++ { ++ *(pbuf+i) = sdio_readb(func, addr+i, &err); ++ ++ if (err) { ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr=0x%05x\n", __func__, err, addr); ++ break; ++ } ++ } ++ return err; ++ } ++ ++ err = sdio_memcpy_fromio(func, pdata, addr, cnt); ++ if (err) { ++ DBG_871X(KERN_ERR "%s: FAIL(%d)! ADDR=%#x Size=%d\n", __func__, err, addr, cnt); ++ } ++ ++_func_exit_; ++ ++ return err; ++} ++ ++/* ++ * Use CMD53 to read data from SDIO device. ++ * ++ * Parameters: ++ * psdio pointer of SDIO_DATA ++ * addr address to read ++ * cnt amount to read ++ * pdata pointer to put data, this should be a "DMA:able scratch buffer"! ++ * ++ * Return: ++ * 0 Success ++ * others Fail ++ */ ++s32 sd_read(struct intf_hdl * pintfhdl, u32 addr, u32 cnt, void *pdata) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ struct sdio_func *func; ++ bool claim_needed; ++ s32 err= -EPERM; ++ ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved )!!!\n",__FUNCTION__); ++ return err; ++ } ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ err = _sd_read(pintfhdl, addr, cnt, pdata); ++ if (claim_needed) ++ sdio_release_host(func); ++_func_exit_; ++ return err; ++} ++ ++/* ++ * Use CMD53 to write data to SDIO device. ++ * This function MUST be called after sdio_claim_host() or ++ * in SDIO ISR(host had been claimed). ++ * ++ * Parameters: ++ * psdio pointer of SDIO_DATA ++ * addr address to write ++ * cnt amount to write ++ * pdata data pointer, this should be a "DMA:able scratch buffer"! ++ * ++ * Return: ++ * 0 Success ++ * others Fail ++ */ ++s32 _sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ struct sdio_func *func; ++ u32 size; ++ s32 err=-EPERM; ++ ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved )!!!\n",__FUNCTION__); ++ return err; ++ } ++ ++ func = psdio->func; ++// size = sdio_align_size(func, cnt); ++ ++ if (unlikely((cnt==1) || (cnt==2))) ++ { ++ int i; ++ u8 *pbuf = (u8*)pdata; ++ ++ for (i = 0; i < cnt; i++) ++ { ++ sdio_writeb(func, *(pbuf+i), addr+i, &err); ++ if (err) { ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr=0x%05x val=0x%02x\n", __func__, err, addr, *(pbuf+i)); ++ break; ++ } ++ } ++ ++ return err; ++ } ++ ++ size = cnt; ++ err = sdio_memcpy_toio(func, addr, pdata, size); ++ if (err) { ++ DBG_871X(KERN_ERR "%s: FAIL(%d)! ADDR=%#x Size=%d(%d)\n", __func__, err, addr, cnt, size); ++ } ++ ++_func_exit_; ++ ++ return err; ++} ++ ++/* ++ * Use CMD53 to write data to SDIO device. ++ * ++ * Parameters: ++ * psdio pointer of SDIO_DATA ++ * addr address to write ++ * cnt amount to write ++ * pdata data pointer, this should be a "DMA:able scratch buffer"! ++ * ++ * Return: ++ * 0 Success ++ * others Fail ++ */ ++s32 sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) ++{ ++ PADAPTER padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ struct sdio_func *func; ++ bool claim_needed; ++ s32 err=-EPERM; ++_func_enter_; ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if(padapter->bSurpriseRemoved){ ++ //DBG_871X(" %s (padapter->bSurpriseRemoved )!!!\n",__FUNCTION__); ++ return err; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ err = _sd_write(pintfhdl, addr, cnt, pdata); ++ if (claim_needed) ++ sdio_release_host(func); ++_func_exit_; ++ return err; ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/usb_intf.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/usb_intf.c +new file mode 100644 +index 00000000..d3f6dd2d +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/usb_intf.c +@@ -0,0 +1,2142 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _HCI_INTF_C_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifndef CONFIG_USB_HCI ++ ++#error "CONFIG_USB_HCI shall be on!\n" ++ ++#endif ++ ++#include ++#include ++#include ++#include ++#ifdef CONFIG_PLATFORM_RTK_DMP ++#include ++#endif ++ ++#if defined (PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) ++ ++#error "Shall be Linux or Windows, but not both!\n" ++ ++#endif ++ ++#ifdef CONFIG_80211N_HT ++extern int rtw_ht_enable; ++extern int rtw_cbw40_enable; ++extern int rtw_ampdu_enable;//for enable tx_ampdu ++#endif ++ ++#ifdef CONFIG_GLOBAL_UI_PID ++int ui_pid[3] = {0, 0, 0}; ++#endif ++ ++ ++extern int pm_netdev_open(struct net_device *pnetdev,u8 bnormal); ++static int rtw_suspend(struct usb_interface *intf, pm_message_t message); ++static int rtw_resume(struct usb_interface *intf); ++int rtw_resume_process(_adapter *padapter); ++ ++ ++static int rtw_drv_init(struct usb_interface *pusb_intf,const struct usb_device_id *pdid); ++static void rtw_dev_remove(struct usb_interface *pusb_intf); ++ ++static void rtw_dev_shutdown(struct device *dev) ++{ ++ struct usb_interface *usb_intf = container_of(dev, struct usb_interface, dev); ++ struct dvobj_priv *dvobj = usb_get_intfdata(usb_intf); ++ _adapter *adapter = dvobj->if1; ++ int i; ++ ++ DBG_871X("%s\n", __func__); ++ ++ for (i = 0; iiface_nums; i++) { ++ adapter = dvobj->padapters[i]; ++ adapter->bSurpriseRemoved = _TRUE; ++ } ++ ++ ATOMIC_SET(&dvobj->continual_io_error, MAX_CONTINUAL_IO_ERR+1); ++} ++ ++#if (LINUX_VERSION_CODE<=KERNEL_VERSION(2,6,23)) ++/* Some useful macros to use to create struct usb_device_id */ ++ #define USB_DEVICE_ID_MATCH_VENDOR 0x0001 ++ #define USB_DEVICE_ID_MATCH_PRODUCT 0x0002 ++ #define USB_DEVICE_ID_MATCH_DEV_LO 0x0004 ++ #define USB_DEVICE_ID_MATCH_DEV_HI 0x0008 ++ #define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010 ++ #define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020 ++ #define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040 ++ #define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080 ++ #define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100 ++ #define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 ++ #define USB_DEVICE_ID_MATCH_INT_NUMBER 0x0400 ++ ++ ++#define USB_DEVICE_ID_MATCH_INT_INFO \ ++ (USB_DEVICE_ID_MATCH_INT_CLASS | \ ++ USB_DEVICE_ID_MATCH_INT_SUBCLASS | \ ++ USB_DEVICE_ID_MATCH_INT_PROTOCOL) ++ ++ ++#define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, cl, sc, pr) \ ++ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \ ++ | USB_DEVICE_ID_MATCH_DEVICE, \ ++ .idVendor = (vend), \ ++ .idProduct = (prod), \ ++ .bInterfaceClass = (cl), \ ++ .bInterfaceSubClass = (sc), \ ++ .bInterfaceProtocol = (pr) ++ ++ /** ++ * USB_VENDOR_AND_INTERFACE_INFO - describe a specific usb vendor with a class of usb interfaces ++ * @vend: the 16 bit USB Vendor ID ++ * @cl: bInterfaceClass value ++ * @sc: bInterfaceSubClass value ++ * @pr: bInterfaceProtocol value ++ * ++ * This macro is used to create a struct usb_device_id that matches a ++ * specific vendor with a specific class of interfaces. ++ * ++ * This is especially useful when explicitly matching devices that have ++ * vendor specific bDeviceClass values, but standards-compliant interfaces. ++ */ ++#define USB_VENDOR_AND_INTERFACE_INFO(vend, cl, sc, pr) \ ++ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \ ++ | USB_DEVICE_ID_MATCH_VENDOR, \ ++ .idVendor = (vend), \ ++ .bInterfaceClass = (cl), \ ++ .bInterfaceSubClass = (sc), \ ++ .bInterfaceProtocol = (pr) ++ ++/* ----------------------------------------------------------------------- */ ++#endif ++ ++#define USB_VENDER_ID_REALTEK 0x0BDA ++ ++/* DID_USB_v916_20130116 */ ++#define RTL8192C_USB_IDS \ ++ /*=== Realtek demoboard ===*/ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8191)},/* Default ID */ \ ++ /****** 8188CUS ********/ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8176)},/* 8188cu 1*1 dongole */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8170)},/* 8188CE-VAU USB minCard */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817E)},/* 8188CE-VAU USB minCard */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817A)},/* 8188cu Slim Solo */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817B)},/* 8188cu Slim Combo */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817D)},/* 8188RU High-power USB Dongle */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8754)},/* 8188 Combo for BC4 */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817F)},/* 8188RU */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x818A)},/* RTL8188CUS-VL */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x018A)},/* RTL8188CTV */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x17C0)}, /* RTK demoboard - USB-N10E */ \ ++ /****** 8192CUS ********/ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8177)},/* 8191cu 1*2 */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8178)},/* 8192cu 2*2 */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817C)},/* 8192CE-VAU USB minCard */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8191)},/* 8192CU 2*2 */ \ ++ {USB_DEVICE(0x1058, 0x0631)},/* Alpha, 8192CU */ \ ++ /*=== Customer ID ===*/ \ ++ /****** 8188CUS Dongle ********/ \ ++ {USB_DEVICE(0x2019, 0xED17)},/* PCI - Edimax */ \ ++ {USB_DEVICE(0x0DF6, 0x0052)},/* Sitecom - Edimax */ \ ++ {USB_DEVICE(0x7392, 0x7811)},/* Edimax - Edimax */ \ ++ {USB_DEVICE(0x07B8, 0x8189)},/* Abocom - Abocom */ \ ++ {USB_DEVICE(0x0EB0, 0x9071)},/* NO Brand - Etop */ \ ++ {USB_DEVICE(0x06F8, 0xE033)},/* Hercules - Edimax */ \ ++ {USB_DEVICE(0x103C, 0x1629)},/* HP - Lite-On ,8188CUS Slim Combo */ \ ++ {USB_DEVICE(0x2001, 0x3308)},/* D-Link - Alpha */ \ ++ {USB_DEVICE(0x050D, 0x1102)},/* Belkin - Edimax */ \ ++ {USB_DEVICE(0x2019, 0xAB2A)},/* Planex - Abocom */ \ ++ {USB_DEVICE(0x20F4, 0x648B)},/* TRENDnet - Cameo */ \ ++ {USB_DEVICE(0x4855, 0x0090)},/* - Feixun */ \ ++ {USB_DEVICE(0x13D3, 0x3357)},/* - AzureWave */ \ ++ {USB_DEVICE(0x0DF6, 0x005C)},/* Sitecom - Edimax */ \ ++ {USB_DEVICE(0x0BDA, 0x5088)},/* Thinkware - CC&C */ \ ++ {USB_DEVICE(0x4856, 0x0091)},/* NetweeN - Feixun */ \ ++ {USB_DEVICE(0x0846, 0x9041)}, /* Netgear - Cameo */ \ ++ {USB_DEVICE(0x2019, 0x4902)},/* Planex - Etop */ \ ++ {USB_DEVICE(0x2019, 0xAB2E)},/* SW-WF02-AD15 -Abocom */ \ ++ {USB_DEVICE(0x2001, 0x330B)}, /* D-LINK - T&W */ \ ++ {USB_DEVICE(0xCDAB, 0x8010)}, /* - - compare */ \ ++ {USB_DEVICE(0x0B05, 0x17BA)}, /* ASUS - Edimax */ \ ++ {USB_DEVICE(0x0BDA, 0x1E1E)}, /* Intel - - */ \ ++ {USB_DEVICE(0x04BB, 0x094c)}, /* I-O DATA - Edimax */ \ ++ /****** 8188CTV ********/ \ ++ {USB_DEVICE(0xCDAB, 0x8011)}, /* - - compare */ \ ++ {USB_DEVICE(0x0BDA, 0x0A8A)}, /* Sony - Foxconn */ \ ++ /****** 8188 RU ********/ \ ++ {USB_DEVICE(0x0BDA, 0x317F)},/* Netcore,Netcore */ \ ++ /****** 8188CE-VAU ********/ \ ++ {USB_DEVICE(0x13D3, 0x3359)},/* - Azwave */ \ ++ {USB_DEVICE(0x13D3, 0x3358)},/* - Azwave */ \ ++ /****** 8188CUS Slim Solo********/ \ ++ {USB_DEVICE(0x04F2, 0xAFF7)},/* XAVI - XAVI */ \ ++ {USB_DEVICE(0x04F2, 0xAFF9)},/* XAVI - XAVI */ \ ++ {USB_DEVICE(0x04F2, 0xAFFA)},/* XAVI - XAVI */ \ ++ /****** 8188CUS Slim Combo ********/ \ ++ {USB_DEVICE(0x04F2, 0xAFF8)},/* XAVI - XAVI */ \ ++ {USB_DEVICE(0x04F2, 0xAFFB)},/* XAVI - XAVI */ \ ++ {USB_DEVICE(0x04F2, 0xAFFC)},/* XAVI - XAVI */ \ ++ {USB_DEVICE(0x2019, 0x1201)},/* Planex - Vencer */ \ ++ /****** 8192CUS Dongle ********/ \ ++ {USB_DEVICE(0x2001, 0x3307)},/* D-Link - Cameo */ \ ++ {USB_DEVICE(0x2001, 0x330A)},/* D-Link - Alpha */ \ ++ {USB_DEVICE(0x2001, 0x3309)},/* D-Link - Alpha */ \ ++ {USB_DEVICE(0x0586, 0x341F)},/* Zyxel - Abocom */ \ ++ {USB_DEVICE(0x7392, 0x7822)},/* Edimax - Edimax */ \ ++ {USB_DEVICE(0x2019, 0xAB2B)},/* Planex - Abocom */ \ ++ {USB_DEVICE(0x07B8, 0x8178)},/* Abocom - Abocom */ \ ++ {USB_DEVICE(0x07AA, 0x0056)},/* ATKK - Gemtek */ \ ++ {USB_DEVICE(0x4855, 0x0091)},/* - Feixun */ \ ++ {USB_DEVICE(0x050D, 0x2102)},/* Belkin - Sercomm */ \ ++ {USB_DEVICE(0x050D, 0x2103)},/* Belkin - Edimax */ \ ++ {USB_DEVICE(0x20F4, 0x624D)},/* TRENDnet */ \ ++ {USB_DEVICE(0x0DF6, 0x0061)},/* Sitecom - Edimax */ \ ++ {USB_DEVICE(0x0B05, 0x17AB)},/* ASUS - Edimax */ \ ++ {USB_DEVICE(0x0846, 0x9021)},/* Netgear - Sercomm */ \ ++ {USB_DEVICE(0x0846, 0xF001)}, /* Netgear - Sercomm */ \ ++ {USB_DEVICE(0x0E66, 0x0019)},/* Hawking,Edimax */ \ ++ {USB_DEVICE(0x0E66, 0x0020)}, /* Hawking - Edimax */ \ ++ {USB_DEVICE(0x050D, 0x1004)}, /* Belkin - Edimax */ \ ++ {USB_DEVICE(0x0BDA, 0x2E2E)}, /* Intel - - */ \ ++ {USB_DEVICE(0x2357, 0x0100)}, /* TP-Link - TP-Link */ \ ++ {USB_DEVICE(0x06F8, 0xE035)}, /* Hercules - Edimax */ \ ++ {USB_DEVICE(0x04BB, 0x0950)}, /* IO-DATA - Edimax */ \ ++ {USB_DEVICE(0x0DF6, 0x0070)}, /* Sitecom - Edimax */ \ ++ {USB_DEVICE(0x0789, 0x016D)}, /* LOGITEC - Edimax */ \ ++ /****** 8192CE-VAU ********/ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8186)},/* Intel-Xavi( Azwave) */ ++ ++#define RTL8192D_USB_IDS \ ++ /*=== Realtek demoboard ===*/ \ ++ /****** 8192DU ********/ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8193)},/* 8192DU-VC */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8194)},/* 8192DU-VS */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8111)},/* Realtek 5G dongle for WiFi Display */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0193)},/* 8192DE-VAU */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8171)},/* 8192DU-VC */ \ ++ /*=== Customer ID ===*/ \ ++ /****** 8192DU-VC ********/ \ ++ {USB_DEVICE(0x2019, 0xAB2C)},/* PCI - Abocm */ \ ++ {USB_DEVICE(0x2019, 0x4903)},/* PCI - ETOP */ \ ++ {USB_DEVICE(0x2019, 0x4904)},/* PCI - ETOP */ \ ++ {USB_DEVICE(0x07B8, 0x8193)},/* Abocom - Abocom */ \ ++ /****** 8192DU-VS ********/ \ ++ {USB_DEVICE(0x20F4, 0x664B)}, /* TRENDnet - Cameo */ \ ++ {USB_DEVICE(0x04DD, 0x954F)}, /* Sharp */ \ ++ {USB_DEVICE(0x04DD, 0x96A6)}, /* Sharp */ \ ++ {USB_DEVICE(0x050D, 0x110A)}, /* Belkin - Edimax */ \ ++ {USB_DEVICE(0x050D, 0x1105)}, /* Belkin - Edimax */ \ ++ {USB_DEVICE(0x050D, 0x120A)}, /* Belkin - Edimax */ \ ++ {USB_DEVICE(0x1668, 0x8102)}, /* - */ \ ++ {USB_DEVICE(0x0BDA, 0xE194)}, /* - Edimax */ \ ++ /****** 8192DU-WiFi Display Dongle ********/ \ ++ {USB_DEVICE(0x2019, 0xAB2D)},/* Planex - Abocom ,5G dongle for WiFi Display */ ++ ++#define RTL8723A_USB_IDS \ ++ {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x8724,0xff,0xff,0xff)}, /* 8723AU 1*1 */ \ ++ {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x1724,0xff,0xff,0xff)}, /* 8723AU 1*1 */ \ ++ {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x0724,0xff,0xff,0xff)}, /* 8723AU 1*1 */ ++ ++#define RTL8188E_USB_IDS \ ++ /*=== Realtek demoboard ===*/ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8179)}, /* 8188EUS */ \ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0179)}, /* 8188ETV */ \ ++ /*=== Customer ID ===*/ \ ++ /****** 8188EUS ********/ \ ++ {USB_DEVICE(0x07B8, 0x8179)}, /* Abocom - Abocom */ ++ ++#ifndef CONFIG_RTL8192C ++ #undef RTL8192C_USB_IDS ++ #define RTL8192C_USB_IDS ++#endif ++#ifndef CONFIG_RTL8192D ++ #undef RTL8192D_USB_IDS ++ #define RTL8192D_USB_IDS ++#endif ++#ifndef CONFIG_RTL8723A ++ #undef RTL8723A_USB_IDS ++ #define RTL8723A_USB_IDS ++#endif ++#ifndef CONFIG_RTL8188E ++ #undef RTL8188E_USB_IDS ++ #define RTL8188E_USB_IDS ++#endif ++ ++static struct usb_device_id rtw_usb_id_tbl[] ={ ++ RTL8192C_USB_IDS ++ RTL8192D_USB_IDS ++ RTL8723A_USB_IDS ++ RTL8188E_USB_IDS ++ {} /* Terminating entry */ ++}; ++MODULE_DEVICE_TABLE(usb, rtw_usb_id_tbl); ++ ++int const rtw_usb_id_len = sizeof(rtw_usb_id_tbl) / sizeof(struct usb_device_id); ++ ++static struct specific_device_id specific_device_id_tbl[] = { ++ {.idVendor=USB_VENDER_ID_REALTEK, .idProduct=0x8177, .flags=SPEC_DEV_ID_DISABLE_HT},//8188cu 1*1 dongole, (b/g mode only) ++ {.idVendor=USB_VENDER_ID_REALTEK, .idProduct=0x817E, .flags=SPEC_DEV_ID_DISABLE_HT},//8188CE-VAU USB minCard (b/g mode only) ++ {.idVendor=0x0b05, .idProduct=0x1791, .flags=SPEC_DEV_ID_DISABLE_HT}, ++ {.idVendor=0x13D3, .idProduct=0x3311, .flags=SPEC_DEV_ID_DISABLE_HT}, ++ {.idVendor=0x13D3, .idProduct=0x3359, .flags=SPEC_DEV_ID_DISABLE_HT},//Russian customer -Azwave (8188CE-VAU g mode) ++#ifdef RTK_DMP_PLATFORM ++ {.idVendor=USB_VENDER_ID_REALTEK, .idProduct=0x8111, .flags=SPEC_DEV_ID_ASSIGN_IFNAME}, // Realtek 5G dongle for WiFi Display ++ {.idVendor=0x2019, .idProduct=0xAB2D, .flags=SPEC_DEV_ID_ASSIGN_IFNAME}, // PCI-Abocom 5G dongle for WiFi Display ++#endif /* RTK_DMP_PLATFORM */ ++ {} ++}; ++ ++struct rtw_usb_drv { ++ struct usb_driver usbdrv; ++ int drv_registered; ++}; ++ ++#ifdef CONFIG_RTL8192C ++static struct usb_device_id rtl8192c_usb_id_tbl[] ={ ++ RTL8192C_USB_IDS ++ {} /* Terminating entry */ ++}; ++ ++struct rtw_usb_drv rtl8192c_usb_drv = { ++ .usbdrv.name = (char*)"rtl8192cu", ++ .usbdrv.probe = rtw_drv_init, ++ .usbdrv.disconnect = rtw_dev_remove, ++ .usbdrv.id_table = rtl8192c_usb_id_tbl, ++ .usbdrv.suspend = rtw_suspend, ++ .usbdrv.resume = rtw_resume, ++ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) ++ .usbdrv.reset_resume = rtw_resume, ++ #endif ++ #ifdef CONFIG_AUTOSUSPEND ++ .usbdrv.supports_autosuspend = 1, ++ #endif ++ ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) ++ .usbdrv.drvwrap.driver.shutdown = rtw_dev_shutdown, ++ #else ++ .usbdrv.driver.shutdown = rtw_dev_shutdown, ++ #endif ++}; ++ ++static struct rtw_usb_drv *usb_drv = &rtl8192c_usb_drv; ++#endif /* CONFIG_RTL8192C */ ++ ++#ifdef CONFIG_RTL8192D ++static struct usb_device_id rtl8192d_usb_id_tbl[] ={ ++ RTL8192D_USB_IDS ++ {} /* Terminating entry */ ++}; ++ ++struct rtw_usb_drv rtl8192d_usb_drv = { ++ .usbdrv.name = (char*)"rtl8192du", ++ .usbdrv.probe = rtw_drv_init, ++ .usbdrv.disconnect = rtw_dev_remove, ++ .usbdrv.id_table = rtl8192d_usb_id_tbl, ++ .usbdrv.suspend = rtw_suspend, ++ .usbdrv.resume = rtw_resume, ++ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) ++ .usbdrv.reset_resume = rtw_resume, ++ #endif ++ #ifdef CONFIG_AUTOSUSPEND ++ .usbdrv.supports_autosuspend = 1, ++ #endif ++ ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) ++ .usbdrv.drvwrap.driver.shutdown = rtw_dev_shutdown, ++ #else ++ .usbdrv.driver.shutdown = rtw_dev_shutdown, ++ #endif ++}; ++static struct rtw_usb_drv *usb_drv = &rtl8192d_usb_drv; ++#endif /* CONFIG_RTL8192D */ ++ ++#ifdef CONFIG_RTL8723A ++static struct usb_device_id rtl8723a_usb_id_tbl[] ={ ++ RTL8723A_USB_IDS ++ {} /* Terminating entry */ ++}; ++ ++struct rtw_usb_drv rtl8723a_usb_drv = { ++ .usbdrv.name = (char*)"rtl8723au", ++ .usbdrv.probe = rtw_drv_init, ++ .usbdrv.disconnect = rtw_dev_remove, ++ .usbdrv.id_table = rtl8723a_usb_id_tbl, ++ .usbdrv.suspend = rtw_suspend, ++ .usbdrv.resume = rtw_resume, ++ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) ++ .usbdrv.reset_resume = rtw_resume, ++ #endif ++ #ifdef CONFIG_AUTOSUSPEND ++ .usbdrv.supports_autosuspend = 1, ++ #endif ++ ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) ++ .usbdrv.drvwrap.driver.shutdown = rtw_dev_shutdown, ++ #else ++ .usbdrv.driver.shutdown = rtw_dev_shutdown, ++ #endif ++}; ++ ++static struct rtw_usb_drv *usb_drv = &rtl8723a_usb_drv; ++#endif /* CONFIG_RTL8723A */ ++ ++#ifdef CONFIG_RTL8188E ++static struct usb_device_id rtl8188e_usb_id_tbl[] ={ ++ RTL8188E_USB_IDS ++ {} /* Terminating entry */ ++}; ++ ++struct rtw_usb_drv rtl8188e_usb_drv = { ++ .usbdrv.name = (char*)"rtl8188eu", ++ .usbdrv.probe = rtw_drv_init, ++ .usbdrv.disconnect = rtw_dev_remove, ++ .usbdrv.id_table = rtl8188e_usb_id_tbl, ++ .usbdrv.suspend = rtw_suspend, ++ .usbdrv.resume = rtw_resume, ++ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) ++ .usbdrv.reset_resume = rtw_resume, ++ #endif ++ #ifdef CONFIG_AUTOSUSPEND ++ .usbdrv.supports_autosuspend = 1, ++ #endif ++ ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) ++ .usbdrv.drvwrap.driver.shutdown = rtw_dev_shutdown, ++ #else ++ .usbdrv.driver.shutdown = rtw_dev_shutdown, ++ #endif ++}; ++ ++static struct rtw_usb_drv *usb_drv = &rtl8188e_usb_drv; ++#endif /* CONFIG_RTL8188E */ ++ ++static inline int RT_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) ++{ ++ return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN); ++} ++ ++static inline int RT_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd) ++{ ++ return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); ++} ++ ++static inline int RT_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) ++{ ++ return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT); ++} ++ ++static inline int RT_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) ++{ ++ return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK); ++} ++ ++static inline int RT_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd) ++{ ++ return (RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_in(epd)); ++} ++ ++static inline int RT_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) ++{ ++ return (RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_out(epd)); ++} ++ ++static inline int RT_usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd) ++{ ++ return (RT_usb_endpoint_xfer_int(epd) && RT_usb_endpoint_dir_in(epd)); ++} ++ ++static inline int RT_usb_endpoint_num(const struct usb_endpoint_descriptor *epd) ++{ ++ return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; ++} ++ ++static u8 rtw_init_intf_priv(struct dvobj_priv *dvobj) ++{ ++ u8 rst = _SUCCESS; ++ ++ #ifdef CONFIG_USB_VENDOR_REQ_MUTEX ++ _rtw_mutex_init(&dvobj->usb_vendor_req_mutex); ++ #endif ++ ++ ++ #ifdef CONFIG_USB_VENDOR_REQ_BUFFER_PREALLOC ++ dvobj->usb_alloc_vendor_req_buf = rtw_zmalloc(MAX_USB_IO_CTL_SIZE); ++ if (dvobj->usb_alloc_vendor_req_buf == NULL) { ++ DBG_871X("alloc usb_vendor_req_buf failed... /n"); ++ rst = _FAIL; ++ goto exit; ++ } ++ dvobj->usb_vendor_req_buf = ++ (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(dvobj->usb_alloc_vendor_req_buf ), ALIGNMENT_UNIT); ++exit: ++ #endif ++ ++ return rst; ++ ++} ++ ++static u8 rtw_deinit_intf_priv(struct dvobj_priv *dvobj) ++{ ++ u8 rst = _SUCCESS; ++ ++ #ifdef CONFIG_USB_VENDOR_REQ_BUFFER_PREALLOC ++ if(dvobj->usb_vendor_req_buf) ++ rtw_mfree(dvobj->usb_alloc_vendor_req_buf, MAX_USB_IO_CTL_SIZE); ++ #endif ++ ++ #ifdef CONFIG_USB_VENDOR_REQ_MUTEX ++ _rtw_mutex_free(&dvobj->usb_vendor_req_mutex); ++ #endif ++ ++ return rst; ++} ++ ++static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) ++{ ++ int i; ++ u8 val8; ++ int status = _FAIL; ++ struct dvobj_priv *pdvobjpriv; ++ struct usb_device_descriptor *pdev_desc; ++ struct usb_host_config *phost_conf; ++ struct usb_config_descriptor *pconf_desc; ++ struct usb_host_interface *phost_iface; ++ struct usb_interface_descriptor *piface_desc; ++ struct usb_host_endpoint *phost_endp; ++ struct usb_endpoint_descriptor *pendp_desc; ++ struct usb_device *pusbd; ++ ++_func_enter_; ++ ++ if ((pdvobjpriv = (struct dvobj_priv*)rtw_zmalloc(sizeof(*pdvobjpriv))) == NULL) { ++ goto exit; ++ } ++ ++ _rtw_mutex_init(&pdvobjpriv->hw_init_mutex); ++ _rtw_mutex_init(&pdvobjpriv->h2c_fwcmd_mutex); ++ _rtw_mutex_init(&pdvobjpriv->setch_mutex); ++ _rtw_mutex_init(&pdvobjpriv->setbw_mutex); ++ pdvobjpriv->processing_dev_remove = _FALSE; ++ ++ pdvobjpriv->pusbintf = usb_intf ; ++ pusbd = pdvobjpriv->pusbdev = interface_to_usbdev(usb_intf); ++ usb_set_intfdata(usb_intf, pdvobjpriv); ++ ++ pdvobjpriv->RtNumInPipes = 0; ++ pdvobjpriv->RtNumOutPipes = 0; ++ ++ //padapter->EepromAddressSize = 6; ++ //pdvobjpriv->nr_endpoint = 6; ++ ++ pdev_desc = &pusbd->descriptor; ++ ++#if 0 ++ DBG_871X("\n8712_usb_device_descriptor:\n"); ++ DBG_871X("bLength=%x\n", pdev_desc->bLength); ++ DBG_871X("bDescriptorType=%x\n", pdev_desc->bDescriptorType); ++ DBG_871X("bcdUSB=%x\n", pdev_desc->bcdUSB); ++ DBG_871X("bDeviceClass=%x\n", pdev_desc->bDeviceClass); ++ DBG_871X("bDeviceSubClass=%x\n", pdev_desc->bDeviceSubClass); ++ DBG_871X("bDeviceProtocol=%x\n", pdev_desc->bDeviceProtocol); ++ DBG_871X("bMaxPacketSize0=%x\n", pdev_desc->bMaxPacketSize0); ++ DBG_871X("idVendor=%x\n", pdev_desc->idVendor); ++ DBG_871X("idProduct=%x\n", pdev_desc->idProduct); ++ DBG_871X("bcdDevice=%x\n", pdev_desc->bcdDevice); ++ DBG_871X("iManufacturer=%x\n", pdev_desc->iManufacturer); ++ DBG_871X("iProduct=%x\n", pdev_desc->iProduct); ++ DBG_871X("iSerialNumber=%x\n", pdev_desc->iSerialNumber); ++ DBG_871X("bNumConfigurations=%x\n", pdev_desc->bNumConfigurations); ++#endif ++ ++ phost_conf = pusbd->actconfig; ++ pconf_desc = &phost_conf->desc; ++ ++#if 0 ++ DBG_871X("\n8712_usb_configuration_descriptor:\n"); ++ DBG_871X("bLength=%x\n", pconf_desc->bLength); ++ DBG_871X("bDescriptorType=%x\n", pconf_desc->bDescriptorType); ++ DBG_871X("wTotalLength=%x\n", pconf_desc->wTotalLength); ++ DBG_871X("bNumInterfaces=%x\n", pconf_desc->bNumInterfaces); ++ DBG_871X("bConfigurationValue=%x\n", pconf_desc->bConfigurationValue); ++ DBG_871X("iConfiguration=%x\n", pconf_desc->iConfiguration); ++ DBG_871X("bmAttributes=%x\n", pconf_desc->bmAttributes); ++ DBG_871X("bMaxPower=%x\n", pconf_desc->bMaxPower); ++#endif ++ ++ //DBG_871X("\n/****** num of altsetting = (%d) ******/\n", pusb_interface->num_altsetting); ++ ++ phost_iface = &usb_intf->altsetting[0]; ++ piface_desc = &phost_iface->desc; ++ ++#if 0 ++ DBG_871X("\n8712_usb_interface_descriptor:\n"); ++ DBG_871X("bLength=%x\n", piface_desc->bLength); ++ DBG_871X("bDescriptorType=%x\n", piface_desc->bDescriptorType); ++ DBG_871X("bInterfaceNumber=%x\n", piface_desc->bInterfaceNumber); ++ DBG_871X("bAlternateSetting=%x\n", piface_desc->bAlternateSetting); ++ DBG_871X("bNumEndpoints=%x\n", piface_desc->bNumEndpoints); ++ DBG_871X("bInterfaceClass=%x\n", piface_desc->bInterfaceClass); ++ DBG_871X("bInterfaceSubClass=%x\n", piface_desc->bInterfaceSubClass); ++ DBG_871X("bInterfaceProtocol=%x\n", piface_desc->bInterfaceProtocol); ++ DBG_871X("iInterface=%x\n", piface_desc->iInterface); ++#endif ++ ++ pdvobjpriv->NumInterfaces = pconf_desc->bNumInterfaces; ++ pdvobjpriv->InterfaceNumber = piface_desc->bInterfaceNumber; ++ pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints; ++ ++ //DBG_871X("\ndump usb_endpoint_descriptor:\n"); ++ ++ for (i = 0; i < pdvobjpriv->nr_endpoint; i++) ++ { ++ phost_endp = phost_iface->endpoint + i; ++ if (phost_endp) ++ { ++ pendp_desc = &phost_endp->desc; ++ ++ DBG_871X("\nusb_endpoint_descriptor(%d):\n", i); ++ DBG_871X("bLength=%x\n",pendp_desc->bLength); ++ DBG_871X("bDescriptorType=%x\n",pendp_desc->bDescriptorType); ++ DBG_871X("bEndpointAddress=%x\n",pendp_desc->bEndpointAddress); ++ //DBG_871X("bmAttributes=%x\n",pendp_desc->bmAttributes); ++ DBG_871X("wMaxPacketSize=%d\n",le16_to_cpu(pendp_desc->wMaxPacketSize)); ++ DBG_871X("bInterval=%x\n",pendp_desc->bInterval); ++ //DBG_871X("bRefresh=%x\n",pendp_desc->bRefresh); ++ //DBG_871X("bSynchAddress=%x\n",pendp_desc->bSynchAddress); ++ ++ if (RT_usb_endpoint_is_bulk_in(pendp_desc)) ++ { ++ DBG_871X("RT_usb_endpoint_is_bulk_in = %x\n", RT_usb_endpoint_num(pendp_desc)); ++ pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = RT_usb_endpoint_num(pendp_desc); ++ pdvobjpriv->RtNumInPipes++; ++ } ++ else if (RT_usb_endpoint_is_int_in(pendp_desc)) ++ { ++ DBG_871X("RT_usb_endpoint_is_int_in = %x, Interval = %x\n", RT_usb_endpoint_num(pendp_desc),pendp_desc->bInterval); ++ pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = RT_usb_endpoint_num(pendp_desc); ++ pdvobjpriv->RtNumInPipes++; ++ } ++ else if (RT_usb_endpoint_is_bulk_out(pendp_desc)) ++ { ++ DBG_871X("RT_usb_endpoint_is_bulk_out = %x\n", RT_usb_endpoint_num(pendp_desc)); ++ pdvobjpriv->RtOutPipe[pdvobjpriv->RtNumOutPipes] = RT_usb_endpoint_num(pendp_desc); ++ pdvobjpriv->RtNumOutPipes++; ++ } ++ pdvobjpriv->ep_num[i] = RT_usb_endpoint_num(pendp_desc); ++ } ++ } ++ ++ DBG_871X("nr_endpoint=%d, in_num=%d, out_num=%d\n\n", pdvobjpriv->nr_endpoint, pdvobjpriv->RtNumInPipes, pdvobjpriv->RtNumOutPipes); ++ ++ if (pusbd->speed == USB_SPEED_HIGH) { ++ pdvobjpriv->ishighspeed = _TRUE; ++ DBG_871X("USB_SPEED_HIGH\n"); ++ } else { ++ pdvobjpriv->ishighspeed = _FALSE; ++ DBG_871X("NON USB_SPEED_HIGH\n"); ++ } ++ ++ if (rtw_init_intf_priv(pdvobjpriv) == _FAIL) { ++ RT_TRACE(_module_os_intfs_c_,_drv_err_,("\n Can't INIT rtw_init_intf_priv\n")); ++ goto free_dvobj; ++ } ++ ++ //.3 misc ++ _rtw_init_sema(&(pdvobjpriv->usb_suspend_sema), 0); ++ rtw_reset_continual_io_error(pdvobjpriv); ++ ++ usb_get_dev(pusbd); ++ ++ status = _SUCCESS; ++ ++free_dvobj: ++ if (status != _SUCCESS && pdvobjpriv) { ++ usb_set_intfdata(usb_intf, NULL); ++ _rtw_mutex_free(&pdvobjpriv->hw_init_mutex); ++ _rtw_mutex_free(&pdvobjpriv->h2c_fwcmd_mutex); ++ _rtw_mutex_free(&pdvobjpriv->setch_mutex); ++ _rtw_mutex_free(&pdvobjpriv->setbw_mutex); ++ rtw_mfree((u8*)pdvobjpriv, sizeof(*pdvobjpriv)); ++ pdvobjpriv = NULL; ++ } ++exit: ++_func_exit_; ++ return pdvobjpriv; ++} ++ ++static void usb_dvobj_deinit(struct usb_interface *usb_intf) ++{ ++ struct dvobj_priv *dvobj = usb_get_intfdata(usb_intf); ++ ++_func_enter_; ++ ++ usb_set_intfdata(usb_intf, NULL); ++ if (dvobj) { ++ //Modify condition for 92DU DMDP 2010.11.18, by Thomas ++ if ((dvobj->NumInterfaces != 2 && dvobj->NumInterfaces != 3) ++ || (dvobj->InterfaceNumber == 1)) { ++ if (interface_to_usbdev(usb_intf)->state != USB_STATE_NOTATTACHED) { ++ //If we didn't unplug usb dongle and remove/insert modlue, driver fails on sitesurvey for the first time when device is up . ++ //Reset usb port for sitesurvey fail issue. 2009.8.13, by Thomas ++ DBG_871X("usb attached..., try to reset usb device\n"); ++ usb_reset_device(interface_to_usbdev(usb_intf)); ++ } ++ } ++ rtw_deinit_intf_priv(dvobj); ++ _rtw_mutex_free(&dvobj->hw_init_mutex); ++ _rtw_mutex_free(&dvobj->h2c_fwcmd_mutex); ++ _rtw_mutex_free(&dvobj->setch_mutex); ++ _rtw_mutex_free(&dvobj->setbw_mutex); ++ rtw_mfree((u8*)dvobj, sizeof(*dvobj)); ++ } ++ ++ //DBG_871X("%s %d\n", __func__, ATOMIC_READ(&usb_intf->dev.kobj.kref.refcount)); ++ usb_put_dev(interface_to_usbdev(usb_intf)); ++ ++_func_exit_; ++} ++ ++static void decide_chip_type_by_usb_device_id(_adapter *padapter, const struct usb_device_id *pdid) ++{ ++ padapter->chip_type = NULL_CHIP_TYPE; ++ hal_set_hw_type(padapter); ++} ++ ++static void usb_intf_start(_adapter *padapter) ++{ ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("+usb_intf_start\n")); ++ ++ rtw_hal_inirp_init(padapter); ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("-usb_intf_start\n")); ++ ++} ++ ++static void usb_intf_stop(_adapter *padapter) ++{ ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("+usb_intf_stop\n")); ++ ++ //disabel_hw_interrupt ++ if(padapter->bSurpriseRemoved == _FALSE) ++ { ++ //device still exists, so driver can do i/o operation ++ //TODO: ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("SurpriseRemoved==_FALSE\n")); ++ } ++ ++ //cancel in irp ++ rtw_hal_inirp_deinit(padapter); ++ ++ //cancel out irp ++ rtw_write_port_cancel(padapter); ++ ++ //todo:cancel other irps ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("-usb_intf_stop\n")); ++ ++} ++ ++void rtw_dev_unload(_adapter *padapter) ++{ ++ struct net_device *pnetdev= (struct net_device*)padapter->pnetdev; ++ u8 val8; ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("+rtw_dev_unload\n")); ++ ++ if(padapter->bup == _TRUE) ++ { ++ DBG_871X("===> rtw_dev_unload\n"); ++ ++ padapter->bDriverStopped = _TRUE; ++ #ifdef CONFIG_XMIT_ACK ++ if (padapter->xmitpriv.ack_tx) ++ rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_DRV_STOP); ++ #endif ++ ++ //s3. ++ if(padapter->intf_stop) ++ { ++ padapter->intf_stop(padapter); ++ } ++ ++ //s4. ++ if(!adapter_to_pwrctl(padapter)->bInternalAutoSuspend ) ++ rtw_stop_drv_threads(padapter); ++ ++ ++ //s5. ++ if(padapter->bSurpriseRemoved == _FALSE) ++ { ++ //DBG_871X("r871x_dev_unload()->rtl871x_hal_deinit()\n"); ++#ifdef CONFIG_WOWLAN ++ if((adapter_to_pwrctl(padapter)->bSupportRemoteWakeup==_TRUE)&&(adapter_to_pwrctl(padapter)->wowlan_mode==_TRUE)){ ++ DBG_871X("%s bSupportWakeOnWlan==_TRUE do not run rtw_hal_deinit()\n",__FUNCTION__); ++ } ++ else ++#endif //CONFIG_WOWLAN ++ { ++ rtw_hal_deinit(padapter); ++ } ++ padapter->bSurpriseRemoved = _TRUE; ++ } ++ ++ padapter->bup = _FALSE; ++#ifdef CONFIG_WOWLAN ++ padapter->hw_init_completed=_FALSE; ++#endif //CONFIG_WOWLAN ++ } ++ else ++ { ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("r871x_dev_unload():padapter->bup == _FALSE\n" )); ++ } ++ ++ DBG_871X("<=== rtw_dev_unload\n"); ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("-rtw_dev_unload\n")); ++ ++} ++ ++static void process_spec_devid(const struct usb_device_id *pdid) ++{ ++ u16 vid, pid; ++ u32 flags; ++ int i; ++ int num = sizeof(specific_device_id_tbl)/sizeof(struct specific_device_id); ++ ++ for(i=0; iidVendor==vid) && (pdid->idProduct==pid) && (flags&SPEC_DEV_ID_DISABLE_HT)) ++ { ++ rtw_ht_enable = 0; ++ rtw_cbw40_enable = 0; ++ rtw_ampdu_enable = 0; ++ } ++#endif ++ ++#ifdef RTK_DMP_PLATFORM ++ // Change the ifname to wlan10 when PC side WFD dongle plugin on DMP platform. ++ // It is used to distinguish between normal and PC-side wifi dongle/module. ++ if((pdid->idVendor==vid) && (pdid->idProduct==pid) && (flags&SPEC_DEV_ID_ASSIGN_IFNAME)) ++ { ++ extern char* ifname; ++ strncpy(ifname, "wlan10", 6); ++ //DBG_871X("%s()-%d: ifname=%s, vid=%04X, pid=%04X\n", __FUNCTION__, __LINE__, ifname, vid, pid); ++ } ++#endif /* RTK_DMP_PLATFORM */ ++ ++ } ++} ++ ++#ifdef SUPPORT_HW_RFOFF_DETECTED ++int rtw_hw_suspend(_adapter *padapter ) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct usb_interface *pusb_intf = adapter_to_dvobj(padapter)->pusbintf; ++ struct net_device *pnetdev = padapter->pnetdev; ++ ++ _func_enter_; ++ ++ if((!padapter->bup) || (padapter->bDriverStopped)||(padapter->bSurpriseRemoved)) ++ { ++ DBG_871X("padapter->bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n", ++ padapter->bup, padapter->bDriverStopped,padapter->bSurpriseRemoved); ++ goto error_exit; ++ } ++ ++ if(padapter)//system suspend ++ { ++ LeaveAllPowerSaveMode(padapter); ++ ++ DBG_871X("==> rtw_hw_suspend\n"); ++ _enter_pwrlock(&pwrpriv->lock); ++ pwrpriv->bips_processing = _TRUE; ++ //padapter->net_closed = _TRUE; ++ //s1. ++ if(pnetdev) ++ { ++ netif_carrier_off(pnetdev); ++ rtw_netif_stop_queue(pnetdev); ++ } ++ ++ //s2. ++ rtw_disassoc_cmd(padapter, 500, _FALSE); ++ ++ //s2-2. indicate disconnect to os ++ //rtw_indicate_disconnect(padapter); ++ { ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ if(check_fwstate(pmlmepriv, _FW_LINKED)) ++ { ++ _clr_fwstate_(pmlmepriv, _FW_LINKED); ++ ++ rtw_led_control(padapter, LED_CTL_NO_LINK); ++ ++ rtw_os_indicate_disconnect(padapter); ++ ++ #ifdef CONFIG_LPS ++ //donnot enqueue cmd ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_DISCONNECT, 0); ++ #endif ++ } ++ ++ } ++ //s2-3. ++ rtw_free_assoc_resources(padapter, 1); ++ ++ //s2-4. ++ rtw_free_network_queue(padapter,_TRUE); ++ #ifdef CONFIG_IPS ++ rtw_ips_dev_unload(padapter); ++ #endif ++ pwrpriv->rf_pwrstate = rf_off; ++ pwrpriv->bips_processing = _FALSE; ++ ++ _exit_pwrlock(&pwrpriv->lock); ++ } ++ else ++ goto error_exit; ++ ++ _func_exit_; ++ return 0; ++ ++error_exit: ++ DBG_871X("%s, failed \n",__FUNCTION__); ++ return (-1); ++ ++} ++ ++int rtw_hw_resume(_adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct usb_interface *pusb_intf = adapter_to_dvobj(padapter)->pusbintf; ++ struct net_device *pnetdev = padapter->pnetdev; ++ ++ _func_enter_; ++ ++ if(padapter)//system resume ++ { ++ DBG_871X("==> rtw_hw_resume\n"); ++ _enter_pwrlock(&pwrpriv->lock); ++ pwrpriv->bips_processing = _TRUE; ++ rtw_reset_drv_sw(padapter); ++ ++ if(pm_netdev_open(pnetdev,_FALSE) != 0) ++ { ++ _exit_pwrlock(&pwrpriv->lock); ++ goto error_exit; ++ } ++ ++ netif_device_attach(pnetdev); ++ netif_carrier_on(pnetdev); ++ ++ if(!rtw_netif_queue_stopped(pnetdev)) ++ rtw_netif_start_queue(pnetdev); ++ else ++ rtw_netif_wake_queue(pnetdev); ++ ++ pwrpriv->bkeepfwalive = _FALSE; ++ pwrpriv->brfoffbyhw = _FALSE; ++ ++ pwrpriv->rf_pwrstate = rf_on; ++ pwrpriv->bips_processing = _FALSE; ++ ++ _exit_pwrlock(&pwrpriv->lock); ++ } ++ else ++ { ++ goto error_exit; ++ } ++ ++ _func_exit_; ++ ++ return 0; ++error_exit: ++ DBG_871X("%s, Open net dev failed \n",__FUNCTION__); ++ return (-1); ++} ++#endif ++ ++#if 1 ++#ifdef CONFIG_WOWLAN ++static void rtw_suspend_wow(_adapter *padapter) ++{ ++ struct net_device *pnetdev = padapter->pnetdev; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct wifidirect_info* pwdinfo = &padapter->wdinfo; ++ struct wowlan_ioctl_param poidparam; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) ++ pwrpriv->wowlan_mode = _TRUE; ++ else ++ pwrpriv->wowlan_mode = _FALSE; ++ ++ rtw_cancel_all_timer(padapter); ++ LeaveAllPowerSaveMode(padapter); ++ ++ rtw_stop_cmd_thread(padapter); ++ ++ ++ //padapter->net_closed = _TRUE; ++ //s1. ++ if(pnetdev) ++ { ++ netif_carrier_off(pnetdev); ++ rtw_netif_stop_queue(pnetdev); ++ } ++ ++ if(pwrpriv->bSupportRemoteWakeup==_TRUE && pwrpriv->wowlan_mode==_TRUE){ ++ //set H2C command ++ poidparam.subcode=WOWLAN_ENABLE; ++ padapter->HalFunc.SetHwRegHandler(padapter,HW_VAR_WOWLAN,(u8 *)&poidparam); ++ } ++ else ++ { ++ //s2. ++ rtw_disassoc_cmd(padapter, 0, _FALSE); ++ } ++ ++ ++#ifdef CONFIG_LAYER2_ROAMING_RESUME ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED)&& rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ { ++ //DBG_871X("%s:%d assoc_ssid:%s\n", __FUNCTION__, __LINE__, pmlmepriv->assoc_ssid.Ssid); ++ DBG_871X("%s:%d %s(" MAC_FMT "), length:%d assoc_ssid.length:%d\n",__FUNCTION__, __LINE__, ++ pmlmepriv->cur_network.network.Ssid.Ssid, ++ MAC_ARG(pmlmepriv->cur_network.network.MacAddress), ++ pmlmepriv->cur_network.network.Ssid.SsidLength, ++ pmlmepriv->assoc_ssid.SsidLength); ++ ++ rtw_set_roaming(padapter, 1); ++ } ++#endif ++ //s2-2. indicate disconnect to os ++ rtw_indicate_disconnect(padapter); ++ //s2-3. ++ rtw_free_assoc_resources(padapter, 1); ++#ifdef CONFIG_AUTOSUSPEND ++ if(!pwrpriv->bInternalAutoSuspend ) ++#endif ++ //s2-4. ++ rtw_free_network_queue(padapter, _TRUE); ++ ++ rtw_dev_unload(padapter); ++ ++ if(check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) ++ rtw_indicate_scan_done(padapter, 1); ++ ++ //if(check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) ++ // rtw_indicate_disconnect(padapter); ++ ++} ++#endif ++static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message) ++{ ++ struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf); ++ _adapter *padapter = dvobj->if1; ++ struct net_device *pnetdev = padapter->pnetdev; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj); ++ struct usb_device *usb_dev = interface_to_usbdev(pusb_intf); ++ ++ ++ int ret = 0; ++ u32 start_time = rtw_get_current_time(); ++ ++ _func_enter_; ++ ++ DBG_871X("==> %s (%s:%d)\n",__FUNCTION__, current->comm, current->pid); ++ ++ ++#ifdef CONFIG_IOL_READ_EFUSE_MAP ++ if(!padapter->bup){ ++ u8 bMacPwrCtrlOn = _FALSE; ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if(bMacPwrCtrlOn) ++ rtw_hal_power_off(padapter); ++ } ++#endif ++ ++ if((!padapter->bup) || (padapter->bDriverStopped)||(padapter->bSurpriseRemoved)) ++ { ++ DBG_871X("padapter->bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n", ++ padapter->bup, padapter->bDriverStopped,padapter->bSurpriseRemoved); ++ goto exit; ++ } ++ ++ if(pwrpriv->bInternalAutoSuspend ) ++ { ++ #ifdef CONFIG_AUTOSUSPEND ++ #ifdef SUPPORT_HW_RFOFF_DETECTED ++ // The FW command register update must after MAC and FW init ready. ++ if((padapter->bFWReady) && (pwrpriv->bHWPwrPindetect ) && (padapter->registrypriv.usbss_enable )) ++ { ++ u8 bOpen = _TRUE; ++ rtw_interface_ps_func(padapter,HAL_USB_SELECT_SUSPEND,&bOpen); ++ //rtl8192c_set_FwSelectSuspend_cmd(padapter,_TRUE ,500);//note fw to support hw power down ping detect ++ } ++ #endif ++ #endif ++ } ++ ++ pwrpriv->bInSuspend = _TRUE; ++ ++ _enter_pwrlock(&pwrpriv->lock); ++#ifdef CONFIG_WOWLAN ++ rtw_suspend_wow(padapter); ++#else ++ rtw_suspend_common(padapter); ++#endif ++ ++#ifdef CONFIG_AUTOSUSPEND ++ pwrpriv->rf_pwrstate = rf_off; ++ pwrpriv->bips_processing = _FALSE; ++#endif ++ _exit_pwrlock(&pwrpriv->lock); ++ ++ ++exit: ++ DBG_871X("<=== %s return %d.............. in %dms\n", __FUNCTION__ ++ , ret, rtw_get_passing_time_ms(start_time)); ++ ++ _func_exit_; ++ return ret; ++} ++#else ++static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message) ++{ ++ struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf); ++ _adapter *padapter = dvobj->if1; ++ struct net_device *pnetdev = padapter->pnetdev; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj); ++ struct usb_device *usb_dev = interface_to_usbdev(pusb_intf); ++#ifdef CONFIG_WOWLAN ++ struct wowlan_ioctl_param poidparam; ++#endif // CONFIG_WOWLAN ++ ++ int ret = 0; ++ u32 start_time = rtw_get_current_time(); ++ ++ _func_enter_; ++ ++ DBG_871X("==> %s (%s:%d)\n",__FUNCTION__, current->comm, current->pid); ++ ++#ifdef CONFIG_WOWLAN ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) ++ pwrpriv->wowlan_mode = _TRUE; ++ else ++ pwrpriv->wowlan_mode = _FALSE; ++#endif ++ ++ if((!padapter->bup) || (padapter->bDriverStopped)||(padapter->bSurpriseRemoved)) ++ { ++ DBG_871X("padapter->bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n", ++ padapter->bup, padapter->bDriverStopped,padapter->bSurpriseRemoved); ++ goto exit; ++ } ++ ++ if(pwrpriv->bInternalAutoSuspend ) ++ { ++ #ifdef CONFIG_AUTOSUSPEND ++ #ifdef SUPPORT_HW_RFOFF_DETECTED ++ // The FW command register update must after MAC and FW init ready. ++ if((padapter->bFWReady) && (pwrpriv->bHWPwrPindetect ) && (padapter->registrypriv.usbss_enable )) ++ { ++ u8 bOpen = _TRUE; ++ rtw_interface_ps_func(padapter,HAL_USB_SELECT_SUSPEND,&bOpen); ++ //rtl8192c_set_FwSelectSuspend_cmd(padapter,_TRUE ,500);//note fw to support hw power down ping detect ++ } ++ #endif ++ #endif ++ } ++ pwrpriv->bInSuspend = _TRUE; ++ rtw_cancel_all_timer(padapter); ++ LeaveAllPowerSaveMode(padapter); ++ ++ rtw_stop_cmd_thread(padapter); ++ ++ _enter_pwrlock(&pwrpriv->lock); ++ //padapter->net_closed = _TRUE; ++ //s1. ++ if(pnetdev) ++ { ++ netif_carrier_off(pnetdev); ++ rtw_netif_stop_queue(pnetdev); ++ } ++ ++#ifdef CONFIG_WOWLAN ++ if(pwrpriv->bSupportRemoteWakeup==_TRUE && pwrpriv->wowlan_mode==_TRUE){ ++ //set H2C command ++ poidparam.subcode=WOWLAN_ENABLE; ++ padapter->HalFunc.SetHwRegHandler(padapter,HW_VAR_WOWLAN,(u8 *)&poidparam); ++ } ++ else ++#else ++ { ++ //s2. ++ rtw_disassoc_cmd(padapter, 0, _FALSE); ++ } ++#endif //CONFIG_WOWLAN ++ ++#ifdef CONFIG_LAYER2_ROAMING_RESUME ++ if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED) ) ++ { ++ //DBG_871X("%s:%d assoc_ssid:%s\n", __FUNCTION__, __LINE__, pmlmepriv->assoc_ssid.Ssid); ++ DBG_871X("%s:%d %s(" MAC_FMT "), length:%d assoc_ssid.length:%d\n",__FUNCTION__, __LINE__, ++ pmlmepriv->cur_network.network.Ssid.Ssid, ++ MAC_ARG(pmlmepriv->cur_network.network.MacAddress), ++ pmlmepriv->cur_network.network.Ssid.SsidLength, ++ pmlmepriv->assoc_ssid.SsidLength); ++ ++ rtw_set_roaming(padapter, 1); ++ } ++#endif ++ //s2-2. indicate disconnect to os ++ rtw_indicate_disconnect(padapter); ++ //s2-3. ++ rtw_free_assoc_resources(padapter, 1); ++#ifdef CONFIG_AUTOSUSPEND ++ if(!pwrpriv->bInternalAutoSuspend ) ++#endif ++ //s2-4. ++ rtw_free_network_queue(padapter, _TRUE); ++ ++ rtw_dev_unload(padapter); ++#ifdef CONFIG_AUTOSUSPEND ++ pwrpriv->rf_pwrstate = rf_off; ++ pwrpriv->bips_processing = _FALSE; ++#endif ++ _exit_pwrlock(&pwrpriv->lock); ++ ++ if(check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) ++ rtw_indicate_scan_done(padapter, 1); ++ ++ if(check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) ++ rtw_indicate_disconnect(padapter); ++ ++exit: ++ DBG_871X("<=== %s return %d.............. in %dms\n", __FUNCTION__ ++ , ret, rtw_get_passing_time_ms(start_time)); ++ ++ _func_exit_; ++ return ret; ++} ++ ++#endif ++static int rtw_resume(struct usb_interface *pusb_intf) ++{ ++ struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf); ++ _adapter *padapter = dvobj->if1; ++ struct net_device *pnetdev = padapter->pnetdev; ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj); ++ int ret = 0; ++ ++ if(pwrpriv->bInternalAutoSuspend ){ ++ ret = rtw_resume_process(padapter); ++ } else { ++#ifdef CONFIG_RESUME_IN_WORKQUEUE ++ rtw_resume_in_workqueue(pwrpriv); ++#else ++ if (rtw_is_earlysuspend_registered(pwrpriv) ++ #ifdef CONFIG_WOWLAN ++ && !pwrpriv->wowlan_mode ++ #endif /* CONFIG_WOWLAN */ ++ ) { ++ /* jeff: bypass resume here, do in late_resume */ ++ rtw_set_do_late_resume(pwrpriv, _TRUE); ++ } else { ++ ret = rtw_resume_process(padapter); ++ } ++#endif /* CONFIG_RESUME_IN_WORKQUEUE */ ++ } ++ ++ return ret; ++ ++} ++ ++int rtw_resume_process(_adapter *padapter) ++{ ++ struct net_device *pnetdev; ++ struct pwrctrl_priv *pwrpriv; ++ int ret = -1; ++ u32 start_time = rtw_get_current_time(); ++#ifdef CONFIG_BT_COEXIST ++ u8 pm_cnt; ++#endif //#ifdef CONFIG_BT_COEXIST ++ _func_enter_; ++ ++ DBG_871X("==> %s (%s:%d)\n",__FUNCTION__, current->comm, current->pid); ++ ++ if(padapter) { ++ pnetdev= padapter->pnetdev; ++ pwrpriv = adapter_to_pwrctl(padapter); ++ } else { ++ goto exit; ++ } ++ ++ _enter_pwrlock(&pwrpriv->lock); ++#ifdef CONFIG_BT_COEXIST ++#ifdef CONFIG_AUTOSUSPEND ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,32)) ++ DBG_871X("%s...pm_usage_cnt(%d) pwrpriv->bAutoResume=%x. ....\n",__func__,atomic_read(&(adapter_to_dvobj(padapter)->pusbintf->pm_usage_cnt)),pwrpriv->bAutoResume); ++ pm_cnt=atomic_read(&(adapter_to_dvobj(padapter)->pusbintf->pm_usage_cnt)); ++ #else ++ DBG_871X("...pm_usage_cnt(%d).....\n", adapter_to_dvobj(padapter)->pusbintf->pm_usage_cnt); ++ pm_cnt = adapter_to_dvobj(padapter)->pusbintf->pm_usage_cnt; ++ #endif ++ ++ DBG_871X("pwrpriv->bAutoResume (%x)\n",pwrpriv->bAutoResume ); ++ if( _TRUE == pwrpriv->bAutoResume ){ ++ pwrpriv->bInternalAutoSuspend = _FALSE; ++ pwrpriv->bAutoResume=_FALSE; ++ DBG_871X("pwrpriv->bAutoResume (%x) pwrpriv->bInternalAutoSuspend(%x)\n",pwrpriv->bAutoResume,pwrpriv->bInternalAutoSuspend ); ++ ++ } ++#endif //#ifdef CONFIG_AUTOSUSPEND ++#endif //#ifdef CONFIG_BT_COEXIST ++ ++ ++ if(rtw_resume_common(padapter)!= 0) { ++ DBG_871X("%s rtw_resume_common failed\n",__FUNCTION__); ++ _exit_pwrlock(&pwrpriv->lock); ++ goto exit; ++ } ++ ++#ifdef CONFIG_AUTOSUSPEND ++ if(pwrpriv->bInternalAutoSuspend ) ++ { ++ #ifdef CONFIG_AUTOSUSPEND ++ #ifdef SUPPORT_HW_RFOFF_DETECTED ++ // The FW command register update must after MAC and FW init ready. ++ if((padapter->bFWReady) && (pwrpriv->bHWPwrPindetect) && (padapter->registrypriv.usbss_enable )) ++ { ++ //rtl8192c_set_FwSelectSuspend_cmd(padapter,_FALSE ,500);//note fw to support hw power down ping detect ++ u8 bOpen = _FALSE; ++ rtw_interface_ps_func(padapter,HAL_USB_SELECT_SUSPEND,&bOpen); ++ } ++ #endif ++ #endif ++#ifdef CONFIG_BT_COEXIST ++ DBG_871X("pwrpriv->bAutoResume (%x)\n",pwrpriv->bAutoResume ); ++ if( _TRUE == pwrpriv->bAutoResume ){ ++ pwrpriv->bInternalAutoSuspend = _FALSE; ++ pwrpriv->bAutoResume=_FALSE; ++ DBG_871X("pwrpriv->bAutoResume (%x) pwrpriv->bInternalAutoSuspend(%x)\n",pwrpriv->bAutoResume,pwrpriv->bInternalAutoSuspend ); ++ } ++ ++#else //#ifdef CONFIG_BT_COEXIST ++ pwrpriv->bInternalAutoSuspend = _FALSE; ++#endif //#ifdef CONFIG_BT_COEXIST ++ pwrpriv->brfoffbyhw = _FALSE; ++ } ++#endif ++ _exit_pwrlock(&pwrpriv->lock); ++ ++ if( padapter->pid[1]!=0) { ++ DBG_871X("pid[1]:%d\n",padapter->pid[1]); ++ rtw_signal_process(padapter->pid[1], SIGUSR2); ++ } ++ ++ ret = 0; ++exit: ++ #ifdef CONFIG_RESUME_IN_WORKQUEUE ++ rtw_unlock_suspend(); ++ #endif //CONFIG_RESUME_IN_WORKQUEUE ++ ++ pwrpriv->bInSuspend = _FALSE; ++ DBG_871X("<=== %s return %d.............. in %dms\n", __FUNCTION__ ++ , ret, rtw_get_passing_time_ms(start_time)); ++ ++ _func_exit_; ++ ++ return ret; ++} ++ ++#ifdef CONFIG_AUTOSUSPEND ++void autosuspend_enter(_adapter* padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); ++ ++ DBG_871X("==>autosuspend_enter...........\n"); ++ ++ pwrpriv->bInternalAutoSuspend = _TRUE; ++ pwrpriv->bips_processing = _TRUE; ++ ++ if(rf_off == pwrpriv->change_rfpwrstate ) ++ { ++#ifndef CONFIG_BT_COEXIST ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)) ++ usb_enable_autosuspend(dvobj->pusbdev); ++ #else ++ dvobj->pusbdev->autosuspend_disabled = 0;//autosuspend disabled by the user ++ #endif ++ ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,33)) ++ usb_autopm_put_interface(dvobj->pusbintf); ++ #elif (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,20)) ++ usb_autopm_enable(dvobj->pusbintf); ++ #else ++ usb_autosuspend_device(dvobj->pusbdev, 1); ++ #endif ++#else //#ifndef CONFIG_BT_COEXIST ++ if(1==pwrpriv->autopm_cnt){ ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)) ++ usb_enable_autosuspend(dvobj->pusbdev); ++ #else ++ dvobj->pusbdev->autosuspend_disabled = 0;//autosuspend disabled by the user ++ #endif ++ ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,33)) ++ usb_autopm_put_interface(dvobj->pusbintf); ++ #elif (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,20)) ++ usb_autopm_enable(dvobj->pusbintf); ++ #else ++ usb_autosuspend_device(dvobj->pusbdev, 1); ++ #endif ++ pwrpriv->autopm_cnt --; ++ } ++ else ++ DBG_871X("0!=pwrpriv->autopm_cnt[%d] didn't usb_autopm_put_interface\n", pwrpriv->autopm_cnt); ++ ++#endif //#ifndef CONFIG_BT_COEXIST ++ } ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,32)) ++ DBG_871X("...pm_usage_cnt(%d).....\n", atomic_read(&(dvobj->pusbintf->pm_usage_cnt))); ++ #else ++ DBG_871X("...pm_usage_cnt(%d).....\n", dvobj->pusbintf->pm_usage_cnt); ++ #endif ++ ++} ++int autoresume_enter(_adapter* padapter) ++{ ++ int result = _SUCCESS; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct security_priv* psecuritypriv=&(padapter->securitypriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); ++ ++ DBG_871X("====> autoresume_enter \n"); ++ ++ if(rf_off == pwrpriv->rf_pwrstate ) ++ { ++ pwrpriv->ps_flag = _FALSE; ++#ifndef CONFIG_BT_COEXIST ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,33)) ++ if (usb_autopm_get_interface(dvobj->pusbintf) < 0) ++ { ++ DBG_871X( "can't get autopm: %d\n", result); ++ result = _FAIL; ++ goto error_exit; ++ } ++ #elif (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,20)) ++ usb_autopm_disable(dvobj->pusbintf); ++ #else ++ usb_autoresume_device(dvobj->pusbdev, 1); ++ #endif ++ ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,32)) ++ DBG_871X("...pm_usage_cnt(%d).....\n", atomic_read(&(dvobj->pusbintf->pm_usage_cnt))); ++ #else ++ DBG_871X("...pm_usage_cnt(%d).....\n", dvobj->pusbintf->pm_usage_cnt); ++ #endif ++#else //#ifndef CONFIG_BT_COEXIST ++ pwrpriv->bAutoResume=_TRUE; ++ if(0==pwrpriv->autopm_cnt){ ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,33)) ++ if (usb_autopm_get_interface(dvobj->pusbintf) < 0) ++ { ++ DBG_871X( "can't get autopm: %d\n", result); ++ result = _FAIL; ++ goto error_exit; ++ } ++ #elif (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,20)) ++ usb_autopm_disable(dvobj->pusbintf); ++ #else ++ usb_autoresume_device(dvobj->pusbdev, 1); ++ #endif ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,32)) ++ DBG_871X("...pm_usage_cnt(%d).....\n", atomic_read(&(dvobj->pusbintf->pm_usage_cnt))); ++ #else ++ DBG_871X("...pm_usage_cnt(%d).....\n", dvobj->pusbintf->pm_usage_cnt); ++ #endif ++ pwrpriv->autopm_cnt++; ++ } ++ else ++ DBG_871X("0!=pwrpriv->autopm_cnt[%d] didn't usb_autopm_get_interface\n",pwrpriv->autopm_cnt); ++#endif //#ifndef CONFIG_BT_COEXIST ++ } ++ DBG_871X("<==== autoresume_enter \n"); ++error_exit: ++ ++ return result; ++} ++#endif ++ ++#ifdef CONFIG_PLATFORM_RTD2880B ++extern void rtd2885_wlan_netlink_sendMsg(char *action_string, char *name); ++#endif ++ ++#ifdef CONFIG_PLATFORM_ARM_SUNxI ++#include ++extern int sw_usb_disable_hcd(__u32 usbc_no); ++extern int sw_usb_enable_hcd(__u32 usbc_no); ++static int usb_wifi_host = 2; ++#endif ++ ++#ifdef CONFIG_PLATFORM_ARM_SUN6I ++#include ++extern int sw_usb_disable_hcd(__u32 usbc_no); ++extern int sw_usb_enable_hcd(__u32 usbc_no); ++extern void wifi_pm_power(int on); ++static script_item_u item; ++#endif ++ ++/* ++ * drv_init() - a device potentially for us ++ * ++ * notes: drv_init() is called when the bus driver has located a card for us to support. ++ * We accept the new device by returning 0. ++*/ ++ ++_adapter *rtw_sw_export = NULL; ++ ++_adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, ++ struct usb_interface *pusb_intf, const struct usb_device_id *pdid) ++{ ++ _adapter *padapter = NULL; ++ struct net_device *pnetdev = NULL; ++ int status = _FAIL; ++ ++ if ((padapter = (_adapter *)rtw_zvmalloc(sizeof(*padapter))) == NULL) { ++ goto exit; ++ } ++ padapter->dvobj = dvobj; ++ dvobj->if1 = padapter; ++ ++ padapter->bDriverStopped=_TRUE; ++ ++ dvobj->padapters[dvobj->iface_nums++] = padapter; ++ padapter->iface_id = IFACE_ID0; ++ ++#if defined(CONFIG_CONCURRENT_MODE) || defined(CONFIG_DUALMAC_CONCURRENT) ++ //set adapter_type/iface type for primary padapter ++ padapter->isprimary = _TRUE; ++ padapter->adapter_type = PRIMARY_ADAPTER; ++ #ifndef CONFIG_HWPORT_SWAP ++ padapter->iface_type = IFACE_PORT0; ++ #else ++ padapter->iface_type = IFACE_PORT1; ++ #endif ++#endif ++ ++ #ifndef RTW_DVOBJ_CHIP_HW_TYPE ++ //step 1-1., decide the chip_type via vid/pid ++ padapter->interface_type = RTW_USB; ++ decide_chip_type_by_usb_device_id(padapter, pdid); ++ #endif ++ ++ if (rtw_handle_dualmac(padapter, 1) != _SUCCESS) ++ goto free_adapter; ++ ++ if((pnetdev = rtw_init_netdev(padapter)) == NULL) { ++ goto handle_dualmac; ++ } ++ SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj)); ++ padapter = rtw_netdev_priv(pnetdev); ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if(rtw_wdev_alloc(padapter, dvobj_to_dev(dvobj)) != 0) { ++ goto handle_dualmac; ++ } ++#endif ++ ++ ++ //step 2. hook HalFunc, allocate HalData ++ hal_set_hal_ops(padapter); ++ ++ padapter->intf_start=&usb_intf_start; ++ padapter->intf_stop=&usb_intf_stop; ++ ++ //step init_io_priv ++ rtw_init_io_priv(padapter, usb_set_intf_ops); ++ ++ //step read_chip_version ++ rtw_hal_read_chip_version(padapter); ++ ++ //step usb endpoint mapping ++ rtw_hal_chip_configure(padapter); ++ ++ //step read efuse/eeprom data and get mac_addr ++ rtw_hal_read_chip_info(padapter); ++ ++ //step 5. ++ if(rtw_init_drv_sw(padapter) ==_FAIL) { ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("Initialize driver software resource Failed!\n")); ++ goto free_hal_data; ++ } ++ ++#ifdef CONFIG_PM ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) ++ if(adapter_to_pwrctl(padapter)->bSupportRemoteWakeup) ++ { ++ dvobj->pusbdev->do_remote_wakeup=1; ++ pusb_intf->needs_remote_wakeup = 1; ++ device_init_wakeup(&pusb_intf->dev, 1); ++ DBG_871X("\n pwrctrlpriv.bSupportRemoteWakeup~~~~~~\n"); ++ DBG_871X("\n pwrctrlpriv.bSupportRemoteWakeup~~~[%d]~~~\n",device_may_wakeup(&pusb_intf->dev)); ++ } ++#endif ++#endif ++ ++#ifdef CONFIG_AUTOSUSPEND ++ if( padapter->registrypriv.power_mgnt != PS_MODE_ACTIVE ) ++ { ++ if(padapter->registrypriv.usbss_enable ){ /* autosuspend (2s delay) */ ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38)) ++ dvobj->pusbdev->dev.power.autosuspend_delay = 0 * HZ;//15 * HZ; idle-delay time ++ #else ++ dvobj->pusbdev->autosuspend_delay = 0 * HZ;//15 * HZ; idle-delay time ++ #endif ++ ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)) ++ usb_enable_autosuspend(dvobj->pusbdev); ++ #elif (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,22) && LINUX_VERSION_CODE<=KERNEL_VERSION(2,6,34)) ++ padapter->bDisableAutosuspend = dvobj->pusbdev->autosuspend_disabled ; ++ dvobj->pusbdev->autosuspend_disabled = 0;//autosuspend disabled by the user ++ #endif ++ ++ //usb_autopm_get_interface(adapter_to_dvobj(padapter)->pusbintf );//init pm_usage_cnt ,let it start from 1 ++ ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,32)) ++ DBG_871X("%s...pm_usage_cnt(%d).....\n",__FUNCTION__,atomic_read(&(dvobj->pusbintf ->pm_usage_cnt))); ++ #else ++ DBG_871X("%s...pm_usage_cnt(%d).....\n",__FUNCTION__,dvobj->pusbintf ->pm_usage_cnt); ++ #endif ++ } ++ } ++#endif ++ //2012-07-11 Move here to prevent the 8723AS-VAU BT auto suspend influence ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,33)) ++ if (usb_autopm_get_interface(pusb_intf) < 0) ++ { ++ DBG_871X( "can't get autopm: \n"); ++ } ++ #endif ++#ifdef CONFIG_BT_COEXIST ++ adapter_to_pwrctl(padapter)->autopm_cnt=1; ++#endif ++ ++ // set mac addr ++ rtw_macaddr_cfg(padapter->eeprompriv.mac_addr); ++ rtw_init_wifidirect_addrs(padapter, padapter->eeprompriv.mac_addr, padapter->eeprompriv.mac_addr); ++ ++ DBG_871X("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n" ++ , padapter->bDriverStopped ++ , padapter->bSurpriseRemoved ++ , padapter->bup ++ , padapter->hw_init_completed ++ ); ++ ++ status = _SUCCESS; ++ ++free_hal_data: ++ if(status != _SUCCESS && padapter->HalData) ++ rtw_mfree(padapter->HalData, sizeof(*(padapter->HalData))); ++free_wdev: ++ if(status != _SUCCESS) { ++ #ifdef CONFIG_IOCTL_CFG80211 ++ rtw_wdev_unregister(padapter->rtw_wdev); ++ rtw_wdev_free(padapter->rtw_wdev); ++ #endif ++ } ++handle_dualmac: ++ if (status != _SUCCESS) ++ rtw_handle_dualmac(padapter, 0); ++free_adapter: ++ if (status != _SUCCESS) { ++ if (pnetdev) ++ rtw_free_netdev(pnetdev); ++ else if (padapter) ++ rtw_vmfree((u8*)padapter, sizeof(*padapter)); ++ padapter = NULL; ++ } ++exit: ++ return padapter; ++} ++ ++static void rtw_usb_if1_deinit(_adapter *if1) ++{ ++ struct net_device *pnetdev = if1->pnetdev; ++ struct mlme_priv *pmlmepriv= &if1->mlmepriv; ++ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(if1); ++ ++ if(check_fwstate(pmlmepriv, _FW_LINKED)) ++ rtw_disassoc_cmd(if1, 0, _FALSE); ++ ++ ++#ifdef CONFIG_AP_MODE ++ free_mlme_ap_info(if1); ++ #ifdef CONFIG_HOSTAPD_MLME ++ hostapd_mode_unload(if1); ++ #endif ++#endif ++/* ++ if(if1->DriverState != DRIVER_DISAPPEAR) { ++ if(pnetdev) { ++ unregister_netdev(pnetdev); //will call netdev_close() ++ rtw_proc_remove_one(pnetdev); ++ } ++ } ++*/ ++ rtw_cancel_all_timer(if1); ++ ++#ifdef CONFIG_WOWLAN ++ pwrctl->wowlan_mode=_FALSE; ++#endif //CONFIG_WOWLAN ++ ++ rtw_dev_unload(if1); ++ ++ DBG_871X("+r871xu_dev_remove, hw_init_completed=%d\n", if1->hw_init_completed); ++ ++ rtw_handle_dualmac(if1, 0); ++ ++#ifdef CONFIG_IOCTL_CFG80211 ++ if(if1->rtw_wdev) ++ { ++ //rtw_wdev_unregister(if1->rtw_wdev); ++ rtw_wdev_free(if1->rtw_wdev); ++ } ++#endif ++ ++#ifdef CONFIG_BT_COEXIST ++ if(1 == pwrctl->autopm_cnt){ ++ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,33)) ++ usb_autopm_put_interface(adapter_to_dvobj(if1)->pusbintf); ++ #elif (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,20)) ++ usb_autopm_enable(adapter_to_dvobj(if1)->pusbintf); ++ #else ++ usb_autosuspend_device(adapter_to_dvobj(if1)->pusbdev, 1); ++ #endif ++ pwrctl->autopm_cnt --; ++ } ++#endif ++ ++ rtw_free_drv_sw(if1); ++ ++ if(pnetdev) ++ rtw_free_netdev(pnetdev); ++ ++#ifdef CONFIG_PLATFORM_RTD2880B ++ DBG_871X("wlan link down\n"); ++ rtd2885_wlan_netlink_sendMsg("linkdown", "8712"); ++#endif ++ ++} ++ ++static void dump_usb_interface(struct usb_interface *usb_intf) ++{ ++ int i; ++ u8 val8; ++ ++ struct usb_device *udev = interface_to_usbdev(usb_intf); ++ struct usb_device_descriptor *dev_desc = &udev->descriptor; ++ ++ struct usb_host_config *act_conf = udev->actconfig; ++ struct usb_config_descriptor *act_conf_desc = &act_conf->desc; ++ ++ struct usb_host_interface *host_iface; ++ struct usb_interface_descriptor *iface_desc; ++ struct usb_host_endpoint *host_endp; ++ struct usb_endpoint_descriptor *endp_desc; ++ ++#if 1 /* The usb device this usb interface belongs to */ ++ DBG_871X("usb_interface:%p, usb_device:%p(num:%d, path:%s), usb_device_descriptor:%p\n", usb_intf, udev, udev->devnum, udev->devpath, dev_desc); ++ DBG_871X("bLength:%u\n", dev_desc->bLength); ++ DBG_871X("bDescriptorType:0x%02x\n", dev_desc->bDescriptorType); ++ DBG_871X("bcdUSB:0x%04x\n", le16_to_cpu(dev_desc->bcdUSB)); ++ DBG_871X("bDeviceClass:0x%02x\n", dev_desc->bDeviceClass); ++ DBG_871X("bDeviceSubClass:0x%02x\n", dev_desc->bDeviceSubClass); ++ DBG_871X("bDeviceProtocol:0x%02x\n", dev_desc->bDeviceProtocol); ++ DBG_871X("bMaxPacketSize0:%u\n", dev_desc->bMaxPacketSize0); ++ DBG_871X("idVendor:0x%04x\n", le16_to_cpu(dev_desc->idVendor)); ++ DBG_871X("idProduct:0x%04x\n", le16_to_cpu(dev_desc->idProduct)); ++ DBG_871X("bcdDevice:0x%04x\n", le16_to_cpu(dev_desc->bcdDevice)); ++ DBG_871X("iManufacturer:0x02%x\n", dev_desc->iManufacturer); ++ DBG_871X("iProduct:0x%02x\n", dev_desc->iProduct); ++ DBG_871X("iSerialNumber:0x%02x\n", dev_desc->iSerialNumber); ++ DBG_871X("bNumConfigurations:%u\n", dev_desc->bNumConfigurations); ++#endif ++ ++ ++#if 1 /* The acting usb_config_descriptor */ ++ DBG_871X("\nact_conf_desc:%p\n", act_conf_desc); ++ DBG_871X("bLength:%u\n", act_conf_desc->bLength); ++ DBG_871X("bDescriptorType:0x%02x\n", act_conf_desc->bDescriptorType); ++ DBG_871X("wTotalLength:%u\n", le16_to_cpu(act_conf_desc->wTotalLength)); ++ DBG_871X("bNumInterfaces:%u\n", act_conf_desc->bNumInterfaces); ++ DBG_871X("bConfigurationValue:0x%02x\n", act_conf_desc->bConfigurationValue); ++ DBG_871X("iConfiguration:0x%02x\n", act_conf_desc->iConfiguration); ++ DBG_871X("bmAttributes:0x%02x\n", act_conf_desc->bmAttributes); ++ DBG_871X("bMaxPower=%u\n", act_conf_desc->bMaxPower); ++#endif ++ ++ ++ DBG_871X("****** num of altsetting = (%d) ******/\n", usb_intf->num_altsetting); ++ /* Get he host side alternate setting (the current alternate setting) for this interface*/ ++ host_iface = usb_intf->cur_altsetting; ++ iface_desc = &host_iface->desc; ++ ++#if 1 /* The current alternate setting*/ ++ DBG_871X("\nusb_interface_descriptor:%p:\n", iface_desc); ++ DBG_871X("bLength:%u\n", iface_desc->bLength); ++ DBG_871X("bDescriptorType:0x%02x\n", iface_desc->bDescriptorType); ++ DBG_871X("bInterfaceNumber:0x%02x\n", iface_desc->bInterfaceNumber); ++ DBG_871X("bAlternateSetting=%x\n", iface_desc->bAlternateSetting); ++ DBG_871X("bNumEndpoints=%x\n", iface_desc->bNumEndpoints); ++ DBG_871X("bInterfaceClass=%x\n", iface_desc->bInterfaceClass); ++ DBG_871X("bInterfaceSubClass=%x\n", iface_desc->bInterfaceSubClass); ++ DBG_871X("bInterfaceProtocol=%x\n", iface_desc->bInterfaceProtocol); ++ DBG_871X("iInterface=%x\n", iface_desc->iInterface); ++#endif ++ ++ ++#if 1 ++ //DBG_871X("\ndump usb_endpoint_descriptor:\n"); ++ ++ for (i = 0; i < iface_desc->bNumEndpoints; i++) ++ { ++ host_endp = host_iface->endpoint + i; ++ if (host_endp) ++ { ++ endp_desc = &host_endp->desc; ++ ++ DBG_871X("\nusb_endpoint_descriptor(%d):\n", i); ++ DBG_871X("bLength=%x\n",endp_desc->bLength); ++ DBG_871X("bDescriptorType=%x\n",endp_desc->bDescriptorType); ++ DBG_871X("bEndpointAddress=%x\n",endp_desc->bEndpointAddress); ++ DBG_871X("bmAttributes=%x\n",endp_desc->bmAttributes); ++ DBG_871X("wMaxPacketSize=%x\n",endp_desc->wMaxPacketSize); ++ DBG_871X("wMaxPacketSize=%x\n",le16_to_cpu(endp_desc->wMaxPacketSize)); ++ DBG_871X("bInterval=%x\n",endp_desc->bInterval); ++ //DBG_871X("bRefresh=%x\n",pendp_desc->bRefresh); ++ //DBG_871X("bSynchAddress=%x\n",pendp_desc->bSynchAddress); ++ ++ if (RT_usb_endpoint_is_bulk_in(endp_desc)) ++ { ++ DBG_871X("RT_usb_endpoint_is_bulk_in = %x\n", RT_usb_endpoint_num(endp_desc)); ++ //pdvobjpriv->RtNumInPipes++; ++ } ++ else if (RT_usb_endpoint_is_int_in(endp_desc)) ++ { ++ DBG_871X("RT_usb_endpoint_is_int_in = %x, Interval = %x\n", RT_usb_endpoint_num(endp_desc),endp_desc->bInterval); ++ //pdvobjpriv->RtNumInPipes++; ++ } ++ else if (RT_usb_endpoint_is_bulk_out(endp_desc)) ++ { ++ DBG_871X("RT_usb_endpoint_is_bulk_out = %x\n", RT_usb_endpoint_num(endp_desc)); ++ //pdvobjpriv->RtNumOutPipes++; ++ } ++ //pdvobjpriv->ep_num[i] = RT_usb_endpoint_num(pendp_desc); ++ } ++ } ++ ++ //DBG_871X("nr_endpoint=%d, in_num=%d, out_num=%d\n\n", pdvobjpriv->nr_endpoint, pdvobjpriv->RtNumInPipes, pdvobjpriv->RtNumOutPipes); ++#endif ++ ++ if (udev->speed == USB_SPEED_HIGH) ++ DBG_871X("USB_SPEED_HIGH\n"); ++ else ++ DBG_871X("NON USB_SPEED_HIGH\n"); ++ ++} ++ ++ ++static int rtw_drv_init(struct usb_interface *pusb_intf, const struct usb_device_id *pdid) ++{ ++ int i; ++ _adapter *if1 = NULL, *if2 = NULL; ++ int status; ++ struct dvobj_priv *dvobj; ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_init\n")); ++ //DBG_871X("+rtw_drv_init\n"); ++ ++ //step 0. ++ process_spec_devid(pdid); ++ ++ /* Initialize dvobj_priv */ ++ if ((dvobj = usb_dvobj_init(pusb_intf)) == NULL) { ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("initialize device object priv Failed!\n")); ++ goto exit; ++ } ++ ++ #ifdef RTW_DVOBJ_CHIP_HW_TYPE ++ decide_chip_type_by_usb_device_id(dvobj, pdid); ++ #endif ++ ++ if ((if1 = rtw_usb_if1_init(dvobj, pusb_intf, pdid)) == NULL) { ++ DBG_871X("rtw_init_primary_adapter Failed!\n"); ++ goto free_dvobj; ++ } ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if((if2 = rtw_drv_if2_init(if1, usb_set_intf_ops)) == NULL) { ++ goto free_if1; ++ } ++#endif ++ ++#ifdef CONFIG_INTEL_PROXIM ++ rtw_sw_export=if1; ++#endif ++ ++#ifdef CONFIG_GLOBAL_UI_PID ++ if(ui_pid[1]!=0) { ++ DBG_871X("ui_pid[1]:%d\n",ui_pid[1]); ++ rtw_signal_process(ui_pid[1], SIGUSR2); ++ } ++#endif ++ ++ //dev_alloc_name && register_netdev ++ if((status = rtw_drv_register_netdev(if1)) != _SUCCESS) { ++ goto free_if2; ++ } ++ ++#ifdef CONFIG_HOSTAPD_MLME ++ hostapd_mode_init(if1); ++#endif ++ ++#ifdef CONFIG_PLATFORM_RTD2880B ++ DBG_871X("wlan link up\n"); ++ rtd2885_wlan_netlink_sendMsg("linkup", "8712"); ++#endif ++ ++#ifdef RTK_DMP_PLATFORM ++ rtw_proc_init_one(if1->pnetdev); ++#endif ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("-871x_drv - drv_init, success!\n")); ++ ++ status = _SUCCESS; ++ ++free_if2: ++ if(status != _SUCCESS && if2) { ++ #ifdef CONFIG_CONCURRENT_MODE ++ rtw_drv_if2_stop(if2); ++ rtw_drv_if2_free(if2); ++ #endif ++ } ++free_if1: ++ if (status != _SUCCESS && if1) { ++ rtw_usb_if1_deinit(if1); ++ } ++free_dvobj: ++ if (status != _SUCCESS) ++ usb_dvobj_deinit(pusb_intf); ++exit: ++ return status == _SUCCESS?0:-ENODEV; ++} ++extern void rtw_unregister_netdevs(struct dvobj_priv *dvobj); ++/* ++ * dev_remove() - our device is being removed ++*/ ++//rmmod module & unplug(SurpriseRemoved) will call r871xu_dev_remove() => how to recognize both ++static void rtw_dev_remove(struct usb_interface *pusb_intf) ++{ ++ struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf); ++ _adapter *padapter = dvobj->if1; ++ struct net_device *pnetdev = padapter->pnetdev; ++ struct mlme_priv *pmlmepriv= &padapter->mlmepriv; ++ ++_func_enter_; ++ ++ DBG_871X("+rtw_dev_remove\n"); ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("+dev_remove()\n")); ++ dvobj->processing_dev_remove = _TRUE; ++ rtw_unregister_netdevs(dvobj); ++ ++ if(usb_drv->drv_registered == _TRUE) ++ { ++ //DBG_871X("r871xu_dev_remove():padapter->bSurpriseRemoved == _TRUE\n"); ++ padapter->bSurpriseRemoved = _TRUE; ++ } ++ /*else ++ { ++ //DBG_871X("r871xu_dev_remove():module removed\n"); ++ padapter->hw_init_completed = _FALSE; ++ }*/ ++#ifdef CONFIG_MP_INCLUDED ++ if (padapter->registrypriv.mp_mode == 1) ++ MPT_DeInitAdapter(padapter); ++#endif ++#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_ANDROID_POWER) ++ rtw_unregister_early_suspend(dvobj_to_pwrctl(dvobj)); ++#endif ++ ++ rtw_pm_set_ips(padapter, IPS_NONE); ++ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE); ++ ++ LeaveAllPowerSaveMode(padapter); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ rtw_drv_if2_stop(dvobj->if2); ++#endif ++ ++ rtw_usb_if1_deinit(padapter); ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ rtw_drv_if2_free(dvobj->if2); ++#endif ++ ++ usb_dvobj_deinit(pusb_intf); ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("-dev_remove()\n")); ++ DBG_871X("-r871xu_dev_remove, done\n"); ++ ++ ++#ifdef CONFIG_INTEL_PROXIM ++ rtw_sw_export=NULL; ++#endif ++ ++_func_exit_; ++ ++ return; ++ ++} ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) ++extern int console_suspend_enabled; ++#endif ++ ++static int __init rtw_drv_entry(void) ++{ ++#ifdef CONFIG_PLATFORM_RTK_DMP ++ u32 tmp; ++ tmp=readl((volatile unsigned int*)0xb801a608); ++ tmp &= 0xffffff00; ++ tmp |= 0x55; ++ writel(tmp,(volatile unsigned int*)0xb801a608);//write dummy register for 1055 ++#endif ++#ifdef CONFIG_PLATFORM_ARM_SUNxI ++#ifndef CONFIG_RTL8723A ++ int ret = 0; ++ /* ----------get usb_wifi_usbc_num------------- */ ++ ret = script_parser_fetch("usb_wifi_para", "usb_wifi_usbc_num", (int *)&usb_wifi_host, 64); ++ if(ret != 0){ ++ DBG_8192C("ERR: script_parser_fetch usb_wifi_usbc_num failed\n"); ++ ret = -ENOMEM; ++ return ret; ++ } ++ DBG_8192C("sw_usb_enable_hcd: usbc_num = %d\n", usb_wifi_host); ++ sw_usb_enable_hcd(usb_wifi_host); ++#endif //CONFIG_RTL8723A ++#endif //CONFIG_PLATFORM_ARM_SUNxI ++ ++#if defined CONFIG_PLATFORM_ARM_SUN6I ++ script_item_value_type_e type; ++ ++ type = script_get_item("wifi_para", "wifi_usbc_id", &item); ++ if(SCIRPT_ITEM_VALUE_TYPE_INT != type){ ++ printk("ERR: script_get_item wifi_usbc_id failed\n"); ++ return -ENOMEM; ++ } ++ ++ printk("sw_usb_enable_hcd: usbc_num = %d\n", item.val); ++ wifi_pm_power(1); ++ mdelay(10); ++ ++ #ifndef CONFIG_RTL8723A ++ sw_usb_enable_hcd(item.val); ++ #endif ++#endif // defined CONFIG_PLATFORM_ARM_SUN6I && !(defined CONFIG_RTL8723A) ++ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("+rtw_drv_entry\n")); ++ ++ DBG_871X(DRV_NAME " driver version=%s\n", DRIVERVERSION); ++ DBG_871X("build time: %s %s\n", __DATE__, __TIME__); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) ++ //console_suspend_enabled=0; ++#endif ++ ++ rtw_suspend_lock_init(); ++ ++ usb_drv->drv_registered = _TRUE; ++ return usb_register(&usb_drv->usbdrv); ++} ++ ++static void __exit rtw_drv_halt(void) ++{ ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("+rtw_drv_halt\n")); ++ DBG_871X("+rtw_drv_halt\n"); ++ ++ usb_drv->drv_registered = _FALSE; ++ usb_deregister(&usb_drv->usbdrv); ++ ++#ifdef CONFIG_PLATFORM_ARM_SUNxI ++#ifndef CONFIG_RTL8723A ++ DBG_8192C("sw_usb_disable_hcd: usbc_num = %d\n", usb_wifi_host); ++ sw_usb_disable_hcd(usb_wifi_host); ++#endif //ifndef CONFIG_RTL8723A ++#endif //CONFIG_PLATFORM_ARM_SUNxI ++ ++#if defined CONFIG_PLATFORM_ARM_SUN6I ++ #ifndef CONFIG_RTL8723A ++ sw_usb_disable_hcd(item.val); ++ #endif ++ wifi_pm_power(0); ++#endif // defined CONFIG_PLATFORM_ARM_SUN6I && !(defined CONFIG_RTL8723A) ++ ++ rtw_suspend_lock_uninit(); ++ DBG_871X("-rtw_drv_halt\n"); ++ ++ rtw_mstat_dump(); ++} ++ ++ ++module_init(rtw_drv_entry); ++module_exit(rtw_drv_halt); ++ ++#ifdef CONFIG_INTEL_PROXIM ++_adapter *rtw_usb_get_sw_pointer(void) ++{ ++ return rtw_sw_export; ++} ++EXPORT_SYMBOL(rtw_usb_get_sw_pointer); ++#endif //CONFIG_INTEL_PROXIM ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/usb_ops_linux.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/usb_ops_linux.c +new file mode 100644 +index 00000000..db754644 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/usb_ops_linux.c +@@ -0,0 +1,698 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ *******************************************************************************/ ++#define _USB_OPS_LINUX_C_ ++ ++#include ++#include ++#include ++ ++#ifdef CONFIG_USB_SUPPORT_ASYNC_VDN_REQ ++static void _usbctrl_vendorreq_async_callback(struct urb *urb, struct pt_regs *regs) ++{ ++ if (urb) { ++ if (urb->context) { ++ rtw_mfree(urb->context); ++ } ++ usb_free_urb(urb); ++ } ++} ++ ++static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request, ++ u16 value, u16 index, void *pdata, u16 len, u8 requesttype) ++{ ++ int rc; ++ unsigned int pipe; ++ u8 reqtype; ++ struct usb_ctrlrequest *dr; ++ struct urb *urb; ++ struct rtl819x_async_write_data { ++ u8 data[VENDOR_CMD_MAX_DATA_LEN]; ++ struct usb_ctrlrequest dr; ++ } *buf; ++ ++ ++ if (requesttype == VENDOR_READ) { ++ pipe = usb_rcvctrlpipe(udev, 0);//read_in ++ reqtype = REALTEK_USB_VENQT_READ; ++ } ++ else { ++ pipe = usb_sndctrlpipe(udev, 0);//write_out ++ reqtype = REALTEK_USB_VENQT_WRITE; ++ } ++ ++ buf = (struct rtl819x_async_write_data *)rtw_zmalloc(sizeof(*buf)); ++ if (!buf) { ++ rc = -ENOMEM; ++ goto exit; ++ } ++ ++ urb = usb_alloc_urb(0, GFP_ATOMIC); ++ if (!urb) { ++ rtw_mfree((u8*)buf, sizeof(*buf)); ++ rc = -ENOMEM; ++ goto exit; ++ } ++ ++ dr = &buf->dr; ++ ++ dr->bRequestType = reqtype; ++ dr->bRequest = request; ++ dr->wValue = cpu_to_le16(value); ++ dr->wIndex = cpu_to_le16(index); ++ dr->wLength = cpu_to_le16(len); ++ ++ _rtw_memcpy(buf, pdata, len); ++ ++ usb_fill_control_urb(urb, udev, pipe, (unsigned char *)dr, buf, len, ++ _usbctrl_vendorreq_async_callback, buf); ++ ++ rc = usb_submit_urb(urb, GFP_ATOMIC); ++ if (rc < 0) { ++ rtw_mfree((u8*)buf, sizeof(*buf)); ++ usb_free_urb(urb); ++ } ++ ++exit: ++ return rc; ++} ++ ++int usb_write_async(struct usb_device *udev, u32 addr, void *pdata, u16 len) ++{ ++ u8 request; ++ u8 requesttype; ++ u16 wvalue; ++ u16 index; ++ ++ int ret; ++ ++ requesttype = VENDOR_WRITE;//write_out ++ request = REALTEK_USB_VENQT_CMD_REQ; ++ index = REALTEK_USB_VENQT_CMD_IDX;//n/a ++ ++ wvalue = (u16)(addr&0x0000ffff); ++ ++ ret = _usbctrl_vendorreq_async_write(udev, request, wvalue, index, pdata, len, requesttype); ++ ++ return ret; ++} ++ ++int usb_async_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val) ++{ ++ u8 data; ++ int ret; ++ struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev; ++ struct usb_device *udev=pdvobjpriv->pusbdev; ++ ++ _func_enter_; ++ data = val; ++ ret = usb_write_async(udev, addr, &data, 1); ++ _func_exit_; ++ ++ return ret; ++} ++ ++int usb_async_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val) ++{ ++ u16 data; ++ int ret; ++ struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev; ++ struct usb_device *udev=pdvobjpriv->pusbdev; ++ ++ _func_enter_; ++ data = val; ++ ret = usb_write_async(udev, addr, &data, 2); ++ _func_exit_; ++ ++ return ret; ++} ++ ++int usb_async_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val) ++{ ++ u32 data; ++ int ret; ++ struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev; ++ struct usb_device *udev=pdvobjpriv->pusbdev; ++ ++ _func_enter_; ++ data = val; ++ ret = usb_write_async(udev, addr, &data, 4); ++ _func_exit_; ++ ++ return ret; ++} ++#endif /* CONFIG_USB_SUPPORT_ASYNC_VDN_REQ */ ++ ++unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr) ++{ ++ unsigned int pipe=0, ep_num=0; ++ struct usb_device *pusbd = pdvobj->pusbdev; ++ ++ if (addr == RECV_BULK_IN_ADDR) { ++ pipe=usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[0]); ++ ++ } else if (addr == RECV_INT_IN_ADDR) { ++ pipe=usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[1]); ++ ++ } else if (addr < HW_QUEUE_ENTRY) { ++ ep_num = pdvobj->Queue2Pipe[addr]; ++ pipe = usb_sndbulkpipe(pusbd, ep_num); ++ } ++ ++ return pipe; ++} ++ ++struct zero_bulkout_context{ ++ void *pbuf; ++ void *purb; ++ void *pirp; ++ void *padapter; ++}; ++ ++static void usb_bulkout_zero_complete(struct urb *purb, struct pt_regs *regs) ++{ ++ struct zero_bulkout_context *pcontext = (struct zero_bulkout_context *)purb->context; ++ ++ //DBG_8192C("+usb_bulkout_zero_complete\n"); ++ ++ if(pcontext) ++ { ++ if(pcontext->pbuf) ++ { ++ rtw_mfree(pcontext->pbuf, sizeof(int)); ++ } ++ ++ if(pcontext->purb && (pcontext->purb==purb)) ++ { ++ usb_free_urb(pcontext->purb); ++ } ++ ++ ++ rtw_mfree((u8*)pcontext, sizeof(struct zero_bulkout_context)); ++ } ++ ++ ++} ++ ++static u32 usb_bulkout_zero(struct intf_hdl *pintfhdl, u32 addr) ++{ ++ int pipe, status, len; ++ u32 ret; ++ unsigned char *pbuf; ++ struct zero_bulkout_context *pcontext; ++ PURB purb = NULL; ++ _adapter *padapter = (_adapter *)pintfhdl->padapter; ++ struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); ++ struct usb_device *pusbd = pdvobj->pusbdev; ++ ++ //DBG_871X("%s\n", __func__); ++ ++ ++ if((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) ||(dvobj_to_pwrctl(pdvobj)->pnp_bstop_trx)) ++ { ++ return _FAIL; ++ } ++ ++ ++ pcontext = (struct zero_bulkout_context *)rtw_zmalloc(sizeof(struct zero_bulkout_context)); ++ ++ pbuf = (unsigned char *)rtw_zmalloc(sizeof(int)); ++ purb = usb_alloc_urb(0, GFP_ATOMIC); ++ ++ len = 0; ++ pcontext->pbuf = pbuf; ++ pcontext->purb = purb; ++ pcontext->pirp = NULL; ++ pcontext->padapter = padapter; ++ ++ ++ //translate DMA FIFO addr to pipehandle ++ //pipe = ffaddr2pipehdl(pdvobj, addr); ++ ++ usb_fill_bulk_urb(purb, pusbd, pipe, ++ pbuf, ++ len, ++ usb_bulkout_zero_complete, ++ pcontext);//context is pcontext ++ ++ status = usb_submit_urb(purb, GFP_ATOMIC); ++ ++ if (!status) ++ { ++ ret= _SUCCESS; ++ } ++ else ++ { ++ ret= _FAIL; ++ } ++ ++ ++ return _SUCCESS; ++ ++} ++ ++void usb_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) ++{ ++ ++} ++ ++void usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) ++{ ++ ++} ++ ++ ++void usb_read_port_cancel(struct intf_hdl *pintfhdl) ++{ ++ int i; ++ struct recv_buf *precvbuf; ++ _adapter *padapter = pintfhdl->padapter; ++ precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf; ++ ++ DBG_871X("%s\n", __func__); ++ ++ padapter->bReadPortCancel = _TRUE; ++ ++ for (i=0; i < NR_RECVBUFF ; i++) { ++ ++ precvbuf->reuse = _TRUE; ++ if (precvbuf->purb) { ++ //DBG_8192C("usb_read_port_cancel : usb_kill_urb \n"); ++ usb_kill_urb(precvbuf->purb); ++ } ++ precvbuf++; ++ } ++ ++#ifdef CONFIG_USB_INTERRUPT_IN_PIPE ++ usb_kill_urb(padapter->recvpriv.int_in_urb); ++#endif ++} ++ ++static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs) ++{ ++ _irqL irqL; ++ int i; ++ struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context; ++ //struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; ++ //_adapter *padapter = pxmitframe->padapter; ++ _adapter *padapter = pxmitbuf->padapter; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ //struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ ++_func_enter_; ++ ++ switch(pxmitbuf->flags) ++ { ++ case VO_QUEUE_INX: ++ pxmitpriv->voq_cnt--; ++ break; ++ case VI_QUEUE_INX: ++ pxmitpriv->viq_cnt--; ++ break; ++ case BE_QUEUE_INX: ++ pxmitpriv->beq_cnt--; ++ break; ++ case BK_QUEUE_INX: ++ pxmitpriv->bkq_cnt--; ++ break; ++ case HIGH_QUEUE_INX: ++#ifdef CONFIG_AP_MODE ++ rtw_chk_hi_queue_cmd(padapter); ++#endif ++ break; ++ default: ++ break; ++ } ++ ++ ++/* ++ _enter_critical(&pxmitpriv->lock, &irqL); ++ ++ pxmitpriv->txirp_cnt--; ++ ++ switch(pattrib->priority) ++ { ++ case 1: ++ case 2: ++ pxmitpriv->bkq_cnt--; ++ //DBG_8192C("pxmitpriv->bkq_cnt=%d\n", pxmitpriv->bkq_cnt); ++ break; ++ case 4: ++ case 5: ++ pxmitpriv->viq_cnt--; ++ //DBG_8192C("pxmitpriv->viq_cnt=%d\n", pxmitpriv->viq_cnt); ++ break; ++ case 6: ++ case 7: ++ pxmitpriv->voq_cnt--; ++ //DBG_8192C("pxmitpriv->voq_cnt=%d\n", pxmitpriv->voq_cnt); ++ break; ++ case 0: ++ case 3: ++ default: ++ pxmitpriv->beq_cnt--; ++ //DBG_8192C("pxmitpriv->beq_cnt=%d\n", pxmitpriv->beq_cnt); ++ break; ++ ++ } ++ ++ _exit_critical(&pxmitpriv->lock, &irqL); ++ ++ ++ if(pxmitpriv->txirp_cnt==0) ++ { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: txirp_cnt== 0, set allrxreturnevt!\n")); ++ _rtw_up_sema(&(pxmitpriv->tx_retevt)); ++ } ++*/ ++ //rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ ++ if(padapter->bSurpriseRemoved || padapter->bDriverStopped ||padapter->bWritePortCancel) ++ { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); ++ DBG_8192C("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bWritePortCancel(%d) pxmitbuf->ext_tag(%x) \n", ++ __FUNCTION__,padapter->bDriverStopped, padapter->bSurpriseRemoved,padapter->bReadPortCancel,pxmitbuf->ext_tag); ++ ++ goto check_completion; ++ } ++ ++ ++ if (purb->status==0) { ++ ++ } else { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete : purb->status(%d) != 0 \n", purb->status)); ++ DBG_871X("###=> urb_write_port_complete status(%d)\n",purb->status); ++ if((purb->status==-EPIPE)||(purb->status==-EPROTO)) ++ { ++ //usb_clear_halt(pusbdev, purb->pipe); ++ //msleep(10); ++ sreset_set_wifi_error_status(padapter, USB_WRITE_PORT_FAIL); ++ } else if (purb->status == -EINPROGRESS) { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: EINPROGESS\n")); ++ goto check_completion; ++ ++ } else if (purb->status == -ENOENT) { ++ DBG_871X("%s: -ENOENT\n", __func__); ++ goto check_completion; ++ ++ } else if (purb->status == -ECONNRESET) { ++ DBG_871X("%s: -ECONNRESET\n", __func__); ++ goto check_completion; ++ ++ } else if (purb->status == -ESHUTDOWN) { ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: ESHUTDOWN\n")); ++ padapter->bDriverStopped=_TRUE; ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bDriverStopped=TRUE\n")); ++ ++ goto check_completion; ++ } ++ else ++ { ++ padapter->bSurpriseRemoved=_TRUE; ++ DBG_8192C("bSurpriseRemoved=TRUE\n"); ++ //rtl8192cu_trigger_gpio_0(padapter); ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bSurpriseRemoved=TRUE\n")); ++ ++ goto check_completion; ++ } ++ } ++ ++ #ifdef DBG_CONFIG_ERROR_DETECT ++ { ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ pHalData->srestpriv.last_tx_complete_time = rtw_get_current_time(); ++ } ++ #endif ++ ++check_completion: ++ _enter_critical(&pxmitpriv->lock_sctx, &irqL); ++ rtw_sctx_done_err(&pxmitbuf->sctx, ++ purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS); ++ _exit_critical(&pxmitpriv->lock_sctx, &irqL); ++ ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ ++ //if(rtw_txframes_pending(padapter)) ++ { ++ tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); ++ } ++ ++_func_exit_; ++ ++} ++ ++u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) ++{ ++ _irqL irqL; ++ unsigned int pipe; ++ int status; ++ u32 ret = _FAIL, bwritezero = _FALSE; ++ PURB purb = NULL; ++ _adapter *padapter = (_adapter *)pintfhdl->padapter; ++ struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct xmit_buf *pxmitbuf = (struct xmit_buf *)wmem; ++ struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; ++ struct usb_device *pusbd = pdvobj->pusbdev; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ ++_func_enter_; ++ ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("+usb_write_port\n")); ++ ++ if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) ||(dvobj_to_pwrctl(pdvobj)->pnp_bstop_trx)) { ++ #ifdef DBG_TX ++ DBG_871X(" DBG_TX %s:%d bDriverStopped%d, bSurpriseRemoved:%d, pnp_bstop_trx:%d\n",__FUNCTION__, __LINE__ ++ ,padapter->bDriverStopped, padapter->bSurpriseRemoved, dvobj_to_pwrctl(pdvobj)->pnp_bstop_trx ); ++ #endif ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port:( padapter->bDriverStopped ||padapter->bSurpriseRemoved ||pwrctl->pnp_bstop_trx)!!!\n")); ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY); ++ goto exit; ++ } ++ ++ _enter_critical(&pxmitpriv->lock, &irqL); ++ ++ switch(addr) ++ { ++ case VO_QUEUE_INX: ++ pxmitpriv->voq_cnt++; ++ pxmitbuf->flags = VO_QUEUE_INX; ++ break; ++ case VI_QUEUE_INX: ++ pxmitpriv->viq_cnt++; ++ pxmitbuf->flags = VI_QUEUE_INX; ++ break; ++ case BE_QUEUE_INX: ++ pxmitpriv->beq_cnt++; ++ pxmitbuf->flags = BE_QUEUE_INX; ++ break; ++ case BK_QUEUE_INX: ++ pxmitpriv->bkq_cnt++; ++ pxmitbuf->flags = BK_QUEUE_INX; ++ break; ++ case HIGH_QUEUE_INX: ++ pxmitbuf->flags = HIGH_QUEUE_INX; ++ break; ++ default: ++ pxmitbuf->flags = MGT_QUEUE_INX; ++ break; ++ } ++ ++ _exit_critical(&pxmitpriv->lock, &irqL); ++ ++ #ifdef DBG_TRX_STA_PKTS ++ { ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ int bmcast = IS_MCAST(pattrib->dst); ++ u8 agg_num = 1; ++ ++ #ifdef CONFIG_USB_HCI ++ #ifdef CONFIG_USB_TX_AGGREGATION ++ if(pxmitframe->agg_num>1) ++ agg_num = pxmitframe->agg_num; ++ #endif ++ #endif ++ ++ #if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ if(pxmitframe->agg_num>1) ++ agg_num = pxmitframe->agg_num; ++ #endif ++ ++ if(bmcast) ++ { ++ psta = rtw_get_bcmc_stainfo(padapter); ++ ++ } else { ++ psta = rtw_get_stainfo(pstapriv, pattrib->dst); ++ } ++ if(psta) ++ { ++ switch(pattrib->priority) ++ { ++ case 1: ++ case 2: ++ psta->tx_bk_cnt += agg_num; ++ break; ++ case 4: ++ case 5: ++ psta->tx_vi_cnt += agg_num; ++ break; ++ case 6: ++ case 7: ++ psta->tx_vo_cnt += agg_num; ++ break; ++ case 0: ++ case 3: ++ default: ++ psta->tx_be_cnt += agg_num; ++ break; ++ } ++ } ++ } ++ #endif ++ ++ purb = pxmitbuf->pxmit_urb[0]; ++ ++#if 0 ++ if(pdvobj->ishighspeed) ++ { ++ if(cnt> 0 && cnt%512 == 0) ++ { ++ //DBG_8192C("ishighspeed, cnt=%d\n", cnt); ++ bwritezero = _TRUE; ++ } ++ } ++ else ++ { ++ if(cnt > 0 && cnt%64 == 0) ++ { ++ //DBG_8192C("cnt=%d\n", cnt); ++ bwritezero = _TRUE; ++ } ++ } ++#endif ++ ++ //translate DMA FIFO addr to pipehandle ++ pipe = ffaddr2pipehdl(pdvobj, addr); ++ ++#ifdef CONFIG_REDUCE_USB_TX_INT ++ if ( (pxmitpriv->free_xmitbuf_cnt%NR_XMITBUFF == 0) ++ || (pxmitbuf->ext_tag == _TRUE) ) ++ { ++ purb->transfer_flags &= (~URB_NO_INTERRUPT); ++ } else { ++ purb->transfer_flags |= URB_NO_INTERRUPT; ++ //DBG_8192C("URB_NO_INTERRUPT "); ++ } ++#endif ++ ++ ++ usb_fill_bulk_urb(purb, pusbd, pipe, ++ pxmitframe->buf_addr, //= pxmitbuf->pbuf ++ cnt, ++ usb_write_port_complete, ++ pxmitbuf);//context is pxmitbuf ++ ++#ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX ++ purb->transfer_dma = pxmitbuf->dma_transfer_addr; ++ purb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++ purb->transfer_flags |= URB_ZERO_PACKET; ++#endif // CONFIG_USE_USB_BUFFER_ALLOC_TX ++ ++#if 0 ++ if (bwritezero) ++ { ++ purb->transfer_flags |= URB_ZERO_PACKET; ++ } ++#endif ++ ++ status = usb_submit_urb(purb, GFP_ATOMIC); ++ if (!status) { ++ #ifdef DBG_CONFIG_ERROR_DETECT ++ { ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); ++ pHalData->srestpriv.last_tx_time = rtw_get_current_time(); ++ } ++ #endif ++ } else { ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR); ++ DBG_871X("usb_write_port, status=%d\n", status); ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port(): usb_submit_urb, status=%x\n", status)); ++ ++ switch (status) { ++ case -ENODEV: ++ padapter->bDriverStopped=_TRUE; ++ break; ++ default: ++ break; ++ } ++ goto exit; ++ } ++ ++ ret= _SUCCESS; ++ ++// Commented by Albert 2009/10/13 ++// We add the URB_ZERO_PACKET flag to urb so that the host will send the zero packet automatically. ++/* ++ if(bwritezero == _TRUE) ++ { ++ usb_bulkout_zero(pintfhdl, addr); ++ } ++*/ ++ ++ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("-usb_write_port\n")); ++ ++exit: ++ if (ret != _SUCCESS) ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++_func_exit_; ++ return ret; ++ ++} ++ ++void usb_write_port_cancel(struct intf_hdl *pintfhdl) ++{ ++ int i, j; ++ _adapter *padapter = pintfhdl->padapter; ++ struct xmit_buf *pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmitbuf; ++ ++ DBG_871X("%s \n", __func__); ++ ++ padapter->bWritePortCancel = _TRUE; ++ ++ for (i=0; ipxmit_urb[j]) { ++ usb_kill_urb(pxmitbuf->pxmit_urb[j]); ++ } ++ } ++ pxmitbuf++; ++ } ++ ++ pxmitbuf = (struct xmit_buf*)padapter->xmitpriv.pxmit_extbuf; ++ for (i = 0; i < NR_XMIT_EXTBUFF; i++) { ++ for (j=0; j<8; j++) { ++ if(pxmitbuf->pxmit_urb[j]) { ++ usb_kill_urb(pxmitbuf->pxmit_urb[j]); ++ } ++ } ++ pxmitbuf++; ++ } ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/xmit_linux.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/xmit_linux.c +new file mode 100644 +index 00000000..979066d8 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/linux/xmit_linux.c +@@ -0,0 +1,456 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++#define _XMIT_OSDEP_C_ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++uint rtw_remainder_len(struct pkt_file *pfile) ++{ ++ return (pfile->buf_len - ((SIZE_PTR)(pfile->cur_addr) - (SIZE_PTR)(pfile->buf_start))); ++} ++ ++void _rtw_open_pktfile (_pkt *pktptr, struct pkt_file *pfile) ++{ ++_func_enter_; ++ ++ pfile->pkt = pktptr; ++ pfile->cur_addr = pfile->buf_start = pktptr->data; ++ pfile->pkt_len = pfile->buf_len = pktptr->len; ++ ++ pfile->cur_buffer = pfile->buf_start ; ++ ++_func_exit_; ++} ++ ++uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen) ++{ ++ uint len = 0; ++ ++_func_enter_; ++ ++ len = rtw_remainder_len(pfile); ++ len = (rlen > len)? len: rlen; ++ ++ if(rmem) ++ skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, rmem, len); ++ ++ pfile->cur_addr += len; ++ pfile->pkt_len -= len; ++ ++_func_exit_; ++ ++ return len; ++} ++ ++sint rtw_endofpktfile(struct pkt_file *pfile) ++{ ++_func_enter_; ++ ++ if (pfile->pkt_len == 0) { ++_func_exit_; ++ return _TRUE; ++ } ++ ++_func_exit_; ++ ++ return _FALSE; ++} ++ ++void rtw_set_tx_chksum_offload(_pkt *pkt, struct pkt_attrib *pattrib) ++{ ++ ++#ifdef CONFIG_TCP_CSUM_OFFLOAD_TX ++ struct sk_buff *skb = (struct sk_buff *)pkt; ++ pattrib->hw_tcp_csum = 0; ++ ++ if (skb->ip_summed == CHECKSUM_PARTIAL) { ++ if (skb_shinfo(skb)->nr_frags == 0) ++ { ++ const struct iphdr *ip = ip_hdr(skb); ++ if (ip->protocol == IPPROTO_TCP) { ++ // TCP checksum offload by HW ++ DBG_871X("CHECKSUM_PARTIAL TCP\n"); ++ pattrib->hw_tcp_csum = 1; ++ //skb_checksum_help(skb); ++ } else if (ip->protocol == IPPROTO_UDP) { ++ //DBG_871X("CHECKSUM_PARTIAL UDP\n"); ++#if 1 ++ skb_checksum_help(skb); ++#else ++ // Set UDP checksum = 0 to skip checksum check ++ struct udphdr *udp = skb_transport_header(skb); ++ udp->check = 0; ++#endif ++ } else { ++ DBG_871X("%s-%d TCP CSUM offload Error!!\n", __FUNCTION__, __LINE__); ++ WARN_ON(1); /* we need a WARN() */ ++ } ++ } ++ else { // IP fragmentation case ++ DBG_871X("%s-%d nr_frags != 0, using skb_checksum_help(skb);!!\n", __FUNCTION__, __LINE__); ++ skb_checksum_help(skb); ++ } ++ } ++#endif ++ ++} ++ ++int rtw_os_xmit_resource_alloc(_adapter *padapter, struct xmit_buf *pxmitbuf,u32 alloc_sz) ++{ ++#ifdef CONFIG_USB_HCI ++ int i; ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct usb_device *pusbd = pdvobjpriv->pusbdev; ++ ++#ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX ++ pxmitbuf->pallocated_buf = rtw_usb_buffer_alloc(pusbd, (size_t)alloc_sz, &pxmitbuf->dma_transfer_addr); ++ pxmitbuf->pbuf = pxmitbuf->pallocated_buf; ++ if(pxmitbuf->pallocated_buf == NULL) ++ return _FAIL; ++#else // CONFIG_USE_USB_BUFFER_ALLOC_TX ++ ++ pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz); ++ if (pxmitbuf->pallocated_buf == NULL) ++ { ++ return _FAIL; ++ } ++ ++ pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ); ++ pxmitbuf->dma_transfer_addr = 0; ++ ++#endif // CONFIG_USE_USB_BUFFER_ALLOC_TX ++ ++ for(i=0; i<8; i++) ++ { ++ pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL); ++ if(pxmitbuf->pxmit_urb[i] == NULL) ++ { ++ DBG_871X("pxmitbuf->pxmit_urb[i]==NULL"); ++ return _FAIL; ++ } ++ ++ } ++#endif ++#if defined(CONFIG_PCI_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz); ++ if (pxmitbuf->pallocated_buf == NULL) ++ { ++ return _FAIL; ++ } ++ ++ pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ); ++#endif ++ ++ return _SUCCESS; ++} ++ ++void rtw_os_xmit_resource_free(_adapter *padapter, struct xmit_buf *pxmitbuf,u32 free_sz) ++{ ++#ifdef CONFIG_USB_HCI ++ int i; ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct usb_device *pusbd = pdvobjpriv->pusbdev; ++ ++ ++ for(i=0; i<8; i++) ++ { ++ if(pxmitbuf->pxmit_urb[i]) ++ { ++ //usb_kill_urb(pxmitbuf->pxmit_urb[i]); ++ usb_free_urb(pxmitbuf->pxmit_urb[i]); ++ } ++ } ++ ++#ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX ++ rtw_usb_buffer_free(pusbd, (size_t)free_sz, pxmitbuf->pallocated_buf, pxmitbuf->dma_transfer_addr); ++ pxmitbuf->pallocated_buf = NULL; ++ pxmitbuf->dma_transfer_addr = 0; ++#else // CONFIG_USE_USB_BUFFER_ALLOC_TX ++ if(pxmitbuf->pallocated_buf) ++ rtw_mfree(pxmitbuf->pallocated_buf, free_sz); ++#endif // CONFIG_USE_USB_BUFFER_ALLOC_TX ++ ++#endif ++#if defined(CONFIG_PCI_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ if(pxmitbuf->pallocated_buf) ++ rtw_mfree(pxmitbuf->pallocated_buf, free_sz); ++#endif ++} ++ ++#define WMM_XMIT_THRESHOLD (NR_XMITFRAME*2/5) ++ ++void rtw_os_pkt_complete(_adapter *padapter, _pkt *pkt) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) ++ u16 queue; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ queue = skb_get_queue_mapping(pkt); ++ if (padapter->registrypriv.wifi_spec) { ++ if(__netif_subqueue_stopped(padapter->pnetdev, queue) && ++ (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD)) ++ { ++ netif_wake_subqueue(padapter->pnetdev, queue); ++ } ++ } else { ++ if(__netif_subqueue_stopped(padapter->pnetdev, queue)) ++ netif_wake_subqueue(padapter->pnetdev, queue); ++ } ++#else ++ if (netif_queue_stopped(padapter->pnetdev)) ++ netif_wake_queue(padapter->pnetdev); ++#endif ++ ++ rtw_skb_free(pkt); ++} ++ ++void rtw_os_xmit_complete(_adapter *padapter, struct xmit_frame *pxframe) ++{ ++ if(pxframe->pkt) ++ rtw_os_pkt_complete(padapter, pxframe->pkt); ++ ++ pxframe->pkt = NULL; ++} ++ ++void rtw_os_xmit_schedule(_adapter *padapter) ++{ ++ _adapter *pri_adapter = padapter; ++ ++#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) ++ if(!padapter) ++ return; ++ ++#ifdef CONFIG_CONCURRENT_MODE ++ if(padapter->adapter_type > PRIMARY_ADAPTER) ++ pri_adapter = padapter->pbuddy_adapter; ++#endif ++ ++ if (_rtw_queue_empty(&pri_adapter->xmitpriv.pending_xmitbuf_queue) == _FALSE) ++ _rtw_up_sema(&pri_adapter->xmitpriv.xmit_sema); ++ ++ ++#else ++ _irqL irqL; ++ struct xmit_priv *pxmitpriv; ++ ++ if(!padapter) ++ return; ++ ++ pxmitpriv = &padapter->xmitpriv; ++ ++ _enter_critical_bh(&pxmitpriv->lock, &irqL); ++ ++ if(rtw_txframes_pending(padapter)) ++ { ++ tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); ++ } ++ ++ _exit_critical_bh(&pxmitpriv->lock, &irqL); ++#endif ++} ++ ++static void rtw_check_xmit_resource(_adapter *padapter, _pkt *pkt) ++{ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)) ++ u16 queue; ++ ++ queue = skb_get_queue_mapping(pkt); ++ if (padapter->registrypriv.wifi_spec) { ++ /* No free space for Tx, tx_worker is too slow */ ++ if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD) { ++ //DBG_871X("%s(): stop netif_subqueue[%d]\n", __FUNCTION__, queue); ++ netif_stop_subqueue(padapter->pnetdev, queue); ++ } ++ } else { ++ if(pxmitpriv->free_xmitframe_cnt<=4) { ++ if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue))) ++ netif_stop_subqueue(padapter->pnetdev, queue); ++ } ++ } ++#else ++ if(pxmitpriv->free_xmitframe_cnt<=4) ++ { ++ if (!rtw_netif_queue_stopped(padapter->pnetdev)) ++ rtw_netif_stop_queue(padapter->pnetdev); ++ } ++#endif ++} ++ ++#ifdef CONFIG_TX_MCAST2UNI ++int rtw_mlcst2unicst(_adapter *padapter, struct sk_buff *skb) ++{ ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ _irqL irqL; ++ _list *phead, *plist; ++ struct sk_buff *newskb; ++ struct sta_info *psta = NULL; ++ u8 chk_alive_num = 0; ++ char chk_alive_list[NUM_STA]; ++ u8 bc_addr[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ u8 null_addr[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++ ++ int i; ++ s32 res; ++ ++ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ ++ //free sta asoc_queue ++ while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { ++ int stainfo_offset; ++ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ plist = get_next(plist); ++ ++ stainfo_offset = rtw_stainfo_offset(pstapriv, psta); ++ if (stainfo_offset_valid(stainfo_offset)) { ++ chk_alive_list[chk_alive_num++] = stainfo_offset; ++ } ++ } ++ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ ++ for (i = 0; i < chk_alive_num; i++) { ++ psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); ++ if(!(psta->state &_FW_LINKED)) ++ continue; ++ ++ /* avoid come from STA1 and send back STA1 */ ++ if (_rtw_memcmp(psta->hwaddr, &skb->data[6], 6) == _TRUE ++ || _rtw_memcmp(psta->hwaddr, null_addr, 6) == _TRUE ++ || _rtw_memcmp(psta->hwaddr, bc_addr, 6) == _TRUE ++ ) ++ continue; ++ ++ newskb = rtw_skb_copy(skb); ++ ++ if (newskb) { ++ _rtw_memcpy(newskb->data, psta->hwaddr, 6); ++ res = rtw_xmit(padapter, &newskb); ++ if (res < 0) { ++ DBG_871X("%s()-%d: rtw_xmit() return error!\n", __FUNCTION__, __LINE__); ++ pxmitpriv->tx_drop++; ++ rtw_skb_free(newskb); ++ } else ++ pxmitpriv->tx_pkts++; ++ } else { ++ DBG_871X("%s-%d: rtw_skb_copy() failed!\n", __FUNCTION__, __LINE__); ++ pxmitpriv->tx_drop++; ++ //rtw_skb_free(skb); ++ return _FALSE; // Caller shall tx this multicast frame via normal way. ++ } ++ } ++ ++ rtw_skb_free(skb); ++ return _TRUE; ++} ++#endif // CONFIG_TX_MCAST2UNI ++ ++ ++int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev); ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++#ifdef CONFIG_TX_MCAST2UNI ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ extern int rtw_mc2u_disable; ++#endif // CONFIG_TX_MCAST2UNI ++ s32 res = 0; ++#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,35)) ++ u16 queue; ++#endif ++ ++_func_enter_; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n")); ++ ++ if (rtw_if_up(padapter) == _FALSE) { ++ RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit_entry: rtw_if_up fail\n")); ++ #ifdef DBG_TX_DROP_FRAME ++ DBG_871X("DBG_TX_DROP_FRAME %s if_up fail\n", __FUNCTION__); ++ #endif ++ goto drop_packet; ++ } ++ ++ rtw_check_xmit_resource(padapter, pkt); ++ ++#ifdef CONFIG_TX_MCAST2UNI ++ if ( !rtw_mc2u_disable ++ && check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE ++ && ( IP_MCAST_MAC(pkt->data) ++ || ICMPV6_MCAST_MAC(pkt->data) ) ++ && (padapter->registrypriv.wifi_spec == 0) ++ ) ++ { ++ if ( pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4) ) { ++ res = rtw_mlcst2unicst(padapter, pkt); ++ if (res == _TRUE) { ++ goto exit; ++ } ++ } else { ++ //DBG_871X("Stop M2U(%d, %d)! ", pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmitbuf_cnt); ++ //DBG_871X("!m2u ); ++ } ++ } ++#endif // CONFIG_TX_MCAST2UNI ++ ++ res = rtw_xmit(padapter, &pkt); ++ if (res < 0) { ++ #ifdef DBG_TX_DROP_FRAME ++ DBG_871X("DBG_TX_DROP_FRAME %s rtw_xmit fail\n", __FUNCTION__); ++ #endif ++ goto drop_packet; ++ } ++ ++ pxmitpriv->tx_pkts++; ++ RT_TRACE(_module_xmit_osdep_c_, _drv_info_, ("rtw_xmit_entry: tx_pkts=%d\n", (u32)pxmitpriv->tx_pkts)); ++ goto exit; ++ ++drop_packet: ++ pxmitpriv->tx_drop++; ++ rtw_skb_free(pkt); ++ RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, ("rtw_xmit_entry: drop, tx_drop=%d\n", (u32)pxmitpriv->tx_drop)); ++ ++exit: ++ ++_func_exit_; ++ ++ return 0; ++} ++ ++int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev) ++{ ++ if (pkt) ++ rtw_mstat_update(MSTAT_TYPE_SKB, MSTAT_ALLOC_SUCCESS, pkt->truesize); ++ return _rtw_xmit_entry(pkt, pnetdev); ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/os_dep/osdep_service.c b/drivers/net/wireless/rtl818x/rtl8189/os_dep/osdep_service.c +new file mode 100644 +index 00000000..ac86e4d2 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/os_dep/osdep_service.c +@@ -0,0 +1,2335 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License 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 Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * ++ ******************************************************************************/ ++ ++ ++#define _OSDEP_SERVICE_C_ ++ ++#include ++#include ++#include ++#include ++#ifdef PLATFORM_LINUX ++#include ++#endif ++#ifdef PLATFORM_FREEBSD ++#include ++#include ++#endif /* PLATFORM_FREEBSD */ ++#ifdef RTK_DMP_PLATFORM ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12)) ++#include ++#endif ++#endif ++ ++#define RT_TAG '1178' ++ ++#ifdef DBG_MEMORY_LEAK ++#ifdef PLATFORM_LINUX ++#include ++atomic_t _malloc_cnt = ATOMIC_INIT(0); ++atomic_t _malloc_size = ATOMIC_INIT(0); ++#endif ++#endif /* DBG_MEMORY_LEAK */ ++ ++ ++#if defined(PLATFORM_LINUX) ++/* ++* Translate the OS dependent @param error_code to OS independent RTW_STATUS_CODE ++* @return: one of RTW_STATUS_CODE ++*/ ++inline int RTW_STATUS_CODE(int error_code){ ++ if(error_code >=0) ++ return _SUCCESS; ++ ++ switch(error_code) { ++ //case -ETIMEDOUT: ++ // return RTW_STATUS_TIMEDOUT; ++ default: ++ return _FAIL; ++ } ++} ++#else ++inline int RTW_STATUS_CODE(int error_code){ ++ return error_code; ++} ++#endif ++ ++u32 rtw_atoi(u8* s) ++{ ++ ++ int num=0,flag=0; ++ int i; ++ for(i=0;i<=strlen(s);i++) ++ { ++ if(s[i] >= '0' && s[i] <= '9') ++ num = num * 10 + s[i] -'0'; ++ else if(s[0] == '-' && i==0) ++ flag =1; ++ else ++ break; ++ } ++ ++ if(flag == 1) ++ num = num * -1; ++ ++ return(num); ++ ++} ++ ++inline u8* _rtw_vmalloc(u32 sz) ++{ ++ u8 *pbuf; ++#ifdef PLATFORM_LINUX ++ pbuf = vmalloc(sz); ++#endif ++#ifdef PLATFORM_FREEBSD ++ pbuf = malloc(sz,M_DEVBUF,M_NOWAIT); ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++ NdisAllocateMemoryWithTag(&pbuf,sz, RT_TAG); ++#endif ++ ++#ifdef DBG_MEMORY_LEAK ++#ifdef PLATFORM_LINUX ++ if ( pbuf != NULL) { ++ atomic_inc(&_malloc_cnt); ++ atomic_add(sz, &_malloc_size); ++ } ++#endif ++#endif /* DBG_MEMORY_LEAK */ ++ ++ return pbuf; ++} ++ ++inline u8* _rtw_zvmalloc(u32 sz) ++{ ++ u8 *pbuf; ++#ifdef PLATFORM_LINUX ++ pbuf = _rtw_vmalloc(sz); ++ if (pbuf != NULL) ++ memset(pbuf, 0, sz); ++#endif ++#ifdef PLATFORM_FREEBSD ++ pbuf = malloc(sz,M_DEVBUF,M_ZERO|M_NOWAIT); ++#endif ++#ifdef PLATFORM_WINDOWS ++ NdisAllocateMemoryWithTag(&pbuf,sz, RT_TAG); ++ if (pbuf != NULL) ++ NdisFillMemory(pbuf, sz, 0); ++#endif ++ ++ return pbuf; ++} ++ ++inline void _rtw_vmfree(u8 *pbuf, u32 sz) ++{ ++#ifdef PLATFORM_LINUX ++ vfree(pbuf); ++#endif ++#ifdef PLATFORM_FREEBSD ++ free(pbuf,M_DEVBUF); ++#endif ++#ifdef PLATFORM_WINDOWS ++ NdisFreeMemory(pbuf,sz, 0); ++#endif ++ ++#ifdef DBG_MEMORY_LEAK ++#ifdef PLATFORM_LINUX ++ atomic_dec(&_malloc_cnt); ++ atomic_sub(sz, &_malloc_size); ++#endif ++#endif /* DBG_MEMORY_LEAK */ ++} ++ ++u8* _rtw_malloc(u32 sz) ++{ ++ ++ u8 *pbuf=NULL; ++ ++#ifdef PLATFORM_LINUX ++#ifdef RTK_DMP_PLATFORM ++ if(sz > 0x4000) ++ pbuf = (u8 *)dvr_malloc(sz); ++ else ++#endif ++ pbuf = kmalloc(sz,in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ pbuf = malloc(sz,M_DEVBUF,M_NOWAIT); ++#endif ++#ifdef PLATFORM_WINDOWS ++ ++ NdisAllocateMemoryWithTag(&pbuf,sz, RT_TAG); ++ ++#endif ++ ++#ifdef DBG_MEMORY_LEAK ++#ifdef PLATFORM_LINUX ++ if ( pbuf != NULL) { ++ atomic_inc(&_malloc_cnt); ++ atomic_add(sz, &_malloc_size); ++ } ++#endif ++#endif /* DBG_MEMORY_LEAK */ ++ ++ return pbuf; ++ ++} ++ ++ ++u8* _rtw_zmalloc(u32 sz) ++{ ++#ifdef PLATFORM_FREEBSD ++ return malloc(sz,M_DEVBUF,M_ZERO|M_NOWAIT); ++#else // PLATFORM_FREEBSD ++ u8 *pbuf = _rtw_malloc(sz); ++ ++ if (pbuf != NULL) { ++ ++#ifdef PLATFORM_LINUX ++ memset(pbuf, 0, sz); ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++ NdisFillMemory(pbuf, sz, 0); ++#endif ++ ++ } ++ ++ return pbuf; ++#endif // PLATFORM_FREEBSD ++} ++ ++void _rtw_mfree(u8 *pbuf, u32 sz) ++{ ++ ++#ifdef PLATFORM_LINUX ++#ifdef RTK_DMP_PLATFORM ++ if(sz > 0x4000) ++ dvr_free(pbuf); ++ else ++#endif ++ kfree(pbuf); ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ free(pbuf,M_DEVBUF); ++#endif ++#ifdef PLATFORM_WINDOWS ++ ++ NdisFreeMemory(pbuf,sz, 0); ++ ++#endif ++ ++#ifdef DBG_MEMORY_LEAK ++#ifdef PLATFORM_LINUX ++ atomic_dec(&_malloc_cnt); ++ atomic_sub(sz, &_malloc_size); ++#endif ++#endif /* DBG_MEMORY_LEAK */ ++ ++} ++ ++#ifdef PLATFORM_FREEBSD ++//review again ++struct sk_buff * dev_alloc_skb(unsigned int size) ++{ ++ struct sk_buff *skb=NULL; ++ u8 *data=NULL; ++ ++ //skb = (struct sk_buff *)_rtw_zmalloc(sizeof(struct sk_buff)); // for skb->len, etc. ++ skb = (struct sk_buff *)_rtw_malloc(sizeof(struct sk_buff)); ++ if(!skb) ++ goto out; ++ data = _rtw_malloc(size); ++ if(!data) ++ goto nodata; ++ ++ skb->head = (unsigned char*)data; ++ skb->data = (unsigned char*)data; ++ skb->tail = (unsigned char*)data; ++ skb->end = (unsigned char*)data + size; ++ skb->len = 0; ++ //printf("%s()-%d: skb=%p, skb->head = %p\n", __FUNCTION__, __LINE__, skb, skb->head); ++ ++out: ++ return skb; ++nodata: ++ _rtw_mfree((u8 *)skb, sizeof(struct sk_buff)); ++ skb = NULL; ++goto out; ++ ++} ++ ++void dev_kfree_skb_any(struct sk_buff *skb) ++{ ++ //printf("%s()-%d: skb->head = %p\n", __FUNCTION__, __LINE__, skb->head); ++ if(skb->head) ++ _rtw_mfree(skb->head, 0); ++ //printf("%s()-%d: skb = %p\n", __FUNCTION__, __LINE__, skb); ++ if(skb) ++ _rtw_mfree((u8 *)skb, 0); ++} ++struct sk_buff *skb_clone(const struct sk_buff *skb) ++{ ++ return NULL; ++} ++ ++#endif /* PLATFORM_FREEBSD */ ++ ++inline struct sk_buff *_rtw_skb_alloc(u32 sz) ++{ ++#ifdef PLATFORM_LINUX ++ return __dev_alloc_skb(sz, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); ++#endif /* PLATFORM_LINUX */ ++ ++#ifdef PLATFORM_FREEBSD ++ return dev_alloc_skb(sz); ++#endif /* PLATFORM_FREEBSD */ ++} ++ ++inline void _rtw_skb_free(struct sk_buff *skb) ++{ ++ dev_kfree_skb_any(skb); ++} ++ ++inline struct sk_buff *_rtw_skb_copy(const struct sk_buff *skb) ++{ ++#ifdef PLATFORM_LINUX ++ return skb_copy(skb, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); ++#endif /* PLATFORM_LINUX */ ++ ++#ifdef PLATFORM_FREEBSD ++ return NULL; ++#endif /* PLATFORM_FREEBSD */ ++} ++ ++inline struct sk_buff *_rtw_skb_clone(struct sk_buff *skb) ++{ ++#ifdef PLATFORM_LINUX ++ return skb_clone(skb, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); ++#endif /* PLATFORM_LINUX */ ++ ++#ifdef PLATFORM_FREEBSD ++ return skb_clone(skb); ++#endif /* PLATFORM_FREEBSD */ ++} ++ ++inline int _rtw_netif_rx(_nic_hdl ndev, struct sk_buff *skb) ++{ ++#ifdef PLATFORM_LINUX ++ skb->dev = ndev; ++ return netif_rx(skb); ++#endif /* PLATFORM_LINUX */ ++ ++#ifdef PLATFORM_FREEBSD ++ return (*ndev->if_input)(ndev, skb); ++#endif /* PLATFORM_FREEBSD */ ++} ++ ++void _rtw_skb_queue_purge(struct sk_buff_head *list) ++{ ++ struct sk_buff *skb; ++ ++ while ((skb = skb_dequeue(list)) != NULL) ++ _rtw_skb_free(skb); ++} ++ ++#ifdef CONFIG_USB_HCI ++inline void *_rtw_usb_buffer_alloc(struct usb_device *dev, size_t size, dma_addr_t *dma) ++{ ++#ifdef PLATFORM_LINUX ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) ++ return usb_alloc_coherent(dev, size, (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL), dma); ++#else ++ return usb_buffer_alloc(dev, size, (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL), dma); ++#endif ++#endif /* PLATFORM_LINUX */ ++ ++#ifdef PLATFORM_FREEBSD ++ return (malloc(size, M_USBDEV, M_NOWAIT | M_ZERO)); ++#endif /* PLATFORM_FREEBSD */ ++} ++inline void _rtw_usb_buffer_free(struct usb_device *dev, size_t size, void *addr, dma_addr_t dma) ++{ ++#ifdef PLATFORM_LINUX ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) ++ usb_free_coherent(dev, size, addr, dma); ++#else ++ usb_buffer_free(dev, size, addr, dma); ++#endif ++#endif /* PLATFORM_LINUX */ ++ ++#ifdef PLATFORM_FREEBSD ++ free(addr, M_USBDEV); ++#endif /* PLATFORM_FREEBSD */ ++} ++#endif /* CONFIG_USB_HCI */ ++ ++#ifdef DBG_MEM_ALLOC ++ ++struct rtw_mem_stat { ++ ATOMIC_T alloc; // the memory bytes we allocate currently ++ ATOMIC_T peak; // the peak memory bytes we allocate ++ ATOMIC_T alloc_cnt; // the alloc count for alloc currently ++ ATOMIC_T alloc_err_cnt; // the error times we fail to allocate memory ++}; ++ ++struct rtw_mem_stat rtw_mem_type_stat[mstat_tf_idx(MSTAT_TYPE_MAX)]; ++struct rtw_mem_stat rtw_mem_func_stat[mstat_ff_idx(MSTAT_FUNC_MAX)]; ++ ++char *MSTAT_TYPE_str[] = { ++ "VIR", ++ "PHY", ++ "SKB", ++ "USB", ++}; ++ ++char *MSTAT_FUNC_str[] = { ++ "UNSP", ++ "IO", ++ "TXIO", ++ "RXIO", ++ "TX", ++ "RX", ++}; ++ ++int _rtw_mstat_dump(char *buf, int len) ++{ ++ int cnt = 0; ++ int i; ++ int value_t[4][mstat_tf_idx(MSTAT_TYPE_MAX)]; ++ int value_f[4][mstat_ff_idx(MSTAT_FUNC_MAX)]; ++ ++ int vir_alloc, vir_peak, vir_alloc_err, phy_alloc, phy_peak, phy_alloc_err; ++ int tx_alloc, tx_peak, tx_alloc_err, rx_alloc, rx_peak, rx_alloc_err; ++ ++ for(i=0;i 5000) { ++ // rtw_mstat_dump(); ++ update_time=rtw_get_current_time(); ++ //} ++} ++ ++ ++ ++inline u8* dbg_rtw_vmalloc(u32 sz, const enum mstat_f flags, const char *func, const int line) ++{ ++ u8 *p; ++ //DBG_871X("DBG_MEM_ALLOC %s:%d %s(%d)\n", func, line, __FUNCTION__, (sz)); ++ ++ p=_rtw_vmalloc((sz)); ++ ++ rtw_mstat_update( ++ flags ++ , p ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL ++ , sz ++ ); ++ ++ return p; ++} ++ ++inline u8* dbg_rtw_zvmalloc(u32 sz, const enum mstat_f flags, const char *func, const int line) ++{ ++ u8 *p; ++ //DBG_871X("DBG_MEM_ALLOC %s:%d %s(%d)\n", func, line, __FUNCTION__, (sz)); ++ ++ p=_rtw_zvmalloc((sz)); ++ ++ rtw_mstat_update( ++ flags ++ , p ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL ++ , sz ++ ); ++ ++ return p; ++} ++ ++inline void dbg_rtw_vmfree(u8 *pbuf, u32 sz, const enum mstat_f flags, const char *func, const int line) ++{ ++ //DBG_871X("DBG_MEM_ALLOC %s:%d %s(%p,%d)\n", func, line, __FUNCTION__, (pbuf), (sz)); ++ ++ _rtw_vmfree((pbuf), (sz)); ++ ++ rtw_mstat_update( ++ flags ++ , MSTAT_FREE ++ , sz ++ ); ++} ++ ++inline u8* dbg_rtw_malloc(u32 sz, const enum mstat_f flags, const char *func, const int line) ++{ ++ u8 *p; ++ ++ //if(sz>=153 && sz<=306) ++ // DBG_871X("DBG_MEM_ALLOC %s:%d %s(%d)\n", func, line, __FUNCTION__, (sz)); ++ ++ //if((sz)>4096) ++ // DBG_871X("DBG_MEM_ALLOC %s:%d %s(%d)\n", func, line, __FUNCTION__, (sz)); ++ ++ p=_rtw_malloc((sz)); ++ ++ rtw_mstat_update( ++ flags ++ , p ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL ++ , sz ++ ); ++ ++ return p; ++} ++ ++inline u8* dbg_rtw_zmalloc(u32 sz, const enum mstat_f flags, const char *func, const int line) ++{ ++ u8 *p; ++ ++ //if(sz>=153 && sz<=306) ++ // DBG_871X("DBG_MEM_ALLOC %s:%d %s(%d)\n", func, line, __FUNCTION__, (sz)); ++ ++ //if((sz)>4096) ++ // DBG_871X("DBG_MEM_ALLOC %s:%d %s(%d)\n", func, line, __FUNCTION__, (sz)); ++ ++ p = _rtw_zmalloc((sz)); ++ ++ rtw_mstat_update( ++ flags ++ , p ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL ++ , sz ++ ); ++ ++ return p; ++} ++ ++inline void dbg_rtw_mfree(u8 *pbuf, u32 sz, const enum mstat_f flags, const char *func, const int line) ++{ ++ //if(sz>=153 && sz<=306) ++ // DBG_871X("DBG_MEM_ALLOC %s:%d %s(%d)\n", func, line, __FUNCTION__, (sz)); ++ ++ //if((sz)>4096) ++ // DBG_871X("DBG_MEM_ALLOC %s:%d %s(%p,%d)\n", func, line, __FUNCTION__, (pbuf), (sz)); ++ ++ _rtw_mfree((pbuf), (sz)); ++ ++ rtw_mstat_update( ++ flags ++ , MSTAT_FREE ++ , sz ++ ); ++} ++ ++inline struct sk_buff * dbg_rtw_skb_alloc(unsigned int size, const enum mstat_f flags, const char *func, int line) ++{ ++ struct sk_buff *skb; ++ unsigned int truesize = 0; ++ ++ skb = _rtw_skb_alloc(size); ++ ++ if(skb) ++ truesize = skb->truesize; ++ ++ if(!skb || truesize < size /*|| size > 4096*/) ++ DBG_871X("DBG_MEM_ALLOC %s:%d %s(%d), skb:%p, truesize=%u\n", func, line, __FUNCTION__, size, skb, truesize); ++ ++ rtw_mstat_update( ++ flags ++ , skb ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL ++ , truesize ++ ); ++ ++ return skb; ++} ++ ++inline void dbg_rtw_skb_free(struct sk_buff *skb, const enum mstat_f flags, const char *func, int line) ++{ ++ unsigned int truesize = skb->truesize; ++ ++ //if(truesize > 4096) ++ // DBG_871X("DBG_MEM_ALLOC %s:%d %s, truesize=%u\n", func, line, __FUNCTION__, truesize); ++ ++ _rtw_skb_free(skb); ++ ++ rtw_mstat_update( ++ flags ++ , MSTAT_FREE ++ , truesize ++ ); ++} ++ ++inline struct sk_buff *dbg_rtw_skb_copy(const struct sk_buff *skb, const enum mstat_f flags, const char *func, const int line) ++{ ++ struct sk_buff *skb_cp; ++ unsigned int truesize = skb->truesize; ++ unsigned int cp_truesize = 0; ++ ++ skb_cp = _rtw_skb_copy(skb); ++ if(skb_cp) ++ cp_truesize = skb_cp->truesize; ++ ++ if(!skb_cp || cp_truesize != truesize /*||cp_truesize > 4096*/) ++ DBG_871X("DBG_MEM_ALLOC %s:%d %s(%u), skb_cp:%p, cp_truesize=%u\n", func, line, __FUNCTION__, truesize, skb_cp, cp_truesize); ++ ++ rtw_mstat_update( ++ flags ++ , skb_cp ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL ++ , truesize ++ ); ++ ++ return skb_cp; ++} ++ ++inline struct sk_buff *dbg_rtw_skb_clone(struct sk_buff *skb, const enum mstat_f flags, const char *func, const int line) ++{ ++ struct sk_buff *skb_cl; ++ unsigned int truesize = skb->truesize; ++ unsigned int cl_truesize = 0; ++ ++ skb_cl = _rtw_skb_clone(skb); ++ if(skb_cl) ++ cl_truesize = skb_cl->truesize; ++ ++ if(!skb_cl || cl_truesize != truesize /*|| cl_truesize > 4096*/) ++ DBG_871X("DBG_MEM_ALLOC %s:%d %s(%u), skb_cl:%p, cl_truesize=%u\n", func, line, __FUNCTION__, truesize, skb_cl, cl_truesize); ++ ++ rtw_mstat_update( ++ flags ++ , skb_cl ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL ++ , truesize ++ ); ++ ++ return skb_cl; ++} ++ ++inline int dbg_rtw_netif_rx(_nic_hdl ndev, struct sk_buff *skb, const enum mstat_f flags, const char *func, int line) ++{ ++ int ret; ++ unsigned int truesize = skb->truesize; ++ ++ //if(truesize > 4096) ++ // DBG_871X("DBG_MEM_ALLOC %s:%d %s, truesize=%u\n", func, line, __FUNCTION__, truesize); ++ ++ ret = _rtw_netif_rx(ndev, skb); ++ ++ rtw_mstat_update( ++ flags ++ , MSTAT_FREE ++ , truesize ++ ); ++ ++ return ret; ++} ++ ++inline void dbg_rtw_skb_queue_purge(struct sk_buff_head *list, enum mstat_f flags, const char *func, int line) ++{ ++ struct sk_buff *skb; ++ ++ while ((skb = skb_dequeue(list)) != NULL) ++ dbg_rtw_skb_free(skb, flags, func, line); ++} ++ ++#ifdef CONFIG_USB_HCI ++inline void *dbg_rtw_usb_buffer_alloc(struct usb_device *dev, size_t size, dma_addr_t *dma, const enum mstat_f flags, const char *func, int line) ++{ ++ void *p; ++ //DBG_871X("DBG_MEM_ALLOC %s:%d %s(%d)\n", func, line, __FUNCTION__, size); ++ ++ p = _rtw_usb_buffer_alloc(dev, size, dma); ++ ++ rtw_mstat_update( ++ flags ++ , p ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL ++ , size ++ ); ++ ++ return p; ++} ++ ++inline void dbg_rtw_usb_buffer_free(struct usb_device *dev, size_t size, void *addr, dma_addr_t dma, const enum mstat_f flags, const char *func, int line) ++{ ++ //DBG_871X("DBG_MEM_ALLOC %s:%d %s(%d)\n", func, line, __FUNCTION__, size); ++ ++ _rtw_usb_buffer_free(dev, size, addr, dma); ++ ++ rtw_mstat_update( ++ flags ++ , MSTAT_FREE ++ , size ++ ); ++} ++#endif /* CONFIG_USB_HCI */ ++#endif /* DBG_MEM_ALLOC */ ++ ++void* rtw_malloc2d(int h, int w, int size) ++{ ++ int j; ++ ++ void **a = (void **) rtw_zmalloc( h*sizeof(void *) + h*w*size ); ++ if(a == NULL) ++ { ++ DBG_871X("%s: alloc memory fail!\n", __FUNCTION__); ++ return NULL; ++ } ++ ++ for( j=0; jprev = pnew; ++ pnew->next = pnext; ++ pnew->prev = pprev; ++ pprev->next = pnew; ++} ++#endif /* PLATFORM_FREEBSD */ ++ ++void _rtw_init_listhead(_list *list) ++{ ++ ++#ifdef PLATFORM_LINUX ++ ++ INIT_LIST_HEAD(list); ++ ++#endif ++ ++#ifdef PLATFORM_FREEBSD ++ list->next = list; ++ list->prev = list; ++#endif ++#ifdef PLATFORM_WINDOWS ++ ++ NdisInitializeListHead(list); ++ ++#endif ++ ++} ++ ++ ++/* ++For the following list_xxx operations, ++caller must guarantee the atomic context. ++Otherwise, there will be racing condition. ++*/ ++u32 rtw_is_list_empty(_list *phead) ++{ ++ ++#ifdef PLATFORM_LINUX ++ ++ if (list_empty(phead)) ++ return _TRUE; ++ else ++ return _FALSE; ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ ++ if (phead->next == phead) ++ return _TRUE; ++ else ++ return _FALSE; ++ ++#endif ++ ++ ++#ifdef PLATFORM_WINDOWS ++ ++ if (IsListEmpty(phead)) ++ return _TRUE; ++ else ++ return _FALSE; ++ ++#endif ++ ++ ++} ++ ++void rtw_list_insert_head(_list *plist, _list *phead) ++{ ++ ++#ifdef PLATFORM_LINUX ++ list_add(plist, phead); ++#endif ++ ++#ifdef PLATFORM_FREEBSD ++ __list_add(plist, phead, phead->next); ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++ InsertHeadList(phead, plist); ++#endif ++} ++ ++void rtw_list_insert_tail(_list *plist, _list *phead) ++{ ++ ++#ifdef PLATFORM_LINUX ++ ++ list_add_tail(plist, phead); ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ ++ __list_add(plist, phead->prev, phead); ++ ++#endif ++#ifdef PLATFORM_WINDOWS ++ ++ InsertTailList(phead, plist); ++ ++#endif ++ ++} ++ ++ ++/* ++ ++Caller must check if the list is empty before calling rtw_list_delete ++ ++*/ ++ ++ ++void _rtw_init_sema(_sema *sema, int init_val) ++{ ++ ++#ifdef PLATFORM_LINUX ++ ++ sema_init(sema, init_val); ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ sema_init(sema, init_val, "rtw_drv"); ++#endif ++#ifdef PLATFORM_OS_XP ++ ++ KeInitializeSemaphore(sema, init_val, SEMA_UPBND); // count=0; ++ ++#endif ++ ++#ifdef PLATFORM_OS_CE ++ if(*sema == NULL) ++ *sema = CreateSemaphore(NULL, init_val, SEMA_UPBND, NULL); ++#endif ++ ++} ++ ++void _rtw_free_sema(_sema *sema) ++{ ++#ifdef PLATFORM_FREEBSD ++ sema_destroy(sema); ++#endif ++#ifdef PLATFORM_OS_CE ++ CloseHandle(*sema); ++#endif ++ ++} ++ ++void _rtw_up_sema(_sema *sema) ++{ ++ ++#ifdef PLATFORM_LINUX ++ ++ up(sema); ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ sema_post(sema); ++#endif ++#ifdef PLATFORM_OS_XP ++ ++ KeReleaseSemaphore(sema, IO_NETWORK_INCREMENT, 1, FALSE ); ++ ++#endif ++ ++#ifdef PLATFORM_OS_CE ++ ReleaseSemaphore(*sema, 1, NULL ); ++#endif ++} ++ ++u32 _rtw_down_sema(_sema *sema) ++{ ++ ++#ifdef PLATFORM_LINUX ++ ++ if (down_interruptible(sema)) ++ return _FAIL; ++ else ++ return _SUCCESS; ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ sema_wait(sema); ++ return _SUCCESS; ++#endif ++#ifdef PLATFORM_OS_XP ++ ++ if(STATUS_SUCCESS == KeWaitForSingleObject(sema, Executive, KernelMode, TRUE, NULL)) ++ return _SUCCESS; ++ else ++ return _FAIL; ++#endif ++ ++#ifdef PLATFORM_OS_CE ++ if(WAIT_OBJECT_0 == WaitForSingleObject(*sema, INFINITE )) ++ return _SUCCESS; ++ else ++ return _FAIL; ++#endif ++} ++ ++ ++ ++void _rtw_mutex_init(_mutex *pmutex) ++{ ++#ifdef PLATFORM_LINUX ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ mutex_init(pmutex); ++#else ++ init_MUTEX(pmutex); ++#endif ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ mtx_init(pmutex, "", NULL, MTX_DEF|MTX_RECURSE); ++#endif ++#ifdef PLATFORM_OS_XP ++ ++ KeInitializeMutex(pmutex, 0); ++ ++#endif ++ ++#ifdef PLATFORM_OS_CE ++ *pmutex = CreateMutex( NULL, _FALSE, NULL); ++#endif ++} ++ ++void _rtw_mutex_free(_mutex *pmutex); ++void _rtw_mutex_free(_mutex *pmutex) ++{ ++#ifdef PLATFORM_LINUX ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ mutex_destroy(pmutex); ++#else ++#endif ++ ++#ifdef PLATFORM_FREEBSD ++ sema_destroy(pmutex); ++#endif ++ ++#endif ++ ++#ifdef PLATFORM_OS_XP ++ ++#endif ++ ++#ifdef PLATFORM_OS_CE ++ ++#endif ++} ++ ++void _rtw_spinlock_init(_lock *plock) ++{ ++ ++#ifdef PLATFORM_LINUX ++ ++ spin_lock_init(plock); ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ mtx_init(plock, "", NULL, MTX_DEF|MTX_RECURSE); ++#endif ++#ifdef PLATFORM_WINDOWS ++ ++ NdisAllocateSpinLock(plock); ++ ++#endif ++ ++} ++ ++void _rtw_spinlock_free(_lock *plock) ++{ ++#ifdef PLATFORM_FREEBSD ++ mtx_destroy(plock); ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++ ++ NdisFreeSpinLock(plock); ++ ++#endif ++ ++} ++#ifdef PLATFORM_FREEBSD ++extern PADAPTER prtw_lock; ++ ++void rtw_mtx_lock(_lock *plock){ ++ if(prtw_lock){ ++ mtx_lock(&prtw_lock->glock); ++ } ++ else{ ++ printf("%s prtw_lock==NULL",__FUNCTION__); ++ } ++} ++void rtw_mtx_unlock(_lock *plock){ ++ if(prtw_lock){ ++ mtx_unlock(&prtw_lock->glock); ++ } ++ else{ ++ printf("%s prtw_lock==NULL",__FUNCTION__); ++ } ++ ++} ++#endif //PLATFORM_FREEBSD ++ ++ ++void _rtw_spinlock(_lock *plock) ++{ ++ ++#ifdef PLATFORM_LINUX ++ ++ spin_lock(plock); ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ mtx_lock(plock); ++#endif ++#ifdef PLATFORM_WINDOWS ++ ++ NdisAcquireSpinLock(plock); ++ ++#endif ++ ++} ++ ++void _rtw_spinunlock(_lock *plock) ++{ ++ ++#ifdef PLATFORM_LINUX ++ ++ spin_unlock(plock); ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ mtx_unlock(plock); ++#endif ++#ifdef PLATFORM_WINDOWS ++ ++ NdisReleaseSpinLock(plock); ++ ++#endif ++} ++ ++ ++void _rtw_spinlock_ex(_lock *plock) ++{ ++ ++#ifdef PLATFORM_LINUX ++ ++ spin_lock(plock); ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ mtx_lock(plock); ++#endif ++#ifdef PLATFORM_WINDOWS ++ ++ NdisDprAcquireSpinLock(plock); ++ ++#endif ++ ++} ++ ++void _rtw_spinunlock_ex(_lock *plock) ++{ ++ ++#ifdef PLATFORM_LINUX ++ ++ spin_unlock(plock); ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ mtx_unlock(plock); ++#endif ++#ifdef PLATFORM_WINDOWS ++ ++ NdisDprReleaseSpinLock(plock); ++ ++#endif ++} ++ ++ ++ ++void _rtw_init_queue(_queue *pqueue) ++{ ++ ++ _rtw_init_listhead(&(pqueue->queue)); ++ ++ _rtw_spinlock_init(&(pqueue->lock)); ++ ++} ++ ++u32 _rtw_queue_empty(_queue *pqueue) ++{ ++ return (rtw_is_list_empty(&(pqueue->queue))); ++} ++ ++ ++u32 rtw_end_of_queue_search(_list *head, _list *plist) ++{ ++ if (head == plist) ++ return _TRUE; ++ else ++ return _FALSE; ++} ++ ++ ++u32 rtw_get_current_time(void) ++{ ++ ++#ifdef PLATFORM_LINUX ++ return jiffies; ++#endif ++#ifdef PLATFORM_FREEBSD ++ struct timeval tvp; ++ getmicrotime(&tvp); ++ return tvp.tv_sec; ++#endif ++#ifdef PLATFORM_WINDOWS ++ LARGE_INTEGER SystemTime; ++ NdisGetCurrentSystemTime(&SystemTime); ++ return (u32)(SystemTime.LowPart);// count of 100-nanosecond intervals ++#endif ++} ++ ++inline u32 rtw_systime_to_ms(u32 systime) ++{ ++#ifdef PLATFORM_LINUX ++ return systime * 1000 / HZ; ++#endif ++#ifdef PLATFORM_FREEBSD ++ return systime * 1000; ++#endif ++#ifdef PLATFORM_WINDOWS ++ return systime / 10000 ; ++#endif ++} ++ ++inline u32 rtw_ms_to_systime(u32 ms) ++{ ++#ifdef PLATFORM_LINUX ++ return ms * HZ / 1000; ++#endif ++#ifdef PLATFORM_FREEBSD ++ return ms /1000; ++#endif ++#ifdef PLATFORM_WINDOWS ++ return ms * 10000 ; ++#endif ++} ++ ++// the input parameter start use the same unit as returned by rtw_get_current_time ++inline s32 rtw_get_passing_time_ms(u32 start) ++{ ++#ifdef PLATFORM_LINUX ++ return rtw_systime_to_ms(jiffies-start); ++#endif ++#ifdef PLATFORM_FREEBSD ++ return rtw_systime_to_ms(rtw_get_current_time()); ++#endif ++#ifdef PLATFORM_WINDOWS ++ LARGE_INTEGER SystemTime; ++ NdisGetCurrentSystemTime(&SystemTime); ++ return rtw_systime_to_ms((u32)(SystemTime.LowPart) - start) ; ++#endif ++} ++ ++inline s32 rtw_get_time_interval_ms(u32 start, u32 end) ++{ ++#ifdef PLATFORM_LINUX ++ return rtw_systime_to_ms(end-start); ++#endif ++#ifdef PLATFORM_FREEBSD ++ return rtw_systime_to_ms(rtw_get_current_time()); ++#endif ++#ifdef PLATFORM_WINDOWS ++ return rtw_systime_to_ms(end-start); ++#endif ++} ++ ++ ++void rtw_sleep_schedulable(int ms) ++{ ++ ++#ifdef PLATFORM_LINUX ++ ++ u32 delta; ++ ++ delta = (ms * HZ)/1000;//(ms) ++ if (delta == 0) { ++ delta = 1;// 1 ms ++ } ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (schedule_timeout(delta) != 0) { ++ return ; ++ } ++ return; ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ DELAY(ms*1000); ++ return ; ++#endif ++ ++#ifdef PLATFORM_WINDOWS ++ ++ NdisMSleep(ms*1000); //(us)*1000=(ms) ++ ++#endif ++ ++} ++ ++ ++void rtw_msleep_os(int ms) ++{ ++ ++#ifdef PLATFORM_LINUX ++ ++ msleep((unsigned int)ms); ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ //Delay for delay microseconds ++ DELAY(ms*1000); ++ return ; ++#endif ++#ifdef PLATFORM_WINDOWS ++ ++ NdisMSleep(ms*1000); //(us)*1000=(ms) ++ ++#endif ++ ++ ++} ++void rtw_usleep_os(int us) ++{ ++ ++#ifdef PLATFORM_LINUX ++ ++ // msleep((unsigned int)us); ++ if ( 1 < (us/1000) ) ++ msleep(1); ++ else ++ msleep( (us/1000) + 1); ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ //Delay for delay microseconds ++ DELAY(us); ++ ++ return ; ++#endif ++#ifdef PLATFORM_WINDOWS ++ ++ NdisMSleep(us); //(us) ++ ++#endif ++ ++ ++} ++ ++ ++#ifdef DBG_DELAY_OS ++void _rtw_mdelay_os(int ms, const char *func, const int line) ++{ ++ #if 0 ++ if(ms>10) ++ DBG_871X("%s:%d %s(%d)\n", func, line, __FUNCTION__, ms); ++ rtw_msleep_os(ms); ++ return; ++ #endif ++ ++ ++ DBG_871X("%s:%d %s(%d)\n", func, line, __FUNCTION__, ms); ++ ++#if defined(PLATFORM_LINUX) ++ ++ mdelay((unsigned long)ms); ++ ++#elif defined(PLATFORM_WINDOWS) ++ ++ NdisStallExecution(ms*1000); //(us)*1000=(ms) ++ ++#endif ++ ++ ++} ++void _rtw_udelay_os(int us, const char *func, const int line) ++{ ++ ++ #if 0 ++ if(us > 1000) { ++ DBG_871X("%s:%d %s(%d)\n", func, line, __FUNCTION__, us); ++ rtw_usleep_os(us); ++ return; ++ } ++ #endif ++ ++ ++ DBG_871X("%s:%d %s(%d)\n", func, line, __FUNCTION__, us); ++ ++ ++#if defined(PLATFORM_LINUX) ++ ++ udelay((unsigned long)us); ++ ++#elif defined(PLATFORM_WINDOWS) ++ ++ NdisStallExecution(us); //(us) ++ ++#endif ++ ++} ++#else ++void rtw_mdelay_os(int ms) ++{ ++ ++#ifdef PLATFORM_LINUX ++ ++ mdelay((unsigned long)ms); ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ DELAY(ms*1000); ++ return ; ++#endif ++#ifdef PLATFORM_WINDOWS ++ ++ NdisStallExecution(ms*1000); //(us)*1000=(ms) ++ ++#endif ++ ++ ++} ++void rtw_udelay_os(int us) ++{ ++ ++#ifdef PLATFORM_LINUX ++ ++ udelay((unsigned long)us); ++ ++#endif ++#ifdef PLATFORM_FREEBSD ++ //Delay for delay microseconds ++ DELAY(us); ++ return ; ++#endif ++#ifdef PLATFORM_WINDOWS ++ ++ NdisStallExecution(us); //(us) ++ ++#endif ++ ++} ++#endif ++ ++void rtw_yield_os() ++{ ++#ifdef PLATFORM_LINUX ++ yield(); ++#endif ++#ifdef PLATFORM_FREEBSD ++ yield(); ++#endif ++#ifdef PLATFORM_WINDOWS ++ SwitchToThread(); ++#endif ++} ++ ++#define RTW_SUSPEND_LOCK_NAME "rtw_wifi" ++#define RTW_SUSPEND_EXT_LOCK_NAME "rtw_wifi_ext" ++ ++ ++#ifdef CONFIG_WAKELOCK ++static struct wake_lock rtw_suspend_lock; ++static struct wake_lock rtw_suspend_ext_lock; ++#elif defined(CONFIG_ANDROID_POWER) ++static android_suspend_lock_t rtw_suspend_lock ={ ++ .name = RTW_SUSPEND_LOCK_NAME ++}; ++static android_suspend_lock_t rtw_suspend_ext_lock ={ ++ .name = RTW_SUSPEND_EXT_LOCK_NAME ++}; ++#endif ++ ++inline void rtw_suspend_lock_init() ++{ ++ #ifdef CONFIG_WAKELOCK ++ wake_lock_init(&rtw_suspend_lock, WAKE_LOCK_SUSPEND, RTW_SUSPEND_LOCK_NAME); ++ wake_lock_init(&rtw_suspend_ext_lock, WAKE_LOCK_SUSPEND, RTW_SUSPEND_EXT_LOCK_NAME); ++ #elif defined(CONFIG_ANDROID_POWER) ++ android_init_suspend_lock(&rtw_suspend_lock); ++ android_init_suspend_ext_lock(&rtw_suspend_ext_lock); ++ #endif ++} ++ ++inline void rtw_suspend_lock_uninit() ++{ ++ #ifdef CONFIG_WAKELOCK ++ wake_lock_destroy(&rtw_suspend_lock); ++ wake_lock_destroy(&rtw_suspend_ext_lock); ++ #elif defined(CONFIG_ANDROID_POWER) ++ android_uninit_suspend_lock(&rtw_suspend_lock); ++ android_uninit_suspend_lock(&rtw_suspend_ext_lock); ++ #endif ++} ++ ++inline void rtw_lock_suspend() ++{ ++ #ifdef CONFIG_WAKELOCK ++ wake_lock(&rtw_suspend_lock); ++ #elif defined(CONFIG_ANDROID_POWER) ++ android_lock_suspend(&rtw_suspend_lock); ++ #endif ++ ++ #if defined(CONFIG_WAKELOCK) || defined(CONFIG_ANDROID_POWER) ++ //DBG_871X("####%s: suspend_lock_count:%d####\n", __FUNCTION__, rtw_suspend_lock.stat.count); ++ #endif ++} ++ ++inline void rtw_unlock_suspend() ++{ ++ #ifdef CONFIG_WAKELOCK ++ wake_unlock(&rtw_suspend_lock); ++ #elif defined(CONFIG_ANDROID_POWER) ++ android_unlock_suspend(&rtw_suspend_lock); ++ #endif ++ ++ #if defined(CONFIG_WAKELOCK) || defined(CONFIG_ANDROID_POWER) ++ //DBG_871X("####%s: suspend_lock_count:%d####\n", __FUNCTION__, rtw_suspend_lock.stat.count); ++ #endif ++} ++ ++inline void rtw_lock_suspend_timeout(u32 timeout_ms) ++{ ++ #ifdef CONFIG_WAKELOCK ++ wake_lock_timeout(&rtw_suspend_lock, rtw_ms_to_systime(timeout_ms)); ++ #elif defined(CONFIG_ANDROID_POWER) ++ android_lock_suspend_auto_expire(&rtw_suspend_lock, rtw_ms_to_systime(timeout_ms)); ++ #endif ++} ++ ++inline void rtw_lock_ext_suspend_timeout(u32 timeout_ms) ++{ ++ #ifdef CONFIG_WAKELOCK ++ wake_lock_timeout(&rtw_suspend_ext_lock, rtw_ms_to_systime(timeout_ms)); ++ #elif defined(CONFIG_ANDROID_POWER) ++ android_lock_suspend_auto_expire(&rtw_suspend_ext_lock, rtw_ms_to_systime(timeout_ms)); ++ #endif ++} ++ ++inline void ATOMIC_SET(ATOMIC_T *v, int i) ++{ ++ #ifdef PLATFORM_LINUX ++ atomic_set(v,i); ++ #elif defined(PLATFORM_WINDOWS) ++ *v=i;// other choice???? ++ #elif defined(PLATFORM_FREEBSD) ++ atomic_set_int(v,i); ++ #endif ++} ++ ++inline int ATOMIC_READ(ATOMIC_T *v) ++{ ++ #ifdef PLATFORM_LINUX ++ return atomic_read(v); ++ #elif defined(PLATFORM_WINDOWS) ++ return *v; // other choice???? ++ #elif defined(PLATFORM_FREEBSD) ++ return atomic_load_acq_32(v); ++ #endif ++} ++ ++inline void ATOMIC_ADD(ATOMIC_T *v, int i) ++{ ++ #ifdef PLATFORM_LINUX ++ atomic_add(i,v); ++ #elif defined(PLATFORM_WINDOWS) ++ InterlockedAdd(v,i); ++ #elif defined(PLATFORM_FREEBSD) ++ atomic_add_int(v,i); ++ #endif ++} ++inline void ATOMIC_SUB(ATOMIC_T *v, int i) ++{ ++ #ifdef PLATFORM_LINUX ++ atomic_sub(i,v); ++ #elif defined(PLATFORM_WINDOWS) ++ InterlockedAdd(v,-i); ++ #elif defined(PLATFORM_FREEBSD) ++ atomic_subtract_int(v,i); ++ #endif ++} ++ ++inline void ATOMIC_INC(ATOMIC_T *v) ++{ ++ #ifdef PLATFORM_LINUX ++ atomic_inc(v); ++ #elif defined(PLATFORM_WINDOWS) ++ InterlockedIncrement(v); ++ #elif defined(PLATFORM_FREEBSD) ++ atomic_add_int(v,1); ++ #endif ++} ++ ++inline void ATOMIC_DEC(ATOMIC_T *v) ++{ ++ #ifdef PLATFORM_LINUX ++ atomic_dec(v); ++ #elif defined(PLATFORM_WINDOWS) ++ InterlockedDecrement(v); ++ #elif defined(PLATFORM_FREEBSD) ++ atomic_subtract_int(v,1); ++ #endif ++} ++ ++inline int ATOMIC_ADD_RETURN(ATOMIC_T *v, int i) ++{ ++ #ifdef PLATFORM_LINUX ++ return atomic_add_return(i,v); ++ #elif defined(PLATFORM_WINDOWS) ++ return InterlockedAdd(v,i); ++ #elif defined(PLATFORM_FREEBSD) ++ atomic_add_int(v,i); ++ return atomic_load_acq_32(v); ++ #endif ++} ++ ++inline int ATOMIC_SUB_RETURN(ATOMIC_T *v, int i) ++{ ++ #ifdef PLATFORM_LINUX ++ return atomic_sub_return(i,v); ++ #elif defined(PLATFORM_WINDOWS) ++ return InterlockedAdd(v,-i); ++ #elif defined(PLATFORM_FREEBSD) ++ atomic_subtract_int(v,i); ++ return atomic_load_acq_32(v); ++ #endif ++} ++ ++inline int ATOMIC_INC_RETURN(ATOMIC_T *v) ++{ ++ #ifdef PLATFORM_LINUX ++ return atomic_inc_return(v); ++ #elif defined(PLATFORM_WINDOWS) ++ return InterlockedIncrement(v); ++ #elif defined(PLATFORM_FREEBSD) ++ atomic_add_int(v,1); ++ return atomic_load_acq_32(v); ++ #endif ++} ++ ++inline int ATOMIC_DEC_RETURN(ATOMIC_T *v) ++{ ++ #ifdef PLATFORM_LINUX ++ return atomic_dec_return(v); ++ #elif defined(PLATFORM_WINDOWS) ++ return InterlockedDecrement(v); ++ #elif defined(PLATFORM_FREEBSD) ++ atomic_subtract_int(v,1); ++ return atomic_load_acq_32(v); ++ #endif ++} ++ ++ ++#ifdef PLATFORM_LINUX ++/* ++* Open a file with the specific @param path, @param flag, @param mode ++* @param fpp the pointer of struct file pointer to get struct file pointer while file opening is success ++* @param path the path of the file to open ++* @param flag file operation flags, please refer to linux document ++* @param mode please refer to linux document ++* @return Linux specific error code ++*/ ++static int openFile(struct file **fpp, char *path, int flag, int mode) ++{ ++ struct file *fp; ++ ++ fp=filp_open(path, flag, mode); ++ if(IS_ERR(fp)) { ++ *fpp=NULL; ++ return PTR_ERR(fp); ++ } ++ else { ++ *fpp=fp; ++ return 0; ++ } ++} ++ ++/* ++* Close the file with the specific @param fp ++* @param fp the pointer of struct file to close ++* @return always 0 ++*/ ++static int closeFile(struct file *fp) ++{ ++ filp_close(fp,NULL); ++ return 0; ++} ++ ++static int readFile(struct file *fp,char *buf,int len) ++{ ++ int rlen=0, sum=0; ++ ++ if (!fp->f_op || !fp->f_op->read) ++ return -EPERM; ++ ++ while(sumf_op->read(fp,buf+sum,len-sum, &fp->f_pos); ++ if(rlen>0) ++ sum+=rlen; ++ else if(0 != rlen) ++ return rlen; ++ else ++ break; ++ } ++ ++ return sum; ++ ++} ++ ++static int writeFile(struct file *fp,char *buf,int len) ++{ ++ int wlen=0, sum=0; ++ ++ if (!fp->f_op || !fp->f_op->write) ++ return -EPERM; ++ ++ while(sumf_op->write(fp,buf+sum,len-sum, &fp->f_pos); ++ if(wlen>0) ++ sum+=wlen; ++ else if(0 != wlen) ++ return wlen; ++ else ++ break; ++ } ++ ++ return sum; ++ ++} ++ ++/* ++* Test if the specifi @param path is a file and readable ++* @param path the path of the file to test ++* @return Linux specific error code ++*/ ++static int isFileReadable(char *path) ++{ ++ struct file *fp; ++ int ret = 0; ++ mm_segment_t oldfs; ++ char buf; ++ ++ fp=filp_open(path, O_RDONLY, 0); ++ if(IS_ERR(fp)) { ++ ret = PTR_ERR(fp); ++ } ++ else { ++ oldfs = get_fs(); set_fs(get_ds()); ++ ++ if(1!=readFile(fp, &buf, 1)) ++ ret = PTR_ERR(fp); ++ ++ set_fs(oldfs); ++ filp_close(fp,NULL); ++ } ++ return ret; ++} ++ ++/* ++* Open the file with @param path and retrive the file content into memory starting from @param buf for @param sz at most ++* @param path the path of the file to open and read ++* @param buf the starting address of the buffer to store file content ++* @param sz how many bytes to read at most ++* @return the byte we've read, or Linux specific error code ++*/ ++static int retriveFromFile(char *path, u8* buf, u32 sz) ++{ ++ int ret =-1; ++ mm_segment_t oldfs; ++ struct file *fp; ++ ++ if(path && buf) { ++ if( 0 == (ret=openFile(&fp,path, O_RDONLY, 0)) ){ ++ DBG_871X("%s openFile path:%s fp=%p\n",__FUNCTION__, path ,fp); ++ ++ oldfs = get_fs(); set_fs(get_ds()); ++ ret=readFile(fp, buf, sz); ++ set_fs(oldfs); ++ closeFile(fp); ++ ++ DBG_871X("%s readFile, ret:%d\n",__FUNCTION__, ret); ++ ++ } else { ++ DBG_871X("%s openFile path:%s Fail, ret:%d\n",__FUNCTION__, path, ret); ++ } ++ } else { ++ DBG_871X("%s NULL pointer\n",__FUNCTION__); ++ ret = -EINVAL; ++ } ++ return ret; ++} ++ ++/* ++* Open the file with @param path and wirte @param sz byte of data starting from @param buf into the file ++* @param path the path of the file to open and write ++* @param buf the starting address of the data to write into file ++* @param sz how many bytes to write at most ++* @return the byte we've written, or Linux specific error code ++*/ ++static int storeToFile(char *path, u8* buf, u32 sz) ++{ ++ int ret =0; ++ mm_segment_t oldfs; ++ struct file *fp; ++ ++ if(path && buf) { ++ if( 0 == (ret=openFile(&fp, path, O_CREAT|O_WRONLY, 0666)) ) { ++ DBG_871X("%s openFile path:%s fp=%p\n",__FUNCTION__, path ,fp); ++ ++ oldfs = get_fs(); set_fs(get_ds()); ++ ret=writeFile(fp, buf, sz); ++ set_fs(oldfs); ++ closeFile(fp); ++ ++ DBG_871X("%s writeFile, ret:%d\n",__FUNCTION__, ret); ++ ++ } else { ++ DBG_871X("%s openFile path:%s Fail, ret:%d\n",__FUNCTION__, path, ret); ++ } ++ } else { ++ DBG_871X("%s NULL pointer\n",__FUNCTION__); ++ ret = -EINVAL; ++ } ++ return ret; ++} ++#endif //PLATFORM_LINUX ++ ++/* ++* Test if the specifi @param path is a file and readable ++* @param path the path of the file to test ++* @return _TRUE or _FALSE ++*/ ++int rtw_is_file_readable(char *path) ++{ ++#ifdef PLATFORM_LINUX ++ if(isFileReadable(path) == 0) ++ return _TRUE; ++ else ++ return _FALSE; ++#else ++ //Todo... ++ return _FALSE; ++#endif ++} ++ ++/* ++* Open the file with @param path and retrive the file content into memory starting from @param buf for @param sz at most ++* @param path the path of the file to open and read ++* @param buf the starting address of the buffer to store file content ++* @param sz how many bytes to read at most ++* @return the byte we've read ++*/ ++int rtw_retrive_from_file(char *path, u8* buf, u32 sz) ++{ ++#ifdef PLATFORM_LINUX ++ int ret =retriveFromFile(path, buf, sz); ++ return ret>=0?ret:0; ++#else ++ //Todo... ++ return 0; ++#endif ++} ++ ++/* ++* Open the file with @param path and wirte @param sz byte of data starting from @param buf into the file ++* @param path the path of the file to open and write ++* @param buf the starting address of the data to write into file ++* @param sz how many bytes to write at most ++* @return the byte we've written ++*/ ++int rtw_store_to_file(char *path, u8* buf, u32 sz) ++{ ++#ifdef PLATFORM_LINUX ++ int ret =storeToFile(path, buf, sz); ++ return ret>=0?ret:0; ++#else ++ //Todo... ++ return 0; ++#endif ++} ++ ++#if 1 //#ifdef MEM_ALLOC_REFINE_ADAPTOR ++#ifdef PLATFORM_LINUX ++struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv, void *old_priv) ++{ ++ struct net_device *pnetdev; ++ struct rtw_netdev_priv_indicator *pnpi; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) ++ pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4); ++#else ++ pnetdev = alloc_etherdev(sizeof(struct rtw_netdev_priv_indicator)); ++#endif ++ if (!pnetdev) ++ goto RETURN; ++ ++ pnpi = netdev_priv(pnetdev); ++ pnpi->priv=old_priv; ++ pnpi->sizeof_priv=sizeof_priv; ++ ++RETURN: ++ return pnetdev; ++} ++ ++struct net_device *rtw_alloc_etherdev(int sizeof_priv) ++{ ++ struct net_device *pnetdev; ++ struct rtw_netdev_priv_indicator *pnpi; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) ++ pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4); ++#else ++ pnetdev = alloc_etherdev(sizeof(struct rtw_netdev_priv_indicator)); ++#endif ++ if (!pnetdev) ++ goto RETURN; ++ ++ pnpi = netdev_priv(pnetdev); ++ ++ pnpi->priv = rtw_zvmalloc(sizeof_priv); ++ if (!pnpi->priv) { ++ free_netdev(pnetdev); ++ pnetdev = NULL; ++ goto RETURN; ++ } ++ ++ pnpi->sizeof_priv=sizeof_priv; ++RETURN: ++ return pnetdev; ++} ++ ++void rtw_free_netdev(struct net_device * netdev) ++{ ++ struct rtw_netdev_priv_indicator *pnpi; ++ ++ if(!netdev) ++ goto RETURN; ++ ++ pnpi = netdev_priv(netdev); ++ ++ if(!pnpi->priv) ++ goto RETURN; ++ ++ rtw_vmfree(pnpi->priv, pnpi->sizeof_priv); ++ free_netdev(netdev); ++ ++RETURN: ++ return; ++} ++ ++/* ++* Jeff: this function should be called under ioctl (rtnl_lock is accquired) while ++* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) ++*/ ++int rtw_change_ifname(_adapter *padapter, const char *ifname) ++{ ++ struct net_device *pnetdev; ++ struct net_device *cur_pnetdev = padapter->pnetdev; ++ struct rereg_nd_name_data *rereg_priv; ++ int ret; ++ ++ if(!padapter) ++ goto error; ++ ++ rereg_priv = &padapter->rereg_nd_name_priv; ++ ++ //free the old_pnetdev ++ if(rereg_priv->old_pnetdev) { ++ free_netdev(rereg_priv->old_pnetdev); ++ rereg_priv->old_pnetdev = NULL; ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)) ++ if(!rtnl_is_locked()) ++ unregister_netdev(cur_pnetdev); ++ else ++#endif ++ unregister_netdevice(cur_pnetdev); ++ ++ rtw_proc_remove_one(cur_pnetdev); ++ ++ rereg_priv->old_pnetdev=cur_pnetdev; ++ ++ pnetdev = rtw_init_netdev(padapter); ++ if (!pnetdev) { ++ ret = -1; ++ goto error; ++ } ++ ++ SET_NETDEV_DEV(pnetdev, dvobj_to_dev(adapter_to_dvobj(padapter))); ++ ++ rtw_init_netdev_name(pnetdev, ifname); ++ ++ _rtw_memcpy(pnetdev->dev_addr, padapter->eeprompriv.mac_addr, ETH_ALEN); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)) ++ if(!rtnl_is_locked()) ++ ret = register_netdev(pnetdev); ++ else ++#endif ++ ret = register_netdevice(pnetdev); ++ ++ if ( ret != 0) { ++ RT_TRACE(_module_hci_intfs_c_,_drv_err_,("register_netdev() failed\n")); ++ goto error; ++ } ++ ++ rtw_proc_init_one(pnetdev); ++ ++ return 0; ++ ++error: ++ ++ return -1; ++ ++} ++#endif ++#endif //MEM_ALLOC_REFINE_ADAPTOR ++ ++#ifdef PLATFORM_FREEBSD ++/* ++ * Copy a buffer from userspace and write into kernel address ++ * space. ++ * ++ * This emulation just calls the FreeBSD copyin function (to ++ * copy data from user space buffer into a kernel space buffer) ++ * and is designed to be used with the above io_write_wrapper. ++ * ++ * This function should return the number of bytes not copied. ++ * I.e. success results in a zero value. ++ * Negative error values are not returned. ++ */ ++unsigned long ++copy_from_user(void *to, const void *from, unsigned long n) ++{ ++ if ( copyin(from, to, n) != 0 ) { ++ /* Any errors will be treated as a failure ++ to copy any of the requested bytes */ ++ return n; ++ } ++ ++ return 0; ++} ++ ++unsigned long ++copy_to_user(void *to, const void *from, unsigned long n) ++{ ++ if ( copyout(from, to, n) != 0 ) { ++ /* Any errors will be treated as a failure ++ to copy any of the requested bytes */ ++ return n; ++ } ++ ++ return 0; ++} ++ ++ ++/* ++ * The usb_register and usb_deregister functions are used to register ++ * usb drivers with the usb subsystem. In this compatibility layer ++ * emulation a list of drivers (struct usb_driver) is maintained ++ * and is used for probing/attaching etc. ++ * ++ * usb_register and usb_deregister simply call these functions. ++ */ ++int ++usb_register(struct usb_driver *driver) ++{ ++ rtw_usb_linux_register(driver); ++ return 0; ++} ++ ++ ++int ++usb_deregister(struct usb_driver *driver) ++{ ++ rtw_usb_linux_deregister(driver); ++ return 0; ++} ++ ++void module_init_exit_wrapper(void *arg) ++{ ++ int (*func)(void) = arg; ++ func(); ++ return; ++} ++ ++#endif //PLATFORM_FREEBSD ++ ++#ifdef CONFIG_PLATFORM_SPRD ++#ifdef do_div ++#undef do_div ++#endif ++#include ++#endif ++ ++u64 rtw_modular64(u64 x, u64 y) ++{ ++#ifdef PLATFORM_LINUX ++ return do_div(x, y); ++#elif defined(PLATFORM_WINDOWS) ++ return (x % y); ++#elif defined(PLATFORM_FREEBSD) ++ return (x %y); ++#endif ++} ++ ++u64 rtw_division64(u64 x, u64 y) ++{ ++#ifdef PLATFORM_LINUX ++ do_div(x, y); ++ return x; ++#elif defined(PLATFORM_WINDOWS) ++ return (x / y); ++#elif defined(PLATFORM_FREEBSD) ++ return (x / y); ++#endif ++} ++ ++void rtw_buf_free(u8 **buf, u32 *buf_len) ++{ ++ u32 ori_len; ++ ++ if (!buf || !buf_len) ++ return; ++ ++ ori_len = *buf_len; ++ ++ if (*buf) { ++ u32 tmp_buf_len = *buf_len; ++ *buf_len = 0; ++ rtw_mfree(*buf, tmp_buf_len); ++ *buf = NULL; ++ } ++} ++ ++void rtw_buf_update(u8 **buf, u32 *buf_len, u8 *src, u32 src_len) ++{ ++ u32 ori_len = 0, dup_len = 0; ++ u8 *ori = NULL; ++ u8 *dup = NULL; ++ ++ if (!buf || !buf_len) ++ return; ++ ++ if (!src || !src_len) ++ goto keep_ori; ++ ++ /* duplicate src */ ++ dup = rtw_malloc(src_len); ++ if (dup) { ++ dup_len = src_len; ++ _rtw_memcpy(dup, src, dup_len); ++ } ++ ++keep_ori: ++ ori = *buf; ++ ori_len = *buf_len; ++ ++ /* replace buf with dup */ ++ *buf_len = 0; ++ *buf = dup; ++ *buf_len = dup_len; ++ ++ /* free ori */ ++ if (ori && ori_len > 0) ++ rtw_mfree(ori, ori_len); ++} ++ ++ ++/** ++ * rtw_cbuf_full - test if cbuf is full ++ * @cbuf: pointer of struct rtw_cbuf ++ * ++ * Returns: _TRUE if cbuf is full ++ */ ++inline bool rtw_cbuf_full(struct rtw_cbuf *cbuf) ++{ ++ return (cbuf->write == cbuf->read-1)? _TRUE : _FALSE; ++} ++ ++/** ++ * rtw_cbuf_empty - test if cbuf is empty ++ * @cbuf: pointer of struct rtw_cbuf ++ * ++ * Returns: _TRUE if cbuf is empty ++ */ ++inline bool rtw_cbuf_empty(struct rtw_cbuf *cbuf) ++{ ++ return (cbuf->write == cbuf->read)? _TRUE : _FALSE; ++} ++ ++/** ++ * rtw_cbuf_push - push a pointer into cbuf ++ * @cbuf: pointer of struct rtw_cbuf ++ * @buf: pointer to push in ++ * ++ * Lock free operation, be careful of the use scheme ++ * Returns: _TRUE push success ++ */ ++bool rtw_cbuf_push(struct rtw_cbuf *cbuf, void *buf) ++{ ++ if (rtw_cbuf_full(cbuf)) ++ return _FAIL; ++ ++ if (0) ++ DBG_871X("%s on %u\n", __func__, cbuf->write); ++ cbuf->bufs[cbuf->write] = buf; ++ cbuf->write = (cbuf->write+1)%cbuf->size; ++ ++ return _SUCCESS; ++} ++ ++/** ++ * rtw_cbuf_pop - pop a pointer from cbuf ++ * @cbuf: pointer of struct rtw_cbuf ++ * ++ * Lock free operation, be careful of the use scheme ++ * Returns: pointer popped out ++ */ ++void *rtw_cbuf_pop(struct rtw_cbuf *cbuf) ++{ ++ void *buf; ++ if (rtw_cbuf_empty(cbuf)) ++ return NULL; ++ ++ if (0) ++ DBG_871X("%s on %u\n", __func__, cbuf->read); ++ buf = cbuf->bufs[cbuf->read]; ++ cbuf->read = (cbuf->read+1)%cbuf->size; ++ ++ return buf; ++} ++ ++/** ++ * rtw_cbuf_alloc - allocte a rtw_cbuf with given size and do initialization ++ * @size: size of pointer ++ * ++ * Returns: pointer of srtuct rtw_cbuf, NULL for allocation failure ++ */ ++struct rtw_cbuf *rtw_cbuf_alloc(u32 size) ++{ ++ struct rtw_cbuf *cbuf; ++ ++ cbuf = (struct rtw_cbuf *)rtw_malloc(sizeof(*cbuf) + sizeof(void*)*size); ++ ++ if (cbuf) { ++ cbuf->write = cbuf->read = 0; ++ cbuf->size = size; ++ } ++ ++ return cbuf; ++} ++ ++/** ++ * rtw_cbuf_free - free the given rtw_cbuf ++ * @cbuf: pointer of struct rtw_cbuf to free ++ */ ++void rtw_cbuf_free(struct rtw_cbuf *cbuf) ++{ ++ rtw_mfree((u8*)cbuf, sizeof(*cbuf) + sizeof(void*)*cbuf->size); ++} ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/runwpa b/drivers/net/wireless/rtl818x/rtl8189/runwpa +new file mode 100644 +index 00000000..f825e8bd +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/runwpa +@@ -0,0 +1,20 @@ ++#!/bin/bash ++ ++if [ "`which iwconfig`" = "" ] ; then ++ echo "WARNING:Wireless tool not exist!" ++ echo " Please install it!" ++ exit ++else ++ if [ `uname -r | cut -d. -f2` -eq 4 ]; then ++ wpa_supplicant -D ipw -c wpa1.conf -i wlan0 ++ else ++ if [ `iwconfig -v |awk '{print $4}' | head -n 1` -lt 18 ] ; then ++ wpa_supplicant -D ipw -c wpa1.conf -i wlan0 ++ else ++ wpa_supplicant -D wext -c wpa1.conf -i wlan0 ++ fi ++ ++ fi ++fi ++ ++ +diff --git a/drivers/net/wireless/rtl818x/rtl8189/wlan0dhcp b/drivers/net/wireless/rtl818x/rtl8189/wlan0dhcp +new file mode 100644 +index 00000000..60433829 +--- /dev/null ++++ b/drivers/net/wireless/rtl818x/rtl8189/wlan0dhcp +@@ -0,0 +1,16 @@ ++#!/bin/bash ++ ++var0=`ps aux|awk '/dhclient wlan0/'|awk '$11!="awk"{print $2}'` ++ ++kill $var0 ++cp ifcfg-wlan0 /etc/sysconfig/network-scripts/ ++ ++dhclient wlan0 ++ ++var1=`ifconfig wlan0 |awk '/inet/{print $2}'|awk -F: '{print $2}'` ++ ++ ++rm -f /etc/sysconfig/network-scripts/ifcfg-wlan0 ++ ++echo "get ip: $var1" ++ +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 8c8377d5..8f99de1a 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1087,4 +1087,26 @@ config RTC_DRV_LOONGSON1 + This driver can also be built as a module. If so, the module + will be called rtc-ls1x. + ++config RTC_DRV_GOKE ++ tristate "goke ipc RTC" ++ depends on GK_RTC ++ help ++ RTC (Realtime Clock) driver for goke ipc. ++choice ++ prompt "Select RTC clock" ++ depends on RTC_DRV_GOKE ++ default CLOCK_24M ++ help ++ Select board base on goke ipc ++ ++config CLOCK_32K ++ bool "32k HZ" ++ help ++ Select Goke goke ipc RTC CLOCK 32k ++ ++config CLOCK_24M ++ bool "24M HZ" ++ help ++ Select Goke goke ipc RTC CLOCK 24M ++endchoice + endif # RTC_CLASS +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 727ae778..61936a30 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -111,3 +111,7 @@ obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o + obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o + obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o + obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o ++ifdef CONFIG_RTC_DRV_GOKE ++obj-$(CONFIG_GK_RTC_V1_00) += rtc-gk_v1_00.o ++endif ++ +diff --git a/drivers/rtc/rtc-gk_v1_00.c b/drivers/rtc/rtc-gk_v1_00.c +new file mode 100644 +index 00000000..6b0db1ab +--- /dev/null ++++ b/drivers/rtc/rtc-gk_v1_00.c +@@ -0,0 +1,320 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ADDR_SHIFT 2 ++ ++#define PWRMGR_BASE GK_VA_PMU_RTC ++ ++#define MCU_RTC_BASE (PWRMGR_BASE + (0x0000 << ADDR_SHIFT)) ++#define MCU_SYS_BASE (PWRMGR_BASE + (0x2800 << ADDR_SHIFT)) ++ ++/* System configure 17 register */ ++#define SYS_REG_CFG17 (MCU_SYS_BASE + (0x0011 << ADDR_SHIFT)) ++#define CFG17_RTC_CLK_SEL_32K (1<<0) ++#define CFG17_RTC_CLK_SEL_24M (0<<0) ++#define CFG17_RTC_SOFT_RESET (1<<1) ++ ++/********************************/ ++/* RTC Register List */ ++/********************************/ ++#define RTC_SYS_CONFIG (MCU_RTC_BASE + (0x00 << ADDR_SHIFT)) ++#define RTC_IRQ_ENABLE (1<<5) ++#define RTC_PAUSE_ENABLE (1<<4) ++#define RTC_STOP_ENABLE (1<<3) ++#define RTC_ENABLE (1<<0) ++ ++#define RTC_P_SCALER_DIV0 (MCU_RTC_BASE + (0x01 << ADDR_SHIFT)) ++#define RTC_P_SCALER_DIV1 (MCU_RTC_BASE + (0x02 << ADDR_SHIFT)) ++#define RTC_P_SCALER_DIV2 (MCU_RTC_BASE + (0x03 << ADDR_SHIFT)) ++#define RTC_P_SCALER_DIV3 (MCU_RTC_BASE + (0x04 << ADDR_SHIFT)) ++ ++#define RTC_PRE_LOAD_HOUR (MCU_RTC_BASE + (0x05 << ADDR_SHIFT)) ++#define RTC_PRE_LOAD_MIN (MCU_RTC_BASE + (0x06 << ADDR_SHIFT)) ++#define RTC_PRE_LOAD_SEC (MCU_RTC_BASE + (0x07 << ADDR_SHIFT)) ++ ++#define RTC_IRQ_CLEAR (MCU_RTC_BASE + (0x08 << ADDR_SHIFT)) ++#define RTC_IRQ_CLR (1<<0) ++ ++#define RTC_PRE_LOAD_DAY_L (MCU_RTC_BASE + (0x09 << ADDR_SHIFT)) ++#define RTC_PRE_LOAD_DAY_H (MCU_RTC_BASE + (0x0A << ADDR_SHIFT)) ++ ++#define RTC_IRQ_STATUS (MCU_RTC_BASE + (0x1A << ADDR_SHIFT)) ++#define RTC_IRQ_GEN (1<<0) ++ ++#define RTC_HOUR_VALUE (MCU_RTC_BASE + (0x1D << ADDR_SHIFT)) ++#define RTC_MIN_VALUE (MCU_RTC_BASE + (0x1C << ADDR_SHIFT)) ++#define RTC_SEC_VALUE (MCU_RTC_BASE + (0x1B << ADDR_SHIFT)) ++ ++#define RTC_DAY_L_VALUE (MCU_RTC_BASE + (0x1E << ADDR_SHIFT)) ++#define RTC_DAY_H_VALUE (MCU_RTC_BASE + (0x1F << ADDR_SHIFT)) ++ ++static unsigned short gk_rtc_get_day(void); ++ ++static void gk_rtc_set_clock(void) ++{ ++#ifdef CONFIG_CLOCK_32K ++ // 32.768KHz clock ++ gk_mcu_writel( SYS_REG_CFG17, CFG17_RTC_CLK_SEL_32K); ++ gk_mcu_writel( RTC_P_SCALER_DIV3, 0x00); ++ gk_mcu_writel( RTC_P_SCALER_DIV2, 0x00); ++ gk_mcu_writel( RTC_P_SCALER_DIV1, 0x7f); ++ gk_mcu_writel( RTC_P_SCALER_DIV0, 0xff); ++#endif ++ ++#ifdef CONFIG_CLOCK_24M ++ gk_mcu_writel( SYS_REG_CFG17, CFG17_RTC_CLK_SEL_24M); ++ gk_mcu_writel( RTC_P_SCALER_DIV3, 0x01); ++ gk_mcu_writel( RTC_P_SCALER_DIV2, 0x6e); ++ gk_mcu_writel( RTC_P_SCALER_DIV1, 0x35); ++ gk_mcu_writel( RTC_P_SCALER_DIV0, 0xff); ++#endif ++} ++ ++static void gk_rtc_stop(void) ++{ ++ /* clear out the hardware. */ ++ gk_mcu_writel( RTC_SYS_CONFIG, 9); ++ ++} ++ ++static void gk_rtc_reset(void) ++{ ++ unsigned char syscfg17; ++ ++ // config ++ gk_mcu_writel( RTC_SYS_CONFIG, 0x0); ++ gk_mcu_writel( RTC_SYS_CONFIG, (RTC_IRQ_ENABLE | RTC_ENABLE)); ++ ++ //reset rtc ++ syscfg17 = gk_mcu_readl( SYS_REG_CFG17); ++ syscfg17 |= CFG17_RTC_SOFT_RESET; ++ gk_mcu_writel( SYS_REG_CFG17, syscfg17); ++} ++ ++static void gk_rtc_start(void) ++{ ++ unsigned char syscfg17; ++ ++ gk_rtc_set_clock(); ++ printk("rtc start...\n"); ++ //if(gk_rtc_get_day() != 0) return; ++ ++ // config ++ gk_mcu_writel( RTC_SYS_CONFIG, 0x0); ++ gk_mcu_writel( RTC_SYS_CONFIG, (RTC_ENABLE)); ++ ++ syscfg17 = gk_mcu_readl( SYS_REG_CFG17); ++ syscfg17 |= CFG17_RTC_SOFT_RESET; ++ gk_mcu_writel( SYS_REG_CFG17, syscfg17); ++} ++ ++static unsigned short gk_rtc_get_day(void) ++{ ++ unsigned char dayh; ++ unsigned char dayl; ++ ++ dayh = gk_mcu_readl(RTC_DAY_H_VALUE); ++ dayl = gk_mcu_readl(RTC_DAY_L_VALUE); ++ ++ //printk("read day = %d - %d \n", dayh, dayl); ++ ++ return (((unsigned short)dayh << 8)|(unsigned short)dayl); ++} ++ ++static unsigned long gk_rtc_get_time(void) ++{ ++ int h,m,s; ++ ++ h = gk_mcu_readl(RTC_HOUR_VALUE); ++ m = gk_mcu_readl(RTC_MIN_VALUE ); ++ s = gk_mcu_readl(RTC_SEC_VALUE ); ++ ++ //printk("read time: h=%d m=%d s=%d \n", h, m, s); ++ ++ return (unsigned long)((h*3600) + m*60 + s); ++} ++ ++static void gk_rtc_set_day(unsigned short day) ++{ ++ unsigned char dayh; ++ unsigned char dayl; ++ ++ dayh = ((day >> 8) & 0xff); ++ dayl = ((day >> 0) & 0xff); ++ ++ //printk("set dayh=%d dayl=%d \n", dayh, dayl); ++ ++ gk_mcu_writel(RTC_PRE_LOAD_DAY_H, dayh); ++ gk_mcu_writel(RTC_PRE_LOAD_DAY_L, dayl); ++} ++ ++static void gk_rtc_write_time(unsigned char hour, unsigned char min, unsigned char sec) ++{ ++ //printk("set time: h=%d m=%d s=%d \n", hour, min, sec); ++ gk_mcu_writel(RTC_PRE_LOAD_HOUR, hour); ++ gk_mcu_writel(RTC_PRE_LOAD_MIN, min); ++ gk_mcu_writel(RTC_PRE_LOAD_SEC, sec); ++} ++ ++static int gk_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ unsigned long t; ++ unsigned short day; ++ unsigned long sec; ++#ifdef CONFIG_PMU_ALWAYS_RUNNING ++ // get pmu controller ++ gk_gpio_config(GPIO_12, GPIO_TYPE_OUTPUT_1); ++ msleep(1); ++ gk_gpio_config(GPIO_12, GPIO_TYPE_OUTPUT_0); ++ msleep(1); ++#endif ++ day = gk_rtc_get_day(); ++ sec = gk_rtc_get_time(); ++ ++ t = day * 3600 * 24 + sec; ++ printk("os read tm: t=%ld \n", t); ++ rtc_time_to_tm(t, tm); ++#ifdef CONFIG_PMU_ALWAYS_RUNNING ++ // release pmu controller & reset pmu ++ gk_mcu_writel(GK_VA_PMU + 0xA05C, PMU_ALWAYS_RUNNING); ++ gk_mcu_writel(GK_VA_PMU + 0xA02C, 0xB2); // 1011 0010 ++ gk_mcu_writel(GK_VA_PMU + 0xA02C, 0x63); // 0110 0011 ++#endif ++ return rtc_valid_tm(tm); ++} ++ ++static int gk_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ unsigned long t; ++ unsigned short day; ++ unsigned long left; ++ unsigned char h,m,s; ++ ++#ifdef CONFIG_PMU_ALWAYS_RUNNING ++ // get pmu controller ++ gk_gpio_config(GPIO_12, GPIO_TYPE_OUTPUT_1); ++ msleep(1); ++ gk_gpio_config(GPIO_12, GPIO_TYPE_OUTPUT_0); ++ msleep(1); ++#endif ++ rtc_tm_to_time(tm, &t); ++ ++ day = t / (3600*24); ++ left = t % (3600*24); ++ ++ h = left / 3600; ++ left = left % 3600; ++ ++ m = left /60; ++ s = left % 60; ++ ++ printk("os set time: day=%d h=%d m=%d s=%d t=%ld\n", day, h, m, s, t); ++ ++ gk_rtc_stop(); ++ gk_rtc_set_day(day); ++ gk_rtc_write_time(h, m, s); ++ // Steven Yu: use start replace reset. ++ //gk_rtc_reset(); ++ gk_rtc_start(); ++ ++#ifdef CONFIG_PMU_ALWAYS_RUNNING ++ // release pmu controller & reset pmu ++ gk_mcu_writel(GK_VA_PMU + 0xA05C, PMU_ALWAYS_RUNNING); ++ gk_mcu_writel(GK_VA_PMU + 0xA02C, 0xB2); // 1011 0010 ++ gk_mcu_writel(GK_VA_PMU + 0xA02C, 0x63); // 0110 0011 ++#endif ++ return 0; ++} ++ ++static struct rtc_class_ops gk_rtc_ops = ++{ ++ .read_time = gk_rtc_read_time, ++ .set_time = gk_rtc_set_time, ++}; ++ ++ ++ ++static int __devinit gk_rtc_probe(struct platform_device *pdev) ++{ ++ struct rtc_device *rtcdev; ++ ++ int ret; ++ ++ ++ printk("rtc base: 0x%x \n", MCU_RTC_BASE); ++ ++ //gk_rtc_stop(); ++ ++ // Steven Yu: do not reset rtc, otherwise the time would be reset or stop. ++ // start rtc in gk_rtc_set_time ++ //gk_rtc_start(); ++ ++ rtcdev = rtc_device_register("gk-rtc", &pdev->dev, &gk_rtc_ops, THIS_MODULE); ++ if (IS_ERR(rtcdev)) ++ { ++ ret = PTR_ERR(rtcdev); ++ goto out_err; ++ } ++ ++ platform_set_drvdata(pdev, rtcdev); ++ ++ return 0; ++ ++out_err: ++ return ret; ++} ++ ++static int __devexit gk_rtc_remove(struct platform_device *pdev) ++{ ++ struct rtc_device *rtcdev = platform_get_drvdata(pdev); ++ ++ rtc_device_unregister(rtcdev); ++ platform_set_drvdata(pdev, NULL); ++ ++ return 0; ++} ++ ++MODULE_ALIAS("platform:gk_rtc"); ++static struct platform_driver gk_rtc_driver = ++{ ++ .remove = __devexit_p(gk_rtc_remove), ++ .driver = ++ { ++ .name = "gk-rtc", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init gk_rtc_init(void) ++{ ++ printk("gk rtc init...\n"); ++ return platform_driver_probe(&gk_rtc_driver, gk_rtc_probe); ++} ++module_init(gk_rtc_init); ++ ++static void __exit gk_rtc_exit(void) ++{ ++ platform_driver_unregister(&gk_rtc_driver); ++} ++module_exit(gk_rtc_exit); ++ ++MODULE_AUTHOR("louis "); ++MODULE_DESCRIPTION("driver for gk internal RTC"); ++MODULE_LICENSE("GPL"); ++ +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index 00c02403..995da67f 100644 +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -452,6 +452,12 @@ config SPI_TLE62X0 + # Add new SPI protocol masters in alphabetical order above this line + # + ++config SPI_GOKE ++ tristate "GOKE IPC SPI Controller" ++ depends on GK_SPI ++ help ++ This selects a driver for the GOKE SPI Controller. ++ + endif # SPI_MASTER + + # (slave support would go here) +diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile +index 9d75d219..ac2a9e64 100644 +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -10,6 +10,9 @@ obj-$(CONFIG_SPI_MASTER) += spi.o + obj-$(CONFIG_SPI_SPIDEV) += spidev.o + + # SPI master controller drivers (bus) ++ifdef CONFIG_SPI_GOKE ++obj-$(CONFIG_GK_SPI_V1_00) += spi-goke_v1_00.o ++endif + obj-$(CONFIG_SPI_ALTERA) += spi-altera.o + obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o + obj-$(CONFIG_SPI_ATH79) += spi-ath79.o +diff --git a/drivers/spi/spi-goke_v1_00.c b/drivers/spi/spi-goke_v1_00.c +new file mode 100644 +index 00000000..87ecd6bb +--- /dev/null ++++ b/drivers/spi/spi-goke_v1_00.c +@@ -0,0 +1,1479 @@ ++/* ++ * linux/drivers/spi/spi_goke_v1_00.c ++ * ++ * ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SPI_USE_IRQ 1 ++#define SPI_DUMP_DATA 0 ++/*============================Global Variables================================*/ ++extern void v6_dma_flush_range(unsigned long start, unsigned long end); ++extern void v6_flush_kern_cache_all(void); ++ ++struct gk_spi { ++ u32 regbase; ++ struct gk_spi_platform_info *pinfo; ++ ++ int irq; ++ struct tasklet_struct tasklet; ++ ++ spinlock_t lock; ++ struct list_head queue; ++ u32 idle; ++ u32 shutdown; ++ ++ struct spi_device *c_dev; ++ struct spi_message *c_msg; ++ struct spi_transfer *c_xfer; ++ ++ u8 rw_mode, bpw, chip_select; ++ u32 ridx, widx, len; ++}; ++ ++struct gk_spi_private { ++ struct spi_device *spi; ++ struct mutex mtx; ++ spinlock_t lock; ++}; ++ ++static struct { ++ int cs_num; ++ struct gk_spi_private *data; ++} gk_spi_private_devices[SPI_MASTER_INSTANCES]; ++ ++static void gk_spi_handle_message(struct gk_spi *); ++static void gk_spi_prepare_message(struct gk_spi *); ++static void gk_spi_prepare_transfer(struct gk_spi *); ++static void gk_spi_finish_transfer(struct gk_spi *); ++static void gk_spi_finish_message(struct gk_spi *); ++static void gk_spi_start_transfer(struct gk_spi *); ++/*============================SPI Bus Driver==================================*/ ++static int gk_spi_setup(struct spi_device *spi) ++{ ++ return 0; ++} ++ ++static void gk_spi_cleanup(struct spi_device *spi) ++{ ++ return; ++} ++ ++static inline void gk_spi_chipselect(struct gk_spi *priv, int is_active) ++{ ++#if SPI_USE_IRQ ++ gk_spi_writel(priv->regbase + SPI_SER_OFFSET, is_active); ++#endif ++#if 1 ++ if(priv->c_dev) ++ { ++ gk_gpio_set_out(priv->pinfo->cs_pins[0], ++ (priv->c_dev->mode & SPI_CS_HIGH) ? GPIO_HIGH : GPIO_LOW); ++ } ++#endif ++} ++ ++static int gk_spi_stop(struct gk_spi *priv) ++{ ++ gk_spi_readl(priv->regbase + SPI_ICR_OFFSET); ++ gk_spi_readl(priv->regbase + SPI_ISR_OFFSET); ++ gk_spi_chipselect(priv, 0); ++ gk_spi_writel(priv->regbase + SPI_SSIENR_OFFSET, 0); ++ ++ return 0; ++} ++ ++static void gk_spi_start_transfer(struct gk_spi *priv) ++{ ++ void *wbuf,*rbuf; ++ u32 widx, ridx, len; ++ u32 xfer_len; ++ u8 cs_id; ++ u16 i, tmp; ++ ++ wbuf = (void *)priv->c_xfer->tx_buf; ++ rbuf = (void *)priv->c_xfer->rx_buf; ++ len = priv->len; ++ cs_id = priv->c_dev->chip_select; ++ widx = priv->widx; ++ ridx = priv->ridx; ++ //printk("=====[%s %d] %08x %d\n",__func__, __LINE__, priv->regbase, priv->pinfo->cs_pins[0]); ++ ++ /* Feed data into FIFO */ ++ switch (priv->rw_mode) ++ { ++ case SPI_WRITE_ONLY: ++ xfer_len = len - widx; ++#if SPI_USE_IRQ ++ if (xfer_len > priv->pinfo->fifo_entries) ++ xfer_len = priv->pinfo->fifo_entries; ++ gk_spi_chipselect(priv, 1 << cs_id); ++ gk_spi_writel(priv->regbase + SPI_RXFTLR_OFFSET, xfer_len); ++ gk_spi_writel(priv->regbase + SPI_TXFTLR_OFFSET, xfer_len); ++ if (priv->bpw <= 8) ++ { ++ for(i = 0; i < xfer_len; i++) ++ { ++ tmp = ((u8 *)wbuf)[widx++]; ++ gk_spi_writeb(priv->regbase + SPI_DR_OFFSET, tmp); ++ } ++#if SPI_DUMP_DATA ++ printk("=====[%s %d] W-%d\n",__func__, __LINE__, xfer_len); ++ for(i = 0; i < xfer_len; i++) ++ { ++ printk("%02x ", ((u8*)wbuf)[i]); ++ } ++ printk("\n"); ++#endif ++ } ++ else ++ { ++ for(i = 0; i < xfer_len; i++) ++ { ++ tmp = ((u16 *)wbuf)[widx++]; ++ gk_spi_writew(priv->regbase + SPI_DR_OFFSET, tmp); ++ } ++ } ++#else ++ gk_spi_chipselect(priv, 1 << cs_id); ++ /* Fill the TX FIFO up with the data to be sent */ ++ if (xfer_len < priv->pinfo->fifo_entries) ++ { ++ len = xfer_len; ++ } ++ else ++ { ++ len = priv->pinfo->fifo_entries; ++ } ++ if (priv->bpw <= 8) ++ { ++#if SPI_DUMP_DATA ++ printk("=====[%s %d] W-%d\n",__func__, __LINE__, xfer_len); ++ for(i = 0; i < xfer_len; i++) ++ { ++ printk("%02x ", ((u8*)wbuf)[i]); ++ } ++ printk("\n"); ++#endif ++ for(i = 0; i < len; i++) ++ { ++ tmp = ((u8 *)wbuf)[widx++]; ++ gk_spi_writeb(priv->regbase + SPI_DR_OFFSET, tmp); ++ } ++ while (len < xfer_len) ++ { ++ // read data first ++ tmp = gk_spi_readb(priv->regbase + SPI_RXFLR_OFFSET); ++ if (tmp) ++ { ++ tmp = gk_spi_readb(priv->regbase + SPI_DR_OFFSET); ++ ridx++; ++ } ++ // FIFO not full ++ tmp = gk_spi_readb(priv->regbase + SPI_TXFLR_OFFSET); ++ if (tmp < (priv->pinfo->fifo_entries/2)) ++ { ++ tmp = ((u8 *)wbuf)[widx++]; ++ gk_spi_writeb(priv->regbase + SPI_DR_OFFSET, tmp); ++ len++; ++ } ++ }; ++ // remain data ++ len = ridx - priv->ridx; ++ while (len < xfer_len) ++ { ++ // read data ++ tmp = gk_spi_readb(priv->regbase + SPI_RXFLR_OFFSET); ++ if (tmp) ++ { ++ tmp = gk_spi_readb(priv->regbase + SPI_DR_OFFSET); ++ ridx++; ++ len++; ++ } ++ }; ++ } ++ else ++ { ++ for(i = 0; i < len; i++) ++ { ++ tmp = ((u16 *)wbuf)[widx++]; ++ gk_spi_writew(priv->regbase + SPI_DR_OFFSET, tmp); ++ } ++ while (len < xfer_len) ++ { ++ // read data first ++ tmp = gk_spi_readb(priv->regbase + SPI_RXFLR_OFFSET); ++ if (tmp) ++ { ++ tmp = gk_spi_readw(priv->regbase + SPI_DR_OFFSET); ++ ridx++; ++ } ++ // FIFO not full ++ tmp = gk_spi_readb(priv->regbase + SPI_TXFLR_OFFSET); ++ if (tmp < (priv->pinfo->fifo_entries/2)) ++ { ++ tmp = ((u16 *)wbuf)[widx++]; ++ gk_spi_writew(priv->regbase + SPI_DR_OFFSET, tmp); ++ len++; ++ } ++ }; ++ // remain data ++ len = ridx - priv->ridx; ++ while (len < xfer_len) ++ { ++ // read data ++ tmp = gk_spi_readb(priv->regbase + SPI_RXFLR_OFFSET); ++ if (tmp) ++ { ++ tmp = gk_spi_readw(priv->regbase + SPI_DR_OFFSET); ++ ridx++; ++ len++; ++ } ++ }; ++ } ++ gk_spi_chipselect(priv, 0); ++#endif ++ break; ++ ++ case SPI_WRITE_READ: ++ xfer_len = len - widx; ++#if SPI_USE_IRQ ++ if (xfer_len > priv->pinfo->fifo_entries) ++ xfer_len = priv->pinfo->fifo_entries; ++ ++ gk_spi_chipselect(priv, 1 << cs_id); ++ gk_spi_writel(priv->regbase + SPI_RXFTLR_OFFSET, xfer_len); ++ gk_spi_writel(priv->regbase + SPI_TXFTLR_OFFSET, xfer_len); ++ if (priv->bpw <= 8) ++ { ++ for(i = 0; i < xfer_len; i++) ++ { ++ tmp = ((u8 *)wbuf)[widx++]; ++ gk_spi_writeb(priv->regbase + SPI_DR_OFFSET, tmp); ++ } ++#if SPI_DUMP_DATA ++ printk("=====[%s %d] W-%d:",__func__, __LINE__, xfer_len); ++ for(i = 0; i < xfer_len; i++) ++ { ++ printk("%02x ", ((u8*)wbuf)[i]); ++ } ++ printk("\n"); ++#endif ++ } ++ else ++ { ++ for(i = 0; i < xfer_len; i++) ++ { ++ tmp = ((u16 *)wbuf)[widx++]; ++ gk_spi_writew(priv->regbase + SPI_DR_OFFSET, tmp); ++ } ++ } ++#else ++ gk_spi_chipselect(priv, 1 << cs_id); ++ if (xfer_len < priv->pinfo->fifo_entries) ++ { ++ len = xfer_len; ++ } ++ else ++ { ++ len = priv->pinfo->fifo_entries; ++ } ++ if (priv->bpw <= 8) ++ { ++#if SPI_DUMP_DATA ++ printk("=====[%s %d] W-%d:",__func__, __LINE__, xfer_len); ++ for(i = 0; i < xfer_len; i++) ++ { ++ printk("%02x ", ((u8*)wbuf)[i]); ++ } ++ printk("\n"); ++#endif ++ /* Fill the TX FIFO up with the data to be sent */ ++ for(i = 0; i < len; i++) ++ { ++ tmp = ((u8 *)wbuf)[widx++]; ++ gk_spi_writeb(priv->regbase + SPI_DR_OFFSET, tmp); ++ } ++ while (len < xfer_len) ++ { ++ // read data first ++ tmp = gk_spi_readb(priv->regbase + SPI_RXFLR_OFFSET); ++ if (tmp) ++ { ++ tmp = gk_spi_readb(priv->regbase + SPI_DR_OFFSET); ++ ((u8 *)rbuf)[ridx++] = tmp & 0xff; ++ } ++ // FIFO not full ++ tmp = gk_spi_readb(priv->regbase + SPI_TXFLR_OFFSET); ++ if (tmp < (priv->pinfo->fifo_entries/2)) ++ { ++ tmp = ((u8 *)wbuf)[widx++]; ++ gk_spi_writeb(priv->regbase + SPI_DR_OFFSET, tmp); ++ len++; ++ } ++ }; ++ // remain data ++ len = ridx - priv->ridx; ++ while (len < xfer_len) ++ { ++ // read data ++ tmp = gk_spi_readb(priv->regbase + SPI_RXFLR_OFFSET); ++ if (tmp) ++ { ++ tmp = gk_spi_readb(priv->regbase + SPI_DR_OFFSET); ++ ((u8 *)rbuf)[ridx++] = tmp & 0xff; ++ len++; ++ } ++ }; ++ v6_dma_flush_range(rbuf, rbuf+xfer_len); ++#if SPI_DUMP_DATA ++ printk("=====[%s %d] R-%d:",__func__, __LINE__, xfer_len); ++ for(i = 0; i < xfer_len; i++) ++ { ++ printk("%02x ", ((u8*)rbuf)[i]); ++ } ++ printk("\n"); ++#endif ++ } ++ else ++ { ++ /* Fill the TX FIFO up with the data to be sent */ ++ for(i = 0; i < len; i++) ++ { ++ tmp = ((u16 *)wbuf)[widx++]; ++ gk_spi_writew(priv->regbase + SPI_DR_OFFSET, tmp); ++ } ++ while (len < xfer_len) ++ { ++ // read data first ++ tmp = gk_spi_readb(priv->regbase + SPI_RXFLR_OFFSET); ++ if (tmp) ++ { ++ tmp = gk_spi_readw(priv->regbase + SPI_DR_OFFSET); ++ ((u16 *)rbuf)[ridx++] = tmp; ++ } ++ // FIFO not full ++ tmp = gk_spi_readb(priv->regbase + SPI_TXFLR_OFFSET); ++ if (tmp < (priv->pinfo->fifo_entries/2)) ++ { ++ tmp = ((u16 *)wbuf)[widx++]; ++ gk_spi_writew(priv->regbase + SPI_DR_OFFSET, tmp); ++ len++; ++ } ++ }; ++ // remain data ++ len = ridx - priv->ridx; ++ while (len < xfer_len) ++ { ++ // read data ++ tmp = gk_spi_readb(priv->regbase + SPI_RXFLR_OFFSET); ++ if (tmp) ++ { ++ tmp = gk_spi_readb(priv->regbase + SPI_DR_OFFSET); ++ ((u16 *)rbuf)[ridx++] = tmp; ++ len++; ++ } ++ }; ++ v6_dma_flush_range(rbuf, rbuf+xfer_len); ++ } ++#endif ++ break; ++ ++ case SPI_READ_ONLY: ++ xfer_len = len - ridx; ++#if SPI_USE_IRQ ++ if (xfer_len > priv->pinfo->fifo_entries) ++ xfer_len = priv->pinfo->fifo_entries; ++ ++ gk_spi_chipselect(priv, 1 << cs_id); ++ gk_spi_writel(priv->regbase + SPI_RXFTLR_OFFSET, xfer_len); ++ gk_spi_writel(priv->regbase + SPI_TXFTLR_OFFSET, xfer_len); ++ for(i = 0; i < xfer_len; i++) ++ gk_spi_writew(priv->regbase + SPI_DR_OFFSET, SPI_DUMMY_DATA); ++#else ++ gk_spi_chipselect(priv, 1 << cs_id); ++ if (xfer_len < priv->pinfo->fifo_entries) ++ { ++ len = xfer_len; ++ } ++ else ++ { ++ len = priv->pinfo->fifo_entries; ++ } ++ ++ if (priv->bpw <= 8) ++ { ++ /* Fill the TX FIFO up with the data to be sent */ ++ for(i = 0; i < len; i++) ++ { ++ gk_spi_writeb(priv->regbase + SPI_DR_OFFSET, SPI_DUMMY_DATA); ++ } ++ while (len < xfer_len) ++ { ++ // read data first ++ tmp = gk_spi_readb(priv->regbase + SPI_RXFLR_OFFSET); ++ if (tmp) ++ { ++ tmp = gk_spi_readb(priv->regbase + SPI_DR_OFFSET); ++ ((u8 *)rbuf)[ridx++] = tmp & 0xff; ++ } ++ // FIFO not full ++ tmp = gk_spi_readb(priv->regbase + SPI_TXFLR_OFFSET); ++ if (tmp < (priv->pinfo->fifo_entries/2)) ++ { ++ tmp = ((u8 *)wbuf)[widx++]; ++ gk_spi_writeb(priv->regbase + SPI_DR_OFFSET, SPI_DUMMY_DATA); ++ len++; ++ } ++ }; ++ // remain data ++ len = ridx - priv->ridx; ++ while (len < xfer_len) ++ { ++ // read data ++ tmp = gk_spi_readb(priv->regbase + SPI_RXFLR_OFFSET); ++ if (tmp) ++ { ++ tmp = gk_spi_readb(priv->regbase + SPI_DR_OFFSET); ++ ((u8 *)rbuf)[ridx++] = tmp & 0xff; ++ len++; ++ } ++ }; ++ v6_dma_flush_range(rbuf, rbuf+xfer_len); ++ } ++ else ++ { ++ /* Fill the TX FIFO up with the data to be sent */ ++ for(i = 0; i < len; i++) ++ { ++ gk_spi_writew(priv->regbase + SPI_DR_OFFSET, SPI_DUMMY_DATA); ++ } ++ while (len < xfer_len) ++ { ++ // read data first ++ tmp = gk_spi_readb(priv->regbase + SPI_RXFLR_OFFSET); ++ if (tmp) ++ { ++ tmp = gk_spi_readw(priv->regbase + SPI_DR_OFFSET); ++ ((u16 *)rbuf)[ridx++] = tmp; ++ } ++ // FIFO not full ++ tmp = gk_spi_readb(priv->regbase + SPI_TXFLR_OFFSET); ++ if (tmp < (priv->pinfo->fifo_entries/2)) ++ { ++ gk_spi_writew(priv->regbase + SPI_DR_OFFSET, SPI_DUMMY_DATA); ++ len++; ++ } ++ }; ++ // remain data ++ len = ridx - priv->ridx; ++ while (len < xfer_len) ++ { ++ // read data ++ tmp = gk_spi_readb(priv->regbase + SPI_RXFLR_OFFSET); ++ if (tmp) ++ { ++ tmp = gk_spi_readb(priv->regbase + SPI_DR_OFFSET); ++ ((u16 *)rbuf)[ridx++] = tmp; ++ len++; ++ } ++ }; ++ v6_dma_flush_range(rbuf, rbuf+xfer_len); ++ } ++ gk_spi_chipselect(priv, 0); ++#endif ++ break; ++ ++ default: ++ break; ++ } ++ ++ priv->widx = widx; ++#if SPI_USE_IRQ ++ enable_irq(priv->irq); ++#else ++ priv->ridx = ridx; ++ gk_spi_finish_transfer(priv); ++#endif ++ return; ++} ++ ++static void gk_spi_tasklet(unsigned long data) ++{ ++ struct gk_spi *priv = (struct gk_spi *)data; ++ void *rbuf; ++ u32 widx, ridx, len; ++ u32 rxflr, xfer_len; ++ u32 status; ++ u16 i, tmp; ++ u32 finish_transfer; ++ ++ /* Wait until SPI idle */ ++ status = gk_spi_readl(priv->regbase + SPI_SR_OFFSET); ++ if (status & 0x1) ++ { ++ /* Transfer is still in progress */ ++ for (i = 0; i < MAX_QUERY_TIMES; i++) ++ { ++ status = gk_spi_readl(priv->regbase + SPI_SR_OFFSET); ++ if (!(status & 0x1)) ++ break; ++ } ++ if (status & 0x1) ++ { ++ tasklet_schedule(&priv->tasklet); ++ return; ++ } ++ } ++ ++ rbuf = (void *)priv->c_xfer->rx_buf; ++ len = priv->len; ++ widx = priv->widx; ++ ridx = priv->ridx; ++ ++ /* Fetch data from FIFO */ ++ switch (priv->rw_mode) ++ { ++ case SPI_WRITE_ONLY: ++ rxflr = gk_spi_readb(priv->regbase + SPI_RXFLR_OFFSET); ++ ++ if (priv->bpw <= 8) ++ { ++ for(i = 0; i < rxflr; i++) ++ { ++ tmp = gk_spi_readb(priv->regbase + SPI_DR_OFFSET); ++ } ++ } ++ else ++ { ++ for(i = 0; i < rxflr; i++) ++ { ++ tmp = gk_spi_readw(priv->regbase + SPI_DR_OFFSET); ++ } ++ } ++ ++ break; ++ case SPI_READ_ONLY: ++ case SPI_WRITE_READ: ++ xfer_len = len - ridx; ++ rxflr = gk_spi_readb(priv->regbase + SPI_RXFLR_OFFSET); ++ if (xfer_len > rxflr) ++ { ++ xfer_len = rxflr; ++ } ++ ++ if(priv->bpw <= 8) ++ { ++ for(i = 0; i < xfer_len; i++) ++ { ++ tmp = gk_spi_readb(priv->regbase + SPI_DR_OFFSET); ++ ((u8 *)rbuf)[ridx++] = tmp & 0xff; ++ } ++#if SPI_DUMP_DATA ++ printk("=====[%s %d] R-%d:",__func__, __LINE__, xfer_len); ++ for(i = 0; i < xfer_len; i++) ++ { ++ printk("%02x ", ((u8*)rbuf)[i]); ++ } ++ printk("\n"); ++#endif ++ } ++ else ++ { ++ for(i = 0; i < xfer_len; i++) ++ { ++ tmp = gk_spi_readw(priv->regbase + SPI_DR_OFFSET); ++ ((u16 *)rbuf)[ridx++] = tmp; ++ } ++ } ++ //v6_dma_flush_range(&rbuf[priv->ridx], &rbuf[ridx-1]); ++ priv->ridx = ridx; ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* Check whether the current transfer ends */ ++ finish_transfer = 0; ++ switch (priv->rw_mode) ++ { ++ case SPI_WRITE_ONLY: ++ if (widx == len) ++ { ++ finish_transfer = 1; ++ } ++ break; ++ ++ case SPI_READ_ONLY: ++ if (ridx == len) ++ { ++ finish_transfer = 1; ++ } ++ break; ++ ++ case SPI_WRITE_READ: ++ if (ridx == len && widx == len) ++ { ++ finish_transfer = 1; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* End transfer or continue filling FIFO */ ++ if (finish_transfer) ++ { ++ gk_spi_finish_transfer(priv); ++ enable_irq(priv->irq); ++ } ++ else ++ { ++ gk_spi_start_transfer(priv); ++ } ++} ++ ++static void gk_spi_prepare_transfer(struct gk_spi *priv) ++{ ++ struct spi_message *msg; ++ struct spi_transfer *xfer; ++ struct gk_spi_cs_config cs_config; ++ u32 ctrlr0; ++ void *wbuf, *rbuf; ++ msg = priv->c_msg; ++ ++ spin_lock(&priv->lock); ++ //if (priv->c_xfer == NULL) ++ { ++ xfer = list_entry(priv->c_msg->transfers.next, struct spi_transfer, transfer_list); ++ } ++ //else ++ { ++ // xfer = list_entry(priv->c_xfer->transfer_list.next, struct spi_transfer, transfer_list); ++ ++ } ++ priv->c_xfer = xfer; ++ //printk("=====[%s %d] %d\n",__func__, __LINE__, priv->c_xfer->speed_hz); ++ list_del(priv->c_msg->transfers.next); ++ spin_unlock(&priv->lock); ++ ++ wbuf = (void *)xfer->tx_buf; ++ rbuf = (void *)xfer->rx_buf; ++ ++ if (priv->bpw <= 8) ++ priv->len = xfer->len; ++ else ++ priv->len = xfer->len >> 1; ++ priv->widx = 0; ++ priv->ridx = 0; ++ if (wbuf && !rbuf) ++ priv->rw_mode = SPI_WRITE_ONLY; ++ if ( !wbuf && rbuf) ++ priv->rw_mode = SPI_READ_ONLY; ++ if (wbuf && rbuf) ++ priv->rw_mode = SPI_WRITE_READ; ++ ++ ctrlr0 = gk_spi_readl(priv->regbase + SPI_CTRLR0_OFFSET); ++ ctrlr0 &= 0xfffff4ff; ++ /* Always use write & read mode due to I1 changes */ ++ ctrlr0 |= (SPI_WRITE_READ << 8); ++ if (priv->c_dev->mode & SPI_LOOP) ++ ctrlr0 |= (0x1 << 11); ++ ++ gk_spi_writel(priv->regbase + SPI_CTRLR0_OFFSET, ctrlr0); ++ ++ if (!priv->chip_select) { ++ cs_config.bus_id = priv->c_dev->master->bus_num; ++ cs_config.cs_id = priv->c_dev->chip_select; ++ cs_config.cs_num = priv->c_dev->master->num_chipselect; ++ cs_config.cs_pins = priv->pinfo->cs_pins; ++ //priv->pinfo->cs_activate(&cs_config); ++ priv->chip_select = 1; ++ } ++ ++ disable_irq_nosync(priv->irq); ++ gk_spi_writel(priv->regbase + SPI_IMR_OFFSET, SPI_TXEIS_MASK); ++ gk_spi_writel(priv->regbase + SPI_SSIENR_OFFSET, 1); ++ gk_spi_chipselect(priv, 0); ++} ++ ++static void gk_spi_finish_transfer(struct gk_spi *priv) ++{ ++ if (priv->c_xfer->cs_change) { ++ struct gk_spi_cs_config cs_config; ++ ++ cs_config.bus_id = priv->c_dev->master->bus_num; ++ cs_config.cs_id = priv->c_msg->spi->chip_select; ++ cs_config.cs_num = priv->c_dev->master->num_chipselect; ++ cs_config.cs_pins = priv->pinfo->cs_pins; ++ ++ priv->pinfo->cs_deactivate(&cs_config); ++ priv->chip_select = 0; ++ } ++ ++ gk_spi_stop(priv); ++ ++ //if (list_is_last(&priv->c_xfer->transfer_list, &priv->c_msg->transfers)) { ++ if (list_empty(&priv->c_msg->transfers)) { ++ gk_spi_finish_message(priv); ++ } ++ else ++ { ++ gk_spi_prepare_transfer(priv); ++ gk_spi_start_transfer(priv); ++ } ++} ++ ++static void gk_spi_finish_message(struct gk_spi *priv) ++{ ++ struct spi_message *msg; ++ unsigned long flags; ++ u32 message_pending; ++ ++ if (priv->chip_select) ++ { ++ struct gk_spi_cs_config cs_config; ++ ++ cs_config.bus_id = priv->c_dev->master->bus_num; ++ cs_config.cs_id = priv->c_msg->spi->chip_select; ++ cs_config.cs_num = priv->c_dev->master->num_chipselect; ++ cs_config.cs_pins = priv->pinfo->cs_pins; ++ ++ priv->pinfo->cs_deactivate(&cs_config); ++ priv->chip_select = 0; ++ } ++ if(priv->c_xfer->rx_buf) ++ { ++ spin_lock(&priv->lock); ++ v6_flush_kern_cache_all(); ++ //v6_dma_flush_range(&priv->c_xfer->rx_buf[0], &priv->c_xfer->rx_buf[priv->c_xfer->len]); ++ spin_unlock(&priv->lock); ++ } ++ msg = priv->c_msg; ++ msg->actual_length = priv->c_xfer->len; ++ msg->status = 0; ++ ++ /* Next Message */ ++ spin_lock_irqsave(&priv->lock, flags); ++ list_del_init(&msg->queue); ++ if (!list_empty(&priv->queue)) ++ { ++ message_pending = 1; ++ } ++ else ++ { ++ message_pending = 0; ++ priv->idle = 1; ++ priv->c_msg = NULL; ++ priv->c_xfer = NULL; ++ } ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ if (message_pending) ++ { ++ gk_spi_handle_message(priv); ++ } ++ if(priv->c_xfer && priv->c_xfer->rx_buf && priv->c_xfer->len) { ++ v6_dma_flush_range((unsigned long)priv->c_xfer->rx_buf, ++ (u32)priv->c_xfer->rx_buf+priv->c_xfer->len); ++ } ++ msg->complete(msg->context); ++} ++ ++static void gk_spi_handle_message(struct gk_spi *priv) ++{ ++ gk_spi_prepare_message(priv); ++ gk_spi_prepare_transfer(priv); ++ gk_spi_start_transfer(priv); ++} ++ ++static void gk_spi_prepare_message(struct gk_spi *priv) ++{ ++ u32 ctrlr0, ssi_clk, sckdv; ++ struct spi_message *msg; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ msg = list_entry(priv->queue.next, struct spi_message, queue); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ctrlr0 = gk_spi_readl(priv->regbase + SPI_CTRLR0_OFFSET); ++ ++ if (msg->spi->bits_per_word < 4) ++ msg->spi->bits_per_word = 4; ++ if (msg->spi->bits_per_word > 16) ++ msg->spi->bits_per_word = 16; ++ priv->bpw = msg->spi->bits_per_word; ++ ++ ctrlr0 &= 0xfffffff0; ++ ctrlr0 |= (priv->bpw - 1); ++ ++ ctrlr0 &= (~((1 << 6) | (1 << 7))); ++ ctrlr0 |= ((msg->spi->mode & (SPI_CPHA | SPI_CPOL)) << 6); ++ if (msg->spi->mode & SPI_LOOP) { ++ ctrlr0 |= 0x00000800; ++ } ++ gk_spi_writel(priv->regbase + SPI_CTRLR0_OFFSET, ctrlr0); ++ ++ //printk("=====[%s %d] %d\n",__func__, __LINE__, priv->c_xfer->speed_hz); ++ ssi_clk = priv->pinfo->get_ssi_freq_hz(); ++ if(msg->spi->max_speed_hz == 0 || msg->spi->max_speed_hz > ssi_clk) ++ msg->spi->max_speed_hz = ssi_clk; ++ ++ sckdv = (u16)(((ssi_clk / msg->spi->max_speed_hz) + 0x01) & 0xfffe); ++ gk_spi_writel(priv->regbase + SPI_BAUDR_OFFSET, sckdv); ++ //gk_spi_writel(priv->regbase + SPI_BAUDR_OFFSET, 0x02); ++ ++ priv->chip_select = 0; ++ priv->c_dev = msg->spi; ++ priv->c_msg = msg; ++} ++ ++static int gk_spi_main_entry(struct spi_device *spi, struct spi_message *msg) ++{ ++ struct gk_spi *priv; ++ struct spi_transfer *xfer; ++ unsigned long flags; ++ u32 shut_down, bus_idle; ++ ++ priv = spi_master_get_devdata(spi->master); ++ spin_lock_irqsave(&priv->lock, flags); ++ shut_down = priv->shutdown; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ if (shut_down) { ++ return -ESHUTDOWN; ++ } ++ ++ /* Validation */ ++ if (list_empty(&msg->transfers) || !spi->max_speed_hz) { ++ return -EINVAL; ++ } ++ ++ list_for_each_entry(xfer, &msg->transfers, transfer_list) { ++ if (!xfer->tx_buf && !xfer->rx_buf) { ++ return -EINVAL; ++ } ++ ++ if (spi->bits_per_word > 8 && (xfer->len & 0x1)) { ++ return -EINVAL; ++ } ++ } ++ ++ /* Queue Message */ ++ msg->status = -EINPROGRESS; ++ msg->actual_length = 0; ++ spin_lock_irqsave(&priv->lock, flags); ++ list_add_tail(&msg->queue, &priv->queue); ++ if (priv->idle) { ++ priv->idle = 0; ++ bus_idle = 1; ++ } else { ++ bus_idle = 0; ++ } ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ /* Handle message right away if bus is idle */ ++ if (bus_idle) { ++ gk_spi_handle_message(priv); ++ } ++ ++ return 0; ++} ++ ++static int gk_spi_inithw(struct gk_spi *priv) ++{ ++ u16 sckdv, i; ++ u32 ctrlr0, ssi_freq; ++ ++ /* Set PLL */ ++ if (priv->pinfo->rct_set_ssi_pll) ++ priv->pinfo->rct_set_ssi_pll(); ++ ++ /* Disable SPI */ ++ gk_spi_stop(priv); ++ ++ /* Config Chip Select Pins */ ++ for (i = 0; i < priv->pinfo->cs_num; i++) { ++ if (priv->pinfo->cs_pins[i] < 0) { ++ continue; ++ } ++ ++ gk_gpio_set_out(priv->pinfo->cs_pins[i], GPIO_HIGH); ++ } ++ ++ /* Initial Register Settings */ ++ ctrlr0 = (( SPI_CFS << 12) | (SPI_WRITE_ONLY << 8) | (SPI_SCPOL << 7) | ++ (SPI_SCPH << 6) | (SPI_FRF << 4) | (SPI_DFS)); ++ gk_spi_writel(priv->regbase + SPI_CTRLR0_OFFSET, ctrlr0); ++ ++ ssi_freq = priv->pinfo->get_ssi_freq_hz(); ++ sckdv = (u16)(((ssi_freq / SPI_BAUD_RATE) + 0x01) & 0xfffe); ++ gk_spi_writel(priv->regbase + SPI_BAUDR_OFFSET, sckdv); ++ ++ gk_spi_writel(priv->regbase + SPI_TXFTLR_OFFSET, 0); ++ gk_spi_writel(priv->regbase + SPI_RXFTLR_OFFSET, 1); ++ gk_spi_writel(priv->regbase + SPI_SER_OFFSET, 1); ++ return 0; ++} ++ ++static irqreturn_t gk_spi_isr(int irq, void *dev_data) ++{ ++ struct gk_spi *priv = dev_data; ++ if (gk_spi_readl(priv->regbase + SPI_ISR_OFFSET)) { ++ disable_irq_nosync(priv->irq); ++ ++ gk_spi_tasklet((unsigned long)priv); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static int __devinit gk_spi_probe(struct platform_device *pdev) ++{ ++ struct gk_spi *priv; ++ struct gk_spi_private *ps; ++ struct spi_master *master; ++ struct spi_device *spidev; ++ struct resource *res; ++ struct gk_spi_platform_info *pinfo; ++ int i, irq, errorCode; ++ ++ gk_rct_writel(GK_VA_RCT + 0x0030, 0x01); ++ //gk_rct_writel(GK_VA_RCT + 0x00A0, 0x01); ++ /* Get IRQ NO. */ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ errorCode = -EINVAL; ++ goto gk_spi_probe_exit3; ++ } ++ ++ /* Get Platform Info */ ++ pinfo = (struct gk_spi_platform_info *)pdev->dev.platform_data; ++ if (!pinfo) { ++ errorCode = -EINVAL; ++ goto gk_spi_probe_exit3; ++ } ++ if (pinfo->cs_num && !pinfo->cs_pins) { ++ errorCode = -EINVAL; ++ goto gk_spi_probe_exit3; ++ } ++ if (!pinfo->cs_activate || !pinfo->cs_deactivate) { ++ errorCode = -EINVAL; ++ goto gk_spi_probe_exit3; ++ } ++ if (!pinfo->get_ssi_freq_hz) { ++ errorCode = -EINVAL; ++ goto gk_spi_probe_exit3; ++ } ++ ++ /* Get Base Address */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ errorCode = -EINVAL; ++ goto gk_spi_probe_exit3; ++ } ++ ++ /* Alocate Master */ ++ master = spi_alloc_master(&pdev->dev, sizeof *priv); ++ if (!master) { ++ errorCode = -ENOMEM; ++ goto gk_spi_probe_exit3; ++ } ++ ++ /* Initalize Device Data */ ++ master->bus_num = pdev->id; ++ master->num_chipselect = pinfo->cs_num; ++ master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_HIGH; ++ master->setup = gk_spi_setup; ++ master->transfer = gk_spi_main_entry; ++ master->cleanup = gk_spi_cleanup; ++ platform_set_drvdata(pdev, master); ++ priv = spi_master_get_devdata(master); ++ priv->regbase = (u32)res->start; ++ priv->irq = irq; ++ priv->pinfo = pinfo; ++ tasklet_init(&priv->tasklet, gk_spi_tasklet, (unsigned long)priv); ++ INIT_LIST_HEAD(&priv->queue); ++ priv->idle = 1; ++ priv->c_dev = NULL; ++ priv->c_msg = NULL; ++ priv->c_xfer = NULL; ++ priv->shutdown = 0; ++ spin_lock_init(&priv->lock); ++ priv->bpw = 16; ++ ++ /* Inittialize Hardware*/ ++ gk_spi_inithw(priv); ++ ++ /* Request IRQ */ ++ errorCode = request_irq(irq, gk_spi_isr, IRQF_TRIGGER_HIGH, ++ dev_name(&pdev->dev), priv); ++ if (errorCode) ++ goto gk_spi_probe_exit2; ++ else ++ dev_info(&pdev->dev, "gk SPI Controller %d created \n", pdev->id); ++ ++ /* Register Master */ ++ errorCode = spi_register_master(master); ++ if (errorCode) ++ goto gk_spi_probe_exit1; ++ ++ /* Allocate Private Devices */ ++ ps = (struct gk_spi_private *)kmalloc(master->num_chipselect * \ ++ sizeof(struct gk_spi_private), GFP_KERNEL); ++ if (!ps) { ++ errorCode = -ENOMEM; ++ goto gk_spi_probe_exit3; ++ } ++ spidev = (struct spi_device *)kmalloc(master->num_chipselect * \ ++ sizeof(struct spi_device), GFP_KERNEL); ++ if (!spidev) { ++ errorCode = -ENOMEM; ++ kfree(ps); ++ goto gk_spi_probe_exit3; ++ } ++ ++ for (i = 0; i < master->num_chipselect; i++) { ++ ps[i].spi = spidev + i; ++ ps[i].spi->master = master; ++ mutex_init(&ps[i].mtx); ++ spin_lock_init(&ps[i].lock); ++ } ++ gk_spi_private_devices[master->bus_num].cs_num = master->num_chipselect; ++ gk_spi_private_devices[master->bus_num].data = ps; ++ goto gk_spi_probe_exit3; ++ ++gk_spi_probe_exit1: ++ free_irq(irq, priv); ++ ++gk_spi_probe_exit2: ++ tasklet_kill(&priv->tasklet); ++ spi_master_put(master); ++ ++gk_spi_probe_exit3: ++ return errorCode; ++} ++ ++static int __devexit gk_spi_remove(struct platform_device *pdev) ++{ ++ ++ struct spi_master *master = platform_get_drvdata(pdev); ++ struct gk_spi *priv = spi_master_get_devdata(master); ++ struct spi_message *msg; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ priv->shutdown = 1; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ tasklet_kill(&priv->tasklet); ++ free_irq(priv->irq, priv); ++ gk_spi_stop(priv); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ list_for_each_entry(msg, &priv->queue, queue) ++ { ++ msg->status = -ESHUTDOWN; ++ msg->complete(msg->context); ++ } ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ spi_unregister_master(master); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int gk_spi_suspend_noirq(struct device *dev) ++{ ++ int errorCode = 0; ++ struct spi_master *master; ++ struct gk_spi *priv; ++ struct platform_device *pdev; ++ ++ pdev = to_platform_device(dev); ++ master = platform_get_drvdata(pdev); ++ priv = spi_master_get_devdata(master); ++ ++ if (priv) ++ { ++ //disable_irq(priv->irq); ++ gk_spi_stop(priv); ++ } ++ else ++ { ++ dev_err(&pdev->dev, "Cannot find valid pinfo\n"); ++ errorCode = -ENXIO; ++ } ++ ++ dev_dbg(&pdev->dev, "%s\n", __func__); ++ ++ return errorCode; ++} ++ ++static int gk_spi_resume_noirq(struct device *dev) ++{ ++ int errorCode = 0; ++ struct spi_master *master; ++ struct gk_spi *priv; ++ struct platform_device *pdev; ++ ++ pdev = to_platform_device(dev); ++ master = platform_get_drvdata(pdev); ++ priv = spi_master_get_devdata(master); ++ if (priv) ++ { ++ gk_spi_inithw(priv); ++ //enable_irq(priv->irq); ++ } ++ else ++ { ++ dev_err(&pdev->dev, "Cannot find valid pinfo\n"); ++ errorCode = -ENXIO; ++ } ++ ++ dev_dbg(&pdev->dev, "%s\n", __func__); ++ ++ return errorCode; ++} ++ ++static const struct dev_pm_ops gk_spi_dev_pm_ops = { ++ .suspend_noirq = gk_spi_suspend_noirq, ++ .resume_noirq = gk_spi_resume_noirq, ++}; ++#endif ++ ++static struct platform_driver gk_spi_driver = { ++ .probe = gk_spi_probe, ++ .remove = __devexit_p(gk_spi_remove), ++ .driver = { ++ .name = "spi", ++ .owner = THIS_MODULE, ++#ifdef CONFIG_PM ++ .pm = &gk_spi_dev_pm_ops, ++#endif ++ }, ++}; ++ ++static int __init gk_spi_init(void) ++{ ++ return platform_driver_register(&gk_spi_driver); ++} ++ ++static void __exit gk_spi_exit(void) ++{ ++ platform_driver_unregister(&gk_spi_driver); ++} ++ ++subsys_initcall(gk_spi_init); ++module_exit(gk_spi_exit); ++ ++MODULE_DESCRIPTION("GOKE SPI Driver"); ++MODULE_LICENSE("GPL"); ++ ++ ++/*=================Utilities for Non-GPL Use==================================*/ ++static void gk_spi_complete(void *arg) ++{ ++ complete(arg); ++} ++ ++int gk_spi_write(gk_spi_cfg_t *spi_cfg, gk_spi_write_t *spi_write) ++{ ++ u8 bus_id, cs_id, cs_num; ++ unsigned long flags; ++ int errorCode; ++ struct gk_spi_private *ps; ++ struct spi_device *spi; ++ struct spi_message msg; ++ struct spi_transfer xfer; ++ ++ DECLARE_COMPLETION_ONSTACK(done); ++ ++ /* Validate Input Args */ ++ if (!spi_cfg || !spi_write) ++ return -EINVAL; ++ ++ bus_id = spi_write->bus_id; ++ cs_id = spi_write->cs_id; ++ cs_num = gk_spi_private_devices[bus_id].cs_num; ++ ps = gk_spi_private_devices[bus_id].data; ++ ++ if (bus_id >= SPI_MASTER_INSTANCES || cs_id >= cs_num ++ || !spi_write->buffer || !spi_write->n_size) ++ return -EINVAL; ++ ++ /* Transfer */ ++ memset(&xfer, 0, sizeof(struct spi_transfer)); ++ xfer.tx_buf = spi_write->buffer; ++ xfer.len = spi_write->n_size; ++ xfer.cs_change = spi_cfg->cs_change; ++ ++ /* Message */ ++ memset(&msg, 0, sizeof(struct spi_message)); ++ INIT_LIST_HEAD(&msg.transfers); ++ list_add_tail(&xfer.transfer_list, &msg.transfers); ++ msg.complete = gk_spi_complete; ++ msg.context = &done; ++ spi = ps[cs_id].spi; ++ msg.spi = spi; ++ ++ mutex_lock(&ps[cs_id].mtx); ++ ++ /* Config */ ++ spi->chip_select = cs_id; ++ spi->mode = spi_cfg->spi_mode; ++ spi->mode &= ~SPI_LOOP; ++ spi->bits_per_word = spi_cfg->cfs_dfs; ++ spi->max_speed_hz = spi_cfg->baud_rate; ++ ++ /* Wait */ ++ spin_lock_irqsave(&ps[cs_id].lock, flags); ++ errorCode = spi->master->transfer(spi, &msg); ++ spin_unlock_irqrestore(&ps[cs_id].lock, flags); ++ if (!errorCode) ++ wait_for_completion(&done); ++ ++ mutex_unlock(&ps[cs_id].mtx); ++ ++ return errorCode; ++} ++EXPORT_SYMBOL(gk_spi_write); ++ ++int gk_spi_read(gk_spi_cfg_t *spi_cfg, gk_spi_read_t *spi_read) ++{ ++ u8 bus_id, cs_id, cs_num; ++ unsigned long flags; ++ int errorCode; ++ struct gk_spi_private *ps; ++ struct spi_device *spi; ++ struct spi_message msg; ++ struct spi_transfer xfer; ++ ++ DECLARE_COMPLETION_ONSTACK(done); ++ ++ /* Validate Input Args */ ++ if (!spi_cfg || !spi_read) ++ return -EINVAL; ++ ++ bus_id = spi_read->bus_id; ++ cs_id = spi_read->cs_id; ++ cs_num = gk_spi_private_devices[bus_id].cs_num; ++ ps = gk_spi_private_devices[bus_id].data; ++ if (bus_id >= SPI_MASTER_INSTANCES || cs_id >= cs_num ++ || !spi_read->buffer || !spi_read->n_size) ++ return -EINVAL; ++ ++ /* Transfer */ ++ memset(&xfer, 0, sizeof(struct spi_transfer)); ++ xfer.rx_buf = spi_read->buffer; ++ xfer.len = spi_read->n_size; ++ xfer.cs_change = spi_cfg->cs_change; ++ ++ /* Message */ ++ memset(&msg, 0, sizeof(struct spi_message)); ++ INIT_LIST_HEAD(&msg.transfers); ++ list_add_tail(&xfer.transfer_list, &msg.transfers); ++ msg.complete = gk_spi_complete; ++ msg.context = &done; ++ spi = ps[cs_id].spi; ++ msg.spi = spi; ++ ++ mutex_lock(&ps[cs_id].mtx); ++ ++ /* Config */ ++ spi->chip_select = cs_id; ++ spi->mode = spi_cfg->spi_mode; ++ spi->mode &= ~SPI_LOOP; ++ spi->bits_per_word = spi_cfg->cfs_dfs; ++ spi->max_speed_hz = spi_cfg->baud_rate; ++ ++ /* Wait */ ++ spin_lock_irqsave(&ps[cs_id].lock, flags); ++ errorCode = spi->master->transfer(spi, &msg); ++ spin_unlock_irqrestore(&ps[cs_id].lock, flags); ++ if (!errorCode) ++ wait_for_completion(&done); ++ ++ mutex_unlock(&ps[cs_id].mtx); ++ ++ return errorCode; ++} ++EXPORT_SYMBOL(gk_spi_read); ++ ++int gk_spi_write_then_read(gk_spi_cfg_t *spi_cfg, ++ gk_spi_write_then_read_t *spi_write_then_read) ++{ ++ u8 bus_id, cs_id, cs_num, *buf; ++ u16 size; ++ unsigned long flags; ++ int errorCode; ++ struct gk_spi_private *ps; ++ struct spi_device *spi; ++ struct spi_message msg; ++ struct spi_transfer xfer; ++ ++ DECLARE_COMPLETION_ONSTACK(done); ++ ++ /* Validate Input Args */ ++ if (!spi_cfg || !spi_write_then_read) ++ return -EINVAL; ++ ++ bus_id = spi_write_then_read->bus_id; ++ cs_id = spi_write_then_read->cs_id; ++ cs_num = gk_spi_private_devices[bus_id].cs_num; ++ ps = gk_spi_private_devices[bus_id].data; ++ ++ if (bus_id >= SPI_MASTER_INSTANCES || cs_id >= cs_num ++ || !spi_write_then_read->w_buffer || !spi_write_then_read->w_size ++ || !spi_write_then_read->r_buffer || !spi_write_then_read->r_size) ++ return -EINVAL; ++ ++ /* Prepare Buffer */ ++ size = spi_write_then_read->w_size + spi_write_then_read->r_size; ++ buf = (u8 *)kmalloc(size, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ memcpy(buf, spi_write_then_read->w_buffer, spi_write_then_read->w_size); ++ memset(buf + spi_write_then_read->w_size, SPI_DUMMY_DATA, ++ spi_write_then_read->r_size); ++ ++ /* Transfer */ ++ memset(&xfer, 0, sizeof(struct spi_transfer)); ++ xfer.tx_buf = buf; ++ xfer.rx_buf = buf; ++ xfer.len = size; ++ xfer.cs_change = spi_cfg->cs_change; ++ ++ /* Message */ ++ memset(&msg, 0, sizeof(struct spi_message)); ++ INIT_LIST_HEAD(&msg.transfers); ++ list_add_tail(&xfer.transfer_list, &msg.transfers); ++ msg.complete = gk_spi_complete; ++ msg.context = &done; ++ spi = ps[cs_id].spi; ++ msg.spi = spi; ++ ++ mutex_lock(&ps[cs_id].mtx); ++ ++ /* Config */ ++ spi->chip_select = cs_id; ++ spi->mode = spi_cfg->spi_mode; ++ spi->mode &= ~SPI_LOOP; ++ spi->bits_per_word = spi_cfg->cfs_dfs; ++ spi->max_speed_hz = spi_cfg->baud_rate; ++ ++ /* Wait */ ++ spin_lock_irqsave(&ps[cs_id].lock, flags); ++ errorCode = spi->master->transfer(spi, &msg); ++ spin_unlock_irqrestore(&ps[cs_id].lock, flags); ++ if (!errorCode) ++ wait_for_completion(&done); ++ ++ mutex_unlock(&ps[cs_id].mtx); ++ ++ /* Free Buffer */ ++ memcpy(spi_write_then_read->r_buffer, buf + spi_write_then_read->w_size, ++ spi_write_then_read->r_size); ++ kfree(buf); ++ ++ return errorCode; ++} ++EXPORT_SYMBOL(gk_spi_write_then_read); ++ ++int gk_spi_write_and_read(gk_spi_cfg_t *spi_cfg, ++ gk_spi_write_and_read_t *spi_write_and_read) ++{ ++ u8 bus_id, cs_id, cs_num; ++ unsigned long flags; ++ int errorCode; ++ struct gk_spi_private *ps; ++ struct spi_device *spi; ++ struct spi_message msg; ++ struct spi_transfer xfer; ++ ++ DECLARE_COMPLETION_ONSTACK(done); ++ ++ /* Validate Input Args */ ++ if (!spi_cfg || !spi_write_and_read) ++ return -EINVAL; ++ ++ bus_id = spi_write_and_read->bus_id; ++ cs_id = spi_write_and_read->cs_id; ++ cs_num = gk_spi_private_devices[bus_id].cs_num; ++ ps = gk_spi_private_devices[bus_id].data; ++ ++ if (bus_id >= SPI_MASTER_INSTANCES || cs_id >= cs_num ++ || !spi_write_and_read->w_buffer|| !spi_write_and_read->r_buffer ++ || !spi_write_and_read->n_size) ++ return -EINVAL; ++ ++ /* Transfer */ ++ memset(&xfer, 0, sizeof(struct spi_transfer)); ++ xfer.tx_buf = spi_write_and_read->w_buffer; ++ xfer.rx_buf = spi_write_and_read->r_buffer; ++ xfer.len = spi_write_and_read->n_size; ++ xfer.cs_change = spi_cfg->cs_change; ++ ++ /* Message */ ++ memset(&msg, 0, sizeof(struct spi_message)); ++ INIT_LIST_HEAD(&msg.transfers); ++ list_add_tail(&xfer.transfer_list, &msg.transfers); ++ msg.complete = gk_spi_complete; ++ msg.context = &done; ++ spi = ps[cs_id].spi; ++ msg.spi = spi; ++ ++ mutex_lock(&ps[cs_id].mtx); ++ ++ /* Config */ ++ spi->chip_select = cs_id; ++ spi->mode = spi_cfg->spi_mode; ++ spi->mode &= ~SPI_LOOP; ++ spi->bits_per_word = spi_cfg->cfs_dfs; ++ spi->max_speed_hz = spi_cfg->baud_rate; ++ ++ /* Wait */ ++ spin_lock_irqsave(&ps[cs_id].lock, flags); ++ errorCode = spi->master->transfer(spi, &msg); ++ spin_unlock_irqrestore(&ps[cs_id].lock, flags); ++ if (!errorCode) ++ wait_for_completion(&done); ++ ++ mutex_unlock(&ps[cs_id].mtx); ++ ++ return errorCode; ++} ++EXPORT_SYMBOL(gk_spi_write_and_read); ++ ++ +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 3b2eaad1..dac6dec5 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -9,6 +9,22 @@ source "drivers/tty/serial/8250/Kconfig" + + comment "Non-8250 serial port support" + ++config SERIAL_GOKE ++ tristate "Goke ipc Soc serial port support" ++ depends on GK_UART ++ select SERIAL_CORE ++ help ++ If you have a machine based on an Goke ipc Soc you ++ can enable its onboard serial ports by enabling this option. ++ ++config SERIAL_GOKE_CONSOLE ++ bool "Console on Goke ipc SoC serial port" ++ depends on SERIAL_GOKE=y ++ select SERIAL_CORE_CONSOLE ++ help ++ If you have enabled the serial port on the Goke ipc Soc ++ you can make it the console by answering Y to this option. ++ + config SERIAL_AMBA_PL010 + tristate "ARM AMBA PL010 serial port support" + depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE) +diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile +index 7257c5d8..f408ea26 100644 +--- a/drivers/tty/serial/Makefile ++++ b/drivers/tty/serial/Makefile +@@ -79,3 +79,6 @@ obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o + obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o + obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o + obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o ++ifdef CONFIG_SERIAL_GOKE ++obj-$(CONFIG_GK_UART_V1_00) += gk_sio_v1_00.o ++endif +diff --git a/drivers/tty/serial/gk_sio_v1_00.c b/drivers/tty/serial/gk_sio_v1_00.c +new file mode 100644 +index 00000000..d7023bfa +--- /dev/null ++++ b/drivers/tty/serial/gk_sio_v1_00.c +@@ -0,0 +1,837 @@ ++/* ++ * drivers/tty/serial/gk_sio_v1_00.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#if defined(CONFIG_SERIAL_GOKE_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) ++#define SUPPORT_SYSRQ ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* ==========================================================================*/ ++static void __serial_gk_enable_ms(struct uart_port *port) ++{ ++ gk_uart_setbitsl((unsigned int)port->membase + UART_IE_OFFSET, UART_IE_EDSSI); ++} ++ ++static void __serial_gk_disable_ms(struct uart_port *port) ++{ ++ gk_uart_clrbitsl((unsigned int)port->membase + UART_IE_OFFSET, UART_IE_EDSSI); ++} ++ ++static inline void wait_for_tx(struct uart_port *port) ++{ ++ u32 ls; ++ ++ ls = gk_uart_readl((unsigned int)port->membase + UART_LS_OFFSET); ++ while ((ls & UART_LS_TEMT) != UART_LS_TEMT) { ++ cpu_relax(); ++ ls = gk_uart_readl((unsigned int)port->membase + UART_LS_OFFSET); ++ } ++} ++ ++static inline void wait_for_rx(struct uart_port *port) ++{ ++ u32 ls; ++ ++ ls = gk_uart_readl((unsigned int)port->membase + UART_LS_OFFSET); ++ while ((ls & UART_LS_DR) != UART_LS_DR) { ++ cpu_relax(); ++ ls = gk_uart_readl((unsigned int)port->membase + UART_LS_OFFSET); ++ } ++} ++ ++/* ==========================================================================*/ ++static inline void serial_gk_receive_chars(struct uart_port *port, ++ u32 tmo) ++{ ++ struct tty_struct *tty = port->state->port.tty; ++ u32 ch; ++ u32 flag; ++ int max_count; ++ u32 ls; ++ ++ ls = gk_uart_readl((unsigned int)port->membase + UART_LS_OFFSET); ++ max_count = port->fifosize; ++ ++ do { ++ flag = TTY_NORMAL; ++ if (unlikely(ls & (UART_LS_BI | UART_LS_PE | ++ UART_LS_FE | UART_LS_OE))) { ++ if (ls & UART_LS_BI) { ++ ls &= ~(UART_LS_FE | UART_LS_PE); ++ port->icount.brk++; ++ ++ if (uart_handle_break(port)) ++ goto ignore_char; ++ } ++ if (ls & UART_LS_FE) ++ port->icount.frame++; ++ if (ls & UART_LS_PE) ++ port->icount.parity++; ++ if (ls & UART_LS_OE) ++ port->icount.overrun++; ++ ++ ls &= port->read_status_mask; ++ ++ if (ls & UART_LS_BI) ++ flag = TTY_BREAK; ++ else if (ls & UART_LS_FE) ++ flag = TTY_FRAME; ++ else if (ls & UART_LS_PE) ++ flag = TTY_PARITY; ++ else if (ls & UART_LS_OE) ++ flag = TTY_OVERRUN; ++ ++ if (ls & UART_LS_OE) { ++ printk(KERN_DEBUG "%s: OVERFLOW\n", __FUNCTION__); ++ } ++ } ++ ++ if (likely(ls & UART_LS_DR)) { ++ ch = gk_uart_readl((unsigned int)port->membase + UART_RB_OFFSET); ++ port->icount.rx++; ++ tmo = 0; ++ ++ if (uart_handle_sysrq_char(port, ch)) ++ goto ignore_char; ++ ++ uart_insert_char(port, ls, UART_LS_OE, ch, flag); ++ } else { ++ if (tmo) { ++ ch = gk_uart_readl((unsigned int)port->membase + UART_RB_OFFSET); ++ printk(KERN_DEBUG "False TMO get %d\n", ch); ++ } ++ } ++ ++ignore_char: ++ ls = gk_uart_readl((unsigned int)port->membase + UART_LS_OFFSET); ++ } while ((ls & UART_LS_DR) && (max_count-- > 0)); ++ ++ spin_unlock(&port->lock); ++ tty_flip_buffer_push(tty); ++ spin_lock(&port->lock); ++} ++ ++static void serial_gk_transmit_chars(struct uart_port *port) ++{ ++ struct circ_buf *xmit = &port->state->xmit; ++ int count; ++ struct gk_uart_port_info *port_info; ++ ++ port_info = (struct gk_uart_port_info *)(port->private_data); ++ ++ if (port->x_char) { ++ gk_uart_writeb((unsigned int)port->membase + UART_TH_OFFSET, port->x_char); ++ port->icount.tx++; ++ port->x_char = 0; ++ return; ++ } ++ ++ if (uart_tx_stopped(port) || uart_circ_empty(xmit)) { ++ port_info->stop_tx(port->membase); ++ return; ++ } ++ ++ count = port->fifosize; ++ while (count-- > 0) { ++ gk_uart_writeb((unsigned int)port->membase + UART_TH_OFFSET, ++ xmit->buf[xmit->tail]); ++ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); ++ port->icount.tx++; ++ if (uart_circ_empty(xmit)) ++ break; ++ } ++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) ++ uart_write_wakeup(port); ++ if (uart_circ_empty(xmit)) ++ port_info->stop_tx(port->membase); ++} ++ ++static inline void serial_gk_check_modem_status(struct uart_port *port) ++{ ++ struct gk_uart_port_info *port_info; ++ u32 ms; ++ ++ port_info = (struct gk_uart_port_info *)(port->private_data); ++ ++ if (port_info->get_ms) { ++ ms = port_info->get_ms(port->membase); ++ ++ if (ms & UART_MS_RI) ++ port->icount.rng++; ++ if (ms & UART_MS_DSR) ++ port->icount.dsr++; ++ if (ms & UART_MS_DCTS) ++ uart_handle_cts_change(port, (ms & UART_MS_CTS)); ++ if (ms & UART_MS_DDCD) ++ uart_handle_dcd_change(port, (ms & UART_MS_DCD)); ++ ++ wake_up_interruptible(&port->state->port.delta_msr_wait); ++ } ++} ++ ++static irqreturn_t serial_gk_irq(int irq, void *dev_id) ++{ ++ struct uart_port *port = dev_id; ++ int rval = IRQ_HANDLED; ++ u32 ii; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&port->lock, flags); ++ ++ ii = gk_uart_readl((unsigned int)port->membase + UART_II_OFFSET); ++ switch (ii & 0x0F) { ++ case UART_II_MODEM_STATUS_CHANGED: ++ serial_gk_check_modem_status(port); ++ break; ++ ++ case UART_II_THR_EMPTY: ++ serial_gk_transmit_chars(port); ++ break; ++ ++ case UART_II_RCV_STATUS: ++ case UART_II_RCV_DATA_AVAIL: ++ serial_gk_receive_chars(port, 0); ++ break; ++ case UART_II_CHAR_TIMEOUT: ++ serial_gk_receive_chars(port, 1); ++ break; ++ ++ case UART_II_NO_INT_PENDING: ++ default: ++ printk(KERN_DEBUG "%s: 0x%x\n", __FUNCTION__, ii); ++ rval = IRQ_NONE; ++ break; ++ } ++ ++ spin_unlock_irqrestore(&port->lock, flags); ++ ++ return rval; ++} ++ ++/* ==========================================================================*/ ++static void serial_gk_enable_ms(struct uart_port *port) ++{ ++ __serial_gk_enable_ms(port); ++} ++ ++static void serial_gk_start_tx(struct uart_port *port) ++{ ++ gk_uart_setbitsl((unsigned int)port->membase + UART_IE_OFFSET, UART_IE_ETBEI); ++} ++ ++static void serial_gk_stop_tx(struct uart_port *port) ++{ ++ struct gk_uart_port_info *port_info; ++ ++ port_info = (struct gk_uart_port_info *)(port->private_data); ++ ++ port_info->stop_tx(port->membase); ++} ++ ++static void serial_gk_stop_rx(struct uart_port *port) ++{ ++ gk_uart_clrbitsl((unsigned int)port->membase + UART_IE_OFFSET, UART_IE_ERBFI); ++} ++ ++static unsigned int serial_gk_tx_empty(struct uart_port *port) ++{ ++ unsigned long flags; ++ unsigned int lsr; ++ ++ spin_lock_irqsave(&port->lock, flags); ++ lsr = gk_uart_readl((unsigned int)port->membase + UART_LS_OFFSET); ++ spin_unlock_irqrestore(&port->lock, flags); ++ ++ return ((lsr & (UART_LS_TEMT | UART_LS_THRE)) == ++ (UART_LS_TEMT | UART_LS_THRE)) ? TIOCSER_TEMT : 0; ++} ++ ++static unsigned int serial_gk_get_mctrl(struct uart_port *port) ++{ ++ unsigned int mctrl = 0; ++ struct gk_uart_port_info *port_info; ++ u32 ms; ++ ++ port_info = (struct gk_uart_port_info *)(port->private_data); ++ ++ if (port_info->get_ms) { ++ ms = port_info->get_ms(port->membase); ++ ++ if (ms & UART_MS_CTS) ++ mctrl |= TIOCM_CTS; ++ if (ms & UART_MS_DSR) ++ mctrl |= TIOCM_DSR; ++ if (ms & UART_MS_RI) ++ mctrl |= TIOCM_RI; ++ if (ms & UART_MS_DCD) ++ mctrl |= TIOCM_CD; ++ } ++ ++ return mctrl; ++} ++ ++static void serial_gk_set_mctrl(struct uart_port *port, ++ unsigned int mctrl) ++{ ++ struct gk_uart_port_info *port_info; ++ u32 mcr; ++ u32 mcr_new = 0; ++ ++ port_info = (struct gk_uart_port_info *)(port->private_data); ++ ++ if (port_info->get_ms) { ++ mcr = gk_uart_readl((unsigned int)port->membase + UART_MC_OFFSET); ++ ++ if (mctrl & TIOCM_DTR) ++ mcr_new |= UART_MC_DTR; ++ if (mctrl & TIOCM_RTS) ++ mcr_new |= UART_MC_RTS; ++ if (mctrl & TIOCM_OUT1) ++ mcr_new |= UART_MC_OUT1; ++ if (mctrl & TIOCM_OUT2) ++ mcr_new |= UART_MC_OUT2; ++ if (mctrl & TIOCM_LOOP) ++ mcr_new |= UART_MC_LB; ++ ++ mcr_new |= port_info->mcr; ++ if (mcr_new != mcr) { ++ if ((mcr & UART_MC_AFCE) == UART_MC_AFCE) { ++ mcr &= ~UART_MC_AFCE; ++ gk_uart_writel((unsigned int)port->membase + UART_MC_OFFSET, ++ mcr); ++ } ++ gk_uart_writel((unsigned int)port->membase + UART_MC_OFFSET, mcr_new); ++ } ++ } ++} ++ ++static void serial_gk_break_ctl(struct uart_port *port, int break_state) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&port->lock, flags); ++ if (break_state != 0) ++ gk_uart_setbitsl((unsigned int)(unsigned int)port->membase + UART_LC_OFFSET, UART_LC_BRK); ++ else ++ gk_uart_clrbitsl((unsigned int)(unsigned int)port->membase + UART_LC_OFFSET, UART_LC_BRK); ++ spin_unlock_irqrestore(&port->lock, flags); ++} ++ ++static int serial_gk_startup(struct uart_port *port) ++{ ++ int retval = 0; ++ struct gk_uart_port_info *port_info; ++ unsigned long flags; ++ ++ port_info = (struct gk_uart_port_info *)(port->private_data); ++ ++ spin_lock_irqsave(&port->lock, flags); ++ gk_uart_setbitsl((unsigned int)port->membase + UART_SRR_OFFSET, 0x00); ++ gk_uart_writel((unsigned int)port->membase + UART_IE_OFFSET, port_info->ier | ++ UART_IE_PTIME); ++ gk_uart_writel((unsigned int)port->membase + UART_FC_OFFSET, (port_info->fcr | ++ UART_FC_XMITR | UART_FC_RCVRR)); ++ gk_uart_writel((unsigned int)port->membase + UART_IE_OFFSET, port_info->ier); ++ spin_unlock_irqrestore(&port->lock, flags); ++ ++ //printk("%s[001] port->irq=%d\n", __FUNCTION__, port->irq); ++ retval = request_irq(port->irq, serial_gk_irq, ++ IRQF_TRIGGER_HIGH, dev_name(port->dev), port); ++ ++ //printk("%s[002] retval = %d\n", __FUNCTION__, retval); ++ ++ return retval; ++} ++ ++static void serial_gk_shutdown(struct uart_port *port) ++{ ++ unsigned long flags; ++ ++ free_irq(port->irq, port); ++ ++ spin_lock_irqsave(&port->lock, flags); ++ gk_uart_clrbitsl((unsigned int)port->membase + UART_LC_OFFSET, UART_LC_BRK); ++ gk_uart_setbitsl((unsigned int)port->membase + UART_SRR_OFFSET, 0x01); ++ spin_unlock_irqrestore(&port->lock, flags); ++} ++ ++static void serial_gk_set_termios(struct uart_port *port, ++ struct ktermios *termios, struct ktermios *old) ++{ ++ struct gk_uart_port_info *port_info; ++ unsigned int baud, quot; ++ u32 lc = 0x0; ++ ++ port_info = (struct gk_uart_port_info *)(port->private_data); ++ ++ port->uartclk = port_info->get_pll(); ++ switch (termios->c_cflag & CSIZE) { ++ case CS5: ++ lc |= UART_LC_CLS_5_BITS; ++ break; ++ case CS6: ++ lc |= UART_LC_CLS_6_BITS; ++ break; ++ case CS7: ++ lc |= UART_LC_CLS_7_BITS; ++ break; ++ case CS8: ++ default: ++ lc |= UART_LC_CLS_8_BITS; ++ break; ++ } ++ ++ if (termios->c_cflag & CSTOPB) ++ lc |= UART_LC_STOP_2BIT; ++ else ++ lc |= UART_LC_STOP_1BIT; ++ ++ if (termios->c_cflag & PARENB) { ++ if (termios->c_cflag & PARODD) ++ lc |= (UART_LC_PEN | UART_LC_ODD_PARITY); ++ else ++ lc |= (UART_LC_PEN | UART_LC_EVEN_PARITY); ++ } ++ ++ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); ++ quot = uart_get_divisor(port, baud); ++ ++ disable_irq(port->irq); ++ uart_update_timeout(port, termios->c_cflag, baud); ++ ++ port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; ++ if (termios->c_iflag & INPCK) ++ port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; ++ if (termios->c_iflag & (BRKINT | PARMRK)) ++ port->read_status_mask |= UART_LSR_BI; ++ ++ port->ignore_status_mask = 0; ++ if (termios->c_iflag & IGNPAR) ++ port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; ++ if (termios->c_iflag & IGNBRK) { ++ port->ignore_status_mask |= UART_LSR_BI; ++ if (termios->c_iflag & IGNPAR) ++ port->ignore_status_mask |= UART_LSR_OE; ++ } ++ if ((termios->c_cflag & CREAD) == 0) ++ port->ignore_status_mask |= UART_LSR_DR; ++ ++ if ((termios->c_cflag & CRTSCTS) == 0) ++ port_info->mcr &= ~UART_MC_AFCE; ++ else ++ port_info->mcr |= UART_MC_AFCE; ++ ++ gk_uart_writel((unsigned int)port->membase + UART_LC_OFFSET, UART_LC_DLAB); ++ ++#if 1 ++{ ++ u32 clk = GK_UART_FREQ; ++ u16 dl; ++ ++ dl = clk * 10 / baud / 16; ++ if (dl % 10 >= 5) ++ dl = (dl / 10) + 1; ++ else ++ dl = (dl / 10); ++ ++ gk_uart_writel((unsigned int)port->membase + UART_DLL_OFFSET, dl & 0xff); ++ gk_uart_writel((unsigned int)port->membase + UART_DLH_OFFSET, (dl >> 8) & 0xff); ++} ++#else ++ gk_uart_writel((unsigned int)port->membase + UART_DLL_OFFSET, quot & 0xff); ++ gk_uart_writel((unsigned int)port->membase + UART_DLH_OFFSET, (quot >> 8) & 0xff); ++#endif ++ ++ gk_uart_writel((unsigned int)port->membase + UART_LC_OFFSET, lc); ++ if (UART_ENABLE_MS(port, termios->c_cflag)) ++ __serial_gk_enable_ms(port); ++ else ++ __serial_gk_disable_ms(port); ++ serial_gk_set_mctrl(port, port->mctrl); ++ ++ enable_irq(port->irq); ++} ++ ++static void serial_gk_pm(struct uart_port *port, ++ unsigned int state, unsigned int oldstate) ++{ ++} ++ ++static void serial_gk_release_port(struct uart_port *port) ++{ ++} ++ ++static int serial_gk_request_port(struct uart_port *port) ++{ ++ return 0; ++} ++ ++static void serial_gk_config_port(struct uart_port *port, int flags) ++{ ++} ++ ++static int serial_gk_verify_port(struct uart_port *port, ++ struct serial_struct *ser) ++{ ++ int retval = 0; ++ ++ if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00) ++ retval = -EINVAL; ++ if (port->irq != ser->irq) ++ retval = -EINVAL; ++ if (ser->io_type != SERIAL_IO_MEM) ++ retval = -EINVAL; ++ ++ return retval; ++} ++ ++static const char *serial_gk_type(struct uart_port *port) ++{ ++ return "gkuart"; ++} ++ ++#ifdef CONFIG_CONSOLE_POLL ++static void serial_gk_poll_put_char(struct uart_port *port, ++ unsigned char chr) ++{ ++ struct gk_uart_port_info *port_info; ++ ++ port_info = (struct gk_uart_port_info *)(port->private_data); ++ if (!port->suspended) { ++ wait_for_tx(port); ++ gk_uart_writeb((unsigned int)port->membase + UART_TH_OFFSET, chr); ++ } ++} ++ ++static int serial_gk_poll_get_char(struct uart_port *port) ++{ ++ struct gk_uart_port_info *port_info; ++ ++ port_info = (struct gk_uart_port_info *)(port->private_data); ++ if (!port->suspended) { ++ wait_for_rx(port); ++ return gk_uart_readl((unsigned int)port->membase + UART_RB_OFFSET); ++ } ++ return 0; ++} ++#endif ++ ++struct uart_ops serial_gk_pops = { ++ .tx_empty = serial_gk_tx_empty, ++ .set_mctrl = serial_gk_set_mctrl, ++ .get_mctrl = serial_gk_get_mctrl, ++ .stop_tx = serial_gk_stop_tx, ++ .start_tx = serial_gk_start_tx, ++ .stop_rx = serial_gk_stop_rx, ++ .enable_ms = serial_gk_enable_ms, ++ .break_ctl = serial_gk_break_ctl, ++ .startup = serial_gk_startup, ++ .shutdown = serial_gk_shutdown, ++ .set_termios = serial_gk_set_termios, ++ .pm = serial_gk_pm, ++ .type = serial_gk_type, ++ .release_port = serial_gk_release_port, ++ .request_port = serial_gk_request_port, ++ .config_port = serial_gk_config_port, ++ .verify_port = serial_gk_verify_port, ++#ifdef CONFIG_CONSOLE_POLL ++ .poll_put_char = serial_gk_poll_put_char, ++ .poll_get_char = serial_gk_poll_get_char, ++#endif ++}; ++ ++/* ==========================================================================*/ ++#if defined(CONFIG_SERIAL_GOKE_CONSOLE) ++static struct uart_driver serial_gk_reg; ++ ++static void serial_gk_console_putchar(struct uart_port *port, int ch) ++{ ++ wait_for_tx(port); ++ gk_uart_writel((unsigned int)port->membase + UART_TH_OFFSET, ch); ++} ++ ++static void serial_gk_console_write(struct console *co, ++ const char *s, unsigned int count) ++{ ++ u32 ie; ++ struct uart_port *port; ++ unsigned long flags; ++ int locked = 1; ++ ++ port = (struct uart_port *)( ++ gk_uart_ports.port[co->index].port); ++ ++ if (!port->suspended) { ++ local_irq_save(flags); ++ if (port->sysrq) { ++ locked = 0; ++ } else if (oops_in_progress) { ++ locked = spin_trylock(&port->lock); ++ } else { ++ spin_lock(&port->lock); ++ locked = 1; ++ } ++ ++ ie = gk_uart_readl((unsigned int)port->membase + UART_IE_OFFSET); ++ gk_uart_writel((unsigned int)port->membase + UART_IE_OFFSET, ++ ie & ~UART_IE_ETBEI); ++ ++ uart_console_write(port, s, count, ++ serial_gk_console_putchar); ++ ++ wait_for_tx(port); ++ gk_uart_writel((unsigned int)port->membase + UART_IE_OFFSET, ie); ++ ++ if (locked) ++ spin_unlock(&port->lock); ++ local_irq_restore(flags); ++ } ++} ++ ++static int __init serial_gk_console_setup(struct console *co, ++ char *options) ++{ ++ struct uart_port *port; ++ int baud = 115200; ++ int bits = 8; ++ int parity = 'n'; ++ int flow = 'n'; ++ ++ if (co->index < 0 || co->index >= gk_uart_ports.total_port_num) ++ co->index = 0; ++ ++#ifdef KE_DEBUG ++ printk("[serial_gk_console_setup]index = %d\n", co->index); ++#endif ++ ++ port = (struct uart_port *)(gk_uart_ports.port[co->index].port); ++ ++ if(gk_uart_ports.port[co->index].set_pll != NULL) ++ { ++ gk_uart_ports.port[co->index].set_pll(); ++ } ++ ++ port->uartclk = gk_uart_ports.port[co->index].get_pll(); ++ port->ops = &serial_gk_pops; ++ port->private_data = &(gk_uart_ports.port[co->index]); ++ port->line = co->index; ++ ++ if (options) ++ uart_parse_options(options, &baud, &parity, &bits, &flow); ++ ++ return uart_set_options(port, co, baud, parity, bits, flow); ++} ++ ++static struct console serial_gk_console = { ++ .name = "ttySGK", ++ .write = serial_gk_console_write, ++ .device = uart_console_device, ++ .setup = serial_gk_console_setup, ++ .flags = CON_PRINTBUFFER, ++ .index = -1, ++ .data = &serial_gk_reg, ++}; ++ ++static int __init serial_gk_console_init(void) ++{ ++ if (serial_gk_reg.nr == -1) ++ serial_gk_reg.nr = gk_uart_ports.total_port_num; ++ ++#ifdef KE_DEBUG ++ printk("gk_console_init start!\n"); ++#endif ++ ++ register_console(&serial_gk_console); ++ ++#ifdef KE_DEBUG ++ printk("gk_console_init End!\n"); ++#endif ++ ++ return 0; ++} ++ ++console_initcall(serial_gk_console_init); ++ ++#define GK_CONSOLE &serial_gk_console ++#else ++#define GK_CONSOLE NULL ++#endif ++ ++/* ==========================================================================*/ ++static struct uart_driver serial_gk_reg = { ++ .owner = THIS_MODULE, ++ .driver_name = "uart", ++ .dev_name = "ttySGK", ++ .major = 204,//TTY_MAJOR, ++ .minor = 18,//64, ++ .nr = UART_INSTANCES, ++ .cons = GK_CONSOLE, ++}; ++ ++static int serial_gk_probe(struct platform_device *pdev) ++{ ++ int retval = 0; ++ struct gk_uart_platform_info *pinfo; ++ struct uart_port *port; ++ ++ printk(KERN_DEBUG "%s: entry\n", __FUNCTION__); ++ ++ pinfo = (struct gk_uart_platform_info *)pdev->dev.platform_data; ++ if (pinfo == NULL) { ++ dev_err(&pdev->dev, "Can't get UART platform data!\n"); ++ retval = -ENXIO; ++ goto serial_gk_probe_exit; ++ } ++ ++ if ((pdev->id < 0) || (pdev->id >= pinfo->total_port_num)) { ++ dev_err(&pdev->dev, "Wrong UART ID %d!\n", pdev->id); ++ retval = -ENXIO; ++ goto serial_gk_probe_exit; ++ } ++ ++ port = (struct uart_port *)(pinfo->port[pdev->id].port); ++ if(pinfo->port[pdev->id].set_pll != NULL) ++ { ++ pinfo->port[pdev->id].set_pll(); ++ } ++ port->uartclk = pinfo->port[pdev->id].get_pll(); ++ port->ops = &serial_gk_pops; ++ port->dev = &pdev->dev; ++ port->private_data = &(pinfo->port[pdev->id]); ++ port->line = pdev->id; ++ ++ retval = uart_add_one_port(&serial_gk_reg, port); ++ if (retval) { ++ dev_err(&pdev->dev, ++ "uart_add_one_port %d fail %d!\n", ++ pdev->id, retval); ++ goto serial_gk_probe_unregister_driver; ++ } else { ++ pinfo->registed_port_num++; ++ } ++ ++ printk(KERN_DEBUG "%s: succeed!\n", __FUNCTION__); ++ ++ goto serial_gk_probe_exit; ++ ++serial_gk_probe_unregister_driver: ++ if (pinfo->registed_port_num == 0) ++ uart_unregister_driver(&serial_gk_reg); ++ ++serial_gk_probe_exit: ++ return retval; ++} ++ ++static int serial_gk_remove(struct platform_device *pdev) ++{ ++ int retval = 0; ++ struct gk_uart_platform_info *pinfo; ++ struct uart_port *port; ++ ++ pinfo = (struct gk_uart_platform_info *)pdev->dev.platform_data; ++ ++ if (pinfo) { ++ port = (struct uart_port *)(pinfo->port[pdev->id].port); ++ retval = uart_remove_one_port(&serial_gk_reg, port); ++ if (retval) { ++ dev_err(&pdev->dev, ++ "uart_remove_one_port %d fail %d!\n", ++ pdev->id, retval); ++ } else { ++ pinfo->registed_port_num--; ++ } ++ ++ if (pinfo->registed_port_num == 0) ++ uart_unregister_driver(&serial_gk_reg); ++ ++ dev_notice(&pdev->dev, "Remove GK UART.\n"); ++ } ++ ++ return retval; ++} ++ ++static struct platform_driver serial_gk_driver = { ++ .probe = serial_gk_probe, ++ .remove = serial_gk_remove, ++ .driver = { ++ .name = "uart", ++ }, ++}; ++ ++int __init serial_gk_init(void) ++{ ++ int ret; ++ ++ printk(KERN_DEBUG "Serial: gk_uart driver\n"); ++ ++ ret = uart_register_driver(&serial_gk_reg); ++ if (ret == 0) ++ { ++ //printk("%s[001] ret=0x%x\n", __FUNCTION__, ret); ++ ret = platform_driver_register(&serial_gk_driver); ++ if (ret) ++ { ++ printk(KERN_ERR "Serial: gk_uart driver register f!\n"); ++ uart_unregister_driver(&serial_gk_reg); ++ } ++ } ++ ++ return ret; ++ ++} ++ ++void __exit serial_gk_exit(void) ++{ ++ platform_driver_unregister(&serial_gk_driver); ++} ++ ++module_init(serial_gk_init); ++module_exit(serial_gk_exit); ++ ++MODULE_DESCRIPTION("GOKE GK SoC UART driver"); ++MODULE_AUTHOR("Goke Microelectronics Inc."); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:gk-uart"); +diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c +index e411f186..25bc1d6e 100644 +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -123,13 +123,23 @@ static void acm_release_minor(struct acm *acm) + static int acm_ctrl_msg(struct acm *acm, int request, int value, + void *buf, int len) + { +- int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), ++ int retval; ++ ++ retval = usb_autopm_get_interface(acm->control); ++ if (retval) ++ return retval; ++ ++ retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), + request, USB_RT_ACM, value, + acm->control->altsetting[0].desc.bInterfaceNumber, + buf, len, 5000); ++ + dev_dbg(&acm->control->dev, + "%s - rq 0x%02x, val %#x, len %#x, result %d\n", + __func__, request, value, len, retval); ++ ++ usb_autopm_put_interface(acm->control); ++ + return retval < 0 ? retval : 0; + } + +@@ -234,12 +244,9 @@ static int acm_write_start(struct acm *acm, int wbn) + acm->susp_count); + usb_autopm_get_interface_async(acm->control); + if (acm->susp_count) { +- if (!acm->delayed_wb) +- acm->delayed_wb = wb; +- else +- usb_autopm_put_interface_async(acm->control); ++ usb_anchor_urb(wb->urb, &acm->delayed); + spin_unlock_irqrestore(&acm->write_lock, flags); +- return 0; /* A white lie */ ++ return 0; + } + usb_mark_last_busy(acm->dev); + +@@ -535,6 +542,7 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) + { + struct acm *acm = container_of(port, struct acm, port); + int retval = -ENODEV; ++ int i; + + dev_dbg(&acm->control->dev, "%s\n", __func__); + +@@ -583,6 +591,8 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) + return 0; + + error_submit_read_urbs: ++ for (i = 0; i < acm->rx_buflimit; i++) ++ usb_kill_urb(acm->read_urbs[i]); + acm->ctrlout = 0; + acm_set_control(acm, acm->ctrlout); + error_set_control: +@@ -610,21 +620,35 @@ static void acm_port_destruct(struct tty_port *port) + static void acm_port_shutdown(struct tty_port *port) + { + struct acm *acm = container_of(port, struct acm, port); ++ struct urb *urb; ++ struct acm_wb *wb; + int i; ++ int pm_err; + + dev_dbg(&acm->control->dev, "%s\n", __func__); + + mutex_lock(&acm->mutex); + if (!acm->disconnected) { +- usb_autopm_get_interface(acm->control); ++ pm_err = usb_autopm_get_interface(acm->control); + acm_set_control(acm, acm->ctrlout = 0); ++ ++ for (;;) { ++ urb = usb_get_from_anchor(&acm->delayed); ++ if (!urb) ++ break; ++ wb = urb->context; ++ wb->use = 0; ++ usb_autopm_put_interface_async(acm->control); ++ } ++ + usb_kill_urb(acm->ctrlurb); + for (i = 0; i < ACM_NW; i++) + usb_kill_urb(acm->wb[i].urb); + for (i = 0; i < acm->rx_buflimit; i++) + usb_kill_urb(acm->read_urbs[i]); + acm->control->needs_remote_wakeup = 0; +- usb_autopm_put_interface(acm->control); ++ if (!pm_err) ++ usb_autopm_put_interface(acm->control); + } + mutex_unlock(&acm->mutex); + } +@@ -886,11 +910,12 @@ static void acm_tty_set_termios(struct tty_struct *tty, + /* FIXME: Needs to clear unsupported bits in the termios */ + acm->clocal = ((termios->c_cflag & CLOCAL) != 0); + +- if (!newline.dwDTERate) { ++ if (C_BAUD(tty) == B0) { + newline.dwDTERate = acm->line.dwDTERate; + newctrl &= ~ACM_CTRL_DTR; +- } else ++ } else if (termios_old && (termios_old->c_cflag & CBAUD) == B0) { + newctrl |= ACM_CTRL_DTR; ++ } + + if (newctrl != acm->ctrlout) + acm_set_control(acm, acm->ctrlout = newctrl); +@@ -983,6 +1008,7 @@ static int acm_probe(struct usb_interface *intf, + unsigned long quirks; + int num_rx_buf; + int i; ++ unsigned int elength = 0; + int combined_interfaces = 0; + + /* normal quirks */ +@@ -1018,6 +1044,12 @@ static int acm_probe(struct usb_interface *intf, + } + + while (buflen > 0) { ++ elength = buffer[0]; ++ if (!elength) { ++ dev_err(&intf->dev, "skipping garbage byte\n"); ++ elength = 1; ++ goto next_desc; ++ } + if (buffer[1] != USB_DT_CS_INTERFACE) { + dev_err(&intf->dev, "skipping garbage\n"); + goto next_desc; +@@ -1025,6 +1057,8 @@ static int acm_probe(struct usb_interface *intf, + + switch (buffer[2]) { + case USB_CDC_UNION_TYPE: /* we've found it */ ++ if (elength < sizeof(struct usb_cdc_union_desc)) ++ goto next_desc; + if (union_header) { + dev_err(&intf->dev, "More than one " + "union descriptor, skipping ...\n"); +@@ -1033,31 +1067,38 @@ static int acm_probe(struct usb_interface *intf, + union_header = (struct usb_cdc_union_desc *)buffer; + break; + case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ ++ if (elength < sizeof(struct usb_cdc_country_functional_desc)) ++ goto next_desc; + cfd = (struct usb_cdc_country_functional_desc *)buffer; + break; + case USB_CDC_HEADER_TYPE: /* maybe check version */ + break; /* for now we ignore it */ + case USB_CDC_ACM_TYPE: ++ if (elength < 4) ++ goto next_desc; + ac_management_function = buffer[3]; + break; + case USB_CDC_CALL_MANAGEMENT_TYPE: ++ if (elength < 5) ++ goto next_desc; + call_management_function = buffer[3]; + call_interface_num = buffer[4]; + if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3) + dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n"); + break; + default: +- /* there are LOTS more CDC descriptors that ++ /* ++ * there are LOTS more CDC descriptors that + * could legitimately be found here. + */ + dev_dbg(&intf->dev, "Ignoring descriptor: " +- "type %02x, length %d\n", +- buffer[2], buffer[0]); ++ "type %02x, length %ud\n", ++ buffer[2], elength); + break; + } + next_desc: +- buflen -= buffer[0]; +- buffer += buffer[0]; ++ buflen -= elength; ++ buffer += elength; + } + + if (!union_header) { +@@ -1083,10 +1124,11 @@ next_desc: + } else { + control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); + data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); +- if (!control_interface || !data_interface) { +- dev_dbg(&intf->dev, "no interfaces\n"); +- return -ENODEV; +- } ++ } ++ ++ if (!control_interface || !data_interface) { ++ dev_dbg(&intf->dev, "no interfaces\n"); ++ return -ENODEV; + } + + if (data_interface_num != call_interface_num) +@@ -1211,6 +1253,7 @@ made_compressed_probe: + acm->bInterval = epread->bInterval; + tty_port_init(&acm->port); + acm->port.ops = &acm_port_ops; ++ init_usb_anchor(&acm->delayed); + + buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); + if (!buf) { +@@ -1403,6 +1446,7 @@ static void acm_disconnect(struct usb_interface *intf) + &dev_attr_wCountryCodes); + device_remove_file(&acm->control->dev, + &dev_attr_iCountryCodeRelDate); ++ kfree(acm->country_codes); + } + device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities); + usb_set_intfdata(acm->control, NULL); +@@ -1441,18 +1485,15 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) + struct acm *acm = usb_get_intfdata(intf); + int cnt; + ++ spin_lock_irq(&acm->read_lock); ++ spin_lock(&acm->write_lock); + if (PMSG_IS_AUTO(message)) { +- int b; +- +- spin_lock_irq(&acm->write_lock); +- b = acm->transmitting; +- spin_unlock_irq(&acm->write_lock); +- if (b) ++ if (acm->transmitting) { ++ spin_unlock(&acm->write_lock); ++ spin_unlock_irq(&acm->read_lock); + return -EBUSY; ++ } + } +- +- spin_lock_irq(&acm->read_lock); +- spin_lock(&acm->write_lock); + cnt = acm->susp_count++; + spin_unlock(&acm->write_lock); + spin_unlock_irq(&acm->read_lock); +@@ -1460,8 +1501,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) + if (cnt) + return 0; + +- if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) +- stop_data_traffic(acm); ++ stop_data_traffic(acm); + + return 0; + } +@@ -1469,29 +1509,24 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) + static int acm_resume(struct usb_interface *intf) + { + struct acm *acm = usb_get_intfdata(intf); +- struct acm_wb *wb; ++ struct urb *urb; + int rv = 0; +- int cnt; + + spin_lock_irq(&acm->read_lock); +- acm->susp_count -= 1; +- cnt = acm->susp_count; +- spin_unlock_irq(&acm->read_lock); ++ spin_lock(&acm->write_lock); + +- if (cnt) +- return 0; ++ if (--acm->susp_count) ++ goto out; + + if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { +- rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); +- +- spin_lock_irq(&acm->write_lock); +- if (acm->delayed_wb) { +- wb = acm->delayed_wb; +- acm->delayed_wb = NULL; +- spin_unlock_irq(&acm->write_lock); +- acm_start_wb(acm, wb); +- } else { +- spin_unlock_irq(&acm->write_lock); ++ rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC); ++ ++ for (;;) { ++ urb = usb_get_from_anchor(&acm->delayed); ++ if (!urb) ++ break; ++ ++ acm_start_wb(acm, urb->context); + } + + /* +@@ -1499,12 +1534,14 @@ static int acm_resume(struct usb_interface *intf) + * do the write path at all cost + */ + if (rv < 0) +- goto err_out; ++ goto out; + +- rv = acm_submit_read_urbs(acm, GFP_NOIO); ++ rv = acm_submit_read_urbs(acm, GFP_ATOMIC); + } ++out: ++ spin_unlock(&acm->write_lock); ++ spin_unlock_irq(&acm->read_lock); + +-err_out: + return rv; + } + +@@ -1542,6 +1579,8 @@ static int acm_reset_resume(struct usb_interface *intf) + + static const struct usb_device_id acm_ids[] = { + /* quirky and broken devices */ ++ { USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */ ++ .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */ + { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ + .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ + }, +@@ -1581,17 +1620,32 @@ static const struct usb_device_id acm_ids[] = { + { USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */ + .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ + }, ++ { USB_DEVICE(0x2184, 0x001c) }, /* GW Instek AFG-2225 */ + { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */ + }, + /* Motorola H24 HSPA module: */ + { USB_DEVICE(0x22b8, 0x2d91) }, /* modem */ +- { USB_DEVICE(0x22b8, 0x2d92) }, /* modem + diagnostics */ +- { USB_DEVICE(0x22b8, 0x2d93) }, /* modem + AT port */ +- { USB_DEVICE(0x22b8, 0x2d95) }, /* modem + AT port + diagnostics */ +- { USB_DEVICE(0x22b8, 0x2d96) }, /* modem + NMEA */ +- { USB_DEVICE(0x22b8, 0x2d97) }, /* modem + diagnostics + NMEA */ +- { USB_DEVICE(0x22b8, 0x2d99) }, /* modem + AT port + NMEA */ +- { USB_DEVICE(0x22b8, 0x2d9a) }, /* modem + AT port + diagnostics + NMEA */ ++ { USB_DEVICE(0x22b8, 0x2d92), /* modem + diagnostics */ ++ .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ ++ }, ++ { USB_DEVICE(0x22b8, 0x2d93), /* modem + AT port */ ++ .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ ++ }, ++ { USB_DEVICE(0x22b8, 0x2d95), /* modem + AT port + diagnostics */ ++ .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ ++ }, ++ { USB_DEVICE(0x22b8, 0x2d96), /* modem + NMEA */ ++ .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ ++ }, ++ { USB_DEVICE(0x22b8, 0x2d97), /* modem + diagnostics + NMEA */ ++ .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ ++ }, ++ { USB_DEVICE(0x22b8, 0x2d99), /* modem + AT port + NMEA */ ++ .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ ++ }, ++ { USB_DEVICE(0x22b8, 0x2d9a), /* modem + AT port + diagnostics + NMEA */ ++ .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ ++ }, + + { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */ + .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on +diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h +index 35ef887b..96147806 100644 +--- a/drivers/usb/class/cdc-acm.h ++++ b/drivers/usb/class/cdc-acm.h +@@ -117,7 +117,7 @@ struct acm { + unsigned int throttled:1; /* actually throttled */ + unsigned int throttle_req:1; /* throttle requested */ + u8 bInterval; +- struct acm_wb *delayed_wb; /* write queued for a device about to be woken */ ++ struct usb_anchor delayed; /* writes queued for a device about to be woken */ + }; + + #define CDC_DATA_INTERFACE_TYPE 0x0a +diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c +index 9dd51f7f..e5fa34e5 100644 +--- a/drivers/usb/class/cdc-wdm.c ++++ b/drivers/usb/class/cdc-wdm.c +@@ -233,6 +233,7 @@ skip_error: + static void wdm_int_callback(struct urb *urb) + { + int rv = 0; ++ int responding; + int status = urb->status; + struct wdm_device *desc; + struct usb_cdc_notification *dr; +@@ -286,8 +287,8 @@ static void wdm_int_callback(struct urb *urb) + + spin_lock(&desc->iuspin); + clear_bit(WDM_READ, &desc->flags); +- set_bit(WDM_RESPONDING, &desc->flags); +- if (!test_bit(WDM_DISCONNECTING, &desc->flags) ++ responding = test_and_set_bit(WDM_RESPONDING, &desc->flags); ++ if (!responding && !test_bit(WDM_DISCONNECTING, &desc->flags) + && !test_bit(WDM_SUSPENDING, &desc->flags)) { + rv = usb_submit_urb(desc->response, GFP_ATOMIC); + dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d", +@@ -687,16 +688,20 @@ static void wdm_rxwork(struct work_struct *work) + { + struct wdm_device *desc = container_of(work, struct wdm_device, rxwork); + unsigned long flags; +- int rv; ++ int rv = 0; ++ int responding; + + spin_lock_irqsave(&desc->iuspin, flags); + if (test_bit(WDM_DISCONNECTING, &desc->flags)) { + spin_unlock_irqrestore(&desc->iuspin, flags); + } else { ++ responding = test_and_set_bit(WDM_RESPONDING, &desc->flags); + spin_unlock_irqrestore(&desc->iuspin, flags); +- rv = usb_submit_urb(desc->response, GFP_KERNEL); ++ if (!responding) ++ rv = usb_submit_urb(desc->response, GFP_KERNEL); + if (rv < 0 && rv != -EPERM) { + spin_lock_irqsave(&desc->iuspin, flags); ++ clear_bit(WDM_RESPONDING, &desc->flags); + if (!test_bit(WDM_DISCONNECTING, &desc->flags)) + schedule_work(&desc->rxwork); + spin_unlock_irqrestore(&desc->iuspin, flags); +@@ -817,13 +822,11 @@ static int wdm_manage_power(struct usb_interface *intf, int on) + { + /* need autopm_get/put here to ensure the usbcore sees the new value */ + int rv = usb_autopm_get_interface(intf); +- if (rv < 0) +- goto err; + + intf->needs_remote_wakeup = on; +- usb_autopm_put_interface(intf); +-err: +- return rv; ++ if (!rv) ++ usb_autopm_put_interface(intf); ++ return 0; + } + + static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) +diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c +index b0585e62..19fa68a7 100644 +--- a/drivers/usb/core/buffer.c ++++ b/drivers/usb/core/buffer.c +@@ -22,17 +22,25 @@ + */ + + /* FIXME tune these based on pool statistics ... */ +-static const size_t pool_max[HCD_BUFFER_POOLS] = { +- /* platforms without dma-friendly caches might need to +- * prevent cacheline sharing... +- */ +- 32, +- 128, +- 512, +- PAGE_SIZE / 2 +- /* bigger --> allocate pages */ ++static size_t pool_max[HCD_BUFFER_POOLS] = { ++ 32, 128, 512, 2048, + }; + ++void __init usb_init_pool_max(void) ++{ ++ /* ++ * The pool_max values must never be smaller than ++ * ARCH_KMALLOC_MINALIGN. ++ */ ++ if (ARCH_KMALLOC_MINALIGN <= 32) ++ ; /* Original value is okay */ ++ else if (ARCH_KMALLOC_MINALIGN <= 64) ++ pool_max[0] = 64; ++ else if (ARCH_KMALLOC_MINALIGN <= 128) ++ pool_max[0] = 0; /* Don't use this pool */ ++ else ++ BUILD_BUG(); /* We don't allow this */ ++} + + /* SETUP primitives */ + +diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c +index f4bdd0ce..f19646ef 100644 +--- a/drivers/usb/core/config.c ++++ b/drivers/usb/core/config.c +@@ -201,6 +201,17 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, + if (n == 0) + n = 9; /* 32 ms = 2^(9-1) uframes */ + j = 16; ++ ++ /* ++ * Adjust bInterval for quirked devices. ++ * This quirk fixes bIntervals reported in ++ * linear microframes. ++ */ ++ if (to_usb_device(ddev)->quirks & ++ USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL) { ++ n = clamp(fls(d->bInterval), i, j); ++ i = j = n; ++ } + break; + default: /* USB_SPEED_FULL or _LOW */ + /* For low-speed, 10 ms is the official minimum. +@@ -424,7 +435,8 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx, + + memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); + if (config->desc.bDescriptorType != USB_DT_CONFIG || +- config->desc.bLength < USB_DT_CONFIG_SIZE) { ++ config->desc.bLength < USB_DT_CONFIG_SIZE || ++ config->desc.bLength > size) { + dev_err(ddev, "invalid descriptor for config index %d: " + "type = 0x%X, length = %d\n", cfgidx, + config->desc.bDescriptorType, config->desc.bLength); +@@ -665,8 +677,6 @@ int usb_get_configuration(struct usb_device *dev) + struct usb_config_descriptor *desc; + + cfgno = 0; +- if (dev->authorized == 0) /* Not really an error */ +- goto out_not_authorized; + result = -ENOMEM; + if (ncfg > USB_MAXCONFIG) { + dev_warn(ddev, "too many configurations: %d, " +@@ -748,7 +758,6 @@ int usb_get_configuration(struct usb_device *dev) + + err: + kfree(desc); +-out_not_authorized: + dev->descriptor.bNumConfigurations = cfgno; + err2: + if (result == -ENOMEM) +diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c +index 404413b0..d2ae3d94 100644 +--- a/drivers/usb/core/devio.c ++++ b/drivers/usb/core/devio.c +@@ -444,6 +444,7 @@ static void async_completed(struct urb *urb) + as->status = urb->status; + signr = as->signr; + if (signr) { ++ memset(&sinfo, 0, sizeof(sinfo)); + sinfo.si_signo = as->signr; + sinfo.si_errno = as->status; + sinfo.si_code = SI_ASYNCIO; +@@ -681,7 +682,25 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, + index &= 0xff; + switch (requesttype & USB_RECIP_MASK) { + case USB_RECIP_ENDPOINT: ++ if ((index & ~USB_DIR_IN) == 0) ++ return 0; + ret = findintfep(ps->dev, index); ++ if (ret < 0) { ++ /* ++ * Some not fully compliant Win apps seem to get ++ * index wrong and have the endpoint number here ++ * rather than the endpoint address (with the ++ * correct direction). Win does let this through, ++ * so we'll not reject it here but leave it to ++ * the device to not break KVM. But we warn. ++ */ ++ ret = findintfep(ps->dev, index ^ 0x80); ++ if (ret >= 0) ++ dev_info(&ps->dev->dev, ++ "%s: process %i (%s) requesting ep %02x but needs %02x\n", ++ __func__, task_pid_nr(current), ++ current->comm, index, index ^ 0x80); ++ } + if (ret >= 0) + ret = checkintf(ps, ret); + break; +@@ -2073,6 +2092,7 @@ static void usbdev_remove(struct usb_device *udev) + wake_up_all(&ps->wait); + list_del_init(&ps->list); + if (ps->discsignr) { ++ memset(&sinfo, 0, sizeof(sinfo)); + sinfo.si_signo = ps->discsignr; + sinfo.si_errno = EPIPE; + sinfo.si_code = SI_ASYNCIO; +diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c +index 9a56635d..621ea00f 100644 +--- a/drivers/usb/core/driver.c ++++ b/drivers/usb/core/driver.c +@@ -530,22 +530,10 @@ int usb_match_device(struct usb_device *dev, const struct usb_device_id *id) + } + + /* returns 0 if no match, 1 if match */ +-int usb_match_one_id(struct usb_interface *interface, +- const struct usb_device_id *id) ++int usb_match_one_id_intf(struct usb_device *dev, ++ struct usb_host_interface *intf, ++ const struct usb_device_id *id) + { +- struct usb_host_interface *intf; +- struct usb_device *dev; +- +- /* proc_connectinfo in devio.c may call us with id == NULL. */ +- if (id == NULL) +- return 0; +- +- intf = interface->cur_altsetting; +- dev = interface_to_usbdev(interface); +- +- if (!usb_match_device(dev, id)) +- return 0; +- + /* The interface class, subclass, and protocol should never be + * checked for a match if the device class is Vendor Specific, + * unless the match record specifies the Vendor ID. */ +@@ -570,6 +558,26 @@ int usb_match_one_id(struct usb_interface *interface, + + return 1; + } ++ ++/* returns 0 if no match, 1 if match */ ++int usb_match_one_id(struct usb_interface *interface, ++ const struct usb_device_id *id) ++{ ++ struct usb_host_interface *intf; ++ struct usb_device *dev; ++ ++ /* proc_connectinfo in devio.c may call us with id == NULL. */ ++ if (id == NULL) ++ return 0; ++ ++ intf = interface->cur_altsetting; ++ dev = interface_to_usbdev(interface); ++ ++ if (!usb_match_device(dev, id)) ++ return 0; ++ ++ return usb_match_one_id_intf(dev, intf, id); ++} + EXPORT_SYMBOL_GPL(usb_match_one_id); + + /** +@@ -906,8 +914,7 @@ EXPORT_SYMBOL_GPL(usb_deregister); + * it doesn't support pre_reset/post_reset/reset_resume or + * because it doesn't support suspend/resume. + * +- * The caller must hold @intf's device's lock, but not its pm_mutex +- * and not @intf->dev.sem. ++ * The caller must hold @intf's device's lock, but not @intf's lock. + */ + void usb_forced_unbind_intf(struct usb_interface *intf) + { +@@ -920,16 +927,37 @@ void usb_forced_unbind_intf(struct usb_interface *intf) + intf->needs_binding = 1; + } + ++/* ++ * Unbind drivers for @udev's marked interfaces. These interfaces have ++ * the needs_binding flag set, for example by usb_resume_interface(). ++ * ++ * The caller must hold @udev's device lock. ++ */ ++static void unbind_marked_interfaces(struct usb_device *udev) ++{ ++ struct usb_host_config *config; ++ int i; ++ struct usb_interface *intf; ++ ++ config = udev->actconfig; ++ if (config) { ++ for (i = 0; i < config->desc.bNumInterfaces; ++i) { ++ intf = config->interface[i]; ++ if (intf->dev.driver && intf->needs_binding) ++ usb_forced_unbind_intf(intf); ++ } ++ } ++} ++ + /* Delayed forced unbinding of a USB interface driver and scan + * for rebinding. + * +- * The caller must hold @intf's device's lock, but not its pm_mutex +- * and not @intf->dev.sem. ++ * The caller must hold @intf's device's lock, but not @intf's lock. + * + * Note: Rebinds will be skipped if a system sleep transition is in + * progress and the PM "complete" callback hasn't occurred yet. + */ +-void usb_rebind_intf(struct usb_interface *intf) ++static void usb_rebind_intf(struct usb_interface *intf) + { + int rc; + +@@ -946,68 +974,66 @@ void usb_rebind_intf(struct usb_interface *intf) + } + } + +-#ifdef CONFIG_PM +- +-/* Unbind drivers for @udev's interfaces that don't support suspend/resume +- * There is no check for reset_resume here because it can be determined +- * only during resume whether reset_resume is needed. ++/* ++ * Rebind drivers to @udev's marked interfaces. These interfaces have ++ * the needs_binding flag set. + * + * The caller must hold @udev's device lock. + */ +-static void unbind_no_pm_drivers_interfaces(struct usb_device *udev) ++static void rebind_marked_interfaces(struct usb_device *udev) + { + struct usb_host_config *config; + int i; + struct usb_interface *intf; +- struct usb_driver *drv; + + config = udev->actconfig; + if (config) { + for (i = 0; i < config->desc.bNumInterfaces; ++i) { + intf = config->interface[i]; +- +- if (intf->dev.driver) { +- drv = to_usb_driver(intf->dev.driver); +- if (!drv->suspend || !drv->resume) +- usb_forced_unbind_intf(intf); +- } ++ if (intf->needs_binding) ++ usb_rebind_intf(intf); + } + } + } + +-/* Unbind drivers for @udev's interfaces that failed to support reset-resume. +- * These interfaces have the needs_binding flag set by usb_resume_interface(). ++/* ++ * Unbind all of @udev's marked interfaces and then rebind all of them. ++ * This ordering is necessary because some drivers claim several interfaces ++ * when they are first probed. + * + * The caller must hold @udev's device lock. + */ +-static void unbind_no_reset_resume_drivers_interfaces(struct usb_device *udev) ++void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev) + { +- struct usb_host_config *config; +- int i; +- struct usb_interface *intf; +- +- config = udev->actconfig; +- if (config) { +- for (i = 0; i < config->desc.bNumInterfaces; ++i) { +- intf = config->interface[i]; +- if (intf->dev.driver && intf->needs_binding) +- usb_forced_unbind_intf(intf); +- } +- } ++ unbind_marked_interfaces(udev); ++ rebind_marked_interfaces(udev); + } + +-static void do_rebind_interfaces(struct usb_device *udev) ++#ifdef CONFIG_PM ++ ++/* Unbind drivers for @udev's interfaces that don't support suspend/resume ++ * There is no check for reset_resume here because it can be determined ++ * only during resume whether reset_resume is needed. ++ * ++ * The caller must hold @udev's device lock. ++ */ ++static void unbind_no_pm_drivers_interfaces(struct usb_device *udev) + { + struct usb_host_config *config; + int i; + struct usb_interface *intf; ++ struct usb_driver *drv; + + config = udev->actconfig; + if (config) { + for (i = 0; i < config->desc.bNumInterfaces; ++i) { + intf = config->interface[i]; +- if (intf->needs_binding) +- usb_rebind_intf(intf); ++ ++ if (intf->dev.driver) { ++ drv = to_usb_driver(intf->dev.driver); ++ if (!drv->suspend || !drv->resume) ++ usb_forced_unbind_intf(intf); ++ } + } + } + } +@@ -1325,7 +1351,7 @@ int usb_resume_complete(struct device *dev) + * whose needs_binding flag is set + */ + if (udev->state != USB_STATE_NOTATTACHED) +- do_rebind_interfaces(udev); ++ rebind_marked_interfaces(udev); + return 0; + } + +@@ -1347,7 +1373,7 @@ int usb_resume(struct device *dev, pm_message_t msg) + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); +- unbind_no_reset_resume_drivers_interfaces(udev); ++ unbind_marked_interfaces(udev); + } + + /* Avoid PM error messages for devices disconnected while suspended +@@ -1660,6 +1686,18 @@ static int autosuspend_check(struct usb_device *udev) + dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n"); + return -EOPNOTSUPP; + } ++ ++ /* ++ * If the device is a direct child of the root hub and the HCD ++ * doesn't handle wakeup requests, don't allow autosuspend when ++ * wakeup is needed. ++ */ ++ if (w && udev->parent == udev->bus->root_hub && ++ bus_to_hcd(udev->bus)->cant_recv_wakeups) { ++ dev_dbg(&udev->dev, "HCD doesn't handle wakeup requests\n"); ++ return -EOPNOTSUPP; ++ } ++ + udev->do_remote_wakeup = w; + return 0; + } +@@ -1682,10 +1720,13 @@ int usb_runtime_suspend(struct device *dev) + if (status == -EAGAIN || status == -EBUSY) + usb_mark_last_busy(udev); + +- /* The PM core reacts badly unless the return code is 0, +- * -EAGAIN, or -EBUSY, so always return -EBUSY on an error. ++ /* ++ * The PM core reacts badly unless the return code is 0, ++ * -EAGAIN, or -EBUSY, so always return -EBUSY on an error ++ * (except for root hubs, because they don't suspend through ++ * an upstream port like other USB devices). + */ +- if (status != 0) ++ if (status != 0 && udev->parent) + return -EBUSY; + return status; + } +diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c +index 2b487d47..50ebe6cf 100644 +--- a/drivers/usb/core/hcd-pci.c ++++ b/drivers/usb/core/hcd-pci.c +@@ -71,7 +71,7 @@ static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd, + continue; + + companion_hcd = pci_get_drvdata(companion); +- if (!companion_hcd) ++ if (!companion_hcd || !companion_hcd->self.root_hub) + continue; + + /* For SET_HS_COMPANION, store a pointer to the EHCI bus in +diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c +index e2cc8df3..f1d0e3ca 100644 +--- a/drivers/usb/core/hcd.c ++++ b/drivers/usb/core/hcd.c +@@ -1528,6 +1528,7 @@ static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status) + int usb_hcd_unlink_urb (struct urb *urb, int status) + { + struct usb_hcd *hcd; ++ struct usb_device *udev = urb->dev; + int retval = -EIDRM; + unsigned long flags; + +@@ -1539,20 +1540,19 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) + spin_lock_irqsave(&hcd_urb_unlink_lock, flags); + if (atomic_read(&urb->use_count) > 0) { + retval = 0; +- usb_get_dev(urb->dev); ++ usb_get_dev(udev); + } + spin_unlock_irqrestore(&hcd_urb_unlink_lock, flags); + if (retval == 0) { + hcd = bus_to_hcd(urb->dev->bus); + retval = unlink1(hcd, urb, status); +- usb_put_dev(urb->dev); ++ if (retval == 0) ++ retval = -EINPROGRESS; ++ else if (retval != -EIDRM && retval != -EBUSY) ++ dev_dbg(&udev->dev, "hcd_unlink_urb %p fail %d\n", ++ urb, retval); ++ usb_put_dev(udev); + } +- +- if (retval == 0) +- retval = -EINPROGRESS; +- else if (retval != -EIDRM && retval != -EBUSY) +- dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n", +- urb, retval); + return retval; + } + +@@ -1882,6 +1882,8 @@ int usb_alloc_streams(struct usb_interface *interface, + return -EINVAL; + if (dev->speed != USB_SPEED_SUPER) + return -EINVAL; ++ if (dev->state < USB_STATE_CONFIGURED) ++ return -ENODEV; + + /* Streams only apply to bulk endpoints. */ + for (i = 0; i < num_eps; i++) +diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c +index 49b139c1..4a4df38f 100644 +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -488,6 +488,15 @@ resubmit: + static inline int + hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt) + { ++ /* Need to clear both directions for control ep */ ++ if (((devinfo >> 11) & USB_ENDPOINT_XFERTYPE_MASK) == ++ USB_ENDPOINT_XFER_CONTROL) { ++ int status = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), ++ HUB_CLEAR_TT_BUFFER, USB_RT_PORT, ++ devinfo ^ 0x8000, tt, NULL, 0, 1000); ++ if (status) ++ return status; ++ } + return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + HUB_CLEAR_TT_BUFFER, USB_RT_PORT, devinfo, + tt, NULL, 0, 1000); +@@ -911,6 +920,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) + clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_C_ENABLE); + } ++ if (portchange & USB_PORT_STAT_C_RESET) { ++ need_debounce_delay = true; ++ clear_port_feature(hub->hdev, port1, ++ USB_PORT_FEAT_C_RESET); ++ } + if ((portchange & USB_PORT_STAT_C_BH_RESET) && + hub_is_superspeed(hub->hdev)) { + need_debounce_delay = true; +@@ -1326,6 +1340,7 @@ static int hub_configure(struct usb_hub *hub, + return 0; + + fail: ++ hdev->maxchild = 0; + dev_err (hub_dev, "config failed, %s (err %d)\n", + message, ret); + /* hub_disconnect() frees urb and descriptor */ +@@ -1386,8 +1401,19 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) + desc = intf->cur_altsetting; + hdev = interface_to_usbdev(intf); + +- /* Hubs have proper suspend/resume support. */ +- usb_enable_autosuspend(hdev); ++ /* ++ * Hubs have proper suspend/resume support, except for root hubs ++ * where the controller driver doesn't have bus_suspend and ++ * bus_resume methods. ++ */ ++ if (hdev->parent) { /* normal device */ ++ usb_enable_autosuspend(hdev); ++ } else { /* root hub */ ++ const struct hc_driver *drv = bus_to_hcd(hdev->bus)->driver; ++ ++ if (drv->bus_suspend && drv->bus_resume) ++ usb_enable_autosuspend(hdev); ++ } + + if (hdev->level == MAX_TOPO_LEVEL) { + dev_err(&intf->dev, +@@ -1612,8 +1638,10 @@ void usb_set_device_state(struct usb_device *udev, + || new_state == USB_STATE_SUSPENDED) + ; /* No change to wakeup settings */ + else if (new_state == USB_STATE_CONFIGURED) +- wakeup = udev->actconfig->desc.bmAttributes +- & USB_CONFIG_ATT_WAKEUP; ++ wakeup = (udev->quirks & ++ USB_QUIRK_IGNORE_REMOTE_WAKEUP) ? 0 : ++ udev->actconfig->desc.bmAttributes & ++ USB_CONFIG_ATT_WAKEUP; + else + wakeup = 0; + } +@@ -1675,12 +1703,12 @@ static void choose_devnum(struct usb_device *udev) + * bus->devnum_next. */ + devnum = find_next_zero_bit(bus->devmap.devicemap, 128, + bus->devnum_next); +- if (devnum >= 128) ++ if (devnum >= 127) + devnum = find_next_zero_bit(bus->devmap.devicemap, + 128, 1); +- bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); ++ bus->devnum_next = ( devnum >= 126 ? 1 : devnum + 1); + } +- if (devnum < 128) { ++ if (devnum < 127) { + set_bit(devnum, bus->devmap.devicemap); + udev->devnum = devnum; + } +@@ -1906,24 +1934,23 @@ static int usb_enumerate_device(struct usb_device *udev) + if (err < 0) { + dev_err(&udev->dev, "can't read configurations, error %d\n", + err); +- goto fail; ++ return err; + } + } +- if (udev->wusb == 1 && udev->authorized == 0) { +- udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); +- udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); +- udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); +- } +- else { +- /* read the standard strings and cache them if present */ +- udev->product = usb_cache_string(udev, udev->descriptor.iProduct); +- udev->manufacturer = usb_cache_string(udev, +- udev->descriptor.iManufacturer); +- udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); +- } ++ ++ /* read the standard strings and cache them if present */ ++ udev->product = usb_cache_string(udev, udev->descriptor.iProduct); ++ udev->manufacturer = usb_cache_string(udev, ++ udev->descriptor.iManufacturer); ++ udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); ++ + err = usb_enumerate_device_otg(udev); +-fail: +- return err; ++ if (err < 0) ++ return err; ++ ++ usb_detect_interface_quirks(udev); ++ ++ return 0; + } + + static void set_usb_port_removable(struct usb_device *udev) +@@ -2074,16 +2101,6 @@ int usb_deauthorize_device(struct usb_device *usb_dev) + usb_dev->authorized = 0; + usb_set_configuration(usb_dev, -1); + +- kfree(usb_dev->product); +- usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); +- kfree(usb_dev->manufacturer); +- usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); +- kfree(usb_dev->serial); +- usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); +- +- usb_destroy_configuration(usb_dev); +- usb_dev->descriptor.bNumConfigurations = 0; +- + out_unauthorized: + usb_unlock_device(usb_dev); + return 0; +@@ -2111,17 +2128,7 @@ int usb_authorize_device(struct usb_device *usb_dev) + goto error_device_descriptor; + } + +- kfree(usb_dev->product); +- usb_dev->product = NULL; +- kfree(usb_dev->manufacturer); +- usb_dev->manufacturer = NULL; +- kfree(usb_dev->serial); +- usb_dev->serial = NULL; +- + usb_dev->authorized = 1; +- result = usb_enumerate_device(usb_dev); +- if (result < 0) +- goto error_enumerate; + /* Choose and set the configuration. This registers the interfaces + * with the driver core and lets interface drivers bind to them. + */ +@@ -2137,7 +2144,6 @@ int usb_authorize_device(struct usb_device *usb_dev) + } + dev_info(&usb_dev->dev, "authorized to connect\n"); + +-error_enumerate: + error_device_descriptor: + usb_autosuspend_device(usb_dev); + error_autoresume: +@@ -3095,8 +3101,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, + retval = hub_port_reset(hub, port1, udev, delay, false); + if (retval < 0) /* error or disconnect */ + goto fail; ++#if 0 ++ //add by liming for usb controler bug, otherwise the usb enumeration error ++ retval = hub_port_reset(hub, port1, udev, delay, false); ++ if (retval < 0) /* error or disconnect */ ++ goto fail; + /* success, speed is known */ +- ++#endif + retval = -ENODEV; + + if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) { +@@ -3213,6 +3224,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, + buf->bMaxPacketSize0; + kfree(buf); + ++#if 0 + retval = hub_port_reset(hub, port1, udev, delay, false); + if (retval < 0) /* error or disconnect */ + goto fail; +@@ -3222,6 +3234,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, + retval = -ENODEV; + goto fail; + } ++#endif + if (r) { + dev_err(&udev->dev, + "device descriptor read/64, error %d\n", +@@ -3355,6 +3368,9 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1) + struct usb_qualifier_descriptor *qual; + int status; + ++ if (udev->quirks & USB_QUIRK_DEVICE_QUALIFIER) ++ return; ++ + qual = kmalloc (sizeof *qual, GFP_KERNEL); + if (qual == NULL) + return; +@@ -3725,9 +3741,10 @@ static void hub_events(void) + + hub = list_entry(tmp, struct usb_hub, event_list); + kref_get(&hub->kref); ++ hdev = hub->hdev; ++ usb_get_dev(hdev); + spin_unlock_irq(&hub_event_lock); + +- hdev = hub->hdev; + hub_dev = hub->intfdev; + intf = to_usb_interface(hub_dev); + dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n", +@@ -3881,7 +3898,9 @@ static void hub_events(void) + hub->hdev->children[i - 1]; + + dev_dbg(hub_dev, "warm reset port %d\n", i); +- if (!udev) { ++ if (!udev || ++ !(portstatus & USB_PORT_STAT_CONNECTION) || ++ udev->state == USB_STATE_NOTATTACHED) { + status = hub_port_reset(hub, i, + NULL, HUB_BH_RESET_TIME, + true); +@@ -3891,8 +3910,8 @@ static void hub_events(void) + usb_lock_device(udev); + status = usb_reset_device(udev); + usb_unlock_device(udev); ++ connect_change = 0; + } +- connect_change = 0; + } + + if (connect_change) +@@ -3940,6 +3959,7 @@ static void hub_events(void) + usb_autopm_put_interface(intf); + loop_disconnected: + usb_unlock_device(hdev); ++ usb_put_dev(hdev); + kref_put(&hub->kref, hub_release); + + } /* end while (1) */ +@@ -4149,6 +4169,12 @@ static int usb_reset_and_verify_device(struct usb_device *udev) + } + parent_hub = hdev_to_hub(parent_hdev); + ++ /* Disable USB2 hardware LPM. ++ * It will be re-enabled by the enumeration process. ++ */ ++ if (udev->usb2_hw_lpm_enabled == 1) ++ usb_set_usb2_hardware_lpm(udev, 0); ++ + set_bit(port1, parent_hub->busy_bits); + for (i = 0; i < SET_CONFIG_TRIES; ++i) { + +@@ -4312,10 +4338,11 @@ int usb_reset_device(struct usb_device *udev) + else if (cintf->condition == + USB_INTERFACE_BOUND) + rebind = 1; ++ if (rebind) ++ cintf->needs_binding = 1; + } +- if (ret == 0 && rebind) +- usb_rebind_intf(cintf); + } ++ usb_unbind_and_rebind_marked_interfaces(udev); + } + + usb_autosuspend_device(udev); +diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h +index e8cdce57..2753cec6 100644 +--- a/drivers/usb/core/otg_whitelist.h ++++ b/drivers/usb/core/otg_whitelist.h +@@ -59,6 +59,11 @@ static int is_targeted(struct usb_device *dev) + le16_to_cpu(dev->descriptor.idProduct) == 0xbadd)) + return 0; + ++ /* OTG PET device is always targeted (see OTG 2.0 ECN 6.4.2) */ ++ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a && ++ le16_to_cpu(dev->descriptor.idProduct) == 0x0200)) ++ return 1; ++ + /* NOTE: can't use usb_match_id() since interface caches + * aren't set up yet. this is cut/paste from that code. + */ +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 8b2a9d83..9fac46d4 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -15,17 +15,22 @@ + #include + #include "usb.h" + +-/* List of quirky USB devices. Please keep this list ordered by: ++/* Lists of quirky USB devices, split in device quirks and interface quirks. ++ * Device quirks are applied at the very beginning of the enumeration process, ++ * right after reading the device descriptor. They can thus only match on device ++ * information. ++ * ++ * Interface quirks are applied after reading all the configuration descriptors. ++ * They can match on both device and interface information. ++ * ++ * Note that the DELAY_INIT and HONOR_BNUMINTERFACES quirks do not make sense as ++ * interface quirks, as they only influence the enumeration process which is run ++ * before processing the interface quirks. ++ * ++ * Please keep the lists ordered by: + * 1) Vendor ID + * 2) Product ID + * 3) Class ID +- * +- * as we want specific devices to be overridden first, and only after that, any +- * class specific quirks. +- * +- * Right now the logic aborts if it finds a valid device in the table, we might +- * want to change that in the future if it turns out that a whole class of +- * devices is broken... + */ + static const struct usb_device_id usb_quirk_list[] = { + /* CBM - Flash disk */ +@@ -38,53 +43,29 @@ static const struct usb_device_id usb_quirk_list[] = { + /* Creative SB Audigy 2 NX */ + { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, + +- /* Logitech Webcam C200 */ +- { USB_DEVICE(0x046d, 0x0802), .driver_info = USB_QUIRK_RESET_RESUME }, +- +- /* Logitech Webcam C250 */ +- { USB_DEVICE(0x046d, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME }, +- +- /* Logitech Webcam C300 */ +- { USB_DEVICE(0x046d, 0x0805), .driver_info = USB_QUIRK_RESET_RESUME }, +- +- /* Logitech Webcam B/C500 */ +- { USB_DEVICE(0x046d, 0x0807), .driver_info = USB_QUIRK_RESET_RESUME }, +- +- /* Logitech Webcam C600 */ +- { USB_DEVICE(0x046d, 0x0808), .driver_info = USB_QUIRK_RESET_RESUME }, +- +- /* Logitech Webcam Pro 9000 */ +- { USB_DEVICE(0x046d, 0x0809), .driver_info = USB_QUIRK_RESET_RESUME }, +- +- /* Logitech Webcam C905 */ +- { USB_DEVICE(0x046d, 0x080a), .driver_info = USB_QUIRK_RESET_RESUME }, +- +- /* Logitech Webcam C210 */ +- { USB_DEVICE(0x046d, 0x0819), .driver_info = USB_QUIRK_RESET_RESUME }, ++ /* Microsoft Wireless Laser Mouse 6000 Receiver */ ++ { USB_DEVICE(0x045e, 0x00e1), .driver_info = USB_QUIRK_RESET_RESUME }, + +- /* Logitech Webcam C260 */ +- { USB_DEVICE(0x046d, 0x081a), .driver_info = USB_QUIRK_RESET_RESUME }, ++ /* Microsoft LifeCam-VX700 v2.0 */ ++ { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME }, + +- /* Logitech Webcam C310 */ +- { USB_DEVICE(0x046d, 0x081b), .driver_info = USB_QUIRK_RESET_RESUME }, ++ /* Logitech Quickcam Fusion */ ++ { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME }, + +- /* Logitech Webcam C910 */ +- { USB_DEVICE(0x046d, 0x0821), .driver_info = USB_QUIRK_RESET_RESUME }, ++ /* Logitech Quickcam Orbit MP */ ++ { USB_DEVICE(0x046d, 0x08c2), .driver_info = USB_QUIRK_RESET_RESUME }, + +- /* Logitech Webcam C160 */ +- { USB_DEVICE(0x046d, 0x0824), .driver_info = USB_QUIRK_RESET_RESUME }, ++ /* Logitech Quickcam Pro for Notebook */ ++ { USB_DEVICE(0x046d, 0x08c3), .driver_info = USB_QUIRK_RESET_RESUME }, + +- /* Logitech Webcam C270 */ +- { USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME }, ++ /* Logitech Quickcam Pro 5000 */ ++ { USB_DEVICE(0x046d, 0x08c5), .driver_info = USB_QUIRK_RESET_RESUME }, + +- /* Logitech Quickcam Pro 9000 */ +- { USB_DEVICE(0x046d, 0x0990), .driver_info = USB_QUIRK_RESET_RESUME }, ++ /* Logitech Quickcam OEM Dell Notebook */ ++ { USB_DEVICE(0x046d, 0x08c6), .driver_info = USB_QUIRK_RESET_RESUME }, + +- /* Logitech Quickcam E3500 */ +- { USB_DEVICE(0x046d, 0x09a4), .driver_info = USB_QUIRK_RESET_RESUME }, +- +- /* Logitech Quickcam Vision Pro */ +- { USB_DEVICE(0x046d, 0x09a6), .driver_info = USB_QUIRK_RESET_RESUME }, ++ /* Logitech Quickcam OEM Cisco VT Camera II */ ++ { USB_DEVICE(0x046d, 0x08c7), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Harmony 700-series */ + { USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT }, +@@ -100,16 +81,34 @@ static const struct usb_device_id usb_quirk_list[] = { + { USB_DEVICE(0x04d8, 0x000c), .driver_info = + USB_QUIRK_CONFIG_INTF_STRINGS }, + ++ /* CarrolTouch 4000U */ ++ { USB_DEVICE(0x04e7, 0x0009), .driver_info = USB_QUIRK_RESET_RESUME }, ++ ++ /* CarrolTouch 4500U */ ++ { USB_DEVICE(0x04e7, 0x0030), .driver_info = USB_QUIRK_RESET_RESUME }, ++ + /* Samsung Android phone modem - ID conflict with SPH-I500 */ + { USB_DEVICE(0x04e8, 0x6601), .driver_info = + USB_QUIRK_CONFIG_INTF_STRINGS }, + ++ { USB_DEVICE(0x04f3, 0x009b), .driver_info = ++ USB_QUIRK_DEVICE_QUALIFIER }, ++ ++ { USB_DEVICE(0x04f3, 0x016f), .driver_info = ++ USB_QUIRK_DEVICE_QUALIFIER }, ++ + /* Roland SC-8820 */ + { USB_DEVICE(0x0582, 0x0007), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Edirol SD-20 */ + { USB_DEVICE(0x0582, 0x0027), .driver_info = USB_QUIRK_RESET_RESUME }, + ++ /* Alcor Micro Corp. Hub */ ++ { USB_DEVICE(0x058f, 0x9254), .driver_info = USB_QUIRK_RESET_RESUME }, ++ ++ /* MicroTouch Systems touchscreen */ ++ { USB_DEVICE(0x0596, 0x051e), .driver_info = USB_QUIRK_RESET_RESUME }, ++ + /* appletouch */ + { USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME }, + +@@ -143,6 +142,9 @@ static const struct usb_device_id usb_quirk_list[] = { + /* Broadcom BCM92035DGROM BT dongle */ + { USB_DEVICE(0x0a5c, 0x2021), .driver_info = USB_QUIRK_RESET_RESUME }, + ++ /* MAYA44USB sound device */ ++ { USB_DEVICE(0x0a92, 0x0091), .driver_info = USB_QUIRK_RESET_RESUME }, ++ + /* Action Semiconductor flash disk */ + { USB_DEVICE(0x10d6, 0x2200), .driver_info = + USB_QUIRK_STRING_FETCH_255 }, +@@ -150,6 +152,10 @@ static const struct usb_device_id usb_quirk_list[] = { + /* SKYMEDI USB_DRIVE */ + { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, + ++ /* Razer - Razer Blade Keyboard */ ++ { USB_DEVICE(0x1532, 0x0116), .driver_info = ++ USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, ++ + /* BUILDWIN Photo Frame */ + { USB_DEVICE(0x1908, 0x1315), .driver_info = + USB_QUIRK_HONOR_BNUMINTERFACES }, +@@ -160,16 +166,65 @@ static const struct usb_device_id usb_quirk_list[] = { + { } /* terminating entry must be last */ + }; + +-static const struct usb_device_id *find_id(struct usb_device *udev) ++static const struct usb_device_id usb_interface_quirk_list[] = { ++ /* Logitech UVC Cameras */ ++ { USB_VENDOR_AND_INTERFACE_INFO(0x046d, USB_CLASS_VIDEO, 1, 0), ++ .driver_info = USB_QUIRK_RESET_RESUME }, ++ ++ /* ASUS Base Station(T100) */ ++ { USB_DEVICE(0x0b05, 0x17e0), .driver_info = ++ USB_QUIRK_IGNORE_REMOTE_WAKEUP }, ++ ++ /* Protocol and OTG Electrical Test Device */ ++ { USB_DEVICE(0x1a0a, 0x0200), .driver_info = ++ USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, ++ ++ { } /* terminating entry must be last */ ++}; ++ ++static bool usb_match_any_interface(struct usb_device *udev, ++ const struct usb_device_id *id) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < udev->descriptor.bNumConfigurations; ++i) { ++ struct usb_host_config *cfg = &udev->config[i]; ++ unsigned int j; ++ ++ for (j = 0; j < cfg->desc.bNumInterfaces; ++j) { ++ struct usb_interface_cache *cache; ++ struct usb_host_interface *intf; ++ ++ cache = cfg->intf_cache[j]; ++ if (cache->num_altsetting == 0) ++ continue; ++ ++ intf = &cache->altsetting[0]; ++ if (usb_match_one_id_intf(udev, intf, id)) ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++static u32 __usb_detect_quirks(struct usb_device *udev, ++ const struct usb_device_id *id) + { +- const struct usb_device_id *id = usb_quirk_list; ++ u32 quirks = 0; ++ ++ for (; id->match_flags; id++) { ++ if (!usb_match_device(udev, id)) ++ continue; + +- for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass || +- id->driver_info; id++) { +- if (usb_match_device(udev, id)) +- return id; ++ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_INFO) && ++ !usb_match_any_interface(udev, id)) ++ continue; ++ ++ quirks |= (u32)(id->driver_info); + } +- return NULL; ++ ++ return quirks; + } + + /* +@@ -177,14 +232,10 @@ static const struct usb_device_id *find_id(struct usb_device *udev) + */ + void usb_detect_quirks(struct usb_device *udev) + { +- const struct usb_device_id *id = usb_quirk_list; +- +- id = find_id(udev); +- if (id) +- udev->quirks = (u32)(id->driver_info); ++ udev->quirks = __usb_detect_quirks(udev, usb_quirk_list); + if (udev->quirks) + dev_dbg(&udev->dev, "USB quirks for this device: %x\n", +- udev->quirks); ++ udev->quirks); + + /* For the present, all devices default to USB-PERSIST enabled */ + #if 0 /* was: #ifdef CONFIG_PM */ +@@ -201,3 +252,16 @@ void usb_detect_quirks(struct usb_device *udev) + udev->persist_enabled = 1; + #endif /* CONFIG_PM */ + } ++ ++void usb_detect_interface_quirks(struct usb_device *udev) ++{ ++ u32 quirks; ++ ++ quirks = __usb_detect_quirks(udev, usb_interface_quirk_list); ++ if (quirks == 0) ++ return; ++ ++ dev_dbg(&udev->dev, "USB interface quirks for this device: %x\n", ++ quirks); ++ udev->quirks |= quirks; ++} +diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c +index c74ba7bb..89669608 100644 +--- a/drivers/usb/core/usb.c ++++ b/drivers/usb/core/usb.c +@@ -1010,6 +1010,7 @@ static int __init usb_init(void) + pr_info("%s: USB support disabled\n", usbcore_name); + return 0; + } ++ usb_init_pool_max(); + + retval = usb_debugfs_init(); + if (retval) +diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h +index 71648dcb..645278fb 100644 +--- a/drivers/usb/core/usb.h ++++ b/drivers/usb/core/usb.h +@@ -24,6 +24,7 @@ extern void usb_disable_device(struct usb_device *dev, int skip_ep0); + extern int usb_deauthorize_device(struct usb_device *); + extern int usb_authorize_device(struct usb_device *); + extern void usb_detect_quirks(struct usb_device *udev); ++extern void usb_detect_interface_quirks(struct usb_device *udev); + extern int usb_remove_device(struct usb_device *udev); + + extern int usb_get_device_descriptor(struct usb_device *dev, +@@ -35,10 +36,13 @@ extern int usb_set_configuration(struct usb_device *dev, int configuration); + extern int usb_choose_configuration(struct usb_device *udev); + + extern void usb_kick_khubd(struct usb_device *dev); ++extern int usb_match_one_id_intf(struct usb_device *dev, ++ struct usb_host_interface *intf, ++ const struct usb_device_id *id); + extern int usb_match_device(struct usb_device *dev, + const struct usb_device_id *id); + extern void usb_forced_unbind_intf(struct usb_interface *intf); +-extern void usb_rebind_intf(struct usb_interface *intf); ++extern void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev); + + extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port, + void *owner); +diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig +index f70cab3b..0d11047b 100644 +--- a/drivers/usb/musb/Kconfig ++++ b/drivers/usb/musb/Kconfig +@@ -7,7 +7,7 @@ + config USB_MUSB_HDRC + tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' + depends on USB && USB_GADGET +- select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN) ++ select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN || GK_MUSB) + select TWL4030_USB if MACH_OMAP_3430SDP + select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA + select USB_OTG_UTILS +@@ -32,8 +32,8 @@ config USB_MUSB_HDRC + + if USB_MUSB_HDRC + +-choice +- prompt "Platform Glue Layer" ++#choice ++# prompt "Platform Glue Layer" + + config USB_MUSB_DAVINCI + tristate "DaVinci" +@@ -45,6 +45,50 @@ config USB_MUSB_DA8XX + + config USB_MUSB_TUSB6010 + tristate "TUSB6010" ++ ++config USB_MUSB_GK ++ boolean "GK MUSB support" ++ depends on USB_MUSB_HDRC && !USB_MUSB_SOC ++ depends on GK_MUSB ++ help ++ Say Y here if your system has a dual role high speed USB ++ controller based on the Mentor Graphics silicon IP. ++ ++if USB_MUSB_GK ++choice ++ prompt "GK USB work mode" ++ default GK_USB_HOST_MODE if USB_MUSB_GK ++ help ++ Slect GK USB work mode between HOST and SLAVE. ++ ++config GK_USB_HOST_MODE ++ bool "USB-MASTER mode" ++ depends on USB_MUSB_GK ++ help ++ GK USB work in HOST mode. ++ ++config GK_USB_SLAVE_MODE ++ bool "USB-SALVE mode" ++ depends on USB_MUSB_GK ++ help ++ GK USB work in SLAVE mode. ++ ++config GK_USB_OTG_MODE ++ bool "GK USB OTG mode" ++ depends on USB_MUSB_GK ++ select USB_OTG_WHITELIST ++ help ++ GK USB OTG mode. ++endchoice ++ ++if GK_USB_OTG_MODE ++config GK_USB_OTG_GPIO ++ int "USB OTG PIN" ++ help ++ GK UUSB OTG pin. ++endif #GK_OTG ++ ++endif #USB_MUSB_GK + + config USB_MUSB_OMAP2PLUS + tristate "OMAP2430 and onwards" +@@ -62,12 +106,12 @@ config USB_MUSB_UX500 + tristate "U8500 and U5500" + depends on (ARCH_U8500 && AB8500_USB) + +-endchoice ++#endchoice + + choice + prompt 'MUSB DMA mode' + default USB_UX500_DMA if USB_MUSB_UX500 +- default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN ++ default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN || USB_MUSB_GK + default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI + default USB_TUSB_OMAP_DMA if USB_MUSB_TUSB6010 + default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X +@@ -83,8 +127,8 @@ config USB_UX500_DMA + Enable DMA transfers on UX500 platforms. + + config USB_INVENTRA_DMA +- bool 'Inventra' +- depends on USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN ++ bool 'use inventra DMA' ++ depends on USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN || USB_MUSB_GK + help + Enable DMA transfers using Mentor's engine. + +diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile +index 88bfb9de..16aad307 100644 +--- a/drivers/usb/musb/Makefile ++++ b/drivers/usb/musb/Makefile +@@ -18,6 +18,7 @@ obj-$(CONFIG_USB_MUSB_DAVINCI) += davinci.o + obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o + obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o + obj-$(CONFIG_USB_MUSB_UX500) += ux500.o ++obj-$(CONFIG_USB_MUSB_GK) += gk_usb.o + + # the kconfig must guarantee that only one of the + # possible I/O schemes will be enabled at a time ... +diff --git a/drivers/usb/musb/gk_usb.c b/drivers/usb/musb/gk_usb.c +new file mode 100644 +index 00000000..61730077 +--- /dev/null ++++ b/drivers/usb/musb/gk_usb.c +@@ -0,0 +1,548 @@ ++/* ++ * drivers/usb/gk_usb.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2014-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++#include ++ ++#include "musb_core.h" ++#include "gk_usb.h" ++ ++ ++static struct timer_list musb_idle_timer; ++static struct musb *the_musb; ++ ++ ++struct gk_glue { ++ struct device *dev; ++ struct platform_device *musb; ++}; ++ ++#define USB_PHY_BASE (GK_VA_USB_PHY) ++#define USB_PHY_REG(x) (USB_PHY_BASE + (x)) ++ ++#define REG_USB_PHY_UTMI0 USB_PHY_REG(0x000) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_01 USB_PHY_REG(0x004) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_02 USB_PHY_REG(0x008) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_03 USB_PHY_REG(0x00C) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_04 USB_PHY_REG(0x010) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_05 USB_PHY_REG(0x014) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_06 USB_PHY_REG(0x018) /* read/write */ ++#define REG_USB_PHY_UTMI_STATUS USB_PHY_REG(0x01C) /* read */ ++#define REG_USB_PHY_UTMI_REG_08 USB_PHY_REG(0x020) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_09 USB_PHY_REG(0x024) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_0A USB_PHY_REG(0x028) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_0B USB_PHY_REG(0x02C) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_0C USB_PHY_REG(0x030) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_10 USB_PHY_REG(0x040) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_11 USB_PHY_REG(0x044) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_12 USB_PHY_REG(0x048) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_13 USB_PHY_REG(0x04C) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_14 USB_PHY_REG(0x050) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_15 USB_PHY_REG(0x054) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_16 USB_PHY_REG(0x058) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_17 USB_PHY_REG(0x05C) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_18 USB_PHY_REG(0x060) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_19 USB_PHY_REG(0x064) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_1A USB_PHY_REG(0x068) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_1B USB_PHY_REG(0x06C) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_1C USB_PHY_REG(0x070) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_1D USB_PHY_REG(0x074) /* read/write */ ++#define REG_USB_PHY_UTMI_REG_1E USB_PHY_REG(0x078) /* read/write */ ++ ++#define REG_UTMI_BASE GK_VA_USB_PHY ++#define REG_PLL_POWER_CONTROL (GK_VA_RCT + 0x0050) /* read/write */ ++ ++//#define USB_AHB_W(addr, value) *(volatile unsigned long*)(addr) = (value) ++//#define USB_AHB_R(addr, value) value = *(volatile unsigned long*)(addr) ++#ifdef CONFIG_GK_USB_OTG_MODE ++static int usb_ctrl_init(void); ++#endif ++ ++void GH_PLL_set_POWER_CONTROL_usb(u8 data) ++{ ++ GH_PLL_POWER_CONTROL_S d; ++ d.all = gk_usb_readl(REG_PLL_POWER_CONTROL); ++ //d.all = *(volatile u32 *)REG_PLL_POWER_CONTROL; ++ d.bitc.usb = data; ++ gk_usb_writel(REG_PLL_POWER_CONTROL, d.all); ++ //*(volatile u32 *)REG_PLL_POWER_CONTROL = d.all; ++} ++ ++void GH_USB_PHY_init(void) ++{ ++ gk_usb_writew(REG_USB_PHY_UTMI0, ((u16)0x0000ff05)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_01, ((u16)0x00009080)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_02, ((u16)0x00003000)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_03, ((u16)0x00003020)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_04, ((u16)0x00000483)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_05, ((u16)0x00008044)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_06, ((u16)0x000000c0)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_08, ((u16)0x00000000)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_09, ((u16)0x000000ff)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_0A, ((u16)0x0000000b)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_0B, ((u16)0x00000000)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_0C, ((u16)0x000023cc)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_10, ((u16)0x00000000)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_11, ((u16)0x00000000)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_12, ((u16)0x00000000)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_13, ((u16)0x00000000)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_14, ((u16)0x00000000)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_15, ((u16)0x00000000)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_16, ((u16)0x00000000)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_17, ((u16)0x00000000)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_18, ((u16)0x00000000)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_19, ((u16)0x00000000)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_1A, ((u16)0x00000000)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_1B, ((u16)0x00000001)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_1C, ((u16)0x00002801)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_1D, ((u16)0x00000000)); ++ gk_usb_writew(REG_USB_PHY_UTMI_REG_1E, ((u16)0x00000000)); ++} ++ ++int gk_usb_phy_init(void) ++{ ++ u32 value = 0; ++ struct gk_gpio_io_info usb_gpio_conf; ++ GH_USB_PHY_init(); ++ printk("musb phy Begin initial sequence ...\n"); ++ ++ usb_gpio_conf.gpio_id = gk_all_gpio_cfg.usb_host; ++#if defined(CONFIG_GK_USB_HOST_MODE) ++ usb_gpio_conf.active_level = GPIO_HIGH; ++#elif defined(CONFIG_GK_USB_SLAVE_MODE) ++ usb_gpio_conf.active_level = GPIO_LOW; ++#elif defined(CONFIG_GK_USB_OTG_MODE) ++ usb_gpio_conf.active_level = GPIO_HIGH; ++#endif ++ usb_gpio_conf.active_delay = 1; ++ ++ gk_set_gpio_output(&usb_gpio_conf, 1); ++ mdelay(20);//100ms ++ ++#if defined(CONFIG_GK_MUSB_CON_V1_10) ++ value = gk_usb_readl(GK_VA_AHB_GREG + 0x8); ++ printk(KERN_DEBUG "val=0x%x\n", value); ++ value &= ~0x00000008; //08->disbale handle ++ value |= 0x00000003; //00->burst8 01->burst16 02->burst32 03->burst64 ++ gk_usb_writel((GK_VA_AHB_GREG + 0x8), value); ++ value = gk_usb_readl(GK_VA_AHB_GREG + 0x8); ++#endif ++ //USB_AHB_R(0x70170050, value); ++ //USB_AHB_W(0x70170050, value | 0x02); ++ //PHY reset ++ GH_PLL_set_POWER_CONTROL_usb(1); ++ GH_PLL_set_POWER_CONTROL_usb(0); ++ mdelay(20); ++ GH_PLL_set_POWER_CONTROL_usb(1); ++ mdelay(10); ++ // init phy ++ //init UTMI ++ gk_usb_writel((REG_UTMI_BASE+(0x04<<2)), 0x0000040f); ++ gk_usb_writel((REG_UTMI_BASE+(0x10<<2)), 0x00008051); ++ gk_usb_writel((REG_UTMI_BASE+(0x11<<2)), 0x00005080); ++ gk_usb_writel((REG_UTMI_BASE+(0x11<<2)), 0x00005090); ++ gk_usb_writel((REG_UTMI_BASE+(0x00<<2)), 0x00006bc3); ++ gk_usb_writel((REG_UTMI_BASE+(0x0A<<2)), 0x00003403); ++ mdelay(20); ++ gk_usb_writel((REG_UTMI_BASE+(0x00<<2)), 0x000069c3); ++ mdelay(20); ++ gk_usb_writel((REG_UTMI_BASE+(0x11<<2)), 0x00005080); ++ mdelay(20); ++ gk_usb_writel((REG_UTMI_BASE+(0x00<<2)), 0x00000001); ++ mdelay(20); ++ gk_usb_writel((REG_UTMI_BASE+(0x1e<<2)), 0x00000001); ++ mdelay(20); ++ gk_usb_writel((REG_UTMI_BASE+(0x1e<<2)), 0x00000000); ++ mdelay(20); ++ gk_usb_writel((REG_UTMI_BASE+(0x03<<2)), 0x00000023); ++ mdelay(20); ++ gk_usb_writel((REG_UTMI_BASE+(0x03<<2)), 0x00000020); ++ gk_usb_writel((REG_UTMI_BASE+(0x0a<<2)), 0x00000003); ++#if defined(CONFIG_GK_USB_HOST_MODE) ++ gk_usb_writel((REG_UTMI_BASE+(0x0a<<2)), 0x00000103); ++#elif defined(CONFIG_GK_USB_OTG_MODE) ++ if (!gk_gpio_get(CONFIG_GK_USB_OTG_GPIO)) ++ { ++ gk_usb_writel((REG_UTMI_BASE+(0x0a<<2)), 0x00000103); ++ } ++ else ++ { ++ gk_usb_writel((REG_UTMI_BASE+(0x0a<<2)), 0x0000010B); ++ } ++#elif defined(CONFIG_GK_USB_SLAVE_MODE) ++ gk_usb_writel((REG_UTMI_BASE+(0x0a<<2)), 0x0000010B); ++#endif ++ mdelay(10); ++ ++ mdelay(20); ++ gk_usb_writel((REG_UTMI_BASE+(0x03<<2)), 0x00000023); ++ mdelay(20); ++ gk_usb_writel((REG_UTMI_BASE+(0x03<<2)), 0x00000020); ++ mdelay(20); ++ ++ //reset USB controller ++ gk_rct_writel(GK_VA_RCT + 0x0088, 0x6CC36011); ++ mdelay(20); ++ gk_rct_writel(GK_VA_RCT + 0x0088, 0x4CC36011); ++ mdelay(20); ++ ++ return 0; ++} ++ ++ ++/*************************************************************************/ ++ ++static void gk_musb_enable(struct musb *musb) ++{ ++ ++} ++ ++static void gk_musb_disable(struct musb *musb) ++{ ++ void __iomem *pBase = musb->ctrl_base; ++ ++ gk_musb_writew((unsigned int)pBase, 0x06, 0x00); ++ gk_musb_writew((unsigned int)pBase, 0x08, 0x00); ++ gk_musb_writeb((unsigned int)pBase, 0x0B, 0x00); ++} ++ ++static int gk_musb_set_mode(struct musb *musb, u8 musb_mode) ++{ ++ return 0; ++} ++ ++static void gk_musb_try_idle(struct musb *musb, unsigned long timeout) ++{ ++ ++} ++ ++/* ++ * Updates cable VBUS status. Caller must take care of locking. ++ */ ++static int gk_musb_vbus_status(struct musb *musb) ++{ ++ int ret = 0; ++ ++ ++ return ret; ++} ++ ++static void gk_musb_set_vbus(struct musb *musb, int is_on) ++{ ++ ++} ++ ++static void musb_do_idle(unsigned long _musb) ++{ ++ ++} ++ ++ ++static int gk_musb_init(struct musb *musb) ++{ ++ struct platform_device *pdev; ++ ++ usb_nop_xceiv_register(); ++ musb->xceiv = usb_get_transceiver(); ++ //printk("musb xceiv = 0x%x \n", (uint32_t)musb->xceiv); ++ if (!musb->xceiv) ++ return -ENODEV; ++ ++ ++ //musb->isr = gk_musb_interrupt; ++ ++ pdev = to_platform_device(musb->controller); ++ ++ setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); ++ ++ printk("gk musb init end...\n"); ++ ++ return 0; ++} ++ ++static int gk_musb_exit(struct musb *musb) ++{ ++ del_timer_sync(&musb_idle_timer); ++ the_musb = NULL; ++ ++ if (musb->board_set_power) ++ musb->board_set_power(0); ++ ++ usb_put_transceiver(musb->xceiv); ++ usb_nop_xceiv_unregister(); ++ return 0; ++} ++ ++static const struct musb_platform_ops gk_ops = { ++ .init = gk_musb_init, ++ .exit = gk_musb_exit, ++ ++ .enable = gk_musb_enable, ++ .disable = gk_musb_disable, ++ ++ .set_mode = gk_musb_set_mode, ++ .try_idle = gk_musb_try_idle, ++ ++ .vbus_status= gk_musb_vbus_status, ++ .set_vbus = gk_musb_set_vbus, ++}; ++ ++static int gk_probe(struct platform_device *pdev) ++{ ++ int ret = -ENOMEM; ++ struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; ++ struct platform_device *musb; ++ struct gk_glue *glue; ++ ++ gk_usb_phy_init(); ++ glue = kzalloc(sizeof(*glue), GFP_KERNEL); ++ if (!glue) { ++ dev_err(&pdev->dev, "failed to allocate glue context\n"); ++ goto err0; ++ } ++ ++ musb = platform_device_alloc("musb-hdrc", -1); ++ if (!musb) { ++ dev_err(&pdev->dev, "failed to allocate musb device\n"); ++ goto err1; ++ } ++ ++ musb->dev.parent = &pdev->dev; ++ musb->dev.dma_mask = &gk_dmamask; ++ musb->dev.coherent_dma_mask = gk_dmamask; ++ ++ glue->dev = &pdev->dev; ++ glue->musb = musb; ++ ++ pdata->platform_ops = &gk_ops; ++ ++ platform_set_drvdata(pdev, glue); ++ ++ ret = platform_device_add_resources(musb, pdev->resource, ++ pdev->num_resources); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to add resources\n"); ++ goto err2; ++ } ++ ++ ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to add platform_data\n"); ++ goto err2; ++ } ++ ++ ret = platform_device_add(musb); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register musb device\n"); ++ goto err1; ++ } ++ printk("platform add gk musb...\n"); ++ ++ ++ return 0; ++ ++err2: ++ platform_device_put(musb); ++ ++err1: ++ kfree(glue); ++ ++err0: ++ return ret; ++} ++ ++static int gk_remove(struct platform_device *pdev) ++{ ++ struct gk_glue *glue = platform_get_drvdata(pdev); ++ ++ platform_device_del(glue->musb); ++ platform_device_put(glue->musb); ++ pdev->resource[0].parent = NULL; ++ pdev->resource[0].sibling = NULL; ++ pdev->resource[0].child = NULL; ++ pdev->resource[1].parent = NULL; ++ pdev->resource[1].sibling = NULL; ++ pdev->resource[1].child = NULL; ++ kfree(glue); ++ ++ return 0; ++} ++ ++static struct platform_driver gk_driver = { ++ .probe = gk_probe, ++ .remove = gk_remove, ++ .driver = { ++ .name = "musb-gk", ++ }, ++}; ++ ++static int __init gk_init(void) ++{ ++#ifdef CONFIG_GK_USB_OTG_MODE ++ usb_ctrl_init(); ++#endif ++ return platform_driver_register(&gk_driver); ++} ++module_init(gk_init); ++ ++static void __exit gk_exit(void) ++{ ++ platform_driver_unregister(&gk_driver); ++} ++module_exit(gk_exit); ++ ++#ifdef CONFIG_GK_USB_OTG_MODE ++static struct semaphore sema_usb_ctrl; ++static u32 usb_ctrl_mode; ++extern void set_usb_unregister(void); ++extern void set_usb_master(void); ++extern void set_usb_slave(void); ++ ++void set_usb_phy_unregister(void) ++{ ++ platform_driver_unregister(&gk_driver); ++} ++EXPORT_SYMBOL(set_usb_phy_unregister); ++ ++void set_usb_phy_master(void) ++{ ++ struct gk_gpio_io_info usb_gpio_conf; ++ usb_gpio_conf.gpio_id = gk_all_gpio_cfg.usb_host; ++ usb_gpio_conf.active_level = GPIO_HIGH; ++ usb_gpio_conf.active_delay = 1; ++ ++ gk_set_gpio_output(&usb_gpio_conf, 1); ++ ++ mdelay(10); ++ ++ platform_driver_register(&gk_driver); ++ ++} ++EXPORT_SYMBOL(set_usb_phy_master); ++ ++void set_usb_phy_slave(void) ++{ ++ struct gk_gpio_io_info usb_gpio_conf; ++ usb_gpio_conf.gpio_id = gk_all_gpio_cfg.usb_host; ++ usb_gpio_conf.active_level = GPIO_LOW; ++ usb_gpio_conf.active_delay = 1; ++ ++ gk_set_gpio_output(&usb_gpio_conf, 1); ++ ++ mdelay(10); ++ ++ platform_driver_register(&gk_driver); ++} ++ ++EXPORT_SYMBOL(set_usb_phy_slave); ++ ++static irqreturn_t usb_ctrl_irq_handle(int irq, void *dummy) ++{ ++ printk("usb_ctrl_irq_handle\n"); ++ printk("irq : %d\n", gk_gpio_get(CONFIG_GK_USB_OTG_GPIO)); ++ ++ if (gk_gpio_get(CONFIG_GK_USB_OTG_GPIO)) ++ { ++ usb_ctrl_mode = 1; ++ } ++ else ++ { ++ usb_ctrl_mode = 0; ++ } ++ ++ mdelay(1); ++ ++ up(&sema_usb_ctrl); ++} ++ ++static void usb_ctrl_task(struct task_struct *p) ++{ ++ while(1) ++ { ++ down(&sema_usb_ctrl); ++ if (usb_ctrl_mode == 1) ++ { ++ printk("usb entry slave mode\n"); ++ set_usb_unregister(); ++ set_usb_phy_unregister(); ++ ++ set_usb_phy_slave(); ++ set_usb_slave(); ++ } ++ else ++ { ++ printk("usb entry master mode\n"); ++ set_usb_unregister(); ++ set_usb_phy_unregister(); ++ ++ set_usb_phy_master(); ++ set_usb_master(); ++ } ++ } ++} ++ ++static int usb_ctrl_init(void) ++{ ++ static struct gk_gpio_irq_info usb_ctrl_irq; ++#if 0 ++ static struct gk_gpio_io_info usb_ctrl_io; ++ usb_ctrl_io.gpio_id = CONFIG_GK_USB_OTG_GPIO; ++ usb_ctrl_io.active_level = 1; ++ usb_ctrl_io.active_delay = 10; ++ ++ printk("GPIO%d : %d\n", CONFIG_GK_USB_OTG_GPIO, gk_get_gpio_input(&usb_ctrl_io)); ++#endif ++ ++ usb_ctrl_irq.pin = CONFIG_GK_USB_OTG_GPIO; ++ usb_ctrl_irq.type = IRQ_TYPE_EDGE_BOTH; ++ usb_ctrl_irq.handler = usb_ctrl_irq_handle; ++ ++ sema_init(&sema_usb_ctrl, 0); ++ if (gk_gpio_get(CONFIG_GK_USB_OTG_GPIO)) ++ { ++ usb_ctrl_mode = 1; ++ } ++ else ++ { ++ usb_ctrl_mode = 0; ++ } ++ ++ kernel_thread(usb_ctrl_task, NULL, 0); ++ gk_gpio_request_irq(&usb_ctrl_irq); ++} ++#endif ++ ++MODULE_DESCRIPTION("GOKE MUSB driver"); ++MODULE_AUTHOR("Goke Microelectronics Inc."); ++MODULE_LICENSE("GPL v2"); ++ +diff --git a/drivers/usb/musb/gk_usb.h b/drivers/usb/musb/gk_usb.h +new file mode 100644 +index 00000000..84469718 +--- /dev/null ++++ b/drivers/usb/musb/gk_usb.h +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (C) 2015 by GOKE LIMITED ++ * ++ * The Inventra Controller Driver for Linux is free software; you ++ * can redistribute it and/or modify it under the terms of the GNU ++ * General Public License version 2 as published by the Free Software ++ * Foundation. ++ */ ++ ++#ifndef __GK_USB_H__ ++#define __GK_USB_H__ ++ ++#include ++ ++ ++typedef union { /* PLL_POWER_CONTROL */ ++ u32 all; ++ struct { ++ u32 unkown1 : 1; ++ u32 usb : 1; ++ u32 unkown2 : 30; ++ } bitc; ++} GH_PLL_POWER_CONTROL_S; ++ ++ ++ ++int gk_usb_phy_init(void); ++ ++ ++ ++#endif /* __GK_USB_H__ */ +diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c +index a2b4008d..71eb2feb 100644 +--- a/drivers/usb/musb/musb_core.c ++++ b/drivers/usb/musb/musb_core.c +@@ -100,6 +100,8 @@ + #include + #include + ++#include ++ + #include "musb_core.h" + + #define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON) +@@ -226,84 +228,50 @@ static struct usb_phy_io_ops musb_ulpi_access = { + + #if !defined(CONFIG_USB_MUSB_TUSB6010) && !defined(CONFIG_USB_MUSB_BLACKFIN) + ++u32 get_epnum_from_fifo(u32 fifo) ++{ ++ return (fifo-GK_VA_USB-0x400)/MUSB_FIFO_EP_OFFSET; ++} ++ + /* + * Load an endpoint's FIFO + */ + void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) + { +- struct musb *musb = hw_ep->musb; ++ //struct musb *musb = hw_ep->musb; + void __iomem *fifo = hw_ep->fifo; ++ int i; ++ u32 fifo_addr; + +- prefetch((u8 *)src); +- +- dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n", +- 'T', hw_ep->epnum, fifo, len, src); +- +- /* we can't assume unaligned reads work */ +- if (likely((0x01 & (unsigned long) src) == 0)) { +- u16 index = 0; +- +- /* best case is 32bit-aligned source address */ +- if ((0x02 & (unsigned long) src) == 0) { +- if (len >= 4) { +- writesl(fifo, src + index, len >> 2); +- index += len & ~0x03; +- } +- if (len & 0x02) { +- musb_writew(fifo, 0, *(u16 *)&src[index]); +- index += 2; +- } +- } else { +- if (len >= 2) { +- writesw(fifo, src + index, len >> 1); +- index += len & ~0x01; +- } +- } +- if (len & 0x01) +- musb_writeb(fifo, 0, src[index]); +- } else { +- /* byte aligned */ +- writesb(fifo, src, len); ++ fifo_addr = get_epnum_from_fifo((u32)fifo)*4+0x20+GK_VA_USB; ++ fifo = (void __iomem *)fifo_addr; ++ for (i = 0; i < len; i++) { ++ musb_writeb(fifo, 0, src[i]); + } + } + ++ + #if !defined(CONFIG_USB_MUSB_AM35X) + /* + * Unload an endpoint's FIFO + */ + void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) + { +- struct musb *musb = hw_ep->musb; ++ //struct musb *musb = hw_ep->musb; + void __iomem *fifo = hw_ep->fifo; + +- dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n", +- 'R', hw_ep->epnum, fifo, len, dst); ++ //printk("%cX ep%d fifo %p count %d buf %p\n", ++ // 'R', hw_ep->epnum, fifo, len, dst); + +- /* we can't assume unaligned writes work */ +- if (likely((0x01 & (unsigned long) dst) == 0)) { +- u16 index = 0; ++ int i; ++ u32 fifo_addr; + +- /* best case is 32bit-aligned destination address */ +- if ((0x02 & (unsigned long) dst) == 0) { +- if (len >= 4) { +- readsl(fifo, dst, len >> 2); +- index = len & ~0x03; +- } +- if (len & 0x02) { +- *(u16 *)&dst[index] = musb_readw(fifo, 0); +- index += 2; +- } +- } else { +- if (len >= 2) { +- readsw(fifo, dst, len >> 1); +- index = len & ~0x01; +- } +- } +- if (len & 0x01) +- dst[index] = musb_readb(fifo, 0); +- } else { +- /* byte aligned */ +- readsb(fifo, dst, len); ++ fifo_addr = get_epnum_from_fifo((u32)fifo)*4+0x20+GK_VA_USB; ++ ++ fifo=(void __iomem *)fifo_addr; ++ ++ for (i = 0; i < len; i++) { ++ dst[i] = musb_readb(fifo, 0); + } + } + #endif +@@ -1497,7 +1465,8 @@ static int __devinit musb_core_init(u16 musb_type, struct musb *musb) + /*-------------------------------------------------------------------------*/ + + #if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \ +- defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500) ++ defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500) || \ ++ defined(CONFIG_GK_MUSB) + + static irqreturn_t generic_interrupt(int irq, void *__hci) + { +@@ -1544,24 +1513,39 @@ irqreturn_t musb_interrupt(struct musb *musb) + (devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral", + musb->int_usb, musb->int_tx, musb->int_rx); + +- /* the core can interrupt us for multiple reasons; docs have +- * a generic interrupt flowchart to follow ++ /** ++ * According to Mentor Graphics' documentation, flowchart on page 98, ++ * IRQ should be handled as follows: ++ * ++ * . Resume IRQ ++ * . Session Request IRQ ++ * . VBUS Error IRQ ++ * . Suspend IRQ ++ * . Connect IRQ ++ * . Disconnect IRQ ++ * . Reset/Babble IRQ ++ * . SOF IRQ (we're not using this one) ++ * . Endpoint 0 IRQ ++ * . TX Endpoints ++ * . RX Endpoints ++ * ++ * We will be following that flowchart in order to avoid any problems ++ * that might arise with internal Finite State Machine. + */ ++ + if (musb->int_usb) + retval |= musb_stage0_irq(musb, musb->int_usb, + devctl, power); + +- /* "stage 1" is handling endpoint irqs */ +- +- /* handle endpoint 0 first */ + if (musb->int_tx & 1) { +- if (devctl & MUSB_DEVCTL_HM) ++ if (is_host_active(musb)) + retval |= musb_h_ep0_irq(musb); + else + retval |= musb_g_ep0_irq(musb); + } + +- /* RX on endpoints 1-15 */ ++ ++ /* RX on endpoints 1-15 */ + reg = musb->int_rx >> 1; + ep_num = 1; + while (reg) { +@@ -1569,12 +1553,14 @@ irqreturn_t musb_interrupt(struct musb *musb) + /* musb_ep_select(musb->mregs, ep_num); */ + /* REVISIT just retval = ep->rx_irq(...) */ + retval = IRQ_HANDLED; +- if (devctl & MUSB_DEVCTL_HM) { +- if (is_host_capable()) +- musb_host_rx(musb, ep_num); +- } else { +- if (is_peripheral_capable()) +- musb_g_rx(musb, ep_num); ++ if (is_host_active(musb)) ++ { ++ //printk("IM,R\n"); ++ musb_host_rx(musb, ep_num); ++ } ++ else ++ { ++ musb_g_rx(musb, ep_num); + } + } + +@@ -1582,20 +1568,23 @@ irqreturn_t musb_interrupt(struct musb *musb) + ep_num++; + } + +- /* TX on endpoints 1-15 */ +- reg = musb->int_tx >> 1; +- ep_num = 1; ++ ++/* TX on endpoints 1-15 */ ++ reg = musb->int_tx >> 1; ++ ep_num = 1; + while (reg) { + if (reg & 1) { + /* musb_ep_select(musb->mregs, ep_num); */ + /* REVISIT just retval |= ep->tx_irq(...) */ + retval = IRQ_HANDLED; +- if (devctl & MUSB_DEVCTL_HM) { +- if (is_host_capable()) +- musb_host_tx(musb, ep_num); +- } else { +- if (is_peripheral_capable()) +- musb_g_tx(musb, ep_num); ++ if (is_host_active(musb)) ++ { ++ //printk(" IM,T\n"); ++ musb_host_tx(musb, ep_num); ++ } ++ else ++ { ++ musb_g_tx(musb, ep_num); + } + } + reg >>= 1; +@@ -1642,6 +1631,7 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit) + } else { + /* receive */ + if (devctl & MUSB_DEVCTL_HM) { ++ //printk("rxdmaint\n"); + if (is_host_capable()) + musb_host_rx(musb, epnum); + } else { +@@ -1860,9 +1850,13 @@ static void musb_free(struct musb *musb) + dma_controller_destroy(c); + } + +- kfree(musb); ++ // use usb_put_hcd replace kfree(musb) ++ usb_put_hcd(musb_to_hcd(musb)); ++ printk("musb_free\n"); ++ //kfree(musb); + } + ++ + /* + * Perform generic per-controller initialization. + * +@@ -1899,7 +1893,20 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) + pm_runtime_enable(musb->controller); + + spin_lock_init(&musb->lock); +- musb->board_mode = plat->mode; ++ ++#if defined(CONFIG_GK_USB_OTG_MODE) ++ if (!gk_gpio_get(CONFIG_GK_USB_OTG_GPIO)) ++ { ++ musb->board_mode = MUSB_HOST; ++ } ++ else ++ { ++ musb->board_mode = MUSB_PERIPHERAL; ++ } ++#else ++ musb->board_mode = plat->mode; ++#endif ++ + musb->board_set_power = plat->set_power; + musb->min_power = plat->min_power; + musb->ops = plat->platform_ops; +@@ -1937,7 +1944,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) + if (use_dma && dev->dma_mask) { + struct dma_controller *c; + +- c = dma_controller_create(musb, musb->mregs); ++ c = dma_controller_create_non_init(musb, musb->mregs); + musb->dma_controller = c; + if (c) + (void) c->start(c); +@@ -1964,7 +1971,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) + INIT_WORK(&musb->irq_work, musb_irq_work); + + /* attach to the IRQ */ +- if (request_irq(nIrq, musb->isr, 0, dev_name(dev), musb)) { ++ if (request_irq(nIrq, musb->isr, IRQF_SHARED | IRQF_TRIGGER_HIGH, dev_name(dev), musb)) { + dev_err(dev, "request_irq %d failed!\n", nIrq); + status = -ENODEV; + goto fail3; +@@ -1997,6 +2004,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) + } + } + ++ + /* For the host-only role, we can activate right away. + * (We expect the ID pin to be forcibly grounded!!) + * Otherwise, wait till the gadget driver hooks up. +@@ -2110,28 +2118,32 @@ static int __devinit musb_probe(struct platform_device *pdev) + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!iomem || irq <= 0) + return -ENODEV; +- ++#if 0 + base = ioremap(iomem->start, resource_size(iomem)); + if (!base) { + dev_err(dev, "ioremap failed\n"); + return -ENOMEM; + } ++#else ++ base = (void __iomem *)iomem->start; ++#endif + + #ifndef CONFIG_MUSB_PIO_ONLY + /* clobbered by use_dma=n */ + orig_dma_mask = dev->dma_mask; + #endif + status = musb_init_controller(dev, irq, base); ++#if 0 + if (status < 0) + iounmap(base); +- ++#endif + return status; + } + + static int __devexit musb_remove(struct platform_device *pdev) + { + struct musb *musb = dev_to_musb(&pdev->dev); +- void __iomem *ctrl_base = musb->ctrl_base; ++ //void __iomem *ctrl_base = musb->ctrl_base; + + /* this gets called on rmmod. + * - Host mode: host may still be active +@@ -2142,7 +2154,7 @@ static int __devexit musb_remove(struct platform_device *pdev) + musb_shutdown(pdev); + + musb_free(musb); +- iounmap(ctrl_base); ++ //iounmap(ctrl_base); + device_init_wakeup(&pdev->dev, 0); + #ifndef CONFIG_MUSB_PIO_ONLY + pdev->dev.dma_mask = orig_dma_mask; +@@ -2411,3 +2423,28 @@ static void __exit musb_cleanup(void) + platform_driver_unregister(&musb_driver); + } + module_exit(musb_cleanup); ++ ++#ifdef CONFIG_GK_USB_OTG_MODE ++void set_usb_unregister(void) ++{ ++ platform_driver_unregister(&musb_driver); ++} ++EXPORT_SYMBOL(set_usb_unregister); ++ ++void set_usb_master(void) ++{ ++ platform_driver_register(&musb_driver); ++ ++ mdelay(10); ++} ++EXPORT_SYMBOL(set_usb_master); ++ ++void set_usb_slave(void) ++{ ++ platform_driver_register(&musb_driver); ++ ++ mdelay(10); ++} ++EXPORT_SYMBOL(set_usb_slave); ++#endif ++ +diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h +index f4a40f00..95f06fea 100644 +--- a/drivers/usb/musb/musb_core.h ++++ b/drivers/usb/musb/musb_core.h +@@ -517,6 +517,7 @@ static inline int musb_read_fifosize(struct musb *musb, + hw_ep->max_packet_sz_rx = 1 << ((reg & 0xf0) >> 4); + hw_ep->is_shared_fifo = false; + } ++ //printk("epnum %d tx %d rx %d\n",epnum,hw_ep->max_packet_sz_tx ,hw_ep->max_packet_sz_rx); + + return 0; + } +diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h +index 3a97c4e2..2b8c0d45 100644 +--- a/drivers/usb/musb/musb_dma.h ++++ b/drivers/usb/musb/musb_dma.h +@@ -129,6 +129,8 @@ struct dma_channel { + size_t actual_len; + enum dma_channel_status status; + bool desired_mode; ++ ++ struct musb_hw_ep *hw_ep; + }; + + /* +@@ -181,6 +183,9 @@ extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit); + extern struct dma_controller *__init + dma_controller_create(struct musb *, void __iomem *); + ++extern struct dma_controller * ++dma_controller_create_non_init(struct musb *musb, void __iomem *base); ++ + extern void dma_controller_destroy(struct dma_controller *); + + #endif /* __MUSB_DMA_H__ */ +diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c +index 95918dac..04e34520 100644 +--- a/drivers/usb/musb/musb_gadget.c ++++ b/drivers/usb/musb/musb_gadget.c +@@ -244,8 +244,9 @@ static void nuke(struct musb_ep *ep, const int status) + musb_writew(epio, MUSB_RXCSR, + 0 | MUSB_RXCSR_FLUSHFIFO); + } +- ++#if defined(CONFIG_GK_MUSB_CON_V1_10) + value = c->channel_abort(ep->dma); ++#endif + dev_dbg(musb->controller, "%s: abort DMA --> %d\n", + ep->name, value); + c->channel_release(ep->dma); +@@ -358,29 +359,65 @@ static void txstate(struct musb *musb, struct musb_request *req) + csr); + + #ifndef CONFIG_MUSB_PIO_ONLY +- if (is_buffer_mapped(req)) { ++ if ((is_buffer_mapped(req))&&(request->length>=max_ep_writesize(musb, musb_ep))) { + struct dma_controller *c = musb->dma_controller; +- size_t request_size; +- +- /* setup DMA, then program endpoint CSR */ +- request_size = min_t(size_t, request->length - request->actual, +- musb_ep->dma->max_len); +- ++ size_t request_size = 0; ++ ++ if((request->length - request->actual>=musb_ep->packet_sz) ++ &&(musb_ep->type!=USB_ENDPOINT_XFER_ISOC)) ++ { ++#if defined(CONFIG_GK_MUSB_CON_V1_10) ++ musb_ep->dma->desired_mode = 1; ++#elif defined(CONFIG_GK_MUSB_CON_V1_00) ++ musb_ep->dma->desired_mode = 0; ++#endif ++ } ++ else ++ { ++ musb_ep->dma->desired_mode = 0; ++ //printk("mod=0\n"); ++ } ++ if(musb_ep->dma->desired_mode == 0) ++ { ++ request_size = min(request->length - request->actual,(unsigned)musb_ep->packet_sz); ++ } ++ else ++ { ++ request_size = min(request->length - request->actual, ++ musb_ep->dma->max_len); ++ } + use_dma = (request->dma != DMA_ADDR_INVALID); + + /* MUSB_TXCSR_P_ISO is still set correctly */ + + #if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) + { +- if (request_size < musb_ep->packet_sz) +- musb_ep->dma->desired_mode = 0; ++ u16 csr_tx; ++ csr_tx = musb_readw(epio, MUSB_TXCSR); ++ if (musb_ep->dma->desired_mode==0) ++ { ++ //musb_ep->dma->desired_mode = 0; ++ csr_tx &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE); ++ csr_tx |= MUSB_TXCSR_DMAENAB; /* against programmer's guide */ ++ } + else +- musb_ep->dma->desired_mode = 1; +- +- use_dma = use_dma && c->channel_program( ++ { ++ //musb_ep->dma->desired_mode = 1; ++ //printk("lsk:csr_tx=0x%x\n",csr_tx); ++ //csr_tx &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); ++ csr_tx |= MUSB_TXCSR_AUTOSET; ++ csr_tx &=~MUSB_TXCSR_DMAENAB; ++ musb_writew(epio, MUSB_TXCSR, csr_tx); ++ csr_tx |= MUSB_TXCSR_DMAMODE; ++ musb_writew(epio, MUSB_TXCSR, csr_tx); ++ csr_tx |= MUSB_TXCSR_DMAENAB; ++ } ++ musb_writew(epio, MUSB_TXCSR, csr_tx); ++ use_dma = use_dma && musb_ep->dma && c->channel_program( + musb_ep->dma, musb_ep->packet_sz, + musb_ep->dma->desired_mode, + request->dma + request->actual, request_size); ++#if 0 + if (use_dma) { + if (musb_ep->dma->desired_mode == 0) { + /* +@@ -401,6 +438,15 @@ static void txstate(struct musb *musb, struct musb_request *req) + csr |= (MUSB_TXCSR_DMAENAB + | MUSB_TXCSR_DMAMODE + | MUSB_TXCSR_MODE); ++ /* ++ * Enable Autoset according to table ++ * below ++ * bulk_split hb_mult Autoset_Enable ++ * 0 0 Yes(Normal) ++ * 0 >0 No(High BW ISO) ++ * 1 0 Yes(HS bulk) ++ * 1 >0 Yes(FS bulk) ++ */ + if (!musb_ep->hb_mult) + csr |= MUSB_TXCSR_AUTOSET; + } +@@ -408,6 +454,7 @@ static void txstate(struct musb *musb, struct musb_request *req) + + musb_writew(epio, MUSB_TXCSR, csr); + } ++#endif + } + + #elif defined(CONFIG_USB_TI_CPPI_DMA) +@@ -463,7 +510,11 @@ static void txstate(struct musb *musb, struct musb_request *req) + + musb_write_fifo(musb_ep->hw_ep, fifo_count, + (u8 *) (request->buf + request->actual)); ++#if defined(CONFIG_USB_INVENTRA_DMA) ++ musb_ep->dma->actual_len=fifo_count; ++#else + request->actual += fifo_count; ++#endif + csr |= MUSB_TXCSR_TXPKTRDY; + csr &= ~MUSB_TXCSR_P_UNDERRUN; + musb_writew(epio, MUSB_TXCSR, csr); +@@ -532,15 +583,15 @@ void musb_g_tx(struct musb *musb, u8 epnum) + + if (request) { + u8 is_dma = 0; +- +- if (dma && (csr & MUSB_TXCSR_DMAENAB)) { ++ //if (dma && (csr & MUSB_TXCSR_DMAENAB)) { ++ if (dma) { + is_dma = 1; +- csr |= MUSB_TXCSR_P_WZC_BITS; +- csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN | +- MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_AUTOSET); +- musb_writew(epio, MUSB_TXCSR, csr); ++ //csr |= MUSB_TXCSR_P_WZC_BITS; ++ //csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN | ++ // MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_AUTOSET); ++ //musb_writew(epio, MUSB_TXCSR, csr); + /* Ensure writebuffer is empty. */ +- csr = musb_readw(epio, MUSB_TXCSR); ++ //csr = musb_readw(epio, MUSB_TXCSR); + request->actual += musb_ep->dma->actual_len; + dev_dbg(musb->controller, "TXCSR%d %04x, DMA off, len %zu, req %p\n", + epnum, csr, musb_ep->dma->actual_len, request); +@@ -550,6 +601,7 @@ void musb_g_tx(struct musb *musb, u8 epnum) + * First, maybe a terminating short packet. Some DMA + * engines might handle this by themselves. + */ ++#if 0 + if ((request->zero && request->length + && (request->length % musb_ep->packet_sz == 0) + && (request->actual == request->length)) +@@ -571,7 +623,7 @@ void musb_g_tx(struct musb *musb, u8 epnum) + | MUSB_TXCSR_TXPKTRDY); + request->zero = 0; + } +- ++#endif + if (request->actual == request->length) { + musb_g_giveback(musb_ep, request, 0); + /* +@@ -649,13 +701,13 @@ static void rxstate(struct musb *musb, struct musb_request *req) + musb_ep = &hw_ep->ep_out; + + len = musb_ep->packet_sz; +- ++#if defined(CONFIG_GK_MUSB_CON_V1_10) + /* We shouldn't get here while DMA is active, but we do... */ + if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) { + dev_dbg(musb->controller, "DMA pending...\n"); + return; + } +- ++#endif + if (csr & MUSB_RXCSR_P_SENDSTALL) { + dev_dbg(musb->controller, "%s stalling, RXCSR %04x\n", + musb_ep->end_point.name, csr); +@@ -697,13 +749,23 @@ static void rxstate(struct musb *musb, struct musb_request *req) + * is set. Currently short_not_ok flag is set only from + * file_storage and f_mass_storage drivers + */ +- +- if (request->short_not_ok && len == musb_ep->packet_sz) ++ //if (request->short_not_ok && len == musb_ep->packet_sz) ++ if((len == musb_ep->packet_sz) ++ &&(request->actual+musb_ep->packet_sz<=request->length) ++ &&(musb_ep->type!=USB_ENDPOINT_XFER_ISOC)) ++ { ++#if defined(CONFIG_GK_MUSB_CON_V1_10) + use_mode_1 = 1; ++#elif defined(CONFIG_GK_MUSB_CON_V1_00) ++ use_mode_1 = 0; ++#endif ++ } + else + use_mode_1 = 0; + + if (request->actual < request->length) { ++ ++#if defined(CONFIG_GK_MUSB_CON_V1_10) + #ifdef CONFIG_USB_INVENTRA_DMA + if (is_buffer_mapped(req)) { + struct dma_controller *c; +@@ -712,7 +774,6 @@ static void rxstate(struct musb *musb, struct musb_request *req) + + c = musb->dma_controller; + channel = musb_ep->dma; +- + /* We use DMA Req mode 0 in rx_csr, and DMA controller operates in + * mode 0 only. So we do not get endpoint interrupts due to DMA + * completion. We only get interrupts from DMA controller. +@@ -748,14 +809,17 @@ static void rxstate(struct musb *musb, struct musb_request *req) + */ + musb_writew(epio, MUSB_RXCSR, + csr | MUSB_RXCSR_DMAMODE); +- musb_writew(epio, MUSB_RXCSR, csr); ++ //musb_writew(epio, MUSB_RXCSR, csr); + + } else { + if (!musb_ep->hb_mult && + musb_ep->hw_ep->rx_double_buffered) + csr |= MUSB_RXCSR_AUTOCLEAR; +- csr |= MUSB_RXCSR_DMAENAB; ++ csr &= ~MUSB_RXCSR_DMAENAB; ++ csr &= ~MUSB_RXCSR_DMAMODE; + musb_writew(epio, MUSB_RXCSR, csr); ++ csr |= MUSB_RXCSR_DMAENAB; ++ musb_writew(epio, MUSB_RXCSR, csr); + } + + if (request->actual < request->length) { +@@ -830,7 +894,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) + return; + } + #endif /* Mentor's DMA */ +- ++#endif + fifo_count = request->length - request->actual; + dev_dbg(musb->controller, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n", + musb_ep->end_point.name, +@@ -920,7 +984,10 @@ void musb_g_rx(struct musb *musb, u8 epnum) + + csr = musb_readw(epio, MUSB_RXCSR); + dma = is_dma_capable() ? musb_ep->dma : NULL; +- ++ // for gk7101 ++#if defined(CONFIG_GK_MUSB_CON_V1_00) ++ dma = NULL; ++#endif + dev_dbg(musb->controller, "<== %s, rxcsr %04x%s %p\n", musb_ep->end_point.name, + csr, dma ? " (dma)" : "", request); + +@@ -944,14 +1011,14 @@ void musb_g_rx(struct musb *musb, u8 epnum) + /* REVISIT not necessarily an error */ + dev_dbg(musb->controller, "%s, incomprx\n", musb_ep->end_point.name); + } +- ++#if defined(CONFIG_GK_MUSB_CON_V1_10) + if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { + /* "should not happen"; likely RXPKTRDY pending for DMA */ + dev_dbg(musb->controller, "%s busy, csr %04x\n", + musb_ep->end_point.name, csr); + return; + } +- ++#endif + if (dma && (csr & MUSB_RXCSR_DMAENAB)) { + csr &= ~(MUSB_RXCSR_AUTOCLEAR + | MUSB_RXCSR_DMAENAB +@@ -1100,11 +1167,15 @@ static int musb_gadget_enable(struct usb_ep *ep, + /* Set TXMAXP with the FIFO size of the endpoint + * to disable double buffering mode. + */ +- if (musb->double_buffer_not_ok) ++ if (musb->double_buffer_not_ok) { + musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx); +- else ++ } else { ++ //if (can_bulk_split(musb, musb_ep->type)) ++ //musb_ep->hb_mult = (hw_ep->max_packet_sz_tx / ++ //musb_ep->packet_sz) - 1; + musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz + | (musb_ep->hb_mult << 11)); ++ } + + csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG; + if (musb_readw(regs, MUSB_TXCSR) +@@ -1167,12 +1238,24 @@ static int musb_gadget_enable(struct usb_ep *ep, + /* NOTE: all the I/O code _should_ work fine without DMA, in case + * for some reason you run out of channels here. + */ +- if (is_dma_capable() && musb->dma_controller) { +- struct dma_controller *c = musb->dma_controller; +- +- musb_ep->dma = c->channel_alloc(c, hw_ep, +- (desc->bEndpointAddress & USB_DIR_IN)); +- } else ++#if defined(CONFIG_GK_MUSB_CON_V1_00) ++ if(usb_endpoint_dir_in(desc)) ++#elif defined(CONFIG_GK_MUSB_CON_V1_10) ++ if(1) ++#endif ++ { ++ if (is_dma_capable() && musb->dma_controller) { ++ struct dma_controller *c = musb->dma_controller; ++ ++ musb_ep->dma = c->channel_alloc(c, hw_ep, ++ usb_endpoint_dir_in(desc)); ++ if (usb_endpoint_dir_in(desc)) ++ hw_ep->tx_channel = musb_ep->dma; ++ else ++ hw_ep->rx_channel = musb_ep->dma; ++ musb_ep->dma->hw_ep = hw_ep; ++ } ++ }else + musb_ep->dma = NULL; + + musb_ep->desc = desc; +@@ -1834,12 +1917,12 @@ static inline void __devinit musb_g_init_endpoints(struct musb *musb) + init_peripheral_ep(musb, &hw_ep->ep_in, epnum, 0); + count++; + } else { +- if (hw_ep->max_packet_sz_tx) { ++ if ((epnum&0x01)&&(hw_ep->max_packet_sz_tx)) { + init_peripheral_ep(musb, &hw_ep->ep_in, + epnum, 1); + count++; + } +- if (hw_ep->max_packet_sz_rx) { ++ else if (hw_ep->max_packet_sz_rx) { + init_peripheral_ep(musb, &hw_ep->ep_out, + epnum, 0); + count++; +diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c +index ef8d7448..79b84fb0 100644 +--- a/drivers/usb/musb/musb_host.c ++++ b/drivers/usb/musb/musb_host.c +@@ -42,7 +42,9 @@ + #include + #include + #include +- ++#include ++#include ++#include + #include "musb_core.h" + #include "musb_host.h" + +@@ -97,13 +99,37 @@ + */ + + ++ ++#if defined(CONFIG_GK_MUSB_CON_V1_00) ++#define USE_M0 1 ++#elif defined(CONFIG_GK_MUSB_CON_V1_10) ++#define USE_M1 1 ++//#define USE_M0 1 ++#endif ++ ++typedef struct ++{ ++ unsigned long size; ++ dma_addr_t phy_addr; ++ dma_addr_t phy_valid_addr; ++ void *vm_addr; ++ void *vm_valid_addr; ++} dma_buf_t; ++ ++dma_buf_t dma_buf_tx,dma_buf_rx; ++ ++static unsigned char dma_en = 0; ++ + static void musb_ep_program(struct musb *musb, u8 epnum, +- struct urb *urb, int is_out, +- u8 *buf, u32 offset, u32 len); ++ struct urb *urb, int is_out, ++ u8 *buf, u32 offset, u32 len); + + /* + * Clear TX fifo. Needed to avoid BABBLE errors. + */ ++/* ++ * modified for hardware bug by liming. ++ */ + static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep) + { + struct musb *musb = ep->musb; +@@ -112,19 +138,20 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep) + u16 lastcsr = 0; + int retries = 1000; + +- csr = musb_readw(epio, MUSB_TXCSR); +- while (csr & MUSB_TXCSR_FIFONOTEMPTY) { ++ csr = musb_readw(epio, MUSB_TXCSR); ++ while ((csr & MUSB_TXCSR_FIFONOTEMPTY)) { + if (csr != lastcsr) + dev_dbg(musb->controller, "Host TX FIFONOTEMPTY csr: %02x\n", csr); +- lastcsr = csr; +- csr |= MUSB_TXCSR_FLUSHFIFO; ++ lastcsr = csr; ++ csr &= ~MUSB_TXCSR_TXPKTRDY; ++ csr |= MUSB_TXCSR_FLUSHFIFO; + musb_writew(epio, MUSB_TXCSR, csr); + csr = musb_readw(epio, MUSB_TXCSR); + if (WARN(retries-- < 1, +- "Could not flush host TX%d fifo: csr: %04x\n", +- ep->epnum, csr)) ++ "Could not flush host TX%d fifo: csr: %04x\n", ++ ep->epnum, csr)) + return; +- mdelay(1); ++ udelay(1); + } + } + +@@ -132,7 +159,7 @@ static void musb_h_ep0_flush_fifo(struct musb_hw_ep *ep) + { + void __iomem *epio = ep->regs; + u16 csr; +- int retries = 5; ++ int retries = 10; + + /* scrub any data left in the fifo */ + do { +@@ -141,11 +168,11 @@ static void musb_h_ep0_flush_fifo(struct musb_hw_ep *ep) + break; + musb_writew(epio, MUSB_TXCSR, MUSB_CSR0_FLUSHFIFO); + csr = musb_readw(epio, MUSB_TXCSR); +- udelay(10); ++ udelay(1); + } while (--retries); + + WARN(!retries, "Could not flush host TX%d fifo: csr: %04x\n", +- ep->epnum, csr); ++ ep->epnum, csr); + + /* and reset for the next transfer */ + musb_writew(epio, MUSB_TXCSR, 0); +@@ -530,7 +557,6 @@ musb_host_packet_rx(struct musb *musb, struct urb *urb, u8 epnum, u8 iso_err) + csr |= MUSB_RXCSR_H_REQPKT; + musb_writew(epio, MUSB_RXCSR, csr); + } +- + return done; + } + +@@ -605,17 +631,20 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep) + ep->rx_reinit = 0; + } + +-static bool musb_tx_dma_program(struct dma_controller *dma, +- struct musb_hw_ep *hw_ep, struct musb_qh *qh, +- struct urb *urb, u32 offset, u32 length) ++static bool musb_tx_dma_program(struct musb *musb, ++ struct dma_controller *dma, ++ struct musb_hw_ep *hw_ep, ++ struct musb_qh *qh, ++ struct urb *urb, ++ u32 offset, ++ u32 length) + { + struct dma_channel *channel = hw_ep->tx_channel; + void __iomem *epio = hw_ep->regs; +- u16 pkt_size = qh->maxpacket; +- u16 csr; +- u8 mode; +- +-#ifdef CONFIG_USB_INVENTRA_DMA ++ u16 pkt_size = qh->maxpacket; ++ u16 csr; ++ u8 mode = 0; ++ + if (length > channel->max_len) + length = channel->max_len; + +@@ -633,37 +662,24 @@ static bool musb_tx_dma_program(struct dma_controller *dma, + } + channel->desired_mode = mode; + musb_writew(epio, MUSB_TXCSR, csr); +-#else +- if (!is_cppi_enabled() && !tusb_dma_omap()) +- return false; +- +- channel->actual_len = 0; +- +- /* +- * TX uses "RNDIS" mode automatically but needs help +- * to identify the zero-length-final-packet case. +- */ +- mode = (urb->transfer_flags & URB_ZERO_PACKET) ? 1 : 0; +-#endif +- +- qh->segsize = length; +- +- /* +- * Ensure the data reaches to main memory before starting +- * DMA transfer +- */ +- wmb(); +- +- if (!dma->channel_program(channel, pkt_size, mode, +- urb->transfer_dma + offset, length)) { +- dma->channel_release(channel); +- hw_ep->tx_channel = NULL; + +- csr = musb_readw(epio, MUSB_TXCSR); +- csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB); +- musb_writew(epio, MUSB_TXCSR, csr | MUSB_TXCSR_H_WZC_BITS); +- return false; +- } ++ channel->hw_ep = hw_ep; ++ ++ if (!urb->align) { ++ //printk("cpy: dst : %p, src : %p, len : %d\n", dma_buf.vm_valid_addr, urb->transfer_dma + qh->offset, length); ++ if (!dma->channel_program(channel, pkt_size, mode, ++ dma_buf_tx.phy_valid_addr + qh->offset, ++ length)) { ++ printk("dma error 1 !!!"); ++ } ++ } else { ++ //wmb(); ++ if (!dma->channel_program(channel, pkt_size, mode, ++ urb->transfer_dma + qh->offset, ++ length)) { ++ printk("dma error 3 !!!"); ++ } ++ } + return true; + } + +@@ -676,7 +692,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum, + u8 *buf, u32 offset, u32 len) + { + struct dma_controller *dma_controller; +- struct dma_channel *dma_channel; ++ struct dma_channel *dma_channel = NULL; + u8 dma_ok; + void __iomem *mbase = musb->mregs; + struct musb_hw_ep *hw_ep = musb->endpoints + epnum; +@@ -694,20 +710,38 @@ static void musb_ep_program(struct musb *musb, u8 epnum, + + musb_ep_select(mbase, epnum); + +- /* candidate for DMA? */ +- dma_controller = musb->dma_controller; +- if (is_dma_capable() && epnum && dma_controller) { +- dma_channel = is_out ? hw_ep->tx_channel : hw_ep->rx_channel; +- if (!dma_channel) { +- dma_channel = dma_controller->channel_alloc( +- dma_controller, hw_ep, is_out); +- if (is_out) +- hw_ep->tx_channel = dma_channel; +- else +- hw_ep->rx_channel = dma_channel; +- } +- } else +- dma_channel = NULL; ++ ++#if defined(CONFIG_GK_MUSB_CON_V1_00) ++ if (is_out) ++#endif ++ { ++ /* candidate for DMA? */ ++ dma_controller = musb->dma_controller; ++ if (is_dma_capable() && epnum && dma_controller) ++ { ++ dma_channel = is_out ? hw_ep->tx_channel : hw_ep->rx_channel; ++ if (!dma_channel) { ++ dma_channel = dma_controller->channel_alloc( ++ dma_controller, hw_ep, is_out); ++ if (is_out) ++ { ++ hw_ep->tx_channel = dma_channel; ++ } ++ else ++ { ++ hw_ep->rx_channel = dma_channel; ++ if((dma_channel_status(dma_channel) == MUSB_DMA_STATUS_BUSY)) ++ { ++ printk("dma busy use pio epnum rx%d\n",epnum); ++ dma_channel = NULL; ++ } ++ } ++ } ++ } ++ else ++ dma_channel = NULL; ++ } ++ + + /* make sure we clear DMAEnab, autoSet bits from previous run */ + +@@ -765,6 +799,17 @@ static void musb_ep_program(struct musb *musb, u8 epnum, + musb_write_txhubaddr(mbase, epnum, qh->h_addr_reg); + musb_write_txhubport(mbase, epnum, qh->h_port_reg); + /* FIXME if !epnum, do the same for RX ... */ ++ if(!epnum){ ++ musb_writeb(mbase, ++ MUSB_BUSCTL_OFFSET(epnum, MUSB_RXFUNCADDR), ++ qh->addr_reg); ++ musb_writeb(mbase, ++ MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBADDR), ++ qh->h_addr_reg); ++ musb_writeb(mbase, ++ MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBPORT), ++ qh->h_port_reg); ++ } + } else + musb_writeb(mbase, MUSB_FADDR, qh->addr_reg); + +@@ -790,15 +835,38 @@ static void musb_ep_program(struct musb *musb, u8 epnum, + qh->type_reg); + } + +- if (can_bulk_split(musb, qh->type)) ++ if (can_bulk_split(musb, qh->type)) { + load_count = min((u32) hw_ep->max_packet_sz_tx, +- len); +- else ++ len); ++ } else { + load_count = min((u32) packet_sz, len); ++ hw_ep->max_packet_sz_tx = packet_sz; ++ } ++ ++ if (dma_channel && (urb->transfer_dma & 0x7)) { ++ memcpy(dma_buf_tx.vm_valid_addr, urb->transfer_buffer, len); ++ urb->align = 0; ++ //udelay(6); ++ } else { ++ urb->align = 1; ++ } ++ ++ wmb(); ++#if defined(USE_M0) ++ //musb dma mode0 ++ if (dma_channel && musb_tx_dma_program(musb, dma_controller, ++ hw_ep, qh, urb, offset, min((u32) hw_ep->max_packet_sz_tx, len))) { ++ ++ load_count = 0; ++ } ++#elif defined(USE_M1) ++ //musb dma mode1 ++ if (dma_channel && musb_tx_dma_program(musb, dma_controller, ++ hw_ep, qh, urb, offset, len)) { + +- if (dma_channel && musb_tx_dma_program(dma_controller, +- hw_ep, qh, urb, offset, len)) + load_count = 0; ++ } ++#endif + + if (load_count) { + /* PIO to load FIFO */ +@@ -838,13 +906,15 @@ static void musb_ep_program(struct musb *musb, u8 epnum, + csr &= MUSB_RXCSR_DISNYET; + } + +- /* kick things off */ +- +- if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) { ++ if ((len> qh->maxpacket)&&(dma_channel)&&(urb->transfer_flags & URB_SHORT_NOT_OK)&&(usb_pipebulk(urb->pipe))) { + /* Candidate for DMA */ + dma_channel->actual_len = 0L; + qh->segsize = len; +- ++ if (urb->transfer_flags & URB_SHORT_NOT_OK) ++ { ++ dma_en = 1; ++ musb_writew(mbase,0x300 + epnum*4,len/qh->maxpacket); ++ } + /* AUTOREQ is in a DMA register */ + musb_writew(hw_ep->regs, MUSB_RXCSR, csr); + csr = musb_readw(hw_ep->regs, MUSB_RXCSR); +@@ -853,22 +923,29 @@ static void musb_ep_program(struct musb *musb, u8 epnum, + * Unless caller treats short RX transfers as + * errors, we dare not queue multiple transfers. + */ +- dma_ok = dma_controller->channel_program(dma_channel, +- packet_sz, !(urb->transfer_flags & +- URB_SHORT_NOT_OK), +- urb->transfer_dma + offset, +- qh->segsize); ++ hw_ep->rx_channel->hw_ep = hw_ep; ++ ++ dma_ok = dma_controller->channel_program( ++ hw_ep->rx_channel, qh->maxpacket, ++ 1, urb->transfer_dma, len); ++ + if (!dma_ok) { + dma_controller->channel_release(dma_channel); + hw_ep->rx_channel = dma_channel = NULL; + } else +- csr |= MUSB_RXCSR_DMAENAB; ++ { ++ csr |= MUSB_RXCSR_DMAENAB; ++ ++ csr |= MUSB_RXCSR_DMAMODE; ++ csr |= MUSB_RXCSR_AUTOCLEAR; ++ csr |=MUSB_RXCSR_H_AUTOREQ; ++ } + } + + csr |= MUSB_RXCSR_H_REQPKT; + dev_dbg(musb->controller, "RXCSR%d := %04x\n", epnum, csr); + musb_writew(hw_ep->regs, MUSB_RXCSR, csr); +- csr = musb_readw(hw_ep->regs, MUSB_RXCSR); ++ csr = musb_readw(hw_ep->regs, MUSB_RXCSR); + } + } + +@@ -1089,8 +1166,10 @@ done: + */ + + #endif +- ++extern u8 usb_short_pack_flag; + /* Service a Tx-Available or dma completion irq for the endpoint */ ++ ++extern unsigned long time_1_start, time_1_end, time_1; + void musb_host_tx(struct musb *musb, u8 epnum) + { + int pipe; +@@ -1107,6 +1186,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) + struct dma_channel *dma; + bool transfer_pending = false; + ++ + musb_ep_select(mbase, epnum); + tx_csr = musb_readw(epio, MUSB_TXCSR); + +@@ -1128,13 +1208,13 @@ void musb_host_tx(struct musb *musb, u8 epnum) + + /* stall; record URB status */ + status = -EPIPE; +- ++ printk("=============[%s %d]\n", __func__, __LINE__); + } else if (tx_csr & MUSB_TXCSR_H_ERROR) { + /* (NON-ISO) dma was disabled, fifo flushed */ + dev_dbg(musb->controller, "TX 3strikes on ep=%d\n", epnum); + + status = -ETIMEDOUT; +- ++ printk("=============[%s %d]\n", __func__, __LINE__); + } else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) { + dev_dbg(musb->controller, "TX end=%d device not responding\n", epnum); + +@@ -1150,12 +1230,14 @@ void musb_host_tx(struct musb *musb, u8 epnum) + musb_writew(epio, MUSB_TXCSR, + MUSB_TXCSR_H_WZC_BITS + | MUSB_TXCSR_TXPKTRDY); ++ printk("=============[%s %d]\n", __func__, __LINE__); + return; + } + + if (status) { + if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { + dma->status = MUSB_DMA_STATUS_CORE_ABORT; ++ printk("[%s %d]status-0x%08x-0x%08x\n", __func__, __LINE__, status, dma->status); + (void) musb->dma_controller->channel_abort(dma); + } + +@@ -1229,9 +1311,8 @@ void musb_host_tx(struct musb *musb, u8 epnum) + * too late (after TXPKTRDY was cleared by controller). + * Re-read TXCSR as we have spoiled its previous value. + */ +- tx_csr = musb_readw(epio, MUSB_TXCSR); ++ tx_csr = musb_readw(epio, MUSB_TXCSR); + } +- + /* + * We may get here from a DMA completion or TXPKTRDY interrupt. + * In any case, we must check the FIFO status here and bail out +@@ -1239,10 +1320,12 @@ void musb_host_tx(struct musb *musb, u8 epnum) + * "missed" TXPKTRDY interrupts and deal with double-buffered + * FIFO mode too... + */ ++ tx_csr = musb_readw(epio, MUSB_TXCSR); + if (tx_csr & (MUSB_TXCSR_FIFONOTEMPTY | MUSB_TXCSR_TXPKTRDY)) { + dev_dbg(musb->controller, "DMA complete but packet still in FIFO, " +- "CSR %04x\n", tx_csr); +- return; ++ "CSR %04x\n", tx_csr); ++ ++ return; + } + } + +@@ -1266,16 +1349,22 @@ void musb_host_tx(struct musb *musb, u8 epnum) + offset = d->offset; + length = d->length; + } +- } else if (dma && urb->transfer_buffer_length == qh->offset) { ++ } else if (dma && (urb->transfer_buffer_length == qh->offset)) { + done = true; + } else { + /* see if we need to send more data, or ZLP */ +- if (qh->segsize < qh->maxpacket) +- done = true; +- else if (qh->offset == urb->transfer_buffer_length +- && !(urb->transfer_flags +- & URB_ZERO_PACKET)) ++ if (!dma) { ++ if (qh->segsize < qh->maxpacket) { ++ done = true; ++ } ++ } ++ ++ if (qh->offset >= urb->transfer_buffer_length ++ && !(urb->transfer_flags ++ & URB_ZERO_PACKET)) { ++ + done = true; ++ } + if (!done) { + offset = qh->offset; + length = urb->transfer_buffer_length - offset; +@@ -1300,12 +1389,9 @@ void musb_host_tx(struct musb *musb, u8 epnum) + musb_advance_schedule(musb, urb, hw_ep, USB_DIR_OUT); + return; + } else if ((usb_pipeisoc(pipe) || transfer_pending) && dma) { +- if (musb_tx_dma_program(musb->dma_controller, hw_ep, qh, urb, +- offset, length)) { +- if (is_cppi_enabled() || tusb_dma_omap()) +- musb_h_tx_dma_start(hw_ep); +- return; +- } ++ musb_tx_dma_program(musb, musb->dma_controller, ++ hw_ep, qh, urb, ++ qh->offset, min((u32) hw_ep->max_packet_sz_tx, length)); + } else if (tx_csr & MUSB_TXCSR_DMAENAB) { + dev_dbg(musb->controller, "not complete, but DMA enabled?\n"); + return; +@@ -1318,19 +1404,21 @@ void musb_host_tx(struct musb *musb, u8 epnum) + * (and presumably, FIFO is not half-full) we should write *two* + * packets before updating TXCSR; other docs disagree... + */ +- if (length > qh->maxpacket) +- length = qh->maxpacket; +- /* Unmap the buffer so that CPU can use it */ +- usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb); +- musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset); +- qh->segsize = length; +- +- musb_ep_select(mbase, epnum); +- musb_writew(epio, MUSB_TXCSR, +- MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); ++ if (!dma) { ++ if (length > qh->maxpacket) ++ length = qh->maxpacket; ++ ++ /* Unmap the buffer so that CPU can use it */ ++ usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb); ++ musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset); ++ ++ qh->segsize = length; ++ musb_ep_select(mbase, epnum); ++ musb_writew(epio, MUSB_TXCSR, ++ MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); ++ } + } + +- + #ifdef CONFIG_USB_INVENTRA_DMA + + /* Host side RX (IN) using Mentor DMA works as follows: +@@ -1418,6 +1506,8 @@ static void musb_bulk_rx_nak_timeout(struct musb *musb, struct musb_hw_ep *ep) + * Service an RX interrupt for the given IN endpoint; docs cover bulk, iso, + * and high-bandwidth IN transfer cases. + */ ++ ++ + void musb_host_rx(struct musb *musb, u8 epnum) + { + struct urb *urb; +@@ -1430,14 +1520,12 @@ void musb_host_rx(struct musb *musb, u8 epnum) + u16 rx_csr, val; + bool iso_err = false; + bool done = false; +- u32 status; +- struct dma_channel *dma; +- ++ u32 status = 0; ++ struct dma_channel *dma = NULL; ++ static int temp_dma_lenth = 0; + musb_ep_select(mbase, epnum); +- + urb = next_urb(qh); + dma = is_dma_capable() ? hw_ep->rx_channel : NULL; +- status = 0; + xfer_len = 0; + + rx_csr = musb_readw(epio, MUSB_RXCSR); +@@ -1464,18 +1552,15 @@ void musb_host_rx(struct musb *musb, u8 epnum) + * handled yet! */ + if (rx_csr & MUSB_RXCSR_H_RXSTALL) { + dev_dbg(musb->controller, "RX end %d STALL\n", epnum); +- + /* stall; record URB status */ + status = -EPIPE; + + } else if (rx_csr & MUSB_RXCSR_H_ERROR) { + dev_dbg(musb->controller, "end %d RX proto error\n", epnum); +- + status = -EPROTO; + musb_writeb(epio, MUSB_RXINTERVAL, 0); + + } else if (rx_csr & MUSB_RXCSR_DATAERROR) { +- + if (USB_ENDPOINT_XFER_ISOC != qh->type) { + dev_dbg(musb->controller, "RX end %d NAK timeout\n", epnum); + +@@ -1524,11 +1609,17 @@ void musb_host_rx(struct musb *musb, u8 epnum) + goto finish; + } + +- if (unlikely(dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY)) { +- /* SHOULD NEVER HAPPEN ... but at least DaVinci has done it */ +- ERR("RX%d dma busy, csr %04x\n", epnum, rx_csr); +- goto finish; +- } ++ if(dma_en == 0) ++ { ++ if((musb_readw(epio, MUSB_RXCOUNT) == 0) || (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY)) ++ { ++ //printk("dma busy use pio\n"); ++ dma = NULL; ++ } ++ } ++ ++ if(qh->maxpacket<512) ++ dma = NULL; + + /* thorough shutdown for now ... given more precise fault handling + * and better queueing support, we might keep a DMA pipeline going +@@ -1560,13 +1651,16 @@ void musb_host_rx(struct musb *musb, u8 epnum) + MUSB_RXCSR_H_WZC_BITS | rx_csr); + } + #endif +- if (dma && (rx_csr & MUSB_RXCSR_DMAENAB)) { ++ if (dma && (dma_en == 1)) { ++ //printk("HRM\n"); ++ dma_en = 0; + xfer_len = dma->actual_len; + + val &= ~(MUSB_RXCSR_DMAENAB + | MUSB_RXCSR_H_AUTOREQ + | MUSB_RXCSR_AUTOCLEAR +- | MUSB_RXCSR_RXPKTRDY); ++ | MUSB_RXCSR_RXPKTRDY ++ |MUSB_RXCSR_DMAMODE); + musb_writew(hw_ep->regs, MUSB_RXCSR, val); + + #ifdef CONFIG_USB_INVENTRA_DMA +@@ -1592,9 +1686,18 @@ void musb_host_rx(struct musb *musb, u8 epnum) + done = (urb->actual_length + xfer_len >= + urb->transfer_buffer_length + || dma->actual_len < qh->maxpacket); +- } + ++ ++ } ++ if(urb->align == 0) ++ { ++ if (usb_pipeisoc(pipe)) ++ memcpy(urb->transfer_buffer + (urb->iso_frame_desc + qh->iso_idx)->offset ,dma_buf_rx.vm_valid_addr,temp_dma_lenth); ++ else ++ memcpy(urb->transfer_buffer + urb->actual_length ,dma_buf_rx.vm_valid_addr,temp_dma_lenth); ++ } + /* send IN token for next packet, without AUTOREQ */ ++ val = musb_readw(epio, MUSB_RXCSR); + if (!done) { + val |= MUSB_RXCSR_H_REQPKT; + musb_writew(epio, MUSB_RXCSR, +@@ -1616,7 +1719,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) + + /* FIXME this is another "SHOULD NEVER HAPPEN" */ + +-/* SCRUB (RX) */ ++ /* SCRUB (RX) */ + /* do the proper sequence to abort the transfer */ + musb_ep_select(mbase, epnum); + val &= ~MUSB_RXCSR_H_REQPKT; +@@ -1632,6 +1735,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) + int ret, length; + dma_addr_t buf; + ++ dma_en = 1; + rx_count = musb_readw(epio, MUSB_RXCOUNT); + + dev_dbg(musb->controller, "RX%d count %d, buffer 0x%x len %d/%d\n", +@@ -1671,26 +1775,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) + buf = urb->transfer_dma + + urb->actual_length; + } +- +- dma->desired_mode = 0; +-#ifdef USE_MODE1 +- /* because of the issue below, mode 1 will +- * only rarely behave with correct semantics. +- */ +- if ((urb->transfer_flags & +- URB_SHORT_NOT_OK) +- && (urb->transfer_buffer_length - +- urb->actual_length) +- > qh->maxpacket) +- dma->desired_mode = 1; +- if (rx_count < hw_ep->max_packet_sz_rx) { +- length = rx_count; +- dma->desired_mode = 0; +- } else { +- length = urb->transfer_buffer_length; +- } +-#endif +- ++ + /* Disadvantage of using mode 1: + * It's basically usable only for mass storage class; essentially all + * other protocols also terminate transfers on short packets. +@@ -1707,32 +1792,35 @@ void musb_host_rx(struct musb *musb, u8 epnum) + * completed, you will find rxcount 0. Okay, so you might think why not + * wait for an interrupt when the pkt is recd. Well, you won't get any! + */ +- + val = musb_readw(epio, MUSB_RXCSR); + val &= ~MUSB_RXCSR_H_REQPKT; +- +- if (dma->desired_mode == 0) +- val &= ~MUSB_RXCSR_H_AUTOREQ; +- else +- val |= MUSB_RXCSR_H_AUTOREQ; ++ val &= ~MUSB_RXCSR_H_AUTOREQ; + val |= MUSB_RXCSR_DMAENAB; +- +- /* autoclear shouldn't be set in high bandwidth */ +- if (qh->hb_mult == 1) +- val |= MUSB_RXCSR_AUTOCLEAR; +- ++ qh->hb_mult = 0; ++ dma->desired_mode = 0; + musb_writew(epio, MUSB_RXCSR, + MUSB_RXCSR_H_WZC_BITS | val); +- ++ + /* REVISIT if when actual_length != 0, + * transfer_buffer_length needs to be + * adjusted first... + */ +- ret = c->channel_program( +- dma, qh->maxpacket, +- dma->desired_mode, buf, length); +- ++ hw_ep->rx_channel->hw_ep = hw_ep; ++ ++ if (buf & 0x7) ++ { ++ urb->align = 0; ++ temp_dma_lenth = length; ++ ret = c->channel_program(dma, qh->maxpacket,dma->desired_mode, dma_buf_rx.phy_valid_addr, length); ++ } ++ else ++ { ++ urb->align = 1; ++ ret = c->channel_program(dma, qh->maxpacket,dma->desired_mode, buf, length); ++ } ++ + if (!ret) { ++ printk("lsk:dma err\n"); + c->channel_release(dma); + hw_ep->rx_channel = NULL; + dma = NULL; +@@ -1756,6 +1844,7 @@ finish: + if (done) { + if (urb->status == -EINPROGRESS) + urb->status = status; ++ //printk("end urb %p\n",urb); + musb_advance_schedule(musb, urb, hw_ep, USB_DIR_IN); + } + } +@@ -1765,19 +1854,22 @@ finish: + * host side hardware endpoint + direction; scheduling may activate + * that hardware endpoint. + */ ++int last_tx_epnum = 3; ++int last_rx_epnum = 0; ++int rx_cnt = 1; + static int musb_schedule( + struct musb *musb, + struct musb_qh *qh, + int is_in) + { +- int idle; +- int best_diff; +- int best_end, epnum; +- struct musb_hw_ep *hw_ep = NULL; +- struct list_head *head = NULL; +- u8 toggle; +- u8 txtype; +- struct urb *urb = next_urb(qh); ++ int idle; ++ int best_diff; ++ int best_end, epnum; ++ struct musb_hw_ep *hw_ep = NULL; ++ struct list_head *head = NULL; ++ u8 toggle; ++ u8 txtype; ++ struct urb *urb = next_urb(qh); + + /* use fixed hardware for control and bulk */ + if (qh->type == USB_ENDPOINT_XFER_CONTROL) { +@@ -1849,20 +1941,27 @@ static int musb_schedule( + else + head = &musb->out_bulk; + +- /* Enable bulk RX NAK timeout scheme when bulk requests are +- * multiplexed. This scheme doen't work in high speed to full ++ /* Enable bulk RX/TX NAK timeout scheme when bulk requests are ++ * multiplexed. This scheme does not work in high speed to full + * speed scenario as NAK interrupts are not coming from a + * full speed device connected to a high speed device. + * NAK timeout interval is 8 (128 uframe or 16ms) for HS and + * 4 (8 frame or 8ms) for FS device. + */ +- if (is_in && qh->dev) ++ if (qh->dev) + qh->intv_reg = + (USB_SPEED_HIGH == qh->dev->speed) ? 8 : 4; + goto success; +- } else if (best_end < 0) { +- return -ENOSPC; +- } ++ } else if ((best_end > 0) && (qh->type == USB_ENDPOINT_XFER_BULK)) { ++ if (is_in) { ++ } else { ++ head = &musb->out_bulk; ++ } ++ } else { ++ if (best_end < 0) { ++ return -ENOSPC; ++ } ++ } + + idle = 1; + qh->mux = 0; +@@ -2254,8 +2353,29 @@ static int musb_h_start(struct usb_hcd *hcd) + /* NOTE: musb_start() is called when the hub driver turns + * on port power, or when (OTG) peripheral starts. + */ +- hcd->state = HC_STATE_RUNNING; ++ hcd->state = HC_STATE_RUNNING; + musb->port1_status = 0; ++ ++ dma_buf_tx.size = 1024*100; ++ dma_buf_tx.vm_addr = dma_alloc_coherent(NULL, dma_buf_tx.size, &dma_buf_tx.phy_addr, GFP_KERNEL); ++ //printk("vm : %p, phy : %p\n", dma_buf.vm_addr, dma_buf.phy_addr); ++ if (dma_buf_tx.vm_addr == NULL) { ++ printk("dma_buf alloc faild!\n"); ++ } else { ++ dma_buf_tx.phy_valid_addr = dma_buf_tx.phy_addr & 0xfffffff8; ++ dma_buf_tx.vm_valid_addr = (void *)((int)dma_buf_tx.vm_addr & 0xfffffff8); ++ } ++#if defined(CONFIG_GK_MUSB_CON_V1_10) ++ dma_buf_rx.size = 1024*100; ++ dma_buf_rx.vm_addr = dma_alloc_coherent(NULL, dma_buf_rx.size, &dma_buf_rx.phy_addr, GFP_KERNEL); ++ //printk("vm : %p, phy : %p\n", dma_buf.vm_addr, dma_buf.phy_addr); ++ if (dma_buf_rx.vm_addr == NULL) { ++ printk("dma_buf alloc faild!\n"); ++ } else { ++ dma_buf_rx.phy_valid_addr = dma_buf_rx.phy_addr & 0xfffffff8; ++ dma_buf_rx.vm_valid_addr = (void *)((int)dma_buf_rx.vm_addr & 0xfffffff8); ++ } ++#endif + return 0; + } + +@@ -2263,6 +2383,12 @@ static void musb_h_stop(struct usb_hcd *hcd) + { + musb_stop(hcd_to_musb(hcd)); + hcd->state = HC_STATE_HALT; ++ // Steven Yu: ++ // dma_buf.vm_addr alloced by dma_alloc_coherent, so must use dma_free_coherent to free. ++ dma_free_coherent(NULL, dma_buf_tx.size, dma_buf_tx.vm_addr, dma_buf_tx.phy_addr); ++#if defined(CONFIG_GK_MUSB_CON_V1_10) ++ dma_free_coherent(NULL, dma_buf_rx.size, dma_buf_rx.vm_addr, dma_buf_rx.phy_addr); ++#endif + } + + static int musb_bus_suspend(struct usb_hcd *hcd) +diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h +index 1d5eda26..f1be4284 100644 +--- a/drivers/usb/musb/musb_io.h ++++ b/drivers/usb/musb/musb_io.h +@@ -36,6 +36,10 @@ + #define __MUSB_LINUX_PLATFORM_ARCH_H__ + + #include ++#include ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++ + + #if !defined(CONFIG_ARM) && !defined(CONFIG_SUPERH) \ + && !defined(CONFIG_AVR32) && !defined(CONFIG_PPC32) \ +@@ -60,19 +64,18 @@ static inline void writesb(const void __iomem *addr, const void *buf, int len) + #ifndef CONFIG_BLACKFIN + + /* NOTE: these offsets are all in bytes */ ++static inline u16 musb_readw(const void __iomem *addr, unsigned int offset) ++ { return gk_musb_readw((unsigned int)addr, offset); } + +-static inline u16 musb_readw(const void __iomem *addr, unsigned offset) +- { return __raw_readw(addr + offset); } ++static inline u32 musb_readl(const void __iomem *addr, unsigned int offset) ++ { return gk_musb_readl((unsigned int)addr, offset); } + +-static inline u32 musb_readl(const void __iomem *addr, unsigned offset) +- { return __raw_readl(addr + offset); } + ++static inline void musb_writew(void __iomem *addr, unsigned int offset, u16 data) ++ { gk_musb_writew((unsigned int)addr, offset, data); } + +-static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data) +- { __raw_writew(data, addr + offset); } +- +-static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data) +- { __raw_writel(data, addr + offset); } ++static inline void musb_writel(void __iomem *addr, unsigned int offset, u32 data) ++ { gk_musb_writel((unsigned int)addr, offset, data); } + + + #if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE) +@@ -80,7 +83,7 @@ static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data) + /* + * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum. + */ +-static inline u8 musb_readb(const void __iomem *addr, unsigned offset) ++static inline u8 musb_readb(const void __iomem *addr, unsigned int offset) + { + u16 tmp; + u8 val; +@@ -94,7 +97,7 @@ static inline u8 musb_readb(const void __iomem *addr, unsigned offset) + return val; + } + +-static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data) ++static inline void musb_writeb(void __iomem *addr, unsigned int offset, u8 data) + { + u16 tmp; + +@@ -110,10 +113,11 @@ static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data) + #else + + static inline u8 musb_readb(const void __iomem *addr, unsigned offset) +- { return __raw_readb(addr + offset); } ++ { return gk_musb_readb((unsigned int)addr, offset); } + + static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data) +- { __raw_writeb(data, addr + offset); } ++ { gk_musb_writeb((unsigned int)addr, offset, data); } ++ + + #endif /* CONFIG_USB_MUSB_TUSB6010 */ + +diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h +index 03f2655a..40f4bdf8 100644 +--- a/drivers/usb/musb/musb_regs.h ++++ b/drivers/usb/musb/musb_regs.h +@@ -213,9 +213,6 @@ + /* HUBADDR */ + #define MUSB_HUBADDR_MULTI_TT 0x80 + +- +-#ifndef CONFIG_BLACKFIN +- + /* + * Common USB registers + */ +@@ -234,13 +231,12 @@ + #define MUSB_TESTMODE 0x0F /* 8 bit */ + + /* Get offset for a given FIFO from musb->mregs */ +-#if defined(CONFIG_USB_MUSB_TUSB6010) || \ +- defined(CONFIG_USB_MUSB_TUSB6010_MODULE) +-#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20)) +-#else +-#define MUSB_FIFO_OFFSET(epnum) (0x20 + ((epnum) * 4)) ++#if defined(CONFIG_GK_MUSB_CON_V1_00) ++#define MUSB_FIFO_EP_OFFSET 0x8 ++#elif defined(CONFIG_GK_MUSB_CON_V1_10) ++#define MUSB_FIFO_EP_OFFSET 0x40 //8 gk7101s/gk8601->0x40 + #endif +- ++#define MUSB_FIFO_OFFSET(epnum) (0x400 + ((epnum) * MUSB_FIFO_EP_OFFSET)) + /* + * Additional Control Registers + */ +@@ -296,14 +292,6 @@ + #define MUSB_FLAT_OFFSET(_epnum, _offset) \ + (0x100 + (0x10*(_epnum)) + (_offset)) + +-#if defined(CONFIG_USB_MUSB_TUSB6010) || \ +- defined(CONFIG_USB_MUSB_TUSB6010_MODULE) +-/* TUSB6010 EP0 configuration register is special */ +-#define MUSB_TUSB_OFFSET(_epnum, _offset) \ +- (0x10 + _offset) +-#include "tusb6010.h" /* Needed "only" for TUSB_EP0_CONF */ +-#endif +- + #define MUSB_TXCSR_MODE 0x2000 + + /* "bus control"/target registers, for host side multipoint (external hubs) */ +@@ -453,193 +441,4 @@ static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum) + return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT)); + } + +-#else /* CONFIG_BLACKFIN */ +- +-#define USB_BASE USB_FADDR +-#define USB_OFFSET(reg) (reg - USB_BASE) +- +-/* +- * Common USB registers +- */ +-#define MUSB_FADDR USB_OFFSET(USB_FADDR) /* 8-bit */ +-#define MUSB_POWER USB_OFFSET(USB_POWER) /* 8-bit */ +-#define MUSB_INTRTX USB_OFFSET(USB_INTRTX) /* 16-bit */ +-#define MUSB_INTRRX USB_OFFSET(USB_INTRRX) +-#define MUSB_INTRTXE USB_OFFSET(USB_INTRTXE) +-#define MUSB_INTRRXE USB_OFFSET(USB_INTRRXE) +-#define MUSB_INTRUSB USB_OFFSET(USB_INTRUSB) /* 8 bit */ +-#define MUSB_INTRUSBE USB_OFFSET(USB_INTRUSBE)/* 8 bit */ +-#define MUSB_FRAME USB_OFFSET(USB_FRAME) +-#define MUSB_INDEX USB_OFFSET(USB_INDEX) /* 8 bit */ +-#define MUSB_TESTMODE USB_OFFSET(USB_TESTMODE)/* 8 bit */ +- +-/* Get offset for a given FIFO from musb->mregs */ +-#define MUSB_FIFO_OFFSET(epnum) \ +- (USB_OFFSET(USB_EP0_FIFO) + ((epnum) * 8)) +- +-/* +- * Additional Control Registers +- */ +- +-#define MUSB_DEVCTL USB_OFFSET(USB_OTG_DEV_CTL) /* 8 bit */ +- +-#define MUSB_LINKINFO USB_OFFSET(USB_LINKINFO)/* 8 bit */ +-#define MUSB_VPLEN USB_OFFSET(USB_VPLEN) /* 8 bit */ +-#define MUSB_HS_EOF1 USB_OFFSET(USB_HS_EOF1) /* 8 bit */ +-#define MUSB_FS_EOF1 USB_OFFSET(USB_FS_EOF1) /* 8 bit */ +-#define MUSB_LS_EOF1 USB_OFFSET(USB_LS_EOF1) /* 8 bit */ +- +-/* Offsets to endpoint registers */ +-#define MUSB_TXMAXP 0x00 +-#define MUSB_TXCSR 0x04 +-#define MUSB_CSR0 MUSB_TXCSR /* Re-used for EP0 */ +-#define MUSB_RXMAXP 0x08 +-#define MUSB_RXCSR 0x0C +-#define MUSB_RXCOUNT 0x10 +-#define MUSB_COUNT0 MUSB_RXCOUNT /* Re-used for EP0 */ +-#define MUSB_TXTYPE 0x14 +-#define MUSB_TYPE0 MUSB_TXTYPE /* Re-used for EP0 */ +-#define MUSB_TXINTERVAL 0x18 +-#define MUSB_NAKLIMIT0 MUSB_TXINTERVAL /* Re-used for EP0 */ +-#define MUSB_RXTYPE 0x1C +-#define MUSB_RXINTERVAL 0x20 +-#define MUSB_TXCOUNT 0x28 +- +-/* Offsets to endpoint registers in indexed model (using INDEX register) */ +-#define MUSB_INDEXED_OFFSET(_epnum, _offset) \ +- (0x40 + (_offset)) +- +-/* Offsets to endpoint registers in flat models */ +-#define MUSB_FLAT_OFFSET(_epnum, _offset) \ +- (USB_OFFSET(USB_EP_NI0_TXMAXP) + (0x40 * (_epnum)) + (_offset)) +- +-/* Not implemented - HW has separate Tx/Rx FIFO */ +-#define MUSB_TXCSR_MODE 0x0000 +- +-static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size) +-{ +-} +- +-static inline void musb_write_txfifoadd(void __iomem *mbase, u16 c_off) +-{ +-} +- +-static inline void musb_write_rxfifosz(void __iomem *mbase, u8 c_size) +-{ +-} +- +-static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off) +-{ +-} +- +-static inline void musb_write_ulpi_buscontrol(void __iomem *mbase, u8 val) +-{ +-} +- +-static inline u8 musb_read_txfifosz(void __iomem *mbase) +-{ +- return 0; +-} +- +-static inline u16 musb_read_txfifoadd(void __iomem *mbase) +-{ +- return 0; +-} +- +-static inline u8 musb_read_rxfifosz(void __iomem *mbase) +-{ +- return 0; +-} +- +-static inline u16 musb_read_rxfifoadd(void __iomem *mbase) +-{ +- return 0; +-} +- +-static inline u8 musb_read_ulpi_buscontrol(void __iomem *mbase) +-{ +- return 0; +-} +- +-static inline u8 musb_read_configdata(void __iomem *mbase) +-{ +- return 0; +-} +- +-static inline u16 musb_read_hwvers(void __iomem *mbase) +-{ +- /* +- * This register is invisible on Blackfin, actually the MUSB +- * RTL version of Blackfin is 1.9, so just harcode its value. +- */ +- return MUSB_HWVERS_1900; +-} +- +-static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase) +-{ +- return NULL; +-} +- +-static inline void musb_write_rxfunaddr(void __iomem *ep_target_regs, +- u8 qh_addr_req) +-{ +-} +- +-static inline void musb_write_rxhubaddr(void __iomem *ep_target_regs, +- u8 qh_h_addr_reg) +-{ +-} +- +-static inline void musb_write_rxhubport(void __iomem *ep_target_regs, +- u8 qh_h_port_reg) +-{ +-} +- +-static inline void musb_write_txfunaddr(void __iomem *mbase, u8 epnum, +- u8 qh_addr_reg) +-{ +-} +- +-static inline void musb_write_txhubaddr(void __iomem *mbase, u8 epnum, +- u8 qh_addr_reg) +-{ +-} +- +-static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum, +- u8 qh_h_port_reg) +-{ +-} +- +-static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum) +-{ +- return 0; +-} +- +-static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum) +-{ +- return 0; +-} +- +-static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum) +-{ +- return 0; +-} +- +-static inline u8 musb_read_txfunaddr(void __iomem *mbase, u8 epnum) +-{ +- return 0; +-} +- +-static inline u8 musb_read_txhubaddr(void __iomem *mbase, u8 epnum) +-{ +- return 0; +-} +- +-static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum) +-{ +- return 0; +-} +- +-#endif /* CONFIG_BLACKFIN */ +- + #endif /* __MUSB_REGS_H__ */ +diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c +index 57a60858..021535b1 100644 +--- a/drivers/usb/musb/musbhsdma.c ++++ b/drivers/usb/musb/musbhsdma.c +@@ -30,352 +30,415 @@ + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ ++ ++#include + #include + #include + #include + #include ++#include ++#include + #include "musb_core.h" + #include "musbhsdma.h" + +-static int dma_controller_start(struct dma_controller *c) +-{ +- /* nothing to do */ +- return 0; +-} ++#include ++#include + +-static void dma_channel_release(struct dma_channel *channel); ++#if CONFIG_USB_MUSB_GK ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++#include ++#include ++#include + +-static int dma_controller_stop(struct dma_controller *c) +-{ +- struct musb_dma_controller *controller = container_of(c, +- struct musb_dma_controller, controller); +- struct musb *musb = controller->private_data; +- struct dma_channel *channel; +- u8 bit; + +- if (controller->used_channels != 0) { +- dev_err(musb->controller, +- "Stopping DMA controller while channel active\n"); ++#define SIZE_4M 0x00400000 /* 4M */ ++#define DMA_LONG_WORD_MASK 0x3 ++#define DMA_CHAN 3 ++#endif + +- for (bit = 0; bit < MUSB_HSDMA_CHANNELS; bit++) { +- if (controller->used_channels & (1 << bit)) { +- channel = &controller->channel[bit].channel; +- dma_channel_release(channel); ++struct semaphore sema_trans; + +- if (!controller->used_channels) +- break; +- } +- } +- } ++unsigned long time_start, time_end, time; + +- return 0; +-} ++unsigned long time_1_start, time_1_end, time_1; + +-static struct dma_channel *dma_channel_allocate(struct dma_controller *c, +- struct musb_hw_ep *hw_ep, u8 transmit) +-{ +- struct musb_dma_controller *controller = container_of(c, +- struct musb_dma_controller, controller); +- struct musb_dma_channel *musb_channel = NULL; +- struct dma_channel *channel = NULL; +- u8 bit; +- +- for (bit = 0; bit < MUSB_HSDMA_CHANNELS; bit++) { +- if (!(controller->used_channels & (1 << bit))) { +- controller->used_channels |= (1 << bit); +- musb_channel = &(controller->channel[bit]); +- musb_channel->controller = controller; +- musb_channel->idx = bit; +- musb_channel->epnum = hw_ep->epnum; +- musb_channel->transmit = transmit; +- channel = &(musb_channel->channel); +- channel->private_data = musb_channel; +- channel->status = MUSB_DMA_STATUS_FREE; +- channel->max_len = 0x100000; +- /* Tx => mode 1; Rx => mode 0 */ +- channel->desired_mode = transmit; +- channel->actual_len = 0; +- break; +- } +- } + +- return channel; +-} ++struct gk_dma_channel { ++ struct dma_channel channel; ++ struct gk_dma_controller *controller; ++ struct musb_hw_ep *hw_ep; ++ struct dma_chan *dma_chan; ++ unsigned int cur_len; ++ gk_dma_req_t req; ++ //dma_cookie_t cookie; ++ u8 ch_num; ++ u8 is_tx; ++ u8 is_allocated; ++ u16 max_packet_sz; ++ u16 short_packet; ++}; + +-static void dma_channel_release(struct dma_channel *channel) +-{ +- struct musb_dma_channel *musb_channel = channel->private_data; ++struct gk_dma_controller { ++ struct dma_controller controller; ++ struct gk_dma_channel rx_channel; ++ struct gk_dma_channel tx_channel; + +- channel->actual_len = 0; +- musb_channel->start_addr = 0; +- musb_channel->len = 0; ++ void *private_data; ++ void __iomem *base; + +- musb_channel->controller->used_channels &= +- ~(1 << musb_channel->idx); ++ u8 ch_num; ++ u8 is_tx; ++}; + +- channel->status = MUSB_DMA_STATUS_UNKNOWN; ++struct gk_dma_controller *controller_irq; ++struct gk_dma_controller *controller_irq_rx; ++u8 usb_short_pack_flag=0; ++ ++void gk_usb_dma_irq_tx(void *dev_id, u32 status) ++{ ++ u8 ep; ++ u8 *mbase; ++ u8 devctl; ++ struct gk_dma_channel *gk_channel; ++ struct gk_dma_controller *controller = NULL; ++ struct musb *musb = NULL; ++ unsigned long flags; ++ ++ controller = (struct gk_dma_controller *)controller_irq; ++ ++ if (controller == NULL) { ++ printk("ERROR : controller is null\n"); ++ return; ++ } ++ ++ musb = controller->private_data; ++ mbase = musb->mregs; ++ spin_lock_irqsave(&musb->lock, flags); ++ ++ gk_channel = &(controller->tx_channel); ++ gk_channel->channel.status = MUSB_DMA_STATUS_FREE; ++ devctl = musb_readb(mbase, MUSB_DEVCTL); ++ ep = gk_channel->hw_ep->epnum; ++ ++ //printk("d1t irq=0x%d\n",irq); ++ if (gk_channel->channel.desired_mode) ++ { ++ int offset = MUSB_EP_OFFSET(ep, MUSB_TXCSR); ++ u16 txcsr,tmp,flag; ++ //printk("d1t\n"); ++ /* ++ * The programming guide says that we ++ * must clear DMAENAB before DMAMODE. ++ */ ++ musb_ep_select(mbase, ep); ++ txcsr = musb_readw(mbase, offset); ++ tmp=txcsr; ++ flag=0; ++ if(tmp&(MUSB_TXCSR_TXPKTRDY|MUSB_TXCSR_FIFONOTEMPTY)) ++ { ++ //printk("d1t\n"); ++#if defined(CONFIG_GK_USB_HOST_MODE) ++ txcsr &= ~(MUSB_TXCSR_DMAENAB ++ | MUSB_TXCSR_AUTOSET|MUSB_TXCSR_TXPKTRDY); ++ musb_writew(mbase, offset, txcsr|MUSB_TXCSR_H_WZC_BITS); ++ ++ txcsr &= ~(MUSB_TXCSR_DMAMODE|MUSB_TXCSR_TXPKTRDY); ++ musb_writew(mbase, offset, txcsr|MUSB_TXCSR_H_WZC_BITS); ++ tmp = musb_readw(mbase, offset); ++ #ifdef CONFIG_USB_INVENTRA_DMA ++ if((tmp&(MUSB_TXCSR_TXPKTRDY|MUSB_TXCSR_FIFONOTEMPTY))==0) ++ musb_dma_completion(musb,ep,1); ++ #endif ++#else ++ txcsr &= ~(MUSB_TXCSR_DMAENAB ++ | MUSB_TXCSR_AUTOSET|MUSB_TXCSR_TXPKTRDY); ++ musb_writew(mbase, offset, txcsr|MUSB_TXCSR_P_WZC_BITS); ++ ++ txcsr &= ~(MUSB_TXCSR_DMAMODE|MUSB_TXCSR_TXPKTRDY); ++ musb_writew(mbase, offset, txcsr|MUSB_TXCSR_P_WZC_BITS); ++ tmp = musb_readw(mbase, offset); ++ #ifdef CONFIG_USB_INVENTRA_DMA ++ if((tmp&(MUSB_TXCSR_TXPKTRDY|MUSB_TXCSR_FIFONOTEMPTY))==0) ++ musb_dma_completion(musb,ep,1); ++ #endif ++#endif ++ } ++ else ++ { ++ //printk("d0t\n"); ++ txcsr &= ~(MUSB_TXCSR_DMAENAB ++ | MUSB_TXCSR_AUTOSET); ++ musb_writew(mbase, offset, txcsr); ++ txcsr &= ~(MUSB_TXCSR_DMAMODE); ++ musb_writew(mbase, offset, txcsr); ++#ifdef CONFIG_USB_INVENTRA_DMA ++ usb_short_pack_flag=0; ++ if(gk_channel->short_packet) ++ { ++ txcsr |= MUSB_TXCSR_TXPKTRDY; ++#if defined(CONFIG_GK_USB_HOST_MODE) ++ musb_writew(mbase, offset, txcsr); ++#endif ++ usb_short_pack_flag=1; ++ gk_channel->short_packet=0; ++ } ++else ++ musb_dma_completion(musb,ep,1); ++#endif ++ } ++ } ++ else ++ { ++ int offset = MUSB_EP_OFFSET(ep, MUSB_TXCSR); ++ u16 txcsr; ++ //printk("0t\n"); ++ /* ++ * The programming guide says that we ++ * must clear DMAENAB before DMAMODE. ++ */ ++ musb_ep_select(mbase, ep); ++ txcsr = musb_readw(mbase, offset); ++ txcsr &= ~(MUSB_TXCSR_DMAENAB | ++ MUSB_TXCSR_DMAMODE | ++ MUSB_TXCSR_AUTOSET ); ++ txcsr |= MUSB_TXCSR_TXPKTRDY; ++ musb_writew(mbase, offset, txcsr); ++ } ++ ++ ++ spin_unlock_irqrestore(&musb->lock, flags); + } + +-static void configure_channel(struct dma_channel *channel, +- u16 packet_sz, u8 mode, +- dma_addr_t dma_addr, u32 len) ++void gk_usb_dma_irq_rx(void *dev_id, u32 status) + { +- struct musb_dma_channel *musb_channel = channel->private_data; +- struct musb_dma_controller *controller = musb_channel->controller; +- struct musb *musb = controller->private_data; +- void __iomem *mbase = controller->base; +- u8 bchannel = musb_channel->idx; +- u16 csr = 0; ++ u8 ep; ++ u8 *mbase; ++ u8 devctl; + +- dev_dbg(musb->controller, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n", +- channel, packet_sz, dma_addr, len, mode); ++ struct gk_dma_channel *gk_channel; ++ struct gk_dma_controller *controller = NULL; ++ struct musb *musb = NULL; ++ unsigned long flags; ++ //printk("d1t irq=0x%d\n",status); + +- if (mode) { +- csr |= 1 << MUSB_HSDMA_MODE1_SHIFT; +- BUG_ON(len < packet_sz); +- } +- csr |= MUSB_HSDMA_BURSTMODE_INCR16 +- << MUSB_HSDMA_BURSTMODE_SHIFT; +- +- csr |= (musb_channel->epnum << MUSB_HSDMA_ENDPOINT_SHIFT) +- | (1 << MUSB_HSDMA_ENABLE_SHIFT) +- | (1 << MUSB_HSDMA_IRQENABLE_SHIFT) +- | (musb_channel->transmit +- ? (1 << MUSB_HSDMA_TRANSMIT_SHIFT) +- : 0); +- +- /* address/count */ +- musb_write_hsdma_addr(mbase, bchannel, dma_addr); +- musb_write_hsdma_count(mbase, bchannel, len); +- +- /* control (this should start things) */ +- musb_writew(mbase, +- MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_CONTROL), +- csr); +-} ++ controller = (struct gk_dma_controller *)controller_irq_rx; + +-static int dma_channel_program(struct dma_channel *channel, +- u16 packet_sz, u8 mode, +- dma_addr_t dma_addr, u32 len) +-{ +- struct musb_dma_channel *musb_channel = channel->private_data; +- struct musb_dma_controller *controller = musb_channel->controller; +- struct musb *musb = controller->private_data; ++ if (controller == NULL) { ++ printk("ERROR : controller is null\n"); ++ return; ++ } + +- dev_dbg(musb->controller, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n", +- musb_channel->epnum, +- musb_channel->transmit ? "Tx" : "Rx", +- packet_sz, dma_addr, len, mode); ++ musb = controller->private_data; ++ mbase = musb->mregs; + +- BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || +- channel->status == MUSB_DMA_STATUS_BUSY); ++ spin_lock_irqsave(&musb->lock, flags); + +- /* Let targets check/tweak the arguments */ +- if (musb->ops->adjust_channel_params) { +- int ret = musb->ops->adjust_channel_params(channel, +- packet_sz, &mode, &dma_addr, &len); +- if (ret) +- return ret; +- } ++ gk_channel = &(controller->rx_channel) ; + +- /* +- * The DMA engine in RTL1.8 and above cannot handle +- * DMA addresses that are not aligned to a 4 byte boundary. +- * It ends up masking the last two bits of the address +- * programmed in DMA_ADDR. +- * +- * Fail such DMA transfers, so that the backup PIO mode +- * can carry out the transfer +- */ +- if ((musb->hwvers >= MUSB_HWVERS_1800) && (dma_addr % 4)) +- return false; ++ gk_channel->channel.status = MUSB_DMA_STATUS_FREE; + +- channel->actual_len = 0; +- musb_channel->start_addr = dma_addr; +- musb_channel->len = len; +- musb_channel->max_packet_sz = packet_sz; +- channel->status = MUSB_DMA_STATUS_BUSY; ++ devctl = musb_readb(mbase, MUSB_DEVCTL); ++ ep = gk_channel->hw_ep->epnum; + +- configure_channel(channel, packet_sz, mode, dma_addr, len); ++#ifdef CONFIG_USB_INVENTRA_DMA ++ musb_dma_completion(musb,ep,0); ++#endif + +- return true; ++ spin_unlock_irqrestore(&musb->lock, flags); + } + +-static int dma_channel_abort(struct dma_channel *channel) ++static struct dma_channel *gk_dma_channel_allocate(struct dma_controller *c, ++ struct musb_hw_ep *hw_ep, u8 is_tx) + { +- struct musb_dma_channel *musb_channel = channel->private_data; +- void __iomem *mbase = musb_channel->controller->base; ++ struct gk_dma_controller *controller = container_of(c, ++ struct gk_dma_controller, controller); ++ struct gk_dma_channel *gk_channel = NULL; ++ static int dma_alloc_rx_init = 0,dma_alloc_tx_init = 0; + +- u8 bchannel = musb_channel->idx; +- int offset; +- u16 csr; ++ if (hw_ep->epnum == 0) { ++ return NULL; ++ } + +- if (channel->status == MUSB_DMA_STATUS_BUSY) { +- if (musb_channel->transmit) { +- offset = MUSB_EP_OFFSET(musb_channel->epnum, +- MUSB_TXCSR); +- +- /* +- * The programming guide says that we must clear +- * the DMAENAB bit before the DMAMODE bit... +- */ +- csr = musb_readw(mbase, offset); +- csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB); +- musb_writew(mbase, offset, csr); +- csr &= ~MUSB_TXCSR_DMAMODE; +- musb_writew(mbase, offset, csr); +- } else { +- offset = MUSB_EP_OFFSET(musb_channel->epnum, +- MUSB_RXCSR); ++ gk_channel = is_tx ? &(controller->tx_channel) : &(controller->rx_channel) ; + +- csr = musb_readw(mbase, offset); +- csr &= ~(MUSB_RXCSR_AUTOCLEAR | +- MUSB_RXCSR_DMAENAB | +- MUSB_RXCSR_DMAMODE); +- musb_writew(mbase, offset, csr); +- } ++ /* Check if channel is already used. */ + +- musb_writew(mbase, +- MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_CONTROL), +- 0); +- musb_write_hsdma_addr(mbase, bchannel, 0); +- musb_write_hsdma_count(mbase, bchannel, 0); +- channel->status = MUSB_DMA_STATUS_FREE; ++ controller->ch_num = hw_ep->epnum; ++ controller->is_tx = is_tx; ++ ++ gk_channel->hw_ep = hw_ep; ++ gk_channel->is_allocated = 1; ++ gk_channel->ch_num = hw_ep->epnum; ++ gk_channel->is_tx = is_tx; ++ ++ gk_channel->channel.private_data = gk_channel; ++ gk_channel->channel.max_len = SIZE_4M; ++ if(!is_tx && dma_alloc_rx_init == 0) ++ { ++ dma_alloc_rx_init = 1; ++ gk_channel->channel.status = MUSB_DMA_STATUS_FREE; ++ } ++ if(is_tx && dma_alloc_tx_init == 0) ++ { ++ dma_alloc_tx_init = 1; ++ gk_channel->channel.status = MUSB_DMA_STATUS_FREE; + } + +- return 0; ++ gk_channel->controller = controller; ++ ++ ++ ++ ++ return &(gk_channel->channel); + } + +-static irqreturn_t dma_controller_irq(int irq, void *private_data) ++static void gk_dma_channel_release(struct dma_channel *channel) + { +- struct musb_dma_controller *controller = private_data; +- struct musb *musb = controller->private_data; +- struct musb_dma_channel *musb_channel; +- struct dma_channel *channel; ++ struct gk_dma_channel *gk_channel = channel->private_data; + +- void __iomem *mbase = controller->base; ++ gk_channel->is_allocated = 0; ++ channel->status = MUSB_DMA_STATUS_FREE; ++ channel->actual_len = 0; + +- irqreturn_t retval = IRQ_NONE; ++} + +- unsigned long flags; ++static int gk_dma_channel_program(struct dma_channel *channel, ++ u16 packet_sz, u8 mode, ++ dma_addr_t dma_addr, u32 len) ++{ ++ struct gk_dma_channel *gk_channel = channel->private_data; ++ gk_dma_req_t *req = &gk_channel->req; ++ struct gk_dma_controller *controller = gk_channel->controller; ++ unsigned char trans_size = 0; + +- u8 bchannel; +- u8 int_hsdma; + +- u32 addr, count; +- u16 csr; ++ if(len <= 0) return false; ++ if(packet_sz & 0x3) return false; ++ if((int)dma_addr & 0x7) return false; + +- spin_lock_irqsave(&musb->lock, flags); ++ gk_channel->max_packet_sz = packet_sz; + +- int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR); ++ channel->status = MUSB_DMA_STATUS_BUSY; ++ channel->desired_mode = mode; + +-#ifdef CONFIG_BLACKFIN +- /* Clear DMA interrupt flags */ +- musb_writeb(mbase, MUSB_HSDMA_INTR, int_hsdma); +-#endif ++ if ((len % 8) == 0) { ++ trans_size = 3; ++ } else if ((len % 4) == 0) { ++ trans_size = 2; ++ } else if ((len % 2) == 0) { ++ trans_size = 1; ++ } else { ++ trans_size = 0; ++ } + +- if (!int_hsdma) { +- dev_dbg(musb->controller, "spurious DMA irq\n"); ++ channel->actual_len = len; ++ controller->is_tx = gk_channel->is_tx; ++ gk_channel->hw_ep = channel->hw_ep; + +- for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) { +- musb_channel = (struct musb_dma_channel *) +- &(controller->channel[bchannel]); +- channel = &musb_channel->channel; +- if (channel->status == MUSB_DMA_STATUS_BUSY) { +- count = musb_read_hsdma_count(mbase, bchannel); + +- if (count == 0) +- int_hsdma |= (1 << bchannel); +- } +- } + +- dev_dbg(musb->controller, "int_hsdma = 0x%x\n", int_hsdma); ++ if(controller->is_tx) ++ { ++ controller_irq = controller; ++#if defined(CONFIG_GK_MUSB_CON_V1_00) ++ req->dst = (u32)gk_channel->hw_ep->fifo - 0x90000000; ++#elif defined(CONFIG_GK_MUSB_CON_V1_10) ++ req->dst = (u32)gk_virt_to_phys((u32)(gk_channel->hw_ep->fifo)); ++#endif ++ if((mode)&&(len%packet_sz)) ++ gk_channel->short_packet=1; ++ else ++ gk_channel->short_packet=0; ++ req->src = dma_addr; //ddr addr ++ req->xfr_count = len; ++ gk_dma_writel(DMA_CHAN_SRC_REG(DMA_CHAN_TX), req->src); ++ gk_dma_writel(DMA_CHAN_DST_REG(DMA_CHAN_TX), req->dst); ++#if defined(CONFIG_GK_MUSB_CON_V1_00) ++ gk_dma_writel(DMA_CHAN_CTR_REG(DMA_CHAN_TX), (0x98000000 | req->xfr_count | (trans_size << 22))); ++#elif defined(CONFIG_GK_MUSB_CON_V1_10) ++ gk_dma_writel(DMA_CHAN_CTR_REG(DMA_CHAN_TX), (0x9B000000 | req->xfr_count | (trans_size << 22))); ++#endif + +- if (!int_hsdma) +- goto done; + } ++ else ++ { ++ controller_irq_rx = controller; ++ req->src = (u32)gk_virt_to_phys((u32)(gk_channel->hw_ep->fifo)); ++ req->dst = dma_addr; //ddr addr ++ req->xfr_count = len; ++ gk_dma_writel(DMA_CHAN_DST_REG(DMA_CHAN_RX), req->dst); ++ gk_dma_writel(DMA_CHAN_SRC_REG(DMA_CHAN_RX), req->src); ++ gk_dma_writel(DMA_CHAN_CTR_REG(DMA_CHAN_RX), (0xab000000 | req->xfr_count | (trans_size << 22))); ++ } ++ ++ return true; ++} ++ ++static int gk_dma_channel_abort(struct dma_channel *channel) ++{ ++ struct gk_dma_channel *gk_channel = channel->private_data; ++ struct gk_dma_controller *controller = gk_channel->controller; ++ struct musb *musb = controller->private_data; ++ void __iomem *epio = musb->endpoints[gk_channel->hw_ep->epnum].regs; ++ u16 csr; ++ + +- for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) { +- if (int_hsdma & (1 << bchannel)) { +- musb_channel = (struct musb_dma_channel *) +- &(controller->channel[bchannel]); +- channel = &musb_channel->channel; +- +- csr = musb_readw(mbase, +- MUSB_HSDMA_CHANNEL_OFFSET(bchannel, +- MUSB_HSDMA_CONTROL)); +- +- if (csr & (1 << MUSB_HSDMA_BUSERROR_SHIFT)) { +- musb_channel->channel.status = +- MUSB_DMA_STATUS_BUS_ABORT; +- } else { +- u8 devctl; +- +- addr = musb_read_hsdma_addr(mbase, +- bchannel); +- channel->actual_len = addr +- - musb_channel->start_addr; +- +- dev_dbg(musb->controller, "ch %p, 0x%x -> 0x%x (%zu / %d) %s\n", +- channel, musb_channel->start_addr, +- addr, channel->actual_len, +- musb_channel->len, +- (channel->actual_len +- < musb_channel->len) ? +- "=> reconfig 0" : "=> complete"); +- +- devctl = musb_readb(mbase, MUSB_DEVCTL); +- +- channel->status = MUSB_DMA_STATUS_FREE; +- +- /* completed */ +- if ((devctl & MUSB_DEVCTL_HM) +- && (musb_channel->transmit) +- && ((channel->desired_mode == 0) +- || (channel->actual_len & +- (musb_channel->max_packet_sz - 1))) +- ) { +- u8 epnum = musb_channel->epnum; +- int offset = MUSB_EP_OFFSET(epnum, +- MUSB_TXCSR); +- u16 txcsr; +- +- /* +- * The programming guide says that we +- * must clear DMAENAB before DMAMODE. +- */ +- musb_ep_select(mbase, epnum); +- txcsr = musb_readw(mbase, offset); +- txcsr &= ~(MUSB_TXCSR_DMAENAB +- | MUSB_TXCSR_AUTOSET); +- musb_writew(mbase, offset, txcsr); +- /* Send out the packet */ +- txcsr &= ~MUSB_TXCSR_DMAMODE; +- txcsr |= MUSB_TXCSR_TXPKTRDY; +- musb_writew(mbase, offset, txcsr); +- } +- musb_dma_completion(musb, musb_channel->epnum, +- musb_channel->transmit); +- } ++ printk( "dma abort channel=%d, is_tx=%d\n", ++ gk_channel->ch_num, gk_channel->is_tx); ++ if(gk_channel->is_tx) ++ { ++ printk("dma status=0x%x\n",gk_dma_readl(DMA_CHAN_STA_REG(DMA_CHAN_TX))); ++ } ++ else ++ printk("dma status=0x%x\n",gk_dma_readl(DMA_CHAN_STA_REG(DMA_CHAN_RX))); ++ if(channel->status == MUSB_DMA_STATUS_BUSY) { ++ if (gk_channel->is_tx) { ++ csr = musb_readw(epio, 0x10 + MUSB_TXCSR); ++ csr &= ~(MUSB_TXCSR_AUTOSET | ++ MUSB_TXCSR_DMAENAB); ++ musb_writew(epio, 0x10 + MUSB_TXCSR, csr); ++ csr &= ~MUSB_TXCSR_DMAMODE; ++ musb_writew(epio, 0x10 + MUSB_TXCSR, csr); ++ } else { ++ csr = musb_readw(epio, 0x10 + MUSB_RXCSR); ++ csr &= ~(MUSB_RXCSR_AUTOCLEAR | ++ MUSB_RXCSR_DMAENAB); ++ musb_writew(epio, 0x10 + MUSB_RXCSR, csr); ++ csr &= ~MUSB_RXCSR_DMAMODE; ++ musb_writew(epio, 0x10 + MUSB_RXCSR, csr); + } +- } ++ } ++ channel->status = MUSB_DMA_STATUS_FREE; + +- retval = IRQ_HANDLED; +-done: +- spin_unlock_irqrestore(&musb->lock, flags); +- return retval; ++ return 0; + } + +-void dma_controller_destroy(struct dma_controller *c) ++static int gk_dma_controller_stop(struct dma_controller *c) + { +- struct musb_dma_controller *controller = container_of(c, +- struct musb_dma_controller, controller); ++ struct gk_dma_controller *controller = container_of(c, ++ struct gk_dma_controller, controller); ++ struct dma_channel *channel; + +- if (!controller) +- return; + +- if (controller->irq) +- free_irq(controller->irq, c); ++ if(controller->is_tx) channel = &controller->tx_channel.channel; ++ else channel = &controller->rx_channel.channel; ++ ++ gk_dma_channel_release(channel); ++ ++ return 0; ++} ++ ++static int gk_dma_controller_start(struct dma_controller *c) ++{ ++ ++ return 0; ++} ++ ++void dma_controller_destroy(struct dma_controller *c) ++{ ++ struct gk_dma_controller *controller = container_of(c, ++ struct gk_dma_controller, controller); + + kfree(controller); + } +@@ -383,40 +446,85 @@ void dma_controller_destroy(struct dma_controller *c) + struct dma_controller *__init + dma_controller_create(struct musb *musb, void __iomem *base) + { +- struct musb_dma_controller *controller; +- struct device *dev = musb->controller; +- struct platform_device *pdev = to_platform_device(dev); +- int irq = platform_get_irq_byname(pdev, "dma"); +- +- if (irq == 0) { +- dev_err(dev, "No DMA interrupt line!\n"); +- return NULL; +- } ++ struct gk_dma_controller *controller; + + controller = kzalloc(sizeof(*controller), GFP_KERNEL); + if (!controller) + return NULL; + +- controller->channel_count = MUSB_HSDMA_CHANNELS; + controller->private_data = musb; ++ + controller->base = base; + +- controller->controller.start = dma_controller_start; +- controller->controller.stop = dma_controller_stop; +- controller->controller.channel_alloc = dma_channel_allocate; +- controller->controller.channel_release = dma_channel_release; +- controller->controller.channel_program = dma_channel_program; +- controller->controller.channel_abort = dma_channel_abort; ++ controller->controller.start = gk_dma_controller_start; ++ controller->controller.stop = gk_dma_controller_stop; ++ controller->controller.channel_alloc = gk_dma_channel_allocate; ++ controller->controller.channel_release = gk_dma_channel_release; ++ controller->controller.channel_program = gk_dma_channel_program; ++ controller->controller.channel_abort = gk_dma_channel_abort; ++ ++ printk("dma controller create ok\n"); ++ ++ return &controller->controller; ++} ++ ++struct dma_controller * ++dma_controller_create_non_init(struct musb *musb, void __iomem *base) ++{ + +- if (request_irq(irq, dma_controller_irq, 0, +- dev_name(musb->controller), &controller->controller)) { +- dev_err(dev, "request_irq %d failed!\n", irq); +- dma_controller_destroy(&controller->controller); ++ struct gk_dma_controller *controller; ++ int err; + ++ controller = kzalloc(sizeof(*controller), GFP_KERNEL); ++ if (!controller) + return NULL; ++ ++ controller->private_data = musb; ++ ++ controller->base = base; ++ ++ controller->controller.start = gk_dma_controller_start; ++ controller->controller.stop = gk_dma_controller_stop; ++ controller->controller.channel_alloc = gk_dma_channel_allocate; ++ controller->controller.channel_release = gk_dma_channel_release; ++ controller->controller.channel_program = gk_dma_channel_program; ++ controller->controller.channel_abort = gk_dma_channel_abort; ++ //controller->controller.is_compatible = gk_dma_is_compatible; ++ ++#if 0 ++ retval = request_irq(DMA_IRQ, gk_usb_dma_irq, ++ IRQ_TYPE_LEVEL_HIGH | SA_SHIRQ, "usb-dma", NULL); ++ if (retval) { ++ pr_err("%s: request_irq %d fail %d!\n", ++ __func__, DMA_IRQ, retval); + } ++#endif + +- controller->irq = irq; ++ //usb_dma_irq = gk_usb_dma_irq; ++#ifdef CONFIG_USB_INVENTRA_DMA ++ err = gk_dma_request_irq(DMA_CHAN_TX, ++ gk_usb_dma_irq_tx, NULL); ++ if (err < 0) ++ return NULL; ++ err = gk_dma_enable_irq(DMA_CHAN_TX, ++ gk_usb_dma_irq_tx); ++ if (err < 0) ++ return NULL; ++#if defined(CONFIG_GK_MUSB_CON_V1_10) ++ err = gk_dma_request_irq(DMA_CHAN_RX, ++ gk_usb_dma_irq_rx, NULL); ++ if (err < 0) ++ return NULL; ++ err = gk_dma_enable_irq(DMA_CHAN_RX, ++ gk_usb_dma_irq_rx); ++ if (err < 0) ++ return NULL; ++#endif ++ ++#endif ++ printk("dma_controller_create_non_init ok\n"); + + return &controller->controller; + } ++ ++ +diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig +index a290be51..ad167e23 100644 +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -2349,6 +2349,16 @@ config FB_PRE_INIT_FB + Select this option if display contents should be inherited as set by + the bootloader. + ++config FB_GOKE ++ tristate "goke ipc Framebuffer support" ++ depends on FB && GK_FB ++ select FB_SYS_FILLRECT ++ select FB_SYS_COPYAREA ++ select FB_SYS_IMAGEBLIT ++ select FB_SYS_FOPS ++ help ++ Frame buffer driver for goke ipc. ++ + config FB_MSM + tristate "MSM Framebuffer support" + depends on FB && ARCH_MSM +diff --git a/drivers/video/Makefile b/drivers/video/Makefile +index 9356add9..d7683036 100644 +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -138,6 +138,7 @@ obj-$(CONFIG_FB_SH_MOBILE_HDMI) += sh_mobile_hdmi.o + obj-$(CONFIG_FB_SH_MOBILE_MERAM) += sh_mobile_meram.o + obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o + obj-$(CONFIG_FB_OMAP) += omap/ ++obj-$(CONFIG_FB_GOKE) += goke/ + obj-y += omap2/ + obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o + obj-$(CONFIG_FB_CARMINE) += carminefb.o +diff --git a/drivers/video/goke/Makefile b/drivers/video/goke/Makefile +new file mode 100644 +index 00000000..e3ad8eea +--- /dev/null ++++ b/drivers/video/goke/Makefile +@@ -0,0 +1,20 @@ ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++# ++ ++ifdef CONFIG_FB_GOKE ++obj-$(CONFIG_GK_FB_V1_00) += gk_fb_v1_00.o ++endif ++ +diff --git a/drivers/video/goke/gk_fb_v1_00.c b/drivers/video/goke/gk_fb_v1_00.c +new file mode 100644 +index 00000000..836982ab +--- /dev/null ++++ b/drivers/video/goke/gk_fb_v1_00.c +@@ -0,0 +1,1267 @@ ++/* ++ * drivers/video/goke/gk_fb_v1_00.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include CONFIG_GK_CHIP_INCLUDE_FILE ++ ++/* video=gk_fb0:x,x, ++ ,[,,] */ ++ ++static const struct gk_fb_color_table_s { ++ enum gk_fb_color_format color_format; ++ int bits_per_pixel; ++ struct fb_bitfield red; ++ struct fb_bitfield green; ++ struct fb_bitfield blue; ++ struct fb_bitfield transp; ++} gk_fb_color_format_table[] = ++{ ++ { ++ .color_format = GK_FB_COLOR_CLUT_8BPP, ++ .bits_per_pixel = 8, ++ .red = ++ { ++ .offset = 0, ++ .length = 0, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 0, ++ .length = 0, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 0, ++ .length = 0, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 0, ++ .length = 0, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_RGB565, ++ .bits_per_pixel = 16, ++ .red = ++ { ++ .offset = 11, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 5, ++ .length = 6, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 0, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 0, ++ .length = 0, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_BGR565, ++ .bits_per_pixel = 16, ++ .red = ++ { ++ .offset = 0, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 5, ++ .length = 6, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 11, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 0, ++ .length = 0, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_AGBR4444, ++ .bits_per_pixel = 16, ++ .red = ++ { ++ .offset = 0, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 8, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 4, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 12, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_RGBA4444, ++ .bits_per_pixel = 16, ++ .red = ++ { ++ .offset = 12, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 8, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 4, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 0, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_BGRA4444, ++ .bits_per_pixel = 16, ++ .red = ++ { ++ .offset = 4, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 8, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 12, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 0, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_ABGR4444, ++ .bits_per_pixel = 16, ++ .red = ++ { ++ .offset = 0, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 4, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 8, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 12, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_ARGB4444, ++ .bits_per_pixel = 16, ++ .red = ++ { ++ .offset = 8, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 4, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 0, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 12, ++ .length = 4, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_AGBR1555, ++ .bits_per_pixel = 16, ++ .red = ++ { ++ .offset = 0, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 10, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 5, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 15, ++ .length = 1, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_GBR1555, ++ .bits_per_pixel = 16, ++ .red = ++ { ++ .offset = 0, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 10, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 5, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 0, ++ .length = 0, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_RGBA5551, ++ .bits_per_pixel = 16, ++ .red = ++ { ++ .offset = 11, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 6, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 1, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 0, ++ .length = 1, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_BGRA5551, ++ .bits_per_pixel = 16, ++ .red = ++ { ++ .offset = 1, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 6, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 11, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 0, ++ .length = 1, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_ABGR1555, ++ .bits_per_pixel = 16, ++ .red = ++ { ++ .offset = 0, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 5, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 10, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 15, ++ .length = 1, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_ARGB1555, ++ .bits_per_pixel = 16, ++ .red = ++ { ++ .offset = 10, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 5, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 0, ++ .length = 5, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 15, ++ .length = 1, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_AGBR8888, ++ .bits_per_pixel = 32, ++ .red = ++ { ++ .offset = 0, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 16, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 8, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 24, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_RGBA8888, ++ .bits_per_pixel = 32, ++ .red = ++ { ++ .offset = 24, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 16, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 8, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 0, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_BGRA8888, ++ .bits_per_pixel = 32, ++ .red = ++ { ++ .offset = 8, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 16, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 24, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 0, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_ABGR8888, ++ .bits_per_pixel = 32, ++ .red = ++ { ++ .offset = 0, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 8, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 16, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 24, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ }, ++ ++ { ++ .color_format = GK_FB_COLOR_ARGB8888, ++ .bits_per_pixel = 32, ++ .red = ++ { ++ .offset = 16, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ .green = ++ { ++ .offset = 8, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ .blue = ++ { ++ .offset = 0, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ .transp = ++ { ++ .offset = 24, ++ .length = 8, ++ .msb_right = 0, ++ }, ++ }, ++}; ++ ++/* ========================================================================== */ ++static int gk_fb_proc_read(char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ int len; ++ struct gk_platform_fb *gk_fb_data; ++ struct fb_info *info; ++ ++ gk_fb_data = (struct gk_platform_fb *)data; ++ info = gk_fb_data->proc_fb_info; ++ ++ *start = page + off; ++ wait_event_interruptible(gk_fb_data->proc_wait, ++ (gk_fb_data->proc_wait_flag > 0)); ++ gk_fb_data->proc_wait_flag = 0; ++ dev_dbg(info->device, "%s:%d %d.\n", __func__, __LINE__, ++ gk_fb_data->proc_wait_flag); ++ len = sprintf(*start, "%04d %04d %04d %04d %04d %04d\n", ++ info->var.xres, info->var.yres, ++ info->fix.line_length, ++ info->var.xoffset, info->var.yoffset, ++ gk_fb_data->color_format); ++ ++ if (off + len > count) { ++ *eof = 1; ++ len = 0; ++ } ++ ++ return len; ++} ++ ++/* ========================================================================== */ ++static int gk_fb_setcmap(struct fb_cmap *cmap, struct fb_info *info) ++{ ++ int errorCode = 0; ++ struct gk_platform_fb *gk_fb_data; ++ int pos; ++ u16 *r, *g, *b, *t; ++ u8 *pclut_table, *pblend_table; ++ ++ if (cmap == &info->cmap) { ++ errorCode = 0; ++ goto gk_fb_setcmap_exit; ++ } ++ ++ if (cmap->start != 0 || cmap->len != 256) { ++ dev_dbg(info->device, ++ "%s: Incorrect parameters: start = %d, len = %d\n", ++ __func__, cmap->start, cmap->len); ++ errorCode = -1; ++ goto gk_fb_setcmap_exit; ++ } ++ ++ if (!cmap->red || !cmap->green || !cmap->blue) { ++ dev_dbg(info->device, "%s: Incorrect rgb pointers!\n", ++ __func__); ++ errorCode = -1; ++ goto gk_fb_setcmap_exit; ++ } ++ ++ gk_fb_data = (struct gk_platform_fb *)info->par; ++ ++ mutex_lock(&gk_fb_data->lock); ++ ++ r = cmap->red; ++ g = cmap->green; ++ b = cmap->blue; ++ t = cmap->transp; ++ pclut_table = gk_fb_data->clut_table; ++ pblend_table = gk_fb_data->blend_table; ++ for (pos = 0; pos < 256; pos++) { ++ *pclut_table++ = *r++; ++ *pclut_table++ = *g++; ++ *pclut_table++ = *b++; ++ if (t) *pblend_table++ = *t++; ++ } ++ ++ if (gk_fb_data->setcmap) { ++ mutex_unlock(&gk_fb_data->lock); ++ errorCode = gk_fb_data->setcmap(cmap, info); ++ } else { ++ mutex_unlock(&gk_fb_data->lock); ++ } ++ ++gk_fb_setcmap_exit: ++ dev_dbg(info->device, "%s:%d %d.\n", __func__, __LINE__, errorCode); ++ return errorCode; ++} ++ ++static int gk_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ int errorCode = 0; ++ struct gk_platform_fb *gk_fb_data; ++ u32 framesize = 0; ++ ++ gk_fb_data = (struct gk_platform_fb *)info->par; ++ ++ mutex_lock(&gk_fb_data->lock); ++ if (gk_fb_data->check_var) { ++ errorCode = gk_fb_data->check_var(var, info); ++ } ++ mutex_unlock(&gk_fb_data->lock); ++ ++ if (var->xres_virtual * var->bits_per_pixel / 8 > info->fix.line_length) { ++ errorCode = -ENOMEM; ++ dev_err(info->device, "%s: xres_virtual[%d] too big [%d]!\n", ++ __func__, var->xres_virtual * var->bits_per_pixel / 8, ++ info->fix.line_length); ++ } ++ ++ framesize = info->fix.line_length * var->yres_virtual; ++ if (framesize > info->fix.smem_len) { ++ errorCode = -ENOMEM; ++ dev_err(info->device, "%s: framesize[%d] too big [%d]!\n", ++ __func__, framesize, info->fix.smem_len); ++ } ++ ++ dev_dbg(info->device, "%s:%d %d.\n", __func__, __LINE__, errorCode); ++ ++ return errorCode; ++} ++ ++static int gk_fb_set_par(struct fb_info *info) ++{ ++ int errorCode = 0, i; ++ struct gk_platform_fb *gk_fb_data; ++ struct fb_var_screeninfo *pvar; ++ static struct fb_var_screeninfo *cur_var; ++ int res_changed = 0; ++ int color_format_changed = 0; ++ enum gk_fb_color_format new_color_format; ++ const struct gk_fb_color_table_s *pTable; ++ ++ gk_fb_data = (struct gk_platform_fb *)info->par; ++ mutex_lock(&gk_fb_data->lock); ++ cur_var = &gk_fb_data->screen_var; ++ pvar = &info->var; ++ ++ if (!gk_fb_data->set_par) ++ goto gkfb_set_par_quick_exit; ++ ++ /* Resolution changed */ ++ if (pvar->xres != cur_var->xres || pvar->yres != cur_var->yres) { ++ res_changed = 1; ++ } ++ ++ /* Color format changed */ ++ if (pvar->bits_per_pixel != cur_var->bits_per_pixel || ++ pvar->red.offset != cur_var->red.offset || ++ pvar->red.length != cur_var->red.length || ++ pvar->red.msb_right != cur_var->red.msb_right || ++ pvar->green.offset != cur_var->green.offset || ++ pvar->green.length != cur_var->green.length || ++ pvar->green.msb_right != cur_var->green.msb_right || ++ pvar->blue.offset != cur_var->blue.offset || ++ pvar->blue.length != cur_var->blue.length || ++ pvar->blue.msb_right != cur_var->blue.msb_right || ++ pvar->transp.offset != cur_var->transp.offset || ++ pvar->transp.length != cur_var->transp.length || ++ pvar->transp.msb_right != cur_var->transp.msb_right) { ++ ++ color_format_changed = 1; ++ } ++ ++ if (!res_changed && !color_format_changed) ++ goto gkfb_set_par_quick_exit; ++ ++ /* Find color format */ ++ new_color_format = gk_fb_data->color_format; ++ pTable = gk_fb_color_format_table; ++ for (i = 0; i < ARRAY_SIZE(gk_fb_color_format_table); i++) { ++ if (pTable->bits_per_pixel == pvar->bits_per_pixel && ++ pTable->red.offset == pvar->red.offset && ++ pTable->red.length == pvar->red.length && ++ pTable->red.msb_right == pvar->red.msb_right && ++ pTable->green.offset == pvar->green.offset && ++ pTable->green.length == pvar->green.length && ++ pTable->green.msb_right == pvar->green.msb_right && ++ pTable->blue.offset == pvar->blue.offset && ++ pTable->blue.length == pvar->blue.length && ++ pTable->blue.msb_right == pvar->blue.msb_right && ++ pTable->transp.offset == pvar->transp.offset && ++ pTable->transp.length == pvar->transp.length && ++ pTable->transp.msb_right == pvar->transp.msb_right) { ++ ++ new_color_format = pTable->color_format; ++ break; ++ } ++ pTable++; ++ } ++ ++ gk_fb_data->color_format = new_color_format; ++ memcpy(cur_var, pvar, sizeof(*pvar)); ++ mutex_unlock(&gk_fb_data->lock); ++ ++ errorCode = gk_fb_data->set_par(info); ++ goto gkfb_set_par_normal_exit; ++ ++gkfb_set_par_quick_exit: ++ memcpy(cur_var, pvar, sizeof(*pvar)); ++ mutex_unlock(&gk_fb_data->lock); ++ ++gkfb_set_par_normal_exit: ++ dev_dbg(info->device, "%s:%d %d.\n", __func__, __LINE__, errorCode); ++ ++ return errorCode; ++} ++ ++static int gk_fb_pan_display(struct fb_var_screeninfo *var, ++ struct fb_info *info) ++{ ++ int errorCode = 0; ++ struct gk_platform_fb *gk_fb_data; ++ ++ gk_fb_data = (struct gk_platform_fb *)info->par; ++ ++ gk_fb_data->proc_wait_flag++; ++ wake_up(&(gk_fb_data->proc_wait)); ++ mutex_lock(&gk_fb_data->lock); ++ gk_fb_data->screen_var.xoffset = var->xoffset; ++ gk_fb_data->screen_var.yoffset = var->yoffset; ++ if (gk_fb_data->pan_display) { ++ errorCode = gk_fb_data->pan_display(var, info); ++ } ++ mutex_unlock(&gk_fb_data->lock); ++ ++ dev_dbg(info->device, "%s:%d %d.\n", __func__, __LINE__, errorCode); ++ ++ return 0; ++} ++ ++static int gk_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) ++{ ++ unsigned long size = vma->vm_end - vma->vm_start; ++ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; ++ ++ if (offset + size > info->fix.smem_len) ++ return -EINVAL; ++ ++ offset += info->fix.smem_start; ++ if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT, ++ size, vma->vm_page_prot)) ++ return -EAGAIN; ++ ++ dev_dbg(info->device, "%s: P(0x%08lx)->V(0x%08lx), size = 0x%08lx.\n", ++ __func__, offset, vma->vm_start, size); ++ ++ return 0; ++} ++ ++static int gk_fb_blank(int blank_mode, struct fb_info *info) ++{ ++ int errorCode = 0; ++ struct gk_platform_fb *gk_fb_data; ++ ++ gk_fb_data = (struct gk_platform_fb *)info->par; ++ ++ mutex_lock(&gk_fb_data->lock); ++ if (gk_fb_data->set_blank) { ++ errorCode = gk_fb_data->set_blank(blank_mode, info); ++ } ++ mutex_unlock(&gk_fb_data->lock); ++ ++ dev_dbg(info->device, "%s:%d %d.\n", __func__, __LINE__, errorCode); ++ ++ return errorCode; ++} ++ ++static struct fb_ops gk_fb_ops = { ++ .owner = THIS_MODULE, ++ .fb_check_var = gk_fb_check_var, ++ .fb_set_par = gk_fb_set_par, ++ .fb_pan_display = gk_fb_pan_display, ++ .fb_fillrect = sys_fillrect, ++ .fb_copyarea = sys_copyarea, ++ .fb_imageblit = sys_imageblit, ++ .fb_mmap = gk_fb_mmap, ++ .fb_setcmap = gk_fb_setcmap, ++ .fb_blank = gk_fb_blank, ++}; ++ ++static int __init gk_fb_setup(struct device *dev, char *options, ++ struct gk_platform_fb *gk_fb_data) ++{ ++ int retval = -1; ++ int ssret; ++ int cl_xres; ++ int cl_yres; ++ int cl_xvirtual; ++ int cl_yvirtual; ++ int cl_format; ++ int cl_cvs_buf; ++ unsigned int cl_prealloc_start; ++ unsigned int cl_prealloc_length; ++ ++ if (!options || !*options) { ++ goto gkfb_setup_exit; ++ } ++ ++ ssret = sscanf(options, "%dx%d,%dx%d,%d,%d,%x,%x", &cl_xres, &cl_yres, ++ &cl_xvirtual, &cl_yvirtual, &cl_format, &cl_cvs_buf, ++ &cl_prealloc_start, &cl_prealloc_length); ++ if (ssret == 6) { ++ gk_fb_data->screen_var.xres = cl_xres; ++ gk_fb_data->screen_var.yres = cl_yres; ++ gk_fb_data->screen_var.xres_virtual = cl_xvirtual; ++ gk_fb_data->screen_var.yres_virtual = cl_yvirtual; ++ gk_fb_data->color_format = cl_format; ++ gk_fb_data->conversion_buf.available = cl_cvs_buf; ++ dev_dbg(dev, "%dx%d,%dx%d,%d,%d\n", cl_xres, cl_yres, ++ cl_xvirtual, cl_yvirtual, cl_format, cl_cvs_buf); ++ retval = 0; ++ } else ++ if (ssret == 8) { ++ gk_fb_data->screen_var.xres = cl_xres; ++ gk_fb_data->screen_var.yres = cl_yres; ++ gk_fb_data->screen_var.xres_virtual = cl_xvirtual; ++ gk_fb_data->screen_var.yres_virtual = cl_yvirtual; ++ gk_fb_data->color_format = cl_format; ++ gk_fb_data->conversion_buf.available = cl_cvs_buf; ++ ++ gk_fb_data->screen_fix.smem_start = cl_prealloc_start; ++ gk_fb_data->screen_fix.smem_len = cl_prealloc_length; ++ gk_fb_data->use_prealloc = 1; ++ dev_dbg(dev, "%dx%d,%dx%d,%d,%d,%x,%x\n", cl_xres, cl_yres, ++ cl_xvirtual, cl_yvirtual, cl_format, cl_cvs_buf, ++ cl_prealloc_start, cl_prealloc_length); ++ retval = 0; ++ } else { ++ dev_err(dev, "Can not support %s@%d!\n", options, ssret); ++ } ++ ++gkfb_setup_exit: ++ return retval; ++} ++ ++static int __devinit gk_fb_probe(struct platform_device *pdev) ++{ ++ int errorCode = 0; ++ struct fb_info *info; ++ char fb_name[64]; ++ char *option; ++ struct gk_platform_fb *gk_fb_data = NULL; ++ u32 i; ++ u32 framesize; ++ u32 line_length; ++ ++//printk("gk framebuffer probe...\n"); ++ gk_fb_data = (struct gk_platform_fb *)pdev->dev.platform_data; ++ if (gk_fb_data == NULL) { ++ dev_err(&pdev->dev, "%s: gk_fb_data is NULL!\n", __func__); ++ errorCode = -ENODEV; ++ goto gkfb_probe_exit; ++ } ++//printk("gk framebuffer use_prealloc ... %d\n", gk_fb_data->use_prealloc); ++ if (gk_fb_data->use_prealloc) { ++ dev_info(&pdev->dev, "%s: use prealloc.\n", __func__); ++ } else { ++ snprintf(fb_name, sizeof(fb_name), "gk_fb%d", pdev->id); ++ if (fb_get_options(fb_name, &option)) { ++ errorCode = -ENODEV; ++ printk("gk framebuffer no options...\n"); ++ goto gkfb_probe_exit; ++ } ++ //printk("gk framebuffer setup...%s\n", option); ++ if (gk_fb_setup(&pdev->dev, option, gk_fb_data)) { ++ errorCode = -ENODEV; ++ goto gkfb_probe_exit; ++ } ++ } ++//printk("gk framebuffer alloc...\n"); ++ info = framebuffer_alloc(sizeof(gk_fb_data), &pdev->dev); ++ if (info == NULL) { ++ dev_err(&pdev->dev, "%s: framebuffer_alloc fail!\n", __func__); ++ errorCode = -ENOMEM; ++ goto gkfb_probe_exit; ++ } ++ ++ mutex_lock(&gk_fb_data->lock); ++ ++ info->fbops = &gk_fb_ops; ++ info->par = gk_fb_data; ++ info->var = gk_fb_data->screen_var; ++ info->fix = gk_fb_data->screen_fix; ++ info->flags = FBINFO_FLAG_DEFAULT; ++ ++ /* Fill Color-related Variables */ ++ for (i = 0; i < ARRAY_SIZE(gk_fb_color_format_table); i++) { ++ if (gk_fb_color_format_table[i].color_format == ++ gk_fb_data->color_format) ++ break; ++ } ++ if (i < ARRAY_SIZE(gk_fb_color_format_table)) { ++ info->var.bits_per_pixel = ++ gk_fb_color_format_table[i].bits_per_pixel; ++ info->var.red = gk_fb_color_format_table[i].red; ++ info->var.green = gk_fb_color_format_table[i].green; ++ info->var.blue = gk_fb_color_format_table[i].blue; ++ info->var.transp = gk_fb_color_format_table[i].transp; ++ } ++ ++ /* Malloc Framebuffer Memory */ ++ line_length = (info->var.xres_virtual * ++ (info->var.bits_per_pixel / 8) + 31) & 0xffffffe0; ++ if (gk_fb_data->use_prealloc == 0) { ++ info->fix.line_length = line_length; ++ } else { ++ info->fix.line_length = ++ (line_length > gk_fb_data->prealloc_line_length) ? ++ line_length : gk_fb_data->prealloc_line_length; ++ } ++ framesize = info->fix.line_length * info->var.yres_virtual; ++ if (framesize % PAGE_SIZE) { ++ framesize /= PAGE_SIZE; ++ framesize++; ++ framesize *= PAGE_SIZE; ++ } ++ if (gk_fb_data->use_prealloc == 0) { ++ info->screen_base = kzalloc(framesize, GFP_KERNEL); ++ if (info->screen_base == NULL) { ++ dev_err(&pdev->dev, "%s(%d): Can't get fbmem!\n", ++ __func__, __LINE__); ++ errorCode = -ENOMEM; ++ goto gkfb_probe_release_framebuffer; ++ } ++ if (gk_fb_data->conversion_buf.available) { ++ gk_fb_data->conversion_buf.ping_buf = ++ kzalloc(framesize, GFP_KERNEL); ++ if (gk_fb_data->conversion_buf.ping_buf == NULL) { ++ gk_fb_data->conversion_buf.available = 0; ++ dev_err(&pdev->dev, "%s(%d): Can't get fbmem!\n", ++ __func__, __LINE__); ++ errorCode = -ENOMEM; ++ goto gkfb_probe_release_framebuffer; ++ } else { ++ gk_fb_data->conversion_buf.ping_buf_size ++ = framesize; ++ } ++ ++ gk_fb_data->conversion_buf.pong_buf = ++ kzalloc(framesize, GFP_KERNEL); ++ if (gk_fb_data->conversion_buf.pong_buf == NULL) { ++ gk_fb_data->conversion_buf.available = 0; ++ dev_err(&pdev->dev, "%s(%d): Can't get fbmem!\n", ++ __func__, __LINE__); ++ errorCode = -ENOMEM; ++ goto gkfb_probe_release_framebuffer; ++ } else { ++ gk_fb_data->conversion_buf.pong_buf_size ++ = framesize; ++ } ++ } ++ info->fix.smem_start = virt_to_phys(info->screen_base); ++ info->fix.smem_len = framesize; ++ } else { ++ if ((info->fix.smem_start == 0) || ++ (info->fix.smem_len < framesize)) { ++ dev_err(&pdev->dev, "%s: prealloc[0x%08x < 0x%08x]!\n", ++ __func__, info->fix.smem_len, framesize); ++ errorCode = -ENOMEM; ++ goto gkfb_probe_release_framebuffer; ++ } ++ ++ info->screen_base = (char __iomem *) ++ gk_phys_to_virt(info->fix.smem_start); ++ //memset(info->screen_base, 0, info->fix.smem_len); ++ ++ if (gk_fb_data->conversion_buf.available) { ++ if (info->fix.smem_len < 3 * framesize) { ++ gk_fb_data->conversion_buf.available = 0; ++ dev_err(&pdev->dev, ++ "%s: prealloc[0x%08x < 0x%08x]!\n", ++ __func__, info->fix.smem_len, ++ 3 * framesize); ++ errorCode = -ENOMEM; ++ goto gkfb_probe_release_framebuffer; ++ } else { ++ gk_fb_data->conversion_buf.ping_buf = ++ info->screen_base + framesize; ++ gk_fb_data->conversion_buf.ping_buf_size = ++ framesize; ++ gk_fb_data->conversion_buf.ping_buf = ++ info->screen_base + framesize; ++ gk_fb_data->conversion_buf.ping_buf_size = ++ framesize; ++ } ++ } ++ } ++ ++ errorCode = fb_alloc_cmap(&info->cmap, 256, 1); ++ if (errorCode < 0) { ++ dev_err(&pdev->dev, "%s: fb_alloc_cmap fail!\n", __func__); ++ errorCode = -ENOMEM; ++ goto gkfb_probe_release_framebuffer; ++ } ++ for (i = info->cmap.start; i < info->cmap.len; i++) { ++ info->cmap.red[i] = ++ gk_fb_data->clut_table[i * GK_CLUT_BYTES + 0]; ++ info->cmap.red[i] <<= 8; ++ info->cmap.green[i] = ++ gk_fb_data->clut_table[i * GK_CLUT_BYTES + 1]; ++ info->cmap.green[i] <<= 8; ++ info->cmap.blue[i] = ++ gk_fb_data->clut_table[i * GK_CLUT_BYTES + 2]; ++ info->cmap.blue[i] <<= 8; ++ if (info->cmap.transp) { ++ info->cmap.transp[i] = gk_fb_data->blend_table[i]; ++ info->cmap.transp[i] <<= 8; ++ } ++ } ++ ++ platform_set_drvdata(pdev, info); ++ gk_fb_data->fb_status = GK_FB_ACTIVE_MODE; ++ mutex_unlock(&gk_fb_data->lock); ++ ++ errorCode = register_framebuffer(info); ++ if (errorCode < 0) { ++ dev_err(&pdev->dev, "%s: register_framebuffer fail!\n", ++ __func__); ++ errorCode = -ENOMEM; ++ mutex_lock(&gk_fb_data->lock); ++ goto gkfb_probe_dealloc_cmap; ++ } ++ ++ gk_fb_data->proc_fb_info = info; ++ gk_fb_data->proc_file = create_proc_entry(dev_name(&pdev->dev), ++ S_IRUGO | S_IWUSR, get_gk_proc_dir()); ++ if (gk_fb_data->proc_file == NULL) { ++ dev_err(&pdev->dev, "Register %s failed!\n", ++ dev_name(&pdev->dev)); ++ errorCode = -ENOMEM; ++ goto gkfb_probe_unregister_framebuffer; ++ } else { ++ gk_fb_data->proc_file->read_proc = gk_fb_proc_read; ++ gk_fb_data->proc_file->data = gk_fb_data; ++ } ++ ++ mutex_lock(&gk_fb_data->lock); ++ gk_fb_data->screen_var = info->var; ++ gk_fb_data->screen_fix = info->fix; ++ mutex_unlock(&gk_fb_data->lock); ++ ++ dev_info(&pdev->dev, ++ "probe p[%dx%d] v[%dx%d] c[%d] b[%d] l[%d] @ [0x%08lx:0x%08x]!\n", ++ info->var.xres, info->var.yres, info->var.xres_virtual, ++ info->var.yres_virtual, gk_fb_data->color_format, ++ gk_fb_data->conversion_buf.available, ++ info->fix.line_length, ++ info->fix.smem_start, info->fix.smem_len); ++ goto gkfb_probe_exit; ++ ++gkfb_probe_unregister_framebuffer: ++ unregister_framebuffer(info); ++ ++gkfb_probe_dealloc_cmap: ++ fb_dealloc_cmap(&info->cmap); ++ ++gkfb_probe_release_framebuffer: ++ framebuffer_release(info); ++ gk_fb_data->fb_status = GK_FB_STOP_MODE; ++ mutex_unlock(&gk_fb_data->lock); ++ ++gkfb_probe_exit: ++ return errorCode; ++} ++ ++static int __devexit gk_fb_remove(struct platform_device *pdev) ++{ ++ struct fb_info *info; ++ struct gk_platform_fb *gk_fb_data = NULL; ++ ++ info = platform_get_drvdata(pdev); ++ if (info) { ++ remove_proc_entry(dev_name(&pdev->dev), ++ get_gk_proc_dir()); ++ unregister_framebuffer(info); ++ ++ gk_fb_data = (struct gk_platform_fb *)info->par; ++ mutex_lock(&gk_fb_data->lock); ++ gk_fb_data->fb_status = GK_FB_STOP_MODE; ++ fb_dealloc_cmap(&info->cmap); ++ if (gk_fb_data->use_prealloc == 0) { ++ if (info->screen_base) { ++ kfree(info->screen_base); ++ } ++ if (gk_fb_data->conversion_buf.available) { ++ if (gk_fb_data->conversion_buf.ping_buf) { ++ kfree(gk_fb_data->conversion_buf.ping_buf); ++ } ++ if (gk_fb_data->conversion_buf.pong_buf) { ++ kfree(gk_fb_data->conversion_buf.pong_buf); ++ } ++ } ++ gk_fb_data->screen_fix.smem_start = 0; ++ gk_fb_data->screen_fix.smem_len = 0; ++ } ++ platform_set_drvdata(pdev, NULL); ++ framebuffer_release(info); ++ mutex_unlock(&gk_fb_data->lock); ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int gk_fb_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ int errorCode = 0; ++ ++ dev_dbg(&pdev->dev, "%s exit with %d @ %d\n", ++ __func__, errorCode, state.event); ++ ++ return errorCode; ++} ++ ++static int gk_fb_resume(struct platform_device *pdev) ++{ ++ int errorCode = 0; ++ ++ dev_dbg(&pdev->dev, "%s exit with %d\n", __func__, errorCode); ++ ++ return errorCode; ++} ++#endif ++ ++static struct platform_driver gk_fb_driver = { ++ .probe = gk_fb_probe, ++ .remove = __devexit_p(gk_fb_remove), ++#ifdef CONFIG_PM ++ .suspend = gk_fb_suspend, ++ .resume = gk_fb_resume, ++#endif ++ .driver = { ++ .name = "gk-fb", ++ }, ++}; ++ ++static int __init gk_fb_init(void) ++{ ++ //printk("init gk framebuffer\n"); ++ return platform_driver_register(&gk_fb_driver); ++} ++ ++static void __exit gk_fb_exit(void) ++{ ++ platform_driver_unregister(&gk_fb_driver); ++} ++ ++module_init(gk_fb_init); ++module_exit(gk_fb_exit); ++ ++MODULE_DESCRIPTION("GK framebuffer driver"); ++MODULE_AUTHOR("Goke Microelectronics Inc."); ++MODULE_LICENSE("GPL"); ++ +diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig +index 37096246..3665ff67 100644 +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -84,6 +84,13 @@ config WM8350_WATCHDOG + + # ARM Architecture + ++config WATCHDOG_GOKE ++ tristate "goke ipc watchdog" ++ depends on GK_WDT ++ help ++ Watchdog timer embedded into goke ipc. This will reboot your ++ system when the timeout is reached. ++ + config ARM_SP805_WATCHDOG + tristate "ARM SP805 Watchdog" + depends on ARM_AMBA +diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile +index e8f479a1..930e6a8f 100644 +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -53,6 +53,9 @@ obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o + obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o + obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o + obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o ++ifdef CONFIG_WATCHDOG_GOKE ++obj-$(CONFIG_GK_WDT_V1_00) += gk_wdt_v1_00.o ++endif + + # AVR32 Architecture + obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o +diff --git a/drivers/watchdog/gk_wdt_v1_00.c b/drivers/watchdog/gk_wdt_v1_00.c +new file mode 100644 +index 00000000..c6113cd6 +--- /dev/null ++++ b/drivers/watchdog/gk_wdt_v1_00.c +@@ -0,0 +1,540 @@ ++/* ++ * linux/drivers/watchdog/gk_wdt.c ++ * ++ * Author: Steven Yu, ++ * Copyright (C) 2012-2015, goke, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include /* for MODULE_ALIAS_MISCDEV */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#define CONFIG_GK_WDT_ATBOOT (0) ++#define CONFIG_GK_WDT_TIMEOUT (15) ++ ++static bool nowayout = WATCHDOG_NOWAYOUT; ++static int tmr_margin = CONFIG_GK_WDT_TIMEOUT; ++static int tmr_atboot = CONFIG_GK_WDT_ATBOOT; ++static int soft_noboot; ++static int debug; ++ ++module_param(tmr_margin, int, 0); ++module_param(tmr_atboot, int, 0); ++module_param(nowayout, bool, 0); ++module_param(soft_noboot, int, 0); ++module_param(debug, int, 1); ++ ++MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. (default=" ++ __MODULE_STRING(CONFIG_GK_WDT_TIMEOUT) ")"); ++MODULE_PARM_DESC(tmr_atboot, ++ "Watchdog is started at boot time if set to 1, default=" ++ __MODULE_STRING(CONFIG_GK_WDT_ATBOOT)); ++MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" ++ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); ++MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, " ++ "0 to reboot (default 0)"); ++MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)"); ++ ++static DEFINE_SPINLOCK(wdt_lock); ++ ++static int init_mode = WDOG_CTR_RST_EN; //WDOG_CTR_INT_EN | WDOG_CTR_RST_EN ++module_param(init_mode, int, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(init_mode, "Watchdog mode: 0x2=reset, 0x4=irq"); ++ ++enum gk_wdt_state { ++ WDT_CLOSE_STATE_DISABLE, ++ WDT_CLOSE_STATE_ALLOW, ++}; ++struct gk_wdt_info ++{ ++ unsigned char __iomem *regbase; ++ ++ struct device *dev; ++ struct resource *mem; ++ unsigned int irq; ++ ++ enum gk_wdt_state state; ++ ++ unsigned int tmo; ++ unsigned int boot_tmo; ++ ++ struct watchdog_device *wdt_dev; ++ ++ unsigned int ctl_reg; ++ unsigned int init_mode; ++ unsigned int act_timeout; ++ ++}; ++ ++static struct gk_wdt_info *pwdtinfo = NULL; ++ ++ ++/* watchdog control routines */ ++ ++#define DBG(fmt, ...) \ ++do { \ ++ if (debug) \ ++ pr_info(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++/* functions */ ++static int gk_wdt_keepalive(struct watchdog_device *wdd) ++{ ++ struct gk_wdt_info *pinfo = pwdtinfo; ++ ++ spin_lock(&wdt_lock); ++ gk_wdt_writel((unsigned int)pinfo->regbase + WDOG_RELOAD_OFFSET, pinfo->tmo); ++ gk_wdt_writel((unsigned int)pinfo->regbase + WDOG_RESTART_OFFSET, WDT_RESTART_VAL); ++ spin_unlock(&wdt_lock); ++ ++ return 0; ++} ++ ++static void __gk_wdt_stop(struct gk_wdt_info *pinfo) ++{ ++ gk_wdt_writel((unsigned int)pinfo->regbase + WDOG_CONTROL_OFFSET, 0); ++ while((gk_wdt_readl((unsigned int)pinfo->regbase + WDOG_CONTROL_OFFSET) ++ & (WDOG_CTR_RST_EN|WDOG_CTR_INT_EN|WDOG_CTR_EN)) != 0); ++} ++ ++static int gk_wdt_stop(struct watchdog_device *wdd) ++{ ++ struct gk_wdt_info *pinfo = pwdtinfo; ++ ++ spin_lock(&wdt_lock); ++ __gk_wdt_stop(pinfo); ++ spin_unlock(&wdt_lock); ++ ++ return 0; ++} ++ ++static int __gk_wdt_start(struct gk_wdt_info *pinfo, u32 ctl_reg) ++{ ++ spin_lock(&wdt_lock); ++ ++ __gk_wdt_stop(pinfo); ++ ++ if (!ctl_reg) ++ ctl_reg = pinfo->init_mode | WDOG_CTR_EN; ++ ++ if ((ctl_reg & WDOG_CTR_RST_EN) == WDOG_CTR_RST_EN) ++ { ++ /* Clear the WDT_RST_L_REG to zero */ ++ //gk_writel(WDT_RST_L_REG, RCT_WDT_RESET_VAL); ++ ++ /* Clear software reset bit. */ ++ //gk_writel(SOFT_RESET_REG, 0x2); ++ } ++ ++ gk_wdt_writel(WDOG_CONTROL_REG, ctl_reg); ++ while(gk_wdt_tstbitsl(WDOG_CONTROL_REG, ctl_reg) != ctl_reg); ++ ++ spin_unlock(&wdt_lock); ++ ++ DBG("%s: ctl_reg=0x%08x\n", __func__, ctl_reg); ++ ++ return 0; ++ ++} ++ ++static int gk_wdt_start(struct watchdog_device *wdd) ++{ ++ struct gk_wdt_info *pinfo = pwdtinfo; ++ __gk_wdt_start(pinfo, 0); ++ return 0; ++} ++ ++static int gk_wdt_is_running(struct gk_wdt_info *pinfo) ++{ ++ return (gk_wdt_readl((unsigned int)pinfo->regbase + WDOG_CONTROL_OFFSET) & WDOG_CTR_EN); ++} ++ ++static int gk_wdt_set_heartbeat(struct watchdog_device *wdd, u32 timeout) ++{ ++ struct gk_wdt_info *pinfo = pwdtinfo; ++ ++ int errorCode = 0; ++ u32 freq; ++ u32 max_tmo; ++ ++ freq = get_apb_bus_freq_hz(); ++ if (freq) ++ max_tmo = 0xFFFFFFFF / freq; ++ else { ++ dev_err(pinfo->dev, "freq == 0 !\n"); ++ errorCode = -EPERM; ++ goto wdt_set_heartbeat_exit; ++ } ++ ++ if (timeout > max_tmo) { ++ dev_err(pinfo->dev, "max_tmo is %d, not %d.\n", max_tmo, timeout); ++ errorCode = -EINVAL; ++ goto wdt_set_heartbeat_exit; ++ } ++ ++ pinfo->tmo = timeout * freq; ++ pinfo->act_timeout = timeout; ++ gk_wdt_keepalive(wdd); ++ ++ DBG("%s: timeout=%d, freq=%u, count=0x%08x\n", __func__, timeout, freq, pinfo->tmo); ++ ++ wdd->timeout = timeout; ++ ++wdt_set_heartbeat_exit: ++ return errorCode; ++ ++} ++ ++static const struct watchdog_info gk_wdt_ident = { ++ .options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE), ++ .firmware_version = 0, ++ .identity = "GK Watchdog", ++}; ++ ++static struct watchdog_ops gk_wdt_ops = { ++ .owner = THIS_MODULE, ++ .start = gk_wdt_start, ++ .stop = gk_wdt_stop, ++ .ping = gk_wdt_keepalive, ++ .set_timeout = gk_wdt_set_heartbeat, ++}; ++ ++static struct watchdog_device gk_wdd = { ++ .info = &gk_wdt_ident, ++ .ops = &gk_wdt_ops, ++}; ++ ++/* interrupt handler code */ ++static irqreturn_t gk_wdt_irq(int irqno, void *devid) ++{ ++ struct gk_wdt_info *pinfo; ++ ++ pinfo = (struct gk_wdt_info *)devid; ++ ++ /* clear the IRQ */ ++ gk_wdt_writel((unsigned int)pinfo->regbase + WDOG_CLR_TMO_OFFSET, 0x01); ++ ++ /* Update the timerout register(Feed something to a dog) */ ++ //gk_wdt_keepalive(pinfo); ++ ++ dev_info(pinfo->dev, "Watchdog timer expired!\n"); ++ ++ return IRQ_HANDLED; ++} ++ ++static int __devinit gk_wdt_probe(struct platform_device *pdev) ++{ ++ struct device *wdt_dev; ++ struct resource *wdt_irq; ++ struct resource *wdt_mem; ++ ++#if 1 ++ void __iomem *wdt_base; ++#endif ++ ++ struct gk_wdt_info *pinfo; ++ ++ unsigned int wtcon; ++ int started = 0; ++ int ret; ++ //int size; ++ ++ printk("[%s]: probe\n", __FUNCTION__); ++ ++ DBG("%s: probe=%p\n", __func__, pdev); ++ ++ wdt_dev = &pdev->dev; ++ ++ wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (wdt_mem == NULL) { ++ dev_err(wdt_dev, "Get WDT memory resource failed\n"); ++ return -ENOENT; ++ } ++ ++ wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ if (wdt_irq == NULL) { ++ dev_err(wdt_dev, "Get WDT irq resource failed\n"); ++ return -ENOENT; ++ } ++#if 0 ++ /* get the memory region for the watchdog timer */ ++ size = resource_size(wdt_mem); ++ if (!request_mem_region(wdt_mem->start, size, pdev->name)) { ++ dev_err(wdt_dev, "Failed to get WDT's memory region\n"); ++ return -EBUSY; ++ } ++ ++ wdt_base = ioremap(wdt_mem->start, size); ++ if (wdt_base == NULL) { ++ dev_err(wdt_dev, "failed to ioremap() region\n"); ++ ret = -EINVAL; ++ goto err_req; ++ } ++#else ++ wdt_base = (void __iomem*)wdt_mem->start; ++#endif ++ ++ DBG("probe: mapped wdt_base=%p\n", wdt_base); ++ printk("[%s]: probe mapped wdt_base=%p\n", __FUNCTION__, wdt_base); ++ ++ pinfo = kzalloc(sizeof(struct gk_wdt_info), GFP_KERNEL); ++ if (pinfo == NULL) { ++ dev_err(wdt_dev, "Out of memory!\n"); ++ ret = -ENOMEM; ++ goto err_map; ++ } ++ ++ pinfo->regbase = (unsigned char __iomem *)wdt_base; ++ pinfo->mem = wdt_mem; ++ pinfo->dev = &pdev->dev; ++ pinfo->irq = wdt_irq->start; ++ pinfo->wdt_dev = &gk_wdd; ++ pinfo->state = WDT_CLOSE_STATE_DISABLE; ++ pinfo->boot_tmo = gk_wdt_readl((unsigned int)pinfo->regbase + WDOG_TIMEOUT_OFFSET); ++ pinfo->init_mode = (init_mode & (WDOG_CTR_INT_EN | WDOG_CTR_RST_EN)); ++ platform_set_drvdata(pdev, pinfo); ++ pwdtinfo = pinfo; ++ ++ /* see if we can actually set the requested timer margin, and if ++ * not, try the default value */ ++ ++ if (gk_wdt_set_heartbeat(pinfo->wdt_dev, tmr_margin)) ++ { ++ started = gk_wdt_set_heartbeat(pinfo->wdt_dev, CONFIG_GK_WDT_TIMEOUT); ++ if (started == 0) ++ dev_info(wdt_dev, ++ "tmr_margin value out of range, default %d used\n", CONFIG_GK_WDT_TIMEOUT); ++ else ++ dev_info(wdt_dev, "default timer value is out of range, cannot start\n"); ++ } ++ ++ ret = request_irq(wdt_irq->start, gk_wdt_irq, IRQF_TRIGGER_RISING, dev_name(&pdev->dev), pinfo); ++ if (ret != 0) { ++ dev_err(wdt_dev, "failed to install irq (%d)\n", ret); ++ goto err_malloc; ++ } ++ ++ watchdog_set_nowayout(pinfo->wdt_dev, nowayout); ++ ++ ret = watchdog_register_device(pinfo->wdt_dev); ++ if (ret) { ++ dev_err(wdt_dev, "cannot register watchdog (%d)\n", ret); ++ goto err_irq; ++ } ++ ++ if (tmr_atboot && started == 0) ++ { ++ dev_info(wdt_dev, "starting watchdog timer\n"); ++ gk_wdt_start(pinfo->wdt_dev); ++ } ++ else if (!tmr_atboot) ++ { ++ /* if we're not enabling the watchdog, then ensure it is ++ * disabled if it has been left running from the bootloader ++ * or other source */ ++ ++ gk_wdt_stop(pinfo->wdt_dev); ++ } ++ ++ /* print out a statement of readiness */ ++ ++ wtcon = gk_wdt_readl((unsigned int)wdt_base + WDOG_CONTROL_OFFSET); ++ ++ ++ printk("watchdog %sactive, reset %sabled, irq %sabled\n", ++ (wtcon & WDOG_CTR_EN) ? "" : "in", ++ (wtcon & WDOG_CTR_RST_EN) ? "en" : "dis", ++ (wtcon & WDOG_CTR_INT_EN) ? "en" : "dis"); ++ ++ ++ return 0; ++ ++err_irq: ++ free_irq(wdt_irq->start, pdev); ++ ++err_malloc: ++ kfree(pinfo); ++ ++err_map: ++ //iounmap(wdt_base); ++ ++//err_req: ++ //release_mem_region(wdt_mem->start, size); ++ ++ return ret; ++ ++} ++ ++static int __devexit gk_wdt_remove(struct platform_device *pdev) ++{ ++ struct gk_wdt_info *pinfo; ++ struct resource *wdt_mem; ++ ++ pinfo = platform_get_drvdata(pdev); ++ ++ if (pinfo) ++ { ++ watchdog_unregister_device(pinfo->wdt_dev); ++ gk_wdt_stop(pinfo->wdt_dev); ++ free_irq(pinfo->irq, pinfo); ++ platform_set_drvdata(pdev, NULL); ++ //iounmap((unsigned int)pinfo->regbase); ++ ++ wdt_mem = pinfo->mem; ++ //release_mem_region(wdt_mem->start, resource_size(wdt_mem)); ++ kfree(pinfo); ++ } ++ ++ dev_notice(&pdev->dev, ++ "Remove GK Media Processor Watch Dog Timer[%s].\n", ++ dev_name(&pdev->dev)); ++ ++ return 0; ++ ++} ++ ++static void gk_wdt_shutdown(struct platform_device *pdev) ++{ ++ struct gk_wdt_info *pinfo; ++ ++ pinfo = platform_get_drvdata(pdev); ++ ++ if (pinfo) ++ gk_wdt_stop(pinfo->wdt_dev); ++ else ++ dev_err(&pdev->dev, "Cannot find valid pinfo\n"); ++ ++ dev_dbg(&pdev->dev, "%s exit.\n", __func__); ++} ++ ++#ifdef CONFIG_PM ++static int gk_wdt_suspend(struct platform_device *pdev, ++ pm_message_t state) ++{ ++ struct gk_wdt_info *pinfo; ++ int errorCode = 0; ++ ++ pinfo = platform_get_drvdata(pdev); ++ ++ if (pinfo) { ++ disable_irq(pinfo->irq); ++ pinfo->ctl_reg = gk_wdt_readl((unsigned int)pinfo->regbase + WDOG_CONTROL_OFFSET); ++ gk_wdt_stop(pinfo); ++ } else { ++ dev_err(&pdev->dev, "Cannot find valid pinfo\n"); ++ errorCode = -ENXIO; ++ } ++ ++ dev_dbg(&pdev->dev, "%s exit with %d @ %d\n", ++ __func__, errorCode, state.event); ++ ++ return errorCode; ++} ++ ++static int gk_wdt_resume(struct platform_device *pdev) ++{ ++ struct gk_wdt_info *pinfo; ++ int errorCode = 0; ++ ++ pinfo = platform_get_drvdata(pdev); ++ ++ if (pinfo) { ++ if (pinfo->ctl_reg) { ++ gk_wdt_set_heartbeat(pinfo, pinfo->act_timeout); ++ gk_wdt_start(pinfo->wdt_dev); ++ } ++ enable_irq(pinfo->irq); ++ } else { ++ dev_err(&pdev->dev, "Cannot find valid pinfo\n"); ++ errorCode = -ENXIO; ++ } ++ ++ dev_dbg(&pdev->dev, "%s exit with %d\n", __func__, errorCode); ++ ++ return errorCode; ++} ++#endif ++ ++ ++#ifdef CONFIG_OF ++static const struct of_device_id gk_wdt_match[] = { ++ { .compatible = "goke,gk-wdt" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, gk_wdt_match); ++#else ++#define gk_wdt_match NULL ++#endif ++ ++static struct platform_driver gk_wdt_driver = { ++ .probe = gk_wdt_probe, ++ .remove = __devexit_p(gk_wdt_remove), ++ .shutdown = gk_wdt_shutdown, ++#ifdef CONFIG_PM ++ .suspend = gk_wdt_suspend, ++ .resume = gk_wdt_resume, ++#endif ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "gk-wdt", ++ .of_match_table = gk_wdt_match, ++ }, ++}; ++ ++ ++static int __init gk_wdt_init(void) ++{ ++ pr_info("GK Watchdog Timer, (c) 2014 Goke Microelectronics\n"); ++ ++ printk("[%s]: init\n", __FUNCTION__); ++ ++ return platform_driver_register(&gk_wdt_driver); ++} ++ ++static void __exit gk_wdt_exit(void) ++{ ++ platform_driver_unregister(&gk_wdt_driver); ++} ++ ++module_init(gk_wdt_init); ++module_exit(gk_wdt_exit); ++ ++MODULE_AUTHOR("Goke Microelectronics Inc."); ++MODULE_DESCRIPTION("GK Watchdog Device Driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); ++MODULE_ALIAS("platform:gk-wdt"); +diff --git a/fs/Kconfig b/fs/Kconfig +index f95ae3a0..f19f3434 100644 +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -203,6 +203,7 @@ source "fs/hfsplus/Kconfig" + source "fs/befs/Kconfig" + source "fs/bfs/Kconfig" + source "fs/efs/Kconfig" ++source "fs/yaffs2/Kconfig" + source "fs/jffs2/Kconfig" + # UBIFS File system configuration + source "fs/ubifs/Kconfig" +diff --git a/fs/Makefile b/fs/Makefile +index 2fb97793..79b94ebe 100644 +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -125,3 +125,4 @@ obj-$(CONFIG_GFS2_FS) += gfs2/ + obj-y += exofs/ # Multiple modules + obj-$(CONFIG_CEPH_FS) += ceph/ + obj-$(CONFIG_PSTORE) += pstore/ ++obj-$(CONFIG_YAFFS_FS) += yaffs2/ +diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c +index 1090eb64..9797fadc 100644 +--- a/fs/jffs2/debug.c ++++ b/fs/jffs2/debug.c +@@ -264,13 +264,11 @@ void __jffs2_dbg_superblock_counts(struct jffs2_sb_info *c) + } + + #define check(sz) \ +-do { \ + if (sz != c->sz##_size) { \ + pr_warn("%s_size mismatch counted 0x%x, c->%s_size 0x%x\n", \ + #sz, sz, #sz, c->sz##_size); \ +- dump = 1; \ +- } \ +-} while (0) ++ dump = 1; \ ++ } + + check(free); + check(dirty); +diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c +index 8608f877..fc4535d2 100644 +--- a/fs/jffs2/file.c ++++ b/fs/jffs2/file.c +@@ -138,39 +138,33 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, + struct page *pg; + struct inode *inode = mapping->host; + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); +- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); +- struct jffs2_raw_inode ri; +- uint32_t alloc_len = 0; + pgoff_t index = pos >> PAGE_CACHE_SHIFT; + uint32_t pageofs = index << PAGE_CACHE_SHIFT; + int ret = 0; + +- jffs2_dbg(1, "%s()\n", __func__); +- +- if (pageofs > inode->i_size) { +- ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, +- ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); +- if (ret) +- return ret; +- } +- +- mutex_lock(&f->sem); + pg = grab_cache_page_write_begin(mapping, index, flags); +- if (!pg) { +- if (alloc_len) +- jffs2_complete_reservation(c); +- mutex_unlock(&f->sem); ++ if (!pg) + return -ENOMEM; +- } + *pagep = pg; + +- if (alloc_len) { ++ D1(printk(KERN_DEBUG "jffs2_write_begin()\n")); ++ ++ if (pageofs > inode->i_size) { + /* Make new hole frag from old EOF to new page */ ++ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); ++ struct jffs2_raw_inode ri; + struct jffs2_full_dnode *fn; ++ uint32_t alloc_len; + + jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", + (unsigned int)inode->i_size, pageofs); + ++ ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, ++ ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); ++ if (ret) ++ goto out_page; ++ ++ mutex_lock(&f->sem); + memset(&ri, 0, sizeof(ri)); + + ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); +@@ -197,6 +191,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, + if (IS_ERR(fn)) { + ret = PTR_ERR(fn); + jffs2_complete_reservation(c); ++ mutex_unlock(&f->sem); + goto out_page; + } + ret = jffs2_add_full_dnode_to_inode(c, f, fn); +@@ -211,10 +206,12 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, + jffs2_mark_node_obsolete(c, fn->raw); + jffs2_free_full_dnode(fn); + jffs2_complete_reservation(c); ++ mutex_unlock(&f->sem); + goto out_page; + } + jffs2_complete_reservation(c); + inode->i_size = pageofs; ++ mutex_unlock(&f->sem); + } + + /* +@@ -223,18 +220,18 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, + * case of a short-copy. + */ + if (!PageUptodate(pg)) { ++ mutex_lock(&f->sem); + ret = jffs2_do_readpage_nolock(inode, pg); ++ mutex_unlock(&f->sem); + if (ret) + goto out_page; + } +- mutex_unlock(&f->sem); + jffs2_dbg(1, "end write_begin(). pg->flags %lx\n", pg->flags); + return ret; + + out_page: + unlock_page(pg); + page_cache_release(pg); +- mutex_unlock(&f->sem); + return ret; + } + +diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c +index bb6f993e..a5499837 100644 +--- a/fs/jffs2/fs.c ++++ b/fs/jffs2/fs.c +@@ -585,6 +585,8 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) + jffs2_start_garbage_collect_thread(c); + return 0; + ++ out_root_i: ++ iput(root_i); + out_root: + jffs2_free_ino_caches(c); + jffs2_free_raw_node_refs(c); +diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c +index 5a2dec2b..ad271c70 100644 +--- a/fs/jffs2/gc.c ++++ b/fs/jffs2/gc.c +@@ -234,8 +234,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) + return 0; + + jffs2_dbg(1, "No progress from erasing block; doing GC anyway\n"); +- mutex_lock(&c->alloc_sem); + spin_lock(&c->erase_completion_lock); ++ mutex_lock(&c->alloc_sem); + } + + /* First, work out which block we're garbage-collecting */ +diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c +index ffa8f12c..6784d1e7 100644 +--- a/fs/jffs2/nodemgmt.c ++++ b/fs/jffs2/nodemgmt.c +@@ -375,16 +375,14 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, + spin_unlock(&c->erase_completion_lock); + + ret = jffs2_prealloc_raw_node_refs(c, jeb, 1); +- ++ if (ret) ++ return ret; + /* Just lock it again and continue. Nothing much can change because + we hold c->alloc_sem anyway. In fact, it's not entirely clear why + we hold c->erase_completion_lock in the majority of this function... + but that's a question for another (more caffeine-rich) day. */ + spin_lock(&c->erase_completion_lock); + +- if (ret) +- return ret; +- + waste = jeb->free_size; + jffs2_link_node_ref(c, jeb, + (jeb->offset + c->sector_size - waste) | REF_OBSOLETE, +diff --git a/fs/yaffs2/Kconfig b/fs/yaffs2/Kconfig +new file mode 100644 +index 00000000..408570fc +--- /dev/null ++++ b/fs/yaffs2/Kconfig +@@ -0,0 +1,171 @@ ++# ++# yaffs file system configurations ++# ++ ++config YAFFS_FS ++ tristate "yaffs2 file system support" ++ default n ++ depends on MTD_BLOCK ++ select YAFFS_YAFFS1 ++ select YAFFS_YAFFS2 ++ help ++ yaffs2, or Yet Another Flash File System, is a file system ++ optimised for NAND Flash chips. ++ ++ To compile the yaffs2 file system support as a module, choose M ++ here: the module will be called yaffs2. ++ ++ If unsure, say N. ++ ++ Further information on yaffs2 is available at ++ . ++ ++config YAFFS_YAFFS1 ++ bool "512 byte / page devices" ++ depends on YAFFS_FS ++ default y ++ help ++ Enable yaffs1 support -- yaffs for 512 byte / page devices ++ ++ Not needed for 2K-page devices. ++ ++ If unsure, say Y. ++ ++config YAFFS_9BYTE_TAGS ++ bool "Use older-style on-NAND data format with pageStatus byte" ++ depends on YAFFS_YAFFS1 ++ default n ++ help ++ ++ Older-style on-NAND data format has a "pageStatus" byte to record ++ chunk/page state. This byte is zero when the page is discarded. ++ Choose this option if you have existing on-NAND data using this ++ format that you need to continue to support. New data written ++ also uses the older-style format. Note: Use of this option ++ generally requires that MTD's oob layout be adjusted to use the ++ older-style format. See notes on tags formats and MTD versions ++ in yaffs_mtdif1.c. ++ ++ If unsure, say N. ++ ++config YAFFS_DOES_ECC ++ bool "Lets yaffs do its own ECC" ++ depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS ++ default n ++ help ++ This enables yaffs to use its own ECC functions instead of using ++ the ones from the generic MTD-NAND driver. ++ ++ If unsure, say N. ++ ++config YAFFS_ECC_WRONG_ORDER ++ bool "Use the same ecc byte order as Steven Hill's nand_ecc.c" ++ depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS ++ default n ++ help ++ This makes yaffs_ecc.c use the same ecc byte order as Steven ++ Hill's nand_ecc.c. If not set, then you get the same ecc byte ++ order as SmartMedia. ++ ++ If unsure, say N. ++ ++config YAFFS_YAFFS2 ++ bool "2048 byte (or larger) / page devices" ++ depends on YAFFS_FS ++ default y ++ help ++ Enable yaffs2 support -- yaffs for >= 2K bytes per page devices ++ ++ If unsure, say Y. ++ ++config YAFFS_AUTO_YAFFS2 ++ bool "Autoselect yaffs2 format" ++ depends on YAFFS_YAFFS2 ++ default y ++ help ++ Without this, you need to explicitely use yaffs2 as the file ++ system type. With this, you can say "yaffs" and yaffs or yaffs2 ++ will be used depending on the device page size (yaffs on ++ 512-byte page devices, yaffs2 on 2K page devices). ++ ++ If unsure, say Y. ++ ++config YAFFS_DISABLE_TAGS_ECC ++ bool "Disable yaffs from doing ECC on tags by default" ++ depends on YAFFS_FS && YAFFS_YAFFS2 ++ default n ++ help ++ This defaults yaffs to using its own ECC calculations on tags instead of ++ just relying on the MTD. ++ This behavior can also be overridden with tags_ecc_on and ++ tags_ecc_off mount options. ++ ++ If unsure, say N. ++ ++config YAFFS_ALWAYS_CHECK_CHUNK_ERASED ++ bool "Force chunk erase check" ++ depends on YAFFS_FS ++ default n ++ help ++ Normally yaffs only checks chunks before writing until an erased ++ chunk is found. This helps to detect any partially written ++ chunks that might have happened due to power loss. ++ ++ Enabling this forces on the test that chunks are erased in flash ++ before writing to them. This takes more time but is potentially ++ a bit more secure. ++ ++ Suggest setting Y during development and ironing out driver ++ issues etc. Suggest setting to N if you want faster writing. ++ ++ If unsure, say Y. ++ ++config YAFFS_EMPTY_LOST_AND_FOUND ++ bool "Empty lost and found on boot" ++ depends on YAFFS_FS ++ default n ++ help ++ If this is enabled then the contents of lost and found is ++ automatically dumped at mount. ++ ++ If unsure, say N. ++ ++config YAFFS_DISABLE_BLOCK_REFRESHING ++ bool "Disable yaffs2 block refreshing" ++ depends on YAFFS_FS ++ default n ++ help ++ If this is set, then block refreshing is disabled. ++ Block refreshing infrequently refreshes the oldest block in ++ a yaffs2 file system. This mechanism helps to refresh flash to ++ mitigate against data loss. This is particularly useful for MLC. ++ ++ If unsure, say N. ++ ++config YAFFS_DISABLE_BACKGROUND ++ bool "Disable yaffs2 background processing" ++ depends on YAFFS_FS ++ default n ++ help ++ If this is set, then background processing is disabled. ++ Background processing makes many foreground activities faster. ++ ++ If unsure, say N. ++ ++config YAFFS_DISABLE_BAD_BLOCK_MARKING ++ bool "Disable yaffs2 bad block marking" ++ depends on YAFFS_FS ++ default n ++ help ++ Useful during early flash bring up to prevent problems causing ++ lots of bad block marking. ++ ++ If unsure, say N. ++ ++config YAFFS_XATTR ++ bool "Enable yaffs2 xattr support" ++ depends on YAFFS_FS ++ default y ++ help ++ If this is set then yaffs2 will provide xattr support. ++ If unsure, say Y. +diff --git a/fs/yaffs2/Makefile b/fs/yaffs2/Makefile +new file mode 100644 +index 00000000..f9a9fb1b +--- /dev/null ++++ b/fs/yaffs2/Makefile +@@ -0,0 +1,18 @@ ++# ++# Makefile for the linux YAFFS filesystem routines. ++# ++ ++obj-$(CONFIG_YAFFS_FS) += yaffs.o ++ ++yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o ++yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o ++yaffs-y += yaffs_tagscompat.o yaffs_tagsmarshall.o ++yaffs-y += yaffs_mtdif.o ++yaffs-y += yaffs_nameval.o yaffs_attribs.o ++yaffs-y += yaffs_allocator.o ++yaffs-y += yaffs_yaffs1.o ++yaffs-y += yaffs_yaffs2.o ++yaffs-y += yaffs_bitmap.o ++yaffs-y += yaffs_summary.o ++yaffs-y += yaffs_verify.o ++ +diff --git a/fs/yaffs2/yaffs_allocator.c b/fs/yaffs2/yaffs_allocator.c +new file mode 100644 +index 00000000..c8f2861c +--- /dev/null ++++ b/fs/yaffs2/yaffs_allocator.c +@@ -0,0 +1,357 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_allocator.h" ++#include "yaffs_guts.h" ++#include "yaffs_trace.h" ++#include "yportenv.h" ++ ++/* ++ * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks ++ * of approx 100 objects that are themn allocated singly. ++ * This is basically a simplified slab allocator. ++ * ++ * We don't use the Linux slab allocator because slab does not allow ++ * us to dump all the objects in one hit when we do a umount and tear ++ * down all the tnodes and objects. slab requires that we first free ++ * the individual objects. ++ * ++ * Once yaffs has been mainlined I shall try to motivate for a change ++ * to slab to provide the extra features we need here. ++ */ ++ ++struct yaffs_tnode_list { ++ struct yaffs_tnode_list *next; ++ struct yaffs_tnode *tnodes; ++}; ++ ++struct yaffs_obj_list { ++ struct yaffs_obj_list *next; ++ struct yaffs_obj *objects; ++}; ++ ++struct yaffs_allocator { ++ int n_tnodes_created; ++ struct yaffs_tnode *free_tnodes; ++ int n_free_tnodes; ++ struct yaffs_tnode_list *alloc_tnode_list; ++ ++ int n_obj_created; ++ struct list_head free_objs; ++ int n_free_objects; ++ ++ struct yaffs_obj_list *allocated_obj_list; ++}; ++ ++static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev) ++{ ++ struct yaffs_allocator *allocator = ++ (struct yaffs_allocator *)dev->allocator; ++ struct yaffs_tnode_list *tmp; ++ ++ if (!allocator) { ++ BUG(); ++ return; ++ } ++ ++ while (allocator->alloc_tnode_list) { ++ tmp = allocator->alloc_tnode_list->next; ++ ++ kfree(allocator->alloc_tnode_list->tnodes); ++ kfree(allocator->alloc_tnode_list); ++ allocator->alloc_tnode_list = tmp; ++ } ++ ++ allocator->free_tnodes = NULL; ++ allocator->n_free_tnodes = 0; ++ allocator->n_tnodes_created = 0; ++} ++ ++static void yaffs_init_raw_tnodes(struct yaffs_dev *dev) ++{ ++ struct yaffs_allocator *allocator = dev->allocator; ++ ++ if (!allocator) { ++ BUG(); ++ return; ++ } ++ ++ allocator->alloc_tnode_list = NULL; ++ allocator->free_tnodes = NULL; ++ allocator->n_free_tnodes = 0; ++ allocator->n_tnodes_created = 0; ++} ++ ++static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes) ++{ ++ struct yaffs_allocator *allocator = ++ (struct yaffs_allocator *)dev->allocator; ++ int i; ++ struct yaffs_tnode *new_tnodes; ++ u8 *mem; ++ struct yaffs_tnode *curr; ++ struct yaffs_tnode *next; ++ struct yaffs_tnode_list *tnl; ++ ++ if (!allocator) { ++ BUG(); ++ return YAFFS_FAIL; ++ } ++ ++ if (n_tnodes < 1) ++ return YAFFS_OK; ++ ++ /* make these things */ ++ new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS); ++ mem = (u8 *) new_tnodes; ++ ++ if (!new_tnodes) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs: Could not allocate Tnodes"); ++ return YAFFS_FAIL; ++ } ++ ++ /* New hookup for wide tnodes */ ++ for (i = 0; i < n_tnodes - 1; i++) { ++ curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size]; ++ next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size]; ++ curr->internal[0] = next; ++ } ++ ++ curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size]; ++ curr->internal[0] = allocator->free_tnodes; ++ allocator->free_tnodes = (struct yaffs_tnode *)mem; ++ ++ allocator->n_free_tnodes += n_tnodes; ++ allocator->n_tnodes_created += n_tnodes; ++ ++ /* Now add this bunch of tnodes to a list for freeing up. ++ * NB If we can't add this to the management list it isn't fatal ++ * but it just means we can't free this bunch of tnodes later. ++ */ ++ tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS); ++ if (!tnl) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "Could not add tnodes to management list"); ++ return YAFFS_FAIL; ++ } else { ++ tnl->tnodes = new_tnodes; ++ tnl->next = allocator->alloc_tnode_list; ++ allocator->alloc_tnode_list = tnl; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added"); ++ ++ return YAFFS_OK; ++} ++ ++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev) ++{ ++ struct yaffs_allocator *allocator = ++ (struct yaffs_allocator *)dev->allocator; ++ struct yaffs_tnode *tn = NULL; ++ ++ if (!allocator) { ++ BUG(); ++ return NULL; ++ } ++ ++ /* If there are none left make more */ ++ if (!allocator->free_tnodes) ++ yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES); ++ ++ if (allocator->free_tnodes) { ++ tn = allocator->free_tnodes; ++ allocator->free_tnodes = allocator->free_tnodes->internal[0]; ++ allocator->n_free_tnodes--; ++ } ++ ++ return tn; ++} ++ ++/* FreeTnode frees up a tnode and puts it back on the free list */ ++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) ++{ ++ struct yaffs_allocator *allocator = dev->allocator; ++ ++ if (!allocator) { ++ BUG(); ++ return; ++ } ++ ++ if (tn) { ++ tn->internal[0] = allocator->free_tnodes; ++ allocator->free_tnodes = tn; ++ allocator->n_free_tnodes++; ++ } ++ dev->checkpoint_blocks_required = 0; /* force recalculation */ ++} ++ ++/*--------------- yaffs_obj alloaction ------------------------ ++ * ++ * Free yaffs_objs are stored in a list using obj->siblings. ++ * The blocks of allocated objects are stored in a linked list. ++ */ ++ ++static void yaffs_init_raw_objs(struct yaffs_dev *dev) ++{ ++ struct yaffs_allocator *allocator = dev->allocator; ++ ++ if (!allocator) { ++ BUG(); ++ return; ++ } ++ ++ allocator->allocated_obj_list = NULL; ++ INIT_LIST_HEAD(&allocator->free_objs); ++ allocator->n_free_objects = 0; ++} ++ ++static void yaffs_deinit_raw_objs(struct yaffs_dev *dev) ++{ ++ struct yaffs_allocator *allocator = dev->allocator; ++ struct yaffs_obj_list *tmp; ++ ++ if (!allocator) { ++ BUG(); ++ return; ++ } ++ ++ while (allocator->allocated_obj_list) { ++ tmp = allocator->allocated_obj_list->next; ++ kfree(allocator->allocated_obj_list->objects); ++ kfree(allocator->allocated_obj_list); ++ allocator->allocated_obj_list = tmp; ++ } ++ ++ INIT_LIST_HEAD(&allocator->free_objs); ++ allocator->n_free_objects = 0; ++ allocator->n_obj_created = 0; ++} ++ ++static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj) ++{ ++ struct yaffs_allocator *allocator = dev->allocator; ++ int i; ++ struct yaffs_obj *new_objs; ++ struct yaffs_obj_list *list; ++ ++ if (!allocator) { ++ BUG(); ++ return YAFFS_FAIL; ++ } ++ ++ if (n_obj < 1) ++ return YAFFS_OK; ++ ++ /* make these things */ ++ new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS); ++ list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS); ++ ++ if (!new_objs || !list) { ++ kfree(new_objs); ++ new_objs = NULL; ++ kfree(list); ++ list = NULL; ++ yaffs_trace(YAFFS_TRACE_ALLOCATE, ++ "Could not allocate more objects"); ++ return YAFFS_FAIL; ++ } ++ ++ /* Hook them into the free list */ ++ for (i = 0; i < n_obj; i++) ++ list_add(&new_objs[i].siblings, &allocator->free_objs); ++ ++ allocator->n_free_objects += n_obj; ++ allocator->n_obj_created += n_obj; ++ ++ /* Now add this bunch of Objects to a list for freeing up. */ ++ ++ list->objects = new_objs; ++ list->next = allocator->allocated_obj_list; ++ allocator->allocated_obj_list = list; ++ ++ return YAFFS_OK; ++} ++ ++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev) ++{ ++ struct yaffs_obj *obj = NULL; ++ struct list_head *lh; ++ struct yaffs_allocator *allocator = dev->allocator; ++ ++ if (!allocator) { ++ BUG(); ++ return obj; ++ } ++ ++ /* If there are none left make more */ ++ if (list_empty(&allocator->free_objs)) ++ yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS); ++ ++ if (!list_empty(&allocator->free_objs)) { ++ lh = allocator->free_objs.next; ++ obj = list_entry(lh, struct yaffs_obj, siblings); ++ list_del_init(lh); ++ allocator->n_free_objects--; ++ } ++ ++ return obj; ++} ++ ++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj) ++{ ++ ++ struct yaffs_allocator *allocator = dev->allocator; ++ ++ if (!allocator) { ++ BUG(); ++ return; ++ } ++ ++ /* Link into the free list. */ ++ list_add(&obj->siblings, &allocator->free_objs); ++ allocator->n_free_objects++; ++} ++ ++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev) ++{ ++ ++ if (!dev->allocator) { ++ BUG(); ++ return; ++ } ++ ++ yaffs_deinit_raw_tnodes(dev); ++ yaffs_deinit_raw_objs(dev); ++ kfree(dev->allocator); ++ dev->allocator = NULL; ++} ++ ++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev) ++{ ++ struct yaffs_allocator *allocator; ++ ++ if (dev->allocator) { ++ BUG(); ++ return; ++ } ++ ++ allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS); ++ if (allocator) { ++ dev->allocator = allocator; ++ yaffs_init_raw_tnodes(dev); ++ yaffs_init_raw_objs(dev); ++ } ++} ++ +diff --git a/fs/yaffs2/yaffs_allocator.h b/fs/yaffs2/yaffs_allocator.h +new file mode 100644 +index 00000000..a8cc3226 +--- /dev/null ++++ b/fs/yaffs2/yaffs_allocator.h +@@ -0,0 +1,30 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_ALLOCATOR_H__ ++#define __YAFFS_ALLOCATOR_H__ ++ ++#include "yaffs_guts.h" ++ ++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev); ++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev); ++ ++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev); ++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn); ++ ++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev); ++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj); ++ ++#endif +diff --git a/fs/yaffs2/yaffs_attribs.c b/fs/yaffs2/yaffs_attribs.c +new file mode 100644 +index 00000000..3d778f22 +--- /dev/null ++++ b/fs/yaffs2/yaffs_attribs.c +@@ -0,0 +1,124 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_guts.h" ++#include "yaffs_attribs.h" ++ ++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh) ++{ ++ obj->yst_uid = oh->yst_uid; ++ obj->yst_gid = oh->yst_gid; ++ obj->yst_atime = oh->yst_atime; ++ obj->yst_mtime = oh->yst_mtime; ++ obj->yst_ctime = oh->yst_ctime; ++ obj->yst_rdev = oh->yst_rdev; ++} ++ ++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj) ++{ ++ oh->yst_uid = obj->yst_uid; ++ oh->yst_gid = obj->yst_gid; ++ oh->yst_atime = obj->yst_atime; ++ oh->yst_mtime = obj->yst_mtime; ++ oh->yst_ctime = obj->yst_ctime; ++ oh->yst_rdev = obj->yst_rdev; ++ ++} ++ ++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c) ++{ ++ obj->yst_mtime = Y_CURRENT_TIME; ++ if (do_a) ++ obj->yst_atime = obj->yst_mtime; ++ if (do_c) ++ obj->yst_ctime = obj->yst_mtime; ++} ++ ++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev) ++{ ++ yaffs_load_current_time(obj, 1, 1); ++ obj->yst_rdev = rdev; ++ obj->yst_uid = uid; ++ obj->yst_gid = gid; ++} ++ ++static loff_t yaffs_get_file_size(struct yaffs_obj *obj) ++{ ++ YCHAR *alias = NULL; ++ obj = yaffs_get_equivalent_obj(obj); ++ ++ switch (obj->variant_type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ return obj->variant.file_variant.file_size; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ alias = obj->variant.symlink_variant.alias; ++ if (!alias) ++ return 0; ++ return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH); ++ default: ++ return 0; ++ } ++} ++ ++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr) ++{ ++ unsigned int valid = attr->ia_valid; ++ ++ if (valid & ATTR_MODE) ++ obj->yst_mode = attr->ia_mode; ++ if (valid & ATTR_UID) ++ obj->yst_uid = attr->ia_uid; ++ if (valid & ATTR_GID) ++ obj->yst_gid = attr->ia_gid; ++ ++ if (valid & ATTR_ATIME) ++ obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime); ++ if (valid & ATTR_CTIME) ++ obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime); ++ if (valid & ATTR_MTIME) ++ obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime); ++ ++ if (valid & ATTR_SIZE) ++ yaffs_resize_file(obj, attr->ia_size); ++ ++ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); ++ ++ return YAFFS_OK; ++ ++} ++ ++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr) ++{ ++ unsigned int valid = 0; ++ ++ attr->ia_mode = obj->yst_mode; ++ valid |= ATTR_MODE; ++ attr->ia_uid = obj->yst_uid; ++ valid |= ATTR_UID; ++ attr->ia_gid = obj->yst_gid; ++ valid |= ATTR_GID; ++ ++ Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime; ++ valid |= ATTR_ATIME; ++ Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime; ++ valid |= ATTR_CTIME; ++ Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime; ++ valid |= ATTR_MTIME; ++ ++ attr->ia_size = yaffs_get_file_size(obj); ++ valid |= ATTR_SIZE; ++ ++ attr->ia_valid = valid; ++ ++ return YAFFS_OK; ++} +diff --git a/fs/yaffs2/yaffs_attribs.h b/fs/yaffs2/yaffs_attribs.h +new file mode 100644 +index 00000000..5b21b085 +--- /dev/null ++++ b/fs/yaffs2/yaffs_attribs.h +@@ -0,0 +1,28 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_ATTRIBS_H__ ++#define __YAFFS_ATTRIBS_H__ ++ ++#include "yaffs_guts.h" ++ ++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh); ++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj); ++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev); ++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c); ++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr); ++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr); ++ ++#endif +diff --git a/fs/yaffs2/yaffs_bitmap.c b/fs/yaffs2/yaffs_bitmap.c +new file mode 100644 +index 00000000..4440e930 +--- /dev/null ++++ b/fs/yaffs2/yaffs_bitmap.c +@@ -0,0 +1,97 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_bitmap.h" ++#include "yaffs_trace.h" ++/* ++ * Chunk bitmap manipulations ++ */ ++ ++static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk) ++{ ++ if (blk < dev->internal_start_block || blk > dev->internal_end_block) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "BlockBits block %d is not valid", ++ blk); ++ BUG(); ++ } ++ return dev->chunk_bits + ++ (dev->chunk_bit_stride * (blk - dev->internal_start_block)); ++} ++ ++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk) ++{ ++ if (blk < dev->internal_start_block || blk > dev->internal_end_block || ++ chunk < 0 || chunk >= dev->param.chunks_per_block) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "Chunk Id (%d:%d) invalid", ++ blk, chunk); ++ BUG(); ++ } ++} ++ ++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk) ++{ ++ u8 *blk_bits = yaffs_block_bits(dev, blk); ++ ++ memset(blk_bits, 0, dev->chunk_bit_stride); ++} ++ ++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) ++{ ++ u8 *blk_bits = yaffs_block_bits(dev, blk); ++ ++ yaffs_verify_chunk_bit_id(dev, blk, chunk); ++ blk_bits[chunk / 8] &= ~(1 << (chunk & 7)); ++} ++ ++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) ++{ ++ u8 *blk_bits = yaffs_block_bits(dev, blk); ++ ++ yaffs_verify_chunk_bit_id(dev, blk, chunk); ++ blk_bits[chunk / 8] |= (1 << (chunk & 7)); ++} ++ ++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) ++{ ++ u8 *blk_bits = yaffs_block_bits(dev, blk); ++ ++ yaffs_verify_chunk_bit_id(dev, blk, chunk); ++ return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; ++} ++ ++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk) ++{ ++ u8 *blk_bits = yaffs_block_bits(dev, blk); ++ int i; ++ ++ for (i = 0; i < dev->chunk_bit_stride; i++) { ++ if (*blk_bits) ++ return 1; ++ blk_bits++; ++ } ++ return 0; ++} ++ ++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk) ++{ ++ u8 *blk_bits = yaffs_block_bits(dev, blk); ++ int i; ++ int n = 0; ++ ++ for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++) ++ n += hweight8(*blk_bits); ++ ++ return n; ++} +diff --git a/fs/yaffs2/yaffs_bitmap.h b/fs/yaffs2/yaffs_bitmap.h +new file mode 100644 +index 00000000..e26b37d8 +--- /dev/null ++++ b/fs/yaffs2/yaffs_bitmap.h +@@ -0,0 +1,33 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* ++ * Chunk bitmap manipulations ++ */ ++ ++#ifndef __YAFFS_BITMAP_H__ ++#define __YAFFS_BITMAP_H__ ++ ++#include "yaffs_guts.h" ++ ++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk); ++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk); ++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); ++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); ++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); ++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk); ++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk); ++ ++#endif +diff --git a/fs/yaffs2/yaffs_checkptrw.c b/fs/yaffs2/yaffs_checkptrw.c +new file mode 100644 +index 00000000..e739fb4a +--- /dev/null ++++ b/fs/yaffs2/yaffs_checkptrw.c +@@ -0,0 +1,474 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_checkptrw.h" ++#include "yaffs_getblockinfo.h" ++ ++struct yaffs_checkpt_chunk_hdr { ++ int version; ++ int seq; ++ u32 sum; ++ u32 xor; ++} ; ++ ++ ++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk) ++{ ++ return chunk - dev->chunk_offset; ++} ++ ++static int apply_block_offset(struct yaffs_dev *dev, int block) ++{ ++ return block - dev->block_offset; ++} ++ ++static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev) ++{ ++ struct yaffs_checkpt_chunk_hdr hdr; ++ ++ hdr.version = YAFFS_CHECKPOINT_VERSION; ++ hdr.seq = dev->checkpt_page_seq; ++ hdr.sum = dev->checkpt_sum; ++ hdr.xor = dev->checkpt_xor; ++ ++ dev->checkpt_byte_offs = sizeof(hdr); ++ ++ memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr)); ++} ++ ++static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev) ++{ ++ struct yaffs_checkpt_chunk_hdr hdr; ++ ++ memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr)); ++ ++ dev->checkpt_byte_offs = sizeof(hdr); ++ ++ return hdr.version == YAFFS_CHECKPOINT_VERSION && ++ hdr.seq == dev->checkpt_page_seq && ++ hdr.sum == dev->checkpt_sum && ++ hdr.xor == dev->checkpt_xor; ++} ++ ++static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev) ++{ ++ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "checkpt blocks_avail = %d", blocks_avail); ++ ++ return (blocks_avail <= 0) ? 0 : 1; ++} ++ ++static int yaffs_checkpt_erase(struct yaffs_dev *dev) ++{ ++ int i; ++ ++ if (!dev->drv.drv_erase_fn) ++ return 0; ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "checking blocks %d to %d", ++ dev->internal_start_block, dev->internal_end_block); ++ ++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i); ++ int offset_i = apply_block_offset(dev, i); ++ int result; ++ ++ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "erasing checkpt block %d", i); ++ ++ dev->n_erasures++; ++ ++ result = dev->drv.drv_erase_fn(dev, offset_i); ++ if(result) { ++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY; ++ dev->n_erased_blocks++; ++ dev->n_free_chunks += ++ dev->param.chunks_per_block; ++ } else { ++ dev->drv.drv_mark_bad_fn(dev, offset_i); ++ bi->block_state = YAFFS_BLOCK_STATE_DEAD; ++ } ++ } ++ } ++ ++ dev->blocks_in_checkpt = 0; ++ ++ return 1; ++} ++ ++static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev) ++{ ++ int i; ++ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "allocating checkpt block: erased %d reserved %d avail %d next %d ", ++ dev->n_erased_blocks, dev->param.n_reserved_blocks, ++ blocks_avail, dev->checkpt_next_block); ++ ++ if (dev->checkpt_next_block >= 0 && ++ dev->checkpt_next_block <= dev->internal_end_block && ++ blocks_avail > 0) { ++ ++ for (i = dev->checkpt_next_block; i <= dev->internal_end_block; ++ i++) { ++ struct yaffs_block_info *bi; ++ ++ bi = yaffs_get_block_info(dev, i); ++ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { ++ dev->checkpt_next_block = i + 1; ++ dev->checkpt_cur_block = i; ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "allocating checkpt block %d", i); ++ return; ++ } ++ } ++ } ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks"); ++ ++ dev->checkpt_next_block = -1; ++ dev->checkpt_cur_block = -1; ++} ++ ++static void yaffs2_checkpt_find_block(struct yaffs_dev *dev) ++{ ++ int i; ++ struct yaffs_ext_tags tags; ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "find next checkpt block: start: blocks %d next %d", ++ dev->blocks_in_checkpt, dev->checkpt_next_block); ++ ++ if (dev->blocks_in_checkpt < dev->checkpt_max_blocks) ++ for (i = dev->checkpt_next_block; i <= dev->internal_end_block; ++ i++) { ++ int chunk = i * dev->param.chunks_per_block; ++ enum yaffs_block_state state; ++ u32 seq; ++ ++ dev->tagger.read_chunk_tags_fn(dev, ++ apply_chunk_offset(dev, chunk), ++ NULL, &tags); ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "find next checkpt block: search: block %d state %d oid %d seq %d eccr %d", ++ i, (int) state, ++ tags.obj_id, tags.seq_number, ++ tags.ecc_result); ++ ++ if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) ++ continue; ++ ++ dev->tagger.query_block_fn(dev, ++ apply_block_offset(dev, i), ++ &state, &seq); ++ if (state == YAFFS_BLOCK_STATE_DEAD) ++ continue; ++ ++ /* Right kind of block */ ++ dev->checkpt_next_block = tags.obj_id; ++ dev->checkpt_cur_block = i; ++ dev->checkpt_block_list[dev->blocks_in_checkpt] = i; ++ dev->blocks_in_checkpt++; ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "found checkpt block %d", i); ++ return; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks"); ++ ++ dev->checkpt_next_block = -1; ++ dev->checkpt_cur_block = -1; ++} ++ ++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing) ++{ ++ int i; ++ ++ dev->checkpt_open_write = writing; ++ ++ /* Got the functions we need? */ ++ if (!dev->tagger.write_chunk_tags_fn || ++ !dev->tagger.read_chunk_tags_fn || ++ !dev->drv.drv_erase_fn || ++ !dev->drv.drv_mark_bad_fn) ++ return 0; ++ ++ if (writing && !yaffs2_checkpt_space_ok(dev)) ++ return 0; ++ ++ if (!dev->checkpt_buffer) ++ dev->checkpt_buffer = ++ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); ++ if (!dev->checkpt_buffer) ++ return 0; ++ ++ dev->checkpt_page_seq = 0; ++ dev->checkpt_byte_count = 0; ++ dev->checkpt_sum = 0; ++ dev->checkpt_xor = 0; ++ dev->checkpt_cur_block = -1; ++ dev->checkpt_cur_chunk = -1; ++ dev->checkpt_next_block = dev->internal_start_block; ++ ++ if (writing) { ++ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); ++ yaffs2_checkpt_init_chunk_hdr(dev); ++ return yaffs_checkpt_erase(dev); ++ } ++ ++ /* Opening for a read */ ++ /* Set to a value that will kick off a read */ ++ dev->checkpt_byte_offs = dev->data_bytes_per_chunk; ++ /* A checkpoint block list of 1 checkpoint block per 16 block is ++ * (hopefully) going to be way more than we need */ ++ dev->blocks_in_checkpt = 0; ++ dev->checkpt_max_blocks = ++ (dev->internal_end_block - dev->internal_start_block) / 16 + 2; ++ dev->checkpt_block_list = ++ kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS); ++ ++ if (!dev->checkpt_block_list) ++ return 0; ++ ++ for (i = 0; i < dev->checkpt_max_blocks; i++) ++ dev->checkpt_block_list[i] = -1; ++ ++ return 1; ++} ++ ++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum) ++{ ++ u32 composite_sum; ++ ++ composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff); ++ *sum = composite_sum; ++ return 1; ++} ++ ++static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev) ++{ ++ int chunk; ++ int offset_chunk; ++ struct yaffs_ext_tags tags; ++ ++ if (dev->checkpt_cur_block < 0) { ++ yaffs2_checkpt_find_erased_block(dev); ++ dev->checkpt_cur_chunk = 0; ++ } ++ ++ if (dev->checkpt_cur_block < 0) ++ return 0; ++ ++ tags.is_deleted = 0; ++ tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */ ++ tags.chunk_id = dev->checkpt_page_seq + 1; ++ tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA; ++ tags.n_bytes = dev->data_bytes_per_chunk; ++ if (dev->checkpt_cur_chunk == 0) { ++ /* First chunk we write for the block? Set block state to ++ checkpoint */ ++ struct yaffs_block_info *bi = ++ yaffs_get_block_info(dev, dev->checkpt_cur_block); ++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; ++ dev->blocks_in_checkpt++; ++ } ++ ++ chunk = ++ dev->checkpt_cur_block * dev->param.chunks_per_block + ++ dev->checkpt_cur_chunk; ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d", ++ chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, ++ tags.obj_id, tags.chunk_id); ++ ++ offset_chunk = apply_chunk_offset(dev, chunk); ++ ++ dev->n_page_writes++; ++ ++ dev->tagger.write_chunk_tags_fn(dev, offset_chunk, ++ dev->checkpt_buffer, &tags); ++ dev->checkpt_page_seq++; ++ dev->checkpt_cur_chunk++; ++ if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) { ++ dev->checkpt_cur_chunk = 0; ++ dev->checkpt_cur_block = -1; ++ } ++ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); ++ ++ yaffs2_checkpt_init_chunk_hdr(dev); ++ ++ ++ return 1; ++} ++ ++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes) ++{ ++ int i = 0; ++ int ok = 1; ++ u8 *data_bytes = (u8 *) data; ++ ++ if (!dev->checkpt_buffer) ++ return 0; ++ ++ if (!dev->checkpt_open_write) ++ return -1; ++ ++ while (i < n_bytes && ok) { ++ dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes; ++ dev->checkpt_sum += *data_bytes; ++ dev->checkpt_xor ^= *data_bytes; ++ ++ dev->checkpt_byte_offs++; ++ i++; ++ data_bytes++; ++ dev->checkpt_byte_count++; ++ ++ if (dev->checkpt_byte_offs < 0 || ++ dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) ++ ok = yaffs2_checkpt_flush_buffer(dev); ++ } ++ ++ return i; ++} ++ ++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes) ++{ ++ int i = 0; ++ int ok = 1; ++ struct yaffs_ext_tags tags; ++ int chunk; ++ int offset_chunk; ++ u8 *data_bytes = (u8 *) data; ++ ++ if (!dev->checkpt_buffer) ++ return 0; ++ ++ if (dev->checkpt_open_write) ++ return -1; ++ ++ while (i < n_bytes && ok) { ++ ++ if (dev->checkpt_byte_offs < 0 || ++ dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) { ++ ++ if (dev->checkpt_cur_block < 0) { ++ yaffs2_checkpt_find_block(dev); ++ dev->checkpt_cur_chunk = 0; ++ } ++ ++ if (dev->checkpt_cur_block < 0) { ++ ok = 0; ++ break; ++ } ++ ++ chunk = dev->checkpt_cur_block * ++ dev->param.chunks_per_block + ++ dev->checkpt_cur_chunk; ++ ++ offset_chunk = apply_chunk_offset(dev, chunk); ++ dev->n_page_reads++; ++ ++ /* read in the next chunk */ ++ dev->tagger.read_chunk_tags_fn(dev, ++ offset_chunk, ++ dev->checkpt_buffer, ++ &tags); ++ ++ if (tags.chunk_id != (dev->checkpt_page_seq + 1) || ++ tags.ecc_result > YAFFS_ECC_RESULT_FIXED || ++ tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) { ++ ok = 0; ++ break; ++ } ++ if(!yaffs2_checkpt_check_chunk_hdr(dev)) { ++ ok = 0; ++ break; ++ } ++ ++ dev->checkpt_page_seq++; ++ dev->checkpt_cur_chunk++; ++ ++ if (dev->checkpt_cur_chunk >= ++ dev->param.chunks_per_block) ++ dev->checkpt_cur_block = -1; ++ ++ } ++ ++ *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs]; ++ dev->checkpt_sum += *data_bytes; ++ dev->checkpt_xor ^= *data_bytes; ++ dev->checkpt_byte_offs++; ++ i++; ++ data_bytes++; ++ dev->checkpt_byte_count++; ++ } ++ ++ return i; ++} ++ ++int yaffs_checkpt_close(struct yaffs_dev *dev) ++{ ++ int i; ++ ++ if (dev->checkpt_open_write) { ++ if (dev->checkpt_byte_offs != ++ sizeof(sizeof(struct yaffs_checkpt_chunk_hdr))) ++ yaffs2_checkpt_flush_buffer(dev); ++ } else if (dev->checkpt_block_list) { ++ for (i = 0; ++ i < dev->blocks_in_checkpt && ++ dev->checkpt_block_list[i] >= 0; i++) { ++ int blk = dev->checkpt_block_list[i]; ++ struct yaffs_block_info *bi = NULL; ++ ++ if (dev->internal_start_block <= blk && ++ blk <= dev->internal_end_block) ++ bi = yaffs_get_block_info(dev, blk); ++ if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY) ++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; ++ } ++ kfree(dev->checkpt_block_list); ++ dev->checkpt_block_list = NULL; ++ } ++ ++ dev->n_free_chunks -= ++ dev->blocks_in_checkpt * dev->param.chunks_per_block; ++ dev->n_erased_blocks -= dev->blocks_in_checkpt; ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d", ++ dev->checkpt_byte_count); ++ ++ if (dev->checkpt_buffer) { ++ /* free the buffer */ ++ kfree(dev->checkpt_buffer); ++ dev->checkpt_buffer = NULL; ++ return 1; ++ } else { ++ return 0; ++ } ++} ++ ++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev) ++{ ++ /* Erase the checkpoint data */ ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "checkpoint invalidate of %d blocks", ++ dev->blocks_in_checkpt); ++ ++ return yaffs_checkpt_erase(dev); ++} +diff --git a/fs/yaffs2/yaffs_checkptrw.h b/fs/yaffs2/yaffs_checkptrw.h +new file mode 100644 +index 00000000..cdbaba71 +--- /dev/null ++++ b/fs/yaffs2/yaffs_checkptrw.h +@@ -0,0 +1,33 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_CHECKPTRW_H__ ++#define __YAFFS_CHECKPTRW_H__ ++ ++#include "yaffs_guts.h" ++ ++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing); ++ ++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes); ++ ++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes); ++ ++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum); ++ ++int yaffs_checkpt_close(struct yaffs_dev *dev); ++ ++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev); ++ ++#endif +diff --git a/fs/yaffs2/yaffs_ecc.c b/fs/yaffs2/yaffs_ecc.c +new file mode 100644 +index 00000000..9294107c +--- /dev/null ++++ b/fs/yaffs2/yaffs_ecc.c +@@ -0,0 +1,281 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 code implements the ECC algorithm used in SmartMedia. ++ * ++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. ++ * The two unused bit are set to 1. ++ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two ++ * such ECC blocks are used on a 512-byte NAND page. ++ * ++ */ ++ ++#include "yportenv.h" ++ ++#include "yaffs_ecc.h" ++ ++/* Table generated by gen-ecc.c ++ * Using a table means we do not have to calculate p1..p4 and p1'..p4' ++ * for each byte of data. These are instead provided in a table in bits7..2. ++ * Bit 0 of each entry indicates whether the entry has an odd or even parity, ++ * and therefore this bytes influence on the line parity. ++ */ ++ ++static const unsigned char column_parity_table[] = { ++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, ++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, ++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, ++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, ++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, ++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, ++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, ++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, ++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, ++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, ++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, ++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, ++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, ++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, ++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, ++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, ++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, ++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, ++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, ++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, ++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, ++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, ++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, ++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, ++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, ++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, ++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, ++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, ++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, ++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, ++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, ++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, ++}; ++ ++ ++/* Calculate the ECC for a 256-byte block of data */ ++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc) ++{ ++ unsigned int i; ++ unsigned char col_parity = 0; ++ unsigned char line_parity = 0; ++ unsigned char line_parity_prime = 0; ++ unsigned char t; ++ unsigned char b; ++ ++ for (i = 0; i < 256; i++) { ++ b = column_parity_table[*data++]; ++ col_parity ^= b; ++ ++ if (b & 0x01) { /* odd number of bits in the byte */ ++ line_parity ^= i; ++ line_parity_prime ^= ~i; ++ } ++ } ++ ++ ecc[2] = (~col_parity) | 0x03; ++ ++ t = 0; ++ if (line_parity & 0x80) ++ t |= 0x80; ++ if (line_parity_prime & 0x80) ++ t |= 0x40; ++ if (line_parity & 0x40) ++ t |= 0x20; ++ if (line_parity_prime & 0x40) ++ t |= 0x10; ++ if (line_parity & 0x20) ++ t |= 0x08; ++ if (line_parity_prime & 0x20) ++ t |= 0x04; ++ if (line_parity & 0x10) ++ t |= 0x02; ++ if (line_parity_prime & 0x10) ++ t |= 0x01; ++ ecc[1] = ~t; ++ ++ t = 0; ++ if (line_parity & 0x08) ++ t |= 0x80; ++ if (line_parity_prime & 0x08) ++ t |= 0x40; ++ if (line_parity & 0x04) ++ t |= 0x20; ++ if (line_parity_prime & 0x04) ++ t |= 0x10; ++ if (line_parity & 0x02) ++ t |= 0x08; ++ if (line_parity_prime & 0x02) ++ t |= 0x04; ++ if (line_parity & 0x01) ++ t |= 0x02; ++ if (line_parity_prime & 0x01) ++ t |= 0x01; ++ ecc[0] = ~t; ++ ++} ++ ++/* Correct the ECC on a 256 byte block of data */ ++ ++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, ++ const unsigned char *test_ecc) ++{ ++ unsigned char d0, d1, d2; /* deltas */ ++ ++ d0 = read_ecc[0] ^ test_ecc[0]; ++ d1 = read_ecc[1] ^ test_ecc[1]; ++ d2 = read_ecc[2] ^ test_ecc[2]; ++ ++ if ((d0 | d1 | d2) == 0) ++ return 0; /* no error */ ++ ++ if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 && ++ ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 && ++ ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) { ++ /* Single bit (recoverable) error in data */ ++ ++ unsigned byte; ++ unsigned bit; ++ ++ bit = byte = 0; ++ ++ if (d1 & 0x80) ++ byte |= 0x80; ++ if (d1 & 0x20) ++ byte |= 0x40; ++ if (d1 & 0x08) ++ byte |= 0x20; ++ if (d1 & 0x02) ++ byte |= 0x10; ++ if (d0 & 0x80) ++ byte |= 0x08; ++ if (d0 & 0x20) ++ byte |= 0x04; ++ if (d0 & 0x08) ++ byte |= 0x02; ++ if (d0 & 0x02) ++ byte |= 0x01; ++ ++ if (d2 & 0x80) ++ bit |= 0x04; ++ if (d2 & 0x20) ++ bit |= 0x02; ++ if (d2 & 0x08) ++ bit |= 0x01; ++ ++ data[byte] ^= (1 << bit); ++ ++ return 1; /* Corrected the error */ ++ } ++ ++ if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) { ++ /* Reccoverable error in ecc */ ++ ++ read_ecc[0] = test_ecc[0]; ++ read_ecc[1] = test_ecc[1]; ++ read_ecc[2] = test_ecc[2]; ++ ++ return 1; /* Corrected the error */ ++ } ++ ++ /* Unrecoverable error */ ++ ++ return -1; ++ ++} ++ ++/* ++ * ECCxxxOther does ECC calcs on arbitrary n bytes of data ++ */ ++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, ++ struct yaffs_ecc_other *ecc_other) ++{ ++ unsigned int i; ++ unsigned char col_parity = 0; ++ unsigned line_parity = 0; ++ unsigned line_parity_prime = 0; ++ unsigned char b; ++ ++ for (i = 0; i < n_bytes; i++) { ++ b = column_parity_table[*data++]; ++ col_parity ^= b; ++ ++ if (b & 0x01) { ++ /* odd number of bits in the byte */ ++ line_parity ^= i; ++ line_parity_prime ^= ~i; ++ } ++ ++ } ++ ++ ecc_other->col_parity = (col_parity >> 2) & 0x3f; ++ ecc_other->line_parity = line_parity; ++ ecc_other->line_parity_prime = line_parity_prime; ++} ++ ++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, ++ struct yaffs_ecc_other *read_ecc, ++ const struct yaffs_ecc_other *test_ecc) ++{ ++ unsigned char delta_col; /* column parity delta */ ++ unsigned delta_line; /* line parity delta */ ++ unsigned delta_line_prime; /* line parity delta */ ++ unsigned bit; ++ ++ delta_col = read_ecc->col_parity ^ test_ecc->col_parity; ++ delta_line = read_ecc->line_parity ^ test_ecc->line_parity; ++ delta_line_prime = ++ read_ecc->line_parity_prime ^ test_ecc->line_parity_prime; ++ ++ if ((delta_col | delta_line | delta_line_prime) == 0) ++ return 0; /* no error */ ++ ++ if (delta_line == ~delta_line_prime && ++ (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) { ++ /* Single bit (recoverable) error in data */ ++ ++ bit = 0; ++ ++ if (delta_col & 0x20) ++ bit |= 0x04; ++ if (delta_col & 0x08) ++ bit |= 0x02; ++ if (delta_col & 0x02) ++ bit |= 0x01; ++ ++ if (delta_line >= n_bytes) ++ return -1; ++ ++ data[delta_line] ^= (1 << bit); ++ ++ return 1; /* corrected */ ++ } ++ ++ if ((hweight32(delta_line) + ++ hweight32(delta_line_prime) + ++ hweight8(delta_col)) == 1) { ++ /* Reccoverable error in ecc */ ++ ++ *read_ecc = *test_ecc; ++ return 1; /* corrected */ ++ } ++ ++ /* Unrecoverable error */ ++ ++ return -1; ++} +diff --git a/fs/yaffs2/yaffs_ecc.h b/fs/yaffs2/yaffs_ecc.h +new file mode 100644 +index 00000000..17d47bd8 +--- /dev/null ++++ b/fs/yaffs2/yaffs_ecc.h +@@ -0,0 +1,44 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* ++ * This code implements the ECC algorithm used in SmartMedia. ++ * ++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. ++ * The two unused bit are set to 1. ++ * The ECC can correct single bit errors in a 256-byte page of data. ++ * Thus, two such ECC blocks are used on a 512-byte NAND page. ++ * ++ */ ++ ++#ifndef __YAFFS_ECC_H__ ++#define __YAFFS_ECC_H__ ++ ++struct yaffs_ecc_other { ++ unsigned char col_parity; ++ unsigned line_parity; ++ unsigned line_parity_prime; ++}; ++ ++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc); ++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, ++ const unsigned char *test_ecc); ++ ++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, ++ struct yaffs_ecc_other *ecc); ++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, ++ struct yaffs_ecc_other *read_ecc, ++ const struct yaffs_ecc_other *test_ecc); ++#endif +diff --git a/fs/yaffs2/yaffs_getblockinfo.h b/fs/yaffs2/yaffs_getblockinfo.h +new file mode 100644 +index 00000000..8fd0802b +--- /dev/null ++++ b/fs/yaffs2/yaffs_getblockinfo.h +@@ -0,0 +1,35 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_GETBLOCKINFO_H__ ++#define __YAFFS_GETBLOCKINFO_H__ ++ ++#include "yaffs_guts.h" ++#include "yaffs_trace.h" ++ ++/* Function to manipulate block info */ ++static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev ++ *dev, int blk) ++{ ++ if (blk < dev->internal_start_block || blk > dev->internal_end_block) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "**>> yaffs: get_block_info block %d is not valid", ++ blk); ++ BUG(); ++ } ++ return &dev->block_info[blk - dev->internal_start_block]; ++} ++ ++#endif +diff --git a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c +new file mode 100644 +index 00000000..1de28173 +--- /dev/null ++++ b/fs/yaffs2/yaffs_guts.c +@@ -0,0 +1,5146 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yportenv.h" ++#include "yaffs_trace.h" ++ ++#include "yaffs_guts.h" ++#include "yaffs_getblockinfo.h" ++#include "yaffs_tagscompat.h" ++#include "yaffs_tagsmarshall.h" ++#include "yaffs_nand.h" ++#include "yaffs_yaffs1.h" ++#include "yaffs_yaffs2.h" ++#include "yaffs_bitmap.h" ++#include "yaffs_verify.h" ++#include "yaffs_nand.h" ++#include "yaffs_packedtags2.h" ++#include "yaffs_nameval.h" ++#include "yaffs_allocator.h" ++#include "yaffs_attribs.h" ++#include "yaffs_summary.h" ++ ++/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */ ++#define YAFFS_GC_GOOD_ENOUGH 2 ++#define YAFFS_GC_PASSIVE_THRESHOLD 4 ++ ++#include "yaffs_ecc.h" ++ ++/* Forward declarations */ ++ ++static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, ++ const u8 *buffer, int n_bytes, int use_reserve); ++ ++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name, ++ int buffer_size); ++ ++/* Function to calculate chunk and offset */ ++ ++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr, ++ int *chunk_out, u32 *offset_out) ++{ ++ int chunk; ++ u32 offset; ++ ++ chunk = (u32) (addr >> dev->chunk_shift); ++ ++ if (dev->chunk_div == 1) { ++ /* easy power of 2 case */ ++ offset = (u32) (addr & dev->chunk_mask); ++ } else { ++ /* Non power-of-2 case */ ++ ++ loff_t chunk_base; ++ ++ chunk /= dev->chunk_div; ++ ++ chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk; ++ offset = (u32) (addr - chunk_base); ++ } ++ ++ *chunk_out = chunk; ++ *offset_out = offset; ++} ++ ++/* Function to return the number of shifts for a power of 2 greater than or ++ * equal to the given number ++ * Note we don't try to cater for all possible numbers and this does not have to ++ * be hellishly efficient. ++ */ ++ ++static inline u32 calc_shifts_ceiling(u32 x) ++{ ++ int extra_bits; ++ int shifts; ++ ++ shifts = extra_bits = 0; ++ ++ while (x > 1) { ++ if (x & 1) ++ extra_bits++; ++ x >>= 1; ++ shifts++; ++ } ++ ++ if (extra_bits) ++ shifts++; ++ ++ return shifts; ++} ++ ++/* Function to return the number of shifts to get a 1 in bit 0 ++ */ ++ ++static inline u32 calc_shifts(u32 x) ++{ ++ u32 shifts; ++ ++ shifts = 0; ++ ++ if (!x) ++ return 0; ++ ++ while (!(x & 1)) { ++ x >>= 1; ++ shifts++; ++ } ++ ++ return shifts; ++} ++ ++/* ++ * Temporary buffer manipulations. ++ */ ++ ++static int yaffs_init_tmp_buffers(struct yaffs_dev *dev) ++{ ++ int i; ++ u8 *buf = (u8 *) 1; ++ ++ memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer)); ++ ++ for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { ++ dev->temp_buffer[i].in_use = 0; ++ buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); ++ dev->temp_buffer[i].buffer = buf; ++ } ++ ++ return buf ? YAFFS_OK : YAFFS_FAIL; ++} ++ ++u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev) ++{ ++ int i; ++ ++ dev->temp_in_use++; ++ if (dev->temp_in_use > dev->max_temp) ++ dev->max_temp = dev->temp_in_use; ++ ++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { ++ if (dev->temp_buffer[i].in_use == 0) { ++ dev->temp_buffer[i].in_use = 1; ++ return dev->temp_buffer[i].buffer; ++ } ++ } ++ ++ yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers"); ++ /* ++ * If we got here then we have to allocate an unmanaged one ++ * This is not good. ++ */ ++ ++ dev->unmanaged_buffer_allocs++; ++ return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS); ++ ++} ++ ++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer) ++{ ++ int i; ++ ++ dev->temp_in_use--; ++ ++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { ++ if (dev->temp_buffer[i].buffer == buffer) { ++ dev->temp_buffer[i].in_use = 0; ++ return; ++ } ++ } ++ ++ if (buffer) { ++ /* assume it is an unmanaged one. */ ++ yaffs_trace(YAFFS_TRACE_BUFFERS, ++ "Releasing unmanaged temp buffer"); ++ kfree(buffer); ++ dev->unmanaged_buffer_deallocs++; ++ } ++ ++} ++ ++/* ++ * Functions for robustisizing TODO ++ * ++ */ ++ ++static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk, ++ const u8 *data, ++ const struct yaffs_ext_tags *tags) ++{ ++ (void) dev; ++ (void) nand_chunk; ++ (void) data; ++ (void) tags; ++} ++ ++static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk, ++ const struct yaffs_ext_tags *tags) ++{ ++ (void) dev; ++ (void) nand_chunk; ++ (void) tags; ++} ++ ++void yaffs_handle_chunk_error(struct yaffs_dev *dev, ++ struct yaffs_block_info *bi) ++{ ++ if (!bi->gc_prioritise) { ++ bi->gc_prioritise = 1; ++ dev->has_pending_prioritised_gc = 1; ++ bi->chunk_error_strikes++; ++ ++ if (bi->chunk_error_strikes > 3) { ++ bi->needs_retiring = 1; /* Too many stikes, so retire */ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs: Block struck out"); ++ ++ } ++ } ++} ++ ++static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk, ++ int erased_ok) ++{ ++ int flash_block = nand_chunk / dev->param.chunks_per_block; ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block); ++ ++ yaffs_handle_chunk_error(dev, bi); ++ ++ if (erased_ok) { ++ /* Was an actual write failure, ++ * so mark the block for retirement.*/ ++ bi->needs_retiring = 1; ++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, ++ "**>> Block %d needs retiring", flash_block); ++ } ++ ++ /* Delete the chunk */ ++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); ++ yaffs_skip_rest_of_block(dev); ++} ++ ++/* ++ * Verification code ++ */ ++ ++/* ++ * Simple hash function. Needs to have a reasonable spread ++ */ ++ ++static inline int yaffs_hash_fn(int n) ++{ ++ if (n < 0) ++ n = -n; ++ return n % YAFFS_NOBJECT_BUCKETS; ++} ++ ++/* ++ * Access functions to useful fake objects. ++ * Note that root might have a presence in NAND if permissions are set. ++ */ ++ ++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev) ++{ ++ return dev->root_dir; ++} ++ ++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev) ++{ ++ return dev->lost_n_found; ++} ++ ++/* ++ * Erased NAND checking functions ++ */ ++ ++int yaffs_check_ff(u8 *buffer, int n_bytes) ++{ ++ /* Horrible, slow implementation */ ++ while (n_bytes--) { ++ if (*buffer != 0xff) ++ return 0; ++ buffer++; ++ } ++ return 1; ++} ++ ++static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk) ++{ ++ int retval = YAFFS_OK; ++ u8 *data = yaffs_get_temp_buffer(dev); ++ struct yaffs_ext_tags tags; ++ int result; ++ ++ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags); ++ ++ if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR) ++ retval = YAFFS_FAIL; ++ ++ if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) || ++ tags.chunk_used) { ++ yaffs_trace(YAFFS_TRACE_NANDACCESS, ++ "Chunk %d not erased", nand_chunk); ++ retval = YAFFS_FAIL; ++ } ++ ++ yaffs_release_temp_buffer(dev, data); ++ ++ return retval; ++ ++} ++ ++static int yaffs_verify_chunk_written(struct yaffs_dev *dev, ++ int nand_chunk, ++ const u8 *data, ++ struct yaffs_ext_tags *tags) ++{ ++ int retval = YAFFS_OK; ++ struct yaffs_ext_tags temp_tags; ++ u8 *buffer = yaffs_get_temp_buffer(dev); ++ int result; ++ ++ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags); ++ if (memcmp(buffer, data, dev->data_bytes_per_chunk) || ++ temp_tags.obj_id != tags->obj_id || ++ temp_tags.chunk_id != tags->chunk_id || ++ temp_tags.n_bytes != tags->n_bytes) ++ retval = YAFFS_FAIL; ++ ++ yaffs_release_temp_buffer(dev, buffer); ++ ++ return retval; ++} ++ ++ ++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks) ++{ ++ int reserved_chunks; ++ int reserved_blocks = dev->param.n_reserved_blocks; ++ int checkpt_blocks; ++ ++ checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev); ++ ++ reserved_chunks = ++ (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block; ++ ++ return (dev->n_free_chunks > (reserved_chunks + n_chunks)); ++} ++ ++static int yaffs_find_alloc_block(struct yaffs_dev *dev) ++{ ++ int i; ++ struct yaffs_block_info *bi; ++ ++ if (dev->n_erased_blocks < 1) { ++ /* Hoosterman we've got a problem. ++ * Can't get space to gc ++ */ ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs tragedy: no more erased blocks"); ++ ++ return -1; ++ } ++ ++ /* Find an empty block. */ ++ ++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { ++ dev->alloc_block_finder++; ++ if (dev->alloc_block_finder < dev->internal_start_block ++ || dev->alloc_block_finder > dev->internal_end_block) { ++ dev->alloc_block_finder = dev->internal_start_block; ++ } ++ ++ bi = yaffs_get_block_info(dev, dev->alloc_block_finder); ++ ++ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { ++ bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING; ++ dev->seq_number++; ++ bi->seq_number = dev->seq_number; ++ dev->n_erased_blocks--; ++ yaffs_trace(YAFFS_TRACE_ALLOCATE, ++ "Allocated block %d, seq %d, %d left" , ++ dev->alloc_block_finder, dev->seq_number, ++ dev->n_erased_blocks); ++ return dev->alloc_block_finder; ++ } ++ } ++ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs tragedy: no more erased blocks, but there should have been %d", ++ dev->n_erased_blocks); ++ ++ return -1; ++} ++ ++static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver, ++ struct yaffs_block_info **block_ptr) ++{ ++ int ret_val; ++ struct yaffs_block_info *bi; ++ ++ if (dev->alloc_block < 0) { ++ /* Get next block to allocate off */ ++ dev->alloc_block = yaffs_find_alloc_block(dev); ++ dev->alloc_page = 0; ++ } ++ ++ if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) { ++ /* No space unless we're allowed to use the reserve. */ ++ return -1; ++ } ++ ++ if (dev->n_erased_blocks < dev->param.n_reserved_blocks ++ && dev->alloc_page == 0) ++ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve"); ++ ++ /* Next page please.... */ ++ if (dev->alloc_block >= 0) { ++ bi = yaffs_get_block_info(dev, dev->alloc_block); ++ ++ ret_val = (dev->alloc_block * dev->param.chunks_per_block) + ++ dev->alloc_page; ++ bi->pages_in_use++; ++ yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page); ++ ++ dev->alloc_page++; ++ ++ dev->n_free_chunks--; ++ ++ /* If the block is full set the state to full */ ++ if (dev->alloc_page >= dev->param.chunks_per_block) { ++ bi->block_state = YAFFS_BLOCK_STATE_FULL; ++ dev->alloc_block = -1; ++ } ++ ++ if (block_ptr) ++ *block_ptr = bi; ++ ++ return ret_val; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!"); ++ ++ return -1; ++} ++ ++static int yaffs_get_erased_chunks(struct yaffs_dev *dev) ++{ ++ int n; ++ ++ n = dev->n_erased_blocks * dev->param.chunks_per_block; ++ ++ if (dev->alloc_block > 0) ++ n += (dev->param.chunks_per_block - dev->alloc_page); ++ ++ return n; ++ ++} ++ ++/* ++ * yaffs_skip_rest_of_block() skips over the rest of the allocation block ++ * if we don't want to write to it. ++ */ ++void yaffs_skip_rest_of_block(struct yaffs_dev *dev) ++{ ++ struct yaffs_block_info *bi; ++ ++ if (dev->alloc_block > 0) { ++ bi = yaffs_get_block_info(dev, dev->alloc_block); ++ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) { ++ bi->block_state = YAFFS_BLOCK_STATE_FULL; ++ dev->alloc_block = -1; ++ } ++ } ++} ++ ++static int yaffs_write_new_chunk(struct yaffs_dev *dev, ++ const u8 *data, ++ struct yaffs_ext_tags *tags, int use_reserver) ++{ ++ int attempts = 0; ++ int write_ok = 0; ++ int chunk; ++ ++ yaffs2_checkpt_invalidate(dev); ++ ++ do { ++ struct yaffs_block_info *bi = 0; ++ int erased_ok = 0; ++ ++ chunk = yaffs_alloc_chunk(dev, use_reserver, &bi); ++ if (chunk < 0) { ++ /* no space */ ++ break; ++ } ++ ++ /* First check this chunk is erased, if it needs ++ * checking. The checking policy (unless forced ++ * always on) is as follows: ++ * ++ * Check the first page we try to write in a block. ++ * If the check passes then we don't need to check any ++ * more. If the check fails, we check again... ++ * If the block has been erased, we don't need to check. ++ * ++ * However, if the block has been prioritised for gc, ++ * then we think there might be something odd about ++ * this block and stop using it. ++ * ++ * Rationale: We should only ever see chunks that have ++ * not been erased if there was a partially written ++ * chunk due to power loss. This checking policy should ++ * catch that case with very few checks and thus save a ++ * lot of checks that are most likely not needed. ++ * ++ * Mods to the above ++ * If an erase check fails or the write fails we skip the ++ * rest of the block. ++ */ ++ ++ /* let's give it a try */ ++ attempts++; ++ ++ if (dev->param.always_check_erased) ++ bi->skip_erased_check = 0; ++ ++ if (!bi->skip_erased_check) { ++ erased_ok = yaffs_check_chunk_erased(dev, chunk); ++ if (erased_ok != YAFFS_OK) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "**>> yaffs chunk %d was not erased", ++ chunk); ++ ++ /* If not erased, delete this one, ++ * skip rest of block and ++ * try another chunk */ ++ yaffs_chunk_del(dev, chunk, 1, __LINE__); ++ yaffs_skip_rest_of_block(dev); ++ continue; ++ } ++ } ++ ++ write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags); ++ ++ if (!bi->skip_erased_check) ++ write_ok = ++ yaffs_verify_chunk_written(dev, chunk, data, tags); ++ ++ if (write_ok != YAFFS_OK) { ++ /* Clean up aborted write, skip to next block and ++ * try another chunk */ ++ yaffs_handle_chunk_wr_error(dev, chunk, erased_ok); ++ continue; ++ } ++ ++ bi->skip_erased_check = 1; ++ ++ /* Copy the data into the robustification buffer */ ++ yaffs_handle_chunk_wr_ok(dev, chunk, data, tags); ++ ++ } while (write_ok != YAFFS_OK && ++ (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts)); ++ ++ if (!write_ok) ++ chunk = -1; ++ ++ if (attempts > 1) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "**>> yaffs write required %d attempts", ++ attempts); ++ dev->n_retried_writes += (attempts - 1); ++ } ++ ++ return chunk; ++} ++ ++/* ++ * Block retiring for handling a broken block. ++ */ ++ ++static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block) ++{ ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block); ++ ++ yaffs2_checkpt_invalidate(dev); ++ ++ yaffs2_clear_oldest_dirty_seq(dev, bi); ++ ++ if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) { ++ if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs: Failed to mark bad and erase block %d", ++ flash_block); ++ } else { ++ struct yaffs_ext_tags tags; ++ int chunk_id = ++ flash_block * dev->param.chunks_per_block; ++ ++ u8 *buffer = yaffs_get_temp_buffer(dev); ++ ++ memset(buffer, 0xff, dev->data_bytes_per_chunk); ++ memset(&tags, 0, sizeof(tags)); ++ tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK; ++ if (dev->tagger.write_chunk_tags_fn(dev, chunk_id - ++ dev->chunk_offset, ++ buffer, ++ &tags) != YAFFS_OK) ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs: Failed to write bad block marker to block %d", ++ flash_block); ++ ++ yaffs_release_temp_buffer(dev, buffer); ++ } ++ } ++ ++ bi->block_state = YAFFS_BLOCK_STATE_DEAD; ++ bi->gc_prioritise = 0; ++ bi->needs_retiring = 0; ++ ++ dev->n_retired_blocks++; ++} ++ ++/*---------------- Name handling functions ------------*/ ++ ++static u16 yaffs_calc_name_sum(const YCHAR *name) ++{ ++ u16 sum = 0; ++ u16 i = 1; ++ ++ if (!name) ++ return 0; ++ ++ while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) { ++ ++ /* 0x1f mask is case insensitive */ ++ sum += ((*name) & 0x1f) * i; ++ i++; ++ name++; ++ } ++ return sum; ++} ++ ++ ++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name) ++{ ++ memset(obj->short_name, 0, sizeof(obj->short_name)); ++ ++ if (name && !name[0]) { ++ yaffs_fix_null_name(obj, obj->short_name, ++ YAFFS_SHORT_NAME_LENGTH); ++ name = obj->short_name; ++ } else if (name && ++ strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <= ++ YAFFS_SHORT_NAME_LENGTH) { ++ strcpy(obj->short_name, name); ++ } ++ ++ obj->sum = yaffs_calc_name_sum(name); ++} ++ ++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj, ++ const struct yaffs_obj_hdr *oh) ++{ ++#ifdef CONFIG_YAFFS_AUTO_UNICODE ++ YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1]; ++ memset(tmp_name, 0, sizeof(tmp_name)); ++ yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name, ++ YAFFS_MAX_NAME_LENGTH + 1); ++ yaffs_set_obj_name(obj, tmp_name); ++#else ++ yaffs_set_obj_name(obj, oh->name); ++#endif ++} ++ ++loff_t yaffs_max_file_size(struct yaffs_dev *dev) ++{ ++ if(sizeof(loff_t) < 8) ++ return YAFFS_MAX_FILE_SIZE_32; ++ else ++ return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk; ++} ++ ++/*-------------------- TNODES ------------------- ++ ++ * List of spare tnodes ++ * The list is hooked together using the first pointer ++ * in the tnode. ++ */ ++ ++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev) ++{ ++ struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev); ++ ++ if (tn) { ++ memset(tn, 0, dev->tnode_size); ++ dev->n_tnodes++; ++ } ++ ++ dev->checkpoint_blocks_required = 0; /* force recalculation */ ++ ++ return tn; ++} ++ ++/* FreeTnode frees up a tnode and puts it back on the free list */ ++static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) ++{ ++ yaffs_free_raw_tnode(dev, tn); ++ dev->n_tnodes--; ++ dev->checkpoint_blocks_required = 0; /* force recalculation */ ++} ++ ++static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev) ++{ ++ yaffs_deinit_raw_tnodes_and_objs(dev); ++ dev->n_obj = 0; ++ dev->n_tnodes = 0; ++} ++ ++static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn, ++ unsigned pos, unsigned val) ++{ ++ u32 *map = (u32 *) tn; ++ u32 bit_in_map; ++ u32 bit_in_word; ++ u32 word_in_map; ++ u32 mask; ++ ++ pos &= YAFFS_TNODES_LEVEL0_MASK; ++ val >>= dev->chunk_grp_bits; ++ ++ bit_in_map = pos * dev->tnode_width; ++ word_in_map = bit_in_map / 32; ++ bit_in_word = bit_in_map & (32 - 1); ++ ++ mask = dev->tnode_mask << bit_in_word; ++ ++ map[word_in_map] &= ~mask; ++ map[word_in_map] |= (mask & (val << bit_in_word)); ++ ++ if (dev->tnode_width > (32 - bit_in_word)) { ++ bit_in_word = (32 - bit_in_word); ++ word_in_map++; ++ mask = ++ dev->tnode_mask >> bit_in_word; ++ map[word_in_map] &= ~mask; ++ map[word_in_map] |= (mask & (val >> bit_in_word)); ++ } ++} ++ ++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn, ++ unsigned pos) ++{ ++ u32 *map = (u32 *) tn; ++ u32 bit_in_map; ++ u32 bit_in_word; ++ u32 word_in_map; ++ u32 val; ++ ++ pos &= YAFFS_TNODES_LEVEL0_MASK; ++ ++ bit_in_map = pos * dev->tnode_width; ++ word_in_map = bit_in_map / 32; ++ bit_in_word = bit_in_map & (32 - 1); ++ ++ val = map[word_in_map] >> bit_in_word; ++ ++ if (dev->tnode_width > (32 - bit_in_word)) { ++ bit_in_word = (32 - bit_in_word); ++ word_in_map++; ++ val |= (map[word_in_map] << bit_in_word); ++ } ++ ++ val &= dev->tnode_mask; ++ val <<= dev->chunk_grp_bits; ++ ++ return val; ++} ++ ++/* ------------------- End of individual tnode manipulation -----------------*/ ++ ++/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------ ++ * The look up tree is represented by the top tnode and the number of top_level ++ * in the tree. 0 means only the level 0 tnode is in the tree. ++ */ ++ ++/* FindLevel0Tnode finds the level 0 tnode, if one exists. */ ++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev, ++ struct yaffs_file_var *file_struct, ++ u32 chunk_id) ++{ ++ struct yaffs_tnode *tn = file_struct->top; ++ u32 i; ++ int required_depth; ++ int level = file_struct->top_level; ++ ++ (void) dev; ++ ++ /* Check sane level and chunk Id */ ++ if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) ++ return NULL; ++ ++ if (chunk_id > YAFFS_MAX_CHUNK_ID) ++ return NULL; ++ ++ /* First check we're tall enough (ie enough top_level) */ ++ ++ i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS; ++ required_depth = 0; ++ while (i) { ++ i >>= YAFFS_TNODES_INTERNAL_BITS; ++ required_depth++; ++ } ++ ++ if (required_depth > file_struct->top_level) ++ return NULL; /* Not tall enough, so we can't find it */ ++ ++ /* Traverse down to level 0 */ ++ while (level > 0 && tn) { ++ tn = tn->internal[(chunk_id >> ++ (YAFFS_TNODES_LEVEL0_BITS + ++ (level - 1) * ++ YAFFS_TNODES_INTERNAL_BITS)) & ++ YAFFS_TNODES_INTERNAL_MASK]; ++ level--; ++ } ++ ++ return tn; ++} ++ ++/* add_find_tnode_0 finds the level 0 tnode if it exists, ++ * otherwise first expands the tree. ++ * This happens in two steps: ++ * 1. If the tree isn't tall enough, then make it taller. ++ * 2. Scan down the tree towards the level 0 tnode adding tnodes if required. ++ * ++ * Used when modifying the tree. ++ * ++ * If the tn argument is NULL, then a fresh tnode will be added otherwise the ++ * specified tn will be plugged into the ttree. ++ */ ++ ++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev, ++ struct yaffs_file_var *file_struct, ++ u32 chunk_id, ++ struct yaffs_tnode *passed_tn) ++{ ++ int required_depth; ++ int i; ++ int l; ++ struct yaffs_tnode *tn; ++ u32 x; ++ ++ /* Check sane level and page Id */ ++ if (file_struct->top_level < 0 || ++ file_struct->top_level > YAFFS_TNODES_MAX_LEVEL) ++ return NULL; ++ ++ if (chunk_id > YAFFS_MAX_CHUNK_ID) ++ return NULL; ++ ++ /* First check we're tall enough (ie enough top_level) */ ++ ++ x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS; ++ required_depth = 0; ++ while (x) { ++ x >>= YAFFS_TNODES_INTERNAL_BITS; ++ required_depth++; ++ } ++ ++ if (required_depth > file_struct->top_level) { ++ /* Not tall enough, gotta make the tree taller */ ++ for (i = file_struct->top_level; i < required_depth; i++) { ++ ++ tn = yaffs_get_tnode(dev); ++ ++ if (tn) { ++ tn->internal[0] = file_struct->top; ++ file_struct->top = tn; ++ file_struct->top_level++; ++ } else { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs: no more tnodes"); ++ return NULL; ++ } ++ } ++ } ++ ++ /* Traverse down to level 0, adding anything we need */ ++ ++ l = file_struct->top_level; ++ tn = file_struct->top; ++ ++ if (l > 0) { ++ while (l > 0 && tn) { ++ x = (chunk_id >> ++ (YAFFS_TNODES_LEVEL0_BITS + ++ (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) & ++ YAFFS_TNODES_INTERNAL_MASK; ++ ++ if ((l > 1) && !tn->internal[x]) { ++ /* Add missing non-level-zero tnode */ ++ tn->internal[x] = yaffs_get_tnode(dev); ++ if (!tn->internal[x]) ++ return NULL; ++ } else if (l == 1) { ++ /* Looking from level 1 at level 0 */ ++ if (passed_tn) { ++ /* If we already have one, release it */ ++ if (tn->internal[x]) ++ yaffs_free_tnode(dev, ++ tn->internal[x]); ++ tn->internal[x] = passed_tn; ++ ++ } else if (!tn->internal[x]) { ++ /* Don't have one, none passed in */ ++ tn->internal[x] = yaffs_get_tnode(dev); ++ if (!tn->internal[x]) ++ return NULL; ++ } ++ } ++ ++ tn = tn->internal[x]; ++ l--; ++ } ++ } else { ++ /* top is level 0 */ ++ if (passed_tn) { ++ memcpy(tn, passed_tn, ++ (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8); ++ yaffs_free_tnode(dev, passed_tn); ++ } ++ } ++ ++ return tn; ++} ++ ++static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id, ++ int chunk_obj) ++{ ++ return (tags->chunk_id == chunk_obj && ++ tags->obj_id == obj_id && ++ !tags->is_deleted) ? 1 : 0; ++ ++} ++ ++static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk, ++ struct yaffs_ext_tags *tags, int obj_id, ++ int inode_chunk) ++{ ++ int j; ++ ++ for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) { ++ if (yaffs_check_chunk_bit ++ (dev, the_chunk / dev->param.chunks_per_block, ++ the_chunk % dev->param.chunks_per_block)) { ++ ++ if (dev->chunk_grp_size == 1) ++ return the_chunk; ++ else { ++ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL, ++ tags); ++ if (yaffs_tags_match(tags, ++ obj_id, inode_chunk)) { ++ /* found it; */ ++ return the_chunk; ++ } ++ } ++ } ++ the_chunk++; ++ } ++ return -1; ++} ++ ++int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk, ++ struct yaffs_ext_tags *tags) ++{ ++ /*Get the Tnode, then get the level 0 offset chunk offset */ ++ struct yaffs_tnode *tn; ++ int the_chunk = -1; ++ struct yaffs_ext_tags local_tags; ++ int ret_val = -1; ++ struct yaffs_dev *dev = in->my_dev; ++ ++ if (!tags) { ++ /* Passed a NULL, so use our own tags space */ ++ tags = &local_tags; ++ } ++ ++ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk); ++ ++ if (!tn) ++ return ret_val; ++ ++ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk); ++ ++ ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id, ++ inode_chunk); ++ return ret_val; ++} ++ ++static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk, ++ struct yaffs_ext_tags *tags) ++{ ++ /* Get the Tnode, then get the level 0 offset chunk offset */ ++ struct yaffs_tnode *tn; ++ int the_chunk = -1; ++ struct yaffs_ext_tags local_tags; ++ struct yaffs_dev *dev = in->my_dev; ++ int ret_val = -1; ++ ++ if (!tags) { ++ /* Passed a NULL, so use our own tags space */ ++ tags = &local_tags; ++ } ++ ++ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk); ++ ++ if (!tn) ++ return ret_val; ++ ++ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk); ++ ++ ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id, ++ inode_chunk); ++ ++ /* Delete the entry in the filestructure (if found) */ ++ if (ret_val != -1) ++ yaffs_load_tnode_0(dev, tn, inode_chunk, 0); ++ ++ return ret_val; ++} ++ ++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk, ++ int nand_chunk, int in_scan) ++{ ++ /* NB in_scan is zero unless scanning. ++ * For forward scanning, in_scan is > 0; ++ * for backward scanning in_scan is < 0 ++ * ++ * nand_chunk = 0 is a dummy insert to make sure the tnodes are there. ++ */ ++ ++ struct yaffs_tnode *tn; ++ struct yaffs_dev *dev = in->my_dev; ++ int existing_cunk; ++ struct yaffs_ext_tags existing_tags; ++ struct yaffs_ext_tags new_tags; ++ unsigned existing_serial, new_serial; ++ ++ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) { ++ /* Just ignore an attempt at putting a chunk into a non-file ++ * during scanning. ++ * If it is not during Scanning then something went wrong! ++ */ ++ if (!in_scan) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs tragedy:attempt to put data chunk into a non-file" ++ ); ++ BUG(); ++ } ++ ++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); ++ return YAFFS_OK; ++ } ++ ++ tn = yaffs_add_find_tnode_0(dev, ++ &in->variant.file_variant, ++ inode_chunk, NULL); ++ if (!tn) ++ return YAFFS_FAIL; ++ ++ if (!nand_chunk) ++ /* Dummy insert, bail now */ ++ return YAFFS_OK; ++ ++ existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk); ++ ++ if (in_scan != 0) { ++ /* If we're scanning then we need to test for duplicates ++ * NB This does not need to be efficient since it should only ++ * happen when the power fails during a write, then only one ++ * chunk should ever be affected. ++ * ++ * Correction for YAFFS2: This could happen quite a lot and we ++ * need to think about efficiency! TODO ++ * Update: For backward scanning we don't need to re-read tags ++ * so this is quite cheap. ++ */ ++ ++ if (existing_cunk > 0) { ++ /* NB Right now existing chunk will not be real ++ * chunk_id if the chunk group size > 1 ++ * thus we have to do a FindChunkInFile to get the ++ * real chunk id. ++ * ++ * We have a duplicate now we need to decide which ++ * one to use: ++ * ++ * Backwards scanning YAFFS2: The old one is what ++ * we use, dump the new one. ++ * YAFFS1: Get both sets of tags and compare serial ++ * numbers. ++ */ ++ ++ if (in_scan > 0) { ++ /* Only do this for forward scanning */ ++ yaffs_rd_chunk_tags_nand(dev, ++ nand_chunk, ++ NULL, &new_tags); ++ ++ /* Do a proper find */ ++ existing_cunk = ++ yaffs_find_chunk_in_file(in, inode_chunk, ++ &existing_tags); ++ } ++ ++ if (existing_cunk <= 0) { ++ /*Hoosterman - how did this happen? */ ++ ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs tragedy: existing chunk < 0 in scan" ++ ); ++ ++ } ++ ++ /* NB The deleted flags should be false, otherwise ++ * the chunks will not be loaded during a scan ++ */ ++ ++ if (in_scan > 0) { ++ new_serial = new_tags.serial_number; ++ existing_serial = existing_tags.serial_number; ++ } ++ ++ if ((in_scan > 0) && ++ (existing_cunk <= 0 || ++ ((existing_serial + 1) & 3) == new_serial)) { ++ /* Forward scanning. ++ * Use new ++ * Delete the old one and drop through to ++ * update the tnode ++ */ ++ yaffs_chunk_del(dev, existing_cunk, 1, ++ __LINE__); ++ } else { ++ /* Backward scanning or we want to use the ++ * existing one ++ * Delete the new one and return early so that ++ * the tnode isn't changed ++ */ ++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); ++ return YAFFS_OK; ++ } ++ } ++ ++ } ++ ++ if (existing_cunk == 0) ++ in->n_data_chunks++; ++ ++ yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk); ++ ++ return YAFFS_OK; ++} ++ ++static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk) ++{ ++ struct yaffs_block_info *the_block; ++ unsigned block_no; ++ ++ yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk); ++ ++ block_no = chunk / dev->param.chunks_per_block; ++ the_block = yaffs_get_block_info(dev, block_no); ++ if (the_block) { ++ the_block->soft_del_pages++; ++ dev->n_free_chunks++; ++ yaffs2_update_oldest_dirty_seq(dev, block_no, the_block); ++ } ++} ++ ++/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all ++ * the chunks in the file. ++ * All soft deleting does is increment the block's softdelete count and pulls ++ * the chunk out of the tnode. ++ * Thus, essentially this is the same as DeleteWorker except that the chunks ++ * are soft deleted. ++ */ ++ ++static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn, ++ u32 level, int chunk_offset) ++{ ++ int i; ++ int the_chunk; ++ int all_done = 1; ++ struct yaffs_dev *dev = in->my_dev; ++ ++ if (!tn) ++ return 1; ++ ++ if (level > 0) { ++ for (i = YAFFS_NTNODES_INTERNAL - 1; ++ all_done && i >= 0; ++ i--) { ++ if (tn->internal[i]) { ++ all_done = ++ yaffs_soft_del_worker(in, ++ tn->internal[i], ++ level - 1, ++ (chunk_offset << ++ YAFFS_TNODES_INTERNAL_BITS) ++ + i); ++ if (all_done) { ++ yaffs_free_tnode(dev, ++ tn->internal[i]); ++ tn->internal[i] = NULL; ++ } else { ++ /* Can this happen? */ ++ } ++ } ++ } ++ return (all_done) ? 1 : 0; ++ } ++ ++ /* level 0 */ ++ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) { ++ the_chunk = yaffs_get_group_base(dev, tn, i); ++ if (the_chunk) { ++ yaffs_soft_del_chunk(dev, the_chunk); ++ yaffs_load_tnode_0(dev, tn, i, 0); ++ } ++ } ++ return 1; ++} ++ ++static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj) ++{ ++ struct yaffs_dev *dev = obj->my_dev; ++ struct yaffs_obj *parent; ++ ++ yaffs_verify_obj_in_dir(obj); ++ parent = obj->parent; ++ ++ yaffs_verify_dir(parent); ++ ++ if (dev && dev->param.remove_obj_fn) ++ dev->param.remove_obj_fn(obj); ++ ++ list_del_init(&obj->siblings); ++ obj->parent = NULL; ++ ++ yaffs_verify_dir(parent); ++} ++ ++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj) ++{ ++ if (!directory) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "tragedy: Trying to add an object to a null pointer directory" ++ ); ++ BUG(); ++ return; ++ } ++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "tragedy: Trying to add an object to a non-directory" ++ ); ++ BUG(); ++ } ++ ++ if (obj->siblings.prev == NULL) { ++ /* Not initialised */ ++ BUG(); ++ } ++ ++ yaffs_verify_dir(directory); ++ ++ yaffs_remove_obj_from_dir(obj); ++ ++ /* Now add it */ ++ list_add(&obj->siblings, &directory->variant.dir_variant.children); ++ obj->parent = directory; ++ ++ if (directory == obj->my_dev->unlinked_dir ++ || directory == obj->my_dev->del_dir) { ++ obj->unlinked = 1; ++ obj->my_dev->n_unlinked_files++; ++ obj->rename_allowed = 0; ++ } ++ ++ yaffs_verify_dir(directory); ++ yaffs_verify_obj_in_dir(obj); ++} ++ ++static int yaffs_change_obj_name(struct yaffs_obj *obj, ++ struct yaffs_obj *new_dir, ++ const YCHAR *new_name, int force, int shadows) ++{ ++ int unlink_op; ++ int del_op; ++ struct yaffs_obj *existing_target; ++ ++ if (new_dir == NULL) ++ new_dir = obj->parent; /* use the old directory */ ++ ++ if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "tragedy: yaffs_change_obj_name: new_dir is not a directory" ++ ); ++ BUG(); ++ } ++ ++ unlink_op = (new_dir == obj->my_dev->unlinked_dir); ++ del_op = (new_dir == obj->my_dev->del_dir); ++ ++ existing_target = yaffs_find_by_name(new_dir, new_name); ++ ++ /* If the object is a file going into the unlinked directory, ++ * then it is OK to just stuff it in since duplicate names are OK. ++ * else only proceed if the new name does not exist and we're putting ++ * it into a directory. ++ */ ++ if (!(unlink_op || del_op || force || ++ shadows > 0 || !existing_target) || ++ new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) ++ return YAFFS_FAIL; ++ ++ yaffs_set_obj_name(obj, new_name); ++ obj->dirty = 1; ++ yaffs_add_obj_to_dir(new_dir, obj); ++ ++ if (unlink_op) ++ obj->unlinked = 1; ++ ++ /* If it is a deletion then we mark it as a shrink for gc */ ++ if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0) ++ return YAFFS_OK; ++ ++ return YAFFS_FAIL; ++} ++ ++/*------------------------ Short Operations Cache ------------------------------ ++ * In many situations where there is no high level buffering a lot of ++ * reads might be short sequential reads, and a lot of writes may be short ++ * sequential writes. eg. scanning/writing a jpeg file. ++ * In these cases, a short read/write cache can provide a huge perfomance ++ * benefit with dumb-as-a-rock code. ++ * In Linux, the page cache provides read buffering and the short op cache ++ * provides write buffering. ++ * ++ * There are a small number (~10) of cache chunks per device so that we don't ++ * need a very intelligent search. ++ */ ++ ++static int yaffs_obj_cache_dirty(struct yaffs_obj *obj) ++{ ++ struct yaffs_dev *dev = obj->my_dev; ++ int i; ++ struct yaffs_cache *cache; ++ int n_caches = obj->my_dev->param.n_caches; ++ ++ for (i = 0; i < n_caches; i++) { ++ cache = &dev->cache[i]; ++ if (cache->object == obj && cache->dirty) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static void yaffs_flush_file_cache(struct yaffs_obj *obj) ++{ ++ struct yaffs_dev *dev = obj->my_dev; ++ int lowest = -99; /* Stop compiler whining. */ ++ int i; ++ struct yaffs_cache *cache; ++ int chunk_written = 0; ++ int n_caches = obj->my_dev->param.n_caches; ++ ++ if (n_caches < 1) ++ return; ++ do { ++ cache = NULL; ++ ++ /* Find the lowest dirty chunk for this object */ ++ for (i = 0; i < n_caches; i++) { ++ if (dev->cache[i].object == obj && ++ dev->cache[i].dirty) { ++ if (!cache || ++ dev->cache[i].chunk_id < lowest) { ++ cache = &dev->cache[i]; ++ lowest = cache->chunk_id; ++ } ++ } ++ } ++ ++ if (cache && !cache->locked) { ++ /* Write it out and free it up */ ++ chunk_written = ++ yaffs_wr_data_obj(cache->object, ++ cache->chunk_id, ++ cache->data, ++ cache->n_bytes, 1); ++ cache->dirty = 0; ++ cache->object = NULL; ++ } ++ } while (cache && chunk_written > 0); ++ ++ if (cache) ++ /* Hoosterman, disk full while writing cache out. */ ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs tragedy: no space during cache write"); ++} ++ ++/*yaffs_flush_whole_cache(dev) ++ * ++ * ++ */ ++ ++void yaffs_flush_whole_cache(struct yaffs_dev *dev) ++{ ++ struct yaffs_obj *obj; ++ int n_caches = dev->param.n_caches; ++ int i; ++ ++ /* Find a dirty object in the cache and flush it... ++ * until there are no further dirty objects. ++ */ ++ do { ++ obj = NULL; ++ for (i = 0; i < n_caches && !obj; i++) { ++ if (dev->cache[i].object && dev->cache[i].dirty) ++ obj = dev->cache[i].object; ++ } ++ if (obj) ++ yaffs_flush_file_cache(obj); ++ } while (obj); ++ ++} ++ ++/* Grab us a cache chunk for use. ++ * First look for an empty one. ++ * Then look for the least recently used non-dirty one. ++ * Then look for the least recently used dirty one...., flush and look again. ++ */ ++static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev) ++{ ++ int i; ++ ++ if (dev->param.n_caches > 0) { ++ for (i = 0; i < dev->param.n_caches; i++) { ++ if (!dev->cache[i].object) ++ return &dev->cache[i]; ++ } ++ } ++ return NULL; ++} ++ ++static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev) ++{ ++ struct yaffs_cache *cache; ++ struct yaffs_obj *the_obj; ++ int usage; ++ int i; ++ int pushout; ++ ++ if (dev->param.n_caches < 1) ++ return NULL; ++ ++ /* Try find a non-dirty one... */ ++ ++ cache = yaffs_grab_chunk_worker(dev); ++ ++ if (!cache) { ++ /* They were all dirty, find the LRU object and flush ++ * its cache, then find again. ++ * NB what's here is not very accurate, ++ * we actually flush the object with the LRU chunk. ++ */ ++ ++ /* With locking we can't assume we can use entry zero, ++ * Set the_obj to a valid pointer for Coverity. */ ++ the_obj = dev->cache[0].object; ++ usage = -1; ++ cache = NULL; ++ pushout = -1; ++ ++ for (i = 0; i < dev->param.n_caches; i++) { ++ if (dev->cache[i].object && ++ !dev->cache[i].locked && ++ (dev->cache[i].last_use < usage || ++ !cache)) { ++ usage = dev->cache[i].last_use; ++ the_obj = dev->cache[i].object; ++ cache = &dev->cache[i]; ++ pushout = i; ++ } ++ } ++ ++ if (!cache || cache->dirty) { ++ /* Flush and try again */ ++ yaffs_flush_file_cache(the_obj); ++ cache = yaffs_grab_chunk_worker(dev); ++ } ++ } ++ return cache; ++} ++ ++/* Find a cached chunk */ ++static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj, ++ int chunk_id) ++{ ++ struct yaffs_dev *dev = obj->my_dev; ++ int i; ++ ++ if (dev->param.n_caches < 1) ++ return NULL; ++ ++ for (i = 0; i < dev->param.n_caches; i++) { ++ if (dev->cache[i].object == obj && ++ dev->cache[i].chunk_id == chunk_id) { ++ dev->cache_hits++; ++ ++ return &dev->cache[i]; ++ } ++ } ++ return NULL; ++} ++ ++/* Mark the chunk for the least recently used algorithym */ ++static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache, ++ int is_write) ++{ ++ int i; ++ ++ if (dev->param.n_caches < 1) ++ return; ++ ++ if (dev->cache_last_use < 0 || ++ dev->cache_last_use > 100000000) { ++ /* Reset the cache usages */ ++ for (i = 1; i < dev->param.n_caches; i++) ++ dev->cache[i].last_use = 0; ++ ++ dev->cache_last_use = 0; ++ } ++ dev->cache_last_use++; ++ cache->last_use = dev->cache_last_use; ++ ++ if (is_write) ++ cache->dirty = 1; ++} ++ ++/* Invalidate a single cache page. ++ * Do this when a whole page gets written, ++ * ie the short cache for this page is no longer valid. ++ */ ++static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id) ++{ ++ struct yaffs_cache *cache; ++ ++ if (object->my_dev->param.n_caches > 0) { ++ cache = yaffs_find_chunk_cache(object, chunk_id); ++ ++ if (cache) ++ cache->object = NULL; ++ } ++} ++ ++/* Invalidate all the cache pages associated with this object ++ * Do this whenever ther file is deleted or resized. ++ */ ++static void yaffs_invalidate_whole_cache(struct yaffs_obj *in) ++{ ++ int i; ++ struct yaffs_dev *dev = in->my_dev; ++ ++ if (dev->param.n_caches > 0) { ++ /* Invalidate it. */ ++ for (i = 0; i < dev->param.n_caches; i++) { ++ if (dev->cache[i].object == in) ++ dev->cache[i].object = NULL; ++ } ++ } ++} ++ ++static void yaffs_unhash_obj(struct yaffs_obj *obj) ++{ ++ int bucket; ++ struct yaffs_dev *dev = obj->my_dev; ++ ++ /* If it is still linked into the bucket list, free from the list */ ++ if (!list_empty(&obj->hash_link)) { ++ list_del_init(&obj->hash_link); ++ bucket = yaffs_hash_fn(obj->obj_id); ++ dev->obj_bucket[bucket].count--; ++ } ++} ++ ++/* FreeObject frees up a Object and puts it back on the free list */ ++static void yaffs_free_obj(struct yaffs_obj *obj) ++{ ++ struct yaffs_dev *dev; ++ ++ if (!obj) { ++ BUG(); ++ return; ++ } ++ dev = obj->my_dev; ++ yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p", ++ obj, obj->my_inode); ++ if (obj->parent) ++ BUG(); ++ if (!list_empty(&obj->siblings)) ++ BUG(); ++ ++ if (obj->my_inode) { ++ /* We're still hooked up to a cached inode. ++ * Don't delete now, but mark for later deletion ++ */ ++ obj->defered_free = 1; ++ return; ++ } ++ ++ yaffs_unhash_obj(obj); ++ ++ yaffs_free_raw_obj(dev, obj); ++ dev->n_obj--; ++ dev->checkpoint_blocks_required = 0; /* force recalculation */ ++} ++ ++void yaffs_handle_defered_free(struct yaffs_obj *obj) ++{ ++ if (obj->defered_free) ++ yaffs_free_obj(obj); ++} ++ ++static int yaffs_generic_obj_del(struct yaffs_obj *in) ++{ ++ /* Iinvalidate the file's data in the cache, without flushing. */ ++ yaffs_invalidate_whole_cache(in); ++ ++ if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) { ++ /* Move to unlinked directory so we have a deletion record */ ++ yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0, ++ 0); ++ } ++ ++ yaffs_remove_obj_from_dir(in); ++ yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__); ++ in->hdr_chunk = 0; ++ ++ yaffs_free_obj(in); ++ return YAFFS_OK; ++ ++} ++ ++static void yaffs_soft_del_file(struct yaffs_obj *obj) ++{ ++ if (!obj->deleted || ++ obj->variant_type != YAFFS_OBJECT_TYPE_FILE || ++ obj->soft_del) ++ return; ++ ++ if (obj->n_data_chunks <= 0) { ++ /* Empty file with no duplicate object headers, ++ * just delete it immediately */ ++ yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top); ++ obj->variant.file_variant.top = NULL; ++ yaffs_trace(YAFFS_TRACE_TRACING, ++ "yaffs: Deleting empty file %d", ++ obj->obj_id); ++ yaffs_generic_obj_del(obj); ++ } else { ++ yaffs_soft_del_worker(obj, ++ obj->variant.file_variant.top, ++ obj->variant. ++ file_variant.top_level, 0); ++ obj->soft_del = 1; ++ } ++} ++ ++/* Pruning removes any part of the file structure tree that is beyond the ++ * bounds of the file (ie that does not point to chunks). ++ * ++ * A file should only get pruned when its size is reduced. ++ * ++ * Before pruning, the chunks must be pulled from the tree and the ++ * level 0 tnode entries must be zeroed out. ++ * Could also use this for file deletion, but that's probably better handled ++ * by a special case. ++ * ++ * This function is recursive. For levels > 0 the function is called again on ++ * any sub-tree. For level == 0 we just check if the sub-tree has data. ++ * If there is no data in a subtree then it is pruned. ++ */ ++ ++static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev, ++ struct yaffs_tnode *tn, u32 level, ++ int del0) ++{ ++ int i; ++ int has_data; ++ ++ if (!tn) ++ return tn; ++ ++ has_data = 0; ++ ++ if (level > 0) { ++ for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) { ++ if (tn->internal[i]) { ++ tn->internal[i] = ++ yaffs_prune_worker(dev, ++ tn->internal[i], ++ level - 1, ++ (i == 0) ? del0 : 1); ++ } ++ ++ if (tn->internal[i]) ++ has_data++; ++ } ++ } else { ++ int tnode_size_u32 = dev->tnode_size / sizeof(u32); ++ u32 *map = (u32 *) tn; ++ ++ for (i = 0; !has_data && i < tnode_size_u32; i++) { ++ if (map[i]) ++ has_data++; ++ } ++ } ++ ++ if (has_data == 0 && del0) { ++ /* Free and return NULL */ ++ yaffs_free_tnode(dev, tn); ++ tn = NULL; ++ } ++ return tn; ++} ++ ++static int yaffs_prune_tree(struct yaffs_dev *dev, ++ struct yaffs_file_var *file_struct) ++{ ++ int i; ++ int has_data; ++ int done = 0; ++ struct yaffs_tnode *tn; ++ ++ if (file_struct->top_level < 1) ++ return YAFFS_OK; ++ ++ file_struct->top = ++ yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0); ++ ++ /* Now we have a tree with all the non-zero branches NULL but ++ * the height is the same as it was. ++ * Let's see if we can trim internal tnodes to shorten the tree. ++ * We can do this if only the 0th element in the tnode is in use ++ * (ie all the non-zero are NULL) ++ */ ++ ++ while (file_struct->top_level && !done) { ++ tn = file_struct->top; ++ ++ has_data = 0; ++ for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) { ++ if (tn->internal[i]) ++ has_data++; ++ } ++ ++ if (!has_data) { ++ file_struct->top = tn->internal[0]; ++ file_struct->top_level--; ++ yaffs_free_tnode(dev, tn); ++ } else { ++ done = 1; ++ } ++ } ++ ++ return YAFFS_OK; ++} ++ ++/*-------------------- End of File Structure functions.-------------------*/ ++ ++/* alloc_empty_obj gets us a clean Object.*/ ++static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev) ++{ ++ struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev); ++ ++ if (!obj) ++ return obj; ++ ++ dev->n_obj++; ++ ++ /* Now sweeten it up... */ ++ ++ memset(obj, 0, sizeof(struct yaffs_obj)); ++ obj->being_created = 1; ++ ++ obj->my_dev = dev; ++ obj->hdr_chunk = 0; ++ obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN; ++ INIT_LIST_HEAD(&(obj->hard_links)); ++ INIT_LIST_HEAD(&(obj->hash_link)); ++ INIT_LIST_HEAD(&obj->siblings); ++ ++ /* Now make the directory sane */ ++ if (dev->root_dir) { ++ obj->parent = dev->root_dir; ++ list_add(&(obj->siblings), ++ &dev->root_dir->variant.dir_variant.children); ++ } ++ ++ /* Add it to the lost and found directory. ++ * NB Can't put root or lost-n-found in lost-n-found so ++ * check if lost-n-found exists first ++ */ ++ if (dev->lost_n_found) ++ yaffs_add_obj_to_dir(dev->lost_n_found, obj); ++ ++ obj->being_created = 0; ++ ++ dev->checkpoint_blocks_required = 0; /* force recalculation */ ++ ++ return obj; ++} ++ ++static int yaffs_find_nice_bucket(struct yaffs_dev *dev) ++{ ++ int i; ++ int l = 999; ++ int lowest = 999999; ++ ++ /* Search for the shortest list or one that ++ * isn't too long. ++ */ ++ ++ for (i = 0; i < 10 && lowest > 4; i++) { ++ dev->bucket_finder++; ++ dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS; ++ if (dev->obj_bucket[dev->bucket_finder].count < lowest) { ++ lowest = dev->obj_bucket[dev->bucket_finder].count; ++ l = dev->bucket_finder; ++ } ++ } ++ ++ return l; ++} ++ ++static int yaffs_new_obj_id(struct yaffs_dev *dev) ++{ ++ int bucket = yaffs_find_nice_bucket(dev); ++ int found = 0; ++ struct list_head *i; ++ u32 n = (u32) bucket; ++ ++ /* Now find an object value that has not already been taken ++ * by scanning the list. ++ */ ++ ++ while (!found) { ++ found = 1; ++ n += YAFFS_NOBJECT_BUCKETS; ++ if (1 || dev->obj_bucket[bucket].count > 0) { ++ list_for_each(i, &dev->obj_bucket[bucket].list) { ++ /* If there is already one in the list */ ++ if (i && list_entry(i, struct yaffs_obj, ++ hash_link)->obj_id == n) { ++ found = 0; ++ } ++ } ++ } ++ } ++ return n; ++} ++ ++static void yaffs_hash_obj(struct yaffs_obj *in) ++{ ++ int bucket = yaffs_hash_fn(in->obj_id); ++ struct yaffs_dev *dev = in->my_dev; ++ ++ list_add(&in->hash_link, &dev->obj_bucket[bucket].list); ++ dev->obj_bucket[bucket].count++; ++} ++ ++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number) ++{ ++ int bucket = yaffs_hash_fn(number); ++ struct list_head *i; ++ struct yaffs_obj *in; ++ ++ list_for_each(i, &dev->obj_bucket[bucket].list) { ++ /* Look if it is in the list */ ++ in = list_entry(i, struct yaffs_obj, hash_link); ++ if (in->obj_id == number) { ++ /* Don't show if it is defered free */ ++ if (in->defered_free) ++ return NULL; ++ return in; ++ } ++ } ++ ++ return NULL; ++} ++ ++static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number, ++ enum yaffs_obj_type type) ++{ ++ struct yaffs_obj *the_obj = NULL; ++ struct yaffs_tnode *tn = NULL; ++ ++ if (number < 0) ++ number = yaffs_new_obj_id(dev); ++ ++ if (type == YAFFS_OBJECT_TYPE_FILE) { ++ tn = yaffs_get_tnode(dev); ++ if (!tn) ++ return NULL; ++ } ++ ++ the_obj = yaffs_alloc_empty_obj(dev); ++ if (!the_obj) { ++ if (tn) ++ yaffs_free_tnode(dev, tn); ++ return NULL; ++ } ++ ++ the_obj->fake = 0; ++ the_obj->rename_allowed = 1; ++ the_obj->unlink_allowed = 1; ++ the_obj->obj_id = number; ++ yaffs_hash_obj(the_obj); ++ the_obj->variant_type = type; ++ yaffs_load_current_time(the_obj, 1, 1); ++ ++ switch (type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ the_obj->variant.file_variant.file_size = 0; ++ the_obj->variant.file_variant.scanned_size = 0; ++ the_obj->variant.file_variant.shrink_size = ++ yaffs_max_file_size(dev); ++ the_obj->variant.file_variant.top_level = 0; ++ the_obj->variant.file_variant.top = tn; ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ INIT_LIST_HEAD(&the_obj->variant.dir_variant.children); ++ INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ /* No action required */ ++ break; ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* todo this should not happen */ ++ break; ++ } ++ return the_obj; ++} ++ ++static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev, ++ int number, u32 mode) ++{ ++ ++ struct yaffs_obj *obj = ++ yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY); ++ ++ if (!obj) ++ return NULL; ++ ++ obj->fake = 1; /* it is fake so it might not use NAND */ ++ obj->rename_allowed = 0; ++ obj->unlink_allowed = 0; ++ obj->deleted = 0; ++ obj->unlinked = 0; ++ obj->yst_mode = mode; ++ obj->my_dev = dev; ++ obj->hdr_chunk = 0; /* Not a valid chunk. */ ++ return obj; ++ ++} ++ ++ ++static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev) ++{ ++ int i; ++ ++ dev->n_obj = 0; ++ dev->n_tnodes = 0; ++ yaffs_init_raw_tnodes_and_objs(dev); ++ ++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { ++ INIT_LIST_HEAD(&dev->obj_bucket[i].list); ++ dev->obj_bucket[i].count = 0; ++ } ++} ++ ++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev, ++ int number, ++ enum yaffs_obj_type type) ++{ ++ struct yaffs_obj *the_obj = NULL; ++ ++ if (number > 0) ++ the_obj = yaffs_find_by_number(dev, number); ++ ++ if (!the_obj) ++ the_obj = yaffs_new_obj(dev, number, type); ++ ++ return the_obj; ++ ++} ++ ++YCHAR *yaffs_clone_str(const YCHAR *str) ++{ ++ YCHAR *new_str = NULL; ++ int len; ++ ++ if (!str) ++ str = _Y(""); ++ ++ len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH); ++ new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS); ++ if (new_str) { ++ strncpy(new_str, str, len); ++ new_str[len] = 0; ++ } ++ return new_str; ++ ++} ++/* ++ *yaffs_update_parent() handles fixing a directories mtime and ctime when a new ++ * link (ie. name) is created or deleted in the directory. ++ * ++ * ie. ++ * create dir/a : update dir's mtime/ctime ++ * rm dir/a: update dir's mtime/ctime ++ * modify dir/a: don't update dir's mtimme/ctime ++ * ++ * This can be handled immediately or defered. Defering helps reduce the number ++ * of updates when many files in a directory are changed within a brief period. ++ * ++ * If the directory updating is defered then yaffs_update_dirty_dirs must be ++ * called periodically. ++ */ ++ ++static void yaffs_update_parent(struct yaffs_obj *obj) ++{ ++ struct yaffs_dev *dev; ++ ++ if (!obj) ++ return; ++ dev = obj->my_dev; ++ obj->dirty = 1; ++ yaffs_load_current_time(obj, 0, 1); ++ if (dev->param.defered_dir_update) { ++ struct list_head *link = &obj->variant.dir_variant.dirty; ++ ++ if (list_empty(link)) { ++ list_add(link, &dev->dirty_dirs); ++ yaffs_trace(YAFFS_TRACE_BACKGROUND, ++ "Added object %d to dirty directories", ++ obj->obj_id); ++ } ++ ++ } else { ++ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL); ++ } ++} ++ ++void yaffs_update_dirty_dirs(struct yaffs_dev *dev) ++{ ++ struct list_head *link; ++ struct yaffs_obj *obj; ++ struct yaffs_dir_var *d_s; ++ union yaffs_obj_var *o_v; ++ ++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories"); ++ ++ while (!list_empty(&dev->dirty_dirs)) { ++ link = dev->dirty_dirs.next; ++ list_del_init(link); ++ ++ d_s = list_entry(link, struct yaffs_dir_var, dirty); ++ o_v = list_entry(d_s, union yaffs_obj_var, dir_variant); ++ obj = list_entry(o_v, struct yaffs_obj, variant); ++ ++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d", ++ obj->obj_id); ++ ++ if (obj->dirty) ++ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL); ++ } ++} ++ ++/* ++ * Mknod (create) a new object. ++ * equiv_obj only has meaning for a hard link; ++ * alias_str only has meaning for a symlink. ++ * rdev only has meaning for devices (a subset of special objects) ++ */ ++ ++static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type, ++ struct yaffs_obj *parent, ++ const YCHAR *name, ++ u32 mode, ++ u32 uid, ++ u32 gid, ++ struct yaffs_obj *equiv_obj, ++ const YCHAR *alias_str, u32 rdev) ++{ ++ struct yaffs_obj *in; ++ YCHAR *str = NULL; ++ struct yaffs_dev *dev = parent->my_dev; ++ ++ /* Check if the entry exists. ++ * If it does then fail the call since we don't want a dup. */ ++ if (yaffs_find_by_name(parent, name)) ++ return NULL; ++ ++ if (type == YAFFS_OBJECT_TYPE_SYMLINK) { ++ str = yaffs_clone_str(alias_str); ++ if (!str) ++ return NULL; ++ } ++ ++ in = yaffs_new_obj(dev, -1, type); ++ ++ if (!in) { ++ kfree(str); ++ return NULL; ++ } ++ ++ in->hdr_chunk = 0; ++ in->valid = 1; ++ in->variant_type = type; ++ ++ in->yst_mode = mode; ++ ++ yaffs_attribs_init(in, gid, uid, rdev); ++ ++ in->n_data_chunks = 0; ++ ++ yaffs_set_obj_name(in, name); ++ in->dirty = 1; ++ ++ yaffs_add_obj_to_dir(parent, in); ++ ++ in->my_dev = parent->my_dev; ++ ++ switch (type) { ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ in->variant.symlink_variant.alias = str; ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ in->variant.hardlink_variant.equiv_obj = equiv_obj; ++ in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id; ++ list_add(&in->hard_links, &equiv_obj->hard_links); ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* do nothing */ ++ break; ++ } ++ ++ if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) { ++ /* Could not create the object header, fail */ ++ yaffs_del_obj(in); ++ in = NULL; ++ } ++ ++ if (in) ++ yaffs_update_parent(parent); ++ ++ return in; ++} ++ ++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent, ++ const YCHAR *name, u32 mode, u32 uid, ++ u32 gid) ++{ ++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode, ++ uid, gid, NULL, NULL, 0); ++} ++ ++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name, ++ u32 mode, u32 uid, u32 gid) ++{ ++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name, ++ mode, uid, gid, NULL, NULL, 0); ++} ++ ++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent, ++ const YCHAR *name, u32 mode, u32 uid, ++ u32 gid, u32 rdev) ++{ ++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode, ++ uid, gid, NULL, NULL, rdev); ++} ++ ++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent, ++ const YCHAR *name, u32 mode, u32 uid, ++ u32 gid, const YCHAR *alias) ++{ ++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode, ++ uid, gid, NULL, alias, 0); ++} ++ ++/* yaffs_link_obj returns the object id of the equivalent object.*/ ++struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name, ++ struct yaffs_obj *equiv_obj) ++{ ++ /* Get the real object in case we were fed a hard link obj */ ++ equiv_obj = yaffs_get_equivalent_obj(equiv_obj); ++ ++ if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK, ++ parent, name, 0, 0, 0, ++ equiv_obj, NULL, 0)) ++ return equiv_obj; ++ ++ return NULL; ++ ++} ++ ++ ++ ++/*---------------------- Block Management and Page Allocation -------------*/ ++ ++static void yaffs_deinit_blocks(struct yaffs_dev *dev) ++{ ++ if (dev->block_info_alt && dev->block_info) ++ vfree(dev->block_info); ++ else ++ kfree(dev->block_info); ++ ++ dev->block_info_alt = 0; ++ ++ dev->block_info = NULL; ++ ++ if (dev->chunk_bits_alt && dev->chunk_bits) ++ vfree(dev->chunk_bits); ++ else ++ kfree(dev->chunk_bits); ++ dev->chunk_bits_alt = 0; ++ dev->chunk_bits = NULL; ++} ++ ++static int yaffs_init_blocks(struct yaffs_dev *dev) ++{ ++ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1; ++ ++ dev->block_info = NULL; ++ dev->chunk_bits = NULL; ++ dev->alloc_block = -1; /* force it to get a new one */ ++ ++ /* If the first allocation strategy fails, thry the alternate one */ ++ dev->block_info = ++ kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS); ++ if (!dev->block_info) { ++ dev->block_info = ++ vmalloc(n_blocks * sizeof(struct yaffs_block_info)); ++ dev->block_info_alt = 1; ++ } else { ++ dev->block_info_alt = 0; ++ } ++ ++ if (!dev->block_info) ++ goto alloc_error; ++ ++ /* Set up dynamic blockinfo stuff. Round up bytes. */ ++ dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8; ++ dev->chunk_bits = ++ kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS); ++ if (!dev->chunk_bits) { ++ dev->chunk_bits = ++ vmalloc(dev->chunk_bit_stride * n_blocks); ++ dev->chunk_bits_alt = 1; ++ } else { ++ dev->chunk_bits_alt = 0; ++ } ++ if (!dev->chunk_bits) ++ goto alloc_error; ++ ++ ++ memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info)); ++ memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks); ++ return YAFFS_OK; ++ ++alloc_error: ++ yaffs_deinit_blocks(dev); ++ return YAFFS_FAIL; ++} ++ ++ ++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no) ++{ ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no); ++ int erased_ok = 0; ++ int i; ++ ++ /* If the block is still healthy erase it and mark as clean. ++ * If the block has had a data failure, then retire it. ++ */ ++ ++ yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE, ++ "yaffs_block_became_dirty block %d state %d %s", ++ block_no, bi->block_state, ++ (bi->needs_retiring) ? "needs retiring" : ""); ++ ++ yaffs2_clear_oldest_dirty_seq(dev, bi); ++ ++ bi->block_state = YAFFS_BLOCK_STATE_DIRTY; ++ ++ /* If this is the block being garbage collected then stop gc'ing */ ++ if (block_no == dev->gc_block) ++ dev->gc_block = 0; ++ ++ /* If this block is currently the best candidate for gc ++ * then drop as a candidate */ ++ if (block_no == dev->gc_dirtiest) { ++ dev->gc_dirtiest = 0; ++ dev->gc_pages_in_use = 0; ++ } ++ ++ if (!bi->needs_retiring) { ++ yaffs2_checkpt_invalidate(dev); ++ erased_ok = yaffs_erase_block(dev, block_no); ++ if (!erased_ok) { ++ dev->n_erase_failures++; ++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, ++ "**>> Erasure failed %d", block_no); ++ } ++ } ++ ++ /* Verify erasure if needed */ ++ if (erased_ok && ++ ((yaffs_trace_mask & YAFFS_TRACE_ERASE) || ++ !yaffs_skip_verification(dev))) { ++ for (i = 0; i < dev->param.chunks_per_block; i++) { ++ if (!yaffs_check_chunk_erased(dev, ++ block_no * dev->param.chunks_per_block + i)) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ ">>Block %d erasure supposedly OK, but chunk %d not erased", ++ block_no, i); ++ } ++ } ++ } ++ ++ if (!erased_ok) { ++ /* We lost a block of free space */ ++ dev->n_free_chunks -= dev->param.chunks_per_block; ++ yaffs_retire_block(dev, block_no); ++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, ++ "**>> Block %d retired", block_no); ++ return; ++ } ++ ++ /* Clean it up... */ ++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY; ++ bi->seq_number = 0; ++ dev->n_erased_blocks++; ++ bi->pages_in_use = 0; ++ bi->soft_del_pages = 0; ++ bi->has_shrink_hdr = 0; ++ bi->skip_erased_check = 1; /* Clean, so no need to check */ ++ bi->gc_prioritise = 0; ++ bi->has_summary = 0; ++ ++ yaffs_clear_chunk_bits(dev, block_no); ++ ++ yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no); ++} ++ ++static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev, ++ struct yaffs_block_info *bi, ++ int old_chunk, u8 *buffer) ++{ ++ int new_chunk; ++ int mark_flash = 1; ++ struct yaffs_ext_tags tags; ++ struct yaffs_obj *object; ++ int matching_chunk; ++ int ret_val = YAFFS_OK; ++ ++ memset(&tags, 0, sizeof(tags)); ++ yaffs_rd_chunk_tags_nand(dev, old_chunk, ++ buffer, &tags); ++ object = yaffs_find_by_number(dev, tags.obj_id); ++ ++ yaffs_trace(YAFFS_TRACE_GC_DETAIL, ++ "Collecting chunk in block %d, %d %d %d ", ++ dev->gc_chunk, tags.obj_id, ++ tags.chunk_id, tags.n_bytes); ++ ++ if (object && !yaffs_skip_verification(dev)) { ++ if (tags.chunk_id == 0) ++ matching_chunk = ++ object->hdr_chunk; ++ else if (object->soft_del) ++ /* Defeat the test */ ++ matching_chunk = old_chunk; ++ else ++ matching_chunk = ++ yaffs_find_chunk_in_file ++ (object, tags.chunk_id, ++ NULL); ++ ++ if (old_chunk != matching_chunk) ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "gc: page in gc mismatch: %d %d %d %d", ++ old_chunk, ++ matching_chunk, ++ tags.obj_id, ++ tags.chunk_id); ++ } ++ ++ if (!object) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "page %d in gc has no object: %d %d %d ", ++ old_chunk, ++ tags.obj_id, tags.chunk_id, ++ tags.n_bytes); ++ } ++ ++ if (object && ++ object->deleted && ++ object->soft_del && tags.chunk_id != 0) { ++ /* Data chunk in a soft deleted file, ++ * throw it away. ++ * It's a soft deleted data chunk, ++ * No need to copy this, just forget ++ * about it and fix up the object. ++ */ ++ ++ /* Free chunks already includes ++ * softdeleted chunks, how ever this ++ * chunk is going to soon be really ++ * deleted which will increment free ++ * chunks. We have to decrement free ++ * chunks so this works out properly. ++ */ ++ dev->n_free_chunks--; ++ bi->soft_del_pages--; ++ ++ object->n_data_chunks--; ++ if (object->n_data_chunks <= 0) { ++ /* remeber to clean up obj */ ++ dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id; ++ dev->n_clean_ups++; ++ } ++ mark_flash = 0; ++ } else if (object) { ++ /* It's either a data chunk in a live ++ * file or an ObjectHeader, so we're ++ * interested in it. ++ * NB Need to keep the ObjectHeaders of ++ * deleted files until the whole file ++ * has been deleted off ++ */ ++ tags.serial_number++; ++ dev->n_gc_copies++; ++ ++ if (tags.chunk_id == 0) { ++ /* It is an object Id, ++ * We need to nuke the ++ * shrinkheader flags since its ++ * work is done. ++ * Also need to clean up ++ * shadowing. ++ */ ++ struct yaffs_obj_hdr *oh; ++ oh = (struct yaffs_obj_hdr *) buffer; ++ ++ oh->is_shrink = 0; ++ tags.extra_is_shrink = 0; ++ oh->shadows_obj = 0; ++ oh->inband_shadowed_obj_id = 0; ++ tags.extra_shadows = 0; ++ ++ /* Update file size */ ++ if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) { ++ yaffs_oh_size_load(oh, ++ object->variant.file_variant.file_size); ++ tags.extra_file_size = ++ object->variant.file_variant.file_size; ++ } ++ ++ yaffs_verify_oh(object, oh, &tags, 1); ++ new_chunk = ++ yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1); ++ } else { ++ new_chunk = ++ yaffs_write_new_chunk(dev, buffer, &tags, 1); ++ } ++ ++ if (new_chunk < 0) { ++ ret_val = YAFFS_FAIL; ++ } else { ++ ++ /* Now fix up the Tnodes etc. */ ++ ++ if (tags.chunk_id == 0) { ++ /* It's a header */ ++ object->hdr_chunk = new_chunk; ++ object->serial = tags.serial_number; ++ } else { ++ /* It's a data chunk */ ++ yaffs_put_chunk_in_file(object, tags.chunk_id, ++ new_chunk, 0); ++ } ++ } ++ } ++ if (ret_val == YAFFS_OK) ++ yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__); ++ return ret_val; ++} ++ ++static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block) ++{ ++ int old_chunk; ++ int ret_val = YAFFS_OK; ++ int i; ++ int is_checkpt_block; ++ int max_copies; ++ int chunks_before = yaffs_get_erased_chunks(dev); ++ int chunks_after; ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block); ++ ++ is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT); ++ ++ yaffs_trace(YAFFS_TRACE_TRACING, ++ "Collecting block %d, in use %d, shrink %d, whole_block %d", ++ block, bi->pages_in_use, bi->has_shrink_hdr, ++ whole_block); ++ ++ /*yaffs_verify_free_chunks(dev); */ ++ ++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL) ++ bi->block_state = YAFFS_BLOCK_STATE_COLLECTING; ++ ++ bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */ ++ ++ dev->gc_disable = 1; ++ ++ yaffs_summary_gc(dev, block); ++ ++ if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) { ++ yaffs_trace(YAFFS_TRACE_TRACING, ++ "Collecting block %d that has no chunks in use", ++ block); ++ yaffs_block_became_dirty(dev, block); ++ } else { ++ ++ u8 *buffer = yaffs_get_temp_buffer(dev); ++ ++ yaffs_verify_blk(dev, bi, block); ++ ++ max_copies = (whole_block) ? dev->param.chunks_per_block : 5; ++ old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk; ++ ++ for (/* init already done */ ; ++ ret_val == YAFFS_OK && ++ dev->gc_chunk < dev->param.chunks_per_block && ++ (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) && ++ max_copies > 0; ++ dev->gc_chunk++, old_chunk++) { ++ if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) { ++ /* Page is in use and might need to be copied */ ++ max_copies--; ++ ret_val = yaffs_gc_process_chunk(dev, bi, ++ old_chunk, buffer); ++ } ++ } ++ yaffs_release_temp_buffer(dev, buffer); ++ } ++ ++ yaffs_verify_collected_blk(dev, bi, block); ++ ++ if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) { ++ /* ++ * The gc did not complete. Set block state back to FULL ++ * because checkpointing does not restore gc. ++ */ ++ bi->block_state = YAFFS_BLOCK_STATE_FULL; ++ } else { ++ /* The gc completed. */ ++ /* Do any required cleanups */ ++ for (i = 0; i < dev->n_clean_ups; i++) { ++ /* Time to delete the file too */ ++ struct yaffs_obj *object = ++ yaffs_find_by_number(dev, dev->gc_cleanup_list[i]); ++ if (object) { ++ yaffs_free_tnode(dev, ++ object->variant.file_variant.top); ++ object->variant.file_variant.top = NULL; ++ yaffs_trace(YAFFS_TRACE_GC, ++ "yaffs: About to finally delete object %d", ++ object->obj_id); ++ yaffs_generic_obj_del(object); ++ object->my_dev->n_deleted_files--; ++ } ++ ++ } ++ chunks_after = yaffs_get_erased_chunks(dev); ++ if (chunks_before >= chunks_after) ++ yaffs_trace(YAFFS_TRACE_GC, ++ "gc did not increase free chunks before %d after %d", ++ chunks_before, chunks_after); ++ dev->gc_block = 0; ++ dev->gc_chunk = 0; ++ dev->n_clean_ups = 0; ++ } ++ ++ dev->gc_disable = 0; ++ ++ return ret_val; ++} ++ ++/* ++ * find_gc_block() selects the dirtiest block (or close enough) ++ * for garbage collection. ++ */ ++ ++static unsigned yaffs_find_gc_block(struct yaffs_dev *dev, ++ int aggressive, int background) ++{ ++ int i; ++ int iterations; ++ unsigned selected = 0; ++ int prioritised = 0; ++ int prioritised_exist = 0; ++ struct yaffs_block_info *bi; ++ int threshold; ++ ++ /* First let's see if we need to grab a prioritised block */ ++ if (dev->has_pending_prioritised_gc && !aggressive) { ++ dev->gc_dirtiest = 0; ++ bi = dev->block_info; ++ for (i = dev->internal_start_block; ++ i <= dev->internal_end_block && !selected; i++) { ++ ++ if (bi->gc_prioritise) { ++ prioritised_exist = 1; ++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL && ++ yaffs_block_ok_for_gc(dev, bi)) { ++ selected = i; ++ prioritised = 1; ++ } ++ } ++ bi++; ++ } ++ ++ /* ++ * If there is a prioritised block and none was selected then ++ * this happened because there is at least one old dirty block ++ * gumming up the works. Let's gc the oldest dirty block. ++ */ ++ ++ if (prioritised_exist && ++ !selected && dev->oldest_dirty_block > 0) ++ selected = dev->oldest_dirty_block; ++ ++ if (!prioritised_exist) /* None found, so we can clear this */ ++ dev->has_pending_prioritised_gc = 0; ++ } ++ ++ /* If we're doing aggressive GC then we are happy to take a less-dirty ++ * block, and search harder. ++ * else (leasurely gc), then we only bother to do this if the ++ * block has only a few pages in use. ++ */ ++ ++ if (!selected) { ++ int pages_used; ++ int n_blocks = ++ dev->internal_end_block - dev->internal_start_block + 1; ++ if (aggressive) { ++ threshold = dev->param.chunks_per_block; ++ iterations = n_blocks; ++ } else { ++ int max_threshold; ++ ++ if (background) ++ max_threshold = dev->param.chunks_per_block / 2; ++ else ++ max_threshold = dev->param.chunks_per_block / 8; ++ ++ if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD) ++ max_threshold = YAFFS_GC_PASSIVE_THRESHOLD; ++ ++ threshold = background ? (dev->gc_not_done + 2) * 2 : 0; ++ if (threshold < YAFFS_GC_PASSIVE_THRESHOLD) ++ threshold = YAFFS_GC_PASSIVE_THRESHOLD; ++ if (threshold > max_threshold) ++ threshold = max_threshold; ++ ++ iterations = n_blocks / 16 + 1; ++ if (iterations > 100) ++ iterations = 100; ++ } ++ ++ for (i = 0; ++ i < iterations && ++ (dev->gc_dirtiest < 1 || ++ dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH); ++ i++) { ++ dev->gc_block_finder++; ++ if (dev->gc_block_finder < dev->internal_start_block || ++ dev->gc_block_finder > dev->internal_end_block) ++ dev->gc_block_finder = ++ dev->internal_start_block; ++ ++ bi = yaffs_get_block_info(dev, dev->gc_block_finder); ++ ++ pages_used = bi->pages_in_use - bi->soft_del_pages; ++ ++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL && ++ pages_used < dev->param.chunks_per_block && ++ (dev->gc_dirtiest < 1 || ++ pages_used < dev->gc_pages_in_use) && ++ yaffs_block_ok_for_gc(dev, bi)) { ++ dev->gc_dirtiest = dev->gc_block_finder; ++ dev->gc_pages_in_use = pages_used; ++ } ++ } ++ ++ if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold) ++ selected = dev->gc_dirtiest; ++ } ++ ++ /* ++ * If nothing has been selected for a while, try the oldest dirty ++ * because that's gumming up the works. ++ */ ++ ++ if (!selected && dev->param.is_yaffs2 && ++ dev->gc_not_done >= (background ? 10 : 20)) { ++ yaffs2_find_oldest_dirty_seq(dev); ++ if (dev->oldest_dirty_block > 0) { ++ selected = dev->oldest_dirty_block; ++ dev->gc_dirtiest = selected; ++ dev->oldest_dirty_gc_count++; ++ bi = yaffs_get_block_info(dev, selected); ++ dev->gc_pages_in_use = ++ bi->pages_in_use - bi->soft_del_pages; ++ } else { ++ dev->gc_not_done = 0; ++ } ++ } ++ ++ if (selected) { ++ yaffs_trace(YAFFS_TRACE_GC, ++ "GC Selected block %d with %d free, prioritised:%d", ++ selected, ++ dev->param.chunks_per_block - dev->gc_pages_in_use, ++ prioritised); ++ ++ dev->n_gc_blocks++; ++ if (background) ++ dev->bg_gcs++; ++ ++ dev->gc_dirtiest = 0; ++ dev->gc_pages_in_use = 0; ++ dev->gc_not_done = 0; ++ if (dev->refresh_skip > 0) ++ dev->refresh_skip--; ++ } else { ++ dev->gc_not_done++; ++ yaffs_trace(YAFFS_TRACE_GC, ++ "GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s", ++ dev->gc_block_finder, dev->gc_not_done, threshold, ++ dev->gc_dirtiest, dev->gc_pages_in_use, ++ dev->oldest_dirty_block, background ? " bg" : ""); ++ } ++ ++ return selected; ++} ++ ++/* New garbage collector ++ * If we're very low on erased blocks then we do aggressive garbage collection ++ * otherwise we do "leasurely" garbage collection. ++ * Aggressive gc looks further (whole array) and will accept less dirty blocks. ++ * Passive gc only inspects smaller areas and only accepts more dirty blocks. ++ * ++ * The idea is to help clear out space in a more spread-out manner. ++ * Dunno if it really does anything useful. ++ */ ++static int yaffs_check_gc(struct yaffs_dev *dev, int background) ++{ ++ int aggressive = 0; ++ int gc_ok = YAFFS_OK; ++ int max_tries = 0; ++ int min_erased; ++ int erased_chunks; ++ int checkpt_block_adjust; ++ ++ if (dev->param.gc_control_fn && ++ (dev->param.gc_control_fn(dev) & 1) == 0) ++ return YAFFS_OK; ++ ++ if (dev->gc_disable) ++ /* Bail out so we don't get recursive gc */ ++ return YAFFS_OK; ++ ++ /* This loop should pass the first time. ++ * Only loops here if the collection does not increase space. ++ */ ++ ++ do { ++ max_tries++; ++ ++ checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev); ++ ++ min_erased = ++ dev->param.n_reserved_blocks + checkpt_block_adjust + 1; ++ erased_chunks = ++ dev->n_erased_blocks * dev->param.chunks_per_block; ++ ++ /* If we need a block soon then do aggressive gc. */ ++ if (dev->n_erased_blocks < min_erased) ++ aggressive = 1; ++ else { ++ if (!background ++ && erased_chunks > (dev->n_free_chunks / 4)) ++ break; ++ ++ if (dev->gc_skip > 20) ++ dev->gc_skip = 20; ++ if (erased_chunks < dev->n_free_chunks / 2 || ++ dev->gc_skip < 1 || background) ++ aggressive = 0; ++ else { ++ dev->gc_skip--; ++ break; ++ } ++ } ++ ++ dev->gc_skip = 5; ++ ++ /* If we don't already have a block being gc'd then see if we ++ * should start another */ ++ ++ if (dev->gc_block < 1 && !aggressive) { ++ dev->gc_block = yaffs2_find_refresh_block(dev); ++ dev->gc_chunk = 0; ++ dev->n_clean_ups = 0; ++ } ++ if (dev->gc_block < 1) { ++ dev->gc_block = ++ yaffs_find_gc_block(dev, aggressive, background); ++ dev->gc_chunk = 0; ++ dev->n_clean_ups = 0; ++ } ++ ++ if (dev->gc_block > 0) { ++ dev->all_gcs++; ++ if (!aggressive) ++ dev->passive_gc_count++; ++ ++ yaffs_trace(YAFFS_TRACE_GC, ++ "yaffs: GC n_erased_blocks %d aggressive %d", ++ dev->n_erased_blocks, aggressive); ++ ++ gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive); ++ } ++ ++ if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) && ++ dev->gc_block > 0) { ++ yaffs_trace(YAFFS_TRACE_GC, ++ "yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d", ++ dev->n_erased_blocks, max_tries, ++ dev->gc_block); ++ } ++ } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) && ++ (dev->gc_block > 0) && (max_tries < 2)); ++ ++ return aggressive ? gc_ok : YAFFS_OK; ++} ++ ++/* ++ * yaffs_bg_gc() ++ * Garbage collects. Intended to be called from a background thread. ++ * Returns non-zero if at least half the free chunks are erased. ++ */ ++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency) ++{ ++ int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block; ++ ++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency); ++ ++ yaffs_check_gc(dev, 1); ++ return erased_chunks > dev->n_free_chunks / 2; ++} ++ ++/*-------------------- Data file manipulation -----------------*/ ++ ++static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer) ++{ ++ int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL); ++ ++ if (nand_chunk >= 0) ++ return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk, ++ buffer, NULL); ++ else { ++ yaffs_trace(YAFFS_TRACE_NANDACCESS, ++ "Chunk %d not found zero instead", ++ nand_chunk); ++ /* get sane (zero) data if you read a hole */ ++ memset(buffer, 0, in->my_dev->data_bytes_per_chunk); ++ return 0; ++ } ++ ++} ++ ++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash, ++ int lyn) ++{ ++ int block; ++ int page; ++ struct yaffs_ext_tags tags; ++ struct yaffs_block_info *bi; ++ ++ if (chunk_id <= 0) ++ return; ++ ++ dev->n_deletions++; ++ block = chunk_id / dev->param.chunks_per_block; ++ page = chunk_id % dev->param.chunks_per_block; ++ ++ if (!yaffs_check_chunk_bit(dev, block, page)) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Deleting invalid chunk %d", chunk_id); ++ ++ bi = yaffs_get_block_info(dev, block); ++ ++ yaffs2_update_oldest_dirty_seq(dev, block, bi); ++ ++ yaffs_trace(YAFFS_TRACE_DELETION, ++ "line %d delete of chunk %d", ++ lyn, chunk_id); ++ ++ if (!dev->param.is_yaffs2 && mark_flash && ++ bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) { ++ ++ memset(&tags, 0, sizeof(tags)); ++ tags.is_deleted = 1; ++ yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags); ++ yaffs_handle_chunk_update(dev, chunk_id, &tags); ++ } else { ++ dev->n_unmarked_deletions++; ++ } ++ ++ /* Pull out of the management area. ++ * If the whole block became dirty, this will kick off an erasure. ++ */ ++ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING || ++ bi->block_state == YAFFS_BLOCK_STATE_FULL || ++ bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN || ++ bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) { ++ dev->n_free_chunks++; ++ yaffs_clear_chunk_bit(dev, block, page); ++ bi->pages_in_use--; ++ ++ if (bi->pages_in_use == 0 && ++ !bi->has_shrink_hdr && ++ bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING && ++ bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) { ++ yaffs_block_became_dirty(dev, block); ++ } ++ } ++} ++ ++static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, ++ const u8 *buffer, int n_bytes, int use_reserve) ++{ ++ /* Find old chunk Need to do this to get serial number ++ * Write new one and patch into tree. ++ * Invalidate old tags. ++ */ ++ ++ int prev_chunk_id; ++ struct yaffs_ext_tags prev_tags; ++ int new_chunk_id; ++ struct yaffs_ext_tags new_tags; ++ struct yaffs_dev *dev = in->my_dev; ++ ++ yaffs_check_gc(dev, 0); ++ ++ /* Get the previous chunk at this location in the file if it exists. ++ * If it does not exist then put a zero into the tree. This creates ++ * the tnode now, rather than later when it is harder to clean up. ++ */ ++ prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags); ++ if (prev_chunk_id < 1 && ++ !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0)) ++ return 0; ++ ++ /* Set up new tags */ ++ memset(&new_tags, 0, sizeof(new_tags)); ++ ++ new_tags.chunk_id = inode_chunk; ++ new_tags.obj_id = in->obj_id; ++ new_tags.serial_number = ++ (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1; ++ new_tags.n_bytes = n_bytes; ++ ++ if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "Writing %d bytes to chunk!!!!!!!!!", ++ n_bytes); ++ BUG(); ++ } ++ ++ new_chunk_id = ++ yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve); ++ ++ if (new_chunk_id > 0) { ++ yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0); ++ ++ if (prev_chunk_id > 0) ++ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__); ++ ++ yaffs_verify_file_sane(in); ++ } ++ return new_chunk_id; ++ ++} ++ ++ ++ ++static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set, ++ const YCHAR *name, const void *value, int size, ++ int flags) ++{ ++ struct yaffs_xattr_mod xmod; ++ int result; ++ ++ xmod.set = set; ++ xmod.name = name; ++ xmod.data = value; ++ xmod.size = size; ++ xmod.flags = flags; ++ xmod.result = -ENOSPC; ++ ++ result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod); ++ ++ if (result > 0) ++ return xmod.result; ++ else ++ return -ENOSPC; ++} ++ ++static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer, ++ struct yaffs_xattr_mod *xmod) ++{ ++ int retval = 0; ++ int x_offs = sizeof(struct yaffs_obj_hdr); ++ struct yaffs_dev *dev = obj->my_dev; ++ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr); ++ char *x_buffer = buffer + x_offs; ++ ++ if (xmod->set) ++ retval = ++ nval_set(x_buffer, x_size, xmod->name, xmod->data, ++ xmod->size, xmod->flags); ++ else ++ retval = nval_del(x_buffer, x_size, xmod->name); ++ ++ obj->has_xattr = nval_hasvalues(x_buffer, x_size); ++ obj->xattr_known = 1; ++ xmod->result = retval; ++ ++ return retval; ++} ++ ++static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name, ++ void *value, int size) ++{ ++ char *buffer = NULL; ++ int result; ++ struct yaffs_ext_tags tags; ++ struct yaffs_dev *dev = obj->my_dev; ++ int x_offs = sizeof(struct yaffs_obj_hdr); ++ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr); ++ char *x_buffer; ++ int retval = 0; ++ ++ if (obj->hdr_chunk < 1) ++ return -ENODATA; ++ ++ /* If we know that the object has no xattribs then don't do all the ++ * reading and parsing. ++ */ ++ if (obj->xattr_known && !obj->has_xattr) { ++ if (name) ++ return -ENODATA; ++ else ++ return 0; ++ } ++ ++ buffer = (char *)yaffs_get_temp_buffer(dev); ++ if (!buffer) ++ return -ENOMEM; ++ ++ result = ++ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags); ++ ++ if (result != YAFFS_OK) ++ retval = -ENOENT; ++ else { ++ x_buffer = buffer + x_offs; ++ ++ if (!obj->xattr_known) { ++ obj->has_xattr = nval_hasvalues(x_buffer, x_size); ++ obj->xattr_known = 1; ++ } ++ ++ if (name) ++ retval = nval_get(x_buffer, x_size, name, value, size); ++ else ++ retval = nval_list(x_buffer, x_size, value, size); ++ } ++ yaffs_release_temp_buffer(dev, (u8 *) buffer); ++ return retval; ++} ++ ++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name, ++ const void *value, int size, int flags) ++{ ++ return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags); ++} ++ ++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name) ++{ ++ return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0); ++} ++ ++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value, ++ int size) ++{ ++ return yaffs_do_xattrib_fetch(obj, name, value, size); ++} ++ ++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size) ++{ ++ return yaffs_do_xattrib_fetch(obj, NULL, buffer, size); ++} ++ ++static void yaffs_check_obj_details_loaded(struct yaffs_obj *in) ++{ ++ u8 *buf; ++ struct yaffs_obj_hdr *oh; ++ struct yaffs_dev *dev; ++ struct yaffs_ext_tags tags; ++ int result; ++ int alloc_failed = 0; ++ ++ if (!in || !in->lazy_loaded || in->hdr_chunk < 1) ++ return; ++ ++ dev = in->my_dev; ++ in->lazy_loaded = 0; ++ buf = yaffs_get_temp_buffer(dev); ++ ++ result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags); ++ oh = (struct yaffs_obj_hdr *)buf; ++ ++ in->yst_mode = oh->yst_mode; ++ yaffs_load_attribs(in, oh); ++ yaffs_set_obj_name_from_oh(in, oh); ++ ++ if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) { ++ in->variant.symlink_variant.alias = ++ yaffs_clone_str(oh->alias); ++ if (!in->variant.symlink_variant.alias) ++ alloc_failed = 1; /* Not returned */ ++ } ++ yaffs_release_temp_buffer(dev, buf); ++} ++ ++static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name, ++ const YCHAR *oh_name, int buff_size) ++{ ++#ifdef CONFIG_YAFFS_AUTO_UNICODE ++ if (dev->param.auto_unicode) { ++ if (*oh_name) { ++ /* It is an ASCII name, do an ASCII to ++ * unicode conversion */ ++ const char *ascii_oh_name = (const char *)oh_name; ++ int n = buff_size - 1; ++ while (n > 0 && *ascii_oh_name) { ++ *name = *ascii_oh_name; ++ name++; ++ ascii_oh_name++; ++ n--; ++ } ++ } else { ++ strncpy(name, oh_name + 1, buff_size - 1); ++ } ++ } else { ++#else ++ (void) dev; ++ { ++#endif ++ strncpy(name, oh_name, buff_size - 1); ++ } ++} ++ ++static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name, ++ const YCHAR *name) ++{ ++#ifdef CONFIG_YAFFS_AUTO_UNICODE ++ ++ int is_ascii; ++ YCHAR *w; ++ ++ if (dev->param.auto_unicode) { ++ ++ is_ascii = 1; ++ w = name; ++ ++ /* Figure out if the name will fit in ascii character set */ ++ while (is_ascii && *w) { ++ if ((*w) & 0xff00) ++ is_ascii = 0; ++ w++; ++ } ++ ++ if (is_ascii) { ++ /* It is an ASCII name, so convert unicode to ascii */ ++ char *ascii_oh_name = (char *)oh_name; ++ int n = YAFFS_MAX_NAME_LENGTH - 1; ++ while (n > 0 && *name) { ++ *ascii_oh_name = *name; ++ name++; ++ ascii_oh_name++; ++ n--; ++ } ++ } else { ++ /* Unicode name, so save starting at the second YCHAR */ ++ *oh_name = 0; ++ strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2); ++ } ++ } else { ++#else ++ dev = dev; ++ { ++#endif ++ strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1); ++ } ++} ++ ++/* UpdateObjectHeader updates the header on NAND for an object. ++ * If name is not NULL, then that new name is used. ++ */ ++int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force, ++ int is_shrink, int shadows, struct yaffs_xattr_mod *xmod) ++{ ++ ++ struct yaffs_block_info *bi; ++ struct yaffs_dev *dev = in->my_dev; ++ int prev_chunk_id; ++ int ret_val = 0; ++ int result = 0; ++ int new_chunk_id; ++ struct yaffs_ext_tags new_tags; ++ struct yaffs_ext_tags old_tags; ++ const YCHAR *alias = NULL; ++ u8 *buffer = NULL; ++ YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1]; ++ struct yaffs_obj_hdr *oh = NULL; ++ loff_t file_size = 0; ++ ++ strcpy(old_name, _Y("silly old name")); ++ ++ if (in->fake && in != dev->root_dir && !force && !xmod) ++ return ret_val; ++ ++ yaffs_check_gc(dev, 0); ++ yaffs_check_obj_details_loaded(in); ++ ++ buffer = yaffs_get_temp_buffer(in->my_dev); ++ oh = (struct yaffs_obj_hdr *)buffer; ++ ++ prev_chunk_id = in->hdr_chunk; ++ ++ if (prev_chunk_id > 0) { ++ result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id, ++ buffer, &old_tags); ++ ++ yaffs_verify_oh(in, oh, &old_tags, 0); ++ memcpy(old_name, oh->name, sizeof(oh->name)); ++ memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr)); ++ } else { ++ memset(buffer, 0xff, dev->data_bytes_per_chunk); ++ } ++ ++ oh->type = in->variant_type; ++ oh->yst_mode = in->yst_mode; ++ oh->shadows_obj = oh->inband_shadowed_obj_id = shadows; ++ ++ yaffs_load_attribs_oh(oh, in); ++ ++ if (in->parent) ++ oh->parent_obj_id = in->parent->obj_id; ++ else ++ oh->parent_obj_id = 0; ++ ++ if (name && *name) { ++ memset(oh->name, 0, sizeof(oh->name)); ++ yaffs_load_oh_from_name(dev, oh->name, name); ++ } else if (prev_chunk_id > 0) { ++ memcpy(oh->name, old_name, sizeof(oh->name)); ++ } else { ++ memset(oh->name, 0, sizeof(oh->name)); ++ } ++ ++ oh->is_shrink = is_shrink; ++ ++ switch (in->variant_type) { ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* Should not happen */ ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED && ++ oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED) ++ file_size = in->variant.file_variant.file_size; ++ yaffs_oh_size_load(oh, file_size); ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ oh->equiv_id = in->variant.hardlink_variant.equiv_id; ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ alias = in->variant.symlink_variant.alias; ++ if (!alias) ++ alias = _Y("no alias"); ++ strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH); ++ oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0; ++ break; ++ } ++ ++ /* process any xattrib modifications */ ++ if (xmod) ++ yaffs_apply_xattrib_mod(in, (char *)buffer, xmod); ++ ++ /* Tags */ ++ memset(&new_tags, 0, sizeof(new_tags)); ++ in->serial++; ++ new_tags.chunk_id = 0; ++ new_tags.obj_id = in->obj_id; ++ new_tags.serial_number = in->serial; ++ ++ /* Add extra info for file header */ ++ new_tags.extra_available = 1; ++ new_tags.extra_parent_id = oh->parent_obj_id; ++ new_tags.extra_file_size = file_size; ++ new_tags.extra_is_shrink = oh->is_shrink; ++ new_tags.extra_equiv_id = oh->equiv_id; ++ new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0; ++ new_tags.extra_obj_type = in->variant_type; ++ yaffs_verify_oh(in, oh, &new_tags, 1); ++ ++ /* Create new chunk in NAND */ ++ new_chunk_id = ++ yaffs_write_new_chunk(dev, buffer, &new_tags, ++ (prev_chunk_id > 0) ? 1 : 0); ++ ++ if (buffer) ++ yaffs_release_temp_buffer(dev, buffer); ++ ++ if (new_chunk_id < 0) ++ return new_chunk_id; ++ ++ in->hdr_chunk = new_chunk_id; ++ ++ if (prev_chunk_id > 0) ++ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__); ++ ++ if (!yaffs_obj_cache_dirty(in)) ++ in->dirty = 0; ++ ++ /* If this was a shrink, then mark the block ++ * that the chunk lives on */ ++ if (is_shrink) { ++ bi = yaffs_get_block_info(in->my_dev, ++ new_chunk_id / ++ in->my_dev->param.chunks_per_block); ++ bi->has_shrink_hdr = 1; ++ } ++ ++ ++ return new_chunk_id; ++} ++ ++/*--------------------- File read/write ------------------------ ++ * Read and write have very similar structures. ++ * In general the read/write has three parts to it ++ * An incomplete chunk to start with (if the read/write is not chunk-aligned) ++ * Some complete chunks ++ * An incomplete chunk to end off with ++ * ++ * Curve-balls: the first chunk might also be the last chunk. ++ */ ++ ++int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes) ++{ ++ int chunk; ++ u32 start; ++ int n_copy; ++ int n = n_bytes; ++ int n_done = 0; ++ struct yaffs_cache *cache; ++ struct yaffs_dev *dev; ++ ++ dev = in->my_dev; ++ ++ while (n > 0) { ++ yaffs_addr_to_chunk(dev, offset, &chunk, &start); ++ chunk++; ++ ++ /* OK now check for the curveball where the start and end are in ++ * the same chunk. ++ */ ++ if ((start + n) < dev->data_bytes_per_chunk) ++ n_copy = n; ++ else ++ n_copy = dev->data_bytes_per_chunk - start; ++ ++ cache = yaffs_find_chunk_cache(in, chunk); ++ ++ /* If the chunk is already in the cache or it is less than ++ * a whole chunk or we're using inband tags then use the cache ++ * (if there is caching) else bypass the cache. ++ */ ++ if (cache || n_copy != dev->data_bytes_per_chunk || ++ dev->param.inband_tags) { ++ if (dev->param.n_caches > 0) { ++ ++ /* If we can't find the data in the cache, ++ * then load it up. */ ++ ++ if (!cache) { ++ cache = ++ yaffs_grab_chunk_cache(in->my_dev); ++ cache->object = in; ++ cache->chunk_id = chunk; ++ cache->dirty = 0; ++ cache->locked = 0; ++ yaffs_rd_data_obj(in, chunk, ++ cache->data); ++ cache->n_bytes = 0; ++ } ++ ++ yaffs_use_cache(dev, cache, 0); ++ ++ cache->locked = 1; ++ ++ memcpy(buffer, &cache->data[start], n_copy); ++ ++ cache->locked = 0; ++ } else { ++ /* Read into the local buffer then copy.. */ ++ ++ u8 *local_buffer = ++ yaffs_get_temp_buffer(dev); ++ yaffs_rd_data_obj(in, chunk, local_buffer); ++ ++ memcpy(buffer, &local_buffer[start], n_copy); ++ ++ yaffs_release_temp_buffer(dev, local_buffer); ++ } ++ } else { ++ /* A full chunk. Read directly into the buffer. */ ++ yaffs_rd_data_obj(in, chunk, buffer); ++ } ++ n -= n_copy; ++ offset += n_copy; ++ buffer += n_copy; ++ n_done += n_copy; ++ } ++ return n_done; ++} ++ ++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset, ++ int n_bytes, int write_through) ++{ ++ ++ int chunk; ++ u32 start; ++ int n_copy; ++ int n = n_bytes; ++ int n_done = 0; ++ int n_writeback; ++ loff_t start_write = offset; ++ int chunk_written = 0; ++ u32 n_bytes_read; ++ loff_t chunk_start; ++ struct yaffs_dev *dev; ++ ++ dev = in->my_dev; ++ ++ while (n > 0 && chunk_written >= 0) { ++ yaffs_addr_to_chunk(dev, offset, &chunk, &start); ++ ++ if (((loff_t)chunk) * ++ dev->data_bytes_per_chunk + start != offset || ++ start >= dev->data_bytes_per_chunk) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "AddrToChunk of offset %lld gives chunk %d start %d", ++ offset, chunk, start); ++ } ++ chunk++; /* File pos to chunk in file offset */ ++ ++ /* OK now check for the curveball where the start and end are in ++ * the same chunk. ++ */ ++ ++ if ((start + n) < dev->data_bytes_per_chunk) { ++ n_copy = n; ++ ++ /* Now calculate how many bytes to write back.... ++ * If we're overwriting and not writing to then end of ++ * file then we need to write back as much as was there ++ * before. ++ */ ++ ++ chunk_start = (((loff_t)(chunk - 1)) * ++ dev->data_bytes_per_chunk); ++ ++ if (chunk_start > in->variant.file_variant.file_size) ++ n_bytes_read = 0; /* Past end of file */ ++ else ++ n_bytes_read = ++ in->variant.file_variant.file_size - ++ chunk_start; ++ ++ if (n_bytes_read > dev->data_bytes_per_chunk) ++ n_bytes_read = dev->data_bytes_per_chunk; ++ ++ n_writeback = ++ (n_bytes_read > ++ (start + n)) ? n_bytes_read : (start + n); ++ ++ if (n_writeback < 0 || ++ n_writeback > dev->data_bytes_per_chunk) ++ BUG(); ++ ++ } else { ++ n_copy = dev->data_bytes_per_chunk - start; ++ n_writeback = dev->data_bytes_per_chunk; ++ } ++ ++ if (n_copy != dev->data_bytes_per_chunk || ++ !dev->param.cache_bypass_aligned || ++ dev->param.inband_tags) { ++ /* An incomplete start or end chunk (or maybe both ++ * start and end chunk), or we're using inband tags, ++ * or we're forcing writes through the cache, ++ * so we want to use the cache buffers. ++ */ ++ if (dev->param.n_caches > 0) { ++ struct yaffs_cache *cache; ++ ++ /* If we can't find the data in the cache, then ++ * load the cache */ ++ cache = yaffs_find_chunk_cache(in, chunk); ++ ++ if (!cache && ++ yaffs_check_alloc_available(dev, 1)) { ++ cache = yaffs_grab_chunk_cache(dev); ++ cache->object = in; ++ cache->chunk_id = chunk; ++ cache->dirty = 0; ++ cache->locked = 0; ++ yaffs_rd_data_obj(in, chunk, ++ cache->data); ++ } else if (cache && ++ !cache->dirty && ++ !yaffs_check_alloc_available(dev, ++ 1)) { ++ /* Drop the cache if it was a read cache ++ * item and no space check has been made ++ * for it. ++ */ ++ cache = NULL; ++ } ++ ++ if (cache) { ++ yaffs_use_cache(dev, cache, 1); ++ cache->locked = 1; ++ ++ memcpy(&cache->data[start], buffer, ++ n_copy); ++ ++ cache->locked = 0; ++ cache->n_bytes = n_writeback; ++ ++ if (write_through) { ++ chunk_written = ++ yaffs_wr_data_obj ++ (cache->object, ++ cache->chunk_id, ++ cache->data, ++ cache->n_bytes, 1); ++ cache->dirty = 0; ++ } ++ } else { ++ chunk_written = -1; /* fail write */ ++ } ++ } else { ++ /* An incomplete start or end chunk (or maybe ++ * both start and end chunk). Read into the ++ * local buffer then copy over and write back. ++ */ ++ ++ u8 *local_buffer = yaffs_get_temp_buffer(dev); ++ ++ yaffs_rd_data_obj(in, chunk, local_buffer); ++ memcpy(&local_buffer[start], buffer, n_copy); ++ ++ chunk_written = ++ yaffs_wr_data_obj(in, chunk, ++ local_buffer, ++ n_writeback, 0); ++ ++ yaffs_release_temp_buffer(dev, local_buffer); ++ } ++ } else { ++ /* A full chunk. Write directly from the buffer. */ ++ ++ chunk_written = ++ yaffs_wr_data_obj(in, chunk, buffer, ++ dev->data_bytes_per_chunk, 0); ++ ++ /* Since we've overwritten the cached data, ++ * we better invalidate it. */ ++ yaffs_invalidate_chunk_cache(in, chunk); ++ } ++ ++ if (chunk_written >= 0) { ++ n -= n_copy; ++ offset += n_copy; ++ buffer += n_copy; ++ n_done += n_copy; ++ } ++ } ++ ++ /* Update file object */ ++ ++ if ((start_write + n_done) > in->variant.file_variant.file_size) ++ in->variant.file_variant.file_size = (start_write + n_done); ++ ++ in->dirty = 1; ++ return n_done; ++} ++ ++int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset, ++ int n_bytes, int write_through) ++{ ++ yaffs2_handle_hole(in, offset); ++ return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through); ++} ++ ++/* ---------------------- File resizing stuff ------------------ */ ++ ++static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size) ++{ ++ ++ struct yaffs_dev *dev = in->my_dev; ++ loff_t old_size = in->variant.file_variant.file_size; ++ int i; ++ int chunk_id; ++ u32 dummy; ++ int last_del; ++ int start_del; ++ ++ if (old_size > 0) ++ yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy); ++ else ++ last_del = 0; ++ ++ yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1, ++ &start_del, &dummy); ++ last_del++; ++ start_del++; ++ ++ /* Delete backwards so that we don't end up with holes if ++ * power is lost part-way through the operation. ++ */ ++ for (i = last_del; i >= start_del; i--) { ++ /* NB this could be optimised somewhat, ++ * eg. could retrieve the tags and write them without ++ * using yaffs_chunk_del ++ */ ++ ++ chunk_id = yaffs_find_del_file_chunk(in, i, NULL); ++ ++ if (chunk_id < 1) ++ continue; ++ ++ if (chunk_id < ++ (dev->internal_start_block * dev->param.chunks_per_block) || ++ chunk_id >= ++ ((dev->internal_end_block + 1) * ++ dev->param.chunks_per_block)) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "Found daft chunk_id %d for %d", ++ chunk_id, i); ++ } else { ++ in->n_data_chunks--; ++ yaffs_chunk_del(dev, chunk_id, 1, __LINE__); ++ } ++ } ++} ++ ++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size) ++{ ++ int new_full; ++ u32 new_partial; ++ struct yaffs_dev *dev = obj->my_dev; ++ ++ yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial); ++ ++ yaffs_prune_chunks(obj, new_size); ++ ++ if (new_partial != 0) { ++ int last_chunk = 1 + new_full; ++ u8 *local_buffer = yaffs_get_temp_buffer(dev); ++ ++ /* Rewrite the last chunk with its new size and zero pad */ ++ yaffs_rd_data_obj(obj, last_chunk, local_buffer); ++ memset(local_buffer + new_partial, 0, ++ dev->data_bytes_per_chunk - new_partial); ++ ++ yaffs_wr_data_obj(obj, last_chunk, local_buffer, ++ new_partial, 1); ++ ++ yaffs_release_temp_buffer(dev, local_buffer); ++ } ++ ++ obj->variant.file_variant.file_size = new_size; ++ ++ yaffs_prune_tree(dev, &obj->variant.file_variant); ++} ++ ++int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size) ++{ ++ struct yaffs_dev *dev = in->my_dev; ++ loff_t old_size = in->variant.file_variant.file_size; ++ ++ yaffs_flush_file_cache(in); ++ yaffs_invalidate_whole_cache(in); ++ ++ yaffs_check_gc(dev, 0); ++ ++ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) ++ return YAFFS_FAIL; ++ ++ if (new_size == old_size) ++ return YAFFS_OK; ++ ++ if (new_size > old_size) { ++ yaffs2_handle_hole(in, new_size); ++ in->variant.file_variant.file_size = new_size; ++ } else { ++ /* new_size < old_size */ ++ yaffs_resize_file_down(in, new_size); ++ } ++ ++ /* Write a new object header to reflect the resize. ++ * show we've shrunk the file, if need be ++ * Do this only if the file is not in the deleted directories ++ * and is not shadowed. ++ */ ++ if (in->parent && ++ !in->is_shadowed && ++ in->parent->obj_id != YAFFS_OBJECTID_UNLINKED && ++ in->parent->obj_id != YAFFS_OBJECTID_DELETED) ++ yaffs_update_oh(in, NULL, 0, 0, 0, NULL); ++ ++ return YAFFS_OK; ++} ++ ++int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync) ++{ ++ if (!in->dirty) ++ return YAFFS_OK; ++ ++ yaffs_flush_file_cache(in); ++ ++ if (data_sync) ++ return YAFFS_OK; ++ ++ if (update_time) ++ yaffs_load_current_time(in, 0, 0); ++ ++ return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ? ++ YAFFS_OK : YAFFS_FAIL; ++} ++ ++ ++/* yaffs_del_file deletes the whole file data ++ * and the inode associated with the file. ++ * It does not delete the links associated with the file. ++ */ ++static int yaffs_unlink_file_if_needed(struct yaffs_obj *in) ++{ ++ int ret_val; ++ int del_now = 0; ++ struct yaffs_dev *dev = in->my_dev; ++ ++ if (!in->my_inode) ++ del_now = 1; ++ ++ if (del_now) { ++ ret_val = ++ yaffs_change_obj_name(in, in->my_dev->del_dir, ++ _Y("deleted"), 0, 0); ++ yaffs_trace(YAFFS_TRACE_TRACING, ++ "yaffs: immediate deletion of file %d", ++ in->obj_id); ++ in->deleted = 1; ++ in->my_dev->n_deleted_files++; ++ if (dev->param.disable_soft_del || dev->param.is_yaffs2) ++ yaffs_resize_file(in, 0); ++ yaffs_soft_del_file(in); ++ } else { ++ ret_val = ++ yaffs_change_obj_name(in, in->my_dev->unlinked_dir, ++ _Y("unlinked"), 0, 0); ++ } ++ return ret_val; ++} ++ ++static int yaffs_del_file(struct yaffs_obj *in) ++{ ++ int ret_val = YAFFS_OK; ++ int deleted; /* Need to cache value on stack if in is freed */ ++ struct yaffs_dev *dev = in->my_dev; ++ ++ if (dev->param.disable_soft_del || dev->param.is_yaffs2) ++ yaffs_resize_file(in, 0); ++ ++ if (in->n_data_chunks > 0) { ++ /* Use soft deletion if there is data in the file. ++ * That won't be the case if it has been resized to zero. ++ */ ++ if (!in->unlinked) ++ ret_val = yaffs_unlink_file_if_needed(in); ++ ++ deleted = in->deleted; ++ ++ if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) { ++ in->deleted = 1; ++ deleted = 1; ++ in->my_dev->n_deleted_files++; ++ yaffs_soft_del_file(in); ++ } ++ return deleted ? YAFFS_OK : YAFFS_FAIL; ++ } else { ++ /* The file has no data chunks so we toss it immediately */ ++ yaffs_free_tnode(in->my_dev, in->variant.file_variant.top); ++ in->variant.file_variant.top = NULL; ++ yaffs_generic_obj_del(in); ++ ++ return YAFFS_OK; ++ } ++} ++ ++int yaffs_is_non_empty_dir(struct yaffs_obj *obj) ++{ ++ return (obj && ++ obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) && ++ !(list_empty(&obj->variant.dir_variant.children)); ++} ++ ++static int yaffs_del_dir(struct yaffs_obj *obj) ++{ ++ /* First check that the directory is empty. */ ++ if (yaffs_is_non_empty_dir(obj)) ++ return YAFFS_FAIL; ++ ++ return yaffs_generic_obj_del(obj); ++} ++ ++static int yaffs_del_symlink(struct yaffs_obj *in) ++{ ++ kfree(in->variant.symlink_variant.alias); ++ in->variant.symlink_variant.alias = NULL; ++ ++ return yaffs_generic_obj_del(in); ++} ++ ++static int yaffs_del_link(struct yaffs_obj *in) ++{ ++ /* remove this hardlink from the list associated with the equivalent ++ * object ++ */ ++ list_del_init(&in->hard_links); ++ return yaffs_generic_obj_del(in); ++} ++ ++int yaffs_del_obj(struct yaffs_obj *obj) ++{ ++ int ret_val = -1; ++ ++ switch (obj->variant_type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ ret_val = yaffs_del_file(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ if (!list_empty(&obj->variant.dir_variant.dirty)) { ++ yaffs_trace(YAFFS_TRACE_BACKGROUND, ++ "Remove object %d from dirty directories", ++ obj->obj_id); ++ list_del_init(&obj->variant.dir_variant.dirty); ++ } ++ return yaffs_del_dir(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ ret_val = yaffs_del_symlink(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ ret_val = yaffs_del_link(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ ret_val = yaffs_generic_obj_del(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ ret_val = 0; ++ break; /* should not happen. */ ++ } ++ return ret_val; ++} ++ ++ ++static void yaffs_empty_dir_to_dir(struct yaffs_obj *from_dir, ++ struct yaffs_obj *to_dir) ++{ ++ struct yaffs_obj *obj; ++ struct list_head *lh; ++ struct list_head *n; ++ ++ list_for_each_safe(lh, n, &from_dir->variant.dir_variant.children) { ++ obj = list_entry(lh, struct yaffs_obj, siblings); ++ yaffs_add_obj_to_dir(to_dir, obj); ++ } ++} ++ ++struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj, ++ enum yaffs_obj_type type) ++{ ++ /* Tear down the old variant */ ++ switch (obj->variant_type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ /* Nuke file data */ ++ yaffs_resize_file(obj, 0); ++ yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top); ++ obj->variant.file_variant.top = NULL; ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ /* Put the children in lost and found. */ ++ yaffs_empty_dir_to_dir(obj, obj->my_dev->lost_n_found); ++ if (!list_empty(&obj->variant.dir_variant.dirty)) ++ list_del_init(&obj->variant.dir_variant.dirty); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ /* Nuke symplink data */ ++ kfree(obj->variant.symlink_variant.alias); ++ obj->variant.symlink_variant.alias = NULL; ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ list_del_init(&obj->hard_links); ++ break; ++ default: ++ break; ++ } ++ ++ memset(&obj->variant, 0, sizeof(obj->variant)); ++ ++ /*Set up new variant if the memset is not enough. */ ++ switch (type) { ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ INIT_LIST_HEAD(&obj->variant.dir_variant.children); ++ INIT_LIST_HEAD(&obj->variant.dir_variant.dirty); ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ default: ++ break; ++ } ++ ++ obj->variant_type = type; ++ ++ return obj; ++ ++} ++ ++static int yaffs_unlink_worker(struct yaffs_obj *obj) ++{ ++ int del_now = 0; ++ ++ if (!obj) ++ return YAFFS_FAIL; ++ ++ if (!obj->my_inode) ++ del_now = 1; ++ ++ yaffs_update_parent(obj->parent); ++ ++ if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { ++ return yaffs_del_link(obj); ++ } else if (!list_empty(&obj->hard_links)) { ++ /* Curve ball: We're unlinking an object that has a hardlink. ++ * ++ * This problem arises because we are not strictly following ++ * The Linux link/inode model. ++ * ++ * We can't really delete the object. ++ * Instead, we do the following: ++ * - Select a hardlink. ++ * - Unhook it from the hard links ++ * - Move it from its parent directory so that the rename works. ++ * - Rename the object to the hardlink's name. ++ * - Delete the hardlink ++ */ ++ ++ struct yaffs_obj *hl; ++ struct yaffs_obj *parent; ++ int ret_val; ++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ hl = list_entry(obj->hard_links.next, struct yaffs_obj, ++ hard_links); ++ ++ yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1); ++ parent = hl->parent; ++ ++ list_del_init(&hl->hard_links); ++ ++ yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl); ++ ++ ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0); ++ ++ if (ret_val == YAFFS_OK) ++ ret_val = yaffs_generic_obj_del(hl); ++ ++ return ret_val; ++ ++ } else if (del_now) { ++ switch (obj->variant_type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ return yaffs_del_file(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ list_del_init(&obj->variant.dir_variant.dirty); ++ return yaffs_del_dir(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ return yaffs_del_symlink(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ return yaffs_generic_obj_del(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ default: ++ return YAFFS_FAIL; ++ } ++ } else if (yaffs_is_non_empty_dir(obj)) { ++ return YAFFS_FAIL; ++ } else { ++ return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir, ++ _Y("unlinked"), 0, 0); ++ } ++} ++ ++static int yaffs_unlink_obj(struct yaffs_obj *obj) ++{ ++ if (obj && obj->unlink_allowed) ++ return yaffs_unlink_worker(obj); ++ ++ return YAFFS_FAIL; ++} ++ ++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name) ++{ ++ struct yaffs_obj *obj; ++ ++ obj = yaffs_find_by_name(dir, name); ++ return yaffs_unlink_obj(obj); ++} ++ ++/* Note: ++ * If old_name is NULL then we take old_dir as the object to be renamed. ++ */ ++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name, ++ struct yaffs_obj *new_dir, const YCHAR *new_name) ++{ ++ struct yaffs_obj *obj = NULL; ++ struct yaffs_obj *existing_target = NULL; ++ int force = 0; ++ int result; ++ struct yaffs_dev *dev; ++ ++ if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ BUG(); ++ return YAFFS_FAIL; ++ } ++ if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ BUG(); ++ return YAFFS_FAIL; ++ } ++ ++ dev = old_dir->my_dev; ++ ++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE ++ /* Special case for case insemsitive systems. ++ * While look-up is case insensitive, the name isn't. ++ * Therefore we might want to change x.txt to X.txt ++ */ ++ if (old_dir == new_dir && ++ old_name && new_name && ++ strcmp(old_name, new_name) == 0) ++ force = 1; ++#endif ++ ++ if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) > ++ YAFFS_MAX_NAME_LENGTH) ++ /* ENAMETOOLONG */ ++ return YAFFS_FAIL; ++ ++ if (old_name) ++ obj = yaffs_find_by_name(old_dir, old_name); ++ else{ ++ obj = old_dir; ++ old_dir = obj->parent; ++ } ++ ++ if (obj && obj->rename_allowed) { ++ /* Now handle an existing target, if there is one */ ++ existing_target = yaffs_find_by_name(new_dir, new_name); ++ if (yaffs_is_non_empty_dir(existing_target)) { ++ return YAFFS_FAIL; /* ENOTEMPTY */ ++ } else if (existing_target && existing_target != obj) { ++ /* Nuke the target first, using shadowing, ++ * but only if it isn't the same object. ++ * ++ * Note we must disable gc here otherwise it can mess ++ * up the shadowing. ++ * ++ */ ++ dev->gc_disable = 1; ++ yaffs_change_obj_name(obj, new_dir, new_name, force, ++ existing_target->obj_id); ++ existing_target->is_shadowed = 1; ++ yaffs_unlink_obj(existing_target); ++ dev->gc_disable = 0; ++ } ++ ++ result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0); ++ ++ yaffs_update_parent(old_dir); ++ if (new_dir != old_dir) ++ yaffs_update_parent(new_dir); ++ ++ return result; ++ } ++ return YAFFS_FAIL; ++} ++ ++/*----------------------- Initialisation Scanning ---------------------- */ ++ ++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id, ++ int backward_scanning) ++{ ++ struct yaffs_obj *obj; ++ ++ if (backward_scanning) { ++ /* Handle YAFFS2 case (backward scanning) ++ * If the shadowed object exists then ignore. ++ */ ++ obj = yaffs_find_by_number(dev, obj_id); ++ if (obj) ++ return; ++ } ++ ++ /* Let's create it (if it does not exist) assuming it is a file so that ++ * it can do shrinking etc. ++ * We put it in unlinked dir to be cleaned up after the scanning ++ */ ++ obj = ++ yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE); ++ if (!obj) ++ return; ++ obj->is_shadowed = 1; ++ yaffs_add_obj_to_dir(dev->unlinked_dir, obj); ++ obj->variant.file_variant.shrink_size = 0; ++ obj->valid = 1; /* So that we don't read any other info. */ ++} ++ ++void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list) ++{ ++ struct list_head *lh; ++ struct list_head *save; ++ struct yaffs_obj *hl; ++ struct yaffs_obj *in; ++ ++ list_for_each_safe(lh, save, hard_list) { ++ hl = list_entry(lh, struct yaffs_obj, hard_links); ++ in = yaffs_find_by_number(dev, ++ hl->variant.hardlink_variant.equiv_id); ++ ++ if (in) { ++ /* Add the hardlink pointers */ ++ hl->variant.hardlink_variant.equiv_obj = in; ++ list_add(&hl->hard_links, &in->hard_links); ++ } else { ++ /* Todo Need to report/handle this better. ++ * Got a problem... hardlink to a non-existant object ++ */ ++ hl->variant.hardlink_variant.equiv_obj = NULL; ++ INIT_LIST_HEAD(&hl->hard_links); ++ } ++ } ++} ++ ++static void yaffs_strip_deleted_objs(struct yaffs_dev *dev) ++{ ++ /* ++ * Sort out state of unlinked and deleted objects after scanning. ++ */ ++ struct list_head *i; ++ struct list_head *n; ++ struct yaffs_obj *l; ++ ++ if (dev->read_only) ++ return; ++ ++ /* Soft delete all the unlinked files */ ++ list_for_each_safe(i, n, ++ &dev->unlinked_dir->variant.dir_variant.children) { ++ l = list_entry(i, struct yaffs_obj, siblings); ++ yaffs_del_obj(l); ++ } ++ ++ list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) { ++ l = list_entry(i, struct yaffs_obj, siblings); ++ yaffs_del_obj(l); ++ } ++} ++ ++/* ++ * This code iterates through all the objects making sure that they are rooted. ++ * Any unrooted objects are re-rooted in lost+found. ++ * An object needs to be in one of: ++ * - Directly under deleted, unlinked ++ * - Directly or indirectly under root. ++ * ++ * Note: ++ * This code assumes that we don't ever change the current relationships ++ * between directories: ++ * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL ++ * lost-n-found->parent == root_dir ++ * ++ * This fixes the problem where directories might have inadvertently been ++ * deleted leaving the object "hanging" without being rooted in the ++ * directory tree. ++ */ ++ ++static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj) ++{ ++ return (obj == dev->del_dir || ++ obj == dev->unlinked_dir || obj == dev->root_dir); ++} ++ ++static void yaffs_fix_hanging_objs(struct yaffs_dev *dev) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_obj *parent; ++ int i; ++ struct list_head *lh; ++ struct list_head *n; ++ int depth_limit; ++ int hanging; ++ ++ if (dev->read_only) ++ return; ++ ++ /* Iterate through the objects in each hash entry, ++ * looking at each object. ++ * Make sure it is rooted. ++ */ ++ ++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { ++ list_for_each_safe(lh, n, &dev->obj_bucket[i].list) { ++ obj = list_entry(lh, struct yaffs_obj, hash_link); ++ parent = obj->parent; ++ ++ if (yaffs_has_null_parent(dev, obj)) { ++ /* These directories are not hanging */ ++ hanging = 0; ++ } else if (!parent || ++ parent->variant_type != ++ YAFFS_OBJECT_TYPE_DIRECTORY) { ++ hanging = 1; ++ } else if (yaffs_has_null_parent(dev, parent)) { ++ hanging = 0; ++ } else { ++ /* ++ * Need to follow the parent chain to ++ * see if it is hanging. ++ */ ++ hanging = 0; ++ depth_limit = 100; ++ ++ while (parent != dev->root_dir && ++ parent->parent && ++ parent->parent->variant_type == ++ YAFFS_OBJECT_TYPE_DIRECTORY && ++ depth_limit > 0) { ++ parent = parent->parent; ++ depth_limit--; ++ } ++ if (parent != dev->root_dir) ++ hanging = 1; ++ } ++ if (hanging) { ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "Hanging object %d moved to lost and found", ++ obj->obj_id); ++ yaffs_add_obj_to_dir(dev->lost_n_found, obj); ++ } ++ } ++ } ++} ++ ++/* ++ * Delete directory contents for cleaning up lost and found. ++ */ ++static void yaffs_del_dir_contents(struct yaffs_obj *dir) ++{ ++ struct yaffs_obj *obj; ++ struct list_head *lh; ++ struct list_head *n; ++ ++ if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) ++ BUG(); ++ ++ list_for_each_safe(lh, n, &dir->variant.dir_variant.children) { ++ obj = list_entry(lh, struct yaffs_obj, siblings); ++ if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) ++ yaffs_del_dir_contents(obj); ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "Deleting lost_found object %d", ++ obj->obj_id); ++ yaffs_unlink_obj(obj); ++ } ++} ++ ++static void yaffs_empty_l_n_f(struct yaffs_dev *dev) ++{ ++ yaffs_del_dir_contents(dev->lost_n_found); ++} ++ ++ ++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory, ++ const YCHAR *name) ++{ ++ int sum; ++ struct list_head *i; ++ YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1]; ++ struct yaffs_obj *l; ++ ++ if (!name) ++ return NULL; ++ ++ if (!directory) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "tragedy: yaffs_find_by_name: null pointer directory" ++ ); ++ BUG(); ++ return NULL; ++ } ++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "tragedy: yaffs_find_by_name: non-directory" ++ ); ++ BUG(); ++ } ++ ++ sum = yaffs_calc_name_sum(name); ++ ++ list_for_each(i, &directory->variant.dir_variant.children) { ++ l = list_entry(i, struct yaffs_obj, siblings); ++ ++ if (l->parent != directory) ++ BUG(); ++ ++ yaffs_check_obj_details_loaded(l); ++ ++ /* Special case for lost-n-found */ ++ if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) { ++ if (!strcmp(name, YAFFS_LOSTNFOUND_NAME)) ++ return l; ++ } else if (l->sum == sum || l->hdr_chunk <= 0) { ++ /* LostnFound chunk called Objxxx ++ * Do a real check ++ */ ++ yaffs_get_obj_name(l, buffer, ++ YAFFS_MAX_NAME_LENGTH + 1); ++ if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH)) ++ return l; ++ } ++ } ++ return NULL; ++} ++ ++/* GetEquivalentObject dereferences any hard links to get to the ++ * actual object. ++ */ ++ ++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj) ++{ ++ if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { ++ obj = obj->variant.hardlink_variant.equiv_obj; ++ yaffs_check_obj_details_loaded(obj); ++ } ++ return obj; ++} ++ ++/* ++ * A note or two on object names. ++ * * If the object name is missing, we then make one up in the form objnnn ++ * ++ * * ASCII names are stored in the object header's name field from byte zero ++ * * Unicode names are historically stored starting from byte zero. ++ * ++ * Then there are automatic Unicode names... ++ * The purpose of these is to save names in a way that can be read as ++ * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII ++ * system to share files. ++ * ++ * These automatic unicode are stored slightly differently... ++ * - If the name can fit in the ASCII character space then they are saved as ++ * ascii names as per above. ++ * - If the name needs Unicode then the name is saved in Unicode ++ * starting at oh->name[1]. ++ ++ */ ++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name, ++ int buffer_size) ++{ ++ /* Create an object name if we could not find one. */ ++ if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) { ++ YCHAR local_name[20]; ++ YCHAR num_string[20]; ++ YCHAR *x = &num_string[19]; ++ unsigned v = obj->obj_id; ++ num_string[19] = 0; ++ while (v > 0) { ++ x--; ++ *x = '0' + (v % 10); ++ v /= 10; ++ } ++ /* make up a name */ ++ strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX); ++ strcat(local_name, x); ++ strncpy(name, local_name, buffer_size - 1); ++ } ++} ++ ++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR *name, int buffer_size) ++{ ++ memset(name, 0, buffer_size * sizeof(YCHAR)); ++ yaffs_check_obj_details_loaded(obj); ++ if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) { ++ strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1); ++ } else if (obj->short_name[0]) { ++ strcpy(name, obj->short_name); ++ } else if (obj->hdr_chunk > 0) { ++ int result; ++ u8 *buffer = yaffs_get_temp_buffer(obj->my_dev); ++ ++ struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer; ++ ++ memset(buffer, 0, obj->my_dev->data_bytes_per_chunk); ++ ++ if (obj->hdr_chunk > 0) { ++ result = yaffs_rd_chunk_tags_nand(obj->my_dev, ++ obj->hdr_chunk, ++ buffer, NULL); ++ } ++ yaffs_load_name_from_oh(obj->my_dev, name, oh->name, ++ buffer_size); ++ ++ yaffs_release_temp_buffer(obj->my_dev, buffer); ++ } ++ ++ yaffs_fix_null_name(obj, name, buffer_size); ++ ++ return strnlen(name, YAFFS_MAX_NAME_LENGTH); ++} ++ ++loff_t yaffs_get_obj_length(struct yaffs_obj *obj) ++{ ++ /* Dereference any hard linking */ ++ obj = yaffs_get_equivalent_obj(obj); ++ ++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) ++ return obj->variant.file_variant.file_size; ++ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) { ++ if (!obj->variant.symlink_variant.alias) ++ return 0; ++ return strnlen(obj->variant.symlink_variant.alias, ++ YAFFS_MAX_ALIAS_LENGTH); ++ } else { ++ /* Only a directory should drop through to here */ ++ return obj->my_dev->data_bytes_per_chunk; ++ } ++} ++ ++int yaffs_get_obj_link_count(struct yaffs_obj *obj) ++{ ++ int count = 0; ++ struct list_head *i; ++ ++ if (!obj->unlinked) ++ count++; /* the object itself */ ++ ++ list_for_each(i, &obj->hard_links) ++ count++; /* add the hard links; */ ++ ++ return count; ++} ++ ++int yaffs_get_obj_inode(struct yaffs_obj *obj) ++{ ++ obj = yaffs_get_equivalent_obj(obj); ++ ++ return obj->obj_id; ++} ++ ++unsigned yaffs_get_obj_type(struct yaffs_obj *obj) ++{ ++ obj = yaffs_get_equivalent_obj(obj); ++ ++ switch (obj->variant_type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ return DT_REG; ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ return DT_DIR; ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ return DT_LNK; ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ return DT_REG; ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ if (S_ISFIFO(obj->yst_mode)) ++ return DT_FIFO; ++ if (S_ISCHR(obj->yst_mode)) ++ return DT_CHR; ++ if (S_ISBLK(obj->yst_mode)) ++ return DT_BLK; ++ if (S_ISSOCK(obj->yst_mode)) ++ return DT_SOCK; ++ return DT_REG; ++ break; ++ default: ++ return DT_REG; ++ break; ++ } ++} ++ ++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj) ++{ ++ obj = yaffs_get_equivalent_obj(obj); ++ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) ++ return yaffs_clone_str(obj->variant.symlink_variant.alias); ++ else ++ return yaffs_clone_str(_Y("")); ++} ++ ++/*--------------------------- Initialisation code -------------------------- */ ++ ++static int yaffs_check_dev_fns(struct yaffs_dev *dev) ++{ ++ struct yaffs_driver *drv = &dev->drv; ++ struct yaffs_tags_handler *tagger = &dev->tagger; ++ ++ /* Common functions, gotta have */ ++ if (!drv->drv_read_chunk_fn || ++ !drv->drv_write_chunk_fn || ++ !drv->drv_erase_fn) ++ return 0; ++ ++ if (dev->param.is_yaffs2 && ++ (!drv->drv_mark_bad_fn || !drv->drv_check_bad_fn)) ++ return 0; ++ ++ /* Install the default tags marshalling functions if needed. */ ++ yaffs_tags_compat_install(dev); ++ yaffs_tags_marshall_install(dev); ++ ++ /* Check we now have the marshalling functions required. */ ++ if (!tagger->write_chunk_tags_fn || ++ !tagger->read_chunk_tags_fn || ++ !tagger->query_block_fn || ++ !tagger->mark_bad_fn) ++ return 0; ++ ++ return 1; ++} ++ ++static int yaffs_create_initial_dir(struct yaffs_dev *dev) ++{ ++ /* Initialise the unlinked, deleted, root and lost+found directories */ ++ dev->lost_n_found = dev->root_dir = NULL; ++ dev->unlinked_dir = dev->del_dir = NULL; ++ dev->unlinked_dir = ++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR); ++ dev->del_dir = ++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR); ++ dev->root_dir = ++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT, ++ YAFFS_ROOT_MODE | S_IFDIR); ++ dev->lost_n_found = ++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND, ++ YAFFS_LOSTNFOUND_MODE | S_IFDIR); ++ ++ if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir ++ && dev->del_dir) { ++ yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found); ++ return YAFFS_OK; ++ } ++ return YAFFS_FAIL; ++} ++ ++/* Low level init. ++ * Typically only used by yaffs_guts_initialise, but also used by the ++ * Low level yaffs driver tests. ++ */ ++ ++int yaffs_guts_ll_init(struct yaffs_dev *dev) ++{ ++ ++ ++ yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_ll_init()"); ++ ++ if (!dev) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs: Need a device" ++ ); ++ return YAFFS_FAIL; ++ } ++ ++ if (dev->ll_init) ++ return YAFFS_OK; ++ ++ dev->internal_start_block = dev->param.start_block; ++ dev->internal_end_block = dev->param.end_block; ++ dev->block_offset = 0; ++ dev->chunk_offset = 0; ++ dev->n_free_chunks = 0; ++ ++ dev->gc_block = 0; ++ ++ if (dev->param.start_block == 0) { ++ dev->internal_start_block = dev->param.start_block + 1; ++ dev->internal_end_block = dev->param.end_block + 1; ++ dev->block_offset = 1; ++ dev->chunk_offset = dev->param.chunks_per_block; ++ } ++ ++ /* Check geometry parameters. */ ++ ++ if ((!dev->param.inband_tags && dev->param.is_yaffs2 && ++ dev->param.total_bytes_per_chunk < 1024) || ++ (!dev->param.is_yaffs2 && ++ dev->param.total_bytes_per_chunk < 512) || ++ (dev->param.inband_tags && !dev->param.is_yaffs2) || ++ dev->param.chunks_per_block < 2 || ++ dev->param.n_reserved_blocks < 2 || ++ dev->internal_start_block <= 0 || ++ dev->internal_end_block <= 0 || ++ dev->internal_end_block <= ++ (dev->internal_start_block + dev->param.n_reserved_blocks + 2) ++ ) { ++ /* otherwise it is too small */ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ", ++ dev->param.total_bytes_per_chunk, ++ dev->param.is_yaffs2 ? "2" : "", ++ dev->param.inband_tags); ++ return YAFFS_FAIL; ++ } ++ ++ /* Sort out space for inband tags, if required */ ++ if (dev->param.inband_tags) ++ dev->data_bytes_per_chunk = ++ dev->param.total_bytes_per_chunk - ++ sizeof(struct yaffs_packed_tags2_tags_only); ++ else ++ dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk; ++ ++ /* Got the right mix of functions? */ ++ if (!yaffs_check_dev_fns(dev)) { ++ /* Function missing */ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "device function(s) missing or wrong"); ++ ++ return YAFFS_FAIL; ++ } ++ ++ if (yaffs_init_nand(dev) != YAFFS_OK) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed"); ++ return YAFFS_FAIL; ++ } ++ ++ return YAFFS_OK; ++} ++ ++ ++int yaffs_guts_format_dev(struct yaffs_dev *dev) ++{ ++ int i; ++ enum yaffs_block_state state; ++ u32 dummy; ++ ++ if(yaffs_guts_ll_init(dev) != YAFFS_OK) ++ return YAFFS_FAIL; ++ ++ if(dev->is_mounted) ++ return YAFFS_FAIL; ++ ++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { ++ yaffs_query_init_block_state(dev, i, &state, &dummy); ++ if (state != YAFFS_BLOCK_STATE_DEAD) ++ yaffs_erase_block(dev, i); ++ } ++ ++ return YAFFS_OK; ++} ++ ++ ++int yaffs_guts_initialise(struct yaffs_dev *dev) ++{ ++ int init_failed = 0; ++ unsigned x; ++ int bits; ++ ++ if(yaffs_guts_ll_init(dev) != YAFFS_OK) ++ return YAFFS_FAIL; ++ ++ if (dev->is_mounted) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted"); ++ return YAFFS_FAIL; ++ } ++ ++ dev->is_mounted = 1; ++ ++ /* OK now calculate a few things for the device */ ++ ++ /* ++ * Calculate all the chunk size manipulation numbers: ++ */ ++ x = dev->data_bytes_per_chunk; ++ /* We always use dev->chunk_shift and dev->chunk_div */ ++ dev->chunk_shift = calc_shifts(x); ++ x >>= dev->chunk_shift; ++ dev->chunk_div = x; ++ /* We only use chunk mask if chunk_div is 1 */ ++ dev->chunk_mask = (1 << dev->chunk_shift) - 1; ++ ++ /* ++ * Calculate chunk_grp_bits. ++ * We need to find the next power of 2 > than internal_end_block ++ */ ++ ++ x = dev->param.chunks_per_block * (dev->internal_end_block + 1); ++ ++ bits = calc_shifts_ceiling(x); ++ ++ /* Set up tnode width if wide tnodes are enabled. */ ++ if (!dev->param.wide_tnodes_disabled) { ++ /* bits must be even so that we end up with 32-bit words */ ++ if (bits & 1) ++ bits++; ++ if (bits < 16) ++ dev->tnode_width = 16; ++ else ++ dev->tnode_width = bits; ++ } else { ++ dev->tnode_width = 16; ++ } ++ ++ dev->tnode_mask = (1 << dev->tnode_width) - 1; ++ ++ /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled), ++ * so if the bitwidth of the ++ * chunk range we're using is greater than 16 we need ++ * to figure out chunk shift and chunk_grp_size ++ */ ++ ++ if (bits <= dev->tnode_width) ++ dev->chunk_grp_bits = 0; ++ else ++ dev->chunk_grp_bits = bits - dev->tnode_width; ++ ++ dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8; ++ if (dev->tnode_size < sizeof(struct yaffs_tnode)) ++ dev->tnode_size = sizeof(struct yaffs_tnode); ++ ++ dev->chunk_grp_size = 1 << dev->chunk_grp_bits; ++ ++ if (dev->param.chunks_per_block < dev->chunk_grp_size) { ++ /* We have a problem because the soft delete won't work if ++ * the chunk group size > chunks per block. ++ * This can be remedied by using larger "virtual blocks". ++ */ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large"); ++ ++ return YAFFS_FAIL; ++ } ++ ++ /* Finished verifying the device, continue with initialisation */ ++ ++ /* More device initialisation */ ++ dev->all_gcs = 0; ++ dev->passive_gc_count = 0; ++ dev->oldest_dirty_gc_count = 0; ++ dev->bg_gcs = 0; ++ dev->gc_block_finder = 0; ++ dev->buffered_block = -1; ++ dev->doing_buffered_block_rewrite = 0; ++ dev->n_deleted_files = 0; ++ dev->n_bg_deletions = 0; ++ dev->n_unlinked_files = 0; ++ dev->n_ecc_fixed = 0; ++ dev->n_ecc_unfixed = 0; ++ dev->n_tags_ecc_fixed = 0; ++ dev->n_tags_ecc_unfixed = 0; ++ dev->n_erase_failures = 0; ++ dev->n_erased_blocks = 0; ++ dev->gc_disable = 0; ++ dev->has_pending_prioritised_gc = 1; ++ /* Assume the worst for now, will get fixed on first GC */ ++ INIT_LIST_HEAD(&dev->dirty_dirs); ++ dev->oldest_dirty_seq = 0; ++ dev->oldest_dirty_block = 0; ++ ++ /* Initialise temporary buffers and caches. */ ++ if (!yaffs_init_tmp_buffers(dev)) ++ init_failed = 1; ++ ++ dev->cache = NULL; ++ dev->gc_cleanup_list = NULL; ++ ++ if (!init_failed && dev->param.n_caches > 0) { ++ int i; ++ void *buf; ++ int cache_bytes = ++ dev->param.n_caches * sizeof(struct yaffs_cache); ++ ++ if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES) ++ dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES; ++ ++ dev->cache = kmalloc(cache_bytes, GFP_NOFS); ++ ++ buf = (u8 *) dev->cache; ++ ++ if (dev->cache) ++ memset(dev->cache, 0, cache_bytes); ++ ++ for (i = 0; i < dev->param.n_caches && buf; i++) { ++ dev->cache[i].object = NULL; ++ dev->cache[i].last_use = 0; ++ dev->cache[i].dirty = 0; ++ dev->cache[i].data = buf = ++ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); ++ } ++ if (!buf) ++ init_failed = 1; ++ ++ dev->cache_last_use = 0; ++ } ++ ++ dev->cache_hits = 0; ++ ++ if (!init_failed) { ++ dev->gc_cleanup_list = ++ kmalloc(dev->param.chunks_per_block * sizeof(u32), ++ GFP_NOFS); ++ if (!dev->gc_cleanup_list) ++ init_failed = 1; ++ } ++ ++ if (dev->param.is_yaffs2) ++ dev->param.use_header_file_size = 1; ++ ++ if (!init_failed && !yaffs_init_blocks(dev)) ++ init_failed = 1; ++ ++ yaffs_init_tnodes_and_objs(dev); ++ ++ if (!init_failed && !yaffs_create_initial_dir(dev)) ++ init_failed = 1; ++ ++ if (!init_failed && dev->param.is_yaffs2 && ++ !dev->param.disable_summary && ++ !yaffs_summary_init(dev)) ++ init_failed = 1; ++ ++ if (!init_failed) { ++ /* Now scan the flash. */ ++ if (dev->param.is_yaffs2) { ++ if (yaffs2_checkpt_restore(dev)) { ++ yaffs_check_obj_details_loaded(dev->root_dir); ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT | ++ YAFFS_TRACE_MOUNT, ++ "yaffs: restored from checkpoint" ++ ); ++ } else { ++ ++ /* Clean up the mess caused by an aborted ++ * checkpoint load then scan backwards. ++ */ ++ yaffs_deinit_blocks(dev); ++ ++ yaffs_deinit_tnodes_and_objs(dev); ++ ++ dev->n_erased_blocks = 0; ++ dev->n_free_chunks = 0; ++ dev->alloc_block = -1; ++ dev->alloc_page = -1; ++ dev->n_deleted_files = 0; ++ dev->n_unlinked_files = 0; ++ dev->n_bg_deletions = 0; ++ ++ if (!init_failed && !yaffs_init_blocks(dev)) ++ init_failed = 1; ++ ++ yaffs_init_tnodes_and_objs(dev); ++ ++ if (!init_failed ++ && !yaffs_create_initial_dir(dev)) ++ init_failed = 1; ++ ++ if (!init_failed && !yaffs2_scan_backwards(dev)) ++ init_failed = 1; ++ } ++ } else if (!yaffs1_scan(dev)) { ++ init_failed = 1; ++ } ++ ++ yaffs_strip_deleted_objs(dev); ++ yaffs_fix_hanging_objs(dev); ++ if (dev->param.empty_lost_n_found) ++ yaffs_empty_l_n_f(dev); ++ } ++ ++ if (init_failed) { ++ /* Clean up the mess */ ++ yaffs_trace(YAFFS_TRACE_TRACING, ++ "yaffs: yaffs_guts_initialise() aborted."); ++ ++ yaffs_deinitialise(dev); ++ return YAFFS_FAIL; ++ } ++ ++ /* Zero out stats */ ++ dev->n_page_reads = 0; ++ dev->n_page_writes = 0; ++ dev->n_erasures = 0; ++ dev->n_gc_copies = 0; ++ dev->n_retried_writes = 0; ++ ++ dev->n_retired_blocks = 0; ++ ++ yaffs_verify_free_chunks(dev); ++ yaffs_verify_blocks(dev); ++ ++ /* Clean up any aborted checkpoint data */ ++ if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0) ++ yaffs2_checkpt_invalidate(dev); ++ ++ yaffs_trace(YAFFS_TRACE_TRACING, ++ "yaffs: yaffs_guts_initialise() done."); ++ return YAFFS_OK; ++} ++ ++void yaffs_deinitialise(struct yaffs_dev *dev) ++{ ++ if (dev->is_mounted) { ++ int i; ++ ++ yaffs_deinit_blocks(dev); ++ yaffs_deinit_tnodes_and_objs(dev); ++ yaffs_summary_deinit(dev); ++ ++ if (dev->param.n_caches > 0 && dev->cache) { ++ ++ for (i = 0; i < dev->param.n_caches; i++) { ++ kfree(dev->cache[i].data); ++ dev->cache[i].data = NULL; ++ } ++ ++ kfree(dev->cache); ++ dev->cache = NULL; ++ } ++ ++ kfree(dev->gc_cleanup_list); ++ ++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) ++ kfree(dev->temp_buffer[i].buffer); ++ ++ dev->is_mounted = 0; ++ ++ yaffs_deinit_nand(dev); ++ } ++} ++ ++int yaffs_count_free_chunks(struct yaffs_dev *dev) ++{ ++ int n_free = 0; ++ int b; ++ struct yaffs_block_info *blk; ++ ++ blk = dev->block_info; ++ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) { ++ switch (blk->block_state) { ++ case YAFFS_BLOCK_STATE_EMPTY: ++ case YAFFS_BLOCK_STATE_ALLOCATING: ++ case YAFFS_BLOCK_STATE_COLLECTING: ++ case YAFFS_BLOCK_STATE_FULL: ++ n_free += ++ (dev->param.chunks_per_block - blk->pages_in_use + ++ blk->soft_del_pages); ++ break; ++ default: ++ break; ++ } ++ blk++; ++ } ++ return n_free; ++} ++ ++int yaffs_get_n_free_chunks(struct yaffs_dev *dev) ++{ ++ /* This is what we report to the outside world */ ++ int n_free; ++ int n_dirty_caches; ++ int blocks_for_checkpt; ++ int i; ++ ++ n_free = dev->n_free_chunks; ++ n_free += dev->n_deleted_files; ++ ++ /* Now count and subtract the number of dirty chunks in the cache. */ ++ ++ for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) { ++ if (dev->cache[i].dirty) ++ n_dirty_caches++; ++ } ++ ++ n_free -= n_dirty_caches; ++ ++ n_free -= ++ ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block); ++ ++ /* Now figure checkpoint space and report that... */ ++ blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev); ++ ++ n_free -= (blocks_for_checkpt * dev->param.chunks_per_block); ++ ++ if (n_free < 0) ++ n_free = 0; ++ ++ return n_free; ++} ++ ++ ++ ++/* ++ * Marshalling functions to get loff_t file sizes into and out of ++ * object headers. ++ */ ++void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize) ++{ ++ oh->file_size_low = (fsize & 0xFFFFFFFF); ++ oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF); ++} ++ ++loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh) ++{ ++ loff_t retval; ++ ++ if (sizeof(loff_t) >= 8 && ~(oh->file_size_high)) ++ retval = (((loff_t) oh->file_size_high) << 32) | ++ (((loff_t) oh->file_size_low) & 0xFFFFFFFF); ++ else ++ retval = (loff_t) oh->file_size_low; ++ ++ return retval; ++} ++ ++ ++void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]) ++{ ++ int i; ++ struct yaffs_block_info *bi; ++ int s; ++ ++ for(i = 0; i < 10; i++) ++ bs[i] = 0; ++ ++ for(i = dev->internal_start_block; i <= dev->internal_end_block; i++) { ++ bi = yaffs_get_block_info(dev, i); ++ s = bi->block_state; ++ if(s > YAFFS_BLOCK_STATE_DEAD || s < YAFFS_BLOCK_STATE_UNKNOWN) ++ bs[0]++; ++ else ++ bs[s]++; ++ } ++} +diff --git a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h +new file mode 100644 +index 00000000..77bc7e99 +--- /dev/null ++++ b/fs/yaffs2/yaffs_guts.h +@@ -0,0 +1,1007 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_GUTS_H__ ++#define __YAFFS_GUTS_H__ ++ ++#include "yportenv.h" ++ ++#define YAFFS_OK 1 ++#define YAFFS_FAIL 0 ++ ++/* Give us a Y=0x59, ++ * Give us an A=0x41, ++ * Give us an FF=0xff ++ * Give us an S=0x53 ++ * And what have we got... ++ */ ++#define YAFFS_MAGIC 0x5941ff53 ++ ++/* ++ * Tnodes form a tree with the tnodes in "levels" ++ * Levels greater than 0 hold 8 slots which point to other tnodes. ++ * Those at level 0 hold 16 slots which point to chunks in NAND. ++ * ++ * A maximum level of 8 thust supports files of size up to: ++ * ++ * 2^(3*MAX_LEVEL+4) ++ * ++ * Thus a max level of 8 supports files with up to 2^^28 chunks which gives ++ * a maximum file size of around 512Gbytees with 2k chunks. ++ */ ++#define YAFFS_NTNODES_LEVEL0 16 ++#define YAFFS_TNODES_LEVEL0_BITS 4 ++#define YAFFS_TNODES_LEVEL0_MASK 0xf ++ ++#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2) ++#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1) ++#define YAFFS_TNODES_INTERNAL_MASK 0x7 ++#define YAFFS_TNODES_MAX_LEVEL 8 ++#define YAFFS_TNODES_MAX_BITS (YAFFS_TNODES_LEVEL0_BITS + \ ++ YAFFS_TNODES_INTERNAL_BITS * \ ++ YAFFS_TNODES_MAX_LEVEL) ++#define YAFFS_MAX_CHUNK_ID ((1 << YAFFS_TNODES_MAX_BITS) - 1) ++ ++#define YAFFS_MAX_FILE_SIZE_32 0x7fffffff ++ ++/* Constants for YAFFS1 mode */ ++#define YAFFS_BYTES_PER_SPARE 16 ++#define YAFFS_BYTES_PER_CHUNK 512 ++#define YAFFS_CHUNK_SIZE_SHIFT 9 ++#define YAFFS_CHUNKS_PER_BLOCK 32 ++#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK) ++ ++#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024 ++#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32 ++ ++ ++ ++#define YAFFS_ALLOCATION_NOBJECTS 100 ++#define YAFFS_ALLOCATION_NTNODES 100 ++#define YAFFS_ALLOCATION_NLINKS 100 ++ ++#define YAFFS_NOBJECT_BUCKETS 256 ++ ++#define YAFFS_OBJECT_SPACE 0x40000 ++#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE - 1) ++ ++/* Binary data version stamps */ ++#define YAFFS_SUMMARY_VERSION 1 ++#define YAFFS_CHECKPOINT_VERSION 7 ++ ++#ifdef CONFIG_YAFFS_UNICODE ++#define YAFFS_MAX_NAME_LENGTH 127 ++#define YAFFS_MAX_ALIAS_LENGTH 79 ++#else ++#define YAFFS_MAX_NAME_LENGTH 255 ++#define YAFFS_MAX_ALIAS_LENGTH 159 ++#endif ++ ++#define YAFFS_SHORT_NAME_LENGTH 15 ++ ++/* Some special object ids for pseudo objects */ ++#define YAFFS_OBJECTID_ROOT 1 ++#define YAFFS_OBJECTID_LOSTNFOUND 2 ++#define YAFFS_OBJECTID_UNLINKED 3 ++#define YAFFS_OBJECTID_DELETED 4 ++ ++/* Fake object Id for summary data */ ++#define YAFFS_OBJECTID_SUMMARY 0x10 ++ ++/* Pseudo object ids for checkpointing */ ++#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20 ++#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21 ++ ++#define YAFFS_MAX_SHORT_OP_CACHES 20 ++ ++#define YAFFS_N_TEMP_BUFFERS 6 ++ ++/* We limit the number attempts at sucessfully saving a chunk of data. ++ * Small-page devices have 32 pages per block; large-page devices have 64. ++ * Default to something in the order of 5 to 10 blocks worth of chunks. ++ */ ++#define YAFFS_WR_ATTEMPTS (5*64) ++ ++/* Sequence numbers are used in YAFFS2 to determine block allocation order. ++ * The range is limited slightly to help distinguish bad numbers from good. ++ * This also allows us to perhaps in the future use special numbers for ++ * special purposes. ++ * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years, ++ * and is a larger number than the lifetime of a 2GB device. ++ */ ++#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000 ++#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xefffff00 ++ ++/* Special sequence number for bad block that failed to be marked bad */ ++#define YAFFS_SEQUENCE_BAD_BLOCK 0xffff0000 ++ ++/* ChunkCache is used for short read/write operations.*/ ++struct yaffs_cache { ++ struct yaffs_obj *object; ++ int chunk_id; ++ int last_use; ++ int dirty; ++ int n_bytes; /* Only valid if the cache is dirty */ ++ int locked; /* Can't push out or flush while locked. */ ++ u8 *data; ++}; ++ ++/* yaffs1 tags structures in RAM ++ * NB This uses bitfield. Bitfields should not straddle a u32 boundary ++ * otherwise the structure size will get blown out. ++ */ ++ ++struct yaffs_tags { ++ u32 chunk_id:20; ++ u32 serial_number:2; ++ u32 n_bytes_lsb:10; ++ u32 obj_id:18; ++ u32 ecc:12; ++ u32 n_bytes_msb:2; ++}; ++ ++union yaffs_tags_union { ++ struct yaffs_tags as_tags; ++ u8 as_bytes[8]; ++}; ++ ++ ++/* Stuff used for extended tags in YAFFS2 */ ++ ++enum yaffs_ecc_result { ++ YAFFS_ECC_RESULT_UNKNOWN, ++ YAFFS_ECC_RESULT_NO_ERROR, ++ YAFFS_ECC_RESULT_FIXED, ++ YAFFS_ECC_RESULT_UNFIXED ++}; ++ ++enum yaffs_obj_type { ++ YAFFS_OBJECT_TYPE_UNKNOWN, ++ YAFFS_OBJECT_TYPE_FILE, ++ YAFFS_OBJECT_TYPE_SYMLINK, ++ YAFFS_OBJECT_TYPE_DIRECTORY, ++ YAFFS_OBJECT_TYPE_HARDLINK, ++ YAFFS_OBJECT_TYPE_SPECIAL ++}; ++ ++#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL ++ ++struct yaffs_ext_tags { ++ unsigned chunk_used; /* Status of the chunk: used or unused */ ++ unsigned obj_id; /* If 0 this is not used */ ++ unsigned chunk_id; /* If 0 this is a header, else a data chunk */ ++ unsigned n_bytes; /* Only valid for data chunks */ ++ ++ /* The following stuff only has meaning when we read */ ++ enum yaffs_ecc_result ecc_result; ++ unsigned block_bad; ++ ++ /* YAFFS 1 stuff */ ++ unsigned is_deleted; /* The chunk is marked deleted */ ++ unsigned serial_number; /* Yaffs1 2-bit serial number */ ++ ++ /* YAFFS2 stuff */ ++ unsigned seq_number; /* The sequence number of this block */ ++ ++ /* Extra info if this is an object header (YAFFS2 only) */ ++ ++ unsigned extra_available; /* Extra info available if not zero */ ++ unsigned extra_parent_id; /* The parent object */ ++ unsigned extra_is_shrink; /* Is it a shrink header? */ ++ unsigned extra_shadows; /* Does this shadow another object? */ ++ ++ enum yaffs_obj_type extra_obj_type; /* What object type? */ ++ ++ loff_t extra_file_size; /* Length if it is a file */ ++ unsigned extra_equiv_id; /* Equivalent object for a hard link */ ++}; ++ ++/* Spare structure for YAFFS1 */ ++struct yaffs_spare { ++ u8 tb0; ++ u8 tb1; ++ u8 tb2; ++ u8 tb3; ++ u8 page_status; /* set to 0 to delete the chunk */ ++ u8 block_status; ++ u8 tb4; ++ u8 tb5; ++ u8 ecc1[3]; ++ u8 tb6; ++ u8 tb7; ++ u8 ecc2[3]; ++}; ++ ++/*Special structure for passing through to mtd */ ++struct yaffs_nand_spare { ++ struct yaffs_spare spare; ++ int eccres1; ++ int eccres2; ++}; ++ ++/* Block data in RAM */ ++ ++enum yaffs_block_state { ++ YAFFS_BLOCK_STATE_UNKNOWN = 0, ++ ++ YAFFS_BLOCK_STATE_SCANNING, ++ /* Being scanned */ ++ ++ YAFFS_BLOCK_STATE_NEEDS_SCAN, ++ /* The block might have something on it (ie it is allocating or full, ++ * perhaps empty) but it needs to be scanned to determine its true ++ * state. ++ * This state is only valid during scanning. ++ * NB We tolerate empty because the pre-scanner might be incapable of ++ * deciding ++ * However, if this state is returned on a YAFFS2 device, ++ * then we expect a sequence number ++ */ ++ ++ YAFFS_BLOCK_STATE_EMPTY, ++ /* This block is empty */ ++ ++ YAFFS_BLOCK_STATE_ALLOCATING, ++ /* This block is partially allocated. ++ * At least one page holds valid data. ++ * This is the one currently being used for page ++ * allocation. Should never be more than one of these. ++ * If a block is only partially allocated at mount it is treated as ++ * full. ++ */ ++ ++ YAFFS_BLOCK_STATE_FULL, ++ /* All the pages in this block have been allocated. ++ * If a block was only partially allocated when mounted we treat ++ * it as fully allocated. ++ */ ++ ++ YAFFS_BLOCK_STATE_DIRTY, ++ /* The block was full and now all chunks have been deleted. ++ * Erase me, reuse me. ++ */ ++ ++ YAFFS_BLOCK_STATE_CHECKPOINT, ++ /* This block is assigned to holding checkpoint data. */ ++ ++ YAFFS_BLOCK_STATE_COLLECTING, ++ /* This block is being garbage collected */ ++ ++ YAFFS_BLOCK_STATE_DEAD ++ /* This block has failed and is not in use */ ++}; ++ ++#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1) ++ ++struct yaffs_block_info { ++ ++ s32 soft_del_pages:10; /* number of soft deleted pages */ ++ s32 pages_in_use:10; /* number of pages in use */ ++ u32 block_state:4; /* One of the above block states. */ ++ /* NB use unsigned because enum is sometimes ++ * an int */ ++ u32 needs_retiring:1; /* Data has failed on this block, */ ++ /*need to get valid data off and retire*/ ++ u32 skip_erased_check:1;/* Skip the erased check on this block */ ++ u32 gc_prioritise:1; /* An ECC check or blank check has failed. ++ Block should be prioritised for GC */ ++ u32 chunk_error_strikes:3; /* How many times we've had ecc etc ++ failures on this block and tried to reuse it */ ++ u32 has_summary:1; /* The block has a summary */ ++ ++ u32 has_shrink_hdr:1; /* This block has at least one shrink header */ ++ u32 seq_number; /* block sequence number for yaffs2 */ ++ ++}; ++ ++/* -------------------------- Object structure -------------------------------*/ ++/* This is the object structure as stored on NAND */ ++ ++struct yaffs_obj_hdr { ++ enum yaffs_obj_type type; ++ ++ /* Apply to everything */ ++ int parent_obj_id; ++ u16 sum_no_longer_used; /* checksum of name. No longer used */ ++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ /* The following apply to all object types except for hard links */ ++ u32 yst_mode; /* protection */ ++ ++ u32 yst_uid; ++ u32 yst_gid; ++ u32 yst_atime; ++ u32 yst_mtime; ++ u32 yst_ctime; ++ ++ /* File size applies to files only */ ++ u32 file_size_low; ++ ++ /* Equivalent object id applies to hard links only. */ ++ int equiv_id; ++ ++ /* Alias is for symlinks only. */ ++ YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1]; ++ ++ u32 yst_rdev; /* stuff for block and char devices (major/min) */ ++ ++ u32 win_ctime[2]; ++ u32 win_atime[2]; ++ u32 win_mtime[2]; ++ ++ u32 inband_shadowed_obj_id; ++ u32 inband_is_shrink; ++ ++ u32 file_size_high; ++ u32 reserved[1]; ++ int shadows_obj; /* This object header shadows the ++ specified object if > 0 */ ++ ++ /* is_shrink applies to object headers written when wemake a hole. */ ++ u32 is_shrink; ++ ++}; ++ ++/*--------------------------- Tnode -------------------------- */ ++ ++struct yaffs_tnode { ++ struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL]; ++}; ++ ++/*------------------------ Object -----------------------------*/ ++/* An object can be one of: ++ * - a directory (no data, has children links ++ * - a regular file (data.... not prunes :->). ++ * - a symlink [symbolic link] (the alias). ++ * - a hard link ++ */ ++ ++struct yaffs_file_var { ++ loff_t file_size; ++ loff_t scanned_size; ++ loff_t shrink_size; ++ int top_level; ++ struct yaffs_tnode *top; ++}; ++ ++struct yaffs_dir_var { ++ struct list_head children; /* list of child links */ ++ struct list_head dirty; /* Entry for list of dirty directories */ ++}; ++ ++struct yaffs_symlink_var { ++ YCHAR *alias; ++}; ++ ++struct yaffs_hardlink_var { ++ struct yaffs_obj *equiv_obj; ++ u32 equiv_id; ++}; ++ ++union yaffs_obj_var { ++ struct yaffs_file_var file_variant; ++ struct yaffs_dir_var dir_variant; ++ struct yaffs_symlink_var symlink_variant; ++ struct yaffs_hardlink_var hardlink_variant; ++}; ++ ++struct yaffs_obj { ++ u8 deleted:1; /* This should only apply to unlinked files. */ ++ u8 soft_del:1; /* it has also been soft deleted */ ++ u8 unlinked:1; /* An unlinked file.*/ ++ u8 fake:1; /* A fake object has no presence on NAND. */ ++ u8 rename_allowed:1; /* Some objects cannot be renamed. */ ++ u8 unlink_allowed:1; ++ u8 dirty:1; /* the object needs to be written to flash */ ++ u8 valid:1; /* When the file system is being loaded up, this ++ * object might be created before the data ++ * is available ++ * ie. file data chunks encountered before ++ * the header. ++ */ ++ u8 lazy_loaded:1; /* This object has been lazy loaded and ++ * is missing some detail */ ++ ++ u8 defered_free:1; /* Object is removed from NAND, but is ++ * still in the inode cache. ++ * Free of object is defered. ++ * until the inode is released. ++ */ ++ u8 being_created:1; /* This object is still being created ++ * so skip some verification checks. */ ++ u8 is_shadowed:1; /* This object is shadowed on the way ++ * to being renamed. */ ++ ++ u8 xattr_known:1; /* We know if this has object has xattribs ++ * or not. */ ++ u8 has_xattr:1; /* This object has xattribs. ++ * Only valid if xattr_known. */ ++ ++ u8 serial; /* serial number of chunk in NAND.*/ ++ u16 sum; /* sum of the name to speed searching */ ++ ++ struct yaffs_dev *my_dev; /* The device I'm on */ ++ ++ struct list_head hash_link; /* list of objects in hash bucket */ ++ ++ struct list_head hard_links; /* hard linked object chain*/ ++ ++ /* directory structure stuff */ ++ /* also used for linking up the free list */ ++ struct yaffs_obj *parent; ++ struct list_head siblings; ++ ++ /* Where's my object header in NAND? */ ++ int hdr_chunk; ++ ++ int n_data_chunks; /* Number of data chunks for this file. */ ++ ++ u32 obj_id; /* the object id value */ ++ ++ u32 yst_mode; ++ ++ YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1]; ++ ++#ifdef CONFIG_YAFFS_WINCE ++ u32 win_ctime[2]; ++ u32 win_mtime[2]; ++ u32 win_atime[2]; ++#else ++ u32 yst_uid; ++ u32 yst_gid; ++ u32 yst_atime; ++ u32 yst_mtime; ++ u32 yst_ctime; ++#endif ++ ++ u32 yst_rdev; ++ ++ void *my_inode; ++ ++ enum yaffs_obj_type variant_type; ++ ++ union yaffs_obj_var variant; ++ ++}; ++ ++struct yaffs_obj_bucket { ++ struct list_head list; ++ int count; ++}; ++ ++/* yaffs_checkpt_obj holds the definition of an object as dumped ++ * by checkpointing. ++ */ ++ ++struct yaffs_checkpt_obj { ++ int struct_type; ++ u32 obj_id; ++ u32 parent_id; ++ int hdr_chunk; ++ enum yaffs_obj_type variant_type:3; ++ u8 deleted:1; ++ u8 soft_del:1; ++ u8 unlinked:1; ++ u8 fake:1; ++ u8 rename_allowed:1; ++ u8 unlink_allowed:1; ++ u8 serial; ++ int n_data_chunks; ++ loff_t size_or_equiv_obj; ++}; ++ ++/*--------------------- Temporary buffers ---------------- ++ * ++ * These are chunk-sized working buffers. Each device has a few. ++ */ ++ ++struct yaffs_buffer { ++ u8 *buffer; ++ int in_use; ++}; ++ ++/*----------------- Device ---------------------------------*/ ++ ++struct yaffs_param { ++ const YCHAR *name; ++ ++ /* ++ * Entry parameters set up way early. Yaffs sets up the rest. ++ * The structure should be zeroed out before use so that unused ++ * and default values are zero. ++ */ ++ ++ int inband_tags; /* Use unband tags */ ++ u32 total_bytes_per_chunk; /* Should be >= 512, does not need to ++ be a power of 2 */ ++ int chunks_per_block; /* does not need to be a power of 2 */ ++ int spare_bytes_per_chunk; /* spare area size */ ++ int start_block; /* Start block we're allowed to use */ ++ int end_block; /* End block we're allowed to use */ ++ int n_reserved_blocks; /* Tuneable so that we can reduce ++ * reserved blocks on NOR and RAM. */ ++ ++ int n_caches; /* If <= 0, then short op caching is disabled, ++ * else the number of short op caches. ++ */ ++ int cache_bypass_aligned; /* If non-zero then bypass the cache for ++ * aligned writes. ++ */ ++ ++ int use_nand_ecc; /* Flag to decide whether or not to use ++ * NAND driver ECC on data (yaffs1) */ ++ int tags_9bytes; /* Use 9 byte tags */ ++ int no_tags_ecc; /* Flag to decide whether or not to do ECC ++ * on packed tags (yaffs2) */ ++ ++ int is_yaffs2; /* Use yaffs2 mode on this device */ ++ ++ int empty_lost_n_found; /* Auto-empty lost+found directory on mount */ ++ ++ int refresh_period; /* How often to check for a block refresh */ ++ ++ /* Checkpoint control. Can be set before or after initialisation */ ++ u8 skip_checkpt_rd; ++ u8 skip_checkpt_wr; ++ ++ int enable_xattr; /* Enable xattribs */ ++ ++ int max_objects; /* ++ * Set to limit the number of objects created. ++ * 0 = no limit. ++ */ ++ ++ /* The remove_obj_fn function must be supplied by OS flavours that ++ * need it. ++ * yaffs direct uses it to implement the faster readdir. ++ * Linux uses it to protect the directory during unlocking. ++ */ ++ void (*remove_obj_fn) (struct yaffs_obj *obj); ++ ++ /* Callback to mark the superblock dirty */ ++ void (*sb_dirty_fn) (struct yaffs_dev *dev); ++ ++ /* Callback to control garbage collection. */ ++ unsigned (*gc_control_fn) (struct yaffs_dev *dev); ++ ++ /* Debug control flags. Don't use unless you know what you're doing */ ++ int use_header_file_size; /* Flag to determine if we should use ++ * file sizes from the header */ ++ int disable_lazy_load; /* Disable lazy loading on this device */ ++ int wide_tnodes_disabled; /* Set to disable wide tnodes */ ++ int disable_soft_del; /* yaffs 1 only: Set to disable the use of ++ * softdeletion. */ ++ ++ int defered_dir_update; /* Set to defer directory updates */ ++ ++#ifdef CONFIG_YAFFS_AUTO_UNICODE ++ int auto_unicode; ++#endif ++ int always_check_erased; /* Force chunk erased check always on */ ++ ++ int disable_summary; ++ int disable_bad_block_marking; ++ ++}; ++ ++struct yaffs_driver { ++ int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk, ++ const u8 *data, int data_len, ++ const u8 *oob, int oob_len); ++ int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk, ++ u8 *data, int data_len, ++ u8 *oob, int oob_len, ++ enum yaffs_ecc_result *ecc_result); ++ int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no); ++ int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no); ++ int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no); ++ int (*drv_initialise_fn) (struct yaffs_dev *dev); ++ int (*drv_deinitialise_fn) (struct yaffs_dev *dev); ++}; ++ ++struct yaffs_tags_handler { ++ int (*write_chunk_tags_fn) (struct yaffs_dev *dev, ++ int nand_chunk, const u8 *data, ++ const struct yaffs_ext_tags *tags); ++ int (*read_chunk_tags_fn) (struct yaffs_dev *dev, ++ int nand_chunk, u8 *data, ++ struct yaffs_ext_tags *tags); ++ ++ int (*query_block_fn) (struct yaffs_dev *dev, int block_no, ++ enum yaffs_block_state *state, ++ u32 *seq_number); ++ int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no); ++}; ++ ++struct yaffs_dev { ++ struct yaffs_param param; ++ struct yaffs_driver drv; ++ struct yaffs_tags_handler tagger; ++ ++ /* Context storage. Holds extra OS specific data for this device */ ++ ++ void *os_context; ++ void *driver_context; ++ ++ struct list_head dev_list; ++ ++ int ll_init; ++ /* Runtime parameters. Set up by YAFFS. */ ++ int data_bytes_per_chunk; ++ ++ /* Non-wide tnode stuff */ ++ u16 chunk_grp_bits; /* Number of bits that need to be resolved if ++ * the tnodes are not wide enough. ++ */ ++ u16 chunk_grp_size; /* == 2^^chunk_grp_bits */ ++ ++ /* Stuff to support wide tnodes */ ++ u32 tnode_width; ++ u32 tnode_mask; ++ u32 tnode_size; ++ ++ /* Stuff for figuring out file offset to chunk conversions */ ++ u32 chunk_shift; /* Shift value */ ++ u32 chunk_div; /* Divisor after shifting: 1 for 2^n sizes */ ++ u32 chunk_mask; /* Mask to use for power-of-2 case */ ++ ++ int is_mounted; ++ int read_only; ++ int is_checkpointed; ++ ++ /* Stuff to support block offsetting to support start block zero */ ++ int internal_start_block; ++ int internal_end_block; ++ int block_offset; ++ int chunk_offset; ++ ++ /* Runtime checkpointing stuff */ ++ int checkpt_page_seq; /* running sequence number of checkpt pages */ ++ int checkpt_byte_count; ++ int checkpt_byte_offs; ++ u8 *checkpt_buffer; ++ int checkpt_open_write; ++ int blocks_in_checkpt; ++ int checkpt_cur_chunk; ++ int checkpt_cur_block; ++ int checkpt_next_block; ++ int *checkpt_block_list; ++ int checkpt_max_blocks; ++ u32 checkpt_sum; ++ u32 checkpt_xor; ++ ++ int checkpoint_blocks_required; /* Number of blocks needed to store ++ * current checkpoint set */ ++ ++ /* Block Info */ ++ struct yaffs_block_info *block_info; ++ u8 *chunk_bits; /* bitmap of chunks in use */ ++ u8 block_info_alt:1; /* allocated using alternative alloc */ ++ u8 chunk_bits_alt:1; /* allocated using alternative alloc */ ++ int chunk_bit_stride; /* Number of bytes of chunk_bits per block. ++ * Must be consistent with chunks_per_block. ++ */ ++ ++ int n_erased_blocks; ++ int alloc_block; /* Current block being allocated off */ ++ u32 alloc_page; ++ int alloc_block_finder; /* Used to search for next allocation block */ ++ ++ /* Object and Tnode memory management */ ++ void *allocator; ++ int n_obj; ++ int n_tnodes; ++ ++ int n_hardlinks; ++ ++ struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS]; ++ u32 bucket_finder; ++ ++ int n_free_chunks; ++ ++ /* Garbage collection control */ ++ u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */ ++ u32 n_clean_ups; ++ ++ unsigned has_pending_prioritised_gc; /* We think this device might ++ have pending prioritised gcs */ ++ unsigned gc_disable; ++ unsigned gc_block_finder; ++ unsigned gc_dirtiest; ++ unsigned gc_pages_in_use; ++ unsigned gc_not_done; ++ unsigned gc_block; ++ unsigned gc_chunk; ++ unsigned gc_skip; ++ struct yaffs_summary_tags *gc_sum_tags; ++ ++ /* Special directories */ ++ struct yaffs_obj *root_dir; ++ struct yaffs_obj *lost_n_found; ++ ++ int buffered_block; /* Which block is buffered here? */ ++ int doing_buffered_block_rewrite; ++ ++ struct yaffs_cache *cache; ++ int cache_last_use; ++ ++ /* Stuff for background deletion and unlinked files. */ ++ struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted ++ files live. */ ++ struct yaffs_obj *del_dir; /* Directory where deleted objects are ++ sent to disappear. */ ++ struct yaffs_obj *unlinked_deletion; /* Current file being ++ background deleted. */ ++ int n_deleted_files; /* Count of files awaiting deletion; */ ++ int n_unlinked_files; /* Count of unlinked files. */ ++ int n_bg_deletions; /* Count of background deletions. */ ++ ++ /* Temporary buffer management */ ++ struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS]; ++ int max_temp; ++ int temp_in_use; ++ int unmanaged_buffer_allocs; ++ int unmanaged_buffer_deallocs; ++ ++ /* yaffs2 runtime stuff */ ++ unsigned seq_number; /* Sequence number of currently ++ allocating block */ ++ unsigned oldest_dirty_seq; ++ unsigned oldest_dirty_block; ++ ++ /* Block refreshing */ ++ int refresh_skip; /* A skip down counter. ++ * Refresh happens when this gets to zero. */ ++ ++ /* Dirty directory handling */ ++ struct list_head dirty_dirs; /* List of dirty directories */ ++ ++ /* Summary */ ++ int chunks_per_summary; ++ struct yaffs_summary_tags *sum_tags; ++ ++ /* Statistics */ ++ u32 n_page_writes; ++ u32 n_page_reads; ++ u32 n_erasures; ++ u32 n_bad_queries; ++ u32 n_bad_markings; ++ u32 n_erase_failures; ++ u32 n_gc_copies; ++ u32 all_gcs; ++ u32 passive_gc_count; ++ u32 oldest_dirty_gc_count; ++ u32 n_gc_blocks; ++ u32 bg_gcs; ++ u32 n_retried_writes; ++ u32 n_retired_blocks; ++ u32 n_ecc_fixed; ++ u32 n_ecc_unfixed; ++ u32 n_tags_ecc_fixed; ++ u32 n_tags_ecc_unfixed; ++ u32 n_deletions; ++ u32 n_unmarked_deletions; ++ u32 refresh_count; ++ u32 cache_hits; ++ u32 tags_used; ++ u32 summary_used; ++ ++}; ++ ++/* The CheckpointDevice structure holds the device information that changes ++ *at runtime and must be preserved over unmount/mount cycles. ++ */ ++struct yaffs_checkpt_dev { ++ int struct_type; ++ int n_erased_blocks; ++ int alloc_block; /* Current block being allocated off */ ++ u32 alloc_page; ++ int n_free_chunks; ++ ++ int n_deleted_files; /* Count of files awaiting deletion; */ ++ int n_unlinked_files; /* Count of unlinked files. */ ++ int n_bg_deletions; /* Count of background deletions. */ ++ ++ /* yaffs2 runtime stuff */ ++ unsigned seq_number; /* Sequence number of currently ++ * allocating block */ ++ ++}; ++ ++struct yaffs_checkpt_validity { ++ int struct_type; ++ u32 magic; ++ u32 version; ++ u32 head; ++}; ++ ++struct yaffs_shadow_fixer { ++ int obj_id; ++ int shadowed_id; ++ struct yaffs_shadow_fixer *next; ++}; ++ ++/* Structure for doing xattr modifications */ ++struct yaffs_xattr_mod { ++ int set; /* If 0 then this is a deletion */ ++ const YCHAR *name; ++ const void *data; ++ int size; ++ int flags; ++ int result; ++}; ++ ++/*----------------------- YAFFS Functions -----------------------*/ ++ ++int yaffs_guts_initialise(struct yaffs_dev *dev); ++void yaffs_deinitialise(struct yaffs_dev *dev); ++ ++int yaffs_get_n_free_chunks(struct yaffs_dev *dev); ++ ++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name, ++ struct yaffs_obj *new_dir, const YCHAR * new_name); ++ ++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name); ++int yaffs_del_obj(struct yaffs_obj *obj); ++struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj, ++ enum yaffs_obj_type type); ++ ++ ++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size); ++loff_t yaffs_get_obj_length(struct yaffs_obj *obj); ++int yaffs_get_obj_inode(struct yaffs_obj *obj); ++unsigned yaffs_get_obj_type(struct yaffs_obj *obj); ++int yaffs_get_obj_link_count(struct yaffs_obj *obj); ++ ++/* File operations */ ++int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset, ++ int n_bytes); ++int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset, ++ int n_bytes, int write_trhrough); ++int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size); ++ ++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent, ++ const YCHAR *name, u32 mode, u32 uid, ++ u32 gid); ++ ++int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync); ++ ++/* Flushing and checkpointing */ ++void yaffs_flush_whole_cache(struct yaffs_dev *dev); ++ ++int yaffs_checkpoint_save(struct yaffs_dev *dev); ++int yaffs_checkpoint_restore(struct yaffs_dev *dev); ++ ++/* Directory operations */ ++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name, ++ u32 mode, u32 uid, u32 gid); ++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir, ++ const YCHAR *name); ++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number); ++ ++/* Link operations */ ++struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name, ++ struct yaffs_obj *equiv_obj); ++ ++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj); ++ ++/* Symlink operations */ ++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent, ++ const YCHAR *name, u32 mode, u32 uid, ++ u32 gid, const YCHAR *alias); ++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj); ++ ++/* Special inodes (fifos, sockets and devices) */ ++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent, ++ const YCHAR *name, u32 mode, u32 uid, ++ u32 gid, u32 rdev); ++ ++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name, ++ const void *value, int size, int flags); ++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value, ++ int size); ++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size); ++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name); ++ ++/* Special directories */ ++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev); ++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev); ++ ++void yaffs_handle_defered_free(struct yaffs_obj *obj); ++ ++void yaffs_update_dirty_dirs(struct yaffs_dev *dev); ++ ++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency); ++ ++/* Debug dump */ ++int yaffs_dump_obj(struct yaffs_obj *obj); ++ ++void yaffs_guts_test(struct yaffs_dev *dev); ++int yaffs_guts_ll_init(struct yaffs_dev *dev); ++ ++ ++/* A few useful functions to be used within the core files*/ ++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash, ++ int lyn); ++int yaffs_check_ff(u8 *buffer, int n_bytes); ++void yaffs_handle_chunk_error(struct yaffs_dev *dev, ++ struct yaffs_block_info *bi); ++ ++u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev); ++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer); ++ ++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev, ++ int number, ++ enum yaffs_obj_type type); ++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk, ++ int nand_chunk, int in_scan); ++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name); ++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj, ++ const struct yaffs_obj_hdr *oh); ++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj); ++YCHAR *yaffs_clone_str(const YCHAR *str); ++void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list); ++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no); ++int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, ++ int force, int is_shrink, int shadows, ++ struct yaffs_xattr_mod *xop); ++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id, ++ int backward_scanning); ++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks); ++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev); ++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev, ++ struct yaffs_file_var *file_struct, ++ u32 chunk_id, ++ struct yaffs_tnode *passed_tn); ++ ++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset, ++ int n_bytes, int write_trhrough); ++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size); ++void yaffs_skip_rest_of_block(struct yaffs_dev *dev); ++ ++int yaffs_count_free_chunks(struct yaffs_dev *dev); ++ ++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev, ++ struct yaffs_file_var *file_struct, ++ u32 chunk_id); ++ ++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn, ++ unsigned pos); ++ ++int yaffs_is_non_empty_dir(struct yaffs_obj *obj); ++ ++int yaffs_guts_format_dev(struct yaffs_dev *dev); ++ ++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr, ++ int *chunk_out, u32 *offset_out); ++/* ++ * Marshalling functions to get loff_t file sizes into aand out of ++ * object headers. ++ */ ++void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize); ++loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh); ++loff_t yaffs_max_file_size(struct yaffs_dev *dev); ++ ++/* ++ * Debug function to count number of blocks in each state ++ * NB Needs to be called with correct number of integers ++ */ ++ ++void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]); ++ ++int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk, ++ struct yaffs_ext_tags *tags); ++ ++#endif +diff --git a/fs/yaffs2/yaffs_linux.h b/fs/yaffs2/yaffs_linux.h +new file mode 100644 +index 00000000..c20ab14b +--- /dev/null ++++ b/fs/yaffs2/yaffs_linux.h +@@ -0,0 +1,48 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_LINUX_H__ ++#define __YAFFS_LINUX_H__ ++ ++#include "yportenv.h" ++ ++struct yaffs_linux_context { ++ struct list_head context_list; /* List of these we have mounted */ ++ struct yaffs_dev *dev; ++ struct super_block *super; ++ struct task_struct *bg_thread; /* Background thread for this device */ ++ int bg_running; ++ struct mutex gross_lock; /* Gross locking mutex*/ ++ u8 *spare_buffer; /* For mtdif2 use. Don't know the buffer size ++ * at compile time so we have to allocate it. ++ */ ++ struct list_head search_contexts; ++ struct task_struct *readdir_process; ++ unsigned mount_id; ++ int dirty; ++}; ++ ++#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context)) ++#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context)) ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++#define WRITE_SIZE_STR "writesize" ++#define WRITE_SIZE(mtd) ((mtd)->writesize) ++#else ++#define WRITE_SIZE_STR "oobblock" ++#define WRITE_SIZE(mtd) ((mtd)->oobblock) ++#endif ++ ++#endif +diff --git a/fs/yaffs2/yaffs_mtdif.c b/fs/yaffs2/yaffs_mtdif.c +new file mode 100644 +index 00000000..7ae63c54 +--- /dev/null ++++ b/fs/yaffs2/yaffs_mtdif.c +@@ -0,0 +1,308 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yportenv.h" ++ ++#include "yaffs_mtdif.h" ++ ++#include "linux/mtd/mtd.h" ++#include "linux/types.h" ++#include "linux/time.h" ++#include "linux/mtd/nand.h" ++#include "linux/kernel.h" ++#include "linux/version.h" ++#include "linux/types.h" ++ ++#include "yaffs_trace.h" ++#include "yaffs_guts.h" ++#include "yaffs_linux.h" ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) ++#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO ++#endif ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) ++#define mtd_erase(m, ei) (m)->erase(m, ei) ++#define mtd_write_oob(m, addr, pops) (m)->write_oob(m, addr, pops) ++#define mtd_read_oob(m, addr, pops) (m)->read_oob(m, addr, pops) ++#define mtd_block_isbad(m, offs) (m)->block_isbad(m, offs) ++#define mtd_block_markbad(m, offs) (m)->block_markbad(m, offs) ++#endif ++ ++ ++ ++int nandmtd_erase_block(struct yaffs_dev *dev, int block_no) ++{ ++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); ++ u32 addr = ++ ((loff_t) block_no) * dev->param.total_bytes_per_chunk * ++ dev->param.chunks_per_block; ++ struct erase_info ei; ++ int retval = 0; ++ ++ ei.mtd = mtd; ++ ei.addr = addr; ++ ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block; ++ ei.time = 1000; ++ ei.retries = 2; ++ ei.callback = NULL; ++ ei.priv = (u_long) dev; ++ ++ retval = mtd_erase(mtd, &ei); ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ ++ return YAFFS_FAIL; ++} ++ ++ ++static int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk, ++ const u8 *data, int data_len, ++ const u8 *oob, int oob_len) ++{ ++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); ++ loff_t addr; ++ struct mtd_oob_ops ops; ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "yaffs_mtd_write(%p, %d, %p, %d, %p, %d)\n", ++ dev, nand_chunk, data, data_len, oob, oob_len); ++ ++ if (!data || !data_len) { ++ data = NULL; ++ data_len = 0; ++ } ++ ++ if (!oob || !oob_len) { ++ oob = NULL; ++ oob_len = 0; ++ } ++ ++ addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk; ++ memset(&ops, 0, sizeof(ops)); ++ ops.mode = MTD_OPS_AUTO_OOB; ++ ops.len = (data) ? data_len : 0; ++ ops.ooblen = oob_len; ++ ops.datbuf = (u8 *)data; ++ ops.oobbuf = (u8 *)oob; ++ ++ retval = mtd_write_oob(mtd, addr, &ops); ++ if (retval) { ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "write_oob failed, chunk %d, mtd error %d", ++ nand_chunk, retval); ++ } ++ return retval ? YAFFS_FAIL : YAFFS_OK; ++} ++ ++static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk, ++ u8 *data, int data_len, ++ u8 *oob, int oob_len, ++ enum yaffs_ecc_result *ecc_result) ++{ ++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); ++ loff_t addr; ++ struct mtd_oob_ops ops; ++ int retval; ++ ++ addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk; ++ memset(&ops, 0, sizeof(ops)); ++ ops.mode = MTD_OPS_AUTO_OOB; ++ ops.len = (data) ? data_len : 0; ++ ops.ooblen = oob_len; ++ ops.datbuf = data; ++ ops.oobbuf = oob; ++ ++#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20)) ++ /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug; ++ * help it out with ops.len = ops.ooblen when ops.datbuf == NULL. ++ */ ++ ops.len = (ops.datbuf) ? ops.len : ops.ooblen; ++#endif ++ /* Read page and oob using MTD. ++ * Check status and determine ECC result. ++ */ ++ retval = mtd_read_oob(mtd, addr, &ops); ++ if (retval) ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "read_oob failed, chunk %d, mtd error %d", ++ nand_chunk, retval); ++ ++ switch (retval) { ++ case 0: ++ /* no error */ ++ if(ecc_result) ++ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; ++ break; ++ ++ case -EUCLEAN: ++ /* MTD's ECC fixed the data */ ++ if(ecc_result) ++ *ecc_result = YAFFS_ECC_RESULT_FIXED; ++ dev->n_ecc_fixed++; ++ break; ++ ++ case -EBADMSG: ++ default: ++ /* MTD's ECC could not fix the data */ ++ dev->n_ecc_unfixed++; ++ if(ecc_result) ++ *ecc_result = YAFFS_ECC_RESULT_UNFIXED; ++ return YAFFS_FAIL; ++ } ++ ++ return YAFFS_OK; ++} ++ ++static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no) ++{ ++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); ++ ++ loff_t addr; ++ struct erase_info ei; ++ int retval = 0; ++ u32 block_size; ++ ++ block_size = dev->param.total_bytes_per_chunk * ++ dev->param.chunks_per_block; ++ addr = ((loff_t) block_no) * block_size; ++ ++ ei.mtd = mtd; ++ ei.addr = addr; ++ ei.len = block_size; ++ ei.time = 1000; ++ ei.retries = 2; ++ ei.callback = NULL; ++ ei.priv = (u_long) dev; ++ ++ retval = mtd_erase(mtd, &ei); ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ ++ return YAFFS_FAIL; ++} ++ ++static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no) ++{ ++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); ++ int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk; ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no); ++ ++ retval = mtd_block_markbad(mtd, (loff_t) blocksize * block_no); ++ return (retval) ? YAFFS_FAIL : YAFFS_OK; ++} ++ ++static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no) ++{ ++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); ++ int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk; ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_MTD, "checking block %d bad", block_no); ++ ++ retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no); ++ return (retval) ? YAFFS_FAIL : YAFFS_OK; ++} ++ ++static int yaffs_mtd_initialise(struct yaffs_dev *dev) ++{ ++ return YAFFS_OK; ++} ++ ++static int yaffs_mtd_deinitialise(struct yaffs_dev *dev) ++{ ++ return YAFFS_OK; ++} ++ ++ ++void yaffs_mtd_drv_install(struct yaffs_dev *dev) ++{ ++ struct yaffs_driver *drv = &dev->drv; ++ ++ drv->drv_write_chunk_fn = yaffs_mtd_write; ++ drv->drv_read_chunk_fn = yaffs_mtd_read; ++ drv->drv_erase_fn = yaffs_mtd_erase; ++ drv->drv_mark_bad_fn = yaffs_mtd_mark_bad; ++ drv->drv_check_bad_fn = yaffs_mtd_check_bad; ++ drv->drv_initialise_fn = yaffs_mtd_initialise; ++ drv->drv_deinitialise_fn = yaffs_mtd_deinitialise; ++} ++ ++ ++struct mtd_info * yaffs_get_mtd_device(dev_t sdev) ++{ ++ struct mtd_info *mtd; ++ ++ mtd = yaffs_get_mtd_device(sdev); ++ ++ /* Check it's an mtd device..... */ ++ if (MAJOR(sdev) != MTD_BLOCK_MAJOR) ++ return NULL; /* This isn't an mtd device */ ++ ++ /* Check it's NAND */ ++ if (mtd->type != MTD_NANDFLASH) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs: MTD device is not NAND it's type %d", ++ mtd->type); ++ return NULL; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd)); ++ yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize); ++ yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) ++ yaffs_trace(YAFFS_TRACE_OS, " size %u", mtd->size); ++#else ++ yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size); ++#endif ++ ++ return mtd; ++} ++ ++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags) ++{ ++ if (yaffs_version == 2) { ++ if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || ++ mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) && ++ !inband_tags) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "MTD device does not have the right page sizes" ++ ); ++ return -1; ++ } ++ } else { ++ if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK || ++ mtd->oobsize != YAFFS_BYTES_PER_SPARE) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "MTD device does not support have the right page sizes" ++ ); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++ ++void yaffs_put_mtd_device(struct mtd_info *mtd) ++{ ++ if(mtd) ++ put_mtd_device(mtd); ++} +diff --git a/fs/yaffs2/yaffs_mtdif.h b/fs/yaffs2/yaffs_mtdif.h +new file mode 100644 +index 00000000..9cff224c +--- /dev/null ++++ b/fs/yaffs2/yaffs_mtdif.h +@@ -0,0 +1,25 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_MTDIF_H__ ++#define __YAFFS_MTDIF_H__ ++ ++#include "yaffs_guts.h" ++ ++void yaffs_mtd_drv_install(struct yaffs_dev *dev); ++struct mtd_info * yaffs_get_mtd_device(dev_t sdev); ++void yaffs_put_mtd_device(struct mtd_info *mtd); ++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags); ++#endif +diff --git a/fs/yaffs2/yaffs_nameval.c b/fs/yaffs2/yaffs_nameval.c +new file mode 100644 +index 00000000..4bdf4ed7 +--- /dev/null ++++ b/fs/yaffs2/yaffs_nameval.c +@@ -0,0 +1,208 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 simple implementation of a name-value store assumes a small number of ++* values and fits into a small finite buffer. ++ * ++ * Each attribute is stored as a record: ++ * sizeof(int) bytes record size. ++ * strnlen+1 bytes name null terminated. ++ * nbytes value. ++ * ---------- ++ * total size stored in record size ++ * ++ * This code has not been tested with unicode yet. ++ */ ++ ++#include "yaffs_nameval.h" ++ ++#include "yportenv.h" ++ ++static int nval_find(const char *xb, int xb_size, const YCHAR *name, ++ int *exist_size) ++{ ++ int pos = 0; ++ int size; ++ ++ memcpy(&size, xb, sizeof(int)); ++ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) { ++ if (!strncmp((YCHAR *) (xb + pos + sizeof(int)), ++ name, size)) { ++ if (exist_size) ++ *exist_size = size; ++ return pos; ++ } ++ pos += size; ++ if (pos < xb_size - sizeof(int)) ++ memcpy(&size, xb + pos, sizeof(int)); ++ else ++ size = 0; ++ } ++ if (exist_size) ++ *exist_size = 0; ++ return -ENODATA; ++} ++ ++static int nval_used(const char *xb, int xb_size) ++{ ++ int pos = 0; ++ int size; ++ ++ memcpy(&size, xb + pos, sizeof(int)); ++ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) { ++ pos += size; ++ if (pos < xb_size - sizeof(int)) ++ memcpy(&size, xb + pos, sizeof(int)); ++ else ++ size = 0; ++ } ++ return pos; ++} ++ ++int nval_del(char *xb, int xb_size, const YCHAR *name) ++{ ++ int pos = nval_find(xb, xb_size, name, NULL); ++ int size; ++ ++ if (pos < 0 || pos >= xb_size) ++ return -ENODATA; ++ ++ /* Find size, shift rest over this record, ++ * then zero out the rest of buffer */ ++ memcpy(&size, xb + pos, sizeof(int)); ++ memcpy(xb + pos, xb + pos + size, xb_size - (pos + size)); ++ memset(xb + (xb_size - size), 0, size); ++ return 0; ++} ++ ++int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, ++ int bsize, int flags) ++{ ++ int pos; ++ int namelen = strnlen(name, xb_size); ++ int reclen; ++ int size_exist = 0; ++ int space; ++ int start; ++ ++ pos = nval_find(xb, xb_size, name, &size_exist); ++ ++ if (flags & XATTR_CREATE && pos >= 0) ++ return -EEXIST; ++ if (flags & XATTR_REPLACE && pos < 0) ++ return -ENODATA; ++ ++ start = nval_used(xb, xb_size); ++ space = xb_size - start + size_exist; ++ ++ reclen = (sizeof(int) + namelen + 1 + bsize); ++ ++ if (reclen > space) ++ return -ENOSPC; ++ ++ if (pos >= 0) { ++ nval_del(xb, xb_size, name); ++ start = nval_used(xb, xb_size); ++ } ++ ++ pos = start; ++ ++ memcpy(xb + pos, &reclen, sizeof(int)); ++ pos += sizeof(int); ++ strncpy((YCHAR *) (xb + pos), name, reclen); ++ pos += (namelen + 1); ++ memcpy(xb + pos, buf, bsize); ++ return 0; ++} ++ ++int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf, ++ int bsize) ++{ ++ int pos = nval_find(xb, xb_size, name, NULL); ++ int size; ++ ++ if (pos >= 0 && pos < xb_size) { ++ ++ memcpy(&size, xb + pos, sizeof(int)); ++ pos += sizeof(int); /* advance past record length */ ++ size -= sizeof(int); ++ ++ /* Advance over name string */ ++ while (xb[pos] && size > 0 && pos < xb_size) { ++ pos++; ++ size--; ++ } ++ /*Advance over NUL */ ++ pos++; ++ size--; ++ ++ /* If bsize is zero then this is a size query. ++ * Return the size, but don't copy. ++ */ ++ if (!bsize) ++ return size; ++ ++ if (size <= bsize) { ++ memcpy(buf, xb + pos, size); ++ return size; ++ } ++ } ++ if (pos >= 0) ++ return -ERANGE; ++ ++ return -ENODATA; ++} ++ ++int nval_list(const char *xb, int xb_size, char *buf, int bsize) ++{ ++ int pos = 0; ++ int size; ++ int name_len; ++ int ncopied = 0; ++ int filled = 0; ++ ++ memcpy(&size, xb + pos, sizeof(int)); ++ while (size > sizeof(int) && ++ size <= xb_size && ++ (pos + size) < xb_size && ++ !filled) { ++ pos += sizeof(int); ++ size -= sizeof(int); ++ name_len = strnlen((YCHAR *) (xb + pos), size); ++ if (ncopied + name_len + 1 < bsize) { ++ memcpy(buf, xb + pos, name_len * sizeof(YCHAR)); ++ buf += name_len; ++ *buf = '\0'; ++ buf++; ++ if (sizeof(YCHAR) > 1) { ++ *buf = '\0'; ++ buf++; ++ } ++ ncopied += (name_len + 1); ++ } else { ++ filled = 1; ++ } ++ pos += size; ++ if (pos < xb_size - sizeof(int)) ++ memcpy(&size, xb + pos, sizeof(int)); ++ else ++ size = 0; ++ } ++ return ncopied; ++} ++ ++int nval_hasvalues(const char *xb, int xb_size) ++{ ++ return nval_used(xb, xb_size) > 0; ++} +diff --git a/fs/yaffs2/yaffs_nameval.h b/fs/yaffs2/yaffs_nameval.h +new file mode 100644 +index 00000000..951e64f8 +--- /dev/null ++++ b/fs/yaffs2/yaffs_nameval.h +@@ -0,0 +1,28 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __NAMEVAL_H__ ++#define __NAMEVAL_H__ ++ ++#include "yportenv.h" ++ ++int nval_del(char *xb, int xb_size, const YCHAR * name); ++int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf, ++ int bsize, int flags); ++int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf, ++ int bsize); ++int nval_list(const char *xb, int xb_size, char *buf, int bsize); ++int nval_hasvalues(const char *xb, int xb_size); ++#endif +diff --git a/fs/yaffs2/yaffs_nand.c b/fs/yaffs2/yaffs_nand.c +new file mode 100644 +index 00000000..0d8499bd +--- /dev/null ++++ b/fs/yaffs2/yaffs_nand.c +@@ -0,0 +1,122 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_nand.h" ++#include "yaffs_tagscompat.h" ++ ++#include "yaffs_getblockinfo.h" ++#include "yaffs_summary.h" ++ ++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk) ++{ ++ return chunk - dev->chunk_offset; ++} ++ ++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk, ++ u8 *buffer, struct yaffs_ext_tags *tags) ++{ ++ int result; ++ struct yaffs_ext_tags local_tags; ++ int flash_chunk = apply_chunk_offset(dev, nand_chunk); ++ ++ dev->n_page_reads++; ++ ++ /* If there are no tags provided use local tags. */ ++ if (!tags) ++ tags = &local_tags; ++ ++ result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags); ++ if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) { ++ ++ struct yaffs_block_info *bi; ++ bi = yaffs_get_block_info(dev, ++ nand_chunk / ++ dev->param.chunks_per_block); ++ yaffs_handle_chunk_error(dev, bi); ++ } ++ return result; ++} ++ ++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev, ++ int nand_chunk, ++ const u8 *buffer, struct yaffs_ext_tags *tags) ++{ ++ int result; ++ int flash_chunk = apply_chunk_offset(dev, nand_chunk); ++ ++ dev->n_page_writes++; ++ ++ if (!tags) { ++ yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags"); ++ BUG(); ++ return YAFFS_FAIL; ++ } ++ ++ tags->seq_number = dev->seq_number; ++ tags->chunk_used = 1; ++ yaffs_trace(YAFFS_TRACE_WRITE, ++ "Writing chunk %d tags %d %d", ++ nand_chunk, tags->obj_id, tags->chunk_id); ++ ++ result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk, ++ buffer, tags); ++ ++ yaffs_summary_add(dev, tags, nand_chunk); ++ ++ return result; ++} ++ ++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no) ++{ ++ block_no -= dev->block_offset; ++ dev->n_bad_markings++; ++ ++ if (dev->param.disable_bad_block_marking) ++ return YAFFS_OK; ++ ++ return dev->tagger.mark_bad_fn(dev, block_no); ++} ++ ++ ++int yaffs_query_init_block_state(struct yaffs_dev *dev, ++ int block_no, ++ enum yaffs_block_state *state, ++ u32 *seq_number) ++{ ++ block_no -= dev->block_offset; ++ return dev->tagger.query_block_fn(dev, block_no, state, seq_number); ++} ++ ++int yaffs_erase_block(struct yaffs_dev *dev, int block_no) ++{ ++ int result; ++ ++ block_no -= dev->block_offset; ++ dev->n_erasures++; ++ result = dev->drv.drv_erase_fn(dev, block_no); ++ return result; ++} ++ ++int yaffs_init_nand(struct yaffs_dev *dev) ++{ ++ if (dev->drv.drv_initialise_fn) ++ return dev->drv.drv_initialise_fn(dev); ++ return YAFFS_OK; ++} ++ ++int yaffs_deinit_nand(struct yaffs_dev *dev) ++{ ++ if (dev->drv.drv_deinitialise_fn) ++ return dev->drv.drv_deinitialise_fn(dev); ++ return YAFFS_OK; ++} +diff --git a/fs/yaffs2/yaffs_nand.h b/fs/yaffs2/yaffs_nand.h +new file mode 100644 +index 00000000..804e97ad +--- /dev/null ++++ b/fs/yaffs2/yaffs_nand.h +@@ -0,0 +1,39 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_NAND_H__ ++#define __YAFFS_NAND_H__ ++#include "yaffs_guts.h" ++ ++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk, ++ u8 *buffer, struct yaffs_ext_tags *tags); ++ ++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev, ++ int nand_chunk, ++ const u8 *buffer, struct yaffs_ext_tags *tags); ++ ++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no); ++ ++int yaffs_query_init_block_state(struct yaffs_dev *dev, ++ int block_no, ++ enum yaffs_block_state *state, ++ unsigned *seq_number); ++ ++int yaffs_erase_block(struct yaffs_dev *dev, int flash_block); ++ ++int yaffs_init_nand(struct yaffs_dev *dev); ++int yaffs_deinit_nand(struct yaffs_dev *dev); ++ ++#endif +diff --git a/fs/yaffs2/yaffs_packedtags1.c b/fs/yaffs2/yaffs_packedtags1.c +new file mode 100644 +index 00000000..dd9a331d +--- /dev/null ++++ b/fs/yaffs2/yaffs_packedtags1.c +@@ -0,0 +1,56 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_packedtags1.h" ++#include "yportenv.h" ++ ++static const u8 all_ff[20] = { ++ 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff ++}; ++ ++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt, ++ const struct yaffs_ext_tags *t) ++{ ++ pt->chunk_id = t->chunk_id; ++ pt->serial_number = t->serial_number; ++ pt->n_bytes = t->n_bytes; ++ pt->obj_id = t->obj_id; ++ pt->ecc = 0; ++ pt->deleted = (t->is_deleted) ? 0 : 1; ++ pt->unused_stuff = 0; ++ pt->should_be_ff = 0xffffffff; ++} ++ ++void yaffs_unpack_tags1(struct yaffs_ext_tags *t, ++ const struct yaffs_packed_tags1 *pt) ++{ ++ ++ if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) { ++ t->block_bad = 0; ++ if (pt->should_be_ff != 0xffffffff) ++ t->block_bad = 1; ++ t->chunk_used = 1; ++ t->obj_id = pt->obj_id; ++ t->chunk_id = pt->chunk_id; ++ t->n_bytes = pt->n_bytes; ++ t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR; ++ t->is_deleted = (pt->deleted) ? 0 : 1; ++ t->serial_number = pt->serial_number; ++ } else { ++ memset(t, 0, sizeof(struct yaffs_ext_tags)); ++ } ++} +diff --git a/fs/yaffs2/yaffs_packedtags1.h b/fs/yaffs2/yaffs_packedtags1.h +new file mode 100644 +index 00000000..3015d58a +--- /dev/null ++++ b/fs/yaffs2/yaffs_packedtags1.h +@@ -0,0 +1,39 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */ ++ ++#ifndef __YAFFS_PACKEDTAGS1_H__ ++#define __YAFFS_PACKEDTAGS1_H__ ++ ++#include "yaffs_guts.h" ++ ++struct yaffs_packed_tags1 { ++ u32 chunk_id:20; ++ u32 serial_number:2; ++ u32 n_bytes:10; ++ u32 obj_id:18; ++ u32 ecc:12; ++ u32 deleted:1; ++ u32 unused_stuff:1; ++ unsigned should_be_ff; ++ ++}; ++ ++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt, ++ const struct yaffs_ext_tags *t); ++void yaffs_unpack_tags1(struct yaffs_ext_tags *t, ++ const struct yaffs_packed_tags1 *pt); ++#endif +diff --git a/fs/yaffs2/yaffs_packedtags2.c b/fs/yaffs2/yaffs_packedtags2.c +new file mode 100644 +index 00000000..e1d18cc3 +--- /dev/null ++++ b/fs/yaffs2/yaffs_packedtags2.c +@@ -0,0 +1,197 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_packedtags2.h" ++#include "yportenv.h" ++#include "yaffs_trace.h" ++ ++/* This code packs a set of extended tags into a binary structure for ++ * NAND storage ++ */ ++ ++/* Some of the information is "extra" struff which can be packed in to ++ * speed scanning ++ * This is defined by having the EXTRA_HEADER_INFO_FLAG set. ++ */ ++ ++/* Extra flags applied to chunk_id */ ++ ++#define EXTRA_HEADER_INFO_FLAG 0x80000000 ++#define EXTRA_SHRINK_FLAG 0x40000000 ++#define EXTRA_SHADOWS_FLAG 0x20000000 ++#define EXTRA_SPARE_FLAGS 0x10000000 ++ ++#define ALL_EXTRA_FLAGS 0xf0000000 ++ ++/* Also, the top 4 bits of the object Id are set to the object type. */ ++#define EXTRA_OBJECT_TYPE_SHIFT (28) ++#define EXTRA_OBJECT_TYPE_MASK ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT) ++ ++static void yaffs_dump_packed_tags2_tags_only( ++ const struct yaffs_packed_tags2_tags_only *ptt) ++{ ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "packed tags obj %d chunk %d byte %d seq %d", ++ ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number); ++} ++ ++static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt) ++{ ++ yaffs_dump_packed_tags2_tags_only(&pt->t); ++} ++ ++static void yaffs_dump_tags2(const struct yaffs_ext_tags *t) ++{ ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d", ++ t->ecc_result, t->block_bad, t->chunk_used, t->obj_id, ++ t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number, ++ t->seq_number); ++ ++} ++ ++static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t) ++{ ++ if (t->chunk_id != 0 || !t->extra_available) ++ return 0; ++ ++ /* Check if the file size is too long to store */ ++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE && ++ (t->extra_file_size >> 31) != 0) ++ return 0; ++ return 1; ++} ++ ++void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt, ++ const struct yaffs_ext_tags *t) ++{ ++ ptt->chunk_id = t->chunk_id; ++ ptt->seq_number = t->seq_number; ++ ptt->n_bytes = t->n_bytes; ++ ptt->obj_id = t->obj_id; ++ ++ /* Only store extra tags for object headers. ++ * If it is a file then only store if the file size is short\ ++ * enough to fit. ++ */ ++ if (yaffs_check_tags_extra_packable(t)) { ++ /* Store the extra header info instead */ ++ /* We save the parent object in the chunk_id */ ++ ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id; ++ if (t->extra_is_shrink) ++ ptt->chunk_id |= EXTRA_SHRINK_FLAG; ++ if (t->extra_shadows) ++ ptt->chunk_id |= EXTRA_SHADOWS_FLAG; ++ ++ ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; ++ ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT); ++ ++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) ++ ptt->n_bytes = t->extra_equiv_id; ++ else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE) ++ ptt->n_bytes = (unsigned) t->extra_file_size; ++ else ++ ptt->n_bytes = 0; ++ } ++ ++ yaffs_dump_packed_tags2_tags_only(ptt); ++ yaffs_dump_tags2(t); ++} ++ ++void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt, ++ const struct yaffs_ext_tags *t, int tags_ecc) ++{ ++ yaffs_pack_tags2_tags_only(&pt->t, t); ++ ++ if (tags_ecc) ++ yaffs_ecc_calc_other((unsigned char *)&pt->t, ++ sizeof(struct yaffs_packed_tags2_tags_only), ++ &pt->ecc); ++} ++ ++void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t, ++ struct yaffs_packed_tags2_tags_only *ptt) ++{ ++ memset(t, 0, sizeof(struct yaffs_ext_tags)); ++ ++ if (ptt->seq_number == 0xffffffff) ++ return; ++ ++ t->block_bad = 0; ++ t->chunk_used = 1; ++ t->obj_id = ptt->obj_id; ++ t->chunk_id = ptt->chunk_id; ++ t->n_bytes = ptt->n_bytes; ++ t->is_deleted = 0; ++ t->serial_number = 0; ++ t->seq_number = ptt->seq_number; ++ ++ /* Do extra header info stuff */ ++ if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) { ++ t->chunk_id = 0; ++ t->n_bytes = 0; ++ ++ t->extra_available = 1; ++ t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS)); ++ t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0; ++ t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0; ++ t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT; ++ t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; ++ ++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) ++ t->extra_equiv_id = ptt->n_bytes; ++ else ++ t->extra_file_size = ptt->n_bytes; ++ } ++ yaffs_dump_packed_tags2_tags_only(ptt); ++ yaffs_dump_tags2(t); ++} ++ ++void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, ++ int tags_ecc) ++{ ++ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR; ++ ++ if (pt->t.seq_number != 0xffffffff && tags_ecc) { ++ /* Chunk is in use and we need to do ECC */ ++ ++ struct yaffs_ecc_other ecc; ++ int result; ++ yaffs_ecc_calc_other((unsigned char *)&pt->t, ++ sizeof(struct yaffs_packed_tags2_tags_only), ++ &ecc); ++ result = ++ yaffs_ecc_correct_other((unsigned char *)&pt->t, ++ sizeof(struct yaffs_packed_tags2_tags_only), ++ &pt->ecc, &ecc); ++ switch (result) { ++ case 0: ++ ecc_result = YAFFS_ECC_RESULT_NO_ERROR; ++ break; ++ case 1: ++ ecc_result = YAFFS_ECC_RESULT_FIXED; ++ break; ++ case -1: ++ ecc_result = YAFFS_ECC_RESULT_UNFIXED; ++ break; ++ default: ++ ecc_result = YAFFS_ECC_RESULT_UNKNOWN; ++ } ++ } ++ yaffs_unpack_tags2_tags_only(t, &pt->t); ++ ++ t->ecc_result = ecc_result; ++ ++ yaffs_dump_packed_tags2(pt); ++ yaffs_dump_tags2(t); ++} +diff --git a/fs/yaffs2/yaffs_packedtags2.h b/fs/yaffs2/yaffs_packedtags2.h +new file mode 100644 +index 00000000..675e7194 +--- /dev/null ++++ b/fs/yaffs2/yaffs_packedtags2.h +@@ -0,0 +1,47 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* This is used to pack YAFFS2 tags, not YAFFS1tags. */ ++ ++#ifndef __YAFFS_PACKEDTAGS2_H__ ++#define __YAFFS_PACKEDTAGS2_H__ ++ ++#include "yaffs_guts.h" ++#include "yaffs_ecc.h" ++ ++struct yaffs_packed_tags2_tags_only { ++ unsigned seq_number; ++ unsigned obj_id; ++ unsigned chunk_id; ++ unsigned n_bytes; ++}; ++ ++struct yaffs_packed_tags2 { ++ struct yaffs_packed_tags2_tags_only t; ++ struct yaffs_ecc_other ecc; ++}; ++ ++/* Full packed tags with ECC, used for oob tags */ ++void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt, ++ const struct yaffs_ext_tags *t, int tags_ecc); ++void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, ++ int tags_ecc); ++ ++/* Only the tags part (no ECC for use with inband tags */ ++void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt, ++ const struct yaffs_ext_tags *t); ++void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t, ++ struct yaffs_packed_tags2_tags_only *pt); ++#endif +diff --git a/fs/yaffs2/yaffs_summary.c b/fs/yaffs2/yaffs_summary.c +new file mode 100644 +index 00000000..3c9e7232 +--- /dev/null ++++ b/fs/yaffs2/yaffs_summary.c +@@ -0,0 +1,312 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++/* Summaries write the useful part of the tags for the chunks in a block into an ++ * an array which is written to the last n chunks of the block. ++ * Reading the summaries gives all the tags for the block in one read. Much ++ * faster. ++ * ++ * Chunks holding summaries are marked with tags making it look like ++ * they are part of a fake file. ++ * ++ * The summary could also be used during gc. ++ * ++ */ ++ ++#include "yaffs_summary.h" ++#include "yaffs_packedtags2.h" ++#include "yaffs_nand.h" ++#include "yaffs_getblockinfo.h" ++#include "yaffs_bitmap.h" ++ ++/* ++ * The summary is built up in an array of summary tags. ++ * This gets written to the last one or two (maybe more) chunks in a block. ++ * A summary header is written as the first part of each chunk of summary data. ++ * The summary header must match or the summary is rejected. ++ */ ++ ++/* Summary tags don't need the sequence number because that is redundant. */ ++struct yaffs_summary_tags { ++ unsigned obj_id; ++ unsigned chunk_id; ++ unsigned n_bytes; ++}; ++ ++/* Summary header */ ++struct yaffs_summary_header { ++ unsigned version; /* Must match current version */ ++ unsigned block; /* Must be this block */ ++ unsigned seq; /* Must be this sequence number */ ++ unsigned sum; /* Just add up all the bytes in the tags */ ++}; ++ ++ ++static void yaffs_summary_clear(struct yaffs_dev *dev) ++{ ++ if (!dev->sum_tags) ++ return; ++ memset(dev->sum_tags, 0, dev->chunks_per_summary * ++ sizeof(struct yaffs_summary_tags)); ++} ++ ++ ++void yaffs_summary_deinit(struct yaffs_dev *dev) ++{ ++ kfree(dev->sum_tags); ++ dev->sum_tags = NULL; ++ kfree(dev->gc_sum_tags); ++ dev->gc_sum_tags = NULL; ++ dev->chunks_per_summary = 0; ++} ++ ++int yaffs_summary_init(struct yaffs_dev *dev) ++{ ++ int sum_bytes; ++ int chunks_used; /* Number of chunks used by summary */ ++ int sum_tags_bytes; ++ ++ sum_bytes = dev->param.chunks_per_block * ++ sizeof(struct yaffs_summary_tags); ++ ++ chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/ ++ (dev->data_bytes_per_chunk - ++ sizeof(struct yaffs_summary_header)); ++ ++ dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used; ++ sum_tags_bytes = sizeof(struct yaffs_summary_tags) * ++ dev->chunks_per_summary; ++ dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS); ++ dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS); ++ if (!dev->sum_tags || !dev->gc_sum_tags) { ++ yaffs_summary_deinit(dev); ++ return YAFFS_FAIL; ++ } ++ ++ yaffs_summary_clear(dev); ++ ++ return YAFFS_OK; ++} ++ ++static unsigned yaffs_summary_sum(struct yaffs_dev *dev) ++{ ++ u8 *sum_buffer = (u8 *)dev->sum_tags; ++ int i; ++ unsigned sum = 0; ++ ++ i = sizeof(struct yaffs_summary_tags) * ++ dev->chunks_per_summary; ++ while (i > 0) { ++ sum += *sum_buffer; ++ sum_buffer++; ++ i--; ++ } ++ ++ return sum; ++} ++ ++static int yaffs_summary_write(struct yaffs_dev *dev, int blk) ++{ ++ struct yaffs_ext_tags tags; ++ u8 *buffer; ++ u8 *sum_buffer = (u8 *)dev->sum_tags; ++ int n_bytes; ++ int chunk_in_nand; ++ int chunk_in_block; ++ int result; ++ int this_tx; ++ struct yaffs_summary_header hdr; ++ int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr); ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk); ++ ++ buffer = yaffs_get_temp_buffer(dev); ++ n_bytes = sizeof(struct yaffs_summary_tags) * ++ dev->chunks_per_summary; ++ memset(&tags, 0, sizeof(struct yaffs_ext_tags)); ++ tags.obj_id = YAFFS_OBJECTID_SUMMARY; ++ tags.chunk_id = 1; ++ chunk_in_block = dev->chunks_per_summary; ++ chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block + ++ dev->chunks_per_summary; ++ hdr.version = YAFFS_SUMMARY_VERSION; ++ hdr.block = blk; ++ hdr.seq = bi->seq_number; ++ hdr.sum = yaffs_summary_sum(dev); ++ ++ do { ++ this_tx = n_bytes; ++ if (this_tx > sum_bytes_per_chunk) ++ this_tx = sum_bytes_per_chunk; ++ memcpy(buffer, &hdr, sizeof(hdr)); ++ memcpy(buffer + sizeof(hdr), sum_buffer, this_tx); ++ tags.n_bytes = this_tx + sizeof(hdr); ++ result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand, ++ buffer, &tags); ++ ++ if (result != YAFFS_OK) ++ break; ++ yaffs_set_chunk_bit(dev, blk, chunk_in_block); ++ bi->pages_in_use++; ++ dev->n_free_chunks--; ++ ++ n_bytes -= this_tx; ++ sum_buffer += this_tx; ++ chunk_in_nand++; ++ chunk_in_block++; ++ tags.chunk_id++; ++ } while (result == YAFFS_OK && n_bytes > 0); ++ yaffs_release_temp_buffer(dev, buffer); ++ ++ ++ if (result == YAFFS_OK) ++ bi->has_summary = 1; ++ ++ ++ return result; ++} ++ ++int yaffs_summary_read(struct yaffs_dev *dev, ++ struct yaffs_summary_tags *st, ++ int blk) ++{ ++ struct yaffs_ext_tags tags; ++ u8 *buffer; ++ u8 *sum_buffer = (u8 *)st; ++ int n_bytes; ++ int chunk_id; ++ int chunk_in_nand; ++ int chunk_in_block; ++ int result; ++ int this_tx; ++ struct yaffs_summary_header hdr; ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk); ++ int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr); ++ int sum_tags_bytes; ++ ++ sum_tags_bytes = sizeof(struct yaffs_summary_tags) * ++ dev->chunks_per_summary; ++ buffer = yaffs_get_temp_buffer(dev); ++ n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary; ++ chunk_in_block = dev->chunks_per_summary; ++ chunk_in_nand = blk * dev->param.chunks_per_block + ++ dev->chunks_per_summary; ++ chunk_id = 1; ++ do { ++ this_tx = n_bytes; ++ if (this_tx > sum_bytes_per_chunk) ++ this_tx = sum_bytes_per_chunk; ++ result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand, ++ buffer, &tags); ++ ++ if (tags.chunk_id != chunk_id || ++ tags.obj_id != YAFFS_OBJECTID_SUMMARY || ++ tags.chunk_used == 0 || ++ tags.ecc_result > YAFFS_ECC_RESULT_FIXED || ++ tags.n_bytes != (this_tx + sizeof(hdr))) ++ result = YAFFS_FAIL; ++ if (result != YAFFS_OK) ++ break; ++ ++ if (st == dev->sum_tags) { ++ /* If we're scanning then update the block info */ ++ yaffs_set_chunk_bit(dev, blk, chunk_in_block); ++ bi->pages_in_use++; ++ } ++ memcpy(&hdr, buffer, sizeof(hdr)); ++ memcpy(sum_buffer, buffer + sizeof(hdr), this_tx); ++ n_bytes -= this_tx; ++ sum_buffer += this_tx; ++ chunk_in_nand++; ++ chunk_in_block++; ++ chunk_id++; ++ } while (result == YAFFS_OK && n_bytes > 0); ++ yaffs_release_temp_buffer(dev, buffer); ++ ++ if (result == YAFFS_OK) { ++ /* Verify header */ ++ if (hdr.version != YAFFS_SUMMARY_VERSION || ++ hdr.seq != bi->seq_number || ++ hdr.sum != yaffs_summary_sum(dev)) ++ result = YAFFS_FAIL; ++ } ++ ++ if (st == dev->sum_tags && result == YAFFS_OK) ++ bi->has_summary = 1; ++ ++ return result; ++} ++ ++int yaffs_summary_add(struct yaffs_dev *dev, ++ struct yaffs_ext_tags *tags, ++ int chunk_in_nand) ++{ ++ struct yaffs_packed_tags2_tags_only tags_only; ++ struct yaffs_summary_tags *sum_tags; ++ int block_in_nand = chunk_in_nand / dev->param.chunks_per_block; ++ int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block; ++ ++ if (!dev->sum_tags) ++ return YAFFS_OK; ++ ++ if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) { ++ yaffs_pack_tags2_tags_only(&tags_only, tags); ++ sum_tags = &dev->sum_tags[chunk_in_block]; ++ sum_tags->chunk_id = tags_only.chunk_id; ++ sum_tags->n_bytes = tags_only.n_bytes; ++ sum_tags->obj_id = tags_only.obj_id; ++ ++ if (chunk_in_block == dev->chunks_per_summary - 1) { ++ /* Time to write out the summary */ ++ yaffs_summary_write(dev, block_in_nand); ++ yaffs_summary_clear(dev); ++ yaffs_skip_rest_of_block(dev); ++ } ++ } ++ return YAFFS_OK; ++} ++ ++int yaffs_summary_fetch(struct yaffs_dev *dev, ++ struct yaffs_ext_tags *tags, ++ int chunk_in_block) ++{ ++ struct yaffs_packed_tags2_tags_only tags_only; ++ struct yaffs_summary_tags *sum_tags; ++ if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) { ++ sum_tags = &dev->sum_tags[chunk_in_block]; ++ tags_only.chunk_id = sum_tags->chunk_id; ++ tags_only.n_bytes = sum_tags->n_bytes; ++ tags_only.obj_id = sum_tags->obj_id; ++ yaffs_unpack_tags2_tags_only(tags, &tags_only); ++ return YAFFS_OK; ++ } ++ return YAFFS_FAIL; ++} ++ ++void yaffs_summary_gc(struct yaffs_dev *dev, int blk) ++{ ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk); ++ int i; ++ ++ if (!bi->has_summary) ++ return; ++ ++ for (i = dev->chunks_per_summary; ++ i < dev->param.chunks_per_block; ++ i++) { ++ if (yaffs_check_chunk_bit(dev, blk, i)) { ++ yaffs_clear_chunk_bit(dev, blk, i); ++ bi->pages_in_use--; ++ dev->n_free_chunks++; ++ } ++ } ++} +diff --git a/fs/yaffs2/yaffs_summary.h b/fs/yaffs2/yaffs_summary.h +new file mode 100644 +index 00000000..be141d07 +--- /dev/null ++++ b/fs/yaffs2/yaffs_summary.h +@@ -0,0 +1,37 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_SUMMARY_H__ ++#define __YAFFS_SUMMARY_H__ ++ ++#include "yaffs_packedtags2.h" ++ ++ ++int yaffs_summary_init(struct yaffs_dev *dev); ++void yaffs_summary_deinit(struct yaffs_dev *dev); ++ ++int yaffs_summary_add(struct yaffs_dev *dev, ++ struct yaffs_ext_tags *tags, ++ int chunk_in_block); ++int yaffs_summary_fetch(struct yaffs_dev *dev, ++ struct yaffs_ext_tags *tags, ++ int chunk_in_block); ++int yaffs_summary_read(struct yaffs_dev *dev, ++ struct yaffs_summary_tags *st, ++ int blk); ++void yaffs_summary_gc(struct yaffs_dev *dev, int blk); ++ ++ ++#endif +diff --git a/fs/yaffs2/yaffs_tagscompat.c b/fs/yaffs2/yaffs_tagscompat.c +new file mode 100644 +index 00000000..092430be +--- /dev/null ++++ b/fs/yaffs2/yaffs_tagscompat.c +@@ -0,0 +1,381 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_guts.h" ++#include "yaffs_tagscompat.h" ++#include "yaffs_ecc.h" ++#include "yaffs_getblockinfo.h" ++#include "yaffs_trace.h" ++ ++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); ++ ++ ++/********** Tags ECC calculations *********/ ++ ++ ++void yaffs_calc_tags_ecc(struct yaffs_tags *tags) ++{ ++ /* Calculate an ecc */ ++ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes; ++ unsigned i, j; ++ unsigned ecc = 0; ++ unsigned bit = 0; ++ ++ tags->ecc = 0; ++ ++ for (i = 0; i < 8; i++) { ++ for (j = 1; j & 0xff; j <<= 1) { ++ bit++; ++ if (b[i] & j) ++ ecc ^= bit; ++ } ++ } ++ tags->ecc = ecc; ++} ++ ++int yaffs_check_tags_ecc(struct yaffs_tags *tags) ++{ ++ unsigned ecc = tags->ecc; ++ ++ yaffs_calc_tags_ecc(tags); ++ ++ ecc ^= tags->ecc; ++ ++ if (ecc && ecc <= 64) { ++ /* TODO: Handle the failure better. Retire? */ ++ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes; ++ ++ ecc--; ++ ++ b[ecc / 8] ^= (1 << (ecc & 7)); ++ ++ /* Now recvalc the ecc */ ++ yaffs_calc_tags_ecc(tags); ++ ++ return 1; /* recovered error */ ++ } else if (ecc) { ++ /* Wierd ecc failure value */ ++ /* TODO Need to do somethiong here */ ++ return -1; /* unrecovered error */ ++ } ++ return 0; ++} ++ ++/********** Tags **********/ ++ ++static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr, ++ struct yaffs_tags *tags_ptr) ++{ ++ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; ++ ++ yaffs_calc_tags_ecc(tags_ptr); ++ ++ spare_ptr->tb0 = tu->as_bytes[0]; ++ spare_ptr->tb1 = tu->as_bytes[1]; ++ spare_ptr->tb2 = tu->as_bytes[2]; ++ spare_ptr->tb3 = tu->as_bytes[3]; ++ spare_ptr->tb4 = tu->as_bytes[4]; ++ spare_ptr->tb5 = tu->as_bytes[5]; ++ spare_ptr->tb6 = tu->as_bytes[6]; ++ spare_ptr->tb7 = tu->as_bytes[7]; ++} ++ ++static void yaffs_get_tags_from_spare(struct yaffs_dev *dev, ++ struct yaffs_spare *spare_ptr, ++ struct yaffs_tags *tags_ptr) ++{ ++ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; ++ int result; ++ ++ tu->as_bytes[0] = spare_ptr->tb0; ++ tu->as_bytes[1] = spare_ptr->tb1; ++ tu->as_bytes[2] = spare_ptr->tb2; ++ tu->as_bytes[3] = spare_ptr->tb3; ++ tu->as_bytes[4] = spare_ptr->tb4; ++ tu->as_bytes[5] = spare_ptr->tb5; ++ tu->as_bytes[6] = spare_ptr->tb6; ++ tu->as_bytes[7] = spare_ptr->tb7; ++ ++ result = yaffs_check_tags_ecc(tags_ptr); ++ if (result > 0) ++ dev->n_tags_ecc_fixed++; ++ else if (result < 0) ++ dev->n_tags_ecc_unfixed++; ++} ++ ++static void yaffs_spare_init(struct yaffs_spare *spare) ++{ ++ memset(spare, 0xff, sizeof(struct yaffs_spare)); ++} ++ ++static int yaffs_wr_nand(struct yaffs_dev *dev, ++ int nand_chunk, const u8 *data, ++ struct yaffs_spare *spare) ++{ ++ int data_size = dev->data_bytes_per_chunk; ++ ++ return dev->drv.drv_write_chunk_fn(dev, nand_chunk, ++ data, data_size, ++ (u8 *) spare, sizeof(*spare)); ++} ++ ++static int yaffs_rd_chunk_nand(struct yaffs_dev *dev, ++ int nand_chunk, ++ u8 *data, ++ struct yaffs_spare *spare, ++ enum yaffs_ecc_result *ecc_result, ++ int correct_errors) ++{ ++ int ret_val; ++ struct yaffs_spare local_spare; ++ int data_size; ++ int spare_size; ++ int ecc_result1, ecc_result2; ++ u8 calc_ecc[3]; ++ ++ if (!spare) { ++ /* If we don't have a real spare, then we use a local one. */ ++ /* Need this for the calculation of the ecc */ ++ spare = &local_spare; ++ } ++ data_size = dev->data_bytes_per_chunk; ++ spare_size = sizeof(struct yaffs_spare); ++ ++ if (dev->param.use_nand_ecc) ++ return dev->drv.drv_read_chunk_fn(dev, nand_chunk, ++ data, data_size, ++ (u8 *) spare, spare_size, ++ ecc_result); ++ ++ ++ /* Handle the ECC at this level. */ ++ ++ ret_val = dev->drv.drv_read_chunk_fn(dev, nand_chunk, ++ data, data_size, ++ (u8 *)spare, spare_size, ++ NULL); ++ if (!data || !correct_errors) ++ return ret_val; ++ ++ /* Do ECC correction if needed. */ ++ yaffs_ecc_calc(data, calc_ecc); ++ ecc_result1 = yaffs_ecc_correct(data, spare->ecc1, calc_ecc); ++ yaffs_ecc_calc(&data[256], calc_ecc); ++ ecc_result2 = yaffs_ecc_correct(&data[256], spare->ecc2, calc_ecc); ++ ++ if (ecc_result1 > 0) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "**>>yaffs ecc error fix performed on chunk %d:0", ++ nand_chunk); ++ dev->n_ecc_fixed++; ++ } else if (ecc_result1 < 0) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "**>>yaffs ecc error unfixed on chunk %d:0", ++ nand_chunk); ++ dev->n_ecc_unfixed++; ++ } ++ ++ if (ecc_result2 > 0) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "**>>yaffs ecc error fix performed on chunk %d:1", ++ nand_chunk); ++ dev->n_ecc_fixed++; ++ } else if (ecc_result2 < 0) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "**>>yaffs ecc error unfixed on chunk %d:1", ++ nand_chunk); ++ dev->n_ecc_unfixed++; ++ } ++ ++ if (ecc_result1 || ecc_result2) { ++ /* We had a data problem on this page */ ++ yaffs_handle_rd_data_error(dev, nand_chunk); ++ } ++ ++ if (ecc_result1 < 0 || ecc_result2 < 0) ++ *ecc_result = YAFFS_ECC_RESULT_UNFIXED; ++ else if (ecc_result1 > 0 || ecc_result2 > 0) ++ *ecc_result = YAFFS_ECC_RESULT_FIXED; ++ else ++ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; ++ ++ return ret_val; ++} ++ ++/* ++ * Functions for robustisizing ++ */ ++ ++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk) ++{ ++ int flash_block = nand_chunk / dev->param.chunks_per_block; ++ ++ /* Mark the block for retirement */ ++ yaffs_get_block_info(dev, flash_block + dev->block_offset)-> ++ needs_retiring = 1; ++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, ++ "**>>Block %d marked for retirement", ++ flash_block); ++ ++ /* TODO: ++ * Just do a garbage collection on the affected block ++ * then retire the block ++ * NB recursion ++ */ ++} ++ ++static int yaffs_tags_compat_wr(struct yaffs_dev *dev, ++ int nand_chunk, ++ const u8 *data, const struct yaffs_ext_tags *ext_tags) ++{ ++ struct yaffs_spare spare; ++ struct yaffs_tags tags; ++ ++ yaffs_spare_init(&spare); ++ ++ if (ext_tags->is_deleted) ++ spare.page_status = 0; ++ else { ++ tags.obj_id = ext_tags->obj_id; ++ tags.chunk_id = ext_tags->chunk_id; ++ ++ tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1); ++ ++ if (dev->data_bytes_per_chunk >= 1024) ++ tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3; ++ else ++ tags.n_bytes_msb = 3; ++ ++ tags.serial_number = ext_tags->serial_number; ++ ++ if (!dev->param.use_nand_ecc && data) { ++ yaffs_ecc_calc(data, spare.ecc1); ++ yaffs_ecc_calc(&data[256], spare.ecc2); ++ } ++ ++ yaffs_load_tags_to_spare(&spare, &tags); ++ } ++ return yaffs_wr_nand(dev, nand_chunk, data, &spare); ++} ++ ++static int yaffs_tags_compat_rd(struct yaffs_dev *dev, ++ int nand_chunk, ++ u8 *data, struct yaffs_ext_tags *ext_tags) ++{ ++ struct yaffs_spare spare; ++ struct yaffs_tags tags; ++ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN; ++ static struct yaffs_spare spare_ff; ++ static int init; ++ int deleted; ++ ++ if (!init) { ++ memset(&spare_ff, 0xff, sizeof(spare_ff)); ++ init = 1; ++ } ++ ++ if (!yaffs_rd_chunk_nand(dev, nand_chunk, ++ data, &spare, &ecc_result, 1)) ++ return YAFFS_FAIL; ++ ++ /* ext_tags may be NULL */ ++ if (!ext_tags) ++ return YAFFS_OK; ++ ++ deleted = (hweight8(spare.page_status) < 7) ? 1 : 0; ++ ++ ext_tags->is_deleted = deleted; ++ ext_tags->ecc_result = ecc_result; ++ ext_tags->block_bad = 0; /* We're reading it */ ++ /* therefore it is not a bad block */ ++ ext_tags->chunk_used = ++ memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0; ++ ++ if (ext_tags->chunk_used) { ++ yaffs_get_tags_from_spare(dev, &spare, &tags); ++ ext_tags->obj_id = tags.obj_id; ++ ext_tags->chunk_id = tags.chunk_id; ++ ext_tags->n_bytes = tags.n_bytes_lsb; ++ ++ if (dev->data_bytes_per_chunk >= 1024) ++ ext_tags->n_bytes |= ++ (((unsigned)tags.n_bytes_msb) << 10); ++ ++ ext_tags->serial_number = tags.serial_number; ++ } ++ ++ return YAFFS_OK; ++} ++ ++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block) ++{ ++ struct yaffs_spare spare; ++ ++ memset(&spare, 0xff, sizeof(struct yaffs_spare)); ++ ++ spare.block_status = 'Y'; ++ ++ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL, ++ &spare); ++ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1, ++ NULL, &spare); ++ ++ return YAFFS_OK; ++} ++ ++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev, ++ int block_no, ++ enum yaffs_block_state *state, ++ u32 *seq_number) ++{ ++ struct yaffs_spare spare0, spare1; ++ static struct yaffs_spare spare_ff; ++ static int init; ++ enum yaffs_ecc_result dummy; ++ ++ if (!init) { ++ memset(&spare_ff, 0xff, sizeof(spare_ff)); ++ init = 1; ++ } ++ ++ *seq_number = 0; ++ ++ /* Look for bad block markers in the first two chunks */ ++ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, ++ NULL, &spare0, &dummy, 0); ++ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1, ++ NULL, &spare1, &dummy, 0); ++ ++ if (hweight8(spare0.block_status & spare1.block_status) < 7) ++ *state = YAFFS_BLOCK_STATE_DEAD; ++ else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0) ++ *state = YAFFS_BLOCK_STATE_EMPTY; ++ else ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; ++ ++ return YAFFS_OK; ++} ++ ++void yaffs_tags_compat_install(struct yaffs_dev *dev) ++{ ++ if(dev->param.is_yaffs2) ++ return; ++ if(!dev->tagger.write_chunk_tags_fn) ++ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_wr; ++ if(!dev->tagger.read_chunk_tags_fn) ++ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_rd; ++ if(!dev->tagger.query_block_fn) ++ dev->tagger.query_block_fn = yaffs_tags_compat_query_block; ++ if(!dev->tagger.mark_bad_fn) ++ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; ++} +diff --git a/fs/yaffs2/yaffs_tagscompat.h b/fs/yaffs2/yaffs_tagscompat.h +new file mode 100644 +index 00000000..92d298a6 +--- /dev/null ++++ b/fs/yaffs2/yaffs_tagscompat.h +@@ -0,0 +1,44 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_TAGSCOMPAT_H__ ++#define __YAFFS_TAGSCOMPAT_H__ ++ ++ ++#include "yaffs_guts.h" ++ ++#if 0 ++ ++ ++int yaffs_tags_compat_wr(struct yaffs_dev *dev, ++ int nand_chunk, ++ const u8 *data, const struct yaffs_ext_tags *tags); ++int yaffs_tags_compat_rd(struct yaffs_dev *dev, ++ int nand_chunk, ++ u8 *data, struct yaffs_ext_tags *tags); ++int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no); ++int yaffs_tags_compat_query_block(struct yaffs_dev *dev, ++ int block_no, ++ enum yaffs_block_state *state, ++ u32 *seq_number); ++ ++#endif ++ ++ ++void yaffs_tags_compat_install(struct yaffs_dev *dev); ++void yaffs_calc_tags_ecc(struct yaffs_tags *tags); ++int yaffs_check_tags_ecc(struct yaffs_tags *tags); ++ ++#endif +diff --git a/fs/yaffs2/yaffs_tagsmarshall.c b/fs/yaffs2/yaffs_tagsmarshall.c +new file mode 100644 +index 00000000..44a83b12 +--- /dev/null ++++ b/fs/yaffs2/yaffs_tagsmarshall.c +@@ -0,0 +1,199 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_guts.h" ++#include "yaffs_trace.h" ++#include "yaffs_packedtags2.h" ++ ++static int yaffs_tags_marshall_write(struct yaffs_dev *dev, ++ int nand_chunk, const u8 *data, ++ const struct yaffs_ext_tags *tags) ++{ ++ struct yaffs_packed_tags2 pt; ++ int retval; ++ ++ int packed_tags_size = ++ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt); ++ void *packed_tags_ptr = ++ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt; ++ ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "yaffs_tags_marshall_write chunk %d data %p tags %p", ++ nand_chunk, data, tags); ++ ++ /* For yaffs2 writing there must be both data and tags. ++ * If we're using inband tags, then the tags are stuffed into ++ * the end of the data buffer. ++ */ ++ if (!data || !tags) ++ BUG(); ++ else if (dev->param.inband_tags) { ++ struct yaffs_packed_tags2_tags_only *pt2tp; ++ pt2tp = ++ (struct yaffs_packed_tags2_tags_only *)(data + ++ dev-> ++ data_bytes_per_chunk); ++ yaffs_pack_tags2_tags_only(pt2tp, tags); ++ } else { ++ yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc); ++ } ++ ++ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk, ++ data, dev->param.total_bytes_per_chunk, ++ (dev->param.inband_tags) ? NULL : packed_tags_ptr, ++ (dev->param.inband_tags) ? 0 : packed_tags_size); ++ ++ return retval; ++} ++ ++static int yaffs_tags_marshall_read(struct yaffs_dev *dev, ++ int nand_chunk, u8 *data, ++ struct yaffs_ext_tags *tags) ++{ ++ int retval = 0; ++ int local_data = 0; ++ u8 spare_buffer[100]; ++ enum yaffs_ecc_result ecc_result; ++ ++ struct yaffs_packed_tags2 pt; ++ ++ int packed_tags_size = ++ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt); ++ void *packed_tags_ptr = ++ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt; ++ ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "yaffs_tags_marshall_read chunk %d data %p tags %p", ++ nand_chunk, data, tags); ++ ++ if (dev->param.inband_tags) { ++ if (!data) { ++ local_data = 1; ++ data = yaffs_get_temp_buffer(dev); ++ } ++ } ++ ++ if (dev->param.inband_tags || (data && !tags)) ++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, ++ data, dev->param.total_bytes_per_chunk, ++ NULL, 0, ++ &ecc_result); ++ else if (tags) ++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, ++ data, dev->param.total_bytes_per_chunk, ++ spare_buffer, packed_tags_size, ++ &ecc_result); ++ else ++ BUG(); ++ ++ ++ if (dev->param.inband_tags) { ++ if (tags) { ++ struct yaffs_packed_tags2_tags_only *pt2tp; ++ pt2tp = ++ (struct yaffs_packed_tags2_tags_only *) ++ &data[dev->data_bytes_per_chunk]; ++ yaffs_unpack_tags2_tags_only(tags, pt2tp); ++ } ++ } else if (tags) { ++ memcpy(packed_tags_ptr, spare_buffer, packed_tags_size); ++ yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc); ++ } ++ ++ if (local_data) ++ yaffs_release_temp_buffer(dev, data); ++ ++ if (tags && ecc_result == YAFFS_ECC_RESULT_UNFIXED) { ++ tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED; ++ dev->n_ecc_unfixed++; ++ } ++ ++ if (tags && ecc_result == -YAFFS_ECC_RESULT_FIXED) { ++ if (tags->ecc_result <= YAFFS_ECC_RESULT_NO_ERROR) ++ tags->ecc_result = YAFFS_ECC_RESULT_FIXED; ++ dev->n_ecc_fixed++; ++ } ++ ++ if (ecc_result < YAFFS_ECC_RESULT_UNFIXED) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++} ++ ++static int yaffs_tags_marshall_query_block(struct yaffs_dev *dev, int block_no, ++ enum yaffs_block_state *state, ++ u32 *seq_number) ++{ ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_MTD, "yaffs_tags_marshall_query_block %d", ++ block_no); ++ ++ retval = dev->drv.drv_check_bad_fn(dev, block_no); ++ ++ if (retval== YAFFS_FAIL) { ++ yaffs_trace(YAFFS_TRACE_MTD, "block is bad"); ++ ++ *state = YAFFS_BLOCK_STATE_DEAD; ++ *seq_number = 0; ++ } else { ++ struct yaffs_ext_tags t; ++ ++ yaffs_tags_marshall_read(dev, ++ block_no * dev->param.chunks_per_block, ++ NULL, &t); ++ ++ if (t.chunk_used) { ++ *seq_number = t.seq_number; ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; ++ } else { ++ *seq_number = 0; ++ *state = YAFFS_BLOCK_STATE_EMPTY; ++ } ++ } ++ ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "block query returns seq %d state %d", ++ *seq_number, *state); ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++} ++ ++static int yaffs_tags_marshall_mark_bad(struct yaffs_dev *dev, int block_no) ++{ ++ return dev->drv.drv_mark_bad_fn(dev, block_no); ++ ++} ++ ++ ++void yaffs_tags_marshall_install(struct yaffs_dev *dev) ++{ ++ if (!dev->param.is_yaffs2) ++ return; ++ ++ if (!dev->tagger.write_chunk_tags_fn) ++ dev->tagger.write_chunk_tags_fn = yaffs_tags_marshall_write; ++ ++ if (!dev->tagger.read_chunk_tags_fn) ++ dev->tagger.read_chunk_tags_fn = yaffs_tags_marshall_read; ++ ++ if (!dev->tagger.query_block_fn) ++ dev->tagger.query_block_fn = yaffs_tags_marshall_query_block; ++ ++ if (!dev->tagger.mark_bad_fn) ++ dev->tagger.mark_bad_fn = yaffs_tags_marshall_mark_bad; ++ ++} +diff --git a/fs/yaffs2/yaffs_tagsmarshall.h b/fs/yaffs2/yaffs_tagsmarshall.h +new file mode 100644 +index 00000000..bf3e68a1 +--- /dev/null ++++ b/fs/yaffs2/yaffs_tagsmarshall.h +@@ -0,0 +1,22 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_TAGSMARSHALL_H__ ++#define __YAFFS_TAGSMARSHALL_H__ ++ ++#include "yaffs_guts.h" ++void yaffs_tags_marshall_install(struct yaffs_dev *dev); ++ ++#endif +diff --git a/fs/yaffs2/yaffs_trace.h b/fs/yaffs2/yaffs_trace.h +new file mode 100644 +index 00000000..fd26054d +--- /dev/null ++++ b/fs/yaffs2/yaffs_trace.h +@@ -0,0 +1,57 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YTRACE_H__ ++#define __YTRACE_H__ ++ ++extern unsigned int yaffs_trace_mask; ++extern unsigned int yaffs_wr_attempts; ++ ++/* ++ * Tracing flags. ++ * The flags masked in YAFFS_TRACE_ALWAYS are always traced. ++ */ ++ ++#define YAFFS_TRACE_OS 0x00000002 ++#define YAFFS_TRACE_ALLOCATE 0x00000004 ++#define YAFFS_TRACE_SCAN 0x00000008 ++#define YAFFS_TRACE_BAD_BLOCKS 0x00000010 ++#define YAFFS_TRACE_ERASE 0x00000020 ++#define YAFFS_TRACE_GC 0x00000040 ++#define YAFFS_TRACE_WRITE 0x00000080 ++#define YAFFS_TRACE_TRACING 0x00000100 ++#define YAFFS_TRACE_DELETION 0x00000200 ++#define YAFFS_TRACE_BUFFERS 0x00000400 ++#define YAFFS_TRACE_NANDACCESS 0x00000800 ++#define YAFFS_TRACE_GC_DETAIL 0x00001000 ++#define YAFFS_TRACE_SCAN_DEBUG 0x00002000 ++#define YAFFS_TRACE_MTD 0x00004000 ++#define YAFFS_TRACE_CHECKPOINT 0x00008000 ++ ++#define YAFFS_TRACE_VERIFY 0x00010000 ++#define YAFFS_TRACE_VERIFY_NAND 0x00020000 ++#define YAFFS_TRACE_VERIFY_FULL 0x00040000 ++#define YAFFS_TRACE_VERIFY_ALL 0x000f0000 ++ ++#define YAFFS_TRACE_SYNC 0x00100000 ++#define YAFFS_TRACE_BACKGROUND 0x00200000 ++#define YAFFS_TRACE_LOCK 0x00400000 ++#define YAFFS_TRACE_MOUNT 0x00800000 ++ ++#define YAFFS_TRACE_ERROR 0x40000000 ++#define YAFFS_TRACE_BUG 0x80000000 ++#define YAFFS_TRACE_ALWAYS 0xf0000000 ++ ++#endif +diff --git a/fs/yaffs2/yaffs_verify.c b/fs/yaffs2/yaffs_verify.c +new file mode 100644 +index 00000000..e8f2f0a6 +--- /dev/null ++++ b/fs/yaffs2/yaffs_verify.c +@@ -0,0 +1,529 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_verify.h" ++#include "yaffs_trace.h" ++#include "yaffs_bitmap.h" ++#include "yaffs_getblockinfo.h" ++#include "yaffs_nand.h" ++ ++int yaffs_skip_verification(struct yaffs_dev *dev) ++{ ++ (void) dev; ++ return !(yaffs_trace_mask & ++ (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); ++} ++ ++static int yaffs_skip_full_verification(struct yaffs_dev *dev) ++{ ++ (void) dev; ++ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL)); ++} ++ ++static int yaffs_skip_nand_verification(struct yaffs_dev *dev) ++{ ++ (void) dev; ++ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND)); ++} ++ ++static const char * const block_state_name[] = { ++ "Unknown", ++ "Needs scan", ++ "Scanning", ++ "Empty", ++ "Allocating", ++ "Full", ++ "Dirty", ++ "Checkpoint", ++ "Collecting", ++ "Dead" ++}; ++ ++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n) ++{ ++ int actually_used; ++ int in_use; ++ ++ if (yaffs_skip_verification(dev)) ++ return; ++ ++ /* Report illegal runtime states */ ++ if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Block %d has undefined state %d", ++ n, bi->block_state); ++ ++ switch (bi->block_state) { ++ case YAFFS_BLOCK_STATE_UNKNOWN: ++ case YAFFS_BLOCK_STATE_SCANNING: ++ case YAFFS_BLOCK_STATE_NEEDS_SCAN: ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Block %d has bad run-state %s", ++ n, block_state_name[bi->block_state]); ++ } ++ ++ /* Check pages in use and soft deletions are legal */ ++ ++ actually_used = bi->pages_in_use - bi->soft_del_pages; ++ ++ if (bi->pages_in_use < 0 || ++ bi->pages_in_use > dev->param.chunks_per_block || ++ bi->soft_del_pages < 0 || ++ bi->soft_del_pages > dev->param.chunks_per_block || ++ actually_used < 0 || actually_used > dev->param.chunks_per_block) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Block %d has illegal values pages_in_used %d soft_del_pages %d", ++ n, bi->pages_in_use, bi->soft_del_pages); ++ ++ /* Check chunk bitmap legal */ ++ in_use = yaffs_count_chunk_bits(dev, n); ++ if (in_use != bi->pages_in_use) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Block %d has inconsistent values pages_in_use %d counted chunk bits %d", ++ n, bi->pages_in_use, in_use); ++} ++ ++void yaffs_verify_collected_blk(struct yaffs_dev *dev, ++ struct yaffs_block_info *bi, int n) ++{ ++ yaffs_verify_blk(dev, bi, n); ++ ++ /* After collection the block should be in the erased state */ ++ ++ if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING && ++ bi->block_state != YAFFS_BLOCK_STATE_EMPTY) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "Block %d is in state %d after gc, should be erased", ++ n, bi->block_state); ++ } ++} ++ ++void yaffs_verify_blocks(struct yaffs_dev *dev) ++{ ++ int i; ++ int state_count[YAFFS_NUMBER_OF_BLOCK_STATES]; ++ int illegal_states = 0; ++ ++ if (yaffs_skip_verification(dev)) ++ return; ++ ++ memset(state_count, 0, sizeof(state_count)); ++ ++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i); ++ yaffs_verify_blk(dev, bi, i); ++ ++ if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES) ++ state_count[bi->block_state]++; ++ else ++ illegal_states++; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary"); ++ ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "%d blocks have illegal states", ++ illegal_states); ++ if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Too many allocating blocks"); ++ ++ for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "%s %d blocks", ++ block_state_name[i], state_count[i]); ++ ++ if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT]) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Checkpoint block count wrong dev %d count %d", ++ dev->blocks_in_checkpt, ++ state_count[YAFFS_BLOCK_STATE_CHECKPOINT]); ++ ++ if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY]) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Erased block count wrong dev %d count %d", ++ dev->n_erased_blocks, ++ state_count[YAFFS_BLOCK_STATE_EMPTY]); ++ ++ if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Too many collecting blocks %d (max is 1)", ++ state_count[YAFFS_BLOCK_STATE_COLLECTING]); ++} ++ ++/* ++ * Verify the object header. oh must be valid, but obj and tags may be NULL in ++ * which case those tests will not be performed. ++ */ ++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh, ++ struct yaffs_ext_tags *tags, int parent_check) ++{ ++ if (obj && yaffs_skip_verification(obj->my_dev)) ++ return; ++ ++ if (!(tags && obj && oh)) { ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Verifying object header tags %p obj %p oh %p", ++ tags, obj, oh); ++ return; ++ } ++ ++ if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || ++ oh->type > YAFFS_OBJECT_TYPE_MAX) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d header type is illegal value 0x%x", ++ tags->obj_id, oh->type); ++ ++ if (tags->obj_id != obj->obj_id) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d header mismatch obj_id %d", ++ tags->obj_id, obj->obj_id); ++ ++ /* ++ * Check that the object's parent ids match if parent_check requested. ++ * ++ * Tests do not apply to the root object. ++ */ ++ ++ if (parent_check && tags->obj_id > 1 && !obj->parent) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d header mismatch parent_id %d obj->parent is NULL", ++ tags->obj_id, oh->parent_obj_id); ++ ++ if (parent_check && obj->parent && ++ oh->parent_obj_id != obj->parent->obj_id && ++ (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED || ++ obj->parent->obj_id != YAFFS_OBJECTID_DELETED)) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d header mismatch parent_id %d parent_obj_id %d", ++ tags->obj_id, oh->parent_obj_id, ++ obj->parent->obj_id); ++ ++ if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */ ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d header name is NULL", ++ obj->obj_id); ++ ++ if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Junk name */ ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d header name is 0xff", ++ obj->obj_id); ++} ++ ++void yaffs_verify_file(struct yaffs_obj *obj) ++{ ++ u32 x; ++ int required_depth; ++ int actual_depth; ++ int last_chunk; ++ u32 offset_in_chunk; ++ u32 the_chunk; ++ ++ u32 i; ++ struct yaffs_dev *dev; ++ struct yaffs_ext_tags tags; ++ struct yaffs_tnode *tn; ++ u32 obj_id; ++ ++ if (!obj) ++ return; ++ ++ if (yaffs_skip_verification(obj->my_dev)) ++ return; ++ ++ dev = obj->my_dev; ++ obj_id = obj->obj_id; ++ ++ ++ /* Check file size is consistent with tnode depth */ ++ yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size, ++ &last_chunk, &offset_in_chunk); ++ last_chunk++; ++ x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS; ++ required_depth = 0; ++ while (x > 0) { ++ x >>= YAFFS_TNODES_INTERNAL_BITS; ++ required_depth++; ++ } ++ ++ actual_depth = obj->variant.file_variant.top_level; ++ ++ /* Check that the chunks in the tnode tree are all correct. ++ * We do this by scanning through the tnode tree and ++ * checking the tags for every chunk match. ++ */ ++ ++ if (yaffs_skip_nand_verification(dev)) ++ return; ++ ++ for (i = 1; i <= last_chunk; i++) { ++ tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i); ++ ++ if (!tn) ++ continue; ++ ++ the_chunk = yaffs_get_group_base(dev, tn, i); ++ if (the_chunk > 0) { ++ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL, ++ &tags); ++ if (tags.obj_id != obj_id || tags.chunk_id != i) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)", ++ obj_id, i, the_chunk, ++ tags.obj_id, tags.chunk_id); ++ } ++ } ++} ++ ++void yaffs_verify_link(struct yaffs_obj *obj) ++{ ++ if (obj && yaffs_skip_verification(obj->my_dev)) ++ return; ++ ++ /* Verify sane equivalent object */ ++} ++ ++void yaffs_verify_symlink(struct yaffs_obj *obj) ++{ ++ if (obj && yaffs_skip_verification(obj->my_dev)) ++ return; ++ ++ /* Verify symlink string */ ++} ++ ++void yaffs_verify_special(struct yaffs_obj *obj) ++{ ++ if (obj && yaffs_skip_verification(obj->my_dev)) ++ return; ++} ++ ++void yaffs_verify_obj(struct yaffs_obj *obj) ++{ ++ struct yaffs_dev *dev; ++ u32 chunk_min; ++ u32 chunk_max; ++ u32 chunk_id_ok; ++ u32 chunk_in_range; ++ u32 chunk_wrongly_deleted; ++ u32 chunk_valid; ++ ++ if (!obj) ++ return; ++ ++ if (obj->being_created) ++ return; ++ ++ dev = obj->my_dev; ++ ++ if (yaffs_skip_verification(dev)) ++ return; ++ ++ /* Check sane object header chunk */ ++ ++ chunk_min = dev->internal_start_block * dev->param.chunks_per_block; ++ chunk_max = ++ (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1; ++ ++ chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min && ++ ((unsigned)(obj->hdr_chunk)) <= chunk_max); ++ chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0); ++ chunk_valid = chunk_in_range && ++ yaffs_check_chunk_bit(dev, ++ obj->hdr_chunk / dev->param.chunks_per_block, ++ obj->hdr_chunk % dev->param.chunks_per_block); ++ chunk_wrongly_deleted = chunk_in_range && !chunk_valid; ++ ++ if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted)) ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d has chunk_id %d %s %s", ++ obj->obj_id, obj->hdr_chunk, ++ chunk_id_ok ? "" : ",out of range", ++ chunk_wrongly_deleted ? ",marked as deleted" : ""); ++ ++ if (chunk_valid && !yaffs_skip_nand_verification(dev)) { ++ struct yaffs_ext_tags tags; ++ struct yaffs_obj_hdr *oh; ++ u8 *buffer = yaffs_get_temp_buffer(dev); ++ ++ oh = (struct yaffs_obj_hdr *)buffer; ++ ++ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags); ++ ++ yaffs_verify_oh(obj, oh, &tags, 1); ++ ++ yaffs_release_temp_buffer(dev, buffer); ++ } ++ ++ /* Verify it has a parent */ ++ if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) { ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d has parent pointer %p which does not look like an object", ++ obj->obj_id, obj->parent); ++ } ++ ++ /* Verify parent is a directory */ ++ if (obj->parent && ++ obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d's parent is not a directory (type %d)", ++ obj->obj_id, obj->parent->variant_type); ++ } ++ ++ switch (obj->variant_type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ yaffs_verify_file(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ yaffs_verify_symlink(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ yaffs_verify_dir(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ yaffs_verify_link(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ yaffs_verify_special(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ default: ++ yaffs_trace(YAFFS_TRACE_VERIFY, ++ "Obj %d has illegaltype %d", ++ obj->obj_id, obj->variant_type); ++ break; ++ } ++} ++ ++void yaffs_verify_objects(struct yaffs_dev *dev) ++{ ++ struct yaffs_obj *obj; ++ int i; ++ struct list_head *lh; ++ ++ if (yaffs_skip_verification(dev)) ++ return; ++ ++ /* Iterate through the objects in each hash entry */ ++ ++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { ++ list_for_each(lh, &dev->obj_bucket[i].list) { ++ obj = list_entry(lh, struct yaffs_obj, hash_link); ++ yaffs_verify_obj(obj); ++ } ++ } ++} ++ ++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj) ++{ ++ struct list_head *lh; ++ struct yaffs_obj *list_obj; ++ int count = 0; ++ ++ if (!obj) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify"); ++ BUG(); ++ return; ++ } ++ ++ if (yaffs_skip_verification(obj->my_dev)) ++ return; ++ ++ if (!obj->parent) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent"); ++ BUG(); ++ return; ++ } ++ ++ if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory"); ++ BUG(); ++ } ++ ++ /* Iterate through the objects in each hash entry */ ++ ++ list_for_each(lh, &obj->parent->variant.dir_variant.children) { ++ list_obj = list_entry(lh, struct yaffs_obj, siblings); ++ yaffs_verify_obj(list_obj); ++ if (obj == list_obj) ++ count++; ++ } ++ ++ if (count != 1) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "Object in directory %d times", ++ count); ++ BUG(); ++ } ++} ++ ++void yaffs_verify_dir(struct yaffs_obj *directory) ++{ ++ struct list_head *lh; ++ struct yaffs_obj *list_obj; ++ ++ if (!directory) { ++ BUG(); ++ return; ++ } ++ ++ if (yaffs_skip_full_verification(directory->my_dev)) ++ return; ++ ++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "Directory has wrong type: %d", ++ directory->variant_type); ++ BUG(); ++ } ++ ++ /* Iterate through the objects in each hash entry */ ++ ++ list_for_each(lh, &directory->variant.dir_variant.children) { ++ list_obj = list_entry(lh, struct yaffs_obj, siblings); ++ if (list_obj->parent != directory) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "Object in directory list has wrong parent %p", ++ list_obj->parent); ++ BUG(); ++ } ++ yaffs_verify_obj_in_dir(list_obj); ++ } ++} ++ ++static int yaffs_free_verification_failures; ++ ++void yaffs_verify_free_chunks(struct yaffs_dev *dev) ++{ ++ int counted; ++ int difference; ++ ++ if (yaffs_skip_verification(dev)) ++ return; ++ ++ counted = yaffs_count_free_chunks(dev); ++ ++ difference = dev->n_free_chunks - counted; ++ ++ if (difference) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "Freechunks verification failure %d %d %d", ++ dev->n_free_chunks, counted, difference); ++ yaffs_free_verification_failures++; ++ } ++} ++ ++int yaffs_verify_file_sane(struct yaffs_obj *in) ++{ ++ (void) in; ++ return YAFFS_OK; ++} +diff --git a/fs/yaffs2/yaffs_verify.h b/fs/yaffs2/yaffs_verify.h +new file mode 100644 +index 00000000..4f4af8d2 +--- /dev/null ++++ b/fs/yaffs2/yaffs_verify.h +@@ -0,0 +1,43 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_VERIFY_H__ ++#define __YAFFS_VERIFY_H__ ++ ++#include "yaffs_guts.h" ++ ++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, ++ int n); ++void yaffs_verify_collected_blk(struct yaffs_dev *dev, ++ struct yaffs_block_info *bi, int n); ++void yaffs_verify_blocks(struct yaffs_dev *dev); ++ ++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh, ++ struct yaffs_ext_tags *tags, int parent_check); ++void yaffs_verify_file(struct yaffs_obj *obj); ++void yaffs_verify_link(struct yaffs_obj *obj); ++void yaffs_verify_symlink(struct yaffs_obj *obj); ++void yaffs_verify_special(struct yaffs_obj *obj); ++void yaffs_verify_obj(struct yaffs_obj *obj); ++void yaffs_verify_objects(struct yaffs_dev *dev); ++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj); ++void yaffs_verify_dir(struct yaffs_obj *directory); ++void yaffs_verify_free_chunks(struct yaffs_dev *dev); ++ ++int yaffs_verify_file_sane(struct yaffs_obj *obj); ++ ++int yaffs_skip_verification(struct yaffs_dev *dev); ++ ++#endif +diff --git a/fs/yaffs2/yaffs_vfs.c b/fs/yaffs2/yaffs_vfs.c +new file mode 100644 +index 00000000..4621043e +--- /dev/null ++++ b/fs/yaffs2/yaffs_vfs.c +@@ -0,0 +1,3458 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * Acknowledgements: ++ * Luc van OostenRyck for numerous patches. ++ * Nick Bane for numerous patches. ++ * Nick Bane for 2.5/2.6 integration. ++ * Andras Toth for mknod rdev issue. ++ * Michael Fischer for finding the problem with inode inconsistency. ++ * Some code bodily lifted from JFFS ++ * ++ * 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 is the file system front-end to YAFFS that hooks it up to ++ * the VFS. ++ * ++ * Special notes: ++ * >> 2.4: sb->u.generic_sbp points to the struct yaffs_dev associated with ++ * this superblock ++ * >> 2.6: sb->s_fs_info points to the struct yaffs_dev associated with this ++ * superblock ++ * >> inode->u.generic_ip points to the associated struct yaffs_obj. ++ */ ++ ++/* ++ * There are two variants of the VFS glue code. This variant should compile ++ * for any version of Linux. ++ */ ++#include ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)) ++#define YAFFS_COMPILE_BACKGROUND ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)) ++#define YAFFS_COMPILE_FREEZER ++#endif ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) ++#define YAFFS_COMPILE_EXPORTFS ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) ++#define YAFFS_USE_SETATTR_COPY ++#define YAFFS_USE_TRUNCATE_SETSIZE ++#endif ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) ++#define YAFFS_HAS_EVICT_INODE ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) ++#define YAFFS_NEW_FOLLOW_LINK 1 ++#else ++#define YAFFS_NEW_FOLLOW_LINK 0 ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) ++#define YAFFS_HAS_WRITE_SUPER ++#endif ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)) ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++ ++#if (YAFFS_NEW_FOLLOW_LINK == 1) ++#include ++#endif ++ ++#ifdef YAFFS_COMPILE_EXPORTFS ++#include ++#endif ++ ++#ifdef YAFFS_COMPILE_BACKGROUND ++#include ++#include ++#endif ++#ifdef YAFFS_COMPILE_FREEZER ++#include ++#endif ++ ++#include ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ ++#include ++ ++#define UnlockPage(p) unlock_page(p) ++#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags) ++ ++/* FIXME: use sb->s_id instead ? */ ++#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf) ++ ++#else ++ ++#include ++#define BDEVNAME_SIZE 0 ++#define yaffs_devname(sb, buf) kdevname(sb->s_dev) ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)) ++/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */ ++#define __user ++#endif ++ ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)) ++#define YPROC_ROOT (&proc_root) ++#else ++#define YPROC_ROOT NULL ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)) ++#define Y_INIT_TIMER(a) init_timer(a) ++#else ++#define Y_INIT_TIMER(a) init_timer_on_stack(a) ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27)) ++#define YAFFS_USE_WRITE_BEGIN_END 1 ++#else ++#define YAFFS_USE_WRITE_BEGIN_END 0 ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) ++#define YAFFS_SUPER_HAS_DIRTY ++#endif ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) ++#define set_nlink(inode, count) do { (inode)->i_nlink = (count); } while(0) ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)) ++static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size) ++{ ++ uint64_t result = partition_size; ++ do_div(result, block_size); ++ return (uint32_t) result; ++} ++#else ++#define YCALCBLOCKS(s, b) ((s)/(b)) ++#endif ++ ++#include ++#include ++ ++#include "yportenv.h" ++#include "yaffs_trace.h" ++#include "yaffs_guts.h" ++#include "yaffs_attribs.h" ++ ++#include "yaffs_linux.h" ++ ++#include "yaffs_mtdif.h" ++#include "yaffs_packedtags2.h" ++#include "yaffs_getblockinfo.h" ++ ++unsigned int yaffs_trace_mask = ++ YAFFS_TRACE_BAD_BLOCKS | ++ YAFFS_TRACE_ALWAYS | ++ 0; ++ ++unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; ++unsigned int yaffs_auto_checkpoint = 1; ++unsigned int yaffs_gc_control = 1; ++unsigned int yaffs_bg_enable = 1; ++unsigned int yaffs_auto_select = 1; ++/* Module Parameters */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++module_param(yaffs_trace_mask, uint, 0644); ++module_param(yaffs_wr_attempts, uint, 0644); ++module_param(yaffs_auto_checkpoint, uint, 0644); ++module_param(yaffs_gc_control, uint, 0644); ++module_param(yaffs_bg_enable, uint, 0644); ++#else ++MODULE_PARM(yaffs_trace_mask, "i"); ++MODULE_PARM(yaffs_wr_attempts, "i"); ++MODULE_PARM(yaffs_auto_checkpoint, "i"); ++MODULE_PARM(yaffs_gc_control, "i"); ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) ++/* use iget and read_inode */ ++#define Y_IGET(sb, inum) iget((sb), (inum)) ++ ++#else ++/* Call local equivalent */ ++#define YAFFS_USE_OWN_IGET ++#define Y_IGET(sb, inum) yaffs_iget((sb), (inum)) ++ ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) ++#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private) ++#else ++#define yaffs_inode_to_obj_lv(iptr) ((iptr)->u.generic_ip) ++#endif ++ ++#define yaffs_inode_to_obj(iptr) \ ++ ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr))) ++#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode) ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->s_fs_info) ++#else ++#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->u.generic_sbp) ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) ++#define Y_CLEAR_INODE(i) clear_inode(i) ++#else ++#define Y_CLEAR_INODE(i) end_writeback(i) ++#endif ++ ++ ++#define update_dir_time(dir) do {\ ++ (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \ ++ } while (0) ++ ++static void yaffs_fill_inode_from_obj(struct inode *inode, ++ struct yaffs_obj *obj); ++ ++ ++static void yaffs_gross_lock(struct yaffs_dev *dev) ++{ ++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locking %p", current); ++ mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock)); ++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locked %p", current); ++} ++ ++static void yaffs_gross_unlock(struct yaffs_dev *dev) ++{ ++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs unlocking %p", current); ++ mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock)); ++} ++ ++ ++static int yaffs_readpage_nolock(struct file *f, struct page *pg) ++{ ++ /* Lifted from jffs2 */ ++ ++ struct yaffs_obj *obj; ++ unsigned char *pg_buf; ++ int ret; ++ loff_t pos = ((loff_t) pg->index) << PAGE_CACHE_SHIFT; ++ struct yaffs_dev *dev; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_readpage_nolock at %lld, size %08x", ++ (long long)pos, ++ (unsigned)PAGE_CACHE_SIZE); ++ ++ obj = yaffs_dentry_to_obj(f->f_dentry); ++ ++ dev = obj->my_dev; ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ BUG_ON(!PageLocked(pg)); ++#else ++ if (!PageLocked(pg)) ++ PAGE_BUG(pg); ++#endif ++ ++ pg_buf = kmap(pg); ++ /* FIXME: Can kmap fail? */ ++ ++ yaffs_gross_lock(dev); ++ ++ ret = yaffs_file_rd(obj, pg_buf, pos, PAGE_CACHE_SIZE); ++ ++ yaffs_gross_unlock(dev); ++ ++ if (ret >= 0) ++ ret = 0; ++ ++ if (ret) { ++ ClearPageUptodate(pg); ++ SetPageError(pg); ++ } else { ++ SetPageUptodate(pg); ++ ClearPageError(pg); ++ } ++ ++ flush_dcache_page(pg); ++ kunmap(pg); ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage_nolock done"); ++ return ret; ++} ++ ++static int yaffs_readpage_unlock(struct file *f, struct page *pg) ++{ ++ int ret = yaffs_readpage_nolock(f, pg); ++ UnlockPage(pg); ++ return ret; ++} ++ ++static int yaffs_readpage(struct file *f, struct page *pg) ++{ ++ int ret; ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage"); ++ ret = yaffs_readpage_unlock(f, pg); ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage done"); ++ return ret; ++} ++ ++ ++static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val) ++{ ++ struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev); ++ ++ if (lc) ++ lc->dirty = val; ++ ++# ifdef YAFFS_SUPER_HAS_DIRTY ++ { ++ struct super_block *sb = lc->super; ++ ++ if (sb) ++ sb->s_dirt = val; ++ } ++#endif ++ ++} ++ ++static void yaffs_set_super_dirty(struct yaffs_dev *dev) ++{ ++ yaffs_set_super_dirty_val(dev, 1); ++} ++ ++static void yaffs_clear_super_dirty(struct yaffs_dev *dev) ++{ ++ yaffs_set_super_dirty_val(dev, 0); ++} ++ ++static int yaffs_check_super_dirty(struct yaffs_dev *dev) ++{ ++ struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev); ++ ++ if (lc && lc->dirty) ++ return 1; ++ ++# ifdef YAFFS_SUPER_HAS_DIRTY ++ { ++ struct super_block *sb = lc->super; ++ ++ if (sb && sb->s_dirt) ++ return 1; ++ } ++#endif ++ return 0; ++ ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_writepage(struct page *page, struct writeback_control *wbc) ++#else ++static int yaffs_writepage(struct page *page) ++#endif ++{ ++ struct yaffs_dev *dev; ++ struct address_space *mapping = page->mapping; ++ struct inode *inode; ++ unsigned long end_index; ++ char *buffer; ++ struct yaffs_obj *obj; ++ int n_written = 0; ++ unsigned n_bytes; ++ loff_t i_size; ++ ++ if (!mapping) ++ BUG(); ++ inode = mapping->host; ++ if (!inode) ++ BUG(); ++ i_size = i_size_read(inode); ++ ++ end_index = i_size >> PAGE_CACHE_SHIFT; ++ ++ if (page->index < end_index) ++ n_bytes = PAGE_CACHE_SIZE; ++ else { ++ n_bytes = i_size & (PAGE_CACHE_SIZE - 1); ++ ++ if (page->index > end_index || !n_bytes) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_writepage at %lld, inode size = %lld!!", ++ ((loff_t)page->index) << PAGE_CACHE_SHIFT, ++ inode->i_size); ++ yaffs_trace(YAFFS_TRACE_OS, ++ " -> don't care!!"); ++ ++ zero_user_segment(page, 0, PAGE_CACHE_SIZE); ++ set_page_writeback(page); ++ unlock_page(page); ++ end_page_writeback(page); ++ return 0; ++ } ++ } ++ ++ if (n_bytes != PAGE_CACHE_SIZE) ++ zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE); ++ ++ get_page(page); ++ ++ buffer = kmap(page); ++ ++ obj = yaffs_inode_to_obj(inode); ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_writepage at %lld, size %08x", ++ ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes); ++ yaffs_trace(YAFFS_TRACE_OS, ++ "writepag0: obj = %lld, ino = %lld", ++ obj->variant.file_variant.file_size, inode->i_size); ++ ++ n_written = yaffs_wr_file(obj, buffer, ++ ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes, 0); ++ ++ yaffs_set_super_dirty(dev); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "writepag1: obj = %lld, ino = %lld", ++ obj->variant.file_variant.file_size, inode->i_size); ++ ++ yaffs_gross_unlock(dev); ++ ++ kunmap(page); ++ set_page_writeback(page); ++ unlock_page(page); ++ end_page_writeback(page); ++ put_page(page); ++ ++ return (n_written == n_bytes) ? 0 : -ENOSPC; ++} ++ ++/* Space holding and freeing is done to ensure we have space available for write_begin/end */ ++/* For now we just assume few parallel writes and check against a small number. */ ++/* Todo: need to do this with a counter to handle parallel reads better */ ++ ++static ssize_t yaffs_hold_space(struct file *f) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev; ++ ++ int n_free_chunks; ++ ++ obj = yaffs_dentry_to_obj(f->f_dentry); ++ ++ dev = obj->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ n_free_chunks = yaffs_get_n_free_chunks(dev); ++ ++ yaffs_gross_unlock(dev); ++ ++ return (n_free_chunks > 20) ? 1 : 0; ++} ++ ++static void yaffs_release_space(struct file *f) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev; ++ ++ obj = yaffs_dentry_to_obj(f->f_dentry); ++ ++ dev = obj->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ yaffs_gross_unlock(dev); ++} ++ ++#if (YAFFS_USE_WRITE_BEGIN_END > 0) ++static int yaffs_write_begin(struct file *filp, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned flags, ++ struct page **pagep, void **fsdata) ++{ ++ struct page *pg = NULL; ++ pgoff_t index = pos >> PAGE_CACHE_SHIFT; ++ ++ int ret = 0; ++ int space_held = 0; ++ ++ /* Get a page */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) ++ pg = grab_cache_page_write_begin(mapping, index, flags); ++#else ++ pg = __grab_cache_page(mapping, index); ++#endif ++ ++ *pagep = pg; ++ if (!pg) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ yaffs_trace(YAFFS_TRACE_OS, ++ "start yaffs_write_begin index %d(%x) uptodate %d", ++ (int)index, (int)index, Page_Uptodate(pg) ? 1 : 0); ++ ++ /* Get fs space */ ++ space_held = yaffs_hold_space(filp); ++ ++ if (!space_held) { ++ ret = -ENOSPC; ++ goto out; ++ } ++ ++ /* Update page if required */ ++ ++ if (!Page_Uptodate(pg)) ++ ret = yaffs_readpage_nolock(filp, pg); ++ ++ if (ret) ++ goto out; ++ ++ /* Happy path return */ ++ yaffs_trace(YAFFS_TRACE_OS, "end yaffs_write_begin - ok"); ++ ++ return 0; ++ ++out: ++ yaffs_trace(YAFFS_TRACE_OS, ++ "end yaffs_write_begin fail returning %d", ret); ++ if (space_held) ++ yaffs_release_space(filp); ++ if (pg) { ++ unlock_page(pg); ++ page_cache_release(pg); ++ } ++ return ret; ++} ++ ++#else ++ ++static int yaffs_prepare_write(struct file *f, struct page *pg, ++ unsigned offset, unsigned to) ++{ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_prepair_write"); ++ ++ if (!Page_Uptodate(pg)) ++ return yaffs_readpage_nolock(f, pg); ++ return 0; ++} ++#endif ++ ++ ++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, ++ loff_t * pos) ++{ ++ struct yaffs_obj *obj; ++ int n_written; ++ loff_t ipos; ++ struct inode *inode; ++ struct yaffs_dev *dev; ++ ++ obj = yaffs_dentry_to_obj(f->f_dentry); ++ ++ if (!obj) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_file_write: hey obj is null!"); ++ return -EINVAL; ++ } ++ ++ dev = obj->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ inode = f->f_dentry->d_inode; ++ ++ if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) ++ ipos = inode->i_size; ++ else ++ ipos = *pos; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_file_write about to write writing %u(%x) bytes to object %d at %lld", ++ (unsigned)n, (unsigned)n, obj->obj_id, ipos); ++ ++ n_written = yaffs_wr_file(obj, buf, ipos, n, 0); ++ ++ yaffs_set_super_dirty(dev); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_file_write: %d(%x) bytes written", ++ (unsigned)n, (unsigned)n); ++ ++ if (n_written > 0) { ++ ipos += n_written; ++ *pos = ipos; ++ if (ipos > inode->i_size) { ++ inode->i_size = ipos; ++ inode->i_blocks = (ipos + 511) >> 9; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_file_write size updated to %lld bytes, %d blocks", ++ ipos, (int)(inode->i_blocks)); ++ } ++ ++ } ++ yaffs_gross_unlock(dev); ++ return (n_written == 0) && (n > 0) ? -ENOSPC : n_written; ++} ++ ++ ++#if (YAFFS_USE_WRITE_BEGIN_END > 0) ++static int yaffs_write_end(struct file *filp, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned copied, ++ struct page *pg, void *fsdadata) ++{ ++ int ret = 0; ++ void *addr, *kva; ++ uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1); ++ ++ kva = kmap(pg); ++ addr = kva + offset_into_page; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_write_end addr %p pos %lld n_bytes %d", ++ addr, pos, copied); ++ ++ ret = yaffs_file_write(filp, addr, copied, &pos); ++ ++ if (ret != copied) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_write_end not same size ret %d copied %d", ++ ret, copied); ++ SetPageError(pg); ++ } ++ ++ kunmap(pg); ++ ++ yaffs_release_space(filp); ++ unlock_page(pg); ++ page_cache_release(pg); ++ return ret; ++} ++#else ++ ++static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, ++ unsigned to) ++{ ++ void *addr, *kva; ++ ++ loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset; ++ int n_bytes = to - offset; ++ int n_written; ++ ++ kva = kmap(pg); ++ addr = kva + offset; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_commit_write addr %p pos %lld n_bytes %d", ++ addr, pos, n_bytes); ++ ++ n_written = yaffs_file_write(f, addr, n_bytes, &pos); ++ ++ if (n_written != n_bytes) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_commit_write not same size n_written %d n_bytes %d", ++ n_written, n_bytes); ++ SetPageError(pg); ++ } ++ kunmap(pg); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_commit_write returning %d", ++ n_written == n_bytes ? 0 : n_written); ++ ++ return n_written == n_bytes ? 0 : n_written; ++} ++#endif ++ ++static struct address_space_operations yaffs_file_address_operations = { ++ .readpage = yaffs_readpage, ++ .writepage = yaffs_writepage, ++#if (YAFFS_USE_WRITE_BEGIN_END > 0) ++ .write_begin = yaffs_write_begin, ++ .write_end = yaffs_write_end, ++#else ++ .prepare_write = yaffs_prepare_write, ++ .commit_write = yaffs_commit_write, ++#endif ++}; ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_file_flush(struct file *file, fl_owner_t id) ++#else ++static int yaffs_file_flush(struct file *file) ++#endif ++{ ++ struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry); ++ ++ struct yaffs_dev *dev = obj->my_dev; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_file_flush object %d (%s)", ++ obj->obj_id, ++ obj->dirty ? "dirty" : "clean"); ++ ++ yaffs_gross_lock(dev); ++ ++ yaffs_flush_file(obj, 1, 0); ++ ++ yaffs_gross_unlock(dev); ++ ++ return 0; ++} ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync) ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34)) ++static int yaffs_sync_object(struct file *file, int datasync) ++#else ++static int yaffs_sync_object(struct file *file, struct dentry *dentry, ++ int datasync) ++#endif ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34)) ++ struct dentry *dentry = file->f_path.dentry; ++#endif ++ ++ obj = yaffs_dentry_to_obj(dentry); ++ ++ dev = obj->my_dev; ++ ++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, ++ "yaffs_sync_object"); ++ yaffs_gross_lock(dev); ++ yaffs_flush_file(obj, 1, datasync); ++ yaffs_gross_unlock(dev); ++ return 0; ++} ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) ++static const struct file_operations yaffs_file_operations = { ++ .read = do_sync_read, ++ .write = do_sync_write, ++ .aio_read = generic_file_aio_read, ++ .aio_write = generic_file_aio_write, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++ .splice_read = generic_file_splice_read, ++ .splice_write = generic_file_splice_write, ++ .llseek = generic_file_llseek, ++}; ++ ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) ++ ++static const struct file_operations yaffs_file_operations = { ++ .read = do_sync_read, ++ .write = do_sync_write, ++ .aio_read = generic_file_aio_read, ++ .aio_write = generic_file_aio_write, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++ .sendfile = generic_file_sendfile, ++}; ++ ++#else ++ ++static const struct file_operations yaffs_file_operations = { ++ .read = generic_file_read, ++ .write = generic_file_write, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ .sendfile = generic_file_sendfile, ++#endif ++}; ++#endif ++ ++ ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) ++static void zero_user_segment(struct page *page, unsigned start, unsigned end) ++{ ++ void *kaddr = kmap_atomic(page, KM_USER0); ++ memset(kaddr + start, 0, end - start); ++ kunmap_atomic(kaddr, KM_USER0); ++ flush_dcache_page(page); ++} ++#endif ++ ++ ++static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize) ++{ ++#ifdef YAFFS_USE_TRUNCATE_SETSIZE ++ truncate_setsize(inode, newsize); ++ return 0; ++#else ++ truncate_inode_pages(&inode->i_data, newsize); ++ return 0; ++#endif ++ ++} ++ ++ ++static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr) ++{ ++#ifdef YAFFS_USE_SETATTR_COPY ++ setattr_copy(inode, attr); ++ return 0; ++#else ++ return inode_setattr(inode, attr); ++#endif ++ ++} ++ ++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) ++{ ++ struct inode *inode = dentry->d_inode; ++ int error = 0; ++ struct yaffs_dev *dev; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_setattr of object %d", ++ yaffs_inode_to_obj(inode)->obj_id); ++#if 0 ++ /* Fail if a requested resize >= 2GB */ ++ if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31)) ++ error = -EINVAL; ++#endif ++ ++ if (error == 0) ++ error = inode_change_ok(inode, attr); ++ if (error == 0) { ++ int result; ++ if (!error) { ++ error = yaffs_vfs_setattr(inode, attr); ++ yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called"); ++ if (attr->ia_valid & ATTR_SIZE) { ++ yaffs_vfs_setsize(inode, attr->ia_size); ++ inode->i_blocks = (inode->i_size + 511) >> 9; ++ } ++ } ++ dev = yaffs_inode_to_obj(inode)->my_dev; ++ if (attr->ia_valid & ATTR_SIZE) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "resize to %d(%x)", ++ (int)(attr->ia_size), ++ (int)(attr->ia_size)); ++ } ++ yaffs_gross_lock(dev); ++ result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr); ++ if (result == YAFFS_OK) { ++ error = 0; ++ } else { ++ error = -EPERM; ++ } ++ yaffs_gross_unlock(dev); ++ ++ } ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error); ++ ++ return error; ++} ++ ++static int yaffs_setxattr(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ struct inode *inode = dentry->d_inode; ++ int error = 0; ++ struct yaffs_dev *dev; ++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode); ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id); ++ ++ if (error == 0) { ++ int result; ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ result = yaffs_set_xattrib(obj, name, value, size, flags); ++ if (result == YAFFS_OK) ++ error = 0; ++ else if (result < 0) ++ error = result; ++ yaffs_gross_unlock(dev); ++ ++ } ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error); ++ ++ return error; ++} ++ ++static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name, ++ void *buff, size_t size) ++{ ++ struct inode *inode = dentry->d_inode; ++ int error = 0; ++ struct yaffs_dev *dev; ++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_getxattr \"%s\" from object %d", ++ name, obj->obj_id); ++ ++ if (error == 0) { ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ error = yaffs_get_xattrib(obj, name, buff, size); ++ yaffs_gross_unlock(dev); ++ ++ } ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error); ++ ++ return error; ++} ++ ++static int yaffs_removexattr(struct dentry *dentry, const char *name) ++{ ++ struct inode *inode = dentry->d_inode; ++ int error = 0; ++ struct yaffs_dev *dev; ++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_removexattr of object %d", obj->obj_id); ++ ++ if (error == 0) { ++ int result; ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ result = yaffs_remove_xattrib(obj, name); ++ if (result == YAFFS_OK) ++ error = 0; ++ else if (result < 0) ++ error = result; ++ yaffs_gross_unlock(dev); ++ ++ } ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_removexattr done returning %d", error); ++ ++ return error; ++} ++ ++static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size) ++{ ++ struct inode *inode = dentry->d_inode; ++ int error = 0; ++ struct yaffs_dev *dev; ++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_listxattr of object %d", obj->obj_id); ++ ++ if (error == 0) { ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ error = yaffs_list_xattrib(obj, buff, size); ++ yaffs_gross_unlock(dev); ++ ++ } ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_listxattr done returning %d", error); ++ ++ return error; ++} ++ ++ ++static const struct inode_operations yaffs_file_inode_operations = { ++ .setattr = yaffs_setattr, ++ .setxattr = yaffs_setxattr, ++ .getxattr = yaffs_getxattr, ++ .listxattr = yaffs_listxattr, ++ .removexattr = yaffs_removexattr, ++}; ++ ++ ++static int yaffs_readlink(struct dentry *dentry, char __user * buffer, ++ int buflen) ++{ ++ unsigned char *alias; ++ int ret; ++ ++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry)); ++ ++ yaffs_gross_unlock(dev); ++ ++ if (!alias) ++ return -ENOMEM; ++ ++ ret = vfs_readlink(dentry, buffer, buflen, alias); ++ kfree(alias); ++ return ret; ++} ++ ++#if (YAFFS_NEW_FOLLOW_LINK == 1) ++static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) ++{ ++ void *ret; ++#else ++static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) ++{ ++ int ret ++#endif ++ unsigned char *alias; ++ int ret_int = 0; ++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry)); ++ yaffs_gross_unlock(dev); ++ ++ if (!alias) { ++ ret_int = -ENOMEM; ++ goto out; ++ } ++#if (YAFFS_NEW_FOLLOW_LINK == 1) ++ nd_set_link(nd, alias); ++ ret = alias; ++out: ++ if (ret_int) ++ ret = ERR_PTR(ret_int); ++ return ret; ++#else ++ ret = vfs_follow_link(nd, alias); ++ kfree(alias); ++out: ++ if (ret_int) ++ ret = ret_int; ++ return ret; ++#endif ++} ++ ++ ++#ifdef YAFFS_HAS_PUT_INODE ++ ++/* For now put inode is just for debugging ++ * Put inode is called when the inode **structure** is put. ++ */ ++static void yaffs_put_inode(struct inode *inode) ++{ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_put_inode: ino %d, count %d"), ++ (int)inode->i_ino, atomic_read(&inode->i_count); ++ ++} ++#endif ++ ++#if (YAFFS_NEW_FOLLOW_LINK == 1) ++void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) ++{ ++ kfree(alias); ++} ++#endif ++ ++static const struct inode_operations yaffs_symlink_inode_operations = { ++ .readlink = yaffs_readlink, ++ .follow_link = yaffs_follow_link, ++#if (YAFFS_NEW_FOLLOW_LINK == 1) ++ .put_link = yaffs_put_link, ++#endif ++ .setattr = yaffs_setattr, ++ .setxattr = yaffs_setxattr, ++ .getxattr = yaffs_getxattr, ++ .listxattr = yaffs_listxattr, ++ .removexattr = yaffs_removexattr, ++}; ++ ++#ifdef YAFFS_USE_OWN_IGET ++ ++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino) ++{ ++ struct inode *inode; ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev = yaffs_super_to_dev(sb); ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_iget for %lu", ino); ++ ++ inode = iget_locked(sb, ino); ++ if (!inode) ++ return ERR_PTR(-ENOMEM); ++ if (!(inode->i_state & I_NEW)) ++ return inode; ++ ++ /* NB This is called as a side effect of other functions, but ++ * we had to release the lock to prevent deadlocks, so ++ * need to lock again. ++ */ ++ ++ yaffs_gross_lock(dev); ++ ++ obj = yaffs_find_by_number(dev, inode->i_ino); ++ ++ yaffs_fill_inode_from_obj(inode, obj); ++ ++ yaffs_gross_unlock(dev); ++ ++ unlock_new_inode(inode); ++ return inode; ++} ++ ++#else ++ ++static void yaffs_read_inode(struct inode *inode) ++{ ++ /* NB This is called as a side effect of other functions, but ++ * we had to release the lock to prevent deadlocks, so ++ * need to lock again. ++ */ ++ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev = yaffs_super_to_dev(inode->i_sb); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_read_inode for %d", (int)inode->i_ino); ++ ++ if (current != yaffs_dev_to_lc(dev)->readdir_process) ++ yaffs_gross_lock(dev); ++ ++ obj = yaffs_find_by_number(dev, inode->i_ino); ++ ++ yaffs_fill_inode_from_obj(inode, obj); ++ ++ if (current != yaffs_dev_to_lc(dev)->readdir_process) ++ yaffs_gross_unlock(dev); ++} ++ ++#endif ++ ++ ++ ++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, ++ struct yaffs_obj *obj) ++{ ++ struct inode *inode; ++ ++ if (!sb) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_get_inode for NULL super_block!!"); ++ return NULL; ++ ++ } ++ ++ if (!obj) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_get_inode for NULL object!!"); ++ return NULL; ++ ++ } ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_get_inode for object %d", obj->obj_id); ++ ++ inode = Y_IGET(sb, obj->obj_id); ++ if (IS_ERR(inode)) ++ return NULL; ++ ++ /* NB Side effect: iget calls back to yaffs_read_inode(). */ ++ /* iget also increments the inode's i_count */ ++ /* NB You can't be holding gross_lock or deadlock will happen! */ ++ ++ return inode; ++} ++ ++ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) ++#define YCRED(x) x ++#else ++#define YCRED(x) (x->cred) ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) ++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, ++ dev_t rdev) ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, ++ dev_t rdev) ++#else ++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, ++ int rdev) ++#endif ++{ ++ struct inode *inode; ++ ++ struct yaffs_obj *obj = NULL; ++ struct yaffs_dev *dev; ++ ++ struct yaffs_obj *parent = yaffs_inode_to_obj(dir); ++ ++ int error = -ENOSPC; ++ uid_t uid = YCRED(current)->fsuid; ++ gid_t gid = ++ (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; ++ ++ if ((dir->i_mode & S_ISGID) && S_ISDIR(mode)) ++ mode |= S_ISGID; ++ ++ if (parent) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_mknod: parent object %d type %d", ++ parent->obj_id, parent->variant_type); ++ } else { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_mknod: could not get parent object"); ++ return -EPERM; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_mknod: making oject for %s, mode %x dev %x", ++ dentry->d_name.name, mode, rdev); ++ ++ dev = parent->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ switch (mode & S_IFMT) { ++ default: ++ /* Special (socket, fifo, device...) */ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making special"); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ obj = ++ yaffs_create_special(parent, dentry->d_name.name, mode, uid, ++ gid, old_encode_dev(rdev)); ++#else ++ obj = ++ yaffs_create_special(parent, dentry->d_name.name, mode, uid, ++ gid, rdev); ++#endif ++ break; ++ case S_IFREG: /* file */ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making file"); ++ obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid, ++ gid); ++ break; ++ case S_IFDIR: /* directory */ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making directory"); ++ obj = yaffs_create_dir(parent, dentry->d_name.name, mode, ++ uid, gid); ++ break; ++ case S_IFLNK: /* symlink */ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making symlink"); ++ obj = NULL; /* Do we ever get here? */ ++ break; ++ } ++ ++ /* Can not call yaffs_get_inode() with gross lock held */ ++ yaffs_gross_unlock(dev); ++ ++ if (obj) { ++ inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj); ++ d_instantiate(dentry, inode); ++ update_dir_time(dir); ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_mknod created object %d count = %d", ++ obj->obj_id, atomic_read(&inode->i_count)); ++ error = 0; ++ yaffs_fill_inode_from_obj(dir, parent); ++ } else { ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object"); ++ error = -ENOMEM; ++ } ++ ++ return error; ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) ++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ++#else ++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ++#endif ++{ ++ int ret_val; ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mkdir"); ++ ret_val = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0); ++ return ret_val; ++} ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) ++static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ++ bool dummy) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) ++static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ++ struct nameidata *n) ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *n) ++#else ++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode) ++#endif ++{ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_create"); ++ return yaffs_mknod(dir, dentry, mode | S_IFREG, 0); ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) ++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, ++ unsigned int dummy) ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, ++ struct nameidata *n) ++#else ++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) ++#endif ++{ ++ struct yaffs_obj *obj; ++ struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */ ++ ++ struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev; ++ ++ if (current != yaffs_dev_to_lc(dev)->readdir_process) ++ yaffs_gross_lock(dev); ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup for %d:%s", ++ yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name); ++ ++ obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name); ++ ++ obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */ ++ ++ /* Can't hold gross lock when calling yaffs_get_inode() */ ++ if (current != yaffs_dev_to_lc(dev)->readdir_process) ++ yaffs_gross_unlock(dev); ++ ++ if (obj) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_lookup found %d", obj->obj_id); ++ ++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); ++ } else { ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup not found"); ++ ++ } ++ ++/* added NCB for 2.5/6 compatability - forces add even if inode is ++ * NULL which creates dentry hash */ ++ d_add(dentry, inode); ++ ++ return NULL; ++} ++ ++/* ++ * Create a link... ++ */ ++static int yaffs_link(struct dentry *old_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ struct inode *inode = old_dentry->d_inode; ++ struct yaffs_obj *obj = NULL; ++ struct yaffs_obj *link = NULL; ++ struct yaffs_dev *dev; ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_link"); ++ ++ obj = yaffs_inode_to_obj(inode); ++ dev = obj->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ if (!S_ISDIR(inode->i_mode)) /* Don't link directories */ ++ link = ++ yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name, ++ obj); ++ ++ if (link) { ++ set_nlink(old_dentry->d_inode, yaffs_get_obj_link_count(obj)); ++ d_instantiate(dentry, old_dentry->d_inode); ++ atomic_inc(&old_dentry->d_inode->i_count); ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_link link count %d i_count %d", ++ old_dentry->d_inode->i_nlink, ++ atomic_read(&old_dentry->d_inode->i_count)); ++ } ++ ++ yaffs_gross_unlock(dev); ++ ++ if (link) { ++ update_dir_time(dir); ++ return 0; ++ } ++ ++ return -EPERM; ++} ++ ++static int yaffs_symlink(struct inode *dir, struct dentry *dentry, ++ const char *symname) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev; ++ uid_t uid = YCRED(current)->fsuid; ++ gid_t gid = ++ (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink"); ++ ++ if (strnlen(dentry->d_name.name, YAFFS_MAX_NAME_LENGTH + 1) > ++ YAFFS_MAX_NAME_LENGTH) ++ return -ENAMETOOLONG; ++ ++ if (strnlen(symname, YAFFS_MAX_ALIAS_LENGTH + 1) > ++ YAFFS_MAX_ALIAS_LENGTH) ++ return -ENAMETOOLONG; ++ ++ dev = yaffs_inode_to_obj(dir)->my_dev; ++ yaffs_gross_lock(dev); ++ obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name, ++ S_IFLNK | S_IRWXUGO, uid, gid, symname); ++ yaffs_gross_unlock(dev); ++ ++ if (obj) { ++ struct inode *inode; ++ ++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); ++ d_instantiate(dentry, inode); ++ update_dir_time(dir); ++ yaffs_trace(YAFFS_TRACE_OS, "symlink created OK"); ++ return 0; ++ } else { ++ yaffs_trace(YAFFS_TRACE_OS, "symlink not created"); ++ } ++ ++ return -ENOMEM; ++} ++ ++/* ++ * The VFS layer already does all the dentry stuff for rename. ++ * ++ * NB: POSIX says you can rename an object over an old object of the same name ++ */ ++static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, ++ struct inode *new_dir, struct dentry *new_dentry) ++{ ++ struct yaffs_dev *dev; ++ int ret_val = YAFFS_FAIL; ++ struct yaffs_obj *target; ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_rename"); ++ dev = yaffs_inode_to_obj(old_dir)->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ /* Check if the target is an existing directory that is not empty. */ ++ target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir), ++ new_dentry->d_name.name); ++ ++ if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY && ++ !list_empty(&target->variant.dir_variant.children)) { ++ ++ yaffs_trace(YAFFS_TRACE_OS, "target is non-empty dir"); ++ ++ ret_val = YAFFS_FAIL; ++ } else { ++ /* Now does unlinking internally using shadowing mechanism */ ++ yaffs_trace(YAFFS_TRACE_OS, "calling yaffs_rename_obj"); ++ ++ ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir), ++ old_dentry->d_name.name, ++ yaffs_inode_to_obj(new_dir), ++ new_dentry->d_name.name); ++ } ++ yaffs_gross_unlock(dev); ++ ++ if (ret_val == YAFFS_OK) { ++ if (target) ++ inode_dec_link_count(new_dentry->d_inode); ++ ++ update_dir_time(old_dir); ++ if (old_dir != new_dir) ++ update_dir_time(new_dir); ++ return 0; ++ } else { ++ return -ENOTEMPTY; ++ } ++} ++ ++ ++ ++ ++static int yaffs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ int ret_val; ++ ++ struct yaffs_dev *dev; ++ struct yaffs_obj *obj; ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_unlink %d:%s", ++ (int)(dir->i_ino), dentry->d_name.name); ++ obj = yaffs_inode_to_obj(dir); ++ dev = obj->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ ret_val = yaffs_unlinker(obj, dentry->d_name.name); ++ ++ if (ret_val == YAFFS_OK) { ++ inode_dec_link_count(dentry->d_inode); ++ dir->i_version++; ++ yaffs_gross_unlock(dev); ++ update_dir_time(dir); ++ return 0; ++ } ++ yaffs_gross_unlock(dev); ++ return -ENOTEMPTY; ++} ++ ++ ++ ++static const struct inode_operations yaffs_dir_inode_operations = { ++ .create = yaffs_create, ++ .lookup = yaffs_lookup, ++ .link = yaffs_link, ++ .unlink = yaffs_unlink, ++ .symlink = yaffs_symlink, ++ .mkdir = yaffs_mkdir, ++ .rmdir = yaffs_unlink, ++ .mknod = yaffs_mknod, ++ .rename = yaffs_rename, ++ .setattr = yaffs_setattr, ++ .setxattr = yaffs_setxattr, ++ .getxattr = yaffs_getxattr, ++ .listxattr = yaffs_listxattr, ++ .removexattr = yaffs_removexattr, ++}; ++ ++/*-----------------------------------------------------------------*/ ++/* Directory search context allows us to unlock access to yaffs during ++ * filldir without causing problems with the directory being modified. ++ * This is similar to the tried and tested mechanism used in yaffs direct. ++ * ++ * A search context iterates along a doubly linked list of siblings in the ++ * directory. If the iterating object is deleted then this would corrupt ++ * the list iteration, likely causing a crash. The search context avoids ++ * this by using the remove_obj_fn to move the search context to the ++ * next object before the object is deleted. ++ * ++ * Many readdirs (and thus seach conexts) may be alive simulateously so ++ * each struct yaffs_dev has a list of these. ++ * ++ * A seach context lives for the duration of a readdir. ++ * ++ * All these functions must be called while yaffs is locked. ++ */ ++ ++struct yaffs_search_context { ++ struct yaffs_dev *dev; ++ struct yaffs_obj *dir_obj; ++ struct yaffs_obj *next_return; ++ struct list_head others; ++}; ++ ++/* ++ * yaffs_new_search() creates a new search context, initialises it and ++ * adds it to the device's search context list. ++ * ++ * Called at start of readdir. ++ */ ++static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir) ++{ ++ struct yaffs_dev *dev = dir->my_dev; ++ struct yaffs_search_context *sc = ++ kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS); ++ if (sc) { ++ sc->dir_obj = dir; ++ sc->dev = dev; ++ if (list_empty(&sc->dir_obj->variant.dir_variant.children)) ++ sc->next_return = NULL; ++ else ++ sc->next_return = ++ list_entry(dir->variant.dir_variant.children.next, ++ struct yaffs_obj, siblings); ++ INIT_LIST_HEAD(&sc->others); ++ list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts)); ++ } ++ return sc; ++} ++ ++/* ++ * yaffs_search_end() disposes of a search context and cleans up. ++ */ ++static void yaffs_search_end(struct yaffs_search_context *sc) ++{ ++ if (sc) { ++ list_del(&sc->others); ++ kfree(sc); ++ } ++} ++ ++/* ++ * yaffs_search_advance() moves a search context to the next object. ++ * Called when the search iterates or when an object removal causes ++ * the search context to be moved to the next object. ++ */ ++static void yaffs_search_advance(struct yaffs_search_context *sc) ++{ ++ if (!sc) ++ return; ++ ++ if (sc->next_return == NULL || ++ list_empty(&sc->dir_obj->variant.dir_variant.children)) ++ sc->next_return = NULL; ++ else { ++ struct list_head *next = sc->next_return->siblings.next; ++ ++ if (next == &sc->dir_obj->variant.dir_variant.children) ++ sc->next_return = NULL; /* end of list */ ++ else ++ sc->next_return = ++ list_entry(next, struct yaffs_obj, siblings); ++ } ++} ++ ++/* ++ * yaffs_remove_obj_callback() is called when an object is unlinked. ++ * We check open search contexts and advance any which are currently ++ * on the object being iterated. ++ */ ++static void yaffs_remove_obj_callback(struct yaffs_obj *obj) ++{ ++ ++ struct list_head *i; ++ struct yaffs_search_context *sc; ++ struct list_head *search_contexts = ++ &(yaffs_dev_to_lc(obj->my_dev)->search_contexts); ++ ++ /* Iterate through the directory search contexts. ++ * If any are currently on the object being removed, then advance ++ * the search context to the next object to prevent a hanging pointer. ++ */ ++ list_for_each(i, search_contexts) { ++ sc = list_entry(i, struct yaffs_search_context, others); ++ if (sc->next_return == obj) ++ yaffs_search_advance(sc); ++ } ++ ++} ++ ++ ++/*-----------------------------------------------------------------*/ ++ ++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev; ++ struct yaffs_search_context *sc; ++ struct inode *inode = f->f_dentry->d_inode; ++ unsigned long offset, curoffs; ++ struct yaffs_obj *l; ++ int ret_val = 0; ++ ++ char name[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ obj = yaffs_dentry_to_obj(f->f_dentry); ++ dev = obj->my_dev; ++ ++ yaffs_gross_lock(dev); ++ ++ yaffs_dev_to_lc(dev)->readdir_process = current; ++ ++ offset = f->f_pos; ++ ++ sc = yaffs_new_search(obj); ++ if (!sc) { ++ ret_val = -ENOMEM; ++ goto out; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_readdir: starting at %d", (int)offset); ++ ++ if (offset == 0) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_readdir: entry . ino %d", ++ (int)inode->i_ino); ++ yaffs_gross_unlock(dev); ++ if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) { ++ yaffs_gross_lock(dev); ++ goto out; ++ } ++ yaffs_gross_lock(dev); ++ offset++; ++ f->f_pos++; ++ } ++ if (offset == 1) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_readdir: entry .. ino %d", ++ (int)f->f_dentry->d_parent->d_inode->i_ino); ++ yaffs_gross_unlock(dev); ++ if (filldir(dirent, "..", 2, offset, ++ f->f_dentry->d_parent->d_inode->i_ino, ++ DT_DIR) < 0) { ++ yaffs_gross_lock(dev); ++ goto out; ++ } ++ yaffs_gross_lock(dev); ++ offset++; ++ f->f_pos++; ++ } ++ ++ curoffs = 1; ++ ++ /* If the directory has changed since the open or last call to ++ readdir, rewind to after the 2 canned entries. */ ++ if (f->f_version != inode->i_version) { ++ offset = 2; ++ f->f_pos = offset; ++ f->f_version = inode->i_version; ++ } ++ ++ while (sc->next_return) { ++ curoffs++; ++ l = sc->next_return; ++ if (curoffs >= offset) { ++ int this_inode = yaffs_get_obj_inode(l); ++ int this_type = yaffs_get_obj_type(l); ++ ++ yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1); ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_readdir: %s inode %d", ++ name, yaffs_get_obj_inode(l)); ++ ++ yaffs_gross_unlock(dev); ++ ++ if (filldir(dirent, ++ name, ++ strlen(name), ++ offset, this_inode, this_type) < 0) { ++ yaffs_gross_lock(dev); ++ goto out; ++ } ++ ++ yaffs_gross_lock(dev); ++ ++ offset++; ++ f->f_pos++; ++ } ++ yaffs_search_advance(sc); ++ } ++ ++out: ++ yaffs_search_end(sc); ++ yaffs_dev_to_lc(dev)->readdir_process = NULL; ++ yaffs_gross_unlock(dev); ++ ++ return ret_val; ++} ++ ++static const struct file_operations yaffs_dir_operations = { ++ .read = generic_read_dir, ++ .readdir = yaffs_readdir, ++ .fsync = yaffs_sync_object, ++ .llseek = generic_file_llseek, ++}; ++ ++static void yaffs_fill_inode_from_obj(struct inode *inode, ++ struct yaffs_obj *obj) ++{ ++ if (inode && obj) { ++ ++ /* Check mode against the variant type and attempt to repair if broken. */ ++ u32 mode = obj->yst_mode; ++ switch (obj->variant_type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ if (!S_ISREG(mode)) { ++ obj->yst_mode &= ~S_IFMT; ++ obj->yst_mode |= S_IFREG; ++ } ++ ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ if (!S_ISLNK(mode)) { ++ obj->yst_mode &= ~S_IFMT; ++ obj->yst_mode |= S_IFLNK; ++ } ++ ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ if (!S_ISDIR(mode)) { ++ obj->yst_mode &= ~S_IFMT; ++ obj->yst_mode |= S_IFDIR; ++ } ++ ++ break; ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ default: ++ /* TODO? */ ++ break; ++ } ++ ++ inode->i_flags |= S_NOATIME; ++ ++ inode->i_ino = obj->obj_id; ++ inode->i_mode = obj->yst_mode; ++ inode->i_uid = obj->yst_uid; ++ inode->i_gid = obj->yst_gid; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) ++ inode->i_blksize = inode->i_sb->s_blocksize; ++#endif ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ ++ inode->i_rdev = old_decode_dev(obj->yst_rdev); ++ inode->i_atime.tv_sec = (time_t) (obj->yst_atime); ++ inode->i_atime.tv_nsec = 0; ++ inode->i_mtime.tv_sec = (time_t) obj->yst_mtime; ++ inode->i_mtime.tv_nsec = 0; ++ inode->i_ctime.tv_sec = (time_t) obj->yst_ctime; ++ inode->i_ctime.tv_nsec = 0; ++#else ++ inode->i_rdev = obj->yst_rdev; ++ inode->i_atime = obj->yst_atime; ++ inode->i_mtime = obj->yst_mtime; ++ inode->i_ctime = obj->yst_ctime; ++#endif ++ inode->i_size = yaffs_get_obj_length(obj); ++ inode->i_blocks = (inode->i_size + 511) >> 9; ++ ++ set_nlink(inode, yaffs_get_obj_link_count(obj)); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_fill_inode mode %x uid %d gid %d size %lld count %d", ++ inode->i_mode, inode->i_uid, inode->i_gid, ++ inode->i_size, atomic_read(&inode->i_count)); ++ ++ switch (obj->yst_mode & S_IFMT) { ++ default: /* fifo, device or socket */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ init_special_inode(inode, obj->yst_mode, ++ old_decode_dev(obj->yst_rdev)); ++#else ++ init_special_inode(inode, obj->yst_mode, ++ (dev_t) (obj->yst_rdev)); ++#endif ++ break; ++ case S_IFREG: /* file */ ++ inode->i_op = &yaffs_file_inode_operations; ++ inode->i_fop = &yaffs_file_operations; ++ inode->i_mapping->a_ops = ++ &yaffs_file_address_operations; ++ break; ++ case S_IFDIR: /* directory */ ++ inode->i_op = &yaffs_dir_inode_operations; ++ inode->i_fop = &yaffs_dir_operations; ++ break; ++ case S_IFLNK: /* symlink */ ++ inode->i_op = &yaffs_symlink_inode_operations; ++ break; ++ } ++ ++ yaffs_inode_to_obj_lv(inode) = obj; ++ ++ obj->my_inode = inode; ++ ++ } else { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_fill_inode invalid parameters"); ++ } ++ ++} ++ ++ ++ ++/* ++ * yaffs background thread functions . ++ * yaffs_bg_thread_fn() the thread function ++ * yaffs_bg_start() launches the background thread. ++ * yaffs_bg_stop() cleans up the background thread. ++ * ++ * NB: ++ * The thread should only run after the yaffs is initialised ++ * The thread should be stopped before yaffs is unmounted. ++ * The thread should not do any writing while the fs is in read only. ++ */ ++ ++static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev) ++{ ++ unsigned erased_chunks = ++ dev->n_erased_blocks * dev->param.chunks_per_block; ++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev); ++ unsigned scattered = 0; /* Free chunks not in an erased block */ ++ ++ if (erased_chunks < dev->n_free_chunks) ++ scattered = (dev->n_free_chunks - erased_chunks); ++ ++ if (!context->bg_running) ++ return 0; ++ else if (scattered < (dev->param.chunks_per_block * 2)) ++ return 0; ++ else if (erased_chunks > dev->n_free_chunks / 2) ++ return 0; ++ else if (erased_chunks > dev->n_free_chunks / 4) ++ return 1; ++ else ++ return 2; ++} ++ ++#ifdef YAFFS_COMPILE_BACKGROUND ++ ++void yaffs_background_waker(unsigned long data) ++{ ++ wake_up_process((struct task_struct *)data); ++} ++ ++static int yaffs_bg_thread_fn(void *data) ++{ ++ struct yaffs_dev *dev = (struct yaffs_dev *)data; ++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev); ++ unsigned long now = jiffies; ++ unsigned long next_dir_update = now; ++ unsigned long next_gc = now; ++ unsigned long expires; ++ unsigned int urgency; ++ ++ int gc_result; ++ struct timer_list timer; ++ ++ yaffs_trace(YAFFS_TRACE_BACKGROUND, ++ "yaffs_background starting for dev %p", (void *)dev); ++ ++#ifdef YAFFS_COMPILE_FREEZER ++ set_freezable(); ++#endif ++ while (context->bg_running) { ++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "yaffs_background"); ++ ++ if (kthread_should_stop()) ++ break; ++ ++#ifdef YAFFS_COMPILE_FREEZER ++ if (try_to_freeze()) ++ continue; ++#endif ++ yaffs_gross_lock(dev); ++ ++ now = jiffies; ++ ++ if (time_after(now, next_dir_update) && yaffs_bg_enable) { ++ yaffs_update_dirty_dirs(dev); ++ next_dir_update = now + HZ; ++ } ++ ++ if (time_after(now, next_gc) && yaffs_bg_enable) { ++ if (!dev->is_checkpointed) { ++ urgency = yaffs_bg_gc_urgency(dev); ++ gc_result = yaffs_bg_gc(dev, urgency); ++ if (urgency > 1) ++ next_gc = now + HZ / 20 + 1; ++ else if (urgency > 0) ++ next_gc = now + HZ / 10 + 1; ++ else ++ next_gc = now + HZ * 2; ++ } else { ++ /* ++ * gc not running so set to next_dir_update ++ * to cut down on wake ups ++ */ ++ next_gc = next_dir_update; ++ } ++ } ++ yaffs_gross_unlock(dev); ++#if 1 ++ expires = next_dir_update; ++ if (time_before(next_gc, expires)) ++ expires = next_gc; ++ if (time_before(expires, now)) ++ expires = now + HZ; ++ ++ Y_INIT_TIMER(&timer); ++ timer.expires = expires + 1; ++ timer.data = (unsigned long)current; ++ timer.function = yaffs_background_waker; ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ add_timer(&timer); ++ schedule(); ++ del_timer_sync(&timer); ++#else ++ msleep(10); ++#endif ++ } ++ ++ return 0; ++} ++ ++static int yaffs_bg_start(struct yaffs_dev *dev) ++{ ++ int retval = 0; ++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev); ++ ++ if (dev->read_only) ++ return -1; ++ ++ context->bg_running = 1; ++ ++ context->bg_thread = kthread_run(yaffs_bg_thread_fn, ++ (void *)dev, "yaffs-bg-%d", ++ context->mount_id); ++ ++ if (IS_ERR(context->bg_thread)) { ++ retval = PTR_ERR(context->bg_thread); ++ context->bg_thread = NULL; ++ context->bg_running = 0; ++ } ++ return retval; ++} ++ ++static void yaffs_bg_stop(struct yaffs_dev *dev) ++{ ++ struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev); ++ ++ ctxt->bg_running = 0; ++ ++ if (ctxt->bg_thread) { ++ kthread_stop(ctxt->bg_thread); ++ ctxt->bg_thread = NULL; ++ } ++} ++#else ++static int yaffs_bg_thread_fn(void *data) ++{ ++ return 0; ++} ++ ++static int yaffs_bg_start(struct yaffs_dev *dev) ++{ ++ return 0; ++} ++ ++static void yaffs_bg_stop(struct yaffs_dev *dev) ++{ ++} ++#endif ++ ++ ++static void yaffs_flush_inodes(struct super_block *sb) ++{ ++ struct inode *iptr; ++ struct yaffs_obj *obj; ++ ++ list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) { ++ obj = yaffs_inode_to_obj(iptr); ++ if (obj) { ++ yaffs_trace(YAFFS_TRACE_OS, ++ "flushing obj %d", ++ obj->obj_id); ++ yaffs_flush_file(obj, 1, 0); ++ } ++ } ++} ++ ++static void yaffs_flush_super(struct super_block *sb, int do_checkpoint) ++{ ++ struct yaffs_dev *dev = yaffs_super_to_dev(sb); ++ if (!dev) ++ return; ++ ++ yaffs_flush_inodes(sb); ++ yaffs_update_dirty_dirs(dev); ++ yaffs_flush_whole_cache(dev); ++ if (do_checkpoint) ++ yaffs_checkpoint_save(dev); ++} ++ ++static LIST_HEAD(yaffs_context_list); ++struct mutex yaffs_context_lock; ++ ++static void yaffs_put_super(struct super_block *sb) ++{ ++ struct yaffs_dev *dev = yaffs_super_to_dev(sb); ++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); ++ ++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS, ++ "yaffs_put_super"); ++ ++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, ++ "Shutting down yaffs background thread"); ++ yaffs_bg_stop(dev); ++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, ++ "yaffs background thread shut down"); ++ ++ yaffs_gross_lock(dev); ++ ++ yaffs_flush_super(sb, 1); ++ ++ yaffs_deinitialise(dev); ++ ++ yaffs_gross_unlock(dev); ++ ++ mutex_lock(&yaffs_context_lock); ++ list_del_init(&(yaffs_dev_to_lc(dev)->context_list)); ++ mutex_unlock(&yaffs_context_lock); ++ ++ if (yaffs_dev_to_lc(dev)->spare_buffer) { ++ kfree(yaffs_dev_to_lc(dev)->spare_buffer); ++ yaffs_dev_to_lc(dev)->spare_buffer = NULL; ++ } ++ ++ kfree(dev); ++ ++ yaffs_put_mtd_device(mtd); ++ ++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS, ++ "yaffs_put_super done"); ++} ++ ++ ++static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev) ++{ ++ return yaffs_gc_control; ++} ++ ++ ++#ifdef YAFFS_COMPILE_EXPORTFS ++ ++static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, ++ uint32_t generation) ++{ ++ return Y_IGET(sb, ino); ++} ++ ++static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb, ++ struct fid *fid, int fh_len, ++ int fh_type) ++{ ++ return generic_fh_to_dentry(sb, fid, fh_len, fh_type, ++ yaffs2_nfs_get_inode); ++} ++ ++static struct dentry *yaffs2_fh_to_parent(struct super_block *sb, ++ struct fid *fid, int fh_len, ++ int fh_type) ++{ ++ return generic_fh_to_parent(sb, fid, fh_len, fh_type, ++ yaffs2_nfs_get_inode); ++} ++ ++struct dentry *yaffs2_get_parent(struct dentry *dentry) ++{ ++ ++ struct super_block *sb = dentry->d_inode->i_sb; ++ struct dentry *parent = ERR_PTR(-ENOENT); ++ struct inode *inode; ++ unsigned long parent_ino; ++ struct yaffs_obj *d_obj; ++ struct yaffs_obj *parent_obj; ++ ++ d_obj = yaffs_inode_to_obj(dentry->d_inode); ++ ++ if (d_obj) { ++ parent_obj = d_obj->parent; ++ if (parent_obj) { ++ parent_ino = yaffs_get_obj_inode(parent_obj); ++ inode = Y_IGET(sb, parent_ino); ++ ++ if (IS_ERR(inode)) { ++ parent = ERR_CAST(inode); ++ } else { ++ parent = d_obtain_alias(inode); ++ if (!IS_ERR(parent)) { ++ parent = ERR_PTR(-ENOMEM); ++ iput(inode); ++ } ++ } ++ } ++ } ++ ++ return parent; ++} ++ ++/* Just declare a zero structure as a NULL value implies ++ * using the default functions of exportfs. ++ */ ++ ++static struct export_operations yaffs_export_ops = { ++ .fh_to_dentry = yaffs2_fh_to_dentry, ++ .fh_to_parent = yaffs2_fh_to_parent, ++ .get_parent = yaffs2_get_parent, ++}; ++ ++#endif ++ ++static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj) ++{ ++ /* Clear the association between the inode and ++ * the struct yaffs_obj. ++ */ ++ obj->my_inode = NULL; ++ yaffs_inode_to_obj_lv(inode) = NULL; ++ ++ /* If the object freeing was deferred, then the real ++ * free happens now. ++ * This should fix the inode inconsistency problem. ++ */ ++ yaffs_handle_defered_free(obj); ++} ++ ++#ifdef YAFFS_HAS_EVICT_INODE ++/* yaffs_evict_inode combines into one operation what was previously done in ++ * yaffs_clear_inode() and yaffs_delete_inode() ++ * ++ */ ++static void yaffs_evict_inode(struct inode *inode) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev; ++ int deleteme = 0; ++ ++ obj = yaffs_inode_to_obj(inode); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_evict_inode: ino %d, count %d %s", ++ (int)inode->i_ino, atomic_read(&inode->i_count), ++ obj ? "object exists" : "null object"); ++ ++ if (!inode->i_nlink && !is_bad_inode(inode)) ++ deleteme = 1; ++ truncate_inode_pages(&inode->i_data, 0); ++ Y_CLEAR_INODE(inode); ++ ++ if (deleteme && obj) { ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ yaffs_del_obj(obj); ++ yaffs_gross_unlock(dev); ++ } ++ if (obj) { ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ yaffs_unstitch_obj(inode, obj); ++ yaffs_gross_unlock(dev); ++ } ++} ++#else ++ ++/* clear is called to tell the fs to release any per-inode data it holds. ++ * The object might still exist on disk and is just being thrown out of the cache ++ * or else the object has actually been deleted and we're being called via ++ * the chain ++ * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode() ++ */ ++ ++static void yaffs_clear_inode(struct inode *inode) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_dev *dev; ++ ++ obj = yaffs_inode_to_obj(inode); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_clear_inode: ino %d, count %d %s", ++ (int)inode->i_ino, atomic_read(&inode->i_count), ++ obj ? "object exists" : "null object"); ++ ++ if (obj) { ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ yaffs_unstitch_obj(inode, obj); ++ yaffs_gross_unlock(dev); ++ } ++ ++} ++ ++/* delete is called when the link count is zero and the inode ++ * is put (ie. nobody wants to know about it anymore, time to ++ * delete the file). ++ * NB Must call clear_inode() ++ */ ++static void yaffs_delete_inode(struct inode *inode) ++{ ++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode); ++ struct yaffs_dev *dev; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_delete_inode: ino %d, count %d %s", ++ (int)inode->i_ino, atomic_read(&inode->i_count), ++ obj ? "object exists" : "null object"); ++ ++ if (obj) { ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ yaffs_del_obj(obj); ++ yaffs_gross_unlock(dev); ++ } ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) ++ truncate_inode_pages(&inode->i_data, 0); ++#endif ++ clear_inode(inode); ++} ++#endif ++ ++ ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev; ++ struct super_block *sb = dentry->d_sb; ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf) ++{ ++ struct yaffs_dev *dev = yaffs_super_to_dev(sb); ++#else ++static int yaffs_statfs(struct super_block *sb, struct statfs *buf) ++{ ++ struct yaffs_dev *dev = yaffs_super_to_dev(sb); ++#endif ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_statfs"); ++ ++ yaffs_gross_lock(dev); ++ ++ buf->f_type = YAFFS_MAGIC; ++ buf->f_bsize = sb->s_blocksize; ++ buf->f_namelen = 255; ++ ++ if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) { ++ /* Do this if chunk size is not a power of 2 */ ++ ++ uint64_t bytes_in_dev; ++ uint64_t bytes_free; ++ ++ bytes_in_dev = ++ ((uint64_t) ++ ((dev->param.end_block - dev->param.start_block + ++ 1))) * ((uint64_t) (dev->param.chunks_per_block * ++ dev->data_bytes_per_chunk)); ++ ++ do_div(bytes_in_dev, sb->s_blocksize); /* bytes_in_dev becomes the number of blocks */ ++ buf->f_blocks = bytes_in_dev; ++ ++ bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) * ++ ((uint64_t) (dev->data_bytes_per_chunk)); ++ ++ do_div(bytes_free, sb->s_blocksize); ++ ++ buf->f_bfree = bytes_free; ++ ++ } else if (sb->s_blocksize > dev->data_bytes_per_chunk) { ++ ++ buf->f_blocks = ++ (dev->param.end_block - dev->param.start_block + 1) * ++ dev->param.chunks_per_block / ++ (sb->s_blocksize / dev->data_bytes_per_chunk); ++ buf->f_bfree = ++ yaffs_get_n_free_chunks(dev) / ++ (sb->s_blocksize / dev->data_bytes_per_chunk); ++ } else { ++ buf->f_blocks = ++ (dev->param.end_block - dev->param.start_block + 1) * ++ dev->param.chunks_per_block * ++ (dev->data_bytes_per_chunk / sb->s_blocksize); ++ ++ buf->f_bfree = ++ yaffs_get_n_free_chunks(dev) * ++ (dev->data_bytes_per_chunk / sb->s_blocksize); ++ } ++ ++ buf->f_files = 0; ++ buf->f_ffree = 0; ++ buf->f_bavail = buf->f_bfree; ++ ++ yaffs_gross_unlock(dev); ++ return 0; ++} ++ ++ ++ ++static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint) ++{ ++ ++ struct yaffs_dev *dev = yaffs_super_to_dev(sb); ++ unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4); ++ unsigned gc_urgent = yaffs_bg_gc_urgency(dev); ++ int do_checkpoint; ++ int dirty = yaffs_check_super_dirty(dev); ++ ++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND, ++ "yaffs_do_sync_fs: gc-urgency %d %s %s%s", ++ gc_urgent, ++ dirty ? "dirty" : "clean", ++ request_checkpoint ? "checkpoint requested" : "no checkpoint", ++ oneshot_checkpoint ? " one-shot" : ""); ++ ++ yaffs_gross_lock(dev); ++ do_checkpoint = ((request_checkpoint && !gc_urgent) || ++ oneshot_checkpoint) && !dev->is_checkpointed; ++ ++ if (dirty || do_checkpoint) { ++ yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint); ++ yaffs_clear_super_dirty(dev); ++ if (oneshot_checkpoint) ++ yaffs_auto_checkpoint &= ~4; ++ } ++ yaffs_gross_unlock(dev); ++ ++ return 0; ++} ++ ++ ++#ifdef YAFFS_HAS_WRITE_SUPER ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static void yaffs_write_super(struct super_block *sb) ++#else ++static int yaffs_write_super(struct super_block *sb) ++#endif ++{ ++ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2); ++ ++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND, ++ "yaffs_write_super %s", ++ request_checkpoint ? " checkpt" : ""); ++ ++ yaffs_do_sync_fs(sb, request_checkpoint); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) ++ return 0; ++#endif ++} ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_sync_fs(struct super_block *sb, int wait) ++#else ++static int yaffs_sync_fs(struct super_block *sb) ++#endif ++{ ++ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1); ++ ++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, ++ "yaffs_sync_fs%s", request_checkpoint ? " checkpt" : ""); ++ ++ yaffs_do_sync_fs(sb, request_checkpoint); ++ ++ return 0; ++} ++ ++ ++ ++static const struct super_operations yaffs_super_ops = { ++ .statfs = yaffs_statfs, ++ ++#ifndef YAFFS_USE_OWN_IGET ++ .read_inode = yaffs_read_inode, ++#endif ++#ifdef YAFFS_HAS_PUT_INODE ++ .put_inode = yaffs_put_inode, ++#endif ++ .put_super = yaffs_put_super, ++#ifdef YAFFS_HAS_EVICT_INODE ++ .evict_inode = yaffs_evict_inode, ++#else ++ .delete_inode = yaffs_delete_inode, ++ .clear_inode = yaffs_clear_inode, ++#endif ++ .sync_fs = yaffs_sync_fs, ++#ifdef YAFFS_HAS_WRITE_SUPER ++ .write_super = yaffs_write_super, ++#endif ++}; ++ ++struct yaffs_options { ++ int inband_tags; ++ int skip_checkpoint_read; ++ int skip_checkpoint_write; ++ int no_cache; ++ int tags_ecc_on; ++ int tags_ecc_overridden; ++ int lazy_loading_enabled; ++ int lazy_loading_overridden; ++ int empty_lost_and_found; ++ int empty_lost_and_found_overridden; ++ int disable_summary; ++}; ++ ++#define MAX_OPT_LEN 30 ++static int yaffs_parse_options(struct yaffs_options *options, ++ const char *options_str) ++{ ++ char cur_opt[MAX_OPT_LEN + 1]; ++ int p; ++ int error = 0; ++ ++ /* Parse through the options which is a comma seperated list */ ++ ++ while (options_str && *options_str && !error) { ++ memset(cur_opt, 0, MAX_OPT_LEN + 1); ++ p = 0; ++ ++ while (*options_str == ',') ++ options_str++; ++ ++ while (*options_str && *options_str != ',') { ++ if (p < MAX_OPT_LEN) { ++ cur_opt[p] = *options_str; ++ p++; ++ } ++ options_str++; ++ } ++ ++ if (!strcmp(cur_opt, "inband-tags")) { ++ options->inband_tags = 1; ++ } else if (!strcmp(cur_opt, "tags-ecc-off")) { ++ options->tags_ecc_on = 0; ++ options->tags_ecc_overridden = 1; ++ } else if (!strcmp(cur_opt, "tags-ecc-on")) { ++ options->tags_ecc_on = 1; ++ options->tags_ecc_overridden = 1; ++ } else if (!strcmp(cur_opt, "lazy-loading-off")) { ++ options->lazy_loading_enabled = 0; ++ options->lazy_loading_overridden = 1; ++ } else if (!strcmp(cur_opt, "lazy-loading-on")) { ++ options->lazy_loading_enabled = 1; ++ options->lazy_loading_overridden = 1; ++ } else if (!strcmp(cur_opt, "disable-summary")) { ++ options->disable_summary = 1; ++ } else if (!strcmp(cur_opt, "empty-lost-and-found-off")) { ++ options->empty_lost_and_found = 0; ++ options->empty_lost_and_found_overridden = 1; ++ } else if (!strcmp(cur_opt, "empty-lost-and-found-on")) { ++ options->empty_lost_and_found = 1; ++ options->empty_lost_and_found_overridden = 1; ++ } else if (!strcmp(cur_opt, "no-cache")) { ++ options->no_cache = 1; ++ } else if (!strcmp(cur_opt, "no-checkpoint-read")) { ++ options->skip_checkpoint_read = 1; ++ } else if (!strcmp(cur_opt, "no-checkpoint-write")) { ++ options->skip_checkpoint_write = 1; ++ } else if (!strcmp(cur_opt, "no-checkpoint")) { ++ options->skip_checkpoint_read = 1; ++ options->skip_checkpoint_write = 1; ++ } else { ++ printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n", ++ cur_opt); ++ error = 1; ++ } ++ } ++ ++ return error; ++} ++ ++ ++static struct dentry *yaffs_make_root(struct inode *inode) ++{ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) ++ struct dentry *root = d_alloc_root(inode); ++ ++ if (!root) ++ iput(inode); ++ ++ return root; ++#else ++ return d_make_root(inode); ++#endif ++} ++ ++ ++ ++ ++static struct super_block *yaffs_internal_read_super(int yaffs_version, ++ struct super_block *sb, ++ void *data, int silent) ++{ ++ int n_blocks; ++ struct inode *inode = NULL; ++ struct dentry *root; ++ struct yaffs_dev *dev = 0; ++ char devname_buf[BDEVNAME_SIZE + 1]; ++ struct mtd_info *mtd; ++ int err; ++ char *data_str = (char *)data; ++ struct yaffs_linux_context *context = NULL; ++ struct yaffs_param *param; ++ ++ int read_only = 0; ++ int inband_tags = 0; ++ ++ struct yaffs_options options; ++ ++ unsigned mount_id; ++ int found; ++ struct yaffs_linux_context *context_iterator; ++ struct list_head *l; ++ ++ if (!sb) { ++ printk(KERN_INFO "yaffs: sb is NULL\n"); ++ return NULL; ++ } ++ ++ sb->s_magic = YAFFS_MAGIC; ++ sb->s_op = &yaffs_super_ops; ++ sb->s_flags |= MS_NOATIME; ++ ++ read_only = ((sb->s_flags & MS_RDONLY) != 0); ++ ++#ifdef YAFFS_COMPILE_EXPORTFS ++ sb->s_export_op = &yaffs_export_ops; ++#endif ++ ++ if (!sb->s_dev) ++ printk(KERN_INFO "yaffs: sb->s_dev is NULL\n"); ++ else if (!yaffs_devname(sb, devname_buf)) ++ printk(KERN_INFO "yaffs: devname is NULL\n"); ++ else ++ printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n", ++ sb->s_dev, ++ yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw"); ++ ++ if (!data_str) ++ data_str = ""; ++ ++ printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str); ++ ++ memset(&options, 0, sizeof(options)); ++ ++ if (yaffs_parse_options(&options, data_str)) { ++ /* Option parsing failed */ ++ return NULL; ++ } ++ ++ sb->s_blocksize = PAGE_CACHE_SIZE; ++ sb->s_blocksize_bits = PAGE_CACHE_SHIFT; ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_read_super: Using yaffs%d", yaffs_version); ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_read_super: block size %d", (int)(sb->s_blocksize)); ++ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs: Attempting MTD mount of %u.%u,\"%s\"", ++ MAJOR(sb->s_dev), MINOR(sb->s_dev), ++ yaffs_devname(sb, devname_buf)); ++ ++ /* Get the device */ ++ mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); ++ if (IS_ERR(mtd)) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs: MTD device %u either not valid or unavailable", ++ MINOR(sb->s_dev)); ++ return NULL; ++ } ++ ++ if (yaffs_auto_select && yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2"); ++ yaffs_version = 2; ++ } ++ ++ /* Added NCB 26/5/2006 for completeness */ ++ if (yaffs_version == 2 && !options.inband_tags ++ && WRITE_SIZE(mtd) == 512) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1"); ++ yaffs_version = 1; ++ } ++ ++ if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) || ++ options.inband_tags) ++ inband_tags = 1; ++ ++ if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0) ++ return NULL; ++ ++ /* OK, so if we got here, we have an MTD that's NAND and looks ++ * like it has the right capabilities ++ * Set the struct yaffs_dev up for mtd ++ */ ++ ++ if (!read_only && !(mtd->flags & MTD_WRITEABLE)) { ++ read_only = 1; ++ printk(KERN_INFO ++ "yaffs: mtd is read only, setting superblock read only\n" ++ ); ++ sb->s_flags |= MS_RDONLY; ++ } ++ ++ dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL); ++ context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL); ++ ++ if (!dev || !context) { ++ kfree(dev); ++ kfree(context); ++ dev = NULL; ++ context = NULL; ++ ++ /* Deep shit could not allocate device structure */ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs_read_super: Failed trying to allocate struct yaffs_dev." ++ ); ++ return NULL; ++ } ++ memset(dev, 0, sizeof(struct yaffs_dev)); ++ param = &(dev->param); ++ ++ memset(context, 0, sizeof(struct yaffs_linux_context)); ++ dev->os_context = context; ++ INIT_LIST_HEAD(&(context->context_list)); ++ context->dev = dev; ++ context->super = sb; ++ ++ dev->read_only = read_only; ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ sb->s_fs_info = dev; ++#else ++ sb->u.generic_sbp = dev; ++#endif ++ ++ ++ dev->driver_context = mtd; ++ param->name = mtd->name; ++ ++ /* Set up the memory size parameters.... */ ++ ++ ++ param->n_reserved_blocks = 5; ++ param->n_caches = (options.no_cache) ? 0 : 10; ++ param->inband_tags = inband_tags; ++ ++ param->enable_xattr = 1; ++ if (options.lazy_loading_overridden) ++ param->disable_lazy_load = !options.lazy_loading_enabled; ++ ++ param->defered_dir_update = 1; ++ ++ if (options.tags_ecc_overridden) ++ param->no_tags_ecc = !options.tags_ecc_on; ++ ++ param->empty_lost_n_found = 1; ++ param->refresh_period = 500; ++ param->disable_summary = options.disable_summary; ++ ++ ++#ifdef CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING ++ param->disable_bad_block_marking = 1; ++#endif ++ if (options.empty_lost_and_found_overridden) ++ param->empty_lost_n_found = options.empty_lost_and_found; ++ ++ /* ... and the functions. */ ++ if (yaffs_version == 2) { ++ param->is_yaffs2 = 1; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++ param->total_bytes_per_chunk = mtd->writesize; ++ param->chunks_per_block = mtd->erasesize / mtd->writesize; ++#else ++ param->total_bytes_per_chunk = mtd->oobblock; ++ param->chunks_per_block = mtd->erasesize / mtd->oobblock; ++#endif ++ n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize); ++ ++ param->start_block = 0; ++ param->end_block = n_blocks - 1; ++ } else { ++ param->is_yaffs2 = 0; ++ n_blocks = YCALCBLOCKS(mtd->size, ++ YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK); ++ ++ param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK; ++ param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK; ++ } ++ ++ param->start_block = 0; ++ param->end_block = n_blocks - 1; ++ ++ yaffs_mtd_drv_install(dev); ++ ++ param->sb_dirty_fn = yaffs_set_super_dirty; ++ param->gc_control_fn = yaffs_gc_control_callback; ++ ++ yaffs_dev_to_lc(dev)->super = sb; ++ ++ param->use_nand_ecc = 1; ++ ++ param->skip_checkpt_rd = options.skip_checkpoint_read; ++ param->skip_checkpt_wr = options.skip_checkpoint_write; ++ ++ mutex_lock(&yaffs_context_lock); ++ /* Get a mount id */ ++ found = 0; ++ for (mount_id = 0; !found; mount_id++) { ++ found = 1; ++ list_for_each(l, &yaffs_context_list) { ++ context_iterator = ++ list_entry(l, struct yaffs_linux_context, ++ context_list); ++ if (context_iterator->mount_id == mount_id) ++ found = 0; ++ } ++ } ++ context->mount_id = mount_id; ++ ++ list_add_tail(&(yaffs_dev_to_lc(dev)->context_list), ++ &yaffs_context_list); ++ mutex_unlock(&yaffs_context_lock); ++ ++ /* Directory search handling... */ ++ INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts)); ++ param->remove_obj_fn = yaffs_remove_obj_callback; ++ ++ mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock)); ++ ++ yaffs_gross_lock(dev); ++ ++ err = yaffs_guts_initialise(dev); ++ ++ yaffs_trace(YAFFS_TRACE_OS, ++ "yaffs_read_super: guts initialised %s", ++ (err == YAFFS_OK) ? "OK" : "FAILED"); ++ ++ if (err == YAFFS_OK) ++ yaffs_bg_start(dev); ++ ++ if (!context->bg_thread) ++ param->defered_dir_update = 0; ++ ++ sb->s_maxbytes = yaffs_max_file_size(dev); ++ ++ /* Release lock before yaffs_get_inode() */ ++ yaffs_gross_unlock(dev); ++ ++ /* Create root inode */ ++ if (err == YAFFS_OK) ++ inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, yaffs_root(dev)); ++ ++ if (!inode) ++ return NULL; ++ ++ inode->i_op = &yaffs_dir_inode_operations; ++ inode->i_fop = &yaffs_dir_operations; ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: got root inode"); ++ ++ root = yaffs_make_root(inode); ++ ++ if (!root) ++ return NULL; ++ ++ sb->s_root = root; ++ if(!dev->is_checkpointed) ++ yaffs_set_super_dirty(dev); ++ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs_read_super: is_checkpointed %d", ++ dev->is_checkpointed); ++ ++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: done"); ++ return sb; ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data, ++ int silent) ++{ ++ return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL; ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++static struct dentry *yaffs_mount(struct file_system_type *fs_type, int flags, ++ const char *dev_name, void *data) ++{ ++ return mount_bdev(fs_type, flags, dev_name, data, yaffs_internal_read_super_mtd); ++} ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_read_super(struct file_system_type *fs, ++ int flags, const char *dev_name, ++ void *data, struct vfsmount *mnt) ++{ ++ ++ return get_sb_bdev(fs, flags, dev_name, data, ++ yaffs_internal_read_super_mtd, mnt); ++} ++#else ++static struct super_block *yaffs_read_super(struct file_system_type *fs, ++ int flags, const char *dev_name, ++ void *data) ++{ ++ ++ return get_sb_bdev(fs, flags, dev_name, data, ++ yaffs_internal_read_super_mtd); ++} ++#endif ++ ++static struct file_system_type yaffs_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "yaffs", ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++ .mount = yaffs_mount, ++#else ++ .get_sb = yaffs_read_super, ++#endif ++ .kill_sb = kill_block_super, ++ .fs_flags = FS_REQUIRES_DEV, ++}; ++#else ++static struct super_block *yaffs_read_super(struct super_block *sb, void *data, ++ int silent) ++{ ++ return yaffs_internal_read_super(1, sb, data, silent); ++} ++ ++static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super, ++ FS_REQUIRES_DEV); ++#endif ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data, ++ int silent) ++{ ++ return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL; ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++static struct dentry *yaffs2_mount(struct file_system_type *fs_type, int flags, ++ const char *dev_name, void *data) ++{ ++ return mount_bdev(fs_type, flags, dev_name, data, yaffs2_internal_read_super_mtd); ++} ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs2_read_super(struct file_system_type *fs, ++ int flags, const char *dev_name, void *data, ++ struct vfsmount *mnt) ++{ ++ return get_sb_bdev(fs, flags, dev_name, data, ++ yaffs2_internal_read_super_mtd, mnt); ++} ++#else ++static struct super_block *yaffs2_read_super(struct file_system_type *fs, ++ int flags, const char *dev_name, ++ void *data) ++{ ++ ++ return get_sb_bdev(fs, flags, dev_name, data, ++ yaffs2_internal_read_super_mtd); ++} ++#endif ++ ++static struct file_system_type yaffs2_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "yaffs2", ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++ .mount = yaffs2_mount, ++#else ++ .get_sb = yaffs2_read_super, ++#endif ++ .kill_sb = kill_block_super, ++ .fs_flags = FS_REQUIRES_DEV, ++}; ++#else ++static struct super_block *yaffs2_read_super(struct super_block *sb, ++ void *data, int silent) ++{ ++ return yaffs_internal_read_super(2, sb, data, silent); ++} ++ ++static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super, ++ FS_REQUIRES_DEV); ++#endif ++ ++ ++static struct proc_dir_entry *my_proc_entry; ++ ++static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev) ++{ ++ struct yaffs_param *param = &dev->param; ++ int bs[10]; ++ ++ yaffs_count_blocks_by_state(dev,bs); ++ ++ buf += sprintf(buf, "start_block.......... %d\n", param->start_block); ++ buf += sprintf(buf, "end_block............ %d\n", param->end_block); ++ buf += sprintf(buf, "total_bytes_per_chunk %d\n", ++ param->total_bytes_per_chunk); ++ buf += sprintf(buf, "use_nand_ecc......... %d\n", param->use_nand_ecc); ++ buf += sprintf(buf, "no_tags_ecc.......... %d\n", param->no_tags_ecc); ++ buf += sprintf(buf, "is_yaffs2............ %d\n", param->is_yaffs2); ++ buf += sprintf(buf, "inband_tags.......... %d\n", param->inband_tags); ++ buf += sprintf(buf, "empty_lost_n_found... %d\n", ++ param->empty_lost_n_found); ++ buf += sprintf(buf, "disable_lazy_load.... %d\n", ++ param->disable_lazy_load); ++ buf += sprintf(buf, "disable_bad_block_mrk %d\n", ++ param->disable_bad_block_marking); ++ buf += sprintf(buf, "refresh_period....... %d\n", ++ param->refresh_period); ++ buf += sprintf(buf, "n_caches............. %d\n", param->n_caches); ++ buf += sprintf(buf, "n_reserved_blocks.... %d\n", ++ param->n_reserved_blocks); ++ buf += sprintf(buf, "always_check_erased.. %d\n", ++ param->always_check_erased); ++ buf += sprintf(buf, "\n"); ++ buf += sprintf(buf, "block count by state\n"); ++ buf += sprintf(buf, "0:%d 1:%d 2:%d 3:%d 4:%d\n", ++ bs[0], bs[1], bs[2], bs[3], bs[4]); ++ buf += sprintf(buf, "5:%d 6:%d 7:%d 8:%d 9:%d\n", ++ bs[5], bs[6], bs[7], bs[8], bs[9]); ++ ++ return buf; ++} ++ ++static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev) ++{ ++ buf += sprintf(buf, "max file size....... %lld\n", ++ (long long) yaffs_max_file_size(dev)); ++ buf += sprintf(buf, "data_bytes_per_chunk. %d\n", ++ dev->data_bytes_per_chunk); ++ buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits); ++ buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size); ++ buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks); ++ buf += sprintf(buf, "blocks_in_checkpt.... %d\n", ++ dev->blocks_in_checkpt); ++ buf += sprintf(buf, "\n"); ++ buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes); ++ buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj); ++ buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks); ++ buf += sprintf(buf, "\n"); ++ buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes); ++ buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads); ++ buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures); ++ buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies); ++ buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs); ++ buf += sprintf(buf, "passive_gc_count..... %u\n", ++ dev->passive_gc_count); ++ buf += sprintf(buf, "oldest_dirty_gc_count %u\n", ++ dev->oldest_dirty_gc_count); ++ buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks); ++ buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs); ++ buf += sprintf(buf, "n_retried_writes..... %u\n", ++ dev->n_retried_writes); ++ buf += sprintf(buf, "n_retired_blocks..... %u\n", ++ dev->n_retired_blocks); ++ buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed); ++ buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed); ++ buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n", ++ dev->n_tags_ecc_fixed); ++ buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n", ++ dev->n_tags_ecc_unfixed); ++ buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits); ++ buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files); ++ buf += sprintf(buf, "n_unlinked_files..... %u\n", ++ dev->n_unlinked_files); ++ buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count); ++ buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions); ++ buf += sprintf(buf, "tags_used............ %u\n", dev->tags_used); ++ buf += sprintf(buf, "summary_used......... %u\n", dev->summary_used); ++ ++ return buf; ++} ++ ++static int yaffs_proc_read(char *page, ++ char **start, ++ off_t offset, int count, int *eof, void *data) ++{ ++ struct list_head *item; ++ char *buf = page; ++ int step = offset; ++ int n = 0; ++ ++ /* Get proc_file_read() to step 'offset' by one on each sucessive call. ++ * We use 'offset' (*ppos) to indicate where we are in dev_list. ++ * This also assumes the user has posted a read buffer large ++ * enough to hold the complete output; but that's life in /proc. ++ */ ++ ++ *(int *)start = 1; ++ ++ /* Print header first */ ++ if (step == 0) ++ buf += ++ sprintf(buf, ++ "Multi-version YAFFS built:" __DATE__ " " __TIME__ ++ "\n"); ++ else if (step == 1) ++ buf += sprintf(buf, "\n"); ++ else { ++ step -= 2; ++ ++ mutex_lock(&yaffs_context_lock); ++ ++ /* Locate and print the Nth entry. Order N-squared but N is small. */ ++ list_for_each(item, &yaffs_context_list) { ++ struct yaffs_linux_context *dc = ++ list_entry(item, struct yaffs_linux_context, ++ context_list); ++ struct yaffs_dev *dev = dc->dev; ++ ++ if (n < (step & ~1)) { ++ n += 2; ++ continue; ++ } ++ if ((step & 1) == 0) { ++ buf += ++ sprintf(buf, "\nDevice %d \"%s\"\n", n, ++ dev->param.name); ++ buf = yaffs_dump_dev_part0(buf, dev); ++ } else { ++ buf = yaffs_dump_dev_part1(buf, dev); ++ } ++ ++ break; ++ } ++ mutex_unlock(&yaffs_context_lock); ++ } ++ ++ return buf - page < count ? buf - page : count; ++} ++ ++/** ++ * Set the verbosity of the warnings and error messages. ++ * ++ * Note that the names can only be a..z or _ with the current code. ++ */ ++ ++static struct { ++ char *mask_name; ++ unsigned mask_bitfield; ++} mask_flags[] = { ++ {"allocate", YAFFS_TRACE_ALLOCATE}, ++ {"always", YAFFS_TRACE_ALWAYS}, ++ {"background", YAFFS_TRACE_BACKGROUND}, ++ {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS}, ++ {"buffers", YAFFS_TRACE_BUFFERS}, ++ {"bug", YAFFS_TRACE_BUG}, ++ {"checkpt", YAFFS_TRACE_CHECKPOINT}, ++ {"deletion", YAFFS_TRACE_DELETION}, ++ {"erase", YAFFS_TRACE_ERASE}, ++ {"error", YAFFS_TRACE_ERROR}, ++ {"gc_detail", YAFFS_TRACE_GC_DETAIL}, ++ {"gc", YAFFS_TRACE_GC}, ++ {"lock", YAFFS_TRACE_LOCK}, ++ {"mtd", YAFFS_TRACE_MTD}, ++ {"nandaccess", YAFFS_TRACE_NANDACCESS}, ++ {"os", YAFFS_TRACE_OS}, ++ {"scan_debug", YAFFS_TRACE_SCAN_DEBUG}, ++ {"scan", YAFFS_TRACE_SCAN}, ++ {"mount", YAFFS_TRACE_MOUNT}, ++ {"tracing", YAFFS_TRACE_TRACING}, ++ {"sync", YAFFS_TRACE_SYNC}, ++ {"write", YAFFS_TRACE_WRITE}, ++ {"verify", YAFFS_TRACE_VERIFY}, ++ {"verify_nand", YAFFS_TRACE_VERIFY_NAND}, ++ {"verify_full", YAFFS_TRACE_VERIFY_FULL}, ++ {"verify_all", YAFFS_TRACE_VERIFY_ALL}, ++ {"all", 0xffffffff}, ++ {"none", 0}, ++ {NULL, 0}, ++}; ++ ++#define MAX_MASK_NAME_LENGTH 40 ++static int yaffs_proc_write_trace_options(struct file *file, const char *buf, ++ unsigned long count, void *data) ++{ ++ unsigned rg = 0, mask_bitfield; ++ char *end; ++ char *mask_name; ++ const char *x; ++ char substring[MAX_MASK_NAME_LENGTH + 1]; ++ int i; ++ int done = 0; ++ int add, len = 0; ++ int pos = 0; ++ ++ rg = yaffs_trace_mask; ++ ++ while (!done && (pos < count)) { ++ done = 1; ++ while ((pos < count) && isspace(buf[pos])) ++ pos++; ++ ++ switch (buf[pos]) { ++ case '+': ++ case '-': ++ case '=': ++ add = buf[pos]; ++ pos++; ++ break; ++ ++ default: ++ add = ' '; ++ break; ++ } ++ mask_name = NULL; ++ ++ mask_bitfield = simple_strtoul(buf + pos, &end, 0); ++ ++ if (end > buf + pos) { ++ mask_name = "numeral"; ++ len = end - (buf + pos); ++ pos += len; ++ done = 0; ++ } else { ++ for (x = buf + pos, i = 0; ++ (*x == '_' || (*x >= 'a' && *x <= 'z')) && ++ i < MAX_MASK_NAME_LENGTH; x++, i++, pos++) ++ substring[i] = *x; ++ substring[i] = '\0'; ++ ++ for (i = 0; mask_flags[i].mask_name != NULL; i++) { ++ if (strcmp(substring, mask_flags[i].mask_name) ++ == 0) { ++ mask_name = mask_flags[i].mask_name; ++ mask_bitfield = ++ mask_flags[i].mask_bitfield; ++ done = 0; ++ break; ++ } ++ } ++ } ++ ++ if (mask_name != NULL) { ++ done = 0; ++ switch (add) { ++ case '-': ++ rg &= ~mask_bitfield; ++ break; ++ case '+': ++ rg |= mask_bitfield; ++ break; ++ case '=': ++ rg = mask_bitfield; ++ break; ++ default: ++ rg |= mask_bitfield; ++ break; ++ } ++ } ++ } ++ ++ yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS; ++ ++ printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask); ++ ++ if (rg & YAFFS_TRACE_ALWAYS) { ++ for (i = 0; mask_flags[i].mask_name != NULL; i++) { ++ char flag; ++ flag = ((rg & mask_flags[i].mask_bitfield) == ++ mask_flags[i].mask_bitfield) ? '+' : '-'; ++ printk(KERN_DEBUG "%c%s\n", flag, ++ mask_flags[i].mask_name); ++ } ++ } ++ ++ return count; ++} ++ ++/* Debug strings are of the form: ++ * .bnnn print info on block n ++ * .cobjn,chunkn print nand chunk id for objn:chunkn ++ */ ++ ++static int yaffs_proc_debug_write(struct file *file, const char *buf, ++ unsigned long count, void *data) ++{ ++ ++ char str[100]; ++ char *p0; ++ char *p1; ++ long p1_val; ++ long p0_val; ++ char cmd; ++ struct list_head *item; ++ ++ memset(str, 0, sizeof(str)); ++ memcpy(str, buf, min((size_t)count, sizeof(str) -1)); ++ ++ cmd = str[1]; ++ ++ p0 = str + 2; ++ ++ p1 = p0; ++ ++ while (*p1 && *p1 != ',') { ++ p1++; ++ } ++ *p1 = '\0'; ++ p1++; ++ ++ p0_val = simple_strtol(p0, NULL, 0); ++ p1_val = simple_strtol(p1, NULL, 0); ++ ++ ++ mutex_lock(&yaffs_context_lock); ++ ++ /* Locate and print the Nth entry. Order N-squared but N is small. */ ++ list_for_each(item, &yaffs_context_list) { ++ struct yaffs_linux_context *dc = ++ list_entry(item, struct yaffs_linux_context, ++ context_list); ++ struct yaffs_dev *dev = dc->dev; ++ ++ if (cmd == 'b') { ++ struct yaffs_block_info *bi; ++ ++ bi = yaffs_get_block_info(dev,p0_val); ++ ++ if(bi) { ++ printk("Block %d: state %d, retire %d, use %d, seq %d\n", ++ (int)p0_val, bi->block_state, ++ bi->needs_retiring, bi->pages_in_use, ++ bi->seq_number); ++ } ++ } else if (cmd == 'c') { ++ struct yaffs_obj *obj; ++ int nand_chunk; ++ ++ obj = yaffs_find_by_number(dev, p0_val); ++ if (!obj) ++ printk("No obj %d\n", (int)p0_val); ++ else { ++ if(p1_val == 0) ++ nand_chunk = obj->hdr_chunk; ++ else ++ nand_chunk = ++ yaffs_find_chunk_in_file(obj, ++ p1_val, NULL); ++ printk("Nand chunk for %d:%d is %d\n", ++ (int)p0_val, (int)p1_val, nand_chunk); ++ } ++ } ++ } ++ ++ mutex_unlock(&yaffs_context_lock); ++ ++ return count; ++} ++ ++static int yaffs_proc_write(struct file *file, const char *buf, ++ unsigned long count, void *data) ++{ ++ if (buf[0] == '.') ++ return yaffs_proc_debug_write(file, buf, count, data); ++ return yaffs_proc_write_trace_options(file, buf, count, data); ++} ++ ++/* Stuff to handle installation of file systems */ ++struct file_system_to_install { ++ struct file_system_type *fst; ++ int installed; ++}; ++ ++static struct file_system_to_install fs_to_install[] = { ++ {&yaffs_fs_type, 0}, ++ {&yaffs2_fs_type, 0}, ++ {NULL, 0} ++}; ++ ++static int __init init_yaffs_fs(void) ++{ ++ int error = 0; ++ struct file_system_to_install *fsinst; ++ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs built " __DATE__ " " __TIME__ " Installing."); ++ ++ mutex_init(&yaffs_context_lock); ++ ++ /* Install the proc_fs entries */ ++ my_proc_entry = create_proc_entry("yaffs", ++ S_IRUGO | S_IFREG, YPROC_ROOT); ++ ++ if (my_proc_entry) { ++ my_proc_entry->write_proc = yaffs_proc_write; ++ my_proc_entry->read_proc = yaffs_proc_read; ++ my_proc_entry->data = NULL; ++ } else { ++ return -ENOMEM; ++ } ++ ++ /* Now add the file system entries */ ++ ++ fsinst = fs_to_install; ++ ++ while (fsinst->fst && !error) { ++ error = register_filesystem(fsinst->fst); ++ if (!error) ++ fsinst->installed = 1; ++ fsinst++; ++ } ++ ++ /* Any errors? uninstall */ ++ if (error) { ++ fsinst = fs_to_install; ++ ++ while (fsinst->fst) { ++ if (fsinst->installed) { ++ unregister_filesystem(fsinst->fst); ++ fsinst->installed = 0; ++ } ++ fsinst++; ++ } ++ } ++ ++ return error; ++} ++ ++static void __exit exit_yaffs_fs(void) ++{ ++ ++ struct file_system_to_install *fsinst; ++ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "yaffs built " __DATE__ " " __TIME__ " removing."); ++ ++ remove_proc_entry("yaffs", YPROC_ROOT); ++ ++ fsinst = fs_to_install; ++ ++ while (fsinst->fst) { ++ if (fsinst->installed) { ++ unregister_filesystem(fsinst->fst); ++ fsinst->installed = 0; ++ } ++ fsinst++; ++ } ++} ++ ++module_init(init_yaffs_fs) ++ module_exit(exit_yaffs_fs) ++ ++ MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system"); ++MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2011"); ++MODULE_LICENSE("GPL"); +diff --git a/fs/yaffs2/yaffs_yaffs1.c b/fs/yaffs2/yaffs_yaffs1.c +new file mode 100644 +index 00000000..d277e20e +--- /dev/null ++++ b/fs/yaffs2/yaffs_yaffs1.c +@@ -0,0 +1,422 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_yaffs1.h" ++#include "yportenv.h" ++#include "yaffs_trace.h" ++#include "yaffs_bitmap.h" ++#include "yaffs_getblockinfo.h" ++#include "yaffs_nand.h" ++#include "yaffs_attribs.h" ++ ++int yaffs1_scan(struct yaffs_dev *dev) ++{ ++ struct yaffs_ext_tags tags; ++ int blk; ++ int result; ++ int chunk; ++ int c; ++ int deleted; ++ enum yaffs_block_state state; ++ LIST_HEAD(hard_list); ++ struct yaffs_block_info *bi; ++ u32 seq_number; ++ struct yaffs_obj_hdr *oh; ++ struct yaffs_obj *in; ++ struct yaffs_obj *parent; ++ int alloc_failed = 0; ++ struct yaffs_shadow_fixer *shadow_fixers = NULL; ++ u8 *chunk_data; ++ ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "yaffs1_scan starts intstartblk %d intendblk %d...", ++ dev->internal_start_block, dev->internal_end_block); ++ ++ chunk_data = yaffs_get_temp_buffer(dev); ++ ++ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; ++ ++ /* Scan all the blocks to determine their state */ ++ bi = dev->block_info; ++ for (blk = dev->internal_start_block; blk <= dev->internal_end_block; ++ blk++) { ++ yaffs_clear_chunk_bits(dev, blk); ++ bi->pages_in_use = 0; ++ bi->soft_del_pages = 0; ++ ++ yaffs_query_init_block_state(dev, blk, &state, &seq_number); ++ ++ bi->block_state = state; ++ bi->seq_number = seq_number; ++ ++ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) ++ bi->block_state = state = YAFFS_BLOCK_STATE_DEAD; ++ ++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, ++ "Block scanning block %d state %d seq %d", ++ blk, state, seq_number); ++ ++ if (state == YAFFS_BLOCK_STATE_DEAD) { ++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, ++ "block %d is bad", blk); ++ } else if (state == YAFFS_BLOCK_STATE_EMPTY) { ++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty "); ++ dev->n_erased_blocks++; ++ dev->n_free_chunks += dev->param.chunks_per_block; ++ } ++ bi++; ++ } ++ ++ /* For each block.... */ ++ for (blk = dev->internal_start_block; ++ !alloc_failed && blk <= dev->internal_end_block; blk++) { ++ ++ cond_resched(); ++ ++ bi = yaffs_get_block_info(dev, blk); ++ state = bi->block_state; ++ ++ deleted = 0; ++ ++ /* For each chunk in each block that needs scanning.... */ ++ for (c = 0; ++ !alloc_failed && c < dev->param.chunks_per_block && ++ state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) { ++ /* Read the tags and decide what to do */ ++ chunk = blk * dev->param.chunks_per_block + c; ++ ++ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, ++ &tags); ++ ++ /* Let's have a good look at this chunk... */ ++ ++ if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED || ++ tags.is_deleted) { ++ /* YAFFS1 only... ++ * A deleted chunk ++ */ ++ deleted++; ++ dev->n_free_chunks++; ++ } else if (!tags.chunk_used) { ++ /* An unassigned chunk in the block ++ * This means that either the block is empty or ++ * this is the one being allocated from ++ */ ++ ++ if (c == 0) { ++ /* We're looking at the first chunk in ++ *the block so the block is unused */ ++ state = YAFFS_BLOCK_STATE_EMPTY; ++ dev->n_erased_blocks++; ++ } else { ++ /* this is the block being allocated */ ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ " Allocating from %d %d", ++ blk, c); ++ state = YAFFS_BLOCK_STATE_ALLOCATING; ++ dev->alloc_block = blk; ++ dev->alloc_page = c; ++ dev->alloc_block_finder = blk; ++ ++ } ++ ++ dev->n_free_chunks += ++ (dev->param.chunks_per_block - c); ++ } else if (tags.chunk_id > 0) { ++ /* chunk_id > 0 so it is a data chunk... */ ++ unsigned int endpos; ++ ++ yaffs_set_chunk_bit(dev, blk, c); ++ bi->pages_in_use++; ++ ++ in = yaffs_find_or_create_by_number(dev, ++ tags.obj_id, ++ YAFFS_OBJECT_TYPE_FILE); ++ /* PutChunkIntoFile checks for a clash ++ * (two data chunks with the same chunk_id). ++ */ ++ ++ if (!in) ++ alloc_failed = 1; ++ ++ if (in) { ++ if (!yaffs_put_chunk_in_file ++ (in, tags.chunk_id, chunk, 1)) ++ alloc_failed = 1; ++ } ++ ++ endpos = ++ (tags.chunk_id - 1) * ++ dev->data_bytes_per_chunk + ++ tags.n_bytes; ++ if (in && ++ in->variant_type == ++ YAFFS_OBJECT_TYPE_FILE && ++ in->variant.file_variant.scanned_size < ++ endpos) { ++ in->variant.file_variant.scanned_size = ++ endpos; ++ if (!dev->param.use_header_file_size) { ++ in->variant. ++ file_variant.file_size = ++ in->variant. ++ file_variant.scanned_size; ++ } ++ ++ } ++ } else { ++ /* chunk_id == 0, so it is an ObjectHeader. ++ * Make the object ++ */ ++ yaffs_set_chunk_bit(dev, blk, c); ++ bi->pages_in_use++; ++ ++ result = yaffs_rd_chunk_tags_nand(dev, chunk, ++ chunk_data, ++ NULL); ++ ++ oh = (struct yaffs_obj_hdr *)chunk_data; ++ ++ in = yaffs_find_by_number(dev, tags.obj_id); ++ if (in && in->variant_type != oh->type) { ++ /* This should not happen, but somehow ++ * Wev'e ended up with an obj_id that ++ * has been reused but not yet deleted, ++ * and worse still it has changed type. ++ * Delete the old object. ++ */ ++ ++ yaffs_del_obj(in); ++ in = NULL; ++ } ++ ++ in = yaffs_find_or_create_by_number(dev, ++ tags.obj_id, ++ oh->type); ++ ++ if (!in) ++ alloc_failed = 1; ++ ++ if (in && oh->shadows_obj > 0) { ++ ++ struct yaffs_shadow_fixer *fixer; ++ fixer = ++ kmalloc(sizeof ++ (struct yaffs_shadow_fixer), ++ GFP_NOFS); ++ if (fixer) { ++ fixer->next = shadow_fixers; ++ shadow_fixers = fixer; ++ fixer->obj_id = tags.obj_id; ++ fixer->shadowed_id = ++ oh->shadows_obj; ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ " Shadow fixer: %d shadows %d", ++ fixer->obj_id, ++ fixer->shadowed_id); ++ ++ } ++ ++ } ++ ++ if (in && in->valid) { ++ /* We have already filled this one. ++ * We have a duplicate and need to ++ * resolve it. */ ++ ++ unsigned existing_serial = in->serial; ++ unsigned new_serial = ++ tags.serial_number; ++ ++ if (((existing_serial + 1) & 3) == ++ new_serial) { ++ /* Use new one - destroy the ++ * exisiting one */ ++ yaffs_chunk_del(dev, ++ in->hdr_chunk, ++ 1, __LINE__); ++ in->valid = 0; ++ } else { ++ /* Use existing - destroy ++ * this one. */ ++ yaffs_chunk_del(dev, chunk, 1, ++ __LINE__); ++ } ++ } ++ ++ if (in && !in->valid && ++ (tags.obj_id == YAFFS_OBJECTID_ROOT || ++ tags.obj_id == ++ YAFFS_OBJECTID_LOSTNFOUND)) { ++ /* We only load some info, don't fiddle ++ * with directory structure */ ++ in->valid = 1; ++ in->variant_type = oh->type; ++ ++ in->yst_mode = oh->yst_mode; ++ yaffs_load_attribs(in, oh); ++ in->hdr_chunk = chunk; ++ in->serial = tags.serial_number; ++ ++ } else if (in && !in->valid) { ++ /* we need to load this info */ ++ ++ in->valid = 1; ++ in->variant_type = oh->type; ++ ++ in->yst_mode = oh->yst_mode; ++ yaffs_load_attribs(in, oh); ++ in->hdr_chunk = chunk; ++ in->serial = tags.serial_number; ++ ++ yaffs_set_obj_name_from_oh(in, oh); ++ in->dirty = 0; ++ ++ /* directory stuff... ++ * hook up to parent ++ */ ++ ++ parent = ++ yaffs_find_or_create_by_number ++ (dev, oh->parent_obj_id, ++ YAFFS_OBJECT_TYPE_DIRECTORY); ++ if (!parent) ++ alloc_failed = 1; ++ if (parent && parent->variant_type == ++ YAFFS_OBJECT_TYPE_UNKNOWN) { ++ /* Set up as a directory */ ++ parent->variant_type = ++ YAFFS_OBJECT_TYPE_DIRECTORY; ++ INIT_LIST_HEAD(&parent-> ++ variant.dir_variant. ++ children); ++ } else if (!parent || ++ parent->variant_type != ++ YAFFS_OBJECT_TYPE_DIRECTORY) { ++ /* Hoosterman, a problem.... ++ * We're trying to use a ++ * non-directory as a directory ++ */ ++ ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." ++ ); ++ parent = dev->lost_n_found; ++ } ++ ++ yaffs_add_obj_to_dir(parent, in); ++ ++ switch (in->variant_type) { ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* Todo got a problem */ ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ if (dev->param. ++ use_header_file_size) ++ in->variant. ++ file_variant.file_size ++ = yaffs_oh_to_size(oh); ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ in->variant. ++ hardlink_variant.equiv_id = ++ oh->equiv_id; ++ list_add(&in->hard_links, ++ &hard_list); ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ in->variant.symlink_variant. ++ alias = ++ yaffs_clone_str(oh->alias); ++ if (!in->variant. ++ symlink_variant.alias) ++ alloc_failed = 1; ++ break; ++ } ++ } ++ } ++ } ++ ++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) { ++ /* If we got this far while scanning, ++ * then the block is fully allocated. */ ++ state = YAFFS_BLOCK_STATE_FULL; ++ } ++ ++ if (state == YAFFS_BLOCK_STATE_ALLOCATING) { ++ /* If the block was partially allocated then ++ * treat it as fully allocated. */ ++ state = YAFFS_BLOCK_STATE_FULL; ++ dev->alloc_block = -1; ++ } ++ ++ bi->block_state = state; ++ ++ /* Now let's see if it was dirty */ ++ if (bi->pages_in_use == 0 && ++ !bi->has_shrink_hdr && ++ bi->block_state == YAFFS_BLOCK_STATE_FULL) ++ yaffs_block_became_dirty(dev, blk); ++ } ++ ++ /* Ok, we've done all the scanning. ++ * Fix up the hard link chains. ++ * We should now have scanned all the objects, now it's time to add ++ * these hardlinks. ++ */ ++ ++ yaffs_link_fixup(dev, &hard_list); ++ ++ /* ++ * Fix up any shadowed objects. ++ * There should not be more than one of these. ++ */ ++ { ++ struct yaffs_shadow_fixer *fixer; ++ struct yaffs_obj *obj; ++ ++ while (shadow_fixers) { ++ fixer = shadow_fixers; ++ shadow_fixers = fixer->next; ++ /* Complete the rename transaction by deleting the ++ * shadowed object then setting the object header ++ to unshadowed. ++ */ ++ obj = yaffs_find_by_number(dev, fixer->shadowed_id); ++ if (obj) ++ yaffs_del_obj(obj); ++ ++ obj = yaffs_find_by_number(dev, fixer->obj_id); ++ ++ if (obj) ++ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); ++ ++ kfree(fixer); ++ } ++ } ++ ++ yaffs_release_temp_buffer(dev, chunk_data); ++ ++ if (alloc_failed) ++ return YAFFS_FAIL; ++ ++ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends"); ++ ++ return YAFFS_OK; ++} +diff --git a/fs/yaffs2/yaffs_yaffs1.h b/fs/yaffs2/yaffs_yaffs1.h +new file mode 100644 +index 00000000..97e2fdd0 +--- /dev/null ++++ b/fs/yaffs2/yaffs_yaffs1.h +@@ -0,0 +1,22 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_YAFFS1_H__ ++#define __YAFFS_YAFFS1_H__ ++ ++#include "yaffs_guts.h" ++int yaffs1_scan(struct yaffs_dev *dev); ++ ++#endif +diff --git a/fs/yaffs2/yaffs_yaffs2.c b/fs/yaffs2/yaffs_yaffs2.c +new file mode 100644 +index 00000000..8c31a661 +--- /dev/null ++++ b/fs/yaffs2/yaffs_yaffs2.c +@@ -0,0 +1,1534 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_guts.h" ++#include "yaffs_trace.h" ++#include "yaffs_yaffs2.h" ++#include "yaffs_checkptrw.h" ++#include "yaffs_bitmap.h" ++#include "yaffs_nand.h" ++#include "yaffs_getblockinfo.h" ++#include "yaffs_verify.h" ++#include "yaffs_attribs.h" ++#include "yaffs_summary.h" ++ ++/* ++ * Checkpoints are really no benefit on very small partitions. ++ * ++ * To save space on small partitions don't bother with checkpoints unless ++ * the partition is at least this big. ++ */ ++#define YAFFS_CHECKPOINT_MIN_BLOCKS 60 ++#define YAFFS_SMALL_HOLE_THRESHOLD 4 ++ ++/* ++ * Oldest Dirty Sequence Number handling. ++ */ ++ ++/* yaffs_calc_oldest_dirty_seq() ++ * yaffs2_find_oldest_dirty_seq() ++ * Calculate the oldest dirty sequence number if we don't know it. ++ */ ++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev) ++{ ++ int i; ++ unsigned seq; ++ unsigned block_no = 0; ++ struct yaffs_block_info *b; ++ ++ if (!dev->param.is_yaffs2) ++ return; ++ ++ /* Find the oldest dirty sequence number. */ ++ seq = dev->seq_number + 1; ++ b = dev->block_info; ++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { ++ if (b->block_state == YAFFS_BLOCK_STATE_FULL && ++ (b->pages_in_use - b->soft_del_pages) < ++ dev->param.chunks_per_block && ++ b->seq_number < seq) { ++ seq = b->seq_number; ++ block_no = i; ++ } ++ b++; ++ } ++ ++ if (block_no) { ++ dev->oldest_dirty_seq = seq; ++ dev->oldest_dirty_block = block_no; ++ } ++} ++ ++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev) ++{ ++ if (!dev->param.is_yaffs2) ++ return; ++ ++ if (!dev->oldest_dirty_seq) ++ yaffs_calc_oldest_dirty_seq(dev); ++} ++ ++/* ++ * yaffs_clear_oldest_dirty_seq() ++ * Called when a block is erased or marked bad. (ie. when its seq_number ++ * becomes invalid). If the value matches the oldest then we clear ++ * dev->oldest_dirty_seq to force its recomputation. ++ */ ++void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev, ++ struct yaffs_block_info *bi) ++{ ++ ++ if (!dev->param.is_yaffs2) ++ return; ++ ++ if (!bi || bi->seq_number == dev->oldest_dirty_seq) { ++ dev->oldest_dirty_seq = 0; ++ dev->oldest_dirty_block = 0; ++ } ++} ++ ++/* ++ * yaffs2_update_oldest_dirty_seq() ++ * Update the oldest dirty sequence number whenever we dirty a block. ++ * Only do this if the oldest_dirty_seq is actually being tracked. ++ */ ++void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no, ++ struct yaffs_block_info *bi) ++{ ++ if (!dev->param.is_yaffs2) ++ return; ++ ++ if (dev->oldest_dirty_seq) { ++ if (dev->oldest_dirty_seq > bi->seq_number) { ++ dev->oldest_dirty_seq = bi->seq_number; ++ dev->oldest_dirty_block = block_no; ++ } ++ } ++} ++ ++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi) ++{ ++ ++ if (!dev->param.is_yaffs2) ++ return 1; /* disqualification only applies to yaffs2. */ ++ ++ if (!bi->has_shrink_hdr) ++ return 1; /* can gc */ ++ ++ yaffs2_find_oldest_dirty_seq(dev); ++ ++ /* Can't do gc of this block if there are any blocks older than this ++ * one that have discarded pages. ++ */ ++ return (bi->seq_number <= dev->oldest_dirty_seq); ++} ++ ++/* ++ * yaffs2_find_refresh_block() ++ * periodically finds the oldest full block by sequence number for refreshing. ++ * Only for yaffs2. ++ */ ++u32 yaffs2_find_refresh_block(struct yaffs_dev *dev) ++{ ++ u32 b; ++ u32 oldest = 0; ++ u32 oldest_seq = 0; ++ struct yaffs_block_info *bi; ++ ++ if (!dev->param.is_yaffs2) ++ return oldest; ++ ++ /* ++ * If refresh period < 10 then refreshing is disabled. ++ */ ++ if (dev->param.refresh_period < 10) ++ return oldest; ++ ++ /* ++ * Fix broken values. ++ */ ++ if (dev->refresh_skip > dev->param.refresh_period) ++ dev->refresh_skip = dev->param.refresh_period; ++ ++ if (dev->refresh_skip > 0) ++ return oldest; ++ ++ /* ++ * Refresh skip is now zero. ++ * We'll do a refresh this time around.... ++ * Update the refresh skip and find the oldest block. ++ */ ++ dev->refresh_skip = dev->param.refresh_period; ++ dev->refresh_count++; ++ bi = dev->block_info; ++ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) { ++ ++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL) { ++ ++ if (oldest < 1 || bi->seq_number < oldest_seq) { ++ oldest = b; ++ oldest_seq = bi->seq_number; ++ } ++ } ++ bi++; ++ } ++ ++ if (oldest > 0) { ++ yaffs_trace(YAFFS_TRACE_GC, ++ "GC refresh count %d selected block %d with seq_number %d", ++ dev->refresh_count, oldest, oldest_seq); ++ } ++ ++ return oldest; ++} ++ ++int yaffs2_checkpt_required(struct yaffs_dev *dev) ++{ ++ int nblocks; ++ ++ if (!dev->param.is_yaffs2) ++ return 0; ++ ++ nblocks = dev->internal_end_block - dev->internal_start_block + 1; ++ ++ return !dev->param.skip_checkpt_wr && ++ !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS); ++} ++ ++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev) ++{ ++ int retval; ++ int n_bytes = 0; ++ int n_blocks; ++ int dev_blocks; ++ ++ if (!dev->param.is_yaffs2) ++ return 0; ++ ++ if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) { ++ /* Not a valid value so recalculate */ ++ dev_blocks = dev->param.end_block - dev->param.start_block + 1; ++ n_bytes += sizeof(struct yaffs_checkpt_validity); ++ n_bytes += sizeof(struct yaffs_checkpt_dev); ++ n_bytes += dev_blocks * sizeof(struct yaffs_block_info); ++ n_bytes += dev_blocks * dev->chunk_bit_stride; ++ n_bytes += ++ (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) * ++ dev->n_obj; ++ n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes; ++ n_bytes += sizeof(struct yaffs_checkpt_validity); ++ n_bytes += sizeof(u32); /* checksum */ ++ ++ /* Round up and add 2 blocks to allow for some bad blocks, ++ * so add 3 */ ++ ++ n_blocks = ++ (n_bytes / ++ (dev->data_bytes_per_chunk * ++ dev->param.chunks_per_block)) + 3; ++ ++ dev->checkpoint_blocks_required = n_blocks; ++ } ++ ++ retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt; ++ if (retval < 0) ++ retval = 0; ++ return retval; ++} ++ ++/*--------------------- Checkpointing --------------------*/ ++ ++static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head) ++{ ++ struct yaffs_checkpt_validity cp; ++ ++ memset(&cp, 0, sizeof(cp)); ++ ++ cp.struct_type = sizeof(cp); ++ cp.magic = YAFFS_MAGIC; ++ cp.version = YAFFS_CHECKPOINT_VERSION; ++ cp.head = (head) ? 1 : 0; ++ ++ return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0; ++} ++ ++static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head) ++{ ++ struct yaffs_checkpt_validity cp; ++ int ok; ++ ++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ ++ if (ok) ++ ok = (cp.struct_type == sizeof(cp)) && ++ (cp.magic == YAFFS_MAGIC) && ++ (cp.version == YAFFS_CHECKPOINT_VERSION) && ++ (cp.head == ((head) ? 1 : 0)); ++ return ok ? 1 : 0; ++} ++ ++static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp, ++ struct yaffs_dev *dev) ++{ ++ cp->n_erased_blocks = dev->n_erased_blocks; ++ cp->alloc_block = dev->alloc_block; ++ cp->alloc_page = dev->alloc_page; ++ cp->n_free_chunks = dev->n_free_chunks; ++ ++ cp->n_deleted_files = dev->n_deleted_files; ++ cp->n_unlinked_files = dev->n_unlinked_files; ++ cp->n_bg_deletions = dev->n_bg_deletions; ++ cp->seq_number = dev->seq_number; ++ ++} ++ ++static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev, ++ struct yaffs_checkpt_dev *cp) ++{ ++ dev->n_erased_blocks = cp->n_erased_blocks; ++ dev->alloc_block = cp->alloc_block; ++ dev->alloc_page = cp->alloc_page; ++ dev->n_free_chunks = cp->n_free_chunks; ++ ++ dev->n_deleted_files = cp->n_deleted_files; ++ dev->n_unlinked_files = cp->n_unlinked_files; ++ dev->n_bg_deletions = cp->n_bg_deletions; ++ dev->seq_number = cp->seq_number; ++} ++ ++static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev) ++{ ++ struct yaffs_checkpt_dev cp; ++ u32 n_bytes; ++ u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1; ++ int ok; ++ ++ /* Write device runtime values */ ++ yaffs2_dev_to_checkpt_dev(&cp, dev); ++ cp.struct_type = sizeof(cp); ++ ++ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ if (!ok) ++ return 0; ++ ++ /* Write block info */ ++ n_bytes = n_blocks * sizeof(struct yaffs_block_info); ++ ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes); ++ if (!ok) ++ return 0; ++ ++ /* Write chunk bits */ ++ n_bytes = n_blocks * dev->chunk_bit_stride; ++ ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes); ++ ++ return ok ? 1 : 0; ++} ++ ++static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev) ++{ ++ struct yaffs_checkpt_dev cp; ++ u32 n_bytes; ++ u32 n_blocks = ++ (dev->internal_end_block - dev->internal_start_block + 1); ++ int ok; ++ ++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ if (!ok) ++ return 0; ++ ++ if (cp.struct_type != sizeof(cp)) ++ return 0; ++ ++ yaffs_checkpt_dev_to_dev(dev, &cp); ++ ++ n_bytes = n_blocks * sizeof(struct yaffs_block_info); ++ ++ ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes); ++ ++ if (!ok) ++ return 0; ++ ++ n_bytes = n_blocks * dev->chunk_bit_stride; ++ ++ ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes); ++ ++ return ok ? 1 : 0; ++} ++ ++static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp, ++ struct yaffs_obj *obj) ++{ ++ cp->obj_id = obj->obj_id; ++ cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0; ++ cp->hdr_chunk = obj->hdr_chunk; ++ cp->variant_type = obj->variant_type; ++ cp->deleted = obj->deleted; ++ cp->soft_del = obj->soft_del; ++ cp->unlinked = obj->unlinked; ++ cp->fake = obj->fake; ++ cp->rename_allowed = obj->rename_allowed; ++ cp->unlink_allowed = obj->unlink_allowed; ++ cp->serial = obj->serial; ++ cp->n_data_chunks = obj->n_data_chunks; ++ ++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) ++ cp->size_or_equiv_obj = obj->variant.file_variant.file_size; ++ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) ++ cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id; ++} ++ ++static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj, ++ struct yaffs_checkpt_obj *cp) ++{ ++ struct yaffs_obj *parent; ++ ++ if (obj->variant_type != cp->variant_type) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "Checkpoint read object %d type %d chunk %d does not match existing object type %d", ++ cp->obj_id, cp->variant_type, cp->hdr_chunk, ++ obj->variant_type); ++ return 0; ++ } ++ ++ obj->obj_id = cp->obj_id; ++ ++ if (cp->parent_id) ++ parent = yaffs_find_or_create_by_number(obj->my_dev, ++ cp->parent_id, ++ YAFFS_OBJECT_TYPE_DIRECTORY); ++ else ++ parent = NULL; ++ ++ if (parent) { ++ if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory", ++ cp->obj_id, cp->parent_id, ++ cp->variant_type, cp->hdr_chunk, ++ parent->variant_type); ++ return 0; ++ } ++ yaffs_add_obj_to_dir(parent, obj); ++ } ++ ++ obj->hdr_chunk = cp->hdr_chunk; ++ obj->variant_type = cp->variant_type; ++ obj->deleted = cp->deleted; ++ obj->soft_del = cp->soft_del; ++ obj->unlinked = cp->unlinked; ++ obj->fake = cp->fake; ++ obj->rename_allowed = cp->rename_allowed; ++ obj->unlink_allowed = cp->unlink_allowed; ++ obj->serial = cp->serial; ++ obj->n_data_chunks = cp->n_data_chunks; ++ ++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) ++ obj->variant.file_variant.file_size = cp->size_or_equiv_obj; ++ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) ++ obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj; ++ ++ if (obj->hdr_chunk > 0) ++ obj->lazy_loaded = 1; ++ return 1; ++} ++ ++static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in, ++ struct yaffs_tnode *tn, u32 level, ++ int chunk_offset) ++{ ++ int i; ++ struct yaffs_dev *dev = in->my_dev; ++ int ok = 1; ++ u32 base_offset; ++ ++ if (!tn) ++ return 1; ++ ++ if (level > 0) { ++ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { ++ if (!tn->internal[i]) ++ continue; ++ ok = yaffs2_checkpt_tnode_worker(in, ++ tn->internal[i], ++ level - 1, ++ (chunk_offset << ++ YAFFS_TNODES_INTERNAL_BITS) + i); ++ } ++ return ok; ++ } ++ ++ /* Level 0 tnode */ ++ base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS; ++ ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) == ++ sizeof(base_offset)); ++ if (ok) ++ ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) == ++ dev->tnode_size); ++ ++ return ok; ++} ++ ++static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj) ++{ ++ u32 end_marker = ~0; ++ int ok = 1; ++ ++ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE) ++ return ok; ++ ++ ok = yaffs2_checkpt_tnode_worker(obj, ++ obj->variant.file_variant.top, ++ obj->variant.file_variant. ++ top_level, 0); ++ if (ok) ++ ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker, ++ sizeof(end_marker)) == sizeof(end_marker)); ++ ++ return ok ? 1 : 0; ++} ++ ++static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj) ++{ ++ u32 base_chunk; ++ int ok = 1; ++ struct yaffs_dev *dev = obj->my_dev; ++ struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant; ++ struct yaffs_tnode *tn; ++ int nread = 0; ++ ++ ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) == ++ sizeof(base_chunk)); ++ ++ while (ok && (~base_chunk)) { ++ nread++; ++ /* Read level 0 tnode */ ++ ++ tn = yaffs_get_tnode(dev); ++ if (tn) ++ ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) == ++ dev->tnode_size); ++ else ++ ok = 0; ++ ++ if (tn && ok) ++ ok = yaffs_add_find_tnode_0(dev, ++ file_stuct_ptr, ++ base_chunk, tn) ? 1 : 0; ++ ++ if (ok) ++ ok = (yaffs2_checkpt_rd ++ (dev, &base_chunk, ++ sizeof(base_chunk)) == sizeof(base_chunk)); ++ } ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "Checkpoint read tnodes %d records, last %d. ok %d", ++ nread, base_chunk, ok); ++ ++ return ok ? 1 : 0; ++} ++ ++static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_checkpt_obj cp; ++ int i; ++ int ok = 1; ++ struct list_head *lh; ++ ++ /* Iterate through the objects in each hash entry, ++ * dumping them to the checkpointing stream. ++ */ ++ ++ for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) { ++ list_for_each(lh, &dev->obj_bucket[i].list) { ++ obj = list_entry(lh, struct yaffs_obj, hash_link); ++ if (!obj->defered_free) { ++ yaffs2_obj_checkpt_obj(&cp, obj); ++ cp.struct_type = sizeof(cp); ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "Checkpoint write object %d parent %d type %d chunk %d obj addr %p", ++ cp.obj_id, cp.parent_id, ++ cp.variant_type, cp.hdr_chunk, obj); ++ ++ ok = (yaffs2_checkpt_wr(dev, &cp, ++ sizeof(cp)) == sizeof(cp)); ++ ++ if (ok && ++ obj->variant_type == ++ YAFFS_OBJECT_TYPE_FILE) ++ ok = yaffs2_wr_checkpt_tnodes(obj); ++ } ++ } ++ } ++ ++ /* Dump end of list */ ++ memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj)); ++ cp.struct_type = sizeof(cp); ++ ++ if (ok) ++ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ ++ return ok ? 1 : 0; ++} ++ ++static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev) ++{ ++ struct yaffs_obj *obj; ++ struct yaffs_checkpt_obj cp; ++ int ok = 1; ++ int done = 0; ++ LIST_HEAD(hard_list); ++ ++ ++ while (ok && !done) { ++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ if (cp.struct_type != sizeof(cp)) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "struct size %d instead of %d ok %d", ++ cp.struct_type, (int)sizeof(cp), ok); ++ ok = 0; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "Checkpoint read object %d parent %d type %d chunk %d ", ++ cp.obj_id, cp.parent_id, cp.variant_type, ++ cp.hdr_chunk); ++ ++ if (ok && cp.obj_id == ~0) { ++ done = 1; ++ } else if (ok) { ++ obj = ++ yaffs_find_or_create_by_number(dev, cp.obj_id, ++ cp.variant_type); ++ if (obj) { ++ ok = yaffs2_checkpt_obj_to_obj(obj, &cp); ++ if (!ok) ++ break; ++ if (obj->variant_type == ++ YAFFS_OBJECT_TYPE_FILE) { ++ ok = yaffs2_rd_checkpt_tnodes(obj); ++ } else if (obj->variant_type == ++ YAFFS_OBJECT_TYPE_HARDLINK) { ++ list_add(&obj->hard_links, &hard_list); ++ } ++ } else { ++ ok = 0; ++ } ++ } ++ } ++ ++ if (ok) ++ yaffs_link_fixup(dev, &hard_list); ++ ++ return ok ? 1 : 0; ++} ++ ++static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev) ++{ ++ u32 checkpt_sum; ++ int ok; ++ ++ yaffs2_get_checkpt_sum(dev, &checkpt_sum); ++ ++ ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) == ++ sizeof(checkpt_sum)); ++ ++ if (!ok) ++ return 0; ++ ++ return 1; ++} ++ ++static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev) ++{ ++ u32 checkpt_sum0; ++ u32 checkpt_sum1; ++ int ok; ++ ++ yaffs2_get_checkpt_sum(dev, &checkpt_sum0); ++ ++ ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) == ++ sizeof(checkpt_sum1)); ++ ++ if (!ok) ++ return 0; ++ ++ if (checkpt_sum0 != checkpt_sum1) ++ return 0; ++ ++ return 1; ++} ++ ++static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev) ++{ ++ int ok = 1; ++ ++ if (!yaffs2_checkpt_required(dev)) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "skipping checkpoint write"); ++ ok = 0; ++ } ++ ++ if (ok) ++ ok = yaffs2_checkpt_open(dev, 1); ++ ++ if (ok) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "write checkpoint validity"); ++ ok = yaffs2_wr_checkpt_validity_marker(dev, 1); ++ } ++ if (ok) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "write checkpoint device"); ++ ok = yaffs2_wr_checkpt_dev(dev); ++ } ++ if (ok) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "write checkpoint objects"); ++ ok = yaffs2_wr_checkpt_objs(dev); ++ } ++ if (ok) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "write checkpoint validity"); ++ ok = yaffs2_wr_checkpt_validity_marker(dev, 0); ++ } ++ ++ if (ok) ++ ok = yaffs2_wr_checkpt_sum(dev); ++ ++ if (!yaffs_checkpt_close(dev)) ++ ok = 0; ++ ++ if (ok) ++ dev->is_checkpointed = 1; ++ else ++ dev->is_checkpointed = 0; ++ ++ return dev->is_checkpointed; ++} ++ ++static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev) ++{ ++ int ok = 1; ++ ++ if (!dev->param.is_yaffs2) ++ ok = 0; ++ ++ if (ok && dev->param.skip_checkpt_rd) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "skipping checkpoint read"); ++ ok = 0; ++ } ++ ++ if (ok) ++ ok = yaffs2_checkpt_open(dev, 0); /* open for read */ ++ ++ if (ok) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "read checkpoint validity"); ++ ok = yaffs2_rd_checkpt_validity_marker(dev, 1); ++ } ++ if (ok) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "read checkpoint device"); ++ ok = yaffs2_rd_checkpt_dev(dev); ++ } ++ if (ok) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "read checkpoint objects"); ++ ok = yaffs2_rd_checkpt_objs(dev); ++ } ++ if (ok) { ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "read checkpoint validity"); ++ ok = yaffs2_rd_checkpt_validity_marker(dev, 0); ++ } ++ ++ if (ok) { ++ ok = yaffs2_rd_checkpt_sum(dev); ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "read checkpoint checksum %d", ok); ++ } ++ ++ if (!yaffs_checkpt_close(dev)) ++ ok = 0; ++ ++ if (ok) ++ dev->is_checkpointed = 1; ++ else ++ dev->is_checkpointed = 0; ++ ++ return ok ? 1 : 0; ++} ++ ++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev) ++{ ++ if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) { ++ dev->is_checkpointed = 0; ++ yaffs2_checkpt_invalidate_stream(dev); ++ } ++ if (dev->param.sb_dirty_fn) ++ dev->param.sb_dirty_fn(dev); ++} ++ ++int yaffs_checkpoint_save(struct yaffs_dev *dev) ++{ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "save entry: is_checkpointed %d", ++ dev->is_checkpointed); ++ ++ yaffs_verify_objects(dev); ++ yaffs_verify_blocks(dev); ++ yaffs_verify_free_chunks(dev); ++ ++ if (!dev->is_checkpointed) { ++ yaffs2_checkpt_invalidate(dev); ++ yaffs2_wr_checkpt_data(dev); ++ } ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT, ++ "save exit: is_checkpointed %d", ++ dev->is_checkpointed); ++ ++ return dev->is_checkpointed; ++} ++ ++int yaffs2_checkpt_restore(struct yaffs_dev *dev) ++{ ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "restore entry: is_checkpointed %d", ++ dev->is_checkpointed); ++ ++ retval = yaffs2_rd_checkpt_data(dev); ++ ++ if (dev->is_checkpointed) { ++ yaffs_verify_objects(dev); ++ yaffs_verify_blocks(dev); ++ yaffs_verify_free_chunks(dev); ++ } ++ ++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, ++ "restore exit: is_checkpointed %d", ++ dev->is_checkpointed); ++ ++ return retval; ++} ++ ++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size) ++{ ++ /* if new_size > old_file_size. ++ * We're going to be writing a hole. ++ * If the hole is small then write zeros otherwise write a start ++ * of hole marker. ++ */ ++ loff_t old_file_size; ++ loff_t increase; ++ int small_hole; ++ int result = YAFFS_OK; ++ struct yaffs_dev *dev = NULL; ++ u8 *local_buffer = NULL; ++ int small_increase_ok = 0; ++ ++ if (!obj) ++ return YAFFS_FAIL; ++ ++ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE) ++ return YAFFS_FAIL; ++ ++ dev = obj->my_dev; ++ ++ /* Bail out if not yaffs2 mode */ ++ if (!dev->param.is_yaffs2) ++ return YAFFS_OK; ++ ++ old_file_size = obj->variant.file_variant.file_size; ++ ++ if (new_size <= old_file_size) ++ return YAFFS_OK; ++ ++ increase = new_size - old_file_size; ++ ++ if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk && ++ yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1)) ++ small_hole = 1; ++ else ++ small_hole = 0; ++ ++ if (small_hole) ++ local_buffer = yaffs_get_temp_buffer(dev); ++ ++ if (local_buffer) { ++ /* fill hole with zero bytes */ ++ loff_t pos = old_file_size; ++ int this_write; ++ int written; ++ memset(local_buffer, 0, dev->data_bytes_per_chunk); ++ small_increase_ok = 1; ++ ++ while (increase > 0 && small_increase_ok) { ++ this_write = increase; ++ if (this_write > dev->data_bytes_per_chunk) ++ this_write = dev->data_bytes_per_chunk; ++ written = ++ yaffs_do_file_wr(obj, local_buffer, pos, this_write, ++ 0); ++ if (written == this_write) { ++ pos += this_write; ++ increase -= this_write; ++ } else { ++ small_increase_ok = 0; ++ } ++ } ++ ++ yaffs_release_temp_buffer(dev, local_buffer); ++ ++ /* If out of space then reverse any chunks we've added */ ++ if (!small_increase_ok) ++ yaffs_resize_file_down(obj, old_file_size); ++ } ++ ++ if (!small_increase_ok && ++ obj->parent && ++ obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED && ++ obj->parent->obj_id != YAFFS_OBJECTID_DELETED) { ++ /* Write a hole start header with the old file size */ ++ yaffs_update_oh(obj, NULL, 0, 1, 0, NULL); ++ } ++ ++ return result; ++} ++ ++struct yaffs_block_index { ++ int seq; ++ int block; ++}; ++ ++static int yaffs2_ybicmp(const void *a, const void *b) ++{ ++ int aseq = ((struct yaffs_block_index *)a)->seq; ++ int bseq = ((struct yaffs_block_index *)b)->seq; ++ int ablock = ((struct yaffs_block_index *)a)->block; ++ int bblock = ((struct yaffs_block_index *)b)->block; ++ ++ if (aseq == bseq) ++ return ablock - bblock; ++ ++ return aseq - bseq; ++} ++ ++static inline int yaffs2_scan_chunk(struct yaffs_dev *dev, ++ struct yaffs_block_info *bi, ++ int blk, int chunk_in_block, ++ int *found_chunks, ++ u8 *chunk_data, ++ struct list_head *hard_list, ++ int summary_available) ++{ ++ struct yaffs_obj_hdr *oh; ++ struct yaffs_obj *in; ++ struct yaffs_obj *parent; ++ int equiv_id; ++ loff_t file_size; ++ int is_shrink; ++ int is_unlinked; ++ struct yaffs_ext_tags tags; ++ int result; ++ int alloc_failed = 0; ++ int chunk = blk * dev->param.chunks_per_block + chunk_in_block; ++ struct yaffs_file_var *file_var; ++ struct yaffs_hardlink_var *hl_var; ++ struct yaffs_symlink_var *sl_var; ++ ++ if (summary_available) { ++ result = yaffs_summary_fetch(dev, &tags, chunk_in_block); ++ tags.seq_number = bi->seq_number; ++ } ++ ++ if (!summary_available || tags.obj_id == 0) { ++ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags); ++ dev->tags_used++; ++ } else { ++ dev->summary_used++; ++ } ++ ++ /* Let's have a good look at this chunk... */ ++ ++ if (!tags.chunk_used) { ++ /* An unassigned chunk in the block. ++ * If there are used chunks after this one, then ++ * it is a chunk that was skipped due to failing ++ * the erased check. Just skip it so that it can ++ * be deleted. ++ * But, more typically, We get here when this is ++ * an unallocated chunk and his means that ++ * either the block is empty or this is the one ++ * being allocated from ++ */ ++ ++ if (*found_chunks) { ++ /* This is a chunk that was skipped due ++ * to failing the erased check */ ++ } else if (chunk_in_block == 0) { ++ /* We're looking at the first chunk in ++ * the block so the block is unused */ ++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY; ++ dev->n_erased_blocks++; ++ } else { ++ if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN || ++ bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) { ++ if (dev->seq_number == bi->seq_number) { ++ /* Allocating from this block*/ ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ " Allocating from %d %d", ++ blk, chunk_in_block); ++ ++ bi->block_state = ++ YAFFS_BLOCK_STATE_ALLOCATING; ++ dev->alloc_block = blk; ++ dev->alloc_page = chunk_in_block; ++ dev->alloc_block_finder = blk; ++ } else { ++ /* This is a partially written block ++ * that is not the current ++ * allocation block. ++ */ ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "Partially written block %d detected. gc will fix this.", ++ blk); ++ } ++ } ++ } ++ ++ dev->n_free_chunks++; ++ ++ } else if (tags.ecc_result == ++ YAFFS_ECC_RESULT_UNFIXED) { ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ " Unfixed ECC in chunk(%d:%d), chunk ignored", ++ blk, chunk_in_block); ++ dev->n_free_chunks++; ++ } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID || ++ tags.chunk_id > YAFFS_MAX_CHUNK_ID || ++ tags.obj_id == YAFFS_OBJECTID_SUMMARY || ++ (tags.chunk_id > 0 && ++ tags.n_bytes > dev->data_bytes_per_chunk) || ++ tags.seq_number != bi->seq_number) { ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored", ++ blk, chunk_in_block, tags.obj_id, ++ tags.chunk_id, tags.n_bytes); ++ dev->n_free_chunks++; ++ } else if (tags.chunk_id > 0) { ++ /* chunk_id > 0 so it is a data chunk... */ ++ loff_t endpos; ++ loff_t chunk_base = (tags.chunk_id - 1) * ++ dev->data_bytes_per_chunk; ++ ++ *found_chunks = 1; ++ ++ yaffs_set_chunk_bit(dev, blk, chunk_in_block); ++ bi->pages_in_use++; ++ ++ in = yaffs_find_or_create_by_number(dev, ++ tags.obj_id, ++ YAFFS_OBJECT_TYPE_FILE); ++ if (!in) ++ /* Out of memory */ ++ alloc_failed = 1; ++ ++ if (in && ++ in->variant_type == YAFFS_OBJECT_TYPE_FILE && ++ chunk_base < in->variant.file_variant.shrink_size) { ++ /* This has not been invalidated by ++ * a resize */ ++ if (!yaffs_put_chunk_in_file(in, tags.chunk_id, ++ chunk, -1)) ++ alloc_failed = 1; ++ ++ /* File size is calculated by looking at ++ * the data chunks if we have not ++ * seen an object header yet. ++ * Stop this practice once we find an ++ * object header. ++ */ ++ endpos = chunk_base + tags.n_bytes; ++ ++ if (!in->valid && ++ in->variant.file_variant.scanned_size < endpos) { ++ in->variant.file_variant. ++ scanned_size = endpos; ++ in->variant.file_variant. ++ file_size = endpos; ++ } ++ } else if (in) { ++ /* This chunk has been invalidated by a ++ * resize, or a past file deletion ++ * so delete the chunk*/ ++ yaffs_chunk_del(dev, chunk, 1, __LINE__); ++ } ++ } else { ++ /* chunk_id == 0, so it is an ObjectHeader. ++ * Thus, we read in the object header and make ++ * the object ++ */ ++ *found_chunks = 1; ++ ++ yaffs_set_chunk_bit(dev, blk, chunk_in_block); ++ bi->pages_in_use++; ++ ++ oh = NULL; ++ in = NULL; ++ ++ if (tags.extra_available) { ++ in = yaffs_find_or_create_by_number(dev, ++ tags.obj_id, ++ tags.extra_obj_type); ++ if (!in) ++ alloc_failed = 1; ++ } ++ ++ if (!in || ++ (!in->valid && dev->param.disable_lazy_load) || ++ tags.extra_shadows || ++ (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT || ++ tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) { ++ ++ /* If we don't have valid info then we ++ * need to read the chunk ++ * TODO In future we can probably defer ++ * reading the chunk and living with ++ * invalid data until needed. ++ */ ++ ++ result = yaffs_rd_chunk_tags_nand(dev, ++ chunk, ++ chunk_data, ++ NULL); ++ ++ oh = (struct yaffs_obj_hdr *)chunk_data; ++ ++ if (dev->param.inband_tags) { ++ /* Fix up the header if they got ++ * corrupted by inband tags */ ++ oh->shadows_obj = ++ oh->inband_shadowed_obj_id; ++ oh->is_shrink = ++ oh->inband_is_shrink; ++ } ++ ++ if (!in) { ++ in = yaffs_find_or_create_by_number(dev, ++ tags.obj_id, oh->type); ++ if (!in) ++ alloc_failed = 1; ++ } ++ } ++ ++ if (!in) { ++ /* TODO Hoosterman we have a problem! */ ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs tragedy: Could not make object for object %d at chunk %d during scan", ++ tags.obj_id, chunk); ++ return YAFFS_FAIL; ++ } ++ ++ if (in->valid) { ++ /* We have already filled this one. ++ * We have a duplicate that will be ++ * discarded, but we first have to suck ++ * out resize info if it is a file. ++ */ ++ if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) && ++ ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) || ++ (tags.extra_available && ++ tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE) ++ )) { ++ loff_t this_size = (oh) ? ++ yaffs_oh_to_size(oh) : ++ tags.extra_file_size; ++ u32 parent_obj_id = (oh) ? ++ oh->parent_obj_id : ++ tags.extra_parent_id; ++ ++ is_shrink = (oh) ? ++ oh->is_shrink : ++ tags.extra_is_shrink; ++ ++ /* If it is deleted (unlinked ++ * at start also means deleted) ++ * we treat the file size as ++ * being zeroed at this point. ++ */ ++ if (parent_obj_id == YAFFS_OBJECTID_DELETED || ++ parent_obj_id == YAFFS_OBJECTID_UNLINKED) { ++ this_size = 0; ++ is_shrink = 1; ++ } ++ ++ if (is_shrink && ++ in->variant.file_variant.shrink_size > ++ this_size) ++ in->variant.file_variant.shrink_size = ++ this_size; ++ ++ if (is_shrink) ++ bi->has_shrink_hdr = 1; ++ } ++ /* Use existing - destroy this one. */ ++ yaffs_chunk_del(dev, chunk, 1, __LINE__); ++ } ++ ++ if (!in->valid && in->variant_type != ++ (oh ? oh->type : tags.extra_obj_type)) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs tragedy: Bad type, %d != %d, for object %d at chunk %d during scan", ++ oh ? oh->type : tags.extra_obj_type, ++ in->variant_type, tags.obj_id, ++ chunk); ++ in = yaffs_retype_obj(in, oh ? oh->type : tags.extra_obj_type); ++ } ++ ++ if (!in->valid && ++ (tags.obj_id == YAFFS_OBJECTID_ROOT || ++ tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) { ++ /* We only load some info, don't fiddle ++ * with directory structure */ ++ in->valid = 1; ++ ++ if (oh) { ++ in->yst_mode = oh->yst_mode; ++ yaffs_load_attribs(in, oh); ++ in->lazy_loaded = 0; ++ } else { ++ in->lazy_loaded = 1; ++ } ++ in->hdr_chunk = chunk; ++ ++ } else if (!in->valid) { ++ /* we need to load this info */ ++ in->valid = 1; ++ in->hdr_chunk = chunk; ++ if (oh) { ++ in->variant_type = oh->type; ++ in->yst_mode = oh->yst_mode; ++ yaffs_load_attribs(in, oh); ++ ++ if (oh->shadows_obj > 0) ++ yaffs_handle_shadowed_obj(dev, ++ oh->shadows_obj, 1); ++ ++ yaffs_set_obj_name_from_oh(in, oh); ++ parent = yaffs_find_or_create_by_number(dev, ++ oh->parent_obj_id, ++ YAFFS_OBJECT_TYPE_DIRECTORY); ++ file_size = yaffs_oh_to_size(oh); ++ is_shrink = oh->is_shrink; ++ equiv_id = oh->equiv_id; ++ } else { ++ in->variant_type = tags.extra_obj_type; ++ parent = yaffs_find_or_create_by_number(dev, ++ tags.extra_parent_id, ++ YAFFS_OBJECT_TYPE_DIRECTORY); ++ file_size = tags.extra_file_size; ++ is_shrink = tags.extra_is_shrink; ++ equiv_id = tags.extra_equiv_id; ++ in->lazy_loaded = 1; ++ } ++ in->dirty = 0; ++ ++ if (!parent) ++ alloc_failed = 1; ++ ++ /* directory stuff... ++ * hook up to parent ++ */ ++ ++ if (parent && ++ parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) { ++ /* Set up as a directory */ ++ parent->variant_type = ++ YAFFS_OBJECT_TYPE_DIRECTORY; ++ INIT_LIST_HEAD(&parent-> ++ variant.dir_variant.children); ++ } else if (!parent || ++ parent->variant_type != ++ YAFFS_OBJECT_TYPE_DIRECTORY) { ++ /* Hoosterman, another problem.... ++ * Trying to use a non-directory as a directory ++ */ ++ ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." ++ ); ++ parent = dev->lost_n_found; ++ } ++ yaffs_add_obj_to_dir(parent, in); ++ ++ is_unlinked = (parent == dev->del_dir) || ++ (parent == dev->unlinked_dir); ++ ++ if (is_shrink) ++ /* Mark the block */ ++ bi->has_shrink_hdr = 1; ++ ++ /* Note re hardlinks. ++ * Since we might scan a hardlink before its equivalent ++ * object is scanned we put them all in a list. ++ * After scanning is complete, we should have all the ++ * objects, so we run through this list and fix up all ++ * the chains. ++ */ ++ ++ switch (in->variant_type) { ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* Todo got a problem */ ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ file_var = &in->variant.file_variant; ++ if (file_var->scanned_size < file_size) { ++ /* This covers the case where the file ++ * size is greater than the data held. ++ * This will happen if the file is ++ * resized to be larger than its ++ * current data extents. ++ */ ++ file_var->file_size = file_size; ++ file_var->scanned_size = file_size; ++ } ++ ++ if (file_var->shrink_size > file_size) ++ file_var->shrink_size = file_size; ++ ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ hl_var = &in->variant.hardlink_variant; ++ if (!is_unlinked) { ++ hl_var->equiv_id = equiv_id; ++ list_add(&in->hard_links, hard_list); ++ } ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ sl_var = &in->variant.symlink_variant; ++ if (oh) { ++ sl_var->alias = ++ yaffs_clone_str(oh->alias); ++ if (!sl_var->alias) ++ alloc_failed = 1; ++ } ++ break; ++ } ++ } ++ } ++ return alloc_failed ? YAFFS_FAIL : YAFFS_OK; ++} ++ ++int yaffs2_scan_backwards(struct yaffs_dev *dev) ++{ ++ int blk; ++ int block_iter; ++ int start_iter; ++ int end_iter; ++ int n_to_scan = 0; ++ enum yaffs_block_state state; ++ int c; ++ int deleted; ++ LIST_HEAD(hard_list); ++ struct yaffs_block_info *bi; ++ u32 seq_number; ++ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1; ++ u8 *chunk_data; ++ int found_chunks; ++ int alloc_failed = 0; ++ struct yaffs_block_index *block_index = NULL; ++ int alt_block_index = 0; ++ int summary_available; ++ ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "yaffs2_scan_backwards starts intstartblk %d intendblk %d...", ++ dev->internal_start_block, dev->internal_end_block); ++ ++ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; ++ ++ block_index = ++ kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS); ++ ++ if (!block_index) { ++ block_index = ++ vmalloc(n_blocks * sizeof(struct yaffs_block_index)); ++ alt_block_index = 1; ++ } ++ ++ if (!block_index) { ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "yaffs2_scan_backwards() could not allocate block index!" ++ ); ++ return YAFFS_FAIL; ++ } ++ ++ dev->blocks_in_checkpt = 0; ++ ++ chunk_data = yaffs_get_temp_buffer(dev); ++ ++ /* Scan all the blocks to determine their state */ ++ bi = dev->block_info; ++ for (blk = dev->internal_start_block; blk <= dev->internal_end_block; ++ blk++) { ++ yaffs_clear_chunk_bits(dev, blk); ++ bi->pages_in_use = 0; ++ bi->soft_del_pages = 0; ++ ++ yaffs_query_init_block_state(dev, blk, &state, &seq_number); ++ ++ bi->block_state = state; ++ bi->seq_number = seq_number; ++ ++ if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) ++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; ++ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) ++ bi->block_state = YAFFS_BLOCK_STATE_DEAD; ++ ++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, ++ "Block scanning block %d state %d seq %d", ++ blk, bi->block_state, seq_number); ++ ++ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) { ++ dev->blocks_in_checkpt++; ++ ++ } else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) { ++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, ++ "block %d is bad", blk); ++ } else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { ++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty "); ++ dev->n_erased_blocks++; ++ dev->n_free_chunks += dev->param.chunks_per_block; ++ } else if (bi->block_state == ++ YAFFS_BLOCK_STATE_NEEDS_SCAN) { ++ /* Determine the highest sequence number */ ++ if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER && ++ seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) { ++ block_index[n_to_scan].seq = seq_number; ++ block_index[n_to_scan].block = blk; ++ n_to_scan++; ++ if (seq_number >= dev->seq_number) ++ dev->seq_number = seq_number; ++ } else { ++ /* TODO: Nasty sequence number! */ ++ yaffs_trace(YAFFS_TRACE_SCAN, ++ "Block scanning block %d has bad sequence number %d", ++ blk, seq_number); ++ } ++ } ++ bi++; ++ } ++ ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "%d blocks to be sorted...", n_to_scan); ++ ++ cond_resched(); ++ ++ /* Sort the blocks by sequence number */ ++ sort(block_index, n_to_scan, sizeof(struct yaffs_block_index), ++ yaffs2_ybicmp, NULL); ++ ++ cond_resched(); ++ ++ yaffs_trace(YAFFS_TRACE_SCAN, "...done"); ++ ++ /* Now scan the blocks looking at the data. */ ++ start_iter = 0; ++ end_iter = n_to_scan - 1; ++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan); ++ ++ /* For each block.... backwards */ ++ for (block_iter = end_iter; ++ !alloc_failed && block_iter >= start_iter; ++ block_iter--) { ++ /* Cooperative multitasking! This loop can run for so ++ long that watchdog timers expire. */ ++ cond_resched(); ++ ++ /* get the block to scan in the correct order */ ++ blk = block_index[block_iter].block; ++ bi = yaffs_get_block_info(dev, blk); ++ deleted = 0; ++ ++ summary_available = yaffs_summary_read(dev, dev->sum_tags, blk); ++ ++ /* For each chunk in each block that needs scanning.... */ ++ found_chunks = 0; ++ if (summary_available) ++ c = dev->chunks_per_summary - 1; ++ else ++ c = dev->param.chunks_per_block - 1; ++ ++ for (/* c is already initialised */; ++ !alloc_failed && c >= 0 && ++ (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN || ++ bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING); ++ c--) { ++ /* Scan backwards... ++ * Read the tags and decide what to do ++ */ ++ if (yaffs2_scan_chunk(dev, bi, blk, c, ++ &found_chunks, chunk_data, ++ &hard_list, summary_available) == ++ YAFFS_FAIL) ++ alloc_failed = 1; ++ } ++ ++ if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) { ++ /* If we got this far while scanning, then the block ++ * is fully allocated. */ ++ bi->block_state = YAFFS_BLOCK_STATE_FULL; ++ } ++ ++ /* Now let's see if it was dirty */ ++ if (bi->pages_in_use == 0 && ++ !bi->has_shrink_hdr && ++ bi->block_state == YAFFS_BLOCK_STATE_FULL) { ++ yaffs_block_became_dirty(dev, blk); ++ } ++ } ++ ++ yaffs_skip_rest_of_block(dev); ++ ++ if (alt_block_index) ++ vfree(block_index); ++ else ++ kfree(block_index); ++ ++ /* Ok, we've done all the scanning. ++ * Fix up the hard link chains. ++ * We have scanned all the objects, now it's time to add these ++ * hardlinks. ++ */ ++ yaffs_link_fixup(dev, &hard_list); ++ ++ yaffs_release_temp_buffer(dev, chunk_data); ++ ++ if (alloc_failed) ++ return YAFFS_FAIL; ++ ++ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends"); ++ ++ return YAFFS_OK; ++} +diff --git a/fs/yaffs2/yaffs_yaffs2.h b/fs/yaffs2/yaffs_yaffs2.h +new file mode 100644 +index 00000000..2363bfd8 +--- /dev/null ++++ b/fs/yaffs2/yaffs_yaffs2.h +@@ -0,0 +1,39 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_YAFFS2_H__ ++#define __YAFFS_YAFFS2_H__ ++ ++#include "yaffs_guts.h" ++ ++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev); ++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev); ++void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev, ++ struct yaffs_block_info *bi); ++void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no, ++ struct yaffs_block_info *bi); ++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi); ++u32 yaffs2_find_refresh_block(struct yaffs_dev *dev); ++int yaffs2_checkpt_required(struct yaffs_dev *dev); ++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev); ++ ++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev); ++int yaffs2_checkpt_save(struct yaffs_dev *dev); ++int yaffs2_checkpt_restore(struct yaffs_dev *dev); ++ ++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size); ++int yaffs2_scan_backwards(struct yaffs_dev *dev); ++ ++#endif +diff --git a/fs/yaffs2/yportenv.h b/fs/yaffs2/yportenv.h +new file mode 100644 +index 00000000..8975af33 +--- /dev/null ++++ b/fs/yaffs2/yportenv.h +@@ -0,0 +1,85 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2011 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YPORTENV_H__ ++#define __YPORTENV_H__ ++ ++/* ++ * Define the MTD version in terms of Linux Kernel versions ++ * This allows yaffs to be used independantly of the kernel ++ * as well as with it. ++ */ ++ ++#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) ++ ++#ifdef YAFFS_OUT_OF_TREE ++#include "moduleconfig.h" ++#endif ++ ++#include ++#define MTD_VERSION_CODE LINUX_VERSION_CODE ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* These type wrappings are used to support Unicode names in WinCE. */ ++#define YCHAR char ++#define YUCHAR unsigned char ++#define _Y(x) x ++ ++#define YAFFS_LOSTNFOUND_NAME "lost+found" ++#define YAFFS_LOSTNFOUND_PREFIX "obj" ++ ++ ++#define YAFFS_ROOT_MODE 0755 ++#define YAFFS_LOSTNFOUND_MODE 0700 ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++#define Y_CURRENT_TIME CURRENT_TIME.tv_sec ++#define Y_TIME_CONVERT(x) (x).tv_sec ++#else ++#define Y_CURRENT_TIME CURRENT_TIME ++#define Y_TIME_CONVERT(x) (x) ++#endif ++ ++#define compile_time_assertion(assertion) \ ++ ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; }) ++ ++ ++#define yaffs_printf(msk, fmt, ...) \ ++ printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__) ++ ++#define yaffs_trace(msk, fmt, ...) do { \ ++ if (yaffs_trace_mask & (msk)) \ ++ printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \ ++} while (0) ++ ++ ++#endif +diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h +index 5f52690c..832f533d 100644 +--- a/include/asm-generic/gpio.h ++++ b/include/asm-generic/gpio.h +@@ -100,7 +100,7 @@ struct gpio_chip { + unsigned offset); + + int (*direction_input)(struct gpio_chip *chip, +- unsigned offset); ++ unsigned offset, int value); + int (*get)(struct gpio_chip *chip, + unsigned offset); + int (*direction_output)(struct gpio_chip *chip, +@@ -153,7 +153,7 @@ extern struct gpio_chip *gpiochip_find(const void *data, + extern int gpio_request(unsigned gpio, const char *label); + extern void gpio_free(unsigned gpio); + +-extern int gpio_direction_input(unsigned gpio); ++extern int gpio_direction_input(unsigned gpio, int value); + extern int gpio_direction_output(unsigned gpio, int value); + + extern int gpio_set_debounce(unsigned gpio, unsigned debounce); +diff --git a/include/linux/gk-i2cmux.h b/include/linux/gk-i2cmux.h +new file mode 100644 +index 00000000..b9757f98 +--- /dev/null ++++ b/include/linux/gk-i2cmux.h +@@ -0,0 +1,18 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _LINUX_GK_I2CMUX_H ++#define _LINUX_GK_I2CMUX_H ++ ++struct gk_i2cmux_platform_data { ++ int parent; ++ unsigned number; ++ unsigned gpio; ++ unsigned select_function; ++ unsigned deselect_function; ++}; ++ ++#endif /* _LINUX_GK_I2CMUX_H */ +diff --git a/include/linux/i2c.h b/include/linux/i2c.h +index 195d8b3d..ea2ade1f 100644 +--- a/include/linux/i2c.h ++++ b/include/linux/i2c.h +@@ -68,6 +68,8 @@ extern int i2c_master_recv(const struct i2c_client *client, char *buf, + */ + extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num); ++extern int i2c_transfer_noevent(struct i2c_adapter *adap, struct i2c_msg *msgs, ++ int num); + + /* This is the very generalized SMBus access routine. You probably do not + want to use this, though; one of the functions below may be much easier, +@@ -361,6 +363,8 @@ struct i2c_algorithm { + int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data); ++ int (*master_xfer_noevent)(struct i2c_adapter *adap, struct i2c_msg *msgs, ++ int num); + + /* To determine what the adapter supports */ + u32 (*functionality) (struct i2c_adapter *); +diff --git a/include/linux/ipcbus.h b/include/linux/ipcbus.h +new file mode 100644 +index 00000000..848b4778 +--- /dev/null ++++ b/include/linux/ipcbus.h +@@ -0,0 +1,29 @@ ++/* ++ * IPC bus. ++ */ ++ ++#ifndef __LINUX_IPCBUS_H ++#define __LINUX_IPCBUS_H ++ ++#include ++#include ++ ++struct ipc_driver { ++ int (*match)(struct device *); ++ int (*probe)(struct device *); ++ int (*remove)(struct device *); ++ void (*shutdown)(struct device *); ++ int (*suspend)(struct device *, pm_message_t); ++ int (*resume)(struct device *); ++ ++ struct device_driver driver; ++ struct device *devices; ++}; ++ ++#define to_ipc_driver(x) container_of((x), struct ipc_driver, driver) ++ ++ ++int ipc_register_driver(struct ipc_driver *); ++void ipc_unregister_driver(struct ipc_driver *); ++ ++#endif /* __LINUX_IPCBUS_H */ +diff --git a/include/linux/phy.h b/include/linux/phy.h +index 6fe0a37d..e53bb8ce 100644 +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -119,6 +119,7 @@ struct mii_bus { + + /* list of all PHYs on bus */ + struct phy_device *phy_map[PHY_MAX_ADDR]; ++ struct phy_device *phy_used; + + /* PHY addresses to be ignored when probing */ + u32 phy_mask; +diff --git a/include/linux/spinlock_types.h b/include/linux/spinlock_types.h +index 73548eb1..eb2231ed 100644 +--- a/include/linux/spinlock_types.h ++++ b/include/linux/spinlock_types.h +@@ -80,6 +80,14 @@ typedef struct spinlock { + + #define __SPIN_LOCK_UNLOCKED(lockname) \ + (spinlock_t ) __SPIN_LOCK_INITIALIZER(lockname) ++ ++/* ++ * SPIN_LOCK_UNLOCKED defeats lockdep state tracking and is hence ++ * deprecated. ++ * Please use DEFINE_SPINLOCK() or __SPIN_LOCK_UNLOCKED() as ++ * appropriate. ++ */ ++#define SPIN_LOCK_UNLOCKED __SPIN_LOCK_UNLOCKED(old_style_spin_init) + + #define DEFINE_SPINLOCK(x) spinlock_t x = __SPIN_LOCK_UNLOCKED(x) + +diff --git a/include/linux/usb.h b/include/linux/usb.h +index 4e8e6685..a66954f6 100644 +--- a/include/linux/usb.h ++++ b/include/linux/usb.h +@@ -714,6 +714,22 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size) + .bcdDevice_lo = (lo), \ + .bcdDevice_hi = (hi) + ++/** ++ * USB_DEVICE_INTERFACE_CLASS - describe a usb device with a specific interface class ++ * @vend: the 16 bit USB Vendor ID ++ * @prod: the 16 bit USB Product ID ++ * @cl: bInterfaceClass value ++ * ++ * This macro is used to create a struct usb_device_id that matches a ++ * specific interface class of devices. ++ */ ++#define USB_DEVICE_INTERFACE_CLASS(vend, prod, cl) \ ++ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ ++ USB_DEVICE_ID_MATCH_INT_CLASS, \ ++ .idVendor = (vend), \ ++ .idProduct = (prod), \ ++ .bInterfaceClass = (cl) ++ + /** + * USB_DEVICE_INTERFACE_PROTOCOL - describe a usb device with a specific interface protocol + * @vend: the 16 bit USB Vendor ID +@@ -1273,6 +1289,7 @@ struct urb { + int number_of_packets; /* (in) number of ISO packets */ + int interval; /* (modify) transfer interval + * (INT/ISO) */ ++ int align; + int error_count; /* (return) number of ISO errors */ + void *context; /* (in) context for completion */ + usb_complete_t complete; /* (in) completion routine */ +diff --git a/include/linux/usb/android_composite.h b/include/linux/usb/android_composite.h +new file mode 100644 +index 00000000..62e72e3b +--- /dev/null ++++ b/include/linux/usb/android_composite.h +@@ -0,0 +1,101 @@ ++/* ++ * Platform data for Android USB ++ * ++ * Copyright (C) 2008 Google, Inc. ++ * Author: Mike Lockwood ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++#ifndef __LINUX_USB_ANDROID_H ++#define __LINUX_USB_ANDROID_H ++ ++#include ++#include ++ ++struct android_usb_function { ++ struct list_head list; ++ char *name; ++ int (*bind_config)(struct usb_configuration *c); ++}; ++ ++struct android_usb_product { ++ /* Default product ID. */ ++ __u16 product_id; ++ ++ /* List of function names associated with this product. ++ * This is used to compute the USB product ID dynamically ++ * based on which functions are enabled. ++ */ ++ int num_functions; ++ char **functions; ++}; ++ ++struct android_usb_platform_data { ++ /* USB device descriptor fields */ ++ __u16 vendor_id; ++ ++ /* Default product ID. */ ++ __u16 product_id; ++ ++ __u16 version; ++ ++ char *product_name; ++ char *manufacturer_name; ++ char *serial_number; ++ ++ /* List of available USB products. ++ * This is used to compute the USB product ID dynamically ++ * based on which functions are enabled. ++ * if num_products is zero or no match can be found, ++ * we use the default product ID ++ */ ++ int num_products; ++ struct android_usb_product *products; ++ ++ /* List of all supported USB functions. ++ * This list is used to define the order in which ++ * the functions appear in the configuration's list of USB interfaces. ++ * This is necessary to avoid depending upon the order in which ++ * the individual function drivers are initialized. ++ */ ++ int num_functions; ++ char **functions; ++}; ++ ++/* Platform data for "usb_mass_storage" driver. */ ++struct usb_mass_storage_platform_data { ++ /* Contains values for the SC_INQUIRY SCSI command. */ ++ char *vendor; ++ char *product; ++ int release; ++ ++ /* number of LUNS */ ++ int nluns; ++}; ++ ++/* Platform data for USB ethernet driver. */ ++struct usb_ether_platform_data { ++ u8 ethaddr[ETH_ALEN]; ++ u32 vendorID; ++ const char *vendorDescr; ++}; ++ ++/* Platform data for ACM driver. */ ++struct acm_platform_data { ++ u8 num_inst; ++}; ++ ++extern void android_register_function(struct android_usb_function *f); ++ ++extern void android_enable_function(struct usb_function *f, int enable); ++ ++ ++#endif /* __LINUX_USB_ANDROID_H */ +diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h +index 5de41570..feb77716 100644 +--- a/include/linux/usb/hcd.h ++++ b/include/linux/usb/hcd.h +@@ -126,6 +126,7 @@ struct usb_hcd { + unsigned wireless:1; /* Wireless USB HCD */ + unsigned authorized_default:1; + unsigned has_tt:1; /* Integrated TT in root hub */ ++ unsigned cant_recv_wakeups:1; + + unsigned int irq; /* irq allocated */ + void __iomem *regs; /* device memory/io */ +@@ -393,12 +394,13 @@ extern int usb_hcd_pci_probe(struct pci_dev *dev, + extern void usb_hcd_pci_remove(struct pci_dev *dev); + extern void usb_hcd_pci_shutdown(struct pci_dev *dev); + +-#ifdef CONFIG_PM_SLEEP ++#ifdef CONFIG_PM + extern const struct dev_pm_ops usb_hcd_pci_pm_ops; + #endif + #endif /* CONFIG_PCI */ + + /* pci-ish (pdev null is ok) buffer alloc/mapping support */ ++void usb_init_pool_max(void); + int hcd_buffer_create(struct usb_hcd *hcd); + void hcd_buffer_destroy(struct usb_hcd *hcd); + +diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h +index 3e93de7e..0972470b 100644 +--- a/include/linux/usb/quirks.h ++++ b/include/linux/usb/quirks.h +@@ -30,4 +30,21 @@ + descriptor */ + #define USB_QUIRK_DELAY_INIT 0x00000040 + ++/* device generates spurious wakeup, ignore remote wakeup capability */ ++#define USB_QUIRK_IGNORE_REMOTE_WAKEUP 0x00000200 ++ ++/* device can't handle device_qualifier descriptor requests */ ++#define USB_QUIRK_DEVICE_QUALIFIER 0x00000100 ++ ++/* ++ * For high speed and super speed interupt endpoints, the USB 2.0 and ++ * USB 3.0 spec require the interval in microframes ++ * (1 microframe = 125 microseconds) to be calculated as ++ * interval = 2 ^ (bInterval-1). ++ * ++ * Devices with this quirk report their bInterval as the result of this ++ * calculation instead of the exponent variable used in the calculation. ++ */ ++#define USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL 0x00000080 ++ + #endif /* __LINUX_USB_QUIRKS_H */ +diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h +index 47428388..56dc033f 100644 +--- a/include/linux/usb/serial.h ++++ b/include/linux/usb/serial.h +@@ -66,6 +66,7 @@ + * port. + * @flags: usb serial port flags + * @write_wait: a wait_queue_head_t used by the port. ++ * @delta_msr_wait: modem-status-change wait queue + * @work: work queue entry for the line discipline waking up. + * @throttled: nonzero if the read urb is inactive to throttle the device + * @throttle_req: nonzero if the tty wants to throttle us +@@ -112,6 +113,7 @@ struct usb_serial_port { + + unsigned long flags; + wait_queue_head_t write_wait; ++ wait_queue_head_t delta_msr_wait; + struct work_struct work; + char throttled; + char throttle_req; +diff --git a/include/linux/vermagic.h b/include/linux/vermagic.h +index 6f8fbcf1..7d89860d 100644 +--- a/include/linux/vermagic.h ++++ b/include/linux/vermagic.h +@@ -25,9 +25,12 @@ + #define MODULE_ARCH_VERMAGIC "" + #endif + ++#if 0 + #define VERMAGIC_STRING \ + UTS_RELEASE " " \ + MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT \ + MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS \ + MODULE_ARCH_VERMAGIC +- ++#else ++#define VERMAGIC_STRING "3.4.43-Goke" ++#endif +diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c +index 92ac7e73..924f357f 100644 +--- a/net/ipv4/ipconfig.c ++++ b/net/ipv4/ipconfig.c +@@ -89,7 +89,7 @@ + + /* Define the friendly delay before and after opening net devices */ + #define CONF_POST_OPEN 10 /* After opening: 10 msecs */ +-#define CONF_CARRIER_TIMEOUT 120000 /* Wait for carrier timeout */ ++#define CONF_CARRIER_TIMEOUT 2000 /* Wait for carrier timeout */ + + /* Define the timeout for waiting for a DHCP/BOOTP/RARP reply */ + #define CONF_OPEN_RETRIES 2 /* (Re)open devices twice */ +diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c +index a9077f44..f5f310c0 100644 +--- a/net/ipv4/tcp_cubic.c ++++ b/net/ipv4/tcp_cubic.c +@@ -153,6 +153,21 @@ static void bictcp_init(struct sock *sk) + tcp_sk(sk)->snd_ssthresh = initial_ssthresh; + } + ++static void bictcp_cwnd_event(struct sock *sk, enum tcp_ca_event event) ++{ ++ if (event == CA_EVENT_TX_START) { ++ s32 delta = tcp_time_stamp - tcp_sk(sk)->lsndtime; ++ struct bictcp *ca = inet_csk_ca(sk); ++ ++ /* We were application limited (idle) for a while. ++ * Shift epoch_start to keep cwnd growth to cubic curve. ++ */ ++ if (ca->epoch_start && delta > 0) ++ ca->epoch_start += delta; ++ return; ++ } ++} ++ + /* calculate the cubic root of x using a table lookup followed by one + * Newton-Raphson iteration. + * Avg err ~= 0.195% +@@ -437,7 +452,8 @@ static struct tcp_congestion_ops cubictcp __read_mostly = { + .cong_avoid = bictcp_cong_avoid, + .set_state = bictcp_state, + .undo_cwnd = bictcp_undo_cwnd, +- .pkts_acked = bictcp_acked, ++ .cwnd_event = bictcp_cwnd_event, ++ .pkts_acked = bictcp_acked, + .owner = THIS_MODULE, + .name = "cubic", + }; +diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig +index 2e4444fe..48788d58 100644 +--- a/net/wireless/Kconfig ++++ b/net/wireless/Kconfig +@@ -1,5 +1,5 @@ + config WIRELESS_EXT +- bool ++ def_bool y + + config WEXT_CORE + def_bool y +@@ -11,10 +11,10 @@ config WEXT_PROC + depends on WEXT_CORE + + config WEXT_SPY +- bool ++ def_bool y + + config WEXT_PRIV +- bool ++ def_bool y + + config CFG80211 + tristate "cfg80211 - wireless configuration API" diff --git a/br-ext-chip-goke/board/gk710x/kernel/patches/0003-overlayfs-v13-3.4-rc7.patch b/br-ext-chip-goke/board/gk710x/kernel/patches/0003-overlayfs-v13-3.4-rc7.patch new file mode 100644 index 00000000..9787cc64 --- /dev/null +++ b/br-ext-chip-goke/board/gk710x/kernel/patches/0003-overlayfs-v13-3.4-rc7.patch @@ -0,0 +1,3363 @@ +diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking +index 4fca82e..42b0539 100644 +--- a/Documentation/filesystems/Locking ++++ b/Documentation/filesystems/Locking +@@ -62,6 +62,7 @@ ata *); + int (*removexattr) (struct dentry *, const char *); + void (*truncate_range)(struct inode *, loff_t, loff_t); + int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len); ++ struct file *(*open)(struct dentry *,struct file *,const struct cred *); + + locking rules: + all may block +@@ -89,6 +90,7 @@ listxattr: no + removexattr: yes + truncate_range: yes + fiemap: no ++open: no + Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on + victim. + cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem. +diff --git a/Documentation/filesystems/overlayfs.txt b/Documentation/filesystems/overlayfs.txt +new file mode 100644 +index 0000000..7161dc3 +--- /dev/null ++++ b/Documentation/filesystems/overlayfs.txt +@@ -0,0 +1,199 @@ ++Written by: Neil Brown ++ ++Overlay Filesystem ++================== ++ ++This document describes a prototype for a new approach to providing ++overlay-filesystem functionality in Linux (sometimes referred to as ++union-filesystems). An overlay-filesystem tries to present a ++filesystem which is the result over overlaying one filesystem on top ++of the other. ++ ++The result will inevitably fail to look exactly like a normal ++filesystem for various technical reasons. The expectation is that ++many use cases will be able to ignore these differences. ++ ++This approach is 'hybrid' because the objects that appear in the ++filesystem do not all appear to belong to that filesystem. In many ++cases an object accessed in the union will be indistinguishable ++from accessing the corresponding object from the original filesystem. ++This is most obvious from the 'st_dev' field returned by stat(2). ++ ++While directories will report an st_dev from the overlay-filesystem, ++all non-directory objects will report an st_dev from the lower or ++upper filesystem that is providing the object. Similarly st_ino will ++only be unique when combined with st_dev, and both of these can change ++over the lifetime of a non-directory object. Many applications and ++tools ignore these values and will not be affected. ++ ++Upper and Lower ++--------------- ++ ++An overlay filesystem combines two filesystems - an 'upper' filesystem ++and a 'lower' filesystem. When a name exists in both filesystems, the ++object in the 'upper' filesystem is visible while the object in the ++'lower' filesystem is either hidden or, in the case of directories, ++merged with the 'upper' object. ++ ++It would be more correct to refer to an upper and lower 'directory ++tree' rather than 'filesystem' as it is quite possible for both ++directory trees to be in the same filesystem and there is no ++requirement that the root of a filesystem be given for either upper or ++lower. ++ ++The lower filesystem can be any filesystem supported by Linux and does ++not need to be writable. The lower filesystem can even be another ++overlayfs. The upper filesystem will normally be writable and if it ++is it must support the creation of trusted.* extended attributes, and ++must provide valid d_type in readdir responses, at least for symbolic ++links - so NFS is not suitable. ++ ++A read-only overlay of two read-only filesystems may use any ++filesystem type. ++ ++Directories ++----------- ++ ++Overlaying mainly involved directories. If a given name appears in both ++upper and lower filesystems and refers to a non-directory in either, ++then the lower object is hidden - the name refers only to the upper ++object. ++ ++Where both upper and lower objects are directories, a merged directory ++is formed. ++ ++At mount time, the two directories given as mount options are combined ++into a merged directory: ++ ++ mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper /overlay ++ ++Then whenever a lookup is requested in such a merged directory, the ++lookup is performed in each actual directory and the combined result ++is cached in the dentry belonging to the overlay filesystem. If both ++actual lookups find directories, both are stored and a merged ++directory is created, otherwise only one is stored: the upper if it ++exists, else the lower. ++ ++Only the lists of names from directories are merged. Other content ++such as metadata and extended attributes are reported for the upper ++directory only. These attributes of the lower directory are hidden. ++ ++whiteouts and opaque directories ++-------------------------------- ++ ++In order to support rm and rmdir without changing the lower ++filesystem, an overlay filesystem needs to record in the upper filesystem ++that files have been removed. This is done using whiteouts and opaque ++directories (non-directories are always opaque). ++ ++The overlay filesystem uses extended attributes with a ++"trusted.overlay." prefix to record these details. ++ ++A whiteout is created as a symbolic link with target ++"(overlay-whiteout)" and with xattr "trusted.overlay.whiteout" set to "y". ++When a whiteout is found in the upper level of a merged directory, any ++matching name in the lower level is ignored, and the whiteout itself ++is also hidden. ++ ++A directory is made opaque by setting the xattr "trusted.overlay.opaque" ++to "y". Where the upper filesystem contains an opaque directory, any ++directory in the lower filesystem with the same name is ignored. ++ ++readdir ++------- ++ ++When a 'readdir' request is made on a merged directory, the upper and ++lower directories are each read and the name lists merged in the ++obvious way (upper is read first, then lower - entries that already ++exist are not re-added). This merged name list is cached in the ++'struct file' and so remains as long as the file is kept open. If the ++directory is opened and read by two processes at the same time, they ++will each have separate caches. A seekdir to the start of the ++directory (offset 0) followed by a readdir will cause the cache to be ++discarded and rebuilt. ++ ++This means that changes to the merged directory do not appear while a ++directory is being read. This is unlikely to be noticed by many ++programs. ++ ++seek offsets are assigned sequentially when the directories are read. ++Thus if ++ - read part of a directory ++ - remember an offset, and close the directory ++ - re-open the directory some time later ++ - seek to the remembered offset ++ ++there may be little correlation between the old and new locations in ++the list of filenames, particularly if anything has changed in the ++directory. ++ ++Readdir on directories that are not merged is simply handled by the ++underlying directory (upper or lower). ++ ++ ++Non-directories ++--------------- ++ ++Objects that are not directories (files, symlinks, device-special ++files etc.) are presented either from the upper or lower filesystem as ++appropriate. When a file in the lower filesystem is accessed in a way ++the requires write-access, such as opening for write access, changing ++some metadata etc., the file is first copied from the lower filesystem ++to the upper filesystem (copy_up). Note that creating a hard-link ++also requires copy_up, though of course creation of a symlink does ++not. ++ ++The copy_up may turn out to be unnecessary, for example if the file is ++opened for read-write but the data is not modified. ++ ++The copy_up process first makes sure that the containing directory ++exists in the upper filesystem - creating it and any parents as ++necessary. It then creates the object with the same metadata (owner, ++mode, mtime, symlink-target etc.) and then if the object is a file, the ++data is copied from the lower to the upper filesystem. Finally any ++extended attributes are copied up. ++ ++Once the copy_up is complete, the overlay filesystem simply ++provides direct access to the newly created file in the upper ++filesystem - future operations on the file are barely noticed by the ++overlay filesystem (though an operation on the name of the file such as ++rename or unlink will of course be noticed and handled). ++ ++ ++Non-standard behavior ++--------------------- ++ ++The copy_up operation essentially creates a new, identical file and ++moves it over to the old name. The new file may be on a different ++filesystem, so both st_dev and st_ino of the file may change. ++ ++Any open files referring to this inode will access the old data and ++metadata. Similarly any file locks obtained before copy_up will not ++apply to the copied up file. ++ ++On a file is opened with O_RDONLY fchmod(2), fchown(2), futimesat(2) ++and fsetxattr(2) will fail with EROFS. ++ ++If a file with multiple hard links is copied up, then this will ++"break" the link. Changes will not be propagated to other names ++referring to the same inode. ++ ++Symlinks in /proc/PID/ and /proc/PID/fd which point to a non-directory ++object in overlayfs will not contain vaid absolute paths, only ++relative paths leading up to the filesystem's root. This will be ++fixed in the future. ++ ++Some operations are not atomic, for example a crash during copy_up or ++rename will leave the filesystem in an inconsitent state. This will ++be addressed in the future. ++ ++Changes to underlying filesystems ++--------------------------------- ++ ++Offline changes, when the overlay is not mounted, are allowed to either ++the upper or the lower trees. ++ ++Changes to the underlying filesystems while part of a mounted overlay ++filesystem are not allowed. If the underlying filesystem is changed, ++the behavior of the overlay is undefined, though it will not result in ++a crash or deadlock. +diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt +index 0d04920..f06c91f 100644 +--- a/Documentation/filesystems/vfs.txt ++++ b/Documentation/filesystems/vfs.txt +@@ -364,6 +364,8 @@ struct inode_operations { + ssize_t (*listxattr) (struct dentry *, char *, size_t); + int (*removexattr) (struct dentry *, const char *); + void (*truncate_range)(struct inode *, loff_t, loff_t); ++ struct file *(*open) (struct dentry *, struct file *, ++ const struct cred *); + }; + + Again, all methods are called without any locks being held, unless +@@ -475,6 +477,12 @@ otherwise noted. + truncate_range: a method provided by the underlying filesystem to truncate a + range of blocks , i.e. punch a hole somewhere in a file. + ++ open: this is an alternative to f_op->open(), the difference is that this ++ method may return any open file, not necessarily originating from the ++ same filesystem as the one i_op->open() was called on. It may be useful ++ for stacking filesystems which want to allow native I/O directly on ++ underlying files. ++ + + The Address Space Object + ======================== +diff --git a/MAINTAINERS b/MAINTAINERS +index b362709..7ba226c 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -4998,6 +4998,13 @@ F: drivers/scsi/osd/ + F: include/scsi/osd_* + F: fs/exofs/ + ++OVERLAYFS FILESYSTEM ++M: Miklos Szeredi ++L: linux-fsdevel@vger.kernel.org ++S: Supported ++F: fs/overlayfs/* ++F: Documentation/filesystems/overlayfs.txt ++ + P54 WIRELESS DRIVER + M: Christian Lamparter + L: linux-wireless@vger.kernel.org +diff --git a/fs/Kconfig b/fs/Kconfig +index f95ae3a..e0c5d43 100644 +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -67,6 +67,7 @@ source "fs/quota/Kconfig" + + source "fs/autofs4/Kconfig" + source "fs/fuse/Kconfig" ++source "fs/overlayfs/Kconfig" + + config CUSE + tristate "Character device in Userspace support" +diff --git a/fs/Makefile b/fs/Makefile +index 2fb9779..fcd9788 100644 +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -106,6 +106,7 @@ obj-$(CONFIG_QNX6FS_FS) += qnx6/ + obj-$(CONFIG_AUTOFS4_FS) += autofs4/ + obj-$(CONFIG_ADFS_FS) += adfs/ + obj-$(CONFIG_FUSE_FS) += fuse/ ++obj-$(CONFIG_OVERLAYFS_FS) += overlayfs/ + obj-$(CONFIG_UDF_FS) += udf/ + obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ + obj-$(CONFIG_OMFS_FS) += omfs/ +diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c +index 6895493..c54ea90 100644 +--- a/fs/ecryptfs/main.c ++++ b/fs/ecryptfs/main.c +@@ -544,6 +544,13 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags + s->s_maxbytes = path.dentry->d_sb->s_maxbytes; + s->s_blocksize = path.dentry->d_sb->s_blocksize; + s->s_magic = ECRYPTFS_SUPER_MAGIC; ++ s->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1; ++ ++ rc = -EINVAL; ++ if (s->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { ++ printk(KERN_ERR "eCryptfs: maximum fs stacking depth exceeded\n"); ++ goto out_free; ++ } + + inode = ecryptfs_get_inode(path.dentry->d_inode, s); + rc = PTR_ERR(inode); +diff --git a/fs/namei.c b/fs/namei.c +index c427919..e172a5b 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -328,6 +328,36 @@ static inline int do_inode_permission(struct inode *inode, int mask) + } + + /** ++ * inode_only_permission - check access rights to a given inode only ++ * @inode: inode to check permissions on ++ * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, ...) ++ * ++ * Uses to check read/write/execute permissions on an inode directly, we do ++ * not check filesystem permissions. ++ */ ++int inode_only_permission(struct inode *inode, int mask) ++{ ++ int retval; ++ ++ /* ++ * Nobody gets write access to an immutable file. ++ */ ++ if (unlikely(mask & MAY_WRITE) && IS_IMMUTABLE(inode)) ++ return -EACCES; ++ ++ retval = do_inode_permission(inode, mask); ++ if (retval) ++ return retval; ++ ++ retval = devcgroup_inode_permission(inode, mask); ++ if (retval) ++ return retval; ++ ++ return security_inode_permission(inode, mask); ++} ++EXPORT_SYMBOL(inode_only_permission); ++ ++/** + * inode_permission - check for access rights to a given inode + * @inode: inode to check permission on + * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, ...) +@@ -341,8 +371,6 @@ static inline int do_inode_permission(struct inode *inode, int mask) + */ + int inode_permission(struct inode *inode, int mask) + { +- int retval; +- + if (unlikely(mask & MAY_WRITE)) { + umode_t mode = inode->i_mode; + +@@ -352,23 +380,9 @@ int inode_permission(struct inode *inode, int mask) + if (IS_RDONLY(inode) && + (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) + return -EROFS; +- +- /* +- * Nobody gets write access to an immutable file. +- */ +- if (IS_IMMUTABLE(inode)) +- return -EACCES; + } + +- retval = do_inode_permission(inode, mask); +- if (retval) +- return retval; +- +- retval = devcgroup_inode_permission(inode, mask); +- if (retval) +- return retval; +- +- return security_inode_permission(inode, mask); ++ return inode_only_permission(inode, mask); + } + + /** +diff --git a/fs/namespace.c b/fs/namespace.c +index e608199..2551ec0 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -1325,6 +1325,24 @@ void drop_collected_mounts(struct vfsmount *mnt) + release_mounts(&umount_list); + } + ++struct vfsmount *clone_private_mount(struct path *path) ++{ ++ struct mount *old_mnt = real_mount(path->mnt); ++ struct mount *new_mnt; ++ ++ if (IS_MNT_UNBINDABLE(old_mnt)) ++ return ERR_PTR(-EINVAL); ++ ++ down_read(&namespace_sem); ++ new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE); ++ up_read(&namespace_sem); ++ if (!new_mnt) ++ return ERR_PTR(-ENOMEM); ++ ++ return &new_mnt->mnt; ++} ++EXPORT_SYMBOL_GPL(clone_private_mount); ++ + int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg, + struct vfsmount *root) + { +diff --git a/fs/open.c b/fs/open.c +index 5720854..3e132ba 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -644,24 +644,24 @@ static inline int __get_file_write_access(struct inode *inode, + return error; + } + +-static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, +- struct file *f, +- int (*open)(struct inode *, struct file *), +- const struct cred *cred) ++static struct file *__dentry_open(struct path *path, struct file *f, ++ int (*open)(struct inode *, struct file *), ++ const struct cred *cred) + { + static const struct file_operations empty_fops = {}; + struct inode *inode; + int error; + ++ path_get(path); + f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | + FMODE_PREAD | FMODE_PWRITE; + + if (unlikely(f->f_flags & O_PATH)) + f->f_mode = FMODE_PATH; + +- inode = dentry->d_inode; ++ inode = path->dentry->d_inode; + if (f->f_mode & FMODE_WRITE) { +- error = __get_file_write_access(inode, mnt); ++ error = __get_file_write_access(inode, path->mnt); + if (error) + goto cleanup_file; + if (!special_file(inode->i_mode)) +@@ -669,8 +669,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, + } + + f->f_mapping = inode->i_mapping; +- f->f_path.dentry = dentry; +- f->f_path.mnt = mnt; ++ f->f_path = *path; + f->f_pos = 0; + file_sb_list_add(f, inode->i_sb); + +@@ -727,7 +726,7 @@ cleanup_all: + * here, so just reset the state. + */ + file_reset_write(f); +- mnt_drop_write(mnt); ++ mnt_drop_write(path->mnt); + } + } + file_sb_list_del(f); +@@ -735,8 +734,7 @@ cleanup_all: + f->f_path.mnt = NULL; + cleanup_file: + put_filp(f); +- dput(dentry); +- mntput(mnt); ++ path_put(path); + return ERR_PTR(error); + } + +@@ -762,14 +760,14 @@ cleanup_file: + struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, + int (*open)(struct inode *, struct file *)) + { ++ struct path path = { .dentry = dentry, .mnt = nd->path.mnt }; + const struct cred *cred = current_cred(); + + if (IS_ERR(nd->intent.open.file)) + goto out; + if (IS_ERR(dentry)) + goto out_err; +- nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt), +- nd->intent.open.file, ++ nd->intent.open.file = __dentry_open(&path, nd->intent.open.file, + open, cred); + out: + return nd->intent.open.file; +@@ -797,11 +795,9 @@ struct file *nameidata_to_filp(struct nameidata *nd) + nd->intent.open.file = NULL; + + /* Has the filesystem initialised the file for us? */ +- if (filp->f_path.dentry == NULL) { +- path_get(&nd->path); +- filp = __dentry_open(nd->path.dentry, nd->path.mnt, filp, +- NULL, cred); +- } ++ if (filp->f_path.dentry == NULL) ++ filp = vfs_open(&nd->path, filp, cred); ++ + return filp; + } + +@@ -812,27 +808,48 @@ struct file *nameidata_to_filp(struct nameidata *nd) + struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, + const struct cred *cred) + { +- int error; + struct file *f; ++ struct file *ret; ++ struct path path = { .dentry = dentry, .mnt = mnt }; + + validate_creds(cred); + + /* We must always pass in a valid mount pointer. */ + BUG_ON(!mnt); + +- error = -ENFILE; ++ ret = ERR_PTR(-ENFILE); + f = get_empty_filp(); +- if (f == NULL) { +- dput(dentry); +- mntput(mnt); +- return ERR_PTR(error); ++ if (f != NULL) { ++ f->f_flags = flags; ++ ret = vfs_open(&path, f, cred); + } ++ path_put(&path); + +- f->f_flags = flags; +- return __dentry_open(dentry, mnt, f, NULL, cred); ++ return ret; + } + EXPORT_SYMBOL(dentry_open); + ++/** ++ * vfs_open - open the file at the given path ++ * @path: path to open ++ * @filp: newly allocated file with f_flag initialized ++ * @cred: credentials to use ++ * ++ * Open the file. If successful, the returned file will have acquired ++ * an additional reference for path. ++ */ ++struct file *vfs_open(struct path *path, struct file *filp, ++ const struct cred *cred) ++{ ++ struct inode *inode = path->dentry->d_inode; ++ ++ if (inode->i_op->open) ++ return inode->i_op->open(path->dentry, filp, cred); ++ else ++ return __dentry_open(path, filp, NULL, cred); ++} ++EXPORT_SYMBOL(vfs_open); ++ + static void __put_unused_fd(struct files_struct *files, unsigned int fd) + { + struct fdtable *fdt = files_fdtable(files); +diff --git a/fs/overlayfs/Kconfig b/fs/overlayfs/Kconfig +new file mode 100644 +index 0000000..c4517da +--- /dev/null ++++ b/fs/overlayfs/Kconfig +@@ -0,0 +1,4 @@ ++config OVERLAYFS_FS ++ tristate "Overlay filesystem support" ++ help ++ Add support for overlay filesystem. +diff --git a/fs/overlayfs/Makefile b/fs/overlayfs/Makefile +new file mode 100644 +index 0000000..8f91889 +--- /dev/null ++++ b/fs/overlayfs/Makefile +@@ -0,0 +1,7 @@ ++# ++# Makefile for the overlay filesystem. ++# ++ ++obj-$(CONFIG_OVERLAYFS_FS) += overlayfs.o ++ ++overlayfs-objs := super.o inode.o dir.o readdir.o copy_up.o +diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c +new file mode 100644 +index 0000000..87dbeee +--- /dev/null ++++ b/fs/overlayfs/copy_up.c +@@ -0,0 +1,385 @@ ++/* ++ * ++ * Copyright (C) 2011 Novell Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "overlayfs.h" ++ ++#define OVL_COPY_UP_CHUNK_SIZE (1 << 20) ++ ++static int ovl_copy_up_xattr(struct dentry *old, struct dentry *new) ++{ ++ ssize_t list_size, size; ++ char *buf, *name, *value; ++ int error; ++ ++ if (!old->d_inode->i_op->getxattr || ++ !new->d_inode->i_op->getxattr) ++ return 0; ++ ++ list_size = vfs_listxattr(old, NULL, 0); ++ if (list_size <= 0) { ++ if (list_size == -EOPNOTSUPP) ++ return 0; ++ return list_size; ++ } ++ ++ buf = kzalloc(list_size, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ error = -ENOMEM; ++ value = kmalloc(XATTR_SIZE_MAX, GFP_KERNEL); ++ if (!value) ++ goto out; ++ ++ list_size = vfs_listxattr(old, buf, list_size); ++ if (list_size <= 0) { ++ error = list_size; ++ goto out_free_value; ++ } ++ ++ for (name = buf; name < (buf + list_size); name += strlen(name) + 1) { ++ size = vfs_getxattr(old, name, value, XATTR_SIZE_MAX); ++ if (size <= 0) { ++ error = size; ++ goto out_free_value; ++ } ++ error = vfs_setxattr(new, name, value, size, 0); ++ if (error) ++ goto out_free_value; ++ } ++ ++out_free_value: ++ kfree(value); ++out: ++ kfree(buf); ++ return error; ++} ++ ++static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len) ++{ ++ struct file *old_file; ++ struct file *new_file; ++ int error = 0; ++ ++ if (len == 0) ++ return 0; ++ ++ old_file = ovl_path_open(old, O_RDONLY); ++ if (IS_ERR(old_file)) ++ return PTR_ERR(old_file); ++ ++ new_file = ovl_path_open(new, O_WRONLY); ++ if (IS_ERR(new_file)) { ++ error = PTR_ERR(new_file); ++ goto out_fput; ++ } ++ ++ /* FIXME: copy up sparse files efficiently */ ++ while (len) { ++ loff_t offset = new_file->f_pos; ++ size_t this_len = OVL_COPY_UP_CHUNK_SIZE; ++ long bytes; ++ ++ if (len < this_len) ++ this_len = len; ++ ++ if (signal_pending_state(TASK_KILLABLE, current)) { ++ error = -EINTR; ++ break; ++ } ++ ++ bytes = do_splice_direct(old_file, &offset, new_file, this_len, ++ SPLICE_F_MOVE); ++ if (bytes <= 0) { ++ error = bytes; ++ break; ++ } ++ ++ len -= bytes; ++ } ++ ++ fput(new_file); ++out_fput: ++ fput(old_file); ++ return error; ++} ++ ++static char *ovl_read_symlink(struct dentry *realdentry) ++{ ++ int res; ++ char *buf; ++ struct inode *inode = realdentry->d_inode; ++ mm_segment_t old_fs; ++ ++ res = -EINVAL; ++ if (!inode->i_op->readlink) ++ goto err; ++ ++ res = -ENOMEM; ++ buf = (char *) __get_free_page(GFP_KERNEL); ++ if (!buf) ++ goto err; ++ ++ old_fs = get_fs(); ++ set_fs(get_ds()); ++ /* The cast to a user pointer is valid due to the set_fs() */ ++ res = inode->i_op->readlink(realdentry, ++ (char __user *)buf, PAGE_SIZE - 1); ++ set_fs(old_fs); ++ if (res < 0) { ++ free_page((unsigned long) buf); ++ goto err; ++ } ++ buf[res] = '\0'; ++ ++ return buf; ++ ++err: ++ return ERR_PTR(res); ++} ++ ++static int ovl_set_timestamps(struct dentry *upperdentry, struct kstat *stat) ++{ ++ struct iattr attr = { ++ .ia_valid = ++ ATTR_ATIME | ATTR_MTIME | ATTR_ATIME_SET | ATTR_MTIME_SET, ++ .ia_atime = stat->atime, ++ .ia_mtime = stat->mtime, ++ }; ++ ++ return notify_change(upperdentry, &attr); ++} ++ ++static int ovl_set_mode(struct dentry *upperdentry, umode_t mode) ++{ ++ struct iattr attr = { ++ .ia_valid = ATTR_MODE, ++ .ia_mode = mode, ++ }; ++ ++ return notify_change(upperdentry, &attr); ++} ++ ++static int ovl_copy_up_locked(struct dentry *upperdir, struct dentry *dentry, ++ struct path *lowerpath, struct kstat *stat, ++ const char *link) ++{ ++ int err; ++ struct path newpath; ++ umode_t mode = stat->mode; ++ ++ /* Can't properly set mode on creation because of the umask */ ++ stat->mode &= S_IFMT; ++ ++ ovl_path_upper(dentry, &newpath); ++ WARN_ON(newpath.dentry); ++ newpath.dentry = ovl_upper_create(upperdir, dentry, stat, link); ++ if (IS_ERR(newpath.dentry)) ++ return PTR_ERR(newpath.dentry); ++ ++ if (S_ISREG(stat->mode)) { ++ err = ovl_copy_up_data(lowerpath, &newpath, stat->size); ++ if (err) ++ goto err_remove; ++ } ++ ++ err = ovl_copy_up_xattr(lowerpath->dentry, newpath.dentry); ++ if (err) ++ goto err_remove; ++ ++ mutex_lock(&newpath.dentry->d_inode->i_mutex); ++ if (!S_ISLNK(stat->mode)) ++ err = ovl_set_mode(newpath.dentry, mode); ++ if (!err) ++ err = ovl_set_timestamps(newpath.dentry, stat); ++ mutex_unlock(&newpath.dentry->d_inode->i_mutex); ++ if (err) ++ goto err_remove; ++ ++ ovl_dentry_update(dentry, newpath.dentry); ++ ++ /* ++ * Easiest way to get rid of the lower dentry reference is to ++ * drop this dentry. This is neither needed nor possible for ++ * directories. ++ */ ++ if (!S_ISDIR(stat->mode)) ++ d_drop(dentry); ++ ++ return 0; ++ ++err_remove: ++ if (S_ISDIR(stat->mode)) ++ vfs_rmdir(upperdir->d_inode, newpath.dentry); ++ else ++ vfs_unlink(upperdir->d_inode, newpath.dentry); ++ ++ dput(newpath.dentry); ++ ++ return err; ++} ++ ++/* ++ * Copy up a single dentry ++ * ++ * Directory renames only allowed on "pure upper" (already created on ++ * upper filesystem, never copied up). Directories which are on lower or ++ * are merged may not be renamed. For these -EXDEV is returned and ++ * userspace has to deal with it. This means, when copying up a ++ * directory we can rely on it and ancestors being stable. ++ * ++ * Non-directory renames start with copy up of source if necessary. The ++ * actual rename will only proceed once the copy up was successful. Copy ++ * up uses upper parent i_mutex for exclusion. Since rename can change ++ * d_parent it is possible that the copy up will lock the old parent. At ++ * that point the file will have already been copied up anyway. ++ */ ++static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, ++ struct path *lowerpath, struct kstat *stat) ++{ ++ int err; ++ struct kstat pstat; ++ struct path parentpath; ++ struct dentry *upperdir; ++ const struct cred *old_cred; ++ struct cred *override_cred; ++ char *link = NULL; ++ ++ ovl_path_upper(parent, &parentpath); ++ upperdir = parentpath.dentry; ++ ++ err = vfs_getattr(parentpath.mnt, parentpath.dentry, &pstat); ++ if (err) ++ return err; ++ ++ if (S_ISLNK(stat->mode)) { ++ link = ovl_read_symlink(lowerpath->dentry); ++ if (IS_ERR(link)) ++ return PTR_ERR(link); ++ } ++ ++ err = -ENOMEM; ++ override_cred = prepare_creds(); ++ if (!override_cred) ++ goto out_free_link; ++ ++ override_cred->fsuid = stat->uid; ++ override_cred->fsgid = stat->gid; ++ /* ++ * CAP_SYS_ADMIN for copying up extended attributes ++ * CAP_DAC_OVERRIDE for create ++ * CAP_FOWNER for chmod, timestamp update ++ * CAP_FSETID for chmod ++ * CAP_MKNOD for mknod ++ */ ++ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); ++ cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); ++ cap_raise(override_cred->cap_effective, CAP_FOWNER); ++ cap_raise(override_cred->cap_effective, CAP_FSETID); ++ cap_raise(override_cred->cap_effective, CAP_MKNOD); ++ old_cred = override_creds(override_cred); ++ ++ mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); ++ if (ovl_path_type(dentry) != OVL_PATH_LOWER) { ++ err = 0; ++ } else { ++ err = ovl_copy_up_locked(upperdir, dentry, lowerpath, ++ stat, link); ++ if (!err) { ++ /* Restore timestamps on parent (best effort) */ ++ ovl_set_timestamps(upperdir, &pstat); ++ } ++ } ++ ++ mutex_unlock(&upperdir->d_inode->i_mutex); ++ ++ revert_creds(old_cred); ++ put_cred(override_cred); ++ ++out_free_link: ++ if (link) ++ free_page((unsigned long) link); ++ ++ return err; ++} ++ ++int ovl_copy_up(struct dentry *dentry) ++{ ++ int err; ++ ++ err = 0; ++ while (!err) { ++ struct dentry *next; ++ struct dentry *parent; ++ struct path lowerpath; ++ struct kstat stat; ++ enum ovl_path_type type = ovl_path_type(dentry); ++ ++ if (type != OVL_PATH_LOWER) ++ break; ++ ++ next = dget(dentry); ++ /* find the topmost dentry not yet copied up */ ++ for (;;) { ++ parent = dget_parent(next); ++ ++ type = ovl_path_type(parent); ++ if (type != OVL_PATH_LOWER) ++ break; ++ ++ dput(next); ++ next = parent; ++ } ++ ++ ovl_path_lower(next, &lowerpath); ++ err = vfs_getattr(lowerpath.mnt, lowerpath.dentry, &stat); ++ if (!err) ++ err = ovl_copy_up_one(parent, next, &lowerpath, &stat); ++ ++ dput(parent); ++ dput(next); ++ } ++ ++ return err; ++} ++ ++/* Optimize by not copying up the file first and truncating later */ ++int ovl_copy_up_truncate(struct dentry *dentry, loff_t size) ++{ ++ int err; ++ struct kstat stat; ++ struct path lowerpath; ++ struct dentry *parent = dget_parent(dentry); ++ ++ err = ovl_copy_up(parent); ++ if (err) ++ goto out_dput_parent; ++ ++ ovl_path_lower(dentry, &lowerpath); ++ err = vfs_getattr(lowerpath.mnt, lowerpath.dentry, &stat); ++ if (err) ++ goto out_dput_parent; ++ ++ if (size < stat.size) ++ stat.size = size; ++ ++ err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat); ++ ++out_dput_parent: ++ dput(parent); ++ return err; ++} +diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c +new file mode 100644 +index 0000000..c914c97 +--- /dev/null ++++ b/fs/overlayfs/dir.c +@@ -0,0 +1,602 @@ ++/* ++ * ++ * Copyright (C) 2011 Novell Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "overlayfs.h" ++ ++static const char *ovl_whiteout_symlink = "(overlay-whiteout)"; ++ ++static int ovl_whiteout(struct dentry *upperdir, struct dentry *dentry) ++{ ++ int err; ++ struct dentry *newdentry; ++ const struct cred *old_cred; ++ struct cred *override_cred; ++ ++ /* FIXME: recheck lower dentry to see if whiteout is really needed */ ++ ++ err = -ENOMEM; ++ override_cred = prepare_creds(); ++ if (!override_cred) ++ goto out; ++ ++ /* ++ * CAP_SYS_ADMIN for setxattr ++ * CAP_DAC_OVERRIDE for symlink creation ++ * CAP_FOWNER for unlink in sticky directory ++ */ ++ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); ++ cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); ++ cap_raise(override_cred->cap_effective, CAP_FOWNER); ++ override_cred->fsuid = 0; ++ override_cred->fsgid = 0; ++ old_cred = override_creds(override_cred); ++ ++ newdentry = lookup_one_len(dentry->d_name.name, upperdir, ++ dentry->d_name.len); ++ err = PTR_ERR(newdentry); ++ if (IS_ERR(newdentry)) ++ goto out_put_cred; ++ ++ /* Just been removed within the same locked region */ ++ WARN_ON(newdentry->d_inode); ++ ++ err = vfs_symlink(upperdir->d_inode, newdentry, ovl_whiteout_symlink); ++ if (err) ++ goto out_dput; ++ ++ ovl_dentry_version_inc(dentry->d_parent); ++ ++ err = vfs_setxattr(newdentry, ovl_whiteout_xattr, "y", 1, 0); ++ if (err) ++ vfs_unlink(upperdir->d_inode, newdentry); ++ ++out_dput: ++ dput(newdentry); ++out_put_cred: ++ revert_creds(old_cred); ++ put_cred(override_cred); ++out: ++ if (err) { ++ /* ++ * There's no way to recover from failure to whiteout. ++ * What should we do? Log a big fat error and... ? ++ */ ++ printk(KERN_ERR "overlayfs: ERROR - failed to whiteout '%s'\n", ++ dentry->d_name.name); ++ } ++ ++ return err; ++} ++ ++static struct dentry *ovl_lookup_create(struct dentry *upperdir, ++ struct dentry *template) ++{ ++ int err; ++ struct dentry *newdentry; ++ struct qstr *name = &template->d_name; ++ ++ newdentry = lookup_one_len(name->name, upperdir, name->len); ++ if (IS_ERR(newdentry)) ++ return newdentry; ++ ++ if (newdentry->d_inode) { ++ const struct cred *old_cred; ++ struct cred *override_cred; ++ ++ /* No need to check whiteout if lower parent is non-existent */ ++ err = -EEXIST; ++ if (!ovl_dentry_lower(template->d_parent)) ++ goto out_dput; ++ ++ if (!S_ISLNK(newdentry->d_inode->i_mode)) ++ goto out_dput; ++ ++ err = -ENOMEM; ++ override_cred = prepare_creds(); ++ if (!override_cred) ++ goto out_dput; ++ ++ /* ++ * CAP_SYS_ADMIN for getxattr ++ * CAP_FOWNER for unlink in sticky directory ++ */ ++ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); ++ cap_raise(override_cred->cap_effective, CAP_FOWNER); ++ old_cred = override_creds(override_cred); ++ ++ err = -EEXIST; ++ if (ovl_is_whiteout(newdentry)) ++ err = vfs_unlink(upperdir->d_inode, newdentry); ++ ++ revert_creds(old_cred); ++ put_cred(override_cred); ++ if (err) ++ goto out_dput; ++ ++ dput(newdentry); ++ newdentry = lookup_one_len(name->name, upperdir, name->len); ++ if (IS_ERR(newdentry)) { ++ ovl_whiteout(upperdir, template); ++ return newdentry; ++ } ++ ++ /* ++ * Whiteout just been successfully removed, parent ++ * i_mutex is still held, there's no way the lookup ++ * could return positive. ++ */ ++ WARN_ON(newdentry->d_inode); ++ } ++ ++ return newdentry; ++ ++out_dput: ++ dput(newdentry); ++ return ERR_PTR(err); ++} ++ ++struct dentry *ovl_upper_create(struct dentry *upperdir, struct dentry *dentry, ++ struct kstat *stat, const char *link) ++{ ++ int err; ++ struct dentry *newdentry; ++ struct inode *dir = upperdir->d_inode; ++ ++ newdentry = ovl_lookup_create(upperdir, dentry); ++ if (IS_ERR(newdentry)) ++ goto out; ++ ++ switch (stat->mode & S_IFMT) { ++ case S_IFREG: ++ err = vfs_create(dir, newdentry, stat->mode, NULL); ++ break; ++ ++ case S_IFDIR: ++ err = vfs_mkdir(dir, newdentry, stat->mode); ++ break; ++ ++ case S_IFCHR: ++ case S_IFBLK: ++ case S_IFIFO: ++ case S_IFSOCK: ++ err = vfs_mknod(dir, newdentry, stat->mode, stat->rdev); ++ break; ++ ++ case S_IFLNK: ++ err = vfs_symlink(dir, newdentry, link); ++ break; ++ ++ default: ++ err = -EPERM; ++ } ++ if (err) { ++ if (ovl_dentry_is_opaque(dentry)) ++ ovl_whiteout(upperdir, dentry); ++ dput(newdentry); ++ newdentry = ERR_PTR(err); ++ } else if (WARN_ON(!newdentry->d_inode)) { ++ /* ++ * Not quite sure if non-instantiated dentry is legal or not. ++ * VFS doesn't seem to care so check and warn here. ++ */ ++ dput(newdentry); ++ newdentry = ERR_PTR(-ENOENT); ++ } ++ ++out: ++ return newdentry; ++ ++} ++ ++static int ovl_set_opaque(struct dentry *upperdentry) ++{ ++ int err; ++ const struct cred *old_cred; ++ struct cred *override_cred; ++ ++ override_cred = prepare_creds(); ++ if (!override_cred) ++ return -ENOMEM; ++ ++ /* CAP_SYS_ADMIN for setxattr of "trusted" namespace */ ++ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); ++ old_cred = override_creds(override_cred); ++ err = vfs_setxattr(upperdentry, ovl_opaque_xattr, "y", 1, 0); ++ revert_creds(old_cred); ++ put_cred(override_cred); ++ ++ return err; ++} ++ ++static int ovl_remove_opaque(struct dentry *upperdentry) ++{ ++ int err; ++ const struct cred *old_cred; ++ struct cred *override_cred; ++ ++ override_cred = prepare_creds(); ++ if (!override_cred) ++ return -ENOMEM; ++ ++ /* CAP_SYS_ADMIN for removexattr of "trusted" namespace */ ++ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); ++ old_cred = override_creds(override_cred); ++ err = vfs_removexattr(upperdentry, ovl_opaque_xattr); ++ revert_creds(old_cred); ++ put_cred(override_cred); ++ ++ return err; ++} ++ ++static int ovl_dir_getattr(struct vfsmount *mnt, struct dentry *dentry, ++ struct kstat *stat) ++{ ++ int err; ++ enum ovl_path_type type; ++ struct path realpath; ++ ++ type = ovl_path_real(dentry, &realpath); ++ err = vfs_getattr(realpath.mnt, realpath.dentry, stat); ++ if (err) ++ return err; ++ ++ stat->dev = dentry->d_sb->s_dev; ++ stat->ino = dentry->d_inode->i_ino; ++ ++ /* ++ * It's probably not worth it to count subdirs to get the ++ * correct link count. nlink=1 seems to pacify 'find' and ++ * other utilities. ++ */ ++ if (type == OVL_PATH_MERGE) ++ stat->nlink = 1; ++ ++ return 0; ++} ++ ++static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev, ++ const char *link) ++{ ++ int err; ++ struct dentry *newdentry; ++ struct dentry *upperdir; ++ struct inode *inode; ++ struct kstat stat = { ++ .mode = mode, ++ .rdev = rdev, ++ }; ++ ++ err = -ENOMEM; ++ inode = ovl_new_inode(dentry->d_sb, mode, dentry->d_fsdata); ++ if (!inode) ++ goto out; ++ ++ err = ovl_copy_up(dentry->d_parent); ++ if (err) ++ goto out_iput; ++ ++ upperdir = ovl_dentry_upper(dentry->d_parent); ++ mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); ++ ++ newdentry = ovl_upper_create(upperdir, dentry, &stat, link); ++ err = PTR_ERR(newdentry); ++ if (IS_ERR(newdentry)) ++ goto out_unlock; ++ ++ ovl_dentry_version_inc(dentry->d_parent); ++ if (ovl_dentry_is_opaque(dentry) && S_ISDIR(mode)) { ++ err = ovl_set_opaque(newdentry); ++ if (err) { ++ vfs_rmdir(upperdir->d_inode, newdentry); ++ ovl_whiteout(upperdir, dentry); ++ goto out_dput; ++ } ++ } ++ ovl_dentry_update(dentry, newdentry); ++ d_instantiate(dentry, inode); ++ inode = NULL; ++ newdentry = NULL; ++ err = 0; ++ ++out_dput: ++ dput(newdentry); ++out_unlock: ++ mutex_unlock(&upperdir->d_inode->i_mutex); ++out_iput: ++ iput(inode); ++out: ++ return err; ++} ++ ++static int ovl_create(struct inode *dir, struct dentry *dentry, umode_t mode, ++ struct nameidata *nd) ++{ ++ return ovl_create_object(dentry, (mode & 07777) | S_IFREG, 0, NULL); ++} ++ ++static int ovl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ++{ ++ return ovl_create_object(dentry, (mode & 07777) | S_IFDIR, 0, NULL); ++} ++ ++static int ovl_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, ++ dev_t rdev) ++{ ++ return ovl_create_object(dentry, mode, rdev, NULL); ++} ++ ++static int ovl_symlink(struct inode *dir, struct dentry *dentry, ++ const char *link) ++{ ++ return ovl_create_object(dentry, S_IFLNK, 0, link); ++} ++ ++static int ovl_do_remove(struct dentry *dentry, bool is_dir) ++{ ++ int err; ++ enum ovl_path_type type; ++ struct path realpath; ++ struct dentry *upperdir; ++ ++ err = ovl_copy_up(dentry->d_parent); ++ if (err) ++ return err; ++ ++ upperdir = ovl_dentry_upper(dentry->d_parent); ++ mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); ++ type = ovl_path_real(dentry, &realpath); ++ if (type != OVL_PATH_LOWER) { ++ err = -ESTALE; ++ if (realpath.dentry->d_parent != upperdir) ++ goto out_d_drop; ++ ++ /* FIXME: create whiteout up front and rename to target */ ++ ++ if (is_dir) ++ err = vfs_rmdir(upperdir->d_inode, realpath.dentry); ++ else ++ err = vfs_unlink(upperdir->d_inode, realpath.dentry); ++ if (err) ++ goto out_d_drop; ++ ++ ovl_dentry_version_inc(dentry->d_parent); ++ } ++ ++ if (type != OVL_PATH_UPPER || ovl_dentry_is_opaque(dentry)) ++ err = ovl_whiteout(upperdir, dentry); ++ ++ /* ++ * Keeping this dentry hashed would mean having to release ++ * upperpath/lowerpath, which could only be done if we are the ++ * sole user of this dentry. Too tricky... Just unhash for ++ * now. ++ */ ++out_d_drop: ++ d_drop(dentry); ++ mutex_unlock(&upperdir->d_inode->i_mutex); ++ ++ return err; ++} ++ ++static int ovl_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ return ovl_do_remove(dentry, false); ++} ++ ++ ++static int ovl_rmdir(struct inode *dir, struct dentry *dentry) ++{ ++ int err; ++ enum ovl_path_type type; ++ ++ type = ovl_path_type(dentry); ++ if (type != OVL_PATH_UPPER) { ++ err = ovl_check_empty_and_clear(dentry, type); ++ if (err) ++ return err; ++ } ++ ++ return ovl_do_remove(dentry, true); ++} ++ ++static int ovl_link(struct dentry *old, struct inode *newdir, ++ struct dentry *new) ++{ ++ int err; ++ struct dentry *olddentry; ++ struct dentry *newdentry; ++ struct dentry *upperdir; ++ struct inode *newinode; ++ ++ err = ovl_copy_up(old); ++ if (err) ++ goto out; ++ ++ err = ovl_copy_up(new->d_parent); ++ if (err) ++ goto out; ++ ++ upperdir = ovl_dentry_upper(new->d_parent); ++ mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); ++ newdentry = ovl_lookup_create(upperdir, new); ++ err = PTR_ERR(newdentry); ++ if (IS_ERR(newdentry)) ++ goto out_unlock; ++ ++ olddentry = ovl_dentry_upper(old); ++ err = vfs_link(olddentry, upperdir->d_inode, newdentry); ++ if (!err) { ++ if (WARN_ON(!newdentry->d_inode)) { ++ dput(newdentry); ++ err = -ENOENT; ++ goto out_unlock; ++ } ++ newinode = ovl_new_inode(old->d_sb, newdentry->d_inode->i_mode, ++ new->d_fsdata); ++ if (!newinode) ++ goto link_fail; ++ ++ ovl_dentry_version_inc(new->d_parent); ++ ovl_dentry_update(new, newdentry); ++ ++ d_instantiate(new, newinode); ++ } else { ++link_fail: ++ if (ovl_dentry_is_opaque(new)) ++ ovl_whiteout(upperdir, new); ++ dput(newdentry); ++ } ++out_unlock: ++ mutex_unlock(&upperdir->d_inode->i_mutex); ++out: ++ return err; ++ ++} ++ ++static int ovl_rename(struct inode *olddir, struct dentry *old, ++ struct inode *newdir, struct dentry *new) ++{ ++ int err; ++ enum ovl_path_type old_type; ++ enum ovl_path_type new_type; ++ struct dentry *old_upperdir; ++ struct dentry *new_upperdir; ++ struct dentry *olddentry; ++ struct dentry *newdentry; ++ struct dentry *trap; ++ bool old_opaque; ++ bool new_opaque; ++ bool new_create = false; ++ bool is_dir = S_ISDIR(old->d_inode->i_mode); ++ ++ /* Don't copy up directory trees */ ++ old_type = ovl_path_type(old); ++ if (old_type != OVL_PATH_UPPER && is_dir) ++ return -EXDEV; ++ ++ if (new->d_inode) { ++ new_type = ovl_path_type(new); ++ ++ if (new_type == OVL_PATH_LOWER && old_type == OVL_PATH_LOWER) { ++ if (ovl_dentry_lower(old)->d_inode == ++ ovl_dentry_lower(new)->d_inode) ++ return 0; ++ } ++ if (new_type != OVL_PATH_LOWER && old_type != OVL_PATH_LOWER) { ++ if (ovl_dentry_upper(old)->d_inode == ++ ovl_dentry_upper(new)->d_inode) ++ return 0; ++ } ++ ++ if (new_type != OVL_PATH_UPPER && ++ S_ISDIR(new->d_inode->i_mode)) { ++ err = ovl_check_empty_and_clear(new, new_type); ++ if (err) ++ return err; ++ } ++ } else { ++ new_type = OVL_PATH_UPPER; ++ } ++ ++ err = ovl_copy_up(old); ++ if (err) ++ return err; ++ ++ err = ovl_copy_up(new->d_parent); ++ if (err) ++ return err; ++ ++ old_upperdir = ovl_dentry_upper(old->d_parent); ++ new_upperdir = ovl_dentry_upper(new->d_parent); ++ ++ trap = lock_rename(new_upperdir, old_upperdir); ++ ++ olddentry = ovl_dentry_upper(old); ++ newdentry = ovl_dentry_upper(new); ++ if (newdentry) { ++ dget(newdentry); ++ } else { ++ new_create = true; ++ newdentry = ovl_lookup_create(new_upperdir, new); ++ err = PTR_ERR(newdentry); ++ if (IS_ERR(newdentry)) ++ goto out_unlock; ++ } ++ ++ err = -ESTALE; ++ if (olddentry->d_parent != old_upperdir) ++ goto out_dput; ++ if (newdentry->d_parent != new_upperdir) ++ goto out_dput; ++ if (olddentry == trap) ++ goto out_dput; ++ if (newdentry == trap) ++ goto out_dput; ++ ++ old_opaque = ovl_dentry_is_opaque(old); ++ new_opaque = ovl_dentry_is_opaque(new) || new_type != OVL_PATH_UPPER; ++ ++ if (is_dir && !old_opaque && new_opaque) { ++ err = ovl_set_opaque(olddentry); ++ if (err) ++ goto out_dput; ++ } ++ ++ err = vfs_rename(old_upperdir->d_inode, olddentry, ++ new_upperdir->d_inode, newdentry); ++ ++ if (err) { ++ if (new_create && ovl_dentry_is_opaque(new)) ++ ovl_whiteout(new_upperdir, new); ++ if (is_dir && !old_opaque && new_opaque) ++ ovl_remove_opaque(olddentry); ++ goto out_dput; ++ } ++ ++ if (old_type != OVL_PATH_UPPER || old_opaque) ++ err = ovl_whiteout(old_upperdir, old); ++ if (is_dir && old_opaque && !new_opaque) ++ ovl_remove_opaque(olddentry); ++ ++ if (old_opaque != new_opaque) ++ ovl_dentry_set_opaque(old, new_opaque); ++ ++ ovl_dentry_version_inc(old->d_parent); ++ ovl_dentry_version_inc(new->d_parent); ++ ++out_dput: ++ dput(newdentry); ++out_unlock: ++ unlock_rename(new_upperdir, old_upperdir); ++ return err; ++} ++ ++const struct inode_operations ovl_dir_inode_operations = { ++ .lookup = ovl_lookup, ++ .mkdir = ovl_mkdir, ++ .symlink = ovl_symlink, ++ .unlink = ovl_unlink, ++ .rmdir = ovl_rmdir, ++ .rename = ovl_rename, ++ .link = ovl_link, ++ .setattr = ovl_setattr, ++ .create = ovl_create, ++ .mknod = ovl_mknod, ++ .permission = ovl_permission, ++ .getattr = ovl_dir_getattr, ++ .setxattr = ovl_setxattr, ++ .getxattr = ovl_getxattr, ++ .listxattr = ovl_listxattr, ++ .removexattr = ovl_removexattr, ++}; +diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c +new file mode 100644 +index 0000000..1a8e232 +--- /dev/null ++++ b/fs/overlayfs/inode.c +@@ -0,0 +1,375 @@ ++/* ++ * ++ * Copyright (C) 2011 Novell Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include "overlayfs.h" ++ ++int ovl_setattr(struct dentry *dentry, struct iattr *attr) ++{ ++ struct dentry *upperdentry; ++ int err; ++ ++ if ((attr->ia_valid & ATTR_SIZE) && !ovl_dentry_upper(dentry)) ++ err = ovl_copy_up_truncate(dentry, attr->ia_size); ++ else ++ err = ovl_copy_up(dentry); ++ if (err) ++ return err; ++ ++ upperdentry = ovl_dentry_upper(dentry); ++ ++ if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) ++ attr->ia_valid &= ~ATTR_MODE; ++ ++ mutex_lock(&upperdentry->d_inode->i_mutex); ++ err = notify_change(upperdentry, attr); ++ mutex_unlock(&upperdentry->d_inode->i_mutex); ++ ++ return err; ++} ++ ++static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry, ++ struct kstat *stat) ++{ ++ struct path realpath; ++ ++ ovl_path_real(dentry, &realpath); ++ return vfs_getattr(realpath.mnt, realpath.dentry, stat); ++} ++ ++int ovl_permission(struct inode *inode, int mask) ++{ ++ struct ovl_entry *oe; ++ struct dentry *alias = NULL; ++ struct inode *realinode; ++ struct dentry *realdentry; ++ bool is_upper; ++ int err; ++ ++ if (S_ISDIR(inode->i_mode)) { ++ oe = inode->i_private; ++ } else if (mask & MAY_NOT_BLOCK) { ++ return -ECHILD; ++ } else { ++ /* ++ * For non-directories find an alias and get the info ++ * from there. ++ */ ++ spin_lock(&inode->i_lock); ++ if (WARN_ON(list_empty(&inode->i_dentry))) { ++ spin_unlock(&inode->i_lock); ++ return -ENOENT; ++ } ++ alias = list_entry(inode->i_dentry.next, ++ struct dentry, d_alias); ++ dget(alias); ++ spin_unlock(&inode->i_lock); ++ oe = alias->d_fsdata; ++ } ++ ++ realdentry = ovl_entry_real(oe, &is_upper); ++ ++ /* Careful in RCU walk mode */ ++ realinode = ACCESS_ONCE(realdentry->d_inode); ++ if (!realinode) { ++ WARN_ON(!(mask & MAY_NOT_BLOCK)); ++ err = -ENOENT; ++ goto out_dput; ++ } ++ ++ if (mask & MAY_WRITE) { ++ umode_t mode = realinode->i_mode; ++ ++ /* ++ * Writes will always be redirected to upper layer, so ++ * ignore lower layer being read-only. ++ * ++ * If the overlay itself is read-only then proceed ++ * with the permission check, don't return EROFS. ++ * This will only happen if this is the lower layer of ++ * another overlayfs. ++ * ++ * If upper fs becomes read-only after the overlay was ++ * constructed return EROFS to prevent modification of ++ * upper layer. ++ */ ++ err = -EROFS; ++ if (is_upper && !IS_RDONLY(inode) && IS_RDONLY(realinode) && ++ (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) ++ goto out_dput; ++ } ++ ++ err = inode_only_permission(realinode, mask); ++out_dput: ++ dput(alias); ++ return err; ++} ++ ++ ++struct ovl_link_data { ++ struct dentry *realdentry; ++ void *cookie; ++}; ++ ++static void *ovl_follow_link(struct dentry *dentry, struct nameidata *nd) ++{ ++ void *ret; ++ struct dentry *realdentry; ++ struct inode *realinode; ++ ++ realdentry = ovl_dentry_real(dentry); ++ realinode = realdentry->d_inode; ++ ++ if (WARN_ON(!realinode->i_op->follow_link)) ++ return ERR_PTR(-EPERM); ++ ++ ret = realinode->i_op->follow_link(realdentry, nd); ++ if (IS_ERR(ret)) ++ return ret; ++ ++ if (realinode->i_op->put_link) { ++ struct ovl_link_data *data; ++ ++ data = kmalloc(sizeof(struct ovl_link_data), GFP_KERNEL); ++ if (!data) { ++ realinode->i_op->put_link(realdentry, nd, ret); ++ return ERR_PTR(-ENOMEM); ++ } ++ data->realdentry = realdentry; ++ data->cookie = ret; ++ ++ return data; ++ } else { ++ return NULL; ++ } ++} ++ ++static void ovl_put_link(struct dentry *dentry, struct nameidata *nd, void *c) ++{ ++ struct inode *realinode; ++ struct ovl_link_data *data = c; ++ ++ if (!data) ++ return; ++ ++ realinode = data->realdentry->d_inode; ++ realinode->i_op->put_link(data->realdentry, nd, data->cookie); ++ kfree(data); ++} ++ ++static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz) ++{ ++ struct path realpath; ++ struct inode *realinode; ++ ++ ovl_path_real(dentry, &realpath); ++ realinode = realpath.dentry->d_inode; ++ ++ if (!realinode->i_op->readlink) ++ return -EINVAL; ++ ++ touch_atime(&realpath); ++ ++ return realinode->i_op->readlink(realpath.dentry, buf, bufsiz); ++} ++ ++ ++static bool ovl_is_private_xattr(const char *name) ++{ ++ return strncmp(name, "trusted.overlay.", 14) == 0; ++} ++ ++int ovl_setxattr(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ int err; ++ struct dentry *upperdentry; ++ ++ if (ovl_is_private_xattr(name)) ++ return -EPERM; ++ ++ err = ovl_copy_up(dentry); ++ if (err) ++ return err; ++ ++ upperdentry = ovl_dentry_upper(dentry); ++ return vfs_setxattr(upperdentry, name, value, size, flags); ++} ++ ++ssize_t ovl_getxattr(struct dentry *dentry, const char *name, ++ void *value, size_t size) ++{ ++ if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE && ++ ovl_is_private_xattr(name)) ++ return -ENODATA; ++ ++ return vfs_getxattr(ovl_dentry_real(dentry), name, value, size); ++} ++ ++ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) ++{ ++ ssize_t res; ++ int off; ++ ++ res = vfs_listxattr(ovl_dentry_real(dentry), list, size); ++ if (res <= 0 || size == 0) ++ return res; ++ ++ if (ovl_path_type(dentry->d_parent) != OVL_PATH_MERGE) ++ return res; ++ ++ /* filter out private xattrs */ ++ for (off = 0; off < res;) { ++ char *s = list + off; ++ size_t slen = strlen(s) + 1; ++ ++ BUG_ON(off + slen > res); ++ ++ if (ovl_is_private_xattr(s)) { ++ res -= slen; ++ memmove(s, s + slen, res - off); ++ } else { ++ off += slen; ++ } ++ } ++ ++ return res; ++} ++ ++int ovl_removexattr(struct dentry *dentry, const char *name) ++{ ++ int err; ++ struct path realpath; ++ enum ovl_path_type type; ++ ++ if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE && ++ ovl_is_private_xattr(name)) ++ return -ENODATA; ++ ++ type = ovl_path_real(dentry, &realpath); ++ if (type == OVL_PATH_LOWER) { ++ err = vfs_getxattr(realpath.dentry, name, NULL, 0); ++ if (err < 0) ++ return err; ++ ++ err = ovl_copy_up(dentry); ++ if (err) ++ return err; ++ ++ ovl_path_upper(dentry, &realpath); ++ } ++ ++ return vfs_removexattr(realpath.dentry, name); ++} ++ ++static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type, ++ struct dentry *realdentry) ++{ ++ if (type != OVL_PATH_LOWER) ++ return false; ++ ++ if (special_file(realdentry->d_inode->i_mode)) ++ return false; ++ ++ if (!(OPEN_FMODE(flags) & FMODE_WRITE) && !(flags & O_TRUNC)) ++ return false; ++ ++ return true; ++} ++ ++static struct file *ovl_open(struct dentry *dentry, struct file *file, ++ const struct cred *cred) ++{ ++ int err; ++ struct path realpath; ++ enum ovl_path_type type; ++ ++ type = ovl_path_real(dentry, &realpath); ++ if (ovl_open_need_copy_up(file->f_flags, type, realpath.dentry)) { ++ if (file->f_flags & O_TRUNC) ++ err = ovl_copy_up_truncate(dentry, 0); ++ else ++ err = ovl_copy_up(dentry); ++ if (err) ++ return ERR_PTR(err); ++ ++ ovl_path_upper(dentry, &realpath); ++ } ++ ++ return vfs_open(&realpath, file, cred); ++} ++ ++static const struct inode_operations ovl_file_inode_operations = { ++ .setattr = ovl_setattr, ++ .permission = ovl_permission, ++ .getattr = ovl_getattr, ++ .setxattr = ovl_setxattr, ++ .getxattr = ovl_getxattr, ++ .listxattr = ovl_listxattr, ++ .removexattr = ovl_removexattr, ++ .open = ovl_open, ++}; ++ ++static const struct inode_operations ovl_symlink_inode_operations = { ++ .setattr = ovl_setattr, ++ .follow_link = ovl_follow_link, ++ .put_link = ovl_put_link, ++ .readlink = ovl_readlink, ++ .getattr = ovl_getattr, ++ .setxattr = ovl_setxattr, ++ .getxattr = ovl_getxattr, ++ .listxattr = ovl_listxattr, ++ .removexattr = ovl_removexattr, ++}; ++ ++struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, ++ struct ovl_entry *oe) ++{ ++ struct inode *inode; ++ ++ inode = new_inode(sb); ++ if (!inode) ++ return NULL; ++ ++ mode &= S_IFMT; ++ ++ inode->i_ino = get_next_ino(); ++ inode->i_mode = mode; ++ inode->i_flags |= S_NOATIME | S_NOCMTIME; ++ ++ switch (mode) { ++ case S_IFDIR: ++ inode->i_private = oe; ++ inode->i_op = &ovl_dir_inode_operations; ++ inode->i_fop = &ovl_dir_operations; ++ break; ++ ++ case S_IFLNK: ++ inode->i_op = &ovl_symlink_inode_operations; ++ break; ++ ++ case S_IFREG: ++ case S_IFSOCK: ++ case S_IFBLK: ++ case S_IFCHR: ++ case S_IFIFO: ++ inode->i_op = &ovl_file_inode_operations; ++ break; ++ ++ default: ++ WARN(1, "illegal file type: %i\n", mode); ++ iput(inode); ++ inode = NULL; ++ } ++ ++ return inode; ++ ++} +diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h +new file mode 100644 +index 0000000..1dd05f7 +--- /dev/null ++++ b/fs/overlayfs/overlayfs.h +@@ -0,0 +1,64 @@ ++/* ++ * ++ * Copyright (C) 2011 Novell Inc. ++ * ++ * 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. ++ */ ++ ++struct ovl_entry; ++ ++enum ovl_path_type { ++ OVL_PATH_UPPER, ++ OVL_PATH_MERGE, ++ OVL_PATH_LOWER, ++}; ++ ++extern const char *ovl_opaque_xattr; ++extern const char *ovl_whiteout_xattr; ++extern const struct dentry_operations ovl_dentry_operations; ++ ++enum ovl_path_type ovl_path_type(struct dentry *dentry); ++u64 ovl_dentry_version_get(struct dentry *dentry); ++void ovl_dentry_version_inc(struct dentry *dentry); ++void ovl_path_upper(struct dentry *dentry, struct path *path); ++void ovl_path_lower(struct dentry *dentry, struct path *path); ++enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path); ++struct dentry *ovl_dentry_upper(struct dentry *dentry); ++struct dentry *ovl_dentry_lower(struct dentry *dentry); ++struct dentry *ovl_dentry_real(struct dentry *dentry); ++struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper); ++bool ovl_dentry_is_opaque(struct dentry *dentry); ++void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque); ++bool ovl_is_whiteout(struct dentry *dentry); ++void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry); ++struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ++ struct nameidata *nd); ++struct file *ovl_path_open(struct path *path, int flags); ++ ++struct dentry *ovl_upper_create(struct dentry *upperdir, struct dentry *dentry, ++ struct kstat *stat, const char *link); ++ ++/* readdir.c */ ++extern const struct file_operations ovl_dir_operations; ++int ovl_check_empty_and_clear(struct dentry *dentry, enum ovl_path_type type); ++ ++/* inode.c */ ++int ovl_setattr(struct dentry *dentry, struct iattr *attr); ++int ovl_permission(struct inode *inode, int mask); ++int ovl_setxattr(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags); ++ssize_t ovl_getxattr(struct dentry *dentry, const char *name, ++ void *value, size_t size); ++ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size); ++int ovl_removexattr(struct dentry *dentry, const char *name); ++ ++struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, ++ struct ovl_entry *oe); ++/* dir.c */ ++extern const struct inode_operations ovl_dir_inode_operations; ++ ++/* copy_up.c */ ++int ovl_copy_up(struct dentry *dentry); ++int ovl_copy_up_truncate(struct dentry *dentry, loff_t size); +diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c +new file mode 100644 +index 0000000..0797efb +--- /dev/null ++++ b/fs/overlayfs/readdir.c +@@ -0,0 +1,566 @@ ++/* ++ * ++ * Copyright (C) 2011 Novell Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "overlayfs.h" ++ ++struct ovl_cache_entry { ++ const char *name; ++ unsigned int len; ++ unsigned int type; ++ u64 ino; ++ bool is_whiteout; ++ struct list_head l_node; ++ struct rb_node node; ++}; ++ ++struct ovl_readdir_data { ++ struct rb_root *root; ++ struct list_head *list; ++ struct list_head *middle; ++ struct dentry *dir; ++ int count; ++ int err; ++}; ++ ++struct ovl_dir_file { ++ bool is_real; ++ bool is_cached; ++ struct list_head cursor; ++ u64 cache_version; ++ struct list_head cache; ++ struct file *realfile; ++}; ++ ++static struct ovl_cache_entry *ovl_cache_entry_from_node(struct rb_node *n) ++{ ++ return container_of(n, struct ovl_cache_entry, node); ++} ++ ++static struct ovl_cache_entry *ovl_cache_entry_find(struct rb_root *root, ++ const char *name, int len) ++{ ++ struct rb_node *node = root->rb_node; ++ int cmp; ++ ++ while (node) { ++ struct ovl_cache_entry *p = ovl_cache_entry_from_node(node); ++ ++ cmp = strncmp(name, p->name, len); ++ if (cmp > 0) ++ node = p->node.rb_right; ++ else if (cmp < 0 || len < p->len) ++ node = p->node.rb_left; ++ else ++ return p; ++ } ++ ++ return NULL; ++} ++ ++static struct ovl_cache_entry *ovl_cache_entry_new(const char *name, int len, ++ u64 ino, unsigned int d_type) ++{ ++ struct ovl_cache_entry *p; ++ ++ p = kmalloc(sizeof(*p) + len + 1, GFP_KERNEL); ++ if (p) { ++ char *name_copy = (char *) (p + 1); ++ memcpy(name_copy, name, len); ++ name_copy[len] = '\0'; ++ p->name = name_copy; ++ p->len = len; ++ p->type = d_type; ++ p->ino = ino; ++ p->is_whiteout = false; ++ } ++ ++ return p; ++} ++ ++static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd, ++ const char *name, int len, u64 ino, ++ unsigned int d_type) ++{ ++ struct rb_node **newp = &rdd->root->rb_node; ++ struct rb_node *parent = NULL; ++ struct ovl_cache_entry *p; ++ ++ while (*newp) { ++ int cmp; ++ struct ovl_cache_entry *tmp; ++ ++ parent = *newp; ++ tmp = ovl_cache_entry_from_node(*newp); ++ cmp = strncmp(name, tmp->name, len); ++ if (cmp > 0) ++ newp = &tmp->node.rb_right; ++ else if (cmp < 0 || len < tmp->len) ++ newp = &tmp->node.rb_left; ++ else ++ return 0; ++ } ++ ++ p = ovl_cache_entry_new(name, len, ino, d_type); ++ if (p == NULL) ++ return -ENOMEM; ++ ++ list_add_tail(&p->l_node, rdd->list); ++ rb_link_node(&p->node, parent, newp); ++ rb_insert_color(&p->node, rdd->root); ++ ++ return 0; ++} ++ ++static int ovl_fill_lower(void *buf, const char *name, int namelen, ++ loff_t offset, u64 ino, unsigned int d_type) ++{ ++ struct ovl_readdir_data *rdd = buf; ++ struct ovl_cache_entry *p; ++ ++ rdd->count++; ++ p = ovl_cache_entry_find(rdd->root, name, namelen); ++ if (p) { ++ list_move_tail(&p->l_node, rdd->middle); ++ } else { ++ p = ovl_cache_entry_new(name, namelen, ino, d_type); ++ if (p == NULL) ++ rdd->err = -ENOMEM; ++ else ++ list_add_tail(&p->l_node, rdd->middle); ++ } ++ ++ return rdd->err; ++} ++ ++static void ovl_cache_free(struct list_head *list) ++{ ++ struct ovl_cache_entry *p; ++ struct ovl_cache_entry *n; ++ ++ list_for_each_entry_safe(p, n, list, l_node) ++ kfree(p); ++ ++ INIT_LIST_HEAD(list); ++} ++ ++static int ovl_fill_upper(void *buf, const char *name, int namelen, ++ loff_t offset, u64 ino, unsigned int d_type) ++{ ++ struct ovl_readdir_data *rdd = buf; ++ ++ rdd->count++; ++ return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type); ++} ++ ++static inline int ovl_dir_read(struct path *realpath, ++ struct ovl_readdir_data *rdd, filldir_t filler) ++{ ++ struct file *realfile; ++ int err; ++ ++ realfile = ovl_path_open(realpath, O_RDONLY | O_DIRECTORY); ++ if (IS_ERR(realfile)) ++ return PTR_ERR(realfile); ++ ++ do { ++ rdd->count = 0; ++ rdd->err = 0; ++ err = vfs_readdir(realfile, filler, rdd); ++ if (err >= 0) ++ err = rdd->err; ++ } while (!err && rdd->count); ++ fput(realfile); ++ ++ return 0; ++} ++ ++static void ovl_dir_reset(struct file *file) ++{ ++ struct ovl_dir_file *od = file->private_data; ++ enum ovl_path_type type = ovl_path_type(file->f_path.dentry); ++ ++ if (ovl_dentry_version_get(file->f_path.dentry) != od->cache_version) { ++ list_del_init(&od->cursor); ++ ovl_cache_free(&od->cache); ++ od->is_cached = false; ++ } ++ WARN_ON(!od->is_real && type != OVL_PATH_MERGE); ++ if (od->is_real && type == OVL_PATH_MERGE) { ++ fput(od->realfile); ++ od->realfile = NULL; ++ od->is_real = false; ++ } ++} ++ ++static int ovl_dir_mark_whiteouts(struct ovl_readdir_data *rdd) ++{ ++ struct ovl_cache_entry *p; ++ struct dentry *dentry; ++ const struct cred *old_cred; ++ struct cred *override_cred; ++ ++ override_cred = prepare_creds(); ++ if (!override_cred) { ++ ovl_cache_free(rdd->list); ++ return -ENOMEM; ++ } ++ ++ /* ++ * CAP_SYS_ADMIN for getxattr ++ * CAP_DAC_OVERRIDE for lookup ++ */ ++ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); ++ cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); ++ old_cred = override_creds(override_cred); ++ ++ mutex_lock(&rdd->dir->d_inode->i_mutex); ++ list_for_each_entry(p, rdd->list, l_node) { ++ if (p->type != DT_LNK) ++ continue; ++ ++ dentry = lookup_one_len(p->name, rdd->dir, p->len); ++ if (IS_ERR(dentry)) ++ continue; ++ ++ p->is_whiteout = ovl_is_whiteout(dentry); ++ dput(dentry); ++ } ++ mutex_unlock(&rdd->dir->d_inode->i_mutex); ++ ++ revert_creds(old_cred); ++ put_cred(override_cred); ++ ++ return 0; ++} ++ ++static inline int ovl_dir_read_merged(struct path *upperpath, ++ struct path *lowerpath, ++ struct ovl_readdir_data *rdd) ++{ ++ int err; ++ struct rb_root root = RB_ROOT; ++ struct list_head middle; ++ ++ rdd->root = &root; ++ if (upperpath->dentry) { ++ rdd->dir = upperpath->dentry; ++ err = ovl_dir_read(upperpath, rdd, ovl_fill_upper); ++ if (err) ++ goto out; ++ ++ err = ovl_dir_mark_whiteouts(rdd); ++ if (err) ++ goto out; ++ } ++ /* ++ * Insert lowerpath entries before upperpath ones, this allows ++ * offsets to be reasonably constant ++ */ ++ list_add(&middle, rdd->list); ++ rdd->middle = &middle; ++ err = ovl_dir_read(lowerpath, rdd, ovl_fill_lower); ++ list_del(&middle); ++out: ++ rdd->root = NULL; ++ ++ return err; ++} ++ ++static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) ++{ ++ struct list_head *l; ++ loff_t off; ++ ++ l = od->cache.next; ++ for (off = 0; off < pos; off++) { ++ if (l == &od->cache) ++ break; ++ l = l->next; ++ } ++ list_move_tail(&od->cursor, l); ++} ++ ++static int ovl_readdir(struct file *file, void *buf, filldir_t filler) ++{ ++ struct ovl_dir_file *od = file->private_data; ++ int res; ++ ++ if (!file->f_pos) ++ ovl_dir_reset(file); ++ ++ if (od->is_real) { ++ res = vfs_readdir(od->realfile, filler, buf); ++ file->f_pos = od->realfile->f_pos; ++ ++ return res; ++ } ++ ++ if (!od->is_cached) { ++ struct path lowerpath; ++ struct path upperpath; ++ struct ovl_readdir_data rdd = { .list = &od->cache }; ++ ++ ovl_path_lower(file->f_path.dentry, &lowerpath); ++ ovl_path_upper(file->f_path.dentry, &upperpath); ++ ++ res = ovl_dir_read_merged(&upperpath, &lowerpath, &rdd); ++ if (res) { ++ ovl_cache_free(rdd.list); ++ return res; ++ } ++ ++ od->cache_version = ovl_dentry_version_get(file->f_path.dentry); ++ od->is_cached = true; ++ ++ ovl_seek_cursor(od, file->f_pos); ++ } ++ ++ while (od->cursor.next != &od->cache) { ++ int over; ++ loff_t off; ++ struct ovl_cache_entry *p; ++ ++ p = list_entry(od->cursor.next, struct ovl_cache_entry, l_node); ++ off = file->f_pos; ++ if (!p->is_whiteout) { ++ over = filler(buf, p->name, p->len, off, p->ino, ++ p->type); ++ if (over) ++ break; ++ } ++ file->f_pos++; ++ list_move(&od->cursor, &p->l_node); ++ } ++ ++ return 0; ++} ++ ++static loff_t ovl_dir_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t res; ++ struct ovl_dir_file *od = file->private_data; ++ ++ mutex_lock(&file->f_dentry->d_inode->i_mutex); ++ if (!file->f_pos) ++ ovl_dir_reset(file); ++ ++ if (od->is_real) { ++ res = vfs_llseek(od->realfile, offset, origin); ++ file->f_pos = od->realfile->f_pos; ++ } else { ++ res = -EINVAL; ++ ++ switch (origin) { ++ case SEEK_CUR: ++ offset += file->f_pos; ++ break; ++ case SEEK_SET: ++ break; ++ default: ++ goto out_unlock; ++ } ++ if (offset < 0) ++ goto out_unlock; ++ ++ if (offset != file->f_pos) { ++ file->f_pos = offset; ++ if (od->is_cached) ++ ovl_seek_cursor(od, offset); ++ } ++ res = offset; ++ } ++out_unlock: ++ mutex_unlock(&file->f_dentry->d_inode->i_mutex); ++ ++ return res; ++} ++ ++static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end, ++ int datasync) ++{ ++ struct ovl_dir_file *od = file->private_data; ++ ++ /* May need to reopen directory if it got copied up */ ++ if (!od->realfile) { ++ struct path upperpath; ++ ++ ovl_path_upper(file->f_path.dentry, &upperpath); ++ od->realfile = ovl_path_open(&upperpath, O_RDONLY); ++ if (IS_ERR(od->realfile)) ++ return PTR_ERR(od->realfile); ++ } ++ ++ return vfs_fsync_range(od->realfile, start, end, datasync); ++} ++ ++static int ovl_dir_release(struct inode *inode, struct file *file) ++{ ++ struct ovl_dir_file *od = file->private_data; ++ ++ list_del(&od->cursor); ++ ovl_cache_free(&od->cache); ++ if (od->realfile) ++ fput(od->realfile); ++ kfree(od); ++ ++ return 0; ++} ++ ++static int ovl_dir_open(struct inode *inode, struct file *file) ++{ ++ struct path realpath; ++ struct file *realfile; ++ struct ovl_dir_file *od; ++ enum ovl_path_type type; ++ ++ od = kzalloc(sizeof(struct ovl_dir_file), GFP_KERNEL); ++ if (!od) ++ return -ENOMEM; ++ ++ type = ovl_path_real(file->f_path.dentry, &realpath); ++ realfile = ovl_path_open(&realpath, file->f_flags); ++ if (IS_ERR(realfile)) { ++ kfree(od); ++ return PTR_ERR(realfile); ++ } ++ INIT_LIST_HEAD(&od->cache); ++ INIT_LIST_HEAD(&od->cursor); ++ od->is_cached = false; ++ od->realfile = realfile; ++ od->is_real = (type != OVL_PATH_MERGE); ++ file->private_data = od; ++ ++ return 0; ++} ++ ++const struct file_operations ovl_dir_operations = { ++ .read = generic_read_dir, ++ .open = ovl_dir_open, ++ .readdir = ovl_readdir, ++ .llseek = ovl_dir_llseek, ++ .fsync = ovl_dir_fsync, ++ .release = ovl_dir_release, ++}; ++ ++static int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list) ++{ ++ int err; ++ struct path lowerpath; ++ struct path upperpath; ++ struct ovl_cache_entry *p; ++ struct ovl_readdir_data rdd = { .list = list }; ++ ++ ovl_path_upper(dentry, &upperpath); ++ ovl_path_lower(dentry, &lowerpath); ++ ++ err = ovl_dir_read_merged(&upperpath, &lowerpath, &rdd); ++ if (err) ++ return err; ++ ++ err = 0; ++ ++ list_for_each_entry(p, list, l_node) { ++ if (p->is_whiteout) ++ continue; ++ ++ if (p->name[0] == '.') { ++ if (p->len == 1) ++ continue; ++ if (p->len == 2 && p->name[1] == '.') ++ continue; ++ } ++ err = -ENOTEMPTY; ++ break; ++ } ++ ++ return err; ++} ++ ++static int ovl_remove_whiteouts(struct dentry *dir, struct list_head *list) ++{ ++ struct path upperpath; ++ struct dentry *upperdir; ++ struct ovl_cache_entry *p; ++ const struct cred *old_cred; ++ struct cred *override_cred; ++ int err; ++ ++ ovl_path_upper(dir, &upperpath); ++ upperdir = upperpath.dentry; ++ ++ override_cred = prepare_creds(); ++ if (!override_cred) ++ return -ENOMEM; ++ ++ /* ++ * CAP_DAC_OVERRIDE for lookup and unlink ++ * CAP_SYS_ADMIN for setxattr of "trusted" namespace ++ * CAP_FOWNER for unlink in sticky directory ++ */ ++ cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); ++ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); ++ cap_raise(override_cred->cap_effective, CAP_FOWNER); ++ old_cred = override_creds(override_cred); ++ ++ err = vfs_setxattr(upperdir, ovl_opaque_xattr, "y", 1, 0); ++ if (err) ++ goto out_revert_creds; ++ ++ mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); ++ list_for_each_entry(p, list, l_node) { ++ struct dentry *dentry; ++ int ret; ++ ++ if (!p->is_whiteout) ++ continue; ++ ++ dentry = lookup_one_len(p->name, upperdir, p->len); ++ if (IS_ERR(dentry)) { ++ printk(KERN_WARNING ++ "overlayfs: failed to lookup whiteout %.*s: %li\n", ++ p->len, p->name, PTR_ERR(dentry)); ++ continue; ++ } ++ ret = vfs_unlink(upperdir->d_inode, dentry); ++ dput(dentry); ++ if (ret) ++ printk(KERN_WARNING ++ "overlayfs: failed to unlink whiteout %.*s: %i\n", ++ p->len, p->name, ret); ++ } ++ mutex_unlock(&upperdir->d_inode->i_mutex); ++ ++out_revert_creds: ++ revert_creds(old_cred); ++ put_cred(override_cred); ++ ++ return err; ++} ++ ++int ovl_check_empty_and_clear(struct dentry *dentry, enum ovl_path_type type) ++{ ++ int err; ++ LIST_HEAD(list); ++ ++ err = ovl_check_empty_dir(dentry, &list); ++ if (!err && type == OVL_PATH_MERGE) ++ err = ovl_remove_whiteouts(dentry, &list); ++ ++ ovl_cache_free(&list); ++ ++ return err; ++} +diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c +new file mode 100644 +index 0000000..1d2d1e2 +--- /dev/null ++++ b/fs/overlayfs/super.c +@@ -0,0 +1,664 @@ ++/* ++ * ++ * Copyright (C) 2011 Novell Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "overlayfs.h" ++ ++MODULE_AUTHOR("Miklos Szeredi "); ++MODULE_DESCRIPTION("Overlay filesystem"); ++MODULE_LICENSE("GPL"); ++ ++struct ovl_config { ++ char *lowerdir; ++ char *upperdir; ++}; ++ ++/* private information held for overlayfs's superblock */ ++struct ovl_fs { ++ struct vfsmount *upper_mnt; ++ struct vfsmount *lower_mnt; ++ /* pathnames of lower and upper dirs, for show_options */ ++ struct ovl_config config; ++}; ++ ++/* private information held for every overlayfs dentry */ ++struct ovl_entry { ++ /* ++ * Keep "double reference" on upper dentries, so that ++ * d_delete() doesn't think it's OK to reset d_inode to NULL. ++ */ ++ struct dentry *__upperdentry; ++ struct dentry *lowerdentry; ++ union { ++ struct { ++ u64 version; ++ bool opaque; ++ }; ++ struct rcu_head rcu; ++ }; ++}; ++ ++const char *ovl_whiteout_xattr = "trusted.overlay.whiteout"; ++const char *ovl_opaque_xattr = "trusted.overlay.opaque"; ++ ++ ++enum ovl_path_type ovl_path_type(struct dentry *dentry) ++{ ++ struct ovl_entry *oe = dentry->d_fsdata; ++ ++ if (oe->__upperdentry) { ++ if (oe->lowerdentry && S_ISDIR(dentry->d_inode->i_mode)) ++ return OVL_PATH_MERGE; ++ else ++ return OVL_PATH_UPPER; ++ } else { ++ return OVL_PATH_LOWER; ++ } ++} ++ ++static struct dentry *ovl_upperdentry_dereference(struct ovl_entry *oe) ++{ ++ struct dentry *upperdentry = ACCESS_ONCE(oe->__upperdentry); ++ smp_read_barrier_depends(); ++ return upperdentry; ++} ++ ++void ovl_path_upper(struct dentry *dentry, struct path *path) ++{ ++ struct ovl_fs *ofs = dentry->d_sb->s_fs_info; ++ struct ovl_entry *oe = dentry->d_fsdata; ++ ++ path->mnt = ofs->upper_mnt; ++ path->dentry = ovl_upperdentry_dereference(oe); ++} ++ ++void ovl_path_lower(struct dentry *dentry, struct path *path) ++{ ++ struct ovl_fs *ofs = dentry->d_sb->s_fs_info; ++ struct ovl_entry *oe = dentry->d_fsdata; ++ ++ path->mnt = ofs->lower_mnt; ++ path->dentry = oe->lowerdentry; ++} ++ ++enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path) ++{ ++ ++ enum ovl_path_type type = ovl_path_type(dentry); ++ ++ if (type == OVL_PATH_LOWER) ++ ovl_path_lower(dentry, path); ++ else ++ ovl_path_upper(dentry, path); ++ ++ return type; ++} ++ ++struct dentry *ovl_dentry_upper(struct dentry *dentry) ++{ ++ struct ovl_entry *oe = dentry->d_fsdata; ++ ++ return ovl_upperdentry_dereference(oe); ++} ++ ++struct dentry *ovl_dentry_lower(struct dentry *dentry) ++{ ++ struct ovl_entry *oe = dentry->d_fsdata; ++ ++ return oe->lowerdentry; ++} ++ ++struct dentry *ovl_dentry_real(struct dentry *dentry) ++{ ++ struct ovl_entry *oe = dentry->d_fsdata; ++ struct dentry *realdentry; ++ ++ realdentry = ovl_upperdentry_dereference(oe); ++ if (!realdentry) ++ realdentry = oe->lowerdentry; ++ ++ return realdentry; ++} ++ ++struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper) ++{ ++ struct dentry *realdentry; ++ ++ realdentry = ovl_upperdentry_dereference(oe); ++ if (realdentry) { ++ *is_upper = true; ++ } else { ++ realdentry = oe->lowerdentry; ++ *is_upper = false; ++ } ++ return realdentry; ++} ++ ++bool ovl_dentry_is_opaque(struct dentry *dentry) ++{ ++ struct ovl_entry *oe = dentry->d_fsdata; ++ return oe->opaque; ++} ++ ++void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque) ++{ ++ struct ovl_entry *oe = dentry->d_fsdata; ++ oe->opaque = opaque; ++} ++ ++void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry) ++{ ++ struct ovl_entry *oe = dentry->d_fsdata; ++ ++ WARN_ON(!mutex_is_locked(&upperdentry->d_parent->d_inode->i_mutex)); ++ WARN_ON(oe->__upperdentry); ++ BUG_ON(!upperdentry->d_inode); ++ smp_wmb(); ++ oe->__upperdentry = dget(upperdentry); ++} ++ ++void ovl_dentry_version_inc(struct dentry *dentry) ++{ ++ struct ovl_entry *oe = dentry->d_fsdata; ++ ++ WARN_ON(!mutex_is_locked(&dentry->d_inode->i_mutex)); ++ oe->version++; ++} ++ ++u64 ovl_dentry_version_get(struct dentry *dentry) ++{ ++ struct ovl_entry *oe = dentry->d_fsdata; ++ ++ WARN_ON(!mutex_is_locked(&dentry->d_inode->i_mutex)); ++ return oe->version; ++} ++ ++bool ovl_is_whiteout(struct dentry *dentry) ++{ ++ int res; ++ char val; ++ ++ if (!dentry) ++ return false; ++ if (!dentry->d_inode) ++ return false; ++ if (!S_ISLNK(dentry->d_inode->i_mode)) ++ return false; ++ ++ res = vfs_getxattr(dentry, ovl_whiteout_xattr, &val, 1); ++ if (res == 1 && val == 'y') ++ return true; ++ ++ return false; ++} ++ ++static bool ovl_is_opaquedir(struct dentry *dentry) ++{ ++ int res; ++ char val; ++ ++ if (!S_ISDIR(dentry->d_inode->i_mode)) ++ return false; ++ ++ res = vfs_getxattr(dentry, ovl_opaque_xattr, &val, 1); ++ if (res == 1 && val == 'y') ++ return true; ++ ++ return false; ++} ++ ++static void ovl_entry_free(struct rcu_head *head) ++{ ++ struct ovl_entry *oe = container_of(head, struct ovl_entry, rcu); ++ kfree(oe); ++} ++ ++static void ovl_dentry_release(struct dentry *dentry) ++{ ++ struct ovl_entry *oe = dentry->d_fsdata; ++ ++ if (oe) { ++ dput(oe->__upperdentry); ++ dput(oe->__upperdentry); ++ dput(oe->lowerdentry); ++ call_rcu(&oe->rcu, ovl_entry_free); ++ } ++} ++ ++const struct dentry_operations ovl_dentry_operations = { ++ .d_release = ovl_dentry_release, ++}; ++ ++static struct ovl_entry *ovl_alloc_entry(void) ++{ ++ return kzalloc(sizeof(struct ovl_entry), GFP_KERNEL); ++} ++ ++static inline struct dentry *ovl_lookup_real(struct dentry *dir, ++ struct qstr *name) ++{ ++ struct dentry *dentry; ++ ++ mutex_lock(&dir->d_inode->i_mutex); ++ dentry = lookup_one_len(name->name, dir, name->len); ++ mutex_unlock(&dir->d_inode->i_mutex); ++ ++ if (IS_ERR(dentry)) { ++ if (PTR_ERR(dentry) == -ENOENT) ++ dentry = NULL; ++ } else if (!dentry->d_inode) { ++ dput(dentry); ++ dentry = NULL; ++ } ++ return dentry; ++} ++ ++static int ovl_do_lookup(struct dentry *dentry) ++{ ++ struct ovl_entry *oe; ++ struct dentry *upperdir; ++ struct dentry *lowerdir; ++ struct dentry *upperdentry = NULL; ++ struct dentry *lowerdentry = NULL; ++ struct inode *inode = NULL; ++ int err; ++ ++ err = -ENOMEM; ++ oe = ovl_alloc_entry(); ++ if (!oe) ++ goto out; ++ ++ upperdir = ovl_dentry_upper(dentry->d_parent); ++ lowerdir = ovl_dentry_lower(dentry->d_parent); ++ ++ if (upperdir) { ++ upperdentry = ovl_lookup_real(upperdir, &dentry->d_name); ++ err = PTR_ERR(upperdentry); ++ if (IS_ERR(upperdentry)) ++ goto out_put_dir; ++ ++ if (lowerdir && upperdentry && ++ (S_ISLNK(upperdentry->d_inode->i_mode) || ++ S_ISDIR(upperdentry->d_inode->i_mode))) { ++ const struct cred *old_cred; ++ struct cred *override_cred; ++ ++ err = -ENOMEM; ++ override_cred = prepare_creds(); ++ if (!override_cred) ++ goto out_dput_upper; ++ ++ /* CAP_SYS_ADMIN needed for getxattr */ ++ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); ++ old_cred = override_creds(override_cred); ++ ++ if (ovl_is_opaquedir(upperdentry)) { ++ oe->opaque = true; ++ } else if (ovl_is_whiteout(upperdentry)) { ++ dput(upperdentry); ++ upperdentry = NULL; ++ oe->opaque = true; ++ } ++ revert_creds(old_cred); ++ put_cred(override_cred); ++ } ++ } ++ if (lowerdir && !oe->opaque) { ++ lowerdentry = ovl_lookup_real(lowerdir, &dentry->d_name); ++ err = PTR_ERR(lowerdentry); ++ if (IS_ERR(lowerdentry)) ++ goto out_dput_upper; ++ } ++ ++ if (lowerdentry && upperdentry && ++ (!S_ISDIR(upperdentry->d_inode->i_mode) || ++ !S_ISDIR(lowerdentry->d_inode->i_mode))) { ++ dput(lowerdentry); ++ lowerdentry = NULL; ++ oe->opaque = true; ++ } ++ ++ if (lowerdentry || upperdentry) { ++ struct dentry *realdentry; ++ ++ realdentry = upperdentry ? upperdentry : lowerdentry; ++ err = -ENOMEM; ++ inode = ovl_new_inode(dentry->d_sb, realdentry->d_inode->i_mode, ++ oe); ++ if (!inode) ++ goto out_dput; ++ } ++ ++ if (upperdentry) ++ oe->__upperdentry = dget(upperdentry); ++ ++ if (lowerdentry) ++ oe->lowerdentry = lowerdentry; ++ ++ dentry->d_fsdata = oe; ++ dentry->d_op = &ovl_dentry_operations; ++ d_add(dentry, inode); ++ ++ return 0; ++ ++out_dput: ++ dput(lowerdentry); ++out_dput_upper: ++ dput(upperdentry); ++out_put_dir: ++ kfree(oe); ++out: ++ return err; ++} ++ ++struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ++ struct nameidata *nd) ++{ ++ int err = ovl_do_lookup(dentry); ++ ++ if (err) ++ return ERR_PTR(err); ++ ++ return NULL; ++} ++ ++struct file *ovl_path_open(struct path *path, int flags) ++{ ++ path_get(path); ++ return dentry_open(path->dentry, path->mnt, flags, current_cred()); ++} ++ ++static void ovl_put_super(struct super_block *sb) ++{ ++ struct ovl_fs *ufs = sb->s_fs_info; ++ ++ if (!(sb->s_flags & MS_RDONLY)) ++ mnt_drop_write(ufs->upper_mnt); ++ ++ mntput(ufs->upper_mnt); ++ mntput(ufs->lower_mnt); ++ ++ kfree(ufs->config.lowerdir); ++ kfree(ufs->config.upperdir); ++ kfree(ufs); ++} ++ ++static int ovl_remount_fs(struct super_block *sb, int *flagsp, char *data) ++{ ++ int flags = *flagsp; ++ struct ovl_fs *ufs = sb->s_fs_info; ++ ++ /* When remounting rw or ro, we need to adjust the write access to the ++ * upper fs. ++ */ ++ if (((flags ^ sb->s_flags) & MS_RDONLY) == 0) ++ /* No change to readonly status */ ++ return 0; ++ ++ if (flags & MS_RDONLY) { ++ mnt_drop_write(ufs->upper_mnt); ++ return 0; ++ } else ++ return mnt_want_write(ufs->upper_mnt); ++} ++ ++/** ++ * ovl_statfs ++ * @sb: The overlayfs super block ++ * @buf: The struct kstatfs to fill in with stats ++ * ++ * Get the filesystem statistics. As writes always target the upper layer ++ * filesystem pass the statfs to the same filesystem. ++ */ ++static int ovl_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ struct dentry *root_dentry = dentry->d_sb->s_root; ++ struct path path; ++ ovl_path_upper(root_dentry, &path); ++ ++ if (!path.dentry->d_sb->s_op->statfs) ++ return -ENOSYS; ++ return path.dentry->d_sb->s_op->statfs(path.dentry, buf); ++} ++ ++/** ++ * ovl_show_options ++ * ++ * Prints the mount options for a given superblock. ++ * Returns zero; does not fail. ++ */ ++static int ovl_show_options(struct seq_file *m, struct dentry *dentry) ++{ ++ struct super_block *sb = dentry->d_sb; ++ struct ovl_fs *ufs = sb->s_fs_info; ++ ++ seq_printf(m, ",lowerdir=%s", ufs->config.lowerdir); ++ seq_printf(m, ",upperdir=%s", ufs->config.upperdir); ++ return 0; ++} ++ ++static const struct super_operations ovl_super_operations = { ++ .put_super = ovl_put_super, ++ .remount_fs = ovl_remount_fs, ++ .statfs = ovl_statfs, ++ .show_options = ovl_show_options, ++}; ++ ++enum { ++ Opt_lowerdir, ++ Opt_upperdir, ++ Opt_err, ++}; ++ ++static const match_table_t ovl_tokens = { ++ {Opt_lowerdir, "lowerdir=%s"}, ++ {Opt_upperdir, "upperdir=%s"}, ++ {Opt_err, NULL} ++}; ++ ++static int ovl_parse_opt(char *opt, struct ovl_config *config) ++{ ++ char *p; ++ ++ config->upperdir = NULL; ++ config->lowerdir = NULL; ++ ++ while ((p = strsep(&opt, ",")) != NULL) { ++ int token; ++ substring_t args[MAX_OPT_ARGS]; ++ ++ if (!*p) ++ continue; ++ ++ token = match_token(p, ovl_tokens, args); ++ switch (token) { ++ case Opt_upperdir: ++ kfree(config->upperdir); ++ config->upperdir = match_strdup(&args[0]); ++ if (!config->upperdir) ++ return -ENOMEM; ++ break; ++ ++ case Opt_lowerdir: ++ kfree(config->lowerdir); ++ config->lowerdir = match_strdup(&args[0]); ++ if (!config->lowerdir) ++ return -ENOMEM; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ } ++ return 0; ++} ++ ++static int ovl_fill_super(struct super_block *sb, void *data, int silent) ++{ ++ struct path lowerpath; ++ struct path upperpath; ++ struct inode *root_inode; ++ struct dentry *root_dentry; ++ struct ovl_entry *oe; ++ struct ovl_fs *ufs; ++ int err; ++ ++ err = -ENOMEM; ++ ufs = kmalloc(sizeof(struct ovl_fs), GFP_KERNEL); ++ if (!ufs) ++ goto out; ++ ++ err = ovl_parse_opt((char *) data, &ufs->config); ++ if (err) ++ goto out_free_ufs; ++ ++ err = -EINVAL; ++ if (!ufs->config.upperdir || !ufs->config.lowerdir) { ++ printk(KERN_ERR "overlayfs: missing upperdir or lowerdir\n"); ++ goto out_free_config; ++ } ++ ++ oe = ovl_alloc_entry(); ++ if (oe == NULL) ++ goto out_free_config; ++ ++ err = kern_path(ufs->config.upperdir, LOOKUP_FOLLOW, &upperpath); ++ if (err) ++ goto out_free_oe; ++ ++ err = kern_path(ufs->config.lowerdir, LOOKUP_FOLLOW, &lowerpath); ++ if (err) ++ goto out_put_upperpath; ++ ++ err = -ENOTDIR; ++ if (!S_ISDIR(upperpath.dentry->d_inode->i_mode) || ++ !S_ISDIR(lowerpath.dentry->d_inode->i_mode)) ++ goto out_put_lowerpath; ++ ++ sb->s_stack_depth = max(upperpath.mnt->mnt_sb->s_stack_depth, ++ lowerpath.mnt->mnt_sb->s_stack_depth) + 1; ++ ++ err = -EINVAL; ++ if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { ++ printk(KERN_ERR "overlayfs: maximum fs stacking depth exceeded\n"); ++ goto out_put_lowerpath; ++ } ++ ++ ++ ufs->upper_mnt = clone_private_mount(&upperpath); ++ err = PTR_ERR(ufs->upper_mnt); ++ if (IS_ERR(ufs->upper_mnt)) { ++ printk(KERN_ERR "overlayfs: failed to clone upperpath\n"); ++ goto out_put_lowerpath; ++ } ++ ++ ufs->lower_mnt = clone_private_mount(&lowerpath); ++ err = PTR_ERR(ufs->lower_mnt); ++ if (IS_ERR(ufs->lower_mnt)) { ++ printk(KERN_ERR "overlayfs: failed to clone lowerpath\n"); ++ goto out_put_upper_mnt; ++ } ++ ++ /* ++ * Make lower_mnt R/O. That way fchmod/fchown on lower file ++ * will fail instead of modifying lower fs. ++ */ ++ ufs->lower_mnt->mnt_flags |= MNT_READONLY; ++ ++ /* If the upper fs is r/o, we mark overlayfs r/o too */ ++ if (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY) ++ sb->s_flags |= MS_RDONLY; ++ ++ if (!(sb->s_flags & MS_RDONLY)) { ++ err = mnt_want_write(ufs->upper_mnt); ++ if (err) ++ goto out_put_lower_mnt; ++ } ++ ++ err = -ENOMEM; ++ root_inode = ovl_new_inode(sb, S_IFDIR, oe); ++ if (!root_inode) ++ goto out_drop_write; ++ ++ root_dentry = d_make_root(root_inode); ++ if (!root_dentry) ++ goto out_drop_write; ++ ++ mntput(upperpath.mnt); ++ mntput(lowerpath.mnt); ++ ++ oe->__upperdentry = dget(upperpath.dentry); ++ oe->lowerdentry = lowerpath.dentry; ++ ++ root_dentry->d_fsdata = oe; ++ root_dentry->d_op = &ovl_dentry_operations; ++ ++ sb->s_op = &ovl_super_operations; ++ sb->s_root = root_dentry; ++ sb->s_fs_info = ufs; ++ ++ return 0; ++ ++out_drop_write: ++ if (!(sb->s_flags & MS_RDONLY)) ++ mnt_drop_write(ufs->upper_mnt); ++out_put_lower_mnt: ++ mntput(ufs->lower_mnt); ++out_put_upper_mnt: ++ mntput(ufs->upper_mnt); ++out_put_lowerpath: ++ path_put(&lowerpath); ++out_put_upperpath: ++ path_put(&upperpath); ++out_free_oe: ++ kfree(oe); ++out_free_config: ++ kfree(ufs->config.lowerdir); ++ kfree(ufs->config.upperdir); ++out_free_ufs: ++ kfree(ufs); ++out: ++ return err; ++} ++ ++static struct dentry *ovl_mount(struct file_system_type *fs_type, int flags, ++ const char *dev_name, void *raw_data) ++{ ++ return mount_nodev(fs_type, flags, raw_data, ovl_fill_super); ++} ++ ++static struct file_system_type ovl_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "overlayfs", ++ .mount = ovl_mount, ++ .kill_sb = kill_anon_super, ++}; ++ ++static int __init ovl_init(void) ++{ ++ return register_filesystem(&ovl_fs_type); ++} ++ ++static void __exit ovl_exit(void) ++{ ++ unregister_filesystem(&ovl_fs_type); ++} ++ ++module_init(ovl_init); ++module_exit(ovl_exit); +diff --git a/fs/splice.c b/fs/splice.c +index f847684..c124964 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -1299,6 +1299,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, + + return ret; + } ++EXPORT_SYMBOL(do_splice_direct); + + static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe, + struct pipe_inode_info *opipe, +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 8de6755..0b531ab 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -489,6 +489,12 @@ struct iattr { + */ + #include + ++/* ++ * Maximum number of layers of fs stack. Needs to be limited to ++ * prevent kernel stack overflow ++ */ ++#define FILESYSTEM_MAX_STACK_DEPTH 2 ++ + /** + * enum positive_aop_returns - aop return codes with specific semantics + * +@@ -1507,6 +1513,11 @@ struct super_block { + + /* Being remounted read-only */ + int s_readonly_remount; ++ ++ /* ++ * Indicates how deep in a filesystem stack this SB is ++ */ ++ int s_stack_depth; + }; + + /* superblock cache pruning functions */ +@@ -1664,6 +1675,8 @@ struct inode_operations { + void (*truncate_range)(struct inode *, loff_t, loff_t); + int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, + u64 len); ++ struct file *(*open) (struct dentry *, struct file *, ++ const struct cred *); + } ____cacheline_aligned; + + struct seq_file; +@@ -2021,6 +2034,7 @@ extern long do_sys_open(int dfd, const char __user *filename, int flags, + extern struct file *filp_open(const char *, int, umode_t); + extern struct file *file_open_root(struct dentry *, struct vfsmount *, + const char *, int); ++extern struct file *vfs_open(struct path *, struct file *, const struct cred *); + extern struct file * dentry_open(struct dentry *, struct vfsmount *, int, + const struct cred *); + extern int filp_close(struct file *, fl_owner_t id); +@@ -2212,6 +2226,7 @@ extern sector_t bmap(struct inode *, sector_t); + #endif + extern int notify_change(struct dentry *, struct iattr *); + extern int inode_permission(struct inode *, int); ++extern int inode_only_permission(struct inode *, int); + extern int generic_permission(struct inode *, int); + + static inline bool execute_ok(struct inode *inode) +diff --git a/include/linux/mount.h b/include/linux/mount.h +index d7029f4..344a262 100644 +--- a/include/linux/mount.h ++++ b/include/linux/mount.h +@@ -66,6 +66,9 @@ extern void mnt_pin(struct vfsmount *mnt); + extern void mnt_unpin(struct vfsmount *mnt); + extern int __mnt_is_readonly(struct vfsmount *mnt); + ++struct path; ++extern struct vfsmount *clone_private_mount(struct path *path); ++ + struct file_system_type; + extern struct vfsmount *vfs_kern_mount(struct file_system_type *type, + int flags, const char *name, diff --git a/br-ext-chip-goke/board/gk710x/kernel/patches/0011-fix-yylloc-for-modern-computers.patch b/br-ext-chip-goke/board/gk710x/kernel/patches/0011-fix-yylloc-for-modern-computers.patch new file mode 100644 index 00000000..d7088f90 --- /dev/null +++ b/br-ext-chip-goke/board/gk710x/kernel/patches/0011-fix-yylloc-for-modern-computers.patch @@ -0,0 +1,11 @@ +--- a/scripts/dtc/dtc-lexer.lex.c_shipped 2015-08-07 22:08:04.000000000 +0300 ++++ b/scripts/dtc/dtc-lexer.lex.c_shipped 2021-11-01 22:15:12.347053553 +0300 +@@ -637,7 +637,7 @@ + #include "srcpos.h" + #include "dtc-parser.tab.h" + +-YYLTYPE yylloc; ++extern YYLTYPE yylloc; + + /* CAUTION: this will stop working if we ever use yyless() or yyunput() */ + #define YY_USER_ACTION \ diff --git a/br-ext-chip-goke/configs/unknown_unknown_gk7102_openipc_defconfig b/br-ext-chip-goke/configs/unknown_unknown_gk7102_openipc_defconfig new file mode 100644 index 00000000..b5c1416e --- /dev/null +++ b/br-ext-chip-goke/configs/unknown_unknown_gk7102_openipc_defconfig @@ -0,0 +1,96 @@ +# Architecture +BR2_arm=y +BR2_arm1176jzf_s=y +BR2_ARM_EABI=y +BR2_KERNEL_HEADERS_VERSION=y +BR2_DEFAULT_KERNEL_VERSION="3.4.43" +BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_3_4=y + +# Toolchain +BR2_PER_PACKAGE_DIRECTORIES=y +BR2_GCC_VERSION_7_X=y +# BR2_TOOLCHAIN_USES_UCLIBC is not set +# BR2_TOOLCHAIN_BUILDROOT_UCLIBC is not set +# BR2_TOOLCHAIN_BUILDROOT_LIBC="uclibc" +BR2_TOOLCHAIN_USES_MUSL=y +BR2_TOOLCHAIN_BUILDROOT_MUSL=y +BR2_TOOLCHAIN_BUILDROOT_LIBC="musl" +BR2_TOOLCHAIN_BUILDROOT_CXX=y +BR2_TOOLCHAIN_BUILDROOT_LOCALE=y +BR2_TOOLCHAIN_BUILDROOT_USE_SSP=y + +# Kernel +BR2_LINUX_KERNEL=y +BR2_LINUX_KERNEL_CUSTOM_VERSION=y +BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="3.4.43" +BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y +BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(BR2_EXTERNAL_GOKE_PATH)/board/gk710x/kernel/gk710x.generic.config" +BR2_LINUX_KERNEL_UIMAGE=y +BR2_LINUX_KERNEL_XZ=y +BR2_LINUX_KERNEL_EXT_GOKE_PATCHER=y +BR2_LINUX_KERNEL_EXT_GOKE_PATCHER_LIST="$(BR2_EXTERNAL_GOKE_PATH)/board/gk710x/kernel/patches/ $(BR2_EXTERNAL_GOKE_PATH)/board/gk710x/kernel/overlay" + +# Filesystem +# BR2_TARGET_TZ_INFO is not set +BR2_TARGET_ROOTFS_CPIO=y +BR2_TARGET_ROOTFS_SQUASHFS=y +BR2_TARGET_ROOTFS_SQUASHFS4_XZ=y +BR2_ROOTFS_OVERLAY="$(TOPDIR)/../general/overlay" +BR2_ROOTFS_POST_BUILD_SCRIPT="$(TOPDIR)/../scripts/executing_commands_for_$(BR2_TOOLCHAIN_BUILDROOT_LIBC).sh" + +# OpenIPC configuration +BR2_TOOLCHAIN_BUILDROOT_VENDOR="openipc" +BR2_TARGET_GENERIC_ISSUE="Welcome to OpenIPC v2.2" +BR2_TARGET_GENERIC_HOSTNAME="openipc-gk7102" +BR2_GLOBAL_PATCH_DIR="$(TOPDIR)/../general/package/all-patches" + +# OpenIPC packages +BR2_PACKAGE_BUSYBOX_CONFIG="$(TOPDIR)/../general/package/busybox/busybox.config" +BR2_PACKAGE_DROPBEAR_OPENIPC=y +# BR2_PACKAGE_FDK_AAC_OPENIPC is not set +BR2_PACKAGE_FWPRINTENV_OPENIPC=y +BR2_PACKAGE_HASERL=y +BR2_PACKAGE_GOKE_OSDRV_GK710X=y +BR2_PACKAGE_IPCTOOL=y +BR2_PACKAGE_JSON_C=y +BR2_PACKAGE_LAME_OPENIPC=y +BR2_PACKAGE_LIBCURL_OPENIPC=y +BR2_PACKAGE_LIBCURL_OPENIPC_CURL=y +# BR2_PACKAGE_LIBCURL_OPENIPC_VERBOSE is not set +# BR2_PACKAGE_LIBCURL_OPENIPC_PROXY_SUPPORT is not set +# BR2_PACKAGE_LIBCURL_OPENIPC_COOKIES_SUPPORT is not set +# BR2_PACKAGE_LIBCURL_OPENIPC_EXTRA_PROTOCOLS_FEATURES is not set +BR2_PACKAGE_LIBCURL_OPENIPC_MBEDTLS=y +BR2_PACKAGE_LIBEVENT_OPENIPC=y +BR2_PACKAGE_LIBEVENT_OPENIPC_REMOVE_PYSCRIPT=y +BR2_PACKAGE_LIBOGG_OPENIPC=y +BR2_PACKAGE_LIBWEBSOCKETS_OPENIPC=y +BR2_PACKAGE_LIBYAML=y +BR2_PACKAGE_MAJESTIC_FONTS=y +# BR2_PACKAGE_MAJESTIC_GK710X=y +BR2_PACKAGE_MBEDTLS_OPENIPC=y +# BR2_PACKAGE_MBEDTLS_OPENIPC_PROGRAMS is not set +# BR2_PACKAGE_MBEDTLS_OPENIPC_COMPRESSION is not set +BR2_PACKAGE_MICROBE_WEB=y +# BR2_PACKAGE_MINI_SNMPD is not set +BR2_PACKAGE_MOTORS=y +BR2_PACKAGE_OPUS_OPENIPC=y +BR2_PACKAGE_OPUS_OPENIPC_FIXED_POINT=y +# BR2_PACKAGE_SSHPASS is not set +BR2_PACKAGE_UACME_OPENIPC=y +BR2_PACKAGE_VTUND_OPENIPC=y +BR2_PACKAGE_YAML_CLI=y + +# WiFi +BR2_PACKAGE_WIRELESS_TOOLS=y +BR2_PACKAGE_WPA_SUPPLICANT=y +BR2_PACKAGE_WPA_SUPPLICANT_CLI=y +BR2_PACKAGE_WPA_SUPPLICANT_NL80211=y +BR2_PACKAGE_WPA_SUPPLICANT_PASSPHRASE=y +BR2_PACKAGE_LINUX_FIRMWARE_OPENIPC=y +BR2_PACKAGE_LINUX_FIRMWARE_OPENIPC_MT7601U=y +# BR2_PACKAGE_RTL8188EU is not set + +# WIREGUARD +BR2_PACKAGE_WIREGUARD_LINUX_COMPAT=y +BR2_PACKAGE_WIREGUARD_TOOLS=y diff --git a/br-ext-chip-goke/configs/unknown_unknown_gk7102s_openipc_defconfig b/br-ext-chip-goke/configs/unknown_unknown_gk7102s_openipc_defconfig new file mode 100644 index 00000000..ad34a072 --- /dev/null +++ b/br-ext-chip-goke/configs/unknown_unknown_gk7102s_openipc_defconfig @@ -0,0 +1,96 @@ +# Architecture +BR2_arm=y +BR2_arm1176jzf_s=y +BR2_ARM_EABI=y +BR2_KERNEL_HEADERS_VERSION=y +BR2_DEFAULT_KERNEL_VERSION="3.4.43" +BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_3_4=y + +# Toolchain +BR2_PER_PACKAGE_DIRECTORIES=y +BR2_GCC_VERSION_7_X=y +# BR2_TOOLCHAIN_USES_UCLIBC is not set +# BR2_TOOLCHAIN_BUILDROOT_UCLIBC is not set +# BR2_TOOLCHAIN_BUILDROOT_LIBC="uclibc" +BR2_TOOLCHAIN_USES_MUSL=y +BR2_TOOLCHAIN_BUILDROOT_MUSL=y +BR2_TOOLCHAIN_BUILDROOT_LIBC="musl" +BR2_TOOLCHAIN_BUILDROOT_CXX=y +BR2_TOOLCHAIN_BUILDROOT_LOCALE=y +BR2_TOOLCHAIN_BUILDROOT_USE_SSP=y + +# Kernel +BR2_LINUX_KERNEL=y +BR2_LINUX_KERNEL_CUSTOM_VERSION=y +BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="3.4.43" +BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y +BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(BR2_EXTERNAL_GOKE_PATH)/board/gk710x/kernel/gk710xs.generic.config" +BR2_LINUX_KERNEL_UIMAGE=y +BR2_LINUX_KERNEL_XZ=y +BR2_LINUX_KERNEL_EXT_GOKE_PATCHER=y +BR2_LINUX_KERNEL_EXT_GOKE_PATCHER_LIST="$(BR2_EXTERNAL_GOKE_PATH)/board/gk710x/kernel/patches/ $(BR2_EXTERNAL_GOKE_PATH)/board/gk710x/kernel/overlay" + +# Filesystem +# BR2_TARGET_TZ_INFO is not set +BR2_TARGET_ROOTFS_CPIO=y +BR2_TARGET_ROOTFS_SQUASHFS=y +BR2_TARGET_ROOTFS_SQUASHFS4_XZ=y +BR2_ROOTFS_OVERLAY="$(TOPDIR)/../general/overlay" +BR2_ROOTFS_POST_BUILD_SCRIPT="$(TOPDIR)/../scripts/executing_commands_for_$(BR2_TOOLCHAIN_BUILDROOT_LIBC).sh" + +# OpenIPC configuration +BR2_TOOLCHAIN_BUILDROOT_VENDOR="openipc" +BR2_TARGET_GENERIC_ISSUE="Welcome to OpenIPC v2.2" +BR2_TARGET_GENERIC_HOSTNAME="openipc-gk7102s" +BR2_GLOBAL_PATCH_DIR="$(TOPDIR)/../general/package/all-patches" + +# OpenIPC packages +BR2_PACKAGE_BUSYBOX_CONFIG="$(TOPDIR)/../general/package/busybox/busybox.config" +BR2_PACKAGE_DROPBEAR_OPENIPC=y +# BR2_PACKAGE_FDK_AAC_OPENIPC is not set +BR2_PACKAGE_FWPRINTENV_OPENIPC=y +BR2_PACKAGE_HASERL=y +BR2_PACKAGE_GOKE_OSDRV_GK710X=y +BR2_PACKAGE_IPCTOOL=y +BR2_PACKAGE_JSON_C=y +BR2_PACKAGE_LAME_OPENIPC=y +BR2_PACKAGE_LIBCURL_OPENIPC=y +BR2_PACKAGE_LIBCURL_OPENIPC_CURL=y +# BR2_PACKAGE_LIBCURL_OPENIPC_VERBOSE is not set +# BR2_PACKAGE_LIBCURL_OPENIPC_PROXY_SUPPORT is not set +# BR2_PACKAGE_LIBCURL_OPENIPC_COOKIES_SUPPORT is not set +# BR2_PACKAGE_LIBCURL_OPENIPC_EXTRA_PROTOCOLS_FEATURES is not set +BR2_PACKAGE_LIBCURL_OPENIPC_MBEDTLS=y +BR2_PACKAGE_LIBEVENT_OPENIPC=y +BR2_PACKAGE_LIBEVENT_OPENIPC_REMOVE_PYSCRIPT=y +BR2_PACKAGE_LIBOGG_OPENIPC=y +BR2_PACKAGE_LIBWEBSOCKETS_OPENIPC=y +BR2_PACKAGE_LIBYAML=y +BR2_PACKAGE_MAJESTIC_FONTS=y +# BR2_PACKAGE_MAJESTIC_GK710X=y +BR2_PACKAGE_MBEDTLS_OPENIPC=y +# BR2_PACKAGE_MBEDTLS_OPENIPC_PROGRAMS is not set +# BR2_PACKAGE_MBEDTLS_OPENIPC_COMPRESSION is not set +BR2_PACKAGE_MICROBE_WEB=y +# BR2_PACKAGE_MINI_SNMPD is not set +BR2_PACKAGE_MOTORS=y +BR2_PACKAGE_OPUS_OPENIPC=y +BR2_PACKAGE_OPUS_OPENIPC_FIXED_POINT=y +# BR2_PACKAGE_SSHPASS is not set +BR2_PACKAGE_UACME_OPENIPC=y +BR2_PACKAGE_VTUND_OPENIPC=y +BR2_PACKAGE_YAML_CLI=y + +# WiFi +BR2_PACKAGE_WIRELESS_TOOLS=y +BR2_PACKAGE_WPA_SUPPLICANT=y +BR2_PACKAGE_WPA_SUPPLICANT_CLI=y +BR2_PACKAGE_WPA_SUPPLICANT_NL80211=y +BR2_PACKAGE_WPA_SUPPLICANT_PASSPHRASE=y +BR2_PACKAGE_LINUX_FIRMWARE_OPENIPC=y +BR2_PACKAGE_LINUX_FIRMWARE_OPENIPC_MT7601U=y +# BR2_PACKAGE_RTL8188EU is not set + +# WIREGUARD +BR2_PACKAGE_WIREGUARD_LINUX_COMPAT=y +BR2_PACKAGE_WIREGUARD_TOOLS=y diff --git a/br-ext-chip-goke/external.mk b/br-ext-chip-goke/external.mk index 49aef1fe..336d955b 100644 --- a/br-ext-chip-goke/external.mk +++ b/br-ext-chip-goke/external.mk @@ -4,6 +4,7 @@ include $(BR2_EXTERNAL_GOKE_PATH)/package/aura-httpd/aura-httpd.mk include $(BR2_EXTERNAL_GOKE_PATH)/package/dropbear-openipc/dropbear-openipc.mk include $(BR2_EXTERNAL_GOKE_PATH)/package/fdk-aac-openipc/fdk-aac-openipc.mk include $(BR2_EXTERNAL_GOKE_PATH)/package/fwprintenv-openipc/fwprintenv-openipc.mk +include $(BR2_EXTERNAL_GOKE_PATH)/package/goke-osdrv-gk710x/goke-osdrv-gk710x.mk include $(BR2_EXTERNAL_GOKE_PATH)/package/goke-osdrv-gk7205v200/goke-osdrv-gk7205v200.mk include $(BR2_EXTERNAL_GOKE_PATH)/package/ipctool/ipctool.mk include $(BR2_EXTERNAL_GOKE_PATH)/package/json-c-openipc/json-c-openipc.mk diff --git a/br-ext-chip-goke/package/goke-osdrv-gk710x b/br-ext-chip-goke/package/goke-osdrv-gk710x new file mode 120000 index 00000000..e360e37b --- /dev/null +++ b/br-ext-chip-goke/package/goke-osdrv-gk710x @@ -0,0 +1 @@ +../../general/package/goke-osdrv-gk710x \ No newline at end of file diff --git a/building.sh b/building.sh index 8fec600d..2b95f3d9 100755 --- a/building.sh +++ b/building.sh @@ -135,6 +135,26 @@ fh8858v210() { ################################################################################# +gk7101() { + soc="gk7101" + fresh && make PLATFORM=goke BOARD=unknown_unknown_${soc}_openipc all && rename +} + +gk7101s() { + soc="gk7101s" + fresh && make PLATFORM=goke BOARD=unknown_unknown_${soc}_openipc all && rename +} + +gk7102() { + soc="gk7102" + fresh && make PLATFORM=goke BOARD=unknown_unknown_${soc}_openipc all && rename +} + +gk7102s() { + soc="gk7102s" + fresh && make PLATFORM=goke BOARD=unknown_unknown_${soc}_openipc all && rename +} + gk7205v200() { soc="gk7205v200" fresh && make PLATFORM=goke BOARD=unknown_unknown_${soc}_openipc all && rename @@ -482,6 +502,10 @@ xm550() { # ####### # +# gk7101 # testing.. +# gk7101s # testing.. +# gk7102 # testing.. +gk7102s # testing.. # gk7202v300 # testing.. # gk7205v200 # OpenIPC # gk7205v200_fpv # FPV @@ -560,7 +584,7 @@ xm550() { # t10 # testing.. # t20 # testing.. # t30 # testing.. -t31 # testing.. +# t31 # testing.. # ####### # diff --git a/general/package/goke-osdrv-gk710x/Config.in b/general/package/goke-osdrv-gk710x/Config.in new file mode 100644 index 00000000..20811a16 --- /dev/null +++ b/general/package/goke-osdrv-gk710x/Config.in @@ -0,0 +1,6 @@ +config BR2_PACKAGE_GOKE_OSDRV_GK710X + bool "goke-osdrv-gk710x" + help + goke-osdrv-gk710x - Goke kernel modules and libs + + https://openipc.org diff --git a/general/package/goke-osdrv-gk710x/files/kmod/audio.ko b/general/package/goke-osdrv-gk710x/files/kmod/audio.ko new file mode 100755 index 0000000000000000000000000000000000000000..d7fd53da67d5bc3bcb12dd331a3b06b803bb94bc GIT binary patch literal 15884 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 S)Ce9YF2gyBd2`>O)c*hb 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 literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/kmod/hw_crypto.ko b/general/package/goke-osdrv-gk710x/files/kmod/hw_crypto.ko new file mode 100755 index 0000000000000000000000000000000000000000..eb4c04f4ba4e503e4f5ab8ba4b7f08949f54cd31 GIT binary patch literal 4668 zcmd5=UuYcX5ud$Vsj?&07gH=jrwRyBf8xYw6qNc&__wyLtR&^8`k>3 z-}QILYpLPY2BoWYovIsOY;OL8u`|8cV7U#lwf3vq+?D$zrH_R^%D>ZEX=wC(y^Uz6 zW`%J&t*}2)wVp)(U34=*6=z=J(ByK1hN~NXY_*}K!~9y}LOl6^c-fk`4ETc_NyxAZ+dsClWs;LL?r(``f7e7lK%?YTl25Mrt()I ztNfQBtNhE5RsM^Rqxlz``cmVZ$h=0r$Q_UiB6mXOy*ZD)*_)=%I>8-a9oz#>fRkVY zoC5pcGPnSq0r!I!!56^i!1LgX;5>L7d2f8toJnHMp-_#9t9 zRx9(J@FRV=^-i!7*yqM#P2CL`OP%k6lv*2%wWql@xKHG6;giesbuh;ynJZoO6F-cN zdcYVzjh%Rbem463gG0uR_y4?fcI_8k&&2+@df^tD0-B!9%!5^<7{zq3^Gi_hEU>|1*bIYmU6b~&p2KN{pJcbnNuEu zE}^`j037N8&(G#&$$akAaWm^9*A&i;hY9#U=}GwEo}+g0=XcK$zBq)Gi2IXv zC?oLRE~0nQ@e#<}pZ)mhv`=&u?;IK?U{j>xeH(^oymuZZIshBTu5;9 zrbxx(x})(vLc9cQ91r(%Gu{Z~uYrT-5AY5G^a2&Bct3%G^RgeeClDlj8bSdnztfPT zdGAE>vOoJV=D{i+L`ota*QSWum|g}){Y>~pms9zj7r&>t6X@6Q!#QaZ`!T;E$aBhc z1AecEV(_cRf%oCIaooo^EZDflF0dNMWyl;?#hb)J52>QW4?vf|(Rt~|hgGcywoWtN z?;!L1sCX+_9QISB>iazmoQ7*+V!zQ)41T$d`2)egh@W*{>GbI)?>Qzu*DWpQX{p%Re1U@JT&CdSTh**|+fx(I!;(LXT%jii zV#O}LYFFH_q-H^(%Umf4m&xSZ@c`#g~Ce0QZDBYKAs2l%(5UlE}5nA z-jj^Of)mm{DOeDk7hD#+EVw54p5Rr%YmA6{SM&t-CfAV?>=PUk92Pvnh<;_!mjy2i zt_i*;cvbKkBl@ii-V(ekcwg`e&TZ;jm_J7RA*|zaOyPlHF@6)w^M(W8&xi-g0Y(@{ zfok1i9r(Wt)^VYx8KLtzNa3gdY|WAJBwqEP2zwFd&kRRgLCIBFJ$3d3Y~A$r9!CB(^_WJ_yA zLa(?{TraLYTdjA!zwsmg>5=)a=v>n;s`Z~QF8;U@JloJ^A*zk8ldoOusEYr%I)CM= z{Fi>@$nQS?;CzQQ+Z54iU5H%`BSx(G?iZqcIB~o=VjXY##AEeag;>{VRvS^Vb6y0i z4eE2PS*<_&oxf__Q#sd&nmZxqM03zu+5FI&YxV;>tb_9rpoMp|Ff+db^N0p_&Kr=! z{#te$WV5f|I@T0;4Y8)-Lmhc8EiNvIO0@y=EX-Esnpy_igcxgFCu(b8!gVI}q&~eE z>)9>P$$Godmsr^hKwiLndERIKqb02BX3p_T;BSR4eb6PKbP*!f2%vu0Jl>=%pLMVn zLwVSmX|{-6^&#tc56V5%<62Q`nCExSU;4w>E=spS8T#PTzka?=hZD2Sk=Sh0s5-XY z58Dn^FizokvsFygRs2d`Y=gFC_B4j)83KDZtA zj0+RCp#2T&xf<<10zY(!<4yVj2uzzr-hyB*C{mX`L)xiq}_JbgJu&(P^V{&Z| zv!9%EtPa~B@rgu@GHFY{v`uP>*8U*2Slj2}&pPaROHi)2Si>)Mn`!mh;D0*5VbA=A zJ@W(ozcN3@<~4|KYbk!tHo8^06?VgXvF|u>#<{kDAM`QQzf4-k$z`>7_i;}tRO^eQ zKWtq0*bf_qc(k#)QhN@Y)R8mTg9Ye-d92yG?brqEtF72y*LGP4TSL~twF0&_uot#N zpO!?mF&ms~b|+?R_w0Bx7KZ$eH7#^d}aqKBKUXxFmZD%JWYdW~>_;JE?sCcIn&mO2{)IJ+jI zv&}B^Ma;F@Sij+5qsu(dG_i&mOE39+HDP_HIS4umTIv*wA-=>Lofy}TFM(e(4)fiHI-whbGn+wb5xw)!ZH-g*dX^$1b1JZuM#34B^+A9a0#7%!DMCH$g zxGRTk<|#v{eM8$rpW_DB5Pkb)>}~thcmeEHSyc{Vy{1(;p^$sos4DaP<5@I_HTdHNy`#N>+SMucEkNI+*dM`Is+vm+`P|XQb5+^hzt0jZXix@#U!epNJ|W4_WA4sz2M%w(UZn z??XTKtpNSdpK(t+cR(Na`S3AfZX)_(Ga!y3uYx|z?Vty9w|CLETg_GP1FhHx&S34f zK%TS#@Dyn7)hB@nHd+6wtK4TI9>gO!dqq3fTNh+gpBH^b%>pgg8)BpnHjgM?U zEathZz7e`~Vy{e~j&#%z?a=Rt-@JF8bT4SbJSfW#7-HRRhFIuVymzB5U>(1+(>iu% z#1I3T?;h~=gRfKZeFI}$1DV&YcjR0Kt$9~KhEI*P3H|Pat!v$mE^Az4v)rcmpu@WN zz;`Ax*JM72$gQrSeQpkl`8Mn+N6{wjg}504Zv`~> zUDgFq7e!scRo8*Ke$*u>GkBlO_c~EWyAK9$YW@K6i>u9o1znhD3!F8>Ch|St5U>Ln z1qOkGK-fy==*&fRen{OrtrzG0*1Hzg4D$2Q#>a?7#9Lj?5BVY1*8=nO2%ez=Ua>nP(?_a=gTG*3J=!*HBRP`2gj-cV3$)AbVX_^?4Gqxql?I48$_yvmbpK%ijJG)jy*6e+~Wn(Z5&G?ii0k2G`CNGGeeb zWMEHNce%xxAJ-4}B(5or$+bkCw?j7l8Abhh#mk)S-0HdJxvx5X-$6ZX(ig*-m_WW; z!CI_h4h3i4CtsRtejReUDlg0jDu?7!y^K8O@I24zPLw0m5#cz_!IbYhYD|Tq!mw3KLU;4zi>gN|12e|hHt=1-O?e#JDEWJ0KHyoR+#91|}czK89 z{e`l5cXh{Uz!RtUsyLOgi8!TBTpQaUOWuvuJ(RJ`^uXn$GlV&4S?j@reF(ncz1bSFqPmpUsQ6*F&mJ>Y>UVT(jWA z9=OD}TD1jL+qGz8f98I}7WaWF?#aivCKmcZ^E@HF6?*~K0qfVop4f*M@Eu|4{v#gu zN82A4q64q-xW5v>EB9)gTYkI&ykmI(8kHa6U5UwH9~E)D2k`z8-t%~WhWE=D1p0_g zz!l=OIE#KOL_t)5zlyr&@V)o)=i3-nG#0GrM@s7ftq`MIZjC%unp40<-V0M^Jqmsjzj*Hi5lg1Fa-eZu z(IRoUc@Aa98TAXq4mZz$#yXL--{O7gaPt)EZcueysOv=CZ-%OJZtUkrzoSYfeL4f1 zbzr}(z&5{)c2SW2d84d&R>DTK#RT}UM(5MuJD~Vr-#5lwvO0n@&e;eat_6-qn_g1! zqU|;~EB;d;M*VnoysyC}VI$rNm^K1@7%$B{24sxs?|^31$-!_pm1A+O>2U+tOE{)C z2U_;l|BX^Mld^LqdrPdCFBCI&Ia%BcPyG%5f?9Ip0=0N-Msaoyg6l0<%|2x@qE#w6}1!c#rWP#vFwa`Wy65EcMI*( zXBH&VXrC2SvXUvgq0I9SM?d=%L!AmD91Z}%yQl=+Iupk zGF%50C6Ui9v!ythWEue?qf&aVr_|>}xb*FE95DFZG1x8;_=v!zF_%Uv?o;xh5P8a< z!&7$g$lo?_RtdiD2c6yI|Cg^~0oo1un85Zgc0BZ`c>Sl*YT(9a|KaZ=cVB=$xuLvksSc5-({7$%CX zcZs&PfN_nn+TUrcHE!^A88;g1TE61%Geo$wf2y3^4J;QOoY1ABoeh`mePt2WrSNnv zo0+t;`<*I=nv28UcLiC@r<3KR2v6nHT!-i)D>x7)-Rq7rCqt4mdCzsc`?X~q9f%YKU|Wx(<5&X!O6b* z(eien!YywWA6HD&Q6BQ8C3(1$N&U1+Wym{$I{j#QkD-p|Rne)~1 zI`FYgek(;CAGYzC#LMy>B=9^9zG)gxJ#6FqTMBj4r7q{Lq1fcOEI*CctzTDI2;}2Z zziWY7zZX!ZTrKZY$iw%drAN&-Prs# z_!=yzNAnT&T-h{>1$Y|D!;E4*Ue1Gdr|sPGqTNCqa#d(~V7uz$Thh*9@m(R2^0_jW zAD{Gun|6DU{J2H99-q9mE?4*jBW3yV33__@@d?+)f@+_@?cDYF#2OdHcAgx|k58<< zVn%-Plf`z`Onsoy5 zZ+hsB9=hK{f73%h?4idz^llGb@X*hD=s6F4%0vH!hyGg+{eg%6$V0cd_7KkhMi1TV zq5D1bP7nQrhaUIP&vc<;3MHVLZmxR8@NgqfS*IZy}`GFyx%1*+s_LJHi^nF$^8urEc?LqdYa?73Z$t72w z6c`^4gU%>CZ5Q(>$!kD-I+M=q1tsS|d%z0Qc6TR)J2?{R zn4(`NVpIQ+xB)^6ghNQj6-LYxA&+>0}m^Z=N#--M#bVTho6iI6ivgq)*9 z$T>-boKJ|56T?11e(op48R9pP9}&MQ#Op-pcbd2!dI34^$3&d30YB=yakeTvOGKjf z0TJ>(R#?T^&H6J$)c>8r4~dX}i3s^KIB!F@VLXNJ5Vzu-CPJ@I6$UVN3(n^bB9i$a z@p{;oh__4O7%+4T>_$ZYimE?Jdb1F3s`?s{dJv(XAGrbb=>$?-g_l?lxt|gt zH-H?5bSDw?1hE_QCf<)blET-C_X%;1h~(^&!Vqjqx{vrZ#us4wM#)ybX$-iCkVLmbP4LkXBXcOXvH0qBNZ+G%&%6*eG%=~7k48?HV@0Pu|-9ns@SF7?%H+dPp8natEgRNm6iAVyYF+t z%{0)~)%SUy&+~@Q;rzeOb*^)r>s;qL=RR}i>$-j~6bd=^FXXg3r(=$DXmUhZRqbAZ zR%eFO?3_26%_p9^{JH3GSD_`fqvSYSajBw{%!Vjk`|DGuen>d4bcLf13SK+V@#BuuG?V@e&6`*{j=v3m9sYLw8TeWJ%)Hx5 zu~|Dx{UMc!6f*Oclv?S>M&e;-S^lGLw*F&oHnMi+#AzQPj9;~8=EPEz{`cU=@K@un znt5Ak6Lki0`=>xV#%$Dmr06*B$T{(zf)oE-?)~nMpLI!FKeabMG;>F(F8MqC3fj;q5txRZ&A zr4zUpaK~}aCzh0s;Xi}R;hx4lg*$>fjC%}s2zL-Sg4=`3Cg>Oa$k4uU%mQOOX`}Ha zr4^+818IpwU;QT&k??ktr}F#B*H|cRi1Iz~o5uB5q=gfGkqC7{iAN(td(6Gd@Dkrmz~6>HfG@uLU-*{qn$N*^@LbXInqzoPJooN+ zw%+pF+9?yKS)M!cGI(y6;W_cOc;_ea&{X&*9Ez{6kK}I8iHBBB5ifqMFiE@!fA&sU zpFaVQXIm z7@4iKNyO`kuQc)h5pkNPIZioAJ>_3Wel#(7rIYBraa#B@)P3XIZf= zk(nkrl)(RJ#7~EhiXVsTgwy zt6JUus@C`ra(NK>y)^&(wEYZg;_{226L6xVgU^JV75O)ScQi2s4OZl}9);ZALI~OL z^HZmq5|{7rWd9$Bo!SY|uEoTmTWzxmKT2MM313AU>!DT5#D79LWX!My)tB_M$+tSNAxGaAedH0hS0~gVmc@v2x`m5?pJWjlhcs!6FC*BZmaYE`Y1N5r-fNR|wW~I4{?p`#!P9Ylyi`|ZZ2pk|%;W!s9!0;u8%VR| zzC~I?;z((v{z!h`>?3){>(`NzhY#U8@?!WgeD#^}DXQO{#MSr3_>K4-*ZA~(F#Ova z%dBuSWBD0_yT)?Y+|y(E0O@aD}b9m_h#vb$+V z=>lkxB0V^kA2fId$MSuo1;;X?aSM#)yUF*`&N7zo2*8~FYkw?P1k&tS-b&gl8B58m z@y0UqTA#l2e#5bhGiI90z>jEdYA#+b+=Kyn{k@UtvIKLxy=~01jgx9 z2)O}#;iq|b`4!pXN9Y6m@LUVD{4g@qw)FyKy*Xss|Dxn$KxVyM88;p+{{`5Re_DV3 z$+RO{4qbMdmPbgpw2X@1=#$0m+vJ^#j$b2xBd~M5rfVFMS`1JoZdz%34S4{sOQU7f87wv<* z&*pi2`e(-H^S=$q7J{_af0&wX7bKO`!|t4 z3M@xBrmG0=pzi6+JB|PO2LGV` zHH9?ksjAl&KT_&+kBs#fL)@9`3wE;*_Ad5%`GmWnioH?!7l|BG(J6<(Ap#5+Tgmai z{LHa0Y+nwl(SRsjbbj3La~;uu`%$`Z|^9 zDSK=h*fLcH?L>9#&7EYbFpIsQWAvUGjs01H`A#C-EN99POdw>lyLi=iDTo6vj?wBZ73vC?4jL$_T%iY zE$)orv~;dm4c^w?#Xi+(F!-lUA1oc5RH`ry+wn~B*_hl>Y5;fP<0kfCXLHJj;`Jqm zHnqN-92BbAGs2aX-dy9;*wIurMM zdb;w2f0c_I2fk#=f>W=~%dTR}YOH0W9&e1HX{4R{vMH`sd+2DuV{H0Ms}yHkr&5Ob zUV8)@4m1A4u0Q^&^APbUZF@YxxJJ{tdYAf}=yN4+Gy!8>N@KCX8w=?`D@8wW4)O+e zi!t7K4Blvg&MnZ=g*P69Hx3)#&^QW*wli=5mZ5i$SFj^_ymI0Lj*}+*pZFRB(Zur1 zE1f&4-%tTV^G0K$zB=IM(FGb-kv7fHxjTq2d^$Oms~2x24c>>DbC0=0qvmNa=%61k_=f5-)y4Kn_Qo7)*3mo&cxTyhe}=n z|Js$Q9i>*oE1HMmlQ`>TkXM3oWF@@P0k3qxEA8;gN_b_J;gx3UtIw4@(E^#|(zuPd zAU}9x>Et5NHRhz49|neGs`%EUA@i);hMk*>%;wro6JNzRu4EiLh+7$vVC5N}1 z;ZBq?Y2IuZVjiIB3QDe|{5kr^Hhk$KX$pv@Yt8!a znDapg`%85y8$y27dVO*3^TyZf131K)OA3!T{#j7e`t;w8?FW|S#Vo9=;ODdr@u6T_5@=UWmi#dkb280ch8^p7apSQP|}xa@$3eV z*2C1x7{YPVrYh9)v+&D8Q9An(Dd3ob-2$>~5ZzHa=`vhaQ*yK4z zuXD7=O@6}XJ!h!29X_0C`G+zQc*p7{IzvZhlr_e0z>dLO#oq4oiFA*&(_d;E%uGus zhNdldcTCgRH@kh)R6db__mZ5!BkzS%t91Ln@%g#?YR7pka|$`){oTU;A(!bx538m z&qLMII^oG-GjA6%Z&zgoOQEcAUS5naf2Xm2b%A@>$>uwNBY0k0AAO`)o2FbcTU^xh zjiNJ{)p=T3W4$uYoOhq_*Ad15y`?F}TG8R&2R}ca0EY$Y3$nUNbXWNfXd>7h>AR2@ zsp1vn9d^Iw_0OSQ$K9L@B|e`ECHo7^Z;@E_0StG~JKfgd+e5blQCOSdfiTBc`&KNCR^pVKo#9$TswyJd#Pq(oK zI46Mfyg8q(0nRff{3ql!aaQq^i8s{vxYimPG;`MJ$yoY)J7u>^P zY5Q%o9X0iDrq1m(PB~-h+)(Y*&H?8MCZDTKwdiaEH74E&ZdJs)P5E!vI<+6ITUxvk zIKQS3_UxJSl`$GFB=7t5q1Dv+LG(;|PofPwZu2PnVfx^hvbn0${reSRi}z)e1%yn`D6ueeA>{-(*8U2%eK)--8TBX)6~5_b~_xFTt+b3(Crssgk7!-e9>y#VBABmx(&%LR?(8zp`ChmG>va{#dWakUV zBF+%*u45|uGs@O+?#!GjDjrT8JQ{I(bMjAc#v4hSbsXPY$MHYSI=K z#A|ZE+73;1mhNP7kw|*zsFT@@xVWYG&)~Y;$Y1SupCCTOdG2m^2swFEF@#(QIgRLM zPVEmb>MvyKc9a&z*B2!3S5r zit0rFQ5Tr#*|pcK;7q{OuOVI)@6W0IL)42Jyu5tsRZ%Zay$dL}={D>&fqKGK^@gZt z`xC5}sVFa+sr+inw~W(HXmw*@Ei_MY&a80>r_V2}A@0faY^tys`s)n(;lvO&i~3?G zI60YYu@!jIvsKO||C$y3g%0+0k@(Qj2J)01$B)MSJBI&$ExbnDiTkqoWUcP0`FSr8 zZZ+ZO3AdPVOZtgYj(9R%UHD-7$Ir%`ThKq8re>3Wh&$cPec= zX*N7Wc%iAciEz?{`w4fN@H)bcCcK7lg9)!D95>+>!d3B&-rCx5wNIl6G@1^L7L%uT zL#cS-SFEMiEbK3|lh)I-r4(XKuK};iR{6O3eRIlYPI(>l^W*|D0bMFWdd=gkA>Sb{tvr>N zJYX%UyKu)eVAO}){tLp~ouupq-=JK_ndR!AY28spxk%U@su8>clo_-8fWtoGZQvt$ zsJSe8VdqzS?DYJqEMwf=)^<$gx zN^CAI=5CSh5q2dqUjy$)H&1ZBHK@D_eYHD%4*fK}rSt`Knh^827y4=JfmOV795~Bg zCY+uCoIe3hcWz0c%bm#H;DD#&PIh*&ejLEb|156Pu@%^p@8Ql>owMbbk3*{P_6bf? z%Y0wgz73ckC;uY!&lBc+{T5)izsB$fVvdg6Thz%j`tsJVO@xta5v$Y32!1?M>qn_RPIV(9XGHotOT%z<4@*y0&jP` zKfjxBn0gBDAw29pndh!!Ar!wo*Kf+~C4D#Pf@||uo4jV)D6{^uKP%X^*ZQ7KKXI4G zJ5wnab{{WwTqXY3`uim7F*+vUXdqk_2v-NfHG%MmaHOvGp!*0*Z&P@GAbcPY9-jGR z{)gQOqlUUrBeR zgXLYuO8v6sg^PG}59_424@9;+9CMl~=bdyR_J^gHyEhz83*IfoEP7mnEBhaNH~3v` zotI!w`O!zc{oM-eICbpdYE#+ba_$#*x9=!*)4zcUi%H4*BT8u>00p z7ooYGj#r{^rd+?ASl@_H$18YCv0a^1$^wERI z*shem$v8E-@LvM89jW|aUS=0I8?`eJH{SzQYIG~eY{i`&E&%P=$Oci zOfKrI_iTT|*p4Ff*XNo3qi+KCDfrThCyrnvdZg60Kr-UU(GcMl6LtvSK-m^(DfwaN z^0o9c>^xaI#T|_kkLVud!K0x#^NM!E@qxREyJf`)>*^cXmpn8Ndj@V4cLa9~cM_*QTnG%==OXTr zqbFDo(Lc*;P5e0VnA=;FZFZ$e%aPVd8upNK%A_45ElwIbZCPjLf^~?rgwnuM=U$Gp zv=~NrYDmymaAU0-XfS1e=7zobatZY_zWnU_S&cLB0_V)3(HjeQj@A{z&XJ>x3os5I z-R%tJ?>uj`SQp9UcRT(0HfT5d(P2-1M%^0~yDT`U}dPoX;5%MvjfR?YLpwL0pGy zfb?H<`ZDF_aqs?@AKveYDPWn~2t8oi(^Ktqvq62>+?$n~uMWJ6$c21r; z<>+5GX$qv}pNyP*KRDdH;dLRM(f?J`_0G*#;=d;v(wV-_>Hq4BQ=&IN5rfs=7ao1; zb)lPYp3PJ_$X1{by@R^FIOpyy5#1ZmnScBjtD{Gp3x0MabivPLmwW;IPvB1CqO=*q z)#2i}2E`rpWBeZ68r)jkI$Uzz43F>hZ4P!}ZytA>v@B^!(ln1(nY0XPY0@;0*O|05 zX&KE~(gsahlC-SSn8&fe9N=80>|6z2xE5Rot_zpO9Wr%msLLL*{FI4T6GzT@xIJ&u zsz^hZ@o;nI`+bO#h8*^AYcOdM(y)blxV4%z>F-ra1Gl=g*4bN>&wRhd)4^D8y;2*DvX;>RTw#xA#J`kaNRWeJ4=A zv4#4y$NtQ(?7zA`UN-hp%E z4Tt>sGG4vi=g8Z0j=a6+$QwCF-aeD3xm$_PQs|R?4KgF3!*^9VO+Br?yb@is-%eCHTpFL1o^^w@p=%4|M!bzi=CbrxCF z&;5q=V{)r9PckhivnuoJX@8sA3iNvt?Z?=A%dTF9Ebp8{zT|Bjef;9D7G;m9qMmf+ z{ftzeWTd)vAexMW}sQZ?xLPKgpaX1BR_6(5; zPN9K4#FyDK2q($+_f&f^#|PSd87@Y!f{!tJdWeO?EBL^sv#p?uG)PSZy=ltrvlvXLkp znd#q+7^I9BCw*HWoDGB@BK#2W!rH&FW(EEIr0*wx3@-UL9GdNi-@@3~vnXo=3!XzQ zB|i(C;5_JJytsFhf9~6|pMB+6n|KZR zlgK}2;#I_D3wpuCxx*VlhvELL>@ZGwK0Y)lFT{87xerlnzTD>n(dFlSUn{$$9fzR( z?Z@QF7P&d=tE6cZ#ClYVV&g zR_SWHfwW8@O?28kZ+5P6=9bdXB44iXy*2lY@ALYwleEnVH`nvk!P2hD@bxJDAWvy) zNZVhLwwAQVD$>@G_H;#BhP3A^()vl;!`ZOfh?zFBr0uLo+ez9`McPB8^;e|rB5h4Y z+AwJ=18Le@ZBES2?VGC9Sn0Ek>HYr4E*> zBTe5?2h-xDotPd>o0V&ry18`hRXbiZjt^1xh$(BwaTjR^18H^~hi7dm4PWE;>q7Wdc5=(J^m~fFv3@%|+fVt2&bWhP-bmVtiT)T_ zK4>Pbt0K)MZDB=P3u$dTvgm}Y307r z&(Gt0CQg0MqHKNEZ|^Qg4fB?7tjpIk-VX9l_UVw`GXZ`Gn^@RgpVwM;K4l)OILDkq zTcfSK!9==j@Y;LioKe@=g=Y48G;ISHo&A6-c1izic)z}51>V|V8^l+Q#eMjRaq8+DYt>z7$_i)U);1RR z>$=2K7B|K^IL=+9>)xbzK=s$VKCX)c>9!9#|IxU12J&P_4bAfFBm?QLV43tiS3a3< z@cY}B2{{9MFHzjHx%I6hK0^F46JJYw%`H1hALV=Wt&vD>#(90{fEn+6P~TrGU3oSEI27aB+#K$Rn;!2-K#1HC!htcV= zXE*I%Al$vN?0W;a@0(4W^82T;HXu9qM}${Z?#*=@#@ZRaWc+sSh@X0P8+B*4u#Yuu z?XG?@e<+nL{*pV->fe7(&J-dB-yVb4B52JK0ppkP`0QPrA^rpBXc|-YHhvm7i}%{tmg;iX!K=Fmp8R)ne_}6T?QJCQ#h=()kkv;N__M zbx*cF=mMX3mExSU&z?t|H`A&UUoUOxYpacYgfk|*pRmri zm41M5j|mUY`+8pAo+y1c;j{_wA-vp#_Y&5bx5|tVUTnhq2& z_VqZ~6}*U}lA>dSs7_*%PV*V38H3w*2Ltzqa356<#w9dc(CdRuir z&nf@t;=Y3J(8!*6M}l=@roVS$JAGZ;=2{(uv!fnIpjB`K!DDEKc5biPDVcZeiQ@E#b)tqO?aCNvit^wDG zYsR^_7F;V%=c+m**V(epm30n&HLeqv#wB?;YB7En&V94vycz$ExD@Ut+%nt>TsQ6( z+;ZGoaUaC3!F>d`7N>Leb-0DN_uy9HR^#4>y9?Kk8^CSE-GkeN+l(8;-G>{(y&uDW+=6kO;XGiHXKSdwp`_UF>$27*IN#BlbGif2lxq-NEhoBzc9c*_T=g)A*aG$~j z;l-2iC}Z(%>UTN)g+Ic#byUuN&k*BVg@!oqCvw*=&UXzB+!KmAgI+szjH5$4jUV-4 z+dBG2*w=M*pUr&#rf*UBW}BE?b3a`Y zUYF318T7;AdxE~`4O8J=iE}GBUqatS*WWhYjsLswHt#X&o6kyq*blwiMemHxUq0>i zTRd?YG@oa9LNwM-*rbocJc=1z4%u$P;;nK4m6B2Z*3jH3(mcls>@pM&9^9R30KKX-3trK zzeezE2B(I^_e(9vXIE{gpTrkZuLT?%iN}a*?p{E+j_~>Tar|lcjrjHW&G=LCgYsZ% zg*=eFtsH;7_0gg656A<~4w|k?^Hwi+I;+@wPh%{a-^x0SYs0nU>{&nvT|;A~GXPS{ zvQ@~w(GD(J&os`A>)3m?YHLA{kEhD>?PAf+vsWP>>MLlZep~v9c4KQPc&jf@oBf7( zR_m$W%#1np;E=7ab8-=_hf`@o{@B>XFs{e?Z03(piCcncMn2U>2^ z+Lk{6yxo`h;oX<89-8!hq@QTHuQZkNVfavX+Y>9GB2Ips1i7}ijUTr8L4TboD_=Oj z1)Q(P4TIZt_^+jnAy@CN+~j>XrEi2B^!Dpre_Ud^%St`cBC0zKj_CJeb!zEXGvAb} zjD;;&hZFECGDz*HUA4t`mgTnqSFi==I(*joyzbgr9MJ1)g#&ai+Ois(j0-$)P(9TV zj;b#ji)WWJKg6?q_gL0G%ht8+s9d`#qw?b81aXD6{+>wi*1(_MRcJ##wWcR}b5P&v zTA8c6t+SY~gBk8O686@0^Nq6J{f+Wn^-gfwwH~{3B%BK|zrx9lxyD34b58F8^G+*# z(FuIDeVjfvaQ8ehYb$&+J2%pDgtwr0Czkz<_KfQDNXx;z=E3pwR=x+jzx0K4Hh*t* zb*__go6o;ACpjcqC(=Vz9qFNI`u^)UW6|ntEzO*g&8LvDk@zFU2ia$LIq)QYH)+ek zqk0q?I@w|qFnY7-Onie^`?)PgL-%eunlyOKiGAI{86pB$W6N;=a^ zbBWhJl+Dj=^wTE{t z0~%k+Th-CpY15^{+VoEFQoj0bzlClOInIR@V=CRj8`BK$^Jm$!L}Iy65_y>($T^H{ zW6xcDXJPRhDm4u9Zp5r1@4LNE&7PA}AMD!@)<2G{4)#I#$D9Yo@XrMB)LDVWe^nqo zi>%Q;S@T5j8W`_Hn0Avouf3_bC46aaDB?Opk*G&Q;cDp^bs6)x{|>2WVDUd2Ev$YK z;$EQ6hFNb05}Zjrh3+o?M56fLEqn&&G?gnI)_;Fh)F@IZWkh9Y^=9D8Er0=iFI9sdkV`bS~ zeW?TAAp$iAw=xH}PHT0xmDT~v8RfhCP$>7gso8vjIj1v@+r9b9cP6@bQE&>Azu*+E zIL17B_MZIYFFJ+e*hS|)b5Gt4-;>XP*Klq#vTaLg@`IGUk38nwoG%RICqLkqowIX* zvIBluXLH^;c2C~Pt%s+m^D^P{o!Kjb9|eB=6~J$Jh45p*Z+r#tn<=Y%$FGD&b?O5) zp#-u3ogx1z?;9WQ4mNt5&ks&2Cp#8*!o&w7XUL^0#!_oTwVTafFIfVg+j>=`2jxm| zop`ytxHiCxYhQvF*SrKT_WW<+#Yx99zf)cm{NE)n3jXh!7uCjZlNUd$x42)57tQ-t zl8HUoKRub4F*32|OqsZvbyxON?Q>W29!&$X?Krw(V(R^+!KpI?GI3kgD)C{s+SxKD z6PKNqiMjhrD}g0B{n>ChH>=>!ol7MTN4fukUeJbYTQ_>@*@0{}ziBj^-qrI?C~FMPU+p%9H1m4bUV0w=a?nT300- zt{!JRWJ8v|;mL(pFc#^+SfpQKELOb4SSLtda z>;J;BSo2b25qPuhvEOIkmqCX_Hg%#Gj?VDyOC$JBn!OuozCM2o`e>?NW6VcuP1`5$ zC~Y@ob>D<3$D1%_ZO6{@D0le|atCbPt9O*X_4~Y4-`bM1zwuE;eXZv!ssD#p_;2WI zf6MQFc>6_9caCTCU*o=ueXCCSE&K+G)dRY+_aoQdT1;g18%Ugi0#7=ik87&<5bx*2 zcF>1xwzxBgTzsG<*MdGT-CpfCa=!8W#XCyRU*Y%HgHQX~Pey>%k?{ACj+-mSIM?c6 zKNQLiczJ3gOxwpKyIkIUqkIi*W4p+I=vOc_l2|E4L9d=&L#KpZmfROSYSD_AFxhXHTw#%zk{0<9w9dHqLMlP8+%O%c&A z3q0YXF&Mt`8+o-Kb-AlR7&~o#8e_uAT(JtCsN;Mz%a~PBUt^HvtU!{GN?OzH$7f)#}z!%;<>>GNr#h%e@5xyxuP*al|;a=q3hDNHN0v_+X zH2oE{_}CSZ!gUiPg$J>BxY2CB4_ip@=X-PaXXobL7yt3I7v`96pPQR|LoQd$FlRm+ zo{+nQ@Edn#^Pe4@lY1NC?f1^fNmrSousbUkSGk#PE;IP?LI!>1)ZjOZNnmH#8;3vj zhQh$-viTn8$Io`fhf3FddP3o2e_dPXV~lGDKc1HkmAw}~wyd~&aJ{EfJPe-60L|(K zPtz>PT$HSUrM z?a^_y)c64MXtE;2R2)zZfZec<{&1Uf+OCCQKUNH7$pZa~@=WU*~wd<75Z& z`aMC9o`gOA$=;Jc0$ne$`~$7TCui_a&&%hZFJ`m(2jCyQ)3>tmO#XR_v@Y&0c9A|F z|9qMJ-!=cl0{pWqAdCKnwk`kc;%?!}v+&PK_-7+`3M=_%CF9RZQM+m!{#i8+|17@X zO#b0*%+jFgzvR;7wn$-eZKN=Zdnl4Q;;G&(y}3JbKYsRpWXkdQq{4++_@^gVd;r;U zf4DYx31RVtoJ{_Bw$|ez9w761$XTC%93Hw)Z~uvIza<{(f*vk+7=tqC^`ynF z;>|PC$KxT_(C~LDgFZw*tqcnC5Wj0M#zXoYm!7lmP!BxR$^FGj9_oPyCIe&5I6Smw z93F~t&+_iTnze@dr_A~`E)T&kmWLj&JOp29?C*z%#7iFk7+&)Dw z*Rf9!wsL5IwPxK}cxW9w*4iAlT4jbg54E5h@`aiagxvXQm zB84zA;W%eWT4%JDX&sx(dgkdrtYM!1qxH+IW#Wgktz}xnw3cO9!^Cr1zwBD3HB4>T zb!=Vk<*#ELsr^=E(5o~yQ_kd{OG)d;*40n?c>IHo*(7~SJlEONU(%V_?|NN>hsw?1 zbPQd-5ns0G7YN4*%f9?P;TYi)_`<8*oLeP&rt>=q+}BO!ibJny$?Z(`7b^FSdpH}} z!+ELdvHvKxz(Ky8=#bqb?9nKtQdbGVW z$$t5|)BDvP^4@duR9U}0{Vje2bUFSZe3kt=ehU8}ei!~D_?#O#hdD<*fWM;3f6w}H z!m^7M@cU8P%{tDQhUCrG8`3Ap9Ej#B^w7WBno;&~2T&wne>?`PF z{S}Nm_JZR63~zg(6RZF1>z)ZYcNAOT8P6`T;l*}=!8q@{2k0BL3$!d4+qaCJC2%jJ zSkHKS_5$ule0Q=vqx8o^V>HOyb>E$_q+rK@-x>AxfchPfR?fd#&3<3+S%$G+NC&iM z)1q5DR1ytEJH6TD(ZSrq{JKX6zOjP_BhW&97A=N*;5Dz$_j!GuW&8Yr7x#H1cx-%y zebzU(w$IdP+lYG3;kOLupfPb-xXzbn6zR(dzA zavp!{PVQYnqn(UxB!gb;UY2u`*ag#~oBz8(YC|$jcf8IV+q+9jS6eL${IX1w+V6OD zy4xF1YUqR#kFn9k{H%j_tMGviGO0#eJ+wwn$|Ic$z|29A@#dn~* zzxW@ozPAv3i$9di=6}f;!Jke4!JM=3XE1it8I%9u+ZCnp20{55cwF;Rb4Gh!TSI5GRb%ABFB!vNTdWfi?tn8*{P*+iJ%eMB>E6A{U%vV@kN+$0 z1oL~>wH?{v8E zquW=Cj`F)n$t8tvd{^%^=*@Ax*`PPaHyxAAvGZr1k^A=dR<`LaUDua`qNUnhOuMnP zvBSBkg5E}mzT+<1*Y}USgUR@z5B*Dv!Ox+L^rLN#?jU9Jtm{7nWr7QV+Q?Uu@)#9rrRxPeJ zcYWx?yMQHHx!gzkir0r!;T@!1c#(MJdQS$}HR{`psp_r)p4T?@Z=tN4mVCHHHb~yF z8Y+2p(Ti<;mDO+RB3t;je*Aom^WsaVdonW0*uL{RyHLuu;VE;YM$A1Ao z={F4Zc4Q1Um2f?-0XGeIpW*Yk{muklJ7az`*CbD3?wRt$b$nS8V@?El$^{4BWcSjb zL0Poc-7Ck*^|2QiSWRCR2G+7^pwUI%xVEX?!BZy+todKgX2^2+J1q0M&_ z)2o`@=~a>I`yKe9s>|)GvhpR)J*GJG%H9pOy4?Sl`udvxMqg8}ps$^08P|BlxVD>d zjaQ88GR87)#x+G)dnh}uZ(>|Km~W}TxGrYgRHlV=-9@+Kbpz=KX5Pj(Ik&OyzcZI` zfy4SQImO-8+ID2h$gJD)`@^^8L%i9$mpiH>QSPO3Pp-B8d$hT<_#of3kRIB@UElpv zfWuq8;F1ryw~vmrEcxnQ?lJEsFC1T=({G_f61R`C27C)wR(aK-2;yW`_oXthbof_@S$XXJA5pgKfLIzL7iG}kWp>)airx@_CrJHannot z2#?33x)ZBA?3H|~JF&m(IoTN)qslp{yyQ51s(sbVnUkx>;ZwbTt9!tZuezPb_-MfHoVM({03g3u7BZQTwH9`4|dAT*r-C6ix zfOXE+k&Kqi3h~y0=%X?XW4v;v?sIW~239U$C;49?3 z>z=90Nne8o-a3?uv!4vm+3Isv&g$J_>1uW?TmPGU%ealLC0bX;){<1NkF{lB9W)wS zOVIbUzS^~9rOCV6@-6w?XMfRJlCw{;crw$1U^(IEed&n93ChQB?Y=C_5*ZO9wOtmve3eG%RpXlOY7U5S%U z6@Crwt>CV5!&ma%Aw1#C?9aV5bzA8GeDT&a-v*%{=CJ#=&gT7d`1$kP7uG$0@^gNq%oJr-bZUT zY4&}zxQWl9FKzHm)Wq%kXeVa*aP9kO&zm?r<-L!l-xXK8+N*1SgdR3<*rZJ+4Lzpz zpovF_OJ^K0ab$w`KH4r5uOVOdfvkyF5oZrvJ7nU}IU*S&TL7|W-1pIv%)3?L9VN@l z;!TY~CC#<={C8=72wO@e%|}dHkme7WG)wdCCT?jyXyTUU{U&Z{zShJo%~zXvkmf5) znx%Ql#4XJ`P2AGF!^ADk+f3Zj+%@r+L-P~p?V@`n&1J{Ycxz6`cB%Pe=Z^ZKbjc;9 zzcpp_SmqUV&X`v!r|)cRU3jF)&MnQKpdQg-^a#zRVWUTA9__YzMEcC%y$;Hx-}IgG zCMW9Kjm*7Deg7w$Q3Jn|qTj?u-qcD4SLvH$;#uPKVc-OBsVI)E&U@GHdCn`PgFVcd z;AfFzIg^jhSgUUYR90usUGV-PllO1r{WG8E+kC}s_;Zx~B4x9t>>D{VWIhc<3?4bk zem_uGaa(sYbtP9<8Jsp!7g;+{jT{q>1LWUIewWE-?@?QYZmPUK^6n&0@5<dqJIfo;ochc>I@kN9nqHyo#J()8wsem~Ot?GSLC6LS8=yAy^!BHS+_?%_)x z#^CVV8cNgKAr=Pb&K^BP$4=HG*=Fo-X8L>Bt!L=Qw@fH_e$heji2xeb`6%R@yr+nJeCm z@8D|>&-fOjX?VWJ{|)7}z_)w9y?j&l`NVMEN%G!3ZS8UOZ7<)?(vQ7-FSv*N5%0S} z|J%Z(sjF{bMdw!HHOxKL*O`RULj2xq7(1WR3hXx++c6xXSs#ZNSO+Z*4tKcs@-6fT z-!luY?$HlTU0>-`-9K|-wJZN*Zrmo1tW3@Fiwcf7C zM;RZ@&tLr~a~2!d`+n*BQD~+3{MpfDCA?UII}^z5!lFU@8=9pEj- zwi~B^s;fHsO=Nv`(K(-{)k{Px*F--&*tNv)<5Wy+anSV9E8DmtC7R#t)k{16@6A{CN%Uv_ z7uBbgIPScAeXryd(TzU$MH4%=I-xE1Ym9rU{C*xcy0XSu=fVziD+JGmd$Q;WLY@5^18L!@M z&K1=jzl&9xVA{~RmFm&ua$6?j-3@L9Z}9=YyN>U_%VA}rXw!fUuzx7PPCseli_NH^i9onD5Y}5-woIc5 z3w|18_*Ez82Hbmb>>-@L$EjUw>ltFaUH0d^Xn;!<*E5%NE|<~Tnas}1B(t-FXLM0) zj`obs$bzO_=&MoJr>$Th{%ZOBfPF-_XLt1S4ej4ex^JWD%}IwJOx>vQD(^~Q>q|Uw zRQFmghyR+LCE=<>#u-d3GxOo*Jh~g>nk~Mc{F|I*_2LWULAfe%_^3--gt+QQxxb(` zPw+dhlG9b#*sX4(-#2T+9*I23Yuw4ttKRH3@v+~B>w($8e!C5vMAy2|j?$H+eTX)0 zrCrvqTE%yzu~UL`W!q}^a^aP}D<|F*4z_)@4L_DciJzC$PiWN?;+@2m2LG`48;lzY zu94riKR>1KRn&{5JbcUQpL3SB*~^w~o9esz(B=C5X{CMJZ>5XB+Sn&(&!)KO`8Isb z1?gW=@VDp6gCNV#iaC+lj`JLR6vmHGLHu;W+_lPZ$J$8>$EEpjntdJei|^TMFJ)d# z<+sM)LwGXb6_it%-zQGL212zo=Kbueg`fSc@}~{_h}mbe zzZir68R~u;_&ZHq-Fse&eX|pILniGO(u7}?ssBgBz2AfYzfVyAI_j@BWqZhDFMYMe ze*^j8Q`WdN!mIMHG5)p2&yat%JdNEWGsH_y`AduZZ#o`!H+V8oa2?j;826a;JF!uP z9e(4LuAb`#-+KvfLQ^MlWpCbz_T_6R7mGiM&i!PmZ-HzQp@QCm zjBpozf?(8V@_KJ2Lfy#x_4(eJeRSoO{XY?<~swovEYyO|ywV$oTGdAI~2)W%Qf9drcYr z&YQ}q?%$HOhq!D#!<64mTyOg+Prs$6d8+t5iTWzSzXsTh}H{m_1W%hY7Q#X_8Fze&>{W)5wE223(V` zb2#*na)XIWpR6-s$~F-%*Cp9|;!niKwpOmiPvFP!opiRCd;gBo6((MT+(V|7YfRoD z@-8DDHSzt#XA{?)*u&bZd9iE$j?%8FJ4z4TzN56&343?i^u1&#ne5#fjpeK!r8@UH z5#s#Lij(Yp!-q4)`<&|B8sNmz@A72*U9?|Axs?XC=Hm(zmLAbRf)E&+Ff(j((R{eTJ7jd5vyT4kP!z zg#7JxeR{!5<>hhdSxfb9e64IsV>Z6z7TH3OzyFwE{ahg3X(F_g{?N+ZHS{Zw=8~l+ z{_-=&e!-qazV4jem9(X6{SEnIB}r`mN7&a;kGX?wvU2^Z6;GU%%YBn7aHp zinADZ3vMNO-N5R?b>P}?E&M(x-;Fv4aF5{j;l73Y4lbyV>b<4I(D(2Z+)~a+ozvfn zO0RI74W)_v{`)HE=RlJh^uanObL=7Nw4(bb+3RZ@bguYT=%>9>BmBB8p?&Hn;H9k2 z>O8(ynWd(T_7&GJ^2_Kqbwj|la5_zyYk+gXb*JI5Umh#-8dK(4%6!PcQCpEfnYk*1 zjYwm-jq~j;x4(4#tNRKm{0pw=D|~2CUtu|G>I%*$yGhepOZ`YxcW$w_x#@`|-LJKH zF#=7(LGY9x%oFcyL$`bP4EjsoygJO!DD>-3?3mV^$V}tTinp&)9_)ZUT>F46r4R95 zyV7)DU-1hj`SGNQUvKggCcX_DfXcf`l{eqvgO~PR;$N#jqEmYJ{iR3h58c68$M~-_ zJYe@ds{{ucsQ=#H3YspbFMc2Fcm6|Tc&bf{qrw(Hg)MGlcvax1eUk7IF5<(n^MB!x z3cTloEVO&8Gt%jw_Sw(Shi$<5@4z??jE4-2{?;nBn zX4c7v&{=fWwVOEW*1&e@Jj5R)&bm5ab>pqXwXRAxRDL7+>;HhSdQACy$+x=g6!Hco z4^5uxR#Ep?rtT+*&qVjHq1-0QwVQHEw=f(7e-`CFLpq{vAZ~EoLL5>K=ywc-`^Sl& z@YeLD`Jck~#LLf{_&@;W56Rm|-VyKIeQ6&2&w%rn#P^$eIm)i5?64`@D>&v{kTbxh z40+og)o-6K&F>^{CiqO@_qY|OPu|)5I#c%}#7F0CxpGb5{O`l0p`Us9e+_sa0$$3L zM@RDT>NL2lBQ70Gbl*o=;FbOR221lFBhTXXFnN?M>-~Gt<@4l;ZuSgPv=H4+ppOXF zTGcgh>4R6-zhkg8Pv2{wGUcFu)1AP5%*2JC#`F7u@tn;#F)mGiM!APfIqHnThbFq} z$@fB9BbOB!hg$J(KWQOsIqWHzrQEY19%j9hJW%=Nlz#{Q3j8_vkKr%FPvaxs%PaBW z+wv;>H{q|wUxMF*uXf%`JNk`xwY8e`4angdXUnk~XTz~SB)*1ni}2UtL#y&S{A=(t z_^-w9$LAaO@+SO?h`%t8vrl~4{W!NQA1Cf$m%EAZ5NUbJ>U>6Rx6xeoiFQMSbHD&dg56R4tr1o51BCKe_<;SUQf|(jqS)t$BsI6m-(pou*-ve9-O{BZ-G4P=y_E&#D zx0`w+q<;y&dj3C_zJ|Zil%wBXInk7Lro7*zGkD&Z3ZGHZkXPk{`0!l$kcl5QWy#|^ z4(8(N_*mPXT!RP13(|$`ou=wpyvsS$ajIPO9$biU7*~U<#>H?E%7j%8cQG!8n~rP5 zHRCS9xwzT57F>uMMH7&5iS|46-wl&gTEbd+P}~%^SQFuT4Tr|1Mv) z9(BySqor}5fC`jy^wBWX|=fYWb<#dxMXq>#-KKt_Rp*|Z*<>Ec+>{)fY!{}Y+i3L>pcDgs-H=5jxxOp zJgPJv7MB`u@%owpFX{-U_9*t77mJ%+V;s%^wLYPc(d1BRw(Tcr=*5gHIuGqef$OdF z+-aMf%GI;JUvITY$*$2( zNQ$xhqH*+aM7L}=_)HXzi4^NBcL;%7V{o2I8O@Ur(#x2c>I#SE+A|wQFpT(ox|R+9wSg9rtOT(L1}%@I@oG z&W=<+XTa!+vf(fngoAkLG!CcrmY^=SG3+=aFrIW4(M9yB9p28-qNLCkC{H{+mEq+F}^h2r0*~UUu(?_>SZabI*h%yuhw1@ zJvy(mkIr;|X)&$~m%?@9mg837RHq7^Q)fRz#6xC%aH-$zN}oJ!dtYqYknDgbwXTfm zs4bjFx4C>v>)uszIsa_~RsxvfwSPgr@jG)K-K3|9ZhwK3-X_|O@j88*mgI>b`m-^~ zSO8!6H753WW7Hn62cG8sQk{iDU-o{;0qn+2=wLQu+=p;AcPjs9Isz|?< zI67!~5@GNksK$pJb1%Y&Uvx}TKA$lBGT>yh#reb^>)BCyEW=)&@FBv72p>u_F63MJ z(U{y@qK$Ga)nDkyb`~@)>O(C)_ea>rXNxJ_^T_)4Mddk3eP`31*F4hu!M0AF^8W)6m_#Z^4wOx1?-3zlr0e*D>ecg*}CRus7dC1G^q-?F;gzbbaBY^(vO) z9xMB1%{}jI;Jdmj_GU~@5{;4opHy}UUXLJ>A0a6vh&sC z2kjh<$S~avV}0YhpMd>?H0d3>TPt3*cgAE-(Vkgr75374?xCCkPh|zqmY2NNZx*1Z zHR+CGBY1gyLOOiVRL8vOBwfF?EMC-FC%jcg@i08$mxniq{{kCrgf=Wa-FHVbGjU<$ zczWkexOfZrcV|xI~I)Uw==$vhE)MTXmz9xzCh8$?qX5?ecNjV$OTzpQa4^d=LH+ zQ~u9Q-1d9%S^6EX=(opb@S{E7mJGGu+6n))2ENWj6<=-QLB39mGftK5v;@XUZB-d~ z!dGiz^I7n%94Cvf9V6k(*m>h6{0?J368*4UdH5bQ@wZW~lK!X6*zKeY>mcit&ok%6 z{XNag;hUGjr^~cIMlWb>b(Ejbrf}A8J__ftGRU~^!;6*ks*)DWsSxrZ{B6pz7dfMU zA$ao}rhodaNAczn)80YiYENk%pVQtys6FJw*m(xDsBG_H%@1UfY}KOw5b&CT5p!qr zjhy7&=I2%ed!K1%4f(@zmK~pYi$_4xX>2dI>tKi*F8hj)p^$k-G@FeG0 zpE+CDTzcNKQQeepp`5<+)|*XUf7z3<-qoH#UzgwC5iiDv&XA+%$DT~E@_=;{8u;xX zV{5IxAwIOazwTXVTzh8ubhhUe(Ntz^?B8kn-et;wvxoa^gS&pmQRj!O!!N>p+5Zc; z@8_IPJn~)kOzO)n6K5Y*yuskE?`~8^ceGVT-`!O5)g17zcK=#`8 zs?oI9Zr}&`M0(;GN^xC?RGSjx^-gOh!$ zN^x9>cobKKlYL8eF4?hW;?Bp(o;3?68`niR&-O*VCc?6RO(1+@>J6{2VlUH)UyUEa zT|(ZaxH{ZfXyK|{#*ElRrBnwSD&eOd1HiZyvx25 zflN~S^B9}EI0MuCyMpj&l5b#G!(|sx+63Nx2($LKF~1dWhCj8JX-B`>y6DD&(jQK2 z&d-QD1^s5rV!qAQZv%DCzpd2D9q$|QFT=k9|5E(x@%5W+;j8$~<9Uy=rcdNImiV60 zc}FhXyuP5{aXi5HulgOw{rLJF$9?$v9mf%T{T7Pw2;x`;?>XYNfSt3B&S@+x4Xgh3 zOd1XWLv}>b@Wu)nPUFoY(eU+Wq2cQ*XsG@B>kSRr&++~IY5L8CUZPcM9^VN=w*=uX z!dd7nI&Dwr40ovXCib+Vqki{t6KM+TH!nGh^ul`xuQOr&=H(g_7QI%RaENgd-7IbO z8*-wR;A?zD;}A4fS_e2-JR429v(fP}Dtrfb8232t2<}N-kiNAQ^j#RBZ?b~Ea}0ey zc^3M9vVy*%=_d_+IS(jzL*Jy~&sos78~g|1JJB>ncoX4H`rJi$BVqCHV#57|w?gMm z!WqIz{B`&X@h#2ld*P~YX(qm;yFXk*S+%Y4Tn--#2mKD;t%UU(e7E51w|Q>H*KhEt z&e>=hq}}mbvCUk7d;JdJZ#A|Q@h0zSqPKA;w)Fqd_C8=zR_ERSGyh;2RvFmEtjh`m zthy@dpes^>VNg^O$eTeyQ8&qG&}{NzvqoZQO51^5kZiDBVO3&i7!%T1Lz)e4>2|yC zb`eZ$YFZRbtfhATIFW4A#$Rhw-!yOdeZJ>8XL%S`Yp>t?o9mkE{6Eiq?sK2}+~+>$ z+~+9i>jP;~;;tdB7Pp_Ym4UPraSKS}eS^ww(gcTS9o=LFSu(zu_*@`J z1M!QAN3JyaGlBTk#LFhA>RA|wUrRi4VSE|!$w0hp2u~wk@Ye+5(OFh%iJ#1zagOcJ zY*PE$Hf&Ld8zcCQMjCdHZ!9z9>znpjmkBMI%h+j$k2^*gZ#LLF^ zkBC>FGz8+Ch(BuMy+C|3@jtNfC%NzE;7k&K#Ks>D#OoZ#F!4L6f567am>c@mNLQ07 zuj35ELDDtucL&O~6W>RCXok<*+eqISNMBF-lcXy?8;I{9{%gcH6TdtVzk&EY#7n21 z3dC$@IUuFC)XhOq%q}diUoj z``wZUwa=mO#9H)})?bUei8525E9KWaQ~SuTyzQ>q6_PGnl`8npTPwglzU{jtv{)F}K#$TWAtPG`dl@Y5;)p|vG z^VaM3RyLxyl^!xopGl6{2%Unhh} z%N?Pd_R0J?+&^C@I#gKS(RcGI0}ZH+sj9Rto0cMNBXx;ZRaUT@@yEQ<%D%?Js&XrB zIo;b%Q%+;7x}5gdR#%m)x8=AuTB)Jj+HuO6vrSdyPM}j(8+4!X=+eEF>^SAJd@o&9 zZl5ierrd7INlvSVa~|c)SPbB7y)Czla#_mh4p()#<&;}l^}SYG4jWCC7RtTTdj(BZ z<$i_iqW0;2$s5ey$#K4y=WJZZEFCr3a+8rwH&9k%MSi)+tmeFzWYq)xwGoA@~gmDc?0@%<0V*5`+RPkxG{FbmTOf%P|l5)U^(qQ zyK&;m?Xcw*s~;%m#!Il=YRb8B;>xYI<<_bnD5trqx*yCPs;d5LvgNXrOHj^@m*Dr( ze9w&&_r2FFUC*Q3%h0tOFTrv;=kLaeE2lHJqL<~A%TvycmteV-lyl?6mD71!mBap5 zrJZtayadZNQO=DMS8lN_m!w>Za&Ei?%gMg68z-(@)Rt?Z+*{DK8!y3f>nP{Oi7WTK zrR#ReY0c=yOR(H}%DHjk%JtfE9hB4FuNyDHa3=g^e-{#Us!uL(XVE1LDwPpT3O39S-Ds1@U@gr+Awyq%4=C?EKJ=| z>Cfz~Ouba=oE4R;2}`cerXQ)?On3p|y(_y)+!-w0MA)rkv<^z8W?;W+hFJ%N7w{eu z>us%rbhbrnpk`dHfs)j*n6k5Q-;XO8^$oZFnR=eT{%N7ES*a-JJw8zgB|6Pn`XJ2G zyTZN9I^3PXaX5845#0yYS%Zn*PR@^Y!UKJM2k$%?-j%SpZ=jDoc$u@~Y4S-PNbRU3 z=&OF4-|@P6#(KqSagx5uv z6(XV$*%6C`a>!>seQ7NwSl+FCeW1MdvQ@s`me+dioys@c?>7X>tL%2#p*|u0ZDk!^ zb^m(@bl#KbGU@xNw=a1=Y2Rf3waum#_|~Mz>APDO^DURR zoxIz4Ypd1fZHrpFFBYyDgntnz+eFxvy^XRfqTFG-#)siG(wGLvVB8(Z`#;D#K;Gjv z@2>-CHHk4^e<1vCgbloxvVSexxe3|T<(!nYvtz$g_tS~~c|8X!->!R&xCneK8269Fow#Ff zWr+1?FLH&_@cVl^z^phoe?@5DF>t9o33#Z!#hHwF*si&ytL=F|cfCLQOnFJ>*>WPW zi#0cAK3EfmFFDf=qTm_f+u=)2<5O{eK^%6QDyj8dBY0~F?iM1NU>g7svM1 z)xJ(!H~Yju#f-#7h7y5u62pG*0lan|CjH2al5JW}4y9n^e6XRA6( zOGchYp4wcf8QH_Vp`DdZ)tl}q)TWQ8n6IzY8ENK-#-8VRSF&!l|F*iV`+Vqw45K}3 zc_TsJ=Dj(6+u;1ejMe|5z5i#z`0f1<#aFdA%(;#C+TPbGAKXK6{k}ig@0|4%Zcd07 zGR9xA?#tHw5w2uKCns)_?H0x!wt1fZ+X?K^2$$C!G3RO8EdN~a4*YY0>rcKZ{;9q7 z1p)r~7kq2wCnZNc%J{~XG(7VlJX^McT$p(Sp2}GoTQ0)*?nl;ZL&o#4t);X+WW75G zE6;a~?6}3qi2KQRd;#-DYD*zX-UxEzlf;D=`04xb57>027Za?lp+yl7%xY{c^fU7;C zK3we)4PWi=5e?yLk7yA0p!SMz`*9EA9>DF#m2K4nxU#F-hdYEjynyn!L%0LDgSev0 zJ8j>7ysB?wfxcyK9}Lp3CPL8K9E(=tLkos(y_@C=;x(; zw}tWT*LkLmZptsnaklMC~y3nc-c);8@1kYZTuUux+Mhh#ul0d(tA2praWBO0S7$#}yyLI=?v9)HRwe<{lkn9D`%~KY5nOxHKK>Qf zT25;)jWO-rMc9YZI211T*>Y>ir?A}d@@uRr-L+l*Z}EM>@yAu||45+yUsL-7JWG77 z+LoK4YfES5%n^N}`gJZ|?SFv!9o@S#Px|hch@VW`MI*wC=x})1isH)j3Il6r6JbaNR`xuHRPkeWeMmyNPcEF5zk|@s3VDUIkAq0MFWS;2D=r zEIgu-F?iU67oM&come^w(#cZ3yAEAW7?}3c-%ZGwvWx2Ak`74plOj%Skj_VRAzP>l zOV^`$J7L33@TTG0*&n`uGt9G}Devd39cMWzv%CoQ8sP23JxN?MadXbY7MP9OM_dbW z5ieVCabfOU=ZV*M1jnqDSDJHPXURi1pfm^1c=3Wu`&Hwm3HNU7hG@U~&1KNzkGTY^ZKf?))>;ShU|J^A^jO%KwrWidMT^ERz8{$Kc1RZ znFL=+p|et7>>=%Bpq^IMbCFN`()BvMk>+x}JuSZD>K5;r1n=2Hn(9(nryB~L>-Tjp za7*@x@$Jm~S?Gaxoz64E&!fI|^AUYm{vz#G|30Yx4aiQH2JoI62k%Yqf_LfI#>SWB zLu;wujW4Hf(|12bJZHzuc$ePIjjK-x9!qccT6+6f6^zjUjJN(@fKg|##)C1fdL7U}qf^n=5ERU0})6E5`0PWZC-Q0E13-qb;E6brR(b!5{=`Izguw3cNQ^YB( ze68Tb(XGyHtgNEjR^l?mnX^T9oap?E&fv6xzr`6Jhx*nSJ=?P$`j+8QRp(|jXE}WS z9Xc!F^T)VB`u&{%?v6&@&Nn#ASqiRsgY&4)S&re(((hB$?{HTez}=q{{{iS%Fll~u z^4!x^@Z1)FXa6|xyyyAK!n2+F9jylEt4D}m0z8g~yYch~Rq$LDfQP!?CTG0o@oo9) zJpp)vP&*|r z{0rgW80`(T=k>6^emUJw*d3xyCx=w8+pB4TInU_ABmnxOi2n=U~ zYmE!7kNabH6t_3bsthh-{YkiQ@`~cV1hOz;t)oS!Pa+c!5!T(!gScA9f0MO(|H4_^ zk=s=nnsm4r{vNX1q36qabpQL3on~z>*z+SkfBTNb$+xR;aB~0$e*_MKx-ZH5mp*C;$(4$KKXo|6Tle)IT16{tx>I=T+fn z_(Q&~hW(c_XlPFWrk{u24%2(ak)`c_p#Jf2^fK|9V?^5v)5(gP4__p{nr`R43(uYh z?{GZKt)DLp@JQ)qgnRL}zo72^wpo>P)i;czcJ#-xeeUFS$wDU<&tkoH6Fj8Q`5o>( zif=4~pRPksu$c7KjJ;O=8U86d4waTBkCUmiN31oP)^u*aS7Rk*VfnIYW1;*Q?y_rU zRaRa)tI`YqF+7kl`!Mls#0xjrbE;s^@r*vYGSEldBO4UmYyKAAREPNPo_lARyLjXA zqm9f3j`s$2FXFwjsp0xUIK#f{sPbP29>jaZkEH+H&);9`_~+3jE7l`Fe+$0*6#qZw zAC#q?d~rMVsou3!ZTj`UogSO3Xj9tuuu+L+jN#(M?TV}iQsuICO{%*z*pZBhJ^ zs&7;R-&h#Hn{f8Lz6bs`vHo)NmT))ivNL5)hqr0iRrLGI*EMS$GHvE*TH~(iXf@8h z1b3|+zt9{E z?#9}~xP|T_O8Yr&3eNqH1ir%ogmLMv_Y-@^=&pL5p9|2P*7-sFiSB}H`=f-FzZ!>6 zjYD_M(4BB9+7mvt7FXSFT*yB}eYB~pJ7B>!Wdm(`I?yJSar64fU8mbL_0luxA=oC# zT-9xwYWENIZSIb}=Qc@3`>)#cpl#FEsy1B`XcIP?20hMji5_xQ^ibVD>hsT9dIF!kcU>DStIB{P8%n5X77K(4KK^F5EQr{N8kb91G>#eIj z2*oF?%lQKnuC*?@EfYosXI#{B#)Wqq7hRWe&3Pi~(K%yhJ4brD>h}*c79vwOV*^2Q ztM0t6D)Nm*+T+&w2V|g&>&YV>m2|ER=y#;s3wd_|VrL?F_bS4-+#M`;zJ~o*baUt+ zsSB;)mHG~O7S@b#KFqtHIWm8x?3RVRT&JlwaTlQPijlXDI1JaFY0q45E@>`lVb0T7 zyBb@W1Kj1|Y*bnIe){?Ao{zZ)r8`jk^)`)ke+Ti)rg@HV3vy=P9M%i7DMS1L{;JQt zFEG)IcxR2|i|$;NY#_lGWiLcF#Qif2=tyM4BZ3~W2|CkTmQB>Fuxu7ISlV-M0Zu?b zQ=M=8%r+y~fP zIu#u$pK6ViBB@-lEfuazPP|Z=yO{H5d}9i>koE3JB(=GCTk2ZuK;KgQ5$EdF2m8R2 zX`hEKN;K;g%A#5Nz1(tiMd^+2{Nc$--b8~hcNa}`q(10{25U3Ees-ZdPlCSejPoSa zqqD;LhUPc<4esrG1g5S$xX)q}B;Uxr0Bm7(K$|(vAW%017_Uh@Tv=i90(=o{v(!YM z$Z>axcbw=iok#FeQ;K?fLpF%Q+-+uD##8LkOP@>~uY{AV-;$iC<1LPyS65OU@CxiH z`FUGU=Z#0l$&0-+Y}8FN?^L1Rsl<^@6N%lAV7sL!N*{-lpDu*Z6Z3Xqkpa0Vbjh`) zDBs(id=y#)4(=Q4ueV*JiATx5xll{G_UfzQVl0+re?~ThsK4YTw;H%7fWJN9LF4l; zPn|-oRxtVE))ih|9|?|dMtc+?-bTAKr~V3gpU6cLTXV8M!rg6f$6iO0eYwOIbIu`( z&QS7lERiK{b3t;m`pxy3<0ZA~|D=!a=m__~k)L#K0^S#|C0r}p`y;Z4wksAL>73pS zuL*;9oni90pHk~>{;A_98|`_?Xc|5Qyt0eCk#mb1vt5kI(|xKpA*r8Xuts;Q2J1~f zuVK7;@eOJVc-mn5S9lWKx^JugranV+9rjz|A&!PaS?CQqYhVo`-pV`>*E_!FG4|oP z=4^@VG@ZvdIghcgdUu1TFnmG0KjipB7W)q4b!$AS{_m^)jE}2@;4LD!;CnhJ?{ML4d|`v? z2Qf1Srk7NgXifN$o#ARctse(ZYQNwTEOWt?=4H3%odai*)z>8-Ed}+%G1?$F*U|r` ze8N9JtT}d_#orYC>I3X#mBBlAvRHrdtvj*FrZY)8ySxd1)Z$U;Ir?M=aU)YaXw~Ok z4!?%S*f$GgbJ*awgT4;nR^Mr$FV&tE_$N}Q2Ryq?8}sEGsMEFgTGB34vpuZkR)`{gI~rp(~E_j>_c9kmgAIgSfg! zC7gKPT5ymr4kh+tA1Ys`JM1c7UC(92DLw*Dv?riCgY^kln-bXkrY^nJ+hXTIuY-A* zG}(%5=-6t`;eb!(&My4$>kjU#@UJ19z^&!q%3t3yI5IF6%1)lq`0=ugdvF`g$QoxtT}hbZ*0FP$&`5ot|V?lNUQ9Hhz-LvJ62B=SCEEn2!(#>6tp4;fJAU&_Q^xXUo z^xRxU&(P4=+G#od2G06ve!|9qp=Z8ZJ|P;;>K&gM+_})3Ut5{K?YMxhIzql2v)srr zk5!h_&WM#`q|Za%sN@0eliY{>@NCTyxnrttFl z;v8UU&-iK5*L=>V$&Li)JV)2({4`)H{-!IJVNI`cfjU3w(!k~Ul$BiE#(6X0l7YfG zUiQL(x1Dw_^Cp{iXw2%o{;w$;9JB5{o-BDIp%G--Gpa%#ApqwFPYUQ^7W0igHt!zN+_~z%BTehyE}M1F3+C;eSTjX7neuwys0ewF|jvqD_B{ z@Ws}@pS+Kd_lxx3pWuo|Uyfh2_7r*+&0*@FZqi1$mkiJJ=Na%81K+<*-YD;YU=QEy zsU!*SvHpL@FFl|?Kfu4l$8x9V-#-B6AWz6xo=|Q3<{14Rh0e5hc`>QG&ur>uCwZM1J?R&R4pX6$qo zl-^;}ZX#_~B3ja$LQ(XJ6Oakjwt3KVTg*SBqwm8<%3lJmi!Dz78UHfjl=Xr7Dg+J4 zuQ71}<+=Co&L@9sI~_a1FvdB)ZvZEi zxLOH*co{+GR!p3D&_v=h#0T3W*{Iq^(f=0RP>G8hvqJ>So zH&{R84IA}^y1%AQjhjrCGX>PE??f3pwH^NW3AWw!W%am;jWce*Z5$n-vD+mbk()=g z26k^O3dictmuZ9Eq}JW84E#LeZ7zgae^Bott+8~EN_SN(pb%;(Rm$@~C>U!JwS6%dfGys=ycmeegU)~Q-apQP!4(Fri zJX;*X9l~|%f9Y4iiQXPG-wuxb;b|`x2d8nidd`dd*|Ua5s@qo$6Ke_6KJg#H^*vya zU2EVnbG_z#=~l*M=5?I=TgO#t{@3si6Rueo%}vLR?*RclSC`G=kHSu_GM42~UPSaLk z&frgHu*rekHRK&FMn}F*n6yV zLSei*U0u9GZR8f$ZnIu>cSp5W$@=<`96TY~0iQ`@na6yh*mD zG=+YhGl%)^ihMB%UzeUxwhU$CKgO719jJ9}Q9Syast>p6D7rmxuJ1a!+MVQ^&(dWCUC~t#zmn@&12Zq2o-^T@jk~!^zI&?dg1=CPA<9@t zQ@8Hm%FaY9YdrBA-OU1T*w*Zv-ZYyyuXB3zCi5-k(k;_#$y+mZ@AS`Q7_)@+CYtQB z(;W1jJ1e}it94l;dWO-3;OpU7s1QnRDJ=6;hc9a`hkt79L=8^26eKS!qhADnjB@*^ zZy!1W`&Juo$!v*5GWpPsH1}~ylio<7ZjXK=_Mbl3|#%AqS~K9 zR%-LO2R3(ZK{g;GtXrF*$ItTq+$?nD_v6mQy$`noeKfY>&3r0-y>t!wmhA8+*zYm- ztTXTs?7%o$b^M{mt2v`T*8{8iGnC~{MMnA@-i2jefxa82FUpr?7vbXH$g^(5UI=x| zKJ*T7Bpe7&x|fVh7015O*!}eeV2Ob%$q0+_d&trnFVtI>D_Hb9nmf~GMF+4rof3J? z9qh#k!L+IjJ-woDDqV5aXA^?op9h?x=jau}i{3l-^)a=$q9fhMZm{skb+|EfZud1- zL+35n+zGBDkps;d&Aos5f1sZU;%Vg5x-um?5#8cv?bf)Av<>vR=u5D>y;x_;Qj~A%h^#NmkOwaiv^0|27@W+HVz|+(p^Aeq<7g*=0 z-(EoO5NsJ6247!ij(z&CsdwRA<}U07_0NA1z4y)ZV?JWW$lN&vYz34$;G6CaziE@Z zYYPptXHyExR&rAJ0i}1&ha%V|r7aQU(njg%0QR5!w{bFNEndSsAsJy18-h-D8H%hh zb{DE;g|7)Wv}G}4BnqE!ZIvvyF?9^rdg*B{vPlO zF16_q`JsK}kip+F{?+Dg{BmGS178Dlvonz_?5y|it}l)FAbW@@a z$)#?uFPh=LNhX?e{KUzgZtq7nLA_KRLl>K$@YfJ~lnBz$WI}C+CVjUCS2W3YrI$K` z7QNJFzDxgE{^j<9+UN$Nc#NnIn|CkvaYT zQl#UXz;;u4eQt8)vW^v%ENirn14AG3lJ=0q2Y@GjK=cMJ-wn*7;q^Jzu+Z}WcPG{F z_s|~=xVt8XnCrB!x3%!y#3RK6BS(w9OPTh$A z{d{LPe13{|JG7eLrM-esPrg%SCynH%hDN>!S+tesjjSjwPCOiAZ=fzdeX}>=(2hc6 z>Y?(&L@o3#9rAs;XKm_g9qC0*V1JFe!0n=i1%GZi+sjP#M%JgO=c?L~&9HHAkvD?O zSfE`~f4`vfwev{ml z)o5Qr_+C{WxL`$yMvviNG$WihK#S|)hdxh&HYg*yb#yt=&G~lUcr7%tQnuKj5vL<% z?L0PjeI0*%KD?88tR=E{`uEh&j63at7@h!4NoR8p`GRY^jUE0TR;Fq_EV=1k(Kq}j z1OM^i%#^=FTr0Ax_~Omfwb7FOzpHTW`r0X5-#n7a9X84NE!a(|1 zaWHqR__!A?)WAo=sRs)Ol8-@OHF{CvB+f8-ePZRJlBe*k(`9?j!$K8)E!Rl;7q|yMcVKK z$+0!yEh9hcsR-@Rc>#?jC!^DEW^T|so*R>{-!i;8;0=nWZ3G8uYmLPNcpjA99_cd| z@x9%QS@TYIXy@y~(^b@`GN*ByFW&|Yh*#Z;dsgbSPHdy6K6(^+^GuxuFukpRG}dpR zd&(DM(TOjbr7QQJu zzCdkAp57}RPp`o^Y229db#|h&pll#~1K+4{t$Wy{8yeKUspw0*Oyf#)7Q#hlmuqN# z12o@EImrR5Q*$cnpC;xrpN4(@@AhCqpNWo$=W8CgwAtUcbG+a2Y{{7K7T395fLv-dG*X*8M)dHUD#AL3unznT9${!RR&>0Ak!f3zN#szzIJ zB|9y{)qJ%9S3Iaou9bT<9-Ry%{gLjq3*P|PXz25!=xnixB3tMEw5`?i-|JCWZ%T z4b#FGa zw}Q=IGl$ELv1sK;wyWgDb@nJ{>Jsg$PUp(Tkn)Av{Cr9ie+s(lJB3B_8uuFi`nKai z(qk%Ja^!nSb7Mw&p!T#cXXXtp+$_1ntc&&#*4UdUz6wui2G47oL!SQa{5SI7&VM)m zC;1QX7u-AGYn=NkokM<-@<<}{|tZO(cz;7 ze7Loi#-VVkJFF?@@!75U;{BX^{1o^Q@6*2To%mnHPu1PcHa>%UIdOAwUjZJ`=Q{ke ziMt#3CE{if*MZ;gQ_9|p|9sLvgZo3$sekl-{B(2t0o><^n@n6gV_Psi8}L69@c(7N zKNRr)dBA@#;AbsAR%c(p|LuVPDf|PR+iuVJZy3UdBHsWm+SR>}c*&Q)Ll{(cYad48 z&k+8K_MfaCWjAS`q@Im7|3joRSC8fIp?wdK-e%L6kUquAuIw`zd@ZwSlPKr*>aXKW zaKwHS*(UD3w}~>X)F+$0f(JS8jPGqAojse;x6m&t{dUsNzsA@3AZIq3`4c`O8(p&T zA4+|qAh}uRZluqPdyo7S7z(n#Bz_eA1=pylwF9D)v%K!MCTxOIGupFtn`w zk}*3d$bm}xFtBBT%}b)cCXe_-D!Hq27V*mi@ym#dkXE1CTIxlf18<{x?@ndHDg$3s z9i2((z;mU4XHTXkP`;P)>}{62D6g}E?pqg9kNm1zK|Y;B_w^Y*uhjU}7?Ui)c#hD{xNE!gtWP30ETbO1zpL*l z?k`#ULqlWqD_)R-52oz+PX)$*=-z0q;a<;M$Uky#G(CZElK<8G#ZTQD-|+!+?j`My ze{5a+G?KaA$Sdeoi|`nuAJV&;%qd2H7grwU?U%__oKHU}Vv!Gl&93#<6ydFL*;7_Lwp^!Q3~j+% z3~beN-ukLF!+Laj$W1z16oN0Ab4-G>x?E7tY5IvW$lgZo59&DKn<4HE)GWwFTuCr>ByHA-r%fw*=+?cv$ar*A9<7W=|qSS?hOK9v(Y5kFlvWVrVMs^K&+rG70QDlV4|~Bgrj=)r8v! zXU8eOaGdh%$iF^NzMXIfVc89?2mT-)_IO>DOMzc;ZzbHCEmO`De+ltEoOyF@wAap$ zlKa$e%f`aDoABDP@U14iek{Dkg!kC6Fz>Q%?AF;r>0Q7v$JbcylVq~yY&J7RgN)3MG& z*3&)PW@LnAN!EGkeDMTxR)6*dqpNR4_CJ_;p}5lv7tET}TT_Sq#6mc^>-C}33-C*9 z1=2RnV`;`=qT_|iK>h`ESubFN6Fq3p3&p$WkC1mx8MiT>>SPU2XY^4KZ+iKo#MPv} zX!KIZALyf2m!rtp()ILR9`Z)`ALaiV{~UXx14}rQarukIvqpNawWY8SS9_d{)$VBOE0vm_ zFM{{mipWsii%F|by;zZc1>7UE+$ud@x7NOzvlWkCIl?#5t=%dbL?*wrd_G~_TN^_6 zHuEg=4*TQb)H3*~Ip5wb+t%_kA2vplU%^f`umD4icT?yb;)MV0l;7Dpx1ha#?URIo zKStU?!nA|G*O*{`0e!2P56vBFbb@qsTzbM<<}~VOo@5_!{*Kq74GZ6Cy{eb<=V@e< zVl2tJG?gzdADLYF5c9_J5y>Q(azAIHSksS+hQctG3H(Lx3A>(Go&;yYlF)7<@fDs@ zMQ@he5}uNLCW4$8?n@pCdC6=z;^jb3*dsi(&wD=9mwJ9`!j7FcY+cb5I&x^SYc6{& z=tH~avImSlsWipcrI@jYJaLoSh}>!92=J))(dU8>$G1O(U-OpM+KSWNmW}sw9+AGG zUmG`kLjGHX|9Fqp(?}n%;r>qP?TwtJa&GQ(uJWv7oJc>e{RCiqk+&FLimER9=s(bX zXf9V-$%N|T2EI4X!m4mBu;`r>_K_MF65pK485z0;H%Yhww+Xi%w*@ze+l(8T-^m&M z96A@lZr&+*MQeeDsoZO(je;N8q!*@LuY{7Bmq9u0yb$^~`cArrIDY6eJ_%PkR!GOlW9RZ6 zzdw8&X>QP%=KH>ELfGX&#v5J97zicv<)evRl{cF^(G@IZ9IPsyZ0_Vpu*TXNGcFy@ zC2P|5u|6<-Ji}fKZ`-O5Q?$|XLPx*LXy>N+dh&$IFU_|Ktk60rhfc)xcc#*u<`x)-{3}ZF+cNXHjdwE*n4L8owQi*IMvSn@{iFt+Vy$?&n=LUhm&!Y`pG) ziWc0xO!W(zSvVjglmG4fKgRzq{`c_zG=JV3F*PT^cT_dwHzm$>)_yWb2$g%9S-S5lYe4C!q%jMJU1 z%?0W3hPFUospFL^NUvdT(;eMfT;0*tT&H_S>H{}7NS<-BpZcRd!1Kdy56+%1SqFZ{ z-gWHB7t_G5Jz95uJ_$c+P8_eShb}${4sJ-Ss66fME=nehvZs1}$MK4{Fkh5DS!XHE z!JhKdnccpNCd*5Vfrj zo(HI-BdL0}ntGPA2frOzMQPiaw2A1OX(-c>FT3p(2e?Ty86c3WBTTz>~Ullzkh0JTbeyy!5IaP z1Y>FXE!-;t|H5%c{?t#@=hx+_)0R=*r@;3H+S)-ouFc6tiH}?1JPvGm<}sAqMU7R} zrTs`Rk?%w|*sZr$y*#qa$lZmF8SvS`Iin1B8pt<^e1oZNn;EO!>J#B}BKKJ@2EXc; z9kfyBn}_kv1Dw<6dXzbhb|C>dxce#D50=M*ipWZ=k(`<4hjw->FYonM-_9XJN!A zlfa_L)HOSx0=`u2{RyZ9sDx z!;ysMTz@Z;zGMC1HC}o)GD0H1i@G{zB(MvSP=0KFqKEPGt}1&;msj!?d6W6ho(%9L zS5yi~?dj-#rPdZsCilmQ=6dKKemJG*-v!T?3-<1`=9~=twH}=6KJS6#uHy7Gc%sfU z@d}@de--v*hc=tOf8|WTCTh)xS=Ds;Ayn zW**+j+6Nhxb)Cv;pF-t=c_*fh(yp7ezHVGkx%I%?cZ9QRBiJVx0hg@rkgFc=|NfbA z(D~y77ZZo9r~Z)5B-TWa*LX+4Yof%rYCQY40Bgcdc*8DzU+cr5D|kL&=T8TJ8oKZj zJ}xB_&@bhM(DjBxvZc&9;}Q57{#N`g_&4F#daxP)cKi+allXVwugBknKg3!3qwvzR zlB_eJP0?@~cQOBE{N33(?T;_6elq~wF#X%8`+kdo#o&@Ym(JM9qzeFq{ERyrJ4 zl5qJJIuPM*Xvy(nUo&r$mSe0HhlT9;(>atZ&wu$G#}n9yQ$hEJK*gq_Fu?Z znIF7R(y z9s!?&+8<^}5x%vYoBgQStCfDB3qNcEJ%Z#p_K@*!H|2d>1}E`r-FtHOwuka{Qhxpu;F|enEI)dXvAT|s#@sWOc3~iGKWV%(JeCH1j+N^r zO)xqb*yATn=eP3_^dRHHv91aZc;HxlE34oD*JEjOpd|-~?jHwv_{2G^J!boFt4HML zKY@Rgf0%!8-d+i=bDrTTh6ij+;6{s&Z0;BKf|y1qsY?A3vT1~+w5@~orBS_DDP49)yika4|MXU zloLN!yj)k;tF+--7^mPoQbo6^%-+gTblaj$*5=r@$du``Mr4ul6M`eX)xe|mz1HrU zx5it;OP135rx$!nXDL0U^fSndj5SjyYdGK4H-?rR3u&DPSfk=G;#W(#Lwg{#3;v?@ zS3bmC9M^iPwU94=HFa4bG4lJRgG*oKZp*91;pD5>D|)r)r5~#F6<;kz3lCKejGSPt z@KEKW=3bm%XOIV~{h}lHrdb;>YaVoS9(019k9T*f=DiN)Ce1@Fw9oVz@B??8y>#B! z@Z(;@@7A}A&C(%HO23@!dn%g4JD>Z{e4nSk?O^e!Z!p_;29XyDEzR8vgp!j}1*hd-UBc3^N z_sXHmLE;aPZ-9J5*WXcGIdZttr|^w_x&H4TE)G9?2eR?uipm}&JV*KHy%dDK3vIB?}u?W^FK)Zf$Q%m{we-}9{?v|9yBNneTcdV z_YuxdVXc{1Ul{T7#V2NME({ZYNVGTucLmU-uGGK{;kIY|Ha)zc4i(Vfx9qC1WMknOY9 z^oo-DY(f%UdWt&^xfK&n~rc778*I%`U!N7s5VIH!nzi9dPlfiT^S_Ad{4NBE!M zf0DoU0){x}JB;ohIb(FA!n6EyzsO8eSr0WbUviHQeJT8m>PJ`OH#{vNp0=vYnVonT z*+TM?_NK*S1;5S;M@Js2=$vp3XX>KBKJP!JGiUuxJ>p^FkF>Ms=AAKKW@RI-6;jt} ze|80Dh?wg-dMnASKd;ZEF9wnILc|YTejHf%ZkF$49;*Bd-1PBgQEP&;k?2>4=d1r$ zm4~OU2pu5YH*H0TIg+*Bsxo|~aftH6)D^7b?`<8@!>YV=tvZ|2o)A5(k{l)-*_GI$ zn~(jN`QT|0@}>AnBX}F#q`h-+CcN~)|Fs6z`GuLdQCxlN8NLAxjlK+xT{c&|4!8kW_WT#He8IxF+5BE~sCS2~IR?fq{1a~Ix#kjL@FT!n^-&@gr;CpSq%>y36V0bF<2^PU1y?2Vd zj#gAAYs<9SGUB^xlPjb9R|~7k+-%D%wq?YhgJlLNlddXrgDumJ?6jIOZTK(WIY{1h zv_pEC`*5X~xf@q{nR{@hm(g6QIa0b-tvlqGzSW<*p?&B`a*VszsIe3d`TJ@U(6LtY z2FVEp?&q~bkE=Dd(*FKLitn}aJ?V-*i7Wlkhj67I`XFvSIPgB<=3&3NaWi~V zXTEM_O!V42e;>rZ!}^!w@3Q_I@o%#J8}M(i{_F9txBjcB^E%q2I^hqIrKGL4Y0PDj zYY5M?;mh$iTR&@uc$4*Ciof3aS?k6dtiOixN~^WuNrW#V{4-=3eQz%QH?4mrY4FYX zNgHk;tg`_pY3++0pxxwCRGwqokQRV$_*ylO?Lg|va#ijbZ2 zjGR6JnZ-jk(!I44@U>>jP?kLazc1K}?CvLCamerybP?w4;*gEoNF0X<;!oNz_->?6 zMt9ioOwunQz1@b-C43>_HXBCY&s8`*pfcxdgWt zdFf?v+yrjKbA(s%5#e(@T;52T9=uwhr{K74Le*uXTuJc`)t_Zvd4zs3og?Zmov{=RsMkS`}gI< zuf=~`C4-=|?V!%j%s%!=JN)x<^rjuNk5w+iEr9#in7b~;uX#dzF(_Bu^X+J8T_}}wH2Ykz|(;bYpd`s)=Bb;a4 znMxMMgQtc(-u%u&e`tJ|#?q&b|82FWCN_RqKkc2%d7)je3nuMXR^#YRZ~QvdrlX{V zJl2);*LZD8*gTU)(&X7xs`c{Yw%z3m>3%Hsl$rb9HD5TXe4phk!@K8;CY0~K5_9Xj z))#pX@M$eP^DLc{%kQGT&T-qzSTTDRp7t!>882gd8_M?{+Pp4w44&}rZT`B}wDh6+ z&*@yzA+SdA_wUhtZtuuqC!=Fa>A{X|1*da!`d7v!)5;p1OCFT|^`n6Qbu6&`&LAXvV{(&d=!lANQEdSvjq-`go_w z?NtQnv_)?++P1s;rz3+_$DIh`$nL{8^PSoYv0b8bLEx$;yNk6jwgccpk7HAfz3TFA zT;_-J?}8(9#|Zwb^LXer;*Vk{Z4ddiPTokk2Ajo0ypQX7k{vQ-h^4W8L^_eSGW({D zpJ7hjLwX1AL#xh7l+l`PGil2IdwffCYpnL>@}`itNb~EZ*r56?{Oc%pH}in{^>e)I zA-;M)`R^f4{to;~$2|wv*wzJ4>c^>qC+WX?7~w6==47s- zu>48 z{D~ZH=y7ecWcpn{U70$)7w|8P<7L?N`#|OnGbU>p+t`SRgc2il^N3fS&A3Z!`UKL$ zq=!kbwdrr(?7veROKSgbYh~kn?wj#lXc&F44~N>G2aZkicUF#&-=Dv4uJf|_x==PB zxtcV8ANP@>@=m1ewAf3P{dIdQ`_YYx=HaJxf=B+}2X6T&bQ(kyKcUiL7v`Rhlx?o2B;2a(2BuH=N zJjYStgYyT!KyRgflW@=TY>sI$t4p zRc@UyA^s!$qsh$`#V@q(dfYsJU@mVYopq-SQt|2R?&8E6&KR+_S3SA|^>l8x zv3uJT+gcg+UMhN|oA1+?;xo-xZLPHM@1M`R1pNE%e71OC^RrqLb|xu<(A_=rtXs6E zef%@NB9kydw-G34lVh9`+*MME=sZ zJkJ6(I3KS8zoso!@`&tCytaY44_!c#xbxscI?JX$toL3*AMgls5c^W-1h&H`71lfM!`Ra~h$~%z^e?R6 z8@sFy=MMPLI^v`Y`7r)A>tBiA>0nmiUuok%gnya!e-Qs->wm(_PyIqHHw`_yC%<7`_Idci`w`mQ8rANryu=F|H*NShnVeMIOw|?n!*w2h_ zvf+({wU@UKUPL>MJ|}9&N}RSr&+l2Ma}u6)FFGCRXpC;A&gfT+Zf1BoI^YH9f~{@_ z9ZpDmTk@x5E2o>mE~~k>C4Bbg>I2hB-^xHV6PsrP_(jdQqMZNmdKI=W)0^V#5xXeKzcHIby>OmwRm3;c~kTzZYCe?k ziH>vjDhhA+VeS!uB>qF){D!M*cVLP zQ7I(0RHop*hO2d+-i3kZ>ztyoiN!Qw_P*SDP5Od%;DjE^%t?(}A6DyYjIChqMw$1O zlowez!nxP#b)543|MA|FyWgd^J8C|FY?}4;{bA;+3!`5A8s_yTduLqoKC)l;YuEU5 zNFKbgmg_#>rq_pccgVjNE`Qj@4@bR5WZcm{Tkd~Sj>)?FLpJ>&>0e@P(QDIxsB~M; zcS!p=WjEQh5cTStXWOzL1}0-SlR2%Oay2&o3Chi<&gHgT59Rbt2h*2Hf1J0t=h^fd z0^i(8+9kZpTkpz(2etb%wr+4@V0de>kB8d{8{0&{@Hz6HWAo*x=XL5iZu32;Zv|CDPBc?Y@t+uL6JGrtJm(vng9|>%NS32kW|<{QsM}HrV`clI~#QE%(ON zdh^t#O|-c9ytTuB3+cUlD{a%CB0Xl|_y}o}!IRb(H{%-Hhu0h`JA006tL{gil_}JH zkTR0_-khSKw!y`m!l7U1sYuHs8{_Dy5HaE5&U3I>x=^K4inX?N@G_?&1|UB~y4>@4V{{ zK!S3T1EYKkz|B7Y@0@!YZq3K``{ikTZ(q#+{uKPo6=m@z-C59ic*mpEu4>!mYJb?` zMrXcjs&Mn4&`J=$!l7)w{%jFEnR`q}ks*9Id|dvV{KCa~daoDUAn1>dkoRatx|cQO z$)Zcn!br#UT12|&HRXSd_ki0x_=>@U z;oZeCJkf8oCyvZ%Y`qH>a9aL0^*whH?Y25BCqKo(_aD)&6U6Jh%f~pcwfAbp zXnI%iqlC3~I8fMC{BD-L{LHRms6+hEiw|+uM(dBhkoj$ncBk~D8 z;f(JU@8V6v&kIkq?{gM^$Mt?JxV=yD;3a4?W79a}@RPJ%G?Z)D%Qw|>Af|7a%dwU;97j*|wlJeGC1j&NKHXe>63n+%kOX74SA{WRf4pDEg@j@bvxli5AU*JmzJ|Eg7<8AD(y3GYpD*=vf}s_ zB(L%6+X_?K%gh%+9BO=4+oe?>{Y}`Xv4!WL*kI7l4^ zR`BsO{@?a_UAYhcarBq&EFQ4eeT#a6F#mUH`h0K@r0K`_hPxw;9=HyAj_hP^T%6GP z+ErzRf1mJ5;PALNt9#+Cyh$$`NIFZ}PTU^CVdgaWR--#JB%N}EIN~GbE(>W(XXVS^ zfhs9m1*ftZD8@wBpKEZac2-oaw%W?$ZZ(!+2vW zYjK{2POHb(ZTen-H@NY`8+xUn{Vz9u>RrEE-oThR{T4NFUr&AO8571fu{W&<-s(`M zpkl6*Zj>{dzFTddcs64ZyqUX?lCd?{icX~qeHlHf>?W)q!N%>}^9wcTH>Y@iYTg(y z_~HJum)da#9;)FN{m!&_(0n}B4lAp?&*FVLE-;r7^vyhWuAOhEs9o?pccyk3`UBm) zAG!cN4DKLq12%oJVQTgr4&okYK343N4|c=qo+Thc-%f*>F|e}`7Z7dZa?|X<*xrAe)Xl+d5+g>EVoqkrEu~0==?Qb z2p27`Pc1HvBOk7tbLRancZX}>9L|`ayWniwblz8s3IEbTz0ABDIQwSqfq|Q;{KxW2 zXBDK?@nohy4Zt-f3s|`HzSDTLT3wH$)v@xHR^iuY$P$lJ-x#eXrxir2Tpa%|X_fW8 zp;c%TS>Q}s)%nJj*}k27;YR0$eOd9e99<2s`s4HO(r)&>3{PO+%h2ZfcfiBEs(yBO znCJQzJX{FuPXY5h;1sVFuUSid5AmkRA3cB+gsb;OI{81y|BL)T`#?1J1ny0^H}mi2 z-^G911JRK$@vlKhy7um9T5pv+z~uN@{sRp5=k;fj)9+}`^L{@3?N=jS$lFKU0DtKY zPT*>t%<&CxiWfGvjT(}(#+C0_2Q{wa493FLEW>j(4_riC79QN5o>A#YOy+*&jLL}~ zU!RPeU$?GfMn$}P7Hg!TJmZFa!g!1N&A($R9QbGQzHIK`vK}u*G9&Egtr71!%sTi7 zHQY0fkYDoYM)Q(rFT2%9o#m04}dL@6UVT;G?@K)O=F@M~}%gJyKDmixPs zb&H?>7k_Rh{pnvIUzl%jk3-+cF~=OqaW|MYeJ$5sI5qFV(z89BbME;RZD2zs zCCR;~65R)uJ_$VD?PKL?@rOt9PlQHPw#}6N8_LFjTX$!>xUaX};$nMhMrC5h7Ym~E z#n7IePG;l6FxF$d|K@Uj`dmQ!PE_$Cq>tFWQyN6OQ8k;W>_D;g2Nnb?T zuFn%rTsaF{ojRX=OSyMJbD@T_=aS(X;O)vsnRtS8oVHBl(}X4WIGFUVwB!iMjyi9p zH>GvvN@dnxH_M#MZKtn>6UU1>*DBeyA$h!_bE|q^QMMu4a1Y=PsjkFB70C=bG7@S?GK*YaeD_Y9nB?@l&jB|n6% z-avOA#aC0!vv@ybP9c%nQtF%iqOnCJTi23~bI zV(H@?+a~r0Mt8T)s{GES*K$_pCbhY93NVOX7@vl3_D7*(>R6wiY-Bf$SNdx7xz)3@ zKW60XuytX723OKaxP7nnjG@*PHssUIj2rHV&Oc)M;{dMd3taWZL0r+n4_G704q@>8 zi*%(PcCKEB4)!6B?5pF96!)w4q0f=c-QC31yY&+IuEj3cE98x4{5yXg5%%lQiF9yI zJ%X-DbOlT1Jb~Xv)=|B=2 z-GE=~4*8q#YkrqsWuoXFlvl3FhpRja>wE9?j{@rk_A53Z?`+KEDw`~~rSSL7sv|`o*;KJeN ze&zx%vyJ$C`8D|p=5%M)~Pl&wbIrN*$lhwQeF7%By zzR`nx@>XI?sV&i2>7`5t9A@#q7Ui4|{E@RQq65~(8FM#g)!F%S$04&g09jpx0p2b<&esZZ zNo*7KgmIo2~EQ;YE5779h?g;1KYSb=`&A+oWCYq2up|-r+Ut`$oko`Wi(0)wbC^YDP6W9g&V$o(z$}o-8+G=Z#TTNi+)x)t?hc@(W1##@GZL=!rgB8 zsqC#tPrEyVjYs?%+q(O|4tE}|%DcO{lf4ON?8~>%SAx&;WYTk76#bKb zuD4aHU@YH`vGi z9JGqFOZlSckoi2m8@RS-r~}taXdd>@iRs=xV{TCc@e%Z7I-3AeFLv-Wd6O&BQ_GgH zWQqp*J1Fl}ubU(r3HB!FCb-s<%?Cg=`*e<01b?tEbk@!7yE%HzL9bo(zn9kD`-Za4 z5S&H*zjx_Kc?oaQ=?(Wy-owZxM^o_FD+N;ncLF-=dggzZPh+r!Jc45*{VROPb^WZq4)*greU~w)aRJ`r;>)fs(-wGv zzSDv$8rMB+2fG_vuAhY;`L$=Nxyp% zMLG)&@Z$uy7`j4l?tsV4_0y6gy%lssiAN$aZ((AxX&?IC;^GmXchtbcY74!UiP>!h zFOQ93))_ssI}3ZD`8T<{`S1tk7J3udN{051X1`ZFPF%c@FZOKtV!_MlEC}l>>RX>f z7u~bB^5tpy!tT01VLb-?-dAy-D1ABdL?L+*eD6Z$v+SdV*}uX1vE!Qs$s>!wV~jck zQ*R_{#@E6gV2FAJkGx*TH?j8)PtE?-n5@{L&fxd=tp|U+<<%M2rLUcGM&E1#C!q{H zjPv!aoWYMQJ*K^rM&Xum30%BOmpo+d$gduu9}CRWp}O){N0J5X#!n9=@{y(lvJ5tm z7AE&j|K;WRNRseL+B6TmJRA;jo;qLdsheBa>0#HF{R_V@u@8`Z*51AMJi+->I@e2l z<9KkawNN(AcXt8E;-q9kosr66S14EbRWiq#vjCj@J?wt~r~C=tfokBNT8fQ zR)^Hzwb<5~n2H!%u{wLIvqANe$I`mH#rd1`Hs+v5W9)T@6RB-6*hqW=eW$aFtD)hV z#I}7gw4a}_}D-$*(PUpFfJn+0x$=<9nxKHJuan<`c z^H?M3J;G;}dJ5q0v; z^(1MydPElkyt@vUiE7pUPpQG*q8|UJX12FWGLZ-w#D7|ggeE5fz0~#e4Nx= z*UTVamhG!VNavO_dNYA@EZ}?oR_J$1QFgBM&5jYyrWCf8*3)Ki%z55jCv}F_OKd?8 zBv}c$nmPAu=v{K2=8$#tp)X5W8G$n}A>dJcnw#CctT|pfeZVtxA(+Mc4ZyOJ5l$Lj z<;Lp1K28ZNr&(rtmJo3%)*VlpL-SCzx?D!JgzbfwDc*jJdf$ItclmSB zi{7Bo+32(HJf{@O-f*qtw+WvqEWLm~@z=)g?0o%=Z~x)R6yP6+__ssl%@CsS?&jf0 zmb1&EZ{ipWMbTv#_%8zwi0Iw2=c)L)gz3KSqzyywjp7HgE2(tx8}Tjq&nHbfYR`s$ zRt$u<#ZQ%w1jHvAfSW|F61!_?OZ9~nIku8?0wpC?{AKHc$)aF$a#juGNC z9u%**P%0mSZt7_6sKx~{$zmz+-(PZ!N;Ol~4Cb(M|o zGmYLe9SuK9dNlEsO4t9(-rIm#S)BL(&v}E*vg(0d%(`y$;YCG7J;17{s~%uABoI9y zDvh)`Dkj8`^h8NQQ&JDR%ZpsJU35iaY&=zy+Wg5s6shG$DcuB2t+g!*CM1_>&xc1h4ZER|P{y*P&W|n79($l-?qm<{JPe09N zaX0YWK|eWJT4O(fzcazReE>fL+*+HT3l#KzCJi$y2l`c-!#xu11~{CP`%#~pq6 zTjSfcqE%v0J+G3WAB9gtBTQ+|W*RU%+$H0nML;F0~;q|9J~5@FZ;DW|h4>XZrGw;Oig1 z+;;vR!S}0Y-C1LJ-6Qzo=}nzH7P+Ij7e6zs zmB*%|cUIYNV2g5Wg~_gQ1-e`E7R$@u!Jr63gy=7V#&DuOR*uaRYV0YfK&Z zG&gnZnz|o*t2xNy@@IfPfIM`c$Ntd0u((^WbA#iC;lueCFz%v?s z@-P4N-PP60*Fe`JkqvJwMnAiz9Bo}$j(z&?%>0?nY41e+qjf+}d9L>ivL1eKh|eLu ziuhdOtBK?23C`oU?EA!beyX{v=`fxmodKSH3pivuzKAh7mo`SpDJ`aWvw+H%2u z<4b2NvCiN}8^;>?T=O-Q?tBUHrNkd6#*ba~R^m&DKS6vk z@ib!jOX?uLkT^owFk#cy#lRb}<*Qv0&Ur_HvzvPg1Z(6yV=JA^b)uoQ$oY|rf-$-j zI$E0@RlOiTr+Pm06!3A)hk^dj>HZfp(TM-VtMXR-7)6>(b&tz+NaGi zdD8QBpAWxJ%ID3Gf2ey;$F(qqI#kZ6>WS2=@o^$` zp@#%c>|BV^F&6QBj&P9S{#xKhr>6ZbJ&!}579IOd_|!lplFlQ$;P*jyfiZ6imoe_= ziYJ3RCYM4Joj!I%$-9vYy5TSL*;7Lv@b69#Cyw(E%lXnZPC0jDIcyWecrj-V|M^tz zw8b~B%9lJN{TqGCx~*tvU%FRE`{8-l(f!W(=x?C;Na~8R{P@Vm4mo$-uBh}nnF{jq z;F?IjgC#3T&efbCnrkL~il^U!pTH3|9%*Cg!6ZL<{=OHq2A3Z@;A_hx&&0WVQ0o<~ zZMFY|%w^XvLHsaG$;b%SmsJ;Xj@FOBi@xbFJ-a=Vu^sP~(AF5Ay1JO~0@=aPGiwj| z5&I8QN3gDw91@m4a*n$ zsfUaY>v(zaM6Kg<2!@DIjF9$pd2@J;$NwiBmtKAd${ zb7a7aCV)Zq2y-b1y-C}N|30Ja4g5j*_<_yEL(syB$IpwQPiTA(_o@WnV^l)lBEPqd zQ8_;4_)WZ%-W9*nJc~b%pxpVK_XzxXEU2WDD=TxT(oIRTI#!`eEz1y``PGy`?Qv_Lg?_?JeCKeQz;nQz7=n z*h#FLwVvyasf>~6Lf(@uM1&8f8`k{`jE*HvSz&z&ndPf!h~7oI6xpw6tt=hO2+9$j zpa-+3^d1Y3bTwW!(1!)%|2nOOV;UoI>W|Y_pZbIHGR0@ziz)8p_RuLI2;NV`UaY? zc5kAGEOtkXU5)!Kw=fpEkkuIP8t0<_n|VJOnIw-)(tXZh8S!S)*Grbpk21dDRF9h{ zBzwfYp=ZOym)Ij{Sgd*Lo1AAy58a8sm=tHhHFu#QJHI1x_i6EgzVr3FDS2b6n*@?G^I2 z9Y?z8*3|0@N9GPeWN71~u+4o7?#;IlkNNgOzHNt}>$_IgbUJg`4(&Ld@r%g^s)sTU zROjNC`;b3Snu|~C+5QG}+C62#ITzh}S8Bs)#HYolt{NiOyS}$`TibYGR6YIa2ddYf z5bQTiMs}L+W3xedlhJvmB}>_|b(da8s{b_N(>(96T$xPot?Dk@iL)5rV^$X9W1a>t z^D6k)mY-nm=|s+fe~HfiPw06M_rHnfYVLW0_r0@L4a%?IqTJ+rkO^)<7y?}gKnTlK{{L6kZ=Cjrw z_&#+mk{*BE_HRC2l8l|CtxeMVa8Cx~O?Rud?exJxw7b}ieq#$fcdNg*bOLGI1y(*G z`OOOVfthMPkT1sdF{1}!}fcxj6T`yf!}uCP`~_=Kc&Bm z0Q+s6v-tw@sq0rKn>Jb5RCXDT=S-&`H6LlNlg_FLPMof2J3L^Jo~$gm1U|6rHbWz< z*Ver8dQG~b47wuLYpi1`@X-6@(;?2cy|*9!zBL=@idOjFMgQ{Ms(7( zyvI35`eEzm_w(pBB&)5kd|>C)@0QGbn?=^iCg|?#D$>X7;(a7rh(&q-f1!8Q92?>5 zJ<{Q%s7G_w^6VU=KRA)QNaLw{t5cDQB=b!r-KU?Vi&6he2KxVAyF3Ddg^J`@RvHHiXD}n18 zWS@i^i>X4X1=@|XMp2$?s8jXN6dbJU;$y(YxSrw?`DXK17Nh)*vk%%IxvM&j`p|`! zPocg%FiZo6J@9tztw}zc3$NFm6ulGj#TDG8^o4ztoLs%*qTQ9~#k(u(FX+K% z-Kgq>J&c1?Q+XQc@u}ih*JxeRc7eTv=|q0(t`@Dk9j$4NGLf=;>Pu4wb7C<94d_0L zi@=-K=_|;O?g^d5cdIK{uTRcMXEBGpqk9R#o;4k4&PAw@D>RC-` z=wU$X-i+}x{S-J6Urtg-bjF4kv>uKQ6jmxf>({d)UU#|4&lj7>|KNGu#c%nC^EY{g zlKIZYVf=#AQZ!R2X@6F8(q3pYLOfm1Y3*AUO8>yShuOO=Tz+?Hl#fgdU%D&qd%}em z>Gpd4KGtu@f&Qw5aIgm+bBN&fnw-u>cM6!XLAkYtV=O^6vkRIHBb%fQ(9X%kAobs z>86!NmKc$}xrhu={q{}Z#J{;XGkP6xdOO71M)2+|><7Q&_mmD{^LH-wAGjMo4i6pH z522H8?92xGAvdSVFU*#nuzo0j8G15$DtNn@8`W;7AIjgZJ+A9YzIUb34=qE_O}mEZ zhlXoYCu4WhO=}E~(b=xfW@OBe9Ca49tv~VCl%_LYmRUZVr2I`caooCzEhPhX$i8h^hnYtIbG5c#=Fv&z^}r(r11N&E-CyztV;^s zZ#3n+hTcf}sO8w5N^d@LOm|UyQ?eFoOUCNFig3ARLN_uLIzj0YQ|J=WA>0HU9b@1P zR!4Oc`Oo66qNnM@mpNlJ+W!vchNI^{79ki@B6Ey~khAzg-N?v?MpO2NB33DR|~0 z58Wo^=w1W)%5n7ne&|m28@j($ykQo)G1)^zlHEmkb_sdstk&$tYRq5F^Ze2x@8o-c z@xDm%<|4o0d4Xj+m^midN|2vOUP5JlamflXB;LPy<9&uS)-TB z=8@fM^>Y0`8e#Qv+f#2&FE`!4r(CO-6VF}-o+Q&b+&I}MZe^daUQT&Bv+x1vdvFZ; z8<7h%rskJ0BxpOt+|$9lO<|BK8AeWPo8=*xU&Ikp*-ofQ-oG`;{vJ9q>2 z4$5(@z>|0oTAsV6+?ehy>U`;R%PSJ-Cxzq2!kXfC_M78V(F?)LS78eg%dIJ5_aj*< z@!8aO$4=rKbVaNIV`cIC9om!j3z3*__UcE+fl)r_PbZ&z(90%GW$Vm_Y$2RpG2{jW1o*c1OJuQ_}HTM-5hUVZ@tpVInU12 zeaLCh8S6IT@FKpGe>r!b1GL<>$iJ`pNqC=pCbmSq@25E98IQ6a_0<1?J^e4H0(ej&q#(rN)d?v7&ZhQE|qSp4kv7Vwg!2QF8KK9K&T;kB{x=Sb%F|C~Q zpF`{UE2rtmJ&^iDx=A>!`qAQlXKeq7Oe3;+Q^zjdgDBIJF>oIO>=z(-A^f3 z;9kir>!PUlQg8z+pI~JwyGc9Uv}qgX*>k+x%o%*<(Beqe?aRm)XJ0>( zMF*Qi|D62OqQ*w_sq~n&BOgfglD?*yHYC?4k+;1|@=uTbZ2sxQGRjG0Ij@?0uC(2I zt~6<-`mzC9=WcrRgDbpIW4*pYWJOZ??dvK};^R_0sn553UVBa8K;vgO=l@!hd#maf zjRDgqzSf26L-f5yR@Im_XIs!i&Z|6zETp?*cA|6Mg}zz)eyRuA5^?Cd$^(?S4O7dP=+XZvIay@6-#YYI;3YlRDd=Db&s|4!07zWqRT&9wE!JouA6V@v8e z^DV;fy2;SH%DscLhbex$a(|!aJmsqI4E>{IY=tO7ALY20BAu z$+$+hn5EA|Qx~3CoJ6_VvCw1R%3{L%p6NUFslGjly$bbTE57dx&rZU#4Q*+hT@!0S zmKKkSB*z7One{=$j{qwBnxv8598Z0Zamg9RLg6n&2jXEDq%@YbFA(sR7bmh7#IL7t z9_O9DQF?^ml05{A8HeC1$vD&))cvSt{AKB@9Cl~O8u9eq+_~CYrr%hn1$KAKq!R;2 z%djETTF3F|{%Ob#)B&(#?-wpq?iNLCnr#5V`|L{^xbaaze^&^$LYh7eRsd0cErcuS$qX~HOkspwja{B zMEmY6^>65@N*>p}_OAU2>eYDTdxHbrRC55l`tin$JZ4*5&g`PKLM$T!p@ zJxHs3)iVfYCCSbuK5nPrfudlWjWM>EFpa|Degq1)x)^LL?LFU#3F z^pPXdhiOUngCkOFi*X-b&KMGH3SZyF_b56z`kb@FymR}R(0wpY(OER)#Amq^SL3mW z%#>p<4qJEif#w{;3)nkciw;NdYHgr%J%ahVTmZA1;6S#P9^Z?H!4Co&#&$wu+qF%4@;l@kR(beV zbvD{qx{ro@PbrnpW1kSD>75z3A>GFy+~D{Ca7P`?#7?J}AAkqK2gECuWkui6eHOc) zJZt&BqG?;SeSNtpr8ylPQKnG(!T-K?P-m<)-~9vh+2?Cs$W(q8f2SkqkM&vZF3tpN z6TQdAsqKE`@J8f%=`5ww{1;;B5!z9JNrx%fOLF-pHceybibn8%7fkUql+w~`RZD>I*$9&%zl&-)YU&Mf#8NFZ4#XO45s||8y_0+ka_AKgAldk>;&y;=R!m z@oqZrz~Q=Ak(2e#`FcELpU;HO(PbZe-ab2Dj|c3t^Y!?Yea7U}+-WjkpGQ!KXp^~M z-4^@K`FfP?v+9hI2Yq4VCi_g+m^)3@+vky_(`Ai$`<&nzfuM1jeU9_2`A>boymheN zohEZV{IN0Kq-zvzTKCQ==j=L4_hOj4GTLT%=57q`%5ZmR7+YKJ%+UQBx@SXoX_z}U zFtLe4H=-4{J~O`kQ_aYHMV*Uljd)3&H)9+mMI-Q#AZ{S0&CP?ZU`YY;Z?j$d|-?EPk6Cd3(XoH(#PKkTW{gJiB2KjkaA?xBj%V$2Fpg}JWQ`!dIR9#4QCY&Z*7(Rfh9~%Y=adi0 z{uP1~j@^Fd@?mhCtHJSFi{qTbF>njV=TUyn;#gxxd)KYW!+LPW)DC?cv28nz=T`E_ zc1~>+PJO+Dr^)X8TJ%q=rsa#%SX-pbUgEq`^n-z4rFeQ@bpdm@?7;L6e8*PB@_ep;7rTFV^&lR$q`p&%6bhB~1?+34W1GVBmfvE3ej(w)Ii*e5 z)Co5Eh1WR_>2Us>`qd}#Y@eac=g|X>DBj50ka-;$TylBLyS3=~=tlep(V>kgfzQ!@ zNIRkf%>OB5b##c7RbuWOy@vM>s|-(N@C{|?8|KR9JZZ`o-FXt{CO6OJF-BN!&%JY7Z!0LoETH>v4AMS}vFegNpt}4qW zQ2HqGA^5g|O>Gh%;?p*GpgHUI-|!h|UF$D1Z@IZ94}aHOqd7+DW}I3cCVr*4G43O` zfgh#0?_@I`{zmnQ&$#qgNT+_o^Ry3jft8h!CELCakE8Dl9FE^T$j9L}&K{c&d{#X8e>ng7@J$YXNQC3w|=x-Q_vilruAF_Uyb> zRq)$5ojiFTI{Q$*{0erhk;(b;a?XwDj)+%g^i)-!Y(E8GlDnjJ4o}a}hLM$P;m|p; zBz0-N0-gqaC%7b63${a6hK{orw#;X}04zG&tmo}#aF!^8?35#9*}LR@Q)+cNj?HgR zin$>9-74$4; zo(*iNgkQ-`*{R&2GFAA#rlPZyYPWtPkeXO!@3>HUxIn)nUbB3f_Lc&DPQmN1KAa4E z-Sm2^jjYi`nX_rv=JA|wC0%uiF8eG@;$^}`A8Cqv`F^_nt>!G!GOPODrsWX z2VPsZ1IuRC8n%8!N_;y}_9Ih`FMo6HY#U{@C+}kK>aJ>bfcn|E4mAMxVb3X z?uk54;<U`mVB15SAhLmY+QF`I%`+e*E#Qj>LXKwd(hPu;Aogg-%Sz? zK~IylzRIZFYn66Dd_d#wgM6PrhWa09Ml_+aTsw5OaIvk=Ps%pDry2#$l+RgDegJlVdrE%ExRi@~pK zF?_~V7voaryHvN*qCW4bOZBSlwRQgtc{rXqOfzcxWMuHAe7|KXXUqJXi}%xh^#d?8 zLqFdyc){H%OXX)iB`1NQ*7p&*64-YNjtR{ zpCtJFNirV+zvx4Ku$*(f+otx@^=k;2`lMEm1^&^lF4&9l|Dw9wIYIL+edGAL=8R9n5B0uwe!w;)*e|ImhjB5uKcc-=nmYLG$_>vS+M^RZjz7zvy`EdamE--6 zH?J3;qkqK@mnQW)u+bEM-X7go?Hj$jx}H84USyM&AJ>yuOFys22J@_QyQ9+4^zv@| znB9pDaG-K4S@;KofKST~odl;Mew-?6HJD2ggROjY!iwx2|z#peJUuhpBbv zta3YLr8yt1_N1+yA@kppadfmPTeh?JbY)MXEt4Wa8xr(^_Vo_^B>*j6COyG+-fuq-_)^#|u@Ar)Y{stWzDIa};W+spW9{S38{IW0M z#tbr-^Jl-1{j!NXpAXKI{y1fT@^zDJ{!tCVx#o8Jd=6#3JQAO}_W1{t*I<92PTCj2 z|Et_Npt2(Dk-%ryHQTb+Qnqy1N;{dncanF%&HHWgy0jM3{#$!3Htp{dUL)$Pb#YtH zOZanFxiR~ED{XN2f)Ta-B|hAH?Y9ib!E*oaNU!bk1inCR+IxUKT+a4T-k*~9|B$!K z=KUFYT^%oxwiX<`WbYD~0PMnHyUn|0WPrmS3*UNtS3{TUqW1YYzK`Q~`jGv83hi-s z1UyUHKU4PoHthm%CKyN9ZyyZd@JaIC0S>b^Z-F$~`wG9iNqc+*{%CC43X8*0ww$ln zzH!fLgTwzezP%d!FSOr22!7q&0beI=8hAJLgz0#nVaEv+fu9U`P@kFzT0`Pb%^S8J`m0Q1U%Q) zC3s#}U%=NJZ?35?%kwt&mZSsK*{<5MfT{UXtyVo#AanS zI_31)*l&%#tJ;+uRh>@U$-YFI-|{W3y(;mpJ1%`{@ZN{l`IM&o>7lxlA>66%Db(%y z>c`@f=|X98=-vB~8T9T9-i7UXg&(csYU^`28?49T>;urac(G_iebh{Ov(c5v_llt# z@{LUwA3bg)XMcIW`Gd$G=#FIX7{}H_b}gvF+Q4m9J}31o*)l=eETdzZU(%c_--eww z9k^rv4K1sD&C&4iHkGAv^*!}9|766_GWG5y-i6E6yBByjJ1rehq4e~RgZV`8vca*V zqlo|0C%K=&>woe1Z>=vzpITq0Zu}Lje^KM&cxYBIe1~z=F>rFVcu}y zS^4q9k5AS0Fa9HWgr9#=2DkxA<9tP01|uwR!w4Nw3|- z@33C`Tnqo#t-K`qKGS|Ho%WY)nQ`7j-w%zqc=Cxw3;(0L_R{!x)B8|AyxD#qU(?ox zVcHrMY|w2VcQtgIHtoX?LQgq?-ewkitr|aF>>azl8;%wZC5GqCKVqJwZ!0e-9yoSd zPSvz&ALZ2>i~pFQO=)aKI9qDYvdq-^(0zusyRYsoqmMAWnlBJ5{rn>!b7a z(ee7@v9my~_hn}hWw{*KVMMUCknFz|dp7Yu5?Bj2i|00Pq5UWLE6d}f*N7+X-kk8B z{C|PZ@lE=)`OnDnsKv#@itF@mtq)%}u3Ow#u;cpoz(q@FF6gtkkgcfd6wIQ%b>Jce zF1E-%g7fg*=XIBL4t`7W8P23ULpx5c-W7?kpNvl7ClB0v3*}DQi_daGn(zvt>*QsL56MZuxTc~KhK_6tk>&)z_Ze*bd z-!pUBWjv<|S7i6#C+){SywuxMy__(Ea5iYMFuU?P=;uzJRpw;`m76B0Z1z4Y=%5Zp zh#hVOLkf7)vzVWzGVe|e^qBFVc zB@N6eZ#@6B;ttL>yE`eg|1DUZ9gmG=CLg`4}_>h{SS!fnU2`XmhZmxh7+9`%Wj-+$KW z!g=?Eo?=!$!cTvOyEoYP!Z*0|?pygSUm;=HwiXuk$;wclgmI~~&)c>wCzjsmZ}0n` zzrFC5c>c^=g1ZoOFG35?V{eJ4=Mq|PiKOSiM6M+Ec%DR#c?8*RB(Rx%5KgQ5j83`^EgY@Pd_6b~%gk2}gVQuP?aJT4*j`(fZ;HHhne_R^ z^!cpZ4fyx@#t+lMyWQuU;64frQIoIW;`K8Ezmk~iRI=o>$rX5l-Ibfb#}J``U&#E&xL zPDN(vE_&m;i=V(3RVUwkJiWVmOMZ8C8qb&T{L$R*>c_IXt4lJwtG5o|uZs8asq&wK zK9TwBXWUs8rv0Dte7dENL#*TL@uQ>dC(Z5QetM4b>W$g&aA%un-=BJFK>Nrnw3e{mRG+$~(tx0AU?p^N^@ z!v}QMU}^GO^jk3RtPAzo8h(G%!q}@=^M}31AecX1zwUk=jFwm7uVe^}xnW?u)%Mq3 zV3d5h6kJQ59Bz&OJ0bjr@gm$`Z(+YyF?`SUm7Du&d7Fbh%+un?Y=S+^XJ-rp`z65M zl|*hy%_zTS`N0J-Z=G;n=wLiqeCrMX;XAFoCU!#{OW5_Xvjx~NX<0!irTGtjV1FtU*`WzPv-RX!DcY-4xQ7)Y3-6JFG7mq>Egj zN5r;b2wu=h*Tu_X@FG6`;)MZy=HSC4(cg^pR=t?c1?TB%>lNKyXK9kP19xy7miv@; zwQa|Th_#kpY4vU&&@=f3_dnZrU7>d;YQH^=-7)V@@LJRlG0xN&`qeth<9RyIqT>bU zvp>d~kG(baLj(EM(U^S6evUF)Kf_*?_udks%wQh%0ecmQ^M%siyrjLz!~0oIU)evN zJ-pnSQvYqMjb74~t9@=Wwx~aX9Dd?yEk*QpgJo-v3%+LT2|TsaM@M?msiyB;8OE&s5J<#*xJa=Z5|2mWYO`at~X)llT*x#@R&}hfw4$?05m1foeF`cEspO*RV zQPMP~Hs2@N>dvBf*PX>#KC%?~FHa+56?RuIMV7iOzq^`7wwf`3z9_r9Iup6-3SY8S zaQ*_^HWxU96PB&+=lS1-Z+Pq%6>D7DyNTU=ceHr#sKNWHVermb8Z#zWToR1QOOcNx zLtRcR*=Yu`M0OP=Z??j)W`d>Qd9;ww`7s+aOxvX$XW*!N2(AC?t0 z|J1fc>e3GoN@_`o}-)w6t)Q`nHof$3y3kEL6H??yi3Gpc&tl_v@R1 z*UJrWD3@9KodO=ia@n+D@OX~!2wm)%j9doK_Be~|e7>-(!3Hpx1K4ZQnf!z7cZ!~x zPo=$XK9K%Nv`Xf6?0X%|Pv|b{eB>p`XYg_Q%}URdm8DBk-(nsO(w6Z%Oh25FH~c0Y)p{EYI3>?bj=JGxUpy`g@=%CHwxPFTP2BG0|j z6VP_{Vq?$4YwFFH|AL*TaMy{9AX#>MlDi^V&$e84YIO$ZL}o%ikJ$u4mex3ZjQ$Jbc`MHtT9|SA4eF=QDqklK)3+P1Z-_hWVI`l6&ce9U zUUEHL-7Q=(hfcm683?_M^Z*Mv-#Hif`IVd@+8sm42I7%EPjwnsf zl9BjMc)(}h_rv@qgX9x@5A!?wLI6u$JLg0w?i#J=S3rN1@g?lI`8XT0|B z;azcbuh=&nEHI)Kwh#sgJlTEPLIrslUUB#tqt1h|(6hb|r;p;f7C!Nk=VqV_CRX2| zmozksiH>=>1&mY`e1fLz}j;=y7%|o74S1*O#_@d-v$YjLGPnLi5(^c5_sC zQE9Qid#v$8^TA$*TcD5FNBt-N&ugZQD)0R@_2ZAk)DvxEE~rVvx0XqZoK&b>RFn2M zHch;KYE2qv{*C_6tZDL`eaJpg?dJTF`aj%Pn{653zcQ|-jIWTE!PaLwbA$N0#_mG+ zcQVO2RmSXo&Nit%dA=QEzooB?tiI8f8$pgARa5RClO}yxlttqI{_ktAIXlfk`=E@a zYvzJ6j4NaBh25Fv25f;E(%1@l)M;oLy5e`qW8BK-OYhvcaIt9J<8BAp5uwgEwxowB zIKf$~lOZt8weH-ze2sgYDT^?syu3ZrLS5@U)|MIWGApphNdKF9Quq~ze@z+#Jp6`l zR@d;niXh$iYVFj^={==gXUr+FpJ?p&%JD&(?hkC};~p{LAzP^Y9%ua@?bGh7F3FCn zZlPYE-;4RZi~ED+C%6&co{ZD8bT^oMgYx@g;Ux*|O(t+B5P6lZJBK~_4u;}A zRauCe8S`SR* zy|YD@uL;q_)?`1nnT5)uss7R=aC;^`@BHMb>V{aPI2oA6()W^4CW6#GX}$TP6|g@sA(c3>V|MBJ3&en5V&;J4PBNq)mOV%UNw)VKRHJ=N#1Yb`>1lK-#^ z9b)TPOm&-nId+ z^uIZ?NxqgT0nA;%ro64>ZLcY>gM96_Jm02aQ+mMJdFrk{-mO+P;l2KzPdH z!ST?E(6OOmXf`4`&LNMheY7D5oeFNRkSTu>+S$31``S0i9~AnCDewc$nVgkxowD|E z6a`N@okRP$O;w%SZy&c-eO8(1-)VFYDk~oe_Gn8mJI5!Xa3vAfm3{lwvP+W z{KufltEo@+9r|7}T5Du&HGCEIb(6(M2iodU1po7?fIm5^Slyct{FIE z;8b_l4(d2wgttj&nPF_|9{OFJ6&OE`d(IetvQYt52VbgF2GikS8HYk;Y?;U%^BqIW zkPjO19E~s8p>+Yj+AV%9*-?AK8slo)BF5Lt@Yp!(5c$;8n3mr>C*x{dxB5f+zP%;pM}PC6F7AI%#8)ng6me9H4U&(5}SHF~t&YNt&@Rv)xiL=V{ZG1fGbZQ3oAt8!wt+>t!Ha+ZZ)=lIu`jY&_2R)`eru27g7H*^)0`1#Ij3}zcSgo z$zMVz^WkE>C)V7ovgh)9@|h2C4wLijDbBj$Q{L5iDRl~lC7}`UBPdt?(c(kb?$z7X9hID$eS}#`As53uvYtoWBuH z+iU2r9h@FQFCd(@hiGq92&ZxCn5}xDZDZ$7n$|DkANbg5Tn_#wCj%HXzBM08Hj<2_ zwzu-Fk(aX2xW*4@dM`VQDEbTSt*Wf$*-?pQRu;m4eTjK_9PjY)!}!bSek<;2&fqtJ zpzjqP#`a3MmhQLH5A1n1dA;SijHR3L->Gkw^V{X$#CV5KqW8GFS|H#3*?_mphU@-J za2KSP?WsNmt#|PKlf?Q~I3J*`>Cb@&e1yrL=q}-nx|JTLIdp}n2(8?JT%m9Ol5b7E z?3(IU%2YqeF4ytuKd|Y_i@%ySjSDvx-1zWo`p&2CR@%PvLw$GuXCFx5bEoY&|6XIm zr9Q)UevrQxc`yE6^w$jX^+h8BzOMSE12%28Jbmuz4^)es*NG%&l#9&cXIPy4khR6! zB>hR<(oJbT59C<%RLCT1ht`|A-{k=G(vmAw?rlD!n1S|_`FpEd9){m8*vHx6d#mRn z!#4P9R%!j3^F#S31oH1gmSlp&zJ3J&!bB^f0f%GQYBwVHo@DJ!!_i$=1NaaUWRp*98FlU74 zlj-16Jjcx^VHyyBtnGjFSBCyX>*{~>djVbL57QNku%Iu21%TS}3(#4NyQjJw+pk)> zXyU!-qG{Z!LAqERAD%8c@Ez2I?X>8kX>@n>Pw6|+jp*X}8WT*q^t7`kF#mH9O`f@Ju zE5shMjqK!wcgLUV$u++pYP;s@TU^_7hiP+0sO{+3xVQ0ylJ0AKZX7bIfqP}y2X5Kp ztF1*Vd+wYk+`L})^bP&aEc=#zC3}9@ws{jW<@2<;R-P0c!lMSq_lu$>+9rB*a;4}) zd*qTYMOUIFM?0d6+0cb#hT-TUSwk1>y$sTY*1M+wqh!4Eh{I$4W!3`1Z9~oX=%AXZ z*UZ_@9)f*EGxlWL9WJBZ_sj)to02-8A3E~^J|&B)oG5dt@Gai$eoJS(1bC474oa^B z4>jvecq7l!`A{$K-C6R68{_HdjjX$g-*aO;KZ>9=T*G+JoAB{?T5_!Z_U40is$^NW z&e0mD1t6ubl6>pVpk?sC<<7UcbH+Lcue*vTTlvUC&pawyjA@;a&p=1ucXn!3S?fcc z36-26{mvwQCz=1HD^XjuUYpME4CTeMz2ztPJ)7SibC&Sbkz<`ncq-j%)|~prL-zF3 ztA_9~Kex)@RqIyQzUOF<`%`<|x%gBT_|oiYNY~3<7~mE<4DJ*_-a#i}Wk+E1v0F&+ zth3=NPvtlrp8SAHXCb-&esCdwV9WgAjHkwlPk&3k>?KWi;u+X^&zi689Aq%1eF5EJ zD?Y)_L6?%^o$?JJo8fbe^PSij@Ov`9-M7$2TRS-P87Gq6nAr<)Z4#bp^Kg$t^<8u}@~pX%($9>x*tOn4f8uxP(yrNf*>kTZAk5wf8Na zoDSzbHF$FUouR*u#J3MiMJ4Tq6<`;a@570 zKxOewSJ&0l_3za67(P%JQ2x#c-|>44@3s;D7#Oz@>-%%?tK2~ur&GqR5WJcbwl_ap z+A{H3*5%KZBxgJ}Ui!xF;#T4v6P_)#B=6yzvEI!@|A%jRWH#NOu!Zyo{X*oSR3XCe zi0au7u2l#5BM#2fs6%NxN$Vobz1Nwh8PJH*G&V#x(qC%tR{2Cb<9H|iW}0`R2ietL zYUoPz(u2+UVOntGMY4yZ0qHYR;7oOh20DR3Htmxw9^H7^24ffz@w`#cLpyx&vuyf& zmccJhW{Ud|F~Zw{96C*M<$lsCb|A8e%G%5b|NR&%Jd&) zE|Z=^>p#izI|y49*R1t+vbGys@7cB9t~l#G!V=1rEM8BBzrxD!vw_FS@GVw`uU+p= zqMTnh8Gg9+-T~xX=?UJ8#ZcQgz_(iPg_8{90xBlNu+M8Yf54WZ}R(g;RwR-D+t?5Jue|rq;xwj${I-Q@^ z60S{eW-TWg|5aJb{W`#3yO#T9x=*AcbrxL@{oJr?-G>$qPx z_-og3@529!oo|2L@n5@+{zcJ`+s`)p=IrNc57gN;M_AKo4=T?7tn7~TTmESqS-Z)W zUv~{^kCQaBw;4|k$cD-6{l}Ae>~Wnv2>Y*;-4K26PgTCF)9i2AI*;@&?#dx=mc9CL z8THa~p}TX6_&oL4PcSy9v}XeCz@}`_$0zovjrg-zx7gZ_z90W+wC~_%>njzVD|V-S z=YyYVUaI^2nIpW5`)yh$c_&+&1AcQRMz+ow?p|Ltmi)~r;tTX1`#Rw%;uT_(Q>(^m zZ#qS+JosZ9OrM-!*7u3FRoyQu0re&98m_6Ut(XXkErWhjsG<gcty(b>eXSxM;JkDeQN#%?7c zexPS)JI1-6L`x`ti%r)Um<; zF}0X{vN;LU)<<}^eHwSS@=cy^bhpwDp7Ebko{a5-?825(rfeMrk95R>Q)hGp|GC6! zm-Z05h|eaTO?(!yqu(p3L*-AR{DqY3-lus#nY`E8Z{>qt{^?*(2lt#3^`0W^CpE%gQ3V^EgW6|bVCxj_V)ThQdktPDQT}V>!FIL67&xf+!q<4-hw*m`&kldf zE(!3LJNfnaYaw4P{!ZYX!(WfvuPWxf^s{g?6Gg?(h(Q2ZU@{c!k;`%$ln&_ZY@ z94-DH6)yr$viChe`QNbkV~igY{U)JPNAsd#-BD`jmwtEsv5R^f{$IwnU$k-vTl-r2 z-A2Az{Ns;p5dQ;wQxE^!DD$o0eN+k2 zS8EMiEj4+gZvigJfc3_s;|2fCnXK^Ge*wADrQwfl2><{0n!L}E_gMMF8^N`&rmk;> z;CiYCt|w~pKK2&idL#bz^_sfA6oTuk7B0twAFRpS_YT6frlzjXgy728z_p?#FK0cE zxgTrsb#Bc(bYo3j@~igM`#GCTNOG{{&};msN1d`ZKk}qLFLBZn1F@5q6BiU05+@zv z_n~~#Nqs9vp5)IMbyAx6_{a$-O^zhVcfv{S(Nn&-B+{~p_nrLi%tw-X{vvr5Z{^*W zDgVp--pOx0?;LpbOOaOg#l{eHZ{6A0l0{DiY&Mg~OZVsX>+5`Lt@JmdRsq0TV< zs7~45*Vc#I@FDeae)3?0g%5vhL-HpsE!@53qCFc9r3!a{oA2bm`B?E0hRxOY^_u#? zQO_gPLwyzMEm41EEAd@#0ViSJ==$N0>(slh1~1YX9BW(a)p=W;IzL%cCw|r5);h1P zQ)i~8&dc6Ho#8%pxSek6bbPym=P-TC-`BC?wO)PgHTAXD)Q8Rf+gcw?&5RM(zE>Gz z;r4M5>us&?`I#H}PwWG@o z*QY%UH@~paFl0W{{DM!DA^D|a)w!T>8G0uk&R#_#PI-K%y&e-wf60DE#oc4CH14i6 zY4|fVek_xAALbA6d82tgPFdXpdlQ_iZ=?Q$F+X3-<1ez9j+C>UJ3KWR8N*&eQteyG zd-iN934V9;yNTb_-PYqjgHCR~&U~7EhbHv>FX2B?dmKsjhXj*i?Gd?sAk{DZ2K6_0 zr}vIMiE=cD57zHT%06YT^n0R_fkF&8qQ{X3z52mucJB+ZOn3RKH_ERr_qy^v>g74x zwYQq1p4h7^Iq7we*@U`F_k=;TjW~!4)u%kF$NA{ljJ;+%`$*YL zA7^4X|AmYp{deT7LM6lR?bu&F##y?Z)8>@ULEn8Q=T#%wLM6?aW9iWLat1w5KKVS2 z`kbFzjLqiF*l3bpx^ec0DzXLTe0STQ<(}pI{PmR)xxz~Dvd-goihlD7fuGWzG0@yVoBk~I z_}C~uHrY2ZI!m6REB5HpI)i-JFQM?Avb5g-zUR}Pmb8564OFjB6)V3*drkgZ(4li6sk~*^VDc@IUOXb3GyQ>$>+g(*Zq$$Up z%a*^uH0gp>^^EuCaEE-bPdE;{y78Gg_>|FE!Z}r+XWfOB#+KCQS@4lw9*>W+L~`E? zqV3}uQ@R6I{^O$HaXdc6{*ygG&%cp;y6d1&(b#bHsVyUHeWJVZ!<0MX4a!w{DtDPJ zOXVi)Z>9Y{zm=Y#4z)9kGq=wyTtvWy!M7bFM@kF#r}{>H<@0?u-DmcS1Ov2G84KMC zS1Na`cSE%RZTqo8>4GVH;DKJb9xUp+3nKff?mW4JLwz$Gj7Lg4;RxToQJQ=J)WeCs z8!nAKK*3oWOP+e)Y7FT6<3hO6+~RqKN00Mv_(~yG_|vAnbIPv$VfzF1;rsYjW5ATH z?^1<_VqW1-;m=>wJksQiDRq+`@$zFL$$7?~A#)J+<=hhnEydtDv4Q*(Lysu~E>ta`;!>YM1i~?%;Fj_1Z;yss&H5c;#@L+&9SXrp)oQDQHiz zR5*b;YiZEtJI&>*Nso30<#;ve4tMfLtML!sOg$PG_{=rqU-jzwa-K!Q;b+GygcISy zm8WkFKMCbm9nqTSaD7KpzQc>ka&?yqTIgcA(H+BQ|~ zOnubMX(RlgA0xn~-%9TwU1c3le)XT@=gOn>3v7B5ex6i^?ji)o=KE>n*BB4_Ajm(R z{3`q2o->N0Q{OdZCW#wzYs%sLzYWfWXVoFxrI~+)PsevvzuL||>$(>F8BNR+h#a%7Y^aym4vcArKZhEMhP z43;yYcp~lBJ;oz#`&DLb{#E36unErAI`FNo$#YVjJc4}<`BX+5_2M6du@T_CUcI6R zwKbaJ4n@X@qo+8(4NZY(&RRFeEzN%Dyx#IO%8y|~Ox=8{l?4 zYX^=)tP^doz$dWANjoxoEHr-gtt&_HsvPNm)Gm!f^|$6JGZuaImHhH}2OWP_K0_0v z>039>o9sAdy<)z_B?IfCfQG~u=TP=uztGbJd;|7dm8CS%73&P+yF6{`490>>&)fXK zbJLdA3`!1H+-3+b9lvi*FhN*l*In6zt#mGa1sie8_GLp7G??dOnxnaVD;#6eV zc4#MMcwtXTdG${E0`YLlHt+Pk@Mrp#_T3eW74N4U?)ZB_erd#;Wm6QcXGN%<^K3oh zxf7;zmt=SJDdc{~Q$zAeWNpXDof9j(OvyYJC*YM z%qH4@T?HFV?9r~%nypdmY#;h>NL^7DPGna_lMYVmih3!+avM*#ahll6u*M>fm&GSJ zaRbki4I7EIj&9`sfLNvwLoZ_NJDYeOiJv2Aqw#p9WeYLBZH|(M(hd?EnjD!elmxTj zcVk$v3vVNCVx5QoofLReo>+FZS?g$=EALs@pqacLyqRbHJ}q@XzLrgSZoQ8@8xxL* zjem+s{8kyK6PvXRzt6}7WjQ$9*i@TqaULhX%2S;x$JM9$)4U7!k1KBreWt!po>Q_< zRNn_ph_6Mmg&ugsI*pwM{J?FPI-&T5Q_&N6`$~Q`@NxO+x->nnrZ4I5!90n1L-Xi)1Tas`%_*Ngo!_aCRkO5v zq#vx$g)8Cb^bTkO{N7k6?WUS{js{MnJbiO>O}e28Ti)V2X|C>DNK^f1SvnZWZ?~2{ z1)5q4-_d!vo>X_S^MZX<(M}FtqdFZ8oOJ|Vb5_#wnq;=D->S>4uk~BJU^_G-cx(BL zTN|q$@s;`LH{wbB@_X1``}hk^1$N+(#+;F<;q~iOPNeZOm6nY0bGnlC*WD?z4)eTA zQSKT3WpyZLo;;&G8h=YFJDbHR4lrWLYpi+b`!gS!6K4rDhhcxoL zbKYwF<*u$?^}DO#C-fz4QT_VO7%_c%Hf8BM@ezG{)g7zL`c~g5zseBK^_{+Pza34~ z#=^zbM$VRvXK!_GW>57)gsTV{!Zn2X1bsIt^X=-H^S)g@i_k$hpKvzeJVJ^vji7pK z>k$7xB%I+7Rq3L44_KqNpTMbnnZKws#nRC#4zF>gdzgegC4cpk@JD?1xP91`cUR6v zhve2_ZjI)iU4Ls`1ilPT&PARQKf3~cIv3ykf=$oJ4(4ot@bMw5FB3eI$$t(qnwQ#B z)wkGtmL=Q51AAuT<1p^y6WwQjnDpD24^N@bH4oqBf8&ShkI~$HdKfWlKlT`xx~n&e1dTvC&5Zt7Hf2WbM*B7XF0(Tl-eM)erg4(w_O1 z$=Js8PX48byjOiGU$*t;o(7{2l>a`;s;KSQ#~`By{`~Z;HY=?Ic|JuS#QGx3)erS> zIaPR}-1k$j!)q76r;HBdk@ta<6VNeJUJvcMTXS}Mat}TQ(J_G=)gvEdr||AH-f_1> zC2Hr;rE{X*GQtYNT0()ahfpNMpc~PU58M-oMMpmUz+6n*`OW(?!Jp)5klm=cM`Ogj zPx2mjfS4dQ8#{33;YOpM3FYxg1D9#{A_02>s$4k@R8!3`s&Qc6F z(DPXY^{K{{;wZE>m%gPOO=H@gT7K-J8EO`0e$bj z6>c@=dub;$JXq%WwoLkBu*~yse7xFW-vj61d)41Tn&UU&@~?&_)UQh^-@&3jT>|`u zAAfx)|22HU^5j8YAYFdCP?|OmAJX1f-K*3n87~ixlt0Zom92Ma-f7I3a%hiYKa}p* zN!Pd1RYz=j;zza5;W@(b{X=#>UY^aDBfzJzr8zX3v;2)cyd?W0t!Z;VLS@Q~$E#C6 z{do0!`ce4=TkZVwDzZV0b3~VN=81Y5kpI`cWZ$*eckqdIx=UR7#@cs#?KAUs+eF&E z$3A!3^zHU}w0+)epXEbN{a&!omxb!+v+u^)cfIx*KGr5VbGdzPw&{%>=pcXzd>Ytw z=YpQa-$d`Uxgy-bt4uuJ#-angkJ?zaW!R8Sl`Wd=)_C3|TQlBu^83rgU$pjS#`a8o zv)uND=3mXj5sTmDnN?*k8|blw?-N-|0na-1^>pAHb2|H7sVH;iHI)@9b5~2-?;$5n zhKGumpF^zic2%KMt-b_2xp29_${c6rBjGO{>8%Rp z__#gQ;C`0gs_tNEG+MKg(?qK~cyv68i&AaM5v;3IACW8E&ii%zs&S3Z67KD$;A zxAj=d9g*FA#B!ZH-2kl(o{@zPcGCa)3*$L_zE$Z;bK_6@Pcho(X}+MXqKhc$$UBX( z#+7EB(+aNDe#u%f+T05Mn^NEfeCvHHd*u@@RvD|z*hEG#^Hx0hCG%Y?bgc0+QM8S3 zara%z-Z^EBO$TonSDVt@WkuUIvHtTjfe&fn-1Gx}sG4FoO~e95#y1tm9S$v zF`TlG^(Fir&8Ey<*iUTl<=bVH@i6uFQ#SS&4!)03hVl>C{Iz*qKK3v;ll3fk+F0F0 z-YjtJ;5kbji}2q{bifR?;7|{+Rh45v(smufhZQBd!kS6w~JCNLxXgc@H0% z!28L-^LY!O)|ZmiWmB{Onp#9yOjt?~4Qc(McJnyo>?e2in06UCk}<0_Da_r}xzyJA zIoD?Dg;Y(NqcN2?7TXhQIq0QDn}=;soIU!7Mb~6>ew#Q`V|?%)k6pTK)gQgC+xTmi zy}E4G%^0xrPR@=2`GDR8?V2%Q>glVlhZea@t}K7z1~1HUqIZn}@mBZl9^NhHTj5wf zw-@ny5#M4TVtj57`q<|Cb>zKFV*r}(Bwr_YMm)yv>HHQi*rxF?3Hsy?!V&PVt;8A| zy7O?yd!b$8NKSazSZ$z=_0+L*A#_dHLfCaZzX`bz%({#0^VBI@q65&RzTL*}iM)G^ z_zB)U0Uc}n%BQ+~gY9C@)cAF6TtpecImC_C0(mo(uXD&5@~3lixZ`P5bv@kN@%g@b($y?c85z=$&}S zg#D$KWPepKzmDEXAEfsQ0lj;`srHaRpm*@^=>0`#Zz*Y}?m>F*uigqgIwu{b_b!NX zE@1&-5#dPmzQnex9=$KOb$-mXIYjS{o(#PsHyL_|7i+$7{^{${yZn>?J;D+8^~Pt} z2cZ2Jg~$i>aJ28{F~|Q!`@PVgp?%B$mqS}aXdhlLIc`marTO-C zw9oge$ZPmNG%lJK-`5?Vj>d=3H2ht>UVMHFVb}ZN|Ag&?#|Ya9gEUUrpQ7wOOXH$v zN8^(%jc@1OcIaUUjn53xIA#1cWjMaxN8W(OpEWct`qnyIKIfNHRzT z&hN2wevhT|d#ZzUPCWsg5B0M@l+FV``$tRXFF{vB=$twno$s$p=l57T*ZnMq`TAr8 zqYgqRp^NawbS~W>ddC{RzW4}qek8u`WEV&0j-P)7n*KzHroHt2ujA+SXu7|Krq|Y? z=`YgfwKUz&yIPvg3`5g*k~a-qh@YpZFJ<}p$&86GFHh9)a`AD|Xq<8l54ZI0XnhCt zEn2Uo@m@>gd!fNv8Xw@DWS66*amg;j(YR!nUnLrs>@pmUOLloZFRxGINjCag2|i&G z;aF*0vWx1h$IIU=jTccq_Ob4f&&g|!g4Pe!kzL*j|IR?Sq9yV0+0bL@@>%6K%fDmD zBu<7OluIm4A1x1;oZ{$OvWk;SB&(cc`S=ce-a7hDU>~@vhKC1oN+6rp@^B}otoRk9 z?L$YP?E`OuwqHUa|1#lKLR>l)a5kJ=9>^*6`S+4zq-`gsWS;#*T<1h@V-4zfIA`L# zPxJg{<&w9;!?Pi}UU&q$77w3fd3XokbXXoPelA&Dd|donGP#pg%pK&Ghc{97o8jRz zpy66syq3Pj$3@@bd9^eimQ(Jp!^0(GNlxkg6{GW4jzH(dH$mt7;g`=5o+rFSI958B z9`vp7@LD>**k=cALZD|6FOR(ez5gcbVMM#%_~Sz5B=j&l-qpiI9^ziCw_6YM97@FJ z2`>>|CLC!TypwvEQtq+veA$dSxxJR>?>S1Ie^~!=cx~!<{@PzLp8x6*c)sox6#pHngQ+jK zKY{V&Ucv!Fk#HnhKay;->@D*AdbGazbT+40aQ_RkdoACuNAth2e7_qV(rtm<66X7d zpzAlIf7dur{-e>qOa2*7|1SCGS4saa`DZx&yX2pv)xYoOaPM=3=Ls(njx-jI#P=ot zsLo^6zdQNoc?|EveE)g)euZ~o-d|4#|90za-sSzjS~{Dzi}&wo_q?YF`w7nxjzsV8 zB=4_B@5|Dj_roiLwQeo%uSfIm^8O?5y}rx)kG%J~7vru2gd*WZ!jZ?a(F-rq^yUyt68B=^^&`FeY{Ytc1^ZEkd~ zelqLvL3=a!#76d}YV8y73DLHIZ{42lTz=2x+b!(hO4k{|Z@{3<8D*>@|8RCU;eFfM zeXKXLZ+oTP)6(6jPQR&h(XwIL$vfST>h^6f#F{%?n9e{&7(%kIqS_WLR8SIH)) z0a%B#$&pRN(dzaeJ{S5YY$NO>94r0jZJozzlXLC)-Jaxpr{@WegICb+cb$hFCcskSp@@CacG;aF+@SZ#Hjt)*MnhWY)~=y1aPzMec2=J$@a2kqyr4e@$t z^Jw|IqwPf@+FmdWZHM{$FT!4D!1DL7?Yxt1oQ>L%WScOp*W0^wcE!J`d$+wEp0}RR zPq?3OthD}i?cF+B@0;d%+oxj(nyAmy>(TvhtPbb42da|Guf%3YXQ!_G^1ElJ-U*wX zz6(8X6QMwOgm9#>a3mehTRl5f_}X_Hq{ESna|<$!v(uEUAJ*O1+rz5I`}^VB;kE3W zv9*6Q`?gN5|3%pBIKCgY**TNBKx^77C5sVDcdv2tMs}L@_`Z|te^dGXii41LE`JCCL;{a+=U9j#-Bv)Pet{?Xd(ti6;o9)wMV0^vww z;YfU6^8Q<~+42AVdxr0adA{WRFwd_i_q^Ra-^u$6E&WT@AI?tG@%&$wtY6FXWt)FA zJinf8{{PS3`2bdRmiPbUPurBHHf^cWHfwKN+R>ImplO>btpP#_Hnb_Elq&NkP5 z`B6E~XX`tCpHJR@)%w2M9$YVOvav9k-v4Foe7CP3*7;F8 z|G#2y=YOi5@Ah_nTkZUnb)MIVYr&;)lgasHI{%lo^P_S;nVp|c-pBHsr7(bf?(b#V zIZ&rPr@%QvJJ6|mF2|kQqw^2nk6(tfgLL-ldstHI++EH*o8s2EI$xn4-g(awA^p2Z zFS*fk3(@m&ibCfrOufjSPguzrA-F-DJNs#$o&WSCIEYL0{DA+g75v-b|3kBN?q>f| z=PFzRt^G{BldiRi?kiuwe&!%+Tz^kEN|2vC1i%Io#=RE1$CU@3T9cLZ7 z^PbXIJ${xu^Qq;k$1ic`KGm0<$G*yW$CO_KdAW0>vghP*Hqrv}`c<9>B^^KEc?I&g zo;*~B{O2s>KM$(mUe1BSC2%R+^UJ=@{yhDhoXPIpI=SMpo9|xoJm*0Tp6z+(aK3`u z!`Hf2vaaWJw4WJ$R>yra!=3-6ZyxHIov_UBM8@>(j*5`{4A53lng1Yul6kdZA!k2H zCbXBCy87{LoKyC2QTp%Rujh62eTJuyf8F2R3+g;hCztPrhvZ)80X~iFOa9&2P(?kt zb48}Zw;w)(4Xj(tm=btYN8o8LO`tO4164Zn5fS%xvNgx@+> zEX5dD%sc_EhLhG=3MT zk93ZX>P7tEOtjD#&^bC8!d%|h&~7s+XNQ$Nd{)%TW$1rg3oebDYz(BWzWK(0*0;*D zJyd6I$NFP(vM~_jY)*X#CVW;@KliTOSkN;%FJ>GJBA?-LunU=sj)RX-zUVm6d=MQ6 z+T%&PaZvI0KL7hE>2GYi9Q~@Xpn2iNj)fS!f1P7tDf59F3pzLLS2Y$iAGoog`5@m| z(0uS;F%~o*oM|j*K6s&HA;CK!DO?7(8TVqxg64x?BTJRkhJ$HCc* z1Ks!i@0=4}d%;U{!mn~pNUdZH;5Os7;9l%F_@6c>ockLvC%llc@Y0;{!smqU*RcnL z>&5lqUhG)-@0t_x-R~{Cd7^Dpd~xLYPS%He^Vmk8HQPvQgFm%(@h8Cp=zo0!QSS)6 zS?f=}%gJ-aMLITU5B3e;MLZ(ET~|MT33%aqUj1<4kyrEWjo6k;q_?y#Kkc3|WzafY z?X7d%_pz4Pi_;lydvH&4hTA^eUYyQz8^q~(=%+a6?Ma;84|s}m-JY3YT}-&*|l;O)+2-btK#);#V^W<5i#Hqbe6)3D)#_Xd75 z&SgIBTnPH?2I`_d&41q^|2q6I3$dfP6S$MO$;Mc)2bF&vKG}VT$<`q58EUr%`Q!~P zp6(^xw+@V{~u<=xz`w&?0vDV zS=kTH!*cJ7{kERdJkrEFz__Eh6S(J>`~2s8zSwh`-TPur?!&SkmT`@P$>e;=u-U0?Ds1OgZ{4CLGPJO zi@oF6A;!*>kl#UQrFU_Lprvyit@V!NQ1edoodvho8-6D(*y|0(Sa`2DJjNbnjOjhK z)8;6~fcAPd2DI0uy)U=ltLK9>Ke>5HWzxQv<{);3$7zv#PZZmhX^<&$qHF1Y`jC4~!CUsN!3k*jvF8l$#Rb6}w+P&teiWVZDBr?+;M?Vtfg?Jml<=G8 zxy;q2#L70)%66Er+_>F#?C%-3<5TmG+u7u+F)G_qV>dTew;gl#qw2Ab^uOqs)!g_B z)z!x9Cd#3CvDC(Ds`Bw;AES-KWz{@hcZRYS!%MnFdgG~XY)w#lM*2hh>+Y=ieH#f! zcVxe<0KMG$Qhk32J*>9l)g8Yt`|`Bc0oDTf^xU`A?k}LdwvztEwAWw5-`NuNtWVTl zS6F-1K(qAnWwL^@msvfWOky(nG8t{pQ)kfGdx&3Rb@AJjHuT$+HG|)#V75)s;S<^v zTHpJTZ0Orcs%uzZtM9jm>Z0@9RhPL|m(9>Ks7p5}9=ey<0H3q&2;TkN108+;^M$l~ z_Ff_~5&hmqxct$w%7$}ts(IwA$l<2h$SdoaVC}N)nC!NLriY_*O0af$2HmplSni$Y zXR_bgke&$EE|1#0@~C}l<5Bz8#-nzR@lpHM#-sMFjYso*YvUQdDf0~9l;L}Dr+riA z8NMm==nMR&4E=Y;d1c$N{PW7A_N|RaS?A`ywXuC2&w=B1;r8I3e_na?*y;CA(3fYN zSGFBHn|oTCjOf^Wo(-A6}~YkhxHO;M)Hk zwA+p3v)%YhkM!}ok9_j!@AKe$0b@~fUE0z(TUFyfJpVPoT*zaEQL{2V4 zPQSYVou)QZ8UF9Q(QmILzkKcXdE)<_)v1p3s?#g1PSw!ZCEs;?K8NlsI|H9j!e=V+ z)i&CH6Q6P8Qw;s85T8%L=Kym;zVbW0gXI=$YJZ_^YfltgP;R>vCu}zs#jC%E-gt8;g7gBs{<9{NZ44 z?DY9%)f{)G#&5>_Qaj1~QbAbiv~^4V`DOee=9CW4E5ViFUhMob^djdMw>K7Dx75D( zs|EA!eRIL|uO9W@o9OVghp^$E&lK!^d27L|K6c3a@bZ+umiaVu%|$3Jt!W-OC%BKf z0>2+J|9qCg`9psHnBN<5k3#=Fao>k~KmPxY-x=3F_U&}{-9J71lD*f-I!NEXJnf!8 zw%JFJN!{}g?*Rn&{AJVSo_)!8&%ZQuuk-bMTW7*Oe|Wze-ZjXz))emfmnz9U_N03b z#(e{j=VAPBT9zaC{{4UZKBn6n(6=$24f@0*cOP-j!4wY+_0M)&=nemL?R%tGwLqR?|NlzSDt+?h@Kmefjr|M{CoRwARd19$Vy%k%ti zkZA1b8<@d!GTV*?&&X`E=VP`V3!Vqqb}V=nU|a6_7xGxBJR;w~ocR1p@U65L`uvN| z;GS^LpFD0L5A~tW;yeAG|2BL6W#YM%E4z691=oU0<0czl!SgTq_u%yW-iVHvp(bL>$3Kmo`1Or`M(Ck;zCgO{@)uK3(vP7=WLIi$XZd}29NuOS}FX_G|#v-ZN7c60h?poH>WfwUW}jYj_9}43SKq&zF72IYHknuxAytp zZsZ@=f=lBjlmB1G^S^HWvVG*A{Ie*pL*6x4=)I=9nGYoUkAoTyZZ3GC^1lOF3(J2W z@)ec;59X17oz>^$Uve+`|AUbHyK|dr;g?VTWmjomRyLK!fs=jNS~)vA_)c=kBr<=d zb-UXWPLYq>GueL?-=8&k&#m1bJtleIW41_i?H<B6-(dRaV}SOU*&j^=_XqdcRT6zfUIf z|I_X_*1Uyt?{E#cRk#-`^S|u<#_H}jXKfwH`&ZHJw?Ch}|MN}XDc)1}tb5j7-@4yB zccOmZjl9ppzNsS2zbAxl_-Gz^{}6uC?^k?^@0{DS?gc#Ku4jBDQ$;-E+XAl(u=jPA z#|O@tGWy1z=l*4|qW4*?SubL}s&8sPjVLM?cK`ue*)KI^(gMk+5G-`n&;lNf35Gu>)bNg`Wt(CpPj?uC8&989~KF6cJ@9tx($XoZ_wHA=g|C{jLd+p1f=?sq%!d~bZ9(8YH4B%Gb61d66 z!DR3DX&n4AXLz{#?y~pYJwNUnO|JKC9Q51w?llg!=-yxBz>$LLVBK589@K!8-!ZzAIG^?UkDL{I`{>i~7#uq9SpSzEKc@FPKik(&xgLJj z^WHuxeoB+}c;ElxyN~SVeTzM;W1lX(`-sM>#;wNcUh>!n4~@&c6_@k-a_)=PKl=!E z9V9P3M;0EB6>dE89?DZ+Wo^t_`^inj0iOW(JVqY9cHeC~Vf=ogJ2y7Pn{AoP2FPpI z=;g=uGX4rG?s;|)+zq`G|2^L2$23-_FisVwG3uAkjnCzLmozO+8?Aid`zm8wJZ~K5 zvC&R8F0~%t^T^kctFIpkk5{crw3nf=?E2+{^o#5?S4PR1)+Le!J&STH@ty`U>>3z89$HOXC><@PeH}vXAdEtb@1EQK)yT4k1)+cPw?B7ZH<**^HPQKru8+|)yu^S=gvy^r-4D|=Y(k7G=a;l^ZmjecNBv z5aj6=sjig)c#90@8cs75EL^dG#~1$Vu3bg|2Fl@gmw<~)eG`3*z+>4z`H>1r8Y4c{sm?ArFIM2ZSA^vduJlv z-WK1`9&c`GYFnH1PB20I5ci+B67D^`4EJAkb#7{F_BOO8lI`A_j;8g=c&e#06Hm8x zCsTokw>I6%O)p)VW0<=b2HX=puk>Z5Q_5a;{>v`9u|{H!<;^?E-Is|x5_D}c<11vbrDZjZ`DU-MPz+>$X7;J zZ&xSDjhx~t-*6cnKUXIgmuP;PqJrYn|0(c!u7FRe7b`ly@Ur<8UQglG-YA}>UZWn2 z_v-07XmSXBE+?u#ag6SFv)UOUeI0eKy!aV~+E=e@z3;hjZ8 zDURAzZMMDSX5#dFJ?E5p<%Q>Z4c<(z@T|IG7w2q0ud@p-n}0hzWI3Em+u!LG7yW60 z+E3*Vun{uqm_8oexEwoxM-3%;-hxf7~Xfz58#uN zjlqJPY-rp`chpb0nK(JwC@qw1%s4AXnBrXG=XHBQ?4CuGXQ~$~I2Zp{vqs*Nm5rBA z636xFD^80e{;&3mLb5S!k~ogfrNrquU*(xvP<>udo|)b$$}^Oejmsv9qk5^oE))KAKJvVvYPi~`ANjK$clpi?y#{t&;Nf7?;?SZ13T7#q#E{rp= zUi3!K>tWJrBwt}gSAh2zHhwptcNlU+g138-=e_HFMSlF61@I@`&`5w)-z@N+p|UQ# zcT1rkE*xfp^y^1_zkZ-!KhUoq=+_VQ>j%2}-FGeJhW6_R`t<`&e;>z? zyMdB{b9&C}xq#7`Oy7RXT(2q7l+GkO;;o6mBi@wYIjhVD@49qnNApd0Hm^^_Q|-;` zM7OrB%j2;+6K_eZZ?#z1d5PqPcx&65_M7f(?RY4@v8go^??`qgGv0L*0yoGQi*J0$ zyS6i)+>mU`c-K}`b$fR;wWea3_E@^3eRVRnp}i|p5o>Mh%rvz%Cuijeof8UOyY8me zxy>+qW$fOrOssuPY<+Tld&j1$rdaXg&1=@)bm#g^H?$1XpqQdJwzkDvlC5i7GOxTg z5finsHIZq7n4)r}x>d|;JH2_g-WlsiKGc=OZlrp%X3Zjc`?{NMie1||#k;?=X>IbA zvDg$Z+1%0|yQw4gy3S-9)nEI2u{&e4sZ;Z8#Y=RwZb){_Cakl)!|Uv7ZizKfXqTv> z`{t^OiU}!#pp7AZHzi`PgK>OAQ)(jf2)m6jV@HCD?g-nCWK-gmG4(lN*LKHX=Kq-D zZR}{xP?dZ^cigd|HAaWxRQ_0VYF+G(*tLn;H%{>=(cH>A;6+~sR8^R&T$rV3NlUM0 ziLGf(C1cH$CzFh=K?afu^;$#*C9NS5q(83fzUfYhm^W|Eo#(4*mnIXfO|hVXV>EJS zYkOO4#@goQEKxb@)>(66GnzZvJ3BM&?WvpYSsa@)YfjayitA%Dx)!EdS2tgOeQd+r zSrxM?V%KzTXp42sskr^Nn_~|o6R~^RH^k=L8mqYdmACNkme|7O4Y9cub8hum>a5wQ z|AXa4vaPv2k?hEoFYt&rw|6AHdAHqp&;50EvGg0#$+fZ7U2BpZK|@dR0vTD`zAhQR zZBE6U*)1D0t?S{#0O-iX0w%E}@=Bd!6h9sEt6Q>kNyDO=*wRHy?_KubE0NRA_Ec9! z4ba*dOEq<@C7%qdu-NUlR@5WpsZ@+HMzl;vYjcL$G4AG6tx0!Ybrp@D=uF2_t?S80 zRbeFfzJA7Q==H^S#~0nRFutUwZc%)B!~BLtR6en~tJ8A|A=A{k&a}*mCGjQ8?u#!@ zX5w|MxL9z-8>p6t|H6Bhk-ojFqd6I0h_Y#G_q+4-kZk0dWXcj`z2+wpr+Wp84W3>i z+1cFDnpR8PvH0G*7sUc0sqsgl*VL71Y45OrB@36`yQpr_!iHt{-m_%k^4OBL=2>2< zwHZlI-cjGtp6+N((iNM$bW_Lr%%*hmj+_R4Wh+W7>+kDVU!D5?O{vzV&O1;~uM8A# zBAHIMB|7hDX-ds(*%)u`*p$w+dkF0MrnRljcicRya#rQdH!VgGyxA@7>yxwBuA7Z4 z&URfodvymYv1N83r+BZ)Y;5XC&Q7(qb#>2Pm+WXure-HPHq2hH0WrICQ)loi-jr^g z)%+{riPCO1ruzB+8P^@FunD;C!`MiFxBxrY^L~yUT=z!>-Y58-U~yKpi#Yr{i2wi9 z0*`BF!E?{;WkGkY7KcU;LXTCScSUUed6$koH>SjCBDx7A!f zC>Oq_K=?W;uDLZFlKVZEpK|^s12WI0d}OC(dCkca$>J!Ue?@pbXO{~;6Jo-6ih8E- zU)DcgIb44E!t&+!-&w|d<@t5^sn3sNddlhdNl@;TIjythev_^qgiq_-7jsGC^0^no z>!mdRf3|@7U$QO{k{dS%{8nA6qjNpyOdK&RX#C9>ft5$57gkS5EELx-Gi6s<8Vh0t!lI%g zpN*RX&fy{|aZQ(4p019K#E!X)74Zz0wsjl7t)1rJlB$#wbCp+4d)L3oSJp20O)lh1 zWqYXw^0a^(&v}9(UIm{1a+iLG>0C(k*XP+sR7~kPcg4x<*zxT zdVwvxo~H=Eiu{#dIDgGCv5)vu!Sm!U8TjSfU-^ae_xoQtGhYe(|L`0x9QA`#UR{j^ zV?O%xB_WQ!3SU1W$WtD^Q^bAzmh+A?8x2#xz32Juthq}4J@gee)sefN-+!IIN#675 zb{4`{l7KrnLl-geDlvDDmXo%Dz4g18Aooz3t>pF^_QLU&MKM6E*Ww&HyTZ}cL|4gO z8I`B{TlxBRB~0aUey+Zv)h`P3>r6b+y!MinmjT2^PSR9`3(79-DJXmFWd#>p+S_x^ zr33g;rmEZ1l9IZjNsPKOYJf7R@h7J@!Q@W^KU>mHYJ-@w|WIJex7x! zclOyO1?LuAR6Modl7d$hO)I#x;IhIiif0yhvpP4e&or$DGaUi8xL+N~)T~UhJLApL zuhzEKOo&v#tgg0H>$+rWlQ*laJ(HZZwykT{>aNyQ;wGLtP@;HzontQ+9qoyxOcNnK zDo1Y5df7;E-L7m~+v&|(-=5GN{BTU;x4LU>oMNVuMsruLX}$k@mhmPZm4n-5>)Q2b zL8hg(GY-QprCHqx_vZHX>-AVdP-tE^xQUyvJP9#t{<5XBnlcn(byp_YNyEM1OBS={ zTldIoCBMt=&smLbdet+Y;eDWaYl^&z2ZQH7m0s~==eqgZ@vDKC-PR&Bh$p-j7v`7x z0?(`9r{_tv|K#{p@jG0;ffa>bUoW0^x$>#pVSXpzH_jX{epvolevA2y>7TXTEB?9A zn-1+R$B%b%{Cw3C3U44@g^L8bcv?Gz^F8{FBCioY<*W8kJfXWc=2~_O{HB^+PjHrB z3%|qsYDRMWv2$`9CJMpG)!y;)UzGlloTUr}itux%xiM zZ>4ekcEc|Q?JigKr|<~#I|@JboA|LR%<}syev6-EP1iyAHHK_L$L}kIh51eWW|9AF zs`#!IcbMPIbBnx6dD!Ln4MT_doqVRquc!EF7uMDH2mF@YxbihlDe}sdp$G(qkv z@-;!2cC8xt6-~Iap!Dn~gsvk0sq&mhk^l5|m<|nayn~(&hf5-JSCKDKVLG=jFW(|P zU>CZI{HNq|9!35W?qT}!2`y6W{qQ;I5MA?dg@j6^^!udIlEX@rcZ{Md{Ca42DgDik z07c&cp13;Dk&6Es=-#V%E`Sab{d>@5*T5426|Ki755?Gu0Yzs(cZuJdA!ed{d0f#C zf1d&y*~u~bW00jy@B@|p&%guFTM;tR&p1N*Ncj6A^bY9bkLB9ylhCCf$o0pU zplhL5TK;N>0ceWsm-kudk`H=bjnV%J?Jkw4fOcp>NvmH~p7Wqbq3f-EUJh1##Pg~V zb%p;fw7ZmkPK3TQLcbW|va zUZO97?weDPm6t1^>uxUa_7Y3{XG5==SHN@90X-l3&;s6PH2MK(cZpvTy8A6Wqif+C zBjFE6=)MTOBSL>7LVp%|_)=^ObIVs5PiNBH2Og8 zD*8I;5oG6t(XWOc;<=vG{spff13QOmCxx`EDO8uIghGjz*r zzDHr9IjXVCL*$(8?W(A8Br{@;PFd=+hE{LZ4SD(}qI|0?L|^Ke}x;(4|Xr@jnCY)#vK_b?B1iIr@jtWh+Qy{4T`UEyqrG?KcN{ z`YOhhh3i?f{&?{GjQV3e^ybyHv4y`I+FOG@g0I3q0lhNC7&7`Vp-**?r^WwQ=+X_j z`V=86rJHi~xeEFe`qb5LzGUewx$-qZpL`qVN*ljT&^z9dtN(kT-KFvL;RyYw5&F*~ z^uY*yC_;}y_uW_M&r2HL--j+?{{Iw- z|APp9zB3R=ukyblLf;sn7e(lMpc5AtdiyN@Ht4?B2J@Bj?}47dp-0m1qWdH1cS0W? zVT@Y)d>MK_?dR(A4d}sJ3;pK~m0pKZyG!N$S%f}MFSOaE@Tt&^m|YG0zK~YG9D2tk zh29Xf_|1c^db+?nfc%MG23_-2WS)K({W|EaETD!heiwBA&(Z(r3x&TAx@SqD-*%!u z4(%@G&uuJk;QIw$sm1>~bT38=D#1^$k5;%#@e4}>s*?7&kQG9i(ehRJr4jmS=nD9` z_PPyv9`Y3m(eu_sAy^7s|#RX;1>ow=aA{{S7szH;=xLOc6J<^3^q z>J;U(^cU;4q+M#iScI;Co;EL7D=Yn7(7V5!(+`c%Y3B1r(kgsYBz+I`;kV}E?~H^G zM(C%Y8@U5NWc&_6?>H+re#fC_EHCi)K$PFhLQ5K7{-9^p6?(f&o@YVVFdw=0z7@LR zlHi?QrN1+hemV3Y^FJcz*C!DP&p`LToO{7mzIQ>_+*0VJE&k(?_#cPfkGwZ94=KNW z(50^`^kSC&AoM=US84ROBI*AvLKjfUTAcd-Le^g|9dv4?o$0)p|_$Rrt(|$*&GRf6#8UC zuD?DK3IB8GhK~jIz0x0m-g!Q6E1SIkOC=`wF}P!o=?} z=);wT{`yw*rz7#d0KNML)^|1^AA}x4A3A+I3O&wvboD<0oyJ~>8UN>?2k&RjHF_Gl zXvf#-594k}=QS_n9@9mNB4@c-vK<{N!V<)^-zo(&3vY4G`^gl%6 zpN!ByhaR~nSkEc_h3G<^Wx@3QW zS4~+&e+@eJX9Zb(b}W+qM-lot=z(sY3Nw47l)0etDeM94IPoio-pdC;GS**npu3UB zM$2yzw7b+EE1`GOzD_>YM#4KH^qZhlU&@V#K4^_qisS41fk^z%K-V)_IsN#>Ncaf! zA@tQW(yRPOBH=%d&{K%m64Gy%E1_L}|3dfo6!`Ddh~FL1!^p&b;)t$?u3E_WvGz+w z(zipeVm_Q{@wY%XG|-1ezdsUxH*{}kJ@R?QKR2hJ{wWfF40?PJdA9kXn7PbdD*vU> zW9auDeyhAUM#686(04`XrU=~yz2o!2zM=U2VI+J9bUpg6((?QBNcb0_cZJ69KSaXE zp!bC8e-?WY?oxeT0X-7Z*HzGI`ormiYUnc74{rW`5PE?5cOPk0-gVG*f1exwJCdcE_d7m`}zjxz4T8N-U@#e zbnR#1Y4knNJ2w}2u<*lQ2R)7Tg2X`a+o9d1^1cIl-u=NlU<&^r^zhzbKUnncNc_Kq zp2~WAGieq6Pm%ENN9dnM=qcrtH)Ic73+*nIXJ&-H9lF0H*Ip|l;mHWy4c)+c&W)c( zBH@oi@BX&}Z`AbFXCmPTpu4dzR#Fz#?{FmiI}!RPiccMTE&fI9eYs2ZxemJW$(%j> zO6Wt90m8(8IrP|a>TPrj^oa{|^K&os{*e5C6xvYtwZ{*jOVI%XR^I0#>0?(CV3+E5Q-ppswC;;fCrtId z2Rcy-fxV{vh9>CEtVbFxd?WOp3v&Il4ccAe|EUQ5XVBxJ^~_fz;a`WY!k*emTIGKf zdTa+}viklTbo%4WZ)QLKXC(c3F_(LwAFhT@(LVAPzuWi`Bk_>Y4?x#_Fei_#(B-el zg})oxU8>I?#~c;#-y5O-B0~QSbUkxsf@I2nG!p&;=rQbBSKsrmLVn+ptMAp&9`k$3 z(k~Egm&&sW`tVuwIlt9EEztWz_IVfd%4gt5xblAlx(|I&R}j!2f*uIz=TAbrOZ>kE zUB>uyJu(@>~*> z|C^EY&q8kwtw;X@`ta18JWrhtBfHeU*Fle*lM7!Q32%zf?GgIz5qcZ+aqRs*cuPJ$ z2AyeU-Z1(p=xXLu7k(g;{vRUrap*&Q^zfvm|7j$=@LB@wQhlaE&qTk}^IQ2}9|^C5 z9$y?h)1&aapcA3}x7S7Dw@2u$5&BP{Ygs>Rr=7)bFZ6cWKW6!VH4^_B=yE!<%EFIA zAEvzJM*jr5_Tk+6;Nt5DuuJu;h|qUL=+{8kGJnK~tMbI5dy)4#qdTE%Lh{iI-NXKX z%YOjcUCQq>(52XS)%+H}A?PjG`;te|e;bK^7%bTHhOv}mhhoEcrF^^dM zC!t5V$vkBA2(+H1u7H;Q{2sKsRGuO!9=k+e6rpd3(DNhoebC*szn_-+BqQN(jL=)5 z_uYg%DKFwb20ehhI{WKW&|8=1+V}I3^urPQ|3v72kI;qJ(_Zxd0n>-mpxvc1Uk5!k zq#qVV!taN!qJL)+SLJPk-hXj!efd`C8LW32E&NgF8ib+O=ubeqOZhzoeP9}K_$_{a z9SQ$O=uzhHeHQ*R=$Y7uLq=bE1M?306BdE|KpzUtC(Y3AQhpie(JciYL)eeM6}n*s zI-W4)|0mF;59H|mk@Wu%p}zy&&qE7rk^1S+xe*Js9QvO#(=o_IML*sK^ zB>dh8{UCHN?K>4-D(@ShyI<=cW#!YGpij{rQkx2YPbB>Zpm#C8N0}EDzB3a3#R&Zj zbUHM@{wNZD4uY`rody2$G2(X>^f30d%YP>Hs-E2ary2>4U22c|2+hG+an4-fBouyh zaQ4)Oq<;BlS$Uj(rQr7FOiI6X5)cvj)zs1468zFhNTh2@$lE^@OKEdnoxwRdSst7~ zrI;LLMf!Nh+SPNLIq)Z*Zfc7sT07IJrcE9{I+D#1zcs7loZl2*ooZ@Z=f#^=ukEPf ziqDNVZR*-k$u*G$jGLY}f}iY695{Pu^`sF9zvb3jC_&ez4f-*m3RYYm;`QS8yLo+6 zT2<#<8#~bkqP4TLD;ej=G7cq)^Js2Ht=j6J)72at&7|K!1N$d6`RBjtG@|CFRBE*z z?hU+yv&n*!mjWN9Q)`FAvx&&V`Y_j9{;$@cvkA6i)~x4Rv%TLMs)7Gj3zbMy?BMr? zL{i7<1Vnm$_Gi%Hfp;KpYc@*o;_VzNPxtZTXZggF-JGPABiE~u zb7W8($a^5yrEfSr#I_Xlh zr^VMo^mu!`xw*CD)?03kS5{S|PY(B`$`eGYITckEt$7ojA;hK0S7SQKPn9ps(&g_c zrOFfH(&Xc3d7Y`{eUACs*QLuB=JLze!Y-`t=}n%0WN4;4-q9NG zNNnQVJI(@anR{zxd@Xi~O%f<{Z~24EKw z5rVlzwvm4}W1O=YIh@fyCv=_13qk2rQl|)F#kD29+WB?yC1kT8h2>C3ol}cb?W>zo z_pVt32QSft0od01#-xXFff3i-(xIbKRo3>lY~p2WS1)dAZJVEXLsw_Uf8Qt`?@A

K7ga+m`LTjeADdm@3txNoxBrjU|HRp`Q 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 literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/lib/libadi.so b/general/package/goke-osdrv-gk710x/files/lib/libadi.so new file mode 100755 index 0000000000000000000000000000000000000000..1455b648bd6b517b8615274eacdf0a2401d014b8 GIT binary patch literal 153545 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%0Aozimt$|yTieW^$o%P`r!2Xy2gga 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 B>`wpy literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/lib/libimage.so b/general/package/goke-osdrv-gk710x/files/lib/libimage.so new file mode 100755 index 0000000000000000000000000000000000000000..2d35911581d0bf18910e4117b9d468cc88b9b7ec GIT binary patch literal 490991 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 W=_T+Oy&~}AkLx}-J(gSY|Nj7mXCveQ literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/script/S95goke b/general/package/goke-osdrv-gk710x/files/script/S95goke new file mode 100755 index 00000000..ca1acc81 --- /dev/null +++ b/general/package/goke-osdrv-gk710x/files/script/S95goke @@ -0,0 +1,72 @@ +#!/bin/sh + +DAEMON="majestic" +PIDFILE="/var/run/$DAEMON.pid" + +DAEMON_ARGS="-s" + +# shellcheck source=/dev/null +[ -r "/etc/default/$DAEMON" ] && . "/etc/default/$DAEMON" + +load_majestic() { + printf 'Starting %s: ' "$DAEMON" + [ -f /usr/bin/$DAEMON ] || echo -en "DISABLED, " + # shellcheck disable=SC2086 # we need the word splitting + start-stop-daemon -b -m -S -q -p "$PIDFILE" -x "/usr/bin/$DAEMON" \ + -- $DAEMON_ARGS + status=$? + if [ "$status" -eq 0 ]; then + echo "OK" + else + echo "FAIL" + fi + return "$status" +} + +# The daemon does not create a pidfile, and use "-m" to instruct start-stop-daemon to create one. +start() { + logger -s -p daemon.info -t goke "Checking MAC address" + if [ "$(fw_printenv -n ethaddr)" = "00:00:23:34:45:66" ]; then + logger -s -p daemon.info -t goke "The eth0 interface has a lousy MAC, you have to change it.." + else + logger -s -p daemon.info -t goke "The eth0 interface has a correct MAC - $(fw_printenv -n ethaddr)" + fi + # + logger -s -p daemon.info -t goke "Loading of kernel modules and initialization of the video system has started" + export TZ=$(cat /etc/TZ) + # load_goke + # + # load_majestic +} + +stop() { + printf 'Stopping %s: ' "$DAEMON" + [ -f /usr/bin/$DAEMON ] || echo -en "DISABLED, " + start-stop-daemon -K -q -p "$PIDFILE" + status=$? + if [ "$status" -eq 0 ]; then + rm -f "$PIDFILE" + echo "OK" + else + echo "FAIL" + fi + return "$status" +} + +restart() { + stop + sleep 1 + reload +} + +reload() { + load_majestic +} + +case "$1" in + start|stop|restart|reload) + "$1";; + *) + echo "Usage: $0 {start|stop|restart|reload}" + exit 1 +esac diff --git a/general/package/goke-osdrv-gk710x/files/script/ircut_demo b/general/package/goke-osdrv-gk710x/files/script/ircut_demo new file mode 100755 index 00000000..c51470a1 --- /dev/null +++ b/general/package/goke-osdrv-gk710x/files/script/ircut_demo @@ -0,0 +1,87 @@ +#!/bin/sh + +# on GK7205V200: +# GPIO1_0 -> GPIO8 (1*8+0 = 8) +# GPIO1_1 -> GPIO9 (1*8+1 = 9) + +# on GK7205V300: +# GPIO1_3 -> GPIO11 +# GPIO1_2 -> GPIO10 + +#(normal mode) +ir_cut_enable() { + # pin_mux + echo "$gpio_0" >/sys/class/gpio/unexport + echo "$gpio_1" >/sys/class/gpio/unexport + echo "$gpio_0" >/sys/class/gpio/export + echo "$gpio_1" >/sys/class/gpio/export + + # dir + echo "out" >/sys/class/gpio/gpio$gpio_0/direction + echo "out" >/sys/class/gpio/gpio$gpio_1/direction + + # data, gpio_1: 0, gpio_0: 1 (normal mode) + echo "1" >/sys/class/gpio/gpio$gpio_0/value + echo "0" >/sys/class/gpio/gpio$gpio_1/value + + #sleep 1s + sleep 1 + + # back to original + echo "0" >/sys/class/gpio/gpio$gpio_0/value + echo "0" >/sys/class/gpio/gpio$gpio_1/value +} + +# (ir mode) +ir_cut_disable() { + # pin_mux + echo "$gpio_0" >/sys/class/gpio/unexport + echo "$gpio_1" >/sys/class/gpio/unexport + echo "$gpio_0" >/sys/class/gpio/export + echo "$gpio_1" >/sys/class/gpio/export + + # dir + echo "out" >/sys/class/gpio/gpio$gpio_0/direction + echo "out" >/sys/class/gpio/gpio$gpio_1/direction + + # data, gpio_1: 1, gpio_0: 0 (ir mode) + echo "0" >/sys/class/gpio/gpio$gpio_0/value + echo "1" >/sys/class/gpio/gpio$gpio_1/value + + #sleep 1s + sleep 1 + + # back to original + echo "0" >/sys/class/gpio/gpio$gpio_0/value + echo "0" >/sys/class/gpio/gpio$gpio_1/value +} + +gpio_0=0 +gpio_1=0 + +if [ $# -lt 2 ]; then + echo "usage : ./ircut_demo " + echo "for example:" + echo "ir mode : ./ircut_demo gk7205v200 1" +else + if [ $1 = "gk7205v200" ]; then + gpio_0=8 + gpio_1=9 + elif [ $1 = "gk7205v300" ]; then + gpio_0=11 + gpio_1=10 + else + echo "wrong chipid: $1, please select: gk7205v200 or gk7205v300." + exit + fi + + if [ $2 -eq 0 ]; then + echo "normal mode, ir_cut on" + ir_cut_enable >/dev/null + elif [ $2 -eq 1 ]; then + echo "ir mode, ir_cut off" + ir_cut_disable >/dev/null + else + echo "invalid mode, please slect 0 or 1." + fi +fi diff --git a/general/package/goke-osdrv-gk710x/files/script/load_goke b/general/package/goke-osdrv-gk710x/files/script/load_goke new file mode 100755 index 00000000..b4ae2a74 --- /dev/null +++ b/general/package/goke-osdrv-gk710x/files/script/load_goke @@ -0,0 +1,54 @@ +#!/bin/sh + + + +kernel_ver=$(uname -r) +cd /lib/modules/$kernel_ver/goke + +USE_OLD_SENSOR_DRIVER=NO #YES or NO, default no use. +USE_LOAD_HAL_DRIVER=YES #YES or NO, default no use. + +if [ $USE_LOAD_HAL_DRIVER = "YES" ];then + insmod hal.ko +fi +insmod hw_crypto.ko +insmod media.ko +insmod audio.ko + +if [ $USE_OLD_SENSOR_DRIVER = "YES" ]; then + if [ -e ${1}.ko ];then + insmod ${1}.ko + else + echo "${1}.ko is no exist." + exit 0 + fi +else + insmod sensor.ko + # Use sensor.ko + rm /tmp/sensor_hw.bin -f + rm /tmp/sensor_ex.ko -f + if [ $# -ne 1 ] ;then + sensordetect + else + if [ -e /etc/sensors/$1"_hw.bin" ];then + if [ -e /tmp/sensor_hw.bin ]; then + rm /tmp/sensor_hw.bin -f + fi + ln -s /etc/sensors/$1"_hw.bin" /tmp/sensor_hw.bin + else + echo "\"/etc/sensors/${1}_hw.bin\" is no exist." + exit 0 + fi + if [ -e $1"_ex.ko" ];then + if [ -e /tmp/sensor_ex.ko ]; then + rm /tmp/sensor_ex.ko -f + fi + ln -s $1"_ex.ko" /tmp/sensor_ex.ko + else + echo "\"${1}_ex.ko\" is no exist." + fi + fi + if [ -e /tmp/sensor_ex.ko ];then + insmod /tmp/sensor_ex.ko + fi +fi diff --git a/general/package/goke-osdrv-gk710x/files/sensor/config/ar0130.bin b/general/package/goke-osdrv-gk710x/files/sensor/config/ar0130.bin new file mode 100755 index 0000000000000000000000000000000000000000..dffaf141f46ee4e5fac6bbe66803143a2d870cd3 GIT binary patch literal 174772 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%0AZ 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 literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/sensor/config/ar0237.bin b/general/package/goke-osdrv-gk710x/files/sensor/config/ar0237.bin new file mode 100755 index 0000000000000000000000000000000000000000..7b5180c71d2ea1db26723c1b0fd1c00364c1e301 GIT binary patch literal 185124 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%0AvIS__Tud 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 literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/sensor/config/imx122.bin b/general/package/goke-osdrv-gk710x/files/sensor/config/imx122.bin new file mode 100755 index 0000000000000000000000000000000000000000..68fd441e9df2fc67657231da10ebc772331f40e7 GIT binary patch literal 185172 zcmeF43qTar`~KgVGkagy6;V(TRslsoUGV~P+s!PkOer-rO}DhXdM67#Oe{+}0^M1-WYul4`Ut{-QZIq#V>@4U~MnRn05 zwz#WZ`&Qdz>fLX6gP0g9^R?YqqUaBZ9DWkryP8Omi1=TWbf5H$G+){&$#Pw}qx`JA zQ2tIlX_B@|^T6NsfVseuJDGxx z=1=Oele?%tX#OXqi2iyxcRB03(dClMx!phO4~p+^TsiA&RL*kFKP{)N)I9J{c%Yz1 zkOYM&r>w>6e@Or7rSH54FX;?byb)CG;#wooV*PeQ@iJ-pTQ4Qi#{4(*8Tt28pG(d4 zMB5GZ@&DzQui;Eyp7*=_5r+AfVyJq4rtb2(>z!qFJaDZm7IjOwfx@dt(OX@5^;8hQhZnuCUau}GEH{M;-|EtqIux@Js{!UBM=n6jASJvMN9l{FI|}< zu#z9v7QXb*ioU4aDXB-%(!zZ3b$#0{Kq|@>0CXZYdZgrhqBiEKlOludvYu8(fx6!9z+fbqX>#7CpDrt zO2j9O&8a1|q7-UJ9jOb(JoKPm)R$6e2(oe`@cH9t8cP!>ohH*%nob!si{{V*T1?Am z6@5q_(Wmq|eMMi>4*HJ1r~ULJ{Y<~o2|7*Z=@LnjPBKY8QU$4!R7I*T)sVuaI#OM! zfz()PDkVv`NViFMNOw#3AY;%;dO&(mdRXc$^^*olL#4;1r!WTPIq3yyqV$sVs`R?_ zru4S-uJpdNKw2yC{~#Zb z56i#EzsbMLXXFcVzAOv9FbiMdCn}4oB3RTEwM3+-Ct^es5igQOGjY4PQ?wTMiVmW) z=q9?0p5jq4Knxa-i6_NK@vL}Wj2Dx{E8;aVP0SE8#cVN8ED}q^3b9747aPQ9;!Ckr zY!f@h90i^o*8gk$zjprD&i~r=pLYGHUH@y> z|JwbZcK@f{|7-XETK?z%@BGi7CI_{Zng=uwXdci!pm{*^faU?s1DXdk4`?3HJfL|% z^MK|7%>$YTG!JMV&^(}dK=Xj+0nG!N2Q&|89?(4SpYeb;{$CsauZ{oL#{X;M|Nn1} z|L13R@e^niJSfJ1?*f|ed>t$K;5j>XJd?+tDpLSep=wl}LZ}9XQaIJ7Iuu3q@EyU1 z)RO=kToxwpgwBTEV&(L%9 z0!^fs@x-n-=q;K_vuPeJqNTJF-x>UvKBLX_4eg}8_`cv_I!d|tw%`RkKT9W>C7a}r zZwdxWVfdb4eW{TYFS+p@!MmgsJdwIHz8~0A>MISB9>aG7pOwZ+FG{cAdx39Bv+%9J zg?N7RDrudx0pAGRB5jj)Nk2#jr6c$@;P2A8g6{$vWFLGJFhCB%_W*0-iO&t>#`qSX zOTJZZDc>#MgYN)#mb=M4Dxx=Mr+ zri3WflmMloVpn_=vtm&6ics)yHtnr>K=Z&&@_pX4%UkgZ>8gM;$>Wb$Z z5w*wlTgh@Jlr34#gJ(pTDfo)|ETxp|Ur;UrSDeN_w(C<$xluF<^<7!c7f*gHxm_-2 zEJwLpu-%g7tfkb)<#>OKx6h6xCAZ7_tCr)Z%j&QXKG>rxpIb>NRlainnZ(gG8fwEG zgbnuv99J;~@6rwaiE{qfE+4mRZ8x}_{;ITosI+p% zYxGyPf~Zk&2Y>Z;%i9l?x7>d(f=X}kKh+PFr~kWI{SfDEuGPP=U&>pqJpIuBwf@R1 z`6J-W$X;FR#pV3VRgU|sYu8t$pkFIrxhmzTFBp+fo^pw3U5|3q7lYc$Q!WBmljSKF zT+VXWIu6=;%>#eO1FYYma>RWE$~nqWj(=?`q8#P;SFU2pQO;e?a{Ofe^3=!WZZF4n zx!jXCp&T}=y)+Npa1TgOW#Nx1EX94opS`qlrF-W_`=#`)XiGH@T%QLxPVdL3(yVjO zpH#)=67k&I@|24yD%bKF^_9O|M!|O7*QhTTPwM6NIj&L8i01%vIsBMlnJ?bon^CUJ z25Boa4_t=_IMz8=JhH@R9wn>fU#N<}`_^lev!fi}jh3fe72E~ql-y8>zqvjxx3R?X zl7DhJ&ex=sTv6h0E@#HuQ(}3^KW|pKlI_s`);w?{JfP{kbT4W;FWoQN(*LFhLT=hC zDA3<-R1~A#KQQQ~HR7gj*dMzO2l(IAM%=uO7aabA0JwQ=2nqU!Ux8)4{Qd2AE62ap zZuj>ut5o1W+`NCh`m%PcVD}66-)gT~wgdj@2A0*n8@1fO#LIs9Wi=X+6IF~H0e`$o z6fZk4Zd3#R;d<2l`C|t!&y>3V>T1>QA8uZtx}AS&s_xHKQ>*pz{#%Pjz?CKcsdlOL zUb(d!{}*<%jF-`=O4vVvT9yho&MAL|9`rEbw7&jqB?sy|F147HdXEZ zSM5``ccZ7pcInDlWTgN2{7d`%qs;vLl}@|yf0eo68?>VAPd18w{!@0T8`O+4tNCkJ zi&|;T1DXdk4`?3HJfL|%^MK|7%>$YTG!JMV&^++p^nh8af^R{l;LT5C&6B+?Af!{?a^f z{T^Wb^80e!^D`N*)-RXiZ%~(~9DftMJms$JH_G1bmHk24Wj zpuY5iY1#Gt)pB#LQQxMb?H1Ns_ICfhH zLVv*1(q4b1+%7!fjO*EjXQKUCeOxXOzjMarcv{*k1iy=xMQ%K6-SNk?v~q>dWpd)T z)dH~>h0}jixzgIAEz>-3y&hm)X5vX>c1&C1DTzES?e*8n^~E#B6OrGGEtr;7-%{do zu_))nG@`U(XpIXh?}2tTf{G&wbX;0N)_EHC!-~2RDXc)prIllydr-!V{@~wOuCz95 z%QO#MuLoEk=};Q$+lh0W9sig1x?C>tn&qYz^c#(!%plYkU0QY6Y6yNol=~NFQMuA} z9)vnZ!rPJR=LvJ zqAk-raJ?SzN8C?<&ds=TW*r$ZE$vm_a#ipv!xNw+Ges8FSC)PQq2DejSF1qh#y`>T z=z{h+@EgUI(Z1l)nuooxLFX+|Ur>S0`FX~ry{u4nN->=qQD05?SXu{PuTgukx1jht9|1H^N!Bh4nc~s}5W8htByo?HmO<*Fm49z4$ym z3|H7jtY@9;%Fr+Cyf12Eee?NTcMbg-3(olb%W3?3E?2))o&T@PUELCGiROXp_kbD7 z=nEa`aGosGW$EY3@|LrrzG3J$Sht1sm9Ag@jlyC0{U9Aal`kw;`uW!nd3!H zZ>8(wpDD-vOL?~2sGwY-&dY8e=kr*%g*q=?zq}tUaSfq^#tU`MPdUH(b+gJ{-4bny z=7H>uZfwPCjgu*C-?hiJ+?;aPe?+w!G!I*4Q-j` zf$R0aUmO2Y-tjcrIGK{ih5L>2jL#`)r~R#Y;6`}h^7t2RoJ?_lvMz7Nc$(sE(B?G{ z+$ax}cl=9v%W30e%KF@|eB*O&)N$47(L7Mx1LYn6Qr>dfIGNHv_bczXo8reto7X&W zqdZXF@h{~qr;U>-{d4>Bj=Q;0$5pFG^FVPA{4?WUcsyKr#=mIeWQrdPZC>-hKji@l z<4$e(#`aR^lAjb8gK=VZJh{ysQgVx2ZfQBo&H1Aof0MNA`bL*1ms-YlQ~xN(W7zCG zg0Ix}c}kRPSw^{(66NClMdeERUHe<}z>V-gr`1IMdLl`WUz#vt`1f_ay@rd1(}rIS zhYa5tzA}7dSZa9B@S0();c-JBLubQXh6F>jA;@4gu%LG z)z#C5>#FH0=!`nAa#}g298`8I-zc9eA1N!9Ol6Lep-ffMm9fe*%Hzr)rH|5G>7uk( zS}QFSx6)K;s6;EZln|wgQc>|y3<`z@{vUrAMFFQ1uH&6=IcxdVvd^;B@}cE@%Vf*b zmPahDEln&z7Ge3>yw$wSJl#CX+{@hB+}Ips7Uo|}Uz=8$-Zs5p8f5BhYHq4$3N*>4 zUyVDB8;lE$Zy3iI2N}B=TN#@gYa1&Wh4F+T$FS9~&alAnreUJtDMLR)S3?_v+t9!e zYN%u|7|!dD>VME@>o@3^>*wm<)W4*EPXD;RpZ-DpeTXoZzLCC;J{U1((tCBMbw?3p zJ9S^_KGCh#E!NG^&CpHJP1KFnJ*gY4>w{RkUw4o04&5z?wisQct|sEGqRy(*>GG8` z%5mk0vR~PwY*)TgK2x%k)yfiOfihcpTX{p7th|WGdscZ$c}y9o^i>{FJW6LoUy5>< zay#NLL205iKm^uSYAV&0K*XR;G5;ɒF)cG+vYzIUGOr0tOHYug&zJGL>l-nKh! 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 SU1-#|)rXewc_Pc&)&B%eJv@m3 literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/sensor/config/imx291.bin b/general/package/goke-osdrv-gk710x/files/sensor/config/imx291.bin new file mode 100755 index 0000000000000000000000000000000000000000..c48cd3d0300e7ecd864f239d6447f9a74ba9f15c GIT binary patch literal 185196 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 NVVj2i*WN?&e*k-@nce^Z literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/sensor/config/jxf22.bin b/general/package/goke-osdrv-gk710x/files/sensor/config/jxf22.bin new file mode 100755 index 0000000000000000000000000000000000000000..cd3a35a39a1b007c5e967d3b87872e500f44bc9c GIT binary patch literal 174820 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 T-Bcyk5o?-OJH2*Bne)E^|7Aed literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/sensor/config/jxh42.bin b/general/package/goke-osdrv-gk710x/files/sensor/config/jxh42.bin new file mode 100755 index 0000000000000000000000000000000000000000..25b06334b40332078b3f7474c8dd599f3aa3c92a GIT binary patch literal 154140 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

    78J%)SV#(uzM#^~^C~qy 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�BTk~0 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

    }ihx#2LfYslG>+G7p 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

    _JDqYoZ#tbXO*(kZz;B>RW^ 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 Zm6L0ybWEw6s>C{CP19NK-mBQ literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/sensor/config/ov9732.bin b/general/package/goke-osdrv-gk710x/files/sensor/config/ov9732.bin new file mode 100755 index 0000000000000000000000000000000000000000..fce2b879cd2099306bbeb8bfa5f7768d4fc98ff1 GIT binary patch literal 154140 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 literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/sensor/config/ov9750.bin b/general/package/goke-osdrv-gk710x/files/sensor/config/ov9750.bin new file mode 100755 index 0000000000000000000000000000000000000000..22c4997ee7dabec9cb53e9fec81dd7f728d0df24 GIT binary patch literal 174820 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

    W0dhS9jG?wE6xk& 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 literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/sensor/config/sc1035.bin b/general/package/goke-osdrv-gk710x/files/sensor/config/sc1035.bin new file mode 100755 index 0000000000000000000000000000000000000000..ea09eecc2cf738ac096026efb7a4834e0c196b84 GIT binary patch literal 174820 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

    =n7XF*yzu_+b+hB7M?&pAbAOi>C{zA}wmnR+b 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 literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/sensor/config/sc1045.bin b/general/package/goke-osdrv-gk710x/files/sensor/config/sc1045.bin new file mode 100755 index 0000000000000000000000000000000000000000..386c5bc21316dbd238515a450dab6999aa201341 GIT binary patch literal 164540 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 BN;d!i literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/sensor/config/sc1135.bin b/general/package/goke-osdrv-gk710x/files/sensor/config/sc1135.bin new file mode 100755 index 0000000000000000000000000000000000000000..527ff8a6a98b26fecc71c8245b2aa25826dff8d4 GIT binary patch literal 174796 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 Sf7wG~{bdiye*c~Kko-?bkO8v* literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/sensor/config/sc1145.bin b/general/package/goke-osdrv-gk710x/files/sensor/config/sc1145.bin new file mode 100755 index 0000000000000000000000000000000000000000..a1728438765d17ca06f642b0ba667aa6611ddf39 GIT binary patch literal 164444 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

    |aJloZ9d90dHi7D}uLAg(wDWhV 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 literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/sensor/config/sc2135.bin b/general/package/goke-osdrv-gk710x/files/sensor/config/sc2135.bin new file mode 100755 index 0000000000000000000000000000000000000000..b6054f1275373384bb761707cbf4cfe5ea7fd3b8 GIT binary patch literal 185244 zcmeEv2|yLq_y3u>^Y-@u6?arb6mWqjxZ?7##jGqTmrPA5&8%F=C9O0uwX7^Dm(;YV zEX_12E!T?7%rcYGQp<(R%2Jceo$dcQ4=#+a2flvU_Wus}@y^`)IcM&ix#uqD-FaMf zZI7O_cBnLJV0`n0mQ?P~&LD+GzeyBcS)m)(5orn$|7)W3QYIXLwn%~1 z*3%f(L-UGWDcq=RRPHF;RTM&L_>EU?R>x5HqUD98lG?p+c@b5ZU!I<1T&KN7AqPDO z`SB%qsNCmOd=;(%|4s;yH!eWlr~rAx1LO?~kT)PeUY`JY$$ulSf=d}ih6R3S0f#q- zI~i|B^Sko0j1WpH@$-&lnSPGSc!_>W%d*ONt;#a}9F_4}_$e*RD&xhMW%@ZP<2ChD zT9#GDYgCr$=ctSq;-|DM>#yL|#Sd1FdzEP)4KMg9 zKh!FUz9@`8pAX`C)4iIWGu8Y^;ibqbGL zP8R%D^i_Uqa4y-8nx-n0Q+Tp42fzG(MVb$RaR|Tse?`2*g=N1L@s1Xj{Z_=wEiC)3 zh<6e-lfM=5&K8#aR>a$$_gUV?yzRioyoz`q=55Mbm-k`b8vItoTMyQ{y!Cmn$_xwq5er;w#v*kIvf($p!0A2TOp&suz(*6C}brkQ0%{U%!@Ha@h)t(c*96#BE`I7 z54KYfcxej%HU-L9L}v6G=902vnJk5W`vbq{k>KBA8A2R})N}>^>wZegygUBiqQ zV>~Z2qjB^fvw-2}ay&Qu{6E%ojq3g(3usutI>?3QUYV*=b*e>ms28)S0fPuGEcgq@HvW^`-uFD-EI{bTerB~+=Y z)KeNLQP^)1ue4GUl}^f)%GJtsN)M&C(oY$v+@aj9j8N`X?nj(piZV@kQh8dLt1M7n zR9;bDQ{GVCQr0Q&DVvl}lY<0exp}wrXs;*F1sq57D z)DP5;)z8$O>MnJkdQkmQJ*MWWr_?-^gh^P1OH>xsMQsr-8j2XvOf(lQMO)E9bP`vJ zt3_9lEP7z4NnbHQ+$L@pcZy+Rgcv36759npB27Gm9W{@N$HffsGOdJ;{ z#3^xBoEL?n2y++>Q4c$!G(n{;pa#{ZFmD@ZKn=aEpb0hewu2Vbl3G(DwfDA!%jinF z%G(yMryHm{T0?K@L$^>0-A1>gJ={gZD3wOh7#ino5tC>NO{2$Y20cx4&?Xkr3*I)d zj56shw260UBYi}l(&zLQeM32Ph<>8ubc)WSMQDoM+a78u;YuS!h1_Tj?Ul>CZK1nz zvob)r9W7xb_UAl^cJQb&Lz%5St7Irkl;zm9vkuXr50y`qFVF(^E8ixS`{szj#^)Bs5V9$NKjj=?bIao3iT?rt9palOTAg`uimN-_O^tP>R9ywe6BTF zeN>&UrlU2?Q=d~`M0 zL20S9RXW0_uTrj6lF`H8r1Vu%ltId!$}o8LXyra-g7T2pyPs6jz5cxr{rtBgr}CAuM>&Ar{;+aH`9(RYoI!t2s!+}F_h7ZMT0^a^)`iDMsZG>a z^!lyUM74u@IXwOvHCgTM_4yQaV5!fKQOBeIe@LCGKCV8gKBdl5pM}@Ipe|OIs>{`t z>f7pCb%VN5{Sbctnff{W{_7IIKMcSB6@GtC%~utn3A=D&JO~vv;raEwo*ygR7!g`u z;Q2kp&Eghut9LvYDpJK5F-}atXfQ=Qg0bL9j0JPVJn^h}zGNg=CNjlJu^QvRJ0eSb z;2j0FiEOb$e1$P!pU4s4m5czs{?Bv$5DKLlXaV6E_oFfDyQu}WK|h~_HqZs5eKPex z@7@osfJgeF=+{T1SLgkR+^0{+C_jtlUNFiR_vqXbKBjHx)4!xW-f{kW^y_GxRgptRgCp@ysaTdX{I#ywuTO+llz zAhd^SYAv*f2(=MLfLJwNZH4yGQN2viz12Xb%r# zM)0Kiv^ocK0v-ikL3`j);BCwc-bH)ZtbT&_@P+yn+QWX#4Sw*B11HcP&SM-NA-gR$ZPF;PtRwuTvE zrg+BN7UU?vEnz+81KbX_VlKdAz&Dr&a2q&+Ilyn?jL0h)|BdHwJb%Og|5yEA;L}VC z)_}YQ;8kEH%mqTJ8b*VfSO?Uhx)>AcQ}Ie5ni`W_3nXBKXysiEw4)A~D|DjEOV)!;bzPoZlM8K6AYrkbSGAcWvhbwu|qwLCeu{!N^u6w#JXTUJ%@F{%k(PN zif_^y+CcAnSBlvfLB64b^dm-(-!P9L?;5ePQX6ANloE&WqN8$!a*fg*vxZxhyS!_G zG^_~Iu^!A&7Gp$MgH^!CSO@M=a2y*ijd{*4sPqe6p{%Ul@!?!3e|&cs|Liis^_C%tdtIC0a_a(<;1U^FD3C z9CD}E|9_%iFn7#HM8Kg`R%#(W)CjAGmP!YBe^+>aALTa85Jw>*Gzs4SREhVmfcL+P zx!^Xe3-&695CJ-Y^?>33e<)OFkPQnM7BDPeSirD=VFAMeh6M}@7#1)rU|7JgfMEf{ z0)_<)3m6tKEMQo`uz+C!!vcl{3=0?*Ff3qL;9qP3e*eSR|7q<1H1_`*`+tr7-~W62 zzxkDQxd)7Qfbsq>-U-V4zAAfnf>tlt3CeE;mc0?i`@0fK-v{IUpYqMX;=P}|^RplJ zck#P{ca*#fHq!ep*m#;$vg4EA1LOUk^6imT*zYOd0{en?(O&O+fk(V=j-1E$Vwvz3 zSg`l4z`9DL5`$fzE$~iY65a{qH%5AScYfZX48`8hv3OTxviE(!nRqYYIb{*v3V0oF zg000aun({c^fT|;*gPeHXx@y6`4Ibu|p{0Yu>&pPQ>K@fLswZ-sPG zuk*eK*0K~uxZ-(H7xKSw}4$4jD7be?B(YhvEnTNvo}=<-;{X4PYT}o^yS$x zbM)o)#yg@Wyh*Cp=fpb(zP#iT9=~&72dt0?f}}66E8Yn(;VmRR&*_JEnIE3r53iH= zy3t;J{5_L)@BRM%y2ZRuFE7~pzlIsHiJJb-E_}bmJQI%iyCGeeQxCepdW5S6#`6*T z&z?5I3c`u^!nhs8dw>1kO5Ff?)dJ-48!LQWZZ8#G_utM7#(h}v2KL47qZ!_)354h0 z`v1M$d%gYDh5ZZn9lrg>aCjj18~T38=7%>J-&$k$;c=hftFJ$v>aX~^H7_x*Zh-m%`cI8?$I5(nK7yIc6uTBhr zHvlc+iU4?bp?A4H0N%ZLi~F_!cn{)@&D4N+X?Uyq;`ciZBUd22^ZXBFn+75x}I|JJ$GcJY4|BiFFNpR)kB(=>c@E&F*&1*({r z0w(j4F2YN~9GZFVi}2hSHJKNA5nc^wVqT4l@T`bkFz)V zAiO~QGEn~wly@nfsiDKLfUgDW{bN6s@nh9AE2sZhCH}z+|2ytK>@WVQQQl8zXh?{Y zpT9FCBs8=7dVjh4a&PQka{uMl?-CV+`uv2H{Wz^w!~``fw}8?gAA0!><1eb8 z@Ad!edFhS$J1}ebG5aei&HJ<0znFaKh5n)gXSqLCt69Sz8dNniT0pr!e^Iqc)s}nV zzoVe|`TreP`gdN#xPSKlfArb-&IgTi!vcl{3=0?*Ff3qLz_5T}0mA}@1q=%q7BDRE z|Dy%|xeoyT9r6GF_51&;KL98bhFhnyU`zT zxlGIFWt8xW)AD#Z_@<)bexo=okC%&{sF;`IO)tjFMGsf;eS~|G%&q(f-%H0U_V2V3e=q;KmyYM}8b+RBfj?`3P<-zo z`>ho-(}a+9l0<{qnC{ z#;f=~0^#{JzL9BI;7?kB|N0!aKNI{X#hW(ptFf4uT*BkDA|C$@#6a}%-sC_FxS~ zh6QvM;Lpo)5Kk`N|5BXlic1ffm-`2J#h+tW{JAshGkB#YHVzC6{ACtk|K)uk#rtH6 zQ-2p@UUrFJ{+;_q_`19Qhpy|-_C}szfj?^j_M=Sr5r2-IQj+@9`A2wJ(8Hf|v%c~^ z?`C}l&!44@Ji`K)-U7w@UyA)asRBR$BfKRgdM>6fP@e1$SYLVlM)5wG;`0A8@6tbE zL!)5;?{Gi?Ps(}!vcSW1$h5U3jEdtk1zgwE7b30 z4Bp>k7r(|gG7Ss-Nel4)4e8%9^{3L{`SwoIE$dYF{WjSU!WZ7fcW_jPT z%JPck8Ot=weU`f{eJ$5o+F6=f!YocpzWJDWpZPQMd*)2@3+AWIlg(qygU!9o*O)t) z#K->wo;Wq!l>vrJ#S}x6pCMam;bRvEA{G<5kBj$AgZ+j_Vz* z9AOUO_{qNA{+4}#{UQ4h`}Ovg_AtA!|7`o*w$}E7?NQrETVLB1wpd#Yn`%2|-DUm2 z`nq+#^i}z4Yg=oSwW?KEf3@UTwp-q{EVnGQJYkt&8D{Bk>1Ii?G`BRcRJB+v z=gddU`_0+r56o|ymzo!vpE6H1-)A0XzSZ0dEzDzXVU97^MH{o3i%h3XN6^Z4nYNiW znbw)!FfB1XZ<=Fz!ZgM7fN7NJF0{2irW;IGn>wMj#hV(NBGBHdn4Bh)sZcwu9oG(P z-)i4zJGE`vM_QJ)PFtxh*A{CpX!EsM+LLH`leG!jSnVEds5V$j(fXqGC2QAeozec< zX|1&8Xn|2$gjPqZfi@Vd+5Z*ouecQy1^>C<{NUe$4+Vc7ygvBF;D>|n48A5fCfFMM zL(m6789@_*ZVqZ0R5|Du*H+gO*HqVSt|V7oSHANb=X&RS=l#yU&i2l_&LYP_$A^w3 zj_Hn6M-N9^M?Ht;IAZ_YzQ&$mpJq?B_qKPkH?fD>3vEBycG%vvy=t3nn`9ei>tnmh z*1}fb7Hli99EjL;^TM{j?Xi+uLUn!Q;Xj9*szcOz%zi(b`UT%KLJkLA>?P|Pvr1?&B ziuoq<_2w(h?ac}1#^}Flnk%7oDduygT+>fzUwcfSn?5mZG_5zSG%Z74wh(P>hH08< z5?a}4^k{=kDW;oE-A!FholQxmL{oyPnJLOtA8oCwDa2$qX=rWdwBNK}(B8h&_G!Dd z9cXb|v=6j*wYAzRZH2Z}dl|jmv)UZ(Y3&KLyD8d4?SAcEw7g;35N(jR?cJnx*Scxf zp!Hp*b<`5k{^GS*tugw*2(7MGORMf}gAUD#ztMx9ka}TkXoEpUQEFiJmqu=UL%?}2 zh>AQ;3>5_QP)M~R{zHnLvJ|&qa5+&A$Y+5w36MX{K$Jhe$F`D!Uf^Iz^8WC#v*h@3 z97_%#2bbi3rQ`5%WJ$gQN+gGmW&QvhS1#f3vCJ>Y`d!k~&wV&>9r@#XEbI7hyN~X; zk4>1t@8!B{M2m3mwUF|0Cp+c=CHZgQ!Rk3l;4x<@%2|ewpDN+?qYW5sz-R+T8!+0yf4>d%!&<=2AGnsY7AWF)L<#g9&Xecz zSf&-_>p6TZA!RO>O1?imEGx_9@x@Z9M=vL3WEr1JNM1#$3W0|K< z^~b(^DI+=l&h;|P3lvgLrizcfIbY^Uj@0d2rqAbNF8?DbU&mKQFE5WJr_jf?TrPD; z4(BnLt1shn3CXD_m0W$w`dF`CPL}J-^m&rYdCbwDOI=)6(Xn1ua%IZ;q~1VMDJN6C zjBg%7Nu|$+dHQlb=4hn~+eQjTRW z2FaJH)Wxa12B%y%2G@hZdh<)JrRPcxmkWUP%5r^~Z@$#0=lbUHb)`%MQ{Icbjx1w+vP{Y` zhxIeZR3a~R%R1;~`1-P*Qind(mrFURN9vXJTu&qJrIhtwryWS#UJsn@rRZ7Q!} zF44{RCUyDC!>6{T&qL}vS0cmrBFkBizP|E0dhS_pq-|JE-iy@1_47TJ9BT=muXzTL zb!MH?UVJV6JxCeW%QAYN{yL{i%J})S4t?ENPJdrE)I)!7d<|)Du8X{;tfxGeb&%(> zob~DN1)oq}P|uUl$@e6mKiAb)#))!Y4(pN6i`xe4(bt{p`kNnJ<>l%1v5iNQK7YQ4qdIxtXUW%Q`Rb6b z4ETGtd{0LL3t5 zE4Iatz_%s*8sPJNv+evnf9A7p=0|`N25^1kv-0=+e+Kt^-~iAF+;D*Jw<@4-8@|u~ zC-A=m_5-_thTzu&_?|BI{P~^^0{ehnKoiJFd1-5ZZCP(?DbLsb0*Hl<7@z^*`y71z zU;i9(Ao~sQC6EoYhJ15C)=An!-%iSV{%jAvC$7^DU>mRnXa{{QfjFQs5DEOz=f4+v z*jAqdp8_8N8-XjK%LB9p5&*VCH1L0U{$E2M+hIHK3GgA11*`{pKKR-XVmAt2SaJ&Xs3A_#rg8u$MZ{S9tE6^E80uq51z@>WrTXDV3fV}Uw zar_3b3|I`j2rL91#5KnP_W*YTw*v!!n}P1Yb--0XC*ZGq{u@x2)xev;a$pJY67U=_ z510ka03HLT0%^b^)af~3F7OoaI4~99dm0Cf1cm~GffS$*@J~Mf^6u$z+{?qjBw#!+ z78nT(2krz00Rw=(Kri4t?&CM$DDVSt0N4$D4r~QB0q+8#t*0odYRfNeDl7y=9g*j9Z2w$%+lSD*`UIp6^jfmT3spcxPYL;~SJZJ;_(1qcT0 zfEiGMeC)Y62^;~w1HJ)v09%0%fc3yi;5FbS;8|c6FddizOaR6J!-2uT0N^Gd8R!CZ z0uq4)pa~EO)B&mi!GIM|fPd5Tzr~0fVlrR0p66qK=f3$xXiw!qa%C!c{?7Gfe5~j2 zvCPw_`eR?dl#v{N=Xx3D1qvxAQ(o^#S>HT)t}mB-F4O1pvCIoJWnI2py&iciIXrLV zV|mWyQinc|^O>tJlXAX1=K6!4FOOLt>(%r9mFe>&m-AR&e=c=#Sw+WsS;>_t>yvr| zNu``j^)kMB924L?c@2HJ%-3`DHfNbY&I?NFFZD?|*2{I{d|Af&7%U^peK{;Ib?Esl zBjs53Vvu~9N?n}FYj7&-$Ms;aUS5N;oSw@(SuWSHvRq%Lm*ae?PtWzuW4%%**Qug& zU!8icEaN(`9(f(9lkbb`!7_a8%V9ptvL3mvVQ!v|E6X+Hvo3iJmf<|sDepyIN0u>P zmPt9OpE;%yd8u30K`+DCm-Uo7^r^mF%1J#^udF9ukFU#dA6XBnOUlSP={ZubZyDQE zUW3<}teb5ob@|JaaRHW<`ZyLOuOZ7>kG{V0I(qI|aHMVYF#)NAui<+v@7FixBuC`g@QvtoMu$Pk)`$C1w2lS%jkw|O3x zLn7Huj-jm_28_7j|1EC(1#GtsFye;Ab2#qLx!>l`0e%GdbAY|TF5q)OA2;5B^VPtc zz;d9x7@H9{{CCBT>S8?R7<-_f8(qrh{{Y&F5jXs2GSzm z<^`IvE?=%*k35zfo;UKbJm+$$L!Za_%+;4kIbR-g{Xx%{$E=U_>iPc4^m&rYc`UC# zm%6yDqGP?RgghQ3_p>p6OxvrHi8yguhTNPSX{^~!u% z#`+jCw!`JV9F~_l^n8|)a;*DekbId+U7X5maLRRK$hxpzjzO@To+~+AF5?)oTwkV_ z<9w-4&-KmYYfGJ6r;5&fb?UjYjO)O9}*VQlCB+D9eqwVeuNh;KD$>Ep{9@4a*W{(%jvn2!{st=B+K<>dO6OQ`t)4iJie~f$#tse+*hZbE6cbJtVdo) z>g4<4daw*1`*N7ivaCnOx|nOk4UM=Vw-sZ*VX-gp{z;BM$~Z5_jg9w|(QUvcvYoI! zc&}YW@2Sc?jQahiyob?vPq{3nssG%7+nxUX*gv}8g!wf9j+YwmDVM$Hyc>4q{c4x$ zJ=NB*Z*!mt&=3d*Y5~T3%Eo)j#(T>D%zNtP?V&W@QzqJgzVDCjH#PPf{`2ptrx1ToD5#KGJMZ{^JTfeRB~l1IsVS|WqhpX@UhI(r}|@GzLb$1f9HA`<^>8VCsSV6 zOIhDMd9E*)d@j@H^RdheG-X}BT)iH7EIAyr;A45tRO;eXUV~Gv8-we?V7*4% z(1;t#xT!ui#O;G)s4~XuTgL6i*l$?&E;8GTZDPEqT-@);cM^T~K=ON=`Zy%VXF2Z1 z-@WG>H}d@+J?65!{=5FT&*S}L{GOU#hkO>iudKYdk@22#S!^zlJ&C^YAnE_|SsU*u z8}BKH!;gL2i5y>KJ2BooFbQ7XAIm0W-4`Z7M&bNE>1=~Ml&FJHME=W?k-pU3&k)t5;*UmkP)LC=@RtgoWDku1~m zrEbn+dHuPbU(vB%mXDb$Q`RT-29ioSnd)VH^Ed{^dGZ?ia+$B^aJ^WcEDPkE*Qk0K zz81@|UYW1g$7L)d%Y8Z0zRZ)5u|FxtvKND1hL5E#PUST?<+?Gr9t_rN#0`zOp@OUr((gBu@h%ywlJOLdb8(sUGnQi;vk&sVJ&vjAxqJ;7r{y)a zye9iJ%gS?E2YD{bePeXSd&>5DaSgbtZ$w?*OyB^m+ABQSmp(q zvMyh)UXMJM9FE!Wu{`H;sY9Q~`OMXqNjYC0bNxZjm&dHHqPUSP)AOZn&SQD~xt?Fq zv0j#snJZJ)C-nxBN;#S8Wqk8^ZO(b}8v1gXujg>RSf4BlSgTcCuxSQO8eLPVA9gQ+Z zCu4Sco)I@J-UsL#x8%Kn{_>3dhQ)DX<2~gIzk5;o5y$C`_mqqG&~n_D|JH;2d&s+R zEZ+&Phw)qP?en*HmiIZy>3Zlc`?DH;-droF}iLFPHgx4%dtI$+AGs zIWDJ{;cKxR>y`O>eO$&evfP&=?aMp~8T*rREPFBNW%yX?;#6LPQ?46>>%m~XM%>Vd z8ya!LVxKYMhW_`P=;M6G_ZybIi^_efe9zkWenaE$DOdFUmd4*xHvXP+E6lgtKx3dG zz;R#x8?pRdkR12r&!+VI&H1|*{Kbtq?z;^z{+@F2{F?XTv#oglu<`el%l{kE#`hZ< z-*4E(MAQjL1QLKIKqOEHs0IWBRzLyHqd)o$I12m#8~}C$p95QgO~AXr-w`+NjkqB$ zMQQji4aaF$ppH0a{Ifr4=ykHJ_-5Y_qVyU>ne|YgM)(GpCP?GauQj_XJ2jr6= zp9=Y`)+)Il3U9JJi&py`@}Za!-#>tQ?024tSE zPSdVwNIeo`DYQ>3%BtCsQqDp4tcTn{i!+|Q(M~#%>ZF51owQ|$lNR)I(v8VZqV_;| zKRnpIb!g`|F_hs*pp?7YQD~lrR-N}y60qu=r^Ox@H3jN@=_1QE7v*en(V{gj@+@(o zT>zsC?9^jI1B!kkmQEgRO{?-fGz16%GV(mbt_-F-It5cd;Oe%)6xA}Aev1yK7i$Dl zm^B!W7)>(!$xvEWH=5F}PoS>*+mo}zfnmVqKw*9`Jq=JP zMubuR@usvlt_>|ILLGqcBF`7#ZU?pi?*Oj?(}A8q5oAY|%CoMb2+Du2Idpcwv4^1* z29pBhfu9Q;05${91GfUFA>Z)=9o?cS|M^x@J|41hKx3dj5DE~mAF^)%gMkAV$a_L4 ze?~K)9qWLjQ3x6*Q3@Jf4un(T|LOH$IQU-<{4W>&7Y_eT_3M8TLx`&ONLI+5#SQ>t zr@{XT^68MzfP7Yk{vR_`p|IWxncL&rxU@-5%A{)K4o9^@An%5J3gk1(_5YUnD#aXC zsme|jlZMNz)GxjY9i0?L$;~5aTxyB`yCI+9*MGb0)u>&zMp0`tQfAG<a@U2b*8}tLpp2J{^3x{on4R8;QzUU zVyOoF|D@WUy8Pb%CwH~dxGq+@9lqbmZ6#|M9z*_*Hrled7ERj~N$#7PQr4UVYWhkd zwSoWd{>?+5mg#vt(?%}=>G1s#88&L04&NUS^m{dg+FTt@+MO}90sh~6OB>n?-){%b{%?i;KO6#l;qexCwZfdzS< z@g0I`3~)Dm|0ei;+h)OJZWv5!LW42rpgA8#ll-)QC@q2ikB9$X0sptc|2M$@2Nigh z!9SJ&8Nf{70pJE81bFQNzv%}5KY+ftUK?5j-yH;m6?wh^Zx`@6z<#?Dm<Aut$+Z|fqxj_{$weT3fO=?7wGU@;QwtQ*9vG3L<6+}Gw>ti)&paJ z-yrWO(*ggVSnB^>;jA7?SDR3d#YAZ^SUCJY1^$~2|I3E|<-q?!;QuLp{XZG?!vB)|%HL#F=o$>Wt#+q~N*N(e>XKO%{5n7+>H_&> z$Y(&F{L0^!sZy^Dl`czDsc!O{7VIdhOzF3V(b14d3Q2+gXJPyghkUwU{~tY9qao8Z z>N#Gc=Djfo2%qAjPiNMo9+yYZstEYb`*D<-T(195htE$+Gt=4gSCPCL1jqTZ@LQ zj-=45no`EY2}E-e$qN5ZhyM>P^Z#u4{AP^#tLNHi-gFxcPP0+x_;=Q*6+Be%3Chli?M&|T=;$(FsPZGk~%b? z8pC2KXK!oDfZz83&Y~Zgp65x2&p!@4)Exc--|r6JZ%{LszIF!F?Pt*(c}lt|D3lfy zMqvm`p!T1^_u%`hfZhcj9<$c~JXS6OW&n2q&46w28F#7Q#KHf!H>K?0Hnae~-wy~a z^85_m4*-wbJAn^?#Q^ssalooldAL^ocKHAE82^u#`hRu!Dv#O0fC)GanSB8J?jt}W zV9EtL;^6-?O2_}pAd>{N2NHmWKxN<*S{ol)$rip|H+U~f&Zq%f3x9#ZomGU z(T`|$7ovwEQ`B22+0mH7;s5FI|7`ewF8tRG`83Gq`t{$}LRHEjm7X}H(9q2H&8<@E zSEj=hM(uMOKo;^D@PC4QnqT>KO*P64*XTI}t|lB3boG*zPD)OwNjudD3RN-wzYvGM z3;v(&cl_Vh#Y~&7FwN6y9y1eS`S@V6eYEYr5;sUlJ#IaYVmvj zKWw#PO=_j>XD#&BVGB*k#xiQj9ab7`sYUKbB58M{rqpk60xg-ENVDLxA@KiAWqPcW z;Oi4?bYh&1cBk6t^%V30U6AK~G?=tK_2|>+7#bJdoI;nhp=t2_Z20~b^dq6rHRxAQ z-1l~B1l0Q0PU@F-`WoZ@Lim2`4ETTA&()~M&yf^Oj%(|GDt}-O#n^ zw5RuVnD1Zhq^quUQu9tu3TlZy0KPu~T{)d~5bbPIhn74ZL!-Zmrxxwd2g2{C08U{1 zInTpuU6cl&9|PRB+(n&Vc2Vd&7kxAheL^byzefiQD+LjxT^CE)8(L#P#o7Tl1pgnG z=UE0p9VnwI}e7`H86?s(nS|NC6fn&fo0QUh4 zfPTPn$hRofF%kYh5&nOm)c<+j9tA`IwE&(Ea38>Z$;$w*BR(pX=RTw;3jSN_|H8!eR#i2$tO~lf)gDuGUMmyB!ck745wH9jrhJ_+uwUBF`g?<=s!Ia^Q zxl8!in(+Nd8vR2PI@&UU!g?msVfengZ0*nby5C@<>#noWU z{YPEYZ-R^J4#PU2hl{GUdB;Mb3nS=ISS)2OXicf`{cvCt{69I*^HnAIFZ}&eAj<^* zRp7s;f~fEJL1g(nh$gIo|1aoYnMOYuMO}W0r;sPxQ#O2m3edE`lMmlu-#r2FocT*& z127x75%?B;RxAaJiCWsi)*r{)tk; zW>ZL{i}dq%|LgZ*kYgQvfvXh~jg*Yw6O>Ua17AZ@i!$K<;qd^^f8sgQd8b(UiT|P03faq0Co`$NnA|`@@R+k+oCp^wuOhEuUaVxYAD3@3hmPo|qGKu+!!m zKZiCt+BT9h?`uXwKW>SExr2A?KMCLGb;O2Kp3e&$v<=vN&Oz&cbtpm0SE7K(N}l6X!ETuTG|tH zf=(`K*$jPvbGeBQJ0obrr_E?ezt-NdKNr5A4us`-?7zUz0rlq~Is>2oVP6n!gWtdU zVGs>}BZ$oNf~eQH{UMYb8%2??$J5bU+S4-lem{T;JiKP+@sji_J!w*doy-T;r~NdV6YOaS)*6M=)J{yPBvA6)AHQ^0u$m64qV`iQEtW?R=5-_h!g#1l9wuE4kWyB{yW8l2SWK zNo(*O#_#JW1=r7p|0esr{wI)Q9q$1vf#;MI*F+_)=2eP2;wXj3+)P>UUtYiG`1RlH zs}UZ8cWuMBPPMvG83mlKjf=UMpzltAajzO3(+x1g(e> z^z`Q^g8Fwl80MJpYs1MylA7WA@c$&g{(tBxGvz#LracqP^x2(e+Hkd*p0D|ea?giV zt4H)SHCVJJ6rq`y;%U_vZRzBNzR%aIzP|;&&vAtGvz{g$T@(#8NOV!{RxWZi zcF~zSF8b2tqQ$2$pZIct`blQj`jpnM8Fg`@9e(PeO!$6RVCQ+yWgCMi>D?geur7#N zyd6Z1UJs%wuLRNQ*+H~*QV>nQJ%~cDd^f0L_;ZaY_qupmQ>Q&XQ}9qEuqEHaKGzGl z5x5TEv6EwIJO=*?pILh)|;8_a#n%;~X5*!1}{R`Q70E?YQTl&qLG zN|Jj4Wx@ZF{Q7S_$b|vbfgm*p8+yZo4l6k|H!Eoovy|kR_DW9NOOy(E@+%(!Io82- zzz|MCO|~CVva5frB-Nj*q(xt$B*nc>Iq=_fzy8|@G7W&bKsCUs=BU3anN_wc;q{(Z z+)>vl?$`|!0{I-j{@d(n80kTUB5%Xz7>yMQ`U?B$dXjS&Z1}3;ZrE4JY`UFt5WmYw z^f&)+b(@J2`j{xTvxyouHlfXEBwp9(yG~lwx8D#E!+(0H@y}WHG5)8v^(UWn!a^N? zu~6bctRud#P{cY51wU<}6SpijZ?1Vq*u(D(j!92Yl!c551>!Drz6sb&4hwVQ2p z^+p?A`L2yRzHOuUS8P=GNgIigh$mcqU&w+wuSU4{jB9%5Xe-*>nfBBbzRzn2C)N;I zCpKu)}>C`@hH|7w{{Ib=Ki!PoqVko zEqeg{4}AY9`jOQ0p8FmOqOri}2Ql8?A4G#j22sz!L3CNKAd0vwh)y;PqSsBIITH3A zYuJ9-zUDOgopwC$r@dH1jL-K-|CX{iUOmc>ga04*j=k)E z8&I|mSPi@hus<&ZrUPRD?wgtb-$Q;RFfP9y{J&eN|9^$Doxtb7r@$s)Ex>wa0b>D< z5pZ9`>l%B(b`yNR31SFd|Gyh;eh6?o&|giZ9%_#3DmAmFTTO`wQr$6olW8Rl(fi=PGnJf{Lhw$yB-pU7njCptp{7feqs+QpEyTJ_~PYSmd;Zf zeRyAFT<_bfv>w0nh2OG3w2*4Rdq>)PnPAR7%mZ>5{Ruu{@J%pu_W+#k*R#ZJ%sY^Pa2*y+jrcAENyoyKjn)8JR^bp6A2 zitgXI`tgS68$I*=Iroq0AGakpd_SYu_i6WO&*C{wdKq}}Y3v<%%t^Bzg1?VMETO-X zZt3i#4iV@F&Tp-|`or2y8$4RO6}5LDc2Mm5bm*Mt?f4*i3wR?oh?X@DqD2uwG`Ct1 zJ!}r55x=;o+gC1%c=Hy^?netE2lVXFyjP9u+EI3~?^9^LXUiw}+-@^scEGzEgX!&c z7-wG(rui>o-TWlR^!qUm_s3`XZ4ZRbt<mYunL$73;~(~9~L}MC-aLMqYrA!I##2-z6HDq zEC*gzbF6dKkm`@9IpL|QJ33jVxCUxg%deHx_O~gyo_;=Ua1CVM237)Sx{yz@%u_?E zO;c0D?@@E3ZcwvhBh~bldzGa2gCL*cBfl0hT!&S_3g8trRhzG-hd!!i)ElX$M%}2U z#x_!uTJBe<{Se3x_K{x?8P>sdcmr4hEKpM`J+6k-9j&G}>ZxWmi%~OMpdV;A9P;=0 z$iD+V>)`v~dw30aUd?qpsixN+tGXNZRx_J6Q*#n9CrKO!`N=-=?}PsyumRxv;CpyU zO;es$srq=88r-6WG-;ux$LA{9ZKp#1Ss(e$;BNw059?q%@IA~`GhGj7-7;|;M^ zHKo9pC7p!|PnM?{yb# zpO4tV!!CN^E*Cx6xr35i>sSNF598f)Ufz)SL~rA-ou@6W^Kd`?rB<9WjF&ihm-tw0u`2ShVA@CVO4ftGjAQT7zYykV= z3HTcO;1*yB!2Q70g`TkE1@FaPQ*Z#W9IPSmIYJX~8v{{51E3C21uz4rAhRFH0_Fj? z1NeMD@|l9*7QNxS?7vCid4Tpn8z3Ht0a%X{I1L%@pWXsER=}|e>{n=fB7cC_|4rEW zqX7z#k9K!TO;?VnIhFURS#>{Aa~r*(hQ!WLb6cPtwri;7dfq`B{#Mt9^zsFeKMfpJ zvnuUZ-H^|Ke0H;RHLJxSHKSc4$iEBuLppgguFE=9pb)ZWfMaTQ@BuZc&Q>+N(VJ>& zv!~S57PqU(?V=%{1^J(J@>a;P4!(yX$esm$QNx`%YDVpC@ZVMN-G?}AP!riJn(GB@eAYY`DcR|KkqJ!^) z@8KlygPL7=hZ{U(IYjLJe=*3i4k-z7ink@|7VI0tA)l5J=BK{)n1t*{x=V zWvOXV8EQ`47&W7HM>X8DAF|Op`RW4|s@7ehDhUb&=VAS_7w1-^JhXaHn=fkmY_{);|i%$%YTusKF>3)w|n9HTv2p_;MSmO>C5_+Gx+_-9hU{ zPK%srZxh%5{;_Q;Z9MIH?5$It__OFo+WhKiJ{Ic*pxGz~#oXm$r!7|5Jyhcj9xy9P}g3vz`vux~Sb%E@}(3^tdRlwTl`> zxu|A!7g>w2H}Rm8zFdcGWsf-{Cf+zb&J*NJ-1bhM=bPT}|D5xlYb@|ff$eB?k*5dRTX!HCxDL1q=qNIs@glc&gh*-V64^~LEp4$~%}sm}?RPNX0(dUK zZJ;OkEPn$~CZFnv7s-$hfqXjTvl6ze*`@MW7nHUkmghR$2wV?z0X!ndnjn&DH4y2M zLBieiH#IdOTTM%R335Y#5Kc?3-wS+Mhi*8&8t5cKw3Z^dMnjR&AVj1#Ii=>rf1!pX zz6`m$fGPmb1-Smb!M~|Q2j9cBz~w+|krWywGV50s$&Jw`#eb z7u-Go>*4$0d$ujJj1tTJ(7}!@XNgYO_qu@Qj3PU4Z8TEI$C;{y;x~b+8@y z96>4;M zYAvToipH4G{CzxwMQ z`)h5dHV!-0+tIcf&3H9>SK_M)FMSf-;g&{cJ-=Le#&as{v}ejoPMQo%dfrJ7KI5cu zGn|w<5ix}kh#hu!(iI7aB{-bq+O@Ub_jCHjzIjcPwj)lQ_c$Ip?`eDPoF{!^5Y2cX zh@Jo*8x=%T?#5?^1A}N}cf=ArL3BfdAZjausP;Fvh*L`!Hrh1&Si+RX3p>VqmG60A zOupwi_|*d7S>PGqY2Yy+4HyZeoPjTYgSq#5%+qIjs_wpRM$`F?2ej?-bD?MD!a~n- zaFzi}fmeVRfcZc=@DOkh&nq!++mF-UeVDuo`$1cnx4Z zvw+FKaDe+JH(&y`6%L4+Quto$+J!})MQA540WSd00rP;TM2dJsB=J_1oG5ihzMzNgGh&bcH0ohAB5a1Ku=(6 zi9FYV<(~)U15X3fL|WDRMN-5NkWhqxGE9bAV6z--`gk>r{nvg-~N z8PPpOmb;BeZWAgpJwHP3HJ~4`3-U|BeHCCGd>?!dbAcyBvPct2wTFwWM!iLHTsz@z zU0q~#{26j9fLnna$iEKmasV#q)xmY(d%(vDG+CsDjuau0{X}vzkH~BpCek__humAh z9l#ODzX{$OzzSd)!1drd@I6cuS*EeVT`xtXHNHZmCDa#L?M^`sa}v)8;2h*vgNGf9 zv$Hs^3Xx0AfPfmGeRy*lwKKNJ9_U#V( zY^wuXj2-mx2M*e_+ClFucF@Y1_$(50iaD4|OlshuJAQmDtn*9fo7TCuaht>Y&v_R0 zIp?|R&9k08J6yCI_-eb0c5KDE;R6?KS?!{CUvkl#GhFoIC>K4^%|)XcxTyQ_Pa~VG z*bsmAwhbNLHs^b8nV;wReswS%T8Yo+fCDQq#x6!Y?%814Is@^92N3tW1AW6)i0wz= zbH2Rig4%5@Y;2#=zs)C|3qALqF7TXyKmH2j0>^;Ez(HUSunl1U=Dy)6U=(m&(Sfi! zMaSJag$FvM!+(pACy|fiGXU#jJ$nJx!F|I^z*Hawh%cJa@ND6VR?8uO3eWf?@Eec| z909%u_KJ{7*&-!8OQgjt7b(qWi|jV{!he#1`oQ;ic5{H!;Ia-Wf3#FSCpcT=)_Y$h zLEa7d%r;{ocLNXs`~cZ!bn;w>UjdfqzX`EdWVt>UA&}3CeqCg{=ZF-@XL)Wck!L@g z3-EiBvJNM3d<^&z*e7yqUx?H?8%1u^3gLD?BXU}gL)+^P`AFa}Wak0=?)zDQb?`kL z2Mz-VM2fmYC zlon|swS8a6HUoZxEcc^D;7R1;n00U+_#XBF+t3HCLm&2%2#=pCG80oEn*f}H>~bG@ z*26m37F>sezz*RK$`Z+uOGJ3wuGG!fXORmEnV6zAhTOo29 zKP}uXhl}KnogixivRHn#g^E@Ji-Bi=2Y~JtI^V!T$9Lhg(NXwZ^hiVV>gr!c&i_s{ zAKN6N-L;Sn1-5zR?T`mn0E+?4BZ@GGC>mj>GuPVbrv`S~bp(COVq1+x-P$&pbmVNS zURRyMMZz6cB$A?vL}uJ?BCR!^rDrYd{xonKzmV}|7@ z?D|5YStL@LoyPdP599AUkeLIpA2hkBe3A<`s9z+qo17JC zEe?qE_U}Pv9&jfRdr^752X`IZLrfm#U<`HChGsm(SH*70&`TOmqJr zQrdn5nHPYOKe=pNdS(xv>5LItC=q^+>CRXA%9Y$V~V`xH~L| z+(e)=%a0ONbO+E4hys38sc15AM4_U3KxzMyS^q5NQD2Lkwr@cW^HWbZmTzq%FXE6k z0IC2*R`@XR5-<>O05i`77v)upIT-hF%XfF}^gOlwgr^V7A93JXz>mNIUD)KACD_R6w-P?6##37qT?>;16Bf$ z05`elZ0&uGzTB~)<D-0$~&&-?YfgUVmRZ3ld|ABOcXOMiZU zzyF~APk;FSsdt@ay}u#;wB$MSaFBXOef<%hcLO~CkI(Op3##fC)KTv%hD!bVHJ^jt zj{o!PcSrKPR`vm{xgYh`Kk7G9JLezk^|l{iA6kqxcN?3~LJb4oi>MZ=v>;Gpg5*QNw!>K7(q$gPJP+7~jF7 zGp~92Nm{h~V|m3bsaP1Sdro z2U~IMuz>kPfBd{jdkuY{2Xq5F6hb2CImKF-3wKOZ!P47W2lwTd|Md8o%^&{ie=s;R zB^XR=8^nKB?no|6Yc7?(GDOD6beSh_$%nF0cCaqrG~$d@Bikr3&NaFiR~SyCzj3EA z!g$zl8;=`L8!s3y8w-uMjCYKc#;3+Q<4faP<2z%o@w4%p5i~-~NHf-KWG0!-%ycu$ zY;D@i60_W_GS4y3H!m_TF}s_ImjGh-fa#yN0|4U51J2~ zst(&gv45@c*T{t1DDbb(QL^uHmf7 zb*itrQT0=|r~&FWRig%}!D@&as)niI>ORf~j8dc3gKCU=SdCK?)FkzYdQ44GkE>~F zx|*S$Rvz`NdQLsBW~&#~Ts2S4SGDRDwNSmL7OBPREww}~RbKUudRM)tK2R&wM{1S& zRIOH@skLgI+MqV7FVt7+YxRxtt1W7)+OED+JJl|=TkTc*R6zZtepbJz1L~mqT^&+~ zl{PCzl4#Xv!!~e{TrStiZ8A(AlF9O{EReV5BiSIV!=%R|%1AOYjUvNgbTxXj9o%g^ zWK1z;8Lt>#zWYtaZoczyv$2_Bwly8*rRH_!9p(e((Ok!vCkL|UUdN8K6aiTXI|mnduWCDE?vSEF}Cr^H+mX= z;Hm}_8h9K0+#oB~89O&N5NnI8iSxxZwm27TMbrFGLOO?NlFJk^_O zZRTpWyV>QB+DHC>D~E(%t*U9Fx6wRS-H4SrDXcEGvUV_w^?URp z=(Wi8YXMJP%j0E*;Akg{@Tx;O8y?M?|Azbx^)Biy)H|uySs?Xmflpn_=QsG_9jYHu zGABR-otqWG&SYw-_hw3cFO!FQD{B$Gr`C@~rQVQm2e}n3_yPS9egv{5asM>l5B0j2 z$w9sDC8#;IemF0?H{`*pS^R335hJPZHkO)an(;d5g<>}?o}>z zBOHD~nC#phFPla;CElT>7GPqbp{B8%Dzb=mbfy zk;fZ-xRIpZ+Cto^tz{d%O!8KH@v#P>jO_4+ZErAS>GYl!TuLpq*ia;DFJ{C)%Jg;-WVPjs1H z$G}h4(u|dO3FHWbh?OtR@i+cE^;+Ol{7-Qo%^``Q4;e?;aNNiIud$wq|FH`ViE!b+ zb)=Hvel}j$G5>}7?uX}r={I-bsdIo1DSyw89TScU%s+R=WsK3R{d)$Bb>HYWP`#N|7+|V8N z-xMu9!;@tA>sC29xRs>-2miJEWsnUqu#Jy!Ru1p!=6LayHIoqhUxEKa|Hl7XzOp$m z14e`1h1+1~*iacm4oL+5_gtJKJ@Maz|C|2ezji+rEFiFrP3R49K{4S(tMI=Q{!hdI zTKw;c|Eo^$U%NjI#=~&v3mqW=*70~Q{7=CD@%X<9{|~;|zP^tkfd9QuVOh45=zJ>T^i4^SqI)q`?1b>b3v1ncVRF$NjH8<@pQq6q%U( z;JBo%G|c`fOv-NO3%B6E&Qdr&{{OxIvFx@Ythm23gzayzDeHcYmX*&omV-JAL685s zm-+bke;WU-cpn3MaGy*fscsS`bKZ-W@q?Sn%AfGxpM7-v{~P~T;ky^+z;Gash#Zn= zaU4h#C;qR*|Ba92^BJ6e{4d7&JV*tBjrczeDz9W8g#UpanKBRmJN=FS^a|Fy@8)(m z^n?uX-x4ar-%OOci&{t*{O>r_CazyugZmf%lWmqzZ3q?I>Gkr#%cWD z$=AOUJkSp^VAazp()*h%@!`J}{~h?Bg#TmC)c=R*Nxe{C-I@)YdI$Rt-zok+5n$T>2D|_6HZ?-r zk^RLH-$fkBRtey*_FwlxYyU0OpX&dEK2t_|Oc~b6tj{6o@rEOgX0;?tpx#QoCztm@ zz4x^9|CR^O9!uwPV7Fau?%+MfAul{-G#h<>QD8*a(|eV`opAf zNtjq&VG@zCBUJiMiI=jz^xtmzi~k%49-sFfznzEg9vA~ou)@Mt(USCeq7=VimBD>m ziF0KBpZ>f4oIC5su<}mzyN!T7c<%)l?|4+vC@!$eI z_wNJ=u!@w=elI1;w)QQg4F5CmzdQct{l)(n9M$vwI(*l2|5f0Devp($Fj>=Pk~cR? zhT{MD$P&qZqe7e~_^-X!^L{<{>$!h-&~a7*ULJSA+ssEVX(5C0f5nq+WfT6-!rNN> zUr8^-iSuVY_um9wm<&!Jk5If5Q>6OSEb-n-rX>E`@IM0oYtGdFN%-H#DzogZB?14P zODpPg40ImiiO>HZ|GY1r$H4yux(}gD7UKWLv-N-Gf5HDg%>V!N-(s+fxTE&k}^_fyCJXzC*jH)kx}AqQzT-6^()J_0LirP_Kg zS%zi*;J-@etL8C&7rz-0N91O)#D5^xx@ z!I=M_>i-zV{QGMn<2^Pu~LMzXWAh4ik=l{xtDeW|^;@U{m3 z6OQ@6AIG)(epm&yFdDi*1kAfFh5WHBnTP*%sil(8yQ;pAvCEnIZ^!>`RyKpytWY7# z6#r`&|Etf&|79opKMViKF*x)62k)b91pWteIG3RNkdE~->%Tu6y5av!#{XsY$N!^n zZ-ikp?lG*PgAGS?Kf~3qhY?727&X>Z!;-a|^LH=e|M`D&{*D%08E#nQF2fR1V>qMw z8vgjp40m#cVY4P0zRVqDi9RQ_gpk?Te|S&vZz%Oc;C91l-eUM7t~R`uON>BLu~C~A zXSg%JCW~wuSwd|5)O${;zb)R7{$J3?cz1oCN!VqEC-ywUotR~Ko0~=;<5O|vJ|Grb zbE#$gKGpxL7c04Hf|4s({M+@De;Ma}-zK`?0c+!ihNIbTv1Tk1Urs-96*4GMf2#lI zpC2aYwF#4|&@d_fH@(C;nV~v|WWT>*(~m~iwwNT|>D{Ac3f@nwj22fmJwGAQa>=SF zNgsVnh@_UY`;2TM8^@3%+QTLTwzre+j+6Xvxh_VU;eEmi@pP^qiJsC~@ zSSsfdvN%R5kh0&3Wyb6ZsXW2|-ng#E{4Sv9{TZOgejo0Shq4ZhWMyg#soaw*qsO(C z$@s6mO~U^W`k}V5?Q8Ehf}Zy;glRAUiXp&bO|D82>-;QnUtK7h@PB`=D)G|GlzOKA zuMU$yp;d;awU(Wqa*ls~g;e9e?QHz-ga3BM|C#KA`jpjYndx5UvvU{!_u+pU{vXdW zuSxYDRiUTiq5tX0n(XE<74ZPePVhNImF z%-_#DzTZA}>!+R`LHWw4Q5y_jOY=h%176l@Ax~d z#^Ob(zs?KGe9gD8b@!xr{CD7g%}L|`<;}4NcC! zo3_^54UcUF{!TT#72R07?&ou7B3J+Ucc`!Bz}WPdrKTm4`~gdjX-Q5qy=n2LJM)Mk zt+yI3+dG`%n{0S0x={ZWwFSrOE2uArGSe%?^xhSi-ncB&nUrce(qc_V<{`tIyO}JL zrDPGf4Ohhl)UTzs#j*N!)RsV7C^X$6Ii|Zoy6J0@XjV6mFnt;Ojq2QuWSP8fxJt$t zwu<)Dze{b*vHF5HMe^_CN4^x1Ry;u$KA|978a59X%aJgNAx9wm#xObZUS{NvFE4E3-`mjop&_m28n*mVWEnV&>h_zY z+TQ7e`XIT3NAe@(P;#UkAcrilJVJKd5Fs14&yLeMB=f)Bo-yIx$6EI^0&QXpTN(S2 zll=FukCM$eziBz^b)SzC-$?Su&X1Bszx-xC_rTpv9{%Nx^j?R1>I``M!bl{e<=YFVb5`Hd$hu2C{u!Wy9zCu1c?3H8)ox zdbO2^VeRX)(8xg3pMT0zWc)l4C-D>L^WmqTgN*y%;{I|gYxj4?O4k|q@0ibZC2q}< z;`~Axyr&(Ja8>m==+y`9cjNzHxE1=qMUVq0dp$5z<}6E-ynVScZGMq#nouDD-1l-0 z;gtLSwf6Y`55)gq2FL#RZ!Z%E{*z;J=Jon693Njt9yCxhF|#nkJi%nL+|~A zrX}Kj(`LEXtW6qX)}#$EotaM4m)p&B+B%qllIEtn;vjYJz@4y<`iFV$G4K$KHeF#O zO^LgQ9FoDNzxgeuCG%?2o!iy4+A7FGNHv`m`>E5t%mZNu^$$|_0I+mbMw%{luj!2$ zYC4+Kn1NP1@h?~_^&baGM zYs!_Tw7A5q&aO183tE`AVnr|Hdg`V_g}$Z!wyt4vYk3$yU53fcOGD)bPP;j;$cX6q zYr`g8U+|`#WBRi4O-p_w(^mAO;b{Mk;joXQwh>%Mz4Mg_>GLetG8r2oy>5(<9xWo| zQnH9TH~%iy(XL5q;e9JIQf|4nb>!Rf1 z3!>zFG6Wpt2ecdeg^}Ili^hpp4NaGJt#bV5huRh$_O!d#kPgkLf0$bBUujm1v}+zC zMdS$BjzmlDH__5!KBq5lieMu1mA1fYm2p=Gatf$d6Ir-rZS95ZmeU#e?a6jn0ADu(o0pj4ZjeSCf4jz~$2bbnb?}2m=?=traS3l z)0y_JS)I8Uf9ILiwi%|sWQ^&m(EV%GkPUm;4vy9`hc~UV(e#I{XWRFgmZXnNOWHf8 zHS-PAlRMY6*`CDThs>Ia+o*{SCYf9+_a=FHk~aOkj3;2SuBr`r7+xdmtRj^ zM@WPX)PGW6!!@nA{Se+aZN_rb8T*#$Nq*Jzrq400+0#vH!C2E$e5V;`-^=vdE2)i! z52;_Vl>CtCA@a^OA>#c($=huenJ7Pnz0#zn@r!&1Gs#kU#PsL6OiR%%WEpfLi-3KR z{SdVaVezhTdE?7)S%mYijSZK7w+ok-mxjp;zyH$UsYhoueYD-EjM2>D29br(+YFSR zW7?{csozR1nUnUHevgzFe~OejTO#EJGRdBuO8?&#k>uG8l?gYNH6C?eV)`8|e$95C zyS1>hS<^1p^j9)3vcF5M?gf9GtdObX5Kh7QN2f>2q#@*xUJxy#%xJm$+46{6TTE}N zb4WVhH#EP^hN;Cd7hhKK1$9#(9qt=OPRO7JGMv1SVOKPeA?3^inlzA`zlo7PkCJiT zc8TTOS1QtTV|(RBw@Yd3kH4t>?8pQ5OMd*(zKDH@GmCM%Ieqs{a5jqkzMo>HdQGfc z{A{e)$s;RBiIwEnKS?@LayWCtluZS*KAhXG$Kt4}FFO8akDc+Wy_~*$ofTFJI>$dB zGJ(90`ux7%zQ^Y$($tbRacL9(Ju$aq{B1?6J6&DTtPB3jA-m27It2O}B09hH2iOKW zJ8%We1$`}m?uS>$h991p@pxTYp^PERdB^hXR9TueR+15;YI6+bEZlEeOSY0l zvYMJj@C4u^y;S^237OCm(p7a>Gv$v@Qm&@)^ifBsK=xs>lme!wc(Ykk{xLPLz+}+- z!u0wYeqrF2*DOsTksjuT%90$doasvWTOBk5`MbzM`NH(If6w&V=TSES^u8!1Xh`zM zh9uo#NaAV^S*f=uS7^cwPez+PeZ;>4`J51v4 z50eJ0$B$YYDq)R6#aR7r%`e_m2(%y&nzXk|!bb z{hAe#Vx(~_@k50C&gIVi!hT%e zUllDs7evdCi2E#Y?svj ziu-=C+o(Oj{^LVjU-?liStYUZ-Yc=P{OMSEn>@nTFD8F5HddZn+CZjW(JbkKPnTp4 z%$iql`NiYfmE?ZeA!O7+`?9b1+h4--<5`|B@MoPX_%u8Y6Sv^v)AavdJi@s4n~BXk zU)43Y_3IsqWJg}biZ2e?Z@Ke#yUzB}xq~{x&;`R`2lIdvmA zl}5J${}u}|5CIBwhWQ@&67)XkdAJ)&z*n~{t+Z}4Ipl@){*PjNW93~vBa|oPUgd5u zO!=DJsj8dTC|^cDaya@Ze_?m!D!Gt8xOVhzw1jBb$9HhN*2QDor`)VA_r=_;9Mntm zf%w}GfBWF?WvZs+0{U=DsA~aH@B{U_PBQ}N`#0`U?&zV)*?6#WHoHwZGHxVC;A-VA zB#WTrd=)4!rp^kwk99Bg_tihIt`)fl?pA?_A*!~~?aGxpK-ISFtDHH#=%J;5y7*lB zaCPrqa|i>S37~6+9b+iBLzFAz4pnQpjUMEF%GKgpdU$&(cflp9rr53=<+^u}Y!JH% zx|e!LeT@k3R|doFKyCCb%9+$x`K`T`yVYf?Hop@+c;(8|K1X@%jj26MtsiQ*zh)rZ z3jKlX1$Di0H@ced;0kg`E>X_BbCjoTk@A+cQ2we0)c->5=g@B^*HOABL~gQ&$PKH> z5{Xmd{M?XU${BsRa;99O{4G1G+T1ebXhSYaX_E4H2%&yAwX5Ko{tQTm+D1fa`Ei*8=bqT$lAWbnVnBBX>(<57o$9t2dMiRmO?cdBGvT%cALa8 z1id_+>EY=_|IT^KBBev;$k3AKdZx5~yfm}I z_WQ{kydy>`E{l;;`gPiV7cF`80k&+_IX3yRtE@4rKg>D&&YU*8w)|SQcIuY;efSjW z^ZLh1-c7O6x>u~^bS8(GzQC4ovC?ca=MQFbTtPmO`YJE+*RH)YcTDYHu;!(!+P!(> z;tn&;JzyU?_D8$U57Sve4Z#Aj5Ve)LJh>rNV5-rXppTuiX z*Tqx}yWo)hvZcS-bGmdrW5l>dc_+pfkkQfzBdZe8e8}!jWLhNuw4N+_7PP zX*YAJ-THf-UFV1TU^RRKI>+!m&{>9y;ANNz6JgkqZi&t#%d*co(yge`k#3c1rUd`U zL4D@f{hs7@D!Ac67zP92N;ns+M+(z^K0Gu3)x*KkOUW_W!1ktD59?HoxrWPnu2!DL ztCYLh2g;e@Re_wv%2T+29<=9_R7_#pc>r#QUU0lt*RNI8#%IbFy;@ltf2psw<&#RxCc{un~ZRDq90DYvqsqeAvE~5u`k#ZEitfb^w zrD=$`(y_0M~>_A~yxS_Q&ZDM!PV%G>l^Wo`MkvgEv``~`DWZLvqW${(d> zB-{qLW%t!Tr>+zE6jrHf^Fw8edrw(Xyoy*~Rh|8caum!_w&JIhrF;@K_rWcoGYwYN z*D(L*_9Ivc?NZN{mZ(tA~HhyK*{06Q$&8YYYQdF%BBVX|;wn7k4lCbgYI zWnR+|d7<^1c#ra=O;cP2lzr$(jFIDB$-7epif-gP>`q-3WWv)2qUEW5ur*qqTpcY>(EmGi z1jiB;(K2CklstI-n=$t;Tbwp%>(HDVd)?ILivA1B*q_z+a5tiU!ftXxzH1=kziJ?3 z$q^Yt&+h}{8pud`e(!12KnBwX*#Eq`#?HBiGA`SiQgGf^$?a^Hjp>lw@)!FN_8&t( zAlr8tdA;=c4w=hX|2Qj9@4^{+0dJ%Su+PWj8j~S#@u3dQDsOr@N9T|vzWY^q@WJ2h zTRu8yce20e1J{7g{^|ui;4-)b&Ig?ZRv4TVWt};qWn5gJg5R&Xt<-Ge9tgl*+y0=oB>{(B$2rvds`-Sp5_7jhqZP<`b; z^Oy^bknx+>Ko7Dfo5!QxSzO2X9iV0ldOO`=e_O9#gNyf|zXK~d3f|U-$PxLG9FXnw0dJu0J^1&3thezRJmfHVTaa^- z`-`fz?IKI%8+yU@YuE3+z7KjUJ-Tm!&I33^|9=`RJHAcWEOlft{lXk(uksaaQJ#_w z%2uhf3|@n0Ao%LBe*baYa{07iOL&WQ3~AwVup&!-8Zj$rcmHcMwy5g7jmlH>G2h{m zW6!O}f^h5Ww9sBe2^1H_UW_PwcV1FOK-aE#-+%AV@@D{ud3t;vkj_;qeM?8|Y zxyAht#TE=Ahvb^CdfP9U&2`lHca6>>)A?a@Kp^EFUJzW+tSGoIFEu!+)HrPpfrIVF zg@1nhbDZE`E&jU7aRKK}ES2dQaS2# z0RDW86VTXg%>T#^Tw|_SM{WD<_+y$2b`Gdi&qa}LNd#_fTiCWRipzj=!vH@}>}wb9q@*2JaSm%d64 z0Z#rCzi}U(Q??_R*67RNh*lrZ9@zHH@8(xLf8enF5Pz@v9rXQl4%siDv&i=WueY`eAiTg$drOTFg|{BuO`ykzHi z)9@C5E!5lewoCodZSPM9{_36ne=qN$ntf<3?syo#t@vMq{~os8+B5W*_}TjJK=9v} z%V&uHwK_-SO#RiLBXbZ3p8?U-D!?4fh5v!dKVQ4vkDu=KAOE{ry&q%_;?i>%zC%5S z^PKE|9P{AB9ZuTP;A6kN~d$tVr*pU}3 zYQa9t`{!q%vw}E&2y(t4xEeTq2u^}tpmRmuVqbC|%RUaYTKt2*(h?W$a73RhhweuTBrfb;u7Ej&BzX|EelD@VArePkgM? z{yAs~&fb?r-dWpV;WZV(*8h_nk_An9y?MdlzIMU?mqYUZa!BO=<&gaUIfrBv>)%`* z>sxSi8_xgb|D61S9taiD&8XE4d1c9*-AZEt7kzwA`gn97uIP3AtfTeY_4<=Pn8m*g zuQsGusQ1yp;-!z+N_`FW7U~_;>vjD8W9#sJf7a^9@$l|-GeQ|>@K-t`C8pNG>qz49 zn^Tj)qf=i^eJ%Aip1=0w`cwu|fmM&P_Iyj2to$ri*4Ywy4b>i0Sen*;2 zejrN@-k&EOFJ&FEmHNO*>j1eayd-JuOv2=FnPxfZp}SZDd{} zS~TV4df_Xt<7*3mAGjX6cwoS=Fv-3pQC7Z~F4bRT%dCEdGGkGRglwpgg-5T2RR2C` zHI|;B`;Iz-?mw`=HXe6gbOUjIoXVBFD$>*SZ4VS<| z&})yU!Eopa*|4W~g3Q>HE|pz!#rtF%$>?7uy`#7$8f%f4@Hp9=Yty~PtUIh-wz))3aR7WtIl>8U^Q?+)_+-UU%Ie4tgb z7w{U6w3Ut%%em0Fy?!m?iTC}_e@URK}#)IYIc(&wtWmE^B&p9r6g) zAsoM^+FxGpN%ue9zXj<-(CZLc3&A=B1d*2H5U{Q{G!6fo;(ufOZ-D>m4E%30{AdnI zBic|1zKEhOKKyL_ACCLoA>mpjv+!Te(tqv#Hg;dNqv)YsLk0l;*ILiq|BZOR1SUfl z{9lLvsrY|zd8%|g1OMmX{4^L2-NAzY7yfU$BTuY<ZtXW+jZ|M#!2kjW?buiftsUBCg^5CMMtpN0Ru@xLxAi*~Sl@#DV* z|5xDcX#B6lf9?JoPz$qQG7N?8kO4cpB*--UFT?*O_@9dZ-SNK~|8+0&araZ%)-52g z2k&+N!7Ql3|2+KPg#SbF|6oizapJ!R|L2^6|ND8oB{R9m8~$hD{}TLn;QuWA-*Yy7 z2yv(SfA%><|8@U+@rm`q|0~5G+Jk2F%kaOe)FfXZwP_vjzYXJm3&wvwh0~7zT}dXo zB*9^HkwC~r;*Fv%-huz^8UJmJ|1BB+8~umzzszAsY0}XglA^xVkv9Bq&G_Gv@jsdI zpDii(KaKyEbu3&)+t{I_B-*kjEPTN7SXwAgQ-Z9( z|By5A-;MJw=m!o6(3m&?|L5TUaQvV15B}?MKO2(ZAnvb#!52nL1pfEKe<%Le;{Uel z(~tjp+}G}pfx*xn=zNl$N%1li|99fQ1^-v#f8W#if870TIKK|wfXU#zB}|g=|BWXY zd+~of{=4vh9sc(|!GAsOYxnioUj|kPfsOd@!T;{~AHe^?_`eSSL-2ng-u69~MWDxh z?Y{0g_JHm^91PW91wZ~z#(x|B*W!Ny{&&HD))5Npi0j9F?Y{0gih(+u-v%qe0|W3s z8~-=re+~Zc$N!%AKMnsqXW+l?Z+-*+2M@H0760GB|1$jd;QzM&h5s(b|Fh2_`Y-w4 z?T_*QRs4Td9Of(dUyJ`Qi=*Kj{C@`jr{Vtu{CDC1K>Y8;{Qq3$|1_1^&0}-eIn>V< zhw%bAB(w0}ga0$|e+vGO$N!P|e+T|w&-}kDeYhp!vnQS~|DC*%>zCAW4U_@ZtRk$A z94{WrL-;=u|A&e%<5v9d!~Fje=Kp14El>N){QvghrqpydWnj{v`W%v*Lzc((6>H+v zVrkx;`TvE?|I3*F6XsEDInDgPv?fH_bq|r^>=0?Y={d8Y_jA!XGqxn8JC~;>ii*-S^Bt#mr3jdw>zY_oV?8p^2{wJKqf9<^<_qF?a?4JXp zp$qb=+FzII>F{S#n6?ym&*AudRS|J(4tFaEE< z|NTA7WisB{j`^>>*Ykeuz8?EWLqF&U39t_TN8^76{?Eey5d5#if3AfnE*?jFf82dN z_ur56n_vm(j3eg{>__l_75?|d|DE{X1^>t3zxxdQ-^pXvPKuHNeXNpz|MT$QhX0fC zf8*KsA8ho;{Qn^H|DpKrKim2Lg8!ob`|9Wa&6s*OGi+w6;SEhOYNC@2N5cf8COM8A zfJnoUX&BDj1Ngs70>xkA|4RIS1%Ic&9gv`>?&KIWGJGNNMr~A_;faqnEXm=9GffOj z=0W`5i~oN7_u>Ci{GUyo?qj(T!rF+0a^@h!a42OsSPbj292Qs7L2^WX#Q&Z6|26*m z@ZXF7FXR7X)ZGb}!tQN`?D87&{pf4uyM%v-ZFAPfek+#5uke2z{(p@BUi^O*|DVDC zu^j)`P*)9v^VpY#gve4Z-0}7sN|y9}%+xs~uSIN0Sg@ovb+**BoPqxn#aVD4$N#sG z1M)Ai+PNUMy%Ff+-#hcdWN>Pj+))=Qw|hh7*1nlx{WfOAUwiPml%5NJO7G(Fx9WiZ zc^v;YKF#sJLGFlbf|W1_27t9RTIRGP18jSmtQwsqdj{pPQ#k$j-w)sQF~1)7`S>IQ z4jyDb5ah1pZs_ze`Ut z{AQCQhW~v}@ZWaKdp%Q20?upJ&;1wT|8V@z!~a#kXG$0RpM(EC{O^sozGGPgGjLoV z^SeR2UjzEszZe8oR3^|n$ZNoVH~t51VHm*w1pM#B<3!-6_Fm8XwflPP*K_|`7!B3m za9n`@OYpxt{;$LTGW;Km|3lBf|4lsZtPxSt8~-El--G{F{2z_~E6&FMefY0)2sr-V zgZ~5Y-}iste>eWR4U0L+s12QHIHM;Rwua*jXYv@slXkyh%e)u=hZvs10Y;$sTCVBc z-SFGbHv)DWB*8f9>DM>L8QzewhC6DE;f{X*|3~6KhxVC63|sC%!&P{L;V-_*s4l<6 z@Yy?1*9zibB=xR($RRVVk;4s_WtdTuG{o>XzuoX<^fx5;disE`G-`{x8rJf24c4Gh zmjVXd8fwU`-=fVk4(Xri3A>pbk{b<6;&q0ld2hp!aRq(E-HbrN1%|V@z2R@4ZPeJC zP$#e*f4g3-ND# z$N`>Dof~e0m5lcvOoP$k@?P(7c_$-Wmin@y7kAG}e8sgsZBFs%tmzqp^2Xx-5YGSg z5r2nssY?gF|2Yrm&n=4-hb>a7QX{3jE<#GYJEdU2K}$y6L#c^fW@m)=#{Y#OZDfUU zs{eYtp9Rxk3=Dvd5K|r|D=s1n5&!)wv&Dk{n_egp@45;Ze)PHZ^Vg5}`h1^0=0Aw@ z`n=x?mUBaP++28{AHV8mL^#>v}mwW?hmcl@kic zNNy*o_}?A>yZ?j#`q+OZxcNb|6aEM0=gJuTkHG%{_&@J#{NMbi{~PhYXB_7~&es2# z|Ap~?ALsw{{Qv0q{}b;0XatNO4R>gO9HM=OrQr`ob@Fcf---X*@!yaCU*i8-{9lFt zx(7}7^1cW^P)|Q1ctZ9VHBq|_SN!*eB!6dAr!h2VevAKK;s1KWSG?MAlz(7&>-&gb zp>`I0N4;i;VNu%+iQHz?ShgC@B){Qn{x$y7vzD{Ya1^e_|CRXfH9Yp$se1`#fX*<{ zd|_C@6}HiE#crUbXPqIaghB-)o$B>-u$RH(q&1)-}J?aFQqchX3GAYeCde)ojP&uoD312A*}12 zc-|Yd_nn{&QsE%(uYl3131Y+lmH6Kg|7YO;3jCje|2m6gBaW{FJ?5`~g)jq#Lw87h zn&YacQe-s#C*l9JI?iDps+4T}xBi3wdhFMkW`ny$NnSUrtb00F2K>-gcHUbqUGRU* z+4#TunE$~7@%AZ|O8ocyPyAm-AL76wsoTtPSnw==Kj6L8o$UW5oI1b6^cr1EXJ{AG z8r|8Hh8LUF$rqXKvrSl^u6ZV&6>hW(^p(-I?CJ7hnGVgc^~!H6~2J_^Xu_*jTCBml0WjRl2n=ynhsHt^3yw^$ti0r ziECUb38p_i-t@IpWhyJ zaBoQBFYmpZ_G9Rvti6UaZzukLi~k$(e>HXQ!D8^e93iWpfkz_b)4L<&lS?Ax;|62o z!{7emtr<*&@{SJI>K>erqxss8YtigT!I4LS=UdU3Qwy+-E1%bc=& zDq2Dxh!*pPXgOTWn&SO0#q6CmJ#|ajuFUoGlJnoI+gSAK#tX}*$NXv^9`TdCC;m5O zo}Xgl`sH~IqzT?PjAmHMU-03nI|6}mqiT}fYBS!@PcXAFv&-3Sj z{;f}YKOP2yc0UjH--^Q%QluyT?-@@PBK~{ve-G|&;uxY%J8>HP{M`~558Vq1X6j~@ zTKw;b|6cs(TIkaAZ2Vt<|Aox|@qY&XC*l9_v-N)xtd^ zPneGQX{JBvanqJYpIF9YrZx8w{GW*b{2xW#y`XzxAE#b3l^m3*W^Ke2a!erU zF|)S$qxkPO{W%lye;odklTv;^{@+KPe(pQq5o$H=daPlSOh@cQ)7xZ%>1#F~|HtD0 zL-;@1tS%l&AMm}Vv%Y_M5VZq9=bs$sLDR3ZRH7d+-3g<~AsJ;>w{+qEefWP5{@;cF zci{hR)af2#eNE%LA2sFf+n_CZBp(?vwE4);yHaW`cbd+W!KN>L5dIIu{{i^l5C8j` z?y5f2T?zk!8+MUBvIbruzIaHeT%Q8N7DiqB=+-8E3SLROI?S2X%XH@TFdc0#Gc9G^ zOn(QRqrkq^&c4y!xgbJ1lReV8VT4@#Yq(srG+a8})CoGE++1nt{q(>RLcDSa(EpiLE^VFLY5A}=5c$Q=QXBq1~Lu2LX z0kQIA?^v1Ik!zf1#L9yQ=|%G9%dJE2O}X0IA?w10;|mJ2>q;!c@n4_&AN?2q^?ZLD z_+TNp!3i1rB4tyRRa_HuB?14(VM1C4P_TP11n>htfhzEpR?7p6@F{Fi@(ADFY$i^b^5tKf$h}) zi9eL30I^$5Pm?XCx7oL*HN$V#5tlE z)+Bso)}(%6I$CZtz1ifW6s$FUMLyHn{u6QlKBR61EQ2*!M{`V$XPJCPmWt1GSyr3X zDW8%9nXIZW3>!AC0XTvivZ&0|*yDnVj{tL)7oBL~+yfmF<5KV?y zX16^*_4!Zl$arq*@?4J@usvl4+C72)x_@^PJPZ?Yed29!BXo_F3GKKBxfvk^FOGBsVrjTD?EFQOjHArl+LURl;)>cOgzFMqZF-t1@l zhVx@Zv%UkgiIuhKv9cyIR#tCsAfGI5ARmrwAS+6)PFebOUe=%MNgqSLMAb7$1q$E@TS;&gL|)Bar_{3nNS-o65<>{cqZN2&-9IE#ArLv?-deneN&G=u)_P?A}tY`GoiBd$=s z;xc+j+R=xnd-)3?7r3uz=#y9HD0k#J%4c!V|7KT`Rz(g;2W82vAP1y9eT1dTMvg$O zy$yBwK<0^^`^hm(yRt@9DPJ6Qi5--?c_ldpJa0~W`WQ=;I_(L--Ftk+AOG` z{y62z9a^q@4ce=kChe7{S(&nAw4)EQm_Des^g-CTo@l;u*1v9DtMd?wss9s)QACbO z5q;2YRds3``j`v3j&A{d$a!2xGl%O5lUY)q!;nU8Q)o^7@hp_1w}FrxRc#@UC8d?B zP0v!btuj5&O(UpA12X#KxdFNg=L`KY+G{?saT-;Il!{4oE5^gW}V z&)zkpsPH?}MV3o#g`YY-2I&3py7^JE?j?8@aDFZMBWo^>lFyouY4}lO%<3C&PF=NY zW#&gI5&0kNdcEk~4aMclo~DPB+Sg#-H8C>pD)?87%*FY+1u^mx-oLmbT4ui#EiYVm zPow9|C)0Hf$x}OSZu3OSMP*Yy{jSRW=r8uMR|V{M9cdtU{Z4+-Pq3qb+_{0?W3or? znBG7Jk!>`vpn=@Fr84D~QK?xs#ttaBZpiME-f!-zyyBhT?A@+AXwRQY_Rynok~bDc zu`d|Je&Cuo$v&4J;1qIzcEw8COSeTfy(-q)_{hDvaSwjoHsaR-<-v36?E9}hWS>p8 zhvo&)c^|VtXA8}QCqd_&>5Q{+htnF3{3I^(&RaJZ-0)l1((bn&sXAx*VS8`(6}{jp z=mFiKD_jU2pbfNuIAGp>%>Qmj{onLIIsRX8%>UK(<3By-GEKR_7BY?g`Dw}#|G4re zO;xtEsVa~$Sy^)*BZJ}*{GWvX6Yzg5+nw$K)p-E)x64r+T-VbUIaRqWQI5ux(8ttOricL9%G8~hEG=RxXG$Ek>_mwsB&jKqP#h7 z{GX^?#p9KfKaBs!pW8+KBh>$iE%XuPYTzaZWs-6=o1`RTf~w9Lue=3g$q^WX{|~C_ z`q!;%hXao(nsN2`xOGI0Rg%E{Qy->(W(PJzBZpwPvJ?#?N8~R2*Zr@z!>urs`V+Z}|G!K5B8Mm^SuW1B z!OE632>)yFpX`Lv0m|FqX6kN$>)_@mL*(ZBp$B;+(ZHL&iEy=>p8GNGMovrgRn-~S zr-Q8;T5rwub4;D=0AID?%b?T+P*Ncclk4G4%ugH`Q1K*-u^pJ zU@(8a0|r42+y*)aq~C_k4R06~%y2f}T+r)(uojNjiget*aK zy&ZqI^11urYxsfsqxj4plrLg0W8YroNZLaW?r!DH*hP-X_vDD|qz`!q{%@lX@LTFO z!&k6}`lDElJ<1urTRGx(tD3}JWbo|bTI}DGBlexL6z(7gi2Q-}Ta@dM=l+uV@2US2 zZ^%w%YrxO>O}-AnpTXDEA7>MP-lQxco0K>1E9Fc6Qq`n?K@a~% zRh>^>OVN5&TegNA0Uvdrz(=r_niJ7kENhfA@-zA%eaewWrc2hR^f7*-ENwr=fAUp2 zyieV`;Dz@uGvxi&u$wHCyL1N1QC28V+`IHKzoTp!%gK^khW~FXU%R)sCj4URUWZrU zwO7OBHFC^e8wb~uMUnz@{Rg*i;=4j?N07B=}_jC;hhVv= zWp{j0S>5WOz01eH*xT=pmG$hXm)sO9#pD{b-S8AyObE``C zytKFKyC3T8OYvLt_6aQE&u_tEcmrO8SE2UEzLa@KM&!&PzVx||mQ_5}E@RhF+kvhk8JF&^c#a;o>7B(mNiBE2uiMthC)pIV2AHhi#Gc@6vATf9OzubjZh#(S;!u=_dfh|sqX*VTy_wjFz!zevhJU^QeREI&Osr@1^;<$`haWxre41WTS!oO>EHFz`)Z>H*hl}X&N1=O zLu;kpa|V6HPCf%?BVG#`06yKrPyefhde5;wWPcT}S}s` zYv_Y^(8sKMaBJy9cK$=XejJ_U;?w=RX`uU{>0=h^{q*4epZ4xP%8t6u^LW**^sOYf zAQu>`1#*+nf<5RD_$B!z=_0?R+6M;MScZ9U&BN^4Npz7DC{T(;ZHu%F4rstafkid~ z85sv>;|w9StAxy~jUWYflFEau<+joR@&MCnBIE(=q<{Oq2*-yx<9PP3J!j{5K8KIL z<5#-Bxv$Ps*Y9rpJ)c9qjE`X>pTi7xIKYo#`x*WnJcs;i&)~K{kM~UAIeRk3y#X6Y zH~A3H7N7YTpT{9ShC?&>nAt)5$DnTxKOVpN9CG{a5$-WFi^v7UA>ZN|;zi_J^~QL) z@5~e7P3Iin@R;}ocR9SuYv3sV-u8VqhsbC?*&5wIxX)}f;|{~?$>Pb@OP!Og7t2Z3 zfz|h%y8qxMXYHF_o%_PUKbra6$k{#5KDc9H`)hbb$_Ke;md_dme<_I}UWww%o7 zEl|fA))0?#eD8x>PJil!|9#Gri!MC>iJLdi`OfuE>2E)9G~BY`YWr z;UfOGZ|2|8+qv|OT*5#9h_vrAdJpL}-#%lZ`Ovu+zHq_pd8;0pKWk__bUCm8S~}?M zOd##AOYN^i2KOh(FUYa+51n;*+?;oC{GoaO^c()y<99u;JBfdZ-;MYiA7p+8^8?JcpF#hZ{I_5C?K@2R@V|#U0NVFo z$o6ZO`91jSV}8%S;(tA_*~{?Xe*V76eES}xCiCrkh?>mb&b<6JyKTpBx_$GXJJ-iW4@!yO8 zL+qe^56Qr9`fuMuvVq(|E+^gOLGB?r$k&viznE+qoA?;|_#8I!ISjDF-@1nYncPn~Yu@10{lc<%XT)z{~k@|)T`z#Srd{V*6eqojQo0rw4=f;>dllJ;E$ z)5-3yxaQhVPd8)le1}=JZkBoA!VAp??hpuH4Ub^_^>AFr=4&k@S>uwOgJMcTeYp?CM{quL*Z~N!(-{p4?uiN(BS54+GV_q`f$NYNc+dp@_ z`SbU{@9?*=gV+2?{JZhrzQd!*d>`{Wc$ZJ|*X{Uk z--C1w^A__1%+L58^X=EZY}-5amv-9sn6+Q~d+^(S?auf;{9ne$(7s1S;=g?lN-zG~ z_n5TrA-bK{?(cJtQ2XnsvBJ>2232mgckzy0_0e_8uuz+U?fpv&-oJO0<> zf8($2;Ap@8|3&`;d>*}g47cOIeV0@FYjE#B_s<_7o41iy_%*{ia*X>(T=M$=@19A& z++#1FL;EhKYuI7?*KqBB?;E)Tv#i)rJp{BwtynNB(hzi)Wmdx3d=?_l_KggM67ku|~T=D^p_F{7R5o6G;p9CP&p zzuLhfe7}cqkD1~360duA_~%Ib?h&$@bRMsB56N`X-FS!T|NJbo?%WH_s#ilZ?`UZF zZYaYYW@a|w9y5b?;}CvN@%sHE++}7iCdblK%pLchZ8~o|->mWGna76~n)3I%hlqPa zetFl)w-%paK6t^o=7p1In?L=+eDmP{%{?Sj&N8Mv&zNl9zuiMJ`QPp#;rsR9YMo=v zmRM}S^vv=f%lm{VNJH*YM*1zwtMaO+kbAawm)g# zY~N-7wY|w6w71(ovPbRLY`6B7+S#>Pwcgqv*H+f9t$nt3ckOR$TWZ^C&(`>xX6IDr z9A}<$sk6*k&5hNW^Ht}Y&i9;Wou4}$6HcEXCiG7Dz=YKk1}5A&;lT-8CX^GNpKx@- zNgZ$R=j?*ztpogB|tyjQWN3KdoO?|I7ON`lIz>-oWV`_fj`@Z+ADk zyWC^$nG<^_eq`e3CjR}zXC_*c-Z|+5lLjVjn6zusu}L!~FPePaCLftRqY*U* z8vj4vL-H5@Z{0(}ckFY|ku-^=`7=Jztcm-)TS?`3{3^Lv@!%luyE_cH$oANnIJZ0iyJHsX=z>eeGO z8`dKqYg&)Ii)Uy*)3P3Utjl_2XE$epF6qj867BJFTrZwydq+>9V%&>gG()C0$utU+y8A@Sd7HzdZHB`~~8j{Hg!mx;2$= zz?+&ht*P(rw5HzFvZg-KWljBlH)nz_>B^dVxQA#GT07d;w|vC5cJQ|`JNEIudvhAr zj_aD%j*B|29iMGkJHFdx?Rch}GeMVhW$if9Lo^AkK9}#6x!kt;_}ieq19hv9XPEk~ zZ(4mk$J}>w%jzq-xFEfoGeMVhW%V8FA)18NMxKG(_)**1$lpk9e38qLdm7fpPc*HK zmvmYiZ)sT@pX#zUR^6Nlx}+;>&8#&medVPe!9tX%bk|IwPnezU3?#N zH)nz_>5BI;?IHU0_cLuj@1(Bc9-VvnmFiFHmRi6)G-=aP5${KTTgy`0x-9kMZq5W< z(v_u7^bk$BOM&lo)Uj>p`y5OEtZr%E975mFwDkKsE&YWS@59V{xjx&?nV?I$vh+C5 zQjTlFJbzxPuV(&!<_|K@Z=UoT<`*-cF<&x2!u%TMOXf$IH_Y>X$okE{hh+XZ^T(M# z&irxak28Oq`QywVXZ|?z$C*FQ{Bh>rct2$ye!kUb`}p_q@8jRczmI<(|33bG{BtJg zlCFIG6HP)N|33bG{QLO#@$ci`$G?w%AOAl7ITLhAS3drUCZUgiAOAl7ef<0Q_wn!J z-^ag?e;@yx3A&^!AOA#?(8s@ze;@xo{(b!W`1kSekAKbtUDB10f1*j~ zkAENkKK_0D`}p_q@8jRcKWBn2>B`4H(IoWo@8jRczmI<(|33bG{QLO#@$ciGGeMVh z<>Q}d68iY}@$ci`$G?w%AOAl7ef<0Q_wmn}pi8>)@lP}fef<0Q_wn!J-^ag?e;@xo z{(b!W_~%T}C0+UWCz^yl{(b!W`1kSekAENkKK_0Db0+ALu6+CxO+p|4KK_0D z`}p_q@8jRczmI<(|33aX6Ld*eKK_X&?2o@|#J`V!AOAl7ef<0Q_wn!J-^V{^>~Dzu z4YR*7_BY1<#zG(eKK_0D`}p_q@8jRczmI<(|33aX6Ld*eKK_X&p^twb|33bG{QLO# z@$ci`$G?w%AOD;Qx}+-~|3s6}$G?w%AOAl7ef<0Q_wn!J-^ag?f6fG5(v^>Yq6zc7 z4;ub`{QLO#@$ci`$G?w%AOAl7Ib*(LeuR0$ykXvi?e|dgk28;dAOAl7ef<0Q_wn!J z-^V{^f-dRG$3M{|z<+@M0RI90xkIEG;GZ|1Zw2@d@Xwi`OS%g1Pc#Vw{0I0C z@E_nmz<+@M0RI901N;a0=S$&IDc3Re*n@Nf_Wiz<+@M z0RI901N;a05AYx0Kfpg{f-dPQz(3I>4DcV|Kfr&0{{a61{sa66_z&Qzub=%5vA<#VH^%

    hp7%e%e}Ml0 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 literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/sensor/fw/gk_fw_710x.bin b/general/package/goke-osdrv-gk710x/files/sensor/fw/gk_fw_710x.bin new file mode 100755 index 0000000000000000000000000000000000000000..1f3d647655e1147d1d1a314d8160233bb2f31f39 GIT binary patch literal 1582496 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�yMf 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

    =1ilE__EM!^H>{KV##hT_ZZh&SE#L$F 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 z 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

    &AG&DZ3}l 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%0AcytqP&Y&T#&X=kL8nL5hR2GRF20~b|m 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�Dc1UmHaDDjkXEbMJCYgxL5)O46_%i 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º*Amy;ZfGEO#IE#r z#oVS3S3R&}6)k3l2%u{ngBIcq;!$Y%mJf1v?c%3TyY6KAx>HebY=ls~uE~(rV{P!# zuD?wO3qDDiCD{xNhh;jABnvN1d|lf9qCz1>=R@2)UXycgLNh16o3d31dXWb;HqkQ~ z&@+21q|rw%Cl@qO&$K|zd>Dutf#wDFAgt`LxZo~^2Im#mCW3uta&oBX!T$>?U1CgP z@8Ro@+QW}zb^3+{OHFKB(nuV(FSU~I?HU2pE9JUt_b*e5bo<}#kt#9{z_je#P(mPd zh@hs3Oaw;>mv0@@8bFaw@cU9A0&yz8o688i{T+)S+$o9KNWRCO^=k!2r?^b9nT^vw z!PViWzsHkph1%L0-iI9+T#uExN1g=j@)MmsI4qtj(9bd?qa)C{aB6p9w$)&D2V8_| z1ZpS&ViM^&g?cW=k+PdA$_$erp>#>#g>>lZ(~|P+B&M4;NKNd{O2O$QDW;RqS-eP_ zpiI>w9I?igqM7Xm1_(^K#*$WqXCYJu51&S`Nwcpv-7=|`o&`RBx);gC{kq;7E@ES# zFHKFPI>8B{iu)@A4fw!r7SgS*!De@rO+9~5G$a=9SJx5oS?4J(I=h`2t(O2-y^dP_ z%P2w0IUIR=u!PXVM2_mfPvTKFMeg^+x*Loz6$Wtk!fgg9n*(n&{;^WAOJ6qyTCIjb z(ro49eJjn%Gu{AoP4>=hTsT|F!)g+J=9o1}5Dr|VRHrx{H%bL1^jeMHg$MM4HVQ4E(0L2M7c*DBg-*+m*mS(!!pp{lP|6} z!K<`N3NSY-M={Y&dDyRPMh2{^?MI@GYKdd>VRAL|s0fr_p1}-6@G9WfOJJrpc~R9< z6QMqy+X*Vlz2Gf!g`afGki8c_o;FlCr(BwMezRvIY2foZU>X0f{ZeOL%|!CGf@3W> z;XvH@IRR9d5JHX4C*J>UKj6WBvSD)2K!@7rX2(fHyRDa54o;bAiiWm{b1n>*M2;b6 z9!UERdVuS1?*3bb;;+Ix__06aqWJ@#7%Ie7oG)lmY@Wj#FKen)1kv5hPYLHNURX(tGDf~GUGGk;n!vwIf%S@U#9Xb(aJfg4&t{mJL5ttEgr~?1 zJ?tkDArQ6<@B`Y3GTJE=IvgmIOVJlQq@tjOXIui+6oV|jWJ3~hlsuDs6KTw$q~4D9 z$23K-Vh$_4WBcF?rRj@UBsACdz_W;|xF1;AdHz(#3c35*Tg#LJE5u!*CJXU3jMJwc z-jU!bWi{n>!bc#F*A{`#g^Y5RX+TpYpQ!Z;EU{#_y~7*CG>qrGI96*m%_}^{KCY3v zZqnSleGt@mr6^|VsU^%Cce<&vcc}-g%XHEAF9uZf-*F9?@LlZHJ^Bqtn`9d8Htb)c#$9xTB% zAk6bJEuMIUi|U*dxf9OxHswi&=rs*rBjxCrC|EbtK(=lJH^-l56u?l^5WxPUD{aX= zKNo63hyZawcp(WvtWVO920|R!m|jFuD3yWiI$&JRp1r`xBUgPGPEWDi>d&Q}cyA(F7~HS8@HGN!6 zv{=@$KC}uHyN;eRslM~C+ZBJp19gYIEy8HEn%-mPuzQOFJmM4{U1qRnyB1J$f=x}} zs)LG7DP`qy%LvywBb@C~jc5lIz~+K9N$FTYqQh8u!OMSQK|+L}wL5QwlrE4bV}=DQ zZj8-r=(EmM_L;u9wHpTkxxcvEDJi@yLtB=4x9k)D1SzKEDzpg687GTz`dR&__!cNu z?_7s!_>D^XX^CW9CE@S~)DZTrd;Fq7Dm&C|0$Zy53_>vJrWu9a{pxXKh>eB8cR7VB z_QrLwQ1u`jhd!FGcdbapRax-nV%-qT9KYEOS=R`lRJ3zLPIl)hQ|MHrpY30T51zE~ z;D%nrMTsgF4-N@~ucXpd$UQ5n)(|fXQeaRY&dO-)Xld#TN&bxvKuS`FJ{P8{<23tu zTq+?G$48butCNquxRsAr;AGQmPJ9o|NWnVRs(|%(mF#Q4FL5Y&^)!}w;!bxW zd9;vFVM5;j>&lmlZ*7`F@OJW6?-UX#&*W<62Ql%j$7|*Em`q2ysu4{s(_L%uiWD?D zw;8J2S&E(-ol>W8&7{nwxLL~-7#Dic!_U!Tbs7L&XyLvHG0!Ta(I%HbVX|qf(8UF zZE2U2rZQcuo=F?O!te5ax7t&0$KE$|z;&zLtXCmY!Gl*bvS8pI_w>u_+RM~g?>gT+ zNh+aq0R0@7BEBoFAx+Y7_t}m|Vc2}G+mkQ=HBg|r) zgZdEOJgvyx{lV7DXGS6iR0Fz*Rx987(+G5Y^#Fa33{y)c2q#vhn;B}atJJMBtCM|b zR3yq$1k5hzFy21gD*w;vczdY%WyB22vo)WQ&}c&%il_TZoxrs@*Z;a71cG!Q!#3h= z=92nIX?PK*r7?LYBH(K;{I~nTyZ@lH^7!qJEVo($ROsRN3F7eYNA8%H{jdVhGzRp4 z6`iD#7Ico0aFB*y_Qj%*1&Zct(pgTpziq<^ExMHOq?`{4XuR!O-mLHP@E(+Y4AvJ~ zHXsQQ?$g0Wln$&Yq9bj*_%SYOW(g^uYCXt(!eB(use|f$pST-sX}~)k2KX~KDnA?6 zv1!r+3v1XvkQS$X5`x$2{1SQ zF~cQuH?*hOFYPEe-Gd|JbkhJGhY@tEXZ2gng#+Z8yPu<0$&TVLL-&LH)~w!Br9~&0 zz=Tc%cQymzCSkO~_G`4gWgmE!xm>pe0S)S9MSbJytM|_RaZN{$dqD8I-y#eOsW>#R z2u6tnIm|DxLn>T|$zSszF1e8yF#EjoSdI&{D7+5_D65P`+#Resb6hFC_>dADJU|7F zaTDO=ZQ^u~R)-OU!;*s+@E%0}CRo|e{IP|8&KIzyUs^PLDM8xu_BXPMMILaPPsDPy zv5vi0Y`2!wO;~nIvFS^OOioMiQ(k0d1MJ|YT~8v62Ud*pF--66>*N~K`q=c3pkY+k zeJe_+GM+m9k&(mrAS?Nr@+G=v6XyW-`z9{Wur&e3gNucLvH6B>n*uZJ(BP$Xgps|Z z`AxQD-e<0r@s{c?#ba zrqR(>Ods|05pvhjZ55ycF(N?qT7q-?&2*DpCZ}#)&BHPOSAHG;9#*uz%<|4j+H~A? z!;}KxSpA4J8Xrw%PFK!Zq(ju9RN^Zx^iNc zW&p>U2m*uadX&BZI2QXwdTQP??i#?cr#$W>Q3de@AgdtA-&(%F(&WAvcA4)}5zt;3 zQ$TfO031tiSQtXkECrGU^n7C!{5{g$K2|fie-zGUwh9CHl<@CFuUhS+qoP`REq2p2 zffE)0$1cBS4h}at8|h6EVR2^4-p>FhZ^cR$XF%(*S*T2+{OE*Ydi-D$`B8R3m*H@lLoZ8y)i^hPek1hYUDE@{7IsGMy#9FpPH#57yZ$}57h|SmPeb=j__3(L z1~t_2@#_3`1qQ~U&-aygGu&b{a7v!C5H9wU-k(O#jM2uGg0xxiQMCBl7NWjS}XHIeQ3?=9P{V2Y|NV=U$KpF-qY5z#&Zt9 z9{IPMr;%dM3Ux|$(tU-^(WcY%0u5ERZJ2i(i^X{M#d)3j)W0P-Ck369ef^2(%)X*TD$EG|Jh|Sm;wb~uNb1_Lapb(i_HiS4QgJQ=Q`eW?uYl(51%p)Rxm?JARtf|12T@xWD@MrYbjr7S z_GVrd^On06OA(HLLe+h!gC{vh5C6&4a>JHwh8?2I|K#eE1C2;ml=ec9$5WP>h$I4& zLKioqp;Qw9SDR=-^^lPGy8*ab0VGXX=6JF-(_s%%v|s3<%d_<%H*00F0#WKZJgnBH zFXri3>X0!Jlxf_A6*;7T2z6bMJ^OGJzi>up5>DRYy-b8qw35*1-?*BuOs>^B?A&Q; zW&2i=Z9U_kTwRp`cO;?Vycc>(QtAWoqT!X{0P5;T&q>t69 zEjh+7|5vU)7q3wE@R|%2QBx~sC||CH?B^57i;+rca-^HY{&x-UjzZ* zYES}C$&)Fvp{axXU7p~rhOz37+&JVWk^d`KpQG;_QnnKh1GuJ#kh(bS@&FsqtBq0F_Ql)SNDrxM7I;U zmIAo?5%0EFeRfmg#-2mZTH-=|zNuM}_#wI@A{1dDUbk{7BF^eVS+Tlm z+Gev0W0K59q%%$Veu3Nsz||nqCX08+L~KPWZe;>>4CHoq$KcJNj{yL_mOp1U zz}KnRQ5 zTp8$;+&0}Oo2GR1Eq=BX_{D!`RPn~#1PgzQ$yK0Rc>O!3j*9)Cd<}{33q)Z=yY+8; z{mTBD&e~)1`k(lEbpW%Yb#9Ff3`H0T4}5K3TuyK>JOPTE6hYY+$O7g7N9En_SCGhk zVaM@~#hJ-eQpz%n6^&@c|CO)xuTTxjBYh_BR?;j3{r4!Vv&pU*Oc{xA^MI0{EJHfUj(} zR-#c(lV8>FtpOOo*PQruT#^gwO$5Qd#jtHxmr2|{g^{TpAK5l*(08)zRCg4!a1>ioQCG2GL;hR7ZdHEeNEjn&z32_?<-5De{XJlCI9Dm`P@Fm2?5VwZ znm#Xwkb3%!V(`k^58CX@eqZ;*bSVqWH-<#K8GWiVF~lLHMq zLJ11zlh8YArgH(A{BJna-yefTBWjFY2g=hgo;QZ}(Q>#G`jejgu*F6=UG`lEgs?{O zCL=jCg`WIWSyk{nDObL9Hk+340oGh`{@%ajE9xW`7qpB*{%F{X4C#+jt&e)TK22Y& z7V62M{JSP=Ay4v7+O%ST#zaevQsX z77+03wv&_shHs2Tc(OgoZnKiq0^MP()qJEMVkC8}fYJT-9B4t5*DWI+3y4Kz@ypVS zL75#dWAHO^D!J%$gPL*P%`2Pnp?ft<$1G|Ly^5G4XJK|NWQclH0`M-qM@sv(#dk-9 zXh5D5x0WC%_;%yrM~dH%oCyp83|j;_d9vIQTyGFDh}~TzG*yPS)8NS-TLv``wt;i-cwxHeT_<8syis z<`wx$K>RP0S`W^Z6lJMBKQ*!`hj_8je!UX^Q*$aSI2l}P?G_}{Sku-mepg{nb09rG4H;8ox~Qz=JNT_@i?=0dG%{dpq{B% z0p@(e4@djq9MN2lzKZSpKnGP7kzXf13|ztV6_j3#4)5Tnnw*pjjsHkeJ|1DGjCQK# zJE~-CY&IUqpL-~V`iMOfEb{oU8Wxu5vR$@@-rR3I3-Y7Ut{^pOsu+qEDY=R~0Doqq zw{-$-ziwp(TJxiQ3{ovCOO2p;lJ8AK^)P-ow~>DeUPp_Fs~r0uo}UT)Y_xJ zJw%2+SzPqy+p(#>(wFhunEK+6cEZj4w;&Kl>)PCrm`n3!3~*;{EIk5gzm+#1w*t=J z_!Z4a@O%A9ja2i=lkOOywZU!DG}^FbrV2Ik1LA=cz*$;E9luK3$*p@^u|Z$r&fW;i zO(&j-pazmcf0DMmBU`Fz(|~6eZy-tq$=>8~c<$SwvcS8!K*^xXS#S;sN2g98|3V=H z9xEJ63&FC{4Vm$SoV&*#d$q@AIB?;)ubwwXYGzADRCe#`YoNVYy2B!4 zv9l+N^VP75inz8vfAqi=+XiCjK1*!3-0ECtG!@UNej0L<-gU|n-_1m1M8nq75A|-^ zXI;&nSlB*qI}r**m9l-5cdj$D8{?9R$8wimD3GEh-g6T3-$kkcCJ zrkUMd14a`L@5}jR&2CM;iHDLkznKMM&QZxF?LYB%6vN33kJ0S?c4N$E8fbHH?(pzf z<2hzE&x$byhS&hvuB;18}DF_L?)}5eM!7w@g*L)8V<|slvjmr&^o7vT0Rdm~ihaS($ zX*A6Lw$CpOr7+|XE$9sz0X6u&rw7=ex%34K4l}jx!pz43a{C*ge#T<`yNRX)@Tl2@ zs<~sT)l0P@5gH7*%Ae@4wrLR^otO!a?H&pz6J8#%0_S|K*}(@I?iq7N>R0H&4hySrb-)slFfjB&fV8BitV(0uVWetk7EJn zD&aE!*?K5uvR-x{5zGe+-c<|uyI?`(p}O%hh#;1~^u!OF7Sl6WE1JH}2@GcKM@PoI z@|&uv=o}+nw+e_@={&~h1T`DNrSJ0lIVJ^*m}wmqLx9h5`yRUHq;CZVc&!Gu@x>m3 zeIY>)HFbYm)c|;Zm`peC#HKYF`3wbW4YVwPP46PMsXqTPGh#b!qr{;%UZjM+R0>Nr zEe8nJ#`2hs6OL$+|CJ2Vu?xEhXX9iZXZk^bWAh^X#SHTB0 zNRzHV71yc11Fc@+!l}!xZM~*oZm+4|G+cl~6QcmmgT7-|qb18uw^91zGmhR5wN1-? zb8vn!8Ey0>e^E9NXHI&*I2`Dcr}bx@h}LB80B{~+dic{>>d`R3PDcrDVU{Q9M}?i^ zBEI=SQWzKhYQ??QC&2L@YjXnK(zot4kw?nBwiahjsq-h%rgp!m{wl{W9b)Rv#iSSR zTXQow%bwsBpDJJBL^xv-ZF&a2C56hL$Ra5V_Lbv^gm_g&`ExZgT$5l-Ti3aGpVGSl zj=vBX^WV-`*I;X>tr1aQJqk9F%l^u|;u_4-TyZ%zIoW13ATQ5cIf_DTRY;biTNwN* zI3E?jIHlI(G`FlJ`VI72*VyL2W+vD{-^30YE2^|W0jWci4_Pt^>fcm__(rc6ydDb{XF@(C?-3i>hgH*b${&T(9A<8 z*CmXdyNFpD7IKo}1k%6ftzUH%avBvwFnzBCi#DsjLka+vk~s-FI2$yyK{Xrl&ISIoYXl6Zz-eF^hCK-r0`g{wX% z^zD4maKK1xHWEz5WRsf~jAMlHEwbKR0@zVNxbHPv4I_Ne%s^P`-3I&5`sII{Cj;o8 zppx-AqBJpc{5Sp62{F_0vem}t>${;}K~1#@I}&)W$nF)I5i9&f{s&^{*!rKMVNbHv zkUyF{QvV<7-YO`sW$OaPgS)%CyF+mI;4Z;ExJz)C5ZqmYI|L07AUFhfx8NGM`(^D1 z{-XB2=boIZ`#9_Sy4UE@)7I=>-9y5b7;SX*?*)u?;YE8>@>Z+Mj9d0iW-dldXvVXd z5;uBx`uxU~*=W?u?tCv3iy<%Nl15 z^sL|*d?D$>1g+nvq6m-Vg^m}Ln1A`b$7|nTr>HmVB0n8(tc;PM}pf{xGbF9a=d3RU4yzm&YLgS0$Ao<3&^rE^zAmQM(T4c z{IqNmi<*oD0v~_L=!8;xn;^plL*0BjEM)d0iIrl+8F`x7unPKXS7Pf`$Wo2?H)@J5 zI_bpG0_DzTC-k7RFFEr}tc#D^!7p)m%dius%H%`-r#N6e_$TE&yJcU)G2l)?iw7bc z{ZBX&iAA}nCAiK0Qyl6a>mk3tsTF<=M^IRmtWXAa??2(t!}@rge;T&&pWcvDac>EzMCaO2$*aws4?roMD-t97=ZyV~J5>5NutU_wa6^ zRiESQBx)HK*wz&EOe&qfQ}3HYU@yHRch+W>=pLX*e1z*s|5&n~n%ly0{#^kaQ~by8 z%=*g=!e%3L&hZb)7|w7@5ef84aBCZpPO+dL+EyKrtRFT&kO{HAx9wQcg7PLD!>8>F zAx4XmUJs?VJAVFjK>Rk~TKhEj1dH{QVxv_=Y_6>|;z=Gp^9Q?v>Dy9NhfwdiZI75J z@nyGdp7JE4y*f)uRtV-TN9ik5dN5(DIV_npj_~rbmv#=^v-Hy5*A=`;`%~{X8g-=q zxStZDxdxN9#o}#oTW3mkep8|5S*L~&lvn3o zMpS5RSF5KC=srrj`1!s!rXLr|ym;g2x1yz9F3p%hyM5C@5Yw|6E)9IcF5x3}%0b5E zkH=wJYe0tm{h8Li{%!q%xU>Ab!v*U!kU1v7LmchU*`l>gXL#os_cEbmqElx9S!tVQaJ1{#>>&I!KHqAYRv1E9ZW~Gz4xcs`Y4?%!RH-vG6PK`e!QIy3P14d z-T>>SZ>wWLNX+o(Ud9{XzS@7{`y}X6dO1wb8{k_Owv(2F^2rb2x61QAQn&+m7U2I> z#!m2*H8>35yBFa;iiUGb$63%0Rkt_?&ZUjPtT|UnCNKFuG%#?F{O65Q&Kd0G5el3l z(Zl+M_Ot01uHX5pzsM3A=IU4SwckQsLHPv9k`z=VbHu0S@(iSzD}~R9HMfvbtc6rg znbowpD6%YtaAr?MJ==&W8Mr*-xq$X6##i~fUwTU=%^2nYtcU~C@=?Yk+q7oAxDU- zV3AY`Sp2hP z{c{$Ko=rd5Ok(pE0(b10UR+s?3MyAXoO-f|lfqdb$d*I8x zJlzo?19F>`qEIBBx*-~-z$C(?CqjYoB1YfHue;xC1N5`7{u?G?{E7sC%R2D$w^2;BTR>KpcD9I>MJ4$soY+j>S`FQ}M1a5O zM2%n^zCaAez+Z^ttE&+4 z-E;u@+2uC3$w1iV)79`b&1z=fZfNlb_%1Ij?MwaqxB8K|LifQW)FuEJXNz3+mxh}N zQ9w4y9?rld^lb&?4`kF z{8HAZi>^-Kcb5E|bM?eCS3thEvwRk@-h%>ocugO`VI<6!6Ha~r`XDdOHTPjtg%I$| zY1;UTagF*&X15OfQ&j7uGBfhDODLmJzv2eh#t||L zJ^w%9I1a5p+ixf82j)9h9n_BZ+j9pp`tQC5p<2qq2T5%u=25OTRabkwEj+la*+4@A zecWIFX}lG-mHT~&-uM-Wx1GmziZv@OKSQ7UGhE#6%yPJN9tnn~X?nszQ2nYuYccQFzHCyWu%o^L z-I+>?%7qC?nOm7qwEXJBp%6YVVJ0B|iDVK@rQ?`>Hx&@V_6Vjcc90k zmOR_&TvdL@LK}UOi8gnu#M;!nTK}ot{dLx9TGnvYI56(!Q-&edxQ)O4X8&K8y~s7& zoB+RDe5p<6*ek~YB~AAUb6mAp1^4CK4RS7_qi6o?i;{#Dz+htn*Bz7OPI z4zW{bThFQr;qM$>$Xmg=2!hkJhz7%UyC5pU18GbCp41)O#bop0nYGpWVZc%%PQ zJ8bBUbX@nJO9brjOuIfI&>s5$utV^vc5yzH2YSE`89w)ZNlTGc0qjs$kj}KLICmVd zLm|c=5Ge3AJ%Alr{dLU7y|`=vV279QD1|b~KHmU#NJKM)!U7$c3)mqI+r!W9+r)4G z)(-1DZSRh6D*ukdREz1~HNvk?0p8!)*xF#j(^mqr$N0eL_z1LMEI|(zoc~ZJV29t{ z9tJoZU!((e=ues594r2q3)rE?!t+)$MkC0-wL{9YfcYXG*dgG#oOY&=0vUPl0Qmq% z%v&^9nii0okhdxWzBNSxvib>$>yES552K}^0dsOwi1YY*_l=yV8#yIg*S+-!-_Q}M zfX=zdNf|zf)gX_Nz1QX+s85x(FLUfW)Fc4!pD)jixOe@~o!)!QEjv!VB>?_tDJ93448=Pohg_Bk2CxSax%GSNPM-&R+{WVtugR>WW*m&>g zh(g&b-jnmxwZIs~lnXfTB+VLfst4`nL6f2<}%`LR&r$~jK)6!2Fol+em6y*i<<)i(~> z&o|l()S5nCTqt{2ijomtv`4O zx56RaozG~a#!LzkDvt&?46v$Tt*TWj0){?P4Q2^nFz&lBVJLbbdOk zjZ@qixVt~CPrJm(NrDOq2@^(#Swn9I^c*`lqP|K@PXautuvL+~^_xfmc-j?X6LYBe z(e|f!+Tcu_*sxV&0sHaD2toBGw63Y_XbSg&b;QBg(Tfzz>Qjh}Z<(%z7FO)X(pKrp zM2)e{{!@%g;{O&;?=Vv5oQg9B^6ytHtqu!nfqJXxZm#D$)pu}h5Jsp>qj?QZih*+H zU~i6D&y;_ua0Pl<_u%=HU3aAMa<_eGEZ6=3;5jF{gN@Xv;c&6Nh*pg`lf{N*TW|Ol zT))&&69pYl&XBmALgGmtLyqDkdvAWQmnV(ot} zJTlI3en61GMX?@JJx%sRj8<;?Q~CpHGD7Dig)<{bD}>$Aemn%=P?9ya8Glab0C0?g z`h0y`cq{OyaP0L3r-rTN^_zQ=rAM}OSJ)ZBV zw)VY@AKCIP#iRVQ4}VIZR!wIM`lTlQm?v@jYx5w#y{%Qez1Cjcf9V&$8{A4S-^ zZKjk4F`PpEX`XfyQ?frNCpzK#USn%Y>DZ5~s#ydQgBAht1IUwr_@S#UF;A)xn((K2 zDlcH_wJu&>5;-Gze|WZE^BPb29cs%GlJ5-vTRi>S_`$j-UeBoU%lKvdfOIip>NC*8 z2k`v2;>T-w+snK^5A90TW5Cb(W!@G+??JWugf{%A^EN=A8pg3etgjm3O6ZaJR*_u9 z0lRytPx6u=)a81}=6_0`06+eJ{L_nk1n}d^jv||>_vGHd{QapoOVM(0tljq5nC2eU zsaD5%|51`r>0wti0`TLQs_DXUDNLt;-R-&7<9rg+3;okP{U5t~k&gg8of3bo?Vbv5 z|I<7<*bjJH(IC))PM-a)VwC*?#J7Q|B>Snd3ad(u>e?E5*1bQC12Oqt!USXR+i>To zs;i)*7%)HP%T(kNG;v49i&fRM@c; z;2-wz+gETj4G+ktf%r<3)8WKf#F_J_c?#nkW6WIFAlRxKykqh#wg&v)axg37AR2vD zNUWy4h3Eyv{|ZO{vmi{`Cua%(N8`SXQJccjG%Pff0FN%w=AXs^@_g8bU!u0%K2m*eViqMqjNKB0$M!Y?f)AKn)Fp~58%hK7Wsp%fH6Nw>U49UjcP{>sr}?{W$5 z#xzK8Yx``sj3$tY&Sj+thS#Ng*NF_McMTgc<<>s63+m2DgXC9$#j`55KScI;!vgiU zqbd@wBm2Z879U-ohEt8oB+LztKDkojX1an^_UZ1K3BPj~JqNCVT{5Oo@)d;)-#b@} zG%IgEoo@ecPoDW1aEn+~5M|}rXAcd+Tnt3h3CKh&>PZO4N1XR4lxueR3Kw*|>gZHI zc`D+Z#dGtK3TYYf*L2awZP$XL-dRRD8Xzd9YpU`H7Nu{O{?}!n{0)3Z2IABZ{{Umj1nO4+f0P?s%6Gll7tM$RlZ1y^E$-{lI93#;uU;{H&?e>4&c@ zy9MG@u}%w~%YUuHWlruim47 zQE5YcP(v03mYlumrBRr@u=?G@gi*l5~cm)W+R%w7(qn zM&p#>Py#NO@Z_?6AImk3YDc7a8mJyhE0XuvN}b2og`=%9BIhx=mBdB=H z><(hl5tK{et{)TI&#Ymq^1VTzzlZXHThkny4`7d9CfD-(Mfd2OWoo|Yy^pZw+6(!C zfnVBfgFU1YTG$5N(6S8zVwjOlsIX$tL#P;qxVu#^X94^lt{%_)$JZiQtm`KkckDvF zz~W1a+1=X$nRj^l69?#$E){kQ0+^7yTCQmqJY-DYKTN*etag0A2=ps5wo**8g0(I| zIB_L|w$!N8--1;o<%9sS9WS@X736imRo-UZsl!AUi;m3?dsql67AE~Hs89c~VE=xY zw-l^ zOQFG1Mmn?2%jd7BWpqxS!O7Q%m3C=S{s2GxIoGL#7f7^_otB)ZiXv#mturzULb+$B zg|Qq=7$sUjzYy`MyKbi@HPsTTE#HIDxn*+kOxBj%DB9TQJ-@lR)31gRHl<}1oCEzX z2Y(e<3*2ak@h7u8>R4x*wJm>2tFs@{=#!L3KUTr2Vg)%j`{w*@Vn%;-R44i6pJ*@ zm?l|xhL8m8?|bbYit{t_FfhWiF6cyrfi0u?tK{;0?;}jxz8=U2 zioAW)(9F}cH{DuvT*x1SkSf(Us^NlVSu&Z%S}+sMNNQ@fT;Y=_liV*u-hoFHfN||{y&%w6iI~ZV9`f#e3F5XtJuVZ6Cge}IzXVfCb zoA9B$RMfLtG)F1_?RYeDLM>L2)u(IaLfCV44)$Ko)24ap#qPKXA96qQd{5sMlCaHS zK(DgmEoIM+aY&foG=S$$!-;wL?EZUh1Y3UDpSk#d0RIQ>1$j9ibV$82r2#8%#%mgT zEZP|mU*eCylkj3xkj?_|JMca5|2j(u`zVqqLxK~<`w~B#5lnB~B77f!pFsdwb1V@; z<-C->aNb`qAHee(el=8Q?8q^pA>e-i?w5HF5TC@-U{IsINyg)5MFNYhG{z8f_XRrU z7=O|@)p}03A`MK-p~rfuO~HJ3He(WZn#VxbqGH2UEbB7aqPjL^ztLZD$Q}6YZg3BE zzu1sgVKPP^g?Tfz1%=;W7pp%hJQ5`S^A?_%P7JNx7(W7mb+ASF*+jgo`sa4{-DrZ< z*(|;(p?Ji7!=liR95_nn*;Bw2<|NPIcSRvm0Shgvt_ z=w6ST$ve12df{8pbYVx}pS9Bx2}B?OjFD( z_T;NgQ>?_qEu6W2$u02>``5^q`-6j@$lNZ0Dlj-{=IQykd@ao9Tw*r zE^zNRe5YiIp}J18Fzq?053J~k<8>>zK@Lv4t#F1ObK(}w07e3XG%{AeQ~i6tp$hR& z!*k}K9#;W;YWmuDve?u)PhyH|{naA+Z!^@7L+XZ*WSY1&MX60PG0ubXV_bXcI!WLq z6wcc$-N%k=&*Pqy1whlabZ`F~5 zJ*uzDjn|pcSLeV48aCwI+)wZ71AOx$;YSZ)409&6 zT1>Dz^_dLg2dj$-Hx9iM)l(iGO-(@70Ek%;t-yuTGAokt?_RWcZYFkvj3)IysS8qjVFA8dR1V6kJW zmq)keR}NAugiPK_T4n19q`0upNKZn)lmXMqm+YydNULH++17e0M_uh9Mc2hO_*7zk zwujuSyX7K+C1lH&`UUI{cX=09HEvnjy#MlGs#0dW_2pLpk3jOY1v+W^?t zme;CaKNr28A?{>-g~TKRS#edG)|N1g35SF-s(%0>?mbsg`QA>{>>zFMdTI|wr~55- zt|&I$MS6sfjbG(J{XK~0?77;$tH8a2qf<#K~u}i3PtQ;7GX-rcT zZTtKC&6neC%DWhz@{kCB`TVDo$gVIOd2HbMFWZGM3|l`lqc6Q|w{jPLdzA5m^R;%} z4LZafyEVoM+hZ=flTx0q{ZABaKb33gapYzHlwZJRwM!_W^9=ZlcGje<+Ygzw?TP|# zU+ZU5%aKhEpJ21E8r9FkxcSG+{$B2ze0l%ajSM_9SSu&#J#-M1>r-}$>y!a@4|6lo z4X6@i7zV_b{JDpBq)yC|pthbLrTspmC{PZQ{o%*;KR^Z#!q<1 zdiy3Gj5p_XJxv5LR!!#xlBSHE#z$B43TzZ=kU1(_SECL#lwRV&FPzd0$22yRv{GCbqmGQ-sS&Fa*Wb9 zanYGa7okUo=?UQg`~fG(`@J@zXjbN zyrs#_7f5YP-{FktKD(mh`ka@emc7+`WzBpDJ4&kmu@1}84p&4j=*bw?k-pVG(Oo(~ zw3%7Wh$0J~fBvcRY5<}HgpGwmp!@39MVM$*jV64T^1{$8p`)N4F<~7Xk$+==l$1(9 zW8yN3gR#m;5mcPC3eIgjOI^VBL~|)CX*p`hvh(s&)GthjvYK}R#I2$V6CZx`L9ZN$ zp|KR!96~CB_B=40_}*Nb=+yeq>PYhrcatHcidVv~hS$w*=(w$H#6eZulg(G?TZ8iK zj|HlylADp-Oo)Unbg)Qq8Xw@e+t&TP9~a06UyIu>>rn?DNnj4Jrk}Jwk5!4wgAv~tgVET}Xae8gH;O3wIR`1NLhu0~^)8-r<+MA;Ya%y`!HWAF- z{tKH-y$$|%hsU@U98y7bH+rM_?G;4FMjV@${uHRsR6;A+bbL@7d+A3^n4-RHe#iK@ z&LX_Zu^1yctZF`OA?fKT9tjgSqjhP5d8W6MUjC-0pSCIP&c7S%rJlUBmply7c6K%d zt65=FL5(#cM35*B%++a9z;CdfA$=>OCo?NJaFO=wcm{lA&pLk{PuP=beOZm3kV8*JEe*-gt(1P4HB-*<9+3rCWm^T%Qg3 zqFu7MT`o7)VHD(rOnBd*Irz|@$ca+6AW&s1JgU}94#&KS`f@l#5;%B__ zKLlfESPS0eTb zUb-fc`}sJW;0=*dtW0U;OUcAxmH-tX+q$e;X5J)L>TLLgphrQlth3Q%V zpRd&^F2f(8%WKQ3nY%uhFAWgBKS6I=%B&)iXyBUBR^jjd6__>~#4{lCScin4F`=Fp z|J!bQ&`20uZKtiu;1k?4+crG6jfAjB1o?P3UVg{4P2}v&Rd75s|7&$!TY7UNO)wgH z`$mSS{fu9`!S-Cd>ulzN0U=iRCWY>&2ujyaJ~htUkKv4^_2d)&jJGA( zQDWB{=J z7^jhW$eGo?tKiXE#_K)1tpqP$|Hkne&THo zLTrC7l=4|ovs#))EN4Mp`K}X(wNnXQs>58l%#LoWJ3tmltv#L5FMOzl0Ey8eGeUm$ z1A2_pfV!?Zh_P$qGCJm7sp3inMQR_EX&K#^Ky*S!NAGnYDf`g~cLN*HM z?`!x*A@U*BD|dI>nZdf->TrZ3pyYFfeqEx4!Aou`NZkl{kp21qYIWO32YE#10|HYR zHvW~pyucC1!M03Ajhc46QG`fdF_8tAQzaFbMF%D5TT$3gdr%(3{XL387nw}%YgkNN zb#>_Fv1uJ2QruwKO8kii>2L*xmwxfz+HvPYKHfgff>-tTgU_Lg9{z55{HRwG_#%KE zbML(`DpAdqFPqa~|F_H9rNQtTaKlNH@$z6ReQHJ(tFgX9=a}CoOO5%g=3;$;8x1Z&BvpJ|QUWf+e(1k%1gb7}DJ8Lnhw7OZkaD-EVW1 zk`8Nzv3JouW8uWOMQ(29m@sp89RmC53ZA9INBRAJ;shAkok4eVeoffbOm?VXr@{_L z7U&rGrZq9ElaftH<~ma=cc#%SC=_GsIZ1Yo*@FJ;L*~#R=-pH=X^^Z5#a8qb*ojmm zR?k_Sd~H@rYmZ3nw|Tt{vw!^YSidj1j5`v(L$D8$^vAx<&` zNn4KZfF9tR5LYSZ1$kqzkt7O$k2jKTulwe^j>RvB-j4)_DkbD52o=8}xx6Y-o0fBcQM~3ed z$le_cPSw!7QvvuK{^nNw9o83BWKxzW;r6~CoZZk~y2NnNn@sz0?6)P#3jyt}p^F(PPDksEl z3gZryLT6%PY2$gDUnnF4rQ2N5&+aZ6w@S7Y<8m2P7t)j_N)J1Wf+!m0Z#K~z@lWZ6WLNz2tyBRRX)!fB z$qF3c9~j?e^KmO4FTCa-V&^5PJ2Ztd$9>WU5ByOW5QeGWz@>2UqL%2vbO#EI-GP{V z=b`~8XI*lgB)n@bTUwv!gzRKz@KXVE`1!twLII_HT4q6x4;Z&CilHVlHDvJaD2OF9 zLF8w?14C{yfe1m^pS5HhePRA$XkENuWv;<5#|`-1*Ysv=CtkWTt`c?G=JKJO=R+#9 zav|SkGJz_HK)OB_iOw{wT$83Q;yaZN&@cOgSLmplbRfzQoCKnxw;PFbZSIBQ^gKwczpkHKMECvoIfJMvBSvit)7p%XPaoaHa#5|ywuqN#RYP$ag`w0?RnjQk zt=hYUqamq(RJL_c zqgfHKkzs4|Z%vBFF973t?jT+4+N1Rma~VnK`*D3wAzWo`=oz;&k6cA0re07c)?FZK zOtDR1^&zY>mtW;Kai4C^2T$!Z|6cS8JOm2U00L@OP7ZnySRug%}fIt(@o^l_xu+E?K@?R5r+WEhDKCxt7h zL)70aBY~FvY%*)@UbcQq7|%^Xi8<;xg5SxWHaS$Y`Y8dPfcJ*i;<4=SI0cH1oCP^> zV~RUkgExS`{D#V7^h3hOJDb6RqL z{Ciis*ZO_QgW_R?cT0s~ljZv|)=ozVn?O*Pi7icjoDb|8AGf`PSzlWReeL^(b96gw z#1oN<6RDrgC)H^sfPJWTaNQ2hWnUHItF9Ff#74fAun;8Dr#qrPHC8s+M)d*C*^}lk z_bmz(&Rq20feHm5dKZvl&%YKnDAMPxU!wnh&MCUXjcZ~Pb4f9n96lLo`N|m)dtZft zw)bZ|4i6!&iAL&#{^DDw-FmMp3`IXkyYl;_>v~Iwr16)0ygXkKsOwu4&+po3G56cp z=_l~~T%-Z=D_~pz-=4C5989fm)(P~^&On{Q7SPo>&a@X72u0_TF7W5P`41CH>a-Z9 zzlL!Q(;BOv#d|~>fi3k{#jT_Z!6Aru3?(5Ohg*-t%#&D?l*%8nW~NeflWs4z4y$_# z$eiLQ#DCBls`9c<7U4)59P{;Hzx)_PCCdPDvNZa1E70#i)XZa}bUK}TZilEt&Pqnu zJfRQ%qpcCttuvFj0>4(z4TYE%I~XR3V*JUL@L-LDJ$|tPHm5wKqOl@>#llfJH zXXPOc-3^%Z%yatk3I1oQD>P?*94n7a|DNW}X`Rzd0lq**51BjalR-MoriY*S7rZ(j z=0|Yg6{}nMe84pv{ost==7l~8|M=CES|MJx&_xjWNtOGXHlb9tXiu`N*mVz$(DP}b zwB)?eobhF6a5x{h#mXmmN&c0!<+Rq$A16NpsIR<+Spzxr67Zehg~92%7Rx3zg<47p zK*h*0?81B{DDwDdx&Y&R7l!MeG2ALp(K_$juMue#IvRnT-tsQI0?u2Gpj}p{f3~8~ z{d^_3fF3i^PVV}6pMMT115DV6A7{ZaarF3`(XyvuXP0LYR~8j`cJ}PaX4WOHmC5}5 zsN3VxiV7i;G>IZCVW1g9-YiAkcgHU5Nr&_w?Ie2F1|^Z+GFAT0)juX&*@ZA#`JZh+ zO_y8YfraTd>s8I8&jsrR#s8wSRj>a6eRg4xzqSc+DgO)?9bIL;HRV&5+w;4HrPzS-t|_+53|c4o|@v14`kw{=~D{?e~4y;~+g zo<+Gc>Z}ND8tNJ_API4sF64M>uenpFza5cvJyH$L4w?37_$9ly&O;Cpfs^hC#6C+g z?lWqoSS`ZmzKKQgO*Fl(S&D=_SlREq$$bm-VUWXpxLcx`75Fx6iSz?@tW?(hjTz3t z*n4|*s-x!6zgZkG<{-5-AEubl@YGM$ENZZplh|#S?f%+h)a;Gz(e#noNgJG-SR-(5 zYj9_qEX%A<=C-a2dcJyXTAHb+r{D0{bUmHd`qmx<#XDrhM^X8o_yYV6@nvByk&8eG zhBzHH1eB}KKiS(&YWO_ZfWe`LgPGe*uZMN;4&(G~pheJv9U{4uqs`PZ%+2J%2XVsi z{hq%{*0BB9<0FS}d19HKqH}ew>kfUX&A5>W-+7+@I5^_I#B=Ez;VR*MyO&_yiJNyjxIR;sf(XYhtZ;~|=C#8;arA(LkfjtK4gZzv*CbKrwrhs0ytACP^?-68rE5!5=E zkoyn^uFjjCa&tq;G%(aZ1acE#t`CM%4t&{eQ?hr4`H8wm9BpQ_cus3{ByFF&8P>Pw zT0NZfImVOngsww+v1_Rd`UH+T8YxVlKln4KrJ_jUQ>t{6mP?)=2_dSQ8Q7VxYc_W3 zC$_Y_6Jwo$3iG0PTdb$(Z)p}<-3zuqA5tUvm#YST!y!ZyIsMZ-0eVdmJP(nlWxx_3 zoB!MQsMS&}Y$P4i>DcI><|`s2O2t^sU7}bnN|9lp**3S+VVvy}-7c7uykgN9lX=3K z_9gH=jsr#p(^5NE!L$avv4u~EWpC|gV&Yf z4J0Jc+l(k83V=g^h~WsTdC2JEDR}&h61SrAV`(B!4XgX`r!jJ}_U|E9!Ziw{2X`Vc zP=pYoPs_jJ8J8StG#8FG%{+BZtk@ANhmuh=qkn#1ALYY>=0m9L$Km>G7sq5Lf(I^a zit<8`kz`oK5KHS9#s(ML(0CK@0CD#Y-k~k`^fD?qu-Uq*+Mw1t=g)B$B~f#0;ngyX z6g-ZZv;@OTKFA8&^pFVR@qN+X$KPIjmrghI#ZL>@U_623jIn*^2_@VZy}=ch@l*E! zzsg8E61ZahD{wyOz$H$=Dg&l$Ma8*Tw=UQ$(>B8L!p_ z0ZDS%Jj*cD`IT%_z5L24f=ozSY!X2=YUBj`zN`0pXX~IN)ZvPjhKCUUE2qi&RK&rg zX}F}&>*FCKVO^s9w4^u4;Y@1ACA>%lhY#norz~RvUtnNn3ht#+1nVUWnZIY;GO~{2 zsG3~)m?jt9{k21U<=1+WG#MlwLl^BQ3eIa-$qiw%q zUJUlyC;B~GtHvML@sr7#?0iW|$sRl#vjA{~Xt7NM8hc(fXxO0DFnNGYgC?xw8@O?B zVB1hGI6qd}k(;Pn@w0$8r(Y`Jyf^MuA&itvUEj?X#zD#*vcNsFv?FqYQrsp8nWzZ@ z!6ov4kWp$`C5US}eB7W+0!^U;@?v2B0kB?1(dylFYYnshQB-klDx;;I_mQB~N8n2X z!kq-|Hw*8I+@)91M8ohV-!>)lgvwJIUT1X})J*COkjC4-p6n9~YA zS2yJzGkv$5O9R^0a)|uVzm7wPmnvRg$7sr(;Q{dwn@}u=2$)V%x{4fs&!?0sH8Qt) z6!3hlXtN}i0@Z~Vh!@xEAOTezbv!AGKrltGet2lr(>?&XU7~GpYA2{oEt|D{L%DD_ zgQc3RgQNeZ5)Go25Y~UQR-=hJKw<2g$rX1S{9Q&b#4Ku)XVqTNrN@vLZN3aapNb)y zY>dLy~WL+ zV8z9@$lUjkf{2~rgXD=N2`EvW|JJX;#)gHc$s_T-tOsXXp(|(NCGP|M0CiblJt6pK zqU&1w#C$goq3|azty4$c?F8$R{(7L!{o20P1;O!^xt}2<(n6-)0?kZ$uAomo?lzKC zrtTFKolJ3zHQA(ABL``5D3&4c38tS^}-sKr!(;92w8eyee$UJ3)5My3B(m@O?yUnU4Y8ZyFP zx86Z~x6@e(U8#3f;~~`Gr*F zap_h@7P}!GxNkLa7L;wmh3BcYDy`xhg7c4fiZ3d#NiSUOAEU@d6e(74zPV{`+L{#g z;^TeSBaZRq0XzJ7F9!D6M!$KSf{~6W? zizUTgryI?(te%#SmIWkxJr9QXBGc9ix)y^EYR=sLj@VeE+8^A0hmFSj*PBQ$50!)M zA05!dWt)j~&ORkYh4MywtTGtPL_#j9vL58@;!DmB4NTnK|d&Ue-6Tm(VkDi|9f z^F@DOTMD(|Vx`t48Y<5g0@gW4iIdrI2{7Ed+w>2mlBuVF?=66R2Q~DoDU)B;c;Wfa zia{YA)3!_$tRjB3g>`$%_t=;v`}~ffbgqdkjz(~S{c+OcGRo(D13xltE$3B}?|5Lm z^5Gk1yP3$$H+_9-qiu%3z#n4n-iNmPh4Qf6_||awlE#1@0{)X{ghqrWrJ4EvE3QI% zLJ(q>w%x%D4CM`J^7Pkm4e8HdZ$nWQ{aakG+4UziSMsd6y>XObe+{mzyeon?QTABQ zKQctz#6gd_IA&O#=)1|ir0v$1eGf+-oA*1onZv)<5a6^^z_r1e(2~ z1zBAjMVONo{+euvh+3>x1-cg>9j=@5nu--c6^WrH7{*7v8YhYC=Ol~Yzb0Px|4;R; z1{#gX^xlF^pzb!u{a3ufjj7?rpLXHUCVr@jI3=TBkzcgq04Yd%SXrst71I`CnBi4P zKoj~ck5ztVBwcn-JedyE z7Kr@SuzM2HNg*&{V=k z@P0fE51zYJOp?tpd|>M{lAMoQ>`!*dQjP13uJ~TIInFr$LLYpZ_B#Ad@g1;RfxQ2> zIJiT@&u2xwA-6y3Lh-ef`o5jPIv>mH*7>UG#1E4SQ}a3OmI3Z4>(wOOR5#1cf!!P{eKf7p7u^_aTIobY5g(OZY9b37Y^K^yXLXh|6r7xoXC{BfcO733`B zUbL#KP0qBl%eFpIH|42rEDMrcw7cmPZV0;(oMzQyf;U!Spl&V5bd>5yAi3JUF$uLH zEWrOwX9;cBK>LNt76uL-_J@c{NesQJH=YFc8OLR~Y!F93i*CQa;yT3IUspHP?Y+FO z3av=u|USxYPF*G$+KlZ`8l;o)T7A?le2+{irG1Swk}fUsr&hyIYRvlKWib zbpHJ-oc$(q7wDG_nh-OK=HSH@yvRBB>oRIgIm+Ia!7QL+y&TW`(@yn)AqbM! z{0U&kg%Pbj7L|C&fE`c8uZWo>d`nM$7ZtM5py2S3N%{*n#NqGnNniS_mw6OWZ-3Ca zn09G6Bi{gtgfUpZ#3edkbiVF`mE7^kd!Ieneg*K8oC{W1kGX{n_yHg;{L}Xh<6voH z5L=Miep5@|^ROC7MoeQ0W2K5(9Wb9l)oiUTIs7MrY(#hQ^Y!26@fsF`_6hslhVIJy z7H&~6h?27iC9-t5Rq`R}fEe8v_&G2R8Fwpri0JK8u^oJ3g&s524L^(yMz#wSlXSz3 z{F(i^Gmh+mV?^EqA*}@wi6G3=>-OBCbZ3mO7H$WsvO1;D%UbRJEt5qS^t4YD(Ivse zA}}6+uYX!sD`1*pL`=4g0eAx;_lvtjMkF(4fv^4!7i$*$OMnK~dhtw)>5>2Q!sOR( z>COy-kJZ*8$9CHC;4JpQJvvW_MVD`l|a@fSh{z$%KI3YRLQPJ z7WP`ZWrv7gTbZV#AJ8)9Xs*V?_7XB34GM8Ud~Qr7Tz80P%=(HVgiF_jTK(vv+b z>?}+YYgT$BL=9U5&2sR3mMc7}yUxEYw3^+HB`UCy|Sv|jZ=RAdA*685y|;KHoFQJ)?U zxEFqEZ80}qG% z4TE)7z-UD592+CW)aRXANgp`<%DZzPb(ofTJ%bS|#Fb%L>guVTofOBFS@=hp0-;p@ zxXRqanqo)tIZ%RJfz0LimUf|C?4%Q_iiX0h0fWfVKz2R18oSSvkfMGqH5n`m!k5I# z(tYvscn}9-nCV1}K#C21byr#=mUgwu(Jf<|{VBL*XNk^0<+)X?rpkwTyf=s?BhN54 zLuJ#~?e_tbT4tf=KvB#oLmw1FC-_=3V)yr`I^8#+C)LCUEEQuWqs8RCgtTcGpGA74}OWjC6+C z4k#(VhO&(E2~I{eDM>}ggGv*%pi5C&t`*b*(N;)%ffbZGi)0?*C6^fHgUAH3eiOT? z!zh~fM^z%_asOz3ClUhBeRXj@e45F7W!+dtbH3R}2x{q6my~+vae6*>AqK*9N$tGBtv3{E~4*zr@9xu_F&Oe{4S`9PuOltk2lu zGCuL=OtqueGcWY1$yxuC;3PfyS4)<0Ua{iUu8@>dJ*G%UD;Sg*CY}w~0bf&!xOodny;QQa86nWmSaBel)wOWW75!vW zQx%>(8L7ATNh>50>)s!C&JKRkQ^pCwSI(i2u7+Pxf((4Gqm2lxQWxrE1AlZdSv;+^ zM`|?n<&#M$pm*sp@w&0xWkdk*eOu`158VnpSQFCUF-T_iqIaQ zfM6VIKF6^@FAagky`Aqb9b=F&T{zwdZc4h~*-_$XAid$$MTpKRCQHj*cBmN;?YR@L zYF#!EbT$3VuCf?Z&A+=g9Mb&|AnGM-$(bg8u#Qh?Jikw(jz9E0kRWv@w5As);JkIY zhYRs{t^X)4SuX`q#GZs(nav&k)rzSFM5_^O%(84jKbXDO(_FA1UH2NEn zNJC{7O!lPy?F26Y0C64HDl z_=#`4K7T*za+sIk@Vt5a7SdpFMpeu8i1)p6L4AqCH;&aQbYCLFp%zW^vMx;ieXGRg z+}jaw(7@-Ri4HH;rfwLS?(+Jp@S^!SZU$N*pajcM1EVJJ4SOn&&a|qKC<>wzish?C zIcsZvU1%%4O4q(s4voGy!uh7TjM*uZQm(tK9tTQ9p{E*=~vz5 z$p)ReKRp#GF3q67ALn&uRNsZamI1N*TZ0?=L4t7)L(ugX@10<%T#0B`JEQ2i;`gK| z;@kW(Nl6S?qch5XG?L!k^S$qs#Z{oKQ@zN8Ugj#o>#>-PodWc|Buk5b-b(bWLu;|?Xu{r@jHZbnGWI|Ulfop|p(8tlH8wVC_4e+9QZ5Axm_UE9cie_v zHBJOWILhzyvvrr?Hybt~EQ>2e{ZP2I3yMlEspX6CrA-?+b zEj0VIT6xF^cu)~-VRp~)2`d=Encum{lb;*woqM+}DKP=}8IeXt^C z+9)}8oK6}B_?wW=oWtapy3R5ypmp)^d^enw9BBSb}jxJ zb@92H_F%AH_M8Y~06K?e@7JJ^J{3e@eA02b123NMku`@GPZaIY;jrMC21>&Bs6WdV zha9U^jXgJ&2h!*R`P12g7p<-|87c$&%qA=FxebBuR0#p}Y#DlQ`m@w4OzrlpSFXt# zDdxL1v^F@Q+Sj9ZW&N#|2n=gl(+g422b_;{U_)Kv?ZGvELWcnFIYPM;z(pbM!S3%~ z8}p6*?&V^Dr#Z3HNo1zi@iQ$q0_e#o-~T;|6&r2ZCO-SLySUWnnX6v0I}iOcZhXoE zrQlYwxp5LtGM)Sx@2f0=0X^uRoOC8m$QqlBY@vyuxd0jgNbO`D;>Xx$rJA%6SqmH? zMIgYqDfGWyFynnx0rKSUEGi6S-hGc@kXpaFSm6hJcbNNH$jb8l4e(vgj2S_Tx0fc4 zz&$jiy$?{sZrHlWV41LQt*HpqksN{0@*&VbT9L+M1ghI1s1R;IUX}lm8hTbGuR{aq zLM76__(XpoQ!w@jx!MhrOJ`q=xO%4j-R08QLR)`LXzAOXi`M@vx zlbSOfUWf2-9M8IA-B6ydfSFHfj*(0%l)P42&69TqV7)qAKf2eye)4w@PqSdHzs9fjR>=y(%rx#=!+*C;hk>UQh~=mErb2y^YnKf;P1Lh zK-~b=;<*_|~LNyY=8hP#4Q#;gi1kn3TT{y*=o0rG8bhRGs&ak}q} z1#xT}vvvffe*d1Ke z3TOk_Xnl9D{Onb%Ucn4ZT@xeHVV1+g7LSOru-q41zbp^!bMRKkUu*-@a#m4itCma# zq49Q|eqbgEZu(5#ru~&b9 zg)Et(QxZn>lvHC;A&dzTa*i%*TjP}~;UUM;s&1*{0T!Oable)w^YdT5$ zg&S-E*RXe$!$&8ZaIr-_#RxIgEysLuI;{&_23+x7?FS0lfjLwAv-+1mh zw>^pMg9fw^1|tZ$#=5X)i(jteY)oaYCXnVVb!E@DrM{(>64xDTWFdbS)8*W8k8ww! zmNjFBpfCUNRixfzawfpCf3A1JPRDMiY+?pjXG;q}`G#V0Y zg0njvnjEW_k>OmNz;aP#->shQRGnM4sXY2*N6Kp1#2g2o>@AxGM4mu-!i17Qluslf z2zz3-E5pPAgM0c*h2Ezw1UvTyhc^%@J?C1Lvcu=GXgZgtGNHoG_;tEulkU?v+ECuc z$J+;Di3Za!!!kC`Z!PYGFGFvw*FaWszuFY&)Ex(=hj)!>MiSp{ZbbLi7(i+xF6&xY zedt8_ZjHIRLUMGuPqos}@XJMmf^;TUgcIX}X*ylZjYX>Rn8LS`utlOI;?m00{q|_S zB_0KOeR@5YFjds049hy`B{=4|>=t#6*JCe#b8&sdh{R$~*<7M~%W_&1+1FdZiaSbL z=-75%PhRb90P?H$MpBblXkMdKb*pS=@#_PN>L|R4ik%+HF9wWiEAGnM zLhxtKlzt*&2F$%Ssk6gW^3&N9{sBEN!kWaf#C1}rDPc})pI;yesL-n5lPNVcpV|s3 z(+Dd~59@nhf6QtBXs8l(l-qJ$caz;$ESbF>Y??IQO4D9JY7L>9gdWFN`I&2}AJTxI zVEx-S>Ce-jUwHYMr!8#fhiEEzFH2L$`n!kdw_Zv^jNIj^Ks?$YUr>yZkywaS%lq>+ zYoKy)wgq(IW3!MiT_R6a-+g8`o6$6r#hYr|s}{LppZ&`g~Dd8PZ5@ZBxiHXsFohWth4|b%_q42gZ7s3{zckr^7qy z&8x}-F^wld?MfJ)I0xqq8KTWgG{DJuRPwDl?_{X^63xViPvc?tmvNFqvi7TSQR4tp z6dluITMtw;PO86HTL@F45R%*6X{h&icK-GV%qi91sZba5e5&Y+p#6<$^NuXo=*-NC zZJiOK-O}^Od!_79V4+Ws$9MBj(y(JLfVw@2{J_IoSAN_PaQQ8zh{ppZ?=`u%+b;)& zrrb+&T*ninuD;paeCz@JKzH=+)w0$a%#G>xMRCLNgJ{6{JhPwJMd~{H5a%w&N$Ifu zvop$)A0H=|xFdWf=g7u{R6LnLZgg+z5EZN565oaCmx#vn->_^jzK%-9MWC`#cPQ>~ZjOc0B;Eiaq(4Nn0g(+v@X) z;MXqJs~~P^v{RHAaGGDDAqLOM890O6=CJr>OMAA(u42AGOW#9Y{9Saq_)k&95KJRO zClo^>IX)M8rnocSM}s3ju^{$Jcq)+8KCrvw-T-NMM;HAY=(J5~ZePKv&mZhqIi4^| z>18Wa&r4DoW}V z;GzdDi82}dW?1nre|3i`7`qIuQa$mpxc4pS@YEdaP>%w8I$;?P=usSAS-T-{D|F^p zj!Ml)6Gh49s^M!4Jr~itmYn5@!VkVZ73IRzXpYvxL^+1NtT%t!gvxyxg@KHfKblz@ zxJ{h5Gvs&)Oog#I6(Zqcu$A)Srf{PywCF$I+T29*G%C}TB~HkuarQN5Q}dsx`}&)m zG0>{?5%r34CDZv1sEkf-3{R^3s&@-~FVH=6zINWb9%5PuxM5rI+~BJz1dv?)B<3kYiKTR0SA z?cZ`k^>l5hBwLiAjmd+m+KT2iR0}gR9ngZfe>5twHm%9hJ!(v!5WWb zmiz|{BP2ZvJWD3t(GmJiHm~E-TM*9o)$qw4{v`i*nF zXAe$z(UK+3rb$rbl1SyHH{25FZq2Zzx3|Z5PLQ+b=;)JfsYL^l`Zx2bPsIQ#Qg-!czEoQ96*>I2 zr}>YAUv$?hxI;pO+Wn{v$mHgc@qqg!K;0SO9&co0v!AIuu$5p#a1PCh{Pn-p=K}hF zrsbt2s0z<``?yrS<4og(W$beQ>Gn_ ze?4F{W)6V|VhEPMv)D^!Vo-kqZeWv+$eUL*m+7G|3jB3#e2B>F(-nSOoFh#M(#$@n zcvVD!;n8uyr$zG6mXP~hsXB01AML>ZhHZQ3de!93PlOIU*m(; zt<(b|nK_-krR#f6qSEPPK@ym_cIhYh)x7RT)M-e7Ktl&}2%6w;KHhnz9lcX3wdjB+ z&GZJ3CqsNZht?^6^FPmUcH7HeON;9;sAlUk^=6ELoiR75hI*!sV+ZAZ5lh{d@$0OmUlNr;mjjr7m`I-Aqg&Te$H zv~k*{NhzN4f8Gk6SX}q0EKfOqp!$=;0vIe8Thaz{5{UI7Z!Ey zg$5AIjN4m+CxIDYoF&~!zOv|3g}=usfNqmr$Pd-%lyy16sw-QGWr3Zz8B&I;SB8xs zX=#9DlC~}vC0P|V{}vYbs31UKG|IIcCmJSzumhv zOt+}d%r!@gBvZlgeN6bNaNbsqr#*8G62aQ0{@F19HE)2rHuUVLG!tW0l>|#Er4sSy z1{$`q5AJc`?`|2){`&i7O8I8Yfpwh2+Z(yMxk?F6z*AoyaH3^$-NR712=96G4Qb~1 z$B}y1>XL-AXav+vm8jB6BON!f1KgFB)yP&wZl{dIY{GsiNdfMONziV+_|IKTBdqae z=0WABLZ^`o5%&A^F8;(kh^8%-x}0|@=)D5K=kc2ytl;VfZ(VZ0}QHSth;Cr z)k0hAJ&j1O3rU{O^S#@->Ww1Mxte}ZZe3o%x3K96*H3v?&c&>Rpo(2zVM)>shv6Qy zku3$9NH_1*HI{(egZ4yuk-HYW5+@YLVNN1&hd3={X{u}Wniz$9Cbua>q-`n3_j`7o zM7jC-*rN^!A4oS0@$X|2#Um8)4o&gsGExko^{B8Ygd8@|2>Us|Uyr!w+Mp1voYwqE zNw1JD&^!nv$0l(`m^Hos$a3;o&S71-^I7#jo6caJ)8EMmFQdC1aDQvAa7BP$Vlx0a zACJ9sY%mxC1)o@5n}6f-*yeT1H7Au&Tj0_Pcu<))(@BJLVQdGE+9Oc5hU4ZfW!=U8I5%{8rw){O!|`BS0|mJp2$z1BtiJq2~I$`KoQw{nopNbtg17uDR$b9>IXQ ziDhN$@0M9zZUP^tLc~qx#X4!Y-x5LlwT9Dpf83m+{4O_*b_m4CJU}ZM3p8fHR$rt2 zmTTJLd(lz~o@n%~(kg_sqUjifUG5$%9D1L|KMW$-t!M;obthf$xM=Lxv(9lmk>+P9 zPT!6M@O4Y^3zDZ<9oL~g>*zjhKtGLp9;kEZV{!UGtj!N+(c@*EJmmNegqq#%#uhXO z=%QtO6GB|pEr%m;{6{=R8VAmlUdH7W8)?cNU`ZUUpEluXB{ZvYqC zOWiH2Tm2~yV<8>=orreGRrxL~A=Aao312=VOBN}{SIUiDADT}J50Wt29;|I=q3`(}NYhxefP9q1?sk^nS&=)qpD zfZ{sIpRU2`mG!Xtv*7o7V;~AWb;J6Fpc5Q|f`g{B_|29Bd5aybI4^6Hf`j~4fB-+= zpuraOtNc?@@pp<+OofwRVo}g9ppCuGjPjt!&n|`2KzdXOGgcktVoTWrY>;g0>=(|l zgqx(?v(NlRM<0Lp#c&-Dz-oD{%*fuoj5VpRfO|C5Ru*PSRG}3x{3ug~8lB1jaYt=O~qT2YaM@9OPI{mqxqP zE6ed`>XbT@j~GG_G1aerNRJ(Kmw%<4{~f-}q17$^CGF)w5fiP}eCVRq0U<)hC?q<; zUOin5GlT0q6=PPcz9FcnEZwHYsU#q{nOO$I=awsdP8vK|`^%VqkFecg0`T@ah7T@R zpCTJmM$y0KJXf~k+6E$77(}Z+`;Q;Vr#;>ONMb|LI<^9BM8CF87izFD zriS=gU%I0tP9o)pxYC^f3G1fjsWmW%2OMRG{saTz@yR&NZ!C>-V8}b%tE}|%5GqyQ zcpUX06=F{8$;8GHNTX@{?wsnE`uW3y$mCv>RxOWMO%ZF^u304%&u^2G5Ok*PBVmT{p|64nT*KaCo!L-hY za#kI6zkC7rEFuOJ?#C{>XX^2EEU@ifS%Xn|^No@4`Q8_mp@Yi{>Okv6!phU#4y`Gh zJ==k|oQbsufibrSv1?R8{GUC>;M+_H!bq~ZPM2ZMLO?(^%$X8xl;;*I5W9bLKbNNE(@OA?Wj4p0rDxZzj^|>Z3N+X=Z zRR!>FBXK>gE~_lDJ}9ZH5jC1UUic1kW?;B2y-P!@;#>KG`V}dER#JE!%9ac8I~wg| zB@TpZWBHr$v(jiN?|mSRcg8L>gnQ%Eca}R#P~i~<>HMHDwZr>SC5hSb8)&#S`3u9< zz#22qHTv7-3pQgLJB-^R8H_+zCOodW=Vd__y)Vd770q%kreprwZ%z2O!6IgR9+gYt z0p>ofGoSMh=w8I2pE|u6=%Keb^0@Z$MtJDCA(2WT;`M3-N&G*9+=hYCzR9E>v?akg zk*$X_|6)-{+LjM^Rr)Nlq2d?aRHa_xxEIyVfn8<)@S#Bl!%HgiP6Veo>hWO^I;_qz zuFB76Z;O<8%F-lv;xmzo(`XYP1?eVm$kLt`OJA0a=(DYIz+lBEzME}cNxrhdTrz&M zF{T#x6KpX7@R#4=o@GQcuvwLAnMtb04<&ulquK2&v6f5CuS8I0dJAKH9d@glSz|b{ zq29LG>Hw{|l1(|IA%Btkbg@#KT#gGnSBd4FZAtO<6~tZ6HeDjF_|7(os{brKG?MOI zc7E-Igo-n=Df$bKOiVzzR^D^eY6oOY;00_=l5HG%)G9Z?Y($2LKD4>sdI}<}%nHQCctYZS~!An!e#Ego`+%<&qDk70D zuL^sE{6r2T=CUKoH@U{^Te#Ndr-flkMsOFkzOqvf+Gov<7y(q>BMFpU3p?yR?BYJ4 zj;K}dEj*m&Wm-x4GErt~J2k zP@2YJmjuc=vU1L_RX78MYl}XJ48{ds@i(pq7rBHe^1w0KKJSz;WI&-&`jVD(G%3153L^aJzNI482M& z!nDur_iA;+^9yX3Ryt=I415u6=V>Zb92{lzlQMsD#KcnX+TvRm`1T|DM3r2NFgg;e z+X^j_(gm#gM~lEYdx4jGS>1q@H#vo3`ZnCxu{2Z=Yn#(0_S;NfPWtI{Z{g~qGE zX{d;&1@n()g^~&0VXK-2N)zyR$XMDuo%$hLL?4~;2lm=I_-x0KU~*`Sjh5}ksDr+r z*#R-2%17ZHr0hdrBNM0C9fr)mSNE(w93OIJf>Pu^)>+wVO1O}}NJKBe6%fX;;B7kf zpgdWfUG1&Az~-#NyD($}mo#Pa0OBF1faXcEvuf%eBrqs&A@RLlCQuq$MrDzN;?pDqw7}w}buC=Qr_nZb1sQ)hInkHd-s? zbC@*CYVr2{@jk60%#D%j5|`*U*ynh3JPhLIy#z1JaJDiQ;Wx}BO4^+}%awVSXFs(D zR0&`o#db=@Pl~Obb4b4 z8p|LHzA%Q;gs{@KhD8Y~jOMmyhB2s=76gasA(o-(t!w-e&_55JqCoI05^M6>X8CJ1 zs07Fhwdn$Gl7pT_a9~@pyp0ICwk?>u3rphVaSVG~=XC4rA&d={(Q0Ysj+(Dq*Hy`T z`TZ#-aB<#E2T4=`=YpE_Y?gEvTvI^&fGV?|nJ0Sp*s7LKS!BuR1&AM@bnYEwK8tO_ zmlN-WxW-apig_%Q^+1V9NWOJ-REsSw#O3Uk|AgJo^U0~>586z{G7;SvV*q;qyD?6xX z2&X(5m77w0i5{G5Y)@<^x$)SD!(uZwUv;t(@O7_nNW$m%yRWBN4Xr`Ok^O38Wu&V} z)e-Fv<|Kn=AW$YkfMb@5!IZ20*0UkA`am7`34iokqLV8i&-|}GdpzfK(MW^*_^5_n zo-a&_lD4CoMP-d9s+Dp@t1IrR%n}dSH{U5YCKvr&CT^~BKG%OXPAjvNeC4yD%J-XM z%)5vvCh3C)p9k}#>!h)J9bUR%`nol+n$|$)Dh^G3(c|ca8ks+a=)713!#>T6IuJ18 zXV(_Y$fur}$p<8$`k!|`0DVXQ>OW4h5@l@J`l?EAT|(6!uPYrhwrurws)6IUVzpIw z9My(4G#Mh29v@ZFZ zMy(^Xr?an8xD5En-rl*2Rndi?ePu!w=Hwa_QJEL&e$7f_SRhOh;a+;rKmt8XrinH_ zV3@!qO-iXsRu)FpP`n0|&45dS7)Nl=Q-zOG8;Mlf0{)JltM7e~l*Mifw`p;sM>y%G zWUrQ*u@&c8kFzn|#_&|&`r6_>jpGxU4NFo$QtY1V-@`r+u879BRftTE}W_)`= z`ro=Q^356iJ1}cbulq-V6$d9u^Q;492AZ-n=d!>i9&q*pDhl=lp3^B{`cLm)85hXm|LUg) z;BWi7L#!mxIP~S(`+pri5s#S0@JbXjU*iV6|5+hlIXi4w((Nx^du|<8`T!V5A7n4_ z*7jbI=tF^$NMUUd92{ zXg`U0_W|xl(p#m=o2f3UPWrK$0pO%vID=vVd>n-0T=3SJPJIN{K67CgvgEV?_w-Q9vG_gP(y z#ivqh3Y$>Z*H5WeQiO2m7?9V+ETQyBC^akQkMQ($>H?q9h2$Ar+LQsGPY%9=3up8D zW$&z{$602MJSG1u1-;+ICL2tR>$bsiXiodN9mKlgNB1YFAC@l7Bq6;$(@ zEv2@uD-=#$R-lB_jYlbnkql*07xzCx*x-@{V=72a!JLQ;ajk`Qs{sBN&$V3 zfVx5eKH-1k$L!riig-K0vERKJ3rC@^2UPVs&6*_=9GnxvTE(gm?q)BJ#u zbD8c$)z$N-CoUY3Wfzh{;%r_1fkKvmY!_HYU*U013hbKZ6Kq}@TbGa?CfouDCyS4X z*u;Lci_H1WEI!_J)i?{vWJC^uHi$pniX{0^804{_|hT8K)6pD7NOZNtRYkwDZIL)EkL9~_x~&CkEq z-?*6RSjlSrQ?>4GWhm`lz*UjdaI{PlU1A4Nc%nVEdIk1o)eEy0^908o?d64ZBmxno zY!9w>mTIxTm?F*MDahD84extJ9;L73g+=b4H>mupSCHly12hb+3{O8xUE;UR*_F8kb`*fz`a(pMj4Bb)KGZJ8<{~$93{#33 zYAlv0YiRoMplaq&<&7;<<>`ob+21({{cFniIg4aGyAX29eu>^!6Bznuk&{up`(So8 zj{qSY5zsr-j!7ym#rMteDl6ll_cTp5=>GvCzwv&h+*Cg!Q?mBy{-pUe$Y=|dyDax4oK4kziT&A6lQYzhSWk@wqQHW z*MJi>XC|W39VdU|>SUm4BZMdi%FhAya6*oGjfT_O43vIOyZ&w;P@#gYbcA3h@VB1< ztZ$Rg9ucN0g1-M&53#ieVe7)ZGaiTU%Fb;EF+wTYJkK(ykT~KTo@StJVa6jp?bod> zz|&ZgrqTDv)7~dupm<^fHyJgOIB1>mZfP^tDQliz4JF<^*e>aIVCtI?`zr2#??#aw z!_h@B0h0RKedF79#UBfjz;AVbWeLEGNVN-MYca`ON6|paiv2PS{x5s@7rufOlLBWy zR2W3w2WmI}@sIRO$rydK_DtUM^>)TB8w>$rqpcL{iC?Gyx`4jl|E7=6Te${_u=0j7 zT3+Fd7W79mcts|z;Jbq9N(BC_xS;iRO`|}_cxNPPr9tEj&1K51z#?f<^ZGCBftI)F zOIs@(u#T`+78QZ0X64&JwqO@4H!?mdL=z=Vv0?G1nxrs(xT{&cF`gUkh&Eun^?#l{ z!K5I&N58oO=qcKv$*9P2t@uWNI-`1s;|#{w{Vbv>;vFe(N*~*7~Qu5-csKDDBIasF>AfNV zh?{&;hlF8HLcbh!kTYhewkZN)7GLz)p;lr4V6WlZEEBJT2EWAj7t$5;5h};NjS<49 zpGMU;4QB{$_!#}-x!r+M!IU!of{+djD#tG0`QI8`g!%Jw3l+r83c>B0@MA-O9}X%1A06_!V|3T@BQZ9-g@1BaV#3J-<)UYHx&C&&a9;{;_pe<7#gzoV&cls}t{w^v-7lz}X^knoDBkZiKML5F?icqpC3 zmFkEql!;RX28->>1OGP85q9A~?gZrLt<2>VY6>TiL?Q`rAn7Ik_OGx@w&4_1^tJ&13X?tW3e^4-4TFlrA;T=GIubOAX#fQW zBurDk?$vF123jDhyVclIvjA>c42%cWOe@=_fo*&&yH7+7VIs5SpzG;UU}{!+Z^+BL z%?WDgd9CvteV2f{dxl4e_~qKSq+B4*y8fA|>rwI-<>(=zFV*MfoOv`F*Cj#HlAchj z2n^P(b$$FPa62z><3QWYch`wowd$HL$+|S2VA%|bGys2^bzqb{X^Q)XJXZEKAx0BH z>Dpl0?4sS?@7r|_;_vJFB z*GL=+L{-Jt;viP3k?#|#HQO^W_;5x>A&q%}d9)nmhbt}3@D@3fd&h*grQovVLL3tO z5?6kPFRDn!;W%wpHpX#ksqgnt+aPMavHHb~wtau{0nzlo`31z8|Kc;9b!SgB!=eq7 zSTs9*out42WNU(aWx_t=w?83s z?i28G(%>rPXthh>_@JNSE}1Gs-vZ)!(}CZ+kF$}!98Vkf9dSQIBLJtb){@s9oOLSX zfXA5WVU4L`=Rha8Y6d}XC!RI34!Bo{v9bus7;9?D{=)y`0JP)blS z$^UHi)*@1GcOm@&Fp&*hrGCdvQe^s8Nx`SE5hOQ)UZN3Xe= zovj)V>oug8|3szHu85p?@|%k~*v;%~ObPg80&RlTuM)Ka)Jd>)89s+~Z4Y6MuhS{)LU*mp>-A%OD+Wp8b)#Kq@gu&{7i2X$G`t{SmPW7^jTat#%O70#XW`yhOZ6l67g7IZZ-DbI z;9aixw_GSjX65wePcHgmw!%WddG}v9A^;qjyx5Sd17oCH7z=alF!=G#F@ww*ehSH8 zm24m_kqJ22o7j;1er7O63JQxiL~d&pa8LC`eMZdTL~}?W&)fA=3I=RLk+)`}I^D#PK(_C1pUY3}4Kno6Y!#xs%fK*7Cq< zs{8N~HR4T2|4j)7CtTvXkxdjv zl1&KUwI6hY-QKz~7ga}^uGt1I+i)ELZ z7lSW(^yP0WCO*ozcbB9)&VyztlC@pZMw-dB*MrafkAA9+p&kUBex!r#FMi`{X!#$et{cU{{-(lGoQ3sI`f2(#7&O}681R=YgokS>>n z*XNdo8Hd4)Q$Op!`1l(S3MOPKn3VWR?3rqy_6bjGJ_L$ER4(Ya{0kv{(Ir#KR?-h6C#Sk?w&_p=udyq^>TzEjsV2zOnHe<2TAswKfA9`|M-48I%wB@w_dQTfSj9UNwu~Tn9&knv+^Cjj1TeR^83Az2&dV5^tMN2oxdY zWJPX=ZBZDGea=1ljwOa~Y5J?_vbM4Qe&zdalFu!27*b%r4ESq;k{>eT7;?Qna05!9 zchn|1!f2r=E`%+)C3&k^HbbWyw828I#e9~z4h<636#g~NH4d(=bdj+ium^{)xarbY z-HgHhhVVScwFE80&_-8_00+}`QFJ#t329uufSYF8o!_3t^=U|2`mzp#cRmcW!H~s~ z!1Iw|kEv>9E3UzD5}Cmi;5chProWI@`uD+y+X;fiAh3HoYYIvN!>gFQT$@Xj&2EH| zicJ&9@*cgh{QZ+Z#Qn0r!ekGMl5n81d4!vWnH&eM2{U@5`{04@iK<_f3T#2sNC8n; zH-dMA_Xz{vuwZ5rNi*~e^OCqvOlo-YF^*ojxKmqCaJ(be#kzJL%ZAlX=#fb>~CR>h=8Jd1pS%*LzRZ*;Qxns=a?(+5DtNXnuJ**Oox?wQm@n zYU~`{YsDHo&5E4gpdO@#YzDx<0rP^4rJfh7O936GTsYGXp}h3(6MxH1dtC$~a${(Y zg34WD$Y!DL{4n_lkY4cd2=q$>j%u1u)QYfWGS8zCe6EjAkj-%9jEM!%;j0?plBZN$ z(asBTf-fpvNcEEqH%C;x;Bts7+t=~bF+57L!EjhG{04Wf?ew*U7eGf{V=LE#iS=Q% zJj6^)=i6J&I=y$sRjo5%UMwu584u2qMY?#n(<#B6*#tF^s=RFxv99x9~9xGy-m0W$pv_!4qx@@JeM3Nz#9C7K$ z1P39I#voc14_Zi_vTvg9OCVsrNRop4uWgw)e&ffOL5c#y0J^c4VDcNu*B)gW(-Ub? z*uXmN-Ibtd$zcKS1IS4q^iGVuN2nHF!IOcnLGRmRwr6KekYumq>@)O;nqK2?HIhVU zC)X{v+`73zTzX+vl+~FHpYa<8D4GCI?HYcOw(XR(8xbZR1WfwL~WHLj^FBr zz?xdIJNz+zhD7z)*2I!;h$?ity-`^T+1VPtEpk8u_!_`3S;nH}!W8Bs|27W5Pvcl_ z+JR%&fpdGVIr%%~P{+HGZmGJ;@VneIBwR>9I5;mLQ2wsH#1v3%2^H5ahyQjyND%y@ zCvtVE`&Rx~SK!fG`)_oVMAKDpUVX2~sxK!_%Zrfxx99)1UbrY5RS{|FjqaLdnz^OP z3c&jd1AnPoEeT!xZNHrlqvlM%o&rta#|PnSBtvLS3NCT_gL*!haks}_hs8X+D+v|$ zugUrh;k*IuKb-$}=ap{uVUT3}(eXEW;BV$~P$C~D^T2mhi^NNn3Iik6HV^k}0Q{&f z7iu&FVnAJ>dYL9qjnBevda zc<4sjl2f`50Y(sI{a`)M?+NB0(+?nuj`8W}|5V)lpZDm0SAPCq%RSDxpUM;tML2-o zzv z;&4@a`0V`Bn8X44)8F)YfZz657j(<{&67Cp{G44c^JNt)qgIY~#8AY>rjJLqnE9vf zK2+*6imerFN>CJflwiR30^6)i>d4>Qbu6bc$A@RPKtHqKt1&nu48Giu(a|1A4&cv8 z^S>EVci>bQiSKTAP^%r095Q49)&cN)0PM;C6#o}3@f_VBo?n@a)Sj4I6RMU8QARZ# z2MydIl4vrR$5sK}Ze18skHIp_ii>su8RFkR2+UcZKL!}wyvLn{R| zk!}Y%=J4LDzYkHp-b48(T>$(CfT#ZrXKf}L3Co9V6?9J61rXvL=C93}}KBHAdLO~n0aQruX#@m5_01I7H`fvCQoq0NgferE; z8R3TE7|k=|pYj8c>p$&a%?Z<#rPxGNXkRYNC8F03~Flwb}E!R zsBmX#M&9XjIW}NDfV#|ou0s*l!%s=N>Jx9V1O-h?wc*Yh&t3DnaWI{}A@-**lsAB` z&a?*4O-U>)y#O_a*E3&VxHvce_4u_ej0#tFIWf=KN~eS(!6sm#$)+IbX+PtYZYDy5 z?>NY*q|p<5bzuh7h4WCJ%Qm5)O+ZV=zA7vk)6?V~P|Kb%jr9Vi7SqK*OHEz8_js)5XH zrn+O|6)P96N-kyIVxas5it{~1$lwZ5x2MHv+@*6bDnx`B?Swj-yQzX_scxwF-@g0v zM}Wi+O#5*l&39vQ!cnxp?Z1Ft?|eD(Jx21|Es_hri^rey{_P&nHsw6c0=gO{sBH`p zzXlnA1g)Q|JvB=-@_Nc|<8e$lq{qL;vNrpaJxa)^P zv@*~59K~*b7zLypj`Jrewu~Fz^Sny|+*;A9O^Xz|)wpQN(5%h82InREhs_NtNA$T& zJwjss?d+EMQ+^Q8?INw4p(V^DWkhfG>H41Hqm8wAYb2O6&2o`mY?vK&dlNHwq>!R| zE|F-m4ov$LLs{EaJ#p1x(mQF|7RpW&Gs3y%9bY4B&TvPu8~n~cMIKg*BB*4T+j)N? zWTBMGK?)&srtEca1jp9zBB8@A2>VxgPNA*eh=@d2>daa{3)D+VaMpGG3K%iPI90?+ zG?TR{k{w7Y&y4DDXf~`RXBG5E!NDQtGOoakcyd^G2E(>IYMRn9Q6;G}?5j9Svu;=H z6{SQ@iuk7>LUIQ0!|2zUjzh1&WbVx4$zYWzqM-+x4YYE}iZ+Fcf?il8ReuRodO%*F z62Ya76oP*egM6`UCTG!ErY!)2tX1_O;hb()bI1$BQ^>~)ei$?kS@&kI1nGwQ;d{>pzG4}qXBz`O$^taW_wNV^TFBbpYPUp{*oBDbE@y{e5lX!%GTLLC z49hd*VnR~%1tsi!u!QQ=s{Go_oqO`B;=0P8va^4oFwUNL_KPgTe@%|dQr0jD1A1m2 z6SoVMX_|i`hh$XXCiXst|9M5Cd3AKJEsPy*Z!{H2D z7GyI2tOCo%RD-t;@h{H^71(O@HU3f7lDUJ z{}Sq~>EYJ_(6CA_=zU%m(2ulhr!abJjr z^?79|<6GDu1`$^se4DXG;vpsKV>r9BJ-eI^XNW=FZ>r-rISi!RA#lM6Bnc|1fautQz(wXOouhpeUDG2Qkac-FE?<#czUsfGr~d7_ zN^No=_)Bt83ii3FMmmz>M>WGe4-P1r`MJXdG0LZU3zd{u)8@~QP2hvGx|D5W3yDfE zzThQ$bd4G+Ylb$k1{$gK3UH9^dFQh!_~5dd*waG zk^khED;fqm2HpBzO+A$u@ylDL@OTHt5#Et3{Bt-n(fb+L9m%`z>W=b`IXj9@pT5E| zk-b#6I8gTkL46LC!~>sac9GLH(xAlR1zT{66s=qG#pGUwM&+eK@wy)4Wi;VGo_e_8 z_^*-9g~x-gYFN$`44nv?5Li*?R>8^xRED=vrFf*LiO}q-kDHaR%OikQMvaZXOxY%c zqo+A<&m^BP2|f)_^osa_H=<9JIG=oe{{VU{fNDd+Wv!nyrt)uce`N zA1TUZAjm*ZAAp`!D?K|YnoBXPie!p;iyImzH(Bky7-pNqt@_#4F^O_Wj|1)hnrAez z<)hAhN%!u6f6L1z9aM2}!8qWv>*gPXKUn^q4@D8nO7^AGeRj;##t|DG!zyDre7OHY z$p2f_YiKdwuCM6!(e_q1)IwYf8x+zmrnfyrwDUw2USAL+1v*mehYPY`JqL~~YyPf< z&0Ug;BU>}beDi9(i9ibv-!RfPlL~pqvh>Y!+ZuQJ+iEb z?m@AG;6-&+u7)f}d7)^e=6j=Om@52g9Mts72PL6$$DSv9e$raKX@LF3Zk1j(yXPk! zE^G%mfU%eB&gZx2nvHRp=`HYbgxQ$PYJI;@wl(Aq$s1I^EDp6EUQr_nt>0&htwvgh znPLcr6>`pCbx_c!<0Cp`F&0_KTcd54?X5Tse0IQ6LR@rrH9Or}OR#LGN{Y?)MAR@j zn!M)JG|4F2S%mu4m^u!{pNHe%?;}PMo=@@qYa5o>k6n2$``>Z7Sn@I+k^DqsAfX*dYRttghd(dON`>|ic0r!BE+bDN*1Q0kt zt^*Mfg$(!0YP^2UBhH*VFTX>Pu0{-{Ed=0aKEh228QC!Cl(khH4Y&}Xqial=)kkxskg8%R z9Vx}~AhLSUTC(5oELsY&b}% z4mh@L8-cz1F!j_pt(cP4Ti~@p+8)`)odA0R5T6F<4+h9z_?ul607XyfrKlM8h;QV3 z#>H>(EW7WQU)<9HZs0P6M?TnGZDo8+Vt+!Y86(W+>XJn5PQkI?4{IaM|0+cI?PZLC z_n(Fgoy|d88!duAE#MwOM8=XQ5T`e<^KK6}e31ilzRkz9*1IsxEnFW|^jF%{n$N?g zQWvd*)|ffJ+Oh7lYado4AFQifA$Eolln2;Z|bR;W3h~u3bMy`FkX)V?W`N>%l z?PKN_sZWmym9~hAT0kFFfPMRK@w2NXdvKKW6Rp(14WVkf&&|x4y8Df}^4YAi+%C4< zS!_l_C>o&RiST#k=wDn{JzvPOGB0jKrijmqHOCWLM)1j|>ko5cftjCru$WqrNZA2) zEA_Ww6I8xSlUy@VnVN~Co**8*TTro%gk1%fr*O8hz7~GP^WZZ>mp|nU5Fh(*bYlg6 z!!na4kg?3AeGWkNXl#*V^#BT%ffAZo_4ZUnKnrDfp!5W_6<`8IpyjyM%6ltcXiQW1p7N!lQ>&-0q!6%= zR7LBcI81mXlOee%`d0z#0oa=tY*^|yTkRT&UWJ0l2`PbULgu5Io#`iV?>rLFf&p2% z<~=3|gE=F-S6Amf82T#;2$2I~h+hP$QtR!E%?R}gd7C{n8L((>=59)_sBc2d%5P6B zT$>d!Zg|9(&XhTC|Eb4cjfcyj8oJ#q;`>{;bOx4+WP{t2Wg6{k@Iks)Gz5*!Q_yfx$S+>eW_laicT;}^)|Kqq+iI0 z_Z8ZDVt+D)uw@@Ep<0I{2x{G?%GZpUd2b@It;QG zk!y8+>x93rA8H3uS5|3z1+)5KVL#&aficOn4(57LRkFdGT@TO95^kY~&=eL8QuFzb zBgy-9JQT{u?@51XR~M|bgBpoj9E{b69+Ut(ZVBqouTR$X%kIY=1xU4(_6PI?trOxD zy}w`BLI%Ev$Z`yenKm!NfR6cF0Y!dsca#yXlSd@AQC2rH>)H1I4zLStC`$9x#5RZa zN+Jm=DaFJdrV9CAmTFWu%KDPc3Mb)U$gzOr(M`g3f_ClC4!A=R3;(&reNIM7EnOsX z{VjpAQI+3rCQcjpls~EhZ=p19sIXYu`n5Aj%PX>i3Qp~}d6T$(rgfb0%!?|u*{4TG z)5tu5tn0V^j}TQdLBgFBOxu8YBCjj{_J5y_Dszi!Z-pGjRlltLKm*{pYEkpxvuD=9 zMShHbOfW}b!0&jwZVpi}!vVUdTwoZQik;N8q-8RE>|us1K`VAAWo?Oj?{?$|$3oZK z`OOo7pZpeTMa}Sqt)u2h8Mdz1=j}u-SqEi^a7G|Kq*`>fCQcEg&UQmE6N0CjPe|b# zQKIsFSusy=n%6mN(9*R=FRMK%>nXA_tJn=YZ@E(2oIy{JOODpHE~WG@#iTP5Ihnr{ zGy>|pM3W=RzW#EB`?P>wb3c7- z{4fPA&fO4GD3{fzR`4_lr91EyI~um2y0>Z(i=RJFd)Ji9$(c4v-Db%;r>MAGH7 zH4iudwBr!24tL|<@~)gu_(fVc1-B0(2dMOZW7{aB#t3{(JI2O09F5|Fb*pI53i2F* zgtgSpD_8>=K$dy51zq%Pyu8x2J3c^7AJE{&FrDGhn2Pp@&B(00&s8=OEi%R>MM>vR zp4^hRu8ZlUCu6m}BCpXyMG?+VXmPB5p$bUIt%#HG+h|-4SNyF^*o7RDKk1VpVz`2hTYJp}8(N~(nV z9({DC)KAmgm^`OR(=z05FfU2cF6Mp&BA-a*v8`cAZmN@PtWD0^ADIwAcHiRB&1yL6 zcXzC<eJ$}bo;E22t_`lje{cm|+fc~gx z!aR6o>hzs?QoxM<(Z}<1d>tIRrS|SxzFGd!M)o%}*;L&$KC*H_4y5A~CS4DucTe>@ zDJnhN_EDeWzfGqe6Uj5y@o?y<$MH#rPD1}F-|4H&v~+aHLk!1FfbObP^;_s$&eHg@ zz`YCS4E)yS$HpSQqXrF}2x85RGt*~C4cf7h9*c9OQvDE4oVpN;GM^~!372sh5Y!?n zJ2c^eQ-8A#XW%U);Qj*WFaPO%%t@_`r#)YREw4Tr@Bo&49t@ub>PkuoV}+VcfgA^q2KYB$U4DLTSnJrifvvkl|1`Rlox!8QbaygQks9D`S?P;$m zcOO`ht+9^ zXc3V5Kqv)@MX%iwL&ZFKBmB?_;}SCo?j$b>`|vWrnAAJuN&Y%Mwe{7cMzyeYC-tGW68kRL{lVmssJxTphmM3Jx{c<_;>z)i-L%Vv#m z+JC;c#HQz(`OAc7ScHJvg50XvrQQv?TbM<@9N^5ulQ;DLxSFe>t)T9c;PBIK{466wqN9gl}ZIV;u2WsQi)eR zMz3cXSgFmMT;gLgaJ#`*?)=pos~koUft7XUK2&q~M>tj%WXI1#YdI)Mm;FPD9wic$ z9tc^&X&_=M@N^dj*WbcCMar0q{384AYATGb939eTeKvxpt=Q?Q#*gXF+ zr{v!-rQ>@L)?iyp4bBlrZ@%`8G2|QS$+jUMd?}_R@lMS(Y!%#o9pvVpeD`+}8)I$6$NUj!8NZK441rz{xxADLhJR6^?$w$~*vtJ{ z<=TU1Or{>~*&ew7hLfgkb6oPmJ!JAD&ga}WS04G5Yi8EOaHQT1@hs^sGq=0*bpoA6 zBio5T7%hwj3)EX$I8vQMGm*G1HZ!xesT)1yvp43o6z-!GP#4w$dUC&0-;nB6SiWc} zJ1eeNe`09gjcDW4Jz7>xMy>U$shnFU5!4nQ#CJ~pwhT-s@`r_K5vuDdVyjy;-78{1 z--#R`YyK9|g`eneB+Hqr7hxtC^CcKppN^F0k(<@a z$if$fn*p5)M?Cas3I8smD{V=qccM4n_SvFCslMu#(4R_hQB6*112QoLc;6KmEO1)A z*u)j)AU3IBXUoatXEoFJHXi@P7v2Qu_uKSRR{P(b!I*8s3}|cb%_Md;jeMWVyJ z*hslHnOm`T4ya#y6O`c{ozF-bKB&?@? z&t#PsHz<7}iE~&7#J`URG@8t7w8ZW6cH@Ll9}9_3DW3~CPe-add-#GEjEr`I-zXNt z7$(9m>_2K+Y3daAd%qOO*h1eAANtclX`OB}ZQ^vixOFpubT8R~MiUVU+w&p|a%)-& zA~!i$1}S{#Y1(Egh<4R)Y5vTtx1`#u+Dkawa7I76%AFht9wh&)fr77;CVkRt zGZ92isYNX|D?m~Fg1;OItvV_`W~Z5~rIJM*LYezJxCXJ(Mt>hS5rN6vRFygnNgoL)-jd7Wuy?*~GkeLHrDdj`wLEO5 zHJ;u~T0g)z^0C4PMdwZFLmM1@o$Bj4>CHzDoS}~L=`E7d*q~%iNnq8FK6<$JSn@lU zvn7_1oR(RpP>Ryw#y(T>}Z8fN*;q*nUdE-hp&SWm{BD_3x+EJxRE23Kk*L?0` z@u1X1P&Ihe#$2i#+gdsOpx6?n!fSLd6oO83>b_ZqE}zU)Gew^QYkJORFRKt#ykBiD z%{x91lPcd|GWy%>1BuFQQETz)^4Z3nZb$T)P2^UZQi>C`j7aIF*>r-P?^^nzIOfD! z%m_>3yhKIN+X}J8Qu5w&hYK8!jYDB7ri(n)VFhdXq||=fo&Wp*1)YPJcxHval#sC) zWbFstAO0S2hHI#Vtl)rZ{=V3Isl^IsA;MAfw;>UD+jhS#WX?m3eL@CT%)I6%n;P$gL`U{UW9e8+0 zVK-T>-21_6Gg(u{B?xW&i47OAq~U>U8c-MRs)Zato`?%q{G|gr*+%M*^VArD(W_Q% zRVtk02o^&!wJ-L&2;WBBN8~aCpeA|pfPr@RX+l2VR&c-+Yys!b{dDC{om~YP)XDFV zUr|$_>_I}{YFYLfjUkVoXej$r^Qp4F>#h_-n$0J{2Nl6sKgvD)1_xfFNH?xnSfXBE zu27m2HSSLQcM;MKC)0jqG>&S53LrrNzEZ&nfXmvfo3RGs$P{Uh36e81XMXzC^hD{o&L}++kT46 z%mv@thtnWfVzsEf7560g-a}W zvCAo5D{PuwZzuKEANgynRH4Z-fkKz^U;+%gr5sXek8QV7ha-T<5o%snA@o4RYnL{$`vQKR;nI{{DA^AUZG zW_6(5yh#)%tPX@#Z5tr$ZnECHTfv3JQVs{DKJ{nu2>*%e+ew7A5%_^y#Vr}i=_(|I z68z%lI&jGM!|pe`lNFp>krf6pGTs68GNT zmp8hls}CrEQqhogm}E;xZF_$cihj833;Bdu?Yk2})QdqsDzP?@p2MmZtuY9E8#;T_ zE4|^A4I93Co-k;J%ARx$zz?rKHdSs7A@o};DgQ=rAZMTYQgg}Gs%5RGuK_hgg2Z(7 z)fFATfn$>Im`F6o@dMY5hr}tvoNc{#a2B3L^k^wP z9n|is>icK`4-G+<X3gg|`nbn&5|x0g`y@Mysh(1q=_=b6-b zv~EtqBPFy|4F`!vA+uL}?n2kS1F3hin{aI+e&sx6<&oxxwR}x>EkRkHF*0-3T!bGW z=OrW(H&9}6zk|qcHaorEw7#Ar4sv1iFVB#Nr%Auuex7l($!3o+C_H9)*+A~HBFaEI z3aS8-c!DAlzYs4Mf^F2PLQ=5jv;U1;y7jhpLEbmO(HWStMfvmz`gQjFm2Gn-j84I# zy3g~B!{jlmS?xS^#g*p|dah7jy#k^LG=#3+Lrp9a*91eMs#nhXpopx$SvwjFfBMV%>N=lBUOE}qJLHU& zP3J9t%42-n1!=Rx)&_Dgc+|<$V7&SDMN^eVb{8jv(bnJjoJaR33}W~iBBbv& zu`{sCc6xfaKTAu?wZ!T(4JNtWJ;BW^crv? zY^H;A&mAuXo};Q*%&4wfV8be99}10;IC(zn5oDSF6fPo3#IrgV{6W_c82z#Mxfppy zB@uDHihUqttYo`Hb%~Q-$|u{Aw*e!9z0IRU+F4Lo!cS7qpqJHgg;ETv0Q378LX^|G zA^QiNgfqM-clKypcKYg-sh~jT*uKCUtM0Cyy@Z09;4Sj3-($tuNFW#632!iA<8BPv z^gpc@cpAuIM@r80aGnIS44lj$8LMhKJ${$STHO+a>Xd)AZpv0TPqhH|_n^XNbS5B8(H?e+eA>M)P5%}%{ z{B4AMk7L(Wk61r<><@3^1H#AXuHhTD6o^qWib0J)PM#`UG}0#DqUrX{-@qT-Eyd@r zL9t&pYQjb^=k1fwuz0BB>Z)aS2{g~YA2i4wXK5neNv^S@F8&m8#~$U0Tp#cYAOD#0 z%QVvWJov9gxaXBHc$&0%7Z(QY%;AF#zpbF%hGTEq!Mf`19`*WT zt5T*<{EyVoB1AO!6aDR6Hgva08nAN~({*cnlw$F{!?J$)3-?poI3k|zfEthH2O?W` ztS1@L5vq>xuXsDSFz7Gg7q*PL1I+19kQ~{?Q(@!D~$&=ip}x{7(}=5%dagj|C^r?5Lfv(|1>ew5l{92Kl@ZH{g9+P zc~Z(x^u^P4&5i#Q_o=u%dDLSq;OoxX)5u4zbghSr;(B~o$x<>F5BRv9ru}3w!}O`# z+p%Q~=?Oq2Rlf+(_u2cEK}db+-0fPj*S`y^|LKN1{d?UTSgUyab^+>EmrN`ZL zvMnqf+0^vzhjQgFYP`-JAUz5CUz}uwUk}`Y#(ohNrJwM#{3y#JpcIxs6tO&uoLh)| zo^Yv9y?@X`C+~<}=e%98n9^xp^L>hs?Hw5`<3})b7Gd!KCYkm(08OoAo6aWSM>PlD z=SvDDqNxe#^_r)sn@dy2M5G7J6;yMnW}u!aa{p}@-<#g-S7;Q~!@(ey?)%;MtBwS&VQP3~FyQrv{kZP#JoR)RH2sOAv79%=|f;8Po3Ovi>H<({M8A}NQcX2CEnQm zz!jMx*ZVbCQ)QWne`?@Y6{fwKzKlb)W#Wlu!-n#Dx%9yPtI}89z4rb+dP)H z^>R%%e);O4`ljs!sd_SlKv~MYZCTLLXEG;kaoMTW1-i{{#HO<@o>~9v1u~U5*{u^s z{8&V!Ho<2wmwJmVMKv97Y+QsVg;9vOxb2Ijhj_@5CaCEH|4P=Z9(d)e*@cMVhD1=@ zskx`^114{I$L>f_LBiO*&%SlilbL zDTiR2uFa)eLXW9p=Pt3eIsbW>U+|0-{o$rxXaNYTG?LNsB@3e`zuW{GB9f)B<$0xZvY{d|H?U?gN8$$_)psYB#WWkYv+YVf+v!Pw^QY13Zz+D2 zS!>qti<(1Tx%&d2q^UC@q|f)c9ir9s+vXBEWI}r2g^Ki|WoYzkzntwYD!pYnvj~H* zSFsc@h1HinW}9E)V@yjGlI%P~@mx#lNl8&5VciEJb%kH!3JSGmf2;Y$ zM){nZXo@nt8z_O%sl{Yr$^XWL5t`{r5B=O-5>Ye5V@vp%je^&)Zwzk(+`$U|4P}wE zMGfkl;L%;N=txH&7~~hFidL+|GWKnfWM`7;*({I3JmCjRnVDo3gLPDpGMAdNtfTGx z63F*m9Pz?Tivg?D9rm{60Q$S^qK z`8Niaa)9m&qZu;K+jwIvxlZ7h_0Hz?>F7Tigi=#$6`1ysoMWrLv4am=35t;?_zjNw z#p5m{IWlr`TCuT$(qnU1;j#8q?+@@TOP6hXD4FsNz3E)}GuX1sr26E~51m)}as|43 zOPBoCBh)6r?8B?vcc?-5a&^9U*gY7R+(8XPOX4wA?2DA}ub18;_OxK;B`za_!$?t^NO?SdPdW}=*5sJ@dpnwM`yQ%)@Zz%+NgYWD{hrEvj6O#X z!2j}Rd=g2kSJRUv^meeI?ABaXOZ`&U<2b%Rg5tmVb93W)=t8T&oQqFiYr<;i&m_uK zyV|Py??@?;Y4qNh^{fL>p;5m?cI)izPv856RA}aNt)J5aQJ{}xt@Sgi z9gs!la3Qj=3Zp4Iz{3B|i^=4oFPAYy>@hz)rY;hKQ5iYKkkA)O?j<)AQoG(6*E zB$DLO$$<;1yT!*uc@GV`t=)69p`*=do}!?Q{}VAwS#QIaLy(+0+BDP%s$OMunaMQ7 zHx7<=Wk!9*flX`4q_IA2uUZ2E{bULX+G@nVyXr%+nqZxD`D9Qc^80tPekdN50(Ee! z(iq-1MOz&c`X9%_u0RcES-^AKL`(`R!<^jYspP>5`s{$;x6#(4stoaexveJL+HT}c zT;e+p6{Tw$I^oq9CU@!w6z50~>FCwd@qD%WDnXG}0vIQ;o_~buBx-wyacEG64^{W) zI4MX8EBlZ0A0ZrMnFlVXVSsUru8AJGhjE{(7W#27EZ-Ra90z=w3b{+#udL1WtCfyQ z{u40nl_OGhaRqK}4%PZ#p}YR}&vEg=7s{2_@0~ifC8NCjY7GUw137G(zgvVTxl37L&y^uxp8g7-X0x}|kUM*#-U$`v@Q}!j@t(6 zR+(^fOh0a!?YX|j(1NR-F|jXj*6^;VA8f2})ud?1taYKSV1bF0Epf%06 z<%(0kJ45^+uxb;VfP5A`n6Hh+$oqb|?zEA;PwVzxosx<_cZysA z6|0W}yjo+a#XmK2trNm5{6guCLox(#Jmm_(sKTaAf-9ot#&qO5gIbpFOd*j%Z=eFE z_;8WSQuUpaL%JzRcLHLisR*n=*h$tJ^hWGX^h>mypcRPE}%pd8bb%reeNuxbWJ^Ye*s=vTma2 zrU6-b6k=W;0KCeQuCN10*@`ds6 zlJqbSXRIopYqq=bk$WiPii!VhxFv*nW3Hr-{7<<9#H#}CgBYSA1DoRKmj5(f_cr7J z&7i-vvF;1WG7nHNNF#Xv>l{T12?%=1joSFTMJ0!M0TJ7D>?@XB;1YSo$LK45FVILN zw(j=Q>NO>neT=NKwee}8q^^}BtWvg5o701TEKVBXvhy=t`?GS9R)Jgl$fJX z)(P`%4nxjfP%H8$TQwFB)z>8i0$N^jPP(yb?%*}I#q6KF6mIHvnatil%J{g3ib!GA zd^34IV_>Tzd8g%ue&&df#R$8k1PG5HfDQ-@62EyEtDKv|s?WhwG-k}x!{J%;{U*JP zi6GnrPe(ZGf;R~`5`H+sPjk2>*l@zycp+)t7;uhoryzQnEkmGi-H(AV~uKb=;#!x;xY!h3KCT;_OZh}_Wy1~cE^lAkbeEn)3877fWObS}H`3dlxl|06lJ z?fC{QCKRS@7xB5GCfa`1NhsnG2&@dwGyXlzlTgY1TGS<^kR$2rSqafeNY6bcqvcI* z*H>CaHv--f>s;B6nJWfs z&ly9Fdd_$#pc&N1vHlqF5FzGdVG@v^5>sTIZ>FTXE@2Nv6b1XDjOCr{_$C>$P>O!!|wPLWT)}+9EHA3 zeiB-Kni)o9pAr~`#g$aNN3nxP_QH@te891Yx3m3S``&OL)>etkrn36*Y>DS~4A_q%qs#Axk~O?9 z^Y3hA+rWid>*)+DW1mgjLBR>X*_dK^woi9FDoHZ4MEcgphB37O`^Trr3|drA_t`CG zFb1p7SMg0}1<2r$zi5+MtdL9;1ut0+`3rad&`t-pVzsCO6KHIEsWZp*^3B^AVa|Xp zSFFdEr+J4P1F#IEl%gT0FJW$~vv&i(ZlV}1wDSpBqtmg%?RS5El0*O*p-pw1L=YNdN=RL7*QuYzU@z-~WuO&x(ObbpgAK z|9DyICYUneu+$+zntjzmgKjrSyR^ra$E-WAEZt=ftEKQ9WnOIS=5%xhWg+hUAEdog zbePW*FdW;qoyJaM+i4m!w$s?Q**J}DHfq?|wrw=V+neWq(eL#9zW2PB&ojHTv$MOi zJF~MhsFde*Q5_@@q%Pch@w49@^yKSKP(^U9Kk|W~bK+sa$(n3M5;{66w=D}%IF+r8 zVl7e>kqPv3xI@mMm4Sf@X(XOgs{PQB-c_y@i3nDg+yT}<;Gh35e?Uf=Skv!*8UCtl zw-KG@U1GU#nKLBm^aUbtt`XJ_{N>>)cgIj)9MFo~(^R((1_y~=fOs5K$O8`E~$`09_lHTUCh zy8h1dkzu_nC*Es2jQyzqmV(FW8?4qr$tH*k8Ibn_@He#Q73{JAEefOp#W`Zd*5L6| zaA;uo>QcFv2njO#qo)qEVr4KxCDxmDZt6)>s+Ah>2mBWwfV@A43^lMnQe;Pfygv`q zKMlpAB_RJR@6Uhf*^>=F!PQmwV15}yus#`F{?0Jp!lcrA?!3{z+?RkWu99!MsKVA1 z@&n=xxT5UQe-+C1^kYb15>j(o5%}{;W)oD#4UdHPPAsjZu!jdgA@Ig6GScTs zwnX@MaB(cs>lNM{)!whlXBw!aVyuCaF47%XllI{Yx93kE%|uJsnRgHs{7Y_8ltwd{ zou}%%Z;`w`S16X{&eH~0LA%)F#E==sI77f5OEwTMxH53sttB2twtY)Z<+DuZ6`1u}D&1_Q(ye+K#bj$XQz z^Ek>>xG;5#IoCs)R(;s{ z9|wHf8g8`q(AkRe=&ll5=z{+p5^~Jh zLr+*g&hJjFxNh+r1$Hehf7;j}IZ;`KY2w$+K$xCqrkB{ANu}P<&a7ad zd2@aO)Fw2bU+UUbX1fkx*~f>_|ucB;VGRhZymz@8YRR&4&zN{4CZ zK(;2mn2f{lz6C!}KAZM@Rm>l9DW^&hC=woZg0IOk5W0~3*u9$|pPZg<()4SYMfpQ% zpEOc9q(2VV(_9tL1rl}k0VAMSMkUXXI`CeBppi<@!#8%^PeYIVX25mKzxfsDVw8Qi zy;jLDj6^Cm>;TCRx~Wrpzliyunk)Sv5cVTf=|G8>B%qkR*&rH1i1`t0^>@S*W+|ap zpqbMuje_Z1e$~3_3?ZWk>K7vjF+w` zqMAav0o*5_5h8`vh8ERFhk-Z&dm~OJo8xBBdL=6}eU4PT3!6KE%_-+!v5Mk{*?#&w zOW%J+-}NKoe~SjusQX^Hdvu0nC&oWI-GwC#hX0(mcv+HLADKuW5n5P%4e|{I-wU0l zq*VHLEuGD(>Buof9#OA2k&r5C0bc2ONPF$N>nij6>TUv~^D9~Ja{z0j{MCEVd9wY< z%i}X#?s-LK9JLowHRdL%XGg=52fy%pcf|4f)Y4t8ULB7SN$0nSn&!t+nLYUc`O#g@ zPuFs>8vhy(U>*Kf{5MOEkss_0Qm=%spIY&dG6T}}wIxZi;#WUA(={;%?jj-IV-tm3 z+~4X@hI#z{=)>Fj_(%HvGsxkk-l6@yOBRW*Yy#j^cuESZTE0F*Uv@_IMY& z^x{!36+vs4a@p~L@`t8R;8v+A``+ZBc|;cOi*3|QzxekrJw7mT;I2>($^X+9)kFxPMc?6T;^y4_rv(5HAaDQm-WK!Y zFr6d|Pfc4&^zui}2>ye*GcS$n%sKH$*tj{(TciGMPErulE}kgVFE}`60{m$U<9;Z1 z4!L1qaE@}uhgTL}6S2>aPI=65X|{91tQ-MzQ()gO+ljJW=^>KdcSVB)P$DTDU~JT zM~jocFE-CCK0fbuBdANeXny4-aP>YF`~qG?Fk3HX_6>SBr|IP3cs5v<=?Fb|IdI#Q zNRiD;PANOB&`%azJ?W&Qzz?GPkf?mF3Syx1fm`du^`)=yj9Hs*Iux_-SCQ_MFTS4I z6)PDoZhWJs6{65@hJosDGntAhZ?1Q6DXOZixoG9X#R8ql$gKL$%0(YBQ^V27Yy{b% zhj^eVrgkRzX40R4@d5TLK)+lG-*u3p_Boo;N_~yxEp99+Uk(0AOAzRjGg$BKyCOaX zyEnf&20{tgY5v}SwbMiHSq*e9<+e98RNC6Jfp&m-@HhUlsN@r69YOTMc7|y@+=;s4 zMsu`G)XHSK6|RH)+^Opuq4L_S6Gzp;@RYaI(Sf4Nu&8o5hDNmykTXRJheg>vq|uT+ zqHARL-<#rQ`8w8UXV>a}%^oKO4wjQx(pifnm*PqbCAmBNjki8&>-UH6h*|*Nw%>@1 zf`|iSf8(u?tY$?|RdBSnzl0 z=D+cByS>gpB~G*hc-2L+IPqL<94odjn1ziO6d9}>6nvR&Y#Fr3C)FosgprYLe-+0} zyG`BEQjnF^$hPc~h96syW7;t&qVTSO?1T?|GiM-xa z2Z-uYU}D@jkRm-qI|vc!pI+2+63~r!ff2_B5^)*W(@C1h@rLSvHGo{@Qv5w$|5~>O zxlY@?!`t!qX+zdbtCtqh=KsH8hT`E-jA zl1qmmo!ya}BG*<9i&Wj>5-P}@{CZN>;cMVBRorTbxk}bb6{WGwoeX`RCx)tei)g9` z&V4{!u>X2zE&Cd$K-uwqIU!xTjgbS>jr^P01h;gA#L~L2)|{2r?%+7vkpB2V{DU_b!MR#)LHizOKMxOSU}d2WXL@R-$PNTqj1g3BjO^x)fc}rFeiI%R7Z#!9aEY4eyo$HfBzE z#J!Y;)?w_W2Gm9hTGh=rk7ZB7y7ly!0gE^O(`!gm-jzg`Z1}i5qpy~4k>FXWC6Kpl zlU^Yt0KUKbM;E8p3^4&CIZH%8@n+YC7u9I;2)DzIBQgVDFJrCkUo^u%hn=iT_-byi z@D!Q+98{Ck-^W^<{x5t0eeaL?un0GjL-tMSxxyYB}7$N3QFV61U!W(*EayqVwbH=R* z`F9Wwl%VP@Lf`|<>DAfDL{g?Lu@12ECFIW+^*^q6j?d#ko}cLkW5*=giHZ}7Xn(d} zz~aku!}PtZ;C^`CR1h^3L(C6#K&NSnxyh06#di|e7{JS>=q$web#im)Of5siHQ0|8 z+pL?vjSy(O680NLU5q65iu@Bn3jd)T-5_pC=}|UP)gH^+4&9?32VpUzgR>ThyE#_P z!(eYPRW+zMqhpIi7xr0j5WSGtc+wNG&FDX$F=6^L}+bV;MiS1Y70 zkWX@a*nGIf(eu;ubq!E9)MjsVg0AC$yaDzhKyL!h&uWdE`>4UHFSb@60PlXPlDrNo*G6h0(w(0V3eTD+>hea6 zi-?0h8KMg`Z>(Sg@3t%g3sqAT6HI`2AAf8^ujJrS=eeOhK{GELL$J6KrDn5qZD8=i z;eI=?U?yg^awH!L5rB3eOcky-Kfu?EG=L5C)w%ikvXHx!6Zl-~m6QfK#tuOJ-Cn6p z?JvA&)LNiD5V`B&h##QIHfTFC8=VmFLBv2k zF7K?82qn5G?6sYOgtz)?b271m0UNVOSynIzs*NcfcTG%0iB=7RAG$B;0dQZ|PkmaQ z%mWwRe*}})`G<}Qq@;H9>zFmUw_x2;r=TaR0PR44Z7;>S3ql)4dm(rexursZ^tXoJ zSt9{(8tPM;9{LaaJNr^^`RVHI7z9P{L{=+h06acXfE#tDtPr5ndNq*=^TD9dODd5n zS0C!TDNGC&4zu%&#HB0=-Ec~iZb?c3B<{vAgMeL#kKiL1jM+kpcvG`Wd!b zK#G{Z)(SH6Qopj&AMd=J6`N-kYy2XOab6ALeKpw)Z(kJl*``K?J{|_;<3PRD;@xt; zKIHg)V0;ra_pmUpAj^QfbN0PO^>#Jwk$XX?4A&oyAQ6Vjjp&2>W1*xuUV4yIJOKKh z4+A7sVO*e!`SS@lllI*+t#x-By$Lk=>o<@T)3(*7IBv1t+I&?YPCm=xbIgf;W}tX2 znIq3&sdMouv%;_d_IW_={(b)m_`~qN5SDuLS2r%sZ-)jYFtw1QqWYS$YNq{54!oH( z7K2>`Tep$M1sV4@@uA|bJ|%#l;oP>DF#4v2W(ZMC*c7Boc*%k1?usm)lU8z5J)~iW zA_IAN24OZAIXB){IbSdweg6R7Uoj>Q7LWR_V{#GpB z)Hf$ClTBWGy1sPY7MM={^D^Sk6$_y|NiW%gY)lN6v-C2@Hkw+Z&YOz6@Vg15B*!_Y zw#Iji4}g6K-L$(de}sO{Ao>^g2P9C@#Inyn*6*TpB&abqEn_mrUy`r2Rq>gBfF!x4 z$3I+E&IpWVdbqZ(?C6P}BhpH4F+4YNnSelTPk)r%NyDj$+H%aE6(C?Rtkq4 zP3=lS^*j57g!{cE2h_R$VhE0PNd>(z)eea*&DR}CznW9D=?5N2+GO4O6P>Do`45|Z z2~}T5$j|uE7i*?EdE=0G?vN5axc}h4~7qGSqs|@(n8C4 z0U^*~SafnROM5!`>5$gXM9Z%bF>H0d^==L|VkUPstiF1skVf|S=-6s*{{8szvGCuq zAC%g|zd*M%wWV-`ksL}mDN|uRSFY$&bK_fs)i^3*Pg|NkdH*5CU|n!)RXLzp_`-**4HHL$^Mp2Ya) zd4CpZ)GT#aj-dH_SBkZ2o#2A2n!TdjuqB}+FvQ0wMV^WPed=F!Z8H(3X6k5vO>ry2 z;qxd%I@CH7_3E48ZP**~{#MsqO8pX#32`jBN2RgpL|puntV_f7ChsA9_`?J0&eCyw z{wVWUg=M_KI(q8#TxGa5)koh8&Krv>&~nuHw%P8RD`EG;`sR+dX7<%UjTKEHia-PQ z^SotPsy5~VYyCC-vp{~?*rS)w# zqr1&5i8z$Y*av1#N+L20_98Mc-RvA# zix9^JEBaSiw!2syzI|En(5sR7rFdjMTT&z+OD*-q@24&}55&~HY35#qGDjcfzL`P( z2GJEHdVwv5QZJ03A6}Tv-*o(~w{C7&uH;^7Fur0g6+Lz@c`}K~#v~dDCk;%!Db%=I zz7cAi&tE95?oUaIjY>4utnVYmLAc?5Jy5OiGSbZW;RxUd^xS{N*GSRuLi?Q<&euhN z1i2E&zYjG~Ai!O4bmLiYriBlJ1VLs-1koY^ydVgOh49OEPypVg!531jIp+`7L81$}D4iCXL+`w8r0Zz2q`97! zmE0bzM)&D0our?Ul8wXonF%!bdEcvNH4s(yy5*ga$-nJ+W5NmFbfPmPwNHkSp{;;M zxbS2J;V)_?p<#BC+=XsZi!*g}tFvIANAR7|xo-)d<*5^MXSyLHbItVT7OBef_kLf^ zIUB*Nz06lU=q*)Pu534ZLGSck`!qTsS*a)i$)R$a;f_zs*Of%qT) zT1V~UUu^=i8i#bizwDJh6}18DS_g~FF_|~h_h0M!Z#e0#%G@ z8fqe)=u#D~MvulzpkZ3vl!f|Y!~y;Lxy(4o*$64~K?R@}SPy^CLz8f9TuIm+GPkch z&=(zy+_s>hOm6t=Nx3zG3~MbRHP&st5=70YMn9XeS-+G-F-FB3gDLLy-mw!md??GI zg3>(P-iTe+4ESlZ70fEIr*g-wkf$rL(vq-{_K=Ijq{uKAR>7?Q0QYgh797p+D)x_9N)<~kcW%mi?2Q+=2%1BA#$l?@t%^> zos6|AwEZ-Xno_GIIQ^4r$ZvdM@sV%h%uJ0mgM&ekb{^MT-uze84&iQd4`DW|Dz-&g z;>FbJs!oCo3S!AJ2&WkNjk&`*vd?FX#yAJY^vR!AuT?x+ZT7BJ$1dN7vu_aVE7$YZ zf`>yeY+Q9f_q>TUD?zd1^?S^iJT{YIQ&H4-hEIq#mo}HX`XN2ulcGK1qnPV3(!#At zQ`k=S-%lydK%sxc!(fW8zBGnv**t%JPZvbNU3H@aj9Py`u=j^=k z`e_!4BW&WIJ)N>Bueoh>OB&E;*77;5N@AuuAE4WhDQFIy z2}BvO5sW~8#|(-i1%LTKwKKpiH%hOP>FzAkLsS&i^;@nyzGVmTsGgJKfeW)!=?Uh- z+ua1r4nhKmL+zamTaxKNfu(Gt2O`KIq!wHoJ$CCwZX_fhna6bk@B7J=U~0!j5S%+i zBGYF%e2bqGUCnfLB==cmzFWOG^gv8{S>&lCeY9FMb`qgkl;cDJnn143%+>n>OPh#} ztsdpD=_py%#aQ*3?PU+kO^~(f#rM<4Mw6XUerjiw5p}HWpKL+f$z48`dtR*}28{Wl zR|k4W?Y@mv22$166mz{W7}7;(v&b8 z7BNWzRbhemtSHlyN0&mNm0$BrW4*cA7}|7rA+d7B^nyq`KAA(Bf2}fM`D_q|Pqz}5 zsoG;gO&ZkL!qxNq<6~tsxF3@ASrj^?1v)p%F%dPD7U>sNFQP^6U1Wa8)3+UkX!DFb zS(y>~p06skE8PV;br5VR0oPqRl;5f4U2Lz?Z9!&LR&q@-Lj#usrulWNGy zo%AfgnYY3(g5kR?nB=sEyB?B>gV3^Xbri<7z{k6H`PY-I{8hDU# z9HI=Y8{piIG_eT^;mW1__c=(Iskit#W6Z%~n&1&5poyu!6&*M|#`LnwS~Po7T; z>i$vhh!VJ$lbQZ`d6C^wH-($=eXP&F%;9_Y{VFDJrM?VL99GEVLxiXil;XYYx&d&S zi^8&?)gZ3JU&#Sab6bkQ{}ZbK=*2H9Sr2zSWZT^Fr9hsm1~LXg_?x!tC`D4286^0O z#sZs2g_KNt;=5~o!;%^<74qp!En0K>i#_2I0)#I$Kpw>V3ug-)vvgR6d)Mqxj?!|E zMYF8R-!IaHh)&UD9j3t|EXl7u*3W3J6*W_YA1xAqJW~I+bd*S+Hh5Df>H>7oj^Bnl znih=!bf_6YLlvCJ>HSSdYpbuzvLT56zvy@uUO8Wtj2;E}10gPjdLkgKLW5qVx6Hb_y7u^q&g| zmC3a|`!6SZ?!AqYK>7H1lMopY#lwAi7F@)85*VPo^pw~icX3VaW>^ZYI@VKkk?yOR zcvnV&seCOP6i@#1{Nnqg4*sb@QAd}ZY}$Ip3f)t(UcWNSfIrDul|$*X@0lqI3u>PR zfP8&y{d$uXw-Wzrw@#3p+~xua>sA8n;q;8&)cwK=tr-#N4QQX*p@o0!L}bpPohu~r zWv7|7Swd>f2760LpDoicxIQ3DRFT<(b0i3K10q^#&p8ul->x|ex|PIKr@eS~O=!@{ z0rTiflll+sSQKB|&tLFU^?-iEPu5AC3y*XBYrh8aYmFc>?ka#6ea;ZYj>p0J<53%U zwbW=Z`KDIG{LvIU=j-2c2Dtb6mz`fLYoGb05i~PDSpptRTsXY&8~Qvv(uzs_F*rc%$cr1Y#!Ju0+D{g{?&c)USfM|#5lic9t{x?o{o zjF8+(;TG40pJB_6LJY=IS^PFj{zQfOfJg$eWgcTz-#SLTT6Vp4&Qt{F!wXo0`wD-i#<@T^AckbxjI^XAFpPg*r{b00~JsF(pt z9!e{Dt7cFL>? zpih}Uf$yEAeGN}UwOHvcHd7ZY_C$O_ju6Uy2bl~y(4G&!f8OL*bzqcSu*jNjK?#Xe z>d9F?&HPM99?+1F&x>U9n?bK|Zl^|rs~=6-J@j?jk6Wm2?u*lgyRrB*Nj=%uNx z@Mi6-oQL0*e3&<-n!{ON%7Q6}Rr)aN5f95*v#gyft1tU#)%X_Qc!|gh=UOC~u53u! z#UKiA*G&dOg&tO)LJGS`4i=b{wHvY@e$?rTfP{SuEu^_s1}A4vzdPK3vyHSQ2m>y` zmyK(aMZx-a7h12{BbX;JA>C)x@NKz|y>O!B<#)}$&i&2c~CF_`fu-RAs zy-xnNA0&L<48rftNcWn`Ap3z}96bGel;(uFA^k5q)VmJb%5sc@tg!I!+r4vUic&9% zna?w+8qQZIy&|aN6cC={eiePS*Fc;~<7;dswjI9^J}UiuDes)cX2t-#6oKD6&(U3S zJq)$_H*aL6&oypEsWN9DSBRa7q@C{Zo%tDtZwGX2V+XcD$Ge9DV?ygwU}9tg;h6Tu zlOyvZA|z)b8Xg8eR1AsDe?p_r=S>{g9#Cf-Xv`}>VeY-&G>6ptxs2YNtZXE7C^_A! z8eLMW=*;k76F52u-RUSD=5{=SEDiG2eG;r>S9rx0Cnk#FaBkSmqexSP126kReo$9s z3L+BI|OPFG#Z;R6c@Kg}CM7j8(^COuro|KkrH>==*{C4DR85 zosGma*2YX^0MV<~ESo-D%}W7;DtvI&v{MReF!I3V6JU6|Ko;n3Oz?V5@Qx2F;()%b zDz}}>g96G2zi!UCY>@sB{!Q1>W|35g7I9DLT3mXkk?wOU!Nn!LLm@r^DF~-d6@Uls z6GAh$gGH*BO4f&J;iI?AFB_%Hnm^ncnLtyg?HzLVt`0bFJwIOS7JWi6o6h=~VG#Ix z8bwg~RNz()#bv`ARa2 z9rfPcT#{8NE#D#x>)-z@YjG#)D8<;jbk2ujTR4=M`x&0~&pb@Pz0eRXPhyVZBbVoQ z*~#gz7APg#+Ft3&Ht~S`)*G4dPtuzC3c-KOxIS%j!PAVm&Xb^jBO_ewzw&N84}8nH zDBE{QE20DPx9@_V3ptFfoN&gF&=9$DMUyGDb1=+;u4J_qoR1A- z+5%qMPO1h3mx{q?Uvoj$@XYMF;PW0;)hMORm-sTG!AGuyc1O1+hjAVa{6y|rZax-r zj^UV46e0RpCz!3$vY1*MUtrk#R-wA_}EW2Tt2PplCnujpkw&F(T{XwqCX~kvr-2^^RivgdV#oUAk8#x*lcTkm*OiY z>5`EZ1!a{t$Vhp>uIHxNmOQAH1t0TBSeDjmOk%D!Eh#gWgk(`pDi$^0mE?*R$l7^O zr3(o23H%&OOO7zq{EhpJbCEpBnCu*B?TWnCozQMs%EVC}4BFP}uq;sonk>XHOC;kZ2jLfKIM1Th%dyJ?WZ` zDKZN0!CCyNB|hA*VpHO^xf*690UOveup_|t{41*A3Rm|tk67m(bH8;qS`F6yQ;sF1 zR4$G{7Y>Q#gn?1^I9uPWYitEG6pb$qpZoJvkT1M1!1wW+f)LSM_vueVV^Q!>6)-gl(~-Mfg}N8dxT0F{+B0s@6jhrBF{*6!{In?D|fI<>bndI;7E9Ki{HbV zG7*b2hOoDf>nKatxDZ@C_1kL!<7rGNpU8-TTb!kEGp`GNB^*Rs~*~fog5FNfw z>Fk-G+Y%2q8|yif*HNpwlpmi!Fr24kqRi7V z)qX`2XElycVFfg`BY8TPQGiX9Z>eCY6@K%@RqWNp2Q0Jy5%{ZGsY+3Emr*^;D{WL$XqJlm||C2cY*rxzH4xnfF&VXS;k$$|MyTI5L7@~M zHx(pf(DJFh_Be!ek@a#N;G$kPeATOmD=`GWQ?2^hCM#P~5J%0C>i*IF5xqIEr+oBS z4}Tt^NC_g^VL})o8GdA)vT!TZ8?6o6Q~frOaZZ34DE~_i{U9Z_v7TUo7u_k??^yIZ;$@SVowq@FLL*^JO8Z23Omo%`yRYwWv2N`c&-*|K}tQrjbO^e&e`!LrYS1`c#qwI(_2{T z6Zj5)i5m8dO5C1zMH#OD~gIt-!ru?X5!U}+|ChsKH zZXc&bCdL=ZEf#5Oiwp;MuJWgoh2afe3^Fe)l%VIQArjI9kI9aLkR7?bu2-Od6j1LTEnkC{cg`o zM36~65wKGFW>_(6v8uP0Bp$e=L*E)Q`Z7c>b8`f0pK(ijM~}tN*4<5O{^VGn96R0> zHCIhAJJ$=%IIUOw#CIjiJ8)^Whg;aKuS{@WSrFO^2Tlw}W8u&!tTed=Q{pB0QI42! zIoVXgtW#;|xj)eCG?uU5@&f?BRSHnb0dp4*`{I;dfnmZa#P96v!dpHAz}uj0!&wn} z>j$PMl}IipYQodMe<-woNdVw4m$hp|dwzmlD2IgklhxPPYnuWr$zx~z^d1lN`+=wgspCdK-t`EX(0b9RT0R6bM`kP+AJxjj=q5J?_w`~6S@hSH$ zzH?tO1&))#**c{?WuC=L-_h7&Ebl`zw0dP1w}D8T$I>->gf$6fXF+znAxB;ZThcFIdkNA)Z= zmks8W>3fq9qS&9E!T*|*F2ocA3}6wLM!o&5vI6sVK^(boxeF(M1IHyFv4 zuma-Gc6(>ioKg6zQ&)eY5a}eZ?2aSZIt!=(-=&;XBN(u>1^=c01O8}(t82ZiKLdV{ ztO`$KI8r|Y=k0&_1t7i&eX?@U7=ou8cTIWbmlB|1C0lOa7wb&KNz{h}ektWKQ zcPntI5A5MO_i5>7WXH`3dy%)jCrq&S{=ryd1*cPzMa!eQmxq*VGCFGf>_TnBp^gf9 zUuUFjMgxgbz`(fG=8KY%yE9+Xz_2$nktKgv8Z6pAi{dcTabF>2 zR0NGRgC5wVkt8A)O5Z#sddjaPE`v1=O(3;=`O~Qi#b9Gvr5MW2g^@y!WmR z`%)_Tz80fr?oLX+^+9+dGQ+l9>QRn^QiVV{aO0MK-h&x#Aa855L5SwsJxqopm99J^J=Xk+`k+u*Quaw{xA^R5N-;)akyyi+2V#u{B=~ zFRce^wZ4Y9JL~}cjj>ozfDElh1>gycXr&+=^x^;<<02OCi+mV00I%cgJjYYuGz8)| z_-T6BN+<2U0pC|p@o_ZK(Q0vfV0B$z#4W*GkEqYP3aY9KjE}i5C`cL}=uL~jh#9yX zk@uXMtuO$6InMBLgKs+m0%#{pD;ceNa)iPVeCjuO(6o@m7jBw^U$a+0dB1sg=P^E4 zaRA>JE$4+fP!w8VzV(b3l7!vSxdG+5NZ;Tc>fpoWB+6&HNco ztSj6CXdr@Pn5l5*);3v}Pm|k-Xn^{QbRHG*Z8#mjqEWauI(LVF`pjC+(DxC`IJ2!? zO-oar*)X&Ou}sJ~CowizM|bO@{~=7ro7egb`Rx zv3aPM2|?qf4@&T%uEZEEf^}Foc^(}PAJV85H!1Oo(cXTu|gxU{> zJ zr$vUi!cPm7kEs!{0HuZ&2j(BM-mPttW4i_LEru(n+s@Bg@mkAXz*v?WQkqjK5wiB` z2Goa<#23ue73>H3eJqz(X*LQ^lg$kgl<#`rU;zIKgV#X%&zVDh*F*Tflpqpmw(zOo77 zz*A$9ZUgowB_j%)bKk9P0A3Uve?IB4I}O0=R}=-pz-u;1M?x0*PiZWY$?Cg=QRQNym)Fl4K2R*0Px{4sJ6gyrc3~? z#u3@aQilHmzz=h=lxVug5&<}K!I~CLR5>Nko`cOyWyTQJI$$3IdkzJ6Ydoa|>Kk-T zbXf1|s{!?WK8FVX;*=%<;3@L@W;sb<@c5 z8l`%6rE;G&tg_F1-#s6KVd?;Sd=3Z%+Jq{HfbY*X0l?>X~ANxbl!0UV9k;G@rgM`~64^W-KJH~j$Jx|jr>6X_cWd@~ZO;VGVPIUGhsDdJ@t+a9mSaOsQ4 zYrQ3q4<^dWCXl0^6b?Yn&%->?qFPAb zs!c%iR?c)R>%=kZ(j@b+alNx23wP^n1M@&$!)q1N8+04!_d%+~(Vc6(`7IyD;}5qJ zMZVG~++;X-D8TLp+~?;~jUEQ)!8P-7d3#RSl?70WYo+Mi)`1 zy!|;Qw*$-z2_Iid(i;(GpnQM=`o-@SPhS8YD2?eYn}?waz-0v*gL;A~F+ifEO|aAn z_DV_Ez*l>mx6W28u7d-tU@{xiDk+LrzOIgZnkS~SEhCYcJbs=xA(VT6p3tPgkq7R% zLO}FPo9zpSASxf8U{d<^u?<;Cil7P!0r;Pw(ngWk_Jjsea%6(q`jyUA;e2ag#m8&m z)t)M5wYW#0XCAVoZe# z;Mtr{0sX*Bvkg?sgZW$?_L(8K35>3t=ryrW_N|T7xKsHODom6~aocaP;y%zJ*(^F; z-}Y`1+f3e!NKSLo!a~z!*V-VANO^%xqVg)3DJ5rh9^wL+cUxv1pVhO!n7)T@>dfFb zOd`sqL&=zyZMVN%d@p_)z4v*JJuyUt21(Ylu(BT@^ci*zsX#pH?Cp7Uqd*e#>pXs7u~AdB%-54Wxug!()!vWd<2&yaipr zR}}D+j#=Y2!o>UWkfsu!90mS$t$JPtbyM6q5tfC=%dbgNx3ziHHqe zDaxy;DSBJua-X`e>2ip>74JV%?WM`$b>ZQSspl&6DN zpgw&}D}ntxNuL$U(>?B&m{;&8m3y2$3`hX3U6qo7@)#o-JY+c`CON6-(Z8^lvsq*E zE9KPBKbiV|+_+PiU%!l98e0BKBpmy>pH_pnpCfwtfi&IDue8mnC;h_iV7hp@K0cz@Mb9B2mCUf;C8$FBucReR9a&{a$Kl5S4p(|-v#!XEtuWG z6*#bwLlk3CJHjK+-+E58AP3>gz8Z1a)OJ7jKrI+#B{4?34{}P6JM#JLk86oA;WIEX zAQV|4xPJD?aw&?<-TIT=3NJZm?kqY>Rv&TH^2XQMb$6ChmVzlvH|h$z%i-rW_f!?T z9ybgOL0?;=6mSoRmYOUauFm%+RybzK>W0EL4Y#6N&q}91U%9ti@9KyP#)C!


    NjlhpxVsL-xkrq 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
    <@sH7x(wN0K-C%%QjNDH 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

    WiR6Xv#CyEE_3!29=!Ed3TgF5 zCeKFF&GLtiz0SjOE*;_nRLY%icpXS>O2QRs^_QrC(gI|@)BT(`H;D2>OiUnO#yEyZ zv5-bs$g)BD+n_CiEJ2AC^s3vS(9#L~69oSpLxwr=NJR=GJEFvyl8}vdNa^dEk(P|# zCkr3oW-0!QzY-35P;k2@^xV1MW*hVuQWX9F)F`&1YuRyV%J>mtb9-MwBHN)XtW?C~ zgir`)$k%T=DvuO)i~NdOJOYlU$OgqB`3TxO;i!h}{_ zLLm^1yh4y;ZZeyFDU}`)V-Q57-3BrG#8C_RYp87w-2 z4H*pk4C;*MVGTw!)w~k$T??Z;At(#IXL=Fa-KA|;MD(5d)`pGM#Yp_#925EH22;YR zu4oGLaVXZN-pH@ z!LZ1$H&g=amXF%bpipE_saQ>M~YNvvrykdCRL9X z8V)h*I@~q&-G0p);Q#rEOsf8Zeil##w$QOH5gs1eP&g7s$lGz&=eST3{eh=$8lM@> zhB=l%@S%}i;B2Gg9x1Kxfcdb3F&EZS?c}r%c@HmjvP^dh_JgE&VPLSrE8_kJaqbHGdMkkHOzQA`wg68~l7$?#YUamo=xMnB6=2laR96HsU6(RJ$g%o0up1^P4D zP`k_)J>#Uh5==#ag?O;`_zsmMWBbwW!g%s)TCw|}PktM(*czjRHg_MY zQdf}#^TI+xU(3F}8pQ=zmYNY8$5x=fh(C=Qh-}G=)oO-dE~@yyR4rczp5`LJu$Q=S zilu@yI!=>Qi8Mlzl98LfGqDb;Kd`E*ms}e@#ze0{35V5gLea_|QpKlNNB3P={H1ek z$b(nmSteR^Ac}Jb4;h~Ns~!b4OriEnMv5}ELaXlRc1fpY9V2(7q+vE927)9_^4Vobx}D)1lLA`njO}G@6K(TOgTd z<<8W+h0Y3P)I+EkVAkcm!Q&AXF^%zi0if1wHP8qZF4?yH=OQ;%Xao6p7TIhFWKj-l zEX1oI%kQ7i8#%hC4y^TgVyBsXo%KzyG}gf1Y$tL)=~e`TjByEyVH&naqJvdVWZ)5u z?iN4@1zXod>1ot(#GgLzrWd{dp7bJ{a5~AEzP0B&p3!O!F7vlUT^;n*U!)WpRz!_H zC};qW*mbMgl~p92$&23kv#Ek0)u*fC<+_FUicKEW?#Ls)v;r+2@|cK0lyVSu1!11} z9ME4$_&J*m;+&6ck0adoPp;mX96q*Dz*4``Lv=xj*$y>Ag4p$7Wb$-ZbyLg z!iTl!Tp6(8tyI!8{-`SL*+k;UipSA+W@fy1azT&!P>9l>kK^mzy8IviYQT967P`hT zH+l<_M=HX9(Ttfs`l5D;Tk`yfWX4=bo)DEH`FjFvRe5UPidT`tNyw_~hxLMYsOq zr1*&4^UK~iKf~Kq4J6v=(1GW>C(kSO?q%n>K}^~Do^MK)TB-*>oSMWlis6TMpLb&|cic@q?>Ia;+6!i%j+`I4rh)+XsBl{N z?3plkGSiLhmfm^DcSA$(tKUb%aQ{6Azz3g!90C(RmCkRej!{>-|9^A>9@9oHzI%cs zvV3E)oZq;u?my3`amo9r=vJwonmIUumbF&jPz=*-Yf1x!+tjmV$x&PbVBv&$;s$cs zAk+hM0dwqXhqUppWaONH`*kz!*CL#H-`MCg;MhUAkl;VvAd0#7!}!0?e;p0b#|~ca z<_!qa&L6gD6T=9cR8p~PeX-^~*PxNivj#K*I)mz1YBCJZQo$+2L!fG0M&r0d4nSPg z3}I(b)I92$>7$y`8?Ir1>vvZB_S&AKQ(kKy8`0=}^Fo{q){pd>9Ir42>vl(LgTj)K zgq%kIM;{$@VfKlkR%~N57xgX)Cam~yV&M>#X9}Q8riBwtQjfk*EK z`icK2MVfTimv7}F`PIi%@xstLb30-$ST#}63oySh#>vt-#K^Wl^K%H1A4QtECf$^UHW56FYudP z0EJ`*Sdbu9u9WxU`Iz9wk|e}VwUfYm4HrgxBWd;I)7G)2a1jSw0ODo}!f0*|LWbn3 zhC#vH_nX`)M#y(!v=JE9`WtHkA927ge;B*Pz6Qjote#+oQpoCtnXLWUKXmZRK*5&F z^G^dqpPqKyw{m53Ex#ItdnEpe()iUTO*Y-HHWxz*HOJ>Gq$!f%d+gd)1rX_aR{USB z;#QEj92u6<^x)SN>Rx5D-;`0$_1lxZZLnf<>$;aM7Qlc!g;h-^=0Yzx;nQL;Gu*Np z9MkOiP+UqJ=1>tlUPeHMpGJ+4M9ErqbVeWDE{qnw3}S(I1JgkX0d{7^5y^#;4Z%aU5b?xyC)1N{%f`Ivk{N(&`znB!0frDjfQt+RO^*_dUMWQI^f=;LO zP=RE5wY2B(+}e44?{{KYzq$-3-=!1O{NR(fYeU_Ix=w#eHq4)5aIv#D>eaJgeiYOBx)7{yw=C;*I|sc#mpF z0J_0U&@y0ctVoa|;v3aFa=@psN#Qw8GZoaJTkYmLomRtC0j&Z9AzCF^8KVVd(qK&i zJxgxvHswkRu7gIW)ARN;e_)&GbjiIS;h)@e^H4xyenL(+$%t6v_1Ozput=>pI690cZ_ zSrP`!gLrLE<;I*jlmpfrv!v;KkTdvz^@#`7C}dCT2w)9UhakS>l}rbOS`+j0SFew= zabH$ZGeuP}>LLki#_%mPpCf|8ALElMvSJV?EK#morK3bKAuOb#j_e@%wGSlo&n-&^IzgL(uA9zjuilU^s zpkpQ4jvn92t|L4MpPbf9o-<}GXy2v+Dz`hv)Sn zQPg}VMW(jS;Rk7!ZD()6RRrmWo>$C3P9{F-DSqjCBj=A~ff+on%?cr|JGF}!MNFi0 zdaIrr$Df-WJ0J%3HxiGv2abk^jOL0ZCrsMfi5pz)`2XP2=NumkNv4#Rzi1$aLM)y8 z-7Qs{Y2$B^F!<gU?BWNUmIvio{!-KNy-TB=OOy86 z`-|xuC4||hh7~!JC`C|hxIdg;+RXkV`ZlBdHu1@Js4emFdqzs+%WdMHzX=`*MV9X{ z9W3_$e4xm+aeHYw!I`fL4axjOI&-XJ=f(0d1=l6m#P8GvWR56Sp-NW!Uev1Bt^tjxV-5yO{ke z9Se}0bvNo6s$9Dc@%nhYQ6f^yD8$85YC?^)qJ&(orMM1?t-mwg_wo$wLf&?@F+ms=Uo3GX+Z;sX*p-Iv#${-pvTU>IIU>-<4q#!bBt zIkmy(=l%k5(?9zEfM!gH%Jb5MAskeBKlX7kAm#%`7OV_Wz70LzKC1`*6scAZyf3bPDgUg z8M^4te{2^anOgazUQteGAFAGh3W<*9k{t)s@!^?jLWH{f>5LyI%&&pO<{y^+-13XE zoYQv2+y!w`L)^HNReFp*h(=2JTx?+-fi~)n$iqh+uz|Vx)t&pqmx^r3#-pC2PX8Q5 z;Y2aLcj5)s`dhPWE=3VFt6AR73K9|W=gZZm_hi#EcJ$epN8-rdlV5~&NccR68sL%= zkFM0K1Ui4+(@R#2-~;a;sDxdZuNS=hEZCpV*3gNLK@+VoPc5t69Q*;lQIh*&WCJq6 zI<&@IKXE8GWz1~J1VbJqJcdxeYB;dw*OzrlVfhz5Zg1)r3z)nee5F$`F=-GFwv?VYw!;h?u=m4&r}q7AHPO_e5Az_{xI!*6~ zuJoQ^!L3-zSgS!?gJj3hC5HFu3*ID$IVuKvx*oYR7~}u;Q9e03f*;AiLv;QS{|c;P z|MSlaD`%-pmQX~H?(|O<`gsdJuvk;)%iMX=?5dvB0}*OnO4_)rri1BJqXq_X_^6KQ zc(aRu_1%$#tcCD|52Yv;SjbaVnJWem=4*BZ-`8{u_(shv*1E3a727hO?#q4ibg6MOQ#_OiSCm zK6*r*D4^&3%Rce-jz~QK{HZpQBP6uHpOBEl34BNqU#WWcUja-!yCwD^+bpR2pvH&^ zF}0yZQYkfj-;6F`tkE^3Pcq~od%H5dY_zMj&n%+G$S{xr#?_c$&XWa_N3!<=NO4ic z3U`)B3?rlmgyaGFTJo+^A%+lZJ2Kdn!-_Bd(LnS$Ri~? zoK_MlOw0gtZt?x_-VU~8WJCtusGoCTc|Gvn!hC!xrZ&w789I25+i@1q+Jdr22t4_- zPJ)?DmigqW-Vq=zF4eT`6RGDAG1D&LX?<@#6E6}-#!|kLM(by1nmgC@uFGlJl>Ib? z8m8K-Ne$#|!q&MNM17=I4oFHWF0?HsIm%{)`I}jgc<{PqN0HC&gs<)~7AQ0k@I!gR z>ykA4tk+u^kc@ApN1GBb43Nz-yTngz`{kJKID0Ee8!ZeGhta()jlxk~<1w!c z=Ilu3%g2knED58cI~}l7r3`<*SaJSsa5q++uucIim05azxveyf-|m_gST1nWDx&M2 zy%|~3tuK58<^vfs+u?P=yzwDEt3OmW=btXR;cpNJu%f+7fx2+8U5`+YFd`kTPw~#X zL>Ab2jPq`4VI~z+VZO*aBalpjTrQz-TM6Bh;d!(9uzf)Z?y`U_Vm2TgvUk}tYGfP* z*h#*9=w>mbn1^g>aX{dmGCA^#mAN_gd|N!YWc2E8KTNobhKe`uB+U#bdaP}~7R(+H$rVY#5!Ccm)X!iXf|d%i#X*gAS7%l`=%>#Na*>feBf zPb3GMBYg06C?|QJWRhS8n8&jNa+P?_OhG3X*5a3AF_-95jql_v@0bSul@|D$e4-%@ zi)k8%X8#7D3uxY?-hsx4!P{yjkVlFad?-@F4KnX>stUlH*h2_|YkCfUR!uM$Haubl z0Gqb6=dDmcsZuMue*Pq65`771E9;PPVGEU-2tig44lNR7ZiN3ElT#hDjl19i7W(KG zi*>8<(5)2uXe1ibSm+-4~aQ6fylR&?ptm zP-_s){TF9~-A1{xwZjL6p>0to z%$Q(<T-Qo z2axOpD&Tqnc#?x4R`_n@6f@}+IS2?P-t&My%newZz;uwvGJq$ka0kxK#5{!GNPEcR z!UYA?GxF6mj8r+8?Q$IQ*y(NqtU1hwS@Gf5&jB>bz8kh3bqJ8BESmC#JRikY9(?spJs z1h=i0rHXp<^6%Y)HT-T3wCFuoj*&JJq}j7v$YXb@28yiYX0G!5HxS>THT<& zuE`c;(cqW)4{Zr&7+J$_o|clT|1Vt0#8f^(o1K4tF8v~?MU>O>9nIZ73ndVpcy!dm zK;kUHc&FoQF?nJ-IEp0n%{3epfG;75g@b1Az)TP;O=}yfW;J2Egg=@s!gSGf`@m%JvkE|}aCzEVMz z!gRgW(UK8oEYy6kUT;$`@XwX2^@frL-sI>Sqy^8kJebm{T_L63BY%uh@|VmRxfG> zz;gpeg?W3(>Z!sFN{2MuIO+iK+$9dVZATdTV(O)d`4-FSbxxa zzy2y0{+^^E9ku5^lkReR0>$0XW(A?5!%Eg$l>C8Y*=a$C+tR*>;|SonA(TB~t+rkw z<+z0}FWc`D19)z`#oex8_nKB0Y3dvhy2(=i<+(ZCkyGgMd&iC5<2w9AhRg=sryQN0 zNw0ZUN&wFdHqs!1GDOj!5P8LY#?>hb0>;2jZ?)*P0OaDaX{C49M2@Dovm_$xo z;vgpE{O*|}r-rZl-bPcUi|Drp_IVu;k0)^a5j+##?HzIN$9E9fqKdJBxMXxYMeZaV zK7awt%uEC_>T3fqE+7uKr1J>~-s(D|3h4n+NC%JKvsuA35f5(KluxubU?KgO+pmG@-$q z&ZKYlyoa>*_88ui0q5M{%uH$)$T;ud*xHI7PRH;%UJcO_P{RGi%@2=pjbjO(!C-)f z5Ex@kR`M9l2@k7AAn81+B`{}&jd~U(-de1L1k4qR8n>WLH{D5=)0@-${_5Tm_YWT* zvieDqI zP!B?jlUiE&37i7-fh)Q4{ECL;t~3qBL=_>K52+$MKbd>Jr}l@3An1`O-uqAs#R)#> zjzw>v2vml7GLZ!AKMp?S;&sA@#YlPY%6an z-@liCKndtvPADKoNeL`e{!^^-6f{u|cFZ|LNH?Asl6%Sgkaz#xQmX~}W?av(Nq#KP zHqP_dryu=Vd|`hP9>pyljeLcIIN8o&EsyrOzsKaGya?#$T9NW$pwy$r@F@Ye_q#i8 z+2O7bR+;ZlU_QvokcF%#^F?xJAkMibyn%dJs@7^cg)_=d@b(}{{BQfSoxjEt9tS*o zCw|F#K2?I*P;jcb4u# zgVWjWr(}mfd`|3~E6A@=>oNQwvTop9W))$^aW02M+cOi6znG_brzGO<&|H)kO)}qS zFgBVp^s7fhl^PdQt6?o~DKy9F3*u=Ojj4lvGPU#w>tFpIlV-rb#GL(pfb>x)#uXuScUCqiMA?JHbwGs#7F6_Mt!S>iZ%!wB# zIk@FsHhj+44mVxe8?40X;^NeG?0$vMO_0xVMs{}z2ygS}3v_;^_m)&7`J%6RL9jN$ z1f`iStDVf4qBEJ%09VzDawKR~?Q0b(4o$iIfjM4noj#|@1;*)yj&Sjn7>gR$VVjt+ zt{OQr3uUa&49Quql8;ZQK=M7+|LbnAjZc)I{4#FlW7!i!6q*c;VWQ&RAKceeLUq?l zpm@gp?LKSGq23Fg*Ci?Lj0Jb)Tb|mea(?oG$J}?0jqu(WK6CG`6riKrC)Pd3B^=8R z(D&&WyIND$_Yb|RcXHAIMmWP0xJCOB@HesUW#`Fs=^N#wDhdxsZbKT#qLglF1bJZ_ zU-4156&$YE{R4k{w|HUn#78?Nf*bU@8PiS$Neu6g+Zd11WNt`XooJs@km&xxEqic8 z>Vda)Am8Y_u&$;2Qb0qa;YM?^V1M6uUUhvSz8yI}Q4ePhH99U6cY!Ivb?Mp{UhM1O zgvAro2=y!hSQff?f>xyDL{h(6x1HIN`e3xxWO~?;I15O!n48ZRSX#_Z?ORdv170~o zj!8*wg(%^+DOpEF;YSdejHVS2C4xdm%xOeTLcLno+C_JyYuzqAZUS8V@4()L7x2gyekH+Q)=!QhMzoe(u+p(#{;lBbJ9C#aRQ(# zMEEY?+O@xSh{vN;u(HQihdhK!=5ny$MYxL*c@}PI6k)*V!F_x(B%=nrU&1XLeR3J< zBVe4@23}^ZSMiye$KE|w-0Knc{t$PUPh{ra;TGdD&Lpg z5h$;6%fnejk`L&0{t-)4H8QjM0Psa6n zmtc=GWnhH}bxQmbv_^@+WxoiW@$P2Hf&BObs7v$vcx5Y!zldi^RI#oe)TLL!U=Z|+ zd*)y{o~$cc98ZHz??DIk;8Yt;8tKs*zo2fX(8+1*E=4dxxoDW?KiijslJke+JUL zT%H2zQ+D|9uHDIyjy|%iV;tc4hCeU1EZ1Jk(C8sOzAzGwn{f_kuHZ4|kXQ>kk0)}r zQUi(QW_UbkLYhUQo)}exG6V34Pej=RbS!M%{>OYk#4XvuHgkFFpL-cyO-%+|Svlip z+=(G*BUwgWfAL_EipDw`DE8mp+-74Y9KSS{&Jx?5ojLt&E8;oVfjBK7k8mcBu@+Uz zHB~dpU&>vwlBn4kJm!nr`Y-lJowr^=&ng%an#i+81|#R9m8k6uyOmyC9mNtrg~(Aq ztvmc~MpjQM6rdnj=zStfoR(Nn7rj(WhI(5&LP^9IA_p-SI71MxtOjz|$a0iHSEftD z|Ht2g=9%Wct+|gmdzIrS&p62QkM=~npW%^%JWB$X)-XxeD7JB-`3@jyHKa4

    3{ zP``5W-Y2U%S6!NqL})x^4?bk3N*L?@siCL+sXq|}QmK%QHxr`tj2U<`L(L%Nb(~!`b^#F6{yZb1)$lN1Hopc_VmkZqA1-mi5DZLF9IZk4NQ&@+9vFx+;1{S7vu43lsc zLKiX=aP&+EF7sF^Y2A^1$w%MD!xW7_qh{H|WcfJzDv&NJ8Q126{O}z>FS}=B6QfBS znD7prCx5_^XQ$m+Swu$;HVy40iICsa!!xVv12W5LZ<1#V=2bSF-dBr!%>t9tMG)oo z+seSFmR{OTthnp9va%~76t@NGUFhRCh(4S;_H%{;2hOj6*vPo}9`dAG(sR_YZR75R zowB%ROh&q){2F$ny#3(#nPFVMqtN4T;0yf?qvx{C*M2|}bT!@ZyKzWA#Lp5-hqVGr zoNg%Sx{unsM_yJclx(V3-hZnM)&67GBhbGQ7*1r_ixv7 zvfo&h20vLooK!JcN$9MOOTF5YNrg5w|IDL^~xYO24JPDBCC; z(L16lvED6xi6AXHzt@NU=RVyqV=1y}Z`OG=Xv*_*oIM+gn@&`jKvN~UWd5GEfUo@r z*e8$Yhg5suK`S!- zyB~v71gPhhSO7k}zAHr*B;iyT0u2m#$F=dUB4nWx-HCNKA?M4;c&u7x`}tovlyv=! zm5yI@L`znAh)o*d2n>>Jfc%I^pn~eBC&D>8`G|_%v-zmVBSNz*0n7vLcV+{K)cXW- z&FAK>2|l!U2+;9$?+jVaSHNZ!oh3BD7u(?>5w6Sgg$XdXOut2a9;4DoD(a>(qrs}a z4sIr57UOSr?8NrTm)lj|1{sY<`^qm1R5mAo?|2GDH_BL^y2_8a1*iRQYTG^@@35QsVxTpW->Ab#DqF>}<5wdlsXp%%ZsVUIF5qKe$dRddu?7oUwHvb z=fX35l2ogX#^rsx6=4NKwczzZUK8MJEC6KJ473%{8$S;^yzahe;Pd@x@NQtXP4Mqy z*7XG1*#Lmgk--FPcTnY*CUvmuD=%hjUk-hiF^B+ti> zUd|Pe;M`&x2Xuh-!F_f43Xe-ud5$li$s3UOc1*o<<_`9D5gUlPXph%0I-`M!VXw`0 zFhBUN^>fw%#ow4FgSg)e{?1Tfb}SUhChE#OlXc^K+_`ifceVEr{^ehWS@O2a(_a#NF!_SnMeGzaTE)$!$ z1X&BkQNVNN`UOYM`{}q^%_7U>3J{kXi%%McYcC$B_v#f|PN8<%I+Wf)@`00mN_wTq z=|yieC2ff|X`%BHRRU(Y?p2i5dI_VR_+tlRSdJr(uxbSD6MB5*n4T)g=`*9P{f-ys zdzQfpI8Fm^P%4~yqtI> zK^pQ00n{n0q&ChIioH!}15#ClEFu{&kF4Ockj<04C-GUn<$uL#v3wfx1}dTo6T~Zf z4&*)?W~~#uIsS}754&aZz?a)nIpPDwx$a+kjDv7wi z+7*V$Tsm^wsctL!5|4%RIh%mEoS$U8lbRhw0dc{2bTXijhi_QR=I9o*o*lv+(1oY{ zb8P^`<=7DY9R0HFP-H*G4c|Lh(CTYE&t1$7p|!mygQ38q2ItT{A9FBRv`)om|A;h2 z3W$p=ciC%x?<*D%*SV7#_@lDyI)X5Pf@FKv|L7H;nKSSOol!c3r5qj3ybR*UqzP!B9 zKYM>#;LgRB5(4%T)ryQXYQ7)zYP_mE<@GBniM+K$2gVmCz02D>VEz-uBhgDE&pj(n z9%w6KS(%R#1r>=AO3>}`g@z~%W{`I9^W~5TaqKB-7NzT1*e@NRF4?^{naxAaqM<5M z`%B6(8&=7j)plHu{NT2heR?22fxAlZj9gE~QqpuJg;N!W5G~3cL5kjPwdw6LW%Jhj z%xk~3G4Kf1#tW!Ru3Mx20pFu6Ir}kygMQh|4Adq4Fwkvyct|gp8*kkkgA_5pa6A6Q z55jpfVm1!t*Ik0tcwpFuKn-Uie*evu3-Z9zXJ5+3A8UcvP#pZ*EjT4a#4u-$l;#1K zM?9+uf|Us^%6qYvQG9Vr7>>m^E~fdw;`&bN`fc>}@$Rt8~Hdg2ujm^E+buzvNJuWIH)WT;a_NiT_5a>c@} zg$Ce|VL_;u`sPX}?*rBEF|!Q!BG$q_D+5x~EY1E4S56^;?6BaGtGl8j#n?Kp#-Jtb z#gC(~KK0z0HrnTCZg1_r0>z>&>NTMk_nvH|qP6tcN{I6KqFnKiX$m^$ZKWhCmkG|E z{>)D7R{LyP9u~fm!;9a*od0=I+z=mBA0+J4g9py{p5ol7^x55DiJFU|XUUl7W-z)v z?skyhywn@kkB%ABFjo}%@aI@C?~2~^QVBb12YEq)xPg6RUw$nv!~yFw7rhAvro`ofjleJx33Pb4wif;DwO}e^Xx+bBwCSzNyRgLu=OgDoboKHA zX_IeA^bz}2d`17L7@3!aBgJNpYWd0e{#Ery9(DX}Hi>EfnMk?rAFkUpeG?BTSU)cf@7_as(dJ>RAa&8pK|%S<>7 zP=3qHsGEq2jGDZfs;)e|XZ|5Fsbc3w75$Y>R0{e7?U@As=g%+_8O_G-6zwcb&FW!k zceOoIk*ms<9KO-rZq^I~7_sVmx@x+kTt}G^2URz;h=I)@8#|Xu5(L=fU41S+-zLu+ zMAxRtM?jk?48!pfHU2%(R{L|uB}P>@iqKZXAfL~wKiWoHavGKj&(@RlO`!88+-9&UHA8YinD2B zvI|M3s-kls2l5DfeCVVSZMfGX1>C~ohbS59E=uy}JrzDlSN6WLIQ8V%FI=g|s(IF2 zgAzE2McjF=`Q(+gt1;Y+?=rjhJ`U{UnV@ z^;I9=CR>^~if0$uW)nyU-p^fcEAcES=4apk_@1LtF3KNX`jAZzpwioR3XzSNmzt^^ zMpgf(I4RqGS{`j+x0ZSy#)(A})qbFSU){~!s%)Z$p(E>11syCsliV5!uDHgq$3Z$5 ztvr`rZauF}FAX9=^e%kLAxHp^kTq;~i(>6Ht;|i)_t~BZIWS+MjX82aH1)SH3vN

    2LMoYt2Zw$ub-afgLXqX1K0QwbG}L$94NqT@Ri#Nz+7|9x16{6rA?M4+)7hG2{R zV2GfGaV13~XwyiU3<%Dm!jRzuvfCf&zx`YPYu+1|-XI$XR|`By*C?%UO<16zFls9- z&s4p=FX)&R$c-*o8Q)2zhZ?e-GJULV0{2VB2!jH`hI8EE3SUbh;?Wiazq&xc_e4Z0 z6!OzQ3(=A!YQ6Vuz8zAnzVoUCn*XA^YfDMydP{Ucj|!SAw0HLV?~ao|xq>&p({?NM zi17?8r!(XKG){nga99ZQf&JuI1PfZR8y{g~V4Ac%gtO;|`S3&o2^ZqI)s2CZz@^3w8IP1u6 z;t8uUU4E+*W&-W~^uHY^t@Va8H-UWY1@%2bf&8-XU1y(qK_fE6tD`Cg z7h?!}vazTfJHeF(GlT-?>?~5_YuRV+-H!kE9Oio^Eb|qpY5MOz zZ$d8W6^kca>Xn#Vl-0->cf_KK`C2se2iawfNm}!;%&8{WWv1DoGf?@95rHJH1$L_lFS~CQSS?h-Z@&3P+mpMh1Ap$b-75^3|@&v{} zfNOO=5NAar=&`D-C^Hb}v&Ll zfxL7n77@X2J(~o+A3d>NeBLF10oQ^9Dj* zB&|R9F6)BoIHd%q7w-X5b*HxBWq1Fl^AY8=HOHKHSfR^ly>w5^I6aFQcX~-kcI-d( zpL;_AX6;gu5a`b!mQiFS_;QBa!Cn(5{W0%LrGamYZ=(iV)~9i*T}0~ie%lW%>+v^* zF_E2U-@IuV$KnU2Z~wRY?M_Do)Z??drcXof_4y{HaX;1xgq)a^4b&2DNNml^xz^D!~b=+yjw z_x@Ae5Z&W^DzcHt=Opq+JTd=!{*2>MwL|D&l?z<=ohjq>DI~VTGvCr%=L7L0xOr|q zo&OF3Fi)Op`VF;icXAru!cvYlQ9zhSB_e~wbGHxevoglDqe6#Q)@l4yyT|ZEdlp^e zMzTXZo43|t(t3SW**`)-RNQl~H;RH>z%oPPRRsgFS|37MkL z?52M0u{^J)f<8nazoYt3_uC!^erJi0Cy%dvjD?U|Fzu?vVt_{BJFL^0jgRpa3kuRU zOw%kXE^go`bIPV@9DYl)0D+{!fP(P|klKk*nHqt)Rmd`BDw%>kA&0s|F z5)v(}bACqVFxZMWs`A%zfOe)p)Sp)uEcmYICU1FCVg>te;{}Q!zp!Op;Zo)ES>^df zOO&Wl?|dcN9nMkIGq!LS76Q=TDTsRexsQ^oK4HYv7RxJ!%a1AXau3aPHKeq zfx7x5N5D9l57TU*n*IuXB5moreX+H?qH{lXec!*ib(hF@A1m{@=ls&Oep#&fIu~~9 z{+<*kg-(*v@`HdTW>FSdvzz!;h_g`2aP8(qtms-_#B(sQy;V+XT&W$@l&WTs!A(** z?&h;6ar+dJAOu&feWC7LUT{%^%SzpG%);=uphy<2?k#U`{y(2DkHXGs%yB?(KY2*M zz{Ba%J=GEpH2v|A5~A*d{yWA(hGU_^Q9MFi5AG`{=2S!B@+9$@=d6zZi2KCW>_Lmj z1>{AoUWv`&GXsfo*iIX5ooKQl5*27grC~PMUBGqR!dcG3PHt$fNXm~sgSr!$jFnE_ z^|qPY1n#@!UjjB1+WA=St%^O)c)WIrITW++Wf*~brK!9dI7&Z-T!_Booe~-sheL9Y zsXte)Yk#3C;nD8bOSav)yM5pik>{3oyLB|EdMk2AhYHU6^DT`y6!Vv3w?tXsRHK}B z1eRk5_uu1t{nzlG-q?1w2Ih|?r;^N}g6BV0)+dGa|7ko^-UO1n=*Xb_-s?W@dkD;J6uCGIKMY%5G zw*XmDB;Hj6p7*9UobocY&g=EN_$Ym3u)~zSj7T_X* zP%UDRMyJrCBv7N{8Acth&}Vlh$_(HP5twtl+z!Vn1DOA8MNBIKm%XXP1TSukh)!^8 zdHMyO0FTob^oiNIFynWuCA56AN~BJ|5KMCVVsciFsQizx@YMQ^o)A?U^FkF$%_jTP zdlXQLuw;6jG9576Y}cDFqY^_OmL&z_r0q4HFYB!h@i(k54M}CoKpMuk0ttI z(2Mn3mA~&RP`|8#QMT=JQJ*ToJhtQTD)JM!Fp{HuJu3w6Z<37!YwI5Z4Sm!uYn11_gRHCpKhXMa5r(Z3rQIsIWHs?YkJVu*U z#14LcT0(0rwo&*dX;b@tN8JL8VA|A-Og$;VPLXsTj`42TQ~g26N)6&;F3e@X(fM0W z)N021hhlS>PxyD%SGv!k;kOQB;&y|?kCI$b`D|FExZJ3*(@WkYv*Z<4;8ZLVeafI^ z!knP;D@rZf9hiQ78l#2jyg7Z-DGH%zbLZn>-w8kk#OXhF_^;__%uf!blzHyBnxbK0 zWYCv+O#GVhU6((jHATsY+|5A8>G?Qjot+tGg&NRUMJ)9WX%RQ>I=aXzG&5lL z`i%F;i2@NLc^NrxH;^H*;(Gt5k;$DxA+_#L%|DF}Ww;FmRhl+=31)#+U;-{o@Wg6JeRX)ZI*_j* zt-e4cU}*``XTK`-Wi3g7b|>JKM||WpcZCApw2i-dVk7|nH&GmA!!N=gRFhqig6v&O~7(t_z0fZ{#umc~`K=7WA{uGagn6(F6NG z`2B`x`zETTy(Z=4faDv0ayD-r_W8Xu9?Q~n?C#CA zq>el1DMd!9?@WKjDeDshpPO+QR$nQE}5mqTFa(H0-o=Od#PpksDx8OCL}OVV&97R1Wb; zd0+JV$9ql5>N1kudCih+h?cS>%Fe+8(unjy8s-}adp?if4-L8f<|lL159nLvi{ASa zVT0ZON_%9gn(ALPLK1m<_GA!eiaV=613ZpR(ns|NJnw$zMwliTC*&NqtAc{ z`9pWIR&L6Y8-$soanK>P3UobQ57?zu{*NDeVNk7bY#TYm{BdS-;l3AGOnVhe?E%u- z+P}WMiGl7c-!Z{6wYduTwGO7Okn!q{X^qs-y*qcMD0KLX-Dw~SCz$fN>x01W{FmA6e(^RO+W4i0(^O#`G!83aMS65b$ktiDQF_}uCGbDmY!z#^zPM{A%WtU*Baw zE6dTBZODGr>-^!a!aiI93b3qTbtANI9RwP(>&;Sy1M*=U;R|ZJ9ae7dKd3fCah+|z zdtgn#OJ^=f3nt*sAJBvLYF0Kw+9H^LA`+}X+fO5P=xr7}jPWx0ySE`^gO#3aaObG+ zsAMOk@r7~1P=qmni*IB;h#1%@ZxuHtEM!Ay-|)e;(bDLoyExkUP8OXE38-gE4oKUTA!dEb}znOy#+jYtDPCej8U5=t2eN#aUq)O zjv{8LUS_pI+6QQe#l{C}dQ{loQn;C98d_UBCzhJNyo43(mPM0P(@9H%SLZ>%e47}D zazWNQzdWljlQ~)wf+BK#B|WcmF!d4=MSCt(W%8RA zIj=Lc915Vn(x2VgtSoFZiJjN*cNVA$#s%cOvPW7+S?$Z9sYm8b%1wFENkUAwKKsA_ z8j|ts(bvGZR;~&4k{C^Ktr%y(R!q^)M9`z9a50W4{=ATog=9L)o*zH;3Y`CsY)t8B zY{n4gSJmt?r*d%g=%LdcJLOlGE2T@cOOdZ*w}qFpY>`)Dipw z8X*p2j1BXgU!&&E64VG2V_WWtH{9(dj!uQXbQ`Hpzgx;V%7&GpTwg*uA|B}F?w<({D8dLOgXBJ*Le14f|Q|AZjE5)QxnZV@)!7UbbXSB zjOa$vll2wr-S53oqI~B2Ah6zR~#Q?b*M_muFhhSpm zm(liR@-X~;hjq&UOUs&WvQ6FSkIon--aU>s!(-Rp0-`f|<_PJ-Ify*VSc+Y_pESY% zCIzLd!LSrWBOVpv!0gt6moRwhnmMh00XwuFp0!Z^cV0AB^zE~-R%8nv=Y};_j2CHd z=4klqjIM#SQoThnih)zJF8a5;yT*v*Kp2$$yd*KNv@nefRLH`Xqi!pX^Ye1+s&lY> z$NQc1Xe7@J^H8RB!w`x$w!ME{uy}i4uO@$Sq%SPt{ZH>v=hDwS)8rJLGnGj zg=0v^-8_N<5rLUn(AZD~ZQy>>F2$^aeU#$sCurkH43op60o@d?dnnw^eT_b?Fkn0? z8zq&<2xF!d214*WUiUq8Broy&vq&s4sB8W7e2OpS zdjE~1o8VJWP32amT|DI6S(FTu-sPM~TCc(m*#$YjH7QIT-77Vl8 zX8i;763-~Rq*woNjhJhKFNXpxJIy~egw=;5`c+-7Xw}#tHyELPZUw?y$fiLLpQ5Pz z+eYZ~)|)G8#RT~l5D@1SsF39;&^{SO!$i9B-&$45n=%LiKOi(w7Hnj>Ppg{h|G?MlTJXHr|=>xdBAG^LB2-oT2-i1P4iOV@cZ1Yns8BO#CM433H^q9 zo1Km^fs(oNJBO}U1XmFld9*wD@TD7VRvZ8Z4b=fQd0Bg=t)6Ei7rN3R=8<` z!qB>)Dq2L)r00dtKz*4gkhdV0c87$?CqJpzi>1d#G*78Em9>VjGyaxtiEB%^N_Uzt zM!)9Y`6y`a8B_Ko^Gab0RXEM%%qwB>k)OAkIOs%fq;{ozs&DW>wi5iVVyz(Lp0qft@TO&1+}@+;%-PZ%<5n7!PUY%3b-tani#hG6HD4zDtlI<~7je2wC@ z*j70X8y6Z?^%^Uej4mI%0lL-Ns1FBW;x!54o)4I#n%qf|yZMCV~gP&zTxDA{Wd@q7}mwsUK_Cv{1|EUrbXdVi$?Mei;ncnt8f!hjsfeFN+-@98$LO%k< zQxqXi#Y8mvy_Y%sxN3PU(n7=Vd&VUYkDa4DbZ8N|hSU9PKRlsUpwSwePY!&*=O6}J z52k6XzWK)o&|2L^V)D!rP4|+$I^+l?frC$?b+8jHiM}imn@K%<;_0UN6M&A9g<@5I z2_gDRWmP2;nr2g-dimbd=r<;YU0mzmI*PZb6r}js+*>Tb@7f1-Z`%*YC8KRP%!Dip z_-7i<2N7)VLZWY6r;;pIR%V@G$EK(`7H%a_1kgT198&=8-qo;((9I&X3{xLf9eZ#c zzG2DhT}?7nmknkWb#>sw0qyE^XH1?!`UlElAf7ygvMFf|dAtb%6EWt}rc?-!-$V&GpDtpP=Xq8&)PQ#U zoGOe=tf0ieb;T}at?SjH83XOcuF%ldcJ6Ej6T*0Hp6kYdc47q>wERAGQ^5Xf-d3Pu z0V$=|Mg&@Rkq;wG8=edpq+$V zPg-@DmGB~q%=MJ`G&h|dtH6OcbJ1yKs-_R^sd2$Q+n+42xtYkqt5Ke2F(Rx?tA?OQ zL9MzRL@n7%PWlzzbYymU@NHHZp;|fb6sss}b1)dO$%yk~2-$}ydx8C&`0;=**bIf! z4xm=5#5;apegx?geRX6;gyawZMmkX=-O}^yq#BB)0D*rF(;x-ta^T@o=cs}kyolnf z3F!}2;KzciXvU&fr}O$;StPF;hZ`_=-K0m9DMU@3B1y-sO^-@yMVg!|JgAf){NW@^?kvQYh|dX=DGlA3rG^EAcIrQ~?A^Ncl&n7JSJ7*bS{ zoumD_zqH}YBu3iZjklJ8>mDQPV|pi(meW$#Ty8)3hFF+gQesCK<|61n_;}nT>RWzv z8VY;gQvi&E6?QWe`$thCqDl)$x)`c|_B5?>$|*u;`vR`1IgO!xmYa--7!U4;d7!@) z>)w<^DWO;$A;da}5B$I1pHaTYVNSd)JOwoqABu7#G)Rpx$guOmW~&7JCMLB|;s0~> z9w8}t@oD->fshJ3A$yhw)#K9DO@@thI>U(kOHT)v_VlZSd$7`vId1lq?`G}x)%FXS zWQ@l@+rAdQy)L!O9iR7vpS08*l!1GHk2ANQr{2f6+!Qh!VdnKC{=mHIJ-zI)5IeYq z58|ZwX9tymXLceg&X8{F*+wFx@9PEuE%-{#cfhfk@gIU%$Kj)_*b&cPEINDDVdtB*@t(E+g zeEUP$bvx>5f7Rn*Kmyk<8_&pF8o4H<}pEfcAfriTqg;QT_4$WI1dqNtdDSQ-<08cS+n;29bmcqo=? z1|yfu;V<1zT1ANh=&7@GO}i)8w$I|!jSGq9?_W@H(zXdZ@=%mHyuYZ#D(S!USNx6= z?ST+DBpD_O=kL>pT3i{CRt)vzvPSS7y>)>XAsDwbE~7|4L_P~;cuZ64wX@v`=v!Zc zxTA}KBX&;L<}VA|G^YH)c58#%3l*HCdnkhHOA9{@#qE7ho@!I8z(-soaTy5ck~wAE zUvlXGd{RHU3M`6C*jMtok0EqMLIw|KBSG@ciPw0A^76(;nx|>o1&?eW-jM33S8sun z3X~&Bl;cv^CCJj+e)BuK1a!f=O66g;h-bA%w-wge%SH_GrkLXs6dB)d5q^6M#3j*0 z;9!;Iy5L;e>Af;=J27Qbg9jn`kI1F-g@D7H+O5UI&(wqy)Q{$CvF*)8HHKstPVJ&14d~=0Zi_>=+ctmduY0lh4vh z_kjHzETCTxiNUe_K`fpMvZ}dxD(o0a0O(wK`U8%GlVvzw4SraZ4C=T*qjcs;oqceB z-kF-{pLihmM$i};x9z>4ql4pLSje_6H8+O(XKNi$=7hr_Ha*O(>?#NlQ5h{j=T-kE zA3#n3Ei7H(So+C{sDCcu#8mnY%BGHhfRS6*$!TQ@XTxR$y|KhpN(pJuHn;Cj{14>q z29e1z!}@%~Y1XH*?urvP4$nIodU-+q{Lho^Q!z$J8!jQk--N&8tpmDeONv(myUsuo ztZTt*Td(s{vlQJwE9_92K8+)A9}qV9q)fzHqug0W8m4+9_n4R*-8hns%3$h)*O#{} z+QDu6y`Yq6b_pSXu6kmUFGX%=l28!)BlRTG?DvQFCl9q0-^J3-_*~Lz)yL&Zhp*+y za~y{`jBDmTW&ucFvsFz&Tg*?G>Xy3Odv7A+ZJqk?_W<3eEK+G3+%7?z96E8~0%q8omnZ+{e_rRVY6YSTzR?ygUsPJFMm{yy5M&PqLvfV> zVO=N+=#()a$M!AUu$)C7YCU@XOh{tLcih58nG7sxiwx5kE83B_tjNAvgL|DBT&Y;(ZMg>G=jn_XAo8Gs`0h(Cr7a zI*6{_Rn${Gelz2XS=Ag_4tl`>X7<@Y_#n75aDXz`s`Y}nO?XR5CiUQ4x^-s9K}A1rFZuC`R2p)+fe(Dj{A z`plfMhtH_!|{T=U@JW}{Mb?IQz89}y=}X#VJ{QMs8*y5Vc( z`Yrfjp`Yl!k9N?fi%6GD@@0!MMmHoSBdM>^c|P}_bUaydn34=_1Ftrm!lqvw3VEj<``Kjo)UMs(#U4bf;g{| zGDY%H8`Xd=*AXN8x3y?X$S5I9K7I{%m#9PbH==tQ_l^fs%5E0NO^Q^N5>QMnu;lAa z?hdUC=kpbvahi+UW+Fu;SEDt*<}R{Nia+7+0i9PiIrDWuwHe~};~dz+NJ1Tddz>`G zIu3>Y7yS!*)tT@#R!H68%Ju067Rq$juk2e1m53NYg&*^=Til;sKP(Fh*rPMlv|<5W zJq_c4-b2X9LWNR(3s>U1I+P)Wxcw%L{L|axH-R<1*YwVBK>9 z$xKEIzQ^?|k@fstL)U9X{xXIy@+77=!rWt}lwqai3>CR-@a~rJ@bBod2UkL*cBH(T zZZK3S!S{o<1ZtB7Zt2e{OQ&iht=tW&)3b~ojN*|kM?^hk*<7E`%jRr-2@9eorS}@X zM#=VtqJGiTdJlddYrO;A*8%DRfB!BfH}v?;@ebMg-_~WwvD~~SN1qL^URt_VuDa&2 z;yuN9G$PP-`~9&C8b?$m-5<5?>?G3s|9V|Uqr8;10E2{6zidt2`KtES|8!kO*c^f( zQCvn>D>k{pS+39izpcwy;#X0+%xnbtPwO(u4v1HL2U$RXbs6*fxnf131Iqu?bs2)1 zN_6Pwk2}D+jQ!l{mFAY6abR5rzg0764Odd{-~Igmugmy{NZ{5jq#&1mh$w?w{MTEfyuISz^{ty3;WX3a zs!QsTa>fhv5iF6u?Wqw?hUB6FboERPxW0qKD1o6q&}A%AX^LAYfDLH3&1v;@Ji5;e%yOmGORP7k$S~+s zbE$v_e{L#C?}OqjW#7J43blk2s9(Y0;}$l8des2+D>ix3_-v_Rrs-RZu0hidQ_?#< zJvfRp-5*V~Ma@6=PXV2~^p1CW^FuB3ZSAPVkO#iGi|B%|@b>_ophqd>5pK`i@1pPL z{iM$P74HV=PCw-Jvr07j%N8cJ1cZrnt9?|`&5-NZ-K#=ryOjU=orObr6&9~<{X0Ub zy}g}=)l66ZL~Cgzc&9fTaZJC9KMfX#E9K2Zn|{;zKCQJyuJsQ4DXY(kP65CbVe#_ zJ%ZE}->8%ZGy9sf&02kKKuKQUCid)~qT-F_nUCEW9~2J>-A=j3v`+c=S8bF;Ipl4~^zB#5{} zx~XL;7%S_;Hw{;~uos#6c>#QP0g_W41&=FgWxRSzcAyT_urlMmc+6rI;~3Cg>GL<4vY%g= zLz?w2I?VCYNLHnKnT)!5=wnvGv^r5-;JnRU!dm47U3&*z z`IE8AO2a@Mr@z>$g!M|W7`SiWO)rX#j{VJF2<@kSl0Fg)f(TaNa7ac2+d_2}{LbZ6Jp9bg-3&yV9ZKC|V06y+B^GD{S4G96bcO-qF3ktU?7`~EQD+-i!58z{zHqBppO7K^Jt|OpES!S7> z_HmQpBwT>I4&dX-n|>mBisr5lK?)RS~mQp#u1zc=*+po zroN1*1RB(GP(QPlsQ`Rj9aI|~Dp>Fd;5HF#nH^+9`{tcpp&Nz$+!vZA9Gk>+xP4wUxAKa! z^}w?GS7N9B6lJVc^o~tpQmABlO`fW9ztpPpFm0PRQ7NBprJ*r_>jX51$M``_r)Z() zDIHUN#+xzvly0zEq4;9H{3PKpYk-IKA*3G!|WxxKg1HKk&mFj^sSX>sU<k<#=isip_H#Ad%(K61)<#9xLV277~tVj<=}JI4YO-N zw}c9-nGj`)So=+lrEJ)t1mIx=+u}05Y|I6KbFFMPY>0lWy36uN49pGA{{(n=gSKde z;8?vK(0M~Sh?|x|jIM%yMlREfo&tC{vY;FzdXz;0;M{jO;WQ!1xn3@+lg68l<_&;{ zy~ZvzXF?Qi0bK?Nvr=8WqDI6=;^pb~A5egYLHn&~Jq=?60nRmO_!!HAX#3>d3?-K2 zE5;4*FyiE*Xe3(wJ)qkS6Yt}0$bUnZTmw;=j|c;J*o7-ln6)b-6yV{_=8MRY4|I^C zyV1w5;A>t053>pUxMBY~7XXZ_yd|1_kSkjlfQQ>ia?0AqglJw(-o!cbJ_iCk96imf zZ&Snzx2m}6E@8fek7|2iHT;=K2)r_PGTXflb(vFfzb$|ZEBv1~g~NTaNnQ$EHztd^ zjao+G-lV5bmOzhX-tIP3K9w7+aFu@%jtY>*0AF9&lE%60o11fg}6K1z1%UwgU>G;)pimkMNS`SdKqo>o2uF2FxBBIO3&lpQ3_#E}o@#9)E(Zpvc zS9e{jfGr|X`%iH(o?2oO3wZd)%4#w-{CS~<9l}YFG^0mlBYfPV-t%vx`G~mSoBcdr z7{x=kF1!BXfK*a)*Hy4@N)QQ1EmK-QR0Q0!Ly&(XzFW<;X^-nvzw_C`uTE?UK3E$Q zcKq#6|Gggp-w->jQD|1czwJlxl`j@*le1$4@T;A}w`Vg4H|zeM&o9wl*sSZt*f4&{ zjmVYLQv>GXRw|k=ga@<4^b9Js%UI8Wsm~fX^k{KUW`1ddk}Q2{n>2-MH6;3_TWy|7 zHKD1$1pRr+zGWuD|oS` zUR`hz@y>7+G2D8EqzlU>4v2((4Wt*CDqlG-6UM zGfdHc3b_J!`JxT95@_p71SusQ!2exEX+O_9#j;qn$9r;>fD{fY+A-pD8vHS{Pc5P2 zWQYxYerk2kWg5jvxn|vSrD6cg&zp^=5q98hAv>vYc~3_^V*>O2>1tQmx5gz6Ku3cm z0PQ1VvRxJ}*Sg`rK>_&HX)|+ZBNrj z7JNeA-HIYTPaw}`6bc)#o=<3ib~WDMpOJc1DFMHFXve5k z9Oc<}pM`D)f!!LBG?mCg^|=$B6aUZo0BN^e%p~9g*Q?TPr)yo01Lwah*n!v_h|>jp zXQx3s*!3r~pPN{3o*!XkCqO$GQJ4i}GN}ll-N-Kbhc4b19H5izA6aD&DWig{L;8$0aCUHVe6u|!{znX{%iSE<-@!7xe zg57w1nGG4;G~h!AMrZ%>PNq^bk&Yf=zmyyW{OW|?Kd!chm;8z=1%igwXifF1^{p@;?=wbU4ZsV`cyI0Qc^>jS*NTekF0P|NK;l8NS- zLD?u!jL!&zoP%l$@PZEEgk9b61PH(jvf4k7T{;%OUSicw8Oe^}0KAaO!JjDw5=a1y zw~S@fA-F*?KY$mG4;{l^!LmXC4oLTfzX%D7gdn_Q-h5J;?*n+@PSrO2S_Cp0(2bKM zBHS5FUboTsFM68OwgJ2lqEV?m@>8N)e1P2=y;EcIJ+fA9GOQT6)CXIlOEYNL7t_kF zD%npEn6KwbcFr4SCpGwpr+j93 zVVT%}>$Y$LlJp)T=)_ifzX@F&KDYldzBeKX4}|+_E;+fE8UDF?2;ha5PzBK?!K~OJ`?$yM-(9jcWtjd6_|`vR4+1qI{Br@{diwa!?9KGpGT=v3zkGI* zvCs@J&LW=fgf+$od~2>J+36D=|1Ch*Ne|katlXD;>z_}1hJMC$v0Zk7N) zn#Oq=>|?^#&2%Z2t8VZ}0r0IUD;g|9jel+cx*Wyx3&}DvNu1F<7`(5z(SUFLs$Q;T zN9Ozn_|a`YBRM_W1;clu4ZQE7CoKTqno?lx2cyc0CZHpEyU%A7Jb_bouG~$Yj#L1A zYXpBP4BAtQV!)5q&5)Yf+YF&Mhtxtp?u)Mmd~2m36iNGf))YX;I32>JQ7g!KG5l>k z;{Mzk@U4mX)|}`>(I@~v`tV8UmnJ&aHByzU*!^ii72sQc!K}|mB)HiCbTqGb&w(&* ziZ#~e19Bzg;DB!}s-Z~x0NQ~K_|Y|Y6M<3bueV3}wZ1Ygq5XhwE&U5Tf?8Wb0nmAY zqqce(w~uJ`9>)gwM6b5cCV=6`37NQ~o2EezDeCdgOasdejcv~J;A1gcv zK~>S~aY@(Oc>v(@rHZqouY#tIfQ}lGMfL_w6`D*O6_!WPX$s(Szr^!HA#t%(fVT_s z?49XJ5vMO!@w-fMa}NP7zu@rk?61UZ0CZj3kO-&#@pCPIlXMw=9sz1yR=UuUF?rYq0@E+>)Omx%~ckp*z~#MkNJTg&rrZE;o12=1JJEc#7EP*7Z)w?w1Gs!Fj<|RrSMvEOTO$ z(cLI^U->Xh09-y8jI{!GN8$$XwlaeWnzSQl)E`({?;#Q!CxFYhM#uLT<}70X-K=pi zFE|EAikgYU?i750=V4rhf20P zwsm#v+~_tp4#b`@^{76@*5_1!%T+l(*~nSC3IO-vC4p&{vr1L;uIStyK5hyV;PQ@< zPnV}RuV#R5OJr&0k4c2_OzFIEOKjB!z~wH=B1q{Ac4Po=Kl0>{RPmC~>Ig4olEx1iHC!{<-azX(vhsZ+DwkAZC1?FM2oBB39oa~VRmzxg@aZq$>ZkMOGUnf^C z$^l%CqIdO#b6KreOh~{3ci9tvu<`0Lp2r^y%;%#`Os=*B?57!9Q>!kcdle)KxU`!u zE=Gr{ZN&$bkC(w^e)5x!^HexL>~7h}@6em6v*3fI zzgEs+#{ZoE`+wFEu9V80#R$`{wnH!F9gTc&@7=c_jDHL3q#kCgM>TiCYWXF_%iT!6 zNjVj5u)lS9C2RUAoEl|<(m2UU$~Tu69J%lhU+(RT^xQ``>rQhE1ALx{ogbsFiqAGo zznakHCw5^2ivD|C5_$N)@j1{pF&-z?y>>f`U(Sr*EPQZ5yL{2f*=59k3;BEv~H<2o^?it|skgkTY8gI+K0C%s)t8dhBcS>z^28y9=8h<%z zq=?8ZM!W&I8$TqcoUq5XLdq7=lvk`HVU*z0)KM?)3gB*Hs#&GqeSG4LyPIc0Rt zQK|0ucNW=xS+SnLc(2!-S9ko!9}IxgMBK9Tp@@BZ08YbLb#JL=nakNuTH3VQU_-Xa z$gcJxQ(R~sw#MXgwI>7S*LdYbj{U7=__-ZLACl$bJi{Mbx1SO9voG%xEPu3#xYPtU ztnhG-ujA}&1~51h3><#mI1~69aRQu{yv15fG33JlaM~|5xZojCjS<|DuVbt^T2X-R z*sF#350_r|I^Y+<7!JXWGRYj!9mDH~Cc=;U90Hsc5>AH}OU8&?2>Yg_t2+Y&@SN$U zbw4PdTohm@_Ye&GtIKll!DR&xN!vyP&>e@wTq>iirU;#M_}?Kb$DDb!|Q3m+t1ahe-Kp;AGTjJ5g zk}z6c6+$r!is%QH7(FPLtd_u+530{}Qg4vl;g29Tw4)hPKzCe_{THe#x%eK?9luIm zw0{rGp-N{NTC;09RRDCy0;$hzf=|Y|K%5%Qy+J$f`s#9JB#wG;G!s)Mpc!BH6KVA) zCD1|hu!DxtCoq0@+{mQ#w93|?Mi2tr(<*5jm#EOY2JqVfCs~rBu$pnVnbu;i{JjLg zKg98>qU@*1DS*EuqQEdX3JSG;cF!qnH;%<26ra{%o8M6Y&$OX^7AuVVYXCe$k!xNc zC^+2+@QgRi)Qjk7g)G1`TW)?7D~2F}4|c3cM5ztE0MCeGI89y|tS$g{Sm)6l zJUWSXxbPwx=rujY0MD#kRLo4+nl}QR0z7B@OyHP9(0Wk;FJp|Yi15jT1xBQlO9nH25f+5 z+Q_ChzA8!10CqvD)bp?)$zyeRL{^+(x?up%3`hLFCu7qY2RJ1=zgmB%G;54Hyg;65 z`fCfoGiWul5ie+3^?==967iaMIq-YmBZ~Dova)1=X9|-@f}f_-na%C%&K-6x>j0kV zloPVgN4X3GIK^m)x}4<%uK$_f#BZ9vzg!9V5ZeUsOxkpPyKw)HSir7? z!XSn5hkS}nJ(~h`K2IXRGu3`Y1dxL7xd5klaxjmcJA&M}=)8S#tIo3nc*YVgD6f-_ zArP?JEw?G5l}_OM_}ob`t%+70MB^N z&om2E6^a6OyjsT=xGls+BhE=6tC5Jp0M8sSjmS7X2EYKEQel_~k!4GtXPW*{V-%T@ z4e-pXdlY<)=OqMSCoZEfmIGPN4j+V^T`qAl2Jj5wPL7iVdSxQODOD%QX5KUNw^mJ4 z-D;xP5&+N4^@M?2eCt5~>`fL zKD4R4dGnYw(*(-r@gnCVHTOCQ++GW@^3ANL{EW#*xYN;*4Rsz@7|uuz?preO6V&O? z{n`zI`mV|~*Z|Kkv9&6BpA{@*Y{$oiOecT|k-@Njz0@;x)JVS$^&wH~Ku?NKA*hkqvN1;QrA&LvF zbn!bRz%yAvkPNs9_Gy5f`wpeY&676n@83uPr8qa00MC53G5eG$T}%L+a;y=iCdJ5) zfTrxepOT9Y3-FAoqv8<7X`2FImlqMhSjPiFK=D@&uMhE~3WA6g9 z$Adu<=BeJ3re89BB^1!(p4`s;HQ-!o{LTF!w0O@?Twl)eLId4rrg8`|TU?D^@OaBd zqQcD=4%k1nOTyYFJ!V?BP)5gewAv(4RlY^n|4nj6^Ui;_cz|s>?Hps|!!Y=C>;Q$T9nvjNNyM6!vZ=b&{CW#y3 z?pec}xz?E!q9l5~cSrUmulPHJA2V5+zwa^3c~DTBecT3x`7C^7;}2usCdJie#z2Q* zxXs?GSZbXId!4rCS4Kv{;AU&6g4;CLh9A2y^KK&hA4|H*Kv%@b1JX;S0&k zTMiLu>Xzb4>2*~k$7Xt$KL|bLcU#xVnj_9Vb%6wBKB^8WNighI#}+QA6WhM1V$HOq z0~XKlDH!gZyY4(_pm%Srnlk(ib9l**Q`#E8*d;pCmZ#e8GokXnT+g*Uio*WB>QR17 zDzFr1876)Mb%(;G{uG38B8-0B!NNIGguhHi*~o_`*74kv0p8F^Tk~s}qLu?oQduEw1N^Z3N z^wcc1066Wr?ru3WS-(cECzMH2A`Zy_Zp7M>r4R#Yk&rW*Fapa@pBL02DHxWt22!z3 zhtPn>)4_ULCL>qR4dZcNbMpwK!d!=$x!|{$V2CYd2E*@{-_))+zo~9V(&j%lY-hY=334ZA9qYYeW|5D84vF*n9nK%8DzGZ{^I} z@NeV~-X>_VOa4{N{3sotj;1)vV|`C!$~gY>wsEL*Nmp1p$cn0FmHiemP()FCyLFV7Fo|UWmRtK3H(m8 zMcziS?7J@iBkPAnS^_84b~`Nxr8%QZ?K%PW&-ty>c9Z{XR9VHISfD33n8j_B+K>j> zEAg0X_yn}lNPa9}Bg;<@9B@1%3>1xQpgP*RzC|6m`I<7_EEXp=7$D9uxak!k?U5M} znIzo&46lkG+$#EB{TyjjcNZ3QC$F3P8fB%J^J|hJKBT(_dHpP5kxX65N!|jXMd4}# zM$is@cJ^d#5B9s+B!;a9VZkF$s2l<{GhQ?0zHT0gmOJCM`Ks#3DQl)Pz4PYXiQ{e? z>lxElL{Q>zYxUXNIVZ8*4%iM`&|(p?efEr|WH{F=++r~Y(!{5v%B@@slOIRSytgEX zStbPg|FrlvI#E#yPd^ zCp%_uQyHR-^Rik!>5KLUsqJU98KBc3$iqlBN;QifSf_fr`e38|_!!dM+uAsUTZ`uZ z*3AQb_kez#A!3R<3t8<=k#US3M*&X6K;6VBwy;YDBC#n{wUSyvtD-!ryJ7xN4;T5F zJ*r*MP6HLu%<9-JVpE&1avIGnL_i|2?gY(_Qsv$WFZS>8RO6zF!=8VMul!;kKEOJT z>SRXJ9i(ec8;V z0a_DqC)gnI4y$k(M&6+7=2)uM=9KAO1Z2OSJ7yXtpzJ3QXPHlu;-9^Whiy8DzV2?6 z>EZD#5NQVajps;niM3s?45f1YITdMCBG$jdc^qYN3w>*RzjBY$D>ig5QguKIky`SH z%%n%ZWr+*+dCnjY=6(gIOhk_3O|(siwVwXn>S9Y21lGE>_ZLK*AZ>6k)Qj&~hqF@B zdIuG^f*Nd)>bCm}c*iD&N8dRP>==Si>BDO;%v6U|?{>{5cYXf-XJeJ%k>!-BQLu?L zr|PL~VHgXxi7Rcu!#oJ}GybXoY?@&Ec%1yd|IY59kPfybU*$Xuv%b}p1S5BOXtynE z)Ah>tZZoK6K}CGJzdowJ#^^XZq>FLIV@$;}Hd+O}%`m}-Gw(}<^(;OJoYCK$cJgTc zOj({mq2Jpah;>6r!(qoI6V{P7W&LK8OLh^I&+(Hnep ztVTKnZtt~>JCyk+mX#(^C2gF)?NKFz{-pkQ{>o>sgPwQfL;G^8w2o18lz4=)te5Sh za0C4!E4@73kst%|X+5o?(SA;?k>4+c%pHN*dWju7KZB6B^r4c8vY zUm6+?QZS3_M^H}~4&*J+ufzPRM}1@rg7n{gT(%dfdSUS`R~?9$I^Xu%8XWU*@vEpY zg_hbb2k=Y9kxA{!^q?Y)o|7{cx_VT097e8Ksok1dHw z0+B~J;5vXfS&mf2Di)Vcp|$4!>TLX?IxMPW=w5&~#mz{C*P~pbE`nI!% z)w6CP7eQ_5byU{onmz)v`ne*ZM6PA}JQ3FZA^FFr zm^>T*H&E=elIQsL6V&OXq*e)*=;PAUb@rtao>l%A-wMn2|zHwW8-(5n!EWQ~&WiF2#Vol418G$Nay`!N0^wL18KeXu zrCA`B%dhsRS^;oSqzAH!YV`FQ#!+?nM#z#DNWyH>mG7Wg1Xi@pb2zLMRGjabv&zte z0wHauO135fA=H9MxReAZ$pR2&!UX~hUt(a-ziy=m^L*B^d#h?_l;u272x0_dQ5Tn? zh;A*T87(UW4c5137cPa37ils6|Fy|o3+*wn$DTi zgwZsPC|qv3qhd-s=V$)8$QzqvG1GL|)c1QJroKsG5pv`Vk$(Nuv3eHvu&@_CVN5tA zKkjRy8GB<>P*&T(ll$gLV3!+4;V+^Lg}VxNj^`d+JhB+A(-(qu5Uj@*+J(?z=V~p_ zN)6lS*HCC^D85Q#+>h`3<&6GfB(=@VbiY(GTW_m( zwi4$I>6?n&O<~%IahsWi+6~GInU`99Q{bjB#c7TNA+tleUx|HL3g;NU&C@*EUN_Af z2I0ho8{x%`Gx_Bb_an)?Dh=Y~xh$m0>^-(C>eitF%0|L16OM>1AUaxK|1-TKiMbMrr&f56eQE zQ`adoJ&(Nk$N`U>|1QOIMEAc@k~E`?-z{4nMNA6b7J ztmGWDn<1Kn1-P-E+zj%>&D#V5?5Op;WpM~X)rm>UaQKIrWxI|iBk)aXIgHENk?ET2 zei*3t&0t$^s#yk?4i{&pN8@lj>aA;M39OC!g%IQ~gN-h|gCOvuCcQ|^p#Qf}r(1i9i$v3l=^bc1h z*GcK|JC?QagB%j8xwG%`W=t5dp{YtH{M>eQT}#9y+iVUokS6N&9Sn>bAk%59|FqQH z>Y9uHT^Uftc{KAOmnjV$oN`W}lE5zbA$Ah^#coV}eesVNhK=*$o$;bfZOa#P8!zG` zS=QW_SJY^C)SnJX{>w>_`+KdF)LqIFVc=ory4XJi&xCC9XLi6D>Qs~vp{-;qWkCop zrg|&XIjcVNY|zk$mrfjK-(2F^+go4*!jN*7c%m`l`dhhe{ggW!$UWeR)RB{ zt%+rp*0f&A&oIa6c^=_PLl`!HLHpd6wex7rPQBS(Y;s;4fLDQu9u?_8X@-c9=J3r7@jkNF@e%4^`A6Y9*7}p z_Hj%PrBoEB2z;)Xnn1JG3sk?f{+=*uHM(Zfa@Y!8IIlp69+$jg-;OluO^FUAh}}?V zsV3L2j;V=-<@NgQ?Dva7YENfj(Q>aof{J8vCtT<6jpu{kjP4HUJ4hvGwe4@#3J5*`)&IN33fB9dVg|Sg0WYd zCb6Ag=GjS6r^9cpf^>vdF?yYI)O_Uc0{-Tb{x;=%siI*ZpPQyh` z^O18A(w`yPX~iOe_n(t=kg=}~XSdr)t3TbX#z<5YD4@yHs2g|jg;a>QnT8E;V%^4@ zFJLM5gW|?HSf0vX1!c<4Rg#SMlnFGxnER%6v;>2ulxd_~8(;uT}es5rv)^Xau;S4KUl-n;ifm z9NG7rc+r$D9c#RY*IYj|-)!s~hPo{Bt7nPhU+?*4YE@k2@|2C>*?U&H)3UdrinWn}%!#HXu0lt9Rr{ z3_<8hsw^mk`^zIQLgsM!?9IiO=PXJlWY7zy#dJQe82@Os;BMVY(|YXnc6U26jL9?p z;ZvM!_{79H1054O{6*-AeDP+Jcx38=Kih+KpWg&yYXfT~f5y~|niwXp+(g4}Sl{ny->4r`z??rQiraZnL z2V++kRZONBjW6ONTAfK1S?;3p{wQ^1qy12d@B10n1K(Tvn?SeG;#_l-3-?Z6w9MBx zRJbe}3bW%odZA6y0*)R5?BQR#!pk;@7rgk)iH;IOJ{lKvo26*;@iqm1v~WvoxC~aI zUbKot60uOR^i8+b62z*U&|lOYpFwGj*!C5-cysrmbjGQlTXWqAohC|xFh1Vzz`4>^ z%V$gjU2~Fp?wEooQgI|C4RbJ+U)y|bbOXC|Fa%o?MO?>3mBdd5T0*YFL@*DQI2f~Y z?D9QiWDV2qO)ci?CWQ4-k)R5x9c)+xvfFjuAS9F+sv3@-&4MP#=|JSStrnu1+GJa$}oRQeUikv?aED;nj1>+s(W@0 z{tEaL4yeZW7{FFnU{Gw(@p|0`35DJj-TGPXsKKQPr|t-o)1+9`Vv+xTF?18vuTbGx99+RHx@LwK&Vo-eQ2y+QYz)k zYN(t};`qEx(El_~@U-O2;9>*Hph1UXpeAP@**Bi`=d~{I(YsP9SK&<`It`8))#foS zk$!mJAMKT6qI$pAoJWXAjj@pW`)PE$f{lE0i|kW10_I(?Hpg;rZ`CM}Cx?lwJtH^G z4lPZZ8*kd^-as5Hxsqg+aTh%)yFal8k;1+g7x;cicnj#g!T*>R%O<=C|3|~;TwEi8 zBO@Wm#+1g#LJksAXq7h5uIHl`h|HV3pZSWw=CmMoYOW{C9*PNv^~4aS$No?CxJ$;t z-X8fxc7${WRuG~}^Tyf*$1N&dZicbph9!=|3MHQC#jwWK&-Q&{7j(_<*&DJ>Wt$6i zjGcMAoiJ{%LLKY}>ajTKfWIiE0*6vw8foWJrpshpF~09VKih(YCQdG85sUtLP_@J4 zS483Mu7nz5>`>6pp~rx~^?QaEak4X~6+P?wC3oq2AWtkI&iO}S*sh7ewIB3hdOG%S zua(pSy}W=t87xT}6SVrLQT4y_WV!u5^sCcW2#_ZbRB17G%2AFV5McYybzIko?%Ca= z5gTwoo^*)Zzlw4z4dnkKerRN&)uGQVnXSCH_z>QV^+uL-DVn2$8SXysW{6|d;OFgU zQ6PbIU6O$DpFKcmKP{GdXiub|jOVfD68t@xxKn*J$i}|t4B??eR95>CbdNO?q|~XP ze&kj&a5(SOiUvEcG9y$?5$489DAL6Kc>-!X%FYTV|AO@eB2cr|dz}~IPjtQ9-uIe) zC8SA7#In{-tZb^2qHU9`44z{KFxCr4di~4yP40!IqtUa&ELZ1Sy;&0@bp}o3U-V&R ztmv8T#y9bEk?6=D0W$-HvX^Z*)XQ4*IdQJr?3KCa2HpBm)SB52qclxleo20rOQ;dV zd2q0ggg8>E9OvPq;7UGP{u|hGZ)rNJO2|NtwonUhgrbEZaK&&Rf030Bt{oM7EHmjMojUG1^K;jc4sTzM z;~=slY%0QqXoB2elI3t4UG(>_`bh;cPonGyxHEz8(OTQRyYf%47IX?(EC&@a*4VAN zavAIGmyH>COW5x#?sWDt)ldxg?b@HSQoo2kT`cbhMr|b0h~*R^d-Lzm1P3excJ|I) zyluZ@PafYGng7$i+{Cm0fBHQSWb`0m5ac;Yy0a(}K9~-_9L6Rj#IAq5fGjL?)?ZhW z8xb)RwNu1{uSCbFnK{m2B$N`lgrDRi#2B9|vU|IX@ix^`PFwydGMT(&i$_4zl(vaT znO@1vYamU7{YU5fUwNe)Ou35UaA?BozO6XN`0?HNR0#=?ew?NLEi+BQLo0kn)Es>` zGC7CO0~YFJT_}io>j|WUB@l)`#^ph$KwRbpq)D25pMRMg6^-ucsq|^TY6eQBR1rdS~q4NW!o0`I~xI}=r=uiXnF9+ zChtPR0aEC{%2+Z~{%%pB^G|CVkXAn1IpX8&^k5YGyky9yQu${V0smD+`W>@*B1u9y zkBx3_eX$?BX-=!HA14^}8#MXQI9nkG9AeV;*!gpE@^MJ34{ldwI>Bm~JA}0;OGn32 z=zb5W<-GFe31R&ZS5iPc#2*pEn>aVM;B;k2@_mBnyNSwi1)CE6GNDn%$XW)(bp0Po zscQ)@SYEvbuzpD-t*meulRlDHMvKm??)lhDk1r7fZ9WuNt-K2{p5PRSUoqc-Anz3W z(xxKF=aj!%=+9pTQ6=a7BO8*oiJN6MXcetv1B)A?5ypo+^TMDZUt8E+LO_I_cu{a^Li7= z!|23%85xh8>8G-f-WOlodd1eU;8Wi6%S%B7SVW}O`-h=Ttp-d3Z|zV`T$eAjjg?d` zw2#*5d{Q>){xAFX*KQyYtdJt9mwoTya;A2A;5?WYFmZ2sa%$LnKN_Oo#|(MSuuO)W zcwO3EI9&v6uAat~eNSfmxYOKu__26H*b`gI1wIio$FOeke{IL@q2A-jD#aocAJNET z88KsQS#DWmh8i9?+N5dk#JbnDw)H}P4?le?g)&cy_yOsUJ^{kBgy!wC}bcMRkD#E7VjnQ zuNi5n6~3Qn5-Ol*jepDXVm1mt0>6uyjG|7T z(pD9gr4oEg+0%M4#mlA^m~VjDk{Z3&sQQg%ah`{|gHil){@c0A@UH%4WS^8b_ozIU zMqb5DL&2rPz(?Vq@hSxIl8HycJ(L<`Me=!yHDA?EE3H)%wto)Q`al0~4u(x{ef%_G zIveus0~AtIfjohI`hlSE#fH2rd#;bm!w*#istE?N*wEM=D(F;G$x+&_mO_Pv$cyR5 zLV)*{z#Ek?>!hU~S7Rl_X>I!E>-^RKbbYYVpdnG$DhrMz9%2*fr%9{PudXy%8NCr8 z9?)NrMtGjC0_}2AFsADL<;0dK@b)6^?`fI6pB&6`6Pe1 zK2CF(b(d5MAp{5lay$lksXfBCz`)OmG z4aDP9vJLCZR?3*ZIZOl{m7UoXy9iYdQXlr5Th7Iw*#(kmw@P*0aOapv7XsJ&Pzc31 z_fZf{%Kguz&b3+cr{EXl8v%4P_no8HWEIBLCI{hBX;iEC1wTVfAA| zl{enopHE?=TKLMkr-m?%TvX5H17yMrm}7@Pe$fBZ*x#Uk?xIK=Is{Lax{V*IU*yV~ zcK6JClKHzQf2Zb>97UP1y4Q$qKSuVvvEI$kaWZUmIS^N_7Zu4Ymyrc;v}ZwVv7`U# z`_($*EZ&!GHe=mPfI$iZ{rEx80e8HO_Z*0egN_j6*~+<>T=?5oi$&sO=Vg+7*6(8s zUXr;WDmaV&h1h-wH0U_8U`Mke10zE;5FAXNg8r54@DJ@T6MpH@@(4^1gnVs&4D=w^ ze3isT5w8??o^0m6HeqQrW_nt*vtf29^P`1&XZ69Cb=%1R# zW<%CNM}M*vt!^~J*E7^ZL$z0rj5b`neTjy{GWc`F#MD+w1rlzsNr0gG#I$a zLWtpFSD2Va0`4>C045PxM4pomos-tJFzFeX4_2BD7ER>?rr^rLF~JXSeb zHo0&G6+Y}IilVN06WFxgPx^qk5HZrK?>HG8`-)WT7U5A8akUD3K82t^1KeUsg1$s5 z00|Z^M3_z|?yUY+c0_dACfb5D@3M7#fj<1j2Lxp=eEH~vOwn=?Dr0XCGAEse9H?3ccuAh_10i8AgPxq(B z(06+$3z!^u_wljkVZ21}a9JESDz4BGEf)SRH-76Z!-muB7-&{xfK!8H^<{ideFneQ zJVZY|bv(^)v_yI{_7Rs=f1k}Pc3R1_Ey&Xg_rwv~rPxEl*g;W{kkFVKzt?=cMvi01 zkLDQ`j^F- zALlXxSoi;A{+atRrwU4TIkW;7Bo7Bl^Nx}zj#c$?^6}otl`aVEzM-@^+$N!<2V(~Q2GoFT-m8dnt1lYD zq4kmdqW6Atr^-7Dn~8A(58h93AcZV(7M}sOgY6aN}4j zEt1<&We_rMmNe|e;xR;?kQy4?oeUINy1Ht12kvL`6)?~xTr&<5otmbbpgI53)z0zn zq>drTL#9}#T;Mv6#m$Z$Q{p3+#&tanL}H+OC~4M(SnXtP^;_kniV-wLdidZ_qaFu8 z{gG&ugWSb0*pJfRO!#H`M_$uCR8c~)Opi7{gb^fI#v1rj-IE}bi&{xjvQTti)~oV% z={~yf*JT*#Rid4s8@1~?61WE9JaVFCtINs<;Ho#^%{ZS(uv-66e2H-JX?mCW)2-$KE}|Y4U*Njf?_aw6gOQd5X?qVlx@N=jcnaF) zY&NPQ^@=Q;05$D>1MN*RYzLc>j^8wTM&!y-$-Mj(vCfR_Cb#UPt@j(0)qd*Q5P9&l zU~tQA2L&nIiil+B6kbAA#6Grzk4ART+BX$4qx{bnD^}P(dA>G9cJe@c9L@wTubEap z+{YJjMp#WuRz^2TvB3_-Es)&6_o9$#rN7#SyCc|YVxs;%_vhAR;H7&rf1sA>{t{Z( zF|8V-Whh3VbMrIJ{&uAIdQ(GN#)!!YgpP_RV9CgZ&ofNDLWXK<$zQBgC%b`pOt;J- zIA@aRd8SoSDG4S)_vlPFkL;!Gk5rf1t=+WeMD<`(_v1J9_FMtAVmeOG{F{`ID*JwR zlERhqc#*s!(^UOehKFEl!kq<1#PXNRJ2UbIQOcxbOy)rIP16(!9*qlP>TU61ae?`n z5B`wYieNn;mPRT@pCR_ zY??o<%$j%))YNT(RIyG_Hcvuh;e68%E;#CmL4FfaGVsYKE9h&zGm<@GUwb_BDch;Z zyA=#zD_F7*=bzck4a-6?)vh|WNug!Bsv$;bMHKp7_Gd#@=9KqQIzJ?g!+(ABFHuLk zk}`z|;gRfZZg>2)q-&$3R>+Vj`rzSk zW?vxd<(oXazca3VZAcj;U{Z*u{)Rg>Lj0Ey?riFAh&_UiJ6UFiTrTg&F66t&@pJ`^yLDgzj+N$6aEVlSy^a03#K#TXJ;EtbyP%f5;Y3Eh_3sVA)H4&;9E9- zR7mwx2kfa2w8{i`cP%}j%s9x+flq@T)TSrGrn*f>wIeD z@XPn;M)NNJ@b93Z|N~ z9E1je`)hBgMt&~B?y@JRN$Tn|85=dDrKy3tL007)<<{nGhz)&(o#I2sw#E46=BoBAn>lMuV1`|IGLuC2!rZ|3TVb}>E<_) zy5Icm&U#_(V6fbiH5A@if{}k5Q~4wpQ*$inB9J{~C-=qcW-z6jjHUf8bMNmK?hhmq zzljV^j&<8dtH(u~N)Ig-!vP(P?_>HAhys1JS#QZ3v}gBKbO8U0y4utTkJO;B#mZ06 zPna{8q}tHj7k`-F39Im`=6I(ICcn-OQcAlgZuH+C(M1uird>$xe_vjLk@?`T(~nQ3 z1o|KUDzyIb{axE~i(e&=7yUCkgk9O>l2plpeY##mfBPO9i;|ih^aa+G%Sx=Uqgcp` zuhF+sI4>*YcmH=eQX(NnmAAan5^ao@_`{uh-p&<$^0VQ(a*xJVgfO+23_C;Oh#|$V zn_(|VLkUBfpx&MD2W#_~H7y!G(AbU15X zTd`9x!%WS)KC0^(85Wv|KM^degyzwR%~% zn;0W$Mf2M}8={x4o|Co9QB+hrEjw}N+U51M>cp;`!CqBicCUQRZx?~Lj%EtjzCH}0!VN6nuybIYAZj{DCIpMn z(YdsNGJ9H*2K>$`Nj=)G@Nq78sT~`=iJ0Jyki!_Y!23k$2p$#puYY59$qGiZs^8<| ztgk)b{mUd0CdaOLT1Cl6dDClbDF~uc+=asS9#N>rADg#o?K!n`cSzD>&(vq#P9G(6 zg_8#Be#mNDo!f0edaovG1>nz8UAL?qCQ>0VupElkl1ljc#_?0z z@~@`$QadS%cr7ad_osm;=m=?)Vg$r>7H@&OU!Oz~KI_sY?93^J;i@sBL>dCVN}+*z zpR1xr_1>UR@z7TYdAI}aMap`)h_XTjhfaeUL^`!;{-r}g9f{*qNTq%ZcazS6i6U+6 zmx*_Tvh-x1tEg8@mx*g3&TTy5=#z{V;!@l=|CQsn3J@Xue)ny1lg$hPk2degRWbEBfcI7A47*}hpEAF!nXXdf zyuRp@z|Ye;2(-mxq-$juDsQZyIB%IWUo@y-X6%R| z3dmj&NmFz=X~3j@M~-ddztUv#j3Up5V`NI`{PnU1#vMr=Y=ke@1!%(8vcZ_n-?7#Y z%-Z8MKy;$UqMVs&J@iPf8;RKxk0li-L-s1}&TRhp;su?pWFfQW@>N!K{6Q9{b(KqS$eFu3*RYcY# zZKE%5D>G!ypKHbzVS)^tzQLF8ZRO+=F8jbZN45hbZSm?r5%Thu zzH|RtTzR%{Xlt9lhX^Vyre-Bo_elfBIUpg9`Q#hr$`w6zbH8msVlNlS!XCS2wS1W3 z$Pw+?P=talHI+?(dFp-p1s1*N42*l-Sms!;KweDvW1w*~cEWSIHsDK_;tSTQB(=W8 zATHJ%WPlq6xey?s`RvKbz=2=1=r_UYlb>I(Rf8xfgP_D!rtPRG8~#~i-00|STd|GN zev_zVA-8FUB3&O8fxiZi|3f-AZ;oDr`2Kv9HVKDwE>v_QQG&59I-B+?F{94FJiS&> zi<|Id%)H@rdBMi8Op6ue{%ko|IovNIJwd?2cZf*>BI<&_gIR*Kpt49;L?sh+sZkcmZWMM;A}@RqJHj>8A|*`u;y znS{v9@Xu5s3fB2?FSBnC^@ok**zpr2A8eX(&gzlHo?)+LYxOCXMWe6%qXG-WvTP_t z8#SKD9w{l0v9!;Zm`I7Yp`-j!DeSpGI5aJF#^|LKxR;n2`7{uz=?h`_ys>bR^u(ySMrf2%Ti)U)+eFqy;Ne0y?Eur+3dmJPg%^Mi1tNpI`) zTcV3v>UMmKM22t#^twpVdbK(uVd&IXa;vCFUp$^#l|sIo`FH|);>HpMuw~ zc0cSR%IvGPXI?tBn7zjxe-R3Qn{FClSp?6G(rF}h$j~@fmnapa3UIasMdEOvc|sTQ z>|B9Hnu5oY%WqZ`9$+33JlV>t`a$!ErTg#t0ib>c(4~)Q4(;g;=vS?KR^t51&On!U zZ2hzi%%ujPai%U}M5jQ7$t zmRIPUsOi#%wI|e0<}44%yVjLmmqLriuv*HBf2>@15wL!Jrggo4gNCKan=FFX&daBc zQ*oni?Lh2I-3}~!B%p-LyKdz+u%PHKX?;qea;}WY+t!ZT6TL}jqQ8(h3Shh>hzI;g zvij=MgTRLY@f+XC{%xrLg#O>|AD_bXApgzZG|r^&=83gKyc6D9@MO9W`oG=xzt5MA z@~?k7+JRY_nEspz7EX~he`Q)%$w--O5jd!nT`(yQYsH8q?qO!%`w}ORAFX=dyhWAE z|4Bc2WI|g2!}i-W4myvl@G1-i10{6QN^JT+^-_+3)O#<3l$`%9@7-q_gX#~z99B~8 zSaB2c$x1%oUkq;SYv}dP@t5s*@9e8RN|nu$P? zVy4GBy5F}EB@RRr#Z1pZQ%sNjqWc7>qqti_X z#)zv%%iV(No=RkGzcI56aoRvGH!eO+bt?mBuDJT-AK1^Ls4V-?>-9*2un`x%5Quo@ z5>WMC@5lB-%>EMfG0cYyTC29Q+1?+Pp5XaBq_y5YL!+gM%7vS;II9cg7LVVFbLp0h za@Q}FC~Z)CoI5=#<`xCpsR_$(M*C|dy{VCD^sPObvE>!Pu(g5b3)I&D^CQ@YYL{_dH9JQt2NNhfXn^f5z?^C*v)o5%l0`vp=NZ z+ugjo8?-hlQAxN_M|xEXz?ws)2y_ZQ>c2YSQk6^uM`3mrLM>6fA>hkk3n6%tS-q(| z3J)KpJe4-lc)O7{7GkOW^6$hdcxx~7Ci|NUop5f?ODbb> zEQu(KW53R|1gzXE+5ivcv)_{T45#l~ai11mq0m!~%9Ps1UGS88$3c|Zli%@X(xl5( zHjo!Tq|Ol>3sFl{xTB&UJ6sZa>*hw+mJ@9b+{R2&hDmF=mZtA5I8enq+K2{MqO!?Y zyX0vRg3xd8`jbA~AlKMKD;oYypq~2UMm%>vr18^d1;IWc;k+#5A&(xED9THSBMHu;~?Cg9X_05^BV+8s=q2BvfEU!*#J$tcK*6~`L zKx4U@gj@GoHA=2Yz;>v1w*^BE*C%!mtoxtfHa$Jd^J+^p4b3-?>ImpJco>DmV zuzB!CmErUEyr$kJbFU2RpO&^;*4aQqTII*g8#p1*d*`bhwN7?UA7L`B>Pk`6o=ZF~ z(c(%EaMPLnvzEE8|*|vg$=QNhU8HW5sxISBISRW27BA zBG~NzWn}G+0bMWcG`H8Ob5F&86x09Ba%US11FE~{HiPP_*pr``5}r^CJ3Ih1B* zo%bR9S_Ol+qU=z~vX>f$pe`PYZ_*{NoJE&%V7p@om~V#Fg=)7@nB%!ARJqEd$|FI4 z9H}J8ZMGVF!PFS6f@7q!`mr!gJehJ-cwjNrf+Mx8_c4{Jxf8(uRdj9rI&-W~B*0YX zuahsQ{J-={8Egu8&;>dXibrd~e-fEXk<5Wq4E-%WRX#ZbvS5l0(5E>;ZrfT>gWTD% z2R*0gcxV132QPRG6~vL}Ii{{fMyeqC{lySi2!>wO zA|v_Gd%SsTYe^dJmJ_Wbm}h7*F$f1*s++muZAk{{-;l32d$_KiRN!vl-aM;|Tayfs zhe4aL0PyZxs%(3{#=I~___AYNgvJzm%BFxT9^Ogd496Nfa!ep2?2kR7uhp4$80G5H zGg&*z8##(2M_Zz^hR5iVMkvCW#2)UV!o{`t3yZoEF{3%D$^YW430NtGtgV)IIZ6<+ zAkaTy!=VCbl`1=+W3H=!sTeY&y6)+ex^yQ0(Q$!(6Ptjt> z5Sj-<1yon1^dWc|lv@Xay#?lXd`ZFB!d(;L;xfSg-L4Ua6#qmfOL8=sw?qcuVbR0p zyv2gv{7Y0WQJq;R{DY7Z{9&2K3^4Nputj(S--MT4-< zTgo}#`Qs}!V|`jP2~W^w?aG%JVcy#GZQPNU`RK5b(PE=pNk#8hf*iR}k4S6KXu>D6 zM_ruOXGw%B;LHgKhTIHiHHg0Jdj4V=G)K=<@7XA&jvQf9RojdG`I(Nlg6>OQD@_CyH(bSxH3jzkb!$L0a|2@;t%AC`D91PVXyj z>vp`P(f%~YLYeed1JCDzz_d1<{^_sbYbgFeW}~jKNje_lAG1(zOfI}>wo4NwA9o2% zuY(V}&q*c;(3etM5s`SYM=v9C3hf3K99>*8@p&y^@tLz zk{VT^h-21&0zGm0sTA1&x#{p5XqEmFjV26?qf|c_i{$BD!1~@EKOzQ(!#ic4z?cR+UeTUrLi zvnQC;wr05?4yBhK3bS$y0(VawD=aT>*wZE7*L_qU?7P8b#|Ydt=)!46^E`ySMx4O9 zJ+bpoF4h{p<8$MVYG!2gGwx=)&{hFRXh_Do_%w(6@;LbK{;60AA@yg5+bw2<15I>w zDBsQSp?L_6f=Pfqfk4GfYzJZf@|O+~Y0hV}2H2yp2;M(JBFD7tvY(9%(+&c)-IS%# zd=u==tX2~80_27{gNBh~K^*#G8M$(7y!RtgCP|8gvMy!3%=|Gv;$wre6j&sV#U1ld z2q75ZE$60TsCJVxBnCz90Uu64%8knNN`ut+VXCx1Yzv6F^Zc6aOKgzn=?@=+p{`>2 z6u7$PA+jBo--S6DNR@I|c3D4V_OTNLROd$g0mok+MOD@(HBzQb?Od*Cp%Fg;ecyjQ z&g6**VJ;FkxS8cNZTFT7<{yPR+piuytkqM;aSy)K@$cI*&}WAb*btv>Y5=RR*9i(1=@vg5cY`R!|t6JW4X z1~l?yLyckczkIw`!ng}fL=~C44#!rccieyKj217N?EQ7qxacaO2|p~h-M=v~TN1ZJC9&h~SOtFhxFw^Ufgw=pr|^Ra zr*T!}w7x25xQiSL+ns!l7Iwa=kqVbgi-KYGZR4S*9N^EKnt1Q#v(w~!Q_9>_*rVEiZTv)XJ_gD`d6^eQ|uLjjjfVy1=yu?N&>Pz&;f%m zYpvjI%_<>i4_^#tX<*E#*YzAt6?rcsLI1ijT#H(gTer-kx=SKZL>x7SpGM^6BhCGP z^N}|}yMbY|S((q(QgS66$NFPs>cb#SM^#zx!&T$?%kb=f6`lul@I!E`a#rHoRBPCBYH0ColtxBvfpk9=n( zn#UD5c6Y;>;MLlY`A;rPCPfx#Rsf&>D_?4mPN70H(_Xd%^MGeA)zlH-odzqaV?@i^ zV|`}5W%ZG7X6$)bEK6aJh=V@;n@R2nO=Lr5MM6IM?o`IHn|G^jh=+-j&S3n%>m{$Q zo0ulPInap?snLAhE~@Ll-{!$VBM3-fLWX`WA$2 zWke6LOkYL5v_@K963E@iekr_FPMa3Dztl`Cb1k?3=>IKf7oSt%H{05SY_09<@soA- zxd_R71#~>7ME;zNM>InkdND6tO=72BU8+Pw-r1m86z2>* z|0zWAz@&ea5@{FR)t&)16~#r}9?~l4`yl!^V=j*n>4+eEK3_YUL%{a2N3c)H9Hlql z838)d>15Tp=0*#%yD@OrGkF9vRpRmnPGAA3v*4Sai$(K;-HjlZKA)#Cgh|cUt3ZjS zM&?eakZuOP{h!UaE5MlCOzHz6sjqs-IJ2J;|a z@N1L7U9zRzp4{h}y@?63EIt+c?4U*d{grm8{N8!5BCN}N8I5GsiRaFvc#rfOFPWE$ zh#q%+o%AgpamP`0lkC_icN5yTcq2Tu#ma6I#0!7RN1tE7*k^|0yra8{|S}vSW9h(!i9X4 z?fR5l(X*Y8AgXO-H&r(HJO~B97aA`9>eS1`hHjPVFj%4CFyO>D}s5 zm6dv?l)Z$R*!&jDqY5q!!DqS1nC8y!zdDS>jiCC~=~1#d1c4ncZD-bG60QPPqjS(7 z`vIz=l(9gl{$41l3EeoZz8{^c$8n1Z5YbSVGJ(3}uny&>HjHc_n9@rjiB)3KFs4bG zVkLdH;Dw4~QUbY!D726FA;^SA$9=S~CjeiCS)Oh!9?IY&ZL;)(7xm~JLSNsl%tw|+ z4_ea6i5wCS@ggHh&l*ulc#`XAQ;@xPcshJLAFz$wrC)wfoIP3}Y<)N=PPJg?94ImI zdM0sVALMB@RI)qz-{kRNf!?zuZ`1EmIwp2CyjBK$XW2a5EV^Xj5Hgy8=LbH--YZCO zO`_(yF&t)o4y$)(WOz_oy`Z#|*mW*6nk1q{rR&a)e_!GUDIsb`qkuKE89WX7^qBlM zxh&i+U=KZ2d%uh%w_5$LR#L>A+2A`R$aALsOp7KMju%yf%{jJ8KM4h@|MYDHE7Ky^ zD`Jjc4wsKW;_OhtvNluPPpS$=9^`(waJ+g{yib6IQ1wT%oNg=7xW-Ih$3-d(&#$X? zQ3`kSCme6#qCUG6EN&Uae{E0r2$GN}2EfY92-=Z zw==6o&-{cj72JRQ3kT#cwT#5YlptC6VRX+nH@FZ!F6;9c=cCU%3>#Td_XB?ccU@9wFVld;%YRiGP}9HxT1MJ^`ma z8y$;EN=o!5%{X9C=hrB?@RAzdVIE*J-cXpHR{yuiL8EOHFc6cYP^|mJoHtl5l7(r6 zv(*hMUD{VHWSY4d+T!#EnlIq4Jus>G_I~RwF{|2fvrBy-nh%E^)V?glI9OH$*Xa6vwcQydbyM2R zWvir1jH@9)A}Dt7`N^Omq?9tYFa``@G7v9g4QAFkAvRk^Y3Yt6e;(6}M3P7t>Aqy;AD z7W*TvKfHW4zXOEI`{lGdCWyRgJ zcvw%H3fd3rw8tRlzoXn~Hj_*fXaB)@B)cmlGx-;gNtKwjhji0|W_arUbq(X-DH{E^ zxc&9b1Pid=>Z<*etTe#lrQ(fCMsC_N?n07{cVrr#6Ov5hCuOk-;69bJ90ls<06c;k z|1ZDM3N-k9;rVzjev3=VgPxBsBphRAYT+-20m-y62At@x1R0^Od4zHJBbCMh`&h}` z=r3{nRU4_~0C?qw#2y6#B~w>JFGwb#l!8z`k7CF=DHuqIcNgD}{_nZ#`G9saCT(x87!CV3ksEn=!8+ZNkazRJtnHm@LhfUxoY z$yPChs;5A*`oHX}niHSvx?=Wf=zp<5`|=*8Y9tWxBhVLaXn812rFJwJ-JK|Wl}{6< zL?t^;TpVN~MYo{O3lTZ%s+ayp1zFrvXŶ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%0A?mYjeR21YN_`f`Z#uvl90v0}BnovRzj7 zjni*U9tl`Q4S%y};Xx5L~he|n^RS<`t0>jKH! zWI|RE41!nUE5(87)Q=A_%I8qOa1!5W6rwuQ{Uc_0C>$zpvG`Jqz7(l%g!VE{y2%vxCf16G?Je5vu4FaM&yc;GaSx zd%(>@==3z^>_c@i3zt0;wfpbF2E3tiqEn}kM|fbSH}rntF*&x8u>mz2K?Ty9vf+kfhu{=nfW4&WsGet_T$|Q+qF~; zPgW948Lsq?!%Z_p2y&6CofH>~20rRK(4xHWrqf3WS6irMJ%Z!~bqWqwJDb_7D?@`{ zuBx8Mh#)rVgl2W_X_QJBd>gDVIyM~2sh#D4~*a_*tY}G05&|CpSR%} z*tL<7C-0B!ooL}(<=4XO;Dn9xF=tcl(dlwf6zQPeCD@nRYlB8p0{$WJ&9gJsIN3>@4^n-sdt zSmct<4SP61!`#G;j(ShrW;iasP5sbnK4Fv1!1l`-<#1Mn5?r z(zJZ|VB$GC8E*?+Xx-%UG_UFt|LiqU$blqX1-7eh>`B44m-OesIc+|#)nj#hkT~sF z5dvXPL%7$j2gKLgB^nF)n^caTY=6@)a;Lv@u`x3E#+AKStn(40dss(yTVQ- z7_ve$tCw}KPZ!&hO(0;s(hM8bvX7@$o}3;Fn_!+1Y;CLhIoiD*0+3hRM~?~@O`g=C zT?UlHhph-8FNAz4cjgx199(j@sRSz|jT_G6rkj--xEHbSrJMf zO;?uUj+-Ipkr*l(@qWtFI)HV9=V>;%L?FQjAfF-zLOj_g)sK(!hD}0LUXk!b=JX^u z0i*R&8@;b$P_#*;@L*HzFhpK)h>hm?VpZ|AXZDK;=6Fnfo}<83Y`l`D+*);b60p&3 zahkzAJXk@5q}Nimu3hKb)r$r}lg`TBTJyrcU3<^c^yLKiu%Cc^ zJe7qx%)i=o641}}8rEl(HCCdXWdF(`b1FqQkhMT$Vpvn*`NMB9YM`Zr0j#mu#fO|c z9nn#Zp9^9_Sa#7w<4XCjSykypkm!vW-q-YGwyEmv)fF~ltJw`O@{Zu+P9%waHhobs z+Qj+W&}uNp9)Z~Z=^v|h9P(xrXCtw;tAkE!jZCL=m;R~{?GZeb_?^S2+hQeo3&nf1 zB-;nDA7lQJzx)~sV@o#+t*aq1Dkj9tH$u0G82@QiJ@5I)7YMB>1C}x}N>hJwTGppd zYR2g3R#LxI5x{TN*@!7V=A_-aaR-WD>LR$cQtxi{W^a?8Ak(0?bZ6&)eLz~SyCkHW z&F*@_OkT&YX5Y&JYL zW#6_$?Ic(9e++m;CCKnoY~L!9pNA!0vhivgz-G<;JRN;sf0#-j@v>A;7tJIx?CJiwB$^v7E2g!LL+|l$Kywjw~z~4B$l;O0-R$*+J z#Q3cW1KYk!okt0fmc;|`Zs5GN&=z!FS&tCwkhkrQ_qfHN+Ql@1`q|@tSRe2ECruME#(noU z8u+R(pz=f}lb|3YaAg_TB=H24RrwUjL;XHspKf_TS>#uBfDP8)2>>1%R$bLS50cll z;J09XJjr>SEDl0+DMQs#?u(oS{1B;Q*=Rc0Pz5~TpmSKY|6WzC*;{Ou_8=pv>g~Jk zc}l>{n&BHlV$pC^r}fwvvA$NrR0nnXu?i6gf(Qr2a?+zE_vt#esae^@@&1)?2A5W1 zsSRSM_f?37;>b}aeu*W}h?Zg|+~??rld37A^11Vxe59_B_BAibd!S1_nvP@ERUILL z8w7RS%<}M3-9gQC5P5rr1>*sq`=sn>4Zc}V3o{>KZg;*$cSGd6P_FFXa8@#GVGJu- z=ks$ne~eo}ApQ51AQqNaI$lPxTA_5=>3PaZ^|xU+5YB?crTl~8RY@-9Bw_w3m*2g` zbEGm1b-o8K(SV`#%{jN}ulTRnPLxjNNhL3PfV~8P(8U}_RXyd$W4+^8Oik`GGAm79 z^(Ym}A>}@wLX@amI#blA9j70 zL@{ne7-O1??Gr*n&ai!6@;j0?~f@sI@o~b#+oYQ=2FzD*?&>t!km_ z5y{H4$%zz|+NFNVGGjLp|3SO{8pp4Ho}Q6wbSwHRRj?U+xf};)$&P~mIQ!+9KSf1x z|NHDz3gK`Gpr5@HW82pWhhZ)kRUtOoN=@FBFZ0LA=4GJz6=f7p3mpdc+TYQ6bv@=K zs3&9tJK3#ex#8ijD>CaYiz*Q{q3rp?hlI(O%?Z^-e!^B!f@Cqve8ukxi0lmnzVp}6 zye#@ZUpdvRpyYQU&&YbcdUV|luT?UnF-EeA$ymI!8YVx0C%?sdWk_C?L_k@H6AIia zKYhAG8D0Hjp7{3Gv^Fj~n*WhAs&-q+c_t8*F0AtJXuAH+zidu*_fQ6jJmP{(M7 z)$(^boFcCNqDI>yyGhd$o{ryw+wDH;;>tjJWi?rv*ksd7Y>lE!CUUQ|+((mIV7;ju zOQJ;EKH1Lcl8@n$BOY+O>XAn*Z3<>M*&&4~bOUuUjmCPChwS^DbpdBniJ z`8%wZ;t6T?tWDRkpnw#%Lcy_37fqSLbwIq4oY037?xqx?M}xC0=b(MCYFv{058I<&C+9%`M9^`>! z-c%SRqEem9Lep`Ay*>W{ zOr9SF#>sE?(EGaD2K`Bev1QGJ1wXX=mIwU8Uj{0TJ}(E#@FJJr?O=}6|4nP;UUcWg% zNrf}>BpOGh%8(dE3=Q-z6fzuX|Fmi{3%(K5DJwo6V4D%i*Jitw+snEYhST=?GCr0v zU~nXN$QebPesNaqIT-ssz|xjPB-S)GQkUG~;haq=75_4CmTWK~ImJHm4*Jw&SLD!^ zT5%|;axr>X0{C$V>to8`k?j$nCl^xK5D}!&V@8Vh?ONu~)~0L86*Rs0Z-$B1K`sn~ z@Lsu<#2c88We!pJ)fShLIS|HUf{WU53Dsr%Dshy^OB6&z2An zB0Y<#j_MCt<=TMH_k=yWX;|uE*}ZR{5NkP@>M~B6NC8bJ*(vK+M5L~ro+4%Y85y&n z-Mw+)6vUCxHkhSU;iByn;8ze=%uKDKcfdNCU4AhZnY8$`wF?MHfMi)OSnGx*WC4$1 zkGUU9nVn5V=q9Mfn#$FeLYo(mA-9JM@0QdjvVv2EM7ZB1-zV%xTD+x9mX=Q$U%)_=Y4 z`7X1co$BhUUsu=eE`%60g>a${hdLr&zU2Q#ddF1^VM zSnj_Hrca$#J`n3d&M2A!vimYYF%uf&pL(lF3e$O$MLq9Kr~O=eE>OCb`Y@ORSaPm+ zVa4Q%A4X5-vQNL3v}n`o_E&!JtRTEc3$RvEj_V8WW@ImB?kg5GSj<{df|+3Y;NGF6fMNlerEd-pg1>kq&#(0j0?cFNkM?P&J#{ z)R@?$;w_F}V=jSqPM9<*YA_JymQQ!gzj1W*TL@mPOcxaa(Wn0zMFsnB%0uqwiX6|x0<9x$6 z+=Co%dAg7)ih!bMA>y8<_&DfcqCRGMvnN!7_pK7_7sZ4vKKjP3L;Wn0kqkV6sQkdY zP6LYu=Fegu7xpQM|9dW{_BW>88<_PAASWW=X`WrfQ+@zn5EyMUt#dqUhd)&d@02lX z#G6MiewG?1!bqd4MP|-aqFn_XKe?)QL#EznUOzme7jh8n6F9qq!B~Vas%Mra^+b^G-g*wKqP1KWr(29}30vBN}=a z6k&?zJ`yYWlJ)8!)<~mIF-RR3r2XX#s@|&AMUC}(4Ta0^3AW-bQ)n*~;;hj(M}8wZ zOP2XYW%l{>gu8v0yA_1XCjshR;7XlCEC$?u%OMO@z#d>Xlw_FBSk&3A;exsPw&`*L`}>zHXqov5cU(wCg#zj| zo@3j!ub_ThptB8$f~*BTG`)!HWol!(BgC31)kd~pLeA;Oh5iA-+SqWGtxn6koPwxw zI!fYug4icV^NwR(Q`K9IXAyFGh#2JN8T%xXI0`C(-&7gpT;4MZhEh5J$4dcKCs}Z?Ah}yS^!+VY2yT?*e<0b|6+p93#`Dz94Ua% zgEZB!&NLc$EyNv&0)y~YhQS)*4_ii!2pm@rWa-nw){+`?l_~aOGL+M5&e3|Tv=T># zu|FXG{tZ?0d$>l(4#H_Ni6n4@fx;d*?3)nDtejAGqO5pk!SWWcS{tv!Qv@dhfX`pa zIJonFI9_Qp7r-sO%@0H zz)_LSU4nGZ@?20jyasX?O8%+~G=m{;`WA6GBn(JSf_AxC$|oW7b9-Nx!*mwIozkwy zA2M`*L!SSST>s@aAW&gP7%%P|Am65>*o)(zdNp>+ZyCX=YN)-6F&Q9FoC&ycRwA%w zluYh&OYBTUSzrMEOA6LUd1v+*EZjpiAv#j<{^b`RO{&|K=nF;c5HE=ne4$6OGEF0_ z>qnpRLBqE$pzpn@>n6e&iresVLd0T2@UcrUG$M9GE#cDMo+vTi+PS?RC8el)Zo0PqT7e5-;@%kN+Y3Py;F zK(o@TuiQyE`SWkm0?$Is{ZTVx;3e6!bz<_zdKObA;)yRZ7JHsXihal8037wx=&@cRiaff0)I5DrE=Iyr~y28<`g&Y>(mH2+iSRgip7yu z(g11tp=Kcl_&xDb{8TY%Ukmi`<6X)}oa=W|P)nrhj}*Y~WLYrZT8QyHYlbZ=fq62M z0M9RHd(MP5w3oI8{uYxIW(x;AXP}Jz5UGajOw{m{-U)4%0X%mL^wPSSVXQ72`TCr2T+4Xd0d!bguJB=BIkM;%IY$b~kM*^s?oA~7w!Km1 zp9c?Mer&W>2+Eoe5oP1@?6e^_H(6ti*#^^{r5M(dwCC5{taUddinEbvqXf7-1#PL5 zF6TPL?f`qQ#Pk!yC66o9mT=OVD^1jetG0zP^Nq!^q^QT3UYoR#p-t6~vnodr;K#gH zT@@c5FF039YpIA1>sKN|p1D*uPHcbb0@tmMa?Jwpx3mXk181*Sm*Uww7C~S95q-zv zju))b1DNM2(vXJa=!qr3F7fk>C1)o)2A)PsW0k(tX+`%i4ZvjyYU&B@RnmQcj!^Fy{NPChUwU&PEV zubnBc{tgAWw`A;+6uJ%oe!dlzN-g$JKSM9<+KGQfDdbc~^~lp*^~2LnY`G z2)$6SejPVzTVL6P+6e433-Eg-D6Scrd1)u(nmF%LSAIPQc#IZc3Z9Qk*c*21L~V+@ zIatAb;LQ4kstxj>e0om>iw8zD<#BtmFUms8usxs0`VHqJmZDORe=^_~!3beOs}R{Z zXqG0_oPo;#_r6hM3xY7;o0E$Ia1S^az;#THh-Hr<_BBM+yLF@(0emkLEUxWW<857m z<8@D}XR69+D#Rzbk%E)4fE=us1o?(9JqGI;Lph;0yO?JKyMCqqaE1eIyr=9rRyCbU z?dPAWmNhk8z9k7sw@S;p(yfeVNgz2Xdf1LmNt%nKLEmxV6^WCpp>UsMSJ3kDhycQE zE@mhicpC_~7L@7x$g_Cwt=-?<&s9VI|rokaHC2;9Gp zHeIyoQL$MsV`l(AW1rU-_ZcW*Jt8&boxZw~sG-4kkYbG75DLILnh#hTO3+E}g}l2b zR=4o*;Vl5tArPeTJu?Fvtg>wR4nznII$Lv}gzG-4Y#K@846En18l5=Uj=ETF{AcW& z;{>$kZ91W*`NWe4Ojh{4D)CXBAO}z;h~;mIwhE*P1S2m(bM`7vtd>_>&?ytw{d zvLgRVwLJxb_fakD!2}N}yJ`_xg zkmrzu)Lk&jpn>-Ydc{{_m4NvV*tKvyCsTLs&ej6ULlX{fqKW`smm@1?dJC0KCjOO^?6?#W;7Npc;-I%Td#X$rO{K)2$B1+dNul?P%@ac?$wsI7NQl0llOce&$ z;^Krt|LH#bt4W1C_;{_JNeQ|#8VzvH7r&kyDfOt* z28hpU=%}%QvoMEZRVzCuah+NT50~K~4JXVkP*I?al85{LwTbAAtzTh~CV%&dPka3b zlF)8!K`j0M#y=82ag3!)QSAFkndjUs`(E5XB1~oiiBv zu@HgQ1Xl;*3eam-UQ@jWqyZa~U2%?e*^?LXLf(^v>p}Ibj{RzTAiX1|*Tss#tw~yVRs9&ivfVet}p&RYEVM(z?w%290 z+{JKAD<&J`+`3A@y41YUs%f4l!6|#oBYA;zj0WiO3{5L-R*Ws)TfF_D7w<~x$mYcYub{M|X{e<1I#Ovm_v3`q9PoUA% zI-lI=;XBcc)fjZh^pG7&P*1lPS}ygZ8tNhaZ2LhNgEZMT_MMUKEqak&c`*VPI6;j! z{ReG(E3D2Jw3@l&LPcrF{FzIdbs7`z-UQ$W^=DfX-u_psr2y@>LW%c)2@PdIzUqtL^pvy0QK24gTb~j;Ukp8M~lf66kPta?TI=~MAzz%I`_nXC{!`@tWS?)P3kw@ zYCc&}*S$>zFeWX+7$bRmFF>eLPY(@-4$98D3sJIx9p#wqON%lAaBmx{n#iXM58-`B zNNnFTG6;~DUKM$dkk0+0h#qDymn-OL=J=SZY;PuuEF3TD6mQC{2T!e00cHVmt!c)h zNVamcN&EFtkc+-=`@#e;tXpdkKu&IZhzPjavo9s)boj4A1%zG za{DY2zxrQk_9PH{>FCT4ygLDUUXGV4bRaihd+EYB*?e18Z|L3)5}34GTH#~wk#eWd zqE`a5Nle>N33~bJI-g3_r0^-VCl+6$!&!FK$7<^O)z2ch?SlJ4dDHLTl#wAd+n_wB z6mqQE&Og?lld|IO2Dl$tND>)7{;Gag=R-L1O_}ENP6Fc_|Gn1G4%t<=+a?+&xKb}$ z?di@P*xQR$Ou}#W%c=XVRs@#YNQ5ba8AC*mpR(-*T?kBdP?IUeVPw`DaR24BjE;!Q z|J;|+3Dh>}Xr1-LF?x@6RQYdIXFJ26;p={v@0}*g&srk80aHc^3AlEN66iC-6&-4T zb3(dfFSL?Nhhl&}o}e=bTXh!?0QM$#CiFL=!oKaaxLBoI=}K|GkhWGs$BLeYA`&y6 zTTe2sxJXDb#=zh0jN?b_Lh`LQcyi$x4zY=Di}dt#2^$W+j2q3+u)d$KgY}tFxLvi@ zcuAa2r5!Y2T{gFq7;h3+`tEW|kF#_SWYpGfBj%ZW(uSt{hHHJdBT(}(6mYYSdKBEK zo^~;LEZfHa24*J$shED$VN}_{Ed55K2b33p*c0|4U`^7Hbo_bYrtkBE*aTotaCA}X z#$_6dn7^HmlR?>Xm#%;3^Cnv6ki)~Rcxz<3ao!*B;NB_#W1kP0Z_2Dy;>OIOglhCn z@n%WCFsdZFI+FQqbvO@{eEMevYwn#r!E`q?%%_myhCU+dMSY+|=DtPC8QNH3I3SGG z!WIp(*|@L%r`=hkpCFf~2rg|6lJ8}f)zcaW^Z0wha*F47RuE;{1ONQPMP;CNLeBziD#b zSf+55^N{nLkTdIE_|j67*oo&J)uEZ_hQPP2{gYDBgW98+XjLeRS5$X7B;d2}t}2`- zL0q;$ko-2627tVS6Xm2VF;yRYfSi(-SJo4<9fmNO6q(wKy+}pb)f!K(rm6SuXWaKL zD%qPf@>kuR1Ey+}_M8kxjkf^toS+#M&p=n|Oq4qs0)4-KU< zPsYmB_VSZjm4~}A=kkx?NUksEwBNU9Cz4O>qnN*RIYZbk-aKDhg3c-TnCAp3eMM-@nn78V$5j_{J;4mu&Uw7&t?5}SM zoo)^ls!+zdKB6NpW%ZfMgW>WGk&mnwuVC>o5+SVEkDG|jmT7Sb2^ojP7a%2JM?>Im4xPRFDNKC(dIu`Y zG})#J?B)bvvp(S}Qg((sF~bp0Ixf78sc=(=z=jH35E%2F7Sqks(4(*}y84nGkua@D z(D$u@pP%F{?FYcLKGZ{Q*3Xnnz6OP;e9)4rFuxGDvy1@#$03e>vAg7~Al5h!M|PFe zdNn-Er#FV2Yj~XuuhfvdB7lBdnIKsf8s-1JFCG}Bjf*^opv7-qpuNsaLIu#X9IEIf zkd@q{l3=ICxYRZMH&5rk^6t2F+TyDQg_G$X@+(i*gjp>&DpI#szstIUN`gvYcFF?s zb^vv63+NZmJfj7;{xEZ+GCro5;BZUi+*z$d;l zT~Pf^>C3ADlZR+4eCutSTlCN1Fv>jZ0RpX@K;}hbd(FToT6Bg7aZB5cAARja-kd+Dyz8w!UR?$yR+hXmh5`AY4=QLEwsRbmP9dW$U#Y^89f=}9xMq9V z{rqYD>Me_axxrnAL6Bk^VN?`2D&T%mpBWzcnc@!xN zzFU~3ehytuHGMIutVG8w{XDJMPU9U}9m7xqa^>D{>sP7<8s6h*2h8J#ZtjD2>`!|Y zADUxOLXZzwPz{8?iNmSs@Q9pxS~(yj904d5-{EBqXm)kWahZ4k^8o6cTCnnSARDGg z)CCLhENpg9%RDY7K)BVprcvBhq{=mE9N8N_CjiU?Dk=Yl-N5EXirE|CDkHl-z@akV z2v51G<-x6WXDOhUA*ZsB6PB_gR0&u36J)}f0ej7~Q?_-5Y9&o%GlP%Z_%7*^8(90k zU;(%h?vZWQSk32}X+ksqe~asq|5HaCkjL*Qk^kX+-fE^8I-ZVhf1&qZd18P(V+4(* zmfwD2;3tglcyPCcrNtuOr4>5n%e=OBT%l_$gM?=OV(q=)Em!`l-;)o-&@RXeCCAyY#E^f)fpGxS}%z#$? z(Y>k}gve=9e3seFe}{Vmojf+)c41-$g17*_ZI1})Y?qUF?P3pv4h^`0Ds36i8I?HB&P+f784AO(dH%J4ApxbNF}i z)-NWCU$9KK;{CJ-d^|wE7F1`QR*N|Y8EDN7f}!GshCgA{G|daW-3cwCeeMsMjuFA* zh)Ky-CTrCchjzCg2n!1JioQ$Q#K6J*30V2qo6tDb7A{Z#JElqXu|OZpe%$o039^3qG@DRWrHDiaka zb@*%bz1l66Vdk$)We}6jmgIhC&pR@r!Q1eu-EbMSxFHr zac}|xKdRV`&mPWlyb(K50AywtY()c zha_Bz`5wOI#AEy!%{i=kXr&_guHlsNENewFEeVE`%W7g@>{4V8)(iuDTye~j0`K}$ z0jA?`&n9*IeRc^@gqYObvhp~wQ4M1KaK7Zop%Cy^wN26AEb|P}I;ZiWXQ;W$I8Cb{ zkmtkS-Um{1E6z`HACz8M;;*zng{4--a!#MZq!)hOQvI%0i%U%&7=Nq8hm39DEh&x4P)`N< zo7N(E?M)uI)lD3i~j<=+7Mtti0>M1*wl;XM^YbojR+m?bj2-_lV6TYWH?4L zEF5hTd~S#*oS&Uj4l|h|I!a+?5O4X=VL{?F^kWxl zp%oJ^#ti<{C2IQXa%ne`TU*MgOmyy39@|_`9ma`O#8x18)QyTTg4S6h=c@eV<>O9n z{~#!JS*f;R;LUe>G({`{(7pKVGE@dR>oJl1yxfxv9V?CtF{k3@Gcv3)YZ==eETcug zEZ-@3C&3uTGvET2SBTTPP1C74Km_1NSn`8nip571M_Yxq+W$09$0Mi5uvK>yfFCev zhnFS1&aT6Ht$O6_v}=UdBGzV=;Op6>NBBoK(ubXiLt>14MXfm2crcGSG4<|m!)?p- zN(Gq3k1)+`yPmpcqWg_99SnQ2<{3`s^rI5wwvppjD}0_9MK6hirqfmZ9_)AA8rXN0 z0qVQp78zd}wR3;NgC1q{BAA4LCe3LKB2pcViQA_Y8_58;F*_20Ha5-VrW+-H z{oB3=qSZ9LfBc?!@PD#j?vdOnKgIKl|0@su-~26rKBSAX;y_k5=q-VPt;s347He%z z7AxvbcNxZmQd@7$?bRyJK-Hz0vh>=hrsP)+-6SU!;72E9$T3Dw#)7MEx7p($@o<)b z%wE8Uk)F{0q#Unnva9n}E;?auntc<(AX_IBkm$fUmp~@uY(Ug5Q?i)$? zJor6<9v?;WmhEpeV$!isI*|d^XT15_$oM`WA)5fMBP~xy^$60xZRCq%zmsM1>FTkc zG1mF#16hRZ#Sj!DDB#Pd_$kg52@(kE(k(kP;Dp-NH!K;98$?eA z+dZ$wgp+Akki4Mg(wkKC7MLuHERq{Xo2_TZxFDo;$e1>6Ut@C7USQd`8`$bOp%he< zA%!Ic0Q0@f;e+tWkKyCm?tF1m>eVIJi7-VBuP#E1wRATuy5>MCcO6~fm77&&TcPb> zv3k4+N}6BVjTA6&c^6wE5$>ML)AB`l09|Lm-8F^;Y6!&~icez;mHV2E)ncO`+AbHh zT-e(2G~ccMR1XMz>VZ!z5Nr%vW)%u)yu~91Dx(L`KiY~_O^CMXSN-Laf52WP=j#vc z*xrh4rbN$hjctV_l1Fu*l31pql}8;H(6$}p4jDcSQ5ay&9tf5wl8^1#ETc_f2)D!( zSB1(OIq|FGMF2LCip2OC{=aZ&_|^T3p^~8Yf2wnm1QN~^1f4TLY#Z!SJSveGD31SA zhBlA8R56+oXLtD~2fv>ld7)IYH{EusV7CMOw@V?*+jb^y*kka_mLLn9Ko6ltB?Y!D z*^TAr8HDuuDKzy8@c;=p5DYDB?2~ z(kUwUEX?Rnzfwd9c;J!L4=v8@qS=phYfFanh~C%k4KKL@!e-{8lUIOUGGY!oiTKLO z>|qmVQbTi$#|l}4Jmk&T{nrgo|4VLw`Y8v0SgyOwe`$M{3Y%y6N2ULly$AU53-M%1 z89eCfsB{J^TRLBI3?GbV6PPN{E70P`Q)J9QV0Oap6wP(^K9;LS(S%!7xxF(3p}8pd zJd&&@0ZGiUN()z}_KS6zr*NS%;uKvG{?L5^8knJ~K}PY9L|mLb0DoB^q!=RwwQHk=1sz5n&Yn1&4ynxPpY^l9NQiK4WbQ1=!~kpu1i%0jP>+br;9UE2{SM`H85 z1I@wAQL#L`OFpGXZZ4S?WqQ}gNLC(Kv6X9C&_k{fjKOE*s z8wsrDY4Q|IE8XcxiG)7O9<)Wzh6(dbz!_`!*)pY|Mc>`NU-qaxa$0G_16^x7etKX_Eq*9U8!;kW!inO`2 z1P4|`=5tWjUDAA3JMw3i$~Zo6LqE%FoX}1zlgCsub6QDdy@k;yH#f?MVrgIe21G!&0MJqoI3hoHHt6E@>%$w{8d07L_l9Q8$o9$W^n__ z@Q8(tQ?o5y$9?!E&WpExeUs^8yc z4|V3KJ=>;!`r%^lySsphVO`hNFE%M`f8d@i9UJJTpm8(VL!JV;K}LqC@oI}Y^8ABE z9C$B_h++h~W)cr^$ZBaBFwXlrLmiOh>lGy;aDfAl!-8EbLdoQOna2y(lXvux9ExQs z21IGs38O6{shpqMAQ;RK)2B$nZ5sw|ERe%82q?DhTAVHlhrG5_-4Y)Z+a zret3Pz(a9}Boemk%pCv^J9+6O@FTez06a)+CV1`51jYZ0hZId1eSff8R)E}q*2~u( zB-M`qcu4jRwe2LMIuk&dB6?2pmj3^XhySe~0B1{#2-nG-eSn*Z^Wa$PfH&y9qIS;V zJ|;^D$MzfyM#1}aRVXI1GO&^?uC`Afm1XvF?J%V8uyKmDDfF>;;cdDCgV6hxsj)~siHjd z;7ClWMW5sX^6fYV?VC?zT?PR8c6DHCiz_LkYU(<7#ys#B3i{Su*Br8Ae;U*cvE}|G zw?5(rvFWrrZilQTBabK<1^AL< zATWD9h_n8PZUCbt5(E9C`c_jc2sQO%R~)$-+wivO7yqq)SBA<)T6$#$aOY#-YKWR95ruQaf(JjXo2S=j z-W8Opi$+AtP zdJ_t>Nth*%E{ZfC&%fPY>Jg}k^_;+7bkhl^HvSejDDQmYL}9=PVLrxxbw$;~PE(Qx zY6dt1V*5^;+DXEm3~gLq!m&8Yyy5G(0-=D9SxIe56X)9?C074%7-SP3QS2V< zki+o2I$*ih(18sq;$K=ZD#d}DR<1W?p>|L01kZE*Slla z%dobmfZkPT46cB*H~8GvOCXuUv+JsUhkyvBDLbm}kkm3sWH;XXX}$|7F@Syvn(9S` z!5s8t(t@1Eo6j1^e0S|Ju&dPcwrc+I?a2cz4T9#CMsMx1Kpq0w(YK>v`t3u@;w{cm zps-14v@)#OPbsA6iJW@PpO;iL)WZIRF%S%i!?QGf(dX@~;XbJEL?OK+j+qP34w})L z72?Y6H0h69l@#ZyD)ep6lf+~wxs_X`5YhCRY8i;l_=5r1-6{9W^vI9(vMw-M#hn=g z6c{R~5myKp*7EpsV_WgIp>jh|5oh{xH;7ladn$B@J1+Qyt@baD zHxk%YHuXx6&Esh{^ZFu_eYs~GKO2v_y$h*vVV&bJB%rH&nHD}Kj1lx!`%DC$D)Er+ zB2+2A)@M=1>29k3*2D^FZeuRG@|1bEw(c~?{Oe$Q+^NrAL$EITpirH^T8bP`peNG* zNr7-Gdk?a7Arv#-wST?~2y|xmhJB0{1+3o`eE%VWgvV}dozZ=a$fn{(42wR zll8CSCorGXTv=&VkjC_WI)&|s)=rF)$lsvg6?1`o$2NnU;EEiWk{g_j%90D3agt3B zSj9A}PpS5zl}$g4iWNPl^UwlNT*+k|5d${oe6{^OR*sEmVT$Ko=q>TpU1>J4a*T|y zaz#i37=l)4)y{F?oUh1l3M;=~`;3kAuoF{;*}M?(vx*%1*auF^PK023@u&{w=D`we zBw9PsM(yjyO}~qOx~t>Z{cU_&KdeYPveULMVUk0Uj){<52Mn|8ZX&bux(dSin}p3| z8EjYmU^Z6?m4y0`Y*nXY@$h4lF9Dv#b@}Go+FD1y8F7%34Sq5rKu(8E4&o3cw(ec} zat;ld$bJBMscM-{Uor3^f7=KNfd= z&Au42(?K4(Bovj^E(C6>6{Dfs6VFp+tSvBV?rAIJpSP?>fbf+0@{UdYLQBMs z0MEUw9_;^-CB0ks2-r6O`^CSwcUWgx@g29pRz^z%afBLPMD2seNGRn0 z)l@ZzwZC5 zzvuVUHqhK*Nc7)+?DHKE-;8T%&P3t2;eYtd+_JtrGwR9v`VLvdc$cH2dLyC&%ZFYZ zN0E$>#I+0m_5}2G|F3$NwoMR!ph+00=!c8uTs;M_RI_-IWc@K|55Y7`eknPDA=Tzu z$0yD8j&nG8$I|mS0Q{i;s!y4>c)+1)h9Y>4;Ci(q4^FZeWH!a zfIaY178DQQ>)-hu1i75<=r=o1imVM()JHBTob@Bh9r61^4Rh4QbYe?o=()^7B?vn;0p|bfcbM~9h2*-vs3&KV z&(S`=fecp~c~qQ0{#LGbsp~D(%Y~|vh~O*vUMf&e0;2KA=+UCdGh7sL?6d4Wjh-T<9*Q_@%@;X&0qA9o z<$3Za=s)sDMyfw9y!o_216-ceZJ;fB{l#}nS)ss!pC8u=K>0i@VHW{@b96id6bB!* zS=L!9vnM|eANPKwy?UI1Wy0B(8ck>4qawnHXuQaaKA>;9tT3t%p*zxoFUy>p8;(1j zM2|n)iXIQ%s#Mv48T7I|g4D*RB@StO;z?N$81{R51hP0*(HtET4}9Cl`AK?!-+m-; zO{A;ce7GO^cX|egNJD-!vESXIvzyeSJ|wT(C7{DmgeRbo8Oe36W5qt)nIX^SYtc*A z%E@!*P6&#Yh@n>(ne&`Q=mwq|f`uO;+fBYl8S#+3>+p1t>-w;Tawo7+mY{1S7&w#B zLNQ-Tv7`DSaTUfA5FBAmXd^ogB5nv0oZNP)R8& z%G91fIKI+z5}5W`uFrv;{R{e%?)gsrOf?b$`3#lb;otW?sqs_Vy{dZv@pq=7t_EsZ zm^7R;LdnTo6!Jf9yJpbA!~~q9(DGp&e(`iwjp)ld7V{DD*d4EH(49lFckFOh1+hk2C%`xmPR$k5f)#avwU>TnnUa2Zp<(}mM9-%$>d<@~N|Z|2 zG@kuz{sI$I-0YoasN45a^jRzO|G<6qNXL2^JePdWYPW5O=X~O~)Merf*6Yn2k)$;? zbj|2j$j*&6UZukN!-zn<^=;s}x5mg)btc}bz?ijfn_{?BmUPJs$|Ioojvp6*uO$eJ zbaM-j6&audN=FksoF`~+5QUcwOahkLo?!3RZ%v~k(o zBiFJbxxy~RypabN!GTd6uH#QbE-k<9ef^5Pn83k7+05nzU9$UXg#hBoC|%6VeeZbd za+K`iV>(1(-MzXR4F#-6YVEX~$U>T8^4dh#y!mpAO?|&Zs$*98JLexHQ?$Gs0-TK5NkwRV18N!s|Pgi1*PV zCsGUbRgC-~-VmCp>V21q2O#WKc)450S8nG&^xMuHy z3+!Ag1zxmrs8P{99TBZZf)p*zN_AGh=}2((1T{~lBf3V@iS{AQ{e`v~+a^s9n^l7d z)y^x>OiKOIUCQkql)=HvrQL5QZY&-9Ik7fZGiW*^ipwY*ep&BsMThI-=X|VY#fC=D zN#cjrPa<2s?mxW<$AM6nFS$>e`(AxMa(qLfZNkHNz9aqUuL3_K$?`Io>S-K=2iSN1 zt#1doUkehH*`CX2sSl5#aXa*Lzz;9Vv+{FX?)|UxSJp%*>d{ijRN~E(pJ{?hZ)|%} zL{$S;vjerPRW8IZsOBeBLC0-MzwncOWR6j9v5^JT^ZU3FAGqtWz56+iTPmmARr(-v z#0n3_lAHTe*pXes?9BT<6dV>mHyd(;n0p^tW|zp@JGT9SVEo-GT+y8F6-)+g8|b&} z9P(~^ax-Joz$7HU_IlnynloGNG0Oah{}1#kGRD92%n3UEuzNr-|DWmxH{VFzf3oTh z7%cZ*xfp-LQVa{miS@mu{I)29-Ir_mIq~EQwgnacsmj_5zsxn6nnchS?r~aL#8>z* zWfiro0;2a~ePGnx@4vZoT<%NURVigP!e4%Q)}QO)#y^D|jM2x_q>*zpJW_%@I85Uv zC0dXbeIw=6>@kSJH#>s01DNM2d{3;(HUxLIwGw*1>QsM<2ND6Y+IJDn(GHJIy=$(l zq}jYS$cd)JxbBr0yjBT##NSmyeV1$Ct{7Js`?iSyIvG)~=;8t7#{8`wbFiuWU3*5= zS--P;bxj3OvVSGLA7dGjEr+8yZT~ATv@Fk~^b4fW_jDYOcsQ`!$C%KtVy|k9|JtuF z+|FBc41<)R;6JD={3b44WU>jV?Kp)Y1LrUDjU9a16gYfc9R<7$kjwk&Y&dWnRn)Hc?3I=WBvF7|sTI+l z`_c*NG1H)4BB8DyYVYYwQaUG$f-Gp~$s{}qOWYe_o_^F60pwwoB9T9+)1&fIymTDn zgYl8vsiWR~mV=$D08Zu!7SrX;kSzD#wq6GKkV4D|v-@I2WAglZ|WJidn{A5h> z7OF&g!Rs(IxGKS46@1f-6Iw*9f`oNZBBx%+`c>2;c*%S~Ajtt3&!u5??T%RHq$u{z8 zvy*Q$jun?n{Hu=8GPbT4B`e?4CR*yVGsP7u(~vL*ZFZR<4~X9$ zk`GulsL*B88ibP8=_gdG`K9~NL~A&eU9Vf;#p5Z^n#BZ-R5jN#;Z|M-EN)zEqD!Hal|4+YN zG?7HI5P~q4$ykMwjdtkoFxe1aD-1{?Zn!fDE|kl36X6Z5c>YqZeGF@EhC`LHe`hUianYd84X^96iq~;azaLdn8~}B(1_+@f{(x?^D~W z%&uFE+l`i7BK+Z;Xu7QPR|J*ptH#)6+TxagzO)cTX+AKN3x1H&pBp6JwYZc;rk7Qn zPmg0|98a#(4Vdi~k1Orm2aGz6Sh5pear9Y6a0FG-t93)p=S^hN=)eiEYJ8sWOY^N`xTUZeHSL zD|7FD^Mc((c>w-Td+h!;4kA6b)kvT-!8~ z;rK2f%$UUhpeOZ5$m#52^AJFX!E<;Xl;p$pe~VYz+&spi`4L#bl$!V!{o)mVD(-wd&yrq)UqVfA?-7xerF9Gnml}3ceBP8s z6WYDTJ8%jaFQ;fs)RC&)%W=MEjOLb>R6)kSi|M7J!u{#6dGljZ#x)^*BRlB~%Pq%s z(m)qfOhleo?KPRSIv`XU*jn5d8+z{|AlcDien%!F<*n<+yY-4!x9WX*@re!c4+8zD z(DSL|+3DmWr@>n6CRS1BJOuwQJ%;d2-&g7g zi~n!qon-NlTM5&GV6@`;9%xx7P#qH5GEUIIx^S?2n7B%>6KlL$GK~#x);Q0Fd971s z--@oSYRnn+LYSgijWa3FqCuFJF-}~_s=bt>&OMqYK>vlLdH^Ni7fjP+|Iwr|4dZD7qDss>Km2H@C020`C|;!TnvlUPxrNI~kU zdUemdrCG2>!9m6sl$p~#^0KtNBC(a|D4pFugxgnlx{-c2!0uIYO$zw|S=1!;H;6%$ zg`RZ*2(1f9BO-WX)NL6(}B3(WztXXcxNCsU~$y@3% z?)MqCAvZTDVnsz+mPtbCd=LiH2$2Jbs3rE8G*(u|k5jHlv<&Yh-?E`^gGdd~jf|eJ zL|M8axVjYUZAft{p69rURA%bO5(@0xoHBRE>7%WbZrhO5ZJ#5*+z7wrf}!q(ek;%r z@VfmkeF5&F0r5tUWP*NGLt-YiyQtOOhigOs`cFBMm@Ao&)%$HrXH+jM#XsSu;v1vY zK#Ws+NblZk3g3;&gbSb^^{vqj;SwgqmBfgVEbn-0jnR?y(OK5EUBzDbtojCxrX>J4 zwEhN?zxJ(jMdljwc4SJoo%?>?)u&eEq0YGkhz~oiG_vK`Vm5%~9O) z#HcyK7@7I%Y%4v^RDhk+O;D$57O#TWQEyY1U^e_?JwMQ{rnM6d*suN_7su>}Q7;co z{xj%RdeTL`u0XpCQgfqEHelS!yqFpn>iIB(R>4Y9TlAT8$N|Eyup^Uy>Ev>BM1gDk z@&lI#7YpyH83nV7Pq~D-_a#Tz@2(_@f&KS=Vpm0M2}zL|+IFE@zv-zxz_`8P$(Y|4 zQ3n#HQ@6~eVK!?P%-P{palYPFr@#g&!bwjl7&gE0VH*R!?+v;6nep58zX1J^f6S#T z9W$F5Up*N6zy4x5V>tX746?-yfvH^~n^M#J8@f%i?<&oL<8vdDW7JA)N4WK!U@Eg0 zExb%+VlCUa4WJK1g}V4O*A`st&To=RN{F&a1fEJXtQ9(xJ@=O)DUhp9R;B_05P?du z@b_c{Y!|3#3HmRa6arrV(g`Y?6FhMk29cAdTF7dz4F&io0DZZ@NA*w>G0YFM3~@-n zfRqc{RP4rrqCV|vL0fd@d4s21Q_U|dU2g&UID$QAR#EO$3q!uN^HEQbpk2wF9zN18 zD*Y>8wpoW{Fzi0K_nh(72fk4kv)ck3s9SehqbQd~&U{TJ*&Us(i}8}FJ<2gCv_8CZ zUcIFj+G+pZapmv&-+Vh(&RZ{az`OeBl%#Ar9&h`dGhW+xbd)~rVBYRn4YBEA8X*#Z zN(s_*4f{?G5T;vP0P_O3;KB$~s4`!ux>%n$fe^Rm`JPsqyLYIb^9@)zX9u%B*};E{ z=P?Q+V(F7SfBxma=)|Fwp?((m(E{|5z5EF@R_j#jq+l zagH#e{`^L4#w3Z@jde;}UP^A|A2i0FDt~JLgWn(`H0r5z-%A7dY;%UGOT{f(s?}O@ zngP~m2GIQ@FF*6i7%d-m*WW;XzI z7JeB9r@fnN{JY=MQSnoeZaMrDp1=ocw62TX>!q)s)s#2?i%v@ep_^UB@4A2Y+i1Tp z+<)=bztP+9z5a|w%S)wM-i1Xig<8y3)pRqz<#>TE53zmH3fS)#HI(}AicojsxCEIl zZ6JjJpTK_M82Hx&S|s zoasA%{$w?FEM=dow>?+_{_3qW6S4(8P#PZ=OFYX@fsWzh=+Z7Eol7Ui@>sMS!k1?jKYUp=e=uo|xnKSNWa;`2AnH zSZt#=jT@%dDdhU+H)2pZCbh#7X5C|vZWWFF7@~gnL{D`8>Q$h5t0eg4n2j?F4&i%| zOqcTbv|Lz^r|W;wNf$9>xQLYw0r-Qw&#bQO-~Kn*}rij9UBRFI7(83SP(RKLnc)`e?x zAnrn3PcwnDaSQX4ro8l2f=Id)GHEaVaI*7qpN2jnYTi592wC|yun|g?DRBOdz9xfKhMq!)hLqIeE_>MWSB-59R{=NTLQy2q^g z>5UcKh{8gHSUzc%w>tb&L&pci*xgO}ol2?U&Z4^~d{kh+fE?uX>uUC2lOY_ce-{%f zfvo|42iaYwRh9d3;D;Aw=GA{+ca=CoxFO8N%92YLe{8yf4ur(>GODuQ9MCFI^p~zor*@hf~6$KR2tL@g)F&&X!s(%Uz zl&3WMAcIMI@*PtEayX)#$d2qdaEP^T4}R|>_WW0#>dClbZ`!YtOJ?5w{uH3FMbNqCYq`I(b6WjWAlek)IpZ(n``jmR%>EVFmjl+7c2WM0Y z98$!;@6G}BRYefD_}1}HL@^jiZq*wZ+)~Ee#-V*P8l|(2PWCe$K`$_ys8YWLzW7%0 zmBL2AJ-&{yeOL6tH_}@YRGGi zwdvsJr(2`t5sE{y9sSMyq-oGn zE|w=$*#CBgnJ1lNOi=#Nw;8d`c!J+WY1!5XS>hV5x2xG(1O*p(^U%Gc;7ULJX$KSPj*m789?{VdA$gR z)4Ausff&foNA&4(>)tzfOE=0yz=dS6xr6erG9yx40Q&EeHD8~^N7>?Ylx~0H;N9`4 zTHI5xqN>DbpR9s3nj6QQnAQ{t>rbu7<{`V+jDS1DKdYr4c%xWf`tF2~PQfn-z#lGE z3TFCz89!9s_8-Hir6&}Jxl1KJA7sB0T-SqPuD??G=>`k%%O{?tbS7geAGB(W8T92= z3#fZDPZnV2eXA=3^Z?{3fS>LBDHmlQC1dE3N`+TyO!K*xggBWlgbNE@bu!Fz=Bt5i zJ4yfa-B?UdAbmzk#hc|X_2zj_Yt<)qm%ck)A%9<{k^1j?oIl49jfS<7 zwkI2dyU~mC;RgC@#-a7=$a#XSEo|r30lK@Q5%zwzeZ_vb!Et_7c@X%yx?Z~pnQRAO zrMxUOxfTD?1@Z)>>XwVxI7T5_NSF7j&1G8JY1vs(8;VGE$6dOu_6}#d$hI^r>w5iv z^{7BVDV$s!So2@FO(t9sj0=#5Yj}3UO)?n6sj}h9fUEo zs}nO1MbTiQJmEE0)EN`tFY@w8iVuZ_`~8rqz)NkzQmdWGQaHEmNLY0B=6+zXErx7# z`rmgQ{lM;Dh}Q58=Z*^7P zJ4u^91oG7&mE%G;8TfIPO!JzZv-AJ+&;M1oGF{Gse{ctnG@g0bH>p9)0l8vS-@;bk z{;&AS@WHv%FyKVFZ#jNmE3V4Ssl8K%HnyA*Gt0CMdhoJFnLNc(@?|(POf|2>Henw#%qJsW8^7x zE4+rJE}@!(vO~00ya>lz*!yr=JRu?zr$W zrFk?njP79Zxp{HFA8Kb9 zOD_<&2q55dn>59%#NH@Iu+4^6t#%)TE-uBp6N6N&4{*PA_2C+woGDh8D2LmnV}rs* zG$oDe4$FX78Ti0Me^~CA*+?5L2A}C4HcDXxi%EY7`F*dm0QX>jP5dhVd&pP@ZL_kW zrz@3>RzA_vUGjZ%a696angdR}A5vBg5u-M_=~z7}&uTmn0Z{ z4cSU9*=$Yp^3iCx3+?!jWfadEn^URgrhW@xLH}a=t~qQ}Al}_cH}Ozfh_w58dAJUN z=9jH_*`jhEtGM;g_C*Zj**AU-{)FL@d9OdBg~K)_tuIK{&u-q;<}KbR@Yk>OnR;Cr zXOq+FFL6-Ak?(l6%x6^l<0@(wkRGFD|S7{n9(p|A;oP1`U0w>t|zjFrLK#SO<)JrJZ$V3fvYWL+P zCc=Y~MlWdpW??2gj-O`gU}JpKyK2t2d?FHGf@G0J!$c21vxe^}XkxOE-wir{>(A!7 zhj#v2Rvq(8hns#v0WSy9U#r?PKY*L40V;V z>A8hr2Xn6Z;1Sr=wY(dnaZ0cE+1K0=)pz!zR;&0?`1)uLqQzfY8=4leTY>TSNCIw&YZB*iNHdJ0bRo(p#@_o)f9Vfx}{AN&I z7Scw^bc{w2{Z!oo_z#fBR20mNyv^W&I(mwwC(k}URoC3QkgqCjG}j`O4xoXQMShot zqK0kPl+Yq5w0_oLU}2`l(qiAYWK!O3E}uzD7X6;ugsHIG1*|WB7|Zy0rf&zV|7AIb zXvsn;(6IdU}^Jx{IhtUYMD=qS&ep1>+N#snb;o}!?9@uf?{v=uUnUB+g zWl;C%Ur5+$Ai~>NCyrtMEhXuX3T6Jg-m?9|`N)`xXdr?1>)RAHW>%XxH=Bxy*UP*a z4?nQJNGuVZo_E(aCW3aZCmls-Oob*?n2G7PBj%@>v$1;A()u>ItUt1f|MJB|??MgD zv+G6wHR=)-<=1>ZbJ7-4x0#j;qUqi{9wJvndUenbklQ@&dOZs)E zAUJhE{RxPFfW6ETV_q_+8-IEtRI%Qbd0bJ*SLk!kM@R(Z2b_}t{*$(8%S0LQjMT%G z8Y2=*X<#d&maWS4<0qw5zeXm?s|cJ!tMkOdIIvIR?T*VcNN<}+Oi}o$R#)G3%L|0+ zLTOryT6H;o;iyI1i%BnDDg9sgfl9jH)vorhT$mNsaz^s05sj=?(9YjGsZve9eER6q zLc~-ycx22WAw((vqa-CO_5tK`!2Yl(7g&r_PK{e0`E2=bw!v7c8_w%e2w~a+>^!{9 zXxc>DW%(zd8tL+Fr>AZ%1gyPRXM^}YbYfjR=}XqyNtIq$p%4SDOP;36@5{8qx4Vq+ zc>_YYTeW5GQJYPTCT!S~%IL4dErcJNK}VHhzJRc21-vV3@u_zmBfN?>DW*C}>{nQ1 zSwMc6D>pKo>>u%BA@-Q*Fz}bDw;p{HHLa3um66|9TV5F9pIb|;d%XBid5`JAqvhp@V|_8;W>PdBZxKLJb_Lnc;T2x- z1?z{(J00@LWWNHwlROYRM;oZk3=Q1yk5W9VwDXYz>*9`CP?1xlsjUabNC4lc@FE!f zG2Lu_9R5-5ox@nz&{U2=x0Y_41zudjI8WT~Iq6rDXEdYCd{}kot*b#8=CVN=> zbw`FA@DIj<2Knd1(fi_&uM|XrmMS_bF+SR58~!+BH=~)Tr(eWQyoI2N5e>7%pbR0KMQ2)Vn;+#~iA)w>v+UIjn+I zVhn!`(VZ^(huz)a!BXAA?_mUAH3%`lYmcf|KM+v(Fx@t!nXURN z5t|a2o>^1dswyWK+@A#qdps%R2}ZXZ3ARgtlJ4(Ib!itQ`@wanV=uyflzK#Ls zPC%c4Jr3Nb=j+w^Hs`ggy2t30qU9@y;AYQ7XInRHF^f4e&}Q1qg^;<8zDH>cE60<5 zLp#%?t^|`F8uV2g^%ZqJ=wFpzr5n&y-d|lavL)uabOq!o0fG$ayNGMX$L6kS?M`|6 zJ@gwXvCZjF3enh6N}g>sz(-sv;t%iubVU#=Ctl-~buPfJVszqQ&Q$Kbc*1rF5c0NG z6wXqY-x-MXbLe)CX)eiJRD1DtVes?b{tKrD;Cal7mkzAd=?AQAbmBM`S1A9zk7jpC zH8A>g0cE_hz8&K|WEi~1VM)YR5*5K;+suJVH{njReZ(45WFX-rgN zFV#uTXqI%rVG>-ozl+F5@miG(S8d2`)m?eas@r(U6c`tU{o>u4Xz$<(*|)Cv+d9Yt z&lAvaopfI2An-)WJi4zZs!{964BVP**fnHZZaOzNMHSSB^(G8kD{j1DX% zX0rELtV^;4v}Lhd`ZZ{sykw=ZRj-hO`qLVUKxBh*V%_}_&anxOPYn)j@xg%`qj4Na zvgbl9bH(S;>Z&CbTP*i169ztA`gKofI`(K)1?0DZ0g{(*FwKsiojcng$Lns`nnQYW zcPP{{p%zHdo%%Th7ix4(7pL~`;m|dVr9urCl?O;~HUnT*b4=G$LsD0C`tK`O>NdhX zCQjF&xhk$#y=m|+6W}B{7eGV~Sn|)FaBM&C=j+Y~MjYqI<}SHWj+Q#4S(DY@)0GB= zD1B>jFm#g9xUne6q=?$xbRy=GJl>Ayi)fb(_3|yWaAu9y_ZWjy614qcH8nkP4fUf| zvbA%?>aHz<`smdwq*yndCZ-pDMc}cZ<9q;gRzKRJs!IaFt*v1PDX&UIy~#xOKI+E4 zl+G~nNt8io?^lc5RkU76v)YwINAdXu!M03&kqrq<6gIK~PbLK>-I z5>UoryoTQ}O^jetTEYSWt9jI|ZpBUIcsiin2E&F#J{@bSh~*?OE#u;Mqv#^hFr*ZNH04Anx*D9Bh(6wXc)c)`QpV zI!(7L7hTJOclm~bk(1G*SyR#bUb^8VDRHs#)v`zQlALr*ZcD~eWk^tf*-p{tLqd$l zSb>4c2aN zc$nLHpc=hteU*ebbqWaHvj5k7 zk8P1J{uNk*b$uJszg6Pw^uA&d`|`>#visP4=4v*Ublk@ z_jskk4CA*-Yuz73_=Z;I%%G}A@2q^GaSZ-c{nSBwg{$p}!jv=enmwtT>7^1PE^<{r z$$*}cQEJazKO)Hfo_@D@#H=JxNy%Y10dIQ@PoXYv^-krP|Ln$9Q&@}t?JwY+gile?d# zTjOPIjE;*-wX*^b>Y<^-OZ+?aHnSl<5_mFoImnCQjS^$HeGG%c&xv#Q!-y0U0Xn_- zbq5S=7T@#VK4hebD7tP?4{gjYPe^wA7ky=+_~G7yNJ{wfhI~Tiu8VSV-4=VT*Gd{) zku)+U65v#y1&>_Ms2iUz)4VPy$wAl;O1T8&-6c>ZO=&#*=&D8N*3^+gws$QS$=i1Z zV4iYp{1oV+q_W#?@AsX{1?9@rP1e$u+P1-@JL|XmCIuo+49s?xfjr^g^Gz#L1ghFT z15+uSbE3uHali>(vYw2YI(akVEwgvfM`7yc_E|v@kJ38p(M>G(@Q3Wd18&Ug{D6*pi50(oa`RMcSrzyPks!Bl;d#kW3b3Re&A823?NrA!#Cxn z3S*{0mGRe{U(x<9bc39;r6&nOk6g81FB~#$X5a84-!|0dWWg8;CVn&GtAe}H4Bi?| zol~qoqwje#JA;;+bz@%A>U|?y_kz9lx@2EK=?L%KTH#-XX{xTOwkD=Xiz@ZEYTp#@ zySxu#CxANsR;I8uCb%p^D0`$w;2_~~&%o@an80Q7QxPFo~b=v#KPPBVP zRX95DM2t_s;G8plN(KpzjAmgGo9~)Y>7Z*Y}UY&jZS$u1N8wVQF?MY z6-HD5e=nW8ho={-!3E%w$z*mGVkIX{hNqlpG>AE(={%=>1v|88Y<;YG#9=;N0ra<4 z@j`-r1;5_M5VPg51xupDW|`Vi3YL%|t3jsfQ~hyQt3D&_szCzQJNH{9HsgRbx*q4g zU9iL>!D27Ir;0${ZO5t$AWVY%A}Kjl%}{u3y`FV!TGNnxh>k=;Wkbl+d6OYYqA!-J zhN}Q8WYb_-j0V{dn0}kZ^@wyv#UN(>xT84Rd+Tp<7n8Jx^cvhb>Nv((VlqR8dRyb}_=l8rVx=3dT^<@L+3EsySEmYgu%&6)> z9scgZAB+M0@=l2QYauSD%=M4T0*H1VRfWD(Yele2*FS_u) zBv73We^#C#jBJ-p!clHnfDf+KABk^~QtNLqY7dlmlrkK0tc&q*ZDH0(b>|#HNrRc= z(0H%Bfp|dP4(RRs=FT-=+7QJZw`VV}A=x0)^mZPTTP5hT92}b6tY8OYJPn?q5BAhCyfNc>m)vC+oQ+Qwk8TBa?nKL0Iy)oQ4^utJt5 zVpbvY9)=rl3Y`B;iASMWAwUz4#-%MKdr@)${qO%?`Yw%UZR({zhETys8p9+Nj;3f@ zT-xnevI^3Ly=hnxTZq?bEg|_z$h;^hLoBc2kvU4s@Z-PuSz_uozmQ-})55&Z6Rs=Y zfxT-MIY-SMQO7jqHqm)50OAM6G=2ST@67A`a0Uh>=5jC(m$81;$DHo-w#<#b)v>7e z$H<2rWXtQVa9UNUWNY%Feh2+4wz8wE%=dwCm#jX6`AI1U-gr|w52~rXMPpOV5Oqg zzGcokcs3Tg}9Xh`s4=?hkp{fFkPGyUGyTA?K!-CFAY5M_J&JP_?^AF*Q*(C9VtYp ziQHJ^98OW_N0u!w>EQ^;Vb3DVNdNwO3UauY3R_Or6E8?Rk=~(>zcszIREm4x#*v(8 zl6S5u(0r9V_Q5i-45560O7Pt*u0p?7`dj;Rk-XIBzAx+_oC3oA%G(DUhNcARGfF#c zG~0L&3#vVf6!q*J>Ii^+r#d|dl%x{$_8c0=KHDYHLp(#pu8^l-`x&x>`Z+a61NH9x zaFf7M2K9a2#REK?GmNG-?6LF;O2?vXs?8~Bj5RH#_BWp5=h+#xDC!eS#U-U%YLX-4 zEisGMEICxkPib#MXWgmNRzx01_FhB`k+Q{GtpmqqpywPOt8vQDTiV*$pK&4}w1@r= zH?>iYvo3&uFep*!^&>H>#OIH6S*;c^E<#H5;*a%Y9djW50sfYpdvBMLK-1eaqEvOM z4&iz(Cl&i{*zG8Wj=?g))Re^8(CB4JC+5i!Vx?zfJ0sOSF^s0=LiTf554Gr<>6)w*JuVqk}Ek?>cM^{l?}%yt)GH&?yq`r{3AG1? zOb_1V-}460SM^_W;D#&TkZUcTUnZ_N>7>jBKC!)Z`z8 zT1aKhiS^R{)HKd2-e@1hHu@-($rYqVEOd*2uLhxgE4u z@9?rgv%tjeC?|rj=~OnFI!g;->3D69K6!u}i@n6|HCB2luH*LZUOV!cM5Wky$bH_a z(~wF`vBU}I_^fb@+U8=@`!oZMJdUMlAPw+wz+mH&*-b?`(|MtGe4_V~GFHVL%00!{$ZG@W z%kX@9U^g&{Rp?`IS)OJ!_s;pyOxeRx^T(WJ_uXJ~;Kk+vHg>UuC2_CylaCE)7 zeh0)P>{|c%LjRlBB!Y{LPPNEqMvS>1kS^fpp-6wH2@bVIa^JEf^oXJ1ZV51F5tZs{m$y|f~X);P%f_75OuD(P~mwT(AG;gKK>O! z?O}$j&Z%p4z8F_fpjbHn+7&QA$r7xgdR14Uu9cX(IK!s>*TyVaHw?DfQe=y>EjqSI z(W89d8zDG;q`sz456|mVIH0fL&CCTooyRZ#HQyk?QkbD-9Y@(>i%F_((v|z?@Pg&* zu^KkF^rMFS8qAjOCg)cMV-4ChuZ;>MrlMegKVZIr1@n|PS_!wfm~>csh*O1g8Vn^N zVPh$X{pU}*ukwCK**{e`L|ha}6Pc^Z6z|Kc_7hgNaqsLEhFbNtXrkWI)Qt%{``70nQqnX_#x9mT8T*CWE1i0lYewPK7@Q$QCk9Q0uqg9;C;O_MO zo-Bq3`kS^AUKWzFAFc9D>HRt|YK|}a{(#62jF$G(4Be@B4rt);|9;uyiFf{{Q&b^( z!OtAZ6X_>&$+`qm|5K`eX(2alt9i&+)%z#V9|q*{K;Pl#N)5CL3#&(fp0ZVa3*9eH z%1S9qMx&Uo*KEFOxgrdxvL99JQtDGM;3%+`Q%%H585vLhzIL=3kJ<)ANf$_>^nly} ze+K%CSS}y>Br8vy>SF>A_LTWc8tqyBzFw0{q&?4RSGo+P+t_MP~C?dzs=E%y!$2 zdlJHJ99+;b^?~MvCU;cDv_Uvh>(H{(s`Op&KGk`uW09WeuqLl!2M;+QCtzQFG}t|^ zCynsHxdw6FR118B1q53_w=CGIN<@0)aT0ms^ckqXyR1CGmR1kty%wt8ImXCd0QN|l z2f^Y~Wlvhag%~WDoF*!FaN5kq~)*_maE=nxVrF{2jn~1tsA21Xwyk0{2)1AFQtzYWEhV z0vuU*pz|*jtzKlTPU+A8%H3#g+hI#j3GUzb8mMD6iZhKy?O2S05$G})*G$#WJ6HmL zM^ITe$Hq^ql!h3(J>^u#3OT$j-hIrgTmtVp{7YwhLV_Bbo9<2ikIKAbvC-sRE@}RRpJXGq;y!2`kqv$kq_dZ-(_VxxaFZkQraxa z8G5r6W-p#Q#<22jcaA)%lA&bo`tppS)LEsBQX?Y{Kp? z*e~EztI0{$I}HUp&B}(r3_j1wf~egV<4M7EDZuP=wMQ|$y5|G-Z_<+;?G*|SDOR~G z{#&%X3g|=QP1^ZX)t0jFCt7=I6;gT!_=PU$cKo%?E&soELFv11&2;YK*CLUNd^p`$ zK@iS*>Alqei-)elTO(6SZZ=dAC0kfLCZK7t<|0cO0NB@m*+r2?ZAJCeHsSAdX+by!J2@H~hsj#RP^=uKlk+Gk9xxH(sb#2Ij`*iSM4Xlk_b?mp;qD`&bV= zc~!ah&<>Y~I(@Q4ThKG(XziXGWB&BMsjKkK9(NFZpyUzZ04tC}_giV(3Ub5Zu$|ceI5vRc@ zI^$7gLJ~qY7sqGr0G1`T?;9T{ZL;A(VOuC|`Hnor*ReoM&jAcNyR-)_yL4AAXZB?Q z0&K(Y{sC%>cx-_$sN6T3pS6FGTi%AD_sZVF!34c}5u;ENT=JcIqBJzbC=7&<7Kl!j zMbrz~>t(M}m;XpN(ro_pqDwlhe~!{UJ^5WV4bQUW3nzhT13Pma|4YMN87^)mg7uVa zF7X&9$PH0bQP~jlD4Uqo=OP3%OG}VNTQ7TZNesc8D&e?O_n(Wc5A#^pJoH>{BS=H% zra7u?x)rIsbmu@l$OTI-Fv#?(++gt3X}UMGNFF;pH_V@8z{jKa7gYi(6alI;OLo}b_T?nVeh5rBcQec zBU$sn_kQKFb-ON`Fn3vt*+;n+{^(qXYv2_pspLihkHt6~dU#+}zCUt>p>G`|s%{Hg z%b%u-5l_GmO%KRB0DHa)`-9DTYaxMIE)hkkPi>uz_GoHLemwj{`cHSKCIJ`TOx<({ZIr;T<3*DDb+>~VhGy1u!!4)7k zV2;+m@78d9@eJz_Ex9$ryH}*=kJiMLN#yxW$4@%gDUlVgygnkg4yvvxI>uO3zZMe` zVbI~c=iVQZ_CzEGGs2u*S!8ccDx$Zb2L5ZVUhR2kIrMIew4|L|uuzeFl$$Y4Ufu+0 zkS&t9iuW7Vf}W8{&2m78!E#69YMoTVh=ywzpH%tA>9nAVaJ@8++J`hMa`7j*@{&KzLrLH6L?0`dJw z>iV-cqpxJu0FwG%Q+)dB7mfV25ZC@|=d8)TKGUvN zuYaPc@r|$4CiF5gAz#{g)JGd=iC_MR>X}5miq+eBMO#N_TyZ(-!VPM0Pf0;ROSUnu5n8aU_ z(Dr~d@EkqQ^AhBkM_>%HL=TJTivhnc6npblVDDe3Ny|R@x1a2l_mx&8NkQk8^#La{ z6&A~Y1T;4Mp^(p=%C?!n>-mCdwhshy%6XMbgZ+JpCL%^GKzTQ_qNgK(=iW=+RIsS% zCZ`wWngugm@Q-i375X8wQ778ndpBpuecvv-MG>Xe^z|A|wU;#dJ3>h^7FVZQT(c%7 z-AU6WQL@@p2%Ion&Mg0wY0tNHLFVJJ@P@PM?iSv{=09Pl|ioo1FrgE}?=S#!0%{7l@? zte~NjS{NBlImQ~T4!Vy%a0xTQqMDg_q=6Ki=zJnKo)q`yXUhilT$bRoU2?rNA7zG` zt=A=?gghJ&PHzxm?mnx@jx3Wfhb}aKGVMiQDpM)sie#o2sr=+OQhT#Y57&(|oxlr2 z7@i_UB2eU!>6=GKsZtLqP^0NkFuB~opUE}j1X-yju^raM56qR>IJ+tnM7`m$UsGZ#D%b_C+Hn2J*>hOs3YM&_u)iJ7ug$j*VaOAqr*SZS*8I z^BP<;VY)E(248KgeulSgtP~IOu9R>?Blc(4X?yg1!D;f>Ra3^I)DMUF#93ki#JPXJ z4?y2MFu$G4Sh#A8t%15haO=0-=8N11eG`XEijUX7dEH>K6Pm~U!6i1c4%V;jH^j5e zT?~7*a(>qxd=oD&?|`qRa#{ov_gE&4ugfVg^*%=k4t7w)i6V!=_q>l}5e?q=Ea&XG zHp)u^EZ@8+Uj|s26Zh0OOE3PbUcON|y{M*vdz|30=(r3My^J(nBkzIAjzikRo4c04 z$?9ZAC&>g8^+5N9p1%}?eTT9gsx#GddNUl=GKGY#QY3#eIMj|_S-x=_6u%_IP8wJ@ z6oQ2gG%$+)zt)|`O!D)C-SYmN{C*Xw#R$@2zwG7`Rd3yy8-?K&18PdR=Vzz(>iGuU zDQrg>rJ;l83*OQ3NKY(e!sj!%1iEt}nsUG}u%&9YJIH{V7O(`BxU9$S~rSch8=wfE*fp|jR zPfjQDP3$*Et+o#@hk<%rf4Q@6nyTehcx`C@J?dXpJ^T(+D z3mU`rDzrawLs6v&LYcuPZu++$Re}Xl$ztO3Fav&DC_vyzMw|#Qig#3h0MlSr8 zyLk;t=7+7G_HwK;&CZ>+s0sA*{@dp~k^u`kU|BmS7&AMJ%IbF{7wuR-6kD$9b?>X0 z)&F@$a(;Cd$j5;5&X#u!-CnS|;D6QO7g-ojp{{i|5yRB|W`1UXlig~-<3gpg=Rh81 zd8%tlI)vCv!KEl!F`DbtkGbwbj9c_{~YHRqxy(M76^oLUYl}$0uKZM&N0O7guWr5 z%T=%AFzpG7##un!V%W;4M-Jj-@!#)90`=Pds+TF(Am!si9e#qfgl8!s3Q3>ZzuyVq z{15c+iNK|iuBWX*=)4eKeUG}0`V9$d(r$gNG=*o8{dS>YWb4-t7Q>%UXKolyoWxR$ zRu^kYKejR{blNjx99>4gG0m+eSF9b?jfom6vfi*^5aCuz#=1{2lSx=iTQ-%N0erX7 zmqA-tE`wQg;RbmHV`wrvXc$yK^XW^tGVu*W!h)KJ5b$*`?X-scACBj&@o%p4e1_lO z3EzAp#zgJyo;y~}8~gwv%9K_T&GF6lXWOGwyV6M8SU{V$l}%dlrT3;J**F4NyvybS z0=8~TiBm;_<5A5R_xR`dF6FcU6lLy;zM}f*zfUwdZ)lu8&J1-CnKu3@7=jVmyEOr2 zG(P8hZ*WlG)92~jt&oSl<6|Cj^48~g>1tBym?k4+8L*QK$Iq0nN}@08E*UU&A+oH) z8h>V<;P8OG&4*phDnyT^E$tvY!wrqS%Eqfi6h?I>Y8Gowg-N`cDek@5c@xkIT17Q6 zRxH7oTzl)@h=4>{OO?e?*?V@rXn#*Y*RfT*CaRyFw->b=g6{e@;}BOXNFOzOHLj*F zn0!M8KaWAdn5i1_hWOS-%r=~mhkV?#aVPeK)l6@ZYafhGhz1j>Hg!v+c@K$`QbP9@+T9j$szYu$;W{`;jx+t6ORE(aiIq8 zj5^)6B|^}<$C-97Ol)BSH3`oAZbw5IvG)Kx8Ndg~Oi+Q)y}mek z#Ws!EV6S|>+MlW(VH#{K^kOT{?$ODnH$O}aQ5CoU`aUN`e`RBDQG}16vPqBC%VGfP z%zvn(xKhsJ8vr=~_&4JQ@B~C^F#Y;?2XGUpAE{6LHPxMEeB*v)(2do|Khy|)K&|{o z#WH|?G>Es!Md3-S!{|WV$Ze`Iu7ptC1^TC%Hadb0u`AN+m9qtVe3q_KvK#wN4nHQu zMmK&D2cjL`Wktd|k)a1syL+0=@IR#2pb0nioaF&}>hUg!AF4?!dxFFm=4%I3lBx7- z+=Pbnl%6U*b-T93N&{Fs~DhbC>BceZV~>?Atf{iR@m2YKd=`_bbWb zyZUdiWikFlHWfO<=L z>`_wqvSI%w+^q{JY9y>7snh}^!b}b`s2U8YDku{FlRi$#oo=%@jCQyDhNhSA*Gd$R z24_as9XWRq;Cqq4#udmY+swx~v4H(G?2s;A$IBXL*9G5-CR~?+o|ju;l7xOK!8d8_ z4((~ep7eW!KUL;f{5qp`o>u}z!ntbyVEgG7O0^}U=*^3tMgE<96MyQ=Fx1z=3LQR8 ze5;wmH@xd`x`RHnph*?os@7u{&^XoWwY3lMlXN!Y60|yW!jny-sy@veP!pw#b_G%3 zo(|QRi0R#C_T14^!zC^Rd6&4Uwav)X#TC(wH$nj4%aSes>oM&mWPa5CHuWcHn0Sib zupIKjN?Yuvqj}{|OeUX5?IgIL|6J;YFYm^o7$tn?Sdg*s_Qg0}K-O>b{FIweoHNHH z|6yy*lC+~UA0PPzCjLqXTT=<}7t&K+-vwx9<&Fs2M{WagJrlEpxK*FZH80#NXNP$u z&nJ@8`Z#%gF%}sDLQW{H0!XH3&Dbl*!WFZ8SJOqi+Tn0S%M4$5yLx168*GXkVPcNn z$?@@LY%H)Xrev+q$bQhDKgP;GQT&^K0QFX2?jG_MRI3kR2c4~J1 zRXR--My0nV{gAh<>JvYSne8^>vxI#uaTCw)Qiz^jvM?<>klG(SG~{T)e!ju|zN zlqK(EKiUj(vxJz$e%~9VVmY&nz_%jkR0cQ68LF4(!)6k54CW47|h+_3`x(5A(;{?2n*Oe_2xW`lPes>JXD zhg=O3Opu6M*rBdUA)A^D=p&eG3escGlO599ru$c~F7P!?ABdQYM}cd~7!6M&*3x~M z!#Ah;gzp`h^qXUCTY6fhi;k4w_`zwAIt0-}9rBqd@Znqf%NogyJA3w{1%RdX#s zHPRayty`0XkG+_5z~82!3;&#}2P-ga#YVJ?8MYO^{T$ACAt8f@eU-@g5goO|PiAff ztaL=vUdMgw?|pWi2VpMwrpnlE_t!<`;L1Bp>9aM*DpCaBo4rJ1dy8|=2qdgZULLCE z^-Z38jV#$Hwr}y)F-BV6XtPpmQtLd(U%dv|eCnJ(z6$qOop3ekVcK0>>90OwxU9Nv zq*tQ-Yqz`WUMVCqSra1*@N^ujJQZ|rMMes})?OnR>kQ&@heBSEStC@fYDA>#$y)Px zm;=N=&*wrp@A#($u{ts+Pgb|x$T;rX>kA^i)0=RtK@|ZU|8Vt}RHu32lYxv#747B* zIe_{@?m+3wzDM93kD-Jdfz_{4ZR>sCj%C`(U3VA>6JhG&9iPMP^|Q zis)PYOVbD&lyosj#-wfOO7hUz-TJzCxrQutzb0Ya1x22>Uyr_crp`OP>0I|`z*6cC zjdN$Y2}MG4{ejBV`hVoTQ+TCK&^8*|w(VqMI}_WsZF6GVw(U%8YhpVSTa)ZL*y}%- zeZANB{m1)st$weZW;Zp47pNR;D55Tded+t7AxL zS@39v7MYQa)eW|DYJP=xS2tnLVR-tLOFT$(*`KHjI-)xvq5RKls=8dUMq5Z(^smYh z0X0@-Zj5lw14y4lkrWjxic62_1~S@@f7hXG&Ia)B&H_lvYne4<1bWYxHiaLSroLW) z{fBZD!74O!f-{+Ec7r2_i{88OtCq*bNK+h>l}wULHEcn&R! zU7{&)2&Drq0q=T*7pRs@x0I?hJV_?{;`L1i$6TG(7c(k(DCed{1)rN}*Y84=5?EZ5 zWJjuYf+myVJymBbW0Hc(5RKhUt&ui1(}tKo-9a9bH0>{HzB5nx1dRHt*(5{BrDqV+ zV4T^2Vb!9kzTOg^(~}oWUQBw+;i6|qGY3ok9!u=7;P`RuI*j^WOHssMntmiZIy*kA z`yvVP8&D|}{EwL%(SI%GO1kOwb>25{n<|tKid=BsOF3Ez2nt;(EdwmbY7;|#7)q=Kv?&mfL&d+8B}EW6 z5)P@vHSW{_gXszo$yU_UTjul54f|Hc?1VTVsX?0BSw4yvC{M762tQOcy!}zatWKbFxVdCOoutqd zpuOBu1cuhZ_Dp9^$HiW&BtH{oOQ=>&%?7MLfPVmRKL4M*g#S0LUx#;4L01Jm-7}bm z1AVqba>7E&-Z(c12Z;YeV27QW_cKy=6ZKG3JFAfXZ*f@|@ar*#_JUDCG?gd1oLTxP zQI1QwkrMPgM;8Odar!bW7rA+Kp&Y~Om1*T$ArHfFVX#X|G(<$4Bf6rh_Orc;R`x(= zh}LaV8L?3zhxarS7!?d&-f;cz*u+u2qs%1~F1>4b|G02S(~8jbr@=c80{1ACUBYn` zQGKqQ2%u~YQgL3B$>ZW}&EV_cn+dpA!%h5&OS5qUv{yW_z6sA)AaB&k!5-O+Fljg5{Q2_T9UV#pObSIcE z8=fD@#At8Kr3yim6U>gXldHi-b|K+=mh`_tw#sYo(F%hDR;uo{XxA`=xMpcQ7 zrwtw(6k}E>LF4|Bhum(uXUeuem(1GyZ=va?bPxRqIHkXhx9bc6_wa0XOd=8tYAEO@ zr>sX)It6!2$6yTNPBofL6Jo-2%GQb?aCr7RhrsR)pQ8m!FIm}>!^cRiwo2lD%>|gt zXz2U%6hn988v;60`fzXhKPrHHl}-iRqt+q_3P8X0EOVU>k>7mj`5~kWJ!NtdaJuE8 z*c2e34lvTrut7Mt9(I5B*NAf9PO|a~Nc~zQ*K>q@XMe%A&;9H=9N!)w;hUFsVVL38 zv+;!BECJaYVaK{UBiWV77gvbX-)TXGye0jn;LGy&Cd&oYR4zK?kN+xqv|;%i6Se&j z5pmtRI$c|MaIAQ5<(*nShW;Y-Q~H8{{lHj>%}-I@nO?YqSmi+7b5jm+qZ%Hje2t0O zEx=zqNz}*l6JNj?Yad}fk%c4VZxB)dV5gIW@f95=Z>D0^sR@3ap<+_LR9)Mt83c?D zBv<7L+C-jrkymTk#68amJda`Bsgw5Lhu|z0r0UWVhiVMX+#%`P<;GQrzVSj>2U;{} zIi!`@c7P`h7R}K|B^_ZXEngcm*2kr)hom-Y?Wj z*%xOoMm=nCqh5cCMP~LJ3TXMmktsrKZ)T4r7Td%(*U;NqUVO4kZ_11$*cqkS2u}L? zyI}WY*&k*K#HC_bwYoU<4VL57lZEqRK0D2n3AKUVTCcxv+r@NzUu%%5JU zW=qA8Ld)Ys1?zM5aNcvi<3wU>yo+-F7WA_`zfIEJ=ikiucq3qEiDmH9DCFT}EojQb z*EamF3|+g~F_qW2%;GP>BziXZaBr7IY!dXdOC+c4FKBQ3 zun+xEqQ+k*@5@mA?`5zD;P;auekhGIoj*P3LWXX>N!^P$5;OD`k?QdFN^Z96WeK}U z-~~44=6*NIUV%*WfK7pO{B;v;4dxY)l(O#PyMs~#5F7Mew1wfZld#gg3_VPsx$ zgVk_k5+Klf#Vv_>grU9{x&K?gIiN1~?2Q6))kNGZFX`fP6J@&2-7Y93?U34S(dXl+ z^pcY`728LR^#Yx!#x{v$;vQBdc9i4*6`Ga;u|cZfEn@ zwvIl5ZE5IM9>l})Vmo9U>SBU);FgaBg5BwOFpu7*mV13t~|&EXHVh z-&}nZ!2o>6=__wp^X~b~jwn)MQfY6avDe?|ZWL%G)w!PG#7w+S;Y=`pr(c>VO6@D~XO}a$&aF8*Ylf9i_*5wfD-j;lK{1soW%HGTl`A)PM z;yUtjgrZL#miwIfGRVd(iGf%fTyviR@qT8mpMQb7r_P&(1f88v#lLU}f^Tvyvw-9k zk2>fep}Zp~8x2Bw(agCt$+d?}mje%fvGZi-e?~gh%-=ZUGXAmdV6d#@a@R=c?uoMe zMPIJ?jXd?&ZSijmd{_^ZorSfPd4@DJY20{(*ogir&LuvrL`ua=r~%@9U7k=Oa{|QOv(4teu`lu-v^<7GgWoSS;)BFbQi^`- zYokc1rhL(Z-W&q@|CY-^u>W6K|d*-1eRnPRWfjmdi%b z^#L=u7k7{t};?ae-InXsd+ zTr^ZLM`tXNU(AElx8Eba3s^Awsnly?jwvYJ^nfe(;BVTk^_AR`{mPQOy4Md<=*LRd zy1CRHoosBu-=>p_aQBl-=(JdAn0LvLKi> zvmHlmNz!?29Y5mxrQqFH(CNAwIO*W5RoZF~$PaA~M$l-D$tY*@fh)w(93=h$UXYM5 zV2U&$sU)B2~zngGh@YX+@YnYx$Ett;>3hLs$jo>h=-o<(uS*pk#* z>O{L^^Qin0X|2PAOTFw?HHAAo4yE6H&S>dSZwvH27%zlNbZPp$N)QkB(PiR8RADDM zjVvBc#dUrhOcN21k29*($w?78kO*m$NPa*8ex@z79ROY$AYdRVzQoNy`mC;@dQVxa_6j|Vl+dz&e!MCSwcSuXsF3u@PEJb<6+f6DJESJM(ITv6;^>K`F) z5WEBVuXjtSA=o#HYOY=0_G|`hW2imV_m@g9M`to_&au|5#M(GaSd{f86}i!XaRKj` z{wIIR|6krEm_yxbYHchg1L8sd>vswN@BM%FsaJv7r&VeY!=-qLZ@1-5sm|0^y1f{X z=U^A#W2T2(4%*@Gd6-C+5Q%wFlV$g}O9`-aA zv{}bEpXpSxKVU42YlqqRYoE$KC05(QEWdMC5ewHFh<4vfUY32) zR8?w)UE>bt0~;chpJIta5ve>ajk)2e_sS6&maIFhZvYBbe%uw*4nN3taq}~)nd<(d z{FvaZUAQ%(9sTW=R^jEboQ2%FSk5?OFtaB3^|%Z0KNU0k?f?bDhn-h_>XnR|47;=e z*}-@&%l*7IDJyeVaFWNF(Hh6HY57sm{(Ly-*x@qV0MS<#25U&{gFd3!M@Bx_xo$*} zpWiwB#Eo(`pD5hid_GL;1D+e$2CNLs+kTm)IgE39{^1PQZoBa2T%WWOgxtFcwt`ka zQSRftc6~i9sry9spI~@odiE>Tt;#E4eeDkJ-s)5{QBr&EmO9@0NN``&OP7amahb3E zh=?-b{xdk3alA-;$wbR@g*sFIh4h}f)&KG*0pdNMH|SlKcoLrdI4Mko$H9&}wm(sq zm(Gm;xBeo?mGtMzZ%`v2IeKcoe)foph4MtjrvHiN7;pDwq#|b=RB9)zPw4oAJJ`?5gGkDq4YbY`zlTw`}k<6BgrC6h)To z)8l!BYDLEntW`C-?uS+dG=>r6RV;1f#uc^CE(2(%`&9>4fmYr&95y;^1=2Pp1N=?~ zOQJ_54q<~`AIO7+1Zwt7$nAoV6{Wy@i|jd2^pHSg1XW`09%)=#DdZ)60h@Uxz%Y2$UK;bXPwdZ?uSdS9&G_Qgu_k7Wig+1Tj(!@37X zPNtFgrKT)sa`8t;SyzFof9AM--Q!p3ntOOP&ZW(T_^EO!q2w4$iYff=vrKQ>TRE`B zD0!feph#kM#|*WuQA52S?og2`Y6Gf#w@of%$0*Z0UfSN^vw$azL1|e*&^>C@{x!@P zq!~cjhbNdeC#UaNL=b*cK?TmiMQ$UgJh;&2LWHGWV!(~x_CBR#IHB25oB0@O1bxjk z0JLm~wZP(&*k%@#ckL?f@?4-b`2vc^%xdmiA-^>OH@{HJhhXUY(zdCp^bmzT?uEw7 zAw{~R23M>5&`8ZSqkFrD{(Z6yO9N*AOh?=MTa_+^c7(GkkiN{_ssFX8dkWY2EtM&; zuW1vmGWTGd?W(w|Ml5h-C<<%5dh$an9pY z<>QNhSz)g2Lxgxd4K?e{eTi z|D4!1);roMJ3xM4>RAW#jeg^SU(eCy8*_Em>Q+i(cp@UU#(AapXoSdfUW*ry(^b_0 z+8qgva@LSDjnykEyF4rQ(X$~$QQrlu3oo`vJG`R5vr?d#>h_uBnC01(LE+ zFq<`JKNTUVcBcN*Ad8MS{M!Rzk`@i;@?^Bvq}d2w&a}654v~LHv^SOUY_??&=aF7; zzZgWc|D`4_AsjvQt~sD}#a%QRMh+uBE>b@7sOu!p2`U-4cTMV6za}ZX97w=(b99Qm zF^B&RP9Z$NEL0ikm;dkXR+rVx0o!Gcq7XBFovafbQBECi3&b^7eHJVh2*4#{ydxoprXu4?ly z-)_`=5KfdJ#r~q8dBH|!i@|p2^56n%dQ%e<@lT}Uo)@^+KtQ!;r&?VmzfjpJk#(>6 zN4v^lT!aLA0_MprG$pkxZ?oJZSC}q@SsG0K{bedcz}Mf$^&{Rue(;exL@<~=)NxPp zG%cGNm|j`3gc4p0Ct?ihVmvPt zFgOen*gl4s#Y^1hM$Rcd?!@7D`cCamLC+6-#piD(>6lJ9s3dgA3_lLrXzV{!4r!u~ z@Zlaz>~<701`0G}_>$3HTZOXt0p*7S+AHXg$m|5DoSKte5X~UO(1f8}ju0wfZZz^~ z7WHSD$XT~Zy_YG%OHA8nK!6Tet}xtJBDBuU`4R>EnR*9Z5aaopkg=$^VT6>QBPFPP*j0`tqCpX%Sd{{ICTT)US87 zEUnWdSx2q-OS~5CE;K3hzydV#ZjB&}ZPfv>Qv<;{j{BUb&CJAk1mWjB&f<7#Q7*du zqHowrAxw~QpNz^geyU0C2w9)6;zs^X0F_GZH;iHxE6*u{6H`5w2Dn%JK6_~wp7kHj zb4J9AMh&{HT{=_)b|~F;H~40mQ~LmU45H8&bAo3c0OY|n6tjOjIf{6vK)m@B4xa$O zfac*pipxH887{8sFPxZ_JySGj@>#!?SweCECLjyor(RXk5^w~X!sUQD%ae_T`GR^d zuDtJ`x_VmsUaZl<3a@L?gm|$0eL(vkp9#K=oUmRfA6W4TGwp@8334ojqZ*?N^La{C zN}wyg%mqmL;1N&RH0p92QPziq`Pyn1YpUxpYH<__pvD3rV5md(5^r2_grOYtuj{XU zoJxQ67fV!usYXp<-Zd(8vUZap(I<@gd~F)Gv(3%4UaPq@w{Qou5Uu;f!T0*CpclD7 z4};s2(|IcRr2WGFw|+d}U0o)%qTZe79dS4h=yvUmh(pKklzwOPTIqk{xXW5R{3Cs) zTRPVB*BDtgK8`~E3*SLVJ8PS_Krbst!GZ-Nr-vYSx0!Z%LHQ}g$U1ETtx zl>=^F;k~Masi6IhFtWNu!*w2CFb|Sz2b>SvtxrHv~g~Nq%X+*!U zB=OoDkVsWhqpeNu)yKmDOiRhuZ^U)qF@htVn%J>_>*fIPBL3?>h#iyzr#%WR_@ixi zO6_t*21=#_92oPwo(I>_Nta@-5MYM_`e9PnP%C~PaG>}LKp(w!m1_7InZNIeDaVjFO+2&r*5QoZnYy0f6 z__LhGrTijNCSbySCNFq_Mc59^~ zzzt0NhJd=ugc?KBAM1N1BGw&5g)ST46nd&o4# z*|-p3HYS|{{qeD&&6h0-I`ez{L}zt%hf2*t#<$ec(M9v)I`WJ`pCd;OcG^|)gOxb$ zeO%9hDVI)~f1H2lsgf!H+b9m?N0@))1Lhy0@;8k_H;QFBF+r!Q%&DjMf0ebEQ+hU+x*nI2U7et_-P*qBiyt?q)I^ShmXLUj z+mcgTu>zbIU74)ObOxEt>0a26We2~EBG-W0Zdvkh@YFqXxvXJ)PqU=k8BnA-YakRTO zwzbkiT*g0A&B#Ym_ ztjoI7oB-*3(dy+Vtac271h7Ga(&Gh8W)k~9rK-FIC9Q}#k-ytOXN#qYjIQl|kRZ0% zCaq*bn=^~wmjvGpDqbF^49^Ps0PMR*qJGBlwdi9djCH)7Ad@>zjfgM!mdisZ{$2oaoNx z)*RBCor+zqnF!t-@9C}K(;JLV_LtjKbGExz^QG^=H2peH;je$|_Xd-!8B?yj-LA5< zoQ<1_2N@(pRY88RWO) z;cnpb*>s*PtH_K8;?&HJ?4b`pFfOLmYVDqwnRs`hWF@*jPXJ7S!L!>MV;k)-1g@%{ z=ZF?k+1Lu@lYs?)t3&NDJt3&5f&T=><#IVdU&wF{%z$m`7XM3M?jsHjF6~~cggT+j zkW()BY7-Vfv^M1S{?!+Xr7|TP%!qH({mPu@9xxrjLYIAWojJ@HRZ*SwI}t!%?md@cBELcg|J4@< zdwelQM`Ih%IwmQ&zlk;geZiP9s6_j0U;Tn}(N36_=tSnB6L;5fpI|>~#T8hbx&Di4 zJU5kr49iALUqmwY?jOiYS|o4HLk<(S#IE;2yZIx`Zc#xNN7SVqZY`cg7MlB!5=bfW zn0_qbZp%y=c)=)?=JbvR3`CIYEs)mPdYn^u8JLA1D(N@EiV}?-nYl7nc~ku4oZYx~ z#0=23ykdelE?$j+0r*6B%PjVa-J0B@uqJ11%1LGjw3&0im=+*^(#}*0Utyoy^Iv;# z(_@u=Erk63y38Ngi%@25riX%!;{H~_#PeV~MXxOfm^k6UCqQAZn`VC5*oj(u!HcEg{@>c4f_@&=j>&|a|JrQ?E}3GH z21W5v&HcQXEQ*qL+FEhefpa;0ml9;)BIKjPdbQg2Q#`@2rvUgv*p#Tyh9y(yH> zJR9ol@DJ8MpbhApy#ai`kO21jf90n(+kj~@cA)hL&&#;`L4v|#tLJQql=&l`vDp2> zR9MVfTIs8C=x|jP;qhO9Tz6q6rPDXEtg6#uUMj;yl!a@f-qZ;$PS|zhxiWu#@Bf(= zm%L5ZPpWq?nUlI)zNU+l9NpSWKpL1CWa;vMYIIKNCY?v&2(pr3@} ze*`7hu&R)T1MJ!V+dNwUPH6U?+07((2RTvy)j0G7!cU_&?+(9QJEl;q`8$T4ns66l zN0^5c^;_7k9TN53`$;~QMuKrQ{c43I^1A(5}e2Vo@w|M zFaE)yQb~yvEmjBl5jMkcyiEijcPVXJGhSEM`jn6Wyv3(i!$sXd12t+c797waqH&!n z;4VO1?B95t$yc8!OD)mBf7RUt#BVt3k(fpKDM4##q@G@WMkWH;3LdH`jHsB5IfSin znJy=5>m9)SBCq;)92!)fi+@ym$Qj~Y!+@6Q0pkGl`M>l7I~0fCtJLBOb0d%B%V zg77yAm9WN|4vi#C&+VzTew}9J!s%uq1phReB&_B9Z&OPFf6h@lK>q-KL9!xMdvw8y z{Hxy%sLQ~s9%kA_M^_Yf*v*&*o?9B5K${GYN9+?WagqvZo>M)&W+wuwag>lh^p)t_ zac-X{kcsi`XI<1f0??(brL1A=cg&uAXI$w0^Fr3iwm2=v@Y2wt=o1`O&BNovA=4%j z=Nn;Irh14H-L`^CSwHb&Ru z8k``9=l9D>YA{F9X_FgTTS^$Wr5i}!*c27rxplVSh;OU~&bAtQE~YXK^b^oa$MMY} z8@BN_APds)T;A)lPTp^e z1RL&XN9_K{VDFGi`al+N)HvVJY-WK7@-Dk*ymA2h0pNZMz$XPW8{!Xv1#X_q(A_!8 zpBsp67Q9d1)qFy4ym{5it$?EFB^A7$s4zUKKTV)YwXLt0Q&+(s2&Pj+dXe1kuJ3Z{ zsO1<2Hi8I~z|HP4KHV*EVCk`Z9TTfDzT;;bT1mZ2UiPj3VYwvV>u~X9&*}zm){V%S4RG$Sv@#IdA^jKpu?htlS7!fTWeg} zMwcfRt~i~KU6Fa3mXUr7QKSlp@}|*{*kj=k$D~GRkmU3xFk2x?$;AYa)F!k|4Gi z;{)fV|CJ5g3&nrc)8D_q?l`HAc--*p;P?PL{}ivP+& z(RsS^flLnYD_vj4yK*9SNIlMI2L)#pP4StxB$2BoZ^-i8C)T#mk-XXf0Ufd)vOz!< zsedOGCra>-bz9`bPD5amDMwyGi($DlL=W2s$+!Z{Gp0F|{6!M4?8v!7q zd;^k?g13oe3vV6ffTQmA@z4@{C0Y(Rq7{LQ9lCduDWaoW^7#rtyPksII;$rrxnb!* zYd;^t*=2cy1ji!mobunko%4}@$pF4{>Ugv$>4T;eS=ucoRtPc886T-V#|CbkZHpSE z_2^U;5TT&P86U0%)^OhylQDU~gkqZ?*Rx~=e2-H;?k1Kb=@Aro7P<5OTgo8#Z_0|P zwvh(pYd})rE;&JDucN%cG>lWw$8(*V)2q>+Lb7yp1$V&rR*xWw+DSSA=3$d>(pIpQ z@MwQg)?tTumK7#$HC-UI{0UhGJ%;(=0CESM2VsJ954HN@QvW4?iW^@)%i4uTQ}@Ck z`g0rn2>DP8!j9GiX4H^dJeB@L!1xkmSs#ZLP$B@n&E5FU5O@x(GHHP&+TT3g0or}! zO%v|2qy^L(J**5i$(r6uqD~osOG^O0Q^lG%)ksxl$?DzQWrw7x!J?TjmadH`7o!gB zmZ}b+|GvZc5*LPZ4&dXG3f>FhoTVY4{|Rl!DC8Nb;+omT$w^DTr$dF5RdA}+o)L}~ zkK8KND&Q1FG)^n$bJ|BgBg&`dpMY@zaz?-n%Iv5sbad>|R9m^99g!9J{lY+^QIqJ= z0h|U6_W!|;1@P}*Jv`2o=(biofk-HQej-khyaezaa4w8A4PfGYl@n*}>)wAG5|;+( zTiuUshCT~FUq&|%!5@vG!(01wc2&S@sJ4~aqLN?Y(;(DmCoVHe8I=`;5hey_56!wxKVF#?Gf9V`v0{`N| zaAy3MP8#+P6@Se^U;v%x3Y4Msk|#I+(#huh4g%tosQX`Z{>%RqmP~6>&lDqsr&XLDY(&7$sX0z1{ zM?aS!zV!JbDCwaDBIwH}5XN9Qdo;20m$gN@3On?PCAKzl<4}V^SHBK9h#y)4Pv7BS zwZJCKc0YW=|FpA?@0WqG&SX@RB%iK39!Y8e=mM-O0NyfSef>}M4FI@$e_Uk<94q-> zsP2uLpeo%rEuA^zLsdmhlG4&wpD)-WHB(V1HR+TtHjiarbk^NZuaT>%uxpX7vi8KT zTBl^^Qmu&>NF89LTaIF4R*p0Hb}_32u1Tnxegh9*wgTNml_=TDR(?{qhsmkkp6iI^ z94@&2f`H*I?%7h2O<4dR4X$(Gb7L>5M7Dq2H9oEJ1&pUV#Ze%hK4+kPf-{xWR}i$^ z_pr;Tiwr^klM(B7vZsIK=bZO%n35|@_-sst5^WaNhyfu4XXPocZ>YxXI{LnRyrpE1 z1i^)fXs1V<430Jg+4u6VNmy4tk>=G+c#uMmO;v3;eA8KB(>V1uJM~2k}*@<~mD00vdS`s2+O^G$#=$y=O~>96h4dsO!1| z$omJDbg%@+#0cCF3X6zuXf(xDC>_{sFUeUDItFmw&HL3h5}BlLy%0E93nWjYGn|fcX`0SY^mi zwI6ZtbFd{lbCSCvJbHHZ#Tx!rW(vKgfaugVazkHpTMyvgt3MdvFy`P#kvOU)F5}cG zSan}HCAu@u6V;v}l8^w%Eh!b;i`w-d8Xz})t3s8DKQZ=&{OTS-FzY;k-`_!~@MW}v z*x2QDB{-FiI;wiWhm58_>1S^FAGu$aQ!lJW<($mhR1vx>b$vRRg?XG6g-A&5B zf-buCbpwkCS?$oH<^XcjG%}G{y;ejcoD5u43!44K)+V^0?~Ec7a0M#snyuRf=x6{8p*)g-(o?>=YQrs}og(Kz^R{aiV+dVTH1Z+QeDm+dnV(z*Z?)qm+%3gNJC)7p82 zhQ(@<)*%s_yDOQ7y{GE?(WUwG%xD$NX*;9CbAhF;9t>gV?10kY-+4^!sz1vmHsb0| z&r+sy8C+ANM$eJWa3BHZk+e?_YoHnC2bd=;s{;dR>W+OSTWvc&#bga&9Xev1mmgP% z<`eiq<|3BmS3nZ~bm9$Xyj$_KHyp;3{8`rh(BMJq^60AC^IwM0O-$T5U$F&!Z#CR__bpj02|M8AjhzP z92mEQ<11~Lr$*W2)f-F#jF>sMQd_OniX4Vc0hA>{XmL^9jG4h1il7US6VmAu0$aFF zbxgE|;V48~0}mcQIepQVl}UCSDkS$&lmV(_ky^3P2Y~J{QCMgr_F7pr{Ck7vyOkIC z)k1+UJRQ_ovNvtlF8xxun>A4{N$5wY07M8-%2*LO*eK4O-Tqqu-OfYl7F-(6dQMtX zLF-bVBw4|e6NvQIR>!XI3Foh_#5euvEd^IvBn8TxFn<=2V8=&_0?KFpg_>6ruMEgMenx9_ax*q!1k<{F`Zk^G9xl;BDDCB{_g@ z(V7Y?CA&n-g*lSOp;f4Fvmf)5y3rp5%S9!uK6uD0@1y~3>DjQQ3>q1875J+Zei)K5 z7A}E{0J?R^d3y+4L?-S*`=g* zQdD2iHEpjv;u<6iiQf{U%1P>RYWKAFGT7RH67tiaW5L9tM%~`qi1xJpn!R1Ju_qNW#HNWgr5ExL1j4pRz#`@J>H&sf3*b_?27SuhE1 zI7zQ@zDewixUA9;wh~GTWbeyCMeEiVvjy7F2;vULV z-)6VPk(pRWMmz!y=>I_XrEj;a{MGnR+KO+UG9?AUZLYe>K1+v&QN6c^#fTieyzCA4 zRngKHvJwJI0adAxie=I+u3F09a?yfLw8f`hGg{w-JbXtNCGej31rjm7#~8u2j)wvI z_er5{8pcOSEH@SZVhlIujGFAz%v23;#R`bT3Ten>doRA0)2O7Y;Pn8le-QUytG8J# z@0xZEy%%>&!M~2NGFzIUX6T77pV6ADWa1yVVUVF{*@W<|G7t9jaupliTlFEqZ4hI{ z2kakCKhWKZNnir#KB~NaywJN-Iw;Xi(%WQ~93r%p^#n!DA{*1xfv9-9OTOTs_O;Kv zSy=^Mgqkt{&XWz~PU>4)_Havg2}Yv>?8ZKh&vzAx8vk+fTJ>6pCVOenbJcX3@+ze6 zG8&Ia=0_U;#_3HF8Pe&8{R@TN0#m@e`3J>=jZ4dRF75LAZlA;D_4eZWD|185tK!?S z!f$X^wPLmm$Zi}?0sD5GS5LSz>M!XY<+Q-hhxe{!cJ-X`5G(z*{R`@~%j!np!2suq&F8t)<$(P?Ka>6+z6pSYyLXwM46eiT#1Im8roN^8x;y1b z1h%7FNUGIuNP3=Ij%oa30N|U-ru@^{s(qdb`JM89T(IjAb=71`mJh9n4Ygg^+r9tD zS!ah+>*NH0Z>-OE)3_ctRFI*PkI zgfyP~6S$Zj#V;-c^tu)w(0(PP`E`6AjsO~SQ>meYLeKQ*$@NVdJCAvh9X)*ekL`W9 zr!vYu2{>MHw8k)!MW&p4dvZ=ici#d{5p5p%;;m&Rdc zeL!bJ0sP;NG~>T~lbI!xD24t8_2gj*X|;f*U4iS}t830V-$`;kp2A0NWi|G;KVf#6 zDg-@E6Qt?$EQ>sDTd5sZ(UXyvLBI#e^f_eN93`J*M`g!@jjJk7-Dvr)eLVkS|5Rlt z%CoI69a(SMc{oF~PeVlYH{^}z5U3CE;{g1X0Gx&{nTxFBi=66z{k^8!!LdHvrCg5d za(IFlnTzFQtOWApRr`ywr=pw8KDbeuK^}%|h~7!_z;4!iGsF19eAOD>7y5|n=kcO_SCT zVh8~AfZPpi&fNkoxCFIx)^MV*GNR@OC53}WA>iKlKh^mG;GzKDmvqyR366&;y`IXk zX(?Ipxr<|=jWMjZxMyx_OKndamij8-iV8QShRn$My6&nEGDkDgaCle!8F_9C!L%d7 za?&;YC1e`6Pi~(wrj>vP#bl*L;LF!d`c@u{lz|D z75hqLuofkfqFYCXTMj~%`zNpv%GCg${EqQ#7_~HcLREdt2g~(>;==}4Wvx|W^1hLO zW8tmd7-Ab%yB$);45@!to#CWElR0{R5MKp*OO#73GxK&qV!Ukb zkH-bA0?L(DNKDA(mXz4y^2km7Td0DgAYNJWh&a!TsCSGhBs; zk0TZ~uM!q)CNfOU<(+TmXHax>LOm#@`S)AAL+r_YMYOg`lZv6X@k}YiT{U7~<_W)Q|JV zO+r*&F={@kmD<&Fh4PShNjXC!&FVIGvdJU|{NN=^s&9@`*|sBfAwS(d7zMaEJureO zBsYdS-@$!(U++VQ#fw8GZgy=OZL1iTXey0=CG;PKw@>_J1M>@zzq(t@|k02 zkRshA`~56s;V*1(zPtk!@*1iDS-Ju~9Q9Ww{bm*BhM$9pHI%D}yw!U9}J-D7Hz`{ihUyyS%6NZQVO36L#FGTEIR=I0pj5T$zB;*`f=p1{rKKgM!OfnWTnnef# zpVHFDtv%L4eiS*#im||0os!gHBC+!9GdGMAPy2qLoNop-A*+>RZ?=dl9^dYkgOb$} zWpO)(M}6*gdr_2PRTi(__Q}ayhS{myGZ_K$i_7Ru+;mXbSR@IXv-m}|(Ro380<>?U z*!5o5?vbVG$P+Kw3RgQe*G==>3peG<0Np)o9L8B`cYCA;iPT!j;;X1MNy9gN*wBfW zq2@k2>OiXaDY0`>Sq-z;G7g{KnKIou>;E?2IlHNOWgZIcQAfmrMC0tM)NTfilvP? z2nHrdeVbyq^8}@}7h+6aLapkleb9Ol~rg9#`2Gl}CaPYHw3|y0aLydmkfzgN*%VHY9{CBSY zqQ`aBI8$u6ujoqEwQaQjKtPdvx%^0}Mvu;!;!0MIWowA9R_69=iM?RHA-3d=2BqI- z;`rK<3}d<`8jRzljBV(4`+q2Vr{K)Gs9QL;+3DCFr(@f;JL=fBZKGq`M#r{o+wSnZ z7ia$$U)5Kq{@Y#8Q+tg$$69+$k9)ob+8>4&;NEh&LuKp@sPn;;41@OaNr@E-n~k?! zOeJ15jJn%vp%l)P$j>-KJ6FLS6>Zwv|H&*N_(NdM+c?=19Wl?BhZr3*(`}QpW#b`}4uIZF zSP456LS*}ukR!Dsas1kC_2(ueXBM@x-)Md{&kS%^Y#Y_40kJ=HVkY4#BwwX2}MzUKYXUpi_~E z=B0AP7V&(Gr)&Gx*YX43zG`B>rLsygqN8sLU52Pr8FZ*t;MdvzTE`cp<)dx+`x)N2 z`d$OhNKm{Fc;5~KGTqIR;i)*=FR0n!7)>qzMz;fU$6{aOH8gh}0OX#A#P7Qq<8y5^ zx_9VW>Iu$yBaZmsTpTT5g-3=4f_BqLFSb>MtYcooKo*mJwX!oi`a?q3XiHRd*w}=! zdb404XL>593MIYG+?@AR*UfN};wE7%=@3M(!YFaqUT1}fkQR?H?NmBEk*D}x`&GP= zLV2LBD;9jed((J%#4Opx&tdu9(1ah-Og%oB$OAhrOQ_1C6^jj!I|;ru^;$|C)Dg3B-emZ zH582*oCvweYHj)@BWooV!Gh}0B*a#ona@SI_G*&k{wAP|_Lz~tSj2(>m8MbBN#e(c zWh9^3SN)=zSQ`o8ayD*2@blM0Mx~2bn_wV^6+P$l+W5uwY^!{(ZZ5x$Dhg-XgHzWb z`HBu9hqN2igakgOYy2J)t}9rOrU&X2o>e9O!4`wOG9vR|Ux(z$6}?;lG&>!^+7i~Y)(iM3Ea}y3Zu|w;4pp-Ij)q7dgRZ>rQu-lt)R0kwM78r4`t>kth|BZlI5LKsrDARIqv^vw*d9P!2C$paut#b zMz72#BFV6Rl{p?DuJ^yq3G%pe7j;e5bz|67+a*)n@a8sSv1Nd&f6N%r=rAMsR!P1p z6IlN%TLK)?uNHqk!%+7GCWpfz{=$-J;bJ@0;gMlpfAKrI1+PD!SXOPmBZX=V-^>M~ z6jNmB_Qk$Z$%M8A)eq3FmDFE6bwy!c0^BN6k3GcZm0=}k{0tE`hjHAGXd?SZA)c>J zM12ZbUB!zSyM4v$d=DLpc9z)SFM=;+Y7a!=R?odc2JkN%`)7Y&}8)Rgt z1-Mu6<3@oreKKoiJ$=U@lgdGk46%{0$Y6&Fw{4P2dstO>8rm*b;YEG=R=T7Uo-ZgC z)Akp)3?q`n(0bb3!+}3?413|MPY(z|HHg~RzrodiyT~-3%<`G=1ajm@K(Q4uV9C+# z4Rx!uuoB?;)M@XzJ$FL}B_35w!0b9Ll7JSKKZ{dr^*EYIzmJm`RE(RmoNF@P1zb`b z)j!$C`genGkEtxI=-g9x8PU<*3j8^+)-0N5hhik!V;R+<>!!AHhA7Sj@@}qcJz>!t_!-E&BHOhrhWW_yA+IUyD=iCBzQEm#c ztJm=%*?t)`PPmM`8!lC{+A~u9?BmHxic86S&cdwSH4Qs&ONAGyY%7?c{>Nc_Y`;343O9d%UXIgURZC{=U&cEc}3cgxGJ>%O!d3S z(y$Ze34S#sXZbEAMC-HoZ%An0aD&ia-wN%i!zvLRn12pxzYnspkrXW6cw>CEsjh<| zqr)YF;?wN;wStSENgHW#%JiM)lM`BjoB{h<(~Ghi-Llz}AKmW~nVYz#Ky=Xn&+%yG zkI&z}%uq6Ur1K`36P(s{#JPXFkyV+{tYTIJDfZv*$dPMdgVTKl(60*6akx!&?W3$A z;*z(CmdgY%G7>DGkM!zzH90$l_?R778-m}dw0EN$kQm(oA?lY?PB!O>(3 z$6X;@6~KvV-2N`ZSo22-dxjmsktjHf*Hkar zv1e15x^zQvYu&Go7Kn}?U-HDUZ)P-9P?4-Qs$OdJ>t;Wj2hgw9^Qd3g$}ZY7qJtj#(K=-a~6lm^D_Xdk(rj8v*wW*@v^d{C$q?XsL^mexHV^hNr=M zoSK+9cA_ZI_qBME8Q3(NX@`SZ#b`&$UPY}i@&oJo2_H`VtL`Lwo7un^oY*%zJ{hH(MboJexPB<24r^F9h zk{B0$UCO&uWn{`PR)>=(u2$j>j;cgDY&zxO0>HJTgo(t%=PzvsT63}!LgtelZ?M*> z-GJ*@8~H1!^ZF-%?+*ie3}$%%v}J8nnIW;DIrT|6Qs@i|-|;9dDo;W^%a)4g>|+>xL~Q#g0T9a`|L&X+t9&^i*TlV>;+9OTUM8o`Sgv>kkiNR=Ja)-0&@N2F$Zl} zFJ2VK{M$k@JD^4jj1b&$_)OFdB8oH*9EOYWem}%l{y^DN=0{nE8xw&E7l{P0x+6N2A(sAokoT#O`RW z!$l{%22uy`vxkf)HzV+HVKbY#?ME!Aj0`zaT;fQYw#pY@G3xWK-Y@+yKiqG=%d2sp zdNce}g>%p{WMmABt7PQ&h)_TLqLc4r5hSa#AeyAy zbfo+_RqA@(KNyT#5J}zza5Z47MnF8XY=>yH<)Q}TkN~)dD&1FWI}l0%TsK35iDD|V z^1!(wk{w8lJX{LPe2ewpi0yb|hS1yF?D6ItSGtG%WopySRsCdy(o`3aQ9p#4#;_O4 zOESY^NF1f3$pjEmw&5c+0AEQ%)PLjU)H33;FQP{GN<(?+BU>M!dK&2Ir}aQRjVKCX zuy>^>3#2JMV)(P*pn|>+(1Y12`Nt@}Kv+hVcFx*ckE}n<_N7MRyk=p|N%)_Bl3{daE7TsKgVE;v7 z4q1>gREtNTf3gyf<*m1Hj$16xeO+H5()>5RPLfxw=#1h(We_K-1@OZ@@T$ZyoUJ%# zlQu6t>{RX))ni4up1<*#R~Wp>=cCqEVE0)&FE1pPh7+Tm$r0)bY}2{@8=$%2%W=df zhzFb3*{#`B>ZMV!TEu$F5*I)P&3@US)J@+OhWiXCKs=WCZyqQay|W^0@Upr4)?Ax) z_P-)>aJEuTVEu8Aj)~4_EeU|0ct;7hRmLeWg5|)f#K&UvsbE2;9mWu6CWycGq~4(Rf@Qk*%=bAWXN{&LV1 zO{C`YG|}(e6)6aqQ$JXiur`EeBzQ0hD{xjnKNss)uupmnRhjo-v zsN0ZYoYRkoB>8H|7|Di&=>a7lvJ0mHqZs)+y0e@9vSIw@j5zXTjw76`Vw_Foay0lm zoMw)yOIRDP>tX(Cfu|9#I^ym~A{9KPYo{++?R;hfdG`e+0%09jgw@>Bl+hp@X)egl zxGW?>WGBx7Bv22d9fi!&kU~}dH#_Pt6y$FS!;Plw#d_ZCfILKryYFl=KYRM&N)e-S z=}{C2RUGS)sYg`)y?uix-?1}g)4)mOf;e;h#tZ*P{Br&hg01N?`G2{+9M z_RUkky~;#4cgnYqSxH)uM|9a-+{HhIcSDRZ++z(N)r*&tLp0ophru$Hg?_j!JTUlc zuZcfj+X97OCl$a?y%y@WF+sCXtBS8qDS*7bAQadFHxmm2$8sz~=j>F-u6~PkY$2_6 zq!%NRO*fxH&*=^+1iw3=kdI6oef<)RE-B-k{uf6|LTb{dlqJF87h#RZo{dEbfLjW` zvCXb}feg^|Yx>n!SYRl8K%>K$fz0r%(~$w>|v%Rzz5#XpXuUwpzUSZ!)) zGX}v{u3iw$i6RlQQZ>I6qESC7{rFwK{YItgOeXO5BgiQdmAW2&8@aGV`jt6G-lbu} zX`C0X2@748<8!0c9krYn;Tx{l$(5Mu0=A+eKQJgmQQUCw?OlN_T6#3E`T*A+xHlX8 z{gZJPlDh%mt7u8TLO6e!2J~qDf+y9C33r|&g_QW~KKI+J0v49Bj$1+p;~L(yK^pOfFQ>WR>=rA4T|lEm)Of-NB=HkbO@C^}~} z@C5YGNbWHTYkrK8-D2(;0C;oS9n0A!J7UV^t}XVs&|>|M?x~Tt=l785gOwR!prO2c zmnMW%bS2V*dWlB+oSUTzpgoe|O3Kg@36Q7~Co|d|YyZW~Gt49gv zf^8=Jh*on@Ex{WCMiU%Vox`)NVfx9WQDMSC_{?b7x4l!s42Pbft1Ir&;1bB+{a5=Nr zFJID7;kb>-wWq-j5}f9EAEUIQTY+_P-&yLuVBNOi+3GuMmts`to+pG6AHw>}R5tgt zi;-#=^Wz_&HyNeC!C|lj7=Wje8syDxu+YrnktIR3kK*P~R(qYu6%MPosPm7b>3_MC zGvbX~V+phtYpVx({mqfMdLL1i>#uhd%x6|>1%HsuB?uNgpwB@vm#by19CBThm239b}INzANB`AQ=AE6 zrhurUWig6)P7%Ooi4jHQfG5&7_oba`6KXVdOIG!BjRmp=D@yOT{`g^}J^q$K;FkC% zm|0AHo2JADv-Udd@prH^765O`k~;jh_9Q%j7x2Ge;(TaJS6+m9xgzwl3x|4VrX-%E z`RR8)+59807Bsz{VWnh|9M4%<@CUiwp;b;0%0T3Q=FyISu0c%cP)m1#s`*vhHDB{B zO@*U>9sBuSddc5o)VIV6;HekmlzAHbmA4_4ScYc+3c1BbHA4n?nG~7ab>~lDC^hxV&mxdilrfmb z#_wwn^fK~H^fdwXP6v(2c}I1T48VK7Oi5`YTM>O8T=@MAi*b$j#=Wc?$27WozeyQ) z?wAV2Y?ii)xbBxon?s-zn38*$pQAJ7>MEoQ#r8@-9BC{Q>)b*AMr*&;$f{awZQwml zHN%6tT13`3dKkwSxkMH!$Kr%+hpu1y_V; z<;F7wW}C}azV@uC_t#z}5jOADg}s*WtsstmOUT1kQ3|prCj2Ic{AK)eeIR`TF#`M1 zNT&0?Tf|T~Q5liNYcCH!ZqC(>t3R+hFuAa{OgIY_Q5$#f?5DJrLP%_2qR(EGy67-h z6&)$14hLiuLw7eubQa+OVE?>`-+KK>uGj1*JyP-v4bgg+UQqD>+1UvrIP)frNIoAs-XjF9_>T8<5|-Y7d62J6%j18F`-k zCf)u0wQ#eCd;-z%AWdOlXYS35ulO906Km(ruev|Q5n7oQM9x@tl*{Aj%?tnXD8o_W z1S+yzFe(fo7ySu}$~H{w_IJza?}8XpavJtf8|n(UsgjoQ`E2ZX^@7c$(~KxzFk@uq z=Q+Zto0XXYYiq*4Q=v@N~XEbwq zMlil13xWQqlEzHwqX7%TWaJZ{XPUWR=S0-}vc07YIHV};t>X|aWTwZfb4x|Si}^(3 zcAr#V;F1WnW-Cr%*-CzP6lp$PzAnT=_bLf}7f|EZiKXT#Eh zro5gAiz`kTI%zG8j4}8kMRM?prW>Zkor+8dp{Be#_Izs~@+fDcV_>eQhUnoHR zd098oLxQ3uJc;!#JXpuob>ok5OUSnfbB@C>#|k0Y2Gq2YTfB!3A`$Fxo5(M|S~OY~ zhCdd8MhZ#EF0g}=h~MNCNmW09{m|`*&5J967XRadxNKJJZ^}$Y z0zJ&4#8*j1){g@Fveb4^O}t6lcK!RXxykd52G_aps+>TE?O3N5YjbYIXnC6ay<_2J zGf|;smHv^q?eH@~HC))h$%OnDsLh4nwN`p9Ea8jM9#)^fm}WN_vkhbN_Vn>42IO?! zoz`5V=XE2;St+0JQvNkl-YTVLgn%XXfI8A5|Na*TS<2xTIpXAFB%ZM#siZR?uL%wa z9Tf)MI~055b_fxWgP|Ast>gbrv^GZ!BC=}v@|T0IWz*0j_l2G7gIh#4Xv!?zqhD|q z35~eyUN2e|FK4fwN}SiPAUip*vxr5pon9z7xG(;bnx;Wo$?3FL9SykmZCbJdyT7T? z+PGhMneSmkjSL{*1&gun*t#C1;$k;F2?}mCb)Tm_Spo$<&`cvH?~}t5Nc5=xA*d^s zp8@BqrhWlYBb@ODkf+BY(;fOiDM+#;SMQp<=2QoE#ueV!=?f zwvwq1x6|*3g2i(5WDura5YmM;*>-wu?~2M2)y6Q94`3BsfE?%Bct?X*68Sq{J-CFA zZQKdR;y~X0-d~k^b}MzA9ms+2bGtVUru~1BtMCf;iA`ZwOzfu|gcIq$ifhxT(9{a3 zZLYb1$*&df9Yn=(8_YfOjLb+B=U1y#`4=yVhBQnOp_QgDvb1ja>zS%mad&`q*w{XXp$cJ@z2I7dT+hkNu~#_IY~bu73S|t>g({U?!rsD?N>0 z(rp<;q&v}!6 z!HY0_{-#7vLXjTzd%9@8c56{CBgJ=m7nxWYubJJqTvf(5kE8>_F~I+#Hr4z6KexUg za@q7_*xwd@3YDG*+CGbD8d7y6A5?@OM`_$g zkN5tP!V(I(!tb-b>t`ZfNueH~MQOb>#^@o^F^&#*)B6~bpBl_ zf=gspRMO9b@R(f3KCUHOp>u$xpXeXvU9g9t(nFTsS(uYP%foN=M?OOGCL_kM9AkDT z(O03yRhgeOFVY`~Lnz@AKz>+ygom%D!t_5*LcO7{hVKyO;1I<4$n>iact6lK;+4zd zCQ!&|Q>%{F zwwB3N6ZI5{IFS7-9?wouO0xc7nMsbq;5L$=sHT}o)x~MCa+>pL`aM{9|)`9MU55r7dS1sy4~cr?@*_z9J~YP} zxlGKO{8$)>oPrR$o|e93-LkJ|b zCgck#?q~w^b~N45tT(Y1xGKB9{_^rC^adTPFG#n{Vl)P7up54}!@UnF2`$=mJT8`N zvj*wA5%S|^1pHhyNVd_9hH+q|;D#C;QEpY|ILL!h5{H;auP7m@-7R5&TD?MX(@!d`^{nfpPcsZT2aPi=-Kgssn9$ zq~!b{toZ*b(PJtotGnYJ!P|3r3GKRn0`jC!vzu3&V9L^d+djqJjN1m8m2pT0pMiKt zajaw=_;1giy2hB6@C`o{@z##PMCDP>Xr;;d1#}~SmlqR=8cwLp(hp+nw+aOOX8H4G z2cRCCx<<&%{2L_q;R+WNWBT zGb0>ijL|>#2P^tX-B++MyzI>3SV5-E_)+gbJ(f09@cXBpavgLrX#OWp$oaFLv=xVT z0J~$K16tV^>V^i8HtA;2olJ(oyf>g<;r++%Og33A0U>7m8Np5Q=CRP-$o9aGKLi1X#qO`h)X-kW%OO& zQRgY}(2S7&bUPcYJ#;d5`t+kMAyH146+B)s6p;PWaA)qS9}rw*wmKNI;yCc0g+{d6 z>VdZHh_Z^5;iO)XX{(cLKYG-q0iSN#$qn(Yk3jp?L;%?qSrd%OdIxIf5GgnzlUKr*&9_?o0P`uCFq$Ps;DTe z7cwAFT1Fe6^`&fnOurvQ_`>YRk@K2Er5gV!9>SKSQWX&S6yZ8#_3o6a#%1YJ>dYEH z3g!+|__t;lk7&xUy+KoB45sUd==YcY83~rEDf=*Wg99sKK*GaR1 zI>*9QI|lsIsJwidrp7MDW)-pR=1(!*mQ!2iRauA~c*&2NM|^NySAw{)ZyKY8rG9e( zG|GB-z<%LLa)~QqA$#k1Ay)b(7u&~NL~6uWP|%0De{}C2_zzE6A6fC0;A{xsiFI7% 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%0ANr5 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

    +&fs+i^H?l>tMsgwjL6B-rjzx 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 literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/sensor/fw/gk_fw_710xs.bin b/general/package/goke-osdrv-gk710x/files/sensor/fw/gk_fw_710xs.bin new file mode 100755 index 0000000000000000000000000000000000000000..002e71c69b9e562af3c0e98a1e8fec3ee373d91d GIT binary patch literal 1583176 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%0DIretY=U!rXrhb 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

    gl;(G#hq(H|4ZlctxBgJp|*M0A@nP| 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 -s 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%0DmwUHIK2l2&!+8Gpy7zdnxCp-qO~lIbRNzvq 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¬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⪚ZfdT~r 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 VGp-OOuxiz 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

    B$tt=7Kk8@iRN& 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

    wp65b6DWrUg#kbXPV++vpEtMS^R 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

    W*HxuK5 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�F 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 literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/sensor/sc1135_ex.ko b/general/package/goke-osdrv-gk710x/files/sensor/sc1135_ex.ko new file mode 100755 index 0000000000000000000000000000000000000000..343a43a3065389e4883713f8363e9b9559fafb94 GIT binary patch literal 5832 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

    3p{j!^&x;k9c`FV;AiZw~iWa#I>|HGl53;)f8 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%0D=cqRx2^&B~hH!Y%2V{ny_W_yVx52Ny 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 PwH&>nk@xd+TPFTrz7r=k literal 0 HcmV?d00001 diff --git a/general/package/goke-osdrv-gk710x/files/sensor/config/jxh62.bin b/general/package/goke-osdrv-gk710x/files/sensor/config/jxh62.bin new file mode 100755 index 0000000000000000000000000000000000000000..2cc3bd8a42d36c0f3f450efde6307ae910c0a2f0 GIT binary patch literal 159316 zcmeF43t-Ll|Nmc~%eimo91O#3a~Z>CGt4l~l%#T5F69-E08-tX7@^Lf9|`*U{v zO`STo8LY~Hk^SQ1@)9 zt(E&!k33oMeEvJiJIY=8pBK0#4evOmt9qYwELff|s;C|Fmlw!o<1dv?GV)2ZC=yht z&6N3m_|gqlL~djWfQd?sEOlH@(;r zruW~HOO=w}_06WVc}xC} z`62nAnVkjK7tA^Pfn8*ksle^{-?_=l?(4bs>e#X@ctvYy>j9GM{)&n;e9zdyV$)_n5bUz zr9tXy$X&8P{u6&|3n*fh0B}U(+b%Bjo+yRyO|q#-$t^fzDOT>AB64Po8)n&S;`>6{ zTz7d#NmsZs_1nvYTuqW~;oFR~&C&&{R9)1Q$on@bfy{4mzTs?3&r8bbNKN;qooz|~ z1Gyygg?G_>FVy3LEiR-txs37lEuXKPDjF7(lERGl<>d-I#`~Wn=UY~P_@83|zn}a4 zoW1q;8?I%dIU z%)YIdTieBf8GE2OF;{m>DZEQd8SFkNhj)1imI_i)DoKchN|=O86{#xKq`E{%4T+Rm zQb(dBT4L}$Pn^`3h7vE0r3t{-Ha4IqE|7IrSy=74;2uo%*i&p}JlDT-~RBt$wfmpq^IqR80%iN^2Fg zFfBrh(&DrP&7)nXwb43YXG%})POZN-Si4snsg2VnXp^<6+DvVZHeY*MdqI0i%hX=i z)@oVWd)SS$P5VsyLOY;+g>{%?+7H@k?VNUAE6@Zh3jX%@x4+;2{r>MC|NY~?|N8I0 z{`>F${P%zU`~UyS{Xf5bR~fUtaJ(%=K#f%=PO1 zI@@a`3EmlBGtBusg|ohE3+H{;W9D}w=6-E3`)h~!-_4i-c9c$-19p+F(p`GUZPE)n z>Tj1jFdw`VGs1q-U+$KHGFXO4stlETF*_WN`QiPTA&!x8m?b_S6J(M+h~4m$F`!cp2h6(1PT<#EZy?DFTr`K2hTVo_{L0OpuwlwhTz5>`0N ztfkad>M8MfLcpW6#4NL|(h*NdaF*Fu8Kexu40D|FpfVNn%O{kD%Ja%{kJP;=C8)l+J|YR615OslEY*P3fLVupB|)(>;Tv6vUm#GLR&?Nx2P_P(}V+k!L3Quq}z+Rq2?BHpMojYx?W2X~#>h!=4oj%x^GY~s+hG8$x82qZ&B<#MKik&yJ zWG;5xWXNLglNzu4JgM<9p49kEzQCTEFXe0bR*rd})i^JTV!}?EK&6yY*88+Zgi=e1 z#y*;cN@F~)(L%XSxdA(AZuUO0al3M-(jU8N?osYj?pMa*H%K2;9#N(#k14b9%*Fyd zv+*3B+2GEa*Ri+eE$ps&Px(;!*!$GRKIKd0Yvo(znDPU5+MLB+8&x%{cI>w)jU6`? zvFD~Lp53Ue)>Y&1^hOi4xq6M-O1)8ShaEV#sNL`kM{l*SIsi{`3{{7#qttQg1nkFo zRGnVh59OX=d4lJtM91qtDDuW>L=<>b+@`-J*a-8ey1K+f5g)r z=dfo-)y$e*b7JRCIjy1=s#Vo$XtlMvc+w+YYl3||*J!PUei|L*^dp{yV?iZM|k?k6^#%O#HIfJnYhZ7W*?_k`;KmZ#DL0z9S!CFXktBwr?-47vISDg?lg0 z;rFRbid}IPKGzqjRL6B922b@hQIc?txJgOIUd!&v?aE!sKxHVN=Nqd`R3{9kCUnxg$HTY3EQ+O?~;2FNsYI!vT*MXY&#pilzLtF(s z>a}X?!l(Fd!9L7hh0pN~!WCeIIvT%j_@Mg8|M~deUhDXOHvaqD-{1az|NqbWzh2;) z7I4V^g{_ipiZ$4}#xlSXVfog)()^&go4LN(Z9ZYzZhGDHlxd=Apy^iAHKrI-WmAAD zPd}>f)3@nw>#Ot?`t$k%eYQSDpP-M@@6r3~z4fko2mL1fI=#7`px4)<^+>(C9;R2) z%j;!yw;rh5b&GD+HC_3~{)GTsF#T`81^(d{uq!FJBQxPXj}^J_i}O031=8iDQgj8Q zGv@pykxRiEfgMi_`KA|8OnQS0S^~Ki z$hV|&tgmmrZdl;rd|6*Z&V-N&bqGX_`V=)Eq)H}tk=j4@qYE>LNIV0^eh^pqF1{-N zS8{B(lH_|O<>FA^lB5?@LOCl|;QlDRXspkbM6P)2|MOyt8?S7|j2rxQ>5`0BgYkr+ z{i5-&xbbQv#>tDvq2lC<8?ORUl8eWUl8#r!$pscO{&8G0#vxZ>uhB7s|9!qC9fwLP z_s{D=#g~}lkgJ5_RY~RO=Or2cLQ6Ova6J8^@qo1`={S^F!t_ciSCVn)zcyaElyG#o zP^@14(JLCGP_+`sB_g$w$hAU0D2ZHWTxFt5kS|AsMkSEzUqZPId|Nc91nKct?n@%a zU%CG`$o)}2@t^;DS|AzUmX^fNQy^Cozf8fmu2)trr9^(7T0;L#gIr0<=lAo!XMgpV z>i^FI3g)$@Le-VHySve+~vydKlk^wKmdwX0q^k_edlp;iT@Y5Ak5}Vl3q#V+$ad; zJbzF=%3b&iZ5Nlk=x0MNt7vqwpF)vuQn6=>MsnThO3DRbS890CEQast=6kmimR9J-=zLmt>Zc2|2o!sZ~?FeT)k4D z8Lr-|aH&hbdih`Noc;C3J*&U{uXZ=QYWe>S`v3peq{*-3w}9UQehc_5;J1L^0)7kl zE#S9+-va+g3;fmJH~f}gP>|bg)pe`e9TfCi>|Y%Uxhk)Ucm)Rs1z`!)8Wa>9%+FV) zAXh0}% zA{Oxb?_cA;CAISvX;gnAehXY=0R>lY{*4k%#*`gXwm`;TbpE%GhFqTteJYehE-5T2 ztR!;on(mq^;J@KM$KrCJTsEZWmz2Mp z|L*e3{mz86UrFrpJ4Jtl-vU>_0_=a8@Jlz2Dc)mo$^I{LSxAS!t9a=$N$KgMr?KW~BmW&cY_ z_tTVg|4T{b41Y_yjKBH!$^7}g;7{S-YXSfMm%nEJOG)kg@9k;+nq5r``1ijQ|9#oj zvdh)%3;w+Sy%xCA`#k*V6+dp2)Gq(tp60LF)wIBs-sj;@uXsN%sa>vSU-0Ms@3nv; z74Rg>JXwi-?N+=)@r0^d($yL2#dY?}{WW&E*zW$%ehXX)3v^wBr`F6Oin!fwwb0q= z@c*Ch0?RL!QT zZ!l+?pEl1lPc+|W?rZL1zR}#w9AmC(4l-NJ=S;^d+43@cKY>tlHORauSe-M^f0}GUPcepEjoTe>p%YX_JRQXDCnPf=R1CO z9CI9SY;(Njc+oM-G0xG~(asU?2ytkRZ|&RcuiNL_C)oSh+u0l1L+qOUJKJ{Ko3^KI zkJyIVy4zaX>e_;Bs_mHdbL+d-m#y=x4_Sv=ds*998(V8y%UU(-50)IuHp_a;a?1kC zG|O1aAWKh6drOj~o~4?lti@tEYyRH6-<)lJ*ZhWgsd<61NXnrWWXJ zai-d)s_1WJOaUg7DPKRWpU{u!U+R1G9s0-m2YQyiMt@CTuD_r^tC@5kChBAL z5&Av)K)tV?qIXB{OV)4FTcQ6o)#LSg=z%r$s(NKT7=6&C+y55*??NvqaQ(S=p6e&q zA=h@-TGunKhg|(#H@a%MtgdgI?>aM_W1U@{4V|T(#{)kKToU+TVDG@Bz|g?FfIR_g z1Lg&c3g{k?7!Vpz;5g`b&#}ZY)sgDx&bLfum?c43E?HTsT_EdWpdkcFVdyqZf z_O0zx+j`rJw%N7^Y=dmwY}eZw*s9oEw)58St-Gz8tgEcgTj!u34Y&5S-eSGp+Q=Gd zt!Q;v&s&b8FMVox&$8OG6ul|kGSM;uV^vQ}2TLnU6H8t6s9=m&isdx=)R*R+=8w#8 zn^&2ao1Zm5X`X?8HO4&D+~1sHzSZ2$e4RPbT;E(9<5vZ9DfBMIeAbj}`WF4`3)6Pf zX45;SwWilh%P^KLKp&f7nrwOiy=)jpw7#YkQ&&?*QyWt&QyZUDt$Ihjy?!Hl-!*!3y$SkXoL*P2jWMvQ9;#Q=%NO=RhmOBd$bKld z;M$OYi;SWK(o}JjkaOVHRpCYC!af7CdhO| zJEEo76nR5iY+h_$?KpbwP{8DKS)~`7Tb^HRo~x-c(v)Hwr*F0<|H3mz%Pcl;`FXK< z$$4Fp%qg}GT3>5$Uamd)mmbjBb!xGBOrBL1EOxu$4X#ppdtpzpIa7~vy zYgNZi^JeIL;tI~IUgn4voOeXaED&jB8fY14>1OZu^UGyto!L=7+mdy5q-mw#l>c?5 zEnvprp{R;#(lv`>Rcwj_Z(*Oi=yfalvK}BZ31i2D;8BncW`lWPA$S%n0RzAga4#4M z#)1dH!(a;N3+@J~U>LX`i~|$EWY8IO1wBD;&<{}l9&jHp&fS49&kX{`xlssr0Jnhd zpcm)^`UA?bOzptUpg5Vqi0=rxfZM?B;NtQoBd!x*ISiS*5H{*`@p;yP=LZ6oljXY= zuzV@tPC%P6ZfOckijr4{hJOUW!9zvMu(T;}QCn8L{ zPXjZ-Ch#%%1bhzmf`i~NI0oJX>%qI=L$D3(0AGLuU_N*nJP%$1uYfneT95^v1dD*t zUzQ{M8dwF^fk(h}z_L66nBFtMNRM@x0%ic;{-xlwp6I01TPO z5S{~`0vW)t$5e!U&lz=M-)G*lz+Av|ee1%0PF?0r8Ttq7`y62TSU>_ z0oI**MwyLsw9~7=*CvLJuZ@|PVGCc|zJ+*lahovi1Mm^p4%UDT;63mmFxq!F!u!Dz zV3dVzM*VjH)7SzoZac$n%r_JG_BF%qhRjl&XFpE^9A{`N!`8G1`vm(g{d_!_1PpsV zjxcRA1PlZBgRy{Z{V-sgP=6>G0mcBMulTm9;b*>SQ;%)E05IKgfc?Zs*SDWsDsRfL zzcPIzU-o0)e!{-Qx*K^LbvN>6KQrv-nRotyd!K+n+Y$Gi}KBegUw*Gk=Z`>j3jNe0Cnf zzU6-zpE*vjz1hdu-iBSCLD)#|Qte{c$mmy>N`rmDCUDla> zcLiYjzWvEagJono7pKiOHGGQoV;}alk>P8Gjc5}?$FRw2#2M}4TNc{?O|TxY&FIgW zz_(pCdgHg^xC3nS9>2ix0Qeew2Tp)f!00FMAn}N~pMmrutoYC$l5k3cuxrP7u-?c?=%mrfk#i-9*(;xQR!`}z|eZb!b z{C&XR2mF1&-v|D?eSm8Or@b7H*5K>`XTZFg=z}1(b^i(I5&if2PTLFkRMxWiZlgjxgm}2Fh0lvHh{Vbz|du0%#(JYz1R+hy^Qwmh`82(`qu!Xu5k!6U*^v~ z!#+WnH{06|SY~n?U^<-v>wPV_9y9~AStCH3u}zpJ+mH1iY!jBrs7ors{XtKV0=fXE znGCK2v<=&i=|%yj%Ra%jAneb9z$o8ngol9vU?AuNx`G~{xVkq*Jo{QLVAP%Er0rQ& zrfZ}<1L0|40vHd*f_uC$uiHUyz`Sk-9l%Y1?L=EMFSfB^Yubf%VP3Q|`-fqdr3hz$ z+2Bbq9ZUj~0rO=YhXdxzJo|#~fO)cAZU8NS(I;8Q`hfi-9I%b)d(5{KVE;G#^eu#6 z2dlwy@ElkI7J^w|F7Pc6ZNc)407C$6eivYSvMhw{*$U7OEEoGoETApePeK805e(=f zEE8>El<73W--GYKVXzl`?qv&(?|}~h%l;}@1z7fH0n2ZceI~+eN7`~6NCWqQp|OtU!yG>0K=9ncX_}v6EjeO01v)TZU!2IC=df8L1hpQ%7Xyl1{UxO zbQBy}-(%nh@D11pz676vtson01RK1(fn%l@*7s?!2+RhLgLJ?;PXuf))|qX__PP_W z&b>fqz&f`FtS{Tl0~&g%i(_>V0m48KC=1wTCcwJ0-n&qT{or%(5!ede2W!E4unN2c zmV+f=0ays;f$3fz!Ep>23r2$>U=SDpQb0G*10;i+KwEGPXbPHx`k*$b3#x)jAQY4V zcHjagK${nUQ{X6|-D&eZfOg*nX!FhBL$CqRH`W2#oW8LPJOk*fPl4HB3U~xO1jc|7 zU?dm}X!HJ{7w8Ob1vi810c}p(HwNry4M81H4bbi(fMZ2DK)Y*RX!iy9e)$P72RsT! zgNfiia2FU1ZUgN>CvYQZ1QJ0U;GT!dpb~HaGq8hSu-}3ECw>G6!DnDM*aFsrjo?l2 zB6t}*3ub{iU!5v;Yr5pTJ?T2kZx* z0QN8L1=V!(UKf^rl8#ZK&^h)DAbqVcET!8gvIVo@0nCViEZBKoc z%gD=+rR_^0o@HVj#}T94ZiHEGrpM?K1u)GX2 zeIuT7OrQ7T%%3vBfaPJ`c%E^*{!*9m#=Se!;n+;uu&l-y&2VKvJMvtmi^6Pw%9aNV z^M0xVplvA6{269E!;B-8@eT7{fN2=AJjXmKM_qp&#R;-s1 zXM|}l>e3dpE8`hvJnKuF^E1<6f8+Q`8QPs=A=`y*WQ?mnBm5I!KV%%wagBpVwg->K z_+hju(`P(&m?zU_zLaOXP>x5&QJ3vSIo6Fj>_4nKWms;Ol}DbZt@xR8Y!kyihTl+! zGPE`2X;apZc~FLNMt`BK(H4|9?%7xt%JUqLjHe#!#k3jEwAg+|zcBLkO@p$GXT2HE zv{-f?8BaU#GwVQ@mLbnFvyMhtStiO-$M6@%QJ%7l<2l-nHf38HY4IG>VmojjLoVR@ zlu;*^k2-8ue&78q;CJBM)57#PW-&eL@O$wiU?128m?p2A>?hPW(&pONH{ff)v{+W7 zyetp(*hko>sLOoA5l26z-?G2653pTm8|oVUn7VaA6o>%SqaRbpXnWd(ea4s*)V$alZoFin_ELp}m<8`3f*E>Qna1NSvCZ|bs*jJ$Uu{3+nR2SKOpXVz&^qDW}jjHyTRvxW!MV1 zU*-ew4%h(Lm)SqrFO6}4_2F1U+pAeqF&voEUuo7f~Wx(hkv_0!?_=;ga_66F|u;U(tzW_$N ze~d88O&hQ+2+Pg9)`Hi;E5Nu0aeOhxG}_4Md-PM|tnbTU30MrC1`EJkFbg~eeEpv`VE<#=8s%UcvptM9VOtxpZCE~zMQk6! zzDirM%tpECH-_!@A#C&y)`id?XixG9V4opuPm>zYXX!wDka#wJ*5Kd%Ocj(i_|c zdV1-GBk2k{gIm1E4mc(Q9@~O8;3jY*xB;~CaxIQY;2PlZp)tawDQE~9fOrrC;y^vX zF_Gga$Gn;a#7`2xosAlv(S3yzxs zj~{?{!6xtV9UQa3TJV->?{OZEv%wrN z3rzQtj^m@?5ikWj1SWz>APtNIV|nr0&4`bZPd5H#=}>){v& zc#H40rM6-@T>AdV9N+kGq;1=!YP7+_lu0c>xht@|R(Htr2l zKu^FnX8W>TJA<1+doQhVWZRPKKuf^(Z3fuBO+Y+g`!)bEAR0u0+8`2C_fiGNP!Iwt zg7RKU;phfV-~e`D1{R=u5gh%mzn2BN`_~N%ulI$0ll}8gkdNyz?-h9OpdcOILoq$$ zo`&anju^6(<9X^a%zF;PFyk1eJnu1?7VnD;d7fh&kBn0hX1WY(-gus;|1qBDDNDbk zj1kB5DaUx8XFPQn$8wke<&Cr$M;$AUOq19E@w|~2j{$)8VtgQAoDt7)lj(9Cr3}L?GvT<({2AtX->@NLq*of}sY_^A!uuxH zo8_duVPmFCIkr9ZSuP_lLzcGZ7|${>j`!_GxjF8$+)SJC%!m2&NL%te)8skUowAH$ zUaUh|z&OJ5jA#CoVSWrVj_L7e#Ip|6;d$!uGtVWc!GPsq-FTjHyk=6D@su^{!Rsk)!?K3?gexOV zJMvtmi^6Pw%JTZla1f{fm?q_!Kf{b?m~n(MzTtBC%rp#Ho@1Vrqb|d&lcB>f`vK1} zOxshRVb;@VE8541Gs3hNb!iLQmGKNSo^_|q`I%|3zj6Ge4DHUbknO@YGR9TT$2do1 zKV%%wan8&m+k;1A{4m;-=`)@>%#&#|U&^yxD90n?sLS@E9P36M_8-=rGAuXC$|KLy zR{TskwuxaM!*8fV8QPliv?=SyJSf9BqrXtrXbZ}-otP%eLV2F!k@3`Hy_h!RnHJm6 z=od!5zG+aF@vJxFnHI~=BjafYer6pA(=y~)X4cUtE6YS#>KOjQILcF&aXd%c(WY!m zBQ2g|T5N|?i066(=hQ}>SU&0)Yazz^3fBUd9>*-EM;*?+xkj`Pa7~11^15lv+l{pS z>xLKBs<<|Bz-z1RIC2ezHls~xH`?6Su3RVE4`^Sm`%uTw`VZH)xUS}3H}tO?((jD^u?Jz|UpMrx8>V4Q z;rh`SpW|qRM}iUHUN5OQ4g!Nge=q>t1@7>2JC40T56~TS^B%k6*co&Lw}7_bCZFT= z2)6<)KoYnHa9t_UdrZL5zixP8U+T-S1$hZ90WW}O!870~;9obqa38_@Szap%?@9cx zzn2BN@HdN4q%{1OhHzR-+>hfkxw4*#~ADc zZHSfgCXi{4yHxyI+Xa+PkZ75O1@Cm|XX6`(Tsvw8{S4^GLO&-GX+l5EtM4wNuO5Pa zb`riUz^{o;PBKYi3iNYJK?nM|Rq;(P^xe=;fqoM5&us>N&EJ%RqGyAZRTP?FvQ&U2oj)o1P zp8@@}BKnoiSfp&OMI3vvVK@tji+G$pFHBu z^|Uz?AgxXYNaE1|sg)BT&Mo*+u9YA?#4LTBkOj@OUUM?lJcTQ z8k_;AJ$I%!rDqSPbn4=i7M+|D(b|bGRX}x+7Z@PfZ&i}H=Od)eThVf8OhXx%*F;uV z^2nic_|wE^Jrhz~G8){|!zDetxa68-msD(xU-wG@)i-Ej?G+@4)>oBvp><@^xcZWG zys_+R)?7NB_sIM_&*D6nECi2(G|&e$1tuVcc%fa(3g``@zy*CCdzF#AnCg-@BUYqnmpb7{CC!q5lmn-p=aRKzq_QKTR4rb2GENoKZN!c*b@sn9q4KfGA~uhc`6Ao#vL3jTlQ6IGUc zVv)oSE?IJO1v!#g1!eI1e^#;nUv;HPDrK0YR2r(@<~^jb(Ik_q2g;FW%S-s<;Sv=G z{l_lp|4~OQ5|Lw(N?R;q%Y^@@{j5rZMt0fqP>>{k6Dn=4t0C@{Q8E|)e>CZL{-2Ox zlQ{T(WV%htrNQ_6ftL51#rmXMR*npj1o;0X`2VCg;^gSY1lbG!pY@yn-_XDz*PzK0 zA{|mA$RTz?^Y8smk!715l6o#!!r}i}@c%aO|MVk`B=y!rSpxq*@?+r`d|PgS+ydWk zb0|QX>aF7W?I_<#6m&wcRyA@Kb^ z@cj+q2kfaAbp zU>Ilv%7F{M7h{*BuFA57{_m)*xxc0>-?!%ile0<|8VGM!2gk? zWW#^cp`Tk9y2W1qW9KVUd$JOPlrOcLRR2lQCMch?gGNxVyS(gs~&xZfTLO-)u|8F+QB=M;xiApv}#gON)IbxPc zy5NGi?%wipa%ebqanzI@Y4HD~Vz2+#XIms`qebFZTBQ0ci&#@WS0&hDmu0sEN$~rj z64J1S$9kd)oQ5@fF?E6>)F#3$>? z82EoO{C_0;f87QD9|^x7itGMe@cquX_9v_hkWv}&|FkV8NzN-RdO)}=t`jM-dtzkC z=6JEf|69ZV-SGdsQ=Z4*_m6@!`2HYV`)^KiO08JyljJiiPiljK`oJ79@KYR+W|cwPnoU z`qBXYzXkr^68@i_=lKLaLZ8b5%K@*wcY#=N!S@Pma^ysaY&ua>GT{FM;s3Gl|3mQq z$@!jNAa@ebcjaEi1^<6BJ3yX+ z-#@V_Kpuqe_gfMmp7a2*4IE>Vgk`1W$eu8n>WGx!wK0;uCSH!d*i@q6|2aS7Pqd%% zywk=hYvK2qxb822@2BC~-v#&nRdo1&&LD@ZY+Fgj?2C}dY0;9^qoK6i+XU%(WF`DR z>#QdSKK}*SitGMb`2Irp{(ZRjZypKX3yRU?JMZkM_-j@snWeU@n z0sr3y|M$TE+r$6I|9bsThy0^p0!Rfng9yO+1n(oRE7WHhaI2p;1peO({*N&%Z(HI0 z|6(}C0{mM0OvzEw@O1SZl4Ng+`)||l?!Sw_{^E)!3&G=(t~`Jpqx0FMo91-QL^NA%>ToG=l|O}*<@22 zo4f_TUm9zZX>ObJIW*T4J%0&0)TTOu0NjTMm>llJ(z5ZXFzNGsO*uI)M*1y{mrYMLmAtvQ z_lEz+p7OYwImO!8Dd*w$-{HEy1-}1GfKvwK21>Op=j}58d__rF9w7mPqGfSnLkZu~ zMEd;FT+-qH^Ur$f-T?mtA=knGn!*3z`&sb)heKTGO&e4>(yokbY+hC7Z>=pU&Ff3> z`o^*(y14|y|5Nfj9pEeUy(GYSH1Eg1g3l}kw*zag$0oamgvjbe7{|B8N|*Kt5(59v zhW`)D_l$-7aBw%EAJd095C0UpkAN5epN0Q#fd6~o{~q{%0c?Qze^!C#X~@n8v%rI( zKWGM2unM|83iZR_|Ks8RG4THw`2P_2zo&5i{{iIQ0c*i>@C3LIGzQ0@%X^XV!ZbEG zp#%Sqf&cgV)&EN=n7@MpNm7ntWpb;e+ZIcBsezJFF+$Sef2r`FZ1jJwpYi%zbp5O} zbOV4WxpE9oDr}P^+jElT9waFhYe0(9{QY+jbe%v|Qso4GMRdDlT3?V@_YiFN ziIi~f^*asv#b3XJ;Sr^3Vf{N0D^ilFeuhP~mn7D8uOwB7l8h=SyZ8RR`1yO~w-hPA zToK1(ikwMlq3jN7Va{BV88|Z79b8Yc!!iCqKMVew3jfVSZs|p?zY*Ao5%z;7W%%Vj z9+WtkTwhtQgi}UUamwJz zPU%+4DNPlpxPJ(go!Nmhby-_`y)k1eO2XI(ITRHwV*(n=k+n@E_WS121ODIdtmlcw zE}7X7z6M4`yQEtLe69lS$*u6=+)%aMj_IXk<^C!%X*$+0LhH+!<&9-><>r!`hw&%R z^9uZA8CVSFfbpOs2nHXY!8P^J46C}Sppq;eUsFadij~$e31SUvChOq;U9kQKxlQ10 zuo5f;w0rRt-M90;Ir_57yRD^|3A=FPQw3}6?ndf++mOdJ_T9e8E`MC0l2o< zId8m<@uCv$AtIp<|L+C=k16zjTfR%oK)^}Je+4)uECROyt}AdH((=OK{{<*RL0yak z@c#{k*Z)QEy?J0J{BNR?q4iZVtxc3zcY)+qcpd)NRl?!_m-fF5=spD=SHfkIlBC_G zBwL#**)B!Ntndb|zugM2zbWwF;;+9?Lw5m~1s+ne)c#7grJ0iC(v+kMtKq*r{$TxW zG4xo6C%|MSTN$Ken_DPJPP398yjH@i^eVi5=feMt>vu*G|5>sR-z9#GI=q5s3?4|8 zdmE;hS}9op4kfmHmL!Mw5jXsw^Y>Wze>(iH=>7ZhvYNbT(j??*@%(5iVEc3oJ$;4^1rE7)PEur@x zD)njRwUvjjoDgB1{6ifq(m+3#e_p4E{`%!sS@WD#UVRdO-Q)qQOz&!yewBmusP`<+ zoYpT?oH(~!^`Ker)s~>@anhv&?*G$^`2XfXc6skkyR5&>E}3oZ@>D~+j4F%q;L96q zKP-N;+^kODR;j)>p_WuX6Dz@YVg0Xcq6EPIQ!m^@?CKgIpLPzAEo}p2L$d%`8WA8< z6pRPkr)ZYhQ`}2hzZ9BqWI#^GkpF~S(ju7!VeYn`5&B;^hI+eXWhb5gXRvdB7NG`mZ<%4vSnIh>2kgqChGVO z;TKOJ{KgJ+a2EbTU)%x~pTc(mU&C*vOw z8E}4ZIB$`5TV5~t|04MRfjIat{6DPF|Jy?LCeR9aKpY4K91lK$?hH^FJeC&|i1|Ot zumb*%I^-=X^#5QL($J+9lTCLZMd?unrDzPD#?gRMH)5mE5wEl#H+^(5*{6SiR*V2ER~1u#@|0( zkMAKKRV2SfJ@uQqjf#;J`0wxU-)rJWm8zZAC3L4QLDxVmS zlK;9*_B>F*`eKXw%iglDOO>3~MZkzSUE>hM4lBr}aC5 za^3nsX|X0y8owMUQO^WQ`RRf3^PoWauthWLB-62A*IUb~PwY1}N)A2MKw6G&B9qrN z$C@O@k29W*`A$g&ZO=L7x*wg=_&cZ6*pE5IR;TQJJyhmDIoMry(AMy$6Zh9rPcDd) zS+_M7_r7LW9K-tEFP@(8liNU7(BYg*TL0*h`0p^E-;Xtck1-E_eZ0BDljAFHOx;$a zTFVnL;@;Lswj9SADEwc~_Y8zyf6y270=IzcK@8xyvK_uR_WXF)vApqBZ^-Kf|6c_E zU({4K!v9AWcTyvI^8SPL~8uTr^|4l1${h|K7Ui|@TmZYdzrjBYj^fSs=RMW!0 zhX2i0(xU^Eqy~2t^Zoa5uYM|y1Joqw$3j0npqVP=E2&B0-zZY^2_-e!rGz)=U(EG) z1oT*jd%!@@TTRkCsp$@nD&;DxnPErZzfUUR(WRB#`h$wO{~ie)qYQ%(zC+DcZ&BU$ z7HUdRn3@%OR7t9_K*@*-R?_Pal_ZQmNk!^EY83X24L}*%!G@uDu2{{Mu4=BOr5awk znwnZUS4od}R*|T1#a(|?G1u>L<1`sPSd)?MG#Oe^lm1&(>Cv;QsrBZ1u1Nbml}=Yq ztNxPWu2Wk{iJK^C@ZYQ={yU)tS4u20#%z%h-2(+e1p*-JKnEozDg5+fG(p z`Pso*3H=|a_n2fi!u>}P{fFn+4&n+>>KXasvwd&;X ztp0aJ-gsxZ*k`g%#>>igno4Tsul_&%A%{$z;E>6qu!h*zA@_H1$iTV|>6U*^Jn!rd zEHm_6$kwv+YNRZ{7Y)T4+*BsTd*mqYA&%sF=8OuI$A<^XV?zVw(cXdbK!-pX z79S|R%LU2}-)u35FI`vuz?~u0N1v(`l|8U&gECugY$8GPno9%t|LUJTi$1}+A(#h$ zfBb!Xm++2L#=h#5fzM!1!9z}|+xNKhhi3Ud=zXj~)7Sf3~@ z;s06ZJ*(hfuY*^>GVlzT4JHAO4ZJ>A%0ChK;rR_!63?HgGcvDzL&+K6R5IZIoeDhf z;rzQG3#@U^T*rgo$pn3Pu_uOC2t1&zgMCEZ%3cs2CxJ!?}NA0WIa>Oa4dxXJPiMV zPuI9c4Uf);|IAQQ8-IM!{Ph#B{>Q)S=W3a167)05KCGreKcmLAszetkIrY<(l*ZdG zy8oqqHlY3oV7;2Ey`pB?7pd;DlhxR;yVcYhEmhnus|EKrWAfpYkCfb2gQ zAlo+wNY?WK^5XD3eMaU+$kUScFLffq{H!e_On{`!kJ)OOM=wkhvT8>g#b3;G5%o#Nt`Z*D+ z)MV%m*3SQnH#+F-LV*U#Di(hA+q6rY0xY)%3(c(C_EfZwC29z%*C}wn23*Nhz#%~DhArKs7BTxwF{Nazps>L(4+#M51qM2{wo9GcWyt4huGs#IKc zvqk?UBj~U*C;VMCBXX{q9NR~AH!81YH=U$pdD6W4EkCfxH5;%8;U#Q)nqiR!-7Qkb zWs%CyzMG=hbijaDcR( z7$7%|#y-M(v4+?yKpNt21xJ<%kn*4IQGa>p?lPa(xT)&0S2x!lS^LKN4Ig^5@oNhr zo3D3c{jk$X&n+Esod+Fm!W`gQr(ECEDb4CQCC25H(C@JgbHm5>FDHzx{6^jA$O)U< z)N9dhe!`~N-J9*r!ur9Mv!0&gvBnO%jmA3L2$!@Ug73`ka7m+E;Zq*$BdF<7j+z&h zeS3d?^=V6+*KOZ-Yy5%0c8T&B{68npb0>VQ59kegf-ayPXaQnDMQ|qnfbHY_8DaCj zSyB78HN6^~8S83VtMLkt4SNU%Of!r$av#`fli_)p2W?ar@M)U-b__fA1yqM`^hxbZh9lL)vQD)#J1j=%+(JGvR6Y zUw7o61O5G8eU@Pgm<%R>QJR=iHMgs`mQty$mIi&PQ%XyT+pnf2JfmhN_JICD=zj_Q z>5w<-@Cd>a!5A%FyGKh4yhBT>*j~%2)<8?IT}G3*95ps!G5ohD^uK}rVd&3*ypaZN zI0=l^(v+cEvg1xIBlu=5w`#nWQ>(0&Ru8`1=y^3cF$MbHLH`8w(;;u9!FFI9aM#K( zE!Emr%P!kdORJKgNv&WlGxlpWsnJqZ67NuRJU>AHEc9o7irt0pVrB9L)MEsGBPZrU z8xGg9^!{2-sav$vutY7ZW+g2x<~ub#ez}_7w4a*pISYLYn0>+|v-X%|=30}aKWvhz z_yOoi8*~{}t)&d?t_61M)jPz~s6~x1P3oRdGaJ69O4C7VxJN}Df}#J!5Sz@o+a|Mn z*<@yWn@q2d?N=6?jCCK(cuM7RB zK5)pq4Gx*R)**9Va>&dXm`@CG$OI3zA8XyE&udHFH+K9kyw-uUwa#~VG47pF{Th!h zceq)lcTRd*zw(1;(N|b6JP;`J_XNtkPXlGnyMdCvB2Xqj9w?*k4wU{e&8#rTl_~?)fpzH=Qr=ti-w3z^fn=Fr60w)0hJu0UR5;7M#%P7pw?X3bxf* zo8K$`?)(*r-$DOF^tDak1MnVr8@#1uYpb;Ez?ZeOiqC4;mZoLa9;>T4;9XQ1~Y zxCv}Vo`(MW2)_%~YZ>@0v=n=$mQ#MQmR5DPmQicGmQ)YpVWS3GQsO!2Ed_1CN02wt zpba;I4d6{J*_x?kmVHi3tujZ;jeJ1Mi0!QkRS6*yY{p?Xt#!?QBA3XDeXCU-< zUXSkzuML#Xng+_JSmMqO3xq8K<^2Nz^44qEk1!(9^nA5}6&`=BdyNrwro?o3_|Zm{ zKl(5+d-oa7@Y+9nb{}@i7hgGL7udPSDLX!O%C-+Me^}*|w--5O)p(~Yz4c|++^~gJ z$88%F)$Q)(4Qm`&)^tykJWpDyUp)KaTl>IXum^k&cKm|zP(J-}4pZ4}vej0l;*2flt9l;B7!3f3{$QYg)mg z>H`YK$22LJk??c=foAj97kG}~961aQ0j9HN5wMmPu_d5FjA}uy?tOnl) z0*coUhklOjdo2a}NzhM)zPsKVS{n4j3-xcjNT2C2|6dC8=QG~P(9bG&P|K~dQ%kD# zp_Uu_hL#F__pkbjPyQF{|D>f@poGAe(e<<$5{ORxJT{P$V-?*#a7 zGIVXl=(7%N!_(mZvG?ZDO_Xo=_dWBZZPKP`fNpe6_q|Q`y$OqgQf%0iy-`sS5aQRO zARs|OStSZc*`t7L#YO=ESsE2(6{4UlvIGHHr9pNmo!|A80-~sR-ap>=ocHHB*J-i2 zGLy-C=6+`8xv!~Z8n0iOI{0U1i}{Y3Qr0nj_5$W87=u%WPVjm^z|Yr#e}=2j1!itz>k45u=MozM?Z{ zBbprkS`*>GF}Q}=GnOz@{zT?1?g?)o_peZpv<#XLO@W3%PbuhTxPmTkm(#hjYl@@u zPKNAW^lRLg!EWhQUa#a${#sv*W4SK0Vfjju20<@CJ)l-lxRP$wdePMtUR3+ScHy{3 zq5n@)3Sz$T>X&MJ;dIWF{#}cn-+o0GQ+rV-4O5Zy8uSX(A9@zT`2=R>(~T$<{eBUx z9P7N5`(OD^v(=|p(u(N^vnp%b6}}Ywvo0m>hECdyb8W7#p&AI+5u|0%JRho`fP0fT zpE%p8mJTK9ntyk5W89jrQ#0ngb~wKx;BZOKTeox)*!(Bmz~5caFZfVDNa0Z%r1I4H zXOHBLs2*9|q8$AGi@zR!zXb7P#9k>a=xeDaVTn|m^^PPJwwLbl&%gKkrFEB>shPy| z8Yo_3uC(jSnRAla3mwd+TZL_J;oJW&zB}*Zbd#7Gel`3W_#N;&;I|ci&#VvOH^6Ud zDlvOFmK`TCEBrS2t?*kO!f%wp-$Y_s_^t38;Wy`;VrKZw4gUB3as6E)mg|Gh9)|aT z-ESmN{=kg7&*A-NzZ2Wj?hRjv#LTgH5BMF~r@}rNNr|BNfQE7E_dC*AcDG1{UX?LB6G_of?gEH~zvu87ZS+=cU%kH7NkJnw( zN#)?TN274fKq`Y;L77lE#2}0*pL-Y85>|8-Zd{2lFHDp@wA?qB)+1K)D# zVt7RT=J1p=6T)-9Zxdep>Baj0;>U5O+Fz0e#k(Xa^CxL!;p%_n-zI!weZ{EH~vSz6Wh)PejIoC!S7hU8q3!-yp~5#WpnJ7;4sH*?D-620z9(Iw?Sg zaRYRcfj#J1=%PqcIfRL2(lQhFBc~shjcusMKIF*3v9O3Q-^KmwFkZm5MhVmOrCHEh z5Uxc?Nzh(7-Va)l>n+th86g!eOp=nCWlP5l*aw`t-?@J`#tXZk%}@=r44MM*F-0zP z7RQtc!);UNH}+pwnH`0GH5!)#})0M zX78${uYZe{dTdCOc2(s`QRj-UXWsmGe$V3gu?wo6%%qX!VN%(=B&k_hj`a21qFc}Y zSN?Z3k)+yKNjj1tNm2o%PF9ziH6fy%;=v-%jk3ZigwZg`jvjC zddw8|7ovnTp-^ZebQX-5ZTGq`T9_n!Aj}gM3pQb`@TIU-_+Hp2IE9l!t#C!SB{0!b zREq&(s2C~6i>YF!m?svCEyXrssb~;8i(SQ@V!8ON_=4D994P)zd{rDOju1zQW5luI zMA0Hn5vPl@#JS=};>Y4rak==ZxJq0j;+nenwYXW_F76b65PuT)i-*Lc;&JhmcuuSp zFN#;i8)CgEGB>7R-b~GWSpW-SAuOClvKSV}5?Knn4&VS3hzJ<1+q?bs8n z1MAG5WZhU#)|(mGv+Ozc0(+75X9Jmu{f||!SJ@CYjE!I;*(mlFdz+1A?gLD?PCYn&+H&O#169~ z>?r$%9b?DYuk0i{#ZI#`>@53@ooBVo#V)Yl*+q7VU1nFy9!dIl0H z0L@vCQZK5Yi8Pg*n1XVTW)`xFM*;7_m_7AijvZtkcA0 z_zr#)&x(X?o5mhtJ+OVo;8WY!w^*-B%uA+`Wy{*hjIzP92{Nl}m2A7rDZ4E5a?`kF zyR~yOx(#-l;AVAO<+k0;>2}%8(>=^R-Te{w9_}XhG48Y6ZSLQ=|LpE^ck^iOk?f)O z=;G1e!|XBDW0A)?k6j+WcwF)DmdDEV@}Bac@@ewVKabBNz{or-gOQU>DIZ!!GX;+?5dU!up5(7?u=n4nG^N*G$t;M3;zV5q^>VBkhq%QRXO$Hby(6 zyTsUI^s)9>O`J8(FCHCo3HAhiA|+Xq^vTX-bBaEd((Gwwtv;PH>>1`veU?6(awylH zYt1v~>kBlPgGt5c#MO=Z0yDzUe~0O_4Z@HAH~+(G*l-8k?uNBOBdVnd=Gz8gg(C6) zF%Q?;IFDY7c{r~7=CM#uysF5CNsLDLP4H{s*TS!b-w}cLg5Lta6Qff;5ARQY{^<{D z(M;qNsI^muWuXtzhCV_^bNJvl!Eb`!4nOW={%IZ_X|UKjyvHVVR2b2Ryu~iZYjHDI z1HT%6E&LkzE%5VsypH?V{~S={7XbN9fM{H0AB{f51szm0TpfrxI~u$f<`LU4k5~)8 z1AgoM{sHcI859j|`UZ;{>_%Cwl~gDClPNtM>j1wRemmw7n&3Cx@3&xe&5#jFh8*Za z)=yVZ-`Hk!t|F99WyH`#eG=Xnei!BuY2de`e&9L~S28xY22w-ku<6!A70umAHV!wl z0)r`JZxqS>5=q@M9doGQw-;g^?)hD4J3kKXfmTAJp`z^q`ush~xHN$5TO;Vyns_pt zOry3HIi%OaufFHEdgDO?kOdkJb%hYaKnEwfp%=Lcxz>e|_GT=#E=Z;5ZrSAepnyzo z-s?p_s6qfHG#J~C~Xd=|7j8RriQ*u2KL6x5*kmfvkDK{WTAf%W^<340t-V2S_{i86bshb>3 zdv?Xr@Uk@Wm2zlo7<#dAA5xFGO#kS;^WHV+L#T<$gdraA@E-r?W+(EPh8Q3g+ef14ms zsUV}3Hb7*<2fo9C{Nwy(Hh9y90vAiip@J1Mzkf`Wk_{Ysv&cCB3mWF_THTWM5{uhA%qKD!*XmN4kOvEAvBZr_Vas=GaM~s4m`t3sf zw1S_%um3TqY*BIxg_B-vj;GS9QHU^w0DhhWV27XAe{;&;)&IyHc;#YsLk>xR+9AVT zWbD8e@Q?8tnc?U4-w6MM>whTN58fhB;KU2mH2wmUPqhLfD|P@i{PbWo45)L zcE)!VrKC;2_)$?4@K25W+a6s1Is1K}){qjitrki1ngYj^X0)f2H>R`p?A7VA? ze4V(K34S>LeEiP)X#YC?H^Bb{u3S8hfp}}=7!;CAkwPwYaKmE*Z19^K`FFt2$N$dz z#=q^SB7?+)=l$eag%)@^RUUE(lE?^nt!Pm)!Ec1$faTlZr@#2y+5~!ZqChP>f8UTp zlG)QNk0rB@FS$^^T^hjgC;sjCEx*MOMkQdsFpyEU?SEpjZ=^?9UK5ql*8%>u@N@pH zf6IT4uR9|3+(^5|jS@@8P{iUaH(xtbieo?XBbm_1KQ8mo9sZ5?Ek6!*KL+eaM$0Mq zoCh_XI9+tR^du(n{o0g{mjD{g{-T=R?YULA2xBC_L0Fk*s(4x7|Pf=XIa6&uhO0GD3k91X}ZjClz%MAnTF{ zS_A%No6~5|vpLu%_w&!|K4+iT{yvZ%l0%zH-KfvRCbVNh7%9)jBF`+9u64~OEBL2B z@XzZ$XP=M#*F%e;iI5RW-igTx-a*uLLo_W`CX)^P_XYnB@bBBmKj;1q`D^G#32J52sTR_*W~7$q4@C55s>r_(u=mmg-nCrKOP!wQ~sgp9=mp z56k~Z@IMdyAGuxsPaP>hPb2y$9+v+!@Xz}Yr8x93Hje-QEC1o(KOFUcUSs{QZW#Z6 z0H~&rnJlQ^e}4~q^W+fBBP5eB22T(hMq0%{+;J4hz@6h#b^jf7Gz0%c< zUOLyA`n0_yd$P}Nuh!Z({gSJkVYrJNgXJe-{lTvh{`>jw7mvPSUpe)0c~I|_9@NF~ zl-Opazao46!lq$?(V>DygkKFmJ&^yWzzSTiA z_Twn@4kl3B2-JTqjvt(VFd;7!VSu#XrvstR$V(wpo|nkNsyuW~eh1@~$V@4>c$K@@Se`mqeCznN+$IIU?YH4YE-9 z_@AHi^Kt(ch}V98?q3NFfec45meMuF^@Rvz5GK&IL+KPhCyy?96;o^QzXx-f|FQPt zJ?f6gao!wE_Ia_?Hyjxr=W}pwQbeP{KksGwS3iFb9r&LN{&#`@>MU}C|E}P_>S6h> zMGiq4_^)l`zYOR9|CRqE=tGvU4wJ!uEyn-1`M-f3>nixY1b%-5zsJBYvOLsZf!`&_ z0hj=Oac3eWj~tn@2k?6h{wvV$WEIY$e*c2{y&Lu0j{3bA^?MxZ_p_+qxv1Yb!~RSC zz6|e0sFpOsDdddND3tj_%&ep1}xusm!IzrV(#7+58AxIgY11gX!SLJaY^TIo_~m_s1pmGIzt*mx&(|nu1+s{%kVQD(fH}c+UESUsutwEy>}x@#(Qik^ z*>)$;4uW3;zx6);tz*4tju~@-2YAtxQZE`G;zh&v1PT2r3OqYr+UlRx^~DHv+adAD zF-)UN9Z~-^@ZaNqR8MajiF5v8ZM|u*)|&<>y{Y#e_?!fu8WB#dDfd^rUF2IG03y zmt|5k`0u-=n6$U~&p^%B;+#Jj?8oA=Pbg}?nveYlK&>Z>q^@m3TMlbzz`z7@ewR-2 zNqM-|QA{D=fAm$I@UQ$%mSZAM5Um**OFezk$aOe}dV>GH;Qt_cnf}$!`L9)@euKSg z@INn$_JIFVovtCv;Gz80JclF*$0G1wgZi%n|33fm{C_g|KZ11_3I31V<$tt*(HJyR zu;8AeMK(wrlT(!~f`?_%$~y8<(8~I}H}>te;?(&4b z*rQ}mUP1cI;o!gIPuK4%P7Cz%R)Gdi66l45_k^C)wC+zJ$DlxP`fHFwK!P!LKN*sj zkt<^`S@UxK)W_d8b0K5Hb8?bcR~K}V_p=Qjk@pWMNLn55}UIWcWJgM_O9>dza}st;{D?<#P``VCQYkv z3I5gayYBKU&-Nzw6mMb?*u7-l^t)3@$B{|)eV+lcHRoojXLP<9`if;~?4t{|rZmk9 z%%;4-1!Oke_5ZQ}M>f>_L%8Pm(^%w?Rj6nqYX7oi^c5dJq^KC%zIj<)&*-SO>ys#J z0M<1wFi|{Uf`guO}-_e5~$`CNV4LYN&Hb z0@;_RlXG|;O}$w}$I-`(UZyv}pBWksy$Zbq@eIQDP&O1$mnNrE)j_nNJeEppQ)%Bu z+yepsdhoyCrmhWM!?XTcLPbyp6a(GP59I7~jRgN`y!L|s$yvxW#5EA`j~r8X{9V@Y znmez3&`%xs$2!ziga3KpKMnj#4Sj?Ucl_b+i3wE=*C5Kle+~Gb*D(I)x6W=r*90{( zK-98Y!7l$*u=^YkG|jgm2V@m;1S-+T|1$dU^8{DkW$=r=L-%AO|2N^i4qXMmm%#6N z!6ZKce)kK`z^&kS1^AsVP|6^|l$itnMew^A-p-AF?!5+G5%lysa*WOiE{|h^Q?*wx z2W}Runok91>@>ldJU}pHW(tlx7wR|fVe8Q7zXI=N=ps}r7{$|q+QTWhy!Qz9fUgCO zX1QREeGfSTF9@2<6v3W%7UOp-yrqr)3kn>~PUG2OpJEKrfrR78G5J}rD0c~Z|BZqn ze6gU7ogiqE%LPY9j9|_?2L3DIeWcNU<~>HIUt)AJozbzaA{|QkitXtz%5!sq#`kkU z9X1a+1aAuFq)vh%qq(5T+eiAMN#xL>rZ?=rM}Nds7G#hede5EqKjKci*Tx9jw(jv* zKdDobWkSc0sm(3XuL!opR)Q_vQ?TZ4Ay?rWWYHxx`uDU@(C%~vIYROHg$r`}7P&<0 z^ZUv^8ME4(=a7t^*yIit)zwD zD{0PhB~2Nuq|q@4*?=Wp>Qcq5(CEirkG<4$Ny>(mSF=Wx_9@6hAmE+)@%|VUSw^X7 z(ohwReF-_FT~zc6atX`bkSnsGy&|T|p}!a~ zzd1hCcLsXz-b2qmZh3YZiv0bjF(zmMc0;R$tIm40qw)#OM_FMB1Ex+&PhC79k4n!L z@eD)id!-@AKOH$8JTE8?3W0bQA{pzooL&_d{K=;=DiC#$YDLZ}-A{>!tds=9!p)3E${T{ZsB z^N)G%;e2QY#GfHB6nYwJ1%=hsFw}hTKNwB^gZ^W+g@C16*cgy;kSEq6z!^ZqA{?AXo24u8;KkNPxK+5 z0lzhZt!Ny)8PG2HdtuofqaA{jmrsD0BWtZjiqp%+cfvXNsDCmLdWMMKgJL7TBpKr*kOEi$1G*dP8C z@R!|iqq3jesQpYgYM1IpZN`tL7IQN_^80fL9nFnM2^6Rf}_wV zSak02FMz-8HaWHVLQan&KcH1VIqCf6l>h!_mj0EycTB%Wn)^NTb)-;lNH`&wwOR!dJxy`i9(nKR_gn=1Tx4$1G6uEhPg zDk`nIJ>|S1xC*p_vt&QKLm=%&C8d3?q!i=^B)+Sp*nUb1PgIiMwn8R<1KG275bVCjR zGD%M&k8tmGmGIS3!8t7AK z5i|pO8|n*TsNkc%H92BmU0PCQU0PO|WnKZv!ZClKUiU8kJ`v(s!aRp`1T+xp4(TBc zbiFQ|ZL6zkKBcZau5(>kx_6xq_&-vN1_fOU{9OkXLRnBE#E)Teh#!+2&=P2PU9H!n zbv}`bx>{r*O$PrX8~9&|{T{Pk=rhO${+5HkCE)KP@HY$my$AlrfWOzk-*f0AHi*`u z4D^3_K->8~-01%lKdVK(SS7mL7mH4B^!ohoUB62Kcpr-_hU~Swoq9L~CA|XerXdD}%Pc&zH+*E>%OzMHej< zEp7`%lX9M@@vjv1;qM}cPw$VqCWU7(G~TYs7-uPG^9Tz8gg}_y)aZX>3)N^3YrJr=ZbQgbJ&As zf8;?kN<3)l+$-Yb4`P(>+?WzLqWhLYY9mGssZUNoY2e{t~P*Hr^r&J5u>B!-spDFx@JWrci|UT{&+ zmaKz!AoM19e-l?XMn$UV4Nnyf``w#f`_`LYe%G7&<$UK+{#8{#r^w+^EpmdB5+Xe_ z<)3xUKR9kou{FY_!#Sd^qC5I*q5t90F{Z~celI`{SELW}q)-!oD4`A?^!91la$tDs zw{zl~xre5ozZIOfan!b=Hx^#gHNS9C*QXw@g`R1lU%AhBpQix~%w1f&Fo-G&wdDjn8UAz?@;kZ?s zIRB`W`OHg`3lxV`x<&GOT^9bH3Gw_uo?Vs*MMFUl&k(Bv$0u%;iJNbQH%GQ;9F8aH zLAPr2zDADtvv`hy3a?Q@JoC&05+I(Z$n(pNK-(c3H0hR)SGQZ$5&pMolDFYmNQ3Lj zivo~C&>R=#aO;Z#Ab(~RnlZh*57T<1$IV}4w(x7BG4>pCL=K6rj2+-_jc6|V5bV4S z^@aZE_d|vVdehug%%PMsi@(6k;a5d{>{(F@zY~5-gWuZde*r)5EgM;Y%t1}ie~Szg zr3X{{6MBfQi0arg$N@SCez%LJyw%`$9(-e<=OO=w_2ynYPZ~mAflSGaUhYioS1($_ zE{l$s)1o8kfN0LxD(dq-2fuT{FSu&xgY|`nt7(H5d5oBmtiV(N8M8L4Lk`OCqA})I z4{y12t*%;Z75IL!Q_MZg~0?F>{k^qABFOXpKIG9FiYJ zdphz!a;rsGVI}&AN5ISbc$K?EQsThlIY`7Kz%clDMId3i(e0*aQ(Y3xL1#pB)M3$? zfS0A$h??AGqP1{}Xw(gXw>#wSnC`dPo!Bt+?bN%`P5;Zn<)5Ow&OiE9z_H%W zh<&0xew*k@!*`dnK-3pb64ko@!P^O{|3X2xKEo}pxeB`Rx`M7fuAqy^Ci<=S8ut^g z1~faUdNthf?z3@UePT(qiPr4dqOD+zXf5dnFUDxP%XnPbrNdry5sxjp@QD|lM;_Uk z94|Wd)9b>)C;NH-@WtuiZx1hySyQq%c~NZVtoI|SV3?>WF~VC6oj!~{zXQl1LcKq+ z(VKpm>rID|OSUf+J;ghBxNq)0(SO}cuPB~FGHd46jCXd%?OdAXHfLaY;JcCKF(WqCr@WX`l4E#sPGQQG zpLI99Z|K(G^*oF0k9lOv@o%2}GY{gKWaI10y@%CL*7U2Nm)K?FuFSlag9?0>o-g@v z!z~@p3*-6_nhVW_c$c?W~idROn9!oEU9w0@MR)SMTGQT^}CdS6`ld_LeT^vs-0FPa}uGgnf2Uqh3P) zaet<9dl5bS$k6aJGFMo4=8EZvSrl!UHKTwT^Aee{s5$yK2>J!v|BiPc-s2^vh2J6T z%dGGl;J3r?jOl#~T+!{3W73kj(zBT(Hx_-&e$1x30q;SG zdtPi*U;KO?+W^aUFK2pn4`vDOj2^(pk)xnzrt}PE%#B7La})GI@+^h@&M0|KB6Tv#^*9iS|a)=gVD$3jy|e$@a}|qdnu5g zBd1=+X%2+rP{8z=P0S=Y9$r-sB+7$Y3G+Ly&f6atY4zvu^}14 zYwr1Hwsk1p1@EWOBR5sl8hIhDYE{${{eF7%0u>`eAa9Ba!51n@Y8K`lIWIIUKsp!a z5j;S9@xapDgWbm!efi84-TWt9x_tEK=0Uko4wMOL(fgB(-k;cI$QXW2V*Z7?0Qt%K z=&NtMn{w>Ht?V5KCKi6$eVy+8e%E!0cs&=-0*iz0Z_2zlK2~M9?j~{yKCKIt%>*@vOql^+)8N*ALR*Sd%=VUdlGrhZh-; zL+}~)H!fVdZjcR~FrP59XBE@_&T?*{*!iPny9r8Sf)U zWE^q~h9d`{KfGQ4;OE}kel`3K`BLz^82l~(zw?+YaRzgyzXyKDg5TG{Z$Ef>FZ~_g zZ7z-5)UTqC`2~1+76A9$@!j^~T!J~okC|FI zpWz-RGepj0>V&CGubsrKIit`AU4cHzKJb=7OD~GF6oZ4MQ}8^MG(1Leia;N)!+8j@ z+&*OFH;0)t=ogNAk7?4zBgfzk<|;5DM+C=qT{~#;F%Me2-Gde(Kjh;VJZPchPV;-X z(}%g)vbnQ5sb|dpK6Dzh#JW&Ah;G4TPn!Q0^a@nwNgtx` z*ZQ-9=3olrjAL6orycRYqX<5a9^Zx~o0&bc0)3D;z7}_ew*;DZQ%UnKLdS6JaJ!Ob zFH+LXSCmv4tfXo4+Q}?zd$S3xwne2$)7MY$O-CGE*8XWC-E?pe?bus&mjiYk{u z^HlV~1Qku|ucG%`sgUo4T+;c=z1|8>2^}_Qc-+g+dTE~v@0Z)T2@qAwL3GcCbS3+r7T4v#PRY6>{PfC2Y*Xc&! z?_B(~!=RxM&n|ie8U(!v@ociLQng<@sWzrqs!dCh%JKsC4l2H0BI)>RxOkq~0H`0- z7vlM7P^5e(=_=QpE zVf4`cjQaNz>fiU^XB%=rz5+kIk9|4xM=yVmQ^+Aa$t>_|;CF-^X3prJnKSVx@b^8l z!%y&Ab-a(B`|m9GwwLH6GYY>lHT;$)$Pj_w3cnqGdphzD;CB^%`2hc^hGlcVnNBdR z2l7MIN0}q|Ff&9SVCF>h-otOo-HQ7ACHUpbuY&IQ_)oOL(y!2Q=5Ra4v_4K`032fW zsQrxK*QW16j>%T!DA<{)AxB^t{M>U#+L2)Oa6ZhUN#EBXS=zChTDr?M~!4 zY(f35LH*`A4ojgs9_~Bd;3fJ6IfO@;(en_afS-{=h8&pqACN=z9W&;9gFf&LsNXB$ zT>>3zhvi{*&@p)NebG_q2y~da+z;Xyx(_|XKQdFCgIQCzF~io%#gW(ne$gM zTQUFaI4VD?YViFGUUs7H)Gem zGd^vlu6gdV`8h=&_PEfH?uS>U3Y@?_6I&{PlLI2HF7e{GiVvo-wvulA3)imB-AL2Bl4v zq};Jn%8Caghk(C^Yi*;};3xO+?4nO0o^iGWnlBx3n~fZ@sgh69IH@dqsI;r_g$L#k z7}0yq^DE41siA*dj|>Y_BL1C@pScqFxrOoT6>R&4K6319(tXn4-*)uR<5?!mjQ(>C z{08_<@Eae(&)-iEzZDrEJOjXm9()b_2KWu|+p&C8!}5Q_I^4hPJL_U}lb8+t^X4Fk z_wb{K9+8Yp1HTo1qwX@ifA7c8i|LVpU_yp~6FvMU_$}z6ccKU0Tv!Kwx&Q3nE?$>2y8QCa3GcvIVkx5g*Ta6cM0Azf9vO;!-D>O34qjr|99=XV+u=ehoPW7vOEkLD-Id|3y%L$bd4Ot?!jTs{C@N@fVlHwB7(#^f$ z($yd1>t5)Xeg)@%F65B#3u|g7KC#NDGuV<0%gf^Y4W_)-i>0Obbh8!cX^>@03zuiD4+11TDkBh^0g`AJ7jz6`mcZO4%lfU;!Y01v; zn>wBo#Km9Bg;T^YnThf6X0T!S9zL z?)e?!`9X-vGY`%jY>L&W0S2zu$iRJ22rGXh#l{J{$u7Ch*I1RBXs0u|9-fjcuU8 zF%&V^OauOn$WgH&$3zdm{vrH)9ju;MSA2)oXuJ>jw>9RNI2v+98rEM2&ZD5K$RL{l z9YdxF!rUYTvP*^OI0iXH=PTA0)+1KZGs@6f^bp@tlihUG_r^8m;T!g+**a|me`=N{UPV@htYyYxy> zbLpM6F_K4Ks+g{kEh+=VxynHEhgWKyG{tT`G)G`PBlJ{&#zaQHlW%7ZWu z-lV%Tj|>fr_`f#X%rwBSfuHvgYvJd8z*hLJ@N3~W!_RXxT$smdyythozutiU6DMK} zY%-E-;m5>svIXLG@SEY+z;A+|_u)D3_pcXl(G41%E>K(K5S%l~ks$!T27ZEH55E&< z>U#L?@H^nYHxIYrAqf0t=%q;Xu>FpQ5g~_Q&rxqY5;lN}4B_yi56BEZ?*lT!Z-ZZZ zZ~f7BjP@<`%s>bG2sC7q8=cEklD3l{weA>3Ay30k@LSXILio+_tMBVvCA@vkfC;A4R_d~F2! z2jeM3o<=)9&Zdc@3utBfJ^xrG)*l)I4S+gB$&kxSPK(zyqtbTa$TWzhwoCCm;~81B z{#rhTY%WG`6rN}1!gfHvQ5|}hu0iLZeUKfReF$x+cvy1scjy5w!ZTsfhq$9hCdu37 zQ~cw_6o`3*A?PDg?#H#w0-VivuSBY<>kg$#W}*qQ!@f6lMz?*8kAqk(6_#P0sNB&JFyKL{|^5q@T*S#TmGxSekD{9fmwdw z{~-A9>B7h2{JX;OIsTb{^dXWQIu8C9{~}Ub@W1JMZ}JraNc#}{w+8oGNDgfQ|9!## zLGZ5u|5@N)`7ivB2J=H8BLr;e+Q*D4!M_|i1imLi=pgv-3;tLB4gYu^I+a3tC?1lX z#(Ln5OyK_<_}7B}=;srtC-~PtfPXv#oi;&hpvBNws3#^wMPq`|zWhKMf<9yy`1b|> z_7AdYIQU=i2mVKc_2Ezj)E6>9@z6Q&zhGH2YF!vkd%%Bd@IM>;uLS?T;6EDt4+sBu z*uMnkPeFU2JNyqwK|@j_|9!##7Vs}C%qI=_$Fop*AHiMr<=AETVgHZ(ui1HuOlYlhMF@s6t{+IfHKmXCu$RSZ% z5Ll)aH9$F(%!=luRyRWqfRZd4*3ifM_w_$)F;Uo5Z9@)8aGq5bNNR;I8p%~;4MesP z-trFr#s}7aKZ`)V!v$*Avx(3|bCjtz8RVX=ohmotIbzO6{vCg)|8^X|40n%T?lMO1 z=P>_gM^j=Ge-KHF9FnRpz3H0EpM3T3^ZIXs--Y`7fchT~?tP(iICNEYMi$ZnH?lWV zk}T7Y0$YaBB?J7f#J{co6=1$EWPswK;~y{@{i}j5U2aO(j)#!_t!OH3nMjqKf5%_z zf7?d(v+y$ny0#B>3vXnUtLfm$AksV)MN06mkJeK31NgUtcV7E#&}?Wp)OjiHz;;)X zBO#DX;Qx4AYL!#^(6)Rlq%BdGtJ|L|;D+*tn~n*TKL zulrN||4)5L;J+H{fL^LPjA82VOxMQx-x2(GBpY==j#wGS@1@8AY=iN8ON`$OFn&+R z_&o;WcQmAD;5mL6zjFTXjo-`Q=Q$+pNiDV`r>rgdkXw@rO_GklTrz7?z&|#AvMJA-gh!QTSu1kM@x@@GwK))9mL{HzvFN=^_MtocJMLS)9wk?2 z5U3>iLPHKoex+8P9cWi+$rTV!j_`2OAkfdAqz#qzaxj~}7eWEA3*QSf>hH6NZO_=k*kYieOi<-VqV zZl}`2Xp_E?e+&54{$>0xbOrNmAuS|_HoeNo_^pCA{n(VYYzm>N;9mp&2e`Bk)7)Y^>Rl}DrKRF?!&ga2zCaQtxIKmK0{-ubwH0c3$pP}}j0 zlm&Pwp(2p_%s>ti_&;|wmBxa9Z3S|~{=h%yo{#%E`(2?TNDb}7;I+&c$wF95yEyZKN^O894+t z@P7{cE5ZLIWQZID|9s5Pb*J|8p`R1l0omqa9R~VS*Eb?5@O%QT1pis!e=PW~1phpX z=#T85!}}bEu<06d4OWiCai|&(MJf-Y*7M>>IWLVif&T&E|I`L#Kt2rr;ou)_Uv;~{ zKY9R8f&T^QL+p(4zw2S^KgwZU8u&l*hw=Y^;lEbIIRn@WOJ$Cmqm%rp%-LQ{}K zU_pr8M0|s9lQZxQ@H-g%z6gGMfZxZ#FM2-;HQ?VJJs>z1=y(pv6w)J$#3@+FCYyxu z`&gX6zlrhtFr2@?jPv*BF@Apv{x&#&&&2tADEzF^|85?hgR3>-`v%>XjQ8j<7Ckqj9v(1)Lj^Y?&1)bG(D0*#gn^yVoCnX4>pL}!u@C5!46 zvIh(xd-yZR0eljDz->vJkw>;%1lkp1w%T2O2Tv4f@DPz+=`7O!0^bw|uD{^kFYjgV zK4UHZy+|G234O#krX>|12Oxn=x&94({P*}bR$=a6rHp!;WEf)0gl>*bZe7}b?Nw&^ z#kcK(CSfIJZ45qhVhmZ*eZjv#CLBN1cbDG^rMeYHIxWeA^n2W?*zzdLi~m58Ib>SX zB=drh$hOZ$2kc8vRK#=s?ci4n|Go47aMb)TU-TZ!705A?Q{bktsF;D6%nKH`R& zf3T7L9r(E(vO?w&B9(rJ2O5qDrYdC&>5)TFS(r)t67%WOW5u)w{4WOooclVk&d2?n zeO~+bL7Sij13k!G;!lR&kt7HI3pS)vG$J*IfdA3pzbE+THJ^*K&uhOE;<-kfpsF%# zmys&!s|&-!BI8H~{@3r!AtU%d2>wGJhW}b*2>F1$n%n$4eUQZj{!672!t)US{rmyz zQO7exe8B%M@L$t-{{LV2uL1vquns!#k1@<2>VF;hy$ODAfZuE2_cHjsfb;J&;P)8# z-H-A24)D7X{8oYAO7J@h{5}tUAA@kUiLOCckwbDBIYPf9N8~p$`J6=kK7#uFBkK27 z)bB4)zn8#24g7*_-LvrWUS6I-@;h{av_dV8k?#L3Z^e^hECIZQCM`pb z*9@}ejsgDz!9VYV=6!7Yqea@M7HO{w&m>;iLj0lYhweM~XuP*X>;3Hru=<>AF-ysi zGz&QZOVdfd z6(MgqTSmWD(IoLja%j7fEvGg3$1$+P7hdeRx{;UUG!opuaZpaf?Q$AAwJlYYj&&b+ z>II({I=>dw%j_T3F*!S-bq#rglUxc;ZP>knwHB!AR=zbqv+(oZB z)49@Ms;t8pXh#waNy?;^;D1kkF)aZ9J;6U8?{n_YL7e@A5U>3!p~_SogUj^X!{L4f0$O!(8;J*m`bLM%?=i=l3JDFzd@%sX3G|s(y`h-!|$T+(8ZW`H;L(q9+ zA#DNw^f3I-1OGa1_s$E`8j`@umv4 z+&}^2cR{Z^0q?gE_DC8Wfy+;Vmi{NW#6g15qo3gP?jxuJdLl=lgW!yL1UUfN0%b%A z=3JFvE4+g7JAanzdg%E%0zEfQpgzwD^i0Z8q5ONjd-o1@WoNMSV?v&czosuKmDPikEF*^TpLk@}mn9LAmm&j=8 zoGSsxWbF~M=4?X_&7es!vcPwl1HpcB5o zM((ThP1x%AA#KejP0j-FKN0-@4_k9s_pFxitFYERnkTq}N4)y-=| z&-{QD=i(z4WnGJ#5xqKfY(Len8TW`+&uIy1KSj&3RK1G{AvoZ6fp#T%Llpdv1phU-hjAo}Mk9wHtG0x;JS_id z;J+ID&jbIH!T+GUIRps9K4T~NwS&KE@H-1VprfH%@YXfRK{o{pL#~MYieOP)L=MP#@Ow&7 z$2tXD(q8bp1N?4;e>wP_0q-b?XQ1#blIwyISteR`S+IIs6f~+@!4Pm(Foz!(Trr0P zOVVyZov{Tu9AALnCGby$m*)Xog7;#heizIl*4h0x!RUQju=pPr)ZvE(d(2+JnDm|C zO#c#n{3`@&;YWg2Hwj)GFLY;r!#r#ZG)}L@IAVlJ_%+7ic3jXaor2NtXTcb@M=-|h z5Gd(u!J7WLpwC?_m~iFEJ;^rc7##$YTF(^B@+haY-=f5Fylhqod0 zTfq^%K`Gl2Qxb_P_NG)8|Iy<(wV}ZAzF5x)_yP>k9Ui8Ev zFKYk27q#2qMQuOyqE>^wsJM8Td-es-ris%Y4+{(J7whw0e#)&Kd0D52tj_;lyRdlG z@e2*dKiM>77`^9B;yBcNl>1u)aOt%a83dYM!kJUEl}>9_(4N+_qrX`{A!()W%?zu- zGk>fpp?F~3Rh=REvTix9^HqWQWm{CV#IB-`QTIOr`?D=7nreE&eSF(`-;v6l5vKK% z63PuD(o5}ixfsM01rzw+cU|}R4)hyyf%`TX^S4Ib*Ma?l+2{>6qrb>l<{erzGE}YB z#nGOUG~}7)Q2g9NT%SOW=)>^8ONQF*k8|&6a!tlH%$h8!0RI~Bzw%-EuSSMQIrtw0 z{s)2o^4mEC=p%kO{;LIez<+HF)&u;H1pm7l>c3IM)jX(NG(mdSTeN!gLJmO>(HPK8 zG>3OV4o3&kl2j_HGaeDGxy7QrFhkVqV$lQU50y7~xnIlkOjs|`{c|A)0dYMQdRy{1Narf$rpx+|D9#3SC8mJF-xeT|}o}N6{8mCR$=17qv;P z(Fa^C8gjElOJSm@(S^XPgu3_>b-`!g>MS~_lc;s;C|bSBkV8-^x$r@YnK&j9UI8qZS*XH)Ny>n<^B)zuTkmr?1p`XPyqu{MHtg zDq0ibM1wX=H0Ai>dE_4G1HK0D2`J;R2c`c2ZS)}R2OgBx-Gh?r{oN8@|H(V{lP=98 z{?{im_{vxD%?d`Pd5X?#Nw5}N5R4^Gcy~ZS$Q=mUrl95<6%_c1f&$)Eknb}~geH;s zp59-`{do?FP%=I4+T|{(=eI^>AMKT1@B=Ql+TmRaU7z7a*WdG^Yvb_zQE-2`8+ww{ z@f_02XWY&#@7Lt`V`oAS?azzBu%8{*o3`i>JC>XgGfFcn;4me%hP1 zcSFxWdvDr|T(eDn-emu62d(?G&THjM$wAA60nygMJ(8w;e;{MD_l>-lLKVe^m#^xy zEiUQaU4;yzPod>1ny^qsvE~x35;-i1!ISd#OHl z|C;*LO#|M@Szb4(@co{1bQR`0-HJN&2|%AhJX5F&S`2*z&4esa4<^^9mwlM@nRs^*SwH!<7c{?4U%5=a^}rK*$F|P8s<30slJiUk3imZu5Wc zVfps~|1~%U)qwwS@IMIr-_9XL>OFCN-XJrcHRg0*AsW3u6)pbNqB^`vw8tz)AO3vs zHy8X>g1`5`-&pLwZ$P(wxBaV-L$Xq|xql{VyltYv{}bf+EJKdRBINLVBs$XPh{oIx zz~5x>_YS-xpp{te9jy?Z!e^r1-6qAYS_?-s-yYTZIf??37 z@N?N3q!p@>LxL;E$|_OqhdhiYD0-(doHJbT(TcnnOPnozd_n&Oi4O#NPM^wHdt zb90~no^zgiJg@WSzOSFmSNOh|f$93Rba(gj(w*VJUcY$cy#YV(+%oiM*~tgplx;rr zN7)f$uggxh=Vx~`hS`M^tF!09!o&C$*Ko-7l5XkDNjLu@C;fEvv>rdXM(zKj>mMBa z!&Bu0uYL8}L#`g(G-hsg!;wLDVdKTwrZ4sYOlSUDb`P{%0vGm?7M$8gx@L4AY5wPL zO7m7+(dUZ8j#9&`v=Ntt7ZxjaOHMmpkpo;|**MjCrzjWqhC8tJgn@Af$OieT^V0LST^jY(vOecUy9lBQQbfEF#HA{gz7G$`(Xtv z?V2tBqHDH#<45Zcn!mB$`oWJE9C7lu7Br53wdd>fkJ7&r>X!J$wO zgStxj9$mK#e}DggLtoin->{KAg!k=V@BZ|Kv{e1QW+kkEd*PSR3U|OQa6MeLf2LI4 zzek<1f5E|%_U{=zcK^wa_T?VJ>dRm1{vVcQhVt$3A@ZDlgLw^oL2em7h-Xj+$hD*L za@)9`GJpQXpHJ~`55IQ1;Okl5cz|aJhsqmz4w1+9)7V46UXtMh<>4`GUOTfI&P5T`P}0m}l1yW3S0Lndf--^ZEB9 z=HFrVb*S!7`HF%(xw=cGhsqv%He3jW3p~pPFXu1fF z1)c-SMEqf@$0Q7JrY>(AZ<>Ui}x;~&27{G(TII>%kfY%8pPsh_ld6NrA&Bfsk>b^NNI^!w}kNx$Re2M-VY z_r4GP=Iz02CPrWEAz4{-al^82$4A}u?(SoLcJoK28#cXHx);~)WtZ8#XV*ygu*>XM z->s2;Y1c?ghSx}~@AmI;_itJU-hRnVBYu{9?vS7U)JE!t*!w_ zZ|hp^ZhR;$ZRPieDlfx}@F&;;&%u*W-IG@R{b^O#o&$c_HRj-3yOxe#&{gl8*LBM= z$Fhgy67KESER+JCK?>O8Gh3c>z$|&oFrW9K^>_~WBAz2WpXd0Rd5&j>EPe3|{z*KC z^!2R7>||)`F$e!<%VQ6y$jgS6d5+n`zYFp2Jp7ya<@^+8PlSMv{}pri@f`M$%$D2w z&XP9_^5y1X7t32l{(wCI7syTH&gD6#v*pPX*k3TQ`V9Z~U^X+~WETEb@VAV=7vnFp zBQNAR$n){HnfKB?i{}8R^BmAA%zhVq=BsedFL#l&WcirAJ$Z|Akvu}bP_7+$KF={W z^9;=Q*#mF}dpxG_e#X_ap8!8#?kg_h$B?;DZt8V`Jfik|dGFA3d5&u)&oQ1Qj~#ou zJlW>IyYVF6kNn@5ZG!XmuzMttq;uP0fh3(%u1Ho}ah>_5H%&g&tac~B4OjK^i^^ar(c)NPrc){!fBW8 z9WhznQv7$GL;enXM2_SA&`Z1@@=?r=gUJ(mOOsi(dos@up8QEK=_H;bJh9A9o>yDO>x#-6=ji2<^ok^!3Jl-ik_4 zn88lNQa@=l&m$kcJui*AZB(B_ocv((@y3G=bgnvV_>G4)3|;i2qYijm9FyPuK`A?F zZ%H3tBk8<6Mjr+B>@&>QNJBs9FAd?Z?X-KkvImqaO6{O`>iey{`jA}x)nlcZGn~(^ z8hXs$@UznH$9Vl9&mUGvPXhLsbx-8;Kf8@SA3i|(lwD>Y{pH<0@BL#WjKr|v5y`1uu`{CFE|g_q$4_~YjbGS79MJm~4Qn-6^angyde zCZ^+m^Zvxf2X4N3;yt%^ja&uyLj)_~p6*hgCEcZAcXiJ`K>x`a23pj%V2i*=0O*CuOG=r@=JV$RJjWQ}-+wp1j&tyF<+XBipEYtb^DWFz9=VF=kROnD zjJ;28v;ULl@R!S5CjN?#y#%T=Yrnx7d2)7*+}68IUZ(K8y1trMvNC&U#B+@7HL+LX z@4a%{#AVDbhOhRZ@b7-H$E1xN0B!QZUaRFfwd_-=dw@M65zj$#?y>*L9)RUMNBAqA z1FZhHSD%Bg?jQLk)tw@cV-HJBBuhi@V-ErQTn=3+Zy2*&uC;%~9)P7h2fT>cJAhZ( zvA5(O`89hCIBUQElqU~fA#X62vq$J2xpvGiEo!v}dIiEKXc; z9q={8^4=C(z_e1|Fvp2w< zkN1)8To3E|NO#-=3;IaEn9h444Eii{dvsL)+Xf7-`&sejkqb9JH0q{%293YbQI5WW zJtEgKdo|p=CokR1?tz=}{ibJNHC&gMe#(BM8`HOX{rH~W6>b=H_ksVhw9jGJZr?g? z{%wQwo+>&6^-?8yU0l?JRHe{_3IW5a2)CR(ezc%bm_`;Y7|^GNatXn=7r2COvgbx1l> zADO1b`gG>Fq3Qag2Cbj%_MMrQ2J-*^it7HNS{MNRp}Nbc7gTo@rQNd!e%@Ug`C<3= z!{6y%ZSU+p`It`pe}}vGw{P&a+?0KrXW-vrj~>s-*RdaD-e(+ ze_r9|K7oInm87@%`uA+&4tCFYk+{4=xF=g8k;_8-~HPL;8}{wmkj z@~ryM-F*IK_RyVt{(YU#zpwH6_fUG|CL?rLVQD>+X6(8@h)oG}Gd5|&eC3(xiFS3V#x$%EwkH}{B2t3E^)9@mD%wCk? zgWl4MFGJK@dVyVLFZBA6^ryKG=bvAh8@lDZ<4113?buP97ChSUjJ)Hhr`aPSn0*{J zv2SG41Q-wXdFeSBUhXSBx3sVH>}eP0{_w$}>eCCh8Be`@=b>W#4db53f9yP3f88;U zF#9{$cxiuW<7~Kyzc-u?#{$nLKfbS@^w|2dq(|p2uGui?--kbP!=mEvx8FVHcXgfi z!{eWx@Zc>Em)b7&Aby2 zU-kA`M@AF=*7$3uuC#p6=cW5`>kD}9`2J7$oQ?C*>+BW(6Z=2b^LK$u`5ZoPcJ1<$ zXB+ouOAlMN`K0l!b6-9Bu6^#r+e=-gMa+MbyZOJX+y!^S9dLWPAa`3jvuK>&31J}X=m=9N_+iT~hOAop|8x(*GM+!*QGEuUXV}|@rgC+M#AKf1ujLu=CZ40;!E@{j|C{I7o2$>SGvC5| zbq~l0=Bs-Es(U!9^IQJKeD(SFCgy9IukJzE%QNgFnBOvn{BpkKzxnvp`4*mkukKN3 zt3E@|{0^RBU&g$|d>bEs&cB$S!ybgO>_OPV9)nuuTbOTRegk^|7BWBiU(D~w^6#<7 zU=Di>n%H9?F~5a90?o`fGe6>A%vX1SG_%KG1bYmm5q!Mr9unqvut#77^EyZ3;8)5!5)Lj!#Rh^e-C>InwW1pnxBiW=O1TZKm<3!_h1iuNUFO?+N*mE=J0d4 zw~o1k`FUUuK{I;@nwX#b^*k^0{bKh>L|zAz;BEF2oCmk`?3*L=B$ zU>SP|c6_l%pc{YFdF&pT3$tN5On^b~a&;fU(>>CI&KQ&~_;f^ioyHx=jY}8Y<8(dT zbj;_>ep;R1&c1=9x^n=kdq?nC-sPx|fu-l$>w*7q%bR@ZmTC#PL$ zf7I*F2_LlIUV86?_e!5Es*%3n4)PYbu15NJHcYRPK5}ZL59Momez3knd;g-=k?+0z zthHzQ-;Q`^ZhPZfmwrBR_oUBC@36P*ohQF!{Q&824+Fag-oAtVAM-#2cGy4txE&cN<=-Uvl)T*A1JPMEgtIar3|ODqWRV;Lnhx+k14T^+R7y_n0qj zpE>r0MfFGhaZGkf?7XJVLmCbZjHo}I4;1NkiycY!qv`eu9skt- zFYXflY~lVl;m>65e;fC=h5OI#J{G0@$r{&cbnNmGJ^SK_&1r4FY)oKdpue=|JZ*qzYu@N;%_bf)-t~X|Jv|x zGV}ive`_;*T>NcT`QO3cIn0k`e(#t5?)}=If9h`a*I-UBKK39!HvVqF-xmCx!~7Qf z+web_Z>#CymFo&PRg+pN^KOV*T*&`w` zKjQ28$Jsry8g76|u$w(3(}6#1q|w0M>2>cF()#M}!L`*rMC^iU!vAGo?-5yq=XX?H zhq=I?9nvBs>>w$>nN8PESJG#8)u+c^en?t>-q^Ig$>D$N>-jPGUIbiE^YAviN7loQ zP=f7m^-as2b?J7`Ovhh2I?W$qr}fh&q<=d1?|Vo}>>1$|;VG`CW1t>n;3c;yf0jt+ zwaRI+RZZ7Fdr&&TveLQpj!5tLNn?6jJTd*`6ZSCiwei-GhM90OIH19vRsGWT zS@r4MS%;?evl`Mx>>=6yXE)uw?|-<5B+aJjQhpzuX{L+Tk4aD4?4{3B z`m@KxKzaT+!5+eN_5bc6k^grO$^Y&l`TzGGlIwoQqZY^ge`OB|5AyN1-@E`bCw=jz z*tH7J%4l>t7<49S@m+!jl4t4K8o~YIwd_-Ph+qoyQ<`OI3iDHVQ|&3tPhoxv^HZ3g z!u%BGr!YT-`6Q(h8l4V2NAok2w4}D6fpny{HI3j(ZSR$&oxBiX z=cyTKC*S4R`B+Zcd23$UIZy$OP6wXDz11WwY3C&kq$BNI+X$|-lh@Mn9D;Nl&mSMh zcRG%HA}1Zk8w($IfC3tw4h9|1;h%3w$6eMyI?{0uHUjU-%d@zwEs&m=nvtHkK$f1^ zn3JBkJnP2G4CE9cl2xJWIrTiVf!P;dwuH>Gabx(&>CR<@Bd=(&=~RrPBv1 zpwa1I(3zwqoqk0F=}4#lmOUE3b*0mJE%3cO`*`me8R=e+{V7lLKm{*Mx_5{I8l4UX zok?2Ky;nAnj&yI#E`yk733!%xFkc7_p27Lcoc|flzlihKasE2aU*`N}&cBHBmpT7D z&R^#I?VP`z^YdE5#XR@4_^gbynC~Vnel{m9UYwT}>k4ReIv8{&X-SK(ZXg|L@$VbK zl@{|l!s@e+Tffi!t8o9G{>u-9Jl~?&o#S_b+Q@n6M%75`QISMguPf6(Z3 zFz8IuQt_X3RQv~5#eWt5Rs2`+U&VhF|5f}4jZO!H&Lk}r|4B#1e{fa&SMguPe--~# z{8#Z`#edM~bTH^l(o*rCbX5EYSH*u7|5f}~@n6M%75`QI2aQe#gU%!^75_;`#eZ;B z{8#Z`#eWt5Rs2`+U&VjW=yWjXOwv;EpLA6G2Uo>^75`QISMguPe--~#{0EIr2ZPQe zEfxPsN5y||Rs2`+U&VhF|5f}~@n6M%(CBn9=uFa5@t<^5{0CRXe--~#{8#Z`#eWt5 zRs08yP6va|BrO&HNk_$ha8>+Q@n6M%75`QISMguPf8hLO&R^#Ii#UIo^Uve_WzOHu z`P(`FzLJXnD*mhZuj0Ro|0@22MyG>8XOfnR|D>bhKe#IXtN5?tzl#4V{;T+};y-Zz zD%`&c_pg=vSK|5f}~@gFog z9Sk~?v{d{j9d$qR_^;wW52i{s{_}99Y~#O;|2F=EMyG>8XOb2R7#c{PMQ&>ZxB48P zjsG_O+xTzezm5Mk{)0xRgF$DKmW}_UW8*)#HvZfAZ{xp>|2F>H_;2GsXmmOlbS7!p z_)j`E{)21dzm5Mk{@eI(|2F=EMyG>8XOfnU|D|2F=EMyG>8XOfnU z|D*K$V|33cv`0wMt zkN-aYgGQ%=L1&VdkN>3O<3G4Q{`>gvgv8XOfnW|D@yNKe#^r`}ptU zzmNYu{`>gv<3DJ0Iv8{&Y5Dk1IzIk`>*K$V|33cv`0wMtkN-aYgGQ%=L1&VdkN>3O z<3G4Q{`>gvgvNo;`1lX5kN-S= zC&l<5?|)4`xK zNh`*G(uwgO+!+63{EzWJ#{U@qWBiZtA2d203_6pvV*Dqa82`bI@ju4@82@AZkMTdo z{}}&4qtn5lGf6APf6|HZAKV!KWBiZtKgRzU|6}}*@gFog9Sk~?v|{`xof!YYjqyLm z{}}&c{EzWJ#{U@qL8H^bpfgD;#(&a@@gLk6|6}}*@ju4@82@AZkMSQgIvor;leA*| zC!HAo!Hw}h#{U@qWBiZtKgRzU|3RbE!JsoqE5?7)iSZxY82@AZkMTdo{}}&c{EzV; zG&&s&I+L_w{3o3l|G|y%KgRzU|6}}*@ju4@82>?|)4`xKNh`*G(uwgO+!+63{EzWJ z#{U@qWBiZtA2@%R^OrgQBFo? z#;FaY+N|C~vH71Xp?E{gQHg4@o(GN=7;U zd|5gEiJWr$&-2Rh2PmM?>0r>Aq@^5xSp(@P$3NHzu5$c`C1qnzN!d6xqinoDRyJG&&s&I+L`Njh8o&j|&gd;EXPll<&iH|>obgmnIpfZ}a>if726suDr5*hyog&4hEe`TFUY( z8%Rf49yfxkEdPx2=Q;lj&R^#I&v5=loWG9q*Kz(b=Pz^qMV!CP`R8%|GUspS{Oz27 zUrA~0Cn>FGWt3K5R$8CUDXok1N~^AbMyG>8XOfoEdUXToD6PM51XpR@&;9Gq{rf)m zufqL%j{Dcj{Ts&p8^-;saQ`aYzgF&Fh5I+3`&Z%qb#VVWxPM(Gh36lY2hPqY56qI4 z2R7xD2bScO2Zk%4(dl5&nWUvWa7_d0C=Wc+2(I!#cS+${N2M||qf}d>8Xw%y%*0#e5g@UCehe z-^F|v^Sqy`!gB}#{s;IU;D3Ps0saU04;q~g2AxS-0sfOtfdAkI_#fbZfd2vh2lyZ0 ze}Mm>(dl5&nWPoqKj{Sc4{m_}0saU0AK-t0{{j97_zxPL4hEe`S^@r(PJsX52KXP~ ze}Ml1{s;IU;D4}2Q9z^9!JsoqE5Lu!3Gg4>0RIF05AZ+0{{a63{15OSG&&s&I+L^l z{3o3N|G^FLKfwP0{{#FF@IS!+0RKUw)4`xKNh`pA(h2Y%+yMUr{15Oy!2baM1N;y0 zA2d203_6pv0{kbP0RO=a@IS!+0RIF05AZ+0{{Zzsqtn5lGf6AJf6@u?AKU={1N;y0 zKfwP0{{#FF@E&cCk|;D3Ps0saU0 zAK-t0|De(7V9=SQ72rSV1o#hbfd2vh2lyZ0e}Ml1{s;IE+`kIla9cDa0UJg{1^By@L%A+z<+`Npwa1I(3zwq@Sk)9 z{(~#!~@L%A+ zz<+`N0{;d6gGQ%=L1&Vdz<<&a_z$kYe}Vr3{{{XF{1^By@Ej=+C# z1^x^C7x*vmU*NyMe}Vs?(dl5&nWQD~pL7KNgDdb~;J?6sf&T*k1^x^C2hLyS{AJF+ zi1U{@|2)oL=KSrPzn$~%D+&A;_%HBZ;J?6sf&ZY<>0r>Aq$Tj5bOio`EAU_7zrcTi z{{sI7{tNsE?q7xbSKnaKS7x*vmU*NyMe}Vs?(dl5& znWQD~pL7KNgDdb~;J?6sf&T*k1^x^C2aQe#gU%!^f&Zi<@E=@({{sI7{tNsU_%HBZ z;6G?|Iv8{&X$kx%9fAMg3jAk{hE&K-&J?oEav{4RSI92R7qYbqXmmOlbS7yPvU3_p zr;u%H1h>F*q=jkBPh)->^V680#{4wqr!hZ``Dx5gV}2U*)0m&e{50mLF+Yv@PUbtA z?_|D{`A+6LneSx2lle~OJDKlfzLWV*<~y11WWJO6wHc|f_LNLv?KyH`?W4KE+MneM zYZV1FIvor;le7wJg9g$mtXTDrm*W=xv=Z8Tw&L(`NFP&3TSjX z7<49S6?R?HKstq8Ya78W?0UacIH8ABIAKbraKia=;e;o0g%f_BFPw0I0veqT2AxS- zg%d7oAf3Vq4>p2ZIN`%mLG+XgVrr%!E|3diW3C`>&liNMfJUc-L1&UyL0sNIItB4i zBe(_eQK>MrmsA)!JyRHZkz5%1WUesuj(lOLrhrDLgF$DKR$=Je2GS`EeYg?a!q87j zg)@6gg)>jj6wdsCTsZToT;a?+^Mx}9E1=QoV9=SQRXFpC2GS{<`P)Wt3uk^>Dy--u z6;_;)DXj41!iuMJg%x+@3oC{wpwa1I(3zxFSaD?o=@eGPjo=nme8&0noPP%AFLVB9 zIR7HfU&s0DIDeV*mpT6;&R^#I^EiK*^S5*UcFw=AR9M0u#3g5C3QK&su;kfXVaeir zVTrDQMyG>8XOdQ7$<+;{Q&{r*MsN#DSP;_LpZoWH?q7xb_Z;`HmHRi0`!|gHSKN`+N5QeoBEnZl}Ba$(h`Tw&Fcd|}ma1vEMx3_6pv z3ahSZAf3XhM;gH`tm-Zmc=ow4Yi6b}YqngNwK-RqwKQLtRj+_Xr-MOfl2&2Xf(Ftl z%v#?FZebSw@{A$RDQ61Z%y%>2&3rfW-OP70-_3kC^WDsMGvCd8H}l=h^Bj_g{~rE( z`0wGrhyNb_gGQ%=L1&VdhySGG;Xk+@{(JcE;lGFf9{zjy@8LgabUGMxCTV&2PdXm{ zgX`hHhyNb_d-(6+zlZ-G{)0xRgF$DKmWThO{)6k`zlZ-G{(JcE;lGFf9{z(yr-MOfl9q@6q~qZ~xE}s{`0wGrhyNb_ zd-(6+KWKD17<49SdH7E{9{z*t;lGFf9{zjy@8Q3P{~rE>MyG>8XOfnO|D@yLKe!(L zd-(6+zlZ-G{(JcE;Xi0}Iv8{&X?gfhIv)Om>*2qL{~rE(`0wGrhyNb_gGQ%=L1&Vd zhySGG;Xk+@{(JcE;lGFf9{zjy@8LgabUGMxCTV&2PdXm{gX`hHhyNb_d-(6+zlZ-G z{sZSPbN({tU&Q&#oPQqYFLVBO&fm`Y_mw>S_we7te-HmX{P*x5G&&s&I+L_K{3jg` z|H1X}-@|_o|2_Qo@ZZCK5C4JtSKN*?}u`0wGr zhyNb_d-x9;oel<_Nm?HMla7b~;ClG);lGFf9{zjy@8Q3P|De(7V9=SQ<>5c+c=!*l zhyNb_d-(6+zlZ-G{(JZj8l4UXok?0A{*#V}|KNJ~FYsUBzrcTi{{sI7{)0xRgF$DK zmcW0~5%>?Tz<+`N0{;d63;Y-OFYq5UIvor;le7f>la9cDa0UJg{1^By@L%A+z<+`N zpwa1I(3zwq@Sk)9{(~#!~@L%A+z<+`N0{;d6gGQ%=L1&Vdz<<&a_z$kYe}Vr3{{{XF{1^By@Ej=+C#1^x^C7x*vmU*NyMe}VtN`T6=E|LHhCU;pDj$@%&EAO8jZ3;Y-O zFYsUBzrcTi|De(7V9=SQCGekg1pb37@L%A+z<+`N0{;d63;YM}A7B6DKOOgvumAC% zb_E;J?6sf&T*k1^x^C7x)hv zoel<_Nm>H`Nk`y6xB~wL{tNsU_%HBZ;J?6s(CBn9=uFZQ_)j_l|G^dbU*uK4MR{_j zC^ySRc|)$q^K(VHRsoGp2ZPQet)e`qfpm&I%Li_e=fH~7nV-)5bmpfsKb`sM%ui>2 zI`h++pU(Vr=BG11o%!j^PiKBQ^X%X#Cd?)tCBcW0&I z?o%_x-RH{1-H+vpyKl`GcMnuRqtn5lGfAts`;rFIDehj|2ySur`=#Qf9#V1AluU8b z`Eqg66S?A~pXZB{4p2a&)4`xKNvk;NvIf#API|Br+~TAUOT{O9O2sFqW{OWG&&s&I+L`Db#og?r&#xJBe=!7PfEoZy`|!e(=){xKah(vp2`(x+?g-V7_5Ls zr-MOfl2&oX6%C|QoblU6aEmiOEfrVxk%}wN$P`z4a&hI;x#G&Z^2L=y6wv5&Fz8Iu zDz3b;fpm&1<3@0cD?j7>dCotB^OrgQGn{`B=da`Zb)3J<`OBPt5$7*+{&}3g%=z0n ze>>;jS1K;;Cl!~Tl_@Uu<>Jz3bH$~L^TnmQ0veqT2AxS-#ids_kWO*w?;F7_F5S=l z>(BlBKKHM}{d`Za>EV;OPQ?9srNxryxxB?oT4hEe`TE*4ZG>}el^&^eo7FTzdiafVeoINvBoIP7E z&fc6W&R&`?&aPKLqtn5lGfAsBdqD%~6lbq*1h+UFe|g5Rm@=O-pE92^pE92^pE92^ zpE92^pE92^pE92^&qGNe{)hM<;(v($A^wN>4;q~g2AxS-A^ww2i2vY*_#fhbi2ot} zhxi}je~AB}(dl5&nWPosKk0<{4{nJ6A^wN>AL4(A{~`W|_zxPL4hEe`S|R?EPKf{D zhWH=ie~AAf{)hM<;(v($pwa1I(3zwa;y>wx_z!M~{~`W|_#fhbi2ot}hxiW~oel<_ zNm?QPlTL{L;D-1g;(v($A^wN>AL4(A|De(7V9=SQ72-eXg!m6`i2ot}hxi}je~AAf z{)hMv8l4UXok?0D{*z9K|KNuBAL4(A{~`W|_#fhbi2tC`>0r>Aq!r>n>4f+XZixRO z{)hM<;(v($A^wN>4;q~g2AxS-A^ww2i2vY*_#fhbi2ot}hxi}je~AB}(dl5&nWPos zKk0<{4{nJ6A^wN>AL4(A{~`W|_z#@F%=ycle-Y;|bN+dpzs&jDIe$Cn-&YFpKg9nK z|3mx_@jt|W(CBn9=uFZI@t<@;{0BG0{}BH}{15Rz#QzZgL;MHsUxoWu;r_L9|0>+S z`P{z>_pgKd*TMbkDuwtT;(v($A^wN>AL2h~bUGMxCTWHEPdXv~gB#+1i2ot}hxi}j ze~AAf{)0xRgF$DKR*3(k6XHL(A^wN>AL4(A{~`W|_#fgwXmmOlbS7zq_)j_^{(~Fh ze}w-L{zv#9;eUkx5&nZlr-MOfl2(NOq!ZykxDozG_#feag#Qu#NBAG%KWKD17<49S zMfguT5&nZ4;eUkx5&lQ`AK`z5{}KL!MyG>8XOdQg|D+S)Ke!S8NBAG%e}w-L{zv#9 z;Xi0}Iv8{&X+`)?IuZVZ8{vP1{}KL2_#feag#Qu#gGQ%=L1&Uyg#V-y;Xk+${zv#9 z;eUkx5&lQ`AK^b}bUGMxCTT_ZPdX9)gB#(0g#Qu#NBAG%e}w-L{)0xRgF$DKR)qhg z6X8F&5&lQ`AK`z5{}KL2_#fdvXmmOlbS7y<_)j_!{(~Fge}w-L{zv#9;eUkx5&nZl zr-MOfl2(NOq!ZykxDozG_#feag#Qu#NBAG%KWKD17<49SMfguT5&nZ4;eUkx5&lQ` zAK`z5{}KKJ=Pz^qGUs2!`OBPt9_KG}{&vpa&iVJ1BK(i=Kf?bA|0Dd5@Ed1lTL#F;3oK=;D3Vu3H~SepWuIj|De(7V9=SQmEb?= zB=`?*g8vErC-|S>e}exB{wMek8l4UXok>~={*z9E|KKM0pWuIj{|Wvl_@Cf^g8!h= z>0r>Aq?O=5=_L3MZi4>_{wMgK;D3Vu3H~Se4;q~g2AxS-3I3B#g8$$q_@Cf^g8vEr zC-|S>e}ey@(dl5&nWUBAKj|d+4{n103H~SepWuIj{|Wvl_zxPL4hEe`S_%G>PJ;j7 zCitJ=e}exB{wMgK;D3Vupwa1I(3zx_;6Ldk_z!M^{|Wvl_@Cf^g8vErC-@JXzs&i| zoPQDLFLVBRoWIQZ+c|$b=VuQf{wMgK;D3Vu3H~Se4;q~g2AxS-3I3B#g8$$q_@Cf^ zg8vErC-|S>e}ezO{i|^QD%`(T?q7xbH=p}g;r?}S|2nvTU8My76Z}u`Kf(V5{}cQN zjZO!H&Lph_|4Apoe{d80Pw+p%{{;UN{7>*d!GF-`bTH^l(n|23bQ1grH^Kh|{}cRA z@IS%-1pgEK2aQe#gU%$a1pi4V!GCZQ{Qvt7iplJpXl8fE26op}_vh3qzz&XP9oWOM zkUbd9?6H``9*So6KvZ}6wEcY-1^%b_pW=Ut|0({b_zxPL4hEe`S}FdMPKy8Frud)Y ze~SMp{-^k#;(v<&pwa1I(3zx_;y>x6_z!N1|0({b_@Cl`ivKD8r}z&Voel<_Nm?oX zlTM2N;HLPW;(v<&DgLMUpW=Ut|De(7V9=SQmEu3?r1%f)k$At9;(v<&DgLMUpW=Ut z|De(7V9=SQmEu3?r1%eRivKD8r}&@Ze~SMp{-^j48l4UXok?0L{*z9M|KO(hpW=Ut z|0({b_@Cl`ivOU|>0r>Aq?O`7>7@7%Zi@dY{-^k#;(v<&DgLMU4;q~g2AxS-DgKjA zivQrI_@Cl`ivKD8r}&@Ze~SO0(dl5&nWUBCKk20S4{nP8DgLMUpW=Ut|0({b_z#@F z%=ycle-Y;|bN+dpzs&jDIe$CnXO9Q|r}&@Ze~SMp{-^j48l4UXok?0L{*z9M|KO(h zpW=Ut|0({b_@Cl`ivPg;e#s3ul zQ~U>wP6va|B&`(xNhigBa8vyMVs8olr}&@Ze~SMp{)0xRgF$DKR*L_mlj1+PDgLMU zpW=Ut|0({nuOy%1KWKD1uzQ4g{7>T;7NHd?}QEB;76DFSScg z^H}~a=_4td8IaL4hh&b-d^_{+nQ58kOgVFTW>Js?X5Y!am;EUFS(Y~hl6%O#<$i23JwVpvI=NmxP&Vbmzc0^}&ymlQFOd2EnandN@+>x~ULs#6UoOv; zuaxJ>SIgJPE%LSUb@C78>*XKGKap>gZ<23e-|?;TZSw8%9rB&>-SQ&2RbC=5lYc4S zBi}2pkXN!v^gj81`2l&A+$OJKH|vA)L-ND&Z{^>~?eg#C4tc%2L4H(zTz*2{C=2;1 z`DytN@-yd6RQj`i?YJI#-${T_xQh{apH$v|8$r{vf?1y)NzLz0LY&24@b= zjOYF4PRg9cJ-9M+L+19(y_vO{4gA{wIrBEZ=Do6Nc4W4J_oFx^dv5m9><_bdWPi=C z+;iDivwQgU87LntJMwqe19=YL9Y{mL5Ovv9d>d zkIg;)(&OVE{d<}{n|hwv^U|I-^<2?&L(i9c?&+D!jmS0TPRmtt*XNeyewRyfQm=!1 zeW%x~UJHA*^?JV7C%x)=H}$@t_m6w8>iuGGsn4iBQ~R{^iTXU>=aW7o`hKtP<$ag+ zeWve6eMjU^%(vv%<#*+W_B*j(OTTsf_VzRTpV|MW{u}y#(BG^%v*xCn4K*Lsm;;&z z+&$nq)_jhyom0D_wzIas(xkK~>y*8UIq=MZ3kNZ3L6TNHeQ>fwP|~`v4iIfZX3LJ@Yo?OLpBVNhBggt8MK~x zgC%pB*;L$7Y&m4ap&JfuIc&tJ4WnADro*Mt8%DQ`X&TEfZo`I#W#e0pXgRXQZgE|HnV)Jm-7e<@?1j#tg$SY%{xWXGtix2_=+;M7bvh0gBL6l-K4m3(cpZ@<5%ItJ(j(HV(qie5B+Cut&hlt^ zseD9ML?h8fj1>#S4slXs3sU}9-`V1<*dV5e&Z3G)m*>fSWPdqBS}6^cq9isz7uX^m zMq5uqWR>1?%rE>>`citj@Q}k!iFgM|kI6%*gJVe{$s~6uT;ibL-Tqtk#G#!ilSCdx zrMYH)5B;s-!gfuD(*dQF>sv~>UZs@lQcAhzrId>*rQC1(@h|P-SIYXlb-AA{P~5Nn ziFWx}(f{#`N0I(K$rMdAztbB##X6(Ch|AtTM&tU!bJIr;IL+7{|Mzua&4Q2$1^z@N8(gmVv1aO-6zS2B~o#P3d0+%KwirLy?; z*2_dLWOB-7OTB&}XC)h1o!=ReGg7+5Zy)i?`Qesaw#07(<{AS{k@=mXO#4NBw{-Fm z{8mt#Lbvi})5;R$&Ix`is7;|1h2Qa(KEF7;F`_La#Txl7lfdH7t$d^S{}}^y>c+7Eo|b?uv7C51gr2As_N3Kk~;fM8On>UzB308MUO= z_zkKfb*65(=Ajq$p?;J=gRvqv9KR-wp>Z^xl4uG|r&*Lt^JoDrp-*WQeMXQXJKuGByZl$uE4QnYlR z^nmoB)JAHL6@$m5$E7Ewr=-48f9W}Ci1d>53a&vJE4?92kS0r0rT3)S(g)H<(n4v8 z^r^H;`b_#<`a=3j+Ai&u_DKh&Bhm@!wDi4nUb-x0O4p=3=_amTG0IliT`ntEkSojH zat*n*Tu*K&2gxCFgd8I`m7B{C$!+C_G*J}RG-zmtEEFUUX1SLN&S z4Y^R3g;7|AyC^Fvh|0oS)DX2rJ<(7Ei4YMXVnkEXTs$P&iigFcqO0gGdWxsTvtpol zUc4w?79+)I@w#|ROcL*icg0LGM|>zg7K_9(u|lj7>%}IqS!@+M#a^*r91_RGDRD;p zC@zXCB1`0meBr=agFgQH`0Men$G<-R>+`?9|JV2b`thHB{HGuP>&O54`JaCNr=S1p z=l}Zp&%b;9=O3{MsVkvdK(~Ny0o?++1#}DO7SJuATR^vfZUNl_x&?F#=oZi|pj$w< zfNlZZ0=fls3+NWmEudRKw}5T|-2!)Q0sZ=a{rZ3X`hWfUfBpLZ|DV_Y^E12n2{imv z8x!sYwBV^auH=U2?AY;49uKNO6{!+=QB|r&)u|@cqB>NU>Qh79BiNXlP$)&dNI*$7Vf1rz$fx887;Avb2$tu|-58Nr}E&1X;!A4TB z6d}dp9>G>p9G*zs754`|E%lQINiX8wz|qn;X`=KF?hAZhnuogrm*V-&pGg~~&A20Q zkF;MpES;3jNat`j;8iKN=w3jR?1no5E6P=HA7C9k@i|a#g1Z1!`F^>j+(vGXdjPx2 z-Q`|#U%5Z-0DMt?8BaGHE5Gr#-~ZQ6bokru|I^1`AAddm|KG;H;;>C{J!?H;@v^*S z_B5|EJ!7h6I&WNQ9Bb@iY;3d}uNd|jRvBg*MjQGW9yK&IG%{2*xEczSOUemlukwYm zMp>rJS7s|ymA8~p$}r_QrLWRMc}#g&X{9`%#3*4(W2J%Or}!$>6fdQsQckfeZi-bg zDMm#o(*NvV2*3_gf9n?bAGd&2ipMh@3^>l?j_|R7gwzVMfAL&H!m(VppXCfrIah4C zU9K~p6JaIqqWY}(o}ZOy!!r?Ym+OcpN?7r%2{YcdqW=|WVg8j|9G*R)$$22hx>dse zx7XJe$DOXu`u-#5`YXAXc%H?tTbdYqSR7k%r0 z#{v>o8E*Yig_StB{k@kiSF&~fYP*!&ioR91z};DZ{j>{ymF75)|DCE>E(*`REsb1| zQ||ZvW+&HIdb#AHc4PlQKW{v#m-X}cL%Ck1l#BbX%l(e(`d7LI{3Q1 zto#?MN-O7qv*15E=jZxLBgcP1>z^*i>*%S_^Y>odkJ8BfULE>(x&{8M1vt)26Gx?u z%fDLgPU5^Y^AOipS~*^q{iFG+wDDV7xj#FOdO6(!zh{AJ_w422VYizV#ca2Gc-%83 zs#UosugZ9NdU|-6jYhMFho>ihz9)*@qeeaPs!##rkN(^36)N!Od!vfSJ$l*sWi~1b z8vw6+q{iRgY*FWa>%U_C|1FWfUBP?SK-sc(SN4Bbd)c!0ObN`v_vqz{*RApA+&xml zZg;;|uV426UTNWe&kWBEWBS7ccu!UMy<;Q&JKX}h1#}DO7SJuATR^vfZUNl_x&?F# z=oZi|pj+VIVS#)1%Y**=hyMG=z5o4#e|fn_FRXuK0g%_f?~wxcxLLjb|BuJtqpY2O z{^8&M5CHfI_#VCP*$)r@kl#Q49Y-;GFLVp&7SJuATR^vfZUNl_x&?F#=oZi|pj$w< zfNlZZ0>5nmt90v$jr{yc1~-vQN+ajr z*fpRua?>MHLP{goQe7Ke8abt|Qun_pSIp#kR=2=kW&st?)u+pqWF38*Zh^nn0vvDK5RX2^(vn(Wxin|ovi$GG?_pi;S0-fpmBuc= zDyVPJE$|mufc-B8acM^y?@UXo_Dk??i4vDeEh(oHie@e!n$uuzvprxxapd^%`{x@beRGlt{67j;9~~zm=9`7hTS; zB(wbG_A9XweWPxHyR-oRO~!b{H~(!&j&n{+dg*fi9lMlddwrX3fxEQ;Un8T%x0aSv zr!H4=od4B!DarQwHr)buYXSaUT#IilEvZgjuH-oXtL;*f?e%TC1@6`Y+VwBVwq#pr zt_LaY^)#KmI(wC-KEIlNHA^GctdXyOY2;Euwgr_&E(|Nrax~a3d|l9g`#PRqYN3D9E%4V^fc;s&PUhFPWV@8+x|Y9M?$?^=TXYND zy#?4$_3LDQZAZ3?_IrH%@BD86SIhlc6Mc(rfxEZBom~G?+Usdbd;Lpk<+ON<{hfHz zuamiZU(jp#_gX-|{^h@O{Yz=>{O|QNy=V8*0{ZnYCI4P_uk3O!eL-*g-)n)t`Z^E2 zzLMvS(%R+U>uGw=?xh9(>gzo8`bv)T(%R)-`hwo}zt;j1Rl=PtGiW8QYd7QVjXPBB zlq64*Z|}1%_usM0?RM8c>lXMcEb!Pm+_h#Tk_dm4TP_NA4){O$c9`-_*G!j9XH7>; zyG>u1R+{FU-ZhOgy<~dE)Ya6=6lwA|RWZ4m3XGSHCyaZHn~W*O4~%acM;nJ2dmB3& zA2LQ88yRaDJ&Y#f4Z}}{(}shFZH5ho6vIb`_Y4yaqYXn1{S7?~j~dz-?l*)R8X9UD zybNUwW`jeyrd(3aC`XlVl~@ z60S5>{FT~DHKmeLPH|IA3Lc^L|NQOr0#`f~^e*0oE;%ljT~4{|b@|+7q01DP5iY%5 z+PZ|eRB;h5=dF9KtE{uEqpW?bZLLkLRjk5#!LrZtndJk^8~DP1_y{~qH3l2&8ol9T7Nf&(&2SN3cF3^X zu*I;>@Tp;eVUA&%VS-_d;bp_~hG*bwT@39F4;t=+w*?vM8EU}a${Ab@21B88UAdy1 zQ%)<#lmp6cWvh~^tW#DfOO%h550n|o6lEejZ?y7?@}lyb(ogBF#4BCleQ`=Fr8)dB zQVCH4;emCO8cJ2g6Fz8Dtp5oAyX6HA+ugkjY+1Imwtcqswz;;~Y<+DH+3MQNwjbO# zyC=K9;{KR>6Zf+2Ke_F6Ti`aoM2$t}|SRxpsApa`kp~xP0gGmCFK` z@h%B29bLj*s<|jG7p?oOYpu!Fan=NDXX|~|`c@BXq2;_~zh$Fkp=GM&RZD+M7fTCE zu%)`iX1Qs;Xg+G*W?o~SZ=MD}dcoY={D`@QIn?ZDu55NO-!%OMU)pc_%Cy$>3A`!E zG}`nc=Bg)551X2sB1{e8QJ$EuB-3^H)M?|l#+}A5jBAWbj2{}`GfskE4L1%l_BF;E zA2qf$K46S8Ha6D7{8haD{rtHtOf<%mZxMXKf&M5C?}M|%6@p< zHf6K2QTa?+sVq}IQ9i|`X#6GwlE6hO&zqX;60>WZBN zfsPW%X51%5l9f`W0KxG0L>*CnK~eet?5P^?gNB{2+w<5B6}@OntW;W?ErnZ z;E4PhH;8u6qm9-45NG7S#kLgI3%DaclyyPAInv|KJbxeSEZZ7+F2gb``yEowS2z7~ zJ8#pt;*{rlitFG?KglDMZX|*_16wbWRL4co@w1<~qJvj&D2* z%%(jK8QR7gTZ8|6b2ZOwT5wY#55qj;YVnC-RKA~eRQ_3%>5*Gh4w{-x4~yo-zL}9@ zHpS)3RA8>*@~v@)c~t&4wo&=M)<BRI@4oFFFW)5k)C(vS(bJC3hDRG z{2rvNCvO+d^jmB@3o@NDC!Hy`%W~f!Jq!{3(nLH-{EMdNJg_^1$;h)?=Rja!}aE1TOQ!P+;o1= zpIO%*fTlm!rRmH5qUpOGGCVF^m!=cfWyfbT;O$&C7u&RUc+9vh&0knX>ob>O8(jyy z-3xHaW!UbT?RO)83~2r5x-|XR23!y8$oA80$Ya2Mz`nuboej8dF00v!Q>_gx<-TbB z<$Bq^JQh4|nh%^o9p?b+&OXR?W7}%}$+1;@Y&2ULu$}AXdUrA(`m-F@r|HUl)?l4AI}Agfw{y(0uW+ng16qt|b!+vqZkpXrAkXEv z?>yFA4}Z^N&UI*G!P|?EJC7ghrs>0J@$%dj*Te94+GkA{Z9ChW%V~Yoe4%)~T6sO9?eo~MkCmjGRtL}L+PuSMwZ3TOw9i_~b#Y#6kL%Ims3c!2F2}MQFFZ%E zPiwKqZE>Ai8=7vM-mW|A%Hyf|9ko0nf?YH;!elk9|%X1MZvFHn*?kIn`o{_2;qH%JFxajo4>zr+6L3 zzvJ!NXU-Q#YrFWiZD>=oXYq2J*Xq*B@xFxpnPZo~V;gF5u6<@%Z9KI+%W2!RalZXC z%Q7sh<+YUS=9pvq@chp<(&kUzCv%+fK1uThZLVc`o?|qda+_Qir`%`u6P|y#Zr-l- zne(NA_4_S3)`jDkeUf!9KL2n#THlJ-!L}@pHXfQ@#cj>|m^w~9eUNf2v){5lnhiDG z*pIaR2*)6oAs_`HO_uLXGhj@OR)yoJx3 zxgI{3*3Ro#hSxl+0hZCut64@nkK^+n{@w@hS|*=&b9*eKombUIzP1xS-{JLFO?TEw zTkj1(2G^d6Kqfp`Ck$U|R#=54e4IZm6}RwZ-LH11=i|w6fe5x5;*3d+|8%c(T2;@$P_pOTguu0 z$aA~gKKl&&1jB9fcv}HEc^oO%(+P0D?*}bFG+>*B0=5~C3D?Qv$NgY3)@ao_>Kw&Ahkdi?>{%Ra$l!4zM!W&K_TgTXVPALs=h1KmJLeUHR;_O-e| z>pSbowr5?r-&)@%AwL0(0wcjI;5jGU){~$I;I`U>he0dAFcFLa;{dnIeS86MyWD1P&=qi-JT4D{`+(+?+{ea%{lf?F7<24# zyJZ0TzZR#TBfko)1xvt3U;%g^OaaqDaedeptj~*JAYhw64dMao!ti)D2W$t{i+v;j zur1h6yaC(76L5^MPHYQJr|ZaH1Q)=M;5azsWEaw}z*fMzF9&M?>;55N{Waa+MxMu! zZ8-uYf+1iK=nvSItiLvf9g)|@kZsAa#oE(WsnJe04Km{a1iVPX)B!~fx zK|RnA)Bs+<8AV*_BDb8IXIa{OL!f#KjqFcb^`Z1cXLJLm)+1?@o#z&2;whXeMrCZIm33E1vc0M8W_0NY(S zVY|=9@5}FkY2Z!pG8hepfTzI#@Hl7(I)aBlD2M_~7=ab!<9dfn;41hI z90W(fF0c`70iS_|U@7H?l8IqrD;U4Sd#aqp?G8~%KJ!uHV7ZJ_&r?gP3H=suwPfbIkT zpM8L@t>EiK_!=_pdJH~q<8y~Hzy!>I&)>8)KR(Cv0#!j-z{in9&~hk=HmHqeg0DC% z>&!mK{bqQas{n1BIkvd(T=z6E5sU(3!OP$|Fc|a&@t`Nr`Voix10WW#Pc;T?XZ8yp zz-_T_a2q_vCZMgu&qV%hFcrKBMuRcnCGY~!+U$cox5?+4+|P#rkFVB8ww*REY`c=i zx418Fhs+mXHCP9hf%#w|m<`?qY=^f1>&13po!IWr1JcoIAYx&pRCE5JU>amBU> z0jx_y!2ZtmX1`@0;qi0y_qDy zc682Y9SDfh}MySnlLwq*~v3 ztY!f2H}_fVx7K$aE3NO{k!LzOX@j&W;J!x!j_Y7h7qBmB{pPXbzPkb|;C^31KhA(7 zfY){QfjxlN5I2I&;4{GMJ1f9PU_M9&?*LvuoB+mw*TKtR1Q-H%-EaWt0eJneE8sPs zPT(QH_P!s40Jb~ZycVbnc)ivWu+3e74QOkJh0r?-WU~I?G+=)_3fR{U0Jb^vC19Jc z2Pt3?SP0$+>~rjE6ToCJ7O>B;&7TMCbN#_nfPJp36Sn(MzH z@C58@Y=W7?w|~C zV6CnY!v(~;XQUJu_>#E}=e7H| zwfgv8WtQW5d0TON@O{Rbz4$&rzPDS`h3{eHd+@Y2w9ouK>!-EFcI0v4y0|U=o^8T? z;qqF4wEEMrjdj&zxJ}l9>(FFQBG2veJ)nHA_$hD{Xl1w^mN|0UHcjsKvMg8J9$fZN zv2CoUwvGG7dT_g}>v6zsmsIC|Y`e^*dE+BO{Z^>-v?L^%~o2QEU(#<+dKvi zfW2S`&}^^uncLOA~E`VEx&C z+@|*3X5_UtwYs?vtn1ex6>$Bx>sGv-E%=`Mtm(*h)@;Z1u#Q|0>%n&9zB5|?wj-~} ztVh1Mjd*Oo0mb$G9G}+~ljHWdpWK&?;4`oiECma}JfP{b6Zzt8t;Xk1!6NVx_yEiY zY^UOV)XJ>G_EjJSa2b~6GTa}wD~}iVhi$S6u>1&Vvka6|fHM_h-QY=VzX0SSS9x z6|fEXGuwl8+5{E@w#f>>e!@0kpPT|%r|Ce`iBnCd;mEV?*+v5Z>*S67C$Bg2IuNe~ z=3|?TQ~|7K9=HZrPyT!ku-=>=0h->dBl8W|2)+cYKkLZ4GamyjhS-*@GpDTgY`|mq z7GRsc>g08#&jYsSFwh5Ry7L+`uPOV3>YyR;0bZaM;NJq6DuCBGU4R|jKpg@p_c0TB z?lbq1`;_HOd7p9-90%NA{=5gU&m02Wzioi~%;Uo2#Qw6>`I-C4{rwco1@AjQb1X~) z++Q9Wjt}-F9wUws_S?aL{f7I@W5oXZEa>I@%xk{!;Ay~Xy{$nzz-#Ng))xwRTz#FX z1u6HN`^)_-0PKgS!H*yf>~f~u7ly}+V~gXOQ=SW0SJsjBc^R;7o%xwXI7LXre~HK^ zHp4L)J~Q|7rBH&wg%aE1eYd00LBxh2=T9ERsm6B_FQ_}ppGKqbD{voP&!8LVQ>NWM);A?7BnQQ7BW3$!0 zN3v8JjHlu;37{Y71-j*yqqtmOitQXge$&Ir-ZF+R<)Ez`^`WF3byLS2HPDiyj$d+J zrCba22iYJ4Tmomo@$f2i;KBN|WqSyvJQhu}@>EI$@gO))eO<{@%kIuqX}Ak)?_?;_ z!5{(jf!B6>t0u+e2U6@?=tI6r9-!ccO2@(48>(LtQdc)jh)&E%6+oZ>59i9BWv6pd z_2{^3813p7Lu(6Eng_;%exN1j=8pb?&c*16d>m*EniYCcRAB%G$3&4|p-P^>46<*+ zO+gf%usxB2wiq`6= zh0&^uQENm2t`U@8p%umX^q?faS1B#vV@e1+fcUi_R+@q#;A3zUSP?s6plmn%KGHc} zsuGuBsS}%AKFlw%TAV_D11UaW8U=)XMFG(_5dTe3rXQFCz5xo#Hs<(?L+rN(%`y$9 z;L~L*`IPYvr0R9rr=>I+Ha#`;lhzb{8s)2@OgAtYYz6tCK9@g$xK9Jyz=j%bv>?cf z#=l+5tJk20%>(4nmo9w}wQ_oF_MI&?8H2JNc?Q;aaA;vq`3^JdE}iBjy)4Nk%&T zH4BZKR+R?#u1nosYfMqKBgvz-+BE%|I&{^$=@@8JcnYuTg1?D#D7YT+HZJ{dLjz*K<0II)?~y#$NM=a9QWzqI5_a0 z7j4U{M{5^`(7XquDG6~u7{ukNUVeG%g6v$?|8vAY$GaBu{W$JHFVHPtqPY4ssoDBK z3Vu0~d=UGtAOkU<1{U8?TaQ7?@vfo8eJ;m7xHQ~G>6hx#f#adH1@WJPc%KClK`#&s zIM$29asPAdBOg1!i^4VrkblD{@~#9CnZXK$!>j~Qp%5}q-yVx-ES2o1RO#93Mn8u7_q|p{v@yo`~m++hG z*(7oQ0ehK_8v?36J1eF38wqiZmIWt<9;fsuJLGxa{}NaPP5@VwjRcg4xF0T)G*~9L zUb2gKTu|kZV7b;Ku5!bXhrb9}mh@`W4^f$F&3zea_x2g;J1Dyy6aarNKOS+9y19|hEIO!n&$4bK|Xms75(dlIgxzE!WO&wZ4wE-#a6xLmiWVREu?vcP4}59-IZo$Gg#i;dN=ttWa7R74!4H ze=x^A2mri~FHTE*W}1O05cWi63V0%beBGmp_WiDi*<8f^S+EOev96`Ozc1S7BlQP< zz;|y=s&XZSJom7T1IC zO2tT5DyW9|A9)w?KhhiJ?=t?YA^r#c9RHsqc2mJuR0W-=4fv#Y3Gn_ueV!bCA=jMK?Zp-b7URx=()_0WDP)PRB`ciV#BPjC<;A4;d zzybK&p(E&iR-zv167@MO(et|kO`}%c=Q(|PX3bUo?rU&3_`VQvIX0^CRLozsN}j)5 zaI$A}Rd9W*Le+7y7j$lPnTOIg`}AGhxPDUNncz*$RzzOQovQ}SzN+@YasRB@nQGd# z3{|dos}Dst-UTD>1Ass9sVxxmm8rnsS2cZX(8H-8MI=o*7;~`OHPsu({k;}utI2h< z)uR)#RQsN**q9d*jV}FI1N;1jwB^SznpZKVX=08#6UY6zo;hlVgV)vf zUcIg!uZs9ziCEW2L4Glq2WEZdNlDx5QsVh0)GsfJIwJOQ+#ikDUv)NDt@~-N`r31d z|7M7DCe}$5(qP~Zd|Oo~k3|8bxI`B1_YWi9Q$g|#wZ-ro>WMhy(-G&)aVLk79ss+* z795DIo#jW1{X=P%e+-R7ymRb#24TPh#5&`gV_hQ*`C#A={6=_^&(cQZu_vNiie{Q_s$O}_p$2h% zT7*q(`D65cpB%O7< zYC-`Equf36)P6YT-@7YU4a9zbRNq{6do9Gj2jX1Aj=U>SK!Fwe^M|U@*%^)Kz>Ek= z-BEPRPf0h_4%qJ>YI#F_xGLg*E#h2bCGsg?F<1a*EfzE-st%1A9)h@!rg+4AYry+` zdx6^g9F8gcIL3i*F?^7(0z7~{raYM^Hl%`AFb5&t`JA8k`)ffm;P|dm0-o6B0qnqa zuMe3wHNn+~F-7P6yx%{|`+mUjT^x?}qIgHT0jvcpLCVOww7?cwbk5KFeUAO4JBk19 zc*y+7Kq_c-7xAxRzcMmRJ9od8Lbp;Ke`s>2YE!|LD6Ni95O<5gQm{fwHms8pD{hvO zYNkol;FM$!$&>=3*x#!H-sf}N4FD6sVlWrw=7ITOkz^OkrPvA^r1Towr9}TDQfiZn zl0Awb=Lv#9Tks5c11tnnP;MG{54;aPl2XeplTxa0kW%aKmSUTnmeL|~q%_qAS>ES2 z2fe^3@F5tEG9y4D7z-vyKJL?{glhAp_Se9SwS6`{_H|4<(f)+`iMtuEITFjYn?DHXC12hA@!8lNO zP9f>MLIzxv>V8n6%G(w4|8z^)rjy6`c6~|-cp-3b_>{|yV^+VHr5K zsU)O z^V?rnw_2{N*FL+ZR)6H0+WO0E#1CSf@dZAh3h)5tBkukM<7&sB+tzq?nqSoEmDuM` z&Q+g9+|O^4tDefsQ9YJpO(6|&&g^os1!*c+3sNq4(YzZCDCt5tB}S+%dfiZ$BJRuA zx}hfA%v0Cx#xX@A;#^}m@w}9#W&KFVk}0USpepNj$A)?B02K)?u$N=8&J`zXDF5D}qX(3hy}d*X1S0xz&*E)#}Ru^+IHy;AV1sWCuA;eG0NeK@wO1 zz69yOgfeDe1#Y0MoNTEiCs(Z@$JcErCpM0feIi@SKI#*Y9RzsZm~_sa#G@uTxD<2x=%NN2qdY49{CngArglSONBdqbPF>AoS@p_z_%@V$0u< z5^9;`kLO|?F8O|4g$t+skCTkUr>OPv^zrS6<(rafSPvYC#9 z^V4ydnPjH&WBZ8UA>(R3^7y&H7atfGITQQ(%{Oz@i@S5wa?^6u$hJ9Z&+9mU7>qb) z5}fq2l1ncu`FFF@BXRXAjBB>8{+9te!bGJ{Vwy`g)Wp+y>e|oq)Sss2snvV%IR#>z z32@?%)ED>w4`9AjoeE|)rgL7=O%CL%?{COgO|$dWr(eleS9C)Bry<5Qb|KGf16#lb zu=0dVi)YuP94VbH6z~Z;V07TJy9Vkq@Nrc&2uNueXPd@ za0p}pIS7Bd7dNXJaN~;^H@&#I8^{AUq*Xn-(!K8T!L>t2Y-!vw!Z)hxg)DX8s4R7? zF-x5@;HvuBx=i)($qaSP_a<5k)}J=frV}Rm`k;yS?l#e}&rNh;;m6+jlUp>h4SF%6 z_Cp`5YULdDv6I);!PBm*@5EeJKmF#K8g$u0O+Yxf@4SUte{Z43PFU!fgBBXG{fOn= z&)@S~v9NCFHxMtqToK zaiN(DTxk2Om#Y+xuOArpQmd!|Pvxs0JeaQ@sGF}EjQMJllQ@4EhZtwZI7vi091I16 zK_3v`rVhou5*86VLH*GGrs`V$rus}?fx7Aljwf~@zBRTXudxOBRImZ8{K*Z=(g8Hj z9lwJj=EsA?LiNploJV|*`whlmJCg{8t3EXJR45Hb%qM_8ApVZyzaG}_f8O`rdHh3< z0$Z>ayMM0yUN6LdgjUD5@b^RDFgOY@+tO({#q~!yvBpnwYQr2kHB1r|N21sK; zNANV*4|)Cxj^TQafRl29^^BZW{h}P#FiTDhE0i;$T_9T-)CbX^J$MT2hWs9|7wiLE z&tW;ycv4RE`Cd+H@RMv0%ahZhjgT!5YJ+gl2J`@%A?^Pp>;PQX0olj{IWMY!CTPwnt~6yaSX$ znOYzMa3AJCmiYjD2Z9U9JrdT{?t2L zwXDxlU1BWc3fv(NO`-a7c%izb7UDkvF;x=%u$}1xdV%;xp44qp6YAU!zo8=TTRPMpQFj{un{e(u z=jVOzpNn5d0L~$btsy|SJ39ZLW5+SX&ufU`xO650L;@^>kqVlE<|3(5YvEI`gRqBm z753;}@U?+p78fj?*f0sz++CX&j; zh}b$0h}ht^B0j1!WP5@H@CtYfya&7?%Txo^fiI{7P@g$Sr1(aNXSYGhl;b^$!+ z4F;pZ+rR~~uD}i0Kp9XTR0cjGzz0i;0YM@)B3h)Y4?!NbQ2T%v!8nkKxq`V0vOx~O zpCiOYcevJ2BviBuAAi&pUR$Kb1VjFQ&d`C0YMG#k8M+f2zd%=BSp zGksjvOiPSrT6Go26eoZ5+PU$^fFm(F@E>V?QJ#;B3K4e$)i$BhDXMBYs+zKr?KMbrNNxhk_d!<_25|Ec8=j9*UZAiE5#2A_j1fXnl>lFVCR zJm7j*mv_K4kyw4ENDW99_Q?5=T?|%&_25ge6YzD!3}0)>*T3?0qFfi(^R|esHccco znkAAV=86%&@`rZ^7l_!a$22({!_)OuWehB$RU0!+r-;YeT~m8s$yNtHpRJBQmZiR3GfO=;%0lPCg%K9IG|WO*Ua(Ns01M^z zwveNXh0HB1RJQTL>eaj|h4|+WjfvWytG4|xSB-x*SAD*It~z&z3w`*t3(W)b!NMWxBl$B&nf9x$giKoEPg^Zyux~|t z%u&dn1gF9G;1bvZS&grd|Jqp}>$6kDy6hI|eyAh#fbfYq40-NDIyeh1fK8A~Eyfqf z^Y!Xn=hwmq{YtF88^=JfMf3s49|0!-_u&V?*M6@n#(LyG2O9y`yICaG_*!H%-YEj2 z_d;H)gZsgDOo5EXr^qh{E5Iti*OsF`uZ>ruMu$(JZF6gwu3Zq2)wySrZ+#vIR{Q+#=j%eL@c}{b(iU#P#N>D zOfxr0l>F@Jn)5|w$l}qdF}KgZeH|uZp2;`SvpFW}f5k)zKbq+ILna!!6~AjNGSTQs zYs$R!^p64WgoZ}Xc3fBIueq+Kbib~y%fF_EZnaYAW-En(h)q_CT5lzFjg^`$v(iH! zTB-fJIKFt@NjCIJ$Zp2)v;6|AsyDZKd+}-G= z(G5TKyOLXuD^ZKO1^Q1u*Gs0MZ|RL{R>qYK~?xH8p7 z*T79+nr5SNZ`-H_2%c!8mT%hViPvm2WK^}Fq!I1Z#lsxxjzJE!3}UxDr~>MMFc1d@ zf@xq2xB-H1+UQv@=jIi!Z*HE7PzoJtV{qrO&+$LfUoLRO%tQQV!bdc&BA*4a!F7-e z@(dxK{d=9vQeR!crKzS;${1wO)hwI{cSP!lvSH$`h zh_oQ+5OsUo{P_}On9ELnLdx}VJ*>+$kyH((EsltQ=A|0`A2XLa9x*#j}7%SxGK^ka!~%}ZFQtWhB;k~?~p$O&H}FQ z9L|F-ih%GdD4PxPi`8)i-ybc;G31Yf6W}D^y1x@XHO`9IkRLGzUqsmqkn602=XqwY zlQg9Jz&GFk_!b-yKIM*!fWT8CE?S%SxSlMqv5|o`)(3SAw5gf_Kb;%siyVc%Jf_fB zD-_x~QlXuAu+rX(_t)J&IxFIkDN8**@Tz)xO{V(&F|3CUw9rS-T4+A__-P9*=xL!( zx>{&)I}0tl-$Kh9S!lJFh1NTAD{VTJ+vKY?L)Bfc=c?bd%TTPq!vfqgc!?SjWjyrWzox1a;`r(S3>cJj1 z`W74lN5FBA{)CNw0GGSi=sJ)dwUK)V#CR(kHE6M^o~mw&?$FqwK3&J5HY>Ez1E4v0 z5VQduKo`&p3-F*a5DB zN`;eZ#uko@ej0TkE{pE9`|UK*?7%UA1N)DX;_tW1Y4zHT4jcnu{`iySQzf)r5Ah%V z=h|mI()}EWpFdwdu{QJ%gC4({|NglD+Fo*tL zIqkauj3G60h?ElMKuzY4(pcCq=~rXOb0nk9;lG~0Z{0J9@#8+g1}VR=;psXiDxxM* z`~ijU$^ny!&SV+sEFOIJ!zLr0pJ}8^&l)MC@wA55E>4Xuc=wv>s1GLL9x5C!Flh{q z8}_ZR(l! zI9b`#jaGrx-Q8&IqgaP*=SH8maHG^nH`-F)jkbHa(Oy%Vz=Ky@)ua0h)bwQq>PVA~ zm_+cZu;JVh=MrF?!=1+G<9GtRo8?Zkui$v%M|WC$YNPkcLr+A0zO_*OYJH*Vn`5I| zpf;$JWutna0SLN+V}Xk{iv1Du!Wqm7$86O75RL)%+UTXNjRIa@?@*_$0GJQn1=GO{ zFdNJT3&1k)8Tbn92WLSJaB<9Wt>HKo5sCSubpD%O6=N5SIR2CVn_dO+hw}6%%Ll-B zlJ3I)(^6B5$>m zfqC?{Ip~m?9L#>O7wiO^!5Z)}cn7=;x`I&PVh(of&%xXQB6HNsIDTM$VsIRB1;-E> zIEJ`ta;0pC3ti80p&MshP(N4?K0H?2@%qImN6&ne&sPsW?@k&=kUuieosNQI&$`oz zp6+z2J1$>()Sb?>bEog`cc=3>#<)`FiID5%3ROq`O?BlY8!@Y#tVX&Pd*hxf3|<>UHV@f%4hs)|51AXiO2pY`7X+*^FI78%E$Vad<>!a<{zcW)u4aq zpO3#p#Gm~x<1YRV1AQaRG zUcd!pVLkH@SijxH@$SMf$Fq5=BNROEMn5wU`DX!+CmcAAaC8M70FEIXIEHZ40p&n` zKYz!mOEHd31!`_18)@Vre*@&##~K1~)B!a?HQ)ux0T&yjibmj z$G~xL5}X33!5Q!axBxOhj-y(A2jU-B?U6s-N1f;ydW9y_JX%fL=m=e)d~%Vzq3ivtlqKDeB-tdp$>rqAvX5L# zt}h45A##*_pWIw-CAXJ5$z9~`axb}$+)sW^9wNUazao#4Uz6XGC&}-~@5(dfIr4|{ z$MPb1sk~fXEw7U|%3sP~%iHDM@;>>Xd{{m%r^{#LALWbkPx4jynw%%&wtpdnQCNkW zunP}SQB)S*qPp-EbwoYUKm>@!B1D9XD4~j`;sMc8v=VJad(lBWA|4Z6#S?#J$>JR`RlF;viy2~;m@Vdr z55!zCPkbak77N5DVv$%PmWmYdsaP&nidAB@SR+0Y>%@AoL3}PYicKO_d?CIRo5dFK zwb&}QiS1&C*eQ02-C~c}E7HV1@r~Fo4v2%|Tf7g6!{UfIiuW;bT%5rBq&S6lI^L(n zcX*${`z+qyiyy>~c%KvJ#Ra@Cic8|M_(@>ZKxB%mB1>e8YvQ`d5qaW<$QK3Trr_BZ z>tj@t8c_r_$DN#yQ(qcPi8LM$cKC=srO#;xeM@I3gKm;VDlgTL8cGpG9??S@D7_-R zDNU0;lv1S6r5(~?_(7ILvb$UbV;?TJz=-#f2g!*T-}mJu@&+06mwICFye zZSxxQF*8|eSst_uu)J+qV@bETSesbmt#4SDS`Xsl$Hp%4E^oQ4a{0lfylbrM^RDw< zkGi_JHE~ODo9}ki&CNa5J<&bYJn#6t@K*)wW&^G9Us3`zr?ye^-}94){pm(Z4lcq7Pt0OAO%t5*xz3099}Tz$(XfNHoO zu)CBL`K}Zfvk&+2m~b5o-;2ce@xWnmy;w3X=Fc$5o@uV0lu$mD(yMf*^qP|?px#bO z32>7#LOMu^krPm!pCRA?!6?hu@>4Hd_{+~C2*4A-b8$0Va-4^Im4GT?6koF+rPW=C z=NVj~)R1u8PcTf1jp6&4vp`*x<$IxuE<)mqiKfUB^%`U*dyTR*E3-0XC)Mz?2h@Fr z(i^R!_z;s68`)X%iJ5`2$3O*?ZNufKE4S`L9*ndletl3nx>NFIPx7c)ojL~jQOh!o zI#61ZWt0(NmnfzW%JOpz_@1oBTs|K69(D#T0pE*ge#A_>o+^(AZ&#y?1GUNbYy+}q z1y`H?T*PEbi#DJfKaXJ}U_1Wj-a{O0Ujn^Gt$Qh10I* zquU?IRQb6KPojJ(pd{RLFdmEnd>>LT(CiICRnC{Evwf=5^xV1>d^nI+evJE9u18^o z8Q0I^IS9F#s>b?M^vF^NAbH?-$t~cQYeMhjiPxi@f$ks zUr4>KR`KNfpm41*!}lL(_a4L{&(|i~7nh~8^=r@q7k`RB7EETZNSZY)hN|HDL%uIM z8TUb*h37Hp;5guGlDB{qFdYnSP?=g!s6(C;0x7LuI1S$r&G#@-60Tv+Ks|h|u}0A~ z$M}30@U@A29pd7RCYo~6hX()TPc1iwkjKO*O2hRB!+{x$$GW`6IOG}a+QXs9^EFDn zY~`pUt|5xTeS|)na1Gza7&?I8Ag2SY`<0R^l+n(g(k6xCo~CG;f@6T;p!DU@&cK?u z50UR>#I;PPQ1(vCPjbVvOmH7Ep2_08AEF+@w;^uk55be}n^B_MW0YQg2<|1GNp|1u zg!Ml>k0er}(B~2V3lYDk;4@|akG(SwZ=ziP{yj6@o3<%!p&M;V_dVUWv=apc1#J{m z1f-EgPzpo=L8vs!E?X27luCnCsca2 z#9bnzG9Lc-h5vKl??KeNqmJ$CXZ=jn9`2_D-)n+UD|ZjjD|`_c6Raf-#t%#EPWbQ1 znJ|86F@C83=lD?x_h*5UWpFUng&MATlYVbt&|!Tm4Jl&{WJx{*|06hMUNQV<{fI1s zgk>1L&R(D84>0$;1LYWjY~h|XVV*xVHVdQd)R@==F8M?Fzn84J=(j8=K`rZvN~^vj(~;wM}P)D7piINNBwSvQ0?X@lJ8HXo7dCZ4Sz3pCHxOZtsbzxOdnS7!1|8i z{7qm5tS@m^U)=oe8$>SiBWOlc0yTV>Mhf`9VsQSj>T4p0+M!?%pa~D%XMKn|&>g6s z7sz+JAJujVBg45^N`U{B@ZSdiZ{89;dfyalYOjf1SbdZGm*9LI*bi!eG0=^M1O}7( zmngdVMlu=UzY_kJ!TJLpWy$j zcaa4GZ&@bFtcU(LxqleGvpxhfSOjK(As!F>mw%LkETbG60{><3e**l!^oajW?$^Tk z{SW|B_6S!++MtIQ%L6*Pdubnkx7|D3yXA`p^29W;~7mQV?Ad z6KE&=Uj+XRaQCVE7>eM(*MH$ZZmc#|J@o&Cy&vjb_&U$$;=E-U03U-+*_i$!Yy@8&2asB(C%Io48G|>FDf}YI z<3c%u@-_4$kB9$1!r#lN4@F%e7zq;mv5((@v*(aJS7~zVrm^}ACtJ`rqzuQ}A(rDb z%6#}g1pY7Jlm%AQGjH00A%JC&5Nl@8yn;rmU!9w8o9msfnH%_Kg|^i+lE-c*bFw?9 z$$SO=PlEqjP=6n!p|%gJ*TQ=QC)q>kWWEAz+vh>r(f(w)u85H}i+Q)vmb8-08BUxv zw+sCLAL|F^JE5UL6p8AiY`5$OtW0GC?Y^ble6u4Xk@%Cj;TW*`0oO5`@#PS@Sn~34CX$Y`&kcC4X6YLpt~GEZ3aY>Y(NUK zjB-c^{~h4J9{$(iIL!MdtoWYI{mg&Xk5CONL!4>y5(O3SPM|jMUk3kKKcfy1U~_-d zy#MIjUxNQW1QY{pIs7k=qU?wMH!LZjop9gqH2!1%|2brt?JWH-{4a$65_*~0{J-ZP z%>US!(O3@u3o-vc@P9A-KR{aUD48A4kU>_D`P-AT1SfEoa1E!3d!I8Zzry^z5&m9= zzy3I9TLadQ$NKqLj>%8B(Ai2xhkaypuOp*xBWZ(!IDNR9v&Fv6>6KGCOXeDTKd`#M z8#Qd+><6ZUug&N`UWBuIvV~u&k-KdoEwWIILH7_#5Xl*0;jMBcXUMGNGMzawgx zyIL>_bXD@yL&4MA#M^U7#tjeip4+Gi{JEpDm5ppM;hZt~4Njf;DW}L=2mftwMu9pF z_z2j;IFUudHeI-E>&1tRY3-389PZy|%tpnR)z_je71pF?oGIfq&XPL~{{Mn{4s|R` zp)afVf9QQ99+p!Fs{OD5=L=u*|00Ad857mEVqW45{l@h3H#ND>aOQlLiLeW>H4s}v z(P8+$A8dQ*{w#d$H{OF{>I2F0S_E~u9Z%Im(-Jq&$eGioSH3*wnm8Esn;#y-o;kq0 z*FJP#g|ES}Jl)LpqiUBhDz1(thsqQx8J|rxXH;RxLt2Ae#ddFAvu87q6|OVy*}Tts zk=fi|0mcNnQuhTx6!B>k)y5{%m^+v|;r|f$Ur{ec55Fy*t$_di;5qZ2&HK##_JFPZ z{lU$J-n4B;7){<0Pi+>azG{f%G@=>1IqWxp7W z6wwr_?wCVb_>Vqj8Upsif95=c&HIne{hRT>R{$d#GA0aEQ12xPq?(#Z4x?0LhWGuz zO}37J-%YS}f79B($^U-%Z{59`QOD9KN-s=Brb#Z{g#WCck@Yh@@%nvQ5Y>4l(6&KY zREZoQ*2m0xnx42GKS!e%{67Kz3;&`2gW!KD{1^Z9zcZHJuW?H1${8Kr;*9RaoY8j# zrwyJ0f4_sjKfzxs{N;FEUO2BVXpeKY7<>+@L0iamt`UoVnEm zP8*AS1LZbOpLq$_@7}1-LQM}a7Ayw0R&aC&w;!Z29J#$1<`i&CEl(b54d}pG!}@Wi zm$mB>-c#q!=1lo4N68g+D!|@HS_I!KKp9{UGwTPkXW~P!ae*|e zc|=U`miP~cyqdPR_n4f713mLcB1`cn9OKXHkB;!YJx~KBb00LiaAcX_OEan!)Mi2~ z)ecLc_I@2l-?Qs}=02PI7lB!Lie5>Gg1V1NAmzYJY8ap*6Ws3ttnk0d`6ln}J%@0O z&HWFq{V}c;dQ%%QiV|?`EiccdOLGeB83y{N@V_B6h-y#7lNobw#Y6vfPwW4lR=9qL z|04X~@DJwyQg_tC|4{h9$G-mG0(ZBAot#40%W2$>a0Z{#oH^(krwHeHV{CI?sZ8XJ zneC7#&=dZZ;+!o9KY=q~9cr;vl{Vu3^HxsdYT+!+j&hoy^PHvCT}~J4#mkjZygu_8 zUY++Q>PMhvHmCuoz+%)^fn}VWsyU;xnbUdiM3xbb(dr5(j}>@xGO`Uavv_4*XI@e8 zK5E#yf%Oz01=Fxl`0PBEtJ{%f_L=uq zg5IcMW5*9*59roXpdKCq^+Yq!JL|B9c#n7g_}C|O;lk2QzYGvAG%3>bhO^aJhD)ENAAAX)Dq(|Ju2sgP${(~wufwkwJ(my|R?mP5+2d@{rRY%mM{Gv66(z0Y9x{F>Y^ z!}k-g8?$&$D0M7Ipx~D>sqRhO!+`s0u$f&)!1E^O*__Yr`8B!!VD88G7AhyziAajL znnDhxxl}h5zXRMK@)Z8t1_jdoX;{m_y|SWwdxiafMqzP^IGQ|UhVx1uM6zJt6O#9DfVsNl#E{f%*n_TnTLAjJ?Ph9(}UM04?-{S7+#)N27j6Nzk=()7xkW~lY?fU zIX>|UMh;2@uk=^)76q;|qF>^zNpJC{j1PEA?o^%%nD<-2S>THL%lSNA!E*VU2T!*T zaMbv*x2vPmUcY8t)uCa$Eeh{XQhQ#WQN-(Whoc{wdA|(o2dp1>1@ebh?RB6vYaD3( zXV`c9a&P|EYiZsm-`N*@WAXcuE(`W1C|*&d=OIs_3vbA0-hT<$+UYpx?CMOfbI#QD zmJ_{o%!!KEIMIl)Z@aP_lJ9m!hX3@8U%d6@&8ZxpmJ^nb75dD&tuX_iIjj8UtLE9eR(_|t_xxrtq4{;OD{9Aq zKQl;*;k*`TKsxY6b7S2P0ilaNjMQo0NZQ^wJTq$O;k;o#*B7kcbz79)xh3WvM~-#5bfOW-i50WR%PrWhzaw_~xj|g<6Ye9jdwdKw z-%kK~pab238u-82g3fh}qD7OHq^->+hsn5i4)>9X{B}S1&+hRtnDcDCZvvHoxjz{U zS&xvZDZ!j|&7nDx9mc^Bs2Xj6=LN_Y(XSP!kNY!K+{->ewy7kANPG<;i^#Z*7h> zLg*Z1sVv~NNo#m*#tzKiR?OebS(XEk1Ui5|$PRh?0{+~;;Q19(aW6F0;53w1`hLV~ zLniXts4tO)@I7xzujVzmyLfXxTk~+JV`Crt9iBzAL2EPuwB0CB`_Bb>@dbfiJ>JZ# z#|s;S-WjnsVptDN!UW!&R)##IrN~3rfqFLfIH8ukkFK9MksBTu?D4J>dB5UBEuzp9 zc;$do{MTQ!$O-Aw>V>W|;@*6rSL*u*uVsIVJcRF1yAiMqD0Ym>u`aaWBlHaqb)n^b z@X^DIF0?h$g$`Xi>&0?N=(*?^|Medz)A=n~FaI${r7M^&eugZh<)~-l@CmqnTIojT zW8COwup2pgxKYqGSIXXXgzGx@9siMijzk!}k0fsYE++GaUv*x~R}K}lM~2CJQ*Vm1 zmmo)RKRjpb1jr$w6~GAep!-7i{Fq6hlg_;xcd~3jTJAHS=8oMSTd+L?YyWo}#AlI( zWOuz7p7#T6zV8Cs10|4yOS0xvT@y(q!N?*n!}ARK=g;bLS4`OThgcR1|C#F*4>98F zEWok|^gsu?0M-4L8QJK?e_pWVcSFqp zpa(3Az=k^3hkpay0u8*`?H+G#?jTr0Jp@g33qg|Xk8^0XFVL%1gF zJ%4eget0v3Em`e)CK0y%*!s6lZdB+YAgS zc;}Y}aoUA?an<+Oi;xY+8R;MaD1Z#yME<~j84X|5==0O?OA+2Vlaq_icgQx5?T~Nv zxGM&J@`w2Huk14f_&w$!%=zJ<7-&I9kPdv;2h*j+cqYS(88qZ_-f+cY(RXR1I3*GO zcZZuzFz4BP&%AFB)IbRoUTCO35l*%_O0pc!p^BFZs2|)9{=fKdL#-9;1U1u|BhN67 z3}PnceiikG`|79l|7s}afA~KQ{wMzf|3i_5D#Cv$qbU!q2s_cV;4RP#^bz!~{RDaQ z0fH{{eL)^QLQo`qA}BH@3HsbG(Th75=M2jOs0N$Bo2X&*0PHwD1-;ALg5K|4K_03T zEK%rvPb|g$^@)NmcLwUqQL_-N2COHx3u@kYNH=`#Ay}N=5_G7mN`_$N_mrFs2Pb7J(jn=%=7&HuwRo0`aqv zgEAhcZZ9IN?kE-YnS#zmg&daFf~8eQ!5W9-r1laNIXd)mjzSH~0r&*lne%Lj8uFLbO?(_oa7>9A76~=*P7zh4vqu#%{(V%6YI+Tq1Etuty%sn+Rb@iz8 zIhN}U`Ij;qM7OMZF@EhWvGSIT7F?6j;>$8x{=1B74#;Th&oVl+SVk9+OF}&_$^GMM z!_&_kO?vtBqglGRp#0B}Wwbox5Ag`gLF^8{8JOoCJ9|PPF+w`Hu$ql3j_`rD1-+XrzS!8~WMd7i3`z??q^nD_g^X0QTOB;$T8?!Apc9&+&p+((7` zF;DA%X$ZVUmZ=E;rH5H0ICj&|@I+q=v7f6H{ukQk|HU|8n^=PHO@h&3nP6?ULNK*l zEl|{2L7BKg(4}w29{wGIDSt1{nZxY71FV;y^|~__Jv`15!GK-3@@C5gb<0(PDe_17 zw;uj&f`8lLp9M9C9@d}6SJp58!$TI>k7MGnk5_II48bb|O=PuTN~jU!=|2g!oUMW( ze>Z9lfLg$MV&|cTQ2|*0{e19)p!QrOXo9K)L&S1Ho=}Y*ruFc5GyL6wnqL9SG&l)n zp}GHpUCpdem$IdjNYMM~vrb#4w&lzRuG}(a0p*$I&O< zI2u=__4*WJ;AaA!L?&pF#bU~;L@)I+!C=o}VLt~uMt5X~yxGZ#dLTQbC?1)n0y0gv zI?}s?hC1lZ&IlM5G$gWA=#(^Z{9BpR1xp^r--1WS-(+mcO-2uo68$@=Yh5T~o(tuU z#;yNC7i#BKE!QmX8`d>zeEi$f#-$Hlcq{kgtj+}n>6*yK@g?BWMmM^=-i@yQ=tkF; z;2L6%8{HX)`v-m9$TiQ6e1snZ6>E<~Cl{?rQJIIykqd)fX%e}}6IV4$kuod%nWE1RqDQw$f&*VEF zd*;Nv;92lGe_tH^J^Vim{}{}52Ak`*0W)CUSAsHN7$hfsatuCG$e7fnR280q9>S;2 zF)9zn+>cClWEnMXD4@enJAUBjXiSd8^#igDz3l$u?x?+Az3J--{BNtE^gIcFPQjl# z_;VKiT!cS1_*0L+x%3Ff@b8=W>lhjjt6&K{C8$wvjX#4Nf(wEHee~M=+mF<;;~Ygj z>zi+a9qYJYc0VD=15XN;@YCpl{#{U}ox}S1GS<&GQFHH+W3WE_CU6;Ue-1H@<$6po z`r~&AhvRXl1ykx7%)b}VM`%Osok!{qpr#4dbAJdN7Bmh=kb`zqFoqpN7Mm51C&4kY z&%j@neZu+n+7ll%w*Cpmy6SD1!G0=BRywCi##c&#Dy^DyyKjkGmI9&yKNjp98Jj zihGb%4zzl_168+npdU{QRD;FT`q|5xZ=8KCe2b_~#Mqs&7kN^L1XBSUx7gTu9(?1B z3^K`?<{(3){IoO8-Rey9W;@gOMb5OqeXD!b%r8S%-0c(hWB7Mz=GCKfx2_EXZddUi(O_Hqe&c1qE+GkOmm$2QNEruK66|H9|1s5$etDd)Fn$ToGFng3(n zZE+KNh<76oEjL<5x#2R(!zFe;`T*7F|7(NZzZVX<)5}%v)U~vmbFbEG6$9&kOBgwO zLFR<`PgOI^?}*=BY!H{yb;c0C^;zdys%WA$hxX zexY99M5iE!r0rl?URUQ!1%r@9Fy<_-A)LJE72babdfxV={ueyygX5kw zX16DOflQLhuSbQh``~`!!DmNhUw1m5FJFC6R2JS7y;pjXF9=+U-hYs`7?~qKpl5h4 z#ua3f%=*lW)=oq(&_{#Zo!`A0mHe8R{(5GzYLurW&PSfn)6LzXfys@fi9a_M|oC*DpR`l=5QEx=O`LXfu9^OC3{fGSZeyC-rX^Edd z8a2oO(4YrVje0y2!T!EI7)P(8u8GGpV07peQUsv)F%rKE`gb+x;WwiX+4@*7_Zcsq z&fewd>D1^*$J2*=Tb?;2#GW7adFqwfwj7K(`S&0B`FD(Vr5z((Y3DG29Fbj} zTxn01EA4f6rF~de92}qRdnCLeqIUMoWb5hYvg=N?%|G87&tO}A%|3=!&2%TzbTG-C zmX1dL*kE^B(aoJ!i^w5s;ZEyL$I(yo-VNFM`ls=`t{%zQH!N0l1X*TQxc~d|+v2EF z4`P&#^q`O7`e^h4jz$09#MT}(6@7m*BpEVDF3IOj3yxaYT9&%v?4;avgJ&0Ph5LJ3 z{~<;l@}y`Gv(J;__IOg_4&)ea@}%t5o+Qpkp5b&)>O9huw69+Y9uU7If#r})S~w+t zHr!u$s8K9K-q1H-4)TWPf(m2~EdWcAIkff@FWNc+eZvF2=xmQY4tHNDifooFrp3AM z$!mN1zF4&IzBm)PAYXxRz&x-BRDc7X13< z)A`Rbk7hMig$3WcnmX=Yk*fCIzw@7+|3)92bMQwAf7I|tgY(~v^Vj;=`TN)T{`Yaj z+6?D8{2|mUP_INi%fYZbVZ8zVX;E*4fA;>_f9c=9e|?1)e&!JT4De3_e@*aDhu1ee z;p@xYF=hng_^8*zUnT05s8>H>y}1V1v-FmfIKp3K4|UiDXl)(N|GXzq#HxBq^#2_Y3qZr zkBx&DPPoy9qu`JmUEJYDm)7EXVm_`X#^ZXTn;YE<$MwX~=Yyotu5psr_H=1jb)GbT zm?#ayXOQ!5iU;BM!MnI$P!F!k=wf2PqDgF;pLJsP3_`Q6ZC$a#*Bu`p3+LKnp_aBiXu&$dYnMF_9jFyn?^&bW7 z*_s%CVD#n8qsjUCCpR^UXT?Tw0CE8a4nqzA(1G^{BWrAs7metPe3BwB8rKOKLhX<# zmWFGK7KPyp?%q#fIV2nA?H0Ee-51Zn>+|3OxCCtA7H9+x=oj_^!5|)}E|z;2?x>3E zRdqFM*mSRgNh6VEh=1nY-S&*4Aj z5NMug{`&XluLkFy@u5G4NBq$|p+9C|^SdK3IJ z!9N@Pkw0NQTSMslG2S76z={kJ1?o+xw><6-=I?+19?*a3uiO)3AjV)T{3XoaCits< zir2TWbrAjr28^LC*ZR1>H}LbH02{z)fOW&;zYiOO)EL9q8b*sTSo3(j0LSk- z!FO;7EC(Y2a!e)Mhmf*{I!a=MLc02Xf)xE8-a{?^hJX1lN$Bmr3s|53MZkLfH-Omy z*^($q)9tfl24;3l_H0v(2EXtc)$^O{#$G00En2ovycN2k4&;qFFNJ! zMZec0gXHK`#nsiLl=b7+=SuBf5~UmW#P8uXV?L+^EF)wgSOS)TRabF80vSZ+t;ix- zzQ=Xf>=QBj$6w84IV7hFB{38KhLHtwfC{L=bKphr8qk9NfMt`6lgfi;NXg21(xAL$ z|IvR1&K>=KasJ!bd4zf+{4v2F{Fs6f{+OTQ{8hAo@2J`(=HK66^Y8y#i}z52G0=cD5W9xbKV?1p9axSU%TZ$2FqX&t?S%CL?m0;D z0KcrX_Tk!L6V?v6E|D&>pGSk=LC>z^@HeoszrkN)a8rg5%MZf+M`<2l>j~U{L}n1i z6O1oe^q<_G}ScM@VVF8SE&NNuv{@rRd^xX?31T zN=6RRG^`=u_MbSjj1YkAG3f?C?wEvY3klZ~60Rkr(ksDI;gTfD=Sq&WX;*<%bWf~5 zflLqv9B(*;9Kn6aA=%?a_u;#=7F2ne6?uY#-|+K$EfUT&L$q zt#QPYfZan#=c6V|-~cj(RgfjRj%tW6rbG`;p8f`>%|Sn;>Ii4B_aS#c?I>2yHW1Z-8R(Yo zhzEEa{!C6WVF9ExDDv=VlQE=DJV2(j1Wu9jA!kvo!?RIYA94Ku})K-9!z9|HQ2O6{LR z#^Ie$CN-Z;a;J7Am-Qf<&nQv^RgyLADEx2E$&+4#|C8bW&+xYq{ws0b_5w42e8__w zlF%5XV=`&npFDmQ|HqszXD#Y)!hiN$<2M2J9ixv8?yG=o zui#iCcWargX{Lt%$TYzCp~v`P!uUby12|320{DNHGyFMz*!R(!;eI73c^3a_qcfR5 zmXq8&AlhHA=n4NT;s0&;-wysyg8#eVzZ+hc^->RGug~0{42pr$*MW8-$WGO|1@(I+ zlvF8E&%pn$;C}=Be+~W{;XmvDk3#KRte&~w8)!fRuzi7NnYZ;Nd7qY)a5I9=eG<